[Pkg-golang-commits] [golang] 02/03: Imported Upstream version 1.7~rc1

Tianon Gravi tianon at debian.org
Mon Jul 11 15:21:52 UTC 2016


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

tianon pushed a commit to branch golang-1.7
in repository golang.

commit 492ecb18053ff973cb5c22b8dc0f5e9119fd5080
Author: Tianon Gravi <admwiggin at gmail.com>
Date:   Mon Jul 11 08:18:45 2016 -0700

    Imported Upstream version 1.7~rc1
---
 AUTHORS                                            |   110 +
 CONTRIBUTORS                                       |   156 +-
 LICENSE                                            |     2 +-
 VERSION                                            |     2 +-
 api/except.txt                                     |     1 +
 api/go1.7.txt                                      |   285 +
 doc/cmd.html                                       |     2 +-
 doc/codewalk/codewalk.js                           |     2 +-
 doc/codewalk/markov.go                             |     2 +-
 doc/codewalk/markov.xml                            |     2 +-
 doc/contribute.html                                |    13 +-
 doc/devel/release.html                             |    23 +-
 doc/effective_go.html                              |     8 +-
 doc/go1.6.html                                     |     2 +-
 doc/go1.7.html                                     |  1236 ++
 doc/go_faq.html                                    |    23 +-
 doc/go_spec.html                                   |    20 +-
 doc/install-source.html                            |    27 +-
 doc/install.html                                   |     4 +-
 doc/security.html                                  |     2 +-
 lib/time/update.bash                               |     8 +-
 lib/time/zoneinfo.zip                              |   Bin 360703 -> 364741 bytes
 misc/android/go_android_exec.go                    |     8 +-
 misc/arm/a                                         |     2 +-
 misc/cgo/errors/err1.go                            |     2 +-
 misc/cgo/errors/err2.go                            |     2 +-
 misc/cgo/errors/err3.go                            |     2 +-
 misc/cgo/errors/issue11097a.go                     |     2 +-
 misc/cgo/errors/issue11097b.go                     |     2 +-
 misc/cgo/errors/issue13129.go                      |     2 +-
 misc/cgo/errors/issue13423.go                      |     2 +-
 misc/cgo/errors/issue13635.go                      |     2 +-
 misc/cgo/errors/issue13830.go                      |    26 +
 misc/cgo/errors/issue14669.go                      |    23 +
 misc/cgo/errors/issue16116.go                      |    12 +
 misc/cgo/errors/issue7757.go                       |     2 +-
 misc/cgo/errors/issue8442.go                       |     2 +-
 misc/cgo/errors/ptr.go                             |    34 +-
 misc/cgo/errors/test.bash                          |    15 +-
 misc/cgo/fortran/answer.f90                        |     9 +
 misc/cgo/fortran/fortran.go                        |    12 +
 misc/cgo/fortran/fortran_test.go                   |    13 +
 misc/cgo/fortran/helloworld/helloworld.f90         |     3 +
 misc/cgo/fortran/test.bash                         |    39 +
 misc/cgo/gmp/fib.go                                |     2 +-
 misc/cgo/gmp/gmp.go                                |     2 +-
 misc/cgo/gmp/pi.go                                 |     2 +-
 misc/cgo/life/c-life.c                             |     2 +-
 misc/cgo/life/life.go                              |     2 +-
 misc/cgo/life/life.h                               |     2 +-
 misc/cgo/life/main.go                              |     2 +-
 misc/cgo/stdio/chain.go                            |     2 +-
 misc/cgo/stdio/fib.go                              |     2 +-
 misc/cgo/stdio/file.go                             |     2 +-
 misc/cgo/stdio/hello.go                            |     2 +-
 misc/cgo/stdio/stdio.go                            |     2 +-
 misc/cgo/test/api.go                               |     2 +-
 misc/cgo/test/basic.go                             |     2 +-
 misc/cgo/test/buildid_linux.go                     |     2 +-
 misc/cgo/test/callback_c.c                         |     4 +-
 misc/cgo/test/callback_c_gc.c                      |     2 +-
 misc/cgo/test/callback_c_gccgo.c                   |     2 +-
 misc/cgo/test/cflags.go                            |     2 +-
 misc/cgo/test/cgo_linux_test.go                    |    11 +-
 misc/cgo/test/cgo_stubs_android_test.go            |    13 +
 misc/cgo/test/cgo_test.go                          |     3 +-
 misc/cgo/test/cgo_unix_test.go                     |     3 +-
 misc/cgo/test/cthread.go                           |     6 +-
 misc/cgo/test/cthread_unix.c                       |     2 +-
 misc/cgo/test/cthread_windows.c                    |     2 +-
 misc/cgo/test/duplicate_symbol.go                  |     2 +-
 misc/cgo/test/exports.go                           |     2 +-
 misc/cgo/test/fpvar.go                             |     2 +-
 misc/cgo/test/gcc68255.go                          |     2 +-
 misc/cgo/test/gcc68255/a.go                        |     2 +-
 misc/cgo/test/gcc68255/c.c                         |     2 +-
 misc/cgo/test/gcc68255/c.h                         |     2 +-
 misc/cgo/test/helpers.go                           |     2 +-
 misc/cgo/test/issue10303.go                        |     2 +-
 misc/cgo/test/issue11925.go                        |     2 +-
 misc/cgo/test/issue12030.go                        |     2 +-
 misc/cgo/test/issue1222.go                         |     2 +-
 misc/cgo/test/issue1328.go                         |     2 +-
 misc/cgo/test/issue13402.go                        |     2 +-
 misc/cgo/test/issue13930.go                        |    13 +
 misc/cgo/test/issue14838.go                        |    37 +
 misc/cgo/test/issue1560.go                         |     2 +-
 misc/cgo/test/issue1635.go                         |     2 +-
 misc/cgo/test/issue2462.go                         |     2 +-
 misc/cgo/test/issue3250.go                         |     4 +-
 misc/cgo/test/issue3250w.go                        |     2 +-
 misc/cgo/test/issue3261.go                         |     2 +-
 misc/cgo/test/issue3729.go                         |     2 +-
 misc/cgo/test/issue3729w.go                        |     2 +-
 misc/cgo/test/issue3741.go                         |     2 +-
 misc/cgo/test/issue3775.go                         |     2 +
 misc/cgo/test/issue3945.go                         |     2 +-
 misc/cgo/test/issue4029.c                          |     2 +-
 misc/cgo/test/issue4029.go                         |     2 +-
 misc/cgo/test/issue4029w.go                        |     2 +-
 misc/cgo/test/issue4273.c                          |     2 +-
 misc/cgo/test/issue4273b.c                         |     2 +-
 misc/cgo/test/issue4339.go                         |     2 +-
 misc/cgo/test/issue4417.go                         |     2 +-
 misc/cgo/test/issue4857.go                         |     2 +-
 misc/cgo/test/issue5227.go                         |     2 +-
 misc/cgo/test/issue5242.go                         |     2 +-
 misc/cgo/test/issue5337.go                         |     2 +-
 misc/cgo/test/issue5337w.go                        |     2 +-
 misc/cgo/test/issue5548.go                         |     2 +-
 misc/cgo/test/issue5548_c.c                        |     2 +-
 misc/cgo/test/issue5603.go                         |     2 +-
 misc/cgo/test/issue5740.go                         |     2 +-
 misc/cgo/test/issue5740a.c                         |     2 +-
 misc/cgo/test/issue5740b.c                         |     2 +-
 misc/cgo/test/issue5986.go                         |     5 +-
 misc/cgo/test/issue6128.go                         |     2 +-
 misc/cgo/test/issue6390.go                         |     2 +-
 misc/cgo/test/issue6472.go                         |     2 +-
 misc/cgo/test/issue6506.go                         |     2 +-
 misc/cgo/test/issue6612.go                         |     2 +-
 misc/cgo/test/issue6833.go                         |     2 +-
 misc/cgo/test/issue6833_c.c                        |     2 +-
 misc/cgo/test/issue6997_linux.c                    |     4 +-
 misc/cgo/test/issue6997_linux.go                   |     4 +-
 misc/cgo/test/issue7234_test.go                    |     2 +-
 misc/cgo/test/issue7560.go                         |     2 +-
 misc/cgo/test/issue7665.go                         |     2 +-
 misc/cgo/test/issue7786.go                         |     2 +-
 misc/cgo/test/issue7978.go                         |     5 +-
 misc/cgo/test/issue8092.go                         |     2 +-
 misc/cgo/test/issue8148.go                         |     2 +-
 misc/cgo/test/issue8331.h                          |     2 +-
 misc/cgo/test/issue8331a.go                        |     2 +-
 misc/cgo/test/issue8331b.go                        |     2 +-
 misc/cgo/test/issue8428.go                         |     2 +-
 misc/cgo/test/issue8441.go                         |     2 +-
 misc/cgo/test/issue8694.go                         |     4 +-
 misc/cgo/test/issue8811.c                          |     2 +-
 misc/cgo/test/issue8811.go                         |     2 +-
 misc/cgo/test/issue8828/issue8828.c                |     2 +-
 misc/cgo/test/issue8945.go                         |     2 +-
 misc/cgo/test/issue9400/asm_386.s                  |     7 +-
 misc/cgo/test/issue9400/asm_amd64x.s               |     2 +-
 misc/cgo/test/issue9400/asm_arm.s                  |     2 +-
 misc/cgo/test/issue9400/asm_arm64.s                |     2 +-
 misc/cgo/test/issue9400/asm_mips64x.s              |    33 +
 misc/cgo/test/issue9400/asm_ppc64x.s               |     2 +-
 misc/cgo/test/issue9400/asm_s390x.s                |    26 +
 misc/cgo/test/issue9400/gccgo.go                   |     2 +-
 misc/cgo/test/issue9400/stubs.go                   |     2 +-
 misc/cgo/test/issue9400_linux.go                   |     2 +-
 misc/cgo/test/issue9510.go                         |     2 +-
 misc/cgo/test/issue9557.go                         |     2 +-
 misc/cgo/test/setgid_linux.go                      |     2 +-
 misc/cgo/test/sigaltstack.go                       |     2 +-
 misc/cgo/test/sigprocmask.c                        |    38 +
 misc/cgo/test/sigprocmask.go                       |    40 +
 misc/cgo/test/sigprocmask_linux.c                  |    36 -
 misc/cgo/test/sigprocmask_linux.go                 |    38 -
 misc/cgo/test/sleep_windows_386.go                 |    20 -
 misc/cgo/testcarchive/carchive_test.go             |   489 +
 misc/cgo/testcarchive/main.c                       |    41 +-
 misc/cgo/testcarchive/main4.c                      |    16 +-
 misc/cgo/testcarchive/main5.c                      |    78 +
 misc/cgo/testcarchive/main_unix.c                  |    53 +
 misc/cgo/testcarchive/main_windows.c               |    17 +
 misc/cgo/testcarchive/src/libgo2/libgo2.go         |     5 +
 misc/cgo/testcarchive/test.bash                    |   106 -
 misc/cgo/testcshared/test.bash                     |     4 +-
 misc/cgo/testgodefs/anonunion.go                   |     2 +-
 misc/cgo/testgodefs/issue8478.go                   |     2 +-
 misc/cgo/testgodefs/main.go                        |     2 +-
 misc/cgo/testsanitizers/msan.go                    |     2 +-
 misc/cgo/testsanitizers/msan2.go                   |     2 +-
 misc/cgo/testsanitizers/msan4.go                   |     2 +-
 misc/cgo/testsanitizers/msan_fail.go               |     2 +-
 misc/cgo/testsanitizers/test.bash                  |   145 +-
 misc/cgo/testsanitizers/tsan.go                    |    44 +
 misc/cgo/testsanitizers/tsan2.go                   |    55 +
 misc/cgo/testsanitizers/tsan3.go                   |    40 +
 misc/cgo/testsanitizers/tsan4.go                   |    34 +
 misc/cgo/testsanitizers/tsan5.go                   |    51 +
 misc/cgo/testsanitizers/tsan6.go                   |    49 +
 misc/cgo/testshared/shared_test.go                 |   110 +-
 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               |    10 +-
 misc/cgo/testshared/src/dep3/dep3.go               |    22 +
 misc/cgo/testshared/src/depBase/asm.s              |    10 +
 misc/cgo/testshared/src/depBase/dep.go             |    22 +
 misc/cgo/testshared/src/depBase/gccgo.go           |     5 +
 misc/cgo/testshared/src/depBase/stubs.go           |     5 +
 misc/cgo/testshared/src/exe/exe.go                 |     6 +-
 misc/cgo/testshared/src/exe2/exe2.go               |     3 +-
 misc/cgo/testshared/src/exe3/exe3.go               |     7 +
 misc/cgo/testtls/tls.go                            |     2 +-
 misc/cgo/testtls/tls_unix.c                        |     2 +-
 misc/git/pre-commit                                |     2 +-
 misc/ios/go_darwin_arm_exec.go                     |    44 +-
 misc/nacl/mkzip.go                                 |     2 +-
 misc/nacl/testzip.proto                            |    30 +-
 misc/swig/callback/callback.cc                     |     2 +-
 misc/swig/callback/callback.go                     |     2 +-
 misc/swig/callback/callback.h                      |     2 +-
 misc/swig/callback/callback.swigcxx                |     2 +-
 misc/swig/callback/callback_test.go                |     2 +-
 misc/swig/stdio/file.swig                          |     2 +-
 misc/swig/stdio/file_test.go                       |     2 +-
 misc/trace/README.md                               |    12 +-
 misc/trace/trace_viewer_lean.html                  |  8773 ++++++---
 src/androidtest.bash                               |     2 +-
 src/archive/tar/common.go                          |    37 +-
 src/archive/tar/format.go                          |   197 +
 src/archive/tar/reader.go                          |   190 +-
 src/archive/tar/writer.go                          |   106 +-
 src/archive/tar/writer_test.go                     |    22 +-
 src/archive/zip/reader.go                          |    13 +-
 src/archive/zip/reader_test.go                     |     2 +-
 src/archive/zip/register.go                        |    40 +-
 src/archive/zip/struct.go                          |     2 +-
 src/archive/zip/writer.go                          |     2 +-
 src/archive/zip/writer_test.go                     |     8 +-
 src/archive/zip/zip_test.go                        |    21 -
 src/bootstrap.bash                                 |     2 +-
 src/bufio/bufio.go                                 |    33 +-
 src/bufio/bufio_test.go                            |     6 +-
 src/bufio/scan_test.go                             |     6 +-
 src/buildall.bash                                  |     8 +-
 src/bytes/buffer.go                                |    18 +-
 src/bytes/bytes.go                                 |    28 +-
 src/bytes/bytes_decl.go                            |     2 +-
 src/bytes/bytes_test.go                            |   427 +-
 src/bytes/compare_test.go                          |     2 +-
 src/bytes/equal_test.go                            |     4 +-
 src/bytes/reader.go                                |    20 +-
 src/bytes/reader_test.go                           |    50 +-
 src/cmd/api/goapi.go                               |    16 +-
 src/cmd/api/goapi_test.go                          |     4 +-
 src/cmd/api/run.go                                 |     4 +-
 src/cmd/asm/doc.go                                 |     2 +-
 src/cmd/asm/internal/arch/amd64.go                 |    28 +
 src/cmd/asm/internal/arch/arch.go                  |   113 +-
 src/cmd/asm/internal/arch/arm.go                   |    16 +-
 src/cmd/asm/internal/arch/arm64.go                 |     4 +-
 src/cmd/asm/internal/arch/mips64.go                |     9 +-
 src/cmd/asm/internal/arch/ppc64.go                 |    11 +-
 src/cmd/asm/internal/arch/s390x.go                 |   139 +
 src/cmd/asm/internal/asm/asm.go                    |   144 +-
 src/cmd/asm/internal/asm/endtoend_test.go          |    11 +-
 src/cmd/asm/internal/asm/operand_test.go           |   108 +-
 src/cmd/asm/internal/asm/parse.go                  |    70 +-
 src/cmd/asm/internal/asm/pseudo_test.go            |     9 +-
 src/cmd/asm/internal/asm/testdata/amd64.s          |    16 +-
 src/cmd/asm/internal/asm/testdata/amd64enc.s       |   368 +-
 src/cmd/asm/internal/asm/testdata/amd64error.s     |     5 +-
 src/cmd/asm/internal/asm/testdata/arm.s            |     2 +-
 src/cmd/asm/internal/asm/testdata/arm64.s          |     4 +-
 src/cmd/asm/internal/asm/testdata/mips64.s         |     3 +-
 src/cmd/asm/internal/asm/testdata/ppc64.s          |     2 +-
 src/cmd/asm/internal/asm/testdata/s390x.s          |   223 +
 src/cmd/asm/internal/flags/flags.go                |     4 +-
 src/cmd/asm/internal/lex/input.go                  |     2 +-
 src/cmd/asm/internal/lex/lex.go                    |     2 +-
 src/cmd/asm/main.go                                |    35 +-
 src/cmd/cgo/ast.go                                 |    29 +-
 src/cmd/cgo/doc.go                                 |    42 +-
 src/cmd/cgo/gcc.go                                 |   245 +-
 src/cmd/cgo/godefs.go                              |     2 +-
 src/cmd/cgo/main.go                                |    27 +-
 src/cmd/cgo/out.go                                 |   224 +-
 src/cmd/cgo/util.go                                |    51 +-
 src/cmd/compile/doc.go                             |     9 +-
 src/cmd/compile/internal/amd64/galign.go           |    72 +-
 src/cmd/compile/internal/amd64/ggen.go             |    63 +-
 src/cmd/compile/internal/amd64/gsubr.go            |    42 +-
 src/cmd/compile/internal/amd64/peep.go             |   165 +-
 src/cmd/compile/internal/amd64/prog.go             |   452 +-
 src/cmd/compile/internal/amd64/reg.go              |     5 +-
 src/cmd/compile/internal/amd64/ssa.go              |  1074 ++
 src/cmd/compile/internal/arm/cgen.go               |     4 +-
 src/cmd/compile/internal/arm/cgen64.go             |    14 +-
 src/cmd/compile/internal/arm/galign.go             |    39 +-
 src/cmd/compile/internal/arm/ggen.go               |    65 +-
 src/cmd/compile/internal/arm/gsubr.go              |    33 +-
 src/cmd/compile/internal/arm/peep.go               |   229 +-
 src/cmd/compile/internal/arm/prog.go               |   160 +-
 src/cmd/compile/internal/arm/reg.go                |     2 +-
 src/cmd/compile/internal/arm/ssa.go                |   154 +
 src/cmd/compile/internal/arm64/cgen.go             |     6 +-
 src/cmd/compile/internal/arm64/galign.go           |    35 +-
 src/cmd/compile/internal/arm64/ggen.go             |   112 +-
 src/cmd/compile/internal/arm64/gsubr.go            |    50 +-
 src/cmd/compile/internal/arm64/peep.go             |   156 +-
 src/cmd/compile/internal/arm64/prog.go             |   161 +-
 src/cmd/compile/internal/arm64/reg.go              |     4 +-
 src/cmd/compile/internal/big/arith_decl.go         |     2 +-
 src/cmd/compile/internal/big/arith_test.go         |    17 +-
 src/cmd/compile/internal/big/example_rat_test.go   |    65 +
 src/cmd/compile/internal/big/float.go              |   278 +-
 src/cmd/compile/internal/big/float_test.go         |    80 +-
 src/cmd/compile/internal/big/floatconv.go          |     2 +-
 .../compile/internal}/big/floatmarsh.go            |     0
 .../compile/internal}/big/floatmarsh_test.go       |     0
 src/cmd/compile/internal/big/ftoa.go               |    15 +-
 src/cmd/compile/internal/big/intconv.go            |    18 +-
 src/cmd/compile/internal/big/intmarsh.go           |    74 +
 src/cmd/compile/internal/big/intmarsh_test.go      |   121 +
 src/cmd/compile/internal/big/nat.go                |     4 +-
 src/cmd/compile/internal/big/rat.go                |     4 +-
 src/cmd/compile/internal/big/ratconv.go            |     4 +-
 src/cmd/compile/internal/big/ratconv_test.go       |     2 +-
 src/cmd/compile/internal/big/ratmarsh.go           |    73 +
 src/cmd/compile/internal/big/ratmarsh_test.go      |   125 +
 src/cmd/compile/internal/big/vendor.bash           |     2 +-
 src/cmd/compile/internal/gc/alg.go                 |   596 +
 src/cmd/compile/internal/gc/align.go               |   444 +-
 src/cmd/compile/internal/gc/asm_test.go            |   159 +
 src/cmd/compile/internal/gc/bexport.go             |  1643 +-
 src/cmd/compile/internal/gc/bimport.go             |  1043 +-
 src/cmd/compile/internal/gc/builtin.go             |   265 +-
 src/cmd/compile/internal/gc/builtin/runtime.go     |    45 +-
 src/cmd/compile/internal/gc/builtin/unsafe.go      |     4 +-
 src/cmd/compile/internal/gc/builtin_test.go        |    31 +
 src/cmd/compile/internal/gc/bv.go                  |    79 +-
 src/cmd/compile/internal/gc/cgen.go                |   537 +-
 src/cmd/compile/internal/gc/closure.go             |   359 +-
 src/cmd/compile/internal/gc/const.go               |   709 +-
 src/cmd/compile/internal/gc/constFold_test.go      | 18108 ++++++++++++++++++
 src/cmd/compile/internal/gc/cplx.go                |    16 +-
 src/cmd/compile/internal/gc/dcl.go                 |   808 +-
 src/cmd/compile/internal/gc/esc.go                 |   885 +-
 src/cmd/compile/internal/gc/export.go              |   182 +-
 src/cmd/compile/internal/gc/fixedbugs_test.go      |    50 +
 src/cmd/compile/internal/gc/fmt.go                 |   744 +-
 src/cmd/compile/internal/gc/gen.go                 |   337 +-
 src/cmd/compile/internal/gc/global_test.go         |    61 +-
 src/cmd/compile/internal/gc/go.go                  |   589 +-
 src/cmd/compile/internal/gc/gsubr.go               |   243 +-
 src/cmd/compile/internal/gc/init.go                |   106 +-
 src/cmd/compile/internal/gc/inl.go                 |   626 +-
 src/cmd/compile/internal/gc/lex.go                 |  2999 +--
 src/cmd/compile/internal/gc/lex_test.go            |    79 +
 src/cmd/compile/internal/gc/logic_test.go          |   289 +
 src/cmd/compile/internal/gc/magic.go               |   220 +
 src/cmd/compile/internal/gc/main.go                |   933 +
 src/cmd/compile/internal/gc/mkbuiltin.go           |   123 +-
 src/cmd/compile/internal/gc/mparith2.go            |   306 -
 src/cmd/compile/internal/gc/mparith3.go            |   251 -
 src/cmd/compile/internal/gc/mpfloat.go             |   269 +
 src/cmd/compile/internal/gc/mpint.go               |   309 +
 src/cmd/compile/internal/gc/obj.go                 |   381 +-
 src/cmd/compile/internal/gc/opnames.go             |     5 +-
 src/cmd/compile/internal/gc/order.go               |   717 +-
 src/cmd/compile/internal/gc/parser.go              |  1177 +-
 src/cmd/compile/internal/gc/pgen.go                |   249 +-
 src/cmd/compile/internal/gc/pgen_test.go           |    65 +-
 src/cmd/compile/internal/gc/plive.go               |   665 +-
 src/cmd/compile/internal/gc/popt.go                |   121 +-
 src/cmd/compile/internal/gc/racewalk.go            |   129 +-
 src/cmd/compile/internal/gc/range.go               |   213 +-
 src/cmd/compile/internal/gc/reflect.go             |  1047 +-
 src/cmd/compile/internal/gc/reg.go                 |    38 +-
 src/cmd/compile/internal/gc/select.go              |   219 +-
 src/cmd/compile/internal/gc/shift_test.go          |  1031 +
 src/cmd/compile/internal/gc/sinit.go               |   728 +-
 src/cmd/compile/internal/gc/sizeof_test.go         |    56 +
 .../internal/gc/sparselocatephifunctions.go        |   199 +
 src/cmd/compile/internal/gc/ssa.go                 |  4468 +++++
 src/cmd/compile/internal/gc/ssa_test.go            |   105 +
 src/cmd/compile/internal/gc/subr.go                |  2247 +--
 src/cmd/compile/internal/gc/swt.go                 |   378 +-
 src/cmd/compile/internal/gc/syntax.go              |   445 +-
 .../compile/internal/gc/testdata/addressed_ssa.go  |   207 +
 src/cmd/compile/internal/gc/testdata/append_ssa.go |    70 +
 .../internal/gc/testdata/arithBoundary_ssa.go      |   735 +
 .../compile/internal/gc/testdata/arithConst_ssa.go | 15211 +++++++++++++++
 src/cmd/compile/internal/gc/testdata/arith_ssa.go  |   580 +
 src/cmd/compile/internal/gc/testdata/array_ssa.go  |   142 +
 src/cmd/compile/internal/gc/testdata/assert_ssa.go |   147 +
 src/cmd/compile/internal/gc/testdata/break_ssa.go  |   255 +
 src/cmd/compile/internal/gc/testdata/chan_ssa.go   |    73 +
 .../compile/internal/gc/testdata/closure_ssa.go    |    38 +
 src/cmd/compile/internal/gc/testdata/cmp_ssa.go    |    48 +
 .../compile/internal/gc/testdata/compound_ssa.go   |   143 +
 src/cmd/compile/internal/gc/testdata/copy_ssa.go   |   695 +
 src/cmd/compile/internal/gc/testdata/ctl_ssa.go    |   160 +
 .../internal/gc/testdata/deferNoReturn_ssa.go      |    17 +
 .../compile/internal/gc/testdata/divbyzero_ssa.go  |    58 +
 src/cmd/compile/internal/gc/testdata/dupLoad.go    |    83 +
 src/cmd/compile/internal/gc/testdata/fp_ssa.go     |  1702 ++
 .../internal/gc/testdata/gen/arithBoundaryGen.go   |   214 +
 .../internal/gc/testdata/gen/arithConstGen.go      |   302 +
 .../internal/gc/testdata/gen/constFoldGen.go       |   307 +
 .../compile/internal/gc/testdata/gen/copyGen.go    |    93 +
 .../compile/internal/gc/testdata/gen/zeroGen.go    |    88 +
 .../compile/internal/gc/testdata/loadstore_ssa.go  |   115 +
 src/cmd/compile/internal/gc/testdata/map_ssa.go    |    45 +
 .../compile/internal/gc/testdata/namedReturn.go    |   105 +
 src/cmd/compile/internal/gc/testdata/phi_ssa.go    |   103 +
 .../compile/internal/gc/testdata/regalloc_ssa.go   |    57 +
 src/cmd/compile/internal/gc/testdata/short_ssa.go  |    60 +
 src/cmd/compile/internal/gc/testdata/slice.go      |    50 +
 src/cmd/compile/internal/gc/testdata/string_ssa.go |   160 +
 src/cmd/compile/internal/gc/testdata/unsafe_ssa.go |   148 +
 src/cmd/compile/internal/gc/testdata/zero_ssa.go   |   538 +
 src/cmd/compile/internal/gc/type.go                |  1224 ++
 src/cmd/compile/internal/gc/typecheck.go           |  1977 +-
 src/cmd/compile/internal/gc/universe.go            |   466 +
 src/cmd/compile/internal/gc/unsafe.go              |   106 +-
 src/cmd/compile/internal/gc/util.go                |     4 +
 src/cmd/compile/internal/gc/walk.go                |  2392 +--
 src/cmd/compile/internal/mips64/cgen.go            |     6 +-
 src/cmd/compile/internal/mips64/galign.go          |    43 +-
 src/cmd/compile/internal/mips64/ggen.go            |    53 +-
 src/cmd/compile/internal/mips64/gsubr.go           |    48 +-
 src/cmd/compile/internal/mips64/peep.go            |   156 +-
 src/cmd/compile/internal/mips64/prog.go            |   178 +-
 src/cmd/compile/internal/mips64/reg.go             |     4 +-
 src/cmd/compile/internal/ppc64/cgen.go             |     6 +-
 src/cmd/compile/internal/ppc64/galign.go           |    49 +-
 src/cmd/compile/internal/ppc64/ggen.go             |    63 +-
 src/cmd/compile/internal/ppc64/gsubr.go            |    77 +-
 src/cmd/compile/internal/ppc64/opt.go              |     4 +-
 src/cmd/compile/internal/ppc64/peep.go             |   187 +-
 src/cmd/compile/internal/ppc64/prog.go             |   361 +-
 src/cmd/compile/internal/ppc64/reg.go              |     6 +-
 src/cmd/compile/internal/s390x/cgen.go             |   178 +
 src/cmd/compile/internal/s390x/galign.go           |    66 +
 src/cmd/compile/internal/s390x/ggen.go             |   577 +
 src/cmd/compile/internal/s390x/gsubr.go            |  1110 ++
 src/cmd/compile/internal/s390x/peep.go             |  1664 ++
 src/cmd/compile/internal/s390x/prog.go             |   179 +
 src/cmd/compile/internal/s390x/reg.go              |   130 +
 src/cmd/compile/internal/ssa/TODO                  |    46 +
 src/cmd/compile/internal/ssa/block.go              |   203 +
 src/cmd/compile/internal/ssa/check.go              |   330 +
 src/cmd/compile/internal/ssa/checkbce.go           |    23 +
 src/cmd/compile/internal/ssa/compile.go            |   362 +
 src/cmd/compile/internal/ssa/config.go             |   284 +
 src/cmd/compile/internal/ssa/copyelim.go           |    82 +
 src/cmd/compile/internal/ssa/copyelim_test.go      |    41 +
 src/cmd/compile/internal/ssa/critical.go           |   116 +
 src/cmd/compile/internal/ssa/cse.go                |   322 +
 src/cmd/compile/internal/ssa/cse_test.go           |   124 +
 src/cmd/compile/internal/ssa/deadcode.go           |   273 +
 src/cmd/compile/internal/ssa/deadcode_test.go      |   161 +
 src/cmd/compile/internal/ssa/deadstore.go          |   116 +
 src/cmd/compile/internal/ssa/deadstore_test.go     |    97 +
 src/cmd/compile/internal/ssa/decompose.go          |   271 +
 src/cmd/compile/internal/ssa/dom.go                |   314 +
 src/cmd/compile/internal/ssa/dom_test.go           |   572 +
 src/cmd/compile/internal/ssa/export_test.go        |    88 +
 src/cmd/compile/internal/ssa/flagalloc.go          |   137 +
 src/cmd/compile/internal/ssa/func.go               |   429 +
 src/cmd/compile/internal/ssa/func_test.go          |   467 +
 src/cmd/compile/internal/ssa/fuse.go               |   148 +
 src/cmd/compile/internal/ssa/fuse_test.go          |   169 +
 src/cmd/compile/internal/ssa/gen/AMD64.rules       |  1566 ++
 src/cmd/compile/internal/ssa/gen/AMD64Ops.go       |   555 +
 src/cmd/compile/internal/ssa/gen/ARM.rules         |    32 +
 src/cmd/compile/internal/ssa/gen/ARMOps.go         |    68 +
 src/cmd/compile/internal/ssa/gen/README            |     7 +
 src/cmd/compile/internal/ssa/gen/dec.rules         |    92 +
 src/cmd/compile/internal/ssa/gen/decOps.go         |    20 +
 src/cmd/compile/internal/ssa/gen/generic.rules     |   834 +
 src/cmd/compile/internal/ssa/gen/genericOps.go     |   453 +
 src/cmd/compile/internal/ssa/gen/main.go           |   300 +
 src/cmd/compile/internal/ssa/gen/rulegen.go        |   721 +
 src/cmd/compile/internal/ssa/html.go               |   471 +
 src/cmd/compile/internal/ssa/id.go                 |    28 +
 src/cmd/compile/internal/ssa/layout.go             |   103 +
 src/cmd/compile/internal/ssa/likelyadjust.go       |   449 +
 src/cmd/compile/internal/ssa/location.go           |    38 +
 src/cmd/compile/internal/ssa/loopbce.go            |   299 +
 src/cmd/compile/internal/ssa/lower.go              |    34 +
 src/cmd/compile/internal/ssa/magic.go              |   260 +
 src/cmd/compile/internal/ssa/nilcheck.go           |   161 +
 src/cmd/compile/internal/ssa/nilcheck_test.go      |   443 +
 src/cmd/compile/internal/ssa/op.go                 |   126 +
 src/cmd/compile/internal/ssa/opGen.go              |  5442 ++++++
 src/cmd/compile/internal/ssa/opt.go                |    14 +
 src/cmd/compile/internal/ssa/passbm_test.go        |   101 +
 src/cmd/compile/internal/ssa/phielim.go            |    69 +
 src/cmd/compile/internal/ssa/phiopt.go             |   114 +
 src/cmd/compile/internal/ssa/print.go              |   150 +
 src/cmd/compile/internal/ssa/prove.go              |   644 +
 src/cmd/compile/internal/ssa/redblack32.go         |   429 +
 src/cmd/compile/internal/ssa/redblack32_test.go    |   276 +
 src/cmd/compile/internal/ssa/regalloc.go           |  2360 +++
 src/cmd/compile/internal/ssa/regalloc_test.go      |    33 +
 src/cmd/compile/internal/ssa/rewrite.go            |   386 +
 src/cmd/compile/internal/ssa/rewriteAMD64.go       | 18956 +++++++++++++++++++
 src/cmd/compile/internal/ssa/rewriteARM.go         |   288 +
 src/cmd/compile/internal/ssa/rewrite_test.go       |   102 +
 src/cmd/compile/internal/ssa/rewritedec.go         |   507 +
 src/cmd/compile/internal/ssa/rewritegeneric.go     | 10385 ++++++++++
 src/cmd/compile/internal/ssa/schedule.go           |   232 +
 src/cmd/compile/internal/ssa/schedule_test.go      |    57 +
 src/cmd/compile/internal/ssa/shift_test.go         |    48 +
 src/cmd/compile/internal/ssa/shortcircuit.go       |   133 +
 src/cmd/compile/internal/ssa/shortcircuit_test.go  |    50 +
 src/cmd/compile/internal/ssa/sizeof_test.go        |    39 +
 src/cmd/compile/internal/ssa/sparsemap.go          |    85 +
 src/cmd/compile/internal/ssa/sparseset.go          |    79 +
 src/cmd/compile/internal/ssa/sparsetree.go         |   186 +
 src/cmd/compile/internal/ssa/sparsetreemap.go      |   169 +
 src/cmd/compile/internal/ssa/stackalloc.go         |   409 +
 src/cmd/compile/internal/ssa/tighten.go            |    88 +
 src/cmd/compile/internal/ssa/trim.go               |    32 +
 src/cmd/compile/internal/ssa/type.go               |   125 +
 src/cmd/compile/internal/ssa/type_test.go          |   101 +
 src/cmd/compile/internal/ssa/value.go              |   270 +
 src/cmd/compile/internal/ssa/zcse.go               |    82 +
 src/cmd/compile/internal/test/README               |     4 +
 src/cmd/compile/internal/test/divconst_test.go     |    73 +
 src/cmd/compile/internal/test/test.go              |     1 +
 src/cmd/compile/internal/x86/cgen.go               |     2 +-
 src/cmd/compile/internal/x86/cgen64.go             |    18 +-
 src/cmd/compile/internal/x86/galign.go             |    32 +-
 src/cmd/compile/internal/x86/ggen.go               |    44 +-
 src/cmd/compile/internal/x86/gsubr.go              |    51 +-
 src/cmd/compile/internal/x86/peep.go               |   115 +-
 src/cmd/compile/internal/x86/prog.go               |   416 +-
 src/cmd/compile/internal/x86/reg.go                |     4 +-
 src/cmd/compile/main.go                            |     5 +-
 src/cmd/cover/cover.go                             |    20 +-
 src/cmd/cover/cover_test.go                        |     2 +-
 src/cmd/cover/testdata/test.go                     |    30 +
 src/cmd/dist/build.go                              |   105 +-
 src/cmd/dist/buildgo.go                            |    64 +-
 src/cmd/dist/buildruntime.go                       |     4 +-
 src/cmd/dist/buildtool.go                          |    14 +-
 src/cmd/dist/cpuid_386.s                           |     2 +-
 src/cmd/dist/cpuid_amd64.s                         |     2 +-
 src/cmd/dist/cpuid_default.s                       |     2 +-
 src/cmd/dist/deps.go                               |     5 +-
 src/cmd/dist/main.go                               |     3 +-
 src/cmd/dist/sys_default.go                        |     2 +-
 src/cmd/dist/sys_windows.go                        |     2 +-
 src/cmd/dist/test.go                               |   152 +-
 src/cmd/dist/util.go                               |    42 +-
 src/cmd/dist/util_gc.go                            |     2 +-
 src/cmd/dist/util_gccgo.go                         |     2 +-
 src/cmd/dist/vfp_arm.s                             |     2 +-
 src/cmd/dist/vfp_default.s                         |     2 +-
 src/cmd/doc/doc_test.go                            |    16 +-
 src/cmd/doc/pkg.go                                 |    74 +-
 src/cmd/doc/testdata/pkg.go                        |    10 +-
 src/cmd/fix/fix.go                                 |     2 +-
 src/cmd/fix/gotypes.go                             |     2 +-
 src/cmd/fix/gotypes_test.go                        |     2 +-
 src/cmd/fix/import_test.go                         |     2 +-
 src/cmd/fix/main.go                                |     2 +-
 src/cmd/fix/main_test.go                           |     2 +-
 src/cmd/fix/netipv6zone.go                         |     2 +-
 src/cmd/fix/netipv6zone_test.go                    |     2 +-
 src/cmd/fix/printerconfig.go                       |     2 +-
 src/cmd/fix/printerconfig_test.go                  |     2 +-
 src/cmd/fix/typecheck.go                           |    16 +-
 src/cmd/go/alldocs.go                              |  3152 +--
 src/cmd/go/bootstrap.go                            |     2 +-
 src/cmd/go/build.go                                |   435 +-
 src/cmd/go/clean.go                                |     2 +-
 src/cmd/go/context.go                              |     3 +-
 src/cmd/go/discovery.go                            |     2 +-
 src/cmd/go/doc.go                                  |     4 +-
 src/cmd/go/env.go                                  |     8 +-
 src/cmd/go/fix.go                                  |     2 +-
 src/cmd/go/fmt.go                                  |     2 +-
 src/cmd/go/generate.go                             |    19 +-
 src/cmd/go/generate_test.go                        |     2 +-
 src/cmd/go/get.go                                  |    39 +-
 src/cmd/go/go11.go                                 |     2 +-
 src/cmd/go/go_test.go                              |   491 +-
 src/cmd/go/go_unix_test.go                         |     2 +-
 src/cmd/go/help.go                                 |    35 +-
 src/cmd/go/http.go                                 |     4 +-
 src/cmd/go/list.go                                 |     7 +-
 src/cmd/go/main.go                                 |    79 +-
 src/cmd/go/match_test.go                           |     2 +-
 src/cmd/go/mkalldocs.sh                            |     5 +-
 src/cmd/go/note.go                                 |     6 +-
 src/cmd/go/note_test.go                            |     4 +-
 src/cmd/go/pkg.go                                  |   155 +-
 src/cmd/go/pkg_test.go                             |     7 +-
 src/cmd/go/run.go                                  |     4 +-
 src/cmd/go/tag_test.go                             |     2 +-
 src/cmd/go/test.go                                 |   102 +-
 src/cmd/go/testdata/dep_test.go                    |     2 +-
 src/cmd/go/testdata/example1_test.go               |     2 +-
 src/cmd/go/testdata/example2_test.go               |     2 +-
 src/cmd/go/testdata/generate/test1.go              |     2 +-
 src/cmd/go/testdata/generate/test2.go              |     2 +-
 src/cmd/go/testdata/generate/test3.go              |     2 +-
 src/cmd/go/testdata/generate/test4.go              |     2 +-
 src/cmd/go/testdata/src/benchfatal/x_test.go       |     7 +
 src/cmd/go/testflag.go                             |     4 +-
 src/cmd/go/testgo.go                               |     2 +-
 src/cmd/go/tool.go                                 |     2 +-
 src/cmd/go/vcs.go                                  |   120 +-
 src/cmd/go/vcs_test.go                             |   178 +-
 src/cmd/go/vendor_test.go                          |    19 +-
 src/cmd/go/version.go                              |     2 +-
 src/cmd/go/vet.go                                  |     2 +-
 src/cmd/gofmt/gofmt.go                             |     4 +-
 src/cmd/gofmt/gofmt_test.go                        |     4 +-
 src/cmd/gofmt/internal.go                          |     6 +-
 src/cmd/gofmt/rewrite.go                           |     4 +-
 src/cmd/gofmt/simplify.go                          |    28 +-
 src/cmd/gofmt/testdata/slices2.golden              |    63 -
 src/cmd/gofmt/testdata/slices2.input               |    63 -
 src/cmd/internal/bio/buf.go                        |    99 +
 src/cmd/internal/bio/must.go                       |    43 +
 src/cmd/internal/gcprog/gcprog.go                  |     2 +-
 src/cmd/internal/goobj/read.go                     |    81 +-
 src/cmd/internal/goobj/read_test.go                |     2 +-
 src/cmd/internal/obj/ar.go                         |    15 -
 src/cmd/internal/obj/arm/a.out.go                  |     2 +-
 src/cmd/internal/obj/arm/asm5.go                   |   172 +-
 src/cmd/internal/obj/arm/list5.go                  |     2 +-
 src/cmd/internal/obj/arm/obj5.go                   |    45 +-
 src/cmd/internal/obj/arm64/a.out.go                |     6 +-
 src/cmd/internal/obj/arm64/anames7.go              |     4 +
 src/cmd/internal/obj/arm64/asm7.go                 |   809 +-
 src/cmd/internal/obj/arm64/list7.go                |     6 +-
 src/cmd/internal/obj/arm64/obj7.go                 |    51 +-
 src/cmd/internal/obj/data.go                       |   160 +-
 src/cmd/internal/obj/flag.go                       |     7 +-
 src/cmd/internal/obj/fmt.go                        |    28 -
 src/cmd/internal/obj/funcdata.go                   |     2 +-
 src/cmd/internal/obj/go.go                         |    29 +-
 src/cmd/internal/obj/ld.go                         |     2 +-
 src/cmd/internal/obj/line_test.go                  |     6 +-
 src/cmd/internal/obj/link.go                       |   384 +-
 src/cmd/internal/obj/mips/a.out.go                 |     9 +-
 src/cmd/internal/obj/mips/anames.go                |     1 +
 src/cmd/internal/obj/mips/anames0.go               |     6 +
 src/cmd/internal/obj/mips/asm0.go                  |   467 +-
 src/cmd/internal/obj/mips/list0.go                 |     6 +-
 src/cmd/internal/obj/mips/obj0.go                  |    50 +-
 src/cmd/internal/obj/obj.go                        |    56 +-
 src/cmd/internal/obj/objfile.go                    |   725 +-
 src/cmd/internal/obj/pass.go                       |    15 +-
 src/cmd/internal/obj/pcln.go                       |    87 +-
 src/cmd/internal/obj/plist.go                      |   218 +
 src/cmd/internal/obj/ppc64/a.out.go                |     7 +-
 src/cmd/internal/obj/ppc64/anames.go               |     5 +
 src/cmd/internal/obj/ppc64/anames9.go              |     4 +
 src/cmd/internal/obj/ppc64/asm9.go                 |   946 +-
 src/cmd/internal/obj/ppc64/list9.go                |     2 +-
 src/cmd/internal/obj/ppc64/obj9.go                 |    63 +-
 src/cmd/internal/obj/s390x/a.out.go                |   896 +
 src/cmd/internal/obj/s390x/anames.go               |   651 +
 src/cmd/internal/obj/s390x/anamesz.go              |    39 +
 src/cmd/internal/obj/s390x/asmz.go                 |  4645 +++++
 src/cmd/internal/obj/s390x/listz.go                |    73 +
 src/cmd/internal/obj/s390x/objz.go                 |  1008 +
 src/cmd/internal/obj/s390x/vector.go               |  1061 ++
 src/cmd/internal/obj/sizeof_test.go                |    40 +
 src/cmd/internal/obj/stack.go                      |     2 +-
 src/cmd/internal/obj/sym.go                        |    34 +-
 src/cmd/internal/obj/textflag.go                   |     9 +-
 src/cmd/internal/obj/util.go                       |   234 +-
 src/cmd/internal/obj/x86/a.out.go                  |    91 +-
 src/cmd/internal/obj/x86/anames.go                 |    51 +-
 src/cmd/internal/obj/x86/asm6.go                   |   985 +-
 src/cmd/internal/obj/x86/list6.go                  |     2 +-
 src/cmd/internal/obj/x86/obj6.go                   |   164 +-
 src/cmd/internal/obj/x86/obj6_test.go              |     5 +-
 src/cmd/internal/objfile/disasm.go                 |     7 +-
 src/cmd/internal/objfile/elf.go                    |    18 +-
 src/cmd/internal/objfile/goobj.go                  |    14 +-
 src/cmd/internal/objfile/macho.go                  |    11 +-
 src/cmd/internal/objfile/objfile.go                |    18 +-
 src/cmd/internal/objfile/pe.go                     |    13 +-
 src/cmd/internal/objfile/plan9obj.go               |    14 +-
 src/cmd/internal/pprof/commands/commands.go        |   244 +
 src/cmd/internal/pprof/driver/driver.go            |  1041 +
 src/cmd/internal/pprof/driver/interactive.go       |   492 +
 src/cmd/internal/pprof/fetch/fetch.go              |    82 +
 src/cmd/internal/pprof/plugin/plugin.go            |   213 +
 src/cmd/internal/pprof/profile/encode.go           |   470 +
 .../internal => internal/pprof}/profile/filter.go  |     0
 src/cmd/internal/pprof/profile/legacy_profile.go   |  1236 ++
 src/cmd/internal/pprof/profile/profile.go          |   572 +
 .../pprof}/profile/profile_test.go                 |     0
 src/cmd/internal/pprof/profile/proto.go            |   360 +
 src/cmd/internal/pprof/profile/proto_test.go       |    67 +
 src/cmd/internal/pprof/profile/prune.go            |    97 +
 src/cmd/internal/pprof/report/report.go            |  1684 ++
 src/cmd/internal/pprof/report/source.go            |   454 +
 .../pprof}/report/source_html.go                   |     0
 .../{pprof/internal => internal/pprof}/svg/svg.go  |     0
 .../internal => internal/pprof}/svg/svgpan.go      |     0
 src/cmd/internal/pprof/symbolizer/symbolizer.go    |   195 +
 src/cmd/internal/pprof/symbolz/symbolz.go          |   111 +
 src/cmd/internal/pprof/tempfile/tempfile.go        |    46 +
 src/cmd/internal/sys/arch.go                       |   148 +
 .../golang.org/x/arch/arm/armasm/decode.go         |   567 -
 .../golang.org/x/arch/x86/x86asm/decode.go         |  1646 --
 .../golang.org/x/arch/x86/x86asm/plan9x.go         |   346 -
 .../x/arch/x86/x86asm/testdata/decode.txt          |  6731 -------
 src/cmd/link/internal/amd64/asm.go                 |    84 +-
 src/cmd/link/internal/amd64/l.go                   |     8 +-
 src/cmd/link/internal/amd64/obj.go                 |    30 +-
 src/cmd/link/internal/amd64/z.go                   |     1 -
 src/cmd/link/internal/arm/asm.go                   |    93 +-
 src/cmd/link/internal/arm/l.go                     |     7 +-
 src/cmd/link/internal/arm/obj.go                   |    17 +-
 src/cmd/link/internal/arm64/asm.go                 |    64 +-
 src/cmd/link/internal/arm64/l.go                   |     7 +-
 src/cmd/link/internal/arm64/obj.go                 |    15 +-
 src/cmd/link/internal/ld/ar.go                     |    31 +-
 src/cmd/link/internal/ld/arch.go                   |    88 -
 src/cmd/link/internal/ld/data.go                   |  1159 +-
 src/cmd/link/internal/ld/deadcode.go               |   342 +
 src/cmd/link/internal/ld/decodesym.go              |   241 +-
 src/cmd/link/internal/ld/dwarf.go                  |  1771 +-
 src/cmd/link/internal/ld/dwarf_defs.go             |     2 +-
 src/cmd/link/internal/ld/elf.go                    |   526 +-
 src/cmd/link/internal/ld/go.go                     |   306 +-
 src/cmd/link/internal/ld/ld.go                     |     2 +-
 src/cmd/link/internal/ld/ldelf.go                  |   228 +-
 src/cmd/link/internal/ld/ldmacho.go                |   107 +-
 src/cmd/link/internal/ld/ldpe.go                   |    68 +-
 src/cmd/link/internal/ld/lib.go                    |   596 +-
 src/cmd/link/internal/ld/link.go                   |   159 +-
 src/cmd/link/internal/ld/macho.go                  |   162 +-
 src/cmd/link/internal/ld/macho_combine_dwarf.go    |     4 +-
 src/cmd/link/internal/ld/objfile.go                |   608 +-
 src/cmd/link/internal/ld/pcln.go                   |   164 +-
 src/cmd/link/internal/ld/pe.go                     |   281 +-
 src/cmd/link/internal/ld/pobj.go                   |    68 +-
 src/cmd/link/internal/ld/sym.go                    |   104 +-
 src/cmd/link/internal/ld/symtab.go                 |   229 +-
 src/cmd/link/internal/ld/util.go                   |    13 +-
 src/cmd/link/internal/mips64/asm.go                |   147 +-
 src/cmd/link/internal/mips64/l.go                  |     7 +-
 src/cmd/link/internal/mips64/obj.go                |    27 +-
 src/cmd/link/internal/ppc64/asm.go                 |    99 +-
 src/cmd/link/internal/ppc64/l.go                   |     7 +-
 src/cmd/link/internal/ppc64/obj.go                 |    26 +-
 src/cmd/link/internal/s390x/asm.go                 |   595 +
 src/cmd/link/internal/s390x/l.go                   |    74 +
 src/cmd/link/internal/s390x/obj.go                 |   114 +
 src/cmd/link/internal/x86/asm.go                   |    81 +-
 src/cmd/link/internal/x86/l.go                     |     6 +-
 src/cmd/link/internal/x86/obj.go                   |    17 +-
 src/cmd/link/link_test.go                          |    30 +
 src/cmd/link/main.go                               |     5 +-
 src/cmd/nm/nm.go                                   |     2 +-
 src/cmd/objdump/objdump_test.go                    |     4 +
 src/cmd/pack/pack.go                               |     6 +-
 src/cmd/pprof/doc.go                               |     2 +-
 src/cmd/pprof/internal/commands/commands.go        |   243 -
 src/cmd/pprof/internal/driver/driver.go            |  1041 -
 src/cmd/pprof/internal/driver/interactive.go       |   492 -
 src/cmd/pprof/internal/fetch/fetch.go              |    82 -
 src/cmd/pprof/internal/plugin/plugin.go            |   213 -
 src/cmd/pprof/internal/profile/encode.go           |   470 -
 src/cmd/pprof/internal/profile/legacy_profile.go   |  1251 --
 src/cmd/pprof/internal/profile/profile.go          |   572 -
 src/cmd/pprof/internal/profile/proto.go            |   298 -
 src/cmd/pprof/internal/profile/prune.go            |    97 -
 src/cmd/pprof/internal/report/report.go            |  1718 --
 src/cmd/pprof/internal/report/source.go            |   454 -
 src/cmd/pprof/internal/symbolizer/symbolizer.go    |   195 -
 src/cmd/pprof/internal/symbolz/symbolz.go          |   111 -
 src/cmd/pprof/internal/tempfile/tempfile.go        |    45 -
 src/cmd/pprof/pprof.go                             |   156 +-
 src/cmd/trace/main.go                              |    72 +-
 src/cmd/trace/pprof.go                             |    80 +-
 src/cmd/trace/trace.go                             |   183 +-
 .../golang.org/x/arch/arm/armasm/Makefile          |     0
 .../vendor/golang.org/x/arch/arm/armasm/decode.go  |   567 +
 .../golang.org/x/arch/arm/armasm/decode_test.go    |     0
 .../golang.org/x/arch/arm/armasm/ext_test.go       |     0
 .../golang.org/x/arch/arm/armasm/gnu.go            |     0
 .../golang.org/x/arch/arm/armasm/inst.go           |     0
 .../golang.org/x/arch/arm/armasm/objdump_test.go   |     0
 .../x/arch/arm/armasm/objdumpext_test.go           |     0
 .../golang.org/x/arch/arm/armasm/plan9x.go         |     0
 .../golang.org/x/arch/arm/armasm/tables.go         |     0
 .../golang.org/x/arch/arm/armasm/testdata/Makefile |     0
 .../x/arch/arm/armasm/testdata/decode.txt          |     0
 .../golang.org/x/arch/x86/x86asm/Makefile          |     0
 .../vendor/golang.org/x/arch/x86/x86asm/decode.go  |  1646 ++
 .../golang.org/x/arch/x86/x86asm/decode_test.go    |     0
 .../golang.org/x/arch/x86/x86asm/ext_test.go       |     0
 .../golang.org/x/arch/x86/x86asm/gnu.go            |     0
 .../golang.org/x/arch/x86/x86asm/inst.go           |     0
 .../golang.org/x/arch/x86/x86asm/inst_test.go      |     0
 .../golang.org/x/arch/x86/x86asm/intel.go          |     0
 .../golang.org/x/arch/x86/x86asm/objdump_test.go   |     0
 .../x/arch/x86/x86asm/objdumpext_test.go           |     0
 .../golang.org/x/arch/x86/x86asm/plan9ext_test.go  |     0
 .../vendor/golang.org/x/arch/x86/x86asm/plan9x.go  |   350 +
 .../golang.org/x/arch/x86/x86asm/plan9x_test.go    |     0
 .../golang.org/x/arch/x86/x86asm/tables.go         |     0
 .../golang.org/x/arch/x86/x86asm/testdata/Makefile |     0
 .../x/arch/x86/x86asm/testdata/decode.txt          |  6733 +++++++
 .../x/arch/x86/x86asm/testdata/libmach8db.c        |     0
 .../golang.org/x/arch/x86/x86asm/xed_test.go       |     0
 .../golang.org/x/arch/x86/x86asm/xedext_test.go    |     0
 src/cmd/{internal/unvendor => vendor}/vendor.json  |     0
 src/cmd/vet/README                                 |    33 +
 src/cmd/vet/asmdecl.go                             |    22 +-
 src/cmd/vet/atomic.go                              |     3 +
 src/cmd/vet/buildtag.go                            |     2 +-
 src/cmd/vet/cgo.go                                 |     6 +-
 src/cmd/vet/composite.go                           |   104 +-
 src/cmd/vet/copylock.go                            |    95 +-
 src/cmd/vet/deadcode.go                            |     4 +-
 src/cmd/vet/doc.go                                 |    39 +-
 src/cmd/vet/example.go                             |   124 -
 src/cmd/vet/internal/cfg/builder.go                |   512 +
 src/cmd/vet/internal/cfg/cfg.go                    |   142 +
 src/cmd/vet/internal/cfg/cfg_test.go               |   190 +
 src/cmd/vet/internal/whitelist/whitelist.go        |    35 +-
 src/cmd/vet/lostcancel.go                          |   318 +
 src/cmd/vet/main.go                                |    48 +-
 src/cmd/vet/method.go                              |     6 +-
 src/cmd/vet/print.go                               |   213 +-
 src/cmd/vet/rangeloop.go                           |     4 +
 src/cmd/vet/shadow.go                              |     4 +-
 src/cmd/vet/structtag.go                           |     2 +-
 src/cmd/vet/testdata/asm.go                        |     2 +
 src/cmd/vet/testdata/asm1.s                        |    11 +
 src/cmd/vet/testdata/asm5.s                        |   193 +
 src/cmd/vet/testdata/atomic.go                     |     9 +
 src/cmd/vet/testdata/buildtag.go                   |     2 +-
 src/cmd/vet/testdata/composite.go                  |    56 +-
 src/cmd/vet/testdata/copylock.go                   |   114 +-
 src/cmd/vet/testdata/copylock_func.go              |    41 +-
 src/cmd/vet/testdata/divergent/buf_test.go         |    12 +-
 src/cmd/vet/testdata/examples_test.go              |    48 -
 src/cmd/vet/testdata/lostcancel.go                 |   155 +
 src/cmd/vet/testdata/print.go                      |    95 +-
 src/cmd/vet/testdata/rangeloop.go                  |     9 +
 src/cmd/vet/testdata/shadow.go                     |     8 +-
 src/cmd/vet/testdata/tests_test.go                 |    74 +
 src/cmd/vet/testdata/unsafeptr.go                  |     2 +-
 src/cmd/vet/tests.go                               |   187 +
 src/cmd/vet/types.go                               |    89 -
 src/cmd/vet/unsafeptr.go                           |     2 +-
 src/cmd/vet/vet_test.go                            |    14 +-
 src/cmd/yacc/doc.go                                |     2 +-
 src/cmd/yacc/testdata/expr/expr.y                  |     4 +-
 src/cmd/yacc/yacc.go                               |    16 +-
 src/cmp.bash                                       |    61 +
 src/compress/bzip2/bzip2.go                        |    17 +-
 src/compress/bzip2/bzip2_test.go                   |   563 +-
 src/compress/bzip2/testdata/fail-issue5747.bz2     |   Bin 0 -> 7232 bytes
 src/compress/bzip2/testdata/pass-random1.bin       |   Bin 0 -> 1024 bytes
 src/compress/bzip2/testdata/pass-random1.bz2       |   Bin 0 -> 1309 bytes
 src/compress/bzip2/testdata/pass-random2.bin       |     1 +
 src/compress/bzip2/testdata/pass-random2.bz2       |   Bin 0 -> 125 bytes
 src/compress/bzip2/testdata/pass-sawtooth.bz2      |   Bin 0 -> 2017 bytes
 src/compress/flate/copy.go                         |    32 -
 src/compress/flate/copy_test.go                    |    54 -
 src/compress/flate/deflate.go                      |   372 +-
 src/compress/flate/deflate_test.go                 |   165 +-
 src/compress/flate/deflatefast.go                  |   174 +
 src/compress/flate/dict_decoder.go                 |   184 +
 src/compress/flate/dict_decoder_test.go            |   139 +
 src/compress/flate/flate_test.go                   |    78 +
 src/compress/flate/huffman_bit_writer.go           |   524 +-
 src/compress/flate/huffman_bit_writer_test.go      |   366 +
 src/compress/flate/huffman_code.go                 |   119 +-
 src/compress/flate/inflate.go                      |   227 +-
 src/compress/flate/inflate_test.go                 |    30 +
 src/compress/flate/reader_test.go                  |   126 +-
 src/compress/flate/reverse_bits.go                 |     2 +-
 .../flate/testdata/huffman-null-max.dyn.expect     |   Bin 0 -> 78 bytes
 .../testdata/huffman-null-max.dyn.expect-noinput   |   Bin 0 -> 78 bytes
 .../flate/testdata/huffman-null-max.golden         |   Bin 0 -> 8204 bytes
 src/compress/flate/testdata/huffman-null-max.in    |   Bin 0 -> 65535 bytes
 .../flate/testdata/huffman-null-max.wb.expect      |   Bin 0 -> 78 bytes
 .../testdata/huffman-null-max.wb.expect-noinput    |   Bin 0 -> 78 bytes
 src/compress/flate/testdata/huffman-pi.dyn.expect  |   Bin 0 -> 1696 bytes
 .../flate/testdata/huffman-pi.dyn.expect-noinput   |   Bin 0 -> 1696 bytes
 src/compress/flate/testdata/huffman-pi.golden      |   Bin 0 -> 1606 bytes
 src/compress/flate/testdata/huffman-pi.in          |     1 +
 src/compress/flate/testdata/huffman-pi.wb.expect   |   Bin 0 -> 1696 bytes
 .../flate/testdata/huffman-pi.wb.expect-noinput    |   Bin 0 -> 1696 bytes
 .../flate/testdata/huffman-rand-1k.dyn.expect      |   Bin 0 -> 1005 bytes
 .../testdata/huffman-rand-1k.dyn.expect-noinput    |   Bin 0 -> 1054 bytes
 src/compress/flate/testdata/huffman-rand-1k.golden |   Bin 0 -> 1005 bytes
 src/compress/flate/testdata/huffman-rand-1k.in     |   Bin 0 -> 1000 bytes
 .../flate/testdata/huffman-rand-1k.wb.expect       |   Bin 0 -> 1005 bytes
 .../testdata/huffman-rand-1k.wb.expect-noinput     |   Bin 0 -> 1054 bytes
 .../flate/testdata/huffman-rand-limit.dyn.expect   |   Bin 0 -> 229 bytes
 .../testdata/huffman-rand-limit.dyn.expect-noinput |   Bin 0 -> 229 bytes
 .../flate/testdata/huffman-rand-limit.golden       |   Bin 0 -> 252 bytes
 src/compress/flate/testdata/huffman-rand-limit.in  |     4 +
 .../flate/testdata/huffman-rand-limit.wb.expect    |   Bin 0 -> 186 bytes
 .../testdata/huffman-rand-limit.wb.expect-noinput  |   Bin 0 -> 186 bytes
 .../flate/testdata/huffman-rand-max.golden         |   Bin 0 -> 65540 bytes
 src/compress/flate/testdata/huffman-rand-max.in    |   Bin 0 -> 65535 bytes
 .../flate/testdata/huffman-shifts.dyn.expect       |   Bin 0 -> 32 bytes
 .../testdata/huffman-shifts.dyn.expect-noinput     |   Bin 0 -> 32 bytes
 src/compress/flate/testdata/huffman-shifts.golden  |   Bin 0 -> 1812 bytes
 src/compress/flate/testdata/huffman-shifts.in      |     2 +
 .../flate/testdata/huffman-shifts.wb.expect        |   Bin 0 -> 32 bytes
 .../testdata/huffman-shifts.wb.expect-noinput      |   Bin 0 -> 32 bytes
 .../flate/testdata/huffman-text-shift.dyn.expect   |   Bin 0 -> 231 bytes
 .../testdata/huffman-text-shift.dyn.expect-noinput |   Bin 0 -> 231 bytes
 .../flate/testdata/huffman-text-shift.golden       |   Bin 0 -> 231 bytes
 src/compress/flate/testdata/huffman-text-shift.in  |    14 +
 .../flate/testdata/huffman-text-shift.wb.expect    |   Bin 0 -> 231 bytes
 .../testdata/huffman-text-shift.wb.expect-noinput  |   Bin 0 -> 231 bytes
 .../flate/testdata/huffman-text.dyn.expect         |     1 +
 .../flate/testdata/huffman-text.dyn.expect-noinput |     1 +
 src/compress/flate/testdata/huffman-text.golden    |     3 +
 src/compress/flate/testdata/huffman-text.in        |    13 +
 src/compress/flate/testdata/huffman-text.wb.expect |     1 +
 .../flate/testdata/huffman-text.wb.expect-noinput  |     1 +
 .../flate/testdata/huffman-zero.dyn.expect         |   Bin 0 -> 17 bytes
 .../flate/testdata/huffman-zero.dyn.expect-noinput |   Bin 0 -> 17 bytes
 src/compress/flate/testdata/huffman-zero.golden    |   Bin 0 -> 51 bytes
 src/compress/flate/testdata/huffman-zero.in        |     1 +
 src/compress/flate/testdata/huffman-zero.wb.expect |   Bin 0 -> 6 bytes
 .../flate/testdata/huffman-zero.wb.expect-noinput  |   Bin 0 -> 6 bytes
 .../testdata/null-long-match.dyn.expect-noinput    |   Bin 0 -> 206 bytes
 .../testdata/null-long-match.wb.expect-noinput     |   Bin 0 -> 206 bytes
 src/compress/flate/token.go                        |     3 -
 src/compress/flate/writer_test.go                  |   192 +-
 src/compress/gzip/gunzip.go                        |   216 +-
 src/compress/gzip/gunzip_test.go                   |   112 +-
 src/compress/gzip/gzip.go                          |    43 +-
 src/compress/gzip/issue14937_test.go               |    59 +
 src/compress/gzip/testdata/issue6550.gz            |   Bin 65536 -> 65536 bytes
 src/compress/lzw/reader_test.go                    |    61 +-
 src/compress/lzw/writer.go                         |     2 +-
 src/compress/lzw/writer_test.go                    |    55 +-
 src/compress/zlib/reader.go                        |    57 +-
 src/compress/zlib/reader_test.go                   |    16 +-
 src/container/heap/heap.go                         |     2 +-
 src/container/heap/heap_test.go                    |     2 +-
 src/container/list/list_test.go                    |     2 +-
 src/context/context.go                             |   473 +
 src/context/context_test.go                        |   608 +
 src/context/withtimeout_test.go                    |    33 +
 src/crypto/aes/aes_gcm.go                          |     5 +-
 src/crypto/aes/aes_test.go                         |    36 -
 src/crypto/aes/asm_s390x.s                         |    93 +
 src/crypto/aes/block.go                            |     2 +-
 src/crypto/aes/cbc_s390x.go                        |    59 +
 src/crypto/aes/cipher.go                           |    18 +-
 src/crypto/aes/cipher_amd64.go                     |    83 +
 src/crypto/aes/cipher_asm.go                       |    48 -
 src/crypto/aes/cipher_generic.go                   |    27 +-
 src/crypto/aes/cipher_s390x.go                     |    90 +
 src/crypto/aes/ctr_s390x.go                        |    76 +
 src/crypto/aes/gcm_amd64.s                         |    32 +-
 src/crypto/aes/modes.go                            |    37 +
 src/crypto/aes/modes_test.go                       |   112 +
 src/crypto/cipher/cbc.go                           |    22 +
 src/crypto/cipher/cipher.go                        |     4 +-
 src/crypto/cipher/cipher_test.go                   |     2 +-
 src/crypto/cipher/ctr.go                           |    10 +
 src/crypto/cipher/example_test.go                  |     7 +-
 src/crypto/cipher/xor.go                           |     2 +-
 src/crypto/cipher/xor_test.go                      |     2 +-
 src/crypto/des/block.go                            |     2 +-
 src/crypto/dsa/dsa.go                              |    14 +-
 src/crypto/ecdsa/ecdsa.go                          |    19 +-
 src/crypto/ecdsa/ecdsa_test.go                     |    25 +-
 src/crypto/elliptic/p224.go                        |     2 +-
 src/crypto/elliptic/p224_test.go                   |     2 +-
 src/crypto/elliptic/p256.go                        |     6 +-
 src/crypto/elliptic/p256_amd64.go                  |    10 +-
 src/crypto/hmac/hmac.go                            |    34 +-
 src/crypto/hmac/hmac_test.go                       |    26 +
 src/crypto/md5/gen.go                              |     2 +-
 src/crypto/md5/md5.go                              |     2 +-
 src/crypto/md5/md5block_arm.s                      |     2 +-
 src/crypto/md5/md5block_decl.go                    |     4 +-
 src/crypto/md5/md5block_generic.go                 |     2 +-
 src/crypto/md5/md5block_ppc64le.s                  |   192 +
 src/crypto/md5/md5block_s390x.s                    |   175 +
 src/crypto/rand/eagain.go                          |     2 +-
 src/crypto/rand/example_test.go                    |     2 +-
 src/crypto/rand/rand.go                            |     5 +-
 src/crypto/rand/rand_linux.go                      |     2 +-
 src/crypto/rand/rand_openbsd.go                    |    28 +
 src/crypto/rand/rand_test.go                       |     2 +-
 src/crypto/rand/rand_unix.go                       |     4 +-
 src/crypto/rand/rand_windows.go                    |     2 +-
 src/crypto/rand/util.go                            |     4 +-
 src/crypto/rand/util_test.go                       |     2 +-
 src/crypto/rc4/rc4.go                              |     4 +-
 src/crypto/rsa/pkcs1v15.go                         |    73 +-
 src/crypto/rsa/pss.go                              |     8 +-
 src/crypto/rsa/rsa.go                              |    37 +-
 src/crypto/sha1/fallback_test.go                   |    34 +
 src/crypto/sha1/issue15617_test.go                 |    28 +
 src/crypto/sha1/sha1.go                            |     2 +-
 src/crypto/sha1/sha1_test.go                       |    25 +-
 src/crypto/sha1/sha1block_386.s                    |     2 +-
 src/crypto/sha1/sha1block_amd64.go                 |    34 +
 src/crypto/sha1/sha1block_amd64.s                  |  1303 +-
 src/crypto/sha1/sha1block_amd64p32.s               |     2 +-
 src/crypto/sha1/sha1block_arm.s                    |     2 +-
 src/crypto/sha1/sha1block_decl.go                  |     4 +-
 src/crypto/sha1/sha1block_generic.go               |     2 +-
 src/crypto/sha1/sha1block_s390x.go                 |    12 +
 src/crypto/sha1/sha1block_s390x.s                  |    34 +
 src/crypto/sha256/fallback_test.go                 |    35 +
 src/crypto/sha256/sha256.go                        |     2 +-
 src/crypto/sha256/sha256_test.go                   |    15 +-
 src/crypto/sha256/sha256block.go                   |     4 +-
 src/crypto/sha256/sha256block_386.s                |     2 +-
 src/crypto/sha256/sha256block_amd64.s              |   871 +-
 src/crypto/sha256/sha256block_decl.go              |     4 +-
 src/crypto/sha256/sha256block_generic.go           |     9 +
 src/crypto/sha256/sha256block_s390x.go             |    12 +
 src/crypto/sha256/sha256block_s390x.s              |    34 +
 src/crypto/sha512/fallback_test.go                 |    37 +
 src/crypto/sha512/sha512.go                        |     2 +-
 src/crypto/sha512/sha512_test.go                   |    15 +-
 src/crypto/sha512/sha512block.go                   |     4 +-
 src/crypto/sha512/sha512block_amd64.s              |     2 +-
 src/crypto/sha512/sha512block_decl.go              |     4 +-
 src/crypto/sha512/sha512block_generic.go           |     9 +
 src/crypto/sha512/sha512block_s390x.go             |    12 +
 src/crypto/sha512/sha512block_s390x.s              |    34 +
 src/crypto/subtle/constant_time.go                 |     2 +-
 src/crypto/tls/alert.go                            |     4 +-
 src/crypto/tls/cipher_suites.go                    |    10 +-
 src/crypto/tls/common.go                           |    76 +-
 src/crypto/tls/conn.go                             |   352 +-
 src/crypto/tls/conn_test.go                        |   125 +
 src/crypto/tls/handshake_client.go                 |   243 +-
 src/crypto/tls/handshake_client_test.go            |   433 +-
 src/crypto/tls/handshake_messages.go               |   136 +-
 src/crypto/tls/handshake_server.go                 |   122 +-
 src/crypto/tls/handshake_server_test.go            |   192 +-
 src/crypto/tls/key_agreement.go                    |    22 +-
 src/crypto/tls/prf.go                              |     2 +-
 .../tls/testdata/Client-TLSv12-RenegotiateOnce     |   251 +
 .../tls/testdata/Client-TLSv12-RenegotiateTwice    |   409 +
 .../Client-TLSv12-RenegotiateTwiceRejected         |   255 +
 .../testdata/Client-TLSv12-RenegotiationRejected   |    97 +
 src/crypto/tls/ticket.go                           |     6 +-
 src/crypto/tls/tls.go                              |    59 +-
 src/crypto/tls/tls_test.go                         |   257 +-
 src/crypto/x509/cert_pool.go                       |    24 +-
 src/crypto/x509/example_test.go                    |    43 +
 src/crypto/x509/pem_decrypt.go                     |     2 +-
 src/crypto/x509/pkcs1.go                           |    11 +-
 src/crypto/x509/pkcs8.go                           |     6 +-
 src/crypto/x509/pkix/pkix.go                       |     2 +-
 src/crypto/x509/root.go                            |     9 +-
 src/crypto/x509/root_cgo_darwin.go                 |    88 +-
 src/crypto/x509/root_darwin_arm_gen.go             |     7 +-
 src/crypto/x509/root_darwin_armx.go                |     7 +-
 src/crypto/x509/root_darwin_test.go                |     2 +-
 src/crypto/x509/root_nocgo_darwin.go               |     4 +-
 src/crypto/x509/root_plan9.go                      |    18 +-
 src/crypto/x509/root_unix.go                       |    23 +-
 src/crypto/x509/root_windows.go                    |     5 +-
 src/crypto/x509/sec1.go                            |    14 +-
 src/crypto/x509/sec1_test.go                       |     4 +-
 src/crypto/x509/verify.go                          |    16 +-
 src/crypto/x509/verify_test.go                     |    46 +-
 src/crypto/x509/x509.go                            |    49 +-
 src/crypto/x509/x509_test.go                       |   107 +-
 src/database/sql/convert.go                        |     9 +-
 src/database/sql/convert_test.go                   |    12 +
 src/database/sql/driver/driver.go                  |    10 +-
 src/database/sql/driver/types.go                   |    21 +-
 src/database/sql/fakedb_test.go                    |    11 +-
 src/database/sql/sql.go                            |    33 +-
 src/database/sql/sql_test.go                       |    10 +-
 src/debug/dwarf/buf.go                             |    10 +-
 src/debug/dwarf/const.go                           |     2 +-
 src/debug/dwarf/entry.go                           |   132 +-
 src/debug/dwarf/entry_test.go                      |   101 +
 src/debug/dwarf/line.go                            |     4 +-
 src/debug/dwarf/line_test.go                       |     2 +-
 src/debug/dwarf/open.go                            |     6 +-
 src/debug/dwarf/testdata/ranges.c                  |    25 +
 src/debug/dwarf/testdata/ranges.elf                |   Bin 0 -> 10348 bytes
 src/debug/dwarf/testdata/typedef.c                 |     2 +-
 src/debug/dwarf/type.go                            |     8 +-
 src/debug/dwarf/type_test.go                       |     4 +-
 src/debug/dwarf/typeunit.go                        |    10 +-
 src/debug/dwarf/unit.go                            |     2 +-
 src/debug/elf/elf.go                               |   146 +-
 src/debug/elf/elf_test.go                          |     2 +-
 src/debug/elf/file.go                              |    97 +-
 src/debug/elf/file_test.go                         |    31 +-
 src/debug/elf/reader.go                            |     8 +-
 .../testdata/go-relocation-test-gcc531-s390x.obj   |   Bin 0 -> 3864 bytes
 src/debug/elf/testdata/hello-world-core.gz         |   Bin 12678 -> 12678 bytes
 src/debug/gosym/pclntab.go                         |    10 +-
 src/debug/gosym/pclntab_test.go                    |    23 +-
 src/debug/gosym/symtab.go                          |    33 +-
 src/debug/gosym/symtab_test.go                     |    43 +
 src/debug/macho/fat.go                             |     8 +-
 src/debug/macho/file.go                            |     8 +-
 src/debug/macho/file_test.go                       |     2 +-
 src/debug/macho/macho.go                           |    25 +-
 src/debug/pe/file.go                               |   218 +-
 src/debug/pe/file_test.go                          |   110 +-
 src/debug/pe/pe.go                                 |    26 +-
 src/debug/pe/section.go                            |   111 +
 src/debug/pe/string.go                             |    66 +
 src/debug/pe/symbol.go                             |    95 +
 .../pe/testdata/gcc-386-mingw-no-symbols-exec      |   Bin 0 -> 8704 bytes
 src/debug/plan9obj/file.go                         |     2 +-
 src/debug/plan9obj/file_test.go                    |     2 +-
 src/debug/plan9obj/plan9obj.go                     |     2 +-
 src/encoding/ascii85/ascii85.go                    |     6 +-
 src/encoding/asn1/asn1.go                          |     7 +-
 src/encoding/asn1/asn1_test.go                     |     4 +-
 src/encoding/asn1/marshal.go                       |     8 +-
 src/encoding/base32/base32.go                      |    10 +-
 src/encoding/base32/base32_test.go                 |     2 +-
 src/encoding/base32/example_test.go                |     2 +-
 src/encoding/base64/base64.go                      |    12 +-
 src/encoding/base64/base64_test.go                 |    47 +-
 src/encoding/base64/example_test.go                |     2 +-
 src/encoding/binary/binary.go                      |    24 +-
 src/encoding/binary/binary_test.go                 |    41 +-
 src/encoding/binary/example_test.go                |     2 +-
 src/encoding/binary/varint.go                      |     2 +-
 src/encoding/csv/reader.go                         |    71 +-
 src/encoding/csv/writer.go                         |    32 +-
 src/encoding/encoding.go                           |     2 +-
 src/encoding/gob/codec_test.go                     |     6 +-
 src/encoding/gob/debug.go                          |     6 +-
 src/encoding/gob/decode.go                         |    24 +-
 src/encoding/gob/decoder.go                        |    10 +-
 src/encoding/gob/doc.go                            |     9 +-
 src/encoding/gob/encode.go                         |    20 +-
 src/encoding/gob/encoder.go                        |     6 +-
 src/encoding/gob/encoder_test.go                   |    92 +-
 src/encoding/gob/error.go                          |     4 +-
 src/encoding/gob/example_interface_test.go         |     2 +-
 src/encoding/gob/example_test.go                   |     2 +-
 src/encoding/gob/gobencdec_test.go                 |     8 +-
 src/encoding/gob/type.go                           |    18 +-
 src/encoding/hex/hex.go                            |     4 +-
 src/encoding/json/bench_test.go                    |     6 +-
 src/encoding/json/decode.go                        |    78 +-
 src/encoding/json/decode_test.go                   |   365 +-
 src/encoding/json/encode.go                        |   263 +-
 src/encoding/json/encode_test.go                   |   127 +-
 src/encoding/json/example_test.go                  |     5 +-
 src/encoding/json/indent.go                        |     2 +-
 src/encoding/json/number_test.go                   |     2 +-
 src/encoding/json/scanner.go                       |     4 +-
 src/encoding/json/scanner_test.go                  |     2 +-
 src/encoding/json/stream.go                        |    56 +-
 src/encoding/json/stream_test.go                   |    68 +-
 src/encoding/json/tagkey_test.go                   |     2 +-
 src/encoding/json/tags_test.go                     |     2 +-
 src/encoding/json/testdata/code.json.gz            |   Bin 120432 -> 120432 bytes
 src/encoding/pem/pem.go                            |     2 +-
 src/encoding/xml/example_test.go                   |     2 +-
 src/encoding/xml/marshal.go                        |    25 +-
 src/encoding/xml/read.go                           |    20 +-
 src/encoding/xml/typeinfo.go                       |     2 +-
 src/encoding/xml/xml.go                            |    17 +-
 src/encoding/xml/xml_test.go                       |     8 +-
 src/errors/errors.go                               |     2 +-
 src/errors/errors_test.go                          |     2 +-
 src/errors/example_test.go                         |     2 +-
 src/expvar/expvar.go                               |    14 +-
 src/expvar/expvar_test.go                          |    18 +-
 src/flag/export_test.go                            |     2 +-
 src/flag/flag.go                                   |    31 +-
 src/fmt/doc.go                                     |    12 +-
 src/fmt/export_test.go                             |     2 +-
 src/fmt/fmt_test.go                                |   781 +-
 src/fmt/format.go                                  |   593 +-
 src/fmt/print.go                                   |   852 +-
 src/fmt/scan.go                                    |   156 +-
 src/fmt/scan_test.go                               |    28 +-
 src/go/ast/ast.go                                  |    10 +-
 src/go/ast/commentmap.go                           |     2 +-
 src/go/ast/import.go                               |     2 +-
 src/go/ast/print.go                                |     7 +-
 src/go/ast/resolve.go                              |     2 +-
 src/go/build/build.go                              |   101 +-
 src/go/build/build_test.go                         |    17 +-
 src/go/build/deps_test.go                          |    59 +-
 src/go/build/doc.go                                |    33 +-
 src/go/build/read.go                               |     5 +-
 src/go/build/read_test.go                          |     2 +-
 src/go/build/syslist.go                            |     2 +-
 src/go/build/syslist_test.go                       |     2 +-
 src/go/constant/value.go                           |     8 +-
 src/go/constant/value_test.go                      |     1 +
 src/go/doc/comment.go                              |     4 +-
 src/go/doc/example.go                              |    30 +-
 src/go/doc/testdata/benchmark.go                   |     8 +-
 src/go/doc/testdata/testing.0.golden               |     4 +-
 src/go/doc/testdata/testing.1.golden               |    10 +-
 src/go/doc/testdata/testing.2.golden               |     4 +-
 src/go/doc/testdata/testing.go                     |    10 +-
 src/go/format/internal.go                          |     6 +-
 src/go/importer/importer.go                        |     2 +-
 src/go/internal/gccgoimporter/importer.go          |     8 +-
 src/go/internal/gcimporter/bimport.go              |   386 +-
 src/go/internal/gcimporter/exportdata.go           |    26 +-
 src/go/internal/gcimporter/gcimporter.go           |     6 +-
 src/go/internal/gcimporter/gcimporter_test.go      |    68 +-
 src/go/internal/gcimporter/testdata/issue15920.go  |    11 +
 src/go/internal/gcimporter/testdata/p.go           |    13 +
 src/go/parser/interface.go                         |    16 +-
 src/go/parser/parser.go                            |    26 +-
 src/go/scanner/scanner.go                          |     8 +-
 src/go/token/position.go                           |     1 +
 src/go/types/api_test.go                           |    83 +
 src/go/types/assignments.go                        |     8 +
 src/go/types/builtins.go                           |     2 +-
 src/go/types/call.go                               |     9 +-
 src/go/types/check.go                              |     4 +-
 src/go/types/decl.go                               |    19 +
 src/go/types/eval.go                               |     4 +-
 src/go/types/expr.go                               |     6 +-
 src/go/types/hilbert_test.go                       |    13 -
 src/go/types/initorder.go                          |    47 +-
 src/go/types/labels.go                             |     2 +-
 src/go/types/object.go                             |     2 +-
 src/go/types/package.go                            |     2 +-
 src/go/types/predicates.go                         |     2 +
 src/go/types/resolver.go                           |     4 +-
 src/go/types/return.go                             |     9 +-
 src/go/types/scope.go                              |     2 +-
 src/go/types/stdlib_test.go                        |    18 +-
 src/go/types/stmt.go                               |    22 +-
 src/go/types/testdata/const0.src                   |     2 +-
 src/go/types/testdata/gotos.src                    |     2 +-
 src/go/types/testdata/issues.src                   |    16 +
 src/go/types/testdata/labels.src                   |     2 +-
 src/go/types/testdata/shifts.src                   |     6 +-
 src/go/types/testdata/stmt0.src                    |    21 +-
 src/go/types/testdata/stmt1.src                    |    76 +
 src/go/types/type.go                               |     2 +-
 src/go/types/universe.go                           |     2 +-
 src/hash/adler32/adler32.go                        |    13 +-
 src/hash/crc32/crc32.go                            |    10 +-
 src/hash/crc32/crc32_amd64.go                      |     8 +-
 src/hash/crc32/crc32_amd64p32.go                   |     8 +-
 src/hash/crc32/crc32_generic.go                    |    14 +-
 src/hash/crc32/crc32_s390x.go                      |   101 +
 src/hash/crc32/crc32_s390x.s                       |   245 +
 src/hash/crc32/crc32_test.go                       |    63 +-
 src/hash/crc64/crc64.go                            |    58 +
 src/hash/crc64/crc64_test.go                       |   114 +-
 src/html/escape.go                                 |     6 +-
 src/html/template/content.go                       |    29 +
 src/html/template/css.go                           |     4 +-
 src/html/template/doc.go                           |     2 +-
 src/html/template/error.go                         |     2 +-
 src/html/template/escape.go                        |    96 +-
 src/html/template/escape_test.go                   |     2 +-
 src/html/template/examplefiles_test.go             |   226 +
 src/html/template/template.go                      |    14 +
 src/html/template/template_test.go                 |     2 +-
 src/html/template/url.go                           |     2 +-
 src/image/color/color.go                           |     2 +-
 src/image/color/palette/gen.go                     |     2 +-
 src/image/color/palette/palette.go                 |     2 +-
 src/image/color/ycbcr.go                           |   110 +-
 src/image/color/ycbcr_test.go                      |    44 +
 src/image/decode_test.go                           |     1 +
 src/image/draw/draw.go                             |    10 +-
 src/image/gif/reader.go                            |    27 +-
 src/image/gif/reader_test.go                       |    80 +-
 src/image/internal/imageutil/gen.go                |    59 +-
 src/image/internal/imageutil/impl.go               |   232 +-
 src/image/jpeg/reader.go                           |     6 +
 src/image/jpeg/scan.go                             |   128 +-
 src/image/png/reader.go                            |     7 +
 src/image/png/reader_test.go                       |    27 +
 .../testdata/video-001.progressive.truncated.jpeg  |   Bin 0 -> 7456 bytes
 .../testdata/video-001.progressive.truncated.png   |   Bin 0 -> 23616 bytes
 .../golang.org/x/net/http2/hpack/encode.go         |   251 -
 src/internal/golang.org/x/net/http2/hpack/hpack.go |   533 -
 .../golang.org/x/net/http2/hpack/hpack_test.go     |   813 -
 .../golang.org/x/net/http2/hpack/huffman.go        |   190 -
 src/internal/nettrace/nettrace.go                  |    45 +
 src/internal/race/doc.go                           |     2 +-
 src/internal/race/norace.go                        |     2 +-
 src/internal/race/race.go                          |     2 +-
 src/internal/singleflight/singleflight.go          |     2 +-
 src/internal/singleflight/singleflight_test.go     |     2 +-
 src/internal/syscall/unix/getentropy_openbsd.go    |    25 +
 src/internal/syscall/unix/getrandom_linux.go       |     2 +-
 src/internal/syscall/unix/getrandom_linux_386.go   |     4 +-
 src/internal/syscall/unix/getrandom_linux_amd64.go |     4 +-
 src/internal/syscall/unix/getrandom_linux_arm.go   |     4 +-
 .../syscall/unix/getrandom_linux_generic.go        |     9 +-
 .../syscall/unix/getrandom_linux_mips64x.go        |     4 +-
 .../syscall/unix/getrandom_linux_ppc64x.go         |     4 +-
 src/internal/syscall/unix/getrandom_linux_s390x.go |     9 +
 .../syscall/windows/registry/registry_test.go      |     4 +-
 src/internal/syscall/windows/registry/syscall.go   |     2 +-
 .../syscall/windows/registry/zsyscall_windows.go   |     8 +-
 src/internal/syscall/windows/syscall_windows.go    |     4 +-
 src/internal/syscall/windows/zsyscall_windows.go   |     8 +-
 src/internal/testenv/testenv.go                    |    43 +-
 src/internal/trace/order.go                        |   278 +
 src/internal/trace/parser.go                       |   510 +-
 src/internal/trace/parser_test.go                  |   115 +-
 src/internal/trace/testdata/http_1_5_good          |   Bin 0 -> 42218 bytes
 src/internal/trace/testdata/stress_1_5_good        |   Bin 0 -> 7446 bytes
 src/internal/trace/testdata/stress_1_5_unordered   |   Bin 0 -> 8194 bytes
 .../trace/testdata/stress_start_stop_1_5_good      |   Bin 0 -> 6997 bytes
 src/io/example_test.go                             |     2 +-
 src/io/io.go                                       |    48 +-
 src/io/io_test.go                                  |     4 +-
 src/io/ioutil/ioutil.go                            |     4 +-
 src/io/ioutil/tempfile.go                          |    10 +-
 src/io/multi.go                                    |     9 +-
 src/io/multi_test.go                               |    34 +-
 src/io/pipe.go                                     |     5 -
 src/log/log.go                                     |    18 +-
 src/log/syslog/syslog.go                           |    42 +-
 src/make.bash                                      |     7 +
 src/make.bat                                       |     4 +
 src/make.rc                                        |     2 +-
 src/math/acosh.go                                  |     2 +-
 src/math/all_test.go                               |     7 -
 src/math/asin_386.s                                |     2 +-
 src/math/asin_amd64.s                              |     2 +-
 src/math/asin_amd64p32.s                           |     2 +-
 src/math/asin_arm.s                                |     2 +-
 src/math/asinh.go                                  |     2 +-
 src/math/atan2_386.s                               |     2 +-
 src/math/atan2_amd64.s                             |     2 +-
 src/math/atan2_amd64p32.s                          |     2 +-
 src/math/atan2_arm.s                               |     2 +-
 src/math/atan_386.s                                |     2 +-
 src/math/atan_amd64.s                              |     2 +-
 src/math/atan_amd64p32.s                           |     2 +-
 src/math/atan_arm.s                                |     2 +-
 src/math/atanh.go                                  |     2 +-
 src/math/big/arith_amd64p32.s                      |     2 +-
 src/math/big/arith_decl.go                         |     2 +-
 src/math/big/arith_decl_pure.go                    |     2 +-
 src/math/big/arith_s390x.s                         |   565 +
 src/math/big/arith_test.go                         |   136 +-
 src/math/big/float.go                              |   274 +-
 src/math/big/float_test.go                         |    80 +-
 src/math/big/floatconv.go                          |     2 +-
 src/math/big/floatconv_test.go                     |     5 +
 src/math/big/floatmarsh.go                         |    89 +-
 src/math/big/floatmarsh_test.go                    |    82 +
 src/math/big/ftoa.go                               |    22 +-
 src/math/big/gcd_test.go                           |    16 +-
 src/math/big/int.go                                |     4 +-
 src/math/big/intconv.go                            |    18 +-
 src/math/big/nat.go                                |    33 +-
 src/math/big/nat_test.go                           |    27 +-
 src/math/big/natconv.go                            |     4 +-
 src/math/big/natconv_test.go                       |   133 +-
 src/math/big/rat.go                                |     4 +-
 src/math/big/ratconv.go                            |    12 +-
 src/math/big/ratconv_test.go                       |     3 +-
 src/math/cmplx/cmath_test.go                       |     7 +-
 src/math/cmplx/sqrt.go                             |     2 +-
 src/math/dim_386.s                                 |     2 +-
 src/math/dim_amd64.s                               |     2 +-
 src/math/dim_amd64p32.s                            |     2 +-
 src/math/dim_arm.s                                 |     2 +-
 src/math/dim_s390x.s                               |   132 +
 src/math/erf.go                                    |     2 +-
 src/math/exp.go                                    |     2 +-
 src/math/exp2_386.s                                |     2 +-
 src/math/exp2_amd64.s                              |     2 +-
 src/math/exp2_amd64p32.s                           |     2 +-
 src/math/exp2_arm.s                                |     2 +-
 src/math/exp_386.s                                 |     2 +-
 src/math/exp_amd64.s                               |     2 +-
 src/math/exp_amd64p32.s                            |     2 +-
 src/math/exp_arm.s                                 |     2 +-
 src/math/expm1.go                                  |     2 +-
 src/math/expm1_386.s                               |     2 +-
 src/math/expm1_amd64.s                             |     2 +-
 src/math/expm1_amd64p32.s                          |     2 +-
 src/math/expm1_arm.s                               |     2 +-
 src/math/export_test.go                            |     2 +-
 src/math/floor_386.s                               |     2 +-
 src/math/floor_amd64.s                             |     2 +-
 src/math/floor_amd64p32.s                          |     2 +-
 src/math/floor_arm.s                               |     2 +-
 src/math/frexp_386.s                               |     2 +-
 src/math/frexp_amd64.s                             |     2 +-
 src/math/frexp_amd64p32.s                          |     2 +-
 src/math/frexp_arm.s                               |     2 +-
 src/math/gamma.go                                  |     2 +-
 src/math/hypot_386.s                               |     2 +-
 src/math/hypot_amd64.s                             |     2 +-
 src/math/hypot_amd64p32.s                          |     2 +-
 src/math/hypot_arm.s                               |     2 +-
 src/math/j0.go                                     |     2 +-
 src/math/j1.go                                     |     2 +-
 src/math/jn.go                                     |     2 +-
 src/math/ldexp_386.s                               |     2 +-
 src/math/ldexp_amd64.s                             |     2 +-
 src/math/ldexp_amd64p32.s                          |     2 +-
 src/math/ldexp_arm.s                               |     2 +-
 src/math/lgamma.go                                 |     2 +-
 src/math/log.go                                    |     2 +-
 src/math/log10_386.s                               |     2 +-
 src/math/log10_amd64.s                             |     2 +-
 src/math/log10_amd64p32.s                          |     2 +-
 src/math/log10_arm.s                               |     2 +-
 src/math/log1p.go                                  |     2 +-
 src/math/log1p_386.s                               |     2 +-
 src/math/log1p_amd64.s                             |     2 +-
 src/math/log1p_amd64p32.s                          |     2 +-
 src/math/log1p_arm.s                               |     2 +-
 src/math/log_386.s                                 |     2 +-
 src/math/log_amd64.s                               |     2 +-
 src/math/log_amd64p32.s                            |     2 +-
 src/math/log_arm.s                                 |     2 +-
 src/math/mod_amd64.s                               |     2 +-
 src/math/mod_amd64p32.s                            |     2 +-
 src/math/mod_arm.s                                 |     2 +-
 src/math/modf.go                                   |     2 +-
 src/math/modf_386.s                                |     2 +-
 src/math/modf_amd64.s                              |     2 +-
 src/math/modf_amd64p32.s                           |     2 +-
 src/math/modf_arm.s                                |     2 +-
 src/math/rand/example_test.go                      |    10 +
 src/math/rand/rand.go                              |    37 +-
 src/math/rand/rand_test.go                         |    40 +-
 src/math/rand/regress_test.go                      |    40 +-
 src/math/remainder.go                              |     2 +-
 src/math/remainder_amd64.s                         |     2 +-
 src/math/remainder_amd64p32.s                      |     2 +-
 src/math/remainder_arm.s                           |     2 +-
 src/math/sin_386.s                                 |     2 +-
 src/math/sin_amd64.s                               |     2 +-
 src/math/sin_amd64p32.s                            |     2 +-
 src/math/sin_arm.s                                 |     2 +-
 src/math/sincos_386.s                              |     2 +-
 src/math/sincos_amd64.s                            |     2 +-
 src/math/sincos_amd64p32.s                         |     2 +-
 src/math/sincos_arm.s                              |     2 +-
 src/math/sqrt.go                                   |     8 +-
 src/math/sqrt_386.s                                |     2 +-
 src/math/sqrt_amd64.s                              |     2 +-
 src/math/sqrt_amd64p32.s                           |     2 +-
 src/math/sqrt_arm.s                                |     2 +-
 src/math/sqrt_arm64.s                              |     2 +-
 src/math/sqrt_ppc64x.s                             |    14 +
 src/math/sqrt_s390x.s                              |    12 +
 src/math/stubs_arm64.s                             |     2 +-
 src/math/stubs_mips64x.s                           |     2 +-
 src/math/stubs_ppc64x.s                            |     5 +-
 src/math/stubs_s390x.s                             |    77 +
 src/math/tan_386.s                                 |     2 +-
 src/math/tan_amd64.s                               |     2 +-
 src/math/tan_amd64p32.s                            |     2 +-
 src/math/tan_arm.s                                 |     2 +-
 src/mime/encodedword.go                            |     8 +-
 src/mime/encodedword_test.go                       |    37 +-
 src/mime/grammar.go                                |     2 +-
 src/mime/mediatype.go                              |     4 +-
 src/mime/multipart/formdata.go                     |     6 +-
 src/mime/multipart/multipart.go                    |     8 +-
 src/mime/multipart/multipart_test.go               |     4 +-
 src/mime/multipart/writer.go                       |    13 +-
 src/mime/multipart/writer_test.go                  |    30 +
 src/mime/type_plan9.go                             |     2 +-
 src/naclmake.bash                                  |    48 +
 src/nacltest.bash                                  |    40 +-
 src/net/addrselect.go                              |     2 +-
 src/net/cgo_android.go                             |     2 +-
 src/net/cgo_bsd.go                                 |     2 +-
 src/net/cgo_linux.go                               |     2 +-
 src/net/cgo_netbsd.go                              |     2 +-
 src/net/cgo_openbsd.go                             |     2 +-
 src/net/cgo_solaris.go                             |     2 +-
 src/net/cgo_stub.go                                |    14 +-
 src/net/cgo_unix.go                                |   138 +-
 src/net/cgo_unix_test.go                           |    66 +-
 src/net/conf.go                                    |    35 +-
 src/net/conf_netcgo.go                             |     2 +-
 src/net/conf_test.go                               |    24 +-
 src/net/conn_test.go                               |     4 +-
 src/net/dial.go                                    |   370 +-
 src/net/dial_gen.go                                |    40 -
 src/net/dial_test.go                               |   483 +-
 src/net/dnsclient.go                               |     4 +-
 src/net/dnsclient_unix.go                          |   225 +-
 src/net/dnsclient_unix_test.go                     |   292 +-
 src/net/dnsconfig_unix.go                          |    76 +-
 src/net/dnsconfig_unix_test.go                     |    82 +-
 src/net/dnsmsg.go                                  |   164 +-
 src/net/dnsmsg_test.go                             |   215 +
 src/net/dnsname_test.go                            |     2 +-
 src/net/error_plan9_test.go                        |     2 +
 src/net/error_posix_test.go                        |    10 -
 src/net/error_test.go                              |    83 +-
 src/net/error_unix_test.go                         |    34 +
 src/net/error_windows_test.go                      |    19 +
 src/net/external_test.go                           |    11 +-
 src/net/fd_mutex.go                                |   101 +-
 src/net/fd_mutex_test.go                           |    72 +-
 src/net/fd_plan9.go                                |    71 +-
 src/net/fd_poll_nacl.go                            |    26 +-
 src/net/fd_poll_runtime.go                         |    44 +-
 src/net/fd_unix.go                                 |   160 +-
 src/net/fd_windows.go                              |   136 +-
 src/net/file_plan9.go                              |     4 +-
 src/net/hook.go                                    |    16 +-
 src/net/hook_windows.go                            |    11 +-
 src/net/hosts.go                                   |     8 +-
 src/net/hosts_test.go                              |    62 +-
 src/net/http/cgi/host.go                           |    12 +-
 src/net/http/cgi/host_test.go                      |    18 +
 src/net/http/cgi/testdata/test.cgi                 |     4 +
 src/net/http/client.go                             |   218 +-
 src/net/http/client_test.go                        |    91 +-
 src/net/http/clientserver_test.go                  |   190 +-
 src/net/http/cookie.go                             |     2 +-
 src/net/http/cookie_test.go                        |     2 +-
 src/net/http/cookiejar/punycode.go                 |     2 +-
 src/net/http/export_test.go                        |    58 +-
 src/net/http/fcgi/fcgi.go                          |     7 -
 src/net/http/filetransport.go                      |     2 +-
 src/net/http/fs.go                                 |    33 +-
 src/net/http/fs_test.go                            |    27 +-
 src/net/http/h2_bundle.go                          |  1689 +-
 src/net/http/header.go                             |    10 +-
 src/net/http/header_test.go                        |     2 +-
 src/net/http/http.go                               |    43 +
 src/net/http/http_test.go                          |    37 +-
 src/net/http/httptest/example_test.go              |     6 +-
 src/net/http/httptest/httptest.go                  |    88 +
 src/net/http/httptest/httptest_test.go             |   177 +
 src/net/http/httptest/recorder.go                  |    98 +-
 src/net/http/httptest/recorder_test.go             |   118 +-
 src/net/http/httptest/server.go                    |    34 +-
 src/net/http/httptest/server_test.go               |     4 +-
 src/net/http/httptrace/trace.go                    |   226 +
 src/net/http/httptrace/trace_test.go               |    62 +
 src/net/http/httputil/dump.go                      |    42 +-
 src/net/http/httputil/dump_test.go                 |    61 +
 src/net/http/httputil/example_test.go              |     2 +-
 src/net/http/httputil/persist.go                   |   173 +-
 src/net/http/httputil/reverseproxy.go              |    20 +-
 src/net/http/httputil/reverseproxy_test.go         |    63 +
 src/net/http/internal/chunked_test.go              |     2 +-
 src/net/http/lex.go                                |   183 -
 src/net/http/lex_test.go                           |   101 -
 src/net/http/main_test.go                          |    23 +-
 src/net/http/method.go                             |     2 +-
 src/net/http/pprof/pprof.go                        |    19 +-
 src/net/http/readrequest_test.go                   |    23 +-
 src/net/http/request.go                            |   277 +-
 src/net/http/request_test.go                       |   106 +-
 src/net/http/requestwrite_test.go                  |     6 +-
 src/net/http/response.go                           |    40 +-
 src/net/http/response_test.go                      |    35 +-
 src/net/http/responsewrite_test.go                 |    35 +-
 src/net/http/serve_test.go                         |   347 +-
 src/net/http/server.go                             |   286 +-
 src/net/http/sniff.go                              |    43 +-
 src/net/http/sniff_test.go                         |    11 +
 src/net/http/status.go                             |   122 +-
 src/net/http/transfer.go                           |    40 +-
 src/net/http/transport.go                          |   906 +-
 src/net/http/transport_internal_test.go            |    69 +
 src/net/http/transport_test.go                     |   521 +-
 src/net/interface.go                               |    85 +-
 src/net/interface_bsd.go                           |   173 +-
 src/net/interface_bsd_test.go                      |    11 +-
 src/net/interface_bsdvar.go                        |    28 +
 src/net/interface_darwin.go                        |    69 +-
 src/net/interface_dragonfly.go                     |    12 -
 src/net/interface_freebsd.go                       |    74 +-
 src/net/interface_linux.go                         |     6 +-
 src/net/interface_linux_test.go                    |     2 +-
 src/net/interface_netbsd.go                        |    12 -
 src/net/interface_openbsd.go                       |    12 -
 src/net/interface_stub.go                          |     6 +-
 src/net/interface_test.go                          |   286 +-
 src/net/interface_unix_test.go                     |    21 +-
 src/net/interface_windows.go                       |     6 +-
 src/net/internal/socktest/switch.go                |     2 +-
 src/net/internal/socktest/sys_windows.go           |    30 +
 src/net/ip.go                                      |    46 +-
 src/net/ip_test.go                                 |   135 +-
 src/net/ipraw_test.go                              |   116 -
 src/net/iprawsock.go                               |   138 +-
 src/net/iprawsock_plan9.go                         |    76 +-
 src/net/iprawsock_posix.go                         |   151 +-
 src/net/iprawsock_test.go                          |   116 +
 src/net/ipsock.go                                  |    78 +-
 src/net/ipsock_plan9.go                            |    76 +-
 src/net/ipsock_posix.go                            |    68 +-
 src/net/listen_test.go                             |    35 +-
 src/net/lookup.go                                  |    98 +-
 src/net/lookup_plan9.go                            |    62 +-
 src/net/lookup_stub.go                             |    27 +-
 src/net/lookup_test.go                             |   188 +-
 src/net/lookup_unix.go                             |    58 +-
 src/net/lookup_windows.go                          |   205 +-
 src/net/lookup_windows_test.go                     |    17 +-
 src/net/mac.go                                     |     2 +-
 src/net/mac_test.go                                |     2 +-
 src/net/mail/message.go                            |   187 +-
 src/net/mail/message_test.go                       |    74 +-
 src/net/main_conf_test.go                          |    38 +
 src/net/main_noconf_test.go                        |    22 +
 src/net/main_plan9_test.go                         |     1 +
 src/net/main_test.go                               |     2 -
 src/net/main_unix_test.go                          |     1 +
 src/net/main_windows_test.go                       |     4 +
 src/net/mockserver_test.go                         |    69 +-
 src/net/net.go                                     |    24 +-
 src/net/net_test.go                                |   110 +
 src/net/net_windows_test.go                        |    54 +-
 src/net/netgo_unix_test.go                         |    10 +-
 src/net/non_unix_test.go                           |    22 -
 src/net/packetconn_test.go                         |     2 +-
 src/net/parse.go                                   |     4 +-
 src/net/pipe.go                                    |     2 +-
 src/net/pipe_test.go                               |     2 +-
 src/net/platform_test.go                           |     3 +-
 src/net/port.go                                    |    62 +
 src/net/port_test.go                               |    52 +
 src/net/protoconn_test.go                          |     2 +-
 src/net/rpc/client.go                              |    12 +-
 src/net/rpc/jsonrpc/all_test.go                    |     2 +-
 src/net/rpc/jsonrpc/client.go                      |     2 +-
 src/net/rpc/jsonrpc/server.go                      |     4 +-
 src/net/rpc/server.go                              |    16 +-
 src/net/rpc/server_test.go                         |     7 +-
 src/net/sendfile_dragonfly.go                      |     6 +-
 src/net/sendfile_freebsd.go                        |     6 +-
 src/net/sendfile_linux.go                          |     4 +-
 src/net/sendfile_solaris.go                        |    15 +-
 src/net/sendfile_stub.go                           |     2 +-
 src/net/sendfile_test.go                           |    90 +
 src/net/sendfile_windows.go                        |     4 +-
 src/net/smtp/smtp.go                               |     8 +-
 src/net/sock_bsd.go                                |     2 +-
 src/net/sock_linux.go                              |     2 +-
 src/net/sock_plan9.go                              |     2 +-
 src/net/sock_posix.go                              |    12 +-
 src/net/sock_stub.go                               |     2 +-
 src/net/sock_windows.go                            |     2 +-
 src/net/sockopt_bsd.go                             |     4 +-
 src/net/sockopt_linux.go                           |     4 +-
 src/net/sockopt_plan9.go                           |     8 +-
 src/net/sockopt_posix.go                           |     2 +-
 src/net/sockopt_solaris.go                         |     4 +-
 src/net/sockopt_stub.go                            |     2 +-
 src/net/sockopt_windows.go                         |     4 +-
 src/net/sockoptip_bsd.go                           |     2 +-
 src/net/sockoptip_linux.go                         |     2 +-
 src/net/sockoptip_posix.go                         |     2 +-
 src/net/sockoptip_stub.go                          |     2 +-
 src/net/sockoptip_windows.go                       |     2 +-
 src/net/tcp_test.go                                |   590 -
 src/net/tcpsock.go                                 |   237 +-
 src/net/tcpsock_plan9.go                           |   211 +-
 src/net/tcpsock_posix.go                           |   239 +-
 src/net/tcpsock_test.go                            |   635 +
 src/net/tcpsock_unix_test.go                       |    79 +
 src/net/tcpsockopt_darwin.go                       |     2 +-
 src/net/tcpsockopt_dragonfly.go                    |     2 +-
 src/net/tcpsockopt_openbsd.go                      |     2 +-
 src/net/tcpsockopt_plan9.go                        |     7 +-
 src/net/tcpsockopt_posix.go                        |     2 +-
 src/net/tcpsockopt_solaris.go                      |     2 +-
 src/net/tcpsockopt_stub.go                         |     2 +-
 src/net/tcpsockopt_unix.go                         |     2 +-
 src/net/tcpsockopt_windows.go                      |     2 +-
 src/net/testdata/Mark.Twain-Tom.Sawyer.txt         |  8465 +++++++++
 src/net/textproto/header.go                        |     6 +-
 src/net/textproto/pipeline.go                      |     6 +-
 src/net/textproto/reader.go                        |   106 +-
 src/net/textproto/reader_test.go                   |     8 +-
 src/net/textproto/textproto.go                     |     4 +-
 src/net/textproto/writer.go                        |     4 +-
 src/net/textproto/writer_test.go                   |     2 +-
 src/net/timeout_test.go                            |    74 +-
 src/net/udp_test.go                                |   364 -
 src/net/udpsock.go                                 |   185 +-
 src/net/udpsock_plan9.go                           |   146 +-
 src/net/udpsock_posix.go                           |   184 +-
 src/net/udpsock_test.go                            |   399 +
 src/net/unix_test.go                               |   473 -
 src/net/unixsock.go                                |   274 +-
 src/net/unixsock_plan9.go                          |   140 +-
 src/net/unixsock_posix.go                          |   275 +-
 src/net/unixsock_test.go                           |   446 +
 src/net/url/url.go                                 |    65 +-
 src/net/url/url_test.go                            |    39 +-
 src/os/doc.go                                      |     6 +-
 src/os/env.go                                      |     6 +-
 src/os/error_test.go                               |    12 +-
 src/os/error_unix.go                               |     2 +-
 src/os/error_unix_test.go                          |    39 +
 src/os/error_windows_test.go                       |    35 +
 src/os/exec.go                                     |    12 +-
 src/os/exec/exec.go                                |    45 +-
 src/os/exec/exec_test.go                           |   131 +-
 src/os/exec/lp_plan9.go                            |    10 +-
 src/os/exec/lp_unix.go                             |    12 +-
 src/os/exec/lp_unix_test.go                        |     2 +-
 src/os/exec/lp_windows.go                          |    86 +-
 src/os/exec/lp_windows_test.go                     |     8 +-
 src/os/exec_posix.go                               |     2 +-
 src/os/exec_unix.go                                |    18 +
 src/os/exec_windows.go                             |     2 +-
 src/os/export_test.go                              |     2 +-
 src/os/file.go                                     |     8 +-
 src/os/file_plan9.go                               |    12 +-
 src/os/file_unix.go                                |    10 +-
 src/os/file_windows.go                             |    32 +-
 src/os/getwd.go                                    |     4 +-
 src/os/os_test.go                                  |   106 +-
 src/os/os_unix_test.go                             |    15 +-
 src/os/os_windows_test.go                          |    24 +-
 src/os/path.go                                     |     2 +-
 src/os/path_test.go                                |     2 +-
 src/os/pipe_test.go                                |     2 +-
 src/os/signal/doc.go                               |     6 +-
 src/os/signal/sig.s                                |     2 +-
 src/os/signal/signal.go                            |     2 +-
 src/os/signal/signal_test.go                       |    13 +
 src/os/stat_darwin.go                              |     2 +-
 src/os/stat_dragonfly.go                           |     4 +-
 src/os/stat_freebsd.go                             |     2 +-
 src/os/stat_linux.go                               |     2 +-
 src/os/stat_nacl.go                                |     2 +-
 src/os/stat_netbsd.go                              |     4 +-
 src/os/stat_openbsd.go                             |     4 +-
 src/os/stat_plan9.go                               |     4 +-
 src/os/stat_solaris.go                             |     4 +-
 src/os/stat_windows.go                             |    18 +-
 src/os/str.go                                      |     2 +-
 src/os/sys_windows.go                              |     2 +-
 src/os/types.go                                    |     2 +-
 src/os/types_windows.go                            |     6 +-
 src/os/user/getgrouplist_darwin.go                 |    29 +
 src/os/user/getgrouplist_unix.go                   |    22 +
 src/os/user/listgroups_solaris.go                  |    17 +
 src/os/user/listgroups_unix.go                     |    52 +
 src/os/user/lookup.go                              |    21 +-
 src/os/user/lookup_android.go                      |    38 +
 src/os/user/lookup_plan9.go                        |    20 +-
 src/os/user/lookup_stubs.go                        |    70 +-
 src/os/user/lookup_unix.go                         |   252 +-
 src/os/user/lookup_windows.go                      |    23 +-
 src/os/user/user.go                                |    36 +-
 src/os/user/user_test.go                           |    76 +-
 src/os/wait_unimp.go                               |    16 +
 src/os/wait_wait6.go                               |    40 +
 src/os/wait_waitid.go                              |    34 +
 src/path/example_test.go                           |     9 +-
 src/path/filepath/example_unix_test.go             |    14 +
 src/path/filepath/export_windows_test.go           |     7 +
 src/path/filepath/match.go                         |    49 +-
 src/path/filepath/match_test.go                    |   171 +-
 src/path/filepath/path.go                          |    18 +-
 src/path/filepath/path_test.go                     |     4 +-
 src/path/filepath/path_windows.go                  |     2 +-
 src/path/filepath/path_windows_test.go             |   161 +
 src/path/filepath/symlink.go                       |     2 +-
 src/path/filepath/symlink_windows.go               |   100 +-
 src/path/match.go                                  |     2 +-
 src/path/path.go                                   |     4 +-
 src/path/path_test.go                              |     8 +-
 src/reflect/all_test.go                            |   893 +-
 src/reflect/asm_386.s                              |     2 +-
 src/reflect/asm_amd64.s                            |     2 +-
 src/reflect/asm_amd64p32.s                         |     2 +-
 src/reflect/asm_arm.s                              |     2 +-
 src/reflect/asm_arm64.s                            |     2 +-
 src/reflect/asm_mips64x.s                          |     2 +-
 src/reflect/asm_ppc64x.s                           |     2 +-
 src/reflect/asm_s390x.s                            |    30 +
 src/reflect/deepequal.go                           |     2 +-
 src/reflect/example_test.go                        |    30 +-
 src/reflect/export_test.go                         |    51 +-
 src/reflect/makefunc.go                            |     2 +-
 src/reflect/set_test.go                            |     4 +-
 src/reflect/type.go                                |  1371 +-
 src/reflect/value.go                               |   107 +-
 src/regexp/backtrack.go                            |     5 +-
 src/regexp/exec.go                                 |    14 +-
 src/regexp/exec_test.go                            |    83 +-
 src/regexp/onepass.go                              |     6 +-
 src/regexp/onepass_test.go                         |     4 +-
 src/regexp/regexp.go                               |   103 +-
 src/regexp/syntax/compile.go                       |     4 +-
 src/regexp/syntax/doc.go                           |     4 +-
 src/regexp/syntax/make_perl_groups.pl              |     2 +-
 src/regexp/syntax/parse.go                         |    34 +-
 src/regexp/syntax/parse_test.go                    |     2 +-
 src/regexp/syntax/prog.go                          |     4 +-
 src/regexp/syntax/regexp.go                        |     6 +-
 src/regexp/syntax/simplify.go                      |     8 +-
 src/regexp/syntax/simplify_test.go                 |     6 +-
 src/run.bash                                       |     1 +
 src/run.bat                                        |     2 +
 src/run.rc                                         |     1 +
 src/runtime/alg.go                                 |    37 +-
 src/runtime/append_test.go                         |   322 +-
 src/runtime/asm.s                                  |     2 +-
 src/runtime/asm_386.s                              |    63 +-
 src/runtime/asm_amd64.s                            |   460 +-
 src/runtime/asm_amd64p32.s                         |    18 +-
 src/runtime/asm_arm.s                              |    34 +-
 src/runtime/asm_arm64.s                            |    36 +-
 src/runtime/asm_mips64x.s                          |   134 +-
 src/runtime/asm_ppc64x.h                           |     4 +-
 src/runtime/asm_ppc64x.s                           |   192 +-
 src/runtime/asm_s390x.s                            |  1135 ++
 src/runtime/atomic_pointer.go                      |    14 +-
 src/runtime/atomic_ppc64x.s                        |     2 +-
 src/runtime/callers_test.go                        |    83 +
 src/runtime/cgo.go                                 |    10 +-
 src/runtime/cgo/asm_386.s                          |    15 +-
 src/runtime/cgo/asm_amd64.s                        |    81 +-
 src/runtime/cgo/asm_arm.s                          |    47 +-
 src/runtime/cgo/asm_arm64.s                        |    81 +-
 src/runtime/cgo/asm_mips64x.s                      |    76 +
 src/runtime/cgo/asm_nacl_amd64p32.s                |     2 +-
 src/runtime/cgo/asm_ppc64x.s                       |    15 +-
 src/runtime/cgo/asm_s390x.s                        |    43 +
 src/runtime/cgo/callbacks.go                       |    38 +-
 src/runtime/cgo/callbacks_traceback.go             |    17 +
 src/runtime/cgo/cgo.go                             |     2 +-
 src/runtime/cgo/dragonfly.go                       |     2 +-
 src/runtime/cgo/freebsd.go                         |     2 +-
 src/runtime/cgo/gcc_386.S                          |     2 +-
 src/runtime/cgo/gcc_amd64.S                        |     2 +-
 src/runtime/cgo/gcc_android.c                      |     4 +-
 src/runtime/cgo/gcc_android_386.c                  |     4 +-
 src/runtime/cgo/gcc_android_amd64.c                |     4 +-
 src/runtime/cgo/gcc_android_arm.c                  |     4 +-
 src/runtime/cgo/gcc_android_arm64.c                |     4 +-
 src/runtime/cgo/gcc_arm.S                          |     2 +-
 src/runtime/cgo/gcc_arm64.S                        |     2 +-
 src/runtime/cgo/gcc_context.c                      |    21 +
 src/runtime/cgo/gcc_darwin_386.c                   |     4 +-
 src/runtime/cgo/gcc_darwin_amd64.c                 |     4 +-
 src/runtime/cgo/gcc_darwin_arm.c                   |     4 +-
 src/runtime/cgo/gcc_darwin_arm64.c                 |     4 +-
 src/runtime/cgo/gcc_dragonfly_amd64.c              |    10 +-
 src/runtime/cgo/gcc_fatalf.c                       |     4 +-
 src/runtime/cgo/gcc_freebsd_386.c                  |     4 +-
 src/runtime/cgo/gcc_freebsd_amd64.c                |     4 +-
 src/runtime/cgo/gcc_freebsd_arm.c                  |     6 +-
 src/runtime/cgo/gcc_libinit.c                      |    49 +-
 src/runtime/cgo/gcc_libinit_linux_ppc64x.c         |    28 -
 src/runtime/cgo/gcc_libinit_openbsd.c              |    36 +-
 src/runtime/cgo/gcc_libinit_windows.c              |   113 +-
 src/runtime/cgo/gcc_linux_386.c                    |     6 +-
 src/runtime/cgo/gcc_linux_amd64.c                  |     6 +-
 src/runtime/cgo/gcc_linux_arm.c                    |     6 +-
 src/runtime/cgo/gcc_linux_arm64.c                  |     6 +-
 src/runtime/cgo/gcc_linux_mips64x.c                |    77 +
 src/runtime/cgo/gcc_linux_ppc64x.c                 |     4 +-
 src/runtime/cgo/gcc_linux_s390x.c                  |    68 +
 src/runtime/cgo/gcc_mips64x.S                      |    79 +
 src/runtime/cgo/gcc_mmap.c                         |     8 +-
 src/runtime/cgo/gcc_netbsd_386.c                   |    10 +-
 src/runtime/cgo/gcc_netbsd_amd64.c                 |    10 +-
 src/runtime/cgo/gcc_netbsd_arm.c                   |    10 +-
 src/runtime/cgo/gcc_openbsd_386.c                  |    46 +-
 src/runtime/cgo/gcc_openbsd_amd64.c                |    45 +-
 src/runtime/cgo/gcc_ppc64x.S                       |     2 +-
 src/runtime/cgo/gcc_s390x.S                        |    46 +
 src/runtime/cgo/gcc_setenv.c                       |     2 +-
 src/runtime/cgo/gcc_signal_darwin_armx.c           |    12 +-
 src/runtime/cgo/gcc_signal_darwin_lldb.c           |     4 +-
 src/runtime/cgo/gcc_solaris_amd64.c                |     2 -
 src/runtime/cgo/gcc_traceback.c                    |    31 +
 src/runtime/cgo/gcc_util.c                         |    31 +-
 src/runtime/cgo/gcc_windows_386.c                  |     4 +-
 src/runtime/cgo/gcc_windows_amd64.c                |     4 +-
 src/runtime/cgo/iscgo.go                           |     6 +-
 src/runtime/cgo/libcgo.h                           |    53 +-
 src/runtime/cgo/mmap.go                            |     6 +-
 src/runtime/cgo/netbsd.go                          |     2 +-
 src/runtime/cgo/openbsd.go                         |     2 +-
 src/runtime/cgo/setenv.go                          |     2 +-
 src/runtime/cgo/signal_darwin_armx.go              |     6 +-
 src/runtime/cgo_mips64x.go                         |    12 +
 src/runtime/cgo_mmap.go                            |     8 +-
 src/runtime/cgo_ppc64x.go                          |     2 +-
 src/runtime/cgocall.go                             |   122 +-
 src/runtime/cgocallback.go                         |     2 +-
 src/runtime/cgocheck.go                            |    31 +-
 src/runtime/chan.go                                |    72 +-
 src/runtime/chan_test.go                           |   109 +-
 src/runtime/chanbarrier_test.go                    |     2 +-
 src/runtime/compiler.go                            |     4 +-
 src/runtime/cpuprof.go                             |    84 +-
 src/runtime/cputicks.go                            |     4 +-
 src/runtime/crash_cgo_test.go                      |    88 +
 src/runtime/crash_nonunix_test.go                  |    13 +
 src/runtime/crash_test.go                          |   168 +-
 src/runtime/crash_unix_test.go                     |     8 +-
 src/runtime/debug.go                               |     2 +-
 src/runtime/debug/debug.s                          |     2 +-
 src/runtime/debug/garbage.go                       |    10 +-
 src/runtime/debug/garbage_test.go                  |     2 +-
 src/runtime/debug/heapdump_test.go                 |     2 +-
 src/runtime/debug/stack_test.go                    |     2 +-
 src/runtime/debug/stubs.go                         |     2 +-
 src/runtime/defs2_linux.go                         |     2 +-
 src/runtime/defs_linux_s390x.go                    |   167 +
 src/runtime/defs_plan9_386.go                      |     6 +
 src/runtime/defs_plan9_amd64.go                    |     6 +
 src/runtime/defs_plan9_arm.go                      |    63 +
 src/runtime/env_plan9.go                           |     2 +-
 src/runtime/env_posix.go                           |     4 +-
 src/runtime/error.go                               |    15 +-
 src/runtime/export_arm_test.go                     |     2 +-
 src/runtime/export_futex_test.go                   |     2 +-
 src/runtime/export_linux_test.go                   |     2 +-
 src/runtime/export_mmap_test.go                    |     2 +-
 src/runtime/export_test.go                         |   135 +-
 src/runtime/export_windows_test.go                 |     8 +-
 src/runtime/extern.go                              |    36 +-
 src/runtime/fastlog2_test.go                       |     2 +-
 src/runtime/funcdata.h                             |     4 +-
 src/runtime/futex_test.go                          |     2 +-
 src/runtime/gcinfo_test.go                         |     9 +-
 src/runtime/go_tls.h                               |     2 +-
 src/runtime/hash64.go                              |     2 +-
 src/runtime/hash_test.go                           |    61 +-
 src/runtime/hashmap.go                             |   131 +-
 src/runtime/hashmap_fast.go                        |    57 +-
 src/runtime/heapdump.go                            |    72 +-
 src/runtime/iface.go                               |   181 +-
 src/runtime/internal/atomic/asm.s                  |     2 +-
 src/runtime/internal/atomic/asm_386.s              |     2 +-
 src/runtime/internal/atomic/asm_amd64.s            |     2 +-
 src/runtime/internal/atomic/asm_amd64p32.s         |     2 +-
 src/runtime/internal/atomic/asm_mips64x.s          |     8 +-
 src/runtime/internal/atomic/asm_ppc64x.s           |    58 +-
 src/runtime/internal/atomic/asm_s390x.s            |   174 +
 src/runtime/internal/atomic/atomic_386.go          |     2 +-
 src/runtime/internal/atomic/atomic_amd64x.go       |     5 +-
 src/runtime/internal/atomic/atomic_arm.go          |     2 +-
 src/runtime/internal/atomic/atomic_arm64.go        |     2 +-
 src/runtime/internal/atomic/atomic_arm64.s         |     2 +-
 src/runtime/internal/atomic/atomic_mips64x.go      |     2 +-
 src/runtime/internal/atomic/atomic_mips64x.s       |    12 +-
 src/runtime/internal/atomic/atomic_ppc64x.go       |     2 +-
 src/runtime/internal/atomic/atomic_s390x.go        |    73 +
 src/runtime/internal/atomic/atomic_test.go         |     2 +-
 src/runtime/internal/atomic/sys_plan9_arm.s        |    11 +
 src/runtime/internal/sys/arch.go                   |    17 +
 src/runtime/internal/sys/arch_386.go               |     2 +-
 src/runtime/internal/sys/arch_amd64.go             |     2 +-
 src/runtime/internal/sys/arch_amd64p32.go          |     2 +-
 src/runtime/internal/sys/arch_arm.go               |     2 +-
 src/runtime/internal/sys/arch_arm64.go             |     2 +-
 src/runtime/internal/sys/arch_mips64.go            |     2 +-
 src/runtime/internal/sys/arch_mips64le.go          |     2 +-
 src/runtime/internal/sys/arch_ppc64.go             |     2 +-
 src/runtime/internal/sys/arch_ppc64le.go           |     2 +-
 src/runtime/internal/sys/arch_s390x.go             |    18 +
 src/runtime/internal/sys/gengoos.go                |     6 +-
 src/runtime/internal/sys/intrinsics.go             |   116 +
 src/runtime/internal/sys/intrinsics_386.s          |    68 +
 src/runtime/internal/sys/intrinsics_stubs.go       |    14 +
 src/runtime/internal/sys/intrinsics_test.go        |    54 +
 src/runtime/internal/sys/sys.go                    |     2 +-
 src/runtime/internal/sys/zgoarch_386.go            |     2 +-
 src/runtime/internal/sys/zgoarch_amd64.go          |     2 +-
 src/runtime/internal/sys/zgoarch_amd64p32.go       |     2 +-
 src/runtime/internal/sys/zgoarch_arm.go            |     2 +-
 src/runtime/internal/sys/zgoarch_arm64.go          |     2 +-
 src/runtime/internal/sys/zgoarch_mips64.go         |     2 +-
 src/runtime/internal/sys/zgoarch_mips64le.go       |     2 +-
 src/runtime/internal/sys/zgoarch_ppc64.go          |     2 +-
 src/runtime/internal/sys/zgoarch_ppc64le.go        |     2 +-
 src/runtime/internal/sys/zgoarch_s390x.go          |    26 +
 src/runtime/internal/sys/zgoos_android.go          |     2 +-
 src/runtime/internal/sys/zgoos_darwin.go           |     2 +-
 src/runtime/internal/sys/zgoos_dragonfly.go        |     2 +-
 src/runtime/internal/sys/zgoos_freebsd.go          |     2 +-
 src/runtime/internal/sys/zgoos_linux.go            |     2 +-
 src/runtime/internal/sys/zgoos_nacl.go             |     2 +-
 src/runtime/internal/sys/zgoos_netbsd.go           |     2 +-
 src/runtime/internal/sys/zgoos_openbsd.go          |     2 +-
 src/runtime/internal/sys/zgoos_plan9.go            |     2 +-
 src/runtime/internal/sys/zgoos_solaris.go          |     2 +-
 src/runtime/internal/sys/zgoos_windows.go          |     2 +-
 src/runtime/lfstack.go                             |     9 +-
 src/runtime/lfstack_32bit.go                       |     8 +-
 src/runtime/lfstack_64bit.go                       |    48 +
 src/runtime/lfstack_amd64.go                       |    24 -
 src/runtime/lfstack_darwin_arm64.go                |    25 -
 src/runtime/lfstack_linux_arm64.go                 |    25 -
 src/runtime/lfstack_linux_mips64x.go               |    32 -
 src/runtime/lfstack_linux_ppc64x.go                |    32 -
 src/runtime/lock_futex.go                          |     8 +-
 src/runtime/lock_sema.go                           |    18 +-
 src/runtime/malloc.go                              |   328 +-
 src/runtime/map_test.go                            |    16 +
 src/runtime/mbarrier.go                            |    58 +-
 src/runtime/mbitmap.go                             |   643 +-
 src/runtime/mcache.go                              |    15 +-
 src/runtime/mcentral.go                            |    85 +-
 src/runtime/mem_bsd.go                             |     8 +-
 src/runtime/mem_darwin.go                          |     8 +-
 src/runtime/mem_linux.go                           |    11 +-
 src/runtime/mem_plan9.go                           |     2 +-
 src/runtime/mem_windows.go                         |     2 +-
 src/runtime/memclr_amd64.s                         |     2 +-
 src/runtime/memclr_arm.s                           |     2 +-
 src/runtime/memclr_s390x.s                         |   122 +
 src/runtime/memmove_386.s                          |    27 +-
 src/runtime/memmove_amd64.s                        |    23 +-
 src/runtime/memmove_arm.s                          |     2 +-
 src/runtime/memmove_linux_amd64_test.go            |     2 +-
 src/runtime/memmove_nacl_amd64p32.s                |     4 +-
 src/runtime/memmove_plan9_386.s                    |     6 +-
 src/runtime/memmove_plan9_amd64.s                  |     6 +-
 src/runtime/memmove_ppc64x.s                       |   117 +-
 src/runtime/memmove_s390x.s                        |   189 +
 src/runtime/memmove_test.go                        |   160 +-
 src/runtime/mfinal.go                              |   103 +-
 src/runtime/mfixalloc.go                           |     6 +-
 src/runtime/mgc.go                                 |   196 +-
 src/runtime/mgcmark.go                             |   379 +-
 src/runtime/mgcsweep.go                            |   159 +-
 src/runtime/mgcwork.go                             |   164 +-
 src/runtime/mheap.go                               |   327 +-
 src/runtime/mknacl.sh                              |     2 +-
 src/runtime/mmap.go                                |     7 +-
 src/runtime/mprof.go                               |    16 +-
 src/runtime/msan.go                                |     8 +-
 src/runtime/msan0.go                               |     2 +-
 src/runtime/msan_amd64.s                           |     2 +-
 src/runtime/msize.go                               |    32 +-
 src/runtime/mstats.go                              |    20 +-
 src/runtime/mstkbar.go                             |    32 +-
 src/runtime/netpoll.go                             |     2 +-
 src/runtime/netpoll_kqueue.go                      |     2 +-
 src/runtime/netpoll_solaris.go                     |     4 +-
 src/runtime/netpoll_windows.go                     |     2 +-
 src/runtime/noasm.go                               |     2 +-
 src/runtime/norace_linux_test.go                   |     4 +-
 src/runtime/norace_test.go                         |     2 +-
 src/runtime/os1_darwin.go                          |   538 -
 src/runtime/os1_dragonfly.go                       |   270 -
 src/runtime/os1_freebsd.go                         |   281 -
 src/runtime/os1_linux.go                           |   388 -
 src/runtime/os1_linux_generic.go                   |    27 -
 src/runtime/os1_linux_mips64x.go                   |    26 -
 src/runtime/os1_nacl.go                            |   214 -
 src/runtime/os1_netbsd.go                          |   275 -
 src/runtime/os1_openbsd.go                         |   278 -
 src/runtime/os1_plan9.go                           |   278 -
 src/runtime/os1_windows.go                         |   682 -
 src/runtime/os2_darwin.go                          |    14 -
 src/runtime/os2_dragonfly.go                       |    15 -
 src/runtime/os2_linux_generic.go                   |    29 -
 src/runtime/os2_linux_mips64x.go                   |    25 -
 src/runtime/os2_nacl.go                            |     2 +-
 src/runtime/os2_netbsd.go                          |    18 -
 src/runtime/os2_openbsd.go                         |     2 +-
 src/runtime/os2_windows.go                         |    19 -
 src/runtime/os3_plan9.go                           |    41 +-
 src/runtime/os3_solaris.go                         |    13 +-
 src/runtime/os_darwin.go                           |   543 +-
 src/runtime/os_dragonfly.go                        |   276 +-
 src/runtime/os_freebsd.go                          |   279 +-
 src/runtime/os_linux.go                            |   438 +-
 src/runtime/os_linux_386.go                        |    33 -
 src/runtime/os_linux_arm.go                        |    49 +-
 src/runtime/os_linux_arm64.go                      |    16 +-
 src/runtime/os_linux_generic.go                    |    48 +
 src/runtime/os_linux_mips64x.go                    |    48 +-
 src/runtime/os_linux_noauxv.go                     |    10 +
 src/runtime/os_linux_s390x.go                      |    46 +
 src/runtime/os_nacl.go                             |   234 +-
 src/runtime/os_netbsd.go                           |   290 +-
 .../{os1_netbsd_386.go => os_netbsd_386.go}        |     0
 .../{os1_netbsd_amd64.go => os_netbsd_amd64.go}    |     0
 src/runtime/os_openbsd.go                          |   278 +-
 src/runtime/os_plan9.go                            |   302 +-
 src/runtime/os_plan9_arm.go                        |    17 +
 src/runtime/os_solaris.go                          |     2 +-
 src/runtime/os_windows.go                          |   722 +-
 src/runtime/panic.go                               |    47 +-
 src/runtime/parfor.go                              |   217 -
 src/runtime/parfor_test.go                         |   128 -
 src/runtime/pprof/mprof_test.go                    |     4 +-
 src/runtime/pprof/pprof.go                         |   133 +-
 src/runtime/pprof/pprof_test.go                    |    76 +-
 src/runtime/print.go                               |     2 +-
 src/runtime/proc.go                                |   514 +-
 src/runtime/proc_runtime_test.go                   |    33 +
 src/runtime/proc_test.go                           |    42 +-
 src/runtime/race.go                                |    99 +-
 src/runtime/race/README                            |     2 +-
 src/runtime/race/output_test.go                    |    21 +-
 src/runtime/race/race_darwin_amd64.syso            |   Bin 300192 -> 341304 bytes
 src/runtime/race/race_freebsd_amd64.syso           |   Bin 368688 -> 399904 bytes
 src/runtime/race/race_linux_amd64.syso             |   Bin 352664 -> 371032 bytes
 src/runtime/race/race_linux_test.go                |    37 +
 src/runtime/race/race_test.go                      |    26 +
 src/runtime/race/race_windows_amd64.syso           |   Bin 349411 -> 363595 bytes
 src/runtime/race/race_windows_test.go              |    46 +
 src/runtime/race/sched_test.go                     |     2 +-
 src/runtime/race/testdata/chan_test.go             |     5 +
 src/runtime/race/testdata/io_test.go               |    37 +-
 src/runtime/race0.go                               |     7 +-
 src/runtime/race_amd64.s                           |    42 +-
 src/runtime/rdebug.go                              |     9 +-
 src/runtime/rt0_darwin_amd64.s                     |    12 +-
 src/runtime/rt0_darwin_arm.s                       |    19 +-
 src/runtime/rt0_darwin_arm64.s                     |    18 +-
 src/runtime/rt0_linux_arm.s                        |    29 +-
 src/runtime/rt0_linux_arm64.s                      |    18 +-
 src/runtime/rt0_linux_mips64x.s                    |    20 +-
 src/runtime/rt0_linux_ppc64le.s                    |   129 +
 src/runtime/rt0_linux_s390x.s                      |    20 +
 src/runtime/rt0_plan9_arm.s                        |    17 +
 src/runtime/rt0_windows_386.s                      |    34 +
 src/runtime/rt0_windows_amd64.s                    |    31 +
 src/runtime/runtime-gdb.py                         |     6 +-
 src/runtime/runtime-gdb_test.go                    |   142 +-
 src/runtime/runtime-lldb_test.go                   |     4 +-
 src/runtime/runtime.go                             |     2 +-
 src/runtime/runtime1.go                            |    51 +-
 src/runtime/runtime2.go                            |   284 +-
 src/runtime/runtime_linux_test.go                  |     2 +-
 src/runtime/runtime_mmap_test.go                   |     2 +-
 src/runtime/runtime_test.go                        |     8 +-
 src/runtime/runtime_unix_test.go                   |     2 +-
 src/runtime/select.go                              |   132 +-
 src/runtime/sema.go                                |   235 +-
 src/runtime/signal1_unix.go                        |    59 +-
 src/runtime/signal2_unix.go                        |     6 +-
 src/runtime/signal_386.go                          |     4 +-
 src/runtime/signal_amd64x.go                       |     4 +-
 src/runtime/signal_arm.go                          |     2 +-
 src/runtime/signal_arm64.go                        |     2 +-
 src/runtime/signal_darwin.go                       |     2 +-
 src/runtime/signal_darwin_386.go                   |     2 +-
 src/runtime/signal_darwin_amd64.go                 |     2 +-
 src/runtime/signal_darwin_arm.go                   |     2 +-
 src/runtime/signal_darwin_arm64.go                 |     2 +-
 src/runtime/signal_dragonfly.go                    |    14 +-
 src/runtime/signal_dragonfly_amd64.go              |    10 +-
 src/runtime/signal_freebsd.go                      |    18 +-
 src/runtime/signal_freebsd_386.go                  |     8 +-
 src/runtime/signal_freebsd_amd64.go                |     6 +-
 src/runtime/signal_freebsd_arm.go                  |     2 +-
 src/runtime/signal_linux_386.go                    |     2 +-
 src/runtime/signal_linux_amd64.go                  |     2 +-
 src/runtime/signal_linux_arm.go                    |     2 +-
 src/runtime/signal_linux_arm64.go                  |     2 +-
 src/runtime/signal_linux_mips64x.go                |     2 +-
 src/runtime/signal_linux_ppc64x.go                 |     2 +-
 src/runtime/signal_linux_s390x.go                  |   208 +
 src/runtime/signal_mips64x.go                      |     2 +-
 src/runtime/signal_nacl_386.go                     |     2 +-
 src/runtime/signal_nacl_amd64p32.go                |     2 +-
 src/runtime/signal_nacl_arm.go                     |     2 +-
 src/runtime/signal_netbsd_386.go                   |    10 +-
 src/runtime/signal_netbsd_amd64.go                 |     4 +-
 src/runtime/signal_netbsd_arm.go                   |     2 +-
 src/runtime/signal_openbsd.go                      |    16 +-
 src/runtime/signal_openbsd_386.go                  |     2 +-
 src/runtime/signal_openbsd_amd64.go                |     2 +-
 src/runtime/signal_openbsd_arm.go                  |     2 +-
 src/runtime/signal_plan9.go                        |     4 +-
 src/runtime/signal_ppc64x.go                       |     2 +-
 src/runtime/signal_sigtramp.go                     |    10 +-
 src/runtime/signal_solaris.go                      |     2 +-
 src/runtime/signal_unix.go                         |     9 +-
 src/runtime/signal_windows.go                      |    10 +-
 src/runtime/sigpanic_unix.go                       |     2 +-
 src/runtime/sigqueue.go                            |    22 +-
 src/runtime/sigqueue_plan9.go                      |     2 +-
 src/runtime/sigtab_linux_generic.go                |     2 +-
 src/runtime/sigtab_linux_mips64x.go                |     2 +-
 src/runtime/slice.go                               |   115 +-
 src/runtime/softfloat64.go                         |     2 +-
 src/runtime/softfloat64_test.go                    |     2 +-
 src/runtime/softfloat_arm.go                       |    19 +-
 src/runtime/sqrt.go                                |     2 +-
 src/runtime/stack.go                               |   262 +-
 src/runtime/stack_test.go                          |     6 +-
 src/runtime/string.go                              |    23 +-
 src/runtime/string_test.go                         |    47 +-
 src/runtime/stubs.go                               |     2 +-
 src/runtime/symtab.go                              |   154 +-
 src/runtime/sys_darwin_386.s                       |     7 +-
 src/runtime/sys_darwin_amd64.s                     |     7 +-
 src/runtime/sys_darwin_arm.s                       |     2 +-
 src/runtime/sys_darwin_arm64.s                     |     2 +-
 src/runtime/sys_dragonfly_amd64.s                  |     6 +-
 src/runtime/sys_linux_386.s                        |    47 +-
 src/runtime/sys_linux_amd64.s                      |    85 +-
 src/runtime/sys_linux_arm.s                        |     6 +-
 src/runtime/sys_linux_arm64.s                      |     4 +
 src/runtime/sys_linux_mips64x.s                    |    12 +-
 src/runtime/sys_linux_ppc64x.s                     |    15 +
 src/runtime/sys_linux_s390x.s                      |   440 +
 src/runtime/sys_netbsd_386.s                       |     2 +-
 src/runtime/sys_netbsd_amd64.s                     |     2 +-
 src/runtime/sys_openbsd_386.s                      |    10 +-
 src/runtime/sys_openbsd_amd64.s                    |     2 +-
 src/runtime/sys_plan9_arm.s                        |   318 +
 src/runtime/sys_s390x.go                           |    45 +
 src/runtime/sys_solaris_amd64.s                    |     6 +-
 src/runtime/sys_windows_386.s                      |    17 +-
 src/runtime/sys_windows_amd64.s                    |    44 +-
 src/runtime/sys_x86.go                             |    10 +-
 src/runtime/syscall_solaris.go                     |     2 +-
 src/runtime/syscall_windows.go                     |     8 +-
 src/runtime/syscall_windows_test.go                |   105 +-
 src/runtime/testdata/testprog/crash.go             |     2 +-
 src/runtime/testdata/testprog/deadlock.go          |    27 +-
 src/runtime/testdata/testprog/gc.go                |    37 +-
 src/runtime/testdata/testprog/main.go              |     2 +-
 src/runtime/testdata/testprog/memprof.go           |    49 +
 src/runtime/testdata/testprog/misc.go              |     2 +-
 src/runtime/testdata/testprog/signal.go            |    16 +-
 src/runtime/testdata/testprog/stringconcat.go      |     2 +-
 src/runtime/testdata/testprog/syscall_windows.go   |     2 +-
 src/runtime/testdata/testprogcgo/aprof.go          |    15 +-
 src/runtime/testdata/testprogcgo/callback.go       |     2 +-
 src/runtime/testdata/testprogcgo/cgo.go            |     2 +-
 src/runtime/testdata/testprogcgo/crash.go          |     2 +-
 src/runtime/testdata/testprogcgo/deadlock.go       |    30 +
 src/runtime/testdata/testprogcgo/dll_windows.go    |     2 +-
 src/runtime/testdata/testprogcgo/dropm.go          |     2 +-
 src/runtime/testdata/testprogcgo/dropm_stub.go     |     2 +-
 src/runtime/testdata/testprogcgo/exec.go           |     2 +-
 src/runtime/testdata/testprogcgo/main.go           |     2 +-
 src/runtime/testdata/testprogcgo/pprof.go          |    97 +
 src/runtime/testdata/testprogcgo/threadpanic.go    |     2 +-
 .../testdata/testprogcgo/threadpanic_unix.c        |     2 +-
 .../testdata/testprogcgo/threadpanic_windows.c     |     5 +-
 src/runtime/testdata/testprogcgo/threadpprof.go    |   112 +
 src/runtime/testdata/testprogcgo/threadprof.go     |     2 +-
 src/runtime/testdata/testprogcgo/traceback.go      |    81 +
 src/runtime/testdata/testprogcgo/tracebackctxt.go  |   107 +
 src/runtime/testdata/testprogcgo/tracebackctxt_c.c |    91 +
 src/runtime/testdata/testprognet/main.go           |     2 +-
 src/runtime/testdata/testprognet/net.go            |     2 +-
 src/runtime/testdata/testprognet/signal.go         |     2 +-
 src/runtime/textflag.h                             |    12 +-
 src/runtime/time.go                                |     2 +-
 src/runtime/tls_arm.s                              |     2 +-
 src/runtime/tls_mips64x.s                          |    15 +-
 src/runtime/tls_ppc64x.s                           |     2 +-
 src/runtime/tls_s390x.s                            |    51 +
 src/runtime/trace.go                               |   219 +-
 src/runtime/trace/trace_stack_test.go              |    16 +-
 src/runtime/trace/trace_test.go                    |    54 +-
 src/runtime/traceback.go                           |   370 +-
 src/runtime/type.go                                |   578 +-
 src/runtime/typekind.go                            |     2 +-
 src/runtime/unaligned1.go                          |     2 +-
 src/runtime/unaligned2.go                          |     2 +-
 src/runtime/vdso_linux_amd64.go                    |    52 +-
 src/runtime/vdso_none.go                           |     6 +-
 src/runtime/vlop_386.s                             |     2 +-
 src/runtime/vlop_arm.s                             |     2 +-
 src/runtime/vlop_arm_test.go                       |    44 +
 src/runtime/vlrt.go                                |     3 +-
 src/runtime/wbfat.go                               |   190 -
 src/runtime/wbfat_gen.go                           |    41 -
 src/runtime/wincallback.go                         |     2 +-
 src/sort/search.go                                 |     8 +-
 src/sort/search_test.go                            |     2 +-
 src/sort/sort.go                                   |    13 +-
 src/sort/sort_test.go                              |     4 +-
 src/strconv/atob.go                                |     2 +-
 src/strconv/atof.go                                |    13 +-
 src/strconv/atof_test.go                           |    26 +-
 src/strconv/atoi.go                                |    14 +-
 src/strconv/atoi_test.go                           |     2 +-
 src/strconv/extfloat.go                            |     4 +-
 src/strconv/fp_test.go                             |     2 +-
 src/strconv/ftoa.go                                |     2 +-
 src/strconv/ftoa_test.go                           |    85 +-
 src/strconv/isprint.go                             |    82 +-
 src/strconv/makeisprint.go                         |     2 +-
 src/strconv/quote.go                               |   150 +-
 src/strconv/quote_test.go                          |    28 +
 src/strings/compare.go                             |     2 +-
 src/strings/compare_test.go                        |     2 +-
 src/strings/reader.go                              |    20 +-
 src/strings/reader_test.go                         |    46 +-
 src/strings/strings.go                             |    37 +-
 src/strings/strings_amd64.go                       |     2 +-
 src/strings/strings_decl.go                        |     2 +-
 src/strings/strings_generic.go                     |     2 +-
 src/strings/strings_test.go                        |   142 +-
 src/sync/atomic/64bit_arm.go                       |     2 +-
 src/sync/atomic/asm_386.s                          |     2 +-
 src/sync/atomic/asm_amd64.s                        |     2 +-
 src/sync/atomic/asm_amd64p32.s                     |     2 +-
 src/sync/atomic/asm_arm.s                          |     4 +-
 src/sync/atomic/asm_arm64.s                        |     2 +-
 src/sync/atomic/asm_darwin_arm.s                   |     2 +-
 src/sync/atomic/asm_freebsd_arm.s                  |     2 +-
 src/sync/atomic/asm_linux_arm.s                    |     2 +-
 src/sync/atomic/asm_mips64x.s                      |     2 +-
 src/sync/atomic/asm_nacl_arm.s                     |     2 +-
 src/sync/atomic/asm_netbsd_arm.s                   |     2 +-
 src/sync/atomic/asm_openbsd_arm.s                  |     2 +-
 src/sync/atomic/asm_plan9_arm.s                    |   108 +
 src/sync/atomic/asm_ppc64x.s                       |    24 +-
 src/sync/atomic/asm_s390x.s                        |   143 +
 src/sync/atomic/atomic_linux_arm_test.go           |     2 +-
 src/sync/atomic/atomic_test.go                     |     4 +-
 src/sync/atomic/doc.go                             |     2 +-
 src/sync/atomic/export_linux_arm_test.go           |     2 +-
 src/sync/atomic/race.s                             |     2 +-
 src/sync/atomic/value.go                           |    14 +
 src/sync/atomic/value_test.go                      |     7 +-
 src/sync/cond.go                                   |    63 +-
 src/sync/cond_test.go                              |    59 +
 src/sync/export_test.go                            |     2 +-
 src/sync/mutex.go                                  |     6 +-
 src/sync/once.go                                   |     4 +-
 src/sync/pool.go                                   |     9 +-
 src/sync/runtime.go                                |    37 +-
 src/sync/runtime_sema_test.go                      |     3 +
 src/sync/rwmutex.go                                |    23 +-
 src/sync/waitgroup.go                              |     8 +-
 src/syscall/asm.s                                  |     2 +-
 src/syscall/asm_linux_s390x.s                      |   156 +
 src/syscall/asm_plan9_arm.s                        |    99 +
 src/syscall/bpf_bsd.go                             |    20 +-
 src/syscall/creds_test.go                          |     2 +-
 src/syscall/dir_plan9.go                           |     1 +
 src/syscall/dll_windows.go                         |     6 +-
 src/syscall/env_plan9.go                           |     2 +-
 src/syscall/env_unix.go                            |     2 +-
 src/syscall/env_windows.go                         |     2 +-
 src/syscall/errors_plan9.go                        |     2 +-
 src/syscall/exec_bsd.go                            |     8 +-
 src/syscall/exec_linux.go                          |    62 +-
 src/syscall/exec_linux_test.go                     |   126 +-
 src/syscall/exec_plan9.go                          |   248 +-
 src/syscall/exec_solaris.go                        |     8 +-
 src/syscall/exec_unix.go                           |    24 +-
 src/syscall/export_test.go                         |     2 +-
 src/syscall/fd_nacl.go                             |     9 +-
 src/syscall/fs_nacl.go                             |     7 +-
 src/syscall/lsf_linux.go                           |    10 +-
 src/syscall/mkall.sh                               |    17 +-
 src/syscall/mkpost.go                              |    63 +
 src/syscall/mksyscall.pl                           |     2 +-
 src/syscall/mksyscall_windows.go                   |    99 +-
 src/syscall/msan.go                                |     2 +-
 src/syscall/msan0.go                               |     2 +-
 src/syscall/net_nacl.go                            |     2 +-
 src/syscall/netlink_linux.go                       |     2 +-
 src/syscall/route_bsd.go                           |    18 +-
 src/syscall/route_bsd_test.go                      |   260 -
 src/syscall/route_darwin.go                        |     4 +-
 src/syscall/route_dragonfly.go                     |     6 +-
 src/syscall/route_freebsd.go                       |     6 +-
 src/syscall/route_ifma_test.go                     |    74 -
 src/syscall/route_netbsd.go                        |     4 +-
 src/syscall/route_noifma_test.go                   |    63 -
 src/syscall/route_openbsd.go                       |     4 +-
 src/syscall/security_windows.go                    |     2 +-
 src/syscall/sockcmsg_linux.go                      |     2 +-
 src/syscall/sockcmsg_unix.go                       |     4 +-
 src/syscall/syscall.go                             |     6 +-
 src/syscall/syscall_bsd.go                         |     2 +-
 src/syscall/syscall_darwin.go                      |     5 +-
 src/syscall/syscall_darwin_386.go                  |     2 +-
 src/syscall/syscall_darwin_amd64.go                |     2 +-
 src/syscall/syscall_darwin_arm.go                  |     2 +-
 src/syscall/syscall_darwin_arm64.go                |     2 +-
 src/syscall/syscall_dragonfly.go                   |     5 +-
 src/syscall/syscall_freebsd.go                     |     5 +-
 src/syscall/syscall_linux.go                       |     8 +-
 src/syscall/syscall_linux_386.go                   |     4 +-
 src/syscall/syscall_linux_s390x.go                 |   299 +
 src/syscall/syscall_nacl.go                        |     4 +-
 src/syscall/syscall_nacl_386.go                    |     2 +-
 src/syscall/syscall_nacl_amd64p32.go               |     2 +-
 src/syscall/syscall_nacl_arm.go                    |     2 +-
 src/syscall/syscall_plan9.go                       |     1 +
 src/syscall/syscall_solaris.go                     |     4 +-
 src/syscall/syscall_test.go                        |    14 +
 src/syscall/syscall_unix.go                        |     2 +-
 src/syscall/syscall_unix_test.go                   |     5 +-
 src/syscall/syscall_windows.go                     |     2 +-
 src/syscall/syscall_windows_386.go                 |     2 +-
 src/syscall/syscall_windows_amd64.go               |     2 +-
 src/syscall/tables_nacl.go                         |     2 +-
 src/syscall/time_nacl_386.s                        |     2 +-
 src/syscall/time_nacl_amd64p32.s                   |     2 +-
 src/syscall/time_nacl_arm.s                        |     2 +-
 src/syscall/types_linux.go                         |    25 +-
 src/syscall/unzip_nacl.go                          |     2 +-
 src/syscall/zerrors_linux_s390x.go                 |  1940 ++
 src/syscall/zerrors_windows_386.go                 |     2 +-
 src/syscall/zerrors_windows_amd64.go               |     2 +-
 src/syscall/zsyscall_darwin_386.go                 |     1 +
 src/syscall/zsyscall_darwin_amd64.go               |     1 +
 src/syscall/zsyscall_darwin_arm.go                 |     1 +
 src/syscall/zsyscall_dragonfly_amd64.go            |     1 +
 src/syscall/zsyscall_freebsd_386.go                |     1 +
 src/syscall/zsyscall_freebsd_amd64.go              |     1 +
 src/syscall/zsyscall_freebsd_arm.go                |     1 +
 src/syscall/zsyscall_linux_s390x.go                |  1576 ++
 src/syscall/zsyscall_netbsd_386.go                 |     1 +
 src/syscall/zsyscall_netbsd_amd64.go               |     1 +
 src/syscall/zsyscall_netbsd_arm.go                 |     1 +
 src/syscall/zsyscall_openbsd_386.go                |     1 +
 src/syscall/zsyscall_openbsd_amd64.go              |     1 +
 src/syscall/zsyscall_plan9_arm.go                  |   294 +
 src/syscall/zsysnum_linux_s390x.go                 |   326 +
 src/syscall/ztypes_linux_s390x.go                  |   620 +
 src/syscall/ztypes_windows.go                      |     2 +-
 src/syscall/ztypes_windows_386.go                  |     2 +-
 src/syscall/ztypes_windows_amd64.go                |     2 +-
 src/testing/allocs.go                              |     4 +-
 src/testing/allocs_test.go                         |     2 +-
 src/testing/benchmark.go                           |   281 +-
 src/testing/example.go                             |    26 +-
 src/testing/iotest/reader.go                       |     2 +-
 src/testing/match.go                               |   167 +
 src/testing/match_test.go                          |   185 +
 src/testing/quick/quick.go                         |    44 +-
 src/testing/sub_test.go                            |   517 +
 src/testing/testing.go                             |   355 +-
 src/testing/testing_test.go                        |     2 +-
 src/text/scanner/example_test.go                   |    21 +-
 src/text/scanner/scanner.go                        |    15 +-
 src/text/scanner/scanner_test.go                   |    62 +-
 src/text/tabwriter/example_test.go                 |    35 +
 src/text/tabwriter/tabwriter.go                    |    50 +-
 src/text/template/doc.go                           |     7 +-
 src/text/template/exec.go                          |    43 +-
 src/text/template/exec_test.go                     |    30 +
 src/text/template/funcs.go                         |     5 +-
 src/text/template/helper.go                        |    14 +
 src/text/template/multi_test.go                    |     2 +-
 src/text/template/parse/lex.go                     |     4 +-
 src/text/template/parse/parse.go                   |    10 +-
 src/text/template/parse/parse_test.go              |     2 +-
 src/time/example_test.go                           |     2 +-
 src/time/format.go                                 |     9 +-
 src/time/format_test.go                            |     2 +-
 src/time/genzabbrs.go                              |     2 +-
 src/time/sleep.go                                  |    27 +-
 src/time/sys_plan9.go                              |     4 +-
 src/time/sys_unix.go                               |     4 +-
 src/time/sys_windows.go                            |     4 +-
 src/time/tick.go                                   |     3 +-
 src/time/tick_test.go                              |     2 +-
 src/time/time.go                                   |    58 +-
 src/time/time_test.go                              |     4 +-
 src/time/zoneinfo_abbrs_windows.go                 |    40 +-
 src/time/zoneinfo_read.go                          |    11 +-
 src/time/zoneinfo_test.go                          |    11 +-
 src/time/zoneinfo_windows.go                       |     4 +-
 src/unicode/graphic.go                             |     2 +-
 src/unicode/letter.go                              |    20 +-
 src/unicode/letter_test.go                         |     2 +-
 src/unicode/maketables.go                          |    41 +-
 src/unicode/script_test.go                         |    10 +-
 src/unicode/tables.go                              |   618 +-
 src/unicode/utf16/export_test.go                   |     2 +-
 src/unicode/utf16/utf16.go                         |    34 +-
 src/unicode/utf16/utf16_test.go                    |    55 +-
 src/unicode/utf8/utf8.go                           |     6 +-
 src/unsafe/unsafe.go                               |     8 +-
 src/vendor/README                                  |     8 -
 src/vendor/golang.org/x/net/http2/hpack/encode.go  |   251 +
 .../golang.org/x/net/http2/hpack/encode_test.go    |     0
 src/vendor/golang.org/x/net/http2/hpack/hpack.go   |   542 +
 .../golang.org/x/net/http2/hpack/hpack_test.go     |   854 +
 src/vendor/golang.org/x/net/http2/hpack/huffman.go |   212 +
 .../golang.org/x/net/http2/hpack/tables.go         |     0
 src/vendor/golang.org/x/net/lex/httplex/httplex.go |   312 +
 .../golang.org/x/net/lex/httplex/httplex_test.go   |   101 +
 src/vendor/golang.org/x/net/route/address.go       |   269 +
 .../golang.org/x/net/route/address_darwin_test.go  |    63 +
 src/vendor/golang.org/x/net/route/address_test.go  |   103 +
 src/vendor/golang.org/x/net/route/binary.go        |    90 +
 src/vendor/golang.org/x/net/route/defs_darwin.go   |   106 +
 .../golang.org/x/net/route/defs_dragonfly.go       |   105 +
 src/vendor/golang.org/x/net/route/defs_freebsd.go  |   329 +
 src/vendor/golang.org/x/net/route/defs_netbsd.go   |   104 +
 src/vendor/golang.org/x/net/route/defs_openbsd.go  |    93 +
 src/vendor/golang.org/x/net/route/interface.go     |    64 +
 .../golang.org/x/net/route/interface_announce.go   |    32 +
 .../golang.org/x/net/route/interface_classic.go    |    66 +
 .../golang.org/x/net/route/interface_freebsd.go    |    78 +
 .../golang.org/x/net/route/interface_multicast.go  |    30 +
 .../golang.org/x/net/route/interface_openbsd.go    |    83 +
 src/vendor/golang.org/x/net/route/message.go       |    70 +
 .../golang.org/x/net/route/message_darwin_test.go  |    27 +
 .../golang.org/x/net/route/message_freebsd_test.go |   106 +
 src/vendor/golang.org/x/net/route/message_test.go  |    95 +
 src/vendor/golang.org/x/net/route/route.go         |    74 +
 src/vendor/golang.org/x/net/route/route_classic.go |    31 +
 src/vendor/golang.org/x/net/route/route_openbsd.go |    28 +
 src/vendor/golang.org/x/net/route/route_test.go    |   385 +
 src/vendor/golang.org/x/net/route/sys.go           |    40 +
 src/vendor/golang.org/x/net/route/sys_darwin.go    |    80 +
 src/vendor/golang.org/x/net/route/sys_dragonfly.go |    71 +
 src/vendor/golang.org/x/net/route/sys_freebsd.go   |   150 +
 src/vendor/golang.org/x/net/route/sys_netbsd.go    |    67 +
 src/vendor/golang.org/x/net/route/sys_openbsd.go   |    72 +
 src/vendor/golang.org/x/net/route/syscall.go       |    33 +
 src/vendor/golang.org/x/net/route/syscall.s        |     8 +
 src/vendor/golang.org/x/net/route/zsys_darwin.go   |    93 +
 .../golang.org/x/net/route/zsys_dragonfly.go       |    92 +
 .../golang.org/x/net/route/zsys_freebsd_386.go     |   120 +
 .../golang.org/x/net/route/zsys_freebsd_amd64.go   |   117 +
 .../golang.org/x/net/route/zsys_freebsd_arm.go     |   117 +
 src/vendor/golang.org/x/net/route/zsys_netbsd.go   |    91 +
 src/vendor/golang.org/x/net/route/zsys_openbsd.go  |    80 +
 test/alg.go                                        |    46 +
 test/alias.go                                      |     2 +-
 test/alias1.go                                     |     2 +-
 test/atomicload.go                                 |    45 +
 test/bench/garbage/Makefile                        |     2 +-
 test/bench/garbage/parser.go                       |     2 +-
 test/bench/garbage/stats.go                        |     2 +-
 test/bench/garbage/tree2.go                        |     2 +-
 test/bench/go1/binarytree_test.go                  |     2 +-
 test/bench/go1/fannkuch_test.go                    |     2 +-
 test/bench/go1/fasta_test.go                       |     8 +-
 test/bench/go1/gob_test.go                         |     2 +-
 test/bench/go1/gzip_test.go                        |     2 +-
 test/bench/go1/http_test.go                        |     2 +-
 test/bench/go1/json_test.go                        |     2 +-
 test/bench/go1/jsondata_test.go                    |     2 +-
 test/bench/go1/mandel_test.go                      |     2 +-
 test/bench/go1/parserdata_test.go                  |     4 +-
 test/bench/go1/revcomp_test.go                     |     2 +-
 test/bench/go1/template_test.go                    |     2 +-
 test/bombad.go                                     |     2 +-
 test/bounds.go                                     |     2 +-
 test/bugs/bug395.go                                |     2 +-
 test/chan/select2.go                               |     2 +-
 test/chan/select5.go                               |     2 +-
 test/chan/select6.go                               |     2 +-
 test/chan/select7.go                               |     2 +-
 test/chan/sendstmt.go                              |     2 +-
 test/checkbce.go                                   |   114 +
 test/cmplxdivide.c                                 |     2 +-
 test/cmplxdivide.go                                |     2 +-
 test/complit1.go                                   |     2 +-
 test/compos.go                                     |     2 +-
 test/const6.go                                     |     2 +-
 test/convert1.go                                   |     2 +-
 test/ddd.go                                        |     2 +-
 test/ddd1.go                                       |     2 +-
 test/ddd2.dir/ddd2.go                              |     2 +-
 test/ddd2.dir/ddd3.go                              |     2 +-
 test/ddd2.go                                       |     2 +-
 test/deferprint.go                                 |     2 +-
 test/divide.go                                     |     2 +-
 test/divmod.go                                     |     2 +-
 test/eof.go                                        |     2 +-
 test/eof1.go                                       |     2 +-
 test/errchk                                        |    11 +
 test/escape2.go                                    |     2 +-
 test/escape2n.go                                   |     2 +-
 test/escape3.go                                    |     2 +-
 test/escape4.go                                    |     2 +-
 test/escape5.go                                    |     2 +-
 test/escape_array.go                               |     2 +-
 test/escape_because.go                             |   177 +
 test/escape_calls.go                               |     2 +-
 test/escape_closure.go                             |     2 +-
 test/escape_field.go                               |     2 +-
 test/escape_iface.go                               |    22 +-
 test/escape_indir.go                               |     2 +-
 test/escape_level.go                               |     2 +-
 test/escape_map.go                                 |     2 +-
 test/escape_param.go                               |     2 +-
 test/escape_slice.go                               |     2 +-
 test/escape_struct_param1.go                       |     2 +-
 test/escape_struct_param2.go                       |     2 +-
 test/escape_struct_return.go                       |     2 +-
 test/fixedbugs/bug083.dir/bug0.go                  |     2 +-
 test/fixedbugs/bug083.dir/bug1.go                  |     2 +-
 test/fixedbugs/bug088.dir/bug0.go                  |     2 +-
 test/fixedbugs/bug088.dir/bug1.go                  |     2 +-
 test/fixedbugs/bug106.dir/bug0.go                  |     2 +-
 test/fixedbugs/bug106.dir/bug1.go                  |     2 +-
 test/fixedbugs/bug108.go                           |     2 +-
 test/fixedbugs/bug133.dir/bug0.go                  |     2 +-
 test/fixedbugs/bug133.dir/bug1.go                  |     2 +-
 test/fixedbugs/bug133.dir/bug2.go                  |     2 +-
 test/fixedbugs/bug13343.go                         |     2 +-
 test/fixedbugs/bug1515.go                          |     2 +-
 test/fixedbugs/bug160.dir/x.go                     |     2 +-
 test/fixedbugs/bug160.dir/y.go                     |     2 +-
 test/fixedbugs/bug203.go                           |     2 +-
 test/fixedbugs/bug227.go                           |     2 +-
 test/fixedbugs/bug228.go                           |     2 +-
 test/fixedbugs/bug229.go                           |     4 +-
 test/fixedbugs/bug230.go                           |     2 +-
 test/fixedbugs/bug231.go                           |     2 +-
 test/fixedbugs/bug232.go                           |     2 +-
 test/fixedbugs/bug233.go                           |     2 +-
 test/fixedbugs/bug234.go                           |     2 +-
 test/fixedbugs/bug235.go                           |     2 +-
 test/fixedbugs/bug236.go                           |     2 +-
 test/fixedbugs/bug237.go                           |     2 +-
 test/fixedbugs/bug243.go                           |     2 +-
 test/fixedbugs/bug245.go                           |     2 +-
 test/fixedbugs/bug247.go                           |     2 +-
 test/fixedbugs/bug249.go                           |     2 +-
 test/fixedbugs/bug250.go                           |     2 +-
 test/fixedbugs/bug251.go                           |     2 +-
 test/fixedbugs/bug252.go                           |     2 +-
 test/fixedbugs/bug253.go                           |     2 +-
 test/fixedbugs/bug254.go                           |     2 +-
 test/fixedbugs/bug255.go                           |     2 +-
 test/fixedbugs/bug256.go                           |     2 +-
 test/fixedbugs/bug257.go                           |     2 +-
 test/fixedbugs/bug258.go                           |     2 +-
 test/fixedbugs/bug259.go                           |     2 +-
 test/fixedbugs/bug261.go                           |     2 +-
 test/fixedbugs/bug266.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/bug275.go                           |     2 +-
 test/fixedbugs/bug278.go                           |     2 +-
 test/fixedbugs/bug279.go                           |     2 +-
 test/fixedbugs/bug280.go                           |     2 +-
 test/fixedbugs/bug281.go                           |     2 +-
 test/fixedbugs/bug282.dir/p1.go                    |     2 +-
 test/fixedbugs/bug282.dir/p2.go                    |     2 +-
 test/fixedbugs/bug283.go                           |     2 +-
 test/fixedbugs/bug285.go                           |     2 +-
 test/fixedbugs/bug286.go                           |     2 +-
 test/fixedbugs/bug287.go                           |     2 +-
 test/fixedbugs/bug288.go                           |     2 +-
 test/fixedbugs/bug289.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/bug295.go                           |     2 +-
 test/fixedbugs/bug296.go                           |     2 +-
 test/fixedbugs/bug297.go                           |     2 +-
 test/fixedbugs/bug298.go                           |     2 +-
 test/fixedbugs/bug299.go                           |     2 +-
 test/fixedbugs/bug300.go                           |     2 +-
 test/fixedbugs/bug301.go                           |     2 +-
 test/fixedbugs/bug302.dir/main.go                  |     2 +-
 test/fixedbugs/bug302.dir/p.go                     |     2 +-
 test/fixedbugs/bug302.go                           |     2 +-
 test/fixedbugs/bug303.go                           |     2 +-
 test/fixedbugs/bug304.go                           |     2 +-
 test/fixedbugs/bug305.go                           |     2 +-
 test/fixedbugs/bug306.dir/p1.go                    |     2 +-
 test/fixedbugs/bug306.dir/p2.go                    |     2 +-
 test/fixedbugs/bug308.go                           |     2 +-
 test/fixedbugs/bug309.go                           |     2 +-
 test/fixedbugs/bug311.go                           |     2 +-
 test/fixedbugs/bug312.go                           |     2 +-
 test/fixedbugs/bug313.dir/a.go                     |     2 +-
 test/fixedbugs/bug313.dir/b.go                     |     2 +-
 test/fixedbugs/bug313.go                           |     2 +-
 test/fixedbugs/bug317.go                           |     2 +-
 test/fixedbugs/bug319.go                           |     2 +-
 test/fixedbugs/bug320.go                           |     2 +-
 test/fixedbugs/bug321.go                           |     2 +-
 test/fixedbugs/bug323.go                           |     2 +-
 test/fixedbugs/bug325.go                           |     2 +-
 test/fixedbugs/bug326.go                           |     2 +-
 test/fixedbugs/bug327.go                           |     2 +-
 test/fixedbugs/bug328.go                           |     2 +-
 test/fixedbugs/bug329.go                           |     2 +-
 test/fixedbugs/bug330.go                           |     2 +-
 test/fixedbugs/bug331.go                           |     2 +-
 test/fixedbugs/bug332.go                           |     2 +-
 test/fixedbugs/bug333.go                           |     2 +-
 test/fixedbugs/bug334.go                           |     2 +-
 test/fixedbugs/bug335.dir/a.go                     |     2 +-
 test/fixedbugs/bug335.dir/b.go                     |     2 +-
 test/fixedbugs/bug335.go                           |     2 +-
 test/fixedbugs/bug336.go                           |     2 +-
 test/fixedbugs/bug337.go                           |     2 +-
 test/fixedbugs/bug338.go                           |     2 +-
 test/fixedbugs/bug339.go                           |     2 +-
 test/fixedbugs/bug340.go                           |     2 +-
 test/fixedbugs/bug341.go                           |     2 +-
 test/fixedbugs/bug342.go                           |     2 +-
 test/fixedbugs/bug343.go                           |     2 +-
 test/fixedbugs/bug344.go                           |     2 +-
 test/fixedbugs/bug345.dir/io.go                    |     2 +-
 test/fixedbugs/bug345.dir/main.go                  |     2 +-
 test/fixedbugs/bug345.go                           |     2 +-
 test/fixedbugs/bug347.go                           |     2 +-
 test/fixedbugs/bug348.go                           |     2 +-
 test/fixedbugs/bug349.go                           |     2 +-
 test/fixedbugs/bug350.go                           |     2 +-
 test/fixedbugs/bug351.go                           |     2 +-
 test/fixedbugs/bug352.go                           |     2 +-
 test/fixedbugs/bug353.go                           |     2 +-
 test/fixedbugs/bug354.go                           |     2 +-
 test/fixedbugs/bug355.go                           |     2 +-
 test/fixedbugs/bug356.go                           |     2 +-
 test/fixedbugs/bug357.go                           |     2 +-
 test/fixedbugs/bug358.go                           |     2 +-
 test/fixedbugs/bug361.go                           |     2 +-
 test/fixedbugs/bug362.go                           |     2 +-
 test/fixedbugs/bug363.go                           |     2 +-
 test/fixedbugs/bug365.go                           |     2 +-
 test/fixedbugs/bug366.go                           |     2 +-
 test/fixedbugs/bug368.go                           |     2 +-
 test/fixedbugs/bug369.dir/main.go                  |     2 +-
 test/fixedbugs/bug369.dir/pkg.go                   |     2 +-
 test/fixedbugs/bug369.go                           |     2 +-
 test/fixedbugs/bug370.go                           |     2 +-
 test/fixedbugs/bug371.go                           |     2 +-
 test/fixedbugs/bug372.go                           |     2 +-
 test/fixedbugs/bug373.go                           |     2 +-
 test/fixedbugs/bug374.go                           |     2 +-
 test/fixedbugs/bug375.go                           |     2 +-
 test/fixedbugs/bug376.go                           |     2 +-
 test/fixedbugs/bug378.go                           |     2 +-
 test/fixedbugs/bug379.go                           |     2 +-
 test/fixedbugs/bug380.go                           |     2 +-
 test/fixedbugs/bug381.go                           |     2 +-
 test/fixedbugs/bug382.dir/pkg.go                   |     2 +-
 test/fixedbugs/bug383.go                           |     2 +-
 test/fixedbugs/bug384.go                           |     2 +-
 test/fixedbugs/bug385_32.go                        |     2 +-
 test/fixedbugs/bug385_64.go                        |     2 +-
 test/fixedbugs/bug386.go                           |     2 +-
 test/fixedbugs/bug387.go                           |     2 +-
 test/fixedbugs/bug388.go                           |     4 +-
 test/fixedbugs/bug389.go                           |     2 +-
 test/fixedbugs/bug391.go                           |     2 +-
 test/fixedbugs/bug392.dir/one.go                   |     2 +-
 test/fixedbugs/bug392.dir/pkg2.go                  |     2 +-
 test/fixedbugs/bug392.dir/pkg3.go                  |     2 +-
 test/fixedbugs/bug393.go                           |     2 +-
 test/fixedbugs/bug394.go                           |     2 +-
 test/fixedbugs/bug396.dir/one.go                   |     2 +-
 test/fixedbugs/bug396.dir/two.go                   |     2 +-
 test/fixedbugs/bug397.go                           |     2 +-
 test/fixedbugs/bug398.go                           |    17 +-
 test/fixedbugs/bug399.go                           |     2 +-
 test/fixedbugs/bug401.go                           |     2 +-
 test/fixedbugs/bug402.go                           |     2 +-
 test/fixedbugs/bug403.go                           |     2 +-
 test/fixedbugs/bug404.dir/one.go                   |     2 +-
 test/fixedbugs/bug404.dir/two.go                   |     2 +-
 test/fixedbugs/bug406.go                           |     2 +-
 test/fixedbugs/bug407.dir/one.go                   |     2 +-
 test/fixedbugs/bug407.dir/two.go                   |     2 +-
 test/fixedbugs/bug409.go                           |     2 +-
 test/fixedbugs/bug410.go                           |     2 +-
 test/fixedbugs/bug411.go                           |     2 +-
 test/fixedbugs/bug412.go                           |     2 +-
 test/fixedbugs/bug413.go                           |     2 +-
 test/fixedbugs/bug414.dir/p1.go                    |     2 +-
 test/fixedbugs/bug414.dir/prog.go                  |     2 +-
 test/fixedbugs/bug414.go                           |     2 +-
 test/fixedbugs/bug415.dir/p.go                     |     2 +-
 test/fixedbugs/bug415.dir/prog.go                  |     2 +-
 test/fixedbugs/bug415.go                           |     2 +-
 test/fixedbugs/bug416.go                           |     2 +-
 test/fixedbugs/bug424.dir/lib.go                   |     2 +-
 test/fixedbugs/bug424.dir/main.go                  |     2 +-
 test/fixedbugs/bug424.go                           |     2 +-
 test/fixedbugs/bug428.go                           |     2 +-
 test/fixedbugs/bug429.go                           |     2 +-
 test/fixedbugs/bug435.go                           |     2 +-
 test/fixedbugs/bug437.dir/one.go                   |     2 +-
 test/fixedbugs/bug437.dir/two.go                   |     2 +-
 test/fixedbugs/bug437.dir/x.go                     |     2 +-
 test/fixedbugs/bug437.go                           |     2 +-
 test/fixedbugs/bug441.go                           |     2 +-
 test/fixedbugs/bug442.go                           |     2 +-
 test/fixedbugs/bug443.go                           |     2 +-
 test/fixedbugs/bug444.go                           |     2 +-
 test/fixedbugs/bug445.go                           |     2 +-
 test/fixedbugs/bug447.go                           |     2 +-
 test/fixedbugs/bug448.dir/pkg1.go                  |     2 +-
 test/fixedbugs/bug448.dir/pkg2.go                  |     2 +-
 test/fixedbugs/bug448.go                           |     2 +-
 test/fixedbugs/bug450.go                           |     2 +-
 test/fixedbugs/bug452.go                           |     2 +-
 test/fixedbugs/bug453.go                           |     2 +-
 test/fixedbugs/bug454.go                           |     2 +-
 test/fixedbugs/bug455.go                           |     2 +-
 test/fixedbugs/bug456.go                           |     2 +-
 test/fixedbugs/bug457.go                           |     2 +-
 test/fixedbugs/bug458.go                           |     2 +-
 test/fixedbugs/bug459.go                           |     2 +-
 test/fixedbugs/bug460.dir/a.go                     |     2 +-
 test/fixedbugs/bug460.dir/b.go                     |     2 +-
 test/fixedbugs/bug460.go                           |     2 +-
 test/fixedbugs/bug461.go                           |     2 +-
 test/fixedbugs/bug462.go                           |     2 +-
 test/fixedbugs/bug463.go                           |     2 +-
 test/fixedbugs/bug464.go                           |     2 +-
 test/fixedbugs/bug465.dir/a.go                     |     2 +-
 test/fixedbugs/bug465.dir/b.go                     |     2 +-
 test/fixedbugs/bug465.go                           |     2 +-
 test/fixedbugs/bug466.dir/a.go                     |     2 +-
 test/fixedbugs/bug466.dir/b.go                     |     2 +-
 test/fixedbugs/bug466.go                           |     2 +-
 test/fixedbugs/bug467.go                           |     2 +-
 test/fixedbugs/bug468.dir/p1.go                    |     2 +-
 test/fixedbugs/bug468.dir/p2.go                    |     2 +-
 test/fixedbugs/bug468.go                           |     2 +-
 test/fixedbugs/bug470.go                           |     2 +-
 test/fixedbugs/bug471.go                           |     2 +-
 test/fixedbugs/bug472.dir/p1.go                    |     2 +-
 test/fixedbugs/bug472.dir/p2.go                    |     2 +-
 test/fixedbugs/bug472.dir/z.go                     |     2 +-
 test/fixedbugs/bug472.go                           |     2 +-
 test/fixedbugs/bug473.go                           |     2 +-
 test/fixedbugs/bug474.go                           |     2 +-
 test/fixedbugs/bug475.go                           |     2 +-
 test/fixedbugs/bug476.go                           |     2 +-
 test/fixedbugs/bug477.go                           |     2 +-
 test/fixedbugs/bug478.dir/a.go                     |     2 +-
 test/fixedbugs/bug478.dir/b.go                     |     2 +-
 test/fixedbugs/bug478.go                           |     2 +-
 test/fixedbugs/bug479.dir/a.go                     |     2 +-
 test/fixedbugs/bug479.dir/b.go                     |     2 +-
 test/fixedbugs/bug479.go                           |     2 +-
 test/fixedbugs/bug480.dir/a.go                     |     2 +-
 test/fixedbugs/bug480.dir/b.go                     |     2 +-
 test/fixedbugs/bug480.go                           |     2 +-
 test/fixedbugs/bug481.go                           |     2 +-
 test/fixedbugs/bug482.go                           |     2 +-
 test/fixedbugs/bug483.go                           |     2 +-
 test/fixedbugs/bug484.go                           |     2 +-
 test/fixedbugs/bug485.go                           |     2 +-
 test/fixedbugs/bug486.go                           |     2 +-
 test/fixedbugs/bug487.go                           |     2 +-
 test/fixedbugs/bug488.dir/a.go                     |     2 +-
 test/fixedbugs/bug488.dir/b.go                     |     2 +-
 test/fixedbugs/bug488.go                           |     2 +-
 test/fixedbugs/bug489.go                           |     2 +-
 test/fixedbugs/bug490.go                           |     2 +-
 test/fixedbugs/bug491.go                           |     2 +-
 test/fixedbugs/gcc61204.go                         |     2 +-
 test/fixedbugs/gcc61244.go                         |     2 +-
 test/fixedbugs/gcc61246.go                         |     2 +-
 test/fixedbugs/gcc61248.go                         |     2 +-
 test/fixedbugs/gcc61253.go                         |     2 +-
 test/fixedbugs/gcc61254.go                         |     2 +-
 test/fixedbugs/gcc61255.go                         |     2 +-
 test/fixedbugs/gcc61258.go                         |     2 +-
 test/fixedbugs/gcc61264.go                         |     2 +-
 test/fixedbugs/gcc61265.go                         |     2 +-
 test/fixedbugs/gcc61273.go                         |     2 +-
 test/fixedbugs/gcc65755.go                         |     2 +-
 test/fixedbugs/issue10047.go                       |     2 +-
 test/fixedbugs/issue10284.go                       |     2 +-
 test/fixedbugs/issue10320.go                       |     2 +-
 test/fixedbugs/issue10332.go                       |     2 +-
 test/fixedbugs/issue10407.go                       |     2 +-
 test/fixedbugs/issue10486.go                       |     2 +-
 test/fixedbugs/issue10607.go                       |     2 +-
 test/fixedbugs/issue10975.go                       |     2 +-
 test/fixedbugs/issue11053.dir/p.go                 |     2 +-
 test/fixedbugs/issue11053.dir/p_test.go            |     2 +-
 test/fixedbugs/issue11326.go                       |     2 +-
 test/fixedbugs/issue11326b.go                      |     2 +-
 test/fixedbugs/issue11361.go                       |    11 +
 test/fixedbugs/issue11362.go                       |     2 +-
 test/fixedbugs/issue11590.go                       |     2 +-
 test/fixedbugs/issue11610.go                       |     4 +-
 test/fixedbugs/issue11656.go                       |     4 +-
 test/fixedbugs/issue11699.go                       |     2 +-
 test/fixedbugs/issue11737.go                       |     2 +-
 test/fixedbugs/issue11750.go                       |     2 +-
 test/fixedbugs/issue11771.go                       |     2 +-
 test/fixedbugs/issue11790.go                       |     2 +-
 test/fixedbugs/issue11987.go                       |     2 +-
 test/fixedbugs/issue12006.go                       |     2 +-
 test/fixedbugs/issue12133.go                       |     2 +-
 test/fixedbugs/issue12347.go                       |    16 +
 test/fixedbugs/issue12411.go                       |     2 +-
 test/fixedbugs/issue12525.go                       |    26 +
 test/fixedbugs/issue12588.go                       |     2 +-
 test/fixedbugs/issue12686.go                       |     2 +-
 test/fixedbugs/issue1304.go                        |     2 +-
 test/fixedbugs/issue13160.go                       |     2 +-
 test/fixedbugs/issue13169.go                       |     2 +-
 test/fixedbugs/issue13248.go                       |     2 +-
 test/fixedbugs/issue13261.go                       |     2 +-
 test/fixedbugs/issue13266.go                       |     2 +-
 test/fixedbugs/issue13273.go                       |     2 +-
 test/fixedbugs/issue13274.go                       |     2 +-
 test/fixedbugs/issue13319.go                       |     2 +-
 test/fixedbugs/issue13337.go                       |    30 +
 test/fixedbugs/issue13471.go                       |     2 +-
 test/fixedbugs/issue13587.go                       |     2 +-
 test/fixedbugs/issue13684.go                       |     2 +-
 test/fixedbugs/issue13779.go                       |    15 +
 test/fixedbugs/issue13799.go                       |     2 +-
 test/fixedbugs/issue13821.go                       |     2 +-
 test/fixedbugs/issue13821b.go                      |     2 +-
 test/fixedbugs/issue14006.go                       |     2 +-
 test/fixedbugs/issue14010.go                       |     2 +-
 test/fixedbugs/issue14136.go                       |    19 +
 test/fixedbugs/issue14331.dir/a.go                 |     2 +-
 test/fixedbugs/issue14331.dir/b.go                 |     2 +-
 test/fixedbugs/issue14331.go                       |     2 +-
 test/fixedbugs/issue14405.go                       |    17 +
 test/fixedbugs/issue14520.go                       |    14 +
 test/fixedbugs/issue14553.go                       |    45 +
 test/fixedbugs/issue14591.go                       |    38 +
 test/fixedbugs/issue14636.go                       |    43 +
 test/fixedbugs/issue14646.go                       |    23 +
 test/fixedbugs/issue14651.go                       |    71 +
 test/fixedbugs/issue14652.go                       |     9 +
 test/fixedbugs/issue14725.go                       |    57 +
 test/fixedbugs/issue14729.go                       |    14 +
 test/fixedbugs/issue14988.go                       |    13 +
 test/fixedbugs/issue14999.go                       |    18 +
 test/fixedbugs/issue15002.go                       |   132 +
 test/fixedbugs/issue15013.go                       |    24 +
 test/fixedbugs/issue15039.go                       |    25 +
 test/fixedbugs/issue15042.go                       |    27 +
 test/fixedbugs/issue15071.dir/exp/exp.go           |    24 +
 test/fixedbugs/issue15071.dir/main.go              |    14 +
 test/fixedbugs/issue15084.go                       |    30 +
 test/fixedbugs/issue15091.go                       |    25 +
 test/fixedbugs/issue15175.go                       |    66 +
 test/fixedbugs/issue15252.go                       |    32 +
 test/fixedbugs/issue15277.go                       |    38 +
 test/fixedbugs/issue15281.go                       |    64 +
 test/fixedbugs/issue15311.go                       |    20 +
 test/fixedbugs/issue15329.go                       |    79 +
 test/fixedbugs/issue15439.go                       |    25 +
 test/fixedbugs/issue15470.dir/a.go                 |    24 +
 test/fixedbugs/issue15470.dir/b.go                 |     3 +
 test/fixedbugs/issue15470.go                       |    10 +
 test/fixedbugs/issue15548.dir/a.go                 |    17 +
 test/fixedbugs/issue15548.dir/b.go                 |     9 +
 test/fixedbugs/issue15548.dir/c.go                 |    10 +
 test/fixedbugs/issue15548.go                       |     7 +
 test/fixedbugs/issue15572.dir/a.go                 |    40 +
 test/fixedbugs/issue15572.dir/b.go                 |    27 +
 test/fixedbugs/issue15572.go                       |    11 +
 test/fixedbugs/issue15585.go                       |    45 +
 test/fixedbugs/issue15602.go                       |    11 +
 test/fixedbugs/issue15604.go                       |    17 +
 test/fixedbugs/issue15646.dir/a.go                 |    23 +
 test/fixedbugs/issue15646.dir/b.go                 |    16 +
 test/fixedbugs/issue15646.go                       |     9 +
 test/fixedbugs/issue15733.go                       |    23 +
 test/fixedbugs/issue15747.go                       |    41 +
 test/fixedbugs/issue15747b.go                      |    19 +
 test/fixedbugs/issue15838.dir/a.go                 |    61 +
 test/fixedbugs/issue15838.dir/b.go                 |     9 +
 test/fixedbugs/issue15838.go                       |    12 +
 test/fixedbugs/issue15898.go                       |    18 +
 test/fixedbugs/issue15902.go                       |    27 +
 test/fixedbugs/issue15920.dir/a.go                 |     9 +
 test/fixedbugs/issue15920.dir/b.go                 |     7 +
 test/fixedbugs/issue15920.go                       |     7 +
 test/fixedbugs/issue15926.go                       |    20 +
 test/fixedbugs/issue15961.go                       |    21 +
 test/fixedbugs/issue15975.go                       |    36 +
 test/fixedbugs/issue15988.go                       |    14 +
 test/fixedbugs/issue16008.go                       |    56 +
 test/fixedbugs/issue16016.go                       |    35 +
 test/fixedbugs/issue16037_run.go                   |    70 +
 test/fixedbugs/issue16095.go                       |   104 +
 test/fixedbugs/issue16130.go                       |    43 +
 test/fixedbugs/issue16133.dir/a1.go                |     7 +
 test/fixedbugs/issue16133.dir/a2.go                |     7 +
 test/fixedbugs/issue16133.dir/b.go                 |     7 +
 test/fixedbugs/issue16133.dir/c.go                 |    10 +
 test/fixedbugs/issue16133.go                       |    10 +
 test/fixedbugs/issue16193.go                       |    27 +
 test/fixedbugs/issue16249.go                       |    58 +
 test/fixedbugs/issue2615.go                        |     2 +-
 test/fixedbugs/issue3552.dir/one.go                |     2 +-
 test/fixedbugs/issue3552.dir/two.go                |     2 +-
 test/fixedbugs/issue3705.go                        |     2 +-
 test/fixedbugs/issue3783.go                        |     2 +-
 test/fixedbugs/issue3925.go                        |     2 +-
 test/fixedbugs/issue4085a.go                       |     2 +-
 test/fixedbugs/issue4085b.go                       |     2 +-
 test/fixedbugs/issue4097.go                        |     2 +-
 test/fixedbugs/issue4099.go                        |     2 +-
 test/fixedbugs/issue4162.go                        |     2 +-
 test/fixedbugs/issue4167.go                        |     2 +-
 test/fixedbugs/issue4232.go                        |     2 +-
 test/fixedbugs/issue4251.go                        |     2 +-
 test/fixedbugs/issue4252.dir/a.go                  |     2 +-
 test/fixedbugs/issue4252.dir/main.go               |     2 +-
 test/fixedbugs/issue4252.go                        |     2 +-
 test/fixedbugs/issue4283.go                        |     2 +-
 test/fixedbugs/issue4313.go                        |     2 +-
 test/fixedbugs/issue4316.go                        |     2 +-
 test/fixedbugs/issue4323.go                        |     2 +-
 test/fixedbugs/issue4326.go                        |     2 +-
 test/fixedbugs/issue4348.go                        |     2 +-
 test/fixedbugs/issue4353.go                        |     2 +-
 test/fixedbugs/issue4359.go                        |     2 +-
 test/fixedbugs/issue4365.go                        |     2 +-
 test/fixedbugs/issue4370.dir/p1.go                 |     2 +-
 test/fixedbugs/issue4370.dir/p2.go                 |     2 +-
 test/fixedbugs/issue4370.dir/p3.go                 |     2 +-
 test/fixedbugs/issue4370.go                        |     2 +-
 test/fixedbugs/issue4388.go                        |     2 +-
 test/fixedbugs/issue4396a.go                       |     2 +-
 test/fixedbugs/issue4396b.go                       |     2 +-
 test/fixedbugs/issue4399.go                        |     2 +-
 test/fixedbugs/issue4405.go                        |     2 +-
 test/fixedbugs/issue4429.go                        |     2 +-
 test/fixedbugs/issue4448.go                        |     2 +-
 test/fixedbugs/issue4452.go                        |     2 +-
 test/fixedbugs/issue4458.go                        |     2 +-
 test/fixedbugs/issue4463.go                        |     2 +-
 test/fixedbugs/issue4468.go                        |     2 +-
 test/fixedbugs/issue4470.go                        |     2 +-
 test/fixedbugs/issue4495.go                        |     2 +-
 test/fixedbugs/issue4517a.go                       |     2 +-
 test/fixedbugs/issue4517b.go                       |     2 +-
 test/fixedbugs/issue4517c.go                       |     2 +-
 test/fixedbugs/issue4517d.go                       |     2 +-
 test/fixedbugs/issue4518.go                        |     2 +-
 test/fixedbugs/issue4529.go                        |     2 +-
 test/fixedbugs/issue4545.go                        |     2 +-
 test/fixedbugs/issue4562.go                        |     2 +-
 test/fixedbugs/issue4585.go                        |     2 +-
 test/fixedbugs/issue4590.dir/pkg1.go               |     2 +-
 test/fixedbugs/issue4590.dir/pkg2.go               |     2 +-
 test/fixedbugs/issue4590.dir/prog.go               |     2 +-
 test/fixedbugs/issue4614.go                        |     2 +-
 test/fixedbugs/issue4618.go                        |     2 +-
 test/fixedbugs/issue4620.go                        |     2 +-
 test/fixedbugs/issue4654.go                        |     2 +-
 test/fixedbugs/issue4663.go                        |     2 +-
 test/fixedbugs/issue4667.go                        |     2 +-
 test/fixedbugs/issue4734.go                        |     2 +-
 test/fixedbugs/issue4748.go                        |     2 +-
 test/fixedbugs/issue4752.go                        |     2 +-
 test/fixedbugs/issue4776.go                        |     2 +-
 test/fixedbugs/issue4785.go                        |     2 +-
 test/fixedbugs/issue4909a.go                       |     2 +-
 test/fixedbugs/issue5002.go                        |     2 +-
 test/fixedbugs/issue5056.go                        |     2 +-
 test/fixedbugs/issue5089.go                        |     2 +-
 test/fixedbugs/issue5231.go                        |     2 +-
 test/fixedbugs/issue5358.go                        |     2 +-
 test/fixedbugs/issue5373.go                        |     2 +-
 test/fixedbugs/issue5581.go                        |     2 +-
 test/fixedbugs/issue5698.go                        |     2 +-
 test/fixedbugs/issue5704.go                        |     2 +-
 test/fixedbugs/issue5793.go                        |     2 +-
 test/fixedbugs/issue5809.go                        |     2 +-
 test/fixedbugs/issue5820.go                        |     2 +-
 test/fixedbugs/issue5841.go                        |     2 +-
 test/fixedbugs/issue5856.go                        |     2 +-
 test/fixedbugs/issue5963.go                        |     2 +-
 test/fixedbugs/issue6004.go                        |     2 +-
 test/fixedbugs/issue6036.go                        |     2 +-
 test/fixedbugs/issue6055.go                        |     2 +-
 test/fixedbugs/issue6131.go                        |     2 +-
 test/fixedbugs/issue6140.go                        |     2 +-
 test/fixedbugs/issue6247.go                        |     2 +-
 test/fixedbugs/issue6269.go                        |     2 +-
 test/fixedbugs/issue6295.dir/p0.go                 |     2 +-
 test/fixedbugs/issue6295.dir/p1.go                 |     2 +-
 test/fixedbugs/issue6295.dir/p2.go                 |     2 +-
 test/fixedbugs/issue6298.go                        |     2 +-
 test/fixedbugs/issue6513.dir/a.go                  |     2 +-
 test/fixedbugs/issue6513.dir/b.go                  |     2 +-
 test/fixedbugs/issue6513.dir/main.go               |     2 +-
 test/fixedbugs/issue6572.go                        |     2 +-
 test/fixedbugs/issue6671.go                        |     2 +-
 test/fixedbugs/issue6703a.go                       |     2 +-
 test/fixedbugs/issue6703b.go                       |     2 +-
 test/fixedbugs/issue6703c.go                       |     2 +-
 test/fixedbugs/issue6703d.go                       |     2 +-
 test/fixedbugs/issue6703e.go                       |     2 +-
 test/fixedbugs/issue6703f.go                       |     2 +-
 test/fixedbugs/issue6703g.go                       |     2 +-
 test/fixedbugs/issue6703h.go                       |     2 +-
 test/fixedbugs/issue6703i.go                       |     2 +-
 test/fixedbugs/issue6703j.go                       |     2 +-
 test/fixedbugs/issue6703k.go                       |     2 +-
 test/fixedbugs/issue6703l.go                       |     2 +-
 test/fixedbugs/issue6703m.go                       |     2 +-
 test/fixedbugs/issue6703n.go                       |     2 +-
 test/fixedbugs/issue6703o.go                       |     2 +-
 test/fixedbugs/issue6703p.go                       |     2 +-
 test/fixedbugs/issue6703q.go                       |     2 +-
 test/fixedbugs/issue6703r.go                       |     2 +-
 test/fixedbugs/issue6703s.go                       |     2 +-
 test/fixedbugs/issue6703t.go                       |     2 +-
 test/fixedbugs/issue6703u.go                       |     2 +-
 test/fixedbugs/issue6703v.go                       |     2 +-
 test/fixedbugs/issue6703w.go                       |     2 +-
 test/fixedbugs/issue6703x.go                       |     2 +-
 test/fixedbugs/issue6703y.go                       |     2 +-
 test/fixedbugs/issue6703z.go                       |     2 +-
 test/fixedbugs/issue6847.go                        |     2 +-
 test/fixedbugs/issue6899.go                        |     2 +-
 test/fixedbugs/issue6964.go                        |     2 +-
 test/fixedbugs/issue7044.go                        |     2 +-
 test/fixedbugs/issue7050.go                        |     2 +-
 test/fixedbugs/issue7150.go                        |     2 +-
 test/fixedbugs/issue7223.go                        |     2 +-
 test/fixedbugs/issue7272.go                        |     2 +-
 test/fixedbugs/issue7310.go                        |     2 +-
 test/fixedbugs/issue7316.go                        |     2 +-
 test/fixedbugs/issue7346.go                        |     2 +-
 test/fixedbugs/issue7366.go                        |     2 +-
 test/fixedbugs/issue7590.go                        |     2 +-
 test/fixedbugs/issue7690.go                        |     2 +-
 test/fixedbugs/issue7794.go                        |     2 +-
 test/fixedbugs/issue7863.go                        |     2 +-
 test/fixedbugs/issue7867.go                        |     2 +-
 test/fixedbugs/issue7884.go                        |     2 +-
 test/fixedbugs/issue7944.go                        |     2 +-
 test/fixedbugs/issue7995.go                        |     2 +-
 test/fixedbugs/issue7996.go                        |     2 +-
 test/fixedbugs/issue7997.go                        |     2 +-
 test/fixedbugs/issue7998.go                        |     2 +-
 test/fixedbugs/issue8004.go                        |     2 +-
 test/fixedbugs/issue8011.go                        |     2 +-
 test/fixedbugs/issue8017.go                        |     2 +-
 test/fixedbugs/issue8028.go                        |     2 +-
 test/fixedbugs/issue8036.go                        |     2 +-
 test/fixedbugs/issue8039.go                        |     2 +-
 test/fixedbugs/issue8047.go                        |     2 +-
 test/fixedbugs/issue8047b.go                       |     2 +-
 test/fixedbugs/issue8048.go                        |     2 +-
 test/fixedbugs/issue8073.go                        |     2 +-
 test/fixedbugs/issue8074.go                        |     2 +-
 test/fixedbugs/issue8076.go                        |     2 +-
 test/fixedbugs/issue8132.go                        |     2 +-
 test/fixedbugs/issue8139.go                        |     2 +-
 test/fixedbugs/issue8154.go                        |     2 +-
 test/fixedbugs/issue8155.go                        |     2 +-
 test/fixedbugs/issue8158.go                        |     2 +-
 test/fixedbugs/issue8183.go                        |     2 +-
 test/fixedbugs/issue8311.go                        |     2 +-
 test/fixedbugs/issue8325.go                        |     2 +-
 test/fixedbugs/issue8336.go                        |     2 +-
 test/fixedbugs/issue8347.go                        |     2 +-
 test/fixedbugs/issue8475.go                        |     2 +-
 test/fixedbugs/issue8507.go                        |     2 +-
 test/fixedbugs/issue8612.go                        |     2 +-
 test/fixedbugs/issue8613.go                        |    39 +
 test/fixedbugs/issue8620.go                        |     2 +-
 test/fixedbugs/issue8745.go                        |     2 +-
 test/fixedbugs/issue8761.go                        |     2 +-
 test/fixedbugs/issue8836.go                        |     2 +-
 test/fixedbugs/issue887.go                         |     2 +-
 test/fixedbugs/issue8947.go                        |     2 +-
 test/fixedbugs/issue8961.go                        |     2 +-
 test/fixedbugs/issue9006.go                        |     2 +-
 test/fixedbugs/issue9017.go                        |     2 +-
 test/fixedbugs/issue9036.go                        |    18 +-
 test/fixedbugs/issue9076.go                        |     2 +-
 test/fixedbugs/issue9083.go                        |     2 +-
 test/fixedbugs/issue9110.go                        |     2 +-
 test/fixedbugs/issue9321.go                        |     2 +-
 test/fixedbugs/issue9355.go                        |     2 +-
 test/fixedbugs/issue9432.go                        |     2 +-
 test/fixedbugs/issue9731.go                        |     2 +-
 test/fixedbugs/issue9862.go                        |     2 +-
 test/float_lit2.go                                 |     2 +-
 test/float_lit3.go                                 |     2 +-
 test/func6.go                                      |     2 +-
 test/func7.go                                      |     2 +-
 test/func8.go                                      |     2 +-
 test/funcdup.go                                    |     2 +-
 test/funcdup2.go                                   |     2 +-
 test/gc2.go                                        |     2 +-
 test/gcstring.go                                   |     2 +-
 test/goprint.go                                    |    11 +-
 test/goto.go                                       |    74 +-
 test/import2.dir/import2.go                        |     2 +-
 test/import2.dir/import3.go                        |     2 +-
 test/import2.go                                    |     2 +-
 test/index.go                                      |     2 +-
 test/index0.go                                     |     2 +-
 test/index1.go                                     |     2 +-
 test/index2.go                                     |     2 +-
 test/init1.go                                      |     4 +-
 test/inline.go                                     |    43 +-
 test/interface/assertinline.go                     |     2 +-
 test/interface/noeq.go                             |     2 +-
 test/interface/recursive1.dir/recursive1.go        |     2 +-
 test/interface/recursive1.dir/recursive2.go        |     2 +-
 test/interface/recursive1.go                       |     2 +-
 test/intrinsic.dir/main.go                         |   109 +
 test/intrinsic.go                                  |     8 +
 test/ken/embed.go                                  |     2 +-
 test/label.go                                      |     9 +-
 test/label1.go                                     |    34 +-
 test/linkmain.go                                   |     2 +-
 test/linkobj.go                                    |   155 +
 test/linkx.go                                      |     2 +-
 test/linkx_run.go                                  |     6 +-
 test/live.go                                       |     3 +-
 test/live1.go                                      |     2 +-
 test/live2.go                                      |     3 +-
 test/live_ssa.go                                   |   648 +
 test/live_syscall.go                               |     2 +-
 test/loopbce.go                                    |   253 +
 test/map1.go                                       |     2 +-
 test/method1.go                                    |    18 +-
 test/method5.go                                    |     2 +-
 test/named.go                                      |     2 +-
 test/named1.go                                     |     2 +-
 test/nilcheck.go                                   |   100 +-
 test/nilptr.go                                     |     2 +-
 test/nilptr2.go                                    |     2 +-
 test/nilptr3.go                                    |    27 +-
 test/nilptr3_ssa.go                                |   230 +
 test/nilptr4.go                                    |     2 +-
 test/nosplit.go                                    |    10 +-
 test/opt_branchlikely.go                           |    85 +
 test/phiopt.go                                     |   108 +
 test/prove.go                                      |   450 +
 test/recover.go                                    |     2 +-
 test/recover1.go                                   |     2 +-
 test/recover2.go                                   |     2 +-
 test/recover3.go                                   |     2 +-
 test/recover4.go                                   |     2 +-
 test/reflectmethod1.go                             |    30 +
 test/reflectmethod2.go                             |    36 +
 test/reflectmethod3.go                             |    35 +
 test/reflectmethod4.go                             |    30 +
 test/rename.go                                     |     2 +-
 test/rename1.go                                    |     2 +-
 test/reorder.go                                    |     2 +-
 test/reorder2.go                                   |     2 +-
 test/return.go                                     |     2 +-
 test/rotate.go                                     |     2 +-
 test/rotate0.go                                    |     2 +-
 test/rotate1.go                                    |     2 +-
 test/rotate2.go                                    |     2 +-
 test/rotate3.go                                    |     2 +-
 test/run.go                                        |    89 +-
 test/rune.go                                       |     2 +-
 test/runtime.go                                    |     2 +-
 test/shift1.go                                     |     2 +-
 test/shift2.go                                     |     2 +-
 test/sinit.go                                      |     2 +-
 test/sizeof.go                                     |     2 +-
 test/slice3.go                                     |     2 +-
 test/slice3err.go                                  |     2 +-
 test/slicecap.go                                   |     2 +-
 test/sliceopt.go                                   |     3 +-
 test/strength.go                                   |    45 +
 test/stress/maps.go                                |     2 +-
 test/stress/parsego.go                             |     2 +-
 test/stress/runstress.go                           |     2 +-
 test/struct0.go                                    |     2 +-
 test/switch5.go                                    |    81 +
 test/switch6.go                                    |    32 +
 test/syntax/chan.go                                |     2 +-
 test/syntax/chan1.go                               |     2 +-
 test/syntax/composite.go                           |     2 +-
 test/syntax/ddd.go                                 |    11 +
 test/syntax/else.go                                |     2 +-
 test/syntax/forvar.go                              |     2 +-
 test/syntax/if.go                                  |     2 +-
 test/syntax/import.go                              |     2 +-
 test/syntax/interface.go                           |     2 +-
 test/syntax/semi1.go                               |     2 +-
 test/syntax/semi2.go                               |     2 +-
 test/syntax/semi3.go                               |     2 +-
 test/syntax/semi4.go                               |     2 +-
 test/syntax/semi5.go                               |     2 +-
 test/syntax/semi6.go                               |     2 +-
 test/syntax/semi7.go                               |     2 +-
 test/syntax/topexpr.go                             |     2 +-
 test/syntax/typesw.go                              |     2 +-
 test/syntax/vareq.go                               |     2 +-
 test/syntax/vareq1.go                              |     2 +-
 test/uintptrescapes.dir/a.go                       |    54 +
 test/uintptrescapes.dir/main.go                    |    91 +
 test/uintptrescapes.go                             |     9 +
 test/uintptrescapes2.go                            |    31 +
 test/undef.go                                      |     2 +-
 test/varerr.go                                     |     2 +-
 test/writebarrier.go                               |    55 +-
 3313 files changed, 258832 insertions(+), 72971 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 34a78e5..9494ba0 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -14,13 +14,17 @@ A Medium Corporation
 Aamir Khan <syst3m.w0rm at gmail.com>
 Aaron France <aaron.l.france at gmail.com>
 Aaron Torres <tcboox at gmail.com>
+Abe Haskins <abeisgreat at abeisgreat.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>
 Aécio Júnior <aeciodantasjunior at gmail.com>
 Ahmed Waheed Moanes <oneofone at gmail.com>
+Ahmy Yulrizka <yulrizka at gmail.com>
+Aiden Scandella <ai at uber.com>
 Ainar Garipov <gugl.zadolbal at gmail.com>
+Akihiro Suda <suda.kyoto at gmail.com>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Alan Shreve <alan at inconshreveable.com>
 Albert Strasheim <fullung at gmail.com>
@@ -28,6 +32,7 @@ Alberto Bertogli <albertito at blitiri.com.ar>
 Alberto Donizetti <alb.donizetti at gmail.com>
 Alberto García Hierro <alberto at garciahierro.com> <alberto.garcia.hierro at gmail.com>
 Aleksandar Dezelin <dezelin at gmail.com>
+Alessandro Arzilli <alessandro.arzilli at gmail.com>
 Alex A Skinner <alex at lx.lc>
 Alex Brainman <alex.brainman at gmail.com>
 Alex Jin <toalexjin at gmail.com>
@@ -50,8 +55,10 @@ Alexey Borzenkov <snaury at gmail.com>
 Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
 Aliaksandr Valialkin <valyala at gmail.com>
 Alif Rachmawadi <subosito at gmail.com>
+Amazon.com, Inc
 Amir Mohammad Saied <amir at gluegadget.com>
 Amrut Joshi <amrut.joshi at gmail.com>
+Andre Nathan <andrenth at gmail.com>
 Andrei Korzhevskii <a.korzhevskiy at gmail.com>
 Andrei Vieru <euvieru at gmail.com>
 Andrew Balholm <andybalholm at gmail.com>
@@ -85,6 +92,8 @@ 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>
+Arlo Breault <arlolra at gmail.com>
+ARM Ltd.
 Arnaud Ysmal <arnaud.ysmal at gmail.com>
 Arne Hormann <arnehormann at gmail.com>
 Arnout Engelen <arnout at bzzt.net>
@@ -92,8 +101,11 @@ Aron Nopanen <aron.nopanen at gmail.com>
 Artyom Pervukhin <artyom.pervukhin at gmail.com>
 Arvindh Rajesh Tamilmani <art at a-30.net>
 Ato Araki <ato.araki at gmail.com>
+Audrey Lim <audreylh at gmail.com>
+Augusto Roman <aroman at gmail.com>
 Aulus Egnatius Varialus <varialus at gmail.com>
 awaw fumin <awawfumin at gmail.com>
+Ayanamist Yang <ayanamist at gmail.com>
 Aymerick Jéhanne <aymerick at jehanne.org>
 Ben Burkert <ben at benburkert.com>
 Ben Olive <sionide21 at gmail.com>
@@ -107,6 +119,8 @@ 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>
+Brady Catherman <brady at gmail.com>
+Brady Sullivan <brady at bsull.com>
 Brendan Daniel Tracey <tracey.brendan at gmail.com>
 Brett Cannon <bcannon at gmail.com>
 Brian Dellisanti <briandellisanti at gmail.com>
@@ -134,23 +148,28 @@ 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 Couder <chriscool at tuxfamily.org>
 Christian Himpel <chressie at googlemail.com>
 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 Nelson <nadiasvertex at gmail.com>
 Christopher Nielsen <m4dh4tt3r at gmail.com>
 Christopher Redden <christopher.redden at gmail.com>
 Christopher Wedgwood <cw at f00f.org>
 CL Sung <clsung at gmail.com> <cl_sung at htc.com>
 Clement Skau <clementskau at gmail.com>
 CloudFlare Inc.
+Colin Edwards <colin at recursivepenguin.com>
 Colin Kennedy <moshen.colin at gmail.com>
+Conrad Irwin <conrad.irwin at gmail.com>
 Conrad Meyer <cemeyer at cs.washington.edu>
 CoreOS, Inc.
 Corey Thomasson <cthom.lists at gmail.com>
 Cristian Staretu <unclejacksons at gmail.com>
+Currant
 Damian Gryski <dgryski at gmail.com>
 Dan Caddigan <goldcaddy77 at gmail.com>
 Dan Callahan <dan.callahan at gmail.com>
@@ -164,9 +183,12 @@ Daniel Lidén <daniel.liden.87 at gmail.com>
 Daniel Morsing <daniel.morsing at gmail.com>
 Daniel Ortiz Pereira da Silva <daniel.particular at gmail.com>
 Daniel Skinner <daniel at dasa.cc>
+Daniel Speichert <daniel at speichert.pl>
 Daniel Theophanes <kardianos at gmail.com>
 Darren Elwood <darren at textnode.com>
+Datong Sun <dndx at idndx.com>
 Dave Cheney <dave at cheney.net>
+David Brophy <dave at brophy.uk>
 David Bürgin <676c7473 at gmail.com>
 David Calavera <david.calavera at gmail.com>
 David du Colombier <0intro at gmail.com>
@@ -176,21 +198,26 @@ David Howden <dhowden at gmail.com>
 David Jakob Fritz <david.jakob.fritz at gmail.com>
 David Leon Gil <coruus at gmail.com>
 David R. Jenni <david.r.jenni at gmail.com>
+David Sansome <me at davidsansome.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 Bernard <db047h at gmail.com>
 Denis Brandolini <denis.brandolini at gmail.com>
+Denys Honsiorovskyi <honsiorovskyi at gmail.com>
 Derek Buitenhuis <derek.buitenhuis at gmail.com>
 Derek Parker <parkerderek86 at gmail.com>
+Derek Shockey <derek.shockey at gmail.com>
 Develer SRL
 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>
 Dirk Gadsden <dirk at esherido.com>
+Diwaker Gupta <diwakergupta at gmail.com>
 Dmitri Shuralyov <shurcooL at gmail.com>
+Dmitriy Dudkin <dudkin.dmitriy 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>
@@ -200,6 +227,7 @@ Donald Huang <don.hcd at gmail.com>
 Donovan Hide <donovanhide at gmail.com>
 Dropbox, Inc.
 Duncan Holm <mail at frou.org>
+Dustin Herbison <djherbis 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>
@@ -211,8 +239,10 @@ Eivind Uggedal <eivind at uggedal.com>
 Elias Naur <elias.naur at gmail.com>
 Emil Hessman <c.emil.hessman at gmail.com> <emil at hessman.se>
 Emmanuel Odeke <emm.odeke at gmail.com> <odeke at ualberta.ca>
+Empirical Interfaces Inc.
 Eoghan Sherry <ejsherry at gmail.com>
 Eric Clark <zerohp at gmail.com>
+Eric Engestrom <eric at engestrom.ch>
 Eric Lagergren <ericscottlagergren at gmail.com>
 Eric Milliken <emilliken at gmail.com>
 Eric Roshan-Eisner <eric.d.eisner at gmail.com>
@@ -220,6 +250,7 @@ Erik Aigner <aigner.erik at gmail.com>
 Erik Dubbelboer <erik at dubbelboer.com>
 Erik St. Martin <alakriti at gmail.com>
 Erik Westrup <erik.westrup at gmail.com>
+Ernest Chiang <ernest_chiang at htc.com>
 Esko Luontola <esko.luontola at gmail.com>
 Evan Phoenix <evan at phx.io>
 Evan Shaw <chickencha at gmail.com>
@@ -231,6 +262,7 @@ Fastly, Inc.
 Fatih Arslan <fatih at arslan.io>
 Fazlul Shahriar <fshahriar at gmail.com>
 Felix Geisendörfer <haimuiba at gmail.com>
+Filippo Valsorda <hi at filippo.io>
 Firmansyah Adiputra <frm.adiputra at gmail.com>
 Florian Uekermann <florian at uekermann-online.de>
 Florian Weimer <fw at deneb.enyo.de>
@@ -241,6 +273,7 @@ Francisco Souza <franciscossouza at gmail.com>
 Frederick Kelly Mayle III <frederickmayle at gmail.com>
 Fredrik Enestad <fredrik.enestad at soundtrackyourbrand.com>
 Frithjof Schulze <schulze at math.uni-hannover.de> <sfrithjof at gmail.com>
+Frits van Bommel <fvbommel at gmail.com>
 Gabriel Aszalos <gabriel.aszalos at gmail.com>
 Gary Burd <gary at beagledreams.com>
 Gaurish Sharma <contact at gaurishsharma.com>
@@ -262,34 +295,44 @@ 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>
+Gyu-Ho Lee <gyuhox at gmail.com>
+H. İbrahim Güngör <igungor 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>
+Harshavardhana <hrshvardhana 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>
+Hironao OTSUBO <motemen at gmail.com>
 Hiroshi Ioka <hirochachacha at gmail.com>
+Hitoshi Mitake <mitake.hitoshi at gmail.com>
+Holden Huang <ttyh061 at gmail.com>
 Hong Ruiqi <hongruiqi at gmail.com>
 Hsin-Ho Yeh <yhh92u at gmail.com>
 Hu Keping <hukeping at huawei.com>
 Ian Gudger <ian at loosescre.ws>
 IBM
 Icarus Sparry <golang at icarus.freeuk.com>
+Idora Shinatose <idora.shinatose at gmail.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>
 Intel Corporation
+Irieda Noboru <irieda at gmail.com>
 Isaac Wagner <ibw at isaacwagner.me>
 Ivan Ukhov <ivan.ukhov at gmail.com>
+Jacob Hoffman-Andrews <github at hoffman-andrews.com>
 Jae Kwon <jae at tendermint.com>
 Jakob Borg <jakob at nym.se>
 Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
+James Bardin <j.bardin at gmail.com>
 James David Chalfant <james.chalfant at gmail.com>
 James Fysh <james.fysh at gmail.com>
 James Gray <james at james4k.com>
@@ -299,6 +342,7 @@ James Schofield <james at shoeboxapp.com>
 James Sweet <james.sweet88 at googlemail.com>
 James Toy <nil at opensesame.st>
 James Whitehead <jnwhiteh at gmail.com>
+Jamil Djadala <djadala at gmail.com>
 Jan H. Hosang <jan.hosang at gmail.com>
 Jan Mercl <0xjnml at gmail.com>
 Jan Mercl <befelemepeseveze at gmail.com>
@@ -306,6 +350,7 @@ Jan Newmarch <jan.newmarch at gmail.com>
 Jan Ziak <0xe2.0x9a.0x9b at gmail.com>
 Jani Monoses <jani.monoses at ubuntu.com>
 Jaroslavas Počepko <jp at webmaster.ms>
+Jason Barnett <jason.w.barnett at gmail.com>
 Jason Del Ponte <delpontej at gmail.com>
 Jason Travis <infomaniac7 at gmail.com>
 Jay Weisskopf <jay at jayschwa.net>
@@ -315,6 +360,7 @@ Jeff Sickel <jas at corpus-callosum.com>
 Jeff Wendling <jeff at spacemonkey.com>
 Jens Frederich <jfrederich at gmail.com>
 Jeremy Jackins <jeremyjackins at gmail.com>
+Jess Frazelle <me at jessfraz.com>
 Jihyun Yu <yjh0502 at gmail.com>
 Jim McGrath <jimmc2 at gmail.com>
 Jimmy Zelinskie <jimmyzelinskie at gmail.com>
@@ -322,17 +368,23 @@ Jingcheng Zhang <diogin at gmail.com>
 Jingguo Yao <yaojingguo at gmail.com>
 Jiong Du <londevil at gmail.com>
 Joakim Sernbrant <serbaut at gmail.com>
+Joe Farrell <joe2farrell at gmail.com>
 Joe Harrison <joehazzers at gmail.com>
+Joe Henke <joed.henke at gmail.com>
 Joe Poirier <jdpoirier at gmail.com>
 Joe Shaw <joe at joeshaw.org>
+Joe Sylve <joe.sylve at gmail.com>
 Joe Tsai <joetsai at digital-static.net>
 Joel Stemmer <stemmertech at gmail.com>
+Johan Sageryd <j at 1616.se>
 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 Jeffery <jjeffery at sp.com.au>
 John Jenkins <twodopeshaggy at gmail.com>
 John Potocny <johnp at vividcortex.com>
+John Schnake <schnake.john at gmail.com>
 John Shahid <jvshahid at gmail.com>
 John Tuley <john at tuley.org>
 Jonathan Boulle <jonathanboulle at gmail.com>
@@ -350,6 +402,7 @@ Joshua Chase <jcjoshuachase at gmail.com>
 Jostein Stuhaug <js at solidsystem.no>
 JT Olds <jtolds at xnet5.com>
 Jukka-Pekka Kekkonen <karatepekka at gmail.com>
+Julian Kornberger <jk+github at digineo.de>
 Julian Phillips <julian at quantumfyre.co.uk>
 Julien Schmidt <google at julienschmidt.com>
 Justin Nuß <nuss.justin at gmail.com>
@@ -366,8 +419,13 @@ Kelvin Foo Chuan Lyi <vmirage at gmail.com>
 Ken Friedenbach <kenliz at cruzio.com>
 Ken Rockot <ken at oz.gs>
 Ken Sedgwick <ken at bonsai.com>
+Kenji Kaneda <kenji.kaneda at gmail.com>
+Kenneth Shaw <kenshaw at gmail.com>
 Kenny Grant <kennygrant at gmail.com>
 Kevin Ballard <kevin at sb.org>
+Kevin Burke <kev at inburke.com>
+Kevin Kirsche <kev.kirsche at gmail.com>
+Kevin Vu <kevin.m.vu at gmail.com>
 Klaus Post <klauspost at gmail.com>
 Konstantin Shaposhnikov <k.shaposhnikov at gmail.com>
 KPCompass, Inc.
@@ -379,12 +437,14 @@ 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 Hinman <hinman at gmail.com>
 Lee Packham <lpackham at gmail.com>
 Lewin Bormann <lewin.bormann at gmail.com>
 Liberty Fund Inc
 Linaro Limited
 Lloyd Dewolf <foolswisdom at gmail.com>
 Lorenzo Stoakes <lstoakes at gmail.com>
+Luan Santos <cfcluan at gmail.com>
 Luca Greco <luca.greco at alcacoop.it>
 Lucien Stuker <lucien.stuker at gmail.com>
 Lucio De Re <lucio.dere at gmail.com>
@@ -397,6 +457,7 @@ 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 Severson <miquella at gmail.com>
 Mark Theunissen <mark.theunissen at gmail.com>
 Marko Juhani Silokunnas <marko.silokunnas at gmail.com>
 Marko Tiikkaja <marko at joh.to>
@@ -404,12 +465,14 @@ Markover Inc. DBA Poptip
 Markus Duft <markus.duft at salomon.at>
 Markus Sonderegger <marraison at gmail.com>
 Markus Zimmermann <zimmski at gmail.com>
+Martin Garton <garton at gmail.com>
 Martin Möhrmann <martisch at uos.de>
 Martin Neubauer <m.ne at gmx.net>
 Martin Olsson <martin at minimum.se>
 Marvin Stenger <marvin.stenger94 at gmail.com>
 Mateusz Czapliński <czapkofan at gmail.com>
 Mathias Beke <git at denbeke.be>
+Mathias Leppich <mleppich at muhqu.de>
 Mathieu Lonjaret <mathieu.lonjaret at gmail.com>
 Mats Lidell <mats.lidell at cag.se>
 Matt Aimonetti <mattaimonetti at gmail.com>
@@ -419,6 +482,7 @@ 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 Robenolt <matt at ydekproductions.com>
 Matt T. Proud <matt.proud at gmail.com>
 Matt Williams <gh at mattyw.net>
 Matthew Brennan <matty.brennan at gmail.com>
@@ -426,6 +490,7 @@ 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>
+Maxwell Krohn <themax at gmail.com>
 Meir Fischer <meirfischer at gmail.com>
 Meng Zhuo <mengzhuo1203 at gmail.com>
 Meteor Development Group
@@ -439,6 +504,7 @@ 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 McConville <momcconville at gmail.com>
 Michael Pearson <mipearson at gmail.com>
 Michael Schaller <michael at 5challer.de>
 Michael Stapelberg <michael at stapelberg.de>
@@ -447,19 +513,24 @@ Michael Vetter <g.bluehut at gmail.com>
 Michal Bohuslávek <mbohuslavek at gmail.com>
 Michał Derkacz <ziutek at lnet.pl>
 Miek Gieben <miek at miek.nl>
+Miguel Mendez <stxmendez at gmail.com>
 Mihai Borobocea <MihaiBorobocea at gmail.com>
 Mikael Tillenius <mikti42 at gmail.com>
 Mike Andrews <mra at xoba.com>
 Mike Rosset <mike.rosset at gmail.com>
+Mikhail Gusarov <dottedmag at dottedmag.net>
 Mikhail Panchenko <m at mihasya.com>
 Miki Tebeka <miki.tebeka at gmail.com>
 Mikio Hara <mikioh.mikioh at gmail.com>
 Mikkel Krautz <mikkel at krautz.dk>
 Miquel Sabaté Solà <mikisabate at gmail.com>
 Mohit Agarwal <mohit at sdf.org>
+Monty Taylor <mordred at inaugust.com>
 Moov Corporation
 Moriyoshi Koizumi <mozo at mozo.jp>
+Morten Siebuhr <sbhr at sbhr.dk>
 Môshe van der Sterre <moshevds at gmail.com>
+Muhammed Uluyol <uluyol0 at gmail.com>
 Nan Deng <monnand at gmail.com>
 Nathan John Youngman <nj at nathany.com>
 Nathan Otterness <otternes at cs.unc.edu>
@@ -467,17 +538,24 @@ Nathan P Finch <nate.finch at gmail.com>
 Nathan VanBenschoten <nvanbenschoten at gmail.com>
 Nathan Youngman <git at nathany.com>
 Neelesh Chandola <neelesh.c98 at gmail.com>
+Netflix, Inc.
 Nevins Bartolomeo <nevins.bartolomeo at gmail.com>
 ngmoco, LLC
+Niall Sheridan <nsheridan at gmail.com>
+Nic Day <nic.day at me.com>
 Nicholas Katsaros <nick at nickkatsaros.com>
 Nicholas Presta <nick at nickpresta.ca> <nick1presta at gmail.com>
 Nicholas Sullivan <nicholas.sullivan at gmail.com>
 Nicholas Waples <nwaples at gmail.com>
 Nick Craig-Wood <nick at craig-wood.com> <nickcw at gmail.com>
+Nick Patavalis <nick.patavalis at gmail.com>
+Nick Petroni <npetroni at cs.umd.edu>
 Nicolas Kaiser <nikai at nikai.net>
 Nicolas Owens <mischief at offblast.org>
 Nicolas S. Dade <nic.dade at gmail.com>
+Niels Widger <niels.widger at gmail.com>
 Nigel Kerr <nigel.kerr at gmail.com>
+Niko Dziemba <niko at dziemba.com>
 Nikolay Turpitko <nikolay at turpitko.com>
 Noah Campbell <noahcampbell at gmail.com>
 Norberto Lopes <nlopes.ml at gmail.com>
@@ -486,8 +564,11 @@ Oling Cat <olingcat at gmail.com>
 Oliver Hookins <ohookins at gmail.com>
 Olivier Antoine <olivier.antoine at gmail.com>
 Olivier Duperray <duperray.olivier at gmail.com>
+Olivier Poitrey <rs at dailymotion.com>
 Olivier Saingre <osaingre at gmail.com>
 Oracle
+Orange
+Özgür Kesim <oec-go at kesim.org>
 Padraig Kitterick <padraigkitterick at gmail.com>
 Palm Stone Games
 Paolo Giarrusso <p.giarrusso at gmail.com>
@@ -507,6 +588,7 @@ Paul Rosania <paul.rosania 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>
+Paulo Casaretto <pcasaretto at gmail.com>
 Pavel Paulau <pavel.paulau at gmail.com>
 Pavel Zinovkin <pavel.zinovkin at gmail.com>
 Pawel Knap <pawelknap88 at gmail.com>
@@ -523,11 +605,16 @@ 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 Børgesen <philip.borgesen at gmail.com>
+Philip Hofer <phofer at umich.edu>
 Philip K. Warren <pkwarren at gmail.com>
+Pierre Durand <pierredurand at gmail.com>
 Pierre Roullon <pierre.roullon at gmail.com>
 Pieter Droogendijk <pieter at binky.org.uk>
 Pietro Gagliardi <pietro10 at mac.com>
+Prashant Varanasi <prashant at prashantv.com>
 Preetam Jinka <pj at preet.am>
+Quan Tran <qeed.quan at gmail.com>
 Quan Yong Zhai <qyzhai at gmail.com>
 Quentin Perez <qperez at ocs.online.net>
 Quoc-Viet Nguyen <afelion at gmail.com>
@@ -538,9 +625,11 @@ Ralph Corderoy <ralph at inputplus.co.uk>
 Red Hat, Inc.
 Reinaldo de Souza Jr <juniorz at gmail.com>
 Rémy Oudompheng <oudomphe at phare.normalesup.org>
+Ricardo Padilha <ricardospadilha at gmail.com>
 Richard Barnes <rlb at ipv.sx>
 Richard Crowley <r at rcrowley.org>
 Richard Eric Gavaletz <gavaletz at gmail.com>
+Richard Miller <miller.research at gmail.com>
 Richard Musiol <mail at richard-musiol.de>
 Rick Arnold <rickarnoldjr at gmail.com>
 Risto Jaakko Saarelma <rsaarelm at gmail.com>
@@ -556,6 +645,7 @@ Rodrigo Moraes de Oliveira <rodrigo.moraes at gmail.com>
 Rodrigo Rafael Monti Kochenburger <divoxx at gmail.com>
 Roger Pau Monné <royger at gmail.com>
 Roger Peppe <rogpeppe at gmail.com>
+Roland Shoemaker <rolandshoemaker at gmail.com>
 Ron Hashimoto <mail at h2so5.net>
 Ron Minnich <rminnich at gmail.com>
 Ross Light <rlight2 at gmail.com>
@@ -567,8 +657,12 @@ Ryan Seys <ryan at ryanseys.com>
 Ryan Slade <ryanslade at gmail.com>
 S.Çağlar Onur <caglar at 10ur.org>
 Salmān Aljammāz <s at 0x65.net>
+Sam Hug <samuel.b.hug at gmail.com>
+Sam Whited <sam at samwhited.com>
 Sanjay Menakuru <balasanjay at gmail.com>
+Sasha Sobol <sasha at scaledinference.com>
 Scott Barron <scott.barron at github.com>
+Scott Bell <scott at sctsm.com>
 Scott Ferguson <scottwferg at gmail.com>
 Scott Lawrence <bytbox at gmail.com>
 Sebastien Binet <seb.binet at gmail.com>
@@ -577,17 +671,23 @@ Sergei Skorobogatov <skorobo at rambler.ru>
 Sergey 'SnakE'  Gromov <snake.scaly at gmail.com>
 Sergio Luis O. B. Correia <sergio at correia.cc>
 Seth Hoenig <seth.a.hoenig at gmail.com>
+Seth Vargo <sethvargo at gmail.com>
+Shahar Kohanim <skohanim at gmail.com>
 Shane Hansen <shanemhansen at gmail.com>
 Shaozhen Ding <dsz0111 at gmail.com>
 Shawn Smith <shawn.p.smith at gmail.com>
 Shenghou Ma <minux.ma at gmail.com>
+Shinji Tanaka <shinji.tanaka at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
 Silvan Jegen <s.jegen at gmail.com>
+Simon Jefford <simon.jefford at gmail.com>
+Simon Thulbourn <simon+github at thulbourn.com>
 Simon Whitehead <chemnova at gmail.com>
 Sokolov Yura <funny.falcon at gmail.com>
 Spencer Nelson <s at spenczar.com>
 Spring Mc <heresy.mc at gmail.com>
 Square, Inc.
+Sridhar Venkatakrishnan <sridhar at laddoo.net>
 StalkR <stalkr at stalkr.net>
 Stan Schwertly <stan at schwertly.com>
 Stefan Nilsson <snilsson at nada.kth.se> <trolleriprofessorn at gmail.com>
@@ -605,6 +705,7 @@ Szabolcs Nagy <nsz at port70.net>
 Tad Glines <tad.glines at gmail.com>
 Taj Khattra <taj.khattra at gmail.com>
 Takeshi YAMANASHI <9.nashi at gmail.com>
+Tal Shprecher <tshprecher at gmail.com>
 Tamir Duberstein <tamird at gmail.com>
 Tarmigan Casebolt <tarmigan at gmail.com>
 Taru Karttunen <taruti at taruti.net>
@@ -615,9 +716,12 @@ Thomas Alan Copeland <talan.copeland at gmail.com>
 Thomas Desrosiers <thomasdesr at gmail.com>
 Thomas Kappler <tkappler at gmail.com>
 Thorben Krueger <thorben.krueger at gmail.com>
+Tilman Dilo <tilman.dilo at gmail.com>
 Tim Cooijmans <timcooijmans at gmail.com>
+Tim Ebringer <tim.ebringer at gmail.com>
 Timo Savola <timo.savola at gmail.com>
 Timo Truyts <alkaloid.btx at gmail.com>
+Timothy Studd <tim at timstudd.com>
 Tobias Columbus <tobias.columbus at gmail.com>
 Todd Neal <todd at tneal.org>
 Tom Heng <zhm20070928 at gmail.com>
@@ -634,20 +738,25 @@ Tyler Treat <ttreat31 at gmail.com>
 Ugorji Nwoke <ugorji at gmail.com>
 Ulf Holm Nielsen <doktor at dyregod.dk>
 Ulrich Kunitz <uli.kunitz at gmail.com>
+Upthere, Inc.
 Uriel Mangado <uriel at berlinblue.org>
+Vadim Grek <vadimprog at gmail.com>
 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>
+Vishvananda Ishaya <vishvananda at gmail.com>
 Vladimir Nikishenko <vova616 at gmail.com>
 Volker Dobler <dr.volker.dobler at gmail.com>
 Wei Guangjing <vcc.163 at gmail.com>
 Willem van der Schyff <willemvds at gmail.com>
 William Josephson <wjosephson at gmail.com>
 William Orr <will at worrbase.com> <ay1244 at gmail.com>
+Wisdom Omuya <deafgoat at gmail.com>
 Xia Bin <snyh at snyh.org>
 Xing Xing <mikespook at gmail.com>
+Xudong Zhang <felixmelon at gmail.com>
 Yahoo Inc.
 Yann Kerhervé <yann.kerherve at gmail.com>
 Yao Zhang <lunaria21 at gmail.com>
@@ -661,6 +770,7 @@ Yoshiyuki Kanno <nekotaroh at gmail.com> <yoshiyuki.kanno at stoic.co.jp>
 Yusuke Kagiwada <block.rxckin.beats at gmail.com>
 Yuusei Kuwana <kuwana at kumama.org>
 Yuval Pavel Zholkover <paulzhol at gmail.com>
+Zemanta d.o.o.
 Ziad Hatahet <hatahet at gmail.com>
 Zorion Arrizabalaga <zorionk at gmail.com>
 申习之 <bronze1man at gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index ae07cfc..6763f52 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -37,6 +37,8 @@ Aaron France <aaron.l.france at gmail.com>
 Aaron Jacobs <jacobsa at google.com>
 Aaron Kemp <kemp.aaron at gmail.com>
 Aaron Torres <tcboox at gmail.com>
+Aaron Zinman <aaron at azinman.com>
+Abe Haskins <abeisgreat at abeisgreat.com>
 Abhinav Gupta <abhinav.g90 at gmail.com>
 Adam Langley <agl at golang.org>
 Adrian Nos <nos.adrian at gmail.com>
@@ -44,7 +46,10 @@ Adrian O'Grady <elpollouk at gmail.com>
 Adrien Bustany <adrien-xx-google at bustany.org>
 Aécio Júnior <aeciodantasjunior at gmail.com>
 Ahmed Waheed Moanes <oneofone at gmail.com>
+Ahmy Yulrizka <yulrizka at gmail.com>
+Aiden Scandella <ai at uber.com>
 Ainar Garipov <gugl.zadolbal at gmail.com>
+Akihiro Suda <suda.kyoto at gmail.com>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Alan Donovan <adonovan at google.com>
 Alan Shreve <alan at inconshreveable.com>
@@ -53,6 +58,7 @@ Alberto Bertogli <albertito at blitiri.com.ar>
 Alberto Donizetti <alb.donizetti at gmail.com>
 Alberto García Hierro <alberto at garciahierro.com> <alberto.garcia.hierro at gmail.com>
 Aleksandar Dezelin <dezelin at gmail.com>
+Alessandro Arzilli <alessandro.arzilli at gmail.com>
 Alex A Skinner <alex at lx.lc>
 Alex Brainman <alex.brainman at gmail.com>
 Alex Bramley <abramley at google.com>
@@ -60,6 +66,7 @@ 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>
+Alex Vaghin <crhyme at google.com>
 Alexander Demakin <alexander.demakin at gmail.com>
 Alexander Larsson <alexander.larsson at gmail.com>
 Alexander Morozov <lk4d4math at gmail.com>
@@ -80,6 +87,7 @@ Aliaksandr Valialkin <valyala at gmail.com>
 Alif Rachmawadi <subosito at gmail.com>
 Amir Mohammad Saied <amir at gluegadget.com>
 Amrut Joshi <amrut.joshi at gmail.com>
+Andre Nathan <andrenth 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>
@@ -98,6 +106,7 @@ 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 Werner <andrew at upthere.com> <awerner32 at gmail.com>
 Andrew Wilkins <axwalk at gmail.com>
 Andrew Williams <williams.andrew at gmail.com>
 Andrey Mirtchovski <mirtchovski at gmail.com>
@@ -119,6 +128,7 @@ Apisak Darakananda <pongad at gmail.com>
 Aram Hăvărneanu <aram at mgk.ro>
 Areski Belaid <areski at gmail.com>
 Arkadi Pyuro <arkadi at google.com>
+Arlo Breault <arlolra at gmail.com>
 Arnaud Ysmal <arnaud.ysmal at gmail.com>
 Arne Hormann <arnehormann at gmail.com>
 Arnout Engelen <arnout at bzzt.net>
@@ -127,9 +137,12 @@ Artyom Pervukhin <artyom.pervukhin at gmail.com>
 Arvindh Rajesh Tamilmani <art at a-30.net>
 Asim Shankar <asimshankar at gmail.com>
 Ato Araki <ato.araki at gmail.com>
+Audrey Lim <audreylh at gmail.com>
+Augusto Roman <aroman 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>
+Ayanamist Yang <ayanamist at gmail.com>
 Aymerick Jéhanne <aymerick at jehanne.org>
 Balazs Lecz <leczb at google.com>
 Ben Burkert <ben at benburkert.com>
@@ -139,10 +152,12 @@ Ben Lynn <benlynn at gmail.com>
 Ben Olive <sionide21 at gmail.com>
 Benjamin Black <b at b3k.us>
 Benjamin Prosnitz <bprosnitz at google.com>
+Benjamin Wester <bwester at squareup.com>
 Benny Siegert <bsiegert at gmail.com>
 Benoit Sigoure <tsunanet at gmail.com>
 Berengar Lehr <Berengar.Lehr at gmx.de>
 Bill Neubauer <wcn at golang.org> <wcn at google.com> <bill.neubauer at gmail.com>
+Bill O'Farrell <billo at ca.ibm.com>
 Bill Thiede <couchmoney at gmail.com>
 Billie Harold Cleek <bhcleek at gmail.com>
 Bjorn Tillenius <bjorn at tillenius.me>
@@ -152,6 +167,8 @@ 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>
+Brady Catherman <brady at gmail.com>
+Brady Sullivan <brady at bsull.com>
 Brandon Gilmore <varz at google.com>
 Brendan Daniel Tracey <tracey.brendan at gmail.com>
 Brendan O'Dea <bod at golang.org>
@@ -163,9 +180,10 @@ Brian Ketelsen <bketelsen at gmail.com>
 Brian Slesinsky <skybrian at google.com>
 Brian Smith <ohohvi at gmail.com>
 Bryan C. Mills <bcmills at google.com>
+Bryan Chan <bryan.chan at ca.ibm.com>
 Bryan Ford <brynosaurus at gmail.com>
-Burcu Dogan <jbd at google.com> <burcujdogan at gmail.com>
 Caine Tighe <arctanofyourface at gmail.com>
+Caio Marcelo de Oliveira Filho <caio.oliveira at intel.com>
 Caleb Spare <cespare at gmail.com>
 Carl Chatfield <carlchatfield at gmail.com>
 Carl Jackson <carl at stripe.com>
@@ -176,6 +194,7 @@ 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>
+Catalin Nicutar <cnicutar at google.com>
 Catalin Patulea <catalinp at google.com>
 Cedric Staub <cs at squareup.com>
 Cezar Sá Espinola <cezarsa at gmail.com>
@@ -183,6 +202,7 @@ ChaiShushan <chaishushan at gmail.com>
 Charles L. Dorian <cldorian at gmail.com>
 Charles Lee <zombie.fml at gmail.com>
 Charles Weill <weill at google.com>
+Cherry Zhang <cherryyz at google.com>
 Chris Broadfoot <cbro at golang.org>
 Chris Dollin <ehog.hedge at gmail.com>
 Chris Farmiloe <chrisfarms at gmail.com>
@@ -194,25 +214,32 @@ 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>
+Chris Zou <chriszou at ca.ibm.com>
+Christian Couder <chriscool at tuxfamily.org>
 Christian Himpel <chressie at googlemail.com> <chressie at gmail.com>
 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 Nelson <nadiasvertex at gmail.com>
 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>
+Christy Perez <christy at linux.vnet.ibm.com>
 CL Sung <clsung at gmail.com> <cl_sung at htc.com>
 Clement Skau <clementskau at gmail.com>
 Colby Ranger <cranger at google.com>
 Colin Cross <ccross at android.com>
+Colin Edwards <colin at recursivepenguin.com>
 Colin Kennedy <moshen.colin at gmail.com>
+Conrad Irwin <conrad.irwin at gmail.com>
 Conrad Meyer <cemeyer at cs.washington.edu>
 Corey Thomasson <cthom.lists at gmail.com>
 Cosmos Nicolaou <cnicolaou at google.com>
 Cristian Staretu <unclejacksons at gmail.com>
+Cuihtlauac ALVARADO <cuihtlauac.alvarado at orange.com>
 Damian Gryski <dgryski at gmail.com>
 Damien Neil <dneil at google.com>
 Dan Caddigan <goldcaddy77 at gmail.com>
@@ -230,8 +257,10 @@ Daniel Morsing <daniel.morsing at gmail.com>
 Daniel Nadasi <dnadasi at google.com>
 Daniel Ortiz Pereira da Silva <daniel.particular at gmail.com>
 Daniel Skinner <daniel at dasa.cc>
+Daniel Speichert <daniel at speichert.pl>
 Daniel Theophanes <kardianos at gmail.com>
 Darren Elwood <darren at textnode.com>
+Datong Sun <dndx at idndx.com>
 Dave Borowitz <dborowitz at google.com>
 Dave Bort <dbort at golang.org>
 Dave Cheney <dave at cheney.net>
@@ -240,6 +269,7 @@ Dave Grijalva <dgrijalva at ngmoco.com>
 David Anderson <danderson at google.com>
 David Barnett <dbarnett at google.com>
 David Benjamin <davidben at google.com>
+David Brophy <dave at brophy.uk>
 David Bürgin <676c7473 at gmail.com>
 David Calavera <david.calavera at gmail.com>
 David Chase <drchase at google.com>
@@ -255,6 +285,7 @@ David Leon Gil <coruus at gmail.com>
 David McLeish <davemc at google.com>
 David Presotto <presotto at gmail.com>
 David R. Jenni <david.r.jenni at gmail.com>
+David Sansome <me at davidsansome.com>
 David Symonds <dsymonds at golang.org>
 David Thomas <davidthomas426 at gmail.com>
 David Titarenco <david.titarenco at gmail.com>
@@ -262,15 +293,19 @@ Davies Liu <davies.liu at gmail.com>
 Dean Prichard <dean.prichard at gmail.com>
 Denis Bernard <db047h at gmail.com>
 Denis Brandolini <denis.brandolini at gmail.com>
+Denys Honsiorovskyi <honsiorovskyi at gmail.com>
 Derek Buitenhuis <derek.buitenhuis at gmail.com>
 Derek Che <drc at yahoo-inc.com>
 Derek Parker <parkerderek86 at gmail.com>
+Derek Shockey <derek.shockey 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>
 Dirk Gadsden <dirk at esherido.com>
+Diwaker Gupta <diwakergupta at gmail.com>
 Dmitri Shuralyov <shurcooL at gmail.com>
+Dmitriy Dudkin <dudkin.dmitriy 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>
@@ -280,8 +315,11 @@ Dominik Honnef <dominik.honnef at gmail.com>
 Dominik Vogt <vogt at linux.vnet.ibm.com>
 Donald Huang <don.hcd at gmail.com>
 Donovan Hide <donovanhide at gmail.com>
+Doug Anderson <douga at google.com>
 Drew Hintz <adhintz at google.com>
 Duncan Holm <mail at frou.org>
+Dustin Carlino <dcarlino at google.com>
+Dustin Herbison <djherbis at gmail.com>
 Dustin Long <dustmop at gmail.com>
 Dustin Sallings <dsallings at gmail.com>
 Dustin Shields-Cloues <dcloues at gmail.com>
@@ -296,6 +334,7 @@ Emil Hessman <c.emil.hessman at gmail.com> <emil at hessman.se>
 Emmanuel Odeke <emm.odeke at gmail.com> <odeke at ualberta.ca>
 Eoghan Sherry <ejsherry at gmail.com>
 Eric Clark <zerohp at gmail.com>
+Eric Engestrom <eric at engestrom.ch>
 Eric Garrido <ekg at google.com>
 Eric Koleda <ekoleda+devrel at google.com>
 Eric Lagergren <ericscottlagergren at gmail.com>
@@ -305,7 +344,9 @@ Erik Aigner <aigner.erik at gmail.com>
 Erik Dubbelboer <erik at dubbelboer.com>
 Erik St. Martin <alakriti at gmail.com>
 Erik Westrup <erik.westrup at gmail.com>
+Ernest Chiang <ernest_chiang at htc.com>
 Esko Luontola <esko.luontola at gmail.com>
+Ethan Burns <eaburns at google.com>
 Evan Broder <evan at stripe.com>
 Evan Brown <evanbrown at google.com>
 Evan Kroske <evankroske at google.com>
@@ -320,6 +361,7 @@ Fatih Arslan <fatih at arslan.io>
 Fazlul Shahriar <fshahriar at gmail.com>
 Federico Simoncelli <fsimonce at redhat.com>
 Felix Geisendörfer <haimuiba at gmail.com>
+Filippo Valsorda <hi at filippo.io>
 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>
@@ -332,11 +374,13 @@ Francisco Souza <franciscossouza at gmail.com>
 Frederick Kelly Mayle III <frederickmayle at gmail.com>
 Fredrik Enestad <fredrik.enestad at soundtrackyourbrand.com>
 Frithjof Schulze <schulze at math.uni-hannover.de> <sfrithjof at gmail.com>
+Frits van Bommel <fvbommel at gmail.com>
 Fumitoshi Ukai <ukai at google.com>
 Gaal Yahas <gaal at google.com>
 Gabriel Aszalos <gabriel.aszalos at gmail.com>
 Garrick Evans <garrick at google.com>
 Gary Burd <gary at beagledreams.com> <gary.burd at gmail.com>
+Gary Elliott <garyelliott at google.com>
 Gaurish Sharma <contact at gaurishsharma.com>
 Gautham Thambidorai <gautham.dorai at gmail.com>
 Geert-Johan Riemer <gjr19912 at gmail.com>
@@ -359,18 +403,25 @@ 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>
+Gyu-Ho Lee <gyuhox at gmail.com>
+H. İbrahim Güngör <igungor at gmail.com>
 Hajime Hoshi <hajimehoshi at gmail.com>
+Hallgrimur Gunnarsson <halg at google.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>
+Harshavardhana <hrshvardhana 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>
+Hironao OTSUBO <motemen at gmail.com>
 Hiroshi Ioka <hirochachacha at gmail.com>
+Hitoshi Mitake <mitake.hitoshi at gmail.com>
+Holden Huang <ttyh061 at gmail.com>
 Hong Ruiqi <hongruiqi at gmail.com>
 Hossein Sheikh Attar <hattar at google.com>
 Hsin-Ho Yeh <yhh92u at gmail.com>
@@ -379,21 +430,27 @@ Hyang-Ah Hana Kim <hakim at google.com> <hyangah at gmail.com>
 Ian Gudger <ian at loosescre.ws>
 Ian Lance Taylor <iant at golang.org>
 Icarus Sparry <golang at icarus.freeuk.com>
+Idora Shinatose <idora.shinatose at gmail.com>
 Igor Dolzhikov <bluesriverz at gmail.com>
 Ilya Tocar <ilya.tocar at intel.com>
 INADA Naoki <songofacandy at gmail.com>
 Ingo Krabbe <ikrabbe.ask at gmail.com>
 Ingo Oeser <nightlyone at googlemail.com> <nightlyone at gmail.com>
+Irieda Noboru <irieda at gmail.com>
 Isaac Wagner <ibw at isaacwagner.me>
 Ivan Krasin <krasin at golang.org>
 Ivan Ukhov <ivan.ukhov at gmail.com>
+Jaana Burcu Dogan <jbd at google.com> <jbd at golang.org> <burcujdogan at gmail.com>
 Jacob Baskin <jbaskin at google.com>
 Jacob H. Haven <jacob at cloudflare.com>
+Jacob Hoffman-Andrews <github at hoffman-andrews.com>
 Jae Kwon <jae at tendermint.com>
 Jakob Borg <jakob at nym.se>
 Jakub Čajka <jcajka at redhat.com>
 Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
 James Aguilar <jaguilar at google.com>
+James Bardin <j.bardin at gmail.com>
+James Chacon <jchacon at google.com>
 James David Chalfant <james.chalfant at gmail.com>
 James Fysh <james.fysh at gmail.com>
 James Gray <james at james4k.com>
@@ -408,6 +465,7 @@ James Whitehead <jnwhiteh at gmail.com>
 Jamie Gennis <jgennis at google.com> <jgennis at gmail.com>
 Jamie Turner <jamwt at dropbox.com>
 Jamie Wilkinson <jaq at spacepants.org>
+Jamil Djadala <djadala at gmail.com>
 Jan H. Hosang <jan.hosang at gmail.com>
 Jan Kratochvil <jan.kratochvil at redhat.com>
 Jan Mercl <0xjnml at gmail.com>
@@ -416,12 +474,14 @@ Jan Newmarch <jan.newmarch at gmail.com>
 Jan Ziak <0xe2.0x9a.0x9b at gmail.com>
 Jani Monoses <jani.monoses at ubuntu.com> <jani.monoses at gmail.com>
 Jaroslavas Počepko <jp at webmaster.ms>
+Jason Barnett <jason.w.barnett at gmail.com>
 Jason Del Ponte <delpontej at gmail.com>
 Jason Hall <jasonhall at google.com>
 Jason Travis <infomaniac7 at gmail.com>
 Jay Weisskopf <jay at jayschwa.net>
 Jean-Marc Eurin <jmeurin at google.com>
 Jed Denlea <jed at fastly.com>
+Jeff Craig <jeffcraig at google.com>
 Jeff Hodges <jeff at somethingsimilar.com>
 Jeff R. Allen <jra at nella.org> <jeff.allen at gmail.com>
 Jeff Sickel <jas at corpus-callosum.com>
@@ -430,6 +490,7 @@ Jens Frederich <jfrederich at gmail.com>
 Jeremiah Harmsen <jeremiah at google.com>
 Jeremy Jackins <jeremyjackins at gmail.com>
 Jeremy Schlatter <jeremy.schlatter at gmail.com>
+Jess Frazelle <me at jessfraz.com>
 Jihyun Yu <yjh0502 at gmail.com>
 Jim Cote <jfcote87 at gmail.com>
 Jim McGrath <jimmc2 at gmail.com>
@@ -438,13 +499,17 @@ Jingcheng Zhang <diogin at gmail.com>
 Jingguo Yao <yaojingguo at gmail.com>
 Jiong Du <londevil at gmail.com>
 Joakim Sernbrant <serbaut at gmail.com>
+Joe Farrell <joe2farrell at gmail.com>
 Joe Harrison <joehazzers at gmail.com>
+Joe Henke <joed.henke at gmail.com>
 Joe Poirier <jdpoirier at gmail.com>
 Joe Shaw <joe at joeshaw.org>
+Joe Sylve <joe.sylve at gmail.com>
 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>
+Johan Sageryd <j at 1616.se>
 John Asmuth <jasmuth at gmail.com>
 John Beisley <huin at google.com>
 John C Barstow <jbowtie at amathaine.com>
@@ -452,12 +517,15 @@ 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 Jeffery <jjeffery at sp.com.au>
 John Jenkins <twodopeshaggy at gmail.com>
 John Newlin <jnewlin at google.com>
 John Potocny <johnp at vividcortex.com>
+John Schnake <schnake.john at gmail.com>
 John Shahid <jvshahid at gmail.com>
 John Tuley <john at tuley.org>
 Jonathan Allie <jonallie at google.com>
+Jonathan Amsterdam <jba at google.com>
 Jonathan Boulle <jonathanboulle at gmail.com>
 Jonathan Feinberg <feinberg at google.com>
 Jonathan Gold <jgold.bg at gmail.com>
@@ -481,13 +549,18 @@ Jostein Stuhaug <js at solidsystem.no>
 JP Sugarbroad <jpsugar at google.com>
 JT Olds <jtolds at xnet5.com>
 Jukka-Pekka Kekkonen <karatepekka at gmail.com>
+Julia Hansbrough <flowerhack at google.com>
+Julian Kornberger <jk+github at digineo.de>
 Julian Phillips <julian at quantumfyre.co.uk>
 Julien Schmidt <google at julienschmidt.com>
 Jungho Ahn <jhahn at google.com>
+Jure Ham <jure.ham at zemanta.com>
 Justin Nuß <nuss.justin at gmail.com>
 Kai Backman <kaib at golang.org>
+Kamal Aboul-Hosn <aboulhosn at google.com>
 Kamil Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
 Kang Hu <hukangustc at gmail.com>
+Karan Dhiman <karandhi at ca.ibm.com>
 Kato Kazuyoshi <kato.kazuyoshi at gmail.com>
 Katrina Owen <katrina.owen at gmail.com>
 Kay Zhu <kayzhu at google.com>
@@ -502,14 +575,20 @@ Ken Friedenbach <kenliz at cruzio.com>
 Ken Rockot <ken at oz.gs> <ken.rockot at gmail.com>
 Ken Sedgwick <ken at bonsai.com>
 Ken Thompson <ken at golang.org>
+Kenji Kaneda <kenji.kaneda at gmail.com>
+Kenneth Shaw <kenshaw at gmail.com>
 Kenny Grant <kennygrant at gmail.com>
 Kevin Ballard <kevin at sb.org>
+Kevin Burke <kev at inburke.com>
+Kevin Kirsche <kev.kirsche at gmail.com>
 Kevin Klues <klueska at gmail.com> <klueska at google.com>
 Kevin Malachowski <chowski at google.com>
+Kevin Vu <kevin.m.vu at gmail.com>
 Kim Shrier <kshrier at racktopsystems.com>
 Kirklin McDonald <kirklin.mcdonald at gmail.com>
 Klaus Post <klauspost at gmail.com>
 Konstantin Shaposhnikov <k.shaposhnikov at gmail.com>
+Kris Rousey <krousey at google.com>
 Kristopher Watts <traetox at gmail.com>
 Kun Li <likunarmstrong at gmail.com>
 Kyle Consalus <consalus at gmail.com>
@@ -519,11 +598,13 @@ 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 Hinman <hinman at gmail.com>
 Lee Packham <lpackham at gmail.com>
 Lewin Bormann <lewin.bormann at gmail.com>
 Lloyd Dewolf <foolswisdom at gmail.com>
 Lorenzo Stoakes <lstoakes at gmail.com>
 Louis Kruger <louisk at google.com>
+Luan Santos <cfcluan at gmail.com>
 Luca Greco <luca.greco at alcacoop.it>
 Lucien Stuker <lucien.stuker at gmail.com>
 Lucio De Re <lucio.dere at gmail.com>
@@ -539,11 +620,13 @@ Manu Garg <manugarg at google.com>
 Manu S Ajith <neo at codingarena.in>
 Manuel Mendez <mmendez534 at gmail.com>
 Marc Weistroff <marc at weistroff.net>
+Marc-Antoine Ruel <maruel at chromium.org>
 Marcel van Lohuizen <mpvl at golang.org>
 Marco Hennings <marco.hennings at freiheit.com>
 Marga Manterola <marga at google.com>
 Marius Nuennerich <mnu at google.com>
 Mark Bucciarelli <mkbucc at gmail.com>
+Mark Severson <miquella at gmail.com>
 Mark Theunissen <mark.theunissen at gmail.com>
 Mark Zavislak <zavislak at google.com>
 Marko Juhani Silokunnas <marko.silokunnas at gmail.com>
@@ -552,12 +635,14 @@ 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 Garton <garton at gmail.com>
 Martin Möhrmann <martisch at uos.de>
 Martin Neubauer <m.ne at gmx.net>
 Martin Olsson <martin at minimum.se>
 Marvin Stenger <marvin.stenger94 at gmail.com>
 Mateusz Czapliński <czapkofan at gmail.com>
 Mathias Beke <git at denbeke.be>
+Mathias Leppich <mleppich at muhqu.de>
 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>
@@ -569,6 +654,7 @@ 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 Robenolt <matt at ydekproductions.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>
@@ -579,6 +665,7 @@ 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>
+Maxwell Krohn <themax at gmail.com>
 Meir Fischer <meirfischer at gmail.com>
 Meng Zhuo <mengzhuo1203 at gmail.com>
 Mhd Sulhan <m.shulhan at gmail.com>
@@ -595,9 +682,12 @@ Michael Lewis <mikelikespie at gmail.com>
 Michael MacInnis <Michael.P.MacInnis at gmail.com>
 Michael Marineau <michael.marineau at coreos.com>
 Michael Matloob <matloob at google.com>
+Michael McConville <momcconville at gmail.com>
 Michael McGreevy <mcgreevy at golang.org>
+Michael Munday <munday at ca.ibm.com>
 Michael Pearson <mipearson at gmail.com>
 Michael Piatek <piatek at google.com>
+Michael Pratt <mpratt 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>
@@ -608,22 +698,29 @@ Michal Bohuslávek <mbohuslavek at gmail.com>
 Michal Cierniak <cierniak at google.com>
 Michał Derkacz <ziutek at lnet.pl>
 Michalis Kargakis <michaliskargakis at gmail.com>
+Michel Lespinasse <walken at google.com>
 Miek Gieben <miek at miek.nl> <remigius.gieben at gmail.com>
+Miguel Mendez <stxmendez at gmail.com>
 Mihai Borobocea <MihaiBorobocea at gmail.com>
 Mikael Tillenius <mikti42 at gmail.com>
 Mike Andrews <mra at xoba.com>
+Mike Danese <mikedanese at google.com>
 Mike Rosset <mike.rosset at gmail.com>
 Mike Samuel <mikesamuel at gmail.com>
 Mike Solomon <msolo at gmail.com>
+Mikhail Gusarov <dottedmag at dottedmag.net>
 Mikhail Panchenko <m at mihasya.com>
 Miki Tebeka <miki.tebeka at gmail.com>
 Mikio Hara <mikioh.mikioh at gmail.com>
 Mikkel Krautz <mikkel at krautz.dk> <krautz at gmail.com>
 Miquel Sabaté Solà <mikisabate at gmail.com>
 Mohit Agarwal <mohit at sdf.org>
+Monty Taylor <mordred at inaugust.com>
 Moriyoshi Koizumi <mozo at mozo.jp>
+Morten Siebuhr <sbhr at sbhr.dk>
 Môshe van der Sterre <moshevds at gmail.com>
 Mrunal Patel <mrunalp at gmail.com>
+Muhammed Uluyol <uluyol0 at gmail.com>
 Nan Deng <monnand at gmail.com>
 Nathan John Youngman <nj at nathany.com>
 Nathan Otterness <otternes at cs.unc.edu>
@@ -633,17 +730,23 @@ Nathan Youngman <git at nathany.com>
 Nathan(yinian) Hu <nathanhu at google.com>
 Neelesh Chandola <neelesh.c98 at gmail.com>
 Nevins Bartolomeo <nevins.bartolomeo at gmail.com>
+Niall Sheridan <nsheridan at gmail.com>
+Nic Day <nic.day at me.com>
 Nicholas Katsaros <nick at nickkatsaros.com>
 Nicholas Presta <nick at nickpresta.ca> <nick1presta at gmail.com>
 Nicholas Sullivan <nicholas.sullivan at gmail.com>
 Nicholas Waples <nwaples at gmail.com>
 Nick Cooper <nmvc at google.com>
 Nick Craig-Wood <nick at craig-wood.com> <nickcw at gmail.com>
+Nick Patavalis <nick.patavalis at gmail.com>
+Nick Petroni <npetroni at cs.umd.edu>
 Nicolas Kaiser <nikai at nikai.net>
 Nicolas Owens <mischief at offblast.org>
 Nicolas S. Dade <nic.dade at gmail.com>
+Niels Widger <niels.widger at gmail.com>
 Nigel Kerr <nigel.kerr at gmail.com>
 Nigel Tao <nigeltao at golang.org>
+Niko Dziemba <niko at dziemba.com>
 Nikolay Turpitko <nikolay at turpitko.com>
 Noah Campbell <noahcampbell at gmail.com>
 Nodir Turakulov <nodir at google.com>
@@ -653,7 +756,10 @@ Oling Cat <olingcat at gmail.com>
 Oliver Hookins <ohookins at gmail.com>
 Olivier Antoine <olivier.antoine at gmail.com>
 Olivier Duperray <duperray.olivier at gmail.com>
+Olivier Poitrey <rs at dailymotion.com>
 Olivier Saingre <osaingre at gmail.com>
+Omar Jarjur <ojarjur at google.com>
+Özgür Kesim <oec-go at kesim.org>
 Padraig Kitterick <padraigkitterick at gmail.com>
 Paolo Giarrusso <p.giarrusso at gmail.com>
 Paolo Martini <mrtnpaolo at gmail.com>
@@ -678,6 +784,8 @@ Paul Rosania <paul.rosania 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>
+Paul Wankadia <junyer at google.com>
+Paulo Casaretto <pcasaretto at gmail.com>
 Pavel Paulau <pavel.paulau at gmail.com>
 Pavel Zinovkin <pavel.zinovkin at gmail.com>
 Pawel Knap <pawelknap88 at gmail.com>
@@ -688,6 +796,7 @@ Petar Maymounkov <petarm at gmail.com>
 Peter Armitage <peter.armitage at gmail.com>
 Peter Collingbourne <pcc at google.com>
 Peter Froehlich <peter.hans.froehlich at gmail.com>
+Peter Gonda <pgonda at google.com>
 Peter Kleiweg <pkleiweg at xs4all.nl>
 Peter McKenzie <petermck at google.com>
 Peter Moody <pmoody at uber.com>
@@ -701,13 +810,19 @@ Peter Waller <peter.waller at gmail.com>
 Peter Weinberger <pjw at golang.org>
 Peter Williams <pwil3058 at gmail.com>
 Phil Pennock <pdp at golang.org>
+Philip Børgesen <philip.borgesen at gmail.com>
+Philip Hofer <phofer at umich.edu>
 Philip K. Warren <pkwarren at gmail.com>
+Pierre Durand <pierredurand at gmail.com>
 Pierre Roullon <pierre.roullon at gmail.com>
 Pieter Droogendijk <pieter at binky.org.uk>
 Pietro Gagliardi <pietro10 at mac.com>
+Prashant Varanasi <prashant at prashantv.com>
 Preetam Jinka <pj at preet.am>
+Quan Tran <qeed.quan at gmail.com>
 Quan Yong Zhai <qyzhai at gmail.com>
 Quentin Perez <qperez at ocs.online.net>
+Quentin Smith <quentin at golang.org>
 Quoc-Viet Nguyen <afelion at gmail.com>
 Rahul Chaudhry <rahulchaudhry at chromium.org>
 Raif S. Naffah <go at naffah-raif.name>
@@ -717,12 +832,16 @@ Raph Levien <raph at google.com>
 Raul Silvera <rsilvera at google.com>
 Reinaldo de Souza Jr <juniorz at gmail.com>
 Rémy Oudompheng <oudomphe at phare.normalesup.org> <remyoudompheng at gmail.com>
+Rhys Hiltner <rhys at justin.tv>
+Ricardo Padilha <ricardospadilha at gmail.com>
 Richard Barnes <rlb at ipv.sx>
 Richard Crowley <r at rcrowley.org>
 Richard Eric Gavaletz <gavaletz at gmail.com>
+Richard Miller <miller.research at gmail.com>
 Richard Musiol <mail at richard-musiol.de> <neelance at gmail.com>
 Rick Arnold <rickarnoldjr at gmail.com>
 Rick Hudson <rlh at golang.org>
+Riku Voipio <riku.voipio at linaro.org>
 Risto Jaakko Saarelma <rsaarelm at gmail.com>
 Rob Earhart <earhart at google.com>
 Rob Norman <rob.norman at infinitycloud.com>
@@ -742,6 +861,7 @@ Rodrigo Moraes de Oliveira <rodrigo.moraes at gmail.com>
 Rodrigo Rafael Monti Kochenburger <divoxx at gmail.com>
 Roger Pau Monné <royger at gmail.com>
 Roger Peppe <rogpeppe at gmail.com>
+Roland Shoemaker <rolandshoemaker at gmail.com>
 Ron Hashimoto <mail at h2so5.net>
 Ron Minnich <rminnich at gmail.com>
 Ross Light <light at google.com> <rlight2 at gmail.com>
@@ -756,18 +876,27 @@ Ryan Lower <rpjlower at gmail.com>
 Ryan Seys <ryan at ryanseys.com>
 Ryan Slade <ryanslade at gmail.com>
 S.Çağlar Onur <caglar at 10ur.org>
+Sai Cheemalapati <saicheems at google.com>
 Salmān Aljammāz <s at 0x65.net>
+Sam Ding <samding at ca.ibm.com>
+Sam Hug <samuel.b.hug at gmail.com>
 Sam Thorogood <thorogood at google.com> <sam.thorogood at gmail.com>
+Sam Whited <sam at samwhited.com>
 Sameer Ajmani <sameer at golang.org> <ajmani at gmail.com>
+Sami Commerot <samic at google.com>
 Sanjay Menakuru <balasanjay at gmail.com>
 Sasha Lionheart <lionhearts at google.com>
+Sasha Sobol <sasha at scaledinference.com>
 Scott Barron <scott.barron at github.com>
+Scott Bell <scott at sctsm.com>
 Scott Ferguson <scottwferg at gmail.com>
 Scott Lawrence <bytbox at gmail.com>
+Scott Mansfield <smansfield at netflix.com>
 Scott Schwartz <scotts at golang.org>
 Scott Van Woudenberg <scottvw at google.com>
 Sean Burford <sburford at google.com>
 Sean Dolphin <Sean.Dolphin at kpcompass.com>
+Sean Harger <sharger at google.com>
 Sebastien Binet <seb.binet at gmail.com>
 Sébastien Paolacci <sebastien.paolacci at gmail.com>
 Sergei Skorobogatov <skorobo at rambler.ru>
@@ -775,20 +904,26 @@ Sergey 'SnakE' Gromov <snake.scaly at gmail.com>
 Sergey Arseev <sergey.arseev at intel.com>
 Sergio Luis O. B. Correia <sergio at correia.cc>
 Seth Hoenig <seth.a.hoenig at gmail.com>
+Seth Vargo <sethvargo at gmail.com>
+Shahar Kohanim <skohanim at gmail.com>
 Shane Hansen <shanemhansen at gmail.com>
 Shaozhen Ding <dsz0111 at gmail.com>
 Shawn Ledbetter <sledbetter at google.com>
 Shawn Smith <shawn.p.smith at gmail.com>
 Shawn Walker-Salas <shawn.walker at oracle.com>
 Shenghou Ma <minux at golang.org> <minux.ma at gmail.com>
+Shinji Tanaka <shinji.tanaka at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
 Shun Fan <sfan at google.com>
 Silvan Jegen <s.jegen at gmail.com>
+Simon Jefford <simon.jefford at gmail.com>
+Simon Thulbourn <simon+github at thulbourn.com>
 Simon Whitehead <chemnova at gmail.com>
 Sokolov Yura <funny.falcon at gmail.com>
 Spencer Nelson <s at spenczar.com>
 Spring Mc <heresy.mc at gmail.com>
 Srdjan Petrovic <spetrovic at google.com>
+Sridhar Venkatakrishnan <sridhar at laddoo.net>
 StalkR <stalkr at stalkr.net>
 Stan Schwertly <stan at schwertly.com>
 Stefan Nilsson <snilsson at nada.kth.se> <trolleriprofessorn at gmail.com>
@@ -803,12 +938,14 @@ 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>
+Suharsh Sivakumar <suharshs at google.com>
 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>
 Takashi Matsuo <tmatsuo at google.com>
 Takeshi YAMANASHI <9.nashi at gmail.com>
+Tal Shprecher <tshprecher at gmail.com>
 Tamir Duberstein <tamird at gmail.com>
 Tarmigan Casebolt <tarmigan at gmail.com>
 Taru Karttunen <taruti at taruti.net>
@@ -820,13 +957,20 @@ Thomas Desrosiers <thomasdesr at gmail.com>
 Thomas Habets <habets at google.com>
 Thomas Kappler <tkappler at gmail.com>
 Thorben Krueger <thorben.krueger at gmail.com>
+Tilman Dilo <tilman.dilo at gmail.com>
 Tim Cooijmans <timcooijmans at gmail.com>
+Tim Ebringer <tim.ebringer at gmail.com>
 Tim Hockin <thockin at google.com>
+Tim Swast <swast at google.com>
 Timo Savola <timo.savola at gmail.com>
 Timo Truyts <alkaloid.btx at gmail.com>
+Timothy Studd <tim at timstudd.com>
+Tipp Moseley <tipp at google.com>
 Tobias Columbus <tobias.columbus at gmail.com> <tobias.columbus at googlemail.com>
+Toby Burress <kurin at google.com>
 Todd Neal <todd at tneal.org>
 Todd Wang <toddwang at gmail.com>
+Tom Bergan <tombergan at google.com>
 Tom Heng <zhm20070928 at gmail.com>
 Tom Linford <tomlinford at gmail.com>
 Tom Szymanski <tgs at google.com>
@@ -837,14 +981,17 @@ Totoro W <tw19881113 at gmail.com>
 Travis Cline <travis.cline at gmail.com>
 Trevor Strohman <trevor.strohman at gmail.com>
 Trey Tacon <ttacon at gmail.com>
+Tristan Amini <tamini01 at ca.ibm.com>
 Tudor Golubenco <tudor.g at gmail.com>
 Tyler Bunnell <tylerbunnell at gmail.com>
 Tyler Treat <ttreat31 at gmail.com>
+Tzu-Jung Lee <roylee17 at currant.com>
 Ugorji Nwoke <ugorji at gmail.com>
 Ulf Holm Nielsen <doktor at dyregod.dk>
 Ulrich Kunitz <uli.kunitz at gmail.com>
 Uriel Mangado <uriel at berlinblue.org>
 Uttam C Pawar <uttam.c.pawar at intel.com>
+Vadim Grek <vadimprog at gmail.com>
 Vadim Vygonets <unixdj at gmail.com>
 Vega Garcia Luis Alfonso <vegacom at gmail.com>
 Vincent Ambo <tazjin at googlemail.com>
@@ -852,9 +999,11 @@ 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>
+Vishvananda Ishaya <vishvananda at gmail.com>
 Vlad Krasnov <vlad at cloudflare.com>
 Vladimir Nikishenko <vova616 at gmail.com>
 Volker Dobler <dr.volker.dobler at gmail.com>
+Wedson Almeida Filho <wedsonaf at google.com>
 Wei Guangjing <vcc.163 at gmail.com>
 Will Chan <willchan at google.com>
 Will Norris <willnorris at google.com>
@@ -862,8 +1011,10 @@ Willem van der Schyff <willemvds at gmail.com>
 William Chan <willchan at chromium.org>
 William Josephson <wjosephson at gmail.com>
 William Orr <will at worrbase.com> <ay1244 at gmail.com>
+Wisdom Omuya <deafgoat at gmail.com>
 Xia Bin <snyh at snyh.org>
 Xing Xing <mikespook at gmail.com>
+Xudong Zhang <felixmelon at gmail.com>
 Yan Zou <yzou at google.com>
 Yann Kerhervé <yann.kerherve at gmail.com>
 Yao Zhang <lunaria21 at gmail.com>
@@ -874,11 +1025,14 @@ 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>
+Yu Heng Zhang <annita.zhang at cn.ibm.com>
+Yu Xuan Zhang <zyxsh at cn.ibm.com>
 Yuki Yugui Sonoda <yugui at google.com>
 Yusuke Kagiwada <block.rxckin.beats at gmail.com>
 Yuusei Kuwana <kuwana at kumama.org>
 Yuval Pavel Zholkover <paulzhol at gmail.com>
 Yves Junqueira <yvesj at google.com> <yves.junqueira at gmail.com>
+Zhongwei Yao <zhongwei.yao at arm.com>
 Ziad Hatahet <hatahet at gmail.com>
 Zorion Arrizabalaga <zorionk at gmail.com>
 申习之 <bronze1man at gmail.com>
diff --git a/LICENSE b/LICENSE
index 7448756..6a66aea 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2012 The Go Authors. All rights reserved.
+Copyright (c) 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
diff --git a/VERSION b/VERSION
index 17df20d..e0b63c7 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.6.2
\ No newline at end of file
+go1.7rc1
\ No newline at end of file
diff --git a/api/except.txt b/api/except.txt
index 59ef942..4040d14 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -329,3 +329,4 @@ 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"
+pkg unicode, const Version = "8.0.0"
diff --git a/api/go1.7.txt b/api/go1.7.txt
new file mode 100644
index 0000000..52cc042
--- /dev/null
+++ b/api/go1.7.txt
@@ -0,0 +1,285 @@
+pkg bytes, func ContainsAny([]uint8, string) bool
+pkg bytes, func ContainsRune([]uint8, int32) bool
+pkg bytes, method (*Reader) Reset([]uint8)
+pkg compress/flate, const HuffmanOnly = -2
+pkg compress/flate, const HuffmanOnly ideal-int
+pkg context, func Background() Context
+pkg context, func TODO() Context
+pkg context, func WithCancel(Context) (Context, CancelFunc)
+pkg context, func WithDeadline(Context, time.Time) (Context, CancelFunc)
+pkg context, func WithTimeout(Context, time.Duration) (Context, CancelFunc)
+pkg context, func WithValue(Context, interface{}, interface{}) Context
+pkg context, type CancelFunc func()
+pkg context, type Context interface { Deadline, Done, Err, Value }
+pkg context, type Context interface, Deadline() (time.Time, bool)
+pkg context, type Context interface, Done() <-chan struct
+pkg context, type Context interface, Err() error
+pkg context, type Context interface, Value(interface{}) interface{}
+pkg context, var Canceled error
+pkg context, var DeadlineExceeded error
+pkg crypto/tls, const RenegotiateFreelyAsClient = 2
+pkg crypto/tls, const RenegotiateFreelyAsClient RenegotiationSupport
+pkg crypto/tls, const RenegotiateNever = 0
+pkg crypto/tls, const RenegotiateNever RenegotiationSupport
+pkg crypto/tls, const RenegotiateOnceAsClient = 1
+pkg crypto/tls, const RenegotiateOnceAsClient RenegotiationSupport
+pkg crypto/tls, type Config struct, DynamicRecordSizingDisabled bool
+pkg crypto/tls, type Config struct, Renegotiation RenegotiationSupport
+pkg crypto/tls, type RenegotiationSupport int
+pkg crypto/x509, func SystemCertPool() (*CertPool, error)
+pkg crypto/x509, type SystemRootsError struct, Err error
+pkg debug/dwarf, method (*Data) Ranges(*Entry) ([][2]uint64, error)
+pkg debug/dwarf, method (*Reader) SeekPC(uint64) (*Entry, error)
+pkg debug/elf, const R_390_12 = 2
+pkg debug/elf, const R_390_12 R_390
+pkg debug/elf, const R_390_16 = 3
+pkg debug/elf, const R_390_16 R_390
+pkg debug/elf, const R_390_20 = 57
+pkg debug/elf, const R_390_20 R_390
+pkg debug/elf, const R_390_32 = 4
+pkg debug/elf, const R_390_32 R_390
+pkg debug/elf, const R_390_64 = 22
+pkg debug/elf, const R_390_64 R_390
+pkg debug/elf, const R_390_8 = 1
+pkg debug/elf, const R_390_8 R_390
+pkg debug/elf, const R_390_COPY = 9
+pkg debug/elf, const R_390_COPY R_390
+pkg debug/elf, const R_390_GLOB_DAT = 10
+pkg debug/elf, const R_390_GLOB_DAT R_390
+pkg debug/elf, const R_390_GOT12 = 6
+pkg debug/elf, const R_390_GOT12 R_390
+pkg debug/elf, const R_390_GOT16 = 15
+pkg debug/elf, const R_390_GOT16 R_390
+pkg debug/elf, const R_390_GOT20 = 58
+pkg debug/elf, const R_390_GOT20 R_390
+pkg debug/elf, const R_390_GOT32 = 7
+pkg debug/elf, const R_390_GOT32 R_390
+pkg debug/elf, const R_390_GOT64 = 24
+pkg debug/elf, const R_390_GOT64 R_390
+pkg debug/elf, const R_390_GOTENT = 26
+pkg debug/elf, const R_390_GOTENT R_390
+pkg debug/elf, const R_390_GOTOFF = 13
+pkg debug/elf, const R_390_GOTOFF R_390
+pkg debug/elf, const R_390_GOTOFF16 = 27
+pkg debug/elf, const R_390_GOTOFF16 R_390
+pkg debug/elf, const R_390_GOTOFF64 = 28
+pkg debug/elf, const R_390_GOTOFF64 R_390
+pkg debug/elf, const R_390_GOTPC = 14
+pkg debug/elf, const R_390_GOTPC R_390
+pkg debug/elf, const R_390_GOTPCDBL = 21
+pkg debug/elf, const R_390_GOTPCDBL R_390
+pkg debug/elf, const R_390_GOTPLT12 = 29
+pkg debug/elf, const R_390_GOTPLT12 R_390
+pkg debug/elf, const R_390_GOTPLT16 = 30
+pkg debug/elf, const R_390_GOTPLT16 R_390
+pkg debug/elf, const R_390_GOTPLT20 = 59
+pkg debug/elf, const R_390_GOTPLT20 R_390
+pkg debug/elf, const R_390_GOTPLT32 = 31
+pkg debug/elf, const R_390_GOTPLT32 R_390
+pkg debug/elf, const R_390_GOTPLT64 = 32
+pkg debug/elf, const R_390_GOTPLT64 R_390
+pkg debug/elf, const R_390_GOTPLTENT = 33
+pkg debug/elf, const R_390_GOTPLTENT R_390
+pkg debug/elf, const R_390_GOTPLTOFF16 = 34
+pkg debug/elf, const R_390_GOTPLTOFF16 R_390
+pkg debug/elf, const R_390_GOTPLTOFF32 = 35
+pkg debug/elf, const R_390_GOTPLTOFF32 R_390
+pkg debug/elf, const R_390_GOTPLTOFF64 = 36
+pkg debug/elf, const R_390_GOTPLTOFF64 R_390
+pkg debug/elf, const R_390_JMP_SLOT = 11
+pkg debug/elf, const R_390_JMP_SLOT R_390
+pkg debug/elf, const R_390_NONE = 0
+pkg debug/elf, const R_390_NONE R_390
+pkg debug/elf, const R_390_PC16 = 16
+pkg debug/elf, const R_390_PC16 R_390
+pkg debug/elf, const R_390_PC16DBL = 17
+pkg debug/elf, const R_390_PC16DBL R_390
+pkg debug/elf, const R_390_PC32 = 5
+pkg debug/elf, const R_390_PC32 R_390
+pkg debug/elf, const R_390_PC32DBL = 19
+pkg debug/elf, const R_390_PC32DBL R_390
+pkg debug/elf, const R_390_PC64 = 23
+pkg debug/elf, const R_390_PC64 R_390
+pkg debug/elf, const R_390_PLT16DBL = 18
+pkg debug/elf, const R_390_PLT16DBL R_390
+pkg debug/elf, const R_390_PLT32 = 8
+pkg debug/elf, const R_390_PLT32 R_390
+pkg debug/elf, const R_390_PLT32DBL = 20
+pkg debug/elf, const R_390_PLT32DBL R_390
+pkg debug/elf, const R_390_PLT64 = 25
+pkg debug/elf, const R_390_PLT64 R_390
+pkg debug/elf, const R_390_RELATIVE = 12
+pkg debug/elf, const R_390_RELATIVE R_390
+pkg debug/elf, const R_390_TLS_DTPMOD = 54
+pkg debug/elf, const R_390_TLS_DTPMOD R_390
+pkg debug/elf, const R_390_TLS_DTPOFF = 55
+pkg debug/elf, const R_390_TLS_DTPOFF R_390
+pkg debug/elf, const R_390_TLS_GD32 = 40
+pkg debug/elf, const R_390_TLS_GD32 R_390
+pkg debug/elf, const R_390_TLS_GD64 = 41
+pkg debug/elf, const R_390_TLS_GD64 R_390
+pkg debug/elf, const R_390_TLS_GDCALL = 38
+pkg debug/elf, const R_390_TLS_GDCALL R_390
+pkg debug/elf, const R_390_TLS_GOTIE12 = 42
+pkg debug/elf, const R_390_TLS_GOTIE12 R_390
+pkg debug/elf, const R_390_TLS_GOTIE20 = 60
+pkg debug/elf, const R_390_TLS_GOTIE20 R_390
+pkg debug/elf, const R_390_TLS_GOTIE32 = 43
+pkg debug/elf, const R_390_TLS_GOTIE32 R_390
+pkg debug/elf, const R_390_TLS_GOTIE64 = 44
+pkg debug/elf, const R_390_TLS_GOTIE64 R_390
+pkg debug/elf, const R_390_TLS_IE32 = 47
+pkg debug/elf, const R_390_TLS_IE32 R_390
+pkg debug/elf, const R_390_TLS_IE64 = 48
+pkg debug/elf, const R_390_TLS_IE64 R_390
+pkg debug/elf, const R_390_TLS_IEENT = 49
+pkg debug/elf, const R_390_TLS_IEENT R_390
+pkg debug/elf, const R_390_TLS_LDCALL = 39
+pkg debug/elf, const R_390_TLS_LDCALL R_390
+pkg debug/elf, const R_390_TLS_LDM32 = 45
+pkg debug/elf, const R_390_TLS_LDM32 R_390
+pkg debug/elf, const R_390_TLS_LDM64 = 46
+pkg debug/elf, const R_390_TLS_LDM64 R_390
+pkg debug/elf, const R_390_TLS_LDO32 = 52
+pkg debug/elf, const R_390_TLS_LDO32 R_390
+pkg debug/elf, const R_390_TLS_LDO64 = 53
+pkg debug/elf, const R_390_TLS_LDO64 R_390
+pkg debug/elf, const R_390_TLS_LE32 = 50
+pkg debug/elf, const R_390_TLS_LE32 R_390
+pkg debug/elf, const R_390_TLS_LE64 = 51
+pkg debug/elf, const R_390_TLS_LE64 R_390
+pkg debug/elf, const R_390_TLS_LOAD = 37
+pkg debug/elf, const R_390_TLS_LOAD R_390
+pkg debug/elf, const R_390_TLS_TPOFF = 56
+pkg debug/elf, const R_390_TLS_TPOFF R_390
+pkg debug/elf, method (R_390) GoString() string
+pkg debug/elf, method (R_390) String() string
+pkg debug/elf, type R_390 int
+pkg encoding/json, method (*Encoder) SetEscapeHTML(bool)
+pkg encoding/json, method (*Encoder) SetIndent(string, string)
+pkg go/build, type Package struct, BinaryOnly bool
+pkg go/build, type Package struct, CgoFFLAGS []string
+pkg go/build, type Package struct, FFiles []string
+pkg go/doc, type Example struct, Unordered bool
+pkg io, const SeekCurrent = 1
+pkg io, const SeekCurrent ideal-int
+pkg io, const SeekEnd = 2
+pkg io, const SeekEnd ideal-int
+pkg io, const SeekStart = 0
+pkg io, const SeekStart ideal-int
+pkg math/big, method (*Float) GobDecode([]uint8) error
+pkg math/big, method (*Float) GobEncode() ([]uint8, error)
+pkg net, method (*Dialer) DialContext(context.Context, string, string) (Conn, error)
+pkg net/http, const StatusAlreadyReported = 208
+pkg net/http, const StatusAlreadyReported ideal-int
+pkg net/http, const StatusFailedDependency = 424
+pkg net/http, const StatusFailedDependency ideal-int
+pkg net/http, const StatusIMUsed = 226
+pkg net/http, const StatusIMUsed ideal-int
+pkg net/http, const StatusInsufficientStorage = 507
+pkg net/http, const StatusInsufficientStorage ideal-int
+pkg net/http, const StatusLocked = 423
+pkg net/http, const StatusLocked ideal-int
+pkg net/http, const StatusLoopDetected = 508
+pkg net/http, const StatusLoopDetected ideal-int
+pkg net/http, const StatusMultiStatus = 207
+pkg net/http, const StatusMultiStatus ideal-int
+pkg net/http, const StatusNotExtended = 510
+pkg net/http, const StatusNotExtended ideal-int
+pkg net/http, const StatusPermanentRedirect = 308
+pkg net/http, const StatusPermanentRedirect ideal-int
+pkg net/http, const StatusProcessing = 102
+pkg net/http, const StatusProcessing ideal-int
+pkg net/http, const StatusUnprocessableEntity = 422
+pkg net/http, const StatusUnprocessableEntity ideal-int
+pkg net/http, const StatusUpgradeRequired = 426
+pkg net/http, const StatusUpgradeRequired ideal-int
+pkg net/http, const StatusVariantAlsoNegotiates = 506
+pkg net/http, const StatusVariantAlsoNegotiates ideal-int
+pkg net/http, method (*Request) Context() context.Context
+pkg net/http, method (*Request) WithContext(context.Context) *Request
+pkg net/http, type Request struct, Response *Response
+pkg net/http, type Response struct, Uncompressed bool
+pkg net/http, type Transport struct, DialContext func(context.Context, string, string) (net.Conn, error)
+pkg net/http, type Transport struct, IdleConnTimeout time.Duration
+pkg net/http, type Transport struct, MaxIdleConns int
+pkg net/http, type Transport struct, MaxResponseHeaderBytes int64
+pkg net/http, var ErrUseLastResponse error
+pkg net/http, var LocalAddrContextKey *contextKey
+pkg net/http, var ServerContextKey *contextKey
+pkg net/http/cgi, type Handler struct, Stderr io.Writer
+pkg net/http/httptest, func NewRequest(string, string, io.Reader) *http.Request
+pkg net/http/httptest, method (*ResponseRecorder) Result() *http.Response
+pkg net/http/httptrace, func ContextClientTrace(context.Context) *ClientTrace
+pkg net/http/httptrace, func WithClientTrace(context.Context, *ClientTrace) context.Context
+pkg net/http/httptrace, type ClientTrace struct
+pkg net/http/httptrace, type ClientTrace struct, ConnectDone func(string, string, error)
+pkg net/http/httptrace, type ClientTrace struct, ConnectStart func(string, string)
+pkg net/http/httptrace, type ClientTrace struct, DNSDone func(DNSDoneInfo)
+pkg net/http/httptrace, type ClientTrace struct, DNSStart func(DNSStartInfo)
+pkg net/http/httptrace, type ClientTrace struct, GetConn func(string)
+pkg net/http/httptrace, type ClientTrace struct, Got100Continue func()
+pkg net/http/httptrace, type ClientTrace struct, GotConn func(GotConnInfo)
+pkg net/http/httptrace, type ClientTrace struct, GotFirstResponseByte func()
+pkg net/http/httptrace, type ClientTrace struct, PutIdleConn func(error)
+pkg net/http/httptrace, type ClientTrace struct, Wait100Continue func()
+pkg net/http/httptrace, type ClientTrace struct, WroteHeaders func()
+pkg net/http/httptrace, type ClientTrace struct, WroteRequest func(WroteRequestInfo)
+pkg net/http/httptrace, type DNSDoneInfo struct
+pkg net/http/httptrace, type DNSDoneInfo struct, Addrs []net.IPAddr
+pkg net/http/httptrace, type DNSDoneInfo struct, Coalesced bool
+pkg net/http/httptrace, type DNSDoneInfo struct, Err error
+pkg net/http/httptrace, type DNSStartInfo struct
+pkg net/http/httptrace, type DNSStartInfo struct, Host string
+pkg net/http/httptrace, type GotConnInfo struct
+pkg net/http/httptrace, type GotConnInfo struct, Conn net.Conn
+pkg net/http/httptrace, type GotConnInfo struct, IdleTime time.Duration
+pkg net/http/httptrace, type GotConnInfo struct, Reused bool
+pkg net/http/httptrace, type GotConnInfo struct, WasIdle bool
+pkg net/http/httptrace, type WroteRequestInfo struct
+pkg net/http/httptrace, type WroteRequestInfo struct, Err error
+pkg net/url, type URL struct, ForceQuery bool
+pkg os/exec, func CommandContext(context.Context, string, ...string) *Cmd
+pkg os/user, func LookupGroup(string) (*Group, error)
+pkg os/user, func LookupGroupId(string) (*Group, error)
+pkg os/user, method (*User) GroupIds() ([]string, error)
+pkg os/user, method (UnknownGroupError) Error() string
+pkg os/user, method (UnknownGroupIdError) Error() string
+pkg os/user, type Group struct
+pkg os/user, type Group struct, Gid string
+pkg os/user, type Group struct, Name string
+pkg os/user, type UnknownGroupError string
+pkg os/user, type UnknownGroupIdError string
+pkg reflect, func StructOf([]StructField) Type
+pkg reflect, method (StructTag) Lookup(string) (string, bool)
+pkg runtime, func CallersFrames([]uintptr) *Frames
+pkg runtime, func KeepAlive(interface{})
+pkg runtime, func SetCgoTraceback(int, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer)
+pkg runtime, method (*Frames) Next() (Frame, bool)
+pkg runtime, type Frame struct
+pkg runtime, type Frame struct, Entry uintptr
+pkg runtime, type Frame struct, File string
+pkg runtime, type Frame struct, Func *Func
+pkg runtime, type Frame struct, Function string
+pkg runtime, type Frame struct, Line int
+pkg runtime, type Frame struct, PC uintptr
+pkg runtime, type Frames struct
+pkg strings, method (*Reader) Reset(string)
+pkg syscall (linux-386), type SysProcAttr struct, Unshareflags uintptr
+pkg syscall (linux-386-cgo), type SysProcAttr struct, Unshareflags uintptr
+pkg syscall (linux-amd64), type SysProcAttr struct, Unshareflags uintptr
+pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Unshareflags uintptr
+pkg syscall (linux-arm), type SysProcAttr struct, Unshareflags uintptr
+pkg syscall (linux-arm-cgo), type SysProcAttr struct, Unshareflags uintptr
+pkg testing, method (*B) Run(string, func(*B)) bool
+pkg testing, method (*T) Run(string, func(*T)) bool
+pkg testing, type InternalExample struct, Unordered bool
+pkg unicode, const Version = "9.0.0"
+pkg unicode, var Adlam *RangeTable
+pkg unicode, var Bhaiksuki *RangeTable
+pkg unicode, var Marchen *RangeTable
+pkg unicode, var Newa *RangeTable
+pkg unicode, var Osage *RangeTable
+pkg unicode, var Prepended_Concatenation_Mark *RangeTable
+pkg unicode, var Sentence_Terminal *RangeTable
+pkg unicode, var Tangut *RangeTable
diff --git a/doc/cmd.html b/doc/cmd.html
index 5d20d38..992f176 100644
--- a/doc/cmd.html
+++ b/doc/cmd.html
@@ -89,7 +89,7 @@ gofmt</a> command with more general options.</td>
 </tr>
 
 <tr>
-<td><a href="//godoc.org/golang.org/x/tools/cmd/vet/">vet</a></td>
+<td><a href="/cmd/vet/">vet</a></td>
 <td>    </td>
 <td>Vet examines Go source code and reports suspicious constructs, such as Printf
 calls whose arguments do not align with the format string.</td>
diff --git a/doc/codewalk/codewalk.js b/doc/codewalk/codewalk.js
index 7bfcd39..abc5937 100644
--- a/doc/codewalk/codewalk.js
+++ b/doc/codewalk/codewalk.js
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/doc/codewalk/markov.go b/doc/codewalk/markov.go
index a8f322e..5f62e05 100644
--- a/doc/codewalk/markov.go
+++ b/doc/codewalk/markov.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/codewalk/markov.xml b/doc/codewalk/markov.xml
index 76c448a..7e44840 100644
--- a/doc/codewalk/markov.xml
+++ b/doc/codewalk/markov.xml
@@ -1,5 +1,5 @@
 <!--
-Copyright 2011 The Go Authors.  All rights reserved.
+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/contribute.html b/doc/contribute.html
index 59b3d20..bcf7b25 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -16,6 +16,10 @@ have <a href="code.html">written and tested your code</a>.
 see <a href="gccgo_contribute.html">Contributing to gccgo</a>.)
 </p>
 
+<p>
+Sensitive security-related issues should be reported to <a href="mailto:security at golang.org">security at golang.org</a>.
+</p>
+
 <h2 id="Design">Discuss your design</h2>
 
 <p>
@@ -349,10 +353,13 @@ with a thorough description of your change.
 The first line of the 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 and should provide context for the
+It should complete the sentence "This change modifies Go to _____."
+The rest of the description elaborates and should provide context for the
 change and explain what it does.
+Write in complete sentences with correct punctuation, just like
+for your comments in Go.
 If there is a helpful reference, mention it here.
+If you've fixed an issue, reference it by number with a # before it.
 </p>
 
 <p>
@@ -360,7 +367,7 @@ After editing, the template might now read:
 </p>
 
 <pre>
-math: improved Sin, Cos and Tan precision for very large arguments
+math: improve Sin, Cos and Tan precision for very large arguments
 
 The existing implementation has poor numerical properties for
 large arguments, so use the McGillicutty algorithm to improve
diff --git a/doc/devel/release.html b/doc/devel/release.html
index a1a615f..97c4133 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -81,8 +81,7 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.5.2">Go
 <p>
 go1.5.3 (released 2016/01/13) includes a security fix to the <code>math/big</code> package
 affecting the <code>crypto/tls</code> package.
-See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.5.3">Go 1.5.3 milestone on our issue tracker</a>
-and the <a href="https://golang.org/s/go153announce">release announcement</a> for details.
+See the <a href="https://golang.org/s/go153announce">release announcement</a> for details.
 </p>
 
 <p>
@@ -127,17 +126,17 @@ Read the <a href="/doc/go1.3">Go 1.3 Release Notes</a> for more information.
 
 <p>
 go1.3.1 (released 2014/08/13) includes bug fixes to the compiler and the <code>runtime</code>, <code>net</code>, and <code>crypto/rsa</code> packages.
-See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=073fc578434bf3e1e22749b559d273c8da728ebb">change history</a> for details.
+See the <a href="https://github.com/golang/go/commits/go1.3.1">change history</a> for details.
 </p>
 
 <p>
 go1.3.2 (released 2014/09/25) includes bug fixes to cgo and the crypto/tls packages.
-See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=go1.3.2">change history</a> for details.
+See the <a href="https://github.com/golang/go/commits/go1.3.2">change history</a> for details.
 </p>
 
 <p>
 go1.3.3 (released 2014/09/30) includes further bug fixes to cgo, the runtime package, and the nacl port. 
-See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.3&r=go1.3.3">change history</a> for details.
+See the <a href="https://github.com/golang/go/commits/go1.3.3">change history</a> for details.
 </p>
 
 <h2 id="go1.2">go1.2 (released 2013/12/01)</h2>
@@ -151,12 +150,12 @@ Read the <a href="/doc/go1.2">Go 1.2 Release Notes</a> for more information.
 
 <p>
 go1.2.1 (released 2014/03/02) includes bug fixes to the <code>runtime</code>, <code>net</code>, and <code>database/sql</code> packages.
-See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.2&r=7ada9e760ce34e78aee5b476c9621556d0fa5d31">change history</a> for details.
+See the <a href="https://github.com/golang/go/commits/go1.2.1">change history</a> for details.
 </p>
 
 <p>
 go1.2.2 (released 2014/05/05) includes a
-<a href="//code.google.com/p/go/source/detail?r=bda3619e7a2c&repo=tools">security fix</a>
+<a href="https://github.com/golang/go/commits/go1.2.2">security fix</a>
 that affects the tour binary included in the binary distributions (thanks to Guillaume T).
 </p>
 
@@ -171,17 +170,17 @@ Read the <a href="/doc/go1.1">Go 1.1 Release Notes</a> for more information.
 
 <p>
 go1.1.1 (released 2013/06/13) includes several compiler and runtime bug fixes.
-See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.1&r=43c4a41d24382a56a90e924800c681e435d9e399">change history</a> for details.
+See the <a href="https://github.com/golang/go/commits/go1.1.1">change history</a> for details.
 </p>
 
 <p>
 go1.1.2 (released 2013/08/13) includes fixes to the <code>gc</code> compiler
 and <code>cgo</code>, and the <code>bufio</code>, <code>runtime</code>,
 <code>syscall</code>, and <code>time</code> packages.
-See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1.1&r=a6a9792f94acd4ff686b2bc57383d163608b91cf">change history</a> for details.
+See the <a href="https://github.com/golang/go/commits/go1.1.2">change history</a> for details.
 If you use package syscall's <code>Getrlimit</code> and <code>Setrlimit</code>
 functions under Linux on the ARM or 386 architectures, please note change
-<a href="//golang.org/change/55ac276af5a7">55ac276af5a7</a>
+<a href="//golang.org/cl/11803043">11803043</a>
 that fixes <a href="//golang.org/issue/5949">issue 5949</a>.
 </p>
 
@@ -208,7 +207,7 @@ The go1 release corresponds to
 
 <p>
 go1.0.1 (released 2012/04/25) was issued to
-<a href="//golang.org/change/a890477d3dfb">fix</a> an
+<a href="//golang.org/cl/6061043">fix</a> an
 <a href="//golang.org/issue/3545">escape analysis bug</a>
 that can lead to memory corruption.
 It also includes several minor code and documentation fixes.
@@ -227,7 +226,7 @@ go1.0.3 (released 2012/09/21) includes minor code and documentation fixes.
 </p>
 
 <p>
-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.
+See the <a href="https://github.com/golang/go/commits/release-branch.go1">go1 release branch history</a> for the complete list of changes.
 </p>
 
 <h2 id="pre.go1">Older releases</h2>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index 5a522f6..1e66c0c 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -239,9 +239,9 @@ starts with the name being declared.
 </p>
 
 <pre>
-// Compile parses a regular expression and returns, if successful, a Regexp
-// object that can be used to match against text.
-func Compile(str string) (regexp *Regexp, err error) {
+// Compile parses a regular expression and returns, if successful,
+// a Regexp that can be used to match against text.
+func Compile(str string) (*Regexp, error) {
 </pre>
 
 <p>
@@ -2014,7 +2014,7 @@ then make the receiver for the method a value of that type.
 type ByteSlice []byte
 
 func (slice ByteSlice) Append(data []byte) []byte {
-    // Body exactly the same as above
+    // Body exactly the same as the Append function defined above.
 }
 </pre>
 <p>
diff --git a/doc/go1.6.html b/doc/go1.6.html
index 8dea862..9594736 100644
--- a/doc/go1.6.html
+++ b/doc/go1.6.html
@@ -168,7 +168,7 @@ Go 1.7 will remove support for the old syntax.
 <p>
 The release schedules for the GCC and Go projects do not coincide.
 GCC release 5 contains the Go 1.4 version of gccgo.
-The next release, GCC 6, will have the Go 1.6 version of gccgo.
+The next release, GCC 6, will have the Go 1.6.1 version of gccgo.
 </p>
 
 <h3 id="go_command">Go command</h3>
diff --git a/doc/go1.7.html b/doc/go1.7.html
new file mode 100644
index 0000000..a460754
--- /dev/null
+++ b/doc/go1.7.html
@@ -0,0 +1,1236 @@
+<!--{
+	"Title": "Go 1.7 Release Notes DRAFT",
+	"Path":  "/doc/go1.7",
+	"Template": true
+}-->
+
+<!--
+for acme:
+Edit .,s;^PKG:([a-z][A-Za-z0-9_/]+);<a href="/pkg/\1/"><code>\1</code></a>;g
+Edit .,s;^([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .',)]|$);<a href="/pkg/\1/#\2\3"><code>\3</code></a>\4;g
+Edit .,s;^FULL:([a-z][A-Za-z0-9_/]+)\.([A-Z][A-Za-z0-9_]+\.)?([A-Z][A-Za-z0-9_]+)([ .',)]|$);<a href="/pkg/\1/#\2\3"><code>\1.\2\3</code></a>\4;g
+Edit .,s;^DPKG:([a-z][A-Za-z0-9_/]+);<dl id="\1"><a href="/pkg/\1/">\1</a></dl>;g
+
+rsc last updated through 6729576
+-->
+
+<!--
+NOTE: In this document and others in this directory, the convention is to
+set fixed-width phrases with non-fixed-width spaces, as in
+<code>hello</code> <code>world</code>.
+Do not send CLs removing the interior tags from such phrases.
+-->
+
+<style>
+ul li { margin: 0.5em 0; }
+</style>
+
+<p>
+<!-- TODO: REMOVE THIS COMMENT -->
+<!-- TODO: Also remove "DRAFT" in the "Title" at the top of this file. -->
+<i>NOTE: This is a DRAFT of the Go 1.7 release notes, prepared for the Go 1.7 beta.
+Go 1.7 has NOT yet been released.
+By our regular schedule, it is expected some time in August 2016.
+</i>
+</p>
+
+<h2 id="introduction">Introduction to Go 1.7</h2>
+
+<p>
+The latest Go release, version 1.7, arrives six months after 1.6.
+Most of its changes are in the implementation of the toolchain, runtime, and libraries.
+There is one minor change to the language specification.
+As always, the release maintains the Go 1 <a href="/doc/go1compat.html">promise of compatibility</a>.
+We expect almost all Go programs to continue to compile and run as before.
+</p>
+
+<p>
+The release <a href="#ports">adds a port to IBM LinuxOne</a>;
+<a href="#compiler">updates the x86-64 compiler back end</a> to generate more efficient code;
+includes the <a href="#context">context package</a>, promoted from the
+<a href="https://golang.org/x/net/context">x/net subrepository</a>
+and now used in the standard library;
+and <a href="#testing">adds support in the testing package</a> for
+creating hierarchies of tests and benchmarks.
+The release also <a href="#cmd/go">finalizes the vendoring support</a>
+started in Go 1.5, making it a standard feature.
+</p>
+
+<h2 id="language">Changes to the language</h2>
+
+<p>
+There is one tiny language change in this release.
+The section on <a href="/ref/spec#Terminating_statements">terminating statements</a>
+clarifies that to determine whether a statement list ends in a terminating statement,
+the “final non-empty statement” is considered the end,
+matching the existing behavior of the gc and gccgo compiler toolchains.
+In earlier releases the definition referred only to the “final statement,”
+leaving the effect of trailing empty statements at the least unclear.
+The <a href="/pkg/go/types/"><code>go/types</code></a>
+package has been updated to match the gc and gccgo compiler toolchains
+in this respect.
+This change has no effect on the correctness of existing programs.
+</p>
+
+<h2 id="ports">Ports</h2>
+
+<p>
+Go 1.7 adds an experimental port to <a href="https://en.wikipedia.org/wiki/Linux_on_z_Systems">Linux on z Systems</a> (<code>linux/s390x</code>)
+and the beginning of a port to Plan 9 on ARM (<code>plan9/arm</code>).
+</p>
+
+<p>
+The experimental ports to Linux on 64-bit MIPS (<code>linux/mips64</code> and <code>linux/mips64le</code>)
+added in Go 1.6 now have full support for cgo and external linking.
+</p>
+
+<p>
+The experimental port to Linux on big-endian 64-bit PowerPC (<code>linux/ppc64</code>)
+now requires the POWER8 architecture or later.
+</p>
+
+<p>
+The OpenBSD port now requires OpenBSD 5.6 or later, for access to the <a href="http://man.openbsd.org/getentropy.2"><i>getentropy</i>(2)</a> system call.
+</p>
+
+<h2 id="tools">Tools</h2>
+
+<h3 id="cmd_asm">Assembler</h3>
+
+<p>
+For 64-bit ARM systems, the vector register names have been
+corrected to <code>V0</code> through <code>V31</code>;
+previous releases incorrectly referred to them as <code>V32</code> through <code>V63</code>.
+</p>
+
+<p>
+For 64-bit x86 systems, the following instructions have been added:
+<code>PCMPESTRI</code>,
+<code>RORXL</code>,
+<code>RORXQ</code>,
+<code>VINSERTI128</code>,
+<code>VPADDD</code>,
+<code>VPADDQ</code>,
+<code>VPALIGNR</code>,
+<code>VPBLENDD</code>,
+<code>VPERM2F128</code>,
+<code>VPERM2I128</code>,
+<code>VPOR</code>,
+<code>VPSHUFB</code>,
+<code>VPSHUFD</code>,
+<code>VPSLLD</code>,
+<code>VPSLLDQ</code>,
+<code>VPSLLQ</code>,
+<code>VPSRLD</code>,
+<code>VPSRLDQ</code>,
+and
+<code>VPSRLQ</code>.
+</p>
+
+<h3 id="compiler">Compiler Toolchain</h3>
+
+<p>
+This release includes a new code generation back end for 64-bit x86 systems,
+following a <a href="https://golang.org/s/go17ssa">proposal from 2015</a>
+that has been under development since then.
+The new back end, based on
+<a href="https://en.wikipedia.org/wiki/Static_single_assignment_form">SSA</a>,
+generates more compact, more efficient code
+and provides a better platform for optimizations
+such as bounds check elimination.
+The new back end reduces the CPU time required by
+<a href="https://golang.org/test/bench/go1/">our benchmark programs</a> by 5-35%.
+</p>
+
+<p>
+For this release, the new back end can be disabled by passing
+<code>-ssa=0</code> to the compiler.
+If you find that your program compiles or runs successfully
+only with the new back end disabled, please
+<a href="https://golang.org/issue/new">file a bug report</a>.
+</p>
+
+<p>
+The format of exported metadata written by the compiler in package archives has changed:
+the old textual format has been replaced by a more compact binary format.
+This results in somewhat smaller package archives and fixes a few
+long-standing corner case bugs.
+</p>
+
+<p>
+For this release, the new export format can be disabled by passing
+<code>-newexport=0</code> to the compiler.
+If you find that your program compiles or runs successfully
+only with the new export format disabled, please
+<a href="https://golang.org/issue/new">file a bug report</a>.
+</p>
+
+<p>
+The linker's <code>-X</code> option no longer supports the unusual two-argument form
+<code>-X</code> <code>name</code> <code>value</code>,
+as <a href="/doc/go1.6#compiler">announced</a> in the Go 1.6 release
+and in warnings printed by the linker.
+Use <code>-X</code> <code>name=value</code> instead.
+</p>
+
+<p>
+The compiler and linker have been optimized and run significantly faster in this release than in Go 1.6,
+although they are still slower than we would like and will continue to be optimized in future releases.
+</p>
+
+<p>
+Due to changes across the compiler toolchain and standard library,
+binaries built with this release should typically be smaller than binaries
+built with Go 1.6,
+sometimes by as much as 20-30%.
+</p>
+
+<p>
+On x86-64 systems, Go programs now maintain stack frame pointers
+as expected by profiling tools like Linux's perf and Intel's VTune,
+making it easier to analyze and optimize Go programs using these tools.
+The frame pointer maintenance has a small run-time overhead that varies
+but averages around 2%. We hope to reduce this cost in future releases.
+To build a toolchain that does not use frame pointers, set
+<code>GOEXPERIMENT=noframepointer</code> when running
+<code>make.bash</code>, <code>make.bat</code>, or <code>make.rc</code>.
+</p>
+
+<h3 id="cmd_cgo">Cgo</h3>
+
+<p>
+Packages using <a href="/cmd/cgo/">cgo</a> may now include
+Fortran source files (in addition to C, C++, Objective C, and SWIG),
+although the Go bindings must still use C language APIs.
+</p>
+
+<p>
+Go bindings may now use a new helper function <code>C.CBytes</code>.
+In contrast to <code>C.CString</code>, which takes a Go <code>string</code>
+and returns a <code>*C.byte</code> (a C <code>char*</code>),
+<code>C.CBytes</code> takes a Go <code>[]byte</code>
+and returns an <code>unsafe.Pointer</code> (a C <code>void*</code>).
+</p>
+
+<p>
+Packages and binaries built using <code>cgo</code> have in past releases
+produced different output on each build,
+due to the embedding of temporary directory names.
+When using this release with
+new enough versions of GCC or Clang
+(those that support the <code>-fdebug-prefix-map</code> option),
+those builds should finally be deterministic.
+</p>
+
+<h3 id="gccgo">Gccgo</h3>
+
+<p>
+Due to the alignment of Go's semiannual release schedule with GCC's annual release schedule,
+GCC release 6 contains the Go 1.6.1 version of gccgo.
+The next release, GCC 7, will likely have the Go 1.8 version of gccgo.
+</p>
+
+<h3 id="cmd_go">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>
+This release removes support for the <code>GO15VENDOREXPERIMENT</code> environment variable,
+as <a href="/doc/go1.6#go_command">announced</a> in the Go 1.6 release.
+<a href="https://golang.org/s/go15vendor">Vendoring support</a>
+is now a standard feature of the <code>go</code> command and toolchain.
+</p>
+
+<p>
+The <code>Package</code> data structure made available to
+“<code>go</code> <code>list</code>” now includes a
+<code>StaleReason</code> field explaining why a particular package
+is or is not considered stale (in need of rebuilding).
+This field is available to the <code>-f</code> or <code>-json</code>
+options and is useful for understanding why a target is being rebuilt.
+</p>
+
+<p>
+The “<code>go</code> <code>get</code>” command now supports
+import paths referring to <code>git.openstack.org</code>.
+</p>
+
+<p>
+This release adds experimental, minimal support for building programs using
+<a href="/pkg/go/build#hdr-Binary_Only_Packages">binary-only packages</a>,
+packages distributed in binary form
+without the corresponding source code.
+This feature is needed in some commercial settings
+but is not intended to be fully integrated into the rest of the toolchain.
+For example, tools that assume access to complete source code
+will not work with such packages, and there are no plans to support
+such packages in the “<code>go</code> <code>get</code>” command.
+</p>
+
+<h3 id="cmd_doc">Go doc</h3>
+
+<p>
+The “<code>go</code> <code>doc</code>” command
+now groups constructors with the type they construct,
+following <a href="/cmd/godoc/"><code>godoc</code></a>.
+</p>
+
+<h3 id="cmd_vet">Go vet</h3>
+
+<p>
+The “<code>go</code> <code>vet</code>” command
+has more accurate analysis in its <code>-copylock</code> and <code>-printf</code> checks,
+and a new <code>-tests</code> check that checks the name and signature of likely test functions.
+To avoid confusion with the new <code>-tests</code> check, the old, unadvertised
+<code>-test</code> option has been removed; it was equivalent to <code>-all</code> <code>-shadow</code>.
+</p>
+
+<p id="vet_lostcancel">
+The <code>vet</code> command also has a new check,
+<code>-lostcancel</code>, which detects failure to call the
+cancelation function returned by the <code>WithCancel</code>,
+<code>WithTimeout</code>, and <code>WithDeadline</code> functions in
+Go 1.7's new <code>context</code> package (see <a
+href='#context'>below</a>).
+Failure to call the function prevents the new <code>Context</code>
+from being reclaimed until its parent is cancelled.
+(The background context is never cancelled.)
+</p>
+
+<h3 id="cmd_dist">Go tool dist</h3>
+
+<p>
+The new subcommand “<code>go</code> <code>tool</code> <code>dist</code> <code>list</code>”
+prints all supported operating system/architecture pairs.
+</p>
+
+<h3 id="cmd_trace">Go tool trace</h3>
+
+<p>
+The “<code>go</code> <code>tool</code> <code>trace</code>” command,
+<a href="/doc/go1.5#trace_command">introduced in Go 1.5</a>,
+has been refined in various ways.
+</p>
+
+<p>
+First, collecting traces is significantly more efficient than in past releases.
+In this release, the typical execution-time overhead of collecting a trace is about 25%;
+in past releases it was at least 400%.
+Second, trace files now include file and line number information,
+making them more self-contained and making the
+original executable optional when running the trace tool.
+Third, the trace tool now breaks up large traces to avoid limits
+in the browser-based viewer.
+</p>
+
+<p>
+Although the trace file format has changed in this release,
+the Go 1.7 tools can still read traces from earlier releases.
+</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.
+Most programs should run a bit faster,
+due to speedups in the garbage collector and
+optimizations in the core library.
+On x86-64 systems, many programs will run significantly faster,
+due to improvements in generated code brought by the
+new compiler back end.
+As noted above, in our own benchmarks,
+the code generation changes alone typically reduce program CPU time by 5-35%.
+</p>
+
+<p>
+<!-- git log &#45&#45grep '-[0-9][0-9]\.[0-9][0-9]%' go1.6.. -->
+There have been significant optimizations bringing more than 10% improvements
+to implementations in the
+<a href="/pkg/crypto/sha1/"><code>crypto/sha1</code></a>,
+<a href="/pkg/crypto/sha256/"><code>crypto/sha256</code></a>,
+<a href="/pkg/encoding/binary/"><code>encoding/binary</code></a>,
+<a href="/pkg/fmt/"><code>fmt</code></a>,
+<a href="/pkg/hash/adler32/"><code>hash/adler32</code></a>,
+<a href="/pkg/hash/crc32/"><code>hash/crc32</code></a>,
+<a href="/pkg/hash/crc64/"><code>hash/crc64</code></a>,
+<a href="/pkg/image/color/"><code>image/color</code></a>,
+<a href="/pkg/math/big/"><code>math/big</code></a>,
+<a href="/pkg/strconv/"><code>strconv</code></a>,
+<a href="/pkg/strings/"><code>strings</code></a>,
+<a href="/pkg/unicode/"><code>unicode</code></a>,
+and
+<a href="/pkg/unicode/utf16/"><code>unicode/utf16</code></a>
+packages.
+</p>
+
+<h2 id="library">Core library</h2>
+
+<h3 id="context">Context</h3>
+
+<p>
+Go 1.7 moves the <code>golang.org/x/net/context</code> package
+into the standard library as <a href="/pkg/context/"><code>context</code></a>.
+This allows the use of contexts for cancelation, timeouts, and passing
+request-scoped data in other standard library packages,
+including
+<a href="#net">net</a>,
+<a href="#net/http">net/http</a>,
+and
+<a href="#os/exec">os/exec</a>,
+as noted below.
+</p>
+
+<p>
+For more information about contexts, see the
+<a href="/pkg/context/">package documentation</a>
+and the Go blog post
+“<a href="https://blog.golang.org/context">Go Concurrent Patterns: Context</a>.”
+</p>
+
+<h3 id="httptrace">HTTP Tracing</h3>
+
+<p>
+Go 1.7 introduces <a href="/pkg/net/http/httptrace/"><code>net/http/httptrace</code></a>,
+a package that provides mechanisms for tracing events within HTTP requests.
+</p>
+
+<h3 id="testing">Testing</h3>
+
+<p>
+The <code>testing</code> package now supports the definition
+of tests with subtests and benchmarks with sub-benchmarks.
+This support makes it easy to write table-driven benchmarks
+and to create hierarchical tests.
+It also provides a way to share common setup and tear-down code.
+See the <a href="/pkg/testing/#hdr-Subtests_and_Sub_benchmarks">package documentation</a> for details.
+</p>
+
+<h3 id="runtime">Runtime</h3>
+
+<p>
+All panics started by the runtime now use panic values
+that implement both the
+builtin <a href="/ref/spec#Errors"><code>error</code></a>,
+and
+<a href="/pkg/runtime/#Error"><code>runtime.Error</code></a>,
+as
+<a href="/ref/spec#Run_time_panics">required by the language specification</a>.
+</p>
+
+<p>
+During panics, if a signal's name is known, it will be printed in the stack trace.
+Otherwise, the signal's number will be used, as it was before Go1.7.
+</p>
+
+<p>
+The new function
+<a href="/pkg/runtime/#KeepAlive"><code>KeepAlive</code></a>
+provides an explicit mechanism for declaring
+that an allocated object must be considered reachable
+at a particular point in a program,
+typically to delay the execution of an associated finalizer.
+</p>
+
+<p>
+The new function
+<a href="/pkg/runtime/#CallersFrames"><code>CallersFrames</code></a>
+translates a PC slice obtained from
+<a href="/pkg/runtime/#Callers"><code>Callers</code></a>
+into a sequence of frames corresponding to the call stack.
+This new API should be preferred instead of direct use of
+<a href="/pkg/runtime/#FuncForPC"><code>FuncForPC</code></a>,
+because the frame sequence can more accurately describe
+call stacks with inlined function calls.
+</p>
+
+<p>
+The new function
+<a href="/pkg/runtime/#SetCgoTraceback"><code>SetCgoTraceback</code></a>
+facilitates tighter integration between Go and C code executing
+in the same process called using cgo.
+</p>
+
+<p>
+On 32-bit systems, the runtime can now use memory allocated
+by the operating system anywhere in the address space,
+eliminating the
+“memory allocated by OS not in usable range” failure
+common in some environments.
+</p>
+
+<p>
+On Windows, Go programs in Go 1.5 and earlier forced
+the global Windows timer resolution to 1ms at startup
+by calling <code>timeBeginPeriod(1)</code>.
+Changing the global timer resolution caused problems on some systems,
+and testing suggested that the call was not needed for good scheduler performance,
+so Go 1.6 removed the call.
+Go 1.7 brings the call back: under some workloads the call
+is still needed for good scheduler performance.
+</p>
+
+
+<h3 id="minor_library_changes">Minor changes to the library</h3>
+
+<p>
+As always, there are various minor changes and updates to the library,
+made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
+in mind.
+</p>
+
+<dl id="bufio"><dt><a href="/pkg/bufio/">bufio</a></dt>
+
+<dd>
+<p>
+In previous releases of Go, if
+<a href="/pkg/bufio/#Reader"><code>Reader</code></a>'s
+<a href="/pkg/bufio/#Reader.Peek"><code>Peek</code></a> method
+were asked for more bytes than fit in the underlying buffer,
+it would return an empty slice and the error <code>ErrBufferFull</code>.
+Now it returns the entire underlying buffer, still accompanied by the error <code>ErrBufferFull</code>.
+</p>
+</dd>
+</dl>
+
+<dl id="bytes"><dt><a href="/pkg/bytes/">bytes</a></dt>
+
+<dd>
+<p>
+The new functions
+<a href="/pkg/bytes/#ContainsAny"><code>ContainsAny</code></a> and
+<a href="/pkg/bytes/#ContainsRune"><code>ContainsRune</code></a>
+have been added for symmetry with
+the <a href="/pkg/strings/"><code>strings</code></a> package.
+</p>
+
+<p>
+In previous releases of Go, if
+<a href="/pkg/bytes/#Reader"><code>Reader</code></a>'s
+<a href="/pkg/bytes/#Reader.Read"><code>Read</code></a> method
+were asked for zero bytes with no data remaining, it would
+return a count of 0 and no error.
+Now it returns a count of 0 and the error
+<a href="/pkg/io/#EOF"><code>io.EOF</code></a>.
+</p>
+
+<p>
+The
+<a href="/pkg/bytes/#Reader"><code>Reader</code></a> type has a new method
+<a href="/pkg/bytes/#Reader.Reset"><code>Reset</code></a> to allow reuse of a <code>Reader</code>.
+</p>
+</dd>
+</dl>
+
+<dl id="compress_flate"><dt><a href="/pkg/compress/flate/">compress/flate</a></dt>
+
+<dd>
+<p>
+As noted above,
+there are significant performance optimizations throughout the package.
+Decompression speed is improved by about 10%,
+while compression speed for <code>DefaultCompression</code> is roughly doubled.
+</p>
+
+<p>
+In addition to those general improvements,
+the
+<code>BestSpeed</code>
+compressor has been replaced entirely and uses an
+algorithm similar to <a href="https://github.com/google/snappy">Snappy</a>,
+resulting in about a 2.5X speed increase,
+although the output can be 5-10% larger than with the previous algorithm.
+</p>
+
+<p>
+There is also a new compression level
+<code>HuffmanOnly</code>
+that applies Huffman but not Lempel-Ziv encoding.
+<a href="https://blog.klauspost.com/constant-time-gzipzip-compression/">Forgoing Lempel-Ziv encoding</a> means that
+<code>HuffmanOnly</code> runs about 3X faster than the new <code>BestSpeed</code>
+but at the cost of producing compressed outputs that are 20-40% larger than those
+generated by the new <code>BestSpeed</code>.
+</p>
+
+<p>
+It is important to note that both
+<code>BestSpeed</code> and <code>HuffmanOnly</code> produce a compressed output that is
+<a href="https://tools.ietf.org/html/rfc1951">RFC 1951</a> compliant.
+In other words, any valid DEFLATE decompressor will continue to be able to decompress these outputs.
+</p>
+
+<p>
+Lastly, there is a minor change to the decompressor's implementation of
+<a href="/pkg/io/#Reader"><code>io.Reader</code></a>. In previous versions,
+the decompressor deferred reporting
+<a href="/pkg/io/#EOF"><code>io.EOF</code></a> until exactly no more bytes could be read.
+Now, it reports
+<a href="/pkg/io/#EOF"><code>io.EOF</code></a> more eagerly when reading the last set of bytes.
+</p>
+</dd>
+</dl>
+
+<dl id="crypto_tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
+
+<dd>
+<p>
+The TLS implementation sends the first few data packets on each connection
+using small record sizes, gradually increasing to the TLS maximum record size.
+This heuristic reduces the amount of data that must be received before
+the first packet can be decrypted, improving communication latency over
+low-bandwidth networks.
+Setting
+<a href="/pkg/crypto/tls/#Config"><code>Config</code></a>'s
+<code>DynamicRecordSizingDisabled</code> field to true
+forces the behavior of Go 1.6 and earlier, where packets are
+as large as possible from the start of the connection.
+</p>
+
+<p>
+The TLS client now has optional, limited support for server-initiated renegotiation,
+enabled by setting the
+<a href="/pkg/crypto/tls/#Config"><code>Config</code></a>'s
+<code>Renegotiation</code> field.
+This is needed for connecting to many Microsoft Azure servers.
+</p>
+
+<p>
+The errors returned by the package now consistently begin with a
+<code>tls:</code> prefix.
+In past releases, some errors used a <code>crypto/tls:</code> prefix,
+some used a <code>tls:</code> prefix, and some had no prefix at all.
+</p>
+
+<p>
+When generating self-signed certificates, the package no longer sets the
+“Authority Key Identifier” field by default.
+</p>
+</dd>
+</dl>
+
+<dl id="crypto_x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
+
+<dd>
+<p>
+The new function
+<a href="/pkg/crypto/x509/#SystemCertPool"><code>SystemCertPool</code></a>
+provides access to the entire system certificate pool if available.
+There is also a new associated error type
+<a href="/pkg/crypto/x509/#SystemRootsError"><code>SystemRootsError</code></a>.
+</p>
+</dd>
+</dl>
+
+<dl id="debug_dwarf"><dt><a href="/pkg/debug/dwarf/">debug/dwarf</a></dt>
+
+<dd>
+<p>
+The
+<a href="/pkg/debug/dwarf/#Reader"><code>Reader</code></a> type's new
+<a href="/pkg/debug/dwarf/#Reader.SeekPC"><code>SeekPC</code></a> method and the
+<a href="/pkg/debug/dwarf/#Data"><code>Data</code></a> type's new
+<a href="/pkg/debug/dwarf/#Ranges"><code>Ranges</code></a> method
+help to find the compilation unit to pass to a
+<a href="/pkg/debug/dwarf/#LineReader"><code>LineReader</code></a>
+and to identify the specific function for a given program counter.
+</p>
+</dd>
+</dl>
+
+<dl id="debug_elf"><dt><a href="/pkg/debug/elf/">debug/elf</a></dt>
+
+<dd>
+<p>
+The new
+<a href="/pkg/debug/elf/#R_390"><code>R_390</code></a> relocation type
+and its many predefined constants
+support the S390 port.
+</p>
+</dd>
+</dl>
+
+<dl id="encoding_asn1"><dt><a href="/pkg/encoding/asn1/">encoding/asn1</a></dt>
+
+<dd>
+<p>
+The ASN.1 decoder now rejects non-minimal integer encodings.
+This may cause the package to reject some invalid but formerly accepted ASN.1 data.
+</p>
+</dd>
+</dl>
+
+<dl id="encoding_json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
+
+<dd>
+<p>
+The
+<a href="/pkg/encoding/json/#Encoder"><code>Encoder</code></a>'s new
+<a href="/pkg/encoding/json/#Encoder.SetIndent"><code>SetIndent</code></a> method
+sets the indentation parameters for JSON encoding,
+like in the top-level
+<a href="/pkg/encoding/json/#Indent"><code>Indent</code></a> function.
+</p>
+
+<p>
+The
+<a href="/pkg/encoding/json/#Encoder"><code>Encoder</code></a>'s new
+<a href="/pkg/encoding/json/#Encoder.SetEscapeHTML"><code>SetEscapeHTML</code></a> method
+controls whether the
+<code>&#x26;</code>, <code>&#x3c;</code>, and <code>&#x3e;</code>
+characters in quoted strings should be escaped as
+<code>\u0026</code>, <code>\u003c</code>, and <code>\u003e</code>,
+respectively.
+As in previous releases, the encoder defaults to applying this escaping,
+to avoid certain problems that can arise when embedding JSON in HTML.
+</p>
+
+<p>
+In earlier versions of Go, this package only supported encoding and decoding
+maps using keys with string types.
+Go 1.7 adds support for maps using keys with integer types:
+the encoding uses a quoted decimal representation as the JSON key.
+Go 1.7 also adds support for encoding maps using non-string keys that implement
+the <code>MarshalText</code>
+(see
+<a href="/pkg/encoding/#TextMarshaler"><code>encoding.TextMarshaler</code></a>)
+method,
+as well as support for decoding maps using non-string keys that implement
+the <code>UnmarshalText</code>
+(see
+<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>)
+method.
+These methods are ignored for keys with string types in order to preserve
+the encoding and decoding used in earlier versions of Go.
+</p>
+
+<p>
+When encoding a slice of typed bytes,
+<a href="/pkg/encoding/json/#Marshal"><code>Marshal</code></a>
+now generates an array of elements encoded using
+that byte type's
+<code>MarshalJSON</code>
+or
+<code>MarshalText</code>
+method if present,
+only falling back to the default base64-encoded string data if neither method is available.
+Earlier versions of Go accept both the original base64-encoded string encoding
+and the array encoding (assuming the byte type also implements
+<code>UnmarshalJSON</code>
+or
+<code>UnmarshalText</code>
+as appropriate),
+so this change should be semantically backwards compatible with earlier versions of Go,
+even though it does change the chosen encoding.
+</p>
+</dd>
+</dl>
+
+<dl id="go_build"><dt><a href="/pkg/go/build/">go/build</a></dt>
+
+<dd>
+<p>
+To implement the go command's new support for binary-only packages
+and for Fortran code in cgo-based packages,
+the
+<a href="/pkg/go/build/#Package"><code>Package</code></a> type
+adds new fields <code>BinaryOnly</code>, <code>CgoFFLAGS</code>, and <code>FFiles</code>.
+</p>
+</dd>
+</dl>
+
+<dl id="go_doc"><dt><a href="/pkg/go/doc/">go/doc</a></dt>
+
+<dd>
+<p>
+To support the corresponding change in <code>go</code> <code>test</code> described above,
+<a href="/pkg/go/doc/#Example"><code>Example</code></a> struct adds a Unordered field
+indicating whether the example may generate its output lines in any order.
+</p>
+</dd>
+</dl>
+
+<dl id="io"><dt><a href="/pkg/io/">io</a></dt>
+
+<dd>
+<p>
+The package adds new constants
+<code>SeekStart</code>, <code>SeekCurrent</code>, and <code>SeekEnd</code>,
+for use with
+<a href="/pkg/io/#Seeker"><code>Seeker</code></a>
+implementations.
+These constants are preferred over <code>os.SEEK_SET</code>, <code>os.SEEK_CUR</code>, and <code>os.SEEK_END</code>,
+but the latter will be preserved for compatibility.
+</p>
+</dd>
+</dl>
+
+<dl id="math_big"><dt><a href="/pkg/math/big/">math/big</a></dt>
+
+<dd>
+<p>
+The
+<a href="/pkg/math/big/#Float"><code>Float</code></a> type adds
+<a href="/pkg/math/big/#Float.GobEncode"><code>GobEncode</code></a> and
+<a href="/pkg/math/big/#Float.GobDecode"><code>GobDecode</code></a> methods,
+so that values of type <code>Float</code> can now be encoded and decoded using the
+<a href="/pkg/encoding/gob/"><code>encoding/gob</code></a>
+package.
+</p>
+</dd>
+</dl>
+
+<dl id="math_rand"><dt><a href="/pkg/math/rand/">math/rand</a></dt>
+
+<dd>
+<p>
+The
+<a href="/pkg/math/rand/#Read"><code>Read</code></a> function and
+<a href="/pkg/math/rand/#Rand"><code>Rand</code></a>'s
+<a href="/pkg/math/rand/#Rand.Read"><code>Read</code></a> method
+now produce a pseudo-random stream of bytes that is consistent and not
+dependent on the size of the input buffer.
+</p>
+</dd>
+</dl>
+
+<dl id="mime_multipart"><dt><a href="/pkg/mime/multipart/">mime/multipart</a></dt>
+
+<dd>
+<p>
+The
+<a href="/pkg/mime/multipart/#Writer"><code>Writer</code></a>
+implementation now emits each multipart section's header sorted by key.
+Previously, iteration over a map caused the section header to use a
+non-deterministic order.
+</p>
+</dd>
+</dl>
+
+<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
+
+<dd>
+<p>
+As part of the introduction of <a href="#context">context</a>, the
+<a href="/pkg/net/#Dialer"><code>Dialer</code></a> type has a new method
+<a href="/pkg/net/#Dialer.DialContext"><code>DialContext</code></a>, like
+<a href="/pkg/net/#Dialer.Dial"><code>Dial</code></a> but adding the
+<a href="/pkg/context/#Context"><code>context.Context</code></a>
+for the dial operation.
+The context is intended to obsolete the <code>Dialer</code>'s
+<code>Cancel</code> and <code>Deadline</code> fields,
+but the implementation continues to respect them,
+for backwards compatibility.
+</p>
+
+<p>
+The
+<a href="/pkg/net/#IP"><code>IP</code></a> type's
+<a href="/pkg/net/#IP.String"><code>String</code></a> method has changed its result for invalid <code>IP</code> addresses.
+In past releases, if an <code>IP</code> byte slice had length other than 0, 4, or 16, <code>String</code>
+returned <code>"?"</code>.
+Go 1.7 adds the hexadecimal encoding of the bytes, as in <code>"?12ab"</code>.
+</p>
+
+<p>
+The pure Go <a href="/pkg/net/#hdr-Name_Resolution">name resolution</a>
+implementation now respects <code>nsswitch.conf</code>'s
+stated preference for the priority of DNS lookups compared to
+local file (that is, <code>/etc/hosts</code>) lookups.
+</p>
+</dd>
+</dl>
+
+<dl id="net_http"><dt><a href="/pkg/net/http/">net/http</a></dt>
+
+<dd>
+<p>
+<a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a>'s
+documentation now makes clear that beginning to write the response
+may prevent future reads on the request body.
+For maximal compatibility, implementations are encouraged to
+read the request body completely before writing any part of the response.
+</p>
+
+<p>
+As part of the introduction of <a href="#context">context</a>, the
+<a href="/pkg/net/http/#Request"><code>Request</code></a> has a new methods
+<a href="/pkg/net/http/#Request.Context"><code>Context</code></a>, to retrieve the associated context, and
+<a href="/pkg/net/http/#Request.WithContext"><code>WithContext</code></a>, to construct a copy of <code>Request</code>
+with a modified context.
+</p>
+
+<p>
+In the
+<a href="/pkg/net/http/#Server"><code>Server</code></a> implementation,
+<a href="/pkg/net/http/#Server.Serve"><code>Serve</code></a> records in the request context
+both the underlying <code>*Server</code> using the key <code>ServerContextKey</code>
+and the local address on which the request was received (a
+<a href="/pkg/net/#Addr"><code>Addr</code></a>) using the key <code>LocalAddrContextKey</code>.
+For example, the address on which a request received is
+<code>req.Context().Value(http.LocalAddrContextKey).(net.Addr)</code>.
+</p>
+
+<p>
+The server implementation now
+pads response codes less than 100 to three digits
+as required by the protocol,
+so that <code>w.WriteHeader(5)</code> uses the HTTP response
+status <code>005</code>, not just <code>5</code>.
+</p>
+
+<p>
+The server implementation now correctly sends only one "Transfer-Encoding" header when "chunked"
+is set explicitly, following <a href="https://tools.ietf.org/html/rfc7230#section-3.3.1">RFC 7230</a>.
+</p>
+
+<p>
+In the server, a 200 status code is sent back by the timeout handler on an empty
+response body, instead of sending back 0 as the status code.
+</p>
+
+<p>
+In the client, the
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a> implementation passes the request context
+to any dial operation connecting to the remote server.
+If a custom dialer is needed, the new <code>Transport</code> field
+<code>DialContext</code> is preferred over the existing <code>Dial</code> field,
+to allow the transport to supply a context.
+</p>
+
+<p>
+The
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a> also adds fields
+<code>IdleConnTimeout</code>,
+<code>MaxIdleConns</code>,
+and
+<code>MaxResponseHeaderBytes</code>
+to help control client resources consumed
+by idle or chatty servers.
+</p>
+
+<p>
+A
+<a href="/pkg/net/http/#Client"><code>Client</code></a>'s configured <code>CheckRedirect</code> function can now
+return <code>ErrUseLastResponse</code> to indicate that the
+most recent redirect response should be returned as the
+result of the HTTP request.
+That response is now available to the <code>CheckRedirect</code> function
+as <code>req.Response</code>.
+</p>
+
+<p>
+Since Go 1, the default behavior of the HTTP client is
+to request server-side compression
+using the <code>Accept-Encoding</code> request header
+and then to decompress the response body transparently,
+and this behavior is adjustable using the
+<a href="/pkg/net/http/#Transport"><code>Transport</code></a>'s <code>DisableCompression</code> field.
+In Go 1.7, to aid the implementation of HTTP proxies, the
+<a href="/pkg/net/http/#Response"><code>Response</code></a>'s new
+<code>Uncompressed</code> field reports whether
+this transparent decompression took place.
+</p>
+
+<p>
+<a href="/pkg/net/http/#DetectContentType"><code>DetectContentType</code></a>
+adds support for a few new audio and video content types.
+</p>
+</dd>
+</dl>
+
+<dl id="net_http_cgi"><dt><a href="/pkg/net/http/cgi/">net/http/cgi</a></dt>
+
+<dd>
+<p>
+The
+<a href="/pkg/net/http/cgi/#Handler"><code>Handler</code></a>
+adds a new field
+<code>Stderr</code>
+that allows redirection of the child process's
+standard error away from the host process's
+standard error.
+</p>
+</dd>
+</dl>
+
+<dl id="net_http_httptest"><dt><a href="/pkg/net/http/httptest/">net/http/httptest</a></dt>
+
+<dd>
+<p>
+The new function
+<a href="/pkg/net/http/httptest/#NewRequest"><code>NewRequest</code></a>
+prepares a new
+<a href="/pkg/net/http/#Request"><code>http.Request</code></a>
+suitable for passing to an
+<a href="/pkg/net/http/#Handler"><code>http.Handler</code></a> during a test.
+</p>
+
+<p>
+The
+<a href="/pkg/net/http/httptest/#ResponseRecorder"><code>ResponseRecorder</code></a>'s new
+<a href="/pkg/net/http/httptest/#ResponseRecorder.Result"><code>Result</code></a> method
+returns the recorded
+<a href="/pkg/net/http/#Response"><code>http.Response</code></a>.
+Tests that need to check the response's headers or trailers
+should call <code>Result</code> and inspect the response fields
+instead of accessing
+<code>ResponseRecorder</code>'s <code>HeaderMap</code> directly.
+</p>
+</dd>
+</dl>
+
+<dl id="net_http_httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
+
+<dd>
+<p>
+The
+<a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a> implementation now responds with “502 Bad Gateway”
+when it cannot reach a back end; in earlier releases it responded with “500 Internal Server Error.”
+</p>
+
+<p>
+Both
+<a href="/pkg/net/http/httputil/#ClientConn"><code>ClientConn</code></a> and
+<a href="/pkg/net/http/httputil/#ServerConn"><code>ServerConn</code></a> have been documented as deprecated.
+They are low-level, old, and unused by Go's current HTTP stack
+and will no longer be updated.
+Programs should use
+<a href="/pkg/net/http/#Client"><code>http.Client</code></a>,
+<a href="/pkg/net/http/#Transport"><code>http.Transport</code></a>,
+and
+<a href="/pkg/net/http/#Server"><code>http.Server</code></a>
+instead.
+</p>
+</dd>
+</dl>
+
+<dl id="net_http_pprof"><dt><a href="/pkg/net/http/pprof/">net/http/pprof</a></dt>
+
+<dd>
+<p>
+The runtime trace HTTP handler, installed to handle the path <code>/debug/pprof/trace</code>,
+now accepts a fractional number in its <code>seconds</code> query parameter,
+allowing collection of traces for intervals smaller than one second.
+This is especially useful on busy servers.
+</p>
+</dd>
+</dl>
+
+<dl><dt><a href="/pkg/net/mail/">net/mail</a></dt>
+
+<dd>
+<p>
+The address parser now allows unescaped UTF-8 text in addresses
+following <a href="https://tools.ietf.org/html/rfc6532">RFC 6532</a>,
+but it does not apply any normalization to the result.
+For compatibility with older mail parsers,
+the address encoder, namely
+<a href="/pkg/net/mail/#Address"><code>Address</code></a>'s
+<a href="/pkg/net/mail/#Address.String"><code>String</code></a> method,
+continues to escape all UTF-8 text following <a href="https://tools.ietf.org/html/rfc5322">RFC 5322</a>.
+</p>
+
+<p>
+The <a href="/pkg/net/mail/#ParseAddress"><code>ParseAddress</code></a>
+function and
+the <a href="/pkg/net/mail/#AddressParser.Parse"><code>AddressParser.Parse</code></a>
+method are stricter.
+They used to ignore any characters following an e-mail address, but
+will now return an error for anything other than whitespace.
+</p>
+</dd>
+</dl>
+
+<dl id="net_url"><dt><a href="/pkg/net/url/">net/url</a></dt>
+
+<dd>
+<p>
+The
+<a href="/pkg/net/url/#URL"><code>URL</code></a>'s
+new <code>ForceQuery</code> field
+records whether the URL must have a query string,
+in order to distinguish URLs without query strings (like <code>/search</code>)
+from URLs with empty query strings (like <code>/search?</code>).
+</p>
+</dd>
+</dl>
+
+<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
+
+<dd>
+<p>
+<a href="/pkg/os/#IsExists"><code>IsExists</code></a> now returns true for <code>syscall.ENOTEMPTY</code>,
+on systems where that error exists.
+</p>
+
+<p>
+On Windows,
+<a href="/pkg/os/#Remove"><code>Remove</code></a> now removes read-only files when possible,
+making the implementation behave as on
+non-Windows systems.
+</p>
+</dd>
+</dl>
+
+<dl id="os_exec"><dt><a href="/pkg/os/exec/">os/exec</a></dt>
+
+<dd>
+<p>
+As part of the introduction of <a href="#context">context</a>,
+the new constructor
+<a href="/pkg/os/exec/#CommandContext"><code>CommandContext</code></a>
+is like
+<a href="/pkg/os/exec/#Command"><code>Command</code></a> but includes a context that can be used to cancel the command execution.
+</p>
+</dd>
+</dl>
+
+<dl id="os_user"><dt><a href="/pkg/os/user/">os/user</a></dt>
+
+<dd>
+<p>
+The
+<a href="/pkg/os/user/#Current"><code>Current</code></a>
+function is now implemented even when cgo is not available.
+</p>
+
+<p>
+The new
+<a href="/pkg/os/user/#Group"><code>Group</code></a> type,
+along with the lookup functions
+<a href="/pkg/os/user/#LookupGroup"><code>LookupGroup</code></a> and
+<a href="/pkg/os/user/#LookupGroupId"><code>LookupGroupId</code></a>
+and the new field <code>GroupIds</code> in the <code>User</code> struct,
+provides access to system-specific user group information.
+</p>
+</dd>
+</dl>
+
+<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
+
+<dd>
+<p>
+Although
+<a href="/pkg/reflect/#Value"><code>Value</code></a>'s
+<a href="/pkg/reflect/#Value.Field"><code>Field</code></a> method has always been documented to panic
+if the given field number <code>i</code> is out of range, it has instead
+silently returned a zero
+<a href="/pkg/reflect/#Value"><code>Value</code></a>.
+Go 1.7 changes the method to behave as documented.
+</p>
+
+<p>
+The new
+<a href="/pkg/reflect/#StructOf"><code>StructOf</code></a>
+function constructs a struct type at run time.
+It completes the set of type constructors, joining
+<a href="/pkg/reflect/#ArrayOf"><code>ArrayOf</code></a>,
+<a href="/pkg/reflect/#ChanOf"><code>ChanOf</code></a>,
+<a href="/pkg/reflect/#FuncOf"><code>FuncOf</code></a>,
+<a href="/pkg/reflect/#MapOf"><code>MapOf</code></a>,
+<a href="/pkg/reflect/#PtrTo"><code>PtrTo</code></a>,
+and
+<a href="/pkg/reflect/#SliceOf"><code>SliceOf</code></a>.
+</p>
+
+<p>
+<a href="/pkg/reflect/#StructTag"><code>StructTag</code></a>'s
+new method
+<a href="/pkg/reflect/#StructTag.Lookup"><code>Lookup</code></a>
+is like
+<a href="/pkg/reflect/#StructTag.Get"><code>Get</code></a>
+but distinguishes the tag not containing the given key
+from the tag associating an empty string with the given key.
+</p>
+
+<p>
+The
+<a href="/pkg/reflect/#Type.Method"><code>Method</code></a> and
+<a href="/pkg/reflect/#Type.NumMethod"><code>NumMethod</code></a>
+methods of
+<a href="/pkg/reflect/#Type"><code>Type</code></a> and
+<a href="/pkg/reflect/#Value"><code>Value</code></a>
+no longer return or count unexported methods.
+</p>
+</dd>
+</dl>
+
+<dl id="strings"><dt><a href="/pkg/strings/">strings</a></dt>
+
+<dd>
+<p>
+In previous releases of Go, if
+<a href="/pkg/strings/#Reader"><code>Reader</code></a>'s
+<a href="/pkg/strings/#Reader.Read"><code>Read</code></a> method
+were asked for zero bytes with no data remaining, it would
+return a count of 0 and no error.
+Now it returns a count of 0 and the error
+<a href="/pkg/io/#EOF"><code>io.EOF</code></a>.
+</p>
+
+<p>
+The
+<a href="/pkg/strings/#Reader"><code>Reader</code></a> type has a new method
+<a href="/pkg/strings/#Reader.Reset"><code>Reset</code></a> to allow reuse of a <code>Reader</code>.
+</p>
+</dd>
+</dl>
+
+<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
+
+<dd>
+<p>
+<a href="/pkg/time/#Duration"><code>Duration</code></a>'s
+time.Duration.String method now reports the zero duration as <code>"0s"</code>, not <code>"0"</code>.
+<a href="/pkg/time/#ParseDuration"><code>ParseDuration</code></a> continues to accept both forms.
+</p>
+
+<p>
+The method call <code>time.Local.String()</code> now returns <code>"Local"</code> on all systems;
+in earlier releases, it returned an empty string on Windows.
+</p>
+
+<p>
+The time zone database in
+<code>$GOROOT/lib/time</code> has been updated
+to IANA release 2016d.
+This fallback database is only used when the system time zone database
+cannot be found, for example on Windows.
+The Windows time zone abbreviation list has also been updated.
+</p>
+</dd>
+</dl>
+
+<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
+
+<dd>
+<p>
+On Linux, the
+<a href="/pkg/syscall/#SysProcAttr"><code>SysProcAttr</code></a> struct
+(as used in
+<a href="/pkg/os/exec/#Cmd"><code>os/exec.Cmd</code></a>'s <code>SysProcAttr</code> field)
+has a new <code>Unshareflags</code> field.
+If the field is nonzero, the child process created by
+<a href="/pkg/syscall/#ForkExec"><code>ForkExec</code></a>
+(as used in <code>exec.Cmd</code>'s <code>Run</code> method)
+will call the
+<a href="http://man7.org/linux/man-pages/man2/unshare.2.html"><i>unshare</i>(2)</a>
+system call before executing the new program.
+</p>
+</dd>
+</dl>
+
+
+<dl id="unicode"><dt><a href="/pkg/unicode/">unicode</a></dt>
+
+<dd>
+<p>
+The <a href="/pkg/unicode/"><code>unicode</code></a> package and associated
+support throughout the system has been upgraded from version 8.0 to
+<a href="http://www.unicode.org/versions/Unicode9.0.0/">Unicode 9.0</a>.
+</p>
+</dd>
+</dl>
diff --git a/doc/go_faq.html b/doc/go_faq.html
index c4c506b..5954d17 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -335,8 +335,10 @@ code that does what generics would enable, if less smoothly.
 </p>
 
 <p>
-This remains an open issue. See <a href="https://golang.org/issue/15292">the generics proposal issue</a>
-for more information.
+The topic remains open.
+For a look at several previous unsuccessful attempts to
+design a good generics solution for Go, see
+<a href="https://golang.org/issue/15292">this proposal</a>.
 </p>
 
 <h3 id="exceptions">
@@ -1807,15 +1809,16 @@ Why does Go perform badly on benchmark X?</h3>
 <p>
 One of Go's design goals is to approach the performance of C for comparable
 programs, yet on some benchmarks it does quite poorly, including several
-in <a href="/test/bench/shootout/">test/bench/shootout</a>. The slowest depend on libraries
-for which versions of comparable performance are not available in Go.
-For instance, <a href="/test/bench/shootout/pidigits.go">pidigits.go</a>
+in <a href="https://go.googlesource.com/exp/+/master/shootout/">golang.org/x/exp/shootout</a>.
+The slowest depend on libraries for which versions of comparable performance
+are not available in Go.
+For instance, <a href="https://go.googlesource.com/exp/+/master/shootout/pidigits.go">pidigits.go</a>
 depends on a multi-precision math package, and the C
 versions, unlike Go's, use <a href="http://gmplib.org/">GMP</a> (which is
 written in optimized assembler).
 Benchmarks that depend on regular expressions
-(<a href="/test/bench/shootout/regex-dna.go">regex-dna.go</a>, for instance) are
-essentially comparing Go's native <a href="/pkg/regexp">regexp package</a> to
+(<a href="https://go.googlesource.com/exp/+/master/shootout/regex-dna.go">regex-dna.go</a>,
+for instance) are essentially comparing Go's native <a href="/pkg/regexp">regexp package</a> to
 mature, highly optimized regular expression libraries like PCRE.
 </p>
 
@@ -1823,9 +1826,9 @@ mature, highly optimized regular expression libraries like PCRE.
 Benchmark games are won by extensive tuning and the Go versions of most
 of the benchmarks need attention.  If you measure comparable C
 and Go programs
-(<a href="/test/bench/shootout/reverse-complement.go">reverse-complement.go</a> is one example), you'll see the two
-languages are much closer in raw performance than this suite would
-indicate.
+(<a href="https://go.googlesource.com/exp/+/master/shootout/reverse-complement.go">reverse-complement.go</a>
+is one example), you'll see the two languages are much closer in raw performance
+than this suite would indicate.
 </p>
 
 <p>
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 6b6e75c..731186e 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-	"Subtitle": "Version of January 5, 2016",
+	"Subtitle": "Version of May 31, 2016",
 	"Path": "/ref/spec"
 }-->
 
@@ -1043,8 +1043,8 @@ promoted methods are included in the method set of the struct as follows:
 <p>
 A field declaration may be followed by an optional string literal <i>tag</i>,
 which becomes an attribute for all the fields in the corresponding
-field declaration. The tags are made
-visible through a <a href="/pkg/reflect/#StructTag">reflection interface</a>
+field declaration. An empty tag string is equivalent to an absent tag.
+The tags are made visible through a <a href="/pkg/reflect/#StructTag">reflection interface</a>
 and take part in <a href="#Type_identity">type identity</a> for structs
 but are otherwise ignored.
 </p>
@@ -2443,9 +2443,8 @@ PrimaryExpr =
 
 Selector       = "." identifier .
 Index          = "[" Expression "]" .
-Slice          = "[" ( [ Expression ] ":" [ Expression ] ) |
-                     ( [ Expression ] ":" Expression ":" Expression )
-                 "]" .
+Slice          = "[" [ Expression ] ":" [ Expression ] "]" |
+                 "[" [ Expression ] ":" Expression ":" Expression "]" .
 TypeAssertion  = "." "(" Type ")" .
 Arguments      = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
 </pre>
@@ -3327,8 +3326,8 @@ var s uint = 33
 var i = 1<<s           // 1 has type int
 var j int32 = 1<<s     // 1 has type int32; j == 0
 var k = uint64(1<<s)   // 1 has type uint64; k == 1<<33
-var m int = 1.0<<s     // 1.0 has type int
-var n = 1.0<<s != i    // 1.0 has type int; n == false if ints are 32bits in size
+var m int = 1.0<<s     // 1.0 has type int; m == 0 if ints are 32bits in size
+var n = 1.0<<s == j    // 1.0 has type int32; n == true
 var o = 1<<s == 2<<s   // 1 and 2 have type int; o == true if ints are 32bits in size
 var p = 1<<s == 1<<33  // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
 var u = 1.0<<s         // illegal: 1.0 has type float64, cannot shift
@@ -4258,7 +4257,7 @@ All other statements are not terminating.
 
 <p>
 A <a href="#Blocks">statement list</a> ends in a terminating statement if the list
-is not empty and its final statement is terminating.
+is not empty and its final non-empty statement is terminating.
 </p>
 
 
@@ -4673,6 +4672,8 @@ Cases then match actual types <code>T</code> against the dynamic type of the
 expression <code>x</code>. As with type assertions, <code>x</code> must be of
 <a href="#Interface_types">interface type</a>, and each non-interface type
 <code>T</code> listed in a case must implement the type of <code>x</code>.
+The types listed in the cases of a type switch must all be
+<a href="#Type_identity">different</a>.
 </p>
 
 <pre class="ebnf">
@@ -4697,6 +4698,7 @@ in the TypeSwitchGuard.
 The type in a case may be <a href="#Predeclared_identifiers"><code>nil</code></a>;
 that case is used when the expression in the TypeSwitchGuard
 is a <code>nil</code> interface value.
+There may be at most one <code>nil</code> case.
 </p>
 
 <p>
diff --git a/doc/install-source.html b/doc/install-source.html
index da71f47..991be3f 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -33,7 +33,7 @@ compiler using the GCC back end, see
 </p>
 
 <p>
-The Go compilers support five instruction sets.
+The Go compilers support seven instruction sets.
 There are important differences in the quality of the compilers for the different
 architectures.
 </p>
@@ -43,15 +43,17 @@ architectures.
 	<code>amd64</code> (also known as <code>x86-64</code>)
 </dt>
 <dd>
-	A mature implementation. The compiler has an effective
-	optimizer (registerizer) and generates good code (although
-	<code>gccgo</code> can do noticeably better sometimes).
+	A mature implementation. New in 1.7 is its SSA-based back end
+	that generates compact, efficient code.
 </dd>
 <dt>
 	<code>386</code> (<code>x86</code> or <code>x86-32</code>)
 </dt>
 <dd>
-	Comparable to the <code>amd64</code> port.
+	Comparable to the <code>amd64</code> port, but does
+	not yet use the SSA-based back end. It has an effective
+	optimizer (registerizer) and generates good code (although
+	<code>gccgo</code> can do noticeably better sometimes).
 </dd>
 <dt>
 	<code>arm</code> (<code>ARM</code>)
@@ -63,19 +65,25 @@ architectures.
 	<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.
+	Supports Linux and Darwin binaries. New in 1.5 and not as well exercised 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.
+	Supports Linux binaries. New in 1.5 and not as well exercised as other ports.
 </dd>
 <dt>
 	<code>mips64, mips64le</code> (64-bit MIPS big- and little-endian)
 </dt>
 <dd>
-	Supports Linux binaries. New in 1.6 and not as well excercised as other ports.
+	Supports Linux binaries. New in 1.6 and not as well exercised as other ports.
+</dd>
+<dt>
+	<code>s390x</code> (IBM System z)
+</dt>
+<dd>
+	Supports Linux binaries. New in 1.7 and not as well exercised as other ports.
 </dd>
 </dl>
 
@@ -452,6 +460,9 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <th width="50"></th><th align="left" width="100"><code>$GOOS</code></th> <th align="left" width="100"><code>$GOARCH</code></th>
 </tr>
 <tr>
+<td></td><td><code>android</code></td> <td><code>arm</code></td>
+</tr>
+<tr>
 <td></td><td><code>darwin</code></td> <td><code>386</code></td>
 </tr>
 <tr>
diff --git a/doc/install.html b/doc/install.html
index 96a7672..0e6b86f 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -221,7 +221,7 @@ and building a simple program, as follows.
 <p>
 Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
 <code class="testUnix">$HOME/work</code>
-<code class="testWindows" style="display: none">%HOME%\work</code>
+<code class="testWindows" style="display: none">C:\work</code>
 for example, and set the <code>GOPATH</code> environment
 variable to point to that location.
 </p>
@@ -231,7 +231,7 @@ $ <b>export GOPATH=$HOME/work</b>
 </pre>
 
 <pre class="testWindows" style="display: none">
-C:\> <b>set GOPATH=%HOME%\work</b>
+C:\> <b>set GOPATH=C:\work</b>
 </pre>
 
 <p>
diff --git a/doc/security.html b/doc/security.html
index 1879ccf..5911586 100644
--- a/doc/security.html
+++ b/doc/security.html
@@ -71,7 +71,7 @@ This person coordinates the fix and release process.</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
+<li>Fixes are prepared for the two most recent major releases 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>
diff --git a/lib/time/update.bash b/lib/time/update.bash
index 86b1f21..e4987bb 100755
--- a/lib/time/update.bash
+++ b/lib/time/update.bash
@@ -1,5 +1,5 @@
-#!/bin/sh
-# Copyright 2012 The Go Authors.  All rights reserved.
+#!/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.
 
@@ -8,8 +8,8 @@
 # Consult http://www.iana.org/time-zones for the latest versions.
 
 # Versions to use.
-CODE=2016a
-DATA=2016a
+CODE=2016f
+DATA=2016f
 
 set -e
 rm -rf work
diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip
index 0207d6b..bbb8e86 100644
Binary files a/lib/time/zoneinfo.zip and b/lib/time/zoneinfo.zip differ
diff --git a/misc/android/go_android_exec.go b/misc/android/go_android_exec.go
index a67e990..ebff845 100644
--- a/misc/android/go_android_exec.go
+++ b/misc/android/go_android_exec.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -91,11 +91,11 @@ func main() {
 
 	run("shell", "rm", "-rf", deviceGotmp) // Clean up.
 
-	output = output[strings.LastIndex(output, "\n")+1:]
-	if !strings.HasPrefix(output, exitstr) {
+	exitIdx := strings.LastIndex(output, exitstr)
+	if exitIdx == -1 {
 		log.Fatalf("no exit code: %q", output)
 	}
-	code, err := strconv.Atoi(output[len(exitstr):])
+	code, err := strconv.Atoi(output[exitIdx+len(exitstr):])
 	if err != nil {
 		log.Fatalf("bad exit code: %v", err)
 	}
diff --git a/misc/arm/a b/misc/arm/a
index 701f494..644e775 100755
--- a/misc/arm/a
+++ b/misc/arm/a
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-# Copyright 2010 The Go Authors.  All rights reserved.
+# 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.
 
diff --git a/misc/cgo/errors/err1.go b/misc/cgo/errors/err1.go
index 8e674dc..61bbcd2 100644
--- a/misc/cgo/errors/err1.go
+++ b/misc/cgo/errors/err1.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/errors/err2.go b/misc/cgo/errors/err2.go
index 0c64ffe..3ab410b 100644
--- a/misc/cgo/errors/err2.go
+++ b/misc/cgo/errors/err2.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/errors/err3.go b/misc/cgo/errors/err3.go
index 3680a4a..609e1a0 100644
--- a/misc/cgo/errors/err3.go
+++ b/misc/cgo/errors/err3.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/errors/issue11097a.go b/misc/cgo/errors/issue11097a.go
index 4508213..028d10c 100644
--- a/misc/cgo/errors/issue11097a.go
+++ b/misc/cgo/errors/issue11097a.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/errors/issue11097b.go b/misc/cgo/errors/issue11097b.go
index 68c5c7c..b00f24f 100644
--- a/misc/cgo/errors/issue11097b.go
+++ b/misc/cgo/errors/issue11097b.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/errors/issue13129.go b/misc/cgo/errors/issue13129.go
index 942d2f7..f7ad7a7 100644
--- a/misc/cgo/errors/issue13129.go
+++ b/misc/cgo/errors/issue13129.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/errors/issue13423.go b/misc/cgo/errors/issue13423.go
index 6b2ad58..fc19157 100644
--- a/misc/cgo/errors/issue13423.go
+++ b/misc/cgo/errors/issue13423.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/errors/issue13635.go b/misc/cgo/errors/issue13635.go
index 689e958..0ce2b1e 100644
--- a/misc/cgo/errors/issue13635.go
+++ b/misc/cgo/errors/issue13635.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/errors/issue13830.go b/misc/cgo/errors/issue13830.go
new file mode 100644
index 0000000..ac20c82
--- /dev/null
+++ b/misc/cgo/errors/issue13830.go
@@ -0,0 +1,26 @@
+// Copyright 2016 The Go 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 converts C void* to Go unsafe.Pointer, so despite appearances C
+// void** is Go *unsafe.Pointer. This test verifies that we detect the
+// problem at build time.
+
+package main
+
+// typedef void v;
+// void F(v** p) {}
+import "C"
+
+import "unsafe"
+
+type v [0]byte
+
+func f(p **v) {
+	C.F((**C.v)(unsafe.Pointer(p))) // ERROR HERE
+}
+
+func main() {
+	var p *v
+	f(&p)
+}
diff --git a/misc/cgo/errors/issue14669.go b/misc/cgo/errors/issue14669.go
new file mode 100644
index 0000000..04d2bcb
--- /dev/null
+++ b/misc/cgo/errors/issue14669.go
@@ -0,0 +1,23 @@
+// Copyright 2016 The Go 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 14669: test that fails when build with CGO_CFLAGS selecting
+// optimization.
+
+package p
+
+/*
+const int E = 1;
+
+typedef struct s {
+	int       c;
+} s;
+*/
+import "C"
+
+func F() {
+	_ = C.s{
+		c: C.E,
+	}
+}
diff --git a/misc/cgo/errors/issue16116.go b/misc/cgo/errors/issue16116.go
new file mode 100644
index 0000000..1e01cab
--- /dev/null
+++ b/misc/cgo/errors/issue16116.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. 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
+
+// void f(void *p, int x) {}
+import "C"
+
+func main() {
+	_ = C.f(1) // ERROR HERE
+}
diff --git a/misc/cgo/errors/issue7757.go b/misc/cgo/errors/issue7757.go
index 5eafd22..0426e9f 100644
--- a/misc/cgo/errors/issue7757.go
+++ b/misc/cgo/errors/issue7757.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/errors/issue8442.go b/misc/cgo/errors/issue8442.go
index 45daf8e..60477ad 100644
--- a/misc/cgo/errors/issue8442.go
+++ b/misc/cgo/errors/issue8442.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/errors/ptr.go b/misc/cgo/errors/ptr.go
index bbcaaab..e39f041 100644
--- a/misc/cgo/errors/ptr.go
+++ b/misc/cgo/errors/ptr.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -290,6 +290,38 @@ var ptrTests = []ptrTest{
 		},
 		fail: true,
 	},
+	{
+		// Don't check non-pointer data.
+		// Uses unsafe code to get a pointer we shouldn't check.
+		// Although we use unsafe, the uintptr represents an integer
+		// that happens to have the same representation as a pointer;
+		// that is, we are testing something that is not unsafe.
+		name: "ptrdata1",
+		c: `#include <stdlib.h>
+                    void f(void* p) {}`,
+		imports: []string{"unsafe"},
+		support: `type S struct { p *int; a [8*8]byte; u uintptr }`,
+		body:    `i := 0; p := &S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(*p)))); *q = *p; C.f(unsafe.Pointer(q))`,
+		fail:    false,
+	},
+	{
+		// Like ptrdata1, but with a type that uses a GC program.
+		name: "ptrdata2",
+		c: `#include <stdlib.h>
+                    void f(void* p) {}`,
+		imports: []string{"unsafe"},
+		support: `type S struct { p *int; a [32769*8]byte; q *int; u uintptr }`,
+		body:    `i := 0; p := S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f(unsafe.Pointer(q))`,
+		fail:    false,
+	},
+	{
+		// Check deferred pointers when they are used, not
+		// when the defer statement is run.
+		name: "defer",
+		c:    `typedef struct s { int *p; } s; void f(s *ps) {}`,
+		body: `p := &C.s{}; defer C.f(p); p.p = new(C.int)`,
+		fail: true,
+	},
 }
 
 func main() {
diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash
index cd358a1..84d44d8 100755
--- a/misc/cgo/errors/test.bash
+++ b/misc/cgo/errors/test.bash
@@ -18,16 +18,16 @@ expect() {
 	file=$1
 	shift
 	if go build $file >errs 2>&1; then
-		echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail but it succeeded
+		echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail on $file but it succeeded
 		exit 1
 	fi
 	if ! test -s errs; then
-		echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output but saw none
+		echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file but saw none
 		exit 1
 	fi
 	for error; do
 		if ! fgrep $error errs >/dev/null 2>&1; then
-			echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output to contain \"$error\" but saw:
+			echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file to contain \"$error\" but saw:
 			cat 1>&2 errs
 			exit 1
 		fi
@@ -44,6 +44,15 @@ check issue11097b.go
 expect issue13129.go C.ushort
 check issue13423.go
 expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble
+check issue13830.go
+check issue16116.go
+
+if ! go build issue14669.go; then
+	exit 1
+fi
+if ! CGO_CFLAGS="-O" go build issue14669.go; then
+	exit 1
+fi
 
 if ! go run ptr.go; then
 	exit 1
diff --git a/misc/cgo/fortran/answer.f90 b/misc/cgo/fortran/answer.f90
new file mode 100644
index 0000000..b3717ee
--- /dev/null
+++ b/misc/cgo/fortran/answer.f90
@@ -0,0 +1,9 @@
+! Copyright 2016 The Go 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 the_answer() result(j) bind(C)
+  use iso_c_binding, only: c_int
+  integer(c_int) :: j ! output
+  j = 42
+end function the_answer
diff --git a/misc/cgo/fortran/fortran.go b/misc/cgo/fortran/fortran.go
new file mode 100644
index 0000000..0079b53
--- /dev/null
+++ b/misc/cgo/fortran/fortran.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fortran
+
+// int the_answer();
+import "C"
+
+func TheAnswer() int {
+	return int(C.the_answer())
+}
diff --git a/misc/cgo/fortran/fortran_test.go b/misc/cgo/fortran/fortran_test.go
new file mode 100644
index 0000000..d0cb9f2
--- /dev/null
+++ b/misc/cgo/fortran/fortran_test.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fortran
+
+import "testing"
+
+func TestFortran(t *testing.T) {
+	if a := TheAnswer(); a != 42 {
+		t.Errorf("Unexpected result for The Answer. Got: %d Want: 42", a)
+	}
+}
diff --git a/misc/cgo/fortran/helloworld/helloworld.f90 b/misc/cgo/fortran/helloworld/helloworld.f90
new file mode 100644
index 0000000..cbc34c1
--- /dev/null
+++ b/misc/cgo/fortran/helloworld/helloworld.f90
@@ -0,0 +1,3 @@
+      program HelloWorldF90
+              write(*,*) "Hello World!"
+      end program HelloWorldF90
diff --git a/misc/cgo/fortran/test.bash b/misc/cgo/fortran/test.bash
new file mode 100755
index 0000000..3d1bc9d
--- /dev/null
+++ b/misc/cgo/fortran/test.bash
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+# Copyright 2016 The Go 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 directory is intended to test the use of Fortran with cgo.
+
+set -e
+
+FC=$1
+
+goos=$(go env GOOS)
+
+libext="so"
+if [ "$goos" == "darwin" ]; then
+	libext="dylib"
+fi
+
+case "$FC" in
+*gfortran*)
+  libpath=$(dirname $($FC -print-file-name=libgfortran.$libext))
+  export CGO_LDFLAGS="$CGO_LDFLAGS -Wl,-rpath,$libpath -L $libpath"
+  ;;
+esac
+
+if ! $FC helloworld/helloworld.f90 -o main.exe >& /dev/null; then
+  echo "skipping Fortran test: could not build helloworld.f90 with $FC"
+  exit 0
+fi
+rm -f main.exe
+
+status=0
+
+if ! go test; then
+  echo "FAIL: go test"
+  status=1
+fi
+
+exit $status
diff --git a/misc/cgo/gmp/fib.go b/misc/cgo/gmp/fib.go
index 18434be..f1091b1 100644
--- a/misc/cgo/gmp/fib.go
+++ b/misc/cgo/gmp/fib.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/misc/cgo/gmp/gmp.go b/misc/cgo/gmp/gmp.go
index d39bfe6..971a10a 100644
--- a/misc/cgo/gmp/gmp.go
+++ b/misc/cgo/gmp/gmp.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/misc/cgo/gmp/pi.go b/misc/cgo/gmp/pi.go
index a189375..d5851e8 100644
--- a/misc/cgo/gmp/pi.go
+++ b/misc/cgo/gmp/pi.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/misc/cgo/life/c-life.c b/misc/cgo/life/c-life.c
index 6572455..f853163 100644
--- a/misc/cgo/life/c-life.c
+++ b/misc/cgo/life/c-life.c
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/misc/cgo/life/life.go b/misc/cgo/life/life.go
index fda5495..170a620 100644
--- a/misc/cgo/life/life.go
+++ b/misc/cgo/life/life.go
@@ -1,6 +1,6 @@
 // skip
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/misc/cgo/life/life.h b/misc/cgo/life/life.h
index b2011b2..11d2b97 100644
--- a/misc/cgo/life/life.h
+++ b/misc/cgo/life/life.h
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/misc/cgo/life/main.go b/misc/cgo/life/main.go
index c17cd6c..aa2f6d1 100644
--- a/misc/cgo/life/main.go
+++ b/misc/cgo/life/main.go
@@ -1,6 +1,6 @@
 // cmpout
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/misc/cgo/stdio/chain.go b/misc/cgo/stdio/chain.go
index 1256133..03cddb7 100644
--- a/misc/cgo/stdio/chain.go
+++ b/misc/cgo/stdio/chain.go
@@ -1,6 +1,6 @@
 // cmpout
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/misc/cgo/stdio/fib.go b/misc/cgo/stdio/fib.go
index eb43cf5..61a1b83 100644
--- a/misc/cgo/stdio/fib.go
+++ b/misc/cgo/stdio/fib.go
@@ -1,6 +1,6 @@
 // cmpout
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/misc/cgo/stdio/file.go b/misc/cgo/stdio/file.go
index e7bb906..a024f2c 100644
--- a/misc/cgo/stdio/file.go
+++ b/misc/cgo/stdio/file.go
@@ -1,6 +1,6 @@
 // skip
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/misc/cgo/stdio/hello.go b/misc/cgo/stdio/hello.go
index 60c0304..47179ba 100644
--- a/misc/cgo/stdio/hello.go
+++ b/misc/cgo/stdio/hello.go
@@ -1,6 +1,6 @@
 // cmpout
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/misc/cgo/stdio/stdio.go b/misc/cgo/stdio/stdio.go
index 76cb8ad..d216e44 100644
--- a/misc/cgo/stdio/stdio.go
+++ b/misc/cgo/stdio/stdio.go
@@ -1,6 +1,6 @@
 // skip
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/api.go b/misc/cgo/test/api.go
index f5a8594..b4ae3dd 100644
--- a/misc/cgo/test/api.go
+++ b/misc/cgo/test/api.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/basic.go b/misc/cgo/test/basic.go
index 019139d..2189af6 100644
--- a/misc/cgo/test/basic.go
+++ b/misc/cgo/test/basic.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/misc/cgo/test/buildid_linux.go b/misc/cgo/test/buildid_linux.go
index 2641dd5..47dd871 100644
--- a/misc/cgo/test/buildid_linux.go
+++ b/misc/cgo/test/buildid_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/callback_c.c b/misc/cgo/test/callback_c.c
index 5ae237b..8921b73 100644
--- a/misc/cgo/test/callback_c.c
+++ b/misc/cgo/test/callback_c.c
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -36,7 +36,7 @@ IntoC(void)
 long long
 mysleep(int seconds) {
 	long long st = GetTickCount();
-	sleep(seconds);
+	Sleep(1000 * seconds);
 	return st;
 }
 #else
diff --git a/misc/cgo/test/callback_c_gc.c b/misc/cgo/test/callback_c_gc.c
index c6ea3c5..eb720eb 100644
--- a/misc/cgo/test/callback_c_gc.c
+++ b/misc/cgo/test/callback_c_gc.c
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/callback_c_gccgo.c b/misc/cgo/test/callback_c_gccgo.c
index ff5dbbb..4eaa818 100644
--- a/misc/cgo/test/callback_c_gccgo.c
+++ b/misc/cgo/test/callback_c_gccgo.c
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/cflags.go b/misc/cgo/test/cflags.go
index 6571fe0..bc290bf 100644
--- a/misc/cgo/test/cflags.go
+++ b/misc/cgo/test/cflags.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/cgo_linux_test.go b/misc/cgo/test/cgo_linux_test.go
index 3cc2af5..9c15f69 100644
--- a/misc/cgo/test/cgo_linux_test.go
+++ b/misc/cgo/test/cgo_linux_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,8 +6,7 @@ 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 Test9400(t *testing.T)        { test9400(t) }
-func TestSigProcMask(t *testing.T) { testSigProcMask(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) }
diff --git a/misc/cgo/test/cgo_stubs_android_test.go b/misc/cgo/test/cgo_stubs_android_test.go
new file mode 100644
index 0000000..710e094
--- /dev/null
+++ b/misc/cgo/test/cgo_stubs_android_test.go
@@ -0,0 +1,13 @@
+// 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 cgotest
+
+import "testing"
+
+// Stubs for tests that fails to build on Android
+func test6997(t *testing.T)        {}
+func test3775(t *testing.T)        {}
+func test8694(t *testing.T)        {}
+func testSigaltstack(t *testing.T) {}
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index 48fb6f1..8a95b02 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -69,5 +69,6 @@ func Test11925(t *testing.T)                 { test11925(t) }
 func Test12030(t *testing.T)                 { test12030(t) }
 func TestGCC68255(t *testing.T)              { testGCC68255(t) }
 func TestCallGoWithString(t *testing.T)      { testCallGoWithString(t) }
+func Test14838(t *testing.T)                 { test14838(t) }
 
 func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
diff --git a/misc/cgo/test/cgo_unix_test.go b/misc/cgo/test/cgo_unix_test.go
index 5808e6e..b3633b7 100644
--- a/misc/cgo/test/cgo_unix_test.go
+++ b/misc/cgo/test/cgo_unix_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -9,3 +9,4 @@ package cgotest
 import "testing"
 
 func TestSigaltstack(t *testing.T) { testSigaltstack(t) }
+func TestSigprocmask(t *testing.T) { testSigprocmask(t) }
diff --git a/misc/cgo/test/cthread.go b/misc/cgo/test/cthread.go
index 68d4a03..af44911 100644
--- a/misc/cgo/test/cthread.go
+++ b/misc/cgo/test/cthread.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,6 +8,7 @@ package cgotest
 import "C"
 
 import (
+	"runtime"
 	"sync"
 	"testing"
 )
@@ -30,6 +31,9 @@ func Add(x int) {
 }
 
 func testCthread(t *testing.T) {
+	if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+		t.Skip("the iOS exec wrapper is unable to properly handle the panic from Add")
+	}
 	sum.i = 0
 	C.doAdd(10, 6)
 
diff --git a/misc/cgo/test/cthread_unix.c b/misc/cgo/test/cthread_unix.c
index d29f2fc..6323e49 100644
--- a/misc/cgo/test/cthread_unix.c
+++ b/misc/cgo/test/cthread_unix.c
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/cthread_windows.c b/misc/cgo/test/cthread_windows.c
index 5f370a8..3a62ddd 100644
--- a/misc/cgo/test/cthread_windows.c
+++ b/misc/cgo/test/cthread_windows.c
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/duplicate_symbol.go b/misc/cgo/test/duplicate_symbol.go
index 69600de..6144271 100644
--- a/misc/cgo/test/duplicate_symbol.go
+++ b/misc/cgo/test/duplicate_symbol.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/misc/cgo/test/exports.go b/misc/cgo/test/exports.go
index 4fe1703..71e5dcd 100644
--- a/misc/cgo/test/exports.go
+++ b/misc/cgo/test/exports.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/fpvar.go b/misc/cgo/test/fpvar.go
index c0ec6f6..7aab8ca 100644
--- a/misc/cgo/test/fpvar.go
+++ b/misc/cgo/test/fpvar.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/gcc68255.go b/misc/cgo/test/gcc68255.go
index 2c4f931..23e103d 100644
--- a/misc/cgo/test/gcc68255.go
+++ b/misc/cgo/test/gcc68255.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/gcc68255/a.go b/misc/cgo/test/gcc68255/a.go
index 02e5494..e106dee 100644
--- a/misc/cgo/test/gcc68255/a.go
+++ b/misc/cgo/test/gcc68255/a.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/gcc68255/c.c b/misc/cgo/test/gcc68255/c.c
index 28cfe72..a4fe193 100644
--- a/misc/cgo/test/gcc68255/c.c
+++ b/misc/cgo/test/gcc68255/c.c
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/gcc68255/c.h b/misc/cgo/test/gcc68255/c.h
index 644003e..05ecd81 100644
--- a/misc/cgo/test/gcc68255/c.h
+++ b/misc/cgo/test/gcc68255/c.h
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/helpers.go b/misc/cgo/test/helpers.go
index 890dcbd..f6a822a 100644
--- a/misc/cgo/test/helpers.go
+++ b/misc/cgo/test/helpers.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue10303.go b/misc/cgo/test/issue10303.go
index dd19dfb..66e2644 100644
--- a/misc/cgo/test/issue10303.go
+++ b/misc/cgo/test/issue10303.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/issue11925.go b/misc/cgo/test/issue11925.go
index 9e50fb7..c5c8a26 100644
--- a/misc/cgo/test/issue11925.go
+++ b/misc/cgo/test/issue11925.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/issue12030.go b/misc/cgo/test/issue12030.go
index ef8f86f..f863c58 100644
--- a/misc/cgo/test/issue12030.go
+++ b/misc/cgo/test/issue12030.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/issue1222.go b/misc/cgo/test/issue1222.go
index c396a0c..4868da8 100644
--- a/misc/cgo/test/issue1222.go
+++ b/misc/cgo/test/issue1222.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/misc/cgo/test/issue1328.go b/misc/cgo/test/issue1328.go
index e1796d6..2401c10 100644
--- a/misc/cgo/test/issue1328.go
+++ b/misc/cgo/test/issue1328.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue13402.go b/misc/cgo/test/issue13402.go
index 6e3e24c..3af24c2 100644
--- a/misc/cgo/test/issue13402.go
+++ b/misc/cgo/test/issue13402.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/issue13930.go b/misc/cgo/test/issue13930.go
new file mode 100644
index 0000000..c4a08ee
--- /dev/null
+++ b/misc/cgo/test/issue13930.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go 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 13930.  Test that cgo's multiple-value special form for
+// C function calls works in variable declaration statements.
+
+package cgotest
+
+// #include <stdlib.h>
+import "C"
+
+var _, _ = C.abs(0)
diff --git a/misc/cgo/test/issue14838.go b/misc/cgo/test/issue14838.go
new file mode 100644
index 0000000..c8e1681
--- /dev/null
+++ b/misc/cgo/test/issue14838.go
@@ -0,0 +1,37 @@
+// Copyright 2016 The Go 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 14838. add CBytes function
+
+package cgotest
+
+/*
+#include <stdlib.h>
+
+int check_cbytes(char *b, size_t l) {
+	int i;
+	for (i = 0; i < l; i++) {
+		if (b[i] != i) {
+			return 0;
+		}
+	}
+	return 1;
+}
+*/
+import "C"
+
+import (
+	"testing"
+	"unsafe"
+)
+
+func test14838(t *testing.T) {
+	data := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+	cData := C.CBytes(data)
+	defer C.free(cData)
+
+	if C.check_cbytes((*C.char)(cData), C.size_t(len(data))) == 0 {
+		t.Fatalf("mismatched data: expected %v, got %v", data, (*(*[10]byte)(unsafe.Pointer(cData)))[:])
+	}
+}
diff --git a/misc/cgo/test/issue1560.go b/misc/cgo/test/issue1560.go
index c46954b..30f6152 100644
--- a/misc/cgo/test/issue1560.go
+++ b/misc/cgo/test/issue1560.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue1635.go b/misc/cgo/test/issue1635.go
index cc4be90..2589927 100644
--- a/misc/cgo/test/issue1635.go
+++ b/misc/cgo/test/issue1635.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue2462.go b/misc/cgo/test/issue2462.go
index 12cd91d..febca1e 100644
--- a/misc/cgo/test/issue2462.go
+++ b/misc/cgo/test/issue2462.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue3250.go b/misc/cgo/test/issue3250.go
index b1ff039..f85c16b 100644
--- a/misc/cgo/test/issue3250.go
+++ b/misc/cgo/test/issue3250.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -13,9 +13,9 @@ package cgotest
 #include <stdlib.h>
 
 static void *thread(void *p) {
-	(void)p;
 	const int M = 100;
 	int i;
+	(void)p;
 	for (i = 0; i < M; i++) {
 		pthread_kill(pthread_self(), SIGCHLD);
 		usleep(rand() % 20 + 5);
diff --git a/misc/cgo/test/issue3250w.go b/misc/cgo/test/issue3250w.go
index e3cb161..c2193aa 100644
--- a/misc/cgo/test/issue3250w.go
+++ b/misc/cgo/test/issue3250w.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue3261.go b/misc/cgo/test/issue3261.go
index 32cb06b..7137569 100644
--- a/misc/cgo/test/issue3261.go
+++ b/misc/cgo/test/issue3261.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue3729.go b/misc/cgo/test/issue3729.go
index 1bea38b..947b90a 100644
--- a/misc/cgo/test/issue3729.go
+++ b/misc/cgo/test/issue3729.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue3729w.go b/misc/cgo/test/issue3729w.go
index 702115b..69296b5 100644
--- a/misc/cgo/test/issue3729w.go
+++ b/misc/cgo/test/issue3729w.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue3741.go b/misc/cgo/test/issue3741.go
index 3d3bbf9..314038c 100644
--- a/misc/cgo/test/issue3741.go
+++ b/misc/cgo/test/issue3741.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue3775.go b/misc/cgo/test/issue3775.go
index 8f81854..5aca760 100644
--- a/misc/cgo/test/issue3775.go
+++ b/misc/cgo/test/issue3775.go
@@ -1,3 +1,5 @@
+// +build !android
+
 package cgotest
 
 /*
diff --git a/misc/cgo/test/issue3945.go b/misc/cgo/test/issue3945.go
index 7e6863f..2f9fe23 100644
--- a/misc/cgo/test/issue3945.go
+++ b/misc/cgo/test/issue3945.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue4029.c b/misc/cgo/test/issue4029.c
index 1ff97ec..eab3683 100644
--- a/misc/cgo/test/issue4029.c
+++ b/misc/cgo/test/issue4029.c
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/issue4029.go b/misc/cgo/test/issue4029.go
index 9282725..5789b99 100644
--- a/misc/cgo/test/issue4029.go
+++ b/misc/cgo/test/issue4029.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue4029w.go b/misc/cgo/test/issue4029w.go
index 1cf43df..18c7201 100644
--- a/misc/cgo/test/issue4029w.go
+++ b/misc/cgo/test/issue4029w.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue4273.c b/misc/cgo/test/issue4273.c
index a3fcf3b..cac9876 100644
--- a/misc/cgo/test/issue4273.c
+++ b/misc/cgo/test/issue4273.c
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue4273b.c b/misc/cgo/test/issue4273b.c
index 93e2f4f..71e3f0d 100644
--- a/misc/cgo/test/issue4273b.c
+++ b/misc/cgo/test/issue4273b.c
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue4339.go b/misc/cgo/test/issue4339.go
index f734a25..4fa4b2b 100644
--- a/misc/cgo/test/issue4339.go
+++ b/misc/cgo/test/issue4339.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue4417.go b/misc/cgo/test/issue4417.go
index 0b48071..9b18287 100644
--- a/misc/cgo/test/issue4417.go
+++ b/misc/cgo/test/issue4417.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/issue4857.go b/misc/cgo/test/issue4857.go
index 54dc39f..b18979b 100644
--- a/misc/cgo/test/issue4857.go
+++ b/misc/cgo/test/issue4857.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5227.go b/misc/cgo/test/issue5227.go
index 336c4c6..53c3bf1 100644
--- a/misc/cgo/test/issue5227.go
+++ b/misc/cgo/test/issue5227.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5242.go b/misc/cgo/test/issue5242.go
index fe0a632..c81cd40 100644
--- a/misc/cgo/test/issue5242.go
+++ b/misc/cgo/test/issue5242.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue5337.go b/misc/cgo/test/issue5337.go
index 8013b66..9041d95 100644
--- a/misc/cgo/test/issue5337.go
+++ b/misc/cgo/test/issue5337.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5337w.go b/misc/cgo/test/issue5337w.go
index 14720a9..7b46757 100644
--- a/misc/cgo/test/issue5337w.go
+++ b/misc/cgo/test/issue5337w.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5548.go b/misc/cgo/test/issue5548.go
index c879f2a..0710da7 100644
--- a/misc/cgo/test/issue5548.go
+++ b/misc/cgo/test/issue5548.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5548_c.c b/misc/cgo/test/issue5548_c.c
index ee9c459..8411526 100644
--- a/misc/cgo/test/issue5548_c.c
+++ b/misc/cgo/test/issue5548_c.c
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5603.go b/misc/cgo/test/issue5603.go
index ecb2aa3..ab84339 100644
--- a/misc/cgo/test/issue5603.go
+++ b/misc/cgo/test/issue5603.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5740.go b/misc/cgo/test/issue5740.go
index 25c8615..059e316 100644
--- a/misc/cgo/test/issue5740.go
+++ b/misc/cgo/test/issue5740.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5740a.c b/misc/cgo/test/issue5740a.c
index 25f18e2..a6a7d0c 100644
--- a/misc/cgo/test/issue5740a.c
+++ b/misc/cgo/test/issue5740a.c
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5740b.c b/misc/cgo/test/issue5740b.c
index 22893f3..c2ff5fb 100644
--- a/misc/cgo/test/issue5740b.c
+++ b/misc/cgo/test/issue5740b.c
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue5986.go b/misc/cgo/test/issue5986.go
index 4f772cd..9be1614 100644
--- a/misc/cgo/test/issue5986.go
+++ b/misc/cgo/test/issue5986.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -13,6 +13,7 @@ static void output5986()
 {
     int current_row = 0, row_count = 0;
     double sum_squares = 0;
+    double d;
     do {
         if (current_row == 10) {
             current_row = 0;
@@ -20,7 +21,7 @@ static void output5986()
         ++row_count;
     }
     while (current_row++ != 1);
-    double d =  sqrt(sum_squares / row_count);
+    d =  sqrt(sum_squares / row_count);
     printf("sqrt is: %g\n", d);
 }
 */
diff --git a/misc/cgo/test/issue6128.go b/misc/cgo/test/issue6128.go
index 4afba24..9832d79 100644
--- a/misc/cgo/test/issue6128.go
+++ b/misc/cgo/test/issue6128.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue6390.go b/misc/cgo/test/issue6390.go
index 6f5715b..5642899 100644
--- a/misc/cgo/test/issue6390.go
+++ b/misc/cgo/test/issue6390.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue6472.go b/misc/cgo/test/issue6472.go
index cd94cac..d416a05 100644
--- a/misc/cgo/test/issue6472.go
+++ b/misc/cgo/test/issue6472.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue6506.go b/misc/cgo/test/issue6506.go
index b79e242..c54b54b 100644
--- a/misc/cgo/test/issue6506.go
+++ b/misc/cgo/test/issue6506.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue6612.go b/misc/cgo/test/issue6612.go
index 902878c..c337f91 100644
--- a/misc/cgo/test/issue6612.go
+++ b/misc/cgo/test/issue6612.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue6833.go b/misc/cgo/test/issue6833.go
index e12d534..de60dbf 100644
--- a/misc/cgo/test/issue6833.go
+++ b/misc/cgo/test/issue6833.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue6833_c.c b/misc/cgo/test/issue6833_c.c
index a77b425..c94c2c6 100644
--- a/misc/cgo/test/issue6833_c.c
+++ b/misc/cgo/test/issue6833_c.c
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue6997_linux.c b/misc/cgo/test/issue6997_linux.c
index 897cdd0..de803d2 100644
--- a/misc/cgo/test/issue6997_linux.c
+++ b/misc/cgo/test/issue6997_linux.c
@@ -1,7 +1,9 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 !android
+
 #include <pthread.h>
 #include <stdio.h>
 #include <unistd.h>
diff --git a/misc/cgo/test/issue6997_linux.go b/misc/cgo/test/issue6997_linux.go
index 638c3b0..0c98ea0 100644
--- a/misc/cgo/test/issue6997_linux.go
+++ b/misc/cgo/test/issue6997_linux.go
@@ -1,7 +1,9 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 !android
+
 // Test that pthread_cancel works as expected
 // (NPTL uses SIGRTMIN to implement thread cancelation)
 // See https://golang.org/issue/6997
diff --git a/misc/cgo/test/issue7234_test.go b/misc/cgo/test/issue7234_test.go
index a020b6a..c191a1a 100644
--- a/misc/cgo/test/issue7234_test.go
+++ b/misc/cgo/test/issue7234_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue7560.go b/misc/cgo/test/issue7560.go
index 4bea6e3..f36d8a1 100644
--- a/misc/cgo/test/issue7560.go
+++ b/misc/cgo/test/issue7560.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue7665.go b/misc/cgo/test/issue7665.go
index da97131..ce03458 100644
--- a/misc/cgo/test/issue7665.go
+++ b/misc/cgo/test/issue7665.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue7786.go b/misc/cgo/test/issue7786.go
index b927637..1344e9e 100644
--- a/misc/cgo/test/issue7786.go
+++ b/misc/cgo/test/issue7786.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/issue7978.go b/misc/cgo/test/issue7978.go
index e8f340f..e4cbf1d 100644
--- a/misc/cgo/test/issue7978.go
+++ b/misc/cgo/test/issue7978.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -103,6 +103,9 @@ func test7978(t *testing.T) {
 	if C.HAS_SYNC_FETCH_AND_ADD == 0 {
 		t.Skip("clang required for __sync_fetch_and_add support on darwin/arm")
 	}
+	if runtime.GOOS == "android" || runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+		t.Skip("GOTRACEBACK is not passed on to the exec wrapper")
+	}
 	if os.Getenv("GOTRACEBACK") != "2" {
 		t.Fatalf("GOTRACEBACK must be 2")
 	}
diff --git a/misc/cgo/test/issue8092.go b/misc/cgo/test/issue8092.go
index 8a14ce6..19123e7 100644
--- a/misc/cgo/test/issue8092.go
+++ b/misc/cgo/test/issue8092.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8148.go b/misc/cgo/test/issue8148.go
index 8e41908..f704788 100644
--- a/misc/cgo/test/issue8148.go
+++ b/misc/cgo/test/issue8148.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8331.h b/misc/cgo/test/issue8331.h
index 936ae9d..8065be0 100644
--- a/misc/cgo/test/issue8331.h
+++ b/misc/cgo/test/issue8331.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8331a.go b/misc/cgo/test/issue8331a.go
index 7fa55be..92e2579 100644
--- a/misc/cgo/test/issue8331a.go
+++ b/misc/cgo/test/issue8331a.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8331b.go b/misc/cgo/test/issue8331b.go
index d52aed6..5324aa2 100644
--- a/misc/cgo/test/issue8331b.go
+++ b/misc/cgo/test/issue8331b.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8428.go b/misc/cgo/test/issue8428.go
index 16fa7cc..2e5a555 100644
--- a/misc/cgo/test/issue8428.go
+++ b/misc/cgo/test/issue8428.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8441.go b/misc/cgo/test/issue8441.go
index 2d871f0..4489ca9 100644
--- a/misc/cgo/test/issue8441.go
+++ b/misc/cgo/test/issue8441.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8694.go b/misc/cgo/test/issue8694.go
index ba7a344..89be7ea 100644
--- a/misc/cgo/test/issue8694.go
+++ b/misc/cgo/test/issue8694.go
@@ -1,7 +1,9 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 !android
+
 package cgotest
 
 /*
diff --git a/misc/cgo/test/issue8811.c b/misc/cgo/test/issue8811.c
index 584bb39..41b3c7c 100644
--- a/misc/cgo/test/issue8811.c
+++ b/misc/cgo/test/issue8811.c
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8811.go b/misc/cgo/test/issue8811.go
index 2e217d9..f812732 100644
--- a/misc/cgo/test/issue8811.go
+++ b/misc/cgo/test/issue8811.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8828/issue8828.c b/misc/cgo/test/issue8828/issue8828.c
index 2950f87..27ec23a 100644
--- a/misc/cgo/test/issue8828/issue8828.c
+++ b/misc/cgo/test/issue8828/issue8828.c
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue8945.go b/misc/cgo/test/issue8945.go
index 572b815..57a5b2d 100644
--- a/misc/cgo/test/issue8945.go
+++ b/misc/cgo/test/issue8945.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue9400/asm_386.s b/misc/cgo/test/issue9400/asm_386.s
index e37a54f..7f158b5 100644
--- a/misc/cgo/test/issue9400/asm_386.s
+++ b/misc/cgo/test/issue9400/asm_386.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,17 +7,18 @@
 #include "textflag.h"
 
 TEXT ·RewindAndSetgid(SB),NOSPLIT,$0-0
+	MOVL	$·Baton(SB), BX
 	// 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)
+	MOVL	$1, (BX)
 
 	// Wait for setgid completion
 loop:
 	PAUSE
-	MOVL	·Baton(SB), AX
+	MOVL	(BX), AX
 	CMPL	AX, $0
 	JNE	loop
 
diff --git a/misc/cgo/test/issue9400/asm_amd64x.s b/misc/cgo/test/issue9400/asm_amd64x.s
index f09e95d..48b8619 100644
--- a/misc/cgo/test/issue9400/asm_amd64x.s
+++ b/misc/cgo/test/issue9400/asm_amd64x.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue9400/asm_arm.s b/misc/cgo/test/issue9400/asm_arm.s
index 5c5983d..166d53f 100644
--- a/misc/cgo/test/issue9400/asm_arm.s
+++ b/misc/cgo/test/issue9400/asm_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue9400/asm_arm64.s b/misc/cgo/test/issue9400/asm_arm64.s
index cba525f..9bb5081 100644
--- a/misc/cgo/test/issue9400/asm_arm64.s
+++ b/misc/cgo/test/issue9400/asm_arm64.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue9400/asm_mips64x.s b/misc/cgo/test/issue9400/asm_mips64x.s
new file mode 100644
index 0000000..63dc906
--- /dev/null
+++ b/misc/cgo/test/issue9400/asm_mips64x.s
@@ -0,0 +1,33 @@
+// Copyright 2016 The Go 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 mips64 mips64le
+// +build !gccgo
+
+#include "textflag.h"
+
+#define SYNC	WORD $0xf
+
+TEXT ·RewindAndSetgid(SB),NOSPLIT|NOFRAME,$0-0
+	// Rewind stack pointer so anything that happens on the stack
+	// will clobber the test pattern created by the caller
+	ADDV	$(1024*8), R29
+
+	// Ask signaller to setgid
+	MOVW	$1, R1
+	SYNC
+	MOVW	R1, ·Baton(SB)
+	SYNC
+
+	// Wait for setgid completion
+loop:
+	SYNC
+	MOVW	·Baton(SB), R1
+	OR	R2, R2, R2	// hint that we're in a spin loop
+	BNE	R1, loop
+	SYNC
+
+	// Restore stack
+	ADDV	$(-1024*8), R29
+	RET
diff --git a/misc/cgo/test/issue9400/asm_ppc64x.s b/misc/cgo/test/issue9400/asm_ppc64x.s
index 9f80087..c88ec3b 100644
--- a/misc/cgo/test/issue9400/asm_ppc64x.s
+++ b/misc/cgo/test/issue9400/asm_ppc64x.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue9400/asm_s390x.s b/misc/cgo/test/issue9400/asm_s390x.s
new file mode 100644
index 0000000..fc9ad72
--- /dev/null
+++ b/misc/cgo/test/issue9400/asm_s390x.s
@@ -0,0 +1,26 @@
+// Copyright 2016 The Go 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
+	ADD	$(1024 * 8), R15
+
+	// Ask signaller to setgid
+	MOVD	$·Baton(SB), R5
+	MOVW	$1, 0(R5)
+
+	// Wait for setgid completion
+loop:
+	SYNC
+	MOVW	·Baton(SB), R3
+	CMPBNE	R3, $0, loop
+
+	// Restore stack
+	SUB	$(1024 * 8), R15
+	RET
diff --git a/misc/cgo/test/issue9400/gccgo.go b/misc/cgo/test/issue9400/gccgo.go
index 6b9d5fa..0ef3a8c 100644
--- a/misc/cgo/test/issue9400/gccgo.go
+++ b/misc/cgo/test/issue9400/gccgo.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue9400/stubs.go b/misc/cgo/test/issue9400/stubs.go
index 1dd8ccd..60193dc 100644
--- a/misc/cgo/test/issue9400/stubs.go
+++ b/misc/cgo/test/issue9400/stubs.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue9400_linux.go b/misc/cgo/test/issue9400_linux.go
index b3b4b79..34eb498 100644
--- a/misc/cgo/test/issue9400_linux.go
+++ b/misc/cgo/test/issue9400_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/issue9510.go b/misc/cgo/test/issue9510.go
index a940bfb..efd3f77 100644
--- a/misc/cgo/test/issue9510.go
+++ b/misc/cgo/test/issue9510.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/issue9557.go b/misc/cgo/test/issue9557.go
index b29bacd..4e8922a 100644
--- a/misc/cgo/test/issue9557.go
+++ b/misc/cgo/test/issue9557.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/test/setgid_linux.go b/misc/cgo/test/setgid_linux.go
index ca95e08..6773f94 100644
--- a/misc/cgo/test/setgid_linux.go
+++ b/misc/cgo/test/setgid_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/cgo/test/sigaltstack.go b/misc/cgo/test/sigaltstack.go
index b641ff6..b16adc7 100644
--- a/misc/cgo/test/sigaltstack.go
+++ b/misc/cgo/test/sigaltstack.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 !windows
+// +build !windows,!android
 
 // Test that the Go runtime still works if C code changes the signal stack.
 
diff --git a/misc/cgo/test/sigprocmask.c b/misc/cgo/test/sigprocmask.c
new file mode 100644
index 0000000..bd99647
--- /dev/null
+++ b/misc/cgo/test/sigprocmask.c
@@ -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.
+
+// +build !windows
+
+#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.go b/misc/cgo/test/sigprocmask.go
new file mode 100644
index 0000000..39b658e
--- /dev/null
+++ b/misc/cgo/test/sigprocmask.go
@@ -0,0 +1,40 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+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/test/sigprocmask_linux.c b/misc/cgo/test/sigprocmask_linux.c
deleted file mode 100644
index 518c533..0000000
--- a/misc/cgo/test/sigprocmask_linux.c
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2015 The Go 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
deleted file mode 100644
index 7d343e9..0000000
--- a/misc/cgo/test/sigprocmask_linux.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2015 The Go Authors. 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/test/sleep_windows_386.go b/misc/cgo/test/sleep_windows_386.go
deleted file mode 100644
index 75687d7..0000000
--- a/misc/cgo/test/sleep_windows_386.go
+++ /dev/null
@@ -1,20 +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 cgotest
-
-/*
-// mingw32 on windows/386 provides usleep() but not sleep(),
-// as we don't want to require all other OSes to provide usleep,
-// we emulate sleep(int s) using win32 API Sleep(int ms).
-
-#include <windows.h>
-
-unsigned int sleep(unsigned int seconds) {
-	Sleep(1000 * seconds);
-	return 0;
-}
-
-*/
-import "C"
diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go
new file mode 100644
index 0000000..ab14c00
--- /dev/null
+++ b/misc/cgo/testcarchive/carchive_test.go
@@ -0,0 +1,489 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package carchive_test
+
+import (
+	"bufio"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"syscall"
+	"testing"
+	"time"
+	"unicode"
+)
+
+// Program to run.
+var bin []string
+
+// C compiler with args (from $(go env CC) $(go env GOGCCFLAGS)).
+var cc []string
+
+// An environment with GOPATH=$(pwd).
+var gopathEnv []string
+
+// ".exe" on Windows.
+var exeSuffix string
+
+var GOOS, GOARCH string
+var libgodir string
+
+func init() {
+	bin = []string{"./testp"}
+	GOOS = goEnv("GOOS")
+	GOARCH = goEnv("GOARCH")
+	execScript := "go_" + GOOS + "_" + GOARCH + "_exec"
+	if executor, err := exec.LookPath(execScript); err == nil {
+		bin = []string{executor, "./testp"}
+	}
+
+	ccOut := goEnv("CC")
+	cc = []string{string(ccOut)}
+
+	out := goEnv("GOGCCFLAGS")
+	quote := '\000'
+	start := 0
+	lastSpace := true
+	backslash := false
+	s := string(out)
+	for i, c := range s {
+		if quote == '\000' && unicode.IsSpace(c) {
+			if !lastSpace {
+				cc = append(cc, s[start:i])
+				lastSpace = true
+			}
+		} else {
+			if lastSpace {
+				start = i
+				lastSpace = false
+			}
+			if quote == '\000' && !backslash && (c == '"' || c == '\'') {
+				quote = c
+				backslash = false
+			} else if !backslash && quote == c {
+				quote = '\000'
+			} else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
+				backslash = true
+			} else {
+				backslash = false
+			}
+		}
+	}
+	if !lastSpace {
+		cc = append(cc, s[start:])
+	}
+
+	if GOOS == "darwin" {
+		// For Darwin/ARM.
+		// TODO(crawshaw): can we do better?
+		cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
+	}
+	libgodir = GOOS + "_" + GOARCH
+	if GOOS == "darwin" && (GOARCH == "arm" || GOARCH == "arm64") {
+		libgodir = GOOS + "_" + GOARCH + "_shared"
+	}
+	cc = append(cc, "-I", filepath.Join("pkg", libgodir))
+
+	// Build an environment with GOPATH=$(pwd)
+	env := os.Environ()
+	var n []string
+	for _, e := range env {
+		if !strings.HasPrefix(e, "GOPATH=") {
+			n = append(n, e)
+		}
+	}
+	dir, err := os.Getwd()
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+	n = append(n, "GOPATH="+dir)
+	gopathEnv = n
+
+	if GOOS == "windows" {
+		exeSuffix = ".exe"
+	}
+}
+
+func goEnv(key string) string {
+	out, err := exec.Command("go", "env", key).Output()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "go env %s failed:\n%s", key, err)
+		fmt.Fprintf(os.Stderr, "%s", err.(*exec.ExitError).Stderr)
+		os.Exit(2)
+	}
+	return strings.TrimSpace(string(out))
+}
+
+func compilemain(t *testing.T, libgo string) {
+	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main.c")
+	if GOOS == "windows" {
+		ccArgs = append(ccArgs, "main_windows.c", libgo, "-lntdll", "-lws2_32", "-lwinmm")
+	} else {
+		ccArgs = append(ccArgs, "main_unix.c", libgo)
+	}
+	t.Log(ccArgs)
+
+	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+}
+
+func TestInstall(t *testing.T) {
+	defer func() {
+		os.Remove("libgo.a")
+		os.Remove("libgo.h")
+		os.Remove("testp")
+		os.RemoveAll("pkg")
+	}()
+
+	cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	compilemain(t, filepath.Join("pkg", libgodir, "libgo.a"))
+
+	binArgs := append(bin, "arg1", "arg2")
+	if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	os.Remove("libgo.a")
+	os.Remove("libgo.h")
+	os.Remove("testp")
+
+	// Test building libgo other than installing it.
+	// Header files are now present.
+	cmd = exec.Command("go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go"))
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	compilemain(t, "libgo.a")
+
+	if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	os.Remove("libgo.a")
+	os.Remove("libgo.h")
+	os.Remove("testp")
+
+	cmd = exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	compilemain(t, "libgo.a")
+
+	if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+}
+
+func TestEarlySignalHandler(t *testing.T) {
+	switch GOOS {
+	case "darwin":
+		switch GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
+		}
+	case "windows":
+		t.Skip("skipping signal test on Windows")
+	}
+
+	defer func() {
+		os.Remove("libgo2.a")
+		os.Remove("libgo2.h")
+		os.Remove("testp")
+		os.RemoveAll("pkg")
+	}()
+
+	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
+	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+}
+
+func TestSignalForwarding(t *testing.T) {
+	switch GOOS {
+	case "darwin":
+		switch GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
+		}
+	case "windows":
+		t.Skip("skipping signal test on Windows")
+	}
+
+	defer func() {
+		os.Remove("libgo2.a")
+		os.Remove("libgo2.h")
+		os.Remove("testp")
+		os.RemoveAll("pkg")
+	}()
+
+	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
+	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	cmd = exec.Command(bin[0], append(bin[1:], "1")...)
+
+	out, err := cmd.CombinedOutput()
+
+	if err == nil {
+		t.Logf("%s", out)
+		t.Error("test program succeeded unexpectedly")
+	} else if ee, ok := err.(*exec.ExitError); !ok {
+		t.Logf("%s", out)
+		t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
+	} else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
+		t.Logf("%s", out)
+		t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
+	} else if !ws.Signaled() || ws.Signal() != syscall.SIGSEGV {
+		t.Logf("%s", out)
+		t.Errorf("got %v; expected SIGSEGV", ee)
+	}
+}
+
+func TestSignalForwardingExternal(t *testing.T) {
+	switch GOOS {
+	case "darwin":
+		switch GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s; see https://golang.org/issue/13701", GOOS, GOARCH)
+		}
+	case "windows":
+		t.Skip("skipping signal test on Windows")
+	}
+
+	defer func() {
+		os.Remove("libgo2.a")
+		os.Remove("libgo2.h")
+		os.Remove("testp")
+		os.RemoveAll("pkg")
+	}()
+
+	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo2.a", "libgo2")
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
+	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	// We want to send the process a signal and see if it dies.
+	// Normally the signal goes to the C thread, the Go signal
+	// handler picks it up, sees that it is running in a C thread,
+	// and the program dies. Unfortunately, occasionally the
+	// signal is delivered to a Go thread, which winds up
+	// discarding it because it was sent by another program and
+	// there is no Go handler for it. To avoid this, run the
+	// program several times in the hopes that it will eventually
+	// fail.
+	const tries = 20
+	for i := 0; i < tries; i++ {
+		cmd = exec.Command(bin[0], append(bin[1:], "2")...)
+
+		stderr, err := cmd.StderrPipe()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer stderr.Close()
+
+		r := bufio.NewReader(stderr)
+
+		err = cmd.Start()
+
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		// Wait for trigger to ensure that the process is started.
+		ok, err := r.ReadString('\n')
+
+		// Verify trigger.
+		if err != nil || ok != "OK\n" {
+			t.Fatalf("Did not receive OK signal")
+		}
+
+		// Give the program a chance to enter the sleep function.
+		time.Sleep(time.Millisecond)
+
+		cmd.Process.Signal(syscall.SIGSEGV)
+
+		err = cmd.Wait()
+
+		if err == nil {
+			continue
+		}
+
+		if ee, ok := err.(*exec.ExitError); !ok {
+			t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
+		} else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
+			t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
+		} else if !ws.Signaled() || ws.Signal() != syscall.SIGSEGV {
+			t.Errorf("got %v; expected SIGSEGV", ee)
+		} else {
+			// We got the error we expected.
+			return
+		}
+	}
+
+	t.Errorf("program succeeded unexpectedly %d times", tries)
+}
+
+func TestOsSignal(t *testing.T) {
+	switch GOOS {
+	case "windows":
+		t.Skip("skipping signal test on Windows")
+	}
+
+	defer func() {
+		os.Remove("libgo3.a")
+		os.Remove("libgo3.h")
+		os.Remove("testp")
+		os.RemoveAll("pkg")
+	}()
+
+	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo3.a", "libgo3")
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
+	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+}
+
+func TestSigaltstack(t *testing.T) {
+	switch GOOS {
+	case "windows":
+		t.Skip("skipping signal test on Windows")
+	}
+
+	defer func() {
+		os.Remove("libgo4.a")
+		os.Remove("libgo4.h")
+		os.Remove("testp")
+		os.RemoveAll("pkg")
+	}()
+
+	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo4.a", "libgo4")
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
+	if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	if out, err := exec.Command(bin[0], bin[1:]...).CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+}
+
+const testar = `#!/usr/bin/env bash
+while expr $1 : '[-]' >/dev/null; do
+  shift
+done
+echo "testar" > $1
+echo "testar" > PWD/testar.ran
+`
+
+func TestExtar(t *testing.T) {
+	switch GOOS {
+	case "windows":
+		t.Skip("skipping signal test on Windows")
+	}
+
+	defer func() {
+		os.Remove("libgo4.a")
+		os.Remove("libgo4.h")
+		os.Remove("testar")
+		os.Remove("testar.ran")
+		os.RemoveAll("pkg")
+	}()
+
+	os.Remove("testar")
+	dir, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+	s := strings.Replace(testar, "PWD", dir, 1)
+	if err := ioutil.WriteFile("testar", []byte(s), 0777); err != nil {
+		t.Fatal(err)
+	}
+
+	cmd := exec.Command("go", "build", "-buildmode=c-archive", "-ldflags=-extar="+filepath.Join(dir, "testar"), "-o", "libgo4.a", "libgo4")
+	cmd.Env = gopathEnv
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Logf("%s", out)
+		t.Fatal(err)
+	}
+
+	if _, err := os.Stat("testar.ran"); err != nil {
+		if os.IsNotExist(err) {
+			t.Error("testar does not exist after go build")
+		} else {
+			t.Errorf("error checking testar: %v", err)
+		}
+	}
+}
diff --git a/misc/cgo/testcarchive/main.c b/misc/cgo/testcarchive/main.c
index a90138f..163b539 100644
--- a/misc/cgo/testcarchive/main.c
+++ b/misc/cgo/testcarchive/main.c
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -10,35 +9,16 @@
 #include "p.h"
 #include "libgo.h"
 
-static void (*oldHandler)(int, siginfo_t*, void*);
-
-static void handler(int signo, siginfo_t* info, void* ctxt) {
-	if (oldHandler) {
-		oldHandler(signo, info, ctxt);
-	}
-}
+extern int install_handler();
+extern int check_handler();
 
 int main(void) {
-	struct sigaction sa;
-	struct sigaction osa;
 	int32_t res;
 
-	// Install our own signal handler.
-	memset(&sa, 0, sizeof sa);
-	sa.sa_sigaction = handler;
-	sigemptyset(&sa.sa_mask);
-	sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
-	memset(&osa, 0, sizeof osa);
-	sigemptyset(&osa.sa_mask);
-	if (sigaction(SIGSEGV, &sa, &osa) < 0) {
-		perror("sigaction");
-		return 2;
+	int r1 = install_handler();
+	if (r1!=0) {
+		return r1;
 	}
-	if (osa.sa_handler == SIG_DFL || (osa.sa_flags&SA_ONSTACK) == 0) {
-		fprintf(stderr, "Go runtime did not install signal handler\n");
-		return 2;
-	}
-	oldHandler = osa.sa_sigaction;
 
 	if (!DidInitRun()) {
 		fprintf(stderr, "ERROR: buildmode=c-archive init should run\n");
@@ -50,14 +30,9 @@ int main(void) {
 		return 2;
 	}
 
-	// Make sure our signal handler is still the one in use.
-	if (sigaction(SIGSEGV, NULL, &sa) < 0) {
-		perror("sigaction check");
-		return 2;
-	}
-	if (sa.sa_sigaction != handler) {
-		fprintf(stderr, "ERROR: wrong signal handler: %p != %p\n", sa.sa_sigaction, handler);
-		return 2;
+	int r2 = check_handler();
+	if (r2!=0) {
+		return r2;
 	}
 
 	res = FromPkg();
diff --git a/misc/cgo/testcarchive/main4.c b/misc/cgo/testcarchive/main4.c
index 2aaf09b..353f980 100644
--- a/misc/cgo/testcarchive/main4.c
+++ b/misc/cgo/testcarchive/main4.c
@@ -44,8 +44,7 @@ static void init() {
 
 // Test raising SIGIO on a C thread with an alternate signal stack
 // when there is a Go signal handler for SIGIO.
-static void* thread1(void* arg) {
-	pthread_t* ptid = (pthread_t*)(arg);
+static void* thread1(void* arg __attribute__ ((unused))) {
 	stack_t ss;
 	int i;
 	stack_t nss;
@@ -65,7 +64,7 @@ static void* thread1(void* arg) {
 	// Send ourselves a SIGIO.  This will be caught by the Go
 	// signal handler which should forward to the C signal
 	// handler.
-	i = pthread_kill(*ptid, SIGIO);
+	i = pthread_kill(pthread_self(), SIGIO);
 	if (i != 0) {
 		fprintf(stderr, "pthread_kill: %s\n", strerror(i));
 		exit(EXIT_FAILURE);
@@ -101,11 +100,11 @@ static void* thread1(void* arg) {
 
 // Test calling a Go function to raise SIGIO on a C thread with an
 // alternate signal stack when there is a Go signal handler for SIGIO.
-static void* thread2(void* arg) {
-	pthread_t* ptid = (pthread_t*)(arg);
+static void* thread2(void* arg __attribute__ ((unused))) {
 	stack_t ss;
 	int i;
 	int oldcount;
+	pthread_t tid;
 	stack_t nss;
 
 	// Set up an alternate signal stack for this thread.
@@ -124,7 +123,8 @@ static void* thread2(void* arg) {
 
 	// Call a Go function that will call a C function to send us a
 	// SIGIO.
-	GoRaiseSIGIO(ptid);
+	tid = pthread_self();
+	GoRaiseSIGIO(&tid);
 
 	// Wait until the signal has been delivered.
 	i = 0;
@@ -161,7 +161,7 @@ int main(int argc, char **argv) {
 	// Tell the Go library to start looking for SIGIO.
 	GoCatchSIGIO();
 
-	i = pthread_create(&tid, NULL, thread1, (void*)(&tid));
+	i = pthread_create(&tid, NULL, thread1, NULL);
 	if (i != 0) {
 		fprintf(stderr, "pthread_create: %s\n", strerror(i));
 		exit(EXIT_FAILURE);
@@ -173,7 +173,7 @@ int main(int argc, char **argv) {
 		exit(EXIT_FAILURE);
 	}
 
-	i = pthread_create(&tid, NULL, thread2, (void*)(&tid));
+	i = pthread_create(&tid, NULL, thread2, NULL);
 	if (i != 0) {
 		fprintf(stderr, "pthread_create: %s\n", strerror(i));
 		exit(EXIT_FAILURE);
diff --git a/misc/cgo/testcarchive/main5.c b/misc/cgo/testcarchive/main5.c
new file mode 100644
index 0000000..9fadf08
--- /dev/null
+++ b/misc/cgo/testcarchive/main5.c
@@ -0,0 +1,78 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test for verifying that the Go runtime properly forwards
+// signals when non-Go signals are raised.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/select.h>
+
+#include "libgo2.h"
+
+int main(int argc, char** argv) {
+	int verbose;
+	int test;
+
+	if (argc < 2) {
+		printf("Missing argument\n");
+		return 1;
+	}
+
+	test = atoi(argv[1]);
+
+	verbose = (argc > 2);
+
+	if (verbose) {
+		printf("calling RunGoroutines\n");
+	}
+
+	Noop();
+
+	switch (test) {
+		case 1: {
+			if (verbose) {
+				printf("attempting segfault\n");
+			}
+
+			volatile int crash = *(int *) 0;
+			break;
+		}
+
+		case 2: {
+			struct timeval tv;
+
+			if (verbose) {
+				printf("attempting external signal test\n");
+			}
+
+			fprintf(stderr, "OK\n");
+			fflush(stderr);
+
+			// The program should be interrupted before
+			// this sleep finishes. We use select rather
+			// than sleep because in older versions of
+			// glibc the sleep function does some signal
+			// fiddling to handle SIGCHLD.  If this
+			// program is fiddling signals just when the
+			// test program sends the signal, the signal
+			// may be delivered to a Go thread which will
+			// break this test.
+			tv.tv_sec = 60;
+			tv.tv_usec = 0;
+			select(0, NULL, NULL, NULL, &tv);
+
+			break;
+		}
+		default:
+			printf("Unknown test: %d\n", test);
+			return 0;
+	}
+
+	printf("FAIL\n");
+	return 0;
+}
diff --git a/misc/cgo/testcarchive/main_unix.c b/misc/cgo/testcarchive/main_unix.c
new file mode 100644
index 0000000..4d9d16f
--- /dev/null
+++ b/misc/cgo/testcarchive/main_unix.c
@@ -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.
+
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+struct sigaction sa;
+struct sigaction osa;
+
+static void (*oldHandler)(int, siginfo_t*, void*);
+
+static void handler(int signo, siginfo_t* info, void* ctxt) {
+	if (oldHandler) {
+		oldHandler(signo, info, ctxt);
+	}
+}
+
+int install_handler() {
+	// Install our own signal handler.
+	memset(&sa, 0, sizeof sa);
+	sa.sa_sigaction = handler;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
+	memset(&osa, 0, sizeof osa);
+	sigemptyset(&osa.sa_mask);
+	if (sigaction(SIGSEGV, &sa, &osa) < 0) {
+		perror("sigaction");
+		return 2;
+	}
+	if (osa.sa_handler == SIG_DFL || (osa.sa_flags&SA_ONSTACK) == 0) {
+		fprintf(stderr, "Go runtime did not install signal handler\n");
+		return 2;
+	}
+	oldHandler = osa.sa_sigaction;
+
+	return 0;
+}
+
+int check_handler() {
+	if (sigaction(SIGSEGV, NULL, &sa) < 0) {
+		perror("sigaction check");
+		return 2;
+	}
+	if (sa.sa_sigaction != handler) {
+		fprintf(stderr, "ERROR: wrong signal handler: %p != %p\n", sa.sa_sigaction, handler);
+		return 2;
+	}
+	return 0;
+}
+
diff --git a/misc/cgo/testcarchive/main_windows.c b/misc/cgo/testcarchive/main_windows.c
new file mode 100644
index 0000000..eded8af
--- /dev/null
+++ b/misc/cgo/testcarchive/main_windows.c
@@ -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.
+
+/*
+ * Dummy implementations for Windows, because Windows doesn't
+ * support Unix-style signal handling.
+ */
+
+int install_handler() {
+	return 0;
+}
+
+
+int check_handler() {
+	return 0;
+}
diff --git a/misc/cgo/testcarchive/src/libgo2/libgo2.go b/misc/cgo/testcarchive/src/libgo2/libgo2.go
index ab40b75..fbed493 100644
--- a/misc/cgo/testcarchive/src/libgo2/libgo2.go
+++ b/misc/cgo/testcarchive/src/libgo2/libgo2.go
@@ -41,5 +41,10 @@ func TestSEGV() {
 	os.Exit(1)
 }
 
+// Noop ensures that the Go runtime is initialized.
+//export Noop
+func Noop() {
+}
+
 func main() {
 }
diff --git a/misc/cgo/testcarchive/test.bash b/misc/cgo/testcarchive/test.bash
deleted file mode 100755
index f4e7c45..0000000
--- a/misc/cgo/testcarchive/test.bash
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/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
-
-status=0
-
-# 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
-if ! $bin arg1 arg2; then
-    echo "FAIL test1a"
-    status=1
-fi
-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
-if ! $bin arg1 arg2; then
-    echo "FAIL test1b"
-    status=1
-fi
-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
-if ! $bin arg1 arg2; then
-    echo "FAIL test1c"
-    status=1
-fi
-rm -rf libgo.a libgo.h testp pkg
-
-case "$(go env GOOS)/$(go env GOARCH)" in
-"darwin/arm" | "darwin/arm64")
-    echo "Skipping test2; see https://golang.org/issue/13701"
-    ;;
-*)
-    GOPATH=$(pwd) go build -buildmode=c-archive -o libgo2.a libgo2
-    $(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main2.c libgo2.a
-    if ! $bin; then
-        echo "FAIL test2"
-        status=1
-    fi
-    rm -rf libgo2.a libgo2.h testp pkg
-    ;;
-esac
-
-GOPATH=$(pwd) go build -buildmode=c-archive -o libgo3.a libgo3
-$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main3.c libgo3.a
-if ! $bin; then
-    echo "FAIL test3"
-    status=1
-fi
-rm -rf libgo3.a libgo3.h testp pkg
-
-GOPATH=$(pwd) go build -buildmode=c-archive -o libgo4.a libgo4
-$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main4.c libgo4.a
-if ! $bin; then
-    echo "FAIL test4"
-    status=1
-fi
-rm -rf libgo4.a libgo4.h testp pkg
-
-rm -f testar
-cat >testar <<EOF
-#!/usr/bin/env bash
-while expr \$1 : '[-]' >/dev/null; do
-  shift
-done
-echo "testar" > \$1
-echo "testar" > $(pwd)/testar.ran
-EOF
-chmod +x testar
-rm -f testar.ran
-GOPATH=$(pwd) go build -buildmode=c-archive -ldflags=-extar=$(pwd)/testar -o libgo4.a libgo4
-if ! test -f testar.ran; then
-    echo "FAIL test5"
-    status=1
-fi
-rm -rf libgo4.a libgo4.h testar testar.ran pkg
-
-exit $status
diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash
index 23c9767..e4bb7d3 100755
--- a/misc/cgo/testcshared/test.bash
+++ b/misc/cgo/testcshared/test.bash
@@ -10,7 +10,7 @@ set -e
 
 if [ ! -f src/libgo/libgo.go ]; then
 	cwd=$(pwd)
-	echo 'misc/cgo/testcshared/test.bash is running in $cwd' 1>&2
+	echo "misc/cgo/testcshared/test.bash is running in $cwd" 1>&2
 	exit 1
 fi
 
@@ -18,7 +18,7 @@ goos=$(go env GOOS)
 goarch=$(go env GOARCH)
 goroot=$(go env GOROOT)
 if [ ! -d "$goroot" ]; then
-	echo 'misc/cgo/testcshared/test.bash cannnot find GOROOT' 1>&2
+	echo 'misc/cgo/testcshared/test.bash cannot find GOROOT' 1>&2
 	echo '$GOROOT:' "$GOROOT" 1>&2
 	echo 'go env GOROOT:' "$goroot" 1>&2
 	exit 1
diff --git a/misc/cgo/testgodefs/anonunion.go b/misc/cgo/testgodefs/anonunion.go
index 7bc736b..18840f2 100644
--- a/misc/cgo/testgodefs/anonunion.go
+++ b/misc/cgo/testgodefs/anonunion.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/testgodefs/issue8478.go b/misc/cgo/testgodefs/issue8478.go
index 92258fd..2321446 100644
--- a/misc/cgo/testgodefs/issue8478.go
+++ b/misc/cgo/testgodefs/issue8478.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/testgodefs/main.go b/misc/cgo/testgodefs/main.go
index 7faccf2..1ce0fd0 100644
--- a/misc/cgo/testgodefs/main.go
+++ b/misc/cgo/testgodefs/main.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/testsanitizers/msan.go b/misc/cgo/testsanitizers/msan.go
index ebfd5c3..7915fa8 100644
--- a/misc/cgo/testsanitizers/msan.go
+++ b/misc/cgo/testsanitizers/msan.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/testsanitizers/msan2.go b/misc/cgo/testsanitizers/msan2.go
index 42dcd20..6690cb0 100644
--- a/misc/cgo/testsanitizers/msan2.go
+++ b/misc/cgo/testsanitizers/msan2.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/testsanitizers/msan4.go b/misc/cgo/testsanitizers/msan4.go
index c75e1c3..6c91ff5 100644
--- a/misc/cgo/testsanitizers/msan4.go
+++ b/misc/cgo/testsanitizers/msan4.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/testsanitizers/msan_fail.go b/misc/cgo/testsanitizers/msan_fail.go
index 757e22c..4c8dab3 100644
--- a/misc/cgo/testsanitizers/msan_fail.go
+++ b/misc/cgo/testsanitizers/msan_fail.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/misc/cgo/testsanitizers/test.bash b/misc/cgo/testsanitizers/test.bash
index feacd89..78747d1 100755
--- a/misc/cgo/testsanitizers/test.bash
+++ b/misc/cgo/testsanitizers/test.bash
@@ -15,35 +15,41 @@ if test -x "$(type -p clang)"; then
 fi
 export CC
 
+msan=yes
+
 TMPDIR=${TMPDIR:-/tmp}
-echo > ${TMPDIR}/testsanitizers$$.c
+echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
 if $CC -fsanitize=memory -c ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$.o 2>&1 | grep "unrecognized" >& /dev/null; then
-  echo "skipping msan test: -fsanitize=memory not supported"
-  rm -f ${TMPDIR}/testsanitizers$$.*
-  exit 0
+  echo "skipping msan tests: -fsanitize=memory not supported"
+  msan=no
 fi
 rm -f ${TMPDIR}/testsanitizers$$.*
 
-# The memory sanitizer in versions of clang before 3.6 don't work with Go.
-if $CC --version | grep clang >& /dev/null; then
+tsan=yes
+
+# The memory and thread sanitizers in versions of clang before 3.6
+# don't work with Go.
+if test "$msan" = "yes" && $CC --version | grep clang >& /dev/null; then
   ver=$($CC --version | sed -e 's/.* version \([0-9.-]*\).*/\1/')
   major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
   minor=$(echo $ver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
   if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 6; then
-    echo "skipping msan test; clang version $major.$minor (older than 3.6)"
-    exit 0
+    echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.6)"
+    msan=no
+    tsan=no
   fi
 
   # Clang before 3.8 does not work with Linux at or after 4.1.
   # golang.org/issue/12898.
-  if test "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 8; then
+  if test "$msan" = "yes" -a "$major" -lt 3 || test "$major" -eq 3 -a "$minor" -lt 8; then
     if test "$(uname)" = Linux; then
       linuxver=$(uname -r)
       linuxmajor=$(echo $linuxver | sed -e 's/\([0-9]*\).*/\1/')
       linuxminor=$(echo $linuxver | sed -e 's/[0-9]*\.\([0-9]*\).*/\1/')
       if test "$linuxmajor" -gt 4 || test "$linuxmajor" -eq 4 -a "$linuxminor" -ge 1; then
-        echo "skipping msan test; clang version $major.$minor (older than 3.8) incompatible with linux version $linuxmajor.$linuxminor (4.1 or newer)"
-        exit 0
+        echo "skipping msan/tsan tests: clang version $major.$minor (older than 3.8) incompatible with linux version $linuxmajor.$linuxminor (4.1 or newer)"
+	msan=no
+	tsan=no
       fi
     fi
   fi
@@ -51,39 +57,106 @@ fi
 
 status=0
 
-if ! go build -msan std; then
-  echo "FAIL: build -msan std"
-  status=1
-fi
+if test "$msan" = "yes"; then
+    if ! go build -msan std; then
+	echo "FAIL: build -msan std"
+	status=1
+    fi
 
-if ! go run -msan msan.go; then
-  echo "FAIL: msan"
-  status=1
-fi
+    if ! go run -msan msan.go; then
+	echo "FAIL: msan"
+	status=1
+    fi
 
-if ! CGO_LDFLAGS="-fsanitize=memory" CGO_CPPFLAGS="-fsanitize=memory" go run -msan -a msan2.go; then
-  echo "FAIL: msan2 with -fsanitize=memory"
-  status=1
-fi
+    if ! CGO_LDFLAGS="-fsanitize=memory" CGO_CPPFLAGS="-fsanitize=memory" go run -msan -a msan2.go; then
+	echo "FAIL: msan2 with -fsanitize=memory"
+	status=1
+    fi
 
-if ! go run -msan -a msan2.go; then
-  echo "FAIL: msan2"
-  status=1
-fi
+    if ! go run -msan -a msan2.go; then
+	echo "FAIL: msan2"
+	status=1
+    fi
+
+    if ! go run -msan msan3.go; then
+	echo "FAIL: msan3"
+	status=1
+    fi
 
-if ! go run -msan msan3.go; then
-  echo "FAIL: msan3"
-  status=1
+    if ! go run -msan msan4.go; then
+	echo "FAIL: msan4"
+	status=1
+    fi
+
+    if go run -msan msan_fail.go 2>/dev/null; then
+	echo "FAIL: msan_fail"
+	status=1
+    fi
 fi
 
-if ! go run -msan msan4.go; then
-  echo "FAIL: msan4"
-  status=1
+if test "$tsan" = "yes"; then
+    echo 'int main() { return 0; }' > ${TMPDIR}/testsanitizers$$.c
+    ok=yes
+    if ! $CC -fsanitize=thread ${TMPDIR}/testsanitizers$$.c -o ${TMPDIR}/testsanitizers$$ &> ${TMPDIR}/testsanitizers$$.err; then
+	ok=no
+    fi
+     if grep "unrecognized" ${TMPDIR}/testsanitizers$$.err >& /dev/null; then
+	echo "skipping tsan tests: -fsanitize=thread not supported"
+	tsan=no
+     elif test "$ok" != "yes"; then
+	 cat ${TMPDIR}/testsanitizers$$.err
+	 echo "skipping tsan tests: -fsanitizer=thread build failed"
+	 tsan=no
+     fi
+     rm -f ${TMPDIR}/testsanitizers$$*
 fi
 
-if go run -msan msan_fail.go 2>/dev/null; then
-  echo "FAIL: msan_fail"
-  status=1
+# Run a TSAN test.
+# $1 test name
+# $2 environment variables
+# $3 go run args
+testtsan() {
+    err=${TMPDIR}/tsanerr$$.out
+    if ! env $2 go run $3 $1 2>$err; then
+	cat $err
+	echo "FAIL: $1"
+	status=1
+    elif grep -i warning $err >/dev/null 2>&1; then
+	cat $err
+	echo "FAIL: $1"
+	status=1
+    fi
+    rm -f $err
+}
+
+if test "$tsan" = "yes"; then
+    testtsan tsan.go
+    testtsan tsan2.go
+    testtsan tsan3.go
+    testtsan tsan4.go
+
+    # These tests are only reliable using clang or GCC version 7 or later.
+    # Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
+    ok=false
+    if ${CC} --version | grep clang >/dev/null 2>&1; then
+	ok=true
+    else
+	ver=$($CC -dumpversion)
+	major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
+	if test "$major" -lt 7; then
+	    echo "skipping remaining TSAN tests: GCC version $major (older than 7)"
+	else
+	    ok=true
+	fi
+    fi
+
+    if test "$ok" = "true"; then
+	# This test requires rebuilding os/user with -fsanitize=thread.
+	testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
+
+	# This test requires rebuilding runtime/cgo with -fsanitize=thread.
+	testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
+    fi
 fi
 
 exit $status
diff --git a/misc/cgo/testsanitizers/tsan.go b/misc/cgo/testsanitizers/tsan.go
new file mode 100644
index 0000000..6c377a7
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan.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.
+
+package main
+
+// This program produced false race reports when run under the C/C++
+// ThreadSanitizer, as it did not understand the synchronization in
+// the Go code.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+int val;
+
+int getVal() {
+	return val;
+}
+
+void setVal(int i) {
+	val = i;
+}
+*/
+import "C"
+
+import (
+	"runtime"
+)
+
+func main() {
+	runtime.LockOSThread()
+	C.setVal(1)
+	c := make(chan bool)
+	go func() {
+		runtime.LockOSThread()
+		C.setVal(2)
+		c <- true
+	}()
+	<-c
+	if v := C.getVal(); v != 2 {
+		panic(v)
+	}
+}
diff --git a/misc/cgo/testsanitizers/tsan2.go b/misc/cgo/testsanitizers/tsan2.go
new file mode 100644
index 0000000..5018a19
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan2.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.
+
+package main
+
+// This program produced false race reports when run under the C/C++
+// ThreadSanitizer, as it did not understand the synchronization in
+// the Go code.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+extern void GoRun(void);
+
+// Yes, you can have definitions if you use //export, as long as they are weak.
+
+int val __attribute__ ((weak));
+
+int run(void) __attribute__ ((weak));
+
+int run() {
+	val = 1;
+	GoRun();
+	return val;
+}
+
+void setVal(int) __attribute__ ((weak));
+
+void setVal(int i) {
+	val = i;
+}
+*/
+import "C"
+
+import "runtime"
+
+//export GoRun
+func GoRun() {
+	runtime.LockOSThread()
+	c := make(chan bool)
+	go func() {
+		runtime.LockOSThread()
+		C.setVal(2)
+		c <- true
+	}()
+	<-c
+}
+
+func main() {
+	if v := C.run(); v != 2 {
+		panic(v)
+	}
+}
diff --git a/misc/cgo/testsanitizers/tsan3.go b/misc/cgo/testsanitizers/tsan3.go
new file mode 100644
index 0000000..87f6c80
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan3.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go Authors. 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
+
+// The stubs for the C functions read and write the same slot on the
+// g0 stack when copying arguments in and out.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+int Func1() {
+	return 0;
+}
+
+void Func2(int x) {
+	(void)x;
+}
+*/
+import "C"
+
+func main() {
+	const N = 10000
+	done := make(chan bool, N)
+	for i := 0; i < N; i++ {
+		go func() {
+			C.Func1()
+			done <- true
+		}()
+		go func() {
+			C.Func2(0)
+			done <- true
+		}()
+	}
+	for i := 0; i < 2*N; i++ {
+		<-done
+	}
+}
diff --git a/misc/cgo/testsanitizers/tsan4.go b/misc/cgo/testsanitizers/tsan4.go
new file mode 100644
index 0000000..f0c76d8
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan4.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go Authors. 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
+
+// Check that calls to C.malloc/C.free do not trigger TSAN false
+// positive reports.
+
+// #cgo CFLAGS: -fsanitize=thread
+// #cgo LDFLAGS: -fsanitize=thread
+// #include <stdlib.h>
+import "C"
+
+import (
+	"runtime"
+	"sync"
+)
+
+func main() {
+	var wg sync.WaitGroup
+	for i := 0; i < 10; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			for i := 0; i < 100; i++ {
+				p := C.malloc(C.size_t(i * 10))
+				runtime.Gosched()
+				C.free(p)
+			}
+		}()
+	}
+	wg.Wait()
+}
diff --git a/misc/cgo/testsanitizers/tsan5.go b/misc/cgo/testsanitizers/tsan5.go
new file mode 100644
index 0000000..1214a77
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan5.go
@@ -0,0 +1,51 @@
+// Copyright 2016 The Go Authors. 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
+
+// Check that calls to C.malloc/C.free do not collide with the calls
+// made by the os/user package.
+
+// #cgo CFLAGS: -fsanitize=thread
+// #cgo LDFLAGS: -fsanitize=thread
+// #include <stdlib.h>
+import "C"
+
+import (
+	"fmt"
+	"os"
+	"os/user"
+	"runtime"
+	"sync"
+)
+
+func main() {
+	u, err := user.Current()
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		// Let the test pass.
+		os.Exit(0)
+	}
+
+	var wg sync.WaitGroup
+	for i := 0; i < 20; i++ {
+		wg.Add(2)
+		go func() {
+			defer wg.Done()
+			for i := 0; i < 1000; i++ {
+				user.Lookup(u.Username)
+				runtime.Gosched()
+			}
+		}()
+		go func() {
+			defer wg.Done()
+			for i := 0; i < 1000; i++ {
+				p := C.malloc(C.size_t(len(u.Username) + 1))
+				runtime.Gosched()
+				C.free(p)
+			}
+		}()
+	}
+	wg.Wait()
+}
diff --git a/misc/cgo/testsanitizers/tsan6.go b/misc/cgo/testsanitizers/tsan6.go
new file mode 100644
index 0000000..c96f08d
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan6.go
@@ -0,0 +1,49 @@
+// Copyright 2016 The Go Authors. 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
+
+// Check that writes to Go allocated memory, with Go synchronization,
+// do not look like a race.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+void f(char *p) {
+	*p = 1;
+}
+*/
+import "C"
+
+import (
+	"runtime"
+	"sync"
+)
+
+func main() {
+	var wg sync.WaitGroup
+	var mu sync.Mutex
+	c := make(chan []C.char, 100)
+	for i := 0; i < 10; i++ {
+		wg.Add(2)
+		go func() {
+			defer wg.Done()
+			for i := 0; i < 100; i++ {
+				c <- make([]C.char, 4096)
+				runtime.Gosched()
+			}
+		}()
+		go func() {
+			defer wg.Done()
+			for i := 0; i < 100; i++ {
+				p := &(<-c)[0]
+				mu.Lock()
+				C.f(p)
+				mu.Unlock()
+			}
+		}()
+	}
+	wg.Wait()
+}
diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
index 86fb530..34d97de 100644
--- a/misc/cgo/testshared/shared_test.go
+++ b/misc/cgo/testshared/shared_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -135,7 +135,7 @@ func testMain(m *testing.M) (int, error) {
 	goCmd(nil, append([]string{"install", "-buildmode=shared"}, minpkgs...)...)
 
 	myContext.InstallSuffix = suffix + "_dynlink"
-	depP, err := myContext.Import("dep", ".", build.ImportComment)
+	depP, err := myContext.Import("depBase", ".", build.ImportComment)
 	if err != nil {
 		return 0, fmt.Errorf("import failed: %v", err)
 	}
@@ -203,6 +203,26 @@ func TestNoTextrel(t *testing.T) {
 	}
 }
 
+// The shared library does not contain symbols called ".dup"
+func TestNoDupSymbols(t *testing.T) {
+	sopath := filepath.Join(gorootInstallDir, soname)
+	f, err := elf.Open(sopath)
+	if err != nil {
+		t.Fatal("elf.Open failed: ", err)
+	}
+	defer f.Close()
+	syms, err := f.Symbols()
+	if err != nil {
+		t.Errorf("error reading symbols %v", err)
+		return
+	}
+	for _, s := range syms {
+		if s.Name == ".dup" {
+			t.Fatalf("%s contains symbol called .dup", sopath)
+		}
+	}
+}
+
 // The install command should have created a "shlibname" file for the
 // listed packages (and runtime/cgo, and math on arm) indicating the
 // name of the shared library containing it.
@@ -309,21 +329,21 @@ func readNotes(f *elf.File) ([]*note, error) {
 	return notes, nil
 }
 
-func dynStrings(path string, flag elf.DynTag) []string {
+func dynStrings(t *testing.T, path string, flag elf.DynTag) []string {
 	f, err := elf.Open(path)
 	defer f.Close()
 	if err != nil {
-		log.Fatal("elf.Open failed: ", err)
+		t.Fatalf("elf.Open(%q) failed: %v", path, err)
 	}
 	dynstrings, err := f.DynString(flag)
 	if err != nil {
-		log.Fatal("dynstring failed: ", err)
+		t.Fatalf("DynString(%s) failed on %s: %v", flag, path, err)
 	}
 	return dynstrings
 }
 
 func AssertIsLinkedToRegexp(t *testing.T, path string, re *regexp.Regexp) {
-	for _, dynstring := range dynStrings(path, elf.DT_NEEDED) {
+	for _, dynstring := range dynStrings(t, path, elf.DT_NEEDED) {
 		if re.MatchString(dynstring) {
 			return
 		}
@@ -337,7 +357,7 @@ func AssertIsLinkedTo(t *testing.T, path, lib string) {
 
 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 _, dynstring := range dynStrings(t, path, tag) {
 			for _, rpath := range strings.Split(dynstring, ":") {
 				if filepath.Clean(rpath) == filepath.Clean(dir) {
 					return
@@ -396,11 +416,11 @@ func TestCgoPIE(t *testing.T) {
 // 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", "-buildmode=shared", "-linkshared", "depBase")
+	AssertIsLinkedTo(t, filepath.Join(gopathInstallDir, "libdepBase.so"), soname)
 	goCmd(t, "install", "-linkshared", "exe")
 	AssertIsLinkedTo(t, "./bin/exe", soname)
-	AssertIsLinkedTo(t, "./bin/exe", "libdep.so")
+	AssertIsLinkedTo(t, "./bin/exe", "libdepBase.so")
 	AssertHasRPath(t, "./bin/exe", gorootInstallDir)
 	AssertHasRPath(t, "./bin/exe", gopathInstallDir)
 	// And check it runs.
@@ -416,7 +436,7 @@ func testPkgListNote(t *testing.T, f *elf.File, note *note) {
 	if isOffsetLoaded(f, note.section.Offset) {
 		t.Errorf("package list section contained in PT_LOAD segment")
 	}
-	if note.desc != "dep\n" {
+	if note.desc != "depBase\n" {
 		t.Errorf("incorrect package list %q", note.desc)
 	}
 }
@@ -466,7 +486,7 @@ func testDepsNote(t *testing.T, f *elf.File, note *note) {
 	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.
+	// libdepBase.so just links against the lib containing the runtime.
 	if note.desc != soname {
 		t.Errorf("incorrect dependency list %q", note.desc)
 	}
@@ -474,8 +494,8 @@ func testDepsNote(t *testing.T, f *elf.File, note *note) {
 
 // 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"))
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
+	f, err := elf.Open(filepath.Join(gopathInstallDir, "libdepBase.so"))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -523,16 +543,24 @@ func TestNotes(t *testing.T) {
 	}
 }
 
-// Build a GOPATH package (dep) into a shared library that links against the goroot
+// Build a GOPATH package (depBase) 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", "depBase")
 	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep2")
 	goCmd(t, "install", "-linkshared", "exe2")
 	run(t, "executable linked to GOPATH library", "./bin/exe2")
 }
 
+func TestThreeGopathShlibs(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep2")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep3")
+	goCmd(t, "install", "-linkshared", "exe3")
+	run(t, "executable linked to GOPATH library", "./bin/exe3")
+}
+
 // If gccgo is not available or not new enough call t.Skip. Otherwise,
 // return a build.Context that is set up for gccgo.
 func prepGccgo(t *testing.T) build.Context {
@@ -566,16 +594,16 @@ func TestGoPathShlibGccgo(t *testing.T) {
 
 	libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
 
-	depP, err := gccgoContext.Import("dep", ".", build.ImportComment)
+	depP, err := gccgoContext.Import("depBase", ".", 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", "-buildmode=shared", "-linkshared", "depBase")
+	AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdepBase.so"), libgoRE)
 	goCmd(t, "install", "-compiler=gccgo", "-linkshared", "exe")
 	AssertIsLinkedToRegexp(t, "./bin/exe", libgoRE)
-	AssertIsLinkedTo(t, "./bin/exe", "libdep.so")
+	AssertIsLinkedTo(t, "./bin/exe", "libdepBase.so")
 	AssertHasRPath(t, "./bin/exe", gccgoInstallDir)
 	// And check it runs.
 	run(t, "gccgo-built", "./bin/exe")
@@ -589,21 +617,21 @@ func TestTwoGopathShlibsGccgo(t *testing.T) {
 
 	libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
 
-	depP, err := gccgoContext.Import("dep", ".", build.ImportComment)
+	depP, err := gccgoContext.Import("depBase", ".", 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", "depBase")
 	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, "libdepBase.so"), libgoRE)
 	AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdep2.so"), libgoRE)
-	AssertIsLinkedTo(t, filepath.Join(gccgoInstallDir, "libdep2.so"), "libdep.so")
+	AssertIsLinkedTo(t, filepath.Join(gccgoInstallDir, "libdep2.so"), "libdepBase.so")
 	AssertIsLinkedToRegexp(t, "./bin/exe2", libgoRE)
 	AssertIsLinkedTo(t, "./bin/exe2", "libdep2")
-	AssertIsLinkedTo(t, "./bin/exe2", "libdep.so")
+	AssertIsLinkedTo(t, "./bin/exe2", "libdepBase.so")
 
 	// And check it runs.
 	run(t, "gccgo-built", "./bin/exe2")
@@ -670,22 +698,22 @@ func AssertNotRebuilt(t *testing.T, msg, path string) {
 }
 
 func TestRebuilding(t *testing.T) {
-	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
 	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")
+	touch("src/depBase/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"))
+	AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "depBase.a"))
+	AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdepBase.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"))
+	touch(filepath.Join(gopathInstallDir, "depBase.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"))
+	AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "depBase.a"))
+	AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdepBase.so"))
 }
 
 func appendFile(path, content string) {
@@ -706,17 +734,17 @@ func appendFile(path, content string) {
 }
 
 func TestABIChecking(t *testing.T) {
-	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
 	goCmd(t, "install", "-linkshared", "exe")
 
-	// If we make an ABI-breaking change to dep and rebuild libp.so but not exe,
+	// If we make an ABI-breaking change to depBase 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
+	// some senses but suffices for the narrow definition of ABI compatibility the
 	// toolchain uses today.
 	resetFileStamps()
-	appendFile("src/dep/dep.go", "func ABIBreak() {}\n")
-	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	appendFile("src/depBase/dep.go", "func ABIBreak() {}\n")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
 	c := exec.Command("./bin/exe")
 	output, err := c.CombinedOutput()
 	if err == nil {
@@ -724,7 +752,7 @@ func TestABIChecking(t *testing.T) {
 	}
 	scanner := bufio.NewScanner(bytes.NewReader(output))
 	foundMsg := false
-	const wantLine = "abi mismatch detected between the executable and libdep.so"
+	const wantLine = "abi mismatch detected between the executable and libdepBase.so"
 	for scanner.Scan() {
 		if scanner.Text() == wantLine {
 			foundMsg = true
@@ -743,10 +771,10 @@ func TestABIChecking(t *testing.T) {
 	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.
+	// function) and rebuild libdepBase.so, exe still works.
 	resetFileStamps()
-	appendFile("src/dep/dep.go", "func noABIBreak() {}\n")
-	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	appendFile("src/depBase/dep.go", "func noABIBreak() {}\n")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "depBase")
 	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
deleted file mode 100644
index 8069ebb..0000000
--- a/misc/cgo/testshared/src/dep/asm.s
+++ /dev/null
@@ -1,10 +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 !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
deleted file mode 100644
index d3bed3f..0000000
--- a/misc/cgo/testshared/src/dep/dep.go
+++ /dev/null
@@ -1,13 +0,0 @@
-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
deleted file mode 100644
index 552ec30..0000000
--- a/misc/cgo/testshared/src/dep/gccgo.go
+++ /dev/null
@@ -1,5 +0,0 @@
-//+build gccgo
-
-package dep
-
-func ImplementedInAsm() {}
diff --git a/misc/cgo/testshared/src/dep/stubs.go b/misc/cgo/testshared/src/dep/stubs.go
deleted file mode 100644
index 036296a..0000000
--- a/misc/cgo/testshared/src/dep/stubs.go
+++ /dev/null
@@ -1,5 +0,0 @@
-//+build !gccgo
-
-package dep
-
-func ImplementedInAsm()
diff --git a/misc/cgo/testshared/src/dep2/dep2.go b/misc/cgo/testshared/src/dep2/dep2.go
index bac1086..c2c812a 100644
--- a/misc/cgo/testshared/src/dep2/dep2.go
+++ b/misc/cgo/testshared/src/dep2/dep2.go
@@ -1,11 +1,15 @@
 package dep2
 
-import "dep"
+import "depBase"
 
 var W int = 1
 
-var hasProg dep.HasProg
+var hasProg depBase.HasProg
+
+type Dep2 struct {
+	depBase.Dep
+}
 
 func G() int {
-	return dep.F() + 1
+	return depBase.F() + 1
 }
diff --git a/misc/cgo/testshared/src/dep3/dep3.go b/misc/cgo/testshared/src/dep3/dep3.go
new file mode 100644
index 0000000..7b7c9da
--- /dev/null
+++ b/misc/cgo/testshared/src/dep3/dep3.go
@@ -0,0 +1,22 @@
+package dep3
+
+// The point of this test file is that it references a type from
+// depBase that is also referenced in dep2, but dep2 is loaded by the
+// linker before depBase (because it is earlier in the import list).
+// There was a bug in the linker where it would not correctly read out
+// the type data in this case and later crash.
+
+import (
+	"dep2"
+	"depBase"
+)
+
+type Dep3 struct {
+	dep  depBase.Dep
+	dep2 dep2.Dep2
+}
+
+func D3() int {
+	var x Dep3
+	return x.dep.X + x.dep2.X
+}
diff --git a/misc/cgo/testshared/src/depBase/asm.s b/misc/cgo/testshared/src/depBase/asm.s
new file mode 100644
index 0000000..f203f8b
--- /dev/null
+++ b/misc/cgo/testshared/src/depBase/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/depBase/dep.go b/misc/cgo/testshared/src/depBase/dep.go
new file mode 100644
index 0000000..c3ae96f
--- /dev/null
+++ b/misc/cgo/testshared/src/depBase/dep.go
@@ -0,0 +1,22 @@
+package depBase
+
+var V int = 1
+
+var HasMask []string = []string{"hi"}
+
+type HasProg struct {
+	array [1024]*byte
+}
+
+type Dep struct {
+	X int
+}
+
+func (d *Dep) Method() int {
+	return 10
+}
+
+func F() int {
+	defer func() {}()
+	return V
+}
diff --git a/misc/cgo/testshared/src/depBase/gccgo.go b/misc/cgo/testshared/src/depBase/gccgo.go
new file mode 100644
index 0000000..3e2b69b
--- /dev/null
+++ b/misc/cgo/testshared/src/depBase/gccgo.go
@@ -0,0 +1,5 @@
+//+build gccgo
+
+package depBase
+
+func ImplementedInAsm() {}
diff --git a/misc/cgo/testshared/src/depBase/stubs.go b/misc/cgo/testshared/src/depBase/stubs.go
new file mode 100644
index 0000000..96573c1
--- /dev/null
+++ b/misc/cgo/testshared/src/depBase/stubs.go
@@ -0,0 +1,5 @@
+//+build !gccgo
+
+package depBase
+
+func ImplementedInAsm()
diff --git a/misc/cgo/testshared/src/exe/exe.go b/misc/cgo/testshared/src/exe/exe.go
index f644776..136803f 100644
--- a/misc/cgo/testshared/src/exe/exe.go
+++ b/misc/cgo/testshared/src/exe/exe.go
@@ -1,12 +1,12 @@
 package main
 
 import (
-	"dep"
+	"depBase"
 	"runtime"
 )
 
 func main() {
-	defer dep.ImplementedInAsm()
+	defer depBase.ImplementedInAsm()
 	runtime.GC()
-	dep.V = dep.F() + 1
+	depBase.V = depBase.F() + 1
 }
diff --git a/misc/cgo/testshared/src/exe2/exe2.go b/misc/cgo/testshared/src/exe2/exe2.go
index acdb4dd..675fd1f 100644
--- a/misc/cgo/testshared/src/exe2/exe2.go
+++ b/misc/cgo/testshared/src/exe2/exe2.go
@@ -3,5 +3,6 @@ package main
 import "dep2"
 
 func main() {
-	dep2.W = dep2.G() + 1
+	d := &dep2.Dep2{}
+	dep2.W = dep2.G() + 1 + d.Method()
 }
diff --git a/misc/cgo/testshared/src/exe3/exe3.go b/misc/cgo/testshared/src/exe3/exe3.go
new file mode 100644
index 0000000..643f260
--- /dev/null
+++ b/misc/cgo/testshared/src/exe3/exe3.go
@@ -0,0 +1,7 @@
+package main
+
+import "dep3"
+
+func main() {
+	dep3.D3()
+}
diff --git a/misc/cgo/testtls/tls.go b/misc/cgo/testtls/tls.go
index 8e9ee70..e634220 100644
--- a/misc/cgo/testtls/tls.go
+++ b/misc/cgo/testtls/tls.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/testtls/tls_unix.c b/misc/cgo/testtls/tls_unix.c
index 5459516..957afce 100644
--- a/misc/cgo/testtls/tls_unix.c
+++ b/misc/cgo/testtls/tls_unix.c
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/git/pre-commit b/misc/git/pre-commit
index 18b7f83..242159f 100755
--- a/misc/git/pre-commit
+++ b/misc/git/pre-commit
@@ -10,7 +10,7 @@
 #
 # This script does not handle file names that contain spaces.
 
-gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
+gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '\.go$')
 [ -z "$gofiles" ] && exit 0
 
 unformatted=$(gofmt -l $gofiles)
diff --git a/misc/ios/go_darwin_arm_exec.go b/misc/ios/go_darwin_arm_exec.go
index 828efe9..1eeb289 100644
--- a/misc/ios/go_darwin_arm_exec.go
+++ b/misc/ios/go_darwin_arm_exec.go
@@ -34,6 +34,7 @@ import (
 	"runtime"
 	"strings"
 	"sync"
+	"syscall"
 	"time"
 )
 
@@ -49,6 +50,11 @@ var (
 	teamID string
 )
 
+// lock is a file lock to serialize iOS runs. It is global to avoid the
+// garbage collector finalizing it, closing the file and releasing the
+// lock prematurely.
+var lock *os.File
+
 func main() {
 	log.SetFlags(0)
 	log.SetPrefix("go_darwin_arm_exec: ")
@@ -76,6 +82,20 @@ func main() {
 		log.Fatal(err)
 	}
 
+	// This wrapper uses complicated machinery to run iOS binaries. It
+	// works, but only when running one binary at a time.
+	// Use a file lock to make sure only one wrapper is running at a time.
+	//
+	// The lock file is never deleted, to avoid concurrent locks on distinct
+	// files with the same path.
+	lockName := filepath.Join(os.TempDir(), "go_darwin_arm_exec.lock")
+	lock, err = os.OpenFile(lockName, os.O_CREATE|os.O_RDONLY, 0666)
+	if err != nil {
+		log.Fatal(err)
+	}
+	if err := syscall.Flock(int(lock.Fd()), syscall.LOCK_EX); 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
@@ -160,10 +180,18 @@ func run(bin string, args []string) (err error) {
 	}
 	defer os.Chdir(oldwd)
 
+	// Setting up lldb is flaky. The test binary itself runs when
+	// started is set to true. Everything before that is considered
+	// part of the setup and is retried.
+	started := false
 	defer func() {
 		if r := recover(); r != nil {
 			if w, ok := r.(waitPanic); ok {
 				err = w.err
+				if !started {
+					fmt.Printf("lldb setup error: %v\n", err)
+					err = errRetry
+				}
 				return
 			}
 			panic(r)
@@ -196,6 +224,7 @@ func run(bin string, args []string) (err error) {
 	s.do(`process handle SIGHUP  --stop false --pass true --notify false`)
 	s.do(`process handle SIGPIPE --stop false --pass true --notify false`)
 	s.do(`process handle SIGUSR1 --stop false --pass true --notify false`)
+	s.do(`process handle SIGCONT --stop false --pass true --notify false`)
 	s.do(`process handle SIGSEGV --stop false --pass true --notify false`) // does not work
 	s.do(`process handle SIGBUS  --stop false --pass true --notify false`) // does not work
 
@@ -209,6 +238,8 @@ func run(bin string, args []string) (err error) {
 
 	s.do(`breakpoint set -n getwd`) // in runtime/cgo/gcc_darwin_arm.go
 
+	started = true
+
 	s.doCmd("run", "stop reason = breakpoint", 20*time.Second)
 
 	// Move the current working directory into the faux gopath.
@@ -260,6 +291,10 @@ func newSession(appdir string, args []string, opts options) (*lldbSession, error
 		exited: make(chan error),
 	}
 
+	iosdPath, err := exec.LookPath("ios-deploy")
+	if err != nil {
+		return nil, err
+	}
 	s.cmd = exec.Command(
 		// lldb tries to be clever with terminals.
 		// So we wrap it in script(1) and be clever
@@ -268,7 +303,7 @@ func newSession(appdir string, args []string, opts options) (*lldbSession, error
 		"-q", "-t", "0",
 		"/dev/null",
 
-		"ios-deploy",
+		iosdPath,
 		"--debug",
 		"-u",
 		"-r",
@@ -312,9 +347,8 @@ func newSession(appdir string, args []string, opts options) (*lldbSession, error
 		i2 := s.out.LastIndex([]byte(" connect"))
 		return i0 > 0 && i1 > 0 && i2 > 0
 	}
-	if err := s.wait("lldb start", cond, 5*time.Second); err != nil {
-		fmt.Printf("lldb start error: %v\n", err)
-		return nil, errRetry
+	if err := s.wait("lldb start", cond, 10*time.Second); err != nil {
+		panic(waitPanic{err})
 	}
 	return s, nil
 }
@@ -334,7 +368,7 @@ func (s *lldbSession) doCmd(cmd string, waitFor string, extraTimeout time.Durati
 }
 
 func (s *lldbSession) wait(reason string, cond func(out *buf) bool, extraTimeout time.Duration) error {
-	doTimeout := 1*time.Second + extraTimeout
+	doTimeout := 2*time.Second + extraTimeout
 	doTimedout := time.After(doTimeout)
 	for {
 		select {
diff --git a/misc/nacl/mkzip.go b/misc/nacl/mkzip.go
index aaf37f1..5ec241e 100644
--- a/misc/nacl/mkzip.go
+++ b/misc/nacl/mkzip.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/nacl/testzip.proto b/misc/nacl/testzip.proto
index 4e82ac9..8a8784c 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -27,23 +27,23 @@ go	src=..
 			internal
 				objfile
 					objfile.go
-				unvendor
-					golang.org
-							x
-								arch
-									arm
-										armasm
-											testdata
-													+
-									x86
-										x86asm
-											testdata
-													+
 			gofmt
 				gofmt.go
 				gofmt_test.go
 				testdata
 					+
+			vendor
+				golang.org
+					x
+						arch
+							arm
+								armasm
+									testdata
+										+
+							x86
+								x86asm
+									testdata
+										+
 		archive
 			tar
 				testdata
@@ -56,6 +56,8 @@ go	src=..
 				testdata
 					+
 			flate
+				testdata
+					+
 			gzip
 				testdata
 					+
@@ -107,6 +109,10 @@ go	src=..
 			png
 				testdata
 					+
+		internal
+			trace
+				testdata
+					+
 		io
 			+
 		mime
diff --git a/misc/swig/callback/callback.cc b/misc/swig/callback/callback.cc
index eac24fb..88bd49c 100644
--- a/misc/swig/callback/callback.cc
+++ b/misc/swig/callback/callback.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/swig/callback/callback.go b/misc/swig/callback/callback.go
index 39c1719..0d6e97f 100644
--- a/misc/swig/callback/callback.go
+++ b/misc/swig/callback/callback.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/swig/callback/callback.h b/misc/swig/callback/callback.h
index 97bf73c..4b66106 100644
--- a/misc/swig/callback/callback.h
+++ b/misc/swig/callback/callback.h
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/misc/swig/callback/callback.swigcxx b/misc/swig/callback/callback.swigcxx
index 0c97ef1..6181fe9 100644
--- a/misc/swig/callback/callback.swigcxx
+++ b/misc/swig/callback/callback.swigcxx
@@ -1,4 +1,4 @@
-/* Copyright 2011 The Go Authors.  All rights reserved.
+/* 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/misc/swig/callback/callback_test.go b/misc/swig/callback/callback_test.go
index dbbbab5..0c8a300 100644
--- a/misc/swig/callback/callback_test.go
+++ b/misc/swig/callback/callback_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/swig/stdio/file.swig b/misc/swig/stdio/file.swig
index 8ba341d..b28ae0a 100644
--- a/misc/swig/stdio/file.swig
+++ b/misc/swig/stdio/file.swig
@@ -1,4 +1,4 @@
-/* Copyright 2011 The Go Authors.  All rights reserved.
+/* 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/misc/swig/stdio/file_test.go b/misc/swig/stdio/file_test.go
index 38d0746..b1a520e 100644
--- a/misc/swig/stdio/file_test.go
+++ b/misc/swig/stdio/file_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/misc/trace/README.md b/misc/trace/README.md
index 8561c79..2e8bb05 100644
--- a/misc/trace/README.md
+++ b/misc/trace/README.md
@@ -1,12 +1,16 @@
 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:
+[instructions](https://github.com/catapult-project/catapult/blob/master/tracing/docs/embedding-trace-viewer.md)
+on revision `623a005a3ffa9de13c4b92bc72290e7bcd1ca591`
+of [catapult](https://github.com/catapult-project/catapult) using:
 ```
-trace-viewer$ ./vulcanize_trace_viewer --config=lean
-trace-viewer$ cp bin/trace_viewer_lean.html $GOROOT/misc/trace/
+catapult$ ./tracing/bin/vulcanize_trace_viewer --config=full
+catapult$ cp tracing/bin/trace_viewer_full.html $GOROOT/misc/trace/trace_viewer_lean.html
 ```
+We are supposed to use --config=lean (produces smaller html),
+but it is broken at the moment:
+https://github.com/catapult-project/catapult/issues/2247
 
 The license for trace-viewer is as follows:
 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
diff --git a/misc/trace/trace_viewer_lean.html b/misc/trace/trace_viewer_lean.html
index 5d40bc5..7939aae 100644
--- a/misc/trace/trace_viewer_lean.html
+++ b/misc/trace/trace_viewer_lean.html
@@ -1,113 +1,9 @@
-<!DOCTYPE HTML>
+<!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>
+  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+<template id="overlay-template">
+  <style>
     overlay-mask {
       left: 0;
       padding: 8px;
@@ -189,50 +85,43 @@
       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>
+
+  <overlay-mask>
+    <overlay-vertical-centering-container>
+      <overlay-frame>
+        <title-bar>
+          <title></title>
+          <close-button>✕</close-button>
+        </title-bar>
+        <overlay-content>
+          <content></content>
+        </overlay-content>
+        <button-bar></button-bar>
+      </overlay-frame>
+    </overlay-vertical-centering-container>
+  </overlay-mask>
+</template><style>
+* /deep/ .labeled-checkbox {
+  display: flex;
+  white-space: nowrap;
+}
+</style><polymer-element is="a" name="tr-ui-a-analysis-link" on-click="{{onClicked_}}" on-mouseenter="{{onMouseEnter_}}" on-mouseleave="{{onMouseLeave_}}">
+  <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>
+    <content></content>
+  </template>
+  
+</polymer-element><polymer-element name="tr-ui-b-table">
+  <template>
+    <style>
       :host {
         display: flex;
         flex-direction: column;
@@ -298,34 +187,31 @@
         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 {
+      /* Light row and cell highlight. */
+      table > tbody[row-highlight-style="light"] > tr[selected],
+      table > tbody[cell-highlight-style="light"] > tr > td[selected] {
         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) {
+      table > tbody[row-highlight-style="light"] >
+          tr:not(.empty-row):not([selected]):hover,
+      table > tbody[cell-highlight-style="light"] >
+          tr:not(.empty-row):not([selected]) > td:hover {
         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 {
+      /* Dark row and cell highlight. */
+      table > tbody[row-highlight-style="dark"] > tr[selected],
+      table > tbody[cell-highlight-style="dark"] > tr > td[selected] {
+        background-color: rgb(103, 199, 165);  /* turquoise */
+      }
+      table > tbody[row-highlight-style="dark"] >
+          tr:not(.empty-row):not([selected]):hover,
+      table > tbody[cell-highlight-style="dark"] >
+          tr:not(.empty-row):not([selected]) > td:hover {
+        background-color: #e6e6e6;  /* grey */
+      }
+      table > tbody[row-highlight-style="dark"] > tr:hover[selected],
+      table > tbody[cell-highlight-style="dark"] > tr[selected] > td:hover {
         background-color: rgb(171, 217, 202);  /* semi-light turquoise */
       }
 
@@ -356,20 +242,19 @@
         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>
+    <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;
@@ -390,80 +275,567 @@
       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>
+    <span id="title"></span><side-element id="side"></side-element>
+  </template>
+
+  
+</polymer-element><polymer-element name="tr-v-ui-scalar-span">
+  <template>
+    <style>
     :host {
-      display: flex;
-      flex-direction: row;
-      align-items: center;
+      display: block;
+      position: relative;
+    }
+    #content.right-align {
+      text-align: right;
+      position: relative;
+      display: block;
+    }
+    #sparkline {
+      width: 0%;
+      position: absolute;
+      bottom: 0;
+      right: 0;
+      display: none;
+      height: 100%;
+      background-color: hsla(216, 100%, 94.5%, .75);
+      border-left: 1px solid hsl(216, 100%, 89%);
+      box-sizing: border-box;
     }
     #warning {
       margin-left: 4px;
       font-size: 66%;
     }
     </style>
-<span id="content"></span>
-<span id="warning" style="display:none">⚠</span>
-</template>
+    <span id="sparkline"></span>
+    <span id="content"></span>
+    <span id="warning" style="display:none">⚠</span>
+  </template>
+  
+</polymer-element><polymer-element is="HTMLUnknownElement" name="tr-ui-a-generic-object-view">
+  <template>
+    <style>
+    :host {
+      display: block;
+      font-family: monospace;
+    }
+    </style>
+    <div id="content">
+    </div>
+  </template>
+
+  
+</polymer-element><polymer-element is="HTMLUnknownElement" name="tr-ui-a-generic-object-view-with-label">
+  <template>
+    <style>
+    :host {
+      display: block;
+    }
+    </style>
+  </template>
+
+  
+</polymer-element><polymer-element name="tr-ui-b-drag-handle">
+  <template>
+    <style>
+    :host {
+      -webkit-user-select: none;
+      box-sizing: border-box;
+      display: block;
+    }
 
-</polymer-element><polymer-element name="tr-ui-u-time-stamp-span">
-<template>
-</template>
+    :host(.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;
+      flex: 0 0 auto;
+      height: 7px;
+      position: relative;
+      z-index: 10;
+    }
 
-</polymer-element><polymer-element name="tr-ui-u-size-in-bytes-span">
-<template>
-<style>
+    :host(.vertical-drag-handle) {
+      background-image: -webkit-gradient(linear,
+                                         0 0, 100% 0,
+                                         from(#E5E5E5),
+                                         to(#D1D1D1));
+      border-left: 1px solid white;
+      border-right: 1px solid #8e8e8e;
+      cursor: ew-resize;
+      flex: 0 0 auto;
+      position: relative;
+      width: 7px;
+      z-index: 10;
+    }
+    </style>
+  </template>
+  
+</polymer-element><polymer-element name="tv-ui-b-hotkey-controller">
+  
+</polymer-element><polymer-element is="HTMLDivElement" name="tr-ui-b-info-bar">
+  <template>
+    <style>
     :host {
-      display: flex;
-      flex-direction: row;
       align-items: center;
+      flex: 0 0 auto;
+      background-color: rgb(252, 235, 162);
+      border-bottom: 1px solid #A3A3A3;
+      border-left: 1px solid white;
+      border-right: 1px solid #A3A3A3;
+      border-top: 1px solid white;
+      display: flex;
+      height: 26px;
+      padding: 0 3px 0 3px;
     }
+
+    :host(.info-bar-hidden) {
+      display: none;
+    }
+
+    #message { flex: 1 1 auto; }
     </style>
-<span id="content"></span>
-</template>
 
-</polymer-element><polymer-element name="tr-ui-a-generic-object-view" is="HTMLUnknownElement">
-<template>
-<style>
+    <span id="message"></span>
+    <span id="buttons"></span>
+  </template>
+
+  
+</polymer-element><style>
+* /deep/ .x-list-view{-webkit-user-select:none;display:block}* /deep/ .x-list-view:focus{outline:none}* /deep/ .x-list-view *{-webkit-user-select:none}* /deep/ .x-list-view>.list-item{padding:2px 4px 2px 4px}* /deep/ .x-list-view:focus>.list-item[selected]{background-color:rgb(171,217,202);outline:1px dotted rgba(0,0,0,0.1);outline-offset:0}* /deep/ .x-list-view>.list-item[selected]{background-color:rgb(103,199,165)}
+</style><polymer-element name="tr-ui-b-mouse-mode-icon">
+  <template>
+    <style>
     :host {
       display: block;
-      font-family: monospace;
+      background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAChCAYAAACbBNzvAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABV0RVh0Q3JlYXRpb24gVGltZQA3LzE2LzEzRNEKUwAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAA9aSURBVHic7V1rTFvl//+UrgUmZWMpbLa6cLErwpYxkqLGkjAG88WSbmumGUllvlmAJctMRtybvlHrLXiJUekMIZuYSCL5gS+EuLIXGEGjqCsllCEW6xQECgzWG7S05/+C/zkp9LTn0gsL6ych9JzznOdzPj19Luf5PN/nCN59913ixRdfRFdXFxLx/2GDgCAIYmpqCoWFhUjE/4cNae+99x4AIFH/Hzak7nDqDu+wOyyw2WzEdl9EMp [...]
+      width: 27px;
+      height: 30px;
+    }
+    :host.active {
+      cursor: auto;
     }
     </style>
-<div id="content">
-</div>
-</template>
-
-</polymer-element>
-<polymer-element name="tr-ui-a-generic-object-view-with-label" is="HTMLUnknownElement">
-<template>
-<style>
+  </template>
+  
+</polymer-element><polymer-element name="tr-ui-b-mouse-mode-selector">
+  <template>
+    <style>
     :host {
+
+      -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;
+    }
+
+    .drag-handle {
+      background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAChCAYAAACbBNzvAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABV0RVh0Q3JlYXRpb24gVGltZQA3LzE2LzEzRNEKUwAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAA9aSURBVHic7V1rTFvl//+UrgUmZWMpbLa6cLErwpYxkqLGkjAG88WSbmumGUllvlmAJctMRtybvlHrLXiJUekMIZuYSCL5gS+EuLIXGEGjqCsllCEW6xQECgzWG7S05/+C/zkp9LTn0gsL6ych9JzznOdzPj19Luf5PN/nCN59913ixRdfRFdXFxLx/2GDgCAIYmpqCoWFhUjE/4cNae+99x4AIFH/Hzak7nDqDu+wOyyw2WzEdl9EMpG23ReQ [...]
+      background-repeat: no-repeat;
+      border-bottom: 1px solid #BCBCBC;
+      cursor: move;
       display: block;
+      height: 13px;
+      width: 27px;
+    }
+
+    .tool-button {
+      background-position: center center;
+      background-repeat: no-repeat;
+      border-bottom: 1px solid #BCBCBC;
+      border-top: 1px solid #F1F1F1;
+      cursor: pointer;
+    }
+
+    .buttons > .tool-button:last-child {
+      border-bottom: none;
     }
+
+    </style>
+    <div class="drag-handle"></div>
+    <div class="buttons">
+    </div>
+  </template>
+</polymer-element><polymer-element name="tr-ui-e-chrome-cc-display-item-list-item">
+  <template>
+    <style>
+      :host {
+        border-bottom: 1px solid #555;
+        display: block;
+        font-size: 12px;
+        padding: 3px 5px;
+      }
+
+      :host(:hover) {
+        background-color: #f0f0f0;
+        cursor: pointer;
+      }
+
+      .header {
+        font-weight: bold;
+        margin: 2px 0;
+      }
+
+      .header > .extra {
+        background-color: #777;
+        border-radius: 4px;
+        color: white;
+        margin: 0 6px;
+        text-decoration: none;
+        padding: 2px 4px;
+      }
+
+      .raw-details {
+        white-space: pre-wrap;
+      }
+
+      .details > dl {
+        margin: 0;
+      }
+
+      :host(:not([selected])) .details {
+        display: none;
+      }
     </style>
-</template>
+    <div class="header">
+      {{name}}
+      <template if="{{richDetails && richDetails.skp64}}">
+        <a class="extra" download="drawing.skp" href="data:application/octet-stream;base64,{{richDetails.skp64}}" on-click="{{stopPropagation}}">SKP</a>
+      </template>
+    </div>
+    <div class="details">
+      <template if="{{rawDetails}}">
+        <div class="raw-details">{{rawDetails}}</div>
+      </template>
+      <template bind="{{richDetails}}" if="{{richDetails}}">
+        <dl>
+          <template bind="{{cullRect}}" if="{{cullRect}}">
+            <dt>Cull rect</dt>
+            <dd>{{x}},{{y}} {{width}}×{{height}}</dd>
+          </template>
+          <template bind="{{visualRect}}" if="{{visualRect}}">
+            <dt>Visual rect</dt>
+            <dd>{{x}},{{y}} {{width}}×{{height}}</dd>
+          </template>
+        </dl>
+      </template>
+    </div>
+  </template>
+  
+</polymer-element><style>
+* * /deep/ tr-ui-e-chrome-cc-picture-ops-list-view{-webkit-flex-direction:column;border-top:1px solid grey;display:-webkit-flex}* /deep/ tr-ui-e-chrome-cc-picture-ops-list-view>.x-list-view{-webkit-flex:1 1 auto;overflow:auto}* /deep/ tr-ui-e-chrome-cc-picture-ops-list-view>.x-list-view .list-item{border-bottom:1px solid #555;font-size:small;font-weight:bold;padding-bottom:5px;padding-left:5px}* /deep/ tr-ui-e-chrome-cc-picture-ops-list-view>.x-list-view .list-item:hover{background-color [...]
+</style><template id="tr-ui-e-chrome-cc-display-item-debugger-template">
+  <style>
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger {
+    -webkit-flex: 1 1 auto;
+    display: -webkit-flex;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > left-panel {
+    -webkit-flex-direction: column;
+    display: -webkit-flex;
+    min-width: 300px;
+    overflow-y: auto;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > left-panel >
+        display-item-info {
+    -webkit-flex: 1 1 auto;
+    padding-top: 2px;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > left-panel >
+        display-item-info .title {
+    font-weight: bold;
+    margin-left: 5px;
+    margin-right: 5px;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > left-panel >
+        display-item-info .export {
+    margin: 5px;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > tr-ui-b-drag-handle {
+    -webkit-flex: 0 0 auto;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > right-panel {
+    -webkit-flex: 1 1 auto;
+    display: -webkit-flex;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > left-panel >
+      display-item-info > header {
+    border-bottom: 1px solid #555;
+  }
+
+  /*************************************************/
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > right-panel >
+      tr-ui-e-chrome-cc-picture-ops-list-view.hasPictureOps {
+    display: block;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > right-panel >
+        tr-ui-b-drag-handle.hasPictureOps {
+    display: block;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > right-panel >
+        tr-ui-e-chrome-cc-picture-ops-list-view {
+    display: none;
+    overflow-y: auto;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger > right-panel >
+        tr-ui-b-drag-handle {
+    display: none;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-display-item-debugger raster-area {
+    -webkit-flex: 1 1 auto;
+    background-color: #ddd;
+    min-height: 200px;
+    min-width: 200px;
+    overflow-y: auto;
+    padding-left: 5px;
+  }
+  </style>
+
+  <left-panel>
+    <display-item-info>
+      <header>
+        <span class="title">Display Item List</span>
+        <span class="size"></span>
+        <div class="export">
+          <input class="dlfilename" type="text" value="displayitemlist.json"/>
+          <button class="dlexport">Export display item list</button>
+        </div>
+        <div class="export">
+          <input class="skpfilename" type="text" value="skpicture.skp"/>
+          <button class="skpexport">Export list as SkPicture</button>
+        </div>
+      </header>
+    </display-item-info>
+  </left-panel>
+  <right-panel>
+    <raster-area><canvas></canvas></raster-area>
+  </right-panel>
+</template><style>
+* /deep/ .tr-ui-e-chrome-cc-display-item-list-view{-webkit-flex:1 1 auto!important;display:-webkit-flex}
+</style><style>
+* /deep/ tr-ui-e-chrome-cc-layer-picker{-webkit-flex-direction:column;display:-webkit-flex}* /deep/ tr-ui-e-chrome-cc-layer-picker>top-controls{-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;display:inline;font-size:14px;padding-left:2px}* /deep/ tr-ui-e-chrome-cc-layer-picker>top-controls input[type='checkbox']{vertical-align:-2px}* /deep/ tr-ui-e-chrome-cc-layer-picker>.x-li [...]
+</style><style>
+* /deep/ quad-stack-view {
+  display: block;
+  float: left;
+  height: 100%;
+  overflow: hidden;
+  position: relative; /* For the absolute positioned mouse-mode-selector */
+  width: 100%;
+}
+
+* /deep/ quad-stack-view > #header {
+  position: absolute;
+  font-size: 70%;
+  top: 10px;
+  left: 10px;
+  width: 800px;
+}
+* /deep/ quad-stack-view > #stacking-distance-slider {
+  position: absolute;
+  font-size: 70%;
+  top: 10px;
+  right: 10px;
+}
 
+* /deep/ quad-stack-view > #chrome-left {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMcAAABICAYAAABC4+HLAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAB3RJTUUH3QcNFyMmV/Pm9QAAIABJREFUeNrtvXmwXdd13vlbe9/7BgzEQAIcQAIEQYKjSAokLVlOW5Fk2nLKmqx0J2Wp0k652h13uiy5XYqdwU7sSnckpZ1yV3U75apU4kos27Elu9NlyRXZjiiRomSTIiWZs0hwHsABJIY33rPX6j/W2ueed3DvAyDKKoGFW0UCeO/ec/fZZ+29v7XWt74lAIuLi7tXV1f/raq+zcy2AogIZsbpvrqfMzNE5IS/1/fVn5sZKaUTrtX9/v7nT+fn9e/1e052X/3r1THWa3R/37+miKCq7c+mjW/a+F/P57vj6/45bayn+wzXs4n+794Q9n [...]
+  display: none;
+}
+
+* /deep/ quad-stack-view > #chrome-mid {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAABICAYAAADRa1RpAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAB3RJTUUH3QcNFycE5v9iFQAAAQtJREFUOMvtkjGSWzEMQx/0eYrM3v8k3vgqycalSwlI8Ufyl3OBFMtGIgUCIEd6PB6RBEASqvfONSrJXrDNbNkQ8ywA2y/SmayW+ZIESTsiyQsxo40xmMS2aUmYbheHpCVd0+UqJGGMsey3mUyldoUvlY3D9rIN0K7Wbe/WbZ+y1yWtaVtrp3VJzAEX6ZVjc2p7b2mtnYhNdl6m05rwtfV/ltx7XypJTpXeO7Y5juOlchzHaWxyrJmuhLapqgIJONv05+srThBgiQpBTSRwGOr3rwccgWHUhJ7P5/YNlbd/2XiL78L/WajP240AQUihfn [...]
+  display: none;
+}
+
+* /deep/ quad-stack-view > #chrome-right {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAABICAYAAACaw4eEAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAB3RJTUUH3QcNFyghKmOqnQAADE1JREFUaN6dmsuyZsdRhb/M2uf07bREYDykPeIleAMibNx92i9BgEPBgyB5xlvgtgI8VDNBI41xhGkpQowERgqw3H0ue1cuBlm1T/3Vu4XNiWj9l12XrMyVK1fWL/v6668lCXdHEt/1Z2YnnyUhCTPbX8dn45pmRkR81z7/XUr59Pz8/K8ePnz47/bVV19pnDhu0t+Pmx0Z+Pv8zWv1/eZnZ2dntw8ePPizZXw4bj5/P3vq6G/eePZiX9fd9/Xng6/reg78/dInzxPG9+/auH83GjEbPUahj6m1Hoa6v1/X9c+XPrlP7INqrfuru7+10W [...]
+  display: none;
+}
+</style><template id="quad-stack-view-template">
+  <div id="header"></div>
+  <input id="stacking-distance-slider" max="400" min="1" step="1" type="range"/>
+  
+  <canvas id="canvas"></canvas>
+  <img id="chrome-left"/>
+  <img id="chrome-mid"/>
+  <img id="chrome-right"/>
+</template><style>
+* /deep/ tr-ui-e-chrome-cc-layer-tree-quad-stack-view {
+  position: relative;
+}
+
+* /deep/ tr-ui-e-chrome-cc-layer-tree-quad-stack-view > top-controls {
+  -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;
+  display: flex;
+  flex-flow: row wrap;
+  flex-direction: row;
+  font-size:  14px;
+  padding-left: 2px;
+  overflow: hidden;
+}
+
+* /deep/ tr-ui-e-chrome-cc-layer-tree-quad-stack-view >
+      top-controls input[type='checkbox'] {
+  vertical-align: -2px;
+}
+
+* /deep/ tr-ui-e-chrome-cc-layer-tree-quad-stack-view > .what-rasterized {
+  color: -webkit-link;
+  cursor: pointer;
+  text-decoration: underline;
+  position: absolute;
+  bottom: 10px;
+  left: 10px;
+}
+
+* /deep/ tr-ui-e-chrome-cc-layer-tree-quad-stack-view > #input-event {
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAMnwAADJ8BPja39wAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAyNSURBVHic7Z1PTCPXHcc/4wWWVbJN2cJSLVqiQJuGpoIGEVWReoBNIlIF5RCRSysOK9EbksUeOHLIIQcULbLEEYk7oqduD6gSRoqUEyK7dCOabOHghCiAE/JntQtesHt4fuM3z2+MZzy2x8ZfaTTjN+Px4/fh9/7Pb6xMJkND4VGk2hloyKkGkJCpASRkagAJmRpAQqYGkJCpASRkaqp2BvzKsizf3w1z38sKc+ZUaQCuAFeB57P7q4AF/Kxsj4GnLrfL+6PDYofQAskCaAJ6gJeB6+QAFOvZpwgwPwOHwC [...]
+  display: none;
+}
+</style><template id="tr-ui-e-chrome-cc-layer-tree-quad-stack-view-template">
+  <img id="input-event"/>
+</template><style>
+* /deep/ tr-ui-e-chrome-cc-layer-view{-webkit-flex-direction:column;display:-webkit-flex;left:0;position:relative;top:0}* /deep/ tr-ui-e-chrome-cc-layer-view>tr-ui-e-chrome-cc-layer-tree-quad-stack-view{-webkit-flex:1 1 100%;-webkit-flex-direction:column;min-height:0;display:-webkit-flex;width:100%}* /deep/tr-ui-e-chrome-cc- layer-view>tr-ui-e-chrome-cc-layer-view-analysis{height:150px;overflow-y:auto}* /deep/ tr-ui-e-chrome-cc-layer-view>tr-ui-e-chrome-cc-layer-view-analysis *{-webkit-u [...]
+</style><style>
+* /deep/ .tr-ui-e-chrome-cc-lthi-s-view{-webkit-flex:1 1 auto!important;-webkit-flex-direction:row;display:-webkit-flex}* /deep/ .tr-ui-e-chrome-cc-lthi-s-view>tr-ui-e-chrome-cc-layer-picker{-webkit-flex:1 1 auto}* /deep/ .tr-ui-e-chrome-cc-lthi-s-view>tr-ui-b-drag-handle{-webkit-flex:0 0 auto}
+</style><style>
+* /deep/ tr-ui-e-chrome-cc-picture-ops-chart-summary-view{-webkit-flex:0 0 auto;font-size:0;margin:0;min-height:200px;min-width:200px;overflow:hidden;padding:0}* /deep/ tr-ui-e-chrome-cc-picture-ops-chart-summary-view.hidden{display:none}
+</style><style>
+* /deep/ tr-ui-e-chrome-cc-picture-ops-chart-view{display:block;height:180px;margin:0;padding:0;position:relative}* /deep/ tr-ui-e-chrome-cc-picture-ops-chart-view>.use-percentile-scale{left:0;position:absolute;top:0}
+</style><template id="tr-ui-e-chrome-cc-picture-debugger-template">
+  <style>
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger {
+    -webkit-flex: 1 1 auto;
+    -webkit-flex-direction: row;
+    display: -webkit-flex;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger > tr-ui-a-generic-object-view {
+    -webkit-flex-direction: column;
+    display: -webkit-flex;
+    width: 400px;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger > left-panel {
+    -webkit-flex-direction: column;
+    display: -webkit-flex;
+    min-width: 300px;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger > left-panel > picture-info {
+    -webkit-flex: 0 0 auto;
+    padding-top: 2px;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger > left-panel >
+        picture-info .title {
+    font-weight: bold;
+    margin-left: 5px;
+    margin-right: 5px;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger > tr-ui-b-drag-handle {
+    -webkit-flex: 0 0 auto;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger .filename {
+    -webkit-user-select: text;
+    margin-left: 5px;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger > right-panel {
+    -webkit-flex: 1 1 auto;
+    -webkit-flex-direction: column;
+    display: -webkit-flex;
+  }
+
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger > right-panel >
+        tr-ui-e-chrome-cc-picture-ops-chart-view {
+    min-height: 150px;
+    min-width : 0;
+    overflow-x: auto;
+    overflow-y: hidden;
+  }
+
+  /*************************************************/
+
+  * /deep/ tr-ui-e-chrome-cc-picture-debugger raster-area {
+    background-color: #ddd;
+    min-height: 200px;
+    min-width: 200px;
+    overflow-y: auto;
+    padding-left: 5px;
+  }
+  </style>
+
+  <left-panel>
+    <picture-info>
+      <div>
+        <span class="title">Skia Picture</span>
+        <span class="size"></span>
+      </div>
+      <div>
+        <input class="filename" type="text" value="skpicture.skp"/>
+        <button class="export">Export</button>
+      </div>
+    </picture-info>
+  </left-panel>
+  <right-panel>
+    <tr-ui-e-chrome-cc-picture-ops-chart-view>
+    </tr-ui-e-chrome-cc-picture-ops-chart-view>
+    <raster-area><canvas></canvas></raster-area>
+  </right-panel>
+</template><style>
+* /deep/ .tr-ui-e-chrome-cc-picture-snapshot-view{-webkit-flex:0 1 auto!important;display:-webkit-flex}
+</style><polymer-element name="tr-ui-a-sub-view">
+  
 </polymer-element><polymer-element name="tr-ui-a-stack-frame">
-<template>
-<style>
+  <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>
+    <tr-ui-b-table id="table"></tr-ui-b-table>
+  </template>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-event-sub-view">
+  <template>
+    <style>
     :host {
       display: flex;
       flex-direction: column;
@@ -473,78 +845,510 @@
       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>
+    <tr-ui-b-table id="table">
+    </tr-ui-b-table>
+  </template>
+  
+</polymer-element><polymer-element name="tr-ui-e-chrome-cc-raster-task-view">
+  <template>
+    <style>
     :host {
       display: flex;
       flex-direction: column;
     }
-    #table {
-      flex: 1 1 auto;
-      align-self: stretch;
+    #heading {
+      flex: 0 0 auto;
     }
     </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>
+    <div id="heading">
+      Rasterization costs in
+      <tr-ui-a-analysis-link id="link"></tr-ui-a-analysis-link>
+    </div>
+    <tr-ui-b-table id="content"></tr-ui-b-table>
+  </template>
+
+  
+</polymer-element><style>
+.tr-ui-e-chrome-gpu-state-snapshot-view{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAEwATABMYqp3KAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB90JCQsBMCH7ZqYAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAUElEQVRYw+3WwQkAIAiF4Vc0hTO5/wiuURvYIcQOv1cRPhDlDXffSsrMsrYiQi/zU80FAACAVX3nt3lWAABA/x+ovnPyAAAA5AHyAAAA3wMOd34Xd+lsglgAAAAASUVORK5CYII=);display:-webkit-flex;overflow:auto}.tr-ui-e-chrome-gpu-state-snapshot-view img{displa [...]
+</style><style>
+  * /deep/ .chart-base #title {
+    font-size: 16pt;
+  }
+
+  * /deep/ .chart-base {
+    font-size: 12pt;
+    -webkit-user-select: none;
+    cursor: default;
+  }
+
+  * /deep/ .chart-base .axis path,
+  * /deep/ .chart-base .axis line {
+    fill: none;
+    shape-rendering: crispEdges;
+    stroke: #000;
+  }
+</style><template id="chart-base-template">
+  <svg> 
+    <g id="chart-area" xmlns="http://www.w3.org/2000/svg">
+      <g class="x axis"></g>
+      <g class="y axis"></g>
+      <text id="title"></text>
+    </g>
+  </svg>
+</template><style>
+  * /deep/ .chart-base-2d.updating-brushing-state #brushes > * {
+    fill: rgb(103, 199, 165)
+  }
+
+  * /deep/ .chart-base-2d #brushes {
+    fill: rgb(213, 236, 229)
+  }
+</style><style>
+* /deep/ .line-chart .line{fill:none;stroke-width:1.5px}* /deep/ .line-chart #brushes>rect{fill:rgb(192,192,192)}
+</style><polymer-element name="tr-ui-side-panel">
+  
+</polymer-element><polymer-element extends="tr-ui-side-panel" name="tr-ui-e-s-input-latency-side-panel">
+  <template>
+    <style>
     :host {
+      flex-direction: column;
       display: flex;
-      flex-direction: row;
     }
-    #events {
+    toolbar {
+      flex: 0 0 auto;
+      border-bottom: 1px solid black;
       display: flex;
-      flex-direction: column;
     }
-
+    result-area {
+      flex: 1 1 auto;
+      display: block;
+      min-height: 0;
+      overflow-y: auto;
+    }
     </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>
+    <toolbar id="toolbar"></toolbar>
+    <result-area id="result_area"></result-area>
+  </template>
+
+  
+</polymer-element><style>
+* /deep/ .pie-chart .arc-text{font-size:8pt}* /deep/ .pie-chart .label{font-size:10pt}* /deep/ .pie-chart polyline{fill:none;stroke:black}
+</style><polymer-element extends="tr-ui-side-panel" name="tr-ui-e-s-time-summary-side-panel">
+  <template>
+    <style>
     :host {
+      flex-direction: column;
       display: flex;
     }
-    #table {
+    toolbar {
+      flex: 0 0 auto;
+      border-bottom: 1px solid black;
+      display: flex;
+    }
+    result-area {
       flex: 1 1 auto;
-      align-self: stretch;
+      display: block;
+      min-height: 0;
+      overflow-y: auto;
     }
     </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>
+    <toolbar id="toolbar"></toolbar>
+    <result-area id="result_area"></result-area>
+  </template>
+
+  
+</polymer-element><style>
+.tr-ui-e-system-stats-snapshot-view .subhead{font-size:small;padding-bottom:10px}.tr-ui-e-system-stats-snapshot-view ul{background-position:0 5px;background-repeat:no-repeat;cursor:pointer;font-family:monospace;list-style:none;margin:0;padding-left:15px}.tr-ui-e-system-stats-snapshot-view li{background-position:0 5px;background-repeat:no-repeat;cursor:pointer;list-style:none;margin:0;padding-left:15px}
+</style><polymer-element name="tr-ui-heading">
+  <template>
+    <style>
     :host {
-      display: flex;
+      background-color: rgb(243, 245, 247);
+      border-right: 1px solid #8e8e8e;
+      display: block;
+      height: 100%;
+      margin: 0;
+      padding: 0 5px 0 0;
+    }
+
+    heading {
+      display: block;
+      overflow-x: hidden;
+      text-align: left;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+
+    #arrow {
+      -webkit-flex: 0 0 auto;
+      font-family: sans-serif;
+      margin-left: 5px;
+      margin-right: 5px;
+      width: 8px;
+    }
+
+    #link, #heading_content {
+      display: none;
+    }
+    </style>
+    <heading id="heading" on-click="{{onHeadingDivClicked_}}">
+      <span id="arrow"></span>
+      <span id="heading_content"></span>
+      <tr-ui-a-analysis-link id="link"></tr-ui-a-analysis-link>
+    </heading>
+  </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>
+.object-instance-track{height:18px}
+</style><style>
+.tr-ui-e-system-stats-instance-track{height:500px}.tr-ui-e-system-stats-instance-track ul{list-style:none;list-style-position:outside;margin:0;overflow:hidden}
+</style><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-alert-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>
+    <tr-ui-b-table id="table">
+    </tr-ui-b-table>
+  </template>
+  
+</polymer-element><polymer-element name="tr-ui-a-stacked-pane">
+  
+</polymer-element><polymer-element extends="tr-ui-a-stacked-pane" name="tr-ui-a-memory-dump-heap-details-pane">
+  <template>
+    <style>
+      :host {
+        display: flex;
+        flex-direction: column;
+      }
+
+      #header {
+        flex: 0 0 auto;
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+
+        background-color: #eee;
+        border-bottom: 1px solid #8e8e8e;
+        border-top: 1px solid white;
+      }
+
+      #label {
+        flex: 1 1 auto;
+        padding: 8px;
+        font-size:  15px;
+        font-weight: bold;
+      }
+
+      #view_mode_container {
+        display: none;
+        flex: 0 0 auto;
+        padding: 5px;
+        font-size: 15px;
+      }
+
+      #contents {
+        flex: 1 0 auto;
+        align-self: stretch;
+        font-size: 12px;
+      }
+
+      #info_text {
+        padding: 8px;
+        color: #666;
+        font-style: italic;
+        text-align: center;
+      }
+
+      #table {
+        display: none;  /* Hide until memory allocator dumps are set. */
+        flex: 1 0 auto;
+        align-self: stretch;
+      }
+    </style>
+    <div id="header">
+      <div id="label">Heap details</div>
+      <div id="view_mode_container">
+        <span>View mode:</span>
+        
+      </div>
+    </div>
+    <div id="contents">
+      <tr-ui-b-info-bar class="info-bar-hidden" id="info_bar">
+      </tr-ui-b-info-bar>
+      <div id="info_text">No heap dump selected</div>
+      <tr-ui-b-table id="table"></tr-ui-b-table>
+    </div>
+  </template>
+</polymer-element><polymer-element extends="tr-ui-a-stacked-pane" 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;
+      }
+
+      #info_text {
+        padding: 8px;
+        color: #666;
+        font-style: italic;
+        text-align: center;
+      }
+
+      #table {
+        display: none;  /* Hide until memory allocator dumps are set. */
+        flex: 1 0 auto;
+        align-self: stretch;
+      }
+    </style>
+    <div id="label">Component details</div>
+    <div id="contents">
+      <div id="info_text">No memory allocator dump selected</div>
+      <tr-ui-b-table id="table"></tr-ui-b-table>
+    </div>
+  </template>
+</polymer-element><polymer-element extends="tr-ui-a-stacked-pane" 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;
+      }
+
+      #info_text {
+        padding: 8px;
+        color: #666;
+        font-style: italic;
+        text-align: center;
+      }
+
+      #table {
+        display: none;  /* Hide until memory dumps are set. */
+        flex: 1 0 auto;
+        align-self: stretch;
+      }
+    </style>
+    <div id="label">Memory maps</div>
+    <div id="contents">
+      <div id="info_text">No memory maps selected</div>
+      <tr-ui-b-table id="table"></tr-ui-b-table>
+    </div>
+  </template>
+</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-b-view-specific-brushing-state">
+  
+</polymer-element><polymer-element extends="tr-ui-a-stacked-pane" 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;
+      }
+
+      #contents {
+        flex: 1 0 auto;
+        align-self: stretch;
+        font-size: 12px;
+      }
+
+      #info_text {
+        padding: 8px;
+        color: #666;
+        font-style: italic;
+        text-align: center;
+      }
+
+      #table {
+        display: none;  /* Hide until memory dumps are set. */
+        flex: 1 0 auto;
+        align-self: stretch;
+      }
+    </style>
+    <tr-ui-b-view-specific-brushing-state id="state" view-id="analysis.memory_dump_overview_pane">
+    </tr-ui-b-view-specific-brushing-state>
+    <div id="label">Overview</div>
+    <div id="contents">
+      <div id="info_text">No memory memory dumps selected</div>
+      <tr-ui-b-table id="table"></tr-ui-b-table>
+    </div>
+  </template>
+</polymer-element><polymer-element extends="tr-ui-a-stacked-pane" name="tr-ui-a-memory-dump-header-pane">
+  <template>
+    <style>
+      :host {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+
+        background-color: #d0d0d0;
+        border-bottom: 1px solid #8e8e8e;
+        border-top: 1px solid white;
+      }
+
+      #label {
+        flex: 1 1 auto;
+        padding: 6px;
+        font-size: 15px;
+      }
+
+      #aggregation_mode_container {
+        display: none;
+        flex: 0 0 auto;
+        padding: 5px;
+        font-size: 15px;
+      }
+    </style>
+    
+    <div id="label"></div>
+    <div id="aggregation_mode_container">
+      <span>Metric aggregation:</span>
+      
+    </div>
+  </template>
+</polymer-element><polymer-element name="tr-ui-a-stacked-pane-view">
+  <template>
+    <style>
+    :host {
+      display: flex;
+      flex-direction: column;
+    }
 
+    #pane_container > * {
+      flex: 0 0 auto;
+    }
+    </style>
+    <div id="pane_container">
+    </div>
+  </template>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-container-memory-dump-sub-view">
+  <template>
+    <div id="content"></div>
+  </template>
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-counter-sample-sub-view">
+  <template>
+    <style>
+    :host {
+      display: flex;
+      flex-direction: column;
+    }
+    </style>
+    <tr-ui-b-table id="table"></tr-ui-b-table>
+  </template>
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-layout-tree-sub-view">
+  <template>
+    <div id="content"></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>
+  <template>
+    <style>
     :host {
       display: flex;
       flex-direction: column;
@@ -562,15 +1366,16 @@
       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>
+    <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 extends="tr-ui-a-sub-view" name="tr-ui-a-multi-event-sub-view">
+  <template>
+    <style>
     :host {
       display: flex;
       overflow: auto;
@@ -598,99 +1403,191 @@
       border-bottom: 1px solid #aaa;
     }
     </style>
-<div id="content"></div>
-</template>
+    <div id="content"></div>
+  </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-multi-thread-slice-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-async-slice-sub-view">
+  <template>
+    <style>
     :host {
       display: flex;
     }
-    #content {
+    #container {
       display: flex;
       flex: 1 1 auto;
     }
-    #content > tr-ui-a-related-events {
+    #events {
       margin-left: 8px;
+      flex: 0 1 200px;
     }
     </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>
+    <div id="container">
+      <tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+      <div id="events">
+        <tr-ui-a-related-events id="relatedEvents"></tr-ui-a-related-events>
+      </div>
+    </div>
+  </template>
+
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-cpu-slice-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>
+    <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%;
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-flow-event-sub-view">
+  <template>
+    <style>
+    :host {
+      display: flex;
     }
-
-    table tr > td:first-child {
-      padding-left: 2px;
+    </style>
+    <tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+  </template>
+
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-frame-sub-view">
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-instant-event-sub-view">
+  <template>
+    <style>
+    :host {
+      display: block;
     }
+    </style>
+    <div id="content"></div>
+  </template>
 
-    table tr > td {
-      padding: 2px 4px 2px 4px;
-      vertical-align: text-top;
-      width: 150px;
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-object-sub-view">
+  <template>
+    <style>
+    :host {
+      display: flex;
     }
-
-    table td td {
-      padding: 0 0 0 0;
-      width: auto;
+    </style>
+    <tr-ui-b-table id="content"></tr-ui-b-table>
+  </template>
+  
+</polymer-element><polymer-element name="tr-ui-a-frame-power-usage-chart">
+  <template>
+    <div id="content"></div>
+  </template>
+</polymer-element><polymer-element name="tr-ui-a-power-sample-summary-table">
+  <template>
+    <tr-ui-b-table id="table"></tr-ui-b-table>
+  </template>
+  
+</polymer-element><polymer-element name="tr-ui-a-power-sample-table">
+  <template>
+    <style>
+    :host {
+      display: flex;
     }
-    tr {
-      vertical-align: top;
+    </style>
+    <tr-ui-b-table id="table"></tr-ui-b-table>
+  </template>
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-power-sample-sub-view">
+  <template>
+    <style>
+    :host {
+      display: flex;
+      flex-direction: row;
     }
-
-    tr:nth-child(2n+0) {
-      background-color: #e2e2e2;
+    #tables {
+      display: flex;
+      flex-direction: column;
+      width: 50%;
+    }
+    #chart {
+      width: 50%;
+    }
+    </style>
+    <div id="tables">
+      <tr-ui-a-power-sample-summary-table id="summaryTable">
+      </tr-ui-a-power-sample-summary-table>
+      <tr-ui-a-power-sample-table id="samplesTable">
+      </tr-ui-a-power-sample-table>
+    </div>
+    <tr-ui-a-frame-power-usage-chart id="chart">
+    </tr-ui-a-frame-power-usage-chart>
+  </template>
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-sample-sub-view">
+  <template>
+    <style>
+    :host { display: block; }
+    #control {
+      background-color: #e6e6e6;
+      background-image: -webkit-gradient(linear, 0 0, 0 100%,
+                                         from(#E5E5E5), to(#D1D1D1));
+      flex: 0 0 auto;
+      overflow-x: auto;
+    }
+    #control::-webkit-scrollbar { height: 0px; }
+    #control {
+      font-size: 12px;
+      display: flex;
+      flex-direction: row;
+      align-items: stretch;
+      margin: 1px;
+      margin-right: 2px;
+    }
+    </style>
+    <div id="control">
+      Sample View Option
+    </div>
+    <tr-ui-b-table id="table">
+    </tr-ui-b-table>
+  </template>
+
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-thread-slice-sub-view">
+  <template>
+    <style>
+    :host {
+      display: flex;
+    }
+    #content {
+      display: flex;
+      flex: 1 1 auto;
+    }
+    #content > tr-ui-a-related-events {
+      margin-left: 8px;
+      flex: 0 1 200px;
     }
     </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>
+    <div id="content"></div>
+  </template>
+
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-thread-time-slice-sub-view">
+  <template>
+    <style>
     :host {
       display: flex;
     }
@@ -698,12 +1595,61 @@
       flex: 1 1 auto;
     }
     </style>
-<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
-</template>
+    <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>
+  
+</polymer-element><polymer-element name="tr-ui-a-user-expectation-related-samples-table">
+  <template>
+    <style>
+    #table {
+      flex: 1 1 auto;
+      align-self: stretch;
+    }
+    </style>
+    <tr-ui-b-table id="table"></tr-ui-b-table>
+  </template>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-multi-user-expectation-sub-view">
+  <template>
+    <style>
+    :host {
+      display: flex;
+      flex: 1 1 auto;
+    }
+    #events {
+      margin-left: 8px;
+      flex: 0 1 200px;
+    }
+    </style>
+    <tr-ui-a-multi-event-sub-view id="realView"></tr-ui-a-multi-event-sub-view>
+    <div id="events">
+      <tr-ui-a-user-expectation-related-samples-table id="relatedSamples"></tr-ui-a-user-expectation-related-samples-table>
+    </div>
+  </template>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-async-slice-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 extends="tr-ui-a-sub-view" name="tr-ui-a-single-cpu-slice-sub-view">
+  <template>
+    <style>
     table {
       border-collapse: collapse;
       border-width: 0;
@@ -733,87 +1679,73 @@
       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>
+    <table>
+      <tbody><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>
+          <tr-v-ui-scalar-span id="start">
+          </tr-v-ui-scalar-span>
+        </td>
+      </tr>
+      <tr>
+        <td>Duration:</td>
+        <td>
+          <tr-v-ui-scalar-span id="duration">
+          </tr-v-ui-scalar-span>
+        </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>
+    </tbody></table>
+  </template>
+
+  
+</polymer-element><polymer-element extends="tr-ui-a-single-event-sub-view" name="tr-ui-a-single-flow-event-sub-view">
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-frame-sub-view">
+  <template>
+    <style>
     :host {
       display: flex;
+      flex-direction: column;
     }
-    #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;
+    #asv {
+      flex: 0 0 auto;
+      align-self: stretch;
     }
     </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>
+    <tr-ui-a-alert-sub-view id="asv">
+    </tr-ui-a-alert-sub-view>
+  </template>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-instant-event-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>
+    <div id="content"></div>
+  </template>
 
-</polymer-element><polymer-element name="tr-ui-a-single-object-instance-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-object-instance-sub-view">
+  <template>
+    <style>
     :host {
       display: block;
     }
@@ -842,12 +1774,12 @@
       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>
+    <div id="content"></div>
+  </template>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-object-snapshot-sub-view">
+  <template>
+    <style>
     #args {
       white-space: pre;
     }
@@ -857,307 +1789,391 @@
       display: flex;
     }
 
-    * {
+    ::content * {
       -webkit-user-select: text;
     }
 
-    .title {
+    ::content .title {
       border-bottom: 1px solid rgb(128, 128, 128);
       font-size: 110%;
       font-weight: bold;
     }
 
-    td, th {
+    ::content 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>
+    <content></content>
+  </template>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-power-sample-sub-view">
+  <template>
+    <style>
+    :host { display: block; }
+    </style>
+    <tr-ui-a-power-sample-table id="samplesTable">
+    </tr-ui-a-power-sample-table>
+  </template>
+
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-sample-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>
+    <tr-ui-b-table id="content"></tr-ui-b-table>
+  </template>
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-thread-slice-sub-view">
+  <template>
+    <style>
     :host {
       display: flex;
+      flex-direction: row;
     }
-    </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;
+    #events {
+      display: flex;
+      flex-direction: column;
     }
+
     </style>
-<div id="content"></div>
-</template>
+    <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 extends="tr-ui-a-sub-view" name="tr-ui-a-single-thread-time-slice-sub-view">
+  <template>
+    <style>
+    table {
+      border-collapse: collapse;
+      border-width: 0;
+      margin-bottom: 25px;
+      width: 100%;
+    }
 
-</polymer-element><polymer-element name="tr-ui-a-single-interaction-record-sub-view" extends="tr-ui-a-sub-view">
+    table tr > td:first-child {
+      padding-left: 2px;
+    }
 
-</polymer-element><polymer-element name="tr-ui-a-multi-interaction-record-sub-view" extends="tr-ui-a-sub-view">
+    table tr > td {
+      padding: 2px 4px 2px 4px;
+      vertical-align: text-top;
+      width: 150px;
+    }
 
-</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 td td {
+      padding: 0 0 0 0;
+      width: auto;
     }
-    #table {
-      flex: 1 1 auto;
-      align-self: stretch;
+    tr {
+      vertical-align: top;
     }
-    </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;
+    tr:nth-child(2n+0) {
+      background-color: #e2e2e2;
     }
     </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>
+    <table>
+      <tbody><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>
+          <tr-v-ui-scalar-span id="start">
+          </tr-v-ui-scalar-span>
+        </td>
+      </tr>
+      <tr>
+        <td>Duration:</td>
+        <td>
+          <tr-v-ui-scalar-span id="duration">
+          </tr-v-ui-scalar-span>
+        </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>
+    </tbody></table>
+  </template>
+
+  
+</polymer-element><polymer-element extends="tr-ui-a-sub-view" name="tr-ui-a-single-user-expectation-sub-view">
+  <template>
+    <style>
     :host {
-      display: inline-block;
+      display: flex;
+      flex-direction: row;
     }
-
-    #square {
-      font-size: 150%;  /* Make the square bigger. */
-      line-height: 0%;  /* Prevent the square from increasing legend height. */
+    #events {
+      display: flex;
+      flex-direction: column;
     }
     </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>
+    <tr-ui-a-single-event-sub-view id="realView"></tr-ui-a-single-event-sub-view>
+    <div id="events">
+      <tr-ui-a-user-expectation-related-samples-table id="relatedSamples"></tr-ui-a-user-expectation-related-samples-table>
+    </div>
+  </template>
+  
+</polymer-element><polymer-element constructor="TracingAnalysisTabView" name="tr-ui-a-tab-view">
+  <template>
+    <style>
       :host {
         display: flex;
-        flex-direction: column;
+        flex-flow: column nowrap;
+        overflow: hidden;
+        box-sizing: border-box;
       }
 
-      #label {
-        flex: 0 0 auto;
-        padding: 8px;
+      tab-strip[tabs-hidden] {
+        display: none;
+      }
 
-        background-color: #eee;
+      tab-strip {
+        background-color: rgb(236, 236, 236);
         border-bottom: 1px solid #8e8e8e;
-        border-top: 1px solid white;
-
-        font-size:  15px;
-        font-weight: bold;
+        display: flex;
+        flex: 0 0 auto;
+        flex-flow: row;
+        overflow-x: auto;
+        padding: 0 10px 0 10px;
+        font-size: 12px;
       }
 
-      #contents {
-        flex: 1 0 auto;
-        align-self: stretch;
-        font-size: 12px;
+      tab-button {
+        display: block;
+        flex: 0 0 auto;
+        padding: 4px 15px 1px 15px;
+        margin-top: 2px;
       }
 
-      #contents .info-text {
-        padding: 8px;
-        color: #666;
-        font-style: italic;
-        text-align: center;
+      tab-button[selected=true] {
+        background-color: white;
+        border: 1px solid rgb(163, 163, 163);
+        border-bottom: none;
+        padding: 3px 14px 1px 14px;
       }
-    </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 {
+      tabs-content-container {
         display: flex;
-        flex-direction: column;
+        flex: 1 1 auto;
+        overflow: auto;
+        width: 100%;
       }
 
-      #label {
-        flex: 0 0 auto;
-        padding: 8px;
-
-        background-color: #eee;
-        border-bottom: 1px solid #8e8e8e;
-        border-top: 1px solid white;
+      ::content > * {
+        flex: 1 1 auto;
+      }
 
-        font-size:  15px;
-        font-weight: bold;
+      ::content > *:not([selected]) {
+        display: none;
       }
 
-      #contents {
-        flex: 1 0 auto;
-        align-self: stretch;
-        font-size: 12px;
+      button-label {
+        display: inline;
       }
 
-      #contents .info-text {
-        padding: 8px;
-        color: #666;
-        font-style: italic;
-        text-align: center;
+      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>
-<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>
+    <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><polymer-element name="tr-ui-a-analysis-view">
+  <template>
+    <style>
       :host {
+        background-color: white;
         display: flex;
         flex-direction: column;
+        height: 275px;
+        overflow: auto;
       }
 
-      #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;
+      :host(.tall-mode) {
+        height: 525px;
       }
 
-      #table {
+      ::content > * {
         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>
+    <content></content>
+  </template>
+  
+</polymer-element><polymer-element name="tr-ui-b-dropdown">
+  <template>
+    <style>
     :host {
+      position: relative;
       display: flex;
-      flex-direction: column;
+    }
+    #outer {
+      display: flex;
+      flex: 0 0 auto;
+      padding: 1px 4px 1px 4px;
+      -webkit-user-select: none;
+      cursor: default;
     }
 
-    #overview_pane,
-    #details_pane_container {
+    #state {
+      display: flex;
+      flex: 0 0 auto;
+      margin-left: 2px;
+      margin-right: 0px;
       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>
+    #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);
+    }
 
-</polymer-element><polymer-element name="tr-ui-a-multi-process-memory-dump-sub-view" extends="tr-ui-a-sub-view">
-<template>
-<style>
-    :host {
+    #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-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>
+    <tr-ui-b-toolbar-button id="outer" on-click="{{ onOuterClick_ }}" on-keydown="{{ onOuterKeyDown_ }}">
+      <div id="icon">⚙</div>
+      <div id="state">▾</div>
+    </tr-ui-b-toolbar-button>
+    <dialog id="dialog" on-cancel="{{ onDialogCancel_ }}" on-click="{{ onDialogClick_ }}">
+      <div id="dialog-frame">
+        <content></content>
+      </div>
+    </dialog>
+  </template>
+  
+</polymer-element><polymer-element is="HTMLUnknownElement" name="tr-ui-b-info-bar-group">
+  <template>
+    <style>
     :host {
+      flex: 0 0 auto;
+      flex-direction: column;
       display: flex;
     }
     </style>
-<tr-ui-b-table id="content"></tr-ui-b-table>
-</template>
+    <div id="messages"></div>
+  </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;
-      }
+  
+</polymer-element><polymer-element name="tr-ui-b-toolbar-button" noscript="">
+  <template>
+    <style>
+    :host {
+      display: flex;
+      background-color: #f8f8f8;
+      border: 1px solid rgba(0, 0, 0, 0.5);
+      color: rgba(0,0,0,0.8);
+      justify-content: center;
+      align-self: stretch;
+      min-width: 23px;
+    }
 
-      :host(.tall-mode) {
-        height: 525px;
-      }
+    :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);
+    }
 
-      ::content > * {
-        flex: 1 0 auto;
-      }
+    #aligner {
+      display: flex;
+      flex: 0 0 auto;
+      align-self: center;
+    }
     </style>
-<content></content>
-</template>
-
+    <div id="aligner">
+      <content></content>
+    </div>
+  </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 [...]
+.letter-dot-track {
+  height: 18px;
+}
 </style><style>
 .chart-track {
   height: 30px;
   position: relative;
 }
 </style><style>
-.letter-dot-track {
-  height: 18px;
+.power-series-track {
+  height: 90px;
 }
 </style><style>
-.object-instance-track{height:18px}
+.spacing-track{height:4px}
 </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'}
@@ -1167,24 +2183,47 @@
 }
 </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>
+</style><polymer-element name="tr-ui-timeline-track-view">
+  <template>
+    <style>
+    :host {
+      -webkit-box-orient: vertical;
+      display: -webkit-box;
+      position: relative;
+    }
+
+    :host ::content * {
+      -webkit-user-select: none;
+      cursor: default;
+    }
+
+    #drag_box {
+      background-color: rgba(0, 0, 255, 0.25);
+      border: 1px solid rgb(0, 0, 96);
+      font-size: 75%;
+      position: fixed;
+    }
+
+    #hint_text {
+      position: absolute;
+      bottom: 6px;
+      right: 6px;
+      font-size: 8pt;
+    }
+    </style>
+    <content></content>
+
+    <div id="drag_box"></div>
+    <div id="hint_text"></div>
+
+    <tv-ui-b-hotkey-controller id="hotkey_controller">
+    </tv-ui-b-hotkey-controller>
+  </template>
+
+  
+</polymer-element><polymer-element name="tr-ui-find-control">
+  <template>
+    <style>
       :host {
         -webkit-user-select: none;
         display: -webkit-flex;
@@ -1204,7 +2243,6 @@ body *{-webkit-user-select:none;box-sizing:border-box}
       }
       tr-ui-b-toolbar-button {
         border-left: none;
-        font-size: 14px;
         margin: 0;
       }
       #hitCount {
@@ -1236,20 +2274,22 @@ body *{-webkit-user-select:none;box-sizing:border-box}
       }
       @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 }}">
-      ←
+
+    <input id="filter" on-blur="{{ filterBlur }}" on-focus="{{ filterFocus }}" on-input="{{ filterTextChanged }}" on-keydown="{{ filterKeyDown }}" on-mouseup="{{ filterMouseUp }}" type="text"/>
+    <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 on-click="{{ findNext }}">
+      →
     </tr-ui-b-toolbar-button>
-<div id="hitCount">0 of 0</div>
-</template>
+    <div id="hitCount">0 of 0</div>
+  </template>
 
-</polymer-element><polymer-element name="tracing-scripting-control" constructor="TracingScriptingControl">
-<template>
-<style>
+  
+</polymer-element><polymer-element name="tr-ui-scripting-control">
+  <template>
+    <style>
       :host {
         flex: 1 1 auto;
       }
@@ -1301,16 +2341,17 @@ body *{-webkit-user-select:none;box-sizing:border-box}
         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">
+    <div class="root hidden" id="root" on-focus="{{ onConsoleFocus }}" tabindex="0">
+      <div id="history"></div>
+      <div id="prompt" on-blur="{{ onConsoleBlur }}" on-keydown="{{ promptKeyDown }}" on-keypress="{{ promptKeyPress }}"></div>
+    </div>
+  </template>
 
-</polymer-element><polymer-element name="tr-ui-side-panel-container" is="HTMLUnknownElement">
-<template>
-<style>
+  
+</polymer-element><polymer-element is="HTMLUnknownElement" name="tr-ui-side-panel-container">
+  <template>
+    <style>
     :host {
       align-items: stretch;
       display: -webkit-flex;
@@ -1363,295 +2404,525 @@ body *{-webkit-user-select:none;box-sizing:border-box}
       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>
+    <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-timeline-view-help-overlay">
+  <template>
+    <style>
     :host {
+      -webkit-flex: 1 1 auto;
+      -webkit-flex-direction: row;
+      display: -webkit-flex;
+      width: 700px;
+    }
+    .column {
+      width: 50%;
+    }
+    h2 {
+      font-size: 1.2em;
+      margin: 0;
+      margin-top: 5px;
+      text-align: center;
+    }
+    h3 {
+      margin: 0;
+      margin-left: 126px;
+      margin-top: 10px;
+    }
+    .pair {
+      -webkit-flex: 1 1 auto;
+      -webkit-flex-direction: row;
+      display: -webkit-flex;
+    }
+    .command {
+      font-family: monospace;
+      margin-right: 5px;
+      text-align: right;
+      width: 150px;
+    }
+    .action {
+      font-size: 0.9em;
+      text-align: left;
+      width: 200px;
+    }
+    tr-ui-b-mouse-mode-icon {
+      border: 1px solid #888;
+      border-radius: 3px;
+      box-shadow: inset 0 0 2px rgba(0,0,0,0.3);
+      display: inline-block;
+      margin-right: 1px;
       position: relative;
-      display: flex;
+      top: 4px;
     }
-    #outer {
+    .mouse-mode-icon.pan-mode {
+      background-position: -1px -11px;
+    }
+    .mouse-mode-icon.select-mode {
+      background-position: -1px -41px;
+    }
+    .mouse-mode-icon.zoom-mode {
+      background-position: -1px -71px;
+    }
+    .mouse-mode-icon.timing-mode {
+      background-position: -1px -101px;
+    }
+    </style>
+    <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>
+        <tr-ui-b-mouse-mode-icon modename="SELECTION"></tr-ui-b-mouse-mode-icon>
+        Select mode
+      </h3>
+      <div class="pair">
+        <div class="command">drag</div>
+        <div class="action">Box select</div>
+      </div>
+
+      <div class="pair">
+        <div class="command"><span class="mod"></span>-click/drag</div>
+        <div class="action">Add events to the current selection</div>
+      </div>
+
+      <div class="pair">
+        <div class="command">double click</div>
+        <div class="action">Select all events with same title</div>
+      </div>
+
+      <h3>
+        <tr-ui-b-mouse-mode-icon modename="PANSCAN"></tr-ui-b-mouse-mode-icon>
+        Pan mode
+      </h3>
+      <div class="pair">
+        <div class="command">drag</div>
+        <div class="action">Pan the view</div>
+      </div>
+
+      <h3>
+        <tr-ui-b-mouse-mode-icon modename="ZOOM"></tr-ui-b-mouse-mode-icon>
+        Zoom mode
+      </h3>
+      <div class="pair">
+        <div class="command">drag</div>
+        <div class="action">Zoom in/out by dragging up/down</div>
+      </div>
+
+      <h3>
+        <tr-ui-b-mouse-mode-icon modename="TIMING"></tr-ui-b-mouse-mode-icon>
+        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">/</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>
+  </template>
+
+  
+</polymer-element><polymer-element name="tr-v-ui-array-of-numbers-span">
+  <template>
+  </template>
+  
+</polymer-element><polymer-element name="tr-v-ui-generic-table-view">
+  <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-timeline-view-metadata-overlay">
+  <template>
+    <style>
+    :host {
+      width: 700px;
+
+      overflow: auto;
+    }
+    </style>
+    <tr-v-ui-generic-table-view id="gtv"></tr-v-ui-generic-table-view>
+  </template>
+
+  
+</polymer-element><polymer-element name="tr-v-ui-preferred-display-unit">
+  
+</polymer-element><polymer-element name="tr-ui-timeline-view">
+  <template>
+    <style>
+    :host {
+      flex-direction: column;
+      cursor: default;
       display: flex;
+      font-family: sans-serif;
+      padding: 0;
+    }
+
+    #control {
+      background-color: #e6e6e6;
+      background-image: -webkit-gradient(linear, 0 0, 0 100%,
+          from(#E5E5E5), to(#D1D1D1));
       flex: 0 0 auto;
-      padding: 1px 4px 1px 4px;
-      -webkit-user-select: none;
-      cursor: default;
+      overflow-x: auto;
+    }
+
+    #control::-webkit-scrollbar { height: 0px; }
+
+    #control > #bar {
       font-size: 12px;
+      display: flex;
+      flex-direction: row;
+      margin: 1px;
     }
 
-    #state {
+    #control > #bar > #title {
       display: flex;
-      flex: 0 0 auto;
-      margin-left: 2px;
-      margin-right: 0px;
-      flex: 0 0 auto;
+      align-items: center;
+      padding-left: 8px;
+      padding-right: 8px;
+      flex: 1 1 auto;
     }
 
-    #icon {
+    #control > #bar > #left_controls,
+    #control > #bar > #right_controls {
       display: flex;
-      flex: 0 0 auto;
-      flex: 0 0 auto;
+      flex-direction: row;
+      align-items: stretch;
     }
-    dialog {
-      position: absolute;
-      padding: 0;
-      border: 0;
-      margin: 0;
+
+    #control > #bar > #left_controls > * { margin-right: 2px; }
+    #control > #bar > #right_controls > * { margin-left: 2px; }
+    #control > #collapsing_controls { display: flex; }
+
+    middle-container {
+      flex: 1 1 auto;
+      flex-direction: row;
+      border-bottom: 1px solid #8e8e8e;
+      display: flex;
+      min-height: 0;
     }
-    dialog::backdrop {
-      background: rgba(0,0,0,.05);
+
+    middle-container ::content track-view-container {
+      flex: 1 1 auto;
+      display: flex;
+      min-height: 0;
+      min-width: 0;
     }
 
-    #dialog-frame {
-      background-color: #fff;
+    middle-container ::content track-view-container > * { flex: 1 1 auto; }
+    middle-container > x-timeline-view-side-panel-container { flex: 0 0 auto; }
+    tr-ui-b-drag-handle { flex: 0 0 auto; }
+    tr-ui-a-analysis-view { flex: 0 0 auto; }
+    </style>
+
+    <tv-ui-b-hotkey-controller id="hkc"></tv-ui-b-hotkey-controller>
+    <div id="control">
+      <div id="bar">
+        <div id="left_controls"></div>
+        <div id="title">^_^</div>
+        <div id="right_controls">
+          <tr-ui-b-toolbar-button id="view_metadata_button">
+            M
+          </tr-ui-b-toolbar-button>
+          <tr-ui-b-dropdown id="view_options_dropdown"></tr-ui-b-dropdown>
+          <tr-ui-find-control id="view_find_control"></tr-ui-find-control>
+          <tr-ui-b-toolbar-button id="view_console_button">
+            »
+          </tr-ui-b-toolbar-button>
+          <tr-ui-b-toolbar-button id="view_help_button">
+            ?
+          </tr-ui-b-toolbar-button>
+        </div>
+      </div>
+      <div id="collapsing_controls"></div>
+      <tr-ui-b-info-bar-group id="import-warnings">
+      </tr-ui-b-info-bar-group>
+    </div>
+    <middle-container>
+      <content></content>
+
+      <tr-ui-side-panel-container id="side_panel_container">
+      </tr-ui-side-panel-container>
+    </middle-container>
+    <tr-ui-b-drag-handle id="drag_handle"></tr-ui-b-drag-handle>
+    <tr-ui-a-analysis-view id="analysis"></tr-ui-a-analysis-view>
+
+    <tr-v-ui-preferred-display-unit id="display_unit">
+    </tr-v-ui-preferred-display-unit>
+  </template>
+
+  
+</polymer-element><polymer-element name="tr-ui-b-grouping-table">
+  <template>
+    <style>
+    :host {
       display: flex;
-      flex-direction: column;
+    }
+    #table {
       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>
+    <tr-ui-b-table id="table"></tr-ui-b-table>
+  </template>
+</polymer-element><polymer-element name="tr-ui-b-grouping-table-groupby-picker">
+  <template>
+    <style>
+    :host {
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+    }
+    groups {
+      -webkit-user-select: none;
+      display: flex;
+      flex-direction: row;
+      padding-left: 10px;
+    }
 
-</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.
+    group, possible-group {
+      display: span;
+      padding-right: 10px;
+      padding-left: 10px;
+    }
 
-/* WARNING: This file is auto generated.
- *
- * Do not edit directly.
- */
+    group {
+      border-left: 1px solid rgba(0,0,0,0);
+      cursor: move;
+    }
 
-/**
- * @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)
+    group.dragging {
+      opacity: 0.2;
+    }
+
+    group.drop-targeted {
+      border-left: 1px solid black;
+    }
+
+
+    #remove {
+      cursor: default;
+    }
+
+    #remove:not([hovered]) {
+      visibility: hidden;
+    }
+    </style>
+    <groups>
+    </groups>
+    <tr-ui-b-dropdown id="add-group"></tr-ui-b-dropdown>
+  </template>
+</polymer-element><template id="tr-ui-b-grouping-table-groupby-picker-group-template">
+  <span id="key"></span>
+  <span id="remove">×</span>
+</template><polymer-element extends="tr-ui-side-panel" name="tr-ui-sp-file-size-stats-side-panel">
+  <template>
+    <style>
+    :host {
+      display: flex;
+      flex-direction: column;
+      width: 600px;
+    }
+    toolbar {
+      align-items: center;
+      background-color: rgb(236, 236, 236);
+      border-bottom: 1px solid #8e8e8e;
+      display: flex;
+      flex-direction: row;
+      flex-direction: row;
+      flex: 0 0 auto;
+      font-size: 12px;
+      padding: 0 10px 0 10px;
+    }
+    table-container {
+      display: flex;
+      min-height: 0px;
+      overflow-y: auto;
+    }
+    </style>
+
+    <toolbar>
+      <span><b>Group by:</b></span>
+      <tr-ui-b-grouping-table-groupby-picker id="picker">
+      </tr-ui-b-grouping-table-groupby-picker>
+    </toolbar>
+    <table-container>
+      <tr-ui-b-grouping-table id="table"></tr-ui-b-grouping-table>
+    </table-container>
+  </template>
+</polymer-element><polymer-element extends="tr-ui-side-panel" name="tr-ui-e-s-alerts-side-panel">
+  <template>
+    <style>
+    :host {
+      display: block;
+      width: 250px;
+    }
+    #content {
+      flex-direction: column;
+      display: flex;
+    }
+    </style>
+
+    <div id="content">
+      <toolbar id="toolbar"></toolbar>
+      <result-area id="result_area"></result-area>
+    </div>
+  </template>
+
+  
+</polymer-element><script>
+
+// Copyright 2015 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 isExported(name){var parts=name.split('.');var cur=global;for(var part;parts.length&&(part=parts.shift());){if(part in cur){cur=cur[part];}else{return false;}}
+return true;}
+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)
+function showPanic(panicTitle,panicDetails){if(tr.isHeadless){if(panicDetails instanceof Error)
+throw panicDetails;throw new Error('Panic: '+panicTitle+':\n'+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++)
+Object.defineProperty(obj,propertyName,propertyDescriptor);}};function initialize(){if(global.isVinn){tr.isVinn=true;}else if(global.process&&global.process.versions.node){tr.isNode=true;}else{tr.isVinn=false;tr.isNode=false;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);}
+tr.isHeadless=tr.isVinn||tr.isNode;}
+return{initialize:initialize,exportTo:exportTo,isExported:isExported,isDefined:isDefined,showPanic:showPanic,hasPanic:hasPanic,getPanicText:getPanicText};})();tr.initialize();'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;}
@@ -1662,60 +2933,60 @@ function comparePossiblyUndefinedValues(x,y,cmp,opt_this){if(x!==undefined&&y!==
 return cmp.call(opt_this,x,y);if(x!==undefined)
 return-1;if(y!==undefined)
 return 1;return 0;}
+function compareNumericWithNaNs(x,y){if(!isNaN(x)&&!isNaN(y))
+return x-y;if(isNaN(x))
+return 1;if(isNaN(y))
+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 cloneDictionary(dict){var clone={};for(var k in dict){clone[k]=dict[k];}
+return clone;}
 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 dictionaryContainsValue(dict,value){for(var key in dict)
+if(dict[key]===value)
+return true;return false;}
 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 filterItems(dict,predicate,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];var value=dict[key];if(predicate.call(opt_this,key,value))
+result[key]=value;}
+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 invertArrayOfDicts(array,opt_dictGetter,opt_this){opt_this=opt_this||this;var result={};for(var i=0;i<array.length;i++){var item=array[i];if(item===undefined)
+continue;var dict=opt_dictGetter?opt_dictGetter.call(opt_this,item):item;if(dict===undefined)
+continue;for(var key in dict){var valueList=result[key];if(valueList===undefined)
+result[key]=valueList=new Array(array.length);valueList[i]=dict[key];}}
+return result;}
+function arrayToDict(array,valueToKeyFn,opt_this){opt_this=opt_this||this;var result={};var length=array.length;for(var i=0;i<length;i++){var value=array[i];var key=valueToKeyFn.call(opt_this,value);result[key]=value;}
+return result;}
 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 [...]
+function findFirstKeyInDictMatching(dict,opt_func,opt_this){var func=opt_func||identity;for(var key in dict){if(func.call(opt_this,key,dict[key]))
+return key;}
+return undefined;}
+function mapValues(map){var values=[];for(var value of map.values())
+values.push(value);return values;}
+function iterMapItems(map,fn,opt_this){opt_this=opt_this||this;for(var key of map.keys())
+fn.call(opt_this,key,map.get(key));}
+return{asArray:asArray,concatenateArrays:concatenateArrays,concatenateObjects:concatenateObjects,compareArrays:compareArrays,comparePossiblyUndefinedValues:comparePossiblyUndefinedValues,compareNumericWithNaNs:compareNumericWithNaNs,cloneDictionary:cloneDictionary,dictionaryLength:dictionaryLength,dictionaryKeys:dictionaryKeys,dictionaryValues:dictionaryValues,dictionaryContainsValue:dictionaryContainsValue,group:group,iterItems:iterItems,mapItems:mapItems,filterItems:filterItems,iterObj [...]
 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_)
@@ -1731,172 +3002,9 @@ return!prevented&&event.rawReturnValue;},hasEventListener:function(type){return
 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 [...]
+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(){var Event;if(tr.isHeadless){function HeadlessEvent(type,opt_bubbles,opt_preventable){this. [...]
+function dispatchSimpleEvent(target,type,opt_bubbles,opt_cancelable){var e=new tr.b.Event(type,opt_bubbles,opt_cancelable);return target.dispatchEvent(e);}
+return{Event:Event,dispatchSimpleEvent:dispatchSimpleEvent};});'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_REGISTRY_MODE:true,TYPE_BASED_REGISTRY_MODE:true};function ExtensionRegistryOptions(mode){if(mode===undefined)
 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_)
@@ -1917,7 +3025,9 @@ return i;return undefined;};registry.unregister=function(constructor){var foundI
 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 extensionRegistryOptions.defaultTypeInfo;};registry.findTypeInfoWithName=function(name){if(typeof(name)!=='string')
+throw new Error('Name is not a string.');var typeInfo=registry.findTypeInfoMatching(function(ti){return ti.constructor.name===name;});if(typeInfo)
+return typeInfo;return undefined;};}
 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 [...]
@@ -1936,32 +3046,203 @@ return{_decorateTypeBasedExtensionRegistry:decorateTypeBasedExtensionRegistry};}
 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)
+return{decorateExtensionRegistry:decorateExtensionRegistry};});'use strict';tr.exportTo('tr.importer',function(){function Importer(){}
+Importer.prototype={__proto__:Object.prototype,get importerName(){return'Importer';},isTraceDataContainer:function(){return false;},extractSubtraces:function(){return[];},importClockSyncMarkers:function(){},importEvents:function(){},importSampleData:function(){},finalizeImport:function(){}};var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);options.defaultMetadata={};options.mandatoryBaseClass=Importer;tr.b.decorateExtensionRegistry(Importer,options);Importer.findImp [...]
+return typeInfo.constructor;return undefined;};return{Importer:Importer};});'use strict';tr.exportTo('tr.e.importer.gcloud_trace',function(){function GcloudTraceImporter(model,eventData){this.importPriority=2;this.eventData_=eventData;}
+GcloudTraceImporter.canImport=function(eventData){if(typeof(eventData)!=='string'&&!(eventData instanceof String))
+return false;var normalizedEventData=eventData.slice(0,20).replace(/\s/g,'');if(normalizedEventData.length<14)
+return false;return normalizedEventData.slice(0,14)=='{"projectId":"';};GcloudTraceImporter.prototype={__proto__:tr.importer.Importer.prototype,get importerName(){return'GcloudTraceImporter';},extractSubtraces:function(){var traceEvents=this.createEventsForTrace();return traceEvents?[traceEvents]:[];},createEventsForTrace:function(){var events=[];var trace=JSON.parse(this.eventData_);var spanLength=trace.spans.length;for(var i=0;i<spanLength;i++){events.push(this.createEventForSpan(trace [...]
+return{'traceEvents':events};},createEventForSpan:function(traceId,span){var newArgs={};if(span.labels){newArgs=JSON.parse(JSON.stringify(span.labels));}
+newArgs['Span ID']=span.spanId;newArgs['Start Time']=span.startTime;newArgs['End Time']=span.endTime;if(span.parentSpanId){newArgs['Parent Span ID']=span.parentSpanId;}
+return{name:span.name,args:newArgs,pid:traceId,ts:Date.parse(span.startTime)*1000,dur:(Date.parse(span.endTime)-Date.parse(span.startTime))*1000,cat:'tracespan',tid:traceId,ph:'X'};}};tr.importer.Importer.register(GcloudTraceImporter);return{GcloudTraceImporter:GcloudTraceImporter};});'use strict';tr.exportTo('tr.b',function(){function convertEventsToRanges(events){return events.map(function(event){return tr.b.Range.fromExplicitRange(event.start,event.end);});}
+function mergeRanges(inRanges,mergeThreshold,mergeFunction){var remainingEvents=inRanges.slice();remainingEvents.sort(function(x,y){return x.min-y.min;});if(remainingEvents.length<=1){var merged=[];if(remainingEvents.length==1){merged.push(mergeFunction(remainingEvents));}
+return merged;}
+var mergedEvents=[];var currentMergeBuffer=[];var rightEdge;function beginMerging(){currentMergeBuffer.push(remainingEvents[0]);remainingEvents.splice(0,1);rightEdge=currentMergeBuffer[0].max;}
+function flushCurrentMergeBuffer(){if(currentMergeBuffer.length==0)
+return;mergedEvents.push(mergeFunction(currentMergeBuffer));currentMergeBuffer=[];if(remainingEvents.length!=0)
+beginMerging();}
+beginMerging();while(remainingEvents.length){var currentEvent=remainingEvents[0];var distanceFromRightEdge=currentEvent.min-rightEdge;if(distanceFromRightEdge<mergeThreshold){rightEdge=Math.max(rightEdge,currentEvent.max);remainingEvents.splice(0,1);currentMergeBuffer.push(currentEvent);continue;}
+flushCurrentMergeBuffer();}
+flushCurrentMergeBuffer();return mergedEvents;}
+function findEmptyRangesBetweenRanges(inRanges,opt_totalRange){if(opt_totalRange&&opt_totalRange.isEmpty)
+opt_totalRange=undefined;var emptyRanges=[];if(!inRanges.length){if(opt_totalRange)
+emptyRanges.push(opt_totalRange);return emptyRanges;}
+inRanges=inRanges.slice();inRanges.sort(function(x,y){return x.min-y.min;});if(opt_totalRange&&(opt_totalRange.min<inRanges[0].min)){emptyRanges.push(tr.b.Range.fromExplicitRange(opt_totalRange.min,inRanges[0].min));}
+inRanges.forEach(function(range,index){for(var otherIndex=0;otherIndex<inRanges.length;++otherIndex){if(index===otherIndex)
+continue;var other=inRanges[otherIndex];if(other.min>range.max){emptyRanges.push(tr.b.Range.fromExplicitRange(range.max,other.min));return;}
+if(other.max>range.max){return;}}
+if(opt_totalRange&&(range.max<opt_totalRange.max)){emptyRanges.push(tr.b.Range.fromExplicitRange(range.max,opt_totalRange.max));}});return emptyRanges;}
+return{convertEventsToRanges:convertEventsToRanges,findEmptyRangesBetweenRanges:findEmptyRangesBetweenRanges,mergeRanges:mergeRanges};});'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.isEmpty_;},addRange:function(range){if(range.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;},get duration(){if(this.isEmpty_)
+return 0;return this.max_-this.min_;},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;},containsExplicitRangeInclusive:function(min,max){if(this.isEmpty)
+return false;return this.min_<=min&&max<=this.max_;},containsExplicitRangeExclusive:function(min,max){if(this.isEmpty)
+return false;return this.min_<min&&max<this.max_;},intersectsExplicitRangeInclusive:function(min,max){if(this.isEmpty)
+return false;return this.min_<=max&&min<=this.max_;},intersectsExplicitRangeExclusive:function(min,max){if(this.isEmpty)
+return false;return this.min_<max&&min<this.max_;},containsRangeInclusive:function(range){if(range.isEmpty)
+return false;return this.containsExplicitRangeInclusive(range.min_,range.max_);},containsRangeExclusive:function(range){if(range.isEmpty)
+return false;return this.containsExplicitRangeExclusive(range.min_,range.max_);},intersectsRangeInclusive:function(range){if(range.isEmpty)
+return false;return this.intersectsExplicitRangeInclusive(range.min_,range.max_);},intersectsRangeExclusive:function(range){if(range.isEmpty)
+return false;return this.intersectsExplicitRangeExclusive(range.min_,range.max_);},findIntersection:function(range){if(this.isEmpty||range.isEmpty)
+return new Range();var min=Math.max(this.min,range.min);var max=Math.min(this.max,range.max);if(max<min)
+return new Range();return Range.fromExplicitRange(min,max);},toJSON:function(){if(this.isEmpty_)
+return{isEmpty:true};return{isEmpty:false,max:this.max,min:this.min};},filterArray:function(array,opt_keyFunc,opt_this){if(this.isEmpty_)
+return[];function binSearch(test){var i0=0;var i1=array.length;while(i0<i1){var i=Math.trunc((i0+i1)/2);if(test(i))
+i1=i;else
+i0=i+1;}
+return i1;}
+var keyFunc=opt_keyFunc||tr.b.identity;function getValue(index){return keyFunc.call(opt_this,array[index]);}
+var first=binSearch(function(i){return this.min_===undefined||this.min_<=getValue(i);}.bind(this));var last=binSearch(function(i){return this.max_!==undefined&&this.max_<getValue(i);}.bind(this));return array.slice(first,last);}};Range.fromDict=function(d){if(d.isEmpty===true){return new Range();}else if(d.isEmpty===false){var range=new Range();range.min=d.min;range.max=d.max;return range;}else{throw new Error('Not a range');}};Range.fromExplicitRange=function(min,max){var range=new Rang [...]
+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 identity(d){return d;}
+function Statistics(){}
+Statistics.divideIfPossibleOrZero=function(numerator,denominator){if(denominator===0)
+return 0;return numerator/denominator;};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.weightedMean=function(ary,weightCallback,opt_valueCallback,opt_this){var valueCallback=opt_valueCallback||identity;var numerator=0;var denominator=0;for(var i=0;i<ary.length;i++){var value=valueCallback.call(opt_this,ary[i],i);if(value===undefined)
+continue;var weight=weightCallback.call(opt_this,ary[i],i,value);numerator+=weight*value;denominator+=weight;}
+if(denominator===0)
+return undefined;return numerator/denominator;};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 Math.sqrt(Statistics.variance(ary,opt_func,opt_this));};Statistics.max=function(ary,opt_func,opt_this){v [...]
+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((a,b)=>a-b);var idx=Math.floor((ary.length-1)*percent);return tmp[idx];};Statistics.clamp=function(value,opt_low,opt_high){opt_low=opt_low||0.0;opt_high=opt_high||1.0;return Math.min(Math.max(value,opt_low),opt_high);};Statistics.normalizeSamples=function(samples){if(samples.length===0){return{normalized_samples:samples,scale:1.0};}
+samples=samples.slice().sort(function(a,b){return a-b;});var low=Math.min.apply(null,samples);var high=Math.max.apply(null,samples);var new_low=0.5/samples.length;var new_high=(samples.length-0.5)/samples.length;if(high-low===0.0){samples=Array.apply(null,new Array(samples.length)).map(function(){return 0.5;});return{normalized_samples:samples,scale:1.0};}
+var scale=(new_high-new_low)/(high-low);for(var i=0;i<samples.length;i++){samples[i]=(samples[i]-low)*scale+new_low;}
+return{normalized_samples:samples,scale:scale};};Statistics.discrepancy=function(samples,opt_location_count){if(samples.length===0)
+return 0.0;var max_local_discrepancy=0;var inv_sample_count=1.0/samples.length;var locations=[];var count_less=[];var count_less_equal=[];if(opt_location_count!==undefined){var sample_index=0;for(var i=0;i<opt_location_count;i++){var location=i/(opt_location_count-1);locations.push(location);while(sample_index<samples.length&&samples[sample_index]<location){sample_index+=1;}
+count_less.push(sample_index);while(sample_index<samples.length&&samples[sample_index]<=location){sample_index+=1;}
+count_less_equal.push(sample_index);}}else{if(samples[0]>0.0){locations.push(0.0);count_less.push(0);count_less_equal.push(0);}
+for(var i=0;i<samples.length;i++){locations.push(samples[i]);count_less.push(i);count_less_equal.push(i+1);}
+if(samples[-1]<1.0){locations.push(1.0);count_less.push(samples.length);count_less_equal.push(samples.length);}}
+for(var i=0;i<locations.length;i++){for(var j=i+1;j<locations.length;j++){var length=locations[j]-locations[i];var count_closed=count_less_equal[j]-count_less[i];var local_discrepancy_closed=Math.abs(count_closed*inv_sample_count-length);var max_local_discrepancy=Math.max(local_discrepancy_closed,max_local_discrepancy);var count_open=count_less[j]-count_less_equal[i];var local_discrepancy_open=Math.abs(count_open*inv_sample_count-length);var max_local_discrepancy=Math.max(local_discrepan [...]
+return max_local_discrepancy;};Statistics.timestampsDiscrepancy=function(timestamps,opt_absolute,opt_location_count){if(timestamps.length===0)
+return 0.0;if(opt_absolute===undefined)
+opt_absolute=true;if(Array.isArray(timestamps[0])){var range_discrepancies=timestamps.map(function(r){return Statistics.timestampsDiscrepancy(r);});return Math.max.apply(null,range_discrepancies);}
+var s=Statistics.normalizeSamples(timestamps);var samples=s.normalized_samples;var sample_scale=s.scale;var discrepancy=Statistics.discrepancy(samples,opt_location_count);var inv_sample_count=1.0/samples.length;if(opt_absolute===true){discrepancy/=sample_scale;}else{discrepancy=Statistics.clamp((discrepancy-inv_sample_count)/(1.0-inv_sample_count));}
+return discrepancy;};Statistics.durationsDiscrepancy=function(durations,opt_absolute,opt_location_count){if(durations.length===0)
+return 0.0;var timestamps=durations.reduce(function(prev,curr,index,array){prev.push(prev[prev.length-1]+curr);return prev;},[0]);return Statistics.timestampsDiscrepancy(timestamps,opt_absolute,opt_location_count);};Statistics.uniformlySampleStream=function(samples,streamLength,newElement,numSamples){if(streamLength<=numSamples){if(samples.length>=streamLength)
+samples[streamLength-1]=newElement;else
+samples.push(newElement);return;}
+var probToKeep=numSamples/streamLength;if(Math.random()>probToKeep)
+return;var index=Math.floor(Math.random()*numSamples);samples[index]=newElement;};Statistics.mergeSampledStreams=function(samplesA,streamLengthA,samplesB,streamLengthB,numSamples){if(streamLengthB<numSamples){var nbElements=Math.min(streamLengthB,samplesB.length);for(var i=0;i<nbElements;++i){Statistics.uniformlySampleStream(samplesA,streamLengthA+i+1,samplesB[i],numSamples);}
+return;}
+if(streamLengthA<numSamples){var nbElements=Math.min(streamLengthA,samplesA.length);var tempSamples=samplesB.slice();for(var i=0;i<nbElements;++i){Statistics.uniformlySampleStream(tempSamples,streamLengthB+i+1,samplesA[i],numSamples);}
+for(var i=0;i<tempSamples.length;++i){samplesA[i]=tempSamples[i];}
+return;}
+var nbElements=Math.min(numSamples,samplesB.length);var probOfSwapping=streamLengthB/(streamLengthA+streamLengthB);for(var i=0;i<nbElements;++i){if(Math.random()<probOfSwapping){samplesA[i]=samplesB[i];}}};return{Statistics:Statistics};});'use strict';tr.exportTo('tr.c',function(){function Auditor(model){this.model_=model;}
+Auditor.prototype={__proto__:Object.prototype,get model(){return this.model_;},runAnnotate:function(){},installUserFriendlyCategoryDriverIfNeeded: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.b',function(){function clamp01(value){return Math.max(0,Math.min(1,value));}
+function Color(opt_r,opt_g,opt_b,opt_a){this.r=Math.floor(opt_r)||0;this.g=Math.floor(opt_g)||0;this.b=Math.floor(opt_b)||0;this.a=opt_a;}
+Color.fromString=function(str){var tmp;var values;if(str.substr(0,4)=='rgb('){tmp=str.substr(4,str.length-5);values=tmp.split(',').map(function(v){return v.replace(/^\s+/,'','g');});if(values.length!=3)
+throw new Error('Malformatted rgb-expression');return new Color(parseInt(values[0]),parseInt(values[1]),parseInt(values[2]));}else if(str.substr(0,5)=='rgba('){tmp=str.substr(5,str.length-6);values=tmp.split(',').map(function(v){return v.replace(/^\s+/,'','g');});if(values.length!=4)
+throw new Error('Malformatted rgb-expression');return new Color(parseInt(values[0]),parseInt(values[1]),parseInt(values[2]),parseFloat(values[3]));}else if(str[0]=='#'&&str.length==7){return new Color(parseInt(str.substr(1,2),16),parseInt(str.substr(3,2),16),parseInt(str.substr(5,2),16));}else{throw new Error('Unrecognized string format.');}};Color.lerp=function(a,b,percent){if(a.a!==undefined&&b.a!==undefined)
+return Color.lerpRGBA(a,b,percent);return Color.lerpRGB(a,b,percent);};Color.lerpRGB=function(a,b,percent){return new Color(((b.r-a.r)*percent)+a.r,((b.g-a.g)*percent)+a.g,((b.b-a.b)*percent)+a.b);};Color.lerpRGBA=function(a,b,percent){return new Color(((b.r-a.r)*percent)+a.r,((b.g-a.g)*percent)+a.g,((b.b-a.b)*percent)+a.b,((b.a-a.a)*percent)+a.a);};Color.fromDict=function(dict){return new Color(dict.r,dict.g,dict.b,dict.a);};Color.fromHSLExplicit=function(h,s,l,a){var r,g,b;function hue [...]
+if(s===0){r=g=b=l;}else{var q=l<0.5?l*(1+s):l+s-l*s;var p=2*l-q;r=hue2rgb(p,q,h+1/3);g=hue2rgb(p,q,h);b=hue2rgb(p,q,h-1/3);}
+return new Color(Math.floor(r*255),Math.floor(g*255),Math.floor(b*255),a);}
+Color.fromHSL=function(hsl){return Color.fromHSLExplicit(hsl.h,hsl.s,hsl.l,hsl.a);}
+Color.prototype={clone:function(){var c=new Color();c.r=this.r;c.g=this.g;c.b=this.b;c.a=this.a;return c;},blendOver:function(bgColor){var oneMinusThisAlpha=1-this.a;var outA=this.a+bgColor.a*oneMinusThisAlpha;var bgBlend=(bgColor.a*oneMinusThisAlpha)/bgColor.a;return new Color(this.r*this.a+bgColor.r*bgBlend,this.g*this.a+bgColor.g*bgBlend,this.b*this.a+bgColor.b*bgBlend,outA);},brighten:function(opt_k){var k;k=opt_k||0.45;return new Color(Math.min(255,this.r+Math.floor(this.r*k)),Math. [...]
+k=opt_k;else
+k=0.45;return new Color(Math.min(255,this.r-Math.floor(this.r*k)),Math.min(255,this.g-Math.floor(this.g*k)),Math.min(255,this.b-Math.floor(this.b*k)),this.a);},desaturate:function(opt_desaturateFactor){var desaturateFactor;if(opt_desaturateFactor!==undefined)
+desaturateFactor=opt_desaturateFactor;else
+desaturateFactor=1;var hsl=this.toHSL();hsl.s=clamp01(hsl.s*(1-desaturateFactor));return Color.fromHSL(hsl);},withAlpha:function(a){return new Color(this.r,this.g,this.b,a);},toString:function(){if(this.a!==undefined){return'rgba('+
+this.r+','+this.g+','+
+this.b+','+this.a+')';}
+return'rgb('+this.r+','+this.g+','+this.b+')';},toHSL:function(){var r=this.r/255;var g=this.g/255;var b=this.b/255;var max=Math.max(r,g,b);var min=Math.min(r,g,b);var h,s;var l=(max+min)/2;if(min===max){h=0;s=0;}else{var delta=max-min;if(l>0.5)
+s=delta/(2-max-min);else
+s=delta/(max+min);if(r===max){h=(g-b)/delta;if(g<b)
+h+=6;}else if(g===max){h=2+((b-r)/delta);}else{h=4+((r-g)/delta);}
+h/=6;}
+return{h:h,s:s,l:l,a:this.a};},toStringWithAlphaOverride:function(alpha){return'rgba('+
+this.r+','+this.g+','+
+this.b+','+alpha+')';}};return{Color:Color};});'use strict';tr.exportTo('tr.b',function(){var generalPurposeColors=[new tr.b.Color(122,98,135),new tr.b.Color(150,83,105),new tr.b.Color(44,56,189),new tr.b.Color(99,86,147),new tr.b.Color(104,129,107),new tr.b.Color(130,178,55),new tr.b.Color(87,109,147),new tr.b.Color(111,145,88),new tr.b.Color(81,152,131),new tr.b.Color(142,91,111),new tr.b.Color(81,163,70),new tr.b.Color(148,94,86),new tr.b.Color(144,89,118),new tr.b.Color(83,150,97),ne [...]
+var paletteBase=[];paletteBase.push.apply(paletteBase,generalPurposeColors);paletteBase.push.apply(paletteBase,tr.b.dictionaryValues(reservedColorsByName));ColorScheme.colors=[];ColorScheme.properties={};ColorScheme.properties={numColorsPerVariant:numColorsPerVariant};function pushVariant(func){var variantColors=paletteBase.map(func);ColorScheme.colors.push.apply(ColorScheme.colors,variantColors);}
+pushVariant(function(c){return c;});ColorScheme.properties.brightenedOffsets=[];ColorScheme.properties.brightenedOffsets.push(ColorScheme.colors.length);pushVariant(function(c){return c.lighten(0.3,0.9);});ColorScheme.properties.brightenedOffsets.push(ColorScheme.colors.length);pushVariant(function(c){return c.lighten(0.48,0.9);});ColorScheme.properties.brightenedOffsets.push(ColorScheme.colors.length);pushVariant(function(c){return c.lighten(0.65,0.9);});ColorScheme.properties.dimmedOff [...]
+throw new Error('Unrecognized color ')+name;return id;};ColorScheme.getColorForReservedNameAsString=function(reservedName){var id=ColorScheme.getColorIdForReservedName(reservedName);return ColorScheme.colorsAsStrings[id];};ColorScheme.getStringHash=function(name){var hash=0;for(var i=0;i<name.length;++i)
+hash=(hash+37*hash+11*name.charCodeAt(i))%0xFFFFFFFF;return hash;};var stringColorIdCache={};ColorScheme.getColorIdForGeneralPurposeString=function(string){if(stringColorIdCache[string]===undefined){var hash=ColorScheme.getStringHash(string);stringColorIdCache[string]=hash%numGeneralPurposeColorIds;}
+return stringColorIdCache[string];};return{ColorScheme:ColorScheme};});'use strict';tr.exportTo('tr.model',function(){var ColorScheme=tr.b.ColorScheme;function EventInfo(title,description,docLinks){this.title=title;this.description=description;this.docLinks=docLinks;this.colorId=ColorScheme.getColorIdForGeneralPurposeString(title);}
+return{EventInfo:EventInfo};});'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.model',function(){function EventRegistry(){}
+var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);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)
+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{EventRegistry:EventRegistry};});'use strict';tr.exportTo('tr.model',function(){var Ev [...]
+this.push(opt_events[i]);}else if(opt_events instanceof EventSet){this.addEventSet(opt_events);}else{this.push(opt_events);}}}
+EventSet.prototype={__proto__:Object.prototype,get bounds(){if(this.bounds_dirty_)
+this.resolveBounds_();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;},resolveBounds_:function(){this.bounds_.reset();for(var i=0;i<this.length_;i++)
+this[i].addBoundsToRange(this.bounds_);this.bounds_dirty_=false;},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];},indexOf:function(event){for(var i=0;i<this.length;i++){if(this[i].guid===event.guid)
+return i;}
+return-1;},addEventSet:function(eventSet){for(var i=0;i<eventSet.length;i++)
+this.push(eventSet[i]);},subEventSet:function(index,count){count=count||1;var eventSet=new EventSet();eventSet.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++)
+eventSet.push(this[i]);return eventSet;},intersectionIsEmpty:function(otherEventSet){return!this.some(function(event){return otherEventSet.contains(event);});},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 allTypeInfos=EventRegistry.getAllRegisteredTypeInfos();var events=this.getEventsOrganizedByCallback(function(event){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');}
+return maxEventTypeInfo.metadata.name;});if(!opt_pruneEmpty){allTypeInfos.forEach(function(eventTypeInfo){if(events[eventTypeInfo.metadata.name]===undefined)
+events[eventTypeInfo.metadata.name]=new EventSet();});}
+return events;},getEventsOrganizedByTitle:function(){return this.getEventsOrganizedByCallback(function(event){if(event.title===undefined)
+throw new Error('An event didn\'t have a title!');return event.title;});},getEventsOrganizedByCallback:function(cb){var eventsByCallback={};for(var i=0;i<this.length;i++){var event=this[i];var key=cb(event);if(key===undefined)
+throw new Error('An event could not be organized');if(eventsByCallback[key]===undefined)
+eventsByCallback[key]=new EventSet();eventsByCallback[key].push(event);}
+return eventsByCallback;},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 event set');}
+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;},filter:function(fn,opt_this){var res=new EventSet();this.forEach(function(slice){if(fn.call(this,slice))
+res.push(slice);},opt_this);return res;},toArray:function(){var ary=[];for(var i=0;i<this.length;i++)
+ary.push(this[i]);return ary;},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;},asDict:function(){var stable_ids=[];this.forEach(function(event){stable_ids.push(event.stableId);});return{'events':stable_ids};}};EventSet.IMMUTABLE_EMPTY_SET=(function(){var s=new EventSet();s.resolveBounds_();s.push=function(){throw new Error('Cannot push to an immutable event set');};s.addEventSet=function(){throw new Error('Cannot add to an immutable event set');};Object.freeze(s);return s;})();return{EventSet:EventSet,RequestSelectionChangeEvent:RequestSe [...]
+var dimmingLevels=[SelectionState.DIMMED0,SelectionState.DIMMED1,SelectionState.DIMMED2];SelectionState.getFromDimmingLevel=function(level){return dimmingLevels[level];}
+return{SelectionState:SelectionState};});'use strict';tr.exportTo('tr.model',function(){var SelectionState=tr.model.SelectionState;function SelectableItem(modelItem){this.modelItem_=modelItem;}
+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 IMMUTABLE_EMPTY_SET=tr.model.EventSet.IMMUTABLE_EMPTY_SET;function Event(){SelectableItem.call(this,this);this.guid_=tr.b.GUID.allocate();this.selectionState=SelectionState.NONE;this.info=undefined;}
+Event.prototype={__proto__:SelectableItem.prototype,get guid(){return this.guid_;},get stableId(){return undefined;},associatedAlerts:IMMUTABLE_EMPTY_SET,addAssociatedAlert:function(alert){if(this.associatedAlerts===IMMUTABLE_EMPTY_SET)
+this.associatedAlerts=new tr.model.EventSet();this.associatedAlerts.push(alert);},addBoundsToRange:function(range){throw new Error('Not implemented');}};return{Event:Event};});'use strict';tr.exportTo('tr.v',function(){var msDisplayMode={scale:1e-3,suffix:'ms',roundedLess:function(a,b){return Math.round(a*1000)<Math.round(b*1000);},format:function(ts){return new Number(ts).toLocaleString(undefined,{minimumFractionDigits:3})+' ms';}};var nsDisplayMode={scale:1e-9,suffix:'ns',roundedLess:f [...]
+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,opt_precisionUnit){if(opt_precisionUnit===undefined)
+opt_precisionUnit=tr.v.TimeDisplayModes.ms;var startsBefore=opt_precisionUnit.roundedLess(that.start,this.start);var endsAfter=opt_precisionUnit.roundedLess(this.end,that.end);return!startsBefore&&!endsAfter;}};return{TimedEvent:TimedEvent};});'use strict';tr.exportTo('tr.v',function(){var TimeDisplayModes=tr.v.TimeDisplayModes;var BINARY_PREFIXES=['','Ki','Mi','Gi','Ti'];var PLUS_MINUS_SIGN=String.fromCharCode(177);function max(a,b){if(a===undefined)
+return b;if(b===undefined)
+return a;return a.scale>b.scale?a:b;}
+var ImprovementDirection={DONT_CARE:0,BIGGER_IS_BETTER:1,SMALLER_IS_BETTER:2};function Unit(unitName,jsonName,isDelta,improvementDirection,formatValue){this.unitName=unitName;this.jsonName=jsonName;this.isDelta=isDelta;this.improvementDirection=improvementDirection;this.formatValue_=formatValue;this.correspondingDeltaUnit=undefined;}
+Unit.prototype={asJSON:function(){return this.jsonName;},format:function(value){var formattedValue=this.formatValue_(value);if(!this.isDelta||value<0)
+return formattedValue;if(value===0)
+return PLUS_MINUS_SIGN+formattedValue;else
+return'+'+formattedValue;}};Unit.reset=function(){Unit.currentTimeDisplayMode=TimeDisplayModes.ms;};Unit.timestampFromUs=function(us){return us/1000;};Unit.maybeTimestampFromUs=function(us){return us===undefined?undefined:us/1000;};Object.defineProperty(Unit,'currentTimeDisplayMode',{get:function(){return Unit.currentTimeDisplayMode_;},set:function(value){if(Unit.currentTimeDisplayMode_===value)
+return;Unit.currentTimeDisplayMode_=value;Unit.dispatchEvent(new tr.b.Event('display-mode-changed'));}});Unit.didPreferredTimeDisplayUnitChange=function(){var largest=undefined;var els=tr.b.findDeepElementsMatching(document.body,'tr-v-ui-preferred-display-unit');els.forEach(function(el){largest=max(largest,el.preferredTimeDisplayMode);});Unit.currentDisplayUnit=largest===undefined?TimeDisplayModes.ms:largest;};Unit.byName={};Unit.byJSONName={};Unit.fromJSON=function(object){var u=Unit.by [...]
+throw new Error('Unrecognized unit');};Unit.define=function(params){tr.b.iterItems(ImprovementDirection,function(_,improvementDirection){var regularUnit=Unit.defineUnitVariant_(params,false,improvementDirection);var deltaUnit=Unit.defineUnitVariant_(params,true,improvementDirection);regularUnit.correspondingDeltaUnit=deltaUnit;deltaUnit.correspondingDeltaUnit=deltaUnit;});};Unit.defineUnitVariant_=function(params,isDelta,improvementDirection){var nameSuffix=isDelta?'Delta':'';switch(impr [...]
+var unitName=params.baseUnitName+nameSuffix;var jsonName=params.baseJsonName+nameSuffix;if(Unit.byName[unitName]!==undefined)
+throw new Error('Unit \''+unitName+'\' already exists');if(Unit.byJSONName[jsonName]!==undefined)
+throw new Error('JSON unit \''+jsonName+'\' alread exists');var unit=new Unit(unitName,jsonName,isDelta,improvementDirection,params.formatValue);Unit.byName[unitName]=unit;Unit.byJSONName[jsonName]=unit;return unit;};tr.b.EventTarget.decorate(Unit);Unit.reset();Unit.define({baseUnitName:'timeDurationInMs',baseJsonName:'ms',formatValue:function(value){return Unit.currentTimeDisplayMode_.format(value);}});Unit.define({baseUnitName:'timeStampInMs',baseJsonName:'tsMs',formatValue:function(va [...]
+var i=0;while(value>=1024&&i<BINARY_PREFIXES.length-1){value/=1024;i++;}
+return signPrefix+value.toFixed(1)+' '+BINARY_PREFIXES[i]+'B';}});Unit.define({baseUnitName:'energyInJoules',baseJsonName:'J',formatValue:function(value){return value.toLocaleString(undefined,{minimumFractionDigits:3})+' J';}});Unit.define({baseUnitName:'powerInWatts',baseJsonName:'W',formatValue:function(value){return value.toLocaleString(undefined,{minimumFractionDigits:3})+' W';}});Unit.define({baseUnitName:'unitlessNumber',baseJsonName:'unitless',formatValue:function(value){return va [...]
+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.v.Unit.byName.timeStampInMs.format(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(){var ColorScheme=tr.b.ColorScheme;var Statistics=tr.b.Statistics;var FRAME_PERF_CLASS={GOOD:'good',BAD:'bad',TERRIBLE:'terrible',NEUTRAL:'generic_work'};function Frame(associatedEvents,threadTimeRanges,o [...]
 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 findHighIndexInSortedArray(ary,mapFn,loVal,hiVal){var lo=loVal||0;var hi=hiVal!==undefined?hiVal:ary.length;while(lo<hi){var mid=(lo+hi)>>1;if(mapFn(ary[mid])>=0)
+lo=mid+1;else
+hi=mid;}
+return hi;}
 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;}}
@@ -1984,124 +3265,710 @@ loInt=ary[idx+1];var loDiff=Math.abs(val-mapLoFn(loInt));var hiDiff=Math.abs(val
 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 [...]
+return{findLowIndexInSortedArray:findLowIndexInSortedArray,findHighIndexInSortedArray:findHighIndexInSortedArray,findIndexInSortedIntervals:findIndexInSortedIntervals,findIndexInSortedClosedIntervals:findIndexInSortedClosedIntervals,iterateOverIntersectingIntervals:iterateOverIntersectingIntervals,getIntersectingIntervals:getIntersectingIntervals,findClosestElementInSortedArray:findClosestElementInSortedArray,findClosestIntervalInSortedIntervals:findClosestIntervalInSortedIntervals};});' [...]
+function makeFrame(threadTimeRanges,surfaceFlinger){var args={};if(surfaceFlinger&&surfaceFlinger.hasVsyncs){var start=Statistics.min(threadTimeRanges,function(threadTimeRanges){return threadTimeRanges.start;});args['deadline']=surfaceFlinger.getFrameDeadline(start);args['frameKickoff']=surfaceFlinger.getFrameKickoff(start);}
+var events=getSlicesForThreadTimeRanges(threadTimeRanges);return new Frame(events,threadTimeRanges,args);}
+function findOverlappingDrawFrame(renderThread,time){if(!renderThread)
+return undefined;var slices=renderThread.sliceGroup.slices;for(var i=0;i<slices.length;i++){var slice=slices[i];if(slice.title==RENDER_THREAD_DRAW_NAME&&slice.start<=time&&time<=slice.end){return slice;}}
+return undefined;}
+function getPreTraversalWorkRanges(uiThread){if(!uiThread)
+return[];var preFrameEvents=[];uiThread.sliceGroup.slices.forEach(function(slice){if(slice.title=='obtainView'||slice.title=='setupListItem'||slice.title=='deliverInputEvent'||slice.title=='RV Scroll')
+preFrameEvents.push(slice);});uiThread.asyncSliceGroup.slices.forEach(function(slice){if(slice.title=='deliverInputEvent')
+preFrameEvents.push(slice);});return tr.b.mergeRanges(tr.b.convertEventsToRanges(preFrameEvents),3,function(events){return{start:events[0].min,end:events[events.length-1].max};});}
+function getFrameStartTime(traversalStart,preTraversalWorkRanges){var preTraversalWorkRange=tr.b.findClosestIntervalInSortedIntervals(preTraversalWorkRanges,function(range){return range.start},function(range){return range.end},traversalStart,3);if(preTraversalWorkRange)
+return preTraversalWorkRange.start;return traversalStart;}
+function getUiThreadDrivenFrames(app){if(!app.uiThread)
+return[];var preTraversalWorkRanges=[];if(app.uiDrawType==UI_DRAW_TYPE.LEGACY)
+preTraversalWorkRanges=getPreTraversalWorkRanges(app.uiThread);var frames=[];app.uiThread.sliceGroup.slices.forEach(function(slice){if(!(slice.title in UI_THREAD_DRAW_NAMES)){return;}
+var threadTimeRanges=[];var uiThreadTimeRange={thread:app.uiThread,start:getFrameStartTime(slice.start,preTraversalWorkRanges),end:slice.end};threadTimeRanges.push(uiThreadTimeRange);var rtDrawSlice=findOverlappingDrawFrame(app.renderThread,slice.end);if(rtDrawSlice){var rtSyncSlice=rtDrawSlice.findDescendentSlice(THREAD_SYNC_NAME);if(rtSyncSlice){uiThreadTimeRange.end=Math.min(uiThreadTimeRange.end,rtSyncSlice.start);}
+threadTimeRanges.push({thread:app.renderThread,start:rtDrawSlice.start,end:rtDrawSlice.end});}
+frames.push(makeFrame(threadTimeRanges,app.surfaceFlinger));});return frames;}
+function getRenderThreadDrivenFrames(app){if(!app.renderThread)
+return[];var frames=[];app.renderThread.sliceGroup.getSlicesOfName(RENDER_THREAD_INDEP_DRAW_NAME).forEach(function(slice){var threadTimeRanges=[{thread:app.renderThread,start:slice.start,end:slice.end}];frames.push(makeFrame(threadTimeRanges,app.surfaceFlinger));});return frames;}
+function getUiDrawType(uiThread){if(!uiThread)
+return UI_DRAW_TYPE.NONE;var slices=uiThread.sliceGroup.slices;for(var i=0;i<slices.length;i++){if(slices[i].title in UI_THREAD_DRAW_NAMES){return UI_THREAD_DRAW_NAMES[slices[i].title];}}
+return UI_DRAW_TYPE.NONE;}
+function getInputSamples(process){var samples=undefined;for(var counterName in process.counters){if(/^android\.aq\:pending/.test(counterName)&&process.counters[counterName].numSeries==1){samples=process.counters[counterName].series[0].samples;break;}}
+if(!samples)
+return[];var inputSamples=[];var lastValue=0;samples.forEach(function(sample){if(sample.value>lastValue){inputSamples.push(sample);}
+lastValue=sample.value;});return inputSamples;}
+function getAnimationAsyncSlices(uiThread){if(!uiThread)
+return[];var slices=[];uiThread.asyncSliceGroup.iterateAllEvents(function(slice){if(/^animator\:/.test(slice.title))
+slices.push(slice);});return slices;}
+function AndroidApp(process,uiThread,renderThread,surfaceFlinger,uiDrawType){this.process=process;this.uiThread=uiThread;this.renderThread=renderThread;this.surfaceFlinger=surfaceFlinger;this.uiDrawType=uiDrawType;this.frames_=undefined;this.inputs_=undefined;};AndroidApp.createForProcessIfPossible=function(process,surfaceFlinger){var uiThread=process.getThread(process.pid);var uiDrawType=getUiDrawType(uiThread);if(uiDrawType==UI_DRAW_TYPE.NONE){uiThread=undefined;}
+var renderThreads=process.findAllThreadsNamed('RenderThread');var renderThread=renderThreads.length==1?renderThreads[0]:undefined;if(uiThread||renderThread){return new AndroidApp(process,uiThread,renderThread,surfaceFlinger,uiDrawType);}};AndroidApp.prototype={getFrames:function(){if(!this.frames_){var uiFrames=getUiThreadDrivenFrames(this);var rtFrames=getRenderThreadDrivenFrames(this);this.frames_=uiFrames.concat(rtFrames);this.frames_.sort(function(a,b){a.end-b.end});}
+return this.frames_;},getInputSamples:function(){if(!this.inputs_){this.inputs_=getInputSamples(this.process);}
+return this.inputs_;},getAnimationAsyncSlices:function(){if(!this.animations_){this.animations_=getAnimationAsyncSlices(this.uiThread);}
+return this.animations_;}};return{AndroidApp:AndroidApp};});'use strict';tr.exportTo('tr.model.helpers',function(){var findLowIndexInSortedArray=tr.b.findLowIndexInSortedArray;var VSYNC_SF_NAME='android.VSYNC-sf';var VSYNC_APP_NAME='android.VSYNC-app';var VSYNC_FALLBACK_NAME='android.VSYNC';var TIMESTAMP_FUDGE_MS=0.01;function getVsyncTimestamps(process,counterName){var vsync=process.counters[counterName];if(!vsync)
+vsync=process.counters[VSYNC_FALLBACK_NAME];if(vsync&&vsync.numSeries==1&&vsync.numSamples>1)
+return vsync.series[0].timestamps;return undefined;}
+function AndroidSurfaceFlinger(process,thread){this.process=process;this.thread=thread;this.appVsync_=undefined;this.sfVsync_=undefined;this.appVsyncTimestamps_=getVsyncTimestamps(process,VSYNC_APP_NAME);this.sfVsyncTimestamps_=getVsyncTimestamps(process,VSYNC_SF_NAME);};AndroidSurfaceFlinger.createForProcessIfPossible=function(process){var mainThread=process.getThread(process.pid);if(mainThread&&mainThread.name&&/surfaceflinger/.test(mainThread.name))
+return new AndroidSurfaceFlinger(process,mainThread);var primaryThreads=process.findAllThreadsNamed('SurfaceFlinger');if(primaryThreads.length==1)
+return new AndroidSurfaceFlinger(process,primaryThreads[0]);return undefined;};AndroidSurfaceFlinger.prototype={get hasVsyncs(){return!!this.appVsyncTimestamps_&&!!this.sfVsyncTimestamps_;},getFrameKickoff:function(timestamp){if(!this.hasVsyncs)
+throw new Error('cannot query vsync info without vsyncs');var firstGreaterIndex=findLowIndexInSortedArray(this.appVsyncTimestamps_,function(x){return x;},timestamp+TIMESTAMP_FUDGE_MS);if(firstGreaterIndex<1)
+return undefined;return this.appVsyncTimestamps_[firstGreaterIndex-1];},getFrameDeadline:function(timestamp){if(!this.hasVsyncs)
+throw new Error('cannot query vsync info without vsyncs');var firstGreaterIndex=findLowIndexInSortedArray(this.sfVsyncTimestamps_,function(x){return x;},timestamp+TIMESTAMP_FUDGE_MS);if(firstGreaterIndex>=this.sfVsyncTimestamps_.length)
+return undefined;return this.sfVsyncTimestamps_[firstGreaterIndex];}};return{AndroidSurfaceFlinger:AndroidSurfaceFlinger};});'use strict';tr.exportTo('tr.model.helpers',function(){var AndroidApp=tr.model.helpers.AndroidApp;var AndroidSurfaceFlinger=tr.model.helpers.AndroidSurfaceFlinger;var IMPORTANT_SURFACE_FLINGER_SLICES={'doComposition':true,'updateTexImage':true,'postFramebuffer':true};var IMPORTANT_UI_THREAD_SLICES={'Choreographer#doFrame':true,'performTraversals':true,'deliverInput [...]
+return;thread.sliceGroup.slices.forEach(function(slice){if(slice.title in important)
+callback(slice);});}
+function AndroidModelHelper(model){this.model=model;this.apps=[];this.surfaceFlinger=undefined;var processes=model.getAllProcesses();for(var i=0;i<processes.length&&!this.surfaceFlinger;i++){this.surfaceFlinger=AndroidSurfaceFlinger.createForProcessIfPossible(processes[i]);}
+model.getAllProcesses().forEach(function(process){var app=AndroidApp.createForProcessIfPossible(process,this.surfaceFlinger);if(app)
+this.apps.push(app);},this);};AndroidModelHelper.guid=tr.b.GUID.allocate();AndroidModelHelper.supportsModel=function(model){return true;};AndroidModelHelper.prototype={iterateImportantSlices:function(callback){if(this.surfaceFlinger){iterateImportantThreadSlices(this.surfaceFlinger.thread,IMPORTANT_SURFACE_FLINGER_SLICES,callback);}
+this.apps.forEach(function(app){iterateImportantThreadSlices(app.uiThread,IMPORTANT_UI_THREAD_SLICES,callback);iterateImportantThreadSlices(app.renderThread,IMPORTANT_RENDER_THREAD_SLICES,callback);});}};return{AndroidModelHelper:AndroidModelHelper};});'use strict';tr.exportTo('tr.model',function(){function Slice(category,title,colorId,start,args,opt_duration,opt_cpuStart,opt_cpuDuration,opt_argsStripped,opt_bind_id){tr.model.TimedEvent.call(this,start);this.category=category||'';this.ti [...]
+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.v.Unit.byName.timeStampInMs.format(this.start);},get stableId(){var parentSliceGroup=this.parentContainer.sliceGroup;return parentSliceGroup.stableId+'.'+
+parentSliceGroup.slices.indexOf(this);},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;},getProcess:function(){var thread=this.parentContainer;if(thread&&thread.getProcess)
+return thread.getProcess();return undefined;},get model(){var process=this.getProcess();if(process!==undefined)
+return this.getProcess().model;return undefined;},findTopmostSlicesRelativeToThisSlice:function(eventPredicate,callback,opt_this){if(eventPredicate(this)){callback.call(opt_this,this);return;}
+this.subSlices.forEach(function(s){s.findTopmostSlicesRelativeToThisSlice(eventPredicate,callback,opt_this);});},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.b.ColorScheme.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.EXI [...]
+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 CompoundEventSelectionState={NOT_SELECTED:0,EVENT_SELECTED:0x1,SOME_ASSOCIATED_EVENTS_ [...]
+UserExpectation.prototype={__proto__:tr.model.TimedEvent.prototype,computeCompoundEvenSelectionState:function(selection){var cess=CompoundEventSelectionState.NOT_SELECTED;if(selection.contains(this))
+cess|=CompoundEventSelectionState.EVENT_SELECTED;if(this.associatedEvents.intersectionIsEmpty(selection))
+return cess;var allContained=this.associatedEvents.every(function(event){return selection.contains(event);});if(allContained)
+cess|=CompoundEventSelectionState.ALL_ASSOCIATED_EVENTS_SELECTED;else
+cess|=CompoundEventSelectionState.SOME_ASSOCIATED_EVENTS_SELECTED;return cess;},get associatedSamples(){var samples=new tr.model.EventSet();this.associatedEvents.forEach(function(event){if(event instanceof tr.model.ThreadSlice)
+samples.addEventSet(event.overlappingSamples);});return samples;},get userFriendlyName(){return this.title+' User Expectation at '+
+tr.v.Unit.byName.timeStampInMs.format(this.start);},get stableId(){return('UserExpectation.'+
+this.parentModel.userModel.expectations.indexOf(this));},get typeInfo(){if(!this.typeInfo_)
+this.typeInfo_=UserExpectation.findTypeInfo(this.constructor);if(!this.typeInfo_)
+throw new Error('Unregistered UserExpectation');return this.typeInfo_;},get colorId(){return this.typeInfo.metadata.colorId;},get stageTitle(){return this.typeInfo.metadata.stageTitle;},get initiatorTitle(){return this.initiatorTitle_;},get title(){if(!this.initiatorTitle)
+return this.stageTitle;return this.initiatorTitle+' '+this.stageTitle;},get totalCpuMs(){var cpuMs=0;this.associatedEvents.forEach(function(event){if(event.cpuSelfTime)
+cpuMs+=event.cpuSelfTime;});return cpuMs;}};var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);tr.b.decorateExtensionRegistry(UserExpectation,options);UserExpectation.addEventListener('will-register',function(e){var metadata=e.typeInfo.metadata;if(metadata.stageTitle===undefined){throw new Error('Registered UserExpectations must provide '+'stageTitle');}
+if(metadata.colorId===undefined){throw new Error('Registered UserExpectations must provide '+'colorId');}});tr.model.EventRegistry.register(UserExpectation,{name:'user-expectation',pluralName:'user-expectations',singleViewElementName:'tr-ui-a-single-user-expectation-sub-view',multiViewElementName:'tr-ui-a-multi-user-expectation-sub-view'});return{UserExpectation:UserExpectation};});'use strict';tr.exportTo('tr.model.um',function(){function ResponseExpectation(parentModel,initiatorTitle,s [...]
+ResponseExpectation.prototype={__proto__:tr.model.um.UserExpectation.prototype,constructor:ResponseExpectation};tr.model.um.UserExpectation.register(ResponseExpectation,{stageTitle:'Response',colorId:tr.b.ColorScheme.getColorIdForReservedName('rail_response')});return{ResponseExpectation:ResponseExpectation};});'use strict';tr.exportTo('tr.v',function(){var Range=tr.b.Range;var MAX_SOURCE_INFOS=16;function NumericBase(unit){if(!(unit instanceof tr.v.Unit))
+throw new Error('Expected provided unit to be instance of Unit');this.unit=unit;}
+NumericBase.prototype={asDict:function(){var d={unit:this.unit.asJSON()};this.asDictInto_(d);return d;}};NumericBase.fromDict=function(d){if(d.type==='scalar')
+return ScalarNumeric.fromDict(d);throw new Error('Not implemented');};function NumericBin(parentNumeric,opt_range){this.parentNumeric=parentNumeric;this.range=opt_range||(new tr.b.Range());this.count=0;this.sourceInfos=[];}
+NumericBin.fromDict=function(parentNumeric,d){var n=new NumericBin(parentNumeric);n.range.min=d.min;n.range.max=d.max;n.count=d.count;n.sourceInfos=d.sourceInfos;return n;};NumericBin.prototype={add:function(value,sourceInfo){this.count+=1;tr.b.Statistics.uniformlySampleStream(this.sourceInfos,this.count,sourceInfo,MAX_SOURCE_INFOS);},addBin:function(other){if(!this.range.equals(other.range))
+throw new Error('Merging incompatible Numeric bins.');tr.b.Statistics.mergeSampledStreams(this.sourceInfos,this.count,other.sourceInfos,other.count,MAX_SOURCE_INFOS);this.count+=other.count;},asDict:function(){return{min:this.range.min,max:this.range.max,count:this.count,sourceInfos:this.sourceInfos.slice(0)};},asJSON:function(){return this.asDict();}};function Numeric(unit,range,binInfo){NumericBase.call(this,unit);this.range=range;this.numNans=0;this.nanSourceInfos=[];this.runningSum=0 [...]
+this.maxCount_=bin.count;},this);}
+Numeric.fromDict=function(d){var range=Range.fromExplicitRange(d.min,d.max);var binInfo={};binInfo.underflowBin=NumericBin.fromDict(undefined,d.underflowBin);binInfo.centralBins=d.centralBins.map(function(binAsDict){return NumericBin.fromDict(undefined,binAsDict);});binInfo.overflowBin=NumericBin.fromDict(undefined,d.overflowBin);var n=new Numeric(tr.v.Unit.fromJSON(d.unit),range,binInfo);n.allBins.forEach(function(bin){bin.parentNumeric=n;});n.runningSum=d.runningSum;n.numNans=d.numNans [...]
+throw new Error('percent must be [0,1]');if(this.numValues==0)
+return 0;var valuesToSkip=Math.floor((this.numValues-1)*percent);for(var i=0;i<this.allBins.length;i++){var bin=this.allBins[i];valuesToSkip-=bin.count;if(valuesToSkip<0){if(bin===this.underflowBin)
+return bin.range.max;else if(bin===this.overflowBin)
+return bin.range.min;else
+return bin.range.center;}}
+throw new Error('Unreachable');},getInterpolatedCountAt:function(value){var bin=this.getBinForValue(value);var idx=this.centralBins.indexOf(bin);if(idx<0){return bin.count;}
+var lesserBin=bin;var greaterBin=bin;var lesserBinCenter=undefined;var greaterBinCenter=undefined;if(value<greaterBin.range.center){if(idx>0){lesserBin=this.centralBins[idx-1];}else{lesserBin=this.underflowBin;lesserBinCenter=lesserBin.range.max;}}else{if(idx<(this.centralBins.length-1)){greaterBin=this.centralBins[idx+1];}else{greaterBin=this.overflowBin;greaterBinCenter=greaterBin.range.min;}}
+if(greaterBinCenter===undefined)
+greaterBinCenter=greaterBin.range.center;if(lesserBinCenter===undefined)
+lesserBinCenter=lesserBin.range.center;value=tr.b.normalize(value,lesserBinCenter,greaterBinCenter);return tr.b.lerp(value,lesserBin.count,greaterBin.count);},getBinForValue:function(value){var binIndex=tr.b.findHighIndexInSortedArray(this.allBins,b=>value<b.range.max?-1:1);return this.allBins[binIndex]||this.overflowBin;},add:function(value,sourceInfo){if(typeof(value)!=='number'||isNaN(value)){this.numNans++;tr.b.Statistics.uniformlySampleStream(this.nanSourceInfos,this.numNans,sourceI [...]
+var bin=this.getBinForValue(value);bin.add(value,sourceInfo);this.runningSum+=value;if(bin.count>this.maxCount_)
+this.maxCount_=bin.count;},addNumeric:function(other){if(!this.range.equals(other.range)||!this.unit===other.unit||this.allBins.length!==other.allBins.length){throw new Error('Merging incompatible Numerics.');}
+tr.b.Statistics.mergeSampledStreams(this.nanSourceInfos,this.numNans,other.nanSourceInfos,other.numNans,MAX_SOURCE_INFOS);this.numNans+=other.numNans;this.runningSum+=other.runningSum;for(var i=0;i<this.allBins.length;++i){this.allBins[i].addBin(other.allBins[i]);}},clone:function(){return Numeric.fromDict(this.asDict());},asDict:function(){var d={unit:this.unit.asJSON(),type:'numeric',min:this.range.min,max:this.range.max,numNans:this.numNans,nanSourceInfos:this.nanSourceInfos,runningSu [...]
+NumericBuilder.prototype={get minBinBoundary(){return this.boundaries_[0];},get maxBinBoundary(){return this.boundaries_[this.boundaries_.length-1];},addBinBoundary:function(nextMaxBinBoundary){if(nextMaxBinBoundary<=this.maxBinBoundary){throw new Error('The added max bin boundary must be larger than '+'the current max boundary');}
+this.boundaries_.push(nextMaxBinBoundary);return this;},addLinearBins:function(nextMaxBinBoundary,binCount){if(binCount<=0)
+throw new Error('Bin count must be positive');var curMaxBinBoundary=this.maxBinBoundary;if(curMaxBinBoundary>=nextMaxBinBoundary){throw new Error('The last added max boundary must be greater than '+'the current max boundary boundary');}
+var binWidth=(nextMaxBinBoundary-curMaxBinBoundary)/binCount;for(var i=1;i<binCount;i++)
+this.addBinBoundary(curMaxBinBoundary+i*binWidth);this.addBinBoundary(nextMaxBinBoundary);return this;},addExponentialBins:function(nextMaxBinBoundary,binCount){if(binCount<=0)
+throw new Error('Bin count must be positive');var curMaxBinBoundary=this.maxBinBoundary;if(curMaxBinBoundary<=0)
+throw new Error('Current max bin boundary must be positive');if(curMaxBinBoundary>=nextMaxBinBoundary){throw new Error('The last added max boundary must be greater than '+'the current max boundary boundary');}
+var binExponentWidth=Math.log(nextMaxBinBoundary/curMaxBinBoundary)/binCount;for(var i=1;i<binCount;i++){this.addBinBoundary(curMaxBinBoundary*Math.exp(i*binExponentWidth));}
+this.addBinBoundary(nextMaxBinBoundary);return this;},build:function(){var binInfo={underflowBin:new NumericBin(undefined,Range.fromExplicitRange(-Number.MAX_VALUE,this.minBinBoundary)),overflowBin:new NumericBin(undefined,Range.fromExplicitRange(this.maxBinBoundary,Number.MAX_VALUE)),centralBins:new Array(this.boundaries_.length-1)};for(var i=0;i<this.boundaries_.length-1;i++){binInfo.centralBins[i]=new NumericBin(undefined,Range.fromExplicitRange(this.boundaries_[i],this.boundaries_[i+1]));}
+var numeric=new Numeric(this.unit_,Range.fromExplicitRange(this.minBinBoundary,this.maxBinBoundary),binInfo);numeric.allBins.forEach(function(bin){bin.parentNumeric=numeric;});return numeric;}};NumericBuilder.createLinear=function(unit,range,numBins){if(range.isEmpty)
+throw new Error('Range must be non-empty');return new NumericBuilder(unit,range.min).addLinearBins(range.max,numBins);};function ScalarNumeric(unit,value){if(!(typeof(value)=='number'))
+throw new Error('Expected value to be number');NumericBase.call(this,unit);this.value=value;}
+ScalarNumeric.prototype={__proto__:NumericBase.prototype,asDictInto_:function(d){d.type='scalar';d.value=this.value;},toString:function(){return this.unit.format(this.value);}};ScalarNumeric.fromDict=function(d){return new ScalarNumeric(tr.v.Unit.fromJSON(d.unit),d.value);};return{NumericBase:NumericBase,NumericBin:NumericBin,Numeric:Numeric,NumericBuilder:NumericBuilder,ScalarNumeric:ScalarNumeric};});'use strict';tr.exportTo('tr.e.audits',function(){var SCHEDULING_STATE=tr.model.SCHEDU [...]
+function getDuration(e){return e.duration;}
+function getCpuDuration(e){return(e.cpuDuration!==undefined)?e.cpuDuration:e.duration;}
+function frameIsActivityStart(frame){for(var i=0;i<frame.associatedEvents.length;i++){if(frame.associatedEvents[i].title=='activityStart')
+return true;}
+return false;}
+function frameMissedDeadline(frame){return frame.args['deadline']&&frame.args['deadline']<frame.end;}
+function DocLinkBuilder(){this.docLinks=[];}
+DocLinkBuilder.prototype={addAppVideo:function(name,videoId){this.docLinks.push({label:'Video Link',textContent:('Android Performance Patterns: '+name),href:'https://www.youtube.com/watch?list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&v='+videoId});return this;},addDacRef:function(name,link){this.docLinks.push({label:'Doc Link',textContent:(name+' documentation'),href:'https://developer.android.com/reference/'+link});return this;},build:function(){return this.docLinks;}};function AndroidAuditor [...]
+this.helper=helper;};AndroidAuditor.viewAlphaAlertInfo_=new EventInfo('Inefficient View alpha usage','Setting an alpha between 0 and 1 has significant performance costs, if one of the fast alpha paths is not used.',new DocLinkBuilder().addAppVideo('Hidden Cost of Transparency','wIy8g8yNhNk').addDacRef('View#setAlpha()','android/view/View.html#setAlpha(float)').build());AndroidAuditor.saveLayerAlertInfo_=new EventInfo('Expensive rendering with Canvas#saveLayer()','Canvas#saveLayer() incur [...]
+events.push(slice);},this);if(events.length>ret.length){var unclippedSeen=Statistics.sum(events,function(slice){return saveLayerRegEx.exec(slice.title)[1]?1:0;});var clippedSeen=events.length-unclippedSeen;var earliestStart=Statistics.min(events,function(slice){return slice.start;});var args={'Unclipped saveLayer count (especially bad!)':unclippedSeen,'Clipped saveLayer count':clippedSeen};events.push(frame);ret.push(new Alert(AndroidAuditor.saveLayerAlertInfo_,earliestStart,events,args));}
+return ret;};AndroidAuditor.pathAlertInfo_=new EventInfo('Path texture churn','Paths are drawn with a mask texture, so when a path is modified / newly drawn, that texture must be generated and uploaded to the GPU. Ensure that you cache paths between frames and do not unnecessarily call Path#reset(). You can cut down on this cost by sharing Path object instances between drawables/views.');AndroidAuditor.getPathAlert_=function(frame){var uploadRegEx=/^Generate Path Texture$/;var events=fra [...]
+return undefined;events.push(frame);return new Alert(AndroidAuditor.pathAlertInfo_,start,events,{'Time spent':new ScalarNumeric(timeDurationInMs,duration)});};AndroidAuditor.uploadAlertInfo_=new EventInfo('Expensive Bitmap uploads','Bitmaps that have been modified / newly drawn must be uploaded to the GPU. Since this is expensive if the total number of pixels uploaded is large, reduce the amount of Bitmap churn in this animation/context, per frame.');AndroidAuditor.getUploadAlert_=functi [...]
+return undefined;var mPixels=(pixelsUploaded/1000000).toFixed(2)+' million';var args={'Pixels uploaded':mPixels,'Time spent':new ScalarNumeric(timeDurationInMs,duration)};events.push(frame);return new Alert(AndroidAuditor.uploadAlertInfo_,start,events,args);};AndroidAuditor.ListViewInflateAlertInfo_=new EventInfo('Inflation during ListView recycling','ListView item recycling involved inflating views. Ensure your Adapter#getView() recycles the incoming View, instead of constructing a new  [...]
+return undefined;var hasInflation=false;for(var i=0;i<events.length;i++){if(events[i]instanceof tr.model.Slice&&events[i].findDescendentSlice('inflate')){hasInflation=true;break;}}
+var start=Statistics.min(events,getStart);var args={'Time spent':new ScalarNumeric(timeDurationInMs,duration)};args['ListView items '+(hasInflation?'inflated':'rebound')]=events.length/2;var eventInfo=hasInflation?AndroidAuditor.ListViewInflateAlertInfo_:AndroidAuditor.ListViewBindAlertInfo_;events.push(frame);return new Alert(eventInfo,start,events,args);};AndroidAuditor.measureLayoutAlertInfo_=new EventInfo('Expensive measure/layout pass','Measure/Layout took a significant time, contri [...]
+return undefined;var start=Statistics.min(events,getStart);events.push(frame);return new Alert(AndroidAuditor.measureLayoutAlertInfo_,start,events,{'Time spent':new ScalarNumeric(timeDurationInMs,duration)});};AndroidAuditor.viewDrawAlertInfo_=new EventInfo('Long View#draw()','Recording the drawing commands of invalidated Views took a long time. Avoid significant work in View or Drawable custom drawing, especially allocations or drawing to Bitmaps.',new DocLinkBuilder().addAppVideo('Inva [...]
+if(!slice||getCpuDuration(slice)<3)
+return undefined;return new Alert(AndroidAuditor.viewDrawAlertInfo_,slice.start,[slice,frame],{'Time spent':new ScalarNumeric(timeDurationInMs,getCpuDuration(slice))});};AndroidAuditor.blockingGcAlertInfo_=new EventInfo('Blocking Garbage Collection','Blocking GCs are caused by object churn, and made worse by having large numbers of objects in the heap. Avoid allocating objects during animations/scrolling, and recycle Bitmaps to avoid triggering garbage collection.',new DocLinkBuilder().a [...]
+return undefined;var start=Statistics.min(events,getStart);events.push(frame);return new Alert(AndroidAuditor.blockingGcAlertInfo_,start,events,{'Blocked duration':new ScalarNumeric(timeDurationInMs,blockedDuration)});};AndroidAuditor.lockContentionAlertInfo_=new EventInfo('Lock contention','UI thread lock contention is caused when another thread holds a lock that the UI thread is trying to use. UI thread progress is blocked until the lock is released. Inspect locking done within the UI  [...]
+return undefined;var start=Statistics.min(events,getStart);events.push(frame);return new Alert(AndroidAuditor.lockContentionAlertInfo_,start,events,{'Blocked duration':new ScalarNumeric(timeDurationInMs,blockedDuration)});};AndroidAuditor.schedulingAlertInfo_=new EventInfo('Scheduling delay','Work to produce this frame was descheduled for several milliseconds, contributing to jank. Ensure that code on the UI thread doesn\'t block on work being done on other threads, and that background t [...]
+totalStats[key]=0;totalStats[key]+=value;totalDuration+=value;});});if(!(SCHEDULING_STATE.RUNNING in totalStats)||totalDuration==0||totalDuration-totalStats[SCHEDULING_STATE.RUNNING]<3)
+return;var args={};tr.b.iterItems(totalStats,function(key,value){if(key===SCHEDULING_STATE.RUNNABLE)
+key='Not scheduled, but runnable';else if(key===SCHEDULING_STATE.UNINTR_SLEEP)
+key='Blocking I/O delay';args[key]=new ScalarNumeric(timeDurationInMs,value);});return new Alert(AndroidAuditor.schedulingAlertInfo_,frame.start,[frame],args);};AndroidAuditor.prototype={__proto__:Auditor.prototype,renameAndSort_:function(){this.model.kernel.important=false;this.model.getAllProcesses().forEach(function(process){if(this.helper.surfaceFlinger&&process==this.helper.surfaceFlinger.process){if(!process.name)
+process.name='SurfaceFlinger';process.sortIndex=Number.NEGATIVE_INFINITY;process.important=false;return;}
+var uiThread=process.getThread(process.pid);if(!process.name&&uiThread&&uiThread.name){if(/^ndroid\./.test(uiThread.name))
+uiThread.name='a'+uiThread.name;process.name=uiThread.name;uiThread.name='UI Thread';}
+process.sortIndex=0;for(var tid in process.threads){process.sortIndex-=process.threads[tid].sliceGroup.slices.length;}},this);this.model.getAllThreads().forEach(function(thread){if(thread.tid==thread.parent.pid)
+thread.sortIndex=-3;if(thread.name=='RenderThread')
+thread.sortIndex=-2;if(/^hwuiTask/.test(thread.name))
+thread.sortIndex=-1;});},pushFramesAndJudgeJank_:function(){var badFramesObserved=0;var framesObserved=0;var surfaceFlinger=this.helper.surfaceFlinger;this.helper.apps.forEach(function(app){app.process.frames=app.getFrames();app.process.frames.forEach(function(frame){if(frame.totalDuration>EXPECTED_FRAME_TIME_MS*2){badFramesObserved+=2;frame.perfClass=FRAME_PERF_CLASS.TERRIBLE;}else if(frame.totalDuration>EXPECTED_FRAME_TIME_MS||frameMissedDeadline(frame)){badFramesObserved++;frame.perfC [...]
+this.model.faviconHue='red';else if(portionBad>0.05)
+this.model.faviconHue='yellow';else
+this.model.faviconHue='green';}},pushEventInfo_:function(){var appAnnotator=new AppAnnotator();this.helper.apps.forEach(function(app){if(app.uiThread)
+appAnnotator.applyEventInfos(app.uiThread.sliceGroup);if(app.renderThread)
+appAnnotator.applyEventInfos(app.renderThread.sliceGroup);});},runAnnotate:function(){if(!this.helper)
+return;this.renameAndSort_();this.pushFramesAndJudgeJank_();this.pushEventInfo_();this.helper.iterateImportantSlices(function(slice){slice.important=true;});},runAudit:function(){if(!this.helper)
+return;var alerts=this.model.alerts;this.helper.apps.forEach(function(app){app.getFrames().forEach(function(frame){alerts.push.apply(alerts,AndroidAuditor.getSaveLayerAlerts_(frame));if(frame.perfClass==FRAME_PERF_CLASS.NEUTRAL||frame.perfClass==FRAME_PERF_CLASS.GOOD)
+return;var alert=AndroidAuditor.getPathAlert_(frame);if(alert)
+alerts.push(alert);var alert=AndroidAuditor.getUploadAlert_(frame);if(alert)
+alerts.push(alert);var alert=AndroidAuditor.getListViewAlert_(frame);if(alert)
+alerts.push(alert);var alert=AndroidAuditor.getMeasureLayoutAlert_(frame);if(alert)
+alerts.push(alert);var alert=AndroidAuditor.getViewDrawAlert_(frame);if(alert)
+alerts.push(alert);var alert=AndroidAuditor.getBlockingGcAlert_(frame);if(alert)
+alerts.push(alert);var alert=AndroidAuditor.getLockContentionAlert_(frame);if(alert)
+alerts.push(alert);var alert=AndroidAuditor.getSchedulingAlert_(frame);if(alert)
+alerts.push(alert);});},this);this.addRenderingInteractionRecords();this.addInputInteractionRecords();},addRenderingInteractionRecords:function(){var events=[];this.helper.apps.forEach(function(app){events.push.apply(events,app.getAnimationAsyncSlices());events.push.apply(events,app.getFrames());});var mergerFunction=function(events){var ir=new tr.model.um.ResponseExpectation(this.model,'Rendering',events[0].min,events[events.length-1].max-events[0].min);this.model.userModel.expectations [...]
+AppAnnotator.prototype={build_:function(){var registerEventInfo=function(dict){this.titleInfoLookup[dict.title]=new EventInfo(dict.title,dict.description,dict.docLinks);if(dict.parents)
+this.titleParentLookup[dict.title]=dict.parents;}.bind(this);registerEventInfo({title:'inflate',description:'Constructing a View hierarchy from pre-processed XML via LayoutInflater#layout. This includes constructing all of the View objects in the hierarchy, and applying styled attributes.'});registerEventInfo({title:'obtainView',description:'Adapter#getView() called to bind content to a recycled View that is being presented.'});registerEventInfo({title:'setupListItem',description:'Attach [...]
+return true;return expectedParentNames.some(function(name){return name in parentNames;});};if(slice.title in this.titleInfoLookup){if(checkExpectedParentNames(this.titleParentLookup[slice.title]))
+slice.info=this.titleInfoLookup[slice.title];}
+if(slice.subSlices.length>0){if(!(slice.title in parentNames))
+parentNames[slice.title]=0;parentNames[slice.title]++;slice.subSlices.forEach(function(subSlice){this.applyEventInfosRecursive_(parentNames,subSlice);},this);parentNames[slice.title]--;if(parentNames[slice.title]==0)
+delete parentNames[slice.title];}},applyEventInfos:function(sliceGroup){sliceGroup.topLevelSlices.forEach(function(slice){this.applyEventInfosRecursive_({},slice);},this);}};return{AndroidAuditor:AndroidAuditor};});'use strict';tr.exportTo('tr.model.helpers',function(){var MAIN_FRAMETIME_TYPE='main_frametime_type';var IMPL_FRAMETIME_TYPE='impl_frametime_type';var MAIN_RENDERING_STATS='BenchmarkInstrumentation::MainThreadRenderingStats';var IMPL_RENDERING_STATS='BenchmarkInstrumentation:: [...]
+slicesInFilterRange.push(slice);}
+return slicesInFilterRange;}
+function ChromeProcessHelper(modelHelper,process){this.modelHelper=modelHelper;this.process=process;}
+ChromeProcessHelper.prototype={get pid(){return this.process.pid;},getFrameEventsInRange:function(frametimeType,range){var titleToGet;if(frametimeType==MAIN_FRAMETIME_TYPE)
+titleToGet=MAIN_RENDERING_STATS;else
+titleToGet=IMPL_RENDERING_STATS;var frameEvents=[];this.process.iterateAllEvents(function(event){if(event.title!==titleToGet)
+return;if(range.intersectsExplicitRangeInclusive(event.start,event.end))
+frameEvents.push(event);});frameEvents.sort(function(a,b){return a.start-b.start});return frameEvents;}};function getFrametimeDataFromEvents(frameEvents){var frametimeData=[];for(var i=1;i<frameEvents.length;i++){var diff=frameEvents[i].start-frameEvents[i-1].start;frametimeData.push({'x':frameEvents[i].start,'frametime':diff});}
+return frametimeData;}
+return{ChromeProcessHelper:ChromeProcessHelper,MAIN_FRAMETIME_TYPE:MAIN_FRAMETIME_TYPE,IMPL_FRAMETIME_TYPE:IMPL_FRAMETIME_TYPE,MAIN_RENDERING_STATS:MAIN_RENDERING_STATS,IMPL_RENDERING_STATS:IMPL_RENDERING_STATS,getSlicesIntersectingRange:getSlicesIntersectingRange,getFrametimeDataFromEvents:getFrametimeDataFromEvents};});'use strict';tr.exportTo('tr.model.helpers',function(){function ChromeBrowserHelper(modelHelper,process){tr.model.helpers.ChromeProcessHelper.call(this,modelHelper,proce [...]
+ChromeBrowserHelper.isBrowserProcess=function(process){return!!process.findAtMostOneThreadNamed('CrBrowserMain');};ChromeBrowserHelper.prototype={__proto__:tr.model.helpers.ChromeProcessHelper.prototype,get rendererHelpers(){return this.modelHelper.rendererHelpers;},getLoadingEventsInRange:function(rangeOfInterest){return this.getAllAsyncSlicesMatching(function(slice){return slice.title.indexOf('WebContentsImpl Loading')===0&&rangeOfInterest.intersectsExplicitRangeInclusive(slice.start,s [...]
+return;if(!(event instanceof tr.e.cc.InputLatencyAsyncSlice))
+return;hasLatency=true;});return hasLatency;});return hasLatency;},getLatencyEventsInRange:function(rangeOfInterest){return this.getAllAsyncSlicesMatching(function(slice){return(slice.title.indexOf('InputLatency')===0)&&rangeOfInterest.intersectsExplicitRangeInclusive(slice.start,slice.end);});},getAllAsyncSlicesMatching:function(pred,opt_this){var events=[];this.iterAllThreads(function(thread){thread.iterateAllEvents(function(slice){if(pred.call(opt_this,slice))
+events.push(slice);});});return events;},getAllNetworkEventsInRange:function(rangeOfInterest){var networkEvents=[];this.modelHelper.model.getAllThreads().forEach(function(thread){thread.asyncSliceGroup.slices.forEach(function(slice){var match=false;if(slice.category=='net'||slice.category=='disabled-by-default-netlog'||slice.category=='netlog'){match=true;}
+if(!match)
+return;if(rangeOfInterest.intersectsExplicitRangeInclusive(slice.start,slice.end))
+networkEvents.push(slice);});});return networkEvents;},iterAllThreads:function(func,opt_this){tr.b.iterItems(this.process.threads,function(tid,thread){func.call(opt_this,thread);});tr.b.iterItems(this.rendererHelpers,function(pid,rendererHelper){var rendererProcess=rendererHelper.process;tr.b.iterItems(rendererProcess.threads,function(tid,thread){func.call(opt_this,thread);});},this);}};return{ChromeBrowserHelper:ChromeBrowserHelper};});'use strict';tr.exportTo('tr.model.helpers',functio [...]
+return false;return process.findAtMostOneThreadNamed('CrGpuMain');};ChromeGpuHelper.prototype={__proto__:tr.model.helpers.ChromeProcessHelper.prototype,get mainThread(){return this.mainThread_;}};return{ChromeGpuHelper:ChromeGpuHelper};});'use strict';tr.exportTo('tr.model.helpers',function(){function ChromeRendererHelper(modelHelper,process){tr.model.helpers.ChromeProcessHelper.call(this,modelHelper,process);this.mainThread_=process.findAtMostOneThreadNamed('CrRendererMain');this.compos [...]
+return false;if(t.name.indexOf('CompositorTileWorker')===0)
+return true;if(t.name.indexOf('CompositorRasterWorker')===0)
+return true;return false;});this.isChromeTracingUI_=process.labels!==undefined&&process.labels.length===1&&process.labels[0]==='chrome://tracing';};ChromeRendererHelper.isRenderProcess=function(process){if(process.findAtMostOneThreadNamed('CrRendererMain'))
+return true;if(process.findAtMostOneThreadNamed('Compositor'))
+return true;return false;};ChromeRendererHelper.prototype={__proto__:tr.model.helpers.ChromeProcessHelper.prototype,get mainThread(){return this.mainThread_;},get compositorThread(){return this.compositorThread_;},get rasterWorkerThreads(){return this.rasterWorkerThreads_;},get isChromeTracingUI(){return this.isChromeTracingUI_;}};return{ChromeRendererHelper:ChromeRendererHelper};});'use strict';tr.exportTo('tr.model.helpers',function(){function findChromeBrowserProcess(model){var browse [...]
+return;browserProcesses.push(process);},this);if(browserProcesses.length===0)
+return undefined;if(browserProcesses.length>1)
+return undefined;return browserProcesses[0];}
+function findChromeRenderProcesses(model){var rendererProcesses=[];model.getAllProcesses().forEach(function(process){if(!tr.model.helpers.ChromeRendererHelper.isRenderProcess(process))
+return;rendererProcesses.push(process);});return rendererProcesses;}
+function findChromeGpuProcess(model){var gpuProcesses=model.getAllProcesses().filter(tr.model.helpers.ChromeGpuHelper.isGpuProcess);if(gpuProcesses.length!=1)
+return undefined;return gpuProcesses[0];}
+function ChromeModelHelper(model){this.model_=model;this.browserProcess_=findChromeBrowserProcess(model);if(this.browserProcess_){this.browserHelper_=new tr.model.helpers.ChromeBrowserHelper(this,this.browserProcess_);}else{this.browserHelper_=undefined;}
+var gpuProcess=findChromeGpuProcess(model);if(gpuProcess){this.gpuHelper_=new tr.model.helpers.ChromeGpuHelper(this,gpuProcess);}else{this.gpuHelper_=undefined;}
+var rendererProcesses_=findChromeRenderProcesses(model);this.rendererHelpers_={};rendererProcesses_.forEach(function(renderProcess){var rendererHelper=new tr.model.helpers.ChromeRendererHelper(this,renderProcess);this.rendererHelpers_[rendererHelper.pid]=rendererHelper;},this);}
+ChromeModelHelper.guid=tr.b.GUID.allocate();ChromeModelHelper.supportsModel=function(model){if(findChromeBrowserProcess(model)!==undefined)
+return true;if(findChromeRenderProcesses(model).length)
+return true;return false;};ChromeModelHelper.prototype={get pid(){throw new Error('woah');},get process(){throw new Error('woah');},get model(){return this.model_;},get browserProcess(){return this.browserProcess_;},get browserHelper(){return this.browserHelper_;},get gpuHelper(){return this.gpuHelper_;},get rendererHelpers(){return this.rendererHelpers_;}};return{ChromeModelHelper:ChromeModelHelper};});'use strict';tr.exportTo('tr.model',function(){function AsyncSlice(category,title,col [...]
+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 parentContainer(){return this.parentContainer_;},set parentContainer(parentContainer){this.parentContainer_=parentContainer;for(var i=0;i<this.subSlices.length;i++){var subSlice=this.subSlices[i];if(subSlice.parentContainer===undefined)
+subSlice.parentContainer=parentContainer;}},get viewSubGroupTitle(){return this.title;},get userFriendlyName(){return'Async slice '+this.title+' at '+
+tr.v.Unit.byName.timeStampInMs.format(this.start);},get stableId(){var parentAsyncSliceGroup=this.parentContainer.asyncSliceGroup;return parentAsyncSliceGroup.stableId+'.'+
+parentAsyncSliceGroup.slices.indexOf(this);},findTopmostSlicesRelativeToThisSlice:function(eventPredicate,callback,opt_this){if(eventPredicate(this))
+callback.call(opt_this,this);else{this.subSlices.forEach(function(s){s.findTopmostSlicesRelativeToThisSlice(eventPredicate,callback,opt_this);});}},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 [...]
+this.determineModernTypeName_();}
+InputLatencyAsyncSlice.prototype={__proto__:AsyncSlice.prototype,get isLegacyEvent(){return this.title==='InputLatency';},get typeName(){if(!this.typeName_)
+this.determineLegacyTypeName_();return this.typeName_;},checkTypeName_:function(){if(!this.typeName_)
+throw'Unable to determine typeName';var found=false;for(var type_name in INPUT_EVENT_TYPE_NAMES){if(this.typeName===INPUT_EVENT_TYPE_NAMES[type_name]){found=true;break;}}
+if(!found)
+this.typeName_=INPUT_EVENT_TYPE_NAMES.UNKNOWN;},determineModernTypeName_:function(){var lastColonIndex=this.title.lastIndexOf(':');if(lastColonIndex<0)
+return;var characterAfterLastColonIndex=lastColonIndex+1;this.typeName_=this.title.slice(characterAfterLastColonIndex);this.checkTypeName_();},determineLegacyTypeName_:function(){this.iterateAllDescendents(function(subSlice){var subSliceIsAInputLatencyAsyncSlice=(subSlice instanceof InputLatencyAsyncSlice);if(!subSliceIsAInputLatencyAsyncSlice)
+return;if(!subSlice.typeName)
+return;if(this.typeName_&&subSlice.typeName_){var subSliceHasDifferentTypeName=(this.typeName_!==subSlice.typeName_);if(subSliceHasDifferentTypeName){throw'InputLatencyAsyncSlice.determineLegacyTypeName_() '+' found multiple typeNames';}}
+this.typeName_=subSlice.typeName_;},this);if(!this.typeName_)
+throw'InputLatencyAsyncSlice.determineLegacyTypeName_() failed';this.checkTypeName_();},getRendererHelper:function(sourceSlices){var traceModel=this.startThread.parent.model;var modelHelper=traceModel.getOrCreateHelper(tr.model.helpers.ChromeModelHelper);if(!modelHelper)
+return undefined;var mainThread=undefined;var compositorThread=undefined;for(var i in sourceSlices){if(sourceSlices[i].parentContainer.name===MAIN_RENDERER_THREAD_NAME)
+mainThread=sourceSlices[i].parentContainer;else if(sourceSlices[i].parentContainer.name===COMPOSITOR_THREAD_NAME)
+compositorThread=sourceSlices[i].parentContainer;if(mainThread&&compositorThread)
+break;}
+var rendererHelpers=modelHelper.rendererHelpers;var pids=Object.keys(rendererHelpers);for(var i=0;i<pids.length;i++){var pid=pids[i];var rendererHelper=rendererHelpers[pid];if(rendererHelper.mainThread===mainThread||rendererHelper.compositorThread===compositorThread)
+return rendererHelper;}
+return undefined;},addEntireSliceHierarchy:function(slice){this.associatedEvents_.push(slice);slice.iterateAllSubsequentSlices(function(subsequentSlice){this.associatedEvents_.push(subsequentSlice);},this);},addDirectlyAssociatedEvents:function(flowEvents){var slices=[];flowEvents.forEach(function(flowEvent){this.associatedEvents_.push(flowEvent);var newSource=flowEvent.startSlice.mostTopLevelSlice;if(slices.indexOf(newSource)===-1)
+slices.push(newSource);},this);var lastFlowEvent=flowEvents[flowEvents.length-1];var lastSource=lastFlowEvent.endSlice.mostTopLevelSlice;if(slices.indexOf(lastSource)===-1)
+slices.push(lastSource);return slices;},addScrollUpdateEvents:function(rendererHelper){if(!rendererHelper||!rendererHelper.compositorThread)
+return;var compositorThread=rendererHelper.compositorThread;var gestureScrollUpdateStart=this.start;var gestureScrollUpdateEnd=this.end;var allCompositorAsyncSlices=compositorThread.asyncSliceGroup.slices;for(var i in allCompositorAsyncSlices){var slice=allCompositorAsyncSlices[i];if(slice.title!=='Latency::ScrollUpdate')
+continue;var parentId=slice.args.data.INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT.sequence_number;if(parentId===undefined){if(slice.start<gestureScrollUpdateStart||slice.start>=gestureScrollUpdateEnd)
+continue;}else{if(parseInt(parentId)!==parseInt(this.id))
+continue;}
+slice.associatedEvents.forEach(function(event){this.associatedEvents_.push(event);},this);break;}},belongToOtherInputs:function(slice,flowEvents){var fromOtherInputs=false;slice.iterateEntireHierarchy(function(subsequentSlice){if(fromOtherInputs)
+return;subsequentSlice.inFlowEvents.forEach(function(inflow){if(fromOtherInputs)
+return;if(inflow.category.indexOf('input')>-1){if(flowEvents.indexOf(inflow)===-1)
+fromOtherInputs=true;}},this);},this);return fromOtherInputs;},triggerOtherInputs:function(event,flowEvents){if(event.outFlowEvents===undefined||event.outFlowEvents.length===0)
+return false;var flow=event.outFlowEvents[0];if(flow.category!==POSTTASK_FLOW_EVENT||!flow.endSlice)
+return false;var endSlice=flow.endSlice;if(this.belongToOtherInputs(endSlice.mostTopLevelSlice,flowEvents))
+return true;return false;},followSubsequentSlices:function(event,queue,visited,flowEvents){var stopFollowing=false;var inputAck=false;event.iterateAllSubsequentSlices(function(slice){if(stopFollowing)
+return;if(slice.title==='TaskQueueManager::RunTask')
+return;if(slice.title==='ThreadProxy::ScheduledActionSendBeginMainFrame')
+return;if(slice.title==='Scheduler::ScheduleBeginImplFrameDeadline'){if(this.triggerOtherInputs(slice,flowEvents))
+return;}
+if(slice.title==='CompositorImpl::PostComposite'){if(this.triggerOtherInputs(slice,flowEvents))
+return;}
+if(slice.title==='InputRouterImpl::ProcessInputEventAck')
+inputAck=true;if(inputAck&&slice.title==='InputRouterImpl::FilterAndSendWebInputEvent')
+stopFollowing=true;this.followCurrentSlice(slice,queue,visited);},this);},followCurrentSlice:function(event,queue,visited){event.outFlowEvents.forEach(function(outflow){if((outflow.category===POSTTASK_FLOW_EVENT||outflow.category===IPC_FLOW_EVENT)&&outflow.endSlice){this.associatedEvents_.push(outflow);var nextEvent=outflow.endSlice.mostTopLevelSlice;if(!visited.contains(nextEvent)){visited.push(nextEvent);queue.push(nextEvent);}}},this);},backtraceFromDraw:function(beginImplFrame,visite [...]
+return a.start-b.start;return a.guid-b.guid;});},addRasterizationEvents:function(prepareTiles,rendererHelper,visited,flowEvents,sortedRasterizerSlices){if(!prepareTiles.args.prepare_tiles_id)
+return;if(!rendererHelper||!rendererHelper.rasterWorkerThreads)
+return;var rasterWorkerThreads=rendererHelper.rasterWorkerThreads;var prepare_tile_id=prepareTiles.args.prepare_tiles_id;var pendingEventQueue=[];if(sortedRasterizerSlices.length===0)
+this.sortRasterizerSlices(rasterWorkerThreads,sortedRasterizerSlices);var numFinishedTasks=0;var RASTER_TASK_TITLE='RasterizerTaskImpl::RunOnWorkerThread';var IMAGEDECODE_TASK_TITLE='ImageDecodeTaskImpl::RunOnWorkerThread';var FINISHED_TASK_TITLE='TaskSetFinishedTaskImpl::RunOnWorkerThread';for(var i=0;i<sortedRasterizerSlices.length;i++){var task=sortedRasterizerSlices[i];if(task.title===RASTER_TASK_TITLE||task.title===IMAGEDECODE_TASK_TITLE){if(task.args.source_prepare_tiles_id===prepa [...]
+this.addEntireSliceHierarchy(task.mostTopLevelSlice);}else if(task.title===FINISHED_TASK_TITLE){if(task.start>prepareTiles.start){pendingEventQueue.push(task.mostTopLevelSlice);if(++numFinishedTasks===3)
+break;}}}
+while(pendingEventQueue.length!=0){var event=pendingEventQueue.pop();this.addEntireSliceHierarchy(event);this.followSubsequentSlices(event,pendingEventQueue,visited,flowEvents);}},addOtherCausallyRelatedEvents:function(rendererHelper,sourceSlices,flowEvents,sortedRasterizerSlices){var pendingEventQueue=[];var visitedEvents=new EventSet();var beginImplFrame=undefined;var prepareTiles=undefined;var sortedRasterizerSlices=[];sourceSlices.forEach(function(sourceSlice){if(!visitedEvents.conta [...]
+this.addRasterizationEvents(prepareTiles,rendererHelper,visitedEvents,flowEvents,sortedRasterizerSlices);var COMPOSITOR_ON_BIFD='Scheduler::OnBeginImplFrameDeadline';beginImplFrame=event.findDescendentSlice(COMPOSITOR_ON_BIFD);if(beginImplFrame)
+this.backtraceFromDraw(beginImplFrame,visitedEvents);}
+var INPUT_GSU='InputLatency::GestureScrollUpdate';if(this.title===INPUT_GSU)
+this.addScrollUpdateEvents(rendererHelper);},get associatedEvents(){if(this.associatedEvents_.length!==0)
+return this.associatedEvents_;var modelIndices=this.startThread.parent.model.modelIndices;var flowEvents=modelIndices.getFlowEventsWithId(this.id);if(flowEvents.length===0)
+return this.associatedEvents_;var sourceSlices=this.addDirectlyAssociatedEvents(flowEvents);var rendererHelper=this.getRendererHelper(sourceSlices);this.addOtherCausallyRelatedEvents(rendererHelper,sourceSlices,flowEvents);return this.associatedEvents_;},get inputLatency(){if(!('data'in this.args))
+return undefined;var data=this.args.data;if(!(END_COMP_NAME in data))
+return undefined;var latency=0;var endTime=data[END_COMP_NAME].time;if(ORIGINAL_COMP_NAME in data){latency=endTime-data[ORIGINAL_COMP_NAME].time;}else if(UI_COMP_NAME in data){latency=endTime-data[UI_COMP_NAME].time;}else if(BEGIN_COMP_NAME in data){latency=endTime-data[BEGIN_COMP_NAME].time;}else{throw new Error('No valid begin latency component');}
+return latency;}};var eventTypeNames=['Char','ContextMenu','GestureClick','GestureFlingCancel','GestureFlingStart','GestureScrollBegin','GestureScrollEnd','GestureScrollUpdate','GestureShowPress','GestureTap','GestureTapCancel','GestureTapDown','GesturePinchBegin','GesturePinchEnd','GesturePinchUpdate','KeyDown','KeyUp','MouseDown','MouseEnter','MouseLeave','MouseMove','MouseUp','MouseWheel','RawKeyDown','ScrollUpdate','TouchCancel','TouchEnd','TouchMove','TouchStart'];var allTypeNames=[ [...]
+var USER_FRIENDLY_CATEGORY_FOR_EVENT_CATEGORY={netlog:'net',overhead:'overhead',startup:'startup',gpu:'gpu'};function ChromeUserFriendlyCategoryDriver(){}
+ChromeUserFriendlyCategoryDriver.fromEvent=function(event){var userFriendlyCategory=USER_FRIENDLY_CATEGORY_FOR_TITLE[event.title];if(userFriendlyCategory){if(userFriendlyCategory==SAME_AS_PARENT){if(event.parentSlice)
+return ChromeUserFriendlyCategoryDriver.fromEvent(event.parentSlice);}else{return userFriendlyCategory;}}
+var eventCategoryParts=tr.b.getCategoryParts(event.category);for(var i=0;i<eventCategoryParts.length;++i){var eventCategory=eventCategoryParts[i];userFriendlyCategory=USER_FRIENDLY_CATEGORY_FOR_EVENT_CATEGORY[eventCategory];if(userFriendlyCategory)
+return userFriendlyCategory;}
+return undefined;};return{ChromeUserFriendlyCategoryDriver:ChromeUserFriendlyCategoryDriver};});'use strict';tr.exportTo('tr.model',function(){return{BROWSER_PROCESS_PID_REF:-1,OBJECT_DEFAULT_SCOPE:'ptr'};});'use strict';tr.exportTo('tr.e.audits',function(){var Auditor=tr.c.Auditor;function ChromeAuditor(model){Auditor.call(this,model);var modelHelper=this.model.getOrCreateHelper(tr.model.helpers.ChromeModelHelper);if(modelHelper&&modelHelper.browserHelper){this.modelHelper=modelHelper;} [...]
+return;for(var pid in this.modelHelper.rendererHelpers){var rendererHelper=this.modelHelper.rendererHelpers[pid];if(rendererHelper.isChromeTracingUI)
+rendererHelper.process.important=false;}},installUserFriendlyCategoryDriverIfNeeded:function(){this.model.addUserFriendlyCategoryDriver(tr.e.chrome.ChromeUserFriendlyCategoryDriver);},runAudit:function(){if(!this.modelHelper)
+return;this.model.replacePIDRefsInPatchups(tr.model.BROWSER_PROCESS_PID_REF,this.modelHelper.browserProcess.pid);this.model.applyObjectRefPatchups();}};Auditor.register(ChromeAuditor);return{ChromeAuditor:ChromeAuditor};});'use strict';tr.exportTo('tr.model',function(){function ObjectSnapshot(objectInstance,ts,args){tr.model.Event.call(this);this.objectInstance=objectInstance;this.ts=ts;this.args=args;}
+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.v.Unit.byName.timeStampInMs.format(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{O [...]
+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.scopedId;}};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=ObjectI [...]
+FrameTreeNodeSnapshot.prototype={__proto__:ObjectSnapshot.prototype,preInitialize:function(){},initialize:function(){},get userFriendlyName(){return'FrameTreeNode';}};ObjectSnapshot.register(FrameTreeNodeSnapshot,{typeName:'FrameTreeNode'});function FrameTreeNodeInstance(){ObjectInstance.apply(this,arguments);}
+FrameTreeNodeInstance.prototype={__proto__:ObjectInstance.prototype};ObjectInstance.register(FrameTreeNodeInstance,{typeName:'FrameTreeNode'});return{FrameTreeNodeSnapshot:FrameTreeNodeSnapshot,FrameTreeNodeInstance:FrameTreeNodeInstance};});'use strict';tr.exportTo('tr.e.chrome',function(){var KNOWN_PROPERTIES={absX:1,absY:1,address:1,anonymous:1,childNeeds:1,children:1,classNames:1,col:1,colSpan:1,float:1,height:1,htmlId:1,name:1,posChildNeeds:1,positioned:1,positionedMovement:1,relX:1 [...]
+this.needsLayoutReasons_.push('self');if(args.childNeeds)
+this.needsLayoutReasons_.push('child');if(args.posChildNeeds)
+this.needsLayoutReasons_.push('positionedChild');if(args.positionedMovement)
+this.needsLayoutReasons_.push('positionedMovement');this.tableRow_=args.row;this.tableCol_=args.col;this.tableRowSpan_=args.rowSpan;this.tableColSpan_=args.colSpan;if(args.children){args.children.forEach(function(child){this.childLayoutObjects_.push(new LayoutObject(snapshot,child));}.bind(this));}
+for(var property in args){if(!KNOWN_PROPERTIES[property])
+this.otherProperties_[property]=args[property];}}
+LayoutObject.prototype={get snapshot(){return this.snapshot_;},get id(){return this.id_;},get name(){return this.name_;},get tag(){return this.tag_;},get relativeRect(){return this.relativeRect_;},get absoluteRect(){return this.absoluteRect_;},get isPositioned(){return this.isPositioned_;},get isFloat(){return this.isFloat_;},get isStickyPositioned(){return this.isStickyPositioned_;},get isRelativePositioned(){return this.isRelativePositioned_;},get isAnonymous(){return this.isAnonymous_ [...]
+return;this.childLayoutObjects.forEach(function(child){child.traverseTree(cb,opt_this);});},get otherPropertyNames(){var names=[];for(var name in this.otherProperties_){names.push(name);}
+return names;},getProperty:function(name){return this.otherProperties_[name];},get previousSnapshotLayoutObject(){if(!this.snapshot.previousSnapshot)
+return undefined;return this.snapshot.previousSnapshot.getLayoutObjectById(this.id);},get nextSnapshotLayoutObject(){if(!this.snapshot.nextSnapshot)
+return undefined;return this.snapshot.nextSnapshot.getLayoutObjectById(this.id);}};return{LayoutObject:LayoutObject};});'use strict';tr.exportTo('tr.e.chrome',function(){var ObjectSnapshot=tr.model.ObjectSnapshot;var ObjectInstance=tr.model.ObjectInstance;function LayoutTreeInstance(){ObjectInstance.apply(this,arguments);}
+LayoutTreeInstance.prototype={__proto__:ObjectInstance.prototype,};ObjectInstance.register(LayoutTreeInstance,{typeName:'LayoutTree'});function LayoutTreeSnapshot(){ObjectSnapshot.apply(this,arguments);this.rootLayoutObject=new tr.e.chrome.LayoutObject(this,this.args);}
+LayoutTreeSnapshot.prototype={__proto__:ObjectSnapshot.prototype,};ObjectSnapshot.register(LayoutTreeSnapshot,{typeName:'LayoutTree'});tr.model.EventRegistry.register(LayoutTreeSnapshot,{name:'layoutTree',pluralName:'layoutTrees',singleViewElementName:'tr-ui-a-layout-tree-sub-view',multiViewElementName:'tr-ui-a-layout-tree-sub-view'});return{LayoutTreeInstance:LayoutTreeInstance,LayoutTreeSnapshot:LayoutTreeSnapshot};});'use strict';tr.exportTo('tr.e.chrome',function(){var constants=tr.e [...]
+RenderFrameSnapshot.prototype={__proto__:ObjectSnapshot.prototype,preInitialize:function(){},initialize:function(){},get userFriendlyName(){return'RenderFrame';}};ObjectSnapshot.register(RenderFrameSnapshot,{typeName:'RenderFrame'});function RenderFrameInstance(){ObjectInstance.apply(this,arguments);}
+RenderFrameInstance.prototype={__proto__:ObjectInstance.prototype};ObjectInstance.register(RenderFrameInstance,{typeName:'RenderFrame'});return{RenderFrameSnapshot:RenderFrameSnapshot,RenderFrameInstance:RenderFrameInstance};});'use strict';tr.exportTo('tr.b',function(){function Base64(){}
+function b64ToUint6(nChr){if(nChr>64&&nChr<91)
+return nChr-65;if(nChr>96&&nChr<123)
+return nChr-71;if(nChr>47&&nChr<58)
+return nChr+4;if(nChr===43)
+return 62;if(nChr===47)
+return 63;return 0;}
+Base64.getDecodedBufferLength=function(input){return input.length*3+1>>2;};Base64.EncodeArrayBufferToString=function(input){var binary='';var bytes=new Uint8Array(input);var len=bytes.byteLength;for(var i=0;i<len;i++)
+binary+=String.fromCharCode(bytes[i]);return btoa(binary);};Base64.DecodeToTypedArray=function(input,output){var nInLen=input.length;var nOutLen=nInLen*3+1>>2;var nMod3=0;var nMod4=0;var nUint24=0;var nOutIdx=0;if(nOutLen>output.byteLength)
+throw new Error('Output buffer too small to decode.');for(var nInIdx=0;nInIdx<nInLen;nInIdx++){nMod4=nInIdx&3;nUint24|=b64ToUint6(input.charCodeAt(nInIdx))<<18-6*nMod4;if(nMod4===3||nInLen-nInIdx===1){for(nMod3=0;nMod3<3&&nOutIdx<nOutLen;nMod3++,nOutIdx++){output.setUint8(nOutIdx,nUint24>>>(16>>>nMod3&24)&255);}
+nUint24=0;}}
+return nOutIdx-1;};Base64.btoa=function(input){return btoa(input);};Base64.atob=function(input){return atob(input);};return{Base64:Base64};});'use strict';tr.exportTo('tr.e.importer.etw',function(){function Parser(importer){this.importer=importer;this.model=importer.model;}
+Parser.prototype={__proto__:Object.prototype};var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);options.mandatoryBaseClass=Parser;tr.b.decorateExtensionRegistry(Parser,options);return{Parser:Parser};});'use strict';tr.exportTo('tr.e.importer.etw',function(){var Parser=tr.e.importer.etw.Parser;var guid='68FDD900-4A3E-11D1-84F4-0000F80464E3';var kEventTraceHeaderOpcode=0;function EventTraceParser(importer){Parser.call(this,importer);importer.registerEventHandler(guid, [...]
+EventTraceParser.prototype={__proto__:Parser.prototype,decodeFields:function(header,decoder){if(header.version!=2)
+throw new Error('Incompatible EventTrace event version.');var bufferSize=decoder.decodeUInt32();var version=decoder.decodeUInt32();var providerVersion=decoder.decodeUInt32();var numberOfProcessors=decoder.decodeUInt32();var endTime=decoder.decodeUInt64ToString();var timerResolution=decoder.decodeUInt32();var maxFileSize=decoder.decodeUInt32();var logFileMode=decoder.decodeUInt32();var buffersWritten=decoder.decodeUInt32();var startBuffers=decoder.decodeUInt32();var pointerSize=decoder.de [...]
+ProcessParser.prototype={__proto__:Parser.prototype,decodeFields:function(header,decoder){if(header.version>5)
+throw new Error('Incompatible Process event version.');var pageDirectoryBase;if(header.version==1)
+pageDirectoryBase=decoder.decodeUInteger(header.is64);var uniqueProcessKey;if(header.version>=2)
+uniqueProcessKey=decoder.decodeUInteger(header.is64);var processId=decoder.decodeUInt32();var parentId=decoder.decodeUInt32();var sessionId;var exitStatus;if(header.version>=1){sessionId=decoder.decodeUInt32();exitStatus=decoder.decodeInt32();}
+var directoryTableBase;if(header.version>=3)
+directoryTableBase=decoder.decodeUInteger(header.is64);var flags;if(header.version>=4)
+flags=decoder.decodeUInt32();var userSID=decoder.decodeSID(header.is64);var imageFileName;if(header.version>=1)
+imageFileName=decoder.decodeString();var commandLine;if(header.version>=2)
+commandLine=decoder.decodeW16String();var packageFullName;var applicationId;if(header.version>=4){packageFullName=decoder.decodeW16String();applicationId=decoder.decodeW16String();}
+var exitTime;if(header.version==5&&header.opcode==kProcessDefunctOpcode)
+exitTime=decoder.decodeUInt64ToString();return{pageDirectoryBase:pageDirectoryBase,uniqueProcessKey:uniqueProcessKey,processId:processId,parentId:parentId,sessionId:sessionId,exitStatus:exitStatus,directoryTableBase:directoryTableBase,flags:flags,userSID:userSID,imageFileName:imageFileName,commandLine:commandLine,packageFullName:packageFullName,applicationId:applicationId,exitTime:exitTime};},decodeStart:function(header,decoder){var fields=this.decodeFields(header,decoder);var process=th [...]
+process.name=fields.imageFileName;return true;},decodeEnd:function(header,decoder){var fields=this.decodeFields(header,decoder);var process=this.model.getOrCreateProcess(fields.processId);process.has_ended=true;return true;},decodeDCStart:function(header,decoder){var fields=this.decodeFields(header,decoder);var process=this.model.getOrCreateProcess(fields.processId);if(process.hasOwnProperty('has_ended'))
+throw new Error('Process clash detected.');process.name=fields.imageFileName;return true;},decodeDCEnd:function(header,decoder){var fields=this.decodeFields(header,decoder);var process=this.model.getOrCreateProcess(fields.processId);process.has_ended=true;return true;},decodeDefunct:function(header,decoder){var fields=this.decodeFields(header,decoder);return true;}};Parser.register(ProcessParser);return{ProcessParser:ProcessParser};});'use strict';tr.exportTo('tr.e.importer.etw',function [...]
+ThreadParser.prototype={__proto__:Parser.prototype,decodeFields:function(header,decoder){if(header.version>3)
+throw new Error('Incompatible Thread event version.');var processId=decoder.decodeUInt32();var threadId=decoder.decodeUInt32();var stackBase;var stackLimit;var userStackBase;var userStackLimit;var affinity;var startAddr;var win32StartAddr;var tebBase;var subProcessTag;var basePriority;var pagePriority;var ioPriority;var threadFlags;var waitMode;if(header.version==1){if(header.opcode==kThreadStartOpcode||header.opcode==kThreadDCStartOpcode){stackBase=decoder.decodeUInteger(header.is64);st [...]
+startAddr=decoder.decodeUInteger(header.is64);else
+affinity=decoder.decodeUInteger(header.is64);win32StartAddr=decoder.decodeUInteger(header.is64);tebBase=decoder.decodeUInteger(header.is64);subProcessTag=decoder.decodeUInt32();if(header.version==3){basePriority=decoder.decodeUInt8();pagePriority=decoder.decodeUInt8();ioPriority=decoder.decodeUInt8();threadFlags=decoder.decodeUInt8();}}
+return{processId:processId,threadId:threadId,stackBase:stackBase,stackLimit:stackLimit,userStackBase:userStackBase,userStackLimit:userStackLimit,affinity:affinity,startAddr:startAddr,win32StartAddr:win32StartAddr,tebBase:tebBase,subProcessTag:subProcessTag,waitMode:waitMode,basePriority:basePriority,pagePriority:pagePriority,ioPriority:ioPriority,threadFlags:threadFlags};},decodeCSwitchFields:function(header,decoder){if(header.version!=2)
+throw new Error('Incompatible Thread event version.');var newThreadId=decoder.decodeUInt32();var oldThreadId=decoder.decodeUInt32();var newThreadPriority=decoder.decodeInt8();var oldThreadPriority=decoder.decodeInt8();var previousCState=decoder.decodeUInt8();var spareByte=decoder.decodeInt8();var oldThreadWaitReason=decoder.decodeInt8();var oldThreadWaitMode=decoder.decodeInt8();var oldThreadState=decoder.decodeInt8();var oldThreadWaitIdealProcessor=decoder.decodeInt8();var newThreadWait [...]
+new_process_name=new_process.name;else
+new_process_name='Unknown process';new_thread_name=new_process_name+' (tid '+fields.newThreadId+')';}
+cpu.switchActiveThread(header.timestamp,{},fields.newThreadId,new_thread_name,fields);return true;}};Parser.register(ThreadParser);return{ThreadParser:ThreadParser};});'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};});!function(t,n){if("object"==typeof exports&&"object"==typeof module)module.exports=n();else if("function"==typeof define&&define.amd)define(n);else{var r=n();for(var a in r)("object"==typeof exports?exports:t)[a]=r[a]}}(this,function(){return function(t){function n(a){if(r[a])return r[a].exports;var e=r[a]={exports:{},id:a,loaded:!1};return t[a].call(e.exports,e,e.exports,n),e.loaded=!0,e.exports}var r [...]
+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=fun [...]
+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.b',function(){function addSingletonGetter(ctor){ctor.getInstance=function(){return ctor.instance_||(ctor.instance_=new ctor());};}
+function deepCopy(value){if(!(value instanceof Object)){if(value===undefined||value===null)
+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;}
+function normalizeException(e){if(e===undefined||e===null){return{typeName:'UndefinedError',message:'Unknown: null or undefined exception',stack:'Unknown'};}
+if(typeof(e)=='string'){return{typeName:'StringError',message:e,stack:[e]};}
+var typeName;if(e.name){typeName=e.name;}else if(e.constructor){if(e.constructor.name){typeName=e.constructor.name;}else{typeName='AnonymousError';}}else{typeName='ErrorWithNoConstructor';}
+var msg=e.message?e.message:'Unknown';return{typeName:typeName,message:msg,stack:e.stack?e.stack:[msg]};}
+function stackTraceAsString(){return new Error().stack+'';}
+function stackTrace(){var stack=stackTraceAsString();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,deepCopy:deepCopy,normalizeException:normalizeException,stackTrace:stackTrace,stackTraceAsString:stackTraceAsString,getUsingPath:getUsingPath};});'use strict';tr.exportTo('tr.b',function(){var ESTIMATED_IDLE_PERIOD_LENGTH_MILLISECONDS=10;var REQUEST_IDLE_CALLBACK_TIMEOUT_MILLISECONDS=100;var recordRAFStacks=false;var pendingPreAFs=[];var pendingRAFs=[];var pendingIdleCallbacks=[];var currentRAFDispatchList=undefined;var rafScheduled=false;var  [...]
+return;rafScheduled=true;if(tr.isHeadless){Promise.resolve().then(function(){processRequests(false,0);},function(e){console.log(e.stack);throw e;});}else{if(window.requestAnimationFrame){window.requestAnimationFrame(processRequests.bind(this,false));}else{var delta=Date.now()-window.performance.now();window.webkitRequestAnimationFrame(function(domTimeStamp){processRequests(false,domTimeStamp-delta);});}}}
+function nativeRequestIdleCallbackSupported(){return!tr.isHeadless&&window.requestIdleCallback;}
+function scheduleIdleWork(){if(idleWorkScheduled)
+return;if(!nativeRequestIdleCallbackSupported()){scheduleRAF();return;}
+idleWorkScheduled=true;window.requestIdleCallback(function(deadline,didTimeout){processIdleWork(false,deadline);},{timeout:REQUEST_IDLE_CALLBACK_TIMEOUT_MILLISECONDS});}
+function onAnimationFrameError(e,opt_stack){console.log(e.stack);if(tr.isHeadless)
+throw e;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(forceAllTasksToRun,frameBeginTime){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&&!nativeRequestIdleCallbackSupported())||forceAllTasksToRun){var rafCompletionDeadline=frameBeginTime+ESTIMATED_IDLE_PERIOD_LENGTH_MILLISECONDS;processIdleWork(forceAllTasksToRun,{timeRemaining:function(){return rafCompletionDeadline-window.performance.now();}});}
+if(pendingIdleCallbacks.length>0)
+scheduleIdleWork();}
+function processIdleWork(forceAllTasksToRun,deadline){idleWorkScheduled=false;while(pendingIdleCallbacks.length>0){runTask(pendingIdleCallbacks.shift());if(!forceAllTasksToRun&&(tr.isHeadless||deadline.timeRemaining()<=0)){break;}}
+if(pendingIdleCallbacks.length>0)
+scheduleIdleWork();}
+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||global,stack:getStack_()});scheduleRAF();}
+function requestAnimationFrameInThisFrameIfPossible(callback,opt_this){if(!currentRAFDispatchList){requestAnimationFrame(callback,opt_this);return;}
+currentRAFDispatchList.push({callback:callback,context:opt_this||global,stack:getStack_()});return;}
+function requestAnimationFrame(callback,opt_this){pendingRAFs.push({callback:callback,context:opt_this||global,stack:getStack_()});scheduleRAF();}
+function requestIdleCallback(callback,opt_this){pendingIdleCallbacks.push({callback:callback,context:opt_this||global,stack:getStack_()});scheduleIdleWork();}
+function forcePendingRAFTasksToRun(frameBeginTime){if(!rafScheduled)
+return;processRequests(false,frameBeginTime);}
+function forceAllPendingTasksToRunForTest(){if(!rafScheduled&&!idleWorkScheduled)
+return;processRequests(true,0);}
+return{onAnimationFrameError:onAnimationFrameError,requestPreAnimationFrame:requestPreAnimationFrame,requestAnimationFrame:requestAnimationFrame,requestAnimationFrameInThisFrameIfPossible:requestAnimationFrameInThisFrameIfPossible,requestIdleCallback:requestIdleCallback,forcePendingRAFTasksToRun:forcePendingRAFTasksToRun,forceAllPendingTasksToRunForTest:forceAllPendingTasksToRunForTest};});'use strict';tr.exportTo('tr.b',function(){var Base64=tr.b.Base64;function computeUserTimingMarkNam [...]
+throw new Error('getMeasureString should have group name');if(functionName===undefined)
+throw new Error('getMeasureString should have function name');var userTimingMarkName=groupName+':'+functionName;if(opt_args!==undefined){userTimingMarkName+='/';userTimingMarkName+=Base64.btoa(JSON.stringify(opt_args));}
+return userTimingMarkName;}
+function Timing(){}
+Timing.nextMarkNumber=0;Timing.mark=function(groupName,functionName,opt_args){if(tr.isHeadless){return{end:function(){}};}
+var userTimingMarkName=computeUserTimingMarkName(groupName,functionName,opt_args);var markBeginName='tvcm.mark'+Timing.nextMarkNumber++;var markEndName='tvcm.mark'+Timing.nextMarkNumber++;window.performance.mark(markBeginName);return{end:function(){window.performance.mark(markEndName);window.performance.measure(userTimingMarkName,markBeginName,markEndName);}};};Timing.wrap=function(groupName,callback,opt_args){if(groupName===undefined)
+throw new Error('Timing.wrap should have group name');if(callback.name==='')
+throw new Error('Anonymous function is not allowed');return Timing.wrapNamedFunction(groupName,callback.name,callback,opt_args);};Timing.wrapNamedFunction=function(groupName,functionName,callback,opt_args){function timedNamedFunction(){var markedTime=Timing.mark(groupName,functionName,opt_args);try{callback.apply(this,arguments);}finally{markedTime.end();}}
+return timedNamedFunction;};function TimedNamedPromise(groupName,name,executor,opt_args){var markedTime=Timing.mark(groupName,name,opt_args);var promise=new Promise(executor);promise.then(function(result){markedTime.end();return result;},function(e){markedTime.end();throw e;});return promise;}
+return{_computeUserTimingMarkName:computeUserTimingMarkName,TimedNamedPromise:TimedNamedPromise,Timing:Timing};});'use strict';tr.exportTo('tr.b',function(){var Timing=tr.b.Timing;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={get name(){return this.runCb_.name;},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_;},timedAfter:function(groupName,cb,thisArg,opt_args){if(cb.name==='')
+throw new Error('Anonymous Task is not allowed');return this.namedTimedAfter(groupName,cb.name,cb,thisArg,opt_args);},namedTimedAfter:function(groupName,name,cb,thisArg,opt_args){if(this.afterTask_)
+throw new Error('Has an after task already');var realTask;if(cb instanceof Task)
+realTask=cb;else
+realTask=new Task(cb,thisArg);this.afterTask_=new Task(function(task){var markedTask=Timing.mark(groupName,name,opt_args);task.subTask(realTask,thisArg);task.subTask(function(){markedTask.end();},thisArg);},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.c',function(){function makeCaseInsensitiveRegex(pattern){pattern=pattern.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');return new RegExp(pattern,'i');}
+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.regex_=makeCaseInsensitiveRegex(text);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 this.regex_.test(slice.title)||(!!slice.category&&this.regex_.test(slice.category));}};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_;}};function FullTextFilter(text){Filter.call(this);this.regex_=makeCaseInsensitiveRegex(text);this.titleOrCategoryFilter_=new TitleOrCategoryFilter(text);}
+FullTextFilter.prototype={__proto__:Filter.prototype,matchObject_:function(obj){for(var key in obj){if(!obj.hasOwnProperty(key))
+continue;if(this.regex_.test(key))
+return true;if(this.regex_.test(obj[key]))
+return true;}
+return false;},matchSlice:function(slice){if(this.titleOrCategoryFilter_.matchSlice(slice))
+return true;return this.matchObject_(slice.args);}};return{Filter:Filter,TitleOrCategoryFilter:TitleOrCategoryFilter,ExactTitleFilter:ExactTitleFilter,FullTextFilter:FullTextFilter};});'use strict';tr.exportTo('tr.model',function(){var ClockDomainId={BATTOR:'BATTOR',UNKNOWN_CHROME_LEGACY:'UNKNOWN_CHROME_LEGACY',LINUX_CLOCK_MONOTONIC:'LINUX_CLOCK_MONOTONIC',MAC_MACH_ABSOLUTE_TIME:'MAC_MACH_ABSOLUTE_TIME',WIN_ROLLOVER_PROTECTED_TIME_GET_TIME:'WIN_ROLLOVER_PROTECTED_TIME_GET_TIME',WIN_QPC:' [...]
+ClockSyncManager.prototype={addClockSyncMarker:function(domainId,syncId,startTs,opt_endTs){if(tr.b.dictionaryValues(ClockDomainId).indexOf(domainId)<0){throw new Error('"'+domainId+'" is not in the list of known '+'clock domain IDs.');}
+if(this.modelDomainId_!==undefined){throw new Error('Cannot add new clock sync markers after getting '+'a model time transformer.');}
+if(this.markersBySyncId_[syncId]===undefined)
+this.markersBySyncId_[syncId]=[];var markers=this.markersBySyncId_[syncId];if(markers.length===1&&markers[0].domainId===domainId){throw new Error('A clock domain cannot sync with itself.');}
+if(markers.length===1&&this.connectorExistsBetween_(markers[0].domainId,domainId)){throw new Error('Cannot add multiple connectors between the same '+'clock domains.');}
+if(markers.length===2){throw new Error('Clock sync with ID "'+syncId+'" is already '+'complete - cannot add a third clock sync marker to it.');}
+markers.push(new ClockSyncMarker(domainId,startTs,opt_endTs));},getModelTimeTransformer:function(domainId){if(this.modelTimeTransformerByDomainId_===undefined)
+this.buildModelTimeTransformerMap_();var transformer=this.modelTimeTransformerByDomainId_[domainId];if(transformer===undefined){throw new Error('No clock sync markers exist pairing clock domain "'+
+domainId+'" '+'with model clock domain "'+
+this.modelDomainId_+'".');}
+return transformer;},buildModelTimeTransformerMap_(){var actualChromeDomain=this.getActualTraceEventImporterDomain_();if(actualChromeDomain!==undefined){this.substituteDomainInMarkers_(actualChromeDomain,ClockDomainId.UNKNOWN_CHROME_LEGACY);}
+this.buildModelTimeTransformerMapImpl_();if(actualChromeDomain!==undefined){var chromeModelTimeTransform=this.modelTimeTransformerByDomainId_[ClockDomainId.UNKNOWN_CHROME_LEGACY];this.modelTimeTransformerByDomainId_[actualChromeDomain]=chromeModelTimeTransform;}},buildModelTimeTransformerMapImpl_(){var connectorsByDomainId_=this.getConnectorsByDomainId_();var uniqueDomainIds=tr.b.dictionaryKeys(connectorsByDomainId_);uniqueDomainIds.sort();var isFullyConnected=function(domainId){return c [...]
+this.modelTimeTransformerByDomainId_={};this.modelTimeTransformerByDomainId_[this.modelDomainId_]=tr.b.identity;var modelConnectors=connectorsByDomainId_[this.modelDomainId_];for(var i=0;i<modelConnectors.length;i++){var conn=modelConnectors[i];if(conn.marker1.domainId===this.modelDomainId_){this.modelTimeTransformerByDomainId_[conn.marker2.domainId]=conn.getTransformer(conn.marker2.domainId,conn.marker1.domainId);}else{this.modelTimeTransformerByDomainId_[conn.marker1.domainId]=conn.get [...]
+return undefined;if(uniqueDomainIds.indexOf(ClockDomainId.LINUX_CLOCK_MONOTONIC)>=0)
+return ClockDomainId.LINUX_CLOCK_MONOTONIC;if(uniqueDomainIds.indexOf(ClockDomainId.MAC_MACH_ABSOLUTE_TIME)>=0)
+return ClockDomainId.MAC_MACH_ABSOLUTE_TIME;if(uniqueDomainIds.indexOf(ClockDomainId.WIN_ROLLOVER_PROTECTED_TIME_GET_TIME)>=0){return ClockDomainId.WIN_ROLLOVER_PROTECTED_TIME_GET_TIME;}
+if(uniqueDomainIds.indexOf(ClockDomainId.WIN_QPC)>=0)
+return ClockDomainId.WIN_QPC;return undefined;},substituteDomainInMarkers_:function(original,replacement){for(var syncId in this.markersBySyncId_){for(var i=0;i<this.markersBySyncId_[syncId].length;i++){var marker=this.markersBySyncId_[syncId][i];if(marker.domainId===original)
+marker.domainId=replacement;}}},getConnectorsByDomainId_:function(){var connectorsByDomainId={};for(var syncId in this.markersBySyncId_){var markers=this.markersBySyncId_[syncId];if(markers.length===1){var markerDomainId=markers[0].domainId;if(connectorsByDomainId[markerDomainId]===undefined)
+connectorsByDomainId[markerDomainId]=[];continue;}
+var conn=new ClockSyncConnector(markers[0],markers[1]);var domain1=conn.marker1.domainId;if(connectorsByDomainId[domain1]===undefined)
+connectorsByDomainId[domain1]=[];var domain2=conn.marker2.domainId;if(connectorsByDomainId[domain2]===undefined)
+connectorsByDomainId[domain2]=[];connectorsByDomainId[markers[0].domainId].push(conn);connectorsByDomainId[markers[1].domainId].push(conn);}
+return connectorsByDomainId;},connectorExistsBetween_(domain1Id,domain2Id){for(var syncId in this.markersBySyncId_){var markers=this.markersBySyncId_[syncId];if(markers.length!==2)
+continue;var connector=new ClockSyncConnector(markers[0],markers[1]);if(connector.isBetween(domain1Id,domain2Id))
+return true;}
+return false;}};function ClockSyncMarker(domainId,startTs,opt_endTs){this.domainId=domainId;this.startTs=startTs;this.endTs=opt_endTs===undefined?startTs:opt_endTs;}
+ClockSyncMarker.prototype={get duration(){return this.endTs-this.startTs;},get ts(){return this.startTs+this.duration/2;}};function ClockSyncConnector(marker1,marker2){if(marker1===undefined||marker2===undefined)
+throw new Error('ClockSyncConnectors must consist of defined markers.');this.marker1=marker1;this.marker2=marker2;}
+ClockSyncConnector.prototype={getTransformer:function(fromDomainId,toDomainId){if(!this.isBetween(fromDomainId,toDomainId))
+throw new Error('This connector cannot perform this transformation.');var fromMarker,toMarker;if(this.marker1.domainId===fromDomainId){fromMarker=this.marker1;toMarker=this.marker2;}else{fromMarker=this.marker2;toMarker=this.marker1;}
+var fromTs=fromMarker.ts,toTs=toMarker.ts;if(fromDomainId==ClockDomainId.BATTOR&&toMarker.duration>BATTOR_FAST_SYNC_THRESHOLD_MS){toTs=toMarker.startTs;}else if(toDomainId==ClockDomainId.BATTOR&&fromMarker.duration>BATTOR_FAST_SYNC_THRESHOLD_MS){fromTs=fromMarker.startTs;}
+var tsShift=toTs-fromTs;return function(ts){return ts+tsShift;};},isBetween:function(domain1Id,domain2Id){if(this.marker1.domainId===domain1Id&&this.marker2.domainId===domain2Id){return true;}
+if(this.marker1.domainId===domain2Id&&this.marker2.domainId===domain1Id){return true;}
+return false;}};return{ClockDomainId:ClockDomainId,ClockSyncManager:ClockSyncManager};});'use strict';tr.exportTo('tr.model',function(){function EventContainer(){this.guid_=tr.b.GUID.allocate();this.important=true;this.bounds_=new tr.b.Range();}
+EventContainer.prototype={get guid(){return this.guid_;},get stableId(){throw new Error('Not implemented');},get bounds(){return this.bounds_;},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'); [...]
+visit(this);},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){throw new Error('Not implemented.');},findTopmostSlices:function(eventPredicate,callback,opt_this){this.iterateAllEventContainers(function(ec){ec.findTopmostSlicesInThisContainer(eventPredicate,callback,opt_this);});},findTopmostSlicesNamed:function(name,callback,opt_this){this.findTopmostSlices(e=>e.title===name,callback,opt_this);}};return{EventContainer:EventContainer};});'use strict';tr.exportTo [...]
+PowerSample.prototype={__proto__:Event.prototype,get series(){return this.series_;},get start(){return this.start_;},set start(value){this.start_=value;},get power(){return this.power_;},set power(value){this.power_=value;},addBoundsToRange:function(range){range.addValue(this.start);}};EventRegistry.register(PowerSample,{name:'powerSample',pluralName:'powerSamples',singleViewElementName:'tr-ui-a-single-power-sample-sub-view',multiViewElementName:'tr-ui-a-multi-power-sample-sub-view'});re [...]
+PowerSeries.prototype={__proto__:tr.model.EventContainer.prototype,get device(){return this.device_;},get samples(){return this.samples_;},get stableId(){return this.device_.stableId+'.PowerSeries';},addPowerSample:function(ts,val){var sample=new PowerSample(this,ts,val);this.samples_.push(sample);return sample;},getEnergyConsumed:function(start,end){var measurementRange=tr.b.Range.fromExplicitRange(start,end);var energyConsumed=0;for(var i=0;i<this.samples.length;i++){var sample=this.sa [...]
+return energyConsumed;},shiftTimestampsForward:function(amount){for(var i=0;i<this.samples_.length;++i)
+this.samples_[i].start+=amount;},updateBounds:function(){this.bounds.reset();if(this.samples_.length===0)
+return;this.bounds.addValue(this.samples_[0].start);this.bounds.addValue(this.samples_[this.samples_.length-1].start);},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){if(eventTypePredicate.call(opt_this,PowerSample))
+this.samples_.forEach(callback,opt_this);},iterateAllChildEventContainers:function(callback,opt_this){}};return{PowerSeries:PowerSeries};});'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.powerSeries_=undefined;this.vSyncTimestamps_=[];};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 powerSeries(){return this [...]
+this.vSyncTimestamps_[i]+=amount;},addCategoriesToDict:function(categoriesDict){},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){},iterateAllChildEventContainers:function(callback,opt_this){if(this.powerSeries_)
+callback.call(opt_this,this.powerSeries_);}};return{Device:Device};});'use strict';tr.exportTo('tr.model',function(){function FlowEvent(category,id,title,colorId,start,args,opt_duration){tr.model.TimedEvent.call(this,start);this.category=category||'';this.title=title;this.colorId=colorId;this.start=start;this.args=args;this.id=id;this.startSlice=undefined;this.endSlice=undefined;this.startStackFrame=undefined;this.endStackFrame=undefined;if(opt_duration!==undefined)
+this.duration=opt_duration;}
+FlowEvent.prototype={__proto__:tr.model.TimedEvent.prototype,get userFriendlyName(){return'Flow event named '+this.title+' at '+
+tr.v.Unit.byName.timeStampInMs.format(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.model',function(){function ContainerMemoryDump(start){tr.model.TimedEvent.call(this,start);this.levelOfDetail=undefined;this.memoryAllocatorDumps_=undefined;this.memoryAlloc [...]
+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];},forceRebuildingMemoryAllocatorDumpByFullNameIndex:function(){this.memoryAllocatorDumpsByFullName_=undefined;},iterateRootAllocatorDumps:function(fn,opt_this){if(this.memoryAllocatorDumps===undefined)
+return;this.memoryAllocatorDumps.forEach(fn,opt_this||this);}};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.numerics={};this.diagnostics={};this.containerMemoryDump=containerMemoryDump;this.owns=undefined;this.ownedBy=[];this.ownedBySiblingSizes=new Map();this.retains=[];this.retainedBy=[];this.weak=fal [...]
+this.containerMemoryDump.containerName;},isDescendantOf:function(otherDump){var dump=this;while(dump!==undefined){if(dump===otherDump)
+return true;dump=dump.parent;}
+return false;},addNumeric:function(name,numeric){if(!(numeric instanceof tr.v.ScalarNumeric))
+throw new Error('Numeric value must be an instance of ScalarNumeric.');if(name in this.numerics)
+throw new Error('Duplicate numeric name: '+name+'.');this.numerics[name]=numeric;},addDiagnostic:function(name,text){if(typeof text!=='string')
+throw new Error('Diagnostic text must be a string.');if(name in this.diagnostics)
+throw new Error('Duplicate diagnostic name: '+name+'.');this.diagnostics[name]=text;},aggregateNumericsRecursively:function(opt_model){var numericNames=new Set();this.children.forEach(function(child){child.aggregateNumericsRecursively(opt_model);tr.b.iterItems(child.numerics,numericNames.add,numericNames);},this);numericNames.forEach(function(numericName){if(numericName===MemoryAllocatorDump.SIZE_NUMERIC_NAME||numericName===MemoryAllocatorDump.EFFECTIVE_SIZE_NUMERIC_NAME||this.numerics[n [...]
+this.numerics[numericName]=MemoryAllocatorDump.aggregateNumerics(this.children.map(function(child){return child.numerics[numericName];}),opt_model);},this);}};MemoryAllocatorDump.aggregateNumerics=function(numerics,opt_model){var shouldLogWarning=!!opt_model;var aggregatedUnit=undefined;var aggregatedValue=0;numerics.forEach(function(numeric){if(numeric===undefined)
+return;var unit=numeric.unit;if(aggregatedUnit===undefined){aggregatedUnit=unit;}else if(aggregatedUnit!==unit){if(shouldLogWarning){opt_model.importWarning({type:'numeric_parse_error',message:'Multiple units provided for numeric: \''+
+aggregatedUnit.unitName+'\' and \''+unit.unitName+'\'.'});shouldLogWarning=false;}
+aggregatedUnit=tr.v.Unit.byName.unitlessNumber_smallerIsBetter;}
+aggregatedValue+=numeric.value;},this);if(aggregatedUnit===undefined)
+return undefined;return new tr.v.ScalarNumeric(aggregatedUnit,aggregatedValue);};function MemoryAllocatorDumpLink(source,target,opt_importance){this.source=source;this.target=target;this.importance=opt_importance;this.size=undefined;}
+var MemoryAllocatorDumpInfoType={PROVIDED_SIZE_LESS_THAN_AGGREGATED_CHILDREN:0,PROVIDED_SIZE_LESS_THAN_LARGEST_OWNER:1};return{MemoryAllocatorDump:MemoryAllocatorDump,MemoryAllocatorDumpLink:MemoryAllocatorDumpLink,MemoryAllocatorDumpInfoType:MemoryAllocatorDumpInfoType};});'use strict';tr.exportTo('tr.model',function(){function GlobalMemoryDump(model,start){tr.model.ContainerMemoryDump.call(this,start);this.model=model;this.processMemoryDumps={};}
+var SIZE_NUMERIC_NAME=tr.model.MemoryAllocatorDump.SIZE_NUMERIC_NAME;var EFFECTIVE_SIZE_NUMERIC_NAME=tr.model.MemoryAllocatorDump.EFFECTIVE_SIZE_NUMERIC_NAME;var MemoryAllocatorDumpInfoType=tr.model.MemoryAllocatorDumpInfoType;var PROVIDED_SIZE_LESS_THAN_AGGREGATED_CHILDREN=MemoryAllocatorDumpInfoType.PROVIDED_SIZE_LESS_THAN_AGGREGATED_CHILDREN;var PROVIDED_SIZE_LESS_THAN_LARGEST_OWNER=MemoryAllocatorDumpInfoType.PROVIDED_SIZE_LESS_THAN_LARGEST_OWNER;function inPlaceFilter(array,predicat [...]
+continue;if(nextPosition<i)
+array[nextPosition]=array[i];nextPosition++;}
+if(nextPosition<array.length)
+array.length=nextPosition;}
+function getSize(dump){var numeric=dump.numerics[SIZE_NUMERIC_NAME];if(numeric===undefined)
+return 0;return numeric.value;}
+function hasSize(dump){return dump.numerics[SIZE_NUMERIC_NAME]!==undefined;}
+function optional(value,defaultValue){if(value===undefined)
+return defaultValue;return value;}
+GlobalMemoryDump.prototype={__proto__:tr.model.ContainerMemoryDump.prototype,get userFriendlyName(){return'Global memory dump at '+
+tr.v.Unit.byName.timeStampInMs.format(this.start);},get containerName(){return'global space';},finalizeGraph:function(){this.removeWeakDumps();this.setUpTracingOverheadOwnership();this.aggregateNumerics();this.calculateSizes();this.calculateEffectiveSizes();this.discountTracingOverheadFromVmRegions();this.forceRebuildingMemoryAllocatorDumpByFullNameIndices();},removeWeakDumps:function(){this.traverseAllocatorDumpsInDepthFirstPreOrder(function(dump){if(dump.weak)
+return;if((dump.owns!==undefined&&dump.owns.target.weak)||(dump.parent!==undefined&&dump.parent.weak)){dump.weak=true;}});function removeWeakDumpsFromListRecursively(dumps){inPlaceFilter(dumps,function(dump){if(dump.weak){return false;}
+removeWeakDumpsFromListRecursively(dump.children);inPlaceFilter(dump.ownedBy,function(ownershipLink){return!ownershipLink.source.weak;});return true;});}
+this.iterateContainerDumps(function(containerDump){var memoryAllocatorDumps=containerDump.memoryAllocatorDumps;if(memoryAllocatorDumps!==undefined)
+removeWeakDumpsFromListRecursively(memoryAllocatorDumps);});},calculateSizes:function(){this.traverseAllocatorDumpsInDepthFirstPostOrder(this.calculateMemoryAllocatorDumpSize_.bind(this));},calculateMemoryAllocatorDumpSize_:function(dump){var shouldDefineSize=false;function getDependencySize(dependencyDump){var numeric=dependencyDump.numerics[SIZE_NUMERIC_NAME];if(numeric===undefined)
+return 0;shouldDefineSize=true;return numeric.value;}
+var sizeNumeric=dump.numerics[SIZE_NUMERIC_NAME];var size=0;var checkDependencySizeIsConsistent=function(){};if(sizeNumeric!==undefined){size=sizeNumeric.value;shouldDefineSize=true;if(sizeNumeric.unit!==tr.v.Unit.byName.sizeInBytes_smallerIsBetter){this.model.importWarning({type:'memory_dump_parse_error',message:'Invalid unit of \'size\' numeric of memory allocator '+'dump '+dump.quantifiedName+': '+
+sizeNumeric.unit.unitName+'.'});}
+checkDependencySizeIsConsistent=function(dependencySize,dependencyInfoType,dependencyName){if(size>=dependencySize)
+return;this.model.importWarning({type:'memory_dump_parse_error',message:'Size provided by memory allocator dump \''+
+dump.fullName+'\''+
+tr.v.Unit.byName.sizeInBytes.format(size)+') is less than '+dependencyName+' ('+
+tr.v.Unit.byName.sizeInBytes.format(dependencySize)+').'});dump.infos.push({type:dependencyInfoType,providedSize:size,dependencySize:dependencySize});}.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 ownedChildDump=ownedDumpLink.target;while(ownedChildDump.parent!==dump)
+ownedChildDump=ownedChildDump.parent;if(childDump!==ownedChildDump){var ownedBySiblingSize=getDependencySize(descendantDump);if(ownedBySiblingSize>0){var previousTotalOwnedBySiblingSize=ownedChildDump.ownedBySiblingSizes.get(childDump)||0;var updatedTotalOwnedBySiblingSize=previousTotalOwnedBySiblingSize+ownedBySiblingSize;ownedChildDump.ownedBySiblingSizes.set(childDump,updatedTotalOwnedBySiblingSize);}}
+return;}
+if(descendantDump.children.length===0){aggregatedChildrenSize+=getDependencySize(descendantDump);return;}
+descendantDump.children.forEach(aggregateDescendantDump);}
+aggregateDescendantDump(childDump);});checkDependencySizeIsConsistent(aggregatedChildrenSize,PROVIDED_SIZE_LESS_THAN_AGGREGATED_CHILDREN,'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);});checkDependencySizeIsConsistent(largestOwnerSize,PROVIDED_SIZE_LESS_THAN_LARGEST_OWNER,'the size of its largest owner');i [...]
+size=Math.max(size,aggregatedChildrenSize,largestOwnerSize);dump.numerics[SIZE_NUMERIC_NAME]=new tr.v.ScalarNumeric(tr.v.Unit.byName.sizeInBytes_smallerIsBetter,size);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.numerics[SIZE_NUMERIC_NAME]=new tr.v.ScalarNumeric(tr.v.Unit. [...]
+return;if(dump.children===undefined||dump.children.length===0){var size=getSize(dump);dump.notOwningSubSize_=size;dump.notOwnedSubSize_=size;return;}
+var notOwningSubSize=0;dump.children.forEach(function(childDump){if(childDump.owns!==undefined)
+return;notOwningSubSize+=optional(childDump.notOwningSubSize_,0);});dump.notOwningSubSize_=notOwningSubSize;var notOwnedSubSize=0;dump.children.forEach(function(childDump){if(childDump.ownedBy.length===0){notOwnedSubSize+=optional(childDump.notOwnedSubSize_,0);return;}
+var largestChildOwnerSize=0;childDump.ownedBy.forEach(function(ownershipLink){largestChildOwnerSize=Math.max(largestChildOwnerSize,getSize(ownershipLink.source));});notOwnedSubSize+=getSize(childDump)-largestChildOwnerSize;});dump.notOwnedSubSize_=notOwnedSubSize;},calculateDumpOwnershipCoefficient_:function(dump){if(!hasSize(dump))
+return;if(dump.ownedBy.length===0)
+return;var owners=dump.ownedBy.map(function(ownershipLink){return{dump:ownershipLink.source,importance:optional(ownershipLink.importance,0),notOwningSubSize:optional(ownershipLink.source.notOwningSubSize_,0)};});owners.sort(function(a,b){if(a.importance===b.importance)
+return a.notOwningSubSize-b.notOwningSubSize;return b.importance-a.importance;});var currentImportanceStartPos=0;var alreadyAttributedSubSize=0;while(currentImportanceStartPos<owners.length){var currentImportance=owners[currentImportanceStartPos].importance;var nextImportanceStartPos=currentImportanceStartPos+1;while(nextImportanceStartPos<owners.length&&owners[nextImportanceStartPos].importance===currentImportance){nextImportanceStartPos++;}
+var attributedNotOwningSubSize=0;for(var pos=currentImportanceStartPos;pos<nextImportanceStartPos;pos++){var owner=owners[pos];var notOwningSubSize=owner.notOwningSubSize;if(notOwningSubSize>alreadyAttributedSubSize){attributedNotOwningSubSize+=(notOwningSubSize-alreadyAttributedSubSize)/(nextImportanceStartPos-pos);alreadyAttributedSubSize=notOwningSubSize;}
+var owningCoefficient=0;if(notOwningSubSize!==0)
+owningCoefficient=attributedNotOwningSubSize/notOwningSubSize;owner.dump.owningCoefficient_=owningCoefficient;}
+currentImportanceStartPos=nextImportanceStartPos;}
+var notOwnedSubSize=optional(dump.notOwnedSubSize_,0);var remainderSubSize=notOwnedSubSize-alreadyAttributedSubSize;var ownedCoefficient=0;if(notOwnedSubSize!==0)
+ownedCoefficient=remainderSubSize/notOwnedSubSize;dump.ownedCoefficient_=ownedCoefficient;},calculateDumpCumulativeOwnershipCoefficient_:function(dump){if(!hasSize(dump))
+return;var cumulativeOwnedCoefficient=optional(dump.ownedCoefficient_,1);var parent=dump.parent;if(dump.parent!==undefined)
+cumulativeOwnedCoefficient*=dump.parent.cumulativeOwnedCoefficient_;dump.cumulativeOwnedCoefficient_=cumulativeOwnedCoefficient;var cumulativeOwningCoefficient;if(dump.owns!==undefined){cumulativeOwningCoefficient=dump.owningCoefficient_*dump.owns.target.cumulativeOwningCoefficient_;}else if(dump.parent!==undefined){cumulativeOwningCoefficient=dump.parent.cumulativeOwningCoefficient_;}else{cumulativeOwningCoefficient=1;}
+dump.cumulativeOwningCoefficient_=cumulativeOwningCoefficient;},calculateDumpEffectiveSize_:function(dump){if(!hasSize(dump)){delete dump.numerics[EFFECTIVE_SIZE_NUMERIC_NAME];return;}
+var effectiveSize;if(dump.children===undefined||dump.children.length===0){effectiveSize=getSize(dump)*dump.cumulativeOwningCoefficient_*dump.cumulativeOwnedCoefficient_;}else{effectiveSize=0;dump.children.forEach(function(childDump){if(!hasSize(childDump))
+return;effectiveSize+=childDump.numerics[EFFECTIVE_SIZE_NUMERIC_NAME].value;});}
+dump.numerics[EFFECTIVE_SIZE_NUMERIC_NAME]=new tr.v.ScalarNumeric(tr.v.Unit.byName.sizeInBytes_smallerIsBetter,effectiveSize);},aggregateNumerics:function(){this.iterateRootAllocatorDumps(function(dump){dump.aggregateNumericsRecursively(this.model);});this.iterateRootAllocatorDumps(this.propagateNumericsAndDiagnosticsRecursively);tr.b.iterItems(this.processMemoryDumps,function(pid,processMemoryDump){processMemoryDump.iterateRootAllocatorDumps(function(dump){dump.aggregateNumericsRecursiv [...]
+processAllocatorDump[field][name]=value;});});});globalAllocatorDump.children.forEach(this.propagateNumericsAndDiagnosticsRecursively,this);},setUpTracingOverheadOwnership:function(){tr.b.iterItems(this.processMemoryDumps,function(pid,dump){dump.setUpTracingOverheadOwnership(this.model);},this);},discountTracingOverheadFromVmRegions:function(){tr.b.iterItems(this.processMemoryDumps,function(pid,dump){dump.discountTracingOverheadFromVmRegions(this.model);},this);},forceRebuildingMemoryAll [...]
+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);visitedDumps.add(dump);openDumps.delete(dump);}
+this.iterateAllRootAllocatorDumps(visit);},traverseAllocatorDumpsInDepthFirstPreOrder:function(fn){var visitedDumps=new WeakSet();function visit(dump){if(visitedDumps.has(dump))
+return;if(dump.owns!==undefined&&!visitedDumps.has(dump.owns.target))
+return;if(dump.parent!==undefined&&!visitedDumps.has(dump.parent))
+return;fn.call(this,dump);visitedDumps.add(dump);dump.ownedBy.forEach(function(ownershipLink){visit.call(this,ownershipLink.source);},this);dump.children.forEach(visit,this);}
+this.iterateAllRootAllocatorDumps(visit);}};tr.model.EventRegistry.register(GlobalMemoryDump,{name:'globalMemoryDump',pluralName:'globalMemoryDumps',singleViewElementName:'tr-ui-a-container-memory-dump-sub-view',multiViewElementName:'tr-ui-a-container-memory-dump-sub-view'});return{GlobalMemoryDump:GlobalMemoryDump};});'use strict';tr.exportTo('tr.model',function(){var InstantEventType={GLOBAL:1,PROCESS:2};function InstantEvent(category,title,colorId,start,args){tr.model.TimedEvent.call( [...]
+tr.v.Unit.byName.timeStampInMs.format(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+' @ '+
+tr.v.Unit.byName.timeStampInMs.format(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 CounterSample(series,t [...]
 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 [...]
+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.se [...]
+tr.v.Unit.byName.timeStampInMs.format(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.name_=name;this.color_=c [...]
 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++)
+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];}},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){if(eventTypePredicate.c [...]
+Counter.prototype={__proto__:tr.model.EventContainer.prototype,get parent(){return this.parent_;},get id(){return this.id_;},get category(){return this.category_;},get name(){return this.name_;},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){},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 [...]
+return x.tid-y.tid;return tmp;};return{Counter:Counter};});'use strict';tr.exportTo('tr.model',function(){var Slice=tr.model.Slice;function CpuSlice(cat,title,colorId,start,args,opt_duration){Slice.apply(this,arguments);this.threadThatWasRunning=undefined;this.cpu=undefined;}
 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))
+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 ColorScheme=tr.b.ColorScheme;var Counter=tr.model.Counter;var CpuSlice=tr.model.CpuSlice;var Slice=tr.model.Slice;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={get samples(){return this.samples_;},get userFriendlyName(){return'CPU '+this.cpuNumber;},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){this.slices.for [...]
 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++)
+callback.call(opt_this,this.counters[id]);},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];},getCounter:function(cat,name){var id=cat+'.'+name;if(!this.counters[id])
+return undefined;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)
+categoriesDict[this.samples_[i].category]=true;},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 duration=end_timestamp-this.lastActiveTimestamp_;var slice=new tr.model.CpuSlice('',this.lastActiveName_,ColorScheme.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,ne [...]
+stats[freqSample.value]=0;stats[freqSample.value]+=intersection.duration;}
+var freqCounter=this.getCounter('','Clock Frequency');if(freqCounter!==undefined){var freqSeries=freqCounter.getSeries(0);if(!freqSeries)
+return;tr.b.iterateOverIntersectingIntervals(freqSeries.samples_,function(x){return x.timestamp;},function(x,index){return index<freqSeries.length-1?freqSeries.samples_[index+1].timestamp:range.max;},range.min,range.max,addStatsForFreq);}
+return stats;}};Cpu.compare=function(x,y){return x.cpuNumber-y.cpuNumber;};return{Cpu:Cpu};});'use strict';tr.exportTo('tr.model',function(){function TimeToObjectInstanceMap(createObjectInstanceFunction,parent,scopedId){this.createObjectInstanceFunction_=createObjectInstanceFunction;this.parent=parent;this.scopedId=scopedId;this.instances=[];}
+TimeToObjectInstanceMap.prototype={idWasCreated:function(category,name,ts){if(this.instances.length==0){this.instances.push(this.createObjectInstanceFunction_(this.parent,this.scopedId,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));}
+lastInstance=this.createObjectInstanceFunction_(this.parent,this.scopedId,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.scopedId,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)
+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.scopedId,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));}
+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.scopedId,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;}
+throw new Error('Cannot delete an id before it was created');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)
+throw new Error('id was already deleted earlier.');lastInstance=this.createObjectInstanceFunction_(this.parent,this.scopedId,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)
+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.instanceMapsByScopedId_={};this.instancesByTypeName_={ [...]
+ObjectCollection.prototype={__proto__:tr.model.EventContainer.prototype,findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){},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 [...]
+instance.snapshots.forEach(callback,opt_this);},opt_this);},createObjectInstance_:function(parent,scopedId,category,name,creationTs,opt_baseTypeName){var constructor=tr.model.ObjectInstance.getConstructor(category,name);var instance=new constructor(parent,scopedId,category,name,creationTs,opt_baseTypeName);var typeName=instance.typeName;var instancesOfTypeName=this.instancesByTypeName_[typeName];if(!instancesOfTypeName){instancesOfTypeName=[];this.instancesByTypeName_[typeName]=instances [...]
+instancesOfTypeName.push(instance);return instance;},getOrCreateInstanceMap_:function(scopedId){var dict;if(scopedId.scope in this.instanceMapsByScopedId_){dict=this.instanceMapsByScopedId_[scopedId.scope];}else{dict={};this.instanceMapsByScopedId_[scopedId.scope]=dict;}
+var instanceMap=dict[scopedId.id];if(instanceMap)
+return instanceMap;instanceMap=new tr.model.TimeToObjectInstanceMap(this.createObjectInstance_,this.parent,scopedId);dict[scopedId.id]=instanceMap;return instanceMap;},idWasCreated:function(scopedId,category,name,ts){var instanceMap=this.getOrCreateInstanceMap_(scopedId);return instanceMap.idWasCreated(category,name,ts);},addSnapshot:function(scopedId,category,name,ts,args,opt_baseTypeName){var instanceMap=this.getOrCreateInstanceMap_(scopedId);var snapshot=instanceMap.addSnapshot(catego [...]
 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='+
@@ -2109,52 +3976,48 @@ 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 snapshot;},idWasDeleted:function(scopedId,category,name,ts){var instanceMap=this.getOrCreateInstanceMap_(scopedId);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 [...]
+deletedInstance.baseTypeName+' existed.');}},autoDeleteObjects:function(maxTimestamp){tr.b.iterItems(this.instanceMapsByScopedId_,function(scope,imapById){tr.b.iterItems(imapById,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(scopedId,ts){var instanceMap;if(scopedId.scope in this.instanceMapsByScopedId_)
+instanceMap=this.instanceMapsByScopedId_[scopedId.scope][scopedId.id];if(!instanceMap)
+return undefined;return instanceMap.getInstanceAt(ts);},getSnapshotAt:function(scopedId,ts){var instance=this.getObjectInstanceAt(scopedId,ts);if(!instance)
+return undefined;return instance.getSnapshotAt(ts);},iterObjectInstances:function(iter,opt_this){opt_this=opt_this||this;tr.b.iterItems(this.instanceMapsByScopedId_,function(scope,imapById){tr.b.iterItems(imapById,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];},getAll [...]
+AsyncSliceGroup.prototype={__proto__:tr.model.EventContainer.prototype,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_;},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){for(var i=0;i<this.slices.length;i++){var slice=this.slices[i];if(slice.isTopLevel)
+slice.findTopmostSlicesRelativeToThisSlice(eventPredicate,callback,opt_this);}},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 ColorScheme=tr.b.ColorScheme;var Slice=tr.model.Slice;function getSliceLo(s){return s.start;}
 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)
+function SliceGroup(parentContainer,opt_sliceConstructor,opt_name){tr.model.EventContainer.call(this);this.parentContainer_=parentContainer;var sliceConstructor=opt_sliceConstructor||Slice;this.sliceConstructor=sliceConstructor;this.openPartialSlices_=[];this.slices=[];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_)
+SliceGroup.prototype={__proto__:tr.model.EventContainer.prototype,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 [...]
+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,opt_c [...]
 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)
+var colorId=opt_colorId||ColorScheme.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)
+return undefined;return this.openPartialSlices_[this.openPartialSlices_.length-1];},endSlice:function(ts,opt_tts,opt_colorId){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 [...]
+throw new Error('Slice '+slice.title+' end time is before its start.');slice.duration=ts-slice.start;slice.didNotFinish=false;slice.colorId=opt_colorId||slice.colorId;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,opt_colorId,opt_bind_id){var colorId=opt_colorId||ColorScheme.getColorIdForGeneralPurposeString(title);var slice=new this.sliceConstructor(category,title,colorId,ts,opt_args?opt_args:{},duration,tts,cpuDuration,opt_argsStripped,opt_bind_id);if(duration===undefined)
+slice.didNotFinish=true;this.pushSlice(slice);return slice;},autoCloseOpenSlices:function(){this.updateBounds();var maxTimestamp=this.bounds.max;for(var sI=0;sI<this.slices.length;sI++){var slice=this.slices[sI];if(slice.didNotFinish)
+slice.duration=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 [...]
+throw new Error('Nope');this.topLevelSlices.forEach(function(s){s.findTopmostSlicesRelativeToThisSlice(eventPredicate,callback,opt_this);});},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){if(eventTypePredicate.call(opt_this,this.sliceConstructor))
 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)
+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;},findFirstSlice:function(){if(!this.haveTopLevelSlicesBeenBuilt)
+throw new Error('Nope');if(0===this.slices.length)
+return undefined;return this.slices[0];},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)
@@ -2176,7 +4039,7 @@ return;var ops=[];for(var i=0;i<this.slices.length;i++){if(this.slices[i].subSli
 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);}}
+var rootSlice=slices[0];this.topLevelSlices=[];this.topLevelSlices.push(rootSlice);rootSlice.isTopLevel=true;for(var i=1;i<slices.length;i++){var slice=slices[i];if(!addSliceIfBounds(rootSlice,slice)){rootSlice=slice;rootSlice.isTopLevel=true;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)
@@ -2191,26 +4054,12 @@ var newSlice=result.copySlice(oldSlice);newSlice.start=when;newSlice.duration=ol
 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)
+closeOpenSlices();return result;};return{SliceGroup:SliceGroup};});'use strict';tr.exportTo('tr.model',function(){var Slice=tr.model.Slice;function ThreadSlice(cat,title,colorId,start,args,opt_duration,opt_cpuStart,opt_cpuDuration,opt_argsStripped,opt_bind_id){Slice.call(this,cat,title,colorId,start,args,opt_duration,opt_cpuStart,opt_cpuDuration,opt_argsStripped,opt_bind_id);this.subSlices=[];}
+ThreadSlice.prototype={__proto__:Slice.prototype,get overlappingSamples(){var samples=new tr.model.EventSet();if(!this.parentContainer||!this.parentContainer.samples)
+return samples;this.parentContainer.samples.forEach(function(sample){if(this.start<=sample.start&&sample.start<=this.end)
+samples.push(sample);},this);return samples;}};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.model',function(){var AsyncSlice=tr.model.AsyncSlice;var AsyncSliceGroup=tr.model.AsyncSliceGroup;var Slice=tr.model.Slice;var SliceGroup=tr.model.SliceGroup;var ThreadSlice=tr.mode [...]
+throw new Error('Parent must be provided.');tr.model.EventContainer.call(this);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');}
+Thread.prototype={__proto__:tr.model.EventContainer.prototype,get model(){return this.parent.model;},get stableId(){return this.parent.stableId+'.'+this.tid;},compareTo:function(that){return Thread.compare(this,that);},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){},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))
@@ -2227,23 +4076,24 @@ if(this.samples_&&this.samples_.length){this.bounds.addValue(this.samples_[0].st
 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 [...]
+categoriesDict[this.samples_[i].category]=true;}},autoCloseOpenSlices:function(){this.sliceGroup.autoCloseOpenSlices();this.kernelSliceGroup.autoCloseOpenSlices();},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.sliceGroup.createSubSlices();this.samples_=this.p [...]
 (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))
+return undefined;return parentKey+'.'+this.name;},getProcess:function(){return this.parent;},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;},getCpuStatsForRange:function(range){var stats={};stats.total=0;if(!this.timeSlices)
+return stats;function addStatsForSlice(threadTimeSlice){var freqRange=tr.b.Range.fromExplicitRange(threadTimeSlice.start,threadTimeSlice.end);var intersection=freqRange.findIntersection(range);if(threadTimeSlice.schedulingState==tr.model.SCHEDULING_STATE.RUNNING){var cpu=threadTimeSlice.cpuOnWhichThreadWasRunning;if(!(cpu.cpuNumber in stats))
+stats[cpu.cpuNumber]=0;stats[cpu.cpuNumber]+=intersection.duration;stats.total+=intersection.duration;}}
+tr.b.iterateOverIntersectingIntervals(this.timeSlices,function(x){return x.start;},function(x){return x.end;},range.min,range.max,addStatsForSlice);return stats;},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 [...]
+throw new Error('Must provide a model');tr.model.EventContainer.call(this);this.model=model;this.threads={};this.counters={};this.objects=new tr.model.ObjectCollection(this);this.sortIndex=0;};ProcessBase.compare=function(x,y){return x.sortIndex-y.sortIndex;};ProcessBase.prototype={__proto__:tr.model.EventContainer.prototype,get stableId(){throw new Error('Not implemented');},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){},iterateAllChildEventContainers:func [...]
 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 [...]
+return n;},shiftTimestampsForward:function(amount){this.iterateAllChildEventContainers(function(child){child.shiftTimestampsForward(amount);});},autoCloseOpenSlices:function(){for(var tid in this.threads){var thread=this.threads[tid];thread.autoCloseOpenSlices();}},autoDeleteObjects:function(maxTimestamp){this.objects.autoDeleteObjects(maxTimestamp);},preInitializeObjects:function(){this.objects.preInitializeAllObjects();},initializeObjects:function(){this.objects.initializeAllObjects(); [...]
 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)
@@ -2260,62 +4110,70 @@ this.counters[id]=new Counter(this,id,cat,name);return this.counters[id];},getSe
 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 [...]
+return realCpuCount;return this.softwareMeasuredCpuCount;},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.addCategoriesToDic [...]
 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 [...]
+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 ModelIndices(model){this.flowEventsById_={};model.flowEvents.forEach(function(fe){if(fe.id!==undefined){if(!this.flowEventsById_.hasOwnProperty(fe.id)){this.flowEventsById_[fe.id]=new  [...]
+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.model',function(){function ModelStats(){this.traceEventCountsByKey_=new Map();this.allTraceEventStats_=[];this.traceEventStatsInTimeIntervals_=new Map();this.allTraceEventStatsInTimeIntervals_=[];this.hasEventSizesinBytes_=false;}
+ModelStats.prototype={TIME_INTERVAL_SIZE_IN_MS:100,willProcessBasicTraceEvent:function(phase,category,title,ts,opt_eventSizeinBytes){var key=phase+'/'+category+'/'+title;var eventStats=this.traceEventCountsByKey_.get(key);if(eventStats===undefined){eventStats={phase:phase,category:category,title:title,numEvents:0,totalEventSizeinBytes:0};this.traceEventCountsByKey_.set(key,eventStats);this.allTraceEventStats_.push(eventStats);}
+eventStats.numEvents++;var timeIntervalKey=Math.floor(tr.v.Unit.timestampFromUs(ts)/this.TIME_INTERVAL_SIZE_IN_MS);var eventStatsByTimeInverval=this.traceEventStatsInTimeIntervals_.get(timeIntervalKey);if(eventStatsByTimeInverval===undefined){eventStatsByTimeInverval={timeInterval:timeIntervalKey,numEvents:0,totalEventSizeinBytes:0};this.traceEventStatsInTimeIntervals_.set(timeIntervalKey,eventStatsByTimeInverval);this.allTraceEventStatsInTimeIntervals_.push(eventStatsByTimeInverval);}
+eventStatsByTimeInverval.numEvents++;if(opt_eventSizeinBytes!==undefined){this.hasEventSizesinBytes_=true;eventStats.totalEventSizeinBytes+=opt_eventSizeinBytes;eventStatsByTimeInverval.totalEventSizeinBytes+=opt_eventSizeinBytes;}},get allTraceEventStats(){return this.allTraceEventStats_;},get allTraceEventStatsInTimeIntervals(){return this.allTraceEventStatsInTimeIntervals_;},get hasEventSizesinBytes(){return this.hasEventSizesinBytes_;}};return{ModelStats:ModelStats};});'use strict';t [...]
 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= [...]
+(this.protectionFlags&VMRegion.PROTECTION_FLAG_EXECUTE?'x':'-')+
+(this.protectionFlags&VMRegion.PROTECTION_FLAG_MAYSHARE?'s':'p'));}};VMRegion.fromDict=function(dict){return new VMRegion(dict.startAddress,dict.sizeInBytes,dict.protectionFlags,dict.mappedFile,dict.byteStats);};function VMRegionClassificationNode(opt_rule){this.rule_=opt_rule||VMRegionClassificationNode.CLASSIFICATION_RULES;this.hasRegions=false;this.sizeInBytes=undefined;this.byteStats={};this.children_=undefined;this.regions_=[];}
+VMRegionClassificationNode.CLASSIFICATION_RULES={name:'Total',children:[{name:'Android',file:/^\/dev\/ashmem(?!\/libc malloc)/,children:[{name:'Java runtime',file:/^\/dev\/ashmem\/dalvik-/,children:[{name:'Spaces',file:/\/dalvik-(alloc|main|large object|non moving|zygote) space/,children:[{name:'Normal',file:/\/dalvik-(alloc|main)/},{name:'Large',file:/\/dalvik-large object/},{name:'Zygote',file:/\/dalvik-zygote/},{name:'Non-moving',file:/\/dalvik-non moving/}]},{name:'Linear Alloc',file [...]
+tree.addStatsFromRegion_(regions[i]);return tree;};VMRegionClassificationNode.prototype={get title(){return this.rule_.name;},get children(){if(this.isLeafNode)
+return undefined;if(this.children_===undefined)
+this.buildTree_();return this.children_;},get regions(){if(!this.isLeafNode){return undefined;}
+return this.regions_;},get allRegionsForTesting(){if(this.regions_!==undefined){if(this.children_!==undefined){throw new Error('Internal error: a VM region classification node '+'cannot have both regions and children');}
+return this.regions_;}
+var regions=[];this.children_.forEach(function(childNode){regions=regions.concat(childNode.allRegionsForTesting);});return regions;},get isLeafNode(){var children=this.rule_.children;return children===undefined||children.length===0;},addRegion:function(region){this.addRegionRecursively_(region,true);},someRegion:function(fn,opt_this){if(this.regions_!==undefined){return this.regions_.some(fn,opt_this);}
+return this.children_.some(function(childNode){return childNode.someRegion(fn,opt_this);});},addRegionRecursively_:function(region,addStatsToThisNode){if(addStatsToThisNode)
+this.addStatsFromRegion_(region);if(this.regions_!==undefined){if(this.children_!==undefined){throw new Error('Internal error: a VM region classification node '+'cannot have both regions and children');}
+this.regions_.push(region);return;}
+function regionRowMatchesChildNide(child){var fileRegExp=child.rule_.file;if(fileRegExp===undefined)
+return true;return fileRegExp.test(region.mappedFile);}
+var matchedChild=tr.b.findFirstInArray(this.children_,regionRowMatchesChildNide);if(matchedChild===undefined){if(this.children_.length!==this.rule_.children.length)
+throw new Error('Internal error');matchedChild=new VMRegionClassificationNode(VMRegionClassificationNode.OTHER_RULE);this.children_.push(matchedChild);}
+matchedChild.addRegionRecursively_(region,true);},buildTree_:function(){var cachedRegions=this.regions_;this.regions_=undefined;this.buildChildNodesRecursively_();for(var i=0;i<cachedRegions.length;i++){this.addRegionRecursively_(cachedRegions[i],false);}},buildChildNodesRecursively_:function(){if(this.children_!==undefined){throw new Error('Internal error: Classification node already has children');}
+if(this.regions_!==undefined&&this.regions_.length!==0){throw new Error('Internal error: Classification node should have no regions');}
+if(this.isLeafNode)
+return;this.regions_=undefined;this.children_=this.rule_.children.map(function(childRule){var child=new VMRegionClassificationNode(childRule);child.buildChildNodesRecursively_();return child;});},addStatsFromRegion_:function(region){this.hasRegions=true;var regionSizeInBytes=region.sizeInBytes;if(regionSizeInBytes!==undefined)
+this.sizeInBytes=(this.sizeInBytes||0)+regionSizeInBytes;var thisByteStats=this.byteStats;var regionByteStats=region.byteStats;for(var byteStatName in regionByteStats){var regionByteStatValue=regionByteStats[byteStatName];if(regionByteStatValue===undefined)
+continue;thisByteStats[byteStatName]=(thisByteStats[byteStatName]||0)+regionByteStatValue;}}};return{VMRegion:VMRegion,VMRegionClassificationNode:VMRegionClassificationNode};});'use strict';tr.exportTo('tr.model',function(){var DISCOUNTED_ALLOCATOR_NAMES=['winheap','malloc'];var TRACING_OVERHEAD_PATH=['allocated_objects','tracing_overhead'];var SIZE_NUMERIC_NAME=tr.model.MemoryAllocatorDump.SIZE_NUMERIC_NAME;var RESIDENT_SIZE_NUMERIC_NAME=tr.model.MemoryAllocatorDump.RESIDENT_SIZE_NUMERI [...]
+return 0;return sizeNumeric.value;}
+function ProcessMemoryDump(globalMemoryDump,process,start){tr.model.ContainerMemoryDump.call(this,start);this.process=process;this.globalMemoryDump=globalMemoryDump;this.totals=undefined;this.vmRegions=undefined;this.heapDumps=undefined;this.tracingOverheadOwnershipSetUp_=false;this.tracingOverheadDiscountedFromVmRegions_=false;};ProcessMemoryDump.prototype={__proto__:tr.model.ContainerMemoryDump.prototype,get userFriendlyName(){return'Process memory dump at '+
+tr.v.Unit.byName.timeStampInMs.format(this.start);},get containerName(){return this.process.userFriendlyName;},get processMemoryDumps(){var dumps={};dumps[this.process.pid]=this;return dumps;},get hasOwnVmRegions(){return this.vmRegions!==undefined;},setUpTracingOverheadOwnership:function(opt_model){if(this.tracingOverheadOwnershipSetUp_)
+return;this.tracingOverheadOwnershipSetUp_=true;var tracingDump=this.getMemoryAllocatorDumpByFullName('tracing');if(tracingDump===undefined||tracingDump.owns!==undefined){return;}
+if(tracingDump.owns!==undefined)
+return;var hasDiscountedFromAllocatorDumps=DISCOUNTED_ALLOCATOR_NAMES.some(function(allocatorName){var allocatorDump=this.getMemoryAllocatorDumpByFullName(allocatorName);if(allocatorDump===undefined)
+return false;var nextPathIndex=0;var currentDump=allocatorDump;var currentFullName=allocatorName;for(;nextPathIndex<TRACING_OVERHEAD_PATH.length;nextPathIndex++){var childFullName=currentFullName+'/'+
+TRACING_OVERHEAD_PATH[nextPathIndex];var childDump=this.getMemoryAllocatorDumpByFullName(childFullName);if(childDump===undefined)
+break;currentDump=childDump;currentFullName=childFullName;}
+for(;nextPathIndex<TRACING_OVERHEAD_PATH.length;nextPathIndex++){var childFullName=currentFullName+'/'+
+TRACING_OVERHEAD_PATH[nextPathIndex];var childDump=new tr.model.MemoryAllocatorDump(currentDump.containerMemoryDump,childFullName);childDump.parent=currentDump;currentDump.children.push(childDump);currentFullName=childFullName;currentDump=childDump;}
+var ownershipLink=new tr.model.MemoryAllocatorDumpLink(tracingDump,currentDump);tracingDump.owns=ownershipLink;currentDump.ownedBy.push(ownershipLink);return true;},this);if(hasDiscountedFromAllocatorDumps)
+this.forceRebuildingMemoryAllocatorDumpByFullNameIndex();},discountTracingOverheadFromVmRegions:function(opt_model){if(this.tracingOverheadDiscountedFromVmRegions_)
+return;this.tracingOverheadDiscountedFromVmRegions_=true;var tracingDump=this.getMemoryAllocatorDumpByFullName('tracing');if(tracingDump===undefined)
+return;var discountedSize=getSizeNumericValue(tracingDump,SIZE_NUMERIC_NAME);var discountedResidentSize=getSizeNumericValue(tracingDump,RESIDENT_SIZE_NUMERIC_NAME);if(discountedSize<=0&&discountedResidentSize<=0)
+return;if(this.totals!==undefined){if(this.totals.residentBytes!==undefined)
+this.totals.residentBytes-=discountedResidentSize;if(this.totals.peakResidentBytes!==undefined)
+this.totals.peakResidentBytes-=discountedResidentSize;}
+if(this.vmRegions!==undefined){var hasSizeInBytes=this.vmRegions.sizeInBytes!==undefined;var hasPrivateDirtyResident=this.vmRegions.byteStats.privateDirtyResident!==undefined;var hasProportionalResident=this.vmRegions.byteStats.proportionalResident!==undefined;if((hasSizeInBytes&&discountedSize>0)||((hasPrivateDirtyResident||hasProportionalResident)&&discountedResidentSize>0)){var byteStats={};if(hasPrivateDirtyResident)
+byteStats.privateDirtyResident=-discountedResidentSize;if(hasProportionalResident)
+byteStats.proportionalResident=-discountedResidentSize;this.vmRegions.addRegion(tr.model.VMRegion.fromDict({mappedFile:'[discounted tracing overhead]',sizeInBytes:hasSizeInBytes?-discountedSize:undefined,byteStats:byteStats}));}}}};ProcessMemoryDump.hookUpMostRecentVmRegionsLinks=function(processDumps){var mostRecentVmRegions=undefined;processDumps.forEach(function(processDump){if(processDump.vmRegions!==undefined)
+mostRecentVmRegions=processDump.vmRegions;processDump.mostRecentVmRegions=mostRecentVmRegions;});};tr.model.EventRegistry.register(ProcessMemoryDump,{name:'processMemoryDump',pluralName:'processMemoryDumps',singleViewElementName:'tr-ui-a-container-memory-dump-sub-view',multiViewElementName:'tr-ui-a-container-memory-dump-sub-view'});return{ProcessMemoryDump:ProcessMemoryDump};});'use strict';tr.exportTo('tr.model',function(){var ProcessBase=tr.model.ProcessBase;var ProcessInstantEvent=tr. [...]
 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)
+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=[];this.activities=[];};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 [...]
+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);},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){ProcessBase.prototype.iterateAllEventsInThisContainer.call(this,eventTypePredicate,callback,opt_this);if(eventTypePredicate.call(opt_this,ProcessInstantEvent))
 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)
+this.memoryDumps.forEach(callback,opt_this);},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
@@ -2323,160 +4181,1340 @@ 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++)
+return'processes.'+this.name;return'processes.'+this.name+'.'+this.labels.join('.');},shiftTimestampsForward:function(amount){for(var i=0;i<this.instantEvents.length;i++)
+this.instantEvents[i].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.memoryDumps[i].shiftTimestampsForward(amount);for(var i=0;i<this.activities.length;i++)
+this.activities[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.memoryDumps[i].addBoundsToRange(this.bounds);for(var i=0;i<this.activities.length;i++)
+this.activities[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;thi [...]
+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.v.Unit.byName.timeStampInMs.format(this.start);}};tr.model.EventRegistry.register(Sample,{name:'sample',pluralName:'samples',singleViewElementName:'tr-ui-a-single-sample-sub-view',multiVi [...]
+throw new Error('id must be given');this.parentFrame_=parentFrame;this.id=id;this.title_=title;this.colorId=colorId;this.children=[];this.sourceInfo_=opt_sourceInfo;if(this.parentFrame_)
 this.parentFrame_.addChild(this);}
-StackFrame.prototype={get parentFrame(){return this.parentFrame_;},set parentFrame(parentFrame){if(this.parentFrame_)
+StackFrame.prototype={get parentFrame(){return this.parentFrame_;},get title(){if(this.sourceInfo_){var src=this.sourceInfo_.toString();return this.title_+(src===''?'':' '+src);}
+return this.title_;},get domain(){var result='unknown';if(this.sourceInfo_&&this.sourceInfo_.domain)
+result=this.sourceInfo_.domain;if(result==='unknown'&&this.parentFrame)
+result=this.parentFrame.domain;return result;},get sourceInfo(){return this.sourceInfo_;},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 stack;},getUserFriendlyStackTrace:function(){return this.stackTrace.map(function(x){return x.title;});}};return{StackFrame:StackFrame};});'use strict';tr.exportTo('tr.model.um',function(){function UserModel(parentModel){tr.model.EventContainer.call(this);this.parentModel_=parentModel;this.expectations_=new tr.model.EventSet();}
+UserModel.prototype={__proto__:tr.model.EventContainer.prototype,get stableId(){return'UserModel';},get parentModel(){return this.parentModel_;},sortExpectations:function(){Array.prototype.sort.call(this.expectations_,function(x,y){return x.start-y.start;});},get expectations(){return this.expectations_;},shiftTimestampsForward:function(amount){},addCategoriesToDict:function(categoriesDict){},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){},iterateAllEventsIn [...]
+this.expectations.forEach(callback,opt_this);},iterateAllChildEventContainers:function(callback,opt_this){},updateBounds:function(){this.bounds.reset();this.expectations.forEach(function(expectation){expectation.addBoundsToRange(this.bounds);},this);}};return{UserModel:UserModel};});'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};});'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);}}
+function extractUrlString(url){var extracted=url.replace(/url\((.*)\)/,'$1');extracted=extracted.replace(/\"(.*)\"/,'$1');return extracted;}
+function toThreeDigitLocaleString(value){return value.toLocaleString(undefined,{minimumFractionDigits:3,maximumFractionDigits:3});}
+return{toThreeDigitLocaleString:toThreeDigitLocaleString,instantiateTemplate:instantiateTemplate,windowRectForElement:windowRectForElement,scrollIntoViewIfNeeded:scrollIntoViewIfNeeded,extractUrlString:extractUrlString};});'use strict';tr.exportTo('tr.ui.b',function(){if(tr.isHeadless)
+return{};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_.bind(this);this.onClick_=this.onClick_.bind(this);this.onFocusIn_=this.onFocusIn_.bind(this);this.onDocumentClick_=this.onDocumentClick_.bind(this);this.onClose_=this.onClose_. [...]
+return;this.visible_=newValue;var e=new tr.b.Event('visible-change');this.dispatchEvent(e);},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('click',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',function(){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 Sample=tr.model.Sample;function Model(){tr.model.EventContainer.call(this);tr.b.EventTarget.decorate(this);this.timestampShiftToZeroAmount_=0;this.faviconHue='blue';this.device=new  [...]
+Model.prototype={__proto__:tr.model.EventContainer.prototype,getOrCreateHelper:function(constructor){if(!constructor.guid)
+throw new Error('Helper constructors must have GUIDs');if(this.helpersByConstructorGUID_[constructor.guid]===undefined){if(this.doesHelperGUIDSupportThisModel_[constructor.guid]===undefined){this.doesHelperGUIDSupportThisModel_[constructor.guid]=constructor.supportsModel(this);}
+if(!this.doesHelperGUIDSupportThisModel_[constructor.guid])
+return undefined;this.helpersByConstructorGUID_[constructor.guid]=new constructor(this);}
+return this.helpersByConstructorGUID_[constructor.guid];},findTopmostSlicesInThisContainer:function(eventPredicate,callback,opt_this){},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,Sample))
+this.samples.forEach(callback,opt_this);},iterateAllChildEventContainers:function(callback,opt_this){callback.call(opt_this,this.userModel);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.timestampShiftToZeroAmount_=shiftAmount;this.iterateAllChildEventContai [...]
+throw new Error('Only traceEventClock is supported.');return tr.v.Unit.timestampFromUs(ts)+
+this.timestampShiftToZeroAmount_;},get numProcesses(){var n=0;for(var p in this.processes)
+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];},addStackFrame:function(stackFrame){if(this.stackFrames[stackFrame.id])
+throw new Error('Stack frame already exists');this.stackFrames[stackFrame.id]=stackFrame;return stackFrame;},getClockSyncRecordsWithSyncId:function(syncId){return this.clockSyncRecords.filter(function(x){return x.syncId===syncId;});},updateCategories_:function(){var categoriesDict={};this.userModel.addCategoriesToDict(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_);},addUserFriendlyCategoryDriver:function(ufcd){this.userFri [...]
+return ufc;}
+return undefined;},findAllThreadsNamed:function(name){var namedThreads=[];namedThreads.push.apply(namedThreads,this.kernel.findAllThreadsNamed(name));for(var pid in this.processes){namedThreads.push.apply(namedThreads,this.processes[pid].findAllThreadsNamed(name));}
+return namedThreads;},get importOptions(){return this.importOptions_;},set importOptions(options){this.importOptions_=options;},get intrinsicTimeUnit(){if(this.intrinsicTimeUnit_===undefined)
+return tr.v.TimeDisplayModes.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 isTimeHighResolution(){if(this.isTimeHighResolution_===undefined)
+this.isTimeHighResolution_=this.isTimeHighResolutionHeuristic_();return this.isTimeHighResolution_;},set isTimeHighResolution(value){if(this.isTimeHighResolution_===value)
+return;if(this.isTimeHighResolution_!==undefined)
+throw new Error('isTimeHighResolution already set');this.isTimeHighResolution_=value;},get canonicalUrl(){return this.canonicalUrl_;},set canonicalUrl(value){if(this.canonicalUrl_===value)
+return;if(this.canonicalUrl_!==undefined)
+throw new Error('canonicalUrl already set');this.canonicalUrl_=value;},importWarning:function(data){data.showToUser=!!data.showToUser;this.importWarnings_.push(data);if(this.reportedImportWarnings_[data.type]===true)
+return;if(this.importOptions_.showImportWarnings)
+console.warn(data.message);this.reportedImportWarnings_[data.type]=true;},get hasImportWarnings(){return(this.importWarnings_.length>0);},get importWarnings(){return this.importWarnings_;},get importWarningsThatShouldBeShownToUser(){return this.importWarnings_.filter(function(warning){return warning.showToUser;});},autoCloseOpenSlices:function(){this.samples.sort(function(x,y){return x.start-y.start;});this.updateBounds();this.kernel.autoCloseOpenSlices();for(var pid in this.processes)
+this.processes[pid].autoCloseOpenSlices();},createSubSlices:function(){this.kernel.createSubSlices();for(var pid in this.processes)
+this.processes[pid].createSubSlices();},preInitializeObjects:function(){for(var pid in this.processes)
+this.processes[pid].preInitializeObjects();},initializeObjects:function(){for(var pid in this.processes)
+this.processes[pid].initializeObjects();},pruneEmptyContainers:function(){this.kernel.pruneEmptyContainers();for(var pid in this.processes)
+this.processes[pid].pruneEmptyContainers();},mergeKernelWithUserland:function(){for(var pid in this.processes)
+this.processes[pid].mergeKernelWithUserland();},computeWorldBounds:function(shiftWorldToZero){this.updateBounds();this.updateCategories_();if(shiftWorldToZero)
+this.shiftWorldToZero();},buildFlowEventIntervalTree:function(){for(var i=0;i<this.flowEvents.length;++i){var flowEvent=this.flowEvents[i];this.flowIntervalTree.insert(flowEvent);}
+this.flowIntervalTree.updateHighValues();},cleanupUndeletedObjects:function(){for(var pid in this.processes)
+this.processes[pid].autoDeleteObjects(this.bounds.max);},sortMemoryDumps:function(){this.globalMemoryDumps.sort(function(x,y){return x.start-y.start;});for(var pid in this.processes)
+this.processes[pid].sortMemoryDumps();},finalizeMemoryGraphs:function(){this.globalMemoryDumps.forEach(function(dump){dump.finalizeGraph();});},buildEventIndices:function(){this.modelIndices=new tr.model.ModelIndices(this);},sortAlerts:function(){this.alerts.sort(function(x,y){return x.start-y.start;});},applyObjectRefPatchups:function(){var unresolved=[];this.patchupsToApply_.forEach(function(patchup){if(patchup.pidRef in this.processes){var snapshot=this.processes[patchup.pidRef].objec [...]
+unresolved.push(patchup);},this);this.patchupsToApply_=unresolved;},replacePIDRefsInPatchups:function(old_pid_ref,new_pid_ref){this.patchupsToApply_.forEach(function(patchup){if(patchup.pidRef===old_pid_ref)
+patchup.pidRef=new_pid_ref;});},isTimeHighResolutionHeuristic_:function(){if(this.intrinsicTimeUnit!==tr.v.TimeDisplayModes.ms)
+return false;var nbEvents=0;var nbPerBin=[];var maxEvents=0;for(var i=0;i<100;++i)
+nbPerBin.push(0);this.iterateAllEvents(function(event){nbEvents++;if(event.start!==undefined){var remainder=Math.floor((event.start-Math.floor(event.start))*100);nbPerBin[remainder]++;maxEvents=Math.max(maxEvents,nbPerBin[remainder]);}});if(nbEvents<100)
+return true;return(maxEvents/nbEvents)<0.9;},joinRefs:function(){this.joinObjectRefs_();this.applyObjectRefPatchups();},joinObjectRefs_:function(){tr.b.iterItems(this.processes,function(pid,process){this.joinObjectRefsForProcess_(pid,process);},this);},joinObjectRefsForProcess_:function(pid,process){tr.b.iterItems(process.threads,function(tid,thread){thread.asyncSliceGroup.slices.forEach(function(item){this.searchItemForIDRefs_(pid,'start',item);},this);thread.sliceGroup.slices.forEach(f [...]
+return;var patchupsToApply=this.patchupsToApply_;function handleField(object,fieldName,fieldValue){if(!fieldValue||(!fieldValue.id_ref&&!fieldValue.idRef))
+return;var scope=fieldValue.scope||tr.model.OBJECT_DEFAULT_SCOPE;var idRef=fieldValue.id_ref||fieldValue.idRef;var scopedId=new tr.model.ScopedId(scope,idRef);var pidRef=fieldValue.pid_ref||fieldValue.pidRef||pid;var ts=item[itemTimestampField];patchupsToApply.push({object:object,field:fieldName,pidRef:pidRef,scopedId:scopedId,ts:ts});}
+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);}};return{Model:Model};});'use strict';tr.exportTo('tr.e.importer.etw',function(){var kThreadGuid='3D6FA8D1-FE05-11D0-9DDA-00C04FD7BA7C';var kThreadDCStartOpcode=3;function Decoder(){this.payload_=new DataView(new ArrayBuffer(256));};Decoder.prototype={__proto__:Object.prototype,reset:function(base64_payload){var decoded_size=tr.b.Base64.getDecodedBufferLength(base64_payload);if(decoded_size>this.payload_.byteLength)
+this.payload_=new DataView(new ArrayBuffer(decoded_size));tr.b.Base64.DecodeToTypedArray(base64_payload,this.payload_);this.position_=0;},skip:function(length){this.position_+=length;},decodeUInt8:function(){var result=this.payload_.getUint8(this.position_,true);this.position_+=1;return result;},decodeUInt16:function(){var result=this.payload_.getUint16(this.position_,true);this.position_+=2;return result;},decodeUInt32:function(){var result=this.payload_.getUint32(this.position_,true);t [...]
+return this.decodeUInt64ToString();return this.decodeUInt32();},decodeString:function(){var str='';while(true){var c=this.decodeUInt8();if(!c)
+return str;str=str+String.fromCharCode(c);}},decodeW16String:function(){var str='';while(true){var c=this.decodeUInt16();if(!c)
+return str;str=str+String.fromCharCode(c);}},decodeFixedW16String:function(length){var old_position=this.position_;var str='';for(var i=0;i<length;i++){var c=this.decodeUInt16();if(!c)
+break;str=str+String.fromCharCode(c);}
+this.position_=old_position+2*length;return str;},decodeBytes:function(length){var bytes=[];for(var i=0;i<length;++i){var c=this.decodeUInt8();bytes.push(c);}
+return bytes;},decodeSID:function(is64){var pSid=this.decodeUInteger(is64);var attributes=this.decodeUInt32();if(is64)
+this.decodeUInt32();var revision=this.decodeUInt8();var subAuthorityCount=this.decodeUInt8();this.decodeUInt16();this.decodeUInt32();if(revision!=1)
+throw'Invalid SID revision: could not decode the SID structure.';var sid=this.decodeBytes(4*subAuthorityCount);return{pSid:pSid,attributes:attributes,sid:sid};},decodeSystemTime:function(){var wYear=this.decodeInt16();var wMonth=this.decodeInt16();var wDayOfWeek=this.decodeInt16();var wDay=this.decodeInt16();var wHour=this.decodeInt16();var wMinute=this.decodeInt16();var wSecond=this.decodeInt16();var wMilliseconds=this.decodeInt16();return{wYear:wYear,wMonth:wMonth,wDayOfWeek:wDayOfWeek [...]
+EtwImporter.canImport=function(events){if(!events.hasOwnProperty('name')||!events.hasOwnProperty('content')||events.name!=='ETW'){return false;}
+return true;};EtwImporter.prototype={__proto__:tr.importer.Importer.prototype,get importerName(){return'EtwImporter';},get model(){return this.model_;},createThreadIfNeeded:function(pid,tid){this.tidsToPid_[tid]=pid;},removeThreadIfPresent:function(tid){this.tidsToPid_[tid]=undefined;},getPidFromWindowsTid:function(tid){if(tid==0)
+return 0;var pid=this.tidsToPid_[tid];if(pid==undefined){return 0;}
+return pid;},getThreadFromWindowsTid:function(tid){var pid=this.getPidFromWindowsTid(tid);var process=this.model_.getProcess(pid);if(!process)
+return undefined;return process.getThread(tid);},getOrCreateCpu:function(cpuNumber){var cpu=this.model_.kernel.getOrCreateCpu(cpuNumber);return cpu;},importEvents:function(){this.events_.content.forEach(this.parseInfo.bind(this));if(this.walltime_==undefined||this.ticks_==undefined)
+throw Error('Cannot find clock sync information in the system trace.');if(this.is64bit_==undefined)
+throw Error('Cannot determine pointer size of the system trace.');this.events_.content.forEach(this.parseEvent.bind(this));},importTimestamp:function(timestamp){var ts=parseInt(timestamp,16);return(ts-this.walltime_+this.ticks_)/1000.;},parseInfo:function(event){if(event.hasOwnProperty('guid')&&event.hasOwnProperty('walltime')&&event.hasOwnProperty('tick')&&event.guid==='ClockSync'){this.walltime_=parseInt(event.walltime,16);this.ticks_=parseInt(event.tick,16);}
+if(this.is64bit_==undefined&&event.hasOwnProperty('guid')&&event.hasOwnProperty('op')&&event.hasOwnProperty('ver')&&event.hasOwnProperty('payload')&&event.guid===kThreadGuid&&event.op==kThreadDCStartOpcode){var decoded_size=tr.b.Base64.getDecodedBufferLength(event.payload);if(event.ver==1){if(decoded_size>=52)
+this.is64bit_=true;else
+this.is64bit_=false;}else if(event.ver==2){if(decoded_size>=64)
+this.is64bit_=true;else
+this.is64bit_=false;}else if(event.ver==3){if(decoded_size>=60)
+this.is64bit_=true;else
+this.is64bit_=false;}}
+return true;},parseEvent:function(event){if(!event.hasOwnProperty('guid')||!event.hasOwnProperty('op')||!event.hasOwnProperty('ver')||!event.hasOwnProperty('cpu')||!event.hasOwnProperty('ts')||!event.hasOwnProperty('payload')){return false;}
+var timestamp=this.importTimestamp(event.ts);var header={guid:event.guid,opcode:event.op,version:event.ver,cpu:event.cpu,timestamp:timestamp,is64:this.is64bit_};var decoder=this.decoder_;decoder.reset(event.payload);var handler=this.getEventHandler(header.guid,header.opcode);if(!handler)
+return false;if(!handler(header,decoder)){this.model_.importWarning({type:'parse_error',message:'Malformed '+header.guid+' event ('+text+')'});return false;}
+return true;},registerEventHandler:function(guid,opcode,handler){if(this.handlers_[guid]==undefined)
+this.handlers_[guid]=[];this.handlers_[guid][opcode]=handler;},getEventHandler:function(guid,opcode){if(this.handlers_[guid]==undefined)
+return undefined;return this.handlers_[guid][opcode];}};tr.importer.Importer.register(EtwImporter);return{EtwImporter:EtwImporter};});!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;"undefined"!=typeof window?b=window:"undefined"!=typeof global?b=global:"undefined"!=typeof self&&(b=self),b.JSZip=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i=" [...]
+throw new Error('Unknown gzip data format');this.model_=model;this.gzipData_=eventData;}
+GzipImporter.canImport=function(eventData){var header;if(eventData instanceof ArrayBuffer)
+header=new Uint8Array(eventData.slice(0,GZIP_MEMBER_HEADER_ID_SIZE));else if(typeof(eventData)==='string'||eventData instanceof String){header=eventData.substring(0,GZIP_MEMBER_HEADER_ID_SIZE);header=JSZip.utils.transformTo('uint8array',header);}else
+return false;return header[0]==GZIP_HEADER_ID1&&header[1]==GZIP_HEADER_ID2&&header[2]==GZIP_DEFLATE_COMPRESSION;};GzipImporter.inflateGzipData_=function(data){var position=0;function getByte(){if(position>=data.length)
+throw new Error('Unexpected end of gzip data');return data[position++];}
+function getWord(){var low=getByte();var high=getByte();return(high<<8)+low;}
+function skipBytes(amount){position+=amount;}
+function skipZeroTerminatedString(){while(getByte()!=0){}}
+var id1=getByte();var id2=getByte();if(id1!==GZIP_HEADER_ID1||id2!==GZIP_HEADER_ID2)
+throw new Error('Not gzip data');var compression_method=getByte();if(compression_method!==GZIP_DEFLATE_COMPRESSION)
+throw new Error('Unsupported compression method: '+compression_method);var flags=getByte();var have_header_crc=flags&(1<<1);var have_extra_fields=flags&(1<<2);var have_file_name=flags&(1<<3);var have_comment=flags&(1<<4);skipBytes(4+1+1);if(have_extra_fields){var bytes_to_skip=getWord();skipBytes(bytes_to_skip);}
+if(have_file_name)
+skipZeroTerminatedString();if(have_comment)
+skipZeroTerminatedString();if(have_header_crc)
+getWord();var inflated_data=JSZip.compressions['DEFLATE'].uncompress(data.subarray(position));var string=GzipImporter.transformToString(inflated_data);if(inflated_data.length>0&&string.length===0){throw new RangeError('Inflated gzip data too long to fit into a string'+' ('+inflated_data.length+').');}
+return string;};GzipImporter.transformToString=function(data){if(typeof TextDecoder==='undefined'){return JSZip.utils.transformTo('string',data);}
+var type=JSZip.utils.getTypeOf(data);if(type==='string')
+return data;if(type==='array'){data=new Uint8Array(data);}
+var decoder=new TextDecoder('utf-8');return decoder.decode(data);};GzipImporter.prototype={__proto__:tr.importer.Importer.prototype,get importerName(){return'GzipImporter';},isTraceDataContainer:function(){return true;},extractSubtraces:function(){var eventData=GzipImporter.inflateGzipData_(this.gzipData_);return eventData?[eventData]:[];}};tr.importer.Importer.register(GzipImporter);return{GzipImporter:GzipImporter};});'use strict';tr.exportTo('tr.importer',function(){function SimpleLin [...]
+SimpleLineReader.prototype={advanceToLineMatching:function(regex){for(;this.curLine_<this.lines_.length;this.curLine_++){var line=this.lines_[this.curLine_];if(this.savedLines_!==undefined)
+this.savedLines_.push(line);if(regex.test(line))
+return true;}
+return false;},get curLineNumber(){return this.curLine_;},beginSavingLines:function(){this.savedLines_=[];},endSavingLinesAndGetResult:function(){var tmp=this.savedLines_;this.savedLines_=undefined;return tmp;}};return{SimpleLineReader:SimpleLineReader};});'use strict';tr.exportTo('tr.e.importer',function(){function Trace2HTMLImporter(model,events){this.importPriority=0;}
+Trace2HTMLImporter.subtraces_=[];function _extractEventsFromHTML(text){Trace2HTMLImporter.subtraces_=[];var r=new tr.importer.SimpleLineReader(text);while(true){if(!r.advanceToLineMatching(new RegExp('^<\s*script id="viewer-data" '+'type="(application\/json|text\/plain)">$')))
+break;r.beginSavingLines();if(!r.advanceToLineMatching(/^<\/\s*script>$/))
+return failure;var raw_events=r.endSavingLinesAndGetResult();raw_events=raw_events.slice(1,raw_events.length-1);var data64=raw_events.join('\n');var buffer=new ArrayBuffer(tr.b.Base64.getDecodedBufferLength(data64));var len=tr.b.Base64.DecodeToTypedArray(data64,new DataView(buffer));Trace2HTMLImporter.subtraces_.push(buffer.slice(0,len));}}
+function _canImportFromHTML(text){if(/^<!DOCTYPE html>/.test(text)===false)
+return false;_extractEventsFromHTML(text);if(Trace2HTMLImporter.subtraces_.length===0)
+return false;return true;}
+Trace2HTMLImporter.canImport=function(events){return _canImportFromHTML(events);};Trace2HTMLImporter.prototype={__proto__:tr.importer.Importer.prototype,get importerName(){return'Trace2HTMLImporter';},isTraceDataContainer:function(){return true;},extractSubtraces:function(){return Trace2HTMLImporter.subtraces_;},importEvents:function(){}};tr.importer.Importer.register(Trace2HTMLImporter);return{Trace2HTMLImporter:Trace2HTMLImporter};});'use strict';tr.exportTo('tr.e.importer.v8',function [...]
+this.splay_(key);if(this.root_.key==key){return;}
+var node=new SplayTree.Node(key,value);if(key>this.root_.key){node.left=this.root_;node.right=this.root_.right;this.root_.right=null;}else{node.right=this.root_;node.left=this.root_.left;this.root_.left=null;}
+this.root_=node;};SplayTree.prototype.remove=function(key){if(this.isEmpty()){throw Error('Key not found: '+key);}
+this.splay_(key);if(this.root_.key!=key){throw Error('Key not found: '+key);}
+var removed=this.root_;if(!this.root_.left){this.root_=this.root_.right;}else{var right=this.root_.right;this.root_=this.root_.left;this.splay_(key);this.root_.right=right;}
+return removed;};SplayTree.prototype.find=function(key){if(this.isEmpty()){return null;}
+this.splay_(key);return this.root_.key==key?this.root_:null;};SplayTree.prototype.findMin=function(){if(this.isEmpty()){return null;}
+var current=this.root_;while(current.left){current=current.left;}
+return current;};SplayTree.prototype.findMax=function(opt_startNode){if(this.isEmpty()){return null;}
+var current=opt_startNode||this.root_;while(current.right){current=current.right;}
+return current;};SplayTree.prototype.findGreatestLessThan=function(key){if(this.isEmpty()){return null;}
+this.splay_(key);if(this.root_.key<=key){return this.root_;}else if(this.root_.left){return this.findMax(this.root_.left);}else{return null;}};SplayTree.prototype.exportKeysAndValues=function(){var result=[];this.traverse_(function(node){result.push([node.key,node.value]);});return result;};SplayTree.prototype.exportValues=function(){var result=[];this.traverse_(function(node){result.push(node.value);});return result;};SplayTree.prototype.splay_=function(key){if(this.isEmpty()){return;}
+var dummy,left,right;dummy=left=right=new SplayTree.Node(null,null);var current=this.root_;while(true){if(key<current.key){if(!current.left){break;}
+if(key<current.left.key){var tmp=current.left;current.left=tmp.right;tmp.right=current;current=tmp;if(!current.left){break;}}
+right.left=current;right=current;current=current.left;}else if(key>current.key){if(!current.right){break;}
+if(key>current.right.key){var tmp=current.right;current.right=tmp.left;tmp.left=current;current=tmp;if(!current.right){break;}}
+left.right=current;left=current;current=current.right;}else{break;}}
+left.right=current.left;right.left=current.right;current.left=dummy.right;current.right=dummy.left;this.root_=current;};SplayTree.prototype.traverse_=function(f){var nodesToVisit=[this.root_];while(nodesToVisit.length>0){var node=nodesToVisit.shift();if(node==null){continue;}
+f(node);nodesToVisit.push(node.left);nodesToVisit.push(node.right);}};SplayTree.Node=function(key,value){this.key=key;this.value=value;};SplayTree.Node.prototype.left=null;SplayTree.Node.prototype.right=null;return{SplayTree:SplayTree};});'use strict';tr.exportTo('tr.e.importer.v8',function(){function CodeMap(){this.dynamics_=new tr.e.importer.v8.SplayTree();this.dynamicsNameGen_=new tr.e.importer.v8.CodeMap.NameGenerator();this.statics_=new tr.e.importer.v8.SplayTree();this.libraries_=n [...]
+for(var i=0,l=to_delete.length;i<l;++i)tree.remove(to_delete[i]);};CodeMap.prototype.isAddressBelongsTo_=function(addr,node){return addr>=node.key&&addr<(node.key+node.value.size);};CodeMap.prototype.findInTree_=function(tree,addr){var node=tree.findGreatestLessThan(addr);return node&&this.isAddressBelongsTo_(addr,node)?node.value:null;};CodeMap.prototype.findEntry=function(addr){var pageAddr=addr>>>CodeMap.PAGE_ALIGNMENT;if(pageAddr in this.pages_){return this.findInTree_(this.statics_, [...]
+var min=this.dynamics_.findMin();var max=this.dynamics_.findMax();if(max!=null&&addr<(max.key+max.value.size)&&addr>=min.key){var dynaEntry=this.findInTree_(this.dynamics_,addr);if(dynaEntry==null)return null;if(!dynaEntry.nameUpdated_){dynaEntry.name=this.dynamicsNameGen_.getName(dynaEntry.name);dynaEntry.nameUpdated_=true;}
+return dynaEntry;}
+return null;};CodeMap.prototype.findDynamicEntryByStartAddress=function(addr){var node=this.dynamics_.find(addr);return node?node.value:null;};CodeMap.prototype.getAllDynamicEntries=function(){return this.dynamics_.exportValues();};CodeMap.prototype.getAllDynamicEntriesWithAddresses=function(){return this.dynamics_.exportKeysAndValues();};CodeMap.prototype.getAllStaticEntries=function(){return this.statics_.exportValues();};CodeMap.prototype.getAllLibrariesEntries=function(){return this. [...]
+var count=++this.knownNames_[name];return name+' {'+count+'}';};return{CodeMap:CodeMap};});'use strict';tr.exportTo('tr.e.importer.v8',function(){function CsvParser(){};CsvParser.CSV_FIELD_RE_=/^"((?:[^"]|"")*)"|([^,]*)/;CsvParser.DOUBLE_QUOTE_RE_=/""/g;CsvParser.prototype.parseLine=function(line){var fieldRe=CsvParser.CSV_FIELD_RE_;var doubleQuoteRe=CsvParser.DOUBLE_QUOTE_RE_;var pos=0;var endPos=line.length;var fields=[];if(endPos>0){do{var fieldMatch=fieldRe.exec(line.substr(pos));if( [...]
+return fields;};function LogReader(dispatchTable){this.dispatchTable_=dispatchTable;this.lineNum_=0;this.csvParser_=new CsvParser();};LogReader.prototype.printError=function(str){};LogReader.prototype.processLogChunk=function(chunk){this.processLog_(chunk.split('\n'));};LogReader.prototype.processLogLine=function(line){this.processLog_([line]);};LogReader.prototype.processStack=function(pc,func,stack){var fullStack=func?[pc,func]:[pc];var prevFrame=pc;for(var i=0,n=stack.length;i<n;++i){ [...]
+return fullStack;};LogReader.prototype.skipDispatch=function(dispatch){return false;};LogReader.prototype.dispatchLogRow_=function(fields){var command=fields[0];if(!(command in this.dispatchTable_))return;var dispatch=this.dispatchTable_[command];if(dispatch===null||this.skipDispatch(dispatch)){return;}
+var parsedFields=[];for(var i=0;i<dispatch.parsers.length;++i){var parser=dispatch.parsers[i];if(parser===null){parsedFields.push(fields[1+i]);}else if(typeof parser=='function'){parsedFields.push(parser(fields[1+i]));}else{parsedFields.push(fields.slice(1+i));break;}}
+dispatch.processor.apply(this,parsedFields);};LogReader.prototype.processLog_=function(lines){for(var i=0,n=lines.length;i<n;++i,++this.lineNum_){var line=lines[i];if(!line){continue;}
+try{var fields=this.csvParser_.parseLine(line);this.dispatchLogRow_(fields);}catch(e){this.printError('line '+(this.lineNum_+1)+': '+
+(e.message||e));}}};return{LogReader:LogReader};});'use strict';tr.exportTo('tr.e.importer.v8',function(){var ColorScheme=tr.b.ColorScheme;function V8LogImporter(model,eventData){this.importPriority=3;this.model_=model;this.logData_=eventData;this.code_map_=new tr.e.importer.v8.CodeMap();this.v8_timer_thread_=undefined;this.v8_thread_=undefined;this.root_stack_frame_=new tr.model.StackFrame(undefined,'v8-root-stack-frame','v8-root-stack-frame',0);this.v8_stack_timeline_=new Array();}
+var kV8BinarySuffixes=['/d8','/libv8.so'];var TimerEventDefaultArgs={'V8.Execute':{pause:false,no_execution:false},'V8.External':{pause:false,no_execution:true},'V8.CompileFullCode':{pause:true,no_execution:true},'V8.RecompileSynchronous':{pause:true,no_execution:true},'V8.RecompileParallel':{pause:false,no_execution:false},'V8.CompileEval':{pause:true,no_execution:true},'V8.Parse':{pause:true,no_execution:true},'V8.PreParse':{pause:true,no_execution:true},'V8.ParseLazy':{pause:true,no_e [...]
+return false;return eventData.substring(0,11)=='v8-version,'||eventData.substring(0,12)=='timer-event,'||eventData.substring(0,5)=='tick,'||eventData.substring(0,15)=='shared-library,'||eventData.substring(0,9)=='profiler,'||eventData.substring(0,14)=='code-creation,';};V8LogImporter.prototype={__proto__:tr.importer.Importer.prototype,get importerName(){return'V8LogImporter';},processTimerEvent_:function(name,start,length){var args=TimerEventDefaultArgs[name];if(args===undefined)return;s [...]
+this.code_map_.addLibrary(start,code_entry);},findCodeKind_:function(kind){for(name in CodeKinds){if(CodeKinds[name].kinds.indexOf(kind)>=0){return CodeKinds[name];}}},processTickEvent_:function(pc,start,unused_x,unused_y,vmstate,stack){start/=1000;function findChildWithEntryID(stackFrame,entryID){for(var i=0;i<stackFrame.children.length;i++){if(stackFrame.children[i].entryID==entryID)
+return stackFrame.children[i];}
+return undefined;}
+var lastStackFrame;if(stack&&stack.length){lastStackFrame=this.root_stack_frame_;stack=stack.reverse();for(var i=0;i<stack.length;i++){if(!stack[i])
+break;var entry=this.code_map_.findEntry(stack[i]);var entryID=entry?entry.id:'Unknown';var childFrame=findChildWithEntryID(lastStackFrame,entryID);if(childFrame===undefined){var entryName=entry?entry.name:'Unknown';lastStackFrame=new tr.model.StackFrame(lastStackFrame,'v8sf-'+tr.b.GUID.allocate(),entryName,ColorScheme.getColorIdForGeneralPurposeString(entryName));lastStackFrame.entryID=entryID;this.model_.addStackFrame(lastStackFrame);}else{lastStackFrame=childFrame;}}}else{var pcEntry= [...]
+lastStackFrame=this.model_.stackFrames[pcEntryID];}
+var sample=new tr.model.Sample(undefined,this.v8_thread_,'V8 PC',start,lastStackFrame,1);this.model_.samples.push(sample);},processDistortion_:function(distortion_in_picoseconds){distortion_per_entry=distortion_in_picoseconds/1000000;},processPlotRange_:function(start,end){xrange_start_override=start;xrange_end_override=end;},processV8Version_:function(major,minor,build,patch,candidate){},importEvents:function(){var logreader=new tr.e.importer.v8.LogReader({'timer-event':{parsers:[null,p [...]
+this.root_stack_frame_.removeAllChildren();function addSlices(slices,thread){for(var i=0;i<slices.length;i++){var duration=slices[i].end-slices[i].start;var slice=new tr.model.Slice('v8',slices[i].name,ColorScheme.getColorIdForGeneralPurposeString(slices[i].name),slices[i].start,{},duration);thread.sliceGroup.pushSlice(slice);addSlices(slices[i].children,thread);}}
+addSlices(this.v8_stack_timeline_,this.v8_thread_);}};tr.importer.Importer.register(V8LogImporter);return{V8LogImporter:V8LogImporter};});'use strict';tr.exportTo('tr.e.importer',function(){function ZipImporter(model,eventData){if(eventData instanceof ArrayBuffer)
+eventData=new Uint8Array(eventData);this.model_=model;this.eventData_=eventData;}
+ZipImporter.canImport=function(eventData){var header;if(eventData instanceof ArrayBuffer)
+header=new Uint8Array(eventData.slice(0,2));else if(typeof(eventData)==='string'||eventData instanceof String)
+header=[eventData.charCodeAt(0),eventData.charCodeAt(1)];else
+return false;return header[0]==='P'.charCodeAt(0)&&header[1]==='K'.charCodeAt(0);};ZipImporter.prototype={__proto__:tr.importer.Importer.prototype,get importerName(){return'ZipImporter';},isTraceDataContainer:function(){return true;},extractSubtraces:function(){var zip=new JSZip(this.eventData_);var subtraces=[];for(var idx in zip.files)
+subtraces.push(zip.files[idx].asBinary());return subtraces;}};tr.importer.Importer.register(ZipImporter);return{ZipImporter:ZipImporter};});'use strict';tr.exportTo('tr.model.source_info',function(){function SourceInfo(file,opt_line,opt_column){this.file_=file;this.line_=opt_line||-1;this.column_=opt_column||-1;}
+SourceInfo.prototype={get file(){return this.file_;},get line(){return this.line_;},get column(){return this.column_;},get domain(){if(!this.file_)
+return undefined;var domain=this.file_.match(/(.*:\/\/[^:\/]*)/i);return domain?domain[1]:undefined;},toString:function(){var str='';if(this.file_)
+str+=this.file_;if(this.line_>0)
+str+=':'+this.line_;if(this.column_>0)
+str+=':'+this.column_;return str;}};return{SourceInfo:SourceInfo};});'use strict';tr.exportTo('tr.model.source_info',function(){function JSSourceInfo(file,line,column,isNative,scriptId,state){tr.model.source_info.SourceInfo.call(this,file,line,column);this.isNative_=isNative;this.scriptId_=scriptId;this.state_=state;}
+JSSourceInfo.prototype={__proto__:tr.model.source_info.SourceInfo.prototype,get state(){return this.state_;},get isNative(){return this.isNative_;},get scriptId(){return this.scriptId_;},toString:function(){var str=this.isNative_?'[native v8] ':'';return str+
+tr.model.source_info.SourceInfo.prototype.toString.call(this);}};return{JSSourceInfo:JSSourceInfo,JSSourceState:{COMPILED:'compiled',OPTIMIZABLE:'optimizable',OPTIMIZED:'optimized',UNKNOWN:'unknown'}};});'use strict';tr.exportTo('tr.e.importer',function(){function TraceCodeEntry(address,size,name,scriptId){this.id_=tr.b.GUID.allocate();this.address_=address;this.size_=size;var rePrefix=/^(\w*:)?([*~]?)(.*)$/m;var tokens=rePrefix.exec(name);var prefix=tokens[1];var state=tokens[2];var bod [...]
+var rawName;var rawUrl;if(prefix==='Script:'){rawName='';rawUrl=body;}else{var spacePos=body.lastIndexOf(' ');rawName=spacePos!==-1?body.substr(0,spacePos):body;rawUrl=spacePos!==-1?body.substr(spacePos+1):'';}
+function splitLineAndColumn(url){var lineColumnRegEx=/(?::(\d+))?(?::(\d+))?$/;var lineColumnMatch=lineColumnRegEx.exec(url);var lineNumber;var columnNumber;if(typeof(lineColumnMatch[1])==='string'){lineNumber=parseInt(lineColumnMatch[1],10);lineNumber=isNaN(lineNumber)?undefined:lineNumber-1;}
+if(typeof(lineColumnMatch[2])==='string'){columnNumber=parseInt(lineColumnMatch[2],10);columnNumber=isNaN(columnNumber)?undefined:columnNumber-1;}
+return{url:url.substring(0,url.length-lineColumnMatch[0].length),lineNumber:lineNumber,columnNumber:columnNumber};}
+var nativeSuffix=' native';var isNative=rawName.endsWith(nativeSuffix);this.name_=isNative?rawName.slice(0,-nativeSuffix.length):rawName;var urlData=splitLineAndColumn(rawUrl);var url=urlData.url||'';var line=urlData.lineNumber||0;var column=urlData.columnNumber||0;this.sourceInfo_=new tr.model.source_info.JSSourceInfo(url,line,column,isNative,scriptId,state);};TraceCodeEntry.prototype={get id(){return this.id_;},get sourceInfo(){return this.sourceInfo_;},get name(){return this.name_;},s [...]
+TraceCodeMap.prototype={addEntry:function(addressHex,size,name,scriptId){var entry=new tr.e.importer.TraceCodeEntry(this.getAddress_(addressHex),size,name,scriptId);this.addEntry_(addressHex,entry);},moveEntry:function(oldAddressHex,newAddressHex,size){var entry=this.getBank_(oldAddressHex).removeEntry(this.getAddress_(oldAddressHex));if(!entry)
+return;entry.address=this.getAddress_(newAddressHex);entry.size=size;this.addEntry_(newAddressHex,entry);},lookupEntry:function(addressHex){return this.getBank_(addressHex).lookupEntry(this.getAddress_(addressHex));},addEntry_:function(addressHex,entry){this.getBank_(addressHex).addEntry(entry);},getAddress_:function(addressHex){var bankSizeHexDigits=13;addressHex=addressHex.slice(2);return parseInt(addressHex.slice(-bankSizeHexDigits),16);},getBank_:function(addressHex){addressHex=addre [...]
+return bank;}};function TraceCodeBank(){this.entries_=[];}
+TraceCodeBank.prototype={removeEntry:function(address){if(this.entries_.length===0)
+return undefined;var index=tr.b.findLowIndexInSortedArray(this.entries_,function(entry){return entry.address;},address);var entry=this.entries_[index];if(!entry||entry.address!==address)
+return undefined;this.entries_.splice(index,1);return entry;},lookupEntry:function(address){var index=tr.b.findHighIndexInSortedArray(this.entries_,function(e){return address-e.address;})-1;var entry=this.entries_[index];return entry&&address<entry.address+entry.size?entry:undefined;},addEntry:function(newEntry){if(this.entries_.length===0)
+this.entries_.push(newEntry);var endAddress=newEntry.address+newEntry.size;var lastIndex=tr.b.findLowIndexInSortedArray(this.entries_,function(entry){return entry.address;},endAddress);var index;for(index=lastIndex-1;index>=0;--index){var entry=this.entries_[index];var entryEndAddress=entry.address+entry.size;if(entryEndAddress<=newEntry.address)
+break;}
+++index;this.entries_.splice(index,lastIndex-index,newEntry);}};return{TraceCodeMap:TraceCodeMap};});'use strict';tr.exportTo('tr.model',function(){function ClockSyncRecord(syncId,start,args){this.syncId_=syncId;this.start_=start;this.args_=args;};ClockSyncRecord.prototype={get syncId(){return this.syncId_;},get start(){return this.start_;},set start(value){this.start_=value;},get args(){return this.args_;}};function InstantClockSyncRecord(syncId,start,args){ClockSyncRecord.call(this,syn [...]
+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.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);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 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.model.Location(args.start.xWorld,args.start.yComponents);var endLoc=new tr.model.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.model.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.annotat [...]
+function HeapDump(processMemoryDump,allocatorName){this.processMemoryDump=processMemoryDump;this.allocatorName=allocatorName;this.entries=[];}
+HeapDump.prototype={addEntry:function(leafStackFrame,objectTypeName,size){var entry=new HeapEntry(this,leafStackFrame,objectTypeName,size);this.entries.push(entry);return entry;}};return{HeapEntry:HeapEntry,HeapDump:HeapDump};});'use strict';tr.exportTo('tr.model',function(){function ScopedId(scope,id){if(scope===undefined){throw new Error('Scope should be defined. Use \''+
+tr.model.OBJECT_DEFAULT_SCOPE+'\' as the default scope.');}
+this.scope=scope;this.id=id;}
+ScopedId.prototype={toString:function(){return'{scope: '+this.scope+', id: '+this.id+'}';}};return{ScopedId:ScopedId};});'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.e.importer',function(){var Base64=tr.b.Base64;var deepCopy=tr.b.deepCopy;var ColorScheme=tr.b.Color [...]
+return ColorScheme.getColorIdForReservedName(event.cname);else if(opt_customName||event.name){return ColorScheme.getColorIdForGeneralPurposeString(opt_customName||event.name);}}
+var timestampFromUs=tr.v.Unit.timestampFromUs;var maybeTimestampFromUs=tr.v.Unit.maybeTimestampFromUs;var PRODUCER='producer';var CONSUMER='consumer';var STEP='step';var LIGHT=tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT;var DETAILED=tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED;var MEMORY_DUMP_LEVEL_OF_DETAIL_ORDER=[undefined,LIGHT,DETAILED];var GLOBAL_MEMORY_ALLOCATOR_DUMP_PREFIX='global/';var BYTE_STAT_NAME_MAP={'pc':'privateCleanResident','pd':'privateDirtyResident','sc':'s [...]
+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.battorData_=container.powerTraceAsString;this.sampleEvents_=container.samples;this.stackFrameEvents_=container.stackFrames;if(container.displayTimeUnit){var unitName=container.displayTimeUnit;var unit=tr.v.TimeDisplayModes[unitName];if(unit===undefined){throw new Error('Unit '+unitName+' [...]
+this.model_.intrinsicTimeUnit=unit;}
+var knownFieldNames={powerTraceAsString:true,samples:true,stackFrames:true,systemTraceEvents:true,traceAnnotations:true,traceEvents:true};for(var fieldName in container){if(fieldName in knownFieldNames)
+continue;this.model_.metadata.push({name:fieldName,value:container[fieldName]});if(fieldName==='metadata'){var metadata=container[fieldName];if(metadata['highres-ticks'])
+this.model_.isTimeHighResolution=metadata['highres-ticks'];if(metadata['clock-domain'])
+this.clockDomainId_=metadata['clock-domain'];}}}}
+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__:tr.importer.Importer.prototype,get importerName(){return'TraceEventImporter';},extractSubtraces:function(){var systemEventsTmp=this.systemTraceEvents_;var battorDataTmp=this.battorData_;this.systemTraceEvents_=undefined;this.battorData_=undefined;var subTraces=systemEventsTmp?[systemEventsTmp]:[];if(battorDataTmp)
+subTraces.push(battorDataTmp);return subTraces;},deepCopyIfNeeded_:function(obj){if(obj===undefined)
+obj={};if(this.eventsWereFromString_)
+return obj;return deepCopy(obj);},deepCopyAlways_:function(obj){if(obj===undefined)
+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,opt_slice){var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);this.allFlowEvents_.push({refGuid:tr.b.GUID.getLastGuid(),sequenceNumber:this.allFlowEvents_.length,event:event,slice:opt [...]
+ctr_name=event.name+'['+event.id+']';else
+ctr_name=event.name;var ctr=this.model_.getOrCreateProcess(event.pid).getOrCreateCounter(event.cat,ctr_name);var reservedColorId=event.cname?getEventColor(event):undefined;if(ctr.numSeries===0){for(var seriesName in event.args){var colorId=reservedColorId||getEventColor(event,ctr.name+'.'+seriesName);ctr.addSeries(new tr.model.CounterSeries(seriesName,colorId));}
+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,getEventColor(event));slice.startStackFrame=this.getStackFrameForEvent_(event);}else if(event.ph==='I'||event.ph==='i'||event.ph==='R'){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),event.argsStripped,getEventColor(event));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 [...]
+var slice=thread.sliceGroup.endSlice(timestampFromUs(event.ts),timestampFromUs(event.tts),getEventColor(event));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){if(event.cat!==undefined&&event.cat.indexOf('trace_event_overhead')>-1)
+return undefined;var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);if(event.flow_out){if(event.flow_in)
+event.flowPhase=STEP;else
+event.flowPhase=PRODUCER;}else if(event.flow_in){event.flowPhase=CONSUMER;}
+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,getEventColor(event),event.bind_id);slice.startStackFrame=this.getStackFrameForEvent_(event);slice.endStackFrame=this.getStackFrameForEvent_(event,true);return slice;},processJitCodeEvent:function(event){if(this.v8ProcessCodeMaps_[event.pid]===undefined)
+this.v8ProcessCodeMaps_[event.pid]=new tr.e.importer.TraceCodeMap();var map=this.v8ProcessCodeMaps_[event.pid];var data=event.args.data;if(event.name==='JitCodeMoved')
+map.moveEntry(data.code_start,data.new_code_start,data.code_len);else
+map.addEntry(data.code_start,data.code_len,data.name,data.script_id);},processMetadataEvent:function(event){if(event.name==='JitCodeAdded'||event.name==='JitCodeMoved'){this.v8SamplingData_.push(event);return;}
+if(event.argsStripped)
+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 i [...]
+n=Math.max(n,this.softwareMeasuredCpuCount_);this.softwareMeasuredCpuCount_=n;}else if(event.name==='stackFrames'){var stackFrames=event.args.stackFrames;if(stackFrames===undefined){this.model_.importWarning({type:'metadata_parse_error',message:'No stack frames found in a \''+event.name+'\' metadata event'});}else{this.importStackFrames_(stackFrames,'p'+event.pid+':');}}else if(event.name==='typeNames'){var objectTypeNameMap=event.args.typeNames;if(objectTypeNameMap===undefined){this.mod [...]
+event.name+'\' metadata event'});}else{this.importObjectTypeNameMap_(objectTypeNameMap,event.pid);}}else{this.model_.importWarning({type:'metadata_parse_error',message:'Unrecognized metadata name: '+event.name});}},processInstantEvent:function(event){if(event.name==='JitCodeAdded'||event.name==='JitCodeMoved'){this.v8SamplingData_.push(event);return;}
+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 instantEvent=new constructor(event.cat,event.name,getEventColor(event),timestampFromUs(event.ts),this.deepCopyIfNeeded_(event.args));switch(instantEvent.type){case tr.model.InstantEventType.GLOBAL:this.model_.instantEvents.push(instantEvent);break;case tr.model.InstantEventType.PROCESS:var process=this.model_.getOrCreateProcess(event.pid);process.instantEvents.push(instantEvent);break;default:throw new Error('Unknown instant event type: '+event.s);}},processV8Sample:function(event){v [...]
+return;var rootStackFrame=this.v8ProcessRootStackFrame_[event.pid];if(!rootStackFrame){rootStackFrame=new tr.model.StackFrame(undefined,'v8-root-stack-frame','v8-root-stack-frame',0);this.v8ProcessRootStackFrame_[event.pid]=rootStackFrame;}
+function findChildWithEntryID(stackFrame,entryID){return tr.b.findFirstInArray(stackFrame.children,function(child){return child.entryID===entryID;});}
+var model=this.model_;function addStackFrame(lastStackFrame,entry){var childFrame=findChildWithEntryID(lastStackFrame,entry.id);if(childFrame)
+return childFrame;var frame=new tr.model.StackFrame(lastStackFrame,tr.b.GUID.allocate(),entry.name,ColorScheme.getColorIdForGeneralPurposeString(entry.name),entry.sourceInfo);frame.entryID=entry.id;model.addStackFrame(frame);return frame;}
+var lastStackFrame=rootStackFrame;if(data.stack.length>0&&this.v8ProcessCodeMaps_[event.pid]){var map=this.v8ProcessCodeMaps_[event.pid];data.stack.reverse();for(var i=0;i<data.stack.length;i++){var entry=map.lookupEntry(data.stack[i]);if(entry===undefined){entry={id:'unknown',name:'unknown',sourceInfo:undefined};}
+lastStackFrame=addStackFrame(lastStackFrame,entry);}}else{var entry={id:data.vm_state,name:data.vm_state,sourceInfo:undefined};lastStackFrame=addStackFrame(lastStackFrame,entry);}
+var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);var sample=new tr.model.Sample(undefined,thread,'V8 Sample',timestampFromUs(event.ts),lastStackFrame,1,this.deepCopyIfNeeded_(event.args));this.model_.samples.push(sample);},processTraceSampleEvent:function(event){if(event.name==='V8Sample'){this.v8SamplingData_.push(event);return;}
+var stackFrame=this.getStackFrameForEvent_(event);if(stackFrame===undefined){stackFrame=this.traceEventSampleStackFramesByName_[event.name];}
+if(stackFrame===undefined){var id='te-'+tr.b.GUID.allocate();stackFrame=new tr.model.StackFrame(undefined,id,event.name,ColorScheme.getColorIdForGeneralPurposeString(event.name));this.model_.addStackFrame(stackFrame);this.traceEventSampleStackFramesByName_[event.name]=stackFrame;}
+var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);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);},processMemoryDumpEvent:function(event){if(event.ph!=='v')
+throw new Error('Invalid memory dump event phase "'+event.ph+'".');var dumpId=event.id;if(dumpId===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Memory dump event (phase \''+event.ph+'\') without a dump ID.'});return;}
+var pid=event.pid;if(pid===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Memory dump event (phase\''+event.ph+'\', dump ID \''+
+dumpId+'\') without a PID.'});return;}
+var allEvents=this.allMemoryDumpEvents_;var dumpIdEvents=allEvents[dumpId];if(dumpIdEvents===undefined)
+allEvents[dumpId]=dumpIdEvents={};var processEvents=dumpIdEvents[pid];if(processEvents===undefined)
+dumpIdEvents[pid]=processEvents=[];processEvents.push(event);},processClockSyncEvent:function(event){if(event.ph!=='c')
+throw new Error('Invalid clock sync event phase "'+event.ph+'".');var syncId=event.args.sync_id;var issueStartTs=event.args.issue_ts;var issueEndTs=event.ts;if(syncId===undefined){this.model_.importWarning({type:'clock_sync_parse_error',message:'Clock sync at time '+issueEndTs+' without an ID.'});return;}
+if(issueStartTs===undefined){this.model_.importWarning({type:'clock_sync_parse_error',message:'Clock sync at time '+issueEndTs+' with ID '+syncId+' without a start timestamp.'});return;}
+this.model_.clockSyncManager.addClockSyncMarker(this.clockDomainId_,syncId,timestampFromUs(issueStartTs),timestampFromUs(issueEndTs-issueStartTs));this.model_.clockSyncRecords.push(new tr.model.PingPongClockSyncRecord(syncId,timestampFromUs(issueStartTs),timestampFromUs(issueEndTs-issueStartTs)));},processV8Events:function(){this.v8SamplingData_.sort(function(a,b){if(a.ts!==b.ts)
+return a.ts-b.ts;if(a.ph==='M'||a.ph==='I')
+return-1;else if(b.ph==='M'||b.ph==='I')
+return 1;return 0;});var length=this.v8SamplingData_.length;for(var i=0;i<length;++i){var event=this.v8SamplingData_[i];if(event.ph==='M'||event.ph==='I'){this.processJitCodeEvent(event);}else if(event.ph==='P'){this.processV8Sample(event);}}},importClockSyncMarkers:function(){this.model_.clockSyncRecords.push(new tr.model.InstantClockSyncRecord('ftrace_importer',0,{}));for(var i=0;i<this.events_.length;i++){var event=this.events_[i];if(event.ph!=='c')
+continue;var eventSizeInBytes=this.model_.importOptions.trackDetailedModelStats?JSON.stringify(event).length:undefined;this.model_.stats.willProcessBasicTraceEvent('clock_sync',event.cat,event.name,event.ts,eventSizeInBytes);this.processClockSyncEvent(event);}},importEvents:function(){if(this.stackFrameEvents_)
+this.importStackFrames_(this.stackFrameEvents_,'g');if(this.traceAnnotations_)
+this.importAnnotations_();var importOptions=this.model_.importOptions;var trackDetailedModelStats=importOptions.trackDetailedModelStats;var modelStats=this.model_.stats;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;}
+var eventSizeInBytes;if(trackDetailedModelStats)
+eventSizeInBytes=JSON.stringify(event).length;else
+eventSizeInBytes=undefined;if(event.ph==='B'||event.ph==='E'){modelStats.willProcessBasicTraceEvent('begin_end (non-compact)',event.cat,event.name,event.ts,eventSizeInBytes);this.processDurationEvent(event);}else if(event.ph==='X'){modelStats.willProcessBasicTraceEvent('begin_end (compact)',event.cat,event.name,event.ts,eventSizeInBytes);var slice=this.processCompleteEvent(event);if(slice!==undefined&&event.bind_id!==undefined)
+this.processFlowEvent(event,slice);}else if(event.ph==='b'||event.ph==='e'||event.ph==='n'||event.ph==='S'||event.ph==='F'||event.ph==='T'||event.ph==='p'){modelStats.willProcessBasicTraceEvent('async',event.cat,event.name,event.ts,eventSizeInBytes);this.processAsyncEvent(event);}else if(event.ph==='I'||event.ph==='i'||event.ph==='R'){modelStats.willProcessBasicTraceEvent('instant',event.cat,event.name,event.ts,eventSizeInBytes);this.processInstantEvent(event);}else if(event.ph==='P'){mo [...]
+event.ph+' ('+event.name+')'});}}
+this.processV8Events();tr.b.iterItems(this.v8ProcessRootStackFrame_,function(name,frame){frame.removeAllChildren();});},importStackFrames_:function(rawStackFrames,idPrefix){var model=this.model_;for(var id in rawStackFrames){var rawStackFrame=rawStackFrames[id];var fullId=idPrefix+id;var textForColor=rawStackFrame.category?rawStackFrame.category:rawStackFrame.name;var stackFrame=new tr.model.StackFrame(undefined,fullId,rawStackFrame.name,ColorScheme.getColorIdForGeneralPurposeString(text [...]
+for(var id in rawStackFrames){var fullId=idPrefix+id;var stackFrame=model.stackFrames[fullId];if(stackFrame===undefined)
+throw new Error('Internal error');var rawStackFrame=rawStackFrames[id];var parentId=rawStackFrame.parent;var parentStackFrame;if(parentId===undefined){parentStackFrame=undefined;}else{var parentFullId=idPrefix+parentId;parentStackFrame=model.stackFrames[parentFullId];if(parentStackFrame===undefined){this.model_.importWarning({type:'metadata_parse_error',message:'Missing parent frame with ID '+parentFullId+' for stack frame \''+stackFrame.name+'\' (ID '+fullId+').'});}}
+stackFrame.parentFrame=parentStackFrame;}},importObjectTypeNameMap_:function(rawObjectTypeNameMap,pid){if(pid in this.objectTypeNameMap_){this.model_.importWarning({type:'metadata_parse_error',message:'Mapping from object type IDs to names provided for pid='+
+pid+' multiple times.'});return;}
+var objectTypeNamePrefix=undefined;var objectTypeNameSuffix=undefined;var objectTypeNameMap={};for(var objectTypeId in rawObjectTypeNameMap){var rawObjectTypeName=rawObjectTypeNameMap[objectTypeId];if(objectTypeNamePrefix===undefined){for(var i=0;i<OBJECT_TYPE_NAME_PATTERNS.length;i++){var pattern=OBJECT_TYPE_NAME_PATTERNS[i];if(rawObjectTypeName.startsWith(pattern.prefix)&&rawObjectTypeName.endsWith(pattern.suffix)){objectTypeNamePrefix=pattern.prefix;objectTypeNameSuffix=pattern.suffix [...]
+if(objectTypeNamePrefix!==undefined&&rawObjectTypeName.startsWith(objectTypeNamePrefix)&&rawObjectTypeName.endsWith(objectTypeNameSuffix)){objectTypeNameMap[objectTypeId]=rawObjectTypeName.substring(objectTypeNamePrefix.length,rawObjectTypeName.length-objectTypeNameSuffix.length);}else{objectTypeNameMap[objectTypeId]=rawObjectTypeName;}}
+this.objectTypeNameMap_[pid]=objectTypeNameMap;},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);}},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={};var nestableMeasureAsyncEventsByKey={};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;}
+if(event.cat==='blink.user_timing'){var matched=/([^\/:]+):([^\/:]+)\/?(.*)/.exec(event.name);if(matched!==null){var key=matched[1]+':'+event.cat;event.args=JSON.parse(Base64.atob(matched[3])||'{}');if(nestableMeasureAsyncEventsByKey[key]===undefined)
+nestableMeasureAsyncEventsByKey[key]=[];nestableMeasureAsyncEventsByKey[key].push(asyncEventState);continue;}}
+var key=event.cat+':'+event.id;if(nestableAsyncEventsByKey[key]===undefined)
+nestableAsyncEventsByKey[key]=[];nestableAsyncEventsByKey[key].push(asyncEventState);}
+this.createLegacyAsyncSlices_(legacyEvents);this.createNestableAsyncSlices_(nestableMeasureAsyncEventsByKey);this.createNestableAsyncSlices_(nestableAsyncEventsByKey);},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,getEventColor(events[0].event),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].event.argsStripped [...]
+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,getEventColor(event,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.startThread=events[startIndex [...]
+if(isValid){slice.startThread.asyncSliceGroup.push(slice);}
+delete asyncEventStatesByNameThenID[name][id];}}}},createNestableAsyncSlices_:function(nestableEventsByKey){for(var key in nestableEventsByKey){var eventStateEntries=nestableEventsByKey[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{function concatenateArguments(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,getEventColor(endState.event),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.startStackFrame=this.getStackFrameForEvent_(startState.event);slice.endStackFrame=this.getStackFrameForEvent_(endState.event); [...]
+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]);}}},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.ph==='s'||event.ph==='f'||event.ph==='t'){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;}
+if(event.bind_id){if(event.flow_in===undefined&&event.flow_out===undefined){that.model_.importWarning({type:'flow_slice_parse_error',message:'Flow producer or consumer require flow_in or flow_out.'});return false;}
+return true;}
+return false;}
+function createFlowEvent(thread,event,opt_slice){var startSlice,flowId,flowStartTs;if(event.bind_id){startSlice=opt_slice;flowId=event.bind_id;flowStartTs=timestampFromUs(event.ts+event.dur);}else{var ts=timestampFromUs(event.ts);startSlice=thread.sliceGroup.findSliceAtTs(ts);if(startSlice===undefined)
+return undefined;flowId=event.id;flowStartTs=ts;}
+var flowEvent=new tr.model.FlowEvent(event.cat,flowId,event.name,getEventColor(event),flowStartTs,that.deepCopyAlways_(event.args));flowEvent.startSlice=startSlice;flowEvent.startStackFrame=that.getStackFrameForEvent_(event);flowEvent.endStackFrame=undefined;startSlice.outFlowEvents.push(flowEvent);return flowEvent;}
+function finishFlowEventWith(flowEvent,thread,event,refGuid,bindToParent,opt_slice){var endSlice;if(event.bind_id){endSlice=opt_slice;}else{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=timestampFromUs(event.ts)-flowEvent.start;flowEvent.endStackFrame=that.getStackFrameForEvent_(event);that.mergeArgsInto_(flowEvent.args,event.args,flowEvent.title);return true;}
+function processFlowConsumer(flowIdToEvent,sliceGuidToEvent,event,slice){var flowEvent=flowIdToEvent[event.bind_id];if(flowEvent===undefined){that.model_.importWarning({type:'flow_slice_ordering_error',message:'Flow consumer '+event.bind_id+' does not have '+'a flow producer'});return false;}else if(flowEvent.endSlice){var flowProducer=flowEvent.startSlice;flowEvent=createFlowEvent(undefined,sliceGuidToEvent[flowProducer.guid],flowProducer);}
+var ok=finishFlowEventWith(flowEvent,undefined,event,refGuid,undefined,slice);if(ok){that.model_.flowEvents.push(flowEvent);}else{that.model_.importWarning({type:'flow_slice_end_error',message:'Flow consumer '+event.bind_id+' does not end '+'at an actual slice, so cannot be created.'});return false;}
+return true;}
+function processFlowProducer(flowIdToEvent,flowStatus,event,slice){if(flowIdToEvent[event.bind_id]&&flowStatus[event.bind_id]){that.model_.importWarning({type:'flow_slice_start_error',message:'Flow producer '+event.bind_id+' already seen'});return false;}
+var flowEvent=createFlowEvent(undefined,event,slice);if(!flowEvent){that.model_.importWarning({type:'flow_slice_start_error',message:'Flow producer '+event.bind_id+' does not start'+'a flow'});return false;}
+flowIdToEvent[event.bind_id]=flowEvent;return;}
+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={};var sliceGuidToEvent={};var flowStatus={};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;if(event.bind_id){var slice=data.slice;sliceGuidToEvent[slice.guid]=event;if(event.flowPhase===PRODUCER){if(!processFlowProducer(flowIdToEvent,flowStatus,event,slice))
+continue;flowStatus[event.bind_id]=true;}
+else{if(!processFlowConsumer(flowIdToEvent,sliceGuidToEvent,event,slice))
+continue;flowStatus[event.bind_id]=false;if(event.flowPhase===STEP){if(!processFlowProducer(flowIdToEvent,flowStatus,event,slice))
+continue;flowStatus[event.bind_id]=true;}}
+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);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_end_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 scopedId=new tr.model.ScopedId(event.scope||tr.model.OBJECT_DEFAULT_SCOPE,event.id);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(scopedId.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(scopedId,event.cat,event.name,ts);}catch(e){this.model_.importWarning({type:'object_parse_error',message:'While processing create of '+
+scopedId+' 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 '+scopedId+' 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(scopedId,cat,event.name,ts,args,baseTypename);snapshot.snapshottedOnThread=thread;}catch(e){this.model_.importWarning({type:'object_parse_error',message:'While processing snapshot of '+
+scopedId+' at ts='+ts+': '+e});return;}
+instance=snapshot.objectInstance;}else if(event.ph==='D'){try{process.objects.idWasDeleted(scopedId,event.cat,event.name,ts);var instanceMap=process.objects.getOrCreateInstanceMap_(scopedId);instance=instanceMap.lastInstance;}catch(e){this.model_.importWarning({type:'object_parse_error',message:'While processing delete of '+
+scopedId+' at ts='+ts+': '+e});return;}}
+if(instance)
+instance.colorId=getEventColor(event,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;var scope=containingSnapshot.objectInstance.scopedId.scope;try{res=process.objects.addSnapshot(new tr.model.ScopedId(scope,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;}
-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())
+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(){for(var dumpId in this.allMemoryDumpEvents_)
+this.createGlobalMemoryDump_(this.allMemoryDumpEvents_[dumpId],dumpId);},createGlobalMemoryDump_:function(dumpIdEvents,dumpId){var globalRange=new tr.b.Range();for(var pid in dumpIdEvents){var processEvents=dumpIdEvents[pid];for(var i=0;i<processEvents.length;i++)
+globalRange.addValue(timestampFromUs(processEvents[i].ts));}
+if(globalRange.isEmpty)
+throw new Error('Internal error: Global memory dump without events');var globalMemoryDump=new tr.model.GlobalMemoryDump(this.model_,globalRange.min);globalMemoryDump.duration=globalRange.range;this.model_.globalMemoryDumps.push(globalMemoryDump);var globalMemoryAllocatorDumpsByFullName={};var levelsOfDetail={};var allMemoryAllocatorDumpsByGuid={};for(var pid in dumpIdEvents){this.createProcessMemoryDump_(globalMemoryDump,globalMemoryAllocatorDumpsByFullName,levelsOfDetail,allMemoryAlloca [...]
+globalMemoryDump.levelOfDetail=levelsOfDetail.global;globalMemoryDump.memoryAllocatorDumps=this.inferMemoryAllocatorDumpTree_(globalMemoryAllocatorDumpsByFullName);this.parseMemoryDumpAllocatorEdges_(allMemoryAllocatorDumpsByGuid,dumpIdEvents,dumpId);},createProcessMemoryDump_:function(globalMemoryDump,globalMemoryAllocatorDumpsByFullName,levelsOfDetail,allMemoryAllocatorDumpsByGuid,processEvents,pid,dumpId){var processRange=new tr.b.Range();for(var i=0;i<processEvents.length;i++)
+processRange.addValue(timestampFromUs(processEvents[i].ts));if(processRange.isEmpty)
+throw new Error('Internal error: Process memory dump without events');var process=this.model_.getOrCreateProcess(pid);var processMemoryDump=new tr.model.ProcessMemoryDump(globalMemoryDump,process,processRange.min);processMemoryDump.duration=processRange.range;process.memoryDumps.push(processMemoryDump);globalMemoryDump.processMemoryDumps[pid]=processMemoryDump;var processMemoryAllocatorDumpsByFullName={};for(var i=0;i<processEvents.length;i++){var processEvent=processEvents[i];var dumps= [...]
+this.parseMemoryDumpTotals_(processMemoryDump,dumps,pid,dumpId);this.parseMemoryDumpVmRegions_(processMemoryDump,dumps,pid,dumpId);this.parseMemoryDumpHeapDumps_(processMemoryDump,dumps,pid,dumpId);this.parseMemoryDumpLevelOfDetail_(levelsOfDetail,dumps,pid,dumpId);this.parseMemoryDumpAllocatorDumps_(processMemoryDump,globalMemoryDump,processMemoryAllocatorDumpsByFullName,globalMemoryAllocatorDumpsByFullName,allMemoryAllocatorDumpsByGuid,dumps,pid,dumpId);}
+if(levelsOfDetail.process===undefined){levelsOfDetail.process=processMemoryDump.vmRegions?DETAILED:LIGHT;}
+if(!this.updateMemoryDumpLevelOfDetail_(levelsOfDetail,'global',levelsOfDetail.process)){this.model_.importWarning({type:'memory_dump_parse_error',message:'diffent levels of detail provided for global memory'+' dump (dump ID='+dumpId+').'});}
+processMemoryDump.levelOfDetail=levelsOfDetail.process;delete levelsOfDetail.process;processMemoryDump.memoryAllocatorDumps=this.inferMemoryAllocatorDumpTree_(processMemoryAllocatorDumpsByFullName);},parseMemoryDumpTotals_:function(processMemoryDump,dumps,pid,dumpId){var rawTotals=dumps.process_totals;if(rawTotals===undefined)
+return;if(processMemoryDump.totals!==undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Process totals provided multiple times for'+' process memory dump for PID='+pid+' and dump ID='+dumpId+'.'});return;}
+var totals={};var platformSpecificTotals=undefined;for(var rawTotalName in rawTotals){var rawTotalValue=rawTotals[rawTotalName];if(rawTotalValue===undefined)
+continue;if(rawTotalName==='resident_set_bytes'){totals.residentBytes=parseInt(rawTotalValue,16);continue;}
+if(rawTotalName==='peak_resident_set_bytes'){totals.peakResidentBytes=parseInt(rawTotalValue,16);continue;}
+if(rawTotalName==='is_peak_rss_resetable'){totals.arePeakResidentBytesResettable=!!rawTotalValue;continue;}
+if(platformSpecificTotals===undefined){platformSpecificTotals={};totals.platformSpecific=platformSpecificTotals;}
+platformSpecificTotals[rawTotalName]=parseInt(rawTotalValue,16);}
+if(totals.peakResidentBytes===undefined&&totals.arePeakResidentBytesResettable!==undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Optional field peak_resident_set_bytes found'+' but is_peak_rss_resetable not found in'+' process memory dump for PID='+pid+' and dump ID='+dumpId+'.'});}
+if(totals.arePeakResidentBytesResettable!==undefined&&totals.peakResidentBytes===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Optional field is_peak_rss_resetable found'+' but peak_resident_set_bytes not found in'+' process memory dump for PID='+pid+' and dump ID='+dumpId+'.'});}
+processMemoryDump.totals=totals;},parseMemoryDumpVmRegions_:function(processMemoryDump,dumps,pid,dumpId){var rawProcessMmaps=dumps.process_mmaps;if(rawProcessMmaps===undefined)
+return;var rawVmRegions=rawProcessMmaps.vm_regions;if(rawVmRegions===undefined)
+return;if(processMemoryDump.vmRegions!==undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'VM regions provided multiple times for'+' process memory dump for PID='+pid+' and dump ID='+dumpId+'.'});return;}
+var vmRegions=new Array(rawVmRegions.length);for(var i=0;i<rawVmRegions.length;i++){var rawVmRegion=rawVmRegions[i];var byteStats={};var rawByteStats=rawVmRegion.bs;for(var rawByteStatName in rawByteStats){var rawByteStatValue=rawByteStats[rawByteStatName];if(rawByteStatValue===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Byte stat \''+rawByteStatName+'\' of VM region '+
+i+' ('+rawVmRegion.mf+') in process memory dump for '+'PID='+pid+' and dump ID='+dumpId+' does not have a value.'});continue;}
+var byteStatName=BYTE_STAT_NAME_MAP[rawByteStatName];if(byteStatName===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Unknown byte stat name \''+rawByteStatName+'\' ('+
+rawByteStatValue+') of VM region '+i+' ('+
+rawVmRegion.mf+') in process memory dump for PID='+pid+' and dump ID='+dumpId+'.'});continue;}
+byteStats[byteStatName]=parseInt(rawByteStatValue,16);}
+vmRegions[i]=new tr.model.VMRegion(parseInt(rawVmRegion.sa,16),parseInt(rawVmRegion.sz,16),rawVmRegion.pf,rawVmRegion.mf,byteStats);}
+processMemoryDump.vmRegions=tr.model.VMRegionClassificationNode.fromRegions(vmRegions);},parseMemoryDumpHeapDumps_:function(processMemoryDump,dumps,pid,dumpId){var rawHeapDumps=dumps.heaps;if(rawHeapDumps===undefined)
+return;if(processMemoryDump.heapDumps!==undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Heap dumps provided multiple times for'+' process memory dump for PID='+pid+' and dump ID='+dumpId+'.'});return;}
+var model=this.model_;var idPrefix='p'+pid+':';var heapDumps={};var objectTypeNameMap=this.objectTypeNameMap_[pid];if(objectTypeNameMap===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Missing mapping from object type IDs to names.'});}
+for(var allocatorName in rawHeapDumps){var entries=rawHeapDumps[allocatorName].entries;if(entries===undefined||entries.length===0){this.model_.importWarning({type:'memory_dump_parse_error',message:'No heap entries in a '+allocatorName+' heap dump for PID='+pid+' and dump ID='+dumpId+'.'});continue;}
+var isOldFormat=entries[0].bt===undefined;if(!isOldFormat&&objectTypeNameMap===undefined){continue;}
+var heapDump=new tr.model.HeapDump(processMemoryDump,allocatorName);for(var i=0;i<entries.length;i++){var entry=entries[i];var leafStackFrameIndex=entry.bt;var leafStackFrame;if(isOldFormat){if(leafStackFrameIndex===undefined){leafStackFrame=undefined;}else{var leafStackFrameId=idPrefix+leafStackFrameIndex;if(leafStackFrameIndex===''){leafStackFrame=undefined;}else{leafStackFrame=model.stackFrames[leafStackFrameId];if(leafStackFrame===undefined){this.model_.importWarning({type:'memory_du [...]
+leafStackFrameId+') of heap entry '+i+' (size '+
+size+') in a '+allocatorName+' heap dump for PID='+pid+'.'});continue;}}
+leafStackFrameId+=':self';if(model.stackFrames[leafStackFrameId]!==undefined){leafStackFrame=model.stackFrames[leafStackFrameId];}else{leafStackFrame=new tr.model.StackFrame(leafStackFrame,leafStackFrameId,'<self>',undefined);model.addStackFrame(leafStackFrame);}}}else{if(leafStackFrameIndex===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Missing stack frame ID of heap entry '+i+' (size '+size+') in a '+allocatorName+' heap dump for PID='+pid+'.'});continue;}
+var leafStackFrameId=idPrefix+leafStackFrameIndex;if(leafStackFrameIndex===''){leafStackFrame=undefined;}else{leafStackFrame=model.stackFrames[leafStackFrameId];if(leafStackFrame===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Missing leaf stack frame (ID '+leafStackFrameId+') of heap entry '+i+' (size '+size+') in a '+
+allocatorName+' heap dump for PID='+pid+'.'});continue;}}}
+var objectTypeId=entry.type;var objectTypeName;if(objectTypeId===undefined){objectTypeName=undefined;}else if(objectTypeNameMap===undefined){continue;}else{objectTypeName=objectTypeNameMap[objectTypeId];if(objectTypeName===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Missing object type name (ID '+objectTypeId+') of heap entry '+i+' (size '+size+') in a '+
+allocatorName+' heap dump for pid='+pid+'.'});continue;}}
+var size=parseInt(entry.size,16);heapDump.addEntry(leafStackFrame,objectTypeName,size);}
+if(heapDump.entries.length>0)
+heapDumps[allocatorName]=heapDump;}
+if(Object.keys(heapDumps).length>0)
+processMemoryDump.heapDumps=heapDumps;},parseMemoryDumpLevelOfDetail_:function(levelsOfDetail,dumps,pid,dumpId){var rawLevelOfDetail=dumps.level_of_detail;var level;switch(rawLevelOfDetail){case'light':level=LIGHT;break;case'detailed':level=DETAILED;break;case undefined:level=undefined;break;default:this.model_.importWarning({type:'memory_dump_parse_error',message:'unknown raw level of detail \''+rawLevelOfDetail+'\' of process memory dump for PID='+pid+' and dump ID='+dumpId+'.'});return;}
+if(!this.updateMemoryDumpLevelOfDetail_(levelsOfDetail,'process',level)){this.model_.importWarning({type:'memory_dump_parse_error',message:'diffent levels of detail provided for process memory'+' dump for PID='+pid+' (dump ID='+dumpId+').'});}},updateMemoryDumpLevelOfDetail_:function(levelsOfDetail,scope,level){if(!(scope in levelsOfDetail)||level===levelsOfDetail[scope]){levelsOfDetail[scope]=level;return true;}
+if(MEMORY_DUMP_LEVEL_OF_DETAIL_ORDER.indexOf(level)>MEMORY_DUMP_LEVEL_OF_DETAIL_ORDER.indexOf(levelsOfDetail[scope])){levelsOfDetail[scope]=level;}
+return false;},parseMemoryDumpAllocatorDumps_:function(processMemoryDump,globalMemoryDump,processMemoryAllocatorDumpsByFullName,globalMemoryAllocatorDumpsByFullName,allMemoryAllocatorDumpsByGuid,dumps,pid,dumpId){var rawAllocatorDumps=dumps.allocators;if(rawAllocatorDumps===undefined)
+return;for(var fullName in rawAllocatorDumps){var rawAllocatorDump=rawAllocatorDumps[fullName];var guid=rawAllocatorDump.guid;if(guid===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Memory allocator dump '+fullName+' for PID='+pid+' and dump ID='+dumpId+' does not have a GUID.'});}
+var flags=rawAllocatorDump.flags||0;var isWeakDump=!!(flags&WEAK_MEMORY_ALLOCATOR_DUMP_FLAG);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) for'+' PID='+pid+' and dump ID='+dumpId+'.'});continue;}
+allocatorDump=new tr.model.MemoryAllocatorDump(containerMemoryDump,fullName,guid);allocatorDump.weak=isWeakDump;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+') for PID='+pid+' and dump ID='+
+dumpId+' dumped in different contexts.'});continue;}
+if(allocatorDump.fullName!==fullName){this.model_.importWarning({type:'memory_dump_parse_error',message:'Memory allocator dump with GUID='+guid+' for PID='+
+pid+' and dump ID='+dumpId+' has multiple names: '+
+allocatorDump.fullName+', '+fullName+' (ignored).'});continue;}
+if(!isWeakDump){allocatorDump.weak=false;}}
+var attributes=rawAllocatorDump.attrs;if(attributes===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Memory allocator dump '+fullName+' (GUID='+guid+') for PID='+pid+' and dump ID='+dumpId+' does not have attributes.'});attributes={};}
+for(var attrName in attributes){var attrArgs=attributes[attrName];var attrType=attrArgs.type;var attrValue=attrArgs.value;switch(attrType){case'scalar':if(attrName in allocatorDump.numerics){this.model_.importWarning({type:'memory_dump_parse_error',message:'Multiple values provided for scalar attribute '+
+attrName+' of memory allocator dump '+fullName+' (GUID='+guid+') for PID='+pid+' and dump ID='+
+dumpId+'.'});break;}
+var unit=attrArgs.units==='bytes'?tr.v.Unit.byName.sizeInBytes_smallerIsBetter:tr.v.Unit.byName.unitlessNumber_smallerIsBetter;var value=parseInt(attrValue,16);allocatorDump.addNumeric(attrName,new tr.v.ScalarNumeric(unit,value));break;case'string':if(attrName in allocatorDump.diagnostics){this.model_.importWarning({type:'memory_dump_parse_error',message:'Multiple values provided for string attribute '+
+attrName+' of memory allocator dump '+fullName+' (GUID='+guid+') for PID='+pid+' and dump ID='+
+dumpId+'.'});break;}
+allocatorDump.addDiagnostic(attrName,attrValue);break;default:this.model_.importWarning({type:'memory_dump_parse_error',message:'Unknown type provided for attribute '+attrName+' of memory allocator dump '+fullName+' (GUID='+guid+') for PID='+pid+' and dump ID='+dumpId+': '+
+attrType});break;}}}},inferMemoryAllocatorDumpTree_:function(memoryAllocatorDumpsByFullName){var rootAllocatorDumps=[];var fullNames=Object.keys(memoryAllocatorDumpsByFullName);fullNames.sort();for(var i=0;i<fullNames.length;i++){var fullName=fullNames[i];var allocatorDump=memoryAllocatorDumpsByFullName[fullName];while(true){var lastSlashIndex=fullName.lastIndexOf('/');if(lastSlashIndex===-1){rootAllocatorDumps.push(allocatorDump);break;}
+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);if(allocatorDump.weak!==false){parentAllocatorDump.weak=undefined;}
+memoryAllocatorDumpsByFullName[parentFullName]=parentAllocatorDump;}
+allocatorDump.parent=parentAllocatorDump;parentAllocatorDump.children.push(allocatorDump);if(parentAlreadyExisted){if(!allocatorDump.weak){while(parentAllocatorDump!==undefined&&parentAllocatorDump.weak===undefined){parentAllocatorDump.weak=false;parentAllocatorDump=parentAllocatorDump.parent;}}
+break;}
+fullName=parentFullName;allocatorDump=parentAllocatorDump;}}
+for(var fullName in memoryAllocatorDumpsByFullName){var allocatorDump=memoryAllocatorDumpsByFullName[fullName];if(allocatorDump.weak===undefined)
+allocatorDump.weak=true;}
+return rootAllocatorDumps;},parseMemoryDumpAllocatorEdges_:function(allMemoryAllocatorDumpsByGuid,dumpIdEvents,dumpId){for(var pid in dumpIdEvents){var processEvents=dumpIdEvents[pid];for(var i=0;i<processEvents.length;i++){var processEvent=processEvents[i];var dumps=processEvent.args.dumps;if(dumps===undefined)
+continue;var rawEdges=dumps.allocators_graph;if(rawEdges===undefined)
+continue;for(var j=0;j<rawEdges.length;j++){var rawEdge=rawEdges[j];var sourceGuid=rawEdge.source;var sourceDump=allMemoryAllocatorDumpsByGuid[sourceGuid];if(sourceDump===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Edge for PID='+pid+' and dump ID='+dumpId+' is missing source memory allocator dump (GUID='+
+sourceGuid+').'});continue;}
+var targetGuid=rawEdge.target;var targetDump=allMemoryAllocatorDumpsByGuid[targetGuid];if(targetDump===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Edge for PID='+pid+' and dump ID='+dumpId+' is missing target memory allocator dump (GUID='+
+targetGuid+').'});continue;}
+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+').'});}else{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+' (PID='+pid+', dump ID='+dumpId+', source='+sourceGuid+', target='+targetGuid+', importance='+importance+').'});}}}}}};tr.importer.Importer.register(TraceEventImporter);return{TraceEventImporter:TraceEventImporter};});'use strict';tr.exportTo('tr.e.measure',function(){var AsyncSlice=tr.mode [...]
+AsyncSlice.apply(this,arguments);}
+MeasureAsyncSlice.prototype={__proto__:AsyncSlice.prototype,get viewSubGroupTitle(){return this.groupTitle_;},get title(){return this.title_;},set title(title){this.title_=title;}};AsyncSlice.register(MeasureAsyncSlice,{categoryParts:['blink.user_timing']});return{MeasureAsyncSlice:MeasureAsyncSlice};});'use strict';tr.exportTo('tr.e.net',function(){var AsyncSlice=tr.model.AsyncSlice;function NetAsyncSlice(){AsyncSlice.apply(this,arguments);this.url_=undefined;this.byteCount_=undefined;t [...]
+NetAsyncSlice.prototype={__proto__:AsyncSlice.prototype,get viewSubGroupTitle(){return'NetLog';},get title(){if(this.isTitleComputed_||!this.isTopLevel)
+return this.title_;if(this.url!==undefined&&this.url.length>0){this.title_=this.url;}else if(this.args!==undefined&&this.args.source_type!==undefined){this.title_=this.args.source_type;}
+this.isTitleComputed_=true;return this.title_;},set title(title){this.title_=title;},get url(){if(this.isUrlComputed_)
+return this.url_;if(this.args!==undefined&&this.args.params!==undefined&&this.args.params.url!==undefined){this.url_=this.args.params.url;}else if(this.subSlices!==undefined&&this.subSlices.length>0){for(var i=0;i<this.subSlices.length&&!this.url_;i++){if(this.subSlices[i].url!==undefined)
+this.url_=this.subSlices[i].url;}}
+this.isUrlComputed_=true;return this.url_;},get byteCount(){if(this.byteCount_!==undefined)
+return this.byteCount_;this.byteCount_=0;if((this.originalTitle==='URL_REQUEST_JOB_FILTERED_BYTES_READ'||this.originalTitle==='URL_REQUEST_JOB_BYTES_READ')&&this.args!==undefined&&this.args.params!==undefined&&this.args.params.byte_count!==undefined){this.byteCount_=this.args.params.byte_count;}
+for(var i=0;i<this.subSlices.length;i++){this.byteCount_+=this.subSlices[i].byteCount;}
+return this.byteCount_;}};AsyncSlice.register(NetAsyncSlice,{categoryParts:['netlog','disabled-by-default-netlog']});return{NetAsyncSlice:NetAsyncSlice};});'use strict';tr.exportTo('tr.model',function(){var ColorScheme=tr.b.ColorScheme;function Activity(name,category,range,args){tr.model.TimedEvent.call(this,range.min);this.title=name;this.category=category;this.colorId=ColorScheme.getColorIdForGeneralPurposeString(name);this.duration=range.duration;this.args=args;this.name=name;};Activi [...]
+var eventLogActivityRE=new RegExp('(\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.\\d+)'+'\\s+(\\d+)\\s+(\\d+)\\s+([A-Z])\\s*'+'(am_\\w+)\\s*:(.*)');var amCreateRE=new RegExp('\s*\\[.*,.*,.*,(.*),.*,.*,.*,.*\\]');var amFocusedRE=new RegExp('\s*\\[\\d+,(.*)\\]');var amProcStartRE=new RegExp('\s*\\[\\d+,\\d+,\\d+,.*,activity,(.*)\\]');var amOnResumeRE=new RegExp('\s*\\[\\d+,(.*)\\]');var amOnPauseRE=new RegExp('\s*\\[\\d+,(.*)\\]');var amLaunchTimeRE=new RegExp('\s*\\[\\d+,\\d+,(.*),(\\d+),(\\d+)');v [...]
+return false;if(/^<!DOCTYPE html>/.test(events))
+return false;return eventLogActivityRE.test(events);};EventLogImporter.prototype={__proto__:Importer.prototype,get importerName(){return'EventLogImporter';},get model(){return this.model_;},getFullActivityName:function(component){var componentSplit=component.split('/');if(componentSplit[1].startsWith('.'))
+return componentSplit[0]+componentSplit[1];return componentSplit[1];},getProcName:function(component){var componentSplit=component.split('/');return componentSplit[0];},findOrCreateActivity:function(activityName){if(activityName in activityMap)
+return activityMap[activityName];var activity={state:ACTIVITY_STATE.NONE,name:activityName};activityMap[activityName]=activity;return activity;},deleteActivity:function(activityName){delete activityMap[activityName];},handleCreateActivity:function(ts,activityName){var activity=this.findOrCreateActivity(activityName);activity.state=ACTIVITY_STATE.CREATED;activity.createdTs=ts;},handleFocusActivity:function(ts,procName,activityName){var activity=this.findOrCreateActivity(activityName);acti [...]
+this.addActivityToProcess(activity);},handleLaunchTime:function(ts,activityName,launchTime){var activity=this.findOrCreateActivity(activityName);activity.launchTime=launchTime;},handleDestroyActivity:function(ts,activityName){this.deleteActivity(activityName);},addActivityToProcess:function(activity){if(activity.pid===undefined)
+return;var process=this.model_.getOrCreateProcess(activity.pid);var range=tr.b.Range.fromExplicitRange(Math.max(this.model_.bounds.min,activity.lastResumeTs),activity.lastPauseTs);var newActivity=new tr.model.Activity(activity.name,'Android Activity',range,{created:activity.createdTs,procstart:activity.procStartTs,lastfocus:activity.lastFocusedTs});process.activities.push(newActivity);},parseAmLine_:function(line){var match=eventLogActivityRE.exec(line);if(!match)
+return;var first_realtime_ts=this.model_.bounds.min-
+this.model_.realtime_to_monotonic_offset_ms;var year=new Date(first_realtime_ts).getFullYear();var ts=match[1].substring(0,5)+'-'+year+' '+
+match[1].substring(5,match[1].length);var monotonic_ts=Date.parse(ts)+
+this.model_.realtime_to_monotonic_offset_ms;var pid=match[2];var action=match[5];var data=match[6];if(action==='am_create_activity'){match=amCreateRE.exec(data);if(match&&match.length>=2){this.handleCreateActivity(monotonic_ts,this.getFullActivityName(match[1]));}}else if(action==='am_focused_activity'){match=amFocusedRE.exec(data);if(match&&match.length>=2){this.handleFocusActivity(monotonic_ts,this.getProcName(match[1]),this.getFullActivityName(match[1]));}}else if(action==='am_proc_st [...]
+this.handleOnResumeCalled(monotonic_ts,pid,match[1]);}else if(action==='am_on_paused_called'){match=amOnPauseRE.exec(data);if(match&&match.length>=2)
+this.handleOnPauseCalled(monotonic_ts,match[1]);}else if(action==='am_activity_launch_time'){match=amLaunchTimeRE.exec(data);this.handleLaunchTime(monotonic_ts,this.getFullActivityName(match[1]),match[2]);}else if(action==='am_destroy_activity'){match=amDestroyRE.exec(data);if(match&&match.length==2){this.handleDestroyActivity(monotonic_ts,this.getFullActivityName(match[1]));}}},importEvents:function(){if(isNaN(this.model_.realtime_to_monotonic_offset_ms)){this.model_.importWarning({type [...]
+this.model_.updateBounds();var lines=this.events_.split('\n');lines.forEach(this.parseAmLine_,this);for(var activityName in activityMap){var activity=activityMap[activityName];if(activity.state==ACTIVITY_STATE.RESUMED){activity.lastPauseTs=this.model_.bounds.max;this.addActivityToProcess(activity);}}}};Importer.register(EventLogImporter);return{EventLogImporter:EventLogImporter};});'use strict';tr.exportTo('tr.e.importer.battor',function(){function BattorImporter(model,events){this.impor [...]
+var TestExports={};var battorDataLineRE=new RegExp('^(\\d+\\.\\d+)\\s+(\\d+\\.\\d+)\\s+(\\d+\\.\\d+)'+'(?:\\s+<(\\S+)>)?$');var battorHeaderLineRE=/^# BattOr/;var sampleRateLineRE=/^# sample_rate (\d+) Hz/;BattorImporter.canImport=function(events){if(!(typeof(events)==='string'||events instanceof String))
+return false;return battorHeaderLineRE.test(events);};BattorImporter.prototype={__proto__:tr.importer.Importer.prototype,get importerName(){return'BattorImporter';},get model(){return this.model_;},importEvents:function(){if(this.model_.device.powerSeries){this.model_.importWarning({type:'import_error',message:'Power counter exists, can not import BattOr power trace.'});return;}
+var name='power';var series=new tr.model.PowerSeries(this.model_.device);this.importPowerSamples(series);var shiftTs=this.explicitClockSync();if(shiftTs===undefined){this.model_.importWarning({type:'clock_sync',message:'No clock sync marker for the BattOr could be found.'});return;}
+series.shiftTimestampsForward(shiftTs);this.model_.device.powerSeries=series;},importPowerSamples:function(series){var lines=this.events_.split('\n');this.model_.updateBounds();var minTs=0;if(this.model_.bounds.min!==undefined)
+minTs=this.model_.bounds.min;lines.forEach(function(line){line=line.trim();if(line.length===0)
+return;if(/^#/.test(line)){groups=sampleRateLineRE.exec(line);if(!groups)
+return;this.sampleRate_=parseInt(groups[1]);}else{var groups=battorDataLineRE.exec(line);if(!groups){this.model_.importWarning({type:'parse_error',message:'Unrecognized line: '+line});return;}
+var time=parseFloat(groups[1])+minTs;var voltage_mV=parseFloat(groups[2]);var current_mA=parseFloat(groups[3]);series.addPowerSample(time,(voltage_mV*current_mA)/1000);if(groups[4]!==undefined&&this.explicitSyncMark_===undefined){var id=groups[4];this.explicitSyncMark_={'id':id,'ts':time};}}},this);},explicitClockSync:function(){if(this.explicitSyncMark_===undefined)
+return undefined;var syncMarks=this.model.getClockSyncRecordsWithSyncId(this.explicitSyncMark_['id']);if(syncMarks.length!==1){this.model_.importWarning({type:'missing_sync_marker',message:'No single clock sync record found for explicit clock sync.'});return undefined;}
+var clockSync=syncMarks[0];var syncTs=clockSync.start;var traceTs=this.explicitSyncMark_['ts'];return syncTs-traceTs;},foundExplicitSyncMark:function(){return this.explicitSyncMark_!==undefined;}};tr.importer.Importer.register(BattorImporter);return{BattorImporter:BattorImporter,_BattorImporterTestExports:TestExports};});'use strict';tr.exportTo('tr.e.importer.ddms',function(){var kPid=0;var kCategory='java';var kMethodLutEndMarker='\n*end\n';var kThreadsStart='\n*threads\n';var kMethods [...]
+Reader.prototype={__proto__:Object.prototype,uint8:function(){var result=this.data_[this.position_];this.position_+=1;return result;},uint16:function(){var result=0;result+=this.uint8();result+=this.uint8()<<8;return result;},uint32:function(){var result=0;result+=this.uint8();result+=this.uint8()<<8;result+=this.uint8()<<16;result+=this.uint8()<<24;return result;},uint64:function(){var low=this.uint32();var high=this.uint32();var low_str=('0000000'+low.toString(16)).substr(-8);var high_ [...]
+DdmsImporter.canImport=function(data){if(typeof(data)==='string'||data instanceof String){var header=data.slice(0,1000);return header.startsWith('*version\n')&&header.indexOf('\nvm=')>=0&&header.indexOf(kThreadsStart)>=0;}
+return false;};DdmsImporter.prototype={__proto__:tr.importer.Importer.prototype,get importerName(){return'DdmsImporter';},get model(){return this.model_;},importEvents:function(){var divider=this.data_.indexOf(kMethodLutEndMarker)+
+kMethodLutEndMarker.length;this.metadata_=this.data_.slice(0,divider);this.methods_={};this.parseThreads();this.parseMethods();var traceReader=new Reader(this.data_.slice(divider));var magic=traceReader.uint32();if(magic!=kTraceMagicValue){throw Error('Failed to match magic value');}
+this.version_=traceReader.uint16();if(this.version_!=kTraceVersionDualClock){throw Error('Unknown version');}
+var dataOffest=traceReader.uint16();var startDateTime=traceReader.uint64();var recordSize=traceReader.uint16();traceReader.seekTo(dataOffest);while(traceReader.hasMore()){this.parseTraceEntry(traceReader);}},parseTraceEntry:function(reader){var tid=reader.uint16();var methodPacked=reader.uint32();var cpuSinceStart=reader.uint32();var wallClockSinceStart=reader.uint32();var method=methodPacked&~kTraceMethodActionMask;var action=methodPacked&kTraceMethodActionMask;var thread=this.getTid(ti [...]
+kThreadsStart.length);threads=threads.slice(0,threads.indexOf('\n*'));threads=threads.split('\n');threads.forEach(this.parseThread.bind(this));},parseThread:function(thread_line){var tid=thread_line.slice(0,thread_line.indexOf('\t'));var thread=this.getTid(parseInt(tid));thread.name=thread_line.slice(thread_line.indexOf('\t')+1);},getTid:function(tid){return this.model_.getOrCreateProcess(kPid).getOrCreateThread(tid);},parseMethods:function(){var methods=this.metadata_.slice(this.metadat [...]
+kMethodsStart.length);methods=methods.slice(0,methods.indexOf('\n*'));methods=methods.split('\n');methods.forEach(this.parseMethod.bind(this));},parseMethod:function(method_line){var data=method_line.split('\t');var methodId=parseInt(data[0]);var methodName=data[1]+'.'+data[2]+data[3];this.addMethod(methodId,methodName);},addMethod:function(methodId,methodName){this.methods_[methodId]=methodName;},getMethodName:function(methodId){return this.methods_[methodId];}};tr.importer.Importer.reg [...]
+Parser.prototype={__proto__:Object.prototype};var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);options.mandatoryBaseClass=Parser;tr.b.decorateExtensionRegistry(Parser,options);return{Parser:Parser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function AndroidParser(importer){Parser.call(this,importer);importer.registerEventHandler('tracing_mark_write:android',AndroidPar [...]
+function parseArgs(argsString){var args={};if(argsString){var argsArray=argsString.split(';');for(var i=0;i<argsArray.length;++i){var parts=argsArray[i].split('=');if(parts[0])
+args[parts.shift()]=parts.join('=');}}
+return args;}
+AndroidParser.prototype={__proto__:Parser.prototype,openAsyncSlice:function(thread,category,name,cookie,ts,args){var asyncSliceConstructor=tr.model.AsyncSlice.getConstructor(category,name);var slice=new asyncSliceConstructor(category,name,ColorScheme.getColorIdForGeneralPurposeString(name),ts,args);var key=category+':'+name+':'+cookie;slice.id=cookie;slice.startThread=thread;if(!this.openAsyncSlices){this.openAsyncSlices={};}
+this.openAsyncSlices[key]=slice;},closeAsyncSlice:function(thread,category,name,cookie,ts,args){if(!this.openAsyncSlices){return;}
+var key=category+':'+name+':'+cookie;var slice=this.openAsyncSlices[key];if(!slice){return;}
+for(var arg in args){if(slice.args[arg]!==undefined){this.model_.importWarning({type:'parse_error',message:'Both the S and F events of '+slice.title+' provided values for argument '+arg+'.'+' The value of the F event will be used.'});}
+slice.args[arg]=args[arg];}
+slice.endThread=thread;slice.duration=ts-slice.start;slice.startThread.asyncSliceGroup.push(slice);slice.subSlices=[new tr.model.AsyncSlice(slice.category,slice.title,slice.colorId,slice.start,slice.args,slice.duration)];delete this.openAsyncSlices[key];},traceMarkWriteAndroidEvent:function(eventName,cpuNumber,pid,ts,eventBase){var eventData=eventBase.details.split('|');switch(eventData[0]){case'B':var ppid=parseInt(eventData[1]);var title=eventData[2];var args=parseArgs(eventData[3]);va [...]
+category='android';var thread=this.model_.getOrCreateProcess(ppid).getOrCreateThread(pid);thread.name=eventBase.threadName;if(!thread.sliceGroup.isTimestampValidForBeginOrEnd(ts)){this.model_.importWarning({type:'parse_error',message:'Timestamps are moving backward.'});return false;}
+this.ppids_[pid]=ppid;thread.sliceGroup.beginSlice(category,title,ts,args);break;case'E':var ppid=this.ppids_[pid];if(ppid===undefined){break;}
+var thread=this.model_.getOrCreateProcess(ppid).getOrCreateThread(pid);if(!thread.sliceGroup.openSliceCount){break;}
+var slice=thread.sliceGroup.endSlice(ts);var args=parseArgs(eventData[3]);for(var arg in args){if(slice.args[arg]!==undefined){this.model_.importWarning({type:'parse_error',message:'Both the B and E events of '+slice.title+' provided values for argument '+arg+'.'+' The value of the E event will be used.'});}
+slice.args[arg]=args[arg];}
+break;case'C':var ppid=parseInt(eventData[1]);var name=eventData[2];var value=parseInt(eventData[3]);var category=eventData[4];if(category===undefined)
+category='android';var ctr=this.model_.getOrCreateProcess(ppid).getOrCreateCounter(category,name);if(ctr.numSeries===0){ctr.addSeries(new tr.model.CounterSeries(value,ColorScheme.getColorIdForGeneralPurposeString(ctr.name+'.'+'value')));}
+ctr.series.forEach(function(series){series.addCounterSample(ts,value);});break;case'S':var ppid=parseInt(eventData[1]);var name=eventData[2];var cookie=parseInt(eventData[3]);var args=parseArgs(eventData[4]);var category=eventData[5];if(category===undefined)
+category='android';var thread=this.model_.getOrCreateProcess(ppid).getOrCreateThread(pid);thread.name=eventBase.threadName;this.ppids_[pid]=ppid;this.openAsyncSlice(thread,category,name,cookie,ts,args);break;case'F':var ppid=parseInt(eventData[1]);var name=eventData[2];var cookie=parseInt(eventData[3]);var args=parseArgs(eventData[4]);var category=eventData[5];if(category===undefined)
+category='android';var thread=this.model_.getOrCreateProcess(ppid).getOrCreateThread(pid);thread.name=eventBase.threadName;this.ppids_[pid]=ppid;this.closeAsyncSlice(thread,category,name,cookie,ts,args);break;default:return false;}
+return true;}};Parser.register(AndroidParser);return{AndroidParser:AndroidParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;var binderTransRE=new RegExp('transaction=(\\d+) dest_node=(\\d+) '+'dest_proc=(\\d+) dest_thread=(\\d+) '+'reply=(\\d+) flags=(0x[0-9a-fA-F]+) '+'code=(0x[0-9a-fA-F]+)');var binderTransReceivedRE=/transaction=(\d+)/;function isBinderThread(name){return(name.indexOf(' [...]
+var TF_ONE_WAY=0x01;var TF_ROOT_OBJECT=0x04;var TF_STATUS_CODE=0x08;var TF_ACCEPT_FDS=0x10;var NO_FLAGS=0;function binderFlagsToHuman(num){var flag=parseInt(num,16);var str='';if(flag&TF_ONE_WAY)
+str+='this is a one-way call: async, no return; ';if(flag&TF_ROOT_OBJECT)
+str+='contents are the components root object; ';if(flag&TF_STATUS_CODE)
+str+='contents are a 32-bit status code; ';if(flag&TF_ACCEPT_FDS)
+str+='allow replies with file descriptors; ';if(flag===NO_FLAGS)
+str+='No Flags Set';return str;}
+function isReplyToOrigin(calling,called){return(called.dest_proc===calling.calling_pid||called.dest_thread===calling.calling_pid);}
+function binderCodeToHuman(code){return'Java Layer Dependent';}
+function doInternalSlice(trans,slice,ts){if(slice.subSlices.length!==0){slice.subSlices[0].start=ts;return slice.subSlices[0];}
+var kthread=trans.calling_kthread.thread;var internal_slice=kthread.sliceGroup.pushCompleteSlice('binder',slice.title,ts,.001,0,0,slice.args);internal_slice.title=slice.title;internal_slice.id=slice.id;internal_slice.colorId=slice.colorId;slice.subSlices.push(internal_slice);return internal_slice;}
+function generateBinderArgsForSlice(trans,c_threadName){return{'Transaction Id':trans.transaction_key,'Destination Node':trans.dest_node,'Destination Process':trans.dest_proc,'Destination Thread':trans.dest_thread,'Destination Name':c_threadName,'Reply transaction?':trans.is_reply_transaction,'Flags':trans.flags+' '+
+binderFlagsToHuman(trans.flags),'Code':trans.code+' '+
+binderCodeToHuman(trans.code),'Calling PID':trans.calling_pid,'Calling tgid':trans.calling_kthread.thread.parent.pid};}
+function BinderTransaction(events,calling_pid,calling_ts,calling_kthread){this.transaction_key=parseInt(events[1]);this.dest_node=parseInt(events[2]);this.dest_proc=parseInt(events[3]);this.dest_thread=parseInt(events[4]);this.is_reply_transaction=parseInt(events[5])===1?true:false;this.expect_reply=((this.is_reply_transaction===false)&&(parseInt(events[6],16)&TF_ONE_WAY)===0);this.flags=events[6];this.code=events[7];this.calling_pid=calling_pid;this.calling_ts=calling_ts;this.calling_kt [...]
+function BinderParser(importer){Parser.call(this,importer);importer.registerEventHandler('binder_locked',BinderParser.prototype.binderLocked.bind(this));importer.registerEventHandler('binder_unlock',BinderParser.prototype.binderUnlock.bind(this));importer.registerEventHandler('binder_lock',BinderParser.prototype.binderLock.bind(this));importer.registerEventHandler('binder_transaction',BinderParser.prototype.binderTransaction.bind(this));importer.registerEventHandler('binder_transaction_r [...]
+BinderParser.prototype={__proto__:Parser.prototype,binderLock:function(eventName,cpuNumber,pid,ts,eventBase){var tgid=parseInt(eventBase.tgid);this.doNameMappings(pid,tgid,eventName.threadName);var kthread=this.importer_.getOrCreateBinderKernelThread(eventBase.threadName,tgid,pid);kthread.binderAttemptLockTS=ts;kthread.binderOpenTsA=ts;return true;},binderLocked:function(eventName,cpuNumber,pid,ts,eventBase){var binder_thread=isBinderThread(eventBase.threadName);var tgid,name;var as_slic [...]
+return false;var args=this.generateArgsForSlice(tgid,pid,name,kthread);rthread.sliceGroup.pushCompleteSlice('binder','binder lock waiting',kthread.binderAttemptLockTS,ts-kthread.binderAttemptLockTS,0,0,args);kthread.binderAttemptLockTS=undefined;return true;},binderUnlock:function(eventName,cpuNumber,pid,ts,eventBase){var tgid=parseInt(eventBase.tgid);var kthread=this.importer_.getOrCreateBinderKernelThread(eventBase.threadName,tgid,pid);if(kthread.binderLockAquiredTS===undefined)
+return false;var args=this.generateArgsForSlice(tgid,pid,eventBase.threadName,kthread);kthread.thread.sliceGroup.pushCompleteSlice('binder','binder lock held',kthread.binderLockAquiredTS,ts-kthread.binderLockAquiredTS,0,0,args);kthread.binderLockAquiredTS=undefined;return true;},binderTransaction:function(eventName,cpuNumber,pid,ts,eventBase){var event=binderTransRE.exec(eventBase.details);if(event===undefined)
+return false;var tgid=parseInt(eventBase.tgid);this.doNameMappings(pid,tgid,eventBase.threadName);var kthread;kthread=this.importer_.getOrCreateBinderKernelThread(eventBase.threadName,tgid,pid);var trans=new BinderTransaction(event,pid,ts,kthread);var args=generateBinderArgsForSlice(trans,eventBase.threadName);var prior_receive=this.getPriorReceiveOnPID(pid);if(prior_receive!==false){return this.modelPriorReceive(prior_receive,ts,pid,tgid,kthread,trans,args,event);}
+var recursive_trans=this.getRecursiveTransactionNeedingCompletion(pid);if(recursive_trans!==false)
+return this.modelRecursiveTransactions(recursive_trans,ts,pid,kthread,trans,args);var slice=kthread.thread.sliceGroup.pushCompleteSlice('binder','',ts,.03,0,0,args);slice.colorId=ColorScheme.getColorIdForGeneralPurposeString(ts.toString());trans.slice=slice;if(trans.expect_reply)
+slice.title='binder transaction';else
+slice.title='binder transaction async';this.addTransactionWaitingForRecv(trans.transaction_key,trans);return true;},binderTransactionReceived:function(eventName,cpuNumber,pid,ts,eventBase){var event=binderTransReceivedRE.exec(eventBase.details);if(event===undefined)
+return false;var transactionkey=parseInt(event[1]);var tgid=parseInt(eventBase.tgid);var kthread;kthread=this.importer_.getOrCreateBinderKernelThread(eventBase.threadName,tgid,pid);var syncComplete=this.getSyncTransNeedsCompletion(transactionkey);if(syncComplete!==false){var sync_trans=syncComplete[0];var sync_slice=sync_trans.slice;var response_trans=syncComplete[1];var response_slice=response_trans.slice;sync_slice.duration=ts-sync_slice.start;var sync_internal=doInternalSlice(sync_tra [...]
+for(var i=1;i<sync_slice.inFlowEvents.length;i++){sync_slice.inFlowEvents[i].duration=ts-sync_slice.inFlowEvents[i].start;}
 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)
+var tr_for_recv=this.getTransactionWaitingForRecv(transactionkey);if(tr_for_recv!==false){if(!tr_for_recv.expect_reply){var args=generateBinderArgsForSlice(tr_for_recv,eventBase.threadName);var slice=kthread.thread.sliceGroup.pushCompleteSlice('binder','binder Async recv',ts,.03,0,0,args);var fake_event=[0,0,0,0,0,0,0];var fake_trans=new BinderTransaction(fake_event,pid,ts,kthread);var flow=this.generateFlow(tr_for_recv.slice,slice,tr_for_recv,fake_trans);this.model_.flowEvents.push(flow [...]
+tr_for_recv.slice.title='binder transaction';this.setCurrentReceiveOnPID(pid,[ts,tr_for_recv]);return true;}
+return false;},modelRecursiveTransactions:function(recursive_trans,ts,pid,kthread,trans,args){var recursive_slice=recursive_trans[1].slice;var orig_slice=recursive_trans[0].slice;recursive_slice.duration=ts-recursive_slice.start;trans.slice=recursive_slice;if(trans.is_reply_transaction){orig_slice.duration=ts-orig_slice.start;this.addSyncTransNeedingCompletion(trans.transaction_key,recursive_trans);if(isReplyToOrigin(recursive_trans[0],trans))
+this.removeRecursiveTransaction(pid);}else{var slice=kthread.thread.sliceGroup.pushCompleteSlice('binder','',ts,.03,0,0,args);trans.slice=slice;this.addTransactionWaitingForRecv(trans.transaction_key,trans);}
+return true;},modelPriorReceive:function(prior_receive,ts,pid,tgid,kthread,trans,args,event){var callee_slice=prior_receive[1].slice;var callee_trans=prior_receive[1];var recv_ts=prior_receive[0];var slice=kthread.thread.sliceGroup.pushCompleteSlice('binder','',recv_ts,ts-recv_ts,0,0,args);var flow=this.generateFlow(callee_slice,slice,callee_trans,trans);this.model_.flowEvents.push(flow);trans.slice=slice;if(trans.is_reply_transaction){slice.title='binder reply';this.addSyncTransNeedingC [...]
+trans1.slice=slice;this.addRecursiveSyncTransNeedingCompletion(pid,[callee_trans,trans]);this.addTransactionWaitingForRecv(trans.transaction_key,trans1);}
+return true;},getRecursiveTransactionNeedingCompletion:function(pid){if(this.recursiveSyncTransWaitingCompletion_ByPID[pid]===undefined)
+return false;var len=this.recursiveSyncTransWaitingCompletion_ByPID[pid].length;if(len===0)
+return false;return this.recursiveSyncTransWaitingCompletion_ByPID[pid][len-1];},addRecursiveSyncTransNeedingCompletion:function(pid,tuple){if(this.recursiveSyncTransWaitingCompletion_ByPID[pid]===undefined)
+this.recursiveSyncTransWaitingCompletion_ByPID[pid]=[];this.recursiveSyncTransWaitingCompletion_ByPID[pid].push(tuple);},removeRecursiveTransaction:function(pid){var len=this.recursiveSyncTransWaitingCompletion_ByPID[pid].length;if(len===0){delete this.recursiveSyncTransWaitingCompletion_ByPID[pid];return;}
+this.recursiveSyncTransWaitingCompletion_ByPID[pid].splice(len-1,1);},setCurrentReceiveOnPID:function(pid,tuple){if(this.receivedTransWaitingConversion[pid]===undefined){this.receivedTransWaitingConversion[pid]=[];}
+this.receivedTransWaitingConversion[pid].push(tuple);},getPriorReceiveOnPID:function(pid){if(this.receivedTransWaitingConversion[pid]===undefined)
+return false;var len=this.receivedTransWaitingConversion[pid].length;if(len===0)
+return false;return this.receivedTransWaitingConversion[pid].splice(len-1,1)[0];},addSyncTransNeedingCompletion:function(transactionkey,tuple){var dict=this.syncTransWaitingCompletion;dict[transactionkey]=tuple;},getSyncTransNeedsCompletion:function(transactionkey){var ret=this.syncTransWaitingCompletion[transactionkey];if(ret===undefined)
+return false;delete this.syncTransWaitingCompletion[transactionkey];return ret;},getTransactionWaitingForRecv:function(transactionkey){var ret=this.transWaitingRecv[transactionkey];if(ret===undefined)
+return false;delete this.transWaitingRecv[transactionkey];return ret;},addTransactionWaitingForRecv:function(transactionkey,transaction){this.transWaitingRecv[transactionkey]=transaction;},generateFlow:function(from,to,from_trans,to_trans){var title='Transaction from : '+
+this.pid2name(from_trans.calling_pid)+' From PID: '+from_trans.calling_pid+' to pid: '+
+to_trans.calling_pid+' Thread Name: '+this.pid2name(to_trans.calling_pid);var ts=from.start;var flow=new tr.model.FlowEvent('binder','binder',title,1,ts,[]);flow.startSlice=from;flow.endSlice=to;flow.start=from.start;flow.duration=to.start-ts;from.outFlowEvents.push(flow);to.inFlowEvents.push(flow);return flow;},generateArgsForSlice:function(tgid,pid,name,kthread){return{'Thread Name':name,'pid':pid,'gid':tgid};},pid2name:function(pid){return this.kthreadlookup[pid];},doNameMappings:func [...]
+this.kthreadlookup[pid]=name;}};Parser.register(BinderParser);return{BinderParser:BinderParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function BusParser(importer){Parser.call(this,importer);importer.registerEventHandler('memory_bus_usage',BusParser.prototype.traceMarkWriteBusEvent.bind(this));this.model_=importer.model_;this.ppids_={};}
+BusParser.prototype={__proto__:Parser.prototype,traceMarkWriteBusEvent:function(eventName,cpuNumber,pid,ts,eventBase,threadName){var re=new RegExp('bus=(\\S+) rw_bytes=(\\d+) r_bytes=(\\d+) '+'w_bytes=(\\d+) cycles=(\\d+) ns=(\\d+)');var event=re.exec(eventBase.details);var name=event[1];var rw_bytes=parseInt(event[2]);var r_bytes=parseInt(event[3]);var w_bytes=parseInt(event[4]);var cycles=parseInt(event[5]);var ns=parseInt(event[6]);var r_bw=r_bytes*1000000000/ns;r_bw/=1024*1024;var w_ [...]
+ctr.series.forEach(function(series){series.addCounterSample(ts,r_bw);});ctr=this.model_.kernel.getOrCreateCounter(null,'bus '+name+' write');if(ctr.numSeries===0){ctr.addSeries(new tr.model.CounterSeries('value',ColorScheme.getColorIdForGeneralPurposeString(ctr.name+'.'+'value')));}
+ctr.series.forEach(function(series){series.addCounterSample(ts,r_bw);});return true;}};Parser.register(BusParser);return{BusParser:BusParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function ClockParser(importer){Parser.call(this,importer);importer.registerEventHandler('clock_set_rate',ClockParser.prototype.traceMarkWriteClockEvent.bind(this));this.model_=importer.model_;this.ppids_={};}
+ClockParser.prototype={__proto__:Parser.prototype,traceMarkWriteClockEvent:function(eventName,cpuNumber,pid,ts,eventBase,threadName){var event=/(\S+) state=(\d+) cpu_id=(\d+)/.exec(eventBase.details);var name=event[1];var rate=parseInt(event[2]);var ctr=this.model_.kernel.getOrCreateCounter(null,name);if(ctr.numSeries===0){ctr.addSeries(new tr.model.CounterSeries('value',ColorScheme.getColorIdForGeneralPurposeString(ctr.name+'.'+'value')));}
+ctr.series.forEach(function(series){series.addCounterSample(ts,rate);});return true;}};Parser.register(ClockParser);return{ClockParser:ClockParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function CpufreqParser(importer){Parser.call(this,importer);importer.registerEventHandler('cpufreq_interactive_up',CpufreqParser.prototype.cpufreqUpDownEvent.bind(this));importer.registerEventHandler('c [...]
+function splitData(input){var data={};var args=input.split(/\s+/);var len=args.length;for(var i=0;i<len;i++){var item=args[i].split('=');data[item[0]]=parseInt(item[1]);}
+return data;}
+CpufreqParser.prototype={__proto__:Parser.prototype,cpufreqSlice:function(ts,eventName,cpu,args){var kthread=this.importer.getOrCreatePseudoThread('cpufreq');kthread.openSlice=eventName;var slice=new tr.model.Slice('',kthread.openSlice,ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),ts,args,0);kthread.thread.sliceGroup.pushSlice(slice);},cpufreqBoostSlice:function(ts,eventName,args){var kthread=this.importer.getOrCreatePseudoThread('cpufreq_boost');kthread.openSlice=even [...]
+DiskParser.prototype={__proto__:Parser.prototype,openAsyncSlice:function(ts,category,threadName,pid,key,name){var kthread=this.importer.getOrCreateKernelThread(category+':'+threadName,pid);var asyncSliceConstructor=tr.model.AsyncSlice.getConstructor(category,name);var slice=new asyncSliceConstructor(category,name,ColorScheme.getColorIdForGeneralPurposeString(name),ts);slice.startThread=kthread.thread;if(!kthread.openAsyncSlices){kthread.openAsyncSlices={};}
+kthread.openAsyncSlices[key]=slice;},closeAsyncSlice:function(ts,category,threadName,pid,key,args){var kthread=this.importer.getOrCreateKernelThread(category+':'+threadName,pid);if(kthread.openAsyncSlices){var slice=kthread.openAsyncSlices[key];if(slice){slice.duration=ts-slice.start;slice.args=args;slice.endThread=kthread.thread;slice.subSlices=[new tr.model.AsyncSlice(category,slice.title,slice.colorId,slice.start,slice.args,slice.duration)];kthread.thread.asyncSliceGroup.push(slice);d [...]
+return false;var device=event[1];var inode=parseInt(event[2]);var pos=parseInt(event[3]);var len=parseInt(event[4]);var key=device+'-'+inode+'-'+pos+'-'+len;this.openAsyncSlice(ts,'f2fs',eventBase.threadName,eventBase.pid,key,'f2fs_write');return true;},f2fsWriteEndEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/dev = \((\d+,\d+)\), ino = (\d+), pos = (\d+), len = (\d+), copied = (\d+)/.exec(eventBase.details);if(!event)
+return false;var device=event[1];var inode=parseInt(event[2]);var pos=parseInt(event[3]);var len=parseInt(event[4]);var error=parseInt(event[5])!==len;var key=device+'-'+inode+'-'+pos+'-'+len;this.closeAsyncSlice(ts,'f2fs',eventBase.threadName,eventBase.pid,key,{device:device,inode:inode,error:error});return true;},ext4WriteBeginEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/dev (\d+,\d+) ino (\d+) pos (\d+) len (\d+) flags (\d+)/.exec(eventBase.details);if(!event)
+return false;var device=event[1];var inode=parseInt(event[2]);var pos=parseInt(event[3]);var len=parseInt(event[4]);var key=device+'-'+inode+'-'+pos+'-'+len;this.openAsyncSlice(ts,'ext4',eventBase.threadName,eventBase.pid,key,'ext4_write');return true;},ext4WriteEndEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/dev (\d+,\d+) ino (\d+) pos (\d+) len (\d+) copied (\d+)/.exec(eventBase.details);if(!event)
+return false;var device=event[1];var inode=parseInt(event[2]);var pos=parseInt(event[3]);var len=parseInt(event[4]);var error=parseInt(event[5])!==len;var key=device+'-'+inode+'-'+pos+'-'+len;this.closeAsyncSlice(ts,'ext4',eventBase.threadName,eventBase.pid,key,{device:device,inode:inode,error:error});return true;},f2fsSyncFileEnterEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=new RegExp('dev = \\((\\d+,\\d+)\\), ino = (\\d+), pino = (\\d+), i_mode = (\\S+), '+'i_size =  [...]
+return false;var device=event[1];var inode=parseInt(event[2]);var key=device+'-'+inode;this.openAsyncSlice(ts,'f2fs',eventBase.threadName,eventBase.pid,key,'fsync');return true;},f2fsSyncFileExitEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=new RegExp('dev = \\((\\d+,\\d+)\\), ino = (\\d+), checkpoint is (\\S+), '+'datasync = (\\d+), ret = (\\d+)').exec(eventBase.details.replace('not needed','not_needed'));if(!event)
+return false;var device=event[1];var inode=parseInt(event[2]);var error=parseInt(event[5]);var key=device+'-'+inode;this.closeAsyncSlice(ts,'f2fs',eventBase.threadName,eventBase.pid,key,{device:device,inode:inode,error:error});return true;},ext4SyncFileEnterEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/dev (\d+,\d+) ino (\d+) parent (\d+) datasync (\d+)/.exec(eventBase.details);if(!event)
+return false;var device=event[1];var inode=parseInt(event[2]);var datasync=event[4]==1;var key=device+'-'+inode;var action=datasync?'fdatasync':'fsync';this.openAsyncSlice(ts,'ext4',eventBase.threadName,eventBase.pid,key,action);return true;},ext4SyncFileExitEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/dev (\d+,\d+) ino (\d+) ret (\d+)/.exec(eventBase.details);if(!event)
+return false;var device=event[1];var inode=parseInt(event[2]);var error=parseInt(event[3]);var key=device+'-'+inode;this.closeAsyncSlice(ts,'ext4',eventBase.threadName,eventBase.pid,key,{device:device,inode:inode,error:error});return true;},blockRqIssueEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=new RegExp('(\\d+,\\d+) (F)?([DWRN])(F)?(A)?(S)?(M)? '+'\\d+ \\(.*\\) (\\d+) \\+ (\\d+) \\[.*\\]').exec(eventBase.details);if(!event)
+return false;var action;switch(event[3]){case'D':action='discard';break;case'W':action='write';break;case'R':action='read';break;case'N':action='none';break;default:action='unknown';break;}
+if(event[2]){action+=' flush';}
+if(event[4]=='F'){action+=' fua';}
+if(event[5]=='A'){action+=' ahead';}
+if(event[6]=='S'){action+=' sync';}
+if(event[7]=='M'){action+=' meta';}
+var device=event[1];var sector=parseInt(event[8]);var numSectors=parseInt(event[9]);var key=device+'-'+sector+'-'+numSectors;this.openAsyncSlice(ts,'block',eventBase.threadName,eventBase.pid,key,action);return true;},blockRqCompleteEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=new RegExp('(\\d+,\\d+) (F)?([DWRN])(F)?(A)?(S)?(M)? '+'\\(.*\\) (\\d+) \\+ (\\d+) \\[(.*)\\]').exec(eventBase.details);if(!event)
+return false;var device=event[1];var sector=parseInt(event[8]);var numSectors=parseInt(event[9]);var error=parseInt(event[10]);var key=device+'-'+sector+'-'+numSectors;this.closeAsyncSlice(ts,'block',eventBase.threadName,eventBase.pid,key,{device:device,sector:sector,numSectors:numSectors,error:error});return true;}};Parser.register(DiskParser);return{DiskParser:DiskParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e. [...]
+DrmParser.prototype={__proto__:Parser.prototype,drmVblankSlice:function(ts,eventName,args){var kthread=this.importer.getOrCreatePseudoThread('drm_vblank');kthread.openSlice=eventName;var slice=new tr.model.Slice('',kthread.openSlice,ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),ts,args,0);kthread.thread.sliceGroup.pushSlice(slice);},vblankEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/crtc=(\d+), seq=(\d+)/.exec(eventBase.details);if(!event)
+return false;var crtc=parseInt(event[1]);var seq=parseInt(event[2]);this.drmVblankSlice(ts,'vblank:'+crtc,{crtc:crtc,seq:seq});return true;}};Parser.register(DrmParser);return{DrmParser:DrmParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function ExynosParser(importer){Parser.call(this,importer);importer.registerEventHandler('exynos_busfreq_target_int',ExynosParser.prototype.busfreqTarget [...]
+ExynosParser.prototype={__proto__:Parser.prototype,exynosBusfreqSample:function(name,ts,frequency){var targetCpu=this.importer.getOrCreateCpu(0);var counter=targetCpu.getOrCreateCounter('',name);if(counter.numSeries===0){counter.addSeries(new tr.model.CounterSeries('frequency',ColorScheme.getColorIdForGeneralPurposeString(counter.name+'.'+'frequency')));}
+counter.series.forEach(function(series){series.addCounterSample(ts,frequency);});},busfreqTargetIntEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/frequency=(\d+)/.exec(eventBase.details);if(!event)
+return false;this.exynosBusfreqSample('INT Frequency',ts,parseInt(event[1]));return true;},busfreqTargetMifEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/frequency=(\d+)/.exec(eventBase.details);if(!event)
+return false;this.exynosBusfreqSample('MIF Frequency',ts,parseInt(event[1]));return true;},exynosPageFlipStateOpenSlice:function(ts,pipe,fb,state){var kthread=this.importer.getOrCreatePseudoThread('exynos_flip_state (pipe:'+pipe+', fb:'+fb+')');kthread.openSliceTS=ts;kthread.openSlice=state;},exynosPageFlipStateCloseSlice:function(ts,pipe,fb,args){var kthread=this.importer.getOrCreatePseudoThread('exynos_flip_state (pipe:'+pipe+', fb:'+fb+')');if(kthread.openSlice){var slice=new tr.model [...]
+kthread.openSlice=undefined;},pageFlipStateEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/pipe=(\d+), fb=(\d+), state=(.*)/.exec(eventBase.details);if(!event)
+return false;var pipe=parseInt(event[1]);var fb=parseInt(event[2]);var state=event[3];this.exynosPageFlipStateCloseSlice(ts,pipe,fb,{pipe:pipe,fb:fb});if(state!=='flipped')
+this.exynosPageFlipStateOpenSlice(ts,pipe,fb,state);return true;}};Parser.register(ExynosParser);return{ExynosParser:ExynosParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var Parser=tr.e.importer.linux_perf.Parser;function GestureParser(importer){Parser.call(this,importer);importer.registerEventHandler('tracing_mark_write:log',GestureParser.prototype.logEvent.bind(this));importer.registerEventHandler('tracing_mark_write:SyncInterpret',GestureParser.prototype.syn [...]
+GestureParser.prototype={__proto__:Parser.prototype,gestureOpenSlice:function(title,ts,opt_args){var thread=this.importer.getOrCreatePseudoThread('gesture').thread;thread.sliceGroup.beginSlice('touchpad_gesture',title,ts,opt_args);},gestureCloseSlice:function(title,ts){var thread=this.importer.getOrCreatePseudoThread('gesture').thread;if(thread.sliceGroup.openSliceCount){var slice=thread.sliceGroup.mostRecentlyOpenedPartialSlice;if(slice.title!=title){this.importer.model.importWarning({t [...]
+slice.title+' in openSlice, and is '+
+title+' in endSlice'});}else{thread.sliceGroup.endSlice(ts);}}},logEvent:function(eventName,cpuNumber,pid,ts,eventBase){var innerEvent=/^\s*(\w+):\s*(\w+)$/.exec(eventBase.details);switch(innerEvent[1]){case'start':this.gestureOpenSlice('GestureLog',ts,{name:innerEvent[2]});break;case'end':this.gestureCloseSlice('GestureLog',ts);}
+return true;},syncEvent:function(eventName,cpuNumber,pid,ts,eventBase){var innerEvent=/^\s*(\w+):\s*(\w+)$/.exec(eventBase.details);switch(innerEvent[1]){case'start':this.gestureOpenSlice('SyncInterpret',ts,{interpreter:innerEvent[2]});break;case'end':this.gestureCloseSlice('SyncInterpret',ts);}
+return true;},timerEvent:function(eventName,cpuNumber,pid,ts,eventBase){var innerEvent=/^\s*(\w+):\s*(\w+)$/.exec(eventBase.details);switch(innerEvent[1]){case'start':this.gestureOpenSlice('HandleTimer',ts,{interpreter:innerEvent[2]});break;case'end':this.gestureCloseSlice('HandleTimer',ts);}
+return true;}};Parser.register(GestureParser);return{GestureParser:GestureParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function I915Parser(importer){Parser.call(this,importer);importer.registerEventHandler('i915_gem_object_create',I915Parser.prototype.gemObjectCreateEvent.bind(this));importer.registerEventHandler('i915_gem_object_bind',I915Parser.prototype.gemObjectBindEvent.bind(this [...]
+I915Parser.prototype={__proto__:Parser.prototype,i915FlipOpenSlice:function(ts,obj,plane){var kthread=this.importer.getOrCreatePseudoThread('i915_flip');kthread.openSliceTS=ts;kthread.openSlice='flip:'+obj+'/'+plane;},i915FlipCloseSlice:function(ts,args){var kthread=this.importer.getOrCreatePseudoThread('i915_flip');if(kthread.openSlice){var slice=new tr.model.Slice('',kthread.openSlice,ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),kthread.openSliceTS,args,ts-kthread.o [...]
+kthread.openSlice=undefined;},i915GemObjectSlice:function(ts,eventName,obj,args){var kthread=this.importer.getOrCreatePseudoThread('i915_gem');kthread.openSlice=eventName+':'+obj;var slice=new tr.model.Slice('',kthread.openSlice,ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),ts,args,0);kthread.thread.sliceGroup.pushSlice(slice);},i915GemRingSlice:function(ts,eventName,dev,ring,args){var kthread=this.importer.getOrCreatePseudoThread('i915_gem_ring');kthread.openSlice=eve [...]
+return false;var obj=event[1];var size=parseInt(event[2]);this.i915GemObjectSlice(ts,eventName,obj,{obj:obj,size:size});return true;},gemObjectBindEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/obj=(\w+), offset=(\w+), size=(\d+)/.exec(eventBase.details);if(!event)
+return false;var obj=event[1];var offset=event[2];var size=parseInt(event[3]);this.i915ObjectGemSlice(ts,eventName+':'+obj,{obj:obj,offset:offset,size:size});return true;},gemObjectChangeDomainEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/obj=(\w+), read=(\w+=>\w+), write=(\w+=>\w+)/.exec(eventBase.details);if(!event)
+return false;var obj=event[1];var read=event[2];var write=event[3];this.i915GemObjectSlice(ts,eventName,obj,{obj:obj,read:read,write:write});return true;},gemObjectPreadWriteEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/obj=(\w+), offset=(\d+), len=(\d+)/.exec(eventBase.details);if(!event)
+return false;var obj=event[1];var offset=parseInt(event[2]);var len=parseInt(event[3]);this.i915GemObjectSlice(ts,eventName,obj,{obj:obj,offset:offset,len:len});return true;},gemObjectFaultEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/obj=(\w+), (\w+) index=(\d+)/.exec(eventBase.details);if(!event)
+return false;var obj=event[1];var type=event[2];var index=parseInt(event[3]);this.i915GemObjectSlice(ts,eventName,obj,{obj:obj,type:type,index:index});return true;},gemObjectDestroyEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/obj=(\w+)/.exec(eventBase.details);if(!event)
+return false;var obj=event[1];this.i915GemObjectSlice(ts,eventName,obj,{obj:obj});return true;},gemRingDispatchEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/dev=(\d+), ring=(\d+), seqno=(\d+)/.exec(eventBase.details);if(!event)
+return false;var dev=parseInt(event[1]);var ring=parseInt(event[2]);var seqno=parseInt(event[3]);this.i915GemRingSlice(ts,eventName,dev,ring,{dev:dev,ring:ring,seqno:seqno});return true;},gemRingFlushEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/dev=(\d+), ring=(\w+), invalidate=(\w+), flush=(\w+)/.exec(eventBase.details);if(!event)
+return false;var dev=parseInt(event[1]);var ring=parseInt(event[2]);var invalidate=event[3];var flush=event[4];this.i915GemRingSlice(ts,eventName,dev,ring,{dev:dev,ring:ring,invalidate:invalidate,flush:flush});return true;},gemRequestEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/dev=(\d+), ring=(\d+), seqno=(\d+)/.exec(eventBase.details);if(!event)
+return false;var dev=parseInt(event[1]);var ring=parseInt(event[2]);var seqno=parseInt(event[3]);this.i915GemRingSlice(ts,eventName,dev,ring,{dev:dev,ring:ring,seqno:seqno});return true;},gemRingWaitEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/dev=(\d+), ring=(\d+)/.exec(eventBase.details);if(!event)
+return false;var dev=parseInt(event[1]);var ring=parseInt(event[2]);this.i915GemRingSlice(ts,eventName,dev,ring,{dev:dev,ring:ring});return true;},regRWEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/(\w+) reg=(\w+), len=(\d+), val=(\(\w+, \w+\))/.exec(eventBase.details);if(!event)
+return false;var rw=event[1];var reg=event[2];var len=event[3];var data=event[3];this.i915RegSlice(ts,rw,reg,{rw:rw,reg:reg,len:len,data:data});return true;},flipEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/plane=(\d+), obj=(\w+)/.exec(eventBase.details);if(!event)
+return false;var plane=parseInt(event[1]);var obj=event[2];if(eventName=='i915_flip_request')
+this.i915FlipOpenSlice(ts,obj,plane);else
+this.i915FlipCloseSlice(ts,{obj:obj,plane:plane});return true;},gpuFrequency:function(eventName,cpuNumver,pid,ts,eventBase){var event=/new_freq=(\d+)/.exec(eventBase.details);if(!event)
+return false;var freq=parseInt(event[1]);this.i915FreqChangeSlice(ts,eventName,{freq:freq});return true;}};Parser.register(I915Parser);return{I915Parser:I915Parser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function IrqParser(importer){Parser.call(this,importer);importer.registerEventHandler('irq_handler_entry',IrqParser.prototype.irqHandlerEntryEvent.bind(this));importer.registerEventHand [...]
+var irqHandlerEntryRE=/irq=(\d+) name=(.+)/;var irqHandlerExitRE=/irq=(\d+) ret=(.+)/;var softirqRE=/vec=(\d+) \[action=(.+)\]/;var ipiHandlerExitRE=/\((.+)\)/;IrqParser.prototype={__proto__:Parser.prototype,irqHandlerEntryEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=irqHandlerEntryRE.exec(eventBase.details);if(!event)
+return false;var irq=parseInt(event[1]);var name=event[2];var thread=this.importer.getOrCreatePseudoThread('irqs cpu '+cpuNumber);thread.lastEntryTs=ts;thread.irqName=name;return true;},irqHandlerExitEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=irqHandlerExitRE.exec(eventBase.details);if(!event)
+return false;var irq=parseInt(event[1]);var ret=event[2];var thread=this.importer.getOrCreatePseudoThread('irqs cpu '+cpuNumber);if(thread.lastEntryTs!==undefined){var duration=ts-thread.lastEntryTs;var slice=new tr.model.Slice('','IRQ ('+thread.irqName+')',ColorScheme.getColorIdForGeneralPurposeString(event[1]),thread.lastEntryTs,{ret:ret},duration);thread.thread.sliceGroup.pushSlice(slice);}
+thread.lastEntryTs=undefined;thread.irqName=undefined;return true;},softirqRaiseEvent:function(eventName,cpuNumber,pid,ts,eventBase){return true;},softirqEntryEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=softirqRE.exec(eventBase.details);if(!event)
+return false;var action=event[2];var thread=this.importer.getOrCreatePseudoThread('softirq cpu '+cpuNumber);thread.lastEntryTs=ts;return true;},softirqExitEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=softirqRE.exec(eventBase.details);if(!event)
+return false;var vec=parseInt(event[1]);var action=event[2];var thread=this.importer.getOrCreatePseudoThread('softirq cpu '+cpuNumber);if(thread.lastEntryTs!==undefined){var duration=ts-thread.lastEntryTs;var slice=new tr.model.Slice('',action,ColorScheme.getColorIdForGeneralPurposeString(event[1]),thread.lastEntryTs,{vec:vec},duration);thread.thread.sliceGroup.pushSlice(slice);}
+thread.lastEntryTs=undefined;return true;},ipiEntryEvent:function(eventName,cpuNumber,pid,ts,eventBase){var thread=this.importer.getOrCreatePseudoThread('irqs cpu '+cpuNumber);thread.lastEntryTs=ts;return true;},ipiExitEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=ipiHandlerExitRE.exec(eventBase.details);if(!event)
+return false;var ipiName=event[1];var thread=this.importer.getOrCreatePseudoThread('irqs cpu '+cpuNumber);if(thread.lastEntryTs!==undefined){var duration=ts-thread.lastEntryTs;var slice=new tr.model.Slice('','IPI ('+ipiName+')',ColorScheme.getColorIdForGeneralPurposeString(ipiName),thread.lastEntryTs,{},duration);thread.thread.sliceGroup.pushSlice(slice);}
+thread.lastEntryTs=undefined;return true;}};Parser.register(IrqParser);return{IrqParser:IrqParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var LinuxPerfParser=tr.e.importer.linux_perf.Parser;function KernelFuncParser(importer){LinuxPerfParser.call(this,importer);importer.registerEventHandler('graph_ent',KernelFuncParser.prototype.traceKernelFuncEnterEvent.bind(this));importer.registerEventHandler('graph_ret',KernelFuncParser.prototype.traceKernelFuncReturnEvent. [...]
+var TestExports={};var funcEnterRE=new RegExp('func=(.+)');TestExports.funcEnterRE=funcEnterRE;KernelFuncParser.prototype={__proto__:LinuxPerfParser.prototype,traceKernelFuncEnterEvent:function(eventName,cpuNumber,pid,ts,eventBase){var eventData=funcEnterRE.exec(eventBase.details);if(!eventData)
+return false;if(eventBase.tgid===undefined){return false;}
+var tgid=parseInt(eventBase.tgid);var name=eventData[1];var thread=this.model_.getOrCreateProcess(tgid).getOrCreateThread(pid);thread.name=eventBase.threadName;var slices=thread.kernelSliceGroup;if(!slices.isTimestampValidForBeginOrEnd(ts)){this.model_.importWarning({type:'parse_error',message:'Timestamps are moving backward.'});return false;}
+var slice=slices.beginSlice(null,name,ts,{});return true;},traceKernelFuncReturnEvent:function(eventName,cpuNumber,pid,ts,eventBase){if(eventBase.tgid===undefined){return false;}
+var tgid=parseInt(eventBase.tgid);var thread=this.model_.getOrCreateProcess(tgid).getOrCreateThread(pid);thread.name=eventBase.threadName;var slices=thread.kernelSliceGroup;if(!slices.isTimestampValidForBeginOrEnd(ts)){this.model_.importWarning({type:'parse_error',message:'Timestamps are moving backward.'});return false;}
+if(slices.openSliceCount>0){slices.endSlice(ts);}
+return true;}};LinuxPerfParser.register(KernelFuncParser);return{KernelFuncParser:KernelFuncParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function MaliParser(importer){Parser.call(this,importer);importer.registerEventHandler('mali_dvfs_event',MaliParser.prototype.dvfsEventEvent.bind(this));importer.registerEventHandler('mali_dvfs_set_clock',MaliParser.prototype.dvfsSetClockEvent.bind(t [...]
+this.addTilerCounter('mali_hwc_TRIANGLES','Triangles');this.addTilerCounter('mali_hwc_QUADS','Quads');this.addTilerCounter('mali_hwc_POLYGONS','Polygons');this.addTilerCounter('mali_hwc_POINTS','Points');this.addTilerCounter('mali_hwc_LINES','Lines');this.addTilerCounter('mali_hwc_VCACHE_HIT','VCache Hit');this.addTilerCounter('mali_hwc_VCACHE_MISS','VCache Miss');this.addTilerCounter('mali_hwc_FRONT_FACING','Front Facing');this.addTilerCounter('mali_hwc_BACK_FACING','Back Facing');this. [...]
+MaliParser.prototype={__proto__:Parser.prototype,maliDDKOpenSlice:function(pid,tid,ts,func,blockinfo){var thread=this.importer.model_.getOrCreateProcess(pid).getOrCreateThread(tid);var funcArgs=/^([\w\d_]*)(?:\(\))?:?\s*(.*)$/.exec(func);thread.sliceGroup.beginSlice('gpu-driver',funcArgs[1],ts,{'args':funcArgs[2],'blockinfo':blockinfo});},maliDDKCloseSlice:function(pid,tid,ts,args,blockinfo){var thread=this.importer.model_.getOrCreateProcess(pid).getOrCreateThread(tid);if(!thread.sliceGr [...]
+thread.sliceGroup.endSlice(ts);},autoDetectLineRE:function(line){var lineREWithThread=/^\s*\(([\w\-]*)\)\s*(\w+):\s*([\w\\\/\.\-]*@\d*):?\s*(.*)$/;if(lineREWithThread.test(line))
+return lineREWithThread;var lineRENoThread=/^s*()(\w+):\s*([\w\\\/.\-]*):?\s*(.*)$/;if(lineRENoThread.test(line))
+return lineRENoThread;return null;},lineRE:null,maliDDKEvent:function(eventName,cpuNumber,pid,ts,eventBase){if(this.lineRE==null){this.lineRE=this.autoDetectLineRE(eventBase.details);if(this.lineRE==null)
 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 [...]
+var maliEvent=this.lineRE.exec(eventBase.details);var tid=(maliEvent[1]===''?'mali':maliEvent[1]);switch(maliEvent[2]){case'cros_trace_print_enter':this.maliDDKOpenSlice(pid,tid,ts,maliEvent[4],maliEvent[3]);break;case'cros_trace_print_exit':this.maliDDKCloseSlice(pid,tid,ts,[],maliEvent[3]);}
+return true;},dvfsSample:function(counterName,seriesName,ts,s){var value=parseInt(s);var counter=this.model_.kernel.getOrCreateCounter('DVFS',counterName);if(counter.numSeries===0){counter.addSeries(new tr.model.CounterSeries(seriesName,ColorScheme.getColorIdForGeneralPurposeString(counter.name)));}
+counter.series.forEach(function(series){series.addCounterSample(ts,value);});},dvfsEventEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/utilization=(\d+)/.exec(eventBase.details);if(!event)
+return false;this.dvfsSample('DVFS Utilization','utilization',ts,event[1]);return true;},dvfsSetClockEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/frequency=(\d+)/.exec(eventBase.details);if(!event)
+return false;this.dvfsSample('DVFS Frequency','frequency',ts,event[1]);return true;},dvfsSetVoltageEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/voltage=(\d+)/.exec(eventBase.details);if(!event)
+return false;this.dvfsSample('DVFS Voltage','voltage',ts,event[1]);return true;},hwcSample:function(cat,counterName,seriesName,ts,eventBase){var event=/val=(\d+)/.exec(eventBase.details);if(!event)
+return false;var value=parseInt(event[1]);var counter=this.model_.kernel.getOrCreateCounter(cat,counterName);if(counter.numSeries===0){counter.addSeries(new tr.model.CounterSeries(seriesName,ColorScheme.getColorIdForGeneralPurposeString(counter.name)));}
+counter.series.forEach(function(series){series.addCounterSample(ts,value);});return true;},jmSample:function(ctrName,seriesName,ts,eventBase){return this.hwcSample('mali:jm','JM: '+ctrName,seriesName,ts,eventBase);},addJMCounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.jmSample(hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addJMCycles:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.jmSample(hwcTitle,'cycles',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},tilerSample:function(ctrName,seriesName,ts,eventBase){return this.hwcSample('mali:tiler','Tiler: '+ctrName,seriesName,ts,eventBase);},addTilerCounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.tilerSample(hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addTilerCycles:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.tilerSample(hwcTitle,'cycles',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},fragSample:function(ctrName,seriesName,ts,eventBase){return this.hwcSample('mali:fragment','Fragment: '+ctrName,seriesName,ts,eventBase);},addFragCounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.fragSample(hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addFragCycles:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.fragSample(hwcTitle,'cycles',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},computeSample:function(ctrName,seriesName,ts,eventBase){return this.hwcSample('mali:compute','Compute: '+ctrName,seriesName,ts,eventBase);},addComputeCounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.computeSample(hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addComputeCycles:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.computeSample(hwcTitle,'cycles',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addTripipeCycles:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.hwcSample('mali:shader','Tripipe: '+hwcTitle,'cycles',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},arithSample:function(ctrName,seriesName,ts,eventBase){return this.hwcSample('mali:arith','Arith: '+ctrName,seriesName,ts,eventBase);},addArithCounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.arithSample(hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addArithCycles:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.arithSample(hwcTitle,'cycles',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addLSCounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.hwcSample('mali:ls','LS: '+hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},textureSample:function(ctrName,seriesName,ts,eventBase){return this.hwcSample('mali:texture','Texture: '+ctrName,seriesName,ts,eventBase);},addTexCounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.textureSample(hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addLSCCounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.hwcSample('mali:lsc','LSC: '+hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addAXICounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.hwcSample('mali:axi','AXI: '+hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},mmuSample:function(ctrName,seriesName,ts,eventBase){return this.hwcSample('mali:mmu','MMU: '+ctrName,seriesName,ts,eventBase);},addMMUCounter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.mmuSample(hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addMMUCycles:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.mmuSample(hwcTitle,'cycles',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},l2Sample:function(ctrName,seriesName,ts,eventBase){return this.hwcSample('mali:l2','L2: '+ctrName,seriesName,ts,eventBase);},addL2Counter:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.l2Sample(hwcTitle,'count',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));},addL2Cycles:function(hwcEventName,hwcTitle){function handler(eventName,cpuNumber,pid,ts,eventBase){return this.l2Sample(hwcTitle,'cycles',ts,eventBase);}
+this.importer.registerEventHandler(hwcEventName,handler.bind(this));}};Parser.register(MaliParser);return{MaliParser:MaliParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var Parser=tr.e.importer.linux_perf.Parser;function MemReclaimParser(importer){Parser.call(this,importer);importer.registerEventHandler('mm_vmscan_kswapd_wake',MemReclaimParser.prototype.kswapdWake.bind(this));importer.registerEventHandler('mm_vmscan_kswapd_sleep',MemReclaimParser.prototype.kswap [...]
+var kswapdWakeRE=/nid=(\d+) order=(\d+)/;var kswapdSleepRE=/nid=(\d+)/;var reclaimBeginRE=/order=(\d+) may_writepage=\d+ gfp_flags=(.+)/;var reclaimEndRE=/nr_reclaimed=(\d+)/;MemReclaimParser.prototype={__proto__:Parser.prototype,kswapdWake:function(eventName,cpuNumber,pid,ts,eventBase){var event=kswapdWakeRE.exec(eventBase.details);if(!event)
+return false;var tgid=parseInt(eventBase.tgid);var nid=parseInt(event[1]);var order=parseInt(event[2]);var kthread=this.importer.getOrCreateKernelThread(eventBase.threadName,tgid,pid);if(kthread.openSliceTS){if(order>kthread.order){kthread.order=order;}}else{kthread.openSliceTS=ts;kthread.order=order;}
+return true;},kswapdSleep:function(eventName,cpuNumber,pid,ts,eventBase){var tgid=parseInt(eventBase.tgid);var kthread=this.importer.getOrCreateKernelThread(eventBase.threadName,tgid,pid);if(kthread.openSliceTS){kthread.thread.sliceGroup.pushCompleteSlice('memreclaim',eventBase.threadName,kthread.openSliceTS,ts-kthread.openSliceTS,0,0,{order:kthread.order});}
+kthread.openSliceTS=undefined;kthread.order=undefined;return true;},reclaimBegin:function(eventName,cpuNumber,pid,ts,eventBase){var event=reclaimBeginRE.exec(eventBase.details);if(!event)
+return false;var order=parseInt(event[1]);var gfp=event[2];var tgid=parseInt(eventBase.tgid);var kthread=this.importer.getOrCreateKernelThread(eventBase.threadName,tgid,pid);kthread.openSliceTS=ts;kthread.order=order;kthread.gfp=gfp;return true;},reclaimEnd:function(eventName,cpuNumber,pid,ts,eventBase){var event=reclaimEndRE.exec(eventBase.details);if(!event)
+return false;var nr_reclaimed=parseInt(event[1]);var tgid=parseInt(eventBase.tgid);var kthread=this.importer.getOrCreateKernelThread(eventBase.threadName,tgid,pid);if(kthread.openSliceTS!==undefined){kthread.thread.sliceGroup.pushCompleteSlice('memreclaim','direct reclaim',kthread.openSliceTS,ts-kthread.openSliceTS,0,0,{order:kthread.order,gfp:kthread.gfp,nr_reclaimed:nr_reclaimed});}
+kthread.openSliceTS=undefined;kthread.order=undefined;kthread.gfp=undefined;return true;}};Parser.register(MemReclaimParser);return{MemReclaimParser:MemReclaimParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function PowerParser(importer){Parser.call(this,importer);importer.registerEventHandler('power_start',PowerParser.prototype.powerStartEvent.bind(this));importer.registerEventHandler(' [...]
+PowerParser.prototype={__proto__:Parser.prototype,cpuStateSlice:function(ts,targetCpuNumber,eventType,cpuState){var targetCpu=this.importer.getOrCreateCpu(targetCpuNumber);var powerCounter;if(eventType!='1'){this.importer.model.importWarning({type:'parse_error',message:'Don\'t understand power_start events of '+'type '+eventType});return;}
+powerCounter=targetCpu.getOrCreateCounter('','C-State');if(powerCounter.numSeries===0){powerCounter.addSeries(new tr.model.CounterSeries('state',ColorScheme.getColorIdForGeneralPurposeString(powerCounter.name+'.'+'state')));}
+powerCounter.series.forEach(function(series){series.addCounterSample(ts,cpuState);});},cpuIdleSlice:function(ts,targetCpuNumber,cpuState){var targetCpu=this.importer.getOrCreateCpu(targetCpuNumber);var powerCounter=targetCpu.getOrCreateCounter('','C-State');if(powerCounter.numSeries===0){powerCounter.addSeries(new tr.model.CounterSeries('state',ColorScheme.getColorIdForGeneralPurposeString(powerCounter.name)));}
+var val=(cpuState!=4294967295?cpuState+1:0);powerCounter.series.forEach(function(series){series.addCounterSample(ts,val);});},cpuFrequencySlice:function(ts,targetCpuNumber,powerState){var targetCpu=this.importer.getOrCreateCpu(targetCpuNumber);var powerCounter=targetCpu.getOrCreateCounter('','Clock Frequency');if(powerCounter.numSeries===0){powerCounter.addSeries(new tr.model.CounterSeries('state',ColorScheme.getColorIdForGeneralPurposeString(powerCounter.name+'.'+'state')));}
+powerCounter.series.forEach(function(series){series.addCounterSample(ts,powerState);});},cpuFrequencyLimitsSlice:function(ts,targetCpuNumber,minFreq,maxFreq){var targetCpu=this.importer.getOrCreateCpu(targetCpuNumber);var powerCounter=targetCpu.getOrCreateCounter('','Clock Frequency Limits');if(powerCounter.numSeries===0){powerCounter.addSeries(new tr.model.CounterSeries('Min Frequency',ColorScheme.getColorIdForGeneralPurposeString(powerCounter.name+'.'+'Min Frequency')));powerCounter.ad [...]
+powerCounter.series.forEach(function(series){if(series.name=='Min Frequency')
+series.addCounterSample(ts,minFreq);if(series.name=='Max Frequency')
+series.addCounterSample(ts,maxFreq);});},powerStartEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/type=(\d+) state=(\d) cpu_id=(\d+)/.exec(eventBase.details);if(!event)
+return false;var targetCpuNumber=parseInt(event[3]);var cpuState=parseInt(event[2]);this.cpuStateSlice(ts,targetCpuNumber,event[1],cpuState);return true;},powerFrequencyEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/type=(\d+) state=(\d+) cpu_id=(\d+)/.exec(eventBase.details);if(!event)
+return false;var targetCpuNumber=parseInt(event[3]);var powerState=parseInt(event[2]);this.cpuFrequencySlice(ts,targetCpuNumber,powerState);return true;},cpuFrequencyEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/state=(\d+) cpu_id=(\d+)/.exec(eventBase.details);if(!event)
+return false;var targetCpuNumber=parseInt(event[2]);var powerState=parseInt(event[1]);this.cpuFrequencySlice(ts,targetCpuNumber,powerState);return true;},cpuFrequencyLimitsEvent:function(eventName,cpu,pid,ts,eventBase){var event=/min=(\d+) max=(\d+) cpu_id=(\d+)/.exec(eventBase.details);if(!event)
+return false;var targetCpuNumber=parseInt(event[3]);var minFreq=parseInt(event[1]);var maxFreq=parseInt(event[2]);this.cpuFrequencyLimitsSlice(ts,targetCpuNumber,minFreq,maxFreq);return true;},cpuIdleEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/state=(\d+) cpu_id=(\d+)/.exec(eventBase.details);if(!event)
+return false;var targetCpuNumber=parseInt(event[2]);var cpuState=parseInt(event[1]);this.cpuIdleSlice(ts,targetCpuNumber,cpuState);return true;}};Parser.register(PowerParser);return{PowerParser:PowerParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function RegulatorParser(importer){Parser.call(this,importer);importer.registerEventHandler('regulator_enable',RegulatorParser.prototype.regula [...]
+var regulatorEnableRE=/name=(.+)/;var regulatorDisableRE=/name=(.+)/;var regulatorSetVoltageCompleteRE=/name=(\S+), val=(\d+)/;RegulatorParser.prototype={__proto__:Parser.prototype,getCtr_:function(ctrName,valueName){var ctr=this.model_.kernel.getOrCreateCounter(null,'vreg '+ctrName+' '+valueName);if(ctr.series[0]===undefined){ctr.addSeries(new tr.model.CounterSeries(valueName,ColorScheme.getColorIdForGeneralPurposeString(ctrName+'.'+valueName)));}
+return ctr;},regulatorEnableEvent:function(eventName,cpuNum,pid,ts,eventBase){var event=regulatorEnableRE.exec(eventBase.details);if(!event)
+return false;var name=event[1];var ctr=this.getCtr_(name,'enabled');ctr.series[0].addCounterSample(ts,1);return true;},regulatorEnableDelayEvent:function(eventName,cpuNum,pid,ts,eventBase){return true;},regulatorEnableCompleteEvent:function(eventName,cpuNum,pid,ts,eventBase){return true;},regulatorDisableEvent:function(eventName,cpuNum,pid,ts,eventBase){var event=regulatorDisableRE.exec(eventBase.details);if(!event)
+return false;var name=event[1];var ctr=this.getCtr_(name,'enabled');ctr.series[0].addCounterSample(ts,0);return true;},regulatorDisableCompleteEvent:function(eventName,cpuNum,pid,ts,eventBase){return true;},regulatorSetVoltageEvent:function(eventName,cpuNum,pid,ts,eventBase){return true;},regulatorSetVoltageCompleteEvent:function(eventName,cpuNum,pid,ts,eventBase){var event=regulatorSetVoltageCompleteRE.exec(eventBase.details);if(!event)
+return false;var name=event[1];var voltage=parseInt(event[2]);var ctr=this.getCtr_(name,'voltage');ctr.series[0].addCounterSample(ts,voltage);return true;}};Parser.register(RegulatorParser);return{RegulatorParser:RegulatorParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var Parser=tr.e.importer.linux_perf.Parser;function SchedParser(importer){Parser.call(this,importer);importer.registerEventHandler('sched_switch',SchedParser.prototype.schedSwitchEvent.bind(this)) [...]
+var TestExports={};var schedSwitchRE=new RegExp('prev_comm=(.+) prev_pid=(\\d+) prev_prio=(\\d+) '+'prev_state=(\\S\\+?|\\S\\|\\S) ==> '+'next_comm=(.+) next_pid=(\\d+) next_prio=(\\d+)');var schedBlockedRE=new RegExp('pid=(\\d+) iowait=(\\d) caller=(.+)');TestExports.schedSwitchRE=schedSwitchRE;var schedWakeupRE=/comm=(.+) pid=(\d+) prio=(\d+) success=(\d+) target_cpu=(\d+)/;TestExports.schedWakeupRE=schedWakeupRE;SchedParser.prototype={__proto__:Parser.prototype,schedSwitchEvent:functi [...]
+return false;var prevState=event[4];var nextComm=event[5];var nextPid=parseInt(event[6]);var nextPrio=parseInt(event[7]);var nextThread=this.importer.threadsByLinuxPid[nextPid];var nextName;if(nextThread)
+nextName=nextThread.userFriendlyName;else
+nextName=nextComm;var cpu=this.importer.getOrCreateCpu(cpuNumber);cpu.switchActiveThread(ts,{stateWhenDescheduled:prevState},nextPid,nextName,{comm:nextComm,tid:nextPid,prio:nextPrio});return true;},schedWakeupEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=schedWakeupRE.exec(eventBase.details);if(!event)
+return false;var fromPid=pid;var comm=event[1];var pid=parseInt(event[2]);var prio=parseInt(event[3]);this.importer.markPidRunnable(ts,pid,comm,prio,fromPid);return true;},schedCpuHotplugEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=/cpu (\d+) (.+) error=(\d+)/.exec(eventBase.details);if(!event)
+return false;var cpuNumber=event[1];var state=event[2];var targetCpu=this.importer.getOrCreateCpu(cpuNumber);var powerCounter=targetCpu.getOrCreateCounter('','Cpu Hotplug');if(powerCounter.numSeries===0){powerCounter.addSeries(new tr.model.CounterSeries('State',tr.b.ColorScheme.getColorIdForGeneralPurposeString(powerCounter.name+'.'+'State')));}
+powerCounter.series.forEach(function(series){if(series.name=='State')
+series.addCounterSample(ts,state.localeCompare('offline')?0:1);});return true;},schedBlockedEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=schedBlockedRE.exec(eventBase.details);if(!event)
+return false;var pid=parseInt(event[1]);var iowait=parseInt(event[2]);var caller=event[3];this.importer.addPidBlockedReason(ts,pid,iowait,caller);return true;}};Parser.register(SchedParser);return{SchedParser:SchedParser,_SchedParserTestExports:TestExports};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function SyncParser(importer){Parser.call(this,importer);importer.registerEventHandler('sync [...]
+var syncTimelineRE=/name=(\S+) value=(\S*)/;var syncWaitRE=/(\S+) name=(\S+) state=(\d+)/;var syncPtRE=/name=(\S+) value=(\S*)/;SyncParser.prototype={__proto__:Parser.prototype,timelineEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=syncTimelineRE.exec(eventBase.details);if(!event)
+return false;var thread=this.importer.getOrCreatePseudoThread(event[1]);if(thread.lastActiveTs!==undefined){var duration=ts-thread.lastActiveTs;var value=thread.lastActiveValue;if(value==undefined)
+value=' ';var slice=new tr.model.Slice('',value,ColorScheme.getColorIdForGeneralPurposeString(value),thread.lastActiveTs,{},duration);thread.thread.sliceGroup.pushSlice(slice);}
+thread.lastActiveTs=ts;thread.lastActiveValue=event[2];return true;},syncWaitEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=syncWaitRE.exec(eventBase.details);if(!event)
+return false;if(eventBase.tgid===undefined){return false;}
+var tgid=parseInt(eventBase.tgid);var thread=this.model_.getOrCreateProcess(tgid).getOrCreateThread(pid);thread.name=eventBase.threadName;var slices=thread.kernelSliceGroup;if(!slices.isTimestampValidForBeginOrEnd(ts)){this.model_.importWarning({type:'parse_error',message:'Timestamps are moving backward.'});return false;}
+var name='fence_wait("'+event[2]+'")';if(event[1]=='begin'){var slice=slices.beginSlice(null,name,ts,{'Start state':event[3]});}else if(event[1]=='end'){if(slices.openSliceCount>0){slices.endSlice(ts);}}else{return false;}
+return true;},syncPtEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=syncPtRE.exec(eventBase.details);if(!event)
+return false;return true;var thread=this.importer.getOrCreateKernelThread(eventBase[1]).thread;thread.syncWaitSyncPts[event[1]]=event[2];return true;}};Parser.register(SyncParser);return{SyncParser:SyncParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var ColorScheme=tr.b.ColorScheme;var Parser=tr.e.importer.linux_perf.Parser;function WorkqueueParser(importer){Parser.call(this,importer);importer.registerEventHandler('workqueue_execute_start',WorkqueueParser.protot [...]
+var workqueueExecuteStartRE=/work struct (.+): function (\S+)/;var workqueueExecuteEndRE=/work struct (.+)/;WorkqueueParser.prototype={__proto__:Parser.prototype,executeStartEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=workqueueExecuteStartRE.exec(eventBase.details);if(!event)
+return false;var kthread=this.importer.getOrCreateKernelThread(eventBase.threadName,pid,pid);kthread.openSliceTS=ts;kthread.openSlice=event[2];return true;},executeEndEvent:function(eventName,cpuNumber,pid,ts,eventBase){var event=workqueueExecuteEndRE.exec(eventBase.details);if(!event)
+return false;var kthread=this.importer.getOrCreateKernelThread(eventBase.threadName,pid,pid);if(kthread.openSlice){var slice=new tr.model.Slice('',kthread.openSlice,ColorScheme.getColorIdForGeneralPurposeString(kthread.openSlice),kthread.openSliceTS,{},ts-kthread.openSliceTS);kthread.thread.sliceGroup.pushSlice(slice);}
+kthread.openSlice=undefined;return true;},executeQueueWork:function(eventName,cpuNumber,pid,ts,eventBase){return true;},executeActivateWork:function(eventName,cpuNumber,pid,ts,eventBase){return true;}};Parser.register(WorkqueueParser);return{WorkqueueParser:WorkqueueParser};});'use strict';tr.exportTo('tr.e.importer.linux_perf',function(){var InstantClockSyncRecord=tr.model.InstantClockSyncRecord;function FTraceImporter(model,events){this.importPriority=2;this.model_=model;this.events_=e [...]
+var TestExports={};var lineREWithTGID=new RegExp('^\\s*(.+)-(\\d+)\\s+\\(\\s*(\\d+|-+)\\)\\s\\[(\\d+)\\]'+'\\s+[dX.][Nnp.][Hhs.][0-9a-f.]'+'\\s+(\\d+\\.\\d+):\\s+(\\S+):\\s(.*)$');var lineParserWithTGID=function(line){var groups=lineREWithTGID.exec(line);if(!groups){return groups;}
+var tgid=groups[3];if(tgid[0]==='-')
+tgid=undefined;return{threadName:groups[1],pid:groups[2],tgid:tgid,cpuNumber:groups[4],timestamp:groups[5],eventName:groups[6],details:groups[7]};};TestExports.lineParserWithTGID=lineParserWithTGID;var lineREWithIRQInfo=new RegExp('^\\s*(.+)-(\\d+)\\s+\\[(\\d+)\\]'+'\\s+[dX.][Nnp.][Hhs.][0-9a-f.]'+'\\s+(\\d+\\.\\d+):\\s+(\\S+):\\s(.*)$');var lineParserWithIRQInfo=function(line){var groups=lineREWithIRQInfo.exec(line);if(!groups){return groups;}
+return{threadName:groups[1],pid:groups[2],cpuNumber:groups[3],timestamp:groups[4],eventName:groups[5],details:groups[6]};};TestExports.lineParserWithIRQInfo=lineParserWithIRQInfo;var lineREWithLegacyFmt=/^\s*(.+)-(\d+)\s+\[(\d+)\]\s*(\d+\.\d+):\s+(\S+):\s(.*)$/;var lineParserWithLegacyFmt=function(line){var groups=lineREWithLegacyFmt.exec(line);if(!groups){return groups;}
+return{threadName:groups[1],pid:groups[2],cpuNumber:groups[3],timestamp:groups[4],eventName:groups[5],details:groups[6]};};TestExports.lineParserWithLegacyFmt=lineParserWithLegacyFmt;var traceEventClockSyncRE=/trace_event_clock_sync: parent_ts=(\d+\.?\d*)/;TestExports.traceEventClockSyncRE=traceEventClockSyncRE;var realTimeClockSyncRE=/trace_event_clock_sync: realtime_ts=(\d+)/;var genericClockSyncRE=/trace_event_clock_sync: name=(\w+)/;var pseudoKernelPID=0;function autoDetectLineParser [...]
+return false;if(lineREWithTGID.test(line))
+return lineParserWithTGID;if(lineREWithIRQInfo.test(line))
+return lineParserWithIRQInfo;if(lineREWithLegacyFmt.test(line))
+return lineParserWithLegacyFmt;return undefined;};TestExports.autoDetectLineParser=autoDetectLineParser;FTraceImporter.canImport=function(events){if(!(typeof(events)==='string'||events instanceof String))
+return false;if(FTraceImporter._extractEventsFromSystraceHTML(events,false).ok)
+return true;if(FTraceImporter._extractEventsFromSystraceMultiHTML(events,false).ok)
+return true;if(/^# tracer:/.test(events))
+return true;var lineBreakIndex=events.indexOf('\n');if(lineBreakIndex>-1)
+events=events.substring(0,lineBreakIndex);if(autoDetectLineParser(events))
+return true;return false;};FTraceImporter._extractEventsFromSystraceHTML=function(incoming_events,produce_result){var failure={ok:false};if(produce_result===undefined)
+produce_result=true;if(/^<!DOCTYPE html>/.test(incoming_events)==false)
+return failure;var r=new tr.importer.SimpleLineReader(incoming_events);if(!r.advanceToLineMatching(/^  <script>$/))
+return failure;if(!r.advanceToLineMatching(/^  var linuxPerfData = "\\$/))
+return failure;var events_begin_at_line=r.curLineNumber+1;r.beginSavingLines();if(!r.advanceToLineMatching(/^  <\/script>$/))
+return failure;var raw_events=r.endSavingLinesAndGetResult();raw_events=raw_events.slice(1,raw_events.length-1);if(!r.advanceToLineMatching(/^<\/body>$/))
+return failure;if(!r.advanceToLineMatching(/^<\/html>$/))
+return failure;function endsWith(str,suffix){return str.indexOf(suffix,str.length-suffix.length)!==-1;}
+function stripSuffix(str,suffix){if(!endsWith(str,suffix))
+return str;return str.substring(str,str.length-suffix.length);}
+var events=[];if(produce_result){for(var i=0;i<raw_events.length;i++){var event=raw_events[i];event=stripSuffix(event,'\\n\\');events.push(event);}}else{events=[raw_events[raw_events.length-1]];}
+var oldLastEvent=events[events.length-1];var newLastEvent=stripSuffix(oldLastEvent,'\\n";');if(newLastEvent==oldLastEvent)
+return failure;events[events.length-1]=newLastEvent;return{ok:true,lines:produce_result?events:undefined,events_begin_at_line:events_begin_at_line};};FTraceImporter._extractEventsFromSystraceMultiHTML=function(incoming_events,produce_result){var failure={ok:false};if(produce_result===undefined)
+produce_result=true;if(new RegExp('^<!DOCTYPE HTML>','i').test(incoming_events)==false)
+return failure;var r=new tr.importer.SimpleLineReader(incoming_events);var events=[];while(!/^# tracer:/.test(events)){if(!r.advanceToLineMatching(/^  <script class="trace-data" type="application\/text">$/))
+return failure;var events_begin_at_line=r.curLineNumber+1;r.beginSavingLines();if(!r.advanceToLineMatching(/^  <\/script>$/))
+return failure;events=r.endSavingLinesAndGetResult();events=events.slice(1,events.length-1);}
+if(!r.advanceToLineMatching(/^<\/body>$/))
+return failure;if(!r.advanceToLineMatching(/^<\/html>$/))
+return failure;return{ok:true,lines:produce_result?events:undefined,events_begin_at_line:events_begin_at_line};};FTraceImporter.prototype={__proto__:tr.importer.Importer.prototype,get importerName(){return'FTraceImporter';},get model(){return this.model_;},importEvents:function(){this.parsers_=this.createParsers_();this.registerDefaultHandlers_();this.parseLines_();this.importClockSyncRecords_();var modelTimeTransformer=this.getModelTimeTransformer_();if(modelTimeTransformer===undefined) [...]
+this.shiftNewlyAddedClockSyncRecords_(modelTimeTransformer);this.importCpuData_(modelTimeTransformer);this.buildMapFromLinuxPidsToThreads_();this.buildPerThreadCpuSlicesFromCpuState_();},registerEventHandler:function(eventName,handler){this.eventHandlers_[eventName]=handler;},getOrCreateCpu:function(cpuNumber){return this.model_.kernel.getOrCreateCpu(cpuNumber);},getOrCreateKernelThread:function(kernelThreadName,pid,tid){if(!this.kernelThreadStates_[kernelThreadName]){var thread=this.mod [...]
+return this.kernelThreadStates_[kernelThreadName];},getOrCreateBinderKernelThread:function(kernelThreadName,pid,tid){var key=kernelThreadName+pid+tid;if(!this.kernelThreadStates_[key]){var thread=this.model_.getOrCreateProcess(pid).getOrCreateThread(tid);thread.name=kernelThreadName;this.kernelThreadStates_[key]={pid:pid,thread:thread,openSlice:undefined,openSliceTS:undefined};this.threadsByLinuxPid[pid]=thread;}
+return this.kernelThreadStates_[key];},getOrCreatePseudoThread:function(threadName){var thread=this.kernelThreadStates_[threadName];if(!thread){thread=this.getOrCreateKernelThread(threadName,pseudoKernelPID,this.pseudoThreadCounter);this.pseudoThreadCounter++;}
+return thread;},markPidRunnable:function(ts,pid,comm,prio,fromPid){this.wakeups_.push({ts:ts,tid:pid,fromTid:fromPid});},addPidBlockedReason:function(ts,pid,iowait,caller){this.blocked_reasons_.push({ts:ts,tid:pid,iowait:iowait,caller:caller});},buildMapFromLinuxPidsToThreads_:function(){this.threadsByLinuxPid={};this.model_.getAllThreads().forEach(function(thread){this.threadsByLinuxPid[thread.tid]=thread;}.bind(this));},buildPerThreadCpuSlicesFromCpuState_:function(){var SCHEDULING_STA [...]
+continue;cpuSlice.threadThatWasRunning=thread;if(!thread.tempCpuSlices)
+thread.tempCpuSlices=[];thread.tempCpuSlices.push(cpuSlice);}}
+for(var i in this.wakeups_){var wakeup=this.wakeups_[i];var thread=this.threadsByLinuxPid[wakeup.tid];if(!thread)
+continue;thread.tempWakeups=thread.tempWakeups||[];thread.tempWakeups.push(wakeup);}
+for(var i in this.blocked_reasons_){var reason=this.blocked_reasons_[i];var thread=this.threadsByLinuxPid[reason.tid];if(!thread)
+continue;thread.tempBlockedReasons=thread.tempBlockedReasons||[];thread.tempBlockedReasons.push(reason);}
+this.model_.getAllThreads().forEach(function(thread){if(thread.tempCpuSlices===undefined)
+return;var origSlices=thread.tempCpuSlices;delete thread.tempCpuSlices;origSlices.sort(function(x,y){return x.start-y.start;});var wakeups=thread.tempWakeups||[];delete thread.tempWakeups;wakeups.sort(function(x,y){return x.ts-y.ts;});var reasons=thread.tempBlockedReasons||[];delete thread.tempBlockedReasons;reasons.sort(function(x,y){return x.ts-y.ts;});var slices=[];if(origSlices.length){var slice=origSlices[0];if(wakeups.length&&wakeups[0].ts<slice.start){var wakeup=wakeups.shift();va [...]
+var runningSlice=new tr.model.ThreadTimeSlice(thread,SCHEDULING_STATE.RUNNING,'',slice.start,{},slice.duration);runningSlice.cpuOnWhichThreadWasRunning=slice.cpu;slices.push(runningSlice);}
+var wakeup=undefined;for(var i=1;i<origSlices.length;i++){var prevSlice=origSlices[i-1];var nextSlice=origSlices[i];var midDuration=nextSlice.start-prevSlice.end;while(wakeups.length&&wakeups[0].ts<nextSlice.start){var w=wakeups.shift();if(wakeup===undefined&&w.ts>prevSlice.end){wakeup=w;}}
+var blocked_reason=undefined;while(reasons.length&&reasons[0].ts<prevSlice.end){var r=reasons.shift();}
+if(wakeup!==undefined&&reasons.length&&reasons[0].ts<wakeup.ts){blocked_reason=reasons.shift();}
+var pushSleep=function(state){if(wakeup!==undefined){midDuration=wakeup.ts-prevSlice.end;}
+if(blocked_reason!==undefined){var args={'kernel callsite when blocked:':blocked_reason.caller};if(blocked_reason.iowait){switch(state){case SCHEDULING_STATE.UNINTR_SLEEP:state=SCHEDULING_STATE.UNINTR_SLEEP_IO;break;case SCHEDULING_STATE.UNINTR_SLEEP_WAKE_KILL:state=SCHEDULING_STATE.UNINTR_SLEEP_WAKE_KILL_IO;break;case SCHEDULING_STATE.UNINTR_SLEEP_WAKING:state=SCHEDULING_STATE.UNINTR_SLEEP_WAKE_KILL_IO;break;default:}}
+slices.push(new tr.model.ThreadTimeSlice(thread,state,'',prevSlice.end,args,midDuration));}else{slices.push(new tr.model.ThreadTimeSlice(thread,state,'',prevSlice.end,{},midDuration));}
+if(wakeup!==undefined){var wakeupDuration=nextSlice.start-wakeup.ts;var args={'wakeup from tid':wakeup.fromTid};slices.push(new tr.model.ThreadTimeSlice(thread,SCHEDULING_STATE.RUNNABLE,'',wakeup.ts,args,wakeupDuration));wakeup=undefined;}};if(prevSlice.args.stateWhenDescheduled=='S'){pushSleep(SCHEDULING_STATE.SLEEPING);}else if(prevSlice.args.stateWhenDescheduled=='R'||prevSlice.args.stateWhenDescheduled=='R+'){slices.push(new tr.model.ThreadTimeSlice(thread,SCHEDULING_STATE.RUNNABLE,' [...]
+prevSlice.args.stateWhenDescheduled});}
+var runningSlice=new tr.model.ThreadTimeSlice(thread,SCHEDULING_STATE.RUNNING,'',nextSlice.start,{},nextSlice.duration);runningSlice.cpuOnWhichThreadWasRunning=prevSlice.cpu;slices.push(runningSlice);}
+thread.timeSlices=slices;},this);},getModelTimeTransformer_:function(){var isAttachedToChromeTrace=this.model.getClockSyncRecordsWithSyncId('ftrace_importer').length!==0;var monotonicSyncs=this.model_.getClockSyncRecordsWithSyncId('ftrace_global_to_monotonic');if(monotonicSyncs.length==0)
+return isAttachedToChromeTrace?undefined:tr.b.identity;var ftraceGlobalTs=monotonicSyncs[0].start;var monotonicTs=monotonicSyncs[0].args.monotonicTs;if(monotonicTs===0)
+return tr.b.identity;return function(ts){return ts+monotonicTs-ftraceGlobalTs;};},createParsers_:function(){var allTypeInfos=tr.e.importer.linux_perf.Parser.getAllRegisteredTypeInfos();var parsers=allTypeInfos.map(function(typeInfo){return new typeInfo.constructor(this);},this);return parsers;},registerDefaultHandlers_:function(){this.registerEventHandler('tracing_mark_write',FTraceImporter.prototype.traceMarkingWriteEvent_.bind(this));this.registerEventHandler('0',FTraceImporter.prototy [...]
+throw new Error('omgbbq');args[parts[0]]=parts[1];}
+this.addClockSyncRecord_(new InstantClockSyncRecord(name,ts,args));return true;}
+event=/parent_ts=(\d+\.?\d*)/.exec(eventBase.details);if(!event)
+return false;var monotonicTs=event[1]*1000;this.addClockSyncRecord_(new InstantClockSyncRecord('ftrace_global_to_monotonic',ts,{monotonicTs:monotonicTs}));return true;},traceMarkingWriteEvent_:function(eventName,cpuNumber,pid,ts,eventBase,threadName){eventBase.details=eventBase.details.replace(/\\n.*$/,'');var event=/^\s*(\w+):\s*(.*)$/.exec(eventBase.details);if(!event){var tag=eventBase.details.substring(0,2);if(tag=='B|'||tag=='E'||tag=='E|'||tag=='X|'||tag=='C|'||tag=='S|'||tag=='F|' [...]
+var writeEventName=eventName+':'+eventBase.subEventName;var handler=this.eventHandlers_[writeEventName];if(!handler){this.model_.importWarning({type:'parse_error',message:'Unknown trace_marking_write event '+writeEventName});return true;}
+return handler(writeEventName,cpuNumber,pid,ts,eventBase,threadName);},importClockSyncRecords_:function(){this.forEachLine_(function(text,eventBase,cpuNumber,pid,ts){var eventName=eventBase.eventName;if(eventName!=='tracing_mark_write'&&eventName!=='0')
+return;if(traceEventClockSyncRE.exec(eventBase.details))
+this.traceClockSyncEvent_(eventName,cpuNumber,pid,ts,eventBase);if(realTimeClockSyncRE.exec(eventBase.details)){var match=realTimeClockSyncRE.exec(eventBase.details);this.model_.realtime_to_monotonic_offset_ms=ts-match[1];}
+if(genericClockSyncRE.exec(eventBase.details))
+this.traceClockSyncEvent_(eventName,cpuNumber,pid,ts,eventBase);}.bind(this));},addClockSyncRecord_:function(csr){this.newlyAddedClockSyncRecords_.push(csr);this.model_.clockSyncRecords.push(csr);},shiftNewlyAddedClockSyncRecords_:function(modelTimeTransformer){this.newlyAddedClockSyncRecords_.forEach(function(csr){csr.start=modelTimeTransformer(csr.start);});},importCpuData_:function(modelTimeTransformer){this.forEachLine_(function(text,eventBase,cpuNumber,pid,ts){var eventName=eventBas [...]
+ts=modelTimeTransformer(ts);if(!handler(eventName,cpuNumber,pid,ts,eventBase)){this.model_.importWarning({type:'parse_error',message:'Malformed '+eventName+' event ('+text+')'});}}.bind(this));},parseLines_:function(){var lines=[];var extractResult=FTraceImporter._extractEventsFromSystraceHTML(this.events_,true);if(!extractResult.ok)
+extractResult=FTraceImporter._extractEventsFromSystraceMultiHTML(this.events_,true);var lines=extractResult.ok?extractResult.lines:this.events_.split('\n');var lineParser=undefined;for(var lineNumber=0;lineNumber<lines.length;++lineNumber){var line=lines[lineNumber].trim();if(line.length==0||/^#/.test(line))
+continue;if(!lineParser){lineParser=autoDetectLineParser(line);if(!lineParser){this.model_.importWarning({type:'parse_error',message:'Cannot parse line: '+line});continue;}}
+var eventBase=lineParser(line);if(!eventBase){this.model_.importWarning({type:'parse_error',message:'Unrecognized line: '+line});continue;}
+this.lines_.push([line,eventBase,parseInt(eventBase.cpuNumber),parseInt(eventBase.pid),parseFloat(eventBase.timestamp)*1000]);}},forEachLine_:function(handler){for(var i=0;i<this.lines_.length;++i){var line=this.lines_[i];handler.apply(this,line);}}};tr.importer.Importer.register(FTraceImporter);return{FTraceImporter:FTraceImporter,_FTraceImporterTestExports:TestExports};});'use strict';tr.exportTo('tr.e.audits',function(){var VSYNC_COUNTER_PRECISIONS={'android.VSYNC-app':15,'android.VSY [...]
+return false;if(title===maxTitle)
+return true;if(precision<=maxPrecision){if(precision===maxPrecision){console.warn('Encountered two different VSync events ('+
+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,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,VSYNC_SLICE_PRECISIONS))
+times.push(slice.start);else if(useInstead(slice.title,BEGIN_FRAME_SLICE_PRECISION)&&slice.args.args&&slice.args.args.frame_time_us)
+times.push(slice.args.args.frame_time_us/1000.0);}}}
+times.sort(function(x,y){return x-y;});return times;}};tr.c.Auditor.register(VSyncAuditor);return{VSyncAuditor:VSyncAuditor};});'use strict';tr.exportTo('tr.importer',function(){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__:tr.importer.Importer.prototype,get importerName(){return'EmptyImporter';}};tr.importer.Importer.register(EmptyImporter);return{EmptyImporter:EmptyImporter};});'use strict';tr.exportTo('tr.model.um',function(){function AnimationExpectation(parentModel,initiatorTitle,start,duration){tr.model.um.UserExpectation.call(this,parentModel,initiatorTitle,start,duration);this.frameEvents_=undefined;}
+AnimationExpectation.prototype={__proto__:tr.model.um.UserExpectation.prototype,constructor:AnimationExpectation,get frameEvents(){if(this.frameEvents_)
+return this.frameEvents_;this.frameEvents_=new tr.model.EventSet();this.associatedEvents.forEach(function(event){if(event.title===tr.model.helpers.IMPL_RENDERING_STATS)
+this.frameEvents_.push(event);},this);return this.frameEvents_;}};tr.model.um.UserExpectation.register(AnimationExpectation,{stageTitle:'Animation',colorId:tr.b.ColorScheme.getColorIdForReservedName('rail_animation')});return{AnimationExpectation:AnimationExpectation};});'use strict';tr.exportTo('tr.importer',function(){function ProtoExpectation(irType,name){this.irType=irType;this.names=new Set(name?[name]:undefined);this.start=Infinity;this.end=-Infinity;this.associatedEvents=new tr.mo [...]
+ProtoExpectation.RESPONSE_TYPE='r';ProtoExpectation.ANIMATION_TYPE='a';ProtoExpectation.IGNORED_TYPE='ignored';ProtoExpectation.prototype={get isValid(){return this.end>this.start;},containsTypeNames:function(typeNames){for(var i=0;i<this.associatedEvents.length;++i){if(typeNames.indexOf(this.associatedEvents[i].typeName)>=0)
+return true;}
+return false;},containsSliceTitle:function(title){for(var i=0;i<this.associatedEvents.length;++i){if(title===this.associatedEvents[i].title)
+return true;}
+return false;},createInteractionRecord:function(model){if(!this.isValid){console.error('Invalid ProtoExpectation: '+this.debug()+' File a bug with this trace!');return undefined;}
+var initiatorTitles=[];this.names.forEach(function(name){initiatorTitles.push(name);});initiatorTitles=initiatorTitles.sort().join(',');var duration=this.end-this.start;var ir=undefined;switch(this.irType){case ProtoExpectation.RESPONSE_TYPE:ir=new tr.model.um.ResponseExpectation(model,initiatorTitles,this.start,duration,this.isAnimationBegin);break;case ProtoExpectation.ANIMATION_TYPE:ir=new tr.model.um.AnimationExpectation(model,initiatorTitles,this.start,duration);break;}
+if(!ir)
+return undefined;ir.sourceEvents.addEventSet(this.associatedEvents);function pushAssociatedEvents(event){ir.associatedEvents.push(event);if(event.associatedEvents)
+ir.associatedEvents.addEventSet(event.associatedEvents);}
+this.associatedEvents.forEach(function(event){pushAssociatedEvents(event);if(event.subSlices)
+event.subSlices.forEach(pushAssociatedEvents);});return ir;},merge:function(other){other.names.forEach(function(name){this.names.add(name);}.bind(this));this.associatedEvents.addEventSet(other.associatedEvents);this.start=Math.min(this.start,other.start);this.end=Math.max(this.end,other.end);if(other.isAnimationBegin)
+this.isAnimationBegin=true;},pushEvent:function(event){this.start=Math.min(this.start,event.start);this.end=Math.max(this.end,event.end);this.associatedEvents.push(event);},containsTimestampInclusive:function(timestamp){return(this.start<=timestamp)&&(timestamp<=this.end);},intersects:function(other){return(other.start<this.end)&&(other.end>this.start);},isNear:function(event,threshold){return(this.end+threshold)>event.start;},debug:function(){var debugString=this.irType+'(';debugString+ [...]
+return x.start-y.start;if(x.end!==y.end)
+return x.end-y.end;if(x.guid&&y.guid)
+return x.guid-y.guid;return 0;}
+function forEventTypesIn(events,typeNames,cb,opt_this){events.forEach(function(event){if(typeNames.indexOf(event.typeName)>=0){cb.call(opt_this,event);}});}
+function causedFrame(event){for(var i=0;i<event.associatedEvents.length;++i){if(event.associatedEvents[i].title===tr.model.helpers.IMPL_RENDERING_STATS)
+return true;}
+return false;}
+function getSortedInputEvents(modelHelper){var inputEvents=[];var browserProcess=modelHelper.browserHelper.process;var mainThread=browserProcess.findAtMostOneThreadNamed('CrBrowserMain');mainThread.asyncSliceGroup.iterateAllEvents(function(slice){if(!slice.isTopLevel)
+return;if(!(slice instanceof tr.e.cc.InputLatencyAsyncSlice))
+return;if(isNaN(slice.start)||isNaN(slice.duration)||isNaN(slice.end))
+return;inputEvents.push(slice);});return inputEvents.sort(compareEvents);}
+function findProtoExpectations(modelHelper,sortedInputEvents){var protoExpectations=[];var handlers=[handleKeyboardEvents,handleMouseResponseEvents,handleMouseWheelEvents,handleMouseDragEvents,handleTapResponseEvents,handlePinchEvents,handleFlingEvents,handleTouchEvents,handleScrollEvents,handleCSSAnimations];handlers.forEach(function(handler){protoExpectations.push.apply(protoExpectations,handler(modelHelper,sortedInputEvents));});protoExpectations.sort(compareEvents);return protoExpect [...]
+function handleKeyboardEvents(modelHelper,sortedInputEvents){var protoExpectations=[];forEventTypesIn(sortedInputEvents,KEYBOARD_TYPE_NAMES,function(event){var pe=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,KEYBOARD_IR_NAME);pe.pushEvent(event);protoExpectations.push(pe);});return protoExpectations;}
+function handleMouseResponseEvents(modelHelper,sortedInputEvents){var protoExpectations=[];forEventTypesIn(sortedInputEvents,MOUSE_RESPONSE_TYPE_NAMES,function(event){var pe=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,MOUSE_IR_NAME);pe.pushEvent(event);protoExpectations.push(pe);});return protoExpectations;}
+function handleMouseWheelEvents(modelHelper,sortedInputEvents){var protoExpectations=[];var currentPE=undefined;var prevEvent_=undefined;forEventTypesIn(sortedInputEvents,MOUSE_WHEEL_TYPE_NAMES,function(event){var prevEvent=prevEvent_;prevEvent_=event;if(currentPE&&(prevEvent.start+MOUSE_WHEEL_THRESHOLD_MS)>=event.start){if(currentPE.irType===ProtoExpectation.ANIMATION_TYPE){currentPE.pushEvent(event);}else{currentPE=new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,MOUSEWHEEL_IR_NAME [...]
+return;}
+currentPE=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,MOUSEWHEEL_IR_NAME);currentPE.pushEvent(event);protoExpectations.push(currentPE);});return protoExpectations;}
+function handleMouseDragEvents(modelHelper,sortedInputEvents){var protoExpectations=[];var currentPE=undefined;var mouseDownEvent=undefined;forEventTypesIn(sortedInputEvents,MOUSE_DRAG_TYPE_NAMES,function(event){switch(event.typeName){case INPUT_TYPE.MOUSE_DOWN:if(causedFrame(event)){var pe=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,MOUSE_IR_NAME);pe.pushEvent(event);protoExpectations.push(pe);}else{mouseDownEvent=event;}
+break;case INPUT_TYPE.MOUSE_MOVE:if(!causedFrame(event)){var pe=new ProtoExpectation(ProtoExpectation.IGNORED_TYPE);pe.pushEvent(event);protoExpectations.push(pe);}else if(!currentPE||!currentPE.isNear(event,MOUSE_MOVE_THRESHOLD_MS)){currentPE=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,MOUSE_IR_NAME);currentPE.pushEvent(event);if(mouseDownEvent){currentPE.associatedEvents.push(mouseDownEvent);mouseDownEvent=undefined;}
+protoExpectations.push(currentPE);}else{if(currentPE.irType===ProtoExpectation.ANIMATION_TYPE){currentPE.pushEvent(event);}else{currentPE=new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,MOUSE_IR_NAME);currentPE.pushEvent(event);protoExpectations.push(currentPE);}}
+break;case INPUT_TYPE.MOUSE_UP:if(!mouseDownEvent){var pe=new ProtoExpectation(causedFrame(event)?ProtoExpectation.RESPONSE_TYPE:ProtoExpectation.IGNORED_TYPE,MOUSE_IR_NAME);pe.pushEvent(event);protoExpectations.push(pe);break;}
+if(currentPE){currentPE.pushEvent(event);}else{currentPE=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,MOUSE_IR_NAME);if(mouseDownEvent)
+currentPE.associatedEvents.push(mouseDownEvent);currentPE.pushEvent(event);protoExpectations.push(currentPE);}
+mouseDownEvent=undefined;currentPE=undefined;break;}});if(mouseDownEvent){currentPE=new ProtoExpectation(ProtoExpectation.IGNORED_TYPE);currentPE.pushEvent(mouseDownEvent);protoExpectations.push(currentPE);}
+return protoExpectations;}
+function handleTapResponseEvents(modelHelper,sortedInputEvents){var protoExpectations=[];var currentPE=undefined;forEventTypesIn(sortedInputEvents,TAP_TYPE_NAMES,function(event){switch(event.typeName){case INPUT_TYPE.TAP_DOWN:currentPE=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,TAP_IR_NAME);currentPE.pushEvent(event);protoExpectations.push(currentPE);break;case INPUT_TYPE.TAP:if(currentPE){currentPE.pushEvent(event);}else{currentPE=new ProtoExpectation(ProtoExpectation.RESPONSE_ [...]
+currentPE=undefined;break;case INPUT_TYPE.TAP_CANCEL:if(!currentPE){var pe=new ProtoExpectation(ProtoExpectation.IGNORED_TYPE);pe.pushEvent(event);protoExpectations.push(pe);break;}
+if(currentPE.isNear(event,INPUT_MERGE_THRESHOLD_MS)){currentPE.pushEvent(event);}else{currentPE=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,TAP_IR_NAME);currentPE.pushEvent(event);protoExpectations.push(currentPE);}
+currentPE=undefined;break;}});return protoExpectations;}
+function handlePinchEvents(modelHelper,sortedInputEvents){var protoExpectations=[];var currentPE=undefined;var sawFirstUpdate=false;var modelBounds=modelHelper.model.bounds;forEventTypesIn(sortedInputEvents,PINCH_TYPE_NAMES,function(event){switch(event.typeName){case INPUT_TYPE.PINCH_BEGIN:if(currentPE&&currentPE.isNear(event,INPUT_MERGE_THRESHOLD_MS)){currentPE.pushEvent(event);break;}
+currentPE=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,PINCH_IR_NAME);currentPE.pushEvent(event);currentPE.isAnimationBegin=true;protoExpectations.push(currentPE);sawFirstUpdate=false;break;case INPUT_TYPE.PINCH_UPDATE:if(!currentPE||((currentPE.irType===ProtoExpectation.RESPONSE_TYPE)&&sawFirstUpdate)||!currentPE.isNear(event,INPUT_MERGE_THRESHOLD_MS)){currentPE=new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,PINCH_IR_NAME);currentPE.pushEvent(event);protoExpectations.push(c [...]
+break;case INPUT_TYPE.PINCH_END:if(currentPE){currentPE.pushEvent(event);}else{var pe=new ProtoExpectation(ProtoExpectation.IGNORED_TYPE);pe.pushEvent(event);protoExpectations.push(pe);}
+currentPE=undefined;break;}});return protoExpectations;}
+function handleFlingEvents(modelHelper,sortedInputEvents){var protoExpectations=[];var currentPE=undefined;function isRendererFling(event){return event.title===RENDERER_FLING_TITLE;}
+var browserHelper=modelHelper.browserHelper;var flingEvents=browserHelper.getAllAsyncSlicesMatching(isRendererFling);forEventTypesIn(sortedInputEvents,FLING_TYPE_NAMES,function(event){flingEvents.push(event);});flingEvents.sort(compareEvents);flingEvents.forEach(function(event){if(event.title===RENDERER_FLING_TITLE){if(currentPE){currentPE.pushEvent(event);}else{currentPE=new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,FLING_IR_NAME);currentPE.pushEvent(event);protoExpectations.push [...]
+return;}
+switch(event.typeName){case INPUT_TYPE.FLING_START:if(currentPE){console.error('Another FlingStart? File a bug with this trace!');currentPE.pushEvent(event);}else{currentPE=new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,FLING_IR_NAME);currentPE.pushEvent(event);currentPE.end=0;protoExpectations.push(currentPE);}
+break;case INPUT_TYPE.FLING_CANCEL:if(currentPE){currentPE.pushEvent(event);currentPE.end=event.start;currentPE=undefined;}else{var pe=new ProtoExpectation(ProtoExpectation.IGNORED_TYPE);pe.pushEvent(event);protoExpectations.push(pe);}
+break;}});if(currentPE&&!currentPE.end)
+currentPE.end=modelHelper.model.bounds.max;return protoExpectations;}
+function handleTouchEvents(modelHelper,sortedInputEvents){var protoExpectations=[];var currentPE=undefined;var sawFirstMove=false;forEventTypesIn(sortedInputEvents,TOUCH_TYPE_NAMES,function(event){switch(event.typeName){case INPUT_TYPE.TOUCH_START:if(currentPE){currentPE.pushEvent(event);}else{currentPE=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,TOUCH_IR_NAME);currentPE.pushEvent(event);currentPE.isAnimationBegin=true;protoExpectations.push(currentPE);sawFirstMove=false;}
+break;case INPUT_TYPE.TOUCH_MOVE:if(!currentPE){currentPE=new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,TOUCH_IR_NAME);currentPE.pushEvent(event);protoExpectations.push(currentPE);break;}
+if((sawFirstMove&&(currentPE.irType===ProtoExpectation.RESPONSE_TYPE))||!currentPE.isNear(event,INPUT_MERGE_THRESHOLD_MS)){var prevEnd=currentPE.end;currentPE=new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,TOUCH_IR_NAME);currentPE.pushEvent(event);currentPE.start=prevEnd;protoExpectations.push(currentPE);}else{currentPE.pushEvent(event);sawFirstMove=true;}
+break;case INPUT_TYPE.TOUCH_END:if(!currentPE){var pe=new ProtoExpectation(ProtoExpectation.IGNORED_TYPE);pe.pushEvent(event);protoExpectations.push(pe);break;}
+if(currentPE.isNear(event,INPUT_MERGE_THRESHOLD_MS)){currentPE.pushEvent(event);}else{var pe=new ProtoExpectation(ProtoExpectation.IGNORED_TYPE);pe.pushEvent(event);protoExpectations.push(pe);}
+currentPE=undefined;break;}});return protoExpectations;}
+function handleScrollEvents(modelHelper,sortedInputEvents){var protoExpectations=[];var currentPE=undefined;var sawFirstUpdate=false;forEventTypesIn(sortedInputEvents,SCROLL_TYPE_NAMES,function(event){switch(event.typeName){case INPUT_TYPE.SCROLL_BEGIN:currentPE=new ProtoExpectation(ProtoExpectation.RESPONSE_TYPE,SCROLL_IR_NAME);currentPE.pushEvent(event);currentPE.isAnimationBegin=true;protoExpectations.push(currentPE);sawFirstUpdate=false;break;case INPUT_TYPE.SCROLL_UPDATE:if(currentP [...]
+break;case INPUT_TYPE.SCROLL_END:if(!currentPE){console.error('ScrollEnd without ScrollUpdate? '+'File a bug with this trace!');var pe=new ProtoExpectation(ProtoExpectation.IGNORED_TYPE);pe.pushEvent(event);protoExpectations.push(pe);break;}
+currentPE.pushEvent(event);break;}});return protoExpectations;}
+function handleCSSAnimations(modelHelper,sortedInputEvents){var animationEvents=modelHelper.browserHelper.getAllAsyncSlicesMatching(function(event){return((event.title===CSS_ANIMATION_TITLE)&&event.isTopLevel&&(event.duration>0));});var framesForProcess={};function getFramesForAnimationProcess(animation){var frames=framesForProcess[animation.parentContainer.parent.guid];if(frames===undefined){var rendererHelper=new tr.model.helpers.ChromeRendererHelper(modelHelper,animation.parentContain [...]
+return frames;}
+var animationRanges=[];function pushAnimationRange(start,end,animation){var range=tr.b.Range.fromExplicitRange(start,end);range.animation=animation;range.frames=range.filterArray(getFramesForAnimationProcess(animation),function(frameEvent){return frameEvent.start;});if(range.frames.length===0)
+return;animationRanges.push(range);}
+animationEvents.forEach(function(animation){if(animation.subSlices.length===0){pushAnimationRange(animation.start,animation.end,animation);}else{var start=undefined;animation.subSlices.forEach(function(sub){if((sub.args.state==='running')&&(start===undefined)){start=sub.start;}else if((sub.args.state==='paused')||(sub.args.state==='idle')||(sub.args.state==='finished')){if(start===undefined){start=modelHelper.model.bounds.min;}
+pushAnimationRange(start,sub.start,animation);start=undefined;}});if(start!==undefined)
+pushAnimationRange(start,modelHelper.model.bounds.max,animation);}});function merge(ranges){var protoExpectation=new ProtoExpectation(ProtoExpectation.ANIMATION_TYPE,CSS_IR_NAME);ranges.forEach(function(range){protoExpectation.start=Math.min(protoExpectation.start,range.min);protoExpectation.end=Math.max(protoExpectation.end,range.max);protoExpectation.associatedEvents.push(range.animation);protoExpectation.associatedEvents.addEventSet(range.frames);});return protoExpectation;}
+return tr.b.mergeRanges(animationRanges,ANIMATION_MERGE_THRESHOLD_MS,merge);}
+function postProcessProtoExpectations(protoExpectations){protoExpectations=mergeIntersectingResponses(protoExpectations);protoExpectations=mergeIntersectingAnimations(protoExpectations);protoExpectations=fixResponseAnimationStarts(protoExpectations);protoExpectations=fixTapResponseTouchAnimations(protoExpectations);return protoExpectations;}
+function mergeIntersectingResponses(protoExpectations){var newPEs=[];while(protoExpectations.length){var pe=protoExpectations.shift();newPEs.push(pe);if(pe.irType!==ProtoExpectation.RESPONSE_TYPE)
+continue;for(var i=0;i<protoExpectations.length;++i){var otherPE=protoExpectations[i];if(otherPE.irType!==pe.irType)
+continue;if(!otherPE.intersects(pe))
+continue;var typeNames=pe.associatedEvents.map(function(event){return event.typeName;});if(otherPE.containsTypeNames(typeNames))
+continue;pe.merge(otherPE);protoExpectations.splice(i,1);--i;}}
+return newPEs;}
+function mergeIntersectingAnimations(protoExpectations){var newPEs=[];while(protoExpectations.length){var pe=protoExpectations.shift();newPEs.push(pe);if(pe.irType!==ProtoExpectation.ANIMATION_TYPE)
+continue;var isCSS=pe.containsSliceTitle(CSS_ANIMATION_TITLE);var isFling=pe.containsTypeNames([INPUT_TYPE.FLING_START]);for(var i=0;i<protoExpectations.length;++i){var otherPE=protoExpectations[i];if(otherPE.irType!==pe.irType)
+continue;if(isCSS!=otherPE.containsSliceTitle(CSS_ANIMATION_TITLE))
+continue;if(!otherPE.intersects(pe))
+continue;if(isFling!=otherPE.containsTypeNames([INPUT_TYPE.FLING_START]))
+continue;pe.merge(otherPE);protoExpectations.splice(i,1);--i;}}
+return newPEs;}
+function fixResponseAnimationStarts(protoExpectations){protoExpectations.forEach(function(ape){if(ape.irType!==ProtoExpectation.ANIMATION_TYPE)
+return;protoExpectations.forEach(function(rpe){if(rpe.irType!==ProtoExpectation.RESPONSE_TYPE)
+return;if(!ape.containsTimestampInclusive(rpe.end))
+return;if(ape.containsTimestampInclusive(rpe.start))
+return;ape.start=rpe.end;});});return protoExpectations;}
+function fixTapResponseTouchAnimations(protoExpectations){function isTapResponse(pe){return(pe.irType===ProtoExpectation.RESPONSE_TYPE)&&pe.containsTypeNames([INPUT_TYPE.TAP]);}
+function isTouchAnimation(pe){return(pe.irType===ProtoExpectation.ANIMATION_TYPE)&&pe.containsTypeNames([INPUT_TYPE.TOUCH_MOVE])&&!pe.containsTypeNames([INPUT_TYPE.SCROLL_UPDATE,INPUT_TYPE.PINCH_UPDATE]);}
+var newPEs=[];while(protoExpectations.length){var pe=protoExpectations.shift();newPEs.push(pe);var peIsTapResponse=isTapResponse(pe);var peIsTouchAnimation=isTouchAnimation(pe);if(!peIsTapResponse&&!peIsTouchAnimation)
+continue;for(var i=0;i<protoExpectations.length;++i){var otherPE=protoExpectations[i];if(!otherPE.intersects(pe))
+continue;if(peIsTapResponse&&!isTouchAnimation(otherPE))
+continue;if(peIsTouchAnimation&&!isTapResponse(otherPE))
+continue;pe.irType=ProtoExpectation.RESPONSE_TYPE;pe.merge(otherPE);protoExpectations.splice(i,1);--i;}}
+return newPEs;}
+function checkAllInputEventsHandled(sortedInputEvents,protoExpectations){var handledEvents=[];protoExpectations.forEach(function(protoExpectation){protoExpectation.associatedEvents.forEach(function(event){if((event.title===CSS_ANIMATION_TITLE)&&(event.subSlices.length>0))
+return;if(handledEvents.indexOf(event)>=0){console.error('double-handled event',event.typeName,parseInt(event.start),parseInt(event.end),protoExpectation);return;}
+handledEvents.push(event);});});sortedInputEvents.forEach(function(event){if(handledEvents.indexOf(event)<0){console.error('UNHANDLED INPUT EVENT!',event.typeName,parseInt(event.start),parseInt(event.end));}});}
+function findInputExpectations(modelHelper){var sortedInputEvents=getSortedInputEvents(modelHelper);var protoExpectations=findProtoExpectations(modelHelper,sortedInputEvents);protoExpectations=postProcessProtoExpectations(protoExpectations);checkAllInputEventsHandled(sortedInputEvents,protoExpectations);var irs=[];protoExpectations.forEach(function(protoExpectation){var ir=protoExpectation.createInteractionRecord(modelHelper.model);if(ir)
+irs.push(ir);});return irs;}
+return{findInputExpectations:findInputExpectations,compareEvents:compareEvents,CSS_ANIMATION_TITLE:CSS_ANIMATION_TITLE};});'use strict';tr.exportTo('tr.model.um',function(){var LOAD_SUBTYPE_NAMES={SUCCESSFUL:'Successful',FAILED:'Failed',STARTUP:'Startup'};var DOES_LOAD_SUBTYPE_NAME_EXIST={};for(var key in LOAD_SUBTYPE_NAMES){DOES_LOAD_SUBTYPE_NAME_EXIST[LOAD_SUBTYPE_NAMES[key]]=true;;}
+function LoadExpectation(parentModel,initiatorTitle,start,duration){if(!DOES_LOAD_SUBTYPE_NAME_EXIST[initiatorTitle])
+throw new Error(initiatorTitle+' is not in LOAD_SUBTYPE_NAMES');tr.model.um.UserExpectation.call(this,parentModel,initiatorTitle,start,duration);this.renderProcess=undefined;this.renderMainThread=undefined;this.routingId=undefined;this.parentRoutingId=undefined;this.loadFinishedEvent=undefined;}
+LoadExpectation.prototype={__proto__:tr.model.um.UserExpectation.prototype,constructor:LoadExpectation};tr.model.um.UserExpectation.register(LoadExpectation,{stageTitle:'Load',colorId:tr.b.ColorScheme.getColorIdForReservedName('rail_load')});return{LOAD_SUBTYPE_NAMES:LOAD_SUBTYPE_NAMES,LoadExpectation:LoadExpectation};});'use strict';tr.exportTo('tr.importer',function(){var NAVIGATION_START='NavigationTiming navigationStart';var FIRST_CONTENTFUL_PAINT_TITLE='firstContentfulPaint';functio [...]
+function getStartupEvents(modelHelper){function isStartupSlice(slice){return slice.title==='BrowserMainLoop::CreateThreads';}
+var events=modelHelper.browserHelper.getAllAsyncSlicesMatching(isStartupSlice);var deduper=new tr.model.EventSet();events.forEach(function(event){var sliceGroup=event.parentContainer.sliceGroup;var slice=sliceGroup&&sliceGroup.findFirstSlice();if(slice)
+deduper.push(slice);});return deduper.toArray();}
+function findLoadExpectationsInternal(modelHelper,subtypeName,openingEvents,closingEvents){var loads=[];openingEvents.forEach(function(openingEvent){closingEvents.forEach(function(closingEvent){if(openingEvent.closingEvent)
+return;if(closingEvent.openingEvent)
+return;if(closingEvent.start<=openingEvent.start)
+return;if(openingEvent.parentContainer.parent.pid!==closingEvent.parentContainer.parent.pid)
+return;openingEvent.closingEvent=closingEvent;closingEvent.openingEvent=openingEvent;var lir=new tr.model.um.LoadExpectation(modelHelper.model,subtypeName,openingEvent.start,closingEvent.end-openingEvent.start);lir.associatedEvents.push(openingEvent);lir.associatedEvents.push(closingEvent);loads.push(lir);});});return loads;}
+function findRenderLoadExpectations(modelHelper){var events=[];modelHelper.model.iterateAllEvents(function(event){if((event.title===NAVIGATION_START)||(event.title===FIRST_CONTENTFUL_PAINT_TITLE))
+events.push(event);});events.sort(tr.importer.compareEvents);var loads=[];var startEvent=undefined;events.forEach(function(event){if(event.title===NAVIGATION_START){startEvent=event;}else if(event.title===FIRST_CONTENTFUL_PAINT_TITLE){if(startEvent){loads.push(new tr.model.um.LoadExpectation(modelHelper.model,tr.model.um.LOAD_SUBTYPE_NAMES.SUCCESSFUL,startEvent.start,event.start-startEvent.start));startEvent=undefined;}}});if(startEvent){loads.push(new tr.model.um.LoadExpectation(modelHe [...]
+return loads;}
+function findLoadExpectations(modelHelper){var loads=[];var commitLoadEvents=modelHelper.browserHelper.getCommitProvisionalLoadEventsInRange(modelHelper.model.bounds);var startupEvents=getStartupEvents(modelHelper);var frameEvents=getAllFrameEvents(modelHelper);var startupLoads=findLoadExpectationsInternal(modelHelper,tr.model.um.LOAD_SUBTYPE_NAMES.STARTUP,startupEvents,frameEvents);loads.push.apply(loads,startupLoads);loads.push.apply(loads,findRenderLoadExpectations(modelHelper));retur [...]
+return{findLoadExpectations:findLoadExpectations};});'use strict';tr.exportTo('tr.model',function(){function getAssociatedEvents(irs){var allAssociatedEvents=new tr.model.EventSet();irs.forEach(function(ir){ir.associatedEvents.forEach(function(event){if(event instanceof tr.model.FlowEvent)
+return;allAssociatedEvents.push(event);});});return allAssociatedEvents;}
+function getUnassociatedEvents(model,associatedEvents){var unassociatedEvents=new tr.model.EventSet();model.getAllProcesses().forEach(function(process){for(var tid in process.threads){var thread=process.threads[tid];thread.sliceGroup.iterateAllEvents(function(event){if(!associatedEvents.contains(event))
+unassociatedEvents.push(event);});}});return unassociatedEvents;}
+function getTotalCpuDuration(events){var cpuMs=0;events.forEach(function(event){if(event.cpuSelfTime)
+cpuMs+=event.cpuSelfTime;});return cpuMs;}
+function getIRCoverageFromModel(model){var associatedEvents=getAssociatedEvents(model.userModel.expectations);if(!associatedEvents.length)
+return undefined;var unassociatedEvents=getUnassociatedEvents(model,associatedEvents);var associatedCpuMs=getTotalCpuDuration(associatedEvents);var unassociatedCpuMs=getTotalCpuDuration(unassociatedEvents);var totalEventCount=associatedEvents.length+unassociatedEvents.length;var totalCpuMs=associatedCpuMs+unassociatedCpuMs;var coveredEventsCpuTimeRatio=undefined;if(totalCpuMs!==0)
+coveredEventsCpuTimeRatio=associatedCpuMs/totalCpuMs;return{associatedEventsCount:associatedEvents.length,unassociatedEventsCount:unassociatedEvents.length,associatedEventsCpuTimeMs:associatedCpuMs,unassociatedEventsCpuTimeMs:unassociatedCpuMs,coveredEventsCountRatio:associatedEvents.length/totalEventCount,coveredEventsCpuTimeRatio:coveredEventsCpuTimeRatio};}
+return{getIRCoverageFromModel:getIRCoverageFromModel,getAssociatedEvents:getAssociatedEvents,getUnassociatedEvents:getUnassociatedEvents};});'use strict';tr.exportTo('tr.model.um',function(){function IdleExpectation(parentModel,start,duration){var initiatorTitle='';tr.model.um.UserExpectation.call(this,parentModel,initiatorTitle,start,duration);}
+IdleExpectation.prototype={__proto__:tr.model.um.UserExpectation.prototype,constructor:IdleExpectation};tr.model.um.UserExpectation.register(IdleExpectation,{stageTitle:'Idle',colorId:tr.b.ColorScheme.getColorIdForReservedName('rail_idle')});return{IdleExpectation:IdleExpectation};});'use strict';tr.exportTo('tr.importer',function(){var INSIGNIFICANT_MS=1;function UserModelBuilder(model){this.model=model;this.modelHelper=model.getOrCreateHelper(tr.model.helpers.ChromeModelHelper);};UserM [...]
+return;var expectations=undefined;try{expectations=this.findUserExpectations();}catch(error){this.model.importWarning({type:'UserModelBuilder',message:error,showToUser:true});return;}
+expectations.forEach(function(expectation){this.model.userModel.expectations.push(expectation);},this);},findUserExpectations:function(){var expectations=[];expectations.push.apply(expectations,tr.importer.findLoadExpectations(this.modelHelper));expectations.push.apply(expectations,tr.importer.findInputExpectations(this.modelHelper));expectations.push.apply(expectations,this.findIdleExpectations(expectations));this.collectUnassociatedEvents_(expectations);return expectations;},collectUna [...]
+vacuumIRs.push(ir);});if(vacuumIRs.length===0)
+return;var allAssociatedEvents=tr.model.getAssociatedEvents(rirs);var unassociatedEvents=tr.model.getUnassociatedEvents(this.model,allAssociatedEvents);unassociatedEvents.forEach(function(event){if(!(event instanceof tr.model.ThreadSlice))
+return;if(!event.isTopLevel)
+return;for(var iri=0;iri<vacuumIRs.length;++iri){var ir=vacuumIRs[iri];if((event.start>=ir.start)&&(event.start<ir.end)){ir.associatedEvents.addEventSet(event.entireHierarchy);return;}}});},findIdleExpectations:function(otherIRs){if(this.model.bounds.isEmpty)
+return;var emptyRanges=tr.b.findEmptyRangesBetweenRanges(tr.b.convertEventsToRanges(otherIRs),this.model.bounds);var irs=[];var model=this.model;emptyRanges.forEach(function(range){if(range.max<(range.min+INSIGNIFICANT_MS))
+return;irs.push(new tr.model.um.IdleExpectation(model,range.min,range.max-range.min));});return irs;}};function createCustomizeModelLinesFromModel(model){var modelLines=[];modelLines.push('      audits.addEvent(model.browserMain,');modelLines.push('          {title: \'model start\', start: 0, end: 1});');var typeNames={};for(var typeName in tr.e.cc.INPUT_EVENT_TYPE_NAMES){typeNames[tr.e.cc.INPUT_EVENT_TYPE_NAMES[typeName]]=typeName;}
+var modelEvents=new tr.model.EventSet();model.userModel.expectations.forEach(function(ir,index){modelEvents.addEventSet(ir.sourceEvents);});modelEvents=modelEvents.toArray();modelEvents.sort(tr.importer.compareEvents);modelEvents.forEach(function(event){var startAndEnd='start: '+parseInt(event.start)+', '+'end: '+parseInt(event.end)+'});';if(event instanceof tr.e.cc.InputLatencyAsyncSlice){modelLines.push('      audits.addInputEvent(model, INPUT_TYPE.'+
+typeNames[event.typeName]+',');}else if(event.title==='RenderFrameImpl::didCommitProvisionalLoad'){modelLines.push('      audits.addCommitLoadEvent(model,');}else if(event.title==='InputHandlerProxy::HandleGestureFling::started'){modelLines.push('      audits.addFlingAnimationEvent(model,');}else if(event.title===tr.model.helpers.IMPL_RENDERING_STATS){modelLines.push('      audits.addFrameEvent(model,');}else if(event.title===tr.importer.CSS_ANIMATION_TITLE){modelLines.push('      audits [...]
+modelLines.push('          {'+startAndEnd);});modelLines.push('      audits.addEvent(model.browserMain,');modelLines.push('          {'+'title: \'model end\', '+'start: '+(parseInt(model.bounds.max)-1)+', '+'end: '+parseInt(model.bounds.max)+'});');return modelLines;}
+function createExpectedIRLinesFromModel(model){var expectedLines=[];var irCount=model.userModel.expectations.length;model.userModel.expectations.forEach(function(ir,index){var irString='      {';irString+='title: \''+ir.title+'\', ';irString+='start: '+parseInt(ir.start)+', ';irString+='end: '+parseInt(ir.end)+', ';irString+='eventCount: '+ir.sourceEvents.length;irString+='}';if(index<(irCount-1))
+irString+=',';expectedLines.push(irString);});return expectedLines;}
+function createIRFinderTestCaseStringFromModel(model){var filename=window.location.hash.substr(1);var testName=filename.substr(filename.lastIndexOf('/')+1);testName=testName.substr(0,testName.indexOf('.'));try{var testLines=[];testLines.push('  /*');testLines.push('    This test was generated from');testLines.push('    '+filename+'');testLines.push('   */');testLines.push('  test(\''+testName+'\', function() {');testLines.push('    var verifier = new UserExpectationVerifier();');testLine [...]
+return{UserModelBuilder:UserModelBuilder,createIRFinderTestCaseStringFromModel:createIRFinderTestCaseStringFromModel};});'use strict';tr.exportTo('tr.importer',function(){var Timing=tr.b.Timing;function ImportOptions(){this.shiftWorldToZero=true;this.pruneEmptyContainers=true;this.showImportWarnings=true;this.trackDetailedModelStats=false;this.customizeModelCallback=undefined;var auditorTypes=tr.c.Auditor.getAllRegisteredTypeInfos();this.auditorConstructors=auditorTypes.map(function(type [...]
+function Import(model,opt_options){if(model===undefined)
+throw new Error('Must provide model to import into.');this.importing_=false;this.importOptions_=opt_options||new ImportOptions();this.model_=model;this.model_.importOptions=this.importOptions_;}
+Import.prototype={__proto__:Object.prototype,importTraces:function(traces){var progressMeter={update:function(msg){}};tr.b.Task.RunSynchronously(this.createImportTracesTask(progressMeter,traces));},importTracesWithProgressDialog:function(traces){if(tr.isHeadless)
+throw new Error('Cannot use this method in headless mode.');var overlay=tr.ui.b.Overlay();overlay.title='Importing...';overlay.userCanClose=false;overlay.msgEl=document.createElement('div');overlay.appendChild(overlay.msgEl);overlay.msgEl.style.margin='20px';overlay.update=function(msg){this.msgEl.textContent=msg;};overlay.visible=true;var promise=tr.b.Task.RunWhenIdle(this.createImportTracesTask(overlay,traces));promise.then(function(){overlay.visible=false;},function(err){overlay.visib [...]
+throw new Error('Already importing.');this.importing_=true;var importTask=new tr.b.Task(function prepareImport(){progressMeter.update('I will now import your traces for you...');},this);var lastTask=importTask;var importers=[];lastTask=lastTask.timedAfter('TraceImport',function createImports(){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.timedAfter('TraceImport',function importClockSyncMarkers(task){importers.forEach(function(importer,index){task.subTask(Timing.wrapNamedFunction('TraceImport',importer.importerName,function runImportClockSyncMarkersOnOneImporter(){progressMeter.update('Importing clock sync markers '+(index+1)+' of '+
+importers.length);importer.importClockSyncMarkers();}),this);},this);},this);lastTask=lastTask.timedAfter('TraceImport',function runImport(task){importers.forEach(function(importer,index){task.subTask(Timing.wrapNamedFunction('TraceImport',importer.importerName,function runImportEventsOnOneImporter(){progressMeter.update('Importing '+(index+1)+' of '+importers.length);importer.importEvents();}),this);},this);},this);if(this.importOptions_.customizeModelCallback){lastTask=lastTask.timedAf [...]
+lastTask=lastTask.timedAfter('TraceImport',function importSampleData(task){importers.forEach(function(importer,index){progressMeter.update('Importing sample data '+(index+1)+'/'+importers.length);importer.importSampleData();},this);},this);lastTask=lastTask.timedAfter('TraceImport',function runAutoclosers(){progressMeter.update('Autoclosing open slices...');this.model_.autoCloseOpenSlices();this.model_.createSubSlices();},this);lastTask=lastTask.timedAfter('TraceImport',function finalize [...]
+lastTask=lastTask.timedAfter('TraceImport',function runMergeKernelWithuserland(){progressMeter.update('Merging kernel with userland...');this.model_.mergeKernelWithUserland();},this);var auditors=[];lastTask=lastTask.timedAfter('TraceImport',function createAuditorsAndRunAnnotate(){progressMeter.update('Adding arbitrary data to model...');auditors=this.importOptions_.auditorConstructors.map(function(auditorConstructor){return new auditorConstructor(this.model_);},this);auditors.forEach(fu [...]
+return new importerConstructor(this.model_,eventData);},hasEventDataDecoder_:function(importers){for(var i=0;i<importers.length;++i){if(!importers[i].isTraceDataContainer())
+return true;}
+return false;}};return{ImportOptions:ImportOptions,Import:Import};});'use strict';tr.exportTo('tr.e.cc',function(){function PictureAsImageData(picture,errorOrImageData){this.picture_=picture;if(errorOrImageData instanceof ImageData){this.error_=undefined;this.imageData_=errorOrImageData;}else{this.error_=errorOrImageData;this.imageData_=undefined;}};PictureAsImageData.Pending=function(picture){return new PictureAsImageData(picture,undefined);};PictureAsImageData.prototype={get picture(){ [...]
+return;var canvas=document.createElement('canvas');var ctx=canvas.getContext('2d');canvas.width=this.imageData_.width;canvas.height=this.imageData_.height;ctx.putImageData(this.imageData_,0,0);return canvas;}};return{PictureAsImageData:PictureAsImageData};});'use strict';tr.exportTo('tr.e.cc',function(){var convertedNameCache={};function convertNameToJSConvention(name){if(name in convertedNameCache)
+return convertedNameCache[name];if(name[0]=='_'||name[name.length-1]=='_'){convertedNameCache[name]=name;return name;}
+var words=name.split('_');if(words.length==1){convertedNameCache[name]=words[0];return words[0];}
+for(var i=1;i<words.length;i++)
+words[i]=words[i][0].toUpperCase()+words[i].substring(1);convertedNameCache[name]=words.join('');return convertedNameCache[name];}
+function convertObjectFieldNamesToJSConventions(object){tr.b.iterObjectFieldsRecursively(object,function(object,fieldName,fieldValue){delete object[fieldName];object[newFieldName]=fieldValue;return newFieldName;});}
+function convertQuadSuffixedTypesToQuads(object){tr.b.iterObjectFieldsRecursively(object,function(object,fieldName,fieldValue){});}
+function convertObject(object){convertObjectFieldNamesToJSConventions(object);convertQuadSuffixedTypesToQuads(object);}
+function moveRequiredFieldsFromArgsToToplevel(object,fields){for(var i=0;i<fields.length;i++){var key=fields[i];if(object.args[key]===undefined)
+throw Error('Expected field '+key+' not found in args');if(object[key]!==undefined)
+throw Error('Field '+key+' already in object');object[key]=object.args[key];delete object.args[key];}}
+function moveOptionalFieldsFromArgsToToplevel(object,fields){for(var i=0;i<fields.length;i++){var key=fields[i];if(object.args[key]===undefined)
+continue;if(object[key]!==undefined)
+throw Error('Field '+key+' already in object');object[key]=object.args[key];delete object.args[key];}}
+function preInitializeObject(object){preInitializeObjectInner(object.args,false);}
+function preInitializeObjectInner(object,hasRecursed){if(!(object instanceof Object))
+return;if(object instanceof Array){for(var i=0;i<object.length;i++)
+preInitializeObjectInner(object[i],true);return;}
+if(hasRecursed&&(object instanceof tr.model.ObjectSnapshot||object instanceof tr.model.ObjectInstance))
+return;for(var key in object){var newKey=convertNameToJSConvention(key);if(newKey!=key){var value=object[key];delete object[key];object[newKey]=value;key=newKey;}
+if(/Quad$/.test(key)&&!(object[key]instanceof tr.b.Quad)){var q;try{q=tr.b.Quad.from8Array(object[key]);}catch(e){console.log(e);}
+object[key]=q;continue;}
+if(/Rect$/.test(key)&&!(object[key]instanceof tr.b.Rect)){var r;try{r=tr.b.Rect.fromArray(object[key]);}catch(e){console.log(e);}
+object[key]=r;}
+preInitializeObjectInner(object[key],true);}}
+function bytesToRoundedMegabytes(bytes){return Math.round(bytes/100000.0)/10.0;}
+return{preInitializeObject:preInitializeObject,convertNameToJSConvention:convertNameToJSConvention,moveRequiredFieldsFromArgsToToplevel:moveRequiredFieldsFromArgsToToplevel,moveOptionalFieldsFromArgsToToplevel:moveOptionalFieldsFromArgsToToplevel,bytesToRoundedMegabytes:bytesToRoundedMegabytes};});'use strict';tr.exportTo('tr.e.cc',function(){var ObjectSnapshot=tr.model.ObjectSnapshot;var PictureCount=0;var OPS_TIMING_ITERATIONS=3;function Picture(skp64,layerRect){this.skp64_=skp64;this. [...]
+Picture.prototype={get canSave(){return true;},get layerRect(){return this.layerRect_;},get guid(){return this.guid_;},getBase64SkpData:function(){return this.skp64_;},getOps:function(){if(!PictureSnapshot.CanGetOps()){console.error(PictureSnapshot.HowToEnablePictureDebugging());return undefined;}
+var ops=window.chrome.skiaBenchmarking.getOps({skp64:this.skp64_,params:{layer_rect:this.layerRect_.toArray()}});if(!ops)
+console.error('Failed to get picture ops.');return ops;},getOpTimings:function(){if(!PictureSnapshot.CanGetOpTimings()){console.error(PictureSnapshot.HowToEnablePictureDebugging());return undefined;}
+var opTimings=window.chrome.skiaBenchmarking.getOpTimings({skp64:this.skp64_,params:{layer_rect:this.layerRect_.toArray()}});if(!opTimings)
+console.error('Failed to get picture op timings.');return opTimings;},tagOpsWithTimings:function(ops){var opTimings=new Array();for(var iteration=0;iteration<OPS_TIMING_ITERATIONS;iteration++){opTimings[iteration]=this.getOpTimings();if(!opTimings[iteration]||!opTimings[iteration].cmd_times)
+return ops;if(opTimings[iteration].cmd_times.length!=ops.length)
+return ops;}
+for(var opIndex=0;opIndex<ops.length;opIndex++){var min=Number.MAX_VALUE;for(var i=0;i<OPS_TIMING_ITERATIONS;i++)
+min=Math.min(min,opTimings[i].cmd_times[opIndex]);ops[opIndex].cmd_time=min;}
+return ops;},rasterize:function(params,rasterCompleteCallback){if(!PictureSnapshot.CanRasterize()||!PictureSnapshot.CanGetOps()){rasterCompleteCallback(new tr.e.cc.PictureAsImageData(this,tr.e.cc.PictureSnapshot.HowToEnablePictureDebugging()));return;}
+var raster=window.chrome.skiaBenchmarking.rasterize({skp64:this.skp64_,params:{layer_rect:this.layerRect_.toArray()}},{stop:params.stopIndex===undefined?-1:params.stopIndex,overdraw:!!params.showOverdraw,params:{}});if(raster){var canvas=document.createElement('canvas');var ctx=canvas.getContext('2d');canvas.width=raster.width;canvas.height=raster.height;var imageData=ctx.createImageData(raster.width,raster.height);imageData.data.set(new Uint8ClampedArray(raster.data));rasterCompleteCall [...]
+LayeredPicture.prototype={__proto__:Picture.prototype,get canSave(){return false;},get typeName(){return'cc::LayeredPicture';},get layerRect(){if(this.layerRect_!==undefined)
+return this.layerRect_;this.layerRect_={x:0,y:0,width:0,height:0};for(var i=0;i<this.pictures_.length;++i){var rect=this.pictures_[i].layerRect;this.layerRect_.x=Math.min(this.layerRect_.x,rect.x);this.layerRect_.y=Math.min(this.layerRect_.y,rect.y);this.layerRect_.width=Math.max(this.layerRect_.width,rect.x+rect.width);this.layerRect_.height=Math.max(this.layerRect_.height,rect.y+rect.height);}
+return this.layerRect_;},get guid(){return this.guid_;},getBase64SkpData:function(){throw new Error('Not available with a LayeredPicture.');},getOps:function(){var ops=[];for(var i=0;i<this.pictures_.length;++i)
+ops=ops.concat(this.pictures_[i].getOps());return ops;},getOpTimings:function(){var opTimings=this.pictures_[0].getOpTimings();for(var i=1;i<this.pictures_.length;++i){var timings=this.pictures_[i].getOpTimings();opTimings.cmd_times=opTimings.cmd_times.concat(timings.cmd_times);opTimings.total_time+=timings.total_time;}
+return opTimings;},tagOpsWithTimings:function(ops){var opTimings=new Array();for(var iteration=0;iteration<OPS_TIMING_ITERATIONS;iteration++){opTimings[iteration]=this.getOpTimings();if(!opTimings[iteration]||!opTimings[iteration].cmd_times)
+return ops;}
+for(var opIndex=0;opIndex<ops.length;opIndex++){var min=Number.MAX_VALUE;for(var i=0;i<OPS_TIMING_ITERATIONS;i++)
+min=Math.min(min,opTimings[i].cmd_times[opIndex]);ops[opIndex].cmd_time=min;}
+return ops;},rasterize:function(params,rasterCompleteCallback){this.picturesAsImageData_=[];var rasterCallback=function(pictureAsImageData){this.picturesAsImageData_.push(pictureAsImageData);if(this.picturesAsImageData_.length!==this.pictures_.length)
+return;var canvas=document.createElement('canvas');var ctx=canvas.getContext('2d');canvas.width=this.layerRect.width;canvas.height=this.layerRect.height;for(var i=0;i<this.picturesAsImageData_.length;++i){ctx.putImageData(this.picturesAsImageData_[i].imageData,this.pictures_[i].layerRect.x,this.pictures_[i].layerRect.y);}
+this.picturesAsImageData_=[];rasterCompleteCallback(new tr.e.cc.PictureAsImageData(this,ctx.getImageData(this.layerRect.x,this.layerRect.y,this.layerRect.width,this.layerRect.height)));}.bind(this);for(var i=0;i<this.pictures_.length;++i)
+this.pictures_[i].rasterize(params,rasterCallback);}};function PictureSnapshot(){ObjectSnapshot.apply(this,arguments);}
+PictureSnapshot.HasSkiaBenchmarking=function(){return tr.isExported('chrome.skiaBenchmarking');}
+PictureSnapshot.CanRasterize=function(){if(!PictureSnapshot.HasSkiaBenchmarking())
+return false;if(!window.chrome.skiaBenchmarking.rasterize)
+return false;return true;}
+PictureSnapshot.CanGetOps=function(){if(!PictureSnapshot.HasSkiaBenchmarking())
+return false;if(!window.chrome.skiaBenchmarking.getOps)
+return false;return true;}
+PictureSnapshot.CanGetOpTimings=function(){if(!PictureSnapshot.HasSkiaBenchmarking())
+return false;if(!window.chrome.skiaBenchmarking.getOpTimings)
+return false;return true;}
+PictureSnapshot.CanGetInfo=function(){if(!PictureSnapshot.HasSkiaBenchmarking())
+return false;if(!window.chrome.skiaBenchmarking.getInfo)
+return false;return true;}
+PictureSnapshot.HowToEnablePictureDebugging=function(){if(tr.isHeadless)
+return'Pictures only work in chrome';var usualReason=['For pictures to show up, you need to have Chrome running with ','--enable-skia-benchmarking. Please restart chrome with this flag ','and try again.'].join('');if(!tr.isExported('global.chrome.skiaBenchmarking'))
+return usualReason;if(!global.chrome.skiaBenchmarking.rasterize)
+return'Your chrome is old';if(!global.chrome.skiaBenchmarking.getOps)
+return'Your chrome is old: skiaBenchmarking.getOps not found';if(!global.chrome.skiaBenchmarking.getOpTimings)
+return'Your chrome is old: skiaBenchmarking.getOpTimings not found';if(!global.chrome.skiaBenchmarking.getInfo)
+return'Your chrome is old: skiaBenchmarking.getInfo not found';return'Rasterizing is on';}
+PictureSnapshot.prototype={__proto__:ObjectSnapshot.prototype,preInitialize:function(){tr.e.cc.preInitializeObject(this);this.rasterResult_=undefined;},initialize:function(){if(this.args.alias)
+this.args=this.args.alias.args;if(!this.args.params.layerRect)
+throw new Error('Missing layer rect');this.layerRect_=this.args.params.layerRect;this.picture_=new Picture(this.args.skp64,this.args.params.layerRect);},set picture(picture){this.picture_=picture;},get canSave(){return this.picture_.canSave;},get layerRect(){return this.layerRect_?this.layerRect_:this.picture_.layerRect;},get guid(){return this.picture_.guid;},getBase64SkpData:function(){return this.picture_.getBase64SkpData();},getOps:function(){return this.picture_.getOps();},getOpTimi [...]
+DisplayItemList.prototype={__proto__:tr.e.cc.Picture.prototype};function DisplayItemListSnapshot(){tr.e.cc.PictureSnapshot.apply(this,arguments);}
+DisplayItemListSnapshot.prototype={__proto__:tr.e.cc.PictureSnapshot.prototype,initialize:function(){tr.e.cc.PictureSnapshot.prototype.initialize.call(this);this.displayItems_=this.args.params.items;},get items(){return this.displayItems_;}};ObjectSnapshot.register(DisplayItemListSnapshot,{typeNames:['cc::DisplayItemList']});return{DisplayItemListSnapshot:DisplayItemListSnapshot,DisplayItemList:DisplayItemList};});'use strict';tr.exportTo('tr.e.cc',function(){var constants={};constants.A [...]
+Region.fromArray=function(array){if(array.length%4!=0)
+throw new Error('Array must consist be a multiple of 4 in length');var r=new Region();for(var i=0;i<array.length;i+=4){r.rects.push(tr.b.Rect.fromXYWH(array[i],array[i+1],array[i+2],array[i+3]));}
+return r;}
+Region.fromArrayOrUndefined=function(array){if(array===undefined)
+return new Region();return Region.fromArray(array);};Region.prototype={__proto__:Region.prototype,rectIntersects:function(r){for(var i=0;i<this.rects.length;i++){if(this.rects[i].intersects(r))
+return true;}
+return false;},addRect:function(r){this.rects.push(r);}};return{Region:Region};});'use strict';tr.exportTo('tr.e.cc',function(){function TileCoverageRect(rect,tile){this.geometryRect=rect;this.tile=tile;}
+return{TileCoverageRect:TileCoverageRect};});'use strict';tr.exportTo('tr.e.cc',function(){var constants=tr.e.cc.constants;var ObjectSnapshot=tr.model.ObjectSnapshot;function LayerImplSnapshot(){ObjectSnapshot.apply(this,arguments);}
+LayerImplSnapshot.prototype={__proto__:ObjectSnapshot.prototype,preInitialize:function(){tr.e.cc.preInitializeObject(this);this.layerTreeImpl_=undefined;this.parentLayer=undefined;},initialize:function(){this.invalidation=new tr.e.cc.Region();this.annotatedInvalidation=new tr.e.cc.Region();this.unrecordedRegion=new tr.e.cc.Region();this.pictures=[];tr.e.cc.moveRequiredFieldsFromArgsToToplevel(this,['layerId','children','layerQuad']);tr.e.cc.moveOptionalFieldsFromArgsToToplevel(this,['mas [...]
+for(var i=0;i<this.children.length;i++)
+this.children[i].parentLayer=this;if(this.maskLayer)
+this.maskLayer.parentLayer=this;if(this.replicaLayer)
+this.replicaLayer.parentLayer=this;if(!this.geometryContentsScale)
+this.geometryContentsScale=1.0;if(!this.idealContentsScale)
+this.idealContentsScale=1.0;this.touchEventHandlerRegion=tr.e.cc.Region.fromArrayOrUndefined(this.args.touchEventHandlerRegion);this.wheelEventHandlerRegion=tr.e.cc.Region.fromArrayOrUndefined(this.args.wheelEventHandlerRegion);this.nonFastScrollableRegion=tr.e.cc.Region.fromArrayOrUndefined(this.args.nonFastScrollableRegion);},get layerTreeImpl(){if(this.layerTreeImpl_)
+return this.layerTreeImpl_;if(this.parentLayer)
+return this.parentLayer.layerTreeImpl;return undefined;},set layerTreeImpl(layerTreeImpl){this.layerTreeImpl_=layerTreeImpl;},get activeLayer(){if(this.layerTreeImpl.whichTree==constants.ACTIVE_TREE)
+return this;var activeTree=this.layerTreeImpl.layerTreeHostImpl.activeTree;return activeTree.findLayerWithId(this.layerId);},get pendingLayer(){if(this.layerTreeImpl.whichTree==constants.PENDING_TREE)
+return this;var pendingTree=this.layerTreeImpl.layerTreeHostImpl.pendingTree;return pendingTree.findLayerWithId(this.layerId);}};function PictureLayerImplSnapshot(){LayerImplSnapshot.apply(this,arguments);}
+PictureLayerImplSnapshot.prototype={__proto__:LayerImplSnapshot.prototype,initialize:function(){LayerImplSnapshot.prototype.initialize.call(this);if(this.args.invalidation){this.invalidation=tr.e.cc.Region.fromArray(this.args.invalidation);delete this.args.invalidation;}
+if(this.args.annotatedInvalidationRects){this.annotatedInvalidation=new tr.e.cc.Region();for(var i=0;i<this.args.annotatedInvalidationRects.length;++i){var annotatedRect=this.args.annotatedInvalidationRects[i];var rect=annotatedRect.geometryRect;rect.reason=annotatedRect.reason;this.annotatedInvalidation.addRect(rect);}
+delete this.args.annotatedInvalidationRects;}
+if(this.args.unrecordedRegion){this.unrecordedRegion=tr.e.cc.Region.fromArray(this.args.unrecordedRegion);delete this.args.unrecordedRegion;}
+if(this.args.pictures){this.pictures=this.args.pictures;this.pictures.sort(function(a,b){return a.ts-b.ts;});}
+this.tileCoverageRects=[];if(this.args.coverageTiles){for(var i=0;i<this.args.coverageTiles.length;++i){var rect=this.args.coverageTiles[i].geometryRect.scale(this.idealContentsScale);var tile=this.args.coverageTiles[i].tile;this.tileCoverageRects.push(new tr.e.cc.TileCoverageRect(rect,tile));}
+delete this.args.coverageTiles;}}};ObjectSnapshot.register(PictureLayerImplSnapshot,{typeName:'cc::PictureLayerImpl'});ObjectSnapshot.register(LayerImplSnapshot,{typeNames:['cc::LayerImpl','cc::DelegatedRendererLayerImpl','cc::HeadsUpDisplayLayerImpl','cc::IOSurfaceLayerImpl','cc::NinePatchLayerImpl','cc::PictureImageLayerImpl','cc::ScrollbarLayerImpl','cc::SolidColorLayerImpl','cc::SurfaceLayerImpl','cc::TextureLayerImpl','cc::TiledLayerImpl','cc::VideoLayerImpl','cc::PaintedScrollbarLa [...]
+LayerTreeImplSnapshot.prototype={__proto__:ObjectSnapshot.prototype,preInitialize:function(){tr.e.cc.preInitializeObject(this);this.layerTreeHostImpl=undefined;this.whichTree=undefined;this.sourceFrameNumber=undefined;},initialize:function(){tr.e.cc.moveRequiredFieldsFromArgsToToplevel(this,['rootLayer','renderSurfaceLayerList']);if(this.args.sourceFrameNumber)
+this.sourceFrameNumber=this.args.sourceFrameNumber;this.rootLayer.layerTreeImpl=this;if(this.args.swapPromiseTraceIds&&this.args.swapPromiseTraceIds.length){this.tracedInputLatencies=[];var ownProcess=this.objectInstance.parent;var modelHelper=ownProcess.model.getOrCreateHelper(tr.model.helpers.ChromeModelHelper);if(modelHelper)
+this._initializeTracedInputLatencies(modelHelper);}},_initializeTracedInputLatencies:function(modelHelper){var latencyEvents=modelHelper.browserHelper.getLatencyEventsInRange(modelHelper.model.bounds);latencyEvents.forEach(function(event){for(var i=0;i<this.args.swapPromiseTraceIds.length;i++){if(!event.args.data||!event.args.data.trace_id)
+continue;if(parseInt(event.args.data.trace_id)===this.args.swapPromiseTraceIds[i])
+this.tracedInputLatencies.push(event);}},this);},get hasSourceFrameBeenDrawnBefore(){if(this.whichTree==tr.e.cc.constants.PENDING_TREE)
+return false;if(this.sourceFrameNumber===undefined)
+return;var thisLTHI=this.layerTreeHostImpl;var thisLTHIIndex=thisLTHI.objectInstance.snapshots.indexOf(thisLTHI);var prevLTHIIndex=thisLTHIIndex-1;if(prevLTHIIndex<0||prevLTHIIndex>=thisLTHI.objectInstance.snapshots.length)
+return false;var prevLTHI=thisLTHI.objectInstance.snapshots[prevLTHIIndex];if(!prevLTHI.activeTree)
+return false;if(prevLTHI.activeTree.sourceFrameNumber===undefined)
+return;return prevLTHI.activeTree.sourceFrameNumber==this.sourceFrameNumber;},get otherTree(){var other=this.whichTree==constants.ACTIVE_TREE?constants.PENDING_TREE:constants.ACTIVE_TREE;return this.layerTreeHostImpl.getTree(other);},get gpuMemoryUsageInBytes(){var totalBytes=0;this.iterLayers(function(layer){if(layer.gpuMemoryUsageInBytes!==undefined)
+totalBytes+=layer.gpuMemoryUsageInBytes;});return totalBytes;},iterLayers:function(func,thisArg){var visitedLayers={};function visitLayer(layer,depth,isMask,isReplica){if(visitedLayers[layer.layerId])
+return;visitedLayers[layer.layerId]=true;func.call(thisArg,layer,depth,isMask,isReplica);if(layer.children){for(var i=0;i<layer.children.length;i++)
+visitLayer(layer.children[i],depth+1);}
+if(layer.maskLayer)
+visitLayer(layer.maskLayer,depth+1,true,false);if(layer.replicaLayer)
+visitLayer(layer.replicaLayer,depth+1,false,true);}
+visitLayer(this.rootLayer,0,false,false);},findLayerWithId:function(id){var foundLayer=undefined;function visitLayer(layer){if(layer.layerId==id)
+foundLayer=layer;}
+this.iterLayers(visitLayer);return foundLayer;}};ObjectSnapshot.register(LayerTreeImplSnapshot,{typeName:'cc::LayerTreeImpl'});return{LayerTreeImplSnapshot:LayerTreeImplSnapshot};});'use strict';tr.exportTo('tr.b',function(){function BBox2(){this.isEmpty_=true;this.min_=undefined;this.max_=undefined;};BBox2.prototype={__proto__:Object.prototype,reset:function(){this.isEmpty_=true;this.min_=undefined;this.max_=undefined;},get isEmpty(){return this.isEmpty_;},addBBox2:function(bbox2){if(bb [...]
+return;this.addVec2(bbox2.min_);this.addVec2(bbox2.max_);},clone:function(){var bbox=new BBox2();bbox.addBBox2(this);return bbox;},addXY:function(x,y){if(this.isEmpty_){this.max_=vec2.create();this.min_=vec2.create();vec2.set(this.max_,x,y);vec2.set(this.min_,x,y);this.isEmpty_=false;return;}
+this.max_[0]=Math.max(this.max_[0],x);this.max_[1]=Math.max(this.max_[1],y);this.min_[0]=Math.min(this.min_[0],x);this.min_[1]=Math.min(this.min_[1],y);},addVec2:function(value){if(this.isEmpty_){this.max_=vec2.create();this.min_=vec2.create();vec2.set(this.max_,value[0],value[1]);vec2.set(this.min_,value[0],value[1]);this.isEmpty_=false;return;}
+this.max_[0]=Math.max(this.max_[0],value[0]);this.max_[1]=Math.max(this.max_[1],value[1]);this.min_[0]=Math.min(this.min_[0],value[0]);this.min_[1]=Math.min(this.min_[1],value[1]);},addQuad:function(quad){this.addVec2(quad.p1);this.addVec2(quad.p2);this.addVec2(quad.p3);this.addVec2(quad.p4);},get minVec2(){if(this.isEmpty_)
+return undefined;return this.min_;},get maxVec2(){if(this.isEmpty_)
+return undefined;return this.max_;},get sizeAsVec2(){if(this.isEmpty_)
+throw new Error('Empty BBox2 has no size');var size=vec2.create();vec2.subtract(size,this.max_,this.min_);return size;},get size(){if(this.isEmpty_)
+throw new Error('Empty BBox2 has no size');return{width:this.max_[0]-this.min_[0],height:this.max_[1]-this.min_[1]};},get width(){if(this.isEmpty_)
+throw new Error('Empty BBox2 has no width');return this.max_[0]-this.min_[0];},get height(){if(this.isEmpty_)
+throw new Error('Empty BBox2 has no width');return this.max_[1]-this.min_[1];},toString:function(){if(this.isEmpty_)
+return'empty';return'min=('+this.min_[0]+','+this.min_[1]+') '+'max=('+this.max_[0]+','+this.max_[1]+')';},asRect:function(){return tr.b.Rect.fromXYWH(this.min_[0],this.min_[1],this.max_[0]-this.min_[0],this.max_[1]-this.min_[1]);}};return{BBox2:BBox2};});'use strict';tr.exportTo('tr.e.cc',function(){var constants=tr.e.cc.constants;var ObjectSnapshot=tr.model.ObjectSnapshot;var ObjectInstance=tr.model.ObjectInstance;function LayerTreeHostImplSnapshot(){ObjectSnapshot.apply(this,arguments);}
+LayerTreeHostImplSnapshot.prototype={__proto__:ObjectSnapshot.prototype,preInitialize:function(){tr.e.cc.preInitializeObject(this);},initialize:function(){tr.e.cc.moveRequiredFieldsFromArgsToToplevel(this,['deviceViewportSize','activeTree']);tr.e.cc.moveOptionalFieldsFromArgsToToplevel(this,['pendingTree']);if(this.args.activeTiles!==undefined){this.activeTiles=this.args.activeTiles;delete this.args.activeTiles;}else if(this.args.tiles!==undefined){this.activeTiles=this.args.tiles;delete [...]
+if(!this.activeTiles)
+this.activeTiles=[];this.activeTree.layerTreeHostImpl=this;this.activeTree.whichTree=constants.ACTIVE_TREE;if(this.pendingTree){this.pendingTree.layerTreeHostImpl=this;this.pendingTree.whichTree=constants.PENDING_TREE;}},getContentsScaleNames:function(){var scales={};for(var i=0;i<this.activeTiles.length;++i){var tile=this.activeTiles[i];scales[tile.contentsScale]=tile.resolution;}
+return scales;},getTree:function(whichTree){if(whichTree==constants.ACTIVE_TREE)
+return this.activeTree;if(whichTree==constants.PENDING_TREE)
+return this.pendingTree;throw new Exception('Unknown tree type + '+whichTree);},get tilesHaveGpuMemoryUsageInfo(){if(this.tilesHaveGpuMemoryUsageInfo_!==undefined)
+return this.tilesHaveGpuMemoryUsageInfo_;for(var i=0;i<this.activeTiles.length;i++){if(this.activeTiles[i].gpuMemoryUsageInBytes===undefined)
+continue;this.tilesHaveGpuMemoryUsageInfo_=true;return true;}
+this.tilesHaveGpuMemoryUsageInfo_=false;return false;},get gpuMemoryUsageInBytes(){if(!this.tilesHaveGpuMemoryUsageInfo)
+return;var usage=0;for(var i=0;i<this.activeTiles.length;i++){var u=this.activeTiles[i].gpuMemoryUsageInBytes;if(u!==undefined)
+usage+=u;}
+return usage;},get userFriendlyName(){var frameNumber;if(!this.activeTree){frameNumber=this.objectInstance.snapshots.indexOf(this);}else{if(this.activeTree.sourceFrameNumber===undefined)
+frameNumber=this.objectInstance.snapshots.indexOf(this);else
+frameNumber=this.activeTree.sourceFrameNumber;}
+return'cc::LayerTreeHostImpl frame '+frameNumber;}};ObjectSnapshot.register(LayerTreeHostImplSnapshot,{typeName:'cc::LayerTreeHostImpl'});function LayerTreeHostImplInstance(){ObjectInstance.apply(this,arguments);this.allLayersBBox_=undefined;}
+LayerTreeHostImplInstance.prototype={__proto__:ObjectInstance.prototype,get allContentsScales(){if(this.allContentsScales_)
+return this.allContentsScales_;var scales={};for(var tileID in this.allTileHistories_){var tileHistory=this.allTileHistories_[tileID];scales[tileHistory.contentsScale]=true;}
+this.allContentsScales_=tr.b.dictionaryKeys(scales);return this.allContentsScales_;},get allLayersBBox(){if(this.allLayersBBox_)
+return this.allLayersBBox_;var bbox=new tr.b.BBox2();function handleTree(tree){tree.renderSurfaceLayerList.forEach(function(layer){bbox.addQuad(layer.layerQuad);});}
+this.snapshots.forEach(function(lthi){handleTree(lthi.activeTree);if(lthi.pendingTree)
+handleTree(lthi.pendingTree);});this.allLayersBBox_=bbox;return this.allLayersBBox_;}};ObjectInstance.register(LayerTreeHostImplInstance,{typeName:'cc::LayerTreeHostImpl'});return{LayerTreeHostImplSnapshot:LayerTreeHostImplSnapshot,LayerTreeHostImplInstance:LayerTreeHostImplInstance};});'use strict';tr.exportTo('tr.e.cc',function(){var tileTypes={highRes:'highRes',lowRes:'lowRes',extraHighRes:'extraHighRes',extraLowRes:'extraLowRes',missing:'missing',culled:'culled',solidColor:'solidColo [...]
+TileSnapshot.prototype={__proto__:ObjectSnapshot.prototype,preInitialize:function(){tr.e.cc.preInitializeObject(this);},initialize:function(){tr.e.cc.moveOptionalFieldsFromArgsToToplevel(this,['layerId','contentsScale','contentRect']);if(this.args.managedState){this.resolution=this.args.managedState.resolution;this.isSolidColor=this.args.managedState.isSolidColor;this.isUsingGpuMemory=this.args.managedState.isUsingGpuMemory;this.hasResource=this.args.managedState.hasResource;this.schedul [...]
+if(this.contentRect)
+this.layerRect=this.contentRect.scale(1.0/this.contentsScale);if(this.isSolidColor)
+this.type_=tr.e.cc.tileTypes.solidColor;else if(!this.hasResource)
+this.type_=tr.e.cc.tileTypes.missing;else if(this.resolution==='HIGH_RESOLUTION')
+this.type_=tr.e.cc.tileTypes.highRes;else if(this.resolution==='LOW_RESOLUTION')
+this.type_=tr.e.cc.tileTypes.lowRes;else
+this.type_=tr.e.cc.tileTypes.unknown;},getTypeForLayer:function(layer){var type=this.type_;if(type==tr.e.cc.tileTypes.unknown){if(this.contentsScale<layer.idealContentsScale)
+type=tr.e.cc.tileTypes.extraLowRes;else if(this.contentsScale>layer.idealContentsScale)
+type=tr.e.cc.tileTypes.extraHighRes;}
+return type;}};ObjectSnapshot.register(TileSnapshot,{typeName:'cc::Tile'});return{TileSnapshot:TileSnapshot};});'use strict';tr.exportTo('tr.ui.b',function(){var EventSet=tr.model.EventSet;var SelectionState=tr.model.SelectionState;function BrushingState(){this.guid_=tr.b.GUID.allocate();this.selection_=new EventSet();this.findMatches_=new EventSet();this.analysisViewRelatedEvents_=new EventSet();this.analysisLinkHoveredEvents_=new EventSet();this.appliedToModel_=undefined;this.viewSpeci [...]
+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_;that.analysisLinkHoveredEvents_=this.analysisLinkHoveredEvents_;that.viewSpecificBrushingStates_=this.viewSpecificBrushingStates_;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;}
+if(!this.analysisLinkHoveredEvents_.equals(that.analysisLinkHoveredEvents_)){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_;if(this.analysisLinkHoveredEvents_.length)
+return this.analysisLinkHoveredEvents_;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 EventSet();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 EventSet();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 EventSet();this.analysisViewRelatedEvents_=analysisViewRelatedEvents;},get analysisLinkHoveredEvents(){return this.analysisLinkHoveredEvents_;},set analysisLinkHoveredEvents(analysisLinkHoveredEvents){if(this.appliedToModel_)
+throw new Error('Cannot mutate this state right now');if(analysisLinkHoveredEvents===undefined)
+analysisLinkHoveredEvents=new EventSet();this.analysisLinkHoveredEvents_=analysisLinkHoveredEvents;},get isAppliedToModel(){return this.appliedToModel_!==undefined;},get viewSpecificBrushingStates(){return this.viewSpecificBrushingStates_;},set viewSpecificBrushingStates(viewSpecificBrushingStates){this.viewSpecificBrushingStates_=viewSpecificBrushingStates;},get causesDimming_(){return this.findMatches_.length>0||this.analysisViewRelatedEvents_.length>0;},get brightenedEvents_(){var bri [...]
+score++;if(this.analysisLinkHoveredEvents_.contains(e))
+score++;e.selectionState=SelectionState.getFromBrighteningLevel(score);},this);return;}
+var brightenedEvents=this.brightenedEvents_;model.iterateAllEvents(function(e){var score;if(brightenedEvents.contains(e)){score=0;if(this.selection_.contains(e))
+score++;if(this.analysisLinkHoveredEvents_.contains(e))
+score++;e.selectionState=SelectionState.getFromBrighteningLevel(score);}else{score=0;if(this.findMatches_.contains(e))
+score++;if(this.analysisViewRelatedEvents_.contains(e))
+score++;e.selectionState=SelectionState.getFromDimmingLevel(score);}}.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.causesDimming_){this.brightenedEvents_.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 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 tr.b.Event('didtick');e.oldTargetState=oldTargetState;this.dispatchEvent(e,false,false);}}};return{AnimationController:AnimationController};});'use strict';tr.exportTo('tr.b',function(){function Settings(){return Settings;};if(tr.b.unittest&&tr.b.unittest.TestRunner){tr.b.unittest.TestRunner.addEventListener('tr-unittest-will-run',function(){if(tr.isHeadless)
+Settings.setAlternativeStorageInstance(new HeadlessStorage());else
+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(key);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';};function HeadlessStorage(){this.length=0;this.hasItem_={};this.items_={};this.itemsAsArray_=undefined;}
+HeadlessStorage.prototype={key:function(index){return this.itemsAsArray[index];},get itemsAsArray(){if(this.itemsAsArray_!==undefined)
+return this.itemsAsArray_;var itemsAsArray=[];for(var k in this.items_)
+itemsAsArray.push(k);this.itemsAsArray_=itemsAsArray;return this.itemsAsArray_;},getItem:function(key){if(!this.hasItem_[key])
+return null;return this.items_[key];},removeItem:function(key){if(!this.hasItem_[key])
+return;var value=this.items_[key];delete this.hasItem_[key];delete this.items_[key];this.length--;this.itemsAsArray_=undefined;return value;},setItem:function(key,value){if(this.hasItem_[key]){this.items_[key]=value;return;}
+this.items_[key]=value;this.hasItem_[key]=true;this.length++;this.itemsAsArray_=undefined;return value;}};if(tr.isHeadless){AddStaticStorageFunctionsToClass_(Settings,new HeadlessStorage());AddStaticStorageFunctionsToClass_(SessionSettings,new HeadlessStorage());}else{AddStaticStorageFunctionsToClass_(Settings,localStorage);AddStaticStorageFunctionsToClass_(SessionSettings,sessionStorage);}
+return{Settings:Settings,SessionSettings:SessionSettings};});'use strict';tr.exportTo('tr.ui.b',function(){function createSpan(opt_dictionary){var ownerDocument=document;if(opt_dictionary&&opt_dictionary.ownerDocument)
+ownerDocument=opt_dictionary.ownerDocument;var spanEl=ownerDocument.createElement('span');if(opt_dictionary){if(opt_dictionary.className)
 spanEl.className=opt_dictionary.className;if(opt_dictionary.textContent)
-spanEl.textContent=opt_dictionary.textContent;if(opt_dictionary.parent)
+spanEl.textContent=opt_dictionary.textContent;if(opt_dictionary.tooltip)
+spanEl.title=opt_dictionary.tooltip;if(opt_dictionary.parent)
 opt_dictionary.parent.appendChild(spanEl);if(opt_dictionary.bold)
-spanEl.style.fontWeight='bold';if(opt_dictionary.marginLeft)
+spanEl.style.fontWeight='bold';if(opt_dictionary.italic)
+spanEl.style.fontStyle='italic';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)
@@ -2491,9 +5529,9 @@ 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);}
+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;optionEl.item=item;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();}
+var oldSetter=targetEl.__lookupSetter__('selectedIndex');selectorEl.__defineGetter__('selectedValue',function(v){return selectorEl.children[selectorEl.selectedIndex].targetPropertyValue;});selectorEl.__defineGetter__('selectedItem',function(v){return selectorEl.children[selectorEl.selectedIndex].item;});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 cha [...]
 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;}
@@ -2506,28 +5544,160 @@ radioEl.checked=true;var labelEl=document.createElement('label');labelEl.textCon
 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)
+var nextCheckboxId=1;function createCheckBox(targetEl,targetElProperty,settingsKey,defaultValue,label,opt_changeCb){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;}
+targetEl[targetElProperty]=buttonEl.checked;if(opt_changeCb)
+opt_changeCb.call();}
 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 createButton(targetEl,targetElProperty,label,opt_changeCb){var buttonEl=document.createElement('input');buttonEl.type='button';function onClick(){if(opt_changeCb)
+opt_changeCb.call();}
+buttonEl.addEventListener('click',onClick);buttonEl.value=label;return buttonEl;}
+function createTextInput(targetEl,targetElProperty,settingsKey,defaultValue){var initialValue=tr.b.Settings.get(settingsKey,defaultValue);var el=document.createElement('input');el.type='text';function onChange(e){tr.b.Settings.set(settingsKey,el.value);targetEl[targetElProperty]=el.value;}
+el.addEventListener('input',onChange);el.value=initialValue;targetEl[targetElProperty]=initialValue;return el;}
 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  [...]
+return{createSpan:createSpan,createDiv:createDiv,createScopedStyle:createScopedStyle,createSelector:createSelector,createOptionGroup:createOptionGroup,createCheckBox:createCheckBox,createButton:createButton,createTextInput:createTextInput,isElementAttachedToDocument:isElementAttachedToDocument,asHTMLOrTextNode:asHTMLOrTextNode};});'use strict';tr.exportTo('tr.ui.b',function(){var ColorScheme=tr.b.ColorScheme;var colors=ColorScheme.colors;var colorsAsStrings=ColorScheme.colorsAsStrings;va [...]
+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 colors[colorId].toStringWithAlphaOverride(1.0);},getObjectInstanceColor:function(instance){var colorId=instance.colorId+this.getColorIdOffset_(instance);return colors[colorId].toStringWithAlphaOverride(0.25);},getObjectSnapshotColor:function(snapshot){var colorId=snapshot.objectInstance.colorId+this.getColorIdOffset_(snapshot);return colors[colorId];},getCou [...]
+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 ColorScheme=tr.b.ColorScheme;var colorsAsStrings=ColorScheme.colorsAsStrings;var EventPresenter=tr.ui.b.EventPresenter;var blackColorId=ColorScheme.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 [...]
+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,colorsAsStrings);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(async&&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',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.initAnimationController_();this.showFlowEvents_=false;this.hig [...]
+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();},getShiftedSelection:function(selection,offset){var newSelection=new tr.model.EventSet();for(var i=0;i<selection.length;i++){var event=selection[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=this.trackForEvent(event);track.addEventNearToProvidedEventToSelection(event,offset,newSelection);}
+if(newSelection.length==0)
+return undefined;return newSelection;},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:TimelineViewport};});'use strict';tr.exportT [...]
+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.model.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 [...]
+BrushingStateController.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_=new BrushingState();this.currentBrushingState_.applyToModelSelectionState(this.model);var e=new tr.b.Event('model-changed',false,false);this.dispatchEvent(e);this.dispatchChangeEvent_();},onUserInitiatedSelectionChange_:function(){var selection=this.selection;if(this.historyEnabled){this.selections_[selection.guid]=selection;var state={selection_guid:sele [...]
+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 EventSet();newBrushingState.findMatches=new EventSet();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 ne [...]
+newStates[id]=oldStates[id];if(newState===undefined)
+delete newStates[viewId];else
+newStates[viewId]=newState;var newBrushingState=this.currentBrushingState_.clone();newBrushingState.viewSpecificBrushingStates=newStates;this.currentBrushingState=newBrushingState;}};BrushingStateController.getControllerForElement=function(element){if(tr.isHeadless)
+throw new Error('Unsupported');var currentElement=element;while(currentElement){if(currentElement.brushingStateController)
+return currentElement.brushingStateController;if(currentElement.parentElement){currentElement=currentElement.parentElement;continue;}
+var currentNode=currentElement;while(currentNode.parentNode)
+currentNode=currentNode.parentNode;currentElement=currentNode.host;}
+return undefined;};return{BrushingStateController:BrushingStateController};});'use strict';Polymer('tr-ui-a-analysis-link',{ready:function(){this.selection_=undefined;},attached:function(){this.controller_=tr.c.BrushingStateController.getControllerForElement(this);},detached:function(){this.clearHighlight_();this.controller_=undefined;},get selection(){return this.selection_;},set selection(selection){this.selection_=selection;this.textContent=selection.userFriendlyName;},setSelectionAnd [...]
+this.textContent=opt_textContent;},getCurrentSelection_:function(){if(typeof this.selection_==='function')
+return this.selection_();return this.selection_;},setHighlight_:function(opt_eventSet){if(this.controller_)
+this.controller_.changeAnalysisLinkHoveredEvents(opt_eventSet);},clearHighlight_:function(opt_eventSet){this.setHighlight_();},onClicked_:function(){if(!this.selection_)
+return;var event=new tr.model.RequestSelectionChangeEvent();event.selection=this.getCurrentSelection_();this.dispatchEvent(event);},onMouseEnter_:function(){this.setHighlight_(this.getCurrentSelection_());},onMouseLeave_:function(){this.clearHighlight_();}});'use strict';tr.exportTo('tr.ui.b',function(){var TableFormat={};TableFormat.SelectionMode={NONE:0,ROW:1,CELL:2};TableFormat.HighlightStyle={DEFAULT:0,NONE:1,LIGHT:2,DARK:3};return{TableFormat:TableFormat};});'use strict';(function() [...]
 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 [...]
+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 [...]
+return;if(number===undefined){this.sortColumnIndex_=undefined;this.updateHeaderArrows_();this.dispatchSortingChangedEvent_();return;}
 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 [...]
+throw new Error('Column '+number+' does not have a comparator.');this.sortColumnIndex_=number;this.updateHeaderArrows_();this.scheduleRebuildBody_();this.dispatchSortingChangedEvent_();},get sortColumnIndex(){return this.sortColumnIndex_;},set sortDescending(value){var newValue=!!value;if(newValue!==this.sortDescending_){this.sortDescending_=newValue;this.updateHeaderArrows_();this.scheduleRebuildBody_();this.dispatchSortingChangedEvent_();}},get sortDescending(){return this.sortDescendi [...]
 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)
+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(this.getExpandedForUserRow_(rows[i]))
 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
@@ -2548,21 +5718,24 @@ 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 [...]
+return lastAddedRow;},getOrCreateRowInfoFor_:function(rowInfoMap,userRow,parentRowInfo){var rowInfo=undefined;if(rowInfoMap.has(userRow)){rowInfo=rowInfoMap.get(userRow);}else{rowInfo={userRow:userRow,htmlNode:undefined,parentRowInfo:parentRowInfo};rowInfoMap.set(userRow,rowInfo);}
+rowInfo.isExpanded=this.getExpandedForUserRow_(userRow);return rowInfo;},customizeTableRow_:function(userRow,trElement){if(!this.customizeTableRowCallback_)
+return;this.customizeTableRowCallback_(userRow,trElement);},getHTMLNodeForRowInfo_:function(tableSection,rowInfo,rowInfoMap,indentation){if(rowInfo.htmlNode){this.customizeTableRow_(rowInfo.userRow,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;this.customizeTableRow_(rowInfo.userRow,trElement);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 [...]
 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';}}
+if(value!==undefined)
 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;}
+var isSelectable=tableSection===this.$.body;var isExpandable=rowInfo.userRow[this.subRowsPropertyName_]&&rowInfo.userRow[this.subRowsPropertyName_].length;if(isSelectable||isExpandable){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));}
+if(isSelectable&&this.selectionMode_!==SelectionMode.NONE){var shouldSelect=false;var columnIndex=getTD(e.target).columnIndex;switch(this.selectionMode_){case SelectionMode.ROW:shouldSelect=this.selectedTableRowInfo_!==rowInfo;break;case SelectionMode.CELL:if(this.doesColumnIndexSupportSelection(columnIndex)){shouldSelect=this.selectedTableRowInfo_!==rowInfo||this.selectedColumnIndex_!==columnIndex;}
+break;default:throw new Error('Invalid selection mode '+
+this.selectionMode_);}
+if(shouldSelect){this.didTableRowInfoGetClicked_(rowInfo,columnIndex);return;}}
+if(isExpandable){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_)
@@ -2572,71 +5745,85 @@ 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 rowInfo.isExpanded;},getExpandedForUserRow_:function(userRow){if(userRow[this.subRowsPropertyName_]===undefined)
+return false;if(userRow[this.subRowsPropertyName_].length===0)
+return false;if(userRow.isExpanded)
+return true;if(userRow.isExpanded===false)
+return false;if(this.defaultExpansionStateCallback_===undefined)
+return false;var parentUserRow=undefined;var rowInfo=this.tableRowsInfo_.get(userRow);if(rowInfo&&rowInfo.parentRowInfo)
+parentUserRow=rowInfo.parentRowInfo.userRow;return this.defaultExpansionStateCallback_(userRow,parentUserRow);},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.maybeUpdateSelectedRow_();},get selectionMode(){return this.selectionMode_;},set selectionMode(selectionMode){if(!tr.b.dictionaryContainsValue(SelectionMode,selectionMode))
+throw new Error('Invalid selection mode '+selectionMode);this.rebuildIfNeeded_();this.selectionMode_=selectionMode;this.didSelectionStateChange_();},get rowHighlightStyle(){return this.rowHighlightStyle_;},set rowHighlightStyle(rowHighlightStyle){if(!tr.b.dictionaryContainsValue(HighlightStyle,rowHighlightStyle))
+throw new Error('Invalid row highlight style '+rowHighlightStyle);this.rebuildIfNeeded_();this.rowHighlightStyle_=rowHighlightStyle;this.didSelectionStateChange_();},get resolvedRowHighlightStyle(){if(this.rowHighlightStyle_!==HighlightStyle.DEFAULT)
+return this.rowHighlightStyle_;switch(this.selectionMode_){case SelectionMode.NONE:return HighlightStyle.NONE;case SelectionMode.ROW:return HighlightStyle.DARK;case SelectionMode.CELL:return HighlightStyle.LIGHT;default:throw new Error('Invalid selection mode '+selectionMode);}},get cellHighlightStyle(){return this.cellHighlightStyle_;},set cellHighlightStyle(cellHighlightStyle){if(!tr.b.dictionaryContainsValue(HighlightStyle,cellHighlightStyle))
+throw new Error('Invalid cell highlight style '+cellHighlightStyle);this.rebuildIfNeeded_();this.cellHighlightStyle_=cellHighlightStyle;this.didSelectionStateChange_();},get resolvedCellHighlightStyle(){if(this.cellHighlightStyle_!==HighlightStyle.DEFAULT)
+return this.cellHighlightStyle_;switch(this.selectionMode_){case SelectionMode.NONE:case SelectionMode.ROW:return HighlightStyle.NONE;case SelectionMode.CELL:return HighlightStyle.DARK;default:throw new Error('Invalid selection mode '+selectionMode);}},setHighlightStyle_:function(highlightAttribute,resolvedHighlightStyle){switch(resolvedHighlightStyle){case HighlightStyle.NONE:this.$.body.removeAttribute(highlightAttribute);break;case HighlightStyle.LIGHT:this.$.body.setAttribute(highlig [...]
+resolvedHighlightStyle);}},didSelectionStateChange_:function(){this.setHighlightStyle_('row-highlight-style',this.resolvedRowHighlightStyle);this.setHighlightStyle_('cell-highlight-style',this.resolvedCellHighlightStyle);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;}
+return;if(this.selectionMode_===SelectionMode.NONE){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)
+this.updateSelectedState_();},didTableRowInfoGetClicked_:function(rowInfo,columnIndex){switch(this.selectionMode_){case SelectionMode.NONE:return;case SelectionMode.CELL:if(!this.doesColumnIndexSupportSelection(columnIndex))
+return;if(this.selectedColumnIndex!==columnIndex)
+this.selectedColumnIndex=columnIndex;case SelectionMode.ROW:if(this.selectedTableRowInfo_!==rowInfo)
+this.selectedTableRow=rowInfo.userRow;}},get selectedTableRow(){if(!this.selectedTableRowInfo_)
+return undefined;return this.selectedTableRowInfo_.userRow;},set selectedTableRow(userRow){this.rebuildIfNeeded_();if(this.selectionMode_===SelectionMode.NONE)
+throw new Error('Selection is off.');var rowInfo;if(userRow===undefined){rowInfo=undefined;}else{rowInfo=this.tableRowsInfo_.get(userRow);if(!rowInfo)
+throw new Error('Row has not been seen, must expand its parents.');}
+var e=this.prepareToChangeSelection_();this.selectedTableRowInfo_=rowInfo;if(this.selectedTableRowInfo_===undefined){this.selectedColumnIndex_=undefined;this.removeSelectedState_();}else{switch(this.selectionMode_){case SelectionMode.ROW:this.selectedColumnIndex_=undefined;break;case SelectionMode.CELL:if(this.selectedColumnIndex_===undefined){var i=this.getFirstSelectableColumnIndex_();if(i==-1)
+throw new Error('Cannot find a selectable column.');this.selectedColumnIndex_=i;}
+break;default:throw new Error('Invalid selection mode '+this.selectionMode_);}
+this.updateSelectedState_();}
+this.dispatchEvent(e);},updateTabIndexForTableRowNode_:function(row){if(this.selectionMode_===SelectionMode.ROW)
+row.tabIndex=0;else
+row.removeAttribute('tabIndex');var enableCellTab=this.selectionMode_===SelectionMode.CELL;for(var i=0;i<this.tableColumns_.length;i++){var cell=row.children[i];if(enableCellTab&&this.doesColumnIndexSupportSelection(i))
+cell.tabIndex=0;else
+cell.removeAttribute('tabIndex');}},prepareToChangeSelection_:function(){var e=new tr.b.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;var rowNode=this.selectedTableRowInfo_.htmlNode;if(select)
+rowNode.setAttribute('selected',true);else
+rowNode.removeAttribute('selected');var cellNode=rowNode.children[this.selectedColumnIndex_];if(!cellNode)
+return;if(select)
+cellNode.setAttribute('selected',true);else
+cellNode.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)
+return-1;},getSelectableNodeGivenTableRowNode_:function(htmlNode){switch(this.selectionMode_){case SelectionMode.ROW:return htmlNode;case SelectionMode.CELL:return htmlNode.children[this.selectedColumnIndex_];default:throw new Error('Invalid selection mode '+this.selectionMode_);}},get selectedColumnIndex(){if(this.selectionMode_!==SelectionMode.CELL)
+return undefined;return this.selectedColumnIndex_;},set selectedColumnIndex(selectedColumnIndex){this.rebuildIfNeeded_();if(this.selectionMode_===SelectionMode.NONE)
+throw new Error('Selection is off.');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)
+this.selectedTableRowInfo_=undefined;this.updateSelectedState_();this.dispatchEvent(e);},onKeyDown_:function(e){if(this.selectionMode_===SelectionMode.NONE)
 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;var code_to_command_names={13:'ENTER',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)
+if(cmdName==='ARROW_RIGHT'){switch(this.selectionMode_){case SelectionMode.ROW: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)
+this.setExpandedForTableRow(rowInfo.userRow,true);this.selectedTableRow=htmlNode.nextElementSibling.rowInfo.userRow;this.focusSelected_();return;case SelectionMode.CELL: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.isExpanded){this.setExpandedForTableRow(rowInfo.userRow,false);this.focusSelected_();return;}
+return;this.selectedColumnIndex=newIndex;this.focusSelected_();return;default:throw new Error('Invalid selection mode '+this.selectionMode_);}}
+if(cmdName==='ARROW_LEFT'){switch(this.selectionMode_){case SelectionMode.ROW: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.$. [...]
+return;case SelectionMode.CELL:var newIndex=this.selectedColumnIndex_-1;if(newIndex<0)
+return;if(!this.doesColumnIndexSupportSelection(newIndex))
+return;this.selectedColumnIndex=newIndex;this.focusSelected_();return;default:throw new Error('Invalid selection mode '+this.selectionMode_);}}
+if(cmdName==='ENTER'){if(rowInfo.userRow[this.subRowsPropertyName_]===undefined)
+return;if(rowInfo.userRow[this.subRowsPropertyName_].length===0)
+return;this.setExpandedForTableRow(rowInfo.userRow,!rowInfo.isExpanded);this.focusSelected_();return;}
+throw new Error('Unrecognized command '+cmdName);},focusSelected_:function(){if(!this.selectedTableRowInfo_)
+return;var node=this.getSelectableNodeGivenTableRowNode_(this.selectedTableRowInfo_.htmlNode);node.focus();},dispatchSortingChangedEvent_:function(){var e=new tr.b.Event('sort-column-changed');e.sortColumnIndex=this.sortColumnIndex_;e.sortDescending=this.sortDescending_;this.dispatchEvent(e);}});})();'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.asHTMLO [...]
 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))
@@ -2654,17 +5841,26 @@ function findDeepElementMatching(element,selector){return findDeepElementMatchin
 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;}
+return{iterateElementDeeply:iterateElementDeeply,findDeepElementMatching:findDeepElementMatching,findDeepElementsMatching:findDeepElementsMatching,findDeepElementMatchingPredicate:findDeepElementMatchingPredicate,findDeepElementsMatchingPredicate:findDeepElementsMatchingPredicate,findDeepElementWithTextContent:findDeepElementWithTextContent};});'use strict';tr.exportTo('tr.ui.b',function(){function getPolymerElementNamed(tagName){for(var i=0;i<Polymer.elements.length;i++){if(Polymer.elem [...]
+return Polymer.elements[i];}}
+function getPolymerElementsThatSubclass(tagName){if(Polymer.waitingFor().length){throw new Error('There are unresolved polymer elements. '+'Wait until Polymer.whenReady');}
+var baseElement;var elementNamesThatExtend={};Polymer.elements.forEach(function(element){if(element.name===tagName)
+baseElement=element;if(element.extends){if(elementNamesThatExtend[element.extends]===undefined)
+elementNamesThatExtend[element.extends]=[];elementNamesThatExtend[element.extends].push(element.name);}});if(!baseElement)
+throw new Error(tagName+' is not a polymer element');var allFoundSubElementNames=[baseElement.name];for(var i=0;i<allFoundSubElementNames.length;i++){var elementName=allFoundSubElementNames[i];allFoundSubElementNames.push.apply(allFoundSubElementNames,elementNamesThatExtend[elementName]);}
+allFoundSubElementNames.shift();return allFoundSubElementNames;}
+return{getPolymerElementNamed:getPolymerElementNamed,getPolymerElementsThatSubclass:getPolymerElementsThatSubclass};});'use strict';tr.exportTo('tr.v.ui',function(){function createScalarSpan(value,opt_config){if(value===undefined)
+return'';var config=opt_config||{};var ownerDocument=config.ownerDocument||document;var span=ownerDocument.createElement('tr-v-ui-scalar-span');var numericValue;if(value instanceof tr.v.ScalarNumeric){span.value=value;numericValue=value.value;}else{var unit=config.unit;if(unit===undefined){throw new Error('Unit must be provided in config when value is a number');}
+span.setValueAndUnit(value,unit);numericValue=value;}
+if(config.total)
+span.percentage=numericValue/config.total;if(config.rightAlign)
+span.rightAlign=true;return span;}
+tr.v.Unit.addEventListener('display-mode-changed',function(e){var scalarSpanTagName='tr-v-ui-scalar-span';var subclassNames=tr.ui.b.getPolymerElementsThatSubclass(scalarSpanTagName);subclassNames.push(scalarSpanTagName);var isSubclass={};subclassNames.forEach(function(n){isSubclass[n.toUpperCase()]=true;});var m=tr.b.findDeepElementsMatchingPredicate(document.body,function(el){return isSubclass[el.tagName];});m.forEach(function(el){el.updateContent_();});});return{createScalarSpan:create [...]
+this.updateContent_();},get unit(){return this.unit_;},set unit(unit){this.unit_=unit;this.updateContent_();},setValueAndUnit:function(value,unit){this.value_=value;this.unit_=unit;this.updateContent_();},get percentage(){return this.percentage_;},set percentage(percentage){this.percentage_=percentage;this.updateSparkline_();},get rightAlign(){return this.$.content.classList.contains('right-align');},set rightAlign(rightAlign){if(rightAlign)
+this.$.content.classList.add('right-align');else
+this.$.content.classList.remove('right-align');},updateSparkline_:function(){if(this.percentage_===undefined){this.$.sparkline.style.display='none';this.$.sparkline.style.width='0';}else{this.$.sparkline.style.display='block';this.$.sparkline.style.width=(this.percentage_*100)+'%';}},updateContent_:function(){if(this.unit_===undefined){this.$.content.textContent='';this.$.content.style.color='';return;}
+this.$.content.textContent=this.unit_.format(this.value);var BIGGER_IS_BETTER=tr.v.ImprovementDirection.BIGGER_IS_BETTER;var SMALLER_IS_BETTER=tr.v.ImprovementDirection.SMALLER_IS_BETTER;var color='';if(this.unit_.isDelta){var improvementDirection=this.unit_.improvementDirection;if(this.value>0){switch(improvementDirection){case BIGGER_IS_BETTER:color='green';break;case SMALLER_IS_BETTER:color='red';break;}}else if(this.value<0){switch(improvementDirection){case BIGGER_IS_BETTER:color='r [...]
+this.$.content.style.color=color;},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';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;}
@@ -2675,103 +5871,1153 @@ if(!(object instanceof Object)){var type=typeof object;if(type=='string'){var ob
 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.model.ObjectSnapshot){var link=document.createElement('tr-ui-a-analysis-link');link.selection=new tr.model.EventSet(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.model.EventSet(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 tr.v.ScalarNumeric){var el=this.ownerDocument.createElement('tr-v-ui-scalar-span');el.value=object;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 [...]
+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 [...]
+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();}});'use strict';tr.exportTo('tr.ui.b',function(){function HotKey(dict){if(dict.eventType===u [...]
+throw new Error('eventType must be given');if(dict.keyCode===undefined&&dict.keyCodes===undefined)
+throw new Error('keyCode or keyCodes must be given');if(dict.keyCode!==undefined&&dict.keyCodes!==undefined)
+throw new Error('Only keyCode or keyCodes can be given');if(dict.callback===undefined)
+throw new Error('callback must be given');this.eventType_=dict.eventType;this.keyCodes_=[];if(dict.keyCode)
+this.pushKeyCode_(dict.keyCode);else if(dict.keyCodes){dict.keyCodes.forEach(this.pushKeyCode_,this);}
+this.useCapture_=!!dict.useCapture;this.callback_=dict.callback;this.thisArg_=dict.thisArg!==undefined?dict.thisArg:undefined;this.helpText_=dict.helpText!==undefined?dict.helpText:undefined;}
+HotKey.prototype={get eventType(){return this.eventType_;},get keyCodes(){return this.keyCodes_;},get helpText(){return this.helpText_;},call:function(e){this.callback_.call(this.thisArg_,e);},pushKeyCode_:function(keyCode){this.keyCodes_.push(keyCode);}};return{HotKey:HotKey};});'use strict';Polymer('tv-ui-b-hotkey-controller',{created:function(){this.isAttached_=false;this.globalMode_=false;this.slavedToParentController_=undefined;this.curHost_=undefined;this.childControllers_=[];this. [...]
+throw new Error('Multiple hotkey controllers attached to this host');host.__hotkeyController=this;this.curHost_=host;var parentElement;if(host.parentElement)
+parentElement=host.parentElement;else
+parentElement=host.parentNode.host;var parentController=tr.b.getHotkeyControllerForElement(parentElement);if(parentController){this.slavedToParentController_=parentController;parentController.addChildController_(this);return;}
+host.addEventListener('keydown',this.onBubblingKeyDown_,false);host.addEventListener('keydown',this.onCapturingKeyDown_,true);host.addEventListener('keypress',this.onBubblingKeyPress_,false);host.addEventListener('keypress',this.onCapturingKeyPress_,true);},detached:function(){this.isAttached_=false;var host=this.curHost_;if(!host)
+return;delete host.__hotkeyController;this.curHost_=undefined;if(this.slavedToParentController_){this.slavedToParentController_.removeChildController_(this);this.slavedToParentController_=undefined;return;}
+host.removeEventListener('keydown',this.onBubblingKeyDown_,false);host.removeEventListener('keydown',this.onCapturingKeyDown_,true);host.removeEventListener('keypress',this.onBubblingKeyPress_,false);host.removeEventListener('keypress',this.onCapturingKeyPress_,true);},addChildController_:function(controller){var i=this.childControllers_.indexOf(controller);if(i!==-1)
+throw new Error('Controller already registered');this.childControllers_.push(controller);},removeChildController_:function(controller){var i=this.childControllers_.indexOf(controller);if(i===-1)
+throw new Error('Controller not registered');this.childControllers_.splice(i,1);return controller;},getKeyMapForEventType_:function(eventType,useCapture){if(eventType==='keydown'){if(!useCapture)
+return this.bubblingKeyDownHotKeys_;else
+return this.capturingKeyDownHotKeys_;}else if(eventType==='keypress'){if(!useCapture)
+return this.bubblingKeyPressHotKeys_;else
+return this.capturingKeyPressHotKeys_;}else{throw new Error('Unsupported key event');}},addHotKey:function(hotKey){if(!(hotKey instanceof tr.ui.b.HotKey))
+throw new Error('hotKey must be a tr.ui.b.HotKey');var keyMap=this.getKeyMapForEventType_(hotKey.eventType,hotKey.useCapture);for(var i=0;i<hotKey.keyCodes.length;i++){var keyCode=hotKey.keyCodes[i];if(keyMap[keyCode])
+throw new Error('Key is already bound for keyCode='+keyCode);}
+for(var i=0;i<hotKey.keyCodes.length;i++){var keyCode=hotKey.keyCodes[i];keyMap[keyCode]=hotKey;}
+return hotKey;},removeHotKey:function(hotKey){if(!(hotKey instanceof tr.ui.b.HotKey))
+throw new Error('hotKey must be a tr.ui.b.HotKey');var keyMap=this.getKeyMapForEventType_(hotKey.eventType,hotKey.useCapture);for(var i=0;i<hotKey.keyCodes.length;i++){var keyCode=hotKey.keyCodes[i];if(!keyMap[keyCode])
+throw new Error('Key is not bound for keyCode='+keyCode);keyMap[keyCode]=hotKey;}
+for(var i=0;i<hotKey.keyCodes.length;i++){var keyCode=hotKey.keyCodes[i];delete keyMap[keyCode];}
+return hotKey;},get globalMode(){return this.globalMode_;},set globalMode(globalMode){var wasAttached=this.isAttached_;if(wasAttached)
+this.detached();this.globalMode_=!!globalMode;if(wasAttached)
+this.attached();},get topmostConroller_(){if(this.slavedToParentController_)
+return this.slavedToParentController_.topmostConroller_;return this;},childRequestsGeneralFocus:function(child){var topmost=this.topmostConroller_;if(topmost.curHost_){if(topmost.curHost_.hasAttribute('tabIndex')){topmost.curHost_.focus();}else{if(document.activeElement)
+document.activeElement.blur();}}else{if(document.activeElement)
+document.activeElement.blur();}},childRequestsBlur:function(child){child.blur();var topmost=this.topmostConroller_;if(topmost.curHost_){topmost.curHost_.focus();}},findHost_:function(){if(this.globalMode_){return document.body;}else{if(this.parentElement)
+return this.parentElement;var node=this;while(node.parentNode){node=node.parentNode;}
+return node.host;}},appendMatchingHotKeysTo_:function(matchedHotKeys,useCapture,e){var localKeyMap=this.getKeyMapForEventType_(e.type,useCapture);var localHotKey=localKeyMap[e.keyCode];if(localHotKey)
+matchedHotKeys.push(localHotKey);for(var i=0;i<this.childControllers_.length;i++){var controller=this.childControllers_[i];controller.appendMatchingHotKeysTo_(matchedHotKeys,useCapture,e);}},onKey_:function(useCapture,e){if(useCapture==false&&e.path[0].tagName=='INPUT')
+return;var sortedControllers;var matchedHotKeys=[];this.appendMatchingHotKeysTo_(matchedHotKeys,useCapture,e);if(matchedHotKeys.length===0)
+return false;if(matchedHotKeys.length>1){throw new Error('More than one hotKey is currently unsupported');}
+var hotKey=matchedHotKeys[0];var prevented=0;prevented|=hotKey.call(e);return!prevented&&e.defaultPrevented;}});'use strict';tr.exportTo('tr.b',function(){function getHotkeyControllerForElement(refElement){var curElement=refElement;while(curElement){if(curElement.tagName==='tv-ui-b-hotkey-controller')
+return curElement;if(curElement.__hotkeyController)
+return curElement.__hotkeyController;if(curElement.parentElement){curElement=curElement.parentElement;continue;}
+curElement=findHost(curElement);}
+return undefined;}
+function findHost(initialNode){var node=initialNode;while(node.parentNode){node=node.parentNode;}
+return node.host;}
+return{getHotkeyControllerForElement:getHotkeyControllerForElement};});'use strict';Polymer('tr-ui-b-info-bar',{ready:function(){this.messageEl_=this.$.message;this.buttonsEl_=this.$.buttons;this.message='';this.visible=false;},get message(){return this.messageEl_.textContent;},set message(message){this.messageEl_.textContent=message;},get visible(){return!this.classList.contains('info-bar-hidden');},set visible(visible){if(visible)
+this.classList.remove('info-bar-hidden');else
+this.classList.add('info-bar-hidden');},removeAllButtons:function(){this.buttonsEl_.textContent='';},addButton:function(text,clickCallback){var button=document.createElement('button');button.textContent=text;button.addEventListener('click',clickCallback);this.buttonsEl_.appendChild(button);return button;}});'use strict';tr.exportTo('tr.ui.b',function(){var ContainerThatDecoratesItsChildren=tr.ui.b.define('div');ContainerThatDecoratesItsChildren.prototype={__proto__:HTMLUnknownElement.pro [...]
+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.b',function(){var ListView=tr.ui.b.define('x-list-view',tr.ui.b.ContainerThatDecoratesItsChildren);ListView.prototype={__proto__:tr.ui.b.Container [...]
+listView.selectedElement.removeAttribute('selected');if(value)
+this.setAttribute('selected','selected');else
+this.removeAttribute('selected');var newSelection=listView.selectedElement;if(newSelection!=oldSelection)
+tr.b.dispatchSimpleEvent(listView,'selection-changed',false);},get:function(){return this.hasAttribute('selected');}});},undecorateChild_:function(item){this.selectionChanged_|=item.selected;item.classList.remove('list-item');item.removeEventListener('click',this.onItemClicked_);delete item.selected;},beginDecorating_:function(){this.selectionChanged_=false;},doneDecoratingForNow_:function(){if(this.selectionChanged_)
+tr.b.dispatchSimpleEvent(this,'selection-changed',false);},get selectedElement(){var el=this.querySelector('.list-item[selected]');if(!el)
+return undefined;return el;},set selectedElement(el){if(!el){if(this.selectedElement)
+this.selectedElement.selected=false;return;}
+if(el.parentElement!=this)
+throw new Error('Can only select elements that are children of this list view');el.selected=true;},getElementByIndex:function(index){return this.querySelector('.list-item:nth-child('+index+')');},clear:function(){var changed=this.selectedElement!==undefined;tr.ui.b.ContainerThatDecoratesItsChildren.prototype.clear.call(this);if(changed)
+tr.b.dispatchSimpleEvent(this,'selection-changed',false);},onItemClicked_:function(e){var currentSelectedElement=this.selectedElement;if(currentSelectedElement)
+currentSelectedElement.removeAttribute('selected');var element=e.target;while(element.parentElement!=this)
+element=element.parentElement;if(element!==currentSelectedElement)
+element.setAttribute('selected','selected');tr.b.dispatchSimpleEvent(this,'selection-changed',false);},onKeyDown_:function(e){if(this.selectedElement===undefined)
+return;if(e.keyCode==38){var prev=this.selectedElement.previousSibling;if(prev){prev.selected=true;tr.ui.b.scrollIntoViewIfNeeded(prev);e.preventDefault();return true;}}else if(e.keyCode==40){var next=this.selectedElement.nextSibling;if(next){next.selected=true;tr.ui.b.scrollIntoViewIfNeeded(next);e.preventDefault();return true;}}},addItem:function(textContent){var item=document.createElement('div');item.textContent=textContent;this.appendChild(item);return item;}};return{ListView:ListVi [...]
+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 [...]
+document.removeEventListener('keyup',opt_keyUpHandler);document.removeEventListener('mouseup',cleanupAndDispatchToMouseUp);if(opt_mouseUpHandler)
+opt_mouseUpHandler(e);}
+document.addEventListener('mousemove',mouseMoveHandler);if(opt_keyUpHandler)
+document.addEventListener('keyup',opt_keyUpHandler);document.addEventListener('mouseup',cleanupAndDispatchToMouseUp);}
+return{MouseTracker:MouseTracker,trackMouseMovesUntilMouseUp:trackMouseMovesUntilMouseUp};});'use strict';tr.exportTo('tr.ui.b',function(){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 MOUSE_SELECTOR_MODE_INFOS={};MOUSE_SELECTOR_MODE_INFOS[MOUSE_SELECTOR_MODE.PANSCAN]={mode:MOUSE_SELECTOR_MODE.PANSCAN,title:'pan' [...]
+throw new Error('Unknown mode');this.modeName=modeName;},modeNameChanged:function(){this.updateContents_();},get active(){return this.active_;},set active(active){this.active_=!!active;if(this.active_)
+this.classList.add('active');else
+this.classList.remove('active');this.updateContents_();},get acceleratorKey(){return this.acceleratorKey_;},set acceleratorKey(acceleratorKey){this.acceleratorKey_=acceleratorKey;this.updateContents_();},updateContents_:function(){if(this.modeName===undefined)
+return;var mode=this.mode;if(mode===undefined)
+throw new Error('Invalid mode');var modeInfo=tr.ui.b.MOUSE_SELECTOR_MODE_INFOS[mode];if(!modeInfo)
+throw new Error('Invalid mode');var title=modeInfo.title;if(this.acceleratorKey_)
+title=title+' ('+this.acceleratorKey_+')';this.title=title;var bp;if(this.active_)
+bp=modeInfo.activeBackgroundPosition;else
+bp=modeInfo.defaultBackgroundPosition;this.style.backgroundPosition=bp;}});'use strict';tr.exportTo('tr.ui.b',function(){var MOUSE_SELECTOR_MODE=tr.ui.b.MOUSE_SELECTOR_MODE;var MOUSE_SELECTOR_MODE_INFOS=tr.ui.b.MOUSE_SELECTOR_MODE_INFOS;var MIN_MOUSE_SELECTION_DISTANCE=4;var MODIFIER={SHIFT:0x1,SPACE:0x2,CMD_OR_CTRL:0x4};function isCmdOrCtrlPressed(event){if(tr.isMac)
+return event.metaKey;else
+return event.ctrlKey;}
+Polymer('tr-ui-b-mouse-mode-selector',{__proto__:HTMLDivElement.prototype,created:function(){this.supportedModeMask_=MOUSE_SELECTOR_MODE.ALL_MODES;this.initialRelativeMouseDownPos_={x:0,y:0};this.defaultMode_=MOUSE_SELECTOR_MODE.PANSCAN;this.settingsKey_=undefined;this.mousePos_={x:0,y:0};this.mouseDownPos_={x:0,y:0};this.onMouseDown_=this.onMouseDown_.bind(this);this.onMouseMove_=this.onMouseMove_.bind(this);this.onMouseUp_=this.onMouseUp_.bind(this);this.onKeyDown_=this.onKeyDown_.bind [...]
+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(MOUSE_SELECTOR_MODE_INFOS[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){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;var button=document.createElement('tr-ui-b-mouse-mode-icon');button.mode=mode;button.classList.add('tool-button');this.buttonsEl_.appendChild(button);}},getButtonForMode_:function(mode){for(var i=0;i<this.buttonsEl_.children.length;i++){var buttonEl=this.buttonsEl_.children[i];if(buttonEl.mode===mode)
+return buttonEl;}
+return undefined;},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(MOUSE_SELECTOR_MODE_INFOS[newMode]===undefined)
+throw new Error('Unrecognized mode');}
+var modeInfo;if(this.currentMode_===newMode)
+return;if(this.currentMode_){var buttonEl=this.getButtonForMode_(this.currentMode_);if(buttonEl)
+buttonEl.active=false;if(this.isInteracting_){var mouseEvent=this.createEvent_(MOUSE_SELECTOR_MODE_INFOS[this.mode].eventNames.end);this.dispatchEvent(mouseEvent);}
+modeInfo=MOUSE_SELECTOR_MODE_INFOS[this.currentMode_];tr.b.dispatchSimpleEvent(this,modeInfo.eventNames.exit,true);}
+this.currentMode_=newMode;if(this.currentMode_){var buttonEl=this.getButtonForMode_(this.currentMode_);if(buttonEl)
+buttonEl.active=true;this.mouseDownPos_.x=this.mousePos_.x;this.mouseDownPos_.y=this.mousePos_.y;modeInfo=MOUSE_SELECTOR_MODE_INFOS[this.currentMode_];if(!this.isInAlternativeMode_)
+tr.b.dispatchSimpleEvent(this,modeInfo.eventNames.enter,true);if(this.isInteracting_){var mouseEvent=this.createEvent_(MOUSE_SELECTOR_MODE_INFOS[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 buttonEl=this.getButtonForMode_(mode);if(buttonEl)
+buttonEl.acceleratorKey=String.fromCharCode(keyCode);},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=this.mousePos_.y;event.deltaX=this.mousePos_.x-this.mouseDownPos_.x;event.deltaY=this.mousePos_.y-this.mouseDownPos_.y;event.mouseDownX=this.mouseDownPos_.x;event.mouseDownY=this.mouseDownPos_.y;event.didPreve [...]
+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_(MOUSE_SELECTOR_MODE_INFOS[this.mode].eventNames.begin,e);if(this.mode===MOUSE_SELECTOR_MODE.SELECTION)
+mouseEvent.appendSelection=isCmdOrCtrlPressed(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_(MOUSE_SELECTOR_MODE_INFOS[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_(MOUSE_SELECTOR_MODE_INFOS[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.path[0].tagName=='INPUT')
+return;if(e.keyCode===' '.charCodeAt(0))
+this.spacePressed_=true;this.updateAlternativeModeState_(e);},onKeyUp_:function(e){if(e.path[0].tagName=='INPUT')
+return;if(e.keyCode===' '.charCodeAt(0))
+this.spacePressed_=false;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=isCmdOrCtrlPressed(e);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_[MODIFIER.SPACE]&smm)!==0){newM [...]
+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 modeInfo=MOUSE_SELECTOR_MODE_INFOS[MOUSE_SELECTOR_MODE.SELECTION];var eventNames=modeInfo.eventNames;var mouseEvent=this.createEvent_(eventNames.begin);mouseEvent.appendSelection=isCmdOrCtrlPressed(e);this.dispatchEvent(mouseEvent);mouseEvent=this.createEvent_(eventNames.end);this.dispatchEvent(mouseEvent);}});return{MIN_MOUSE_SELECTION_DISTANCE:MIN_MOUSE_SELECTION_DISTANCE,MODIFIER:MODIFIER};});'use strict';(function(){var DETAILS_SPLIT_REGEX=/^(\S*)\s*([\S\s]*)$/;Polymer('tr [...]
+throw new Error('Render pass (with id) is required');this.renderPass_=renderPass;this.renderPassId_=renderPassId;}
+RenderPassSelection.prototype={__proto__:Selection.prototype,get specicifity(){return 1;},get associatedLayerId(){return undefined;},get associatedRenderPassId(){return this.renderPassId_;},get renderPass(){return this.renderPass_;},createAnalysis:function(){var dataView=document.createElement('tr-ui-a-generic-object-view-with-label');dataView.label='RenderPass '+this.renderPassId_;dataView.object=this.renderPass_.args;return dataView;},get title(){return this.renderPass_.objectInstance. [...]
+throw new Error('Layer is required');this.layer_=layer;}
+LayerSelection.prototype={__proto__:Selection.prototype,get specicifity(){return 1;},get associatedLayerId(){return this.layer_.layerId;},get associatedRenderPassId(){return undefined;},get layer(){return this.layer_;},createAnalysis:function(){var dataView=document.createElement('tr-ui-a-generic-object-view-with-label');dataView.label='Layer '+this.layer_.layerId;if(this.layer_.usingGpuRasterization)
+dataView.label+=' (GPU-rasterized)';dataView.object=this.layer_.args;return dataView;},get title(){return this.layer_.objectInstance.typeName;},findEquivalent:function(lthi){var layer=lthi.activeTree.findLayerWithId(this.layer_.layerId)||lthi.pendingTree.findLayerWithId(this.layer_.layerId);if(!layer)
+return undefined;return new LayerSelection(layer);}};function TileSelection(tile,opt_data){this.tile_=tile;this.data_=opt_data||{};}
+TileSelection.prototype={__proto__:Selection.prototype,get specicifity(){return 2;},get associatedLayerId(){return this.tile_.layerId;},get highlightsByLayerId(){var highlights={};highlights[this.tile_.layerId]=[{colorKey:this.tile_.objectInstance.typeName,rect:this.tile_.layerRect}];return highlights;},createAnalysis:function(){var analysis=document.createElement('tr-ui-a-generic-object-view-with-label');analysis.label='Tile '+this.tile_.objectInstance.id+' on layer '+
+this.tile_.layerId;if(this.data_){analysis.object={moreInfo:this.data_,tileArgs:this.tile_.args};}else{analysis.object=this.tile_.args;}
+return analysis;},findEquivalent:function(lthi){var tileInstance=this.tile_.tileInstance;if(lthi.ts<tileInstance.creationTs||lthi.ts>=tileInstance.deletionTs)
+return undefined;var tileSnapshot=tileInstance.getSnapshotAt(lthi.ts);if(!tileSnapshot)
+return undefined;return new TileSelection(tileSnapshot);}};function LayerRectSelection(layer,rectType,rect,opt_data){this.layer_=layer;this.rectType_=rectType;this.rect_=rect;this.data_=opt_data!==undefined?opt_data:rect;}
+LayerRectSelection.prototype={__proto__:Selection.prototype,get specicifity(){return 2;},get associatedLayerId(){return this.layer_.layerId;},get highlightsByLayerId(){var highlights={};highlights[this.layer_.layerId]=[{colorKey:this.rectType_,rect:this.rect_}];return highlights;},createAnalysis:function(){var analysis=document.createElement('tr-ui-a-generic-object-view-with-label');analysis.label=this.rectType_+' on layer '+this.layer_.layerId;analysis.object=this.data_;return analysis; [...]
+AnimationRectSelection.prototype={__proto__:Selection.prototype,get specicifity(){return 0;},get associatedLayerId(){return this.layer_.layerId;},createAnalysis:function(){var analysis=document.createElement('tr-ui-a-generic-object-view-with-label');analysis.label='Animation Bounds of layer '+this.layer_.layerId;analysis.object=this.rect_;return analysis;}};return{Selection:Selection,RenderPassSelection:RenderPassSelection,LayerSelection:LayerSelection,TileSelection:TileSelection,LayerRe [...]
+return;var ops=this.picture_.getOps();if(!ops)
+return;ops=this.picture_.tagOpsWithTimings(ops);ops=this.opsTaggedWithAnnotations_(ops);for(var i=0;i<ops.length;i++){var op=ops[i];var item=document.createElement('div');item.opIndex=op.opIndex;item.textContent=i+') '+op.cmd_string;if(op.elementInfo.tag||op.elementInfo.id||op.elementInfo.class){var elementInfo=document.createElement('span');elementInfo.classList.add('elementInfo');var tag=op.elementInfo.tag?op.elementInfo.tag:'unknown';var id=op.elementInfo.id?'id='+op.elementInfo.id:un [...]
+op.elementInfo.class:undefined;elementInfo.textContent='<'+tag+(id?' ':'')+
+(id?id:'')+(className?' ':'')+
+(className?className:'')+'>';item.appendChild(elementInfo);}
+if(op.info.length>0){var infoItem=document.createElement('div');infoItem.textContent=JSON.stringify(op.info);item.appendChild(infoItem);}
+if(op.cmd_time&&op.cmd_time>=0.0001){var time=document.createElement('span');time.classList.add('time');var rounded=op.cmd_time.toFixed(4);time.textContent='('+rounded+'ms)';item.appendChild(time);}
+this.opsList_.appendChild(item);}},onSelectionChanged_:function(e){var beforeSelectedOp=true;if(this.opsList_.selectedElement===this.selectedOp_){this.opsList_.selectedElement=undefined;beforeSelectedOp=false;this.selectedOpIndex_=undefined;}
+this.selectedOp_=this.opsList_.selectedElement;var ops=this.opsList_.children;for(var i=0;i<ops.length;i++){var op=ops[i];if(op===this.selectedOp_){beforeSelectedOp=false;this.selectedOpIndex_=op.opIndex;}else if(beforeSelectedOp){op.setAttribute('beforeSelection','beforeSelection');}else{op.removeAttribute('beforeSelection');}}
+tr.b.dispatchSimpleEvent(this,'selection-changed',false);},get numOps(){return this.opsList_.children.length;},get selectedOpIndex(){return this.selectedOpIndex_;},set selectedOpIndex(s){this.selectedOpIndex_=s;if(s===undefined){this.opsList_.selectedElement=this.selectedOp_;this.onSelectionChanged_();}else{if(s<0)throw new Error('Invalid index');if(s>=this.numOps)throw new Error('Invalid index');this.opsList_.selectedElement=this.opsList_.getElementByIndex(s+1);tr.ui.b.scrollIntoViewIfN [...]
+elementInfo.tag=info.substring(info.indexOf(ANNOTATION_TAG)+
+ANNOTATION_TAG.length).toLowerCase();else if(info.indexOf(ANNOTATION_ID)!=-1)
+elementInfo.id=info.substring(info.indexOf(ANNOTATION_ID)+
+ANNOTATION_ID.length);else if(info.indexOf(ANNOTATION_CLASS)!=-1)
+elementInfo.class=info.substring(info.indexOf(ANNOTATION_CLASS)+
+ANNOTATION_CLASS.length);annotations.push(info);});});});op.annotations=annotations;op.elementInfo=elementInfo;opsWithoutAnnotations.push(op);}}
+return opsWithoutAnnotations;}};return{PictureOpsListView:PictureOpsListView};});'use strict';tr.exportTo('tr.ui.e.chrome.cc',function(){var THIS_DOC=document.currentScript.ownerDocument;var DisplayItemDebugger=tr.ui.b.define('tr-ui-e-chrome-cc-display-item-debugger');DisplayItemDebugger.prototype={__proto__:HTMLUnknownElement.prototype,decorate:function(){var node=tr.ui.b.instantiateTemplate('#tr-ui-e-chrome-cc-display-item-debugger-template',THIS_DOC);this.appendChild(node);this.pictur [...]
+var bounds=this.rasterArea_.getBoundingClientRect();var selectorBounds=this.mouseModeSelector_.getBoundingClientRect();this.mouseModeSelector_.pos={x:(bounds.right-selectorBounds.width-10),y:bounds.top};this.rasterize_();this.scheduleUpdateContents_();},getRasterCanvasSize_:function(){var style=window.getComputedStyle(this.rasterArea_);var width=parseInt(style.width);var height=parseInt(style.height);if(this.picture_){width=Math.max(width,this.picture_.layerRect.width);height=Math.max(he [...]
+return{width:width,height:height};},scheduleUpdateContents_:function(){if(this.updateContentsPending_)
+return;this.updateContentsPending_=true;tr.b.requestAnimationFrameInThisFrameIfPossible(this.updateContents_.bind(this));},updateContents_:function(){this.updateContentsPending_=false;if(this.picture_){this.sizeInfo_.textContent='('+
+this.picture_.layerRect.width+' x '+
+this.picture_.layerRect.height+')';}
+if(!this.pictureAsImageData_)
+return;this.infoBar_.visible=false;this.infoBar_.removeAllButtons();if(this.pictureAsImageData_.error){this.infoBar_.message='Cannot rasterize...';this.infoBar_.addButton('More info...',function(e){var overlay=new tr.ui.b.Overlay();overlay.textContent=this.pictureAsImageData_.error;overlay.visible=true;e.stopPropagation();return false;}.bind(this));this.infoBar_.visible=true;}
+this.drawPicture_();},drawPicture_:function(){var size=this.getRasterCanvasSize_();if(size.width!==this.rasterCanvas_.width)
+this.rasterCanvas_.width=size.width;if(size.height!==this.rasterCanvas_.height)
+this.rasterCanvas_.height=size.height;this.rasterCtx_.clearRect(0,0,size.width,size.height);if(!this.picture_||!this.pictureAsImageData_.imageData)
+return;var imgCanvas=this.pictureAsImageData_.asCanvas();var w=imgCanvas.width;var h=imgCanvas.height;this.rasterCtx_.drawImage(imgCanvas,0,0,w,h,0,0,w*this.zoomScaleValue_,h*this.zoomScaleValue_);},rasterize_:function(){if(this.picture_){this.picture_.rasterize({showOverdraw:false},this.onRasterComplete_.bind(this));}},onRasterComplete_:function(pictureAsImageData){this.pictureAsImageData_=pictureAsImageData;this.scheduleUpdateContents_();},onDisplayItemListSelection_:function(e){var se [...]
+var index=Array.prototype.indexOf.call(this.displayItemListView_.children,selected);var displayItem=this.displayItemList_.items[index];if(displayItem&&displayItem.skp64)
+this.picture=new tr.e.cc.Picture(displayItem.skp64,this.displayItemList_.layerRect);else
+this.picture=undefined;},onDisplayItemInfoClick_:function(e){if(e&&e.target==this.displayItemInfo_){this.displayItemListView_.selectedElement=undefined;}},updateDrawOpsList_:function(showOpsList){if(showOpsList){this.pictureOpsListView_.picture=this.picture_;if(this.pictureOpsListView_.numOps>0){this.pictureOpsListView_.classList.add('hasPictureOps');this.pictureOpsListDragHandle_.classList.add('hasPictureOps');}}else{this.pictureOpsListView_.classList.remove('hasPictureOps');this.pictur [...]
+return;var currentMouseViewPos=this.extractRelativeMousePosition_(e);this.zoomScaleValue_+=((this.lastMouseViewPos_.y-currentMouseViewPos.y)*0.001);this.zoomScaleValue_=Math.max(this.zoomScaleValue_,0.1);this.drawPicture_();this.lastMouseViewPos_=currentMouseViewPos;},onEndZoom_:function(e){this.lastMouseViewPos_=undefined;this.isZooming_=false;e.preventDefault();},extractRelativeMousePosition_:function(e){return{x:e.clientX-this.rasterArea_.offsetLeft,y:e.clientY-this.rasterArea_.offset [...]
+return;var length=rawData.length;var arrayBuffer=new ArrayBuffer(length);var uint8Array=new Uint8Array(arrayBuffer);for(var c=0;c<length;c++)
+uint8Array[c]=rawData.charCodeAt(c);var blob=new Blob([uint8Array],{type:'application/octet-binary'});var blobUrl=window.URL.createObjectURL(blob);var link=document.createElementNS('http://www.w3.org/1999/xhtml','a');link.href=blobUrl;link.download=filename;var event=document.createEvent('MouseEvents');event.initMouseEvent('click',true,false,window,0,0,0,0,0,false,false,false,false,0,null);link.dispatchEvent(event);},onExportDisplayListClicked_:function(){var rawData=JSON.stringify(this. [...]
+this.displayItemDebugger_.displayItemList=this.objectSnapshot_;}};tr.ui.analysis.ObjectSnapshotView.register(DisplayItemSnapshotView,{typeNames:['cc::DisplayItemList'],showInstances:false});return{DisplayItemSnapshotView:DisplayItemSnapshotView};});'use strict';tr.exportTo('tr.ui.e.chrome.cc',function(){var constants=tr.e.cc.constants;var bytesToRoundedMegabytes=tr.e.cc.bytesToRoundedMegabytes;var RENDER_PASS_QUADS=Math.max(constants.ACTIVE_TREE,constants.PENDING_TREE)+1;var LayerPicker= [...]
+return undefined;return this.lthiSnapshot.getTree(this.whichTree);},get isRenderPassQuads(){return this.renderPassQuads_;},get showPureTransformLayers(){return this.showPureTransformLayers_;},set showPureTransformLayers(show){if(this.showPureTransformLayers_===show)
+return;this.showPureTransformLayers_=show;this.updateContents_();},getRenderPassInfos_:function(){if(!this.lthiSnapshot_)
+return[];var renderPassInfo=[];if(!this.lthiSnapshot_.args.frame||!this.lthiSnapshot_.args.frame.renderPasses)
+return renderPassInfo;var renderPasses=this.lthiSnapshot_.args.frame.renderPasses;for(var i=0;i<renderPasses.length;++i){var info={renderPass:renderPasses[i],depth:0,id:i,name:'cc::RenderPass'};renderPassInfo.push(info);}
+return renderPassInfo;},getLayerInfos_:function(){if(!this.lthiSnapshot_)
+return[];var tree=this.lthiSnapshot_.getTree(this.whichTree_);if(!tree)
+return[];var layerInfos=[];var showPureTransformLayers=this.showPureTransformLayers_;function isPureTransformLayer(layer){if(layer.args.compositingReasons&&layer.args.compositingReasons.length!=1&&layer.args.compositingReasons[0]!='No reasons given')
+return false;if(layer.args.drawsContent)
+return false;return true;}
+var visitedLayers={};function visitLayer(layer,depth,isMask,isReplica){if(visitedLayers[layer.layerId])
+return;visitedLayers[layer.layerId]=true;var info={layer:layer,depth:depth};if(layer.args.drawsContent)
+info.name=layer.objectInstance.name;else
+info.name='cc::LayerImpl';if(layer.usingGpuRasterization)
+info.name+=' (G)';info.isMaskLayer=isMask;info.replicaLayer=isReplica;if(showPureTransformLayers||!isPureTransformLayer(layer))
+layerInfos.push(info);};tree.iterLayers(visitLayer);return layerInfos;},updateContents_:function(){if(this.renderPassQuads_)
+this.updateRenderPassContents_();else
+this.updateLayerContents_();},updateRenderPassContents_:function(){this.itemList_.clear();var selectedRenderPassId;if(this.selection_&&this.selection_.associatedRenderPassId)
+selectedRenderPassId=this.selection_.associatedRenderPassId;var renderPassInfos=this.getRenderPassInfos_();renderPassInfos.forEach(function(renderPassInfo){var renderPass=renderPassInfo.renderPass;var id=renderPassInfo.id;var item=this.createElementWithDepth_(renderPassInfo.depth);var labelEl=item.appendChild(tr.ui.b.createSpan());labelEl.textContent=renderPassInfo.name+' '+id;item.renderPass=renderPass;item.renderPassId=id;this.itemList_.appendChild(item);if(id==selectedRenderPassId){re [...]
+selectedLayerId=this.selection_.associatedLayerId;var layerInfos=this.getLayerInfos_();layerInfos.forEach(function(layerInfo){var layer=layerInfo.layer;var id=layer.layerId;var item=this.createElementWithDepth_(layerInfo.depth);var labelEl=item.appendChild(tr.ui.b.createSpan());labelEl.textContent=layerInfo.name+' '+id;var notesEl=item.appendChild(tr.ui.b.createSpan());if(layerInfo.isMaskLayer)
+notesEl.textContent+='(mask)';if(layerInfo.isReplicaLayer)
+notesEl.textContent+='(replica)';if(layer.gpuMemoryUsageInBytes!==undefined){var rounded=bytesToRoundedMegabytes(layer.gpuMemoryUsageInBytes);if(rounded!==0)
+notesEl.textContent+=' ('+rounded+' MB)';}
+item.layer=layer;this.itemList_.appendChild(item);if(layer.layerId==selectedLayerId){layer.selectionState=tr.model.SelectionState.SELECTED;item.selected=true;}},this);}finally{this.changingItemSelection_=false;}},createElementWithDepth_:function(depth){var item=document.createElement('div');var indentEl=item.appendChild(tr.ui.b.createSpan());indentEl.style.whiteSpace='pre';for(var i=0;i<depth;i++)
+indentEl.textContent=indentEl.textContent+' ';return item;},onItemSelectionChanged_:function(e){if(this.changingItemSelection_)
+return;if(this.renderPassQuads_)
+this.onRenderPassSelected_(e);else
+this.onLayerSelected_(e);tr.b.dispatchSimpleEvent(this,'selection-change',false);},onRenderPassSelected_:function(e){var selectedRenderPass;var selectedRenderPassId;if(this.itemList_.selectedElement){selectedRenderPass=this.itemList_.selectedElement.renderPass;selectedRenderPassId=this.itemList_.selectedElement.renderPassId;}
+if(selectedRenderPass){this.selection_=new tr.ui.e.chrome.cc.RenderPassSelection(selectedRenderPass,selectedRenderPassId);}else{this.selection_=undefined;}},onLayerSelected_:function(e){var selectedLayer;if(this.itemList_.selectedElement)
+selectedLayer=this.itemList_.selectedElement.layer;if(selectedLayer)
+this.selection_=new tr.ui.e.chrome.cc.LayerSelection(selectedLayer);else
+this.selection_=undefined;},get selection(){return this.selection_;},set selection(selection){if(this.selection_==selection)
+return;this.selection_=selection;this.updateContents_();}};return{LayerPicker:LayerPicker};});'use strict';tr.exportTo('tr.e.cc',function(){var ObjectSnapshot=tr.model.ObjectSnapshot;function RenderPassSnapshot(){ObjectSnapshot.apply(this,arguments);}
+RenderPassSnapshot.prototype={__proto__:ObjectSnapshot.prototype,preInitialize:function(){tr.e.cc.preInitializeObject(this);},initialize:function(){tr.e.cc.moveRequiredFieldsFromArgsToToplevel(this,['quadList']);}};ObjectSnapshot.register(RenderPassSnapshot,{typeName:'cc::RenderPass'});return{RenderPassSnapshot:RenderPassSnapshot};});'use strict';tr.exportTo('tr.ui.b',function(){var constants={DEFAULT_SCALE:0.5,DEFAULT_EYE_DISTANCE:10000,MINIMUM_DISTANCE:1000,MAXIMUM_DISTANCE:100000,FOV: [...]
+if(this.deviceRect_){var rect=tr.ui.b.windowRectForElement(this.canvas_).scaleSize(this.pixelRatio_);this.eye_[0]=this.deviceRect_.width/2;this.eye_[1]=this.deviceRect_.height/2;this.gazeTarget_[0]=this.deviceRect_.width/2;this.gazeTarget_[1]=this.deviceRect_.height/2;}
+this.saveCameraToSettings(settings);this.dispatchRenderEvent_();},updatePanByDelta:function(delta){var rect=tr.ui.b.windowRectForElement(this.canvas_).scaleSize(this.pixelRatio_);var eyeVector=[this.eye_[0]-this.gazeTarget_[0],this.eye_[1]-this.gazeTarget_[1],this.eye_[2]-this.gazeTarget_[2]];var length=vec3.length(eyeVector);vec3.normalize(eyeVector,eyeVector);var halfFov=constants.FOV/2;var multiplier=2.0*length*Math.tan(tr.b.deg2rad(halfFov))/rect.height;var up=[0,1,0];var rotMatrix=m [...]
+if(Math.abs(this.gazeTarget_[2])>1e-6){var gazeVector=[-eyeVector[0],-eyeVector[1],-eyeVector[2]];var newLength=tr.b.clamp(-this.eye_[2]/gazeVector[2],constants.MINIMUM_DISTANCE,constants.MAXIMUM_DISTANCE);for(var i=0;i<3;++i)
+this.gazeTarget_[i]=this.eye_[i]+newLength*gazeVector[i];}
+this.saveCameraToSettings(tr.b.SessionSettings());this.dispatchRenderEvent_();},updateZoomByDelta:function(delta){var deltaY=delta[1];deltaY=tr.b.clamp(deltaY,-50,50);var scale=1.0-deltaY/100.0;var eyeVector=[0,0,0];vec3.subtract(eyeVector,this.eye_,this.gazeTarget_);var length=vec3.length(eyeVector);if(length*scale<constants.MINIMUM_DISTANCE)
+scale=constants.MINIMUM_DISTANCE/length;else if(length*scale>constants.MAXIMUM_DISTANCE)
+scale=constants.MAXIMUM_DISTANCE/length;vec3.scale(eyeVector,eyeVector,scale);vec3.add(this.eye_,this.gazeTarget_,eyeVector);this.saveCameraToSettings(tr.b.SessionSettings());this.dispatchRenderEvent_();},updateRotateByDelta:function(delta){delta[0]*=0.5;delta[1]*=0.5;if(Math.abs(this.rotation_[0]+delta[1])>constants.MAXIMUM_TILT)
+return;if(Math.abs(this.rotation_[1]-delta[0])>constants.MAXIMUM_TILT)
+return;var eyeVector=[0,0,0,0];vec3.subtract(eyeVector,this.eye_,this.gazeTarget_);var rotMatrix=mat4.create();mat4.rotate(rotMatrix,rotMatrix,-tr.b.deg2rad(this.rotation_[0]),[1,0,0]);mat4.rotate(rotMatrix,rotMatrix,-tr.b.deg2rad(this.rotation_[1]),[0,1,0]);vec4.transformMat4(eyeVector,eyeVector,rotMatrix);this.rotation_[0]+=delta[1];this.rotation_[1]-=delta[0];mat4.identity(rotMatrix);mat4.rotate(rotMatrix,rotMatrix,tr.b.deg2rad(this.rotation_[1]),[0,1,0]);mat4.rotate(rotMatrix,rotMatr [...]
+return;var delta=this.getMouseDelta_(e,this.lastMousePosition_);this.lastMousePosition_=this.getMousePosition_(e);this.updatePanByDelta(delta);},onPanEnd_:function(e){this.panning_=false;},onZoomBegin_:function(e){this.zooming_=true;var p=this.getMousePosition_(e);this.lastMousePosition_=p;this.zoomPoint_=p;},onZoomUpdate_:function(e){if(!this.zooming_)
+return;var delta=this.getMouseDelta_(e,this.lastMousePosition_);this.lastMousePosition_=this.getMousePosition_(e);this.updateZoomByDelta(delta);},onZoomEnd_:function(e){this.zooming_=false;this.zoomPoint_=undefined;},onRotateBegin_:function(e){this.rotating_=true;this.lastMousePosition_=this.getMousePosition_(e);},onRotateUpdate_:function(e){if(!this.rotating_)
+return;var delta=this.getMouseDelta_(e,this.lastMousePosition_);this.lastMousePosition_=this.getMousePosition_(e);this.updateRotateByDelta(delta);},onRotateEnd_:function(e){this.rotating_=false;},getMousePosition_:function(e){var rect=tr.ui.b.windowRectForElement(this.canvas_);return[(e.clientX-rect.x)*this.pixelRatio_,(e.clientY-rect.y)*this.pixelRatio_];},getMouseDelta_:function(e,p){var newP=this.getMousePosition_(e);return[newP[0]-p[0],newP[1]-p[1]];},dispatchRenderEvent_:function(){ [...]
+function drawTriangleSub(ctx,img,p0,p1,p2,t0,t1,t2,opt_recursion_depth){var depth=opt_recursion_depth||0;var subdivisionIndex=0;if(depth<constants.SUBDIVISION_MINIMUM){subdivisionIndex=7;}else if(depth<constants.SUBDIVISION_RECURSION_DEPTH){if(Math.abs(p0[2]-p1[2])>constants.SUBDIVISION_DEPTH_THRESHOLD)
+subdivisionIndex+=1;if(Math.abs(p0[2]-p2[2])>constants.SUBDIVISION_DEPTH_THRESHOLD)
+subdivisionIndex+=2;if(Math.abs(p1[2]-p2[2])>constants.SUBDIVISION_DEPTH_THRESHOLD)
+subdivisionIndex+=4;}
+var p01=vec4.create();var p02=vec4.create();var p12=vec4.create();var t01=vec2.create();var t02=vec2.create();var t12=vec2.create();for(var i=0;i<2;++i){p0[i]*=p0[2];p1[i]*=p1[2];p2[i]*=p2[2];}
+for(var i=0;i<4;++i){p01[i]=(p0[i]+p1[i])/2;p02[i]=(p0[i]+p2[i])/2;p12[i]=(p1[i]+p2[i])/2;}
+for(var i=0;i<2;++i){p0[i]/=p0[2];p1[i]/=p1[2];p2[i]/=p2[2];p01[i]/=p01[2];p02[i]/=p02[2];p12[i]/=p12[2];}
+for(var i=0;i<2;++i){t01[i]=(t0[i]+t1[i])/2;t02[i]=(t0[i]+t2[i])/2;t12[i]=(t1[i]+t2[i])/2;}
+switch(subdivisionIndex){case 1:drawTriangleSub(ctx,img,p0,p01,p2,t0,t01,t2,depth+1);drawTriangleSub(ctx,img,p01,p1,p2,t01,t1,t2,depth+1);break;case 2:drawTriangleSub(ctx,img,p0,p1,p02,t0,t1,t02,depth+1);drawTriangleSub(ctx,img,p1,p02,p2,t1,t02,t2,depth+1);break;case 3:drawTriangleSub(ctx,img,p0,p01,p02,t0,t01,t02,depth+1);drawTriangleSub(ctx,img,p02,p01,p2,t02,t01,t2,depth+1);drawTriangleSub(ctx,img,p01,p1,p2,t01,t1,t2,depth+1);break;case 4:drawTriangleSub(ctx,img,p0,p12,p2,t0,t12,t2,de [...]
+var tmp_vec4=vec4.create();function transform(transformed,point,matrix,viewport){vec4.set(tmp_vec4,point[0],point[1],0,1);vec4.transformMat4(tmp_vec4,tmp_vec4,matrix);var w=tmp_vec4[3];if(w<1e-6)w=1e-6;transformed[0]=((tmp_vec4[0]/w)+1)*viewport.width/2;transformed[1]=((tmp_vec4[1]/w)+1)*viewport.height/2;transformed[2]=w;}
+function drawProjectedQuadBackgroundToContext(quad,p1,p2,p3,p4,ctx,quadCanvas){if(quad.imageData){quadCanvas.width=quad.imageData.width;quadCanvas.height=quad.imageData.height;quadCanvas.getContext('2d').putImageData(quad.imageData,0,0);var quadBBox=new tr.b.BBox2();quadBBox.addQuad(quad);var iw=quadCanvas.width;var ih=quadCanvas.height;drawTriangleSub(ctx,quadCanvas,p1,p2,p4,[0,0],[iw,0],[0,ih]);drawTriangleSub(ctx,quadCanvas,p2,p3,p4,[iw,0],[iw,ih],[0,ih]);}
+if(quad.backgroundColor){ctx.fillStyle=quad.backgroundColor;ctx.beginPath();ctx.moveTo(p1[0],p1[1]);ctx.lineTo(p2[0],p2[1]);ctx.lineTo(p3[0],p3[1]);ctx.lineTo(p4[0],p4[1]);ctx.closePath();ctx.fill();}}
+function drawProjectedQuadOutlineToContext(quad,p1,p2,p3,p4,ctx,quadCanvas){ctx.beginPath();ctx.moveTo(p1[0],p1[1]);ctx.lineTo(p2[0],p2[1]);ctx.lineTo(p3[0],p3[1]);ctx.lineTo(p4[0],p4[1]);ctx.closePath();ctx.save();if(quad.borderColor)
+ctx.strokeStyle=quad.borderColor;else
+ctx.strokeStyle='rgb(128,128,128)';if(quad.shadowOffset){ctx.shadowColor='rgb(0, 0, 0)';ctx.shadowOffsetX=quad.shadowOffset[0];ctx.shadowOffsetY=quad.shadowOffset[1];if(quad.shadowBlur)
+ctx.shadowBlur=quad.shadowBlur;}
+if(quad.borderWidth)
+ctx.lineWidth=quad.borderWidth;else
+ctx.lineWidth=1;ctx.stroke();ctx.restore();}
+function drawProjectedQuadSelectionOutlineToContext(quad,p1,p2,p3,p4,ctx,quadCanvas){if(!quad.upperBorderColor)
+return;ctx.lineWidth=8;ctx.strokeStyle=quad.upperBorderColor;ctx.beginPath();ctx.moveTo(p1[0],p1[1]);ctx.lineTo(p2[0],p2[1]);ctx.lineTo(p3[0],p3[1]);ctx.lineTo(p4[0],p4[1]);ctx.closePath();ctx.stroke();}
+function drawProjectedQuadToContext(passNumber,quad,p1,p2,p3,p4,ctx,quadCanvas){if(passNumber===0){drawProjectedQuadBackgroundToContext(quad,p1,p2,p3,p4,ctx,quadCanvas);}else if(passNumber===1){drawProjectedQuadOutlineToContext(quad,p1,p2,p3,p4,ctx,quadCanvas);}else if(passNumber===2){drawProjectedQuadSelectionOutlineToContext(quad,p1,p2,p3,p4,ctx,quadCanvas);}else{throw new Error('Invalid pass number');}}
+var tmp_p1=vec3.create();var tmp_p2=vec3.create();var tmp_p3=vec3.create();var tmp_p4=vec3.create();function transformAndProcessQuads(matrix,viewport,quads,numPasses,handleQuadFunc,opt_arg1,opt_arg2){for(var passNumber=0;passNumber<numPasses;passNumber++){for(var i=0;i<quads.length;i++){var quad=quads[i];transform(tmp_p1,quad.p1,matrix,viewport);transform(tmp_p2,quad.p2,matrix,viewport);transform(tmp_p3,quad.p3,matrix,viewport);transform(tmp_p4,quad.p4,matrix,viewport);handleQuadFunc(pas [...]
+var QuadStackView=tr.ui.b.define('quad-stack-view');QuadStackView.prototype={__proto__:HTMLUnknownElement.prototype,decorate:function(){this.className='quad-stack-view';var node=tr.ui.b.instantiateTemplate('#quad-stack-view-template',THIS_DOC);this.appendChild(node);this.updateHeaderVisibility_();this.canvas_=this.querySelector('#canvas');this.chromeImages_={left:this.querySelector('#chrome-left'),mid:this.querySelector('#chrome-mid'),right:this.querySelector('#chrome-right')};var stacki [...]
+this.querySelector('#header').style.display='';else
+this.querySelector('#header').style.display='none';},get headerText(){return this.querySelector('#header').textContent;},set headerText(headerText){this.querySelector('#header').textContent=headerText;this.updateHeaderVisibility_();},onStackingDistanceChange_:function(e){tr.b.Settings.set('quadStackView.stackingDistance',this.stackingDistance);this.scheduleRender();e.stopPropagation();},get stackingDistance(){return this.querySelector('#stacking-distance-slider').value;},get mouseModeSel [...]
+return;this.deviceRect_=rect;this.camera_.deviceRect=rect;this.chromeQuad_=undefined;},resize:function(){if(!this.offsetParent)
+return true;var width=parseInt(window.getComputedStyle(this.offsetParent).width);var height=parseInt(window.getComputedStyle(this.offsetParent).height);var rect=tr.b.Rect.fromXYWH(0,0,width,height);if(rect.equalTo(this.viewportRect_))
+return false;this.viewportRect_=rect;this.style.width=width+'px';this.style.height=height+'px';this.canvas_.style.width=width+'px';this.canvas_.style.height=height+'px';this.canvas_.width=this.pixelRatio_*width;this.canvas_.height=this.pixelRatio_*height;if(!this.cameraWasReset_){this.camera_.resetCamera();this.cameraWasReset_=true;}
+return true;},readyToDraw:function(){if(!this.chromeImages_.left.src){var leftContent=window.getComputedStyle(this.chromeImages_.left).backgroundImage;leftContent=tr.ui.b.extractUrlString(leftContent);var midContent=window.getComputedStyle(this.chromeImages_.mid).backgroundImage;midContent=tr.ui.b.extractUrlString(midContent);var rightContent=window.getComputedStyle(this.chromeImages_.right).backgroundImage;rightContent=tr.ui.b.extractUrlString(rightContent);this.chromeImages_.left.src=l [...]
+return(this.chromeImages_.left.height>0)&&(this.chromeImages_.mid.height>0)&&(this.chromeImages_.right.height>0);},get chromeQuad(){if(this.chromeQuad_)
+return this.chromeQuad_;var chromeCanvas=document.createElement('canvas');var offsetY=this.chromeImages_.left.height;chromeCanvas.width=this.deviceRect_.width;chromeCanvas.height=this.deviceRect_.height+offsetY;var leftWidth=this.chromeImages_.left.width;var midWidth=this.chromeImages_.mid.width;var rightWidth=this.chromeImages_.right.width;var chromeCtx=chromeCanvas.getContext('2d');chromeCtx.drawImage(this.chromeImages_.left,0,0);chromeCtx.save();chromeCtx.translate(leftWidth,0);var s= [...]
+return false;this.redrawScheduled_=true;tr.b.requestAnimationFrame(this.render,this);},onRenderRequired_:function(e){this.scheduleRender();},stackTransformAndProcessQuads_:function(numPasses,handleQuadFunc,includeChromeQuad,opt_arg1,opt_arg2){var mv=this.camera_.modelViewMatrix;var p=this.camera_.projectionMatrix;var viewport=tr.b.Rect.fromXYWH(0,0,this.canvas_.width,this.canvas_.height);var quadStacks=[];for(var i=0;i<this.quads_.length;++i){var quad=this.quads_[i];var stackingId=quad.s [...]
+quadStacks.push([]);quadStacks[stackingId].push(quad);}
+var mvp=mat4.create();this.maxStackingGroupId_=quadStacks.length;var effectiveStackingDistance=this.stackingDistance*this.camera_.stackingDistanceDampening;mat4.multiply(mvp,p,mv);for(var i=0;i<quadStacks.length;++i){transformAndProcessQuads(mvp,viewport,quadStacks[i],numPasses,handleQuadFunc,opt_arg1,opt_arg2);mat4.translate(mv,mv,[0,0,effectiveStackingDistance]);mat4.multiply(mvp,p,mv);}
+if(includeChromeQuad&&this.deviceRect_){transformAndProcessQuads(mvp,viewport,[this.chromeQuad],numPasses,drawProjectedQuadToContext,opt_arg1,opt_arg2);}},render:function(){this.redrawScheduled_=false;if(!this.readyToDraw()){setTimeout(this.scheduleRender.bind(this),constants.IMAGE_LOAD_RETRY_TIME_MS);return;}
+if(!this.quads_)
+return;var canvasCtx=this.canvas_.getContext('2d');if(!this.resize())
+canvasCtx.clearRect(0,0,this.canvas_.width,this.canvas_.height);var quadCanvas=document.createElement('canvas');this.stackTransformAndProcessQuads_(3,drawProjectedQuadToContext,true,canvasCtx,quadCanvas);quadCanvas.width=0;},trackMouse_:function(){this.mouseModeSelector_=document.createElement('tr-ui-b-mouse-mode-selector');this.mouseModeSelector_.targetElement=this.canvas_;this.mouseModeSelector_.supportedModeMask=tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION|tr.ui.b.MOUSE_SELECTOR_MODE.PANSCAN [...]
+res.push(quad);}
+this.stackTransformAndProcessQuads_(1,handleQuad,false);var e=new tr.b.Event('selectionchange');e.quads=res;this.dispatchEvent(e);}};return{QuadStackView:QuadStackView};});'use strict';tr.exportTo('tr.ui.e.chrome.cc',function(){var ColorScheme=tr.b.ColorScheme;var THIS_DOC=document.currentScript.ownerDocument;var TILE_HEATMAP_TYPE={};TILE_HEATMAP_TYPE.NONE='none';TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY='scheduledPriority';TILE_HEATMAP_TYPE.USING_GPU_MEMORY='usingGpuMemory';var cc=tr.ui.e.ch [...]
+var bytesToRoundedMegabytes=tr.e.cc.bytesToRoundedMegabytes;var LayerTreeQuadStackView=tr.ui.b.define('tr-ui-e-chrome-cc-layer-tree-quad-stack-view');LayerTreeQuadStackView.prototype={__proto__:HTMLDivElement.prototype,decorate:function(){this.isRenderPassQuads_=false;this.pictureAsImageData_={};this.messages_=[];this.controls_=document.createElement('top-controls');this.infoBar_=document.createElement('tr-ui-b-info-bar');this.quadStackView_=new tr.ui.b.QuadStackView();this.quadStackView [...]
+return;this.layerTreeImpl_=layerTreeImpl;this.selection=undefined;},get extraHighlightsByLayerId(){return this.extraHighlightsByLayerId_;},set extraHighlightsByLayerId(extraHighlightsByLayerId){this.extraHighlightsByLayerId_=extraHighlightsByLayerId;this.scheduleUpdateContents_();},get showOtherLayers(){return this.showOtherLayers_;},set showOtherLayers(show){this.showOtherLayers_=show;this.updateContents_();},get showAnimationBounds(){return this.showAnimationBounds_;},set showAnimation [...]
+return;this.selection_=selection;tr.b.dispatchSimpleEvent(this,'selection-change');this.updateContents_();},regenerateContent:function(){this.updateTilesSelector_();this.updateContents_();},loadDataForImageElement_:function(image,callback){var imageContent=window.getComputedStyle(image).backgroundImage;image.src=tr.ui.b.extractUrlString(imageContent);image.onload=function(){var canvas=document.createElement('canvas');var ctx=canvas.getContext('2d');canvas.width=image.width;canvas.height= [...]
+selectableQuads.sort(function(x,y){var z=x.stackingGroupId-y.stackingGroupId;if(z!=0)
+return z;return x.selectionToSetIfClicked.specicifity-
+y.selectionToSetIfClicked.specicifity;});var quadToSelect=selectableQuads[selectableQuads.length-1];this.selection=quadToSelect.selectionToSetIfClicked;},scheduleUpdateContents_:function(){if(this.updateContentsPending_)
+return;this.updateContentsPending_=true;tr.b.requestAnimationFrameInThisFrameIfPossible(this.updateContents_,this);},updateContents_:function(){if(!this.layerTreeImpl_){this.quadStackView_.headerText='No tree';this.quadStackView_.quads=[];return;}
+var status=this.computePictureLoadingStatus_();if(!status.picturesComplete)
+return;var lthi=this.layerTreeImpl_.layerTreeHostImpl;var lthiInstance=lthi.objectInstance;var worldViewportRect=tr.b.Rect.fromXYWH(0,0,lthi.deviceViewportSize.width,lthi.deviceViewportSize.height);this.quadStackView_.deviceRect=worldViewportRect;if(this.isRenderPassQuads_)
+this.quadStackView_.quads=this.generateRenderPassQuads();else
+this.quadStackView_.quads=this.generateLayerQuads();this.updateWhatRasterizedLinkState_();var message='';if(lthi.tilesHaveGpuMemoryUsageInfo){var thisTreeUsageInBytes=this.layerTreeImpl_.gpuMemoryUsageInBytes;var otherTreeUsageInBytes=lthi.gpuMemoryUsageInBytes-
+thisTreeUsageInBytes;message+=bytesToRoundedMegabytes(thisTreeUsageInBytes)+'MB on this tree';if(otherTreeUsageInBytes){message+=', '+
+bytesToRoundedMegabytes(otherTreeUsageInBytes)+'MB on the other tree';}}else{if(this.layerTreeImpl_){var thisTreeUsageInBytes=this.layerTreeImpl_.gpuMemoryUsageInBytes;message+=bytesToRoundedMegabytes(thisTreeUsageInBytes)+'MB on this tree';if(this.layerTreeImpl_.otherTree){message+=', ???MB on other tree. ';}}}
+if(lthi.args.tileManagerBasicState){var tmgs=lthi.args.tileManagerBasicState.globalState;message+=' (softMax='+
+bytesToRoundedMegabytes(tmgs.softMemoryLimitInBytes)+'MB, hardMax='+
+bytesToRoundedMegabytes(tmgs.hardMemoryLimitInBytes)+'MB, '+
+tmgs.memoryLimitPolicy+')';}else{var thread=lthi.snapshottedOnThread;var didManageTilesSlices=thread.sliceGroup.slices.filter(function(s){if(s.category!=='tr.e.cc')
+return false;if(s.title!=='DidManage')
+return false;if(s.end>lthi.ts)
+return false;return true;});didManageTilesSlices.sort(function(x,y){return x.end-y.end;});if(didManageTilesSlices.length>0){var newest=didManageTilesSlices[didManageTilesSlices.length-1];var tmgs=newest.args.state.global_state;message+=' (softMax='+
+bytesToRoundedMegabytes(tmgs.soft_memory_limit_in_bytes)+'MB, hardMax='+
+bytesToRoundedMegabytes(tmgs.hard_memory_limit_in_bytes)+'MB, '+
+tmgs.memory_limit_policy+')';}}
+if(this.layerTreeImpl_.otherTree)
+message+=' (Another tree exists)';if(message.length)
+this.quadStackView_.headerText=message;else
+this.quadStackView_.headerText=undefined;this.updateInfoBar_(status.messages);},updateTilesSelector_:function(){var data=createTileRectsSelectorBaseOptions();if(this.layerTreeImpl_){var lthi=this.layerTreeImpl_.layerTreeHostImpl;var scaleNames=lthi.getContentsScaleNames();for(var scale in scaleNames){data.push({label:'Scale '+scale+' ('+scaleNames[scale]+')',value:scale});}}
+var new_selector=tr.ui.b.createSelector(this,'howToShowTiles','layerView.howToShowTiles','none',data);this.controls_.replaceChild(new_selector,this.tileRectsSelector_);this.tileRectsSelector_=new_selector;},computePictureLoadingStatus_:function(){var layers=this.layers;var status={messages:[],picturesComplete:true};if(this.showContents){var hasPendingRasterizeImage=false;var firstPictureError=undefined;var hasMissingLayerRect=false;var hasUnresolvedPictureRef=false;for(var i=0;i<layers.l [...]
+if(!picture.layerRect){hasMissingLayerRect=true;continue;}
+var pictureAsImageData=this.pictureAsImageData_[picture.guid];if(!pictureAsImageData){hasPendingRasterizeImage=true;this.pictureAsImageData_[picture.guid]=tr.e.cc.PictureAsImageData.Pending(this);picture.rasterize({stopIndex:undefined},function(pictureImageData){var picture_=pictureImageData.picture;this.pictureAsImageData_[picture_.guid]=pictureImageData;this.scheduleUpdateContents_();}.bind(this));continue;}
+if(pictureAsImageData.isPending()){hasPendingRasterizeImage=true;continue;}
+if(pictureAsImageData.error){if(!firstPictureError)
+firstPictureError=pictureAsImageData.error;break;}}}
+if(hasPendingRasterizeImage){status.picturesComplete=false;}else{if(hasUnresolvedPictureRef){status.messages.push({header:'Missing picture',details:'Your trace didnt have pictures for every layer. '+'Old chrome versions had this problem'});}
+if(hasMissingLayerRect){status.messages.push({header:'Missing layer rect',details:'Your trace may be corrupt or from a very old '+'Chrome revision.'});}
+if(firstPictureError){status.messages.push({header:'Cannot rasterize',details:firstPictureError});}}}
+if(this.showInputEvents&&this.layerTreeImpl.tracedInputLatencies&&this.inputEventImageData_===undefined){var image=this.querySelector('#input-event');if(!image.src){this.loadDataForImageElement_(image,function(imageData){this.inputEventImageData_=imageData;this.updateContentsPending_=false;this.scheduleUpdateContents_();}.bind(this));}
+status.picturesComplete=false;}
+return status;},get selectedRenderPass(){if(this.selection)
+return this.selection.renderPass_;},get selectedLayer(){if(this.selection){var selectedLayerId=this.selection.associatedLayerId;return this.layerTreeImpl_.findLayerWithId(selectedLayerId);}},get renderPasses(){var renderPasses=this.layerTreeImpl.layerTreeHostImpl.args.frame.renderPasses;if(!this.showOtherLayers){var selectedRenderPass=this.selectedRenderPass;if(selectedRenderPass)
+renderPasses=[selectedRenderPass];}
+return renderPasses;},get layers(){var layers=this.layerTreeImpl.renderSurfaceLayerList;if(!this.showOtherLayers){var selectedLayer=this.selectedLayer;if(selectedLayer)
+layers=[selectedLayer];}
+return layers;},appendImageQuads_:function(quads,layer,layerQuad){for(var ir=0;ir<layer.pictures.length;++ir){var picture=layer.pictures[ir];if(!picture.layerRect)
+continue;var unitRect=picture.layerRect.asUVRectInside(layer.bounds);var iq=layerQuad.projectUnitRect(unitRect);var pictureData=this.pictureAsImageData_[picture.guid];if(this.showContents&&pictureData&&pictureData.imageData){iq.imageData=pictureData.imageData;iq.borderColor='rgba(0,0,0,0)';}else{iq.imageData=undefined;}
+iq.stackingGroupId=layerQuad.stackingGroupId;quads.push(iq);}},appendAnimationQuads_:function(quads,layer,layerQuad){if(!layer.animationBoundsRect)
+return;var rect=layer.animationBoundsRect;var abq=tr.b.Quad.fromRect(rect);abq.backgroundColor='rgba(164,191,48,0.5)';abq.borderColor='rgba(205,255,0,0.75)';abq.borderWidth=3.0;abq.stackingGroupId=layerQuad.stackingGroupId;abq.selectionToSetIfClicked=new cc.AnimationRectSelection(layer,rect);quads.push(abq);},appendInvalidationQuads_:function(quads,layer,layerQuad){if(layer.layerTreeImpl.hasSourceFrameBeenDrawnBefore)
+return;for(var ir=0;ir<layer.annotatedInvalidation.rects.length;ir++){var rect=layer.annotatedInvalidation.rects[ir];var unitRect=rect.asUVRectInside(layer.bounds);var iq=layerQuad.projectUnitRect(unitRect);iq.backgroundColor='rgba(0, 255, 0, 0.1)';if(rect.reason==='renderer insertion')
+iq.backgroundColor='rgba(0, 255, 128, 0.1)';iq.borderColor='rgba(0, 255, 0, 1)';iq.stackingGroupId=layerQuad.stackingGroupId;iq.selectionToSetIfClicked=new cc.LayerRectSelection(layer,'Invalidation rect ('+rect.reason+')',rect,rect);quads.push(iq);}
+if(layer.annotatedInvalidation.rects.length===0){for(var ir=0;ir<layer.invalidation.rects.length;ir++){var rect=layer.invalidation.rects[ir];var unitRect=rect.asUVRectInside(layer.bounds);var iq=layerQuad.projectUnitRect(unitRect);iq.backgroundColor='rgba(0, 255, 0, 0.1)';iq.borderColor='rgba(0, 255, 0, 1)';iq.stackingGroupId=layerQuad.stackingGroupId;iq.selectionToSetIfClicked=new cc.LayerRectSelection(layer,'Invalidation rect',rect,rect);quads.push(iq);}}},appendUnrecordedRegionQuads_: [...]
+return;for(var ir=0;ir<region.rects.length;ir++){var rect=region.rects[ir];var unitRect=rect.asUVRectInside(layer.bounds);var iq=layerQuad.projectUnitRect(unitRect);iq.backgroundColor=backgroundColor.toString();iq.borderColor=borderColor.toString();iq.borderWidth=4.0;iq.stackingGroupId=stackingGroupId;iq.selectionToSetIfClicked=new cc.LayerRectSelection(layer,label,rect,rect);quads.push(iq);}}
+processRegion(layer.touchEventHandlerRegion,'Touch listener',tr.b.Color.fromString('rgb(228, 226, 27)'));processRegion(layer.wheelEventHandlerRegion,'Wheel listener',tr.b.Color.fromString('rgb(176, 205, 29)'));processRegion(layer.nonFastScrollableRegion,'Repaints on scroll',tr.b.Color.fromString('rgb(213, 134, 32)'));},appendTileCoverageRectQuads_:function(quads,layer,layerQuad,heatmapType){if(!layer.tileCoverageRects)
+return;var tiles=[];for(var ct=0;ct<layer.tileCoverageRects.length;++ct){var tile=layer.tileCoverageRects[ct].tile;if(tile!==undefined)
+tiles.push(tile);}
+var lthi=this.layerTreeImpl_.layerTreeHostImpl;var minMax=this.getMinMaxForHeatmap_(lthi.activeTiles,heatmapType);var heatmapResult=this.computeHeatmapColors_(tiles,minMax,heatmapType);var heatIndex=0;for(var ct=0;ct<layer.tileCoverageRects.length;++ct){var rect=layer.tileCoverageRects[ct].geometryRect;rect=rect.scale(1.0/layer.geometryContentsScale);var tile=layer.tileCoverageRects[ct].tile;var unitRect=rect.asUVRectInside(layer.bounds);var quad=layerQuad.projectUnitRect(unitRect);quad. [...]
+quad.borderColor=tr.e.cc.tileBorder[type].color;quad.borderWidth=tr.e.cc.tileBorder[type].width;var label;if(tile)
+label='coverageRect';else
+label='checkerboard coverageRect';quad.selectionToSetIfClicked=new cc.LayerRectSelection(layer,label,rect,layer.tileCoverageRects[ct]);quads.push(quad);}},appendLayoutRectQuads_:function(quads,layer,layerQuad){if(!layer.layoutRects){return;}
+for(var ct=0;ct<layer.layoutRects.length;++ct){var rect=layer.layoutRects[ct].geometryRect;rect=rect.scale(1.0/layer.geometryContentsScale);var unitRect=rect.asUVRectInside(layer.bounds);var quad=layerQuad.projectUnitRect(unitRect);quad.backgroundColor='rgba(0, 0, 0, 0)';quad.stackingGroupId=layerQuad.stackingGroupId;quad.borderColor='rgba(0, 0, 200, 0.7)';quad.borderWidth=2;var label;label='Layout rect';quad.selectionToSetIfClicked=new cc.LayerRectSelection(layer,label,rect);quads.push( [...]
+return 0.5;return tile.isUsingGpuMemory?0:1;}},getMinMaxForHeatmap_:function(tiles,heatmapType){var range=new tr.b.Range();if(heatmapType==TILE_HEATMAP_TYPE.USING_GPU_MEMORY){range.addValue(0);range.addValue(1);return range;}
+for(var i=0;i<tiles.length;++i){var value=this.getValueForHeatmap_(tiles[i],heatmapType);if(value===undefined)
+continue;range.addValue(value);}
+if(range.range===0)
+range.addValue(1);return range;},computeHeatmapColors_:function(tiles,minMax,heatmapType){var min=minMax.min;var max=minMax.max;var color=function(value){var hue=120*(1-(value-min)/(max-min));if(hue<0)
+hue=0;return'hsla('+hue+', 100%, 50%, 0.5)';};var values=[];for(var i=0;i<tiles.length;++i){var tile=tiles[i];var value=this.getValueForHeatmap_(tile,heatmapType);var res={value:value,color:value!==undefined?color(value):undefined};values.push(res);}
+return values;},appendTilesWithScaleQuads_:function(quads,layer,layerQuad,scale,heatmapType){var lthi=this.layerTreeImpl_.layerTreeHostImpl;var tiles=[];for(var i=0;i<lthi.activeTiles.length;++i){var tile=lthi.activeTiles[i];if(Math.abs(tile.contentsScale-scale)>1e-6)
+continue;if(layer.layerId!=tile.layerId)
+continue;tiles.push(tile);}
+var minMax=this.getMinMaxForHeatmap_(lthi.activeTiles,heatmapType);var heatmapResult=this.computeHeatmapColors_(tiles,minMax,heatmapType);for(var i=0;i<tiles.length;++i){var tile=tiles[i];var rect=tile.layerRect;if(!tile.layerRect)
+continue;var unitRect=rect.asUVRectInside(layer.bounds);var quad=layerQuad.projectUnitRect(unitRect);quad.backgroundColor='rgba(0, 0, 0, 0)';quad.stackingGroupId=layerQuad.stackingGroupId;var type=tile.getTypeForLayer(layer);quad.borderColor=tr.e.cc.tileBorder[type].color;quad.borderWidth=tr.e.cc.tileBorder[type].width;quad.backgroundColor=heatmapResult[i].color;var data={tileType:type};if(heatmapType!==TILE_HEATMAP_TYPE.NONE)
+data[heatmapType]=heatmapResult[i].value;quad.selectionToSetIfClicked=new cc.TileSelection(tile,data);quads.push(quad);}},appendHighlightQuadsForLayer_:function(quads,layer,layerQuad,highlights){highlights.forEach(function(highlight){var rect=highlight.rect;var unitRect=rect.asUVRectInside(layer.bounds);var quad=layerQuad.projectUnitRect(unitRect);var colorId=ColorScheme.getColorIdForGeneralPurposeString(highlight.colorKey);colorId+=ColorScheme.properties.brightenedOffsets[0];var color=C [...]
+return[];var renderPasses=this.renderPasses;if(!renderPasses)
+return[];var quads=[];for(var i=0;i<renderPasses.length;++i){var quadList=renderPasses[i].quadList;for(var j=0;j<quadList.length;++j){var drawQuad=quadList[j];var quad=drawQuad.rectAsTargetSpaceQuad.clone();quad.borderColor='rgb(170, 204, 238)';quad.borderWidth=2;quad.stackingGroupId=i;quads.push(quad);}}
+return quads;},generateLayerQuads:function(){this.updateContentsPending_=false;var layers=this.layers;var quads=[];var nextStackingGroupId=0;var alreadyVisitedLayerIds={};var selectionHighlightsByLayerId;if(this.selection)
+selectionHighlightsByLayerId=this.selection.highlightsByLayerId;else
+selectionHighlightsByLayerId={};var extraHighlightsByLayerId=this.extraHighlightsByLayerId||{};for(var i=1;i<=layers.length;i++){var layer=layers[layers.length-i];alreadyVisitedLayerIds[layer.layerId]=true;if(layer.objectInstance.name=='cc::NinePatchLayerImpl')
+continue;var layerQuad=layer.layerQuad.clone();if(layer.usingGpuRasterization){var pixelRatio=window.devicePixelRatio||1;layerQuad.borderWidth=2.0*pixelRatio;layerQuad.borderColor='rgba(154,205,50,0.75)';}else{layerQuad.borderColor='rgba(0,0,0,0.75)';}
+layerQuad.stackingGroupId=nextStackingGroupId++;layerQuad.selectionToSetIfClicked=new cc.LayerSelection(layer);layerQuad.layer=layer;if(this.showOtherLayers&&this.selectedLayer==layer)
+layerQuad.upperBorderColor='rgb(156,189,45)';if(this.showAnimationBounds)
+this.appendAnimationQuads_(quads,layer,layerQuad);this.appendImageQuads_(quads,layer,layerQuad);quads.push(layerQuad);if(this.showInvalidations)
+this.appendInvalidationQuads_(quads,layer,layerQuad);if(this.showUnrecordedRegion)
+this.appendUnrecordedRegionQuads_(quads,layer,layerQuad);if(this.showBottlenecks)
+this.appendBottleneckQuads_(quads,layer,layerQuad,layerQuad.stackingGroupId);if(this.showLayoutRects)
+this.appendLayoutRectQuads_(quads,layer,layerQuad);if(this.howToShowTiles==='coverage'){this.appendTileCoverageRectQuads_(quads,layer,layerQuad,this.tileHeatmapType);}else if(this.howToShowTiles!=='none'){this.appendTilesWithScaleQuads_(quads,layer,layerQuad,this.howToShowTiles,this.tileHeatmapType);}
+var highlights;highlights=extraHighlightsByLayerId[layer.layerId];if(highlights){this.appendHighlightQuadsForLayer_(quads,layer,layerQuad,highlights);}
+highlights=selectionHighlightsByLayerId[layer.layerId];if(highlights){this.appendHighlightQuadsForLayer_(quads,layer,layerQuad,highlights);}}
+this.layerTreeImpl.iterLayers(function(layer,depth,isMask,isReplica){if(!this.showOtherLayers&&this.selectedLayer!=layer)
+return;if(alreadyVisitedLayerIds[layer.layerId])
+return;var layerQuad=layer.layerQuad;var stackingGroupId=nextStackingGroupId++;if(this.showBottlenecks)
+this.appendBottleneckQuads_(quads,layer,layerQuad,stackingGroupId);},this);var tracedInputLatencies=this.layerTreeImpl.tracedInputLatencies;if(this.showInputEvents&&tracedInputLatencies){for(var i=0;i<tracedInputLatencies.length;i++){var coordinatesArray=tracedInputLatencies[i].args.data.coordinates;for(var j=0;j<coordinatesArray.length;j++){var inputQuad=tr.b.Quad.fromXYWH(coordinatesArray[j].x-25,coordinatesArray[j].y-25,50,50);inputQuad.borderColor='rgba(0, 0, 0, 0)';inputQuad.imageDa [...]
+return quads;},updateInfoBar_:function(infoBarMessages){if(infoBarMessages.length){this.infoBar_.removeAllButtons();this.infoBar_.message='Some problems were encountered...';this.infoBar_.addButton('More info...',function(e){var overlay=new tr.ui.b.Overlay();overlay.textContent='';infoBarMessages.forEach(function(message){var title=document.createElement('h3');title.textContent=message.header;var details=document.createElement('div');details.textContent=message.details;overlay.appendChil [...]
+return;var tile=tr.e.cc.getTileFromRasterTaskSlice(event);if(tile===undefined)
+return false;if(tile.containingSnapshot==lthi)
+tasks.push(event);},this);return tasks;},updateWhatRasterizedLinkState_:function(){var tasks=this.getWhatRasterized_();if(tasks.length){this.whatRasterizedLink_.textContent=tasks.length+' raster tasks';this.whatRasterizedLink_.style.display='';}else{this.whatRasterizedLink_.textContent='';this.whatRasterizedLink_.style.display='none';}},onWhatRasterizedLinkClicked_:function(){var tasks=this.getWhatRasterized_();var event=new tr.model.RequestSelectionChangeEvent();event.selection=new tr.m [...]
+var analysis=selection.createAnalysis();this.analysisEl_.appendChild(analysis);}else{this.dragBar_.style.display='none';this.analysisEl_.style.display='none';var analysis=this.analysisEl_.firstChild;if(analysis)
+this.analysisEl_.removeChild(analysis);this.layerTreeQuadStackView_.style.height=window.getComputedStyle(this).height;}
+tr.b.dispatchSimpleEvent(this,'selection-change');},createPictureBtn_:function(pictures){if(!(pictures instanceof Array))
+pictures=[pictures];var link=document.createElement('tr-ui-a-analysis-link');link.selection=function(){var layeredPicture=new tr.e.cc.LayeredPicture(pictures);var snapshot=new tr.e.cc.PictureSnapshot(layeredPicture);snapshot.picture=layeredPicture;var selection=new tr.model.EventSet();selection.push(snapshot);return selection;};link.textContent='View in Picture Debugger';return link;},onRequestSelectionChangeFromAnalysisEl_:function(e){if(!(e.selection instanceof tr.ui.e.chrome.cc.Selection))
+return;e.stopPropagation();this.selection=e.selection;},get extraHighlightsByLayerId(){return this.layerTreeQuadStackView_.extraHighlightsByLayerId;},set extraHighlightsByLayerId(extraHighlightsByLayerId){this.layerTreeQuadStackView_.extraHighlightsByLayerId=extraHighlightsByLayerId;}};return{LayerView:LayerView};});'use strict';tr.exportTo('tr.ui.e.chrome.cc',function(){var LayerTreeHostImplSnapshotView=tr.ui.b.define('tr-ui-e-chrome-cc-layer-tree-host-impl-snapshot-view',tr.ui.analysis [...]
+layerTreeImpl=lthi.getTree(this.layerPicker_.whichTree);this.layerPicker_.lthiSnapshot=lthi;this.layerView_.layerTreeImpl=layerTreeImpl;this.layerView_.regenerateContent();if(!this.selection_)
+return;this.selection=this.selection_.findEquivalent(lthi);},get selection(){return this.selection_;},set selection(selection){if(this.selection_==selection)
+return;this.selection_=selection;this.layerPicker_.selection=selection;this.layerView_.selection=selection;tr.b.dispatchSimpleEvent(this,'cc-selection-change');},onLayerPickerSelectionChanged_:function(){this.selection_=this.layerPicker_.selection;this.layerView_.selection=this.selection;this.layerView_.layerTreeImpl=this.layerPicker_.layerTreeImpl;this.layerView_.isRenderPassQuads=this.layerPicker_.isRenderPassQuads;this.layerView_.regenerateContent();tr.b.dispatchSimpleEvent(this,'cc-s [...]
+return;this.processPictureData_();this.requiresRedraw=true;this.updateChartContents();},hide:function(){this.classList.add('hidden');},show:function(){this.classList.remove('hidden');if(this.pictureDataProcessed_)
+return;this.processPictureData_();this.requiresRedraw=true;this.updateChartContents();},onMouseMove_:function(e){var lastBarMouseOverTarget=this.currentBarMouseOverTarget_;this.currentBarMouseOverTarget_=null;var x=e.offsetX;var y=e.offsetY;var chartLeft=CHART_PADDING_LEFT;var chartRight=this.chartWidth_-CHART_PADDING_RIGHT;var chartTop=AXIS_PADDING_TOP;var chartBottom=this.chartHeight_-AXIS_PADDING_BOTTOM;var chartInnerWidth=chartRight-chartLeft;if(x>chartLeft&&x<chartRight&&y>chartTop& [...]
+if(this.currentBarMouseOverTarget_===lastBarMouseOverTarget)
+return;this.drawChartContents_();},updateChartContents:function(){if(this.requiresRedraw)
+this.updateChartDimensions_();this.drawChartContents_();},updateChartDimensions_:function(){this.chartWidth_=this.offsetWidth;this.chartHeight_=this.offsetHeight;this.chart_.width=this.chartWidth_*this.chartScale_;this.chart_.height=this.chartHeight_*this.chartScale_;this.chart_.style.width=this.chartWidth_+'px';this.chart_.style.height=this.chartHeight_+'px';this.chartCtx_.scale(this.chartScale_,this.chartScale_);},processPictureData_:function(){this.resetOpsTimingData_();this.pictureDa [...]
+return;var ops=this.picture_.getOps();if(!ops)
+return;ops=this.picture_.tagOpsWithTimings(ops);if(ops[0].cmd_time===undefined)
+return;this.collapseOpsToTimingBuckets_(ops);},drawChartContents_:function(){this.clearChartContents_();if(this.opsTimingData_.length===0){this.showNoTimingDataMessage_();return;}
+this.drawChartAxes_();this.drawBars_();this.drawLineAtBottomOfChart_();if(this.currentBarMouseOverTarget_===null)
+return;this.drawTooltip_();},drawLineAtBottomOfChart_:function(){this.chartCtx_.strokeStyle='#AAA';this.chartCtx_.moveTo(0,this.chartHeight_-0.5);this.chartCtx_.lineTo(this.chartWidth_,this.chartHeight_-0.5);this.chartCtx_.stroke();},drawTooltip_:function(){var tooltipData=this.opsTimingData_[this.currentBarMouseOverTarget_];var tooltipTitle=tooltipData.cmd_string;var tooltipTime=tooltipData.cmd_time.toFixed(4);var tooltipWidth=110;var tooltipHeight=40;var chartInnerWidth=this.chartWidth [...]
+CHART_PADDING_LEFT;var barWidth=chartInnerWidth/this.opsTimingData_.length;var tooltipOffset=Math.round((tooltipWidth-barWidth)*0.5);var left=CHART_PADDING_LEFT+this.currentBarMouseOverTarget_*barWidth-tooltipOffset;var top=Math.round((this.chartHeight_-tooltipHeight)*0.5);this.chartCtx_.save();this.chartCtx_.shadowOffsetX=0;this.chartCtx_.shadowOffsetY=5;this.chartCtx_.shadowBlur=4;this.chartCtx_.shadowColor='rgba(0,0,0,0.4)';this.chartCtx_.strokeStyle='#888';this.chartCtx_.fillStyle='# [...]
+height-opHeight,barWidth-2*BAR_PADDING,opHeight);}},getOpColor_:function(opName){var characters=opName.split('');var hue=characters.reduce(this.reduceNameToHue,0)%360;return'hsl('+hue+', 30%, 50%)';},reduceNameToHue:function(previousValue,currentValue,index,array){return Math.round(previousValue+currentValue.charCodeAt(0)*HUE_CHAR_CODE_ADJUSTMENT);},drawChartAxes_:function(){var len=this.opsTimingData_.length;var max=this.opsTimingData_[0].cmd_time;var min=this.opsTimingData_[len-1].cmd_ [...]
+CHART_PADDING_RIGHT;var barWidth=Math.floor(totalBarWidth/len);var tickYInterval=height/(VERTICAL_TICKS-1);var tickYPosition=0;var tickValInterval=(max-min)/(VERTICAL_TICKS-1);var tickVal=0;this.chartCtx_.fillStyle='#333';this.chartCtx_.strokeStyle='#777';this.chartCtx_.save();this.chartCtx_.translate(0.5,0.5);this.chartCtx_.save();this.chartCtx_.translate(AXIS_PADDING_LEFT,AXIS_PADDING_TOP);this.chartCtx_.moveTo(0,0);this.chartCtx_.lineTo(0,height);this.chartCtx_.lineTo(width,height);th [...]
+this.chartCtx_.stroke();this.chartCtx_.restore();this.chartCtx_.save();this.chartCtx_.translate(CHART_PADDING_LEFT+Math.round(barWidth*0.5),AXIS_PADDING_TOP+height+LABEL_PADDING);this.chartCtx_.font='10px Arial';this.chartCtx_.textAlign='center';this.chartCtx_.textBaseline='top';var labelTickLeft;var labelTickBottom;for(var l=0;l<len;l++){labelTickLeft=Math.round(l*barWidth);labelTickBottom=l%2*LABEL_INTERLEAVE_OFFSET;this.chartCtx_.save();this.chartCtx_.moveTo(labelTickLeft,-LABEL_PADDI [...]
+this.chartCtx_.restore();this.chartCtx_.restore();},clearChartContents_:function(){this.chartCtx_.clearRect(0,0,this.chartWidth_,this.chartHeight_);},showNoTimingDataMessage_:function(){this.chartCtx_.font='800 italic 14px Arial';this.chartCtx_.fillStyle='#333';this.chartCtx_.textAlign='center';this.chartCtx_.textBaseline='middle';this.chartCtx_.fillText('No timing data available.',this.chartWidth_*0.5,this.chartHeight_*0.5);},collapseOpsToTimingBuckets_:function(ops){var opsTimingDataIn [...]
+continue;opIndex=opsTimingDataIndexHash_[op.cmd_string]||null;if(opIndex===null){timingData.push({cmd_time:0,cmd_string:op.cmd_string});opIndex=timingData.length-1;opsTimingDataIndexHash_[op.cmd_string]=opIndex;}
+timingData[opIndex].cmd_time+=op.cmd_time;}
+timingData.sort(this.sortTimingBucketsByOpTimeDescending_);this.collapseTimingBucketsToOther_(4);},collapseTimingBucketsToOther_:function(count){var timingData=this.opsTimingData_;var otherSource=timingData.splice(count,timingData.length-count);var otherDestination=null;if(!otherSource.length)
+return;timingData.push({cmd_time:0,cmd_string:'Other'});otherDestination=timingData[timingData.length-1];for(var i=0;i<otherSource.length;i++){otherDestination.cmd_time+=otherSource[i].cmd_time;}},sortTimingBucketsByOpTimeDescending_:function(a,b){return b.cmd_time-a.cmd_time;},resetOpsTimingData_:function(){this.opsTimingData_.length=0;}};return{PictureOpsChartSummaryView:PictureOpsChartSummaryView};});'use strict';tr.exportTo('tr.ui.e.chrome.cc',function(){var BAR_PADDING=1;var BAR_WID [...]
+return;var totalOpCost=0;this.opCosts_=this.pictureOps_.map(function(op){totalOpCost+=op.cmd_time;return op.cmd_time;});this.opCosts_.sort();var ninetyFifthPercentileCostIndex=Math.floor(this.opCosts_.length*0.95);this.ninetyFifthPercentileCost_=this.opCosts_[ninetyFifthPercentileCostIndex];this.maxCost_=this.opCosts_[this.opCosts_.length-1];this.totalOpCost_=totalOpCost;},extractBarIndex_:function(e){var index=undefined;if(this.pictureOps_===undefined||this.pictureOps_.length===0)
+return index;var x=e.offsetX;var y=e.offsetY;var totalBarWidth=(BAR_WIDTH+BAR_PADDING)*this.pictureOps_.length;var chartLeft=CHART_PADDING_LEFT;var chartTop=0;var chartBottom=this.chartHeight_-CHART_PADDING_BOTTOM;var chartRight=chartLeft+totalBarWidth;if(x<chartLeft||x>chartRight||y<chartTop||y>chartBottom)
+return index;index=Math.floor((x-chartLeft)/totalBarWidth*this.pictureOps_.length);index=tr.b.clamp(index,0,this.pictureOps_.length-1);return index;},onClick_:function(e){var barClicked=this.extractBarIndex_(e);if(barClicked===undefined)
+return;if(barClicked===this.selectedOpIndex)
+this.selectedOpIndex=undefined;else
+this.selectedOpIndex=barClicked;e.preventDefault();tr.b.dispatchSimpleEvent(this,'selection-changed',false);},onMouseMove_:function(e){var lastBarMouseOverTarget=this.currentBarMouseOverTarget_;this.currentBarMouseOverTarget_=this.extractBarIndex_(e);if(this.currentBarMouseOverTarget_===lastBarMouseOverTarget)
+return;this.drawChartContents_();},scrollSelectedItemIntoViewIfNecessary:function(){if(this.selectedOpIndex===undefined)
+return;var width=this.offsetWidth;var left=this.scrollLeft;var right=left+width;var targetLeft=CHART_PADDING_LEFT+
+(BAR_WIDTH+BAR_PADDING)*this.selectedOpIndex;if(targetLeft>left&&targetLeft<right)
+return;this.scrollLeft=(targetLeft-width*0.5);},updateChartContents:function(){if(this.dimensionsHaveChanged)
+this.updateChartDimensions_();this.drawChartContents_();},updateChartDimensions_:function(){if(!this.pictureOps_)
+return;var width=CHART_PADDING_LEFT+CHART_PADDING_RIGHT+
+((BAR_WIDTH+BAR_PADDING)*this.pictureOps_.length);if(width<this.offsetWidth)
+width=this.offsetWidth;this.chartWidth_=width;this.chartHeight_=this.getBoundingClientRect().height;this.chart_.width=this.chartWidth_*this.chartScale_;this.chart_.height=this.chartHeight_*this.chartScale_;this.chart_.style.width=this.chartWidth_+'px';this.chart_.style.height=this.chartHeight_+'px';this.chartCtx_.scale(this.chartScale_,this.chartScale_);this.dimensionsHaveChanged=false;},drawChartContents_:function(){this.clearChartContents_();if(this.pictureOps_===undefined||this.pictur [...]
+this.drawSelection_();this.drawBars_();this.drawChartAxes_();this.drawLinesAtTickMarks_();this.drawLineAtBottomOfChart_();if(this.currentBarMouseOverTarget_===undefined)
+return;this.drawTooltip_();},drawSelection_:function(){if(this.selectedOpIndex===undefined)
+return;var width=(BAR_WIDTH+BAR_PADDING)*this.selectedOpIndex;this.chartCtx_.fillStyle='rgb(223, 235, 230)';this.chartCtx_.fillRect(CHART_PADDING_LEFT,CHART_PADDING_TOP,width,this.chartHeight_-CHART_PADDING_TOP-CHART_PADDING_BOTTOM);},drawChartAxes_:function(){var min=this.opCosts_[0];var max=this.opCosts_[this.opCosts_.length-1];var height=this.chartHeight_-AXIS_PADDING_TOP-AXIS_PADDING_BOTTOM;var tickYInterval=height/(VERTICAL_TICKS-1);var tickYPosition=0;var tickValInterval=(max-min)/ [...]
+AXIS_PADDING_BOTTOM);this.chartCtx_.lineTo(this.chartWidth_-AXIS_PADDING_RIGHT,this.chartHeight_-AXIS_PADDING_BOTTOM);this.chartCtx_.stroke();this.chartCtx_.closePath();this.chartCtx_.translate(AXIS_PADDING_LEFT,AXIS_PADDING_TOP);this.chartCtx_.font='10px Arial';this.chartCtx_.textAlign='right';this.chartCtx_.textBaseline='middle';this.chartCtx_.beginPath();for(var t=0;t<VERTICAL_TICKS;t++){tickYPosition=Math.round(t*tickYInterval);tickVal=(max-t*tickValInterval).toFixed(4);this.chartCtx [...]
+this.chartCtx_.stroke();this.chartCtx_.closePath();this.chartCtx_.restore();},drawLinesAtTickMarks_:function(){var height=this.chartHeight_-AXIS_PADDING_TOP-AXIS_PADDING_BOTTOM;var width=this.chartWidth_-AXIS_PADDING_LEFT-AXIS_PADDING_RIGHT;var tickYInterval=height/(VERTICAL_TICKS-1);var tickYPosition=0;this.chartCtx_.save();this.chartCtx_.translate(AXIS_PADDING_LEFT+0.5,AXIS_PADDING_TOP+0.5);this.chartCtx_.beginPath();this.chartCtx_.strokeStyle='rgba(0,0,0,0.05)';for(var t=0;t<VERTICAL_ [...]
+this.chartCtx_.restore();this.chartCtx_.closePath();},drawLineAtBottomOfChart_:function(){this.chartCtx_.strokeStyle='#AAA';this.chartCtx_.beginPath();this.chartCtx_.moveTo(0,this.chartHeight_-0.5);this.chartCtx_.lineTo(this.chartWidth_,this.chartHeight_-0.5);this.chartCtx_.stroke();this.chartCtx_.closePath();},drawTooltip_:function(){var tooltipData=this.pictureOps_[this.currentBarMouseOverTarget_];var tooltipTitle=tooltipData.cmd_string;var tooltipTime=tooltipData.cmd_time.toFixed(4);v [...]
+CHART_PADDING_LEFT;var barWidth=BAR_WIDTH+BAR_PADDING;var tooltipOffset=Math.round((tooltipWidth-barWidth)*0.5);var left=CHART_PADDING_LEFT+this.currentBarMouseOverTarget_*barWidth-tooltipOffset;var top=Math.round((this.chartHeight_-tooltipHeight)*0.5);this.chartCtx_.save();this.chartCtx_.shadowOffsetX=0;this.chartCtx_.shadowOffsetY=5;this.chartCtx_.shadowBlur=4;this.chartCtx_.shadowColor='rgba(0,0,0,0.4)';this.chartCtx_.strokeStyle='#888';this.chartCtx_.fillStyle='#EEE';this.chartCtx_.f [...]
+toolTipTimePercentage+'%)',left+8,top+22);},drawBars_:function(){var op;var opColor=0;var opHeight=0;var opWidth=BAR_WIDTH+BAR_PADDING;var opHover=false;var bottom=this.chartHeight_-CHART_PADDING_BOTTOM;var maxHeight=this.chartHeight_-CHART_PADDING_BOTTOM-
+CHART_PADDING_TOP;var maxValue;if(this.usePercentileScale)
+maxValue=this.ninetyFifthPercentileCost_;else
+maxValue=this.maxCost_;for(var b=0;b<this.pictureOps_.length;b++){op=this.pictureOps_[b];opHeight=Math.round((op.cmd_time/maxValue)*maxHeight);opHeight=Math.max(opHeight,1);opHover=(b===this.currentBarMouseOverTarget_);opColor=this.getOpColor_(op.cmd_string,opHover);if(b===this.selectedOpIndex)
+this.chartCtx_.fillStyle='#FFFF00';else
+this.chartCtx_.fillStyle=opColor;this.chartCtx_.fillRect(CHART_PADDING_LEFT+b*opWidth,bottom-opHeight,BAR_WIDTH,opHeight);}},getOpColor_:function(opName,hover){var characters=opName.split('');var hue=characters.reduce(this.reduceNameToHue,0)%360;var saturation=30;var lightness=hover?'75%':'50%';return'hsl('+hue+', '+saturation+'%, '+lightness+'%)';},reduceNameToHue:function(previousValue,currentValue,index,array){return Math.round(previousValue+currentValue.charCodeAt(0)*HUE_CHAR_CODE_AD [...]
+uint8Array[c]=rawData.charCodeAt(c);var blob=new Blob([uint8Array],{type:'application/octet-binary'});var blobUrl=window.webkitURL.createObjectURL(blob);var link=document.createElementNS('http://www.w3.org/1999/xhtml','a');link.href=blobUrl;link.download=this.filename_.value;var event=document.createEvent('MouseEvents');event.initMouseEvent('click',true,false,window,0,0,0,0,0,false,false,false,false,0,null);link.dispatchEvent(event);},get picture(){return this.picture_;},set picture(pict [...]
+var bounds=this.rasterArea_.getBoundingClientRect();var selectorBounds=this.mouseModeSelector_.getBoundingClientRect();this.mouseModeSelector_.pos={x:(bounds.right-selectorBounds.width-10),y:bounds.top};this.rasterize_();this.scheduleUpdateContents_();},getRasterCanvasSize_:function(){var style=window.getComputedStyle(this.rasterArea_);var width=Math.max(parseInt(style.width),this.picture_.layerRect.width);var height=Math.max(parseInt(style.height),this.picture_.layerRect.height);return{ [...]
+return;this.updateContentsPending_=true;tr.b.requestAnimationFrameInThisFrameIfPossible(this.updateContents_.bind(this));},updateContents_:function(){this.updateContentsPending_=false;if(this.picture_){this.sizeInfo_.textContent='('+
+this.picture_.layerRect.width+' x '+
+this.picture_.layerRect.height+')';}
+this.drawOpsChartView_.updateChartContents();this.drawOpsChartView_.scrollSelectedItemIntoViewIfNecessary();if(!this.pictureAsImageData_)
+return;this.infoBar_.visible=false;this.infoBar_.removeAllButtons();if(this.pictureAsImageData_.error){this.infoBar_.message='Cannot rasterize...';this.infoBar_.addButton('More info...',function(e){var overlay=new tr.ui.b.Overlay();overlay.textContent=this.pictureAsImageData_.error;overlay.visible=true;e.stopPropagation();return false;}.bind(this));this.infoBar_.visible=true;}
+this.drawPicture_();},drawPicture_:function(){var size=this.getRasterCanvasSize_();if(size.width!==this.rasterCanvas_.width)
+this.rasterCanvas_.width=size.width;if(size.height!==this.rasterCanvas_.height)
+this.rasterCanvas_.height=size.height;this.rasterCtx_.clearRect(0,0,size.width,size.height);if(!this.pictureAsImageData_.imageData)
+return;var imgCanvas=this.pictureAsImageData_.asCanvas();var w=imgCanvas.width;var h=imgCanvas.height;this.rasterCtx_.drawImage(imgCanvas,0,0,w,h,0,0,w*this.zoomScaleValue_,h*this.zoomScaleValue_);},rasterize_:function(){if(this.picture_){this.picture_.rasterize({stopIndex:this.drawOpsView_.selectedOpIndex,showOverdraw:this.showOverdraw_},this.onRasterComplete_.bind(this));}},onRasterComplete_:function(pictureAsImageData){this.pictureAsImageData_=pictureAsImageData;this.scheduleUpdateCon [...]
+this.selectedOpIndex=tr.b.clamp(this.selectedOpIndex+increment,0,this.numOps);},get numOps(){return this.drawOpsView_.numOps;},get selectedOpIndex(){return this.drawOpsView_.selectedOpIndex;},set selectedOpIndex(index){this.drawOpsView_.selectedOpIndex=index;this.drawOpsChartView_.selectedOpIndex=index;},onChartBarClicked_:function(e){this.drawOpsView_.selectedOpIndex=this.drawOpsChartView_.selectedOpIndex;},onChangeDrawOps_:function(e){this.rasterize_();this.scheduleUpdateContents_();th [...]
+this.drawOpsChartSummaryView_.show();else
+this.drawOpsChartSummaryView_.hide();},trackMouse_:function(){this.mouseModeSelector_=document.createElement('tr-ui-b-mouse-mode-selector');this.mouseModeSelector_.targetElement=this.rasterArea_;this.rasterArea_.appendChild(this.mouseModeSelector_);this.mouseModeSelector_.supportedModeMask=tr.ui.b.MOUSE_SELECTOR_MODE.ZOOM;this.mouseModeSelector_.mode=tr.ui.b.MOUSE_SELECTOR_MODE.ZOOM;this.mouseModeSelector_.defaultMode=tr.ui.b.MOUSE_SELECTOR_MODE.ZOOM;this.mouseModeSelector_.settingsKey=' [...]
+return;var currentMouseViewPos=this.extractRelativeMousePosition_(e);this.zoomScaleValue_+=((this.lastMouseViewPos_.y-currentMouseViewPos.y)*0.001);this.zoomScaleValue_=Math.max(this.zoomScaleValue_,0.1);this.drawPicture_();this.lastMouseViewPos_=currentMouseViewPos;},onEndZoom_:function(e){this.lastMouseViewPos_=undefined;this.isZooming_=false;e.preventDefault();},extractRelativeMousePosition_:function(e){return{x:e.clientX-this.rasterArea_.offsetLeft,y:e.clientY-this.rasterArea_.offset [...]
+this.pictureDebugger_.picture=this.objectSnapshot_;}};tr.ui.analysis.ObjectSnapshotView.register(PictureSnapshotView,{typeNames:['cc::Picture','cc::LayeredPicture'],showInstances:false});return{PictureSnapshotView:PictureSnapshotView};});'use strict';tr.exportTo('tr.e.cc',function(){var knownRasterTaskNames=['TileManager::RunRasterTask','RasterWorkerPoolTaskImpl::RunRasterOnThread','RasterWorkerPoolTaskImpl::Raster','RasterTaskImpl::Raster','cc::RasterTask','RasterTask'];var knownAnalysi [...]
+return undefined;var tileData;if(slice.args.data)
+tileData=slice.args.data;else
+tileData=slice.args.tileData;if(tileData===undefined)
+return undefined;if(tileData.tile_id)
+return tileData.tile_id;var tile=tileData.tileId;if(!(tile instanceof tr.e.cc.TileSnapshot))
+return undefined;return tileData.tileId;}
+function isSliceDoingRasterization(slice){if(knownRasterTaskNames.indexOf(slice.title)!==-1)
+return true;return false;}
+function isSliceDoingAnalysis(slice){if(knownAnalysisTaskNames.indexOf(slice.title)!==-1)
+return true;return false;}
+return{getTileFromRasterTaskSlice:getTileFromRasterTaskSlice,isSliceDoingRasterization:isSliceDoingRasterization,isSliceDoingAnalysis:isSliceDoingAnalysis};});'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(){thro [...]
+var hasName=false;var hasTitle=false;table.tableRows=stackFrame.stackTrace;table.tableRows.forEach(function(row){hasName|=row.name!==undefined;hasTitle|=row.title!==undefined;});var cols=[];if(hasName){cols.push({title:'Name',value:function(row){return row.name;}});}
+if(hasTitle){cols.push({title:'Title',value:function(row){return row.title;}});}
+table.tableColumns=cols;table.rebuild();},tableForTesting:function(){return this.$.table;}});'use strict';Polymer('tr-ui-a-single-event-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 selection(){return this.currentSelection_;},set selection(selection){if(selection.length!==1)
 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:'Category',value:event.category});if(event.model!==undefined){var ufc=event.model.getUserFriendlyCategoryFromEvent(event);if(ufc!==undefined)
+rows.push({name:'User Friendly Category',value:ufc});}
+if(event.name)
+rows.push({name:'Name',value:event.name});rows.push({name:'Start',value:tr.v.ui.createScalarSpan(event.start,{unit:tr.v.Unit.byName.timeStampInMs})});if(event.duration){rows.push({name:'Wall Duration',value:tr.v.ui.createScalarSpan(event.duration,{unit:tr.v.Unit.byName.timeDurationInMs})});}
+if(event.cpuDuration){rows.push({name:'CPU Duration',value:tr.v.ui.createScalarSpan(event.cpuDuration,{unit:tr.v.Unit.byName.timeDurationInMs})});}
+if(event.subSlices!==undefined&&event.subSlices.length!==0){if(event.selfTime){rows.push({name:'Self Time',value:tr.v.ui.createScalarSpan(event.selfTime,{unit:tr.v.Unit.byName.timeDurationInMs})});}
+if(event.cpuSelfTime){var cpuSelfTimeEl=tr.v.ui.createScalarSpan(event.cpuSelfTime,{unit:tr.v.Unit.byName.timeDurationInMs});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});}
+if(event.durationInUserTime){rows.push({name:'Duration (U)',value:tr.v.ui.createScalarSpan(event.durationInUserTime,{unit:tr.v.Unit.byName.timeDurationInMs})});}
 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});}
+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.model.EventSet(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 [...]
+this.addArgsToRows_(rows,event.args);var event=new tr.b.Event('customize-rows');event.rows=rows;this.dispatchEvent(event);this.$.table.tableRows=rows;this.$.table.rebuild();}});'use strict';Polymer('tr-ui-e-chrome-cc-raster-task-view',{created:function(){this.selection_=undefined;},set selection(selection){this.selection_=selection;this.updateContents_();},updateColumns_:function(hadCpuDurations){var timeSpanConfig={unit:tr.v.Unit.byName.timeDurationInMs,ownerDocument:this.ownerDocument} [...]
+return'Totals';if(row.layer){var linkEl=document.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(function(){return new tr.ui.e.chrome.cc.LayerSelection(costs.layer);},'Layer '+row.layerId);return linkEl;}else{return'Layer '+row.layerId;}},width:'250px'},{title:'Num Tiles',value:function(row){return row.numTiles;},cmp:function(a,b){return a.numTiles-b.numTiles;}},{title:'Num Analysis Tasks',value:function(row){return row.numAnalysisTasks;},cmp:function(a,b){return a.n [...]
+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.$.content.tableColumns=columns;this.$.content.sortColumnIndex=columns.length-1;},updateContents_:function(){var table=this.$.content;if(this.selection_.length===0){this.$.link.setSelectionAndContent(undefined,'');table.tableRows=[];table.footerRows=[];table.rebuild();return;}
+var lthi=tr.e.cc.getTileFromRasterTaskSlice(this.selection_[0]).containingSnapshot;this.$.link.setSelectionAndContent(function(){return new tr.model.EventSet(lthi);},lthi.userFriendlyName);var costsByLayerId={};function getCurrentCostsForLayerId(tile){var layerId=tile.layerId;var lthi=tile.containingSnapshot;var layer;if(lthi.activeTree)
+layer=lthi.activeTree.findLayerWithId(layerId);if(layer===undefined&&lthi.pendingTree)
+layer=lthi.pendingTree.findLayerWithId(layerId);if(costsByLayerId[layerId]===undefined){costsByLayerId[layerId]={layerId:layerId,layer:layer,numTiles:0,numAnalysisTasks:0,numRasterTasks:0,duration:0,cpuDuration:0};}
+return costsByLayerId[layerId];}
+var totalDuration=0;var totalCpuDuration=0;var totalNumAnalyzeTasks=0;var totalNumRasterizeTasks=0;var hadCpuDurations=false;var tilesThatWeHaveSeen={};this.selection_.forEach(function(slice){var tile=tr.e.cc.getTileFromRasterTaskSlice(slice);var curCosts=getCurrentCostsForLayerId(tile);if(!tilesThatWeHaveSeen[tile.objectInstance.id]){tilesThatWeHaveSeen[tile.objectInstance.id]=true;curCosts.numTiles+=1;}
+if(tr.e.cc.isSliceDoingAnalysis(slice)){curCosts.numAnalysisTasks+=1;totalNumAnalyzeTasks+=1;}else{curCosts.numRasterTasks+=1;totalNumRasterizeTasks+=1;}
+curCosts.duration+=slice.duration;totalDuration+=slice.duration;if(slice.cpuDuration!==undefined){curCosts.cpuDuration+=slice.cpuDuration;totalCpuDuration+=slice.cpuDuration;hadCpuDurations=true;}});this.updateColumns_(hadCpuDurations);table.tableRows=tr.b.dictionaryValues(costsByLayerId);table.rebuild();table.footerRows=[{isTotals:true,numTiles:tr.b.dictionaryLength(tilesThatWeHaveSeen),numAnalysisTasks:totalNumAnalyzeTasks,numRasterTasks:totalNumRasterizeTasks,duration:totalDuration,cp [...]
+throw new Error('Fail: '+whySupported.why);this.slices_=tr.b.asArray(selection);this.tiles_=this.slices_.map(function(slice){var tile=tr.e.cc.getTileFromRasterTaskSlice(slice);if(tile===undefined)
+throw new Error('This should never happen due to .supports check.');return tile;});}
+RasterTaskSelection.whySuported=function(selection){if(!(selection instanceof tr.model.EventSet))
+return{ok:false,why:'Must be selection'};if(selection.length===0)
+return{ok:false,why:'Selection must be non empty'};var tile0;for(var i=0;i<selection.length;i++){var event=selection[i];if(!(event instanceof tr.model.Slice))
+return{ok:false,why:'Not a slice'};var tile=tr.e.cc.getTileFromRasterTaskSlice(selection[i]);if(tile===undefined)
+return{ok:false,why:'No tile found'};if(i===0){tile0=tile;}else{if(tile.containingSnapshot!=tile0.containingSnapshot){return{ok:false,why:'Raster tasks are from different compositor instances'};}}}
+return{ok:true};}
+RasterTaskSelection.supports=function(selection){return RasterTaskSelection.whySuported(selection).ok;};RasterTaskSelection.prototype={__proto__:tr.ui.e.chrome.cc.Selection.prototype,get specicifity(){return 3;},get associatedLayerId(){var tile0=this.tiles_[0];var allSameLayer=this.tiles_.every(function(tile){tile.layerId==tile0.layerId;});if(allSameLayer)
+return tile0.layerId;return undefined;},get extraHighlightsByLayerId(){var highlights={};this.tiles_.forEach(function(tile,i){if(highlights[tile.layerId]===undefined)
+highlights[tile.layerId]=[];var slice=this.slices_[i];highlights[tile.layerId].push({colorKey:slice.title,rect:tile.layerRect});},this);return highlights;},createAnalysis:function(){var sel=new tr.model.EventSet();this.slices_.forEach(function(slice){sel.push(slice);});var analysis;if(sel.length==1)
+analysis=document.createElement('tr-ui-a-single-event-sub-view');else
+analysis=document.createElement('tr-ui-e-chrome-cc-raster-task-view');analysis.selection=sel;return analysis;},findEquivalent:function(lthi){return undefined;},get containingSnapshot(){return this.tiles_[0].containingSnapshot;}};return{RasterTaskSelection:RasterTaskSelection};});'use strict';tr.exportTo('tr.ui.e.chrome.cc',function(){var TileSnapshotView=tr.ui.b.define('tr-ui-e-chrome-cc-tile-snapshot-view',tr.ui.analysis.ObjectSnapshotView);TileSnapshotView.prototype={__proto__:tr.ui.an [...]
+return;this.layerTreeView_.objectSnapshot=layerTreeHostImpl;this.layerTreeView_.selection=new tr.ui.e.chrome.cc.TileSelection(tile);}};tr.ui.analysis.ObjectSnapshotView.register(TileSnapshotView,{typeName:'cc::Tile',showInTrackView:false});return{TileSnapshotView:TileSnapshotView};});'use strict';tr.exportTo('tr.e.gpu',function(){var ObjectSnapshot=tr.model.ObjectSnapshot;function StateSnapshot(){ObjectSnapshot.apply(this,arguments);}
+StateSnapshot.prototype={__proto__:ObjectSnapshot.prototype,preInitialize:function(){this.screenshot_=undefined;},initialize:function(){if(this.args.screenshot)
+this.screenshot_=this.args.screenshot;},get screenshot(){return this.screenshot_;}};ObjectSnapshot.register(StateSnapshot,{typeName:'gpu::State'});return{StateSnapshot:StateSnapshot};});'use strict';tr.exportTo('tr.e.gpu',function(){var AsyncSlice=tr.model.AsyncSlice;function GpuAsyncSlice(){AsyncSlice.apply(this,arguments);}
+GpuAsyncSlice.prototype={__proto__:AsyncSlice.prototype,get viewSubGroupTitle(){if(this.args.channel){if(this.category=='disabled-by-default-gpu.device')
+return'Device.'+this.args.channel;else
+return'Service.'+this.args.channel;}
+return this.title;}};AsyncSlice.register(GpuAsyncSlice,{categoryParts:['disabled-by-default-gpu.device','disabled-by-default-gpu.service']});return{GpuAsyncSlice:GpuAsyncSlice};});'use strict';tr.exportTo('tr.ui.e.chrome.gpu',function(){var StateSnapshotView=tr.ui.b.define('tr-ui-e-chrome-gpu-state-snapshot-view',tr.ui.analysis.ObjectSnapshotView);StateSnapshotView.prototype={__proto__:tr.ui.analysis.ObjectSnapshotView.prototype,decorate:function(){this.classList.add('tr-ui-e-chrome-gpu- [...]
+this.objectSnapshot_.screenshot;}}};tr.ui.analysis.ObjectSnapshotView.register(StateSnapshotView,{typeName:'gpu::State'});return{StateSnapshotView:StateSnapshotView};});!function(){function n(n){return null!=n&&!isNaN(n)}function t(n){return n.length}function e(n){for(var t=1;n*t%1;)t*=10;return t}function r(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function u(){}function i(n){return aa+n in this}function o(n){return n [...]
+id+=ColorScheme.properties.brightenedOffsets[0];return ColorScheme.colorsAsStrings[id];}
+var ChartBase=tr.ui.b.define('svg',undefined,svgNS);ChartBase.prototype={__proto__:HTMLUnknownElement.prototype,decorate:function(){this.classList.add('chart-base');this.chartTitle_=undefined;this.seriesKeys_=undefined;this.width_=400;this.height_=300;var template=THIS_DOC.querySelector('#chart-base-template');var svgEl=template.content.querySelector('svg');for(var i=0;i<svgEl.children.length;i++)
+this.appendChild(svgEl.children[i].cloneNode(true));Object.defineProperty(this,'width',{get:function(){return this.width_;},set:function(width){this.width_=width;this.updateContents_();}});Object.defineProperty(this,'height',{get:function(){return this.height_;},set:function(height){this.height_=height;this.updateContents_();}});},get chartTitle(){return this.chartTitle_;},set chartTitle(chartTitle){this.chartTitle_=chartTitle;this.updateContents_();},get chartAreaElement(){return this.q [...]
+margin.top+=20;return margin;},get margin(){return this.getMargin_();},get chartAreaSize(){var margin=this.margin;return{width:this.width_-margin.left-margin.right,height:this.height_-margin.top-margin.bottom};},getLegendKeys_:function(){throw new Error('Not implemented');},updateScales_:function(){throw new Error('Not implemented');},updateContents_:function(){var margin=this.margin;var thisSel=d3.select(this);thisSel.attr('width',this.width_);thisSel.attr('height',this.height_);var cha [...]
+var width=this.chartAreaSize.width;titleSel.attr('transform','translate('+width*0.5+',-5)').style('display',undefined).style('text-anchor','middle').attr('class','title').attr('width',width).text(this.chartTitle_);},updateLegend_:function(){var keys=this.getLegendKeys_();if(keys===undefined)
+return;var chartAreaSel=d3.select(this.chartAreaElement);var chartAreaSize=this.chartAreaSize;var legendEntriesSel=chartAreaSel.selectAll('.legend').data(keys.slice().reverse());legendEntriesSel.enter().append('g').attr('class','legend').attr('transform',function(d,i){return'translate(0,'+i*20+')';}).append('text').text(function(key){return key;});legendEntriesSel.exit().remove();legendEntriesSel.attr('x',chartAreaSize.width-18).attr('width',18).attr('height',18).style('fill',function(ke [...]
+return this.tempHighlightedLegendKey_;return this.highlightedLegendKey_;},pushTempHighlightedLegendKey:function(key){if(this.tempHighlightedLegendKey_)
+throw new Error('push cannot nest');this.tempHighlightedLegendKey_=key;this.updateHighlight_();},popTempHighlightedLegendKey:function(key){if(this.tempHighlightedLegendKey_!=key)
+throw new Error('pop cannot happen');this.tempHighlightedLegendKey_=undefined;this.updateHighlight_();},updateHighlight_:function(){var chartAreaSel=d3.select(this.chartAreaElement);var legendEntriesSel=chartAreaSel.selectAll('.legend');var that=this;legendEntriesSel.each(function(key){var highlighted=key==that.currentHighlightedLegendKey;var color=getColorOfKey(key,highlighted);this.style.fill=color;if(highlighted)
+this.style.fontWeight='bold';else
+this.style.fontWeight='';});}};return{getColorOfKey:getColorOfKey,ChartBase:ChartBase};});'use strict';tr.exportTo('tr.ui.b',function(){var ChartBase=tr.ui.b.ChartBase;var ChartBase2D=tr.ui.b.define('chart-base-2d',ChartBase);ChartBase2D.prototype={__proto__:ChartBase.prototype,decorate:function(){ChartBase.prototype.decorate.call(this);this.classList.add('chart-base-2d');this.xScale_=d3.scale.linear();this.yScale_=d3.scale.linear();this.isYLogScale_=false;this.yLogScaleMin_=undefined;th [...]
+throw new Error('data must be an Array');this.data_=data;this.updateSeriesKeys_();this.updateDataRange_();this.updateContents_();},set isYLogScale(logScale){if(logScale)
+this.yScale_=d3.scale.log(10);else
+this.yScale_=d3.scale.linear();this.isYLogScale_=logScale;},getYScaleMin_:function(){return this.isYLogScale_?this.yLogScaleMin_:0;},getYScaleDomain_:function(minValue,maxValue){if(this.isYLogScale_)
+return[this.getYScaleMin_(),maxValue];return[Math.min(minValue,this.getYScaleMin_()),maxValue];},getSampleWidth_:function(data,index,leftSide){var leftIndex,rightIndex;if(leftSide){leftIndex=Math.max(index-1,0);rightIndex=index;}else{leftIndex=index;rightIndex=Math.min(index+1,data.length-1);}
+var leftWidth=this.getXForDatum_(data[index],index)-
+this.getXForDatum_(data[leftIndex],leftIndex);var rightWidth=this.getXForDatum_(data[rightIndex],rightIndex)-
+this.getXForDatum_(data[index],index);return leftWidth*0.5+rightWidth*0.5;},getLegendKeys_:function(){if(this.seriesKeys_&&this.seriesKeys_.length>1)
+return this.seriesKeys_.slice();return[];},updateSeriesKeys_:function(){var keySet={};this.data_.forEach(function(datum){Object.keys(datum).forEach(function(key){if(this.isDatumFieldSeries_(key))
+keySet[key]=true;},this);},this);this.seriesKeys_=Object.keys(keySet);},isDatumFieldSeries_:function(fieldName){throw new Error('Not implemented');},getXForDatum_:function(datum,index){throw new Error('Not implemented');},updateScales_:function(){if(this.data_.length===0)
+return;var width=this.chartAreaSize.width;var height=this.chartAreaSize.height;this.xScale_.range([0,width]);this.xScale_.domain(d3.extent(this.data_,this.getXForDatum_.bind(this)));var yRange=new tr.b.Range();this.data_.forEach(function(datum){this.seriesKeys_.forEach(function(key){if(datum[key]!==undefined)
+yRange.addValue(datum[key]);});},this);this.yScale_.range([height,0]);this.yScale_.domain([yRange.min,yRange.max]);},updateBrushContents_:function(brushSel){brushSel.selectAll('*').remove();},updateXAxis_:function(xAxis){xAxis.selectAll('*').remove();xAxis[0][0].style.opacity=0;xAxis.attr('transform','translate(0,'+this.chartAreaSize.height+')').call(d3.svg.axis().scale(this.xScale_).orient('bottom'));window.requestAnimationFrame(function(){var previousRight=undefined;xAxis.selectAll('.t [...]
+minValue=1;var onePowerLess=Math.floor(Math.log(minValue)/Math.log(10))-1;this.yLogScaleMin_=Math.pow(10,onePowerLess);}},updateYAxis_:function(yAxis){yAxis.selectAll('*').remove();yAxis[0][0].style.opacity=0;var axisModifier=d3.svg.axis().scale(this.yScale_).orient('left');if(this.isYLogScale_){if(this.yLogScaleMin_===undefined)
+return;var minValue=this.dataRange_.min;if(minValue==0)
+minValue=1;var largestPower=Math.ceil(Math.log(this.dataRange_.max)/Math.log(10))+1;var smallestPower=Math.floor(Math.log(minValue)/Math.log(10));var tickValues=[];for(var i=smallestPower;i<largestPower;i++){tickValues.push(Math.pow(10,i));}
+axisModifier=axisModifier.tickValues(tickValues).tickFormat(function(d){return d;});}
+yAxis.call(axisModifier);window.requestAnimationFrame(function(){var previousTop=undefined;var leftMargin=0;yAxis.selectAll('.tick')[0].forEach(function(tick){var bbox=tick.getBBox();leftMargin=Math.max(leftMargin,bbox.width);var currentTop=tick.transform.baseVal[0].matrix.f;var currentBottom=currentTop+bbox.height;if((previousTop===undefined)||(previousTop>(currentBottom+3))){previousTop=currentTop;}else{tick.style.opacity=0;}});if(leftMargin>this.leftMargin_){this.leftMargin_=leftMargi [...]
+return;if(multiSeriesDatum[seriesKey]===undefined)
+return;if(!this.isDatumFieldSeries_(seriesKey))
+return;var singleSeriesDatum={x:x};singleSeriesDatum[seriesKey]=multiSeriesDatum[seriesKey];dataBySeriesKey[seriesKey].push(singleSeriesDatum);},this);},this);return dataBySeriesKey;},getDataPointAtClientPoint_:function(clientX,clientY){var rect=this.getBoundingClientRect();var margin=this.margin;var x=clientX-rect.left-margin.left;var y=clientY-rect.top-margin.top;x=this.xScale_.invert(x);y=this.yScale_.invert(y);x=tr.b.clamp(x,this.xScale_.domain()[0],this.xScale_.domain()[1]);y=tr.b.c [...]
+var dataEvent=new tr.b.Event('item-mousemove');dataEvent.button=button;this.prepareDataEvent_(mouseEvent,dataEvent);this.dispatchEvent(dataEvent);},onMouseUp_:function(button,mouseEvent){mouseEvent.preventDefault();mouseEvent.stopPropagation();var dataEvent=new tr.b.Event('item-mouseup');dataEvent.button=button;this.prepareDataEvent_(mouseEvent,dataEvent);this.dispatchEvent(dataEvent);this.classList.remove('updating-brushing-state');}};return{ChartBase2D:ChartBase2D};});'use strict';tr.e [...]
+this.getSampleWidth_(this.data_,leftIndex,true));r.addValue(this.getXForDatum_(this.data_[rightIndex],rightIndex)+
+this.getSampleWidth_(this.data_,rightIndex,false));return r;},getDataIndex_:function(dataX){if(!this.data_)
+return undefined;var bisect=d3.bisector(this.getXForDatum_.bind(this)).right;return bisect(this.data_,dataX)-1;},prepareDataEvent_:function(mouseEvent,dataEvent){ChartBase2D.prototype.prepareDataEvent_.call(this,mouseEvent,dataEvent);dataEvent.index=this.getDataIndex_(dataEvent.x);if(dataEvent.index!==undefined)
+dataEvent.data=this.data_[dataEvent.index];},updateBrushContents_:function(brushSel){brushSel.selectAll('*').remove();var brushes=this.brushedRange_.isEmpty?[]:[this.brushedRange_];var brushRectsSel=brushSel.selectAll('rect').data(brushes);brushRectsSel.enter().append('rect');brushRectsSel.exit().remove();brushRectsSel.attr('x',function(d){return this.xScale_(d.min);}.bind(this)).attr('y',0).attr('width',function(d){return this.xScale_(d.max)-this.xScale_(d.min);}.bind(this)).attr('heigh [...]
+this.updateToolbar_();this.updateContents_();},get frametimeType(){return this.frametimeType_;},set frametimeType(type){if(this.frametimeType_===type)
+return;this.frametimeType_=type;this.updateContents_();},get selectedProcessId(){return this.selectedProcessId_;},set selectedProcessId(process){if(this.selectedProcessId_===process)
+return;this.selectedProcessId_=process;this.updateContents_();},set selection(selection){if(this.latencyChart_===undefined)
+return;this.latencyChart_.brushedRange=selection.bounds;},setBrushedIndices:function(mouseDownIndex,curIndex){this.mouseDownIndex_=mouseDownIndex;this.curMouseIndex_=curIndex;this.updateBrushedRange_();},updateBrushedRange_:function(){if(this.latencyChart_===undefined)
+return;var r=new tr.b.Range();if(this.mouseDownIndex_===undefined){this.latencyChart_.brushedRange=r;return;}
+r=this.latencyChart_.computeBrushRangeFromIndices(this.mouseDownIndex_,this.curMouseIndex_);this.latencyChart_.brushedRange=r;var latencySlices=[];this.model_.getAllThreads().forEach(function(thread){thread.iterateAllEvents(function(event){if(event.title.indexOf('InputLatency:')===0)
+latencySlices.push(event);});});latencySlices=tr.model.helpers.getSlicesIntersectingRange(r,latencySlices);var event=new tr.model.RequestSelectionChangeEvent();event.selection=new tr.model.EventSet(latencySlices);this.latencyChart_.dispatchEvent(event);},registerMouseEventForLatencyChart_:function(){this.latencyChart_.addEventListener('item-mousedown',function(e){this.mouseDownIndex_=e.index;this.curMouseIndex_=e.index;this.updateBrushedRange_();}.bind(this));this.latencyChart_.addEventL [...]
+return;this.curMouseIndex_=e.index;this.updateBrushedRange_();}.bind(this));this.latencyChart_.addEventListener('item-mouseup',function(e){this.curMouseIndex=e.index;this.updateBrushedRange_();}.bind(this));},updateToolbar_:function(){var browserProcess=this.modelHelper_.browserProcess;var labels=[];if(browserProcess!==undefined){var label_str='Browser: '+browserProcess.pid;labels.push({label:label_str,value:browserProcess.pid});}
+tr.b.iterItems(this.modelHelper_.rendererHelpers,function(pid,rendererHelper){var rendererProcess=rendererHelper.process;var label_str='Renderer: '+rendererProcess.userFriendlyName;labels.push({label:label_str,value:rendererProcess.userFriendlyName});},this);if(labels.length===0)
+return;this.selectedProcessId_=labels[0].value;var toolbarEl=this.$.toolbar;toolbarEl.appendChild(tr.ui.b.createSelector(this,'frametimeType','inputLatencySidePanel.frametimeType',this.frametimeType_,[{label:'Main Thread Frame Times',value:tr.model.helpers.MAIN_FRAMETIME_TYPE},{label:'Impl Thread Frame Times',value:tr.model.helpers.IMPL_FRAMETIME_TYPE}]));toolbarEl.appendChild(tr.ui.b.createSelector(this,'selectedProcessId','inputLatencySidePanel.selectedProcessId',this.selectedProcessId [...]
+return this.model_.bounds;else
+return this.rangeOfInterest_;},createLatencyLineChart:function(data,title){var chart=new tr.ui.b.LineChart();var width=600;if(document.body.clientWidth!=undefined)
+width=document.body.clientWidth*0.5;chart.setSize({width:width,height:chart.height});chart.chartTitle=title;chart.data=data;return chart;},updateContents_:function(){var resultArea=this.$.result_area;this.latencyChart_=undefined;this.frametimeChart_=undefined;resultArea.textContent='';if(this.modelHelper_===undefined)
+return;var rangeOfInterest=this.currentRangeOfInterest;var chromeProcess;if(this.modelHelper_.rendererHelpers[this.selectedProcessId_])
+chromeProcess=this.modelHelper_.rendererHelpers[this.selectedProcessId_];else
+chromeProcess=this.modelHelper_.browserHelper;var frameEvents=chromeProcess.getFrameEventsInRange(this.frametimeType,rangeOfInterest);var frametimeData=tr.model.helpers.getFrametimeDataFromEvents(frameEvents);var averageFrametime=tr.b.Statistics.mean(frametimeData,function(d){return d.frametime;});var latencyEvents=this.modelHelper_.browserHelper.getLatencyEventsInRange(rangeOfInterest);var latencyData=[];latencyEvents.forEach(function(event){if(event.inputLatency===undefined)
+return;latencyData.push({x:event.start,latency:event.inputLatency/1000});});var averageLatency=tr.b.Statistics.mean(latencyData,function(d){return d.latency;});var latencySummaryText=document.createElement('div');latencySummaryText.appendChild(tr.ui.b.createSpan({textContent:'Average Latency '+averageLatency+' ms',bold:true}));resultArea.appendChild(latencySummaryText);var frametimeSummaryText=document.createElement('div');frametimeSummaryText.appendChild(tr.ui.b.createSpan({textContent: [...]
+if(frametimeData.length!=0){this.frametimeChart_=this.createLatencyLineChart(frametimeData,'Frame Times');this.frametimeChart_.style.display='block';resultArea.appendChild(this.frametimeChart_);}},get rangeOfInterest(){return this.rangeOfInterest_;},set rangeOfInterest(rangeOfInterest){this.rangeOfInterest_=rangeOfInterest;this.updateContents_();},supportsModel:function(m){if(m==undefined){return{supported:false,reason:'Unknown tracing model'};}
+if(!tr.model.helpers.ChromeModelHelper.supportsModel(m)){return{supported:false,reason:'No Chrome browser or renderer process found'};}
+var modelHelper=m.getOrCreateHelper(tr.model.helpers.ChromeModelHelper);if(modelHelper.browserHelper&&modelHelper.browserHelper.hasLatencyEvents){return{supported:true};}
+return{supported:false,reason:'No InputLatency events trace. Consider enabling '+'benchmark" and "input" category when recording the trace'};},get textLabel(){return'Input Latency';}});'use strict';tr.exportTo('tr.ui.b',function(){var ChartBase=tr.ui.b.ChartBase;var getColorOfKey=tr.ui.b.getColorOfKey;var MIN_RADIUS=100;var PieChart=tr.ui.b.define('pie-chart',ChartBase);PieChart.prototype={__proto__:ChartBase.prototype,decorate:function(){ChartBase.prototype.decorate.call(this);this.clas [...]
+throw new Error('Label '+k+' has been used already');seriesKeys.push(k);seenSeriesKeys[k]=true;},this);this.seriesKeys_=seriesKeys;}else{this.seriesKeys_=undefined;}
+this.data_=data;this.updateContents_();},get margin(){var margin={top:0,right:0,bottom:0,left:0};if(this.chartTitle_)
+margin.top+=40;return margin;},getMinSize:function(){this.updateContents_();var labelSel=d3.select(this.labelsGroup_).selectAll('.label');var maxLabelWidth=-Number.MAX_VALUE;var leftTextHeightSum=0;var rightTextHeightSum=0;labelSel.each(function(l){var r=this.getBoundingClientRect();maxLabelWidth=Math.max(maxLabelWidth,r.width+32);if(this.style.textAnchor=='end'){leftTextHeightSum+=r.height;}else{rightTextHeightSum+=r.height;}});var titleWidth=this.querySelector('#title').getBoundingClie [...]
+return;},updateContents_:function(){ChartBase.prototype.updateContents_.call(this);if(!this.data_)
+return;var width=this.chartAreaSize.width;var height=this.chartAreaSize.height;var radius=Math.max(MIN_RADIUS,Math.min(width,height*0.95)/2);d3.select(this.pieGroup_).attr('transform','translate('+width/2+','+height/2+')');var pieLayout=d3.layout.pie().value(function(d){return d.value;}).sort(null);var piePathsSel=d3.select(this.pathsGroup_).datum(this.data_).selectAll('path').data(pieLayout);function midAngle(d){return d.startAngle+(d.endAngle-d.startAngle)/2;}
+var pathsArc=d3.svg.arc().innerRadius(0).outerRadius(radius-30);var valueLabelArc=d3.svg.arc().innerRadius(radius-100).outerRadius(radius-30);var lineBeginArc=d3.svg.arc().innerRadius(radius-50).outerRadius(radius-50);var lineEndArc=d3.svg.arc().innerRadius(radius).outerRadius(radius);piePathsSel.enter().append('path').attr('class','arc').attr('fill',function(d,i){var origData=this.data_[i];var highlighted=(origData.label===this.currentHighlightedLegendKey);return getColorOfKey(origData. [...]
+return'';if(d.endAngle-d.startAngle<0.4)
+return'';return origData.valueText;}.bind(this));piePathsSel.exit().remove();var labelSel=d3.select(this.labelsGroup_).selectAll('.label').data(pieLayout(this.data_));labelSel.enter().append('text').attr('class','label').attr('dy','.35em');labelSel.text(function(d){if(d.data.label.length>40)
+return d.data.label.substr(0,40)+'...';return d.data.label;});labelSel.attr('transform',function(d){var pos=lineEndArc.centroid(d);pos[0]=radius*(midAngle(d)<Math.PI?1:-1);return'translate('+pos+')';});labelSel.style('text-anchor',function(d){return midAngle(d)<Math.PI?'start':'end';});var lineSel=d3.select(this.linesGroup_).selectAll('.line').data(pieLayout(this.data_));lineSel.enter().append('polyline').attr('class','line').attr('dy','.35em');lineSel.attr('points',function(d){var pos=l [...]
+ResultsForGroup.prototype={get wallTime(){var wallSum=tr.b.Statistics.sum(this.topLevelSlices,function(x){return x.duration;});return wallSum;},get cpuTime(){var cpuDuration=0;for(var i=0;i<this.topLevelSlices.length;i++){var x=this.topLevelSlices[i];if(x.cpuDuration===undefined){if(x.duration===undefined)
+continue;return 0;}
+cpuDuration+=x.cpuDuration;}
+return cpuDuration;},appendGroupContents:function(group){if(group.model!=this.model)
+throw new Error('Models must be the same');group.allSlices.forEach(function(slice){this.allSlices.push(slice);},this);group.topLevelSlices.forEach(function(slice){this.topLevelSlices.push(slice);},this);},appendThreadSlices:function(rangeOfInterest,thread){var tmp=this.getSlicesIntersectingRange(rangeOfInterest,thread.sliceGroup.slices);tmp.forEach(function(slice){this.allSlices.push(slice);},this);tmp=this.getSlicesIntersectingRange(rangeOfInterest,thread.sliceGroup.topLevelSlices);tmp. [...]
+slicesInFilterRange.push(slice);}
+return slicesInFilterRange;}};Polymer('tr-ui-e-s-time-summary-side-panel',{ready:function(){this.rangeOfInterest_=new tr.b.Range();this.selection_=undefined;this.groupBy_=GROUP_BY_PROCESS_NAME;this.groupingUnit_=CPU_TIME_GROUPING_UNIT;this.showCpuIdleTime_=true;this.chart_=undefined;var toolbarEl=this.$.toolbar;this.groupBySelector_=tr.ui.b.createSelector(this,'groupBy','timeSummarySidePanel.groupBy',this.groupBy_,[{label:'Group by process',value:GROUP_BY_PROCESS_NAME},{label:'Group by t [...]
+sum+=opt_extraValue;function compareByValue(a,b){return getValue(a)-getValue(b);}
+groups.sort(compareByValue);var thresshold=0.1*sum;while(groups.length>1){var group=groups[0];if(getValue(group)>=thresshold)
+break;var v=getValue(group);if(v+getValue(otherGroup)>thresshold)
+break;groups.splice(0,1);otherGroup.appendGroupContents(group);}
+if(getValue(otherGroup)>0)
+groups.push(otherGroup);groups.sort(compareByValue);return groups;},generateResultsForGroup:function(model,name){return new ResultsForGroup(model,name);},createPieChartFromResultGroups:function(groups,title,getValue,opt_extraData){var chart=new tr.ui.b.PieChart();function pushDataForGroup(data,resultsForGroup,value){data.push({label:resultsForGroup.name,value:value,valueText:tr.v.Unit.byName.timeDurationInMs.format(value),resultsForGroup:resultsForGroup});}
+chart.addEventListener('item-click',function(clickEvent){var resultsForGroup=clickEvent.data.resultsForGroup;if(resultsForGroup===undefined)
+return;var event=new tr.model.RequestSelectionChangeEvent();event.selection=new tr.model.EventSet(resultsForGroup.allSlices);event.selection.timeSummaryGroupName=resultsForGroup.name;chart.dispatchEvent(event);});var data=[];groups.forEach(function(resultsForGroup){var value=getValue(resultsForGroup);if(value===0)
+return;pushDataForGroup(data,resultsForGroup,value);});if(opt_extraData)
+data.push.apply(data,opt_extraData);chart.chartTitle=title;chart.data=data;return chart;},get model(){return this.model_;},set model(model){this.model_=model;this.updateContents_();},get groupBy(){return groupBy_;},set groupBy(groupBy){this.groupBy_=groupBy;if(this.groupBySelector_)
+this.groupBySelector_.selectedValue=groupBy;this.updateContents_();},get groupingUnit(){return groupingUnit_;},set groupingUnit(groupingUnit){this.groupingUnit_=groupingUnit;if(this.groupingUnitSelector_)
+this.groupingUnitSelector_.selectedValue=groupingUnit;this.updateShowCpuIdleTimeCheckboxVisibility_();this.updateContents_();},get showCpuIdleTime(){return this.showCpuIdleTime_;},set showCpuIdleTime(showCpuIdleTime){this.showCpuIdleTime_=showCpuIdleTime;if(this.showCpuIdleTimeCheckbox_)
+this.showCpuIdleTimeCheckbox_.checked=showCpuIdleTime;this.updateContents_();},updateShowCpuIdleTimeCheckboxVisibility_:function(){if(!this.showCpuIdleTimeCheckbox_)
+return;var visible=this.groupingUnit_==CPU_TIME_GROUPING_UNIT;if(visible)
+this.showCpuIdleTimeCheckbox_.style.display='';else
+this.showCpuIdleTimeCheckbox_.style.display='none';},getGroupNameForThread_:function(thread){if(this.groupBy_==GROUP_BY_THREAD_NAME)
+return thread.name?thread.name:thread.userFriendlyName;if(this.groupBy_==GROUP_BY_PROCESS_NAME)
+return thread.parent.userFriendlyName;},updateContents_:function(){var resultArea=this.$.result_area;this.chart_=undefined;resultArea.textContent='';if(this.model_===undefined)
+return;var rangeOfInterest;if(this.rangeOfInterest_.isEmpty)
+rangeOfInterest=this.model_.bounds;else
+rangeOfInterest=this.rangeOfInterest_;var allGroup=this.generateResultsForGroup(this.model_,'all');var resultsByGroupName={};this.model_.getAllThreads().forEach(function(thread){var groupName=this.getGroupNameForThread_(thread);if(resultsByGroupName[groupName]===undefined){resultsByGroupName[groupName]=this.generateResultsForGroup(this.model_,groupName);}
+resultsByGroupName[groupName].appendThreadSlices(rangeOfInterest,thread);allGroup.appendThreadSlices(rangeOfInterest,thread);},this);var getValueFromGroup=function(group){if(this.groupingUnit_==WALL_TIME_GROUPING_UNIT)
+return group.wallTime;return group.cpuTime;}.bind(this);var summaryText=document.createElement('div');summaryText.appendChild(tr.ui.b.createSpan({textContent:'Total '+this.groupingUnit_+': ',bold:true}));summaryText.appendChild(tr.v.ui.createScalarSpan(getValueFromGroup(allGroup),{unit:tr.v.Unit.byName.timeDurationInMs,ownerDocument:this.ownerDocument}));resultArea.appendChild(summaryText);var extraValue=0;var extraData=[];if(this.showCpuIdleTime_&&this.groupingUnit_===CPU_TIME_GROUPING_ [...]
+var otherGroup=this.generateResultsForGroup(this.model_,'Other');var groups=this.trimPieChartData(tr.b.dictionaryValues(resultsByGroupName),otherGroup,getValueFromGroup,extraValue);if(groups.length==0){resultArea.appendChild(tr.ui.b.createSpan({textContent:'No data'}));return undefined;}
+this.chart_=this.createPieChartFromResultGroups(groups,this.groupingUnit_+' breakdown by '+this.groupBy_,getValueFromGroup,extraData);resultArea.appendChild(this.chart_);this.chart_.addEventListener('click',function(){var event=new tr.model.RequestSelectionChangeEvent();event.selection=new tr.c.EventSet([]);this.dispatchEvent(event);});this.chart_.setSize(this.chart_.getMinSize());},get selection(){return selection_;},set selection(selection){this.selection_=selection;if(this.chart_===un [...]
+return;if(selection.timeSummaryGroupName)
+this.chart_.highlightedLegendKey=selection.timeSummaryGroupName;else
+this.chart_.highlightedLegendKey=undefined;},get rangeOfInterest(){return this.rangeOfInterest_;},set rangeOfInterest(rangeOfInterest){this.rangeOfInterest_=rangeOfInterest;this.updateContents_();},supportsModel:function(model){return{supported:false};},get textLabel(){return'Time Summary';}});}());'use strict';tr.exportTo('tr.e.system_stats',function(){var ObjectSnapshot=tr.model.ObjectSnapshot;function SystemStatsSnapshot(objectInstance,ts,args){ObjectSnapshot.apply(this,arguments);thi [...]
+SystemStatsSnapshot.prototype={__proto__:ObjectSnapshot.prototype,initialize:function(){if(this.args.length==0)
+throw new Error('No system stats snapshot data.');this.stats_=this.args;},getStats:function(){return this.stats_;},setStats:function(stats){this.stats_=stats;}};ObjectSnapshot.register(SystemStatsSnapshot,{typeName:'base::TraceEventSystemStatsMonitor::SystemStats'});return{SystemStatsSnapshot:SystemStatsSnapshot};});'use strict';tr.exportTo('tr.ui.e.system_stats',function(){var SystemStatsSnapshotView=tr.ui.b.define('tr-ui-e-system-stats-snapshot-view',tr.ui.analysis.ObjectSnapshotView); [...]
+this.textContent='';var stats=snapshot.getStats();this.appendChild(this.buildList_(stats));},isFloat:function(n){return typeof n==='number'&&n%1!==0;},buildList_:function(stats){var statList=document.createElement('ul');for(var statName in stats){var statText=document.createElement('li');statText.textContent=''+statName+': ';statList.appendChild(statText);if(stats[statName]instanceof Object){statList.appendChild(this.buildList_(stats[statName]));}else{if(this.isFloat(stats[statName]))
+statText.textContent+=stats[statName].toFixed(2);else
+statText.textContent+=stats[statName];}}
+return statList;}};tr.ui.analysis.ObjectSnapshotView.register(SystemStatsSnapshotView,{typeName:'base::TraceEventSystemStatsMonitor::SystemStats'});return{SystemStatsSnapshotView:SystemStatsSnapshotView};});'use strict';tr.exportTo('tr.ui.b',function(){var constants={HEADING_WIDTH:250};return{constants:constants};});'use strict';Polymer('tr-ui-heading',{DOWN_ARROW:String.fromCharCode(0x25BE),RIGHT_ARROW:String.fromCharCode(0x25B8),ready:function(viewport){this.style.width=(tr.ui.b.consta [...]
+return;this.heading_=text;this.updateContents_();},set arrowVisible(val){if(this.arrowVisible_===val)
+return;this.arrowVisible_=!!val;this.updateContents_();},set tooltip(text){this.$.heading.title=text;},set selectionGenerator(generator){if(this.selectionGenerator_===generator)
+return;this.selectionGenerator_=generator;this.updateContents_();},get expanded(){return this.expanded_;},set expanded(expanded){if(this.expanded_===expanded)
+return;this.expanded_=!!expanded;this.updateContents_();},onHeadingDivClicked_:function(){this.dispatchEvent(new tr.b.Event('heading-clicked',{'bubbles':true}));},updateContents_:function(){if(this.arrowVisible_){this.$.arrow.style.display='';}else{this.$.arrow.style.display='none';this.$.heading.style.display=this.expanded_?'':'none';}
+if(this.arrowVisible_){this.$.arrow.textContent=this.expanded_?this.DOWN_ARROW:this.RIGHT_ARROW;}
+this.$.link.style.display='none';this.$.heading_content.style.display='none';if(this.selectionGenerator_){this.$.link.style.display='inline-block';this.$.link.selection=this.selectionGenerator_;this.$.link.textContent=this.heading_;}else{this.$.heading_content.style.display='inline-block';this.$.heading_content.textContent=this.heading_;}}});'use strict';tr.exportTo('tr.ui.tracks',function(){var Track=tr.ui.b.define('track',tr.ui.b.ContainerThatDecoratesItsChildren);Track.prototype={__pr [...]
+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 StackedBarsTrack=tr.ui.b.define('stacked-bars-track',tr.ui.tracks.Track);StackedBarsTrack.prototype={__proto__:tr.ui.tracks.Track.prototype,decorate:function(viewport){tr.ui.tracks.Track.prototype.decorate.call(this,viewport);this.classList.add('stacked-bars-track');this.objectInstance_=null;this.heading_=document.createElement('tr-ui-heading');this.appendChild(this.headin [...]
+var snapshots=this.objectInstance_.snapshots;var maxBounds=this.objectInstance_.parent.model.bounds.max;tr.b.iterateOverIntersectingIntervals(snapshots,function(x){return x.ts;},function(x,i){if(i==snapshots.length-1){if(snapshots.length==1)
+return maxBounds;return snapshots[i].ts-snapshots[i-1].ts;}
+return snapshots[i+1].ts-snapshots[i].ts;},loWX,hiWX,onSnapshot);},addEventNearToProvidedEventToSelection:function(event,offset,selection){if(!(event instanceof tr.model.ObjectSnapshot))
+throw new Error('Unrecognized event');var objectSnapshots=this.objectInstance_.snapshots;var index=objectSnapshots.indexOf(event);var newIndex=index+offset;if(newIndex>=0&&newIndex<objectSnapshots.length){selection.push(objectSnapshots[newIndex]);return true;}
+return false;},addAllEventsMatchingFilterToSelection:function(filter,selection){},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){var snapshot=tr.b.findClosestElementInSortedArray(this.objectInstance_.snapshots,function(x){return x.ts;},worldX,worldMaxDist);if(!snapshot)
+return;selection.push(snapshot);}};return{StackedBarsTrack:StackedBarsTrack};});'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.Track);ObjectInstanceTrack.prototype={__proto__:tr.ui.tracks.Track.prototype,decorate:function(viewport){tr.ui.tracks.Track.prototype.decorate.call(this,viewport);this.classList.add('object-instance-t [...]
+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.e.system_stats',function(){var EventPresenter=tr.ui.b.EventPresenter;var statCount;var excludedStats={'meminfo':{'pswpin':0,'pswpout':0,'pgmajfault':0},'diskinfo':{'io':0,'io_time':0,'read_time':0,'reads':0,'reads_merged':0,'sectors_read [...]
+if(objectInstances.length!=1)
+throw new Error('Bad object instance count.');this.objectInstance_=objectInstances[0];if(this.objectInstance_!==null){this.computeRates_(this.objectInstance_.snapshots);this.maxStats_=this.computeMaxStats_(this.objectInstance_.snapshots);}},computeRates_:function(snapshots){for(var i=0;i<snapshots.length;i++){var snapshot=snapshots[i];var stats=snapshot.getStats();var prevSnapshot;var prevStats;if(i==0){prevSnapshot=snapshots[0];}else{prevSnapshot=snapshots[i-1];}
+prevStats=prevSnapshot.getStats();var timeIntervalSeconds=(snapshot.ts-prevSnapshot.ts)/1000;if(timeIntervalSeconds==0)
+timeIntervalSeconds=1;this.computeRatesRecursive_(prevStats,stats,timeIntervalSeconds);}},computeRatesRecursive_:function(prevStats,stats,timeIntervalSeconds){for(var statName in stats){if(stats[statName]instanceof Object){this.computeRatesRecursive_(prevStats[statName],stats[statName],timeIntervalSeconds);}else{if(statName=='sectors_read'){stats['bytes_read_per_sec']=(stats['sectors_read']-
+prevStats['sectors_read'])*512/timeIntervalSeconds;}
+if(statName=='sectors_written'){stats['bytes_written_per_sec']=(stats['sectors_written']-
+prevStats['sectors_written'])*512/timeIntervalSeconds;}
+if(statName=='pgmajfault'){stats['pgmajfault_per_sec']=(stats['pgmajfault']-
+prevStats['pgmajfault'])/timeIntervalSeconds;}
+if(statName=='pswpin'){stats['bytes_swpin_per_sec']=(stats['pswpin']-
+prevStats['pswpin'])*1000/timeIntervalSeconds;}
+if(statName=='pswpout'){stats['bytes_swpout_per_sec']=(stats['pswpout']-
+prevStats['pswpout'])*1000/timeIntervalSeconds;}}}},computeMaxStats_:function(snapshots){var maxStats=new Object();statCount=0;for(var i=0;i<snapshots.length;i++){var snapshot=snapshots[i];var stats=snapshot.getStats();this.computeMaxStatsRecursive_(stats,maxStats,excludedStats);}
+return maxStats;},computeMaxStatsRecursive_:function(stats,maxStats,excludedStats){for(var statName in stats){if(stats[statName]instanceof Object){if(!(statName in maxStats))
+maxStats[statName]=new Object();var excludedNested;if(excludedStats&&statName in excludedStats)
+excludedNested=excludedStats[statName];else
+excludedNested=null;this.computeMaxStatsRecursive_(stats[statName],maxStats[statName],excludedNested);}else{if(excludedStats&&statName in excludedStats)
+continue;if(!(statName in maxStats)){maxStats[statName]=0;statCount++;}
+if(stats[statName]>maxStats[statName])
+maxStats[statName]=stats[statName];}}},get height(){return window.getComputedStyle(this).height;},set height(height){this.style.height=height;},draw:function(type,viewLWorld,viewRWorld){switch(type){case tr.ui.tracks.DrawType.GENERAL_EVENT:this.drawStatBars_(viewLWorld,viewRWorld);break;}},drawStatBars_:function(viewLWorld,viewRWorld){var ctx=this.context();var pixelRatio=window.devicePixelRatio||1;var bounds=this.getBoundingClientRect();var width=bounds.width*pixelRatio;var height=(boun [...]
+lowIndex-=1;for(var i=lowIndex;i<objectSnapshots.length;++i){var snapshot=objectSnapshots[i];var trace=snapshot.getStats();var currentY=height;var left=snapshot.ts;if(left>viewRWorld)
+break;var leftView=vp.xWorldToView(left);if(leftView<0)
+leftView=0;var right;if(i!=objectSnapshots.length-1){right=objectSnapshots[i+1].ts;}else{if(objectSnapshots.length>1)
+right=objectSnapshots[i].ts+(objectSnapshots[i].ts-
+objectSnapshots[i-1].ts);else
+right=this.objectInstance_.parent.model.bounds.max;}
+var rightView=vp.xWorldToView(right);if(rightView>width)
+rightView=width;leftView=Math.floor(leftView);rightView=Math.floor(rightView);this.drawStatBarsRecursive_(snapshot,leftView,rightView,height,trace,maxStats,currentY);if(i==lowIndex)
+this.drawStatNames_(leftView,height,currentY,'',maxStats);}
+ctx.lineWidth=1;},drawStatBarsRecursive_:function(snapshot,leftView,rightView,height,stats,maxStats,currentY){var ctx=this.context();for(var statName in maxStats){if(stats[statName]instanceof Object){currentY=this.drawStatBarsRecursive_(snapshot,leftView,rightView,height,stats[statName],maxStats[statName],currentY);}else{var maxStat=maxStats[statName];ctx.fillStyle=EventPresenter.getBarSnapshotColor(snapshot,Math.round(currentY/height));var barHeight;if(maxStat>0){barHeight=height*Math.m [...]
+ctx.fillRect(leftView,currentY-barHeight,Math.max(rightView-leftView,1),barHeight);currentY+=height;}}
+return currentY;},drawStatNames_:function(leftView,height,currentY,prefix,maxStats){var ctx=this.context();ctx.textAlign='end';ctx.font='12px Arial';ctx.fillStyle='#000000';for(var statName in maxStats){if(maxStats[statName]instanceof Object){currentY=this.drawStatNames_(leftView,height,currentY,statName,maxStats[statName]);}else{var fullname=statName;if(prefix!='')
+fullname=prefix+' :: '+statName;ctx.fillText(fullname,leftView-10,currentY-height/4);currentY+=height;}}
+return currentY;}};tr.ui.tracks.ObjectInstanceTrack.register(SystemStatsInstanceTrack,{typeName:'base::TraceEventSystemStatsMonitor::SystemStats'});return{SystemStatsInstanceTrack:SystemStatsInstanceTrack};});'use strict';tr.exportTo('tr.c',function(){function ScriptingObject(){}
+ScriptingObject.prototype={onModelChanged:function(model){}};return{ScriptingObject:ScriptingObject};});'use strict';tr.exportTo('tr.c',function(){function ScriptingController(brushingStateController){this.brushingStateController_=brushingStateController;this.scriptObjectNames_=[];this.scriptObjectValues_=[];this.brushingStateController.addEventListener('model-changed',this.onModelChanged_.bind(this));var typeInfos=ScriptingObjectRegistry.getAllRegisteredTypeInfos();typeInfos.forEach(fun [...]
+function ScriptingObjectRegistry(){}
+var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);tr.b.decorateExtensionRegistry(ScriptingObjectRegistry,options);ScriptingController.prototype={get brushingStateController(){return this.brushingStateController_;},onModelChanged_:function(){this.scriptObjectValues_.forEach(function(v){if(v.onModelChanged)
+v.onModelChanged(this.brushingStateController.model);},this);},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.metrics',function(){function MetricRe [...]
+var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);options.defaultMetadata={};options.mandatoryBaseClass=Function;tr.b.decorateExtensionRegistry(MetricRegistry,options);return{MetricRegistry:MetricRegistry};});'use strict';tr.exportTo('tr.v',function(){function Value(canonicalUrl,name,opt_options,opt_groupingKeys,opt_diagnostics){if(typeof(name)!=='string')
+throw new Error('Expected value_name grouping key to be provided');this.groupingKeys={name:name};if(opt_groupingKeys){for(var keyName in opt_groupingKeys){this.addGroupingKey(keyName,opt_groupingKeys[keyName]);}}
+this.diagnostics=opt_diagnostics||{};this.diagnostics.canonical_url=canonicalUrl;var options=opt_options||{};this.description=options.description;this.important=options.important!==undefined?options.important:false;}
+Value.fromDict=function(d){if(d.type==='numeric')
+return NumericValue.fromDict(d);if(d.type==='dict')
+return DictValue.fromDict(d);if(d.type=='failure')
+return FailureValue.fromDict(d);if(d.type==='skip')
+return SkipValue.fromDict(d);throw new Error('Not implemented');};Value.prototype={get name(){return this.groupingKeys.name;},get canonicalUrl(){return this.diagnostics.canonical_url;},addGroupingKey:function(keyName,key){if(keyName==='name')
+throw new Error('Invalid groupingKey name "name"');if(this.groupingKeys.hasOwnProperty(keyName))
+throw new Error('Tried to redefine grouping key '+keyName);this.groupingKeys[keyName]=key;},asDict:function(){return this.asJSON();},asJSON:function(){var d={grouping_keys:tr.b.cloneDictionary(this.groupingKeys),description:this.description,important:this.important,diagnostics:this.diagnostics};this._asDictInto(d);if(d.type===undefined)
+throw new Error('_asDictInto must set type field');return d;},_asDictInto:function(d){throw new Error('Not implemented');}};function NumericValue(canonicalUrl,name,numeric,opt_options,opt_groupingKeys,opt_diagnostics){if(!(numeric instanceof tr.v.NumericBase))
+throw new Error('Expected numeric to be instance of tr.v.NumericBase');Value.call(this,canonicalUrl,name,opt_options,opt_groupingKeys,opt_diagnostics);this.numeric=numeric;}
+NumericValue.fromDict=function(d){if(d.numeric===undefined)
+throw new Error('Expected numeric to be provided');var numeric=tr.v.NumericBase.fromDict(d.numeric);var name=d.grouping_keys.name;d.grouping_keys=tr.b.cloneDictionary(d.groupingKeys);delete d.grouping_keys.name;return new NumericValue(d.diagnostics.canonical_url,name,numeric,d,d.grouping_keys,d.diagnostics);};NumericValue.prototype={__proto__:Value.prototype,_asDictInto:function(d){d.type='numeric';d.numeric=this.numeric.asDict();}};function DictValue(canonicalUrl,name,value,opt_options, [...]
+DictValue.fromDict=function(d){if(d.units!==undefined)
+throw new Error('Expected units to be undefined');if(d.value===undefined)
+throw new Error('Expected value to be provided');var name=d.grouping_keys.name;d.grouping_keys=tr.b.cloneDictionary(d.groupingKeys);delete d.grouping_keys.name;return new DictValue(d.diagnostics.canonical_url,name,d.value,d,d.groupingKeys,d.diagnostics);};DictValue.prototype={__proto__:Value.prototype,_asDictInto:function(d){d.type='dict';d.value=this.value;}};function FailureValue(canonicalUrl,name,opt_options,opt_groupingKeys,opt_diagnostics){var options=opt_options||{};var stack;if(op [...]
+if(typeof stack!=='string')
+throw new Error('stack must be provided as a string');if(canonicalUrl===undefined){throw new Error('FailureValue must provide canonicalUrl');}
+Value.call(this,canonicalUrl,name,options,opt_groupingKeys,opt_diagnostics);this.stack=stack;}
+FailureValue.fromError=function(canonicalUrl,e){var ex=tr.b.normalizeException(e);return new FailureValue(canonicalUrl,ex.typeName,{description:ex.message,stack:ex.stack});};FailureValue.fromDict=function(d){if(d.units!==undefined)
+throw new Error('Expected units to be undefined');if(d.stack_str===undefined)
+throw new Error('Expected stack_str to be provided');var name=d.grouping_keys.name;d.grouping_keys=tr.b.cloneDictionary(d.groupingKeys);delete d.grouping_keys.name;return new FailureValue(d.diagnostics.canonical_url,name,d,d.grouping_keys,d.diagnostics);};FailureValue.prototype={__proto__:Value.prototype,_asDictInto:function(d){d.type='failure';d.stack_str=this.stack;}};function SkipValue(canonicalUrl,name,opt_options,opt_groupingKeys,opt_diagnostics){Value.call(this,canonicalUrl,name,op [...]
+SkipValue.fromDict=function(d){if(d.units!==undefined)
+throw new Error('Expected units to be undefined');var name=d.grouping_keys.name;d.grouping_keys=tr.b.cloneDictionary(d.groupingKeys);delete d.grouping_keys.name;return new SkipValue(d.diagnostics.canonical_url,name,d,d.grouping_keys,d.diagnostics);};SkipValue.prototype={__proto__:Value.prototype,_asDictInto:function(d){d.type='skip';}};return{Value:Value,NumericValue:NumericValue,DictValue:DictValue,FailureValue:FailureValue,SkipValue:SkipValue};});'use strict';tr.exportTo('tr.metrics',f [...]
+sampleMetric.prototype={__proto__:Function.prototype};tr.metrics.MetricRegistry.register(sampleMetric);return{sampleMetric:sampleMetric};});'use strict';tr.exportTo('tr.metrics.sh',function(){function perceptualBlend(ir,index,score){return Math.exp(1-score);}
+function filterExpectationsByRange(irs,opt_range){var filteredExpectations=[];irs.forEach(function(ir){if(!(ir instanceof tr.model.um.UserExpectation))
+return;if(!opt_range||opt_range.intersectsExplicitRangeExclusive(ir.start,ir.end))
+filteredExpectations.push(ir);});return filteredExpectations;}
+return{perceptualBlend:perceptualBlend,filterExpectationsByRange:filterExpectationsByRange};});'use strict';tr.exportTo('tr.metrics.sh',function(){var UNIT=tr.v.Unit.byName.normalizedPercentage_biggerIsBetter;var DESCRIPTION='Normalized CPU budget consumption';function EfficiencyMetric(valueList,model){var scores=[];model.userModel.expectations.forEach(function(ue){var options={};options.description=DESCRIPTION;var groupingKeys={};groupingKeys.userExpectationStableId=ue.stableId;grouping [...]
+return;var cpuFractionBudget=tr.b.Range.fromExplicitRange(0.5,1.5);if(ue instanceof tr.model.um.IdleExpectation){cpuFractionBudget=tr.b.Range.fromExplicitRange(0.1,1);}else if(ue instanceof tr.model.um.AnimationExpectation){cpuFractionBudget=tr.b.Range.fromExplicitRange(1,2);}
+var cpuMsBudget=tr.b.Range.fromExplicitRange(ue.duration*cpuFractionBudget.min,ue.duration*cpuFractionBudget.max);var normalizedCpu=tr.b.normalize(ue.totalCpuMs,cpuMsBudget.min,cpuMsBudget.max);score=1-tr.b.clamp(normalizedCpu,0,1);scores.push(score);valueList.addValue(new tr.v.NumericValue(model.canonicalUrl,'efficiency',new tr.v.ScalarNumeric(UNIT,score),options,groupingKeys));});var options={};options.description=DESCRIPTION;var groupingKeys={};var overallScore=tr.b.Statistics.weighte [...]
+return;valueList.addValue(new tr.v.NumericValue(model.canonicalUrl,'efficiency',new tr.v.ScalarNumeric(UNIT,overallScore),options,groupingKeys));}
+EfficiencyMetric.prototype={__proto__:Function.prototype};tr.metrics.MetricRegistry.register(EfficiencyMetric);return{EfficiencyMetric:EfficiencyMetric};});'use strict';tr.exportTo('tr.metrics.sh',function(){var timeDurationInMs_smallerIsBetter=tr.v.Unit.byName.timeDurationInMs_smallerIsBetter;function findTargetRendererHelper(model){var chromeHelper=model.getOrCreateHelper(tr.model.helpers.ChromeModelHelper);var largestPid=-1;for(var pid in chromeHelper.rendererHelpers){var rendererHelp [...]
+continue;if(pid>largestPid)
+largestPid=pid;}
+if(largestPid===-1)
+return undefined;return chromeHelper.rendererHelpers[largestPid];}
+function findNavigationStartEvent(rendererHelper){var navigationStartEvent=undefined;rendererHelper.mainThread.sliceGroup.iterateAllEventsInThisContainer(()=>true,function(ev){if(navigationStartEvent!==undefined||ev.category!=='blink.user_timing')
+return;if(ev.title==='navigationStart')
+navigationStartEvent=ev;},this);return navigationStartEvent;}
+function findFirstPaintEvent(rendererHelper,title,frame){var firstPaintEvent=undefined;rendererHelper.process.iterateAllEvents(function(ev){if(firstPaintEvent!==undefined||ev.category!=='blink.user_timing'||ev.title!==title||ev.args===undefined||ev.args['frame']!==frame)
+return;firstPaintEvent=ev;},this);return firstPaintEvent;}
+function firstPaintMetric(valueList,model){var rendererHelper=findTargetRendererHelper(model);var navigationStartEvent=findNavigationStartEvent(rendererHelper);if(navigationStartEvent===undefined)
+throw new Error('Failed to find navigationStartEvent.');var frame=navigationStartEvent.args['frame'];var firstContentfulPaintEvent=findFirstPaintEvent(rendererHelper,'firstContentfulPaint',frame);if(firstContentfulPaintEvent===undefined)
+throw new Error('Failed to find firstContentfulPaintEvent for frame '+frame);var grouping_keys={};var timeToFirstContentfulPaint=firstContentfulPaintEvent.start-navigationStartEvent.start;valueList.addValue(new tr.v.NumericValue(model.canonicalUrlThatCreatedThisTrace,'firstContentfulPaint',new tr.v.ScalarNumeric(timeDurationInMs_smallerIsBetter,timeToFirstContentfulPaint),{description:'time to first contentful paint'},grouping_keys));}
+firstPaintMetric.prototype={__proto__:Function.prototype};tr.metrics.MetricRegistry.register(firstPaintMetric);return{firstPaintMetric:firstPaintMetric};});'use strict';tr.exportTo('tr.metrics.sh',function(){var RESPONSE_HISTOGRAM=tr.v.Numeric.fromDict({unit:'unitless',min:150,max:5000,centralBinWidth:485,underflowBin:{min:-Number.MAX_VALUE,max:150,count:1000},centralBins:[{min:150,max:635,count:708},{min:635,max:1120,count:223},{min:1120,max:1605,count:50},{min:1605,max:2090,count:33},{ [...]
+function groupingKeysForUserExpectation(ue){var groupingKeys={};groupingKeys.userExpectationStableId=ue.stableId;groupingKeys.userExpectationStageTitle=ue.stageTitle;groupingKeys.userExpectationInitiatorTitle=ue.initiatorTitle;return groupingKeys;}
+var MAX_FPS=60;var MIN_FPS=10;function computeAnimationThroughput(animationExpectation){if(animationExpectation.frameEvents===undefined||animationExpectation.frameEvents.length===0)
+throw new Error('Animation missing frameEvents '+
+animationExpectation.stableId);var durationSeconds=animationExpectation.duration/1000;var avgSpf=durationSeconds/animationExpectation.frameEvents.length;var throughput=1-tr.b.normalize(avgSpf,1/MAX_FPS,1/MIN_FPS);return tr.b.clamp(throughput,0,1);}
+var MIN_DISCREPANCY=0.05;var MAX_DISCREPANCY=0.3;function computeAnimationSmoothness(animationExpectation){if(animationExpectation.frameEvents===undefined||animationExpectation.frameEvents.length===0)
+throw new Error('Animation missing frameEvents '+
+animationExpectation.stableId);var frameTimestamps=animationExpectation.frameEvents;frameTimestamps=frameTimestamps.toArray().map(function(event){return event.start;});var absolute=false;var discrepancy=tr.b.Statistics.timestampsDiscrepancy(frameTimestamps,absolute);var smoothness=1-tr.b.normalize(discrepancy,MIN_DISCREPANCY,MAX_DISCREPANCY);return tr.b.clamp(smoothness,0,1);}
+function computeAnimationResponsiveness(animationExpectation,diagnosticValues){var throughput=computeAnimationThroughput(animationExpectation);if(throughput===undefined)
+throw new Error('Missing throughput for '+
+animationExpectation.stableId);var options={};options.description='Mean Opinion Score for Animation throughput';diagnosticValues.addValue(new tr.v.NumericValue(animationExpectation.parentModel.canonicalUrl,'throughput',new tr.v.ScalarNumeric(UNIT,throughput),options,groupingKeysForUserExpectation(animationExpectation)));var smoothness=computeAnimationSmoothness(animationExpectation);if(smoothness===undefined)
+throw new Error('Missing smoothness for '+
+animationExpectation.stableId);options={};options.description='Mean Opinion Score for Animation smoothness';diagnosticValues.addValue(new tr.v.NumericValue(animationExpectation.parentModel.canonicalUrl,'smoothness',new tr.v.ScalarNumeric(UNIT,smoothness),options,groupingKeysForUserExpectation(animationExpectation)));return tr.b.Statistics.weightedMean([throughput,smoothness],tr.metrics.sh.perceptualBlend);}
+function computeResponsiveness(ue,diagnosticValues){var score=undefined;var options={};if(ue instanceof tr.model.um.IdleExpectation){throw new Error('Responsiveness is not defined for Idle');}else if(ue instanceof tr.model.um.LoadExpectation){score=computeDurationResponsiveness(LOAD_HISTOGRAM,ue.duration);options.description='Mean Opinion Score of Time to First ContentfulPaint';}else if(ue instanceof tr.model.um.ResponseExpectation){var histogram=RESPONSE_HISTOGRAM;if(ue.isAnimationBegin)
+histogram=FAST_RESPONSE_HISTOGRAM;score=computeDurationResponsiveness(histogram,ue.duration);options.description='Mean Opinion Score of input latency';}else if(ue instanceof tr.model.um.AnimationExpectation){score=computeAnimationResponsiveness(ue,diagnosticValues);options.description='Mean Opinion Score of perceptual blend of throughput and smoothness';}else{throw new Error('Unrecognized stage for '+ue.stableId);}
+if(score===undefined)
+throw new Error('Unable to compute responsiveness for '+ue.stableId);diagnosticValues.addValue(new tr.v.NumericValue(ue.parentModel.canonicalUrl,'responsiveness',new tr.v.ScalarNumeric(UNIT,score),options,groupingKeysForUserExpectation(ue)));return score;}
+function responsivenessMetric(valueList,model){var scores=[];var diagnosticValues=new tr.metrics.ValueList();model.userModel.expectations.forEach(function(ue){if(ue instanceof tr.model.um.IdleExpectation)
+return;scores.push(computeResponsiveness(ue,diagnosticValues));});var options={};options.description='Perceptual blend of responsiveness of RAIL user expectations';var groupingKeys={};var overallScore=tr.b.Statistics.weightedMean(scores,tr.metrics.sh.perceptualBlend);if(overallScore===undefined)
+return;var diagnostics={values:diagnosticValues.valueDicts};valueList.addValue(new tr.v.NumericValue(model.canonicalUrl,'responsiveness',new tr.v.ScalarNumeric(UNIT,overallScore),options,groupingKeys,diagnostics));}
+responsivenessMetric.prototype={__proto__:Function.prototype};tr.metrics.MetricRegistry.register(responsivenessMetric);return{responsivenessMetric:responsivenessMetric,computeDurationResponsiveness:computeDurationResponsiveness,FAST_RESPONSE_HISTOGRAM:FAST_RESPONSE_HISTOGRAM};});'use strict';tr.exportTo('tr.metrics.sh',function(){var LONG_TASK_MS=50;var normalizedPercentage_smallerIsBetter=tr.v.Unit.byName.normalizedPercentage_smallerIsBetter;var timeDurationInMs_smallerIsBetter=tr.v.Uni [...]
+longTasks.push(event);});return longTasks;}
+function computeResponsivenessRisk(durationMs){durationMs+=16;return 1-tr.metrics.sh.computeDurationResponsiveness(tr.metrics.sh.FAST_RESPONSE_HISTOGRAM,durationMs);}
+function perceptualBlendSmallerIsBetter(hazardScore){return Math.exp(hazardScore);}
+function computeLongIdleTaskHazard(hazardScores,valueList,ue){var longTaskScores=[];var durationValues=new tr.metrics.ValueList();findLongTasks(ue).forEach(function(longTask){longTaskScores.push(computeResponsivenessRisk(longTask.duration));durationValues.addValue(new tr.v.NumericValue(ue.parentModel.canonicalUrlThatCreatedThisTrace,'long idle task duration',new tr.v.ScalarNumeric(timeDurationInMs_smallerIsBetter,longTask.duration),{description:'Duration of a long idle task'}));});var op [...]
+hazardScore=0;hazardScores.push(hazardScore);valueList.addValue(new tr.v.NumericValue(ue.parentModel.canonicalUrlThatCreatedThisTrace,'long idle tasks hazard',new tr.v.ScalarNumeric(normalizedPercentage_smallerIsBetter,hazardScore),options,groupingKeys,diagnostics));}
+function hazardMetric(valueList,model){var hazardScores=[];var hazardValues=new tr.metrics.ValueList();model.userModel.expectations.forEach(function(ue){if(ue instanceof tr.model.um.IdleExpectation)
+computeLongIdleTaskHazard(hazardScores,hazardValues,ue);});var options={description:'Risk of impacting responsiveness'};var groupingKeys={};var diagnostics={values:hazardValues.valueDicts};var overallHazard=tr.b.Statistics.weightedMean(hazardScores,perceptualBlendSmallerIsBetter);if(overallHazard===undefined)
+overallHazard=0;valueList.addValue(new tr.v.NumericValue(model.canonicalUrlThatCreatedThisTrace,'hazard',new tr.v.ScalarNumeric(normalizedPercentage_smallerIsBetter,overallHazard),options,groupingKeys,diagnostics));}
+hazardMetric.prototype={__proto__:Function.prototype};tr.metrics.MetricRegistry.register(hazardMetric);return{hazardMetric:hazardMetric,computeLongIdleTaskHazard:computeLongIdleTaskHazard};});'use strict';tr.exportTo('tr.metrics.sh',function(){var DISPLAYED_SIZE_NUMERIC_NAME=tr.model.MemoryAllocatorDump.DISPLAYED_SIZE_NUMERIC_NAME;var LIGHT=tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT;var DETAILED=tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED;var ScalarNumeric=tr.v.ScalarNumeri [...]
+memoryMetric.prototype={__proto__:Function.prototype};function addGeneralMemoryDumpValues(valueList,model){addPerProcessNameMemoryDumpValues(model.globalMemoryDumps,function(processDump,addProcessScalar){addProcessScalar('process_count',new ScalarNumeric(unitlessNumber_smallerIsBetter,1));if(processDump.memoryAllocatorDumps===undefined)
+return;processDump.memoryAllocatorDumps.forEach(function(rootAllocatorDump){addProcessScalar('allocator_'+rootAllocatorDump.name,rootAllocatorDump.numerics[DISPLAYED_SIZE_NUMERIC_NAME]);addProcessScalar('allocated_objects_'+rootAllocatorDump.name,rootAllocatorDump.numerics['allocated_objects_size']);});var memtrackDump=processDump.getMemoryAllocatorDumpByFullName('gpu/android_memtrack');if(memtrackDump!==undefined){memtrackDump.children.forEach(function(memtrackChildDump){addProcessScala [...]
+function addDetailedMemoryDumpValues(valueList,model){var heavyGlobalMemoryDumps=model.globalMemoryDumps.filter(g=>g.levelOfDetail===DETAILED);addPerProcessNameMemoryDumpValues(heavyGlobalMemoryDumps,function(processDump,addProcessScalar){tr.b.iterItems(MMAPS_METRICS,function(metricName,metricSpec){var node=getDescendantVmRegionClassificationNode(processDump.vmRegions,metricSpec.path);var value=node?(node.byteStats[metricSpec.byteStat]||0):0;addProcessScalar('mmaps_'+metricName,new Scala [...]
+function getDescendantVmRegionClassificationNode(node,path){for(var i=0;i<path.length;i++){if(node===undefined)
+break;node=tr.b.findFirstInArray(node.children,c=>c.title===path[i]);}
+return node;}
+function addMemoryDumpCountValues(valueList,model){var levelOfDetailNameToDumpCount={'total':0};LEVEL_OF_DETAIL_NAMES.forEach(function(levelOfDetailName){levelOfDetailNameToDumpCount[levelOfDetailName]=0;});model.globalMemoryDumps.forEach(function(globalDump){levelOfDetailNameToDumpCount.total++;var levelOfDetailName=LEVEL_OF_DETAIL_NAMES.get(globalDump.levelOfDetail);if(!(levelOfDetailName in levelOfDetailNameToDumpCount))
+return;levelOfDetailNameToDumpCount[levelOfDetailName]++;});tr.b.iterItems(levelOfDetailNameToDumpCount,function(levelOfDetailName,levelOfDetailDumpCount){valueList.addValue(new tr.v.NumericValue(model.canonicalUrl,'memory_dump_count_'+levelOfDetailName,new ScalarNumeric(unitlessNumber_smallerIsBetter,levelOfDetailDumpCount)));});}
+function addPerProcessNameMemoryDumpValues(globalDumps,customProcessDumpValueExtractor,valueList,model){var timeToProcessNameToValueNameToScalar=calculatePerProcessNameMemoryDumpValues(globalDumps,customProcessDumpValueExtractor);injectTotalsIntoPerProcessNameMemoryDumpValues(timeToProcessNameToValueNameToScalar);reportPerProcessNameMemoryDumpValues(timeToProcessNameToValueNameToScalar,valueList,model);}
+function calculatePerProcessNameMemoryDumpValues(globalDumps,customProcessDumpValueExtractor){return globalDumps.map(function(globalDump){var processNameToValueNameToScalar={};tr.b.iterItems(globalDump.processMemoryDumps,function(_,processDump){var rawProcessName=processDump.process.name||'unknown';var processName=rawProcessName.toLowerCase().replace(' ','_');var valueNameToScalar=processNameToValueNameToScalar[processName];if(valueNameToScalar===undefined)
+processNameToValueNameToScalar[processName]=valueNameToScalar={};customProcessDumpValueExtractor(processDump,function addProcessScalar(name,processDumpScalar){if(processDumpScalar===undefined)
+return;var processNameSumScalar=valueNameToScalar[name];if(processNameSumScalar===undefined){valueNameToScalar[name]=processNameSumScalar=new ScalarNumeric(processDumpScalar.unit,processDumpScalar.value);}else{if(processDumpScalar.unit!==processNameSumScalar.unit){throw new Error('Multiple units provided for value \''+
+name+'\' of \''+processName+'\' processes: '+
+processNameSumScalar.unit.unitName+' and '+
+processDumpScalar.unit.unitName);}
+processNameSumScalar.value+=processDumpScalar.value;}});});return processNameToValueNameToScalar;});}
+function injectTotalsIntoPerProcessNameMemoryDumpValues(timeToProcessNameToValueNameToScalar){timeToProcessNameToValueNameToScalar.forEach(function(processNameToValueNameToScalar){var valueNameToProcessNameToScalar=tr.b.invertArrayOfDicts(tr.b.dictionaryValues(processNameToValueNameToScalar));processNameToValueNameToScalar.total=tr.b.mapItems(valueNameToProcessNameToScalar,function(valueName,perProcessScalars){var unit=tr.b.findFirstInArray(perProcessScalars).unit;var value=perProcessSca [...]
+return accumulator;if(scalar.unit!==unit){throw new Error('Multiple units provided for value \''+
+valueName+'\' of different processes: '+
+unit.unitName+' and '+scalar.unit.unitName);}
+return accumulator+scalar.value;},0);return new ScalarNumeric(unit,value);});});}
+function reportPerProcessNameMemoryDumpValues(timeToProcessNameToValueNameToScalar,valueList,model){var processNameToTimeToValueNameToScalar=tr.b.invertArrayOfDicts(timeToProcessNameToValueNameToScalar);tr.b.iterItems(processNameToTimeToValueNameToScalar,function(processName,timeToValueNameToScalar){var valueNameToTimeToScalar=tr.b.invertArrayOfDicts(timeToValueNameToScalar);tr.b.iterItems(valueNameToTimeToScalar,function(valueName,timeToScalar){valueList.addValue(new tr.v.NumericValue(m [...]
+function mergeScalarsIntoNumeric(scalars){var unit=tr.b.findFirstInArray(scalars).unit;var numeric=MEMORY_NUMERIC_BUILDER_MAP.get(unit).build();for(var i=0;i<scalars.length;i++){var scalar=scalars[i];numeric.add(scalar===undefined?0:scalar.value);}
+return numeric;}
+tr.metrics.MetricRegistry.register(memoryMetric);return{memoryMetric:memoryMetric};});'use strict';tr.exportTo('tr.metrics.sh',function(){function SystemHealthMetrics(valueList,model){tr.metrics.sh.responsivenessMetric(valueList,model);tr.metrics.sh.EfficiencyMetric(valueList,model);tr.metrics.sh.hazardMetric(valueList,model);}
+SystemHealthMetrics.prototype={__proto__:Function.prototype};tr.metrics.MetricRegistry.register(SystemHealthMetrics);return{SystemHealthMetrics:SystemHealthMetrics};});'use strict';tr.exportTo('tr.metrics',function(){function tracingMetric(valueList,model){if(!model.stats.hasEventSizesinBytes){throw new Error('Model stats does not have event size information. '+'Please enable ImportOptions.trackDetailedModelStats.');}
+var eventStats=model.stats.allTraceEventStatsInTimeIntervals;eventStats.sort(function(a,b){return a.timeInterval-b.timeInterval;});var maxEventCountPerSec=0;var maxEventBytesPerSec=0;var totalTraceBytes=0;var WINDOW_SIZE=Math.floor(1000/model.stats.TIME_INTERVAL_SIZE_IN_MS);var runningEventNumPerSec=0;var runningEventBytesPerSec=0;var start=0;var end=0;while(end<eventStats.length){var startEventStats=eventStats[start];var endEventStats=eventStats[end];var timeWindow=endEventStats.timeInt [...]
+runningEventNumPerSec+=endEventStats.numEvents;if(maxEventCountPerSec<runningEventNumPerSec)
+maxEventCountPerSec=runningEventNumPerSec;runningEventBytesPerSec+=endEventStats.totalEventSizeinBytes;if(maxEventBytesPerSec<runningEventBytesPerSec)
+maxEventBytesPerSec=runningEventBytesPerSec;totalTraceBytes+=endEventStats.totalEventSizeinBytes;end++;}
+var stats=model.stats.allTraceEventStats;var categoryStatsMap=new Map();var categoryStats=[];for(var i=0;i<stats.length;i++){var categoryStat=categoryStatsMap.get(stats[i].category);if(categoryStat===undefined){categoryStat={category:stats[i].category,totalEventSizeinBytes:0};categoryStatsMap.set(stats[i].category,categoryStat);categoryStats.push(categoryStat);}
+categoryStat.totalEventSizeinBytes+=stats[i].totalEventSizeinBytes;}
+var maxCategoryStats=categoryStats.reduce(function(a,b){return a.totalEventSizeinBytes<b.totalEventSizeinBytes?b:a;});var maxEventBytesPerCategory=maxCategoryStats.totalEventSizeinBytes;var maxCategoryName=maxCategoryStats.category;var maxEventCountPerSecValue=new tr.v.ScalarNumeric(tr.v.Unit.byName.unitlessNumber_smallerIsBetter,maxEventCountPerSec);var maxEventBytesPerSecValue=new tr.v.ScalarNumeric(tr.v.Unit.byName.sizeInBytes_smallerIsBetter,maxEventBytesPerSec);var totalTraceBytesVa [...]
+tracingMetric.prototype={__proto__:Function.prototype};tr.metrics.MetricRegistry.register(tracingMetric);return{tracingMetric:tracingMetric};});'use strict';tr.exportTo('tr.metrics.v8',function(){var DURATION_NUMERIC_BUILDER=tr.v.NumericBuilder.createLinear(tr.v.Unit.byName.timeDurationInMs_smallerIsBetter,tr.b.Range.fromExplicitRange(4,200),100);function computeExecuteMetrics(valueList,model){var cpuTotalExecution=DURATION_NUMERIC_BUILDER.build();var wallTotalExecution=DURATION_NUMERIC_ [...]
+function computeParseLazyMetrics(valueList,model){var cpuSelfParseLazy=DURATION_NUMERIC_BUILDER.build();var wallSelfParseLazy=DURATION_NUMERIC_BUILDER.build();model.findTopmostSlicesNamed('V8.ParseLazyMicroSeconds',function(e){cpuSelfParseLazy.add(e.cpuSelfTime);wallSelfParseLazy.add(e.selfTime);});model.findTopmostSlicesNamed('V8.ParseLazy',function(e){cpuSelfParseLazy.add(e.cpuSelfTime);wallSelfParseLazy.add(e.selfTime);});valueList.addValue(new tr.v.NumericValue(model.canonicalUrl,'v8 [...]
+function computeCompileFullCodeMetrics(valueList,model){var cpuSelfCompileFullCode=DURATION_NUMERIC_BUILDER.build();var wallSelfCompileFullCode=DURATION_NUMERIC_BUILDER.build();model.findTopmostSlicesNamed('V8.CompileFullCode',function(e){cpuSelfCompileFullCode.add(e.cpuSelfTime);wallSelfCompileFullCode.add(e.selfTime);});valueList.addValue(new tr.v.NumericValue(model.canonicalUrl,'v8_compile_full_code_cpu_self',cpuSelfCompileFullCode,{description:'cpu self time spent performing compilin [...]
+function computeCompileIgnitionMetrics(valueList,model){var cpuSelfCompileIgnition=DURATION_NUMERIC_BUILDER.build();var wallSelfCompileIgnition=DURATION_NUMERIC_BUILDER.build();model.findTopmostSlicesNamed('V8.CompileIgnition',function(e){cpuSelfCompileIgnition.add(e.cpuSelfTime);wallSelfCompileIgnition.add(e.selfTime);});valueList.addValue(new tr.v.NumericValue(model.canonicalUrl,'v8_compile_ignition_cpu_self',cpuSelfCompileIgnition,{description:'cpu self time spent in compile ignition' [...]
+function computeRecompileMetrics(valueList,model){var cpuTotalRecompileSynchronous=DURATION_NUMERIC_BUILDER.build();var wallTotalRecompileSynchronous=DURATION_NUMERIC_BUILDER.build();var cpuTotalRecompileConcurrent=DURATION_NUMERIC_BUILDER.build();var wallTotalRecompileConcurrent=DURATION_NUMERIC_BUILDER.build();var cpuTotalRecompileOverall=DURATION_NUMERIC_BUILDER.build();var wallTotalRecompileOverall=DURATION_NUMERIC_BUILDER.build();model.findTopmostSlicesNamed('V8.RecompileSynchronous [...]
+function computeOptimizeCodeMetrics(valueList,model){var cpuTotalOptimizeCode=DURATION_NUMERIC_BUILDER.build();var wallTotalOptimizeCode=DURATION_NUMERIC_BUILDER.build();model.findTopmostSlicesNamed('V8.OptimizeCode',function(e){cpuTotalOptimizeCode.add(e.cpuDuration);wallTotalOptimizeCode.add(e.duration);});valueList.addValue(new tr.v.NumericValue(model.canonicalUrl,'v8_optimize_code_cpu_total',cpuTotalOptimizeCode,{description:'cpu total time spent in code optimization'}));valueList.ad [...]
+function computeDeoptimizeCodeMetrics(valueList,model){var cpuTotalDeoptimizeCode=DURATION_NUMERIC_BUILDER.build();var wallTotalDeoptimizeCode=DURATION_NUMERIC_BUILDER.build();model.findTopmostSlicesNamed('V8.DeoptimizeCode',function(e){cpuTotalDeoptimizeCode.add(e.cpuDuration);wallTotalDeoptimizeCode.add(e.duration);});valueList.addValue(new tr.v.NumericValue(model.canonicalUrl,'v8_deoptimize_code_cpu_total',cpuTotalDeoptimizeCode,{description:'cpu total time spent in code deoptimizatio [...]
+function executionMetric(valueList,model){computeExecuteMetrics(valueList,model);computeParseLazyMetrics(valueList,model);computeCompileIgnitionMetrics(valueList,model);computeCompileFullCodeMetrics(valueList,model);computeRecompileMetrics(valueList,model);computeOptimizeCodeMetrics(valueList,model);computeDeoptimizeCodeMetrics(valueList,model);}
+executionMetric.prototype={__proto__:Function.prototype};tr.metrics.MetricRegistry.register(executionMetric);return{executionMetric:executionMetric};});'use strict';tr.exportTo('tr.metrics.v8',function(){function V8Metrics(valueList,model){tr.metrics.v8.V8ExecutionMetric(valueList,model);}
+V8Metrics.prototype={__proto__:Function.prototype};tr.metrics.MetricRegistry.register(V8Metrics);return{V8Metrics:V8Metrics};});'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 selection(){return this.currentSelection_;},set selection(selection [...]
+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();},get relatedEventsToHighlight(){if(!this.currentSelection_)
+return undefined;return this.currentSelection_[0].associatedEvents;}});'use strict';tr.exportTo('tr.b',function(){function MultiDimensionalViewNode(title,isLowerBound){this.title=title;var dimensions=title.length;this.children=new Array(dimensions);for(var i=0;i<dimensions;i++)
+this.children[i]=new Map();this.total=0;this.self=0;this.isLowerBound=!!isLowerBound;}
+MultiDimensionalViewNode.prototype={get subRows(){return tr.b.mapValues(this.children[0]);}};var MultiDimensionalViewType={TOP_DOWN_TREE_VIEW:0,TOP_DOWN_HEAVY_VIEW:1,BOTTOM_UP_HEAVY_VIEW:2};function MultiDimensionalViewBuilder(dimensions){if(dimensions<0)
+throw new Error('Dimensions must be non-negative');this.dimensions_=dimensions;this.buildRoot_=this.createRootNode_();this.topDownTreeViewRoot_=undefined;this.topDownHeavyViewRoot_=undefined;this.bottomUpHeavyViewNode_=undefined;this.maxDimensionDepths_=new Array(dimensions);for(var d=0;d<dimensions;d++)
+this.maxDimensionDepths_[d]=0;}
+MultiDimensionalViewBuilder.ValueKind={SELF:0,TOTAL:1};MultiDimensionalViewBuilder.prototype={addPath:function(path,value,valueKind){if(this.buildRoot_===undefined){throw new Error('Paths cannot be added after either view has been built');}
+if(path.length!==this.dimensions_)
+throw new Error('Path must be '+this.dimensions_+'-dimensional');var node=this.buildRoot_;for(var d=0;d<path.length;d++){var singleDimensionPath=path[d];var singleDimensionPathLength=singleDimensionPath.length;this.maxDimensionDepths_[d]=Math.max(this.maxDimensionDepths_[d],singleDimensionPathLength);for(var i=0;i<singleDimensionPathLength;i++)
+node=this.getOrCreateChildNode_(node,d,singleDimensionPath[i]);}
+switch(valueKind){case MultiDimensionalViewBuilder.ValueKind.SELF:node.self+=value;break;case MultiDimensionalViewBuilder.ValueKind.TOTAL:node.total+=value;break;default:throw new Error('Invalid value kind: '+valueKind);}
+node.isLowerBound=false;},buildView:function(viewType){switch(viewType){case MultiDimensionalViewType.TOP_DOWN_TREE_VIEW:return this.buildTopDownTreeView();case MultiDimensionalViewType.TOP_DOWN_HEAVY_VIEW:return this.buildTopDownHeavyView();case MultiDimensionalViewType.BOTTOM_UP_HEAVY_VIEW:return this.buildBottomUpHeavyView();default:throw new Error('Unknown multi-dimensional view type: '+viewType);}},buildTopDownTreeView:function(){if(this.topDownTreeViewRoot_===undefined){var treeVie [...]
+return this.topDownTreeViewRoot_;},buildTopDownHeavyView:function(){if(this.topDownHeavyViewRoot_===undefined){this.topDownHeavyViewRoot_=this.buildGenericHeavyView_(this.addDimensionToTopDownHeavyViewNode_.bind(this));}
+return this.topDownHeavyViewRoot_;},buildBottomUpHeavyView:function(){if(this.bottomUpHeavyViewNode_===undefined){this.bottomUpHeavyViewNode_=this.buildGenericHeavyView_(this.addDimensionToBottomUpHeavyViewNode_.bind(this));}
+return this.bottomUpHeavyViewNode_;},createRootNode_:function(){return new MultiDimensionalViewNode(new Array(this.dimensions_),true);},getOrCreateChildNode_:function(parentNode,dimension,childDimensionTitle){if(dimension<0||dimension>=this.dimensions_)
+throw new Error('Invalid dimension');var dimensionChildren=parentNode.children[dimension];var childNode=dimensionChildren.get(childDimensionTitle);if(childNode!==undefined)
+return childNode;var childTitle=parentNode.title.slice();childTitle[dimension]=childDimensionTitle;childNode=new MultiDimensionalViewNode(childTitle,true);dimensionChildren.set(childDimensionTitle,childNode);return childNode;},setUpMissingChildRelationships_:function(node,firstDimensionToSetUp){for(var d=firstDimensionToSetUp;d<this.dimensions_;d++){var currentDimensionChildTitles=new Set(node.children[d].keys());for(var i=0;i<d;i++){for(var previousDimensionChildNode of node.children[i] [...]
+previousDimensionChildNode.children[d].keys()){currentDimensionChildTitles.add(previousDimensionGrandChildTitle);}}}
+for(var currentDimensionChildTitle of currentDimensionChildTitles){var currentDimensionChildNode=this.getOrCreateChildNode_(node,d,currentDimensionChildTitle);for(var i=0;i<d;i++){for(var previousDimensionChildNode of node.children[i].values()){var previousDimensionGrandChildNode=previousDimensionChildNode.children[d].get(currentDimensionChildTitle);if(previousDimensionGrandChildNode!==undefined){currentDimensionChildNode.children[i].set(previousDimensionChildNode.title[i],previousDimens [...]
+this.setUpMissingChildRelationships_(currentDimensionChildNode,d);}}},finalizeTotalValues_:function(node,firstDimensionToFinalize,dimensionalSelfSumsMap){var dimensionalSelfSums=new Array(this.dimensions_);var maxChildResidualSum=0;var nodeSelfSum=node.self;for(var d=0;d<this.dimensions_;d++){var childResidualSum=0;for(var childNode of node.children[d].values()){if(d>=firstDimensionToFinalize)
+this.finalizeTotalValues_(childNode,d,dimensionalSelfSumsMap);var childNodeSelfSums=dimensionalSelfSumsMap.get(childNode);nodeSelfSum+=childNodeSelfSums[d];var residual=childNode.total-childNodeSelfSums[this.dimensions_-1];childResidualSum+=residual;}
+dimensionalSelfSums[d]=nodeSelfSum;maxChildResidualSum=Math.max(maxChildResidualSum,childResidualSum);}
+node.total=Math.max(node.total,nodeSelfSum+maxChildResidualSum);if(dimensionalSelfSumsMap.has(node))
+throw new Error('Internal error: Node finalized more than once');dimensionalSelfSumsMap.set(node,dimensionalSelfSums);},buildGenericHeavyView_:function(treeViewNodeHandler){var treeViewRoot=this.buildTopDownTreeView();var heavyViewRoot=this.createRootNode_();heavyViewRoot.total=treeViewRoot.total;heavyViewRoot.self=treeViewRoot.self;heavyViewRoot.isLowerBound=treeViewRoot.isLowerBound;var recursionDepthTrackers=new Array(this.dimensions_);for(var d=0;d<this.dimensions_;d++){recursionDept [...]
+this.addDimensionsToGenericHeavyViewNode_(treeViewRoot,heavyViewRoot,0,recursionDepthTrackers,false,treeViewNodeHandler);this.setUpMissingChildRelationships_(heavyViewRoot,0);return heavyViewRoot;},addDimensionsToGenericHeavyViewNode_:function(treeViewParentNode,heavyViewParentNode,startDimension,recursionDepthTrackers,previousDimensionsRecursive,treeViewNodeHandler){for(var d=startDimension;d<this.dimensions_;d++){this.addDimensionDescendantsToGenericHeavyViewNode_(treeViewParentNode,he [...]
+heavyViewChildNode.total+=treeViewChildNode.total;this.addDimensionsToGenericHeavyViewNode_(treeViewChildNode,heavyViewChildNode,currentDimension+1,recursionDepthTrackers,currentOrPreviousDimensionsRecursive,this.addDimensionToTopDownHeavyViewNode_.bind(this));for(var treeViewGrandChildNode of
+treeViewChildNode.children[currentDimension].values()){recursionDepthTracker.push(treeViewGrandChildNode);this.addDimensionToTopDownHeavyViewNodeRecursively_(treeViewGrandChildNode,heavyViewChildNode,currentDimension,recursionDepthTrackers,previousDimensionsRecursive,subTreeDepth+1);recursionDepthTracker.pop();}},addDimensionToBottomUpHeavyViewNode_:function(treeViewChildNode,heavyViewParentNode,currentDimension,recursionDepthTrackers,previousDimensionsRecursive){var recursionDepthTracke [...]
+heavyViewDescendantNode.total+=treeViewChildNode.total;this.addDimensionsToGenericHeavyViewNode_(treeViewChildNode,heavyViewDescendantNode,currentDimension+1,recursionDepthTrackers,currentOrPreviousDimensionsRecursive,this.addDimensionToBottomUpHeavyViewNode_.bind(this));}}};function RecursionDepthTracker(maxDepth,dimension){this.titlePath=new Array(maxDepth);this.viewNodePath=new Array(maxDepth);this.bottomIndex=this.topIndex=maxDepth;this.dimension_=dimension;this.currentTrackerNode_=t [...]
+RecursionDepthTracker.prototype={push:function(viewNode){if(this.bottomIndex===0)
+throw new Error('Cannot push to a full tracker');var title=viewNode.title[this.dimension_];this.bottomIndex--;this.titlePath[this.bottomIndex]=title;this.viewNodePath[this.bottomIndex]=viewNode;var childTrackerNode=this.currentTrackerNode_.children.get(title);if(childTrackerNode!==undefined){this.currentTrackerNode_=childTrackerNode;return;}
+var maxLengths=zFunction(this.titlePath,this.bottomIndex);var recursionDepth=0;for(var i=0;i<maxLengths.length;i++)
+recursionDepth=Math.max(recursionDepth,maxLengths[i]);childTrackerNode=this.createNode_(recursionDepth,this.currentTrackerNode_);this.currentTrackerNode_.children.set(title,childTrackerNode);this.currentTrackerNode_=childTrackerNode;},pop:function(){if(this.bottomIndex===this.topIndex)
+throw new Error('Cannot pop from an empty tracker');this.titlePath[this.bottomIndex]=undefined;this.viewNodePath[this.bottomIndex]=undefined;this.bottomIndex++;this.currentTrackerNode_=this.currentTrackerNode_.parent;},get recursionDepth(){return this.currentTrackerNode_.recursionDepth;},createNode_:function(recursionDepth,parent){return{recursionDepth:recursionDepth,parent:parent,children:new Map()};}};function zFunction(list,startIndex){var n=list.length-startIndex;if(n===0)
+return[];var z=new Array(n);z[0]=0;for(var i=1,left=0,right=0;i<n;++i){var maxLength;if(i<=right)
+maxLength=Math.min(right-i+1,z[i-left]);else
+maxLength=0;while(i+maxLength<n&&list[startIndex+maxLength]===list[startIndex+i+maxLength]){++maxLength;}
+if(i+maxLength-1>right){left=i;right=i+maxLength-1;}
+z[i]=maxLength;}
+return z;}
+return{MultiDimensionalViewBuilder:MultiDimensionalViewBuilder,MultiDimensionalViewType:MultiDimensionalViewType,MultiDimensionalViewNode:MultiDimensionalViewNode,RecursionDepthTracker:RecursionDepthTracker,zFunction:zFunction};});'use strict';tr.exportTo('tr.ui.analysis',function(){var NO_BREAK_SPACE=String.fromCharCode(160);var RIGHTWARDS_ARROW=String.fromCharCode(8594);var COLLATOR=new Intl.Collator(undefined,{numeric:true});function TitleColumn(title){this.title=title;}
+TitleColumn.prototype={supportsCellSelection:false,value:function(row){var formattedTitle=this.formatTitle(row);var contexts=row.contexts;if(contexts===undefined||contexts.length===0)
+return formattedTitle;var firstContext=contexts[0];var lastContext=contexts[contexts.length-1];var changeDefinedContextCount=0;for(var i=1;i<contexts.length;i++){if((contexts[i]===undefined)!==(contexts[i-1]===undefined))
+changeDefinedContextCount++;}
+var color=undefined;var prefix=undefined;if(!firstContext&&lastContext){color='red';prefix='+++';}else if(firstContext&&!lastContext){color='green';prefix='---';}
+if(changeDefinedContextCount>1){color='purple';}
+if(color===undefined&&prefix===undefined)
+return formattedTitle;var titleEl=document.createElement('span');if(prefix!==undefined){var prefixEl=tr.ui.b.createSpan({textContent:prefix});prefixEl.style.fontFamily='monospace';titleEl.appendChild(prefixEl);titleEl.appendChild(tr.ui.b.asHTMLOrTextNode(NO_BREAK_SPACE));}
+if(color!==undefined)
+titleEl.style.color=color;titleEl.appendChild(tr.ui.b.asHTMLOrTextNode(formattedTitle));return titleEl;},formatTitle:function(row){return row.title;},cmp:function(rowA,rowB){return COLLATOR.compare(rowA.title,rowB.title);}};function MemoryColumn(name,cellPath,aggregationMode){this.name=name;this.cellPath=cellPath;this.aggregationMode=aggregationMode;}
+MemoryColumn.fromRows=function(rows,cellKey,aggregationMode,rules){var cellNames=new Set();function gatherCellNames(rows){rows.forEach(function(row){if(row===undefined)
+return;var fieldCells=row[cellKey];if(fieldCells!==undefined){tr.b.iterItems(fieldCells,function(fieldName,fieldCell){if(fieldCell===undefined||fieldCell.fields===undefined)
+return;cellNames.add(fieldName);});}
+var subRows=row.subRows;if(subRows!==undefined)
+gatherCellNames(subRows);});}
+gatherCellNames(rows);var positions=[];cellNames.forEach(function(cellName){var cellPath=[cellKey,cellName];var matchingRule=MemoryColumn.findMatchingRule(cellName,rules);var constructor=matchingRule.columnConstructor;var column=new constructor(cellName,cellPath,aggregationMode);positions.push({importance:matchingRule.importance,column:column});});positions.sort(function(a,b){if(a.importance===b.importance)
+return COLLATOR.compare(a.column.name,b.column.name);return b.importance-a.importance;});return positions.map(function(position){return position.column});};MemoryColumn.spaceEqually=function(columns){var columnWidth=(100/columns.length).toFixed(3)+'%';columns.forEach(function(column){column.width=columnWidth;});};MemoryColumn.findMatchingRule=function(name,rules){for(var i=0;i<rules.length;i++){var rule=rules[i];if(MemoryColumn.nameMatchesCondition(name,rule.condition))
+return rule;}
+return undefined;};MemoryColumn.nameMatchesCondition=function(name,condition){if(condition===undefined)
+return true;if(typeof(condition)==='string')
+return name===condition;return condition.test(name);};MemoryColumn.AggregationMode={DIFF:0,MAX:1};MemoryColumn.SOME_TIMESTAMPS_INFO_QUANTIFIER='at some selected timestamps';MemoryColumn.prototype={get title(){return this.name;},cell:function(row){var cell=row;var cellPath=this.cellPath;for(var i=0;i<cellPath.length;i++){if(cell===undefined)
+return undefined;cell=cell[cellPath[i]];}
+return cell;},aggregateCells:function(row,subRows){},fields:function(row){var cell=this.cell(row);if(cell===undefined)
+return undefined;return cell.fields;},value:function(row){var fields=this.fields(row);if(this.hasAllRelevantFieldsUndefined(fields))
+return'';var contexts=row.contexts;var color=this.color(fields,contexts);var infos=[];this.addInfos(fields,contexts,infos);var formattedFields=this.formatFields(fields);if((color===undefined||formattedFields==='')&&infos.length===0)
+return formattedFields;var fieldEl=document.createElement('span');fieldEl.style.display='flex';fieldEl.style.alignItems='center';fieldEl.appendChild(tr.ui.b.asHTMLOrTextNode(formattedFields));infos.forEach(function(info){var infoEl=document.createElement('span');infoEl.style.paddingLeft='4px';infoEl.style.cursor='help';infoEl.style.fontWeight='bold';infoEl.textContent=info.icon;if(info.color!==undefined)
+infoEl.style.color=info.color;infoEl.title=info.message;fieldEl.appendChild(infoEl);},this);if(color!==undefined)
+fieldEl.style.color=color;return fieldEl;},hasAllRelevantFieldsUndefined:function(fields){if(fields===undefined)
+return true;switch(this.aggregationMode){case MemoryColumn.AggregationMode.DIFF:return fields[0]===undefined&&fields[fields.length-1]===undefined;case MemoryColumn.AggregationMode.MAX:default:return fields.every(function(field){return field===undefined;});}},color:function(fields,contexts){return undefined;},formatFields:function(fields){if(fields.length===1)
+return this.formatSingleField(fields[0]);else
+return this.formatMultipleFields(fields);},formatSingleField:function(field){throw new Error('Not implemented');},formatMultipleFields:function(fields){switch(this.aggregationMode){case MemoryColumn.AggregationMode.DIFF:return this.formatMultipleFieldsDiff(fields[0],fields[fields.length-1]);case MemoryColumn.AggregationMode.MAX:return this.formatMultipleFieldsMax(fields);default:return tr.ui.b.createSpan({textContent:'(unsupported aggregation mode)',italic:true});}},formatMultipleFieldsD [...]
+throw new Error('Different number of fields');var undefinedA=this.hasAllRelevantFieldsUndefined(fieldsA);var undefinedB=this.hasAllRelevantFieldsUndefined(fieldsB);if(undefinedA&&undefinedB)
+return 0;if(undefinedA)
+return-1;if(undefinedB)
+return 1;return this.compareFields(fieldsA,fieldsB);},compareFields:function(fieldsA,fieldsB){if(fieldsA.length===1)
+return this.compareSingleFields(fieldsA[0],fieldsB[0]);else
+return this.compareMultipleFields(fieldsA,fieldsB);},compareSingleFields:function(fieldA,fieldB){throw new Error('Not implemented');},compareMultipleFields:function(fieldsA,fieldsB){switch(this.aggregationMode){case MemoryColumn.AggregationMode.DIFF:return this.compareMultipleFieldsDiff(fieldsA[0],fieldsA[fieldsA.length-1],fieldsB[0],fieldsB[fieldsB.length-1]);case MemoryColumn.AggregationMode.MAX:return this.compareMultipleFieldsMax(fieldsA,fieldsB);default:return 0;}},compareMultipleFi [...]
+return accumulator;if(accumulator===undefined||this.compareSingleFields(field,accumulator)>0){return field;}
+return accumulator;}.bind(this),undefined);},addInfos:function(fields,contexts,infos){},getImportance:function(importanceRules){if(importanceRules.length===0)
+return 0;var matchingRule=MemoryColumn.findMatchingRule(this.name,importanceRules);if(matchingRule!==undefined)
+return matchingRule.importance;var minImportance=importanceRules[0].importance;for(var i=1;i<importanceRules.length;i++)
+minImportance=Math.min(minImportance,importanceRules[i].importance);return minImportance-1;}};function StringMemoryColumn(name,cellPath,aggregationMode){MemoryColumn.call(this,name,cellPath,aggregationMode);}
+StringMemoryColumn.prototype={__proto__:MemoryColumn.prototype,formatSingleField:function(string){return string;},formatMultipleFieldsDiff:function(firstString,lastString){if(firstString===undefined){var spanEl=tr.ui.b.createSpan({color:'red'});spanEl.appendChild(tr.ui.b.asHTMLOrTextNode('+'));spanEl.appendChild(tr.ui.b.asHTMLOrTextNode(this.formatSingleField(lastString)));return spanEl;}else if(lastString===undefined){var spanEl=tr.ui.b.createSpan({color:'green'});spanEl.appendChild(tr. [...]
+return 1;if(firstStringA!==undefined&&firstStringB===undefined)
+return-1;if(firstStringA===undefined&&firstStringB===undefined)
+return this.compareSingleFields(lastStringA,lastStringB);if(lastStringA===undefined&&lastStringB!==undefined)
+return-1;if(lastStringA!==undefined&&lastStringB===undefined)
+return 1;if(lastStringA===undefined&&lastStringB===undefined)
+return this.compareSingleFields(firstStringB,firstStringA);var areStringsAEqual=firstStringA===lastStringA;var areStringsBEqual=firstStringB===lastStringB;if(areStringsAEqual&&areStringsBEqual)
+return 0;if(areStringsAEqual)
+return-1;if(areStringsBEqual)
+return 1;return 0;}};function NumericMemoryColumn(name,cellPath,aggregationMode){MemoryColumn.call(this,name,cellPath,aggregationMode);}
+NumericMemoryColumn.DIFF_EPSILON=0.0001;NumericMemoryColumn.prototype={__proto__:MemoryColumn.prototype,aggregateCells:function(row,subRows){var subRowCells=subRows.map(this.cell,this);var hasDefinedSubRowNumeric=false;var timestampCount=undefined;subRowCells.forEach(function(subRowCell){if(subRowCell===undefined)
+return;var subRowNumerics=subRowCell.fields;if(subRowNumerics===undefined)
+return;if(timestampCount===undefined)
+timestampCount=subRowNumerics.length;else if(timestampCount!==subRowNumerics.length)
+throw new Error('Sub-rows have different numbers of timestamps');if(hasDefinedSubRowNumeric)
+return;hasDefinedSubRowNumeric=subRowNumerics.some(function(numeric){return numeric!==undefined;});});if(!hasDefinedSubRowNumeric)
+return;var cellPath=this.cellPath;var rowCell=row;for(var i=0;i<cellPath.length;i++){var nextStepName=cellPath[i];var nextStep=rowCell[nextStepName];if(nextStep===undefined){if(i<cellPath.length-1)
+nextStep={};else
+nextStep=new MemoryCell(undefined);rowCell[nextStepName]=nextStep;}
+rowCell=nextStep;}
+if(rowCell.fields===undefined){rowCell.fields=new Array(timestampCount);}else if(rowCell.fields.length!==timestampCount){throw new Error('Row has a different number of timestamps than sub-rows');}
+for(var i=0;i<timestampCount;i++){if(rowCell.fields[i]!==undefined)
+continue;rowCell.fields[i]=tr.model.MemoryAllocatorDump.aggregateNumerics(subRowCells.map(function(subRowCell){if(subRowCell===undefined||subRowCell.fields===undefined)
+return undefined;return subRowCell.fields[i];}));}},formatSingleField:function(numeric){if(numeric===undefined)
+return'';return tr.v.ui.createScalarSpan(numeric);},formatMultipleFieldsDiff:function(firstNumeric,lastNumeric){return this.formatSingleField(this.getDiffField_(firstNumeric,lastNumeric));},compareSingleFields:function(numericA,numericB){return numericA.value-numericB.value;},compareMultipleFieldsDiff:function(firstNumericA,lastNumericA,firstNumericB,lastNumericB){return this.getDiffFieldValue_(firstNumericA,lastNumericA)-
+this.getDiffFieldValue_(firstNumericB,lastNumericB);},getDiffField_:function(firstNumeric,lastNumeric){var definedNumeric=firstNumeric||lastNumeric;return new tr.v.ScalarNumeric(definedNumeric.unit.correspondingDeltaUnit,this.getDiffFieldValue_(firstNumeric,lastNumeric));},getDiffFieldValue_:function(firstNumeric,lastNumeric){var firstValue=firstNumeric===undefined?0:firstNumeric.value;var lastValue=lastNumeric===undefined?0:lastNumeric.value;var diff=lastValue-firstValue;return Math.abs [...]
+MemoryCell.extractFields=function(cell){if(cell===undefined)
+return undefined;return cell.fields;};var RECURSIVE_EXPANSION_MAX_VISIBLE_ROW_COUNT=10;function expandTableRowsRecursively(table){var currentLevelRows=table.tableRows;var totalVisibleRowCount=currentLevelRows.length;while(currentLevelRows.length>0){var nextLevelRowCount=0;currentLevelRows.forEach(function(currentLevelRow){var subRows=currentLevelRow.subRows;if(subRows===undefined||subRows.length===0)
+return;nextLevelRowCount+=subRows.length;});if(totalVisibleRowCount+nextLevelRowCount>RECURSIVE_EXPANSION_MAX_VISIBLE_ROW_COUNT){break;}
+var nextLevelRows=new Array(nextLevelRowCount);var nextLevelRowIndex=0;currentLevelRows.forEach(function(currentLevelRow){var subRows=currentLevelRow.subRows;if(subRows===undefined||subRows.length===0)
+return;table.setExpandedForTableRow(currentLevelRow,true);subRows.forEach(function(subRow){nextLevelRows[nextLevelRowIndex++]=subRow;});});totalVisibleRowCount+=nextLevelRowCount;currentLevelRows=nextLevelRows;}}
+function aggregateTableRowCellsRecursively(row,columns,opt_predicate){var subRows=row.subRows;if(subRows===undefined||subRows.length===0)
+return;subRows.forEach(function(subRow){aggregateTableRowCellsRecursively(subRow,columns,opt_predicate);});if(opt_predicate===undefined||opt_predicate(row.contexts))
+aggregateTableRowCells(row,subRows,columns);}
+function aggregateTableRowCells(row,subRows,columns){columns.forEach(function(column){if(!(column instanceof MemoryColumn))
+return;column.aggregateCells(row,subRows);});}
+function createCells(timeToValues,valueFieldsGetter){var fieldNameToFields=tr.b.invertArrayOfDicts(timeToValues,valueFieldsGetter);return tr.b.mapItems(fieldNameToFields,function(fieldName,fields){return new tr.ui.analysis.MemoryCell(fields);});}
+function createWarningInfo(message){return{message:message,icon:String.fromCharCode(9888),color:'red'};}
+return{TitleColumn:TitleColumn,MemoryColumn:MemoryColumn,StringMemoryColumn:StringMemoryColumn,NumericMemoryColumn:NumericMemoryColumn,MemoryCell:MemoryCell,expandTableRowsRecursively:expandTableRowsRecursively,aggregateTableRowCellsRecursively:aggregateTableRowCellsRecursively,aggregateTableRowCells:aggregateTableRowCells,createCells:createCells,createWarningInfo:createWarningInfo};});'use strict';Polymer('tr-ui-a-stacked-pane',{rebuild:function(){if(!this.paneDirty_){return;}
+this.paneDirty_=false;this.rebuildPane_();},scheduleRebuildPane_:function(){if(this.paneDirty_)
+return;this.paneDirty_=true;setTimeout(this.rebuild.bind(this),0);},rebuildPane_:function(){},set childPaneBuilder(childPaneBuilder){this.childPaneBuilder_=childPaneBuilder;this.dispatchEvent(new tr.b.Event('request-child-pane-change'));},get childPaneBuilder(){return this.childPaneBuilder_;},appended:function(){this.rebuild();}});'use strict';tr.exportTo('tr.ui.analysis',function(){var ScalarNumeric=tr.v.ScalarNumeric;var sizeInBytes_smallerIsBetter=tr.v.Unit.byName.sizeInBytes_smallerI [...]
+HeapDumpNodeTitleColumn.prototype={__proto__:tr.ui.analysis.TitleColumn.prototype,formatTitle:function(row){var title=row.title;var dimension=row.dimension;switch(dimension){case RowDimension.ROOT:return title;case RowDimension.STACK_FRAME:case RowDimension.OBJECT_TYPE:return this.formatSubRow_(title,dimension);default:throw new Error('Invalid row dimension: '+row.dimension);}},cmp:function(rowA,rowB){if(rowA.dimension!==rowB.dimension)
+return rowA.dimension-rowB.dimension;return tr.ui.analysis.TitleColumn.prototype.cmp.call(this,rowA,rowB);},formatSubRow_:function(title,dimension){var titleEl=document.createElement('span');var symbolEl=document.createElement('span');var symbolColorName;if(dimension===RowDimension.STACK_FRAME){symbolEl.textContent=LATIN_SMALL_LETTER_F_WITH_HOOK;symbolEl.title='Stack frame';symbolColorName='heap_dump_stack_frame';}else{symbolEl.textContent=CIRCLED_LATIN_CAPITAL_LETTER_T;symbolEl.title='O [...]
+symbolEl.style.color=tr.b.ColorScheme.getColorForReservedNameAsString(symbolColorName);symbolEl.style.paddingRight='4px';symbolEl.style.cursor='help';symbolEl.style.weight='bold';titleEl.appendChild(symbolEl);titleEl.appendChild(document.createTextNode(title));return titleEl;}};var COLUMN_RULES=[{importance:0,columnConstructor:tr.ui.analysis.NumericMemoryColumn}];Polymer('tr-ui-a-memory-dump-heap-details-pane',{created:function(){this.heapDumps_=undefined;this.aggregationMode_=undefined; [...]
+this.$.info_text.style.display='none';this.$.table.style.display='block';this.$.view_mode_container.style.display='block';this.$.info_bar.visible=this.heavyView;var stackFrameTrees=this.createStackFrameTrees_(this.heapDumps_);var rows=this.createRows_(stackFrameTrees);var columns=this.createColumns_(rows);this.$.table.tableRows=rows;this.$.table.tableColumns=columns;this.$.table.rebuild();tr.ui.analysis.expandTableRowsRecursively(this.$.table);},createStackFrameTrees_:function(heapDumps) [...]
+return undefined;var builder=new tr.b.MultiDimensionalViewBuilder(2);heapDump.entries.forEach(function(entry){var leafStackFrame=entry.leafStackFrame;var stackTracePath=leafStackFrame===undefined?[]:leafStackFrame.getUserFriendlyStackTrace().reverse();var objectTypeName=entry.objectTypeName;var objectTypeNamePath=objectTypeName===undefined?[]:[objectTypeName];builder.addPath([stackTracePath,objectTypeNamePath],entry.size,tr.b.MultiDimensionalViewBuilder.ValueKind.TOTAL);},this);return bu [...]
+return[];var rootRowTitle=definedHeapDump.allocatorName;return[this.createHeapRowRecursively_(stackFrameTrees,RowDimension.ROOT,rootRowTitle)];},createHeapRowRecursively_:function(nodes,dimension,title){var cells=tr.ui.analysis.createCells(nodes,function(node){return{'Size':new ScalarNumeric(sizeInBytes_smallerIsBetter,node.total)};});var row={dimension:dimension,title:title,contexts:nodes,cells:cells};var stackFrameSubRows=this.createHeapDimensionSubRowsRecursively_(nodes,RowDimension.S [...]
+row.subRows=subRows;return row;},createHeapDimensionSubRowsRecursively_:function(nodes,dimension){var dimensionGroupedChildNodes=tr.b.dictionaryValues(tr.b.invertArrayOfDicts(nodes,function(node){var childDict={};var displayedChildrenTotal=0;var hasDisplayedChildren=false;for(var child of node.children[dimension].values()){if(!this.heavyView&&child.isLowerBound)
+continue;childDict[child.title[dimension]]=child;displayedChildrenTotal+=child.total;hasDisplayedChildren=true;}
+if(!this.heavyView&&displayedChildrenTotal<node.total&&hasDisplayedChildren){var otherTitle=node.title.slice();otherTitle[dimension]='<other>';childDict['<other>']={title:otherTitle,total:node.total-displayedChildrenTotal,children:[new Map(),new Map()]};}
+return childDict;},this));return dimensionGroupedChildNodes.map(function(subRowNodes){var subRowTitle=tr.b.findFirstInArray(subRowNodes).title[dimension];return this.createHeapRowRecursively_(subRowNodes,dimension,subRowTitle);},this);},createColumns_:function(rows){var titleColumn=new HeapDumpNodeTitleColumn('Stack frame');titleColumn.width='500px';var numericColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'cells',this.aggregationMode_,COLUMN_RULES);tr.ui.analysis.MemoryColumn.spaceEq [...]
+AllocatorDumpNameColumn.prototype={__proto__:tr.ui.analysis.TitleColumn.prototype,formatTitle:function(row){if(!row.suballocation)
+return row.title;return tr.ui.b.createSpan({textContent:row.title,italic:true,tooltip:row.fullNames===undefined?undefined:row.fullNames.join(', ')});}};function getAndUpdateEntry(map,name,createdCallback){var entry=map.get(name);if(entry===undefined){entry={count:0};createdCallback(entry);map.set(name,entry);}
+entry.count++;return entry;}
+function SizeInfoMessageBuilder(){this.parts_=[];this.indent_=0;}
+SizeInfoMessageBuilder.prototype={append:function(){this.parts_.push.apply(this.parts_,Array.prototype.slice.apply(arguments));},appendMap:function(map,hasPluralSuffix,emptyText,itemCallback,opt_this){opt_this=opt_this||this;if(map.size===0){if(emptyText)
+this.append(emptyText);}else if(map.size===1){this.parts_.push(' ');var key=map.keys().next().value;itemCallback.call(opt_this,key,map.get(key));}else{if(hasPluralSuffix)
+this.parts_.push('s');this.parts_.push(':');this.indent_++;for(var key of map.keys()){this.parts_.push('\n',' '.repeat(3*(this.indent_-1)),' - ');itemCallback.call(opt_this,key,map.get(key));}
+this.indent_--;}},appendImportanceRange:function(range){this.append(' (importance: ');if(range.min===range.max)
+this.append(range.min);else
+this.append(range.min,EN_DASH,range.max);this.append(')');},appendSizeIfDefined:function(size){if(size!==undefined)
+this.append(' (',tr.v.Unit.byName.sizeInBytes.format(size),')');},appendSomeTimestampsQuantifier:function(){this.append(' ',tr.ui.analysis.MemoryColumn.SOME_TIMESTAMPS_INFO_QUANTIFIER);},build:function(){return this.parts_.join('');}};function EffectiveSizeColumn(name,cellPath,aggregationMode){tr.ui.analysis.NumericMemoryColumn.call(this,name,cellPath,aggregationMode);}
+EffectiveSizeColumn.prototype={__proto__:tr.ui.analysis.NumericMemoryColumn.prototype,addInfos:function(numerics,memoryAllocatorDumps,infos){if(memoryAllocatorDumps===undefined)
+return;var ownerNameToEntry=new Map();var ownedNameToEntry=new Map();for(var i=0;i<numerics.length;i++){if(numerics[i]===undefined)
+continue;var dump=memoryAllocatorDumps[i];if(dump===SUBALLOCATION_CONTEXT)
+return;dump.ownedBy.forEach(function(ownerLink){var ownerDump=ownerLink.source;this.getAndUpdateOwnershipEntry_(ownerNameToEntry,ownerDump,ownerLink);},this);var ownedLink=dump.owns;if(ownedLink!==undefined){var ownedDump=ownedLink.target;var ownedEntry=this.getAndUpdateOwnershipEntry_(ownedNameToEntry,ownedDump,ownedLink,true);var sharerNameToEntry=ownedEntry.sharerNameToEntry;ownedDump.ownedBy.forEach(function(sharerLink){var sharerDump=sharerLink.source;if(sharerDump===dump)
+return;this.getAndUpdateOwnershipEntry_(sharerNameToEntry,sharerDump,sharerLink);},this);}}
+if(ownerNameToEntry.size>0){var messageBuilder=new SizeInfoMessageBuilder();messageBuilder.append('shared by');messageBuilder.appendMap(ownerNameToEntry,false,undefined,function(ownerName,ownerEntry){messageBuilder.append(ownerName);if(ownerEntry.count<numerics.length)
+messageBuilder.appendSomeTimestampsQuantifier();messageBuilder.appendImportanceRange(ownerEntry.importanceRange);},this);infos.push({message:messageBuilder.build(),icon:LEFTWARDS_OPEN_HEADED_ARROW,color:'green'});}
+if(ownedNameToEntry.size>0){var messageBuilder=new SizeInfoMessageBuilder();messageBuilder.append('shares');messageBuilder.appendMap(ownedNameToEntry,false,undefined,function(ownedName,ownedEntry){messageBuilder.append(ownedName);var ownedCount=ownedEntry.count;if(ownedCount<numerics.length)
+messageBuilder.appendSomeTimestampsQuantifier();messageBuilder.appendImportanceRange(ownedEntry.importanceRange);messageBuilder.append(' with');messageBuilder.appendMap(ownedEntry.sharerNameToEntry,false,' no other dumps',function(sharerName,sharerEntry){messageBuilder.append(sharerName);if(sharerEntry.count<ownedCount)
+messageBuilder.appendSomeTimestampsQuantifier();messageBuilder.appendImportanceRange(sharerEntry.importanceRange);},this);},this);infos.push({message:messageBuilder.build(),icon:RIGHTWARDS_OPEN_HEADED_ARROW,color:'green'});}},getAndUpdateOwnershipEntry_:function(map,dump,link,opt_withSharerNameToEntry){var entry=getAndUpdateEntry(map,dump.quantifiedName,function(newEntry){newEntry.importanceRange=new tr.b.Range();if(opt_withSharerNameToEntry)
+newEntry.sharerNameToEntry=new Map();});entry.importanceRange.addValue(link.importance||0);return entry;}};function SizeColumn(name,cellPath,aggregationMode){tr.ui.analysis.NumericMemoryColumn.call(this,name,cellPath,aggregationMode);}
+SizeColumn.prototype={__proto__:tr.ui.analysis.NumericMemoryColumn.prototype,addInfos:function(numerics,memoryAllocatorDumps,infos){if(memoryAllocatorDumps===undefined)
+return;this.addOverlapInfo_(numerics,memoryAllocatorDumps,infos);this.addProvidedSizeWarningInfos_(numerics,memoryAllocatorDumps,infos);},addOverlapInfo_:function(numerics,memoryAllocatorDumps,infos){var siblingNameToEntry=new Map();for(var i=0;i<numerics.length;i++){if(numerics[i]===undefined)
+continue;var dump=memoryAllocatorDumps[i];if(dump===SUBALLOCATION_CONTEXT)
+return;var ownedBySiblingSizes=dump.ownedBySiblingSizes;for(var siblingDump of ownedBySiblingSizes.keys()){var siblingName=siblingDump.name;getAndUpdateEntry(siblingNameToEntry,siblingName,function(newEntry){if(numerics.length===1)
+newEntry.size=ownedBySiblingSizes.get(siblingDump);});}}
+if(siblingNameToEntry.size>0){var messageBuilder=new SizeInfoMessageBuilder();messageBuilder.append('overlaps with its sibling');messageBuilder.appendMap(siblingNameToEntry,true,undefined,function(siblingName,siblingEntry){messageBuilder.append('\'',siblingName,'\'');messageBuilder.appendSizeIfDefined(siblingEntry.size);if(siblingEntry.count<numerics.length)
+messageBuilder.appendSomeTimestampsQuantifier();},this);infos.push({message:messageBuilder.build(),icon:CIRCLED_LATIN_SMALL_LETTER_I,color:'blue'});}},addProvidedSizeWarningInfos_:function(numerics,memoryAllocatorDumps,infos){var infoTypeToEntry=new Map();for(var i=0;i<numerics.length;i++){if(numerics[i]===undefined)
+continue;var dump=memoryAllocatorDumps[i];if(dump===SUBALLOCATION_CONTEXT)
+return;dump.infos.forEach(function(dumpInfo){getAndUpdateEntry(infoTypeToEntry,dumpInfo.type,function(newEntry){if(numerics.length===1){newEntry.providedSize=dumpInfo.providedSize;newEntry.dependencySize=dumpInfo.dependencySize;}});});}
+for(var infoType of infoTypeToEntry.keys()){var entry=infoTypeToEntry.get(infoType);var messageBuilder=new SizeInfoMessageBuilder();messageBuilder.append('provided size');messageBuilder.appendSizeIfDefined(entry.providedSize);var dependencyName;switch(infoType){case PROVIDED_SIZE_LESS_THAN_AGGREGATED_CHILDREN:dependencyName='the aggregated size of the children';break;case PROVIDED_SIZE_LESS_THAN_LARGEST_OWNER:dependencyName='the size of the largest owner';break;default:dependencyName='an [...]
+messageBuilder.append(' was less than ',dependencyName);messageBuilder.appendSizeIfDefined(entry.dependencySize);if(entry.count<numerics.length)
+messageBuilder.appendSomeTimestampsQuantifier();infos.push(tr.ui.analysis.createWarningInfo(messageBuilder.build()));}}};var NUMERIC_COLUMN_RULES=[{condition:tr.model.MemoryAllocatorDump.EFFECTIVE_SIZE_NUMERIC_NAME,importance:10,columnConstructor:EffectiveSizeColumn},{condition:tr.model.MemoryAllocatorDump.SIZE_NUMERIC_NAME,importance:9,columnConstructor:SizeColumn},{condition:'page_size',importance:0,columnConstructor:tr.ui.analysis.NumericMemoryColumn},{condition:/size/,importance:5,co [...]
+this.$.info_text.style.display='none';this.$.table.style.display='block';var rows=this.createRows_();var columns=this.createColumns_(rows);rows.forEach(function(rootRow){tr.ui.analysis.aggregateTableRowCellsRecursively(rootRow,columns,function(contexts){return contexts!==undefined&&contexts.some(function(context){return context===SUBALLOCATION_CONTEXT;});});});this.$.table.tableRows=rows;this.$.table.tableColumns=columns;this.$.table.rebuild();tr.ui.analysis.expandTableRowsRecursively(th [...]
+var ownerDump=dump.ownedBy[0].source;if(dump.ownedBy.length>1||dump.children.length>0||ownerDump.containerMemoryDump!==dump.containerMemoryDump){suballocatedBy=undefined;break;}
+if(suballocatedBy===undefined){suballocatedBy=ownerDump.fullName;}else if(suballocatedBy!==ownerDump.fullName){suballocatedBy=undefined;break;}}}
+var row={title:title,fullNames:[fullName],contexts:dumps,numericCells:numericCells,diagnosticCells:diagnosticCells,suballocatedBy:suballocatedBy};var childDumpNameToDumps=tr.b.invertArrayOfDicts(dumps,function(dump){return tr.b.arrayToDict(dump.children,function(child){return child.name;});});var subRows=[];var suballocationClassificationRootNode=undefined;tr.b.iterItems(childDumpNameToDumps,function(childName,childDumps){var childRow=this.createAllocatorRowRecursively_(childDumps);if(ch [...]
+if(subRows.length>0)
+row.subRows=subRows;return row;},classifySuballocationRow_:function(suballocationRow,rootNode){if(rootNode===undefined){rootNode={children:{},row:undefined};}
+var suballocationLevels=suballocationRow.suballocatedBy.split('/');var currentNode=rootNode;for(var i=0;i<suballocationLevels.length;i++){var suballocationLevel=suballocationLevels[i];var nextNode=currentNode.children[suballocationLevel];if(nextNode===undefined){currentNode.children[suballocationLevel]=nextNode={children:{},row:undefined};}
+var currentNode=nextNode;}
+var existingRow=currentNode.row;if(existingRow!==undefined){for(var i=0;i<suballocationRow.contexts.length;i++){var newContext=suballocationRow.contexts[i];if(newContext===undefined)
+continue;if(existingRow.contexts[i]!==undefined)
+throw new Error('Multiple suballocations with the same owner name');existingRow.contexts[i]=newContext;['numericCells','diagnosticCells'].forEach(function(cellKey){var suballocationCells=suballocationRow[cellKey];if(suballocationCells===undefined)
+return;tr.b.iterItems(suballocationCells,function(cellName,cell){if(cell===undefined)
+return;var fields=cell.fields;if(fields===undefined)
+return;var field=fields[i];if(field===undefined)
+return;var existingCells=existingRow[cellKey];if(existingCells===undefined){existingCells={};existingRow[cellKey]=existingCells;}
+var existingCell=existingCells[cellName];if(existingCell===undefined){existingCell=new tr.ui.analysis.MemoryCell(new Array(fields.length));existingCells[cellName]=existingCell;}
+existingCell.fields[i]=field;});});}
+existingRow.fullNames.push.apply(existingRow.fullNames,suballocationRow.fullNames);}else{currentNode.row=suballocationRow;}
+return rootNode;},createSuballocationRowRecursively_:function(name,node){var childCount=Object.keys(node.children).length;if(childCount===0){if(node.row===undefined)
+throw new Error('Suballocation node must have a row or children');var row=node.row;row.title=name;row.suballocation=true;return row;}
+var subRows=tr.b.dictionaryValues(tr.b.mapItems(node.children,this.createSuballocationRowRecursively_,this));if(node.row!==undefined){var row=node.row;row.title='<unspecified>';row.suballocation=true;subRows.unshift(row);}
+var contexts=new Array(subRows[0].contexts.length);for(var i=0;i<subRows.length;i++){subRows[i].contexts.forEach(function(subContext,index){if(subContext!==undefined)
+contexts[index]=SUBALLOCATION_CONTEXT;});}
+return{title:name,suballocation:true,contexts:contexts,subRows:subRows};},createColumns_:function(rows){var titleColumn=new AllocatorDumpNameColumn();titleColumn.width='200px';var numericColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'numericCells',this.aggregationMode_,NUMERIC_COLUMN_RULES);var diagnosticColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'diagnosticCells',this.aggregationMode_,DIAGNOSTIC_COLUMN_RULES);var fieldColumns=numericColumns.concat(diagnosticColumns);tr.ui.ana [...]
+return undefined;var hexPadding=is64BitAddress?'0000000000000000':'00000000';return(hexPadding+address.toString(16)).substr(-hexPadding.length);}
+function pruneEmptyRuleRows(row){if(row.subRows===undefined||row.subRows.length===0)
+return;if(row.subRows[0].rule===undefined){return;}
+row.subRows.forEach(pruneEmptyRuleRows);row.subRows=row.subRows.filter(function(subRow){return subRow.subRows.length>0;});}
+Polymer('tr-ui-a-memory-dump-vm-regions-details-pane',{created:function(){this.vmRegions_=undefined;this.aggregationMode_=undefined;},ready:function(){this.$.table.selectionMode=tr.ui.b.TableFormat.SelectionMode.ROW;},set vmRegions(vmRegions){this.vmRegions_=vmRegions;this.scheduleRebuildPane_();},get vmRegions(){return this.vmRegions_;},set aggregationMode(aggregationMode){this.aggregationMode_=aggregationMode;this.scheduleRebuildPane_();},get aggregationMode(){return this.aggregationMo [...]
+this.$.info_text.style.display='none';this.$.table.style.display='block';var rows=this.createRows_(this.vmRegions_);var columns=this.createColumns_(rows);this.$.table.tableRows=rows;this.$.table.tableColumns=columns;this.$.table.rebuild();tr.ui.analysis.expandTableRowsRecursively(this.$.table);},createRows_:function(timeToVmRegionTree){var is64BitAddress=timeToVmRegionTree.some(function(vmRegionTree){if(vmRegionTree===undefined)
+return false;return vmRegionTree.someRegion(function(region){if(region.startAddress===undefined)
+return false;return region.startAddress>=4294967296;});});return[this.createClassificationNodeRow(timeToVmRegionTree,is64BitAddress)];},createClassificationNodeRow:function(timeToNode,is64BitAddress){var definedNode=tr.b.findFirstInArray(timeToNode);var childNodeIdToTimeToNode=tr.b.dictionaryValues(tr.b.invertArrayOfDicts(timeToNode,function(node){var children=node.children;if(children===undefined)
+return undefined;var childMap={};children.forEach(function(childNode){if(!childNode.hasRegions)
+return;childMap[childNode.title]=childNode;});return childMap;}));var childNodeSubRows=childNodeIdToTimeToNode.map(function(timeToChildNode){return this.createClassificationNodeRow(timeToChildNode,is64BitAddress);},this);var regionIdToTimeToRegion=tr.b.dictionaryValues(tr.b.invertArrayOfDicts(timeToNode,function(node){var regions=node.regions;if(regions===undefined)
+return undefined;return tr.b.arrayToDict(regions,function(region){return region.uniqueIdWithinProcess;});}));var regionSubRows=regionIdToTimeToRegion.map(function(timeToRegion){return this.createRegionRow_(timeToRegion,is64BitAddress);},this);var subRows=childNodeSubRows.concat(regionSubRows);return{title:definedNode.title,contexts:timeToNode,variableCells:this.createVariableCells_(timeToNode),subRows:subRows};},createRegionRow_:function(timeToRegion,is64BitAddress){var definedRegion=tr. [...]
+return undefined;return{'Start address':hexString(startAddress,is64BitAddress)};});},createVariableCells_:function(timeToRegion){return tr.ui.analysis.createCells(timeToRegion,function(region){var fields={};var sizeInBytes=region.sizeInBytes;if(sizeInBytes!==undefined){fields['Virtual size']=new ScalarNumeric(sizeInBytes_smallerIsBetter,sizeInBytes);}
+var protectionFlags=region.protectionFlagsToString;if(protectionFlags!==undefined)
+fields['Protection flags']=protectionFlags;tr.b.iterItems(BYTE_STAT_COLUMN_MAP,function(byteStatName,columnName){var byteStat=region.byteStats[byteStatName];if(byteStat===undefined)
+return;fields[columnName]=new ScalarNumeric(sizeInBytes_smallerIsBetter,byteStat);});return fields;});},createColumns_:function(rows){var titleColumn=new tr.ui.analysis.TitleColumn('Mapped file');titleColumn.width='200px';var constantColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'constantCells',undefined,CONSTANT_COLUMN_RULES);var variableColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'variableCells',this.aggregationMode_,VARIABLE_COLUMN_RULES);var fieldColumns=constantColumns.con [...]
+var colorId=tr.b.ColorScheme.getColorIdForGeneralPurposeString(label);this.setLabelAndColorId(label,colorId);},setLabelAndColorId:function(label,colorId){this.label_=label;this.$.label.textContent='';this.$.label.appendChild(tr.ui.b.asHTMLOrTextNode(label));if(colorId===undefined)
+this.$.square.style.color='initial';else
+this.$.square.style.color=tr.b.ColorScheme.colorsAsStrings[colorId];}});'use strict';Polymer('tr-ui-b-view-specific-brushing-state',{get viewId(){return this.getAttribute('view-id');},set viewId(viewId){this.setAttribute('view-id',viewId);},get:function(){var viewId=this.viewId;if(!viewId)
+throw new Error('Element must have a view-id attribute!');var brushingStateController=tr.c.BrushingStateController.getControllerForElement(this);if(!brushingStateController)
+return undefined;return brushingStateController.getViewSpecificBrushingState(viewId);},set:function(state){var viewId=this.viewId;if(!viewId)
+throw new Error('Element must have a view-id attribute!');var brushingStateController=tr.c.BrushingStateController.getControllerForElement(this);if(!brushingStateController)
+return;brushingStateController.changeViewSpecificBrushingState(viewId,state);}});'use strict';tr.exportTo('tr.ui.analysis',function(){var ColorScheme=tr.b.ColorScheme;var ScalarNumeric=tr.v.ScalarNumeric;var sizeInBytes_smallerIsBetter=tr.v.Unit.byName.sizeInBytes_smallerIsBetter;var PLATFORM_SPECIFIC_TOTAL_NAME_SUFFIX='_bytes';var DISPLAYED_SIZE_NUMERIC_NAME=tr.model.MemoryAllocatorDump.DISPLAYED_SIZE_NUMERIC_NAME;var SOME_TIMESTAMPS_INFO_QUANTIFIER=tr.ui.analysis.MemoryColumn.SOME_TIME [...]
+return;if(result===undefined)
+result=new Array(list.length);result[index]=value;});return result;}
+function ProcessNameColumn(){tr.ui.analysis.TitleColumn.call(this,'Process');}
+ProcessNameColumn.prototype={__proto__:tr.ui.analysis.TitleColumn.prototype,formatTitle:function(row){if(row.contexts===undefined)
+return row.title;var titleEl=document.createElement('tr-ui-b-color-legend');titleEl.label=row.title;return titleEl;}};function UsedMemoryColumn(name,cellPath,aggregationMode){tr.ui.analysis.NumericMemoryColumn.call(this,name,cellPath,aggregationMode);}
+UsedMemoryColumn.COLOR=ColorScheme.getColorForReservedNameAsString('used_memory_column');UsedMemoryColumn.OLDER_COLOR=ColorScheme.getColorForReservedNameAsString('older_used_memory_column');UsedMemoryColumn.prototype={__proto__:tr.ui.analysis.NumericMemoryColumn.prototype,get title(){return tr.ui.b.createSpan({textContent:this.name,color:UsedMemoryColumn.COLOR});},color:function(numerics,processMemoryDumps){return UsedMemoryColumn.COLOR;},getChildPaneBuilder:function(processMemoryDumps){ [...]
+return undefined;var vmRegions=lazyMap(processMemoryDumps,function(pmd){if(pmd===undefined)
+return undefined;return pmd.mostRecentVmRegions;});if(vmRegions===undefined)
+return undefined;return function(){var pane=document.createElement('tr-ui-a-memory-dump-vm-regions-details-pane');pane.vmRegions=vmRegions;pane.aggregationMode=this.aggregationMode;return pane;}.bind(this);}};function PeakMemoryColumn(name,cellPath,aggregationMode){UsedMemoryColumn.call(this,name,cellPath,aggregationMode);}
+PeakMemoryColumn.prototype={__proto__:UsedMemoryColumn.prototype,addInfos:function(numerics,processMemoryDumps,infos){if(processMemoryDumps===undefined)
+return;var resettableValueCount=0;var nonResettableValueCount=0;for(var i=0;i<numerics.length;i++){if(numerics[i]===undefined)
+continue;if(processMemoryDumps[i].arePeakResidentBytesResettable)
+resettableValueCount++;else
+nonResettableValueCount++;}
+if(resettableValueCount>0&&nonResettableValueCount>0){infos.push(tr.ui.analysis.createWarningInfo('Both resettable and '+'non-resettable peak RSS values were provided by the process'));}else if(resettableValueCount>0){infos.push({icon:RIGHTWARDS_ARROW_WITH_HOOK,message:'Peak RSS since previous memory dump.'});}else{infos.push({icon:RIGHTWARDS_ARROW_FROM_BAR,message:'Peak RSS since process startup. Finer grained '+'peaks require a Linux kernel version '+
+GREATER_THAN_OR_EQUAL_TO+' 4.0.'});}}};function ByteStatColumn(name,cellPath,aggregationMode){UsedMemoryColumn.call(this,name,cellPath,aggregationMode);}
+ByteStatColumn.prototype={__proto__:UsedMemoryColumn.prototype,color:function(numerics,processMemoryDumps){if(processMemoryDumps===undefined)
+return UsedMemoryColumn.COLOR;var allOlderValues=processMemoryDumps.every(function(processMemoryDump){if(processMemoryDump===undefined)
+return true;return!processMemoryDump.hasOwnVmRegions;});if(allOlderValues)
+return UsedMemoryColumn.OLDER_COLOR;else
+return UsedMemoryColumn.COLOR;},addInfos:function(numerics,processMemoryDumps,infos){if(processMemoryDumps===undefined)
+return;var olderValueCount=0;for(var i=0;i<numerics.length;i++){var processMemoryDump=processMemoryDumps[i];if(processMemoryDump!==undefined&&!processMemoryDump.hasOwnVmRegions){olderValueCount++;}}
+if(olderValueCount===0)
+return;var infoQuantifier=olderValueCount<numerics.length?' '+SOME_TIMESTAMPS_INFO_QUANTIFIER:'';infos.push({message:'Older value'+infoQuantifier+' (only heavy (purple) memory dumps contain memory maps).',icon:UNMARRIED_PARTNERSHIP_SYMBOL});}};UsedMemoryColumn.RULES=[{condition:'Total resident',importance:10,columnConstructor:UsedMemoryColumn},{condition:'Peak total resident',importance:9,columnConstructor:PeakMemoryColumn},{condition:'PSS',importance:8,columnConstructor:ByteStatColumn}, [...]
+AllocatorColumn.prototype={__proto__:tr.ui.analysis.NumericMemoryColumn.prototype,get title(){var titleEl=document.createElement('tr-ui-b-color-legend');titleEl.label=this.name;return titleEl;},addInfos:function(numerics,processMemoryDumps,infos){if(processMemoryDumps===undefined)
+return;var heapDumpCount=0;for(var i=0;i<processMemoryDumps.length;i++){var processMemoryDump=processMemoryDumps[i];if(processMemoryDump===undefined)
+continue;var heapDumps=processMemoryDump.heapDumps;if(heapDumps===undefined)
+continue;if(heapDumps[this.name]!==undefined)
+heapDumpCount++;}
+if(heapDumpCount===0)
+return;var infoQuantifier=heapDumpCount<numerics.length?' '+SOME_TIMESTAMPS_INFO_QUANTIFIER:'';infos.push({message:'Heap dump provided'+infoQuantifier+'.',icon:TRIGRAM_FOR_HEAVEN});},getChildPaneBuilder:function(processMemoryDumps){if(processMemoryDumps===undefined)
+return undefined;var memoryAllocatorDumps=lazyMap(processMemoryDumps,function(pmd){if(pmd===undefined)
+return undefined;return pmd.getMemoryAllocatorDumpByFullName(this.name);},this);if(memoryAllocatorDumps===undefined)
+return undefined;var heapDumps=lazyMap(processMemoryDumps,function(pmd){if(pmd===undefined||pmd.heapDumps===undefined)
+return undefined;return pmd.heapDumps[this.name];},this);return function(){var pane=document.createElement('tr-ui-a-memory-dump-allocator-details-pane');pane.memoryAllocatorDumps=memoryAllocatorDumps;pane.heapDumps=heapDumps;pane.aggregationMode=this.aggregationMode;return pane;}.bind(this);}};function TracingColumn(name,cellPath,aggregationMode){AllocatorColumn.call(this,name,cellPath,aggregationMode);}
+TracingColumn.COLOR=ColorScheme.getColorForReservedNameAsString('tracing_memory_column');TracingColumn.prototype={__proto__:AllocatorColumn.prototype,get title(){return tr.ui.b.createSpan({textContent:this.name,color:TracingColumn.COLOR});},color:function(numerics,processMemoryDumps){return TracingColumn.COLOR;}};AllocatorColumn.RULES=[{condition:'tracing',importance:0,columnConstructor:TracingColumn},{importance:1,columnConstructor:AllocatorColumn}];Polymer('tr-ui-a-memory-dump-overview [...]
+var selectedTableRow=this.$.table.selectedTableRow;if(!selectedTableRow)
+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;},changeChildPane_:function(){this.storeSelection_();this.childPaneBuilder=this.determineChildPaneBuilderFromSelection_();},determineChildPaneBuilderFromSelection_:function(){if(this.processMemoryDumps_===undefined||this.processMemoryDumps_.length===0){return undefined;}
+var selectedTableRow=this.$.table.selectedTableRow;if(!selectedTableRow)
+return undefined;var selectedColumnIndex=this.$.table.selectedColumnIndex;if(selectedColumnIndex===undefined)
+return undefined;var selectedColumn=this.$.table.tableColumns[selectedColumnIndex];return selectedColumn.getChildPaneBuilder(selectedTableRow.contexts);},rebuildPane_:function(){if(this.processMemoryDumps_===undefined||this.processMemoryDumps_.length===0){this.$.info_text.style.display='block';this.$.table.style.display='none';this.$.table.clear();this.$.table.rebuild();return;}
+this.$.info_text.style.display='none';this.$.table.style.display='block';var rows=this.createRows_();var columns=this.createColumns_(rows);var footerRows=this.createFooterRows_(rows,columns);this.$.table.tableRows=rows;this.$.table.footerRows=footerRows;this.$.table.tableColumns=columns;this.$.table.rebuild();this.restoreSelection_();},createRows_:function(){var timeToPidToProcessMemoryDump=this.processMemoryDumps_;var pidToTimeToProcessMemoryDump=tr.b.invertArrayOfDicts(timeToPidToProce [...]
+return;sizes[cellName]=new ScalarNumeric(sizeInBytes_smallerIsBetter,total);});var platformSpecific=totals.platformSpecific;if(platformSpecific!==undefined){tr.b.iterItems(platformSpecific,function(name,size){if(name.endsWith(PLATFORM_SPECIFIC_TOTAL_NAME_SUFFIX)){name=name.substring(0,name.length-
+PLATFORM_SPECIFIC_TOTAL_NAME_SUFFIX.length);}
+name=name.replace('_',' ').trim();name=name.charAt(0).toUpperCase()+name.slice(1);sizes[name]=new ScalarNumeric(sizeInBytes_smallerIsBetter,size);});}}
+var vmRegions=dump.mostRecentVmRegions;if(vmRegions!==undefined){tr.b.iterItems(UsedMemoryColumn.BYTE_STAT_MAP,function(byteStatName,cellName){var byteStat=vmRegions.byteStats[byteStatName];if(byteStat===undefined)
+return;sizes[cellName]=new ScalarNumeric(sizeInBytes_smallerIsBetter,byteStat);});}
+return sizes;});var allocatorCells=tr.ui.analysis.createCells(timeToDump,function(dump){var memoryAllocatorDumps=dump.memoryAllocatorDumps;if(memoryAllocatorDumps===undefined)
+return undefined;var sizes={};memoryAllocatorDumps.forEach(function(allocatorDump){var rootDisplayedSizeNumeric=allocatorDump.numerics[DISPLAYED_SIZE_NUMERIC_NAME];if(rootDisplayedSizeNumeric!==undefined)
+sizes[allocatorDump.fullName]=rootDisplayedSizeNumeric;});return sizes;});return{title:process.userFriendlyName,contexts:timeToDump,usedMemoryCells:usedMemoryCells,allocatorCells:allocatorCells};}));},createFooterRows_:function(rows,columns){if(rows.length<=1)
+return[];var totalRow={title:'Total'};tr.ui.analysis.aggregateTableRowCells(totalRow,rows,columns);return[totalRow];},createColumns_:function(rows){var titleColumn=new ProcessNameColumn();titleColumn.width='200px';var usedMemorySizeColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'usedMemoryCells',this.aggregationMode_,UsedMemoryColumn.RULES);var allocatorSizeColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'allocatorCells',this.aggregationMode_,AllocatorColumn.RULES);var sizeColumns=u [...]
+selectedRowTitle=selectedRow.title;var selectedColumnName;var selectedColumnIndex=this.$.table.selectedColumnIndex;if(selectedColumnIndex!==undefined){var selectedColumn=this.$.table.tableColumns[selectedColumnIndex];selectedColumnName=selectedColumn.name;}
+this.$.state.set({rowTitle:selectedRowTitle,columnName:selectedColumnName});},restoreSelection_:function(){var settings=this.$.state.get();if(settings===undefined||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;}});return{ProcessNameColumn:ProcessNameColumn,UsedMemoryColumn:UsedMemoryColumn,PeakMemoryColumn:PeakMemoryColumn,ByteStatColumn:ByteStatColumn,AllocatorColumn:AllocatorColumn,TracingColumn:TracingColumn};});'use strict';tr.exportTo('tr.ui.analysis',function(){Polymer('tr-ui-a-memory-dump-header-pane',{created:function(){this.containerMemoryDumps_=undefined;},ready:function(){this.$.agg [...]
+var containerDumpCount=this.containerMemoryDumps_.length;var isMultiSelection=containerDumpCount>1;this.$.label.appendChild(document.createTextNode('Selected '+containerDumpCount+' memory dump'+
+(isMultiSelection?'s':'')+' in '+this.containerMemoryDumps_[0].containerName+' at '));this.$.label.appendChild(document.createTextNode(tr.v.Unit.byName.timeStampInMs.format(this.containerMemoryDumps_[0].start)));if(isMultiSelection){var ELLIPSIS=String.fromCharCode(8230);this.$.label.appendChild(document.createTextNode(ELLIPSIS));this.$.label.appendChild(document.createTextNode(tr.v.Unit.byName.timeStampInMs.format(this.containerMemoryDumps_[containerDumpCount-1].start)));}},updateAggreg [...]
+displayStyle='none';else
+displayStyle='initial';this.$.aggregation_mode_container.style.display=displayStyle;},changeChildPane_:function(){this.childPaneBuilder=function(){if(this.containerMemoryDumps_===undefined||this.containerMemoryDumps_.length<=0)
+return undefined;var overviewPane=document.createElement('tr-ui-a-memory-dump-overview-pane');overviewPane.processMemoryDumps=this.containerMemoryDumps_.map(function(containerDump){return containerDump.processMemoryDumps;});overviewPane.aggregationMode=this.aggregationMode;return overviewPane;}.bind(this);}});return{};});'use strict';Polymer('tr-ui-a-stacked-pane-view',{setPaneBuilder:function(paneBuilder,opt_parentPane){var paneContainer=this.$.pane_container;if(opt_parentPane){if(!(opt [...]
+throw new Error('Parent pane must be an HTML element');if(opt_parentPane.parentElement!==paneContainer)
+throw new Error('Parent pane must be a child of the pane container');}
+while(paneContainer.lastElementChild!==null&&paneContainer.lastElementChild!==opt_parentPane){var removedPane=this.$.pane_container.lastElementChild;var listener=this.listeners_.get(removedPane);if(listener===undefined)
+throw new Error('No listener associated with pane');this.listeners_.delete(removedPane);removedPane.removeEventListener('request-child-pane-change',listener);paneContainer.removeChild(removedPane);}
+if(opt_parentPane&&opt_parentPane.parentElement!==paneContainer)
+throw new Error('Parent pane was removed from the pane container');if(!paneBuilder)
+return;var pane=paneBuilder();if(!pane)
+return;if(!(pane instanceof HTMLElement))
+throw new Error('Pane must be an HTML element');var listener=function(event){this.setPaneBuilder(pane.childPaneBuilder,pane);}.bind(this);if(!this.listeners_){this.listeners_=new WeakMap();}
+this.listeners_.set(pane,listener);pane.addEventListener('request-child-pane-change',listener);paneContainer.appendChild(pane);pane.appended();},rebuild:function(){var currentPane=this.$.pane_container.firstElementChild;while(currentPane){currentPane.rebuild();currentPane=currentPane.nextElementSibling;}},get panesForTesting(){var panes=[];var currentChild=this.$.pane_container.firstElementChild;while(currentChild){panes.push(currentChild);currentChild=currentChild.nextElementSibling;}
+return panes;}});'use strict';tr.exportTo('tr.ui.analysis',function(){Polymer('tr-ui-a-container-memory-dump-sub-view',{set selection(selection){if(selection===undefined){this.currentSelection_=undefined;this.dumpsByContainerName_=undefined;this.updateContents_();return;}
+selection.forEach(function(event){if(!(event instanceof tr.model.ContainerMemoryDump)){throw new Error('Memory dump sub-view only supports container memory dumps');}});this.currentSelection_=selection;this.dumpsByContainerName_=tr.b.group(this.currentSelection_.toArray(),function(dump){return dump.containerName;});tr.b.iterItems(this.dumpsByContainerName_,function(containerName,dumps){dumps.sort(function(a,b){return a.start-b.start;});});this.updateContents_();},get selection(){return th [...]
+return;var containerNames=Object.keys(this.dumpsByContainerName_);if(containerNames.length===0)
+return;if(containerNames.length>1)
+this.buildViewForMultipleContainerNames_();else
+this.buildViewForSingleContainerName_();},buildViewForSingleContainerName_:function(){var containerMemoryDumps=tr.b.dictionaryValues(this.dumpsByContainerName_)[0];var dumpView=this.ownerDocument.createElement('tr-ui-a-stacked-pane-view');this.$.content.appendChild(dumpView);dumpView.setPaneBuilder(function(){var headerPane=document.createElement('tr-ui-a-memory-dump-header-pane');headerPane.containerMemoryDumps=containerMemoryDumps;return headerPane;});},buildViewForMultipleContainerNam [...]
+return this.singleDumpValue_(row);else
+return this.groupedDumpValue_(row);},singleDumpValue_:function(row){var linkEl=ownerDocument.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(new tr.model.EventSet([row]));linkEl.appendChild(tr.v.ui.createScalarSpan(row.start,{unit:tr.v.Unit.byName.timeStampInMs,ownerDocument:ownerDocument}));return linkEl;},groupedDumpValue_:function(row){var linkEl=ownerDocument.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(new tr.model.EventSet(row.subRows)); [...]
+(row.subRows.length===1?'':'s')+' in '}));linkEl.appendChild(tr.ui.b.createSpan({ownerDocument:ownerDocument,textContent:row.containerName,bold:true}));return linkEl;}}];var table=this.ownerDocument.createElement('tr-ui-b-table');table.tableColumns=columns;table.tableRows=rows;table.showHeader=false;table.rebuild();this.$.content.appendChild(table);}});return{};});'use strict';(function(){var COUNTER_SAMPLE_TABLE_COLUMNS=[{title:'Counter',width:'150px',value:function(row){return row.coun [...]
+rows.push(seriesRows[0]);},this);},this);return rows;},getRowsForSamples_:function(samples){return samples.map(function(sample){return{start:sample.timestamp,value:sample.value};});}});})();'use strict';tr.exportTo('tr.ui.analysis',function(){Polymer('tr-ui-a-layout-tree-sub-view',{set selection(selection){this.currentSelection_=selection;this.updateContents_();},get selection(){return this.currentSelection_;},updateContents_:function(){this.$.content.textContent='';if(!this.currentSelection_)
+return;var columns=[{title:'Tag/Name',value:function(layoutObject){return layoutObject.tag||':'+layoutObject.name;}},{title:'htmlId',value:function(layoutObject){return layoutObject.htmlId||'';}},{title:'classNames',value:function(layoutObject){return layoutObject.classNames||'';}},{title:'reasons',value:function(layoutObject){return layoutObject.needsLayoutReasons.join(', ');}},{title:'width',value:function(layoutObject){return layoutObject.absoluteRect.width;}},{title:'height',value:fu [...]
+return'';return layoutObject.tableRow;}},{title:'col',value:function(layoutObject){if(layoutObject.tableCol===undefined)
+return'';return layoutObject.tableCol;}},{title:'rowSpan',value:function(layoutObject){if(layoutObject.tableRowSpan===undefined)
+return'';return layoutObject.tableRowSpan;}},{title:'colSpan',value:function(layoutObject){if(layoutObject.tableColSpan===undefined)
+return'';return layoutObject.tableColSpan;}},{title:'address',value:function(layoutObject){return layoutObject.id.toString(16);}}];var table=this.ownerDocument.createElement('tr-ui-b-table');table.defaultExpansionStateCallback=function(layoutObject,parentLayoutObject){return true;};table.subRowsPropertyName='childLayoutObjects';table.tableColumns=columns;table.tableRows=this.currentSelection_.map(function(snapshot){return snapshot.rootLayoutObject;});table.rebuild();this.$.content.append [...]
 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= [...]
+hasRange=false;rows.push({title:'Selection start',value:hasRange?tr.v.ui.createScalarSpan(selection.bounds.min,{unit:tr.v.Unit.byName.timeStampInMs,ownerDocument:this.ownerDocument}):'<empty>'});rows.push({title:'Selection extent',value:hasRange?tr.v.ui.createScalarSpan(selection.bounds.range,{unit:tr.v.Unit.byName.timeDurationInMs,ownerDocument:this.ownerDocument}):'<empty>'});this.$.table.tableRows=rows;this.$.table.rebuild();}});'use strict';tr.exportTo('tr.ui.analysis',function(){fun [...]
+this.totalsRow=true;this.title_=title;},get title(){return this.title_;},get duration(){if(this.duration_===undefined){this.duration_=tr.b.Statistics.sum(this.events_,function(event){return event.duration;});}
 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 this.numAlerts_;},get untotallableArgs(){this.updateArgsIfNeeded_();return this.untotallableArgs_;},get totalledArgs(){this.updateArgsIfNeeded_();return this.totalledArgs_;},get maxDuration(){if(this.maxDuration_===undefined){this.maxDuration_=tr.b.Statistics.max(this.events_,function(event){return event.duration;});}
+return this.maxDuration_;},get maxCpuDuration(){if(this.maxCpuDuration_===undefined){this.maxCpuDuration_=tr.b.Statistics.max(this.events_,function(event){return event.cpuDuration;});}
+return this.maxCpuDuration_;},get maxSelfTime(){if(this.maxSelfTime_===undefined){this.maxSelfTime_=tr.b.Statistics.max(this.events_,function(event){return event.selfTime;});}
+return this.maxSelfTime_;},get maxCpuSelfTime(){if(this.maxCpuSelfTime_===undefined){this.maxCpuSelfTime_=tr.b.Statistics.max(this.events_,function(event){return event.cpuSelfTime;});}
+return this.maxCpuSelfTime_;},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)
+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,maxValues){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;}});}
+hasAlerts=true;});var ownerDocument=this.ownerDocument;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.model.EventSet(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',value:function(row){return tr.v.ui.createScalarSpan(row.duration,{unit:tr.v.Unit.byName.timeDurationInMs,total:row.totalsRow?undefined:maxValues.duration,ow [...]
+if(this.eventsHaveDuration_&&hasCpuData){columns.push({title:'CPU Duration',value:function(row){return tr.v.ui.createScalarSpan(row.cpuDuration,{unit:tr.v.Unit.byName.timeDurationInMs,total:row.totalsRow?undefined:maxValues.cpuDuration,ownerDocument:ownerDocument,rightAlign:true});},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.cpuDuration-rowB.cpuDuration;}});}
+if(this.eventsHaveSubRows_&&this.eventsHaveDuration_){columns.push({title:'Self time',value:function(row){return tr.v.ui.createScalarSpan(row.selfTime,{unit:tr.v.Unit.byName.timeDurationInMs,total:row.totalsRow?undefined:maxValues.selfTime,ownerDocument:ownerDocument,rightAlign:true});},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',value:function(row){return tr.v.ui.createScalarSpan(row.cpuSelfTime,{unit:tr.v.Unit.byName.timeDurationInMs,total:row.totalsRow?undefined:maxValues.cpuSelfTime,ownerDocument:ownerDocument,rightAlign:true});},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
@@ -2785,22 +7031,23 @@ 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 [...]
+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 maxValues={duration:undefined,selfTime:undefined,cpuSelfTime:undefined,cpuDuration:undefined};if(this.eventsHaveDuration){for(var column in maxValues){maxValues[column]=tr.b.St [...]
+var footerRows=[];if(this.showTotals_){var multiEventSummary=new tr.ui.analysis.MultiEventSummary('Totals',allEvents);footerRows.push(multiEventSummary);}
+this.updateTableColumns_(rows,maxValues);this.$.table.tableRows=rows;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.upda [...]
 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;}});}
+colWidthPercentage='33.3333%';var ownerDocument=this.ownerDocument;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.model.EventSet(row.event);});linkEl.appendChild(tr.v.ui.createScalarSpan(row.start,{unit:tr.v.Unit.byName.timeStampInMs,ownerDocument:ownerDocument}));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.v.ui.createScalarSpan(row.duration,{unit [...]
+if(this.eventsHaveDuration_&&hasCpuData){columns.push({title:'CPU Duration (ms)',value:function(row){return tr.v.ui.createScalarSpan(row.cpuDuration,{unit:tr.v.Unit.byName.timeDurationInMs,ownerDocument:ownerDocument});},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.v.ui.createScalarSpan(row.selfTime,{unit:tr.v.Unit.byName.timeDurationInMs,ownerDocument:ownerDocument});},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.v.ui.createScalarSpan(row.cpuSelfTime,{unit:tr.v.Unit.byName.timeDurationInMs,ownerDocument:ownerDocument});},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];}}
+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>'});}
@@ -2810,80 +7057,76 @@ colWidthPercentage=(100/(columns.length-1)).toFixed(3)+'%';for(var i=1;i<columns
 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;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 [...]
+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.model.EventSet();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.model.EventSet();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.model.EventSet();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.cancelFunctions_=[];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);},setRelatedEvents:function(eventSet){this.cancelAllTasks_();this.eventGroups_=[];this.addConnectedFlows_(eventSet);this.addConnectedEvents_(eventSet);this.addOverlappingSamples_(eventSet);this.updateContents_();},addConnectedFlows_:function(eventSet){var classifier=new tr.ui.analysis.FlowClassifier();eventSet.forEach(function(slice){if(slice.inFlowEvents){ [...]
+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.model.EventSet(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'));},cancelAllTasks_:function(){this.cancelFunctions_.forEach(function(cancelFunction){cancelFunction( [...]
+events.push(event.startSlice);}.bind(this)));this.cancelFunctions_.push(this.createEventsLinkIfNeeded_('Following events','Add all events that have been caused by the selected one(s), '+'connected by flow arrows or by call stack.',eventSet,function(event,events){this.addOutFlowEvents_(event,events);this.addDescendents_(event,events);if(event.endSlice)
+events.push(event.endSlice);}.bind(this)));this.cancelFunctions_.push(this.createEventsLinkIfNeeded_('All connected events','Add all events connected to the selected one(s) by flow arrows or '+'by call stack.',eventSet,function(event,events){this.addInFlowEvents_(event,events);this.addOutFlowEvents_(event,events);this.addAncestors_(event,events);this.addDescendents_(event,events);if(event.startSlice)
+events.push(event.startSlice);if(event.endSlice)
+events.push(event.endSlice);}.bind(this)));},createEventsLinkIfNeeded_:function(title,tooltip,events,addFunction){events=new tr.model.EventSet(events);var lengthBefore=events.length;var task;var isCanceled=false;function addEventsUntilTimeout(startingIndex){if(isCanceled)
+return;var startingTime=window.performance.now();while(startingIndex<events.length){addFunction(events[startingIndex],events);startingIndex++;if(window.performance.now()-startingTime>8){var newTask=new tr.b.Task(addEventsUntilTimeout.bind(this,startingIndex),this);task.after(newTask);task=newTask;return;}}
+if(lengthBefore===events.length)
+return;this.eventGroups_.push({type:title,tooltip:tooltip,selection:events});this.updateContents_();};function cancelTask(){isCanceled=true;}
+task=new tr.b.Task(addEventsUntilTimeout.bind(this,0),this);tr.b.Task.RunWhenIdle(task);return cancelTask;},addInFlowEvents_:function(event,eventSet){if(!event.inFlowEvents)
+return;event.inFlowEvents.forEach(function(e){eventSet.push(e);});},addOutFlowEvents_:function(event,eventSet){if(!event.outFlowEvents)
+return;event.outFlowEvents.forEach(function(e){eventSet.push(e);});},addAncestors_:function(event,eventSet){if(!event.iterateAllAncestors)
+return;event.iterateAllAncestors(function(e){eventSet.push(e);});},addDescendents_:function(event,eventSet){if(!event.iterateAllDescendents)
+return;event.iterateAllDescendents(function(e){eventSet.push(e);});},addOverlappingSamples_:function(eventSet){var samples=new tr.model.EventSet;eventSet.forEach(function(slice){if(!slice.parentContainer||!slice.parentContainer.samples)
+return;var candidates=slice.parentContainer.samples;var range=tr.b.Range.fromExplicitRange(slice.start,slice.start+slice.duration);var filteredSamples=range.filterArray(candidates,function(value){return value.start;});filteredSamples.forEach(function(sample){samples.push(sample);});}.bind(this));if(samples.length>0){this.eventGroups_.push({type:'Overlapping samples',tooltip:'All samples overlapping the selected slice(s).',selection:samples});}},updateContents_:function(){var table=this.$ [...]
+table.tableRows=[];else
+table.tableRows=this.eventGroups_.slice();table.rebuild();}});'use strict';Polymer('tr-ui-a-multi-async-slice-sub-view',{get selection(){return this.$.content.selection;},set selection(selection){this.$.content.selection=selection;this.$.relatedEvents.setRelatedEvents(selection);if(this.$.relatedEvents.hasRelatedEvents()){this.$.relatedEvents.style.display='';}else{this.$.relatedEvents.style.display='none';}},get relatedEventsToHighlight(){if(!this.$.content.selection)
+return undefined;var selection=new tr.model.EventSet();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)
+return selection;return undefined;}});'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-multi-flow-event-sub-view',{ready:function(){this.$.content.eventsHaveDuration=false;this.$.content.eventsHaveSubRows=false;},set selection(selection){this.$.content.selecti [...]
+return undefined;var selection=new tr.model.EventSet();this.currentSelection_.forEach(function(frameEvent){frameEvent.associatedEvents.forEach(function(event){selection.push(event);});});return selection;}});'use strict';Polymer('tr-ui-a-multi-instant-event-sub-view',{created:function(){this.currentSelection_=undefined;},set selection(selection){this.$.content.textContent='';var realView=document.createElement('tr-ui-a-multi-event-sub-view');realView.eventsHaveDuration=false;realView.eve [...]
+return tr.v.ui.createScalarSpan(event.ts,timeSpanConfig);var spanEl=document.createElement('span');spanEl.appendChild(tr.v.ui.createScalarSpan(event.creationTs,timeSpanConfig));spanEl.appendChild(tr.ui.b.createSpan({textContent:'-',marginLeft:'4px',marginRight:'4px'}));if(event.deletionTs!=Number.MAX_VALUE){spanEl.appendChild(tr.v.ui.createScalarSpan(event.deletionTs,timeSpanConfig));}
+return spanEl;},width:'200px'},{title:'Second',value:function(event){var linkEl=document.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(function(){return new tr.model.EventSet(event);},event.userFriendlyName);return linkEl;},width:'100%'}];table.tableRows=objectEvents;table.rebuild();}});'use strict';var EventSet=tr.model.EventSet;var CHART_TITLE='Power (W) by ms since vertical sync';var CHART_WIDTH_FRACTION_OF_BODY=0.5;Polymer('tr-ui-a-frame-power-usage-chart',{rea [...]
+return;this.chart_=this.createChart_(data);this.$.content.appendChild(this.chart_);},createChart_:function(data){var chart=new tr.ui.b.LineChart();var width=document.body.clientWidth*CHART_WIDTH_FRACTION_OF_BODY;chart.setSize({width:width,height:chart.height});chart.chartTitle=CHART_TITLE;chart.data=data;return chart;},clearChart_:function(){var content=this.$.content;while(content.firstChild)
+content.removeChild(content.firstChild);this.chart_=undefined;},getDataForLineChart_:function(){var sortedSamples=this.sortSamplesByTimestampAscending_(this.samples);var vSyncTimestamps=this.vSyncTimestamps.slice();var lastVSyncTimestamp=undefined;var points=[];var frameNumber=0;sortedSamples.forEach(function(sample){while(vSyncTimestamps.length>0&&vSyncTimestamps[0]<=sample.start){lastVSyncTimestamp=vSyncTimestamps.shift();frameNumber++;}
+if(lastVSyncTimestamp===undefined)
+return;var point={x:sample.start-lastVSyncTimestamp};point['f'+frameNumber]=sample.power/1000;points.push(point);});return points;},sortSamplesByTimestampAscending_:function(samples){return samples.toArray().sort(function(smpl1,smpl2){return smpl1.start-smpl2.start;});}});'use strict';Polymer('tr-ui-a-power-sample-summary-table',{ready:function(){this.$.table.tableColumns=[{title:'Min power',width:'100px',value:function(row){return tr.v.Unit.byName.powerInWatts.format(row.min/1000.0);}}, [...]
+return;this.samples_=(samples===undefined)?new tr.model.EventSet():samples;this.updateContents_();},updateContents_:function(){if(this.samples.length===0){this.$.table.tableRows=[];}else{this.$.table.tableRows=[{min:this.getMin(),max:this.getMax(),timeWeightedAverage:this.getTimeWeightedAverage(),energyConsumed:this.getEnergyConsumed(),sampleCount:this.samples.length}];}
+this.$.table.rebuild();},getMin:function(){return Math.min.apply(null,this.samples.map(function(sample){return sample.power;}));},getMax:function(){return Math.max.apply(null,this.samples.map(function(sample){return sample.power;}));},getTimeWeightedAverage:function(){var energyConsumed=this.getEnergyConsumed();if(energyConsumed==='N/A')
+return'N/A';var energyInMillijoules=this.getEnergyConsumed()*1000;var durationInSeconds=this.samples.bounds.duration/1000;return energyInMillijoules/durationInSeconds;},getEnergyConsumed:function(){if(this.samples.length<2)
+return'N/A';var bounds=this.samples.bounds;return this.samples[0].series.getEnergyConsumed(bounds.min,bounds.max);}});'use strict';var EventSet=tr.model.EventSet;Polymer('tr-ui-a-power-sample-table',{ready:function(){this.$.table.tableColumns=[{title:'Time',width:'100px',value:function(row){return tr.v.ui.createScalarSpan(row.start,{unit:tr.v.Unit.byName.timeStampInMs});}},{title:'Power',width:'100%',value:function(row){return tr.v.ui.createScalarSpan(row.power/1000,{unit:tr.v.Unit.byNam [...]
+return false;var arr=title.split(SAMPLE_TYPE.NATIVEV8);row.functionName=arr[0].trim();if(row.functionName==='')
+row.functionName='(anonymous function)';row.fileName=SAMPLE_TYPE.NATIVEV8;var fileNameSuffix=arr[1].trim();if(fileNameSuffix!=='')
+row.fileName+=' '+fileNameSuffix;return true;},processGeneralSampleRow_:function(row){var title=row.title[0];var idx=title.lastIndexOf(' ');if(idx===-1){row.functionName=title;row.fileName='unknown';return;}
+var prefix=title.substr(0,idx);var suffix=title.substr(idx+1);if(suffix.startsWith('v8/')){row.functionName=suffix;row.fileName='unknown';}else if(suffix===''){row.functionName=prefix;row.fileName='unknown';}else if(prefix===''){row.functionName='(anonymous function)';row.fileName=suffix.substr(suffix.lastIndexOf('/')+1);}else{row.functionName=prefix;row.fileName=suffix.substr(suffix.lastIndexOf('/')+1);}},processSampleRows_:function(rows){rows.forEach(function(row){if(!this.processTyped [...]
+this.processGeneralSampleRow_(row);this.processSampleRows_(row.subRows);},this);},updateContents_:function(){if(this.selection===undefined){this.$.table.tableColumns=[];this.$.table.tableRows=[];this.$.table.rebuild();return;}
+var samplingData=this.createSamplingSummary_(this.selection,this.viewOption);var columns=[this.createPercentColumn_('Total',samplingData.total),this.createSamplesColumn_('Total'),this.createPercentColumn_('Self',samplingData.total),this.createSamplesColumn_('Self'),{title:'Function Name',value:function(row){return row.functionName;},width:'150px',cmp:function(a,b){return a.functionName.localeCompare(b.functionName);},showExpandButtons:true},{title:'Location',value:function(row){return ro [...]
+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.setRelatedEvents(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-multi-thread-time-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-user-expectation-related-samples-table',{ready:function(){this.samples_=[];this.$.table.tableColumns=[{title:'Event(s)',value:function(row){var typeEl=document.createElement( [...]
+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;}}];},hasRelatedSamples:function(){return(this.samples_&&this.samples_.length>0);},set selection(eventSet){this.samples_=[];var samples=new tr.model.EventSet;eventSet.forEach(function(ue){samples.addEventSet(ue.associatedSamples);}.bind(this));if(samples.length>0){this.samples_.push({type:'Overlapping samples',tooltip:'All samples overlapping the selected user expectation(s).',selection:samples});}
+this.updateContents_();},updateContents_:function(){var table=this.$.table;if(this.samples_&&this.samples_.length>0)
+table.tableRows=this.samples_.slice();else
+table.tableRows=[];table.rebuild();}});'use strict';Polymer('tr-ui-a-multi-user-expectation-sub-view',{created:function(){this.currentSelection_=undefined;},set selection(selection){this.currentSelection_=selection;this.$.realView.setSelectionWithoutErrorChecks(selection);this.currentSelection_=selection;this.$.relatedSamples.selection=selection;if(this.$.relatedSamples.hasRelatedSamples())
+this.$.events.style.display='';else
+this.$.events.style.display='none';},get selection(){return this.currentSelection_;},get relatedEventsToHighlight(){if(!this.currentSelection_)
+return undefined;var selection=new tr.model.EventSet();this.currentSelection_.forEach(function(ir){ir.associatedEvents.forEach(function(event){selection.push(event);});});return selection;}});'use strict';Polymer('tr-ui-a-single-async-slice-sub-view',{get selection(){return this.$.content.selection;},set selection(selection){if(selection.length!==1)
+throw new Error('Only supports single slices');this.$.content.setSelectionWithoutErrorChecks(selection);this.$.relatedEvents.setRelatedEvents(selection);if(this.$.relatedEvents.hasRelatedEvents()){this.$.relatedEvents.style.display='';}else{this.$.relatedEvents.style.display='none';}},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-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 [...]
+shadowRoot.querySelector('#start').setValueAndUnit(cpuSlice.start,tr.v.Unit.byName.timeStampInMs);shadowRoot.querySelector('#duration').setValueAndUnit(cpuSlice.duration,tr.v.Unit.byName.timeDurationInMs);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.model.EventS [...]
+shadowRoot.querySelector('#args').object=cpuSlice.args;}});'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.setSelectionAndContent(function(){return new tr.model.EventSet(slice);});linkEl.textContent=slice.userFriendlyName;return linkEl;}
+rows.push({name:'From',value:createLinkTo(event.startSlice)});rows.push({name:'To',value:createLinkTo(event.endSlice)});return rows;}});'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-single-instant-event-sub-view',{created:function(){this.currentSelection_=undefined;},set selection(selection){this.$.content.textContent='';var realView=document.createElement('tr-ui-a-single-event-sub-view');realView.setSelectionWithoutErrorChecks(selection);this.$.content.appendChild(realView);this.currentSelection_=selection;},get selection(){return this.currentSelection_;}});'use str [...]
 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)
@@ -2893,256 +7136,93 @@ 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'); [...]
+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.model.EventSet(snapshot);snapshotsEl.appendChild(snapshotLink);});}});'use strict';Polymer('tr-ui-a-single-object-snapshot-sub-view',{created:function(){this.currentSelection_=undefi [...]
 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 [...]
+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 [...]
+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.v.ui.createScalarSpan(sample.start,{unit:tr.v.Unit.byName.timeStampInMs,ownerDocument:this.ownerDocument})});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-single-thread-s [...]
+this.$.relatedEvents.style.display='';else
+this.$.relatedEvents.style.display='none';}});'use strict';Polymer('tr-ui-a-single-thread-time-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.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.b.ColorScheme.colorsAsStrings[timeSlice.colorId];shadowRoot.querySelector('#state').style.backgroundColor=stateColor;shadowRoot.querySelector('#process-name').textContent=thread.parent.userFriendlyName;shadowRoot.querySelector('#thread-name [...]
+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';tr.exportTo('tr.metrics',function(){function ValueList(values){this.values_=[];if(values!==undefined)
+values.forEach(this.addValue,this);}
+ValueList.prototype={get valueDicts(){return this.values_.map(function(v){return v.asDict();});},getValuesWithName:function(name){return this.values_.filter(function(value){return value.name.indexOf(name)>-1;});},addValue:function(v){if(!(v instanceof tr.v.NumericValue)){var err=new Error('Tried to add value '+v+' which is non-Numeric');err.name='ValueError';throw err;}
+this.values_.push(v);if(v.numeric instanceof tr.v.Numeric){this.values_.push.apply(this.values_,ValueList.computeSummaryValuesForNumericValue(v));}}};ValueList.computeSummaryValuesForNumericValue=function(value){if(!(value instanceof tr.v.NumericValue&&value.numeric instanceof tr.v.Numeric))
+throw new Error('Tried to compute summary values for non-numeric');var canonicalUrl=value.canonicalUrl;var name=value.name;var n=value.numeric;var description=value.description;var sumNumeric=new tr.v.ScalarNumeric(n.unit,n.runningSum);var countNumeric=new tr.v.ScalarNumeric(tr.v.Unit.byName.unitlessNumber_smallerIsBetter,n.numValues);var avgNumeric=new tr.v.ScalarNumeric(n.unit,n.average);return[new tr.v.NumericValue(canonicalUrl,name+'_sum',sumNumeric,{description:description}),new tr. [...]
+this.$.events.style.display='';else
+this.$.events.style.display='none';},get relatedEventsToHighlight(){if(!this.currentSelection_)
+return undefined;return this.currentSelection_[0].associatedEvents;},onCustomizeRows_:function(event){var ue=this.selection[0];var valueList=new tr.metrics.ValueList();function runMetric(metricInfo){try{metricInfo.constructor(valueList,ue.parentModel);}catch(failure){console.error(metricInfo,failure);}}
+tr.metrics.MetricRegistry.getAllRegisteredTypeInfos().forEach(runMetric);var metricValues={};valueList.valueDicts.forEach(function(value){if(value.grouping_keys.userExpectationStableId!==ue.stableId)
+return;if((value.type!=='numeric')||(value.numeric.type!=='scalar'))
+return;metricValues[value.grouping_keys.name]=value.numeric;});for(var name in metricValues){event.rows.push({name:name,value:tr.v.ui.createScalarSpan(metricValues[name].value,{unit:tr.v.Unit.fromJSON(metricValues[name].unit)})});}
+if(ue.rawCpuMs){event.rows.push({name:'Total CPU',value:tr.v.ui.createScalarSpan(ue.totalCpuMs,{unit:tr.v.Unit.byName.timeDurationInMs})});}}});'use strict';Polymer('tr-ui-a-tab-view',{ready:function(){this.$.tshh.style.display='none';this.tabs_=[];this.selectedTab_=undefined;for(var i=0;i<this.children.length;i++)
+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)
+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');},get tabs(){return this.tabs_.map(function(tabObject){return tabObject.content;});},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,forAttri [...]
+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']});},saveTabStates:function(){this.saveCurrentTabScrollPosition_();},saveCurrentTabScrollPosition_:function(){if(this.selectedTab_){this.selectedTab_.conte [...]
 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)
+this.classList.remove('tall-mode');},get tallMode(){return this.classList.contains('tall-mode');},get tabView(){return this.tabView_;},get brushingStateController(){return this.brushingStateController_;},set brushingStateController(brushingStateController){if(this.brushingStateController){this.brushingStateController_.removeEventListener('change',this.onSelectionChanged_);}
+this.brushingStateController_=brushingStateController;if(this.brushingStateController){this.brushingStateController_.addEventListener('change',this.onSelectionChanged_);}
+this.onSelectionChanged_();},get selection(){return this.brushingStateController_.selection;},onSelectionChanged_:function(e){var selection=this.brushingStateController_.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;}
+this.tallMode=false;var previouslySelectedTab=this.tabView_.selectedTab;this.tabView_.removeEventListener('selected-tab-change',this.onSelectedTabChange_);var previousSubViews={};for(var i=0;i<this.tabView_.children.length;i++){var previousSubView=this.tabView_.children[i];previousSubViews[previousSubView._eventTypeName]=previousSubView;}
+this.tabView_.saveTabStates();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,previousSubViews[eventTypeName]);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)
+tab=this.tabView_.firstChild;this.tabView_.selectedTab=tab;this.onSelectedTabChange_();this.tabView_.addEventListener('selected-tab-change',this.onSelectedTabChange_);},createSubViewForSelection_:function(eventTypeName,subSelection,previousSubView){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)
+throw new Error('Element not registered: '+tagName);var subView;if(previousSubView&&previousSubView.tagName===tagName.toUpperCase())
+subView=previousSubView;else
+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 [...]
+camelLabel=EventRegistry.getUserFriendlyPluralName(eventTypeName);subView.tabLabel=camelLabel+' ('+subSelection.length+')';return subView;},onSelectedTabChange_:function(){var brushingStateController=this.brushingStateController_;if(this.tabView_.selectedTab){var selectedTab=this.tabView_.selectedTab;this.tallMode=selectedTab.requiresTallView;if(brushingStateController){var rlth=selectedTab.relatedEventsToHighlight;brushingStateController.changeAnalysisViewRelatedEvents(rlth);}}else{this [...]
+brushingStateController.changeAnalysisViewRelatedEvents(undefined);}}});})();'use strict';Polymer('tr-ui-b-dropdown',{ready:function(){this.$.outer.tabIndex=0;},get iconElement(){return this.$.icon;},onOuterKeyDown_:function(e){if(e.keyCode===' '.charCodeAt(0)){this.toggle_();e.preventDefault();e.stopPropagation();}},onOuterClick_:function(e){var or=this.$.outer.getBoundingClientRect();var inside=true;inside&=e.clientX>=or.left;inside&=e.clientX<or.right;inside&=e.clientY>=or.top;inside& [...]
+return;e.preventDefault();this.toggle_();},toggle_:function(){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;if(e.srcElement!==this.$.dialog)
+return;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');this.$.outer.focus();},get isOpen(){return this.$.dialog.hasAttribute('open');}});'use strict';tr.exportTo('tr.ui.b',function(){var FaviconsByHue={blue:'data:image/vndmicrosofticon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjj8xAGArIgqOPzE8nUY3dqJJOJeiSTiXnUY3do4/MTxhKyIKjkAxAAAAAAAAAAAAAAAAAAAAAABQJBwAAAAAAZJBMzSoSzqlsU8+6bRQP/21UT//tVE// [...]
+throw new Error('buttonText must be provided');if(opt_buttons[i].onClick===undefined)
+throw new Error('onClick must be provided');}
+this.messages_.push({text:text,buttons:opt_buttons||[]});this.updateContents_();},updateContents_:function(){this.$.messages.textContent='';this.messages_.forEach(function(message){var bar=document.createElement('tr-ui-b-info-bar');bar.message=message.text;bar.visible=true;message.buttons.forEach(function(button){bar.addButton(button.buttonText,button.onClick);},this);this.$.messages.appendChild(bar);},this);}});'use strict';tr.exportTo('tr.ui',function(){var Task=tr.b.Task;function Find [...]
 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));}}
+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.brushingStateController_;if(!sc)
+return;this.enqueueOperation_(function(){this.filterHits_=new tr.model.EventSet();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.FullTextFilter(filterText);var filterHits=new tr.model.EventSet();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  [...]
+this.currentHitIndex_=0;var N=this.filterHits.length;this.currentHitIndex_=(this.currentHitIndex_+dir+N)%N;if(!this.brushingStateController_)
+return;this.brushingStateController_.findFocusChangedTo(this.filterHits.subEventSet(this.currentHitIndex_,1));},findNext:function(){this.find_(1);},findPrevious:function(){this.find_(-1);}};return{FindController:FindController};});'use strict';tr.exportTo('tr.ui.b',function(){function TimingTool(viewport,targetElement){this.viewport_=viewport;this.onMouseMove_=this.onMouseMove_.bind(this);this.onDblClick_=this.onDblClick_.bind(this);this.targetElement_=targetElement;this.isMovingLeftEdge [...]
 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)
@@ -3160,45 +7240,49 @@ 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 [...]
+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 result;}};return{TimingTool:TimingTool};});'use strict';tr.exportTo('tr.ui',function(){var kDefaultPanAnimationDurationMs=100.0;function TimelineDisplayTransformPanAnimation(deltaX,deltaY,opt_durationMs){this.deltaX=deltaX;this.deltaY=deltaY;if(opt_durationMs===undefined)
+this.durationMs=kDefaultPanAnimationDurationMs;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=kDefaultPanAnimationDurationMs;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.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 [...]
 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';}
+tr.ui.b.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 [...]
+continue;this.children[i].addEventsToTrackMap(eventToTrackMap);}}};return{DrawingContainer:DrawingContainer,DrawType:DrawType};});'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(){var EventPresenter=tr.ui.b.EventPresenter;var SelectionState=tr.model.SelectionState;var LetterDotTrack=tr.ui.b.define('letter-dot-track',tr.ui.tracks.Track);LetterDotTrack.prototype={__proto__:tr.ui.tracks.Track.prototype,decorate:function(viewport){tr.ui.tracks.Track.prototype.decorate.call(this,viewport);this.classList.add( [...]
+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 dt=this.viewport.currentDisplayTransform;var dumpRadiusView=this.dumpRadiusView;var itemRadiusWorld=dt.xViewVectorToWorld(height);var items [...]
+break;if(item.selected!==selected)
+continue;var xView=dt.xWorldToView(x);ctx.fillStyle=EventPresenter.getSelectableItemColorAsString(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 AlertTrack=tr.ui.b.define('alert-track',tr.ui.tracks.LetterDotTrack);AlertTrack.prototype={__pr [...]
+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 Task=tr.b.Task;var ContainerTrack=tr.ui.b.define('container-track',tr.ui.tracks.Track);ContainerTrack.prototype={__proto__:tr.ui.tracks.Track.prototype,decorate:function(viewport){tr.ui.tracks.Track.prototype.decorate.call(this,viewport);},detach:function(){thi [...]
 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)
+return tracks;},drawTrack:function(type){this.tracks_.forEach(function(track){track.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)
+tr.ui.tracks.Track.prototype.addClosestEventToSelection.apply(this,arguments);},addContainersToTrackMap:function(containerToTrackMap){this.tracks_.forEach(function(track){track.addContainersToTrackMap(containerToTrackMap);});},clearTracks_:function(){this.tracks_.forEach(function(track){this.removeChild(track);},this);}};return{ContainerTrack:ContainerTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){function ChartAxis(opt_min,opt_max){this.guid_=tr.b.GUID.allocate();this.boun [...]
 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)
@@ -3207,13 +7291,7 @@ 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 [...]
+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.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 Even [...]
 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);}
@@ -3252,24 +7330,35 @@ return false;var index=tr.b.findFirstIndexInArray(this.points,function(point){re
 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 [...]
+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_={};}
+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[];var axis=new tr.ui.tracks.ChartAxis(0,undefined);var pts=this.powerSeries_.samples.map(function(smpl){return new tr.ui.tracks.ChartPoint(smpl,smpl.start,smpl.power);});var renderingConfig={chartType:tr.ui.tracks.ChartSeriesType.AREA,colorId:ColorScheme.getColorIdForGeneralPurposeString(this.heading)};return[new tr.ui.tracks.ChartSeries(pts,axis,renderingConfig)];}};return{PowerSeriesTrack:PowerSeriesTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var SpacingTrack=tr [...]
+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.numerics[DISPLAYED_SIZE_NUMERIC_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=ColorScheme.getColorIdForGeneralP [...]
+function buildMemoryLetterDots(memoryDumps){var lightMemoryColorId=ColorScheme.getColorIdForReservedName('light_memory_dump');var detailedMemoryColorId=ColorScheme.getColorIdForReservedName('detailed_memory_dump');return memoryDumps.map(function(memoryDump){var memoryColorId;switch(memoryDump.levelOfDetail){case DETAILED:memoryColorId=detailedMemoryColorId;break;case LIGHT:default:memoryColorId=lightMemoryColorId;}
+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 cumulativePss=pssBase;if(proces [...]
+cumulativePss+=vmRegions.byteStats.proportionalResident||0;}
+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=ColorScheme.getColorIdForGeneralPurposeString(process.userFriendlyName);var renderingConfig={chartType:tr.ui.tracks.ChartSeriesType.AREA,colorId:colorId,backgroundOpacity:0.8};series.push(new tr.ui.tracks.ChartSeries(points,axis, [...]
+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='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='Memory per component';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(){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 [...]
 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;}
@@ -3286,57 +7375,57 @@ 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_= [...]
+this.ephemeralSettingsByGUID_[object.guid]={};return this.ephemeralSettingsByGUID_[object.guid];}};return{ModelSettings:ModelSettings};});'use strict';tr.exportTo('tr.ui.tracks',function(){var CounterTrack=tr.ui.b.define('counter-track',tr.ui.tracks.ChartTrack);CounterTrack.prototype={__proto__:tr.ui.tracks.ChartTrack.prototype,decorate:function(viewport){tr.ui.tracks.ChartTrack.prototype.decorate.call(this,viewport);this.classList.add('counter-track');},get counter(){return this.chart;} [...]
+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.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_=undefined;this.itemsToGroup_=undefined;th [...]
 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;}
+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(i===0)
+this.children[i].arrowVisible=true;this.children[i].expanded=this.expanded;}
+if(this.children.length===1){this.children[0].expanded=true;this.children[0].arrowVisible=false;}},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 [...]
+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 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.tracks.MultiRowTrack.prototype.decorate.call(this,viewport);this.classList.add('object-instance-group-track');this.objectInstances_=undefined;},get objectInstances(){re [...]
 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 [...]
+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)
+onRect=onRect.bind(this);var instantEventWidth=2*viewPixWidthWorld;tr.b.iterateOverIntersectingIntervals(this.rects_,function(x){return x.start;},function(x){return x.duration==0?x.duration+instantEventWidth: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;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 ColorScheme=tr.b.ColorScheme;var ProcessSummaryTrack=tr.ui.b.define('process-summ [...]
 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));}
+ops.sort(function(a,b){return a.time-b.time;});var rects=[];var genericColorId=ColorScheme.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 [...]
+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 [...]
+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 SampleTrack=tr.ui.b.define('sample-track',tr.ui.tracks.RectTrack);SampleTrack.prototype={__proto__:tr.ui.tracks.RectTrack.prototype,decorate:function(viewport){tr.ui.tracks.RectTrack.prototype.decorate.call(this,viewport);},get samples(){return this.rects;},set samples(samples){this.rects=samples;}};return{SampleTrack:SampleTrack};});'use strict';tr.exportTo('tr.u [...]
 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)
@@ -3347,21 +7436,7 @@ 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 subRows;}};return{SliceGroupTrack:SliceGroupTrack};});'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.updateContents_();},get [...]
 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);}
@@ -3370,17 +7445,17 @@ this.appendChild(track);}},appendAsyncSliceTracks_:function(){var subGroups=this
 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]);}
+sampleTitle;samplesTrack.tooltip=this.thread_.userFriendlyDetails;samplesTrack.selectionGenerator=function(){var selection=new tr.model.EventSet();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.children.length>1;return true;},onHeaderClick_:function(e){e.stopPropagation();e.preventDefault();this.expanded=!this.expanded;},updateContents_:function(){this.clearTracks_();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 [...]
+return;var track=new tr.ui.tracks.FrameTrack(this.viewport);track.frames=frames;this.appendChild(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=ObjectInstanceView.getTypeInfo(un [...]
 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)
@@ -3399,56 +7474,33 @@ if(this.detailedMode_){this.appendSamplesTracks_();for(var counterName in this.c
 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 [...]
+sampleTitle;samplesTrack.tooltip=this.cpu_.userFriendlyDetails;samplesTrack.selectionGenerator=function(){var selection=new tr.model.EventSet();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 [...]
+this.appendChild(new SpacingTrack(this.viewport));}};return{KernelTrack:KernelTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var InteractionTrack=tr.ui.b.define('interaction-track',tr.ui.tracks.MultiRowTrack);InteractionTrack.prototype={__proto__:tr.ui.tracks.MultiRowTrack.prototype,decorate:function(viewport){tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this,viewport);this.heading='Interactions';this.subRows_=[];},set model(model){this.setItemsToGroup(model.userModel [...]
+return this.subRows_;this.subRows_.push.apply(this.subRows_,tr.ui.tracks.AsyncSliceGroupTrack.prototype.buildSubRows_.call({},slices,true));return this.subRows_;},addSubTrack_:function(slices){var track=new tr.ui.tracks.SliceTrack(this.viewport);track.slices=slices;this.appendChild(track);return track;}};return{InteractionTrack:InteractionTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var ALLOCATED_MEMORY_TRACK_HEIGHT=50;var ProcessMemoryDumpTrack=tr.ui.b.define('process-me [...]
 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={ [...]
+return;var track=new tr.ui.tracks.ChartTrack(this.viewport);track.heading='Memory per component';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={__proto__:Pr [...]
 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 [...]
+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){tr.ui.tracks.ProcessTrackBase.prototype.addContainersToTrackMap.apply(this,arguments);containerToTrackMap.addContainer(this.process,this);},appe [...]
+var instantEventWidth=2*viewPixWidthWorld;tr.b.iterateOverIntersectingIntervals(this.processBase.instantEvents,function(x){return x.start;},function(x){return x.duration+instantEventWidth;},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,worl [...]
 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);}
+this.updateContentsForLowerMode_();},updateContentsForUpperMode_:function(){},updateContentsForLowerMode_:function(){if(this.model_.userModel.expectations.length){var mrt=new tr.ui.tracks.InteractionTrack(this.viewport_);mrt.model=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)
+this.appendDeviceTrack_();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;var vp=this.viewport_;this.instantEvents.forEach(function(ev){eventToTrackMap.addEvent(ev,this);}.bind(this));},appendDeviceTrack_:function(){var device=this.model.device;var track=new tr.ui.tracks.DeviceTrack(this.viewport);track.device=this.model.device;if(!track.hasVisibleContent)
+return;this.appendChild(track);},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)
@@ -3465,8 +7517,8 @@ 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 [...]
+var instantEventWidth=3*viewPixWidthWorld;tr.b.iterateOverIntersectingIntervals(this.model_.instantEvents,function(x){return x.start;},function(x){return x.duration+instantEventWidth;},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,s [...]
+RulerTrack.prototype={__proto__:tr.ui.tracks.Track.prototype,decorate:function(viewport){tr.ui.tracks.Track.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_);var heading=document.createElement('tr-ui-heading');heading.arrowVisible=false;this.appendChild(heading);},det [...]
 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 [...]
@@ -3481,205 +7533,60 @@ var leftMarker=interestRange.min;var rightMarker=interestRange.max;var leftMarke
 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)
+ctx.restore();},addIntersectingEventsInRangeToSelection:function(loVX,hiVX,loY,hiY,selection){},addAllEventsMatchingFilterToSelection:function(filter,selection){}};return{RulerTrack:RulerTrack};});'use strict';Polymer('tr-ui-timeline-track-view',{ready:function(){this.displayTransform_=new tr.ui.TimelineDisplayTransform();this.model_=undefined;this.timelineView_=undefined;this.viewport_=new tr.ui.TimelineViewport(this);this.viewportDisplayTransformAtMouseDown_=undefined;this.brushingStat [...]
+this.brushingStateController_=brushingStateController;if(this.brushingStateController_){this.brushingStateController_.addEventListener('change',this.onSelectionChanged_);}},set timelineView(view){this.timelineView_=view;},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:functio [...]
+throw new Error('Model cannot be undefined');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));},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.min;range=1000;}else{min=this.model_.bounds.min;range=t [...]
+var boost=range*0.15;this.displayTransform_.set(this.viewport_.currentDisplayTransform);this.displayTransform_.xSetWorldBounds(min-boost,min+range+boost,w);this.viewport_.setDisplayTransformImmediately(this.displayTransform_);},addAllEventsMatchingFilterToSelectionAsTask:function(filter,selection){var modelTrack=this.modelTrack_;var firstT=modelTrack.addAllEventsMatchingFilterToSelectionAsTask(filter,selection);var lastT=firstT.after(function(){this.upperModelTrack_.addAllEventsMatchingF [...]
+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_();},addHotKeys_:function(){this.addKeyDownHotKeys_();this.addKeyPressHotKeys_();},addKeyPressHotKeys_:function(){var addBinding=function(dict){dict.eventType='keypress';dict.useCapture=false;dict.thisArg=this;var bi [...]
+e.preventDefault();e.stopPropagation();}});addBinding({keyCode:39,callback:function(e){var curSel=this.brushingStateController_.selection;var sel=this.viewport.getShiftedSelection(curSel,1);if(sel){this.brushingStateController.changeSelectionFromTimeline(sel);this.panToSelection();}else{this.queueSmoothPan_(-this.viewWidth_*0.3,0);}
+e.preventDefault();e.stopPropagation();}});},onDblClick_:function(e){if(this.mouseModeSelector_.mode!==tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION)
+return;var curSelection=this.brushingStateController_.selection;if(!curSelection.length||!curSelection[0].title)
+return;var selection=new tr.model.EventSet();var filter=new tr.c.ExactTitleFilter(curSelection[0].title);this.modelTrack_.addAllEventsMatchingFilterToSelection(filter,selection);this.brushingStateController.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;var relativePosition=this.extractRelativeMousePosition_(e);var loc=tr.model.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 [...]
+var state=new tr.ui.b.UIState(loc,this.viewport_.currentDisplayTransform.scaleX);this.timelineView_.setFindCtlText(state.toUserFriendlyString(this.viewport_));}.bind(this),undefined,function onKeyUpDuringDrag(){if(this.dragBeginEvent_){this.setDragBoxPosition_(this.dragBoxXStart_,this.dragBoxYStart_,this.dragBoxXEnd_,this.dragBoxYEnd_);}}.bind(this));},queueSmoothPan_:function(viewDeltaX,deltaY){var deltaX=this.viewport_.currentDisplayTransform.xViewVectorToWorld(viewDeltaX);var animatio [...]
+smooth=!!smooth;var vp=this.viewport_;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{this.displayTransform_.set(vp.currentDisplayTransform);this. [...]
+return;var bounds=this.brushingStateController.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.brushingStateController.selectionOfInterest.bounds;var worldCenter=bounds.center;var viewWidth=this.viewWidth_;var dt=this.viewport_.currentDisplayTransform;if(false&&!bounds.range){if(dt.xWorldToView(bounds.center)<0||dt.xWorldToView(bounds.center)>viewWidth){this.displayTransform_.set(dt);this.displayTransform_.xPanWorldPosToViewPos(worldCenter,'center',viewWidth);var deltaX=this.displayTransform_.panX-dt.panX;var animation=new tr.ui.TimelineDisplayTransformPanAn [...]
 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 [...]
+this.displayTransform_.set(dt);this.displayTransform_.xPanWorldBoundsIntoView(bounds.min,bounds.max,viewWidth);var deltaX=this.displayTransform_.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=thi [...]
 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;}
+this.model.removeAnnotation(this.xNavStringMarker_);this.xNavStringMarker_=new tr.model.XMarkerAnnotation(worldCenter);this.model.addAnnotation(this.xNavStringMarker_);},setCurrentSelectionAsInterestRange_:function(){var selectionBounds=this.brushingStateController_.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 [...]
+this.viewport_.interestRange.set(selectionBounds);},toggleHighDetails_:function(){this.viewport_.highDetails=!this.viewport_.highDetails;},hideDragBox_:function(){this.$.drag_box.style.left='-1000px';this.$.drag_box.style.top='-1000px';this.$.drag_box.style.width=0;this.$.drag_box.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= [...]
+return false;var results={};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 finalDragBox=intersectRect_(clipRect,dragRect);this.$.drag_box.style.left=finalDragBox.left+'px';this.$.drag_box.style.width=finalDragBox.width+'px';this.$.drag_box.style.top=finalDragBox.top+'px';t [...]
 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-
+return touches;},storeInitialMouseDownPos_:function(e){var position=this.extractRelativeMousePosition_(e);this.mouseViewPosAtMouseDown_.x=position.x;this.mouseViewPosAtMouseDown_.y=position.y;},focusElements_:function(){this.$.hotkey_controller.childRequestsGeneralFocus(this);},storeInitialInteractionPositionsAndFocus_:function(e){this.storeInitialMouseDownPos_(e);this.storeLastMousePos_(e);this.focusElements_();},onBeginPanScan_:function(e){var vp=this.viewport_;this.viewportDisplayTran [...]
+return;var viewWidth=this.viewWidth_;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)
+this.mouseViewPosAtMouseDown_.y;this.displayTransform_.set(this.viewportDisplayTransformAtMouseDown_);this.displayTransform_.incrementPanXInViewUnits(xDeltaView);this.displayTransform_.panY-=yDelta;this.viewport_.setDisplayTransformImmediately(this.displayTransform_);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;this.hideDragBox_();var eDown=this.dragBeginEvent_;this.dragBeginEvent_=undefined;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 tr.model.EventSet();if(eDown.appendSelection){var previousSelection=this.br [...]
+selection.addEventSet(previousSelection);}
+this.modelTrack_.addIntersectingEventsInRangeToSelection(loVX,hiVX,loY,hiY,selection);this.brushingStateController_.changeSelectionFromTimeline(selection);},onBeginZoom_:function(e){this.isZooming_=true;this.storeInitialInteractionPositionsAndFocus_(e);e.preventDefault();},onUpdateZoom_:function(e){if(!this.isZooming_)
 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 [...]
+(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.viewWidth_;var pixelRatio=window.devicePixelRatio||1;var xD [...]
+this.pendingHintTextClearTimeout_=setTimeout(this.hideHintText_.bind(this),1000);this.$.hint_text.textContent=text;this.$.hint_text.style.display='';},hideHintText_:function(){this.pendingHintTextClearTimeout_=undefined;this.$.hint_text.style.display='none';}});'use strict';Polymer('tr-ui-find-control',{filterKeyDown:function(e){if(e.keyCode===27){var hkc=tr.b.getHotkeyControllerForElement(this);if(hkc){hkc.childRequestsBlur(this);}else{this.blur();}
+e.preventDefault();e.stopPropagation();return;}else if(e.keyCode===13){if(e.shiftKey)
+this.findPrevious();else
+this.findNext();}},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.startFilt [...]
 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=[];}
+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.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)
@@ -3689,11 +7596,12 @@ FilterAllOf.prototype={__proto__:tr.e.tquery.Filter.prototype,set subExpressions
 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 new FilterAllOf(exprs);},{name:'allOf'});return{FilterAllOf:FilterAllOf};});'use strict';tr.exportTo('tr.e.tquery',function(){function FilterNot(subExpression){tr.e.tquery.Filter.call(this);this.subExpression=subExpression;}
+FilterNot.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){return!this.subExpression.evaluate(context);}};tr.c.ScriptingObjectRegistry.register(function(){var exprs=Array.prototype.slice.call(arguments);if(exprs.length!==1)
+throw new Error('not() must have exactly one subexpression');return new FilterNot(exprs[0]);},{name:'not'});return{FilterNot:FilterNot};});'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.Filte [...]
 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 false;}};tr.c.ScriptingObjectRegistry.register(function(){var exprs=Array.prototype.slice.call(arguments);return new FilterAnyOf(exprs);},{name:'anyOf'});tr.c.ScriptingObjectRegistry.register(function(){var exprs=Array.prototype.slice.call(arguments);return new tr.e.tquery.FilterNot(new FilterAnyOf(exprs));},{name:'noneOf'});return{FilterAnyOf:FilterAnyOf};});'use strict';tr.exportTo('tr.e.tquery',function(){function FilterHasAncestor(opt_subExpression){this.subExpression=opt_subE [...]
 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 [...]
@@ -3702,20 +7610,23 @@ return this.matchValue_(context.event.duration,this.expected);}};tr.c.ScriptingO
 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 [...]
+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 addEventTreeToSelection(selection,event){selection.push(event);if(!event.subSlices)
+return;event.subSlices.forEach(addEventTreeToSelection.bind(undefined,selection));}
+function TQuery(model){tr.c.ScriptingObject.call(this);this.model_=model;this.parent_=undefined;this.filterExpression_=undefined;this.selection_=undefined;};TQuery.prototype={__proto__:tr.c.ScriptingObject.prototype,onModelChanged:function(model){this.model_=model;this.selection_=undefined;},get brushingStateController(){return this.brushingStateController_;},filter:function(filterExpression){var result=new TQuery(this.model_);result.parent_=this;result.filterExpression_=tr.e.tquery.Filt [...]
 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);}}
+continue;node.selection_=new tr.model.EventSet();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;context=context.push(event);for(var i=0;i<event.subSlices.length;i++){context.event=event.subSlices[i];this.evaluateFilterExpressionForEvent_(context,inputSelection,outputSelection,seenEvents);}},selectEverythingAsTask_:function(selection){var filterTask=new tr.b.Task();this.model_.iterateAllEventContainers(function(container){filterTask.subTask(function(){container.iterateAllEventsInThisContainer(function(){return true;},addEventTreeToSelection.bind(undefined,selection));},this); [...]
+return this.selection_;}};tr.c.ScriptingObjectRegistry.register(new TQuery(),{name:'$t'});return{TQuery:TQuery};});'use strict';Polymer('tr-ui-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.leng [...]
+return;e.preventDefault();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)
+if(result instanceof tr.e.tquery.TQuery){result.ready().then(function(selection){this.addLine_(selection.length+' matches');this.controller_.brushingStateController.showScriptControlSelection(selection);}.bind(this));}else{this.addLine_(result);}
+promptEl.scrollIntoView();},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.brushingStateController_=brushingStateController;if(this.brushingStateController){this.brushingStateController_.addEventListener('change',this.onSelectionChanged_);this.brushingStateController_.addEventListener('model-changed',this.onModelChanged_);}},get selection(){return this.brushingStateController_.selection;},onSelectionChanged_:function(){if(this.activePanel)
+this.activePanel.selection=this.selection;},get model(){return this.brushingStateController_.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))
@@ -3728,314 +7639,118 @@ return undefined;},updateContents_:function(){var previouslyActivePanelType=this
 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 [...]
+this.activePanel.rangeOfInterest=range;}});'use strict';Polymer('tr-ui-timeline-view-help-overlay',{ready:function(){var mod=tr.isMac?'cmd ':'ctrl';var spans=this.shadowRoot.querySelectorAll('span.mod');for(var i=0;i<spans.length;i++){spans[i].textContent=mod;}}});'use strict';tr.exportTo('tr.v',function(){function GenericTable(items){if(items!==undefined)
+this.items=items;else
+this.items=[];};GenericTable.prototype={};return{GenericTable:GenericTable};});'use strict';tr.exportTo('tr.v.ui',function(){var ArrayOfNumbersSummaryModes={AVERAGE_MODE:'average-mode',TOTAL_MODE:'total-mode'};return{ArrayOfNumbersSummaryModes:ArrayOfNumbersSummaryModes};});'use strict';Polymer('tr-v-ui-array-of-numbers-span',{created:function(){this.numbers_=undefined;this.summaryMode_=tr.v.ui.ArrayOfNumbersSummaryModes.AVERAGE_MODE;},get summaryMode(){return this.summaryMode_;},set sum [...]
+if(!(numbers instanceof Array))
+throw new Error('Must provide an array');this.numbers_=numbers;this.updateContents_();},updateContents_:function(){if(this.numbers_===undefined){this.shadowRoot.textContent='-';return;}
+var ArrayOfNumbersSummaryModes=tr.v.ui.ArrayOfNumbersSummaryModes;var value;if(this.summaryMode_===ArrayOfNumbersSummaryModes.AVERAGE_MODE)
+value=tr.b.Statistics.mean(this.numbers_);else
+value=tr.b.Statistics.sum(this.numbers_);var valueRounded=Math.round(value*1000.0)/1000.0;this.shadowRoot.textContent=valueRounded;}});'use strict';tr.exportTo('tr.v.ui',function(){var TEXT_COLUMN_MODE=1;var NUMERIC_COLUMN_MODE=2;var ELEMENT_COLUMN_MODE=3;function isNumeric(value){if((typeof value)==='number')
+return true;else if(value instanceof Number)
+return true;return false;}
+function GenericTableViewTotalsItem(opt_values){if(opt_values!==undefined)
+this.values=opt_values;else
+this.values=[];}
+function GenericTableViewColumnDescriptor(fieldName,firstFieldValue){this.title=fieldName;this.fieldName=fieldName;this.updateModeGivenValue(firstFieldValue);}
+GenericTableViewColumnDescriptor.prototype={get columnMode(){return this.columnMode_;},get isInNumericMode(){return this.columnMode_===NUMERIC_COLUMN_MODE;},cmp:function(a,b){if(this.columnMode_===ELEMENT_COLUMN_MODE)
+return 0;return tr.b.comparePossiblyUndefinedValues(a,b,function(a,b){var vA=a[this.fieldName];var vB=b[this.fieldName];return tr.b.comparePossiblyUndefinedValues(vA,vB,function(vA,vB){if(vA.localeCompare)
+return vA.localeCompare(vB);return vA-vB;},this);},this);},updateModeGivenValue:function(fieldValue){if(this.columnMode_===undefined){if(fieldValue===undefined||fieldValue===null)
+return;if(isNumeric(fieldValue)){this.columnMode_=NUMERIC_COLUMN_MODE;return;}
+if(fieldValue instanceof HTMLElement){this.columnMode_=ELEMENT_COLUMN_MODE;return;}
+this.columnMode_=TEXT_COLUMN_MODE;return;}
+if(fieldValue===undefined||fieldValue===null)
+return;if(isNumeric(fieldValue))
+return;if(fieldValue instanceof HTMLElement){this.columnMode_=ELEMENT_COLUMN_MODE;return;}
+if(this.columnMode_===NUMERIC_COLUMN_MODE)
+this.columnMode_=TEXT_COLUMN_MODE;},value:function(item){var fieldValue=item[this.fieldName];if(fieldValue instanceof GenericTableViewTotalsItem){var span=document.createElement('tr-v-ui-array-of-numbers-span');span.summaryMode=tr.v.ui.ArrayOfNumbersSummaryModes.TOTAL_MODE;span.numbers=fieldValue.values;return span;}
+if(fieldValue===undefined)
+return'-';if(fieldValue instanceof HTMLElement)
+return fieldValue;if(fieldValue instanceof Object){var gov=document.createElement('tr-ui-a-generic-object-view');gov.object=fieldValue;return gov;}
+return fieldValue;}};Polymer('tr-v-ui-generic-table-view',{created:function(){this.items_=undefined;this.importantColumNames_=[];},get items(){return this.items_;},set items(itemsOrGenericTable){if(itemsOrGenericTable===undefined){this.items_=undefined;}else if(itemsOrGenericTable instanceof Array){this.items_=itemsOrGenericTable;}else if(itemsOrGenericTable instanceof tr.v.GenericTable){this.items_=itemsOrGenericTable.items;}
+this.updateContents_();},get importantColumNames(){return this.importantColumNames_;},set importantColumNames(importantColumNames){this.importantColumNames_=importantColumNames;this.updateContents_();},createColumns_:function(){var columnsByName={};this.items_.forEach(function(item){tr.b.iterItems(item,function(itemFieldName,itemFieldValue){var colDesc=columnsByName[itemFieldName];if(colDesc!==undefined){colDesc.updateModeGivenValue(itemFieldValue);return;}
+colDesc=new GenericTableViewColumnDescriptor(itemFieldName,itemFieldValue);columnsByName[itemFieldName]=colDesc;},this);},this);var columns=tr.b.dictionaryValues(columnsByName);if(columns.length===0)
+return undefined;var isColumnNameImportant={};var importantColumNames=this.importantColumNames||[];importantColumNames.forEach(function(icn){isColumnNameImportant[icn]=true;});columns.sort(function(a,b){var iA=isColumnNameImportant[a.title]?1:0;var iB=isColumnNameImportant[b.title]?1:0;if((iB-iA)!==0)
+return iB-iA;return a.title.localeCompare(b.title);});var colWidthPercentage;if(columns.length==1)
+colWidthPercentage='100%';else
+colWidthPercentage=(100/(columns.length-1)).toFixed(3)+'%';columns[0].width='250px';for(var i=1;i<columns.length;i++)
+columns[i].width=colWidthPercentage;return columns;},createFooterRowsIfNeeded_:function(columns){var hasColumnThatIsNumeric=columns.some(function(column){return column.isInNumericMode;});if(!hasColumnThatIsNumeric)
+return[];var totalsItems={};columns.forEach(function(column){if(!column.isInNumericMode)
+return;var totalsItem=new GenericTableViewTotalsItem();this.items_.forEach(function(item){var fieldValue=item[column.fieldName];if(fieldValue===undefined||fieldValue===null)
+return;totalsItem.values.push(fieldValue);});totalsItems[column.fieldName]=totalsItem;},this);return[totalsItems];},updateContents_:function(){var columns;if(this.items_!==undefined)
+columns=this.createColumns_();if(!columns){this.$.table.tableColumns=[];this.$.table.tableRows=[];this.$.table.footerRows=[];return;}
+this.$.table.tableColumns=columns;this.$.table.tableRows=this.items_;this.$.table.footerRows=this.createFooterRowsIfNeeded_(columns);this.$.table.rebuild();},get selectionMode(){return this.$.table.selectionMode;},set selectionMode(selectionMode){this.$.table.selectionMode=selectionMode;},get rowHighlightStyle(){return this.$.table.rowHighlightStyle;},set rowHighlightStyle(rowHighlightStyle){this.$.table.rowHighlightStyle=rowHighlightStyle;},get cellHighlightStyle(){return this.$.table.c [...]
+return;this.preferredTimeDisplayMode_=v;tr.v.Unit.didPreferredTimeDisplayUnitChange();}});'use strict';Polymer('tr-ui-timeline-view',{ready:function(){this.tabIndex=0;this.titleEl_=this.$.title;this.leftControlsEl_=this.$.left_controls;this.rightControlsEl_=this.$.right_controls;this.collapsingControlsEl_=this.$.collapsing_controls;this.sidePanelContainer_=this.$.side_panel_container;this.brushingStateController_=new tr.c.BrushingStateController(this);this.findCtl_=this.$.view_find_contr [...]
+this.optionsDropdown_=this.$.view_options_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.highlightVSyncC [...]
 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 [...]
+return;this.trackView_.viewport.highlightVSync=highlightVSync;},initHelpButton_:function(){var helpButtonEl=this.$.view_help_button;function onClick(e){var dlg=new tr.ui.b.Overlay();dlg.title='Chrome Tracing Help';dlg.appendChild(document.createElement('tr-ui-timeline-view-help-overlay'));dlg.visible=true;e.stopPropagation();}
+helpButtonEl.addEventListener('click',onClick.bind(this));},initConsoleButton_:function(){var toggleEl=this.$.view_console_button;function onClick(e){this.scriptingCtl_.toggleVisibility();e.stopPropagation();return false;}
+toggleEl.addEventListener('click',onClick.bind(this));},initMetadataButton_:function(){var showEl=this.$.view_metadata_button;function onClick(e){var dlg=new tr.ui.b.Overlay();dlg.title='Metadata for trace';var metadataOverlay=document.createElement('tr-ui-timeline-view-metadata-overlay');metadataOverlay.metadata=this.model.metadata;dlg.appendChild(metadataOverlay);dlg.visible=true;e.stopPropagation();return false;}
+showEl.addEventListener('click',onClick.bind(this));this.updateMetadataButtonVisibility_();},updateMetadataButtonVisibility_:function(){var showEl=this.$.view_metadata_button;showEl.style.display=(this.model&&this.model.metadata.length)?'':'none';},get leftControls(){return this.leftControlsEl_;},get rightControls(){return this.rightControlsEl_;},get collapsingControls(){return this.collapsingControlsEl_;},get viewTitle(){return this.titleEl_.textContent.substring(this.titleEl_.textConte [...]
 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)
+return this.trackView_.model;return undefined;},set model(model){var modelInstanceChanged=model!=this.model;var modelValid=model&&!model.bounds.isEmpty;var importWarningsEl=this.shadowRoot.querySelector('#import-warnings');importWarningsEl.textContent='';if(modelInstanceChanged){if(this.railScoreSpan_)
+this.railScoreSpan_.model=undefined;this.trackViewContainer_.textContent='';if(this.trackView_){this.trackView_.viewport.removeEventListener('change',this.onViewportChanged_);this.trackView_.brushingStateController=undefined;this.trackView_.detach();this.trackView_=undefined;}
+this.brushingStateController_.modelWillChange();}
+if(modelValid&&!this.trackView_){this.trackView_=document.createElement('tr-ui-timeline-track-view');this.trackView_.timelineView=this;this.trackView.brushingStateController=this.brushingStateController_;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_)
+this.railScoreSpan_.model=model;this.$.display_unit.preferredTimeDisplayMode=model.intrinsicTimeUnit;}
+if(model){model.importWarningsThatShouldBeShownToUser.forEach(function(importWarning){importWarningsEl.addMessage('Import Warning: '+importWarning.type+': '+
+importWarning.message);},this);}
+if(modelInstanceChanged){this.updateMetadataButtonVisibility_();this.brushingStateController_.modelDidChange();this.onViewportChanged_();}},get brushingStateController(){return this.brushingStateController_;},get trackView(){return this.trackView_;},get settings(){if(!this.settings_)
+this.settings_=new tr.b.Settings();return this.settings_;},set focusElement(value){throw new Error('This is deprecated. Please set globalMode to true.');},bindKeyListeners_:function(){var hkc=this.hotkeyController;hkc.addHotKey(new tr.ui.b.HotKey({eventType:'keypress',keyCode:'`'.charCodeAt(0),useCapture:true,thisArg:this,callback:function(e){this.scriptingCtl_.toggleVisibility();if(!this.scriptingCtl_.hasFocus)
+this.focus();e.stopPropagation();}}));hkc.addHotKey(new tr.ui.b.HotKey({eventType:'keypress',keyCode:'/'.charCodeAt(0),useCapture:true,thisArg:this,callback:function(e){if(this.scriptingCtl_.hasFocus)
+return;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;}
+this.findCtl_.focus();e.preventDefault();e.stopPropagation();}}));hkc.addHotKey(new tr.ui.b.HotKey({eventType:'keypress',keyCode:'?'.charCodeAt(0),useCapture:false,thisArg:this,callback:function(e){this.$.view_help_button.click();e.stopPropagation();}}));hkc.addHotKey(new tr.ui.b.HotKey({eventType:'keypress',keyCode:'v'.charCodeAt(0),useCapture:false,thisArg:this,callback:function(e){this.toggleHighlightVSync_();e.stopPropagation();}}));},onViewportChanged_:function(e){var spc=this.sideP [...]
 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++;}
+spc.rangeOfInterest=vr;if(this.railScoreSpan_&&this.model)
+this.railScoreSpan_.model=this.model;},toggleHighlightVSync_:function(){this.highlightVSyncCheckbox_.checked=!this.highlightVSyncCheckbox_.checked;},setFindCtlText:function(string){this.findCtl_.setText(string);}});'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=new tr.b.Color(0,0,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.generateStripes=function(times,minTime,maxTime){if(times.length===0)
+return[];var stripes=[];var lowIndex=tr.b.findLowIndexInSortedArray(times,function(time){return time;},minTime);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;}
+VSyncHighlighter.prototype={__proto__:Highlighter.prototype,processModel:function(model){this.times_=model.device.vSyncTimestamps;},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};});
+var pixelRatio=window.devicePixelRatio||1;var height=viewHeight*pixelRatio;var c=VSyncHighlighter.VSYNC_HIGHLIGHT_COLOR;ctx.fillStyle=c.toStringWithAlphaOverride(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};});'u [...]
+groupingKeyFuncs=[];this.groupingKeyFuncs_=groupingKeyFuncs;this.rowStatsConstructor_=rowStatsConstructor;this.subRowsBuilt_=false;this.subRows_=undefined;this.rowStats_=undefined;}
+Row.prototype={getCurrentGroupingKeyFunc_:function(){if(this.groupingKeyFuncs_.length===0)
+return undefined;return this.groupingKeyFuncs_[0];},get data(){return this.data_;},get rowStats(){if(this.rowStats_===undefined){this.rowStats_=new this.rowStatsConstructor_(this);}
+return this.rowStats_;},rebuildSubRowsIfNeeded_:function(){if(this.subRowsBuilt_)
+return;this.subRowsBuilt_=true;var groupingKeyFunc=this.getCurrentGroupingKeyFunc_();if(groupingKeyFunc===undefined){this.subRows_=undefined;return;}
+var dataByKey={};var hasValues=false;this.data_.forEach(function(datum){var key=groupingKeyFunc(datum);hasValues=hasValues||(key!==undefined);if(dataByKey[key]===undefined)
+dataByKey[key]=[];dataByKey[key].push(datum);});if(!hasValues){this.subRows_=undefined;return;}
+this.subRows_=[];for(var key in dataByKey){var row=new Row(key,dataByKey[key],this.groupingKeyFuncs_.slice(1),this.rowStatsConstructor_);this.subRows_.push(row);}},get isExpanded(){return(this.subRows&&(this.subRows.length>0)&&(this.subRows.length<5));},get subRows(){this.rebuildSubRowsIfNeeded_();return this.subRows_;}};Polymer('tr-ui-b-grouping-table',{created:function(){this.dataToGroup_=undefined;this.groupBy_=undefined;this.rowStatsConstructor_=undefined;},get tableColumns(){return  [...]
+throw new Error('Already initialized.');this.defaultGroupKeys_=defaultGroupKeys;this.maybeInit_();},get possibleGroups(){return this.possibleGroups_;},set possibleGroups(possibleGroups){if(!this.needsInit_)
+throw new Error('Already initialized.');this.possibleGroups_=possibleGroups;this.maybeInit_();},get settingsKey(){return this.settingsKey_;},set settingsKey(settingsKey){if(!this.needsInit_)
+throw new Error('Already initialized.');this.settingsKey_=settingsKey;this.maybeInit_();},maybeInit_:function(){if(!this.needsInit_)
+return;if(this.settingsKey_===undefined)
+return;if(this.defaultGroupKeys_===undefined)
+return;if(this.possibleGroups_===undefined)
+return;this.needsInit_=false;var addGroupEl=this.shadowRoot.querySelector('#add-group');addGroupEl.iconElement.textContent='Add another...';this.currentGroupKeys=tr.b.Settings.get(this.settingsKey_,this.defaultGroupKeys_);},get currentGroupKeys(){return this.currentGroupKeys_;},get currentGroups(){var groupsByKey={};this.possibleGroups_.forEach(function(group){groupsByKey[group.key]=group;});return this.currentGroupKeys_.map(function(groupKey){return groupsByKey[groupKey];});},set curren [...]
+return;if(!(currentGroupKeys instanceof Array))
+throw new Error('Must be array');this.currentGroupKeys_=currentGroupKeys;this.updateGroups_();tr.b.Settings.set(this.settingsKey_,this.currentGroupKeys_);var e=new tr.b.Event('current-groups-changed');this.dispatchEvent(e);},updateGroups_:function(){var groupsEl=this.shadowRoot.querySelector('groups');var addGroupEl=this.shadowRoot.querySelector('#add-group');groupsEl.textContent='';addGroupEl.textContent='';var unusedGroups={};var groupsByKey={};this.possibleGroups_.forEach(function(gro [...]
+groupsEl.children[i].classList.remove('drop-targeted');groupEl.classList.remove('dragging');this.dragging_=false;}.bind(this));groupEl.addEventListener('dragenter',function(e){if(!this.dragging_)
+return;groupEl.classList.add('drop-targeted');if(this.dragging_)
+e.preventDefault();}.bind(this));groupEl.addEventListener('dragleave',function(e){if(!this.dragging_)
+return;groupEl.classList.remove('drop-targeted');e.preventDefault();}.bind(this));groupEl.addEventListener('dragover',function(e){if(!this.dragging_)
+return;e.preventDefault();groupEl.classList.add('drop-targeted');}.bind(this));groupEl.addEventListener('drop',function(e){if(!this.dragging_)
+return;var srcKey=e.dataTransfer.getData('groupKey');var dstKey=groupEl.groupKey;if(srcKey===dstKey)
+return;var newKeys=this.currentGroupKeys_.slice();var srcIndex=this.currentGroupKeys_.indexOf(srcKey);newKeys.splice(srcIndex,1);var dstIndex=this.currentGroupKeys_.indexOf(dstKey);newKeys.splice(dstIndex,0,srcKey);this.currentGroupKeys=newKeys;e.dataTransfer.clearData();e.preventDefault();e.stopPropagation();}.bind(this));}});return{};});'use strict';(function(){Polymer('tr-ui-sp-file-size-stats-side-panel',{ready:function(){this.model_=undefined;this.selection_=new tr.model.EventSet(); [...]
+if(m.stats.allTraceEventStats.length===0){return{supported:false,reason:'No stats were collected for this file.'};}
+return{supported:true};},get model(){return this.model_;},set model(model){this.model_=model;this.updateContents_();},get rangeOfInterest(){return this.rangeOfInterest_;},set rangeOfInterest(rangeOfInterest){this.rangeOfInterest_=rangeOfInterest;},get selection(){return this.selection_;},set selection(selection){this.selection_=selection;},createColumns_:function(stats){var columns=[{title:'Title',value:function(row){var titleEl=document.createElement('span');titleEl.textContent=row.titl [...]
+b.rowStats.totalEventSizeinBytes;},width:'80px'});}
+return columns;},updateContents_:function(){var table=this.$.table;var columns=this.createColumns_(this.model.stats);table.rowStatsConstructor=function ModelStatsRowStats(row){var sum=tr.b.Statistics.sum(row.data,function(x){return x.numEvents;});var totalEventSizeinBytes=tr.b.Statistics.sum(row.data,function(x){return x.totalEventSizeinBytes;});return{numEvents:sum,totalEventSizeinBytes:totalEventSizeinBytes};};table.tableColumns=columns;table.sortColumnIndex=1;table.sortDescending=true [...]
+this.$.table.rebuild();}});})();'use strict';Polymer('tr-ui-e-s-alerts-side-panel',{ready:function(){this.rangeOfInterest_=new tr.b.Range();this.selection_=undefined;},get model(){return this.model_;},set model(model){this.model_=model;this.updateContents_();},set selection(selection){},set rangeOfInterest(rangeOfInterest){},selectAlertsOfType:function(alertTypeString){var alertsOfType=this.model_.alerts.filter(function(alert){return alert.title===alertTypeString;});var event=new tr.mode [...]
+alertsByType[alert.title]=[];alertsByType[alert.title].push(alert);});return alertsByType;},alertsTableRows_:function(alertsByType){return Object.keys(alertsByType).map(function(key){return{alertType:key,count:alertsByType[key].length};});},alertsTableColumns_:function(){return[{title:'Alert type',value:function(row){return row.alertType;},width:'180px'},{title:'Count',width:'100%',value:function(row){return row.count;}}];},createAlertsTable_:function(alerts){var alertsByType=this.alerts [...]
+this.selectAlertsOfType(row.alertType);}.bind(this));return table;},updateContents_:function(){this.$.result_area.textContent='';if(this.model_===undefined)
+return;var panel=this.createAlertsTable_(this.model_.alerts);this.$.result_area.appendChild(panel);},supportsModel:function(m){if(m==undefined){return{supported:false,reason:'Unknown tracing model'};}else if(m.alerts.length===0){return{supported:false,reason:'No alerts in tracing model'};}
+return{supported:true};},get textLabel(){return'Alerts';}});
 </script>
 </head>
   <body>
diff --git a/src/androidtest.bash b/src/androidtest.bash
index 84c2222..823b83b 100755
--- a/src/androidtest.bash
+++ b/src/androidtest.bash
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-# Copyright 2014 The Go Authors.  All rights reserved.
+# 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/src/archive/tar/common.go b/src/archive/tar/common.go
index 36f4e23..2a1e432 100644
--- a/src/archive/tar/common.go
+++ b/src/archive/tar/common.go
@@ -21,10 +21,8 @@ import (
 	"time"
 )
 
+// Header type flags.
 const (
-	blockSize = 512
-
-	// Types
 	TypeReg           = '0'    // regular file
 	TypeRegA          = '\x00' // regular file
 	TypeLink          = '1'    // hard link
@@ -61,12 +59,6 @@ type Header struct {
 	Xattrs     map[string]string
 }
 
-// File name constants from the tar spec.
-const (
-	fileNameSize       = 100 // Maximum number of bytes in a standard tar name.
-	fileNamePrefixSize = 155 // Maximum number of ustar extension bytes.
-)
-
 // FileInfo returns an os.FileInfo for the Header.
 func (h *Header) FileInfo() os.FileInfo {
 	return headerFileInfo{h}
@@ -279,33 +271,6 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
 	return h, nil
 }
 
-var zeroBlock = make([]byte, blockSize)
-
-// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
-// We compute and return both.
-func checksum(header []byte) (unsigned int64, signed int64) {
-	for i := 0; i < len(header); i++ {
-		if i == 148 {
-			// The chksum field (header[148:156]) is special: it should be treated as space bytes.
-			unsigned += ' ' * 8
-			signed += ' ' * 8
-			i += 7
-			continue
-		}
-		unsigned += int64(header[i])
-		signed += int64(int8(header[i]))
-	}
-	return
-}
-
-type slicer []byte
-
-func (sp *slicer) next(n int) (b []byte) {
-	s := *sp
-	b, *sp = s[0:n], s[n:]
-	return
-}
-
 func isASCII(s string) bool {
 	for _, c := range s {
 		if c >= 0x80 {
diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go
new file mode 100644
index 0000000..c2c9910
--- /dev/null
+++ b/src/archive/tar/format.go
@@ -0,0 +1,197 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// Constants to identify various tar formats.
+const (
+	// The format is unknown.
+	formatUnknown = (1 << iota) / 2 // Sequence of 0, 1, 2, 4, 8, etc...
+
+	// The format of the original Unix V7 tar tool prior to standardization.
+	formatV7
+
+	// The old and new GNU formats, which are incompatible with USTAR.
+	// This does cover the old GNU sparse extension.
+	// This does not cover the GNU sparse extensions using PAX headers,
+	// versions 0.0, 0.1, and 1.0; these fall under the PAX format.
+	formatGNU
+
+	// Schily's tar format, which is incompatible with USTAR.
+	// This does not cover STAR extensions to the PAX format; these fall under
+	// the PAX format.
+	formatSTAR
+
+	// USTAR is the former standardization of tar defined in POSIX.1-1988.
+	// This is incompatible with the GNU and STAR formats.
+	formatUSTAR
+
+	// PAX is the latest standardization of tar defined in POSIX.1-2001.
+	// This is an extension of USTAR and is "backwards compatible" with it.
+	//
+	// Some newer formats add their own extensions to PAX, such as GNU sparse
+	// files and SCHILY extended attributes. Since they are backwards compatible
+	// with PAX, they will be labelled as "PAX".
+	formatPAX
+)
+
+// Magics used to identify various formats.
+const (
+	magicGNU, versionGNU     = "ustar ", " \x00"
+	magicUSTAR, versionUSTAR = "ustar\x00", "00"
+	trailerSTAR              = "tar\x00"
+)
+
+// Size constants from various tar specifications.
+const (
+	blockSize  = 512 // Size of each block in a tar stream
+	nameSize   = 100 // Max length of the name field in USTAR format
+	prefixSize = 155 // Max length of the prefix field in USTAR format
+)
+
+var zeroBlock block
+
+type block [blockSize]byte
+
+// Convert block to any number of formats.
+func (b *block) V7() *headerV7       { return (*headerV7)(b) }
+func (b *block) GNU() *headerGNU     { return (*headerGNU)(b) }
+func (b *block) STAR() *headerSTAR   { return (*headerSTAR)(b) }
+func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) }
+func (b *block) Sparse() sparseArray { return (sparseArray)(b[:]) }
+
+// GetFormat checks that the block is a valid tar header based on the checksum.
+// It then attempts to guess the specific format based on magic values.
+// If the checksum fails, then formatUnknown is returned.
+func (b *block) GetFormat() (format int) {
+	// Verify checksum.
+	var p parser
+	value := p.parseOctal(b.V7().Chksum())
+	chksum1, chksum2 := b.ComputeChecksum()
+	if p.err != nil || (value != chksum1 && value != chksum2) {
+		return formatUnknown
+	}
+
+	// Guess the magic values.
+	magic := string(b.USTAR().Magic())
+	version := string(b.USTAR().Version())
+	trailer := string(b.STAR().Trailer())
+	switch {
+	case magic == magicUSTAR && trailer == trailerSTAR:
+		return formatSTAR
+	case magic == magicUSTAR:
+		return formatUSTAR
+	case magic == magicGNU && version == versionGNU:
+		return formatGNU
+	default:
+		return formatV7
+	}
+}
+
+// SetFormat writes the magic values necessary for specified format
+// and then updates the checksum accordingly.
+func (b *block) SetFormat(format int) {
+	// Set the magic values.
+	switch format {
+	case formatV7:
+		// Do nothing.
+	case formatGNU:
+		copy(b.GNU().Magic(), magicGNU)
+		copy(b.GNU().Version(), versionGNU)
+	case formatSTAR:
+		copy(b.STAR().Magic(), magicUSTAR)
+		copy(b.STAR().Version(), versionUSTAR)
+		copy(b.STAR().Trailer(), trailerSTAR)
+	case formatUSTAR, formatPAX:
+		copy(b.USTAR().Magic(), magicUSTAR)
+		copy(b.USTAR().Version(), versionUSTAR)
+	default:
+		panic("invalid format")
+	}
+
+	// Update checksum.
+	// This field is special in that it is terminated by a NULL then space.
+	var f formatter
+	field := b.V7().Chksum()
+	chksum, _ := b.ComputeChecksum() // Possible values are 256..128776
+	f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
+	field[7] = ' '
+}
+
+// ComputeChecksum computes the checksum for the header block.
+// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
+// signed byte values.
+// We compute and return both.
+func (b *block) ComputeChecksum() (unsigned, signed int64) {
+	for i, c := range b {
+		if 148 <= i && i < 156 {
+			c = ' ' // Treat the checksum field itself as all spaces.
+		}
+		unsigned += int64(uint8(c))
+		signed += int64(int8(c))
+	}
+	return unsigned, signed
+}
+
+type headerV7 [blockSize]byte
+
+func (h *headerV7) Name() []byte     { return h[000:][:100] }
+func (h *headerV7) Mode() []byte     { return h[100:][:8] }
+func (h *headerV7) UID() []byte      { return h[108:][:8] }
+func (h *headerV7) GID() []byte      { return h[116:][:8] }
+func (h *headerV7) Size() []byte     { return h[124:][:12] }
+func (h *headerV7) ModTime() []byte  { return h[136:][:12] }
+func (h *headerV7) Chksum() []byte   { return h[148:][:8] }
+func (h *headerV7) TypeFlag() []byte { return h[156:][:1] }
+func (h *headerV7) LinkName() []byte { return h[157:][:100] }
+
+type headerGNU [blockSize]byte
+
+func (h *headerGNU) V7() *headerV7       { return (*headerV7)(h) }
+func (h *headerGNU) Magic() []byte       { return h[257:][:6] }
+func (h *headerGNU) Version() []byte     { return h[263:][:2] }
+func (h *headerGNU) UserName() []byte    { return h[265:][:32] }
+func (h *headerGNU) GroupName() []byte   { return h[297:][:32] }
+func (h *headerGNU) DevMajor() []byte    { return h[329:][:8] }
+func (h *headerGNU) DevMinor() []byte    { return h[337:][:8] }
+func (h *headerGNU) AccessTime() []byte  { return h[345:][:12] }
+func (h *headerGNU) ChangeTime() []byte  { return h[357:][:12] }
+func (h *headerGNU) Sparse() sparseArray { return (sparseArray)(h[386:][:24*4+1]) }
+func (h *headerGNU) RealSize() []byte    { return h[483:][:12] }
+
+type headerSTAR [blockSize]byte
+
+func (h *headerSTAR) V7() *headerV7      { return (*headerV7)(h) }
+func (h *headerSTAR) Magic() []byte      { return h[257:][:6] }
+func (h *headerSTAR) Version() []byte    { return h[263:][:2] }
+func (h *headerSTAR) UserName() []byte   { return h[265:][:32] }
+func (h *headerSTAR) GroupName() []byte  { return h[297:][:32] }
+func (h *headerSTAR) DevMajor() []byte   { return h[329:][:8] }
+func (h *headerSTAR) DevMinor() []byte   { return h[337:][:8] }
+func (h *headerSTAR) Prefix() []byte     { return h[345:][:131] }
+func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] }
+func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] }
+func (h *headerSTAR) Trailer() []byte    { return h[508:][:4] }
+
+type headerUSTAR [blockSize]byte
+
+func (h *headerUSTAR) V7() *headerV7     { return (*headerV7)(h) }
+func (h *headerUSTAR) Magic() []byte     { return h[257:][:6] }
+func (h *headerUSTAR) Version() []byte   { return h[263:][:2] }
+func (h *headerUSTAR) UserName() []byte  { return h[265:][:32] }
+func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] }
+func (h *headerUSTAR) DevMajor() []byte  { return h[329:][:8] }
+func (h *headerUSTAR) DevMinor() []byte  { return h[337:][:8] }
+func (h *headerUSTAR) Prefix() []byte    { return h[345:][:155] }
+
+type sparseArray []byte
+
+func (s sparseArray) Entry(i int) sparseNode { return (sparseNode)(s[i*24:]) }
+func (s sparseArray) IsExtended() []byte     { return s[24*s.MaxEntries():][:1] }
+func (s sparseArray) MaxEntries() int        { return len(s) / 24 }
+
+type sparseNode []byte
+
+func (s sparseNode) Offset() []byte   { return s[00:][:12] }
+func (s sparseNode) NumBytes() []byte { return s[12:][:12] }
diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go
index c8cb69a..096ef08 100644
--- a/src/archive/tar/reader.go
+++ b/src/archive/tar/reader.go
@@ -13,7 +13,6 @@ import (
 	"io"
 	"io/ioutil"
 	"math"
-	"os"
 	"strconv"
 	"strings"
 	"time"
@@ -30,11 +29,11 @@ const maxNanoSecondIntSize = 9
 // The Next method advances to the next file in the archive (including the first),
 // and then it can be treated as an io.Reader to access the file's data.
 type Reader struct {
-	r       io.Reader
-	err     error
-	pad     int64           // amount of padding (ignored) after current file entry
-	curr    numBytesReader  // reader for current file entry
-	hdrBuff [blockSize]byte // buffer to use in readHeader
+	r    io.Reader
+	err  error
+	pad  int64          // amount of padding (ignored) after current file entry
+	curr numBytesReader // reader for current file entry
+	blk  block          // buffer to use as temporary local storage
 }
 
 type parser struct {
@@ -99,17 +98,6 @@ const (
 	paxGNUSparseRealSize  = "GNU.sparse.realsize"
 )
 
-// Keywords for old GNU sparse headers
-const (
-	oldGNUSparseMainHeaderOffset               = 386
-	oldGNUSparseMainHeaderIsExtendedOffset     = 482
-	oldGNUSparseMainHeaderNumEntries           = 4
-	oldGNUSparseExtendedHeaderIsExtendedOffset = 504
-	oldGNUSparseExtendedHeaderNumEntries       = 21
-	oldGNUSparseOffsetSize                     = 12
-	oldGNUSparseNumBytesSize                   = 12
-)
-
 // NewReader creates a new Reader reading from r.
 func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
 
@@ -307,7 +295,7 @@ func mergePAX(hdr *Header, headers map[string]string) error {
 			if err != nil {
 				return err
 			}
-			hdr.Size = int64(size)
+			hdr.Size = size
 		default:
 			if strings.HasPrefix(k, paxXattr) {
 				if hdr.Xattrs == nil {
@@ -337,17 +325,17 @@ func parsePAXTime(t string) (time.Time, error) {
 		if err != nil {
 			return time.Time{}, err
 		}
-		nano_buf := string(buf[pos+1:])
+		nanoBuf := string(buf[pos+1:])
 		// Pad as needed before converting to a decimal.
 		// For example .030 -> .030000000 -> 30000000 nanoseconds
-		if len(nano_buf) < maxNanoSecondIntSize {
+		if len(nanoBuf) < maxNanoSecondIntSize {
 			// Right pad
-			nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len(nano_buf))
-		} else if len(nano_buf) > maxNanoSecondIntSize {
+			nanoBuf += strings.Repeat("0", maxNanoSecondIntSize-len(nanoBuf))
+		} else if len(nanoBuf) > maxNanoSecondIntSize {
 			// Right truncate
-			nano_buf = nano_buf[:maxNanoSecondIntSize]
+			nanoBuf = nanoBuf[:maxNanoSecondIntSize]
 		}
-		nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0)
+		nanoseconds, err = strconv.ParseInt(nanoBuf, 10, 0)
 		if err != nil {
 			return time.Time{}, err
 		}
@@ -379,14 +367,14 @@ func parsePAX(r io.Reader) (map[string]string, error) {
 		}
 		sbuf = residual
 
-		keyStr := string(key)
+		keyStr := key
 		if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
 			// GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
 			sparseMap.WriteString(value)
 			sparseMap.Write([]byte{','})
 		} else {
 			// Normal key. Set the value in the headers map.
-			headers[keyStr] = string(value)
+			headers[keyStr] = value
 		}
 	}
 	if sparseMap.Len() != 0 {
@@ -523,10 +511,10 @@ func (tr *Reader) skipUnread() error {
 		// io.Seeker, but calling Seek always returns an error and performs
 		// no action. Thus, we try an innocent seek to the current position
 		// to see if Seek is really supported.
-		pos1, err := sr.Seek(0, os.SEEK_CUR)
+		pos1, err := sr.Seek(0, io.SeekCurrent)
 		if err == nil {
 			// Seek seems supported, so perform the real Seek.
-			pos2, err := sr.Seek(dataSkip-1, os.SEEK_CUR)
+			pos2, err := sr.Seek(dataSkip-1, io.SeekCurrent)
 			if err != nil {
 				tr.err = err
 				return tr.err
@@ -543,17 +531,6 @@ func (tr *Reader) skipUnread() error {
 	return tr.err
 }
 
-func (tr *Reader) verifyChecksum(header []byte) bool {
-	if tr.err != nil {
-		return false
-	}
-
-	var p parser
-	given := p.parseOctal(header[148:156])
-	unsigned, signed := checksum(header)
-	return p.err == nil && (given == unsigned || given == signed)
-}
-
 // readHeader reads the next block header and assumes that the underlying reader
 // is already aligned to a block boundary.
 //
@@ -562,19 +539,16 @@ func (tr *Reader) verifyChecksum(header []byte) bool {
 //	* Exactly 1 block of zeros is read and EOF is hit.
 //	* At least 2 blocks of zeros are read.
 func (tr *Reader) readHeader() *Header {
-	header := tr.hdrBuff[:]
-	copy(header, zeroBlock)
-
-	if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+	if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil {
 		return nil // io.EOF is okay here
 	}
 
 	// Two blocks of zero bytes marks the end of the archive.
-	if bytes.Equal(header, zeroBlock[0:blockSize]) {
-		if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+	if bytes.Equal(tr.blk[:], zeroBlock[:]) {
+		if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil {
 			return nil // io.EOF is okay here
 		}
-		if bytes.Equal(header, zeroBlock[0:blockSize]) {
+		if bytes.Equal(tr.blk[:], zeroBlock[:]) {
 			tr.err = io.EOF
 		} else {
 			tr.err = ErrHeader // zero block and then non-zero block
@@ -582,71 +556,55 @@ func (tr *Reader) readHeader() *Header {
 		return nil
 	}
 
-	if !tr.verifyChecksum(header) {
+	// Verify the header matches a known format.
+	format := tr.blk.GetFormat()
+	if format == formatUnknown {
 		tr.err = ErrHeader
 		return nil
 	}
 
-	// Unpack
 	var p parser
 	hdr := new(Header)
-	s := slicer(header)
-
-	hdr.Name = p.parseString(s.next(100))
-	hdr.Mode = p.parseNumeric(s.next(8))
-	hdr.Uid = int(p.parseNumeric(s.next(8)))
-	hdr.Gid = int(p.parseNumeric(s.next(8)))
-	hdr.Size = p.parseNumeric(s.next(12))
-	hdr.ModTime = time.Unix(p.parseNumeric(s.next(12)), 0)
-	s.next(8) // chksum
-	hdr.Typeflag = s.next(1)[0]
-	hdr.Linkname = p.parseString(s.next(100))
-
-	// The remainder of the header depends on the value of magic.
-	// The original (v7) version of tar had no explicit magic field,
-	// so its magic bytes, like the rest of the block, are NULs.
-	magic := string(s.next(8)) // contains version field as well.
-	var format string
-	switch {
-	case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988)
-		if string(header[508:512]) == "tar\x00" {
-			format = "star"
-		} else {
-			format = "posix"
-		}
-	case magic == "ustar  \x00": // old GNU tar
-		format = "gnu"
-	}
 
-	switch format {
-	case "posix", "gnu", "star":
-		hdr.Uname = p.parseString(s.next(32))
-		hdr.Gname = p.parseString(s.next(32))
-		devmajor := s.next(8)
-		devminor := s.next(8)
+	// Unpack the V7 header.
+	v7 := tr.blk.V7()
+	hdr.Name = p.parseString(v7.Name())
+	hdr.Mode = p.parseNumeric(v7.Mode())
+	hdr.Uid = int(p.parseNumeric(v7.UID()))
+	hdr.Gid = int(p.parseNumeric(v7.GID()))
+	hdr.Size = p.parseNumeric(v7.Size())
+	hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
+	hdr.Typeflag = v7.TypeFlag()[0]
+	hdr.Linkname = p.parseString(v7.LinkName())
+
+	// Unpack format specific fields.
+	if format > formatV7 {
+		ustar := tr.blk.USTAR()
+		hdr.Uname = p.parseString(ustar.UserName())
+		hdr.Gname = p.parseString(ustar.GroupName())
 		if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
-			hdr.Devmajor = p.parseNumeric(devmajor)
-			hdr.Devminor = p.parseNumeric(devminor)
+			hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
+			hdr.Devminor = p.parseNumeric(ustar.DevMinor())
 		}
+
 		var prefix string
 		switch format {
-		case "posix", "gnu":
-			prefix = p.parseString(s.next(155))
-		case "star":
-			prefix = p.parseString(s.next(131))
-			hdr.AccessTime = time.Unix(p.parseNumeric(s.next(12)), 0)
-			hdr.ChangeTime = time.Unix(p.parseNumeric(s.next(12)), 0)
+		case formatUSTAR, formatGNU:
+			// TODO(dsnet): Do not use the prefix field for the GNU format!
+			// See golang.org/issues/12594
+			ustar := tr.blk.USTAR()
+			prefix = p.parseString(ustar.Prefix())
+		case formatSTAR:
+			star := tr.blk.STAR()
+			prefix = p.parseString(star.Prefix())
+			hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
+			hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
 		}
 		if len(prefix) > 0 {
 			hdr.Name = prefix + "/" + hdr.Name
 		}
 	}
 
-	if p.err != nil {
-		tr.err = p.err
-		return nil
-	}
-
 	nb := hdr.Size
 	if isHeaderOnlyType(hdr.Typeflag) {
 		nb = 0
@@ -663,14 +621,14 @@ func (tr *Reader) readHeader() *Header {
 	// Check for old GNU sparse format entry.
 	if hdr.Typeflag == TypeGNUSparse {
 		// Get the real size of the file.
-		hdr.Size = p.parseNumeric(header[483:495])
+		hdr.Size = p.parseNumeric(tr.blk.GNU().RealSize())
 		if p.err != nil {
 			tr.err = p.err
 			return nil
 		}
 
 		// Read the sparse map.
-		sp := tr.readOldGNUSparseMap(header)
+		sp := tr.readOldGNUSparseMap(&tr.blk)
 		if tr.err != nil {
 			return nil
 		}
@@ -682,26 +640,24 @@ func (tr *Reader) readHeader() *Header {
 		}
 	}
 
+	if p.err != nil {
+		tr.err = p.err
+		return nil
+	}
+
 	return hdr
 }
 
 // readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
 // The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
 // then one or more extension headers are used to store the rest of the sparse map.
-func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
+func (tr *Reader) readOldGNUSparseMap(blk *block) []sparseEntry {
 	var p parser
-	isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
-	spCap := oldGNUSparseMainHeaderNumEntries
-	if isExtended {
-		spCap += oldGNUSparseExtendedHeaderNumEntries
-	}
-	sp := make([]sparseEntry, 0, spCap)
-	s := slicer(header[oldGNUSparseMainHeaderOffset:])
-
-	// Read the four entries from the main tar header
-	for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
-		offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
-		numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
+	var s sparseArray = blk.GNU().Sparse()
+	var sp = make([]sparseEntry, 0, s.MaxEntries())
+	for i := 0; i < s.MaxEntries(); i++ {
+		offset := p.parseOctal(s.Entry(i).Offset())
+		numBytes := p.parseOctal(s.Entry(i).NumBytes())
 		if p.err != nil {
 			tr.err = p.err
 			return nil
@@ -712,17 +668,17 @@ func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
 		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
 	}
 
-	for isExtended {
+	for s.IsExtended()[0] > 0 {
 		// There are more entries. Read an extension header and parse its entries.
-		sparseHeader := make([]byte, blockSize)
-		if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil {
+		var blk block
+		if _, tr.err = io.ReadFull(tr.r, blk[:]); tr.err != nil {
 			return nil
 		}
-		isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
-		s = slicer(sparseHeader)
-		for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
-			offset := p.parseNumeric(s.next(oldGNUSparseOffsetSize))
-			numBytes := p.parseNumeric(s.next(oldGNUSparseNumBytesSize))
+		s = blk.Sparse()
+
+		for i := 0; i < s.MaxEntries(); i++ {
+			offset := p.parseOctal(s.Entry(i).Offset())
+			numBytes := p.parseOctal(s.Entry(i).NumBytes())
 			if p.err != nil {
 				tr.err = p.err
 				return nil
diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go
index 0426381..426e443 100644
--- a/src/archive/tar/writer.go
+++ b/src/archive/tar/writer.go
@@ -36,10 +36,10 @@ type Writer struct {
 	nb         int64 // number of unwritten bytes for current file entry
 	pad        int64 // amount of padding to write after current file entry
 	closed     bool
-	usedBinary bool            // whether the binary numeric field extension was used
-	preferPax  bool            // use pax header instead of binary numeric header
-	hdrBuff    [blockSize]byte // buffer to use in writeHeader when writing a regular header
-	paxHdrBuff [blockSize]byte // buffer to use in writeHeader when writing a pax header
+	usedBinary bool  // whether the binary numeric field extension was used
+	preferPax  bool  // use PAX header instead of binary numeric header
+	hdrBuff    block // buffer to use in writeHeader when writing a regular header
+	paxHdrBuff block // buffer to use in writeHeader when writing a PAX header
 }
 
 type formatter struct {
@@ -153,27 +153,24 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 	// a map to hold pax header records, if any are needed
 	paxHeaders := make(map[string]string)
 
-	// TODO(shanemhansen): we might want to use PAX headers for
+	// TODO(dsnet): we might want to use PAX headers for
 	// subsecond time resolution, but for now let's just capture
 	// too long fields or non ascii characters
 
-	var f formatter
-	var header []byte
-
 	// We need to select which scratch buffer to use carefully,
 	// since this method is called recursively to write PAX headers.
 	// If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
 	// If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
 	// already being used by the non-recursive call, so we must use paxHdrBuff.
-	header = tw.hdrBuff[:]
+	header := &tw.hdrBuff
 	if !allowPax {
-		header = tw.paxHdrBuff[:]
+		header = &tw.paxHdrBuff
 	}
-	copy(header, zeroBlock)
-	s := slicer(header)
+	copy(header[:], zeroBlock[:])
 
 	// Wrappers around formatter that automatically sets paxHeaders if the
 	// argument extends beyond the capacity of the input byte slice.
+	var f formatter
 	var formatString = func(b []byte, s string, paxKeyword string) {
 		needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
 		if needsPaxHeader {
@@ -202,44 +199,33 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 		f.formatNumeric(b, x)
 	}
 
-	// keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
-	pathHeaderBytes := s.next(fileNameSize)
-
-	formatString(pathHeaderBytes, hdr.Name, paxPath)
-
 	// Handle out of range ModTime carefully.
 	var modTime int64
 	if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) {
 		modTime = hdr.ModTime.Unix()
 	}
 
-	f.formatOctal(s.next(8), hdr.Mode)               // 100:108
-	formatNumeric(s.next(8), int64(hdr.Uid), paxUid) // 108:116
-	formatNumeric(s.next(8), int64(hdr.Gid), paxGid) // 116:124
-	formatNumeric(s.next(12), hdr.Size, paxSize)     // 124:136
-	formatNumeric(s.next(12), modTime, paxNone)      // 136:148 --- consider using pax for finer granularity
-	s.next(8)                                        // chksum (148:156)
-	s.next(1)[0] = hdr.Typeflag                      // 156:157
-
-	formatString(s.next(100), hdr.Linkname, paxLinkpath)
-
-	copy(s.next(8), []byte("ustar\x0000"))          // 257:265
-	formatString(s.next(32), hdr.Uname, paxUname)   // 265:297
-	formatString(s.next(32), hdr.Gname, paxGname)   // 297:329
-	formatNumeric(s.next(8), hdr.Devmajor, paxNone) // 329:337
-	formatNumeric(s.next(8), hdr.Devminor, paxNone) // 337:345
-
-	// keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
-	prefixHeaderBytes := s.next(155)
-	formatString(prefixHeaderBytes, "", paxNone) // 345:500  prefix
+	v7 := header.V7()
+	formatString(v7.Name(), hdr.Name, paxPath)
+	// TODO(dsnet): The GNU format permits the mode field to be encoded in
+	// base-256 format. Thus, we can use formatNumeric instead of formatOctal.
+	f.formatOctal(v7.Mode(), hdr.Mode)
+	formatNumeric(v7.UID(), int64(hdr.Uid), paxUid)
+	formatNumeric(v7.GID(), int64(hdr.Gid), paxGid)
+	formatNumeric(v7.Size(), hdr.Size, paxSize)
+	// TODO(dsnet): Consider using PAX for finer time granularity.
+	formatNumeric(v7.ModTime(), modTime, paxNone)
+	v7.TypeFlag()[0] = hdr.Typeflag
+	formatString(v7.LinkName(), hdr.Linkname, paxLinkpath)
+
+	ustar := header.USTAR()
+	formatString(ustar.UserName(), hdr.Uname, paxUname)
+	formatString(ustar.GroupName(), hdr.Gname, paxGname)
+	formatNumeric(ustar.DevMajor(), hdr.Devmajor, paxNone)
+	formatNumeric(ustar.DevMinor(), hdr.Devminor, paxNone)
 
-	// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
-	if tw.usedBinary {
-		copy(header[257:265], []byte("ustar  \x00"))
-	}
-
-	_, paxPathUsed := paxHeaders[paxPath]
 	// try to use a ustar header when only the name is too long
+	_, paxPathUsed := paxHeaders[paxPath]
 	if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
 		prefix, suffix, ok := splitUSTARPath(hdr.Name)
 		if ok {
@@ -247,16 +233,16 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 			delete(paxHeaders, paxPath)
 
 			// Update the path fields
-			formatString(pathHeaderBytes, suffix, paxNone)
-			formatString(prefixHeaderBytes, prefix, paxNone)
+			formatString(v7.Name(), suffix, paxNone)
+			formatString(ustar.Prefix(), prefix, paxNone)
 		}
 	}
 
-	// The chksum field is terminated by a NUL and a space.
-	// This is different from the other octal fields.
-	chksum, _ := checksum(header)
-	f.formatOctal(header[148:155], chksum) // Never fails
-	header[155] = ' '
+	if tw.usedBinary {
+		header.SetFormat(formatGNU)
+	} else {
+		header.SetFormat(formatUSTAR)
+	}
 
 	// Check if there were any formatting errors.
 	if f.err != nil {
@@ -278,10 +264,10 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 			return err
 		}
 	}
-	tw.nb = int64(hdr.Size)
+	tw.nb = hdr.Size
 	tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize
 
-	_, tw.err = tw.w.Write(header)
+	_, tw.err = tw.w.Write(header[:])
 	return tw.err
 }
 
@@ -289,10 +275,10 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
 // If the path is not splittable, then it will return ("", "", false).
 func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
 	length := len(name)
-	if length <= fileNameSize || !isASCII(name) {
+	if length <= nameSize || !isASCII(name) {
 		return "", "", false
-	} else if length > fileNamePrefixSize+1 {
-		length = fileNamePrefixSize + 1
+	} else if length > prefixSize+1 {
+		length = prefixSize + 1
 	} else if name[length-1] == '/' {
 		length--
 	}
@@ -300,7 +286,7 @@ func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
 	i := strings.LastIndex(name[:length], "/")
 	nlen := len(name) - i - 1 // nlen is length of suffix
 	plen := i                 // plen is length of prefix
-	if i <= 0 || nlen > fileNameSize || nlen == 0 || plen > fileNamePrefixSize {
+	if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize {
 		return "", "", false
 	}
 	return name[:i], name[i+1:], true
@@ -316,15 +302,15 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
 	// succeed, and seems harmless enough.
 	ext.ModTime = hdr.ModTime
 	// The spec asks that we namespace our pseudo files
-	// with the current pid.  However, this results in differing outputs
-	// for identical inputs.  As such, the constant 0 is now used instead.
+	// with the current pid. However, this results in differing outputs
+	// for identical inputs. As such, the constant 0 is now used instead.
 	// golang.org/issue/12358
 	dir, file := path.Split(hdr.Name)
 	fullName := path.Join(dir, "PaxHeaders.0", file)
 
 	ascii := toASCII(fullName)
-	if len(ascii) > 100 {
-		ascii = ascii[:100]
+	if len(ascii) > nameSize {
+		ascii = ascii[:nameSize]
 	}
 	ext.Name = ascii
 	// Construct the body
@@ -407,7 +393,7 @@ func (tw *Writer) Close() error {
 
 	// trailer: two zero blocks
 	for i := 0; i < 2; i++ {
-		_, tw.err = tw.w.Write(zeroBlock)
+		_, tw.err = tw.w.Write(zeroBlock[:])
 		if tw.err != nil {
 			break
 		}
diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go
index 6e91d90..27aa8e5 100644
--- a/src/archive/tar/writer_test.go
+++ b/src/archive/tar/writer_test.go
@@ -587,17 +587,17 @@ func TestSplitUSTARPath(t *testing.T) {
 		{"", "", "", false},
 		{"abc", "", "", false},
 		{"用戶名", "", "", false},
-		{sr("a", fileNameSize), "", "", false},
-		{sr("a", fileNameSize) + "/", "", "", false},
-		{sr("a", fileNameSize) + "/a", sr("a", fileNameSize), "a", true},
-		{sr("a", fileNamePrefixSize) + "/", "", "", false},
-		{sr("a", fileNamePrefixSize) + "/a", sr("a", fileNamePrefixSize), "a", true},
-		{sr("a", fileNameSize+1), "", "", false},
-		{sr("/", fileNameSize+1), sr("/", fileNameSize-1), "/", true},
-		{sr("a", fileNamePrefixSize) + "/" + sr("b", fileNameSize),
-			sr("a", fileNamePrefixSize), sr("b", fileNameSize), true},
-		{sr("a", fileNamePrefixSize) + "//" + sr("b", fileNameSize), "", "", false},
-		{sr("a/", fileNameSize), sr("a/", 77) + "a", sr("a/", 22), true},
+		{sr("a", nameSize), "", "", false},
+		{sr("a", nameSize) + "/", "", "", false},
+		{sr("a", nameSize) + "/a", sr("a", nameSize), "a", true},
+		{sr("a", prefixSize) + "/", "", "", false},
+		{sr("a", prefixSize) + "/a", sr("a", prefixSize), "a", true},
+		{sr("a", nameSize+1), "", "", false},
+		{sr("/", nameSize+1), sr("/", nameSize-1), "/", true},
+		{sr("a", prefixSize) + "/" + sr("b", nameSize),
+			sr("a", prefixSize), sr("b", nameSize), true},
+		{sr("a", prefixSize) + "//" + sr("b", nameSize), "", "", false},
+		{sr("a/", nameSize), sr("a/", 77) + "a", sr("a/", 22), true},
 	}
 
 	for _, v := range vectors {
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index 10e8172..f6c3ead 100644
--- a/src/archive/zip/reader.go
+++ b/src/archive/zip/reader.go
@@ -87,7 +87,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
 	z.File = make([]*File, 0, end.directoryRecords)
 	z.Comment = end.comment
 	rs := io.NewSectionReader(r, 0, size)
-	if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil {
+	if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil {
 		return err
 	}
 	buf := bufio.NewReader(rs)
@@ -153,19 +153,18 @@ func (f *File) DataOffset() (offset int64, err error) {
 
 // Open returns a ReadCloser that provides access to the File's contents.
 // Multiple files may be read concurrently.
-func (f *File) Open() (rc io.ReadCloser, err error) {
+func (f *File) Open() (io.ReadCloser, error) {
 	bodyOffset, err := f.findBodyOffset()
 	if err != nil {
-		return
+		return nil, err
 	}
 	size := int64(f.CompressedSize64)
 	r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
 	dcomp := f.zip.decompressor(f.Method)
 	if dcomp == nil {
-		err = ErrAlgorithm
-		return
+		return nil, ErrAlgorithm
 	}
-	rc = dcomp(r)
+	var rc io.ReadCloser = dcomp(r)
 	var desr io.Reader
 	if f.hasDataDescriptor() {
 		desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
@@ -176,7 +175,7 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
 		f:    f,
 		desr: desr,
 	}
-	return
+	return rc, nil
 }
 
 type checksumReader struct {
diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go
index 72cf5d9..dfaae78 100644
--- a/src/archive/zip/reader_test.go
+++ b/src/archive/zip/reader_test.go
@@ -399,7 +399,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
 	// Don't bother uncompressing: too big.
 	if ft.Content == nil && ft.File == "" && ft.Size > 0 {
 		if size != ft.Size {
-			t.Errorf("%v: uncompressed size %#x, want %#x", size, ft.Size)
+			t.Errorf("%v: uncompressed size %#x, want %#x", ft.Name, size, ft.Size)
 		}
 		r.Close()
 		return
diff --git a/src/archive/zip/register.go b/src/archive/zip/register.go
index 8fccbf7..2e76386 100644
--- a/src/archive/zip/register.go
+++ b/src/archive/zip/register.go
@@ -64,6 +64,44 @@ func (w *pooledFlateWriter) Close() error {
 	return err
 }
 
+var flateReaderPool sync.Pool
+
+func newFlateReader(r io.Reader) io.ReadCloser {
+	fr, ok := flateReaderPool.Get().(io.ReadCloser)
+	if ok {
+		fr.(flate.Resetter).Reset(r, nil)
+	} else {
+		fr = flate.NewReader(r)
+	}
+	return &pooledFlateReader{fr: fr}
+}
+
+type pooledFlateReader struct {
+	mu sync.Mutex // guards Close and Read
+	fr io.ReadCloser
+}
+
+func (r *pooledFlateReader) Read(p []byte) (n int, err error) {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	if r.fr == nil {
+		return 0, errors.New("Read after Close")
+	}
+	return r.fr.Read(p)
+}
+
+func (r *pooledFlateReader) Close() error {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+	var err error
+	if r.fr != nil {
+		err = r.fr.Close()
+		flateReaderPool.Put(r.fr)
+		r.fr = nil
+	}
+	return err
+}
+
 var (
 	mu sync.RWMutex // guards compressor and decompressor maps
 
@@ -74,7 +112,7 @@ var (
 
 	decompressors = map[uint16]Decompressor{
 		Store:   ioutil.NopCloser,
-		Deflate: flate.NewReader,
+		Deflate: newFlateReader,
 	}
 )
 
diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go
index 5ee4f88..e92d02f 100644
--- a/src/archive/zip/struct.go
+++ b/src/archive/zip/struct.go
@@ -5,7 +5,7 @@
 /*
 Package zip provides support for reading and writing ZIP archives.
 
-See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+See: https://www.pkware.com/documents/casestudies/APPNOTE.TXT
 
 This package does not support disk spanning.
 
diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go
index 5ce66e6..3a9292e 100644
--- a/src/archive/zip/writer.go
+++ b/src/archive/zip/writer.go
@@ -52,7 +52,7 @@ func (w *Writer) Flush() error {
 }
 
 // Close finishes writing the zip file by writing the central directory.
-// It does not (and can not) close the underlying writer.
+// It does not (and cannot) close the underlying writer.
 func (w *Writer) Close() error {
 	if w.last != nil && !w.last.closed {
 		if err := w.last.close(); err != nil {
diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go
index 01b63f2..86841c7 100644
--- a/src/archive/zip/writer_test.go
+++ b/src/archive/zip/writer_test.go
@@ -184,7 +184,7 @@ func BenchmarkCompressedZipGarbage(b *testing.B) {
 	b.ReportAllocs()
 	var buf bytes.Buffer
 	bigBuf := bytes.Repeat([]byte("a"), 1<<20)
-	for i := 0; i < b.N; i++ {
+	for i := 0; i <= b.N; i++ {
 		buf.Reset()
 		zw := NewWriter(&buf)
 		for j := 0; j < 3; j++ {
@@ -195,5 +195,11 @@ func BenchmarkCompressedZipGarbage(b *testing.B) {
 			w.Write(bigBuf)
 		}
 		zw.Close()
+		if i == 0 {
+			// Reset the timer after the first time through.
+			// This effectively discards the very large initial flate setup cost,
+			// as well as the initialization of bigBuf.
+			b.ResetTimer()
+		}
 	}
 }
diff --git a/src/archive/zip/zip_test.go b/src/archive/zip/zip_test.go
index f785abf..3a3c915 100644
--- a/src/archive/zip/zip_test.go
+++ b/src/archive/zip/zip_test.go
@@ -366,27 +366,6 @@ func testZip64DirectoryRecordLength(buf *rleBuffer, t *testing.T) {
 	}
 }
 
-func testInvalidHeader(h *FileHeader, t *testing.T) {
-	var buf bytes.Buffer
-	z := NewWriter(&buf)
-
-	f, err := z.CreateHeader(h)
-	if err != nil {
-		t.Fatalf("error creating header: %v", err)
-	}
-	if _, err := f.Write([]byte("hi")); err != nil {
-		t.Fatalf("error writing content: %v", err)
-	}
-	if err := z.Close(); err != nil {
-		t.Fatalf("error closing zip writer: %v", err)
-	}
-
-	b := buf.Bytes()
-	if _, err = NewReader(bytes.NewReader(b), int64(len(b))); err != ErrFormat {
-		t.Fatalf("got %v, expected ErrFormat", err)
-	}
-}
-
 func testValidHeader(h *FileHeader, t *testing.T) {
 	var buf bytes.Buffer
 	z := NewWriter(&buf)
diff --git a/src/bootstrap.bash b/src/bootstrap.bash
index 7947e84..da3dff4 100755
--- a/src/bootstrap.bash
+++ b/src/bootstrap.bash
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-# Copyright 2015 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.
 
diff --git a/src/bufio/bufio.go b/src/bufio/bufio.go
index 6a70f70..3b30b8b 100644
--- a/src/bufio/bufio.go
+++ b/src/bufio/bufio.go
@@ -124,14 +124,16 @@ func (b *Reader) Peek(n int) ([]byte, error) {
 	if n < 0 {
 		return nil, ErrNegativeCount
 	}
-	if n > len(b.buf) {
-		return nil, ErrBufferFull
-	}
-	// 0 <= n <= len(b.buf)
-	for b.w-b.r < n && b.err == nil {
+
+	for b.w-b.r < n && b.w-b.r < len(b.buf) && b.err == nil {
 		b.fill() // b.w-b.r < len(b.buf) => buffer is not full
 	}
 
+	if n > len(b.buf) {
+		return b.buf[b.r:b.w], ErrBufferFull
+	}
+
+	// 0 <= n <= len(b.buf)
 	var err error
 	if avail := b.w - b.r; avail < n {
 		// not enough data in buffer
@@ -220,7 +222,7 @@ func (b *Reader) Read(p []byte) (n int, err error) {
 
 // ReadByte reads and returns a single byte.
 // If no byte is available, returns an error.
-func (b *Reader) ReadByte() (c byte, err error) {
+func (b *Reader) ReadByte() (byte, error) {
 	b.lastRuneSize = -1
 	for b.r == b.w {
 		if b.err != nil {
@@ -228,13 +230,13 @@ func (b *Reader) ReadByte() (c byte, err error) {
 		}
 		b.fill() // buffer is empty
 	}
-	c = b.buf[b.r]
+	c := b.buf[b.r]
 	b.r++
 	b.lastByte = int(c)
 	return c, nil
 }
 
-// UnreadByte unreads the last byte.  Only the most recently read byte can be unread.
+// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
 func (b *Reader) UnreadByte() error {
 	if b.lastByte < 0 || b.r == 0 && b.w > 0 {
 		return ErrInvalidUnreadByte
@@ -264,7 +266,7 @@ func (b *Reader) ReadRune() (r rune, size int, err error) {
 		return 0, 0, b.readErr()
 	}
 	r, size = rune(b.buf[b.r]), 1
-	if r >= 0x80 {
+	if r >= utf8.RuneSelf {
 		r, size = utf8.DecodeRune(b.buf[b.r:b.w])
 	}
 	b.r += size
@@ -273,7 +275,7 @@ func (b *Reader) ReadRune() (r rune, size int, err error) {
 	return r, size, nil
 }
 
-// UnreadRune unreads the last rune.  If the most recent read operation on
+// UnreadRune unreads the last rune. If the most recent read operation on
 // the buffer was not a ReadRune, UnreadRune returns an error.  (In this
 // regard it is stricter than UnreadByte, which will unread the last byte
 // from any read operation.)
@@ -395,12 +397,12 @@ func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
 // ReadBytes returns err != nil if and only if the returned data does not end in
 // delim.
 // For simple uses, a Scanner may be more convenient.
-func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
+func (b *Reader) ReadBytes(delim byte) ([]byte, error) {
 	// Use ReadSlice to look for array,
 	// accumulating full buffers.
 	var frag []byte
 	var full [][]byte
-
+	var err error
 	for {
 		var e error
 		frag, e = b.ReadSlice(delim)
@@ -442,10 +444,9 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
 // ReadString returns err != nil if and only if the returned data does not end in
 // delim.
 // For simple uses, a Scanner may be more convenient.
-func (b *Reader) ReadString(delim byte) (line string, err error) {
+func (b *Reader) ReadString(delim byte) (string, error) {
 	bytes, err := b.ReadBytes(delim)
-	line = string(bytes)
-	return line, err
+	return string(bytes), err
 }
 
 // WriteTo implements io.WriterTo.
@@ -705,7 +706,7 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
 		}
 	}
 	if err == io.EOF {
-		// If we filled the buffer exactly, flush pre-emptively.
+		// If we filled the buffer exactly, flush preemptively.
 		if b.Available() == 0 {
 			err = b.flush()
 		} else {
diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go
index 666c44e..8580486 100644
--- a/src/bufio/bufio_test.go
+++ b/src/bufio/bufio_test.go
@@ -673,8 +673,8 @@ func TestPeek(t *testing.T) {
 	if _, err := buf.Peek(-1); err != ErrNegativeCount {
 		t.Fatalf("want ErrNegativeCount got %v", err)
 	}
-	if _, err := buf.Peek(32); err != ErrBufferFull {
-		t.Fatalf("want ErrBufFull got %v", err)
+	if s, err := buf.Peek(32); string(s) != "abcdefghijklmnop" || err != ErrBufferFull {
+		t.Fatalf("want %q, ErrBufFull got %q, err=%v", "abcdefghijklmnop", string(s), err)
 	}
 	if _, err := buf.Read(p[0:3]); string(p[0:3]) != "abc" || err != nil {
 		t.Fatalf("want %q got %q, err=%v", "abc", string(p[0:3]), err)
@@ -1475,7 +1475,7 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) {
 		b.Fatal("ioutil.Discard doesn't support ReaderFrom")
 	}
 	for i := 0; i < b.N; i++ {
-		r.Seek(0, 0)
+		r.Seek(0, io.SeekStart)
 		srcReader.Reset(onlyReader{r})
 		n, err := srcReader.WriteTo(ioutil.Discard)
 		if err != nil {
diff --git a/src/bufio/scan_test.go b/src/bufio/scan_test.go
index 07b1a56..1bb1e88 100644
--- a/src/bufio/scan_test.go
+++ b/src/bufio/scan_test.go
@@ -264,10 +264,6 @@ func testNoNewline(text string, lines []string, t *testing.T) {
 	}
 }
 
-var noNewlineLines = []string{
-	"abcdefghijklmn\nopqrstuvwxyz",
-}
-
 // Test that the line splitter handles a final line without a newline.
 func TestScanLineNoNewline(t *testing.T) {
 	const text = "abcdefghijklmn\nopqrstuvwxyz"
@@ -351,7 +347,7 @@ func TestSplitError(t *testing.T) {
 // Test that an EOF is overridden by a user-generated scan error.
 func TestErrAtEOF(t *testing.T) {
 	s := NewScanner(strings.NewReader("1 2 33"))
-	// This spitter will fail on last entry, after s.err==EOF.
+	// This splitter will fail on last entry, after s.err==EOF.
 	split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
 		advance, token, err = ScanWords(data, atEOF)
 		if len(token) > 1 {
diff --git a/src/buildall.bash b/src/buildall.bash
index f686dd8..a322fe5 100755
--- a/src/buildall.bash
+++ b/src/buildall.bash
@@ -32,13 +32,13 @@ 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 | sed -e 's|linux-mips64x|linux-mips64 linux-mips64le|' | 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)"
 
+# put linux, nacl first in the target list to get all the architectures up front.
+targets="$((../bin/go tool dist list | sed -n 's/^\(.*\)\/\(.*\)/\1-\2/p'; echo linux-386-387 linux-arm-arm5) | sort | egrep -v android-arm | egrep "$pattern" | egrep 'linux|nacl')
+$(../bin/go tool dist list | sed -n 's/^\(.*\)\/\(.*\)/\1-\2/p' | egrep -v 'android-arm|darwin-arm' | egrep "$pattern" | egrep -v 'linux|nacl')"
+
 failed=false
 for target in $targets
 do
diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go
index ddaba3b..9154a1b 100644
--- a/src/bytes/buffer.go
+++ b/src/bytes/buffer.go
@@ -17,8 +17,8 @@ import (
 type Buffer struct {
 	buf       []byte            // contents are the bytes buf[off : len(buf)]
 	off       int               // read at &buf[off], write at &buf[len(buf)]
-	runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
-	bootstrap [64]byte          // memory to hold first slice; helps small buffers (Printf) avoid allocation.
+	runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each call to WriteRune
+	bootstrap [64]byte          // memory to hold first slice; helps small buffers avoid allocation.
 	lastRead  readOp            // last read operation, so that Unread* can work correctly.
 }
 
@@ -44,7 +44,7 @@ var ErrTooLarge = errors.New("bytes.Buffer: too large")
 func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
 
 // String returns the contents of the unread portion of the buffer
-// as a string.  If the Buffer is a nil pointer, it returns "<nil>".
+// as a string. If the Buffer is a nil pointer, it returns "<nil>".
 func (b *Buffer) String() string {
 	if b == nil {
 		// Special case, useful in debugging.
@@ -145,7 +145,7 @@ func (b *Buffer) WriteString(s string) (n int, err error) {
 }
 
 // MinRead is the minimum slice size passed to a Read call by
-// Buffer.ReadFrom.  As long as the Buffer has at least MinRead bytes beyond
+// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond
 // what is required to hold the contents of r, ReadFrom will not grow the
 // underlying buffer.
 const MinRead = 512
@@ -252,7 +252,7 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) {
 }
 
 // Read reads the next len(p) bytes from the buffer or until the buffer
-// is drained.  The return value n is the number of bytes read.  If the
+// is drained. The return value n is the number of bytes read. If the
 // buffer has no data to return, err is io.EOF (unless len(p) is zero);
 // otherwise it is nil.
 func (b *Buffer) Read(p []byte) (n int, err error) {
@@ -293,14 +293,14 @@ func (b *Buffer) Next(n int) []byte {
 
 // ReadByte reads and returns the next byte from the buffer.
 // If no byte is available, it returns error io.EOF.
-func (b *Buffer) ReadByte() (c byte, err error) {
+func (b *Buffer) ReadByte() (byte, error) {
 	b.lastRead = opInvalid
 	if b.off >= len(b.buf) {
 		// Buffer is empty, reset to recover space.
 		b.Truncate(0)
 		return 0, io.EOF
 	}
-	c = b.buf[b.off]
+	c := b.buf[b.off]
 	b.off++
 	b.lastRead = opRead
 	return c, nil
@@ -347,7 +347,7 @@ func (b *Buffer) UnreadRune() error {
 }
 
 // UnreadByte unreads the last byte returned by the most recent
-// read operation.  If write has happened since the last read, UnreadByte
+// read operation. If write has happened since the last read, UnreadByte
 // returns an error.
 func (b *Buffer) UnreadByte() error {
 	if b.lastRead != opReadRune && b.lastRead != opRead {
@@ -400,7 +400,7 @@ func (b *Buffer) ReadString(delim byte) (line string, err error) {
 }
 
 // NewBuffer creates and initializes a new Buffer using buf as its initial
-// contents.  It is intended to prepare a Buffer to read existing data.  It
+// contents. It is intended to prepare a Buffer to read existing data. It
 // can also be used to size the internal buffer for writing. To do that,
 // buf should have the desired capacity but a length of zero.
 //
diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index b868240..305c85d 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -83,6 +83,16 @@ func Contains(b, subslice []byte) bool {
 	return Index(b, subslice) != -1
 }
 
+// ContainsAny reports whether any of the UTF-8-encoded Unicode code points in chars are within b.
+func ContainsAny(b []byte, chars string) bool {
+	return IndexAny(b, chars) >= 0
+}
+
+// ContainsRune reports whether the Unicode code point r is within b.
+func ContainsRune(b []byte, r rune) bool {
+	return IndexRune(b, r) >= 0
+}
+
 // Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
 func Index(s, sep []byte) int {
 	n := len(sep)
@@ -164,7 +174,7 @@ func IndexRune(s []byte, r rune) int {
 
 // IndexAny interprets s as a sequence of UTF-8-encoded Unicode code points.
 // It returns the byte index of the first occurrence in s of any of the Unicode
-// code points in chars.  It returns -1 if chars is empty or if there is no code
+// code points in chars. It returns -1 if chars is empty or if there is no code
 // point in common.
 func IndexAny(s []byte, chars string) int {
 	if len(chars) > 0 {
@@ -188,8 +198,8 @@ func IndexAny(s []byte, chars string) int {
 }
 
 // LastIndexAny interprets s as a sequence of UTF-8-encoded Unicode code
-// points.  It returns the byte index of the last occurrence in s of any of
-// the Unicode code points in chars.  It returns -1 if chars is empty or if
+// points. It returns the byte index of the last occurrence in s of any of
+// the Unicode code points in chars. It returns -1 if chars is empty or if
 // there is no code point in common.
 func LastIndexAny(s []byte, chars string) int {
 	if len(chars) > 0 {
@@ -276,7 +286,7 @@ func Fields(s []byte) [][]byte {
 
 // FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
 // It splits the slice s at each run of code points c satisfying f(c) and
-// returns a slice of subslices of s.  If all code points in s satisfy f(c), or
+// returns a slice of subslices of s. If all code points in s satisfy f(c), or
 // len(s) == 0, an empty slice is returned.
 // FieldsFunc makes no guarantees about the order in which it calls f(c).
 // If f does not return consistent results for a given c, FieldsFunc may crash.
@@ -352,12 +362,12 @@ func HasSuffix(s, suffix []byte) bool {
 
 // Map returns a copy of the byte slice s with all its characters modified
 // according to the mapping function. If mapping returns a negative value, the character is
-// dropped from the string with no replacement.  The characters in s and the
+// dropped from the string with no replacement. The characters in s and the
 // output are interpreted as UTF-8-encoded Unicode code points.
 func Map(mapping func(r rune) rune, s []byte) []byte {
 	// In the worst case, the slice can grow when mapped, making
-	// things unpleasant.  But it's so rare we barge in assuming it's
-	// fine.  It could also shrink but that falls out naturally.
+	// things unpleasant. But it's so rare we barge in assuming it's
+	// fine. It could also shrink but that falls out naturally.
 	maxbytes := len(s) // length of b
 	nbytes := 0        // number of bytes encoded in b
 	b := make([]byte, maxbytes)
@@ -697,7 +707,7 @@ func EqualFold(s, t []byte) bool {
 			return false
 		}
 
-		// General case.  SimpleFold(x) returns the next equivalent rune > x
+		// General case. SimpleFold(x) returns the next equivalent rune > x
 		// or wraps around to smaller values.
 		r := unicode.SimpleFold(sr)
 		for r != sr && r < tr {
@@ -709,6 +719,6 @@ func EqualFold(s, t []byte) bool {
 		return false
 	}
 
-	// One string is empty.  Are both?
+	// One string is empty. Are both?
 	return len(s) == len(t)
 }
diff --git a/src/bytes/bytes_decl.go b/src/bytes/bytes_decl.go
index b453f21..df0614f 100644
--- a/src/bytes/bytes_decl.go
+++ b/src/bytes/bytes_decl.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go
index 8df62fc..c48f662 100644
--- a/src/bytes/bytes_test.go
+++ b/src/bytes/bytes_test.go
@@ -6,6 +6,7 @@ package bytes_test
 
 import (
 	. "bytes"
+	"fmt"
 	"math/rand"
 	"reflect"
 	"testing"
@@ -47,32 +48,6 @@ type BinOpTest struct {
 	i int
 }
 
-var equalTests = []struct {
-	a, b []byte
-	i    int
-}{
-	{[]byte(""), []byte(""), 0},
-	{[]byte("a"), []byte(""), 1},
-	{[]byte(""), []byte("a"), -1},
-	{[]byte("abc"), []byte("abc"), 0},
-	{[]byte("ab"), []byte("abc"), -1},
-	{[]byte("abc"), []byte("ab"), 1},
-	{[]byte("x"), []byte("ab"), 1},
-	{[]byte("ab"), []byte("x"), -1},
-	{[]byte("x"), []byte("a"), 1},
-	{[]byte("b"), []byte("x"), -1},
-	// test runtime·memeq's chunked implementation
-	{[]byte("abcdefgh"), []byte("abcdefgh"), 0},
-	{[]byte("abcdefghi"), []byte("abcdefghi"), 0},
-	{[]byte("abcdefghi"), []byte("abcdefghj"), -1},
-	// nil tests
-	{nil, nil, 0},
-	{[]byte(""), nil, 0},
-	{nil, []byte(""), 0},
-	{[]byte("a"), nil, 1},
-	{nil, []byte("a"), -1},
-}
-
 func TestEqual(t *testing.T) {
 	for _, tt := range compareTests {
 		eql := Equal(tt.a, tt.b)
@@ -113,7 +88,7 @@ func TestEqualExhaustive(t *testing.T) {
 	}
 }
 
-// make sure Equal returns false for minimally different strings.  The data
+// make sure Equal returns false for minimally different strings. The data
 // is all zeros except for a single one in one location.
 func TestNotEqual(t *testing.T) {
 	var size = 128
@@ -335,6 +310,41 @@ func TestIndexByteBig(t *testing.T) {
 	}
 }
 
+// test a small index across all page offsets
+func TestIndexByteSmall(t *testing.T) {
+	b := make([]byte, 5015) // bigger than a page
+	// Make sure we find the correct byte even when straddling a page.
+	for i := 0; i <= len(b)-15; i++ {
+		for j := 0; j < 15; j++ {
+			b[i+j] = byte(100 + j)
+		}
+		for j := 0; j < 15; j++ {
+			p := IndexByte(b[i:i+15], byte(100+j))
+			if p != j {
+				t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 100+j, p)
+			}
+		}
+		for j := 0; j < 15; j++ {
+			b[i+j] = 0
+		}
+	}
+	// Make sure matches outside the slice never trigger.
+	for i := 0; i <= len(b)-15; i++ {
+		for j := 0; j < 15; j++ {
+			b[i+j] = 1
+		}
+		for j := 0; j < 15; j++ {
+			p := IndexByte(b[i:i+15], byte(0))
+			if p != -1 {
+				t.Errorf("IndexByte(%q, %d) = %d", b[i:i+15], 0, p)
+			}
+		}
+		for j := 0; j < 15; j++ {
+			b[i+j] = 0
+		}
+	}
+}
+
 func TestIndexRune(t *testing.T) {
 	for _, tt := range indexRuneTests {
 		a := []byte(tt.a)
@@ -348,165 +358,152 @@ func TestIndexRune(t *testing.T) {
 
 var bmbuf []byte
 
-func BenchmarkIndexByte32(b *testing.B)          { bmIndexByte(b, IndexByte, 32) }
-func BenchmarkIndexByte4K(b *testing.B)          { bmIndexByte(b, IndexByte, 4<<10) }
-func BenchmarkIndexByte4M(b *testing.B)          { bmIndexByte(b, IndexByte, 4<<20) }
-func BenchmarkIndexByte64M(b *testing.B)         { bmIndexByte(b, IndexByte, 64<<20) }
-func BenchmarkIndexBytePortable32(b *testing.B)  { bmIndexByte(b, IndexBytePortable, 32) }
-func BenchmarkIndexBytePortable4K(b *testing.B)  { bmIndexByte(b, IndexBytePortable, 4<<10) }
-func BenchmarkIndexBytePortable4M(b *testing.B)  { bmIndexByte(b, IndexBytePortable, 4<<20) }
-func BenchmarkIndexBytePortable64M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 64<<20) }
-
-func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
-	if len(bmbuf) < n {
-		bmbuf = make([]byte, n)
-	}
-	b.SetBytes(int64(n))
-	buf := bmbuf[0:n]
-	buf[n-1] = 'x'
-	for i := 0; i < b.N; i++ {
-		j := index(buf, 'x')
-		if j != n-1 {
-			b.Fatal("bad index", j)
-		}
+func valName(x int) string {
+	if s := x >> 20; s<<20 == x {
+		return fmt.Sprintf("%dM", s)
+	}
+	if s := x >> 10; s<<10 == x {
+		return fmt.Sprintf("%dK", s)
 	}
-	buf[n-1] = '\x00'
+	return fmt.Sprint(x)
 }
 
-func BenchmarkEqual0(b *testing.B) {
-	var buf [4]byte
-	buf1 := buf[0:0]
-	buf2 := buf[1:1]
-	for i := 0; i < b.N; i++ {
-		eq := Equal(buf1, buf2)
-		if !eq {
-			b.Fatal("bad equal")
-		}
-	}
-}
-
-func BenchmarkEqual1(b *testing.B)           { bmEqual(b, Equal, 1) }
-func BenchmarkEqual6(b *testing.B)           { bmEqual(b, Equal, 6) }
-func BenchmarkEqual9(b *testing.B)           { bmEqual(b, Equal, 9) }
-func BenchmarkEqual15(b *testing.B)          { bmEqual(b, Equal, 15) }
-func BenchmarkEqual16(b *testing.B)          { bmEqual(b, Equal, 16) }
-func BenchmarkEqual20(b *testing.B)          { bmEqual(b, Equal, 20) }
-func BenchmarkEqual32(b *testing.B)          { bmEqual(b, Equal, 32) }
-func BenchmarkEqual4K(b *testing.B)          { bmEqual(b, Equal, 4<<10) }
-func BenchmarkEqual4M(b *testing.B)          { bmEqual(b, Equal, 4<<20) }
-func BenchmarkEqual64M(b *testing.B)         { bmEqual(b, Equal, 64<<20) }
-func BenchmarkEqualPort1(b *testing.B)       { bmEqual(b, EqualPortable, 1) }
-func BenchmarkEqualPort6(b *testing.B)       { bmEqual(b, EqualPortable, 6) }
-func BenchmarkEqualPort32(b *testing.B)      { bmEqual(b, EqualPortable, 32) }
-func BenchmarkEqualPort4K(b *testing.B)      { bmEqual(b, EqualPortable, 4<<10) }
-func BenchmarkEqualPortable4M(b *testing.B)  { bmEqual(b, EqualPortable, 4<<20) }
-func BenchmarkEqualPortable64M(b *testing.B) { bmEqual(b, EqualPortable, 64<<20) }
-
-func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) {
-	if len(bmbuf) < 2*n {
-		bmbuf = make([]byte, 2*n)
-	}
-	b.SetBytes(int64(n))
-	buf1 := bmbuf[0:n]
-	buf2 := bmbuf[n : 2*n]
-	buf1[n-1] = 'x'
-	buf2[n-1] = 'x'
-	for i := 0; i < b.N; i++ {
-		eq := equal(buf1, buf2)
-		if !eq {
-			b.Fatal("bad equal")
-		}
+func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) {
+	for _, n := range sizes {
+		b.Run(valName(n), func(b *testing.B) {
+			if len(bmbuf) < n {
+				bmbuf = make([]byte, n)
+			}
+			b.SetBytes(int64(n))
+			f(b, n)
+		})
 	}
-	buf1[n-1] = '\x00'
-	buf2[n-1] = '\x00'
 }
 
-func BenchmarkIndex32(b *testing.B)  { bmIndex(b, Index, 32) }
-func BenchmarkIndex4K(b *testing.B)  { bmIndex(b, Index, 4<<10) }
-func BenchmarkIndex4M(b *testing.B)  { bmIndex(b, Index, 4<<20) }
-func BenchmarkIndex64M(b *testing.B) { bmIndex(b, Index, 64<<20) }
+var indexSizes = []int{10, 32, 4 << 10, 4 << 20, 64 << 20}
 
-func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) {
-	if len(bmbuf) < n {
-		bmbuf = make([]byte, n)
-	}
-	b.SetBytes(int64(n))
-	buf := bmbuf[0:n]
-	buf[n-1] = 'x'
-	for i := 0; i < b.N; i++ {
-		j := index(buf, buf[n-7:])
-		if j != n-7 {
-			b.Fatal("bad index", j)
-		}
-	}
-	buf[n-1] = '\x00'
+func BenchmarkIndexByte(b *testing.B) {
+	benchBytes(b, indexSizes, bmIndexByte(IndexByte))
 }
 
-func BenchmarkIndexEasy32(b *testing.B)  { bmIndexEasy(b, Index, 32) }
-func BenchmarkIndexEasy4K(b *testing.B)  { bmIndexEasy(b, Index, 4<<10) }
-func BenchmarkIndexEasy4M(b *testing.B)  { bmIndexEasy(b, Index, 4<<20) }
-func BenchmarkIndexEasy64M(b *testing.B) { bmIndexEasy(b, Index, 64<<20) }
+func BenchmarkIndexBytePortable(b *testing.B) {
+	benchBytes(b, indexSizes, bmIndexByte(IndexBytePortable))
+}
 
-func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) {
-	if len(bmbuf) < n {
-		bmbuf = make([]byte, n)
-	}
-	b.SetBytes(int64(n))
-	buf := bmbuf[0:n]
-	buf[n-1] = 'x'
-	buf[n-7] = 'x'
-	for i := 0; i < b.N; i++ {
-		j := index(buf, buf[n-7:])
-		if j != n-7 {
-			b.Fatal("bad index", j)
+func bmIndexByte(index func([]byte, byte) int) func(b *testing.B, n int) {
+	return func(b *testing.B, n int) {
+		buf := bmbuf[0:n]
+		buf[n-1] = 'x'
+		for i := 0; i < b.N; i++ {
+			j := index(buf, 'x')
+			if j != n-1 {
+				b.Fatal("bad index", j)
+			}
 		}
+		buf[n-1] = '\x00'
 	}
-	buf[n-1] = '\x00'
-	buf[n-7] = '\x00'
 }
 
-func BenchmarkCount32(b *testing.B)  { bmCount(b, Count, 32) }
-func BenchmarkCount4K(b *testing.B)  { bmCount(b, Count, 4<<10) }
-func BenchmarkCount4M(b *testing.B)  { bmCount(b, Count, 4<<20) }
-func BenchmarkCount64M(b *testing.B) { bmCount(b, Count, 64<<20) }
-
-func bmCount(b *testing.B, count func([]byte, []byte) int, n int) {
-	if len(bmbuf) < n {
-		bmbuf = make([]byte, n)
-	}
-	b.SetBytes(int64(n))
-	buf := bmbuf[0:n]
-	buf[n-1] = 'x'
-	for i := 0; i < b.N; i++ {
-		j := count(buf, buf[n-7:])
-		if j != 1 {
-			b.Fatal("bad count", j)
+func BenchmarkEqual(b *testing.B) {
+	b.Run("0", func(b *testing.B) {
+		var buf [4]byte
+		buf1 := buf[0:0]
+		buf2 := buf[1:1]
+		for i := 0; i < b.N; i++ {
+			eq := Equal(buf1, buf2)
+			if !eq {
+				b.Fatal("bad equal")
+			}
 		}
-	}
-	buf[n-1] = '\x00'
+	})
+
+	sizes := []int{1, 6, 9, 15, 16, 20, 32, 4 << 10, 4 << 20, 64 << 20}
+	benchBytes(b, sizes, bmEqual(Equal))
 }
 
-func BenchmarkCountEasy32(b *testing.B)  { bmCountEasy(b, Count, 32) }
-func BenchmarkCountEasy4K(b *testing.B)  { bmCountEasy(b, Count, 4<<10) }
-func BenchmarkCountEasy4M(b *testing.B)  { bmCountEasy(b, Count, 4<<20) }
-func BenchmarkCountEasy64M(b *testing.B) { bmCountEasy(b, Count, 64<<20) }
+func BenchmarkEqualPort(b *testing.B) {
+	sizes := []int{1, 6, 32, 4 << 10, 4 << 20, 64 << 20}
+	benchBytes(b, sizes, bmEqual(EqualPortable))
+}
 
-func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) {
-	if len(bmbuf) < n {
-		bmbuf = make([]byte, n)
-	}
-	b.SetBytes(int64(n))
-	buf := bmbuf[0:n]
-	buf[n-1] = 'x'
-	buf[n-7] = 'x'
-	for i := 0; i < b.N; i++ {
-		j := count(buf, buf[n-7:])
-		if j != 1 {
-			b.Fatal("bad count", j)
+func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) {
+	return func(b *testing.B, n int) {
+		if len(bmbuf) < 2*n {
+			bmbuf = make([]byte, 2*n)
+		}
+		buf1 := bmbuf[0:n]
+		buf2 := bmbuf[n : 2*n]
+		buf1[n-1] = 'x'
+		buf2[n-1] = 'x'
+		for i := 0; i < b.N; i++ {
+			eq := equal(buf1, buf2)
+			if !eq {
+				b.Fatal("bad equal")
+			}
 		}
+		buf1[n-1] = '\x00'
+		buf2[n-1] = '\x00'
 	}
-	buf[n-1] = '\x00'
-	buf[n-7] = '\x00'
+}
+
+func BenchmarkIndex(b *testing.B) {
+	benchBytes(b, indexSizes, func(b *testing.B, n int) {
+		buf := bmbuf[0:n]
+		buf[n-1] = 'x'
+		for i := 0; i < b.N; i++ {
+			j := Index(buf, buf[n-7:])
+			if j != n-7 {
+				b.Fatal("bad index", j)
+			}
+		}
+		buf[n-1] = '\x00'
+	})
+}
+
+func BenchmarkIndexEasy(b *testing.B) {
+	benchBytes(b, indexSizes, func(b *testing.B, n int) {
+		buf := bmbuf[0:n]
+		buf[n-1] = 'x'
+		buf[n-7] = 'x'
+		for i := 0; i < b.N; i++ {
+			j := Index(buf, buf[n-7:])
+			if j != n-7 {
+				b.Fatal("bad index", j)
+			}
+		}
+		buf[n-1] = '\x00'
+		buf[n-7] = '\x00'
+	})
+}
+
+func BenchmarkCount(b *testing.B) {
+	benchBytes(b, indexSizes, func(b *testing.B, n int) {
+		buf := bmbuf[0:n]
+		buf[n-1] = 'x'
+		for i := 0; i < b.N; i++ {
+			j := Count(buf, buf[n-7:])
+			if j != 1 {
+				b.Fatal("bad count", j)
+			}
+		}
+		buf[n-1] = '\x00'
+	})
+}
+
+func BenchmarkCountEasy(b *testing.B) {
+	benchBytes(b, indexSizes, func(b *testing.B, n int) {
+		buf := bmbuf[0:n]
+		buf[n-1] = 'x'
+		buf[n-7] = 'x'
+		for i := 0; i < b.N; i++ {
+			j := Count(buf, buf[n-7:])
+			if j != 1 {
+				b.Fatal("bad count", j)
+			}
+		}
+		buf[n-1] = '\x00'
+		buf[n-7] = '\x00'
+	})
 }
 
 type ExplodeTest struct {
@@ -760,7 +757,7 @@ func TestMap(t *testing.T) {
 	// Run a couple of awful growth/shrinkage tests
 	a := tenRunes('a')
 
-	// 1.  Grow.  This triggers two reallocations in Map.
+	// 1.  Grow. This triggers two reallocations in Map.
 	maxRune := func(r rune) rune { return unicode.MaxRune }
 	m := Map(maxRune, []byte(a))
 	expect := tenRunes(unicode.MaxRune)
@@ -1207,6 +1204,57 @@ func TestContains(t *testing.T) {
 	}
 }
 
+var ContainsAnyTests = []struct {
+	b        []byte
+	substr   string
+	expected bool
+}{
+	{[]byte(""), "", false},
+	{[]byte(""), "a", false},
+	{[]byte(""), "abc", false},
+	{[]byte("a"), "", false},
+	{[]byte("a"), "a", true},
+	{[]byte("aaa"), "a", true},
+	{[]byte("abc"), "xyz", false},
+	{[]byte("abc"), "xcz", true},
+	{[]byte("a☺b☻c☹d"), "uvw☻xyz", true},
+	{[]byte("aRegExp*"), ".(|)*+?^$[]", true},
+	{[]byte(dots + dots + dots), " ", false},
+}
+
+func TestContainsAny(t *testing.T) {
+	for _, ct := range ContainsAnyTests {
+		if ContainsAny(ct.b, ct.substr) != ct.expected {
+			t.Errorf("ContainsAny(%s, %s) = %v, want %v",
+				ct.b, ct.substr, !ct.expected, ct.expected)
+		}
+	}
+}
+
+var ContainsRuneTests = []struct {
+	b        []byte
+	r        rune
+	expected bool
+}{
+	{[]byte(""), 'a', false},
+	{[]byte("a"), 'a', true},
+	{[]byte("aaa"), 'a', true},
+	{[]byte("abc"), 'y', false},
+	{[]byte("abc"), 'c', true},
+	{[]byte("a☺b☻c☹d"), 'x', false},
+	{[]byte("a☺b☻c☹d"), '☻', true},
+	{[]byte("aRegExp*"), '*', true},
+}
+
+func TestContainsRune(t *testing.T) {
+	for _, ct := range ContainsRuneTests {
+		if ContainsRune(ct.b, ct.r) != ct.expected {
+			t.Errorf("ContainsRune(%q, %q) = %v, want %v",
+				ct.b, ct.r, !ct.expected, ct.expected)
+		}
+	}
+}
+
 var makeFieldsInput = func() []byte {
 	x := make([]byte, 1<<20)
 	// Input is ~10% space, ~10% 2-byte UTF-8, rest ASCII non-space.
@@ -1256,33 +1304,24 @@ func BenchmarkRepeat(b *testing.B) {
 	}
 }
 
-func benchmarkBytesCompare(b *testing.B, n int) {
-	var x = make([]byte, n)
-	var y = make([]byte, n)
+func BenchmarkBytesCompare(b *testing.B) {
+	for n := 1; n <= 2048; n <<= 1 {
+		b.Run(fmt.Sprint(n), func(b *testing.B) {
+			var x = make([]byte, n)
+			var y = make([]byte, n)
 
-	for i := 0; i < n; i++ {
-		x[i] = 'a'
-	}
+			for i := 0; i < n; i++ {
+				x[i] = 'a'
+			}
 
-	for i := 0; i < n; i++ {
-		y[i] = 'a'
-	}
+			for i := 0; i < n; i++ {
+				y[i] = 'a'
+			}
 
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		Compare(x, y)
-	}
-}
-
-func BenchmarkBytesCompare1(b *testing.B)    { benchmarkBytesCompare(b, 1) }
-func BenchmarkBytesCompare2(b *testing.B)    { benchmarkBytesCompare(b, 2) }
-func BenchmarkBytesCompare4(b *testing.B)    { benchmarkBytesCompare(b, 4) }
-func BenchmarkBytesCompare8(b *testing.B)    { benchmarkBytesCompare(b, 8) }
-func BenchmarkBytesCompare16(b *testing.B)   { benchmarkBytesCompare(b, 16) }
-func BenchmarkBytesCompare32(b *testing.B)   { benchmarkBytesCompare(b, 32) }
-func BenchmarkBytesCompare64(b *testing.B)   { benchmarkBytesCompare(b, 64) }
-func BenchmarkBytesCompare128(b *testing.B)  { benchmarkBytesCompare(b, 128) }
-func BenchmarkBytesCompare256(b *testing.B)  { benchmarkBytesCompare(b, 256) }
-func BenchmarkBytesCompare512(b *testing.B)  { benchmarkBytesCompare(b, 512) }
-func BenchmarkBytesCompare1024(b *testing.B) { benchmarkBytesCompare(b, 1024) }
-func BenchmarkBytesCompare2048(b *testing.B) { benchmarkBytesCompare(b, 2048) }
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				Compare(x, y)
+			}
+		})
+	}
+}
diff --git a/src/bytes/compare_test.go b/src/bytes/compare_test.go
index f2d81d5..35088a1 100644
--- a/src/bytes/compare_test.go
+++ b/src/bytes/compare_test.go
@@ -62,7 +62,7 @@ func TestCompareBytes(t *testing.T) {
 	a := make([]byte, n+1)
 	b := make([]byte, n+1)
 	for len := 0; len < 128; len++ {
-		// randomish but deterministic data.  No 0 or 255.
+		// 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)
diff --git a/src/bytes/equal_test.go b/src/bytes/equal_test.go
index 1bf19a7..9fdead8 100644
--- a/src/bytes/equal_test.go
+++ b/src/bytes/equal_test.go
@@ -14,11 +14,11 @@ import (
 )
 
 // This file tests the situation where memeq is checking
-// data very near to a page boundary.  We want to make sure
+// data very near to a page boundary. We want to make sure
 // equal does not read across the boundary and cause a page
 // fault where it shouldn't.
 
-// This test runs only on linux.  The code being tested is
+// This test runs only on linux. The code being tested is
 // not OS-specific, so it does not need to be tested on all
 // operating systems.
 
diff --git a/src/bytes/reader.go b/src/bytes/reader.go
index b89d154..28cfc7a 100644
--- a/src/bytes/reader.go
+++ b/src/bytes/reader.go
@@ -36,9 +36,6 @@ func (r *Reader) Len() int {
 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
-	}
 	if r.i >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
@@ -63,14 +60,14 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
 	return
 }
 
-func (r *Reader) ReadByte() (b byte, err error) {
+func (r *Reader) ReadByte() (byte, error) {
 	r.prevRune = -1
 	if r.i >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
-	b = r.s[r.i]
+	b := r.s[r.i]
 	r.i++
-	return
+	return b, nil
 }
 
 func (r *Reader) UnreadByte() error {
@@ -111,11 +108,11 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
 	r.prevRune = -1
 	var abs int64
 	switch whence {
-	case 0:
+	case io.SeekStart:
 		abs = offset
-	case 1:
-		abs = int64(r.i) + offset
-	case 2:
+	case io.SeekCurrent:
+		abs = r.i + offset
+	case io.SeekEnd:
 		abs = int64(len(r.s)) + offset
 	default:
 		return 0, errors.New("bytes.Reader.Seek: invalid whence")
@@ -146,5 +143,8 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
 	return
 }
 
+// Reset resets the Reader to be reading from b.
+func (r *Reader) Reset(b []byte) { *r = Reader{b, 0, -1} }
+
 // NewReader returns a new Reader reading from b.
 func NewReader(b []byte) *Reader { return &Reader{b, 0, -1} }
diff --git a/src/bytes/reader_test.go b/src/bytes/reader_test.go
index b929a28..7b3034d 100644
--- a/src/bytes/reader_test.go
+++ b/src/bytes/reader_test.go
@@ -9,7 +9,6 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
-	"os"
 	"sync"
 	"testing"
 )
@@ -22,17 +21,18 @@ func TestReader(t *testing.T) {
 		n       int
 		want    string
 		wantpos int64
+		readerr error
 		seekerr string
 	}{
-		{seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
-		{seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
-		{seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
-		{seek: os.SEEK_SET, off: -1, seekerr: "bytes.Reader.Seek: negative position"},
-		{seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
-		{seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
-		{seek: os.SEEK_SET, n: 5, want: "01234"},
-		{seek: os.SEEK_CUR, n: 5, want: "56789"},
-		{seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
+		{seek: io.SeekStart, off: 0, n: 20, want: "0123456789"},
+		{seek: io.SeekStart, off: 1, n: 1, want: "1"},
+		{seek: io.SeekCurrent, off: 1, wantpos: 3, n: 2, want: "34"},
+		{seek: io.SeekStart, off: -1, seekerr: "bytes.Reader.Seek: negative position"},
+		{seek: io.SeekStart, off: 1 << 33, wantpos: 1 << 33, readerr: io.EOF},
+		{seek: io.SeekCurrent, off: 1, wantpos: 1<<33 + 1, readerr: io.EOF},
+		{seek: io.SeekStart, n: 5, want: "01234"},
+		{seek: io.SeekCurrent, n: 5, want: "56789"},
+		{seek: io.SeekEnd, off: -1, n: 1, wantpos: 9, want: "9"},
 	}
 
 	for i, tt := range tests {
@@ -50,8 +50,8 @@ func TestReader(t *testing.T) {
 		}
 		buf := make([]byte, tt.n)
 		n, err := r.Read(buf)
-		if err != nil {
-			t.Errorf("%d. read = %v", i, err)
+		if err != tt.readerr {
+			t.Errorf("%d. read = %v; want %v", i, err, tt.readerr)
 			continue
 		}
 		got := string(buf[:n])
@@ -63,7 +63,7 @@ func TestReader(t *testing.T) {
 
 func TestReadAfterBigSeek(t *testing.T) {
 	r := NewReader([]byte("0123456789"))
-	if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+	if _, err := r.Seek(1<<31+5, io.SeekStart); err != nil {
 		t.Fatal(err)
 	}
 	if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
@@ -174,7 +174,7 @@ func TestReaderLen(t *testing.T) {
 		t.Errorf("r.Len(): got %d, want %d", got, want)
 	}
 	if n, err := r.Read(make([]byte, 1)); err != nil || n != 1 {
-		t.Errorf("Read failed: read %d %v", n, err)
+		t.Errorf("Read failed: read %d %v; want 1, nil", n, err)
 	}
 	if got, want := r.Len(), 0; got != want {
 		t.Errorf("r.Len(): got %d, want %d", got, want)
@@ -188,7 +188,7 @@ var UnreadRuneErrorTests = []struct {
 	{"Read", func(r *Reader) { r.Read([]byte{0}) }},
 	{"ReadByte", func(r *Reader) { r.ReadByte() }},
 	{"UnreadRune", func(r *Reader) { r.UnreadRune() }},
-	{"Seek", func(r *Reader) { r.Seek(0, 1) }},
+	{"Seek", func(r *Reader) { r.Seek(0, io.SeekCurrent) }},
 	{"WriteTo", func(r *Reader) { r.WriteTo(&Buffer{}) }},
 }
 
@@ -256,3 +256,23 @@ func TestReaderLenSize(t *testing.T) {
 		t.Errorf("Size = %d; want 3", r.Size())
 	}
 }
+
+func TestReaderReset(t *testing.T) {
+	r := NewReader([]byte("世界"))
+	if _, _, err := r.ReadRune(); err != nil {
+		t.Errorf("ReadRune: unexpected error: %v", err)
+	}
+
+	const want = "abcdef"
+	r.Reset([]byte(want))
+	if err := r.UnreadRune(); err == nil {
+		t.Errorf("UnreadRune: expected error, got nil")
+	}
+	buf, err := ioutil.ReadAll(r)
+	if err != nil {
+		t.Errorf("ReadAll: unexpected error: %v", err)
+	}
+	if got := string(buf); got != want {
+		t.Errorf("ReadAll: got %q, want %q", got, want)
+	}
+}
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 8b20d12..e9c9147 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -143,6 +143,11 @@ func main() {
 		w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
 
 		for _, name := range pkgNames {
+			// Vendored packages do not contribute to our
+			// public API surface.
+			if strings.HasPrefix(name, "vendor/") {
+				continue
+			}
 			// - Package "unsafe" contains special signatures requiring
 			//   extra care when printing them - ignore since it is not
 			//   going to change w/o a language change.
@@ -368,15 +373,6 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
 	return f, nil
 }
 
-func contains(list []string, s string) bool {
-	for _, t := range list {
-		if t == s {
-			return true
-		}
-	}
-	return false
-}
-
 // The package cache doesn't operate correctly in rare (so far artificial)
 // circumstances (issue 8425). Disable before debugging non-obvious errors
 // from the type-checker.
diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go
index 1d2cc9a..0d00f6a 100644
--- a/src/cmd/api/goapi_test.go
+++ b/src/cmd/api/goapi_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -178,7 +178,7 @@ func BenchmarkAll(b *testing.B) {
 		for _, context := range contexts {
 			w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
 			for _, name := range pkgNames {
-				if name != "unsafe" && !strings.HasPrefix(name, "cmd/") {
+				if name != "unsafe" && !strings.HasPrefix(name, "cmd/") && !internalPkg.MatchString(name) {
 					pkg, _ := w.Import(name)
 					w.export(pkg)
 				}
diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go
index 2c1ad87..c8433c5 100644
--- a/src/cmd/api/run.go
+++ b/src/cmd/api/run.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -26,7 +26,7 @@ func main() {
 	}
 
 	out, err := exec.Command("go", "tool", "api",
-		"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6"),
+		"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7"),
 		"-next", file("next"),
 		"-except", file("except")).CombinedOutput()
 	if err != nil {
diff --git a/src/cmd/asm/doc.go b/src/cmd/asm/doc.go
index a9c8bfb..aa62147 100644
--- a/src/cmd/asm/doc.go
+++ b/src/cmd/asm/doc.go
@@ -20,7 +20,7 @@ The GOOS and GOARCH environment variables set the desired target.
 Flags:
 
 	-D value
-		predefined symbol with optional simple value -D=identifer=value;
+		predefined symbol with optional simple value -D=identifier=value;
 		can be set multiple times
 	-I value
 		include directory; can be set multiple times
diff --git a/src/cmd/asm/internal/arch/amd64.go b/src/cmd/asm/internal/arch/amd64.go
new file mode 100644
index 0000000..625e136
--- /dev/null
+++ b/src/cmd/asm/internal/arch/amd64.go
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go 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
+// AMD64 instruction set, to minimize its interaction
+// with the core of the assembler.
+
+package arch
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+// IsAMD4OP reports whether the op (as defined by an ppc64.A* constant) is
+// The FMADD-like instructions behave similarly.
+func IsAMD4OP(op obj.As) bool {
+	switch op {
+	case x86.AVPERM2F128,
+		x86.AVPALIGNR,
+		x86.AVPERM2I128,
+		x86.AVINSERTI128,
+		x86.AVPBLENDD:
+		return true
+	}
+	return false
+}
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
index c14a13c..4b5b46a 100644
--- a/src/cmd/asm/internal/arch/arch.go
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -10,6 +10,7 @@ import (
 	"cmd/internal/obj/arm64"
 	"cmd/internal/obj/mips"
 	"cmd/internal/obj/ppc64"
+	"cmd/internal/obj/s390x"
 	"cmd/internal/obj/x86"
 	"fmt"
 	"strings"
@@ -27,7 +28,7 @@ const (
 type Arch struct {
 	*obj.LinkArch
 	// Map of instruction names to enumeration.
-	Instructions map[string]int
+	Instructions map[string]obj.As
 	// 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).
@@ -44,14 +45,6 @@ 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 {
@@ -82,6 +75,10 @@ func Set(GOARCH string) *Arch {
 		a := archPPC64()
 		a.LinkArch = &ppc64.Linkppc64le
 		return a
+	case "s390x":
+		a := archS390x()
+		a.LinkArch = &s390x.Links390x
+		return a
 	}
 	return nil
 }
@@ -102,13 +99,13 @@ func archX86(linkArch *obj.LinkArch) *Arch {
 	register["PC"] = RPC
 	// Register prefix not used on this architecture.
 
-	instructions := make(map[string]int)
+	instructions := make(map[string]obj.As)
 	for i, s := range obj.Anames {
-		instructions[s] = i
+		instructions[s] = obj.As(i)
 	}
 	for i, s := range x86.Anames {
-		if i >= obj.A_ARCHSPECIFIC {
-			instructions[s] = i + obj.ABaseAMD64
+		if obj.As(i) >= obj.A_ARCHSPECIFIC {
+			instructions[s] = obj.As(i) + obj.ABaseAMD64
 		}
 	}
 	// Annoying aliases.
@@ -162,8 +159,6 @@ func archX86(linkArch *obj.LinkArch) *Arch {
 	instructions["MOVDQ2Q"] = x86.AMOVQ
 	instructions["MOVNTDQ"] = x86.AMOVNTO
 	instructions["MOVOA"] = x86.AMOVO
-	instructions["PF2ID"] = x86.APF2IL
-	instructions["PI2FD"] = x86.API2FL
 	instructions["PSLLDQ"] = x86.APSLLO
 	instructions["PSRLDQ"] = x86.APSRLO
 	instructions["PADDD"] = x86.APADDL
@@ -202,13 +197,13 @@ func archArm() *Arch {
 		"R": true,
 	}
 
-	instructions := make(map[string]int)
+	instructions := make(map[string]obj.As)
 	for i, s := range obj.Anames {
-		instructions[s] = i
+		instructions[s] = obj.As(i)
 	}
 	for i, s := range arm.Anames {
-		if i >= obj.A_ARCHSPECIFIC {
-			instructions[s] = i + obj.ABaseARM
+		if obj.As(i) >= obj.A_ARCHSPECIFIC {
+			instructions[s] = obj.As(i) + obj.ABaseARM
 		}
 	}
 	// Annoying aliases.
@@ -290,13 +285,13 @@ func archArm64() *Arch {
 		"V": true,
 	}
 
-	instructions := make(map[string]int)
+	instructions := make(map[string]obj.As)
 	for i, s := range obj.Anames {
-		instructions[s] = i
+		instructions[s] = obj.As(i)
 	}
 	for i, s := range arm64.Anames {
-		if i >= obj.A_ARCHSPECIFIC {
-			instructions[s] = i + obj.ABaseARM64
+		if obj.As(i) >= obj.A_ARCHSPECIFIC {
+			instructions[s] = obj.As(i) + obj.ABaseARM64
 		}
 	}
 	// Annoying aliases.
@@ -350,13 +345,13 @@ func archPPC64() *Arch {
 		"SPR": true,
 	}
 
-	instructions := make(map[string]int)
+	instructions := make(map[string]obj.As)
 	for i, s := range obj.Anames {
-		instructions[s] = i
+		instructions[s] = obj.As(i)
 	}
 	for i, s := range ppc64.Anames {
-		if i >= obj.A_ARCHSPECIFIC {
-			instructions[s] = i + obj.ABasePPC64
+		if obj.As(i) >= obj.A_ARCHSPECIFIC {
+			instructions[s] = obj.As(i) + obj.ABasePPC64
 		}
 	}
 	// Annoying aliases.
@@ -398,6 +393,9 @@ func archMips64() *Arch {
 	// Avoid unintentionally clobbering g using R30.
 	delete(register, "R30")
 	register["g"] = mips.REG_R30
+	// Avoid unintentionally clobbering RSB using R28.
+	delete(register, "R28")
+	register["RSB"] = mips.REG_R28
 	registerPrefix := map[string]bool{
 		"F":   true,
 		"FCR": true,
@@ -405,13 +403,13 @@ func archMips64() *Arch {
 		"R":   true,
 	}
 
-	instructions := make(map[string]int)
+	instructions := make(map[string]obj.As)
 	for i, s := range obj.Anames {
-		instructions[s] = i
+		instructions[s] = obj.As(i)
 	}
 	for i, s := range mips.Anames {
-		if i >= obj.A_ARCHSPECIFIC {
-			instructions[s] = i + obj.ABaseMIPS64
+		if obj.As(i) >= obj.A_ARCHSPECIFIC {
+			instructions[s] = obj.As(i) + obj.ABaseMIPS64
 		}
 	}
 	// Annoying alias.
@@ -426,3 +424,56 @@ func archMips64() *Arch {
 		IsJump:         jumpMIPS64,
 	}
 }
+
+func archS390x() *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 := s390x.REG_R0; i <= s390x.REG_R15; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	for i := s390x.REG_F0; i <= s390x.REG_F15; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	for i := s390x.REG_V0; i <= s390x.REG_V31; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	for i := s390x.REG_AR0; i <= s390x.REG_AR15; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	register["LR"] = s390x.REG_LR
+	// Pseudo-registers.
+	register["SB"] = RSB
+	register["FP"] = RFP
+	register["PC"] = RPC
+	// Avoid unintentionally clobbering g using R13.
+	delete(register, "R13")
+	register["g"] = s390x.REG_R13
+	registerPrefix := map[string]bool{
+		"AR": true,
+		"F":  true,
+		"R":  true,
+	}
+
+	instructions := make(map[string]obj.As)
+	for i, s := range obj.Anames {
+		instructions[s] = obj.As(i)
+	}
+	for i, s := range s390x.Anames {
+		if obj.As(i) >= obj.A_ARCHSPECIFIC {
+			instructions[s] = obj.As(i) + obj.ABaseS390X
+		}
+	}
+	// Annoying aliases.
+	instructions["BR"] = s390x.ABR
+	instructions["BL"] = s390x.ABL
+
+	return &Arch{
+		LinkArch:       &s390x.Links390x,
+		Instructions:   instructions,
+		Register:       register,
+		RegisterPrefix: registerPrefix,
+		RegisterNumber: s390xRegisterNumber,
+		IsJump:         jumpS390x,
+	}
+}
diff --git a/src/cmd/asm/internal/arch/arm.go b/src/cmd/asm/internal/arch/arm.go
index 502a906..967dedc 100644
--- a/src/cmd/asm/internal/arch/arm.go
+++ b/src/cmd/asm/internal/arch/arm.go
@@ -89,7 +89,7 @@ func jumpArm(word string) bool {
 
 // 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 {
+func IsARMCMP(op obj.As) bool {
 	switch op {
 	case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
 		return true
@@ -99,7 +99,7 @@ func IsARMCMP(op int) bool {
 
 // 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 {
+func IsARMSTREX(op obj.As) bool {
 	switch op {
 	case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
 		return true
@@ -114,7 +114,7 @@ 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 {
+func IsARMMRC(op obj.As) bool {
 	switch op {
 	case arm.AMRC, aMCR: // Note: aMCR is defined in this package.
 		return true
@@ -123,7 +123,7 @@ func IsARMMRC(op int) bool {
 }
 
 // IsARMFloatCmp reports whether the op is a floating comparison instruction.
-func IsARMFloatCmp(op int) bool {
+func IsARMFloatCmp(op obj.As) bool {
 	switch op {
 	case arm.ACMPF, arm.ACMPD:
 		return true
@@ -135,7 +135,7 @@ func IsARMFloatCmp(op int) bool {
 // 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) {
+func ARMMRCOffset(op obj.As, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 obj.As, ok bool) {
 	op1 := int64(0)
 	if op == arm.AMRC {
 		op1 = 1
@@ -159,7 +159,7 @@ func ARMMRCOffset(op int, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int
 
 // 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 {
+func IsARMMULA(op obj.As) bool {
 	switch op {
 	case arm.AMULA, arm.AMULAWB, arm.AMULAWT:
 		return true
@@ -167,7 +167,7 @@ func IsARMMULA(op int) bool {
 	return false
 }
 
-var bcode = []int{
+var bcode = []obj.As{
 	arm.ABEQ,
 	arm.ABNE,
 	arm.ABCS,
@@ -198,7 +198,7 @@ func ARMConditionCodes(prog *obj.Prog, cond string) bool {
 	}
 	/* 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])
+		prog.As = bcode[(bits^arm.C_SCOND_XOR)&0xf]
 		bits = (bits &^ 0xf) | arm.C_SCOND_NONE
 	}
 	prog.Scond = bits
diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go
index 0f29e81..ab64a05 100644
--- a/src/cmd/asm/internal/arch/arm64.go
+++ b/src/cmd/asm/internal/arch/arm64.go
@@ -51,7 +51,7 @@ func jumpArm64(word string) bool {
 
 // 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 {
+func IsARM64CMP(op obj.As) bool {
 	switch op {
 	case arm64.ACMN, arm64.ACMP, arm64.ATST,
 		arm64.ACMNW, arm64.ACMPW, arm64.ATSTW:
@@ -63,7 +63,7 @@ func IsARM64CMP(op int) bool {
 // 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 {
+func IsARM64STLXR(op obj.As) bool {
 	switch op {
 	case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR:
 		return true
diff --git a/src/cmd/asm/internal/arch/mips64.go b/src/cmd/asm/internal/arch/mips64.go
index b5867d9..dd93cfb 100644
--- a/src/cmd/asm/internal/arch/mips64.go
+++ b/src/cmd/asm/internal/arch/mips64.go
@@ -8,7 +8,10 @@
 
 package arch
 
-import "cmd/internal/obj/mips"
+import (
+	"cmd/internal/obj"
+	"cmd/internal/obj/mips"
+)
 
 func jumpMIPS64(word string) bool {
 	switch word {
@@ -20,7 +23,7 @@ func jumpMIPS64(word string) bool {
 
 // IsMIPS64CMP reports whether the op (as defined by an mips.A* constant) is
 // one of the CMP instructions that require special handling.
-func IsMIPS64CMP(op int) bool {
+func IsMIPS64CMP(op obj.As) bool {
 	switch op {
 	case mips.ACMPEQF, mips.ACMPEQD, mips.ACMPGEF, mips.ACMPGED,
 		mips.ACMPGTF, mips.ACMPGTD:
@@ -31,7 +34,7 @@ func IsMIPS64CMP(op int) bool {
 
 // IsMIPS64MUL reports whether the op (as defined by an mips.A* constant) is
 // one of the MUL/DIV/REM instructions that require special handling.
-func IsMIPS64MUL(op int) bool {
+func IsMIPS64MUL(op obj.As) bool {
 	switch op {
 	case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU,
 		mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU,
diff --git a/src/cmd/asm/internal/arch/ppc64.go b/src/cmd/asm/internal/arch/ppc64.go
index 6523fbf..fef2565 100644
--- a/src/cmd/asm/internal/arch/ppc64.go
+++ b/src/cmd/asm/internal/arch/ppc64.go
@@ -8,7 +8,10 @@
 
 package arch
 
-import "cmd/internal/obj/ppc64"
+import (
+	"cmd/internal/obj"
+	"cmd/internal/obj/ppc64"
+)
 
 func jumpPPC64(word string) bool {
 	switch word {
@@ -21,7 +24,7 @@ func jumpPPC64(word string) bool {
 // 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 {
+func IsPPC64RLD(op obj.As) bool {
 	switch op {
 	case ppc64.ARLDC, ppc64.ARLDCCC, ppc64.ARLDCL, ppc64.ARLDCLCC,
 		ppc64.ARLDCR, ppc64.ARLDCRCC, ppc64.ARLDMI, ppc64.ARLDMICC,
@@ -38,7 +41,7 @@ func IsPPC64RLD(op int) bool {
 
 // 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 {
+func IsPPC64CMP(op obj.As) bool {
 	switch op {
 	case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU:
 		return true
@@ -48,7 +51,7 @@ func IsPPC64CMP(op int) bool {
 
 // 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 {
+func IsPPC64NEG(op obj.As) bool {
 	switch op {
 	case ppc64.AADDMECC, ppc64.AADDMEVCC, ppc64.AADDMEV, ppc64.AADDME,
 		ppc64.AADDZECC, ppc64.AADDZEVCC, ppc64.AADDZEV, ppc64.AADDZE,
diff --git a/src/cmd/asm/internal/arch/s390x.go b/src/cmd/asm/internal/arch/s390x.go
new file mode 100644
index 0000000..6fa0292
--- /dev/null
+++ b/src/cmd/asm/internal/arch/s390x.go
@@ -0,0 +1,139 @@
+// Copyright 2016 The Go 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
+// s390x instruction set, to minimize its interaction
+// with the core of the assembler.
+
+package arch
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/obj/s390x"
+)
+
+func jumpS390x(word string) bool {
+	switch word {
+	case "BC",
+		"BCL",
+		"BEQ",
+		"BGE",
+		"BGT",
+		"BL",
+		"BLE",
+		"BLT",
+		"BNE",
+		"BR",
+		"BVC",
+		"BVS",
+		"CMPBEQ",
+		"CMPBGE",
+		"CMPBGT",
+		"CMPBLE",
+		"CMPBLT",
+		"CMPBNE",
+		"CMPUBEQ",
+		"CMPUBGE",
+		"CMPUBGT",
+		"CMPUBLE",
+		"CMPUBLT",
+		"CMPUBNE",
+		"CALL",
+		"JMP":
+		return true
+	}
+	return false
+}
+
+// IsS390xRLD reports whether the op (as defined by an s390x.A* constant) is
+// one of the RLD-like instructions that require special handling.
+// The FMADD-like instructions behave similarly.
+func IsS390xRLD(op obj.As) bool {
+	switch op {
+	case s390x.AFMADD,
+		s390x.AFMADDS,
+		s390x.AFMSUB,
+		s390x.AFMSUBS,
+		s390x.AFNMADD,
+		s390x.AFNMADDS,
+		s390x.AFNMSUB,
+		s390x.AFNMSUBS:
+		return true
+	}
+	return false
+}
+
+// IsS390xCMP reports whether the op (as defined by an s390x.A* constant) is
+// one of the CMP instructions that require special handling.
+func IsS390xCMP(op obj.As) bool {
+	switch op {
+	case s390x.ACMP, s390x.ACMPU, s390x.ACMPW, s390x.ACMPWU:
+		return true
+	}
+	return false
+}
+
+// IsS390xNEG reports whether the op (as defined by an s390x.A* constant) is
+// one of the NEG-like instructions that require special handling.
+func IsS390xNEG(op obj.As) bool {
+	switch op {
+	case s390x.AADDME,
+		s390x.AADDZE,
+		s390x.ANEG,
+		s390x.ASUBME,
+		s390x.ASUBZE:
+		return true
+	}
+	return false
+}
+
+// IsS390xWithLength reports whether the op (as defined by an s390x.A* constant)
+// refers to an instruction which takes a length as its first argument.
+func IsS390xWithLength(op obj.As) bool {
+	switch op {
+	case s390x.AMVC, s390x.ACLC, s390x.AXC, s390x.AOC, s390x.ANC:
+		return true
+	case s390x.AVLL, s390x.AVSTL:
+		return true
+	}
+	return false
+}
+
+// IsS390xWithIndex reports whether the op (as defined by an s390x.A* constant)
+// refers to an instruction which takes an index as its first argument.
+func IsS390xWithIndex(op obj.As) bool {
+	switch op {
+	case s390x.AVSCEG, s390x.AVSCEF, s390x.AVGEG, s390x.AVGEF:
+		return true
+	case s390x.AVGMG, s390x.AVGMF, s390x.AVGMH, s390x.AVGMB:
+		return true
+	case s390x.AVLEIG, s390x.AVLEIF, s390x.AVLEIH, s390x.AVLEIB:
+		return true
+	case s390x.AVPDI:
+		return true
+	}
+	return false
+}
+
+func s390xRegisterNumber(name string, n int16) (int16, bool) {
+	switch name {
+	case "AR":
+		if 0 <= n && n <= 15 {
+			return s390x.REG_AR0 + n, true
+		}
+	case "F":
+		if 0 <= n && n <= 15 {
+			return s390x.REG_F0 + n, true
+		}
+	case "R":
+		if 0 <= n && n <= 15 {
+			return s390x.REG_R0 + n, true
+		}
+	case "V":
+		if 0 <= n && n <= 31 {
+			return s390x.REG_V0 + n, true
+		}
+	}
+	return 0, false
+}
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 9827d70..c9c6420 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -13,6 +13,7 @@ import (
 	"cmd/asm/internal/flags"
 	"cmd/asm/internal/lex"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 )
 
 // TODO: configure the architecture
@@ -23,14 +24,14 @@ var testOut *bytes.Buffer // Gathers output when testing.
 // 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':
+		switch p.arch.Family {
+		case sys.ARM:
 			if !arch.ARMConditionCodes(prog, cond) {
 				p.errorf("unrecognized condition code .%q", cond)
 				return
 			}
 
-		case '7':
+		case sys.ARM64:
 			if !arch.ARM64Suffix(prog, cond) {
 				p.errorf("unrecognized suffix .%q", cond)
 				return
@@ -58,7 +59,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
 		}
 		p.pendingLabels = p.pendingLabels[0:0]
 	}
-	prog.Pc = int64(p.pc)
+	prog.Pc = p.pc
 	if *flags.Debug {
 		fmt.Println(p.histLineNum, prog)
 	}
@@ -219,18 +220,23 @@ func (p *Parser) asmData(word string, operands [][]lex.Token) {
 	}
 	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,
+	switch valueAddr.Type {
+	case obj.TYPE_CONST:
+		nameAddr.Sym.WriteInt(p.ctxt, nameAddr.Offset, int(scale), valueAddr.Offset)
+	case obj.TYPE_FCONST:
+		switch scale {
+		case 4:
+			nameAddr.Sym.WriteFloat32(p.ctxt, nameAddr.Offset, float32(valueAddr.Val.(float64)))
+		case 8:
+			nameAddr.Sym.WriteFloat64(p.ctxt, nameAddr.Offset, valueAddr.Val.(float64))
+		default:
+			panic("bad float scale")
+		}
+	case obj.TYPE_SCONST:
+		nameAddr.Sym.WriteString(p.ctxt, nameAddr.Offset, int(scale), valueAddr.Val.(string))
+	case obj.TYPE_ADDR:
+		nameAddr.Sym.WriteAddr(p.ctxt, nameAddr.Offset, int(scale), valueAddr.Sym, valueAddr.Offset)
 	}
-
-	p.append(prog, "", false)
 }
 
 // asmGlobl assembles a GLOBL pseudo-op.
@@ -341,12 +347,12 @@ func (p *Parser) asmFuncData(word string, operands [][]lex.Token) {
 // JMP	R1
 // JMP	exit
 // JMP	3(PC)
-func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
+func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
 	var target *obj.Addr
 	prog := &obj.Prog{
 		Ctxt:   p.ctxt,
 		Lineno: p.histLineNum,
-		As:     int16(op),
+		As:     op,
 	}
 	switch len(a) {
 	case 1:
@@ -356,7 +362,7 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
 		target = &a[1]
 		prog.From = a[0]
 	case 3:
-		if p.arch.Thechar == '9' {
+		if p.arch.Family == sys.PPC64 {
 			// Special 3-operand jumps.
 			// First two must be constants; a[1] is a register number.
 			target = &a[2]
@@ -365,7 +371,7 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
 				Offset: p.getConstant(prog, op, &a[0]),
 			}
 			reg := int16(p.getConstant(prog, op, &a[1]))
-			reg, ok := p.arch.RegisterNumber("R", int16(reg))
+			reg, ok := p.arch.RegisterNumber("R", reg)
 			if !ok {
 				p.errorf("bad register number %d", reg)
 				return
@@ -373,7 +379,7 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
 			prog.Reg = reg
 			break
 		}
-		if p.arch.Thechar == '0' {
+		if p.arch.Family == sys.MIPS64 {
 			// 3-operand jumps.
 			// First two must be registers
 			target = &a[2]
@@ -381,6 +387,20 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			break
 		}
+		if p.arch.Family == sys.S390X {
+			// 3-operand jumps.
+			target = &a[2]
+			prog.From = a[0]
+			if a[1].Reg != 0 {
+				// Compare two registers and jump.
+				prog.Reg = p.getRegister(prog, op, &a[1])
+			} else {
+				// Compare register with immediate and jump.
+				prog.From3 = newAddr(a[1])
+			}
+			break
+		}
+
 		fallthrough
 	default:
 		p.errorf("wrong number of arguments to %s instruction", obj.Aconv(op))
@@ -419,7 +439,7 @@ func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
 		// 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 {
+		if p.arch.Family == sys.PPC64 && target.Offset == 0 {
 			prog.To.Type = obj.TYPE_REG
 		}
 	case target.Type == obj.TYPE_CONST:
@@ -455,12 +475,12 @@ func (p *Parser) branch(jmp, target *obj.Prog) {
 
 // asmInstruction assembles an instruction.
 // MOVW R9, (R10)
-func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
+func (p *Parser) asmInstruction(op obj.As, 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),
+		As:     op,
 	}
 	switch len(a) {
 	case 0:
@@ -473,14 +493,14 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 			prog.From = a[0]
 			// prog.To is no address.
 		}
-		if p.arch.Thechar == '9' && arch.IsPPC64NEG(op) {
+		if p.arch.Family == sys.PPC64 && 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 p.arch.Family == sys.ARM {
 			if arch.IsARMCMP(op) {
 				prog.From = a[0]
 				prog.Reg = p.getRegister(prog, op, &a[1])
@@ -513,11 +533,11 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 				prog.Reg = p.getRegister(prog, op, &a[1])
 				break
 			}
-		} else if p.arch.Thechar == '7' && arch.IsARM64CMP(op) {
+		} else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) {
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			break
-		} else if p.arch.Thechar == '0' {
+		} else if p.arch.Family == sys.MIPS64 {
 			if arch.IsMIPS64CMP(op) || arch.IsMIPS64MUL(op) {
 				prog.From = a[0]
 				prog.Reg = p.getRegister(prog, op, &a[1])
@@ -527,12 +547,12 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 		prog.From = a[0]
 		prog.To = a[1]
 	case 3:
-		switch p.arch.Thechar {
-		case '0':
+		switch p.arch.Family {
+		case sys.MIPS64:
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			prog.To = a[2]
-		case '5':
+		case sys.ARM:
 			// Special cases.
 			if arch.IsARMSTREX(op) {
 				/*
@@ -548,7 +568,16 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			prog.To = a[2]
-		case '7':
+		case sys.AMD64:
+			// Catch missing operand here, because we store immediate as part of From3, and can't distinguish
+			// missing operand from legal value 0 in obj/x86/asm6.
+			if arch.IsAMD4OP(op) {
+				p.errorf("4 operands required, but only 3 are provided for %s instruction", obj.Aconv(op))
+			}
+			prog.From = a[0]
+			prog.From3 = newAddr(a[1])
+			prog.To = a[2]
+		case sys.ARM64:
 			// ARM64 instructions with one input and two outputs.
 			if arch.IsARM64STLXR(op) {
 				prog.From = a[0]
@@ -563,11 +592,11 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			prog.To = a[2]
-		case '6', '8':
+		case sys.I386:
 			prog.From = a[0]
 			prog.From3 = newAddr(a[1])
 			prog.To = a[2]
-		case '9':
+		case sys.PPC64:
 			if arch.IsPPC64CMP(op) {
 				// CMPW etc.; third argument is a CR register that goes into prog.Reg.
 				prog.From = a[0]
@@ -593,12 +622,21 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 				p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op))
 				return
 			}
+		case sys.S390X:
+			if arch.IsS390xWithLength(op) || arch.IsS390xWithIndex(op) {
+				prog.From = a[1]
+				prog.From3 = newAddr(a[0])
+			} else {
+				prog.Reg = p.getRegister(prog, op, &a[1])
+				prog.From = a[0]
+			}
+			prog.To = a[2]
 		default:
 			p.errorf("TODO: implement three-operand instructions for this architecture")
 			return
 		}
 	case 4:
-		if p.arch.Thechar == '5' && arch.IsARMMULA(op) {
+		if p.arch.Family == sys.ARM && arch.IsARMMULA(op) {
 			// All must be registers.
 			p.getRegister(prog, op, &a[0])
 			r1 := p.getRegister(prog, op, &a[1])
@@ -611,14 +649,31 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 			prog.Reg = r1
 			break
 		}
-		if p.arch.Thechar == '7' {
+		if p.arch.Family == sys.AMD64 {
+			// 4 operand instruction have form  ymm1, ymm2, ymm3/m256, imm8
+			// So From3 is always just a register, so we store imm8 in Offset field,
+			// to avoid increasing size of Prog.
+			prog.From = a[1]
+			prog.From3 = newAddr(a[2])
+			if a[0].Type != obj.TYPE_CONST {
+				p.errorf("first operand must be an immediate in %s instruction", obj.Aconv(op))
+			}
+			if prog.From3.Type != obj.TYPE_REG {
+				p.errorf("third operand must be a register in %s instruction", obj.Aconv(op))
+			}
+			prog.From3.Offset = int64(p.getImmediate(prog, op, &a[0]))
+			prog.To = a[3]
+			prog.RegTo2 = -1
+			break
+		}
+		if p.arch.Family == sys.ARM64 {
 			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) {
+		if p.arch.Family == sys.PPC64 && 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?
@@ -628,10 +683,17 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 			prog.To = a[3]
 			break
 		}
+		if p.arch.Family == sys.S390X {
+			prog.From = a[1]
+			prog.Reg = p.getRegister(prog, op, &a[2])
+			prog.From3 = newAddr(a[0])
+			prog.To = a[3]
+			break
+		}
 		p.errorf("can't handle %s instruction with 4 operands", obj.Aconv(op))
 		return
 	case 5:
-		if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
+		if p.arch.Family == sys.PPC64 && 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])
@@ -653,7 +715,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
 		p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op))
 		return
 	case 6:
-		if p.arch.Thechar == '5' && arch.IsARMMRC(op) {
+		if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
 			// Strange special case: MCR, MRC.
 			prog.To.Type = obj.TYPE_CONST
 			x0 := p.getConstant(prog, op, &a[0])
@@ -707,7 +769,7 @@ func (p *Parser) getConstantPseudo(pseudo string, addr *obj.Addr) int64 {
 }
 
 // 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 {
+func (p *Parser) getConstant(prog *obj.Prog, op obj.As, 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))
 	}
@@ -715,7 +777,7 @@ func (p *Parser) getConstant(prog *obj.Prog, op int, addr *obj.Addr) int64 {
 }
 
 // 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 {
+func (p *Parser) getImmediate(prog *obj.Prog, op obj.As, 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))
 	}
@@ -723,7 +785,7 @@ func (p *Parser) getImmediate(prog *obj.Prog, op int, addr *obj.Addr) int64 {
 }
 
 // getRegister checks that addr represents a register and returns its value.
-func (p *Parser) getRegister(prog *obj.Prog, op int, addr *obj.Addr) int16 {
+func (p *Parser) getRegister(prog *obj.Prog, op obj.As, 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))
 	}
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
index 4bc7e2f..bc992a7 100644
--- a/src/cmd/asm/internal/asm/endtoend_test.go
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -5,6 +5,7 @@
 package asm
 
 import (
+	"bufio"
 	"bytes"
 	"fmt"
 	"io/ioutil"
@@ -33,7 +34,7 @@ func testEndToEnd(t *testing.T, goarch, file string) {
 	pList := obj.Linknewplist(ctxt)
 	var ok bool
 	testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
-	ctxt.Bso = obj.Binitw(os.Stdout)
+	ctxt.Bso = bufio.NewWriter(os.Stdout)
 	defer ctxt.Bso.Flush()
 	failed := false
 	ctxt.DiagFunc = func(format string, args ...interface{}) {
@@ -179,7 +180,7 @@ Diff:
 		t.Errorf(format, args...)
 		ok = false
 	}
-	obj.Flushplist(ctxt)
+	obj.FlushplistNoFree(ctxt)
 
 	for p := top; p != nil; p = p.Link {
 		if p.As == obj.ATEXT {
@@ -271,7 +272,7 @@ func testErrors(t *testing.T, goarch, file string) {
 	pList := obj.Linknewplist(ctxt)
 	var ok bool
 	testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
-	ctxt.Bso = obj.Binitw(os.Stdout)
+	ctxt.Bso = bufio.NewWriter(os.Stdout)
 	defer ctxt.Bso.Flush()
 	failed := false
 	var errBuf bytes.Buffer
@@ -389,3 +390,7 @@ func TestMIPS64EndToEnd(t *testing.T) {
 func TestPPC64EndToEnd(t *testing.T) {
 	testEndToEnd(t, "ppc64", "ppc64")
 }
+
+func TestS390XEndToEnd(t *testing.T) {
+	testEndToEnd(t, "s390x", "s390x")
+}
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index ecf52c5..eafc8a3 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -70,6 +70,11 @@ func TestMIPS64OperandParser(t *testing.T) {
 	testOperandParser(t, parser, mips64OperandTests)
 }
 
+func TestS390XOperandParser(t *testing.T) {
+	parser := newParser("s390x")
+	testOperandParser(t, parser, s390xOperandTests)
+}
+
 type operandTest struct {
 	input, output string
 }
@@ -127,6 +132,9 @@ var amd64OperandTests = []operandTest{
 	{"(SI)(BX*1)", "(SI)(BX*1)"},
 	{"(SI)(DX*1)", "(SI)(DX*1)"},
 	{"(SP)", "(SP)"},
+	{"(SP)(AX*4)", "(SP)(AX*4)"},
+	{"32(SP)(BX*2)", "32(SP)(BX*2)"},
+	{"32323(SP)(R8*4)", "32323(SP)(R8*4)"},
 	{"+3(PC)", "3(PC)"},
 	{"-1(DI)(BX*1)", "-1(DI)(BX*1)"},
 	{"-3(PC)", "-3(PC)"},
@@ -504,7 +512,6 @@ var mips64OperandTests = []operandTest{
 	{"R25", "R25"},
 	{"R26", "R26"},
 	{"R27", "R27"},
-	{"R28", "R28"},
 	{"R29", "R29"},
 	{"R3", "R3"},
 	{"R31", "R31"},
@@ -517,6 +524,105 @@ var mips64OperandTests = []operandTest{
 	{"LO", "LO"},
 	{"a(FP)", "a(FP)"},
 	{"g", "g"},
+	{"RSB", "RSB"},
+	{"ret+8(FP)", "ret+8(FP)"},
+	{"runtime·abort(SB)", "runtime.abort(SB)"},
+	{"·AddUint32(SB)", "\"\".AddUint32(SB)"},
+	{"·trunc(SB)", "\"\".trunc(SB)"},
+	{"[):[o-FP", ""}, // Issue 12469 - asm hung parsing the o-FP range on non ARM platforms.
+}
+
+var s390xOperandTests = []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)"},
+	{"$~3", "$-4"},
+	{"(-288-3*8)(R1)", "-312(R1)"},
+	{"(16)(R7)", "16(R7)"},
+	{"(8)(g)", "8(g)"},
+	{"(R0)", "(R0)"},
+	{"(R3)", "(R3)"},
+	{"(R4)", "(R4)"},
+	{"(R5)", "(R5)"},
+	{"-1(R4)", "-1(R4)"},
+	{"-1(R5)", "-1(R5)"},
+	{"6(PC)", "6(PC)"},
+	{"R0", "R0"},
+	{"R1", "R1"},
+	{"R2", "R2"},
+	{"R3", "R3"},
+	{"R4", "R4"},
+	{"R5", "R5"},
+	{"R6", "R6"},
+	{"R7", "R7"},
+	{"R8", "R8"},
+	{"R9", "R9"},
+	{"R10", "R10"},
+	{"R11", "R11"},
+	{"R12", "R12"},
+	// {"R13", "R13"}, R13 is g
+	{"R14", "R14"},
+	{"R15", "R15"},
+	{"F0", "F0"},
+	{"F1", "F1"},
+	{"F2", "F2"},
+	{"F3", "F3"},
+	{"F4", "F4"},
+	{"F5", "F5"},
+	{"F6", "F6"},
+	{"F7", "F7"},
+	{"F8", "F8"},
+	{"F9", "F9"},
+	{"F10", "F10"},
+	{"F11", "F11"},
+	{"F12", "F12"},
+	{"F13", "F13"},
+	{"F14", "F14"},
+	{"F15", "F15"},
+	{"V0", "V0"},
+	{"V1", "V1"},
+	{"V2", "V2"},
+	{"V3", "V3"},
+	{"V4", "V4"},
+	{"V5", "V5"},
+	{"V6", "V6"},
+	{"V7", "V7"},
+	{"V8", "V8"},
+	{"V9", "V9"},
+	{"V10", "V10"},
+	{"V11", "V11"},
+	{"V12", "V12"},
+	{"V13", "V13"},
+	{"V14", "V14"},
+	{"V15", "V15"},
+	{"V16", "V16"},
+	{"V17", "V17"},
+	{"V18", "V18"},
+	{"V19", "V19"},
+	{"V20", "V20"},
+	{"V21", "V21"},
+	{"V22", "V22"},
+	{"V23", "V23"},
+	{"V24", "V24"},
+	{"V25", "V25"},
+	{"V26", "V26"},
+	{"V27", "V27"},
+	{"V28", "V28"},
+	{"V29", "V29"},
+	{"V30", "V30"},
+	{"V31", "V31"},
+	{"a(FP)", "a(FP)"},
+	{"g", "g"},
 	{"ret+8(FP)", "ret+8(FP)"},
 	{"runtime·abort(SB)", "runtime.abort(SB)"},
 	{"·AddUint32(SB)", "\"\".AddUint32(SB)"},
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index 4258c5c..40206e6 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -19,6 +19,7 @@ import (
 	"cmd/asm/internal/flags"
 	"cmd/asm/internal/lex"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 )
 
 type Parser struct {
@@ -130,7 +131,7 @@ func (p *Parser) line() bool {
 		for {
 			tok = p.lex.Next()
 			if len(operands) == 0 && len(items) == 0 {
-				if (p.arch.Thechar == '5' || p.arch.Thechar == '7') && tok == '.' {
+				if p.arch.InFamily(sys.ARM, sys.ARM64) && tok == '.' {
 					// ARM conditionals.
 					tok = p.lex.Next()
 					str := p.lex.Text()
@@ -183,12 +184,10 @@ func (p *Parser) line() bool {
 			p.errorf("missing operand")
 		}
 	}
-	i, present := arch.Pseudos[word]
-	if present {
-		p.pseudo(i, word, operands)
+	if p.pseudo(word, operands) {
 		return true
 	}
-	i, present = p.arch.Instructions[word]
+	i, present := p.arch.Instructions[word]
 	if present {
 		p.instruction(i, word, cond, operands)
 		return true
@@ -197,7 +196,7 @@ func (p *Parser) line() bool {
 	return true
 }
 
-func (p *Parser) instruction(op int, word, cond string, operands [][]lex.Token) {
+func (p *Parser) instruction(op obj.As, word, cond string, operands [][]lex.Token) {
 	p.addr = p.addr[0:0]
 	p.isJump = p.arch.IsJump(word)
 	for _, op := range operands {
@@ -214,21 +213,22 @@ func (p *Parser) instruction(op int, word, cond string, operands [][]lex.Token)
 	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:
+func (p *Parser) pseudo(word string, operands [][]lex.Token) bool {
+	switch word {
+	case "DATA":
 		p.asmData(word, operands)
-	case obj.AGLOBL:
+	case "FUNCDATA":
+		p.asmFuncData(word, operands)
+	case "GLOBL":
 		p.asmGlobl(word, operands)
-	case obj.APCDATA:
+	case "PCDATA":
 		p.asmPCData(word, operands)
-	case obj.AFUNCDATA:
-		p.asmFuncData(word, operands)
+	case "TEXT":
+		p.asmText(word, operands)
 	default:
-		p.errorf("unimplemented: %s", word)
+		return false
 	}
+	return true
 }
 
 func (p *Parser) start(operand []lex.Token) {
@@ -297,7 +297,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
 			p.errorf("illegal use of register list")
 		}
 		p.registerList(a)
-		p.expect(scanner.EOF)
+		p.expectOperandEnd()
 		return true
 	}
 
@@ -331,7 +331,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
 			}
 		}
 		// fmt.Printf("REG %s\n", obj.Dconv(&emptyProg, 0, a))
-		p.expect(scanner.EOF)
+		p.expectOperandEnd()
 		return true
 	}
 
@@ -363,7 +363,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
 			a.Type = obj.TYPE_FCONST
 			a.Val = p.floatExpr()
 			// fmt.Printf("FCONST %s\n", obj.Dconv(&emptyProg, 0, a))
-			p.expect(scanner.EOF)
+			p.expectOperandEnd()
 			return true
 		}
 		if p.have(scanner.String) {
@@ -378,7 +378,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
 			a.Type = obj.TYPE_SCONST
 			a.Val = str
 			// fmt.Printf("SCONST %s\n", obj.Dconv(&emptyProg, 0, a))
-			p.expect(scanner.EOF)
+			p.expectOperandEnd()
 			return true
 		}
 		a.Offset = int64(p.expr())
@@ -392,7 +392,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
 				a.Type = obj.TYPE_MEM
 			}
 			// fmt.Printf("CONST %d %s\n", a.Offset, obj.Dconv(&emptyProg, 0, a))
-			p.expect(scanner.EOF)
+			p.expectOperandEnd()
 			return true
 		}
 		// fmt.Printf("offset %d \n", a.Offset)
@@ -402,7 +402,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
 	p.registerIndirect(a, prefix)
 	// fmt.Printf("DONE %s\n", p.arch.Dconv(&emptyProg, 0, a))
 
-	p.expect(scanner.EOF)
+	p.expectOperandEnd()
 	return true
 }
 
@@ -421,7 +421,7 @@ func (p *Parser) atStartOfRegister(name string) bool {
 // We have consumed the register or R prefix.
 func (p *Parser) atRegisterShift() bool {
 	// ARM only.
-	if p.arch.Thechar != '5' {
+	if p.arch.Family != sys.ARM {
 		return false
 	}
 	// R1<<...
@@ -477,15 +477,14 @@ func (p *Parser) register(name string, prefix rune) (r1, r2 int16, scale int8, o
 	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' {
+			if !p.arch.InFamily(sys.ARM, sys.ARM64) {
 				p.errorf("(register,register) not supported on this architecture")
 				return
 			}
 		case '+':
-			if char != '9' {
+			if p.arch.Family != sys.PPC64 {
 				p.errorf("(register+register) not supported on this architecture")
 				return
 			}
@@ -650,7 +649,7 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
 	a.Reg = r1
 	if r2 != 0 {
 		// TODO: Consistency in the encoding would be nice here.
-		if p.arch.Thechar == '5' || p.arch.Thechar == '7' {
+		if p.arch.InFamily(sys.ARM, sys.ARM64) {
 			// Special form
 			// ARM: destination register pair (R1, R2).
 			// ARM64: register pair (R1, R2) for LDP/STP.
@@ -663,7 +662,7 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
 			// Nothing may follow
 			return
 		}
-		if p.arch.Thechar == '9' {
+		if p.arch.Family == sys.PPC64 {
 			// Special form for PPC64: (R1+R2); alias for (R1)(R2*1).
 			if prefix != 0 || scale != 0 {
 				p.errorf("illegal address mode for register+register")
@@ -753,7 +752,7 @@ ListLoop:
 
 // 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" {
+	if p.arch.Family == sys.ARM && name == "g" {
 		return 10
 	}
 	if name[0] != 'R' {
@@ -983,14 +982,19 @@ func (p *Parser) more() bool {
 
 // 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)
+	p.expect(expected, expected.String())
 	return p.next()
 }
 
+// expectOperandEnd verifies that the parsing state is properly at the end of an operand.
+func (p *Parser) expectOperandEnd() {
+	p.expect(scanner.EOF, "end of operand")
+}
+
 // 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())
+func (p *Parser) expect(expectedToken lex.ScanToken, expectedMessage string) {
+	if p.peek() != expectedToken {
+		p.errorf("expected %s, found %s", expectedMessage, p.next())
 	}
 }
 
diff --git a/src/cmd/asm/internal/asm/pseudo_test.go b/src/cmd/asm/internal/asm/pseudo_test.go
index ee13b72..1697973 100644
--- a/src/cmd/asm/internal/asm/pseudo_test.go
+++ b/src/cmd/asm/internal/asm/pseudo_test.go
@@ -9,7 +9,6 @@ import (
 	"strings"
 	"testing"
 
-	"cmd/asm/internal/arch"
 	"cmd/asm/internal/lex"
 )
 
@@ -35,8 +34,8 @@ func TestErroneous(t *testing.T) {
 		{"TEXT", "%", "expect two or three operands for TEXT"},
 		{"TEXT", "1, 1", "TEXT symbol \"<erroneous symbol>\" must be a symbol(SB)"},
 		{"TEXT", "$\"foo\", 0, $1", "TEXT symbol \"<erroneous symbol>\" must be a symbol(SB)"},
-		{"TEXT", "$0É:0, 0, $1", "expected EOF, found É"},   // Issue #12467.
-		{"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"}, // Issue 12468.
+		{"TEXT", "$0É:0, 0, $1", "expected end of operand, found É"}, // Issue #12467.
+		{"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"},          // Issue 12468.
 		{"FUNCDATA", "", "expect two operands for FUNCDATA"},
 		{"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"},
 		{"DATA", "", "expect two operands for DATA"},
@@ -58,11 +57,9 @@ func TestErroneous(t *testing.T) {
 		parser.errorCount = 0
 		parser.lineNum++
 		parser.histLineNum++
-		op, ok := arch.Pseudos[test.pseudo]
-		if !ok {
+		if !parser.pseudo(test.pseudo, tokenize(test.operands)) {
 			t.Fatalf("Wrong pseudo-instruction: %s", test.pseudo)
 		}
-		parser.pseudo(op, test.pseudo, tokenize(test.operands))
 		errorLine := buf.String()
 		if test.expected != errorLine {
 			t.Errorf("Unexpected error %q; expected %q", errorLine, test.expected)
diff --git a/src/cmd/asm/internal/asm/testdata/amd64.s b/src/cmd/asm/internal/asm/testdata/amd64.s
index 70e7636..da01442 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64.s
+++ b/src/cmd/asm/internal/asm/testdata/amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -127,5 +127,19 @@ loop:
 	MOVNTDQ	X1, (AX)	// MOVNTO X1, (AX)
 	MOVOA	(AX), X1	// MOVO (AX), X1
 
+// Tests for SP indexed addresses.
+	MOVQ	foo(SP)(AX*1), BX		// 488b1c04
+	MOVQ	foo+32(SP)(CX*2), DX		// 488b544c20
+	MOVQ	foo+32323(SP)(R8*4), R9		// 4e8b8c84437e0000
+	MOVL	foo(SP)(SI*8), DI		// 8b3cf4
+	MOVL	foo+32(SP)(R10*1), R11		// 468b5c1420
+	MOVL	foo+32323(SP)(R12*2), R13	// 468bac64437e0000
+	MOVW	foo(SP)(AX*4), R8		// 66448b0484
+	MOVW	foo+32(SP)(R9*8), CX		// 66428b4ccc20
+	MOVW	foo+32323(SP)(AX*1), DX		// 668b9404437e0000
+	MOVB	foo(SP)(AX*2), AL		// 8a0444
+	MOVB	foo+32(SP)(CX*4), AH		// 8a648c20
+	MOVB	foo+32323(SP)(CX*8), R9		// 448a8ccc437e0000
+
 // LTYPE0 nonnon	{ outcode($1, &$2); }
 	RET // c3
diff --git a/src/cmd/asm/internal/asm/testdata/amd64enc.s b/src/cmd/asm/internal/asm/testdata/amd64enc.s
index 63fdcac..22dfe12 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64enc.s
+++ b/src/cmd/asm/internal/asm/testdata/amd64enc.s
@@ -5008,22 +5008,22 @@ TEXT asmtest(SB),7,$0
 	RORB $7, (R11)                          // 41c00b07
 	RORB $7, DL                             // c0ca07
 	RORB $7, R11                            // 41c0cb07
-	//TODO: RORXL $7, (BX), DX              // c4e37bf01307
-	//TODO: RORXL $7, (R11), DX             // c4c37bf01307
-	//TODO: RORXL $7, DX, DX                // c4e37bf0d207
-	//TODO: RORXL $7, R11, DX               // c4c37bf0d307
-	//TODO: RORXL $7, (BX), R11             // c4637bf01b07
-	//TODO: RORXL $7, (R11), R11            // c4437bf01b07
-	//TODO: RORXL $7, DX, R11               // c4637bf0da07
-	//TODO: RORXL $7, R11, R11              // c4437bf0db07
-	//TODO: RORXQ $7, (BX), DX              // c4e3fbf01307
-	//TODO: RORXQ $7, (R11), DX             // c4c3fbf01307
-	//TODO: RORXQ $7, DX, DX                // c4e3fbf0d207
-	//TODO: RORXQ $7, R11, DX               // c4c3fbf0d307
-	//TODO: RORXQ $7, (BX), R11             // c463fbf01b07
-	//TODO: RORXQ $7, (R11), R11            // c443fbf01b07
-	//TODO: RORXQ $7, DX, R11               // c463fbf0da07
-	//TODO: RORXQ $7, R11, R11              // c443fbf0db07
+	RORXL $7, (BX), DX              // c4e37bf01307
+	RORXL $7, (R11), DX             // c4c37bf01307
+	RORXL $7, DX, DX                // c4e37bf0d207
+	RORXL $7, R11, DX               // c4c37bf0d307
+	RORXL $7, (BX), R11             // c4637bf01b07
+	RORXL $7, (R11), R11            // c4437bf01b07
+	RORXL $7, DX, R11               // c4637bf0da07
+	RORXL $7, R11, R11              // c4437bf0db07
+	RORXQ $7, (BX), DX              // c4e3fbf01307
+	RORXQ $7, (R11), DX             // c4c3fbf01307
+	RORXQ $7, DX, DX                // c4e3fbf0d207
+	RORXQ $7, R11, DX               // c4c3fbf0d307
+	RORXQ $7, (BX), R11             // c463fbf01b07
+	RORXQ $7, (R11), R11            // c443fbf01b07
+	RORXQ $7, DX, R11               // c463fbf0da07
+	RORXQ $7, R11, R11              // c443fbf0db07
 	ROUNDPD $7, (BX), X2                    // 660f3a091307
 	ROUNDPD $7, (R11), X2                   // 66410f3a091307
 	ROUNDPD $7, X2, X2                      // 660f3a09d207
@@ -7420,14 +7420,14 @@ TEXT asmtest(SB),7,$0
 	//TODO: VINSERTF128 $7, (R11), Y15, Y11 // c44305181b07
 	//TODO: VINSERTF128 $7, X2, Y15, Y11    // c4630518da07
 	//TODO: VINSERTF128 $7, X11, Y15, Y11   // c4430518db07
-	//TODO: VINSERTI128 $7, (BX), Y15, Y2   // c4e305381307
-	//TODO: VINSERTI128 $7, (R11), Y15, Y2  // c4c305381307
-	//TODO: VINSERTI128 $7, X2, Y15, Y2     // c4e30538d207
-	//TODO: VINSERTI128 $7, X11, Y15, Y2    // c4c30538d307
-	//TODO: VINSERTI128 $7, (BX), Y15, Y11  // c46305381b07
-	//TODO: VINSERTI128 $7, (R11), Y15, Y11 // c44305381b07
-	//TODO: VINSERTI128 $7, X2, Y15, Y11    // c4630538da07
-	//TODO: VINSERTI128 $7, X11, Y15, Y11   // c4430538db07
+	VINSERTI128 $7, (BX), Y15, Y2   // c4e305381307
+	VINSERTI128 $7, (R11), Y15, Y2  // c4c305381307
+	VINSERTI128 $7, X2, Y15, Y2     // c4e30538d207
+	VINSERTI128 $7, X11, Y15, Y2    // c4c30538d307
+	VINSERTI128 $7, (BX), Y15, Y11  // c46305381b07
+	VINSERTI128 $7, (R11), Y15, Y11 // c44305381b07
+	VINSERTI128 $7, X2, Y15, Y11    // c4630538da07
+	VINSERTI128 $7, X11, Y15, Y11   // c4430538db07
 	//TODO: VINSERTPS $7, (BX), X9, X2      // c4e331211307
 	//TODO: VINSERTPS $7, (R11), X9, X2     // c4c331211307
 	//TODO: VINSERTPS $7, X2, X9, X2        // c4e33121d207
@@ -8142,38 +8142,38 @@ TEXT asmtest(SB),7,$0
 	//TODO: VPADDB (R11), Y15, Y11          // c44105fc1b
 	//TODO: VPADDB Y2, Y15, Y11             // c46105fcda or c505fcda
 	//TODO: VPADDB Y11, Y15, Y11            // c44105fcdb
-	//TODO: VPADDD (BX), X9, X2             // c4e131fe13 or c5b1fe13
-	//TODO: VPADDD (R11), X9, X2            // c4c131fe13
-	//TODO: VPADDD X2, X9, X2               // c4e131fed2 or c5b1fed2
-	//TODO: VPADDD X11, X9, X2              // c4c131fed3
-	//TODO: VPADDD (BX), X9, X11            // c46131fe1b or c531fe1b
-	//TODO: VPADDD (R11), X9, X11           // c44131fe1b
-	//TODO: VPADDD X2, X9, X11              // c46131feda or c531feda
-	//TODO: VPADDD X11, X9, X11             // c44131fedb
-	//TODO: VPADDD (BX), Y15, Y2            // c4e105fe13 or c585fe13
-	//TODO: VPADDD (R11), Y15, Y2           // c4c105fe13
-	//TODO: VPADDD Y2, Y15, Y2              // c4e105fed2 or c585fed2
-	//TODO: VPADDD Y11, Y15, Y2             // c4c105fed3
-	//TODO: VPADDD (BX), Y15, Y11           // c46105fe1b or c505fe1b
-	//TODO: VPADDD (R11), Y15, Y11          // c44105fe1b
-	//TODO: VPADDD Y2, Y15, Y11             // c46105feda or c505feda
-	//TODO: VPADDD Y11, Y15, Y11            // c44105fedb
-	//TODO: VPADDQ (BX), X9, X2             // c4e131d413 or c5b1d413
-	//TODO: VPADDQ (R11), X9, X2            // c4c131d413
-	//TODO: VPADDQ X2, X9, X2               // c4e131d4d2 or c5b1d4d2
-	//TODO: VPADDQ X11, X9, X2              // c4c131d4d3
-	//TODO: VPADDQ (BX), X9, X11            // c46131d41b or c531d41b
-	//TODO: VPADDQ (R11), X9, X11           // c44131d41b
-	//TODO: VPADDQ X2, X9, X11              // c46131d4da or c531d4da
-	//TODO: VPADDQ X11, X9, X11             // c44131d4db
-	//TODO: VPADDQ (BX), Y15, Y2            // c4e105d413 or c585d413
-	//TODO: VPADDQ (R11), Y15, Y2           // c4c105d413
-	//TODO: VPADDQ Y2, Y15, Y2              // c4e105d4d2 or c585d4d2
-	//TODO: VPADDQ Y11, Y15, Y2             // c4c105d4d3
-	//TODO: VPADDQ (BX), Y15, Y11           // c46105d41b or c505d41b
-	//TODO: VPADDQ (R11), Y15, Y11          // c44105d41b
-	//TODO: VPADDQ Y2, Y15, Y11             // c46105d4da or c505d4da
-	//TODO: VPADDQ Y11, Y15, Y11            // c44105d4db
+	VPADDD (BX), X9, X2             // c4e131fe13 or c5b1fe13
+	VPADDD (R11), X9, X2            // c4c131fe13
+	VPADDD X2, X9, X2               // c4e131fed2 or c5b1fed2
+	VPADDD X11, X9, X2              // c4c131fed3
+	VPADDD (BX), X9, X11            // c46131fe1b or c531fe1b
+	VPADDD (R11), X9, X11           // c44131fe1b
+	VPADDD X2, X9, X11              // c46131feda or c531feda
+	VPADDD X11, X9, X11             // c44131fedb
+	VPADDD (BX), Y15, Y2            // c4e105fe13 or c585fe13
+	VPADDD (R11), Y15, Y2           // c4c105fe13
+	VPADDD Y2, Y15, Y2              // c4e105fed2 or c585fed2
+	VPADDD Y11, Y15, Y2             // c4c105fed3
+	VPADDD (BX), Y15, Y11           // c46105fe1b or c505fe1b
+	VPADDD (R11), Y15, Y11          // c44105fe1b
+	VPADDD Y2, Y15, Y11             // c46105feda or c505feda
+	VPADDD Y11, Y15, Y11            // c44105fedb
+	VPADDQ (BX), X9, X2             // c4e131d413 or c5b1d413
+	VPADDQ (R11), X9, X2            // c4c131d413
+	VPADDQ X2, X9, X2               // c4e131d4d2 or c5b1d4d2
+	VPADDQ X11, X9, X2              // c4c131d4d3
+	VPADDQ (BX), X9, X11            // c46131d41b or c531d41b
+	VPADDQ (R11), X9, X11           // c44131d41b
+	VPADDQ X2, X9, X11              // c46131d4da or c531d4da
+	VPADDQ X11, X9, X11             // c44131d4db
+	VPADDQ (BX), Y15, Y2            // c4e105d413 or c585d413
+	VPADDQ (R11), Y15, Y2           // c4c105d413
+	VPADDQ Y2, Y15, Y2              // c4e105d4d2 or c585d4d2
+	VPADDQ Y11, Y15, Y2             // c4c105d4d3
+	VPADDQ (BX), Y15, Y11           // c46105d41b or c505d41b
+	VPADDQ (R11), Y15, Y11          // c44105d41b
+	VPADDQ Y2, Y15, Y11             // c46105d4da or c505d4da
+	VPADDQ Y11, Y15, Y11            // c44105d4db
 	//TODO: VPADDSB (BX), X9, X2            // c4e131ec13 or c5b1ec13
 	//TODO: VPADDSB (R11), X9, X2           // c4c131ec13
 	//TODO: VPADDSB X2, X9, X2              // c4e131ecd2 or c5b1ecd2
@@ -8262,14 +8262,14 @@ TEXT asmtest(SB),7,$0
 	//TODO: VPALIGNR $7, (R11), X9, X11     // c443310f1b07
 	//TODO: VPALIGNR $7, X2, X9, X11        // c463310fda07
 	//TODO: VPALIGNR $7, X11, X9, X11       // c443310fdb07
-	//TODO: VPALIGNR $7, (BX), Y15, Y2      // c4e3050f1307
-	//TODO: VPALIGNR $7, (R11), Y15, Y2     // c4c3050f1307
-	//TODO: VPALIGNR $7, Y2, Y15, Y2        // c4e3050fd207
-	//TODO: VPALIGNR $7, Y11, Y15, Y2       // c4c3050fd307
-	//TODO: VPALIGNR $7, (BX), Y15, Y11     // c463050f1b07
-	//TODO: VPALIGNR $7, (R11), Y15, Y11    // c443050f1b07
-	//TODO: VPALIGNR $7, Y2, Y15, Y11       // c463050fda07
-	//TODO: VPALIGNR $7, Y11, Y15, Y11      // c443050fdb07
+	VPALIGNR $7, (BX), Y15, Y2      // c4e3050f1307
+	VPALIGNR $7, (R11), Y15, Y2     // c4c3050f1307
+	VPALIGNR $7, Y2, Y15, Y2        // c4e3050fd207
+	VPALIGNR $7, Y11, Y15, Y2       // c4c3050fd307
+	VPALIGNR $7, (BX), Y15, Y11     // c463050f1b07
+	VPALIGNR $7, (R11), Y15, Y11    // c443050f1b07
+	VPALIGNR $7, Y2, Y15, Y11       // c463050fda07
+	VPALIGNR $7, Y11, Y15, Y11      // c443050fdb07
 	VPAND (BX), X9, X2                      // c4e131db13 or c5b1db13
 	VPAND (R11), X9, X2                     // c4c131db13
 	VPAND X2, X9, X2                        // c4e131dbd2 or c5b1dbd2
@@ -8342,14 +8342,14 @@ TEXT asmtest(SB),7,$0
 	//TODO: VPBLENDD $7, (R11), X9, X11     // c44331021b07
 	//TODO: VPBLENDD $7, X2, X9, X11        // c4633102da07
 	//TODO: VPBLENDD $7, X11, X9, X11       // c4433102db07
-	//TODO: VPBLENDD $7, (BX), Y15, Y2      // c4e305021307
-	//TODO: VPBLENDD $7, (R11), Y15, Y2     // c4c305021307
-	//TODO: VPBLENDD $7, Y2, Y15, Y2        // c4e30502d207
-	//TODO: VPBLENDD $7, Y11, Y15, Y2       // c4c30502d307
-	//TODO: VPBLENDD $7, (BX), Y15, Y11     // c46305021b07
-	//TODO: VPBLENDD $7, (R11), Y15, Y11    // c44305021b07
-	//TODO: VPBLENDD $7, Y2, Y15, Y11       // c4630502da07
-	//TODO: VPBLENDD $7, Y11, Y15, Y11      // c4430502db07
+	VPBLENDD $7, (BX), Y15, Y2      // c4e305021307
+	VPBLENDD $7, (R11), Y15, Y2     // c4c305021307
+	VPBLENDD $7, Y2, Y15, Y2        // c4e30502d207
+	VPBLENDD $7, Y11, Y15, Y2       // c4c30502d307
+	VPBLENDD $7, (BX), Y15, Y11     // c46305021b07
+	VPBLENDD $7, (R11), Y15, Y11    // c44305021b07
+	VPBLENDD $7, Y2, Y15, Y11       // c4630502da07
+	VPBLENDD $7, Y11, Y15, Y11      // c4430502db07
 	//TODO: VPBLENDVB XMM12, (BX), X9, X2   // c4e3314c13c0
 	//TODO: VPBLENDVB XMM12, (R11), X9, X2  // c4c3314c13c0
 	//TODO: VPBLENDVB XMM12, X2, X9, X2     // c4e3314cd2c0
@@ -8614,22 +8614,22 @@ TEXT asmtest(SB),7,$0
 	//TODO: VPCMPISTRM $7, (R11), X11       // c44379621b07
 	//TODO: VPCMPISTRM $7, X2, X11          // c4637962da07
 	//TODO: VPCMPISTRM $7, X11, X11         // c4437962db07
-	//TODO: VPERM2F128 $7, (BX), Y15, Y2    // c4e305061307
-	//TODO: VPERM2F128 $7, (R11), Y15, Y2   // c4c305061307
-	//TODO: VPERM2F128 $7, Y2, Y15, Y2      // c4e30506d207
-	//TODO: VPERM2F128 $7, Y11, Y15, Y2     // c4c30506d307
-	//TODO: VPERM2F128 $7, (BX), Y15, Y11   // c46305061b07
-	//TODO: VPERM2F128 $7, (R11), Y15, Y11  // c44305061b07
-	//TODO: VPERM2F128 $7, Y2, Y15, Y11     // c4630506da07
-	//TODO: VPERM2F128 $7, Y11, Y15, Y11    // c4430506db07
-	//TODO: VPERM2I128 $7, (BX), Y15, Y2    // c4e305461307
-	//TODO: VPERM2I128 $7, (R11), Y15, Y2   // c4c305461307
-	//TODO: VPERM2I128 $7, Y2, Y15, Y2      // c4e30546d207
-	//TODO: VPERM2I128 $7, Y11, Y15, Y2     // c4c30546d307
-	//TODO: VPERM2I128 $7, (BX), Y15, Y11   // c46305461b07
-	//TODO: VPERM2I128 $7, (R11), Y15, Y11  // c44305461b07
-	//TODO: VPERM2I128 $7, Y2, Y15, Y11     // c4630546da07
-	//TODO: VPERM2I128 $7, Y11, Y15, Y11    // c4430546db07
+	VPERM2F128 $7, (BX), Y15, Y2    // c4e305061307
+	VPERM2F128 $7, (R11), Y15, Y2   // c4c305061307
+	VPERM2F128 $7, Y2, Y15, Y2      // c4e30506d207
+	VPERM2F128 $7, Y11, Y15, Y2     // c4c30506d307
+	VPERM2F128 $7, (BX), Y15, Y11   // c46305061b07
+	VPERM2F128 $7, (R11), Y15, Y11  // c44305061b07
+	VPERM2F128 $7, Y2, Y15, Y11     // c4630506da07
+	VPERM2F128 $7, Y11, Y15, Y11    // c4430506db07
+	VPERM2I128 $7, (BX), Y15, Y2    // c4e305461307
+	VPERM2I128 $7, (R11), Y15, Y2   // c4c305461307
+	VPERM2I128 $7, Y2, Y15, Y2      // c4e30546d207
+	VPERM2I128 $7, Y11, Y15, Y2     // c4c30546d307
+	VPERM2I128 $7, (BX), Y15, Y11   // c46305461b07
+	VPERM2I128 $7, (R11), Y15, Y11  // c44305461b07
+	VPERM2I128 $7, Y2, Y15, Y11     // c4630546da07
+	VPERM2I128 $7, Y11, Y15, Y11    // c4430546db07
 	//TODO: VPERMD (BX), Y15, Y2            // c4e2053613
 	//TODO: VPERMD (R11), Y15, Y2           // c4c2053613
 	//TODO: VPERMD Y2, Y15, Y2              // c4e20536d2
@@ -9462,22 +9462,22 @@ TEXT asmtest(SB),7,$0
 	//TODO: VPMULUDQ (R11), Y15, Y11        // c44105f41b
 	//TODO: VPMULUDQ Y2, Y15, Y11           // c46105f4da or c505f4da
 	//TODO: VPMULUDQ Y11, Y15, Y11          // c44105f4db
-	//TODO: VPOR (BX), X9, X2               // c4e131eb13 or c5b1eb13
-	//TODO: VPOR (R11), X9, X2              // c4c131eb13
-	//TODO: VPOR X2, X9, X2                 // c4e131ebd2 or c5b1ebd2
-	//TODO: VPOR X11, X9, X2                // c4c131ebd3
-	//TODO: VPOR (BX), X9, X11              // c46131eb1b or c531eb1b
-	//TODO: VPOR (R11), X9, X11             // c44131eb1b
-	//TODO: VPOR X2, X9, X11                // c46131ebda or c531ebda
-	//TODO: VPOR X11, X9, X11               // c44131ebdb
-	//TODO: VPOR (BX), Y15, Y2              // c4e105eb13 or c585eb13
-	//TODO: VPOR (R11), Y15, Y2             // c4c105eb13
-	//TODO: VPOR Y2, Y15, Y2                // c4e105ebd2 or c585ebd2
-	//TODO: VPOR Y11, Y15, Y2               // c4c105ebd3
-	//TODO: VPOR (BX), Y15, Y11             // c46105eb1b or c505eb1b
-	//TODO: VPOR (R11), Y15, Y11            // c44105eb1b
-	//TODO: VPOR Y2, Y15, Y11               // c46105ebda or c505ebda
-	//TODO: VPOR Y11, Y15, Y11              // c44105ebdb
+	VPOR (BX), X9, X2               // c4e131eb13 or c5b1eb13
+	VPOR (R11), X9, X2              // c4c131eb13
+	VPOR X2, X9, X2                 // c4e131ebd2 or c5b1ebd2
+	VPOR X11, X9, X2                // c4c131ebd3
+	VPOR (BX), X9, X11              // c46131eb1b or c531eb1b
+	VPOR (R11), X9, X11             // c44131eb1b
+	VPOR X2, X9, X11                // c46131ebda or c531ebda
+	VPOR X11, X9, X11               // c44131ebdb
+	VPOR (BX), Y15, Y2              // c4e105eb13 or c585eb13
+	VPOR (R11), Y15, Y2             // c4c105eb13
+	VPOR Y2, Y15, Y2                // c4e105ebd2 or c585ebd2
+	VPOR Y11, Y15, Y2               // c4c105ebd3
+	VPOR (BX), Y15, Y11             // c46105eb1b or c505eb1b
+	VPOR (R11), Y15, Y11            // c44105eb1b
+	VPOR Y2, Y15, Y11               // c46105ebda or c505ebda
+	VPOR Y11, Y15, Y11              // c44105ebdb
 	//TODO: VPSADBW (BX), X9, X2            // c4e131f613 or c5b1f613
 	//TODO: VPSADBW (R11), X9, X2           // c4c131f613
 	//TODO: VPSADBW X2, X9, X2              // c4e131f6d2 or c5b1f6d2
@@ -9494,38 +9494,38 @@ TEXT asmtest(SB),7,$0
 	//TODO: VPSADBW (R11), Y15, Y11         // c44105f61b
 	//TODO: VPSADBW Y2, Y15, Y11            // c46105f6da or c505f6da
 	//TODO: VPSADBW Y11, Y15, Y11           // c44105f6db
-	//TODO: VPSHUFB (BX), X9, X2            // c4e2310013
-	//TODO: VPSHUFB (R11), X9, X2           // c4c2310013
-	//TODO: VPSHUFB X2, X9, X2              // c4e23100d2
-	//TODO: VPSHUFB X11, X9, X2             // c4c23100d3
-	//TODO: VPSHUFB (BX), X9, X11           // c46231001b
-	//TODO: VPSHUFB (R11), X9, X11          // c44231001b
-	//TODO: VPSHUFB X2, X9, X11             // c4623100da
-	//TODO: VPSHUFB X11, X9, X11            // c4423100db
-	//TODO: VPSHUFB (BX), Y15, Y2           // c4e2050013
-	//TODO: VPSHUFB (R11), Y15, Y2          // c4c2050013
-	//TODO: VPSHUFB Y2, Y15, Y2             // c4e20500d2
-	//TODO: VPSHUFB Y11, Y15, Y2            // c4c20500d3
-	//TODO: VPSHUFB (BX), Y15, Y11          // c46205001b
-	//TODO: VPSHUFB (R11), Y15, Y11         // c44205001b
-	//TODO: VPSHUFB Y2, Y15, Y11            // c4620500da
-	//TODO: VPSHUFB Y11, Y15, Y11           // c4420500db
-	//TODO: VPSHUFD $7, (BX), X2            // c4e179701307 or c5f9701307
-	//TODO: VPSHUFD $7, (R11), X2           // c4c179701307
-	//TODO: VPSHUFD $7, X2, X2              // c4e17970d207 or c5f970d207
-	//TODO: VPSHUFD $7, X11, X2             // c4c17970d307
-	//TODO: VPSHUFD $7, (BX), X11           // c46179701b07 or c579701b07
-	//TODO: VPSHUFD $7, (R11), X11          // c44179701b07
-	//TODO: VPSHUFD $7, X2, X11             // c4617970da07 or c57970da07
-	//TODO: VPSHUFD $7, X11, X11            // c4417970db07
-	//TODO: VPSHUFD $7, (BX), Y2            // c4e17d701307 or c5fd701307
-	//TODO: VPSHUFD $7, (R11), Y2           // c4c17d701307
-	//TODO: VPSHUFD $7, Y2, Y2              // c4e17d70d207 or c5fd70d207
-	//TODO: VPSHUFD $7, Y11, Y2             // c4c17d70d307
-	//TODO: VPSHUFD $7, (BX), Y11           // c4617d701b07 or c57d701b07
-	//TODO: VPSHUFD $7, (R11), Y11          // c4417d701b07
-	//TODO: VPSHUFD $7, Y2, Y11             // c4617d70da07 or c57d70da07
-	//TODO: VPSHUFD $7, Y11, Y11            // c4417d70db07
+	VPSHUFB (BX), X9, X2            // c4e2310013
+	VPSHUFB (R11), X9, X2           // c4c2310013
+	VPSHUFB X2, X9, X2              // c4e23100d2
+	VPSHUFB X11, X9, X2             // c4c23100d3
+	VPSHUFB (BX), X9, X11           // c46231001b
+	VPSHUFB (R11), X9, X11          // c44231001b
+	VPSHUFB X2, X9, X11             // c4623100da
+	VPSHUFB X11, X9, X11            // c4423100db
+	VPSHUFB (BX), Y15, Y2           // c4e2050013
+	VPSHUFB (R11), Y15, Y2          // c4c2050013
+	VPSHUFB Y2, Y15, Y2             // c4e20500d2
+	VPSHUFB Y11, Y15, Y2            // c4c20500d3
+	VPSHUFB (BX), Y15, Y11          // c46205001b
+	VPSHUFB (R11), Y15, Y11         // c44205001b
+	VPSHUFB Y2, Y15, Y11            // c4620500da
+	VPSHUFB Y11, Y15, Y11           // c4420500db
+	VPSHUFD $7, (BX), X2            // c4e179701307 or c5f9701307
+	VPSHUFD $7, (R11), X2           // c4c179701307
+	VPSHUFD $7, X2, X2              // c4e17970d207 or c5f970d207
+	VPSHUFD $7, X11, X2             // c4c17970d307
+	VPSHUFD $7, (BX), X11           // c46179701b07 or c579701b07
+	VPSHUFD $7, (R11), X11          // c44179701b07
+	VPSHUFD $7, X2, X11             // c4617970da07 or c57970da07
+	VPSHUFD $7, X11, X11            // c4417970db07
+	VPSHUFD $7, (BX), Y2            // c4e17d701307 or c5fd701307
+	VPSHUFD $7, (R11), Y2           // c4c17d701307
+	VPSHUFD $7, Y2, Y2              // c4e17d70d207 or c5fd70d207
+	VPSHUFD $7, Y11, Y2             // c4c17d70d307
+	VPSHUFD $7, (BX), Y11           // c4617d701b07 or c57d701b07
+	VPSHUFD $7, (R11), Y11          // c4417d701b07
+	VPSHUFD $7, Y2, Y11             // c4617d70da07 or c57d70da07
+	VPSHUFD $7, Y11, Y11            // c4417d70db07
 	//TODO: VPSHUFHW $7, (BX), X2           // c4e17a701307 or c5fa701307
 	//TODO: VPSHUFHW $7, (R11), X2          // c4c17a701307
 	//TODO: VPSHUFHW $7, X2, X2             // c4e17a70d207 or c5fa70d207
@@ -9606,30 +9606,30 @@ TEXT asmtest(SB),7,$0
 	//TODO: VPSIGNW (R11), Y15, Y11         // c44205091b
 	//TODO: VPSIGNW Y2, Y15, Y11            // c4620509da
 	//TODO: VPSIGNW Y11, Y15, Y11           // c4420509db
-	//TODO: VPSLLD (BX), X9, X2             // c4e131f213 or c5b1f213
-	//TODO: VPSLLD (R11), X9, X2            // c4c131f213
-	//TODO: VPSLLD X2, X9, X2               // c4e131f2d2 or c5b1f2d2
-	//TODO: VPSLLD X11, X9, X2              // c4c131f2d3
-	//TODO: VPSLLD (BX), X9, X11            // c46131f21b or c531f21b
-	//TODO: VPSLLD (R11), X9, X11           // c44131f21b
-	//TODO: VPSLLD X2, X9, X11              // c46131f2da or c531f2da
-	//TODO: VPSLLD X11, X9, X11             // c44131f2db
-	//TODO: VPSLLD $7, X2, X9               // c4e13172f207 or c5b172f207
-	//TODO: VPSLLD $7, X11, X9              // c4c13172f307
-	//TODO: VPSLLDQ $7, X2, X9              // c4e13173fa07 or c5b173fa07
-	//TODO: VPSLLDQ $7, X11, X9             // c4c13173fb07
-	//TODO: VPSLLDQ $7, Y2, Y15             // c4e10573fa07 or c58573fa07
-	//TODO: VPSLLDQ $7, Y11, Y15            // c4c10573fb07
-	//TODO: VPSLLQ (BX), X9, X2             // c4e131f313 or c5b1f313
-	//TODO: VPSLLQ (R11), X9, X2            // c4c131f313
-	//TODO: VPSLLQ X2, X9, X2               // c4e131f3d2 or c5b1f3d2
-	//TODO: VPSLLQ X11, X9, X2              // c4c131f3d3
-	//TODO: VPSLLQ (BX), X9, X11            // c46131f31b or c531f31b
-	//TODO: VPSLLQ (R11), X9, X11           // c44131f31b
-	//TODO: VPSLLQ X2, X9, X11              // c46131f3da or c531f3da
-	//TODO: VPSLLQ X11, X9, X11             // c44131f3db
-	//TODO: VPSLLQ $7, X2, X9               // c4e13173f207 or c5b173f207
-	//TODO: VPSLLQ $7, X11, X9              // c4c13173f307
+	VPSLLD (BX), X9, X2             // c4e131f213 or c5b1f213
+	VPSLLD (R11), X9, X2            // c4c131f213
+	VPSLLD X2, X9, X2               // c4e131f2d2 or c5b1f2d2
+	VPSLLD X11, X9, X2              // c4c131f2d3
+	VPSLLD (BX), X9, X11            // c46131f21b or c531f21b
+	VPSLLD (R11), X9, X11           // c44131f21b
+	VPSLLD X2, X9, X11              // c46131f2da or c531f2da
+	VPSLLD X11, X9, X11             // c44131f2db
+	VPSLLD $7, X2, X9               // c4e13172f207 or c5b172f207
+	VPSLLD $7, X11, X9              // c4c13172f307
+	VPSLLDQ $7, X2, X9              // c4e13173fa07 or c5b173fa07
+	VPSLLDQ $7, X11, X9             // c4c13173fb07
+	VPSLLDQ $7, Y2, Y15             // c4e10573fa07 or c58573fa07
+	VPSLLDQ $7, Y11, Y15            // c4c10573fb07
+	VPSLLQ (BX), X9, X2             // c4e131f313 or c5b1f313
+	VPSLLQ (R11), X9, X2            // c4c131f313
+	VPSLLQ X2, X9, X2               // c4e131f3d2 or c5b1f3d2
+	VPSLLQ X11, X9, X2              // c4c131f3d3
+	VPSLLQ (BX), X9, X11            // c46131f31b or c531f31b
+	VPSLLQ (R11), X9, X11           // c44131f31b
+	VPSLLQ X2, X9, X11              // c46131f3da or c531f3da
+	VPSLLQ X11, X9, X11             // c44131f3db
+	VPSLLQ $7, X2, X9               // c4e13173f207 or c5b173f207
+	VPSLLQ $7, X11, X9              // c4c13173f307
 	//TODO: VPSLLVD (BX), X9, X2            // c4e2314713
 	//TODO: VPSLLVD (R11), X9, X2           // c4c2314713
 	//TODO: VPSLLVD X2, X9, X2              // c4e23147d2
@@ -9738,30 +9738,30 @@ TEXT asmtest(SB),7,$0
 	//TODO: VPSRAW X11, Y15, Y11            // c44105e1db
 	//TODO: VPSRAW $7, Y2, Y15              // c4e10571e207 or c58571e207
 	//TODO: VPSRAW $7, Y11, Y15             // c4c10571e307
-	//TODO: VPSRLD (BX), X9, X2             // c4e131d213 or c5b1d213
-	//TODO: VPSRLD (R11), X9, X2            // c4c131d213
-	//TODO: VPSRLD X2, X9, X2               // c4e131d2d2 or c5b1d2d2
-	//TODO: VPSRLD X11, X9, X2              // c4c131d2d3
-	//TODO: VPSRLD (BX), X9, X11            // c46131d21b or c531d21b
-	//TODO: VPSRLD (R11), X9, X11           // c44131d21b
-	//TODO: VPSRLD X2, X9, X11              // c46131d2da or c531d2da
-	//TODO: VPSRLD X11, X9, X11             // c44131d2db
-	//TODO: VPSRLD $7, X2, X9               // c4e13172d207 or c5b172d207
-	//TODO: VPSRLD $7, X11, X9              // c4c13172d307
-	//TODO: VPSRLDQ $7, X2, X9              // c4e13173da07 or c5b173da07
-	//TODO: VPSRLDQ $7, X11, X9             // c4c13173db07
-	//TODO: VPSRLDQ $7, Y2, Y15             // c4e10573da07 or c58573da07
-	//TODO: VPSRLDQ $7, Y11, Y15            // c4c10573db07
-	//TODO: VPSRLQ (BX), X9, X2             // c4e131d313 or c5b1d313
-	//TODO: VPSRLQ (R11), X9, X2            // c4c131d313
-	//TODO: VPSRLQ X2, X9, X2               // c4e131d3d2 or c5b1d3d2
-	//TODO: VPSRLQ X11, X9, X2              // c4c131d3d3
-	//TODO: VPSRLQ (BX), X9, X11            // c46131d31b or c531d31b
-	//TODO: VPSRLQ (R11), X9, X11           // c44131d31b
-	//TODO: VPSRLQ X2, X9, X11              // c46131d3da or c531d3da
-	//TODO: VPSRLQ X11, X9, X11             // c44131d3db
-	//TODO: VPSRLQ $7, X2, X9               // c4e13173d207 or c5b173d207
-	//TODO: VPSRLQ $7, X11, X9              // c4c13173d307
+	VPSRLD (BX), X9, X2             // c4e131d213 or c5b1d213
+	VPSRLD (R11), X9, X2            // c4c131d213
+	VPSRLD X2, X9, X2               // c4e131d2d2 or c5b1d2d2
+	VPSRLD X11, X9, X2              // c4c131d2d3
+	VPSRLD (BX), X9, X11            // c46131d21b or c531d21b
+	VPSRLD (R11), X9, X11           // c44131d21b
+	VPSRLD X2, X9, X11              // c46131d2da or c531d2da
+	VPSRLD X11, X9, X11             // c44131d2db
+	VPSRLD $7, X2, X9               // c4e13172d207 or c5b172d207
+	VPSRLD $7, X11, X9              // c4c13172d307
+	VPSRLDQ $7, X2, X9              // c4e13173da07 or c5b173da07
+	VPSRLDQ $7, X11, X9             // c4c13173db07
+	VPSRLDQ $7, Y2, Y15             // c4e10573da07 or c58573da07
+	VPSRLDQ $7, Y11, Y15            // c4c10573db07
+	VPSRLQ (BX), X9, X2             // c4e131d313 or c5b1d313
+	VPSRLQ (R11), X9, X2            // c4c131d313
+	VPSRLQ X2, X9, X2               // c4e131d3d2 or c5b1d3d2
+	VPSRLQ X11, X9, X2              // c4c131d3d3
+	VPSRLQ (BX), X9, X11            // c46131d31b or c531d31b
+	VPSRLQ (R11), X9, X11           // c44131d31b
+	VPSRLQ X2, X9, X11              // c46131d3da or c531d3da
+	VPSRLQ X11, X9, X11             // c44131d3db
+	VPSRLQ $7, X2, X9               // c4e13173d207 or c5b173d207
+	VPSRLQ $7, X11, X9              // c4c13173d307
 	//TODO: VPSRLVD (BX), X9, X2            // c4e2314513
 	//TODO: VPSRLVD (R11), X9, X2           // c4c2314513
 	//TODO: VPSRLVD X2, X9, X2              // c4e23145d2
diff --git a/src/cmd/asm/internal/asm/testdata/amd64error.s b/src/cmd/asm/internal/asm/testdata/amd64error.s
index 9895b54..fe3ebec 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64error.s
+++ b/src/cmd/asm/internal/asm/testdata/amd64error.s
@@ -1,7 +1,8 @@
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
 TEXT errors(SB),$0
-	MOVL	foo<>(SB)(AX), AX // ERROR "invalid instruction"
+	MOVL	foo<>(SB)(AX), AX	// ERROR "invalid instruction"
+	MOVL	(AX)(SP*1), AX		// ERROR "invalid instruction"
 	RET
diff --git a/src/cmd/asm/internal/asm/testdata/arm.s b/src/cmd/asm/internal/asm/testdata/arm.s
index 8062750..06fc44c 100644
--- a/src/cmd/asm/internal/asm/testdata/arm.s
+++ b/src/cmd/asm/internal/asm/testdata/arm.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index 22d4306..8d50196 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -237,7 +237,7 @@ again:
 //
 //		LSTXR reg ',' addr ',' reg
 //	{
-//		outtcode($1, &$2, &$4, &$6);
+//		outcode($1, &$2, &$4, &$6);
 //	}
 	LDAXRW	(R0), R2
 	STLXRW	R1, (R0), R3
diff --git a/src/cmd/asm/internal/asm/testdata/mips64.s b/src/cmd/asm/internal/asm/testdata/mips64.s
index 12330a2..e217d35 100644
--- a/src/cmd/asm/internal/asm/testdata/mips64.s
+++ b/src/cmd/asm/internal/asm/testdata/mips64.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -326,7 +326,6 @@ label4:
 // WORD
 //
 	WORD	$1
-	WORD	$foo(SB)
 
 //
 // NOP
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s
index c46c6b2..2e3bf3b 100644
--- a/src/cmd/asm/internal/asm/testdata/ppc64.s
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/asm/internal/asm/testdata/s390x.s b/src/cmd/asm/internal/asm/testdata/s390x.s
new file mode 100644
index 0000000..7729384
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/s390x.s
@@ -0,0 +1,223 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
+	MOVD	R1, R2                // b9040021
+	MOVW	R3, R4                // b9140043
+	MOVH	R5, R6                // b9070065
+	MOVB	R7, R8                // b9060087
+	MOVWZ	R1, R2                // b9160021
+	MOVHZ	R2, R3                // b9850032
+	MOVBZ	R4, R5                // b9840054
+	MOVDBR	R1, R2                // b90f0021
+	MOVWBR	R3, R4                // b91f0043
+
+	MOVD	(R15), R1             // e310f0000004
+	MOVW	(R15), R2             // e320f0000014
+	MOVH	(R15), R3             // e330f0000015
+	MOVB	(R15), R4             // e340f0000077
+	MOVWZ	(R15), R5             // e350f0000016
+	MOVHZ	(R15), R6             // e360f0000091
+	MOVBZ	(R15), R7             // e370f0000090
+	MOVDBR	(R15), R8             // e380f000000f
+	MOVWBR	(R15), R9             // e390f000001e
+
+	MOVD	R1, n-8(SP)           // e310f0100024
+	MOVW	R2, n-8(SP)           // e320f0100050
+	MOVH	R3, n-8(SP)           // e330f0100070
+	MOVB	R4, n-8(SP)           // e340f0100072
+	MOVWZ	R5, n-8(SP)           // e350f0100050
+	MOVHZ	R6, n-8(SP)           // e360f0100070
+	MOVBZ	R7, n-8(SP)           // e370f0100072
+	MOVDBR	R8, n-8(SP)           // e380f010002f
+	MOVWBR	R9, n-8(SP)           // e390f010003e
+
+	MOVD	$-8589934592, R1      // c01efffffffe
+	MOVW	$-131072, R2          // c021fffe0000
+	MOVH	$-512, R3             // a739fe00
+	MOVB	$-1, R4               // a749ffff
+
+	MOVD	$-2147483648, n-8(SP) // c0b180000000e3b0f0100024
+	MOVW	$-131072, n-8(SP)     // c0b1fffe0000e3b0f0100050
+	MOVH	$-512, n-8(SP)        // e544f010fe00
+	MOVB	$-1, n-8(SP)          // 92fff010
+
+	ADD	R1, R2                // b9e81022
+	ADD	R1, R2, R3            // b9e81032
+	ADD	$8192, R1             // c21800002000
+	ADD	$8192, R1, R2         // ec21200000d9
+	ADDC	R1, R2                // b9ea1022
+	ADDC	$1, R1, R2            // b9040021c22a00000001
+	ADDC	R1, R2, R3            // b9ea1032
+	SUB	R3, R4                // b9090043
+	SUB	R3, R4, R5            // b9e93054
+	SUB	$8192, R3             // c238ffffe000
+	SUB	$8192, R3, R4         // ec43e00000d9
+	SUBC	R1, R2                // b90b0021
+	SUBC	$1, R1, R2            // b9040021c22affffffff
+	SUBC	R2, R3, R4            // b9eb2043
+	MULLW	R6, R7                // b91c0076
+	MULLW	R6, R7, R8            // b9040087b91c0086
+	MULLW	$8192, R6             // a76d2000
+	MULLW	$8192, R6, R7         // b9040076a77d2000
+	MULLW	$-65537, R8           // c280fffeffff
+	MULLW   $-65537, R8, R9       // b9040098c290fffeffff
+	MULLD	$-2147483648, R1      // c21080000000
+	MULLD   $-2147483648, R1, R2  // b9040021c22080000000
+	MULHD	R9, R8                // b90400b8b98600a9ebb9003f000ab98000b8b90900abebb8003f000ab98000b9b9e9b08a
+	MULHD	R7, R2, R1            // b90400b2b98600a7ebb7003f000ab98000b2b90900abebb2003f000ab98000b7b9e9b01a
+	MULHDU	R3, R4                // b90400b4b98600a3b904004a
+	MULHDU	R5, R6, R7            // b90400b6b98600a5b904007a
+	DIVD	R1, R2                // b90400b2b90d00a1b904002b
+	DIVD	R1, R2, R3            // b90400b2b90d00a1b904003b
+	DIVW	R4, R5                // b90400b5b91d00a4b904005b
+	DIVW	R4, R5, R6            // b90400b5b91d00a4b904006b
+	DIVDU	R7, R8                // b90400a0b90400b8b98700a7b904008b
+	DIVDU	R7, R8, R9            // b90400a0b90400b8b98700a7b904009b
+	DIVWU	R1, R2                // b90400a0b90400b2b99700a1b904002b
+	DIVWU	R1, R2, R3            // b90400a0b90400b2b99700a1b904003b
+
+	XC	$8, (R15), n-8(SP)       // XC  (R15), $8, n-8(SP)       // d707f010f000
+	NC	$8, (R15), n-8(SP)       // NC  (R15), $8, n-8(SP)       // d407f010f000
+	OC	$8, (R15), n-8(SP)       // OC  (R15), $8, n-8(SP)       // d607f010f000
+	MVC	$8, (R15), n-8(SP)       // MVC (R15), $8, n-8(SP)       // d207f010f000
+	CLC	$8, (R15), n-8(SP)       // CLC (R15), $8, n-8(SP)       // d507f000f010
+	XC	$256, -8(R15), -8(R15)   // XC  -8(R15), $256, -8(R15)   // b90400afc2a8fffffff8d7ffa000a000
+	MVC	$256, 8192(R1), 8192(R2) // MVC 8192(R1), $256, 8192(R2) // b90400a2c2a800002000b90400b1c2b800002000d2ffa000b000
+
+	CMP	R1, R2                 // b9200012
+	CMP	R3, $-2147483648       // c23c80000000
+	CMPU	R4, R5                 // b9210045
+	CMPU	R6, $4294967295        // c26effffffff
+	CMPW	R7, R8                 // 1978
+	CMPW	R9, $-2147483648       // c29d80000000
+	CMPWU	R1, R2                 // 1512
+	CMPWU	R3, $4294967295        // c23fffffffff
+
+	BNE	0(PC)                  // a7740000
+	BEQ	0(PC)                  // a7840000
+	BLT	0(PC)                  // a7440000
+	BLE	0(PC)                  // a7c40000
+	BGT	0(PC)                  // a7240000
+	BGE	0(PC)                  // a7a40000
+
+	CMPBNE	R1, R2, 0(PC)          // ec1200007064
+	CMPBEQ	R3, R4, 0(PC)          // ec3400008064
+	CMPBLT	R5, R6, 0(PC)          // ec5600004064
+	CMPBLE	R7, R8, 0(PC)          // ec780000c064
+	CMPBGT	R9, R1, 0(PC)          // ec9100002064
+	CMPBGE	R2, R3, 0(PC)          // ec230000a064
+
+	CMPBNE	R1, $-127, 0(PC)       // ec170000817c
+	CMPBEQ	R3, $0, 0(PC)          // ec380000007c
+	CMPBLT	R5, $128, 0(PC)        // ec540000807c
+	CMPBLE	R7, $127, 0(PC)        // ec7c00007f7c
+	CMPBGT	R9, $0, 0(PC)          // ec920000007c
+	CMPBGE	R2, $128, 0(PC)        // ec2a0000807c
+
+	CMPUBNE	R1, R2, 0(PC)          // ec1200007065
+	CMPUBEQ	R3, R4, 0(PC)          // ec3400008065
+	CMPUBLT	R5, R6, 0(PC)          // ec5600004065
+	CMPUBLE	R7, R8, 0(PC)          // ec780000c065
+	CMPUBGT	R9, R1, 0(PC)          // ec9100002065
+	CMPUBGE	R2, R3, 0(PC)          // ec230000a065
+
+	CMPUBNE	R1, $256, 0(PC)        // ec170000007d
+	CMPUBEQ	R3, $0, 0(PC)          // ec380000007d
+	CMPUBLT	R5, $256, 0(PC)        // ec540000007d
+	CMPUBLE	R7, $0, 0(PC)          // ec7c0000007d
+	CMPUBGT	R9, $256, 0(PC)        // ec920000007d
+	CMPUBGE	R2, $0, 0(PC)          // ec2a0000007d
+
+	CEFBRA	R0, F15                // b39400f0
+	CDFBRA	R1, F14                // b39500e1
+	CEGBRA	R2, F13                // b3a400d2
+	CDGBRA	R3, F12                // b3a500c3
+
+	CELFBR	R0, F15                // b39000f0
+	CDLFBR	R1, F14                // b39100e1
+	CELGBR	R2, F13                // b3a000d2
+	CDLGBR	R3, F12                // b3a100c3
+
+	CFEBRA	F15, R1                // b398501f
+	CFDBRA	F14, R2                // b399502e
+	CGEBRA	F13, R3                // b3a8503d
+	CGDBRA	F12, R4                // b3a9504c
+
+	CLFEBR	F15, R1                // b39c501f
+	CLFDBR	F14, R2                // b39d502e
+	CLGEBR	F13, R3                // b3ac503d
+	CLGDBR	F12, R4                // b3ad504c
+
+	FMOVS	$0, F11                // b37400b0
+	FMOVD	$0, F12                // b37500c0
+	FMOVS	(R1)(R2*1), F0         // ed0210000064
+	FMOVS	n-8(SP), F15           // edf0f0100064
+	FMOVD	-9999999(R8)(R9*1), F8 // c0a1ff67698141aa9000ed8a80000065
+	FMOVD	F4, F5                 // 2854
+	FADDS	F0, F15                // b30a00f0
+	FADD	F1, F14                // b31a00e1
+	FSUBS	F2, F13                // b30b00d2
+	FSUB	F3, F12                // b31b00c3
+	FMULS	F4, F11                // b31700b4
+	FMUL	F5, F10                // b31c00a5
+	FDIVS	F6, F9                 // b30d0096
+	FDIV	F7, F8                 // b31d0087
+	FABS	F1, F2                 // b3100021
+	FSQRTS	F3, F4                 // b3140043
+	FSQRT	F5, F15                // b31500f5
+
+	VL	(R15), V1              // e710f0000006
+	VST	V1, (R15)              // e710f000000e
+	VL	(R15), V31             // e7f0f0000806
+	VST	V31, (R15)             // e7f0f000080e
+	VESLB	$5, V14                // e7ee00050030
+	VESRAG	$0, V15, V16           // e70f0000383a
+	VLM	(R15), V8, V23         // e787f0000436
+	VSTM	V8, V23, (R15)         // e787f000043e
+	VONE	V1                     // e710ffff0044
+	VZERO	V16                    // e70000000844
+	VGBM	$52428, V31            // e7f0cccc0844
+	VREPIB	$255, V4               // e74000ff0045
+	VREPG	$1, V4, V16            // e7040001384d
+	VREPB	$4, V31, V1            // e71f0004044d
+	VFTCIDB	$4095, V1, V2          // e721fff0304a
+	WFTCIDB	$3276, V15, V16        // e70fccc8384a
+	VPOPCT	V8, V19                // e73800000850
+	VFEEZBS	V1, V2, V31            // e7f120300880
+	WFCHDBS	V22, V23, V4           // e746701836eb
+	VMNH	V1, V2, V30            // e7e1200018fe
+	VO	V2, V1, V0             // e7021000006a
+	VERLLVF	V2, V30, V27           // e7be20002c73
+	VSCBIB	V0, V23, V24           // e78700000cf5
+	VNOT	V16, V1                // e7101000046b
+	VCLZF	V16, V17               // e71000002c53
+	VLVGP	R3, R4, V8             // e78340000062
+
+	// Some vector instructions have their inputs reordered.
+	// Typically the reordering puts the length/index input into From3.
+	VGEG	$1, 8(R15)(V30*1), V31  // VGEG    8(R15)(V30*1), $1, V31  // e7fef0081c12
+	VSCEG	$1, V31, 16(R15)(V30*1) // VSCEG   V31, $1, 16(R15)(V30*1) // e7fef0101c1a
+	VGEF	$0, 2048(R15)(V1*1), V2 // VGEF    2048(R15)(V1*1), $0, V2 // e721f8000013
+	VSCEF	$0, V2, 4095(R15)(V1*1) // VSCEF   V2, $0, 4095(R15)(V1*1) // e721ffff001b
+	VLL	R0, (R15), V1           // VLL     (R15), R0, V1           // e710f0000037
+	VSTL	R0, V16, (R15)          // VSTL    V16, R0, (R15)          // e700f000083f
+	VGMH	$8, $16, V12            // VGMH    $16, $8, V12            // e7c008101046
+	VLEIF	$2, $-43, V16           // VLEIF   $-43, $2, V16           // e700ffd52843
+	VSLDB	$3, V1, V16, V18        // VSLDB   V1, V16, $3, V18        // e72100030a77
+	VERIMB	$2, V31, V1, V2         // VERIMB  V31, V1, $2, V2         // e72f10020472
+	VSEL	V1, V2, V3, V4          // VSEL    V2, V3, V1, V4          // e7412000308d
+	VGFMAH	V21, V31, V24, V0       // VGFMAH  V31, V24, V21, V0       // e705f10087bc
+	WFMSDB	V2, V25, V24, V31       // WFMSDB  V25, V24, V2, V31       // e7f298038b8e
+	VPERM	V31, V0, V2, V3         // VPERM   V0, V2, V31, V3         // e73f0000248c
+	VPDI	$1, V2, V31, V1         // VPDI    V2, V31, $1, V1         // e712f0001284
+
+	RET
+
+TEXT main·init(SB),7,$0 // TEXT main.init(SB), 7, $0
+	RET
+
+TEXT main·main(SB),7,$0 // TEXT main.main(SB), 7, $0
+	BL      main·foo(SB)    // CALL main.foo(SB)
+	RET
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
index fd42e84..4557c2a 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -20,7 +20,7 @@ var (
 	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")
-	AllErrors = flag.Bool("e", false, "no limit on number of errors reported")
+	AllErrors  = flag.Bool("e", false, "no limit on number of errors reported")
 )
 
 var (
@@ -29,7 +29,7 @@ var (
 )
 
 func init() {
-	flag.Var(&D, "D", "predefined symbol with optional simple value -D=identifer=value; can be set multiple times")
+	flag.Var(&D, "D", "predefined symbol with optional simple value -D=identifier=value; can be set multiple times")
 	flag.Var(&I, "I", "include directory; can be set multiple times")
 }
 
diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go
index 33b9d8a..4855daa 100644
--- a/src/cmd/asm/internal/lex/input.go
+++ b/src/cmd/asm/internal/lex/input.go
@@ -30,7 +30,7 @@ type Input struct {
 	peekText        string
 }
 
-// NewInput returns a
+// NewInput returns an Input from the given path.
 func NewInput(name string) *Input {
 	return &Input{
 		// include directories: look in source dir, then -I directories.
diff --git a/src/cmd/asm/internal/lex/lex.go b/src/cmd/asm/internal/lex/lex.go
index 6fce55f..8133905 100644
--- a/src/cmd/asm/internal/lex/lex.go
+++ b/src/cmd/asm/internal/lex/lex.go
@@ -77,7 +77,7 @@ func NewLexer(name string, ctxt *obj.Link) TokenReader {
 	input := NewInput(name)
 	fd, err := os.Open(name)
 	if err != nil {
-		log.Fatalf("asm: %s\n", err)
+		log.Fatalf("%s\n", err)
 	}
 	input.Push(NewTokenizer(name, fd, fd))
 	return input
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index f48050c..c612583 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -5,6 +5,7 @@
 package main
 
 import (
+	"bufio"
 	"flag"
 	"fmt"
 	"log"
@@ -15,6 +16,7 @@ import (
 	"cmd/asm/internal/flags"
 	"cmd/asm/internal/lex"
 
+	"cmd/internal/bio"
 	"cmd/internal/obj"
 )
 
@@ -26,30 +28,31 @@ func main() {
 
 	architecture := arch.Set(GOARCH)
 	if architecture == nil {
-		log.Fatalf("asm: unrecognized architecture %s", GOARCH)
+		log.Fatalf("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)
+	ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
+	ctxt.Bso = bufio.NewWriter(os.Stdout)
 	defer ctxt.Bso.Flush()
-	output := obj.Binitw(fd)
-	fmt.Fprintf(output, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
-	fmt.Fprintf(output, "!\n")
+
+	// Create object file, write header.
+	out, err := os.Create(*flags.OutputFile)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer bio.MustClose(out)
+	buf := bufio.NewWriter(bio.MustWriter(out))
+
+	fmt.Fprintf(buf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
+	fmt.Fprintf(buf, "!\n")
 
 	lexer := lex.NewLexer(flag.Arg(0), ctxt)
 	parser := asm.NewParser(ctxt, architecture, lexer)
@@ -63,12 +66,12 @@ func main() {
 	pList.Firstpc, ok = parser.Parse()
 	if ok {
 		// reports errors to parser.Errorf
-		obj.Writeobjdirect(ctxt, output)
+		obj.Writeobjdirect(ctxt, buf)
 	}
 	if !ok || diag {
-		log.Printf("asm: assembly of %s failed", flag.Arg(0))
+		log.Printf("assembly of %s failed", flag.Arg(0))
 		os.Remove(*flags.OutputFile)
 		os.Exit(1)
 	}
-	output.Flush()
+	buf.Flush()
 }
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index c3a24c2..000ecd4 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -40,7 +40,7 @@ func sourceLine(n ast.Node) int {
 }
 
 // ReadGo populates f with information learned from reading the
-// Go source file with the given file name.  It gathers the C preamble
+// Go source file with the given file name. It gathers the C preamble
 // attached to the import "C" comment, a list of references to C.xxx,
 // a list of exported functions, and the actual AST, to be rewritten and
 // printed.
@@ -73,7 +73,7 @@ func (f *File) ReadGo(name string) {
 		}
 		for _, spec := range d.Specs {
 			s, ok := spec.(*ast.ImportSpec)
-			if !ok || string(s.Path.Value) != `"C"` {
+			if !ok || s.Path.Value != `"C"` {
 				continue
 			}
 			sawC = true
@@ -106,7 +106,7 @@ func (f *File) ReadGo(name string) {
 		ws := 0
 		for _, spec := range d.Specs {
 			s, ok := spec.(*ast.ImportSpec)
-			if !ok || string(s.Path.Value) != `"C"` {
+			if !ok || s.Path.Value != `"C"` {
 				d.Specs[ws] = spec
 				ws++
 			}
@@ -147,7 +147,7 @@ func commentText(g *ast.CommentGroup) string {
 	}
 	var pieces []string
 	for _, com := range g.List {
-		c := string(com.Text)
+		c := com.Text
 		// Remove comment markers.
 		// The parser has given us exactly the comment text.
 		switch c[1] {
@@ -172,7 +172,7 @@ func (f *File) saveExprs(x interface{}, context string) {
 			f.saveRef(x, context)
 		}
 	case *ast.CallExpr:
-		f.saveCall(x)
+		f.saveCall(x, context)
 	}
 }
 
@@ -220,7 +220,7 @@ func (f *File) saveRef(n *ast.Expr, context string) {
 }
 
 // Save calls to C.xxx for later processing.
-func (f *File) saveCall(call *ast.CallExpr) {
+func (f *File) saveCall(call *ast.CallExpr, context string) {
 	sel, ok := call.Fun.(*ast.SelectorExpr)
 	if !ok {
 		return
@@ -228,7 +228,8 @@ func (f *File) saveCall(call *ast.CallExpr) {
 	if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
 		return
 	}
-	f.Calls = append(f.Calls, call)
+	c := &Call{Call: call, Deferred: context == "defer"}
+	f.Calls = append(f.Calls, c)
 }
 
 // If a function should be exported add it to ExpFunc.
@@ -242,11 +243,11 @@ func (f *File) saveExport(x interface{}, context string) {
 		return
 	}
 	for _, c := range n.Doc.List {
-		if !strings.HasPrefix(string(c.Text), "//export ") {
+		if !strings.HasPrefix(c.Text, "//export ") {
 			continue
 		}
 
-		name := strings.TrimSpace(string(c.Text[9:]))
+		name := strings.TrimSpace(c.Text[9:])
 		if name == "" {
 			error_(c.Pos(), "export missing name")
 		}
@@ -401,7 +402,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
 	case *ast.GoStmt:
 		f.walk(n.Call, "expr", visit)
 	case *ast.DeferStmt:
-		f.walk(n.Call, "expr", visit)
+		f.walk(n.Call, "defer", visit)
 	case *ast.ReturnStmt:
 		f.walk(n.Results, "expr", visit)
 	case *ast.BranchStmt:
@@ -447,7 +448,11 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
 	case *ast.ImportSpec:
 	case *ast.ValueSpec:
 		f.walk(&n.Type, "type", visit)
-		f.walk(n.Values, "expr", visit)
+		if len(n.Names) == 2 && len(n.Values) == 1 {
+			f.walk(&n.Values[0], "as2", visit)
+		} else {
+			f.walk(n.Values, "expr", visit)
+		}
 	case *ast.TypeSpec:
 		f.walk(&n.Type, "type", visit)
 
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index bd38a5c..d3a7b6d 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -31,9 +31,9 @@ See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples.  See
 "C? Go? Cgo!" for an introduction to using cgo:
 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
+CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS and LDFLAGS may be defined with pseudo
+#cgo directives within these comments to tweak the behavior of the C, C++
+or Fortran 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 https://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
@@ -53,7 +53,7 @@ For example:
 	// #include <png.h>
 	import "C"
 
-When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS and
+When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
 CGO_LDFLAGS environment variables are added to the flags derived from
 these directives.  Package-specific flags should be set using the
 directives, not the environment variables, so that builds work in
@@ -62,10 +62,11 @@ unmodified environments.
 All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
 used to compile C files in that package.  All the CPPFLAGS and CXXFLAGS
 directives in a package are concatenated and used to compile C++ files in that
-package.  All the LDFLAGS directives in any package in the program are
-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.
+package.  All the CPPFLAGS and FFLAGS directives in a package are concatenated
+and used to compile Fortran files in that package.  All the LDFLAGS directives
+in any package in the program are 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
@@ -83,7 +84,8 @@ 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
 compiled with the C compiler.  Any .cc, .cpp, or .cxx files will be
-compiled with the C++ compiler.  Any .h, .hh, .hpp, or .hxx files will
+compiled with the C++ compiler.  Any .f, .F, .for or .f90 files will be
+compiled with the fortran compiler. Any .h, .hh, .hpp, or .hxx files will
 not be compiled separately, but, if these header files are changed,
 the C and C++ files will be recompiled.  The default C and C++
 compilers may be changed by the CC and CXX environment variables,
@@ -133,7 +135,7 @@ C's union types are represented as a Go byte array with the same length.
 
 Go structs cannot embed fields with C types.
 
-Go code can not refer to zero-sized fields that occur at the end of
+Go code cannot refer to zero-sized fields that occur at the end of
 non-empty C structs.  To get the address of such a field (which is the
 only operation you can do with a zero-sized field) you must take the
 address of the struct and add the size of the struct.
@@ -148,8 +150,9 @@ assignment context to retrieve both the return value (if any) and the
 C errno variable as an error (use _ to skip the result value if the
 function returns void).  For example:
 
-	n, err := C.sqrt(-1)
+	n, err = C.sqrt(-1)
 	_, err := C.voidFunc()
+	var n, err = C.sqrt(1)
 
 Calling C function pointers is currently not supported, however you can
 declare Go variables which hold C function pointers and pass them
@@ -195,6 +198,13 @@ by making copies of the data.  In pseudo-Go definitions:
 	// if C.free is needed).
 	func C.CString(string) *C.char
 
+	// Go []byte slice to C array
+	// The C array is allocated in the C heap using malloc.
+	// It is the caller's responsibility to arrange for it to be
+	// freed, such as by calling C.free (be sure to include stdlib.h
+	// if C.free is needed).
+	func C.CBytes([]byte) unsafe.Pointer
+
 	// C string to Go string
 	func C.GoString(*C.char) string
 
@@ -501,7 +511,6 @@ 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;
@@ -510,8 +519,7 @@ file compiled by gcc, the file x.cgo2.c:
 		a->r = puts((void*)a->p0);
 	}
 
-It waits for Go runtime to be initialized (required for shared libraries),
-extracts the arguments from the pointer to _Cfunc_puts's argument
+It 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.
 
@@ -529,8 +537,8 @@ linkage to the desired libraries. The main function is provided by
 _cgo_main.c:
 
 	int main() { return 0; }
-	void crosscall2(void(*fn)(void*, int), void *a, int c) { }
-	void _cgo_wait_runtime_init_done() { }
+	void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { }
+	uintptr_t _cgo_wait_runtime_init_done() { }
 	void _cgo_allocate(void *a, int c) { }
 	void _cgo_panic(void *a, int c) { }
 
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index e1456cb..fc1d011 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -83,7 +83,7 @@ func (f *File) DiscardCgoDirectives() {
 	f.Preamble = strings.Join(linesOut, "\n")
 }
 
-// addToFlag appends args to flag.  All flags are later written out onto the
+// addToFlag appends args to flag. All flags are later written out onto the
 // _cgo_flags file for the build system to use.
 func (p *Package) addToFlag(flag string, args []string) {
 	p.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
@@ -99,7 +99,7 @@ func (p *Package) addToFlag(flag string, args []string) {
 // Single quotes and double quotes are recognized to prevent splitting within the
 // quoted region, and are removed from the resulting substrings. If a quote in s
 // isn't closed err will be set and r will have the unclosed argument as the
-// last element.  The backslash is used for escaping.
+// last element. The backslash is used for escaping.
 //
 // For example, the following string:
 //
@@ -236,7 +236,7 @@ func (p *Package) guessKinds(f *File) []*Name {
 			if isConst {
 				n.Kind = "const"
 				// Turn decimal into hex, just for consistency
-				// with enum-derived constants.  Otherwise
+				// with enum-derived constants. Otherwise
 				// in the cgo -godefs output half the constants
 				// are in hex and half are in whatever the #define used.
 				i, err := strconv.ParseInt(n.Define, 0, 64)
@@ -385,7 +385,7 @@ func (p *Package) guessKinds(f *File) []*Name {
 	if nerrors > 0 {
 		// Check if compiling the preamble by itself causes any errors,
 		// because the messages we've printed out so far aren't helpful
-		// to users debugging preamble mistakes.  See issue 8442.
+		// to users debugging preamble mistakes. See issue 8442.
 		preambleErrors := p.gccErrors([]byte(f.Preamble))
 		if len(preambleErrors) > 0 {
 			error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
@@ -403,7 +403,7 @@ func (p *Package) guessKinds(f *File) []*Name {
 // being referred to as C.xxx.
 func (p *Package) loadDWARF(f *File, names []*Name) {
 	// Extract the types from the DWARF section of an object
-	// from a well-formed C program.  Gcc only generates DWARF info
+	// from a well-formed C program. Gcc only generates DWARF info
 	// for symbols in the object file, so it is not enough to print the
 	// preamble and hope the symbols we care about will be there.
 	// Instead, emit
@@ -421,7 +421,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
 	}
 
 	// Apple's LLVM-based gcc does not include the enumeration
-	// names and values in its DWARF debug output.  In case we're
+	// names and values in its DWARF debug output. In case we're
 	// using such a gcc, create a data block initialized with the values.
 	// We can read them out of the object file.
 	fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
@@ -432,7 +432,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
 			fmt.Fprintf(&b, "\t0,\n")
 		}
 	}
-	// for the last entry, we can not use 0, otherwise
+	// for the last entry, we cannot use 0, otherwise
 	// in case all __cgodebug_data is zero initialized,
 	// LLVM-based gcc will place the it in the __DATA.__common
 	// zero-filled section (our debug/macho doesn't support
@@ -581,7 +581,7 @@ func (p *Package) mangleName(n *Name) {
 func (p *Package) rewriteCalls(f *File) {
 	for _, call := range f.Calls {
 		// This is a call to C.xxx; set goname to "xxx".
-		goname := call.Fun.(*ast.SelectorExpr).Sel.Name
+		goname := call.Call.Fun.(*ast.SelectorExpr).Sel.Name
 		if goname == "malloc" {
 			continue
 		}
@@ -594,39 +594,62 @@ func (p *Package) rewriteCalls(f *File) {
 	}
 }
 
-// rewriteCall rewrites one call to add pointer checks.  We replace
+// rewriteCall rewrites one call to add pointer checks. We replace
 // each pointer argument x with _cgoCheckPointer(x).(T).
-func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
+func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
+	// Avoid a crash if the number of arguments is
+	// less than the number of parameters.
+	// This will be caught when the generated file is compiled.
+	if len(call.Call.Args) < len(name.FuncType.Params) {
+		return
+	}
+
+	any := false
 	for i, param := range name.FuncType.Params {
-		if len(call.Args) <= i {
-			// Avoid a crash; this will be caught when the
-			// generated file is compiled.
-			return
-		}
-
-		// An untyped nil does not need a pointer check, and
-		// when _cgoCheckPointer returns the untyped nil the
-		// type assertion we are going to insert will fail.
-		// Easier to just skip nil arguments.
-		// TODO: Note that this fails if nil is shadowed.
-		if id, ok := call.Args[i].(*ast.Ident); ok && id.Name == "nil" {
-			continue
+		if p.needsPointerCheck(f, param.Go, call.Call.Args[i]) {
+			any = true
+			break
+		}
+	}
+	if !any {
+		return
+	}
+
+	// We need to rewrite this call.
+	//
+	// We are going to rewrite C.f(p) to C.f(_cgoCheckPointer(p)).
+	// If the call to C.f is deferred, that will check p at the
+	// point of the defer statement, not when the function is called, so
+	// rewrite to func(_cgo0 ptype) { C.f(_cgoCheckPointer(_cgo0)) }(p)
+
+	var dargs []ast.Expr
+	if call.Deferred {
+		dargs = make([]ast.Expr, len(name.FuncType.Params))
+	}
+	for i, param := range name.FuncType.Params {
+		origArg := call.Call.Args[i]
+		darg := origArg
+
+		if call.Deferred {
+			dargs[i] = darg
+			darg = ast.NewIdent(fmt.Sprintf("_cgo%d", i))
+			call.Call.Args[i] = darg
 		}
 
-		if !p.needsPointerCheck(f, param.Go) {
+		if !p.needsPointerCheck(f, param.Go, origArg) {
 			continue
 		}
 
 		c := &ast.CallExpr{
 			Fun: ast.NewIdent("_cgoCheckPointer"),
 			Args: []ast.Expr{
-				call.Args[i],
+				darg,
 			},
 		}
 
 		// Add optional additional arguments for an address
 		// expression.
-		c.Args = p.checkAddrArgs(f, c.Args, call.Args[i])
+		c.Args = p.checkAddrArgs(f, c.Args, origArg)
 
 		// _cgoCheckPointer returns interface{}.
 		// We need to type assert that to the type we want.
@@ -636,19 +659,19 @@ func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
 		// Instead we use a local variant of _cgoCheckPointer.
 
 		var arg ast.Expr
-		if n := p.unsafeCheckPointerName(param.Go); n != "" {
+		if n := p.unsafeCheckPointerName(param.Go, call.Deferred); n != "" {
 			c.Fun = ast.NewIdent(n)
 			arg = c
 		} else {
 			// In order for the type assertion to succeed,
 			// we need it to match the actual type of the
-			// argument.  The only type we have is the
-			// type of the function parameter.  We know
+			// argument. The only type we have is the
+			// type of the function parameter. We know
 			// that the argument type must be assignable
 			// to the function parameter type, or the code
 			// would not compile, but there is nothing
 			// requiring that the types be exactly the
-			// same.  Add a type conversion to the
+			// same. Add a type conversion to the
 			// argument so that the type assertion will
 			// succeed.
 			c.Args[0] = &ast.CallExpr{
@@ -664,18 +687,77 @@ func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
 			}
 		}
 
-		call.Args[i] = arg
+		call.Call.Args[i] = arg
+	}
+
+	if call.Deferred {
+		params := make([]*ast.Field, len(name.FuncType.Params))
+		for i, param := range name.FuncType.Params {
+			ptype := param.Go
+			if p.hasUnsafePointer(ptype) {
+				// Avoid generating unsafe.Pointer by using
+				// interface{}. This works because we are
+				// going to call a _cgoCheckPointer function
+				// anyhow.
+				ptype = &ast.InterfaceType{
+					Methods: &ast.FieldList{},
+				}
+			}
+			params[i] = &ast.Field{
+				Names: []*ast.Ident{
+					ast.NewIdent(fmt.Sprintf("_cgo%d", i)),
+				},
+				Type: ptype,
+			}
+		}
+
+		dbody := &ast.CallExpr{
+			Fun:  call.Call.Fun,
+			Args: call.Call.Args,
+		}
+		call.Call.Fun = &ast.FuncLit{
+			Type: &ast.FuncType{
+				Params: &ast.FieldList{
+					List: params,
+				},
+			},
+			Body: &ast.BlockStmt{
+				List: []ast.Stmt{
+					&ast.ExprStmt{
+						X: dbody,
+					},
+				},
+			},
+		}
+		call.Call.Args = dargs
+		call.Call.Lparen = token.NoPos
+		call.Call.Rparen = token.NoPos
+
+		// There is a Ref pointing to the old call.Call.Fun.
+		for _, ref := range f.Ref {
+			if ref.Expr == &call.Call.Fun {
+				ref.Expr = &dbody.Fun
+			}
+		}
 	}
 }
 
 // needsPointerCheck returns whether the type t needs a pointer check.
 // This is true if t is a pointer and if the value to which it points
 // might contain a pointer.
-func (p *Package) needsPointerCheck(f *File, t ast.Expr) bool {
+func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
+	// An untyped nil does not need a pointer check, and when
+	// _cgoCheckPointer returns the untyped nil the type assertion we
+	// are going to insert will fail.  Easier to just skip nil arguments.
+	// TODO: Note that this fails if nil is shadowed.
+	if id, ok := arg.(*ast.Ident); ok && id.Name == "nil" {
+		return false
+	}
+
 	return p.hasPointer(f, t, true)
 }
 
-// hasPointer is used by needsPointerCheck.  If top is true it returns
+// hasPointer is used by needsPointerCheck. If top is true it returns
 // whether t is or contains a pointer that might point to a pointer.
 // If top is false it returns whether t is or contains a pointer.
 // f may be nil.
@@ -732,7 +814,7 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
 		if goTypes[t.Name] != nil {
 			return false
 		}
-		// We can't figure out the type.  Conservative
+		// We can't figure out the type. Conservative
 		// approach is to assume it has a pointer.
 		return true
 	case *ast.SelectorExpr:
@@ -750,7 +832,7 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
 		if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
 			return p.hasPointer(f, name.Type.Go, top)
 		}
-		// We can't figure out the type.  Conservative
+		// We can't figure out the type. Conservative
 		// approach is to assume it has a pointer.
 		return true
 	default:
@@ -760,14 +842,14 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
 }
 
 // checkAddrArgs tries to add arguments to the call of
-// _cgoCheckPointer when the argument is an address expression.  We
+// _cgoCheckPointer when the argument is an address expression. We
 // pass true to mean that the argument is an address operation of
 // something other than a slice index, which means that it's only
 // necessary to check the specific element pointed to, not the entire
-// object.  This is for &s.f, where f is a field in a struct.  We can
+// object. This is for &s.f, where f is a field in a struct. We can
 // pass a slice or array, meaning that we should check the entire
 // slice or array but need not check any other part of the object.
-// This is for &s.a[i], where we need to check all of a.  However, we
+// This is for &s.a[i], where we need to check all of a. However, we
 // only pass the slice or array if we can refer to it without side
 // effects.
 func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr {
@@ -786,7 +868,7 @@ func (p *Package) checkAddrArgs(f *File, args []ast.Expr, x ast.Expr) []ast.Expr
 	index, ok := u.X.(*ast.IndexExpr)
 	if !ok {
 		// This is the address of something that is not an
-		// index expression.  We only need to examine the
+		// index expression. We only need to examine the
 		// single value to which it points.
 		// TODO: what if true is shadowed?
 		return append(args, ast.NewIdent("true"))
@@ -853,26 +935,37 @@ func (p *Package) isType(t ast.Expr) bool {
 	return false
 }
 
-// unsafeCheckPointerName is given the Go version of a C type.  If the
+// unsafeCheckPointerName is given the Go version of a C type. If the
 // type uses unsafe.Pointer, we arrange to build a version of
-// _cgoCheckPointer that returns that type.  This avoids using a type
-// assertion to unsafe.Pointer in our copy of user code.  We return
+// _cgoCheckPointer that returns that type. This avoids using a type
+// assertion to unsafe.Pointer in our copy of user code. We return
 // the name of the _cgoCheckPointer function we are going to build, or
 // the empty string if the type does not use unsafe.Pointer.
-func (p *Package) unsafeCheckPointerName(t ast.Expr) string {
+//
+// The deferred parameter is true if this check is for the argument of
+// a deferred function. In that case we need to use an empty interface
+// as the argument type, because the deferred function we introduce in
+// rewriteCall will use an empty interface type, and we can't add a
+// type assertion. This is handled by keeping a separate list, and
+// writing out the lists separately in writeDefs.
+func (p *Package) unsafeCheckPointerName(t ast.Expr, deferred bool) string {
 	if !p.hasUnsafePointer(t) {
 		return ""
 	}
 	var buf bytes.Buffer
 	conf.Fprint(&buf, fset, t)
 	s := buf.String()
-	for i, t := range p.CgoChecks {
+	checks := &p.CgoChecks
+	if deferred {
+		checks = &p.DeferredCgoChecks
+	}
+	for i, t := range *checks {
 		if s == t {
-			return p.unsafeCheckPointerNameIndex(i)
+			return p.unsafeCheckPointerNameIndex(i, deferred)
 		}
 	}
-	p.CgoChecks = append(p.CgoChecks, s)
-	return p.unsafeCheckPointerNameIndex(len(p.CgoChecks) - 1)
+	*checks = append(*checks, s)
+	return p.unsafeCheckPointerNameIndex(len(*checks)-1, deferred)
 }
 
 // hasUnsafePointer returns whether the Go type t uses unsafe.Pointer.
@@ -900,13 +993,16 @@ func (p *Package) hasUnsafePointer(t ast.Expr) bool {
 
 // unsafeCheckPointerNameIndex returns the name to use for a
 // _cgoCheckPointer variant based on the index in the CgoChecks slice.
-func (p *Package) unsafeCheckPointerNameIndex(i int) string {
+func (p *Package) unsafeCheckPointerNameIndex(i int, deferred bool) string {
+	if deferred {
+		return fmt.Sprintf("_cgoCheckPointerInDefer%d", i)
+	}
 	return fmt.Sprintf("_cgoCheckPointer%d", i)
 }
 
 // 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 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
@@ -929,7 +1025,7 @@ func (p *Package) rewriteRef(f *File) {
 
 	// Now that we have all the name types filled in,
 	// scan through the Refs to identify the ones that
-	// are trying to do a ,err call.  Also check that
+	// are trying to do a ,err call. Also check that
 	// functions are only used in calls.
 	for _, r := range f.Ref {
 		if r.Name.Kind == "const" && r.Name.Const == "" {
@@ -987,7 +1083,7 @@ func (p *Package) rewriteRef(f *File) {
 					f.Name[fpName] = name
 				}
 				r.Name = name
-				// Rewrite into call to _Cgo_ptr to prevent assignments.  The _Cgo_ptr
+				// Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
 				// function is defined in out.go and simply returns its argument. See
 				// issue 7757.
 				expr = &ast.CallExpr{
@@ -1009,7 +1105,7 @@ func (p *Package) rewriteRef(f *File) {
 			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))
+				error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
 			}
 
 		case "type":
@@ -1089,6 +1185,8 @@ func (p *Package) gccMachine() []string {
 		return []string{"-m31"}
 	case "s390x":
 		return []string{"-m64"}
+	case "mips64", "mips64le":
+		return []string{"-mabi=64"}
 	}
 	return nil
 }
@@ -1155,7 +1253,7 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
 			for i := range f.Symtab.Syms {
 				s := &f.Symtab.Syms[i]
 				if isDebugData(s.Name) {
-					// Found it.  Now find data section.
+					// Found it. Now find data section.
 					if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
 						sect := f.Sections[i]
 						if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
@@ -1182,7 +1280,7 @@ func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte)
 			for i := range symtab {
 				s := &symtab[i]
 				if isDebugData(s.Name) {
-					// Found it.  Now find data section.
+					// Found it. Now find data section.
 					if i := int(s.Section); 0 <= i && i < len(f.Sections) {
 						sect := f.Sections[i]
 						if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
@@ -1235,18 +1333,26 @@ func (p *Package) gccDefines(stdin []byte) string {
 }
 
 // gccErrors runs gcc over the C program stdin and returns
-// the errors that gcc prints.  That is, this function expects
+// the errors that gcc prints. That is, this function expects
 // gcc to fail.
 func (p *Package) gccErrors(stdin []byte) string {
 	// TODO(rsc): require failure
 	args := p.gccCmd()
 
+	// Optimization options can confuse the error messages; remove them.
+	nargs := make([]string, 0, len(args))
+	for _, arg := range args {
+		if !strings.HasPrefix(arg, "-O") {
+			nargs = append(nargs, arg)
+		}
+	}
+
 	if *debugGcc {
-		fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+		fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
 		os.Stderr.Write(stdin)
 		fmt.Fprint(os.Stderr, "EOF\n")
 	}
-	stdout, stderr, _ := run(stdin, args)
+	stdout, stderr, _ := run(stdin, nargs)
 	if *debugGcc {
 		os.Stderr.Write(stdout)
 		os.Stderr.Write(stderr)
@@ -1282,8 +1388,7 @@ func runGcc(stdin []byte, args []string) (string, string) {
 // with equivalent memory layout.
 type typeConv struct {
 	// Cache of already-translated or in-progress types.
-	m       map[dwarf.Type]*Type
-	typedef map[string]ast.Expr
+	m map[dwarf.Type]*Type
 
 	// Map from types to incomplete pointers to those types.
 	ptrs map[dwarf.Type][]*Type
@@ -1375,7 +1480,7 @@ var dwarfToName = map[string]string{
 
 const signedDelta = 64
 
-// String returns the current type representation.  Format arguments
+// String returns the current type representation. Format arguments
 // are assembled within this method so that any changes in mutable
 // values are taken into account.
 func (tr *TypeRepr) String() string {
@@ -1815,7 +1920,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
 		}
 	case *dwarf.TypedefType:
 		// C has much more relaxed rules than Go for
-		// implicit type conversions.  When the parameter
+		// implicit type conversions. When the parameter
 		// is type T defined as *X, simulate a little of the
 		// laxness of C by making the argument *X instead of T.
 		if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
@@ -1831,7 +1936,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
 			}
 
 			// Remember the C spelling, in case the struct
-			// has __attribute__((unavailable)) on it.  See issue 2888.
+			// has __attribute__((unavailable)) on it. See issue 2888.
 			t.Typedef = dt.Name
 		}
 	}
@@ -1846,7 +1951,7 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
 	for i, f := range dtype.ParamType {
 		// gcc's DWARF generator outputs a single DotDotDotType parameter for
 		// function pointers that specify no parameters (e.g. void
-		// (*__cgo_0)()).  Treat this special case as void.  This case is
+		// (*__cgo_0)()).  Treat this special case as void. This case is
 		// invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
 		// legal).
 		if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
@@ -1917,8 +2022,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 	off := int64(0)
 
 	// Rename struct fields that happen to be named Go keywords into
-	// _{keyword}.  Create a map from C ident -> Go ident.  The Go ident will
-	// be mangled.  Any existing identifier that already has the same name on
+	// _{keyword}.  Create a map from C ident -> Go ident. The Go ident will
+	// be mangled. Any existing identifier that already has the same name on
 	// the C-side will cause the Go-mangled version to be prefixed with _.
 	// (e.g. in a struct with fields '_type' and 'type', the latter would be
 	// rendered as '__type' in Go).
@@ -1958,7 +2063,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 
 		// 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
+		// union as the field in the struct. This handles
 		// cases like the glibc <sys/resource.h> file; see
 		// issue 6677.
 		if *godefs {
@@ -2028,7 +2133,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 	// 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.
+	// which means that it cannot be referenced from Go.
 	for off > 0 && sizes[len(sizes)-1] == 0 {
 		n := len(sizes)
 		fld = fld[0 : n-1]
@@ -2082,7 +2187,7 @@ func godefsFields(fld []*ast.Field) {
 }
 
 // fieldPrefix returns the prefix that should be removed from all the
-// field names when generating the C or Go code.  For generated
+// field names when generating the C or Go code. For generated
 // C, we leave the names as is (tv_sec, tv_usec), since that's what
 // people are used to seeing in C.  For generated Go code, such as
 // package syscall's data structures, we drop a common prefix
@@ -2092,7 +2197,7 @@ func fieldPrefix(fld []*ast.Field) string {
 	for _, f := range fld {
 		for _, n := range f.Names {
 			// Ignore field names that don't have the prefix we're
-			// looking for.  It is common in C headers to have fields
+			// looking for. It is common in C headers to have fields
 			// named, say, _pad in an otherwise prefixed header.
 			// If the struct has 3 fields tv_sec, tv_usec, _pad1, then we
 			// still want to remove the tv_ prefix.
diff --git a/src/cmd/cgo/godefs.go b/src/cmd/cgo/godefs.go
index aff616e..6d638f0 100644
--- a/src/cmd/cgo/godefs.go
+++ b/src/cmd/cgo/godefs.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 0906ceb..72ac19a 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -42,7 +42,10 @@ type Package struct {
 	GoFiles     []string // list of Go files
 	GccFiles    []string // list of gcc output files
 	Preamble    string   // collected preamble for _cgo_export.h
-	CgoChecks   []string // see unsafeCheckPointerName
+
+	// See unsafeCheckPointerName.
+	CgoChecks         []string
+	DeferredCgoChecks []string
 }
 
 // A File collects information about a single Go input file.
@@ -52,7 +55,7 @@ type File struct {
 	Package  string              // Package name
 	Preamble string              // C preamble (doc comment on import "C")
 	Ref      []*Ref              // all references to C.xxx in AST
-	Calls    []*ast.CallExpr     // all calls to C.xxx in AST
+	Calls    []*Call             // all calls to C.xxx in AST
 	ExpFunc  []*ExpFunc          // exported functions for this file
 	Name     map[string]*Name    // map from Go name to Name
 }
@@ -66,6 +69,12 @@ func nameKeys(m map[string]*Name) []string {
 	return ks
 }
 
+// A Call refers to a call of a C.xxx function in the AST.
+type Call struct {
+	Call     *ast.CallExpr
+	Deferred bool
+}
+
 // A Ref refers to an expression of the form C.xxx in the AST.
 type Ref struct {
 	Name    *Name
@@ -156,7 +165,7 @@ var intSizeMap = map[string]int64{
 	"ppc64":    8,
 	"ppc64le":  8,
 	"s390":     4,
-	"s390x":    4,
+	"s390x":    8,
 }
 
 var cPrefix string
@@ -190,9 +199,9 @@ func main() {
 
 	if *dynobj != "" {
 		// cgo -dynimport is essentially a separate helper command
-		// built into the cgo binary.  It scans a gcc-produced executable
+		// built into the cgo binary. It scans a gcc-produced executable
 		// and dumps information about the imported symbols and the
-		// imported libraries.  The 'go build' rules for cgo prepare an
+		// imported libraries. The 'go build' rules for cgo prepare an
 		// appropriate executable and then use its import information
 		// instead of needing to make the linkers duplicate all the
 		// specialized knowledge gcc has about where to look for imported
@@ -227,6 +236,12 @@ func main() {
 
 	goFiles := args[i:]
 
+	for _, arg := range args[:i] {
+		if arg == "-fsanitize=thread" {
+			tsanProlog = yesTsanProlog
+		}
+	}
+
 	p := newPackage(args[:i])
 
 	// Record CGO_LDFLAGS from the environment for external linking.
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index ca0ec0a..842b1c5 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -50,14 +50,16 @@ func (p *Package) writeDefs() {
 	// Write C main file for using gcc to resolve imports.
 	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, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
+		fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done() { return 0; }\n")
+		fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\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 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")
+		// which provides these functions. We just need a prototype.
+		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n")
+		fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
+		fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
 	}
 	fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
 	fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
@@ -110,7 +112,13 @@ func (p *Package) writeDefs() {
 	}
 
 	for i, t := range p.CgoChecks {
-		n := p.unsafeCheckPointerNameIndex(i)
+		n := p.unsafeCheckPointerNameIndex(i, false)
+		fmt.Fprintf(fgo2, "\nfunc %s(p %s, args ...interface{}) %s {\n", n, t, t)
+		fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
+		fmt.Fprintf(fgo2, "}\n")
+	}
+	for i, t := range p.DeferredCgoChecks {
+		n := p.unsafeCheckPointerNameIndex(i, true)
 		fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
 		fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
 		fmt.Fprintf(fgo2, "}\n")
@@ -173,10 +181,11 @@ func (p *Package) writeDefs() {
 	}
 	fmt.Fprintf(fgo2, "\n")
 
+	callsMalloc := false
 	for _, key := range nameKeys(p.Name) {
 		n := p.Name[key]
 		if n.FuncType != nil {
-			p.writeDefsFunc(fgo2, n)
+			p.writeDefsFunc(fgo2, n, &callsMalloc)
 		}
 	}
 
@@ -187,6 +196,12 @@ func (p *Package) writeDefs() {
 	} else {
 		p.writeExports(fgo2, fm, fgcc, fgcch)
 	}
+
+	if callsMalloc && !*gccgo {
+		fmt.Fprint(fgo2, strings.Replace(cMallocDefGo, "PREFIX", cPrefix, -1))
+		fmt.Fprint(fgcc, strings.Replace(strings.Replace(cMallocDefC, "PREFIX", cPrefix, -1), "PACKED", p.packedAttribute(), -1))
+	}
+
 	if err := fgcc.Close(); err != nil {
 		fatalf("%s", err)
 	}
@@ -350,7 +365,7 @@ func (p *Package) structType(n *Name) (string, int64) {
 	return buf.String(), off
 }
 
-func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
+func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) {
 	name := n.Go
 	gtype := n.FuncType.Go
 	void := gtype.Results == nil || len(gtype.Results.List) == 0
@@ -439,6 +454,9 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
 
 	if inProlog {
 		fmt.Fprint(fgo2, builtinDefs[name])
+		if strings.Contains(builtinDefs[name], "_cgo_cmalloc") {
+			*callsMalloc = true
+		}
 		return
 	}
 
@@ -458,6 +476,7 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
 	}
 
 	fmt.Fprint(fgo2, "\n")
+	fmt.Fprint(fgo2, "//go:cgo_unsafe_args\n")
 	conf.Fprint(fgo2, fset, d)
 	fmt.Fprint(fgo2, " {\n")
 
@@ -507,6 +526,7 @@ func (p *Package) writeOutput(f *File, srcfile string) {
 	// Gcc output starts with the preamble.
 	fmt.Fprintf(fgcc, "%s\n", f.Preamble)
 	fmt.Fprintf(fgcc, "%s\n", gccProlog)
+	fmt.Fprintf(fgcc, "%s\n", tsanProlog)
 
 	for _, key := range nameKeys(f.Name) {
 		n := f.Name[key]
@@ -531,6 +551,7 @@ func fixGo(name string) string {
 
 var isBuiltin = map[string]bool{
 	"_Cfunc_CString":   true,
+	"_Cfunc_CBytes":    true,
 	"_Cfunc_GoString":  true,
 	"_Cfunc_GoStringN": true,
 	"_Cfunc_GoBytes":   true,
@@ -555,6 +576,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
 
 	// Gcc wrapper unpacks the C argument struct
 	// and calls the actual C function.
+	fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
 	if n.AddError {
 		fmt.Fprintf(fgcc, "int\n")
 	} else {
@@ -563,7 +585,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
 	fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
 	fmt.Fprintf(fgcc, "{\n")
 	if n.AddError {
-		fmt.Fprintf(fgcc, "\terrno = 0;\n")
+		fmt.Fprintf(fgcc, "\tint _cgo_errno;\n")
 	}
 	// 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
@@ -573,10 +595,18 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
 		// Save the stack top for use below.
 		fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
 	}
+	tr := n.FuncType.Result
+	if tr != nil {
+		fmt.Fprintf(fgcc, "\t__typeof__(a->r) r;\n")
+	}
+	fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+	if n.AddError {
+		fmt.Fprintf(fgcc, "\terrno = 0;\n")
+	}
 	fmt.Fprintf(fgcc, "\t")
-	if t := n.FuncType.Result; t != nil {
-		fmt.Fprintf(fgcc, "__typeof__(a->r) r = ")
-		if c := t.C.String(); c[len(c)-1] == '*' {
+	if tr != nil {
+		fmt.Fprintf(fgcc, "r = ")
+		if c := tr.C.String(); c[len(c)-1] == '*' {
 			fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
 		}
 	}
@@ -589,7 +619,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
 		// the Go equivalents had good type params.
 		// However, our version of the type omits the magic
 		// words const and volatile, which can provoke
-		// C compiler warnings.  Silence them by casting
+		// C compiler warnings. Silence them by casting
 		// all pointers to void*.  (Eventually that will produce
 		// other warnings.)
 		if c := t.C.String(); c[len(c)-1] == '*' {
@@ -598,6 +628,10 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
 		fmt.Fprintf(fgcc, "a->p%d", i)
 	}
 	fmt.Fprintf(fgcc, ");\n")
+	if n.AddError {
+		fmt.Fprintf(fgcc, "\t_cgo_errno = errno;\n")
+	}
+	fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
 	if n.FuncType.Result != nil {
 		// The cgo call may have caused a stack copy (via a callback).
 		// Adjust the return value pointer appropriately.
@@ -606,18 +640,19 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
 		fmt.Fprintf(fgcc, "\ta->r = r;\n")
 	}
 	if n.AddError {
-		fmt.Fprintf(fgcc, "\treturn errno;\n")
+		fmt.Fprintf(fgcc, "\treturn _cgo_errno;\n")
 	}
 	fmt.Fprintf(fgcc, "}\n")
 	fmt.Fprintf(fgcc, "\n")
 }
 
-// Write out a wrapper for a function when using gccgo.  This is a
-// simple wrapper that just calls the real function.  We only need a
+// Write out a wrapper for a function when using gccgo. This is a
+// simple wrapper that just calls the real function. We only need a
 // wrapper to support static functions in the prologue--without a
 // wrapper, we can't refer to the function, since the reference is in
 // a different file.
 func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
+	fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
 	if t := n.FuncType.Result; t != nil {
 		fmt.Fprintf(fgcc, "%s\n", t.C.String())
 	} else {
@@ -636,9 +671,13 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
 	}
 	fmt.Fprintf(fgcc, ")\n")
 	fmt.Fprintf(fgcc, "{\n")
+	if t := n.FuncType.Result; t != nil {
+		fmt.Fprintf(fgcc, "\t%s r;\n", t.C.String())
+	}
+	fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
 	fmt.Fprintf(fgcc, "\t")
 	if t := n.FuncType.Result; t != nil {
-		fmt.Fprintf(fgcc, "return ")
+		fmt.Fprintf(fgcc, "r = ")
 		// Cast to void* to avoid warnings due to omitted qualifiers.
 		if c := t.C.String(); c[len(c)-1] == '*' {
 			fmt.Fprintf(fgcc, "(void*)")
@@ -656,6 +695,16 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
 		fmt.Fprintf(fgcc, "p%d", i)
 	}
 	fmt.Fprintf(fgcc, ");\n")
+	fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
+	if t := n.FuncType.Result; t != nil {
+		fmt.Fprintf(fgcc, "\treturn ")
+		// Cast to void* to avoid warnings due to omitted qualifiers
+		// and explicit incompatible struct types.
+		if c := t.C.String(); c[len(c)-1] == '*' {
+			fmt.Fprintf(fgcc, "(void*)")
+		}
+		fmt.Fprintf(fgcc, "r;\n")
+	}
 	fmt.Fprintf(fgcc, "}\n")
 	fmt.Fprintf(fgcc, "\n")
 }
@@ -679,16 +728,20 @@ 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 <stdlib.h>\n")
 	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\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")
+	fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
+	fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done();\n")
+	fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
+	fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
+	fmt.Fprintf(fgcc, "%s\n", tsanProlog)
 
 	for _, exp := range p.ExpFunc {
 		fn := exp.Func
 
 		// Construct a gcc struct matching the gc argument and
-		// result frame.  The gcc struct will be compiled with
+		// result frame. The gcc struct will be compiled with
 		// __attribute__((packed)) so all padding must be accounted
 		// for explicitly.
 		ctype := "struct {\n"
@@ -783,10 +836,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
 		}
 		fmt.Fprintf(fgcch, "\nextern %s;\n", s)
 
-		fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
+		fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
+		fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
 		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__SIZE_TYPE__ _cgo_ctxt = _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)
@@ -798,7 +852,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
 			func(i int, aname string, atype ast.Expr) {
 				fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
 			})
-		fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off)
+		fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
+		fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
+		fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+		fmt.Fprintf(fgcc, "\t_cgo_release_context(_cgo_ctxt);\n")
 		if gccResult != "void" {
 			if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
 				fmt.Fprintf(fgcc, "\treturn a.r0;\n")
@@ -823,10 +880,10 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
 		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) {\n", cPrefix, exp.ExpName)
+		fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", 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, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n")
 		fmt.Fprintf(fgo2, "}\n")
 
 		fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
@@ -915,6 +972,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
 
 	fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
+	fmt.Fprintf(fgcc, "%s\n", tsanProlog)
 
 	for _, exp := range p.ExpFunc {
 		fn := exp.Func
@@ -983,13 +1041,17 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 		fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
 		fmt.Fprint(fgcc, "\n")
 
-		fmt.Fprint(fgcc, "\n")
+		fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n")
 		fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
+		if resultCount > 0 {
+			fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
+		}
 		fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n")
 		fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n")
+		fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
 		fmt.Fprint(fgcc, "\t")
 		if resultCount > 0 {
-			fmt.Fprint(fgcc, "return ")
+			fmt.Fprint(fgcc, "r = ")
 		}
 		fmt.Fprintf(fgcc, "%s(", goName)
 		if fn.Recv != nil {
@@ -1003,6 +1065,10 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 				fmt.Fprintf(fgcc, "p%d", i)
 			})
 		fmt.Fprint(fgcc, ");\n")
+		fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+		if resultCount > 0 {
+			fmt.Fprint(fgcc, "\treturn r;\n")
+		}
 		fmt.Fprint(fgcc, "}\n")
 
 		// Dummy declaration for _cgo_main.c
@@ -1257,6 +1323,36 @@ extern char* _cgo_topofstack(void);
 #include <string.h>
 `
 
+// Prologue defining TSAN functions in C.
+const noTsanProlog = `
+#define CGO_NO_SANITIZE_THREAD
+#define _cgo_tsan_acquire()
+#define _cgo_tsan_release()
+`
+
+// This must match the TSAN code in runtime/cgo/libcgo.h.
+const yesTsanProlog = `
+#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
+
+long long _cgo_sync __attribute__ ((common));
+
+extern void __tsan_acquire(void*);
+extern void __tsan_release(void*);
+
+__attribute__ ((unused))
+static void _cgo_tsan_acquire() {
+	__tsan_acquire(&_cgo_sync);
+}
+
+__attribute__ ((unused))
+static void _cgo_tsan_release() {
+	__tsan_release(&_cgo_sync);
+}
+`
+
+// Set to yesTsanProlog if we see -fsanitize=thread in the flags for gcc.
+var tsanProlog = noTsanProlog
+
 const builtinProlog = `
 #include <stddef.h> /* for ptrdiff_t and size_t below */
 
@@ -1269,6 +1365,7 @@ _GoString_ GoString(char *p);
 _GoString_ GoStringN(char *p, int l);
 _GoBytes_ GoBytes(void *p, int n);
 char *CString(_GoString_);
+void *CBytes(_GoBytes_);
 void *_CMalloc(size_t);
 `
 
@@ -1276,11 +1373,8 @@ const goProlog = `
 //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)
+func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
 
 //go:linkname _cgoCheckPointer runtime.cgoCheckPointer
 func _cgoCheckPointer(interface{}, ...interface{}) interface{}
@@ -1324,7 +1418,7 @@ func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
 
 const cStringDef = `
 func _Cfunc_CString(s string) *_Ctype_char {
-	p := _cgo_runtime_cmalloc(uintptr(len(s)+1))
+	p := _cgo_cmalloc(uint64(len(s)+1))
 	pp := (*[1<<30]byte)(p)
 	copy(pp[:], s)
 	pp[len(s)] = 0
@@ -1332,9 +1426,18 @@ func _Cfunc_CString(s string) *_Ctype_char {
 }
 `
 
+const cBytesDef = `
+func _Cfunc_CBytes(b []byte) unsafe.Pointer {
+	p := _cgo_cmalloc(uint64(len(b)))
+	pp := (*[1<<30]byte)(p)
+	copy(pp[:], b)
+	return p
+}
+`
+
 const cMallocDef = `
 func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
-	return _cgo_runtime_cmalloc(uintptr(n))
+	return _cgo_cmalloc(uint64(n))
 }
 `
 
@@ -1343,9 +1446,54 @@ var builtinDefs = map[string]string{
 	"GoStringN": goStringNDef,
 	"GoBytes":   goBytesDef,
 	"CString":   cStringDef,
+	"CBytes":    cBytesDef,
 	"_CMalloc":  cMallocDef,
 }
 
+// Definitions for C.malloc in Go and in C. We define it ourselves
+// since we call it from functions we define, such as C.CString.
+// Also, we have historically ensured that C.malloc does not return
+// nil even for an allocation of 0.
+
+const cMallocDefGo = `
+//go:cgo_import_static _cgoPREFIX_Cfunc__Cmalloc
+//go:linkname __cgofn__cgoPREFIX_Cfunc__Cmalloc _cgoPREFIX_Cfunc__Cmalloc
+var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte
+var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc)
+
+//go:cgo_unsafe_args
+func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) {
+	_cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0)))
+	return
+}
+`
+
+// cMallocDefC defines the C version of C.malloc for the gc compiler.
+// It is defined here because C.CString and friends need a definition.
+// We define it by hand, rather than simply inventing a reference to
+// C.malloc, because <stdlib.h> may not have been included.
+// This is approximately what writeOutputFunc would generate, but
+// skips the cgo_topofstack code (which is only needed if the C code
+// calls back into Go). This also avoids returning nil for an
+// allocation of 0 bytes.
+const cMallocDefC = `
+CGO_NO_SANITIZE_THREAD
+void _cgoPREFIX_Cfunc__Cmalloc(void *v) {
+	struct {
+		unsigned long long p0;
+		void *r1;
+	} PACKED *a = v;
+	void *ret;
+	_cgo_tsan_acquire();
+	ret = malloc(a->p0);
+	if (ret == 0 && a->p0 == 0) {
+		ret = malloc(1);
+	}
+	a->r1 = ret;
+	_cgo_tsan_release();
+}
+`
+
 func (p *Package) cPrologGccgo() string {
 	return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
 		"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
@@ -1380,6 +1528,12 @@ const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
 	return p;
 }
 
+void *_cgoPREFIX_Cfunc_CBytes(struct __go_open_array b) {
+	char *p = malloc(b.__count);
+	memmove(p, b.__values, b.__count);
+	return p;
+}
+
 struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) {
 	intgo len = (p != NULL) ? strlen(p) : 0;
 	return __go_byte_array_to_string(p, len);
@@ -1505,5 +1659,5 @@ static void GoInit(void) {
 		runtime_iscgo = 1;
 }
 
-extern void _cgo_wait_runtime_init_done() __attribute__ ((weak));
+extern __SIZE_TYPE__ _cgo_wait_runtime_init_done() __attribute__ ((weak));
 `
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index 3adb8e8..4f5c488 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"fmt"
 	"go/token"
+	"io/ioutil"
 	"os"
 	"os/exec"
 )
@@ -16,6 +17,43 @@ import (
 // It returns the output to standard output and standard error.
 // ok indicates whether the command exited successfully.
 func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
+	if i := find(argv, "-xc"); i >= 0 && argv[len(argv)-1] == "-" {
+		// Some compilers have trouble with standard input.
+		// Others have trouble with -xc.
+		// Avoid both problems by writing a file with a .c extension.
+		f, err := ioutil.TempFile("", "cgo-gcc-input-")
+		if err != nil {
+			fatalf("%s", err)
+		}
+		name := f.Name()
+		f.Close()
+		if err := ioutil.WriteFile(name+".c", stdin, 0666); err != nil {
+			os.Remove(name)
+			fatalf("%s", err)
+		}
+		defer os.Remove(name)
+		defer os.Remove(name + ".c")
+
+		// Build new argument list without -xc and trailing -.
+		new := append(argv[:i:i], argv[i+1:len(argv)-1]...)
+
+		// Since we are going to write the file to a temporary directory,
+		// we will need to add -I . explicitly to the command line:
+		// any #include "foo" before would have looked in the current
+		// directory as the directory "holding" standard input, but now
+		// the temporary directory holds the input.
+		// We've also run into compilers that reject "-I." but allow "-I", ".",
+		// so be sure to use two arguments.
+		// This matters mainly for people invoking cgo -godefs by hand.
+		new = append(new, "-I", ".")
+
+		// Finish argument list with path to C file.
+		new = append(new, name+".c")
+
+		argv = new
+		stdin = nil
+	}
+
 	p := exec.Command(argv[0], argv[1:]...)
 	p.Stdin = bytes.NewReader(stdin)
 	var bout, berr bytes.Buffer
@@ -30,6 +68,15 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
 	return
 }
 
+func find(argv []string, target string) int {
+	for i, arg := range argv {
+		if arg == target {
+			return i
+		}
+	}
+	return -1
+}
+
 func lineno(pos token.Pos) string {
 	return fset.Position(pos).String()
 }
@@ -37,7 +84,7 @@ func lineno(pos token.Pos) string {
 // Die with an error message.
 func fatalf(msg string, args ...interface{}) {
 	// If we've already printed other errors, they might have
-	// caused the fatal condition.  Assume they're enough.
+	// caused the fatal condition. Assume they're enough.
 	if nerrors == 0 {
 		fmt.Fprintf(os.Stderr, msg+"\n", args...)
 	}
diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go
index 2b45e5b..2e77f70 100644
--- a/src/cmd/compile/doc.go
+++ b/src/cmd/compile/doc.go
@@ -60,8 +60,15 @@ Flags:
 	-installsuffix suffix
 		Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix
 		instead of $GOROOT/pkg/$GOOS_$GOARCH.
+	-l
+		Disable inlining.
 	-largemodel
-		Generated code that assumes a large memory model.
+		Generate code that assumes a large memory model.
+	-linkobj file
+		Write linker-specific object to file and compiler-specific
+		object to usual output file (as specified by -o).
+		Without this flag, the -o output is a combination of both
+		linker and compiler input.
 	-memprofile file
 		Write memory profile for the compilation to file.
 	-memprofilerate rate
diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go
index 9837ea6..4291534 100644
--- a/src/cmd/compile/internal/amd64/galign.go
+++ b/src/cmd/compile/internal/amd64/galign.go
@@ -11,71 +11,34 @@ import (
 )
 
 var (
-	thechar     int           = '6'
-	thestring   string        = "amd64"
-	thelinkarch *obj.LinkArch = &x86.Linkamd64
+	addptr = x86.AADDQ
+	movptr = x86.AMOVQ
+	leaptr = x86.ALEAQ
+	cmpptr = x86.ACMPQ
 )
 
-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{
-	{"int", gc.TINT, gc.TINT64},
-	{"uint", gc.TUINT, gc.TUINT64},
-	{"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)
+	if gc.Ctxt.Flag_dynlink || obj.Getgoos() == "nacl" {
+		resvd = append(resvd, x86.REG_R15)
+	}
+	if gc.Ctxt.Framepointer_enabled || obj.Getgoos() == "nacl" {
+		resvd = append(resvd, x86.REG_BP)
 	}
+	gc.Thearch.ReservedRegs = resvd
 }
 
 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.LinkArch = &x86.Linkamd64
+	if obj.Getgoarch() == "amd64p32" {
+		gc.Thearch.LinkArch = &x86.Linkamd64p32
 	}
-
-	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
@@ -85,8 +48,7 @@ func Main() {
 	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.MAXWIDTH = 1 << 50
 
 	gc.Thearch.AddIndex = addindex
 	gc.Thearch.Betypeinit = betypeinit
@@ -105,7 +67,6 @@ func Main() {
 	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
@@ -124,6 +85,11 @@ func Main() {
 	gc.Thearch.Doregbits = doregbits
 	gc.Thearch.Regnames = regnames
 
+	gc.Thearch.SSARegToReg = ssaRegToReg
+	gc.Thearch.SSAMarkMoves = ssaMarkMoves
+	gc.Thearch.SSAGenValue = ssaGenValue
+	gc.Thearch.SSAGenBlock = ssaGenBlock
+
 	gc.Main()
 	gc.Exit(0)
 }
diff --git a/src/cmd/compile/internal/amd64/ggen.go b/src/cmd/compile/internal/amd64/ggen.go
index 84c3d5d..909f7b0 100644
--- a/src/cmd/compile/internal/amd64/ggen.go
+++ b/src/cmd/compile/internal/amd64/ggen.go
@@ -10,13 +10,14 @@ import (
 	"cmd/internal/obj/x86"
 )
 
-func defframe(ptxt *obj.Prog) {
-	var n *gc.Node
+// no floating point in note handlers on Plan 9
+var isPlan9 = obj.Getgoos() == "plan9"
 
+func defframe(ptxt *obj.Prog) {
 	// 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)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 	ptxt.To.Offset = int64(frame)
 
@@ -31,8 +32,7 @@ func defframe(ptxt *obj.Prog) {
 	x0 := 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
+	for _, n := range gc.Curfn.Func.Dcl {
 		if !n.Name.Needzero {
 			continue
 		}
@@ -40,7 +40,7 @@ func defframe(ptxt *obj.Prog) {
 			gc.Fatalf("needzero class %d", n.Class)
 		}
 		if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
-			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
+			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
 		}
 
 		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
@@ -126,7 +126,7 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uin
 			*ax = 1
 		}
 		p = appendpp(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo)
-	} else if cnt <= int64(8*gc.Widthreg) {
+	} else if !isPlan9 && cnt <= int64(8*gc.Widthreg) {
 		if *x0 == 0 {
 			p = appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
 			*x0 = 1
@@ -139,12 +139,11 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uin
 		if cnt%16 != 0 {
 			p = appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+cnt-int64(16))
 		}
-	} else if !gc.Nacl && (cnt <= int64(128*gc.Widthreg)) {
+	} else if !gc.Nacl && !isPlan9 && (cnt <= int64(128*gc.Widthreg)) {
 		if *x0 == 0 {
 			p = appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
 			*x0 = 1
 		}
-
 		p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo+dzDI(cnt), obj.TYPE_REG, x86.REG_DI, 0)
 		p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, dzOff(cnt))
 		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
@@ -167,15 +166,15 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uin
 	return p
 }
 
-func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
+func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
 	q := gc.Ctxt.NewProg()
 	gc.Clearp(q)
-	q.As = int16(as)
+	q.As = as
 	q.Lineno = p.Lineno
-	q.From.Type = int16(ftype)
+	q.From.Type = ftype
 	q.From.Reg = int16(freg)
 	q.From.Offset = foffset
-	q.To.Type = int16(ttype)
+	q.To.Type = ttype
 	q.To.Reg = int16(treg)
 	q.To.Offset = toffset
 	q.Link = p.Link
@@ -205,17 +204,17 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 
 	t0 := t
 	check := false
-	if gc.Issigned[t.Etype] {
+	if t.IsSigned() {
 		check = true
-		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
+		if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -(1<<uint64(t.Width*8-1)) {
 			check = false
-		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
 			check = false
 		}
 	}
 
 	if t.Width < 4 {
-		if gc.Issigned[t.Etype] {
+		if t.IsSigned() {
 			t = gc.Types[gc.TINT32]
 		} else {
 			t = gc.Types[gc.TUINT32]
@@ -292,7 +291,7 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	var olddx gc.Node
 	var dx gc.Node
 	savex(x86.REG_DX, &dx, &olddx, res, t)
-	if !gc.Issigned[t.Etype] {
+	if !t.IsSigned() {
 		gc.Nodconst(&n4, t, 0)
 		gmove(&n4, &dx)
 	} else {
@@ -398,7 +397,7 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 		var n1 gc.Node
 		gc.Regalloc(&n1, nl.Type, res)
 		gc.Cgen(nl, &n1)
-		sc := uint64(nr.Int())
+		sc := uint64(nr.Int64())
 		if sc >= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
 			var n3 gc.Node
@@ -479,7 +478,7 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 		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] {
+		if op == gc.ORSH && nl.Type.IsSigned() {
 			gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
 			gins(a, &n3, &n2)
 		} else {
@@ -532,7 +531,7 @@ func cgen_bmul(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) bool {
 	// perform full-width multiplication.
 	t := gc.Types[gc.TUINT64]
 
-	if gc.Issigned[nl.Type.Etype] {
+	if nl.Type.IsSigned() {
 		t = gc.Types[gc.TINT64]
 	}
 	var n1 gc.Node
@@ -563,7 +562,7 @@ func clearfat(nl *gc.Node) {
 
 	w := nl.Type.Width
 
-	if w > 1024 || (gc.Nacl && w >= 64) {
+	if w > 1024 || (w >= 64 && (gc.Nacl || isPlan9)) {
 		var oldn1 gc.Node
 		var n1 gc.Node
 		savex(x86.REG_DI, &n1, &oldn1, nil, gc.Types[gc.Tptr])
@@ -630,6 +629,22 @@ func clearfat(nl *gc.Node) {
 }
 
 func clearfat_tail(n1 *gc.Node, b int64) {
+	if b >= 16 && isPlan9 {
+		var z gc.Node
+		gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
+		q := b / 8
+		for ; q > 0; q-- {
+			n1.Type = z.Type
+			gins(x86.AMOVQ, &z, n1)
+			n1.Xoffset += 8
+			b -= 8
+		}
+		if b != 0 {
+			n1.Xoffset -= 8 - b
+			gins(x86.AMOVQ, &z, n1)
+		}
+		return
+	}
 	if b >= 16 {
 		var vec_zero gc.Node
 		gc.Regalloc(&vec_zero, gc.Types[gc.TFLOAT64], nil)
@@ -713,7 +728,7 @@ func expandchecks(firstp *obj.Prog) {
 			continue
 		}
 		if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
-			gc.Warnl(int(p.Lineno), "generated nil check")
+			gc.Warnl(p.Lineno, "generated nil check")
 		}
 
 		// check is
@@ -732,7 +747,7 @@ func expandchecks(firstp *obj.Prog) {
 		p2.Lineno = p.Lineno
 		p1.Pc = 9999
 		p2.Pc = 9999
-		p.As = int16(cmpptr)
+		p.As = cmpptr
 		p.To.Type = obj.TYPE_CONST
 		p.To.Offset = 0
 		p1.As = x86.AJNE
diff --git a/src/cmd/compile/internal/amd64/gsubr.go b/src/cmd/compile/internal/amd64/gsubr.go
index 003b0ad..5d9070c 100644
--- a/src/cmd/compile/internal/amd64/gsubr.go
+++ b/src/cmd/compile/internal/amd64/gsubr.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -52,7 +52,7 @@ var resvd = []int{
  * generate
  *	as $c, reg
  */
-func gconreg(as int, c int64, reg int) {
+func gconreg(as obj.As, c int64, reg int) {
 	var nr gc.Node
 
 	switch as {
@@ -72,7 +72,7 @@ func gconreg(as int, c int64, reg int) {
  * generate
  *	as $c, n
  */
-func ginscon(as int, c int64, n2 *gc.Node) {
+func ginscon(as obj.As, c int64, n2 *gc.Node) {
 	var n1 gc.Node
 
 	switch as {
@@ -101,7 +101,7 @@ func ginscon(as int, c int64, n2 *gc.Node) {
 }
 
 func ginscmp(op gc.Op, 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 {
+	if t.IsInteger() && 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
@@ -112,11 +112,11 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 	// A special case to make write barriers more efficient.
 	// Comparing the first field of a named struct can be done directly.
 	base := n1
-	if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Type.Sym == n1.Right.Sym {
+	if n1.Op == gc.ODOT && n1.Left.Type.IsStruct() && n1.Left.Type.Field(0).Sym == n1.Sym {
 		base = n1.Left
 	}
 
-	if base.Op == gc.ONAME && base.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
+	if base.Op == gc.ONAME && base.Class != gc.PAUTOHEAP || n1.Op == gc.OINDREG {
 		r1 = *n1
 	} else {
 		gc.Regalloc(&r1, t, n1)
@@ -124,7 +124,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 		gc.Cgen(n1, &g1)
 		gmove(&g1, &r1)
 	}
-	if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] && gc.Smallintconst(n2) {
+	if n2.Op == gc.OLITERAL && t.IsInteger() && gc.Smallintconst(n2) {
 		r2 = *n2
 	} else {
 		gc.Regalloc(&r2, t, n2)
@@ -144,7 +144,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 	return gc.Gbranch(optoas(op, t), nil, likely)
 }
 
-func ginsboolval(a int, n *gc.Node) {
+func ginsboolval(a obj.As, n *gc.Node) {
 	gins(jmptoset(a), nil, n)
 }
 
@@ -178,7 +178,7 @@ func bignodes() {
  */
 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))
+		fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
 	}
 
 	ft := gc.Simsimtype(f.Type)
@@ -191,7 +191,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 	}
 
 	// cannot have two memory operands
-	var a int
+	var a obj.As
 	if gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
 	}
@@ -213,7 +213,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 			// 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 {
+				if i := con.Int64(); int64(int32(i)) != i {
 					goto hard
 				}
 			}
@@ -229,7 +229,9 @@ func gmove(f *gc.Node, t *gc.Node) {
 
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
-		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong))
+		gc.Dump("f", f)
+		gc.Dump("t", t)
+		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
 
 		/*
 		 * integer copy and truncate
@@ -583,7 +585,7 @@ func samaddr(f *gc.Node, t *gc.Node) bool {
  * generate one instruction:
  *	as f, t
  */
-func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+func gins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
 	//	Node nod;
 
 	//	if(f != N && f->op == OINDEX) {
@@ -681,7 +683,7 @@ func ginsnop() {
 /*
  * return Axxx for Oxxx on type t.
  */
-func optoas(op gc.Op, t *gc.Type) int {
+func optoas(op gc.Op, t *gc.Type) obj.As {
 	if t == nil {
 		gc.Fatalf("optoas: t is nil")
 	}
@@ -722,7 +724,7 @@ func optoas(op gc.Op, t *gc.Type) int {
 	a := obj.AXXX
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatalf("optoas: no entry %v-%v", gc.Oconv(int(op), 0), t)
+		gc.Fatalf("optoas: no entry %v-%v", op, t)
 
 	case OADDR_ | gc.TPTR32:
 		a = x86.ALEAL
@@ -1229,7 +1231,7 @@ func optoas(op gc.Op, t *gc.Type) int {
 }
 
 // jmptoset returns ASETxx for AJxx.
-func jmptoset(jmp int) int {
+func jmptoset(jmp obj.As) obj.As {
 	switch jmp {
 	case x86.AJEQ:
 		return x86.ASETEQ
@@ -1264,7 +1266,7 @@ func jmptoset(jmp int) int {
 	case x86.AJPS:
 		return x86.ASETPS
 	}
-	gc.Fatalf("jmptoset: no entry for %v", gc.Oconv(jmp, 0))
+	gc.Fatalf("jmptoset: no entry for %v", jmp)
 	panic("unreachable")
 }
 
@@ -1298,7 +1300,7 @@ func sudoclean() {
  * after successful sudoaddable,
  * to release the register used for a.
  */
-func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
+func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
 	if n.Type == nil {
 		return false
 	}
@@ -1310,7 +1312,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
 		if !gc.Isconst(n, gc.CTINT) {
 			break
 		}
-		v := n.Int()
+		v := n.Int64()
 		if v >= 32000 || v <= -32000 {
 			break
 		}
@@ -1408,7 +1410,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
 		}
 
 		a.Type = obj.TYPE_NONE
-		a.Index = obj.TYPE_NONE
+		a.Index = x86.REG_NONE
 		gc.Fixlargeoffset(&n1)
 		gc.Naddr(a, &n1)
 		return true
diff --git a/src/cmd/compile/internal/amd64/peep.go b/src/cmd/compile/internal/amd64/peep.go
index 452f954..4ae5fce 100644
--- a/src/cmd/compile/internal/amd64/peep.go
+++ b/src/cmd/compile/internal/amd64/peep.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -80,7 +80,7 @@ func rnops(r *gc.Flow) *gc.Flow {
 }
 
 func peep(firstp *obj.Prog) {
-	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	g := gc.Flowstart(firstp, nil)
 	if g == nil {
 		return
 	}
@@ -94,7 +94,7 @@ func peep(firstp *obj.Prog) {
 	// 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 {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
 		case x86.ALEAL,
@@ -252,21 +252,21 @@ 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
+	// 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
+	// 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 {
+	for r := 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)) {
+					if prevl(r, p.From.Reg) {
 						excise(r)
 					}
 				}
@@ -285,7 +285,7 @@ loop1:
 	// 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 {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
 		case x86.AMOVB,
@@ -307,7 +307,7 @@ func pushback(r0 *gc.Flow) {
 	var p *obj.Prog
 
 	var b *gc.Flow
-	p0 := (*obj.Prog)(r0.Prog)
+	p0 := 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 {
@@ -338,7 +338,7 @@ func pushback(r0 *gc.Flow) {
 
 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("pushback\n")
-		for r := (*gc.Flow)(b); ; r = r.Link {
+		for r := b; ; r = r.Link {
 			fmt.Printf("\t%v\n", r.Prog)
 			if r == r0 {
 				break
@@ -346,7 +346,7 @@ func pushback(r0 *gc.Flow) {
 		}
 	}
 
-	t := obj.Prog(*r0.Prog)
+	t := *r0.Prog
 	for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) {
 		p0 = r.Link.Prog
 		p = r.Prog
@@ -368,7 +368,7 @@ func pushback(r0 *gc.Flow) {
 
 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("\tafter\n")
-		for r := (*gc.Flow)(b); ; r = r.Link {
+		for r := b; ; r = r.Link {
 			fmt.Printf("\t%v\n", r.Prog)
 			if r == r0 {
 				break
@@ -378,7 +378,7 @@ func pushback(r0 *gc.Flow) {
 }
 
 func excise(r *gc.Flow) {
-	p := (*obj.Prog)(r.Prog)
+	p := r.Prog
 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("%v ===delete===\n", p)
 	}
@@ -405,7 +405,7 @@ func regtyp(a *obj.Addr) bool {
 func elimshortmov(g *gc.Graph) {
 	var p *obj.Prog
 
-	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		if regtyp(&p.To) {
 			switch p.As {
@@ -427,7 +427,7 @@ func elimshortmov(g *gc.Graph) {
 			}
 
 			if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
-				// move or artihmetic into partial register.
+				// move or arithmetic 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).
@@ -505,10 +505,10 @@ func regconsttyp(a *obj.Addr) bool {
 }
 
 // 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) {
+func prevl(r0 *gc.Flow, reg int16) bool {
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
 		p := r.Prog
-		if p.To.Type == obj.TYPE_REG && int(p.To.Reg) == reg {
+		if p.To.Type == obj.TYPE_REG && p.To.Reg == reg {
 			flags := progflags(p)
 			if flags&gc.RightWrite != 0 {
 				if flags&gc.SizeL != 0 {
@@ -518,7 +518,6 @@ func prevl(r0 *gc.Flow, reg int) bool {
 			}
 		}
 	}
-
 	return false
 }
 
@@ -540,8 +539,8 @@ 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)
+	p := r0.Prog
+	v1 := &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))
@@ -549,7 +548,7 @@ func subprop(r0 *gc.Flow) bool {
 		return false
 	}
 
-	v2 := (*obj.Addr)(&p.To)
+	v2 := &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))
@@ -587,7 +586,7 @@ func subprop(r0 *gc.Flow) bool {
 		}
 
 		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)
+			copysub(&p.To, v1, v2, true)
 			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 {
@@ -598,16 +597,14 @@ func subprop(r0 *gc.Flow) bool {
 
 			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)
+				copysub(&p.From, v1, v2, true)
+				copysub(&p.To, v1, v2, true)
 				if gc.Debug['P'] != 0 {
 					fmt.Printf("%v\n", r.Prog)
 				}
 			}
 
-			t := int(int(v1.Reg))
-			v1.Reg = v2.Reg
-			v2.Reg = int16(t)
+			v1.Reg, v2.Reg = v2.Reg, v1.Reg
 			if gc.Debug['P'] != 0 {
 				fmt.Printf("%v last\n", r.Prog)
 			}
@@ -621,7 +618,7 @@ func subprop(r0 *gc.Flow) bool {
 			break
 		}
 
-		if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
+		if copysub(&p.From, v1, v2, false) || copysub(&p.To, v1, v2, false) {
 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 				fmt.Printf("\tcopysub failed\n")
 			}
@@ -651,17 +648,17 @@ 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)
+	p := r0.Prog
+	v1 := &p.From
+	v2 := &p.To
 	if copyas(v1, v2) {
 		return true
 	}
 	gactive++
-	return copy1(v1, v2, r0.S1, 0)
+	return copy1(v1, v2, r0.S1, false)
 }
 
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
 	if uint32(r.Active) == gactive {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("act set; return 1\n")
@@ -671,24 +668,21 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 	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)
+		fmt.Printf("copy %v->%v f=%v\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
+		p := r.Prog
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("%v", p)
 		}
-		if f == 0 && gc.Uniqp(r) == nil {
-			f = 1
+		if !f && gc.Uniqp(r) == nil {
+			f = true
 			if gc.Debug['P'] != 0 {
-				fmt.Printf("; merge; f=%d", f)
+				fmt.Printf("; merge; f=%v", f)
 			}
 		}
 
-		t = copyu(p, v2, nil)
-		switch t {
+		switch t := copyu(p, v2, nil); t {
 		case 2: /* rar, can't split */
 			if gc.Debug['P'] != 0 {
 				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
@@ -703,14 +697,14 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 		case 1, /* used, substitute */
 			4: /* use and set */
-			if f != 0 {
+			if f {
 				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)
+					fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				} else {
-					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+					fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				}
 				return false
 			}
@@ -733,12 +727,12 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 
-		if f == 0 {
-			t = copyu(p, v1, nil)
-			if f == 0 && (t == 2 || t == 3 || t == 4) {
-				f = 1
+		if !f {
+			t := copyu(p, v1, nil)
+			if t == 2 || t == 3 || t == 4 {
+				f = true
 				if gc.Debug['P'] != 0 {
-					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+					fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
 				}
 			}
 		}
@@ -752,7 +746,6 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 	}
-
 	return true
 }
 
@@ -768,7 +761,7 @@ 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 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -797,7 +790,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		}
 
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -842,7 +835,10 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 	if p.Info.Flags&gc.RightWrite != 0 {
 		if copyas(&p.To, v) {
 			if s != nil {
-				return copysub(&p.From, v, s, 1)
+				if copysub(&p.From, v, s, true) {
+					return 1
+				}
+				return 0
 			}
 			if copyau(&p.From, v) {
 				return 4
@@ -853,10 +849,13 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 
 	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 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
-			return copysub(&p.To, v, s, 1)
+			if copysub(&p.To, v, s, true) {
+				return 1
+			}
+			return 0
 		}
 
 		if copyau(&p.From, v) {
@@ -866,7 +865,6 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 			return 1
 		}
 	}
-
 	return 0
 }
 
@@ -938,58 +936,43 @@ func copyau(a *obj.Addr, v *obj.Addr) bool {
 			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 {
+// copysub substitute s for v in a.
+// copysub returns true on failure to substitute. TODO(dfc) reverse this logic, copysub should return false on failure
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
 	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)
+		if s.Reg >= x86.REG_AX && s.Reg <= x86.REG_R15 || s.Reg >= x86.REG_X0 && s.Reg <= x86.REG_X0+15 {
+			if f {
+				a.Reg = s.Reg
 			}
 		}
-
-		return 0
+		return false
 	}
 
 	if regtyp(v) {
-		reg := int(int(v.Reg))
-		if a.Type == obj.TYPE_MEM && int(a.Reg) == reg {
+		if a.Type == obj.TYPE_MEM && a.Reg == v.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 */
+				return true /* can't use BP-base with index */
 			}
-			if f != 0 {
+			if f {
 				a.Reg = s.Reg
 			}
 		}
-
-		//			return 0;
-		if int(a.Index) == reg {
-			if f != 0 {
+		if a.Index == v.Reg {
+			if f {
 				a.Index = s.Reg
 			}
-			return 0
 		}
-
-		return 0
 	}
-
-	return 0
+	return false
 }
 
 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)
+	p0 := r0.Prog
+	v0 := &p0.To
+	r := r0
 
 loop:
 	r = gc.Uniqs(r)
@@ -1000,8 +983,8 @@ loop:
 		return
 	}
 
-	p = r.Prog
-	t = copyu(p, v0, nil)
+	p := r.Prog
+	t := copyu(p, v0, nil)
 	switch t {
 	case 0, // miss
 		1: // use
diff --git a/src/cmd/compile/internal/amd64/prog.go b/src/cmd/compile/internal/amd64/prog.go
index b3724b4..91b479b 100644
--- a/src/cmd/compile/internal/amd64/prog.go
+++ b/src/cmd/compile/internal/amd64/prog.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -22,9 +22,7 @@ const (
 // 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{
+var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
 	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
 	obj.ATEXT:     {Flags: gc.Pseudo},
 	obj.AFUNCDATA: {Flags: gc.Pseudo},
@@ -38,221 +36,241 @@ var progtable = [x86.ALAST]obj.ProgInfo{
 
 	// NOP is an internal no-op that also stands
 	// for USED and SET annotations, not the Intel opcode.
-	obj.ANOP:       {Flags: gc.LeftRead | gc.RightWrite},
-	x86.AADCL:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.AADCQ:      {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.AADCW:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.AADDB:      {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AADDL:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AADDW:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AADDQ:      {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AADDSD:     {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	x86.AADDSS:     {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	x86.AANDB:      {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AANDL:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AANDQ:      {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AANDW:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
-	obj.ACALL:      {Flags: gc.RightAddr | gc.Call | gc.KillCarry},
-	x86.ACDQ:       {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
-	x86.ACQO:       {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
-	x86.ACWD:       {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
-	x86.ACLD:       {Flags: gc.OK},
-	x86.ASTD:       {Flags: gc.OK},
-	x86.ACMPB:      {Flags: gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACMPL:      {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACMPQ:      {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACMPW:      {Flags: gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACOMISD:    {Flags: gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACOMISS:    {Flags: gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACVTSD2SL:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSD2SQ:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSD2SS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSL2SD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSL2SS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSQ2SD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSQ2SS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSS2SD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSS2SL:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSS2SQ:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTTSD2SL: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTTSD2SQ: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTTSS2SL: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTTSS2SQ: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ADECB:      {Flags: gc.SizeB | RightRdwr},
-	x86.ADECL:      {Flags: gc.SizeL | RightRdwr},
-	x86.ADECQ:      {Flags: gc.SizeQ | RightRdwr},
-	x86.ADECW:      {Flags: gc.SizeW | RightRdwr},
-	x86.ADIVB:      {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
-	x86.ADIVL:      {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.ADIVQ:      {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.ADIVW:      {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.ADIVSD:     {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	x86.ADIVSS:     {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	x86.AIDIVB:     {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
-	x86.AIDIVL:     {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.AIDIVQ:     {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.AIDIVW:     {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.AIMULB:     {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
-	x86.AIMULL:     {Flags: gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
-	x86.AIMULQ:     {Flags: gc.SizeQ | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
-	x86.AIMULW:     {Flags: gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
-	x86.AINCB:      {Flags: gc.SizeB | RightRdwr},
-	x86.AINCL:      {Flags: gc.SizeL | RightRdwr},
-	x86.AINCQ:      {Flags: gc.SizeQ | RightRdwr},
-	x86.AINCW:      {Flags: gc.SizeW | RightRdwr},
-	x86.AJCC:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJCS:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJEQ:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJGE:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJGT:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJHI:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJLE:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJLS:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJLT:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJMI:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJNE:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJOC:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJOS:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJPC:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJPL:       {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJPS:       {Flags: gc.Cjmp | gc.UseCarry},
-	obj.AJMP:       {Flags: gc.Jump | gc.Break | gc.KillCarry},
-	x86.ALEAL:      {Flags: gc.LeftAddr | gc.RightWrite},
-	x86.ALEAQ:      {Flags: gc.LeftAddr | gc.RightWrite},
-	x86.AMOVBLSX:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVBLZX:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVBQSX:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVBQZX:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVBWSX:   {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVBWZX:   {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVLQSX:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVLQZX:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVWLSX:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVWLZX:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVWQSX:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVWQZX:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVQL:     {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVB:      {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVL:      {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVQ:      {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVW:      {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVUPS:    {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVSB:     {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
-	x86.AMOVSL:     {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
-	x86.AMOVSQ:     {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
-	x86.AMOVSW:     {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
-	obj.ADUFFCOPY:  {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI | X0},
-	x86.AMOVSD:     {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVSS:     {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move},
+	obj.ANOP:               {Flags: gc.LeftRead | gc.RightWrite},
+	x86.AADCL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.AADCQ & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.AADCW & obj.AMask:  {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.AADDB & obj.AMask:  {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AADDL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AADDW & obj.AMask:  {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AADDQ & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AADDSD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.AADDSS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	x86.AANDB & obj.AMask:  {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AANDL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AANDQ & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AANDW & obj.AMask:  {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+
+	x86.ABSFL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.SetCarry},
+	x86.ABSFQ & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.SetCarry},
+	x86.ABSFW & obj.AMask:   {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.SetCarry},
+	x86.ABSRL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.SetCarry},
+	x86.ABSRQ & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.SetCarry},
+	x86.ABSRW & obj.AMask:   {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.SetCarry},
+	x86.ABSWAPL & obj.AMask: {Flags: gc.SizeL | RightRdwr},
+	x86.ABSWAPQ & obj.AMask: {Flags: gc.SizeQ | RightRdwr},
+
+	obj.ACALL & obj.AMask: {Flags: gc.RightAddr | gc.Call | gc.KillCarry},
+	x86.ACDQ & obj.AMask:  {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
+	x86.ACQO & obj.AMask:  {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
+	x86.ACWD & obj.AMask:  {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
+	x86.ACLD & obj.AMask:  {Flags: gc.OK},
+	x86.ASTD & obj.AMask:  {Flags: gc.OK},
+
+	x86.ACMOVLEQ & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.UseCarry},
+	x86.ACMOVLNE & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.UseCarry},
+	x86.ACMOVQEQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.UseCarry},
+	x86.ACMOVQNE & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.UseCarry},
+	x86.ACMOVWEQ & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.UseCarry},
+	x86.ACMOVWNE & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.UseCarry},
+
+	x86.ACMPB & obj.AMask:      {Flags: gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACMPL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACMPQ & obj.AMask:      {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACMPW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACOMISD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACOMISS & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACVTSD2SL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSD2SQ & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSD2SS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSL2SD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSL2SS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSQ2SD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSQ2SS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSS2SD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSS2SL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSS2SQ & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTTSD2SL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTTSD2SQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTTSS2SL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTTSS2SQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ADECB & obj.AMask:      {Flags: gc.SizeB | RightRdwr},
+	x86.ADECL & obj.AMask:      {Flags: gc.SizeL | RightRdwr},
+	x86.ADECQ & obj.AMask:      {Flags: gc.SizeQ | RightRdwr},
+	x86.ADECW & obj.AMask:      {Flags: gc.SizeW | RightRdwr},
+	x86.ADIVB & obj.AMask:      {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+	x86.ADIVL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.ADIVQ & obj.AMask:      {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.ADIVW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.ADIVSD & obj.AMask:     {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.ADIVSS & obj.AMask:     {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	x86.AIDIVB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+	x86.AIDIVL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.AIDIVQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.AIDIVW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.AIMULB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+	x86.AIMULL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
+	x86.AIMULQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
+	x86.AIMULW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
+	x86.AINCB & obj.AMask:      {Flags: gc.SizeB | RightRdwr},
+	x86.AINCL & obj.AMask:      {Flags: gc.SizeL | RightRdwr},
+	x86.AINCQ & obj.AMask:      {Flags: gc.SizeQ | RightRdwr},
+	x86.AINCW & obj.AMask:      {Flags: gc.SizeW | RightRdwr},
+	x86.AJCC & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJCS & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJEQ & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJGE & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJGT & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJHI & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJLE & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJLS & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJLT & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJMI & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJNE & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJOC & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJOS & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJPC & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJPL & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJPS & obj.AMask:       {Flags: gc.Cjmp | gc.UseCarry},
+	obj.AJMP & obj.AMask:       {Flags: gc.Jump | gc.Break | gc.KillCarry},
+	x86.ALEAW & obj.AMask:      {Flags: gc.LeftAddr | gc.RightWrite},
+	x86.ALEAL & obj.AMask:      {Flags: gc.LeftAddr | gc.RightWrite},
+	x86.ALEAQ & obj.AMask:      {Flags: gc.LeftAddr | gc.RightWrite},
+	x86.AMOVBLSX & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVBLZX & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVBQSX & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVBQZX & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVBWSX & obj.AMask:   {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVBWZX & obj.AMask:   {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVLQSX & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVLQZX & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVWLSX & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVWLZX & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVWQSX & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVWQZX & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVQL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVB & obj.AMask:      {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVQ & obj.AMask:      {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVUPS & obj.AMask:    {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVSB & obj.AMask:     {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
+	x86.AMOVSL & obj.AMask:     {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
+	x86.AMOVSQ & obj.AMask:     {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
+	x86.AMOVSW & obj.AMask:     {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
+	obj.ADUFFCOPY & obj.AMask:  {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI | X0},
+	x86.AMOVSD & obj.AMask:     {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVSS & obj.AMask:     {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move},
 
-	// We use MOVAPD as a faster synonym for MOVSD.
-	x86.AMOVAPD:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMULB:     {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
-	x86.AMULL:     {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
-	x86.AMULQ:     {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
-	x86.AMULW:     {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
-	x86.AMULSD:    {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	x86.AMULSS:    {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	x86.ANEGB:     {Flags: gc.SizeB | RightRdwr | gc.SetCarry},
-	x86.ANEGL:     {Flags: gc.SizeL | RightRdwr | gc.SetCarry},
-	x86.ANEGQ:     {Flags: gc.SizeQ | RightRdwr | gc.SetCarry},
-	x86.ANEGW:     {Flags: gc.SizeW | RightRdwr | gc.SetCarry},
-	x86.ANOTB:     {Flags: gc.SizeB | RightRdwr},
-	x86.ANOTL:     {Flags: gc.SizeL | RightRdwr},
-	x86.ANOTQ:     {Flags: gc.SizeQ | RightRdwr},
-	x86.ANOTW:     {Flags: gc.SizeW | RightRdwr},
-	x86.AORB:      {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AORL:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AORQ:      {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AORW:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.APOPQ:     {Flags: gc.SizeQ | gc.RightWrite},
-	x86.APUSHQ:    {Flags: gc.SizeQ | gc.LeftRead},
-	x86.ARCLB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCLL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCLQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCLW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCRB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCRL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCRQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCRW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.AREP:      {Flags: gc.OK, Reguse: CX, Regset: CX},
-	x86.AREPN:     {Flags: gc.OK, Reguse: CX, Regset: CX},
-	obj.ARET:      {Flags: gc.Break | gc.KillCarry},
-	x86.AROLB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.AROLL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.AROLQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.AROLW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ARORB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ARORL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ARORQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ARORW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASALB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASALL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASALQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASALW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASARB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASARL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASARQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASARW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASBBB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.ASBBL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.ASBBQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.ASBBW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.ASETCC:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETCS:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETEQ:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETGE:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETGT:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETHI:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETLE:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETLS:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETLT:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETMI:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETNE:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETOC:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETOS:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETPC:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETPL:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASETPS:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
-	x86.ASHLB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHLL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHLQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHLW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHRB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHRL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHRQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHRW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASQRTSD:   {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	x86.ASTOSB:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
-	x86.ASTOSL:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
-	x86.ASTOSQ:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
-	x86.ASTOSW:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
-	obj.ADUFFZERO: {Flags: gc.OK, Reguse: X0 | DI, Regset: DI},
-	x86.ASUBB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.ASUBL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.ASUBQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.ASUBW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.ASUBSD:    {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	x86.ASUBSS:    {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	x86.ATESTB:    {Flags: gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ATESTL:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ATESTQ:    {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ATESTW:    {Flags: gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.AUCOMISD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
-	x86.AUCOMISS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightRead},
-	x86.AXCHGB:    {Flags: gc.SizeB | LeftRdwr | RightRdwr},
-	x86.AXCHGL:    {Flags: gc.SizeL | LeftRdwr | RightRdwr},
-	x86.AXCHGQ:    {Flags: gc.SizeQ | LeftRdwr | RightRdwr},
-	x86.AXCHGW:    {Flags: gc.SizeW | LeftRdwr | RightRdwr},
-	x86.AXORB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AXORL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AXORQ:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AXORW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AXORPS:    {Flags: gc.LeftRead | RightRdwr},
+	// We use&obj.AMask MOVAPD as a faster synonym for MOVSD.
+	x86.AMOVAPD & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMULB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+	x86.AMULL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
+	x86.AMULQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
+	x86.AMULW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
+	x86.AMULSD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.AMULSS & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	x86.ANEGB & obj.AMask:     {Flags: gc.SizeB | RightRdwr | gc.SetCarry},
+	x86.ANEGL & obj.AMask:     {Flags: gc.SizeL | RightRdwr | gc.SetCarry},
+	x86.ANEGQ & obj.AMask:     {Flags: gc.SizeQ | RightRdwr | gc.SetCarry},
+	x86.ANEGW & obj.AMask:     {Flags: gc.SizeW | RightRdwr | gc.SetCarry},
+	x86.ANOTB & obj.AMask:     {Flags: gc.SizeB | RightRdwr},
+	x86.ANOTL & obj.AMask:     {Flags: gc.SizeL | RightRdwr},
+	x86.ANOTQ & obj.AMask:     {Flags: gc.SizeQ | RightRdwr},
+	x86.ANOTW & obj.AMask:     {Flags: gc.SizeW | RightRdwr},
+	x86.AORB & obj.AMask:      {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AORL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AORQ & obj.AMask:      {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AORW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.APOPQ & obj.AMask:     {Flags: gc.SizeQ | gc.RightWrite},
+	x86.APUSHQ & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead},
+	x86.APXOR & obj.AMask:     {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.ARCLB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCLL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCLQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCLW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCRB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCRL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCRQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCRW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.AREP & obj.AMask:      {Flags: gc.OK, Reguse: CX, Regset: CX},
+	x86.AREPN & obj.AMask:     {Flags: gc.OK, Reguse: CX, Regset: CX},
+	obj.ARET & obj.AMask:      {Flags: gc.Break | gc.KillCarry},
+	x86.AROLB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.AROLL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.AROLQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.AROLW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ARORB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ARORL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ARORQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ARORW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASALB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASALL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASALQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASALW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASARB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASARL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASARQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASARW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASBBB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.ASBBL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.ASBBQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.ASBBW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.ASETCC & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETCS & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETEQ & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETGE & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETGT & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETHI & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETLE & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETLS & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETLT & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETMI & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETNE & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETOC & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETOS & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETPC & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETPL & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASETPS & obj.AMask:    {Flags: gc.SizeB | gc.RightWrite | gc.UseCarry},
+	x86.ASHLB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHLL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHLQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHLW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHRB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHRL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHRQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHRW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASQRTSD & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.ASTOSB & obj.AMask:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
+	x86.ASTOSL & obj.AMask:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
+	x86.ASTOSQ & obj.AMask:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
+	x86.ASTOSW & obj.AMask:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
+	obj.ADUFFZERO & obj.AMask: {Flags: gc.OK, Reguse: X0 | DI, Regset: DI},
+	x86.ASUBB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.ASUBL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.ASUBQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.ASUBW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.ASUBSD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.ASUBSS & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	x86.ATESTB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ATESTL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ATESTQ & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ATESTW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.AUCOMISD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
+	x86.AUCOMISS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightRead},
+	x86.AXCHGB & obj.AMask:    {Flags: gc.SizeB | LeftRdwr | RightRdwr},
+	x86.AXCHGL & obj.AMask:    {Flags: gc.SizeL | LeftRdwr | RightRdwr},
+	x86.AXCHGQ & obj.AMask:    {Flags: gc.SizeQ | LeftRdwr | RightRdwr},
+	x86.AXCHGW & obj.AMask:    {Flags: gc.SizeW | LeftRdwr | RightRdwr},
+	x86.AXORB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AXORL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AXORQ & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AXORW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AXORPS & obj.AMask:    {Flags: gc.LeftRead | RightRdwr},
 }
 
 func progflags(p *obj.Prog) uint32 {
-	flags := progtable[p.As].Flags
+	flags := progtable[p.As&obj.AMask].Flags
 	if flags&gc.ImulAXDX != 0 && p.To.Type != obj.TYPE_NONE {
 		flags |= RightRdwr
 	}
@@ -260,12 +278,12 @@ func progflags(p *obj.Prog) uint32 {
 }
 
 func progcarryflags(p *obj.Prog) uint32 {
-	return progtable[p.As].Flags
+	return progtable[p.As&obj.AMask].Flags
 }
 
 func proginfo(p *obj.Prog) {
 	info := &p.Info
-	*info = progtable[p.As]
+	*info = progtable[p.As&obj.AMask]
 	if info.Flags == 0 {
 		gc.Fatalf("unknown instruction %v", p)
 	}
diff --git a/src/cmd/compile/internal/amd64/reg.go b/src/cmd/compile/internal/amd64/reg.go
index 60822fb..77720c8 100644
--- a/src/cmd/compile/internal/amd64/reg.go
+++ b/src/cmd/compile/internal/amd64/reg.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,7 +32,6 @@ package amd64
 
 import (
 	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
 
@@ -121,7 +120,7 @@ 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 {
+	} else if gc.Ctxt.Framepointer_enabled {
 		// BP is part of the calling convention if framepointer_enabled.
 		b &^= (1 << (x86.REG_BP - x86.REG_AX))
 	}
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
new file mode 100644
index 0000000..756bcec
--- /dev/null
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -0,0 +1,1074 @@
+// Copyright 2016 The Go Authors. 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 (
+	"fmt"
+	"math"
+
+	"cmd/compile/internal/gc"
+	"cmd/compile/internal/ssa"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+// Smallest possible faulting page at address zero.
+const minZeroPage = 4096
+
+// ssaRegToReg maps ssa register numbers to obj register numbers.
+var ssaRegToReg = []int16{
+	x86.REG_AX,
+	x86.REG_CX,
+	x86.REG_DX,
+	x86.REG_BX,
+	x86.REG_SP,
+	x86.REG_BP,
+	x86.REG_SI,
+	x86.REG_DI,
+	x86.REG_R8,
+	x86.REG_R9,
+	x86.REG_R10,
+	x86.REG_R11,
+	x86.REG_R12,
+	x86.REG_R13,
+	x86.REG_R14,
+	x86.REG_R15,
+	x86.REG_X0,
+	x86.REG_X1,
+	x86.REG_X2,
+	x86.REG_X3,
+	x86.REG_X4,
+	x86.REG_X5,
+	x86.REG_X6,
+	x86.REG_X7,
+	x86.REG_X8,
+	x86.REG_X9,
+	x86.REG_X10,
+	x86.REG_X11,
+	x86.REG_X12,
+	x86.REG_X13,
+	x86.REG_X14,
+	x86.REG_X15,
+	0, // SB isn't a real register.  We fill an Addr.Reg field with 0 in this case.
+}
+
+// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
+func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
+	flive := b.FlagsLiveAtEnd
+	if b.Control != nil && b.Control.Type.IsFlags() {
+		flive = true
+	}
+	for i := len(b.Values) - 1; i >= 0; i-- {
+		v := b.Values[i]
+		if flive && (v.Op == ssa.OpAMD64MOVLconst || v.Op == ssa.OpAMD64MOVQconst) {
+			// The "mark" is any non-nil Aux value.
+			v.Aux = v
+		}
+		if v.Type.IsFlags() {
+			flive = false
+		}
+		for _, a := range v.Args {
+			if a.Type.IsFlags() {
+				flive = true
+			}
+		}
+	}
+}
+
+// loadByType returns the load instruction of the given type.
+func loadByType(t ssa.Type) obj.As {
+	// Avoid partial register write
+	if !t.IsFloat() && t.Size() <= 2 {
+		if t.Size() == 1 {
+			return x86.AMOVBLZX
+		} else {
+			return x86.AMOVWLZX
+		}
+	}
+	// Otherwise, there's no difference between load and store opcodes.
+	return storeByType(t)
+}
+
+// storeByType returns the store instruction of the given type.
+func storeByType(t ssa.Type) obj.As {
+	width := t.Size()
+	if t.IsFloat() {
+		switch width {
+		case 4:
+			return x86.AMOVSS
+		case 8:
+			return x86.AMOVSD
+		}
+	} else {
+		switch width {
+		case 1:
+			return x86.AMOVB
+		case 2:
+			return x86.AMOVW
+		case 4:
+			return x86.AMOVL
+		case 8:
+			return x86.AMOVQ
+		}
+	}
+	panic("bad store type")
+}
+
+// moveByType returns the reg->reg move instruction of the given type.
+func moveByType(t ssa.Type) obj.As {
+	if t.IsFloat() {
+		// Moving the whole sse2 register is faster
+		// than moving just the correct low portion of it.
+		// There is no xmm->xmm move with 1 byte opcode,
+		// so use movups, which has 2 byte opcode.
+		return x86.AMOVUPS
+	} else {
+		switch t.Size() {
+		case 1:
+			// Avoids partial register write
+			return x86.AMOVL
+		case 2:
+			return x86.AMOVL
+		case 4:
+			return x86.AMOVL
+		case 8:
+			return x86.AMOVQ
+		case 16:
+			return x86.AMOVUPS // int128s are in SSE registers
+		default:
+			panic(fmt.Sprintf("bad int register width %d:%s", t.Size(), t))
+		}
+	}
+}
+
+// opregreg emits instructions for
+//     dest := dest(To) op src(From)
+// and also returns the created obj.Prog so it
+// may be further adjusted (offset, scale, etc).
+func opregreg(op obj.As, dest, src int16) *obj.Prog {
+	p := gc.Prog(op)
+	p.From.Type = obj.TYPE_REG
+	p.To.Type = obj.TYPE_REG
+	p.To.Reg = dest
+	p.From.Reg = src
+	return p
+}
+
+func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
+	s.SetLineno(v.Line)
+	switch v.Op {
+	case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL:
+		r := gc.SSARegNum(v)
+		r1 := gc.SSARegNum(v.Args[0])
+		r2 := gc.SSARegNum(v.Args[1])
+		switch {
+		case r == r1:
+			p := gc.Prog(v.Op.Asm())
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = r2
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = r
+		case r == r2:
+			p := gc.Prog(v.Op.Asm())
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = r1
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = r
+		default:
+			var asm obj.As
+			if v.Op == ssa.OpAMD64ADDQ {
+				asm = x86.ALEAQ
+			} else {
+				asm = x86.ALEAL
+			}
+			p := gc.Prog(asm)
+			p.From.Type = obj.TYPE_MEM
+			p.From.Reg = r1
+			p.From.Scale = 1
+			p.From.Index = r2
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = r
+		}
+	// 2-address opcode arithmetic
+	case ssa.OpAMD64SUBQ, ssa.OpAMD64SUBL,
+		ssa.OpAMD64MULQ, ssa.OpAMD64MULL,
+		ssa.OpAMD64ANDQ, ssa.OpAMD64ANDL,
+		ssa.OpAMD64ORQ, ssa.OpAMD64ORL,
+		ssa.OpAMD64XORQ, ssa.OpAMD64XORL,
+		ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL,
+		ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
+		ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB,
+		ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD, ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD,
+		ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD,
+		ssa.OpAMD64PXOR:
+		r := gc.SSARegNum(v)
+		if r != gc.SSARegNum(v.Args[0]) {
+			v.Fatalf("input[0] and output not in same register %s", v.LongString())
+		}
+		opregreg(v.Op.Asm(), r, gc.SSARegNum(v.Args[1]))
+
+	case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW,
+		ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU,
+		ssa.OpAMD64MODQ, ssa.OpAMD64MODL, ssa.OpAMD64MODW,
+		ssa.OpAMD64MODQU, ssa.OpAMD64MODLU, ssa.OpAMD64MODWU:
+
+		// Arg[0] is already in AX as it's the only register we allow
+		// and AX is the only output
+		x := gc.SSARegNum(v.Args[1])
+
+		// CPU faults upon signed overflow, which occurs when most
+		// negative int is divided by -1.
+		var j *obj.Prog
+		if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
+			v.Op == ssa.OpAMD64DIVW || v.Op == ssa.OpAMD64MODQ ||
+			v.Op == ssa.OpAMD64MODL || v.Op == ssa.OpAMD64MODW {
+
+			var c *obj.Prog
+			switch v.Op {
+			case ssa.OpAMD64DIVQ, ssa.OpAMD64MODQ:
+				c = gc.Prog(x86.ACMPQ)
+				j = gc.Prog(x86.AJEQ)
+				// go ahead and sign extend to save doing it later
+				gc.Prog(x86.ACQO)
+
+			case ssa.OpAMD64DIVL, ssa.OpAMD64MODL:
+				c = gc.Prog(x86.ACMPL)
+				j = gc.Prog(x86.AJEQ)
+				gc.Prog(x86.ACDQ)
+
+			case ssa.OpAMD64DIVW, ssa.OpAMD64MODW:
+				c = gc.Prog(x86.ACMPW)
+				j = gc.Prog(x86.AJEQ)
+				gc.Prog(x86.ACWD)
+			}
+			c.From.Type = obj.TYPE_REG
+			c.From.Reg = x
+			c.To.Type = obj.TYPE_CONST
+			c.To.Offset = -1
+
+			j.To.Type = obj.TYPE_BRANCH
+
+		}
+
+		// for unsigned ints, we sign extend by setting DX = 0
+		// signed ints were sign extended above
+		if v.Op == ssa.OpAMD64DIVQU || v.Op == ssa.OpAMD64MODQU ||
+			v.Op == ssa.OpAMD64DIVLU || v.Op == ssa.OpAMD64MODLU ||
+			v.Op == ssa.OpAMD64DIVWU || v.Op == ssa.OpAMD64MODWU {
+			c := gc.Prog(x86.AXORQ)
+			c.From.Type = obj.TYPE_REG
+			c.From.Reg = x86.REG_DX
+			c.To.Type = obj.TYPE_REG
+			c.To.Reg = x86.REG_DX
+		}
+
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = x
+
+		// signed division, rest of the check for -1 case
+		if j != nil {
+			j2 := gc.Prog(obj.AJMP)
+			j2.To.Type = obj.TYPE_BRANCH
+
+			var n *obj.Prog
+			if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
+				v.Op == ssa.OpAMD64DIVW {
+				// n * -1 = -n
+				n = gc.Prog(x86.ANEGQ)
+				n.To.Type = obj.TYPE_REG
+				n.To.Reg = x86.REG_AX
+			} else {
+				// n % -1 == 0
+				n = gc.Prog(x86.AXORQ)
+				n.From.Type = obj.TYPE_REG
+				n.From.Reg = x86.REG_DX
+				n.To.Type = obj.TYPE_REG
+				n.To.Reg = x86.REG_DX
+			}
+
+			j.To.Val = n
+			j2.To.Val = s.Pc()
+		}
+
+	case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB,
+		ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU:
+		// the frontend rewrites constant division by 8/16/32 bit integers into
+		// HMUL by a constant
+		// SSA rewrites generate the 64 bit versions
+
+		// Arg[0] is already in AX as it's the only register we allow
+		// and DX is the only output we care about (the high bits)
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[1])
+
+		// IMULB puts the high portion in AH instead of DL,
+		// so move it to DL for consistency
+		if v.Type.Size() == 1 {
+			m := gc.Prog(x86.AMOVB)
+			m.From.Type = obj.TYPE_REG
+			m.From.Reg = x86.REG_AH
+			m.To.Type = obj.TYPE_REG
+			m.To.Reg = x86.REG_DX
+		}
+
+	case ssa.OpAMD64AVGQU:
+		// compute (x+y)/2 unsigned.
+		// Do a 64-bit add, the overflow goes into the carry.
+		// Shift right once and pull the carry back into the 63rd bit.
+		r := gc.SSARegNum(v)
+		if r != gc.SSARegNum(v.Args[0]) {
+			v.Fatalf("input[0] and output not in same register %s", v.LongString())
+		}
+		p := gc.Prog(x86.AADDQ)
+		p.From.Type = obj.TYPE_REG
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+		p.From.Reg = gc.SSARegNum(v.Args[1])
+		p = gc.Prog(x86.ARCRQ)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 1
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+
+	case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst:
+		r := gc.SSARegNum(v)
+		a := gc.SSARegNum(v.Args[0])
+		if r == a {
+			if v.AuxInt == 1 {
+				var asm obj.As
+				// Software optimization manual recommends add $1,reg.
+				// But inc/dec is 1 byte smaller. ICC always uses inc
+				// Clang/GCC choose depending on flags, but prefer add.
+				// Experiments show that inc/dec is both a little faster
+				// and make a binary a little smaller.
+				if v.Op == ssa.OpAMD64ADDQconst {
+					asm = x86.AINCQ
+				} else {
+					asm = x86.AINCL
+				}
+				p := gc.Prog(asm)
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = r
+				return
+			}
+			if v.AuxInt == -1 {
+				var asm obj.As
+				if v.Op == ssa.OpAMD64ADDQconst {
+					asm = x86.ADECQ
+				} else {
+					asm = x86.ADECL
+				}
+				p := gc.Prog(asm)
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = r
+				return
+			}
+			p := gc.Prog(v.Op.Asm())
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = v.AuxInt
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = r
+			return
+		}
+		var asm obj.As
+		if v.Op == ssa.OpAMD64ADDQconst {
+			asm = x86.ALEAQ
+		} else {
+			asm = x86.ALEAL
+		}
+		p := gc.Prog(asm)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = a
+		p.From.Offset = v.AuxInt
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+
+	case ssa.OpAMD64CMOVQEQconst, ssa.OpAMD64CMOVLEQconst, ssa.OpAMD64CMOVWEQconst,
+		ssa.OpAMD64CMOVQNEconst, ssa.OpAMD64CMOVLNEconst, ssa.OpAMD64CMOVWNEconst:
+		r := gc.SSARegNum(v)
+		if r != gc.SSARegNum(v.Args[0]) {
+			v.Fatalf("input[0] and output not in same register %s", v.LongString())
+		}
+
+		// Constant into AX
+		p := gc.Prog(moveByType(v.Type))
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = v.AuxInt
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = x86.REG_AX
+
+		p = gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = x86.REG_AX
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+
+	case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst:
+		r := gc.SSARegNum(v)
+		if r != gc.SSARegNum(v.Args[0]) {
+			v.Fatalf("input[0] and output not in same register %s", v.LongString())
+		}
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = v.AuxInt
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+		// TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
+		// then we don't need to use resultInArg0 for these ops.
+		//p.From3 = new(obj.Addr)
+		//p.From3.Type = obj.TYPE_REG
+		//p.From3.Reg = gc.SSARegNum(v.Args[0])
+
+	case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst,
+		ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst,
+		ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst,
+		ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst,
+		ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst,
+		ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst, ssa.OpAMD64SHRBconst,
+		ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst, ssa.OpAMD64SARBconst,
+		ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst, ssa.OpAMD64ROLBconst:
+		r := gc.SSARegNum(v)
+		if r != gc.SSARegNum(v.Args[0]) {
+			v.Fatalf("input[0] and output not in same register %s", v.LongString())
+		}
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = v.AuxInt
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+	case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask:
+		r := gc.SSARegNum(v)
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = r
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+	case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8:
+		r := gc.SSARegNum(v.Args[0])
+		i := gc.SSARegNum(v.Args[1])
+		p := gc.Prog(x86.ALEAQ)
+		switch v.Op {
+		case ssa.OpAMD64LEAQ1:
+			p.From.Scale = 1
+			if i == x86.REG_SP {
+				r, i = i, r
+			}
+		case ssa.OpAMD64LEAQ2:
+			p.From.Scale = 2
+		case ssa.OpAMD64LEAQ4:
+			p.From.Scale = 4
+		case ssa.OpAMD64LEAQ8:
+			p.From.Scale = 8
+		}
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = r
+		p.From.Index = i
+		gc.AddAux(&p.From, v)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpAMD64LEAQ:
+		p := gc.Prog(x86.ALEAQ)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux(&p.From, v)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpAMD64CMPQ, ssa.OpAMD64CMPL, ssa.OpAMD64CMPW, ssa.OpAMD64CMPB,
+		ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB:
+		opregreg(v.Op.Asm(), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[0]))
+	case ssa.OpAMD64UCOMISS, ssa.OpAMD64UCOMISD:
+		// Go assembler has swapped operands for UCOMISx relative to CMP,
+		// must account for that right here.
+		opregreg(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]))
+	case ssa.OpAMD64CMPQconst, ssa.OpAMD64CMPLconst, ssa.OpAMD64CMPWconst, ssa.OpAMD64CMPBconst:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		p.To.Type = obj.TYPE_CONST
+		p.To.Offset = v.AuxInt
+	case ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = v.AuxInt
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+	case ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
+		x := gc.SSARegNum(v)
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = v.AuxInt
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = x
+		// If flags are live at this instruction, suppress the
+		// MOV $0,AX -> XOR AX,AX optimization.
+		if v.Aux != nil {
+			p.Mark |= x86.PRESERVEFLAGS
+		}
+	case ssa.OpAMD64MOVSSconst, ssa.OpAMD64MOVSDconst:
+		x := gc.SSARegNum(v)
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_FCONST
+		p.From.Val = math.Float64frombits(uint64(v.AuxInt))
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = x
+	case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVWQSXload, ssa.OpAMD64MOVLQSXload, ssa.OpAMD64MOVOload:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux(&p.From, v)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux(&p.From, v)
+		p.From.Scale = 8
+		p.From.Index = gc.SSARegNum(v.Args[1])
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux(&p.From, v)
+		p.From.Scale = 4
+		p.From.Index = gc.SSARegNum(v.Args[1])
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpAMD64MOVWloadidx2:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux(&p.From, v)
+		p.From.Scale = 2
+		p.From.Index = gc.SSARegNum(v.Args[1])
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpAMD64MOVBloadidx1, ssa.OpAMD64MOVWloadidx1, ssa.OpAMD64MOVLloadidx1, ssa.OpAMD64MOVQloadidx1, ssa.OpAMD64MOVSSloadidx1, ssa.OpAMD64MOVSDloadidx1:
+		r := gc.SSARegNum(v.Args[0])
+		i := gc.SSARegNum(v.Args[1])
+		if i == x86.REG_SP {
+			r, i = i, r
+		}
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = r
+		p.From.Scale = 1
+		p.From.Index = i
+		gc.AddAux(&p.From, v)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[1])
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux(&p.To, v)
+	case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[2])
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+		p.To.Scale = 8
+		p.To.Index = gc.SSARegNum(v.Args[1])
+		gc.AddAux(&p.To, v)
+	case ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[2])
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+		p.To.Scale = 4
+		p.To.Index = gc.SSARegNum(v.Args[1])
+		gc.AddAux(&p.To, v)
+	case ssa.OpAMD64MOVWstoreidx2:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[2])
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+		p.To.Scale = 2
+		p.To.Index = gc.SSARegNum(v.Args[1])
+		gc.AddAux(&p.To, v)
+	case ssa.OpAMD64MOVBstoreidx1, ssa.OpAMD64MOVWstoreidx1, ssa.OpAMD64MOVLstoreidx1, ssa.OpAMD64MOVQstoreidx1, ssa.OpAMD64MOVSSstoreidx1, ssa.OpAMD64MOVSDstoreidx1:
+		r := gc.SSARegNum(v.Args[0])
+		i := gc.SSARegNum(v.Args[1])
+		if i == x86.REG_SP {
+			r, i = i, r
+		}
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[2])
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = r
+		p.To.Scale = 1
+		p.To.Index = i
+		gc.AddAux(&p.To, v)
+	case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_CONST
+		sc := v.AuxValAndOff()
+		p.From.Offset = sc.Val()
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux2(&p.To, v, sc.Off())
+	case ssa.OpAMD64MOVQstoreconstidx1, ssa.OpAMD64MOVQstoreconstidx8, ssa.OpAMD64MOVLstoreconstidx1, ssa.OpAMD64MOVLstoreconstidx4, ssa.OpAMD64MOVWstoreconstidx1, ssa.OpAMD64MOVWstoreconstidx2, ssa.OpAMD64MOVBstoreconstidx1:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_CONST
+		sc := v.AuxValAndOff()
+		p.From.Offset = sc.Val()
+		r := gc.SSARegNum(v.Args[0])
+		i := gc.SSARegNum(v.Args[1])
+		switch v.Op {
+		case ssa.OpAMD64MOVBstoreconstidx1, ssa.OpAMD64MOVWstoreconstidx1, ssa.OpAMD64MOVLstoreconstidx1, ssa.OpAMD64MOVQstoreconstidx1:
+			p.To.Scale = 1
+			if i == x86.REG_SP {
+				r, i = i, r
+			}
+		case ssa.OpAMD64MOVWstoreconstidx2:
+			p.To.Scale = 2
+		case ssa.OpAMD64MOVLstoreconstidx4:
+			p.To.Scale = 4
+		case ssa.OpAMD64MOVQstoreconstidx8:
+			p.To.Scale = 8
+		}
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = r
+		p.To.Index = i
+		gc.AddAux2(&p.To, v, sc.Off())
+	case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
+		ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD,
+		ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
+		ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
+		opregreg(v.Op.Asm(), gc.SSARegNum(v), gc.SSARegNum(v.Args[0]))
+	case ssa.OpAMD64DUFFZERO:
+		p := gc.Prog(obj.ADUFFZERO)
+		p.To.Type = obj.TYPE_ADDR
+		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+		p.To.Offset = v.AuxInt
+	case ssa.OpAMD64MOVOconst:
+		if v.AuxInt != 0 {
+			v.Unimplementedf("MOVOconst can only do constant=0")
+		}
+		r := gc.SSARegNum(v)
+		opregreg(x86.AXORPS, r, r)
+	case ssa.OpAMD64DUFFCOPY:
+		p := gc.Prog(obj.ADUFFCOPY)
+		p.To.Type = obj.TYPE_ADDR
+		p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
+		p.To.Offset = v.AuxInt
+
+	case ssa.OpCopy, ssa.OpAMD64MOVQconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?
+		if v.Type.IsMemory() {
+			return
+		}
+		x := gc.SSARegNum(v.Args[0])
+		y := gc.SSARegNum(v)
+		if x != y {
+			opregreg(moveByType(v.Type), y, x)
+		}
+	case ssa.OpLoadReg:
+		if v.Type.IsFlags() {
+			v.Unimplementedf("load flags not implemented: %v", v.LongString())
+			return
+		}
+		p := gc.Prog(loadByType(v.Type))
+		n, off := gc.AutoVar(v.Args[0])
+		p.From.Type = obj.TYPE_MEM
+		p.From.Node = n
+		p.From.Sym = gc.Linksym(n.Sym)
+		p.From.Offset = off
+		if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
+			p.From.Name = obj.NAME_PARAM
+			p.From.Offset += n.Xoffset
+		} else {
+			p.From.Name = obj.NAME_AUTO
+		}
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+
+	case ssa.OpStoreReg:
+		if v.Type.IsFlags() {
+			v.Unimplementedf("store flags not implemented: %v", v.LongString())
+			return
+		}
+		p := gc.Prog(storeByType(v.Type))
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		n, off := gc.AutoVar(v)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Node = n
+		p.To.Sym = gc.Linksym(n.Sym)
+		p.To.Offset = off
+		if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
+			p.To.Name = obj.NAME_PARAM
+			p.To.Offset += n.Xoffset
+		} else {
+			p.To.Name = obj.NAME_AUTO
+		}
+	case ssa.OpPhi:
+		// just check to make sure regalloc and stackalloc did it right
+		if v.Type.IsMemory() {
+			return
+		}
+		f := v.Block.Func
+		loc := f.RegAlloc[v.ID]
+		for _, a := range v.Args {
+			if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
+				v.Fatalf("phi arg at different location than phi: %v @ %v, but arg %v @ %v\n%s\n", v, loc, a, aloc, v.Block.Func)
+			}
+		}
+	case ssa.OpInitMem:
+		// memory arg needs no code
+	case ssa.OpArg:
+		// input args need no code
+	case ssa.OpAMD64LoweredGetClosurePtr:
+		// Output is hardwired to DX only,
+		// and DX contains the closure pointer on
+		// closure entry, and this "instruction"
+		// is scheduled to the very beginning
+		// of the entry block.
+	case ssa.OpAMD64LoweredGetG:
+		r := gc.SSARegNum(v)
+		// See the comments in cmd/internal/obj/x86/obj6.go
+		// near CanUse1InsnTLS for a detailed explanation of these instructions.
+		if x86.CanUse1InsnTLS(gc.Ctxt) {
+			// MOVQ (TLS), r
+			p := gc.Prog(x86.AMOVQ)
+			p.From.Type = obj.TYPE_MEM
+			p.From.Reg = x86.REG_TLS
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = r
+		} else {
+			// MOVQ TLS, r
+			// MOVQ (r)(TLS*1), r
+			p := gc.Prog(x86.AMOVQ)
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = x86.REG_TLS
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = r
+			q := gc.Prog(x86.AMOVQ)
+			q.From.Type = obj.TYPE_MEM
+			q.From.Reg = r
+			q.From.Index = x86.REG_TLS
+			q.From.Scale = 1
+			q.To.Type = obj.TYPE_REG
+			q.To.Reg = r
+		}
+	case ssa.OpAMD64CALLstatic:
+		if v.Aux.(*gc.Sym) == gc.Deferreturn.Sym {
+			// 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.
+			ginsnop()
+		}
+		p := gc.Prog(obj.ACALL)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = gc.Linksym(v.Aux.(*gc.Sym))
+		if gc.Maxarg < v.AuxInt {
+			gc.Maxarg = v.AuxInt
+		}
+	case ssa.OpAMD64CALLclosure:
+		p := gc.Prog(obj.ACALL)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+		if gc.Maxarg < v.AuxInt {
+			gc.Maxarg = v.AuxInt
+		}
+	case ssa.OpAMD64CALLdefer:
+		p := gc.Prog(obj.ACALL)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = gc.Linksym(gc.Deferproc.Sym)
+		if gc.Maxarg < v.AuxInt {
+			gc.Maxarg = v.AuxInt
+		}
+	case ssa.OpAMD64CALLgo:
+		p := gc.Prog(obj.ACALL)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = gc.Linksym(gc.Newproc.Sym)
+		if gc.Maxarg < v.AuxInt {
+			gc.Maxarg = v.AuxInt
+		}
+	case ssa.OpAMD64CALLinter:
+		p := gc.Prog(obj.ACALL)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+		if gc.Maxarg < v.AuxInt {
+			gc.Maxarg = v.AuxInt
+		}
+	case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL,
+		ssa.OpAMD64BSWAPQ, ssa.OpAMD64BSWAPL,
+		ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL:
+		r := gc.SSARegNum(v)
+		if r != gc.SSARegNum(v.Args[0]) {
+			v.Fatalf("input[0] and output not in same register %s", v.LongString())
+		}
+		p := gc.Prog(v.Op.Asm())
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+	case ssa.OpAMD64BSFQ, ssa.OpAMD64BSFL, ssa.OpAMD64BSFW,
+		ssa.OpAMD64BSRQ, ssa.OpAMD64BSRL, ssa.OpAMD64BSRW,
+		ssa.OpAMD64SQRTSD:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpSP, ssa.OpSB:
+		// nothing to do
+	case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE,
+		ssa.OpAMD64SETL, ssa.OpAMD64SETLE,
+		ssa.OpAMD64SETG, ssa.OpAMD64SETGE,
+		ssa.OpAMD64SETGF, ssa.OpAMD64SETGEF,
+		ssa.OpAMD64SETB, ssa.OpAMD64SETBE,
+		ssa.OpAMD64SETORD, ssa.OpAMD64SETNAN,
+		ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
+		p := gc.Prog(v.Op.Asm())
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+
+	case ssa.OpAMD64SETNEF:
+		p := gc.Prog(v.Op.Asm())
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+		q := gc.Prog(x86.ASETPS)
+		q.To.Type = obj.TYPE_REG
+		q.To.Reg = x86.REG_AX
+		// ORL avoids partial register write and is smaller than ORQ, used by old compiler
+		opregreg(x86.AORL, gc.SSARegNum(v), x86.REG_AX)
+
+	case ssa.OpAMD64SETEQF:
+		p := gc.Prog(v.Op.Asm())
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+		q := gc.Prog(x86.ASETPC)
+		q.To.Type = obj.TYPE_REG
+		q.To.Reg = x86.REG_AX
+		// ANDL avoids partial register write and is smaller than ANDQ, used by old compiler
+		opregreg(x86.AANDL, gc.SSARegNum(v), x86.REG_AX)
+
+	case ssa.OpAMD64InvertFlags:
+		v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
+	case ssa.OpAMD64FlagEQ, ssa.OpAMD64FlagLT_ULT, ssa.OpAMD64FlagLT_UGT, ssa.OpAMD64FlagGT_ULT, ssa.OpAMD64FlagGT_UGT:
+		v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
+	case ssa.OpAMD64REPSTOSQ:
+		gc.Prog(x86.AREP)
+		gc.Prog(x86.ASTOSQ)
+	case ssa.OpAMD64REPMOVSQ:
+		gc.Prog(x86.AREP)
+		gc.Prog(x86.AMOVSQ)
+	case ssa.OpVarDef:
+		gc.Gvardef(v.Aux.(*gc.Node))
+	case ssa.OpVarKill:
+		gc.Gvarkill(v.Aux.(*gc.Node))
+	case ssa.OpVarLive:
+		gc.Gvarlive(v.Aux.(*gc.Node))
+	case ssa.OpKeepAlive:
+		if !v.Args[0].Type.IsPtrShaped() {
+			v.Fatalf("keeping non-pointer alive %v", v.Args[0])
+		}
+		n, off := gc.AutoVar(v.Args[0])
+		if n == nil {
+			v.Fatalf("KeepLive with non-spilled value %s %s", v, v.Args[0])
+		}
+		if off != 0 {
+			v.Fatalf("KeepLive with non-zero offset spill location %s:%d", n, off)
+		}
+		gc.Gvarlive(n)
+	case ssa.OpAMD64LoweredNilCheck:
+		// Optimization - if the subsequent block has a load or store
+		// at the same address, we don't need to issue this instruction.
+		mem := v.Args[1]
+		for _, w := range v.Block.Succs[0].Block().Values {
+			if w.Op == ssa.OpPhi {
+				if w.Type.IsMemory() {
+					mem = w
+				}
+				continue
+			}
+			if len(w.Args) == 0 || !w.Args[len(w.Args)-1].Type.IsMemory() {
+				// w doesn't use a store - can't be a memory op.
+				continue
+			}
+			if w.Args[len(w.Args)-1] != mem {
+				v.Fatalf("wrong store after nilcheck v=%s w=%s", v, w)
+			}
+			switch w.Op {
+			case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload,
+				ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore,
+				ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVWQSXload, ssa.OpAMD64MOVLQSXload,
+				ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVOload,
+				ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVOstore:
+				if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
+					if gc.Debug_checknil != 0 && int(v.Line) > 1 {
+						gc.Warnl(v.Line, "removed nil check")
+					}
+					return
+				}
+			case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
+				off := ssa.ValAndOff(v.AuxInt).Off()
+				if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
+					if gc.Debug_checknil != 0 && int(v.Line) > 1 {
+						gc.Warnl(v.Line, "removed nil check")
+					}
+					return
+				}
+			}
+			if w.Type.IsMemory() {
+				if w.Op == ssa.OpVarDef || w.Op == ssa.OpVarKill || w.Op == ssa.OpVarLive {
+					// these ops are OK
+					mem = w
+					continue
+				}
+				// We can't delay the nil check past the next store.
+				break
+			}
+		}
+		// Issue a load which will fault if the input is nil.
+		// TODO: We currently use the 2-byte instruction TESTB AX, (reg).
+		// Should we use the 3-byte TESTB $0, (reg) instead?  It is larger
+		// but it doesn't have false dependency on AX.
+		// Or maybe allocate an output register and use MOVL (reg),reg2 ?
+		// That trades clobbering flags for clobbering a register.
+		p := gc.Prog(x86.ATESTB)
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = x86.REG_AX
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux(&p.To, v)
+		if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
+			gc.Warnl(v.Line, "generated nil check")
+		}
+	default:
+		v.Unimplementedf("genValue not implemented: %s", v.LongString())
+	}
+}
+
+var blockJump = [...]struct {
+	asm, invasm obj.As
+}{
+	ssa.BlockAMD64EQ:  {x86.AJEQ, x86.AJNE},
+	ssa.BlockAMD64NE:  {x86.AJNE, x86.AJEQ},
+	ssa.BlockAMD64LT:  {x86.AJLT, x86.AJGE},
+	ssa.BlockAMD64GE:  {x86.AJGE, x86.AJLT},
+	ssa.BlockAMD64LE:  {x86.AJLE, x86.AJGT},
+	ssa.BlockAMD64GT:  {x86.AJGT, x86.AJLE},
+	ssa.BlockAMD64ULT: {x86.AJCS, x86.AJCC},
+	ssa.BlockAMD64UGE: {x86.AJCC, x86.AJCS},
+	ssa.BlockAMD64UGT: {x86.AJHI, x86.AJLS},
+	ssa.BlockAMD64ULE: {x86.AJLS, x86.AJHI},
+	ssa.BlockAMD64ORD: {x86.AJPC, x86.AJPS},
+	ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
+}
+
+var eqfJumps = [2][2]gc.FloatingEQNEJump{
+	{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPS, Index: 1}}, // next == b.Succs[0]
+	{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
+}
+var nefJumps = [2][2]gc.FloatingEQNEJump{
+	{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPC, Index: 1}}, // next == b.Succs[0]
+	{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
+}
+
+func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
+	s.SetLineno(b.Line)
+
+	switch b.Kind {
+	case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
+		if b.Succs[0].Block() != next {
+			p := gc.Prog(obj.AJMP)
+			p.To.Type = obj.TYPE_BRANCH
+			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+		}
+	case ssa.BlockDefer:
+		// defer returns in rax:
+		// 0 if we should continue executing
+		// 1 if we should jump to deferreturn call
+		p := gc.Prog(x86.ATESTL)
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = x86.REG_AX
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = x86.REG_AX
+		p = gc.Prog(x86.AJNE)
+		p.To.Type = obj.TYPE_BRANCH
+		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
+		if b.Succs[0].Block() != next {
+			p := gc.Prog(obj.AJMP)
+			p.To.Type = obj.TYPE_BRANCH
+			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+		}
+	case ssa.BlockExit:
+		gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
+	case ssa.BlockRet:
+		gc.Prog(obj.ARET)
+	case ssa.BlockRetJmp:
+		p := gc.Prog(obj.AJMP)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+
+	case ssa.BlockAMD64EQF:
+		gc.SSAGenFPJump(s, b, next, &eqfJumps)
+
+	case ssa.BlockAMD64NEF:
+		gc.SSAGenFPJump(s, b, next, &nefJumps)
+
+	case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
+		ssa.BlockAMD64LT, ssa.BlockAMD64GE,
+		ssa.BlockAMD64LE, ssa.BlockAMD64GT,
+		ssa.BlockAMD64ULT, ssa.BlockAMD64UGT,
+		ssa.BlockAMD64ULE, ssa.BlockAMD64UGE:
+		jmp := blockJump[b.Kind]
+		likely := b.Likely
+		var p *obj.Prog
+		switch next {
+		case b.Succs[0].Block():
+			p = gc.Prog(jmp.invasm)
+			likely *= -1
+			p.To.Type = obj.TYPE_BRANCH
+			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
+		case b.Succs[1].Block():
+			p = gc.Prog(jmp.asm)
+			p.To.Type = obj.TYPE_BRANCH
+			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+		default:
+			p = gc.Prog(jmp.asm)
+			p.To.Type = obj.TYPE_BRANCH
+			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+			q := gc.Prog(obj.AJMP)
+			q.To.Type = obj.TYPE_BRANCH
+			s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
+		}
+
+		// liblink reorders the instruction stream as it sees fit.
+		// Pass along what we know so liblink can make use of it.
+		// TODO: Once we've fully switched to SSA,
+		// make liblink leave our output alone.
+		switch likely {
+		case ssa.BranchUnlikely:
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = 0
+		case ssa.BranchLikely:
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = 1
+		}
+
+	default:
+		b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
+	}
+}
diff --git a/src/cmd/compile/internal/arm/cgen.go b/src/cmd/compile/internal/arm/cgen.go
index 289da5d..c60df08 100644
--- a/src/cmd/compile/internal/arm/cgen.go
+++ b/src/cmd/compile/internal/arm/cgen.go
@@ -60,7 +60,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// for example moving [4]byte must use 4 MOVB not 1 MOVW.
 	align := int(n.Type.Align)
 
-	var op int
+	var op obj.As
 	switch align {
 	default:
 		gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
@@ -87,7 +87,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// 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 {
+	if osrc < odst && odst < osrc+w {
 		dir = -dir
 	}
 
diff --git a/src/cmd/compile/internal/arm/cgen64.go b/src/cmd/compile/internal/arm/cgen64.go
index d46d5a8..33e8406 100644
--- a/src/cmd/compile/internal/arm/cgen64.go
+++ b/src/cmd/compile/internal/arm/cgen64.go
@@ -19,7 +19,7 @@ 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.Fatalf("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0))
+		gc.Fatalf("cgen64 %v of %v", n.Op, res.Op)
 	}
 
 	l := n.Left
@@ -35,7 +35,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 	split64(l, &lo1, &hi1)
 	switch n.Op {
 	default:
-		gc.Fatalf("cgen64 %v", gc.Oconv(int(n.Op), 0))
+		gc.Fatalf("cgen64 %v", n.Op)
 
 	case gc.OMINUS:
 		var lo2 gc.Node
@@ -126,7 +126,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 	var ah gc.Node
 	gc.Regalloc(&ah, hi1.Type, nil)
 
-	// Do op.  Leave result in ah:al.
+	// Do op. Leave result in ah:al.
 	switch n.Op {
 	default:
 		gc.Fatalf("cgen64: not implemented: %v\n", n)
@@ -237,7 +237,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 	//	shld hi:lo, c
 	//	shld lo:t, c
 	case gc.OLROT:
-		v := uint64(r.Int())
+		v := uint64(r.Int64())
 
 		var bl gc.Node
 		gc.Regalloc(&bl, lo1.Type, nil)
@@ -291,7 +291,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 		var p4 *obj.Prog
 		var p5 *obj.Prog
 		if r.Op == gc.OLITERAL {
-			v := uint64(r.Int())
+			v := uint64(r.Int64())
 			if v >= 64 {
 				// TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
 				// here and below (verify it optimizes to EOR)
@@ -452,7 +452,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 		var creg gc.Node
 		var p3 *obj.Prog
 		if r.Op == gc.OLITERAL {
-			v := uint64(r.Int())
+			v := uint64(r.Int64())
 			if v >= 64 {
 				if bh.Type.Etype == gc.TINT32 {
 					//	MOVW	bh->31, al
@@ -793,7 +793,7 @@ func cmp64(nl *gc.Node, nr *gc.Node, op gc.Op, likely int, to *obj.Prog) {
 	var br *obj.Prog
 	switch op {
 	default:
-		gc.Fatalf("cmp64 %v %v", gc.Oconv(int(op), 0), t)
+		gc.Fatalf("cmp64 %v %v", op, t)
 
 		// cmp hi
 	// bne L
diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go
index 58c7f7b..afd86e4 100644
--- a/src/cmd/compile/internal/arm/galign.go
+++ b/src/cmd/compile/internal/arm/galign.go
@@ -6,42 +6,15 @@ package arm
 
 import (
 	"cmd/compile/internal/gc"
-	"cmd/internal/obj"
+	"cmd/compile/internal/ssa"
 	"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{
-	{"int", gc.TINT, gc.TINT32},
-	{"uint", gc.TUINT, gc.TUINT32},
-	{"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.LinkArch = &arm.Linkarm
 	gc.Thearch.REGSP = arm.REGSP
 	gc.Thearch.REGCTXT = arm.REGCTXT
 	gc.Thearch.REGCALLX = arm.REG_R1
@@ -51,7 +24,7 @@ func Main() {
 	gc.Thearch.REGMAX = arm.REGEXT
 	gc.Thearch.FREGMIN = arm.REG_F0
 	gc.Thearch.FREGMAX = arm.FREGEXT
-	gc.Thearch.MAXWIDTH = MAXWIDTH
+	gc.Thearch.MAXWIDTH = (1 << 32) - 1
 	gc.Thearch.ReservedRegs = resvd
 
 	gc.Thearch.Betypeinit = betypeinit
@@ -70,7 +43,6 @@ func Main() {
 	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
@@ -89,6 +61,11 @@ func Main() {
 	gc.Thearch.Doregbits = doregbits
 	gc.Thearch.Regnames = regnames
 
+	gc.Thearch.SSARegToReg = ssaRegToReg
+	gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
+	gc.Thearch.SSAGenValue = ssaGenValue
+	gc.Thearch.SSAGenBlock = ssaGenBlock
+
 	gc.Main()
 	gc.Exit(0)
 }
diff --git a/src/cmd/compile/internal/arm/ggen.go b/src/cmd/compile/internal/arm/ggen.go
index 517b4f4..4a45e58 100644
--- a/src/cmd/compile/internal/arm/ggen.go
+++ b/src/cmd/compile/internal/arm/ggen.go
@@ -11,12 +11,10 @@ import (
 )
 
 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)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 	ptxt.To.Offset = int64(frame)
 
@@ -28,8 +26,7 @@ func defframe(ptxt *obj.Prog) {
 	hi := int64(0)
 	lo := hi
 	r0 := uint32(0)
-	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
-		n = l.N
+	for _, n := range gc.Curfn.Func.Dcl {
 		if !n.Name.Needzero {
 			continue
 		}
@@ -37,7 +34,7 @@ func defframe(ptxt *obj.Prog) {
 			gc.Fatalf("needzero class %d", n.Class)
 		}
 		if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
-			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
+			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.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
@@ -98,15 +95,15 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Pr
 	return p
 }
 
-func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int32, ttype int, treg int, toffset int32) *obj.Prog {
+func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int32, ttype obj.AddrType, treg int, toffset int32) *obj.Prog {
 	q := gc.Ctxt.NewProg()
 	gc.Clearp(q)
-	q.As = int16(as)
+	q.As = as
 	q.Lineno = p.Lineno
-	q.From.Type = int16(ftype)
+	q.From.Type = ftype
 	q.From.Reg = int16(freg)
 	q.From.Offset = int64(foffset)
-	q.To.Type = int16(ttype)
+	q.To.Type = ttype
 	q.To.Reg = int16(treg)
 	q.To.Offset = int64(toffset)
 	q.Link = p.Link
@@ -124,7 +121,7 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	}
 
 	t := nl.Type
-	w := int(t.Width * 8)
+	w := t.Width * 8
 	var n1 gc.Node
 	gc.Regalloc(&n1, t, res)
 	gc.Cgen(nl, &n1)
@@ -146,7 +143,7 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	case gc.TINT32,
 		gc.TUINT32:
 		var p *obj.Prog
-		if gc.Issigned[t.Etype] {
+		if t.IsSigned() {
 			p = gins(arm.AMULL, &n2, nil)
 		} else {
 			p = gins(arm.AMULLU, &n2, nil)
@@ -181,7 +178,7 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 	w := int(nl.Type.Width * 8)
 
 	if op == gc.OLROT {
-		v := nr.Int()
+		v := nr.Int64()
 		var n1 gc.Node
 		gc.Regalloc(&n1, nl.Type, res)
 		if w == 32 {
@@ -208,17 +205,17 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 		var n1 gc.Node
 		gc.Regalloc(&n1, nl.Type, res)
 		gc.Cgen(nl, &n1)
-		sc := uint64(nr.Int())
+		sc := uint64(nr.Int64())
 		if sc == 0 {
 		} else // nothing to do
 		if sc >= uint64(nl.Type.Width*8) {
-			if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
+			if op == gc.ORSH && nl.Type.IsSigned() {
 				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] {
+			if op == gc.ORSH && nl.Type.IsSigned() {
 				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
@@ -297,7 +294,7 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 	if op == gc.ORSH {
 		var p1 *obj.Prog
 		var p2 *obj.Prog
-		if gc.Issigned[nl.Type.Etype] {
+		if nl.Type.IsSigned() {
 			p1 = gshift(arm.AMOVW, &n2, arm.SHIFT_AR, int32(w)-1, &n2)
 			p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_AR, &n1, &n2)
 		} else {
@@ -344,6 +341,11 @@ func clearfat(nl *gc.Node) {
 	c := w % 4 // bytes
 	q := w / 4 // quads
 
+	if nl.Type.Align < 4 {
+		q = 0
+		c = w
+	}
+
 	var r0 gc.Node
 	r0.Op = gc.OREGISTER
 
@@ -398,6 +400,27 @@ func clearfat(nl *gc.Node) {
 		}
 	}
 
+	if c > 4 {
+		// Loop to zero unaligned memory.
+		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(c)
+
+		p = gins(arm.AMOVB, &nz, &dst)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = 1
+		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)
+		c = 0
+	}
 	var p *obj.Prog
 	for c > 0 {
 		p = gins(arm.AMOVB, &nz, &dst)
@@ -424,7 +447,7 @@ func expandchecks(firstp *obj.Prog) {
 			continue
 		}
 		if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
-			gc.Warnl(int(p.Lineno), "generated nil check")
+			gc.Warnl(p.Lineno, "generated nil check")
 		}
 		if p.From.Type != obj.TYPE_REG {
 			gc.Fatalf("invalid nil check %v", p)
@@ -467,7 +490,7 @@ func ginsnop() {
  * generate
  *	as $c, n
  */
-func ginscon(as int, c int64, n *gc.Node) {
+func ginscon(as obj.As, c int64, n *gc.Node) {
 	var n1 gc.Node
 	gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
 	var n2 gc.Node
@@ -478,7 +501,7 @@ func ginscon(as int, c int64, n *gc.Node) {
 }
 
 func ginscmp(op gc.Op, 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 {
+	if t.IsInteger() && n1.Op == gc.OLITERAL && n1.Int64() == 0 && n2.Op != gc.OLITERAL {
 		op = gc.Brrev(op)
 		n1, n2 = n2, n1
 	}
@@ -487,7 +510,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 	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 {
+	if t.IsInteger() && n2.Op == gc.OLITERAL && n2.Int64() == 0 {
 		gins(arm.ACMP, &r1, n2)
 	} else {
 		gc.Regalloc(&r2, t, n2)
diff --git a/src/cmd/compile/internal/arm/gsubr.go b/src/cmd/compile/internal/arm/gsubr.go
index 108d78a..b5d7bc0 100644
--- a/src/cmd/compile/internal/arm/gsubr.go
+++ b/src/cmd/compile/internal/arm/gsubr.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -86,17 +86,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 
 			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
-			}
-
+		case gc.ONAME, gc.OINDREG:
 			// nothing
-		case gc.OINDREG:
-			break
 		}
 
 		*lo = *n
@@ -112,7 +103,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 	case gc.OLITERAL:
 		var n1 gc.Node
 		n.Convconst(&n1, n.Type)
-		i := n1.Int()
+		i := n1.Int64()
 		gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
 		i >>= 32
 		if n.Type.Etype == gc.TINT64 {
@@ -149,7 +140,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 
 	// cannot have two memory operands;
 	// except 64-bit, which always copies via registers anyway.
-	var a int
+	var a obj.As
 	var r1 gc.Node
 	if !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
@@ -636,7 +627,7 @@ func samaddr(f *gc.Node, t *gc.Node) bool {
  * generate one instruction:
  *	as f, t
  */
-func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+func gins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
 	//	Node nod;
 	//	int32 v;
 
@@ -719,7 +710,7 @@ func raddr(n *gc.Node, p *obj.Prog) {
 	gc.Naddr(&a, n)
 	if a.Type != obj.TYPE_REG {
 		if n != nil {
-			gc.Fatalf("bad in raddr: %v", gc.Oconv(int(n.Op), 0))
+			gc.Fatalf("bad in raddr: %v", n.Op)
 		} else {
 			gc.Fatalf("bad in raddr: <null>")
 		}
@@ -732,7 +723,7 @@ func raddr(n *gc.Node, p *obj.Prog) {
 /* 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 {
+func gshift(as obj.As, lhs *gc.Node, stype int32, sval int32, rhs *gc.Node) *obj.Prog {
 	if sval <= 0 || sval > 32 {
 		gc.Fatalf("bad shift value: %d", sval)
 	}
@@ -747,7 +738,7 @@ func gshift(as int, lhs *gc.Node, stype int32, sval int32, rhs *gc.Node) *obj.Pr
 
 /* generate a register shift
  */
-func gregshift(as int, lhs *gc.Node, stype int32, reg *gc.Node, rhs *gc.Node) *obj.Prog {
+func gregshift(as obj.As, 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
@@ -757,7 +748,7 @@ func gregshift(as int, lhs *gc.Node, stype int32, reg *gc.Node, rhs *gc.Node) *o
 /*
  * return Axxx for Oxxx on type t.
  */
-func optoas(op gc.Op, t *gc.Type) int {
+func optoas(op gc.Op, t *gc.Type) obj.As {
 	if t == nil {
 		gc.Fatalf("optoas: t is nil")
 	}
@@ -790,7 +781,7 @@ func optoas(op gc.Op, t *gc.Type) int {
 	a := obj.AXXX
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatalf("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]])
+		gc.Fatalf("optoas: no entry %v-%v etype %v simtype %v", op, t, gc.Types[t.Etype], gc.Types[gc.Simtype[t.Etype]])
 
 		/*	case CASE(OADDR, TPTR32):
 				a = ALEAL;
@@ -1131,7 +1122,7 @@ func dotaddable(n *gc.Node, n1 *gc.Node) bool {
  * after successful sudoaddable,
  * to release the register used for a.
  */
-func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
+func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
 	if n.Type == nil {
 		return false
 	}
@@ -1143,7 +1134,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
 		if !gc.Isconst(n, gc.CTINT) {
 			break
 		}
-		v := n.Int()
+		v := n.Int64()
 		if v >= 32000 || v <= -32000 {
 			break
 		}
diff --git a/src/cmd/compile/internal/arm/peep.go b/src/cmd/compile/internal/arm/peep.go
index bc49ebc..e1c8e4d 100644
--- a/src/cmd/compile/internal/arm/peep.go
+++ b/src/cmd/compile/internal/arm/peep.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -41,13 +41,12 @@ var gactive uint32
 
 // UNUSED
 func peep(firstp *obj.Prog) {
-	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	g := gc.Flowstart(firstp, nil)
 	if g == nil {
 		return
 	}
 	gactive = 0
 
-	var r *gc.Flow
 	var p *obj.Prog
 	var t int
 loop1:
@@ -56,7 +55,7 @@ loop1:
 	}
 
 	t = 0
-	for r = g.Start; r != nil; r = r.Link {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
 		/*
@@ -119,7 +118,7 @@ loop1:
 		goto loop1
 	}
 
-	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
 		/*
@@ -139,7 +138,7 @@ loop1:
 		}
 	}
 
-	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
 		case arm.AMOVW,
@@ -248,12 +247,12 @@ func regtyp(a *obj.Addr) bool {
  * will be eliminated by copy propagation.
  */
 func subprop(r0 *gc.Flow) bool {
-	p := (*obj.Prog)(r0.Prog)
-	v1 := (*obj.Addr)(&p.From)
+	p := r0.Prog
+	v1 := &p.From
 	if !regtyp(v1) {
 		return false
 	}
-	v2 := (*obj.Addr)(&p.To)
+	v2 := &p.To
 	if !regtyp(v2) {
 		return false
 	}
@@ -289,7 +288,7 @@ func subprop(r0 *gc.Flow) bool {
 			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)
+						copysub(&p.To, v1, v2, true)
 						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 {
@@ -300,17 +299,15 @@ func subprop(r0 *gc.Flow) bool {
 
 						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)
+							copysub(&p.From, v1, v2, true)
+							copysub1(p, v1, v2, true)
+							copysub(&p.To, v1, v2, true)
 							if gc.Debug['P'] != 0 {
 								fmt.Printf("%v\n", r.Prog)
 							}
 						}
 
-						t := int(int(v1.Reg))
-						v1.Reg = v2.Reg
-						v2.Reg = int16(t)
+						v1.Reg, v2.Reg = v2.Reg, v1.Reg
 						if gc.Debug['P'] != 0 {
 							fmt.Printf("%v last\n", r.Prog)
 						}
@@ -323,7 +320,7 @@ func subprop(r0 *gc.Flow) bool {
 		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 {
+		if copysub(&p.From, v1, v2, false) || copysub1(p, v1, v2, false) || copysub(&p.To, v1, v2, false) {
 			break
 		}
 	}
@@ -344,17 +341,17 @@ func subprop(r0 *gc.Flow) bool {
  *	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)
+	p := r0.Prog
+	v1 := &p.From
+	v2 := &p.To
 	if copyas(v1, v2) {
 		return true
 	}
 	gactive++
-	return copy1(v1, v2, r0.S1, 0)
+	return copy1(v1, v2, r0.S1, false)
 }
 
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
 	if uint32(r.Active) == gactive {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("act set; return 1\n")
@@ -364,24 +361,21 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 	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)
+		fmt.Printf("copy %v->%v f=%v\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
+		p := r.Prog
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("%v", p)
 		}
-		if f == 0 && gc.Uniqp(r) == nil {
-			f = 1
+		if !f && gc.Uniqp(r) == nil {
+			f = true
 			if gc.Debug['P'] != 0 {
-				fmt.Printf("; merge; f=%d", f)
+				fmt.Printf("; merge; f=%v", f)
 			}
 		}
 
-		t = copyu(p, v2, nil)
-		switch t {
+		switch t := copyu(p, v2, nil); t {
 		case 2: /* rar, can't split */
 			if gc.Debug['P'] != 0 {
 				fmt.Printf("; %vrar; return 0\n", gc.Ctxt.Dconv(v2))
@@ -396,14 +390,14 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 		case 1, /* used, substitute */
 			4: /* use and set */
-			if f != 0 {
+			if f {
 				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)
+					fmt.Printf("; %vused+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				} else {
-					fmt.Printf("; %vused and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+					fmt.Printf("; %vused and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				}
 				return false
 			}
@@ -426,12 +420,12 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 
-		if f == 0 {
-			t = copyu(p, v1, nil)
-			if f == 0 && (t == 2 || t == 3 || t == 4) {
-				f = 1
+		if !f {
+			t := copyu(p, v1, nil)
+			if t == 2 || t == 3 || t == 4 {
+				f = true
 				if gc.Debug['P'] != 0 {
-					fmt.Printf("; %vset and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+					fmt.Printf("; %vset and !f; f=%v", gc.Ctxt.Dconv(v1), f)
 				}
 			}
 		}
@@ -445,7 +439,6 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 	}
-
 	return true
 }
 
@@ -511,13 +504,13 @@ func constprop(c1 *obj.Addr, v1 *obj.Addr, r *gc.Flow) {
  * 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))
+	p := r.Prog
+	r1 := findpre(r, &p.From)
 	if r1 == nil {
 		return false
 	}
 
-	p1 := (*obj.Prog)(r1.Prog)
+	p1 := r1.Prog
 	if p1.As == p.As {
 		// Two consecutive extensions.
 		goto gotit
@@ -545,7 +538,7 @@ gotit:
 	}
 
 	if gc.Debug['P'] != 0 {
-		fmt.Printf(" => %v\n", obj.Aconv(int(p.As)))
+		fmt.Printf(" => %v\n", obj.Aconv(p.As))
 	}
 	return true
 }
@@ -563,7 +556,7 @@ gotit:
  * ..
  */
 func shiftprop(r *gc.Flow) bool {
-	p := (*obj.Prog)(r.Prog)
+	p := r.Prog
 	if p.To.Type != obj.TYPE_REG {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("\tBOTCH: result not reg; FAILURE\n")
@@ -571,8 +564,8 @@ func shiftprop(r *gc.Flow) bool {
 		return false
 	}
 
-	n := int(int(p.To.Reg))
-	a := obj.Addr(obj.Addr{})
+	n := p.To.Reg
+	var a obj.Addr
 	if p.Reg != 0 && p.Reg != p.To.Reg {
 		a.Type = obj.TYPE_REG
 		a.Reg = p.Reg
@@ -581,7 +574,7 @@ func shiftprop(r *gc.Flow) bool {
 	if gc.Debug['P'] != 0 {
 		fmt.Printf("shiftprop\n%v", p)
 	}
-	r1 := (*gc.Flow)(r)
+	r1 := r
 	var p1 *obj.Prog
 	for {
 		/* find first use of shift result; abort if shift operands or result are changed */
@@ -644,7 +637,7 @@ func shiftprop(r *gc.Flow) bool {
 		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.Reg == n || (p1.Reg == 0 && p1.To.Type == obj.TYPE_REG && p1.To.Reg == n) {
 			if p1.From.Type != obj.TYPE_REG {
 				if gc.Debug['P'] != 0 {
 					fmt.Printf("\tcan't swap; FAILURE\n")
@@ -653,7 +646,7 @@ func shiftprop(r *gc.Flow) bool {
 			}
 
 			p1.Reg = p1.From.Reg
-			p1.From.Reg = int16(n)
+			p1.From.Reg = n
 			switch p1.As {
 			case arm.ASUB:
 				p1.As = arm.ARSB
@@ -678,14 +671,14 @@ func shiftprop(r *gc.Flow) bool {
 		arm.ATST,
 		arm.ACMP,
 		arm.ACMN:
-		if int(p1.Reg) == n {
+		if 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 p1.Reg == 0 && p1.To.Reg == n {
 			if gc.Debug['P'] != 0 {
 				fmt.Printf("\tshift result used twice; FAILURE\n")
 			}
@@ -700,7 +693,7 @@ func shiftprop(r *gc.Flow) bool {
 			return false
 		}
 
-		if p1.From.Type != obj.TYPE_REG || int(p1.From.Reg) != n {
+		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != n {
 			if gc.Debug['P'] != 0 {
 				fmt.Printf("\tBOTCH: where is it used?; FAILURE\n")
 			}
@@ -709,9 +702,9 @@ func shiftprop(r *gc.Flow) bool {
 	}
 
 	/* check whether shift result is used subsequently */
-	p2 := (*obj.Prog)(p1)
+	p2 := p1
 
-	if int(p1.To.Reg) != n {
+	if p1.To.Reg != n {
 		var p1 *obj.Prog
 		for {
 			r1 = gc.Uniqs(r1)
@@ -746,19 +739,18 @@ func shiftprop(r *gc.Flow) bool {
 
 	/* make the substitution */
 	p2.From.Reg = 0
-
-	o := int(int(p.Reg))
+	o := p.Reg
 	if o == 0 {
-		o = int(p.To.Reg)
+		o = p.To.Reg
 	}
 	o &= 15
 
 	switch p.From.Type {
 	case obj.TYPE_CONST:
-		o |= int((p.From.Offset & 0x1f) << 7)
+		o |= int16(p.From.Offset&0x1f) << 7
 
 	case obj.TYPE_REG:
-		o |= 1<<4 | (int(p.From.Reg)&15)<<8
+		o |= 1<<4 | (p.From.Reg&15)<<8
 	}
 
 	switch p.As {
@@ -911,7 +903,7 @@ func findu1(r *gc.Flow, v *obj.Addr) bool {
 }
 
 func finduse(g *gc.Graph, r *gc.Flow, v *obj.Addr) bool {
-	for r1 := (*gc.Flow)(g.Start); r1 != nil; r1 = r1.Link {
+	for r1 := g.Start; r1 != nil; r1 = r1.Link {
 		r1.Active = 0
 	}
 	return findu1(r, v)
@@ -931,10 +923,10 @@ func finduse(g *gc.Graph, r *gc.Flow, v *obj.Addr) bool {
  *   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)
+	p := r.Prog
+	v := *a
 	v.Type = obj.TYPE_REG
-	r1 := (*gc.Flow)(findpre(r, &v))
+	r1 := findpre(r, &v)
 	if r1 != nil {
 		p1 := r1.Prog
 		if p1.To.Type == obj.TYPE_REG && p1.To.Reg == v.Reg {
@@ -993,7 +985,7 @@ func xtramodes(g *gc.Graph, r *gc.Flow, a *obj.Addr) bool {
 
 			case arm.AMOVW:
 				if p1.From.Type == obj.TYPE_REG {
-					r2 := (*gc.Flow)(findinc(r1, r, &p1.From))
+					r2 := 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) {
@@ -1018,7 +1010,7 @@ func xtramodes(g *gc.Graph, r *gc.Flow, a *obj.Addr) bool {
 	}
 
 	if a != &p.From || a.Reg != p.To.Reg {
-		r1 := (*gc.Flow)(findinc(r, nil, &v))
+		r1 := findinc(r, nil, &v)
 		if r1 != nil {
 			/* post-indexing */
 			p1 := r1.Prog
@@ -1044,7 +1036,7 @@ func xtramodes(g *gc.Graph, r *gc.Flow, a *obj.Addr) bool {
 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)))
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
 		return 2
 
 	case arm.AMOVM:
@@ -1056,7 +1048,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 				if p.From.Offset&(1<<uint(v.Reg)) != 0 {
 					return 1
 				}
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 				return 0
@@ -1077,7 +1069,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 				if p.To.Offset&(1<<uint(v.Reg)) != 0 {
 					return 1
 				}
-				if copysub(&p.From, v, s, 1) != 0 {
+				if copysub(&p.From, v, s, true) {
 					return 1
 				}
 				return 0
@@ -1132,11 +1124,11 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		}
 
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
 			if !copyas(&p.To, v) {
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 			}
@@ -1201,14 +1193,14 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		arm.ATST:
 		/* read,, */
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
-			if copysub1(p, v, s, 1) != 0 {
+			if copysub1(p, v, s, true) {
 				return 1
 			}
 			if !copyas(&p.To, v) {
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 			}
@@ -1259,10 +1251,13 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		arm.ABGT,
 		arm.ABLE:
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
+				return 1
+			}
+			if copysub1(p, v, s, true) {
 				return 1
 			}
-			return copysub1(p, v, s, 1)
+			return 0
 		}
 
 		if copyau(&p.From, v) {
@@ -1275,12 +1270,11 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 
 	case arm.AB: /* funny */
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
 		}
-
 		if copyau(&p.To, v) {
 			return 1
 		}
@@ -1315,7 +1309,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		}
 
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -1326,7 +1320,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		}
 		return 3
 
-		// R0 is zero, used by DUFFZERO, cannot be substituted.
+	// 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 {
@@ -1340,7 +1334,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 
 		return 0
 
-		// R0 is scratch, set by DUFFCOPY, cannot be substituted.
+	// 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 {
@@ -1464,48 +1458,43 @@ func copyau1(p *obj.Prog, v *obj.Addr) bool {
 	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 {
+// copysub substitute s for v in a.
+// copysub returns true on failure to substitute.
+// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
+	if f && 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
+	return false
 }
 
-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
-		}
+// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
+func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f bool) bool {
+	if f && copyau1(p1, v) {
+		p1.Reg = s.Reg
 	}
-	return 0
+	return false
 }
 
 var predinfo = []struct {
-	opcode    int
-	notopcode int
+	opcode    obj.As
+	notopcode obj.As
 	scond     int
 	notscond  int
 }{
@@ -1558,7 +1547,6 @@ func predicable(p *obj.Prog) bool {
 	switch p.As {
 	case obj.ANOP,
 		obj.AXXX,
-		obj.ADATA,
 		obj.AGLOBL,
 		obj.ATEXT,
 		arm.AWORD:
@@ -1653,9 +1641,8 @@ func joinsplit(r *gc.Flow, j *Joininfo) int {
 func successor(r *gc.Flow) *gc.Flow {
 	if r.S1 != nil {
 		return r.S1
-	} else {
-		return r.S2
 	}
+	return r.S2
 }
 
 func applypred(rstart *gc.Flow, j *Joininfo, cond int, branch int) {
@@ -1669,15 +1656,15 @@ func applypred(rstart *gc.Flow, j *Joininfo, cond int, branch int) {
 		pred = predinfo[rstart.Prog.As-arm.ABEQ].notscond
 	}
 
-	for r := (*gc.Flow)(j.start); ; r = successor(r) {
+	for r := 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)
+					r.Prog.As = predinfo[rstart.Prog.As-arm.ABEQ].opcode
 				} else {
-					r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].notopcode)
+					r.Prog.As = predinfo[rstart.Prog.As-arm.ABEQ].notopcode
 				}
 			}
 		} else if predicable(r.Prog) {
@@ -1700,7 +1687,7 @@ func predicate(g *gc.Graph) {
 	var j1 Joininfo
 	var j2 Joininfo
 
-	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+	for r := g.Start; r != nil; r = r.Link {
 		if isbranch(r.Prog) {
 			t1 = joinsplit(r.S1, &j1)
 			t2 = joinsplit(r.S2, &j2)
@@ -1742,6 +1729,6 @@ func smallindir(a *obj.Addr, reg *obj.Addr) bool {
 }
 
 func excise(r *gc.Flow) {
-	p := (*obj.Prog)(r.Prog)
+	p := r.Prog
 	obj.Nopout(p)
 }
diff --git a/src/cmd/compile/internal/arm/prog.go b/src/cmd/compile/internal/arm/prog.go
index 81be77a..f69548a 100644
--- a/src/cmd/compile/internal/arm/prog.go
+++ b/src/cmd/compile/internal/arm/prog.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -21,9 +21,7 @@ const (
 // 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{
+var progtable = [arm.ALAST & obj.AMask]obj.ProgInfo{
 	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
 	obj.ATEXT:     {Flags: gc.Pseudo},
 	obj.AFUNCDATA: {Flags: gc.Pseudo},
@@ -40,104 +38,104 @@ var progtable = [arm.ALAST]obj.ProgInfo{
 	obj.ANOP: {Flags: gc.LeftRead | gc.RightWrite},
 
 	// Integer.
-	arm.AADC:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AADD:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AAND:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ABIC:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ACMN:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
-	arm.ACMP:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
-	arm.ADIVU:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ADIV:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AEOR:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AMODU:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AMOD:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AMULALU: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr},
-	arm.AMULAL:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr},
-	arm.AMULA:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr},
-	arm.AMULU:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AMUL:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AMULL:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AMULLU:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.AMVN:    {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite},
-	arm.AORR:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ARSB:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ARSC:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ASBC:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ASLL:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ASRA:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ASRL:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ASUB:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm.ATEQ:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
-	arm.ATST:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
+	arm.AADC & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AADD & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AAND & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ABIC & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ACMN & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
+	arm.ACMP & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
+	arm.ADIVU & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ADIV & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AEOR & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AMODU & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AMOD & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AMULALU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr},
+	arm.AMULAL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr},
+	arm.AMULA & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr},
+	arm.AMULU & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AMUL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AMULL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AMULLU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.AMVN & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite},
+	arm.AORR & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ARSB & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ARSC & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ASBC & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ASLL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ASRA & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ASRL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ASUB & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm.ATEQ & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
+	arm.ATST & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
 
 	// Floating point.
-	arm.AADDD:  {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	arm.AADDF:  {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	arm.ACMPD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
-	arm.ACMPF:  {Flags: gc.SizeF | gc.LeftRead | gc.RightRead},
-	arm.ADIVD:  {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	arm.ADIVF:  {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	arm.AMULD:  {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	arm.AMULF:  {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	arm.ASUBD:  {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	arm.ASUBF:  {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	arm.ASQRTD: {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	arm.AADDD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	arm.AADDF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	arm.ACMPD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
+	arm.ACMPF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightRead},
+	arm.ADIVD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	arm.ADIVF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	arm.AMULD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	arm.AMULF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	arm.ASUBD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	arm.ASUBF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	arm.ASQRTD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
 
 	// Conversions.
-	arm.AMOVWD: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm.AMOVWF: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm.AMOVDF: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm.AMOVDW: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm.AMOVFD: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm.AMOVFW: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVWD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVWF & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVDF & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVDW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVFD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVFW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
 
 	// Moves.
-	arm.AMOVB: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm.AMOVD: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm.AMOVF: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm.AMOVH: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm.AMOVW: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
+	arm.AMOVB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move},
+	arm.AMOVD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+	arm.AMOVF & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move},
+	arm.AMOVH & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move},
+	arm.AMOVW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
 
-	// In addtion, duffzero reads R0,R1 and writes R1.  This fact is
+	// In addition, duffzero reads R0,R1 and writes R1.  This fact is
 	// encoded in peep.c
 	obj.ADUFFZERO: {Flags: gc.Call},
 
-	// In addtion, duffcopy reads R1,R2 and writes R0,R1,R2.  This fact is
+	// In addition, duffcopy reads R1,R2 and writes R0,R1,R2.  This fact is
 	// encoded in peep.c
 	obj.ADUFFCOPY: {Flags: gc.Call},
 
 	// These should be split into the two different conversions instead
 	// of overloading the one.
-	arm.AMOVBS: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm.AMOVBU: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm.AMOVHS: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm.AMOVHU: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVBS & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVBU & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVHS & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm.AMOVHU & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
 
 	// Jumps.
-	arm.AB:   {Flags: gc.Jump | gc.Break},
-	arm.ABL:  {Flags: gc.Call},
-	arm.ABEQ: {Flags: gc.Cjmp},
-	arm.ABNE: {Flags: gc.Cjmp},
-	arm.ABCS: {Flags: gc.Cjmp},
-	arm.ABHS: {Flags: gc.Cjmp},
-	arm.ABCC: {Flags: gc.Cjmp},
-	arm.ABLO: {Flags: gc.Cjmp},
-	arm.ABMI: {Flags: gc.Cjmp},
-	arm.ABPL: {Flags: gc.Cjmp},
-	arm.ABVS: {Flags: gc.Cjmp},
-	arm.ABVC: {Flags: gc.Cjmp},
-	arm.ABHI: {Flags: gc.Cjmp},
-	arm.ABLS: {Flags: gc.Cjmp},
-	arm.ABGE: {Flags: gc.Cjmp},
-	arm.ABLT: {Flags: gc.Cjmp},
-	arm.ABGT: {Flags: gc.Cjmp},
-	arm.ABLE: {Flags: gc.Cjmp},
-	obj.ARET: {Flags: gc.Break},
+	arm.AB & obj.AMask:   {Flags: gc.Jump | gc.Break},
+	arm.ABL & obj.AMask:  {Flags: gc.Call},
+	arm.ABEQ & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABNE & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABCS & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABHS & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABCC & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABLO & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABMI & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABPL & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABVS & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABVC & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABHI & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABLS & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABGE & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABLT & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABGT & obj.AMask: {Flags: gc.Cjmp},
+	arm.ABLE & obj.AMask: {Flags: gc.Cjmp},
+	obj.ARET:             {Flags: gc.Break},
 }
 
 func proginfo(p *obj.Prog) {
 	info := &p.Info
-	*info = progtable[p.As]
+	*info = progtable[p.As&obj.AMask]
 	if info.Flags == 0 {
 		gc.Fatalf("unknown instruction %v", p)
 	}
diff --git a/src/cmd/compile/internal/arm/reg.go b/src/cmd/compile/internal/arm/reg.go
index b72ccc9..2313bc4 100644
--- a/src/cmd/compile/internal/arm/reg.go
+++ b/src/cmd/compile/internal/arm/reg.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
diff --git a/src/cmd/compile/internal/arm/ssa.go b/src/cmd/compile/internal/arm/ssa.go
new file mode 100644
index 0000000..8f466e3
--- /dev/null
+++ b/src/cmd/compile/internal/arm/ssa.go
@@ -0,0 +1,154 @@
+// Copyright 2016 The Go Authors. 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/compile/internal/ssa"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+)
+
+var ssaRegToReg = []int16{
+	arm.REG_R0,
+	arm.REG_R1,
+	arm.REG_R2,
+	arm.REG_R3,
+	arm.REGSP, // aka R13
+}
+
+func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
+	s.SetLineno(v.Line)
+	switch v.Op {
+	case ssa.OpInitMem:
+		// memory arg needs no code
+	case ssa.OpArg:
+		// input args need no code
+	case ssa.OpSP, ssa.OpSB:
+		// nothing to do
+	case ssa.OpCopy:
+	case ssa.OpLoadReg:
+		// TODO: by type
+		p := gc.Prog(arm.AMOVW)
+		n, off := gc.AutoVar(v.Args[0])
+		p.From.Type = obj.TYPE_MEM
+		p.From.Node = n
+		p.From.Sym = gc.Linksym(n.Sym)
+		p.From.Offset = off
+		if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
+			p.From.Name = obj.NAME_PARAM
+			p.From.Offset += n.Xoffset
+		} else {
+			p.From.Name = obj.NAME_AUTO
+		}
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+
+	case ssa.OpStoreReg:
+		// TODO: by type
+		p := gc.Prog(arm.AMOVW)
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		n, off := gc.AutoVar(v)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Node = n
+		p.To.Sym = gc.Linksym(n.Sym)
+		p.To.Offset = off
+		if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
+			p.To.Name = obj.NAME_PARAM
+			p.To.Offset += n.Xoffset
+		} else {
+			p.To.Name = obj.NAME_AUTO
+		}
+	case ssa.OpARMADD:
+		r := gc.SSARegNum(v)
+		r1 := gc.SSARegNum(v.Args[0])
+		r2 := gc.SSARegNum(v.Args[1])
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = r1
+		p.Reg = r2
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = r
+	case ssa.OpARMADDconst:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = v.AuxInt
+		if v.Aux != nil {
+			panic("can't handle symbolic constant yet")
+		}
+		p.Reg = gc.SSARegNum(v.Args[0])
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpARMMOVWconst:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = v.AuxInt
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpARMCMP:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		// Special layout in ARM assembly
+		// Comparing to x86, the operands of ARM's CMP are reversed.
+		p.From.Reg = gc.SSARegNum(v.Args[1])
+		p.Reg = gc.SSARegNum(v.Args[0])
+	case ssa.OpARMMOVWload:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux(&p.From, v)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = gc.SSARegNum(v)
+	case ssa.OpARMMOVWstore:
+		p := gc.Prog(v.Op.Asm())
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = gc.SSARegNum(v.Args[1])
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = gc.SSARegNum(v.Args[0])
+		gc.AddAux(&p.To, v)
+	case ssa.OpARMCALLstatic:
+		// TODO: deferreturn
+		p := gc.Prog(obj.ACALL)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Name = obj.NAME_EXTERN
+		p.To.Sym = gc.Linksym(v.Aux.(*gc.Sym))
+		if gc.Maxarg < v.AuxInt {
+			gc.Maxarg = v.AuxInt
+		}
+	case ssa.OpVarDef:
+		gc.Gvardef(v.Aux.(*gc.Node))
+	case ssa.OpVarKill:
+		gc.Gvarkill(v.Aux.(*gc.Node))
+	case ssa.OpVarLive:
+		gc.Gvarlive(v.Aux.(*gc.Node))
+	case ssa.OpARMLessThan:
+		v.Fatalf("pseudo-op made it to output: %s", v.LongString())
+	default:
+		v.Unimplementedf("genValue not implemented: %s", v.LongString())
+	}
+}
+
+func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
+	s.SetLineno(b.Line)
+
+	switch b.Kind {
+	case ssa.BlockCall:
+		if b.Succs[0].Block() != next {
+			p := gc.Prog(obj.AJMP)
+			p.To.Type = obj.TYPE_BRANCH
+			s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+		}
+	case ssa.BlockRet:
+		gc.Prog(obj.ARET)
+	case ssa.BlockARMLT:
+		p := gc.Prog(arm.ABLT)
+		p.To.Type = obj.TYPE_BRANCH
+		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+		p = gc.Prog(obj.AJMP)
+		p.To.Type = obj.TYPE_BRANCH
+		s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
+	}
+}
diff --git a/src/cmd/compile/internal/arm64/cgen.go b/src/cmd/compile/internal/arm64/cgen.go
index a7f1c18..87f3498 100644
--- a/src/cmd/compile/internal/arm64/cgen.go
+++ b/src/cmd/compile/internal/arm64/cgen.go
@@ -17,7 +17,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// for example moving [4]byte must use 4 MOVB not 1 MOVW.
 	align := int(n.Type.Align)
 
-	var op int
+	var op obj.As
 	switch align {
 	default:
 		gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
@@ -48,7 +48,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// the src and dst overlap, then reverse direction
 	dir := align
 
-	if osrc < odst && int64(odst) < int64(osrc)+w {
+	if osrc < odst && odst < osrc+w {
 		dir = -dir
 	}
 
@@ -129,7 +129,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 		// 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
+		// ADDs. That will produce shorter, more
 		// pipeline-able code.
 		var p *obj.Prog
 		for ; c > 0; c-- {
diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go
index d61fd3c..7acc4e0 100644
--- a/src/cmd/compile/internal/arm64/galign.go
+++ b/src/cmd/compile/internal/arm64/galign.go
@@ -6,42 +6,14 @@ 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{
-	{"int", gc.TINT, gc.TINT64},
-	{"uint", gc.TUINT, gc.TUINT64},
-	{"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.LinkArch = &arm64.Linkarm64
 	gc.Thearch.REGSP = arm64.REGSP
 	gc.Thearch.REGCTXT = arm64.REGCTXT
 	gc.Thearch.REGCALLX = arm64.REGRT1
@@ -52,11 +24,13 @@ func Main() {
 	gc.Thearch.REGZERO = arm64.REGZERO
 	gc.Thearch.FREGMIN = arm64.REG_F0
 	gc.Thearch.FREGMAX = arm64.REG_F31
-	gc.Thearch.MAXWIDTH = MAXWIDTH
+	gc.Thearch.MAXWIDTH = 1 << 50
 	gc.Thearch.ReservedRegs = resvd
 
 	gc.Thearch.Betypeinit = betypeinit
 	gc.Thearch.Cgen_hmul = cgen_hmul
+	gc.Thearch.AddSetCarry = AddSetCarry
+	gc.Thearch.RightShiftWithCarry = RightShiftWithCarry
 	gc.Thearch.Cgen_shift = cgen_shift
 	gc.Thearch.Clearfat = clearfat
 	gc.Thearch.Defframe = defframe
@@ -69,7 +43,6 @@ func Main() {
 	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
diff --git a/src/cmd/compile/internal/arm64/ggen.go b/src/cmd/compile/internal/arm64/ggen.go
index c495bbc..bddfed6 100644
--- a/src/cmd/compile/internal/arm64/ggen.go
+++ b/src/cmd/compile/internal/arm64/ggen.go
@@ -12,12 +12,10 @@ import (
 )
 
 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)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 
 	// arm64 requires that the frame size (not counting saved LR)
@@ -37,8 +35,7 @@ func defframe(ptxt *obj.Prog) {
 	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
+	for _, n := range gc.Curfn.Func.Dcl {
 		if !n.Name.Needzero {
 			continue
 		}
@@ -46,7 +43,7 @@ func defframe(ptxt *obj.Prog) {
 			gc.Fatalf("needzero class %d", n.Class)
 		}
 		if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
-			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
+			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
 		}
 
 		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
@@ -109,15 +106,15 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
 	return p
 }
 
-func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
+func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
 	q := gc.Ctxt.NewProg()
 	gc.Clearp(q)
-	q.As = int16(as)
+	q.As = as
 	q.Lineno = p.Lineno
-	q.From.Type = int16(ftype)
+	q.From.Type = ftype
 	q.From.Reg = int16(freg)
 	q.From.Offset = foffset
-	q.To.Type = int16(ttype)
+	q.To.Type = ttype
 	q.To.Reg = int16(treg)
 	q.To.Offset = toffset
 	q.Link = p.Link
@@ -146,23 +143,23 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	// 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,
+	// DIVW will leave unpredictable result in higher 32-bit,
 	// so always use DIVD/DIVDU.
 	t := nl.Type
 
 	t0 := t
 	check := false
-	if gc.Issigned[t.Etype] {
+	if t.IsSigned() {
 		check = true
-		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
+		if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -(1<<uint64(t.Width*8-1)) {
 			check = false
-		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
 			check = false
 		}
 	}
 
 	if t.Width < 8 {
-		if gc.Issigned[t.Etype] {
+		if t.IsSigned() {
 			t = gc.Types[gc.TINT64]
 		} else {
 			t = gc.Types[gc.TUINT64]
@@ -255,6 +252,53 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	}
 }
 
+// RightShiftWithCarry generates a constant unsigned
+// right shift with carry.
+//
+// res = n >> shift // with carry
+func RightShiftWithCarry(n *gc.Node, shift uint, res *gc.Node) {
+	// Extra 1 is for carry bit.
+	maxshift := uint(n.Type.Width*8 + 1)
+	if shift == 0 {
+		gmove(n, res)
+	} else if shift < maxshift {
+		// 1. clear rightmost bit of target
+		var n1 gc.Node
+		gc.Nodconst(&n1, n.Type, 1)
+		gins(optoas(gc.ORSH, n.Type), &n1, n)
+		gins(optoas(gc.OLSH, n.Type), &n1, n)
+		// 2. add carry flag to target
+		var n2 gc.Node
+		gc.Nodconst(&n1, n.Type, 0)
+		gc.Regalloc(&n2, n.Type, nil)
+		gins(optoas(gc.OAS, n.Type), &n1, &n2)
+		gins(arm64.AADC, &n2, n)
+		// 3. right rotate 1 bit
+		gc.Nodconst(&n1, n.Type, 1)
+		gins(arm64.AROR, &n1, n)
+
+		// ARM64 backend doesn't eliminate shifts by 0. It is manually checked here.
+		if shift > 1 {
+			var n3 gc.Node
+			gc.Nodconst(&n3, n.Type, int64(shift-1))
+			cgen_shift(gc.ORSH, true, n, &n3, res)
+		} else {
+			gmove(n, res)
+		}
+		gc.Regfree(&n2)
+	} else {
+		gc.Fatalf("RightShiftWithCarry: shift(%v) is bigger than max size(%v)", shift, maxshift)
+	}
+}
+
+// AddSetCarry generates add and set carry.
+//
+//   res = nl + nr // with carry flag set
+func AddSetCarry(nl *gc.Node, nr *gc.Node, res *gc.Node) {
+	gins(arm64.AADDS, nl, nr)
+	gmove(nr, res)
+}
+
 /*
  * generate high multiply:
  *   res = (nl*nr) >> width
@@ -265,8 +309,8 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
 		nl, nr = nr, nl
 	}
 
-	t := (*gc.Type)(nl.Type)
-	w := int(int(t.Width * 8))
+	t := nl.Type
+	w := t.Width * 8
 	var n1 gc.Node
 	gc.Cgenr(nl, &n1, res)
 	var n2 gc.Node
@@ -276,21 +320,21 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
 		gc.TINT16,
 		gc.TINT32:
 		gins(optoas(gc.OMUL, t), &n2, &n1)
-		p := (*obj.Prog)(gins(arm64.AASR, nil, &n1))
+		p := gins(arm64.AASR, nil, &n1)
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(w)
+		p.From.Offset = w
 
 	case gc.TUINT8,
 		gc.TUINT16,
 		gc.TUINT32:
 		gins(optoas(gc.OMUL, t), &n2, &n1)
-		p := (*obj.Prog)(gins(arm64.ALSR, nil, &n1))
+		p := gins(arm64.ALSR, nil, &n1)
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(w)
+		p.From.Offset = w
 
 	case gc.TINT64,
 		gc.TUINT64:
-		if gc.Issigned[t.Etype] {
+		if t.IsSigned() {
 			gins(arm64.ASMULH, &n2, &n1)
 		} else {
 			gins(arm64.AUMULH, &n2, &n1)
@@ -311,14 +355,14 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
  *	res = nl >> nr
  */
 func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
-	a := int(optoas(op, nl.Type))
+	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) {
+		sc := uint64(nr.Int64())
+		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)
@@ -380,8 +424,8 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 	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] {
+		p1 := gc.Gbranch(optoas(gc.OLT, tcount), nil, +1)
+		if op == gc.ORSH && nl.Type.IsSigned() {
 			gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
 			gins(a, &n3, &n2)
 		} else {
@@ -406,15 +450,15 @@ func clearfat(nl *gc.Node) {
 		fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
 	}
 
-	w := uint64(uint64(nl.Type.Width))
+	w := 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
+	c := w % 8 // bytes
+	q := w / 8 // dwords
 
 	var r0 gc.Node
 	gc.Nodreg(&r0, gc.Types[gc.TUINT64], arm64.REGZERO)
@@ -440,7 +484,7 @@ func clearfat(nl *gc.Node) {
 		p.To.Type = obj.TYPE_MEM
 		p.To.Offset = 8
 		p.Scond = arm64.C_XPRE
-		pl := (*obj.Prog)(p)
+		pl := p
 
 		p = gcmp(arm64.ACMP, &dst, &end)
 		gc.Patch(gc.Gbranch(arm64.ABNE, nil, 0), pl)
@@ -453,7 +497,7 @@ func clearfat(nl *gc.Node) {
 		p := gins(arm64.ASUB, nil, &dst)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 8
-		f := (*gc.Node)(gc.Sysfunc("duffzero"))
+		f := gc.Sysfunc("duffzero")
 		p = gins(obj.ADUFFZERO, nil, f)
 		gc.Afunclit(&p.To, f)
 
@@ -486,7 +530,7 @@ func clearfat(nl *gc.Node) {
 func expandchecks(firstp *obj.Prog) {
 	var p1 *obj.Prog
 
-	for p := (*obj.Prog)(firstp); p != nil; p = p.Link {
+	for p := firstp; p != nil; p = p.Link {
 		if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
 			fmt.Printf("expandchecks: %v\n", p)
 		}
@@ -494,7 +538,7 @@ func expandchecks(firstp *obj.Prog) {
 			continue
 		}
 		if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
-			gc.Warnl(int(p.Lineno), "generated nil check")
+			gc.Warnl(p.Lineno, "generated nil check")
 		}
 		if p.From.Type != obj.TYPE_REG {
 			gc.Fatalf("invalid nil check %v\n", p)
diff --git a/src/cmd/compile/internal/arm64/gsubr.go b/src/cmd/compile/internal/arm64/gsubr.go
index c0aa45e..ddf2ed9 100644
--- a/src/cmd/compile/internal/arm64/gsubr.go
+++ b/src/cmd/compile/internal/arm64/gsubr.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -53,7 +53,7 @@ var resvd = []int{
  * generate
  *	as $c, n
  */
-func ginscon(as int, c int64, n2 *gc.Node) {
+func ginscon(as obj.As, c int64, n2 *gc.Node) {
 	var n1 gc.Node
 
 	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
@@ -77,7 +77,7 @@ func ginscon(as int, c int64, n2 *gc.Node) {
  * generate
  *	as n, $c (CMP)
  */
-func ginscon2(as int, n2 *gc.Node, c int64) {
+func ginscon2(as obj.As, n2 *gc.Node, c int64) {
 	var n1 gc.Node
 
 	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
@@ -103,7 +103,7 @@ func ginscon2(as int, n2 *gc.Node, c int64) {
 }
 
 func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
-	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
+	if t.IsInteger() && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
 		// Reverse comparison to place constant last.
 		op = gc.Brrev(op)
 		n1, n2 = n2, n1
@@ -114,8 +114,8 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 	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())
+	if t.IsInteger() && gc.Isconst(n2, gc.CTINT) {
+		ginscon2(optoas(gc.OCMP, t), &r1, n2.Int64())
 	} else {
 		gc.Regalloc(&r2, t, n2)
 		gc.Regalloc(&g2, n1.Type, &r2)
@@ -137,12 +137,12 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
  */
 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))
+		fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
 	}
 
 	ft := int(gc.Simsimtype(f.Type))
 	tt := int(gc.Simsimtype(t.Type))
-	cvt := (*gc.Type)(t.Type)
+	cvt := t.Type
 
 	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
 		gc.Complexmove(f, t)
@@ -151,7 +151,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 
 	// cannot have two memory operands
 	var r1 gc.Node
-	var a int
+	var a obj.As
 	if gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
 	}
@@ -214,7 +214,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
-		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong))
+		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
 
 		/*
 		 * integer copy and truncate
@@ -470,7 +470,7 @@ hard:
 // 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 {
+func gins(as obj.As, f, t *gc.Node) *obj.Prog {
 	if as >= obj.A_ARCHSPECIFIC {
 		if x, ok := f.IntLiteral(); ok {
 			ginscon(as, x, t)
@@ -490,7 +490,7 @@ func gins(as int, f, t *gc.Node) *obj.Prog {
  * generate one instruction:
  *	as f, t
  */
-func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
 	// TODO(austin): Add self-move test like in 6g (but be careful
 	// of truncation moves)
 
@@ -567,7 +567,7 @@ func raddr(n *gc.Node, p *obj.Prog) {
 	gc.Naddr(&a, n)
 	if a.Type != obj.TYPE_REG {
 		if n != nil {
-			gc.Fatalf("bad in raddr: %v", gc.Oconv(int(n.Op), 0))
+			gc.Fatalf("bad in raddr: %v", n.Op)
 		} else {
 			gc.Fatalf("bad in raddr: <null>")
 		}
@@ -577,9 +577,9 @@ func raddr(n *gc.Node, p *obj.Prog) {
 	}
 }
 
-func gcmp(as int, lhs *gc.Node, rhs *gc.Node) *obj.Prog {
+func gcmp(as obj.As, lhs *gc.Node, rhs *gc.Node) *obj.Prog {
 	if lhs.Op != gc.OREGISTER {
-		gc.Fatalf("bad operands to gcmp: %v %v", gc.Oconv(int(lhs.Op), 0), gc.Oconv(int(rhs.Op), 0))
+		gc.Fatalf("bad operands to gcmp: %v %v", lhs.Op, rhs.Op)
 	}
 
 	p := rawgins(as, rhs, nil)
@@ -590,7 +590,7 @@ func gcmp(as int, lhs *gc.Node, rhs *gc.Node) *obj.Prog {
 /*
  * return Axxx for Oxxx on type t.
  */
-func optoas(op gc.Op, t *gc.Type) int {
+func optoas(op gc.Op, t *gc.Type) obj.As {
 	if t == nil {
 		gc.Fatalf("optoas: t is nil")
 	}
@@ -619,10 +619,10 @@ func optoas(op gc.Op, t *gc.Type) int {
 		OSQRT_  = uint32(gc.OSQRT) << 16
 	)
 
-	a := int(obj.AXXX)
+	a := obj.AXXX
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
+		gc.Fatalf("optoas: no entry for op=%v type=%v", op, t)
 
 	case OEQ_ | gc.TBOOL,
 		OEQ_ | gc.TINT8,
@@ -890,18 +890,6 @@ func optoas(op gc.Op, t *gc.Type) int {
 		ORSH_ | 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 OHMUL_ | gc.TINT64:
 		a = arm64.ASMULH
 
@@ -987,7 +975,7 @@ func sudoclean() {
  * after successful sudoaddable,
  * to release the register used for a.
  */
-func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
+func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
 	// TODO(minux)
 
 	*a = obj.Addr{}
diff --git a/src/cmd/compile/internal/arm64/peep.go b/src/cmd/compile/internal/arm64/peep.go
index daa626f..e32c264 100644
--- a/src/cmd/compile/internal/arm64/peep.go
+++ b/src/cmd/compile/internal/arm64/peep.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -40,7 +40,7 @@ import (
 var gactive uint32
 
 func peep(firstp *obj.Prog) {
-	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	g := gc.Flowstart(firstp, nil)
 	if g == nil {
 		return
 	}
@@ -91,7 +91,7 @@ loop1:
 	 */
 	var p1 *obj.Prog
 	var r1 *gc.Flow
-	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
 		default:
@@ -130,7 +130,7 @@ loop1:
 	}
 
 	// MOVD $c, R'; ADD R', R (R' unused) -> ADD $c, R
-	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
 		default:
@@ -162,7 +162,7 @@ loop1:
 			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)
+			fmt.Printf("encoding $%d directly into %v in:\n%v\n%v\n", p.From.Offset, obj.Aconv(p1.As), p, p1)
 		}
 		p1.From.Type = obj.TYPE_CONST
 		p1.From = p.From
@@ -179,7 +179,7 @@ ret:
 }
 
 func excise(r *gc.Flow) {
-	p := (*obj.Prog)(r.Prog)
+	p := r.Prog
 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("%v ===delete===\n", p)
 	}
@@ -210,12 +210,12 @@ func regtyp(a *obj.Addr) bool {
  * 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)
+	p := r0.Prog
+	v1 := &p.From
 	if !regtyp(v1) {
 		return false
 	}
-	v2 := (*obj.Addr)(&p.To)
+	v2 := &p.To
 	if !regtyp(v2) {
 		return false
 	}
@@ -234,7 +234,7 @@ func subprop(r0 *gc.Flow) bool {
 		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)
+					copysub(&p.To, v1, v2, true)
 					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 {
@@ -245,17 +245,15 @@ func subprop(r0 *gc.Flow) bool {
 
 					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)
+						copysub(&p.From, v1, v2, true)
+						copysub1(p, v1, v2, true)
+						copysub(&p.To, v1, v2, true)
 						if gc.Debug['P'] != 0 {
 							fmt.Printf("%v\n", r.Prog)
 						}
 					}
 
-					t := int(int(v1.Reg))
-					v1.Reg = v2.Reg
-					v2.Reg = int16(t)
+					v1.Reg, v2.Reg = v2.Reg, v1.Reg
 					if gc.Debug['P'] != 0 {
 						fmt.Printf("%v last\n", r.Prog)
 					}
@@ -267,7 +265,7 @@ func subprop(r0 *gc.Flow) bool {
 		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 {
+		if copysub(&p.From, v1, v2, false) || copysub1(p, v1, v2, false) || copysub(&p.To, v1, v2, false) {
 			break
 		}
 	}
@@ -288,9 +286,9 @@ func subprop(r0 *gc.Flow) bool {
  *	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)
+	p := r0.Prog
+	v1 := &p.From
+	v2 := &p.To
 	if copyas(v1, v2) {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("eliminating self-move: %v\n", r0.Prog)
@@ -302,12 +300,12 @@ func copyprop(r0 *gc.Flow) bool {
 	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)
+	return copy1(v1, v2, r0.S1, false)
 }
 
 // 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 {
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
 	if uint32(r.Active) == gactive {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("act set; return 1\n")
@@ -317,27 +315,24 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 	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)
+		fmt.Printf("copy1 replace %v with %v f=%v\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
+		p := r.Prog
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("%v", p)
 		}
-		if f == 0 && gc.Uniqp(r) == nil {
+		if !f && gc.Uniqp(r) == nil {
 			// Multiple predecessors; conservatively
 			// assume v1 was set on other path
-			f = 1
+			f = true
 
 			if gc.Debug['P'] != 0 {
-				fmt.Printf("; merge; f=%d", f)
+				fmt.Printf("; merge; f=%v", f)
 			}
 		}
 
-		t = copyu(p, v2, nil)
-		switch t {
+		switch t := copyu(p, v2, nil); t {
 		case 2: /* rar, can't split */
 			if gc.Debug['P'] != 0 {
 				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
@@ -352,14 +347,14 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 		case 1, /* used, substitute */
 			4: /* use and set */
-			if f != 0 {
+			if f {
 				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)
+					fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				} else {
-					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+					fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				}
 				return false
 			}
@@ -382,12 +377,12 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 
-		if f == 0 {
-			t = copyu(p, v1, nil)
-			if f == 0 && (t == 2 || t == 3 || t == 4) {
-				f = 1
+		if !f {
+			t := copyu(p, v1, nil)
+			if t == 2 || t == 3 || t == 4 {
+				f = true
 				if gc.Debug['P'] != 0 {
-					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+					fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
 				}
 			}
 		}
@@ -401,7 +396,6 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 	}
-
 	return true
 }
 
@@ -429,7 +423,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 
 	switch p.As {
 	default:
-		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
 		return 2
 
 	case obj.ANOP, /* read p->from, write p->to */
@@ -466,13 +460,13 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		arm64.AFMOVD:
 		if p.Scond == 0 {
 			if s != nil {
-				if copysub(&p.From, v, s, 1) != 0 {
+				if copysub(&p.From, v, s, true) {
 					return 1
 				}
 
 				// Update only indirect uses of v in p->to
 				if !copyas(&p.To, v) {
-					if copysub(&p.To, v, s, 1) != 0 {
+					if copysub(&p.To, v, s, true) {
 						return 1
 					}
 				}
@@ -510,7 +504,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 			}
 
 			if s != nil {
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 				return 0
@@ -524,7 +518,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 				return 2
 			}
 			if s != nil {
-				if copysub(&p.From, v, s, 1) != 0 {
+				if copysub(&p.From, v, s, true) {
 					return 1
 				}
 				return 0
@@ -540,10 +534,13 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		return 0
 
 	case arm64.AADD, /* read p->from, read p->reg, write p->to */
+		arm64.AADDS,
 		arm64.ASUB,
+		arm64.AADC,
 		arm64.AAND,
 		arm64.AORR,
 		arm64.AEOR,
+		arm64.AROR,
 		arm64.AMUL,
 		arm64.ASMULL,
 		arm64.AUMULL,
@@ -563,16 +560,16 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		arm64.AFDIVD,
 		arm64.AFDIVS:
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
-			if copysub1(p, v, s, 1) != 0 {
+			if copysub1(p, v, s, true) {
 				return 1
 			}
 
 			// Update only indirect uses of v in p->to
 			if !copyas(&p.To, v) {
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 			}
@@ -624,10 +621,13 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		arm64.AFCMPD,
 		arm64.AFCMPS:
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
+				return 1
+			}
+			if copysub1(p, v, s, true) {
 				return 1
 			}
-			return copysub1(p, v, s, 1)
+			return 0
 		}
 
 		if copyau(&p.From, v) {
@@ -640,7 +640,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 
 	case arm64.AB: /* read p->to */
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -666,7 +666,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		}
 
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -717,23 +717,16 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 	}
 }
 
-// copyas returns 1 if a and v address the same register.
+// copyas returns true 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
+	return regtyp(v) && a.Type == v.Type && a.Reg == v.Reg
 }
 
-// copyau returns 1 if a either directly or indirectly addresses the
+// copyau returns true if a either directly or indirectly addresses the
 // same register as v.
 //
 // If a is the from operand, this means this operation reads the
@@ -754,37 +747,30 @@ func copyau(a *obj.Addr, v *obj.Addr) bool {
 	return false
 }
 
-// copyau1 returns 1 if p->reg references the same register as v and v
+// copyau1 returns true 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
+	return regtyp(v) && v.Reg != 0 && p.Reg == v.Reg
 }
 
-// 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
-		}
+// copysub replaces v with s in a if f==true or indicates it if could if f==false.
+// Returns true on failure to substitute (it always succeeds on arm64).
+// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
+	if f && copyau(a, v) {
+		a.Reg = s.Reg
 	}
-	return 0
+	return false
 }
 
-// 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
-		}
+// copysub1 replaces v with s in p1->reg if f==true or indicates if it could if f==false.
+// Returns true on failure to substitute (it always succeeds on arm64).
+// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
+func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f bool) bool {
+	if f && copyau1(p1, v) {
+		p1.Reg = s.Reg
 	}
-	return 0
+	return false
 }
 
 func sameaddr(a *obj.Addr, v *obj.Addr) bool {
diff --git a/src/cmd/compile/internal/arm64/prog.go b/src/cmd/compile/internal/arm64/prog.go
index a8e8bc5..d504d0f 100644
--- a/src/cmd/compile/internal/arm64/prog.go
+++ b/src/cmd/compile/internal/arm64/prog.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -24,7 +24,7 @@ const (
 // 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{
+var progtable = [arm64.ALAST & obj.AMask]obj.ProgInfo{
 	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
 	obj.ATEXT:     {Flags: gc.Pseudo},
 	obj.AFUNCDATA: {Flags: gc.Pseudo},
@@ -38,101 +38,104 @@ var progtable = [arm64.ALAST]obj.ProgInfo{
 
 	// NOP is an internal no-op that also stands
 	// for USED and SET annotations, not the Power opcode.
-	obj.ANOP:    {Flags: gc.LeftRead | gc.RightWrite},
-	arm64.AHINT: {Flags: gc.OK},
+	obj.ANOP:                {Flags: gc.LeftRead | gc.RightWrite},
+	arm64.AHINT & obj.AMask: {Flags: gc.OK},
 
 	// Integer
-	arm64.AADD:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.ASUB:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.ANEG:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AAND:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AORR:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AEOR:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AMUL:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.ASMULL: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AUMULL: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.ASMULH: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AUMULH: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.ASDIV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AUDIV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.ALSL:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.ALSR:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AASR:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.ACMP:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
+	arm64.AADD & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.ASUB & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.ANEG & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AAND & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AORR & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AEOR & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AMUL & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.ASMULL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AUMULL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.ASMULH & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AUMULH & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.ASDIV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AUDIV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.ALSL & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.ALSR & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AASR & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.ACMP & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
+	arm64.AADC & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.UseCarry},
+	arm64.AROR & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AADDS & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.SetCarry},
 
 	// Floating point.
-	arm64.AFADDD:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AFADDS:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AFSUBD:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AFSUBS:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AFNEGD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
-	arm64.AFNEGS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite},
-	arm64.AFSQRTD: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
-	arm64.AFMULD:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AFMULS:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AFDIVD:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AFDIVS:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	arm64.AFCMPD:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead},
-	arm64.AFCMPS:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead},
+	arm64.AFADDD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AFADDS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AFSUBD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AFSUBS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AFNEGD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
+	arm64.AFNEGS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite},
+	arm64.AFSQRTD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
+	arm64.AFMULD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AFMULS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AFDIVD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AFDIVS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	arm64.AFCMPD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead},
+	arm64.AFCMPS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead},
 
 	// float -> integer
-	arm64.AFCVTZSD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AFCVTZSS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AFCVTZSDW: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AFCVTZSSW: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AFCVTZUD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AFCVTZUS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AFCVTZUDW: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AFCVTZUSW: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTZSD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTZSS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTZSDW & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTZSSW & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTZUD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTZUS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTZUDW & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTZUSW & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
 
 	// float -> float
-	arm64.AFCVTSD: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AFCVTDS: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTSD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AFCVTDS & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
 
 	// integer -> float
-	arm64.ASCVTFD:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.ASCVTFS:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.ASCVTFWD: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.ASCVTFWS: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AUCVTFD:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AUCVTFS:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AUCVTFWD: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	arm64.AUCVTFWS: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.ASCVTFD & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.ASCVTFS & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.ASCVTFWD & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.ASCVTFWS & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AUCVTFD & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AUCVTFS & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AUCVTFWD & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	arm64.AUCVTFWS & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
 
 	// Moves
-	arm64.AMOVB:  {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	arm64.AMOVBU: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	arm64.AMOVH:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	arm64.AMOVHU: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	arm64.AMOVW:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	arm64.AMOVWU: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	arm64.AMOVD:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	arm64.AFMOVS: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	arm64.AFMOVD: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+	arm64.AMOVB & obj.AMask:  {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	arm64.AMOVBU & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	arm64.AMOVH & obj.AMask:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	arm64.AMOVHU & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	arm64.AMOVW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	arm64.AMOVWU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	arm64.AMOVD & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
+	arm64.AFMOVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	arm64.AFMOVD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
 
 	// Jumps
-	arm64.AB:      {Flags: gc.Jump | gc.Break},
-	arm64.ABL:     {Flags: gc.Call},
-	arm64.ABEQ:    {Flags: gc.Cjmp},
-	arm64.ABNE:    {Flags: gc.Cjmp},
-	arm64.ABGE:    {Flags: gc.Cjmp},
-	arm64.ABLT:    {Flags: gc.Cjmp},
-	arm64.ABGT:    {Flags: gc.Cjmp},
-	arm64.ABLE:    {Flags: gc.Cjmp},
-	arm64.ABLO:    {Flags: gc.Cjmp},
-	arm64.ABLS:    {Flags: gc.Cjmp},
-	arm64.ABHI:    {Flags: gc.Cjmp},
-	arm64.ABHS:    {Flags: gc.Cjmp},
-	arm64.ACBZ:    {Flags: gc.Cjmp},
-	arm64.ACBNZ:   {Flags: gc.Cjmp},
-	obj.ARET:      {Flags: gc.Break},
-	obj.ADUFFZERO: {Flags: gc.Call},
-	obj.ADUFFCOPY: {Flags: gc.Call},
+	arm64.AB & obj.AMask:    {Flags: gc.Jump | gc.Break},
+	arm64.ABL & obj.AMask:   {Flags: gc.Call},
+	arm64.ABEQ & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ABNE & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ABGE & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ABLT & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ABGT & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ABLE & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ABLO & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ABLS & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ABHI & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ABHS & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ACBZ & obj.AMask:  {Flags: gc.Cjmp},
+	arm64.ACBNZ & obj.AMask: {Flags: gc.Cjmp},
+	obj.ARET:                {Flags: gc.Break},
+	obj.ADUFFZERO:           {Flags: gc.Call},
+	obj.ADUFFCOPY:           {Flags: gc.Call},
 }
 
 func proginfo(p *obj.Prog) {
 	info := &p.Info
-	*info = progtable[p.As]
+	*info = progtable[p.As&obj.AMask]
 	if info.Flags == 0 {
 		gc.Fatalf("proginfo: unknown instruction %v", p)
 	}
diff --git a/src/cmd/compile/internal/arm64/reg.go b/src/cmd/compile/internal/arm64/reg.go
index b84359a..6e24dc2 100644
--- a/src/cmd/compile/internal/arm64/reg.go
+++ b/src/cmd/compile/internal/arm64/reg.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -113,7 +113,7 @@ func regnames(n *int) []string {
 
 func excludedregs() uint64 {
 	// Exclude registers with fixed functions
-	regbits := uint64(RtoB(arm64.REGRT1) | RtoB(arm64.REGRT2) | RtoB(arm64.REGPR))
+	regbits := RtoB(arm64.REGRT1) | RtoB(arm64.REGRT2) | RtoB(arm64.REGPR)
 
 	// Exclude R26 - R31.
 	for r := arm64.REGMAX + 1; r <= arm64.REGZERO; r++ {
diff --git a/src/cmd/compile/internal/big/arith_decl.go b/src/cmd/compile/internal/big/arith_decl.go
index fe13577..d60b7f9 100644
--- a/src/cmd/compile/internal/big/arith_decl.go
+++ b/src/cmd/compile/internal/big/arith_decl.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/compile/internal/big/arith_test.go b/src/cmd/compile/internal/big/arith_test.go
index f46a494..7d2f69a 100644
--- a/src/cmd/compile/internal/big/arith_test.go
+++ b/src/cmd/compile/internal/big/arith_test.go
@@ -158,21 +158,6 @@ var sumVW = []argVW{
 	{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},
@@ -442,7 +427,7 @@ func benchmarkBitLenN(b *testing.B, nbits uint) {
 	}
 }
 
-// Individual bitLen tests.  Numbers chosen to examine both sides
+// 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) }
diff --git a/src/cmd/compile/internal/big/example_rat_test.go b/src/cmd/compile/internal/big/example_rat_test.go
new file mode 100644
index 0000000..ef06497
--- /dev/null
+++ b/src/cmd/compile/internal/big/example_rat_test.go
@@ -0,0 +1,65 @@
+// Copyright 2015 The Go Authors. 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"
+)
+
+// Use the classic continued fraction for e
+//     e = [1; 0, 1, 1, 2, 1, 1, ... 2n, 1, 1, ...]
+// i.e., for the nth term, use
+//     1          if   n mod 3 != 1
+//  (n-1)/3 * 2   if   n mod 3 == 1
+func recur(n, lim int64) *big.Rat {
+	term := new(big.Rat)
+	if n%3 != 1 {
+		term.SetInt64(1)
+	} else {
+		term.SetInt64((n - 1) / 3 * 2)
+	}
+
+	if n > lim {
+		return term
+	}
+
+	// Directly initialize frac as the fractional
+	// inverse of the result of recur.
+	frac := new(big.Rat).Inv(recur(n+1, lim))
+
+	return term.Add(term, frac)
+}
+
+// This example demonstrates how to use big.Rat to compute the
+// first 15 terms in the sequence of rational convergents for
+// the constant e (base of natural logarithm).
+func Example_eConvergents() {
+	for i := 1; i <= 15; i++ {
+		r := recur(0, int64(i))
+
+		// Print r both as a fraction and as a floating-point number.
+		// Since big.Rat implements fmt.Formatter, we can use %-13s to
+		// get a left-aligned string representation of the fraction.
+		fmt.Printf("%-13s = %s\n", r, r.FloatString(8))
+	}
+
+	// Output:
+	// 2/1           = 2.00000000
+	// 3/1           = 3.00000000
+	// 8/3           = 2.66666667
+	// 11/4          = 2.75000000
+	// 19/7          = 2.71428571
+	// 87/32         = 2.71875000
+	// 106/39        = 2.71794872
+	// 193/71        = 2.71830986
+	// 1264/465      = 2.71827957
+	// 1457/536      = 2.71828358
+	// 2721/1001     = 2.71828172
+	// 23225/8544    = 2.71828184
+	// 25946/9545    = 2.71828182
+	// 49171/18089   = 2.71828183
+	// 517656/190435 = 2.71828183
+}
diff --git a/src/cmd/compile/internal/big/float.go b/src/cmd/compile/internal/big/float.go
index b1c748c..4b8ad38 100644
--- a/src/cmd/compile/internal/big/float.go
+++ b/src/cmd/compile/internal/big/float.go
@@ -392,15 +392,13 @@ func (z *Float) round(sbit uint) {
 	// 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
+	bits := m * _W           // present mantissa bits; bits > 0
 	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
@@ -415,111 +413,77 @@ func (z *Float) round(sbit uint) {
 
 	// 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
+	rbit := z.mant.bit(r) & 1    // rounding bit; be safe and ensure it's a single bit
 	if sbit == 0 {
+		// TODO(gri) if rbit != 0 we don't need to compute sbit for some rounding modes (optimization)
 		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
-		}
-	}
+	sbit &= 1 // be safe and ensure it's a single bit
 
 	// cut off extra words
+	n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision
 	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
+	// determine number of trailing zero bits (ntz) and compute lsb mask of mantissa's least-significant word
+	ntz := n*_W - z.prec // 0 <= ntz < _W
+	lsb := Word(1) << ntz
+
+	// round if result is inexact
+	if rbit|sbit != 0 {
+		// Make rounding decision: The result mantissa is truncated ("rounded down")
+		// by default. Decide if we need to increment, or "round up", the (unsigned)
+		// mantissa.
+		inc := false
+		switch z.mode {
+		case ToNegativeInf:
+			inc = z.neg
+		case ToZero:
+			// nothing to do
+		case ToNearestEven:
+			inc = rbit != 0 && (sbit != 0 || z.mant[0]&lsb != 0)
+		case ToNearestAway:
+			inc = rbit != 0
+		case AwayFromZero:
+			inc = true
+		case ToPositiveInf:
+			inc = !z.neg
+		default:
+			panic("unreachable")
 		}
 
-	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 {
+		// A positive result (!z.neg) is Above the exact result if we increment,
+		// and it's Below if we truncate (Exact results require no rounding).
+		// For a negative result (z.neg) it is exactly the opposite.
+		z.acc = makeAcc(inc != z.neg)
+
+		if inc {
+			// add 1 to mantissa
+			if addVW(z.mant, z.mant, lsb) != 0 {
+				// mantissa overflow => adjust exponent
+				if z.exp >= MaxExp {
+					// exponent overflow
+					z.form = inf
+					return
+				}
 				z.exp++
-			} else {
-				// exponent overflow
-				z.acc = makeAcc(!z.neg)
-				z.form = inf
-				return
+				// adjust mantissa: divide by 2 to compensate for exponent adjustment
+				shrVU(z.mant, z.mant, 1)
+				// set msb == carry == 1 from the mantissa overflow above
+				const msb = 1 << (_W - 1)
+				z.mant[n-1] |= msb
 			}
 		}
-		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 {
@@ -874,21 +838,43 @@ func (x *Float) Float32() (float32, Accuracy) {
 			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
+		// Float mantissa m is 0.5 <= m < 1.0; compute exponent e for float32 mantissa.
+		e := x.exp - 1 // exponent for normal mantissa m with 1.0 <= m < 2.0
 
-		// If the exponent is too small, we may have a denormal number
-		// in which case we have fewer mantissa bits available: reduce
-		// precision accordingly.
+		// Compute precision p for float32 mantissa.
+		// If the exponent is too small, we have a denormal number before
+		// rounding and fewer than p mantissa bits of precision available
+		// (the exponent remains fixed but the mantissa gets shifted right).
+		p := mbits + 1 // precision of normal float
 		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
+			// recompute precision
+			p = mbits + 1 - emin + int(e)
+			// If p == 0, the mantissa of x is shifted so much to the right
+			// that its msb falls immediately to the right of the float32
+			// mantissa space. In other words, if the smallest denormal is
+			// considered "1.0", for p == 0, the mantissa value m is >= 0.5.
+			// If m > 0.5, it is rounded up to 1.0; i.e., the smallest denormal.
+			// If m == 0.5, it is rounded down to even, i.e., 0.0.
+			// If p < 0, the mantissa value m is <= "0.25" which is never rounded up.
+			if p < 0 /* m <= 0.25 */ || p == 0 && x.mant.sticky(uint(len(x.mant))*_W-1) == 0 /* m == 0.5 */ {
+				// underflow to ±0
+				if x.neg {
+					var z float32
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// otherwise, round up
+			// We handle p == 0 explicitly because it's easy and because
+			// Float.round doesn't support rounding to 0 bits of precision.
+			if p == 0 {
+				if x.neg {
+					return -math.SmallestNonzeroFloat32, Below
+				}
+				return math.SmallestNonzeroFloat32, Above
 			}
 		}
+		// p > 0
 
 		// round
 		var r Float
@@ -898,12 +884,8 @@ func (x *Float) Float32() (float32, Accuracy) {
 
 		// 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 {
+		// If the exponent is too large, also overflow to ±Inf.
+		if r.form == inf || e > emax {
 			// overflow
 			if x.neg {
 				return float32(math.Inf(-1)), Below
@@ -921,17 +903,12 @@ func (x *Float) Float32() (float32, Accuracy) {
 		// 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)
+			// denormal number: recompute precision
+			// Since rounding may have at best increased precision
+			// and we have eliminated p <= 0 early, we know p > 0.
+			// bexp == 0 for denormals
+			p = mbits + 1 - emin + int(e)
+			mant = msb32(r.mant) >> uint(fbits-p)
 		} else {
 			// normal number: emin <= e <= emax
 			bexp = uint32(e+bias) << mbits
@@ -981,21 +958,43 @@ func (x *Float) Float64() (float64, Accuracy) {
 			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
+		// Float mantissa m is 0.5 <= m < 1.0; compute exponent e for float64 mantissa.
+		e := x.exp - 1 // exponent for normal mantissa m with 1.0 <= m < 2.0
 
-		// If the exponent is too small, we may have a denormal number
-		// in which case we have fewer mantissa bits available: reduce
-		// precision accordingly.
+		// Compute precision p for float64 mantissa.
+		// If the exponent is too small, we have a denormal number before
+		// rounding and fewer than p mantissa bits of precision available
+		// (the exponent remains fixed but the mantissa gets shifted right).
+		p := mbits + 1 // precision of normal float
 		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
+			// recompute precision
+			p = mbits + 1 - emin + int(e)
+			// If p == 0, the mantissa of x is shifted so much to the right
+			// that its msb falls immediately to the right of the float64
+			// mantissa space. In other words, if the smallest denormal is
+			// considered "1.0", for p == 0, the mantissa value m is >= 0.5.
+			// If m > 0.5, it is rounded up to 1.0; i.e., the smallest denormal.
+			// If m == 0.5, it is rounded down to even, i.e., 0.0.
+			// If p < 0, the mantissa value m is <= "0.25" which is never rounded up.
+			if p < 0 /* m <= 0.25 */ || p == 0 && x.mant.sticky(uint(len(x.mant))*_W-1) == 0 /* m == 0.5 */ {
+				// underflow to ±0
+				if x.neg {
+					var z float64
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// otherwise, round up
+			// We handle p == 0 explicitly because it's easy and because
+			// Float.round doesn't support rounding to 0 bits of precision.
+			if p == 0 {
+				if x.neg {
+					return -math.SmallestNonzeroFloat64, Below
+				}
+				return math.SmallestNonzeroFloat64, Above
 			}
 		}
+		// p > 0
 
 		// round
 		var r Float
@@ -1005,17 +1004,13 @@ func (x *Float) Float64() (float64, Accuracy) {
 
 		// 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 {
+		// If the exponent is too large, also overflow to ±Inf.
+		if r.form == inf || e > emax {
 			// overflow
 			if x.neg {
-				return math.Inf(-1), Below
+				return float64(math.Inf(-1)), Below
 			}
-			return math.Inf(+1), Above
+			return float64(math.Inf(+1)), Above
 		}
 		// e <= emax
 
@@ -1028,17 +1023,12 @@ func (x *Float) Float64() (float64, Accuracy) {
 		// 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)
+			// denormal number: recompute precision
+			// Since rounding may have at best increased precision
+			// and we have eliminated p <= 0 early, we know p > 0.
+			// bexp == 0 for denormals
+			p = mbits + 1 - emin + int(e)
+			mant = msb64(r.mant) >> uint(fbits-p)
 		} else {
 			// normal number: emin <= e <= emax
 			bexp = uint64(e+bias) << mbits
@@ -1427,7 +1417,7 @@ func (z *Float) Add(x, y *Float) *Float {
 	}
 
 	if x.form == finite && y.form == finite {
-		// x + y (commom case)
+		// x + y (common case)
 		z.neg = x.neg
 		if x.neg == y.neg {
 			// x + y == x + y
diff --git a/src/cmd/compile/internal/big/float_test.go b/src/cmd/compile/internal/big/float_test.go
index d3b214b..464619b 100644
--- a/src/cmd/compile/internal/big/float_test.go
+++ b/src/cmd/compile/internal/big/float_test.go
@@ -829,7 +829,7 @@ func TestFloatFloat32(t *testing.T) {
 	}{
 		{"0", 0, Exact},
 
-		// underflow
+		// underflow to zero
 		{"1e-1000", 0, Below},
 		{"0x0.000002p-127", 0, Below},
 		{"0x.0000010p-126", 0, Below},
@@ -843,6 +843,46 @@ func TestFloatFloat32(t *testing.T) {
 		{"1p-149", math.SmallestNonzeroFloat32, Exact},
 		{"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal
 
+		// special denormal cases (see issues 14553, 14651)
+		{"0x0.0000001p-126", math.Float32frombits(0x00000000), Below}, // underflow to zero
+		{"0x0.0000008p-126", math.Float32frombits(0x00000000), Below}, // underflow to zero
+		{"0x0.0000010p-126", math.Float32frombits(0x00000000), Below}, // rounded down to even
+		{"0x0.0000011p-126", math.Float32frombits(0x00000001), Above}, // rounded up to smallest denormal
+		{"0x0.0000018p-126", math.Float32frombits(0x00000001), Above}, // rounded up to smallest denormal
+
+		{"0x1.0000000p-149", math.Float32frombits(0x00000001), Exact}, // smallest denormal
+		{"0x0.0000020p-126", math.Float32frombits(0x00000001), Exact}, // smallest denormal
+		{"0x0.fffffe0p-126", math.Float32frombits(0x007fffff), Exact}, // largest denormal
+		{"0x1.0000000p-126", math.Float32frombits(0x00800000), Exact}, // smallest normal
+
+		{"0x0.8p-149", math.Float32frombits(0x000000000), Below}, // rounded down to even
+		{"0x0.9p-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+		{"0x0.ap-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+		{"0x0.bp-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+		{"0x0.cp-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+
+		{"0x1.0p-149", math.Float32frombits(0x000000001), Exact}, // smallest denormal
+		{"0x1.7p-149", math.Float32frombits(0x000000001), Below},
+		{"0x1.8p-149", math.Float32frombits(0x000000002), Above},
+		{"0x1.9p-149", math.Float32frombits(0x000000002), Above},
+
+		{"0x2.0p-149", math.Float32frombits(0x000000002), Exact},
+		{"0x2.8p-149", math.Float32frombits(0x000000002), Below}, // rounded down to even
+		{"0x2.9p-149", math.Float32frombits(0x000000003), Above},
+
+		{"0x3.0p-149", math.Float32frombits(0x000000003), Exact},
+		{"0x3.7p-149", math.Float32frombits(0x000000003), Below},
+		{"0x3.8p-149", math.Float32frombits(0x000000004), Above}, // rounded up to even
+
+		{"0x4.0p-149", math.Float32frombits(0x000000004), Exact},
+		{"0x4.8p-149", math.Float32frombits(0x000000004), Below}, // rounded down to even
+		{"0x4.9p-149", math.Float32frombits(0x000000005), Above},
+
+		// specific case from issue 14553
+		{"0x7.7p-149", math.Float32frombits(0x000000007), Below},
+		{"0x7.8p-149", math.Float32frombits(0x000000008), Above},
+		{"0x7.9p-149", math.Float32frombits(0x000000008), Above},
+
 		// normals
 		{"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal
 		{"1p-126", math.Float32frombits(0x00800000), Exact},         // smallest normal
@@ -881,7 +921,7 @@ func TestFloatFloat32(t *testing.T) {
 			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)
+				t.Errorf("%s: got %g (%#08x, %s); want %g (%#08x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
 			}
 
 			// test that x.SetFloat64(float64(f)).Float32() == f
@@ -903,18 +943,48 @@ func TestFloatFloat64(t *testing.T) {
 	}{
 		{"0", 0, Exact},
 
-		// underflow
+		// underflow to zero
 		{"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
+		{"0x0.00000000000010p-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
 
+		// special denormal cases (see issues 14553, 14651)
+		{"0x0.00000000000001p-1022", math.Float64frombits(0x00000000000000000), Below}, // underflow to zero
+		{"0x0.00000000000004p-1022", math.Float64frombits(0x00000000000000000), Below}, // underflow to zero
+		{"0x0.00000000000008p-1022", math.Float64frombits(0x00000000000000000), Below}, // rounded down to even
+		{"0x0.00000000000009p-1022", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+		{"0x0.0000000000000ap-1022", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+
+		{"0x0.8p-1074", math.Float64frombits(0x00000000000000000), Below}, // rounded down to even
+		{"0x0.9p-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+		{"0x0.ap-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+		{"0x0.bp-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+		{"0x0.cp-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+
+		{"0x1.0p-1074", math.Float64frombits(0x00000000000000001), Exact},
+		{"0x1.7p-1074", math.Float64frombits(0x00000000000000001), Below},
+		{"0x1.8p-1074", math.Float64frombits(0x00000000000000002), Above},
+		{"0x1.9p-1074", math.Float64frombits(0x00000000000000002), Above},
+
+		{"0x2.0p-1074", math.Float64frombits(0x00000000000000002), Exact},
+		{"0x2.8p-1074", math.Float64frombits(0x00000000000000002), Below}, // rounded down to even
+		{"0x2.9p-1074", math.Float64frombits(0x00000000000000003), Above},
+
+		{"0x3.0p-1074", math.Float64frombits(0x00000000000000003), Exact},
+		{"0x3.7p-1074", math.Float64frombits(0x00000000000000003), Below},
+		{"0x3.8p-1074", math.Float64frombits(0x00000000000000004), Above}, // rounded up to even
+
+		{"0x4.0p-1074", math.Float64frombits(0x00000000000000004), Exact},
+		{"0x4.8p-1074", math.Float64frombits(0x00000000000000004), Below}, // rounded down to even
+		{"0x4.9p-1074", math.Float64frombits(0x00000000000000005), Above},
+
 		// normals
 		{"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal
 		{"1p-1022", math.Float64frombits(0x0010000000000000), Exact},                 // smallest normal
@@ -958,7 +1028,7 @@ func TestFloatFloat64(t *testing.T) {
 			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)
+				t.Errorf("%s: got %g (%#016x, %s); want %g (%#016x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
 			}
 
 			// test that x.SetFloat64(f).Float64() == f
diff --git a/src/cmd/compile/internal/big/floatconv.go b/src/cmd/compile/internal/big/floatconv.go
index 37d5c06..a884df6 100644
--- a/src/cmd/compile/internal/big/floatconv.go
+++ b/src/cmd/compile/internal/big/floatconv.go
@@ -85,7 +85,7 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
 	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.
+		// Adjust relevant exponent accordingly.
 		d := int64(fcount)
 		switch b {
 		case 10:
diff --git a/src/math/big/floatmarsh.go b/src/cmd/compile/internal/big/floatmarsh.go
similarity index 100%
copy from src/math/big/floatmarsh.go
copy to src/cmd/compile/internal/big/floatmarsh.go
diff --git a/src/math/big/floatmarsh_test.go b/src/cmd/compile/internal/big/floatmarsh_test.go
similarity index 100%
copy from src/math/big/floatmarsh_test.go
copy to src/cmd/compile/internal/big/floatmarsh_test.go
diff --git a/src/cmd/compile/internal/big/ftoa.go b/src/cmd/compile/internal/big/ftoa.go
index c5cdb5e..624ea5e 100644
--- a/src/cmd/compile/internal/big/ftoa.go
+++ b/src/cmd/compile/internal/big/ftoa.go
@@ -333,9 +333,9 @@ func (x *Float) fmtB(buf []byte) []byte {
 	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.
+// 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,
+// and 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 {
@@ -374,12 +374,11 @@ func min(x, y int) int {
 }
 
 // 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'.
+// formats for floating-point numbers ('b', 'e', 'E', 'f', 'F',
+// 'g', 'G') as well as 'p' and 'v'. See (*Float).Text for the
+// interpretation of '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
+// in digits, the output field width, as well as the format flags
 // '+' and ' ' for sign control, '0' for space or zero padding,
 // and '-' for left or right justification. See the fmt package
 // for details.
diff --git a/src/cmd/compile/internal/big/intconv.go b/src/cmd/compile/internal/big/intconv.go
index 56a75f8..daf674a 100644
--- a/src/cmd/compile/internal/big/intconv.go
+++ b/src/cmd/compile/internal/big/intconv.go
@@ -52,16 +52,16 @@ func writeMultiple(s fmt.State, text string, count int) {
 	}
 }
 
-// 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).
+// Format implements 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.
+// flags 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 '-' for left or right
+// justification.
 //
 func (x *Int) Format(s fmt.State, ch rune) {
 	// determine base
diff --git a/src/cmd/compile/internal/big/intmarsh.go b/src/cmd/compile/internal/big/intmarsh.go
new file mode 100644
index 0000000..4ff57b6
--- /dev/null
+++ b/src/cmd/compile/internal/big/intmarsh.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 implements encoding/decoding of Ints.
+
+package big
+
+import "fmt"
+
+// 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
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (x *Int) MarshalText() (text []byte, err error) {
+	if x == nil {
+		return []byte("<nil>"), nil
+	}
+	return x.abs.itoa(x.neg, 10), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (z *Int) UnmarshalText(text []byte) error {
+	// TODO(gri): get rid of the []byte/string conversion
+	if _, ok := z.SetString(string(text), 0); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+	}
+	return nil
+}
+
+// The JSON marshallers are only here for API backward compatibility
+// (programs that explicitly look for these two methods). JSON works
+// fine with the TextMarshaler only.
+
+// MarshalJSON implements the json.Marshaler interface.
+func (x *Int) MarshalJSON() ([]byte, error) {
+	return x.MarshalText()
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (z *Int) UnmarshalJSON(text []byte) error {
+	return z.UnmarshalText(text)
+}
diff --git a/src/cmd/compile/internal/big/intmarsh_test.go b/src/cmd/compile/internal/big/intmarsh_test.go
new file mode 100644
index 0000000..f82956c
--- /dev/null
+++ b/src/cmd/compile/internal/big/intmarsh_test.go
@@ -0,0 +1,121 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+	"bytes"
+	"encoding/gob"
+	"encoding/json"
+	"encoding/xml"
+	"testing"
+)
+
+var encodingTests = []string{
+	"0",
+	"1",
+	"2",
+	"10",
+	"1000",
+	"1234567890",
+	"298472983472983471903246121093472394872319615612417471234712061",
+}
+
+func TestIntGobEncoding(t *testing.T) {
+	var medium bytes.Buffer
+	enc := gob.NewEncoder(&medium)
+	dec := gob.NewDecoder(&medium)
+	for _, test := range encodingTests {
+		for _, sign := range []string{"", "+", "-"} {
+			x := sign + test
+			medium.Reset() // empty buffer for each test case (in case of failures)
+			var tx Int
+			tx.SetString(x, 10)
+			if err := enc.Encode(&tx); err != nil {
+				t.Errorf("encoding of %s failed: %s", &tx, err)
+				continue
+			}
+			var rx Int
+			if err := dec.Decode(&rx); err != nil {
+				t.Errorf("decoding of %s failed: %s", &tx, err)
+				continue
+			}
+			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.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out)
+	}
+}
+
+func TestIntJSONEncoding(t *testing.T) {
+	for _, test := range encodingTests {
+		for _, sign := range []string{"", "+", "-"} {
+			x := sign + test
+			var tx Int
+			tx.SetString(x, 10)
+			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 TestIntXMLEncoding(t *testing.T) {
+	for _, test := range encodingTests {
+		for _, sign := range []string{"", "+", "-"} {
+			x := sign + test
+			var tx Int
+			tx.SetString(x, 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)
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/nat.go b/src/cmd/compile/internal/big/nat.go
index 79cf6e0..7668b64 100644
--- a/src/cmd/compile/internal/big/nat.go
+++ b/src/cmd/compile/internal/big/nat.go
@@ -647,7 +647,7 @@ 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
+	// 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
@@ -1018,7 +1018,7 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
 		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
+				// gain. Use go test -bench=".*" in crypto/rsa
 				// to check performance before making changes.
 				zz = zz.mul(z, z)
 				zz, z = z, zz
diff --git a/src/cmd/compile/internal/big/rat.go b/src/cmd/compile/internal/big/rat.go
index 2cd9ed0..56ce33d 100644
--- a/src/cmd/compile/internal/big/rat.go
+++ b/src/cmd/compile/internal/big/rat.go
@@ -63,7 +63,7 @@ func (z *Rat) SetFloat64(f float64) *Rat {
 
 // 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.
+// 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 (
@@ -161,7 +161,7 @@ func quotToFloat32(a, b nat) (f float32, exact bool) {
 
 // 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.
+// 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 (
diff --git a/src/cmd/compile/internal/big/ratconv.go b/src/cmd/compile/internal/big/ratconv.go
index 4566ff4..57df124 100644
--- a/src/cmd/compile/internal/big/ratconv.go
+++ b/src/cmd/compile/internal/big/ratconv.go
@@ -15,7 +15,7 @@ import (
 )
 
 func ratTok(ch rune) bool {
-	return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+	return strings.ContainsRune("+-/0123456789.eE", ch)
 }
 
 // Scan is a support routine for fmt.Scanner. It accepts the formats
@@ -25,7 +25,7 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
 	if err != nil {
 		return err
 	}
-	if strings.IndexRune("efgEFGv", ch) < 0 {
+	if !strings.ContainsRune("efgEFGv", ch) {
 		return errors.New("Rat.Scan: invalid verb")
 	}
 	if _, ok := z.SetString(string(tok)); !ok {
diff --git a/src/cmd/compile/internal/big/ratconv_test.go b/src/cmd/compile/internal/big/ratconv_test.go
index da2fdab..17bda47 100644
--- a/src/cmd/compile/internal/big/ratconv_test.go
+++ b/src/cmd/compile/internal/big/ratconv_test.go
@@ -137,7 +137,7 @@ func TestFloatString(t *testing.T) {
 	}
 }
 
-// Test inputs to Rat.SetString.  The prefix "long:" causes the test
+// 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.
diff --git a/src/cmd/compile/internal/big/ratmarsh.go b/src/cmd/compile/internal/big/ratmarsh.go
new file mode 100644
index 0000000..b82e8d4
--- /dev/null
+++ b/src/cmd/compile/internal/big/ratmarsh.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.
+
+// This file implements encoding/decoding of Rats.
+
+package big
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+)
+
+// 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 (x *Rat) MarshalText() (text []byte, err error) {
+	// TODO(gri): get rid of the []byte/string conversion
+	return []byte(x.RatString()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (z *Rat) UnmarshalText(text []byte) error {
+	// TODO(gri): get rid of the []byte/string conversion
+	if _, ok := z.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/ratmarsh_test.go b/src/cmd/compile/internal/big/ratmarsh_test.go
new file mode 100644
index 0000000..351d109
--- /dev/null
+++ b/src/cmd/compile/internal/big/ratmarsh_test.go
@@ -0,0 +1,125 @@
+// Copyright 2015 The Go Authors. 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"
+	"testing"
+)
+
+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)
+			continue
+		}
+		var rx Rat
+		if err := dec.Decode(&rx); err != nil {
+			t.Errorf("decoding of %s failed: %s", &tx, err)
+			continue
+		}
+		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.Fatalf("transmission of (*Int)(nil) 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)
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/vendor.bash b/src/cmd/compile/internal/big/vendor.bash
index 1b191cc..ac3ec9b 100755
--- a/src/cmd/compile/internal/big/vendor.bash
+++ b/src/cmd/compile/internal/big/vendor.bash
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-# Copyright 2015 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.
 
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
new file mode 100644
index 0000000..136612d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -0,0 +1,596 @@
+// Copyright 2016 The Go Authors. 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"
+
+// AlgKind describes the kind of algorithms used for comparing and
+// hashing a Type.
+type AlgKind int
+
+const (
+	// These values are known by runtime.
+	ANOEQ AlgKind = iota
+	AMEM0
+	AMEM8
+	AMEM16
+	AMEM32
+	AMEM64
+	AMEM128
+	ASTRING
+	AINTER
+	ANILINTER
+	AFLOAT32
+	AFLOAT64
+	ACPLX64
+	ACPLX128
+
+	// Type can be compared/hashed as regular memory.
+	AMEM AlgKind = 100
+
+	// Type needs special comparison/hashing functions.
+	ASPECIAL AlgKind = -1
+)
+
+// IsComparable reports whether t is a comparable type.
+func (t *Type) IsComparable() bool {
+	a, _ := algtype1(t)
+	return a != ANOEQ
+}
+
+// IsRegularMemory reports whether t can be compared/hashed as regular memory.
+func (t *Type) IsRegularMemory() bool {
+	a, _ := algtype1(t)
+	return a == AMEM
+}
+
+// IncomparableField returns an incomparable Field of struct Type t, if any.
+func (t *Type) IncomparableField() *Field {
+	for _, f := range t.FieldSlice() {
+		if !f.Type.IsComparable() {
+			return f
+		}
+	}
+	return nil
+}
+
+// algtype is like algtype1, except it returns the fixed-width AMEMxx variants
+// instead of the general AMEM kind when possible.
+func algtype(t *Type) AlgKind {
+	a, _ := algtype1(t)
+	if a == AMEM {
+		switch t.Width {
+		case 0:
+			return AMEM0
+		case 1:
+			return AMEM8
+		case 2:
+			return AMEM16
+		case 4:
+			return AMEM32
+		case 8:
+			return AMEM64
+		case 16:
+			return AMEM128
+		}
+	}
+
+	return a
+}
+
+// algtype1 returns the AlgKind used for comparing and hashing Type t.
+// If it returns ANOEQ, it also returns the component type of t that
+// makes it incomparable.
+func algtype1(t *Type) (AlgKind, *Type) {
+	if t.Broke {
+		return AMEM, nil
+	}
+	if t.Noalg {
+		return ANOEQ, t
+	}
+
+	switch t.Etype {
+	case TANY, TFORW:
+		// will be defined later.
+		return ANOEQ, t
+
+	case TINT8, TUINT8, TINT16, TUINT16,
+		TINT32, TUINT32, TINT64, TUINT64,
+		TINT, TUINT, TUINTPTR,
+		TBOOL, TPTR32, TPTR64,
+		TCHAN, TUNSAFEPTR:
+		return AMEM, nil
+
+	case TFUNC, TMAP:
+		return ANOEQ, t
+
+	case TFLOAT32:
+		return AFLOAT32, nil
+
+	case TFLOAT64:
+		return AFLOAT64, nil
+
+	case TCOMPLEX64:
+		return ACPLX64, nil
+
+	case TCOMPLEX128:
+		return ACPLX128, nil
+
+	case TSTRING:
+		return ASTRING, nil
+
+	case TINTER:
+		if t.IsEmptyInterface() {
+			return ANILINTER, nil
+		}
+		return AINTER, nil
+
+	case TSLICE:
+		return ANOEQ, t
+
+	case TARRAY:
+		a, bad := algtype1(t.Elem())
+		switch a {
+		case AMEM:
+			return AMEM, nil
+		case ANOEQ:
+			return ANOEQ, bad
+		}
+
+		switch t.NumElem() {
+		case 0:
+			// We checked above that the element type is comparable.
+			return AMEM, nil
+		case 1:
+			// Single-element array is same as its lone element.
+			return a, nil
+		}
+
+		return ASPECIAL, nil
+
+	case TSTRUCT:
+		fields := t.FieldSlice()
+
+		// One-field struct is same as that one field alone.
+		if len(fields) == 1 && !isblanksym(fields[0].Sym) {
+			return algtype1(fields[0].Type)
+		}
+
+		ret := AMEM
+		for i, f := range fields {
+			// All fields must be comparable.
+			a, bad := algtype1(f.Type)
+			if a == ANOEQ {
+				return ANOEQ, bad
+			}
+
+			// Blank fields, padded fields, fields with non-memory
+			// equality need special compare.
+			if a != AMEM || isblanksym(f.Sym) || ispaddedfield(t, i) {
+				ret = ASPECIAL
+			}
+		}
+
+		return ret, nil
+	}
+
+	Fatalf("algtype1: unexpected type %v", t)
+	return 0, nil
+}
+
+// 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.Append(n)
+	np := n.Left
+	n = Nod(ODCLFIELD, newname(Lookup("h")), typenod(Types[TUINTPTR]))
+	tfn.List.Append(n)
+	nh := n.Left
+	n = Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])) // return value
+	tfn.Rlist.Append(n)
+
+	funchdr(fn)
+	fn.Func.Nname.Name.Param.Ntype = 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:
+		Fatalf("genhash %v", t)
+
+	case TARRAY:
+		// An array of pure memory would be handled by the
+		// standard algorithm, so the element type must not be
+		// pure memory.
+		hashel := hashfor(t.Elem())
+
+		n := Nod(ORANGE, nil, Nod(OIND, np, nil))
+		ni := newname(Lookup("i"))
+		ni.Type = Types[TINT]
+		n.List.Set1(ni)
+		n.Colas = true
+		colasdefn(n.List.Slice(), n)
+		ni = n.List.First()
+
+		// 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.Append(na)
+		call.List.Append(nh)
+		n.Nbody.Append(Nod(OAS, nh, call))
+
+		fn.Nbody.Append(n)
+
+	case TSTRUCT:
+		// Walk the struct using memhash for runs of AMEM
+		// and calling specific hash functions for the others.
+		for i, fields := 0, t.FieldSlice(); i < len(fields); {
+			f := fields[i]
+
+			// Skip blank fields.
+			if isblanksym(f.Sym) {
+				i++
+				continue
+			}
+
+			// Hash non-memory fields with appropriate hash function.
+			if !f.Type.IsRegularMemory() {
+				hashel := hashfor(f.Type)
+				call := Nod(OCALL, hashel, nil)
+				nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
+				na := Nod(OADDR, nx, nil)
+				na.Etype = 1 // no escape to heap
+				call.List.Append(na)
+				call.List.Append(nh)
+				fn.Nbody.Append(Nod(OAS, nh, call))
+				i++
+				continue
+			}
+
+			// Otherwise, hash a maximal length run of raw memory.
+			size, next := memrun(t, i)
+
+			// h = hashel(&p.first, size, h)
+			hashel := hashmem(f.Type)
+			call := Nod(OCALL, hashel, nil)
+			nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
+			na := Nod(OADDR, nx, nil)
+			na.Etype = 1 // no escape to heap
+			call.List.Append(na)
+			call.List.Append(nh)
+			call.List.Append(Nodintconst(size))
+			fn.Nbody.Append(Nod(OAS, nh, call))
+
+			i = next
+		}
+	}
+
+	r := Nod(ORETURN, nil, nil)
+	r.List.Append(nh)
+	fn.Nbody.Append(r)
+
+	if Debug['r'] != 0 {
+		dumplist("genhash body", fn.Nbody)
+	}
+
+	funcbody(fn)
+	Curfn = fn
+	fn.Func.Dupok = true
+	fn = typecheck(fn, Etop)
+	typecheckslice(fn.Nbody.Slice(), Etop)
+	Curfn = nil
+	popdcl()
+	testdclstack()
+
+	// 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 = false
+
+	Disable_checknil++
+	funccompile(fn)
+	Disable_checknil--
+
+	safemode = old_safemode
+}
+
+func hashfor(t *Type) *Node {
+	var sym *Sym
+
+	switch a, _ := algtype1(t); a {
+	case AMEM:
+		Fatalf("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.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
+	tfn.List.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	tfn.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	tfn = typecheck(tfn, Etype)
+	n.Type = tfn.Type
+	return n
+}
+
+// geneq generates 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.Append(n)
+	np := n.Left
+	n = Nod(ODCLFIELD, newname(Lookup("q")), typenod(Ptrto(t)))
+	tfn.List.Append(n)
+	nq := n.Left
+	n = Nod(ODCLFIELD, nil, typenod(Types[TBOOL]))
+	tfn.Rlist.Append(n)
+
+	funchdr(fn)
+	fn.Func.Nname.Name.Param.Ntype = typecheck(fn.Func.Nname.Name.Param.Ntype, Etype)
+
+	// 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:
+		Fatalf("geneq %v", t)
+
+	case TARRAY:
+		// 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.Set1(ni)
+		nrange.Colas = true
+		colasdefn(nrange.List.Slice(), nrange)
+		ni = nrange.List.First()
+
+		// 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.Append(Nodbool(false))
+		nif.Nbody.Append(r)
+		nrange.Nbody.Append(nif)
+		fn.Nbody.Append(nrange)
+
+		// return true
+		ret := Nod(ORETURN, nil, nil)
+		ret.List.Append(Nodbool(true))
+		fn.Nbody.Append(ret)
+
+	case TSTRUCT:
+		var cond *Node
+		and := func(n *Node) {
+			if cond == nil {
+				cond = n
+				return
+			}
+			cond = Nod(OANDAND, cond, n)
+		}
+
+		// Walk the struct using memequal for runs of AMEM
+		// and calling specific equality tests for the others.
+		for i, fields := 0, t.FieldSlice(); i < len(fields); {
+			f := fields[i]
+
+			// Skip blank-named fields.
+			if isblanksym(f.Sym) {
+				i++
+				continue
+			}
+
+			// Compare non-memory fields with field equality.
+			if !f.Type.IsRegularMemory() {
+				and(eqfield(np, nq, f.Sym))
+				i++
+				continue
+			}
+
+			// Find maximal length run of memory-only fields.
+			size, next := memrun(t, i)
+
+			// TODO(rsc): All the calls to newname are wrong for
+			// cross-package unexported fields.
+			if s := fields[i:next]; len(s) <= 2 {
+				// Two or fewer fields: use plain field equality.
+				for _, f := range s {
+					and(eqfield(np, nq, f.Sym))
+				}
+			} else {
+				// More than two fields: use memequal.
+				and(eqmem(np, nq, f.Sym, size))
+			}
+			i = next
+		}
+
+		if cond == nil {
+			cond = Nodbool(true)
+		}
+
+		ret := Nod(ORETURN, nil, nil)
+		ret.List.Append(cond)
+		fn.Nbody.Append(ret)
+	}
+
+	if Debug['r'] != 0 {
+		dumplist("geneq body", fn.Nbody)
+	}
+
+	funcbody(fn)
+	Curfn = fn
+	fn.Func.Dupok = true
+	fn = typecheck(fn, Etop)
+	typecheckslice(fn.Nbody.Slice(), Etop)
+	Curfn = nil
+	popdcl()
+	testdclstack()
+
+	// 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 = false
+
+	// Disable checknils while compiling this code.
+	// We are comparing a struct or an array,
+	// neither of which can be nil, and our comparisons
+	// are shallow.
+	Disable_checknil++
+
+	funccompile(fn)
+
+	safemode = old_safemode
+	Disable_checknil--
+}
+
+// eqfield returns the node
+// 	p.field == q.field
+func eqfield(p *Node, q *Node, field *Sym) *Node {
+	nx := NodSym(OXDOT, p, field)
+	ny := NodSym(OXDOT, q, field)
+	ne := Nod(OEQ, nx, ny)
+	return ne
+}
+
+// eqmem returns the node
+// 	memequal(&p.field, &q.field [, size])
+func eqmem(p *Node, q *Node, field *Sym, size int64) *Node {
+	nx := Nod(OADDR, NodSym(OXDOT, p, field), nil)
+	nx.Etype = 1 // does not escape
+	ny := Nod(OADDR, NodSym(OXDOT, q, field), nil)
+	ny.Etype = 1 // does not escape
+	nx = typecheck(nx, Erv)
+	ny = typecheck(ny, Erv)
+
+	fn, needsize := eqmemfunc(size, nx.Type.Elem())
+	call := Nod(OCALL, fn, nil)
+	call.List.Append(nx)
+	call.List.Append(ny)
+	if needsize {
+		call.List.Append(Nodintconst(size))
+	}
+
+	return call
+}
+
+func eqmemfunc(size int64, t *Type) (fn *Node, needsize bool) {
+	switch size {
+	default:
+		fn = syslook("memequal")
+		needsize = true
+	case 1, 2, 4, 8, 16:
+		buf := fmt.Sprintf("memequal%d", int(size)*8)
+		fn = syslook(buf)
+	}
+
+	fn = substArgTypes(fn, t, t)
+	return fn, needsize
+}
+
+// memrun finds runs of struct fields for which memory-only algs are appropriate.
+// t is the parent struct type, and start is the field index at which to start the run.
+// size is the length in bytes of the memory included in the run.
+// next is the index just after the end of the memory run.
+func memrun(t *Type, start int) (size int64, next int) {
+	next = start
+	for {
+		next++
+		if next == t.NumFields() {
+			break
+		}
+		// Stop run after a padded field.
+		if ispaddedfield(t, next-1) {
+			break
+		}
+		// Also, stop before a blank or non-memory field.
+		if f := t.Field(next); isblanksym(f.Sym) || !f.Type.IsRegularMemory() {
+			break
+		}
+	}
+	return t.Field(next-1).End() - t.Field(start).Offset, next
+}
+
+// ispaddedfield reports whether the i'th field of struct type t is followed
+// by padding.
+func ispaddedfield(t *Type, i int) bool {
+	if !t.IsStruct() {
+		Fatalf("ispaddedfield called non-struct %v", t)
+	}
+	end := t.Width
+	if i+1 < t.NumFields() {
+		end = t.Field(i + 1).Offset
+	}
+	return t.Field(i).End() != end
+}
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index 812a8cb..2b62405 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -4,8 +4,6 @@
 
 package gc
 
-import "cmd/internal/obj"
-
 // machine size and rounding alignment is dictated around
 // the size of a pointer, set in betypeinit (see ../amd64/galign.go).
 var defercalc int
@@ -19,11 +17,8 @@ func Rnd(o int64, r int64) int64 {
 
 func offmod(t *Type) {
 	o := int32(0)
-	for f := t.Type; f != nil; f = f.Down {
-		if f.Etype != TFIELD {
-			Fatalf("offmod: not TFIELD: %v", Tconv(f, obj.FmtLong))
-		}
-		f.Width = int64(o)
+	for _, f := range t.Fields().Slice() {
+		f.Offset = int64(o)
 		o += int32(Widthptr)
 		if int64(o) >= Thearch.MAXWIDTH {
 			Yyerror("interface too large")
@@ -40,10 +35,7 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
 	}
 	lastzero := int64(0)
 	var w int64
-	for f := t.Type; f != nil; f = f.Down {
-		if f.Etype != TFIELD {
-			Fatalf("widstruct: not TFIELD: %v", Tconv(f, obj.FmtLong))
-		}
+	for _, f := range t.Fields().Slice() {
 		if f.Type == nil {
 			// broken field, just skip it so that other valid fields
 			// get a width.
@@ -61,14 +53,17 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
 		if f.Type.Align > 0 {
 			o = Rnd(o, int64(f.Type.Align))
 		}
-		f.Width = o // really offset for TFIELD
+		f.Offset = o
 		if f.Nname != nil {
-			// this same stackparam logic is in addrescapes
-			// in typecheck.go.  usually addrescapes runs after
-			// widstruct, in which case we could drop this,
+			// addrescapes has similar code to update these offsets.
+			// 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
+			// NOTE(rsc): This comment may be stale.
+			// It's possible the ordering has changed and this is
+			// now the common case. I'm not sure.
+			if f.Nname.Name.Param.Stackcopy != nil {
+				f.Nname.Name.Param.Stackcopy.Xoffset = o
 				f.Nname.Xoffset = 0
 			} else {
 				f.Nname.Xoffset = o
@@ -80,15 +75,15 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
 		}
 		o += w
 		if o >= Thearch.MAXWIDTH {
-			Yyerror("type %v too large", Tconv(errtype, obj.FmtLong))
+			Yyerror("type %v too large", Tconv(errtype, 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
+	// 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.
+	// pointer to the next object in the heap. See issue 9401.
 	if flag == 1 && o > starto && o == lastzero {
 		o++
 	}
@@ -123,15 +118,12 @@ func dowidth(t *Type) {
 	}
 
 	if t.Width == -2 {
-		lno := int(lineno)
-		lineno = int32(t.Lineno)
 		if !t.Broke {
 			t.Broke = true
-			Yyerror("invalid recursive type %v", t)
+			yyerrorl(t.Lineno, "invalid recursive type %v", t)
 		}
 
 		t.Width = 0
-		lineno = int32(lno)
 		return
 	}
 
@@ -144,8 +136,8 @@ func dowidth(t *Type) {
 	// defer checkwidth calls until after we're done
 	defercalc++
 
-	lno := int(lineno)
-	lineno = int32(t.Lineno)
+	lno := lineno
+	lineno = t.Lineno
 	t.Width = -2
 	t.Align = 0
 
@@ -187,11 +179,11 @@ func dowidth(t *Type) {
 
 	case TPTR32:
 		w = 4
-		checkwidth(t.Type)
+		checkwidth(t.Elem())
 
 	case TPTR64:
 		w = 8
-		checkwidth(t.Type)
+		checkwidth(t.Elem())
 
 	case TUNSAFEPTR:
 		w = int64(Widthptr)
@@ -205,28 +197,25 @@ func dowidth(t *Type) {
 	case TCHAN: // implemented as pointer
 		w = int64(Widthptr)
 
-		checkwidth(t.Type)
+		checkwidth(t.Elem())
 
 		// make fake type to check later to
 		// trigger channel argument check.
-		t1 := typ(TCHANARGS)
-
-		t1.Type = t
+		t1 := typChanArgs(t)
 		checkwidth(t1)
 
 	case TCHANARGS:
-		t1 := t.Type
-		dowidth(t.Type) // just in case
-		if t1.Type.Width >= 1<<16 {
+		t1 := t.ChanArgs()
+		dowidth(t1) // just in case
+		if t1.Elem().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)
+		checkwidth(t.Val())
+		checkwidth(t.Key())
 
 	case TFORW: // should have been filled in
 		if !t.Broke {
@@ -249,35 +238,37 @@ func dowidth(t *Type) {
 		t.Align = uint8(Widthptr)
 
 	case TARRAY:
-		if t.Type == nil {
+		if t.Elem() == 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.isDDDArray() {
 			if !t.Broke {
 				Yyerror("use of [...] array outside of array literal")
 				t.Broke = true
 			}
-		} else {
-			Fatalf("dowidth %v", t) // probably [...]T
+			break
 		}
 
+		dowidth(t.Elem())
+		if t.Elem().Width != 0 {
+			cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
+			if uint64(t.NumElem()) > cap {
+				Yyerror("type %v larger than address space", Tconv(t, FmtLong))
+			}
+		}
+		w = t.NumElem() * t.Elem().Width
+		t.Align = t.Elem().Align
+
+	case TSLICE:
+		if t.Elem() == nil {
+			break
+		}
+		w = int64(sizeof_Array)
+		checkwidth(t.Elem())
+		t.Align = uint8(Widthptr)
+
 	case TSTRUCT:
-		if t.Funarg {
+		if t.IsFuncArgStruct() {
 			Fatalf("dowidth fn struct %v", t)
 		}
 		w = widstruct(t, t, 0, 1)
@@ -285,23 +276,18 @@ func dowidth(t *Type) {
 	// make fake type to check later to
 	// trigger function argument computation.
 	case TFUNC:
-		t1 := typ(TFUNCARGS)
-
-		t1.Type = t
+		t1 := typFuncArgs(t)
 		checkwidth(t1)
-
-		// width of func type is pointer
-		w = int64(Widthptr)
+		w = int64(Widthptr) // width of func type is pointer
 
 	// 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
+		t1 := t.FuncArgs()
+		w = widstruct(t1, t1.Recvs(), 0, 0)
+		w = widstruct(t1, t1.Params(), w, Widthreg)
+		w = widstruct(t1, t1.Results(), w, Widthreg)
+		t1.Extra.(*FuncType).Argwid = w
 		if w%int64(Widthreg) != 0 {
 			Warn("bad type %v %d\n", t1, w)
 		}
@@ -320,7 +306,7 @@ func dowidth(t *Type) {
 		t.Align = uint8(w)
 	}
 
-	lineno = int32(lno)
+	lineno = lno
 
 	if defercalc == 1 {
 		resumecheckwidth()
@@ -344,14 +330,8 @@ func dowidth(t *Type) {
 // 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
+var deferredTypeStack []*Type
 
 func checkwidth(t *Type) {
 	if t == nil {
@@ -360,7 +340,7 @@ func checkwidth(t *Type) {
 
 	// function arg structs should not be checked
 	// outside of the enclosing function.
-	if t.Funarg {
+	if t.IsFuncArgStruct() {
 		Fatalf("checkwidth %v", t)
 	}
 
@@ -374,16 +354,7 @@ func checkwidth(t *Type) {
 	}
 	t.Deferwidth = true
 
-	l := tlfree
-	if l != nil {
-		tlfree = l.next
-	} else {
-		l = new(TypeList)
-	}
-
-	l.t = t
-	l.next = tlq
-	tlq = l
+	deferredTypeStack = append(deferredTypeStack, t)
 }
 
 func defercheckwidth() {
@@ -398,300 +369,29 @@ func resumecheckwidth() {
 	if defercalc == 0 {
 		Fatalf("resumecheckwidth")
 	}
-	for l := tlq; l != nil; l = tlq {
-		l.t.Deferwidth = false
-		tlq = l.next
-		dowidth(l.t)
-		l.next = tlfree
-		tlfree = l
-	}
-
-	defercalc = 0
-}
-
-var itable *Type // distinguished *byte
-
-func typeinit() {
-	if Widthptr == 0 {
-		Fatalf("typeinit before betypeinit")
-	}
-
-	for et := EType(0); et < NTYPE; et++ {
-		Simtype[et] = et
-	}
-
-	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 et := TINT8; et <= TUINT64; et++ {
-		Isint[et] = 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 et := EType(0); et < NTYPE; et++ {
-		if Isint[et] || et == TIDEAL {
-			okforeq[et] = true
-			okforcmp[et] = true
-			okforarith[et] = true
-			okforadd[et] = true
-			okforand[et] = true
-			okforconst[et] = true
-			issimple[et] = true
-			Minintval[et] = new(Mpint)
-			Maxintval[et] = new(Mpint)
-		}
-
-		if Isfloat[et] {
-			okforeq[et] = true
-			okforcmp[et] = true
-			okforadd[et] = true
-			okforarith[et] = true
-			okforconst[et] = true
-			issimple[et] = true
-			minfltval[et] = newMpflt()
-			maxfltval[et] = newMpflt()
-		}
-
-		if Iscomplex[et] {
-			okforeq[et] = true
-			okforadd[et] = true
-			okforarith[et] = true
-			okforconst[et] = true
-			issimple[et] = 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] = Tptr
-
-	Simtype[TCHAN] = Tptr
-	Simtype[TFUNC] = Tptr
-	Simtype[TUNSAFEPTR] = Tptr
-
-	// pick up the backend thearch.typedefs
-	for i = range Thearch.Typedefs {
-		s := Lookup(Thearch.Typedefs[i].Name)
-		s1 := Pkglookup(Thearch.Typedefs[i].Name, builtinpkg)
-
-		etype := Thearch.Typedefs[i].Etype
-		if int(etype) >= len(Types) {
-			Fatalf("typeinit: %s bad etype", s.Name)
-		}
-		sameas := Thearch.Typedefs[i].Sameas
-		if int(sameas) >= len(Types) {
-			Fatalf("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 != nil {
-			Fatalf("typeinit: %s already defined", s.Name)
-		}
-
-		t = typ(etype)
-		t.Sym = s1
-
+	for len(deferredTypeStack) > 0 {
+		t := deferredTypeStack[len(deferredTypeStack)-1]
+		deferredTypeStack = deferredTypeStack[:len(deferredTypeStack)-1]
+		t.Deferwidth = false
 		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]
+	defercalc = 0
 }
 
 // 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)
-	}
+	var w int64
 
-	fp = funcfirst(&save, t)
-	for fp != nil {
-		x = fp.Width + fp.Type.Width
-		if x > w {
-			w = x
+	for _, p := range recvsParamsResults {
+		for _, f := range p(t).Fields().Slice() {
+			if x := f.End(); x > w {
+				w = x
+			}
 		}
-		fp = funcnext(&save)
 	}
 
-	w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1)
+	w = Rnd(w, int64(Widthptr))
 	if int64(int(w)) != w {
 		Fatalf("argsize too big")
 	}
diff --git a/src/cmd/compile/internal/gc/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go
new file mode 100644
index 0000000..21b5910
--- /dev/null
+++ b/src/cmd/compile/internal/gc/asm_test.go
@@ -0,0 +1,159 @@
+// Copyright 2016 The Go Authors. 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"
+	"fmt"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strings"
+	"testing"
+)
+
+// TestAssembly checks to make sure the assembly generated for
+// functions contains certain expected instructions.
+// Note: this test will fail if -ssa=0.
+func TestAssembly(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+	if runtime.GOOS == "windows" {
+		// TODO: remove if we can get "go tool compile -S" to work on windows.
+		t.Skipf("skipping test: recursive windows compile not working")
+	}
+	dir, err := ioutil.TempDir("", "TestAssembly")
+	if err != nil {
+		t.Fatalf("could not create directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	for _, test := range asmTests {
+		asm := compileToAsm(dir, test.arch, fmt.Sprintf(template, test.function))
+		// Get rid of code for "".init. Also gets rid of type algorithms & other junk.
+		if i := strings.Index(asm, "\n\"\".init "); i >= 0 {
+			asm = asm[:i+1]
+		}
+		for _, r := range test.regexps {
+			if b, err := regexp.MatchString(r, asm); !b || err != nil {
+				t.Errorf("expected:%s\ngo:%s\nasm:%s\n", r, test.function, asm)
+			}
+		}
+	}
+}
+
+// compile compiles the package pkg for architecture arch and
+// returns the generated assembly.  dir is a scratch directory.
+func compileToAsm(dir, arch, pkg string) string {
+	// Create source.
+	src := filepath.Join(dir, "test.go")
+	f, err := os.Create(src)
+	if err != nil {
+		panic(err)
+	}
+	f.Write([]byte(pkg))
+	f.Close()
+
+	var stdout, stderr bytes.Buffer
+	cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
+	cmd.Env = mergeEnvLists([]string{"GOARCH=" + arch}, os.Environ())
+	cmd.Stdout = &stdout
+	cmd.Stderr = &stderr
+	if err := cmd.Run(); err != nil {
+		panic(err)
+	}
+	if s := stderr.String(); s != "" {
+		panic(fmt.Errorf("Stderr = %s\nWant empty", s))
+	}
+	return stdout.String()
+}
+
+// template to convert a function to a full file
+const template = `
+package main
+%s
+`
+
+type asmTest struct {
+	// architecture to compile to
+	arch string
+	// function to compile
+	function string
+	// regexps that must match the generated assembly
+	regexps []string
+}
+
+var asmTests = [...]asmTest{
+	{"amd64", `
+func f(x int) int {
+	return x * 64
+}
+`,
+		[]string{"\tSHLQ\t\\$6,"},
+	},
+	{"amd64", `
+func f(x int) int {
+	return x * 96
+}`,
+		[]string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"},
+	},
+}
+
+// mergeEnvLists merges the two environment lists such that
+// variables with the same name in "in" replace those in "out".
+// This always returns a newly allocated slice.
+func mergeEnvLists(in, out []string) []string {
+	out = append([]string(nil), out...)
+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
+}
+
+// TestLineNumber checks to make sure the generated assembly has line numbers
+// see issue #16214
+func TestLineNumber(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+	dir, err := ioutil.TempDir("", "TestLineNumber")
+	if err != nil {
+		t.Fatalf("could not create directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	src := filepath.Join(dir, "x.go")
+	err = ioutil.WriteFile(src, []byte(issue16214src), 0644)
+	if err != nil {
+		t.Fatalf("could not write file: %v", err)
+	}
+
+	cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("fail to run go tool compile: %v", err)
+	}
+
+	if strings.Contains(string(out), "unknown line number") {
+		t.Errorf("line number missing in assembly:\n%s", out)
+	}
+}
+
+var issue16214src = `
+package main
+
+func Mod32(x uint32) uint32 {
+	return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has Lineno 0
+}
+`
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index b49f0fb..38e035e 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -3,59 +3,61 @@
 // license that can be found in the LICENSE file.
 
 // Binary package export.
-// Based loosely on x/tools/go/importer.
-// (see fmt.go, go.y as "documentation" for how to use/setup data structures)
-//
-// Use "-newexport" flag to enable.
-
-// TODO(gri):
-// - inlined functions
+// (see fmt.go, parser.go as "documentation" for how to use/setup data structures)
 
 /*
-Export data encoding:
+1) Export data encoding principles:
 
 The export data is a serialized description of the graph of exported
-objects: constants, types, variables, and functions. Only types can
-be re-exported and so we need to know which package they are coming
+"objects": constants, types, variables, and functions. In general,
+types - but also objects referred to from inlined function bodies -
+can be reexported and so we need to know which package they are coming
 from. Therefore, packages are also part of the export graph.
 
-The roots of the graph are the list of constants, variables, functions,
-and eventually types. Types are written last because most of them will
-be written as part of other objects which will reduce the number of
-types that need to be written separately.
+The roots of the graph are two lists of objects. The 1st list (phase 1,
+see Export) contains all objects that are exported at the package level.
+These objects are the full representation of the package's API, and they
+are the only information a platform-independent tool (e.g., go/types)
+needs to know to type-check against a package.
+
+The 2nd list of objects contains all objects referred to from exported
+inlined function bodies. These objects are needed by the compiler to
+make sense of the function bodies; the exact list contents are compiler-
+specific.
+
+Finally, the export data contains a list of representations for inlined
+function bodies. The format of this representation is compiler specific.
 
 The graph is serialized in in-order fashion, starting with the roots.
 Each object in the graph is serialized by writing its fields sequentially.
 If the field is a pointer to another object, that object is serialized,
 recursively. Otherwise the field is written. Non-pointer fields are all
-encoded as either an integer or string value.
-
-Only packages and types may be referred to more than once. When getting
-to a package or type that was not serialized before, a number (index) is
-assigned to it, starting at 0. In this case, the encoding starts with an
-integer tag with a value < 0. The tag value indicates the kind of object
-(package or type) that follows and that this is the first time that we
-see this object. If the package or tag was already serialized, the encoding
-starts with the respective package or type index >= 0. An importer can
-trivially determine if a package or type needs to be read in for the first
-time (tag < 0) and entered into the respective package or type table, or
-if the package or type was seen already (index >= 0), in which case the
-index is the table index where the respective object can be found.
+encoded as integer or string values.
+
+Some objects (packages, types) may be referred to more than once. When
+reaching an object that was not serialized before, an integer _index_
+is assigned to it, starting at 0. In this case, the encoding starts
+with an integer _tag_ < 0. The tag value indicates the kind of object
+that follows and that this is the first time that we see this object.
+If the object was already serialized, the encoding is simply the object
+index >= 0. An importer can trivially determine if an object needs to
+be read in for the first time (tag < 0) and entered into the respective
+object table, or if the object was seen already (index >= 0), in which
+case the index is used to look up the object in a table.
 
 Before exporting or importing, the type tables are populated with the
 predeclared types (int, string, error, unsafe.Pointer, etc.). This way
 they are automatically encoded with a known and fixed type index.
 
-Encoding format:
+2) Encoding format:
 
 The export data starts with a single byte indicating the encoding format
 (compact, or with debugging information), followed by a version string
-(so we can evolve the encoding if need be), the name of the imported
-package, and a string containing platform-specific information for that
-package.
+(so we can evolve the encoding if need be), and then the package object
+for the exported package (with an empty path).
 
-After this header, the lists of objects follow. After the objects, platform-
-specific data may be found which is not used strictly for type checking.
+After this header, two lists of objects and the list of inlined function
+bodies follows.
 
 The encoding of objects is straight-forward: Constants, variables, and
 functions start with their name, type, and possibly a value. Named types
@@ -65,76 +67,184 @@ the previously imported type pointer so that we have exactly one version
 (i.e., one pointer) for each named type (and read but discard the current
 type encoding). Unnamed types simply encode their respective fields.
 
-In the encoding, all lists (of objects, struct fields, methods, parameter
-names, but also the bytes of a string, etc.) start with an integer which
-is the length of the list. This permits an importer to allocate the right
-amount of space to hold the list without the need to grow it later.
+In the encoding, some lists start with the list length. Some lists are
+terminated with an end marker (usually for lists where we may not know
+the length a priori).
 
-All integer values use a variable-length encoding for compact representation.
+Integers use variable-length encoding for compact representation.
 
-If debugFormat is set, each integer and string value is preceeded by a marker
-and position information in the encoding. This mechanism permits an importer
-to recognize immediately when it is out of sync. The importer recognizes this
-mode automatically (i.e., it can import export data produced with debugging
-support even if debugFormat is not set at the time of import). Using this mode
-will massively increase the size of the export data (by a factor of 2 to 3)
-and is only recommended for debugging.
+Strings are canonicalized similar to objects that may occur multiple times:
+If the string was exported already, it is represented by its index only.
+Otherwise, the export data starts with the negative string length (negative,
+so we can distinguish from string index), followed by the string bytes.
+The empty string is mapped to index 0.
 
 The exporter and importer are completely symmetric in implementation: For
-each encoding routine there is the matching and symmetric decoding routine.
+each encoding routine there is a matching and symmetric decoding routine.
 This symmetry makes it very easy to change or extend the format: If a new
 field needs to be encoded, a symmetric change can be made to exporter and
 importer.
+
+3) Making changes to the encoding format:
+
+Any change to the encoding format requires a respective change in the
+exporter below and a corresponding symmetric change to the importer in
+bimport.go.
+
+Furthermore, it requires a corresponding change to go/internal/gcimporter
+and golang.org/x/tools/go/gcimporter15. Changes to the latter must preserve
+compatibility with both the last release of the compiler, and with the
+corresponding compiler at tip. That change is necessarily more involved,
+as it must switch based on the version number in the export data file.
+
+It is recommended to turn on debugFormat when working on format changes
+as it will help finding encoding/decoding inconsistencies quickly.
+
+Special care must be taken to update builtin.go when the export format
+changes: builtin.go contains the export data obtained by compiling the
+builtin/runtime.go and builtin/unsafe.go files; those compilations in
+turn depend on importing the data in builtin.go. Thus, when the export
+data format changes, the compiler must be able to import the data in
+builtin.go even if its format has not yet changed. Proceed in several
+steps as follows:
+
+- Change the exporter to use the new format, and use a different version
+  string as well.
+- Update the importer accordingly, but accept both the old and the new
+  format depending on the version string.
+- all.bash should pass at this point.
+- Run mkbuiltin.go: this will create a new builtin.go using the new
+  export format.
+- go test -run Builtin should pass at this point.
+- Remove importer support for the old export format and (maybe) revert
+  the version string again (it's only needed to mark the transition).
+- all.bash should still pass.
+
+Don't forget to set debugFormat to false.
 */
 
 package gc
 
 import (
+	"bufio"
 	"bytes"
 	"cmd/compile/internal/big"
-	"cmd/internal/obj"
 	"encoding/binary"
 	"fmt"
 	"sort"
 	"strings"
 )
 
-// debugging support
+// If debugFormat is set, each integer and string value is preceded by a marker
+// and position information in the encoding. This mechanism permits an importer
+// to recognize immediately when it is out of sync. The importer recognizes this
+// mode automatically (i.e., it can import export data produced with debugging
+// support even if debugFormat is not set at the time of import). This mode will
+// lead to massively larger export data (by a factor of 2 to 3) and should only
+// be enabled during development and debugging.
+//
+// NOTE: This flag is the first flag to enable if importing dies because of
+// (suspected) format errors, and whenever a change is made to the format.
+const debugFormat = false // default: false
+
+// forceObjFileStability enforces additional constraints in export data
+// and other parts of the compiler to eliminate object file differences
+// only due to the choice of export format.
+// TODO(gri) disable and remove once there is only one export format again
+const forceObjFileStability = true
+
+// Supported export format versions.
+// TODO(gri) Make this more systematic (issue #16244).
 const (
-	debugFormat = false // use debugging format for export data (emits a lot of additional data)
+	exportVersion0 = "v0"
+	exportVersion1 = "v1"
+	exportVersion  = exportVersion1
 )
 
-const exportVersion = "v0"
+// exportInlined enables the export of inlined function bodies and related
+// dependencies. The compiler should work w/o any loss of functionality with
+// the flag disabled, but the generated code will lose access to inlined
+// function bodies across packages, leading to performance bugs.
+// Leave for debugging.
+const exportInlined = true // default: true
+
+// trackAllTypes enables cycle tracking for all types, not just named
+// types. The existing compiler invariants assume that unnamed types
+// that are not completely set up are not used, or else there are spurious
+// errors.
+// If disabled, only named types are tracked, possibly leading to slightly
+// less efficient encoding in rare cases. It also prevents the export of
+// some corner-case type declarations (but those are not handled correctly
+// with with the textual export format either).
+// TODO(gri) enable and remove once issues caused by it are fixed
+const trackAllTypes = false
+
+type exporter struct {
+	out *bufio.Writer
+
+	// object -> index maps, indexed in order of serialization
+	strIndex map[string]int
+	pkgIndex map[*Pkg]int
+	typIndex map[*Type]int
+	funcList []*Func
+
+	// position encoding
+	posInfoFormat bool
+	prevFile      string
+	prevLine      int
 
-// Set forceNewExport to force the use of the new export format - for testing on the build dashboard.
-// TODO(gri) remove eventually
-const forceNewExport = false
+	// debugging support
+	written int // bytes written
+	indent  int // for p.trace
+	trace   bool
+}
 
-// Export writes the export data for localpkg to out and returns the number of bytes written.
-func Export(out *obj.Biobuf, trace bool) int {
+// export writes the exportlist for localpkg to out and returns the number of bytes written.
+func export(out *bufio.Writer, trace bool) int {
 	p := exporter{
 		out:      out,
+		strIndex: map[string]int{"": 0}, // empty string is mapped to 0
 		pkgIndex: make(map[*Pkg]int),
 		typIndex: make(map[*Type]int),
-		trace:    trace,
+		// don't emit pos info for builtin packages
+		// (not needed and avoids path name diffs in builtin.go between
+		// Windows and non-Windows machines, exposed via builtin_test.go)
+		posInfoFormat: Debug['A'] == 0,
+		trace:         trace,
 	}
 
-	// write low-level encoding format
+	// TODO(gri) clean up the ad-hoc encoding of the file format below
+	// (we need this so we can read the builtin package export data
+	// easily w/o being affected by format changes)
+
+	// first byte indicates low-level encoding format
 	var format byte = 'c' // compact
 	if debugFormat {
 		format = 'd'
 	}
-	p.byte(format)
+	p.rawByte(format)
+
+	format = 'n' // track named types only
+	if trackAllTypes {
+		format = 'a'
+	}
+	p.rawByte(format)
+
+	// posInfo exported or not?
+	p.bool(p.posInfoFormat)
 
 	// --- generic export data ---
 
 	if p.trace {
-		p.tracef("\n--- generic export data ---\n")
+		p.tracef("\n--- package ---\n")
 		if p.indent != 0 {
-			Fatalf("incorrect indentation %d", p.indent)
+			Fatalf("exporter: incorrect indentation %d", p.indent)
 		}
 	}
 
+	if p.trace {
+		p.tracef("version = ")
+	}
 	p.string(exportVersion)
 	if p.trace {
 		p.tracef("\n")
@@ -146,36 +256,43 @@ func Export(out *obj.Biobuf, trace bool) int {
 		p.typIndex[typ] = index
 	}
 	if len(p.typIndex) != len(predecl) {
-		Fatalf("duplicate entries in type map?")
+		Fatalf("exporter: duplicate entries in type map?")
 	}
 
 	// write package data
 	if localpkg.Path != "" {
-		Fatalf("local package path not empty: %q", localpkg.Path)
+		Fatalf("exporter: local package path not empty: %q", localpkg.Path)
 	}
 	p.pkg(localpkg)
-
-	// write compiler-specific flags
-	// go.y:import_safety
-	{
-		var flags string
-		if safemode != 0 {
-			flags = "safe"
-		}
-		p.string(flags)
-	}
-
 	if p.trace {
 		p.tracef("\n")
 	}
 
-	// collect objects to export
-	var consts, vars, funcs []*Sym
-	var types []*Type
+	// export objects
+	//
+	// First, export all exported (package-level) objects; i.e., all objects
+	// in the current exportlist. These objects represent all information
+	// required to import this package and type-check against it; i.e., this
+	// is the platform-independent export data. The format is generic in the
+	// sense that different compilers can use the same representation.
+	//
+	// During this first phase, more objects may be added to the exportlist
+	// (due to inlined function bodies and their dependencies). Export those
+	// objects in a second phase. That data is platform-specific as it depends
+	// on the inlining decisions of the compiler and the representation of the
+	// inlined function bodies.
+
+	// remember initial exportlist length
+	var numglobals = len(exportlist)
+
+	// Phase 1: Export objects in _current_ exportlist; exported objects at
+	//          package level.
+	// Use range since we want to ignore objects added to exportlist during
+	// this phase.
+	objcount := 0
 	for _, n := range exportlist {
 		sym := n.Sym
-		// TODO(gri) Closures appear marked as exported.
-		// Investigate and determine if we need this.
+
 		if sym.Flags&SymExported != 0 {
 			continue
 		}
@@ -183,167 +300,155 @@ func Export(out *obj.Biobuf, trace bool) int {
 
 		// TODO(gri) Closures have dots in their names;
 		// e.g., TestFloatZeroValue.func1 in math/big tests.
-		// We may not need this eventually. See also comment
-		// on sym.Flags&SymExported test above.
 		if strings.Contains(sym.Name, ".") {
-			Fatalf("unexpected export symbol: %v", sym)
+			Fatalf("exporter: unexpected symbol: %v", sym)
 		}
 
-		if sym.Flags&SymExport != 0 {
-			if sym.Def == nil {
-				Fatalf("unknown export symbol: %v", sym)
-			}
-			switch n := sym.Def; n.Op {
-			case OLITERAL:
-				// constant
-				typecheck(&n, Erv)
-				if n == nil || n.Op != OLITERAL {
-					Fatalf("dumpexportconst: oconst nil: %v", sym)
-				}
-				consts = append(consts, sym)
+		// TODO(gri) Should we do this check?
+		// if sym.Flags&SymExport == 0 {
+		// 	continue
+		// }
 
-			case ONAME:
-				// variable or function
-				typecheck(&n, Erv|Ecall)
-				if n == nil || n.Type == nil {
-					Fatalf("variable/function exported but not defined: %v", sym)
-				}
-				if n.Type.Etype == TFUNC && n.Class == PFUNC {
-					funcs = append(funcs, sym)
-				} else {
-					vars = append(vars, sym)
-				}
+		if sym.Def == nil {
+			Fatalf("exporter: unknown export symbol: %v", sym)
+		}
 
-			case OTYPE:
-				// named type
-				t := n.Type
-				if t.Etype == TFORW {
-					Fatalf("export of incomplete type %v", sym)
-				}
-				types = append(types, t)
+		// TODO(gri) Optimization: Probably worthwhile collecting
+		// long runs of constants and export them "in bulk" (saving
+		// tags and types, and making import faster).
 
-			default:
-				Fatalf("unexpected export symbol: %v %v", Oconv(int(n.Op), 0), sym)
-			}
+		if p.trace {
+			p.tracef("\n")
 		}
+		p.obj(sym)
+		objcount++
 	}
-	exportlist = nil // match export.go use of exportlist
 
-	// for reproducible output
-	sort.Sort(symByName(consts))
-	sort.Sort(symByName(vars))
-	sort.Sort(symByName(funcs))
-	// sort types later when we have fewer types left
+	// indicate end of list
+	if p.trace {
+		p.tracef("\n")
+	}
+	p.tag(endTag)
 
-	// write consts
-	p.int(len(consts))
-	for _, sym := range consts {
-		n := sym.Def
-		typ := n.Type // may or may not be specified
-		// Untyped (ideal) constants get their own type. This decouples
-		// the constant type from the encoding of the constant value.
-		if typ == nil || isideal(typ) {
-			typ = untype(n.Val().Ctype())
-		}
+	// for self-verification only (redundant)
+	p.int(objcount)
 
-		p.string(sym.Name)
-		p.typ(typ)
-		p.value(n.Val())
-	}
+	// --- compiler-specific export data ---
 
-	// write vars
-	p.int(len(vars))
-	for _, sym := range vars {
-		p.string(sym.Name)
-		p.typ(sym.Def.Type)
+	if p.trace {
+		p.tracef("\n--- compiler-specific export data ---\n[ ")
+		if p.indent != 0 {
+			Fatalf("exporter: incorrect indentation")
+		}
 	}
 
-	// write funcs
-	p.int(len(funcs))
-	for _, sym := range funcs {
-		p.string(sym.Name)
-		// The type can only be a signature for functions. However, by always
-		// writing the complete type specification (rather than just a signature)
-		// we keep the option open of sharing common signatures across multiple
-		// functions as a means to further compress the export data.
-		p.typ(sym.Def.Type)
-		p.int(p.collectInlined(sym.Def))
+	// write compiler-specific flags
+	p.bool(safemode)
+	if p.trace {
+		p.tracef("\n")
 	}
 
-	// determine which types are still left to write and sort them
-	i := 0
-	for _, t := range types {
-		if _, ok := p.typIndex[t]; !ok {
-			types[i] = t
-			i++
+	// Phase 2: Export objects added to exportlist during phase 1.
+	// Don't use range since exportlist may grow during this phase
+	// and we want to export all remaining objects.
+	objcount = 0
+	for i := numglobals; exportInlined && i < len(exportlist); i++ {
+		n := exportlist[i]
+		sym := n.Sym
+
+		// TODO(gri) The rest of this loop body is identical with
+		// the loop body above. Leave alone for now since there
+		// are different optimization opportunities, but factor
+		// eventually.
+
+		if sym.Flags&SymExported != 0 {
+			continue
 		}
-	}
-	types = types[:i]
-	sort.Sort(typByName(types))
+		sym.Flags |= SymExported
 
-	// write types
-	p.int(len(types))
-	for _, t := range types {
-		// Writing a type may further reduce the number of types
-		// that are left to be written, but at this point we don't
-		// care.
-		p.typ(t)
+		// TODO(gri) Closures have dots in their names;
+		// e.g., TestFloatZeroValue.func1 in math/big tests.
+		if strings.Contains(sym.Name, ".") {
+			Fatalf("exporter: unexpected symbol: %v", sym)
+		}
+
+		// TODO(gri) Should we do this check?
+		// if sym.Flags&SymExport == 0 {
+		// 	continue
+		// }
+
+		if sym.Def == nil {
+			Fatalf("exporter: unknown export symbol: %v", sym)
+		}
+
+		// TODO(gri) Optimization: Probably worthwhile collecting
+		// long runs of constants and export them "in bulk" (saving
+		// tags and types, and making import faster).
+
+		if p.trace {
+			p.tracef("\n")
+		}
+		p.obj(sym)
+		objcount++
 	}
 
+	// indicate end of list
 	if p.trace {
 		p.tracef("\n")
 	}
+	p.tag(endTag)
 
-	// --- compiler-specific export data ---
+	// for self-verification only (redundant)
+	p.int(objcount)
+
+	// --- inlined function bodies ---
 
 	if p.trace {
-		p.tracef("\n--- compiler specific export data ---\n")
+		p.tracef("\n--- inlined function bodies ---\n")
 		if p.indent != 0 {
-			Fatalf("incorrect indentation")
+			Fatalf("exporter: incorrect indentation")
 		}
 	}
 
-	// write inlined function bodies
-	p.int(len(p.inlined))
-	for i, f := range p.inlined {
-		p.body(i, f)
+	// write inlineable function bodies
+	objcount = 0
+	for i, f := range p.funcList {
+		if f != nil {
+			// function has inlineable body:
+			// write index and body
+			if p.trace {
+				p.tracef("\n----\nfunc { %s }\n", hconv(f.Inl, FmtSharp))
+			}
+			p.int(i)
+			p.stmtList(f.Inl)
+			if p.trace {
+				p.tracef("\n")
+			}
+			objcount++
+		}
 	}
 
+	// indicate end of list
 	if p.trace {
 		p.tracef("\n")
 	}
+	p.int(-1) // invalid index terminates list
 
-	// --- end of export data ---
-
-	return p.written
-}
-
-type symByName []*Sym
+	// for self-verification only (redundant)
+	p.int(objcount)
 
-func (a symByName) Len() int           { return len(a) }
-func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
-func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
-
-type typByName []*Type
-
-func (a typByName) Len() int           { return len(a) }
-func (a typByName) Less(i, j int) bool { return a[i].Sym.Name < a[j].Sym.Name }
-func (a typByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+	if p.trace {
+		p.tracef("\n--- end ---\n")
+	}
 
-type exporter struct {
-	out      *obj.Biobuf
-	pkgIndex map[*Pkg]int
-	typIndex map[*Type]int
-	inlined  []*Func
+	// --- end of export data ---
 
-	written int // bytes written
-	indent  int // for p.trace
-	trace   bool
+	return p.written
 }
 
 func (p *exporter) pkg(pkg *Pkg) {
 	if pkg == nil {
-		Fatalf("unexpected nil pkg")
+		Fatalf("exporter: unexpected nil pkg")
 	}
 
 	// if we saw the package before, write its index (>= 0)
@@ -364,9 +469,170 @@ func (p *exporter) pkg(pkg *Pkg) {
 	p.string(pkg.Path)
 }
 
+func unidealType(typ *Type, val Val) *Type {
+	// Untyped (ideal) constants get their own type. This decouples
+	// the constant type from the encoding of the constant value.
+	if typ == nil || typ.IsUntyped() {
+		typ = untype(val.Ctype())
+	}
+	return typ
+}
+
+func (p *exporter) obj(sym *Sym) {
+	// Exported objects may be from different packages because they
+	// may be re-exported as depencies when exporting inlined function
+	// bodies. Thus, exported object names must be fully qualified.
+	//
+	// TODO(gri) This can only happen if exportInlined is enabled
+	// (default), and during phase 2 of object export. Objects exported
+	// in phase 1 (compiler-indendepent objects) are by definition only
+	// the objects from the current package and not pulled in via inlined
+	// function bodies. In that case the package qualifier is not needed.
+	// Possible space optimization.
+
+	n := sym.Def
+	switch n.Op {
+	case OLITERAL:
+		// constant
+		// TODO(gri) determine if we need the typecheck call here
+		n = typecheck(n, Erv)
+		if n == nil || n.Op != OLITERAL {
+			Fatalf("exporter: dumpexportconst: oconst nil: %v", sym)
+		}
+
+		p.tag(constTag)
+		p.pos(n)
+		// TODO(gri) In inlined functions, constants are used directly
+		// so they should never occur as re-exported objects. We may
+		// not need the qualified name here. See also comment above.
+		// Possible space optimization.
+		p.qualifiedName(sym)
+		p.typ(unidealType(n.Type, n.Val()))
+		p.value(n.Val())
+
+	case OTYPE:
+		// named type
+		t := n.Type
+		if t.Etype == TFORW {
+			Fatalf("exporter: export of incomplete type %v", sym)
+		}
+
+		p.tag(typeTag)
+		p.typ(t)
+
+	case ONAME:
+		// variable or function
+		n = typecheck(n, Erv|Ecall)
+		if n == nil || n.Type == nil {
+			Fatalf("exporter: variable/function exported but not defined: %v", sym)
+		}
+
+		if n.Type.Etype == TFUNC && n.Class == PFUNC {
+			// function
+			p.tag(funcTag)
+			p.pos(n)
+			p.qualifiedName(sym)
+
+			sig := sym.Def.Type
+			inlineable := isInlineable(sym.Def)
+
+			p.paramList(sig.Params(), inlineable)
+			p.paramList(sig.Results(), inlineable)
+
+			var f *Func
+			if inlineable {
+				f = sym.Def.Func
+				// TODO(gri) re-examine reexportdeplist:
+				// Because we can trivially export types
+				// in-place, we don't need to collect types
+				// inside function bodies in the exportlist.
+				// With an adjusted reexportdeplist used only
+				// by the binary exporter, we can also avoid
+				// the global exportlist.
+				reexportdeplist(f.Inl)
+			}
+			p.funcList = append(p.funcList, f)
+		} else {
+			// variable
+			p.tag(varTag)
+			p.pos(n)
+			p.qualifiedName(sym)
+			p.typ(sym.Def.Type)
+		}
+
+	default:
+		Fatalf("exporter: unexpected export symbol: %v %v", n.Op, sym)
+	}
+}
+
+func (p *exporter) pos(n *Node) {
+	if !p.posInfoFormat {
+		return
+	}
+
+	file, line := fileLine(n)
+	if file == p.prevFile {
+		// common case: write line delta
+		// delta == 0 means different file or no line change
+		delta := line - p.prevLine
+		p.int(delta)
+		if delta == 0 {
+			p.int(-1) // -1 means no file change
+		}
+	} else {
+		// different file
+		p.int(0)
+		// Encode filename as length of common prefix with previous
+		// filename, followed by (possibly empty) suffix. Filenames
+		// frequently share path prefixes, so this can save a lot
+		// of space and make export data size less dependent on file
+		// path length. The suffix is unlikely to be empty because
+		// file names tend to end in ".go".
+		n := commonPrefixLen(p.prevFile, file)
+		p.int(n)           // n >= 0
+		p.string(file[n:]) // write suffix only
+		p.prevFile = file
+		p.int(line)
+	}
+	p.prevLine = line
+}
+
+func fileLine(n *Node) (file string, line int) {
+	if n != nil {
+		file, line = Ctxt.LineHist.AbsFileLine(int(n.Lineno))
+	}
+	return
+}
+
+func commonPrefixLen(a, b string) int {
+	if len(a) > len(b) {
+		a, b = b, a
+	}
+	// len(a) <= len(b)
+	i := 0
+	for i < len(a) && a[i] == b[i] {
+		i++
+	}
+	return i
+}
+
+func isInlineable(n *Node) bool {
+	if exportInlined && n != nil && n.Func != nil && n.Func.Inl.Len() != 0 {
+		// 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)
+		}
+		return true
+	}
+	return false
+}
+
+var errorInterface *Type // lazily initialized
+
 func (p *exporter) typ(t *Type) {
 	if t == nil {
-		Fatalf("nil type")
+		Fatalf("exporter: nil type")
 	}
 
 	// Possible optimization: Anonymous pointer types *T where
@@ -385,69 +651,105 @@ func (p *exporter) typ(t *Type) {
 	}
 
 	// otherwise, remember the type, write the type tag (< 0) and type data
-	if p.trace {
-		p.tracef("T%d = {>\n", len(p.typIndex))
-		defer p.tracef("<\n} ")
+	if trackAllTypes {
+		if p.trace {
+			p.tracef("T%d = {>\n", len(p.typIndex))
+			defer p.tracef("<\n} ")
+		}
+		p.typIndex[t] = len(p.typIndex)
 	}
-	p.typIndex[t] = len(p.typIndex)
 
 	// pick off named types
-	if sym := t.Sym; sym != nil {
-		// Fields should be exported by p.field().
-		if t.Etype == TFIELD {
-			Fatalf("printing a field/parameter with wrong function")
+	if tsym := t.Sym; tsym != nil {
+		if !trackAllTypes {
+			// if we don't track all types, track named types now
+			p.typIndex[t] = len(p.typIndex)
 		}
+
 		// Predeclared types should have been found in the type map.
 		if t.Orig == t {
-			Fatalf("predeclared type missing from type map?")
-		}
-		// TODO(gri) The assertion below seems incorrect (crashes during all.bash).
-		// Investigate.
-		/*
-			// we expect the respective definition to point to us
-			if sym.Def.Type != t {
-				Fatalf("type definition doesn't point to us?")
-			}
-		*/
+			Fatalf("exporter: predeclared type missing from type map?")
+		}
+
+		n := typenod(t)
+		if n.Type != t {
+			Fatalf("exporter: named type definition incorrectly set up")
+		}
 
 		p.tag(namedTag)
-		p.qualifiedName(sym)
+		p.pos(n)
+		p.qualifiedName(tsym)
 
 		// write underlying type
-		p.typ(t.Orig)
+		orig := t.Orig
+		if orig == errortype {
+			// The error type is the only predeclared type which has
+			// a composite underlying type. When we encode that type,
+			// make sure to encode the underlying interface rather than
+			// the named type again. See also the comment in universe.go
+			// regarding the errortype and issue #15920.
+			if errorInterface == nil {
+				errorInterface = makeErrorInterface()
+			}
+			orig = errorInterface
+		}
+		p.typ(orig)
 
 		// interfaces don't have associated methods
-		if t.Orig.Etype == TINTER {
+		if t.Orig.IsInterface() {
 			return
 		}
 
 		// sort methods for reproducible export format
 		// TODO(gri) Determine if they are already sorted
 		// in which case we can drop this step.
-		var methods []*Type
-		for m := t.Method; m != nil; m = m.Down {
+		var methods []*Field
+		for _, m := range t.Methods().Slice() {
 			methods = append(methods, m)
 		}
 		sort.Sort(methodbyname(methods))
 		p.int(len(methods))
 
-		if p.trace && t.Method != nil {
-			p.tracef("associated methods {>\n")
+		if p.trace && len(methods) > 0 {
+			p.tracef("associated methods {>")
 		}
 
 		for _, m := range methods {
-			p.string(m.Sym.Name)
-			p.paramList(getthisx(m.Type))
-			p.paramList(getinargx(m.Type))
-			p.paramList(getoutargx(m.Type))
-			p.int(p.collectInlined(m.Type.Nname))
-
-			if p.trace && m.Down != nil {
+			if p.trace {
 				p.tracef("\n")
 			}
+			if strings.Contains(m.Sym.Name, ".") {
+				Fatalf("invalid symbol name: %s (%v)", m.Sym.Name, m.Sym)
+			}
+
+			p.pos(m.Nname)
+			p.fieldSym(m.Sym, false)
+
+			sig := m.Type
+			mfn := sig.Nname()
+			inlineable := isInlineable(mfn)
+
+			p.paramList(sig.Recvs(), inlineable)
+			p.paramList(sig.Params(), inlineable)
+			p.paramList(sig.Results(), inlineable)
+
+			// for issue #16243
+			// We make this conditional for 1.7 to avoid consistency problems
+			// with installed packages compiled with an older version.
+			// TODO(gri) Clean up after 1.7 is out (issue #16244)
+			if exportVersion == exportVersion1 {
+				p.bool(m.Nointerface)
+			}
+
+			var f *Func
+			if inlineable {
+				f = mfn.Func
+				reexportdeplist(mfn.Func.Inl)
+			}
+			p.funcList = append(p.funcList, f)
 		}
 
-		if p.trace && t.Method != nil {
+		if p.trace && len(methods) > 0 {
 			p.tracef("<\n} ")
 		}
 
@@ -457,19 +759,21 @@ func (p *exporter) typ(t *Type) {
 	// otherwise we have a type literal
 	switch t.Etype {
 	case TARRAY:
-		// TODO(gri) define named constant for the -100
-		if t.Bound >= 0 || t.Bound == -100 {
-			p.tag(arrayTag)
-			p.int64(t.Bound)
-		} else {
-			p.tag(sliceTag)
+		if t.isDDDArray() {
+			Fatalf("array bounds should be known at export time: %v", t)
 		}
-		p.typ(t.Type)
+		p.tag(arrayTag)
+		p.int64(t.NumElem())
+		p.typ(t.Elem())
 
-	case T_old_DARRAY:
-		// see p.param use of T_old_DARRAY
+	case TSLICE:
+		p.tag(sliceTag)
+		p.typ(t.Elem())
+
+	case TDDDFIELD:
+		// see p.param use of TDDDFIELD
 		p.tag(dddTag)
-		p.typ(t.Type)
+		p.typ(t.DDDField())
 
 	case TSTRUCT:
 		p.tag(structTag)
@@ -477,12 +781,12 @@ func (p *exporter) typ(t *Type) {
 
 	case TPTR32, TPTR64: // could use Tptr but these are constants
 		p.tag(pointerTag)
-		p.typ(t.Type)
+		p.typ(t.Elem())
 
 	case TFUNC:
 		p.tag(signatureTag)
-		p.paramList(getinargx(t))
-		p.paramList(getoutargx(t))
+		p.paramList(t.Params(), false)
+		p.paramList(t.Results(), false)
 
 	case TINTER:
 		p.tag(interfaceTag)
@@ -494,99 +798,94 @@ func (p *exporter) typ(t *Type) {
 
 	case TMAP:
 		p.tag(mapTag)
-		p.typ(t.Down) // key
-		p.typ(t.Type) // val
+		p.typ(t.Key())
+		p.typ(t.Val())
 
 	case TCHAN:
 		p.tag(chanTag)
-		p.int(int(t.Chan))
-		p.typ(t.Type)
+		p.int(int(t.ChanDir()))
+		p.typ(t.Elem())
 
 	default:
-		Fatalf("unexpected type: %s (Etype = %d)", Tconv(t, 0), t.Etype)
+		Fatalf("exporter: unexpected type: %s (Etype = %d)", Tconv(t, 0), t.Etype)
 	}
 }
 
 func (p *exporter) qualifiedName(sym *Sym) {
+	if strings.Contains(sym.Name, ".") {
+		Fatalf("exporter: invalid symbol name: %s", sym.Name)
+	}
 	p.string(sym.Name)
 	p.pkg(sym.Pkg)
 }
 
 func (p *exporter) fieldList(t *Type) {
-	if p.trace && t.Type != nil {
-		p.tracef("fields {>\n")
+	if p.trace && t.NumFields() > 0 {
+		p.tracef("fields {>")
 		defer p.tracef("<\n} ")
 	}
 
-	p.int(countfield(t))
-	for f := t.Type; f != nil; f = f.Down {
-		p.field(f)
-		if p.trace && f.Down != nil {
+	p.int(t.NumFields())
+	for _, f := range t.Fields().Slice() {
+		if p.trace {
 			p.tracef("\n")
 		}
+		p.field(f)
 	}
 }
 
-func (p *exporter) field(f *Type) {
-	if f.Etype != TFIELD {
-		Fatalf("field expected")
-	}
-
-	p.fieldName(f)
+func (p *exporter) field(f *Field) {
+	p.pos(f.Nname)
+	p.fieldName(f.Sym, f)
 	p.typ(f.Type)
-	p.note(f.Note)
-}
-
-func (p *exporter) note(n *string) {
-	var s string
-	if n != nil {
-		s = *n
-	}
-	p.string(s)
+	p.string(f.Note)
 }
 
 func (p *exporter) methodList(t *Type) {
-	if p.trace && t.Type != nil {
-		p.tracef("methods {>\n")
+	if p.trace && t.NumFields() > 0 {
+		p.tracef("methods {>")
 		defer p.tracef("<\n} ")
 	}
 
-	p.int(countfield(t))
-	for m := t.Type; m != nil; m = m.Down {
-		p.method(m)
-		if p.trace && m.Down != nil {
+	p.int(t.NumFields())
+	for _, m := range t.Fields().Slice() {
+		if p.trace {
 			p.tracef("\n")
 		}
+		p.method(m)
 	}
 }
 
-func (p *exporter) method(m *Type) {
-	if m.Etype != TFIELD {
-		Fatalf("method expected")
-	}
-
-	p.fieldName(m)
-	// TODO(gri) For functions signatures, we use p.typ() to export
-	// so we could share the same type with multiple functions. Do
-	// the same here, or never try to do this for functions.
-	p.paramList(getinargx(m.Type))
-	p.paramList(getoutargx(m.Type))
+func (p *exporter) method(m *Field) {
+	p.pos(m.Nname)
+	p.fieldName(m.Sym, m)
+	p.paramList(m.Type.Params(), false)
+	p.paramList(m.Type.Results(), false)
 }
 
 // fieldName is like qualifiedName but it doesn't record the package
 // for blank (_) or exported names.
-func (p *exporter) fieldName(t *Type) {
-	sym := t.Sym
-
-	var name string
-	if t.Embedded == 0 {
-		name = sym.Name
-	} else if bname := basetypeName(t); bname != "" && !exportname(bname) {
-		// anonymous field with unexported base type name: use "?" as field name
-		// (bname != "" per spec, but we are conservative in case of errors)
-		name = "?"
+func (p *exporter) fieldName(sym *Sym, t *Field) {
+	if t != nil && sym != t.Sym {
+		Fatalf("exporter: invalid fieldName parameters")
+	}
+
+	name := sym.Name
+	if t != nil {
+		if t.Embedded == 0 {
+			name = sym.Name
+		} else if bname := basetypeName(t.Type); bname != "" && !exportname(bname) {
+			// anonymous field with unexported base type name: use "?" as field name
+			// (bname != "" per spec, but we are conservative in case of errors)
+			name = "?"
+		} else {
+			name = ""
+		}
 	}
 
+	if strings.Contains(name, ".") {
+		Fatalf("exporter: invalid symbol name: %s", name)
+	}
 	p.string(name)
 	if name == "?" || name != "_" && name != "" && !exportname(name) {
 		p.pkg(sym.Pkg)
@@ -595,74 +894,128 @@ func (p *exporter) fieldName(t *Type) {
 
 func basetypeName(t *Type) string {
 	s := t.Sym
-	if s == nil && Isptr[t.Etype] {
-		s = t.Type.Sym // deref
+	if s == nil && t.IsPtr() {
+		s = t.Elem().Sym // deref
 	}
 	if s != nil {
+		if strings.Contains(s.Name, ".") {
+			Fatalf("exporter: invalid symbol name: %s", s.Name)
+		}
 		return s.Name
 	}
 	return ""
 }
 
-func (p *exporter) paramList(params *Type) {
-	if params.Etype != TSTRUCT || !params.Funarg {
-		Fatalf("parameter list expected")
+func (p *exporter) paramList(params *Type, numbered bool) {
+	if !params.IsFuncArgStruct() {
+		Fatalf("exporter: parameter list expected")
 	}
 
 	// use negative length to indicate unnamed parameters
 	// (look at the first parameter only since either all
 	// names are present or all are absent)
-	n := countfield(params)
-	if n > 0 && parName(params.Type) == "" {
+	//
+	// TODO(gri) If we don't have an exported function
+	// body, the parameter names are irrelevant for the
+	// compiler (though they may be of use for other tools).
+	// Possible space optimization.
+	n := params.NumFields()
+	if n > 0 && parName(params.Field(0), numbered) == "" {
 		n = -n
 	}
 	p.int(n)
-	for q := params.Type; q != nil; q = q.Down {
-		p.param(q, n)
+	for _, q := range params.Fields().Slice() {
+		p.param(q, n, numbered)
 	}
 }
 
-func (p *exporter) param(q *Type, n int) {
-	if q.Etype != TFIELD {
-		Fatalf("parameter expected")
-	}
+func (p *exporter) param(q *Field, n int, numbered bool) {
 	t := q.Type
 	if q.Isddd {
 		// create a fake type to encode ... just for the p.typ call
-		// (T_old_DARRAY is not used anywhere else in the compiler,
-		// we use it here to communicate between p.param and p.typ.)
-		t = &Type{Etype: T_old_DARRAY, Type: t.Type}
+		t = typDDDField(t.Elem())
 	}
 	p.typ(t)
 	if n > 0 {
-		p.string(parName(q))
+		name := parName(q, numbered)
+		if name == "" {
+			// Sometimes we see an empty name even for n > 0.
+			// This appears to happen for interface methods
+			// with _ (blank) parameter names. Make sure we
+			// have a proper name and package so we don't crash
+			// during import (see also issue #15470).
+			// (parName uses "" instead of "?" as in fmt.go)
+			// TODO(gri) review parameter name encoding
+			name = "_"
+		}
+		p.string(name)
+		if name != "_" {
+			// Because of (re-)exported inlined functions
+			// the importpkg may not be the package to which this
+			// function (and thus its parameter) belongs. We need to
+			// supply the parameter package here. We need the package
+			// when the function is inlined so we can properly resolve
+			// the name. The _ (blank) parameter cannot be accessed, so
+			// we don't need to export a package.
+			//
+			// TODO(gri) This is compiler-specific. Try using importpkg
+			// here and then update the symbols if we find an inlined
+			// body only. Otherwise, the parameter name is ignored and
+			// the package doesn't matter. This would remove an int
+			// (likely 1 byte) for each named parameter.
+			p.pkg(q.Sym.Pkg)
+		}
 	}
 	// TODO(gri) This is compiler-specific (escape info).
 	// Move into compiler-specific section eventually?
 	// (Not having escape info causes tests to fail, e.g. runtime GCInfoTest)
-	p.note(q.Note)
+	p.string(q.Note)
 }
 
-func parName(q *Type) string {
-	if q.Sym == nil {
+func parName(f *Field, numbered bool) string {
+	s := f.Sym
+	if s == nil {
 		return ""
 	}
-	name := q.Sym.Name
-	// undo gc-internal name mangling - we just need the source name
-	if len(name) > 0 && name[0] == '~' {
-		// name is ~b%d or ~r%d
-		switch name[1] {
-		case 'b':
-			return "_"
-		case 'r':
-			return ""
-		default:
-			Fatalf("unexpected parameter name: %s", name)
+
+	// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
+	// ~r%d is a (formerly) unnamed result.
+	if f.Nname != nil {
+		if f.Nname.Orig != nil {
+			s = f.Nname.Orig.Sym
+			if s != nil && s.Name[0] == '~' {
+				if s.Name[1] == 'r' { // originally an unnamed result
+					return "" // s = nil
+				} else if s.Name[1] == 'b' { // originally the blank identifier _
+					return "_" // belongs to localpkg
+				}
+			}
+		} else {
+			return "" // s = nil
 		}
 	}
-	// undo gc-internal name specialization
-	if i := strings.Index(name, "·"); i > 0 {
-		name = name[:i] // cut off numbering
+
+	if s == nil {
+		return ""
+	}
+
+	// print symbol with Vargen number or not as desired
+	name := s.Name
+	if strings.Contains(name, ".") {
+		Fatalf("invalid symbol name: %s", name)
+	}
+
+	// Functions that can be inlined use numbered parameters so we can distingish them
+	// from other names in their context after inlining (i.e., the parameter numbering
+	// is a form of parameter rewriting). See issue 4326 for an example and test case.
+	if forceObjFileStability || numbered {
+		if !strings.Contains(name, "·") && f.Nname != nil && f.Nname.Name != nil && f.Nname.Name.Vargen > 0 {
+			name = fmt.Sprintf("%s·%d", name, f.Nname.Name.Vargen) // append Vargen
+		}
+	} else {
+		if i := strings.Index(name, "·"); i > 0 {
+			name = name[:i] // cut off Vargen
+		}
 	}
 	return name
 }
@@ -681,17 +1034,17 @@ func (p *exporter) value(x Val) {
 		p.tag(tag)
 
 	case *Mpint:
-		if Mpcmpfixfix(Minintval[TINT64], x) <= 0 && Mpcmpfixfix(x, Maxintval[TINT64]) <= 0 {
+		if Minintval[TINT64].Cmp(x) <= 0 && x.Cmp(Maxintval[TINT64]) <= 0 {
 			// common case: x fits into an int64 - use compact encoding
 			p.tag(int64Tag)
-			p.int64(Mpgetfix(x))
+			p.int64(x.Int64())
 			return
 		}
 		// uncommon case: large x - use float encoding
 		// (powers of 2 will be encoded efficiently with exponent)
-		p.tag(floatTag)
 		f := newMpflt()
-		Mpmovefixflt(f, x)
+		f.SetInt(x)
+		p.tag(floatTag)
 		p.float(f)
 
 	case *Mpflt:
@@ -707,8 +1060,12 @@ func (p *exporter) value(x Val) {
 		p.tag(stringTag)
 		p.string(x)
 
+	case *NilVal:
+		// not a constant but used in exported function bodies
+		p.tag(nilTag)
+
 	default:
-		Fatalf("unexpected value %v (%T)", x, x)
+		Fatalf("exporter: unexpected value %v (%T)", x, x)
 	}
 }
 
@@ -733,7 +1090,7 @@ func (p *exporter) float(x *Mpflt) {
 	m.SetMantExp(&m, int(m.MinPrec()))
 	mant, acc := m.Int(nil)
 	if acc != big.Exact {
-		Fatalf("internal error")
+		Fatalf("exporter: internal error")
 	}
 
 	p.int(sign)
@@ -744,37 +1101,532 @@ func (p *exporter) float(x *Mpflt) {
 // ----------------------------------------------------------------------------
 // Inlined function bodies
 
-// TODO(gri) This section is incomplete. At the moment nothing meaningful
-// is written out for exported functions with inlined function bodies.
+// Approach: More or less closely follow what fmt.go is doing for FExp mode
+// but instead of emitting the information textually, emit the node tree in
+// binary form.
 
-func (p *exporter) collectInlined(n *Node) int {
-	if n != nil && 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)
+// TODO(gri) Improve tracing output. The current format is difficult to read.
+
+// stmtList may emit more (or fewer) than len(list) nodes.
+func (p *exporter) stmtList(list Nodes) {
+	if p.trace {
+		if list.Len() == 0 {
+			p.tracef("{}")
+		} else {
+			p.tracef("{>")
+			defer p.tracef("<\n}")
+		}
+	}
+
+	for _, n := range list.Slice() {
+		if p.trace {
+			p.tracef("\n")
+		}
+		// TODO inlining produces expressions with ninits. we can't export these yet.
+		// (from fmt.go:1461ff)
+		if opprec[n.Op] < 0 {
+			p.stmt(n)
+		} else {
+			p.expr(n)
 		}
-		p.inlined = append(p.inlined, n.Func)
-		return len(p.inlined) - 1 // index >= 0 => inlined
 	}
-	return -1 // index < 0 => not inlined
+
+	p.op(OEND)
 }
 
-func (p *exporter) body(i int, f *Func) {
-	p.int(i)
-	p.block(f.Inl)
+func (p *exporter) exprList(list Nodes) {
+	if p.trace {
+		if list.Len() == 0 {
+			p.tracef("{}")
+		} else {
+			p.tracef("{>")
+			defer p.tracef("<\n}")
+		}
+	}
+
+	for _, n := range list.Slice() {
+		if p.trace {
+			p.tracef("\n")
+		}
+		p.expr(n)
+	}
+
+	p.op(OEND)
 }
 
-func (p *exporter) block(list *NodeList) {
-	p.int(count(list))
-	for q := list; q != nil; q = q.Next {
-		p.stmt(q.N)
+func (p *exporter) elemList(list Nodes) {
+	if p.trace {
+		p.tracef("[ ")
+	}
+	p.int(list.Len())
+	if p.trace {
+		if list.Len() == 0 {
+			p.tracef("] {}")
+		} else {
+			p.tracef("] {>")
+			defer p.tracef("<\n}")
+		}
+	}
+
+	for _, n := range list.Slice() {
+		if p.trace {
+			p.tracef("\n")
+		}
+		p.fieldSym(n.Left.Sym, false)
+		p.expr(n.Right)
 	}
 }
 
+func (p *exporter) expr(n *Node) {
+	if p.trace {
+		p.tracef("( ")
+		defer p.tracef(") ")
+	}
+
+	// from nodefmt (fmt.go)
+	//
+	// nodefmt reverts nodes back to their original - we don't need to do
+	// it because we are not bound to produce valid Go syntax when exporting
+	//
+	// if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
+	// 	n = n.Orig
+	// }
+
+	// from exprfmt (fmt.go)
+	for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
+		n = n.Left
+	}
+
+	switch op := n.Op; op {
+	// expressions
+	// (somewhat closely following the structure of exprfmt in fmt.go)
+	case OPAREN:
+		p.expr(n.Left) // unparen
+
+	// case ODDDARG:
+	//	unimplemented - handled by default case
+
+	// case OREGISTER:
+	//	unimplemented - handled by default case
+
+	case OLITERAL:
+		if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
+			p.expr(n.Orig)
+			break
+		}
+		p.op(OLITERAL)
+		p.typ(unidealType(n.Type, n.Val()))
+		p.value(n.Val())
+
+	case ONAME:
+		// Special case: name used as local variable in export.
+		// _ becomes ~b%d internally; print as _ for export
+		if n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
+			p.op(ONAME)
+			p.string("_") // inlined and customized version of p.sym(n)
+			break
+		}
+
+		if n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
+			p.op(ONAME)
+			p.sym(n)
+			break
+		}
+
+		// 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 n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
+			p.op(OXDOT)
+			p.expr(n.Left) // n.Left.Op == OTYPE
+			p.fieldSym(n.Right.Sym, true)
+			break
+		}
+
+		p.op(ONAME)
+		p.sym(n)
+
+	// case OPACK, ONONAME:
+	// 	should have been resolved by typechecking - handled by default case
+
+	case OTYPE:
+		p.op(OTYPE)
+		if p.bool(n.Type == nil) {
+			p.sym(n)
+		} else {
+			p.typ(n.Type)
+		}
+
+	// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
+	// 	should have been resolved by typechecking - handled by default case
+
+	// case OCLOSURE:
+	//	unimplemented - handled by default case
+
+	// case OCOMPLIT:
+	// 	should have been resolved by typechecking - handled by default case
+
+	case OPTRLIT:
+		p.op(OPTRLIT)
+		p.expr(n.Left)
+		p.bool(n.Implicit)
+
+	case OSTRUCTLIT:
+		p.op(OSTRUCTLIT)
+		p.typ(n.Type)
+		p.elemList(n.List) // special handling of field names
+
+	case OARRAYLIT, OMAPLIT:
+		p.op(OCOMPLIT)
+		p.typ(n.Type)
+		p.exprList(n.List)
+
+	case OKEY:
+		p.op(OKEY)
+		p.exprsOrNil(n.Left, n.Right)
+
+	// case OCALLPART:
+	//	unimplemented - handled by default case
+
+	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
+		p.op(OXDOT)
+		p.expr(n.Left)
+		p.fieldSym(n.Sym, true)
+
+	case ODOTTYPE, ODOTTYPE2:
+		p.op(ODOTTYPE)
+		p.expr(n.Left)
+		if p.bool(n.Right != nil) {
+			p.expr(n.Right)
+		} else {
+			p.typ(n.Type)
+		}
+
+	case OINDEX, OINDEXMAP:
+		p.op(OINDEX)
+		p.expr(n.Left)
+		p.expr(n.Right)
+
+	case OSLICE, OSLICESTR, OSLICEARR:
+		p.op(OSLICE)
+		p.expr(n.Left)
+		low, high, _ := n.SliceBounds()
+		p.exprsOrNil(low, high)
+
+	case OSLICE3, OSLICE3ARR:
+		p.op(OSLICE3)
+		p.expr(n.Left)
+		low, high, max := n.SliceBounds()
+		p.exprsOrNil(low, high)
+		p.expr(max)
+
+	case OCOPY, OCOMPLEX:
+		// treated like other builtin calls (see e.g., OREAL)
+		p.op(op)
+		p.expr(n.Left)
+		p.expr(n.Right)
+		p.op(OEND)
+
+	case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
+		p.op(OCONV)
+		p.typ(n.Type)
+		if n.Left != nil {
+			p.expr(n.Left)
+			p.op(OEND)
+		} else {
+			p.exprList(n.List) // emits terminating OEND
+		}
+
+	case OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
+		p.op(op)
+		if n.Left != nil {
+			p.expr(n.Left)
+			p.op(OEND)
+		} else {
+			p.exprList(n.List) // emits terminating OEND
+		}
+		// only append() calls may contain '...' arguments
+		if op == OAPPEND {
+			p.bool(n.Isddd)
+		} else if n.Isddd {
+			Fatalf("exporter: unexpected '...' with %s call", opnames[op])
+		}
+
+	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
+		p.op(OCALL)
+		p.expr(n.Left)
+		p.exprList(n.List)
+		p.bool(n.Isddd)
+
+	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
+		p.op(op) // must keep separate from OMAKE for importer
+		p.typ(n.Type)
+		switch {
+		default:
+			// empty list
+			p.op(OEND)
+		case n.List.Len() != 0: // pre-typecheck
+			p.exprList(n.List) // emits terminating OEND
+		case n.Right != nil:
+			p.expr(n.Left)
+			p.expr(n.Right)
+			p.op(OEND)
+		case n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()):
+			p.expr(n.Left)
+			p.op(OEND)
+		}
+
+	// unary expressions
+	case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
+		p.op(op)
+		p.expr(n.Left)
+
+	// binary expressions
+	case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
+		OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
+		p.op(op)
+		p.expr(n.Left)
+		p.expr(n.Right)
+
+	case OADDSTR:
+		p.op(OADDSTR)
+		p.exprList(n.List)
+
+	case OCMPSTR, OCMPIFACE:
+		p.op(Op(n.Etype))
+		p.expr(n.Left)
+		p.expr(n.Right)
+
+	case ODCLCONST:
+		// if exporting, DCLCONST should just be removed as its usage
+		// has already been replaced with literals
+		// TODO(gri) these should not be exported in the first place
+		// TODO(gri) why is this considered an expression in fmt.go?
+		p.op(ODCLCONST)
+
+	default:
+		Fatalf("cannot export %s (%d) node\n"+
+			"==> please file an issue and assign to gri@\n", n.Op, n.Op)
+	}
+}
+
+// Caution: stmt will emit more than one node for statement nodes n that have a non-empty
+// n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.).
 func (p *exporter) stmt(n *Node) {
-	// TODO(gri) do something sensible here
-	p.string("body")
+	if p.trace {
+		p.tracef("( ")
+		defer p.tracef(") ")
+	}
+
+	if n.Ninit.Len() > 0 && !stmtwithinit(n.Op) {
+		if p.trace {
+			p.tracef("( /* Ninits */ ")
+		}
+
+		// can't use stmtList here since we don't want the final OEND
+		for _, n := range n.Ninit.Slice() {
+			p.stmt(n)
+		}
+
+		if p.trace {
+			p.tracef(") ")
+		}
+	}
+
+	switch op := n.Op; op {
+	case ODCL:
+		p.op(ODCL)
+		switch n.Left.Class {
+		case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
+			// TODO(gri) when is this not PAUTO?
+			// Also, originally this didn't look like
+			// the default case. Investigate.
+			fallthrough
+		default:
+			// TODO(gri) Can we ever reach here?
+			p.bool(false)
+			p.sym(n.Left)
+		}
+		p.typ(n.Left.Type)
+
+	// case ODCLFIELD:
+	//	unimplemented - handled by default case
+
+	case OAS, OASWB:
+		// 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 n.Right != nil {
+			p.op(OAS)
+			p.expr(n.Left)
+			p.expr(n.Right)
+		}
+
+	case OASOP:
+		p.op(OASOP)
+		p.int(int(n.Etype))
+		p.expr(n.Left)
+		if p.bool(!n.Implicit) {
+			p.expr(n.Right)
+		}
+
+	case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+		p.op(OAS2)
+		p.exprList(n.List)
+		p.exprList(n.Rlist)
+
+	case ORETURN:
+		p.op(ORETURN)
+		p.exprList(n.List)
+
+	// case ORETJMP:
+	// 	unreachable - generated by compiler for trampolin routines
+
+	case OPROC, ODEFER:
+		p.op(op)
+		p.expr(n.Left)
+
+	case OIF:
+		p.op(OIF)
+		p.stmtList(n.Ninit)
+		p.expr(n.Left)
+		p.stmtList(n.Nbody)
+		p.stmtList(n.Rlist)
+
+	case OFOR:
+		p.op(OFOR)
+		p.stmtList(n.Ninit)
+		p.exprsOrNil(n.Left, n.Right)
+		p.stmtList(n.Nbody)
+
+	case ORANGE:
+		p.op(ORANGE)
+		p.stmtList(n.List)
+		p.expr(n.Right)
+		p.stmtList(n.Nbody)
+
+	case OSELECT, OSWITCH:
+		p.op(op)
+		p.stmtList(n.Ninit)
+		p.exprsOrNil(n.Left, nil)
+		p.stmtList(n.List)
+
+	case OCASE, OXCASE:
+		p.op(OXCASE)
+		p.stmtList(n.List)
+		p.stmtList(n.Nbody)
+
+	case OFALL, OXFALL:
+		p.op(OXFALL)
+
+	case OBREAK, OCONTINUE:
+		p.op(op)
+		p.exprsOrNil(n.Left, nil)
+
+	case OEMPTY:
+		// nothing to emit
+
+	case OGOTO, OLABEL:
+		p.op(op)
+		p.expr(n.Left)
+
+	default:
+		Fatalf("exporter: CANNOT EXPORT: %s\nPlease notify gri@\n", n.Op)
+	}
+}
+
+func (p *exporter) exprsOrNil(a, b *Node) {
+	ab := 0
+	if a != nil {
+		ab |= 1
+	}
+	if b != nil {
+		ab |= 2
+	}
+	p.int(ab)
+	if ab&1 != 0 {
+		p.expr(a)
+	}
+	if ab&2 != 0 {
+		p.expr(b)
+	}
+}
+
+func (p *exporter) fieldSym(s *Sym, short bool) {
+	name := s.Name
+
+	// remove leading "type." in method names ("(T).m" -> "m")
+	if short {
+		if i := strings.LastIndex(name, "."); i >= 0 {
+			name = name[i+1:]
+		}
+	}
+
+	// we should never see a _ (blank) here - these are accessible ("read") fields
+	// TODO(gri) can we assert this with an explicit check?
+	p.string(name)
+	if !exportname(name) {
+		p.pkg(s.Pkg)
+	}
+}
+
+// sym must encode the _ (blank) identifier as a single string "_" since
+// encoding for some nodes is based on this assumption (e.g. ONAME nodes).
+func (p *exporter) sym(n *Node) {
+	s := n.Sym
+	if s.Pkg != nil {
+		if len(s.Name) > 0 && s.Name[0] == '.' {
+			Fatalf("exporter: exporting synthetic symbol %s", s.Name)
+		}
+	}
+
+	if p.trace {
+		p.tracef("{ SYM ")
+		defer p.tracef("} ")
+	}
+
+	name := s.Name
+
+	// remove leading "type." in method names ("(T).m" -> "m")
+	if i := strings.LastIndex(name, "."); i >= 0 {
+		name = name[i+1:]
+	}
+
+	if strings.Contains(name, "·") && n.Name.Vargen > 0 {
+		Fatalf("exporter: unexpected · in symbol name")
+	}
+
+	if i := n.Name.Vargen; i > 0 {
+		name = fmt.Sprintf("%s·%d", name, i)
+	}
+
+	p.string(name)
+	if name != "_" {
+		p.pkg(s.Pkg)
+	}
+}
+
+func (p *exporter) bool(b bool) bool {
+	if p.trace {
+		p.tracef("[")
+		defer p.tracef("= %v] ", b)
+	}
+
+	x := 0
+	if b {
+		x = 1
+	}
+	p.int(x)
+	return b
+}
+
+func (p *exporter) op(op Op) {
+	if p.trace {
+		p.tracef("[")
+		defer p.tracef("= %s] ", op)
+	}
+
+	p.int(int(op))
 }
 
 // ----------------------------------------------------------------------------
@@ -782,7 +1634,7 @@ func (p *exporter) stmt(n *Node) {
 
 func (p *exporter) index(marker byte, index int) {
 	if index < 0 {
-		Fatalf("invalid index < 0")
+		Fatalf("exporter: invalid index < 0")
 	}
 	if debugFormat {
 		p.marker('t')
@@ -795,7 +1647,7 @@ func (p *exporter) index(marker byte, index int) {
 
 func (p *exporter) tag(tag int) {
 	if tag >= 0 {
-		Fatalf("invalid tag >= 0")
+		Fatalf("exporter: invalid tag >= 0")
 	}
 	if debugFormat {
 		p.marker('t')
@@ -827,17 +1679,30 @@ func (p *exporter) string(s string) {
 	if p.trace {
 		p.tracef("%q ", s)
 	}
-	p.rawInt64(int64(len(s)))
+	// if we saw the string before, write its index (>= 0)
+	// (the empty string is mapped to 0)
+	if i, ok := p.strIndex[s]; ok {
+		p.rawInt64(int64(i))
+		return
+	}
+	// otherwise, remember string and write its negative length and bytes
+	p.strIndex[s] = len(p.strIndex)
+	p.rawInt64(-int64(len(s)))
 	for i := 0; i < len(s); i++ {
-		p.byte(s[i])
+		p.rawByte(s[i])
 	}
 }
 
 // marker emits a marker byte and position information which makes
-// it easy for a reader to detect if it is "out of sync". Used for
-// debugFormat format only.
+// it easy for a reader to detect if it is "out of sync". Used only
+// if debugFormat is set.
 func (p *exporter) marker(m byte) {
-	p.byte(m)
+	p.rawByte(m)
+	// Uncomment this for help tracking down the location
+	// of an incorrect marker when running in debugFormat.
+	// if p.trace {
+	// 	p.tracef("#%d ", p.written)
+	// }
 	p.rawInt64(int64(p.written))
 }
 
@@ -846,12 +1711,12 @@ func (p *exporter) rawInt64(x int64) {
 	var tmp [binary.MaxVarintLen64]byte
 	n := binary.PutVarint(tmp[:], x)
 	for i := 0; i < n; i++ {
-		p.byte(tmp[i])
+		p.rawByte(tmp[i])
 	}
 }
 
-// byte is the bottleneck interface to write to p.out.
-// byte escapes b as follows (any encoding does that
+// rawByte is the bottleneck interface to write to p.out.
+// rawByte escapes b as follows (any encoding does that
 // hides '$'):
 //
 //	'$'  => '|' 'S'
@@ -859,7 +1724,8 @@ func (p *exporter) rawInt64(x int64) {
 //
 // Necessary so other tools can find the end of the
 // export data by searching for "$$".
-func (p *exporter) byte(b byte) {
+// rawByte should only be used by low-level encoders.
+func (p *exporter) rawByte(b byte) {
 	switch b {
 	case '$':
 		// write '$' as '|' 'S'
@@ -867,17 +1733,17 @@ func (p *exporter) byte(b byte) {
 		fallthrough
 	case '|':
 		// write '|' as '|' '|'
-		obj.Bputc(p.out, '|')
+		p.out.WriteByte('|')
 		p.written++
 	}
-	obj.Bputc(p.out, b)
+	p.out.WriteByte(b)
 	p.written++
 }
 
 // tracef is like fmt.Printf but it rewrites the format string
 // to take care of indentation.
 func (p *exporter) tracef(format string, args ...interface{}) {
-	if strings.IndexAny(format, "<>\n") >= 0 {
+	if strings.ContainsAny(format, "<>\n") {
 		var buf bytes.Buffer
 		for i := 0; i < len(format); i++ {
 			// no need to deal with runes
@@ -907,8 +1773,13 @@ func (p *exporter) tracef(format string, args ...interface{}) {
 
 // Tags. Must be < 0.
 const (
-	// Packages
+	// Objects
 	packageTag = -(iota + 1)
+	constTag
+	typeTag
+	varTag
+	funcTag
+	endTag
 
 	// Types
 	namedTag
@@ -930,15 +1801,22 @@ const (
 	fractionTag // not used by gc
 	complexTag
 	stringTag
+	nilTag
+	unknownTag // not used by gc (only appears in packages with errors)
 )
 
 // Debugging support.
 // (tagString is only used when tracing is enabled)
 var tagString = [...]string{
-	// Packages:
+	// Objects
 	-packageTag: "package",
+	-constTag:   "const",
+	-typeTag:    "type",
+	-varTag:     "var",
+	-funcTag:    "func",
+	-endTag:     "end",
 
-	// Types:
+	// Types
 	-namedTag:     "named type",
 	-arrayTag:     "array",
 	-sliceTag:     "slice",
@@ -950,7 +1828,7 @@ var tagString = [...]string{
 	-mapTag:       "map",
 	-chanTag:      "chan",
 
-	// Values:
+	// Values
 	-falseTag:    "false",
 	-trueTag:     "true",
 	-int64Tag:    "int64",
@@ -958,6 +1836,8 @@ var tagString = [...]string{
 	-fractionTag: "fraction",
 	-complexTag:  "complex",
 	-stringTag:   "string",
+	-nilTag:      "nil",
+	-unknownTag:  "unknown",
 }
 
 // untype returns the "pseudo" untyped type for a Ctype (import/export use only).
@@ -980,17 +1860,10 @@ func untype(ctype Ctype) *Type {
 	case CTNIL:
 		return Types[TNIL]
 	}
-	Fatalf("unknown Ctype")
+	Fatalf("exporter: unknown Ctype")
 	return nil
 }
 
-var (
-	idealint     = typ(TIDEAL)
-	idealrune    = typ(TIDEAL)
-	idealfloat   = typ(TIDEAL)
-	idealcomplex = typ(TIDEAL)
-)
-
 var predecl []*Type // initialized lazily
 
 func predeclared() []*Type {
@@ -1035,6 +1908,12 @@ func predeclared() []*Type {
 
 			// package unsafe
 			Types[TUNSAFEPTR],
+
+			// invalid type (package contains errors)
+			Types[Txxx],
+
+			// any type, for builtin export data
+			Types[TANY],
 		}
 	}
 	return predecl
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 731f31b..2b666cc 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -3,14 +3,16 @@
 // license that can be found in the LICENSE file.
 
 // Binary package import.
-// Based loosely on x/tools/go/importer.
+// See bexport.go for the export data format and how
+// to make a format change.
 
 package gc
 
 import (
+	"bufio"
 	"cmd/compile/internal/big"
-	"cmd/internal/obj"
 	"encoding/binary"
+	"fmt"
 )
 
 // The overall structure of Import is symmetric to Export: For each
@@ -18,25 +20,57 @@ import (
 // in bimport.go. Changing the export format requires making symmetric
 // changes to bimport.go and bexport.go.
 
+type importer struct {
+	in      *bufio.Reader
+	buf     []byte // reused for reading strings
+	version string
+
+	// object lists, in order of deserialization
+	strList       []string
+	pkgList       []*Pkg
+	typList       []*Type
+	funcList      []*Node // nil entry means already declared
+	trackAllTypes bool
+
+	// for delayed type verification
+	cmpList []struct{ pt, t *Type }
+
+	// position encoding
+	posInfoFormat bool
+	prevFile      string
+	prevLine      int
+
+	// debugging support
+	debugFormat bool
+	read        int // bytes read
+}
+
 // Import populates importpkg from the serialized package data.
-func Import(in *obj.Biobuf) {
-	p := importer{in: in}
-	p.buf = p.bufarray[:]
+func Import(in *bufio.Reader) {
+	p := importer{
+		in:      in,
+		strList: []string{""}, // empty string is mapped to 0
+	}
 
 	// read low-level encoding format
-	switch format := p.byte(); format {
+	switch format := p.rawByte(); format {
 	case 'c':
 		// compact format - nothing to do
 	case 'd':
 		p.debugFormat = true
 	default:
-		Fatalf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
+		Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format)
 	}
 
+	p.trackAllTypes = p.rawByte() == 'a'
+
+	p.posInfoFormat = p.bool()
+
 	// --- generic export data ---
 
-	if v := p.string(); v != exportVersion {
-		Fatalf("unknown export data version: %s", v)
+	p.version = p.string()
+	if p.version != exportVersion0 && p.version != exportVersion1 {
+		Fatalf("importer: unknown export data version: %s", p.version)
 	}
 
 	// populate typList with predeclared "known" types
@@ -44,74 +78,116 @@ func Import(in *obj.Biobuf) {
 
 	// read package data
 	p.pkg()
-	if p.pkgList[0] != importpkg {
-		Fatalf("imported package not found in pkgList[0]")
-	}
-
-	// read compiler-specific flags
-	importpkg.Safe = p.string() == "safe"
 
 	// defer some type-checking until all types are read in completely
-	// (go.y:import_there)
+	// (parser.go:import_package)
 	tcok := typecheckok
 	typecheckok = true
 	defercheckwidth()
 
-	// read consts
-	for i := p.int(); i > 0; i-- {
-		sym := p.localname()
-		typ := p.typ()
-		val := p.value(typ)
-		if isideal(typ) {
-			// canonicalize ideal types
-			typ = Types[TIDEAL]
+	// read objects
+
+	// phase 1
+	objcount := 0
+	for {
+		tag := p.tagOrIndex()
+		if tag == endTag {
+			break
 		}
-		importconst(sym, typ, nodlit(val))
+		p.obj(tag)
+		objcount++
 	}
 
-	// read vars
-	for i := p.int(); i > 0; i-- {
-		sym := p.localname()
-		typ := p.typ()
-		importvar(sym, typ)
+	// self-verification
+	if count := p.int(); count != objcount {
+		Fatalf("importer: got %d objects; want %d", objcount, count)
 	}
 
-	// read funcs
-	for i := p.int(); i > 0; i-- {
-		// go.y:hidden_fndcl
-		sym := p.localname()
-		typ := p.typ()
-		// TODO(gri) fix this
-		p.int() // read and discard index of inlined function body for now
+	// --- compiler-specific export data ---
 
-		importsym(sym, ONAME)
-		if sym.Def != nil && sym.Def.Op == ONAME && !Eqtype(typ, sym.Def.Type) {
-			Fatalf("inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, typ)
+	// read compiler-specific flags
+
+	// read but ignore safemode bit (see issue #15772)
+	p.bool() // formerly: importpkg.Safe = p.bool()
+
+	// phase 2
+	objcount = 0
+	for {
+		tag := p.tagOrIndex()
+		if tag == endTag {
+			break
 		}
+		p.obj(tag)
+		objcount++
+	}
 
-		n := newfuncname(sym)
-		n.Type = typ
-		declare(n, PFUNC)
-		funchdr(n)
+	// self-verification
+	if count := p.int(); count != objcount {
+		Fatalf("importer: got %d objects; want %d", objcount, count)
+	}
 
-		// go.y:hidden_import
-		n.Func.Inl = nil
-		funcbody(n)
-		importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
+	// read inlineable functions bodies
+	if dclcontext != PEXTERN {
+		Fatalf("importer: unexpected context %d", dclcontext)
 	}
 
-	// read types
-	for i := p.int(); i > 0; i-- {
-		// name is parsed as part of named type
-		p.typ()
+	objcount = 0
+	for i0 := -1; ; {
+		i := p.int() // index of function with inlineable body
+		if i < 0 {
+			break
+		}
+
+		// don't process the same function twice
+		if i <= i0 {
+			Fatalf("importer: index not increasing: %d <= %d", i, i0)
+		}
+		i0 = i
+
+		if Funcdepth != 0 {
+			Fatalf("importer: unexpected Funcdepth %d", Funcdepth)
+		}
+
+		// Note: In the original code, funchdr and funcbody are called for
+		// all functions (that were not yet imported). Now, we are calling
+		// them only for functions with inlineable bodies. funchdr does
+		// parameter renaming which doesn't matter if we don't have a body.
+
+		if f := p.funcList[i]; f != nil {
+			// function not yet imported - read body and set it
+			funchdr(f)
+			body := p.stmtList()
+			if body == nil {
+				// Make sure empty body is not interpreted as
+				// no inlineable body (see also parser.fnbody)
+				// (not doing so can cause significant performance
+				// degradation due to unnecessary calls to empty
+				// functions).
+				body = []*Node{Nod(OEMPTY, nil, nil)}
+			}
+			f.Func.Inl.Set(body)
+			funcbody(f)
+		} else {
+			// function already imported - read body but discard declarations
+			dclcontext = PDISCARD // throw away any declarations
+			p.stmtList()
+			dclcontext = PEXTERN
+		}
+
+		objcount++
 	}
 
-	// --- compiler-specific export data ---
+	// self-verification
+	if count := p.int(); count != objcount {
+		Fatalf("importer: got %d functions; want %d", objcount, count)
+	}
 
-	for i := p.int(); i > 0; i-- {
-		p.body()
+	if dclcontext != PEXTERN {
+		Fatalf("importer: unexpected context %d", dclcontext)
 	}
 
+	p.verifyTypes()
+
 	// --- end of export data ---
 
 	typecheckok = tcok
@@ -120,15 +196,17 @@ func Import(in *obj.Biobuf) {
 	testdclstack() // debugging only
 }
 
-type importer struct {
-	in       *obj.Biobuf
-	buf      []byte   // for reading strings
-	bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
-	pkgList  []*Pkg
-	typList  []*Type
-
-	debugFormat bool
-	read        int // bytes read
+func (p *importer) verifyTypes() {
+	for _, pair := range p.cmpList {
+		pt := pair.pt
+		t := pair.t
+		if !Eqtype(pt.Orig, t) {
+			// TODO(gri) Is this a possible regular error (stale files)
+			// or can this only happen if export/import is flawed?
+			// (if the latter, change to Fatalf here)
+			Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, FmtLong), pt.Sym.Importdef.Path, Tconv(t, FmtLong), importpkg.Path)
+		}
+	}
 }
 
 func (p *importer) pkg() *Pkg {
@@ -140,7 +218,7 @@ func (p *importer) pkg() *Pkg {
 
 	// otherwise, i is the package tag (< 0)
 	if i != packageTag {
-		Fatalf("expected package tag, found tag = %d", i)
+		Fatalf("importer: expected package tag, found tag = %d", i)
 	}
 
 	// read package data
@@ -149,45 +227,162 @@ func (p *importer) pkg() *Pkg {
 
 	// we should never see an empty package name
 	if name == "" {
-		Fatalf("empty package name in import")
+		Fatalf("importer: empty package name for path %q", path)
 	}
 
 	// we should never see a bad import path
 	if isbadimport(path) {
-		Fatalf("bad path in import: %q", path)
+		Fatalf("importer: bad package path %q for package %s", path, name)
+	}
+
+	// an empty path denotes the package we are currently importing;
+	// it must be the first package we see
+	if (path == "") != (len(p.pkgList) == 0) {
+		Fatalf("importer: package path %q for pkg index %d", path, len(p.pkgList))
 	}
 
-	// an empty path denotes the package we are currently importing
+	// see importimport (export.go)
 	pkg := importpkg
 	if path != "" {
 		pkg = mkpkg(path)
 	}
 	if pkg.Name == "" {
 		pkg.Name = name
+		numImport[name]++
 	} else if pkg.Name != name {
-		Fatalf("inconsistent package names: got %s; want %s (path = %s)", pkg.Name, name, path)
+		Yyerror("importer: conflicting package names %s and %s for path %q", pkg.Name, name, path)
+	}
+	if incannedimport == 0 && myimportpath != "" && path == myimportpath {
+		Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
+		errorexit()
 	}
 	p.pkgList = append(p.pkgList, pkg)
 
 	return pkg
 }
 
-func (p *importer) localname() *Sym {
-	// go.y:hidden_importsym
-	name := p.string()
-	if name == "" {
-		Fatalf("unexpected anonymous name")
+func idealType(typ *Type) *Type {
+	if typ.IsUntyped() {
+		// canonicalize ideal types
+		typ = Types[TIDEAL]
+	}
+	return typ
+}
+
+func (p *importer) obj(tag int) {
+	switch tag {
+	case constTag:
+		p.pos()
+		sym := p.qualifiedName()
+		typ := p.typ()
+		val := p.value(typ)
+		importconst(sym, idealType(typ), nodlit(val))
+
+	case typeTag:
+		p.typ()
+
+	case varTag:
+		p.pos()
+		sym := p.qualifiedName()
+		typ := p.typ()
+		importvar(sym, typ)
+
+	case funcTag:
+		p.pos()
+		sym := p.qualifiedName()
+		params := p.paramList()
+		result := p.paramList()
+
+		sig := functype(nil, params, result)
+		importsym(sym, ONAME)
+		if sym.Def != nil && sym.Def.Op == ONAME {
+			// function was imported before (via another import)
+			if !Eqtype(sig, sym.Def.Type) {
+				Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
+			}
+			p.funcList = append(p.funcList, nil)
+			break
+		}
+
+		n := newfuncname(sym)
+		n.Type = sig
+		declare(n, PFUNC)
+		p.funcList = append(p.funcList, n)
+		importlist = append(importlist, n)
+
+		if Debug['E'] > 0 {
+			fmt.Printf("import [%q] func %v \n", importpkg.Path, n)
+			if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
+				fmt.Printf("inl body: %v\n", n.Func.Inl)
+			}
+		}
+
+	default:
+		Fatalf("importer: unexpected object (tag = %d)", tag)
 	}
-	structpkg = importpkg // go.y:hidden_pkg_importsym
-	return importpkg.Lookup(name)
+}
+
+func (p *importer) pos() {
+	if !p.posInfoFormat {
+		return
+	}
+
+	file := p.prevFile
+	line := p.prevLine
+	if delta := p.int(); delta != 0 {
+		// line changed
+		line += delta
+	} else if n := p.int(); n >= 0 {
+		// file changed
+		file = p.prevFile[:n] + p.string()
+		p.prevFile = file
+		line = p.int()
+	}
+	p.prevLine = line
+
+	// TODO(gri) register new position
 }
 
 func (p *importer) newtyp(etype EType) *Type {
 	t := typ(etype)
-	p.typList = append(p.typList, t)
+	if p.trackAllTypes {
+		p.typList = append(p.typList, t)
+	}
 	return t
 }
 
+// This is like the function importtype but it delays the
+// type identity check for types that have been seen already.
+// importer.importtype and importtype and (export.go) need to
+// remain in sync.
+func (p *importer) importtype(pt, 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 = lineno
+		declare(n, PEXTERN)
+		checkwidth(pt)
+	} else {
+		// pt.Orig and t must be identical. Since t may not be
+		// fully set up yet, collect the types and verify identity
+		// later.
+		p.cmpList = append(p.cmpList, struct{ pt, t *Type }{pt, t})
+	}
+
+	if Debug['E'] != 0 {
+		fmt.Printf("import type %v %v\n", pt, Tconv(t, FmtLong))
+	}
+}
+
 func (p *importer) typ() *Type {
 	// if the type was seen before, i is its index (>= 0)
 	i := p.tagOrIndex()
@@ -199,78 +394,89 @@ func (p *importer) typ() *Type {
 	var t *Type
 	switch i {
 	case namedTag:
-		// go.y:hidden_importsym
+		// parser.go:hidden_importsym
+		p.pos()
 		tsym := p.qualifiedName()
 
-		// go.y:hidden_pkgtype
+		// parser.go:hidden_pkgtype
 		t = pkgtype(tsym)
-		importsym(tsym, OTYPE)
 		p.typList = append(p.typList, t)
 
 		// read underlying type
-		// go.y:hidden_type
+		// parser.go:hidden_type
 		t0 := p.typ()
-		importtype(t, t0) // go.y:hidden_import
+		if p.trackAllTypes {
+			// If we track all types, we cannot check equality of previously
+			// imported types until later. Use customized version of importtype.
+			p.importtype(t, t0)
+		} else {
+			importtype(t, t0)
+		}
 
 		// interfaces don't have associated methods
-		if t0.Etype == TINTER {
+		if t0.IsInterface() {
 			break
 		}
 
+		// set correct import context (since p.typ() may be called
+		// while importing the body of an inlined function)
+		savedContext := dclcontext
+		dclcontext = PEXTERN
+
 		// read associated methods
 		for i := p.int(); i > 0; i-- {
-			// go.y:hidden_fndcl
-			name := p.string()
+			// parser.go:hidden_fndcl
+
+			p.pos()
+			sym := p.fieldSym()
+
 			recv := p.paramList() // TODO(gri) do we need a full param list for the receiver?
 			params := p.paramList()
 			result := p.paramList()
-			// TODO(gri) fix this
-			p.int() // read and discard index of inlined function body for now
 
-			pkg := localpkg
-			if !exportname(name) {
-				pkg = tsym.Pkg
+			nointerface := false
+			if p.version == exportVersion1 {
+				nointerface = p.bool()
 			}
-			sym := pkg.Lookup(name)
 
-			n := methodname1(newname(sym), recv.N.Right)
-			n.Type = functype(recv.N, params, result)
+			n := methodname1(newname(sym), recv[0].Right)
+			n.Type = functype(recv[0], params, result)
 			checkwidth(n.Type)
-			// addmethod uses the global variable structpkg to verify consistency
-			{
-				saved := structpkg
-				structpkg = tsym.Pkg
-				addmethod(sym, n.Type, false, nointerface)
-				structpkg = saved
-			}
-			nointerface = false
-			funchdr(n)
+			addmethod(sym, n.Type, tsym.Pkg, false, nointerface)
+			p.funcList = append(p.funcList, n)
+			importlist = append(importlist, n)
 
-			// (comment from go.y)
+			// (comment from parser.go)
 			// 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
+			// out by typecheck's lookdot as this $$.ttype. So by providing
 			// this back link here we avoid special casing there.
-			n.Type.Nname = n
+			n.Type.SetNname(n)
 
-			// go.y:hidden_import
-			n.Func.Inl = nil
-			funcbody(n)
-			importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
+			if Debug['E'] > 0 {
+				fmt.Printf("import [%q] meth %v \n", importpkg.Path, n)
+				if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
+					fmt.Printf("inl body: %v\n", n.Func.Inl)
+				}
+			}
 		}
 
-	case arrayTag, sliceTag:
+		dclcontext = savedContext
+
+	case arrayTag:
 		t = p.newtyp(TARRAY)
-		t.Bound = -1
-		if i == arrayTag {
-			t.Bound = p.int64()
-		}
-		t.Type = p.typ()
+		bound := p.int64()
+		elem := p.typ()
+		t.Extra = &ArrayType{Elem: elem, Bound: bound}
+
+	case sliceTag:
+		t = p.newtyp(TSLICE)
+		elem := p.typ()
+		t.Extra = SliceType{Elem: elem}
 
 	case dddTag:
-		t = p.newtyp(T_old_DARRAY)
-		t.Bound = -1
-		t.Type = p.typ()
+		t = p.newtyp(TDDDFIELD)
+		t.Extra = DDDFieldType{T: p.typ()}
 
 	case structTag:
 		t = p.newtyp(TSTRUCT)
@@ -278,7 +484,7 @@ func (p *importer) typ() *Type {
 
 	case pointerTag:
 		t = p.newtyp(Tptr)
-		t.Type = p.typ()
+		t.Extra = PtrType{Elem: p.typ()}
 
 	case signatureTag:
 		t = p.newtyp(TFUNC)
@@ -289,26 +495,28 @@ func (p *importer) typ() *Type {
 	case interfaceTag:
 		t = p.newtyp(TINTER)
 		if p.int() != 0 {
-			Fatalf("unexpected embedded interface")
+			Fatalf("importer: unexpected embedded interface")
 		}
 		tointerface0(t, p.methodList())
 
 	case mapTag:
 		t = p.newtyp(TMAP)
-		t.Down = p.typ() // key
-		t.Type = p.typ() // val
+		mt := t.MapType()
+		mt.Key = p.typ()
+		mt.Val = p.typ()
 
 	case chanTag:
 		t = p.newtyp(TCHAN)
-		t.Chan = uint8(p.int())
-		t.Type = p.typ()
+		ct := t.ChanType()
+		ct.Dir = ChanDir(p.int())
+		ct.Elem = p.typ()
 
 	default:
-		Fatalf("unexpected type (tag = %d)", i)
+		Fatalf("importer: unexpected type (tag = %d)", i)
 	}
 
 	if t == nil {
-		Fatalf("nil type (type tag = %d)", i)
+		Fatalf("importer: nil type (type tag = %d)", i)
 	}
 
 	return t
@@ -320,24 +528,23 @@ func (p *importer) qualifiedName() *Sym {
 	return pkg.Lookup(name)
 }
 
-// go.y:hidden_structdcl_list
-func (p *importer) fieldList() *NodeList {
-	i := p.int()
-	if i == 0 {
-		return nil
-	}
-	n := list1(p.field())
-	for i--; i > 0; i-- {
-		n = list(n, p.field())
+// parser.go:hidden_structdcl_list
+func (p *importer) fieldList() (fields []*Node) {
+	if n := p.int(); n > 0 {
+		fields = make([]*Node, n)
+		for i := range fields {
+			fields[i] = p.field()
+		}
 	}
-	return n
+	return
 }
 
-// go.y:hidden_structdcl
+// parser.go:hidden_structdcl
 func (p *importer) field() *Node {
+	p.pos()
 	sym := p.fieldName()
 	typ := p.typ()
-	note := p.note()
+	note := p.string()
 
 	var n *Node
 	if sym.Name != "" {
@@ -345,8 +552,8 @@ func (p *importer) field() *Node {
 	} else {
 		// anonymous field - typ must be T or *T and T must be a type name
 		s := typ.Sym
-		if s == nil && Isptr[typ.Etype] {
-			s = typ.Type.Sym // deref
+		if s == nil && typ.IsPtr() {
+			s = typ.Elem().Sym // deref
 		}
 		pkg := importpkg
 		if sym != nil {
@@ -355,46 +562,38 @@ func (p *importer) field() *Node {
 		n = embedded(s, pkg)
 		n.Right = typenod(typ)
 	}
-	n.SetVal(note)
+	n.SetVal(Val{U: note})
 
 	return n
 }
 
-func (p *importer) note() (v Val) {
-	if s := p.string(); s != "" {
-		v.U = s
+// parser.go:hidden_interfacedcl_list
+func (p *importer) methodList() (methods []*Node) {
+	if n := p.int(); n > 0 {
+		methods = make([]*Node, n)
+		for i := range methods {
+			methods[i] = p.method()
+		}
 	}
 	return
 }
 
-// go.y:hidden_interfacedcl_list
-func (p *importer) methodList() *NodeList {
-	i := p.int()
-	if i == 0 {
-		return nil
-	}
-	n := list1(p.method())
-	for i--; i > 0; i-- {
-		n = list(n, p.method())
-	}
-	return n
-}
-
-// go.y:hidden_interfacedcl
+// parser.go:hidden_interfacedcl
 func (p *importer) method() *Node {
+	p.pos()
 	sym := p.fieldName()
 	params := p.paramList()
 	result := p.paramList()
 	return Nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result)))
 }
 
-// go.y:sym,hidden_importsym
+// parser.go:sym,hidden_importsym
 func (p *importer) fieldName() *Sym {
 	name := p.string()
 	pkg := localpkg
 	if name == "_" {
 		// During imports, unqualified non-exported identifiers are from builtinpkg
-		// (see go.y:sym). The binary exporter only exports blank as a non-exported
+		// (see parser.go:sym). The binary exporter only exports blank as a non-exported
 		// identifier without qualification.
 		pkg = builtinpkg
 	} else if name == "?" || name != "" && !exportname(name) {
@@ -406,8 +605,8 @@ func (p *importer) fieldName() *Sym {
 	return pkg.Lookup(name)
 }
 
-// go.y:ohidden_funarg_list
-func (p *importer) paramList() *NodeList {
+// parser.go:ohidden_funarg_list
+func (p *importer) paramList() []*Node {
 	i := p.int()
 	if i == 0 {
 		return nil
@@ -419,22 +618,21 @@ func (p *importer) paramList() *NodeList {
 		named = false
 	}
 	// i > 0
-	n := list1(p.param(named))
-	i--
-	for ; i > 0; i-- {
-		n = list(n, p.param(named))
+	n := make([]*Node, i)
+	for i := range n {
+		n[i] = p.param(named)
 	}
 	return n
 }
 
-// go.y:hidden_funarg
+// parser.go:hidden_funarg
 func (p *importer) param(named bool) *Node {
 	typ := p.typ()
 
 	isddd := false
-	if typ.Etype == T_old_DARRAY {
-		// T_old_DARRAY indicates ... type
-		typ.Etype = TARRAY
+	if typ.Etype == TDDDFIELD {
+		// TDDDFIELD indicates wrapped ... slice type
+		typ = typSlice(typ.DDDField())
 		isddd = true
 	}
 
@@ -444,16 +642,20 @@ func (p *importer) param(named bool) *Node {
 	if named {
 		name := p.string()
 		if name == "" {
-			Fatalf("expected named parameter")
+			Fatalf("importer: expected named parameter")
+		}
+		// TODO(gri) Supply function/method package rather than
+		// encoding the package for each parameter repeatedly.
+		pkg := localpkg
+		if name != "_" {
+			pkg = p.pkg()
 		}
-		// The parameter package doesn't matter; it's never consulted.
-		// We use the builtinpkg per go.y:sym (line 1181).
-		n.Left = newname(builtinpkg.Lookup(name))
+		n.Left = newname(pkg.Lookup(name))
 	}
 
 	// TODO(gri) This is compiler-specific (escape info).
 	// Move into compiler-specific section eventually?
-	n.SetVal(p.note())
+	n.SetVal(Val{U: p.string()})
 
 	return n
 }
@@ -462,38 +664,50 @@ func (p *importer) value(typ *Type) (x Val) {
 	switch tag := p.tagOrIndex(); tag {
 	case falseTag:
 		x.U = false
+
 	case trueTag:
 		x.U = true
+
 	case int64Tag:
 		u := new(Mpint)
-		Mpmovecfix(u, p.int64())
+		u.SetInt64(p.int64())
 		u.Rune = typ == idealrune
 		x.U = u
+
 	case floatTag:
 		f := newMpflt()
 		p.float(f)
-		if typ == idealint || Isint[typ.Etype] {
+		if typ == idealint || typ.IsInteger() {
 			// uncommon case: large int encoded as float
 			u := new(Mpint)
-			mpmovefltfix(u, f)
+			u.SetFloat(f)
 			x.U = u
 			break
 		}
 		x.U = f
+
 	case complexTag:
 		u := new(Mpcplx)
 		p.float(&u.Real)
 		p.float(&u.Imag)
 		x.U = u
+
 	case stringTag:
 		x.U = p.string()
+
+	case unknownTag:
+		Fatalf("importer: unknown constant (importing package with errors)")
+
+	case nilTag:
+		x.U = new(NilVal)
+
 	default:
-		Fatalf("unexpected value tag %d", tag)
+		Fatalf("importer: unexpected value tag %d", tag)
 	}
 
 	// verify ideal type
-	if isideal(typ) && untype(x.Ctype()) != typ {
-		Fatalf("value %v and type %v don't match", x, typ)
+	if typ.IsUntyped() && untype(x.Ctype()) != typ {
+		Fatalf("importer: value %v and type %v don't match", x, typ)
 	}
 
 	return
@@ -502,7 +716,7 @@ func (p *importer) value(typ *Type) (x Val) {
 func (p *importer) float(x *Mpflt) {
 	sign := p.int()
 	if sign == 0 {
-		Mpmovecflt(x, 0)
+		x.SetFloat64(0)
 		return
 	}
 
@@ -519,20 +733,404 @@ func (p *importer) float(x *Mpflt) {
 // ----------------------------------------------------------------------------
 // Inlined function bodies
 
-func (p *importer) body() {
-	p.int()
-	p.block()
+// Approach: Read nodes and use them to create/declare the same data structures
+// as done originally by the (hidden) parser by closely following the parser's
+// original code. In other words, "parsing" the import data (which happens to
+// be encoded in binary rather textual form) is the best way at the moment to
+// re-establish the syntax tree's invariants. At some future point we might be
+// able to avoid this round-about way and create the rewritten nodes directly,
+// possibly avoiding a lot of duplicate work (name resolution, type checking).
+//
+// Refined nodes (e.g., ODOTPTR as a refinement of OXDOT) are exported as their
+// unrefined nodes (since this is what the importer uses). The respective case
+// entries are unreachable in the importer.
+
+func (p *importer) stmtList() []*Node {
+	var list []*Node
+	for {
+		n := p.node()
+		if n == nil {
+			break
+		}
+		// OBLOCK nodes may be created when importing ODCL nodes - unpack them
+		if n.Op == OBLOCK {
+			list = append(list, n.List.Slice()...)
+		} else {
+			list = append(list, n)
+		}
+	}
+	return list
+}
+
+func (p *importer) exprList() []*Node {
+	var list []*Node
+	for {
+		n := p.expr()
+		if n == nil {
+			break
+		}
+		list = append(list, n)
+	}
+	return list
+}
+
+func (p *importer) elemList() []*Node {
+	c := p.int()
+	list := make([]*Node, c)
+	for i := range list {
+		list[i] = Nod(OKEY, mkname(p.fieldSym()), p.expr())
+	}
+	return list
+}
+
+func (p *importer) expr() *Node {
+	n := p.node()
+	if n != nil && n.Op == OBLOCK {
+		Fatalf("unexpected block node: %v", n)
+	}
+	return n
+}
+
+// TODO(gri) split into expr and stmt
+func (p *importer) node() *Node {
+	switch op := p.op(); op {
+	// expressions
+	// case OPAREN:
+	// 	unreachable - unpacked by exporter
+
+	// case ODDDARG:
+	//	unimplemented
+
+	// case OREGISTER:
+	//	unimplemented
+
+	case OLITERAL:
+		typ := p.typ()
+		n := nodlit(p.value(typ))
+		if !typ.IsUntyped() {
+			conv := Nod(OCALL, typenod(typ), nil)
+			conv.List.Set1(n)
+			n = conv
+		}
+		return n
+
+	case ONAME:
+		return mkname(p.sym())
+
+	// case OPACK, ONONAME:
+	// 	unreachable - should have been resolved by typechecking
+
+	case OTYPE:
+		if p.bool() {
+			return mkname(p.sym())
+		}
+		return typenod(p.typ())
+
+	// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
+	//      unreachable - should have been resolved by typechecking
+
+	// case OCLOSURE:
+	//	unimplemented
+
+	case OPTRLIT:
+		n := p.expr()
+		if !p.bool() /* !implicit, i.e. '&' operator */ {
+			if n.Op == OCOMPLIT {
+				// Special case for &T{...}: turn into (*T){...}.
+				n.Right = Nod(OIND, n.Right, nil)
+				n.Right.Implicit = true
+			} else {
+				n = Nod(OADDR, n, nil)
+			}
+		}
+		return n
+
+	case OSTRUCTLIT:
+		n := Nod(OCOMPLIT, nil, typenod(p.typ()))
+		n.List.Set(p.elemList()) // special handling of field names
+		return n
+
+	// case OARRAYLIT, OMAPLIT:
+	// 	unreachable - mapped to case OCOMPLIT below by exporter
+
+	case OCOMPLIT:
+		n := Nod(OCOMPLIT, nil, typenod(p.typ()))
+		n.List.Set(p.exprList())
+		return n
+
+	case OKEY:
+		left, right := p.exprsOrNil()
+		return Nod(OKEY, left, right)
+
+	// case OCALLPART:
+	//	unimplemented
+
+	// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
+	// 	unreachable - mapped to case OXDOT below by exporter
+
+	case OXDOT:
+		// see parser.new_dotname
+		return NodSym(OXDOT, p.expr(), p.fieldSym())
+
+	// case ODOTTYPE, ODOTTYPE2:
+	// 	unreachable - mapped to case ODOTTYPE below by exporter
+
+	case ODOTTYPE:
+		n := Nod(ODOTTYPE, p.expr(), nil)
+		if p.bool() {
+			n.Right = p.expr()
+		} else {
+			n.Right = typenod(p.typ())
+		}
+		return n
+
+	// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
+	// 	unreachable - mapped to cases below by exporter
+
+	case OINDEX:
+		return Nod(op, p.expr(), p.expr())
+
+	case OSLICE, OSLICE3:
+		n := Nod(op, p.expr(), nil)
+		low, high := p.exprsOrNil()
+		var max *Node
+		if n.Op.IsSlice3() {
+			max = p.expr()
+		}
+		n.SetSliceBounds(low, high, max)
+		return n
+
+	// case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
+	// 	unreachable - mapped to OCONV case below by exporter
+
+	case OCONV:
+		n := Nod(OCALL, typenod(p.typ()), nil)
+		n.List.Set(p.exprList())
+		return n
+
+	case OCOPY, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
+		n := builtinCall(op)
+		n.List.Set(p.exprList())
+		if op == OAPPEND {
+			n.Isddd = p.bool()
+		}
+		return n
+
+	// case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
+	// 	unreachable - mapped to OCALL case below by exporter
+
+	case OCALL:
+		n := Nod(OCALL, p.expr(), nil)
+		n.List.Set(p.exprList())
+		n.Isddd = p.bool()
+		return n
+
+	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
+		n := builtinCall(OMAKE)
+		n.List.Append(typenod(p.typ()))
+		n.List.Append(p.exprList()...)
+		return n
+
+	// unary expressions
+	case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
+		return Nod(op, p.expr(), nil)
+
+	// binary expressions
+	case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
+		OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
+		return Nod(op, p.expr(), p.expr())
+
+	case OADDSTR:
+		list := p.exprList()
+		x := list[0]
+		for _, y := range list[1:] {
+			x = Nod(OADD, x, y)
+		}
+		return x
+
+	// case OCMPSTR, OCMPIFACE:
+	// 	unreachable - mapped to std comparison operators by exporter
+
+	case ODCLCONST:
+		// TODO(gri) these should not be exported in the first place
+		return Nod(OEMPTY, nil, nil)
+
+	// --------------------------------------------------------------------
+	// statements
+	case ODCL:
+		var lhs *Node
+		if p.bool() {
+			lhs = p.expr()
+		} else {
+			lhs = dclname(p.sym())
+		}
+		// TODO(gri) avoid list created here!
+		return liststmt(variter([]*Node{lhs}, typenod(p.typ()), nil))
+
+	// case ODCLFIELD:
+	//	unimplemented
+
+	// case OAS, OASWB:
+	// 	unreachable - mapped to OAS case below by exporter
+
+	case OAS:
+		return Nod(OAS, p.expr(), p.expr())
+
+	case OASOP:
+		n := Nod(OASOP, nil, nil)
+		n.Etype = EType(p.int())
+		n.Left = p.expr()
+		if !p.bool() {
+			n.Right = Nodintconst(1)
+			n.Implicit = true
+		} else {
+			n.Right = p.expr()
+		}
+		return n
+
+	// case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+	// 	unreachable - mapped to OAS2 case below by exporter
+
+	case OAS2:
+		n := Nod(OAS2, nil, nil)
+		n.List.Set(p.exprList())
+		n.Rlist.Set(p.exprList())
+		return n
+
+	case ORETURN:
+		n := Nod(ORETURN, nil, nil)
+		n.List.Set(p.exprList())
+		return n
+
+	// case ORETJMP:
+	// 	unreachable - generated by compiler for trampolin routines (not exported)
+
+	case OPROC, ODEFER:
+		return Nod(op, p.expr(), nil)
+
+	case OIF:
+		markdcl()
+		n := Nod(OIF, nil, nil)
+		n.Ninit.Set(p.stmtList())
+		n.Left = p.expr()
+		n.Nbody.Set(p.stmtList())
+		n.Rlist.Set(p.stmtList())
+		popdcl()
+		return n
+
+	case OFOR:
+		markdcl()
+		n := Nod(OFOR, nil, nil)
+		n.Ninit.Set(p.stmtList())
+		n.Left, n.Right = p.exprsOrNil()
+		n.Nbody.Set(p.stmtList())
+		popdcl()
+		return n
+
+	case ORANGE:
+		markdcl()
+		n := Nod(ORANGE, nil, nil)
+		n.List.Set(p.stmtList())
+		n.Right = p.expr()
+		n.Nbody.Set(p.stmtList())
+		popdcl()
+		return n
+
+	case OSELECT, OSWITCH:
+		markdcl()
+		n := Nod(op, nil, nil)
+		n.Ninit.Set(p.stmtList())
+		n.Left, _ = p.exprsOrNil()
+		n.List.Set(p.stmtList())
+		popdcl()
+		return n
+
+	// case OCASE, OXCASE:
+	// 	unreachable - mapped to OXCASE case below by exporter
+
+	case OXCASE:
+		markdcl()
+		n := Nod(OXCASE, nil, nil)
+		n.Xoffset = int64(block)
+		n.List.Set(p.exprList())
+		// TODO(gri) eventually we must declare variables for type switch
+		// statements (type switch statements are not yet exported)
+		n.Nbody.Set(p.stmtList())
+		popdcl()
+		return n
+
+	// case OFALL:
+	// 	unreachable - mapped to OXFALL case below by exporter
+
+	case OXFALL:
+		n := Nod(OXFALL, nil, nil)
+		n.Xoffset = int64(block)
+		return n
+
+	case OBREAK, OCONTINUE:
+		left, _ := p.exprsOrNil()
+		if left != nil {
+			left = newname(left.Sym)
+		}
+		return Nod(op, left, nil)
+
+	// case OEMPTY:
+	// 	unreachable - not emitted by exporter
+
+	case OGOTO, OLABEL:
+		n := Nod(op, newname(p.expr().Sym), nil)
+		n.Sym = dclstack // context, for goto restrictions
+		return n
+
+	case OEND:
+		return nil
+
+	default:
+		Fatalf("cannot import %s (%d) node\n"+
+			"==> please file an issue and assign to gri@\n", op, op)
+		panic("unreachable") // satisfy compiler
+	}
+}
+
+func builtinCall(op Op) *Node {
+	return Nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil)
 }
 
-func (p *importer) block() {
-	for i := p.int(); i > 0; i-- {
-		p.stmt()
+func (p *importer) exprsOrNil() (a, b *Node) {
+	ab := p.int()
+	if ab&1 != 0 {
+		a = p.expr()
 	}
+	if ab&2 != 0 {
+		b = p.expr()
+	}
+	return
+}
+
+func (p *importer) fieldSym() *Sym {
+	name := p.string()
+	pkg := localpkg
+	if !exportname(name) {
+		pkg = p.pkg()
+	}
+	return pkg.Lookup(name)
+}
+
+func (p *importer) sym() *Sym {
+	name := p.string()
+	pkg := localpkg
+	if name != "_" {
+		pkg = p.pkg()
+	}
+	return pkg.Lookup(name)
+}
+
+func (p *importer) bool() bool {
+	return p.int() != 0
 }
 
-func (p *importer) stmt() {
-	// TODO(gri) do something sensible here
-	p.string()
+func (p *importer) op() Op {
+	return Op(p.int())
 }
 
 // ----------------------------------------------------------------------------
@@ -549,7 +1147,7 @@ func (p *importer) tagOrIndex() int {
 func (p *importer) int() int {
 	x := p.int64()
 	if int64(int(x)) != x {
-		Fatalf("exported integer too large")
+		Fatalf("importer: exported integer too large")
 	}
 	return int(x)
 }
@@ -566,30 +1164,34 @@ func (p *importer) string() string {
 	if p.debugFormat {
 		p.marker('s')
 	}
-
-	if n := int(p.rawInt64()); n > 0 {
-		if cap(p.buf) < n {
-			p.buf = make([]byte, n)
-		} else {
-			p.buf = p.buf[:n]
-		}
-		for i := 0; i < n; i++ {
-			p.buf[i] = p.byte()
-		}
-		return string(p.buf)
+	// if the string was seen before, i is its index (>= 0)
+	// (the empty string is at index 0)
+	i := p.rawInt64()
+	if i >= 0 {
+		return p.strList[i]
 	}
-
-	return ""
+	// otherwise, i is the negative string length (< 0)
+	if n := int(-i); n <= cap(p.buf) {
+		p.buf = p.buf[:n]
+	} else {
+		p.buf = make([]byte, n)
+	}
+	for i := range p.buf {
+		p.buf[i] = p.rawByte()
+	}
+	s := string(p.buf)
+	p.strList = append(p.strList, s)
+	return s
 }
 
 func (p *importer) marker(want byte) {
-	if got := p.byte(); got != want {
-		Fatalf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
+	if got := p.rawByte(); got != want {
+		Fatalf("importer: incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
 	}
 
 	pos := p.read
 	if n := int(p.rawInt64()); n != pos {
-		Fatalf("incorrect position: got %d; want %d", n, pos)
+		Fatalf("importer: incorrect position: got %d; want %d", n, pos)
 	}
 }
 
@@ -597,29 +1199,30 @@ func (p *importer) marker(want byte) {
 func (p *importer) rawInt64() int64 {
 	i, err := binary.ReadVarint(p)
 	if err != nil {
-		Fatalf("read error: %v", err)
+		Fatalf("importer: read error: %v", err)
 	}
 	return i
 }
 
 // needed for binary.ReadVarint in rawInt64
 func (p *importer) ReadByte() (byte, error) {
-	return p.byte(), nil
+	return p.rawByte(), nil
 }
 
-// byte is the bottleneck interface for reading from p.in.
+// rawByte is the bottleneck interface for reading from p.in.
 // It unescapes '|' 'S' to '$' and '|' '|' to '|'.
-func (p *importer) byte() byte {
-	c := obj.Bgetc(p.in)
+// rawByte should only be used by low-level decoders.
+func (p *importer) rawByte() byte {
+	c, err := p.in.ReadByte()
 	p.read++
-	if c < 0 {
-		Fatalf("read error")
+	if err != nil {
+		Fatalf("importer: read error: %v", err)
 	}
 	if c == '|' {
-		c = obj.Bgetc(p.in)
+		c, err = p.in.ReadByte()
 		p.read++
-		if c < 0 {
-			Fatalf("read error")
+		if err != nil {
+			Fatalf("importer: read error: %v", err)
 		}
 		switch c {
 		case 'S':
@@ -627,8 +1230,8 @@ func (p *importer) byte() byte {
 		case '|':
 			// nothing to do
 		default:
-			Fatalf("unexpected escape sequence in export data")
+			Fatalf("importer: unexpected escape sequence in export data")
 		}
 	}
-	return byte(c)
+	return c
 }
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index 4199fb3..c1a6418 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -3,167 +3,108 @@
 package gc
 
 const runtimeimport = "" +
-	"package 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 @\"\".writeBarrier struct { @\"\".enabled bool; @\"\".needed bool; @\"\".cgo 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" +
-	"func @\"\".msanread (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
-	"func @\"\".msanwrite (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
-	"\n" +
-	"$$\n"
+	"cn\x00\x03v1\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00" +
+	"\x01\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15pani" +
+	"cdivide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00" +
+	"\t\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11go" +
+	"recover\x00\x01\x17\b\x00\x01\x1b\x00\x00\x00\t\x11printbool\x00\x01\x00\x00\x00\t\x13print" +
+	"float\x00\x01\x1a\x00\x00\t\x0fprintint\x00\x01\n\x00\x00\t\x0fprinthex\x00\x01\x14\x00\x00" +
+	"\t\x11printuint\x00\x01\x14\x00\x00\t\x17printcomplex\x00\x01\x1e\x00\x00\t\x15pri" +
+	"ntstring\x00\x01 \x00\x00\t\x17printpointer\x00\x01:\x00\x00\t\x13printi" +
+	"face\x00\x01:\x00\x00\t\x13printeface\x00\x01:\x00\x00\t\x13printslice\x00\x01" +
+	":\x00\x00\t\rprintnl\x00\x00\x00\t\rprintsp\x00\x00\x00\t\x11printlock\x00\x00" +
+	"\x00\t\x15printunlock\x00\x00\x00\t\x19concatstring2\x00\x05\x17\x0f@\"\x00 " +
+	"\x00 \x00\x01 \x00\t\x19concatstring3\x00\a\x17\x0f@\"\x00 \x00 \x00 \x00\x01 \x00\t\x19c" +
+	"oncatstring4\x00\t\x17\x0f@\"\x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatst" +
+	"ring5\x00\v\x17\x0f@\"\x00 \x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstrings" +
+	"\x00\x03\x17\x0f@\"\x00\x11 \x00\x01 \x00\t\x11cmpstring\x00\x03 \x00 \x00\x01\x02\x00\t\x0feqstr" +
+	"ing\x00\x03 \x00 \x00\x01\x00\x00\t\x11intstring\x00\x03\x17\x0f\b\"\x00\n\x00\x01 \x00\t!sli" +
+	"cebytetostring\x00\x03\x17\x0f@\"\x00\x11\"\x00\x01 \x00\t'slicebyteto" +
+	"stringtmp\x00\x01\x11\"\x00\x01 \x00\t!slicerunetostring\x00\x03\x17\x0f" +
+	"@\"\x00\x11|S\x00\x01 \x00\t!stringtoslicebyte\x00\x03\x17\x0f@\"\x00 \x00\x01\x11" +
+	"\"\x00\t'stringtoslicebytetmp\x00\x01 \x00\x01\x11\"\x00\t!string" +
+	"toslicerune\x00\x03\x17\x0f@|S\x00 \x00\x01\x11|S\x00\t\x13stringiter\x00\x03" +
+	" \x00\x02\x00\x01\x02\x00\t\x15stringiter2\x00\x03 \x00\x02\x00\x04\x02\rretk·1\x00\x00|S" +
+	"\rretv·2\x00\x00\t\x11slicecopy\x00\x06:\tto·2\x00\x00:\tfr·3\x00" +
+	"\x00\x16\vwid·4\x00\x1bunsafe-uintptr\x01\x02\x00\t\x1dslicestrin" +
+	"gcopy\x00\x04:^\x00\x00:`\x00\x00\x01\x02\x00\t\rconvI2E\x00\x02:\relem·2\x00\x00" +
+	"\x02:\vret·1\x00\x00\t\rconvI2I\x00\x04\x17\"\b\x00\x00:\relem·3\x00\x00\x02:" +
+	"l\x00\x00\t\rconvT2E\x00\x06\x17\"\b\x00\x00\x17:p\x00\x00\x17:\vbuf·4\x00\x00\x02:l\x00\x00" +
+	"\t\rconvT2I\x00\x06\x17\"\vtab·2\x00\x00\x17:p\x00\x00\x17:t\x00\x00\x02:l\x00\x00\t\x11a" +
+	"ssertE2E\x00\x06\x17\"\vtyp·1\x00\x00:\x0fiface·2\x00\x00\x17:\vret\xc2" +
+	"\xb73\x00\x00\x00\t\x13assertE2E2\x00\x06\x17\"\b\x00\x00:\x0fiface·3\x00\x00\x17:\vr" +
+	"et·4\x00\x00\x01\x00\x00\t\x11assertE2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00" +
+	"\t\x13assertE2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11asser" +
+	"tE2T\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertE2T2\x00\x06\x17\"\b" +
+	"\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2E\x00\x06\x17\"||\x00\x00:~\x00\x00\x17" +
+	":\x80\x01\x00\x00\x00\t\x13assertI2E2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t" +
+	"\x11assertI2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2I" +
+	"2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2T\x00\x06\x17\"||\x00" +
+	"\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01" +
+	"\x00\x00\x01\x00\x00\t\x17panicdottype\x00\x06\x17\"\rhave·1\x00\x00\x17\"\rwant" +
+	"·2\x00\x00\x17\"\x84\x01\x00\x00\x00\t\rifaceeq\x00\x04:\ti1·2\x00\x00:\ti2·3\x00" +
+	"\x00\x02\x00l\x00\x00\t\refaceeq\x00\x04:\xa4\x01\x00\x00:\xa6\x01\x00\x00\x02\x00l\x00\x00\t\rmakema" +
+	"p\x00\b\x17\"\x13mapType·2\x00\x00\n\rhint·3\x00\x00\x17:\x11mapbuf·" +
+	"4\x00\x00\x17:\x17bucketbuf·5\x00\x00\x02\x1d::\rhmap·1\x00\x00\t\x13mapa" +
+	"ccess1\x00\x06\x17\"\xac\x01\x00\x00\x1d::\rhmap·3\x00\x00\x17:\vkey·4\x00\x00\x02\x17" +
+	":\vval·1\x00\x00\t!mapaccess1_fast32\x00\x06\x17\"\xac\x01\x00\x00\x1d::" +
+	"\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t!mapaccess1_fast64\x00\x06\x17\"\xac" +
+	"\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t#mapaccess1_fasts" +
+	"tr\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t\x1bmapaccess" +
+	"1_fat\x00\b\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00\x17:\xba\x01\x00\x00\x17\"\rzero·5\x00\x00\x02\x17" +
+	":\xbc\x01\x00\x00\t\x13mapaccess2\x00\x06\x17\"\x13mapType·3\x00\x00\x1d::\rhm" +
+	"ap·4\x00\x00\x17:\vkey·5\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\rpres·2\x00\x00\t!ma" +
+	"paccess2_fast32\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01" +
+	"\x00\x00\x00\xd0\x01\x00\x00\t!mapaccess2_fast64\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00" +
+	"\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t#mapaccess2_faststr\x00\x06" +
+	"\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x1bmapacces" +
+	"s2_fat\x00\b\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00\x17:\xce\x01\x00\x00\x17\"\rzero·6\x00\x00\x04" +
+	"\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x13mapassign1\x00\b\x17\"\x13mapType·1\x00\x00" +
+	"\x1d::\rhmap·2\x00\x00\x17:\vkey·3\x00\x00\x17:\vval·4\x00\x00\x00\t\x15ma" +
+	"piterinit\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\x0fhiter·3\x00\x00\x00\t\x11" +
+	"mapdelete\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\xe2\x01\x00\x00\x00\t\x15mapiter" +
+	"next\x00\x02\x17:\x0fhiter·1\x00\x00\x00\t\x0fmakechan\x00\x04\x17\"\x15chanT" +
+	"ype·2\x00\x00\n\xae\x01\x00\x00\x02\x1f\x06:\x0fhchan·1\x00\x00\t\x11chanrecv1\x00" +
+	"\x06\x17\"\x15chanType·1\x00\x00\x1f\x02:\x0fhchan·2\x00\x00\x17:p\x00\x00\x00\t\x11c" +
+	"hanrecv2\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x02:\x0fhchan·3\x00\x00\x17:\relem·4" +
+	"\x00\x00\x01\x00\x00\t\x11chansend1\x00\x06\x17\"\xf8\x01\x00\x00\x1f\x04:\xfa\x01\x00\x00\x17:p\x00\x00\x00\t\x11c" +
+	"losechan\x00\x02:\xf4\x01\x00\x00\x00\a\x17writeBarrier\x00\x15\x06\renable" +
+	"d\x00\x00\x00\vneeded\x00\x00\x00\x05cgo\x00\x00\x00\t\x1dwritebarrierptr\x00\x04" +
+	"\x17:\vdst·1\x00\x00:\vsrc·2\x00\x00\x00\t\x17typedmemmove\x00\x06\x17\"" +
+	"||\x00\x00\x17:\vdst·2\x00\x00\x17:\vsrc·3\x00\x00\x00\t\x1btypedslicec" +
+	"opy\x00\x06\x17\"\b\x00\x00:\vdst·3\x00\x00:\vsrc·4\x00\x00\x01\x02\x00\t\x17selec" +
+	"tnbsend\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x01\x00\x00\t\x17selectn" +
+	"brecv\x00\x06\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x1f\x02:\x0fhchan·4\x00\x00\x01\x00\x00\t\x19sel" +
+	"ectnbrecv2\x00\b\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x17\x00\x15received·4\x00\x00\x1f" +
+	"\x02:\x0fhchan·5\x00\x00\x01\x00\x00\t\x11newselect\x00\x06\x17\"\vsel·1\x00\x00" +
+	"\n\x13selsize·2\x00\x00\b\rsize·3\x00\x00\x00\t\x13selectsend\x00\x06" +
+	"\x17\"\vsel·2\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x02\x00\x15selected·1\x00\x00" +
+	"\t\x13selectrecv\x00\x06\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t" +
+	"\x15selectrecv2\x00\b\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x17\x00\x15rece" +
+	"ived·5\x00\x00\x02\x00\xb8\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb6\x02\x00\x00\x02\x00" +
+	"\xb8\x02\x00\x00\t\x0fselectgo\x00\x02\x17\"\xae\x02\x00\x00\x00\t\tblock\x00\x00\x00\t\x11makes" +
+	"lice\x00\x06\x17\"\b\x00\x00\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary·" +
+	"1\x00\x00\t\x11growslice\x00\x06\x17\"\b\x00\x00\x11:\vold·3\x00\x00\x02\xca\x02\x00\x00\x02\x11:" +
+	"\xcc\x02\x00\x00\t\rmemmove\x00\x06\x17:\tto·1\x00\x00\x17:\vfrm·2\x00\x00\x16\x11le" +
+	"ngth·3\x00d\x00\t\vmemclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length\xc2" +
+	"\xb72\x00d\x00\t\x0fmemequal\x00\x06\x17:\ax·2\x00\x00\x17:\ay·3\x00\x00\x16\rsiz" +
+	"e·4\x00d\x01\x00\x00\t\x11memequal8\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13m" +
+	"emequal16\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04" +
+	"\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal64\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00" +
+	"\x00\x01\x00\x00\t\x15memequal128\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x0fint6" +
+	"4div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64" +
+	"mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat6" +
+	"4toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64touint64\x00\x01\x1a\x00\x01\x14\x00\t" +
+	"\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1duint64tofloat64\x00" +
+	"\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e\vnum·2\x00\x00\x1e\vden·" +
+	"3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefuncenter\x00\x01\x16d\x00\t\x17race" +
+	"funcexit\x00\x00\x00\t\x0fraceread\x00\x01\x16d\x00\t\x11racewrite\x00\x01\x16" +
+	"d\x00\t\x19racereadrange\x00\x04\x16\raddr·1\x00d\x16\rsize·2\x00" +
+	"d\x00\t\x1bracewriterange\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x0fmsanrea" +
+	"d\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x11msanwrite\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\v\xf4" +
+	"\x01\x02\v\x00\x01\x00\n$$\n"
 
 const unsafeimport = "" +
-	"package unsafe\n" +
-	"type @\"\".Pointer uintptr\n" +
-	"func @\"\".Offsetof (? any) (? uintptr)\n" +
-	"func @\"\".Sizeof (? any) (? uintptr)\n" +
-	"func @\"\".Alignof (? any) (? uintptr)\n" +
-	"\n" +
-	"$$\n"
+	"cn\x00\x03v1\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01" +
+	":\x00\x01\x16\x00\t\vSizeof\x00\x01:\x00\x01\x16\x00\t\rAlignof\x00\x01:\x00\x01\x16\x00\v\b\x00\v" +
+	"\x00\x01\x00\n$$\n"
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index a50fc2e..e9316cb 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -3,12 +3,12 @@
 // 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 update builtin.go. This is not done automatically
 // to avoid depending on having a working compiler binary.
 
 // +build ignore
 
-package PACKAGE
+package runtime
 
 // emitted by compiler, not referred to by go programs
 
@@ -60,11 +60,10 @@ 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)
+func convT2I(tab *byte, elem, buf *any) (ret any)
 
 // interface type assertions  x.(T)
 func assertE2E(typ *byte, iface any, ret *any)
@@ -83,8 +82,6 @@ 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)
@@ -92,10 +89,12 @@ 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 mapaccess1_fat(mapType *byte, hmap map[any]any, key *any, zero *byte) (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 mapaccess2_fat(mapType *byte, hmap map[any]any, key *any, zero *byte) (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)
@@ -115,39 +114,6 @@ var writeBarrier struct {
 }
 
 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)
@@ -167,7 +133,6 @@ 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)
 
diff --git a/src/cmd/compile/internal/gc/builtin/unsafe.go b/src/cmd/compile/internal/gc/builtin/unsafe.go
index ce50869..6e25db6 100644
--- a/src/cmd/compile/internal/gc/builtin/unsafe.go
+++ b/src/cmd/compile/internal/gc/builtin/unsafe.go
@@ -3,12 +3,12 @@
 // 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 update builtin.go. This is not done automatically
 // to avoid depending on having a working compiler binary.
 
 // +build ignore
 
-package PACKAGE
+package unsafe
 
 type Pointer uintptr // not really; filled in by compiler
 
diff --git a/src/cmd/compile/internal/gc/builtin_test.go b/src/cmd/compile/internal/gc/builtin_test.go
new file mode 100644
index 0000000..94111e6
--- /dev/null
+++ b/src/cmd/compile/internal/gc/builtin_test.go
@@ -0,0 +1,31 @@
+// Copyright 2016 The Go Authors. 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_test
+
+import (
+	"bytes"
+	"internal/testenv"
+	"io/ioutil"
+	"os/exec"
+	"testing"
+)
+
+func TestBuiltin(t *testing.T) {
+	testenv.MustHaveGoRun(t)
+
+	old, err := ioutil.ReadFile("builtin.go")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	new, err := exec.Command("go", "run", "mkbuiltin.go", "-stdout").Output()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !bytes.Equal(old, new) {
+		t.Fatal("builtin.go out of date; run mkbuiltin.go")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/bv.go b/src/cmd/compile/internal/gc/bv.go
index c19ec81..d1c2192 100644
--- a/src/cmd/compile/internal/gc/bv.go
+++ b/src/cmd/compile/internal/gc/bv.go
@@ -7,32 +7,20 @@ package gc
 import "fmt"
 
 const (
-	WORDSIZE  = 4
 	WORDBITS  = 32
 	WORDMASK  = WORDBITS - 1
 	WORDSHIFT = 5
 )
 
-// A Bvec is a bit vector.
-type Bvec struct {
+// 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)}
+func bvalloc(n int32) bvec {
+	nword := (n + WORDBITS - 1) / WORDBITS
+	return bvec{n, make([]uint32, nword)}
 }
 
 type bulkBvec struct {
@@ -50,53 +38,38 @@ func bvbulkalloc(nbit int32, count int32) bulkBvec {
 	}
 }
 
-func (b *bulkBvec) next() Bvec {
-	out := Bvec{b.nbit, b.words[:b.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) {
+func bvandnot(dst bvec, src1 bvec, src2 bvec) {
 	for i, x := range src1.b {
 		dst.b[i] = x &^ src2.b[i]
 	}
 }
 
-func bvcmp(bv1 Bvec, bv2 Bvec) int {
+func bveq(bv1 bvec, bv2 bvec) bool {
 	if bv1.n != bv2.n {
 		Fatalf("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 false
 		}
 	}
-	return 0
+	return true
 }
 
-func bvcopy(dst Bvec, src Bvec) {
+func bvcopy(dst bvec, src bvec) {
 	for i, x := range src.b {
 		dst.b[i] = x
 	}
 }
 
-func bvconcat(src1 Bvec, src2 Bvec) Bvec {
-	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 {
+func bvget(bv bvec, i int32) int {
 	if i < 0 || i >= bv.n {
 		Fatalf("bvget: index %d is out of bounds with length %d\n", i, bv.n)
 	}
@@ -105,7 +78,7 @@ func bvget(bv Bvec, i int32) int {
 
 // bvnext returns the smallest index >= i for which bvget(bv, i) == 1.
 // If there is no such index, bvnext returns -1.
-func bvnext(bv Bvec, i int32) int {
+func bvnext(bv bvec, i int32) int32 {
 	if i >= bv.n {
 		return -1
 	}
@@ -131,10 +104,10 @@ func bvnext(bv Bvec, i int32) int {
 		i++
 	}
 
-	return int(i)
+	return i
 }
 
-func bvisempty(bv Bvec) bool {
+func bvisempty(bv bvec) bool {
 	for i := int32(0); i < bv.n; i += WORDBITS {
 		if bv.b[i>>WORDSHIFT] != 0 {
 			return false
@@ -143,7 +116,7 @@ func bvisempty(bv Bvec) bool {
 	return true
 }
 
-func bvnot(bv Bvec) {
+func bvnot(bv bvec) {
 	i := int32(0)
 	w := int32(0)
 	for ; i < bv.n; i, w = i+WORDBITS, w+1 {
@@ -152,41 +125,33 @@ func bvnot(bv Bvec) {
 }
 
 // union
-func bvor(dst Bvec, src1 Bvec, src2 Bvec) {
+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) {
+func bvand(dst bvec, src1 bvec, src2 bvec) {
 	for i, x := range src1.b {
 		dst.b[i] = x & src2.b[i]
 	}
 }
 
-func bvprint(bv Bvec) {
+func bvprint(bv bvec) {
 	fmt.Printf("#*")
 	for i := int32(0); i < bv.n; i++ {
 		fmt.Printf("%d", bvget(bv, i))
 	}
 }
 
-func bvreset(bv Bvec, i int32) {
-	if i < 0 || i >= bv.n {
-		Fatalf("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) {
+func bvresetall(bv bvec) {
 	for i := range bv.b {
 		bv.b[i] = 0
 	}
 }
 
-func bvset(bv Bvec, i int32) {
+func bvset(bv bvec, i int32) {
 	if i < 0 || i >= bv.n {
 		Fatalf("bvset: index %d is out of bounds with length %d\n", i, bv.n)
 	}
diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go
index 6456240..74fe463 100644
--- a/src/cmd/compile/internal/gc/cgen.go
+++ b/src/cmd/compile/internal/gc/cgen.go
@@ -7,6 +7,7 @@ package gc
 import (
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
+	"cmd/internal/sys"
 	"fmt"
 )
 
@@ -88,7 +89,7 @@ func cgen_wb(n, res *Node, wb bool) {
 
 	if !res.Addable {
 		if n.Ullman > res.Ullman {
-			if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
+			if Ctxt.Arch.RegSize == 4 && Is64(n.Type) {
 				var n1 Node
 				Tempname(&n1, n.Type)
 				Cgen(n, &n1)
@@ -110,30 +111,29 @@ func cgen_wb(n, res *Node, wb bool) {
 			return
 		}
 
-		var f int
 		if res.Ullman < UINF {
 			if Complexop(n, res) {
 				Complexgen(n, res)
 				return
 			}
 
-			f = 1 // gen thru register
+			f := true // gen through register
 			switch n.Op {
 			case OLITERAL:
 				if Smallintconst(n) {
-					f = 0
+					f = false
 				}
 
 			case OREGISTER:
-				f = 0
+				f = false
 			}
 
-			if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 && !wb {
+			if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 && !wb {
 				a := Thearch.Optoas(OAS, res.Type)
 				var addr obj.Addr
 				if Thearch.Sudoaddable(a, res, &addr) {
 					var p1 *obj.Prog
-					if f != 0 {
+					if f {
 						var n2 Node
 						Regalloc(&n2, res.Type, nil)
 						Cgen(n, &n2)
@@ -152,7 +152,7 @@ func cgen_wb(n, res *Node, wb bool) {
 			}
 		}
 
-		if Ctxt.Arch.Thechar == '8' {
+		if Ctxt.Arch.Family == sys.I386 {
 			// no registers to speak of
 			var n1, n2 Node
 			Tempname(&n1, n.Type)
@@ -175,12 +175,12 @@ func cgen_wb(n, res *Node, wb bool) {
 	// 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) {
+		if n.Left.Type.IsSlice() || n.Left.Type.IsString() {
 			n.Addable = n.Left.Addable
 		}
 
 	case OCAP:
-		if Isslice(n.Left.Type) {
+		if n.Left.Type.IsSlice() {
 			n.Addable = n.Left.Addable
 		}
 
@@ -204,10 +204,10 @@ func cgen_wb(n, res *Node, wb bool) {
 
 	// Write barrier now handled. Code below this line can ignore wb.
 
-	if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
+	if Ctxt.Arch.Family == sys.ARM { // TODO(rsc): Maybe more often?
 		// if both are addressable, move
 		if n.Addable && res.Addable {
-			if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || Iscomplex[n.Type.Etype] || Iscomplex[res.Type.Etype] {
+			if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || n.Type.IsComplex() || res.Type.IsComplex() {
 				Thearch.Gmove(n, res)
 			} else {
 				var n1 Node
@@ -247,12 +247,12 @@ func cgen_wb(n, res *Node, wb bool) {
 		return
 	}
 
-	if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable {
+	if Ctxt.Arch.InFamily(sys.AMD64, sys.I386, sys.S390X) && n.Addable {
 		Thearch.Gmove(n, res)
 		return
 	}
 
-	if Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+	if Ctxt.Arch.InFamily(sys.ARM64, sys.MIPS64, sys.PPC64) {
 		// if both are addressable, move
 		if n.Addable {
 			if n.Op == OREGISTER || res.Op == OREGISTER {
@@ -269,7 +269,7 @@ func cgen_wb(n, res *Node, wb bool) {
 	}
 
 	// 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] {
+	if Ctxt.Arch.Family == sys.ARM && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() {
 		a := Thearch.Optoas(OAS, n.Type)
 		var addr obj.Addr
 		if Thearch.Sudoaddable(a, n, &addr) {
@@ -311,7 +311,7 @@ func cgen_wb(n, res *Node, wb bool) {
 	}
 
 	// 64-bit ops are hard on 32-bit machine.
-	if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
+	if Ctxt.Arch.RegSize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
 		switch n.Op {
 		// math goes to cgen64.
 		case OMINUS,
@@ -330,12 +330,12 @@ func cgen_wb(n, res *Node, wb bool) {
 		}
 	}
 
-	if Thearch.Cgen_float != nil && nl != nil && Isfloat[n.Type.Etype] && Isfloat[nl.Type.Etype] {
+	if Thearch.Cgen_float != nil && nl != nil && n.Type.IsFloat() && nl.Type.IsFloat() {
 		Thearch.Cgen_float(n, res)
 		return
 	}
 
-	if !Iscomplex[n.Type.Etype] && Ctxt.Arch.Regsize == 8 {
+	if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 {
 		a := Thearch.Optoas(OAS, n.Type)
 		var addr obj.Addr
 		if Thearch.Sudoaddable(a, n, &addr) {
@@ -356,12 +356,12 @@ func cgen_wb(n, res *Node, wb bool) {
 		}
 	}
 
-	var a int
+	var a obj.As
 	switch n.Op {
 	default:
 		Dump("cgen", n)
 		Dump("cgen-res", res)
-		Fatalf("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
+		Fatalf("cgen: unknown op %v", Nconv(n, FmtShort|FmtSign))
 
 	case OOROR, OANDAND,
 		OEQ, ONE,
@@ -389,9 +389,9 @@ func cgen_wb(n, res *Node, wb bool) {
 		return
 
 	case OMINUS:
-		if Isfloat[nl.Type.Etype] {
+		if nl.Type.IsFloat() {
 			nr = Nodintconst(-1)
-			Convlit(&nr, n.Type)
+			nr = convlit(nr, n.Type)
 			a = Thearch.Optoas(OMUL, nl.Type)
 			goto sbop
 		}
@@ -402,11 +402,11 @@ func cgen_wb(n, res *Node, wb bool) {
 		Regalloc(&n1, nl.Type, res)
 
 		Cgen(nl, &n1)
-		if Ctxt.Arch.Thechar == '5' {
+		if Ctxt.Arch.Family == sys.ARM {
 			var n2 Node
 			Nodconst(&n2, nl.Type, 0)
 			Thearch.Gins(a, &n2, &n1)
-		} else if Ctxt.Arch.Thechar == '7' {
+		} else if Ctxt.Arch.Family == sys.ARM64 {
 			Thearch.Gins(a, &n1, &n1)
 		} else {
 			Thearch.Gins(a, nil, &n1)
@@ -453,7 +453,7 @@ func cgen_wb(n, res *Node, wb bool) {
 			return
 		}
 
-		if Ctxt.Arch.Thechar == '8' {
+		if Ctxt.Arch.Family == sys.I386 {
 			var n1 Node
 			var n2 Node
 			Tempname(&n2, n.Type)
@@ -466,19 +466,19 @@ func cgen_wb(n, res *Node, wb bool) {
 
 		var n1 Node
 		var n2 Node
-		if Ctxt.Arch.Thechar == '5' {
+		if Ctxt.Arch.Family == sys.ARM {
 			if nl.Addable && !Is64(nl.Type) {
 				Regalloc(&n1, nl.Type, res)
 				Thearch.Gmove(nl, &n1)
 			} else {
-				if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || Isfloat[nl.Type.Etype] {
+				if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || nl.Type.IsFloat() {
 					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] {
+			if n.Type.Width > int64(Widthptr) || Is64(n.Type) || n.Type.IsFloat() {
 				Tempname(&n2, n.Type)
 			} else {
 				Regalloc(&n2, n.Type, nil)
@@ -518,8 +518,7 @@ func cgen_wb(n, res *Node, wb bool) {
 	case ODOT,
 		ODOTPTR,
 		OINDEX,
-		OIND,
-		ONAME: // PHEAP or PPARAMREF var
+		OIND:
 		var n1 Node
 		Igen(n, &n1, res)
 
@@ -555,7 +554,7 @@ func cgen_wb(n, res *Node, wb bool) {
 		Regfree(&n1)
 
 	case OLEN:
-		if Istype(nl.Type, TMAP) || Istype(nl.Type, TCHAN) {
+		if nl.Type.IsMap() || nl.Type.IsChan() {
 			// map and chan have len in the first int-sized word.
 			// a zero pointer means zero length
 			var n1 Node
@@ -579,7 +578,7 @@ func cgen_wb(n, res *Node, wb bool) {
 			break
 		}
 
-		if Istype(nl.Type, TSTRING) || Isslice(nl.Type) {
+		if nl.Type.IsString() || nl.Type.IsSlice() {
 			// both slice and string have len one pointer into the struct.
 			// a zero pointer means zero length
 			var n1 Node
@@ -592,10 +591,10 @@ func cgen_wb(n, res *Node, wb bool) {
 			break
 		}
 
-		Fatalf("cgen: OLEN: unknown type %v", Tconv(nl.Type, obj.FmtLong))
+		Fatalf("cgen: OLEN: unknown type %v", Tconv(nl.Type, FmtLong))
 
 	case OCAP:
-		if Istype(nl.Type, TCHAN) {
+		if nl.Type.IsChan() {
 			// chan has cap in the second int-sized word.
 			// a zero pointer means zero length
 			var n1 Node
@@ -620,7 +619,7 @@ func cgen_wb(n, res *Node, wb bool) {
 			break
 		}
 
-		if Isslice(nl.Type) {
+		if nl.Type.IsSlice() {
 			var n1 Node
 			Igen(nl, &n1, res)
 			n1.Type = Types[Simtype[TUINT]]
@@ -630,7 +629,7 @@ func cgen_wb(n, res *Node, wb bool) {
 			break
 		}
 
-		Fatalf("cgen: OCAP: unknown type %v", Tconv(nl.Type, obj.FmtLong))
+		Fatalf("cgen: OCAP: unknown type %v", Tconv(nl.Type, FmtLong))
 
 	case OADDR:
 		if n.Bounded { // let race detector avoid nil checks
@@ -654,7 +653,7 @@ func cgen_wb(n, res *Node, wb bool) {
 		cgen_callret(n, res)
 
 	case OMOD, ODIV:
-		if Isfloat[n.Type.Etype] || Thearch.Dodiv == nil {
+		if n.Type.IsFloat() || Thearch.Dodiv == nil {
 			a = Thearch.Optoas(n.Op, nl.Type)
 			goto abop
 		}
@@ -708,7 +707,7 @@ sbop: // symmetric binary
 abop: // asymmetric binary
 	var n1 Node
 	var n2 Node
-	if Ctxt.Arch.Thechar == '8' {
+	if Ctxt.Arch.Family == sys.I386 {
 		// no registers, sigh
 		if Smallintconst(nr) {
 			var n1 Node
@@ -752,14 +751,14 @@ abop: // asymmetric binary
 		Regalloc(&n1, nl.Type, res)
 		Cgen(nl, &n1)
 
-		if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+		if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
 			n2 = *nr
 		} else {
 			Regalloc(&n2, nr.Type, nil)
 			Cgen(nr, &n2)
 		}
 	} else {
-		if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+		if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
 			n2 = *nr
 		} else {
 			Regalloc(&n2, nr.Type, res)
@@ -781,7 +780,7 @@ var sys_wbptr *Node
 
 func cgen_wbptr(n, res *Node) {
 	if Curfn != nil {
-		if Curfn.Func.Nowritebarrier {
+		if Curfn.Func.Pragma&Nowritebarrier != 0 {
 			Yyerror("write barrier prohibited")
 		}
 		if Curfn.Func.WBLineno == 0 {
@@ -801,9 +800,9 @@ func cgen_wbptr(n, res *Node) {
 		Cgenr(n, &src, nil)
 	}
 
-	wbVar := syslook("writeBarrier", 0)
-	wbEnabled := Nod(ODOT, wbVar, newname(wbVar.Type.Type.Sym))
-	wbEnabled = typecheck(&wbEnabled, Erv)
+	wbVar := syslook("writeBarrier")
+	wbEnabled := NodSym(ODOT, wbVar, wbVar.Type.Field(0).Sym)
+	wbEnabled = typecheck(wbEnabled, Erv)
 	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)
@@ -831,7 +830,7 @@ func cgen_wbptr(n, res *Node) {
 
 func cgen_wbfat(n, res *Node) {
 	if Curfn != nil {
-		if Curfn.Func.Nowritebarrier {
+		if Curfn.Func.Pragma&Nowritebarrier != 0 {
 			Yyerror("write barrier prohibited")
 		}
 		if Curfn.Func.WBLineno == 0 {
@@ -877,8 +876,8 @@ func cgen_wbfat(n, res *Node) {
 // cgen_norm moves n1 to res, truncating to expected type if necessary.
 // n1 is a register, and cgen_norm frees it.
 func cgen_norm(n, n1, res *Node) {
-	switch Ctxt.Arch.Thechar {
-	case '6', '8':
+	switch Ctxt.Arch.Family {
+	case sys.AMD64, sys.I386:
 		// We use sized math, so the result is already truncated.
 	default:
 		switch n.Op {
@@ -905,7 +904,7 @@ func Mgen(n *Node, n1 *Node, rg *Node) {
 
 	Tempname(n1, n.Type)
 	Cgen(n, n1)
-	if n.Type.Width <= int64(Widthptr) || Isfloat[n.Type.Etype] {
+	if n.Type.Width <= int64(Widthptr) || n.Type.IsFloat() {
 		n2 := *n1
 		Regalloc(n1, n.Type, rg)
 		Thearch.Gmove(&n2, n1)
@@ -946,7 +945,7 @@ func Cgenr(n *Node, a *Node, res *Node) {
 		OCALLINTER:
 		var n1 Node
 		Igen(n, &n1, res)
-		Regalloc(a, Types[Tptr], &n1)
+		Regalloc(a, n.Type, &n1)
 		Thearch.Gmove(&n1, a)
 		Regfree(&n1)
 
@@ -978,10 +977,14 @@ func Agenr(n *Node, a *Node, res *Node) {
 
 	case OIND:
 		Cgenr(n.Left, a, res)
-		Cgen_checknil(a)
+		if !n.Left.NonNil {
+			Cgen_checknil(a)
+		} else if Debug_checknil != 0 && n.Lineno > 1 {
+			Warnl(n.Lineno, "removed nil check")
+		}
 
 	case OINDEX:
-		if Ctxt.Arch.Thechar == '5' {
+		if Ctxt.Arch.Family == sys.ARM {
 			var p2 *obj.Prog // to be patched to panicindex.
 			w := uint32(n.Type.Width)
 			bounded := Debug['B'] != 0 || n.Bounded
@@ -1033,9 +1036,9 @@ func Agenr(n *Node, a *Node, res *Node) {
 				if Isconst(nl, CTSTR) {
 					Fatalf("constant string constant index")
 				}
-				v := uint64(Mpgetfix(nr.Val().U.(*Mpint)))
+				v := uint64(nr.Int64())
 				var n2 Node
-				if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+				if nl.Type.IsSlice() || nl.Type.IsString() {
 					if Debug['B'] == 0 && !n.Bounded {
 						n1 = n3
 						n1.Op = OINDREG
@@ -1070,7 +1073,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 				// 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 {
+				} else if nl.Type.IsSlice() || nl.Type.IsString() {
 					n1 = n3
 					n1.Op = OINDREG
 					n1.Type = Types[Tptr]
@@ -1078,7 +1081,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 					Regalloc(&n4, Types[TUINT32], nil)
 					Thearch.Gmove(&n1, &n4)
 				} else {
-					Nodconst(&n4, Types[TUINT32], nl.Type.Bound)
+					Nodconst(&n4, Types[TUINT32], nl.Type.NumElem())
 				}
 				p1 := Thearch.Ginscmp(OLT, Types[TUINT32], &n2, &n4, +1)
 				if n4.Op == OREGISTER {
@@ -1096,7 +1099,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 				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 {
+			} else if nl.Type.IsSlice() || nl.Type.IsString() {
 				n1 = n3
 				n1.Op = OINDREG
 				n1.Type = Types[Tptr]
@@ -1128,7 +1131,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 			Regfree(&n2)
 			break
 		}
-		if Ctxt.Arch.Thechar == '8' {
+		if Ctxt.Arch.Family == sys.I386 {
 			var p2 *obj.Prog // to be patched to panicindex.
 			w := uint32(n.Type.Width)
 			bounded := Debug['B'] != 0 || n.Bounded
@@ -1168,7 +1171,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 
 			// For fixed array we really want the pointer in n3.
 			var n2 Node
-			if Isfixedarray(nl.Type) {
+			if nl.Type.IsArray() {
 				Regalloc(&n2, Types[Tptr], &n3)
 				Agen(&n3, &n2)
 				Regfree(&n3)
@@ -1185,8 +1188,8 @@ func Agenr(n *Node, a *Node, res *Node) {
 				if Isconst(nl, CTSTR) {
 					Fatalf("constant string constant index") // front end should handle
 				}
-				v := uint64(Mpgetfix(nr.Val().U.(*Mpint)))
-				if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+				v := uint64(nr.Int64())
+				if nl.Type.IsSlice() || nl.Type.IsString() {
 					if Debug['B'] == 0 && !n.Bounded {
 						nlen := n3
 						nlen.Type = Types[TUINT32]
@@ -1216,7 +1219,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 			// i is in register n1, extend to 32 bits.
 			t := Types[TUINT32]
 
-			if Issigned[n1.Type.Etype] {
+			if n1.Type.IsSigned() {
 				t = Types[TINT32]
 			}
 
@@ -1231,12 +1234,12 @@ func Agenr(n *Node, a *Node, res *Node) {
 				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 {
+				} else if nl.Type.IsSlice() || nl.Type.IsString() {
 					nlen = n3
 					nlen.Type = t
 					nlen.Xoffset += int64(Array_nel)
 				} else {
-					Nodconst(&nlen, t, nl.Type.Bound)
+					Nodconst(&nlen, t, nl.Type.NumElem())
 				}
 
 				p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1)
@@ -1259,7 +1262,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 			// Load base pointer in n3.
 			Regalloc(&tmp, Types[Tptr], &n3)
 
-			if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+			if nl.Type.IsSlice() || nl.Type.IsString() {
 				n3.Type = Types[Tptr]
 				n3.Xoffset += int64(Array_array)
 				Thearch.Gmove(&n3, &tmp)
@@ -1305,7 +1308,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 		if nl.Addable {
 			Cgenr(nr, &n1, nil)
 			if !Isconst(nl, CTSTR) {
-				if Isfixedarray(nl.Type) {
+				if nl.Type.IsArray() {
 					Agenr(nl, &n3, res)
 				} else {
 					Igen(nl, &nlen, res)
@@ -1328,7 +1331,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 
 	irad:
 		if !Isconst(nl, CTSTR) {
-			if Isfixedarray(nl.Type) {
+			if nl.Type.IsArray() {
 				Agenr(nl, &n3, res)
 			} else {
 				if !nl.Addable {
@@ -1375,8 +1378,8 @@ func Agenr(n *Node, a *Node, res *Node) {
 			if Isconst(nl, CTSTR) {
 				Fatalf("constant string constant index") // front end should handle
 			}
-			v := uint64(Mpgetfix(nr.Val().U.(*Mpint)))
-			if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+			v := uint64(nr.Int64())
+			if nl.Type.IsSlice() || nl.Type.IsString() {
 				if Debug['B'] == 0 && !n.Bounded {
 					p1 := Thearch.Ginscmp(OGT, Types[Simtype[TUINT]], &nlen, Nodintconst(int64(v)), +1)
 					Ginscall(Panicindex, -1)
@@ -1396,7 +1399,7 @@ func Agenr(n *Node, a *Node, res *Node) {
 		// type of the index
 		t := Types[TUINT64]
 
-		if Issigned[n1.Type.Etype] {
+		if n1.Type.IsSigned() {
 			t = Types[TINT64]
 		}
 
@@ -1414,10 +1417,10 @@ func Agenr(n *Node, a *Node, res *Node) {
 			}
 			if Isconst(nl, CTSTR) {
 				Nodconst(&nlen, t, int64(len(nl.Val().U.(string))))
-			} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+			} else if nl.Type.IsSlice() || nl.Type.IsString() {
 				// nlen already initialized
 			} else {
-				Nodconst(&nlen, t, nl.Type.Bound)
+				Nodconst(&nlen, t, nl.Type.NumElem())
 			}
 
 			p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1)
@@ -1541,7 +1544,8 @@ func Agen(n *Node, res *Node) {
 
 	switch n.Op {
 	default:
-		Fatalf("agen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
+		Dump("bad agen", n)
+		Fatalf("agen: unknown op %v", Nconv(n, FmtShort|FmtSign))
 
 	case OCALLMETH:
 		cgen_callmeth(n, 0)
@@ -1567,27 +1571,13 @@ func Agen(n *Node, res *Node) {
 		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)
-			Fatalf("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)
-			Fatalf("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)
+		if !nl.NonNil {
+			Cgen_checknil(res)
+		} else if Debug_checknil != 0 && n.Lineno > 1 {
+			Warnl(n.Lineno, "removed nil check")
+		}
 
 	case ODOT:
 		Agen(nl, res)
@@ -1597,7 +1587,11 @@ func Agen(n *Node, res *Node) {
 
 	case ODOTPTR:
 		Cgen(nl, res)
-		Cgen_checknil(res)
+		if !nl.NonNil {
+			Cgen_checknil(res)
+		} else if Debug_checknil != 0 && n.Lineno > 1 {
+			Warnl(n.Lineno, "removed nil check")
+		}
 		if n.Xoffset != 0 {
 			addOffset(res, n.Xoffset)
 		}
@@ -1605,7 +1599,7 @@ func Agen(n *Node, res *Node) {
 }
 
 func addOffset(res *Node, offset int64) {
-	if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' {
+	if Ctxt.Arch.InFamily(sys.AMD64, sys.I386) {
 		Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res)
 		return
 	}
@@ -1634,8 +1628,9 @@ func Igen(n *Node, a *Node, res *Node) {
 
 	switch n.Op {
 	case ONAME:
-		if (n.Class&PHEAP != 0) || n.Class == PPARAMREF {
-			break
+		if n.Class == PAUTOHEAP {
+			Dump("igen", n)
+			Fatalf("bad name")
 		}
 		*a = *n
 		return
@@ -1658,7 +1653,11 @@ func Igen(n *Node, a *Node, res *Node) {
 
 	case ODOTPTR:
 		Cgenr(n.Left, a, res)
-		Cgen_checknil(a)
+		if !n.Left.NonNil {
+			Cgen_checknil(a)
+		} else if Debug_checknil != 0 && n.Lineno > 1 {
+			Warnl(n.Lineno, "removed nil check")
+		}
 		a.Op = OINDREG
 		a.Xoffset += n.Xoffset
 		a.Type = n.Type
@@ -1677,25 +1676,24 @@ func Igen(n *Node, a *Node, res *Node) {
 			cgen_callinter(n, nil, 0)
 		}
 
-		var flist Iter
-		fp := Structfirst(&flist, Getoutarg(n.Left.Type))
+		fp := n.Left.Type.Results().Field(0)
 		*a = Node{}
 		a.Op = OINDREG
 		a.Reg = int16(Thearch.REGSP)
 		a.Addable = true
-		a.Xoffset = fp.Width + Ctxt.FixedFrameSize()
+		a.Xoffset = fp.Offset + Ctxt.FixedFrameSize()
 		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)) {
+		// 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 n.Left.Type.IsArray() || (n.Left.Type.IsPtr() && n.Left.Left.Type.IsArray()) {
 			if Isconst(n.Right, CTINT) {
 				// Compute &a.
-				if !Isptr[n.Left.Type.Etype] {
+				if !n.Left.Type.IsPtr() {
 					Igen(n.Left, a, res)
 				} else {
 					var n1 Node
@@ -1710,7 +1708,7 @@ func Igen(n *Node, a *Node, res *Node) {
 				// Compute &a[i] as &a + i*width.
 				a.Type = n.Type
 
-				a.Xoffset += Mpgetfix(n.Right.Val().U.(*Mpint)) * n.Type.Width
+				a.Xoffset += n.Right.Int64() * n.Type.Width
 				Fixlargeoffset(a)
 				return
 			}
@@ -1753,7 +1751,7 @@ func Bvgen(n, res *Node, wantTrue bool) {
 func bvgenjump(n, res *Node, wantTrue, geninit bool) {
 	init := n.Ninit
 	if !geninit {
-		n.Ninit = nil
+		n.Ninit.Set(nil)
 	}
 	p1 := Gbranch(obj.AJMP, nil, 0)
 	p2 := Pc
@@ -1763,7 +1761,7 @@ func bvgenjump(n, res *Node, wantTrue, geninit bool) {
 	Bgen(n, wantTrue, 0, p2)
 	Thearch.Gmove(Nodbool(false), res)
 	Patch(p3, Pc)
-	n.Ninit = init
+	n.Ninit.MoveNodes(&init)
 }
 
 // bgenx is the backend for Bgen and Bvgen.
@@ -1785,14 +1783,14 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 	Genlist(n.Ninit)
 
 	if n.Type == nil {
-		Convlit(&n, Types[TBOOL])
+		n = convlit(n, Types[TBOOL])
 		if n.Type == nil {
 			return
 		}
 	}
 
-	if n.Type.Etype != TBOOL {
-		Fatalf("bgen: bad type %v for %v", n.Type, Oconv(int(n.Op), 0))
+	if !n.Type.IsBoolean() {
+		Fatalf("bgen: bad type %v for %v", n.Type, n.Op)
 	}
 
 	for n.Op == OCONVNOP {
@@ -1800,7 +1798,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 		Genlist(n.Ninit)
 	}
 
-	if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] {
+	if Thearch.Bgen_float != nil && n.Left != nil && n.Left.Type.IsFloat() {
 		if genval {
 			bvgenjump(n, res, wantTrue, false)
 			return
@@ -1827,13 +1825,14 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 		return
 
 	case ONAME:
+		// Some architectures might need a temporary or other help here,
+		// but they don't support direct generation of a bool value yet.
+		// We can fix that as we go.
+		mayNeedTemp := Ctxt.Arch.InFamily(sys.ARM, sys.ARM64, sys.MIPS64, sys.PPC64, sys.S390X)
+
 		if genval {
-			// 5g, 7g, and 9g might need a temporary or other help here,
-			// but they don't support direct generation of a bool value yet.
-			// We can fix that as we go.
-			switch Ctxt.Arch.Thechar {
-			case '0', '5', '7', '9':
-				Fatalf("genval 0g, 5g, 7g, 9g ONAMES not fully implemented")
+			if mayNeedTemp {
+				Fatalf("genval ONAMES not fully implemented")
 			}
 			Cgen(n, res)
 			if !wantTrue {
@@ -1842,7 +1841,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 			return
 		}
 
-		if n.Addable && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' {
+		if n.Addable && !mayNeedTemp {
 			// no need for a temporary
 			bgenNonZero(n, nil, wantTrue, likely, to)
 			return
@@ -1857,7 +1856,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 	case OLITERAL:
 		// n is a constant.
 		if !Isconst(n, CTBOOL) {
-			Fatalf("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong))
+			Fatalf("bgen: non-bool const %v\n", Nconv(n, FmtLong))
 		}
 		if genval {
 			Cgen(Nodbool(wantTrue == n.Val().U.(bool)), res)
@@ -1918,14 +1917,14 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 	op := n.Op
 
 	if !wantTrue {
-		if Isfloat[nr.Type.Etype] {
+		if nr.Type.IsFloat() {
 			// Brcom is not valid on floats when NaN is involved.
 			ll := n.Ninit // avoid re-genning Ninit
-			n.Ninit = nil
+			n.Ninit.Set(nil)
 			if genval {
 				bgenx(n, res, true, likely, to)
 				Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) // res = !res
-				n.Ninit = ll
+				n.Ninit.Set(ll.Slice())
 				return
 			}
 			p1 := Gbranch(obj.AJMP, nil, 0)
@@ -1934,7 +1933,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 			bgenx(n, res, true, -likely, p2)
 			Patch(Gbranch(obj.AJMP, nil, 0), to)
 			Patch(p2, Pc)
-			n.Ninit = ll
+			n.Ninit.Set(ll.Slice())
 			return
 		}
 
@@ -1948,10 +1947,10 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 		nl, nr = nr, nl
 	}
 
-	if Isslice(nl.Type) || Isinter(nl.Type) {
+	if nl.Type.IsSlice() || nl.Type.IsInterface() {
 		// front end should only leave cmp to literal nil
 		if (op != OEQ && op != ONE) || nr.Op != OLITERAL {
-			if Isslice(nl.Type) {
+			if nl.Type.IsSlice() {
 				Yyerror("illegal slice comparison")
 			} else {
 				Yyerror("illegal interface comparison")
@@ -1961,7 +1960,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 
 		var ptr Node
 		Igen(nl, &ptr, nil)
-		if Isslice(nl.Type) {
+		if nl.Type.IsSlice() {
 			ptr.Xoffset += int64(Array_array)
 		}
 		ptr.Type = Types[Tptr]
@@ -1974,12 +1973,12 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 		return
 	}
 
-	if Iscomplex[nl.Type.Etype] {
+	if nl.Type.IsComplex() {
 		complexbool(op, nl, nr, res, wantTrue, likely, to)
 		return
 	}
 
-	if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
+	if Ctxt.Arch.RegSize == 4 && Is64(nr.Type) {
 		if genval {
 			// TODO: Teach Cmp64 to generate boolean values and remove this.
 			bvgenjump(n, res, wantTrue, false)
@@ -2017,7 +2016,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 		Regfree(&n2)
 	} else {
 		var n1 Node
-		if !nl.Addable && Ctxt.Arch.Thechar == '8' {
+		if !nl.Addable && Ctxt.Arch.Family == sys.I386 {
 			Tempname(&n1, nl.Type)
 		} else {
 			Regalloc(&n1, nl.Type, nil)
@@ -2026,13 +2025,13 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 		Cgen(nl, &n1)
 		nl = &n1
 
-		if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '9' {
+		if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.PPC64 {
 			Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
 			bins(nr.Type, res, op, likely, to)
 			return
 		}
 
-		if !nr.Addable && Ctxt.Arch.Thechar == '8' {
+		if !nr.Addable && Ctxt.Arch.Family == sys.I386 {
 			nr = CgenTemp(nr)
 		}
 
@@ -2046,13 +2045,13 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 	l, r := nl, nr
 
 	// On x86, only < and <= work right with NaN; reverse if needed
-	if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (op == OGT || op == OGE) {
+	if Ctxt.Arch.Family == sys.AMD64 && nl.Type.IsFloat() && (op == OGT || op == OGE) {
 		l, r = r, l
 		op = Brrev(op)
 	}
 
 	// MIPS does not have CMP instruction
-	if Ctxt.Arch.Thechar == '0' {
+	if Ctxt.Arch.Family == sys.MIPS64 {
 		p := Thearch.Ginscmp(op, nr.Type, l, r, likely)
 		Patch(p, to)
 		return
@@ -2063,9 +2062,9 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 
 	// 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 nl.Type.IsFloat() {
+		switch Ctxt.Arch.Family {
+		case sys.ARM:
 			if genval {
 				Fatalf("genval 5g Isfloat special cases not implemented")
 			}
@@ -2079,7 +2078,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 				Patch(p, Pc)
 			}
 			return
-		case '6':
+		case sys.AMD64:
 			switch n.Op {
 			case OEQ:
 				// neither NE nor P
@@ -2113,7 +2112,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 				}
 				return
 			}
-		case '7', '9':
+		case sys.ARM64, sys.PPC64:
 			if genval {
 				Fatalf("genval 7g, 9g Isfloat special cases not implemented")
 			}
@@ -2145,7 +2144,7 @@ func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
 	}
 
 	// MIPS does not have CMP instruction
-	if Thearch.Thechar == '0' {
+	if Thearch.LinkArch.Family == sys.MIPS64 {
 		p := Gbranch(Thearch.Optoas(op, n.Type), n.Type, likely)
 		Naddr(&p.From, n)
 		Patch(p, to)
@@ -2197,7 +2196,7 @@ func stkof(n *Node) int64 {
 
 	case ODOT:
 		t := n.Left.Type
-		if Isptr[t.Etype] {
+		if t.IsPtr() {
 			break
 		}
 		off := stkof(n.Left)
@@ -2208,7 +2207,7 @@ func stkof(n *Node) int64 {
 
 	case OINDEX:
 		t := n.Left.Type
-		if !Isfixedarray(t) {
+		if !t.IsArray() {
 			break
 		}
 		off := stkof(n.Left)
@@ -2216,20 +2215,19 @@ func stkof(n *Node) int64 {
 			return off
 		}
 		if Isconst(n.Right, CTINT) {
-			return off + t.Type.Width*Mpgetfix(n.Right.Val().U.(*Mpint))
+			return off + t.Elem().Width*n.Right.Int64()
 		}
 		return +1000 // on stack but not sure exactly where
 
 	case OCALLMETH, OCALLINTER, OCALLFUNC:
 		t := n.Left.Type
-		if Isptr[t.Etype] {
-			t = t.Type
+		if t.IsPtr() {
+			t = t.Elem()
 		}
 
-		var flist Iter
-		t = Structfirst(&flist, Getoutarg(t))
-		if t != nil {
-			return t.Width + Ctxt.FixedFrameSize()
+		f := t.Results().Field(0)
+		if f != nil {
+			return f.Offset + Ctxt.FixedFrameSize()
 		}
 	}
 
@@ -2263,9 +2261,9 @@ func sgen_wb(n *Node, ns *Node, w int64, wb bool) {
 	// 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)
+		for _, ln := range Curfn.Func.Dcl {
+			if ln.Class == PPARAMOUT {
+				Gvardef(ln)
 			}
 		}
 	}
@@ -2296,7 +2294,7 @@ func sgen_wb(n *Node, ns *Node, w int64, wb bool) {
 
 	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
+		// an unknown position. Could generate code to test
 		// for forward/backward copy, but instead just copy
 		// to a temporary location first.
 		//
@@ -2355,7 +2353,7 @@ func Ginscall(f *Node, proc int) {
 				// into the instruction stream.
 				Thearch.Ginsnop()
 
-				if Thearch.Thechar == '9' {
+				if Thearch.LinkArch.Family == sys.PPC64 {
 					// On ppc64, when compiling Go into position
 					// independent code on ppc64le we insert an
 					// instruction to reload the TOC pointer from the
@@ -2364,7 +2362,7 @@ func Ginscall(f *Node, proc int) {
 					// If the MOVD is not needed, insert a hardware NOP
 					// so that the same number of instructions are used
 					// on ppc64 in both shared and non-shared modes.
-					if Ctxt.Flag_shared != 0 {
+					if Ctxt.Flag_shared {
 						p := Thearch.Gins(ppc64.AMOVD, nil, nil)
 						p.From.Type = obj.TYPE_MEM
 						p.From.Offset = 24
@@ -2439,12 +2437,7 @@ func Ginscall(f *Node, proc int) {
 func cgen_callinter(n *Node, res *Node, proc int) {
 	i := n.Left
 	if i.Op != ODOTINTER {
-		Fatalf("cgen_callinter: not ODOTINTER %v", Oconv(int(i.Op), 0))
-	}
-
-	f := i.Right // field
-	if f.Op != ONAME {
-		Fatalf("cgen_callinter: not ONAME %v", Oconv(int(f.Op), 0))
+		Fatalf("cgen_callinter: not ODOTINTER %v", i.Op)
 	}
 
 	i = i.Left // interface
@@ -2560,11 +2553,10 @@ func cgen_call(n *Node, proc int) {
 func cgen_callret(n *Node, res *Node) {
 	t := n.Left.Type
 	if t.Etype == TPTR32 || t.Etype == TPTR64 {
-		t = t.Type
+		t = t.Elem()
 	}
 
-	var flist Iter
-	fp := Structfirst(&flist, Getoutarg(t))
+	fp := t.Results().Field(0)
 	if fp == nil {
 		Fatalf("cgen_callret: nil")
 	}
@@ -2574,7 +2566,7 @@ func cgen_callret(n *Node, res *Node) {
 	nod.Reg = int16(Thearch.REGSP)
 	nod.Addable = true
 
-	nod.Xoffset = fp.Width + Ctxt.FixedFrameSize()
+	nod.Xoffset = fp.Offset + Ctxt.FixedFrameSize()
 	nod.Type = fp.Type
 	Cgen_as(res, &nod)
 }
@@ -2584,12 +2576,11 @@ func cgen_callret(n *Node, res *Node) {
 //	res = &return value from call.
 func cgen_aret(n *Node, res *Node) {
 	t := n.Left.Type
-	if Isptr[t.Etype] {
-		t = t.Type
+	if t.IsPtr() {
+		t = t.Elem()
 	}
 
-	var flist Iter
-	fp := Structfirst(&flist, Getoutarg(t))
+	fp := t.Results().Field(0)
 	if fp == nil {
 		Fatalf("cgen_aret: nil")
 	}
@@ -2598,7 +2589,7 @@ func cgen_aret(n *Node, res *Node) {
 	nod1.Op = OINDREG
 	nod1.Reg = int16(Thearch.REGSP)
 	nod1.Addable = true
-	nod1.Xoffset = fp.Width + Ctxt.FixedFrameSize()
+	nod1.Xoffset = fp.Offset + Ctxt.FixedFrameSize()
 	nod1.Type = fp.Type
 
 	if res.Op != OREGISTER {
@@ -2630,24 +2621,70 @@ func cgen_ret(n *Node) {
 	}
 }
 
+// hasHMUL64 reports whether the architecture supports 64-bit
+// signed and unsigned high multiplication (OHMUL).
+func hasHMUL64() bool {
+	switch Ctxt.Arch.Family {
+	case sys.AMD64, sys.S390X, sys.ARM64:
+		return true
+	case sys.ARM, sys.I386, sys.MIPS64, sys.PPC64:
+		return false
+	}
+	Fatalf("unknown architecture")
+	return false
+}
+
+// hasRROTC64 reports whether the architecture supports 64-bit
+// rotate through carry instructions (ORROTC).
+func hasRROTC64() bool {
+	switch Ctxt.Arch.Family {
+	case sys.AMD64:
+		return true
+	case sys.ARM, sys.ARM64, sys.I386, sys.MIPS64, sys.PPC64, sys.S390X:
+		return false
+	}
+	Fatalf("unknown architecture")
+	return false
+}
+
+func hasRightShiftWithCarry() bool {
+	switch Ctxt.Arch.Family {
+	case sys.ARM64:
+		return true
+	case sys.AMD64, sys.ARM, sys.I386, sys.MIPS64, sys.PPC64, sys.S390X:
+		return false
+	}
+	Fatalf("unknown architecture")
+	return false
+}
+
+func hasAddSetCarry() bool {
+	switch Ctxt.Arch.Family {
+	case sys.ARM64:
+		return true
+	case sys.AMD64, sys.ARM, sys.I386, sys.MIPS64, sys.PPC64, sys.S390X:
+		return false
+	}
+	Fatalf("unknown architecture")
+	return false
+}
+
 // generate division according to op, one of:
 //	res = nl / nr
 //	res = nl % nr
 func cgen_div(op Op, 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 == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+	// Architectures need to support 64-bit high multiplications
+	// (OHMUL) in order to perform divide by constant optimizations.
+	if nr.Op != OLITERAL || !hasHMUL64() {
 		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
+	// Try to do division using multiplication: (2^w)/d.
+	// See Hacker's Delight, chapter 10.
 	switch Simtype[nl.Type.Etype] {
 	default:
 		goto longdiv
@@ -2655,11 +2692,23 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
 	case TUINT64:
 		var m Magic
 		m.W = w
-		m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
+		m.Ud = uint64(nr.Int64())
 		Umagic(&m)
 		if m.Bad != 0 {
 			break
 		}
+
+		// In order to add the numerator we need to be able to
+		// avoid overflow. This is done by shifting the result of the
+		// addition right by 1 and inserting the carry bit into
+		// the MSB. For now this needs the RROTC instruction.
+		// TODO(mundaym): Hacker's Delight 2nd ed. chapter 10 proposes
+		// an alternative sequence of instructions for architectures
+		// (TODO: MIPS64, PPC64, S390X) that do not have a shift
+		// right with carry instruction.
+		if m.Ua != 0 && !hasRROTC64() && !hasRightShiftWithCarry() {
+			goto longdiv
+		}
 		if op == OMOD {
 			goto longmod
 		}
@@ -2673,13 +2722,21 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
 		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)
+			// Need to add numerator accounting for overflow.
+			if hasAddSetCarry() {
+				Thearch.AddSetCarry(&n1, &n3, &n3)
+			} else {
+				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)
+			if !hasRROTC64() {
+				Thearch.RightShiftWithCarry(&n3, uint(m.S), &n3)
+			} else {
+				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
@@ -2693,7 +2750,7 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
 	case TINT64:
 		var m Magic
 		m.W = w
-		m.Sd = Mpgetfix(nr.Val().U.(*Mpint))
+		m.Sd = nr.Int64()
 		Smagic(&m)
 		if m.Bad != 0 {
 			break
@@ -2711,7 +2768,7 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
 		Thearch.Cgen_hmul(&n1, &n2, &n3)
 
 		if m.Sm < 0 {
-			// need to add numerator
+			// Need to add numerator (cannot overflow).
 			Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
 		}
 
@@ -2724,8 +2781,8 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
 		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
+			// This could probably be removed by factoring it into
+			// the multiplier.
 			Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3)
 		}
 
@@ -2737,14 +2794,14 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
 
 	goto longdiv
 
-	// division and mod using (slow) hardware instruction
+	// 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
+	// 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)
@@ -2754,11 +2811,6 @@ longmod:
 	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
@@ -2803,13 +2855,8 @@ func cgen_append(n, res *Node) {
 		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)
-		Fatalf("append not lowered")
-	}
-	for l := n.List; l != nil; l = l.Next {
-		if l.N.Ullman >= UINF {
+	for _, n1 := range n.List.Slice() {
+		if n1.Ullman >= UINF {
 			Fatalf("append with function call arguments")
 		}
 	}
@@ -2818,7 +2865,7 @@ func cgen_append(n, res *Node) {
 	//
 	// 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)
+	needFullUpdate := !samesafeexpr(res, n.List.First())
 
 	// Copy src triple into base, len, cap.
 	base := temp(Types[Tptr])
@@ -2826,7 +2873,7 @@ func cgen_append(n, res *Node) {
 	cap := temp(Types[TUINT])
 
 	var src Node
-	Igen(n.List.N, &src, nil)
+	Igen(n.List.First(), &src, nil)
 	src.Type = Types[Tptr]
 	Thearch.Gmove(&src, base)
 	src.Type = Types[TUINT]
@@ -2839,7 +2886,7 @@ func cgen_append(n, res *Node) {
 	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)
+	Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(n.List.Len()-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
@@ -2854,7 +2901,7 @@ func cgen_append(n, res *Node) {
 	arg.Addable = true
 	arg.Xoffset = Ctxt.FixedFrameSize()
 	arg.Type = Ptrto(Types[TUINT8])
-	Cgen(typename(res.Type), &arg)
+	Cgen(typename(res.Type.Elem()), &arg)
 	arg.Xoffset += int64(Widthptr)
 
 	arg.Type = Types[Tptr]
@@ -2874,8 +2921,8 @@ func cgen_append(n, res *Node) {
 	arg.Xoffset += int64(Widthptr)
 	Regfree(&rlen)
 
-	fn := syslook("growslice", 1)
-	substArgTypes(fn, res.Type.Type, res.Type.Type)
+	fn := syslook("growslice")
+	fn = substArgTypes(fn, res.Type.Elem(), res.Type.Elem())
 	Ginscall(fn, 0)
 
 	if Widthptr == 4 && Widthreg == 8 {
@@ -2909,7 +2956,7 @@ func cgen_append(n, res *Node) {
 	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.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(n.List.Len()-1), &r1)
 	Thearch.Gmove(&r1, &dst)
 	Regfree(&r1)
 	dst.Xoffset += int64(Widthptr)
@@ -2947,7 +2994,7 @@ func cgen_append(n, res *Node) {
 	// is not going to use a write barrier.
 	i := 0
 	var r2 Node
-	for l := n.List.Next; l != nil; l = l.Next {
+	for _, n2 := range n.List.Slice()[1:] {
 		Regalloc(&r1, Types[Tptr], nil)
 		Thearch.Gmove(base, &r1)
 		Regalloc(&r2, Types[TUINT], nil)
@@ -2955,20 +3002,20 @@ func cgen_append(n, res *Node) {
 		if i > 0 {
 			Thearch.Gins(Thearch.Optoas(OADD, Types[TUINT]), Nodintconst(int64(i)), &r2)
 		}
-		w := res.Type.Type.Width
+		w := res.Type.Elem().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.Ginscon(Thearch.Optoas(OMUL, Types[TUINT]), 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))
+		r1.Type = res.Type.Elem()
+		cgen_wb(n2, &r1, needwritebarrier(&r1, n2))
 		Regfree(&r1)
 		i++
 	}
@@ -3005,11 +3052,11 @@ func cgen_slice(n, res *Node, wb bool) {
 	regalloc := Regalloc
 	ginscon := Thearch.Ginscon
 	gins := Thearch.Gins
-	if Thearch.Thechar == '8' {
+	if Thearch.LinkArch.Family == sys.I386 {
 		regalloc = func(n *Node, t *Type, reuse *Node) {
 			Tempname(n, t)
 		}
-		ginscon = func(as int, c int64, n *Node) {
+		ginscon = func(as obj.As, c int64, n *Node) {
 			var n1 Node
 			Regalloc(&n1, n.Type, n)
 			Thearch.Gmove(n, &n1)
@@ -3017,7 +3064,7 @@ func cgen_slice(n, res *Node, wb bool) {
 			Thearch.Gmove(&n1, n)
 			Regfree(&n1)
 		}
-		gins = func(as int, f, t *Node) *obj.Prog {
+		gins = func(as obj.As, f, t *Node) *obj.Prog {
 			var n1 Node
 			Regalloc(&n1, t.Type, t)
 			Thearch.Gmove(t, &n1)
@@ -3035,7 +3082,7 @@ func cgen_slice(n, res *Node, wb bool) {
 			return
 		}
 		if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
-			Nodconst(&xlen, indexRegType, n.Left.Type.Type.Bound)
+			Nodconst(&xlen, indexRegType, n.Left.Type.Elem().NumElem())
 			return
 		}
 		if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
@@ -3068,15 +3115,7 @@ func cgen_slice(n, res *Node, wb bool) {
 		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
-	}
+	x1, x2, x3 := n.SliceBounds() // unevaluated index arguments
 
 	// 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.
@@ -3193,22 +3232,22 @@ func cgen_slice(n, res *Node, wb bool) {
 	// 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
+		bound = n.Left.Type.Elem().NumElem()
 	} 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 {
+		if i.Val().U.(*Mpint).CmpInt64(0) < 0 || bound >= 0 && i.Val().U.(*Mpint).CmpInt64(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 {
+		if j.Val().U.(*Mpint).CmpInt64(0) < 0 || bound >= 0 && j.Val().U.(*Mpint).CmpInt64(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 {
+		if k.Val().U.(*Mpint).CmpInt64(0) < 0 || bound >= 0 && k.Val().U.(*Mpint).CmpInt64(bound) > 0 {
 			Yyerror("slice index out of bounds")
 		}
 	}
@@ -3217,7 +3256,7 @@ func cgen_slice(n, res *Node, wb bool) {
 	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
+			n1.Op == OLITERAL && n2.Op == OLITERAL && n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint)) == 0
 	}
 
 	// obvious reports whether n1 <= n2 is obviously true,
@@ -3236,7 +3275,7 @@ func cgen_slice(n, res *Node, wb bool) {
 			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 {
+			if n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint)) <= 0 {
 				return true // n1, n2 constants such that n1 <= n2
 			}
 			Yyerror("slice index out of bounds")
@@ -3248,12 +3287,12 @@ func cgen_slice(n, res *Node, wb bool) {
 	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 {
+		if Ctxt.Arch.RegSize == 4 && Is64(n1.Type) {
+			if n1.Val().U.(*Mpint).CmpInt64(1<<31) >= 0 {
 				Fatalf("missed slice out of bounds check")
 			}
 			var tmp Node
-			Nodconst(&tmp, indexRegType, Mpgetfix(n1.Val().U.(*Mpint)))
+			Nodconst(&tmp, indexRegType, n1.Int64())
 			n1 = &tmp
 		}
 		p := Thearch.Ginscmp(OGT, indexRegType, n1, n2, -1)
@@ -3337,9 +3376,9 @@ func cgen_slice(n, res *Node, wb bool) {
 			switch j.Op {
 			case OLITERAL:
 				if Isconst(&i, CTINT) {
-					Nodconst(&j, indexRegType, Mpgetfix(j.Val().U.(*Mpint))-Mpgetfix(i.Val().U.(*Mpint)))
+					Nodconst(&j, indexRegType, j.Int64()-i.Int64())
 					if Debug_slice > 0 {
-						Warn("slice: result len == %d", Mpgetfix(j.Val().U.(*Mpint)))
+						Warn("slice: result len == %d", j.Int64())
 					}
 					break
 				}
@@ -3354,7 +3393,7 @@ func cgen_slice(n, res *Node, wb bool) {
 				fallthrough
 			case OREGISTER:
 				if i.Op == OLITERAL {
-					v := Mpgetfix(i.Val().U.(*Mpint))
+					v := i.Int64()
 					if v != 0 {
 						ginscon(Thearch.Optoas(OSUB, indexRegType), v, &j)
 					}
@@ -3397,9 +3436,9 @@ func cgen_slice(n, res *Node, wb bool) {
 			switch k.Op {
 			case OLITERAL:
 				if Isconst(&i, CTINT) {
-					Nodconst(&k, indexRegType, Mpgetfix(k.Val().U.(*Mpint))-Mpgetfix(i.Val().U.(*Mpint)))
+					Nodconst(&k, indexRegType, k.Int64()-i.Int64())
 					if Debug_slice > 0 {
-						Warn("slice: result cap == %d", Mpgetfix(k.Val().U.(*Mpint)))
+						Warn("slice: result cap == %d", k.Int64())
 					}
 					break
 				}
@@ -3420,7 +3459,7 @@ func cgen_slice(n, res *Node, wb bool) {
 						Warn("slice: result cap == 0")
 					}
 				} else if i.Op == OLITERAL {
-					v := Mpgetfix(i.Val().U.(*Mpint))
+					v := i.Int64()
 					if v != 0 {
 						ginscon(Thearch.Optoas(OSUB, indexRegType), v, &k)
 					}
@@ -3477,7 +3516,13 @@ func cgen_slice(n, res *Node, wb bool) {
 			Cgenr(n.Left, &xbase, nil)
 			Cgen_checknil(&xbase)
 		} else {
-			regalloc(&xbase, Ptrto(res.Type.Type), nil)
+			var ptr *Type
+			if n.Op == OSLICESTR {
+				ptr = ptrToUint8
+			} else {
+				ptr = Ptrto(n.Type.Elem())
+			}
+			regalloc(&xbase, ptr, nil)
 			x.Type = xbase.Type
 			Thearch.Gmove(&x, &xbase)
 			Regfree(&x)
@@ -3500,10 +3545,10 @@ func cgen_slice(n, res *Node, wb bool) {
 			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
+				w = res.Type.Elem().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)
+				ginscon(Thearch.Optoas(OADD, xbase.Type), i.Int64()*w, &xbase)
 			} else if Thearch.AddIndex != nil && Thearch.AddIndex(&i, w, &xbase) {
 				// done by back end
 			} else if w == 1 {
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index df3e31a..66c710f 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -5,7 +5,6 @@
 package gc
 
 import (
-	"cmd/internal/obj"
 	"fmt"
 )
 
@@ -26,40 +25,39 @@ func closurehdr(ntype *Node) {
 	// references to these variables need to
 	// refer to the variables in the external
 	// function declared below; see walkclosure.
-	n.List = ntype.List
+	n.List.Set(ntype.List.Slice())
 
-	n.Rlist = ntype.Rlist
-	ntype.List = nil
-	ntype.Rlist = nil
-	for l := n.List; l != nil; l = l.Next {
-		name = l.N.Left
+	n.Rlist.Set(ntype.Rlist.Slice())
+	ntype.List.Set(nil)
+	ntype.Rlist.Set(nil)
+	for _, n1 := range n.List.Slice() {
+		name = n1.Left
 		if name != nil {
 			name = newname(name.Sym)
 		}
-		a = Nod(ODCLFIELD, name, l.N.Right)
-		a.Isddd = l.N.Isddd
+		a = Nod(ODCLFIELD, name, n1.Right)
+		a.Isddd = n1.Isddd
 		if name != nil {
 			name.Isddd = a.Isddd
 		}
-		ntype.List = list(ntype.List, a)
+		ntype.List.Append(a)
 	}
-
-	for l := n.Rlist; l != nil; l = l.Next {
-		name = l.N.Left
+	for _, n2 := range n.Rlist.Slice() {
+		name = n2.Left
 		if name != nil {
 			name = newname(name.Sym)
 		}
-		ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, name, l.N.Right))
+		ntype.Rlist.Append(Nod(ODCLFIELD, name, n2.Right))
 	}
 }
 
-func closurebody(body *NodeList) *Node {
-	if body == nil {
-		body = list1(Nod(OEMPTY, nil, nil))
+func closurebody(body []*Node) *Node {
+	if len(body) == 0 {
+		body = []*Node{Nod(OEMPTY, nil, nil)}
 	}
 
 	func_ := Curfn
-	func_.Nbody = body
+	func_.Nbody.Set(body)
 	func_.Func.Endlineno = lineno
 	funcbody(func_)
 
@@ -67,25 +65,52 @@ func closurebody(body *NodeList) *Node {
 	// 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)
+	for _, v := range func_.Func.Cvars.Slice() {
+		// Unlink from v1; see comment in syntax.go type Param for these fields.
+		v1 := v.Name.Defn
+		v1.Name.Param.Innermost = v.Name.Param.Outer
+
+		// If the closure usage of v is not dense,
+		// we need to make it dense; now that we're out
+		// of the function in which v appeared,
+		// look up v.Sym in the enclosing function
+		// and keep it around for use in the compiled code.
+		//
+		// That is, suppose we just finished parsing the innermost
+		// closure f4 in this code:
+		//
+		//	func f() {
+		//		v := 1
+		//		func() { // f2
+		//			use(v)
+		//			func() { // f3
+		//				func() { // f4
+		//					use(v)
+		//				}()
+		//			}()
+		//		}()
+		//	}
+		//
+		// At this point v.Outer is f2's v; there is no f3's v.
+		// To construct the closure f4 from within f3,
+		// we need to use f3's v and in this case we need to create f3's v.
+		// We are now in the context of f3, so calling oldname(v.Sym)
+		// obtains f3's v, creating it if necessary (as it is in the example).
+		//
+		// capturevars will decide whether to use v directly or &v.
+		v.Name.Param.Outer = 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
+	for _, ln := range func_.Func.Cvars.Slice() {
+		n := ln.Name.Defn
 		if !n.Name.Captured {
 			n.Name.Captured = true
 			if n.Name.Decldepth == 0 {
-				Fatalf("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort))
+				Fatalf("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, FmtShort))
 			}
 
 			// Ignore assignments to the variable in straightline code
@@ -96,14 +121,14 @@ func typecheckclosure(func_ *Node, top int) {
 		}
 	}
 
-	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
+	for _, ln := range func_.Func.Dcl {
+		if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
+			ln.Name.Decldepth = 1
 		}
 	}
 
 	oldfn := Curfn
-	typecheck(&func_.Func.Ntype, Etype)
+	func_.Func.Ntype = typecheck(func_.Func.Ntype, Etype)
 	func_.Type = func_.Func.Ntype.Type
 	func_.Func.Top = top
 
@@ -115,13 +140,13 @@ func typecheckclosure(func_ *Node, top int) {
 		Curfn = func_
 		olddd := decldepth
 		decldepth = 1
-		typechecklist(func_.Nbody, Etop)
+		typecheckslice(func_.Nbody.Slice(), Etop)
 		decldepth = olddd
 		Curfn = oldfn
 	}
 
 	// Create top-level function
-	xtop = list(xtop, makeclosure(func_))
+	xtop = append(xtop, makeclosure(func_))
 }
 
 // closurename returns name for OCLOSURE n.
@@ -141,7 +166,7 @@ func closurename(n *Node) *Sym {
 	prefix := ""
 	if n.Func.Outerfunc == nil {
 		// Global closure.
-		outer = "glob"
+		outer = "glob."
 
 		prefix = "func"
 		closurename_closgen++
@@ -170,7 +195,7 @@ func closurename(n *Node) *Sym {
 		n.Func.Outerfunc.Func.Closgen++
 		gen = n.Func.Outerfunc.Func.Closgen
 	} else {
-		Fatalf("closurename called for %v", Nconv(n, obj.FmtShort))
+		Fatalf("closurename called for %v", Nconv(n, FmtShort))
 	}
 	n.Sym = Lookupf("%s.%s%d", outer, prefix, gen)
 	return n.Sym
@@ -181,8 +206,8 @@ func makeclosure(func_ *Node) *Node {
 	// that begins by reading closure parameters.
 	xtype := Nod(OTFUNC, nil, nil)
 
-	xtype.List = func_.List
-	xtype.Rlist = func_.Rlist
+	xtype.List.Set(func_.List.Slice())
+	xtype.Rlist.Set(func_.Rlist.Slice())
 
 	// create the function
 	xfunc := Nod(ODCLFUNC, nil, nil)
@@ -197,19 +222,20 @@ func makeclosure(func_ *Node) *Node {
 	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 {
+	xfunc.Nbody.Set(func_.Nbody.Slice())
+	xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
+	func_.Func.Dcl = nil
+	if xfunc.Nbody.Len() == 0 {
 		Fatalf("empty body - won't generate any code")
 	}
-	typecheck(&xfunc, Etop)
+	xfunc = typecheck(xfunc, Etop)
 
 	xfunc.Func.Closure = func_
 	func_.Func.Closure = xfunc
 
-	func_.Nbody = nil
-	func_.List = nil
-	func_.Rlist = nil
+	func_.Nbody.Set(nil)
+	func_.List.Set(nil)
+	func_.Rlist.Set(nil)
 
 	return xfunc
 }
@@ -220,16 +246,12 @@ func makeclosure(func_ *Node) *Node {
 // 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)
+	lno := 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
+	func_.Func.Enter.Set(nil)
+	for _, v := range func_.Func.Cvars.Slice() {
 		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.
@@ -246,14 +268,14 @@ func capturevars(xfunc *Node) {
 		// 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
+		outer := v.Name.Param.Outer
+		outermost := v.Name.Defn
 
 		// 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 {
+		if outer.Class != PPARAMOUT && !outermost.Addrtaken && !outermost.Assigned && v.Type.Width <= 128 {
 			v.Name.Byval = true
 		} else {
-			v.Name.Param.Closure.Addrtaken = true
+			outermost.Addrtaken = true
 			outer = Nod(OADDR, outer, nil)
 		}
 
@@ -266,20 +288,20 @@ func capturevars(xfunc *Node) {
 			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))
+			Warnl(v.Lineno, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, outermost.Addrtaken, outermost.Assigned, int32(v.Type.Width))
 		}
 
-		typecheck(&outer, Erv)
-		func_.Func.Enter = list(func_.Func.Enter, outer)
+		outer = typecheck(outer, Erv)
+		func_.Func.Enter.Append(outer)
 	}
 
-	lineno = int32(lno)
+	lineno = 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)
+	lno := lineno
 	lineno = xfunc.Lineno
 	func_ := xfunc.Func.Closure
 
@@ -302,23 +324,15 @@ func transformclosure(xfunc *Node) {
 		// 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
+		var params []*Field
+		var decls []*Node
+		for _, v := range func_.Func.Cvars.Slice() {
 			if v.Op == OXXX {
 				continue
 			}
-			fld = typ(TFIELD)
-			fld.Funarg = true
+			fld := newField()
+			fld.Funarg = FunargParams
 			if v.Name.Byval {
 				// If v is captured by value, we merely downgrade it to PPARAM.
 				v.Class = PPARAM
@@ -328,9 +342,9 @@ func transformclosure(xfunc *Node) {
 			} else {
 				// If v of type T is captured by reference,
 				// we introduce function param &v *T
-				// and v remains PPARAMREF with &v heapaddr
+				// and v remains PAUTOHEAP with &v heapaddr
 				// (accesses will implicitly deref &v).
-				addr = newname(Lookupf("&%s", v.Sym.Name))
+				addr := newname(Lookupf("&%s", v.Sym.Name))
 				addr.Type = Ptrto(v.Type)
 				addr.Class = PPARAM
 				v.Name.Heapaddr = addr
@@ -340,14 +354,15 @@ func transformclosure(xfunc *Node) {
 			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)
+			params = append(params, fld)
+			decls = append(decls, fld.Nname)
+		}
 
-			*param = fld
-			param = &fld.Down
+		if len(params) > 0 {
+			// Prepend params and decls.
+			f.Type.Params().SetFields(append(params, f.Type.Params().FieldSlice()...))
+			xfunc.Func.Dcl = append(decls, xfunc.Func.Dcl...)
 		}
-		*param = original_args
-		xfunc.Func.Dcl = concat(xfunc.Func.Dcl, original_dcl)
 
 		// Recalculate param offsets.
 		if f.Type.Width > 0 {
@@ -357,19 +372,14 @@ func transformclosure(xfunc *Node) {
 		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
+		var body []*Node
 		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
+		for _, v := range func_.Func.Cvars.Slice() {
 			if v.Op == OXXX {
 				continue
 			}
-			nvar++
 
 			// cv refers to the field inside of closure OSTRUCTLIT.
 			cv = Nod(OCLOSUREVAR, nil, nil)
@@ -386,8 +396,8 @@ func transformclosure(xfunc *Node) {
 				// 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))
+				xfunc.Func.Dcl = append(xfunc.Func.Dcl, v)
+				body = append(body, Nod(OAS, v, cv))
 			} else {
 				// Declare variable holding addresses taken from closure
 				// and initialize in entry prologue.
@@ -396,28 +406,62 @@ func transformclosure(xfunc *Node) {
 				addr.Class = PAUTO
 				addr.Used = true
 				addr.Name.Curfn = xfunc
-				xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr)
+				xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr)
 				v.Name.Heapaddr = addr
 				if v.Name.Byval {
 					cv = Nod(OADDR, cv, nil)
 				}
-				body = list(body, Nod(OAS, addr, cv))
+				body = append(body, Nod(OAS, addr, cv))
 			}
 		}
 
-		typechecklist(body, Etop)
-		walkstmtlist(body)
-		xfunc.Func.Enter = body
-		xfunc.Func.Needctxt = nvar > 0
+		if len(body) > 0 {
+			typecheckslice(body, Etop)
+			walkstmtlist(body)
+			xfunc.Func.Enter.Set(body)
+			xfunc.Func.Needctxt = true
+		}
+	}
+
+	lineno = lno
+}
+
+// hasemptycvars returns true iff closure func_ has an
+// empty list of captured vars. OXXX nodes don't count.
+func hasemptycvars(func_ *Node) bool {
+	for _, v := range func_.Func.Cvars.Slice() {
+		if v.Op == OXXX {
+			continue
+		}
+		return false
 	}
+	return true
+}
 
-	lineno = int32(lno)
+// closuredebugruntimecheck applies boilerplate checks for debug flags
+// and compiling runtime
+func closuredebugruntimecheck(r *Node) {
+	if Debug_closure > 0 {
+		if r.Esc == EscHeap {
+			Warnl(r.Lineno, "heap closure, captured vars = %v", r.Func.Cvars)
+		} else {
+			Warnl(r.Lineno, "stack closure, captured vars = %v", r.Func.Cvars)
+		}
+	}
+	if compiling_runtime && r.Esc == EscHeap {
+		yyerrorl(r.Lineno, "heap-allocated closure, not allowed in runtime.")
+	}
 }
 
-func walkclosure(func_ *Node, init **NodeList) *Node {
+func walkclosure(func_ *Node, init *Nodes) *Node {
 	// If no closure vars, don't bother wrapping.
-	if func_.Func.Cvars == nil {
+	if hasemptycvars(func_) {
+		if Debug_closure > 0 {
+			Warnl(func_.Lineno, "closure converted to global")
+		}
 		return func_.Func.Closure.Func.Nname
+	} else {
+		closuredebugruntimecheck(func_)
 	}
 
 	// Create closure in the form of a composite literal.
@@ -436,11 +480,9 @@ func walkclosure(func_ *Node, init **NodeList) *Node {
 
 	typ := Nod(OTSTRUCT, nil, nil)
 
-	typ.List = list1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
+	typ.List.Set1(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
+	for _, v := range func_.Func.Cvars.Slice() {
 		if v.Op == OXXX {
 			continue
 		}
@@ -448,20 +490,20 @@ func walkclosure(func_ *Node, init **NodeList) *Node {
 		if !v.Name.Byval {
 			typ1 = Nod(OIND, typ1, nil)
 		}
-		typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1))
+		typ.List.Append(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)
+	clos.List.Set(append([]*Node{Nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)}, func_.Func.Enter.Slice()...))
 
 	// Force type conversion from *struct to the func type.
 	clos = Nod(OCONVNOP, clos, nil)
 
 	clos.Type = func_.Type
 
-	typecheck(&clos, Erv)
+	clos = typecheck(clos, Erv)
 
 	// typecheck will insert a PTRLIT node under CONVNOP,
 	// tag it with escape analysis result.
@@ -476,12 +518,10 @@ func walkclosure(func_ *Node, init **NodeList) *Node {
 		delete(prealloc, func_)
 	}
 
-	walkexpr(&clos, init)
-
-	return clos
+	return walkexpr(clos, init)
 }
 
-func typecheckpartialcall(fn *Node, sym *Node) {
+func typecheckpartialcall(fn *Node, sym *Sym) {
 	switch fn.Op {
 	case ODOTINTER, ODOTMETH:
 		break
@@ -493,27 +533,27 @@ func typecheckpartialcall(fn *Node, sym *Node) {
 	// Create top-level function.
 	xfunc := makepartialcall(fn, fn.Type, sym)
 	fn.Func = xfunc.Func
-	fn.Right = sym
+	fn.Right = newname(sym)
 	fn.Op = OCALLPART
 	fn.Type = xfunc.Type
 }
 
 var makepartialcall_gopkg *Pkg
 
-func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
+func makepartialcall(fn *Node, t0 *Type, meth *Sym) *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)
+	if exportname(meth.Name) {
+		p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Name)
 	} else {
-		p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), Sconv(meth.Sym, obj.FmtLeft))
+		p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, FmtLeft|FmtShort), sconv(meth, FmtLeft))
 	}
 	basetype := rcvrtype
-	if Isptr[rcvrtype.Etype] {
-		basetype = basetype.Type
+	if rcvrtype.IsPtr() {
+		basetype = basetype.Elem()
 	}
-	if basetype.Etype != TINTER && basetype.Sym == nil {
+	if !basetype.IsInterface() && basetype.Sym == nil {
 		Fatalf("missing base type for %v", rcvrtype)
 	}
 
@@ -540,42 +580,42 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
 
 	xtype := Nod(OTFUNC, nil, nil)
 	i := 0
-	var l *NodeList
-	var callargs *NodeList
+	var l []*Node
+	var callargs []*Node
 	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))
+	for _, t := range t0.Params().Fields().Slice() {
+		n = newname(LookupN("a", i))
 		i++
 		n.Class = PPARAM
-		xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
-		callargs = list(callargs, n)
+		xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
+		callargs = append(callargs, n)
 		fld = Nod(ODCLFIELD, n, typenod(t.Type))
 		if t.Isddd {
 			fld.Isddd = true
 			ddd = true
 		}
 
-		l = list(l, fld)
+		l = append(l, fld)
 	}
 
-	xtype.List = l
+	xtype.List.Set(l)
 	i = 0
 	l = nil
-	var retargs *NodeList
-	for t := getoutargx(t0).Type; t != nil; t = t.Down {
-		n = newname(Lookupf("r%d", i))
+	var retargs []*Node
+	for _, t := range t0.Results().Fields().Slice() {
+		n = newname(LookupN("r", 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)))
+		xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
+		retargs = append(retargs, n)
+		l = append(l, Nod(ODCLFIELD, n, typenod(t.Type)))
 	}
 
-	xtype.Rlist = l
+	xtype.Rlist.Set(l)
 
 	xfunc.Func.Dupok = true
 	xfunc.Func.Nname = newfuncname(sym)
@@ -600,41 +640,42 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
 	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.Xoffset = 0
+	xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr)
+	var body []*Node
+	if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
 		ptr.Name.Param.Ntype = typenod(rcvrtype)
-		body = list(body, Nod(OAS, ptr, cv))
+		body = append(body, Nod(OAS, ptr, cv))
 	} else {
 		ptr.Name.Param.Ntype = typenod(Ptrto(rcvrtype))
-		body = list(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
+		body = append(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
 	}
 
-	call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil)
-	call.List = callargs
+	call := Nod(OCALL, NodSym(OXDOT, ptr, meth), nil)
+	call.List.Set(callargs)
 	call.Isddd = ddd
-	if t0.Outtuple == 0 {
-		body = list(body, call)
+	if t0.Results().NumFields() == 0 {
+		body = append(body, call)
 	} else {
 		n := Nod(OAS2, nil, nil)
-		n.List = retargs
-		n.Rlist = list1(call)
-		body = list(body, n)
+		n.List.Set(retargs)
+		n.Rlist.Set1(call)
+		body = append(body, n)
 		n = Nod(ORETURN, nil, nil)
-		body = list(body, n)
+		body = append(body, n)
 	}
 
-	xfunc.Nbody = body
+	xfunc.Nbody.Set(body)
 
-	typecheck(&xfunc, Etop)
+	xfunc = typecheck(xfunc, Etop)
 	sym.Def = xfunc
-	xtop = list(xtop, xfunc)
+	xtop = append(xtop, xfunc)
 	Curfn = savecurfn
 
 	return xfunc
 }
 
-func walkpartialcall(n *Node, init **NodeList) *Node {
+func walkpartialcall(n *Node, init *Nodes) *Node {
 	// Create closure in the form of a composite literal.
 	// For x.M with receiver (x) type T, the generated code looks like:
 	//
@@ -642,7 +683,7 @@ func walkpartialcall(n *Node, init **NodeList) *Node {
 	//
 	// Like walkclosure above.
 
-	if Isinter(n.Left.Type) {
+	if n.Left.Type.IsInterface() {
 		// Trigger panic for method on nil interface now.
 		// Otherwise it happens in the wrapper and is confusing.
 		n.Left = cheapexpr(n.Left, init)
@@ -651,21 +692,21 @@ func walkpartialcall(n *Node, init **NodeList) *Node {
 	}
 
 	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)))
+	typ.List.Set1(Nod(ODCLFIELD, newname(Lookup("F")), typenod(Types[TUINTPTR])))
+	typ.List.Append(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)
+	clos.List.Set1(Nod(OCFUNC, n.Func.Nname, nil))
+	clos.List.Append(n.Left)
 
 	// Force type conversion from *struct to the func type.
 	clos = Nod(OCONVNOP, clos, nil)
 
 	clos.Type = n.Type
 
-	typecheck(&clos, Erv)
+	clos = typecheck(clos, Erv)
 
 	// typecheck will insert a PTRLIT node under CONVNOP,
 	// tag it with escape analysis result.
@@ -680,7 +721,5 @@ func walkpartialcall(n *Node, init **NodeList) *Node {
 		delete(prealloc, n)
 	}
 
-	walkexpr(&clos, init)
-
-	return clos
+	return walkexpr(clos, init)
 }
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index 795b53d..882daec 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -10,26 +10,79 @@ import (
 	"strings"
 )
 
-// IntLiteral returns the Node's literal value as an interger.
+// Ctype describes the constant kind of an "ideal" (untyped) constant.
+type Ctype int8
+
+const (
+	CTxxx Ctype = iota
+
+	CTINT
+	CTRUNE
+	CTFLT
+	CTCPLX
+	CTSTR
+	CTBOOL
+	CTNIL
+)
+
+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{}
+}
+
+func (v Val) Ctype() Ctype {
+	switch x := v.U.(type) {
+	default:
+		Fatalf("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 NilVal struct{}
+
+// IntLiteral returns the Node's literal value as an integer.
 func (n *Node) IntLiteral() (x int64, ok bool) {
 	switch {
 	case n == nil:
 		return
 	case Isconst(n, CTINT):
-		return n.Int(), true
+		return n.Int64(), true
 	case Isconst(n, CTBOOL):
 		return int64(obj.Bool2int(n.Bool())), true
 	}
 	return
 }
 
-// Int returns n as an int.
-// n must be an integer constant.
-func (n *Node) Int() int64 {
+// Int64 returns n as an int64.
+// n must be an integer or rune constant.
+func (n *Node) Int64() int64 {
 	if !Isconst(n, CTINT) {
 		Fatalf("Int(%v)", n)
 	}
-	return Mpgetfix(n.Val().U.(*Mpint))
+	return n.Val().U.(*Mpint).Int64()
 }
 
 // SetInt sets n's value to i.
@@ -38,7 +91,7 @@ func (n *Node) SetInt(i int64) {
 	if !Isconst(n, CTINT) {
 		Fatalf("SetInt(%v)", n)
 	}
-	Mpmovecfix(n.Val().U.(*Mpint), i)
+	n.Val().U.(*Mpint).SetInt64(i)
 }
 
 // SetBigInt sets n's value to x.
@@ -71,52 +124,71 @@ func truncfltlit(oldv *Mpflt, t *Type) *Mpflt {
 	overflow(v, t)
 
 	fv := newMpflt()
-	mpmovefltflt(fv, oldv)
+	fv.Set(oldv)
 
 	// convert large precision literal floating
 	// into limited precision (float64 or float32)
 	switch t.Etype {
 	case TFLOAT64:
-		d := mpgetflt(fv)
-		Mpmovecflt(fv, d)
+		d := fv.Float64()
+		fv.SetFloat64(d)
 
 	case TFLOAT32:
-		d := mpgetflt32(fv)
-		Mpmovecflt(fv, d)
+		d := fv.Float32()
+		fv.SetFloat64(d)
 	}
 
 	return fv
 }
 
+// NegOne returns a Node of type t with value -1.
+func NegOne(t *Type) *Node {
+	n := Nodintconst(-1)
+	n = convlit(n, t)
+	return n
+}
+
+// canReuseNode indicates whether it is known to be safe
+// to reuse a Node.
+type canReuseNode bool
+
+const (
+	noReuse canReuseNode = false // not necessarily safe to reuse
+	reuseOK canReuseNode = true  // safe to reuse
+)
+
 // convert n, if literal, to type t.
 // implicit conversion.
-func Convlit(np **Node, t *Type) {
-	convlit1(np, t, false)
+// The result of convlit MUST be assigned back to n, e.g.
+// 	n.Left = convlit(n.Left, t)
+func convlit(n *Node, t *Type) *Node {
+	return convlit1(n, t, false, noReuse)
 }
 
-// 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
+// convlit1 converts n, if literal, to type t.
+// It returns a new node if necessary.
+// The result of convlit1 MUST be assigned back to n, e.g.
+// 	n.Left = convlit1(n.Left, t, explicit, reuse)
+func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
+	if n == nil || t == nil || n.Type == nil || t.IsUntyped() || n.Type == t {
+		return n
 	}
-	if !explicit && !isideal(n.Type) {
-		return
+	if !explicit && !n.Type.IsUntyped() {
+		return n
 	}
 
-	if n.Op == OLITERAL {
-		nn := Nod(OXXX, nil, nil)
-		*nn = *n
-		n = nn
-		*np = n
+	if n.Op == OLITERAL && !reuse {
+		// Can't always set n.Type directly on OLITERAL nodes.
+		// See discussion on CL 20813.
+		nn := *n
+		n = &nn
+		reuse = true
 	}
 
 	switch n.Op {
 	default:
 		if n.Type == idealbool {
-			if t.Etype == TBOOL {
+			if t.IsBoolean() {
 				n.Type = t
 			} else {
 				n.Type = Types[TBOOL]
@@ -124,81 +196,74 @@ func convlit1(np **Node, t *Type, explicit bool) {
 		}
 
 		if n.Type.Etype == TIDEAL {
-			Convlit(&n.Left, t)
-			Convlit(&n.Right, t)
+			n.Left = convlit(n.Left, t)
+			n.Right = convlit(n.Right, t)
 			n.Type = t
 		}
 
-		return
+		return n
 
 		// 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
+			return defaultlitreuse(n, nil, reuse)
 		}
 
 	case OLSH, ORSH:
-		convlit1(&n.Left, t, explicit && isideal(n.Left.Type))
+		n.Left = convlit1(n.Left, t, explicit && n.Left.Type.IsUntyped(), noReuse)
 		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] {
+		if t != nil && !t.IsInteger() {
 			Yyerror("invalid operation: %v (shift of type %v)", n, t)
 			t = nil
 		}
 
 		n.Type = t
-		return
+		return n
 
 	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:
+				// If trying to convert to non-complex type,
+				// leave as complex128 and let typechecker complain.
 				t = Types[TCOMPLEX128]
 				fallthrough
-
-				//fallthrough
 			case TCOMPLEX128:
 				n.Type = t
-
-				Convlit(&n.Left, Types[TFLOAT64])
-				Convlit(&n.Right, Types[TFLOAT64])
+				n.Left = convlit(n.Left, Types[TFLOAT64])
+				n.Right = convlit(n.Right, Types[TFLOAT64])
 
 			case TCOMPLEX64:
 				n.Type = t
-				Convlit(&n.Left, Types[TFLOAT32])
-				Convlit(&n.Right, Types[TFLOAT32])
+				n.Left = convlit(n.Left, Types[TFLOAT32])
+				n.Right = convlit(n.Right, Types[TFLOAT32])
 			}
 		}
 
-		return
+		return n
 	}
 
 	// avoided repeated calculations, errors
 	if Eqtype(n.Type, t) {
-		return
+		return n
 	}
 
 	ct := consttype(n)
-	var et int
+	var et EType
 	if ct < 0 {
 		goto bad
 	}
 
-	et = int(t.Etype)
+	et = t.Etype
 	if et == TINTER {
 		if ct == CTNIL && n.Type == Types[TNIL] {
 			n.Type = t
-			return
+			return n
 		}
-
-		defaultlit(np, nil)
-		return
+		return defaultlitreuse(n, nil, reuse)
 	}
 
 	switch ct {
@@ -213,12 +278,10 @@ func convlit1(np **Node, t *Type, explicit bool) {
 
 			// let normal conversion code handle it
 		case TSTRING:
-			return
+			return n
 
 		case TARRAY:
-			if !Isslice(t) {
-				goto bad
-			}
+			goto bad
 
 		case TPTR32,
 			TPTR64,
@@ -226,6 +289,7 @@ func convlit1(np **Node, t *Type, explicit bool) {
 			TMAP,
 			TCHAN,
 			TFUNC,
+			TSLICE,
 			TUNSAFEPTR:
 			break
 
@@ -234,14 +298,14 @@ func convlit1(np **Node, t *Type, explicit bool) {
 		case TUINTPTR:
 			if n.Type.Etype == TUNSAFEPTR {
 				n.SetVal(Val{new(Mpint)})
-				Mpmovecfix(n.Val().U.(*Mpint), 0)
+				n.Val().U.(*Mpint).SetInt64(0)
 			} else {
 				goto bad
 			}
 		}
 
 	case CTSTR, CTBOOL:
-		if et != int(n.Type.Etype) {
+		if et != n.Type.Etype {
 			goto bad
 		}
 
@@ -294,7 +358,7 @@ func convlit1(np **Node, t *Type, explicit bool) {
 	}
 
 	n.Type = t
-	return
+	return n
 
 bad:
 	if n.Diag == 0 {
@@ -304,29 +368,29 @@ bad:
 		n.Diag = 1
 	}
 
-	if isideal(n.Type) {
-		defaultlit(&n, nil)
-		*np = n
+	if n.Type.IsUntyped() {
+		n = defaultlitreuse(n, nil, reuse)
 	}
+	return n
 }
 
 func copyval(v Val) Val {
-	switch v.Ctype() {
-	case CTINT, CTRUNE:
+	switch u := v.U.(type) {
+	case *Mpint:
 		i := new(Mpint)
-		mpmovefixfix(i, v.U.(*Mpint))
-		i.Rune = v.U.(*Mpint).Rune
+		i.Set(u)
+		i.Rune = u.Rune
 		v.U = i
 
-	case CTFLT:
+	case *Mpflt:
 		f := newMpflt()
-		mpmovefltflt(f, v.U.(*Mpflt))
+		f.Set(u)
 		v.U = f
 
-	case CTCPLX:
+	case *Mpcplx:
 		c := new(Mpcplx)
-		mpmovefltflt(&c.Real, &v.U.(*Mpcplx).Real)
-		mpmovefltflt(&c.Imag, &v.U.(*Mpcplx).Imag)
+		c.Real.Set(&u.Real)
+		c.Imag.Set(&u.Imag)
 		v.U = c
 	}
 
@@ -334,17 +398,17 @@ func copyval(v Val) Val {
 }
 
 func tocplx(v Val) Val {
-	switch v.Ctype() {
-	case CTINT, CTRUNE:
+	switch u := v.U.(type) {
+	case *Mpint:
 		c := new(Mpcplx)
-		Mpmovefixflt(&c.Real, v.U.(*Mpint))
-		Mpmovecflt(&c.Imag, 0.0)
+		c.Real.SetInt(u)
+		c.Imag.SetFloat64(0.0)
 		v.U = c
 
-	case CTFLT:
+	case *Mpflt:
 		c := new(Mpcplx)
-		mpmovefltflt(&c.Real, v.U.(*Mpflt))
-		Mpmovecflt(&c.Imag, 0.0)
+		c.Real.Set(u)
+		c.Imag.SetFloat64(0.0)
 		v.U = c
 	}
 
@@ -352,17 +416,17 @@ func tocplx(v Val) Val {
 }
 
 func toflt(v Val) Val {
-	switch v.Ctype() {
-	case CTINT, CTRUNE:
+	switch u := v.U.(type) {
+	case *Mpint:
 		f := newMpflt()
-		Mpmovefixflt(f, v.U.(*Mpint))
+		f.SetInt(u)
 		v.U = f
 
-	case CTCPLX:
+	case *Mpcplx:
 		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))
+		f.Set(&u.Real)
+		if u.Imag.CmpFloat64(0) != 0 {
+			Yyerror("constant %v%vi truncated to real", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|FmtSign))
 		}
 		v.U = f
 	}
@@ -371,31 +435,33 @@ func toflt(v Val) Val {
 }
 
 func toint(v Val) Val {
-	switch v.Ctype() {
-	case CTRUNE:
-		i := new(Mpint)
-		mpmovefixfix(i, v.U.(*Mpint))
-		v.U = i
+	switch u := v.U.(type) {
+	case *Mpint:
+		if u.Rune {
+			i := new(Mpint)
+			i.Set(u)
+			v.U = i
+		}
 
-	case CTFLT:
+	case *Mpflt:
 		i := new(Mpint)
-		if f := v.U.(*Mpflt); mpmovefltfix(i, f) < 0 {
+		if i.SetFloat(u) < 0 {
 			msg := "constant %v truncated to integer"
-			// provide better error message if mpmovefltfix failed because f was too large
-			if f.Val.IsInt() {
+			// provide better error message if SetFloat failed because f was too large
+			if u.Val.IsInt() {
 				msg = "constant %v overflows integer"
 			}
-			Yyerror(msg, Fconv(f, obj.FmtSharp))
+			Yyerror(msg, fconv(u, FmtSharp))
 		}
 		v.U = i
 
-	case CTCPLX:
+	case *Mpcplx:
 		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 i.SetFloat(&u.Real) < 0 {
+			Yyerror("constant %v%vi truncated to integer", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|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))
+		if u.Imag.CmpFloat64(0) != 0 {
+			Yyerror("constant %v%vi truncated to real", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|FmtSign))
 		}
 		v.U = i
 	}
@@ -404,30 +470,25 @@ func toint(v Val) Val {
 }
 
 func doesoverflow(v Val, t *Type) bool {
-	switch v.Ctype() {
-	case CTINT, CTRUNE:
-		if !Isint[t.Etype] {
+	switch u := v.U.(type) {
+	case *Mpint:
+		if !t.IsInteger() {
 			Fatalf("overflow: %v integer constant", t)
 		}
-		if Mpcmpfixfix(v.U.(*Mpint), Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[t.Etype]) > 0 {
-			return true
-		}
+		return u.Cmp(Minintval[t.Etype]) < 0 || u.Cmp(Maxintval[t.Etype]) > 0
 
-	case CTFLT:
-		if !Isfloat[t.Etype] {
+	case *Mpflt:
+		if !t.IsFloat() {
 			Fatalf("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
-		}
+		return u.Cmp(minfltval[t.Etype]) <= 0 || u.Cmp(maxfltval[t.Etype]) >= 0
 
-	case CTCPLX:
-		if !Iscomplex[t.Etype] {
+	case *Mpcplx:
+		if !t.IsComplex() {
 			Fatalf("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 u.Real.Cmp(minfltval[t.Etype]) <= 0 || u.Real.Cmp(maxfltval[t.Etype]) >= 0 ||
+			u.Imag.Cmp(minfltval[t.Etype]) <= 0 || u.Imag.Cmp(maxfltval[t.Etype]) >= 0
 	}
 
 	return false
@@ -446,26 +507,21 @@ func overflow(v Val, t *Type) {
 	}
 
 	if doesoverflow(v, t) {
-		Yyerror("constant %s overflows %v", Vconv(v, 0), t)
+		Yyerror("constant %s overflows %v", vconv(v, 0), 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")
+	switch u := v.U.(type) {
+	case *Mpint:
+		var i int64 = 0xFFFD
+		if u.Cmp(Minintval[TUINT32]) >= 0 && u.Cmp(Maxintval[TUINT32]) <= 0 {
+			i = u.Int64()
 		}
-		r := uint(Mpgetfix(v.U.(*Mpint)))
-		v = Val{}
-		v.U = string(r)
-
-	case CTFLT:
-		Yyerror("no float -> string")
-		fallthrough
+		v.U = string(i)
 
-	case CTNIL:
-		v = Val{}
+	case *NilVal:
+		// Can happen because of string([]byte(nil)).
 		v.U = ""
 	}
 
@@ -543,38 +599,30 @@ func evconst(n *Node) {
 
 		// 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
+		s := n.List.Slice()
+		for i1 := 0; i1 < len(s); i1++ {
+			if Isconst(s[i1], CTSTR) && i1+1 < len(s) && Isconst(s[i1+1], CTSTR) {
+				// merge from i1 up to but not including i2
 				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
+				i2 := i1
+				for i2 < len(s) && Isconst(s[i2], CTSTR) {
+					strs = append(strs, s[i2].Val().U.(string))
+					i2++
 				}
 
-				nl = Nod(OXXX, nil, nil)
-				*nl = *l1.N
-				nl.Orig = nl
+				nl := *s[i1]
+				nl.Orig = &nl
 				nl.SetVal(Val{strings.Join(strs, "")})
-				l1.N = nl
-				l1.Next = l2
+				s[i1] = &nl
+				s = append(s[:i1+1], s[i2:]...)
 			}
 		}
 
-		// 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) {
+		if len(s) == 1 && Isconst(s[0], CTSTR) {
 			n.Op = OLITERAL
-			n.SetVal(n.List.N.Val())
+			n.SetVal(s[0].Val())
+		} else {
+			n.List.Set(s)
 		}
 
 		return
@@ -587,7 +635,7 @@ func evconst(n *Node) {
 	if consttype(nl) < 0 {
 		return
 	}
-	wl := int(nl.Type.Etype)
+	wl := nl.Type.Etype
 	if Isint[wl] || Isfloat[wl] || Iscomplex[wl] {
 		wl = TIDEAL
 	}
@@ -630,8 +678,8 @@ func evconst(n *Node) {
 
 	nr := n.Right
 	var rv Val
-	var lno int
-	var wr int
+	var lno int32
+	var wr EType
 	var v Val
 	var norig *Node
 	var nn *Node
@@ -647,28 +695,25 @@ func evconst(n *Node) {
 		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)
+				Yyerror("illegal constant expression %v %v", n.Op, nl.Type)
 				n.Diag = 1
 			}
 			return
 
 		case OCONV_ | CTNIL_,
 			OARRAYBYTESTR_ | CTNIL_:
-			if n.Type.Etype == TSTRING {
+			if n.Type.IsString() {
 				v = tostr(v)
 				nl.Type = n.Type
 				break
 			}
 			fallthrough
-
-			// fall through
 		case OCONV_ | CTINT_,
 			OCONV_ | CTRUNE_,
 			OCONV_ | CTFLT_,
 			OCONV_ | CTSTR_,
 			OCONV_ | CTBOOL_:
-			convlit1(&nl, n.Type, true)
-
+			nl = convlit1(nl, n.Type, true, false)
 			v = nl.Val()
 
 		case OPLUS_ | CTINT_,
@@ -677,13 +722,13 @@ func evconst(n *Node) {
 
 		case OMINUS_ | CTINT_,
 			OMINUS_ | CTRUNE_:
-			mpnegfix(v.U.(*Mpint))
+			v.U.(*Mpint).Neg()
 
 		case OCOM_ | CTINT_,
 			OCOM_ | CTRUNE_:
-			et := Txxx
+			var et EType = Txxx
 			if nl.Type != nil {
-				et = int(nl.Type.Etype)
+				et = nl.Type.Etype
 			}
 
 			// calculate the mask in b
@@ -692,7 +737,7 @@ func evconst(n *Node) {
 			switch et {
 			// signed guys change sign
 			default:
-				Mpmovecfix(&b, -1)
+				b.SetInt64(-1)
 
 				// unsigned guys invert their bits
 			case TUINT8,
@@ -701,23 +746,23 @@ func evconst(n *Node) {
 				TUINT64,
 				TUINT,
 				TUINTPTR:
-				mpmovefixfix(&b, Maxintval[et])
+				b.Set(Maxintval[et])
 			}
 
-			mpxorfixfix(v.U.(*Mpint), &b)
+			v.U.(*Mpint).Xor(&b)
 
 		case OPLUS_ | CTFLT_:
 			break
 
 		case OMINUS_ | CTFLT_:
-			mpnegflt(v.U.(*Mpflt))
+			v.U.(*Mpflt).Neg()
 
 		case OPLUS_ | CTCPLX_:
 			break
 
 		case OMINUS_ | CTCPLX_:
-			mpnegflt(&v.U.(*Mpcplx).Real)
-			mpnegflt(&v.U.(*Mpcplx).Imag)
+			v.U.(*Mpcplx).Real.Neg()
+			v.U.(*Mpcplx).Imag.Neg()
 
 		case ONOT_ | CTBOOL_:
 			if !v.U.(bool) {
@@ -733,7 +778,7 @@ func evconst(n *Node) {
 	if consttype(nr) < 0 {
 		return
 	}
-	wr = int(nr.Type.Etype)
+	wr = nr.Type.Etype
 	if Isint[wr] || Isfloat[wr] || Iscomplex[wr] {
 		wr = TIDEAL
 	}
@@ -748,12 +793,12 @@ func evconst(n *Node) {
 	// ideal const mixes with anything but otherwise must match.
 	default:
 		if nl.Type.Etype != TIDEAL {
-			defaultlit(&nr, nl.Type)
+			nr = defaultlit(nr, nl.Type)
 			n.Right = nr
 		}
 
 		if nr.Type.Etype != TIDEAL {
-			defaultlit(&nl, nr.Type)
+			nl = defaultlit(nl, nr.Type)
 			n.Left = nl
 		}
 
@@ -764,10 +809,10 @@ func evconst(n *Node) {
 		// right must be unsigned.
 	// left can be ideal.
 	case OLSH, ORSH:
-		defaultlit(&nr, Types[TUINT])
+		nr = defaultlit(nr, Types[TUINT])
 
 		n.Right = nr
-		if nr.Type != nil && (Issigned[nr.Type.Etype] || !Isint[nr.Type.Etype]) {
+		if nr.Type != nil && (nr.Type.IsSigned() || !nr.Type.IsInteger()) {
 			goto illegal
 		}
 		if nl.Val().Ctype() != CTRUNE {
@@ -800,18 +845,18 @@ func evconst(n *Node) {
 	// Rune and int turns into rune.
 	if v.Ctype() == CTRUNE && rv.Ctype() == CTINT {
 		i := new(Mpint)
-		mpmovefixfix(i, rv.U.(*Mpint))
+		i.Set(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))
+			i.Set(rv.U.(*Mpint))
 			rv.U = i
 		} else {
 			i := new(Mpint)
-			mpmovefixfix(i, v.U.(*Mpint))
+			i.Set(v.U.(*Mpint))
 			i.Rune = true
 			v.U = i
 		}
@@ -832,77 +877,77 @@ func evconst(n *Node) {
 
 	case OADD_ | CTINT_,
 		OADD_ | CTRUNE_:
-		mpaddfixfix(v.U.(*Mpint), rv.U.(*Mpint), 0)
+		v.U.(*Mpint).Add(rv.U.(*Mpint))
 
 	case OSUB_ | CTINT_,
 		OSUB_ | CTRUNE_:
-		mpsubfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).Sub(rv.U.(*Mpint))
 
 	case OMUL_ | CTINT_,
 		OMUL_ | CTRUNE_:
-		mpmulfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).Mul(rv.U.(*Mpint))
 
 	case ODIV_ | CTINT_,
 		ODIV_ | CTRUNE_:
-		if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
+		if rv.U.(*Mpint).CmpInt64(0) == 0 {
 			Yyerror("division by zero")
-			mpsetovf(v.U.(*Mpint))
+			v.U.(*Mpint).SetOverflow()
 			break
 		}
 
-		mpdivfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).Quo(rv.U.(*Mpint))
 
 	case OMOD_ | CTINT_,
 		OMOD_ | CTRUNE_:
-		if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
+		if rv.U.(*Mpint).CmpInt64(0) == 0 {
 			Yyerror("division by zero")
-			mpsetovf(v.U.(*Mpint))
+			v.U.(*Mpint).SetOverflow()
 			break
 		}
 
-		mpmodfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).Rem(rv.U.(*Mpint))
 
 	case OLSH_ | CTINT_,
 		OLSH_ | CTRUNE_:
-		mplshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).Lsh(rv.U.(*Mpint))
 
 	case ORSH_ | CTINT_,
 		ORSH_ | CTRUNE_:
-		mprshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).Rsh(rv.U.(*Mpint))
 
 	case OOR_ | CTINT_,
 		OOR_ | CTRUNE_:
-		mporfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).Or(rv.U.(*Mpint))
 
 	case OAND_ | CTINT_,
 		OAND_ | CTRUNE_:
-		mpandfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).And(rv.U.(*Mpint))
 
 	case OANDNOT_ | CTINT_,
 		OANDNOT_ | CTRUNE_:
-		mpandnotfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).AndNot(rv.U.(*Mpint))
 
 	case OXOR_ | CTINT_,
 		OXOR_ | CTRUNE_:
-		mpxorfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+		v.U.(*Mpint).Xor(rv.U.(*Mpint))
 
 	case OADD_ | CTFLT_:
-		mpaddfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
+		v.U.(*Mpflt).Add(rv.U.(*Mpflt))
 
 	case OSUB_ | CTFLT_:
-		mpsubfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
+		v.U.(*Mpflt).Sub(rv.U.(*Mpflt))
 
 	case OMUL_ | CTFLT_:
-		mpmulfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
+		v.U.(*Mpflt).Mul(rv.U.(*Mpflt))
 
 	case ODIV_ | CTFLT_:
-		if mpcmpfltc(rv.U.(*Mpflt), 0) == 0 {
+		if rv.U.(*Mpflt).CmpFloat64(0) == 0 {
 			Yyerror("division by zero")
-			Mpmovecflt(v.U.(*Mpflt), 1.0)
+			v.U.(*Mpflt).SetFloat64(1.0)
 			break
 		}
 
-		mpdivfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
+		v.U.(*Mpflt).Quo(rv.U.(*Mpflt))
 
 		// The default case above would print 'ideal % ideal',
 	// which is not quite an ideal error.
@@ -915,21 +960,21 @@ func evconst(n *Node) {
 		return
 
 	case OADD_ | CTCPLX_:
-		mpaddfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
-		mpaddfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
+		v.U.(*Mpcplx).Real.Add(&rv.U.(*Mpcplx).Real)
+		v.U.(*Mpcplx).Imag.Add(&rv.U.(*Mpcplx).Imag)
 
 	case OSUB_ | CTCPLX_:
-		mpsubfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
-		mpsubfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
+		v.U.(*Mpcplx).Real.Sub(&rv.U.(*Mpcplx).Real)
+		v.U.(*Mpcplx).Imag.Sub(&rv.U.(*Mpcplx).Imag)
 
 	case OMUL_ | CTCPLX_:
 		cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx))
 
 	case ODIV_ | CTCPLX_:
-		if mpcmpfltc(&rv.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&rv.U.(*Mpcplx).Imag, 0) == 0 {
+		if rv.U.(*Mpcplx).Real.CmpFloat64(0) == 0 && rv.U.(*Mpcplx).Imag.CmpFloat64(0) == 0 {
 			Yyerror("complex division by zero")
-			Mpmovecflt(&rv.U.(*Mpcplx).Real, 1.0)
-			Mpmovecflt(&rv.U.(*Mpcplx).Imag, 0.0)
+			rv.U.(*Mpcplx).Real.SetFloat64(1.0)
+			rv.U.(*Mpcplx).Imag.SetFloat64(0.0)
 			break
 		}
 
@@ -943,90 +988,90 @@ func evconst(n *Node) {
 
 	case OEQ_ | CTINT_,
 		OEQ_ | CTRUNE_:
-		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) == 0 {
+		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) == 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case ONE_ | CTINT_,
 		ONE_ | CTRUNE_:
-		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) != 0 {
+		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) != 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OLT_ | CTINT_,
 		OLT_ | CTRUNE_:
-		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) < 0 {
+		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) < 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OLE_ | CTINT_,
 		OLE_ | CTRUNE_:
-		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) <= 0 {
+		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) <= 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OGE_ | CTINT_,
 		OGE_ | CTRUNE_:
-		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) >= 0 {
+		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) >= 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OGT_ | CTINT_,
 		OGT_ | CTRUNE_:
-		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) > 0 {
+		if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) > 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OEQ_ | CTFLT_:
-		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) == 0 {
+		if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) == 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case ONE_ | CTFLT_:
-		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) != 0 {
+		if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) != 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OLT_ | CTFLT_:
-		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) < 0 {
+		if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) < 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OLE_ | CTFLT_:
-		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) <= 0 {
+		if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) <= 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OGE_ | CTFLT_:
-		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) >= 0 {
+		if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) >= 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OGT_ | CTFLT_:
-		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) > 0 {
+		if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) > 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case OEQ_ | CTCPLX_:
-		if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) == 0 && mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) == 0 {
+		if v.U.(*Mpcplx).Real.Cmp(&rv.U.(*Mpcplx).Real) == 0 && v.U.(*Mpcplx).Imag.Cmp(&rv.U.(*Mpcplx).Imag) == 0 {
 			goto settrue
 		}
 		goto setfalse
 
 	case ONE_ | CTCPLX_:
-		if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) != 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) != 0 {
+		if v.U.(*Mpcplx).Real.Cmp(&rv.U.(*Mpcplx).Real) != 0 || v.U.(*Mpcplx).Imag.Cmp(&rv.U.(*Mpcplx).Imag) != 0 {
 			goto settrue
 		}
 		goto setfalse
@@ -1104,10 +1149,9 @@ ret:
 	n.SetVal(v)
 
 	// check range.
-	lno = int(setlineno(n))
-
+	lno = setlineno(n)
 	overflow(v, n.Type)
-	lineno = int32(lno)
+	lineno = lno
 
 	// truncate precision for non-ideal float.
 	if v.Ctype() == CTFLT && n.Type.Etype != TIDEAL {
@@ -1135,7 +1179,7 @@ setfalse:
 
 illegal:
 	if n.Diag == 0 {
-		Yyerror("illegal constant expression: %v %v %v", nl.Type, Oconv(int(n.Op), 0), nr.Type)
+		Yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type)
 		n.Diag = 1
 	}
 }
@@ -1176,15 +1220,15 @@ func nodcplxlit(r Val, i Val) *Node {
 		Fatalf("nodcplxlit ctype %d/%d", r.Ctype(), i.Ctype())
 	}
 
-	mpmovefltflt(&c.Real, r.U.(*Mpflt))
-	mpmovefltflt(&c.Imag, i.U.(*Mpflt))
+	c.Real.Set(r.U.(*Mpflt))
+	c.Imag.Set(i.U.(*Mpflt))
 	return n
 }
 
 // idealkind returns a constant kind like consttype
 // but for an arbitrary "ideal" (untyped constant) expression.
 func idealkind(n *Node) Ctype {
-	if n == nil || !isideal(n.Type) {
+	if n == nil || !n.Type.IsUntyped() {
 		return CTxxx
 	}
 
@@ -1245,31 +1289,36 @@ func idealkind(n *Node) Ctype {
 	}
 }
 
-func defaultlit(np **Node, t *Type) {
-	n := *np
-	if n == nil || !isideal(n.Type) {
-		return
+// The result of defaultlit MUST be assigned back to n, e.g.
+// 	n.Left = defaultlit(n.Left, t)
+func defaultlit(n *Node, t *Type) *Node {
+	return defaultlitreuse(n, t, noReuse)
+}
+
+// The result of defaultlitreuse MUST be assigned back to n, e.g.
+// 	n.Left = defaultlitreuse(n.Left, t, reuse)
+func defaultlitreuse(n *Node, t *Type, reuse canReuseNode) *Node {
+	if n == nil || !n.Type.IsUntyped() {
+		return n
 	}
 
-	if n.Op == OLITERAL {
-		nn := Nod(OXXX, nil, nil)
-		*nn = *n
-		n = nn
-		*np = n
+	if n.Op == OLITERAL && !reuse {
+		nn := *n
+		n = &nn
+		reuse = true
 	}
 
-	lno := int(setlineno(n))
+	lno := setlineno(n)
 	ctype := idealkind(n)
 	var t1 *Type
 	switch ctype {
 	default:
 		if t != nil {
-			Convlit(np, t)
-			return
+			return convlit(n, t)
 		}
 
 		if n.Val().Ctype() == CTNIL {
-			lineno = int32(lno)
+			lineno = lno
 			if n.Diag == 0 {
 				Yyerror("use of untyped nil")
 				n.Diag = 1
@@ -1281,21 +1330,21 @@ func defaultlit(np **Node, t *Type) {
 
 		if n.Val().Ctype() == CTSTR {
 			t1 := Types[TSTRING]
-			Convlit(np, t1)
+			n = convlit1(n, t1, false, reuse)
 			break
 		}
 
 		Yyerror("defaultlit: unknown literal: %v", n)
 
 	case CTxxx:
-		Fatalf("defaultlit: idealkind is CTxxx: %v", Nconv(n, obj.FmtSign))
+		Fatalf("defaultlit: idealkind is CTxxx: %v", Nconv(n, FmtSign))
 
 	case CTBOOL:
 		t1 := Types[TBOOL]
-		if t != nil && t.Etype == TBOOL {
+		if t != nil && t.IsBoolean() {
 			t1 = t
 		}
-		Convlit(np, t1)
+		n = convlit1(n, t1, false, reuse)
 
 	case CTINT:
 		t1 = Types[TINT]
@@ -1314,21 +1363,21 @@ func defaultlit(np **Node, t *Type) {
 		goto num
 	}
 
-	lineno = int32(lno)
-	return
+	lineno = lno
+	return n
 
 num:
 	// Note: n.Val().Ctype() can be CTxxx (not a constant) here
 	// in the case of an untyped non-constant value, like 1<<i.
 	v1 := n.Val()
 	if t != nil {
-		if Isint[t.Etype] {
+		if t.IsInteger() {
 			t1 = t
 			v1 = toint(n.Val())
-		} else if Isfloat[t.Etype] {
+		} else if t.IsFloat() {
 			t1 = t
 			v1 = toflt(n.Val())
-		} else if Iscomplex[t.Etype] {
+		} else if t.IsComplex() {
 			t1 = t
 			v1 = tocplx(n.Val())
 		}
@@ -1340,61 +1389,64 @@ num:
 	if n.Val().Ctype() != CTxxx {
 		overflow(n.Val(), t1)
 	}
-	Convlit(np, t1)
-	lineno = int32(lno)
-	return
+	n = convlit1(n, t1, false, reuse)
+	lineno = lno
+	return n
 }
 
 // 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
+// The results of defaultlit2 MUST be assigned back to l and r, e.g.
+// 	n.Left, n.Right = defaultlit2(n.Left, n.Right, force)
+func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
 	if l.Type == nil || r.Type == nil {
-		return
+		return l, r
 	}
-	if !isideal(l.Type) {
-		Convlit(rp, l.Type)
-		return
+	if !l.Type.IsUntyped() {
+		r = convlit(r, l.Type)
+		return l, r
 	}
 
-	if !isideal(r.Type) {
-		Convlit(lp, r.Type)
-		return
+	if !r.Type.IsUntyped() {
+		l = convlit(l, r.Type)
+		return l, r
 	}
 
-	if force == 0 {
-		return
+	if !force {
+		return l, r
 	}
-	if l.Type.Etype == TBOOL {
-		Convlit(lp, Types[TBOOL])
-		Convlit(rp, Types[TBOOL])
+
+	if l.Type.IsBoolean() {
+		l = convlit(l, Types[TBOOL])
+		r = convlit(r, Types[TBOOL])
 	}
 
 	lkind := idealkind(l)
 	rkind := idealkind(r)
 	if lkind == CTCPLX || rkind == CTCPLX {
-		Convlit(lp, Types[TCOMPLEX128])
-		Convlit(rp, Types[TCOMPLEX128])
-		return
+		l = convlit(l, Types[TCOMPLEX128])
+		r = convlit(r, Types[TCOMPLEX128])
+		return l, r
 	}
 
 	if lkind == CTFLT || rkind == CTFLT {
-		Convlit(lp, Types[TFLOAT64])
-		Convlit(rp, Types[TFLOAT64])
-		return
+		l = convlit(l, Types[TFLOAT64])
+		r = convlit(r, Types[TFLOAT64])
+		return l, r
 	}
 
 	if lkind == CTRUNE || rkind == CTRUNE {
-		Convlit(lp, runetype)
-		Convlit(rp, runetype)
-		return
+		l = convlit(l, runetype)
+		r = convlit(r, runetype)
+		return l, r
 	}
 
-	Convlit(lp, Types[TINT])
-	Convlit(rp, Types[TINT])
+	l = convlit(l, Types[TINT])
+	r = convlit(r, Types[TINT])
+
+	return l, r
 }
 
 // strlit returns the value of a literal string Node as a string.
@@ -1416,7 +1468,7 @@ func Smallintconst(n *Node) bool {
 			return true
 
 		case TIDEAL, TINT64, TUINT64, TPTR64:
-			if Mpcmpfixfix(n.Val().U.(*Mpint), Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT32]) > 0 {
+			if n.Val().U.(*Mpint).Cmp(Minintval[TINT32]) < 0 || n.Val().U.(*Mpint).Cmp(Maxintval[TINT32]) > 0 {
 				break
 			}
 			return true
@@ -1439,10 +1491,10 @@ func nonnegconst(n *Node) int {
 			TINT64,
 			TUINT64,
 			TIDEAL:
-			if Mpcmpfixfix(n.Val().U.(*Mpint), Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT32]) > 0 {
+			if n.Val().U.(*Mpint).Cmp(Minintval[TUINT32]) < 0 || n.Val().U.(*Mpint).Cmp(Maxintval[TINT32]) > 0 {
 				break
 			}
-			return int(Mpgetfix(n.Val().U.(*Mpint)))
+			return int(n.Int64())
 		}
 	}
 
@@ -1494,10 +1546,10 @@ func (n *Node) Convconst(con *Node, t *Type) {
 		var i int64
 		switch n.Val().Ctype() {
 		default:
-			Fatalf("convconst ctype=%d %v", n.Val().Ctype(), Tconv(t, obj.FmtLong))
+			Fatalf("convconst ctype=%d %v", n.Val().Ctype(), Tconv(t, FmtLong))
 
 		case CTINT, CTRUNE:
-			i = Mpgetfix(n.Val().U.(*Mpint))
+			i = n.Int64()
 
 		case CTBOOL:
 			i = int64(obj.Bool2int(n.Val().U.(bool)))
@@ -1507,7 +1559,7 @@ func (n *Node) Convconst(con *Node, t *Type) {
 		}
 
 		i = iconv(i, tt)
-		Mpmovecfix(con.Val().U.(*Mpint), i)
+		con.Val().U.(*Mpint).SetInt64(i)
 		return
 	}
 
@@ -1531,7 +1583,7 @@ func (n *Node) Convconst(con *Node, t *Type) {
 		return
 	}
 
-	Fatalf("convconst %v constant", Tconv(t, obj.FmtLong))
+	Fatalf("convconst %v constant", Tconv(t, FmtLong))
 }
 
 // complex multiply v *= rv
@@ -1542,28 +1594,28 @@ func cmplxmpy(v *Mpcplx, rv *Mpcplx) {
 	var bc Mpflt
 	var ad Mpflt
 
-	mpmovefltflt(&ac, &v.Real)
-	mpmulfltflt(&ac, &rv.Real) // ac
+	ac.Set(&v.Real)
+	ac.Mul(&rv.Real) // ac
 
-	mpmovefltflt(&bd, &v.Imag)
+	bd.Set(&v.Imag)
 
-	mpmulfltflt(&bd, &rv.Imag) // bd
+	bd.Mul(&rv.Imag) // bd
 
-	mpmovefltflt(&bc, &v.Imag)
+	bc.Set(&v.Imag)
 
-	mpmulfltflt(&bc, &rv.Real) // bc
+	bc.Mul(&rv.Real) // bc
 
-	mpmovefltflt(&ad, &v.Real)
+	ad.Set(&v.Real)
 
-	mpmulfltflt(&ad, &rv.Imag) // ad
+	ad.Mul(&rv.Imag) // ad
 
-	mpmovefltflt(&v.Real, &ac)
+	v.Real.Set(&ac)
 
-	mpsubfltflt(&v.Real, &bd) // ac-bd
+	v.Real.Sub(&bd) // ac-bd
 
-	mpmovefltflt(&v.Imag, &bc)
+	v.Imag.Set(&bc)
 
-	mpaddfltflt(&v.Imag, &ad) // bc+ad
+	v.Imag.Add(&ad) // bc+ad
 }
 
 // complex divide v /= rv
@@ -1575,40 +1627,40 @@ func cmplxdiv(v *Mpcplx, rv *Mpcplx) {
 	var ad Mpflt
 	var cc_plus_dd Mpflt
 
-	mpmovefltflt(&cc_plus_dd, &rv.Real)
-	mpmulfltflt(&cc_plus_dd, &rv.Real) // cc
+	cc_plus_dd.Set(&rv.Real)
+	cc_plus_dd.Mul(&rv.Real) // cc
 
-	mpmovefltflt(&ac, &rv.Imag)
+	ac.Set(&rv.Imag)
 
-	mpmulfltflt(&ac, &rv.Imag) // dd
+	ac.Mul(&rv.Imag) // dd
 
-	mpaddfltflt(&cc_plus_dd, &ac) // cc+dd
+	cc_plus_dd.Add(&ac) // cc+dd
 
-	mpmovefltflt(&ac, &v.Real)
+	ac.Set(&v.Real)
 
-	mpmulfltflt(&ac, &rv.Real) // ac
+	ac.Mul(&rv.Real) // ac
 
-	mpmovefltflt(&bd, &v.Imag)
+	bd.Set(&v.Imag)
 
-	mpmulfltflt(&bd, &rv.Imag) // bd
+	bd.Mul(&rv.Imag) // bd
 
-	mpmovefltflt(&bc, &v.Imag)
+	bc.Set(&v.Imag)
 
-	mpmulfltflt(&bc, &rv.Real) // bc
+	bc.Mul(&rv.Real) // bc
 
-	mpmovefltflt(&ad, &v.Real)
+	ad.Set(&v.Real)
 
-	mpmulfltflt(&ad, &rv.Imag) // ad
+	ad.Mul(&rv.Imag) // ad
 
-	mpmovefltflt(&v.Real, &ac)
+	v.Real.Set(&ac)
 
-	mpaddfltflt(&v.Real, &bd)         // ac+bd
-	mpdivfltflt(&v.Real, &cc_plus_dd) // (ac+bd)/(cc+dd)
+	v.Real.Add(&bd)         // ac+bd
+	v.Real.Quo(&cc_plus_dd) // (ac+bd)/(cc+dd)
 
-	mpmovefltflt(&v.Imag, &bc)
+	v.Imag.Set(&bc)
 
-	mpsubfltflt(&v.Imag, &ad)         // bc-ad
-	mpdivfltflt(&v.Imag, &cc_plus_dd) // (bc+ad)/(cc+dd)
+	v.Imag.Sub(&ad)         // bc-ad
+	v.Imag.Quo(&cc_plus_dd) // (bc+ad)/(cc+dd)
 }
 
 // Is n a Go language constant (as opposed to a compile-time constant)?
@@ -1670,10 +1722,10 @@ func isgoconst(n *Node) bool {
 		// function calls or channel receive operations.
 		t := l.Type
 
-		if t != nil && Isptr[t.Etype] {
-			t = t.Type
+		if t != nil && t.IsPtr() {
+			t = t.Elem()
 		}
-		if Isfixedarray(t) && !hascallchan(l) {
+		if t != nil && t.IsArray() && !hascallchan(l) {
 			return true
 		}
 
@@ -1743,14 +1795,13 @@ func hascallchan(n *Node) bool {
 	if hascallchan(n.Left) || hascallchan(n.Right) {
 		return true
 	}
-
-	for l := n.List; l != nil; l = l.Next {
-		if hascallchan(l.N) {
+	for _, n1 := range n.List.Slice() {
+		if hascallchan(n1) {
 			return true
 		}
 	}
-	for l := n.Rlist; l != nil; l = l.Next {
-		if hascallchan(l.N) {
+	for _, n2 := range n.Rlist.Slice() {
+		if hascallchan(n2) {
 			return true
 		}
 	}
diff --git a/src/cmd/compile/internal/gc/constFold_test.go b/src/cmd/compile/internal/gc/constFold_test.go
new file mode 100644
index 0000000..ef6a3c1
--- /dev/null
+++ b/src/cmd/compile/internal/gc/constFold_test.go
@@ -0,0 +1,18108 @@
+package gc
+
+import "testing"
+
+func TestConstFolduint64add(t *testing.T) {
+	var x, y, r uint64
+	x = 0
+	y = 0
+	r = x + y
+	if r != 0 {
+		t.Errorf("0 + 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x + y
+	if r != 1 {
+		t.Errorf("0 + 1 = %d, want 1", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != 4294967296 {
+		t.Errorf("0 + 4294967296 = %d, want 4294967296", r)
+	}
+	y = 18446744073709551615
+	r = x + y
+	if r != 18446744073709551615 {
+		t.Errorf("0 + 18446744073709551615 = %d, want 18446744073709551615", r)
+	}
+	x = 1
+	y = 0
+	r = x + y
+	if r != 1 {
+		t.Errorf("1 + 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 2 {
+		t.Errorf("1 + 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != 4294967297 {
+		t.Errorf("1 + 4294967296 = %d, want 4294967297", r)
+	}
+	y = 18446744073709551615
+	r = x + y
+	if r != 0 {
+		t.Errorf("1 + 18446744073709551615 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x + y
+	if r != 4294967296 {
+		t.Errorf("4294967296 + 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x + y
+	if r != 4294967297 {
+		t.Errorf("4294967296 + 1 = %d, want 4294967297", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != 8589934592 {
+		t.Errorf("4294967296 + 4294967296 = %d, want 8589934592", r)
+	}
+	y = 18446744073709551615
+	r = x + y
+	if r != 4294967295 {
+		t.Errorf("4294967296 + 18446744073709551615 = %d, want 4294967295", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x + y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 + 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x + y
+	if r != 0 {
+		t.Errorf("18446744073709551615 + 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != 4294967295 {
+		t.Errorf("18446744073709551615 + 4294967296 = %d, want 4294967295", r)
+	}
+	y = 18446744073709551615
+	r = x + y
+	if r != 18446744073709551614 {
+		t.Errorf("18446744073709551615 + 18446744073709551615 = %d, want 18446744073709551614", r)
+	}
+}
+func TestConstFolduint64sub(t *testing.T) {
+	var x, y, r uint64
+	x = 0
+	y = 0
+	r = x - y
+	if r != 0 {
+		t.Errorf("0 - 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x - y
+	if r != 18446744073709551615 {
+		t.Errorf("0 - 1 = %d, want 18446744073709551615", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != 18446744069414584320 {
+		t.Errorf("0 - 4294967296 = %d, want 18446744069414584320", r)
+	}
+	y = 18446744073709551615
+	r = x - y
+	if r != 1 {
+		t.Errorf("0 - 18446744073709551615 = %d, want 1", r)
+	}
+	x = 1
+	y = 0
+	r = x - y
+	if r != 1 {
+		t.Errorf("1 - 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x - y
+	if r != 0 {
+		t.Errorf("1 - 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != 18446744069414584321 {
+		t.Errorf("1 - 4294967296 = %d, want 18446744069414584321", r)
+	}
+	y = 18446744073709551615
+	r = x - y
+	if r != 2 {
+		t.Errorf("1 - 18446744073709551615 = %d, want 2", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x - y
+	if r != 4294967296 {
+		t.Errorf("4294967296 - 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x - y
+	if r != 4294967295 {
+		t.Errorf("4294967296 - 1 = %d, want 4294967295", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != 0 {
+		t.Errorf("4294967296 - 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x - y
+	if r != 4294967297 {
+		t.Errorf("4294967296 - 18446744073709551615 = %d, want 4294967297", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x - y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 - 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x - y
+	if r != 18446744073709551614 {
+		t.Errorf("18446744073709551615 - 1 = %d, want 18446744073709551614", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != 18446744069414584319 {
+		t.Errorf("18446744073709551615 - 4294967296 = %d, want 18446744069414584319", r)
+	}
+	y = 18446744073709551615
+	r = x - y
+	if r != 0 {
+		t.Errorf("18446744073709551615 - 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFolduint64div(t *testing.T) {
+	var x, y, r uint64
+	x = 0
+	y = 1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 1
+	r = x / y
+	if r != 1 {
+		t.Errorf("1 / 1 = %d, want 1", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 18446744073709551615 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 1
+	r = x / y
+	if r != 4294967296 {
+		t.Errorf("4294967296 / 1 = %d, want 4294967296", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 1 {
+		t.Errorf("4294967296 / 4294967296 = %d, want 1", r)
+	}
+	y = 18446744073709551615
+	r = x / y
+	if r != 0 {
+		t.Errorf("4294967296 / 18446744073709551615 = %d, want 0", r)
+	}
+	x = 18446744073709551615
+	y = 1
+	r = x / y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 / 1 = %d, want 18446744073709551615", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 4294967295 {
+		t.Errorf("18446744073709551615 / 4294967296 = %d, want 4294967295", r)
+	}
+	y = 18446744073709551615
+	r = x / y
+	if r != 1 {
+		t.Errorf("18446744073709551615 / 18446744073709551615 = %d, want 1", r)
+	}
+}
+func TestConstFolduint64mul(t *testing.T) {
+	var x, y, r uint64
+	x = 0
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 1 {
+		t.Errorf("1 * 1 = %d, want 1", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("1 * 4294967296 = %d, want 4294967296", r)
+	}
+	y = 18446744073709551615
+	r = x * y
+	if r != 18446744073709551615 {
+		t.Errorf("1 * 18446744073709551615 = %d, want 18446744073709551615", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("4294967296 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("4294967296 * 1 = %d, want 4294967296", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("4294967296 * 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x * y
+	if r != 18446744069414584320 {
+		t.Errorf("4294967296 * 18446744073709551615 = %d, want 18446744069414584320", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("18446744073709551615 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 * 1 = %d, want 18446744073709551615", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 18446744069414584320 {
+		t.Errorf("18446744073709551615 * 4294967296 = %d, want 18446744069414584320", r)
+	}
+	y = 18446744073709551615
+	r = x * y
+	if r != 1 {
+		t.Errorf("18446744073709551615 * 18446744073709551615 = %d, want 1", r)
+	}
+}
+func TestConstFolduint64mod(t *testing.T) {
+	var x, y, r uint64
+	x = 0
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 4294967296 = %d, want 1", r)
+	}
+	y = 18446744073709551615
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 18446744073709551615 = %d, want 1", r)
+	}
+	x = 4294967296
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("4294967296 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("4294967296 % 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x % y
+	if r != 4294967296 {
+		t.Errorf("4294967296 % 18446744073709551615 = %d, want 4294967296", r)
+	}
+	x = 18446744073709551615
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("18446744073709551615 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 4294967295 {
+		t.Errorf("18446744073709551615 % 4294967296 = %d, want 4294967295", r)
+	}
+	y = 18446744073709551615
+	r = x % y
+	if r != 0 {
+		t.Errorf("18446744073709551615 % 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64add(t *testing.T) {
+	var x, y, r int64
+	x = -9223372036854775808
+	y = -9223372036854775808
+	r = x + y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 + -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x + y
+	if r != 1 {
+		t.Errorf("-9223372036854775808 + -9223372036854775807 = %d, want 1", r)
+	}
+	y = -4294967296
+	r = x + y
+	if r != 9223372032559808512 {
+		t.Errorf("-9223372036854775808 + -4294967296 = %d, want 9223372032559808512", r)
+	}
+	y = -1
+	r = x + y
+	if r != 9223372036854775807 {
+		t.Errorf("-9223372036854775808 + -1 = %d, want 9223372036854775807", r)
+	}
+	y = 0
+	r = x + y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 + 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x + y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775808 + 1 = %d, want -9223372036854775807", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != -9223372032559808512 {
+		t.Errorf("-9223372036854775808 + 4294967296 = %d, want -9223372032559808512", r)
+	}
+	y = 9223372036854775806
+	r = x + y
+	if r != -2 {
+		t.Errorf("-9223372036854775808 + 9223372036854775806 = %d, want -2", r)
+	}
+	y = 9223372036854775807
+	r = x + y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 + 9223372036854775807 = %d, want -1", r)
+	}
+	x = -9223372036854775807
+	y = -9223372036854775808
+	r = x + y
+	if r != 1 {
+		t.Errorf("-9223372036854775807 + -9223372036854775808 = %d, want 1", r)
+	}
+	y = -9223372036854775807
+	r = x + y
+	if r != 2 {
+		t.Errorf("-9223372036854775807 + -9223372036854775807 = %d, want 2", r)
+	}
+	y = -4294967296
+	r = x + y
+	if r != 9223372032559808513 {
+		t.Errorf("-9223372036854775807 + -4294967296 = %d, want 9223372032559808513", r)
+	}
+	y = -1
+	r = x + y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775807 + -1 = %d, want -9223372036854775808", r)
+	}
+	y = 0
+	r = x + y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 + 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x + y
+	if r != -9223372036854775806 {
+		t.Errorf("-9223372036854775807 + 1 = %d, want -9223372036854775806", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != -9223372032559808511 {
+		t.Errorf("-9223372036854775807 + 4294967296 = %d, want -9223372032559808511", r)
+	}
+	y = 9223372036854775806
+	r = x + y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 + 9223372036854775806 = %d, want -1", r)
+	}
+	y = 9223372036854775807
+	r = x + y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 + 9223372036854775807 = %d, want 0", r)
+	}
+	x = -4294967296
+	y = -9223372036854775808
+	r = x + y
+	if r != 9223372032559808512 {
+		t.Errorf("-4294967296 + -9223372036854775808 = %d, want 9223372032559808512", r)
+	}
+	y = -9223372036854775807
+	r = x + y
+	if r != 9223372032559808513 {
+		t.Errorf("-4294967296 + -9223372036854775807 = %d, want 9223372032559808513", r)
+	}
+	y = -4294967296
+	r = x + y
+	if r != -8589934592 {
+		t.Errorf("-4294967296 + -4294967296 = %d, want -8589934592", r)
+	}
+	y = -1
+	r = x + y
+	if r != -4294967297 {
+		t.Errorf("-4294967296 + -1 = %d, want -4294967297", r)
+	}
+	y = 0
+	r = x + y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 + 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x + y
+	if r != -4294967295 {
+		t.Errorf("-4294967296 + 1 = %d, want -4294967295", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != 0 {
+		t.Errorf("-4294967296 + 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x + y
+	if r != 9223372032559808510 {
+		t.Errorf("-4294967296 + 9223372036854775806 = %d, want 9223372032559808510", r)
+	}
+	y = 9223372036854775807
+	r = x + y
+	if r != 9223372032559808511 {
+		t.Errorf("-4294967296 + 9223372036854775807 = %d, want 9223372032559808511", r)
+	}
+	x = -1
+	y = -9223372036854775808
+	r = x + y
+	if r != 9223372036854775807 {
+		t.Errorf("-1 + -9223372036854775808 = %d, want 9223372036854775807", r)
+	}
+	y = -9223372036854775807
+	r = x + y
+	if r != -9223372036854775808 {
+		t.Errorf("-1 + -9223372036854775807 = %d, want -9223372036854775808", r)
+	}
+	y = -4294967296
+	r = x + y
+	if r != -4294967297 {
+		t.Errorf("-1 + -4294967296 = %d, want -4294967297", r)
+	}
+	y = -1
+	r = x + y
+	if r != -2 {
+		t.Errorf("-1 + -1 = %d, want -2", r)
+	}
+	y = 0
+	r = x + y
+	if r != -1 {
+		t.Errorf("-1 + 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 0 {
+		t.Errorf("-1 + 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != 4294967295 {
+		t.Errorf("-1 + 4294967296 = %d, want 4294967295", r)
+	}
+	y = 9223372036854775806
+	r = x + y
+	if r != 9223372036854775805 {
+		t.Errorf("-1 + 9223372036854775806 = %d, want 9223372036854775805", r)
+	}
+	y = 9223372036854775807
+	r = x + y
+	if r != 9223372036854775806 {
+		t.Errorf("-1 + 9223372036854775807 = %d, want 9223372036854775806", r)
+	}
+	x = 0
+	y = -9223372036854775808
+	r = x + y
+	if r != -9223372036854775808 {
+		t.Errorf("0 + -9223372036854775808 = %d, want -9223372036854775808", r)
+	}
+	y = -9223372036854775807
+	r = x + y
+	if r != -9223372036854775807 {
+		t.Errorf("0 + -9223372036854775807 = %d, want -9223372036854775807", r)
+	}
+	y = -4294967296
+	r = x + y
+	if r != -4294967296 {
+		t.Errorf("0 + -4294967296 = %d, want -4294967296", r)
+	}
+	y = -1
+	r = x + y
+	if r != -1 {
+		t.Errorf("0 + -1 = %d, want -1", r)
+	}
+	y = 0
+	r = x + y
+	if r != 0 {
+		t.Errorf("0 + 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x + y
+	if r != 1 {
+		t.Errorf("0 + 1 = %d, want 1", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != 4294967296 {
+		t.Errorf("0 + 4294967296 = %d, want 4294967296", r)
+	}
+	y = 9223372036854775806
+	r = x + y
+	if r != 9223372036854775806 {
+		t.Errorf("0 + 9223372036854775806 = %d, want 9223372036854775806", r)
+	}
+	y = 9223372036854775807
+	r = x + y
+	if r != 9223372036854775807 {
+		t.Errorf("0 + 9223372036854775807 = %d, want 9223372036854775807", r)
+	}
+	x = 1
+	y = -9223372036854775808
+	r = x + y
+	if r != -9223372036854775807 {
+		t.Errorf("1 + -9223372036854775808 = %d, want -9223372036854775807", r)
+	}
+	y = -9223372036854775807
+	r = x + y
+	if r != -9223372036854775806 {
+		t.Errorf("1 + -9223372036854775807 = %d, want -9223372036854775806", r)
+	}
+	y = -4294967296
+	r = x + y
+	if r != -4294967295 {
+		t.Errorf("1 + -4294967296 = %d, want -4294967295", r)
+	}
+	y = -1
+	r = x + y
+	if r != 0 {
+		t.Errorf("1 + -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x + y
+	if r != 1 {
+		t.Errorf("1 + 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 2 {
+		t.Errorf("1 + 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != 4294967297 {
+		t.Errorf("1 + 4294967296 = %d, want 4294967297", r)
+	}
+	y = 9223372036854775806
+	r = x + y
+	if r != 9223372036854775807 {
+		t.Errorf("1 + 9223372036854775806 = %d, want 9223372036854775807", r)
+	}
+	y = 9223372036854775807
+	r = x + y
+	if r != -9223372036854775808 {
+		t.Errorf("1 + 9223372036854775807 = %d, want -9223372036854775808", r)
+	}
+	x = 4294967296
+	y = -9223372036854775808
+	r = x + y
+	if r != -9223372032559808512 {
+		t.Errorf("4294967296 + -9223372036854775808 = %d, want -9223372032559808512", r)
+	}
+	y = -9223372036854775807
+	r = x + y
+	if r != -9223372032559808511 {
+		t.Errorf("4294967296 + -9223372036854775807 = %d, want -9223372032559808511", r)
+	}
+	y = -4294967296
+	r = x + y
+	if r != 0 {
+		t.Errorf("4294967296 + -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x + y
+	if r != 4294967295 {
+		t.Errorf("4294967296 + -1 = %d, want 4294967295", r)
+	}
+	y = 0
+	r = x + y
+	if r != 4294967296 {
+		t.Errorf("4294967296 + 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x + y
+	if r != 4294967297 {
+		t.Errorf("4294967296 + 1 = %d, want 4294967297", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != 8589934592 {
+		t.Errorf("4294967296 + 4294967296 = %d, want 8589934592", r)
+	}
+	y = 9223372036854775806
+	r = x + y
+	if r != -9223372032559808514 {
+		t.Errorf("4294967296 + 9223372036854775806 = %d, want -9223372032559808514", r)
+	}
+	y = 9223372036854775807
+	r = x + y
+	if r != -9223372032559808513 {
+		t.Errorf("4294967296 + 9223372036854775807 = %d, want -9223372032559808513", r)
+	}
+	x = 9223372036854775806
+	y = -9223372036854775808
+	r = x + y
+	if r != -2 {
+		t.Errorf("9223372036854775806 + -9223372036854775808 = %d, want -2", r)
+	}
+	y = -9223372036854775807
+	r = x + y
+	if r != -1 {
+		t.Errorf("9223372036854775806 + -9223372036854775807 = %d, want -1", r)
+	}
+	y = -4294967296
+	r = x + y
+	if r != 9223372032559808510 {
+		t.Errorf("9223372036854775806 + -4294967296 = %d, want 9223372032559808510", r)
+	}
+	y = -1
+	r = x + y
+	if r != 9223372036854775805 {
+		t.Errorf("9223372036854775806 + -1 = %d, want 9223372036854775805", r)
+	}
+	y = 0
+	r = x + y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 + 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x + y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775806 + 1 = %d, want 9223372036854775807", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != -9223372032559808514 {
+		t.Errorf("9223372036854775806 + 4294967296 = %d, want -9223372032559808514", r)
+	}
+	y = 9223372036854775806
+	r = x + y
+	if r != -4 {
+		t.Errorf("9223372036854775806 + 9223372036854775806 = %d, want -4", r)
+	}
+	y = 9223372036854775807
+	r = x + y
+	if r != -3 {
+		t.Errorf("9223372036854775806 + 9223372036854775807 = %d, want -3", r)
+	}
+	x = 9223372036854775807
+	y = -9223372036854775808
+	r = x + y
+	if r != -1 {
+		t.Errorf("9223372036854775807 + -9223372036854775808 = %d, want -1", r)
+	}
+	y = -9223372036854775807
+	r = x + y
+	if r != 0 {
+		t.Errorf("9223372036854775807 + -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x + y
+	if r != 9223372032559808511 {
+		t.Errorf("9223372036854775807 + -4294967296 = %d, want 9223372032559808511", r)
+	}
+	y = -1
+	r = x + y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775807 + -1 = %d, want 9223372036854775806", r)
+	}
+	y = 0
+	r = x + y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 + 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x + y
+	if r != -9223372036854775808 {
+		t.Errorf("9223372036854775807 + 1 = %d, want -9223372036854775808", r)
+	}
+	y = 4294967296
+	r = x + y
+	if r != -9223372032559808513 {
+		t.Errorf("9223372036854775807 + 4294967296 = %d, want -9223372032559808513", r)
+	}
+	y = 9223372036854775806
+	r = x + y
+	if r != -3 {
+		t.Errorf("9223372036854775807 + 9223372036854775806 = %d, want -3", r)
+	}
+	y = 9223372036854775807
+	r = x + y
+	if r != -2 {
+		t.Errorf("9223372036854775807 + 9223372036854775807 = %d, want -2", r)
+	}
+}
+func TestConstFoldint64sub(t *testing.T) {
+	var x, y, r int64
+	x = -9223372036854775808
+	y = -9223372036854775808
+	r = x - y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 - -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x - y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 - -9223372036854775807 = %d, want -1", r)
+	}
+	y = -4294967296
+	r = x - y
+	if r != -9223372032559808512 {
+		t.Errorf("-9223372036854775808 - -4294967296 = %d, want -9223372032559808512", r)
+	}
+	y = -1
+	r = x - y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775808 - -1 = %d, want -9223372036854775807", r)
+	}
+	y = 0
+	r = x - y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 - 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x - y
+	if r != 9223372036854775807 {
+		t.Errorf("-9223372036854775808 - 1 = %d, want 9223372036854775807", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != 9223372032559808512 {
+		t.Errorf("-9223372036854775808 - 4294967296 = %d, want 9223372032559808512", r)
+	}
+	y = 9223372036854775806
+	r = x - y
+	if r != 2 {
+		t.Errorf("-9223372036854775808 - 9223372036854775806 = %d, want 2", r)
+	}
+	y = 9223372036854775807
+	r = x - y
+	if r != 1 {
+		t.Errorf("-9223372036854775808 - 9223372036854775807 = %d, want 1", r)
+	}
+	x = -9223372036854775807
+	y = -9223372036854775808
+	r = x - y
+	if r != 1 {
+		t.Errorf("-9223372036854775807 - -9223372036854775808 = %d, want 1", r)
+	}
+	y = -9223372036854775807
+	r = x - y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 - -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x - y
+	if r != -9223372032559808511 {
+		t.Errorf("-9223372036854775807 - -4294967296 = %d, want -9223372032559808511", r)
+	}
+	y = -1
+	r = x - y
+	if r != -9223372036854775806 {
+		t.Errorf("-9223372036854775807 - -1 = %d, want -9223372036854775806", r)
+	}
+	y = 0
+	r = x - y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 - 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x - y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775807 - 1 = %d, want -9223372036854775808", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != 9223372032559808513 {
+		t.Errorf("-9223372036854775807 - 4294967296 = %d, want 9223372032559808513", r)
+	}
+	y = 9223372036854775806
+	r = x - y
+	if r != 3 {
+		t.Errorf("-9223372036854775807 - 9223372036854775806 = %d, want 3", r)
+	}
+	y = 9223372036854775807
+	r = x - y
+	if r != 2 {
+		t.Errorf("-9223372036854775807 - 9223372036854775807 = %d, want 2", r)
+	}
+	x = -4294967296
+	y = -9223372036854775808
+	r = x - y
+	if r != 9223372032559808512 {
+		t.Errorf("-4294967296 - -9223372036854775808 = %d, want 9223372032559808512", r)
+	}
+	y = -9223372036854775807
+	r = x - y
+	if r != 9223372032559808511 {
+		t.Errorf("-4294967296 - -9223372036854775807 = %d, want 9223372032559808511", r)
+	}
+	y = -4294967296
+	r = x - y
+	if r != 0 {
+		t.Errorf("-4294967296 - -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x - y
+	if r != -4294967295 {
+		t.Errorf("-4294967296 - -1 = %d, want -4294967295", r)
+	}
+	y = 0
+	r = x - y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 - 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x - y
+	if r != -4294967297 {
+		t.Errorf("-4294967296 - 1 = %d, want -4294967297", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != -8589934592 {
+		t.Errorf("-4294967296 - 4294967296 = %d, want -8589934592", r)
+	}
+	y = 9223372036854775806
+	r = x - y
+	if r != 9223372032559808514 {
+		t.Errorf("-4294967296 - 9223372036854775806 = %d, want 9223372032559808514", r)
+	}
+	y = 9223372036854775807
+	r = x - y
+	if r != 9223372032559808513 {
+		t.Errorf("-4294967296 - 9223372036854775807 = %d, want 9223372032559808513", r)
+	}
+	x = -1
+	y = -9223372036854775808
+	r = x - y
+	if r != 9223372036854775807 {
+		t.Errorf("-1 - -9223372036854775808 = %d, want 9223372036854775807", r)
+	}
+	y = -9223372036854775807
+	r = x - y
+	if r != 9223372036854775806 {
+		t.Errorf("-1 - -9223372036854775807 = %d, want 9223372036854775806", r)
+	}
+	y = -4294967296
+	r = x - y
+	if r != 4294967295 {
+		t.Errorf("-1 - -4294967296 = %d, want 4294967295", r)
+	}
+	y = -1
+	r = x - y
+	if r != 0 {
+		t.Errorf("-1 - -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x - y
+	if r != -1 {
+		t.Errorf("-1 - 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x - y
+	if r != -2 {
+		t.Errorf("-1 - 1 = %d, want -2", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != -4294967297 {
+		t.Errorf("-1 - 4294967296 = %d, want -4294967297", r)
+	}
+	y = 9223372036854775806
+	r = x - y
+	if r != -9223372036854775807 {
+		t.Errorf("-1 - 9223372036854775806 = %d, want -9223372036854775807", r)
+	}
+	y = 9223372036854775807
+	r = x - y
+	if r != -9223372036854775808 {
+		t.Errorf("-1 - 9223372036854775807 = %d, want -9223372036854775808", r)
+	}
+	x = 0
+	y = -9223372036854775808
+	r = x - y
+	if r != -9223372036854775808 {
+		t.Errorf("0 - -9223372036854775808 = %d, want -9223372036854775808", r)
+	}
+	y = -9223372036854775807
+	r = x - y
+	if r != 9223372036854775807 {
+		t.Errorf("0 - -9223372036854775807 = %d, want 9223372036854775807", r)
+	}
+	y = -4294967296
+	r = x - y
+	if r != 4294967296 {
+		t.Errorf("0 - -4294967296 = %d, want 4294967296", r)
+	}
+	y = -1
+	r = x - y
+	if r != 1 {
+		t.Errorf("0 - -1 = %d, want 1", r)
+	}
+	y = 0
+	r = x - y
+	if r != 0 {
+		t.Errorf("0 - 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x - y
+	if r != -1 {
+		t.Errorf("0 - 1 = %d, want -1", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != -4294967296 {
+		t.Errorf("0 - 4294967296 = %d, want -4294967296", r)
+	}
+	y = 9223372036854775806
+	r = x - y
+	if r != -9223372036854775806 {
+		t.Errorf("0 - 9223372036854775806 = %d, want -9223372036854775806", r)
+	}
+	y = 9223372036854775807
+	r = x - y
+	if r != -9223372036854775807 {
+		t.Errorf("0 - 9223372036854775807 = %d, want -9223372036854775807", r)
+	}
+	x = 1
+	y = -9223372036854775808
+	r = x - y
+	if r != -9223372036854775807 {
+		t.Errorf("1 - -9223372036854775808 = %d, want -9223372036854775807", r)
+	}
+	y = -9223372036854775807
+	r = x - y
+	if r != -9223372036854775808 {
+		t.Errorf("1 - -9223372036854775807 = %d, want -9223372036854775808", r)
+	}
+	y = -4294967296
+	r = x - y
+	if r != 4294967297 {
+		t.Errorf("1 - -4294967296 = %d, want 4294967297", r)
+	}
+	y = -1
+	r = x - y
+	if r != 2 {
+		t.Errorf("1 - -1 = %d, want 2", r)
+	}
+	y = 0
+	r = x - y
+	if r != 1 {
+		t.Errorf("1 - 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x - y
+	if r != 0 {
+		t.Errorf("1 - 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != -4294967295 {
+		t.Errorf("1 - 4294967296 = %d, want -4294967295", r)
+	}
+	y = 9223372036854775806
+	r = x - y
+	if r != -9223372036854775805 {
+		t.Errorf("1 - 9223372036854775806 = %d, want -9223372036854775805", r)
+	}
+	y = 9223372036854775807
+	r = x - y
+	if r != -9223372036854775806 {
+		t.Errorf("1 - 9223372036854775807 = %d, want -9223372036854775806", r)
+	}
+	x = 4294967296
+	y = -9223372036854775808
+	r = x - y
+	if r != -9223372032559808512 {
+		t.Errorf("4294967296 - -9223372036854775808 = %d, want -9223372032559808512", r)
+	}
+	y = -9223372036854775807
+	r = x - y
+	if r != -9223372032559808513 {
+		t.Errorf("4294967296 - -9223372036854775807 = %d, want -9223372032559808513", r)
+	}
+	y = -4294967296
+	r = x - y
+	if r != 8589934592 {
+		t.Errorf("4294967296 - -4294967296 = %d, want 8589934592", r)
+	}
+	y = -1
+	r = x - y
+	if r != 4294967297 {
+		t.Errorf("4294967296 - -1 = %d, want 4294967297", r)
+	}
+	y = 0
+	r = x - y
+	if r != 4294967296 {
+		t.Errorf("4294967296 - 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x - y
+	if r != 4294967295 {
+		t.Errorf("4294967296 - 1 = %d, want 4294967295", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != 0 {
+		t.Errorf("4294967296 - 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x - y
+	if r != -9223372032559808510 {
+		t.Errorf("4294967296 - 9223372036854775806 = %d, want -9223372032559808510", r)
+	}
+	y = 9223372036854775807
+	r = x - y
+	if r != -9223372032559808511 {
+		t.Errorf("4294967296 - 9223372036854775807 = %d, want -9223372032559808511", r)
+	}
+	x = 9223372036854775806
+	y = -9223372036854775808
+	r = x - y
+	if r != -2 {
+		t.Errorf("9223372036854775806 - -9223372036854775808 = %d, want -2", r)
+	}
+	y = -9223372036854775807
+	r = x - y
+	if r != -3 {
+		t.Errorf("9223372036854775806 - -9223372036854775807 = %d, want -3", r)
+	}
+	y = -4294967296
+	r = x - y
+	if r != -9223372032559808514 {
+		t.Errorf("9223372036854775806 - -4294967296 = %d, want -9223372032559808514", r)
+	}
+	y = -1
+	r = x - y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775806 - -1 = %d, want 9223372036854775807", r)
+	}
+	y = 0
+	r = x - y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 - 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x - y
+	if r != 9223372036854775805 {
+		t.Errorf("9223372036854775806 - 1 = %d, want 9223372036854775805", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != 9223372032559808510 {
+		t.Errorf("9223372036854775806 - 4294967296 = %d, want 9223372032559808510", r)
+	}
+	y = 9223372036854775806
+	r = x - y
+	if r != 0 {
+		t.Errorf("9223372036854775806 - 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x - y
+	if r != -1 {
+		t.Errorf("9223372036854775806 - 9223372036854775807 = %d, want -1", r)
+	}
+	x = 9223372036854775807
+	y = -9223372036854775808
+	r = x - y
+	if r != -1 {
+		t.Errorf("9223372036854775807 - -9223372036854775808 = %d, want -1", r)
+	}
+	y = -9223372036854775807
+	r = x - y
+	if r != -2 {
+		t.Errorf("9223372036854775807 - -9223372036854775807 = %d, want -2", r)
+	}
+	y = -4294967296
+	r = x - y
+	if r != -9223372032559808513 {
+		t.Errorf("9223372036854775807 - -4294967296 = %d, want -9223372032559808513", r)
+	}
+	y = -1
+	r = x - y
+	if r != -9223372036854775808 {
+		t.Errorf("9223372036854775807 - -1 = %d, want -9223372036854775808", r)
+	}
+	y = 0
+	r = x - y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 - 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x - y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775807 - 1 = %d, want 9223372036854775806", r)
+	}
+	y = 4294967296
+	r = x - y
+	if r != 9223372032559808511 {
+		t.Errorf("9223372036854775807 - 4294967296 = %d, want 9223372032559808511", r)
+	}
+	y = 9223372036854775806
+	r = x - y
+	if r != 1 {
+		t.Errorf("9223372036854775807 - 9223372036854775806 = %d, want 1", r)
+	}
+	y = 9223372036854775807
+	r = x - y
+	if r != 0 {
+		t.Errorf("9223372036854775807 - 9223372036854775807 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64div(t *testing.T) {
+	var x, y, r int64
+	x = -9223372036854775808
+	y = -9223372036854775808
+	r = x / y
+	if r != 1 {
+		t.Errorf("-9223372036854775808 / -9223372036854775808 = %d, want 1", r)
+	}
+	y = -9223372036854775807
+	r = x / y
+	if r != 1 {
+		t.Errorf("-9223372036854775808 / -9223372036854775807 = %d, want 1", r)
+	}
+	y = -4294967296
+	r = x / y
+	if r != 2147483648 {
+		t.Errorf("-9223372036854775808 / -4294967296 = %d, want 2147483648", r)
+	}
+	y = -1
+	r = x / y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 / -1 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x / y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 / 1 = %d, want -9223372036854775808", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != -2147483648 {
+		t.Errorf("-9223372036854775808 / 4294967296 = %d, want -2147483648", r)
+	}
+	y = 9223372036854775806
+	r = x / y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 / 9223372036854775806 = %d, want -1", r)
+	}
+	y = 9223372036854775807
+	r = x / y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 / 9223372036854775807 = %d, want -1", r)
+	}
+	x = -9223372036854775807
+	y = -9223372036854775808
+	r = x / y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 / -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x / y
+	if r != 1 {
+		t.Errorf("-9223372036854775807 / -9223372036854775807 = %d, want 1", r)
+	}
+	y = -4294967296
+	r = x / y
+	if r != 2147483647 {
+		t.Errorf("-9223372036854775807 / -4294967296 = %d, want 2147483647", r)
+	}
+	y = -1
+	r = x / y
+	if r != 9223372036854775807 {
+		t.Errorf("-9223372036854775807 / -1 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x / y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 / 1 = %d, want -9223372036854775807", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != -2147483647 {
+		t.Errorf("-9223372036854775807 / 4294967296 = %d, want -2147483647", r)
+	}
+	y = 9223372036854775806
+	r = x / y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 / 9223372036854775806 = %d, want -1", r)
+	}
+	y = 9223372036854775807
+	r = x / y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 / 9223372036854775807 = %d, want -1", r)
+	}
+	x = -4294967296
+	y = -9223372036854775808
+	r = x / y
+	if r != 0 {
+		t.Errorf("-4294967296 / -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("-4294967296 / -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x / y
+	if r != 1 {
+		t.Errorf("-4294967296 / -4294967296 = %d, want 1", r)
+	}
+	y = -1
+	r = x / y
+	if r != 4294967296 {
+		t.Errorf("-4294967296 / -1 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x / y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 / 1 = %d, want -4294967296", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != -1 {
+		t.Errorf("-4294967296 / 4294967296 = %d, want -1", r)
+	}
+	y = 9223372036854775806
+	r = x / y
+	if r != 0 {
+		t.Errorf("-4294967296 / 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("-4294967296 / 9223372036854775807 = %d, want 0", r)
+	}
+	x = -1
+	y = -9223372036854775808
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != 1 {
+		t.Errorf("-1 / -1 = %d, want 1", r)
+	}
+	y = 1
+	r = x / y
+	if r != -1 {
+		t.Errorf("-1 / 1 = %d, want -1", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / 9223372036854775807 = %d, want 0", r)
+	}
+	x = 0
+	y = -9223372036854775808
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 9223372036854775807 = %d, want 0", r)
+	}
+	x = 1
+	y = -9223372036854775808
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != -1 {
+		t.Errorf("1 / -1 = %d, want -1", r)
+	}
+	y = 1
+	r = x / y
+	if r != 1 {
+		t.Errorf("1 / 1 = %d, want 1", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 9223372036854775807 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = -9223372036854775808
+	r = x / y
+	if r != 0 {
+		t.Errorf("4294967296 / -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("4294967296 / -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x / y
+	if r != -1 {
+		t.Errorf("4294967296 / -4294967296 = %d, want -1", r)
+	}
+	y = -1
+	r = x / y
+	if r != -4294967296 {
+		t.Errorf("4294967296 / -1 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x / y
+	if r != 4294967296 {
+		t.Errorf("4294967296 / 1 = %d, want 4294967296", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 1 {
+		t.Errorf("4294967296 / 4294967296 = %d, want 1", r)
+	}
+	y = 9223372036854775806
+	r = x / y
+	if r != 0 {
+		t.Errorf("4294967296 / 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("4294967296 / 9223372036854775807 = %d, want 0", r)
+	}
+	x = 9223372036854775806
+	y = -9223372036854775808
+	r = x / y
+	if r != 0 {
+		t.Errorf("9223372036854775806 / -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("9223372036854775806 / -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x / y
+	if r != -2147483647 {
+		t.Errorf("9223372036854775806 / -4294967296 = %d, want -2147483647", r)
+	}
+	y = -1
+	r = x / y
+	if r != -9223372036854775806 {
+		t.Errorf("9223372036854775806 / -1 = %d, want -9223372036854775806", r)
+	}
+	y = 1
+	r = x / y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 / 1 = %d, want 9223372036854775806", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 2147483647 {
+		t.Errorf("9223372036854775806 / 4294967296 = %d, want 2147483647", r)
+	}
+	y = 9223372036854775806
+	r = x / y
+	if r != 1 {
+		t.Errorf("9223372036854775806 / 9223372036854775806 = %d, want 1", r)
+	}
+	y = 9223372036854775807
+	r = x / y
+	if r != 0 {
+		t.Errorf("9223372036854775806 / 9223372036854775807 = %d, want 0", r)
+	}
+	x = 9223372036854775807
+	y = -9223372036854775808
+	r = x / y
+	if r != 0 {
+		t.Errorf("9223372036854775807 / -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x / y
+	if r != -1 {
+		t.Errorf("9223372036854775807 / -9223372036854775807 = %d, want -1", r)
+	}
+	y = -4294967296
+	r = x / y
+	if r != -2147483647 {
+		t.Errorf("9223372036854775807 / -4294967296 = %d, want -2147483647", r)
+	}
+	y = -1
+	r = x / y
+	if r != -9223372036854775807 {
+		t.Errorf("9223372036854775807 / -1 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x / y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 / 1 = %d, want 9223372036854775807", r)
+	}
+	y = 4294967296
+	r = x / y
+	if r != 2147483647 {
+		t.Errorf("9223372036854775807 / 4294967296 = %d, want 2147483647", r)
+	}
+	y = 9223372036854775806
+	r = x / y
+	if r != 1 {
+		t.Errorf("9223372036854775807 / 9223372036854775806 = %d, want 1", r)
+	}
+	y = 9223372036854775807
+	r = x / y
+	if r != 1 {
+		t.Errorf("9223372036854775807 / 9223372036854775807 = %d, want 1", r)
+	}
+}
+func TestConstFoldint64mul(t *testing.T) {
+	var x, y, r int64
+	x = -9223372036854775808
+	y = -9223372036854775808
+	r = x * y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 * -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x * y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 * -9223372036854775807 = %d, want -9223372036854775808", r)
+	}
+	y = -4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 * -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x * y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 * -1 = %d, want -9223372036854775808", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 * 1 = %d, want -9223372036854775808", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 * 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x * y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 * 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x * y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 * 9223372036854775807 = %d, want -9223372036854775808", r)
+	}
+	x = -9223372036854775807
+	y = -9223372036854775808
+	r = x * y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775807 * -9223372036854775808 = %d, want -9223372036854775808", r)
+	}
+	y = -9223372036854775807
+	r = x * y
+	if r != 1 {
+		t.Errorf("-9223372036854775807 * -9223372036854775807 = %d, want 1", r)
+	}
+	y = -4294967296
+	r = x * y
+	if r != -4294967296 {
+		t.Errorf("-9223372036854775807 * -4294967296 = %d, want -4294967296", r)
+	}
+	y = -1
+	r = x * y
+	if r != 9223372036854775807 {
+		t.Errorf("-9223372036854775807 * -1 = %d, want 9223372036854775807", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 * 1 = %d, want -9223372036854775807", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("-9223372036854775807 * 4294967296 = %d, want 4294967296", r)
+	}
+	y = 9223372036854775806
+	r = x * y
+	if r != 9223372036854775806 {
+		t.Errorf("-9223372036854775807 * 9223372036854775806 = %d, want 9223372036854775806", r)
+	}
+	y = 9223372036854775807
+	r = x * y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 * 9223372036854775807 = %d, want -1", r)
+	}
+	x = -4294967296
+	y = -9223372036854775808
+	r = x * y
+	if r != 0 {
+		t.Errorf("-4294967296 * -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x * y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 * -9223372036854775807 = %d, want -4294967296", r)
+	}
+	y = -4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("-4294967296 * -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("-4294967296 * -1 = %d, want 4294967296", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-4294967296 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 * 1 = %d, want -4294967296", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("-4294967296 * 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x * y
+	if r != 8589934592 {
+		t.Errorf("-4294967296 * 9223372036854775806 = %d, want 8589934592", r)
+	}
+	y = 9223372036854775807
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("-4294967296 * 9223372036854775807 = %d, want 4294967296", r)
+	}
+	x = -1
+	y = -9223372036854775808
+	r = x * y
+	if r != -9223372036854775808 {
+		t.Errorf("-1 * -9223372036854775808 = %d, want -9223372036854775808", r)
+	}
+	y = -9223372036854775807
+	r = x * y
+	if r != 9223372036854775807 {
+		t.Errorf("-1 * -9223372036854775807 = %d, want 9223372036854775807", r)
+	}
+	y = -4294967296
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("-1 * -4294967296 = %d, want 4294967296", r)
+	}
+	y = -1
+	r = x * y
+	if r != 1 {
+		t.Errorf("-1 * -1 = %d, want 1", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -1 {
+		t.Errorf("-1 * 1 = %d, want -1", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != -4294967296 {
+		t.Errorf("-1 * 4294967296 = %d, want -4294967296", r)
+	}
+	y = 9223372036854775806
+	r = x * y
+	if r != -9223372036854775806 {
+		t.Errorf("-1 * 9223372036854775806 = %d, want -9223372036854775806", r)
+	}
+	y = 9223372036854775807
+	r = x * y
+	if r != -9223372036854775807 {
+		t.Errorf("-1 * 9223372036854775807 = %d, want -9223372036854775807", r)
+	}
+	x = 0
+	y = -9223372036854775808
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 9223372036854775807 = %d, want 0", r)
+	}
+	x = 1
+	y = -9223372036854775808
+	r = x * y
+	if r != -9223372036854775808 {
+		t.Errorf("1 * -9223372036854775808 = %d, want -9223372036854775808", r)
+	}
+	y = -9223372036854775807
+	r = x * y
+	if r != -9223372036854775807 {
+		t.Errorf("1 * -9223372036854775807 = %d, want -9223372036854775807", r)
+	}
+	y = -4294967296
+	r = x * y
+	if r != -4294967296 {
+		t.Errorf("1 * -4294967296 = %d, want -4294967296", r)
+	}
+	y = -1
+	r = x * y
+	if r != -1 {
+		t.Errorf("1 * -1 = %d, want -1", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 1 {
+		t.Errorf("1 * 1 = %d, want 1", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("1 * 4294967296 = %d, want 4294967296", r)
+	}
+	y = 9223372036854775806
+	r = x * y
+	if r != 9223372036854775806 {
+		t.Errorf("1 * 9223372036854775806 = %d, want 9223372036854775806", r)
+	}
+	y = 9223372036854775807
+	r = x * y
+	if r != 9223372036854775807 {
+		t.Errorf("1 * 9223372036854775807 = %d, want 9223372036854775807", r)
+	}
+	x = 4294967296
+	y = -9223372036854775808
+	r = x * y
+	if r != 0 {
+		t.Errorf("4294967296 * -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("4294967296 * -9223372036854775807 = %d, want 4294967296", r)
+	}
+	y = -4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("4294967296 * -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x * y
+	if r != -4294967296 {
+		t.Errorf("4294967296 * -1 = %d, want -4294967296", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("4294967296 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("4294967296 * 1 = %d, want 4294967296", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != 0 {
+		t.Errorf("4294967296 * 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x * y
+	if r != -8589934592 {
+		t.Errorf("4294967296 * 9223372036854775806 = %d, want -8589934592", r)
+	}
+	y = 9223372036854775807
+	r = x * y
+	if r != -4294967296 {
+		t.Errorf("4294967296 * 9223372036854775807 = %d, want -4294967296", r)
+	}
+	x = 9223372036854775806
+	y = -9223372036854775808
+	r = x * y
+	if r != 0 {
+		t.Errorf("9223372036854775806 * -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x * y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 * -9223372036854775807 = %d, want 9223372036854775806", r)
+	}
+	y = -4294967296
+	r = x * y
+	if r != 8589934592 {
+		t.Errorf("9223372036854775806 * -4294967296 = %d, want 8589934592", r)
+	}
+	y = -1
+	r = x * y
+	if r != -9223372036854775806 {
+		t.Errorf("9223372036854775806 * -1 = %d, want -9223372036854775806", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("9223372036854775806 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 * 1 = %d, want 9223372036854775806", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != -8589934592 {
+		t.Errorf("9223372036854775806 * 4294967296 = %d, want -8589934592", r)
+	}
+	y = 9223372036854775806
+	r = x * y
+	if r != 4 {
+		t.Errorf("9223372036854775806 * 9223372036854775806 = %d, want 4", r)
+	}
+	y = 9223372036854775807
+	r = x * y
+	if r != -9223372036854775806 {
+		t.Errorf("9223372036854775806 * 9223372036854775807 = %d, want -9223372036854775806", r)
+	}
+	x = 9223372036854775807
+	y = -9223372036854775808
+	r = x * y
+	if r != -9223372036854775808 {
+		t.Errorf("9223372036854775807 * -9223372036854775808 = %d, want -9223372036854775808", r)
+	}
+	y = -9223372036854775807
+	r = x * y
+	if r != -1 {
+		t.Errorf("9223372036854775807 * -9223372036854775807 = %d, want -1", r)
+	}
+	y = -4294967296
+	r = x * y
+	if r != 4294967296 {
+		t.Errorf("9223372036854775807 * -4294967296 = %d, want 4294967296", r)
+	}
+	y = -1
+	r = x * y
+	if r != -9223372036854775807 {
+		t.Errorf("9223372036854775807 * -1 = %d, want -9223372036854775807", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("9223372036854775807 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 * 1 = %d, want 9223372036854775807", r)
+	}
+	y = 4294967296
+	r = x * y
+	if r != -4294967296 {
+		t.Errorf("9223372036854775807 * 4294967296 = %d, want -4294967296", r)
+	}
+	y = 9223372036854775806
+	r = x * y
+	if r != -9223372036854775806 {
+		t.Errorf("9223372036854775807 * 9223372036854775806 = %d, want -9223372036854775806", r)
+	}
+	y = 9223372036854775807
+	r = x * y
+	if r != 1 {
+		t.Errorf("9223372036854775807 * 9223372036854775807 = %d, want 1", r)
+	}
+}
+func TestConstFoldint64mod(t *testing.T) {
+	var x, y, r int64
+	x = -9223372036854775808
+	y = -9223372036854775808
+	r = x % y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 % -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x % y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 % -9223372036854775807 = %d, want -1", r)
+	}
+	y = -4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 % -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 % 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x % y
+	if r != -2 {
+		t.Errorf("-9223372036854775808 % 9223372036854775806 = %d, want -2", r)
+	}
+	y = 9223372036854775807
+	r = x % y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 % 9223372036854775807 = %d, want -1", r)
+	}
+	x = -9223372036854775807
+	y = -9223372036854775808
+	r = x % y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 % -9223372036854775808 = %d, want -9223372036854775807", r)
+	}
+	y = -9223372036854775807
+	r = x % y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 % -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x % y
+	if r != -4294967295 {
+		t.Errorf("-9223372036854775807 % -4294967296 = %d, want -4294967295", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != -4294967295 {
+		t.Errorf("-9223372036854775807 % 4294967296 = %d, want -4294967295", r)
+	}
+	y = 9223372036854775806
+	r = x % y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 % 9223372036854775806 = %d, want -1", r)
+	}
+	y = 9223372036854775807
+	r = x % y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 % 9223372036854775807 = %d, want 0", r)
+	}
+	x = -4294967296
+	y = -9223372036854775808
+	r = x % y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 % -9223372036854775808 = %d, want -4294967296", r)
+	}
+	y = -9223372036854775807
+	r = x % y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 % -9223372036854775807 = %d, want -4294967296", r)
+	}
+	y = -4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("-4294967296 % -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-4294967296 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-4294967296 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("-4294967296 % 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x % y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 % 9223372036854775806 = %d, want -4294967296", r)
+	}
+	y = 9223372036854775807
+	r = x % y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 % 9223372036854775807 = %d, want -4294967296", r)
+	}
+	x = -1
+	y = -9223372036854775808
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % -9223372036854775808 = %d, want -1", r)
+	}
+	y = -9223372036854775807
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % -9223372036854775807 = %d, want -1", r)
+	}
+	y = -4294967296
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % -4294967296 = %d, want -1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-1 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-1 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % 4294967296 = %d, want -1", r)
+	}
+	y = 9223372036854775806
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % 9223372036854775806 = %d, want -1", r)
+	}
+	y = 9223372036854775807
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % 9223372036854775807 = %d, want -1", r)
+	}
+	x = 0
+	y = -9223372036854775808
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -9223372036854775808 = %d, want 0", r)
+	}
+	y = -9223372036854775807
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 9223372036854775807 = %d, want 0", r)
+	}
+	x = 1
+	y = -9223372036854775808
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % -9223372036854775808 = %d, want 1", r)
+	}
+	y = -9223372036854775807
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % -9223372036854775807 = %d, want 1", r)
+	}
+	y = -4294967296
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % -4294967296 = %d, want 1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 4294967296 = %d, want 1", r)
+	}
+	y = 9223372036854775806
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 9223372036854775806 = %d, want 1", r)
+	}
+	y = 9223372036854775807
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 9223372036854775807 = %d, want 1", r)
+	}
+	x = 4294967296
+	y = -9223372036854775808
+	r = x % y
+	if r != 4294967296 {
+		t.Errorf("4294967296 % -9223372036854775808 = %d, want 4294967296", r)
+	}
+	y = -9223372036854775807
+	r = x % y
+	if r != 4294967296 {
+		t.Errorf("4294967296 % -9223372036854775807 = %d, want 4294967296", r)
+	}
+	y = -4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("4294967296 % -4294967296 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("4294967296 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("4294967296 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 0 {
+		t.Errorf("4294967296 % 4294967296 = %d, want 0", r)
+	}
+	y = 9223372036854775806
+	r = x % y
+	if r != 4294967296 {
+		t.Errorf("4294967296 % 9223372036854775806 = %d, want 4294967296", r)
+	}
+	y = 9223372036854775807
+	r = x % y
+	if r != 4294967296 {
+		t.Errorf("4294967296 % 9223372036854775807 = %d, want 4294967296", r)
+	}
+	x = 9223372036854775806
+	y = -9223372036854775808
+	r = x % y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 % -9223372036854775808 = %d, want 9223372036854775806", r)
+	}
+	y = -9223372036854775807
+	r = x % y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 % -9223372036854775807 = %d, want 9223372036854775806", r)
+	}
+	y = -4294967296
+	r = x % y
+	if r != 4294967294 {
+		t.Errorf("9223372036854775806 % -4294967296 = %d, want 4294967294", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("9223372036854775806 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("9223372036854775806 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 4294967294 {
+		t.Errorf("9223372036854775806 % 4294967296 = %d, want 4294967294", r)
+	}
+	y = 9223372036854775806
+	r = x % y
+	if r != 0 {
+		t.Errorf("9223372036854775806 % 9223372036854775806 = %d, want 0", r)
+	}
+	y = 9223372036854775807
+	r = x % y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 % 9223372036854775807 = %d, want 9223372036854775806", r)
+	}
+	x = 9223372036854775807
+	y = -9223372036854775808
+	r = x % y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 % -9223372036854775808 = %d, want 9223372036854775807", r)
+	}
+	y = -9223372036854775807
+	r = x % y
+	if r != 0 {
+		t.Errorf("9223372036854775807 % -9223372036854775807 = %d, want 0", r)
+	}
+	y = -4294967296
+	r = x % y
+	if r != 4294967295 {
+		t.Errorf("9223372036854775807 % -4294967296 = %d, want 4294967295", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("9223372036854775807 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("9223372036854775807 % 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x % y
+	if r != 4294967295 {
+		t.Errorf("9223372036854775807 % 4294967296 = %d, want 4294967295", r)
+	}
+	y = 9223372036854775806
+	r = x % y
+	if r != 1 {
+		t.Errorf("9223372036854775807 % 9223372036854775806 = %d, want 1", r)
+	}
+	y = 9223372036854775807
+	r = x % y
+	if r != 0 {
+		t.Errorf("9223372036854775807 % 9223372036854775807 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32add(t *testing.T) {
+	var x, y, r uint32
+	x = 0
+	y = 0
+	r = x + y
+	if r != 0 {
+		t.Errorf("0 + 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x + y
+	if r != 1 {
+		t.Errorf("0 + 1 = %d, want 1", r)
+	}
+	y = 4294967295
+	r = x + y
+	if r != 4294967295 {
+		t.Errorf("0 + 4294967295 = %d, want 4294967295", r)
+	}
+	x = 1
+	y = 0
+	r = x + y
+	if r != 1 {
+		t.Errorf("1 + 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 2 {
+		t.Errorf("1 + 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x + y
+	if r != 0 {
+		t.Errorf("1 + 4294967295 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x + y
+	if r != 4294967295 {
+		t.Errorf("4294967295 + 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x + y
+	if r != 0 {
+		t.Errorf("4294967295 + 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x + y
+	if r != 4294967294 {
+		t.Errorf("4294967295 + 4294967295 = %d, want 4294967294", r)
+	}
+}
+func TestConstFolduint32sub(t *testing.T) {
+	var x, y, r uint32
+	x = 0
+	y = 0
+	r = x - y
+	if r != 0 {
+		t.Errorf("0 - 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x - y
+	if r != 4294967295 {
+		t.Errorf("0 - 1 = %d, want 4294967295", r)
+	}
+	y = 4294967295
+	r = x - y
+	if r != 1 {
+		t.Errorf("0 - 4294967295 = %d, want 1", r)
+	}
+	x = 1
+	y = 0
+	r = x - y
+	if r != 1 {
+		t.Errorf("1 - 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x - y
+	if r != 0 {
+		t.Errorf("1 - 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x - y
+	if r != 2 {
+		t.Errorf("1 - 4294967295 = %d, want 2", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x - y
+	if r != 4294967295 {
+		t.Errorf("4294967295 - 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x - y
+	if r != 4294967294 {
+		t.Errorf("4294967295 - 1 = %d, want 4294967294", r)
+	}
+	y = 4294967295
+	r = x - y
+	if r != 0 {
+		t.Errorf("4294967295 - 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32div(t *testing.T) {
+	var x, y, r uint32
+	x = 0
+	y = 1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 1
+	r = x / y
+	if r != 1 {
+		t.Errorf("1 / 1 = %d, want 1", r)
+	}
+	y = 4294967295
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 4294967295 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 1
+	r = x / y
+	if r != 4294967295 {
+		t.Errorf("4294967295 / 1 = %d, want 4294967295", r)
+	}
+	y = 4294967295
+	r = x / y
+	if r != 1 {
+		t.Errorf("4294967295 / 4294967295 = %d, want 1", r)
+	}
+}
+func TestConstFolduint32mul(t *testing.T) {
+	var x, y, r uint32
+	x = 0
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 1 {
+		t.Errorf("1 * 1 = %d, want 1", r)
+	}
+	y = 4294967295
+	r = x * y
+	if r != 4294967295 {
+		t.Errorf("1 * 4294967295 = %d, want 4294967295", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("4294967295 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 4294967295 {
+		t.Errorf("4294967295 * 1 = %d, want 4294967295", r)
+	}
+	y = 4294967295
+	r = x * y
+	if r != 1 {
+		t.Errorf("4294967295 * 4294967295 = %d, want 1", r)
+	}
+}
+func TestConstFolduint32mod(t *testing.T) {
+	var x, y, r uint32
+	x = 0
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 4294967295 = %d, want 1", r)
+	}
+	x = 4294967295
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("4294967295 % 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x % y
+	if r != 0 {
+		t.Errorf("4294967295 % 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32add(t *testing.T) {
+	var x, y, r int32
+	x = -2147483648
+	y = -2147483648
+	r = x + y
+	if r != 0 {
+		t.Errorf("-2147483648 + -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x + y
+	if r != 1 {
+		t.Errorf("-2147483648 + -2147483647 = %d, want 1", r)
+	}
+	y = -1
+	r = x + y
+	if r != 2147483647 {
+		t.Errorf("-2147483648 + -1 = %d, want 2147483647", r)
+	}
+	y = 0
+	r = x + y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 + 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x + y
+	if r != -2147483647 {
+		t.Errorf("-2147483648 + 1 = %d, want -2147483647", r)
+	}
+	y = 2147483647
+	r = x + y
+	if r != -1 {
+		t.Errorf("-2147483648 + 2147483647 = %d, want -1", r)
+	}
+	x = -2147483647
+	y = -2147483648
+	r = x + y
+	if r != 1 {
+		t.Errorf("-2147483647 + -2147483648 = %d, want 1", r)
+	}
+	y = -2147483647
+	r = x + y
+	if r != 2 {
+		t.Errorf("-2147483647 + -2147483647 = %d, want 2", r)
+	}
+	y = -1
+	r = x + y
+	if r != -2147483648 {
+		t.Errorf("-2147483647 + -1 = %d, want -2147483648", r)
+	}
+	y = 0
+	r = x + y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 + 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x + y
+	if r != -2147483646 {
+		t.Errorf("-2147483647 + 1 = %d, want -2147483646", r)
+	}
+	y = 2147483647
+	r = x + y
+	if r != 0 {
+		t.Errorf("-2147483647 + 2147483647 = %d, want 0", r)
+	}
+	x = -1
+	y = -2147483648
+	r = x + y
+	if r != 2147483647 {
+		t.Errorf("-1 + -2147483648 = %d, want 2147483647", r)
+	}
+	y = -2147483647
+	r = x + y
+	if r != -2147483648 {
+		t.Errorf("-1 + -2147483647 = %d, want -2147483648", r)
+	}
+	y = -1
+	r = x + y
+	if r != -2 {
+		t.Errorf("-1 + -1 = %d, want -2", r)
+	}
+	y = 0
+	r = x + y
+	if r != -1 {
+		t.Errorf("-1 + 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 0 {
+		t.Errorf("-1 + 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x + y
+	if r != 2147483646 {
+		t.Errorf("-1 + 2147483647 = %d, want 2147483646", r)
+	}
+	x = 0
+	y = -2147483648
+	r = x + y
+	if r != -2147483648 {
+		t.Errorf("0 + -2147483648 = %d, want -2147483648", r)
+	}
+	y = -2147483647
+	r = x + y
+	if r != -2147483647 {
+		t.Errorf("0 + -2147483647 = %d, want -2147483647", r)
+	}
+	y = -1
+	r = x + y
+	if r != -1 {
+		t.Errorf("0 + -1 = %d, want -1", r)
+	}
+	y = 0
+	r = x + y
+	if r != 0 {
+		t.Errorf("0 + 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x + y
+	if r != 1 {
+		t.Errorf("0 + 1 = %d, want 1", r)
+	}
+	y = 2147483647
+	r = x + y
+	if r != 2147483647 {
+		t.Errorf("0 + 2147483647 = %d, want 2147483647", r)
+	}
+	x = 1
+	y = -2147483648
+	r = x + y
+	if r != -2147483647 {
+		t.Errorf("1 + -2147483648 = %d, want -2147483647", r)
+	}
+	y = -2147483647
+	r = x + y
+	if r != -2147483646 {
+		t.Errorf("1 + -2147483647 = %d, want -2147483646", r)
+	}
+	y = -1
+	r = x + y
+	if r != 0 {
+		t.Errorf("1 + -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x + y
+	if r != 1 {
+		t.Errorf("1 + 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 2 {
+		t.Errorf("1 + 1 = %d, want 2", r)
+	}
+	y = 2147483647
+	r = x + y
+	if r != -2147483648 {
+		t.Errorf("1 + 2147483647 = %d, want -2147483648", r)
+	}
+	x = 2147483647
+	y = -2147483648
+	r = x + y
+	if r != -1 {
+		t.Errorf("2147483647 + -2147483648 = %d, want -1", r)
+	}
+	y = -2147483647
+	r = x + y
+	if r != 0 {
+		t.Errorf("2147483647 + -2147483647 = %d, want 0", r)
+	}
+	y = -1
+	r = x + y
+	if r != 2147483646 {
+		t.Errorf("2147483647 + -1 = %d, want 2147483646", r)
+	}
+	y = 0
+	r = x + y
+	if r != 2147483647 {
+		t.Errorf("2147483647 + 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x + y
+	if r != -2147483648 {
+		t.Errorf("2147483647 + 1 = %d, want -2147483648", r)
+	}
+	y = 2147483647
+	r = x + y
+	if r != -2 {
+		t.Errorf("2147483647 + 2147483647 = %d, want -2", r)
+	}
+}
+func TestConstFoldint32sub(t *testing.T) {
+	var x, y, r int32
+	x = -2147483648
+	y = -2147483648
+	r = x - y
+	if r != 0 {
+		t.Errorf("-2147483648 - -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x - y
+	if r != -1 {
+		t.Errorf("-2147483648 - -2147483647 = %d, want -1", r)
+	}
+	y = -1
+	r = x - y
+	if r != -2147483647 {
+		t.Errorf("-2147483648 - -1 = %d, want -2147483647", r)
+	}
+	y = 0
+	r = x - y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 - 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x - y
+	if r != 2147483647 {
+		t.Errorf("-2147483648 - 1 = %d, want 2147483647", r)
+	}
+	y = 2147483647
+	r = x - y
+	if r != 1 {
+		t.Errorf("-2147483648 - 2147483647 = %d, want 1", r)
+	}
+	x = -2147483647
+	y = -2147483648
+	r = x - y
+	if r != 1 {
+		t.Errorf("-2147483647 - -2147483648 = %d, want 1", r)
+	}
+	y = -2147483647
+	r = x - y
+	if r != 0 {
+		t.Errorf("-2147483647 - -2147483647 = %d, want 0", r)
+	}
+	y = -1
+	r = x - y
+	if r != -2147483646 {
+		t.Errorf("-2147483647 - -1 = %d, want -2147483646", r)
+	}
+	y = 0
+	r = x - y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 - 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x - y
+	if r != -2147483648 {
+		t.Errorf("-2147483647 - 1 = %d, want -2147483648", r)
+	}
+	y = 2147483647
+	r = x - y
+	if r != 2 {
+		t.Errorf("-2147483647 - 2147483647 = %d, want 2", r)
+	}
+	x = -1
+	y = -2147483648
+	r = x - y
+	if r != 2147483647 {
+		t.Errorf("-1 - -2147483648 = %d, want 2147483647", r)
+	}
+	y = -2147483647
+	r = x - y
+	if r != 2147483646 {
+		t.Errorf("-1 - -2147483647 = %d, want 2147483646", r)
+	}
+	y = -1
+	r = x - y
+	if r != 0 {
+		t.Errorf("-1 - -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x - y
+	if r != -1 {
+		t.Errorf("-1 - 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x - y
+	if r != -2 {
+		t.Errorf("-1 - 1 = %d, want -2", r)
+	}
+	y = 2147483647
+	r = x - y
+	if r != -2147483648 {
+		t.Errorf("-1 - 2147483647 = %d, want -2147483648", r)
+	}
+	x = 0
+	y = -2147483648
+	r = x - y
+	if r != -2147483648 {
+		t.Errorf("0 - -2147483648 = %d, want -2147483648", r)
+	}
+	y = -2147483647
+	r = x - y
+	if r != 2147483647 {
+		t.Errorf("0 - -2147483647 = %d, want 2147483647", r)
+	}
+	y = -1
+	r = x - y
+	if r != 1 {
+		t.Errorf("0 - -1 = %d, want 1", r)
+	}
+	y = 0
+	r = x - y
+	if r != 0 {
+		t.Errorf("0 - 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x - y
+	if r != -1 {
+		t.Errorf("0 - 1 = %d, want -1", r)
+	}
+	y = 2147483647
+	r = x - y
+	if r != -2147483647 {
+		t.Errorf("0 - 2147483647 = %d, want -2147483647", r)
+	}
+	x = 1
+	y = -2147483648
+	r = x - y
+	if r != -2147483647 {
+		t.Errorf("1 - -2147483648 = %d, want -2147483647", r)
+	}
+	y = -2147483647
+	r = x - y
+	if r != -2147483648 {
+		t.Errorf("1 - -2147483647 = %d, want -2147483648", r)
+	}
+	y = -1
+	r = x - y
+	if r != 2 {
+		t.Errorf("1 - -1 = %d, want 2", r)
+	}
+	y = 0
+	r = x - y
+	if r != 1 {
+		t.Errorf("1 - 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x - y
+	if r != 0 {
+		t.Errorf("1 - 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x - y
+	if r != -2147483646 {
+		t.Errorf("1 - 2147483647 = %d, want -2147483646", r)
+	}
+	x = 2147483647
+	y = -2147483648
+	r = x - y
+	if r != -1 {
+		t.Errorf("2147483647 - -2147483648 = %d, want -1", r)
+	}
+	y = -2147483647
+	r = x - y
+	if r != -2 {
+		t.Errorf("2147483647 - -2147483647 = %d, want -2", r)
+	}
+	y = -1
+	r = x - y
+	if r != -2147483648 {
+		t.Errorf("2147483647 - -1 = %d, want -2147483648", r)
+	}
+	y = 0
+	r = x - y
+	if r != 2147483647 {
+		t.Errorf("2147483647 - 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x - y
+	if r != 2147483646 {
+		t.Errorf("2147483647 - 1 = %d, want 2147483646", r)
+	}
+	y = 2147483647
+	r = x - y
+	if r != 0 {
+		t.Errorf("2147483647 - 2147483647 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32div(t *testing.T) {
+	var x, y, r int32
+	x = -2147483648
+	y = -2147483648
+	r = x / y
+	if r != 1 {
+		t.Errorf("-2147483648 / -2147483648 = %d, want 1", r)
+	}
+	y = -2147483647
+	r = x / y
+	if r != 1 {
+		t.Errorf("-2147483648 / -2147483647 = %d, want 1", r)
+	}
+	y = -1
+	r = x / y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 / -1 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x / y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 / 1 = %d, want -2147483648", r)
+	}
+	y = 2147483647
+	r = x / y
+	if r != -1 {
+		t.Errorf("-2147483648 / 2147483647 = %d, want -1", r)
+	}
+	x = -2147483647
+	y = -2147483648
+	r = x / y
+	if r != 0 {
+		t.Errorf("-2147483647 / -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x / y
+	if r != 1 {
+		t.Errorf("-2147483647 / -2147483647 = %d, want 1", r)
+	}
+	y = -1
+	r = x / y
+	if r != 2147483647 {
+		t.Errorf("-2147483647 / -1 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x / y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 / 1 = %d, want -2147483647", r)
+	}
+	y = 2147483647
+	r = x / y
+	if r != -1 {
+		t.Errorf("-2147483647 / 2147483647 = %d, want -1", r)
+	}
+	x = -1
+	y = -2147483648
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / -2147483647 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != 1 {
+		t.Errorf("-1 / -1 = %d, want 1", r)
+	}
+	y = 1
+	r = x / y
+	if r != -1 {
+		t.Errorf("-1 / 1 = %d, want -1", r)
+	}
+	y = 2147483647
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / 2147483647 = %d, want 0", r)
+	}
+	x = 0
+	y = -2147483648
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -2147483647 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 2147483647 = %d, want 0", r)
+	}
+	x = 1
+	y = -2147483648
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / -2147483647 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != -1 {
+		t.Errorf("1 / -1 = %d, want -1", r)
+	}
+	y = 1
+	r = x / y
+	if r != 1 {
+		t.Errorf("1 / 1 = %d, want 1", r)
+	}
+	y = 2147483647
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 2147483647 = %d, want 0", r)
+	}
+	x = 2147483647
+	y = -2147483648
+	r = x / y
+	if r != 0 {
+		t.Errorf("2147483647 / -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x / y
+	if r != -1 {
+		t.Errorf("2147483647 / -2147483647 = %d, want -1", r)
+	}
+	y = -1
+	r = x / y
+	if r != -2147483647 {
+		t.Errorf("2147483647 / -1 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x / y
+	if r != 2147483647 {
+		t.Errorf("2147483647 / 1 = %d, want 2147483647", r)
+	}
+	y = 2147483647
+	r = x / y
+	if r != 1 {
+		t.Errorf("2147483647 / 2147483647 = %d, want 1", r)
+	}
+}
+func TestConstFoldint32mul(t *testing.T) {
+	var x, y, r int32
+	x = -2147483648
+	y = -2147483648
+	r = x * y
+	if r != 0 {
+		t.Errorf("-2147483648 * -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x * y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 * -2147483647 = %d, want -2147483648", r)
+	}
+	y = -1
+	r = x * y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 * -1 = %d, want -2147483648", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-2147483648 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 * 1 = %d, want -2147483648", r)
+	}
+	y = 2147483647
+	r = x * y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 * 2147483647 = %d, want -2147483648", r)
+	}
+	x = -2147483647
+	y = -2147483648
+	r = x * y
+	if r != -2147483648 {
+		t.Errorf("-2147483647 * -2147483648 = %d, want -2147483648", r)
+	}
+	y = -2147483647
+	r = x * y
+	if r != 1 {
+		t.Errorf("-2147483647 * -2147483647 = %d, want 1", r)
+	}
+	y = -1
+	r = x * y
+	if r != 2147483647 {
+		t.Errorf("-2147483647 * -1 = %d, want 2147483647", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-2147483647 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 * 1 = %d, want -2147483647", r)
+	}
+	y = 2147483647
+	r = x * y
+	if r != -1 {
+		t.Errorf("-2147483647 * 2147483647 = %d, want -1", r)
+	}
+	x = -1
+	y = -2147483648
+	r = x * y
+	if r != -2147483648 {
+		t.Errorf("-1 * -2147483648 = %d, want -2147483648", r)
+	}
+	y = -2147483647
+	r = x * y
+	if r != 2147483647 {
+		t.Errorf("-1 * -2147483647 = %d, want 2147483647", r)
+	}
+	y = -1
+	r = x * y
+	if r != 1 {
+		t.Errorf("-1 * -1 = %d, want 1", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -1 {
+		t.Errorf("-1 * 1 = %d, want -1", r)
+	}
+	y = 2147483647
+	r = x * y
+	if r != -2147483647 {
+		t.Errorf("-1 * 2147483647 = %d, want -2147483647", r)
+	}
+	x = 0
+	y = -2147483648
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -2147483647 = %d, want 0", r)
+	}
+	y = -1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 2147483647 = %d, want 0", r)
+	}
+	x = 1
+	y = -2147483648
+	r = x * y
+	if r != -2147483648 {
+		t.Errorf("1 * -2147483648 = %d, want -2147483648", r)
+	}
+	y = -2147483647
+	r = x * y
+	if r != -2147483647 {
+		t.Errorf("1 * -2147483647 = %d, want -2147483647", r)
+	}
+	y = -1
+	r = x * y
+	if r != -1 {
+		t.Errorf("1 * -1 = %d, want -1", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 1 {
+		t.Errorf("1 * 1 = %d, want 1", r)
+	}
+	y = 2147483647
+	r = x * y
+	if r != 2147483647 {
+		t.Errorf("1 * 2147483647 = %d, want 2147483647", r)
+	}
+	x = 2147483647
+	y = -2147483648
+	r = x * y
+	if r != -2147483648 {
+		t.Errorf("2147483647 * -2147483648 = %d, want -2147483648", r)
+	}
+	y = -2147483647
+	r = x * y
+	if r != -1 {
+		t.Errorf("2147483647 * -2147483647 = %d, want -1", r)
+	}
+	y = -1
+	r = x * y
+	if r != -2147483647 {
+		t.Errorf("2147483647 * -1 = %d, want -2147483647", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("2147483647 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 2147483647 {
+		t.Errorf("2147483647 * 1 = %d, want 2147483647", r)
+	}
+	y = 2147483647
+	r = x * y
+	if r != 1 {
+		t.Errorf("2147483647 * 2147483647 = %d, want 1", r)
+	}
+}
+func TestConstFoldint32mod(t *testing.T) {
+	var x, y, r int32
+	x = -2147483648
+	y = -2147483648
+	r = x % y
+	if r != 0 {
+		t.Errorf("-2147483648 % -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x % y
+	if r != -1 {
+		t.Errorf("-2147483648 % -2147483647 = %d, want -1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-2147483648 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-2147483648 % 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x % y
+	if r != -1 {
+		t.Errorf("-2147483648 % 2147483647 = %d, want -1", r)
+	}
+	x = -2147483647
+	y = -2147483648
+	r = x % y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 % -2147483648 = %d, want -2147483647", r)
+	}
+	y = -2147483647
+	r = x % y
+	if r != 0 {
+		t.Errorf("-2147483647 % -2147483647 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-2147483647 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-2147483647 % 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x % y
+	if r != 0 {
+		t.Errorf("-2147483647 % 2147483647 = %d, want 0", r)
+	}
+	x = -1
+	y = -2147483648
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % -2147483648 = %d, want -1", r)
+	}
+	y = -2147483647
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % -2147483647 = %d, want -1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-1 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-1 % 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % 2147483647 = %d, want -1", r)
+	}
+	x = 0
+	y = -2147483648
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -2147483648 = %d, want 0", r)
+	}
+	y = -2147483647
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -2147483647 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 2147483647 = %d, want 0", r)
+	}
+	x = 1
+	y = -2147483648
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % -2147483648 = %d, want 1", r)
+	}
+	y = -2147483647
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % -2147483647 = %d, want 1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 2147483647 = %d, want 1", r)
+	}
+	x = 2147483647
+	y = -2147483648
+	r = x % y
+	if r != 2147483647 {
+		t.Errorf("2147483647 % -2147483648 = %d, want 2147483647", r)
+	}
+	y = -2147483647
+	r = x % y
+	if r != 0 {
+		t.Errorf("2147483647 % -2147483647 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("2147483647 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("2147483647 % 1 = %d, want 0", r)
+	}
+	y = 2147483647
+	r = x % y
+	if r != 0 {
+		t.Errorf("2147483647 % 2147483647 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16add(t *testing.T) {
+	var x, y, r uint16
+	x = 0
+	y = 0
+	r = x + y
+	if r != 0 {
+		t.Errorf("0 + 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x + y
+	if r != 1 {
+		t.Errorf("0 + 1 = %d, want 1", r)
+	}
+	y = 65535
+	r = x + y
+	if r != 65535 {
+		t.Errorf("0 + 65535 = %d, want 65535", r)
+	}
+	x = 1
+	y = 0
+	r = x + y
+	if r != 1 {
+		t.Errorf("1 + 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 2 {
+		t.Errorf("1 + 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x + y
+	if r != 0 {
+		t.Errorf("1 + 65535 = %d, want 0", r)
+	}
+	x = 65535
+	y = 0
+	r = x + y
+	if r != 65535 {
+		t.Errorf("65535 + 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x + y
+	if r != 0 {
+		t.Errorf("65535 + 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x + y
+	if r != 65534 {
+		t.Errorf("65535 + 65535 = %d, want 65534", r)
+	}
+}
+func TestConstFolduint16sub(t *testing.T) {
+	var x, y, r uint16
+	x = 0
+	y = 0
+	r = x - y
+	if r != 0 {
+		t.Errorf("0 - 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x - y
+	if r != 65535 {
+		t.Errorf("0 - 1 = %d, want 65535", r)
+	}
+	y = 65535
+	r = x - y
+	if r != 1 {
+		t.Errorf("0 - 65535 = %d, want 1", r)
+	}
+	x = 1
+	y = 0
+	r = x - y
+	if r != 1 {
+		t.Errorf("1 - 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x - y
+	if r != 0 {
+		t.Errorf("1 - 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x - y
+	if r != 2 {
+		t.Errorf("1 - 65535 = %d, want 2", r)
+	}
+	x = 65535
+	y = 0
+	r = x - y
+	if r != 65535 {
+		t.Errorf("65535 - 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x - y
+	if r != 65534 {
+		t.Errorf("65535 - 1 = %d, want 65534", r)
+	}
+	y = 65535
+	r = x - y
+	if r != 0 {
+		t.Errorf("65535 - 65535 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16div(t *testing.T) {
+	var x, y, r uint16
+	x = 0
+	y = 1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 1
+	r = x / y
+	if r != 1 {
+		t.Errorf("1 / 1 = %d, want 1", r)
+	}
+	y = 65535
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 65535 = %d, want 0", r)
+	}
+	x = 65535
+	y = 1
+	r = x / y
+	if r != 65535 {
+		t.Errorf("65535 / 1 = %d, want 65535", r)
+	}
+	y = 65535
+	r = x / y
+	if r != 1 {
+		t.Errorf("65535 / 65535 = %d, want 1", r)
+	}
+}
+func TestConstFolduint16mul(t *testing.T) {
+	var x, y, r uint16
+	x = 0
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 1 {
+		t.Errorf("1 * 1 = %d, want 1", r)
+	}
+	y = 65535
+	r = x * y
+	if r != 65535 {
+		t.Errorf("1 * 65535 = %d, want 65535", r)
+	}
+	x = 65535
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("65535 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 65535 {
+		t.Errorf("65535 * 1 = %d, want 65535", r)
+	}
+	y = 65535
+	r = x * y
+	if r != 1 {
+		t.Errorf("65535 * 65535 = %d, want 1", r)
+	}
+}
+func TestConstFolduint16mod(t *testing.T) {
+	var x, y, r uint16
+	x = 0
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 65535 = %d, want 1", r)
+	}
+	x = 65535
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("65535 % 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x % y
+	if r != 0 {
+		t.Errorf("65535 % 65535 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16add(t *testing.T) {
+	var x, y, r int16
+	x = -32768
+	y = -32768
+	r = x + y
+	if r != 0 {
+		t.Errorf("-32768 + -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x + y
+	if r != 1 {
+		t.Errorf("-32768 + -32767 = %d, want 1", r)
+	}
+	y = -1
+	r = x + y
+	if r != 32767 {
+		t.Errorf("-32768 + -1 = %d, want 32767", r)
+	}
+	y = 0
+	r = x + y
+	if r != -32768 {
+		t.Errorf("-32768 + 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x + y
+	if r != -32767 {
+		t.Errorf("-32768 + 1 = %d, want -32767", r)
+	}
+	y = 32766
+	r = x + y
+	if r != -2 {
+		t.Errorf("-32768 + 32766 = %d, want -2", r)
+	}
+	y = 32767
+	r = x + y
+	if r != -1 {
+		t.Errorf("-32768 + 32767 = %d, want -1", r)
+	}
+	x = -32767
+	y = -32768
+	r = x + y
+	if r != 1 {
+		t.Errorf("-32767 + -32768 = %d, want 1", r)
+	}
+	y = -32767
+	r = x + y
+	if r != 2 {
+		t.Errorf("-32767 + -32767 = %d, want 2", r)
+	}
+	y = -1
+	r = x + y
+	if r != -32768 {
+		t.Errorf("-32767 + -1 = %d, want -32768", r)
+	}
+	y = 0
+	r = x + y
+	if r != -32767 {
+		t.Errorf("-32767 + 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x + y
+	if r != -32766 {
+		t.Errorf("-32767 + 1 = %d, want -32766", r)
+	}
+	y = 32766
+	r = x + y
+	if r != -1 {
+		t.Errorf("-32767 + 32766 = %d, want -1", r)
+	}
+	y = 32767
+	r = x + y
+	if r != 0 {
+		t.Errorf("-32767 + 32767 = %d, want 0", r)
+	}
+	x = -1
+	y = -32768
+	r = x + y
+	if r != 32767 {
+		t.Errorf("-1 + -32768 = %d, want 32767", r)
+	}
+	y = -32767
+	r = x + y
+	if r != -32768 {
+		t.Errorf("-1 + -32767 = %d, want -32768", r)
+	}
+	y = -1
+	r = x + y
+	if r != -2 {
+		t.Errorf("-1 + -1 = %d, want -2", r)
+	}
+	y = 0
+	r = x + y
+	if r != -1 {
+		t.Errorf("-1 + 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 0 {
+		t.Errorf("-1 + 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x + y
+	if r != 32765 {
+		t.Errorf("-1 + 32766 = %d, want 32765", r)
+	}
+	y = 32767
+	r = x + y
+	if r != 32766 {
+		t.Errorf("-1 + 32767 = %d, want 32766", r)
+	}
+	x = 0
+	y = -32768
+	r = x + y
+	if r != -32768 {
+		t.Errorf("0 + -32768 = %d, want -32768", r)
+	}
+	y = -32767
+	r = x + y
+	if r != -32767 {
+		t.Errorf("0 + -32767 = %d, want -32767", r)
+	}
+	y = -1
+	r = x + y
+	if r != -1 {
+		t.Errorf("0 + -1 = %d, want -1", r)
+	}
+	y = 0
+	r = x + y
+	if r != 0 {
+		t.Errorf("0 + 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x + y
+	if r != 1 {
+		t.Errorf("0 + 1 = %d, want 1", r)
+	}
+	y = 32766
+	r = x + y
+	if r != 32766 {
+		t.Errorf("0 + 32766 = %d, want 32766", r)
+	}
+	y = 32767
+	r = x + y
+	if r != 32767 {
+		t.Errorf("0 + 32767 = %d, want 32767", r)
+	}
+	x = 1
+	y = -32768
+	r = x + y
+	if r != -32767 {
+		t.Errorf("1 + -32768 = %d, want -32767", r)
+	}
+	y = -32767
+	r = x + y
+	if r != -32766 {
+		t.Errorf("1 + -32767 = %d, want -32766", r)
+	}
+	y = -1
+	r = x + y
+	if r != 0 {
+		t.Errorf("1 + -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x + y
+	if r != 1 {
+		t.Errorf("1 + 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 2 {
+		t.Errorf("1 + 1 = %d, want 2", r)
+	}
+	y = 32766
+	r = x + y
+	if r != 32767 {
+		t.Errorf("1 + 32766 = %d, want 32767", r)
+	}
+	y = 32767
+	r = x + y
+	if r != -32768 {
+		t.Errorf("1 + 32767 = %d, want -32768", r)
+	}
+	x = 32766
+	y = -32768
+	r = x + y
+	if r != -2 {
+		t.Errorf("32766 + -32768 = %d, want -2", r)
+	}
+	y = -32767
+	r = x + y
+	if r != -1 {
+		t.Errorf("32766 + -32767 = %d, want -1", r)
+	}
+	y = -1
+	r = x + y
+	if r != 32765 {
+		t.Errorf("32766 + -1 = %d, want 32765", r)
+	}
+	y = 0
+	r = x + y
+	if r != 32766 {
+		t.Errorf("32766 + 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x + y
+	if r != 32767 {
+		t.Errorf("32766 + 1 = %d, want 32767", r)
+	}
+	y = 32766
+	r = x + y
+	if r != -4 {
+		t.Errorf("32766 + 32766 = %d, want -4", r)
+	}
+	y = 32767
+	r = x + y
+	if r != -3 {
+		t.Errorf("32766 + 32767 = %d, want -3", r)
+	}
+	x = 32767
+	y = -32768
+	r = x + y
+	if r != -1 {
+		t.Errorf("32767 + -32768 = %d, want -1", r)
+	}
+	y = -32767
+	r = x + y
+	if r != 0 {
+		t.Errorf("32767 + -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x + y
+	if r != 32766 {
+		t.Errorf("32767 + -1 = %d, want 32766", r)
+	}
+	y = 0
+	r = x + y
+	if r != 32767 {
+		t.Errorf("32767 + 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x + y
+	if r != -32768 {
+		t.Errorf("32767 + 1 = %d, want -32768", r)
+	}
+	y = 32766
+	r = x + y
+	if r != -3 {
+		t.Errorf("32767 + 32766 = %d, want -3", r)
+	}
+	y = 32767
+	r = x + y
+	if r != -2 {
+		t.Errorf("32767 + 32767 = %d, want -2", r)
+	}
+}
+func TestConstFoldint16sub(t *testing.T) {
+	var x, y, r int16
+	x = -32768
+	y = -32768
+	r = x - y
+	if r != 0 {
+		t.Errorf("-32768 - -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x - y
+	if r != -1 {
+		t.Errorf("-32768 - -32767 = %d, want -1", r)
+	}
+	y = -1
+	r = x - y
+	if r != -32767 {
+		t.Errorf("-32768 - -1 = %d, want -32767", r)
+	}
+	y = 0
+	r = x - y
+	if r != -32768 {
+		t.Errorf("-32768 - 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x - y
+	if r != 32767 {
+		t.Errorf("-32768 - 1 = %d, want 32767", r)
+	}
+	y = 32766
+	r = x - y
+	if r != 2 {
+		t.Errorf("-32768 - 32766 = %d, want 2", r)
+	}
+	y = 32767
+	r = x - y
+	if r != 1 {
+		t.Errorf("-32768 - 32767 = %d, want 1", r)
+	}
+	x = -32767
+	y = -32768
+	r = x - y
+	if r != 1 {
+		t.Errorf("-32767 - -32768 = %d, want 1", r)
+	}
+	y = -32767
+	r = x - y
+	if r != 0 {
+		t.Errorf("-32767 - -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x - y
+	if r != -32766 {
+		t.Errorf("-32767 - -1 = %d, want -32766", r)
+	}
+	y = 0
+	r = x - y
+	if r != -32767 {
+		t.Errorf("-32767 - 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x - y
+	if r != -32768 {
+		t.Errorf("-32767 - 1 = %d, want -32768", r)
+	}
+	y = 32766
+	r = x - y
+	if r != 3 {
+		t.Errorf("-32767 - 32766 = %d, want 3", r)
+	}
+	y = 32767
+	r = x - y
+	if r != 2 {
+		t.Errorf("-32767 - 32767 = %d, want 2", r)
+	}
+	x = -1
+	y = -32768
+	r = x - y
+	if r != 32767 {
+		t.Errorf("-1 - -32768 = %d, want 32767", r)
+	}
+	y = -32767
+	r = x - y
+	if r != 32766 {
+		t.Errorf("-1 - -32767 = %d, want 32766", r)
+	}
+	y = -1
+	r = x - y
+	if r != 0 {
+		t.Errorf("-1 - -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x - y
+	if r != -1 {
+		t.Errorf("-1 - 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x - y
+	if r != -2 {
+		t.Errorf("-1 - 1 = %d, want -2", r)
+	}
+	y = 32766
+	r = x - y
+	if r != -32767 {
+		t.Errorf("-1 - 32766 = %d, want -32767", r)
+	}
+	y = 32767
+	r = x - y
+	if r != -32768 {
+		t.Errorf("-1 - 32767 = %d, want -32768", r)
+	}
+	x = 0
+	y = -32768
+	r = x - y
+	if r != -32768 {
+		t.Errorf("0 - -32768 = %d, want -32768", r)
+	}
+	y = -32767
+	r = x - y
+	if r != 32767 {
+		t.Errorf("0 - -32767 = %d, want 32767", r)
+	}
+	y = -1
+	r = x - y
+	if r != 1 {
+		t.Errorf("0 - -1 = %d, want 1", r)
+	}
+	y = 0
+	r = x - y
+	if r != 0 {
+		t.Errorf("0 - 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x - y
+	if r != -1 {
+		t.Errorf("0 - 1 = %d, want -1", r)
+	}
+	y = 32766
+	r = x - y
+	if r != -32766 {
+		t.Errorf("0 - 32766 = %d, want -32766", r)
+	}
+	y = 32767
+	r = x - y
+	if r != -32767 {
+		t.Errorf("0 - 32767 = %d, want -32767", r)
+	}
+	x = 1
+	y = -32768
+	r = x - y
+	if r != -32767 {
+		t.Errorf("1 - -32768 = %d, want -32767", r)
+	}
+	y = -32767
+	r = x - y
+	if r != -32768 {
+		t.Errorf("1 - -32767 = %d, want -32768", r)
+	}
+	y = -1
+	r = x - y
+	if r != 2 {
+		t.Errorf("1 - -1 = %d, want 2", r)
+	}
+	y = 0
+	r = x - y
+	if r != 1 {
+		t.Errorf("1 - 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x - y
+	if r != 0 {
+		t.Errorf("1 - 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x - y
+	if r != -32765 {
+		t.Errorf("1 - 32766 = %d, want -32765", r)
+	}
+	y = 32767
+	r = x - y
+	if r != -32766 {
+		t.Errorf("1 - 32767 = %d, want -32766", r)
+	}
+	x = 32766
+	y = -32768
+	r = x - y
+	if r != -2 {
+		t.Errorf("32766 - -32768 = %d, want -2", r)
+	}
+	y = -32767
+	r = x - y
+	if r != -3 {
+		t.Errorf("32766 - -32767 = %d, want -3", r)
+	}
+	y = -1
+	r = x - y
+	if r != 32767 {
+		t.Errorf("32766 - -1 = %d, want 32767", r)
+	}
+	y = 0
+	r = x - y
+	if r != 32766 {
+		t.Errorf("32766 - 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x - y
+	if r != 32765 {
+		t.Errorf("32766 - 1 = %d, want 32765", r)
+	}
+	y = 32766
+	r = x - y
+	if r != 0 {
+		t.Errorf("32766 - 32766 = %d, want 0", r)
+	}
+	y = 32767
+	r = x - y
+	if r != -1 {
+		t.Errorf("32766 - 32767 = %d, want -1", r)
+	}
+	x = 32767
+	y = -32768
+	r = x - y
+	if r != -1 {
+		t.Errorf("32767 - -32768 = %d, want -1", r)
+	}
+	y = -32767
+	r = x - y
+	if r != -2 {
+		t.Errorf("32767 - -32767 = %d, want -2", r)
+	}
+	y = -1
+	r = x - y
+	if r != -32768 {
+		t.Errorf("32767 - -1 = %d, want -32768", r)
+	}
+	y = 0
+	r = x - y
+	if r != 32767 {
+		t.Errorf("32767 - 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x - y
+	if r != 32766 {
+		t.Errorf("32767 - 1 = %d, want 32766", r)
+	}
+	y = 32766
+	r = x - y
+	if r != 1 {
+		t.Errorf("32767 - 32766 = %d, want 1", r)
+	}
+	y = 32767
+	r = x - y
+	if r != 0 {
+		t.Errorf("32767 - 32767 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16div(t *testing.T) {
+	var x, y, r int16
+	x = -32768
+	y = -32768
+	r = x / y
+	if r != 1 {
+		t.Errorf("-32768 / -32768 = %d, want 1", r)
+	}
+	y = -32767
+	r = x / y
+	if r != 1 {
+		t.Errorf("-32768 / -32767 = %d, want 1", r)
+	}
+	y = -1
+	r = x / y
+	if r != -32768 {
+		t.Errorf("-32768 / -1 = %d, want -32768", r)
+	}
+	y = 1
+	r = x / y
+	if r != -32768 {
+		t.Errorf("-32768 / 1 = %d, want -32768", r)
+	}
+	y = 32766
+	r = x / y
+	if r != -1 {
+		t.Errorf("-32768 / 32766 = %d, want -1", r)
+	}
+	y = 32767
+	r = x / y
+	if r != -1 {
+		t.Errorf("-32768 / 32767 = %d, want -1", r)
+	}
+	x = -32767
+	y = -32768
+	r = x / y
+	if r != 0 {
+		t.Errorf("-32767 / -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x / y
+	if r != 1 {
+		t.Errorf("-32767 / -32767 = %d, want 1", r)
+	}
+	y = -1
+	r = x / y
+	if r != 32767 {
+		t.Errorf("-32767 / -1 = %d, want 32767", r)
+	}
+	y = 1
+	r = x / y
+	if r != -32767 {
+		t.Errorf("-32767 / 1 = %d, want -32767", r)
+	}
+	y = 32766
+	r = x / y
+	if r != -1 {
+		t.Errorf("-32767 / 32766 = %d, want -1", r)
+	}
+	y = 32767
+	r = x / y
+	if r != -1 {
+		t.Errorf("-32767 / 32767 = %d, want -1", r)
+	}
+	x = -1
+	y = -32768
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != 1 {
+		t.Errorf("-1 / -1 = %d, want 1", r)
+	}
+	y = 1
+	r = x / y
+	if r != -1 {
+		t.Errorf("-1 / 1 = %d, want -1", r)
+	}
+	y = 32766
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / 32766 = %d, want 0", r)
+	}
+	y = 32767
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / 32767 = %d, want 0", r)
+	}
+	x = 0
+	y = -32768
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 32766 = %d, want 0", r)
+	}
+	y = 32767
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 32767 = %d, want 0", r)
+	}
+	x = 1
+	y = -32768
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != -1 {
+		t.Errorf("1 / -1 = %d, want -1", r)
+	}
+	y = 1
+	r = x / y
+	if r != 1 {
+		t.Errorf("1 / 1 = %d, want 1", r)
+	}
+	y = 32766
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 32766 = %d, want 0", r)
+	}
+	y = 32767
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 32767 = %d, want 0", r)
+	}
+	x = 32766
+	y = -32768
+	r = x / y
+	if r != 0 {
+		t.Errorf("32766 / -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x / y
+	if r != 0 {
+		t.Errorf("32766 / -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != -32766 {
+		t.Errorf("32766 / -1 = %d, want -32766", r)
+	}
+	y = 1
+	r = x / y
+	if r != 32766 {
+		t.Errorf("32766 / 1 = %d, want 32766", r)
+	}
+	y = 32766
+	r = x / y
+	if r != 1 {
+		t.Errorf("32766 / 32766 = %d, want 1", r)
+	}
+	y = 32767
+	r = x / y
+	if r != 0 {
+		t.Errorf("32766 / 32767 = %d, want 0", r)
+	}
+	x = 32767
+	y = -32768
+	r = x / y
+	if r != 0 {
+		t.Errorf("32767 / -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x / y
+	if r != -1 {
+		t.Errorf("32767 / -32767 = %d, want -1", r)
+	}
+	y = -1
+	r = x / y
+	if r != -32767 {
+		t.Errorf("32767 / -1 = %d, want -32767", r)
+	}
+	y = 1
+	r = x / y
+	if r != 32767 {
+		t.Errorf("32767 / 1 = %d, want 32767", r)
+	}
+	y = 32766
+	r = x / y
+	if r != 1 {
+		t.Errorf("32767 / 32766 = %d, want 1", r)
+	}
+	y = 32767
+	r = x / y
+	if r != 1 {
+		t.Errorf("32767 / 32767 = %d, want 1", r)
+	}
+}
+func TestConstFoldint16mul(t *testing.T) {
+	var x, y, r int16
+	x = -32768
+	y = -32768
+	r = x * y
+	if r != 0 {
+		t.Errorf("-32768 * -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x * y
+	if r != -32768 {
+		t.Errorf("-32768 * -32767 = %d, want -32768", r)
+	}
+	y = -1
+	r = x * y
+	if r != -32768 {
+		t.Errorf("-32768 * -1 = %d, want -32768", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-32768 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -32768 {
+		t.Errorf("-32768 * 1 = %d, want -32768", r)
+	}
+	y = 32766
+	r = x * y
+	if r != 0 {
+		t.Errorf("-32768 * 32766 = %d, want 0", r)
+	}
+	y = 32767
+	r = x * y
+	if r != -32768 {
+		t.Errorf("-32768 * 32767 = %d, want -32768", r)
+	}
+	x = -32767
+	y = -32768
+	r = x * y
+	if r != -32768 {
+		t.Errorf("-32767 * -32768 = %d, want -32768", r)
+	}
+	y = -32767
+	r = x * y
+	if r != 1 {
+		t.Errorf("-32767 * -32767 = %d, want 1", r)
+	}
+	y = -1
+	r = x * y
+	if r != 32767 {
+		t.Errorf("-32767 * -1 = %d, want 32767", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-32767 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -32767 {
+		t.Errorf("-32767 * 1 = %d, want -32767", r)
+	}
+	y = 32766
+	r = x * y
+	if r != 32766 {
+		t.Errorf("-32767 * 32766 = %d, want 32766", r)
+	}
+	y = 32767
+	r = x * y
+	if r != -1 {
+		t.Errorf("-32767 * 32767 = %d, want -1", r)
+	}
+	x = -1
+	y = -32768
+	r = x * y
+	if r != -32768 {
+		t.Errorf("-1 * -32768 = %d, want -32768", r)
+	}
+	y = -32767
+	r = x * y
+	if r != 32767 {
+		t.Errorf("-1 * -32767 = %d, want 32767", r)
+	}
+	y = -1
+	r = x * y
+	if r != 1 {
+		t.Errorf("-1 * -1 = %d, want 1", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -1 {
+		t.Errorf("-1 * 1 = %d, want -1", r)
+	}
+	y = 32766
+	r = x * y
+	if r != -32766 {
+		t.Errorf("-1 * 32766 = %d, want -32766", r)
+	}
+	y = 32767
+	r = x * y
+	if r != -32767 {
+		t.Errorf("-1 * 32767 = %d, want -32767", r)
+	}
+	x = 0
+	y = -32768
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 32766 = %d, want 0", r)
+	}
+	y = 32767
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 32767 = %d, want 0", r)
+	}
+	x = 1
+	y = -32768
+	r = x * y
+	if r != -32768 {
+		t.Errorf("1 * -32768 = %d, want -32768", r)
+	}
+	y = -32767
+	r = x * y
+	if r != -32767 {
+		t.Errorf("1 * -32767 = %d, want -32767", r)
+	}
+	y = -1
+	r = x * y
+	if r != -1 {
+		t.Errorf("1 * -1 = %d, want -1", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 1 {
+		t.Errorf("1 * 1 = %d, want 1", r)
+	}
+	y = 32766
+	r = x * y
+	if r != 32766 {
+		t.Errorf("1 * 32766 = %d, want 32766", r)
+	}
+	y = 32767
+	r = x * y
+	if r != 32767 {
+		t.Errorf("1 * 32767 = %d, want 32767", r)
+	}
+	x = 32766
+	y = -32768
+	r = x * y
+	if r != 0 {
+		t.Errorf("32766 * -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x * y
+	if r != 32766 {
+		t.Errorf("32766 * -32767 = %d, want 32766", r)
+	}
+	y = -1
+	r = x * y
+	if r != -32766 {
+		t.Errorf("32766 * -1 = %d, want -32766", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("32766 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 32766 {
+		t.Errorf("32766 * 1 = %d, want 32766", r)
+	}
+	y = 32766
+	r = x * y
+	if r != 4 {
+		t.Errorf("32766 * 32766 = %d, want 4", r)
+	}
+	y = 32767
+	r = x * y
+	if r != -32766 {
+		t.Errorf("32766 * 32767 = %d, want -32766", r)
+	}
+	x = 32767
+	y = -32768
+	r = x * y
+	if r != -32768 {
+		t.Errorf("32767 * -32768 = %d, want -32768", r)
+	}
+	y = -32767
+	r = x * y
+	if r != -1 {
+		t.Errorf("32767 * -32767 = %d, want -1", r)
+	}
+	y = -1
+	r = x * y
+	if r != -32767 {
+		t.Errorf("32767 * -1 = %d, want -32767", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("32767 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 32767 {
+		t.Errorf("32767 * 1 = %d, want 32767", r)
+	}
+	y = 32766
+	r = x * y
+	if r != -32766 {
+		t.Errorf("32767 * 32766 = %d, want -32766", r)
+	}
+	y = 32767
+	r = x * y
+	if r != 1 {
+		t.Errorf("32767 * 32767 = %d, want 1", r)
+	}
+}
+func TestConstFoldint16mod(t *testing.T) {
+	var x, y, r int16
+	x = -32768
+	y = -32768
+	r = x % y
+	if r != 0 {
+		t.Errorf("-32768 % -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x % y
+	if r != -1 {
+		t.Errorf("-32768 % -32767 = %d, want -1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-32768 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-32768 % 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x % y
+	if r != -2 {
+		t.Errorf("-32768 % 32766 = %d, want -2", r)
+	}
+	y = 32767
+	r = x % y
+	if r != -1 {
+		t.Errorf("-32768 % 32767 = %d, want -1", r)
+	}
+	x = -32767
+	y = -32768
+	r = x % y
+	if r != -32767 {
+		t.Errorf("-32767 % -32768 = %d, want -32767", r)
+	}
+	y = -32767
+	r = x % y
+	if r != 0 {
+		t.Errorf("-32767 % -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-32767 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-32767 % 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x % y
+	if r != -1 {
+		t.Errorf("-32767 % 32766 = %d, want -1", r)
+	}
+	y = 32767
+	r = x % y
+	if r != 0 {
+		t.Errorf("-32767 % 32767 = %d, want 0", r)
+	}
+	x = -1
+	y = -32768
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % -32768 = %d, want -1", r)
+	}
+	y = -32767
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % -32767 = %d, want -1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-1 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-1 % 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % 32766 = %d, want -1", r)
+	}
+	y = 32767
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % 32767 = %d, want -1", r)
+	}
+	x = 0
+	y = -32768
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -32768 = %d, want 0", r)
+	}
+	y = -32767
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 32766 = %d, want 0", r)
+	}
+	y = 32767
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 32767 = %d, want 0", r)
+	}
+	x = 1
+	y = -32768
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % -32768 = %d, want 1", r)
+	}
+	y = -32767
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % -32767 = %d, want 1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 32766 = %d, want 1", r)
+	}
+	y = 32767
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 32767 = %d, want 1", r)
+	}
+	x = 32766
+	y = -32768
+	r = x % y
+	if r != 32766 {
+		t.Errorf("32766 % -32768 = %d, want 32766", r)
+	}
+	y = -32767
+	r = x % y
+	if r != 32766 {
+		t.Errorf("32766 % -32767 = %d, want 32766", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("32766 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("32766 % 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x % y
+	if r != 0 {
+		t.Errorf("32766 % 32766 = %d, want 0", r)
+	}
+	y = 32767
+	r = x % y
+	if r != 32766 {
+		t.Errorf("32766 % 32767 = %d, want 32766", r)
+	}
+	x = 32767
+	y = -32768
+	r = x % y
+	if r != 32767 {
+		t.Errorf("32767 % -32768 = %d, want 32767", r)
+	}
+	y = -32767
+	r = x % y
+	if r != 0 {
+		t.Errorf("32767 % -32767 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("32767 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("32767 % 1 = %d, want 0", r)
+	}
+	y = 32766
+	r = x % y
+	if r != 1 {
+		t.Errorf("32767 % 32766 = %d, want 1", r)
+	}
+	y = 32767
+	r = x % y
+	if r != 0 {
+		t.Errorf("32767 % 32767 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8add(t *testing.T) {
+	var x, y, r uint8
+	x = 0
+	y = 0
+	r = x + y
+	if r != 0 {
+		t.Errorf("0 + 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x + y
+	if r != 1 {
+		t.Errorf("0 + 1 = %d, want 1", r)
+	}
+	y = 255
+	r = x + y
+	if r != 255 {
+		t.Errorf("0 + 255 = %d, want 255", r)
+	}
+	x = 1
+	y = 0
+	r = x + y
+	if r != 1 {
+		t.Errorf("1 + 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 2 {
+		t.Errorf("1 + 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x + y
+	if r != 0 {
+		t.Errorf("1 + 255 = %d, want 0", r)
+	}
+	x = 255
+	y = 0
+	r = x + y
+	if r != 255 {
+		t.Errorf("255 + 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x + y
+	if r != 0 {
+		t.Errorf("255 + 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x + y
+	if r != 254 {
+		t.Errorf("255 + 255 = %d, want 254", r)
+	}
+}
+func TestConstFolduint8sub(t *testing.T) {
+	var x, y, r uint8
+	x = 0
+	y = 0
+	r = x - y
+	if r != 0 {
+		t.Errorf("0 - 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x - y
+	if r != 255 {
+		t.Errorf("0 - 1 = %d, want 255", r)
+	}
+	y = 255
+	r = x - y
+	if r != 1 {
+		t.Errorf("0 - 255 = %d, want 1", r)
+	}
+	x = 1
+	y = 0
+	r = x - y
+	if r != 1 {
+		t.Errorf("1 - 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x - y
+	if r != 0 {
+		t.Errorf("1 - 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x - y
+	if r != 2 {
+		t.Errorf("1 - 255 = %d, want 2", r)
+	}
+	x = 255
+	y = 0
+	r = x - y
+	if r != 255 {
+		t.Errorf("255 - 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x - y
+	if r != 254 {
+		t.Errorf("255 - 1 = %d, want 254", r)
+	}
+	y = 255
+	r = x - y
+	if r != 0 {
+		t.Errorf("255 - 255 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8div(t *testing.T) {
+	var x, y, r uint8
+	x = 0
+	y = 1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 1
+	r = x / y
+	if r != 1 {
+		t.Errorf("1 / 1 = %d, want 1", r)
+	}
+	y = 255
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 255 = %d, want 0", r)
+	}
+	x = 255
+	y = 1
+	r = x / y
+	if r != 255 {
+		t.Errorf("255 / 1 = %d, want 255", r)
+	}
+	y = 255
+	r = x / y
+	if r != 1 {
+		t.Errorf("255 / 255 = %d, want 1", r)
+	}
+}
+func TestConstFolduint8mul(t *testing.T) {
+	var x, y, r uint8
+	x = 0
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 1 {
+		t.Errorf("1 * 1 = %d, want 1", r)
+	}
+	y = 255
+	r = x * y
+	if r != 255 {
+		t.Errorf("1 * 255 = %d, want 255", r)
+	}
+	x = 255
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("255 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 255 {
+		t.Errorf("255 * 1 = %d, want 255", r)
+	}
+	y = 255
+	r = x * y
+	if r != 1 {
+		t.Errorf("255 * 255 = %d, want 1", r)
+	}
+}
+func TestConstFolduint8mod(t *testing.T) {
+	var x, y, r uint8
+	x = 0
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 255 = %d, want 1", r)
+	}
+	x = 255
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("255 % 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x % y
+	if r != 0 {
+		t.Errorf("255 % 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8add(t *testing.T) {
+	var x, y, r int8
+	x = -128
+	y = -128
+	r = x + y
+	if r != 0 {
+		t.Errorf("-128 + -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x + y
+	if r != 1 {
+		t.Errorf("-128 + -127 = %d, want 1", r)
+	}
+	y = -1
+	r = x + y
+	if r != 127 {
+		t.Errorf("-128 + -1 = %d, want 127", r)
+	}
+	y = 0
+	r = x + y
+	if r != -128 {
+		t.Errorf("-128 + 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x + y
+	if r != -127 {
+		t.Errorf("-128 + 1 = %d, want -127", r)
+	}
+	y = 126
+	r = x + y
+	if r != -2 {
+		t.Errorf("-128 + 126 = %d, want -2", r)
+	}
+	y = 127
+	r = x + y
+	if r != -1 {
+		t.Errorf("-128 + 127 = %d, want -1", r)
+	}
+	x = -127
+	y = -128
+	r = x + y
+	if r != 1 {
+		t.Errorf("-127 + -128 = %d, want 1", r)
+	}
+	y = -127
+	r = x + y
+	if r != 2 {
+		t.Errorf("-127 + -127 = %d, want 2", r)
+	}
+	y = -1
+	r = x + y
+	if r != -128 {
+		t.Errorf("-127 + -1 = %d, want -128", r)
+	}
+	y = 0
+	r = x + y
+	if r != -127 {
+		t.Errorf("-127 + 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x + y
+	if r != -126 {
+		t.Errorf("-127 + 1 = %d, want -126", r)
+	}
+	y = 126
+	r = x + y
+	if r != -1 {
+		t.Errorf("-127 + 126 = %d, want -1", r)
+	}
+	y = 127
+	r = x + y
+	if r != 0 {
+		t.Errorf("-127 + 127 = %d, want 0", r)
+	}
+	x = -1
+	y = -128
+	r = x + y
+	if r != 127 {
+		t.Errorf("-1 + -128 = %d, want 127", r)
+	}
+	y = -127
+	r = x + y
+	if r != -128 {
+		t.Errorf("-1 + -127 = %d, want -128", r)
+	}
+	y = -1
+	r = x + y
+	if r != -2 {
+		t.Errorf("-1 + -1 = %d, want -2", r)
+	}
+	y = 0
+	r = x + y
+	if r != -1 {
+		t.Errorf("-1 + 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 0 {
+		t.Errorf("-1 + 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x + y
+	if r != 125 {
+		t.Errorf("-1 + 126 = %d, want 125", r)
+	}
+	y = 127
+	r = x + y
+	if r != 126 {
+		t.Errorf("-1 + 127 = %d, want 126", r)
+	}
+	x = 0
+	y = -128
+	r = x + y
+	if r != -128 {
+		t.Errorf("0 + -128 = %d, want -128", r)
+	}
+	y = -127
+	r = x + y
+	if r != -127 {
+		t.Errorf("0 + -127 = %d, want -127", r)
+	}
+	y = -1
+	r = x + y
+	if r != -1 {
+		t.Errorf("0 + -1 = %d, want -1", r)
+	}
+	y = 0
+	r = x + y
+	if r != 0 {
+		t.Errorf("0 + 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x + y
+	if r != 1 {
+		t.Errorf("0 + 1 = %d, want 1", r)
+	}
+	y = 126
+	r = x + y
+	if r != 126 {
+		t.Errorf("0 + 126 = %d, want 126", r)
+	}
+	y = 127
+	r = x + y
+	if r != 127 {
+		t.Errorf("0 + 127 = %d, want 127", r)
+	}
+	x = 1
+	y = -128
+	r = x + y
+	if r != -127 {
+		t.Errorf("1 + -128 = %d, want -127", r)
+	}
+	y = -127
+	r = x + y
+	if r != -126 {
+		t.Errorf("1 + -127 = %d, want -126", r)
+	}
+	y = -1
+	r = x + y
+	if r != 0 {
+		t.Errorf("1 + -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x + y
+	if r != 1 {
+		t.Errorf("1 + 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x + y
+	if r != 2 {
+		t.Errorf("1 + 1 = %d, want 2", r)
+	}
+	y = 126
+	r = x + y
+	if r != 127 {
+		t.Errorf("1 + 126 = %d, want 127", r)
+	}
+	y = 127
+	r = x + y
+	if r != -128 {
+		t.Errorf("1 + 127 = %d, want -128", r)
+	}
+	x = 126
+	y = -128
+	r = x + y
+	if r != -2 {
+		t.Errorf("126 + -128 = %d, want -2", r)
+	}
+	y = -127
+	r = x + y
+	if r != -1 {
+		t.Errorf("126 + -127 = %d, want -1", r)
+	}
+	y = -1
+	r = x + y
+	if r != 125 {
+		t.Errorf("126 + -1 = %d, want 125", r)
+	}
+	y = 0
+	r = x + y
+	if r != 126 {
+		t.Errorf("126 + 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x + y
+	if r != 127 {
+		t.Errorf("126 + 1 = %d, want 127", r)
+	}
+	y = 126
+	r = x + y
+	if r != -4 {
+		t.Errorf("126 + 126 = %d, want -4", r)
+	}
+	y = 127
+	r = x + y
+	if r != -3 {
+		t.Errorf("126 + 127 = %d, want -3", r)
+	}
+	x = 127
+	y = -128
+	r = x + y
+	if r != -1 {
+		t.Errorf("127 + -128 = %d, want -1", r)
+	}
+	y = -127
+	r = x + y
+	if r != 0 {
+		t.Errorf("127 + -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x + y
+	if r != 126 {
+		t.Errorf("127 + -1 = %d, want 126", r)
+	}
+	y = 0
+	r = x + y
+	if r != 127 {
+		t.Errorf("127 + 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x + y
+	if r != -128 {
+		t.Errorf("127 + 1 = %d, want -128", r)
+	}
+	y = 126
+	r = x + y
+	if r != -3 {
+		t.Errorf("127 + 126 = %d, want -3", r)
+	}
+	y = 127
+	r = x + y
+	if r != -2 {
+		t.Errorf("127 + 127 = %d, want -2", r)
+	}
+}
+func TestConstFoldint8sub(t *testing.T) {
+	var x, y, r int8
+	x = -128
+	y = -128
+	r = x - y
+	if r != 0 {
+		t.Errorf("-128 - -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x - y
+	if r != -1 {
+		t.Errorf("-128 - -127 = %d, want -1", r)
+	}
+	y = -1
+	r = x - y
+	if r != -127 {
+		t.Errorf("-128 - -1 = %d, want -127", r)
+	}
+	y = 0
+	r = x - y
+	if r != -128 {
+		t.Errorf("-128 - 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x - y
+	if r != 127 {
+		t.Errorf("-128 - 1 = %d, want 127", r)
+	}
+	y = 126
+	r = x - y
+	if r != 2 {
+		t.Errorf("-128 - 126 = %d, want 2", r)
+	}
+	y = 127
+	r = x - y
+	if r != 1 {
+		t.Errorf("-128 - 127 = %d, want 1", r)
+	}
+	x = -127
+	y = -128
+	r = x - y
+	if r != 1 {
+		t.Errorf("-127 - -128 = %d, want 1", r)
+	}
+	y = -127
+	r = x - y
+	if r != 0 {
+		t.Errorf("-127 - -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x - y
+	if r != -126 {
+		t.Errorf("-127 - -1 = %d, want -126", r)
+	}
+	y = 0
+	r = x - y
+	if r != -127 {
+		t.Errorf("-127 - 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x - y
+	if r != -128 {
+		t.Errorf("-127 - 1 = %d, want -128", r)
+	}
+	y = 126
+	r = x - y
+	if r != 3 {
+		t.Errorf("-127 - 126 = %d, want 3", r)
+	}
+	y = 127
+	r = x - y
+	if r != 2 {
+		t.Errorf("-127 - 127 = %d, want 2", r)
+	}
+	x = -1
+	y = -128
+	r = x - y
+	if r != 127 {
+		t.Errorf("-1 - -128 = %d, want 127", r)
+	}
+	y = -127
+	r = x - y
+	if r != 126 {
+		t.Errorf("-1 - -127 = %d, want 126", r)
+	}
+	y = -1
+	r = x - y
+	if r != 0 {
+		t.Errorf("-1 - -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x - y
+	if r != -1 {
+		t.Errorf("-1 - 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x - y
+	if r != -2 {
+		t.Errorf("-1 - 1 = %d, want -2", r)
+	}
+	y = 126
+	r = x - y
+	if r != -127 {
+		t.Errorf("-1 - 126 = %d, want -127", r)
+	}
+	y = 127
+	r = x - y
+	if r != -128 {
+		t.Errorf("-1 - 127 = %d, want -128", r)
+	}
+	x = 0
+	y = -128
+	r = x - y
+	if r != -128 {
+		t.Errorf("0 - -128 = %d, want -128", r)
+	}
+	y = -127
+	r = x - y
+	if r != 127 {
+		t.Errorf("0 - -127 = %d, want 127", r)
+	}
+	y = -1
+	r = x - y
+	if r != 1 {
+		t.Errorf("0 - -1 = %d, want 1", r)
+	}
+	y = 0
+	r = x - y
+	if r != 0 {
+		t.Errorf("0 - 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x - y
+	if r != -1 {
+		t.Errorf("0 - 1 = %d, want -1", r)
+	}
+	y = 126
+	r = x - y
+	if r != -126 {
+		t.Errorf("0 - 126 = %d, want -126", r)
+	}
+	y = 127
+	r = x - y
+	if r != -127 {
+		t.Errorf("0 - 127 = %d, want -127", r)
+	}
+	x = 1
+	y = -128
+	r = x - y
+	if r != -127 {
+		t.Errorf("1 - -128 = %d, want -127", r)
+	}
+	y = -127
+	r = x - y
+	if r != -128 {
+		t.Errorf("1 - -127 = %d, want -128", r)
+	}
+	y = -1
+	r = x - y
+	if r != 2 {
+		t.Errorf("1 - -1 = %d, want 2", r)
+	}
+	y = 0
+	r = x - y
+	if r != 1 {
+		t.Errorf("1 - 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x - y
+	if r != 0 {
+		t.Errorf("1 - 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x - y
+	if r != -125 {
+		t.Errorf("1 - 126 = %d, want -125", r)
+	}
+	y = 127
+	r = x - y
+	if r != -126 {
+		t.Errorf("1 - 127 = %d, want -126", r)
+	}
+	x = 126
+	y = -128
+	r = x - y
+	if r != -2 {
+		t.Errorf("126 - -128 = %d, want -2", r)
+	}
+	y = -127
+	r = x - y
+	if r != -3 {
+		t.Errorf("126 - -127 = %d, want -3", r)
+	}
+	y = -1
+	r = x - y
+	if r != 127 {
+		t.Errorf("126 - -1 = %d, want 127", r)
+	}
+	y = 0
+	r = x - y
+	if r != 126 {
+		t.Errorf("126 - 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x - y
+	if r != 125 {
+		t.Errorf("126 - 1 = %d, want 125", r)
+	}
+	y = 126
+	r = x - y
+	if r != 0 {
+		t.Errorf("126 - 126 = %d, want 0", r)
+	}
+	y = 127
+	r = x - y
+	if r != -1 {
+		t.Errorf("126 - 127 = %d, want -1", r)
+	}
+	x = 127
+	y = -128
+	r = x - y
+	if r != -1 {
+		t.Errorf("127 - -128 = %d, want -1", r)
+	}
+	y = -127
+	r = x - y
+	if r != -2 {
+		t.Errorf("127 - -127 = %d, want -2", r)
+	}
+	y = -1
+	r = x - y
+	if r != -128 {
+		t.Errorf("127 - -1 = %d, want -128", r)
+	}
+	y = 0
+	r = x - y
+	if r != 127 {
+		t.Errorf("127 - 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x - y
+	if r != 126 {
+		t.Errorf("127 - 1 = %d, want 126", r)
+	}
+	y = 126
+	r = x - y
+	if r != 1 {
+		t.Errorf("127 - 126 = %d, want 1", r)
+	}
+	y = 127
+	r = x - y
+	if r != 0 {
+		t.Errorf("127 - 127 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8div(t *testing.T) {
+	var x, y, r int8
+	x = -128
+	y = -128
+	r = x / y
+	if r != 1 {
+		t.Errorf("-128 / -128 = %d, want 1", r)
+	}
+	y = -127
+	r = x / y
+	if r != 1 {
+		t.Errorf("-128 / -127 = %d, want 1", r)
+	}
+	y = -1
+	r = x / y
+	if r != -128 {
+		t.Errorf("-128 / -1 = %d, want -128", r)
+	}
+	y = 1
+	r = x / y
+	if r != -128 {
+		t.Errorf("-128 / 1 = %d, want -128", r)
+	}
+	y = 126
+	r = x / y
+	if r != -1 {
+		t.Errorf("-128 / 126 = %d, want -1", r)
+	}
+	y = 127
+	r = x / y
+	if r != -1 {
+		t.Errorf("-128 / 127 = %d, want -1", r)
+	}
+	x = -127
+	y = -128
+	r = x / y
+	if r != 0 {
+		t.Errorf("-127 / -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x / y
+	if r != 1 {
+		t.Errorf("-127 / -127 = %d, want 1", r)
+	}
+	y = -1
+	r = x / y
+	if r != 127 {
+		t.Errorf("-127 / -1 = %d, want 127", r)
+	}
+	y = 1
+	r = x / y
+	if r != -127 {
+		t.Errorf("-127 / 1 = %d, want -127", r)
+	}
+	y = 126
+	r = x / y
+	if r != -1 {
+		t.Errorf("-127 / 126 = %d, want -1", r)
+	}
+	y = 127
+	r = x / y
+	if r != -1 {
+		t.Errorf("-127 / 127 = %d, want -1", r)
+	}
+	x = -1
+	y = -128
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != 1 {
+		t.Errorf("-1 / -1 = %d, want 1", r)
+	}
+	y = 1
+	r = x / y
+	if r != -1 {
+		t.Errorf("-1 / 1 = %d, want -1", r)
+	}
+	y = 126
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / 126 = %d, want 0", r)
+	}
+	y = 127
+	r = x / y
+	if r != 0 {
+		t.Errorf("-1 / 127 = %d, want 0", r)
+	}
+	x = 0
+	y = -128
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 126 = %d, want 0", r)
+	}
+	y = 127
+	r = x / y
+	if r != 0 {
+		t.Errorf("0 / 127 = %d, want 0", r)
+	}
+	x = 1
+	y = -128
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != -1 {
+		t.Errorf("1 / -1 = %d, want -1", r)
+	}
+	y = 1
+	r = x / y
+	if r != 1 {
+		t.Errorf("1 / 1 = %d, want 1", r)
+	}
+	y = 126
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 126 = %d, want 0", r)
+	}
+	y = 127
+	r = x / y
+	if r != 0 {
+		t.Errorf("1 / 127 = %d, want 0", r)
+	}
+	x = 126
+	y = -128
+	r = x / y
+	if r != 0 {
+		t.Errorf("126 / -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x / y
+	if r != 0 {
+		t.Errorf("126 / -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x / y
+	if r != -126 {
+		t.Errorf("126 / -1 = %d, want -126", r)
+	}
+	y = 1
+	r = x / y
+	if r != 126 {
+		t.Errorf("126 / 1 = %d, want 126", r)
+	}
+	y = 126
+	r = x / y
+	if r != 1 {
+		t.Errorf("126 / 126 = %d, want 1", r)
+	}
+	y = 127
+	r = x / y
+	if r != 0 {
+		t.Errorf("126 / 127 = %d, want 0", r)
+	}
+	x = 127
+	y = -128
+	r = x / y
+	if r != 0 {
+		t.Errorf("127 / -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x / y
+	if r != -1 {
+		t.Errorf("127 / -127 = %d, want -1", r)
+	}
+	y = -1
+	r = x / y
+	if r != -127 {
+		t.Errorf("127 / -1 = %d, want -127", r)
+	}
+	y = 1
+	r = x / y
+	if r != 127 {
+		t.Errorf("127 / 1 = %d, want 127", r)
+	}
+	y = 126
+	r = x / y
+	if r != 1 {
+		t.Errorf("127 / 126 = %d, want 1", r)
+	}
+	y = 127
+	r = x / y
+	if r != 1 {
+		t.Errorf("127 / 127 = %d, want 1", r)
+	}
+}
+func TestConstFoldint8mul(t *testing.T) {
+	var x, y, r int8
+	x = -128
+	y = -128
+	r = x * y
+	if r != 0 {
+		t.Errorf("-128 * -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x * y
+	if r != -128 {
+		t.Errorf("-128 * -127 = %d, want -128", r)
+	}
+	y = -1
+	r = x * y
+	if r != -128 {
+		t.Errorf("-128 * -1 = %d, want -128", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-128 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -128 {
+		t.Errorf("-128 * 1 = %d, want -128", r)
+	}
+	y = 126
+	r = x * y
+	if r != 0 {
+		t.Errorf("-128 * 126 = %d, want 0", r)
+	}
+	y = 127
+	r = x * y
+	if r != -128 {
+		t.Errorf("-128 * 127 = %d, want -128", r)
+	}
+	x = -127
+	y = -128
+	r = x * y
+	if r != -128 {
+		t.Errorf("-127 * -128 = %d, want -128", r)
+	}
+	y = -127
+	r = x * y
+	if r != 1 {
+		t.Errorf("-127 * -127 = %d, want 1", r)
+	}
+	y = -1
+	r = x * y
+	if r != 127 {
+		t.Errorf("-127 * -1 = %d, want 127", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-127 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -127 {
+		t.Errorf("-127 * 1 = %d, want -127", r)
+	}
+	y = 126
+	r = x * y
+	if r != 126 {
+		t.Errorf("-127 * 126 = %d, want 126", r)
+	}
+	y = 127
+	r = x * y
+	if r != -1 {
+		t.Errorf("-127 * 127 = %d, want -1", r)
+	}
+	x = -1
+	y = -128
+	r = x * y
+	if r != -128 {
+		t.Errorf("-1 * -128 = %d, want -128", r)
+	}
+	y = -127
+	r = x * y
+	if r != 127 {
+		t.Errorf("-1 * -127 = %d, want 127", r)
+	}
+	y = -1
+	r = x * y
+	if r != 1 {
+		t.Errorf("-1 * -1 = %d, want 1", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("-1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != -1 {
+		t.Errorf("-1 * 1 = %d, want -1", r)
+	}
+	y = 126
+	r = x * y
+	if r != -126 {
+		t.Errorf("-1 * 126 = %d, want -126", r)
+	}
+	y = 127
+	r = x * y
+	if r != -127 {
+		t.Errorf("-1 * 127 = %d, want -127", r)
+	}
+	x = 0
+	y = -128
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * -1 = %d, want 0", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 126 = %d, want 0", r)
+	}
+	y = 127
+	r = x * y
+	if r != 0 {
+		t.Errorf("0 * 127 = %d, want 0", r)
+	}
+	x = 1
+	y = -128
+	r = x * y
+	if r != -128 {
+		t.Errorf("1 * -128 = %d, want -128", r)
+	}
+	y = -127
+	r = x * y
+	if r != -127 {
+		t.Errorf("1 * -127 = %d, want -127", r)
+	}
+	y = -1
+	r = x * y
+	if r != -1 {
+		t.Errorf("1 * -1 = %d, want -1", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("1 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 1 {
+		t.Errorf("1 * 1 = %d, want 1", r)
+	}
+	y = 126
+	r = x * y
+	if r != 126 {
+		t.Errorf("1 * 126 = %d, want 126", r)
+	}
+	y = 127
+	r = x * y
+	if r != 127 {
+		t.Errorf("1 * 127 = %d, want 127", r)
+	}
+	x = 126
+	y = -128
+	r = x * y
+	if r != 0 {
+		t.Errorf("126 * -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x * y
+	if r != 126 {
+		t.Errorf("126 * -127 = %d, want 126", r)
+	}
+	y = -1
+	r = x * y
+	if r != -126 {
+		t.Errorf("126 * -1 = %d, want -126", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("126 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 126 {
+		t.Errorf("126 * 1 = %d, want 126", r)
+	}
+	y = 126
+	r = x * y
+	if r != 4 {
+		t.Errorf("126 * 126 = %d, want 4", r)
+	}
+	y = 127
+	r = x * y
+	if r != -126 {
+		t.Errorf("126 * 127 = %d, want -126", r)
+	}
+	x = 127
+	y = -128
+	r = x * y
+	if r != -128 {
+		t.Errorf("127 * -128 = %d, want -128", r)
+	}
+	y = -127
+	r = x * y
+	if r != -1 {
+		t.Errorf("127 * -127 = %d, want -1", r)
+	}
+	y = -1
+	r = x * y
+	if r != -127 {
+		t.Errorf("127 * -1 = %d, want -127", r)
+	}
+	y = 0
+	r = x * y
+	if r != 0 {
+		t.Errorf("127 * 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x * y
+	if r != 127 {
+		t.Errorf("127 * 1 = %d, want 127", r)
+	}
+	y = 126
+	r = x * y
+	if r != -126 {
+		t.Errorf("127 * 126 = %d, want -126", r)
+	}
+	y = 127
+	r = x * y
+	if r != 1 {
+		t.Errorf("127 * 127 = %d, want 1", r)
+	}
+}
+func TestConstFoldint8mod(t *testing.T) {
+	var x, y, r int8
+	x = -128
+	y = -128
+	r = x % y
+	if r != 0 {
+		t.Errorf("-128 % -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x % y
+	if r != -1 {
+		t.Errorf("-128 % -127 = %d, want -1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-128 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-128 % 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x % y
+	if r != -2 {
+		t.Errorf("-128 % 126 = %d, want -2", r)
+	}
+	y = 127
+	r = x % y
+	if r != -1 {
+		t.Errorf("-128 % 127 = %d, want -1", r)
+	}
+	x = -127
+	y = -128
+	r = x % y
+	if r != -127 {
+		t.Errorf("-127 % -128 = %d, want -127", r)
+	}
+	y = -127
+	r = x % y
+	if r != 0 {
+		t.Errorf("-127 % -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-127 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-127 % 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x % y
+	if r != -1 {
+		t.Errorf("-127 % 126 = %d, want -1", r)
+	}
+	y = 127
+	r = x % y
+	if r != 0 {
+		t.Errorf("-127 % 127 = %d, want 0", r)
+	}
+	x = -1
+	y = -128
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % -128 = %d, want -1", r)
+	}
+	y = -127
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % -127 = %d, want -1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-1 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("-1 % 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % 126 = %d, want -1", r)
+	}
+	y = 127
+	r = x % y
+	if r != -1 {
+		t.Errorf("-1 % 127 = %d, want -1", r)
+	}
+	x = 0
+	y = -128
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -128 = %d, want 0", r)
+	}
+	y = -127
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 126 = %d, want 0", r)
+	}
+	y = 127
+	r = x % y
+	if r != 0 {
+		t.Errorf("0 % 127 = %d, want 0", r)
+	}
+	x = 1
+	y = -128
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % -128 = %d, want 1", r)
+	}
+	y = -127
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % -127 = %d, want 1", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("1 % 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 126 = %d, want 1", r)
+	}
+	y = 127
+	r = x % y
+	if r != 1 {
+		t.Errorf("1 % 127 = %d, want 1", r)
+	}
+	x = 126
+	y = -128
+	r = x % y
+	if r != 126 {
+		t.Errorf("126 % -128 = %d, want 126", r)
+	}
+	y = -127
+	r = x % y
+	if r != 126 {
+		t.Errorf("126 % -127 = %d, want 126", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("126 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("126 % 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x % y
+	if r != 0 {
+		t.Errorf("126 % 126 = %d, want 0", r)
+	}
+	y = 127
+	r = x % y
+	if r != 126 {
+		t.Errorf("126 % 127 = %d, want 126", r)
+	}
+	x = 127
+	y = -128
+	r = x % y
+	if r != 127 {
+		t.Errorf("127 % -128 = %d, want 127", r)
+	}
+	y = -127
+	r = x % y
+	if r != 0 {
+		t.Errorf("127 % -127 = %d, want 0", r)
+	}
+	y = -1
+	r = x % y
+	if r != 0 {
+		t.Errorf("127 % -1 = %d, want 0", r)
+	}
+	y = 1
+	r = x % y
+	if r != 0 {
+		t.Errorf("127 % 1 = %d, want 0", r)
+	}
+	y = 126
+	r = x % y
+	if r != 1 {
+		t.Errorf("127 % 126 = %d, want 1", r)
+	}
+	y = 127
+	r = x % y
+	if r != 0 {
+		t.Errorf("127 % 127 = %d, want 0", r)
+	}
+}
+func TestConstFolduint64uint64lsh(t *testing.T) {
+	var x, r uint64
+	var y uint64
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x << y
+	if r != 4294967296 {
+		t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != 8589934592 {
+		t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x << y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x << y
+	if r != 18446744073709551614 {
+		t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("18446744073709551615 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("18446744073709551615 << 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFolduint64uint64rsh(t *testing.T) {
+	var x, r uint64
+	var y uint64
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x >> y
+	if r != 4294967296 {
+		t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483648 {
+		t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x >> y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 9223372036854775807 {
+		t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("18446744073709551615 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("18446744073709551615 >> 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFolduint64uint32lsh(t *testing.T) {
+	var x, r uint64
+	var y uint32
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967295 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x << y
+	if r != 4294967296 {
+		t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != 8589934592 {
+		t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 4294967295 = %d, want 0", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x << y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x << y
+	if r != 18446744073709551614 {
+		t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("18446744073709551615 << 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFolduint64uint32rsh(t *testing.T) {
+	var x, r uint64
+	var y uint32
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967295 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x >> y
+	if r != 4294967296 {
+		t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483648 {
+		t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 4294967295 = %d, want 0", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x >> y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 9223372036854775807 {
+		t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("18446744073709551615 >> 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFolduint64uint16lsh(t *testing.T) {
+	var x, r uint64
+	var y uint16
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 65535 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x << y
+	if r != 4294967296 {
+		t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != 8589934592 {
+		t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 65535 = %d, want 0", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x << y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x << y
+	if r != 18446744073709551614 {
+		t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("18446744073709551615 << 65535 = %d, want 0", r)
+	}
+}
+func TestConstFolduint64uint16rsh(t *testing.T) {
+	var x, r uint64
+	var y uint16
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 65535 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x >> y
+	if r != 4294967296 {
+		t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483648 {
+		t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 65535 = %d, want 0", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x >> y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 9223372036854775807 {
+		t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("18446744073709551615 >> 65535 = %d, want 0", r)
+	}
+}
+func TestConstFolduint64uint8lsh(t *testing.T) {
+	var x, r uint64
+	var y uint8
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 255 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x << y
+	if r != 4294967296 {
+		t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != 8589934592 {
+		t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 255 = %d, want 0", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x << y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x << y
+	if r != 18446744073709551614 {
+		t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("18446744073709551615 << 255 = %d, want 0", r)
+	}
+}
+func TestConstFolduint64uint8rsh(t *testing.T) {
+	var x, r uint64
+	var y uint8
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 255 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x >> y
+	if r != 4294967296 {
+		t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483648 {
+		t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 255 = %d, want 0", r)
+	}
+	x = 18446744073709551615
+	y = 0
+	r = x >> y
+	if r != 18446744073709551615 {
+		t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 9223372036854775807 {
+		t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("18446744073709551615 >> 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64uint64lsh(t *testing.T) {
+	var x, r int64
+	var y uint64
+	x = -9223372036854775808
+	y = 0
+	r = x << y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = -9223372036854775807
+	y = 0
+	r = x << y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = -4294967296
+	y = 0
+	r = x << y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != -8589934592 {
+		t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-4294967296 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-4294967296 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x << y
+	if r != 4294967296 {
+		t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != 8589934592 {
+		t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 9223372036854775806
+	y = 0
+	r = x << y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775806 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775806 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 9223372036854775807
+	y = 0
+	r = x << y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775807 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775807 << 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64uint64rsh(t *testing.T) {
+	var x, r int64
+	var y uint64
+	x = -9223372036854775808
+	y = 0
+	r = x >> y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -4611686018427387904 {
+		t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = -9223372036854775807
+	y = 0
+	r = x >> y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -4611686018427387904 {
+		t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = -4294967296
+	y = 0
+	r = x >> y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -2147483648 {
+		t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-4294967296 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-4294967296 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x >> y
+	if r != 4294967296 {
+		t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483648 {
+		t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 9223372036854775806
+	y = 0
+	r = x >> y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 4611686018427387903 {
+		t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775806 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775806 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 9223372036854775807
+	y = 0
+	r = x >> y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 4611686018427387903 {
+		t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775807 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775807 >> 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64uint32lsh(t *testing.T) {
+	var x, r int64
+	var y uint32
+	x = -9223372036854775808
+	y = 0
+	r = x << y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 << 4294967295 = %d, want 0", r)
+	}
+	x = -9223372036854775807
+	y = 0
+	r = x << y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 << 4294967295 = %d, want 0", r)
+	}
+	x = -4294967296
+	y = 0
+	r = x << y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != -8589934592 {
+		t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-4294967296 << 4294967295 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 4294967295 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967295 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x << y
+	if r != 4294967296 {
+		t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != 8589934592 {
+		t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 4294967295 = %d, want 0", r)
+	}
+	x = 9223372036854775806
+	y = 0
+	r = x << y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775806 << 4294967295 = %d, want 0", r)
+	}
+	x = 9223372036854775807
+	y = 0
+	r = x << y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775807 << 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64uint32rsh(t *testing.T) {
+	var x, r int64
+	var y uint32
+	x = -9223372036854775808
+	y = 0
+	r = x >> y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -4611686018427387904 {
+		t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 >> 4294967295 = %d, want -1", r)
+	}
+	x = -9223372036854775807
+	y = 0
+	r = x >> y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -4611686018427387904 {
+		t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 >> 4294967295 = %d, want -1", r)
+	}
+	x = -4294967296
+	y = 0
+	r = x >> y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -2147483648 {
+		t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-4294967296 >> 4294967295 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967295 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x >> y
+	if r != 4294967296 {
+		t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483648 {
+		t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 4294967295 = %d, want 0", r)
+	}
+	x = 9223372036854775806
+	y = 0
+	r = x >> y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 4611686018427387903 {
+		t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775806 >> 4294967295 = %d, want 0", r)
+	}
+	x = 9223372036854775807
+	y = 0
+	r = x >> y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 4611686018427387903 {
+		t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775807 >> 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64uint16lsh(t *testing.T) {
+	var x, r int64
+	var y uint16
+	x = -9223372036854775808
+	y = 0
+	r = x << y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 << 65535 = %d, want 0", r)
+	}
+	x = -9223372036854775807
+	y = 0
+	r = x << y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 << 65535 = %d, want 0", r)
+	}
+	x = -4294967296
+	y = 0
+	r = x << y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != -8589934592 {
+		t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-4294967296 << 65535 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 65535 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 65535 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x << y
+	if r != 4294967296 {
+		t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != 8589934592 {
+		t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 65535 = %d, want 0", r)
+	}
+	x = 9223372036854775806
+	y = 0
+	r = x << y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775806 << 65535 = %d, want 0", r)
+	}
+	x = 9223372036854775807
+	y = 0
+	r = x << y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775807 << 65535 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64uint16rsh(t *testing.T) {
+	var x, r int64
+	var y uint16
+	x = -9223372036854775808
+	y = 0
+	r = x >> y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -4611686018427387904 {
+		t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 >> 65535 = %d, want -1", r)
+	}
+	x = -9223372036854775807
+	y = 0
+	r = x >> y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -4611686018427387904 {
+		t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 >> 65535 = %d, want -1", r)
+	}
+	x = -4294967296
+	y = 0
+	r = x >> y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -2147483648 {
+		t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-4294967296 >> 65535 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 65535 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 65535 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x >> y
+	if r != 4294967296 {
+		t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483648 {
+		t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 65535 = %d, want 0", r)
+	}
+	x = 9223372036854775806
+	y = 0
+	r = x >> y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 4611686018427387903 {
+		t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775806 >> 65535 = %d, want 0", r)
+	}
+	x = 9223372036854775807
+	y = 0
+	r = x >> y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 4611686018427387903 {
+		t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775807 >> 65535 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64uint8lsh(t *testing.T) {
+	var x, r int64
+	var y uint8
+	x = -9223372036854775808
+	y = 0
+	r = x << y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775808 << 255 = %d, want 0", r)
+	}
+	x = -9223372036854775807
+	y = 0
+	r = x << y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-9223372036854775807 << 255 = %d, want 0", r)
+	}
+	x = -4294967296
+	y = 0
+	r = x << y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != -8589934592 {
+		t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-4294967296 << 255 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 255 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 255 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x << y
+	if r != 4294967296 {
+		t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x << y
+	if r != 8589934592 {
+		t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967296 << 255 = %d, want 0", r)
+	}
+	x = 9223372036854775806
+	y = 0
+	r = x << y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775806 << 255 = %d, want 0", r)
+	}
+	x = 9223372036854775807
+	y = 0
+	r = x << y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("9223372036854775807 << 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldint64uint8rsh(t *testing.T) {
+	var x, r int64
+	var y uint8
+	x = -9223372036854775808
+	y = 0
+	r = x >> y
+	if r != -9223372036854775808 {
+		t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -4611686018427387904 {
+		t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775808 >> 255 = %d, want -1", r)
+	}
+	x = -9223372036854775807
+	y = 0
+	r = x >> y
+	if r != -9223372036854775807 {
+		t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -4611686018427387904 {
+		t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-9223372036854775807 >> 255 = %d, want -1", r)
+	}
+	x = -4294967296
+	y = 0
+	r = x >> y
+	if r != -4294967296 {
+		t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -2147483648 {
+		t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-4294967296 >> 255 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 255 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 255 = %d, want 0", r)
+	}
+	x = 4294967296
+	y = 0
+	r = x >> y
+	if r != 4294967296 {
+		t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483648 {
+		t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967296 >> 255 = %d, want 0", r)
+	}
+	x = 9223372036854775806
+	y = 0
+	r = x >> y
+	if r != 9223372036854775806 {
+		t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 4611686018427387903 {
+		t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775806 >> 255 = %d, want 0", r)
+	}
+	x = 9223372036854775807
+	y = 0
+	r = x >> y
+	if r != 9223372036854775807 {
+		t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 4611686018427387903 {
+		t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("9223372036854775807 >> 255 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32uint64lsh(t *testing.T) {
+	var x, r uint32
+	var y uint64
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x << y
+	if r != 4294967295 {
+		t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x << y
+	if r != 4294967294 {
+		t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967295 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967295 << 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32uint64rsh(t *testing.T) {
+	var x, r uint32
+	var y uint64
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x >> y
+	if r != 4294967295 {
+		t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483647 {
+		t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967295 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967295 >> 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32uint32lsh(t *testing.T) {
+	var x, r uint32
+	var y uint32
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967295 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x << y
+	if r != 4294967295 {
+		t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x << y
+	if r != 4294967294 {
+		t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967295 << 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32uint32rsh(t *testing.T) {
+	var x, r uint32
+	var y uint32
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967295 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x >> y
+	if r != 4294967295 {
+		t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483647 {
+		t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967295 >> 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32uint16lsh(t *testing.T) {
+	var x, r uint32
+	var y uint16
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 65535 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x << y
+	if r != 4294967295 {
+		t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x << y
+	if r != 4294967294 {
+		t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967295 << 65535 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32uint16rsh(t *testing.T) {
+	var x, r uint32
+	var y uint16
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 65535 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x >> y
+	if r != 4294967295 {
+		t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483647 {
+		t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967295 >> 65535 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32uint8lsh(t *testing.T) {
+	var x, r uint32
+	var y uint8
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 255 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x << y
+	if r != 4294967295 {
+		t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x << y
+	if r != 4294967294 {
+		t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("4294967295 << 255 = %d, want 0", r)
+	}
+}
+func TestConstFolduint32uint8rsh(t *testing.T) {
+	var x, r uint32
+	var y uint8
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 255 = %d, want 0", r)
+	}
+	x = 4294967295
+	y = 0
+	r = x >> y
+	if r != 4294967295 {
+		t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 2147483647 {
+		t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("4294967295 >> 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32uint64lsh(t *testing.T) {
+	var x, r int32
+	var y uint64
+	x = -2147483648
+	y = 0
+	r = x << y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483648 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483648 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483648 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = -2147483647
+	y = 0
+	r = x << y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-2147483647 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483647 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483647 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 2147483647
+	y = 0
+	r = x << y
+	if r != 2147483647 {
+		t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("2147483647 << 1 = %d, want -2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("2147483647 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("2147483647 << 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32uint64rsh(t *testing.T) {
+	var x, r int32
+	var y uint64
+	x = -2147483648
+	y = 0
+	r = x >> y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1073741824 {
+		t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483648 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483648 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = -2147483647
+	y = 0
+	r = x >> y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1073741824 {
+		t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483647 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483647 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 2147483647
+	y = 0
+	r = x >> y
+	if r != 2147483647 {
+		t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 1073741823 {
+		t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("2147483647 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("2147483647 >> 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32uint32lsh(t *testing.T) {
+	var x, r int32
+	var y uint32
+	x = -2147483648
+	y = 0
+	r = x << y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483648 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483648 << 4294967295 = %d, want 0", r)
+	}
+	x = -2147483647
+	y = 0
+	r = x << y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-2147483647 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483647 << 4294967295 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 4294967295 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967295 = %d, want 0", r)
+	}
+	x = 2147483647
+	y = 0
+	r = x << y
+	if r != 2147483647 {
+		t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("2147483647 << 1 = %d, want -2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("2147483647 << 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32uint32rsh(t *testing.T) {
+	var x, r int32
+	var y uint32
+	x = -2147483648
+	y = 0
+	r = x >> y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1073741824 {
+		t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483648 >> 4294967295 = %d, want -1", r)
+	}
+	x = -2147483647
+	y = 0
+	r = x >> y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1073741824 {
+		t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483647 >> 4294967295 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967295 = %d, want 0", r)
+	}
+	x = 2147483647
+	y = 0
+	r = x >> y
+	if r != 2147483647 {
+		t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 1073741823 {
+		t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("2147483647 >> 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32uint16lsh(t *testing.T) {
+	var x, r int32
+	var y uint16
+	x = -2147483648
+	y = 0
+	r = x << y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483648 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483648 << 65535 = %d, want 0", r)
+	}
+	x = -2147483647
+	y = 0
+	r = x << y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-2147483647 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483647 << 65535 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 65535 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 65535 = %d, want 0", r)
+	}
+	x = 2147483647
+	y = 0
+	r = x << y
+	if r != 2147483647 {
+		t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("2147483647 << 1 = %d, want -2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("2147483647 << 65535 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32uint16rsh(t *testing.T) {
+	var x, r int32
+	var y uint16
+	x = -2147483648
+	y = 0
+	r = x >> y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1073741824 {
+		t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483648 >> 65535 = %d, want -1", r)
+	}
+	x = -2147483647
+	y = 0
+	r = x >> y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1073741824 {
+		t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483647 >> 65535 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 65535 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 65535 = %d, want 0", r)
+	}
+	x = 2147483647
+	y = 0
+	r = x >> y
+	if r != 2147483647 {
+		t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 1073741823 {
+		t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("2147483647 >> 65535 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32uint8lsh(t *testing.T) {
+	var x, r int32
+	var y uint8
+	x = -2147483648
+	y = 0
+	r = x << y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483648 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483648 << 255 = %d, want 0", r)
+	}
+	x = -2147483647
+	y = 0
+	r = x << y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-2147483647 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-2147483647 << 255 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 255 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 255 = %d, want 0", r)
+	}
+	x = 2147483647
+	y = 0
+	r = x << y
+	if r != 2147483647 {
+		t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("2147483647 << 1 = %d, want -2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("2147483647 << 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldint32uint8rsh(t *testing.T) {
+	var x, r int32
+	var y uint8
+	x = -2147483648
+	y = 0
+	r = x >> y
+	if r != -2147483648 {
+		t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1073741824 {
+		t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483648 >> 255 = %d, want -1", r)
+	}
+	x = -2147483647
+	y = 0
+	r = x >> y
+	if r != -2147483647 {
+		t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1073741824 {
+		t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-2147483647 >> 255 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 255 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 255 = %d, want 0", r)
+	}
+	x = 2147483647
+	y = 0
+	r = x >> y
+	if r != 2147483647 {
+		t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 1073741823 {
+		t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("2147483647 >> 255 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16uint64lsh(t *testing.T) {
+	var x, r uint16
+	var y uint64
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 65535
+	y = 0
+	r = x << y
+	if r != 65535 {
+		t.Errorf("65535 << 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x << y
+	if r != 65534 {
+		t.Errorf("65535 << 1 = %d, want 65534", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("65535 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("65535 << 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16uint64rsh(t *testing.T) {
+	var x, r uint16
+	var y uint64
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 65535
+	y = 0
+	r = x >> y
+	if r != 65535 {
+		t.Errorf("65535 >> 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 32767 {
+		t.Errorf("65535 >> 1 = %d, want 32767", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("65535 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("65535 >> 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16uint32lsh(t *testing.T) {
+	var x, r uint16
+	var y uint32
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967295 = %d, want 0", r)
+	}
+	x = 65535
+	y = 0
+	r = x << y
+	if r != 65535 {
+		t.Errorf("65535 << 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x << y
+	if r != 65534 {
+		t.Errorf("65535 << 1 = %d, want 65534", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("65535 << 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16uint32rsh(t *testing.T) {
+	var x, r uint16
+	var y uint32
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967295 = %d, want 0", r)
+	}
+	x = 65535
+	y = 0
+	r = x >> y
+	if r != 65535 {
+		t.Errorf("65535 >> 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 32767 {
+		t.Errorf("65535 >> 1 = %d, want 32767", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("65535 >> 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16uint16lsh(t *testing.T) {
+	var x, r uint16
+	var y uint16
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 65535 = %d, want 0", r)
+	}
+	x = 65535
+	y = 0
+	r = x << y
+	if r != 65535 {
+		t.Errorf("65535 << 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x << y
+	if r != 65534 {
+		t.Errorf("65535 << 1 = %d, want 65534", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("65535 << 65535 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16uint16rsh(t *testing.T) {
+	var x, r uint16
+	var y uint16
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 65535 = %d, want 0", r)
+	}
+	x = 65535
+	y = 0
+	r = x >> y
+	if r != 65535 {
+		t.Errorf("65535 >> 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 32767 {
+		t.Errorf("65535 >> 1 = %d, want 32767", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("65535 >> 65535 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16uint8lsh(t *testing.T) {
+	var x, r uint16
+	var y uint8
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 255 = %d, want 0", r)
+	}
+	x = 65535
+	y = 0
+	r = x << y
+	if r != 65535 {
+		t.Errorf("65535 << 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x << y
+	if r != 65534 {
+		t.Errorf("65535 << 1 = %d, want 65534", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("65535 << 255 = %d, want 0", r)
+	}
+}
+func TestConstFolduint16uint8rsh(t *testing.T) {
+	var x, r uint16
+	var y uint8
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 255 = %d, want 0", r)
+	}
+	x = 65535
+	y = 0
+	r = x >> y
+	if r != 65535 {
+		t.Errorf("65535 >> 0 = %d, want 65535", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 32767 {
+		t.Errorf("65535 >> 1 = %d, want 32767", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("65535 >> 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16uint64lsh(t *testing.T) {
+	var x, r int16
+	var y uint64
+	x = -32768
+	y = 0
+	r = x << y
+	if r != -32768 {
+		t.Errorf("-32768 << 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32768 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32768 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32768 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = -32767
+	y = 0
+	r = x << y
+	if r != -32767 {
+		t.Errorf("-32767 << 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-32767 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32767 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32767 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 32766
+	y = 0
+	r = x << y
+	if r != 32766 {
+		t.Errorf("32766 << 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("32766 << 1 = %d, want -4", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("32766 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("32766 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 32767
+	y = 0
+	r = x << y
+	if r != 32767 {
+		t.Errorf("32767 << 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("32767 << 1 = %d, want -2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("32767 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("32767 << 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16uint64rsh(t *testing.T) {
+	var x, r int16
+	var y uint64
+	x = -32768
+	y = 0
+	r = x >> y
+	if r != -32768 {
+		t.Errorf("-32768 >> 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -16384 {
+		t.Errorf("-32768 >> 1 = %d, want -16384", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32768 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32768 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = -32767
+	y = 0
+	r = x >> y
+	if r != -32767 {
+		t.Errorf("-32767 >> 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -16384 {
+		t.Errorf("-32767 >> 1 = %d, want -16384", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32767 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32767 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 32766
+	y = 0
+	r = x >> y
+	if r != 32766 {
+		t.Errorf("32766 >> 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 16383 {
+		t.Errorf("32766 >> 1 = %d, want 16383", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32766 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32766 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 32767
+	y = 0
+	r = x >> y
+	if r != 32767 {
+		t.Errorf("32767 >> 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 16383 {
+		t.Errorf("32767 >> 1 = %d, want 16383", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32767 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32767 >> 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16uint32lsh(t *testing.T) {
+	var x, r int16
+	var y uint32
+	x = -32768
+	y = 0
+	r = x << y
+	if r != -32768 {
+		t.Errorf("-32768 << 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32768 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32768 << 4294967295 = %d, want 0", r)
+	}
+	x = -32767
+	y = 0
+	r = x << y
+	if r != -32767 {
+		t.Errorf("-32767 << 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-32767 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32767 << 4294967295 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 4294967295 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967295 = %d, want 0", r)
+	}
+	x = 32766
+	y = 0
+	r = x << y
+	if r != 32766 {
+		t.Errorf("32766 << 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("32766 << 1 = %d, want -4", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("32766 << 4294967295 = %d, want 0", r)
+	}
+	x = 32767
+	y = 0
+	r = x << y
+	if r != 32767 {
+		t.Errorf("32767 << 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("32767 << 1 = %d, want -2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("32767 << 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16uint32rsh(t *testing.T) {
+	var x, r int16
+	var y uint32
+	x = -32768
+	y = 0
+	r = x >> y
+	if r != -32768 {
+		t.Errorf("-32768 >> 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -16384 {
+		t.Errorf("-32768 >> 1 = %d, want -16384", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32768 >> 4294967295 = %d, want -1", r)
+	}
+	x = -32767
+	y = 0
+	r = x >> y
+	if r != -32767 {
+		t.Errorf("-32767 >> 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -16384 {
+		t.Errorf("-32767 >> 1 = %d, want -16384", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32767 >> 4294967295 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967295 = %d, want 0", r)
+	}
+	x = 32766
+	y = 0
+	r = x >> y
+	if r != 32766 {
+		t.Errorf("32766 >> 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 16383 {
+		t.Errorf("32766 >> 1 = %d, want 16383", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32766 >> 4294967295 = %d, want 0", r)
+	}
+	x = 32767
+	y = 0
+	r = x >> y
+	if r != 32767 {
+		t.Errorf("32767 >> 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 16383 {
+		t.Errorf("32767 >> 1 = %d, want 16383", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32767 >> 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16uint16lsh(t *testing.T) {
+	var x, r int16
+	var y uint16
+	x = -32768
+	y = 0
+	r = x << y
+	if r != -32768 {
+		t.Errorf("-32768 << 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32768 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32768 << 65535 = %d, want 0", r)
+	}
+	x = -32767
+	y = 0
+	r = x << y
+	if r != -32767 {
+		t.Errorf("-32767 << 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-32767 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32767 << 65535 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 65535 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 65535 = %d, want 0", r)
+	}
+	x = 32766
+	y = 0
+	r = x << y
+	if r != 32766 {
+		t.Errorf("32766 << 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("32766 << 1 = %d, want -4", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("32766 << 65535 = %d, want 0", r)
+	}
+	x = 32767
+	y = 0
+	r = x << y
+	if r != 32767 {
+		t.Errorf("32767 << 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("32767 << 1 = %d, want -2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("32767 << 65535 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16uint16rsh(t *testing.T) {
+	var x, r int16
+	var y uint16
+	x = -32768
+	y = 0
+	r = x >> y
+	if r != -32768 {
+		t.Errorf("-32768 >> 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -16384 {
+		t.Errorf("-32768 >> 1 = %d, want -16384", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32768 >> 65535 = %d, want -1", r)
+	}
+	x = -32767
+	y = 0
+	r = x >> y
+	if r != -32767 {
+		t.Errorf("-32767 >> 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -16384 {
+		t.Errorf("-32767 >> 1 = %d, want -16384", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32767 >> 65535 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 65535 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 65535 = %d, want 0", r)
+	}
+	x = 32766
+	y = 0
+	r = x >> y
+	if r != 32766 {
+		t.Errorf("32766 >> 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 16383 {
+		t.Errorf("32766 >> 1 = %d, want 16383", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32766 >> 65535 = %d, want 0", r)
+	}
+	x = 32767
+	y = 0
+	r = x >> y
+	if r != 32767 {
+		t.Errorf("32767 >> 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 16383 {
+		t.Errorf("32767 >> 1 = %d, want 16383", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32767 >> 65535 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16uint8lsh(t *testing.T) {
+	var x, r int16
+	var y uint8
+	x = -32768
+	y = 0
+	r = x << y
+	if r != -32768 {
+		t.Errorf("-32768 << 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32768 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32768 << 255 = %d, want 0", r)
+	}
+	x = -32767
+	y = 0
+	r = x << y
+	if r != -32767 {
+		t.Errorf("-32767 << 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-32767 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-32767 << 255 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 255 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 255 = %d, want 0", r)
+	}
+	x = 32766
+	y = 0
+	r = x << y
+	if r != 32766 {
+		t.Errorf("32766 << 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("32766 << 1 = %d, want -4", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("32766 << 255 = %d, want 0", r)
+	}
+	x = 32767
+	y = 0
+	r = x << y
+	if r != 32767 {
+		t.Errorf("32767 << 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("32767 << 1 = %d, want -2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("32767 << 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldint16uint8rsh(t *testing.T) {
+	var x, r int16
+	var y uint8
+	x = -32768
+	y = 0
+	r = x >> y
+	if r != -32768 {
+		t.Errorf("-32768 >> 0 = %d, want -32768", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -16384 {
+		t.Errorf("-32768 >> 1 = %d, want -16384", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32768 >> 255 = %d, want -1", r)
+	}
+	x = -32767
+	y = 0
+	r = x >> y
+	if r != -32767 {
+		t.Errorf("-32767 >> 0 = %d, want -32767", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -16384 {
+		t.Errorf("-32767 >> 1 = %d, want -16384", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-32767 >> 255 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 255 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 255 = %d, want 0", r)
+	}
+	x = 32766
+	y = 0
+	r = x >> y
+	if r != 32766 {
+		t.Errorf("32766 >> 0 = %d, want 32766", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 16383 {
+		t.Errorf("32766 >> 1 = %d, want 16383", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32766 >> 255 = %d, want 0", r)
+	}
+	x = 32767
+	y = 0
+	r = x >> y
+	if r != 32767 {
+		t.Errorf("32767 >> 0 = %d, want 32767", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 16383 {
+		t.Errorf("32767 >> 1 = %d, want 16383", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("32767 >> 255 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8uint64lsh(t *testing.T) {
+	var x, r uint8
+	var y uint64
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 255
+	y = 0
+	r = x << y
+	if r != 255 {
+		t.Errorf("255 << 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x << y
+	if r != 254 {
+		t.Errorf("255 << 1 = %d, want 254", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("255 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("255 << 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8uint64rsh(t *testing.T) {
+	var x, r uint8
+	var y uint64
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 255
+	y = 0
+	r = x >> y
+	if r != 255 {
+		t.Errorf("255 >> 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 127 {
+		t.Errorf("255 >> 1 = %d, want 127", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("255 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("255 >> 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8uint32lsh(t *testing.T) {
+	var x, r uint8
+	var y uint32
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967295 = %d, want 0", r)
+	}
+	x = 255
+	y = 0
+	r = x << y
+	if r != 255 {
+		t.Errorf("255 << 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x << y
+	if r != 254 {
+		t.Errorf("255 << 1 = %d, want 254", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("255 << 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8uint32rsh(t *testing.T) {
+	var x, r uint8
+	var y uint32
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967295 = %d, want 0", r)
+	}
+	x = 255
+	y = 0
+	r = x >> y
+	if r != 255 {
+		t.Errorf("255 >> 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 127 {
+		t.Errorf("255 >> 1 = %d, want 127", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("255 >> 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8uint16lsh(t *testing.T) {
+	var x, r uint8
+	var y uint16
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 65535 = %d, want 0", r)
+	}
+	x = 255
+	y = 0
+	r = x << y
+	if r != 255 {
+		t.Errorf("255 << 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x << y
+	if r != 254 {
+		t.Errorf("255 << 1 = %d, want 254", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("255 << 65535 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8uint16rsh(t *testing.T) {
+	var x, r uint8
+	var y uint16
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 65535 = %d, want 0", r)
+	}
+	x = 255
+	y = 0
+	r = x >> y
+	if r != 255 {
+		t.Errorf("255 >> 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 127 {
+		t.Errorf("255 >> 1 = %d, want 127", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("255 >> 65535 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8uint8lsh(t *testing.T) {
+	var x, r uint8
+	var y uint8
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 255 = %d, want 0", r)
+	}
+	x = 255
+	y = 0
+	r = x << y
+	if r != 255 {
+		t.Errorf("255 << 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x << y
+	if r != 254 {
+		t.Errorf("255 << 1 = %d, want 254", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("255 << 255 = %d, want 0", r)
+	}
+}
+func TestConstFolduint8uint8rsh(t *testing.T) {
+	var x, r uint8
+	var y uint8
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 255 = %d, want 0", r)
+	}
+	x = 255
+	y = 0
+	r = x >> y
+	if r != 255 {
+		t.Errorf("255 >> 0 = %d, want 255", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 127 {
+		t.Errorf("255 >> 1 = %d, want 127", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("255 >> 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8uint64lsh(t *testing.T) {
+	var x, r int8
+	var y uint64
+	x = -128
+	y = 0
+	r = x << y
+	if r != -128 {
+		t.Errorf("-128 << 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-128 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-128 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-128 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = -127
+	y = 0
+	r = x << y
+	if r != -127 {
+		t.Errorf("-127 << 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-127 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-127 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-127 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 126
+	y = 0
+	r = x << y
+	if r != 126 {
+		t.Errorf("126 << 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("126 << 1 = %d, want -4", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("126 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("126 << 18446744073709551615 = %d, want 0", r)
+	}
+	x = 127
+	y = 0
+	r = x << y
+	if r != 127 {
+		t.Errorf("127 << 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("127 << 1 = %d, want -2", r)
+	}
+	y = 4294967296
+	r = x << y
+	if r != 0 {
+		t.Errorf("127 << 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x << y
+	if r != 0 {
+		t.Errorf("127 << 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8uint64rsh(t *testing.T) {
+	var x, r int8
+	var y uint64
+	x = -128
+	y = 0
+	r = x >> y
+	if r != -128 {
+		t.Errorf("-128 >> 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -64 {
+		t.Errorf("-128 >> 1 = %d, want -64", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-128 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-128 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = -127
+	y = 0
+	r = x >> y
+	if r != -127 {
+		t.Errorf("-127 >> 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -64 {
+		t.Errorf("-127 >> 1 = %d, want -64", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-127 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-127 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 126
+	y = 0
+	r = x >> y
+	if r != 126 {
+		t.Errorf("126 >> 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 63 {
+		t.Errorf("126 >> 1 = %d, want 63", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("126 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("126 >> 18446744073709551615 = %d, want 0", r)
+	}
+	x = 127
+	y = 0
+	r = x >> y
+	if r != 127 {
+		t.Errorf("127 >> 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 63 {
+		t.Errorf("127 >> 1 = %d, want 63", r)
+	}
+	y = 4294967296
+	r = x >> y
+	if r != 0 {
+		t.Errorf("127 >> 4294967296 = %d, want 0", r)
+	}
+	y = 18446744073709551615
+	r = x >> y
+	if r != 0 {
+		t.Errorf("127 >> 18446744073709551615 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8uint32lsh(t *testing.T) {
+	var x, r int8
+	var y uint32
+	x = -128
+	y = 0
+	r = x << y
+	if r != -128 {
+		t.Errorf("-128 << 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-128 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-128 << 4294967295 = %d, want 0", r)
+	}
+	x = -127
+	y = 0
+	r = x << y
+	if r != -127 {
+		t.Errorf("-127 << 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-127 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-127 << 4294967295 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 4294967295 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 4294967295 = %d, want 0", r)
+	}
+	x = 126
+	y = 0
+	r = x << y
+	if r != 126 {
+		t.Errorf("126 << 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("126 << 1 = %d, want -4", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("126 << 4294967295 = %d, want 0", r)
+	}
+	x = 127
+	y = 0
+	r = x << y
+	if r != 127 {
+		t.Errorf("127 << 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("127 << 1 = %d, want -2", r)
+	}
+	y = 4294967295
+	r = x << y
+	if r != 0 {
+		t.Errorf("127 << 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8uint32rsh(t *testing.T) {
+	var x, r int8
+	var y uint32
+	x = -128
+	y = 0
+	r = x >> y
+	if r != -128 {
+		t.Errorf("-128 >> 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -64 {
+		t.Errorf("-128 >> 1 = %d, want -64", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-128 >> 4294967295 = %d, want -1", r)
+	}
+	x = -127
+	y = 0
+	r = x >> y
+	if r != -127 {
+		t.Errorf("-127 >> 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -64 {
+		t.Errorf("-127 >> 1 = %d, want -64", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-127 >> 4294967295 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 4294967295 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 4294967295 = %d, want 0", r)
+	}
+	x = 126
+	y = 0
+	r = x >> y
+	if r != 126 {
+		t.Errorf("126 >> 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 63 {
+		t.Errorf("126 >> 1 = %d, want 63", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("126 >> 4294967295 = %d, want 0", r)
+	}
+	x = 127
+	y = 0
+	r = x >> y
+	if r != 127 {
+		t.Errorf("127 >> 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 63 {
+		t.Errorf("127 >> 1 = %d, want 63", r)
+	}
+	y = 4294967295
+	r = x >> y
+	if r != 0 {
+		t.Errorf("127 >> 4294967295 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8uint16lsh(t *testing.T) {
+	var x, r int8
+	var y uint16
+	x = -128
+	y = 0
+	r = x << y
+	if r != -128 {
+		t.Errorf("-128 << 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-128 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-128 << 65535 = %d, want 0", r)
+	}
+	x = -127
+	y = 0
+	r = x << y
+	if r != -127 {
+		t.Errorf("-127 << 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-127 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-127 << 65535 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 65535 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 65535 = %d, want 0", r)
+	}
+	x = 126
+	y = 0
+	r = x << y
+	if r != 126 {
+		t.Errorf("126 << 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("126 << 1 = %d, want -4", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("126 << 65535 = %d, want 0", r)
+	}
+	x = 127
+	y = 0
+	r = x << y
+	if r != 127 {
+		t.Errorf("127 << 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("127 << 1 = %d, want -2", r)
+	}
+	y = 65535
+	r = x << y
+	if r != 0 {
+		t.Errorf("127 << 65535 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8uint16rsh(t *testing.T) {
+	var x, r int8
+	var y uint16
+	x = -128
+	y = 0
+	r = x >> y
+	if r != -128 {
+		t.Errorf("-128 >> 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -64 {
+		t.Errorf("-128 >> 1 = %d, want -64", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-128 >> 65535 = %d, want -1", r)
+	}
+	x = -127
+	y = 0
+	r = x >> y
+	if r != -127 {
+		t.Errorf("-127 >> 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -64 {
+		t.Errorf("-127 >> 1 = %d, want -64", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-127 >> 65535 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 65535 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 65535 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 65535 = %d, want 0", r)
+	}
+	x = 126
+	y = 0
+	r = x >> y
+	if r != 126 {
+		t.Errorf("126 >> 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 63 {
+		t.Errorf("126 >> 1 = %d, want 63", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("126 >> 65535 = %d, want 0", r)
+	}
+	x = 127
+	y = 0
+	r = x >> y
+	if r != 127 {
+		t.Errorf("127 >> 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 63 {
+		t.Errorf("127 >> 1 = %d, want 63", r)
+	}
+	y = 65535
+	r = x >> y
+	if r != 0 {
+		t.Errorf("127 >> 65535 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8uint8lsh(t *testing.T) {
+	var x, r int8
+	var y uint8
+	x = -128
+	y = 0
+	r = x << y
+	if r != -128 {
+		t.Errorf("-128 << 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("-128 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-128 << 255 = %d, want 0", r)
+	}
+	x = -127
+	y = 0
+	r = x << y
+	if r != -127 {
+		t.Errorf("-127 << 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("-127 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-127 << 255 = %d, want 0", r)
+	}
+	x = -1
+	y = 0
+	r = x << y
+	if r != -1 {
+		t.Errorf("-1 << 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("-1 << 1 = %d, want -2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("-1 << 255 = %d, want 0", r)
+	}
+	x = 0
+	y = 0
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("0 << 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x << y
+	if r != 1 {
+		t.Errorf("1 << 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x << y
+	if r != 2 {
+		t.Errorf("1 << 1 = %d, want 2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("1 << 255 = %d, want 0", r)
+	}
+	x = 126
+	y = 0
+	r = x << y
+	if r != 126 {
+		t.Errorf("126 << 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x << y
+	if r != -4 {
+		t.Errorf("126 << 1 = %d, want -4", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("126 << 255 = %d, want 0", r)
+	}
+	x = 127
+	y = 0
+	r = x << y
+	if r != 127 {
+		t.Errorf("127 << 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x << y
+	if r != -2 {
+		t.Errorf("127 << 1 = %d, want -2", r)
+	}
+	y = 255
+	r = x << y
+	if r != 0 {
+		t.Errorf("127 << 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldint8uint8rsh(t *testing.T) {
+	var x, r int8
+	var y uint8
+	x = -128
+	y = 0
+	r = x >> y
+	if r != -128 {
+		t.Errorf("-128 >> 0 = %d, want -128", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -64 {
+		t.Errorf("-128 >> 1 = %d, want -64", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-128 >> 255 = %d, want -1", r)
+	}
+	x = -127
+	y = 0
+	r = x >> y
+	if r != -127 {
+		t.Errorf("-127 >> 0 = %d, want -127", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -64 {
+		t.Errorf("-127 >> 1 = %d, want -64", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-127 >> 255 = %d, want -1", r)
+	}
+	x = -1
+	y = 0
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 0 = %d, want -1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 1 = %d, want -1", r)
+	}
+	y = 255
+	r = x >> y
+	if r != -1 {
+		t.Errorf("-1 >> 255 = %d, want -1", r)
+	}
+	x = 0
+	y = 0
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 0 = %d, want 0", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("0 >> 255 = %d, want 0", r)
+	}
+	x = 1
+	y = 0
+	r = x >> y
+	if r != 1 {
+		t.Errorf("1 >> 0 = %d, want 1", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 1 = %d, want 0", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("1 >> 255 = %d, want 0", r)
+	}
+	x = 126
+	y = 0
+	r = x >> y
+	if r != 126 {
+		t.Errorf("126 >> 0 = %d, want 126", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 63 {
+		t.Errorf("126 >> 1 = %d, want 63", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("126 >> 255 = %d, want 0", r)
+	}
+	x = 127
+	y = 0
+	r = x >> y
+	if r != 127 {
+		t.Errorf("127 >> 0 = %d, want 127", r)
+	}
+	y = 1
+	r = x >> y
+	if r != 63 {
+		t.Errorf("127 >> 1 = %d, want 63", r)
+	}
+	y = 255
+	r = x >> y
+	if r != 0 {
+		t.Errorf("127 >> 255 = %d, want 0", r)
+	}
+}
+func TestConstFoldCompareuint64(t *testing.T) {
+	{
+		var x uint64 = 0
+		var y uint64 = 0
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint64 = 0
+		var y uint64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint64 = 0
+		var y uint64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint64 = 0
+		var y uint64 = 18446744073709551615
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint64 = 1
+		var y uint64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint64 = 1
+		var y uint64 = 1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint64 = 1
+		var y uint64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint64 = 1
+		var y uint64 = 18446744073709551615
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint64 = 4294967296
+		var y uint64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint64 = 4294967296
+		var y uint64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint64 = 4294967296
+		var y uint64 = 4294967296
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint64 = 4294967296
+		var y uint64 = 18446744073709551615
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint64 = 18446744073709551615
+		var y uint64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint64 = 18446744073709551615
+		var y uint64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint64 = 18446744073709551615
+		var y uint64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint64 = 18446744073709551615
+		var y uint64 = 18446744073709551615
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+}
+func TestConstFoldCompareint64(t *testing.T) {
+	{
+		var x int64 = -9223372036854775808
+		var y int64 = -9223372036854775808
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775808
+		var y int64 = -9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775808
+		var y int64 = -4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775808
+		var y int64 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775808
+		var y int64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775808
+		var y int64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775808
+		var y int64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775808
+		var y int64 = 9223372036854775806
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775808
+		var y int64 = 9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775807
+		var y int64 = -9223372036854775808
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775807
+		var y int64 = -9223372036854775807
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775807
+		var y int64 = -4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775807
+		var y int64 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775807
+		var y int64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775807
+		var y int64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775807
+		var y int64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775807
+		var y int64 = 9223372036854775806
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -9223372036854775807
+		var y int64 = 9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -4294967296
+		var y int64 = -9223372036854775808
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -4294967296
+		var y int64 = -9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -4294967296
+		var y int64 = -4294967296
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -4294967296
+		var y int64 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -4294967296
+		var y int64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -4294967296
+		var y int64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -4294967296
+		var y int64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -4294967296
+		var y int64 = 9223372036854775806
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -4294967296
+		var y int64 = 9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -1
+		var y int64 = -9223372036854775808
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -1
+		var y int64 = -9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -1
+		var y int64 = -4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -1
+		var y int64 = -1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = -1
+		var y int64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -1
+		var y int64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -1
+		var y int64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -1
+		var y int64 = 9223372036854775806
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = -1
+		var y int64 = 9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 0
+		var y int64 = -9223372036854775808
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 0
+		var y int64 = -9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 0
+		var y int64 = -4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 0
+		var y int64 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 0
+		var y int64 = 0
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 0
+		var y int64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 0
+		var y int64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 0
+		var y int64 = 9223372036854775806
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 0
+		var y int64 = 9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 1
+		var y int64 = -9223372036854775808
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 1
+		var y int64 = -9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 1
+		var y int64 = -4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 1
+		var y int64 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 1
+		var y int64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 1
+		var y int64 = 1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 1
+		var y int64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 1
+		var y int64 = 9223372036854775806
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 1
+		var y int64 = 9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 4294967296
+		var y int64 = -9223372036854775808
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 4294967296
+		var y int64 = -9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 4294967296
+		var y int64 = -4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 4294967296
+		var y int64 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 4294967296
+		var y int64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 4294967296
+		var y int64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 4294967296
+		var y int64 = 4294967296
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 4294967296
+		var y int64 = 9223372036854775806
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 4294967296
+		var y int64 = 9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775806
+		var y int64 = -9223372036854775808
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775806
+		var y int64 = -9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775806
+		var y int64 = -4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775806
+		var y int64 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775806
+		var y int64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775806
+		var y int64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775806
+		var y int64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775806
+		var y int64 = 9223372036854775806
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775806
+		var y int64 = 9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775807
+		var y int64 = -9223372036854775808
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775807
+		var y int64 = -9223372036854775807
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775807
+		var y int64 = -4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775807
+		var y int64 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775807
+		var y int64 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775807
+		var y int64 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775807
+		var y int64 = 4294967296
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775807
+		var y int64 = 9223372036854775806
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int64 = 9223372036854775807
+		var y int64 = 9223372036854775807
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+}
+func TestConstFoldCompareuint32(t *testing.T) {
+	{
+		var x uint32 = 0
+		var y uint32 = 0
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint32 = 0
+		var y uint32 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint32 = 0
+		var y uint32 = 4294967295
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint32 = 1
+		var y uint32 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint32 = 1
+		var y uint32 = 1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint32 = 1
+		var y uint32 = 4294967295
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint32 = 4294967295
+		var y uint32 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint32 = 4294967295
+		var y uint32 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint32 = 4294967295
+		var y uint32 = 4294967295
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+}
+func TestConstFoldCompareint32(t *testing.T) {
+	{
+		var x int32 = -2147483648
+		var y int32 = -2147483648
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483648
+		var y int32 = -2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483648
+		var y int32 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483648
+		var y int32 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483648
+		var y int32 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483648
+		var y int32 = 2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483647
+		var y int32 = -2147483648
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483647
+		var y int32 = -2147483647
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483647
+		var y int32 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483647
+		var y int32 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483647
+		var y int32 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -2147483647
+		var y int32 = 2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -1
+		var y int32 = -2147483648
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = -1
+		var y int32 = -2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = -1
+		var y int32 = -1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = -1
+		var y int32 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -1
+		var y int32 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = -1
+		var y int32 = 2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = 0
+		var y int32 = -2147483648
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 0
+		var y int32 = -2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 0
+		var y int32 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 0
+		var y int32 = 0
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 0
+		var y int32 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = 0
+		var y int32 = 2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = 1
+		var y int32 = -2147483648
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 1
+		var y int32 = -2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 1
+		var y int32 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 1
+		var y int32 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 1
+		var y int32 = 1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 1
+		var y int32 = 2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int32 = 2147483647
+		var y int32 = -2147483648
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 2147483647
+		var y int32 = -2147483647
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 2147483647
+		var y int32 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 2147483647
+		var y int32 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 2147483647
+		var y int32 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int32 = 2147483647
+		var y int32 = 2147483647
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+}
+func TestConstFoldCompareuint16(t *testing.T) {
+	{
+		var x uint16 = 0
+		var y uint16 = 0
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint16 = 0
+		var y uint16 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint16 = 0
+		var y uint16 = 65535
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint16 = 1
+		var y uint16 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint16 = 1
+		var y uint16 = 1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint16 = 1
+		var y uint16 = 65535
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint16 = 65535
+		var y uint16 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint16 = 65535
+		var y uint16 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint16 = 65535
+		var y uint16 = 65535
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+}
+func TestConstFoldCompareint16(t *testing.T) {
+	{
+		var x int16 = -32768
+		var y int16 = -32768
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = -32768
+		var y int16 = -32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32768
+		var y int16 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32768
+		var y int16 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32768
+		var y int16 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32768
+		var y int16 = 32766
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32768
+		var y int16 = 32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32767
+		var y int16 = -32768
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = -32767
+		var y int16 = -32767
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = -32767
+		var y int16 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32767
+		var y int16 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32767
+		var y int16 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32767
+		var y int16 = 32766
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -32767
+		var y int16 = 32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -1
+		var y int16 = -32768
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = -1
+		var y int16 = -32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = -1
+		var y int16 = -1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = -1
+		var y int16 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -1
+		var y int16 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -1
+		var y int16 = 32766
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = -1
+		var y int16 = 32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = 0
+		var y int16 = -32768
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 0
+		var y int16 = -32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 0
+		var y int16 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 0
+		var y int16 = 0
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 0
+		var y int16 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = 0
+		var y int16 = 32766
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = 0
+		var y int16 = 32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = 1
+		var y int16 = -32768
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 1
+		var y int16 = -32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 1
+		var y int16 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 1
+		var y int16 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 1
+		var y int16 = 1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 1
+		var y int16 = 32766
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = 1
+		var y int16 = 32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = 32766
+		var y int16 = -32768
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32766
+		var y int16 = -32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32766
+		var y int16 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32766
+		var y int16 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32766
+		var y int16 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32766
+		var y int16 = 32766
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32766
+		var y int16 = 32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int16 = 32767
+		var y int16 = -32768
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32767
+		var y int16 = -32767
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32767
+		var y int16 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32767
+		var y int16 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32767
+		var y int16 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32767
+		var y int16 = 32766
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int16 = 32767
+		var y int16 = 32767
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+}
+func TestConstFoldCompareuint8(t *testing.T) {
+	{
+		var x uint8 = 0
+		var y uint8 = 0
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint8 = 0
+		var y uint8 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint8 = 0
+		var y uint8 = 255
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint8 = 1
+		var y uint8 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint8 = 1
+		var y uint8 = 1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint8 = 1
+		var y uint8 = 255
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x uint8 = 255
+		var y uint8 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint8 = 255
+		var y uint8 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x uint8 = 255
+		var y uint8 = 255
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+}
+func TestConstFoldCompareint8(t *testing.T) {
+	{
+		var x int8 = -128
+		var y int8 = -128
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = -128
+		var y int8 = -127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -128
+		var y int8 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -128
+		var y int8 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -128
+		var y int8 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -128
+		var y int8 = 126
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -128
+		var y int8 = 127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -127
+		var y int8 = -128
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = -127
+		var y int8 = -127
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = -127
+		var y int8 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -127
+		var y int8 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -127
+		var y int8 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -127
+		var y int8 = 126
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -127
+		var y int8 = 127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -1
+		var y int8 = -128
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = -1
+		var y int8 = -127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = -1
+		var y int8 = -1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = -1
+		var y int8 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -1
+		var y int8 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -1
+		var y int8 = 126
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = -1
+		var y int8 = 127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = 0
+		var y int8 = -128
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 0
+		var y int8 = -127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 0
+		var y int8 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 0
+		var y int8 = 0
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 0
+		var y int8 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = 0
+		var y int8 = 126
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = 0
+		var y int8 = 127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = 1
+		var y int8 = -128
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 1
+		var y int8 = -127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 1
+		var y int8 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 1
+		var y int8 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 1
+		var y int8 = 1
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 1
+		var y int8 = 126
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = 1
+		var y int8 = 127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = 126
+		var y int8 = -128
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 126
+		var y int8 = -127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 126
+		var y int8 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 126
+		var y int8 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 126
+		var y int8 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 126
+		var y int8 = 126
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 126
+		var y int8 = 127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if !(x < y) {
+			t.Errorf("!(%d < %d)", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if x >= y {
+			t.Errorf("%d >= %d", x, y)
+		}
+	}
+	{
+		var x int8 = 127
+		var y int8 = -128
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 127
+		var y int8 = -127
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 127
+		var y int8 = -1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 127
+		var y int8 = 0
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 127
+		var y int8 = 1
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 127
+		var y int8 = 126
+		if x == y {
+			t.Errorf("%d == %d", x, y)
+		}
+		if !(x != y) {
+			t.Errorf("!(%d != %d)", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if !(x > y) {
+			t.Errorf("!(%d > %d)", x, y)
+		}
+		if x <= y {
+			t.Errorf("%d <= %d", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+	{
+		var x int8 = 127
+		var y int8 = 127
+		if !(x == y) {
+			t.Errorf("!(%d == %d)", x, y)
+		}
+		if x != y {
+			t.Errorf("%d != %d", x, y)
+		}
+		if x < y {
+			t.Errorf("%d < %d", x, y)
+		}
+		if x > y {
+			t.Errorf("%d > %d", x, y)
+		}
+		if !(x <= y) {
+			t.Errorf("!(%d <= %d)", x, y)
+		}
+		if !(x >= y) {
+			t.Errorf("!(%d >= %d)", x, y)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/cplx.go b/src/cmd/compile/internal/gc/cplx.go
index b692456..96a1dfb 100644
--- a/src/cmd/compile/internal/gc/cplx.go
+++ b/src/cmd/compile/internal/gc/cplx.go
@@ -89,8 +89,9 @@ func subnode(nr *Node, ni *Node, nc *Node) {
 	t := Types[tc]
 
 	if nc.Op == OLITERAL {
-		nodfconst(nr, t, &nc.Val().U.(*Mpcplx).Real)
-		nodfconst(ni, t, &nc.Val().U.(*Mpcplx).Imag)
+		u := nc.Val().U.(*Mpcplx)
+		nodfconst(nr, t, &u.Real)
+		nodfconst(ni, t, &u.Imag)
 		return
 	}
 
@@ -229,20 +230,20 @@ func nodfconst(n *Node, t *Type, fval *Mpflt) {
 	n.SetVal(Val{fval})
 	n.Type = t
 
-	if !Isfloat[t.Etype] {
+	if !t.IsFloat() {
 		Fatalf("nodfconst: bad type %v", t)
 	}
 }
 
 func Complexop(n *Node, res *Node) bool {
 	if n != nil && n.Type != nil {
-		if Iscomplex[n.Type.Etype] {
+		if n.Type.IsComplex() {
 			goto maybe
 		}
 	}
 
 	if res != nil && res.Type != nil {
-		if Iscomplex[res.Type.Etype] {
+		if res.Type.IsComplex() {
 			goto maybe
 		}
 	}
@@ -398,13 +399,12 @@ func Complexgen(n *Node, res *Node) {
 	switch n.Op {
 	default:
 		Dump("complexgen: unknown op", n)
-		Fatalf("complexgen: unknown op %v", Oconv(int(n.Op), 0))
+		Fatalf("complexgen: unknown op %v", n.Op)
 
 	case ODOT,
 		ODOTPTR,
 		OINDEX,
 		OIND,
-		ONAME, // PHEAP or PPARAMREF var
 		OCALLFUNC,
 		OCALLMETH,
 		OCALLINTER:
@@ -457,7 +457,7 @@ func Complexgen(n *Node, res *Node) {
 
 	switch n.Op {
 	default:
-		Fatalf("complexgen: unknown op %v", Oconv(int(n.Op), 0))
+		Fatalf("complexgen: unknown op %v", n.Op)
 
 	case OCONV:
 		Complexmove(nl, res)
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index fc47a39..a4b98ec 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -7,24 +7,33 @@ package gc
 import (
 	"cmd/internal/obj"
 	"fmt"
+	"sort"
 	"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
+
+var externdcl []*Node
 
-// declaration stack & operations
-func dcopy(a *Sym, b *Sym) {
+var blockgen int32 // max block number
+
+var block int32 // current block number
+
+// dclstack maintains a stack of shadowed symbol declarations so that
+// popdcl can restore their declarations when a block scope ends.
+// The stack is maintained as a linked list, using Sym's Link field.
+//
+// In practice, the "stack" actually ends up forming a tree: goto and label
+// statements record the current state of dclstack so that checkgoto can
+// validate that a goto statement does not jump over any declarations or
+// into a new block scope.
+//
+// Finally, the Syms in this list are not "real" Syms as they don't actually
+// represent object names. Sym is just a convenient type for saving shadowed
+// Sym definitions, and only a subset of its fields are actually used.
+var dclstack *Sym
+
+func dcopy(a, b *Sym) {
 	a.Pkg = b.Pkg
 	a.Name = b.Name
 	a.Def = b.Def
@@ -40,43 +49,34 @@ func push() *Sym {
 	return d
 }
 
+// pushdcl pushes the current declaration for symbol s (if any) so that
+// it can be shadowed by a new declaration within a nested block scope.
 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
 }
 
+// popdcl pops the innermost block scope and restores all symbol declarations
+// to their previous state.
 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)
+	d := dclstack
+	for ; d != nil && d.Name != ""; d = d.Link {
+		s := Pkglookup(d.Name, d.Pkg)
+		lno := 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)
-		}
+		d.Lastlineno = lno
 	}
 
 	if d == nil {
 		Fatalf("popdcl: no mark")
 	}
-	dclstack = d.Link
+
+	dclstack = d.Link // pop mark
 	block = d.Block
 }
 
+// markdcl records the start of a new block scope for declarations.
 func markdcl() {
 	d := push()
 	d.Name = "" // used as a mark in fifo
@@ -86,23 +86,17 @@ func markdcl() {
 	block = blockgen
 }
 
-//	if(dflag())
-//		print("markdcl\n");
-func dumpdcl(st string) {
-	var s *Sym
-
+// keep around for debugging
+func dumpdclstack() {
 	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("%6d  %p", i, d)
+		if d.Name != "" {
+			fmt.Printf("  '%s'  %v\n", d.Name, Pkglookup(d.Name, d.Pkg))
+		} else {
+			fmt.Printf("  ---\n")
 		}
-
-		fmt.Printf(" '%s'", d.Name)
-		s = Pkglookup(d.Name, d.Pkg)
-		fmt.Printf(" %v\n", s)
+		i++
 	}
 }
 
@@ -113,11 +107,11 @@ func testdclstack() {
 				errorexit()
 			}
 			Yyerror("mark left on the stack")
-			continue
 		}
 	}
 }
 
+// redeclare emits a diagnostic about symbol s being redeclared somewhere.
 func redeclare(s *Sym, where string) {
 	if s.Lastlineno == 0 {
 		var tmp string
@@ -129,8 +123,8 @@ func redeclare(s *Sym, where string) {
 		pkgstr := tmp
 		Yyerror("%v redeclared %s\n"+"\tprevious declaration during import %q", s, where, pkgstr)
 	} else {
-		line1 := parserline()
-		line2 := int(s.Lastlineno)
+		line1 := lineno
+		line2 := s.Lastlineno
 
 		// When an import and a declaration collide in separate files,
 		// present the import as the "redeclared", because the declaration
@@ -138,10 +132,10 @@ func redeclare(s *Sym, where string) {
 		// See issue 4510.
 		if s.Def == nil {
 			line2 = line1
-			line1 = int(s.Lastlineno)
+			line1 = s.Lastlineno
 		}
 
-		yyerrorl(int(line1), "%v redeclared %s\n"+"\tprevious declaration at %v", s, where, Ctxt.Line(line2))
+		yyerrorl(line1, "%v redeclared %s\n"+"\tprevious declaration at %v", s, where, linestr(line2))
 	}
 }
 
@@ -151,6 +145,8 @@ var vargen int
 
 var declare_typegen int
 
+// declare records that Node n declares symbol n.Sym in the specified
+// declaration context.
 func declare(n *Node, ctxt Class) {
 	if ctxt == PDISCARD {
 		return
@@ -164,10 +160,10 @@ func declare(n *Node, ctxt Class) {
 		// named OLITERAL needs Name; most OLITERALs don't.
 		n.Name = new(Name)
 	}
-	n.Lineno = int32(parserline())
+	n.Lineno = lineno
 	s := n.Sym
 
-	// kludgy: typecheckok means we're past parsing.  Eg genwrapper may declare out of package names later.
+	// 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 %v", s)
 	}
@@ -179,15 +175,12 @@ func declare(n *Node, ctxt Class) {
 	gen := 0
 	if ctxt == PEXTERN {
 		externdcl = append(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 {
 			Fatalf("automatic outside function")
 		}
 		if Curfn != nil {
-			Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+			Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
 		}
 		if n.Op == OTYPE {
 			declare_typegen++
@@ -213,7 +206,7 @@ func declare(n *Node, ctxt Class) {
 	}
 
 	s.Block = block
-	s.Lastlineno = int32(parserline())
+	s.Lastlineno = lineno
 	s.Def = n
 	n.Name.Vargen = int32(gen)
 	n.Name.Funcdepth = Funcdepth
@@ -234,63 +227,56 @@ func addvar(n *Node, t *Type, ctxt Class) {
 
 // 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
+func variter(vl []*Node, t *Node, el []*Node) []*Node {
+	var init []*Node
+	doexpr := len(el) > 0
 
-	if count(el) == 1 && count(vl) > 1 {
-		e := el.N
+	if len(el) == 1 && len(vl) > 1 {
+		e := el[0]
 		as2 := Nod(OAS2, nil, nil)
-		as2.List = vl
-		as2.Rlist = list1(e)
-		var v *Node
-		for ; vl != nil; vl = vl.Next {
-			v = vl.N
+		as2.List.Set(vl)
+		as2.Rlist.Set1(e)
+		for _, v := range vl {
 			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))
+				init = append(init, Nod(ODCL, v, nil))
 			}
 		}
 
-		return list(init, as2)
+		return append(init, as2)
 	}
 
-	var v *Node
-	var e *Node
-	for ; vl != nil; vl = vl.Next {
+	for _, v := range vl {
+		var e *Node
 		if doexpr {
-			if el == nil {
+			if len(el) == 0 {
 				Yyerror("missing expression in var declaration")
 				break
 			}
-
-			e = el.N
-			el = el.Next
-		} else {
-			e = nil
+			e = el[0]
+			el = el[1:]
 		}
 
-		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))
+				init = append(init, Nod(ODCL, v, nil))
 			}
 			e = Nod(OAS, v, e)
-			init = list(init, e)
+			init = append(init, e)
 			if e.Right != nil {
 				v.Name.Defn = e
 			}
 		}
 	}
 
-	if el != nil {
+	if len(el) != 0 {
 		Yyerror("extra expression in var declaration")
 	}
 	return init
@@ -298,52 +284,48 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
 
 // declare constants from grammar
 // new_name_list [[type] = expr_list]
-func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
+func constiter(vl []*Node, t *Node, cl []*Node) []*Node {
 	lno := int32(0) // default is to leave line number alone in listtreecopy
-	if cl == nil {
+	if len(cl) == 0 {
 		if t != nil {
 			Yyerror("const declaration cannot have type without expression")
 		}
 		cl = lastconst
 		t = lasttype
-		lno = vl.N.Lineno
+		lno = vl[0].Lineno
 	} else {
 		lastconst = cl
 		lasttype = t
 	}
-	cl = listtreecopy(cl, lno)
+	clcopy := listtreecopy(cl, lno)
 
-	var v *Node
-	var c *Node
-	var vv *NodeList
-	for ; vl != nil; vl = vl.Next {
-		if cl == nil {
+	var vv []*Node
+	for _, v := range vl {
+		if len(clcopy) == 0 {
 			Yyerror("missing value in const declaration")
 			break
 		}
 
-		c = cl.N
-		cl = cl.Next
+		c := clcopy[0]
+		clcopy = clcopy[1:]
 
-		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))
+		vv = append(vv, Nod(ODCLCONST, v, nil))
 	}
 
-	if cl != nil {
+	if len(clcopy) != 0 {
 		Yyerror("extra expression in const declaration")
 	}
 	iota_ += 1
 	return vv
 }
 
-// this generates a new name node,
-// typically for labels or other one-off names.
+// newname returns a new ONAME Node associated with symbol s.
 func newname(s *Sym) *Node {
 	if s == nil {
 		Fatalf("newname nil")
@@ -388,49 +370,51 @@ func typenod(t *Type) *Node {
 	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.
+// oldname returns the Node that declares symbol s in the current scope.
+// If no such Node currently exists, an ONONAME Node is returned instead.
 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.
+		// Maybe a top-level declaration will come along later to
+		// define s. resolve will check s.Def again once all input
+		// source has been processed.
 		n = newname(s)
 		n.Op = ONONAME
 		n.Name.Iota = iota_ // save current iota value in const declarations
+		return n
 	}
 
 	if Curfn != nil && n.Op == ONAME && n.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth {
-		// inner func is referring to var in outer func.
+		// 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 := n.Name.Param.Innermost
+		if c == nil || c.Name.Funcdepth != Funcdepth {
+			// Do not have a closure var for the active closure yet; make one.
+			c = Nod(ONAME, nil, nil)
 			c.Sym = s
-			c.Class = PPARAMREF
+			c.Class = PAUTOHEAP
+			c.setIsClosureVar(true)
 			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
+
+			// Link into list of active closure variables.
+			// Popped from list in func closurebody.
+			c.Name.Param.Outer = n.Name.Param.Innermost
+			n.Name.Param.Innermost = c
+
 			c.Xoffset = 0
-			Curfn.Func.Cvars = list(Curfn.Func.Cvars, c)
+			Curfn.Func.Cvars.Append(c)
 		}
 
 		// return ref to closure var, not original
-		return n.Name.Param.Closure
+		return c
 	}
 
 	return n
@@ -450,29 +434,26 @@ func colasname(n *Node) bool {
 	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
+func colasdefn(left []*Node, defn *Node) {
+	for _, n := range left {
+		if n.Sym != nil {
+			n.Sym.Flags |= SymUniq
 		}
 	}
 
-	nnew := 0
-	nerr := 0
-	var n *Node
-	for l := left; l != nil; l = l.Next {
-		n = l.N
+	var nnew, nerr int
+	for i, n := range left {
 		if isblank(n) {
 			continue
 		}
 		if !colasname(n) {
-			yyerrorl(int(defn.Lineno), "non-name %v on left side of :=", n)
+			yyerrorl(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)
+			yyerrorl(defn.Lineno, "%v repeated on left side of :=", n.Sym)
 			n.Diag++
 			nerr++
 			continue
@@ -487,33 +468,30 @@ func colasdefn(left *NodeList, defn *Node) {
 		n = newname(n.Sym)
 		declare(n, dclcontext)
 		n.Name.Defn = defn
-		defn.Ninit = list(defn.Ninit, Nod(ODCL, n, nil))
-		l.N = n
+		defn.Ninit.Append(Nod(ODCL, n, nil))
+		left[i] = n
 	}
 
 	if nnew == 0 && nerr == 0 {
-		yyerrorl(int(defn.Lineno), "no new variables on left side of :=")
+		yyerrorl(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
+func colas(left, right []*Node, lno int32) *Node {
+	n := Nod(OAS, nil, nil) // assume common case
+	n.Colas = true
+	n.Lineno = lno     // set before calling colasdefn for correct error line
+	colasdefn(left, n) // modifies left, call before using left[0] in common case
+	if len(left) == 1 && len(right) == 1 {
+		// common case
+		n.Left = left[0]
+		n.Right = right[0]
+	} else {
+		n.Op = OAS2
+		n.List.Set(left)
+		n.Rlist.Set(right)
 	}
-
-	return as
+	return n
 }
 
 // declare the arguments in an
@@ -530,10 +508,8 @@ func ifacedcl(n *Node) {
 	n.Func = new(Func)
 	n.Func.FCurfn = Curfn
 	dclcontext = PPARAM
-	markdcl()
-	Funcdepth++
-	n.Func.Outer = Curfn
-	Curfn = n
+
+	funcstart(n)
 	funcargs(n.Right)
 
 	// funcbody is normally called after the parser has
@@ -552,7 +528,7 @@ func ifacedcl(n *Node) {
 func funchdr(n *Node) {
 	// change the declaration context from extern to auto
 	if Funcdepth == 0 && dclcontext != PEXTERN {
-		Fatalf("funchdr: dclcontext")
+		Fatalf("funchdr: dclcontext = %d", dclcontext)
 	}
 
 	if importpkg == nil && n.Func.Nname != nil {
@@ -560,11 +536,7 @@ func funchdr(n *Node) {
 	}
 
 	dclcontext = PAUTO
-	markdcl()
-	Funcdepth++
-
-	n.Func.Outer = Curfn
-	Curfn = n
+	funcstart(n)
 
 	if n.Func.Nname != nil {
 		funcargs(n.Func.Nname.Name.Param.Ntype)
@@ -577,13 +549,13 @@ func funchdr(n *Node) {
 
 func funcargs(nt *Node) {
 	if nt.Op != OTFUNC {
-		Fatalf("funcargs %v", Oconv(int(nt.Op), 0))
+		Fatalf("funcargs %v", 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)
+	vargen = nt.Rlist.Len()
 
 	// declare the receiver and in arguments.
 	// no n->defn because type checking of func header
@@ -591,7 +563,7 @@ func funcargs(nt *Node) {
 	if nt.Left != nil {
 		n := nt.Left
 		if n.Op != ODCLFIELD {
-			Fatalf("funcargs receiver %v", Oconv(int(n.Op), 0))
+			Fatalf("funcargs receiver %v", n.Op)
 		}
 		if n.Left != nil {
 			n.Left.Op = ONAME
@@ -604,11 +576,9 @@ func funcargs(nt *Node) {
 		}
 	}
 
-	var n *Node
-	for l := nt.List; l != nil; l = l.Next {
-		n = l.N
+	for _, n := range nt.List.Slice() {
 		if n.Op != ODCLFIELD {
-			Fatalf("funcargs in %v", Oconv(int(n.Op), 0))
+			Fatalf("funcargs in %v", n.Op)
 		}
 		if n.Left != nil {
 			n.Left.Op = ONAME
@@ -622,19 +592,16 @@ func funcargs(nt *Node) {
 	}
 
 	// declare the out arguments.
-	gen := count(nt.List)
+	gen := nt.List.Len()
 	var i int = 0
-	var nn *Node
-	for l := nt.Rlist; l != nil; l = l.Next {
-		n = l.N
-
+	for _, n := range nt.Rlist.Slice() {
 		if n.Op != ODCLFIELD {
-			Fatalf("funcargs out %v", Oconv(int(n.Op), 0))
+			Fatalf("funcargs out %v", n.Op)
 		}
 
 		if n.Left == nil {
 			// Name so that escape analysis can track it. ~r stands for 'result'.
-			n.Left = newname(Lookupf("~r%d", gen))
+			n.Left = newname(LookupN("~r", gen))
 			gen++
 		}
 
@@ -650,13 +617,11 @@ func funcargs(nt *Node) {
 			// 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)
+			nn := *n.Left
+			nn.Orig = &nn
+			nn.Sym = LookupN("~b", gen)
 			gen++
-			n.Left = nn
+			n.Left = &nn
 		}
 
 		n.Left.Name.Param.Ntype = n.Right
@@ -676,55 +641,57 @@ func funcargs2(t *Type) {
 		Fatalf("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)
+	for _, ft := range t.Recvs().Fields().Slice() {
+		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)
+	for _, ft := range t.Params().Fields().Slice() {
+		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)
+	for _, ft := range t.Results().Fields().Slice() {
+		if ft.Nname == nil || ft.Nname.Sym == nil {
+			continue
 		}
+		n := ft.Nname
+		n.Type = ft.Type
+		declare(n, PPARAMOUT)
 	}
 }
 
+var funcstack []*Node // stack of previous values of Curfn
+var Funcdepth int32   // len(funcstack) during parsing, but then forced to be the same later during compilation
+
+// start the function.
+// called before funcargs; undone at end of funcbody.
+func funcstart(n *Node) {
+	markdcl()
+	funcstack = append(funcstack, Curfn)
+	Funcdepth++
+	Curfn = n
+}
+
 // 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 {
-		Fatalf("funcbody: dclcontext")
+		Fatalf("funcbody: unexpected dclcontext %d", dclcontext)
 	}
 	popdcl()
+	funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1]
 	Funcdepth--
-	Curfn = n.Func.Outer
-	n.Func.Outer = nil
 	if Funcdepth == 0 {
 		dclcontext = PEXTERN
 	}
@@ -754,33 +721,33 @@ func checkembeddedtype(t *Type) {
 		return
 	}
 
-	if t.Sym == nil && Isptr[t.Etype] {
-		t = t.Type
-		if t.Etype == TINTER {
+	if t.Sym == nil && t.IsPtr() {
+		t = t.Elem()
+		if t.IsInterface() {
 			Yyerror("embedded type cannot be a pointer to interface")
 		}
 	}
 
-	if Isptr[t.Etype] {
+	if t.IsPtr() || t.IsUnsafePtr() {
 		Yyerror("embedded type cannot be a pointer")
-	} else if t.Etype == TFORW && t.Embedlineno == 0 {
-		t.Embedlineno = lineno
+	} else if t.Etype == TFORW && t.ForwardType().Embedlineno == 0 {
+		t.ForwardType().Embedlineno = lineno
 	}
 }
 
-func structfield(n *Node) *Type {
-	lno := int(lineno)
+func structfield(n *Node) *Field {
+	lno := lineno
 	lineno = n.Lineno
 
 	if n.Op != ODCLFIELD {
 		Fatalf("structfield: oops %v\n", n)
 	}
 
-	f := typ(TFIELD)
+	f := newField()
 	f.Isddd = n.Isddd
 
 	if n.Right != nil {
-		typecheck(&n.Right, Etype)
+		n.Right = typecheck(n.Right, Etype)
 		n.Type = n.Right.Type
 		if n.Left != nil {
 			n.Left.Type = n.Type
@@ -797,17 +764,13 @@ func structfield(n *Node) *Type {
 		f.Broke = true
 	}
 
-	switch n.Val().Ctype() {
-	case CTSTR:
-		f.Note = new(string)
-		*f.Note = n.Val().U.(string)
-
+	switch u := n.Val().U.(type) {
+	case string:
+		f.Note = u
 	default:
 		Yyerror("field annotation must be string")
-		fallthrough
-
-	case CTxxx:
-		f.Note = nil
+	case nil:
+		// noop
 	}
 
 	if n.Left != nil && n.Left.Op == ONAME {
@@ -816,93 +779,87 @@ func structfield(n *Node) *Type {
 		f.Sym = f.Nname.Sym
 	}
 
-	lineno = int32(lno)
+	lineno = lno
 	return f
 }
 
-var uniqgen uint32
+// checkdupfields emits errors for duplicately named fields or methods in
+// a list of struct or interface types.
+func checkdupfields(what string, ts ...*Type) {
+	lno := lineno
 
-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
+	seen := make(map[*Sym]bool)
+	for _, t := range ts {
+		for _, f := range t.Fields().Slice() {
+			if f.Sym == nil || f.Nname == nil || isblank(f.Nname) {
+				continue
 			}
+			if seen[f.Sym] {
+				lineno = f.Nname.Lineno
+				Yyerror("duplicate %s %s", what, f.Sym.Name)
+				continue
+			}
+			seen[f.Sym] = true
 		}
 	}
 
-	lineno = int32(lno)
+	lineno = lno
 }
 
 // convert a parsed id/type list into
 // a type for struct/interface/arglist
-func tostruct(l *NodeList) *Type {
+func tostruct(l []*Node) *Type {
 	t := typ(TSTRUCT)
 	tostruct0(t, l)
 	return t
 }
 
-func tostruct0(t *Type, l *NodeList) {
-	if t == nil || t.Etype != TSTRUCT {
+func tostruct0(t *Type, l []*Node) {
+	if t == nil || !t.IsStruct() {
 		Fatalf("struct expected")
 	}
 
-	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; f = f.Down {
+	fields := make([]*Field, len(l))
+	for i, n := range l {
+		f := structfield(n)
 		if f.Broke {
 			t.Broke = true
 		}
+		fields[i] = f
 	}
+	t.SetFields(fields)
 
-	uniqgen++
-	checkdupfields(t.Type, "field")
+	checkdupfields("field", t)
 
 	if !t.Broke {
 		checkwidth(t)
 	}
 }
 
-func tofunargs(l *NodeList) *Type {
-	var f *Type
-
+func tofunargs(l []*Node, funarg Funarg) *Type {
 	t := typ(TSTRUCT)
-	t.Funarg = true
+	t.StructType().Funarg = funarg
 
-	for tp := &t.Type; l != nil; l = l.Next {
-		f = structfield(l.N)
-		f.Funarg = true
+	fields := make([]*Field, len(l))
+	for i, n := range l {
+		f := structfield(n)
+		f.Funarg = funarg
 
 		// esc.go 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
+		if n.Left != nil && n.Left.Class == PPARAM {
+			n.Left.Name.Param.Field = f
 		}
-
-		*tp = f
-		tp = &f.Down
-	}
-
-	for f := t.Type; f != nil && !t.Broke; f = f.Down {
 		if f.Broke {
 			t.Broke = true
 		}
+		fields[i] = f
 	}
-
+	t.SetFields(fields)
 	return t
 }
 
-func interfacefield(n *Node) *Type {
-	lno := int(lineno)
+func interfacefield(n *Node) *Field {
+	lno := lineno
 	lineno = n.Lineno
 
 	if n.Op != ODCLFIELD {
@@ -913,7 +870,7 @@ func interfacefield(n *Node) *Type {
 		Yyerror("interface method cannot have annotation")
 	}
 
-	f := typ(TFIELD)
+	f := newField()
 	f.Isddd = n.Isddd
 
 	if n.Right != nil {
@@ -922,8 +879,7 @@ func interfacefield(n *Node) *Type {
 			// 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.Type.SetNname(n.Right)
 			n.Left.Type = n.Type
 			queuemethod(n)
 
@@ -933,7 +889,7 @@ func interfacefield(n *Node) *Type {
 				f.Sym = f.Nname.Sym
 			}
 		} else {
-			typecheck(&n.Right, Etype)
+			n.Right = typecheck(n.Right, Etype)
 			n.Type = n.Right.Type
 
 			if n.Embedded != 0 {
@@ -964,53 +920,48 @@ func interfacefield(n *Node) *Type {
 		f.Broke = true
 	}
 
-	lineno = int32(lno)
+	lineno = lno
 	return f
 }
 
-func tointerface(l *NodeList) *Type {
+func tointerface(l []*Node) *Type {
 	t := typ(TINTER)
 	tointerface0(t, l)
 	return t
 }
 
-func tointerface0(t *Type, l *NodeList) *Type {
-	if t == nil || t.Etype != TINTER {
+func tointerface0(t *Type, l []*Node) *Type {
+	if t == nil || !t.IsInterface() {
 		Fatalf("interface expected")
 	}
 
-	tp := &t.Type
-	for ; l != nil; l = l.Next {
-		f := interfacefield(l.N)
+	var fields []*Field
+	for _, n := range l {
+		f := interfacefield(n)
 
-		if l.N.Left == nil && f.Type.Etype == TINTER {
+		if n.Left == nil && f.Type.IsInterface() {
 			// embedded interface, inline methods
-			for t1 := f.Type.Type; t1 != nil; t1 = t1.Down {
-				f = typ(TFIELD)
+			for _, t1 := range f.Type.Fields().Slice() {
+				f = newField()
 				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
+				fields = append(fields, f)
 			}
 		} else {
-			*tp = f
-			tp = &f.Down
+			fields = append(fields, f)
 		}
-	}
-
-	for f := t.Type; f != nil && !t.Broke; f = f.Down {
 		if f.Broke {
 			t.Broke = true
 		}
 	}
+	sort.Sort(methcmp(fields))
+	t.SetFields(fields)
 
-	uniqgen++
-	checkdupfields(t.Type, "method")
-	t = sortinter(t)
+	checkdupfields("method", t)
 	checkwidth(t)
 
 	return t
@@ -1021,7 +972,7 @@ func embedded(s *Sym, pkg *Pkg) *Node {
 		CenterDot = 0xB7
 	)
 	// Names sometimes have disambiguation junk
-	// appended after a center dot.  Discard it when
+	// appended after a center dot. Discard it when
 	// making the name for the embedded struct field.
 	name := s.Name
 
@@ -1043,106 +994,6 @@ func embedded(s *Sym, pkg *Pkg) *Node {
 	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.go 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
@@ -1152,60 +1003,52 @@ func fakethis() *Node {
 // Those methods have an anonymous *struct{} as the receiver.
 // (See fakethis above.)
 func isifacemethod(f *Type) bool {
-	rcvr := getthisx(f).Type
+	rcvr := f.Recv()
 	if rcvr.Sym != nil {
 		return false
 	}
 	t := rcvr.Type
-	if !Isptr[t.Etype] {
+	if !t.IsPtr() {
 		return false
 	}
-	t = t.Type
-	if t.Sym != nil || t.Etype != TSTRUCT || t.Type != nil {
+	t = t.Elem()
+	if t.Sym != nil || !t.IsStruct() || t.NumFields() != 0 {
 		return false
 	}
 	return true
 }
 
 // turn a parsed function declaration into a type
-func functype(this *Node, in *NodeList, out *NodeList) *Type {
+func functype(this *Node, in, out []*Node) *Type {
 	t := typ(TFUNC)
 	functype0(t, this, in, out)
 	return t
 }
 
-func functype0(t *Type, this *Node, in *NodeList, out *NodeList) {
+func functype0(t *Type, this *Node, in, out []*Node) {
 	if t == nil || t.Etype != TFUNC {
 		Fatalf("function type expected")
 	}
 
-	var rcvr *NodeList
+	var rcvr []*Node
 	if this != nil {
-		rcvr = list1(this)
+		rcvr = []*Node{this}
 	}
-	t.Type = tofunargs(rcvr)
-	t.Type.Down = tofunargs(out)
-	t.Type.Down.Down = tofunargs(in)
+	*t.RecvsP() = tofunargs(rcvr, FunargRcvr)
+	*t.ResultsP() = tofunargs(out, FunargResults)
+	*t.ParamsP() = tofunargs(in, FunargParams)
 
-	uniqgen++
-	checkdupfields(t.Type.Type, "argument")
-	checkdupfields(t.Type.Down.Type, "argument")
-	checkdupfields(t.Type.Down.Down.Type, "argument")
+	checkdupfields("argument", t.Recvs(), t.Results(), t.Params())
 
-	if t.Type.Broke || t.Type.Down.Broke || t.Type.Down.Down.Broke {
+	if t.Recvs().Broke || t.Results().Broke || t.Params().Broke {
 		t.Broke = true
 	}
 
-	if this != nil {
-		t.Thistuple = 1
-	}
-	t.Outtuple = count(out)
-	t.Intuple = count(in)
-	t.Outnamed = false
-	if t.Outtuple > 0 && out.N.Left != nil && out.N.Left.Orig != nil {
-		s := out.N.Left.Orig.Sym
+	t.FuncType().Outnamed = false
+	if len(out) > 0 && out[0].Left != nil && out[0].Left.Orig != nil {
+		s := out[0].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 = true
+			t.FuncType().Outnamed = true
 		}
 	}
 }
@@ -1223,8 +1066,8 @@ func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
 		goto bad
 	}
 	s = t.Sym
-	if s == nil && Isptr[t.Etype] {
-		t = t.Type
+	if s == nil && t.IsPtr() {
+		t = t.Elem()
 		if t == nil {
 			goto bad
 		}
@@ -1251,16 +1094,16 @@ func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
 	}
 
 	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)
+		if t0.Sym == nil && t0.IsPtr() {
+			p = fmt.Sprintf("(%v).%s.%s%s", Tconv(t0, FmtLeft|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)
+			p = fmt.Sprintf("%v.%s.%s%s", Tconv(t0, FmtLeft|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)
+		if t0.Sym == nil && t0.IsPtr() {
+			p = fmt.Sprintf("(%v).%s%s", Tconv(t0, FmtLeft|FmtShort), nsym.Name, suffix)
 		} else {
-			p = fmt.Sprintf("%v.%s%s", Tconv(t0, obj.FmtLeft|obj.FmtShort), nsym.Name, suffix)
+			p = fmt.Sprintf("%v.%s%s", Tconv(t0, FmtLeft|FmtShort), nsym.Name, suffix)
 		}
 	}
 
@@ -1315,36 +1158,38 @@ func methodname1(n *Node, t *Node) *Node {
 	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) {
+// Add a method, declared as a function.
+// - msym is the method symbol
+// - t is function type (with receiver)
+// - tpkg is the package of the type declaring the method during import, or nil (ignored) --- for verification only
+func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
 	// get field sym
-	if sf == nil {
+	if msym == nil {
 		Fatalf("no method symbol")
 	}
 
 	// get parent type sym
-	pa := getthisx(t).Type // ptr to this structure
-	if pa == nil {
+	rf := t.Recv() // ptr to this structure
+	if rf == nil {
 		Yyerror("missing receiver")
 		return
 	}
 
-	pa = pa.Type
-	f := methtype(pa, 1)
-	if f == nil {
+	pa := rf.Type // base type
+	mt := methtype(pa, 1)
+	if mt == nil {
 		t = pa
 		if t == nil { // rely on typecheck having complained before
 			return
 		}
 		if t != nil {
-			if Isptr[t.Etype] {
+			if t.IsPtr() {
 				if t.Sym != nil {
 					Yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
 					return
 				}
 
-				t = t.Type
+				t = t.Elem()
 			}
 
 			if t.Broke { // rely on typecheck having complained before
@@ -1355,12 +1200,12 @@ func addmethod(sf *Sym, t *Type, local bool, nointerface bool) {
 				return
 			}
 
-			if Isptr[t.Etype] {
+			if t.IsPtr() {
 				Yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
 				return
 			}
 
-			if t.Etype == TINTER {
+			if t.IsInterface() {
 				Yyerror("invalid receiver type %v (%v is an interface type)", pa, t)
 				return
 			}
@@ -1368,62 +1213,54 @@ func addmethod(sf *Sym, t *Type, local bool, nointerface bool) {
 
 		// 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))
+		Yyerror("invalid receiver type %v (%v / %v)", pa, Tconv(pa, FmtLong), Tconv(t, FmtLong))
 
 		return
 	}
 
-	pa = f
+	pa = mt
 	if local && !pa.Local {
 		Yyerror("cannot define new methods on non-local type %v", pa)
 		return
 	}
 
-	if isblanksym(sf) {
+	if isblanksym(msym) {
 		return
 	}
 
-	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)
+	if pa.IsStruct() {
+		for _, f := range pa.Fields().Slice() {
+			if f.Sym == msym {
+				Yyerror("type %v has both field and method named %v", pa, msym)
 				return
 			}
 		}
 	}
 
-	n := Nod(ODCLFIELD, newname(sf), nil)
+	n := Nod(ODCLFIELD, newname(msym), nil)
 	n.Type = t
 
-	var d *Type // last found
-	for f := pa.Method; f != nil; f = f.Down {
-		d = f
-		if f.Etype != TFIELD {
-			Fatalf("addmethod: not TFIELD: %v", Tconv(f, obj.FmtLong))
-		}
-		if sf.Name != f.Sym.Name {
+	for _, f := range pa.Methods().Slice() {
+		if msym.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)
+		// Eqtype only checks that incoming and result parameters match,
+		// so explicitly check that the receiver parameters match too.
+		if !Eqtype(t, f.Type) || !Eqtype(t.Recv().Type, f.Type.Recv().Type) {
+			Yyerror("method redeclared: %v.%v\n\t%v\n\t%v", pa, msym, f.Type, t)
 		}
 		return
 	}
 
-	f = structfield(n)
+	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 {
-		Fatalf("imported method name %v in wrong package %s\n", Sconv(f.Sym, obj.FmtSign), structpkg.Name)
+	if tpkg != nil && f.Sym != nil && !exportname(f.Sym.Name) && f.Sym.Pkg != tpkg {
+		Fatalf("imported method name %v in wrong package %s\n", sconv(f.Sym, FmtSign), tpkg.Name)
 	}
 
-	if d == nil {
-		pa.Method = f
-	} else {
-		d.Down = f
-	}
-	return
+	pa.Methods().Append(f)
 }
 
 func funccompile(n *Node) {
@@ -1449,8 +1286,17 @@ func funccompile(n *Node) {
 	Funcdepth = n.Func.Depth + 1
 	compile(n)
 	Curfn = nil
+	Pc = nil
+	continpc = nil
+	breakpc = nil
 	Funcdepth = 0
 	dclcontext = PEXTERN
+	if nerrors != 0 {
+		// If we have compile errors, ignore any assembler/linker errors.
+		Ctxt.DiagFunc = func(string, ...interface{}) {}
+	}
+	flushdata()
+	obj.Flushplist(Ctxt) // convert from Prog list to machine code
 }
 
 func funcsym(s *Sym) *Sym {
@@ -1467,7 +1313,7 @@ func makefuncsym(s *Sym) {
 	if isblanksym(s) {
 		return
 	}
-	if compiling_runtime != 0 && s.Name == "getg" {
+	if compiling_runtime && s.Name == "getg" {
 		// runtime.getg() is not a real function and so does
 		// not get a funcsym.
 		return
@@ -1525,7 +1371,7 @@ func checknowritebarrierrec() {
 
 		// Check nowritebarrierrec functions.
 		for _, n := range list {
-			if !n.Func.Nowritebarrierrec {
+			if n.Func.Pragma&Nowritebarrierrec == 0 {
 				continue
 			}
 			call, hasWB := c.best[n]
@@ -1536,19 +1382,19 @@ func checknowritebarrierrec() {
 			// Build the error message in reverse.
 			err := ""
 			for call.target != nil {
-				err = fmt.Sprintf("\n\t%v: called by %v%s", Ctxt.Line(int(call.lineno)), n.Func.Nname, err)
+				err = fmt.Sprintf("\n\t%v: called by %v%s", linestr(call.lineno), n.Func.Nname, err)
 				n = call.target
 				call = c.best[n]
 			}
 			err = fmt.Sprintf("write barrier prohibited by caller; %v%s", n.Func.Nname, err)
-			yyerrorl(int(n.Func.WBLineno), err)
+			yyerrorl(n.Func.WBLineno, err)
 		}
 	})
 }
 
-func (c *nowritebarrierrecChecker) visitcodelist(l *NodeList) {
-	for ; l != nil; l = l.Next {
-		c.visitcode(l.N)
+func (c *nowritebarrierrecChecker) visitcodelist(l Nodes) {
+	for _, n := range l.Slice() {
+		c.visitcode(n)
 	}
 }
 
@@ -1572,12 +1418,12 @@ func (c *nowritebarrierrecChecker) visitcode(n *Node) {
 func (c *nowritebarrierrecChecker) visitcall(n *Node) {
 	fn := n.Left
 	if n.Op == OCALLMETH {
-		fn = n.Left.Right.Sym.Def
+		fn = n.Left.Sym.Def
 	}
 	if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil {
 		return
 	}
-	if (compiling_runtime != 0 || fn.Sym.Pkg == Runtimepkg) && fn.Sym.Name == "allocm" {
+	if (compiling_runtime || fn.Sym.Pkg == Runtimepkg) && fn.Sym.Name == "allocm" {
 		return
 	}
 	defn := fn.Name.Defn
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 06b6082..90ad75c 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -5,7 +5,6 @@
 package gc
 
 import (
-	"cmd/internal/obj"
 	"fmt"
 	"strconv"
 	"strings"
@@ -15,7 +14,7 @@ import (
 // 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
+// in the static call graph. The algorithm for doing that is taken
 // from Sedgewick, Algorithms, Second Edition, p. 482, with two
 // adaptations.
 //
@@ -54,13 +53,13 @@ type bottomUpVisitor struct {
 // 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 []*Node, recursive bool)) {
+func visitBottomUp(list []*Node, analyze func(list []*Node, 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)
+	for _, n := range list {
+		if n.Op == ODCLFUNC && n.Func.FCurfn == nil {
+			v.visit(n)
 		}
 	}
 }
@@ -110,9 +109,9 @@ func (v *bottomUpVisitor) visit(n *Node) uint32 {
 	return min
 }
 
-func (v *bottomUpVisitor) visitcodelist(l *NodeList, min uint32) uint32 {
-	for ; l != nil; l = l.Next {
-		min = v.visitcode(l.N, min)
+func (v *bottomUpVisitor) visitcodelist(l Nodes, min uint32) uint32 {
+	for _, n := range l.Slice() {
+		min = v.visitcode(n, min)
 	}
 	return min
 }
@@ -132,7 +131,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
 	if n.Op == OCALLFUNC || n.Op == OCALLMETH {
 		fn := n.Left
 		if n.Op == OCALLMETH {
-			fn = n.Left.Right.Sym.Def
+			fn = n.Left.Sym.Def
 		}
 		if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil {
 			m := v.visit(fn.Name.Defn)
@@ -161,7 +160,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
 //
 // 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
+// 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
@@ -173,7 +172,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
 // 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
+// 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.
 //
@@ -183,7 +182,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
 // needs to be moved to the heap, and new(T) and slice
 // literals are always real allocations.
 
-func escapes(all *NodeList) {
+func escapes(all []*Node) {
 	visitBottomUp(all, escAnalyze)
 }
 
@@ -298,10 +297,20 @@ func (l Level) guaranteedDereference() int {
 	return int(l.suffixValue)
 }
 
+// An EscStep documents one step in the path from memory
+// that is heap allocated to the (alleged) reason for the
+// heap allocation.
+type EscStep struct {
+	src, dst *Node    // the endpoints of this edge in the escape-to-heap chain.
+	parent   *EscStep // used in flood to record path
+	why      string   // explanation for this step in the escape-to-heap chain
+	busy     bool     // used in prevent to snip cycles.
+}
+
 type NodeEscState struct {
 	Curfn             *Node
-	Escflowsrc        *NodeList // flow(this, src)
-	Escretval         *NodeList // on OCALLxxx, list of dummy return values
+	Escflowsrc        []EscStep // flow(this, src)
+	Escretval         Nodes     // 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
@@ -329,11 +338,11 @@ func (e *EscState) track(n *Node) {
 	n.Esc = EscNone // until proven otherwise
 	nE := e.nodeEscState(n)
 	nE.Escloopdepth = e.loopdepth
-	e.noesc = list(e.noesc, n)
+	e.noesc = append(e.noesc, n)
 }
 
 // Escape constants are numbered in order of increasing "escapiness"
-// to help make inferences be monotonic.  With the exception of
+// 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 (
@@ -371,7 +380,7 @@ func escMax(e, etype uint16) uint16 {
 }
 
 // For each input parameter to a function, the escapeReturnEncoding describes
-// how the parameter may leak to the function's outputs.  This is currently the
+// 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. )
@@ -389,17 +398,39 @@ type EscState struct {
 	// 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
+	dsts      []*Node // all dst nodes
+	loopdepth int32   // for detecting nested loop scopes
+	pdepth    int     // for debug printing in recursions.
+	dstcount  int     // diagnostic
+	edgecount int     // diagnostic
+	noesc     []*Node // 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
 }
 
+func (e *EscState) stepWalk(dst, src *Node, why string, parent *EscStep) *EscStep {
+	// TODO: keep a cache of these, mark entry/exit in escwalk to avoid allocation
+	// Or perhaps never mind, since it is disabled unless printing is on.
+	// We may want to revisit this, since the EscStep nodes would make
+	// an excellent replacement for the poorly-separated graph-build/graph-flood
+	// stages.
+	if Debug['m'] == 0 {
+		return nil
+	}
+	return &EscStep{src: src, dst: dst, why: why, parent: parent}
+}
+
+func (e *EscState) stepAssign(step *EscStep, dst, src *Node, why string) *EscStep {
+	if Debug['m'] == 0 {
+		return nil
+	}
+	if step != nil { // Caller may have known better.
+		return step
+	}
+	return &EscStep{src: src, dst: dst, why: why}
+}
+
 // 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 {
@@ -424,15 +455,15 @@ func escAnalyze(all []*Node, recursive bool) {
 	e.nodeEscState(&e.theSink).Escloopdepth = -1
 	e.recursive = recursive
 
-	for i := len(all) - 1; i >= 0; i-- {
-		if n := all[i]; n.Op == ODCLFUNC {
+	for _, n := range all {
+		if n.Op == ODCLFUNC {
 			n.Esc = EscFuncPlanned
 		}
 	}
 
 	// flow-analyze functions
-	for i := len(all) - 1; i >= 0; i-- {
-		if n := all[i]; n.Op == ODCLFUNC {
+	for _, n := range all {
+		if n.Op == ODCLFUNC {
 			escfunc(e, n)
 		}
 	}
@@ -441,21 +472,21 @@ func escAnalyze(all []*Node, recursive bool) {
 
 	// 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 _, n := range e.dsts {
+		escflood(e, n)
 	}
 
 	// for all top level functions, tag the typenodes corresponding to the param nodes
-	for i := len(all) - 1; i >= 0; i-- {
-		if n := all[i]; n.Op == ODCLFUNC {
+	for _, n := range all {
+		if n.Op == ODCLFUNC {
 			esctag(e, 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 _, n := range e.noesc {
+			if n.Esc == EscNone {
+				Warnl(n.Lineno, "%v %v does not escape", e.curfnSym(n), Nconv(n, FmtShort))
 			}
 		}
 	}
@@ -476,35 +507,35 @@ func escfunc(e *EscState, func_ *Node) {
 	savefn := Curfn
 	Curfn = func_
 
-	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-		if ll.N.Op != ONAME {
+	for _, ln := range Curfn.Func.Dcl {
+		if ln.Op != ONAME {
 			continue
 		}
-		llNE := e.nodeEscState(ll.N)
-		switch ll.N.Class {
+		llNE := e.nodeEscState(ln)
+		switch ln.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) {
+			if ln.Type != nil && !haspointers(ln.Type) {
 				break
 			}
-			if Curfn.Nbody == nil && !Curfn.Noescape {
-				ll.N.Esc = EscHeap
+			if Curfn.Nbody.Len() == 0 && !Curfn.Noescape {
+				ln.Esc = EscHeap
 			} else {
-				ll.N.Esc = EscNone // prime for escflood later
+				ln.Esc = EscNone // prime for escflood later
 			}
-			e.noesc = list(e.noesc, ll.N)
+			e.noesc = append(e.noesc, ln)
 		}
 	}
 
 	// 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)
+		for _, ln := range Curfn.Func.Dcl {
+			if ln.Op == ONAME && ln.Class == PPARAMOUT {
+				escflows(e, &e.theSink, ln, e.stepAssign(nil, ln, ln, "returned from recursive function"))
 			}
 		}
 	}
@@ -517,14 +548,14 @@ func escfunc(e *EscState, func_ *Node) {
 
 // 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.
+// 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 escloopdepthlist(e *EscState, l Nodes) {
+	for _, n := range l.Slice() {
+		escloopdepth(e, n)
 	}
 }
 
@@ -538,7 +569,7 @@ func escloopdepth(e *EscState, n *Node) {
 	switch n.Op {
 	case OLABEL:
 		if n.Left == nil || n.Left.Sym == nil {
-			Fatalf("esc:label without label: %v", Nconv(n, obj.FmtSign))
+			Fatalf("esc:label without label: %v", Nconv(n, FmtSign))
 		}
 
 		// Walk will complain about this label being already defined, but that's not until
@@ -549,7 +580,7 @@ func escloopdepth(e *EscState, n *Node) {
 
 	case OGOTO:
 		if n.Left == nil || n.Left.Sym == nil {
-			Fatalf("esc:goto without label: %v", Nconv(n, obj.FmtSign))
+			Fatalf("esc:goto without label: %v", Nconv(n, FmtSign))
 		}
 
 		// If we come past one that's uninitialized, this must be a (harmless) forward jump
@@ -566,9 +597,9 @@ func escloopdepth(e *EscState, n *Node) {
 	escloopdepthlist(e, n.Rlist)
 }
 
-func esclist(e *EscState, l *NodeList, up *Node) {
-	for ; l != nil; l = l.Next {
-		esc(e, l.N, up)
+func esclist(e *EscState, l Nodes, up *Node) {
+	for _, n := range l.Slice() {
+		esc(e, n, up)
 	}
 }
 
@@ -576,8 +607,14 @@ func esc(e *EscState, n *Node, up *Node) {
 	if n == nil {
 		return
 	}
+	if n.Type == structkey {
+		// This is the left side of x:y in a struct literal.
+		// x is syntax, not an expression.
+		// See #14405.
+		return
+	}
 
-	lno := int(setlineno(n))
+	lno := setlineno(n)
 
 	// ninit logically runs at a different loopdepth than the rest of the for loop.
 	esclist(e, n.Ninit, n)
@@ -591,26 +628,26 @@ func esc(e *EscState, n *Node, up *Node) {
 	// 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
+		for _, n1 := range n.List.Slice() { // cases
+			// it.N().Rlist is the variable per case
+			if n1.Rlist.Len() != 0 {
+				e.nodeEscState(n1.Rlist.First()).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)
+	if n.Esc != EscHeap && n.Type != nil &&
+		(n.Type.Width > MaxStackVarSize ||
+			(n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 ||
+			n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
+		if Debug['m'] > 2 {
+			Warnl(n.Lineno, "%v is too large for stack", n)
 		}
 		n.Esc = EscHeap
 		addrescapes(n)
-		escassign(e, &e.theSink, n)
+		escassignSinkNilWhy(e, n, n, "too large for stack") // TODO category: tooLarge
 	}
 
 	esc(e, n.Left, n)
@@ -623,8 +660,8 @@ func esc(e *EscState, n *Node, up *Node) {
 		e.loopdepth--
 	}
 
-	if Debug['m'] > 1 {
-		fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n)
+	if Debug['m'] > 2 {
+		fmt.Printf("%v:[%d] %v esc: %v\n", linestr(lineno), e.loopdepth, funcSym(Curfn), n)
 	}
 
 	switch n.Op {
@@ -636,12 +673,12 @@ func esc(e *EscState, n *Node, up *Node) {
 
 	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)
+			if Debug['m'] > 2 {
+				fmt.Printf("%v:%v non-looping label\n", linestr(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)
+			if Debug['m'] > 2 {
+				fmt.Printf("%v: %v looping label\n", linestr(lineno), n)
 			}
 			e.loopdepth++
 		}
@@ -653,28 +690,28 @@ func esc(e *EscState, n *Node, up *Node) {
 		n.Left.Sym.Label = nil
 
 	case ORANGE:
-		if n.List != nil && n.List.Next != nil {
+		if n.List.Len() >= 2 {
 			// Everything but fixed array is a dereference.
 
 			// If fixed array is really the address of fixed array,
 			// it is also a dereference, because it is implicitly
 			// dereferenced (see #12588)
-			if Isfixedarray(n.Type) &&
-				!(Isptr[n.Right.Type.Etype] && Eqtype(n.Right.Type.Type, n.Type)) {
-				escassign(e, n.List.Next.N, n.Right)
+			if n.Type.IsArray() &&
+				!(n.Right.Type.IsPtr() && Eqtype(n.Right.Type.Elem(), n.Type)) {
+				escassignNilWhy(e, n.List.Second(), n.Right, "range")
 			} else {
-				escassignDereference(e, n.List.Next.N, n.Right)
+				escassignDereference(e, n.List.Second(), n.Right, e.stepAssign(nil, n.List.Second(), n.Right, "range-deref"))
 			}
 		}
 
 	case OSWITCH:
 		if n.Left != nil && n.Left.Op == OTYPESW {
-			for ll := n.List; ll != nil; ll = ll.Next {
+			for _, n2 := range n.List.Slice() {
 				// 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)
+				// it.N().Rlist is the variable per case
+				if n2.Rlist.Len() != 0 {
+					escassignNilWhy(e, n2.Rlist.First(), n.Left.Right, "switch case")
 				}
 			}
 		}
@@ -706,30 +743,31 @@ func esc(e *EscState, n *Node, up *Node) {
 			// 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))
+				Warnl(n.Lineno, "%v ignoring self-assignment to %v", e.curfnSym(n), Nconv(n.Left, FmtShort))
 			}
 
 			break
 		}
 
-		escassign(e, n.Left, n.Right)
+		escassign(e, n.Left, n.Right, nil)
 
 	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)
+		if n.List.Len() == n.Rlist.Len() {
+			rs := n.Rlist.Slice()
+			for i, n := range n.List.Slice() {
+				escassignNilWhy(e, n, rs[i], "assign-pair")
 			}
 		}
 
-	case OAS2RECV, // v, ok = <-ch
-		OAS2MAPR,    // v, ok = m[k]
-		OAS2DOTTYPE: // v, ok = x.(type)
-		escassign(e, n.List.N, n.Rlist.N)
+	case OAS2RECV: // v, ok = <-ch
+		escassignNilWhy(e, n.List.First(), n.Rlist.First(), "assign-pair-receive")
+	case OAS2MAPR: // v, ok = m[k]
+		escassignNilWhy(e, n.List.First(), n.Rlist.First(), "assign-pair-mapr")
+	case OAS2DOTTYPE: // v, ok = x.(type)
+		escassignNilWhy(e, n.List.First(), n.Rlist.First(), "assign-pair-dot-type")
 
 	case OSEND: // ch <- x
-		escassign(e, &e.theSink, n.Right)
+		escassignSinkNilWhy(e, n, n.Right, "send")
 
 	case ODEFER:
 		if e.loopdepth == 1 { // top level
@@ -737,15 +775,21 @@ func esc(e *EscState, n *Node, up *Node) {
 		}
 		// arguments leak out of scope
 		// TODO: leak to a dummy node instead
-		fallthrough
+		// defer f(x) - f and x escape
+		escassignSinkNilWhy(e, n, n.Left.Left, "defer func")
+
+		escassignSinkNilWhy(e, n, n.Left.Right, "defer func ...") // ODDDARG for call
+		for _, n4 := range n.Left.List.Slice() {
+			escassignSinkNilWhy(e, n, n4, "defer func arg")
+		}
 
 	case OPROC:
 		// go f(x) - f and x escape
-		escassign(e, &e.theSink, n.Left.Left)
+		escassignSinkNilWhy(e, n, n.Left.Left, "go func")
 
-		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)
+		escassignSinkNilWhy(e, n, n.Left.Right, "go func ...") // ODDDARG for call
+		for _, n4 := range n.Left.List.Slice() {
+			escassignSinkNilWhy(e, n, n4, "go func arg")
 		}
 
 	case OCALLMETH, OCALLFUNC, OCALLINTER:
@@ -753,122 +797,124 @@ func esc(e *EscState, n *Node, up *Node) {
 
 		// 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)
+		rs := e.nodeEscState(n.Rlist.First()).Escretval.Slice()
+		for i, n := range n.List.Slice() {
+			if i >= len(rs) {
+				break
+			}
+			escassignNilWhy(e, n, rs[i], "assign-pair-func-call")
 		}
-		if lr != nil || ll != nil {
+		if n.List.Len() != len(rs) {
 			Fatalf("esc oas2func")
 		}
 
 	case ORETURN:
 		ll := n.List
-		if count(n.List) == 1 && Curfn.Type.Outtuple > 1 {
+		if n.List.Len() == 1 && Curfn.Type.Results().NumFields() > 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
+			ll = e.nodeEscState(n.List.First()).Escretval
 		}
 
-		for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next {
-			if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT {
+		i := 0
+		for _, lrn := range Curfn.Func.Dcl {
+			if i >= ll.Len() {
+				break
+			}
+			if lrn.Op != ONAME || lrn.Class != PPARAMOUT {
 				continue
 			}
-			escassign(e, lr.N, ll.N)
-			ll = ll.Next
+			escassignNilWhy(e, lrn, ll.Index(i), "return")
+			i++
 		}
 
-		if ll != nil {
+		if i < ll.Len() {
 			Fatalf("esc return list")
 		}
 
 		// Argument could leak through recover.
 	case OPANIC:
-		escassign(e, &e.theSink, n.Left)
+		escassignSinkNilWhy(e, n, n.Left, "panic")
 
 	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
+			for _, nn := range n.List.Slice()[1:] {
+				escassignSinkNilWhy(e, n, nn, "appended to slice") // 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))
+			slice2 := n.List.Second()
+			escassignDereference(e, &e.theSink, slice2, e.stepAssign(nil, n, slice2, "appended slice...")) // lose track of assign of dereference
+			if Debug['m'] > 3 {
+				Warnl(n.Lineno, "%v special treatment of append(slice1, slice2...) %v", e.curfnSym(n), Nconv(n, FmtShort))
 			}
 		}
-		escassignDereference(e, &e.theSink, n.List.N) // The original elements are now leaked, too
+		escassignDereference(e, &e.theSink, n.List.First(), e.stepAssign(nil, n, n.List.First(), "appendee slice")) // The original elements are now leaked, too
 
 	case OCOPY:
-		escassignDereference(e, &e.theSink, n.Right) // lose track of assign of dereference
+		escassignDereference(e, &e.theSink, n.Right, e.stepAssign(nil, n, n.Right, "copied slice")) // lose track of assign of dereference
 
 	case OCONV, OCONVNOP:
-		escassign(e, n, n.Left)
+		escassignNilWhy(e, n, n.Left, "converted")
 
 	case OCONVIFACE:
 		e.track(n)
-		escassign(e, n, n.Left)
+		escassignNilWhy(e, n, n.Left, "interface-converted")
 
 	case OARRAYLIT:
-		if Isslice(n.Type) {
+		why := "array literal element"
+		if n.Type.IsSlice() {
 			// Slice itself is not leaked until proven otherwise
 			e.track(n)
+			why = "slice literal element"
 		}
-
 		// Link values to array/slice
-		for ll := n.List; ll != nil; ll = ll.Next {
-			escassign(e, n, ll.N.Right)
+		for _, n5 := range n.List.Slice() {
+			escassign(e, n, n5.Right, e.stepAssign(nil, n, n5.Right, why))
 		}
 
 		// Link values to struct.
 	case OSTRUCTLIT:
-		for ll := n.List; ll != nil; ll = ll.Next {
-			escassign(e, n, ll.N.Right)
+		for _, n6 := range n.List.Slice() {
+			escassignNilWhy(e, n, n6.Right, "struct literal element")
 		}
 
 	case OPTRLIT:
 		e.track(n)
 
 		// Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too.
-		escassign(e, n, n.Left)
+		escassignNilWhy(e, n, n.Left, "pointer literal [assign]")
 
 	case OCALLPART:
 		e.track(n)
 
 		// Contents make it to memory, lose track.
-		escassign(e, &e.theSink, n.Left)
+		escassignSinkNilWhy(e, n, n.Left, "call part")
 
 	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)
+		for _, n7 := range n.List.Slice() {
+			escassignSinkNilWhy(e, n, n7.Left, "map literal key")
+			escassignSinkNilWhy(e, n, n7.Right, "map literal value")
 		}
 
-		// 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
+		// Link addresses of captured variables to closure.
+		for _, v := range n.Func.Cvars.Slice() {
 			if v.Op == OXXX { // unnamed out argument; see dcl.go:/^funcargs
 				continue
 			}
-			a = v.Name.Param.Closure
+			a := v.Name.Defn
 			if !v.Name.Byval {
 				a = Nod(OADDR, a, nil)
 				a.Lineno = v.Lineno
 				e.nodeEscState(a).Escloopdepth = e.loopdepth
-				typecheck(&a, Erv)
+				a = typecheck(a, Erv)
 			}
 
-			escassign(e, n, a)
+			escassignNilWhy(e, n, a, "captured by a closure")
 		}
 		fallthrough
 
@@ -917,27 +963,50 @@ func esc(e *EscState, n *Node, up *Node) {
 		}
 	}
 
-	lineno = int32(lno)
+	lineno = lno
+}
+
+// escassignNilWhy bundles a common case of
+// escassign(e, dst, src, e.stepAssign(nil, dst, src, reason))
+func escassignNilWhy(e *EscState, dst, src *Node, reason string) {
+	var step *EscStep
+	if Debug['m'] != 0 {
+		step = e.stepAssign(nil, dst, src, reason)
+	}
+	escassign(e, dst, src, step)
+}
+
+// escassignSinkNilWhy bundles a common case of
+// escassign(e, &e.theSink, src, e.stepAssign(nil, dst, src, reason))
+func escassignSinkNilWhy(e *EscState, dst, src *Node, reason string) {
+	var step *EscStep
+	if Debug['m'] != 0 {
+		step = e.stepAssign(nil, dst, src, reason)
+	}
+	escassign(e, &e.theSink, src, step)
 }
 
 // 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) {
+func escassign(e *EscState, dst, src *Node, step *EscStep) {
 	if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX {
 		return
 	}
 
-	if Debug['m'] > 1 {
+	if Debug['m'] > 2 {
 		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))
+			linestr(lineno), e.loopdepth, funcSym(Curfn),
+			Nconv(dst, FmtShort), jconv(dst, FmtShort), dst.Op,
+			Nconv(src, FmtShort), jconv(src, FmtShort), src.Op)
 	}
 
 	setlineno(dst)
 
+	originalDst := dst
+	dstwhy := "assigned"
+
 	// Analyze lhs of assignment.
 	// Replace dst with e->theSink if we can't track it.
 	switch dst.Op {
@@ -959,33 +1028,39 @@ func escassign(e *EscState, dst *Node, src *Node) {
 
 	case ONAME:
 		if dst.Class == PEXTERN {
+			dstwhy = "assigned to top level variable"
 			dst = &e.theSink
 		}
 
-	case ODOT: // treat "dst.x  = src" as "dst = src"
-		escassign(e, dst.Left, src)
-
+	case ODOT: // treat "dst.x = src" as "dst = src"
+		escassign(e, dst.Left, src, e.stepAssign(step, originalDst, src, "dot-equals"))
 		return
 
 	case OINDEX:
-		if Isfixedarray(dst.Left.Type) {
-			escassign(e, dst.Left, src)
+		if dst.Left.Type.IsArray() {
+			escassign(e, dst.Left, src, e.stepAssign(step, originalDst, src, "array-element-equals"))
 			return
 		}
 
+		dstwhy = "slice-element-equals"
 		dst = &e.theSink // lose track of dereference
 
-	case OIND, ODOTPTR:
+	case OIND:
+		dstwhy = "star-equals"
+		dst = &e.theSink // lose track of dereference
+
+	case ODOTPTR:
+		dstwhy = "star-dot-equals"
 		dst = &e.theSink // lose track of dereference
 
 		// lose track of key and value
 	case OINDEXMAP:
-		escassign(e, &e.theSink, dst.Right)
-
+		escassign(e, &e.theSink, dst.Right, e.stepAssign(nil, originalDst, src, "key of map put"))
+		dstwhy = "value of map put"
 		dst = &e.theSink
 	}
 
-	lno := int(setlineno(src))
+	lno := setlineno(src)
 	e.pdepth++
 
 	switch src.Op {
@@ -993,7 +1068,6 @@ func escassign(e *EscState, dst *Node, src *Node) {
 		OIND,    // dst = *x
 		ODOTPTR, // dst = (*x).f
 		ONAME,
-		OPARAM,
 		ODDDARG,
 		OPTRLIT,
 		OARRAYLIT,
@@ -1011,7 +1085,7 @@ func escassign(e *EscState, dst *Node, src *Node) {
 		OCALLPART,
 		ORUNESTR,
 		OCONVIFACE:
-		escflows(e, dst, src)
+		escflows(e, dst, src, e.stepAssign(step, originalDst, src, dstwhy))
 
 	case OCLOSURE:
 		// OCLOSURE is lowered to OPTRLIT,
@@ -1020,13 +1094,13 @@ func escassign(e *EscState, dst *Node, src *Node) {
 		a.Lineno = src.Lineno
 		e.nodeEscState(a).Escloopdepth = e.nodeEscState(src).Escloopdepth
 		a.Type = Ptrto(src.Type)
-		escflows(e, dst, a)
+		escflows(e, dst, a, e.stepAssign(nil, originalDst, src, dstwhy))
 
 	// 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)
+		for _, n := range e.nodeEscState(src).Escretval.Slice() {
+			escflows(e, dst, n, e.stepAssign(nil, originalDst, n, dstwhy))
 		}
 
 		// A non-pointer escaping from a struct does not concern us.
@@ -1042,7 +1116,6 @@ func escassign(e *EscState, dst *Node, src *Node) {
 		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,
@@ -1050,24 +1123,30 @@ func escassign(e *EscState, dst *Node, src *Node) {
 		OSLICE3ARR,
 		OSLICESTR:
 		// Conversions, field access, slice all preserve the input value.
-		escassign(e, dst, src.Left)
+		escassign(e, dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
+
+	case ODOTTYPE:
+		if src.Type != nil && !haspointers(src.Type) {
+			break
+		}
+		escassign(e, dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
 
 	case OAPPEND:
 		// Append returns first argument.
 		// Subsequent arguments are already leaked because they are operands to append.
-		escassign(e, dst, src.List.N)
+		escassign(e, dst, src.List.First(), e.stepAssign(step, dst, src.List.First(), dstwhy))
 
 	case OINDEX:
 		// Index of array preserves input value.
-		if Isfixedarray(src.Left.Type) {
-			escassign(e, dst, src.Left)
+		if src.Left.Type.IsArray() {
+			escassign(e, dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
 		} else {
-			escflows(e, dst, src)
+			escflows(e, dst, src, e.stepAssign(step, originalDst, src, dstwhy))
 		}
 
 		// Might be pointer arithmetic, in which case
 	// the operands flow into the result.
-	// TODO(rsc): Decide what the story is here.  This is unsettling.
+	// TODO(rsc): Decide what the story is here. This is unsettling.
 	case OADD,
 		OSUB,
 		OOR,
@@ -1082,13 +1161,13 @@ func escassign(e *EscState, dst *Node, src *Node) {
 		OPLUS,
 		OMINUS,
 		OCOM:
-		escassign(e, dst, src.Left)
+		escassign(e, dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
 
-		escassign(e, dst, src.Right)
+		escassign(e, dst, src.Right, e.stepAssign(step, originalDst, src, dstwhy))
 	}
 
 	e.pdepth--
-	lineno = int32(lno)
+	lineno = lno
 }
 
 // Common case for escapes is 16 bits 000000000xxxEEEE
@@ -1096,12 +1175,12 @@ func escassign(e *EscState, dst *Node, src *Node) {
 //  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
+// 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 {
+func mktag(mask int) string {
 	switch mask & EscMask {
 	case EscNone, EscReturn:
 		break
@@ -1111,22 +1190,22 @@ func mktag(mask int) *string {
 	}
 
 	if mask < len(tags) && tags[mask] != "" {
-		return &tags[mask]
+		return tags[mask]
 	}
 
 	s := fmt.Sprintf("esc:0x%x", mask)
 	if mask < len(tags) {
 		tags[mask] = s
 	}
-	return &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:") {
+func parsetag(note string) uint16 {
+	if !strings.HasPrefix(note, "esc:") {
 		return EscUnknown
 	}
-	n, _ := strconv.ParseInt((*note)[4:], 0, 0)
+	n, _ := strconv.ParseInt(note[4:], 0, 0)
 	em := uint16(n)
 	if em == 0 {
 		return EscNone
@@ -1188,19 +1267,19 @@ func describeEscape(em uint16) string {
 
 // 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 {
+func escassignfromtag(e *EscState, note string, dsts Nodes, src *Node) uint16 {
 	em := parsetag(note)
 	if src.Op == OLITERAL {
 		return em
 	}
 
-	if Debug['m'] > 2 {
+	if Debug['m'] > 3 {
 		fmt.Printf("%v::assignfromtag:: src=%v, em=%s\n",
-			Ctxt.Line(int(lineno)), Nconv(src, obj.FmtShort), describeEscape(em))
+			linestr(lineno), Nconv(src, FmtShort), describeEscape(em))
 	}
 
 	if em == EscUnknown {
-		escassign(e, &e.theSink, src)
+		escassignSinkNilWhy(e, src, src, "passed to function[unknown]")
 		return em
 	}
 
@@ -1211,11 +1290,12 @@ func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint
 	// If content inside parameter (reached via indirection)
 	// escapes to heap, mark as such.
 	if em&EscContentEscapes != 0 {
-		escassign(e, &e.theSink, e.addDereference(src))
+		escassign(e, &e.theSink, e.addDereference(src), e.stepAssign(nil, src, src, "passed to function[content escapes]"))
 	}
 
 	em0 := em
-	for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>bitsPerOutputInTag, dsts.Next {
+	dstsi := 0
+	for em >>= EscReturnBits; em != 0 && dstsi < dsts.Len(); em = em >> bitsPerOutputInTag {
 		// 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
@@ -1227,24 +1307,25 @@ func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint
 			for i := uint16(0); i < embits-1; i++ {
 				n = e.addDereference(n) // encode level>0 as indirections
 			}
-			escassign(e, dsts.N, n)
+			escassign(e, dsts.Index(dstsi), n, e.stepAssign(nil, dsts.Index(dstsi), src, "passed-to-and-returned-from-function"))
 		}
+		dstsi++
 	}
 	// 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 {
+	if em != 0 && dstsi >= dsts.Len() {
 		Fatalf("corrupt esc tag %q or messed up escretval list\n", note)
 	}
 	return em0
 }
 
-func escassignDereference(e *EscState, dst *Node, src *Node) {
+func escassignDereference(e *EscState, dst *Node, src *Node, step *EscStep) {
 	if src.Op == OLITERAL {
 		return
 	}
-	escassign(e, dst, e.addDereference(src))
+	escassign(e, dst, e.addDereference(src), step)
 }
 
 // addDereference constructs a suitable OIND note applied to src.
@@ -1255,11 +1336,11 @@ func (e *EscState) addDereference(n *Node) *Node {
 	e.nodeEscState(ind).Escloopdepth = e.nodeEscState(n).Escloopdepth
 	ind.Lineno = n.Lineno
 	t := n.Type
-	if Istype(t, Tptr) {
+	if t.IsKind(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
+		// might yield the type of an element. To be enhanced...
+		t = t.Elem()
 	}
 	ind.Type = t
 	return ind
@@ -1302,8 +1383,8 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
 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 {
+	nE.Escretval.Set(nil) // Suspect this is not nil for indirect calls.
+	for _, t := range fntype.Results().Fields().Slice() {
 		src := Nod(ONAME, nil, nil)
 		buf := fmt.Sprintf(".out%d", i)
 		i++
@@ -1314,7 +1395,7 @@ func initEscretval(e *EscState, n *Node, fntype *Type) {
 		e.nodeEscState(src).Escloopdepth = e.loopdepth
 		src.Used = true
 		src.Lineno = n.Lineno
-		nE.Escretval = list(nE.Escretval, src)
+		nE.Escretval.Append(src)
 	}
 }
 
@@ -1338,7 +1419,7 @@ func esccall(e *EscState, n *Node, up *Node) {
 		indirect = fn.Op != ONAME || fn.Class != PFUNC
 
 	case OCALLMETH:
-		fn = n.Left.Right.Sym.Def
+		fn = n.Left.Sym.Def
 		if fn != nil {
 			fntype = fn.Type
 		} else {
@@ -1351,9 +1432,9 @@ func esccall(e *EscState, n *Node, up *Node) {
 	}
 
 	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()).
+	if n.List.Len() == 1 {
+		a := n.List.First()
+		if a.Type.IsFuncArgStruct() { // f(g())
 			ll = e.nodeEscState(a).Escretval
 		}
 	}
@@ -1361,25 +1442,25 @@ func esccall(e *EscState, n *Node, up *Node) {
 	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))
+		for _, n1 := range ll.Slice() {
+			escassignSinkNilWhy(e, n, n1, "parameter to indirect call")
+			if Debug['m'] > 3 {
+				fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", linestr(lineno), Nconv(n1, 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
+			t := fntype.Recv()
 			src := n.Left.Left
 			if haspointers(t.Type) {
-				escassign(e, &e.theSink, src)
+				escassignSinkNilWhy(e, n, src, "receiver in indirect call")
 			}
 		} else { // indirect and OCALLFUNC = could be captured variables, too. (#14409)
-			ll = e.nodeEscState(n).Escretval
-			for ; ll != nil; ll = ll.Next {
-				escassignDereference(e, ll.N, fn)
+			ll := e.nodeEscState(n).Escretval.Slice()
+			for _, llN := range ll {
+				escassignDereference(e, llN, fn, e.stepAssign(nil, llN, fn, "captured by called closure"))
 			}
 		}
 		return
@@ -1387,68 +1468,72 @@ func esccall(e *EscState, n *Node, up *Node) {
 
 	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))
+		fn.Name.Defn != nil && fn.Name.Defn.Nbody.Len() != 0 && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged {
+		if Debug['m'] > 3 {
+			fmt.Printf("%v::esccall:: %v in recursive group\n", linestr(lineno), Nconv(n, FmtShort))
 		}
 
-		// function in same mutually recursive group.  Incorporate into flow graph.
+		// 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 {
+		if fn.Name.Defn.Esc == EscFuncUnknown || nE.Escretval.Len() != 0 {
 			Fatalf("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)
-		}
-
+		lls := ll.Slice()
+		sawRcvr := false
 		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
-			}
-		}
+		for _, n2 := range fn.Name.Defn.Func.Dcl {
+			switch n2.Class {
+			case PPARAM:
+				if n.Op != OCALLFUNC && !sawRcvr {
+					escassignNilWhy(e, n2, n.Left.Left, "call receiver")
+					sawRcvr = true
+					continue
+				}
+				if len(lls) == 0 {
+					continue
+				}
+				src = lls[0]
+				if n2.Isddd && !n.Isddd {
+					// Introduce ODDDARG node to represent ... allocation.
+					src = Nod(ODDDARG, nil, nil)
+					arr := typArray(n2.Type.Elem(), int64(len(lls)))
+					src.Type = Ptrto(arr) // make pointer so it will be tracked
+					src.Lineno = n.Lineno
+					e.track(src)
+					n.Right = src
+				}
+				escassignNilWhy(e, n2, src, "arg to recursive call")
+				if src != lls[0] {
+					// "..." arguments are untracked
+					for _, n2 := range lls {
+						if Debug['m'] > 3 {
+							fmt.Printf("%v::esccall:: ... <- %v, untracked\n", linestr(lineno), Nconv(n2, FmtShort))
+						}
+						escassignSinkNilWhy(e, src, n2, "... arg to recursive call")
+					}
+					// No more PPARAM processing, but keep
+					// going for PPARAMOUT.
+					lls = nil
+					continue
+				}
+				lls = lls[1:]
 
-		// "..." 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))
+			case PPARAMOUT:
+				nE.Escretval.Append(n2)
 			}
-			escassign(e, &e.theSink, ll.N)
 		}
 
 		return
 	}
 
-	// Imported or completely analyzed function.  Use the escape tags.
-	if nE.Escretval != nil {
-		Fatalf("esc already decorated call %v\n", Nconv(n, obj.FmtSign))
+	// Imported or completely analyzed function. Use the escape tags.
+	if nE.Escretval.Len() != 0 {
+		Fatalf("esc already decorated call %v\n", Nconv(n, FmtSign))
 	}
 
-	if Debug['m'] > 2 {
-		fmt.Printf("%v::esccall:: %v not recursive\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
+	if Debug['m'] > 3 {
+		fmt.Printf("%v::esccall:: %v not recursive\n", linestr(lineno), Nconv(n, FmtShort))
 	}
 
 	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
@@ -1458,7 +1543,7 @@ func esccall(e *EscState, n *Node, up *Node) {
 
 	// Receiver.
 	if n.Op != OCALLFUNC {
-		t := getthisx(fntype).Type
+		t := fntype.Recv()
 		src := n.Left.Left
 		if haspointers(t.Type) {
 			escassignfromtag(e, t.Note, nE.Escretval, src)
@@ -1466,22 +1551,24 @@ func esccall(e *EscState, n *Node, up *Node) {
 	}
 
 	var src *Node
-	for t := getinargx(fntype).Type; ll != nil; ll = ll.Next {
-		src = ll.N
+	note := ""
+	i := 0
+	lls := ll.Slice()
+	for t, it := IterFields(fntype.Params()); i < len(lls); i++ {
+		src = lls[i]
+		note = t.Note
 		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
+			arr := typArray(t.Type.Elem(), int64(len(lls)-i))
+			src.Type = Ptrto(arr) // 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 {
+			if escassignfromtag(e, note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC {
 				a := src
 				for a.Op == OCONVNOP {
 					a = a.Left
@@ -1507,24 +1594,34 @@ func esccall(e *EscState, n *Node, up *Node) {
 			}
 		}
 
-		if src != ll.N {
+		if src != lls[i] {
 			// This occurs when function parameter type Isddd and n not Isddd
 			break
 		}
-		t = t.Down
+
+		if note == uintptrEscapesTag {
+			escassignSinkNilWhy(e, src, src, "escaping uintptr")
+		}
+
+		t = it.Next()
 	}
 
-	for ; ll != nil; ll = ll.Next {
-		if Debug['m'] > 2 {
-			fmt.Printf("%v::esccall:: ... <- %v\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
+	// Store arguments into slice for ... arg.
+	for ; i < len(lls); i++ {
+		if Debug['m'] > 3 {
+			fmt.Printf("%v::esccall:: ... <- %v\n", linestr(lineno), Nconv(lls[i], FmtShort))
+		}
+		if note == uintptrEscapesTag {
+			escassignSinkNilWhy(e, src, lls[i], "arg to uintptrescapes ...")
+		} else {
+			escassignNilWhy(e, src, lls[i], "arg to ...")
 		}
-		escassign(e, src, ll.N) // args to slice
 	}
 }
 
 // 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) {
+func escflows(e *EscState, dst, src *Node, why *EscStep) {
 	if dst == nil || src == nil || dst == src {
 		return
 	}
@@ -1534,19 +1631,25 @@ func escflows(e *EscState, dst *Node, src *Node) {
 		return
 	}
 
-	if Debug['m'] > 2 {
-		fmt.Printf("%v::flows:: %v <- %v\n", Ctxt.Line(int(lineno)), Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort))
+	if Debug['m'] > 3 {
+		fmt.Printf("%v::flows:: %v <- %v\n", linestr(lineno), Nconv(dst, FmtShort), Nconv(src, FmtShort))
 	}
 
 	dstE := e.nodeEscState(dst)
-	if dstE.Escflowsrc == nil {
-		e.dsts = list(e.dsts, dst)
+	if len(dstE.Escflowsrc) == 0 {
+		e.dsts = append(e.dsts, dst)
 		e.dstcount++
 	}
 
 	e.edgecount++
 
-	dstE.Escflowsrc = list(dstE.Escflowsrc, src)
+	if why == nil {
+		dstE.Escflowsrc = append(dstE.Escflowsrc, EscStep{src: src})
+	} else {
+		starwhy := *why
+		starwhy.src = src // TODO: need to reconcile this w/ needs of explanations.
+		dstE.Escflowsrc = append(dstE.Escflowsrc, starwhy)
+	}
 }
 
 // Whenever we hit a reference node, the level goes up by one, and whenever
@@ -1554,9 +1657,9 @@ func escflows(e *EscState, dst *Node, src *Node) {
 // 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
+// so if this node is an OADDR, its argument should be marked as escaping iff
+// its currfn/e->loopdepth are different from the flood's root.
+// Once an object has been moved to the heap, all of its upstream should be considered
 // escaping to the global scope.
 func escflood(e *EscState, dst *Node) {
 	switch dst.Op {
@@ -1568,13 +1671,14 @@ func escflood(e *EscState, dst *Node) {
 	}
 
 	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)
+	if Debug['m'] > 2 {
+		fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, FmtShort), e.curfnSym(dst), dstE.Escloopdepth)
 	}
 
-	for l := dstE.Escflowsrc; l != nil; l = l.Next {
+	for i, l := range dstE.Escflowsrc {
 		e.walkgen++
-		escwalk(e, levelFrom(0), dst, l.N)
+		dstE.Escflowsrc[i].parent = nil
+		escwalk(e, levelFrom(0), dst, l.src, &dstE.Escflowsrc[i])
 	}
 }
 
@@ -1585,13 +1689,37 @@ func funcOutputAndInput(dst, src *Node) bool {
 		src.Op == ONAME && src.Class == PPARAM && src.Name.Curfn == dst.Name.Curfn
 }
 
+func (es *EscStep) describe(src *Node) {
+	if Debug['m'] < 2 {
+		return
+	}
+	step0 := es
+	for step := step0; step != nil && !step.busy; step = step.parent {
+		// TODO: We get cycles. Trigger is i = &i (where var i interface{})
+		step.busy = true
+		// The trail is a little odd because of how the
+		// graph is constructed.  The link to the current
+		// Node is parent.src unless parent is nil in which
+		// case it is step.dst.
+		nextDest := step.parent
+		dst := step.dst
+		if nextDest != nil {
+			dst = nextDest.src
+		}
+		Warnl(src.Lineno, "\tfrom %s (%s) at %s", dst, step.why, dst.Line())
+	}
+	for step := step0; step != nil && step.busy; step = step.parent {
+		step.busy = false
+	}
+}
+
 const NOTALOOPDEPTH = -1
 
-func escwalk(e *EscState, level Level, dst *Node, src *Node) {
-	escwalkBody(e, level, dst, src, NOTALOOPDEPTH)
+func escwalk(e *EscState, level Level, dst *Node, src *Node, step *EscStep) {
+	escwalkBody(e, level, dst, src, step, NOTALOOPDEPTH)
 }
 
-func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth int32) {
+func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep, extraloopdepth int32) {
 	if src.Op == OLITERAL {
 		return
 	}
@@ -1622,15 +1750,17 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth
 		modSrcLoopdepth = extraloopdepth
 	}
 
-	if Debug['m'] > 1 {
+	if Debug['m'] > 2 {
 		fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d] extraloopdepth=%v\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, extraloopdepth)
+			level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", src.Op, Nconv(src, FmtShort), jconv(src, FmtShort), e.curfnSym(src), srcE.Escloopdepth, extraloopdepth)
 	}
 
 	e.pdepth++
 
 	// Input parameter flowing to output parameter?
 	var leaks bool
+	var osrcesc uint16 // used to prevent duplicate error messages
+
 	dstE := e.nodeEscState(dst)
 	if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscScope && dst.Esc != EscHeap {
 		// This case handles:
@@ -1639,10 +1769,11 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth
 		// 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())
+			if Debug['m'] <= 2 {
+				Warnl(src.Lineno, "leaking param: %v to result %v level=%v", Nconv(src, FmtShort), dst.Sym, level.int())
+				step.describe(src)
 			} else {
-				Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level)
+				Warnl(src.Lineno, "leaking param: %v to result %v level=%v", Nconv(src, FmtShort), dst.Sym, level)
 			}
 		}
 		if src.Esc&EscMask != EscReturn {
@@ -1659,77 +1790,91 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth
 		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))
+			Warnl(src.Lineno, "mark escaped content: %v", Nconv(src, FmtShort))
+			step.describe(src)
 		}
 	}
 
 	leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Escloopdepth < modSrcLoopdepth
 
+	osrcesc = src.Esc
 	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))
+					if Debug['m'] <= 2 {
+						if osrcesc != src.Esc {
+							Warnl(src.Lineno, "leaking param content: %v", Nconv(src, FmtShort))
+							step.describe(src)
+						}
 					} 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, modSrcLoopdepth, Nconv(dst, obj.FmtShort))
+						Warnl(src.Lineno, "leaking param content: %v level=%v dst.eld=%v src.eld=%v dst=%v",
+							Nconv(src, FmtShort), level, dstE.Escloopdepth, modSrcLoopdepth, Nconv(dst, FmtShort))
 					}
 				}
 			} else {
 				src.Esc = EscScope
 				if Debug['m'] != 0 {
-					if Debug['m'] == 1 {
-						Warnl(int(src.Lineno), "leaking param: %v", Nconv(src, obj.FmtShort))
+
+					if Debug['m'] <= 2 {
+						Warnl(src.Lineno, "leaking param: %v", Nconv(src, FmtShort))
+						step.describe(src)
 					} 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, modSrcLoopdepth, Nconv(dst, obj.FmtShort))
+						Warnl(src.Lineno, "leaking param: %v level=%v dst.eld=%v src.eld=%v dst=%v",
+							Nconv(src, FmtShort), level, dstE.Escloopdepth, modSrcLoopdepth, Nconv(dst, FmtShort))
 					}
 				}
 			}
 		}
 
-		// Treat a PPARAMREF closure variable as equivalent to the
+		// Treat a captured closure variable as equivalent to the
 		// original variable.
-		if src.Class == PPARAMREF {
+		if src.isClosureVar() {
 			if leaks && Debug['m'] != 0 {
-				Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort))
+				Warnl(src.Lineno, "leaking closure reference %v", Nconv(src, FmtShort))
+				step.describe(src)
 			}
-			escwalk(e, level, dst, src.Name.Param.Closure)
+			escwalk(e, level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step))
 		}
 
 	case OPTRLIT, OADDR:
+		why := "pointer literal"
+		if src.Op == OADDR {
+			why = "address-of"
+		}
 		if leaks {
 			src.Esc = EscHeap
-			addrescapes(src.Left)
-			if Debug['m'] != 0 {
+			if Debug['m'] != 0 && osrcesc != src.Esc {
 				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, modSrcLoopdepth)
+				if Debug['m'] > 2 {
+					Warnl(src.Lineno, "%v escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
+						Nconv(p, FmtShort), level, dst, dstE.Escloopdepth, modSrcLoopdepth)
 				} else {
-					Warnl(int(src.Lineno), "%v escapes to heap", Nconv(p, obj.FmtShort))
+					Warnl(src.Lineno, "%v escapes to heap", Nconv(p, FmtShort))
+					step.describe(src)
 				}
 			}
-			escwalkBody(e, level.dec(), dst, src.Left, modSrcLoopdepth)
+			addrescapes(src.Left)
+			escwalkBody(e, level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step), modSrcLoopdepth)
 			extraloopdepth = modSrcLoopdepth // passes to recursive case, seems likely a no-op
 		} else {
-			escwalk(e, level.dec(), dst, src.Left)
+			escwalk(e, level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step))
 		}
 
 	case OAPPEND:
-		escwalk(e, level, dst, src.List.N)
+		escwalk(e, level, dst, src.List.First(), e.stepWalk(dst, src.List.First(), "append-first-arg", step))
 
 	case ODDDARG:
 		if leaks {
 			src.Esc = EscHeap
-			if Debug['m'] != 0 {
-				Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort))
+			if Debug['m'] != 0 && osrcesc != src.Esc {
+				Warnl(src.Lineno, "%v escapes to heap", Nconv(src, FmtShort))
+				step.describe(src)
 			}
 			extraloopdepth = modSrcLoopdepth
 		}
@@ -1737,11 +1882,11 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth
 		level = level.dec()
 
 	case OARRAYLIT:
-		if Isfixedarray(src.Type) {
+		if src.Type.IsArray() {
 			break
 		}
-		for ll := src.List; ll != nil; ll = ll.Next {
-			escwalk(e, level.dec(), dst, ll.N.Right)
+		for _, n1 := range src.List.Slice() {
+			escwalk(e, level.dec(), dst, n1.Right, e.stepWalk(dst, n1.Right, "slice-literal-element", step))
 		}
 
 		fallthrough
@@ -1762,30 +1907,38 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth
 		OCONVIFACE:
 		if leaks {
 			src.Esc = EscHeap
-			if Debug['m'] != 0 {
-				Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort))
+			if Debug['m'] != 0 && osrcesc != src.Esc {
+				Warnl(src.Lineno, "%v escapes to heap", Nconv(src, FmtShort))
+				step.describe(src)
 			}
 			extraloopdepth = modSrcLoopdepth
 		}
 
 	case ODOT,
-		ODOTTYPE,
+		ODOTTYPE:
+		escwalk(e, level, dst, src.Left, e.stepWalk(dst, src.Left, "dot", step))
+
+	case
 		OSLICE,
 		OSLICEARR,
 		OSLICE3,
 		OSLICE3ARR,
 		OSLICESTR:
-		escwalk(e, level, dst, src.Left)
+		escwalk(e, level, dst, src.Left, e.stepWalk(dst, src.Left, "slice", step))
 
 	case OINDEX:
-		if Isfixedarray(src.Left.Type) {
-			escwalk(e, level, dst, src.Left)
+		if src.Left.Type.IsArray() {
+			escwalk(e, level, dst, src.Left, e.stepWalk(dst, src.Left, "fixed-array-index-of", step))
 			break
 		}
 		fallthrough
 
-	case ODOTPTR, OINDEXMAP, OIND:
-		escwalk(e, level.inc(), dst, src.Left)
+	case ODOTPTR:
+		escwalk(e, level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "dot of pointer", step))
+	case OINDEXMAP:
+		escwalk(e, level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "map index", step))
+	case OIND:
+		escwalk(e, level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "indirection", step))
 
 	// 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
@@ -1793,21 +1946,23 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, extraloopdepth
 	// 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 {
+		if srcE.Escretval.Len() != 0 {
+			if Debug['m'] > 2 {
 				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))
+					linestr(lineno), e.loopdepth,
+					Nconv(dst, FmtShort), Nconv(src, FmtShort), Nconv(srcE.Escretval.First(), FmtShort))
 			}
-			src = srcE.Escretval.N
+			src = srcE.Escretval.First()
 			srcE = e.nodeEscState(src)
 		}
 	}
 
 recurse:
 	level = level.copy()
-	for ll := srcE.Escflowsrc; ll != nil; ll = ll.Next {
-		escwalkBody(e, level, dst, ll.N, extraloopdepth)
+	for i, ll := range srcE.Escflowsrc {
+		srcE.Escflowsrc[i].parent = step
+		escwalkBody(e, level, dst, ll.src, &srcE.Escflowsrc[i], extraloopdepth)
+		srcE.Escflowsrc[i].parent = nil
 	}
 
 	e.pdepth--
@@ -1820,14 +1975,25 @@ recurse:
 // lets us take the address below to get a *string.
 var unsafeUintptrTag = "unsafe-uintptr"
 
+// This special tag is applied to uintptr parameters of functions
+// marked go:uintptrescapes.
+const uintptrEscapesTag = "uintptr-escapes"
+
 func esctag(e *EscState, func_ *Node) {
 	func_.Esc = EscFuncTagged
 
+	name := func(s *Sym, narg int) string {
+		if s != nil {
+			return s.Name
+		}
+		return fmt.Sprintf("arg#%d", narg)
+	}
+
 	// External functions are assumed unsafe,
 	// unless //go:noescape is given before the declaration.
-	if func_.Nbody == nil {
+	if func_.Nbody.Len() == 0 {
 		if func_.Noescape {
-			for t := getinargx(func_.Type).Type; t != nil; t = t.Down {
+			for _, t := range func_.Type.Params().Fields().Slice() {
 				if haspointers(t.Type) {
 					t.Note = mktag(EscNone)
 				}
@@ -1841,38 +2007,55 @@ func esctag(e *EscState, func_ *Node) {
 		// but we are reusing the ability to annotate an individual function
 		// argument and pass those annotations along to importing code.
 		narg := 0
-		for t := getinargx(func_.Type).Type; t != nil; t = t.Down {
+		for _, t := range func_.Type.Params().Fields().Slice() {
 			narg++
 			if t.Type.Etype == TUINTPTR {
 				if Debug['m'] != 0 {
-					var name string
-					if t.Sym != nil {
-						name = t.Sym.Name
-					} else {
-						name = fmt.Sprintf("arg#%d", narg)
-					}
-					Warnl(int(func_.Lineno), "%v assuming %v is unsafe uintptr", funcSym(func_), name)
+					Warnl(func_.Lineno, "%v assuming %v is unsafe uintptr", funcSym(func_), name(t.Sym, narg))
 				}
-				t.Note = &unsafeUintptrTag
+				t.Note = unsafeUintptrTag
 			}
 		}
 
 		return
 	}
 
+	if func_.Func.Pragma&UintptrEscapes != 0 {
+		narg := 0
+		for _, t := range func_.Type.Params().Fields().Slice() {
+			narg++
+			if t.Type.Etype == TUINTPTR {
+				if Debug['m'] != 0 {
+					Warnl(func_.Lineno, "%v marking %v as escaping uintptr", funcSym(func_), name(t.Sym, narg))
+				}
+				t.Note = uintptrEscapesTag
+			}
+
+			if t.Isddd && t.Type.Elem().Etype == TUINTPTR {
+				// final argument is ...uintptr.
+				if Debug['m'] != 0 {
+					Warnl(func_.Lineno, "%v marking %v as escaping ...uintptr", funcSym(func_), name(t.Sym, narg))
+				}
+				t.Note = uintptrEscapesTag
+			}
+		}
+	}
+
 	savefn := Curfn
 	Curfn = func_
 
-	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-		if ll.N.Op != ONAME {
+	for _, ln := range Curfn.Func.Dcl {
+		if ln.Op != ONAME {
 			continue
 		}
 
-		switch ll.N.Esc & EscMask {
+		switch ln.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))
+			if haspointers(ln.Type) { // don't bother tagging for scalars
+				if ln.Name.Param.Field.Note != uintptrEscapesTag {
+					ln.Name.Param.Field.Note = mktag(int(ln.Esc))
+				}
 			}
 
 		case EscHeap, // touched by escflood, moved to heap
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index e50cf38..911ef0f 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -5,8 +5,9 @@
 package gc
 
 import (
+	"bufio"
 	"bytes"
-	"cmd/internal/obj"
+	"cmd/internal/bio"
 	"fmt"
 	"sort"
 	"unicode"
@@ -14,8 +15,8 @@ import (
 )
 
 var (
-	newexport    int // if set, use new export format
-	Debug_export int // if set, print debugging information about export data
+	newexport    bool // if set, use new export format
+	Debug_export int  // if set, print debugging information about export data
 	exportsize   int
 )
 
@@ -27,7 +28,7 @@ func exportf(format string, args ...interface{}) {
 	}
 }
 
-var asmlist *NodeList
+var asmlist []*Node
 
 // Mark n's symbol as exported
 func exportsym(n *Node) {
@@ -89,7 +90,7 @@ func autoexport(n *Node, ctxt Class) {
 	}
 	if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 {
 		n.Sym.Flags |= SymAsm
-		asmlist = list(asmlist, n)
+		asmlist = append(asmlist, n)
 	}
 }
 
@@ -106,9 +107,9 @@ func dumppkg(p *Pkg) {
 }
 
 // Look for anything we need for the inline body
-func reexportdeplist(ll *NodeList) {
-	for ; ll != nil; ll = ll.Next {
-		reexportdep(ll.N)
+func reexportdeplist(ll Nodes) {
+	for _, n := range ll.Slice() {
+		reexportdep(n)
 	}
 }
 
@@ -120,7 +121,7 @@ func reexportdep(n *Node) {
 	//print("reexportdep %+hN\n", n);
 	switch n.Op {
 	case ONAME:
-		switch n.Class &^ PHEAP {
+		switch n.Class {
 		// methods will be printed along with their type
 		// nodes for T.Method expressions
 		case PFUNC:
@@ -129,7 +130,7 @@ func reexportdep(n *Node) {
 			}
 
 			// nodes for method calls.
-			if n.Type == nil || n.Type.Thistuple > 0 {
+			if n.Type == nil || n.Type.Recv() != nil {
 				break
 			}
 			fallthrough
@@ -148,8 +149,8 @@ func reexportdep(n *Node) {
 		t := n.Left.Type
 
 		if t != Types[t.Etype] && t != idealbool && t != idealstring {
-			if Isptr[t.Etype] {
-				t = t.Type
+			if t.IsPtr() {
+				t = t.Elem()
 			}
 			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
 				if Debug['E'] != 0 {
@@ -162,8 +163,8 @@ func reexportdep(n *Node) {
 	case OLITERAL:
 		t := n.Type
 		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
-			if Isptr[t.Etype] {
-				t = t.Type
+			if t.IsPtr() {
+				t = t.Elem()
 			}
 			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
 				if Debug['E'] != 0 {
@@ -175,7 +176,7 @@ func reexportdep(n *Node) {
 		fallthrough
 
 	case OTYPE:
-		if n.Sym != nil && !exportedsym(n.Sym) {
+		if n.Sym != nil && n.Sym.Def != nil && !exportedsym(n.Sym) {
 			if Debug['E'] != 0 {
 				fmt.Printf("reexport literal/type %v\n", n.Sym)
 			}
@@ -201,8 +202,11 @@ func reexportdep(n *Node) {
 		OMAKECHAN:
 		t := n.Type
 
-		if t.Sym == nil && t.Type != nil {
-			t = t.Type
+		switch t.Etype {
+		case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE:
+			if t.Sym == nil {
+				t = t.Elem()
+			}
 		}
 		if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
 			if Debug['E'] != 0 {
@@ -221,8 +225,7 @@ func reexportdep(n *Node) {
 }
 
 func dumpexportconst(s *Sym) {
-	n := s.Def
-	typecheck(&n, Erv)
+	n := typecheck(s.Def, Erv)
 	if n == nil || n.Op != OLITERAL {
 		Fatalf("dumpexportconst: oconst nil: %v", s)
 	}
@@ -230,16 +233,16 @@ func dumpexportconst(s *Sym) {
 	t := n.Type // may or may not be specified
 	dumpexporttype(t)
 
-	if t != nil && !isideal(t) {
-		exportf("\tconst %v %v = %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
+	if t != nil && !t.IsUntyped() {
+		exportf("\tconst %v %v = %v\n", sconv(s, FmtSharp), Tconv(t, FmtSharp), vconv(n.Val(), FmtSharp))
 	} else {
-		exportf("\tconst %v = %v\n", Sconv(s, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
+		exportf("\tconst %v = %v\n", sconv(s, FmtSharp), vconv(n.Val(), FmtSharp))
 	}
 }
 
 func dumpexportvar(s *Sym) {
 	n := s.Def
-	typecheck(&n, Erv|Ecall)
+	n = typecheck(n, Erv|Ecall)
 	if n == nil || n.Type == nil {
 		Yyerror("variable exported but not defined: %v", s)
 		return
@@ -249,7 +252,7 @@ func dumpexportvar(s *Sym) {
 	dumpexporttype(t)
 
 	if t.Etype == TFUNC && n.Class == PFUNC {
-		if n.Func != nil && n.Func.Inl != nil {
+		if n.Func != nil && n.Func.Inl.Len() != 0 {
 			// 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 {
@@ -257,19 +260,19 @@ func dumpexportvar(s *Sym) {
 			}
 
 			// NOTE: The space after %#S here is necessary for ld's export data parser.
-			exportf("\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Func.Inl, obj.FmtSharp|obj.FmtBody))
+			exportf("\tfunc %v %v { %v }\n", sconv(s, FmtSharp), Tconv(t, FmtShort|FmtSharp), hconv(n.Func.Inl, FmtSharp|FmtBody))
 
 			reexportdeplist(n.Func.Inl)
 		} else {
-			exportf("\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
+			exportf("\tfunc %v %v\n", sconv(s, FmtSharp), Tconv(t, FmtShort|FmtSharp))
 		}
 	} else {
-		exportf("\tvar %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp))
+		exportf("\tvar %v %v\n", sconv(s, FmtSharp), Tconv(t, FmtSharp))
 	}
 }
 
 // methodbyname sorts types by symbol name.
-type methodbyname []*Type
+type methodbyname []*Field
 
 func (x methodbyname) Len() int           { return len(x) }
 func (x methodbyname) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
@@ -284,40 +287,53 @@ func dumpexporttype(t *Type) {
 	}
 	t.Printed = true
 
-	if t.Sym != nil && t.Etype != TFIELD {
+	if t.Sym != nil {
 		dumppkg(t.Sym.Pkg)
 	}
 
-	dumpexporttype(t.Type)
-	dumpexporttype(t.Down)
-
-	if t.Sym == nil || t.Etype == TFIELD {
+	switch t.Etype {
+	case TSTRUCT, TINTER:
+		for _, f := range t.Fields().Slice() {
+			dumpexporttype(f.Type)
+		}
+	case TFUNC:
+		dumpexporttype(t.Recvs())
+		dumpexporttype(t.Results())
+		dumpexporttype(t.Params())
+	case TMAP:
+		dumpexporttype(t.Val())
+		dumpexporttype(t.Key())
+	case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE:
+		dumpexporttype(t.Elem())
+	}
+
+	if t.Sym == nil {
 		return
 	}
 
-	var m []*Type
-	for f := t.Method; f != nil; f = f.Down {
-		dumpexporttype(f)
+	var m []*Field
+	for _, f := range t.Methods().Slice() {
+		dumpexporttype(f.Type)
 		m = append(m, f)
 	}
 	sort.Sort(methodbyname(m))
 
-	exportf("\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong))
+	exportf("\ttype %v %v\n", sconv(t.Sym, FmtSharp), Tconv(t, FmtSharp|FmtLong))
 	for _, f := range m {
 		if f.Nointerface {
 			exportf("\t//go:nointerface\n")
 		}
-		if f.Type.Nname != nil && f.Type.Nname.Func.Inl != nil { // nname was set by caninl
+		if f.Type.Nname() != nil && f.Type.Nname().Func.Inl.Len() != 0 { // 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)
+				typecheckinl(f.Type.Nname())
 			}
-			exportf("\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)
+			exportf("\tfunc %v %v %v { %v }\n", Tconv(f.Type.Recvs(), FmtSharp), sconv(f.Sym, FmtShort|FmtByte|FmtSharp), Tconv(f.Type, FmtShort|FmtSharp), hconv(f.Type.Nname().Func.Inl, FmtSharp|FmtBody))
+			reexportdeplist(f.Type.Nname().Func.Inl)
 		} else {
-			exportf("\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))
+			exportf("\tfunc %v %v %v\n", Tconv(f.Type.Recvs(), FmtSharp), sconv(f.Sym, FmtShort|FmtByte|FmtSharp), Tconv(f.Type, FmtShort|FmtSharp))
 		}
 	}
 }
@@ -338,7 +354,7 @@ func dumpsym(s *Sym) {
 
 	switch s.Def.Op {
 	default:
-		Yyerror("unexpected export symbol: %v %v", Oconv(int(s.Def.Op), 0), s)
+		Yyerror("unexpected export symbol: %v %v", s.Def.Op, s)
 
 	case OLITERAL:
 		dumpexportconst(s)
@@ -361,16 +377,15 @@ func dumpexport() {
 	}
 
 	size := 0 // size of export section without enclosing markers
-	if forceNewExport || newexport != 0 {
+	if newexport {
 		// binary export
 		// The linker also looks for the $$ marker - use char after $$ to distinguish format.
-		exportf("\n$$B\n")        // indicate binary format
-		const verifyExport = true // enable to check format changes
-		if verifyExport {
+		exportf("\n$$B\n") // indicate binary format
+		if debugFormat {
 			// save a copy of the export data
 			var copy bytes.Buffer
-			bcopy := obj.Binitw(&copy)
-			size = Export(bcopy, Debug_export != 0)
+			bcopy := bufio.NewWriter(&copy)
+			size = export(bcopy, Debug_export != 0)
 			bcopy.Flush() // flushing to bytes.Buffer cannot fail
 			if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
 				Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
@@ -387,12 +402,12 @@ func dumpexport() {
 			pkgMap = make(map[string]*Pkg)
 			pkgs = nil
 			importpkg = mkpkg("")
-			Import(obj.Binitr(&copy)) // must not die
+			Import(bufio.NewReader(&copy)) // must not die
 			importpkg = nil
 			pkgs = savedPkgs
 			pkgMap = savedPkgMap
 		} else {
-			size = Export(bout, Debug_export != 0)
+			size = export(bout.Writer, Debug_export != 0)
 		}
 		exportf("\n$$\n")
 	} else {
@@ -402,7 +417,7 @@ func dumpexport() {
 		exportf("\n$$\n") // indicate textual format
 		exportsize = 0
 		exportf("package %s", localpkg.Name)
-		if safemode != 0 {
+		if safemode {
 			exportf(" safe")
 		}
 		exportf("\n")
@@ -414,9 +429,8 @@ func dumpexport() {
 		}
 
 		// exportlist grows during iteration - cannot use range
-		for len(exportlist) > 0 {
-			n := exportlist[0]
-			exportlist = exportlist[1:]
+		for i := 0; i < len(exportlist); i++ {
+			n := exportlist[i]
 			lineno = n.Lineno
 			dumpsym(n.Sym)
 		}
@@ -431,10 +445,8 @@ func dumpexport() {
 	}
 }
 
-// import
-
-// return the sym for ss, which should match lexical
-func importsym(s *Sym, op Op) *Sym {
+// importsym declares symbol s as an imported object representable by op.
+func importsym(s *Sym, op Op) {
 	if s.Def != nil && s.Def.Op != op {
 		pkgstr := fmt.Sprintf("during import %q", importpkg.Path)
 		redeclare(s, pkgstr)
@@ -442,17 +454,16 @@ func importsym(s *Sym, op Op) *Sym {
 
 	// mark the symbol so it is not reexported
 	if s.Def == nil {
-		if exportname(s.Name) || initname(s.Name) {
+		if Debug['A'] != 0 || 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
+// pkgtype returns the named type declared by symbol s.
+// If no such type has been declared yet, a forward declaration is returned.
 func pkgtype(s *Sym) *Type {
 	importsym(s, OTYPE)
 	if s.Def == nil || s.Def.Op != OTYPE {
@@ -468,6 +479,10 @@ func pkgtype(s *Sym) *Type {
 	return s.Def.Type
 }
 
+// numImport tracks how often a package with a given name is imported.
+// It is used to provide a better error message (by using the package
+// path to disambiguate) if a package that appears multiple times with
+// the same name appears in an error message.
 var numImport = make(map[string]int)
 
 func importimport(s *Sym, path string) {
@@ -492,9 +507,10 @@ func importimport(s *Sym, path string) {
 	}
 }
 
+// importconst declares symbol s as an imported constant with type t and value n.
 func importconst(s *Sym, t *Type, n *Node) {
 	importsym(s, OLITERAL)
-	Convlit(&n, t)
+	n = convlit(n, t)
 
 	if s.Def != nil { // TODO: check if already the same.
 		return
@@ -506,9 +522,8 @@ func importconst(s *Sym, t *Type, n *Node) {
 	}
 
 	if n.Sym != nil {
-		n1 := Nod(OXXX, nil, nil)
-		*n1 = *n
-		n = n1
+		n1 := *n
+		n = &n1
 	}
 
 	n.Orig = newname(s)
@@ -520,6 +535,7 @@ func importconst(s *Sym, t *Type, n *Node) {
 	}
 }
 
+// importvar declares symbol s as an imported variable with type t.
 func importvar(s *Sym, t *Type) {
 	importsym(s, ONAME)
 	if s.Def != nil && s.Def.Op == ONAME {
@@ -535,10 +551,11 @@ func importvar(s *Sym, t *Type) {
 	declare(n, PEXTERN)
 
 	if Debug['E'] != 0 {
-		fmt.Printf("import var %v %v\n", s, Tconv(t, obj.FmtLong))
+		fmt.Printf("import var %v %v\n", s, Tconv(t, FmtLong))
 	}
 }
 
+// importtype and importer.importtype (bimport.go) need to remain in sync.
 func importtype(pt *Type, t *Type) {
 	// override declaration in unsafe.go for Pointer.
 	// there is no way in Go code to define unsafe.Pointer
@@ -552,50 +569,45 @@ func importtype(pt *Type, t *Type) {
 		copytype(pt.Nod, t)
 		pt.Nod = n // unzero nod
 		pt.Sym.Importdef = importpkg
-		pt.Sym.Lastlineno = int32(parserline())
+		pt.Sym.Lastlineno = lineno
 		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)
+		Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, FmtLong), pt.Sym.Importdef.Path, Tconv(t, FmtLong), importpkg.Path)
 	}
 
 	if Debug['E'] != 0 {
-		fmt.Printf("import type %v %v\n", pt, Tconv(t, obj.FmtLong))
+		fmt.Printf("import type %v %v\n", pt, Tconv(t, FmtLong))
 	}
 }
 
 func dumpasmhdr() {
-	var b *obj.Biobuf
-
-	b, err := obj.Bopenw(asmhdr)
+	b, err := bio.Create(asmhdr)
 	if err != nil {
 		Fatalf("%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
+	fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
+	for _, n := range asmlist {
 		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))
+			fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, vconv(n.Val(), FmtSharp))
 
 		case OTYPE:
-			t = n.Type
-			if t.Etype != TSTRUCT || t.Map != nil || t.Funarg {
+			t := n.Type
+			if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
 				break
 			}
 			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
-			for t = t.Type; t != nil; t = t.Down {
+			for _, t := range t.Fields().Slice() {
 				if !isblanksym(t.Sym) {
-					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Width))
+					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset))
 				}
 			}
 		}
 	}
 
-	obj.Bterm(b)
+	b.Close()
 }
diff --git a/src/cmd/compile/internal/gc/fixedbugs_test.go b/src/cmd/compile/internal/gc/fixedbugs_test.go
new file mode 100644
index 0000000..19b1d9a
--- /dev/null
+++ b/src/cmd/compile/internal/gc/fixedbugs_test.go
@@ -0,0 +1,50 @@
+// Copyright 2016 The Go Authors. 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 "testing"
+
+type T struct {
+	x [2]int64 // field that will be clobbered. Also makes type not SSAable.
+	p *byte    // has a pointer
+}
+
+//go:noinline
+func makeT() T {
+	return T{}
+}
+
+var g T
+
+var sink []byte
+
+func TestIssue15854(t *testing.T) {
+	for i := 0; i < 10000; i++ {
+		if g.x[0] != 0 {
+			t.Fatalf("g.x[0] clobbered with %x\n", g.x[0])
+		}
+		// The bug was in the following assignment. The return
+		// value of makeT() is not copied out of the args area of
+		// stack frame in a timely fashion. So when write barriers
+		// are enabled, the marshaling of the args for the write
+		// barrier call clobbers the result of makeT() before it is
+		// read by the write barrier code.
+		g = makeT()
+		sink = make([]byte, 1000) // force write barriers to eventually happen
+	}
+}
+func TestIssue15854b(t *testing.T) {
+	const N = 10000
+	a := make([]T, N)
+	for i := 0; i < N; i++ {
+		a = append(a, makeT())
+		sink = make([]byte, 1000) // force write barriers to eventually happen
+	}
+	for i, v := range a {
+		if v.x[0] != 0 {
+			t.Fatalf("a[%d].x[0] clobbered with %x\n", i, v.x[0])
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index d00e5a6..3d26a1d 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -13,6 +13,24 @@ import (
 	"unicode/utf8"
 )
 
+// A FmtFlag value is a set of flags (or 0).
+// They control how the Xconv functions format their values.
+// See the respective function's documentation for details.
+type FmtFlag int
+
+const (
+	FmtWidth    FmtFlag = 1 << iota
+	FmtLeft             // "-"
+	FmtSharp            // "#"
+	FmtSign             // "+"
+	FmtUnsigned         // "u"
+	FmtShort            // "h"
+	FmtLong             // "l"
+	FmtComma            // ","
+	FmtByte             // "hh"
+	FmtBody             // for printing export bodies
+)
+
 //
 // Format conversions
 //	%L int		Line numbers
@@ -43,7 +61,7 @@ import (
 //			'h' (only in +/debug mode) suppress recursion
 //			'l' (only in Error mode) print "foo (type Bar)"
 //
-//	%H NodeList*	NodeLists
+//	%H Nodes	Nodes
 //		Flags: those of %N
 //			','  separate items with ',' instead of ';'
 //
@@ -69,7 +87,7 @@ var fmtbody bool
 // 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
+// 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.
 
 //
@@ -89,22 +107,22 @@ var fmtbody bool
 //	%-uT		type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
 //
 
-func setfmode(flags *int) (fm int, fb bool) {
+func setfmode(flags *FmtFlag) (fm int, fb bool) {
 	fm = fmtmode
 	fb = fmtbody
-	if *flags&obj.FmtSign != 0 {
+	if *flags&FmtSign != 0 {
 		fmtmode = FDbg
-	} else if *flags&obj.FmtSharp != 0 {
+	} else if *flags&FmtSharp != 0 {
 		fmtmode = FExp
-	} else if *flags&obj.FmtLeft != 0 {
+	} else if *flags&FmtLeft != 0 {
 		fmtmode = FTypeId
 	}
 
-	if *flags&obj.FmtBody != 0 {
+	if *flags&FmtBody != 0 {
 		fmtbody = true
 	}
 
-	*flags &^= (obj.FmtSharp | obj.FmtLeft | obj.FmtSign | obj.FmtBody)
+	*flags &^= (FmtSharp | FmtLeft | FmtSign | FmtBody)
 	return
 }
 
@@ -171,17 +189,25 @@ var goopnames = []string{
 	OSUB:      "-",
 	OSWITCH:   "switch",
 	OXOR:      "^",
+	OXFALL:    "fallthrough",
+}
+
+func (o Op) String() string {
+	return oconv(o, 0)
+}
+
+func (o Op) GoString() string {
+	return oconv(o, FmtSharp)
 }
 
-// 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] != "" {
+func oconv(o Op, flag FmtFlag) string {
+	if (flag&FmtSharp != 0) || fmtmode != FDbg {
+		if o >= 0 && int(o) < len(goopnames) && goopnames[o] != "" {
 			return goopnames[o]
 		}
 	}
 
-	if o >= 0 && o < len(opnames) && opnames[o] != "" {
+	if o >= 0 && int(o) < len(opnames) && opnames[o] != "" {
 		return opnames[o]
 	}
 
@@ -192,17 +218,17 @@ var classnames = []string{
 	"Pxxx",
 	"PEXTERN",
 	"PAUTO",
+	"PAUTOHEAP",
 	"PPARAM",
 	"PPARAMOUT",
-	"PPARAMREF",
 	"PFUNC",
 }
 
 // Fmt "%J": Node details.
-func Jconv(n *Node, flag int) string {
+func jconv(n *Node, flag FmtFlag) string {
 	var buf bytes.Buffer
 
-	c := flag & obj.FmtShort
+	c := flag & FmtShort
 
 	if c == 0 && n.Ullman != 0 {
 		fmt.Fprintf(&buf, " u(%d)", n.Ullman)
@@ -225,14 +251,10 @@ func Jconv(n *Node, flag int) string {
 	}
 
 	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)
+		if int(n.Class) < len(classnames) {
+			fmt.Fprintf(&buf, " class(%s)", classnames[n.Class])
 		} else {
-			fmt.Fprintf(&buf, " class(%d?%s)", n.Class&^PHEAP, s)
+			fmt.Fprintf(&buf, " class(%d?)", n.Class)
 		}
 	}
 
@@ -300,6 +322,12 @@ func Jconv(n *Node, flag int) string {
 	if n.Assigned {
 		buf.WriteString(" assigned")
 	}
+	if n.Bounded {
+		buf.WriteString(" bounded")
+	}
+	if n.NonNil {
+		buf.WriteString(" nonnil")
+	}
 
 	if c == 0 && n.Used {
 		fmt.Fprintf(&buf, " used(%v)", n.Used)
@@ -308,17 +336,18 @@ func Jconv(n *Node, flag int) 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)
+func vconv(v Val, flag FmtFlag) string {
+	switch u := v.U.(type) {
+	case *Mpint:
+		if !u.Rune {
+			if (flag&FmtSharp != 0) || fmtmode == FExp {
+				return bconv(u, FmtSharp)
+			}
+			return bconv(u, 0)
 		}
-		return Bconv(v.U.(*Mpint), 0)
 
-	case CTRUNE:
-		x := Mpgetfix(v.U.(*Mpint))
-		if ' ' <= x && x < 0x80 && x != '\\' && x != '\'' {
+		x := u.Int64()
+		if ' ' <= x && x < utf8.RuneSelf && x != '\\' && x != '\'' {
 			return fmt.Sprintf("'%c'", int(x))
 		}
 		if 0 <= x && x < 1<<16 {
@@ -327,39 +356,39 @@ func Vconv(v Val, flag int) string {
 		if 0 <= x && x <= utf8.MaxRune {
 			return fmt.Sprintf("'\\U%08x'", uint64(x))
 		}
-		return fmt.Sprintf("('\\x00' + %v)", v.U.(*Mpint))
+		return fmt.Sprintf("('\\x00' + %v)", u)
 
-	case CTFLT:
-		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
-			return Fconv(v.U.(*Mpflt), 0)
+	case *Mpflt:
+		if (flag&FmtSharp != 0) || fmtmode == FExp {
+			return fconv(u, 0)
 		}
-		return Fconv(v.U.(*Mpflt), obj.FmtSharp)
+		return fconv(u, FmtSharp)
 
-	case CTCPLX:
-		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
-			return fmt.Sprintf("(%v+%vi)", &v.U.(*Mpcplx).Real, &v.U.(*Mpcplx).Imag)
+	case *Mpcplx:
+		if (flag&FmtSharp != 0) || fmtmode == FExp {
+			return fmt.Sprintf("(%v+%vi)", &u.Real, &u.Imag)
 		}
-		if mpcmpfltc(&v.U.(*Mpcplx).Real, 0) == 0 {
-			return fmt.Sprintf("%vi", Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
+		if v.U.(*Mpcplx).Real.CmpFloat64(0) == 0 {
+			return fmt.Sprintf("%vi", fconv(&u.Imag, FmtSharp))
 		}
-		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) == 0 {
-			return Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp)
+		if v.U.(*Mpcplx).Imag.CmpFloat64(0) == 0 {
+			return fconv(&u.Real, 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))
+		if v.U.(*Mpcplx).Imag.CmpFloat64(0) < 0 {
+			return fmt.Sprintf("(%v%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
 		}
-		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(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
 
-	case CTSTR:
-		return strconv.Quote(v.U.(string))
+	case string:
+		return strconv.Quote(u)
 
-	case CTBOOL:
-		if v.U.(bool) {
+	case bool:
+		if u {
 			return "true"
 		}
 		return "false"
 
-	case CTNIL:
+	case *NilVal:
 		return "nil"
 	}
 
@@ -376,6 +405,7 @@ s%^	........*\]%&~%g
 s%~	%%g
 */
 var etnames = []string{
+	Txxx:        "Txxx",
 	TINT:        "INT",
 	TUINT:       "UINT",
 	TINT8:       "INT8",
@@ -396,18 +426,25 @@ var etnames = []string{
 	TPTR64:      "PTR64",
 	TFUNC:       "FUNC",
 	TARRAY:      "ARRAY",
+	TSLICE:      "SLICE",
 	TSTRUCT:     "STRUCT",
 	TCHAN:       "CHAN",
 	TMAP:        "MAP",
 	TINTER:      "INTER",
 	TFORW:       "FORW",
-	TFIELD:      "FIELD",
 	TSTRING:     "STRING",
+	TUNSAFEPTR:  "TUNSAFEPTR",
 	TANY:        "ANY",
+	TIDEAL:      "TIDEAL",
+	TNIL:        "TNIL",
+	TBLANK:      "TBLANK",
+	TFUNCARGS:   "TFUNCARGS",
+	TCHANARGS:   "TCHANARGS",
+	TINTERMETH:  "TINTERMETH",
+	TDDDFIELD:   "TDDDFIELD",
 }
 
-// Fmt "%E": etype
-func Econv(et EType) string {
+func (et EType) String() string {
 	if int(et) < len(etnames) && etnames[et] != "" {
 		return etnames[et]
 	}
@@ -415,8 +452,8 @@ func Econv(et EType) string {
 }
 
 // Fmt "%S": syms
-func symfmt(s *Sym, flag int) string {
-	if s.Pkg != nil && flag&obj.FmtShort == 0 {
+func symfmt(s *Sym, flag FmtFlag) string {
+	if s.Pkg != nil && flag&FmtShort == 0 {
 		switch fmtmode {
 		case FErr: // This is for the user
 			if s.Pkg == builtinpkg || s.Pkg == localpkg {
@@ -427,16 +464,16 @@ func symfmt(s *Sym, flag int) string {
 			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)
+			return s.Pkg.Name + "." + s.Name
 
 		case FDbg:
-			return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
+			return s.Pkg.Name + "." + s.Name
 
 		case FTypeId:
-			if flag&obj.FmtUnsigned != 0 {
-				return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name) // dcommontype, typehash
+			if flag&FmtUnsigned != 0 {
+				return s.Pkg.Name + "." + s.Name // dcommontype, typehash
 			}
-			return fmt.Sprintf("%s.%s", s.Pkg.Prefix, s.Name) // (methodsym), typesym, weaksym
+			return s.Pkg.Prefix + "." + s.Name // (methodsym), typesym, weaksym
 
 		case FExp:
 			if s.Name != "" && s.Name[0] == '.' {
@@ -448,7 +485,7 @@ func symfmt(s *Sym, flag int) string {
 		}
 	}
 
-	if flag&obj.FmtByte != 0 {
+	if flag&FmtByte != 0 {
 		// FmtByte (hh) implies FmtShort (h)
 		// skip leading "type." in method name
 		p := s.Name
@@ -491,7 +528,7 @@ var basicnames = []string{
 	TBLANK:      "blank",
 }
 
-func typefmt(t *Type, flag int) string {
+func typefmt(t *Type, flag FmtFlag) string {
 	if t == nil {
 		return "<T>"
 	}
@@ -499,7 +536,7 @@ func typefmt(t *Type, flag int) string {
 	if t == bytetype || t == runetype {
 		// in %-T mode collapse rune and byte with their originals.
 		if fmtmode != FTypeId {
-			return Sconv(t.Sym, obj.FmtShort)
+			return sconv(t.Sym, FmtShort)
 		}
 		t = Types[t.Etype]
 	}
@@ -509,18 +546,18 @@ func typefmt(t *Type, flag int) string {
 	}
 
 	// 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] {
+	if flag&FmtLong == 0 && t.Sym != nil && t != Types[t.Etype] {
 		switch fmtmode {
 		case FTypeId:
-			if flag&obj.FmtShort != 0 {
+			if flag&FmtShort != 0 {
 				if t.Vargen != 0 {
-					return fmt.Sprintf("%v·%d", Sconv(t.Sym, obj.FmtShort), t.Vargen)
+					return fmt.Sprintf("%v·%d", sconv(t.Sym, FmtShort), t.Vargen)
 				}
-				return Sconv(t.Sym, obj.FmtShort)
+				return sconv(t.Sym, FmtShort)
 			}
 
-			if flag&obj.FmtUnsigned != 0 {
-				return Sconv(t.Sym, obj.FmtUnsigned)
+			if flag&FmtUnsigned != 0 {
+				return sconv(t.Sym, FmtUnsigned)
 			}
 			fallthrough
 
@@ -530,7 +567,7 @@ func typefmt(t *Type, flag int) string {
 			}
 		}
 
-		return Sconv(t.Sym, 0)
+		return sconv(t.Sym, 0)
 	}
 
 	if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
@@ -543,65 +580,65 @@ func typefmt(t *Type, flag int) string {
 
 	if fmtmode == FDbg {
 		fmtmode = 0
-		str := Econv(t.Etype) + "-" + typefmt(t, flag)
+		str := t.Etype.String() + "-" + 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))
+		if fmtmode == FTypeId && (flag&FmtShort != 0) {
+			return "*" + Tconv(t.Elem(), FmtShort)
 		}
-		return fmt.Sprintf("*%v", t.Type)
+		return "*" + t.Elem().String()
 
 	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)
+		if t.isDDDArray() {
+			return "[...]" + t.Elem().String()
 		}
-		return fmt.Sprintf("[]%v", t.Type)
+		return fmt.Sprintf("[%d]%v", t.NumElem(), t.Elem())
+
+	case TSLICE:
+		return "[]" + t.Elem().String()
 
 	case TCHAN:
-		switch t.Chan {
+		switch t.ChanDir() {
 		case Crecv:
-			return fmt.Sprintf("<-chan %v", t.Type)
+			return "<-chan " + t.Elem().String()
 
 		case Csend:
-			return fmt.Sprintf("chan<- %v", t.Type)
+			return "chan<- " + t.Elem().String()
 		}
 
-		if t.Type != nil && t.Type.Etype == TCHAN && t.Type.Sym == nil && t.Type.Chan == Crecv {
-			return fmt.Sprintf("chan (%v)", t.Type)
+		if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym == nil && t.Elem().ChanDir() == Crecv {
+			return "chan (" + t.Elem().String() + ")"
 		}
-		return fmt.Sprintf("chan %v", t.Type)
+		return "chan " + t.Elem().String()
 
 	case TMAP:
-		return fmt.Sprintf("map[%v]%v", t.Down, t.Type)
+		return "map[" + t.Key().String() + "]" + t.Val().String()
 
 	case TINTER:
 		var buf bytes.Buffer
 		buf.WriteString("interface {")
-		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+		for i, f := range t.Fields().Slice() {
+			if i != 0 {
+				buf.WriteString(";")
+			}
 			buf.WriteString(" ")
 			switch {
-			case t1.Sym == nil:
+			case f.Sym == nil:
 				// Check first that a symbol is defined for this type.
 				// Wrong interface definitions may have types lacking a symbol.
 				break
-			case exportname(t1.Sym.Name):
-				buf.WriteString(Sconv(t1.Sym, obj.FmtShort))
+			case exportname(f.Sym.Name):
+				buf.WriteString(sconv(f.Sym, FmtShort))
 			default:
-				buf.WriteString(Sconv(t1.Sym, obj.FmtUnsigned))
-			}
-			buf.WriteString(Tconv(t1.Type, obj.FmtShort))
-			if t1.Down != nil {
-				buf.WriteString(";")
+				buf.WriteString(sconv(f.Sym, FmtUnsigned))
 			}
+			buf.WriteString(Tconv(f.Type, FmtShort))
 		}
-		if t.Type != nil {
+		if t.NumFields() != 0 {
 			buf.WriteString(" ")
 		}
 		buf.WriteString("}")
@@ -609,159 +646,89 @@ func typefmt(t *Type, flag int) string {
 
 	case TFUNC:
 		var buf bytes.Buffer
-		if flag&obj.FmtShort != 0 {
+		if flag&FmtShort != 0 {
 			// no leading func
 		} else {
-			if t.Thistuple != 0 {
+			if t.Recv() != nil {
 				buf.WriteString("method")
-				buf.WriteString(Tconv(getthisx(t), 0))
+				buf.WriteString(Tconv(t.Recvs(), 0))
 				buf.WriteString(" ")
 			}
 			buf.WriteString("func")
 		}
-		buf.WriteString(Tconv(getinargx(t), 0))
+		buf.WriteString(Tconv(t.Params(), 0))
 
-		switch t.Outtuple {
+		switch t.Results().NumFields() {
 		case 0:
 			break
 
 		case 1:
 			if fmtmode != FExp {
 				buf.WriteString(" ")
-				buf.WriteString(Tconv(getoutargx(t).Type.Type, 0)) // struct->field->field's type
+				buf.WriteString(Tconv(t.Results().Field(0).Type, 0)) // struct->field->field's type
 				break
 			}
 			fallthrough
 
 		default:
 			buf.WriteString(" ")
-			buf.WriteString(Tconv(getoutargx(t), 0))
+			buf.WriteString(Tconv(t.Results(), 0))
 		}
 		return buf.String()
 
 	case TSTRUCT:
-		if t.Map != nil {
+		if m := t.StructType().Map; m != nil {
+			mt := m.MapType()
 			// 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 mt.Bucket == t {
+				return "map.bucket[" + m.Key().String() + "]" + m.Val().String()
 			}
 
-			if t.Map.Hmap == t {
-				return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type)
+			if mt.Hmap == t {
+				return "map.hdr[" + m.Key().String() + "]" + m.Val().String()
 			}
 
-			if t.Map.Hiter == t {
-				return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type)
+			if mt.Hiter == t {
+				return "map.iter[" + m.Key().String() + "]" + m.Val().String()
 			}
 
 			Yyerror("unknown internal map type")
 		}
 
 		var buf bytes.Buffer
-		if t.Funarg {
+		if t.IsFuncArgStruct() {
 			buf.WriteString("(")
+			var flag1 FmtFlag
 			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(", ")
-					}
+				flag1 = FmtShort
+			}
+			for i, f := range t.Fields().Slice() {
+				if i != 0 {
+					buf.WriteString(", ")
 				}
+				buf.WriteString(Fldconv(f, flag1))
 			}
 			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 {
+			for i, f := range t.Fields().Slice() {
+				if i != 0 {
 					buf.WriteString(";")
 				}
+				buf.WriteString(" ")
+				buf.WriteString(Fldconv(f, FmtLong))
 			}
-			if t.Type != nil {
+			if t.NumFields() != 0 {
 				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 {
-					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.go 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
-		}
-
-		// The fmtbody flag is intended to suppress escape analysis annotations
-		// when printing a function type used in a function body.
-		// (The escape analysis tags do not apply to func vars.)
-		// But it must not suppress struct field tags.
-		// See golang.org/issue/13777 and golang.org/issue/14331.
-		if flag&obj.FmtShort == 0 && (!fmtbody || !t.Funarg) && 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 " + t.Sym.String()
 		}
 		return "undefined"
 
@@ -770,14 +737,23 @@ func typefmt(t *Type, flag int) string {
 			return "@\"unsafe\".Pointer"
 		}
 		return "unsafe.Pointer"
+
+	case TDDDFIELD:
+		if fmtmode == FExp {
+			Fatalf("cannot use TDDDFIELD with old exporter")
+		}
+		return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.DDDField())
+
+	case Txxx:
+		return "Txxx"
 	}
 
 	if fmtmode == FExp {
-		Fatalf("missing %v case during export", Econv(t.Etype))
+		Fatalf("missing %v case during export", t.Etype)
 	}
 
 	// Don't know how to handle - fall back to detailed prints.
-	return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.Type)
+	return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.Elem())
 }
 
 // Statements which may be rendered with a simplestmt as init.
@@ -795,14 +771,14 @@ func stmtfmt(n *Node) 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
+	// 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(n.Op)
+	simpleinit := n.Ninit.Len() == 1 && n.Ninit.First().Ninit.Len() == 0 && stmtwithinit(n.Op)
 
 	// otherwise, print the inits as separate statements
-	complexinit := n.Ninit != nil && !simpleinit && (fmtmode != FErr)
+	complexinit := n.Ninit.Len() != 0 && !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)
@@ -818,8 +794,8 @@ func stmtfmt(n *Node) string {
 	switch n.Op {
 	case ODCL:
 		if fmtmode == FExp {
-			switch n.Left.Class &^ PHEAP {
-			case PPARAM, PPARAMOUT, PAUTO:
+			switch n.Left.Class {
+			case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
 				f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
 				goto ret
 			}
@@ -835,7 +811,7 @@ func stmtfmt(n *Node) string {
 		}
 
 	// Don't export "v = <N>" initializing statements, hope they're always
-	// preceded by the DCL which will be re-parsed and typecheck to reproduce
+	// preceded by the DCL which will be re-parsed and typechecked to reproduce
 	// the "v = <N>" again.
 	case OAS, OASWB:
 		if fmtmode == FExp && n.Right == nil {
@@ -858,20 +834,20 @@ func stmtfmt(n *Node) string {
 			break
 		}
 
-		f += fmt.Sprintf("%v %v= %v", n.Left, Oconv(int(n.Etype), obj.FmtSharp), n.Right)
+		f += fmt.Sprintf("%v %#v= %v", n.Left, Op(n.Etype), n.Right)
 
 	case OAS2:
 		if n.Colas && !complexinit {
-			f += fmt.Sprintf("%v := %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
+			f += fmt.Sprintf("%v := %v", hconv(n.List, FmtComma), hconv(n.Rlist, FmtComma))
 			break
 		}
 		fallthrough
 
 	case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
-		f += fmt.Sprintf("%v = %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
+		f += fmt.Sprintf("%v = %v", hconv(n.List, FmtComma), hconv(n.Rlist, FmtComma))
 
 	case ORETURN:
-		f += fmt.Sprintf("return %v", Hconv(n.List, obj.FmtComma))
+		f += fmt.Sprintf("return %v", hconv(n.List, FmtComma))
 
 	case ORETJMP:
 		f += fmt.Sprintf("retjmp %v", n.Sym)
@@ -884,11 +860,11 @@ func stmtfmt(n *Node) string {
 
 	case OIF:
 		if simpleinit {
-			f += fmt.Sprintf("if %v; %v { %v }", n.Ninit.N, n.Left, n.Nbody)
+			f += fmt.Sprintf("if %v; %v { %v }", n.Ninit.First(), n.Left, n.Nbody)
 		} else {
 			f += fmt.Sprintf("if %v { %v }", n.Left, n.Nbody)
 		}
-		if n.Rlist != nil {
+		if n.Rlist.Len() != 0 {
 			f += fmt.Sprintf(" else { %v }", n.Rlist)
 		}
 
@@ -900,7 +876,7 @@ func stmtfmt(n *Node) string {
 
 		f += "for"
 		if simpleinit {
-			f += fmt.Sprintf(" %v;", n.Ninit.N)
+			f += fmt.Sprintf(" %v;", n.Ninit.First())
 		} else if n.Right != nil {
 			f += " ;"
 		}
@@ -923,32 +899,32 @@ func stmtfmt(n *Node) string {
 			break
 		}
 
-		if n.List == nil {
+		if n.List.Len() == 0 {
 			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)
+		f += fmt.Sprintf("for %v = range %v { %v }", hconv(n.List, FmtComma), n.Right, n.Nbody)
 
 	case OSELECT, OSWITCH:
 		if fmtmode == FErr {
-			f += fmt.Sprintf("%v statement", Oconv(int(n.Op), 0))
+			f += fmt.Sprintf("%v statement", n.Op)
 			break
 		}
 
-		f += Oconv(int(n.Op), obj.FmtSharp)
+		f += n.Op.GoString() // %#v
 		if simpleinit {
-			f += fmt.Sprintf(" %v;", n.Ninit.N)
+			f += fmt.Sprintf(" %v;", n.Ninit.First())
 		}
 		if n.Left != nil {
-			f += Nconv(n.Left, 0)
+			f += fmt.Sprintf(" %s ", 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)
+		if n.List.Len() != 0 {
+			f += fmt.Sprintf("case %v: %v", hconv(n.List, FmtComma), n.Nbody)
 		} else {
 			f += fmt.Sprintf("default: %v", n.Nbody)
 		}
@@ -959,9 +935,9 @@ func stmtfmt(n *Node) string {
 		OFALL,
 		OXFALL:
 		if n.Left != nil {
-			f += fmt.Sprintf("%v %v", Oconv(int(n.Op), obj.FmtSharp), n.Left)
+			f += fmt.Sprintf("%#v %v", n.Op, n.Left)
 		} else {
-			f += Oconv(int(n.Op), obj.FmtSharp)
+			f += n.Op.GoString() // %#v
 		}
 
 	case OEMPTY:
@@ -1127,7 +1103,7 @@ func exprfmt(n *Node, prec int) string {
 				return exprfmt(n.Orig, prec)
 			}
 			if n.Sym != nil {
-				return Sconv(n.Sym, 0)
+				return sconv(n.Sym, 0)
 			}
 		}
 		if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
@@ -1136,14 +1112,14 @@ func exprfmt(n *Node, prec int) string {
 		if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && 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))
+			if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == 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 fmt.Sprintf("%v(%v)", n.Type, vconv(n.Val(), 0))
 			}
 		}
 
-		return 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
@@ -1159,20 +1135,20 @@ func exprfmt(n *Node, prec int) string {
 		// 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))
+			if n.Left.Type.IsPtr() {
+				return fmt.Sprintf("(%v).%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte))
 			} else {
-				return fmt.Sprintf("%v.%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
+				return fmt.Sprintf("%v.%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte))
 			}
 		}
 		fallthrough
 
 	case OPACK, ONONAME:
-		return Sconv(n.Sym, 0)
+		return sconv(n.Sym, 0)
 
 	case OTYPE:
 		if n.Type == nil && n.Sym != nil {
-			return Sconv(n.Sym, 0)
+			return sconv(n.Sym, 0)
 		}
 		return Tconv(n.Type, 0)
 
@@ -1180,15 +1156,13 @@ func exprfmt(n *Node, prec int) string {
 		if n.Left != nil {
 			return fmt.Sprintf("[]%v", n.Left)
 		}
-		var f string
-		f += fmt.Sprintf("[]%v", n.Right)
-		return f // happens before typecheck
+		return fmt.Sprintf("[]%v", n.Right) // happens before typecheck
 
 	case OTMAP:
 		return fmt.Sprintf("map[%v]%v", n.Left, n.Right)
 
 	case OTCHAN:
-		switch n.Etype {
+		switch ChanDir(n.Etype) {
 		case Crecv:
 			return fmt.Sprintf("<-chan %v", n.Left)
 
@@ -1196,7 +1170,7 @@ func exprfmt(n *Node, prec int) string {
 			return fmt.Sprintf("chan<- %v", n.Left)
 
 		default:
-			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.Etype == Crecv {
+			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && ChanDir(n.Left.Etype) == Crecv {
 				return fmt.Sprintf("chan (%v)", n.Left)
 			} else {
 				return fmt.Sprintf("chan %v", n.Left)
@@ -1216,17 +1190,17 @@ func exprfmt(n *Node, prec int) string {
 		if fmtmode == FErr {
 			return "func literal"
 		}
-		if n.Nbody != nil {
+		if n.Nbody.Len() != 0 {
 			return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
 		}
-		return fmt.Sprintf("%v { %v }", n.Type, n.Name.Param.Closure.Nbody)
+		return fmt.Sprintf("%v { %v }", n.Type, n.Func.Closure.Nbody)
 
 	case OCOMPLIT:
-		ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && Isptr[n.Right.Type.Etype]
+		ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && n.Right.Type.IsPtr()
 		if fmtmode == FErr {
 			if n.Right != nil && n.Right.Type != nil && !n.Implicit {
 				if ptrlit {
-					return fmt.Sprintf("&%v literal", n.Right.Type.Type)
+					return fmt.Sprintf("&%v literal", n.Right.Type.Elem())
 				} else {
 					return fmt.Sprintf("%v literal", n.Right.Type)
 				}
@@ -1237,10 +1211,10 @@ func exprfmt(n *Node, prec int) string {
 
 		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.Type.Elem(), hconv(n.List, FmtComma))
 		}
 
-		return fmt.Sprintf("(%v{ %v })", n.Right, Hconv(n.List, obj.FmtComma))
+		return fmt.Sprintf("(%v{ %v })", n.Right, hconv(n.List, FmtComma))
 
 	case OPTRLIT:
 		if fmtmode == FExp && n.Left.Implicit {
@@ -1256,10 +1230,10 @@ func exprfmt(n *Node, prec int) string {
 			} 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)
+			for i1, n1 := range n.List.Slice() {
+				f += fmt.Sprintf(" %v:%v", sconv(n1.Left.Sym, FmtShort|FmtByte), n1.Right)
 
-				if l.Next != nil {
+				if i1+1 < n.List.Len() {
 					f += ","
 				} else {
 					f += " "
@@ -1280,15 +1254,15 @@ func exprfmt(n *Node, prec int) string {
 			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 }", hconv(n.List, FmtComma))
 		}
-		return fmt.Sprintf("(%v{ %v })", n.Type, Hconv(n.List, obj.FmtComma))
+		return fmt.Sprintf("(%v{ %v })", n.Type, hconv(n.List, FmtComma))
 
 	case OKEY:
 		if n.Left != nil && n.Right != nil {
-			if fmtmode == FExp && n.Left.Type != nil && n.Left.Type.Etype == TFIELD {
+			if fmtmode == FExp && n.Left.Type == structkey {
 				// requires special handling of field names
-				return fmt.Sprintf("%v:%v", Sconv(n.Left.Sym, obj.FmtShort|obj.FmtByte), n.Right)
+				return fmt.Sprintf("%v:%v", sconv(n.Left.Sym, FmtShort|FmtByte), n.Right)
 			} else {
 				return fmt.Sprintf("%v:%v", n.Left, n.Right)
 			}
@@ -1302,19 +1276,24 @@ func exprfmt(n *Node, prec int) string {
 		}
 		return ":"
 
-	case OXDOT,
-		ODOT,
-		ODOTPTR,
-		ODOTINTER,
-		ODOTMETH,
-		OCALLPART:
+	case 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))
+		f += fmt.Sprintf(".%v", sconv(n.Right.Sym, FmtShort|FmtByte))
+		return f
+
+	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
+		var f string
+		f += exprfmt(n.Left, nprec)
+		if n.Sym == nil {
+			f += ".<nil>"
+			return f
+		}
+		f += fmt.Sprintf(".%v", sconv(n.Sym, FmtShort|FmtByte))
 		return f
 
 	case ODOTTYPE, ODOTTYPE2:
@@ -1327,20 +1306,32 @@ func exprfmt(n *Node, prec int) string {
 		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 OINDEX, OINDEXMAP:
+		return fmt.Sprintf("%s[%v]", exprfmt(n.Left, nprec), n.Right)
+
+	case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
+		var buf bytes.Buffer
+		buf.WriteString(exprfmt(n.Left, nprec))
+		buf.WriteString("[")
+		low, high, max := n.SliceBounds()
+		if low != nil {
+			buf.WriteString(low.String())
+		}
+		buf.WriteString(":")
+		if high != nil {
+			buf.WriteString(high.String())
+		}
+		if n.Op.IsSlice3() {
+			buf.WriteString(":")
+			if max != nil {
+				buf.WriteString(max.String())
+			}
+		}
+		buf.WriteString("]")
+		return buf.String()
 
 	case OCOPY, OCOMPLEX:
-		return fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), n.Left, n.Right)
+		return fmt.Sprintf("%#v(%v, %v)", n.Op, n.Left, n.Right)
 
 	case OCONV,
 		OCONVIFACE,
@@ -1356,7 +1347,7 @@ func exprfmt(n *Node, prec int) string {
 		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))
+		return fmt.Sprintf("%v(%v)", n.Type, hconv(n.List, FmtComma))
 
 	case OREAL,
 		OIMAG,
@@ -1372,31 +1363,31 @@ func exprfmt(n *Node, prec int) string {
 		OPRINT,
 		OPRINTN:
 		if n.Left != nil {
-			return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), n.Left)
+			return fmt.Sprintf("%#v(%v)", n.Op, 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...)", n.Op, hconv(n.List, FmtComma))
 		}
-		return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
+		return fmt.Sprintf("%#v(%v)", n.Op, hconv(n.List, 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))
+			f += fmt.Sprintf("(%v...)", hconv(n.List, FmtComma))
 			return f
 		}
-		f += fmt.Sprintf("(%v)", Hconv(n.List, obj.FmtComma))
+		f += fmt.Sprintf("(%v)", hconv(n.List, 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.List.Len() != 0 { // pre-typecheck
+			return fmt.Sprintf("make(%v, %v)", n.Type, hconv(n.List, 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)) {
+		if n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()) {
 			return fmt.Sprintf("make(%v, %v)", n.Type, n.Left)
 		}
 		return fmt.Sprintf("make(%v)", n.Type)
@@ -1409,11 +1400,9 @@ func exprfmt(n *Node, prec int) string {
 		OIND,
 		ONOT,
 		ORECV:
-		var f string
+		f := n.Op.GoString() // %#v
 		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 += " "
 		}
 		f += exprfmt(n.Left, nprec+1)
 		return f
@@ -1442,17 +1431,19 @@ func exprfmt(n *Node, prec int) string {
 		var f string
 		f += exprfmt(n.Left, nprec)
 
-		f += fmt.Sprintf(" %v ", Oconv(int(n.Op), obj.FmtSharp))
+		f += fmt.Sprintf(" %#v ", n.Op)
 		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 {
+		i := 0
+		for _, n1 := range n.List.Slice() {
+			if i != 0 {
 				f += " + "
 			}
-			f += exprfmt(l.N, nprec)
+			f += exprfmt(n1, nprec)
+			i++
 		}
 
 		return f
@@ -1461,15 +1452,22 @@ func exprfmt(n *Node, prec int) string {
 		var f string
 		f += exprfmt(n.Left, nprec)
 		// TODO(marvin): Fix Node.EType type union.
-		f += fmt.Sprintf(" %v ", Oconv(int(n.Etype), obj.FmtSharp))
+		f += fmt.Sprintf(" %#v ", Op(n.Etype))
 		f += exprfmt(n.Right, nprec+1)
 		return f
+
+	case ODCLCONST:
+		// if exporting, DCLCONST should just be removed as its usage
+		// has already been replaced with literals
+		if fmtbody {
+			return ""
+		}
 	}
 
-	return fmt.Sprintf("<node %v>", Oconv(int(n.Op), 0))
+	return fmt.Sprintf("<node %v>", n.Op)
 }
 
-func nodefmt(n *Node, flag int) string {
+func nodefmt(n *Node, flag FmtFlag) string {
 	t := n.Type
 
 	// we almost always want the original, except in export mode for literals
@@ -1479,7 +1477,7 @@ func nodefmt(n *Node, flag int) string {
 		n = n.Orig
 	}
 
-	if flag&obj.FmtLong != 0 && t != nil {
+	if flag&FmtLong != 0 && t != nil {
 		if t.Etype == TNIL {
 			return "nil"
 		} else {
@@ -1505,12 +1503,12 @@ func indent(buf *bytes.Buffer) {
 	}
 }
 
-func nodedump(n *Node, flag int) string {
+func nodedump(n *Node, flag FmtFlag) string {
 	if n == nil {
 		return ""
 	}
 
-	recur := flag&obj.FmtShort == 0
+	recur := flag&FmtShort == 0
 
 	var buf bytes.Buffer
 	if recur {
@@ -1520,41 +1518,41 @@ func nodedump(n *Node, flag int) string {
 			return buf.String()
 		}
 
-		if n.Ninit != nil {
-			fmt.Fprintf(&buf, "%v-init%v", Oconv(int(n.Op), 0), n.Ninit)
+		if n.Ninit.Len() != 0 {
+			fmt.Fprintf(&buf, "%v-init%v", n.Op, n.Ninit)
 			indent(&buf)
 		}
 	}
 
 	switch n.Op {
 	default:
-		fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
+		fmt.Fprintf(&buf, "%v%v", n.Op, 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))
+		fmt.Fprintf(&buf, "%v-%v%v", n.Op, 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))
+		fmt.Fprintf(&buf, "%v-%v%v", n.Op, 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))
+			fmt.Fprintf(&buf, "%v-%v%v", n.Op, n.Sym, jconv(n, 0))
 		} else {
-			fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
+			fmt.Fprintf(&buf, "%v%v", n.Op, jconv(n, 0))
 		}
-		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
+		if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype)
+			fmt.Fprintf(&buf, "%v-ntype%v", n.Op, 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))
+		fmt.Fprintf(&buf, "%v-%v%v", n.Op, Op(n.Etype), 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)
+		fmt.Fprintf(&buf, "%v %v%v type=%v", n.Op, 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)
+			fmt.Fprintf(&buf, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
 		}
 	}
 
@@ -1573,19 +1571,19 @@ func nodedump(n *Node, flag int) string {
 		if n.Right != nil {
 			buf.WriteString(Nconv(n.Right, 0))
 		}
-		if n.List != nil {
+		if n.List.Len() != 0 {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-list%v", Oconv(int(n.Op), 0), n.List)
+			fmt.Fprintf(&buf, "%v-list%v", n.Op, n.List)
 		}
 
-		if n.Rlist != nil {
+		if n.Rlist.Len() != 0 {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-rlist%v", Oconv(int(n.Op), 0), n.Rlist)
+			fmt.Fprintf(&buf, "%v-rlist%v", n.Op, n.Rlist)
 		}
 
-		if n.Nbody != nil {
+		if n.Nbody.Len() != 0 {
 			indent(&buf)
-			fmt.Fprintf(&buf, "%v-body%v", Oconv(int(n.Op), 0), n.Nbody)
+			fmt.Fprintf(&buf, "%v-body%v", n.Op, n.Nbody)
 		}
 	}
 
@@ -1593,13 +1591,13 @@ func nodedump(n *Node, flag int) string {
 }
 
 func (s *Sym) String() string {
-	return Sconv(s, 0)
+	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 {
+func sconv(s *Sym, flag FmtFlag) string {
+	if flag&FmtLong != 0 {
 		panic("linksymfmt")
 	}
 
@@ -1624,11 +1622,95 @@ func (t *Type) String() string {
 	return Tconv(t, 0)
 }
 
+func Fldconv(f *Field, flag FmtFlag) string {
+	if f == nil {
+		return "<T>"
+	}
+
+	sf := flag
+	sm, sb := setfmode(&flag)
+
+	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
+		fmtpkgpfx++
+	}
+	if fmtpkgpfx != 0 {
+		flag |= FmtUnsigned
+	}
+
+	var name string
+	if flag&FmtShort == 0 {
+		s := f.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) && f.Nname != nil {
+			if f.Nname.Orig != nil {
+				s = f.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 && f.Embedded == 0 {
+			if f.Funarg != FunargNone {
+				name = Nconv(f.Nname, 0)
+			} else if flag&FmtLong != 0 {
+				name = sconv(s, FmtShort|FmtByte) // qualify non-exported names (used on structs, not on funarg)
+			} else {
+				name = sconv(s, 0)
+			}
+		} else if fmtmode == FExp {
+			if f.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 {
+				name = fmt.Sprintf("@%q.?", s.Pkg.Path)
+			} else {
+				name = "?"
+			}
+		}
+	}
+
+	var typ string
+	if f.Isddd {
+		typ = "..." + Tconv(f.Type.Elem(), 0)
+	} else {
+		typ = Tconv(f.Type, 0)
+	}
+
+	str := typ
+	if name != "" {
+		str = name + " " + typ
+	}
+
+	// The fmtbody flag is intended to suppress escape analysis annotations
+	// when printing a function type used in a function body.
+	// (The escape analysis tags do not apply to func vars.)
+	// But it must not suppress struct field tags.
+	// See golang.org/issue/13777 and golang.org/issue/14331.
+	if flag&FmtShort == 0 && (!fmtbody || f.Funarg == FunargNone) && f.Note != "" {
+		str += " " + strconv.Quote(f.Note)
+	}
+
+	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
+		fmtpkgpfx--
+	}
+
+	flag = sf
+	fmtbody = sb
+	fmtmode = sm
+	return str
+}
+
 // 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 {
+func Tconv(t *Type, flag FmtFlag) string {
 	if t == nil {
 		return "<T>"
 	}
@@ -1641,16 +1723,16 @@ func Tconv(t *Type, flag int) string {
 	sf := flag
 	sm, sb := setfmode(&flag)
 
-	if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
+	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
 		fmtpkgpfx++
 	}
 	if fmtpkgpfx != 0 {
-		flag |= obj.FmtUnsigned
+		flag |= FmtUnsigned
 	}
 
 	str := typefmt(t, flag)
 
-	if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
+	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
 		fmtpkgpfx--
 	}
 
@@ -1668,7 +1750,7 @@ func (n *Node) String() string {
 // 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 {
+func Nconv(n *Node, flag FmtFlag) string {
 	if n == nil {
 		return "<N>"
 	}
@@ -1695,14 +1777,14 @@ func Nconv(n *Node, flag int) string {
 	return str
 }
 
-func (l *NodeList) String() string {
-	return Hconv(l, 0)
+func (n Nodes) String() string {
+	return hconv(n, 0)
 }
 
-// Fmt '%H': NodeList.
+// Fmt '%H': Nodes.
 // 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 {
+func hconv(l Nodes, flag FmtFlag) string {
+	if l.Len() == 0 && fmtmode == FDbg {
 		return "<nil>"
 	}
 
@@ -1711,14 +1793,14 @@ func Hconv(l *NodeList, flag int) string {
 	sep := "; "
 	if fmtmode == FDbg {
 		sep = "\n"
-	} else if flag&obj.FmtComma != 0 {
+	} else if flag&FmtComma != 0 {
 		sep = ", "
 	}
 
 	var buf bytes.Buffer
-	for ; l != nil; l = l.Next {
-		buf.WriteString(Nconv(l.N, 0))
-		if l.Next != nil {
+	for i, n := range l.Slice() {
+		buf.WriteString(Nconv(n, 0))
+		if i+1 < l.Len() {
 			buf.WriteString(sep)
 		}
 	}
@@ -1729,10 +1811,10 @@ func Hconv(l *NodeList, flag int) string {
 	return buf.String()
 }
 
-func dumplist(s string, l *NodeList) {
-	fmt.Printf("%s%v\n", s, Hconv(l, obj.FmtSign))
+func dumplist(s string, l Nodes) {
+	fmt.Printf("%s%v\n", s, hconv(l, FmtSign))
 }
 
 func Dump(s string, n *Node) {
-	fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, obj.FmtSign))
+	fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, FmtSign))
 }
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index b756055..fc0003d 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -2,18 +2,18 @@
 // 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.
+
 package gc
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 )
 
-// portable half of code generator.
-// mainly statements and control flow.
-var labellist *Label
-
-var lastlabel *Label
+// TODO: labellist should become part of a "compilation state" for functions.
+var labellist []*Label
 
 func Sysfunc(name string) *Node {
 	n := newname(Pkglookup(name, Runtimepkg))
@@ -43,49 +43,38 @@ func addrescapes(n *Node) {
 			break
 		}
 
-		switch n.Class {
-		case PPARAMREF:
+		// If a closure reference escapes, mark the outer variable as escaping.
+		if n.isClosureVar() {
 			addrescapes(n.Name.Defn)
+			break
+		}
 
-		// 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)
+		if n.Class != PPARAM && n.Class != PPARAMOUT && n.Class != PAUTO {
+			break
+		}
 
-			n.Name.Param.Stackparam.Type = n.Type
-			n.Name.Param.Stackparam.Addable = true
-			if n.Xoffset == BADWIDTH {
-				Fatalf("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
+		// This is a plain parameter or local variable that needs to move to the heap,
+		// but possibly for the function outside the one we're compiling.
+		// That is, if we have:
+		//
+		//	func f(x int) {
+		//		func() {
+		//			global = &x
+		//		}
+		//	}
+		//
+		// then we're analyzing the inner closure but we need to move x to the
+		// heap in f, not in the inner closure. Flip over to f before calling moveToHeap.
+		oldfn := Curfn
+		Curfn = n.Name.Curfn
+		if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
+			Curfn = Curfn.Func.Closure
 		}
+		ln := lineno
+		lineno = Curfn.Lineno
+		moveToHeap(n)
+		Curfn = oldfn
+		lineno = ln
 
 	case OIND, ODOTPTR:
 		break
@@ -96,19 +85,129 @@ func addrescapes(n *Node) {
 	// escape--the pointer inside x does, but that
 	// is always a heap pointer anyway.
 	case ODOT, OINDEX, OPAREN, OCONVNOP:
-		if !Isslice(n.Left.Type) {
+		if !n.Left.Type.IsSlice() {
 			addrescapes(n.Left)
 		}
 	}
 }
 
+// isParamStackCopy reports whether this is the on-stack copy of a
+// function parameter that moved to the heap.
+func (n *Node) isParamStackCopy() bool {
+	return n.Op == ONAME && (n.Class == PPARAM || n.Class == PPARAMOUT) && n.Name.Heapaddr != nil
+}
+
+// isParamHeapCopy reports whether this is the on-heap copy of
+// a function parameter that moved to the heap.
+func (n *Node) isParamHeapCopy() bool {
+	return n.Op == ONAME && n.Class == PAUTOHEAP && n.Name.Param.Stackcopy != nil
+}
+
+// paramClass reports the parameter class (PPARAM or PPARAMOUT)
+// of the node, which may be an unmoved on-stack parameter
+// or the on-heap or on-stack copy of a parameter that moved to the heap.
+// If the node is not a parameter, paramClass returns Pxxx.
+func (n *Node) paramClass() Class {
+	if n.Op != ONAME {
+		return Pxxx
+	}
+	if n.Class == PPARAM || n.Class == PPARAMOUT {
+		return n.Class
+	}
+	if n.isParamHeapCopy() {
+		return n.Name.Param.Stackcopy.Class
+	}
+	return Pxxx
+}
+
+// moveToHeap records the parameter or local variable n as moved to the heap.
+func moveToHeap(n *Node) {
+	if Debug['r'] != 0 {
+		Dump("MOVE", n)
+	}
+	if compiling_runtime {
+		Yyerror("%v escapes to heap, not allowed in runtime.", n)
+	}
+	if n.Class == PAUTOHEAP {
+		Dump("n", n)
+		Fatalf("double move to heap")
+	}
+
+	// Allocate a local stack variable to hold the pointer to the heap copy.
+	// temp will add it to the function declaration list automatically.
+	heapaddr := temp(Ptrto(n.Type))
+	heapaddr.Sym = Lookup("&" + n.Sym.Name)
+	heapaddr.Orig.Sym = heapaddr.Sym
+
+	// Parameters have a local stack copy used at function start/end
+	// in addition to the copy in the heap that may live longer than
+	// the function.
+	if n.Class == PPARAM || n.Class == PPARAMOUT {
+		if n.Xoffset == BADWIDTH {
+			Fatalf("addrescapes before param assignment")
+		}
+
+		// We rewrite n below to be a heap variable (indirection of heapaddr).
+		// Preserve a copy so we can still write code referring to the original,
+		// and substitute that copy into the function declaration list
+		// so that analyses of the local (on-stack) variables use it.
+		stackcopy := Nod(ONAME, nil, nil)
+		stackcopy.Sym = n.Sym
+		stackcopy.Type = n.Type
+		stackcopy.Xoffset = n.Xoffset
+		stackcopy.Class = n.Class
+		stackcopy.Name.Heapaddr = heapaddr
+		if n.Class == PPARAM {
+			stackcopy.SetNotLiveAtEnd(true)
+		}
+		if n.Class == PPARAMOUT {
+			// Make sure the pointer to the heap copy is kept live throughout the function.
+			// The function could panic at any point, and then a defer could recover.
+			// Thus, we need the pointer to the heap copy always available so the
+			// post-deferreturn code can copy the return value back to the stack.
+			// See issue 16095.
+			heapaddr.setIsOutputParamHeapAddr(true)
+		}
+		n.Name.Param.Stackcopy = stackcopy
+
+		// Substitute the stackcopy into the function variable list so that
+		// liveness and other analyses use the underlying stack slot
+		// and not the now-pseudo-variable n.
+		found := false
+		for i, d := range Curfn.Func.Dcl {
+			if d == n {
+				Curfn.Func.Dcl[i] = stackcopy
+				found = true
+				break
+			}
+			// Parameters are before locals, so can stop early.
+			// This limits the search even in functions with many local variables.
+			if d.Class == PAUTO {
+				break
+			}
+		}
+		if !found {
+			Fatalf("cannot find %v in local variable list", n)
+		}
+		Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
+	}
+
+	// Modify n in place so that uses of n now mean indirection of the heapaddr.
+	n.Class = PAUTOHEAP
+	n.Ullman = 2
+	n.Xoffset = 0
+	n.Name.Heapaddr = heapaddr
+	n.Esc = EscHeap
+	if Debug['m'] != 0 {
+		fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
+	}
+}
+
 func clearlabels() {
-	for l := labellist; l != nil; l = l.Link {
+	for _, l := range labellist {
 		l.Sym.Label = nil
 	}
-
-	labellist = nil
-	lastlabel = nil
+	labellist = labellist[:0]
 }
 
 func newlab(n *Node) *Label {
@@ -116,14 +215,9 @@ func newlab(n *Node) *Label {
 	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
+		labellist = append(labellist, lab)
 	}
 
 	if n.Op == OLABEL {
@@ -139,6 +233,8 @@ func newlab(n *Node) *Label {
 	return lab
 }
 
+// There is a copy of checkgoto in the new SSA backend.
+// Please keep them in sync.
 func checkgoto(from *Node, to *Node) {
 	if from.Sym == to.Sym {
 		return
@@ -157,7 +253,7 @@ func checkgoto(from *Node, to *Node) {
 		fs = fs.Link
 	}
 	if fs != to.Sym {
-		lno := int(lineno)
+		lno := lineno
 		setlineno(from)
 
 		// decide what to complain about.
@@ -187,11 +283,11 @@ func checkgoto(from *Node, to *Node) {
 		}
 
 		if block != nil {
-			Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
+			Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
 		} else {
-			Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
+			Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, linestr(dcl.Lastlineno))
 		}
-		lineno = int32(lno)
+		lineno = lno
 	}
 }
 
@@ -210,9 +306,9 @@ func stmtlabel(n *Node) *Label {
 }
 
 // compile statements
-func Genlist(l *NodeList) {
-	for ; l != nil; l = l.Next {
-		gen(l.N)
+func Genlist(l Nodes) {
+	for _, n := range l.Slice() {
+		gen(n)
 	}
 }
 
@@ -220,7 +316,7 @@ func Genlist(l *NodeList) {
 func cgen_proc(n *Node, proc int) {
 	switch n.Left.Op {
 	default:
-		Fatalf("cgen_proc: unknown call %v", Oconv(int(n.Left.Op), 0))
+		Fatalf("cgen_proc: unknown call %v", n.Left.Op)
 
 	case OCALLMETH:
 		cgen_callmeth(n.Left, proc)
@@ -245,16 +341,9 @@ func cgen_dcl(n *Node) {
 		Fatalf("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)
+	if n.Class == PAUTOHEAP {
+		Fatalf("cgen_dcl %v", n)
 	}
-	Cgen_as(n.Name.Heapaddr, prealloc[n])
 }
 
 // generate discard of value
@@ -265,7 +354,7 @@ func cgen_discard(nr *Node) {
 
 	switch nr.Op {
 	case ONAME:
-		if nr.Class&PHEAP == 0 && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF {
+		if nr.Class != PAUTOHEAP && nr.Class != PEXTERN && nr.Class != PFUNC {
 			gused(nr)
 		}
 
@@ -322,12 +411,12 @@ func Clearslim(n *Node) {
 	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)
+		z.Val().U.(*Mpcplx).Real.SetFloat64(0.0)
+		z.Val().U.(*Mpcplx).Imag.SetFloat64(0.0)
 
 	case TFLOAT32, TFLOAT64:
 		var zero Mpflt
-		Mpmovecflt(&zero, 0.0)
+		zero.SetFloat64(0.0)
 		z.SetVal(Val{&zero})
 
 	case TPTR32, TPTR64, TCHAN, TMAP:
@@ -345,7 +434,7 @@ func Clearslim(n *Node) {
 		TUINT32,
 		TUINT64:
 		z.SetVal(Val{new(Mpint)})
-		Mpmovecfix(z.Val().U.(*Mpint), 0)
+		z.Val().U.(*Mpint).SetInt64(0)
 
 	default:
 		Fatalf("clearslim called on type %v", n.Type)
@@ -406,7 +495,7 @@ func cgen_dottype(n *Node, res, resok *Node, wb bool) {
 	Regalloc(&r1, byteptr, nil)
 	iface.Type = byteptr
 	Cgen(&iface, &r1)
-	if !isnilinter(n.Left.Type) {
+	if !n.Left.Type.IsEmptyInterface() {
 		// Holding itab, want concrete type in second word.
 		p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
 		r2 = r1
@@ -429,13 +518,13 @@ func cgen_dottype(n *Node, res, resok *Node, wb bool) {
 		q := Gbranch(obj.AJMP, nil, 0)
 		Patch(p, Pc)
 		Regrealloc(&r2) // reclaim from above, for this failure path
-		fn := syslook("panicdottype", 0)
+		fn := syslook("panicdottype")
 		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)
+		call.List.Set([]*Node{&r1, &r2, typename(n.Left.Type)})
+		call.List.Set(ascompatte(OCALLFUNC, call, false, fn.Type.Params(), call.List.Slice(), 0, nil))
 		gen(call)
 		Regfree(&r1)
 		Regfree(&r2)
@@ -495,7 +584,7 @@ func Cgen_As2dottype(n, res, resok *Node) {
 	Regalloc(&r1, byteptr, res)
 	iface.Type = byteptr
 	Cgen(&iface, &r1)
-	if !isnilinter(n.Left.Type) {
+	if !n.Left.Type.IsEmptyInterface() {
 		// Holding itab, want concrete type in second word.
 		p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
 		r2 = r1
@@ -517,11 +606,11 @@ func Cgen_As2dottype(n, res, resok *Node) {
 	q := Gbranch(obj.AJMP, nil, 0)
 	Patch(p, Pc)
 
-	fn := syslook("panicdottype", 0)
+	fn := syslook("panicdottype")
 	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)
+	call.List.Set([]*Node{&r1, &r2, typename(n.Left.Type)})
+	call.List.Set(ascompatte(OCALLFUNC, call, false, fn.Type.Params(), call.List.Slice(), 0, nil))
 	gen(call)
 	Regfree(&r1)
 	Regfree(&r2)
@@ -585,6 +674,10 @@ func Tempname(nn *Node, t *Type) {
 	if Curfn == nil {
 		Fatalf("no curfn for tempname")
 	}
+	if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
+		Dump("Tempname", Curfn)
+		Fatalf("adding tempname to wrong closure function")
+	}
 
 	if t == nil {
 		Yyerror("tempname called with nil type")
@@ -593,7 +686,7 @@ func Tempname(nn *Node, t *Type) {
 
 	// give each tmp a different name so that there
 	// a chance to registerizer them
-	s := Lookupf("autotmp_%.4d", statuniqgen)
+	s := LookupN("autotmp_", statuniqgen)
 	statuniqgen++
 	n := Nod(ONAME, nil, nil)
 	n.Sym = s
@@ -604,7 +697,7 @@ func Tempname(nn *Node, t *Type) {
 	n.Ullman = 1
 	n.Esc = EscNever
 	n.Name.Curfn = Curfn
-	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
 
 	dowidth(t)
 	n.Xoffset = 0
@@ -612,8 +705,8 @@ func Tempname(nn *Node, t *Type) {
 }
 
 func temp(t *Type) *Node {
-	n := Nod(OXXX, nil, nil)
-	Tempname(n, t)
+	var n Node
+	Tempname(&n, t)
 	n.Sym.Def.Used = true
 	return n.Orig
 }
@@ -629,7 +722,7 @@ func gen(n *Node) {
 		goto ret
 	}
 
-	if n.Ninit != nil {
+	if n.Ninit.Len() > 0 {
 		Genlist(n.Ninit)
 	}
 
@@ -637,7 +730,7 @@ func gen(n *Node) {
 
 	switch n.Op {
 	default:
-		Fatalf("gen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
+		Fatalf("gen: unknown op %v", Nconv(n, FmtShort|FmtSign))
 
 	case OCASE,
 		OFALL,
@@ -827,7 +920,7 @@ func gen(n *Node) {
 		cgen_dcl(n.Left)
 
 	case OAS:
-		if gen_as_init(n) {
+		if gen_as_init(n, false) {
 			break
 		}
 		Cgen_as(n.Left, n.Right)
@@ -836,7 +929,7 @@ func gen(n *Node) {
 		Cgen_as_wb(n.Left, n.Right, true)
 
 	case OAS2DOTTYPE:
-		cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, needwritebarrier(n.List.N, n.Rlist.N))
+		cgen_dottype(n.Rlist.First(), n.List.First(), n.List.Second(), needwritebarrier(n.List.First(), n.Rlist.First()))
 
 	case OCALLMETH:
 		cgen_callmeth(n, 0)
@@ -867,10 +960,10 @@ func gen(n *Node) {
 		Cgen_checknil(n.Left)
 
 	case OVARKILL:
-		gvarkill(n.Left)
+		Gvarkill(n.Left)
 
 	case OVARLIVE:
-		gvarlive(n.Left)
+		Gvarlive(n.Left)
 	}
 
 ret:
@@ -906,11 +999,6 @@ func Cgen_as_wb(nl, nr *Node, wb bool) {
 	}
 
 	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
@@ -947,7 +1035,7 @@ func cgen_callmeth(n *Node, proc int) {
 
 	n2 := *n
 	n2.Op = OCALLFUNC
-	n2.Left = l.Right
+	n2.Left = newname(l.Sym)
 	n2.Left.Type = l.Type
 
 	if n2.Left.Op == ONAME {
@@ -965,16 +1053,16 @@ func CgenTemp(n *Node) *Node {
 }
 
 func checklabels() {
-	for lab := labellist; lab != nil; lab = lab.Link {
+	for _, lab := range labellist {
 		if lab.Def == nil {
 			for _, n := range lab.Use {
-				yyerrorl(int(n.Lineno), "label %v not defined", lab.Sym)
+				yyerrorl(n.Lineno, "label %v not defined", lab.Sym)
 			}
 			continue
 		}
 
 		if lab.Use == nil && !lab.Used {
-			yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", lab.Sym)
+			yyerrorl(lab.Def.Lineno, "label %v defined and not used", lab.Sym)
 			continue
 		}
 
@@ -1029,7 +1117,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool {
 		// Emit vardef if needed.
 		if nl.Op == ONAME {
 			switch nl.Type.Etype {
-			case TARRAY, TSTRING, TINTER, TSTRUCT:
+			case TARRAY, TSLICE, TSTRING, TINTER, TSTRUCT:
 				Gvardef(nl)
 			}
 		}
@@ -1077,7 +1165,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool {
 			nodl.Type = t
 			nodl.Xoffset = lbase + offset
 			nodr.Type = t
-			if Isfloat[t.Etype] {
+			if t.IsFloat() {
 				// TODO(rsc): Cache zero register like we do for integers?
 				Clearslim(&nodl)
 			} else {
@@ -1173,7 +1261,7 @@ func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset i
 		}
 		// NOTE: Assuming little endian (signed top half at offset 4).
 		// We don't have any 32-bit big-endian systems.
-		if Thearch.Thechar != '5' && Thearch.Thechar != '8' {
+		if !Thearch.LinkArch.InFamily(sys.ARM, sys.I386) {
 			Fatalf("unknown 32-bit architecture")
 		}
 		return f(Types[TUINT32], startOffset) &&
@@ -1202,42 +1290,27 @@ func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset i
 		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))
-		}
+	case TSLICE:
+		return f(Ptrto(t.Elem()), startOffset+int64(Array_array)) &&
+			f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
+			f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
 
+	case TARRAY:
 		// Short-circuit [1e6]struct{}.
-		if t.Type.Width == 0 {
+		if t.Elem().Width == 0 {
 			return true
 		}
 
-		for i := int64(0); i < t.Bound; i++ {
-			if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) {
+		for i := int64(0); i < t.NumElem(); i++ {
+			if !visitComponents(t.Elem(), startOffset+i*t.Elem().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.
-			Fatalf("struct not at offset 0")
-		}
-
-		for field := t.Type; field != nil; field = field.Down {
-			if field.Etype != TFIELD {
-				Fatalf("bad struct")
-			}
-			if !visitComponents(field.Type, startOffset+field.Width, f) {
+		for _, field := range t.Fields().Slice() {
+			if !visitComponents(field.Type, startOffset+field.Offset, f) {
 				return false
 			}
 		}
diff --git a/src/cmd/compile/internal/gc/global_test.go b/src/cmd/compile/internal/gc/global_test.go
index 6c388af..f0139e7 100644
--- a/src/cmd/compile/internal/gc/global_test.go
+++ b/src/cmd/compile/internal/gc/global_test.go
@@ -11,12 +11,13 @@ import (
 	"log"
 	"os"
 	"os/exec"
-	"path"
+	"path/filepath"
+	"strings"
 	"testing"
 )
 
 // Make sure "hello world" does not link in all the
-// fmt.scanf routines.  See issue 6853.
+// fmt.scanf routines. See issue 6853.
 func TestScanfRemoval(t *testing.T) {
 	testenv.MustHaveGoBuild(t)
 
@@ -28,7 +29,7 @@ func TestScanfRemoval(t *testing.T) {
 	defer os.RemoveAll(dir)
 
 	// Create source.
-	src := path.Join(dir, "test.go")
+	src := filepath.Join(dir, "test.go")
 	f, err := os.Create(src)
 	if err != nil {
 		log.Fatalf("could not create source file: %v", err)
@@ -43,7 +44,7 @@ func main() {
 	f.Close()
 
 	// Name of destination.
-	dst := path.Join(dir, "test")
+	dst := filepath.Join(dir, "test")
 
 	// Compile source.
 	cmd := exec.Command("go", "build", "-o", dst, src)
@@ -58,7 +59,57 @@ func main() {
 	if err != nil {
 		log.Fatalf("could not read target: %v", err)
 	}
-	if bytes.Index(out, []byte("scanInt")) != -1 {
+	if bytes.Contains(out, []byte("scanInt")) {
 		log.Fatalf("scanf code not removed from helloworld")
 	}
 }
+
+// Make sure -S prints assembly code. See issue 14515.
+func TestDashS(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	// Make a directory to work in.
+	dir, err := ioutil.TempDir("", "issue14515-")
+	if err != nil {
+		log.Fatalf("could not create directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	// Create source.
+	src := filepath.Join(dir, "test.go")
+	f, err := os.Create(src)
+	if err != nil {
+		log.Fatalf("could not create source file: %v", err)
+	}
+	f.Write([]byte(`
+package main
+import "fmt"
+func main() {
+	fmt.Println("hello world")
+}
+`))
+	f.Close()
+
+	// Compile source.
+	cmd := exec.Command("go", "build", "-gcflags", "-S", "-o", filepath.Join(dir, "test"), src)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		log.Fatalf("could not build target: %v", err)
+	}
+
+	patterns := []string{
+		// It is hard to look for actual instructions in an
+		// arch-independent way. So we'll just look for
+		// pseudo-ops that are arch-independent.
+		"\tTEXT\t",
+		"\tFUNCDATA\t",
+		"\tPCDATA\t",
+	}
+	outstr := string(out)
+	for _, p := range patterns {
+		if !strings.Contains(outstr, p) {
+			println(outstr)
+			panic("can't find pattern " + p)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index 3146cae..2e4caca 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -5,123 +5,22 @@
 package gc
 
 import (
-	"bytes"
-	"cmd/compile/internal/big"
+	"bufio"
+	"cmd/compile/internal/ssa"
+	"cmd/internal/bio"
 	"cmd/internal/obj"
 )
 
-// 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() Ctype {
-	switch x := v.U.(type) {
-	default:
-		Fatalf("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
+	Name     string // package name, e.g. "sys"
+	Path     string // string literal used in import statement, e.g. "runtime/internal/sys"
+	Pathsym  *obj.LSym
 	Prefix   string // escaped path for use in symbol table
 	Imported bool   // export data of this package was parsed
 	Exported bool   // import line written in export data
@@ -130,11 +29,17 @@ type Pkg struct {
 	Syms     map[string]*Sym
 }
 
+// Sym represents an object name. Most commonly, this is a Go identifier naming
+// an object declared within a package, but Syms are also used to name internal
+// synthesized objects.
+//
+// As a special exception, field and method names that are exported use the Sym
+// associated with localpkg instead of the package that declared them. This
+// allows using Sym pointer equality to test for Go identifier uniqueness when
+// handling selector expressions.
 type Sym struct {
-	Lexical   uint16
-	Flags     uint8
+	Flags     SymFlags
 	Link      *Sym
-	Uniqgen   uint32
 	Importdef *Pkg   // where imported definition was found
 	Linkname  string // link name
 
@@ -142,82 +47,19 @@ type Sym struct {
 	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       EType
-	Nointerface bool
-	Noalg       bool
-	Chan        uint8
-	Trecur      uint8 // to detect loops
-	Printed     bool
-	Embedded    uint8 // TFIELD embedded type
-	Funarg      bool  // on TSTRUCT and TFIELD
-	Copyany     bool
-	Local       bool // created in this file
-	Deferwidth  bool
-	Broke       bool // 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  bool
-
-	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 []*Node
-
-	Lastfn *Node // for usefield
+	Label   *Label // corresponding label (ephemeral)
+	Origpkg *Pkg   // original package for . import
+	Lsym    *obj.LSym
+	Fsym    *Sym // funcsym
 }
 
 type Label struct {
-	Sym  *Sym
-	Def  *Node
-	Use  []*Node
-	Link *Label
+	Sym *Sym
+	Def *Node
+	Use []*Node
 
 	// for use during gen
 	Gotopc   *obj.Prog // pointer to unresolved gotos
@@ -228,112 +70,16 @@ type Label struct {
 	Used bool
 }
 
-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
-}
+type SymFlags uint8
 
 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
-}
-
-type EType uint8
-
-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 // Doesn't seem to be used in existing code. Used now for Isddd export (see bexport.go). TODO(gri) rename.
-	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
-)
-
-// Ctype describes the constant kind of an "ideal" (untyped) constant.
-type Ctype int8
-
-const (
-	CTxxx Ctype = 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
+	SymExport SymFlags = 1 << iota // to be exported
+	SymPackage
+	SymExported // already written out by export
+	SymUniq
+	SymSiggen
+	SymAsm
+	SymAlgGen
 )
 
 // The Class of a variable/function describes the "storage class"
@@ -345,84 +91,14 @@ const (
 	Pxxx      Class = iota
 	PEXTERN         // global variable
 	PAUTO           // local variables
+	PAUTOHEAP       // local variable or parameter moved to heap
 	PPARAM          // input arguments
 	PPARAMOUT       // output results
-	PPARAMREF       // closure variable reference
 	PFUNC           // global function
 
 	PDISCARD // discard during parse of duplicate import
-
-	PHEAP = 1 << 7 // an extra bit to identify an escaped variable
-)
-
-const (
-	Etop      = 1 << 1 // 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  EType
-	Sameas EType
-}
-
-type Sig struct {
-	name   string
-	pkg    *Pkg
-	isym   *Sym
-	tsym   *Sym
-	type_  *Type
-	mtype  *Type
-	offset int32
-}
-
-type Io struct {
-	infile     string
-	bin        *obj.Biobuf
-	cp         string // used for content when bin==nil
-	last       int
-	peekc      int
-	peekc1     int // second peekc for ...
-	nlsemi     bool
-	eofnl      bool
-	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.
 //
@@ -450,25 +126,14 @@ var sizeof_Array int // runtime sizeof(Array)
 // } 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 linkobj string
 
-var bout *obj.Biobuf
+var bout *bio.Writer
 
 var nerrors int
 
@@ -478,13 +143,9 @@ var nsyntaxerrors int
 
 var decldepth int32
 
-var safemode int
-
-var nolocalimports int
+var safemode bool
 
-var lexbuf bytes.Buffer
-var strbuf bytes.Buffer
-var litbuf string // LLITERAL value for use in syntax error messages
+var nolocalimports bool
 
 var Debug [256]int
 
@@ -493,19 +154,15 @@ 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 autopkg *Pkg // fake package for allocating auto variables
 
-var builtinpkg *Pkg // fake package for builtins
+var importpkg *Pkg // package being imported
 
-var gostringpkg *Pkg // fake pkg for Go strings
+var itabpkg *Pkg // fake pkg for itab entries
 
-var itabpkg *Pkg // fake pkg for itab cache
+var itablinkpkg *Pkg // fake package for runtime itab entries
 
 var Runtimepkg *Pkg // package runtime
 
@@ -515,45 +172,28 @@ var msanpkg *Pkg // package runtime/msan
 
 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 mappkg *Pkg // fake package for map zero value
+var zerosize int64
+
 var Tptr EType // 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]EType
 
 var (
-	Isptr     [NTYPE]bool
 	isforw    [NTYPE]bool
 	Isint     [NTYPE]bool
 	Isfloat   [NTYPE]bool
 	Iscomplex [NTYPE]bool
-	Issigned  [NTYPE]bool
 	issimple  [NTYPE]bool
 )
 
@@ -583,9 +223,7 @@ var minfltval [NTYPE]*Mpflt
 
 var maxfltval [NTYPE]*Mpflt
 
-var xtop *NodeList
-
-var externdcl []*Node
+var xtop []*Node
 
 var exportlist []*Node
 
@@ -601,7 +239,7 @@ var statuniqgen int // name generator for static temps
 
 var iota_ int32
 
-var lastconst *NodeList
+var lastconst []*Node
 
 var lasttype *Node
 
@@ -611,10 +249,6 @@ 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 bool // flag that curfn has defer statement
 
 var Curfn *Node
@@ -627,50 +261,35 @@ var Widthreg int
 
 var nblank *Node
 
-var Funcdepth int32
-
 var typecheckok bool
 
-var compiling_runtime int
+var compiling_runtime bool
 
 var compiling_wrappers int
 
-var use_writebarrier int
+var use_writebarrier bool
 
-var pure_go int
+var pure_go bool
 
 var flag_installsuffix string
 
-var flag_race int
+var flag_race bool
 
-var flag_msan int
+var flag_msan bool
 
-var flag_largemodel int
+var flag_largemodel bool
 
 // Whether we are adding any sort of code instrumentation, such as
 // when the race detector is enabled.
 var instrumenting bool
 
-// Pending annotations for next func declaration.
-var (
-	noescape          bool
-	noinline          bool
-	norace            bool
-	nosplit           bool
-	nowritebarrier    bool
-	nowritebarrierrec bool
-	systemstack       bool
-)
-
 var debuglive int
 
 var Ctxt *obj.Link
 
-var nointerface bool
+var writearchive bool
 
-var writearchive int
-
-var bstdout obj.Biobuf
+var bstdout *bufio.Writer
 
 var Nacl bool
 
@@ -684,34 +303,6 @@ var nodfp *Node
 
 var Disable_checknil int
 
-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 bool   // 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 (
@@ -755,6 +346,9 @@ const (
 
 	// Set, use, or kill of carry bit.
 	// Kill means we never look at the carry bit after this kind of instruction.
+	// Originally for understanding ADC, RCR, and so on, but now also
+	// tracks set, use, and kill of the zero and overflow bits as well.
+	// TODO rename to {Set,Use,Kill}Flags
 	SetCarry  = 1 << 24
 	UseCarry  = 1 << 25
 	KillCarry = 1 << 26
@@ -768,10 +362,8 @@ const (
 )
 
 type Arch struct {
-	Thechar      int
-	Thestring    string
-	Thelinkarch  *obj.LinkArch
-	Typedefs     []Typedef
+	LinkArch *obj.LinkArch
+
 	REGSP        int
 	REGCTXT      int
 	REGCALLX     int // BX
@@ -785,23 +377,25 @@ type Arch struct {
 	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(Op, *Node, *Node, *Node) bool
-	Cgen_float   func(*Node, *Node) // optional
-	Cgen_hmul    func(*Node, *Node, *Node)
-	Cgen_shift   func(Op, bool, *Node, *Node, *Node)
-	Clearfat     func(*Node)
-	Cmp64        func(*Node, *Node, Op, int, *obj.Prog) // only on 32-bit systems
-	Defframe     func(*obj.Prog)
-	Dodiv        func(Op, *Node, *Node, *Node)
-	Excise       func(*Flow)
-	Expandchecks func(*obj.Prog)
-	Getg         func(*Node)
-	Gins         func(int, *Node, *Node) *obj.Prog
+	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(Op, *Node, *Node, *Node) bool
+	Cgen_float          func(*Node, *Node) // optional
+	Cgen_hmul           func(*Node, *Node, *Node)
+	RightShiftWithCarry func(*Node, uint, *Node)  // only on systems without RROTC instruction
+	AddSetCarry         func(*Node, *Node, *Node) // only on systems when ADD does not update carry flag
+	Cgen_shift          func(Op, bool, *Node, *Node, *Node)
+	Clearfat            func(*Node)
+	Cmp64               func(*Node, *Node, Op, int, *obj.Prog) // only on 32-bit systems
+	Defframe            func(*obj.Prog)
+	Dodiv               func(Op, *Node, *Node, *Node)
+	Excise              func(*Flow)
+	Expandchecks        func(*obj.Prog)
+	Getg                func(*Node)
+	Gins                func(obj.As, *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.
@@ -821,13 +415,12 @@ type Arch struct {
 	// corresponding to the desired value.
 	// The second argument is the destination.
 	// If not present, Ginsboolval will be emulated with jumps.
-	Ginsboolval func(int, *Node)
+	Ginsboolval func(obj.As, *Node)
 
-	Ginscon      func(int, int64, *Node)
+	Ginscon      func(obj.As, 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
@@ -835,17 +428,30 @@ type Arch struct {
 	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
+	Sudoaddable  func(obj.As, *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(Op, *Type) int
+	Optoas       func(Op, *Type) obj.As
 	Doregbits    func(int) uint64
 	Regnames     func(*int) []string
 	Use387       bool // should 8g use 387 FP instructions instead of sse2.
+
+	// SSARegToReg maps ssa register numbers to obj register numbers.
+	SSARegToReg []int16
+
+	// SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
+	SSAMarkMoves func(*SSAGenState, *ssa.Block)
+
+	// SSAGenValue emits Prog(s) for the Value.
+	SSAGenValue func(*SSAGenState, *ssa.Value)
+
+	// SSAGenBlock emits end-of-block Progs. SSAGenValue should be called
+	// for all values in the block before SSAGenBlock.
+	SSAGenBlock func(s *SSAGenState, b, next *ssa.Block)
 }
 
 var pcloc int32
@@ -862,4 +468,13 @@ var Panicindex *Node
 
 var panicslice *Node
 
+var panicdivide *Node
+
 var throwreturn *Node
+
+var growslice *Node
+
+var writebarrierptr *Node
+var typedmemmove *Node
+
+var panicdottype *Node
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index 30bf736..4943d9d 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,16 +32,17 @@ package gc
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"runtime"
 	"strings"
 )
 
-var ddumped int
-
-var dfirst *obj.Prog
-
-var dpc *obj.Prog
+var (
+	ddumped bool
+	dfirst  *obj.Prog
+	dpc     *obj.Prog
+)
 
 // Is this node a memory operand?
 func Ismem(n *Node) bool {
@@ -52,12 +53,13 @@ func Ismem(n *Node) bool {
 		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
+		// amd64 and s390x use PC relative addressing.
+		// TODO(rsc): not sure why ppc64 needs this too.
+		return Thearch.LinkArch.InFamily(sys.AMD64, sys.PPC64, sys.S390X)
 	}
 
 	return false
@@ -79,11 +81,11 @@ func Samereg(a *Node, b *Node) bool {
 	return true
 }
 
-func Gbranch(as int, t *Type, likely int) *obj.Prog {
+func Gbranch(as obj.As, 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' && Thearch.Thechar != '0' {
+	if as != obj.AJMP && likely != 0 && !Thearch.LinkArch.InFamily(sys.PPC64, sys.ARM64, sys.MIPS64, sys.S390X) {
 		p.From.Type = obj.TYPE_CONST
 		if likely > 0 {
 			p.From.Offset = 1
@@ -97,11 +99,11 @@ func Gbranch(as int, t *Type, likely int) *obj.Prog {
 	return p
 }
 
-func Prog(as int) *obj.Prog {
+func Prog(as obj.As) *obj.Prog {
 	var p *obj.Prog
 
-	if as == obj.ADATA || as == obj.AGLOBL {
-		if ddumped != 0 {
+	if as == obj.AGLOBL {
+		if ddumped {
 			Fatalf("already dumped data")
 		}
 		if dpc == nil {
@@ -119,13 +121,11 @@ func Prog(as int) *obj.Prog {
 		p.Link = Pc
 	}
 
-	if lineno == 0 {
-		if Debug['K'] != 0 {
-			Warn("prog: line 0")
-		}
+	if lineno == 0 && Debug['K'] != 0 {
+		Warn("prog: line 0")
 	}
 
-	p.As = int16(as)
+	p.As = as
 	p.Lineno = lineno
 	return p
 }
@@ -163,7 +163,17 @@ func Clearp(p *obj.Prog) {
 }
 
 func dumpdata() {
-	ddumped = 1
+	ddumped = true
+	if dfirst == nil {
+		return
+	}
+	newplist()
+	*Pc = *dfirst
+	Pc = dpc
+	Clearp(Pc)
+}
+
+func flushdata() {
 	if dfirst == nil {
 		return
 	}
@@ -171,6 +181,8 @@ func dumpdata() {
 	*Pc = *dfirst
 	Pc = dpc
 	Clearp(Pc)
+	dfirst = nil
+	dpc = nil
 }
 
 // Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
@@ -224,13 +236,17 @@ func ggloblnod(nam *Node) {
 }
 
 func ggloblsym(s *Sym, width int32, flags int16) {
+	ggloblLSym(Linksym(s), width, flags)
+}
+
+func ggloblLSym(s *obj.LSym, 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)
+	p.From.Sym = s
 	if flags&obj.LOCAL != 0 {
 		p.From.Sym.Local = true
-		flags &= ^obj.LOCAL
+		flags &^= obj.LOCAL
 	}
 	p.To.Type = obj.TYPE_CONST
 	p.To.Offset = int64(width)
@@ -260,7 +276,7 @@ func gused(n *Node) {
 func Isfat(t *Type) bool {
 	if t != nil {
 		switch t.Etype {
-		case TSTRUCT, TARRAY, TSTRING,
+		case TSTRUCT, TARRAY, TSLICE, TSTRING,
 			TINTER: // maybe remove later
 			return true
 		}
@@ -310,13 +326,13 @@ func Naddr(a *obj.Addr, n *Node) {
 		a := a // copy to let escape into Ctxt.Dconv
 		Debug['h'] = 1
 		Dump("naddr", n)
-		Fatalf("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(a))
+		Fatalf("naddr: bad %v %v", n.Op, 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.
+		if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
 			a.Width = 0
 		}
 
@@ -328,22 +344,10 @@ func Naddr(a *obj.Addr, n *Node) {
 		if a.Offset != int64(int32(a.Offset)) {
 			Yyerror("offset %d too large for OINDREG", a.Offset)
 		}
-		if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+		if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
 			a.Width = 0
 		}
 
-		// n->left is PHEAP ONAME for stack parameter.
-	// compute address of actual parameter on stack.
-	case OPARAM:
-		a.Etype = uint8(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 {
 			Fatalf("closurevar without needctxt")
@@ -371,14 +375,8 @@ func Naddr(a *obj.Addr, n *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)
-					}
-				}
-			}
+		if n.Name.Method && n.Type != nil && n.Type.Sym != nil && n.Type.Sym.Pkg != nil {
+			s = Pkglookup(s.Name, n.Type.Sym.Pkg)
 		}
 
 		a.Type = obj.TYPE_MEM
@@ -408,39 +406,39 @@ func Naddr(a *obj.Addr, n *Node) {
 		// A special case to make write barriers more efficient.
 		// Taking the address of the first field of a named struct
 		// is the same as taking the address of the struct.
-		if n.Left.Type.Etype != TSTRUCT || n.Left.Type.Type.Sym != n.Right.Sym {
+		if !n.Left.Type.IsStruct() || n.Left.Type.Field(0).Sym != n.Sym {
 			Debug['h'] = 1
 			Dump("naddr", n)
-			Fatalf("naddr: bad %v %v", Oconv(int(n.Op), 0), Ctxt.Dconv(a))
+			Fatalf("naddr: bad %v %v", n.Op, Ctxt.Dconv(a))
 		}
 		Naddr(a, n.Left)
 
 	case OLITERAL:
-		if Thearch.Thechar == '8' {
+		if Thearch.LinkArch.Family == sys.I386 {
 			a.Width = 0
 		}
-		switch n.Val().Ctype() {
+		switch u := n.Val().U.(type) {
 		default:
-			Fatalf("naddr: const %v", Tconv(n.Type, obj.FmtLong))
+			Fatalf("naddr: const %v", Tconv(n.Type, FmtLong))
 
-		case CTFLT:
+		case *Mpflt:
 			a.Type = obj.TYPE_FCONST
-			a.Val = mpgetflt(n.Val().U.(*Mpflt))
+			a.Val = u.Float64()
 
-		case CTINT, CTRUNE:
+		case *Mpint:
 			a.Sym = nil
 			a.Type = obj.TYPE_CONST
-			a.Offset = Mpgetfix(n.Val().U.(*Mpint))
+			a.Offset = u.Int64()
 
-		case CTSTR:
-			datagostring(n.Val().U.(string), a)
+		case string:
+			datagostring(u, a)
 
-		case CTBOOL:
+		case bool:
 			a.Sym = nil
 			a.Type = obj.TYPE_CONST
-			a.Offset = int64(obj.Bool2int(n.Val().U.(bool)))
+			a.Offset = int64(obj.Bool2int(u))
 
-		case CTNIL:
+		case *NilVal:
 			a.Sym = nil
 			a.Type = obj.TYPE_CONST
 			a.Offset = 0
@@ -449,12 +447,12 @@ func Naddr(a *obj.Addr, n *Node) {
 	case OADDR:
 		Naddr(a, n.Left)
 		a.Etype = uint8(Tptr)
-		if Thearch.Thechar != '0' && Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64.
+		if !Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { // TODO(rsc): Do this even for these architectures.
 			a.Width = int64(Widthptr)
 		}
 		if a.Type != obj.TYPE_MEM {
 			a := a // copy to let escape into Ctxt.Dconv
-			Fatalf("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(int(n.Left.Op), 0))
+			Fatalf("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), n.Left.Op)
 		}
 		a.Type = obj.TYPE_ADDR
 
@@ -488,7 +486,7 @@ func Naddr(a *obj.Addr, n *Node) {
 		}
 		a.Etype = uint8(Simtype[TUINT])
 		a.Offset += int64(Array_nel)
-		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+		if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
 			a.Width = int64(Widthint)
 		}
 
@@ -501,11 +499,10 @@ func Naddr(a *obj.Addr, n *Node) {
 		}
 		a.Etype = uint8(Simtype[TUINT])
 		a.Offset += int64(Array_cap)
-		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+		if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
 			a.Width = int64(Widthint)
 		}
 	}
-	return
 }
 
 func newplist() *obj.Plist {
@@ -518,75 +515,121 @@ func newplist() *obj.Plist {
 	return pl
 }
 
-func nodarg(t *Type, fp int) *Node {
+// nodarg returns a Node for the function argument denoted by t,
+// which is either the entire function argument or result struct (t is a  struct *Type)
+// or a specific argument (t is a *Field within a struct *Type).
+//
+// If fp is 0, the node is for use by a caller invoking the given
+// function, preparing the arguments before the call
+// or retrieving the results after the call.
+// In this case, the node will correspond to an outgoing argument
+// slot like 8(SP).
+//
+// If fp is 1, the node is for use by the function itself
+// (the callee), to retrieve its arguments or write its results.
+// In this case the node will be an ONAME with an appropriate
+// type and offset.
+func nodarg(t interface{}, fp int) *Node {
 	var n *Node
 
-	// entire argument struct, not just one arg
-	if t.Etype == TSTRUCT && t.Funarg {
+	var funarg Funarg
+	switch t := t.(type) {
+	default:
+		Fatalf("bad nodarg %T(%v)", t, t)
+
+	case *Type:
+		// Entire argument struct, not just one arg
+		if !t.IsFuncArgStruct() {
+			Fatalf("nodarg: bad type %v", t)
+		}
+		funarg = t.StructType().Funarg
+
+		// Build fake variable name for whole arg struct.
 		n = Nod(ONAME, nil, nil)
 		n.Sym = Lookup(".args")
 		n.Type = t
-		var savet Iter
-		first := Structfirst(&savet, &t)
+		first := t.Field(0)
 		if first == nil {
 			Fatalf("nodarg: bad struct")
 		}
-		if first.Width == BADWIDTH {
+		if first.Offset == BADWIDTH {
 			Fatalf("nodarg: offset not computed for %v", t)
 		}
-		n.Xoffset = first.Width
+		n.Xoffset = first.Offset
 		n.Addable = true
-		goto fp
-	}
 
-	if t.Etype != TFIELD {
-		Fatalf("nodarg: not field %v", t)
-	}
+	case *Field:
+		funarg = t.Funarg
+		if fp == 1 {
+			// NOTE(rsc): This should be using t.Nname directly,
+			// except in the case where t.Nname.Sym is the blank symbol and
+			// so the assignment would be discarded during code generation.
+			// In that case we need to make a new node, and there is no harm
+			// in optimization passes to doing so. But otherwise we should
+			// definitely be using the actual declaration and not a newly built node.
+			// The extra Fatalf checks here are verifying that this is the case,
+			// without changing the actual logic (at time of writing, it's getting
+			// toward time for the Go 1.7 beta).
+			// At some quieter time (assuming we've never seen these Fatalfs happen)
+			// we could change this code to use "expect" directly.
+			expect := t.Nname
+			if expect.isParamHeapCopy() {
+				expect = expect.Name.Param.Stackcopy
+			}
 
-	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
+			for _, n := range Curfn.Func.Dcl {
+				if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
+					if n != expect {
+						Fatalf("nodarg: unexpected node: %v (%p %v) vs %v (%p %v)", n, n, n.Op, t.Nname, t.Nname, t.Nname.Op)
+					}
+					return n
+				}
 			}
-		}
-	}
 
-	n = Nod(ONAME, nil, nil)
-	n.Type = t.Type
-	n.Sym = t.Sym
+			if !isblanksym(expect.Sym) {
+				Fatalf("nodarg: did not find node in dcl list: %v", expect)
+			}
+		}
 
-	if t.Width == BADWIDTH {
-		Fatalf("nodarg: offset not computed for %v", t)
+		// Build fake name for individual variable.
+		// This is safe because if there was a real declared name
+		// we'd have used it above.
+		n = Nod(ONAME, nil, nil)
+		n.Type = t.Type
+		n.Sym = t.Sym
+		if t.Offset == BADWIDTH {
+			Fatalf("nodarg: offset not computed for %v", t)
+		}
+		n.Xoffset = t.Offset
+		n.Addable = true
+		n.Orig = t.Nname
 	}
-	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
+	default:
+		Fatalf("bad fp")
 
+	case 0: // preparing arguments for call
+		n.Op = OINDREG
 		n.Reg = int16(Thearch.REGSP)
 		n.Xoffset += Ctxt.FixedFrameSize()
 
-	case 1: // input arg
+	case 1: // reading arguments inside call
 		n.Class = PPARAM
-
-	case 2: // offset output arg
-		Fatalf("shouldn't be used")
+		if funarg == FunargResults {
+			n.Class = PPARAMOUT
+		}
 	}
 
 	n.Typecheck = 1
+	n.Addrtaken = true // keep optimizers at bay
 	return n
 }
 
@@ -679,7 +722,7 @@ func Regalloc(n *Node, t *Type, o *Node) {
 		Fatalf("regalloc: t nil")
 	}
 	et := Simtype[t.Etype]
-	if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) {
+	if Ctxt.Arch.RegSize == 4 && (et == TINT64 || et == TUINT64) {
 		Fatalf("regalloc 64bit")
 	}
 
diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go
index 6071ab4..67a050a 100644
--- a/src/cmd/compile/internal/gc/init.go
+++ b/src/cmd/compile/internal/gc/init.go
@@ -27,39 +27,38 @@ var renameinit_initgen int
 
 func renameinit() *Sym {
 	renameinit_initgen++
-	return Lookupf("init.%d", renameinit_initgen)
+	return LookupN("init.", 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 {
+//      var initdone· uint8                             (1)
+//      func init() {                                   (2)
+//              if initdone· > 1 {                      (3)
+//                      return                          (3a)
+//              }
+//              if initdone· == 1 {                     (4)
+//                      throw()                         (4a)
+//              }
+//              initdone· = 1                           (5)
+//              // over all matching imported symbols
+//                      <pkg>.init()                    (6)
+//              { <init stmts> }                        (7)
+//              init.<n>() // if any                    (8)
+//              initdone· = 2                           (9)
+//              return                                  (10)
+//      }
+func anyinit(n []*Node) bool {
 	// are there any interesting init statements
-	for l := n; l != nil; l = l.Next {
-		switch l.N.Op {
+	for _, ln := range n {
+		switch ln.Op {
 		case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
 			break
 
 		case OAS, OASWB:
-			if isblank(l.N.Left) && candiscard(l.N.Right) {
+			if isblank(ln.Left) && candiscard(ln.Right) {
 				break
 			}
 			fallthrough
-
-			// fall through
 		default:
 			return true
 		}
@@ -88,18 +87,18 @@ func anyinit(n *NodeList) bool {
 	return false
 }
 
-func fninit(n *NodeList) {
+func fninit(n []*Node) {
 	if Debug['A'] != 0 {
 		// sys.go or unsafe.go during compiler build
 		return
 	}
 
-	n = initfix(n)
-	if !anyinit(n) {
+	nf := initfix(n)
+	if !anyinit(nf) {
 		return
 	}
 
-	var r *NodeList
+	var r []*Node
 
 	// (1)
 	gatevar := newname(Lookup("initdone·"))
@@ -118,68 +117,67 @@ func fninit(n *NodeList) {
 
 	// (3)
 	a := Nod(OIF, nil, nil)
-
-	a.Left = Nod(ONE, gatevar, Nodintconst(0))
-	r = list(r, a)
+	a.Left = Nod(OGT, gatevar, Nodintconst(1))
+	a.Likely = 1
+	r = append(r, a)
+	// (3a)
+	a.Nbody.Set1(Nod(ORETURN, nil, nil))
 
 	// (4)
 	b := Nod(OIF, nil, nil)
-
-	b.Left = Nod(OEQ, gatevar, Nodintconst(2))
-	b.Nbody = list1(Nod(ORETURN, nil, nil))
-	a.Nbody = list1(b)
+	b.Left = Nod(OEQ, gatevar, Nodintconst(1))
+	// this actually isn't likely, but code layout is better
+	// like this: no JMP needed after the call.
+	b.Likely = 1
+	r = append(r, b)
+	// (4a)
+	b.Nbody.Set1(Nod(OCALL, syslook("throwinit"), nil))
 
 	// (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)
+	r = append(r, a)
 
-	// (7)
+	// (6)
 	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)
+			r = append(r, a)
 		}
 	}
 
-	// (8)
-	r = concat(r, n)
+	// (7)
+	r = append(r, nf...)
 
-	// (9)
+	// (8)
 	// could check that it is fn of no args/returns
 	for i := 1; ; i++ {
-		s := Lookupf("init.%d", i)
+		s := LookupN("init.", i)
 		if s.Def == nil {
 			break
 		}
 		a = Nod(OCALL, s.Def, nil)
-		r = list(r, a)
+		r = append(r, a)
 	}
 
-	// (10)
+	// (9)
 	a = Nod(OAS, gatevar, Nodintconst(2))
 
-	r = list(r, a)
+	r = append(r, a)
 
-	// (11)
+	// (10)
 	a = Nod(ORETURN, nil, nil)
 
-	r = list(r, a)
+	r = append(r, a)
 	exportsym(fn.Func.Nname)
 
-	fn.Nbody = r
+	fn.Nbody.Set(r)
 	funcbody(fn)
 
 	Curfn = fn
-	typecheck(&fn, Etop)
-	typechecklist(r, Etop)
+	fn = typecheck(fn, Etop)
+	typecheckslice(r, Etop)
 	Curfn = nil
 	funccompile(fn)
 }
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index 64afd67..0c1b050 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -7,7 +7,7 @@
 // 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,
+// The debug['l'] flag controls the aggressiveness. 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
@@ -27,34 +27,20 @@
 
 package gc
 
-import (
-	"cmd/internal/obj"
-	"fmt"
-)
+import "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
+// 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 {
+	if fn.Type.Recv() != nil {
 		// method
-		rcvr := getthisx(fn.Type).Type.Type
+		rcvr := fn.Type.Recv().Type
 
-		if Isptr[rcvr.Etype] {
-			rcvr = rcvr.Type
+		if rcvr.IsPtr() {
+			rcvr = rcvr.Elem()
 		}
 		if rcvr.Sym == nil {
-			Fatalf("receiver with no sym: [%v] %v  (%v)", fn.Sym, Nconv(fn, obj.FmtLong), rcvr)
+			Fatalf("receiver with no sym: [%v] %v  (%v)", fn.Sym, Nconv(fn, FmtLong), rcvr)
 		}
 		return rcvr.Sym.Pkg
 	}
@@ -63,10 +49,10 @@ func fnpkg(fn *Node) *Pkg {
 	return fn.Sym.Pkg
 }
 
-// Lazy typechecking of imported bodies.  For local functions, caninl will set ->typecheck
+// 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))
+	lno := setlineno(fn)
 
 	// typecheckinl is only for imported functions;
 	// their bodies may refer to unsafe as long as the package
@@ -78,21 +64,21 @@ func typecheckinl(fn *Node) {
 		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))
+	if Debug['m'] > 2 || Debug_export != 0 {
+		fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, FmtLong), hconv(fn.Func.Inl, FmtSharp))
 	}
 
 	save_safemode := safemode
-	safemode = 0
+	safemode = false
 
 	savefn := Curfn
 	Curfn = fn
-	typechecklist(fn.Func.Inl, Etop)
+	typecheckslice(fn.Func.Inl.Slice(), Etop)
 	Curfn = savefn
 
 	safemode = save_safemode
 
-	lineno = int32(lno)
+	lineno = lno
 }
 
 // Caninl determines whether fn is inlineable.
@@ -103,16 +89,16 @@ func caninl(fn *Node) {
 		Fatalf("caninl %v", fn)
 	}
 	if fn.Func.Nname == nil {
-		Fatalf("caninl no nname %v", Nconv(fn, obj.FmtSign))
+		Fatalf("caninl no nname %v", Nconv(fn, FmtSign))
 	}
 
 	// If marked "go:noinline", don't inline
-	if fn.Func.Noinline {
+	if fn.Func.Pragma&Noinline != 0 {
 		return
 	}
 
 	// If fn has no body (is defined outside of Go), cannot inline it.
-	if fn.Nbody == nil {
+	if fn.Nbody.Len() == 0 {
 		return
 	}
 
@@ -122,8 +108,9 @@ func caninl(fn *Node) {
 
 	// 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 {
+		f := fn.Type.Params().Fields()
+		if len := f.Len(); len > 0 {
+			if t := f.Index(len - 1); t.Isddd {
 				return
 			}
 		}
@@ -140,7 +127,7 @@ func caninl(fn *Node) {
 	}
 
 	const maxBudget = 80
-	budget := maxBudget // allowed hairyness
+	budget := int32(maxBudget) // allowed hairyness
 	if ishairylist(fn.Nbody, &budget) || budget < 0 {
 		return
 	}
@@ -148,35 +135,38 @@ func caninl(fn *Node) {
 	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)
+	n := fn.Func.Nname
+
+	n.Func.Inl.Set(fn.Nbody.Slice())
+	fn.Nbody.Set(inlcopylist(n.Func.Inl.Slice()))
+	inldcl := inlcopylist(n.Name.Defn.Func.Dcl)
+	n.Func.Inldcl.Set(inldcl)
+	n.Func.InlCost = 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
+	fn.Type.SetNname(n)
 
 	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))
+		fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(n, FmtSharp), Tconv(fn.Type, FmtSharp), hconv(n.Func.Inl, FmtSharp))
 	} else if Debug['m'] != 0 {
-		fmt.Printf("%v: can inline %v\n", fn.Line(), fn.Func.Nname)
+		fmt.Printf("%v: can inline %v\n", fn.Line(), n)
 	}
 
 	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) {
+func ishairylist(ll Nodes, budget *int32) bool {
+	for _, n := range ll.Slice() {
+		if ishairy(n, budget) {
 			return true
 		}
 	}
 	return false
 }
 
-func ishairy(n *Node, budget *int) bool {
+func ishairy(n *Node, budget *int32) bool {
 	if n == nil {
 		return false
 	}
@@ -184,13 +174,14 @@ func ishairy(n *Node, budget *int) bool {
 	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)
+		if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 {
+			*budget -= fn.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)
+			if d := n.Left.Sym.Def; d != nil && d.Func.Inl.Len() != 0 {
+				*budget -= d.Func.InlCost
 				break
 			}
 		}
@@ -200,14 +191,15 @@ func ishairy(n *Node, budget *int) bool {
 
 	// Call is okay if inlinable and we have the budget for the body.
 	case OCALLMETH:
-		if n.Left.Type == nil {
-			Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, obj.FmtSign))
+		t := n.Left.Type
+		if t == nil {
+			Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, FmtSign))
 		}
-		if n.Left.Type.Nname == nil {
-			Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign))
+		if t.Nname() == nil {
+			Fatalf("no function definition for [%p] %v\n", t, Tconv(t, FmtSign))
 		}
-		if n.Left.Type.Nname.Func.Inl != nil {
-			*budget -= int(n.Left.Type.Nname.Func.InlCost)
+		if inlfn := t.Nname().Func; inlfn.Inl.Len() != 0 {
+			*budget -= inlfn.InlCost
 			break
 		}
 		if Debug['l'] < 4 {
@@ -225,11 +217,11 @@ func ishairy(n *Node, budget *int) bool {
 		ORANGE,
 		OFOR,
 		OSELECT,
-		OSWITCH,
+		OTYPESW,
 		OPROC,
 		ODEFER,
-		ODCLTYPE,  // can't print yet
-		ODCLCONST, // can't print yet
+		ODCLTYPE, // can't print yet
+		OBREAK,
 		ORETJMP:
 		return true
 	}
@@ -242,12 +234,12 @@ func ishairy(n *Node, budget *int) bool {
 // 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))
+func inlcopylist(ll []*Node) []*Node {
+	s := make([]*Node, 0, len(ll))
+	for _, n := range ll {
+		s = append(s, inlcopy(n))
 	}
-	return l
+	return s
 }
 
 func inlcopy(n *Node) *Node {
@@ -260,27 +252,26 @@ func inlcopy(n *Node) *Node {
 		return n
 	}
 
-	m := Nod(OXXX, nil, nil)
-	*m = *n
+	m := *n
 	if m.Func != nil {
-		m.Func.Inl = nil
+		m.Func.Inl.Set(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)
+	m.List.Set(inlcopylist(n.List.Slice()))
+	m.Rlist.Set(inlcopylist(n.Rlist.Slice()))
+	m.Ninit.Set(inlcopylist(n.Ninit.Slice()))
+	m.Nbody.Set(inlcopylist(n.Nbody.Slice()))
 
-	return m
+	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.
+// calls made to inlineable functions. This is the external entry point.
 func inlcalls(fn *Node) {
 	savefn := Curfn
 	Curfn = fn
-	inlnode(&fn)
+	fn = inlnode(fn)
 	if fn != Curfn {
 		Fatalf("inlnode replaced curfn")
 	}
@@ -292,18 +283,18 @@ func inlconv2stmt(n *Node) {
 	n.Op = OBLOCK
 
 	// n->ninit stays
-	n.List = n.Nbody
+	n.List.Set(n.Nbody.Slice())
 
-	n.Nbody = nil
-	n.Rlist = nil
+	n.Nbody.Set(nil)
+	n.Rlist.Set(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
+// The result of inlconv2expr MUST be assigned back to n, e.g.
+// 	n.Left = inlconv2expr(n.Left)
+func inlconv2expr(n *Node) *Node {
+	r := n.Rlist.First()
+	return addinit(r, append(n.Ninit.Slice(), n.Nbody.Slice()...))
 }
 
 // Turn the rlist (with the return values) of the OINLCALL in
@@ -311,24 +302,25 @@ func inlconv2expr(np **Node) {
 // 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 {
-		Fatalf("inlconv2list %v\n", Nconv(n, obj.FmtSign))
+func inlconv2list(n *Node) []*Node {
+	if n.Op != OINLCALL || n.Rlist.Len() == 0 {
+		Fatalf("inlconv2list %v\n", Nconv(n, FmtSign))
 	}
 
-	l := n.Rlist
-	addinit(&l.N, concat(n.Ninit, n.Nbody))
-	return l
+	s := n.Rlist.Slice()
+	s[0] = addinit(s[0], append(n.Ninit.Slice(), n.Nbody.Slice()...))
+	return s
 }
 
-func inlnodelist(l *NodeList) {
-	for ; l != nil; l = l.Next {
-		inlnode(&l.N)
+func inlnodelist(l Nodes) {
+	s := l.Slice()
+	for i := range s {
+		s[i] = inlnode(s[i])
 	}
 }
 
 // inlnode recurses over the tree to find inlineable calls, which will
-// be turned into OINLCALLs by mkinlcall.  When the recursion comes
+// 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
@@ -338,13 +330,13 @@ func inlnodelist(l *NodeList) {
 // 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
+// The result of inlnode MUST be assigned back to n, e.g.
+// 	n.Left = inlnode(n.Left)
+func inlnode(n *Node) *Node {
+	if n == nil {
+		return n
 	}
 
-	n := *np
-
 	switch n.Op {
 	// inhibit inlining of their argument
 	case ODEFER, OPROC:
@@ -358,38 +350,38 @@ func inlnode(np **Node) {
 		// TODO do them here (or earlier),
 	// so escape analysis can avoid more heapmoves.
 	case OCLOSURE:
-		return
+		return n
 	}
 
-	lno := int(setlineno(n))
+	lno := setlineno(n)
 
 	inlnodelist(n.Ninit)
-	for l := n.Ninit; l != nil; l = l.Next {
-		if l.N.Op == OINLCALL {
-			inlconv2stmt(l.N)
+	for _, n1 := range n.Ninit.Slice() {
+		if n1.Op == OINLCALL {
+			inlconv2stmt(n1)
 		}
 	}
 
-	inlnode(&n.Left)
+	n.Left = inlnode(n.Left)
 	if n.Left != nil && n.Left.Op == OINLCALL {
-		inlconv2expr(&n.Left)
+		n.Left = inlconv2expr(n.Left)
 	}
 
-	inlnode(&n.Right)
+	n.Right = inlnode(n.Right)
 	if n.Right != nil && n.Right.Op == OINLCALL {
 		if n.Op == OFOR {
 			inlconv2stmt(n.Right)
 		} else {
-			inlconv2expr(&n.Right)
+			n.Right = 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)
+		for _, n2 := range n.List.Slice() {
+			if n2.Op == OINLCALL {
+				inlconv2stmt(n2)
 			}
 		}
 
@@ -401,16 +393,17 @@ func inlnode(np **Node) {
 		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)
+		if n.List.Len() == 1 && n.List.First().Op == OINLCALL && n.List.First().Rlist.Len() > 1 {
+			n.List.Set(inlconv2list(n.List.First()))
 			break
 		}
 		fallthrough
 
 	default:
-		for l := n.List; l != nil; l = l.Next {
-			if l.N.Op == OINLCALL {
-				inlconv2expr(&l.N)
+		s := n.List.Slice()
+		for i1, n1 := range s {
+			if n1.Op == OINLCALL {
+				s[i1] = inlconv2expr(s[i1])
 			}
 		}
 	}
@@ -418,31 +411,32 @@ func inlnode(np **Node) {
 	inlnodelist(n.Rlist)
 	switch n.Op {
 	case OAS2FUNC:
-		if n.Rlist.N.Op == OINLCALL {
-			n.Rlist = inlconv2list(n.Rlist.N)
+		if n.Rlist.First().Op == OINLCALL {
+			n.Rlist.Set(inlconv2list(n.Rlist.First()))
 			n.Op = OAS2
 			n.Typecheck = 0
-			typecheck(np, Etop)
+			n = typecheck(n, Etop)
 			break
 		}
 		fallthrough
 
 	default:
-		for l := n.Rlist; l != nil; l = l.Next {
-			if l.N.Op == OINLCALL {
+		s := n.Rlist.Slice()
+		for i1, n1 := range s {
+			if n1.Op == OINLCALL {
 				if n.Op == OIF {
-					inlconv2stmt(l.N)
+					inlconv2stmt(n1)
 				} else {
-					inlconv2expr(&l.N)
+					s[i1] = inlconv2expr(s[i1])
 				}
 			}
 		}
 	}
 
 	inlnodelist(n.Nbody)
-	for l := n.Nbody; l != nil; l = l.Next {
-		if l.N.Op == OINLCALL {
-			inlconv2stmt(l.N)
+	for _, n := range n.Nbody.Slice() {
+		if n.Op == OINLCALL {
+			inlconv2stmt(n)
 		}
 	}
 
@@ -453,44 +447,47 @@ func inlnode(np **Node) {
 	case OCALLFUNC, OCALLMETH:
 		// TODO(marvin): Fix Node.EType type union.
 		if n.Etype == EType(OPROC) || n.Etype == EType(ODEFER) {
-			return
+			return n
 		}
 	}
 
 	switch n.Op {
 	case OCALLFUNC:
 		if Debug['m'] > 3 {
-			fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, obj.FmtSign))
+			fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, FmtSign))
 		}
-		if n.Left.Func != nil && n.Left.Func.Inl != nil { // normal case
-			mkinlcall(np, n.Left, n.Isddd)
+		if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall1(n) { // normal case
+			n = mkinlcall(n, 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)
+				n = mkinlcall(n, 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))
+			fmt.Printf("%v:call to meth %v\n", n.Line(), Nconv(n.Left.Right, FmtLong))
 		}
 
 		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
 		if n.Left.Type == nil {
-			Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, obj.FmtSign))
+			Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, FmtSign))
 		}
 
-		if n.Left.Type.Nname == nil {
-			Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign))
+		if n.Left.Type.Nname() == nil {
+			Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, FmtSign))
 		}
 
-		mkinlcall(np, n.Left.Type.Nname, n.Isddd)
+		n = mkinlcall(n, n.Left.Type.Nname(), n.Isddd)
 	}
 
-	lineno = int32(lno)
+	lineno = lno
+	return n
 }
 
-func mkinlcall(np **Node, fn *Node, isddd bool) {
+// The result of mkinlcall MUST be assigned back to n, e.g.
+// 	n.Left = mkinlcall(n.Left, fn, isddd)
+func mkinlcall(n *Node, fn *Node, isddd bool) *Node {
 	save_safemode := safemode
 
 	// imported functions may refer to unsafe as long as the
@@ -498,13 +495,14 @@ func mkinlcall(np **Node, fn *Node, isddd bool) {
 	pkg := fnpkg(fn)
 
 	if pkg != localpkg && pkg != nil {
-		safemode = 0
+		safemode = false
 	}
-	mkinlcall1(np, fn, isddd)
+	n = mkinlcall1(n, fn, isddd)
 	safemode = save_safemode
+	return n
 }
 
-func tinlvar(t *Type) *Node {
+func tinlvar(t *Field) *Node {
 	if t.Nname != nil && !isblank(t.Nname) {
 		if t.Nname.Name.Inlvar == nil {
 			Fatalf("missing inlvar for %v\n", t.Nname)
@@ -512,8 +510,7 @@ func tinlvar(t *Type) *Node {
 		return t.Nname.Name.Inlvar
 	}
 
-	typecheck(&nblank, Erv|Easgn)
-	return nblank
+	return typecheck(nblank, Erv|Easgn)
 }
 
 var inlgen int
@@ -522,73 +519,71 @@ var inlgen int
 // 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) {
+// The result of mkinlcall1 MUST be assigned back to n, e.g.
+// 	n.Left = mkinlcall1(n.Left, fn, isddd)
+func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
 	// For variadic fn.
-	if fn.Func.Inl == nil {
-		return
+	if fn.Func.Inl.Len() == 0 {
+		return n
 	}
 
 	if fn == Curfn || fn.Name.Defn == Curfn {
-		return
+		return n
 	}
 
 	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))
+		fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), fn.Sym, Tconv(fn.Type, FmtSharp), hconv(fn.Func.Inl, 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))
+		fmt.Printf("%v: Before inlining: %v\n", n.Line(), Nconv(n, 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
+	var dcl []*Node
+	if fn.Name.Defn != nil {
+		// local function
+		dcl = fn.Func.Inldcl.Slice()
 	} else {
+		// imported function
 		dcl = fn.Func.Dcl
 	}
 
-	inlretvars = nil
+	var retvars []*Node
 	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.
+	for _, ln := range dcl {
+		if ln.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
+		if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
+			continue
+		}
+		if ln.Op == ONAME {
+			ln.Name.Inlvar = typecheck(inlvar(ln), Erv)
+			if ln.Class == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class == PPARAM {
+				ninit.Append(Nod(ODCL, ln.Name.Inlvar, nil))
 			}
 		}
 	}
 
 	// temporaries for return values.
 	var m *Node
-	for t := getoutargx(fn.Type).Type; t != nil; t = t.Down {
+	for _, t := range fn.Type.Results().Fields().Slice() {
 		if t != nil && t.Nname != nil && !isblank(t.Nname) {
 			m = inlvar(t.Nname)
-			typecheck(&m, Erv)
+			m = typecheck(m, Erv)
 			t.Nname.Name.Inlvar = m
 		} else {
 			// anonymous return values, synthesize names for use in assignment that replaces return
@@ -596,29 +591,28 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 			i++
 		}
 
-		ninit = list(ninit, Nod(ODCL, m, nil))
-		inlretvars = list(inlretvars, m)
+		ninit.Append(Nod(ODCL, m, nil))
+		retvars = append(retvars, m)
 	}
 
 	// assign receiver.
-	var as *Node
-	if fn.Type.Thistuple != 0 && n.Left.Op == ODOTMETH {
+	if fn.Type.Recv() != nil && n.Left.Op == ODOTMETH {
 		// method call with a receiver.
-		t := getthisx(fn.Type).Type
+		t := fn.Type.Recv()
 
 		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
 			Fatalf("missing inlvar for %v\n", t.Nname)
 		}
 		if n.Left.Left == nil {
-			Fatalf("method call without receiver: %v", Nconv(n, obj.FmtSign))
+			Fatalf("method call without receiver: %v", Nconv(n, FmtSign))
 		}
 		if t == nil {
-			Fatalf("method call unknown receiver type: %v", Nconv(n, obj.FmtSign))
+			Fatalf("method call unknown receiver type: %v", Nconv(n, FmtSign))
 		}
-		as = Nod(OAS, tinlvar(t), n.Left.Left)
+		as := Nod(OAS, tinlvar(t), n.Left.Left)
 		if as != nil {
-			typecheck(&as, Etop)
-			ninit = list(ninit, as)
+			as = typecheck(as, Etop)
+			ninit.Append(as)
 		}
 	}
 
@@ -627,7 +621,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 
 	var varargtype *Type
 	varargcount := 0
-	for t := fn.Type.Type.Down.Down.Type; t != nil; t = t.Down {
+	for _, t := range fn.Type.Params().Fields().Slice() {
 		if t.Isddd {
 			variadic = true
 			varargtype = t.Type
@@ -642,110 +636,110 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 	// 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 {
+	if n.List.Len() == 1 {
+		switch n.List.First().Op {
 		case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH:
-			if n.List.N.Left.Type.Outtuple > 1 {
-				multiret = n.List.N.Left.Type.Outtuple - 1
+			if n.List.First().Left.Type.Results().NumFields() > 1 {
+				multiret = n.List.First().Left.Type.Results().NumFields() - 1
 			}
 		}
 	}
 
 	if variadic {
-		varargcount = count(n.List) + multiret
+		varargcount = n.List.Len() + multiret
 		if n.Left.Op != ODOTMETH {
-			varargcount -= fn.Type.Thistuple
+			varargcount -= fn.Type.Recvs().NumFields()
 		}
-		varargcount -= fn.Type.Intuple - 1
+		varargcount -= fn.Type.Params().NumFields() - 1
 	}
 
 	// assign arguments to the parameters' temp names
-	as = Nod(OAS2, nil, nil)
+	as := Nod(OAS2, nil, nil)
 
-	as.Rlist = n.List
-	ll := n.List
+	as.Rlist.Set(n.List.Slice())
+	li := 0
 
 	// 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 {
+	if fn.Type.Recv() != nil && n.Left.Op != ODOTMETH {
 		// non-method call to method
-		if n.List == nil {
-			Fatalf("non-method call to method without first arg: %v", Nconv(n, obj.FmtSign))
+		if n.List.Len() == 0 {
+			Fatalf("non-method call to method without first arg: %v", Nconv(n, FmtSign))
 		}
 
 		// append receiver inlvar to LHS.
-		t := getthisx(fn.Type).Type
+		t := fn.Type.Recv()
 
 		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
 			Fatalf("missing inlvar for %v\n", t.Nname)
 		}
 		if t == nil {
-			Fatalf("method call unknown receiver type: %v", Nconv(n, obj.FmtSign))
+			Fatalf("method call unknown receiver type: %v", Nconv(n, FmtSign))
 		}
-		as.List = list(as.List, tinlvar(t))
-		ll = ll.Next // track argument count.
+		as.List.Append(tinlvar(t))
+		li++
 	}
 
 	// append ordinary arguments to LHS.
-	chkargcount := n.List != nil && n.List.Next != nil
+	chkargcount := n.List.Len() > 1
 
-	var vararg *Node      // the slice argument to a variadic call
-	var varargs *NodeList // the list of LHS names to put in vararg.
+	var vararg *Node    // the slice argument to a variadic call
+	var varargs []*Node // 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 {
+		for _, t := range fn.Type.Params().Fields().Slice() {
 			if variadic && t.Isddd {
 				vararg = tinlvar(t)
-				for i = 0; i < varargcount && ll != nil; i++ {
+				for i = 0; i < varargcount && li < n.List.Len(); i++ {
 					m = argvar(varargtype, i)
-					varargs = list(varargs, m)
-					as.List = list(as.List, m)
+					varargs = append(varargs, m)
+					as.List.Append(m)
 				}
 
 				break
 			}
 
-			as.List = list(as.List, tinlvar(t))
+			as.List.Append(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 {
+		t, it := IterFields(fn.Type.Params())
+		for t != nil {
+			if li >= n.List.Len() {
 				break
 			}
 			if variadic && t.Isddd {
 				break
 			}
-			as.List = list(as.List, tinlvar(t))
-			t = t.Down
-			ll = ll.Next
+			as.List.Append(tinlvar(t))
+			t = it.Next()
+			li++
 		}
 
 		// 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++ {
+			for i = 0; i < varargcount && li < n.List.Len(); i++ {
 				m = argvar(varargtype, i)
-				varargs = list(varargs, m)
-				as.List = list(as.List, m)
-				ll = ll.Next
+				varargs = append(varargs, m)
+				as.List.Append(m)
+				li++
 			}
 
 			if i == varargcount {
-				t = t.Down
+				t = it.Next()
 			}
 		}
 
-		if ll != nil || t != nil {
-			Fatalf("arg count mismatch: %v  vs %v\n", Tconv(getinargx(fn.Type), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
+		if li < n.List.Len() || t != nil {
+			Fatalf("arg count mismatch: %v  vs %v\n", Tconv(fn.Type.Params(), FmtSharp), hconv(n.List, FmtComma))
 		}
 	}
 
-	if as.Rlist != nil {
-		typecheck(&as, Etop)
-		ninit = list(ninit, as)
+	if as.Rlist.Len() != 0 {
+		as = typecheck(as, Etop)
+		ninit.Append(as)
 	}
 
 	// turn the variadic args into a slice.
@@ -755,59 +749,60 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 			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))
+			vararrtype := typArray(varargtype.Elem(), int64(varargcount))
+			as.Right = Nod(OCOMPLIT, nil, typenod(vararrtype))
+			as.Right.List.Set(varargs)
+			as.Right = Nod(OSLICE, as.Right, nil)
 		}
 
-		typecheck(&as, Etop)
-		ninit = list(ninit, as)
+		as = typecheck(as, Etop)
+		ninit.Append(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)
+	for _, n := range retvars {
+		as = Nod(OAS, n, nil)
+		as = typecheck(as, Etop)
+		ninit.Append(as)
 	}
 
-	inlretlabel = newlabel_inl()
+	retlabel := 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))
+	subst := inlsubst{
+		retlabel: retlabel,
+		retvars:  retvars,
+	}
+
+	body := subst.list(fn.Func.Inl)
+
+	body = append(body, Nod(OGOTO, retlabel, nil)) // avoid 'not used' when function doesn't have return
+	body = append(body, Nod(OLABEL, retlabel, nil))
 
-	typechecklist(body, Etop)
+	typecheckslice(body, Etop)
 
 	//dumplist("ninit post", ninit);
 
 	call := Nod(OINLCALL, nil, nil)
 
-	call.Ninit = ninit
-	call.Nbody = body
-	call.Rlist = inlretvars
+	call.Ninit.Set(ninit.Slice())
+	call.Nbody.Set(body)
+	call.Rlist.Set(retvars)
 	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
+	as.Rlist.Set(nil)
 
-	setlno(call, int(n.Lineno))
+	setlno(call, n.Lineno)
 
-	as.Rlist = args
+	as.Rlist.Set(args.Slice())
 
 	//dumplist("call body", body);
 
-	*np = call
-
-	inlfn = saveinlfn
+	n = call
 
 	// transitive inlining
 	// might be nice to do this before exporting the body,
@@ -815,19 +810,21 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 	// 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)
+	body = fn.Func.Inl.Slice()
+	fn.Func.Inl.Set(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)
+	for _, n := range call.Nbody.Slice() {
+		if n.Op == OINLCALL {
+			inlconv2stmt(n)
 		}
 	}
-	fn.Func.Inl = body
+	fn.Func.Inl.Set(body)
 
 	if Debug['m'] > 2 {
-		fmt.Printf("%v: After inlining %v\n\n", n.Line(), Nconv(*np, obj.FmtSign))
+		fmt.Printf("%v: After inlining %v\n\n", n.Line(), Nconv(n, FmtSign))
 	}
+
+	return n
 }
 
 // Every time we expand a function we generate a new set of tmpnames,
@@ -835,7 +832,7 @@ func mkinlcall1(np **Node, fn *Node, isddd bool) {
 // 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))
+		fmt.Printf("inlvar %v\n", Nconv(var_, FmtSign))
 	}
 
 	n := newname(var_.Sym)
@@ -847,35 +844,35 @@ func inlvar(var_ *Node) *Node {
 
 	// 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.
+	// unchanged. See bugs 11053 and 9537.
 	if var_.Esc == EscHeap {
 		addrescapes(n)
 	}
 
-	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+	Curfn.Func.Dcl = append(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))
+func retvar(t *Field, i int) *Node {
+	n := newname(LookupN("~r", 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)
+	Curfn.Func.Dcl = append(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 := newname(LookupN("~arg", i))
+	n.Type = t.Elem()
 	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)
+	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
 	return n
 }
 
@@ -883,24 +880,35 @@ var newlabel_inl_label int
 
 func newlabel_inl() *Node {
 	newlabel_inl_label++
-	n := newname(Lookupf(".inlret%.6d", newlabel_inl_label))
+	n := newname(LookupN(".inlret", 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))
+// The inlsubst type implements the actual inlining of a single
+// function call.
+type inlsubst struct {
+	// Target of the goto substituted in place of a return.
+	retlabel *Node
+
+	// Temporary result variables.
+	retvars []*Node
+}
+
+// list inlines a list of nodes.
+func (subst *inlsubst) list(ll Nodes) []*Node {
+	s := make([]*Node, 0, ll.Len())
+	for _, n := range ll.Slice() {
+		s = append(s, subst.node(n))
 	}
-	return l
+	return s
 }
 
-func inlsubst(n *Node) *Node {
+// node recursively copies a node from the saved pristine body of the
+// inlined function, substituting references to input/output
+// parameters with ones to the tmpnames, and substituting returns with
+// assignments to the output.
+func (subst *inlsubst) node(n *Node) *Node {
 	if n == nil {
 		return nil
 	}
@@ -909,13 +917,13 @@ func inlsubst(n *Node) *Node {
 	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))
+				fmt.Printf("substituting name %v  ->  %v\n", Nconv(n, FmtSign), Nconv(n.Name.Inlvar, FmtSign))
 			}
 			return n.Name.Inlvar
 		}
 
 		if Debug['m'] > 2 {
-			fmt.Printf("not substituting name %v\n", Nconv(n, obj.FmtSign))
+			fmt.Printf("not substituting name %v\n", Nconv(n, FmtSign))
 		}
 		return n
 
@@ -926,24 +934,26 @@ func inlsubst(n *Node) *Node {
 
 	//		dump("Return before substitution", n);
 	case ORETURN:
-		m := Nod(OGOTO, inlretlabel, nil)
+		m := Nod(OGOTO, subst.retlabel, nil)
 
-		m.Ninit = inlsubstlist(n.Ninit)
+		m.Ninit.Set(subst.list(n.Ninit))
 
-		if inlretvars != nil && n.List != nil {
+		if len(subst.retvars) != 0 && n.List.Len() != 0 {
 			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)
+			// Make a shallow copy of retvars.
+			// Otherwise OINLCALL.Rlist will be the same list,
+			// and later walk and typecheck may clobber it.
+			for _, n := range subst.retvars {
+				as.List.Append(n)
 			}
-			as.Rlist = inlsubstlist(n.List)
-			typecheck(&as, Etop)
-			m.Ninit = list(m.Ninit, as)
+			as.Rlist.Set(subst.list(n.List))
+			as = typecheck(as, Etop)
+			m.Ninit.Append(as)
 		}
 
-		typechecklist(m.Ninit, Etop)
-		typecheck(&m, Etop)
+		typecheckslice(m.Ninit.Slice(), Etop)
+		m = typecheck(m, Etop)
 
 		//		dump("Return after substitution", m);
 		return m
@@ -951,46 +961,46 @@ func inlsubst(n *Node) *Node {
 	case OGOTO, OLABEL:
 		m := Nod(OXXX, nil, nil)
 		*m = *n
-		m.Ninit = nil
+		m.Ninit.Set(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
+	default:
+		m := Nod(OXXX, nil, nil)
+		*m = *n
+		m.Ninit.Set(nil)
 
-	if n.Op == OCLOSURE {
-		Fatalf("cannot inline function containing closure: %v", Nconv(n, obj.FmtSign))
-	}
+		if n.Op == OCLOSURE {
+			Fatalf("cannot inline function containing closure: %v", Nconv(n, 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)
+		m.Left = subst.node(n.Left)
+		m.Right = subst.node(n.Right)
+		m.List.Set(subst.list(n.List))
+		m.Rlist.Set(subst.list(n.Rlist))
+		m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
+		m.Nbody.Set(subst.list(n.Nbody))
 
-	return m
+		return m
+	}
 }
 
 // Plaster over linenumbers
-func setlnolist(ll *NodeList, lno int) {
-	for ; ll != nil; ll = ll.Next {
-		setlno(ll.N, lno)
+func setlnolist(ll Nodes, lno int32) {
+	for _, n := range ll.Slice() {
+		setlno(n, lno)
 	}
 }
 
-func setlno(n *Node, lno int) {
+func setlno(n *Node, lno int32) {
 	if n == nil {
 		return
 	}
 
 	// don't clobber names, unless they're freshly synthesized
 	if n.Op != ONAME || n.Lineno == 0 {
-		n.Lineno = int32(lno)
+		n.Lineno = lno
 	}
 
 	setlno(n.Left, lno)
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index b9c2735..f38819d 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -2,909 +2,50 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:generate go run mkbuiltin.go runtime unsafe
-
 package gc
 
 import (
+	"bufio"
 	"bytes"
 	"cmd/internal/obj"
-	"flag"
 	"fmt"
 	"io"
-	"log"
-	"os"
-	"path"
 	"strconv"
 	"strings"
 	"unicode"
 	"unicode/utf8"
 )
 
-var imported_unsafe bool
-
-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
-	{"export", &Debug_export},         // print export data
-}
-
 const (
 	EOF = -1
+	BOM = 0xFEFF
 )
 
-func usage() {
-	fmt.Printf("usage: compile [options] file.go...\n")
-	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("compile version %s%s%s\n", 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.DiagFunc = 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("msan", "build code compatible with C/C++ memory sanitizer", &flag_msan)
-	obj.Flagcount("newexport", "use new export format", &newexport) // TODO(gri) remove eventually (issue 13241)
-	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
-	switch Thearch.Thechar {
-	case '5', '6', '7', '8', '9':
-		obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
-	}
-	if Thearch.Thechar == '6' {
-		obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
-	}
-	switch Thearch.Thechar {
-	case '5', '6', '7', '8', '9':
-		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"
-	}
-	if flag_msan != 0 {
-		msanpkg = mkpkg("runtime/msan")
-		msanpkg.Name = "msan"
-	}
-	if flag_race != 0 && flag_msan != 0 {
-		log.Fatal("can not use both -race and -msan")
-	} else if flag_race != 0 || flag_msan != 0 {
-		instrumenting = true
-	}
-
-	// 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 {
-		Fatalf("betypeinit failed")
-	}
-
-	lexinit()
-	typeinit()
-	lexinit1()
-
-	blockgen = 1
-	dclcontext = PEXTERN
-	nerrors = 0
-	lexlineno = 1
-	const BOM = 0xFEFF
-
-	for _, infile = range flag.Args() {
-		if trace && Debug['x'] != 0 {
-			fmt.Printf("--- %s ---\n", infile)
-		}
-
-		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 = false
-		curio.eofnl = false
-		curio.last = 0
-
-		// Skip initial BOM if present.
-		if obj.Bgetrune(curio.bin) != BOM {
-			obj.Bungetrune(curio.bin)
-		}
-
-		block = 1
-		iota_ = -1000000
-
-		imported_unsafe = false
-
-		parse_file()
-		if nsyntaxerrors != 0 {
-			errorexit()
-		}
-
-		linehistpop()
-		if curio.bin != nil {
-			obj.Bterm(curio.bin)
-		}
-	}
-
-	testdclstack()
-	mkpackage(localpkg.Name) // final import not used checks
-	lexfini()
-
-	typecheckok = true
-	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 _, n := range importlist {
-			if n.Func.Inl != nil {
-				saveerrors()
-				typecheckinl(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 []*Node, recursive bool) {
-			// TODO: use a range statement here if the order does not matter
-			for i := len(list) - 1; i >= 0; i-- {
-				n := list[i]
-				if n.Op == ODCLFUNC {
-					caninl(n)
-					inlcalls(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)
-	}
-
-	if compiling_runtime != 0 {
-		checknowritebarrierrec()
-	}
-
-	// Phase 9: Check external declarations.
-	for i, n := range externdcl {
-		if n.Op == ONAME {
-			typecheck(&externdcl[i], 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 && 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 _, err := os.Stat(file); err == nil {
-			return file, true
-		}
-		file = fmt.Sprintf("%s.o", name)
-		if _, err := os.Stat(file); err == nil {
-			return file, true
-		}
-		return "", false
-	}
-
-	// local imports should be canonicalized already.
-	// don't want to see "encoding/../encoding/base64"
-	// as different from "encoding/base64".
-	if q := path.Clean(name); q != 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 _, err := os.Stat(file); err == nil {
-			return file, true
-		}
-		file = fmt.Sprintf("%s/%s.o", p.dir, name)
-		if _, err := os.Stat(file); err == nil {
-			return file, true
-		}
-	}
-
-	if goroot != "" {
-		suffix := ""
-		suffixsep := ""
-		if flag_installsuffix != "" {
-			suffixsep = "_"
-			suffix = flag_installsuffix
-		} else if flag_race != 0 {
-			suffixsep = "_"
-			suffix = "race"
-		} else if flag_msan != 0 {
-			suffixsep = "_"
-			suffix = "msan"
-		}
-
-		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", goroot, goos, goarch, suffixsep, suffix, name)
-		if _, err := os.Stat(file); err == nil {
-			return file, true
-		}
-		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name)
-		if _, err := os.Stat(file); err == nil {
-			return file, true
-		}
-	}
-
-	return "", false
-}
-
-func fakeimport() {
-	importpkg = mkpkg("fake")
-	cannedimports("fake.o", "$$\n")
-}
-
-// TODO(gri) line argument doesn't appear to be used
-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()
-	}
-
-	path_ := f.U.(string)
-
-	if mapped, ok := importMap[path_]; ok {
-		path_ = mapped
-	}
-
-	if path_ == "unsafe" {
-		if safemode != 0 {
-			Yyerror("cannot import package unsafe")
-			errorexit()
-		}
-
-		importpkg = mkpkg(f.U.(string))
-		cannedimports("unsafe.o", unsafeimport)
-		imported_unsafe = true
-		return
-	}
-
-	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 {
-		tag := ""
-		if importpkg.Safe {
-			tag = "safe"
-		}
-
-		p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag)
-		cannedimports(file, p)
-		return
-	}
-
-	importpkg.Imported = true
+// lexlineno is the line number _after_ the most recently read rune.
+// In particular, it's advanced (or rewound) as newlines are read (or unread).
+var lexlineno int32
 
-	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
-
-	// In the importfile, if we find:
-	// $$\n  (old format): position the input right after $$\n and return
-	// $$B\n (new format): import directly, then feed the lexer a dummy statement
-
-	// look for $$
-	var c int
-	for {
-		c = obj.Bgetc(imp)
-		if c < 0 {
-			break
-		}
-		if c == '$' {
-			c = obj.Bgetc(imp)
-			if c == '$' || c < 0 {
-				break
-			}
-		}
-	}
-
-	// get character after $$
-	if c >= 0 {
-		c = obj.Bgetc(imp)
-	}
+// lineno is the line number at the start of the most recently lexed token.
+var lineno int32
 
-	switch c {
-	case '\n':
-		// old export format
-		pushedio = curio
-
-		curio.bin = imp
-		curio.peekc = 0
-		curio.peekc1 = 0
-		curio.infile = file
-		curio.nlsemi = false
-		typecheckok = true
-
-		push_parser()
-
-	case 'B':
-		// new export format
-		obj.Bgetc(imp) // skip \n after $$B
-		Import(imp)
-
-		// continue as if the package was imported before (see above)
-		tag := ""
-		if importpkg.Safe {
-			tag = "safe"
-		}
-		p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag)
-		cannedimports(file, p)
-		// Reset incannedimport flag (we are not truly in a
-		// canned import) - this will cause importpkg.Direct to
-		// be set via parser.import_package (was issue #13977).
-		//
-		// TODO(gri) Remove this global variable and convoluted
-		// code in the process of streamlining the import code.
-		incannedimport = 0
-
-	default:
-		Yyerror("no import in %q", f.U.(string))
-	}
-}
-
-func unimportfile() {
-	pop_parser()
-
-	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 = false
-}
-
-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 = false
-	curio.importsafe = false
-
-	typecheckok = true
-	incannedimport = 1
-
-	push_parser()
-}
+var lexbuf bytes.Buffer
+var strbuf bytes.Buffer
+var litbuf string // LLITERAL value for use in syntax error messages
 
-func isSpace(c int) bool {
+func isSpace(c rune) bool {
 	return c == ' ' || c == '\t' || c == '\n' || c == '\r'
 }
 
-func isAlpha(c int) bool {
-	return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+func isLetter(c rune) bool {
+	return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_'
 }
 
-func isDigit(c int) bool {
+func isDigit(c rune) bool {
 	return '0' <= c && c <= '9'
 }
-func isAlnum(c int) bool {
-	return isAlpha(c) || isDigit(c)
+
+func isQuoted(s string) bool {
+	return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
 }
 
 func plan9quote(s string) string {
@@ -919,34 +60,76 @@ func plan9quote(s string) string {
 	return s
 }
 
-func isfrog(c int) bool {
-	// complain about possibly invisible control characters
-	if c < ' ' {
-		return !isSpace(c) // exclude good white space
-	}
+type Pragma uint16
 
-	if 0x7f <= c && c <= 0xa0 { // DEL, unicode block including unbreakable space.
-		return true
-	}
-	return false
-}
+const (
+	Nointerface       Pragma = 1 << iota
+	Noescape                 // func parameters don't escape
+	Norace                   // func must not have race detector annotations
+	Nosplit                  // func should not execute on separate stack
+	Noinline                 // func should not be inlined
+	Systemstack              // func must run on system stack
+	Nowritebarrier           // emit compiler error instead of write barrier
+	Nowritebarrierrec        // error on write barrier in this or recursive callees
+	CgoUnsafeArgs            // treat a pointer to one arg as a pointer to them all
+	UintptrEscapes           // pointers converted to uintptr escape
+)
+
+type lexer struct {
+	// source
+	bin        *bufio.Reader
+	prevlineno int32 // line no. of most recently read character
+
+	nlsemi bool // if set, '\n' and EOF translate to ';'
 
-type yySymType struct {
-	sym *Sym
-	val Val
-	op  Op
+	// pragma flags
+	// accumulated by lexer; reset by parser
+	pragma Pragma
+
+	// current token
+	tok  int32
+	sym_ *Sym   // valid if tok == LNAME
+	val  Val    // valid if tok == LLITERAL
+	op   Op     // valid if tok == LOPER, LASOP, or LINCOP, or prec > 0
+	prec OpPrec // operator precedence; 0 if not a binary operator
 }
 
+type OpPrec int
+
+const (
+	// Precedences of binary operators (must be > 0).
+	PCOMM OpPrec = 1 + iota
+	POROR
+	PANDAND
+	PCMP
+	PADD
+	PMUL
+)
+
 const (
-	LLITERAL = 57346 + iota
+	// The value of single-char tokens is just their character's Unicode value.
+	// They are all below utf8.RuneSelf. Shift other tokens up to avoid conflicts.
+
+	// names and literals
+	LNAME = utf8.RuneSelf + iota
+	LLITERAL
+
+	// operator-based operations
+	LOPER
 	LASOP
+	LINCOP
+
+	// miscellaneous
 	LCOLAS
+	LCOMM
+	LDDD
+
+	// keywords
 	LBREAK
 	LCASE
 	LCHAN
 	LCONST
 	LCONTINUE
-	LDDD
 	LDEFAULT
 	LDEFER
 	LELSE
@@ -959,7 +142,6 @@ const (
 	LIMPORT
 	LINTERFACE
 	LMAP
-	LNAME
 	LPACKAGE
 	LRANGE
 	LRETURN
@@ -968,649 +150,726 @@ const (
 	LSWITCH
 	LTYPE
 	LVAR
-	LANDAND
-	LANDNOT
-	LCOMM
-	LDEC
-	LEQ
-	LGE
-	LGT
+
 	LIGNORE
-	LINC
-	LLE
-	LLSH
-	LLT
-	LNE
-	LOROR
-	LRSH
 )
 
-func _yylex(yylval *yySymType) int32 {
-	var c1 int
-	var op Op
-	var escflag int
-	var v int64
-	var cp *bytes.Buffer
-	var s *Sym
-	var str string
-
-	prevlineno = lineno
-
-l0:
-	c := getc()
-	if isSpace(c) {
-		if c == '\n' && curio.nlsemi {
-			ungetc(c)
-			if Debug['x'] != 0 {
-				fmt.Printf("lex: implicit semi\n")
-			}
-			return ';'
-		}
+var lexn = map[rune]string{
+	LNAME:    "NAME",
+	LLITERAL: "LITERAL",
 
-		goto l0
-	}
+	LOPER:  "OPER",
+	LASOP:  "ASOP",
+	LINCOP: "INCOP",
 
-	lineno = lexlineno // start of token
+	LCOLAS: "COLAS",
+	LCOMM:  "COMM",
+	LDDD:   "DDD",
 
-	if c >= utf8.RuneSelf {
-		// all multibyte runes are alpha
-		cp = &lexbuf
-		cp.Reset()
+	LBREAK:     "BREAK",
+	LCASE:      "CASE",
+	LCHAN:      "CHAN",
+	LCONST:     "CONST",
+	LCONTINUE:  "CONTINUE",
+	LDEFAULT:   "DEFAULT",
+	LDEFER:     "DEFER",
+	LELSE:      "ELSE",
+	LFALL:      "FALL",
+	LFOR:       "FOR",
+	LFUNC:      "FUNC",
+	LGO:        "GO",
+	LGOTO:      "GOTO",
+	LIF:        "IF",
+	LIMPORT:    "IMPORT",
+	LINTERFACE: "INTERFACE",
+	LMAP:       "MAP",
+	LPACKAGE:   "PACKAGE",
+	LRANGE:     "RANGE",
+	LRETURN:    "RETURN",
+	LSELECT:    "SELECT",
+	LSTRUCT:    "STRUCT",
+	LSWITCH:    "SWITCH",
+	LTYPE:      "TYPE",
+	LVAR:       "VAR",
 
-		goto talph
-	}
+	// LIGNORE is never escaping lexer.next
+}
 
-	if isAlpha(c) {
-		cp = &lexbuf
-		cp.Reset()
-		goto talph
+func lexname(lex rune) string {
+	if s, ok := lexn[lex]; ok {
+		return s
 	}
-
-	if isDigit(c) {
-		cp = &lexbuf
-		cp.Reset()
-		if c != '0' {
-			for {
-				cp.WriteByte(byte(c))
-				c = getc()
-				if 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 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 !isDigit(c) {
-				break
-			}
-			if c < '0' || c > '7' {
-				c1 = 1 // not octal
+	return fmt.Sprintf("LEX-%d", lex)
+}
+
+func (l *lexer) next() {
+	nlsemi := l.nlsemi
+	l.nlsemi = false
+	l.prec = 0
+
+l0:
+	// skip white space
+	c := l.getr()
+	for isSpace(c) {
+		if c == '\n' && nlsemi {
+			if Debug['x'] != 0 {
+				fmt.Printf("lex: implicit semi\n")
 			}
-			cp.WriteByte(byte(c))
-			c = getc()
+			// Insert implicit semicolon on previous line,
+			// before the newline character.
+			lineno = lexlineno - 1
+			l.tok = ';'
+			return
 		}
+		c = l.getr()
+	}
 
-		if c == '.' {
-			goto casedot
-		}
-		if c == 'e' || c == 'E' {
-			goto caseep
-		}
-		if c == 'i' {
-			goto casei
-		}
-		if c1 != 0 {
-			Yyerror("malformed octal constant")
+	// start of token
+	lineno = lexlineno
+
+	// identifiers and keywords
+	// (for better error messages consume all chars >= utf8.RuneSelf for identifiers)
+	if isLetter(c) || c >= utf8.RuneSelf {
+		l.ident(c)
+		if l.tok == LIGNORE {
+			goto l0
 		}
-		goto ncu
+		return
 	}
+	// c < utf8.RuneSelf
+
+	var c1 rune
+	var op Op
+	var prec OpPrec
 
 	switch c {
 	case EOF:
-		lineno = prevlineno
-		ungetc(EOF)
-		return -1
+		l.ungetr()
+		// Treat EOF as "end of line" for the purposes
+		// of inserting a semicolon.
+		if nlsemi {
+			if Debug['x'] != 0 {
+				fmt.Printf("lex: implicit semi\n")
+			}
+			l.tok = ';'
+			return
+		}
+		l.tok = -1
+		return
 
-	case '_':
-		cp = &lexbuf
-		cp.Reset()
-		goto talph
+	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+		l.number(c)
+		return
 
 	case '.':
-		c1 = getc()
+		c1 = l.getr()
 		if isDigit(c1) {
-			cp = &lexbuf
-			cp.Reset()
-			cp.WriteByte(byte(c))
-			c = c1
-			goto casedot
+			l.ungetr()
+			l.number('.')
+			return
 		}
 
 		if c1 == '.' {
-			c1 = getc()
-			if c1 == '.' {
+			p, err := l.bin.Peek(1)
+			if err == nil && p[0] == '.' {
+				l.getr()
 				c = LDDD
 				goto lx
 			}
 
-			ungetc(c1)
+			l.ungetr()
 			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 {
-				cp.WriteRune(rune(v))
-			}
-		}
-
-		goto strlit
+		l.stdString()
+		return
 
-		// `...`
 	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
+		l.rawString()
+		return
 
-		// '.'
 	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
+		l.rune()
+		return
 
 	case '/':
-		c1 = getc()
+		c1 = l.getr()
 		if c1 == '*' {
-			nl := false
+			c = l.getr()
 			for {
-				c = int(getr())
-				if c == '\n' {
-					nl = true
-				}
-				for c == '*' {
-					c = int(getr())
+				if c == '*' {
+					c = l.getr()
 					if c == '/' {
-						if nl {
-							ungetc('\n')
-						}
-						goto l0
-					}
-
-					if c == '\n' {
-						nl = true
+						break
 					}
+					continue
 				}
-
 				if c == EOF {
 					Yyerror("eof in comment")
 					errorexit()
 				}
+				c = l.getr()
+			}
+
+			// A comment containing newlines acts like a newline.
+			if lexlineno > lineno && nlsemi {
+				if Debug['x'] != 0 {
+					fmt.Printf("lex: implicit semi\n")
+				}
+				l.tok = ';'
+				return
 			}
+			goto l0
 		}
 
 		if c1 == '/' {
-			c = getlinepragma()
+			c = l.getlinepragma()
 			for {
 				if c == '\n' || c == EOF {
-					ungetc(c)
+					l.ungetr()
 					goto l0
 				}
 
-				c = int(getr())
+				c = l.getr()
 			}
 		}
 
-		if c1 == '=' {
-			op = ODIV
-			goto asop
-		}
+		op = ODIV
+		prec = PMUL
+		goto binop1
 
 	case ':':
-		c1 = getc()
+		c1 = l.getr()
 		if c1 == '=' {
-			c = int(LCOLAS)
+			c = LCOLAS
 			goto lx
 		}
 
 	case '*':
-		c1 = getc()
-		if c1 == '=' {
-			op = OMUL
-			goto asop
-		}
+		op = OMUL
+		prec = PMUL
+		goto binop
 
 	case '%':
-		c1 = getc()
-		if c1 == '=' {
-			op = OMOD
-			goto asop
-		}
+		op = OMOD
+		prec = PMUL
+		goto binop
 
 	case '+':
-		c1 = getc()
-		if c1 == '+' {
-			c = int(LINC)
-			goto lx
-		}
-
-		if c1 == '=' {
-			op = OADD
-			goto asop
-		}
+		op = OADD
+		goto incop
 
 	case '-':
-		c1 = getc()
-		if c1 == '-' {
-			c = int(LDEC)
-			goto lx
-		}
-
-		if c1 == '=' {
-			op = OSUB
-			goto asop
-		}
+		op = OSUB
+		goto incop
 
 	case '>':
-		c1 = getc()
+		c = LOPER
+		c1 = l.getr()
 		if c1 == '>' {
-			c = int(LRSH)
-			c1 = getc()
-			if c1 == '=' {
-				op = ORSH
-				goto asop
-			}
-
-			break
+			op = ORSH
+			prec = PMUL
+			goto binop
 		}
 
+		l.prec = PCMP
 		if c1 == '=' {
-			c = int(LGE)
+			l.op = OGE
 			goto lx
 		}
-
-		c = int(LGT)
+		l.op = OGT
 
 	case '<':
-		c1 = getc()
+		c = LOPER
+		c1 = l.getr()
 		if c1 == '<' {
-			c = int(LLSH)
-			c1 = getc()
-			if c1 == '=' {
-				op = OLSH
-				goto asop
-			}
-
-			break
+			op = OLSH
+			prec = PMUL
+			goto binop
 		}
 
-		if c1 == '=' {
-			c = int(LLE)
+		if c1 == '-' {
+			c = LCOMM
+			// Not a binary operator, but parsed as one
+			// so we can give a good error message when used
+			// in an expression context.
+			l.prec = PCOMM
+			l.op = OSEND
 			goto lx
 		}
 
-		if c1 == '-' {
-			c = int(LCOMM)
+		l.prec = PCMP
+		if c1 == '=' {
+			l.op = OLE
 			goto lx
 		}
-
-		c = int(LLT)
+		l.op = OLT
 
 	case '=':
-		c1 = getc()
+		c1 = l.getr()
 		if c1 == '=' {
-			c = int(LEQ)
+			c = LOPER
+			l.prec = PCMP
+			l.op = OEQ
 			goto lx
 		}
 
 	case '!':
-		c1 = getc()
+		c1 = l.getr()
 		if c1 == '=' {
-			c = int(LNE)
+			c = LOPER
+			l.prec = PCMP
+			l.op = ONE
 			goto lx
 		}
 
 	case '&':
-		c1 = getc()
+		c1 = l.getr()
 		if c1 == '&' {
-			c = int(LANDAND)
+			c = LOPER
+			l.prec = PANDAND
+			l.op = OANDAND
 			goto lx
 		}
 
 		if c1 == '^' {
-			c = int(LANDNOT)
-			c1 = getc()
-			if c1 == '=' {
-				op = OANDNOT
-				goto asop
-			}
-
-			break
+			c = LOPER
+			op = OANDNOT
+			prec = PMUL
+			goto binop
 		}
 
-		if c1 == '=' {
-			op = OAND
-			goto asop
-		}
+		op = OAND
+		prec = PMUL
+		goto binop1
 
 	case '|':
-		c1 = getc()
+		c1 = l.getr()
 		if c1 == '|' {
-			c = int(LOROR)
+			c = LOPER
+			l.prec = POROR
+			l.op = OOROR
 			goto lx
 		}
 
-		if c1 == '=' {
-			op = OOR
-			goto asop
-		}
+		op = OOR
+		prec = PADD
+		goto binop1
 
 	case '^':
-		c1 = getc()
-		if c1 == '=' {
-			op = OXOR
-			goto asop
+		op = OXOR
+		prec = PADD
+		goto binop
+
+	case '(', '[', '{', ',', ';':
+		goto lx
+
+	case ')', ']', '}':
+		l.nlsemi = true
+		goto lx
+
+	case '#', '$', '?', '@', '\\':
+		if importpkg != nil {
+			goto lx
 		}
+		fallthrough
 
 	default:
-		goto lx
+		// anything else is illegal
+		Yyerror("syntax error: illegal character %#U", c)
+		goto l0
 	}
 
-	ungetc(c1)
+	l.ungetr()
 
 lx:
 	if Debug['x'] != 0 {
-		if c > 0xff {
-			fmt.Printf("%v lex: TOKEN %s\n", Ctxt.Line(int(lexlineno)), lexname(c))
+		if c >= utf8.RuneSelf {
+			fmt.Printf("%v lex: TOKEN %s\n", linestr(lineno), lexname(c))
 		} else {
-			fmt.Printf("%v lex: TOKEN '%c'\n", Ctxt.Line(int(lexlineno)), c)
+			fmt.Printf("%v lex: TOKEN '%c'\n", linestr(lineno), 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
+	l.tok = c
+	return
+
+incop:
+	c1 = l.getr()
+	if c1 == c {
+		l.nlsemi = true
+		l.op = op
+		c = LINCOP
+		goto lx
 	}
+	prec = PADD
+	goto binop1
 
-	return int32(c)
+binop:
+	c1 = l.getr()
+binop1:
+	if c1 != '=' {
+		l.ungetr()
+		l.op = op
+		l.prec = prec
+		goto lx
+	}
 
-asop:
-	yylval.op = op
+	l.op = op
 	if Debug['x'] != 0 {
 		fmt.Printf("lex: TOKEN ASOP %s=\n", goopnames[op])
 	}
-	return LASOP
+	l.tok = LASOP
+}
+
+func (l *lexer) ident(c rune) {
+	cp := &lexbuf
+	cp.Reset()
+
+	// accelerate common case (7bit ASCII)
+	for isLetter(c) || isDigit(c) {
+		cp.WriteByte(byte(c))
+		c = l.getr()
+	}
 
-	// cp is set to lexbuf and some
-	// prefix has been stored
-talph:
+	// general case
 	for {
 		if c >= utf8.RuneSelf {
-			ungetc(c)
-			r := rune(getr())
-
-			// 0xb7 · is used for internal names
-			if !unicode.IsLetter(r) && !unicode.IsDigit(r) && (importpkg == nil || r != 0xb7) {
-				Yyerror("invalid identifier character U+%04x", r)
-			}
-			if cp.Len() == 0 && unicode.IsDigit(r) {
-				Yyerror("identifier cannot begin with digit U+%04x", r)
+			if unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || importpkg != nil && c == 0xb7 {
+				if cp.Len() == 0 && unicode.IsDigit(c) {
+					Yyerror("identifier cannot begin with digit %#U", c)
+				}
+			} else {
+				Yyerror("invalid identifier character %#U", c)
 			}
-			cp.WriteRune(r)
-		} else if !isAlnum(c) && c != '_' {
-			break
-		} else {
+			cp.WriteRune(c)
+		} else if isLetter(c) || isDigit(c) {
 			cp.WriteByte(byte(c))
+		} else {
+			break
 		}
-		c = getc()
+		c = l.getr()
 	}
 
 	cp = nil
-	ungetc(c)
+	l.ungetr()
 
-	s = LookupBytes(lexbuf.Bytes())
-	if s.Lexical == LIGNORE {
-		goto l0
+	name := lexbuf.Bytes()
+
+	if len(name) >= 2 {
+		if tok, ok := keywords[string(name)]; ok {
+			if Debug['x'] != 0 {
+				fmt.Printf("lex: %s\n", lexname(tok))
+			}
+			switch tok {
+			case LBREAK, LCONTINUE, LFALL, LRETURN:
+				l.nlsemi = true
+			}
+			l.tok = tok
+			return
+		}
 	}
 
+	s := LookupBytes(name)
 	if Debug['x'] != 0 {
-		fmt.Printf("lex: %s %s\n", s, lexname(int(s.Lexical)))
+		fmt.Printf("lex: ident %s\n", s)
 	}
-	yylval.sym = s
-	return int32(s.Lexical)
+	l.sym_ = s
+	l.nlsemi = true
+	l.tok = LNAME
+}
 
-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)
-	}
+var keywords = map[string]int32{
+	"break":       LBREAK,
+	"case":        LCASE,
+	"chan":        LCHAN,
+	"const":       LCONST,
+	"continue":    LCONTINUE,
+	"default":     LDEFAULT,
+	"defer":       LDEFER,
+	"else":        LELSE,
+	"fallthrough": LFALL,
+	"for":         LFOR,
+	"func":        LFUNC,
+	"go":          LGO,
+	"goto":        LGOTO,
+	"if":          LIF,
+	"import":      LIMPORT,
+	"interface":   LINTERFACE,
+	"map":         LMAP,
+	"package":     LPACKAGE,
+	"range":       LRANGE,
+	"return":      LRETURN,
+	"select":      LSELECT,
+	"struct":      LSTRUCT,
+	"switch":      LSWITCH,
+	"type":        LTYPE,
+	"var":         LVAR,
+
+	// 💩
+	"notwithstanding":      LIGNORE,
+	"thetruthofthematter":  LIGNORE,
+	"despiteallobjections": LIGNORE,
+	"whereas":              LIGNORE,
+	"insofaras":            LIGNORE,
+}
 
-	if Debug['x'] != 0 {
-		fmt.Printf("lex: integer literal\n")
-	}
-	litbuf = "literal " + str
-	return LLITERAL
+func (l *lexer) number(c rune) {
+	cp := &lexbuf
+	cp.Reset()
 
-casedot:
-	for {
-		cp.WriteByte(byte(c))
-		c = getc()
-		if !isDigit(c) {
-			break
+	// parse mantissa before decimal point or exponent
+	isInt := false
+	malformedOctal := false
+	if c != '.' {
+		if c != '0' {
+			// decimal or float
+			for isDigit(c) {
+				cp.WriteByte(byte(c))
+				c = l.getr()
+			}
+
+		} else {
+			// c == 0
+			cp.WriteByte('0')
+			c = l.getr()
+			if c == 'x' || c == 'X' {
+				isInt = true // must be int
+				cp.WriteByte(byte(c))
+				c = l.getr()
+				for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+					cp.WriteByte(byte(c))
+					c = l.getr()
+				}
+				if lexbuf.Len() == 2 {
+					Yyerror("malformed hex constant")
+				}
+			} else {
+				// decimal 0, octal, or float
+				for isDigit(c) {
+					if c > '7' {
+						malformedOctal = true
+					}
+					cp.WriteByte(byte(c))
+					c = l.getr()
+				}
+			}
 		}
 	}
 
-	if c == 'i' {
-		goto casei
-	}
-	if c != 'e' && c != 'E' {
-		goto caseout
-	}
+	// unless we have a hex number, parse fractional part or exponent, if any
+	var str string
+	if !isInt {
+		isInt = true // assume int unless proven otherwise
 
-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()
-	}
+		// fraction
+		if c == '.' {
+			isInt = false
+			cp.WriteByte('.')
+			c = l.getr()
+			for isDigit(c) {
+				cp.WriteByte(byte(c))
+				c = l.getr()
+			}
+			// Falling through to exponent parsing here permits invalid
+			// floating-point numbers with fractional mantissa and base-2
+			// (p or P) exponent. We don't care because base-2 exponents
+			// can only show up in machine-generated textual export data
+			// which will use correct formatting.
+		}
+
+		// exponent
+		// base-2 exponent (p or P) is only allowed in export data (see #9036)
+		// TODO(gri) Once we switch to binary import data, importpkg will
+		// always be nil in this function. Simplify the code accordingly.
+		if c == 'e' || c == 'E' || importpkg != nil && (c == 'p' || c == 'P') {
+			isInt = false
+			cp.WriteByte(byte(c))
+			c = l.getr()
+			if c == '+' || c == '-' {
+				cp.WriteByte(byte(c))
+				c = l.getr()
+			}
+			if !isDigit(c) {
+				Yyerror("malformed floating point constant exponent")
+			}
+			for isDigit(c) {
+				cp.WriteByte(byte(c))
+				c = l.getr()
+			}
+		}
 
-	if !isDigit(c) {
-		Yyerror("malformed floating point constant exponent")
-	}
-	for isDigit(c) {
-		cp.WriteByte(byte(c))
-		c = getc()
+		// imaginary constant
+		if c == 'i' {
+			str = lexbuf.String()
+			x := new(Mpcplx)
+			x.Real.SetFloat64(0.0)
+			x.Imag.SetString(str)
+			if x.Imag.Val.IsInf() {
+				Yyerror("overflow in imaginary constant")
+				x.Imag.SetFloat64(0.0)
+			}
+			l.val.U = x
+
+			if Debug['x'] != 0 {
+				fmt.Printf("lex: imaginary literal\n")
+			}
+			goto done
+		}
 	}
 
-	if c == 'i' {
-		goto casei
+	l.ungetr()
+
+	if isInt {
+		if malformedOctal {
+			Yyerror("malformed octal constant")
+		}
+
+		str = lexbuf.String()
+		x := new(Mpint)
+		x.SetString(str)
+		if x.Ovf {
+			Yyerror("overflow in constant")
+			x.SetInt64(0)
+		}
+		l.val.U = x
+
+		if Debug['x'] != 0 {
+			fmt.Printf("lex: integer literal\n")
+		}
+
+	} else { // float
+
+		str = lexbuf.String()
+		x := newMpflt()
+		x.SetString(str)
+		if x.Val.IsInf() {
+			Yyerror("overflow in float constant")
+			x.SetFloat64(0.0)
+		}
+		l.val.U = x
+
+		if Debug['x'] != 0 {
+			fmt.Printf("lex: floating literal\n")
+		}
 	}
-	goto caseout
 
-	// imaginary constant
-casei:
-	cp = nil
+done:
+	litbuf = "" // lazily initialized in (*parser).syntax_error
+	l.nlsemi = true
+	l.tok = LLITERAL
+}
+
+func (l *lexer) stdString() {
+	lexbuf.Reset()
+	lexbuf.WriteString(`"<string>"`)
+
+	cp := &strbuf
+	cp.Reset()
 
-	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).Imag, 0.0)
+	for {
+		r, b, ok := l.onechar('"')
+		if !ok {
+			break
+		}
+		if r == 0 {
+			cp.WriteByte(b)
+		} else {
+			cp.WriteRune(r)
+		}
 	}
 
+	l.val.U = internString(cp.Bytes())
 	if Debug['x'] != 0 {
-		fmt.Printf("lex: imaginary literal\n")
+		fmt.Printf("lex: string literal\n")
 	}
-	litbuf = "literal " + str
-	return LLITERAL
+	litbuf = "string literal"
+	l.nlsemi = true
+	l.tok = 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)
-	}
+func (l *lexer) rawString() {
+	lexbuf.Reset()
+	lexbuf.WriteString("`<string>`")
 
-	if Debug['x'] != 0 {
-		fmt.Printf("lex: floating literal\n")
+	cp := &strbuf
+	cp.Reset()
+
+	for {
+		c := l.getr()
+		if c == '\r' {
+			continue
+		}
+		if c == EOF {
+			Yyerror("eof in string")
+			break
+		}
+		if c == '`' {
+			break
+		}
+		cp.WriteRune(c)
 	}
-	litbuf = "literal " + str
-	return LLITERAL
 
-strlit:
-	yylval.val.U = internString(cp.Bytes())
+	l.val.U = internString(cp.Bytes())
 	if Debug['x'] != 0 {
 		fmt.Printf("lex: string literal\n")
 	}
 	litbuf = "string literal"
-	return LLITERAL
+	l.nlsemi = true
+	l.tok = LLITERAL
 }
 
-var internedStrings = map[string]string{}
+func (l *lexer) rune() {
+	r, b, ok := l.onechar('\'')
+	if !ok {
+		Yyerror("empty character literal or unescaped ' in character literal")
+		r = '\''
+	}
+	if r == 0 {
+		r = rune(b)
+	}
 
-func internString(b []byte) string {
-	s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
-	if ok {
-		return s
+	if c := l.getr(); c != '\'' {
+		Yyerror("missing '")
+		l.ungetr()
 	}
-	s = string(b)
-	internedStrings[s] = s
-	return s
+
+	x := new(Mpint)
+	l.val.U = x
+	x.SetInt64(int64(r))
+	x.Rune = true
+	if Debug['x'] != 0 {
+		fmt.Printf("lex: codepoint literal\n")
+	}
+	litbuf = "rune literal"
+	l.nlsemi = true
+	l.tok = LLITERAL
 }
 
-func more(pp *string) bool {
-	p := *pp
-	for p != "" && isSpace(int(p[0])) {
-		p = p[1:]
+var internedStrings = map[string]string{}
+
+func internString(b []byte) string {
+	s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
+	if !ok {
+		s = string(b)
+		internedStrings[s] = s
 	}
-	*pp = p
-	return p != ""
+	return s
 }
 
 // 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' {
+func (l *lexer) getlinepragma() rune {
+	c := l.getr()
+	if c == 'g' { // check for //go: directive
 		cp := &lexbuf
 		cp.Reset()
 		cp.WriteByte('g') // already read
 		for {
-			c = int(getr())
+			c = l.getr()
 			if c == EOF || c >= utf8.RuneSelf {
 				return c
 			}
@@ -1624,86 +883,78 @@ func getlinepragma() int {
 		text := strings.TrimSuffix(lexbuf.String(), "\r")
 
 		if strings.HasPrefix(text, "go:cgo_") {
-			pragcgo(text)
+			pragcgobuf += pragcgo(text)
 		}
 
-		cmd = text
-		verb = cmd
-		if i := strings.Index(verb, " "); i >= 0 {
+		verb := text
+		if i := strings.Index(text, " "); i >= 0 {
 			verb = verb[:i]
 		}
 
-		if verb == "go:linkname" {
+		switch verb {
+		case "go:linkname":
 			if !imported_unsafe {
 				Yyerror("//go:linkname only allowed in Go files that import \"unsafe\"")
 			}
-			f := strings.Fields(cmd)
+			f := strings.Fields(text)
 			if len(f) != 3 {
 				Yyerror("usage: //go:linkname localname linkname")
-				return c
+				break
 			}
-
 			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:noinline" {
-			noinline = true
-			return c
-		}
-
-		if verb == "go:systemstack" {
-			if compiling_runtime == 0 {
+		case "go:nointerface":
+			if obj.Fieldtrack_enabled != 0 {
+				l.pragma |= Nointerface
+			}
+		case "go:noescape":
+			l.pragma |= Noescape
+		case "go:norace":
+			l.pragma |= Norace
+		case "go:nosplit":
+			l.pragma |= Nosplit
+		case "go:noinline":
+			l.pragma |= Noinline
+		case "go:systemstack":
+			if !compiling_runtime {
 				Yyerror("//go:systemstack only allowed in runtime")
 			}
-			systemstack = true
-			return c
-		}
-
-		if verb == "go:nowritebarrier" {
-			if compiling_runtime == 0 {
+			l.pragma |= Systemstack
+		case "go:nowritebarrier":
+			if !compiling_runtime {
 				Yyerror("//go:nowritebarrier only allowed in runtime")
 			}
-			nowritebarrier = true
-			return c
-		}
-
-		if verb == "go:nowritebarrierrec" {
-			if compiling_runtime == 0 {
+			l.pragma |= Nowritebarrier
+		case "go:nowritebarrierrec":
+			if !compiling_runtime {
 				Yyerror("//go:nowritebarrierrec only allowed in runtime")
 			}
-			nowritebarrierrec = true
-			nowritebarrier = true // Implies nowritebarrier
-			return c
+			l.pragma |= Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
+		case "go:cgo_unsafe_args":
+			l.pragma |= CgoUnsafeArgs
+		case "go:uintptrescapes":
+			// For the next function declared in the file
+			// any uintptr arguments may be pointer values
+			// converted to uintptr. This directive
+			// ensures that the referenced allocated
+			// object, if any, is retained and not moved
+			// until the call completes, even though from
+			// the types alone it would appear that the
+			// object is no longer needed during the
+			// call. The conversion to uintptr must appear
+			// in the argument list.
+			// Used in syscall/dll_windows.go.
+			l.pragma |= UintptrEscapes
 		}
 		return c
 	}
+
+	// check for //line directive
 	if c != 'l' {
 		return c
 	}
 	for i := 1; i < 5; i++ {
-		c = int(getr())
-		if c != int("line "[i]) {
+		c = l.getr()
+		if c != rune("line "[i]) {
 			return c
 		}
 	}
@@ -1712,7 +963,7 @@ func getlinepragma() int {
 	cp.Reset()
 	linep := 0
 	for {
-		c = int(getr())
+		c = l.getr()
 		if c == EOF {
 			return c
 		}
@@ -1727,367 +978,226 @@ func getlinepragma() int {
 		}
 		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()
-		}
+	n, err := strconv.Atoi(text[linep:])
+	if err != nil {
+		return c // todo: make this an error instead? it is almost certainly a bug.
+	}
+	if n > 1e8 {
+		Yyerror("line number out of range")
+		errorexit()
 	}
-
 	if n <= 0 {
 		return c
 	}
 
-	name = text[:linep-1]
-	linehistupdate(name, n)
+	linehistupdate(text[:linep-1], 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) && !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
+func pragcgo(text string) string {
+	f := pragmaFields(text)
+
+	verb := f[0][3:] // skip "go:"
+	switch verb {
+	case "cgo_export_static", "cgo_export_dynamic":
+		switch {
+		case len(f) == 2 && !isQuoted(f[1]):
+			local := plan9quote(f[1])
+			return fmt.Sprintln(verb, local)
+
+		case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
+			local := plan9quote(f[1])
+			remote := plan9quote(f[2])
+			return fmt.Sprintln(verb, local, remote)
+
+		default:
+			Yyerror(`usage: //go:%s local [remote]`, verb)
+		}
+	case "cgo_import_dynamic":
+		switch {
+		case len(f) == 2 && !isQuoted(f[1]):
+			local := plan9quote(f[1])
+			return fmt.Sprintln(verb, local)
+
+		case len(f) == 3 && !isQuoted(f[1]) && !isQuoted(f[2]):
+			local := plan9quote(f[1])
+			remote := plan9quote(f[2])
+			return fmt.Sprintln(verb, local, remote)
+
+		case len(f) == 4 && !isQuoted(f[1]) && !isQuoted(f[2]) && isQuoted(f[3]):
+			local := plan9quote(f[1])
+			remote := plan9quote(f[2])
+			library := plan9quote(strings.Trim(f[3], `"`))
+			return fmt.Sprintln(verb, local, remote, library)
+
+		default:
+			Yyerror(`usage: //go:cgo_import_dynamic local [remote ["library"]]`)
+		}
+	case "cgo_import_static":
+		switch {
+		case len(f) == 2 && !isQuoted(f[1]):
+			local := plan9quote(f[1])
+			return fmt.Sprintln(verb, local)
+
+		default:
+			Yyerror(`usage: //go:cgo_import_static local`)
+		}
+	case "cgo_dynamic_linker":
+		switch {
+		case len(f) == 2 && isQuoted(f[1]):
+			path := plan9quote(strings.Trim(f[1], `"`))
+			return fmt.Sprintln(verb, path)
+
+		default:
+			Yyerror(`usage: //go:cgo_dynamic_linker "path"`)
+		}
+	case "cgo_ldflag":
+		switch {
+		case len(f) == 2 && isQuoted(f[1]):
+			arg := plan9quote(strings.Trim(f[1], `"`))
+			return fmt.Sprintln(verb, arg)
+
+		default:
+			Yyerror(`usage: //go:cgo_ldflag "arg"`)
+		}
+	}
+	return ""
 }
 
-// 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" {
-		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" {
-		p, ok := getquoted(&q)
-		if !ok {
-			Yyerror("usage: //go:cgo_ldflag \"arg\"")
-			return
+// pragmaFields is similar to strings.FieldsFunc(s, isSpace)
+// but does not split when inside double quoted regions and always
+// splits before the start and after the end of a double quoted region.
+// pragmaFields does not recognize escaped quotes. If a quote in s is not
+// closed the part after the opening quote will not be returned as a field.
+func pragmaFields(s string) []string {
+	var a []string
+	inQuote := false
+	fieldStart := -1 // Set to -1 when looking for start of field.
+	for i, c := range s {
+		switch {
+		case c == '"':
+			if inQuote {
+				inQuote = false
+				a = append(a, s[fieldStart:i+1])
+				fieldStart = -1
+			} else {
+				inQuote = true
+				if fieldStart >= 0 {
+					a = append(a, s[fieldStart:i])
+				}
+				fieldStart = i
+			}
+		case !inQuote && isSpace(c):
+			if fieldStart >= 0 {
+				a = append(a, s[fieldStart:i])
+				fieldStart = -1
+			}
+		default:
+			if fieldStart == -1 {
+				fieldStart = i
+			}
 		}
-		pragcgobuf += fmt.Sprintf("cgo_ldflag %v\n", plan9quote(p))
-		return
-
-	}
-}
-
-func yylex(yylval *yySymType) int32 {
-	lx := _yylex(yylval)
-
-	if curio.nlsemi && 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 = true
-
-	default:
-		curio.nlsemi = false
+	if !inQuote && fieldStart >= 0 { // Last field might end at the end of the string.
+		a = append(a, s[fieldStart:])
 	}
-
-	return lx
+	return a
 }
 
-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)
-		// recognize BOM (U+FEFF): UTF-8 encoding is 0xef 0xbb 0xbf
-		if c == 0xef {
-			buf, err := curio.bin.Peek(2)
-			if err != nil {
-				yyerrorl(int(lexlineno), "illegal UTF-8 sequence ef % x followed by read error (%v)", string(buf), err)
-				errorexit()
-			}
-			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
-			}
+func (l *lexer) getr() rune {
+redo:
+	l.prevlineno = lexlineno
+	r, w, err := l.bin.ReadRune()
+	if err != nil {
+		if err != io.EOF {
+			Fatalf("io error: %v", err)
 		}
+		return -1
 	}
-
-check:
-	switch c {
+	switch r {
 	case 0:
-		if curio.bin != nil {
-			Yyerror("illegal NUL byte")
-			break
-		}
-		fallthrough
-
-		// insert \n at EOF
-	case EOF:
-		if curio.eofnl || curio.last == '\n' {
-			return EOF
-		}
-		curio.eofnl = true
-		c = '\n'
-		fallthrough
-
+		yyerrorl(lexlineno, "illegal NUL byte")
 	case '\n':
-		if pushedio.bin == nil {
+		if importpkg == nil {
 			lexlineno++
 		}
+	case utf8.RuneError:
+		if w == 1 {
+			yyerrorl(lexlineno, "illegal UTF-8 sequence")
+		}
+	case BOM:
+		yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file")
+		goto redo
 	}
 
-	curio.last = c
-	return c
-}
-
-func ungetc(c int) {
-	curio.peekc1 = curio.peekc
-	curio.peekc = c
-	if c == '\n' && pushedio.bin == nil {
-		lexlineno--
-	}
+	return r
 }
 
-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 (l *lexer) ungetr() {
+	l.bin.UnreadRune()
+	lexlineno = l.prevlineno
 }
 
-func escchar(e int, escflg *int, val *int64) bool {
-	*escflg = 0
-
-	c := int(getr())
+// onechar lexes a single character within a rune or interpreted string literal,
+// handling escape sequences as necessary.
+func (l *lexer) onechar(quote rune) (r rune, b byte, ok bool) {
+	c := l.getr()
 	switch c {
 	case EOF:
 		Yyerror("eof in string")
-		return true
+		l.ungetr()
+		return
 
 	case '\n':
 		Yyerror("newline in string")
-		return true
+		l.ungetr()
+		return
 
 	case '\\':
 		break
 
+	case quote:
+		return
+
 	default:
-		if c == e {
-			return true
-		}
-		*val = int64(c)
-		return false
+		return c, 0, true
 	}
 
-	u := 0
-	c = int(getr())
-	var i int
+	c = l.getr()
 	switch c {
 	case 'x':
-		*escflg = 1 // it's a byte
-		i = 2
-		goto hex
+		return 0, byte(l.hexchar(2)), true
 
 	case 'u':
-		i = 4
-		u = 1
-		goto hex
+		return l.unichar(4), 0, true
 
 	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'
+		return l.unichar(8), 0, true
+
+	case '0', '1', '2', '3', '4', '5', '6', '7':
+		x := c - '0'
 		for i := 2; i > 0; i-- {
-			c = getc()
+			c = l.getr()
 			if c >= '0' && c <= '7' {
-				l = l*8 + int64(c) - '0'
+				x = x*8 + c - '0'
 				continue
 			}
 
 			Yyerror("non-octal character in escape sequence: %c", c)
-			ungetc(c)
+			l.ungetr()
 		}
 
-		if l > 255 {
-			Yyerror("octal escape value > 255: %d", l)
+		if x > 255 {
+			Yyerror("octal escape value > 255: %d", x)
 		}
 
-		*val = l
-		return false
+		return 0, byte(x), true
 
 	case 'a':
 		c = '\a'
@@ -2107,481 +1217,42 @@ func escchar(e int, escflg *int, val *int64) bool {
 		c = '\\'
 
 	default:
-		if c != e {
+		if c != quote {
 			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   EType
-	op      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},
-}
-
-// lexinit initializes known symbols and the basic types.
-func lexinit() {
-	for _, s := range syms {
-		lex := s.lexical
-		s1 := Lookup(s.name)
-		s1.Lexical = uint16(lex)
-
-		if etype := s.etype; etype != Txxx {
-			if int(etype) >= len(Types) {
-				Fatalf("lexinit: %s bad etype", s.name)
-			}
-			s2 := Pkglookup(s.name, builtinpkg)
-			t := Types[etype]
-			if t == nil {
-				t = typ(etype)
-				t.Sym = s2
-
-				if etype != TANY && etype != TSTRING {
-					dowidth(t)
-				}
-				Types[etype] = t
-			}
-
-			s2.Lexical = LNAME
-			s2.Def = typenod(t)
-			s2.Def.Name = new(Name)
-			continue
-		}
-
-		// TODO(marvin): Fix Node.EType type union.
-		if etype := s.op; etype != OXXX {
-			s2 := Pkglookup(s.name, builtinpkg)
-			s2.Lexical = LNAME
-			s2.Def = Nod(ONAME, nil, nil)
-			s2.Def.Sym = s2
-			s2.Def.Etype = EType(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 = true
-	in := typ(TSTRUCT)
-	in.Funarg = true
-	out := typ(TSTRUCT)
-	out.Type = typ(TFIELD)
-	out.Type.Type = Types[TSTRING]
-	out.Funarg = true
-	f := typ(TFUNC)
-	*getthis(f) = rcvr
-	*Getoutarg(f) = out
-	*getinarg(f) = in
-	f.Thistuple = 1
-	f.Intuple = 0
-	f.Outnamed = false
-	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() {
-	for i := range syms {
-		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
-		}
-
-		// TODO(marvin): Fix Node.EType type union.
-		etype = EType(syms[i].op)
-		if etype != EType(OXXX) && s.Def == nil {
-			s.Def = Nod(ONAME, nil, nil)
-			s.Def.Sym = s
-			s.Def.Etype = 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.
-	if s := Lookup("byte"); s.Def == nil {
-		s.Def = typenod(bytetype)
-		s.Def.Name = new(Name)
-		s.Origpkg = builtinpkg
-	}
-
-	if s := Lookup("error"); s.Def == nil {
-		s.Def = typenod(errortype)
-		s.Def.Name = new(Name)
-		s.Origpkg = builtinpkg
-	}
-
-	if s := Lookup("rune"); s.Def == nil {
-		s.Def = typenod(runetype)
-		s.Def.Name = new(Name)
-		s.Origpkg = builtinpkg
-	}
-
-	if s := Lookup("nil"); 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
-	}
-
-	if s := Lookup("iota"); s.Def == nil {
-		s.Def = Nod(OIOTA, nil, nil)
-		s.Def.Sym = s
-		s.Origpkg = builtinpkg
-	}
-
-	if s := Lookup("true"); s.Def == nil {
-		s.Def = Nodbool(true)
-		s.Def.Sym = s
-		s.Def.Name = new(Name)
-		s.Origpkg = builtinpkg
-	}
-
-	if s := Lookup("false"); 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 = map[int]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 {
-	if s, ok := lexn[lex]; ok {
-		return s
-	}
-	return fmt.Sprintf("LEX-%d", lex)
+	return c, 0, true
 }
 
-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 (l *lexer) unichar(n int) rune {
+	x := l.hexchar(n)
+	if x > utf8.MaxRune || 0xd800 <= x && x < 0xe000 {
+		Yyerror("invalid Unicode code point in escape sequence: %#x", x)
+		x = utf8.RuneError
 	}
+	return rune(x)
 }
 
-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
-				}
+func (l *lexer) hexchar(n int) uint32 {
+	var x uint32
 
-				s.Def = nil
-				continue
-			}
+	for ; n > 0; n-- {
+		var d uint32
+		switch c := l.getr(); {
+		case isDigit(c):
+			d = uint32(c - '0')
+		case 'a' <= c && c <= 'f':
+			d = uint32(c - 'a' + 10)
+		case 'A' <= c && c <= 'F':
+			d = uint32(c - 'A' + 10)
+		default:
+			Yyerror("non-hex character in escape sequence: %c", c)
+			l.ungetr()
+			return x
 		}
+		x = x*16 + d
 	}
 
-	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
-	}
+	return x
 }
diff --git a/src/cmd/compile/internal/gc/lex_test.go b/src/cmd/compile/internal/gc/lex_test.go
new file mode 100644
index 0000000..9230b30
--- /dev/null
+++ b/src/cmd/compile/internal/gc/lex_test.go
@@ -0,0 +1,79 @@
+// Copyright 2016 The Go Authors. 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 "testing"
+
+func eq(a, b []string) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i := 0; i < len(a); i++ {
+		if a[i] != b[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func TestPragmaFields(t *testing.T) {
+
+	var tests = []struct {
+		in   string
+		want []string
+	}{
+		{"", []string{}},
+		{" \t ", []string{}},
+		{`""""`, []string{`""`, `""`}},
+		{"  a'b'c  ", []string{"a'b'c"}},
+		{"1 2 3 4", []string{"1", "2", "3", "4"}},
+		{"\n☺\t☹\n", []string{"☺", "☹"}},
+		{`"1 2 "  3  " 4 5"`, []string{`"1 2 "`, `3`, `" 4 5"`}},
+		{`"1""2 3""4"`, []string{`"1"`, `"2 3"`, `"4"`}},
+		{`12"34"`, []string{`12`, `"34"`}},
+		{`12"34 `, []string{`12`}},
+	}
+
+	for _, tt := range tests {
+		got := pragmaFields(tt.in)
+		if !eq(got, tt.want) {
+			t.Errorf("pragmaFields(%q) = %v; want %v", tt.in, got, tt.want)
+			continue
+		}
+	}
+}
+
+func TestPragcgo(t *testing.T) {
+
+	var tests = []struct {
+		in   string
+		want string
+	}{
+		{`go:cgo_export_dynamic local`, "cgo_export_dynamic local\n"},
+		{`go:cgo_export_dynamic local remote`, "cgo_export_dynamic local remote\n"},
+		{`go:cgo_export_dynamic local' remote'`, "cgo_export_dynamic 'local''' 'remote'''\n"},
+		{`go:cgo_export_static local`, "cgo_export_static local\n"},
+		{`go:cgo_export_static local remote`, "cgo_export_static local remote\n"},
+		{`go:cgo_export_static local' remote'`, "cgo_export_static 'local''' 'remote'''\n"},
+		{`go:cgo_import_dynamic local`, "cgo_import_dynamic local\n"},
+		{`go:cgo_import_dynamic local remote`, "cgo_import_dynamic local remote\n"},
+		{`go:cgo_import_dynamic local remote "library"`, "cgo_import_dynamic local remote library\n"},
+		{`go:cgo_import_dynamic local' remote' "lib rary"`, "cgo_import_dynamic 'local''' 'remote''' 'lib rary'\n"},
+		{`go:cgo_import_static local`, "cgo_import_static local\n"},
+		{`go:cgo_import_static local'`, "cgo_import_static 'local'''\n"},
+		{`go:cgo_dynamic_linker "/path/"`, "cgo_dynamic_linker /path/\n"},
+		{`go:cgo_dynamic_linker "/p ath/"`, "cgo_dynamic_linker '/p ath/'\n"},
+		{`go:cgo_ldflag "arg"`, "cgo_ldflag arg\n"},
+		{`go:cgo_ldflag "a rg"`, "cgo_ldflag 'a rg'\n"},
+	}
+
+	for _, tt := range tests {
+		got := pragcgo(tt.in)
+		if got != tt.want {
+			t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, tt.want)
+			continue
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/logic_test.go b/src/cmd/compile/internal/gc/logic_test.go
new file mode 100644
index 0000000..78d2dd2
--- /dev/null
+++ b/src/cmd/compile/internal/gc/logic_test.go
@@ -0,0 +1,289 @@
+package gc
+
+import "testing"
+
+// Tests to make sure logic simplification rules are correct.
+
+func TestLogic64(t *testing.T) {
+	// test values to determine function equality
+	values := [...]int64{-1 << 63, 1<<63 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
+
+	// golden functions we use repeatedly
+	zero := func(x int64) int64 { return 0 }
+	id := func(x int64) int64 { return x }
+	or := func(x, y int64) int64 { return x | y }
+	and := func(x, y int64) int64 { return x & y }
+	y := func(x, y int64) int64 { return y }
+
+	for _, test := range [...]struct {
+		name   string
+		f      func(int64) int64
+		golden func(int64) int64
+	}{
+		{"x|x", func(x int64) int64 { return x | x }, id},
+		{"x|0", func(x int64) int64 { return x | 0 }, id},
+		{"x|-1", func(x int64) int64 { return x | -1 }, func(x int64) int64 { return -1 }},
+		{"x&x", func(x int64) int64 { return x & x }, id},
+		{"x&0", func(x int64) int64 { return x & 0 }, zero},
+		{"x&-1", func(x int64) int64 { return x & -1 }, id},
+		{"x^x", func(x int64) int64 { return x ^ x }, zero},
+		{"x^0", func(x int64) int64 { return x ^ 0 }, id},
+		{"x^-1", func(x int64) int64 { return x ^ -1 }, func(x int64) int64 { return ^x }},
+		{"x+0", func(x int64) int64 { return x + 0 }, id},
+		{"x-x", func(x int64) int64 { return x - x }, zero},
+		{"x*0", func(x int64) int64 { return x * 0 }, zero},
+		{"^^x", func(x int64) int64 { return ^^x }, id},
+	} {
+		for _, v := range values {
+			got := test.f(v)
+			want := test.golden(v)
+			if want != got {
+				t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
+			}
+		}
+	}
+	for _, test := range [...]struct {
+		name   string
+		f      func(int64, int64) int64
+		golden func(int64, int64) int64
+	}{
+		{"x|(x|y)", func(x, y int64) int64 { return x | (x | y) }, or},
+		{"x|(y|x)", func(x, y int64) int64 { return x | (y | x) }, or},
+		{"(x|y)|x", func(x, y int64) int64 { return (x | y) | x }, or},
+		{"(y|x)|x", func(x, y int64) int64 { return (y | x) | x }, or},
+		{"x&(x&y)", func(x, y int64) int64 { return x & (x & y) }, and},
+		{"x&(y&x)", func(x, y int64) int64 { return x & (y & x) }, and},
+		{"(x&y)&x", func(x, y int64) int64 { return (x & y) & x }, and},
+		{"(y&x)&x", func(x, y int64) int64 { return (y & x) & x }, and},
+		{"x^(x^y)", func(x, y int64) int64 { return x ^ (x ^ y) }, y},
+		{"x^(y^x)", func(x, y int64) int64 { return x ^ (y ^ x) }, y},
+		{"(x^y)^x", func(x, y int64) int64 { return (x ^ y) ^ x }, y},
+		{"(y^x)^x", func(x, y int64) int64 { return (y ^ x) ^ x }, y},
+		{"-(y-x)", func(x, y int64) int64 { return -(y - x) }, func(x, y int64) int64 { return x - y }},
+		{"(x+y)-x", func(x, y int64) int64 { return (x + y) - x }, y},
+		{"(y+x)-x", func(x, y int64) int64 { return (y + x) - x }, y},
+	} {
+		for _, v := range values {
+			for _, w := range values {
+				got := test.f(v, w)
+				want := test.golden(v, w)
+				if want != got {
+					t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
+				}
+			}
+		}
+	}
+}
+
+func TestLogic32(t *testing.T) {
+	// test values to determine function equality
+	values := [...]int32{-1 << 31, 1<<31 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
+
+	// golden functions we use repeatedly
+	zero := func(x int32) int32 { return 0 }
+	id := func(x int32) int32 { return x }
+	or := func(x, y int32) int32 { return x | y }
+	and := func(x, y int32) int32 { return x & y }
+	y := func(x, y int32) int32 { return y }
+
+	for _, test := range [...]struct {
+		name   string
+		f      func(int32) int32
+		golden func(int32) int32
+	}{
+		{"x|x", func(x int32) int32 { return x | x }, id},
+		{"x|0", func(x int32) int32 { return x | 0 }, id},
+		{"x|-1", func(x int32) int32 { return x | -1 }, func(x int32) int32 { return -1 }},
+		{"x&x", func(x int32) int32 { return x & x }, id},
+		{"x&0", func(x int32) int32 { return x & 0 }, zero},
+		{"x&-1", func(x int32) int32 { return x & -1 }, id},
+		{"x^x", func(x int32) int32 { return x ^ x }, zero},
+		{"x^0", func(x int32) int32 { return x ^ 0 }, id},
+		{"x^-1", func(x int32) int32 { return x ^ -1 }, func(x int32) int32 { return ^x }},
+		{"x+0", func(x int32) int32 { return x + 0 }, id},
+		{"x-x", func(x int32) int32 { return x - x }, zero},
+		{"x*0", func(x int32) int32 { return x * 0 }, zero},
+		{"^^x", func(x int32) int32 { return ^^x }, id},
+	} {
+		for _, v := range values {
+			got := test.f(v)
+			want := test.golden(v)
+			if want != got {
+				t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
+			}
+		}
+	}
+	for _, test := range [...]struct {
+		name   string
+		f      func(int32, int32) int32
+		golden func(int32, int32) int32
+	}{
+		{"x|(x|y)", func(x, y int32) int32 { return x | (x | y) }, or},
+		{"x|(y|x)", func(x, y int32) int32 { return x | (y | x) }, or},
+		{"(x|y)|x", func(x, y int32) int32 { return (x | y) | x }, or},
+		{"(y|x)|x", func(x, y int32) int32 { return (y | x) | x }, or},
+		{"x&(x&y)", func(x, y int32) int32 { return x & (x & y) }, and},
+		{"x&(y&x)", func(x, y int32) int32 { return x & (y & x) }, and},
+		{"(x&y)&x", func(x, y int32) int32 { return (x & y) & x }, and},
+		{"(y&x)&x", func(x, y int32) int32 { return (y & x) & x }, and},
+		{"x^(x^y)", func(x, y int32) int32 { return x ^ (x ^ y) }, y},
+		{"x^(y^x)", func(x, y int32) int32 { return x ^ (y ^ x) }, y},
+		{"(x^y)^x", func(x, y int32) int32 { return (x ^ y) ^ x }, y},
+		{"(y^x)^x", func(x, y int32) int32 { return (y ^ x) ^ x }, y},
+		{"-(y-x)", func(x, y int32) int32 { return -(y - x) }, func(x, y int32) int32 { return x - y }},
+		{"(x+y)-x", func(x, y int32) int32 { return (x + y) - x }, y},
+		{"(y+x)-x", func(x, y int32) int32 { return (y + x) - x }, y},
+	} {
+		for _, v := range values {
+			for _, w := range values {
+				got := test.f(v, w)
+				want := test.golden(v, w)
+				if want != got {
+					t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
+				}
+			}
+		}
+	}
+}
+
+func TestLogic16(t *testing.T) {
+	// test values to determine function equality
+	values := [...]int16{-1 << 15, 1<<15 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
+
+	// golden functions we use repeatedly
+	zero := func(x int16) int16 { return 0 }
+	id := func(x int16) int16 { return x }
+	or := func(x, y int16) int16 { return x | y }
+	and := func(x, y int16) int16 { return x & y }
+	y := func(x, y int16) int16 { return y }
+
+	for _, test := range [...]struct {
+		name   string
+		f      func(int16) int16
+		golden func(int16) int16
+	}{
+		{"x|x", func(x int16) int16 { return x | x }, id},
+		{"x|0", func(x int16) int16 { return x | 0 }, id},
+		{"x|-1", func(x int16) int16 { return x | -1 }, func(x int16) int16 { return -1 }},
+		{"x&x", func(x int16) int16 { return x & x }, id},
+		{"x&0", func(x int16) int16 { return x & 0 }, zero},
+		{"x&-1", func(x int16) int16 { return x & -1 }, id},
+		{"x^x", func(x int16) int16 { return x ^ x }, zero},
+		{"x^0", func(x int16) int16 { return x ^ 0 }, id},
+		{"x^-1", func(x int16) int16 { return x ^ -1 }, func(x int16) int16 { return ^x }},
+		{"x+0", func(x int16) int16 { return x + 0 }, id},
+		{"x-x", func(x int16) int16 { return x - x }, zero},
+		{"x*0", func(x int16) int16 { return x * 0 }, zero},
+		{"^^x", func(x int16) int16 { return ^^x }, id},
+	} {
+		for _, v := range values {
+			got := test.f(v)
+			want := test.golden(v)
+			if want != got {
+				t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
+			}
+		}
+	}
+	for _, test := range [...]struct {
+		name   string
+		f      func(int16, int16) int16
+		golden func(int16, int16) int16
+	}{
+		{"x|(x|y)", func(x, y int16) int16 { return x | (x | y) }, or},
+		{"x|(y|x)", func(x, y int16) int16 { return x | (y | x) }, or},
+		{"(x|y)|x", func(x, y int16) int16 { return (x | y) | x }, or},
+		{"(y|x)|x", func(x, y int16) int16 { return (y | x) | x }, or},
+		{"x&(x&y)", func(x, y int16) int16 { return x & (x & y) }, and},
+		{"x&(y&x)", func(x, y int16) int16 { return x & (y & x) }, and},
+		{"(x&y)&x", func(x, y int16) int16 { return (x & y) & x }, and},
+		{"(y&x)&x", func(x, y int16) int16 { return (y & x) & x }, and},
+		{"x^(x^y)", func(x, y int16) int16 { return x ^ (x ^ y) }, y},
+		{"x^(y^x)", func(x, y int16) int16 { return x ^ (y ^ x) }, y},
+		{"(x^y)^x", func(x, y int16) int16 { return (x ^ y) ^ x }, y},
+		{"(y^x)^x", func(x, y int16) int16 { return (y ^ x) ^ x }, y},
+		{"-(y-x)", func(x, y int16) int16 { return -(y - x) }, func(x, y int16) int16 { return x - y }},
+		{"(x+y)-x", func(x, y int16) int16 { return (x + y) - x }, y},
+		{"(y+x)-x", func(x, y int16) int16 { return (y + x) - x }, y},
+	} {
+		for _, v := range values {
+			for _, w := range values {
+				got := test.f(v, w)
+				want := test.golden(v, w)
+				if want != got {
+					t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
+				}
+			}
+		}
+	}
+}
+
+func TestLogic8(t *testing.T) {
+	// test values to determine function equality
+	values := [...]int8{-1 << 7, 1<<7 - 1, -4, -3, -2, -1, 0, 1, 2, 3, 4}
+
+	// golden functions we use repeatedly
+	zero := func(x int8) int8 { return 0 }
+	id := func(x int8) int8 { return x }
+	or := func(x, y int8) int8 { return x | y }
+	and := func(x, y int8) int8 { return x & y }
+	y := func(x, y int8) int8 { return y }
+
+	for _, test := range [...]struct {
+		name   string
+		f      func(int8) int8
+		golden func(int8) int8
+	}{
+		{"x|x", func(x int8) int8 { return x | x }, id},
+		{"x|0", func(x int8) int8 { return x | 0 }, id},
+		{"x|-1", func(x int8) int8 { return x | -1 }, func(x int8) int8 { return -1 }},
+		{"x&x", func(x int8) int8 { return x & x }, id},
+		{"x&0", func(x int8) int8 { return x & 0 }, zero},
+		{"x&-1", func(x int8) int8 { return x & -1 }, id},
+		{"x^x", func(x int8) int8 { return x ^ x }, zero},
+		{"x^0", func(x int8) int8 { return x ^ 0 }, id},
+		{"x^-1", func(x int8) int8 { return x ^ -1 }, func(x int8) int8 { return ^x }},
+		{"x+0", func(x int8) int8 { return x + 0 }, id},
+		{"x-x", func(x int8) int8 { return x - x }, zero},
+		{"x*0", func(x int8) int8 { return x * 0 }, zero},
+		{"^^x", func(x int8) int8 { return ^^x }, id},
+	} {
+		for _, v := range values {
+			got := test.f(v)
+			want := test.golden(v)
+			if want != got {
+				t.Errorf("[%s](%d)=%d, want %d", test.name, v, got, want)
+			}
+		}
+	}
+	for _, test := range [...]struct {
+		name   string
+		f      func(int8, int8) int8
+		golden func(int8, int8) int8
+	}{
+		{"x|(x|y)", func(x, y int8) int8 { return x | (x | y) }, or},
+		{"x|(y|x)", func(x, y int8) int8 { return x | (y | x) }, or},
+		{"(x|y)|x", func(x, y int8) int8 { return (x | y) | x }, or},
+		{"(y|x)|x", func(x, y int8) int8 { return (y | x) | x }, or},
+		{"x&(x&y)", func(x, y int8) int8 { return x & (x & y) }, and},
+		{"x&(y&x)", func(x, y int8) int8 { return x & (y & x) }, and},
+		{"(x&y)&x", func(x, y int8) int8 { return (x & y) & x }, and},
+		{"(y&x)&x", func(x, y int8) int8 { return (y & x) & x }, and},
+		{"x^(x^y)", func(x, y int8) int8 { return x ^ (x ^ y) }, y},
+		{"x^(y^x)", func(x, y int8) int8 { return x ^ (y ^ x) }, y},
+		{"(x^y)^x", func(x, y int8) int8 { return (x ^ y) ^ x }, y},
+		{"(y^x)^x", func(x, y int8) int8 { return (y ^ x) ^ x }, y},
+		{"-(y-x)", func(x, y int8) int8 { return -(y - x) }, func(x, y int8) int8 { return x - y }},
+		{"(x+y)-x", func(x, y int8) int8 { return (x + y) - x }, y},
+		{"(y+x)-x", func(x, y int8) int8 { return (y + x) - x }, y},
+	} {
+		for _, v := range values {
+			for _, w := range values {
+				got := test.f(v, w)
+				want := test.golden(v, w)
+				if want != got {
+					t.Errorf("[%s](%d,%d)=%d, want %d", test.name, v, w, got, want)
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/magic.go b/src/cmd/compile/internal/gc/magic.go
new file mode 100644
index 0000000..f8eb182
--- /dev/null
+++ b/src/cmd/compile/internal/gc/magic.go
@@ -0,0 +1,220 @@
+// 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
+
+// Transmogrify slow integer division into fast multiplication using magic.
+
+// 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
+}
+
+// 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
+}
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
new file mode 100644
index 0000000..b4df7ed
--- /dev/null
+++ b/src/cmd/compile/internal/gc/main.go
@@ -0,0 +1,933 @@
+// 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 run mkbuiltin.go
+
+package gc
+
+import (
+	"bufio"
+	"cmd/compile/internal/ssa"
+	"cmd/internal/obj"
+	"cmd/internal/sys"
+	"flag"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"path"
+	"runtime"
+	"strconv"
+	"strings"
+)
+
+var imported_unsafe bool
+
+var (
+	goos    string
+	goarch  string
+	goroot  string
+	buildid string
+)
+
+var (
+	Debug_append  int
+	Debug_closure 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
+	{"closure", &Debug_closure},       // print information about closure 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
+	{"export", &Debug_export},         // print export data
+}
+
+func usage() {
+	fmt.Printf("usage: compile [options] file.go...\n")
+	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("compile version %s%s%s\n", obj.Getgoversion(), sep, p)
+	os.Exit(0)
+}
+
+// supportsDynlink reports whether or not the code generator for the given
+// architecture supports the -shared and -dynlink flags.
+func supportsDynlink(arch *sys.Arch) bool {
+	return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
+}
+
+func Main() {
+	defer hidePanic()
+
+	goarch = obj.Getgoarch()
+
+	Ctxt = obj.Linknew(Thearch.LinkArch)
+	Ctxt.DiagFunc = Yyerror
+	bstdout = bufio.NewWriter(os.Stdout)
+	Ctxt.Bso = bstdout
+
+	localpkg = mkpkg("")
+	localpkg.Prefix = "\"\""
+	autopkg = mkpkg("")
+	autopkg.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
+	itabpkg = mkpkg("go.itab")
+	itabpkg.Name = "go.itab"
+	itabpkg.Prefix = "go.itab" // not go%2eitab
+
+	itablinkpkg = mkpkg("go.itablink")
+	itablinkpkg.Name = "go.itablink"
+	itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
+
+	trackpkg = mkpkg("go.track")
+	trackpkg.Name = "go.track"
+	trackpkg.Prefix = "go.track" // not go%2etrack
+
+	typepkg = mkpkg("type")
+	typepkg.Name = "type"
+
+	// pseudo-package used for map zero values
+	mappkg = mkpkg("go.map")
+	mappkg.Name = "go.map"
+	mappkg.Prefix = "go.map"
+
+	goroot = obj.Getgoroot()
+	goos = obj.Getgoos()
+
+	Nacl = goos == "nacl"
+	if Nacl {
+		flag_largemodel = true
+	}
+
+	flag.BoolVar(&compiling_runtime, "+", false, "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'])
+	flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
+	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("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'])
+	flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
+	flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
+	flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)")
+	flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`")
+	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)
+	flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
+	obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
+	obj.Flagcount("l", "disable inlining", &Debug['l'])
+	flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
+	obj.Flagcount("live", "debug liveness analysis", &debuglive)
+	obj.Flagcount("m", "print optimization decisions", &Debug['m'])
+	flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
+	flag.BoolVar(&newexport, "newexport", true, "use new export format") // TODO(gri) remove eventually (issue 15323)
+	flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
+	flag.StringVar(&outfile, "o", "", "write output to `file`")
+	flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
+	flag.BoolVar(&writearchive, "pack", false, "write package file instead of object file")
+	obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
+	flag.BoolVar(&flag_race, "race", false, "enable race detector")
+	obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
+	flag.StringVar(&Ctxt.LineHist.TrimPathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
+	flag.BoolVar(&safemode, "u", false, "reject unsafe code")
+	obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
+	obj.Flagcount("w", "debug type checking", &Debug['w'])
+	flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
+	obj.Flagcount("x", "debug lexer", &Debug['x'])
+	var flag_shared bool
+	var flag_dynlink bool
+	if supportsDynlink(Thearch.LinkArch.Arch) {
+		flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library")
+		flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
+	}
+	if Thearch.LinkArch.Family == sys.AMD64 {
+		flag.BoolVar(&flag_largemodel, "largemodel", false, "generate code that assumes a large memory model")
+	}
+	flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
+	flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
+	flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
+	flag.BoolVar(&ssaEnabled, "ssa", true, "use SSA backend to generate code")
+	obj.Flagparse(usage)
+
+	Ctxt.Flag_shared = flag_dynlink || flag_shared
+	Ctxt.Flag_dynlink = flag_dynlink
+	Ctxt.Flag_optimize = Debug['N'] == 0
+
+	Ctxt.Debugasm = int32(Debug['S'])
+	Ctxt.Debugvlog = int32(Debug['v'])
+
+	if flag.NArg() < 1 {
+		usage()
+	}
+
+	startProfile()
+
+	if flag_race {
+		racepkg = mkpkg("runtime/race")
+		racepkg.Name = "race"
+	}
+	if flag_msan {
+		msanpkg = mkpkg("runtime/msan")
+		msanpkg.Name = "msan"
+	}
+	if flag_race && flag_msan {
+		log.Fatal("cannot use both -race and -msan")
+	} else if flag_race || flag_msan {
+		instrumenting = true
+	}
+
+	// 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
+					}
+				}
+			}
+			// special case for ssa for now
+			if strings.HasPrefix(name, "ssa/") {
+				// expect form ssa/phase/flag
+				// e.g. -d=ssa/generic_cse/time
+				// _ in phase name also matches space
+				phase := name[4:]
+				flag := "debug" // default flag is debug
+				if i := strings.Index(phase, "/"); i >= 0 {
+					flag = phase[i+1:]
+					phase = phase[:i]
+				}
+				err := ssa.PhaseOption(phase, flag, val)
+				if err != "" {
+					log.Fatalf(err)
+				}
+				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()
+	Widthint = Thearch.LinkArch.IntSize
+	Widthptr = Thearch.LinkArch.PtrSize
+	Widthreg = Thearch.LinkArch.RegSize
+
+	initUniverse()
+
+	blockgen = 1
+	dclcontext = PEXTERN
+	nerrors = 0
+	lexlineno = 1
+
+	loadsys()
+
+	for _, infile = range flag.Args() {
+		if trace && Debug['x'] != 0 {
+			fmt.Printf("--- %s ---\n", infile)
+		}
+
+		linehistpush(infile)
+
+		f, err := os.Open(infile)
+		if err != nil {
+			fmt.Printf("open %s: %v\n", infile, err)
+			errorexit()
+		}
+		bin := bufio.NewReader(f)
+
+		// Skip initial BOM if present.
+		if r, _, _ := bin.ReadRune(); r != BOM {
+			bin.UnreadRune()
+		}
+
+		block = 1
+		iota_ = -1000000
+
+		imported_unsafe = false
+
+		parse_file(bin)
+		if nsyntaxerrors != 0 {
+			errorexit()
+		}
+
+		// Instead of converting EOF into '\n' in getc and count it as an extra line
+		// for the line history to work, and which then has to be corrected elsewhere,
+		// just add a line here.
+		lexlineno++
+
+		linehistpop()
+		f.Close()
+	}
+
+	testdclstack()
+	mkpackage(localpkg.Name) // final import not used checks
+	finishUniverse()
+
+	typecheckok = true
+	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()
+
+	// Don't use range--typecheck can add closures to xtop.
+	for i := 0; i < len(xtop); i++ {
+		if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 {
+			xtop[i] = typecheck(xtop[i], Etop)
+		}
+	}
+
+	// Phase 2: Variable assignments.
+	//   To check interface assignments, depends on phase 1.
+
+	// Don't use range--typecheck can add closures to xtop.
+	for i := 0; i < len(xtop); i++ {
+		if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 {
+			xtop[i] = typecheck(xtop[i], Etop)
+		}
+	}
+	resumecheckwidth()
+
+	// Phase 3: Type check function bodies.
+	// Don't use range--typecheck can add closures to xtop.
+	for i := 0; i < len(xtop); i++ {
+		if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE {
+			Curfn = xtop[i]
+			decldepth = 1
+			saveerrors()
+			typecheckslice(Curfn.Nbody.Slice(), Etop)
+			checkreturn(Curfn)
+			if nerrors != 0 {
+				Curfn.Nbody.Set(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 _, n := range xtop {
+		if n.Op == ODCLFUNC && n.Func.Closure != nil {
+			Curfn = n
+			capturevars(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 _, n := range importlist {
+			if n.Func.Inl.Len() != 0 {
+				saveerrors()
+				typecheckinl(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 []*Node, recursive bool) {
+			for _, n := range list {
+				if n.Op == ODCLFUNC {
+					caninl(n)
+					inlcalls(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 _, n := range xtop {
+		if n.Op == ODCLFUNC && n.Func.Closure != nil {
+			Curfn = n
+			transformclosure(n)
+		}
+	}
+
+	Curfn = nil
+
+	// Phase 8: Compile top level functions.
+	// Don't use range--walk can add functions to xtop.
+	for i := 0; i < len(xtop); i++ {
+		if xtop[i].Op == ODCLFUNC {
+			funccompile(xtop[i])
+		}
+	}
+
+	if nsavederrors+nerrors == 0 {
+		fninit(xtop)
+	}
+
+	if compiling_runtime {
+		checknowritebarrierrec()
+	}
+
+	// Phase 9: Check external declarations.
+	for i, n := range externdcl {
+		if n.Op == ONAME {
+			externdcl[i] = typecheck(externdcl[i], 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 *bufio.Reader, 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 *bufio.Reader) bool {
+	// archive header
+	p, err := b.ReadString('\n')
+	if err != nil {
+		log.Fatalf("reading input: %v", err)
+	}
+	if p != "!<arch>\n" {
+		return false
+	}
+
+	// package export block should be first
+	sz := arsize(b, "__.PKGDEF")
+	return sz > 0
+}
+
+var idirs []string
+
+func addidir(dir string) {
+	if dir != "" {
+		idirs = append(idirs, dir)
+	}
+}
+
+func isDriveLetter(b byte) bool {
+	return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
+}
+
+// is this path a local name?  begins with ./ or ../ or /
+func islocalname(name string) bool {
+	return strings.HasPrefix(name, "/") ||
+		runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(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 || nolocalimports {
+			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 _, err := os.Stat(file); err == nil {
+			return file, true
+		}
+		file = fmt.Sprintf("%s.o", name)
+		if _, err := os.Stat(file); err == nil {
+			return file, true
+		}
+		return "", false
+	}
+
+	// local imports should be canonicalized already.
+	// don't want to see "encoding/../encoding/base64"
+	// as different from "encoding/base64".
+	if q := path.Clean(name); q != name {
+		Yyerror("non-canonical import path %q (should be %q)", name, q)
+		return "", false
+	}
+
+	for _, dir := range idirs {
+		file = fmt.Sprintf("%s/%s.a", dir, name)
+		if _, err := os.Stat(file); err == nil {
+			return file, true
+		}
+		file = fmt.Sprintf("%s/%s.o", dir, name)
+		if _, err := os.Stat(file); err == nil {
+			return file, true
+		}
+	}
+
+	if goroot != "" {
+		suffix := ""
+		suffixsep := ""
+		if flag_installsuffix != "" {
+			suffixsep = "_"
+			suffix = flag_installsuffix
+		} else if flag_race {
+			suffixsep = "_"
+			suffix = "race"
+		} else if flag_msan {
+			suffixsep = "_"
+			suffix = "msan"
+		}
+
+		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", goroot, goos, goarch, suffixsep, suffix, name)
+		if _, err := os.Stat(file); err == nil {
+			return file, true
+		}
+		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name)
+		if _, err := os.Stat(file); err == nil {
+			return file, true
+		}
+	}
+
+	return "", false
+}
+
+// loadsys loads the definitions for the low-level runtime and unsafe functions,
+// so that the compiler can generate calls to them,
+// but does not make the names "runtime" or "unsafe" visible as packages.
+func loadsys() {
+	if Debug['A'] != 0 {
+		return
+	}
+
+	block = 1
+	iota_ = -1000000
+	incannedimport = 1
+
+	// The first byte in the binary export format is a 'c' or 'd'
+	// specifying the encoding format. We could just check that
+	// byte, but this is a perhaps more robust. Also, it is not
+	// speed-critical.
+	// TODO(gri) simplify once textual export format has gone
+	if strings.HasPrefix(runtimeimport, "package") {
+		// textual export format
+		importpkg = Runtimepkg
+		parse_import(bufio.NewReader(strings.NewReader(runtimeimport)), nil)
+		importpkg = unsafepkg
+		parse_import(bufio.NewReader(strings.NewReader(unsafeimport)), nil)
+	} else {
+		// binary export format
+		importpkg = Runtimepkg
+		Import(bufio.NewReader(strings.NewReader(runtimeimport)))
+		importpkg = unsafepkg
+		Import(bufio.NewReader(strings.NewReader(unsafeimport)))
+	}
+
+	importpkg = nil
+	incannedimport = 0
+}
+
+func importfile(f *Val, indent []byte) {
+	if importpkg != nil {
+		Fatalf("importpkg not nil")
+	}
+
+	path_, ok := f.U.(string)
+	if !ok {
+		Yyerror("import statement not a string")
+		return
+	}
+
+	if len(path_) == 0 {
+		Yyerror("import path is empty")
+		return
+	}
+
+	if isbadimport(path_) {
+		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 path_ == "main" {
+		Yyerror("cannot import \"main\"")
+		errorexit()
+	}
+
+	if myimportpath != "" && path_ == myimportpath {
+		Yyerror("import %q while compiling that package (import cycle)", path_)
+		errorexit()
+	}
+
+	if mapped, ok := importMap[path_]; ok {
+		path_ = mapped
+	}
+
+	if path_ == "unsafe" {
+		if safemode {
+			Yyerror("cannot import package unsafe")
+			errorexit()
+		}
+
+		importpkg = unsafepkg
+		imported_unsafe = true
+		return
+	}
+
+	if islocalname(path_) {
+		if path_[0] == '/' {
+			Yyerror("import path cannot be absolute path")
+			return
+		}
+
+		prefix := Ctxt.Pathname
+		if localimport != "" {
+			prefix = localimport
+		}
+		path_ = path.Join(prefix, path_)
+
+		if isbadimport(path_) {
+			return
+		}
+	}
+
+	file, found := findpkg(path_)
+	if !found {
+		Yyerror("can't find import: %q", path_)
+		errorexit()
+	}
+
+	importpkg = mkpkg(path_)
+
+	if importpkg.Imported {
+		return
+	}
+
+	importpkg.Imported = true
+
+	impf, err := os.Open(file)
+	if err != nil {
+		Yyerror("can't open import: %q: %v", path_, err)
+		errorexit()
+	}
+	defer impf.Close()
+	imp := bufio.NewReader(impf)
+
+	if strings.HasSuffix(file, ".a") {
+		if !skiptopkgdef(imp) {
+			Yyerror("import %s: not a package file", file)
+			errorexit()
+		}
+	}
+
+	// check object header
+	p, err := imp.ReadString('\n')
+	if err != nil {
+		log.Fatalf("reading input: %v", err)
+	}
+	if len(p) > 0 {
+		p = p[:len(p)-1]
+	}
+
+	if p != "empty archive" {
+		if !strings.HasPrefix(p, "go object ") {
+			Yyerror("import %s: not a go object file: %s", file, p)
+			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()
+		}
+	}
+
+	// process header lines
+	for {
+		p, err = imp.ReadString('\n')
+		if err != nil {
+			log.Fatalf("reading input: %v", err)
+		}
+		if p == "\n" {
+			break // header ends with blank line
+		}
+		if strings.HasPrefix(p, "safe") {
+			importpkg.Safe = true
+			break // ok to ignore rest
+		}
+	}
+
+	// assume files move (get installed)
+	// so don't record the full path.
+	linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
+
+	// In the importfile, if we find:
+	// $$\n  (old format): position the input right after $$\n and return
+	// $$B\n (new format): import directly, then feed the lexer a dummy statement
+
+	// look for $$
+	var c byte
+	for {
+		c, err = imp.ReadByte()
+		if err != nil {
+			break
+		}
+		if c == '$' {
+			c, err = imp.ReadByte()
+			if c == '$' || err != nil {
+				break
+			}
+		}
+	}
+
+	// get character after $$
+	if err == nil {
+		c, _ = imp.ReadByte()
+	}
+
+	switch c {
+	case '\n':
+		// old export format
+		parse_import(imp, indent)
+
+	case 'B':
+		// new export format
+		if Debug_export != 0 {
+			fmt.Printf("importing %s (%s)\n", path_, file)
+		}
+		imp.ReadByte() // skip \n after $$B
+		Import(imp)
+
+	default:
+		Yyerror("no import in %q", path_)
+		errorexit()
+	}
+
+	if safemode && !importpkg.Safe {
+		Yyerror("cannot import unsafe package %q", importpkg.Path)
+	}
+}
+
+func pkgnotused(lineno int32, 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(lineno, "imported and not used: %q", path)
+	} else {
+		yyerrorl(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(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(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 runtime.GOOS == "windows" {
+			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 {
+			suffix = ".a"
+		}
+		outfile = p + suffix
+	}
+}
diff --git a/src/cmd/compile/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go
index b1e4458..58cbd24 100644
--- a/src/cmd/compile/internal/gc/mkbuiltin.go
+++ b/src/cmd/compile/internal/gc/mkbuiltin.go
@@ -4,95 +4,110 @@
 
 // +build ignore
 
-// Generate builtin.go from builtin/runtime.go and builtin/unsafe.go
-// (passed as arguments on the command line by a go:generate comment).
+// Generate builtin.go from builtin/runtime.go and builtin/unsafe.go.
 // Run this after changing builtin/runtime.go and builtin/unsafe.go
 // or after changing the export metadata format in the compiler.
 // Either way, you need to have a working compiler binary first.
+// See bexport.go for how to make an export metadata format change.
 package main
 
 import (
-	"bufio"
+	"bytes"
+	"flag"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"log"
 	"os"
 	"os/exec"
-	"strings"
 )
 
+var stdout = flag.Bool("stdout", false, "write to stdout instead of builtin.go")
+
 func main() {
-	f, err := os.Create("builtin.go")
-	if err != nil {
-		log.Fatal(err)
-	}
-	defer f.Close()
-	w := bufio.NewWriter(f)
+	flag.Parse()
 
-	fmt.Fprintln(w, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT")
-	fmt.Fprintln(w, "")
-	fmt.Fprintln(w, "package gc")
+	var b bytes.Buffer
+	fmt.Fprintln(&b, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT")
+	fmt.Fprintln(&b, "")
+	fmt.Fprintln(&b, "package gc")
 
-	for _, name := range os.Args[1:] {
-		mkbuiltin(w, name)
-	}
+	mkbuiltin(&b, "runtime")
+	mkbuiltin(&b, "unsafe")
 
-	if err := w.Flush(); err != nil {
+	var err error
+	if *stdout {
+		_, err = os.Stdout.Write(b.Bytes())
+	} else {
+		err = ioutil.WriteFile("builtin.go", b.Bytes(), 0666)
+	}
+	if err != nil {
 		log.Fatal(err)
 	}
 }
 
-// Compile .go file, import data from .6 file, and write Go string version.
+// Compile .go file, import data from .o 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 {
+	args := []string{"tool", "compile", "-A"}
+	if name == "runtime" {
+		args = append(args, "-u")
+	}
+	args = append(args, "builtin/"+name+".go")
+
+	if err := exec.Command("go", args...).Run(); err != nil {
 		log.Fatal(err)
 	}
 	obj := name + ".o"
 	defer os.Remove(obj)
 
-	r, err := os.Open(obj)
+	b, err := ioutil.ReadFile(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
+	// Look for $$B that introduces binary export data.
+	textual := false // TODO(gri) remove once we switched to binary export format
+	i := bytes.Index(b, []byte("\n$$B\n"))
+	if i < 0 {
+		// Look for $$ that introduces textual export data.
+		i = bytes.Index(b, []byte("\n$$\n"))
+		if i < 0 {
+			log.Fatal("did not find beginning of export data")
 		}
+		textual = true
+		i-- // textual data doesn't have B
 	}
-	log.Fatal("did not find beginning of imports")
+	b = b[i+5:]
 
-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
+	// Look for $$ that closes export data.
+	i = bytes.Index(b, []byte("\n$$\n"))
+	if i < 0 {
+		log.Fatal("did not find end of export data")
+	}
+	b = b[:i+4]
+
+	// Process and reformat export data.
+	fmt.Fprintf(w, "\nconst %simport = \"\"", name)
+	if textual {
+		for _, p := range bytes.SplitAfter(b, []byte("\n")) {
+			// Chop leading white space.
+			p = bytes.TrimLeft(p, " \t")
+			if len(p) == 0 {
+				continue
+			}
+
+			fmt.Fprintf(w, " +\n\t%q", p)
 		}
-
-		// 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
+	} else {
+		const n = 40 // number of bytes per line
+		for len(b) > 0 {
+			i := len(b)
+			if i > n {
+				i = n
+			}
+			fmt.Fprintf(w, " +\n\t%q", b[:i])
+			b = b[i:]
 		}
-
-		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")
+	fmt.Fprintf(w, "\n")
 }
diff --git a/src/cmd/compile/internal/gc/mparith2.go b/src/cmd/compile/internal/gc/mparith2.go
deleted file mode 100644
index 28c3a00..0000000
--- a/src/cmd/compile/internal/gc/mparith2.go
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-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 {
-	// avoid converting huge floating-point numbers to integers
-	// (2*Mpprec is large enough to permit all tests to pass)
-	if b.Val.MantExp(nil) > 2*Mpprec {
-		return -1
-	}
-
-	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 {
-		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
deleted file mode 100644
index 9bcfda7..0000000
--- a/src/cmd/compile/internal/gc/mparith3.go
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
-	"cmd/compile/internal/big"
-	"cmd/internal/obj"
-	"fmt"
-	"math"
-)
-
-/// 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 + 0 // avoid -0 (should not be needed, but be conservative)
-}
-
-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 + 0 // avoid -0 (should not be needed, but be conservative)
-}
-
-func Mpmovecflt(a *Mpflt, c float64) {
-	if Mpdebug {
-		fmt.Printf("\nconst %g", c)
-	}
-
-	// convert -0 to 0
-	if c == 0 {
-		c = 0
-	}
-	a.Val.SetFloat64(c)
-
-	if Mpdebug {
-		fmt.Printf(" = %v\n", a)
-	}
-}
-
-func mpnegflt(a *Mpflt) {
-	// avoid -0
-	if a.Val.Sign() != 0 {
-		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:]
-	}
-
-	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.SetFloat64(0)
-		return
-	}
-
-	if f.IsInf() {
-		Yyerror("constant too large: %s", as)
-		a.Val.SetFloat64(0)
-		return
-	}
-
-	// -0 becomes 0
-	if f.Sign() == 0 && f.Signbit() {
-		a.Val.SetFloat64(0)
-	}
-}
-
-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 f.Sign() < 0 {
-		sign = "-"
-		f = new(big.Float).Abs(f)
-	} else if flag&obj.FmtSign != 0 {
-		sign = "+"
-	}
-
-	// Don't try to convert infinities (will not terminate).
-	if f.IsInf() {
-		return sign + "Inf"
-	}
-
-	// Use exact fmt formatting if in float64 range (common case):
-	// proceed if f doesn't underflow to 0 or overflow to inf.
-	if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !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.
-	// f = mant * 2**exp
-	var mant big.Float
-	exp := f.MantExp(&mant) // 0.5 <= mant < 1.0
-
-	// approximate float64 mantissa m and decimal exponent d
-	// f ~ m * 10**d
-	m, _ := mant.Float64()                     // 0.5 <= m < 1.0
-	d := float64(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))
-
-	// ensure 1 <= m < 10
-	switch {
-	case m < 1-0.5e-6:
-		// The %.6g format below rounds m to 5 digits after the
-		// decimal point. Make sure that m*10 < 10 even after
-		// rounding up: m*10 + 0.5e-5 < 10 => m < 1 - 0.5e6.
-		m *= 10
-		e--
-	case m >= 10:
-		m /= 10
-		e++
-	}
-
-	return fmt.Sprintf("%s%.6ge%+d", sign, m, e)
-}
diff --git a/src/cmd/compile/internal/gc/mpfloat.go b/src/cmd/compile/internal/gc/mpfloat.go
new file mode 100644
index 0000000..a0f15a9
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mpfloat.go
@@ -0,0 +1,269 @@
+// 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"
+	"fmt"
+	"math"
+)
+
+// implements float arithmetic
+
+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
+)
+
+// Mpflt represents a floating-point constant.
+type Mpflt struct {
+	Val big.Float
+}
+
+// Mpcplx represents a complex constant.
+type Mpcplx struct {
+	Real Mpflt
+	Imag Mpflt
+}
+
+func newMpflt() *Mpflt {
+	var a Mpflt
+	a.Val.SetPrec(Mpprec)
+	return &a
+}
+
+func (a *Mpflt) SetInt(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 (a *Mpflt) Set(b *Mpflt) {
+	a.Val.Set(&b.Val)
+}
+
+func (a *Mpflt) Add(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 (a *Mpflt) AddFloat64(c float64) {
+	var b Mpflt
+
+	b.SetFloat64(c)
+	a.Add(&b)
+}
+
+func (a *Mpflt) Sub(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 (a *Mpflt) Mul(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 (a *Mpflt) MulFloat64(c float64) {
+	var b Mpflt
+
+	b.SetFloat64(c)
+	a.Mul(&b)
+}
+
+func (a *Mpflt) Quo(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 (a *Mpflt) Cmp(b *Mpflt) int {
+	return a.Val.Cmp(&b.Val)
+}
+
+func (a *Mpflt) CmpFloat64(c float64) int {
+	if c == 0 {
+		return a.Val.Sign() // common case shortcut
+	}
+	return a.Val.Cmp(big.NewFloat(c))
+}
+
+func (a *Mpflt) Float64() float64 {
+	x, _ := a.Val.Float64()
+
+	// check for overflow
+	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
+		Yyerror("mpgetflt ovf")
+	}
+
+	return x + 0 // avoid -0 (should not be needed, but be conservative)
+}
+
+func (a *Mpflt) Float32() float64 {
+	x32, _ := a.Val.Float32()
+	x := float64(x32)
+
+	// check for overflow
+	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
+		Yyerror("mpgetflt32 ovf")
+	}
+
+	return x + 0 // avoid -0 (should not be needed, but be conservative)
+}
+
+func (a *Mpflt) SetFloat64(c float64) {
+	if Mpdebug {
+		fmt.Printf("\nconst %g", c)
+	}
+
+	// convert -0 to 0
+	if c == 0 {
+		c = 0
+	}
+	a.Val.SetFloat64(c)
+
+	if Mpdebug {
+		fmt.Printf(" = %v\n", a)
+	}
+}
+
+func (a *Mpflt) Neg() {
+	// avoid -0
+	if a.Val.Sign() != 0 {
+		a.Val.Neg(&a.Val)
+	}
+}
+
+//
+// floating point input
+// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
+//
+func (a *Mpflt) SetString(as string) {
+	for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
+		as = as[1:]
+	}
+
+	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.SetFloat64(0)
+		return
+	}
+
+	if f.IsInf() {
+		Yyerror("constant too large: %s", as)
+		a.Val.SetFloat64(0)
+		return
+	}
+
+	// -0 becomes 0
+	if f.Sign() == 0 && f.Signbit() {
+		a.Val.SetFloat64(0)
+	}
+}
+
+func (f *Mpflt) String() string {
+	return fconv(f, 0)
+}
+
+func fconv(fvp *Mpflt, flag FmtFlag) string {
+	if flag&FmtSharp == 0 {
+		return fvp.Val.Text('b', 0)
+	}
+
+	// use decimal format for error messages
+
+	// determine sign
+	f := &fvp.Val
+	var sign string
+	if f.Sign() < 0 {
+		sign = "-"
+		f = new(big.Float).Abs(f)
+	} else if flag&FmtSign != 0 {
+		sign = "+"
+	}
+
+	// Don't try to convert infinities (will not terminate).
+	if f.IsInf() {
+		return sign + "Inf"
+	}
+
+	// Use exact fmt formatting if in float64 range (common case):
+	// proceed if f doesn't underflow to 0 or overflow to inf.
+	if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !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.
+	// f = mant * 2**exp
+	var mant big.Float
+	exp := f.MantExp(&mant) // 0.5 <= mant < 1.0
+
+	// approximate float64 mantissa m and decimal exponent d
+	// f ~ m * 10**d
+	m, _ := mant.Float64()                     // 0.5 <= m < 1.0
+	d := float64(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))
+
+	// ensure 1 <= m < 10
+	switch {
+	case m < 1-0.5e-6:
+		// The %.6g format below rounds m to 5 digits after the
+		// decimal point. Make sure that m*10 < 10 even after
+		// rounding up: m*10 + 0.5e-5 < 10 => m < 1 - 0.5e6.
+		m *= 10
+		e--
+	case m >= 10:
+		m /= 10
+		e++
+	}
+
+	return fmt.Sprintf("%s%.6ge%+d", sign, m, e)
+}
diff --git a/src/cmd/compile/internal/gc/mpint.go b/src/cmd/compile/internal/gc/mpint.go
new file mode 100644
index 0000000..fe37baa
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mpint.go
@@ -0,0 +1,309 @@
+// 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"
+	"fmt"
+)
+
+// implements integer arithmetic
+
+// 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
+}
+
+func (a *Mpint) SetOverflow() {
+	a.Val.SetUint64(1) // avoid spurious div-zero errors
+	a.Ovf = true
+}
+
+func (a *Mpint) checkOverflow(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 {
+		a.SetOverflow()
+	}
+	return a.Ovf
+}
+
+func (a *Mpint) Set(b *Mpint) {
+	a.Val.Set(&b.Val)
+}
+
+func (a *Mpint) SetFloat(b *Mpflt) int {
+	// avoid converting huge floating-point numbers to integers
+	// (2*Mpprec is large enough to permit all tests to pass)
+	if b.Val.MantExp(nil) > 2*Mpprec {
+		return -1
+	}
+
+	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 (a *Mpint) Add(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpaddfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	a.Val.Add(&a.Val, &b.Val)
+
+	if a.checkOverflow(0) {
+		Yyerror("constant addition overflow")
+	}
+}
+
+func (a *Mpint) Sub(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpsubfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	a.Val.Sub(&a.Val, &b.Val)
+
+	if a.checkOverflow(0) {
+		Yyerror("constant subtraction overflow")
+	}
+}
+
+func (a *Mpint) Mul(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpmulfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	a.Val.Mul(&a.Val, &b.Val)
+
+	if a.checkOverflow(0) {
+		Yyerror("constant multiplication overflow")
+	}
+}
+
+func (a *Mpint) Quo(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpdivfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	a.Val.Quo(&a.Val, &b.Val)
+
+	if a.checkOverflow(0) {
+		// can only happen for div-0 which should be checked elsewhere
+		Yyerror("constant division overflow")
+	}
+}
+
+func (a *Mpint) Rem(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpmodfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	a.Val.Rem(&a.Val, &b.Val)
+
+	if a.checkOverflow(0) {
+		// should never happen
+		Yyerror("constant modulo overflow")
+	}
+}
+
+func (a *Mpint) Or(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mporfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	a.Val.Or(&a.Val, &b.Val)
+}
+
+func (a *Mpint) And(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpandfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	a.Val.And(&a.Val, &b.Val)
+}
+
+func (a *Mpint) AndNot(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpandnotfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	a.Val.AndNot(&a.Val, &b.Val)
+}
+
+func (a *Mpint) Xor(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpxorfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	a.Val.Xor(&a.Val, &b.Val)
+}
+
+func (a *Mpint) Lsh(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mplshfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	s := b.Int64()
+	if s < 0 || s >= Mpprec {
+		msg := "shift count too large"
+		if s < 0 {
+			msg = "invalid negative shift count"
+		}
+		Yyerror("%s: %d", msg, s)
+		a.SetInt64(0)
+		return
+	}
+
+	if a.checkOverflow(int(s)) {
+		Yyerror("constant shift overflow")
+		return
+	}
+	a.Val.Lsh(&a.Val, uint(s))
+}
+
+func (a *Mpint) Rsh(b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mprshfixfix")
+		}
+		a.SetOverflow()
+		return
+	}
+
+	s := b.Int64()
+	if s < 0 {
+		Yyerror("invalid negative shift count: %d", s)
+		if a.Val.Sign() < 0 {
+			a.SetInt64(-1)
+		} else {
+			a.SetInt64(0)
+		}
+		return
+	}
+
+	a.Val.Rsh(&a.Val, uint(s))
+}
+
+func (a *Mpint) Cmp(b *Mpint) int {
+	return a.Val.Cmp(&b.Val)
+}
+
+func (a *Mpint) CmpInt64(c int64) int {
+	if c == 0 {
+		return a.Val.Sign() // common case shortcut
+	}
+	return a.Val.Cmp(big.NewInt(c))
+}
+
+func (a *Mpint) Neg() {
+	a.Val.Neg(&a.Val)
+}
+
+func (a *Mpint) Int64() int64 {
+	if a.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("constant overflow")
+		}
+		return 0
+	}
+
+	return a.Val.Int64()
+}
+
+func (a *Mpint) SetInt64(c int64) {
+	a.Val.SetInt64(c)
+}
+
+func (a *Mpint) SetString(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 a.checkOverflow(0) {
+		Yyerror("constant too large: %s", as)
+	}
+}
+
+func (x *Mpint) String() string {
+	return bconv(x, 0)
+}
+
+func bconv(xval *Mpint, flag FmtFlag) string {
+	if flag&FmtSharp != 0 {
+		return fmt.Sprintf("%#x", &xval.Val)
+	}
+	return xval.Val.String()
+}
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index 66549be..b5c06d1 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -5,8 +5,11 @@
 package gc
 
 import (
+	"cmd/internal/bio"
 	"cmd/internal/obj"
+	"crypto/sha256"
 	"fmt"
+	"io"
 	"strconv"
 )
 
@@ -19,9 +22,36 @@ 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))
 }
 
+// These modes say which kind of object file to generate.
+// The default use of the toolchain is to set both bits,
+// generating a combined compiler+linker object, one that
+// serves to describe the package to both the compiler and the linker.
+// In fact the compiler and linker read nearly disjoint sections of
+// that file, though, so in a distributed build setting it can be more
+// efficient to split the output into two files, supplying the compiler
+// object only to future compilations and the linker object only to
+// future links.
+//
+// By default a combined object is written, but if -linkobj is specified
+// on the command line then the default -o output is a compiler object
+// and the -linkobj output is a linker object.
+const (
+	modeCompilerObj = 1 << iota
+	modeLinkerObj
+)
+
 func dumpobj() {
+	if linkobj == "" {
+		dumpobj1(outfile, modeCompilerObj|modeLinkerObj)
+	} else {
+		dumpobj1(outfile, modeCompilerObj)
+		dumpobj1(linkobj, modeLinkerObj)
+	}
+}
+
+func dumpobj1(outfile string, mode int) {
 	var err error
-	bout, err = obj.Bopenw(outfile)
+	bout, err = bio.Create(outfile)
 	if err != nil {
 		Flusherrors()
 		fmt.Printf("can't create %s: %v\n", outfile, err)
@@ -30,36 +60,63 @@ func dumpobj() {
 
 	startobj := int64(0)
 	var arhdr [ArhdrSize]byte
-	if writearchive != 0 {
-		obj.Bwritestring(bout, "!<arch>\n")
+	if writearchive {
+		bout.WriteString("!<arch>\n")
 		arhdr = [ArhdrSize]byte{}
 		bout.Write(arhdr[:])
-		startobj = obj.Boffset(bout)
+		startobj = bout.Offset()
+	}
+
+	printheader := func() {
+		fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
+		if buildid != "" {
+			fmt.Fprintf(bout, "build id %q\n", buildid)
+		}
+		if localpkg.Name == "main" {
+			fmt.Fprintf(bout, "main\n")
+		}
+		if safemode {
+			fmt.Fprintf(bout, "safe\n")
+		} else {
+			fmt.Fprintf(bout, "----\n") // room for some other tool to write "safe"
+		}
+		fmt.Fprintf(bout, "\n") // header ends with blank line
 	}
 
-	fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
-	dumpexport()
+	printheader()
+
+	if mode&modeCompilerObj != 0 {
+		dumpexport()
+	}
 
-	if writearchive != 0 {
+	if writearchive {
 		bout.Flush()
-		size := obj.Boffset(bout) - startobj
+		size := bout.Offset() - startobj
 		if size&1 != 0 {
-			obj.Bputc(bout, 0)
+			bout.WriteByte(0)
 		}
-		obj.Bseek(bout, startobj-ArhdrSize, 0)
+		bout.Seek(startobj-ArhdrSize, 0)
 		formathdr(arhdr[:], "__.PKGDEF", size)
 		bout.Write(arhdr[:])
 		bout.Flush()
+		bout.Seek(startobj+size+(size&1), 0)
+	}
 
-		obj.Bseek(bout, startobj+size+(size&1), 0)
+	if mode&modeLinkerObj == 0 {
+		bout.Close()
+		return
+	}
+
+	if writearchive {
+		// start object file
 		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())
+		startobj = bout.Offset()
+		printheader()
 	}
 
 	if pragcgobuf != "" {
-		if writearchive != 0 {
+		if writearchive {
 			// write empty export section; must be before cgo section
 			fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
 		}
@@ -84,21 +141,26 @@ func dumpobj() {
 	dumpglobls()
 	externdcl = tmp
 
+	if zerosize > 0 {
+		zero := Pkglookup("zero", mappkg)
+		ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA)
+	}
+
 	dumpdata()
-	obj.Writeobjdirect(Ctxt, bout)
+	obj.Writeobjdirect(Ctxt, bout.Writer)
 
-	if writearchive != 0 {
+	if writearchive {
 		bout.Flush()
-		size := obj.Boffset(bout) - startobj
+		size := bout.Offset() - startobj
 		if size&1 != 0 {
-			obj.Bputc(bout, 0)
+			bout.WriteByte(0)
 		}
-		obj.Bseek(bout, startobj-ArhdrSize, 0)
+		bout.Seek(startobj-ArhdrSize, 0)
 		formathdr(arhdr[:], "_go_.o", size)
 		bout.Write(arhdr[:])
 	}
 
-	obj.Bterm(bout)
+	bout.Close()
 }
 
 func dumpglobls() {
@@ -130,11 +192,6 @@ func dumpglobls() {
 	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
@@ -157,12 +214,16 @@ func Linksym(s *Sym) *obj.LSym {
 }
 
 func duintxx(s *Sym, off int, v uint64, wid int) int {
+	return duintxxLSym(Linksym(s), off, v, wid)
+}
+
+func duintxxLSym(s *obj.LSym, 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)))
+	return int(obj.Setuintxx(Ctxt, s, int64(off), v, int64(wid)))
 }
 
 func duint8(s *Sym, off int, v uint8) int {
@@ -181,61 +242,59 @@ func duintptr(s *Sym, off int, v uint64) int {
 	return duintxx(s, off, v, Widthptr)
 }
 
-var stringsym_gen int
+// stringConstantSyms holds the pair of symbols we create for a
+// constant string.
+type stringConstantSyms struct {
+	hdr  *obj.LSym // string header
+	data *obj.LSym // actual string data
+}
+
+// stringConstants maps from the symbol name we use for the string
+// contents to the pair of linker symbols for that string.
+var stringConstants = make(map[string]stringConstantSyms, 100)
 
-func stringsym(s string) (hdr, data *Sym) {
+func stringsym(s string) (hdr, data *obj.LSym) {
 	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
+		// Huge strings are hashed to avoid long names in object files.
+		// Indulge in some paranoia by writing the length of s, too,
+		// as protection against length extension attacks.
+		h := sha256.New()
+		io.WriteString(h, s)
+		symname = fmt.Sprintf(".gostring.%d.%x", len(s), h.Sum(nil))
 	} else {
-		// small strings get named by their contents,
-		// so that multiple modules using the same string
-		// can share it.
+		// Small strings get named directly by their contents.
 		symname = strconv.Quote(s)
-		pkg = gostringpkg
 	}
 
-	symhdr := Pkglookup("hdr."+symname, pkg)
-	symdata := Pkglookup(symname, pkg)
+	const prefix = "go.string."
+	symdataname := prefix + symname
 
-	// SymUniq flag indicates that data is generated already
-	if symhdr.Flags&SymUniq != 0 {
-		return symhdr, symdata
+	// All the strings have the same prefix, so ignore it for map
+	// purposes, but use a slice of the symbol name string to
+	// reduce long-term memory overhead.
+	key := symdataname[len(prefix):]
+
+	if syms, ok := stringConstants[key]; ok {
+		return syms.hdr, syms.data
 	}
-	symhdr.Flags |= SymUniq
-	symhdr.Def = newname(symhdr)
+
+	symhdrname := "go.string.hdr." + symname
+
+	symhdr := obj.Linklookup(Ctxt, symhdrname, 0)
+	symdata := obj.Linklookup(Ctxt, symdataname, 0)
+
+	stringConstants[key] = stringConstantSyms{symhdr, symdata}
 
 	// 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)
+	off = dsymptrLSym(symhdr, off, symdata, 0)
+	off = duintxxLSym(symhdr, off, uint64(len(s)), Widthint)
+	ggloblLSym(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)
+	off = dsnameLSym(symdata, 0, s)
+	ggloblLSym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
 
 	return symhdr, symdata
 }
@@ -243,22 +302,12 @@ func stringsym(s string) (hdr, data *Sym) {
 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])
-	}
-
+	off := dsname(sym, 0, s)
 	ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL)
 
 	if nam.Op != ONAME {
@@ -274,8 +323,7 @@ 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.Sym = symdata
 	a.Offset = 0
 	a.Etype = uint8(Simtype[TINT])
 }
@@ -284,8 +332,7 @@ 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.Sym = symhdr
 	a.Offset = 0
 	a.Etype = uint8(TSTRING)
 }
@@ -302,113 +349,113 @@ func dgostrlitptr(s *Sym, off int, lit *string) int {
 		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 = uint8(Simtype[TINT])
+	symhdr, _ := stringsym(*lit)
+	Linksym(s).WriteAddr(Ctxt, int64(off), Widthptr, symhdr, 0)
 	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 dsnameLSym(Linksym(s), off, t)
+}
+
+func dsnameLSym(s *obj.LSym, off int, t string) int {
+	s.WriteString(Ctxt, int64(off), len(t), t)
 	return off + len(t)
 }
 
 func dsymptr(s *Sym, off int, x *Sym, xoff int) int {
-	off = int(Rnd(int64(off), int64(Widthptr)))
+	return dsymptrLSym(Linksym(s), off, Linksym(x), xoff)
+}
 
-	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)
+func dsymptrLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
+	off = int(Rnd(int64(off), int64(Widthptr)))
+	s.WriteAddr(Ctxt, int64(off), Widthptr, x, int64(xoff))
 	off += Widthptr
+	return off
+}
 
+func dsymptrOffLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
+	s.WriteOff(Ctxt, int64(off), x, int64(xoff))
+	off += 4
 	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
-		}
+	if nam.Op != ONAME {
+		Fatalf("gdata nam op %v", nam.Op)
+	}
+	if nam.Sym == nil {
+		Fatalf("gdata nil nam sym")
 	}
 
-	p := Thearch.Gins(obj.ADATA, nam, nr)
-	p.From3 = new(obj.Addr)
-	p.From3.Type = obj.TYPE_CONST
-	p.From3.Offset = int64(wid)
+	switch nr.Op {
+	case OLITERAL:
+		switch u := nr.Val().U.(type) {
+		case *Mpcplx:
+			gdatacomplex(nam, u)
+
+		case string:
+			gdatastring(nam, u)
+
+		case bool:
+			i := int64(obj.Bool2int(u))
+			Linksym(nam.Sym).WriteInt(Ctxt, nam.Xoffset, wid, i)
+
+		case *Mpint:
+			Linksym(nam.Sym).WriteInt(Ctxt, nam.Xoffset, wid, u.Int64())
+
+		case *Mpflt:
+			s := Linksym(nam.Sym)
+			f := u.Float64()
+			switch nam.Type.Etype {
+			case TFLOAT32:
+				s.WriteFloat32(Ctxt, nam.Xoffset, float32(f))
+			case TFLOAT64:
+				s.WriteFloat64(Ctxt, nam.Xoffset, f)
+			}
+
+		default:
+			Fatalf("gdata unhandled OLITERAL %v", nr)
+		}
+
+	case OADDR:
+		if nr.Left.Op != ONAME {
+			Fatalf("gdata ADDR left op %s", nr.Left.Op)
+		}
+		to := nr.Left
+		Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(to.Sym), to.Xoffset)
+
+	case ONAME:
+		if nr.Class != PFUNC {
+			Fatalf("gdata NAME not PFUNC %d", nr.Class)
+		}
+		Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(funcsym(nr.Sym)), nr.Xoffset)
+
+	default:
+		Fatalf("gdata unhandled op %v %v\n", nr, nr.Op)
+	}
 }
 
 func gdatacomplex(nam *Node, cval *Mpcplx) {
-	cst := cplxsubtype(nam.Type.Etype)
-	w := int(Types[cst].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)
+	t := Types[cplxsubtype(nam.Type.Etype)]
+	r := cval.Real.Float64()
+	i := cval.Imag.Float64()
+	s := Linksym(nam.Sym)
+
+	switch t.Etype {
+	case TFLOAT32:
+		s.WriteFloat32(Ctxt, nam.Xoffset, float32(r))
+		s.WriteFloat32(Ctxt, nam.Xoffset+4, float32(i))
+	case TFLOAT64:
+		s.WriteFloat64(Ctxt, nam.Xoffset, r)
+		s.WriteFloat64(Ctxt, nam.Xoffset+8, i)
+	}
 }
 
 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)
+	s := Linksym(nam.Sym)
+	_, symdata := stringsym(sval)
+	s.WriteAddr(Ctxt, nam.Xoffset, Widthptr, symdata, 0)
+	s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthint, int64(len(sval)))
 }
diff --git a/src/cmd/compile/internal/gc/opnames.go b/src/cmd/compile/internal/gc/opnames.go
index 0609643..bcdae6c 100644
--- a/src/cmd/compile/internal/gc/opnames.go
+++ b/src/cmd/compile/internal/gc/opnames.go
@@ -76,7 +76,6 @@ var opnames = []string{
 	OINDEX:           "INDEX",
 	OINDEXMAP:        "INDEXMAP",
 	OKEY:             "KEY",
-	OPARAM:           "PARAM",
 	OLEN:             "LEN",
 	OMAKE:            "MAKE",
 	OMAKECHAN:        "MAKECHAN",
@@ -160,5 +159,9 @@ var opnames = []string{
 	OLROT:            "LROT",
 	ORROTC:           "RROTC",
 	ORETJMP:          "RETJMP",
+	OPS:              "PS",
+	OPC:              "PC",
+	OSQRT:            "SQRT",
+	OGETG:            "GETG",
 	OEND:             "END",
 }
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index a2e1228..f3b1028 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -10,7 +10,7 @@ import (
 )
 
 // Rewrite tree to use separate statements to enforce
-// order of evaluation.  Makes walk easier, because it
+// 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.
@@ -41,9 +41,8 @@ import (
 
 // 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)
+	out  []*Node // list of generated statements
+	temp []*Node // stack of temporary variables
 }
 
 // Order rewrites fn->nbody to apply the ordering constraints
@@ -54,7 +53,7 @@ func order(fn *Node) {
 		dumplist(s, fn.Nbody)
 	}
 
-	orderblock(&fn.Nbody)
+	orderblockNodes(&fn.Nbody)
 }
 
 // Ordertemp allocates a new temporary with the given type,
@@ -64,18 +63,11 @@ 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)
+		a = typecheck(a, Etop)
+		order.out = append(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
+	order.temp = append(order.temp, var_)
 	return var_
 }
 
@@ -94,8 +86,8 @@ func ordertemp(t *Type, order *Order, clear bool) *Node {
 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)
+	a = typecheck(a, Etop)
+	order.out = append(order.out, a)
 	return var_
 }
 
@@ -115,12 +107,10 @@ func ordercheapexpr(n *Node, order *Order) *Node {
 		if l == n.Left {
 			return n
 		}
-		a := Nod(OXXX, nil, nil)
-		*a = *n
-		a.Orig = a
+		a := *n
+		a.Orig = &a
 		a.Left = l
-		typecheck(&a, Erv)
-		return a
+		return typecheck(&a, Erv)
 	}
 
 	return ordercopyexpr(n, n.Type, order, 0)
@@ -143,28 +133,24 @@ func ordersafeexpr(n *Node, order *Order) *Node {
 		if l == n.Left {
 			return n
 		}
-		a := Nod(OXXX, nil, nil)
-		*a = *n
-		a.Orig = a
+		a := *n
+		a.Orig = &a
 		a.Left = l
-		typecheck(&a, Erv)
-		return a
+		return typecheck(&a, Erv)
 
 	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 := *n
+		a.Orig = &a
 		a.Left = l
-		typecheck(&a, Erv)
-		return a
+		return typecheck(&a, Erv)
 
 	case OINDEX, OINDEXMAP:
 		var l *Node
-		if Isfixedarray(n.Left.Type) {
+		if n.Left.Type.IsArray() {
 			l = ordersafeexpr(n.Left, order)
 		} else {
 			l = ordercheapexpr(n.Left, order)
@@ -173,17 +159,15 @@ func ordersafeexpr(n *Node, order *Order) *Node {
 		if l == n.Left && r == n.Right {
 			return n
 		}
-		a := Nod(OXXX, nil, nil)
-		*a = *n
-		a.Orig = a
+		a := *n
+		a.Orig = &a
 		a.Left = l
 		a.Right = r
-		typecheck(&a, Erv)
-		return a
+		return typecheck(&a, Erv)
+	default:
+		Fatalf("ordersafeexpr %v", n.Op)
+		return nil // not reached
 	}
-
-	Fatalf("ordersafeexpr %v", Oconv(int(n.Op), 0))
-	return nil // not reached
 }
 
 // Istemp reports whether n is a temporary variable.
@@ -207,124 +191,122 @@ func isaddrokay(n *Node) bool {
 // 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
+func orderaddrtemp(n *Node, order *Order) *Node {
 	if isaddrokay(n) {
-		return
+		return n
 	}
-	*np = ordercopyexpr(n, n.Type, order, 0)
+	return ordercopyexpr(n, n.Type, order, 0)
 }
 
+type ordermarker int
+
 // Marktemp returns the top of the temporary variable stack.
-func marktemp(order *Order) *NodeList {
-	return order.temp
+func marktemp(order *Order) ordermarker {
+	return ordermarker(len(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
-	}
+func poptemp(mark ordermarker, order *Order) {
+	order.temp = order.temp[:mark]
 }
 
 // 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) {
+func cleantempnopop(mark ordermarker, order *Order, out *[]*Node) {
 	var kill *Node
 
-	for l := order.temp; l != mark; l = l.Next {
-		if l.N.Name.Keepalive {
-			l.N.Name.Keepalive = false
-			kill = Nod(OVARLIVE, l.N, nil)
-			typecheck(&kill, Etop)
-			*out = list(*out, kill)
+	for i := len(order.temp) - 1; i >= int(mark); i-- {
+		n := order.temp[i]
+		if n.Name.Keepalive {
+			n.Name.Keepalive = false
+			n.Addrtaken = true // ensure SSA keeps the n variable
+			kill = Nod(OVARLIVE, n, nil)
+			kill = typecheck(kill, Etop)
+			*out = append(*out, kill)
 		}
-		kill = Nod(OVARKILL, l.N, nil)
-		typecheck(&kill, Etop)
-		*out = list(*out, kill)
+		kill = Nod(OVARKILL, n, nil)
+		kill = typecheck(kill, Etop)
+		*out = append(*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) {
+func cleantemp(top ordermarker, 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)
+func orderstmtlist(l Nodes, order *Order) {
+	for _, n := range l.Slice() {
+		orderstmt(n, order)
 	}
 }
 
-// Orderblock orders the block of statements *l onto a new list,
-// and then replaces *l with that list.
-func orderblock(l **NodeList) {
+// Orderblock orders the block of statements l onto a new list,
+// and returns the ordered list.
+func orderblock(l Nodes) []*Node {
+	var order Order
+	mark := marktemp(&order)
+	orderstmtlist(l, &order)
+	cleantemp(mark, &order)
+	return order.out
+}
+
+// OrderblockNodes orders the block of statements in n into a new slice,
+// and then replaces the old slice in n with the new slice.
+func orderblockNodes(n *Nodes) {
 	var order Order
 	mark := marktemp(&order)
-	orderstmtlist(*l, &order)
+	orderstmtlist(*n, &order)
 	cleantemp(mark, &order)
-	*l = order.out
+	n.Set(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
+// The result of orderexprinplace MUST be assigned back to n, e.g.
+// 	n.Left = orderexprinplace(n.Left, outer)
+func orderexprinplace(n *Node, outer *Order) *Node {
 	var order Order
-	orderexpr(&n, &order, nil)
-	addinit(&n, order.out)
+	n = orderexpr(n, &order, nil)
+	n = 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
+	outer.temp = append(outer.temp, order.temp...)
+	return 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
+// The result of orderstmtinplace MUST be assigned back to n, e.g.
+// 	n.Left = orderstmtinplace(n.Left)
+func orderstmtinplace(n *Node) *Node {
 	var order Order
 	mark := marktemp(&order)
 	orderstmt(n, &order)
 	cleantemp(mark, &order)
-	*np = liststmt(order.out)
+	return 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
+	n.Ninit.Set(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 {
+func ismulticall(l Nodes) bool {
 	// one arg only
-	if l == nil || l.Next != nil {
+	if l.Len() != 1 {
 		return false
 	}
-	n := l.N
+	n := l.First()
 
 	// must be call
 	switch n.Op {
@@ -336,40 +318,38 @@ func ismulticall(l *NodeList) bool {
 	}
 
 	// call must return multiple values
-	return n.Left.Type.Outtuple > 1
+	return n.Left.Type.Results().NumFields() > 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 {
-		Fatalf("copyret %v %d", n.Type, n.Left.Type.Outtuple)
+func copyret(n *Node, order *Order) []*Node {
+	if !n.Type.IsFuncArgStruct() {
+		Fatalf("copyret %v %d", n.Type, n.Left.Type.Results().NumFields())
 	}
 
-	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)
+	var l1 []*Node
+	var l2 []*Node
+	for _, t := range n.Type.Fields().Slice() {
+		tmp := temp(t.Type)
+		l1 = append(l1, tmp)
+		l2 = append(l2, tmp)
 	}
 
 	as := Nod(OAS2, nil, nil)
-	as.List = l1
-	as.Rlist = list1(n)
-	typecheck(&as, Etop)
+	as.List.Set(l1)
+	as.Rlist.Set1(n)
+	as = typecheck(as, Etop)
 	orderstmt(as, order)
 
 	return l2
 }
 
 // Ordercallargs orders the list of call arguments *l.
-func ordercallargs(l **NodeList, order *Order) {
+func ordercallargs(l *Nodes, order *Order) {
 	if ismulticall(*l) {
 		// return f() where f() is multiple values.
-		*l = copyret((*l).N, order)
+		l.Set(copyret(l.First(), order))
 	} else {
 		orderexprlist(*l, order)
 	}
@@ -378,36 +358,45 @@ func ordercallargs(l **NodeList, order *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
+	n.Left = orderexpr(n.Left, order, nil)
+	n.Right = orderexpr(n.Right, order, nil) // ODDDARG temp
 	ordercallargs(&n.List, order)
 
 	if n.Op == OCALLFUNC {
-		for l, t := n.List, getinargx(n.Left.Type).Type; l != nil && t != nil; l, t = l.Next, t.Down {
+		t, it := IterFields(n.Left.Type.Params())
+		for i := range n.List.Slice() {
 			// Check for "unsafe-uintptr" tag provided by escape analysis.
 			// If present and the argument is really a pointer being converted
 			// to uintptr, arrange for the pointer to be kept alive until the call
 			// returns, by copying it into a temp and marking that temp
 			// still alive when we pop the temp stack.
-			if t.Note != nil && *t.Note == unsafeUintptrTag {
-				xp := &l.N
-				for (*xp).Op == OCONVNOP && !Isptr[(*xp).Type.Etype] {
+			if t == nil {
+				break
+			}
+			if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag {
+				xp := n.List.Addr(i)
+				for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() {
 					xp = &(*xp).Left
 				}
 				x := *xp
-				if Isptr[x.Type.Etype] {
+				if x.Type.IsPtr() {
 					x = ordercopyexpr(x, x.Type, order, 0)
 					x.Name.Keepalive = true
 					*xp = x
 				}
 			}
+			next := it.Next()
+			if next == nil && t.Isddd && t.Note == uintptrEscapesTag {
+				next = t
+			}
+			t = next
 		}
 	}
 }
 
 // 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.
+// where x is addressable.
 // (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:
@@ -431,48 +420,51 @@ func ordercall(n *Node, order *Order) {
 func ordermapassign(n *Node, order *Order) {
 	switch n.Op {
 	default:
-		Fatalf("ordermapassign %v", Oconv(int(n.Op), 0))
+		Fatalf("ordermapassign %v", n.Op)
 
 	case OAS:
-		order.out = list(order.out, n)
+		order.out = append(order.out, n)
 
 		// We call writebarrierfat only for values > 4 pointers long. See walk.go.
+		// TODO(mdempsky): writebarrierfat doesn't exist anymore, but removing that
+		// logic causes net/http's tests to become flaky; see CL 21242.
 		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)
+			a = typecheck(a, Etop)
+			order.out = append(order.out, a)
 		}
 
 	case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
-		var post *NodeList
+		var post []*Node
 		var m *Node
 		var a *Node
-		for l := n.List; l != nil; l = l.Next {
-			if l.N.Op == OINDEXMAP {
-				m = l.N
+		for i1, n1 := range n.List.Slice() {
+			if n1.Op == OINDEXMAP {
+				m = n1
 				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 instrumenting && 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)
+				n.List.SetIndex(i1, ordertemp(m.Type, order, false))
+				a = Nod(OAS, m, n.List.Index(i1))
+				a = typecheck(a, Etop)
+				post = append(post, a)
+			} else if instrumenting && n.Op == OAS2FUNC && !isblank(n.List.Index(i1)) {
+				m = n.List.Index(i1)
+				t := ordertemp(m.Type, order, false)
+				n.List.SetIndex(i1, t)
+				a = Nod(OAS, m, t)
+				a = typecheck(a, Etop)
+				post = append(post, a)
 			}
 		}
 
-		order.out = list(order.out, n)
-		order.out = concat(order.out, post)
+		order.out = append(order.out, n)
+		order.out = append(order.out, post...)
 	}
 }
 
@@ -484,21 +476,21 @@ func orderstmt(n *Node, order *Order) {
 		return
 	}
 
-	lno := int(setlineno(n))
+	lno := setlineno(n)
 
 	orderinit(n, order)
 
 	switch n.Op {
 	default:
-		Fatalf("orderstmt %v", Oconv(int(n.Op), 0))
+		Fatalf("orderstmt %v", n.Op)
 
 	case OVARKILL, OVARLIVE:
-		order.out = list(order.out, n)
+		order.out = append(order.out, n)
 
 	case OAS:
 		t := marktemp(order)
-		orderexpr(&n.Left, order, nil)
-		orderexpr(&n.Right, order, n.Left)
+		n.Left = orderexpr(n.Left, order, nil)
+		n.Right = orderexpr(n.Right, order, n.Left)
 		ordermapassign(n, order)
 		cleantemp(t, order)
 
@@ -510,15 +502,15 @@ func orderstmt(n *Node, order *Order) {
 		ORECOVER,
 		ORECV:
 		t := marktemp(order)
-		orderexpr(&n.Left, order, nil)
-		orderexpr(&n.Right, order, nil)
+		n.Left = orderexpr(n.Left, order, nil)
+		n.Right = 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)
+			order.out = append(order.out, n)
 		}
 		cleantemp(t, order)
 
@@ -530,7 +522,7 @@ func orderstmt(n *Node, order *Order) {
 		// a map index expression.
 		t := marktemp(order)
 
-		orderexpr(&n.Left, order, nil)
+		n.Left = orderexpr(n.Left, order, nil)
 		n.Left = ordersafeexpr(n.Left, order)
 		tmp1 := treecopy(n.Left, 0)
 		if tmp1.Op == OINDEXMAP {
@@ -539,8 +531,8 @@ func orderstmt(n *Node, order *Order) {
 		tmp1 = ordercopyexpr(tmp1, n.Left.Type, order, 0)
 		// TODO(marvin): Fix Node.EType type union.
 		n.Right = Nod(Op(n.Etype), tmp1, n.Right)
-		typecheck(&n.Right, Erv)
-		orderexpr(&n.Right, order, nil)
+		n.Right = typecheck(n.Right, Erv)
+		n.Right = orderexpr(n.Right, order, nil)
 		n.Etype = 0
 		n.Op = OAS
 		ordermapassign(n, order)
@@ -552,15 +544,15 @@ func orderstmt(n *Node, order *Order) {
 		t := marktemp(order)
 
 		orderexprlist(n.List, order)
-		r := n.Rlist.N
-		orderexpr(&r.Left, order, nil)
-		orderexpr(&r.Right, order, nil)
+		r := n.Rlist.First()
+		r.Left = orderexpr(r.Left, order, nil)
+		r.Right = orderexpr(r.Right, order, nil)
 
 		// See case OINDEXMAP below.
 		if r.Right.Op == OARRAYBYTESTR {
 			r.Right.Op = OARRAYBYTESTRTMP
 		}
-		orderaddrtemp(&r.Right, order)
+		r.Right = orderaddrtemp(r.Right, order)
 		ordermapassign(n, order)
 		cleantemp(t, order)
 
@@ -569,7 +561,7 @@ func orderstmt(n *Node, order *Order) {
 		t := marktemp(order)
 
 		orderexprlist(n.List, order)
-		ordercall(n.Rlist.N, order)
+		ordercall(n.Rlist.First(), order)
 		ordermapassign(n, order)
 		cleantemp(t, order)
 
@@ -580,17 +572,17 @@ func orderstmt(n *Node, order *Order) {
 		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)
+		n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // i in i.(T)
+		if isblank(n.List.First()) {
+			order.out = append(order.out, n)
 		} else {
-			typ := n.Rlist.N.Type
+			typ := n.Rlist.First().Type
 			tmp1 := ordertemp(typ, order, haspointers(typ))
-			order.out = list(order.out, n)
-			r := Nod(OAS, n.List.N, tmp1)
-			typecheck(&r, Etop)
+			order.out = append(order.out, n)
+			r := Nod(OAS, n.List.First(), tmp1)
+			r = typecheck(r, Etop)
 			ordermapassign(r, order)
-			n.List = list(list1(tmp1), n.List.Next.N)
+			n.List.Set([]*Node{tmp1, n.List.Second()})
 		}
 
 		cleantemp(t, order)
@@ -601,23 +593,23 @@ func orderstmt(n *Node, order *Order) {
 		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))
+		n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // arg to recv
+		ch := n.Rlist.First().Left.Type
+		tmp1 := ordertemp(ch.Elem(), order, haspointers(ch.Elem()))
 		var tmp2 *Node
-		if !isblank(n.List.Next.N) {
-			tmp2 = ordertemp(n.List.Next.N.Type, order, false)
+		if !isblank(n.List.Second()) {
+			tmp2 = ordertemp(n.List.Second().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)
+		order.out = append(order.out, n)
+		r := Nod(OAS, n.List.First(), tmp1)
+		r = typecheck(r, Etop)
 		ordermapassign(r, order)
-		r = Nod(OAS, n.List.Next.N, tmp2)
-		typecheck(&r, Etop)
+		r = Nod(OAS, n.List.Second(), tmp2)
+		r = typecheck(r, Etop)
 		ordermapassign(r, order)
-		n.List = list(list1(tmp1), tmp2)
+		n.List.Set([]*Node{tmp1, tmp2})
 		cleantemp(t, order)
 
 		// Special: does not save n onto out.
@@ -635,14 +627,14 @@ func orderstmt(n *Node, order *Order) {
 		OGOTO,
 		OLABEL,
 		ORETJMP:
-		order.out = list(order.out, n)
+		order.out = append(order.out, n)
 
 		// Special: handle call arguments.
 	case OCALLFUNC, OCALLINTER, OCALLMETH:
 		t := marktemp(order)
 
 		ordercall(n, order)
-		order.out = list(order.out, n)
+		order.out = append(order.out, n)
 		cleantemp(t, order)
 
 		// Special: order arguments to inner call but not call itself.
@@ -657,7 +649,7 @@ func orderstmt(n *Node, order *Order) {
 			orderexprlist(n.Left.List, order)
 
 			t1 := marktemp(order)
-			np := &n.Left.List.Next.N // map key
+			np := n.Left.List.Addr(1) // map key
 			*np = ordercopyexpr(*np, (*np).Type, order, 0)
 			poptemp(t1, order)
 
@@ -665,15 +657,15 @@ func orderstmt(n *Node, order *Order) {
 			ordercall(n.Left, order)
 		}
 
-		order.out = list(order.out, n)
+		order.out = append(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)
+		n.List.SetIndex(0, orderexpr(n.List.Index(0), order, nil))
+		n.List.SetIndex(1, orderexpr(n.List.Index(1), order, nil))
+		n.List.SetIndex(1, orderaddrtemp(n.List.Index(1), order)) // map key
+		order.out = append(order.out, n)
 		cleantemp(t, order)
 
 		// Clean temporaries from condition evaluation at
@@ -681,13 +673,13 @@ func orderstmt(n *Node, order *Order) {
 	case OFOR:
 		t := marktemp(order)
 
-		orderexprinplace(&n.Left, order)
-		var l *NodeList
+		n.Left = orderexprinplace(n.Left, order)
+		var l []*Node
 		cleantempnopop(t, order, &l)
-		n.Nbody = concat(l, n.Nbody)
-		orderblock(&n.Nbody)
-		orderstmtinplace(&n.Right)
-		order.out = list(order.out, n)
+		n.Nbody.Set(append(l, n.Nbody.Slice()...))
+		orderblockNodes(&n.Nbody)
+		n.Right = orderstmtinplace(n.Right)
+		order.out = append(order.out, n)
 		cleantemp(t, order)
 
 		// Clean temporaries from condition at
@@ -695,95 +687,95 @@ func orderstmt(n *Node, order *Order) {
 	case OIF:
 		t := marktemp(order)
 
-		orderexprinplace(&n.Left, order)
-		var l *NodeList
+		n.Left = orderexprinplace(n.Left, order)
+		var l []*Node
 		cleantempnopop(t, order, &l)
-		n.Nbody = concat(l, n.Nbody)
+		n.Nbody.Set(append(l, n.Nbody.Slice()...))
 		l = nil
 		cleantempnopop(t, order, &l)
-		n.Rlist = concat(l, n.Rlist)
+		n.Rlist.Set(append(l, n.Rlist.Slice()...))
 		poptemp(t, order)
-		orderblock(&n.Nbody)
-		orderblock(&n.Rlist)
-		order.out = list(order.out, n)
+		orderblockNodes(&n.Nbody)
+		n.Rlist.Set(orderblock(n.Rlist))
+		order.out = append(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)
+		n.Left = orderexpr(n.Left, order, nil)
+		if !n.Left.Type.IsInterface() {
+			n.Left = orderaddrtemp(n.Left, order)
 		}
-		order.out = list(order.out, n)
+		order.out = append(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)
+		// 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.
+
+		// Mark []byte(str) range expression to reuse string backing storage.
+		// It is safe because the storage cannot be mutated.
+		if n.Right.Op == OSTRARRAYBYTE {
+			n.Right.Op = OSTRARRAYBYTETMP
+		}
 
-		orderexpr(&n.Right, order, nil)
+		t := marktemp(order)
+		n.Right = orderexpr(n.Right, order, nil)
 		switch n.Type.Etype {
 		default:
 			Fatalf("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) {
+		case TARRAY, TSLICE:
+			if n.List.Len() < 2 || isblank(n.List.Second()) {
 				// 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:
+			// chan, string, slice, array ranges use value multiple times.
+			// make copy.
 			r := n.Right
 
-			if r.Type.Etype == TSTRING && r.Type != Types[TSTRING] {
+			if r.Type.IsString() && r.Type != Types[TSTRING] {
 				r = Nod(OCONV, r, nil)
 				r.Type = Types[TSTRING]
-				typecheck(&r, Erv)
+				r = 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:
+			// 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.
 			prealloc[n] = ordertemp(Types[TUINT8], order, true)
 		}
-
-		for l := n.List; l != nil; l = l.Next {
-			orderexprinplace(&l.N, order)
+		for i := range n.List.Slice() {
+			n.List.SetIndex(i, orderexprinplace(n.List.Index(i), order))
 		}
-		orderblock(&n.Nbody)
-		order.out = list(order.out, n)
+		orderblockNodes(&n.Nbody)
+		order.out = append(order.out, n)
 		cleantemp(t, order)
 
 	case ORETURN:
 		ordercallargs(&n.List, order)
-		order.out = list(order.out, n)
+		order.out = append(order.out, n)
 
 	// Special: clean case temporaries in each block entry.
 	// Select must enter one of its blocks, so there is no
@@ -800,43 +792,43 @@ func orderstmt(n *Node, order *Order) {
 		var tmp1 *Node
 		var tmp2 *Node
 		var r *Node
-		for l := n.List; l != nil; l = l.Next {
-			if l.N.Op != OXCASE {
-				Fatalf("order select case %v", Oconv(int(l.N.Op), 0))
+		for _, n2 := range n.List.Slice() {
+			if n2.Op != OXCASE {
+				Fatalf("order select case %v", n2.Op)
 			}
-			r = l.N.Left
-			setlineno(l.N)
+			r = n2.Left
+			setlineno(n2)
 
 			// Append any new body prologue to ninit.
 			// The next loop will insert ninit into nbody.
-			if l.N.Ninit != nil {
+			if n2.Ninit.Len() != 0 {
 				Fatalf("order select ninit")
 			}
 			if r != nil {
 				switch r.Op {
 				default:
-					Yyerror("unknown op in select %v", Oconv(int(r.Op), 0))
+					Yyerror("unknown op in select %v", r.Op)
 					Dump("select case", r)
 
-					// If this is case x := <-ch or case x, y := <-ch, the case has
+				// 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 {
-						init := r.Ninit
-						if init != nil && init.N.Op == ODCL && init.N.Left == r.Left {
-							init = init.Next
+						i := 0
+						if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left {
+							i++
 						}
-						if init != nil && init.N.Op == ODCL && r.List != nil && init.N.Left == r.List.N {
-							init = init.Next
+						if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() {
+							i++
 						}
-						if init == nil {
-							r.Ninit = nil
+						if i >= r.Ninit.Len() {
+							r.Ninit.Set(nil)
 						}
 					}
 
-					if r.Ninit != nil {
+					if r.Ninit.Len() != 0 {
 						Yyerror("ninit on select recv")
 						dumplist("ninit", r.Ninit)
 					}
@@ -846,7 +838,7 @@ func orderstmt(n *Node, order *Order) {
 					// 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)
+					r.Right.Left = 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)
@@ -869,78 +861,77 @@ func orderstmt(n *Node, order *Order) {
 
 						if r.Colas {
 							tmp2 = Nod(ODCL, tmp1, nil)
-							typecheck(&tmp2, Etop)
-							l.N.Ninit = list(l.N.Ninit, tmp2)
+							tmp2 = typecheck(tmp2, Etop)
+							n2.Ninit.Append(tmp2)
 						}
 
-						r.Left = ordertemp(r.Right.Left.Type.Type, order, haspointers(r.Right.Left.Type.Type))
+						r.Left = ordertemp(r.Right.Left.Type.Elem(), order, haspointers(r.Right.Left.Type.Elem()))
 						tmp2 = Nod(OAS, tmp1, r.Left)
-						typecheck(&tmp2, Etop)
-						l.N.Ninit = list(l.N.Ninit, tmp2)
+						tmp2 = typecheck(tmp2, Etop)
+						n2.Ninit.Append(tmp2)
 					}
 
-					if r.List != nil && isblank(r.List.N) {
-						r.List = nil
+					if r.List.Len() != 0 && isblank(r.List.First()) {
+						r.List.Set(nil)
 					}
-					if r.List != nil {
-						tmp1 = r.List.N
+					if r.List.Len() != 0 {
+						tmp1 = r.List.First()
 						if r.Colas {
 							tmp2 = Nod(ODCL, tmp1, nil)
-							typecheck(&tmp2, Etop)
-							l.N.Ninit = list(l.N.Ninit, tmp2)
+							tmp2 = typecheck(tmp2, Etop)
+							n2.Ninit.Append(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)
+						r.List.Set1(ordertemp(tmp1.Type, order, false))
+						tmp2 = Nod(OAS, tmp1, r.List.First())
+						tmp2 = typecheck(tmp2, Etop)
+						n2.Ninit.Append(tmp2)
 					}
-
-					orderblock(&l.N.Ninit)
+					n2.Ninit.Set(orderblock(n2.Ninit))
 
 				case OSEND:
-					if r.Ninit != nil {
+					if r.Ninit.Len() != 0 {
 						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)
+					r.Left = orderexpr(r.Left, order, nil)
 
 					if !istemp(r.Left) {
 						r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0)
 					}
-					orderexpr(&r.Right, order, nil)
+					r.Right = orderexpr(r.Right, order, nil)
 					if !istemp(r.Right) {
 						r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0)
 					}
 				}
 			}
 
-			orderblock(&l.N.Nbody)
+			orderblockNodes(&n2.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
+		for _, n3 := range n.List.Slice() {
+			s := n3.Ninit.Slice()
+			cleantempnopop(t, order, &s)
+			n3.Nbody.Set(append(s, n3.Nbody.Slice()...))
+			n3.Ninit.Set(nil)
 		}
 
-		order.out = list(order.out, n)
+		order.out = append(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)
+		n.Left = orderexpr(n.Left, order, nil)
+		n.Right = orderexpr(n.Right, order, nil)
+		n.Right = orderaddrtemp(n.Right, order)
+		order.out = append(order.out, n)
 		cleantemp(t, order)
 
 		// TODO(rsc): Clean temporaries more aggressively.
@@ -953,34 +944,36 @@ func orderstmt(n *Node, order *Order) {
 	case OSWITCH:
 		t := marktemp(order)
 
-		orderexpr(&n.Left, order, nil)
-		for l := n.List; l != nil; l = l.Next {
-			if l.N.Op != OXCASE {
-				Fatalf("order switch case %v", Oconv(int(l.N.Op), 0))
+		n.Left = orderexpr(n.Left, order, nil)
+		for _, n4 := range n.List.Slice() {
+			if n4.Op != OXCASE {
+				Fatalf("order switch case %v", n4.Op)
 			}
-			orderexprlistinplace(l.N.List, order)
-			orderblock(&l.N.Nbody)
+			orderexprlistinplace(n4.List, order)
+			orderblockNodes(&n4.Nbody)
 		}
 
-		order.out = list(order.out, n)
+		order.out = append(order.out, n)
 		cleantemp(t, order)
 	}
 
-	lineno = int32(lno)
+	lineno = 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)
+func orderexprlist(l Nodes, order *Order) {
+	s := l.Slice()
+	for i := range s {
+		s[i] = orderexpr(s[i], 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)
+func orderexprlistinplace(l Nodes, order *Order) {
+	s := l.Slice()
+	for i := range s {
+		s[i] = orderexprinplace(s[i], order)
 	}
 }
 
@@ -992,19 +985,20 @@ var prealloc = map[*Node]*Node{}
 // 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
+// The result of orderexpr MUST be assigned back to n, e.g.
+// 	n.Left = orderexpr(n.Left, order, lhs)
+func orderexpr(n *Node, order *Order, lhs *Node) *Node {
 	if n == nil {
-		return
+		return n
 	}
 
-	lno := int(setlineno(n))
+	lno := setlineno(n)
 	orderinit(n, order)
 
 	switch n.Op {
 	default:
-		orderexpr(&n.Left, order, nil)
-		orderexpr(&n.Right, order, nil)
+		n.Left = orderexpr(n.Left, order, nil)
+		n.Right = orderexpr(n.Right, order, nil)
 		orderexprlist(n.List, order)
 		orderexprlist(n.Rlist, order)
 
@@ -1014,10 +1008,8 @@ func orderexpr(np **Node, order *Order, lhs *Node) {
 	case OADDSTR:
 		orderexprlist(n.List, order)
 
-		if count(n.List) > 5 {
-			t := typ(TARRAY)
-			t.Bound = int64(count(n.List))
-			t.Type = Types[TSTRING]
+		if n.List.Len() > 5 {
+			t := typArray(Types[TSTRING], int64(n.List.Len()))
 			prealloc[n] = ordertemp(t, order, false)
 		}
 
@@ -1031,22 +1023,22 @@ func orderexpr(np **Node, order *Order, lhs *Node) {
 		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
+		for _, n1 := range n.List.Slice() {
+			hasbyte = hasbyte || n1.Op == OARRAYBYTESTR
+			haslit = haslit || n1.Op == OLITERAL && len(n1.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
+			for _, n2 := range n.List.Slice() {
+				if n2.Op == OARRAYBYTESTR {
+					n2.Op = OARRAYBYTESTRTMP
 				}
 			}
 		}
 
 	case OCMPSTR:
-		orderexpr(&n.Left, order, nil)
-		orderexpr(&n.Right, order, nil)
+		n.Left = orderexpr(n.Left, order, nil)
+		n.Right = orderexpr(n.Right, order, nil)
 
 		// Mark string(byteSlice) arguments to reuse byteSlice backing
 		// buffer during conversion. String comparison does not
@@ -1060,9 +1052,9 @@ func orderexpr(np **Node, order *Order, lhs *Node) {
 
 		// key must be addressable
 	case OINDEXMAP:
-		orderexpr(&n.Left, order, nil)
+		n.Left = orderexpr(n.Left, order, nil)
 
-		orderexpr(&n.Right, order, nil)
+		n.Right = 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
@@ -1078,7 +1070,7 @@ func orderexpr(np **Node, order *Order, lhs *Node) {
 			n.Right.Op = OARRAYBYTESTRTMP
 		}
 
-		orderaddrtemp(&n.Right, order)
+		n.Right = orderaddrtemp(n.Right, order)
 		if n.Etype == 0 {
 			// use of value (not being assigned);
 			// make copy in temporary.
@@ -1088,24 +1080,38 @@ func orderexpr(np **Node, order *Order, lhs *Node) {
 		// concrete type (not interface) argument must be addressable
 	// temporary to pass to runtime.
 	case OCONVIFACE:
-		orderexpr(&n.Left, order, nil)
+		n.Left = orderexpr(n.Left, order, nil)
+
+		if !n.Left.Type.IsInterface() {
+			n.Left = orderaddrtemp(n.Left, order)
+		}
 
-		if !Isinter(n.Left.Type) {
-			orderaddrtemp(&n.Left, order)
+	case OCONVNOP:
+		if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) {
+			// When reordering unsafe.Pointer(f()) into a separate
+			// statement, the conversion and function call must stay
+			// together. See golang.org/issue/15329.
+			orderinit(n.Left, order)
+			ordercall(n.Left, order)
+			if lhs == nil || lhs.Op != ONAME || instrumenting {
+				n = ordercopyexpr(n, n.Type, order, 0)
+			}
+		} else {
+			n.Left = orderexpr(n.Left, order, nil)
 		}
 
 	case OANDAND, OOROR:
 		mark := marktemp(order)
-		orderexpr(&n.Left, order, nil)
+		n.Left = 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
+		var s []*Node
 
-		cleantempnopop(mark, order, &l)
-		n.Right.Ninit = concat(l, n.Right.Ninit)
-		orderexprinplace(&n.Right, order)
+		cleantempnopop(mark, order, &s)
+		n.Right.Ninit.Set(append(s, n.Right.Ninit.Slice()...))
+		n.Right = orderexprinplace(n.Right, order)
 
 	case OCALLFUNC,
 		OCALLINTER,
@@ -1131,40 +1137,32 @@ func orderexpr(np **Node, order *Order, lhs *Node) {
 
 	case OAPPEND:
 		ordercallargs(&n.List, order)
-		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.N) {
+		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) {
 			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)
+	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
+		n.Left = orderexpr(n.Left, order, nil)
+		low, high, max := n.SliceBounds()
+		low = orderexpr(low, order, nil)
+		low = ordercheapexpr(low, order)
+		high = orderexpr(high, order, nil)
+		high = ordercheapexpr(high, order)
+		max = orderexpr(max, order, nil)
+		max = ordercheapexpr(max, order)
+		n.SetSliceBounds(low, high, max)
 		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 {
+		if n.Noescape && n.Func.Cvars.Len() > 0 {
 			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)
+		n.Left = orderexpr(n.Left, order, nil)
+		n.Right = orderexpr(n.Right, order, nil)
 		orderexprlist(n.List, order)
 		orderexprlist(n.Rlist, order)
 		if n.Noescape {
@@ -1177,11 +1175,11 @@ func orderexpr(np **Node, order *Order, lhs *Node) {
 			// 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)
+			prealloc[n] = ordertemp(n.Type.Elem(), order, false)
 		}
 
 	case ODOTTYPE, ODOTTYPE2:
-		orderexpr(&n.Left, order, nil)
+		n.Left = 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).
@@ -1190,22 +1188,21 @@ func orderexpr(np **Node, order *Order, lhs *Node) {
 		}
 
 	case ORECV:
-		orderexpr(&n.Left, order, nil)
+		n.Left = 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)
+		n.Left = orderexpr(n.Left, order, nil)
+		n.Right = orderexpr(n.Right, order, nil)
 		t := n.Left.Type
-		if t.Etype == TSTRUCT || Isfixedarray(t) {
+		if t.IsStruct() || t.IsArray() {
 			// 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)
+			n.Left = orderaddrtemp(n.Left, order)
+			n.Right = orderaddrtemp(n.Right, order)
 		}
 	}
 
-	lineno = int32(lno)
-
-	*np = n
+	lineno = lno
+	return n
 }
diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go
index 054cf73..3897db9 100644
--- a/src/cmd/compile/internal/gc/parser.go
+++ b/src/cmd/compile/internal/gc/parser.go
@@ -5,7 +5,7 @@
 package gc
 
 // The recursive-descent parser is built around a slighty modified grammar
-// of Go to accomodate for the constraints imposed by strict one token look-
+// of Go to accommodate for the constraints imposed by strict one token look-
 // ahead, and for better error handling. Subsequent checks of the constructed
 // syntax tree restrict the language accepted by the compiler to proper Go.
 //
@@ -13,6 +13,7 @@ package gc
 // to handle optional commas and semicolons before a closing ) or } .
 
 import (
+	"bufio"
 	"fmt"
 	"strconv"
 	"strings"
@@ -20,81 +21,34 @@ import (
 
 const trace = false // if set, parse tracing can be enabled with -x
 
-// TODO(gri) Once we handle imports w/o redirecting the underlying
-// source of the lexer we can get rid of these. They are here for
-// compatibility with the existing yacc-based parser setup (issue 13242).
-var thenewparser parser // the parser in use
-var savedstate []parser // saved parser state, used during import
-
-func push_parser() {
-	// Indentation (for tracing) must be preserved across parsers
-	// since we are changing the lexer source (and parser state)
-	// under foot, in the middle of productions. This won't be
-	// needed anymore once we fix issue 13242, but neither will
-	// be the push/pop_parser functionality.
-	// (Instead we could just use a global variable indent, but
-	// but eventually indent should be parser-specific anyway.)
-	indent := thenewparser.indent
-	savedstate = append(savedstate, thenewparser)
-	thenewparser = parser{indent: indent} // preserve indentation
-	thenewparser.next()
-}
-
-func pop_parser() {
-	indent := thenewparser.indent
-	n := len(savedstate) - 1
-	thenewparser = savedstate[n]
-	thenewparser.indent = indent // preserve indentation
-	savedstate = savedstate[:n]
-}
-
-// parse_file sets up a new parser and parses a single Go source file.
-func parse_file() {
-	thenewparser = parser{}
-	thenewparser.loadsys()
-	thenewparser.next()
-	thenewparser.file()
+// parse_import parses the export data of a package that is imported.
+func parse_import(bin *bufio.Reader, indent []byte) {
+	newparser(bin, indent).import_package()
 }
 
-// loadsys 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.
-func (p *parser) loadsys() {
-	if trace && Debug['x'] != 0 {
-		defer p.trace("loadsys")()
-	}
-
-	importpkg = Runtimepkg
-
-	if Debug['A'] != 0 {
-		cannedimports("runtime.Builtin", "package runtime\n\n$$\n\n")
-	} else {
-		cannedimports("runtime.Builtin", runtimeimport)
-	}
-	curio.importsafe = true
-
-	p.import_package()
-	p.import_there()
-
-	importpkg = nil
+// parse_file parses a single Go source file.
+func parse_file(bin *bufio.Reader) {
+	newparser(bin, nil).file()
 }
 
 type parser struct {
-	tok    int32     // next token (one-token look-ahead)
-	op     Op        // valid if tok == LASOP
-	val    Val       // valid if tok == LLITERAL
-	sym_   *Sym      // valid if tok == LNAME
-	fnest  int       // function nesting level (for error handling)
-	xnest  int       // expression nesting level (for complit ambiguity resolution)
-	yy     yySymType // for temporary use by next
-	indent []byte    // tracing support
+	lexer
+	fnest  int    // function nesting level (for error handling)
+	xnest  int    // expression nesting level (for complit ambiguity resolution)
+	indent []byte // tracing support
+
+	// TODO(gri) remove this once we switch to binary export format
+	structpkg *Pkg // for verification in addmethod only
 }
 
-func (p *parser) next() {
-	p.tok = yylex(&p.yy)
-	p.op = p.yy.op
-	p.val = p.yy.val
-	p.sym_ = p.yy.sym
+// newparser returns a new parser ready to parse from src.
+// indent is the initial indentation for tracing output.
+func newparser(src *bufio.Reader, indent []byte) *parser {
+	var p parser
+	p.bin = src
+	p.indent = indent
+	p.next()
+	return &p
 }
 
 func (p *parser) got(tok int32) bool {
@@ -141,16 +95,23 @@ func (p *parser) syntax_error(msg string) {
 	// determine token string
 	var tok string
 	switch p.tok {
-	case LLITERAL:
-		tok = litbuf
 	case LNAME:
 		if p.sym_ != nil && p.sym_.Name != "" {
 			tok = p.sym_.Name
 		} else {
 			tok = "name"
 		}
+	case LLITERAL:
+		if litbuf == "" {
+			litbuf = "literal " + lexbuf.String()
+		}
+		tok = litbuf
+	case LOPER:
+		tok = goopnames[p.op]
 	case LASOP:
 		tok = goopnames[p.op] + "="
+	case LINCOP:
+		tok = goopnames[p.op] + goopnames[p.op]
 	default:
 		tok = tokstring(p.tok)
 	}
@@ -159,11 +120,11 @@ func (p *parser) syntax_error(msg string) {
 }
 
 // Like syntax_error, but reports error at given line rather than current lexer line.
-func (p *parser) syntax_error_at(lineno int32, msg string) {
-	defer func(lineno int32) {
-		lexlineno = lineno
-	}(lexlineno)
-	lexlineno = lineno
+func (p *parser) syntax_error_at(lno int32, msg string) {
+	defer func(lno int32) {
+		lineno = lno
+	}(lineno)
+	lineno = lno
 	p.syntax_error(msg)
 }
 
@@ -235,15 +196,22 @@ func tokstring(tok int32) string {
 }
 
 var tokstrings = map[int32]string{
-	LLITERAL:   "LLITERAL",
-	LASOP:      "op=",
-	LCOLAS:     ":=",
+	LNAME:    "NAME",
+	LLITERAL: "LITERAL",
+
+	LOPER:  "op",
+	LASOP:  "op=",
+	LINCOP: "opop",
+
+	LCOLAS: ":=",
+	LCOMM:  "<-",
+	LDDD:   "...",
+
 	LBREAK:     "break",
 	LCASE:      "case",
 	LCHAN:      "chan",
 	LCONST:     "const",
 	LCONTINUE:  "continue",
-	LDDD:       "...",
 	LDEFAULT:   "default",
 	LDEFER:     "defer",
 	LELSE:      "else",
@@ -256,7 +224,6 @@ var tokstrings = map[int32]string{
 	LIMPORT:    "import",
 	LINTERFACE: "interface",
 	LMAP:       "map",
-	LNAME:      "LNAME",
 	LPACKAGE:   "package",
 	LRANGE:     "range",
 	LRETURN:    "return",
@@ -265,21 +232,6 @@ var tokstrings = map[int32]string{
 	LSWITCH:    "switch",
 	LTYPE:      "type",
 	LVAR:       "var",
-	LANDAND:    "&&",
-	LANDNOT:    "&^",
-	LCOMM:      "<-",
-	LDEC:       "--",
-	LEQ:        "==",
-	LGE:        ">=",
-	LGT:        ">",
-	LIGNORE:    "LIGNORE", // we should never see this one
-	LINC:       "++",
-	LLE:        "<=",
-	LLSH:       "<<",
-	LLT:        "<",
-	LNE:        "!=",
-	LOROR:      "||",
-	LRSH:       ">>",
 }
 
 // usage: defer p.trace(msg)()
@@ -317,7 +269,7 @@ func (p *parser) file() {
 		p.want(';')
 	}
 
-	xtop = concat(xtop, p.xdcl_list())
+	xtop = append(xtop, p.xdcl_list()...)
 
 	p.want(EOF)
 }
@@ -329,13 +281,11 @@ func (p *parser) package_() {
 		defer p.trace("package_")()
 	}
 
-	if p.got(LPACKAGE) {
-		mkpackage(p.sym().Name)
-	} else {
-		prevlineno = lineno // see issue #13267
+	if !p.got(LPACKAGE) {
 		p.syntax_error("package statement must be first")
 		errorexit()
 	}
+	mkpackage(p.sym().Name)
 }
 
 // ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
@@ -347,108 +297,89 @@ func (p *parser) import_() {
 	p.want(LIMPORT)
 	if p.got('(') {
 		for p.tok != EOF && p.tok != ')' {
-			p.import_stmt()
+			p.importdcl()
 			if !p.osemi(')') {
 				break
 			}
 		}
 		p.want(')')
 	} else {
-		p.import_stmt()
-	}
-}
-
-func (p *parser) import_stmt() {
-	if trace && Debug['x'] != 0 {
-		defer p.trace("import_stmt")()
-	}
-
-	line := int32(p.import_here())
-	if p.tok == LPACKAGE {
-		p.import_package()
-		p.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 = line
-
-		if strings.HasPrefix(my.Name, ".") {
-			importdot(ipkg, pack)
-			return
-		}
-		if my.Name == "init" {
-			lineno = line
-			Yyerror("cannot import package as init - init must be a func")
-			return
-		}
-		if my.Name == "_" {
-			return
-		}
-		if my.Def != nil {
-			lineno = line
-			redeclare(my, "as imported package name")
-		}
-		my.Def = pack
-		my.Lastlineno = line
-		my.Block = 1 // at top level
-
-		return
-	}
-
-	p.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 {
-		Fatalf("phase error in import")
+		p.importdcl()
 	}
 }
 
 // ImportSpec = [ "." | PackageName ] ImportPath .
 // ImportPath = string_lit .
-//
-// import_here switches the underlying lexed source to the export data
-// of the imported package.
-func (p *parser) import_here() int {
+func (p *parser) importdcl() {
 	if trace && Debug['x'] != 0 {
-		defer p.trace("import_here")()
+		defer p.trace("importdcl")()
 	}
 
-	importmyname = nil
+	var my *Sym
 	switch p.tok {
 	case LNAME, '@', '?':
 		// import with given name
-		importmyname = p.sym()
+		my = p.sym()
 
 	case '.':
 		// import into my name space
-		importmyname = Lookup(".")
+		my = Lookup(".")
 		p.next()
 	}
 
-	var path Val
-	if p.tok == LLITERAL {
-		path = p.val
-		p.next()
-	} else {
+	if p.tok != LLITERAL {
 		p.syntax_error("missing import path; require quoted string")
 		p.advance(';', ')')
+		return
+	}
+
+	line := lineno
+
+	// We need to clear importpkg before calling p.next(),
+	// otherwise it will affect lexlineno.
+	// TODO(mdempsky): Fix this clumsy API.
+	importfile(&p.val, p.indent)
+	ipkg := importpkg
+	importpkg = nil
+
+	p.next()
+	if ipkg == nil {
+		if nerrors == 0 {
+			Fatalf("phase error in import")
+		}
+		return
+	}
+
+	ipkg.Direct = true
+
+	if my == nil {
+		my = Lookup(ipkg.Name)
 	}
 
-	line := parserline()
-	importfile(&path, line)
-	return line
+	pack := Nod(OPACK, nil, nil)
+	pack.Sym = my
+	pack.Name.Pkg = ipkg
+	pack.Lineno = line
+
+	if strings.HasPrefix(my.Name, ".") {
+		importdot(ipkg, pack)
+		return
+	}
+	if my.Name == "init" {
+		lineno = line
+		Yyerror("cannot import package as init - init must be a func")
+		return
+	}
+	if my.Name == "_" {
+		return
+	}
+	if my.Def != nil {
+		lineno = line
+		redeclare(my, "as imported package name")
+	}
+	my.Def = pack
+	my.Lastlineno = line
+	my.Block = 1 // at top level
 }
 
 // import_package parses the header of an imported package as exported
@@ -467,10 +398,8 @@ func (p *parser) import_package() {
 		p.import_error()
 	}
 
+	// read but skip "safe" bit (see issue #15772)
 	if p.tok == LNAME {
-		if p.sym_.Name == "safe" {
-			curio.importsafe = true
-		}
 		p.next()
 	}
 	p.want(';')
@@ -481,23 +410,8 @@ func (p *parser) import_package() {
 	} else if importpkg.Name != name {
 		Yyerror("conflicting names %s and %s for package %q", importpkg.Name, name, importpkg.Path)
 	}
-	if incannedimport == 0 {
-		importpkg.Direct = true
-	}
-	importpkg.Safe = curio.importsafe
-
-	if safemode != 0 && !curio.importsafe {
-		Yyerror("cannot import unsafe package %q", importpkg.Path)
-	}
-}
-
-// import_there parses the imported package definitions and then switches
-// the underlying lexed source back to the importing package.
-func (p *parser) import_there() {
-	if trace && Debug['x'] != 0 {
-		defer p.trace("import_there")()
-	}
 
+	typecheckok = true
 	defercheckwidth()
 
 	p.hidden_import_list()
@@ -508,19 +422,19 @@ func (p *parser) import_there() {
 	}
 
 	resumecheckwidth()
-	unimportfile()
+	typecheckok = false
 }
 
 // Declaration = ConstDecl | TypeDecl | VarDecl .
 // ConstDecl   = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
 // TypeDecl    = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
 // VarDecl     = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
-func (p *parser) common_dcl() *NodeList {
+func (p *parser) common_dcl() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("common_dcl")()
 	}
 
-	var dcl func() *NodeList
+	var dcl func() []*Node
 	switch p.tok {
 	case LVAR:
 		dcl = p.vardcl
@@ -537,34 +451,34 @@ func (p *parser) common_dcl() *NodeList {
 	}
 
 	p.next()
-	var l *NodeList
+	var s []*Node
 	if p.got('(') {
 		for p.tok != EOF && p.tok != ')' {
-			l = concat(l, dcl())
+			s = append(s, dcl()...)
 			if !p.osemi(')') {
 				break
 			}
 		}
 		p.want(')')
 	} else {
-		l = dcl()
+		s = dcl()
 	}
 
 	iota_ = -100000
 	lastconst = nil
 
-	return l
+	return s
 }
 
 // VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
-func (p *parser) vardcl() *NodeList {
+func (p *parser) vardcl() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("vardcl")()
 	}
 
 	names := p.dcl_name_list()
 	var typ *Node
-	var exprs *NodeList
+	var exprs []*Node
 	if p.got('=') {
 		exprs = p.expr_list()
 	} else {
@@ -578,14 +492,14 @@ func (p *parser) vardcl() *NodeList {
 }
 
 // ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
-func (p *parser) constdcl() *NodeList {
+func (p *parser) constdcl() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("constdcl")()
 	}
 
 	names := p.dcl_name_list()
 	var typ *Node
-	var exprs *NodeList
+	var exprs []*Node
 	if p.tok != EOF && p.tok != ';' && p.tok != ')' {
 		typ = p.try_ntype()
 		if p.got('=') {
@@ -597,7 +511,7 @@ func (p *parser) constdcl() *NodeList {
 }
 
 // TypeSpec = identifier Type .
-func (p *parser) typedcl() *NodeList {
+func (p *parser) typedcl() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("typedcl")()
 	}
@@ -611,7 +525,7 @@ func (p *parser) typedcl() *NodeList {
 		p.advance(';', ')')
 	}
 
-	return list1(typedcl1(name, typ, true))
+	return []*Node{typedcl1(name, typ, true)}
 }
 
 // SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
@@ -631,9 +545,9 @@ func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node {
 
 	lhs := p.expr_list()
 
-	if count(lhs) == 1 && p.tok != '=' && p.tok != LCOLAS && p.tok != LRANGE {
+	if len(lhs) == 1 && p.tok != '=' && p.tok != LCOLAS && p.tok != LRANGE {
 		// expr
-		lhs := lhs.N
+		lhs := lhs[0]
 		switch p.tok {
 		case LASOP:
 			// expr LASOP expr
@@ -645,22 +559,13 @@ func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node {
 			stmt.Etype = EType(op) // rathole to pass opcode
 			return stmt
 
-		case LINC:
-			// expr LINC
-			p.next()
-
-			stmt := Nod(OASOP, lhs, Nodintconst(1))
-			stmt.Implicit = true
-			stmt.Etype = EType(OADD)
-			return stmt
-
-		case LDEC:
-			// expr LDEC
+		case LINCOP:
+			// expr LINCOP
 			p.next()
 
 			stmt := Nod(OASOP, lhs, Nodintconst(1))
 			stmt.Implicit = true
-			stmt.Etype = EType(OSUB)
+			stmt.Etype = EType(p.op)
 			return stmt
 
 		case ':':
@@ -703,7 +608,7 @@ func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node {
 		if rangeOk && p.got(LRANGE) {
 			// expr_list '=' LRANGE expr
 			r := Nod(ORANGE, nil, p.expr())
-			r.List = lhs
+			r.List.Set(lhs)
 			r.Etype = 0 // := flag
 			return r
 		}
@@ -711,14 +616,14 @@ func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node {
 		// expr_list '=' expr_list
 		rhs := p.expr_list()
 
-		if lhs.Next == nil && rhs.Next == nil {
+		if len(lhs) == 1 && len(rhs) == 1 {
 			// simple
-			return Nod(OAS, lhs.N, rhs.N)
+			return Nod(OAS, lhs[0], rhs[0])
 		}
 		// multiple
 		stmt := Nod(OAS2, nil, nil)
-		stmt.List = lhs
-		stmt.Rlist = rhs
+		stmt.List.Set(lhs)
+		stmt.Rlist.Set(rhs)
 		return stmt
 
 	case LCOLAS:
@@ -728,7 +633,7 @@ func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node {
 		if rangeOk && p.got(LRANGE) {
 			// expr_list LCOLAS LRANGE expr
 			r := Nod(ORANGE, nil, p.expr())
-			r.List = lhs
+			r.List.Set(lhs)
 			r.Colas = true
 			colasdefn(lhs, r)
 			return r
@@ -737,21 +642,21 @@ func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node {
 		// expr_list LCOLAS expr_list
 		rhs := p.expr_list()
 
-		if rhs.N.Op == OTYPESW {
-			ts := Nod(OTYPESW, nil, rhs.N.Right)
-			if rhs.Next != nil {
+		if rhs[0].Op == OTYPESW {
+			ts := Nod(OTYPESW, nil, rhs[0].Right)
+			if len(rhs) > 1 {
 				Yyerror("expr.(type) must be alone in list")
 			}
-			if lhs.Next != nil {
-				Yyerror("argument count mismatch: %d = %d", count(lhs), 1)
-			} else if (lhs.N.Op != ONAME && lhs.N.Op != OTYPE && lhs.N.Op != ONONAME && (lhs.N.Op != OLITERAL || lhs.N.Name == nil)) || isblank(lhs.N) {
-				Yyerror("invalid variable name %s in type switch", lhs.N)
+			if len(lhs) > 1 {
+				Yyerror("argument count mismatch: %d = %d", len(lhs), 1)
+			} else if (lhs[0].Op != ONAME && lhs[0].Op != OTYPE && lhs[0].Op != ONONAME && (lhs[0].Op != OLITERAL || lhs[0].Name == nil)) || isblank(lhs[0]) {
+				Yyerror("invalid variable name %s in type switch", lhs[0])
 			} else {
-				ts.Left = dclname(lhs.N.Sym)
+				ts.Left = dclname(lhs[0].Sym)
 			} // it's a colas, so must not re-use an oldname
 			return ts
 		}
-		return colas(lhs, rhs, int32(lno))
+		return colas(lhs, rhs, lno)
 
 	default:
 		p.syntax_error("expecting := or = or comma")
@@ -772,16 +677,20 @@ func (p *parser) labeled_stmt(label *Node) *Node {
 		ls = p.stmt()
 		if ls == missing_stmt {
 			// report error at line of ':' token
-			p.syntax_error_at(prevlineno, "missing statement after label")
+			p.syntax_error_at(label.Lineno, "missing statement after label")
 			// we are already at the end of the labeled statement - no need to advance
 			return missing_stmt
 		}
 	}
 
 	label.Name.Defn = ls
-	l := list1(label)
+	l := []*Node{label}
 	if ls != nil {
-		l = list(l, ls)
+		if ls.Op == OBLOCK && ls.Ninit.Len() == 0 {
+			l = append(l, ls.List.Slice()...)
+		} else {
+			l = append(l, ls)
+		}
 	}
 	return liststmt(l)
 }
@@ -813,13 +722,13 @@ func (p *parser) case_(tswitch *Node) *Node {
 			// done in casebody()
 			markdcl() // matching popdcl in caseblock
 			stmt := Nod(OXCASE, nil, nil)
-			stmt.List = cases
+			stmt.List.Set(cases)
 			if tswitch != nil {
 				if n := tswitch.Left; n != nil {
 					// type switch - declare variable
 					nn := newname(n.Sym)
 					declare(nn, dclcontext)
-					stmt.Rlist = list1(nn)
+					stmt.Rlist.Set1(nn)
 
 					// keep track of the instances for reporting unused
 					nn.Name.Defn = tswitch
@@ -840,14 +749,14 @@ func (p *parser) case_(tswitch *Node) *Node {
 			markdcl() // matching popdcl in caseblock
 			stmt := Nod(OXCASE, nil, nil)
 			var n *Node
-			if cases.Next == nil {
-				n = Nod(OAS, cases.N, rhs)
+			if len(cases) == 1 {
+				n = Nod(OAS, cases[0], rhs)
 			} else {
 				n = Nod(OAS2, nil, nil)
-				n.List = cases
-				n.Rlist = list1(rhs)
+				n.List.Set(cases)
+				n.Rlist.Set1(rhs)
 			}
-			stmt.List = list1(n)
+			stmt.List.Set1(n)
 
 			p.want(':') // consume ':' after declaring select cases for correct lineno
 			return stmt
@@ -863,7 +772,7 @@ func (p *parser) case_(tswitch *Node) *Node {
 			// done in casebody()
 			markdcl() // matching popdcl in caseblock
 			stmt := Nod(OXCASE, nil, nil)
-			stmt.List = list1(colas(cases, list1(rhs), int32(lno)))
+			stmt.List.Set1(colas(cases, []*Node{rhs}, lno))
 
 			p.want(':') // consume ':' after declaring select cases for correct lineno
 			return stmt
@@ -887,7 +796,7 @@ func (p *parser) case_(tswitch *Node) *Node {
 				// type switch - declare variable
 				nn := newname(n.Sym)
 				declare(nn, dclcontext)
-				stmt.Rlist = list1(nn)
+				stmt.Rlist.Set1(nn)
 
 				// keep track of the instances for reporting unused
 				nn.Name.Defn = tswitch
@@ -908,33 +817,21 @@ func (p *parser) case_(tswitch *Node) *Node {
 
 // Block         = "{" StatementList "}" .
 // StatementList = { Statement ";" } .
-func (p *parser) compound_stmt(else_clause bool) *Node {
+func (p *parser) compound_stmt() *Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("compound_stmt")()
 	}
 
 	markdcl()
-	if p.got('{') {
-		// ok
-	} else if else_clause {
-		p.syntax_error("else must be followed by if or statement block")
-		p.advance(LNAME, '}')
-	} else {
-		panic("unreachable")
-	}
-
+	p.want('{')
 	l := p.stmt_list()
 	p.want('}')
-
-	var stmt *Node
-	if l == nil {
-		stmt = Nod(OEMPTY, nil, nil)
-	} else {
-		stmt = liststmt(l)
-	}
 	popdcl()
 
-	return stmt
+	if len(l) == 0 {
+		return Nod(OEMPTY, nil, nil)
+	}
+	return liststmt(l)
 }
 
 // caseblock parses a superset of switch and select clauses.
@@ -949,7 +846,7 @@ func (p *parser) caseblock(tswitch *Node) *Node {
 
 	stmt := p.case_(tswitch) // does markdcl
 	stmt.Xoffset = int64(block)
-	stmt.Nbody = p.stmt_list()
+	stmt.Nbody.Set(p.stmt_list())
 
 	popdcl()
 
@@ -957,7 +854,7 @@ func (p *parser) caseblock(tswitch *Node) *Node {
 }
 
 // caseblock_list parses a superset of switch and select clause lists.
-func (p *parser) caseblock_list(tswitch *Node) (l *NodeList) {
+func (p *parser) caseblock_list(tswitch *Node) (l []*Node) {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("caseblock_list")()
 	}
@@ -968,14 +865,14 @@ func (p *parser) caseblock_list(tswitch *Node) (l *NodeList) {
 	}
 
 	for p.tok != EOF && p.tok != '}' {
-		l = list(l, p.caseblock(tswitch))
+		l = append(l, p.caseblock(tswitch))
 	}
 	p.want('}')
 	return
 }
 
 // loop_body parses if and for statement bodies.
-func (p *parser) loop_body(context string) *NodeList {
+func (p *parser) loop_body(context string) []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("loop_body")()
 	}
@@ -1011,7 +908,7 @@ func (p *parser) for_header() *Node {
 		}
 		h := Nod(OFOR, nil, nil)
 		if init != nil {
-			h.Ninit = list1(init)
+			h.Ninit.Set1(init)
 		}
 		h.Left = cond
 		h.Right = post
@@ -1037,7 +934,7 @@ func (p *parser) for_body() *Node {
 	stmt := p.for_header()
 	body := p.loop_body("for clause")
 
-	stmt.Nbody = concat(stmt.Nbody, body)
+	stmt.Nbody.Append(body...)
 	return stmt
 }
 
@@ -1114,7 +1011,9 @@ func (p *parser) if_header() *Node {
 
 	init, cond, _ := p.header(false)
 	h := Nod(OIF, nil, nil)
-	h.Ninit = list1(init)
+	if init != nil {
+		h.Ninit.Set1(init)
+	}
 	h.Left = cond
 	return h
 }
@@ -1134,69 +1033,29 @@ func (p *parser) if_stmt() *Node {
 		Yyerror("missing condition in if statement")
 	}
 
-	stmt.Nbody = p.loop_body("if clause")
-
-	l := p.elseif_list_else() // does markdcl
+	stmt.Nbody.Set(p.loop_body("if clause"))
 
-	n := stmt
-	popdcl()
-	for nn := l; nn != nil; nn = nn.Next {
-		if nn.N.Op == OIF {
-			popdcl()
+	if p.got(LELSE) {
+		switch p.tok {
+		case LIF:
+			stmt.Rlist.Set1(p.if_stmt())
+		case '{':
+			cs := p.compound_stmt()
+			if cs.Op == OBLOCK && cs.Ninit.Len() == 0 {
+				stmt.Rlist.Set(cs.List.Slice())
+			} else {
+				stmt.Rlist.Set1(cs)
+			}
+		default:
+			p.syntax_error("else must be followed by if or statement block")
+			p.advance(LNAME, '}')
 		}
-		n.Rlist = list1(nn.N)
-		n = nn.N
 	}
 
+	popdcl()
 	return stmt
 }
 
-func (p *parser) elseif() *NodeList {
-	if trace && Debug['x'] != 0 {
-		defer p.trace("elseif")()
-	}
-
-	// LELSE LIF already consumed
-	markdcl() // matching popdcl in if_stmt
-
-	stmt := p.if_header()
-	if stmt.Left == nil {
-		Yyerror("missing condition in if statement")
-	}
-
-	stmt.Nbody = p.loop_body("if clause")
-
-	return list1(stmt)
-}
-
-func (p *parser) elseif_list_else() (l *NodeList) {
-	if trace && Debug['x'] != 0 {
-		defer p.trace("elseif_list_else")()
-	}
-
-	for p.got(LELSE) {
-		if p.got(LIF) {
-			l = concat(l, p.elseif())
-		} else {
-			l = concat(l, p.else_())
-			break
-		}
-	}
-
-	return l
-}
-
-func (p *parser) else_() *NodeList {
-	if trace && Debug['x'] != 0 {
-		defer p.trace("else")()
-	}
-
-	l := &NodeList{N: p.compound_stmt(true)}
-	l.End = l
-	return l
-
-}
-
 // switch_stmt parses both expression and type switch statements.
 //
 // SwitchStmt     = ExprSwitchStmt | TypeSwitchStmt .
@@ -1218,7 +1077,7 @@ func (p *parser) switch_stmt() *Node {
 		tswitch = nil
 	}
 
-	hdr.List = p.caseblock_list(tswitch)
+	hdr.List.Set(p.caseblock_list(tswitch))
 	popdcl()
 
 	return hdr
@@ -1232,59 +1091,22 @@ func (p *parser) select_stmt() *Node {
 
 	p.want(LSELECT)
 	hdr := Nod(OSELECT, nil, nil)
-	hdr.List = p.caseblock_list(nil)
+	hdr.List.Set(p.caseblock_list(nil))
 	return hdr
 }
 
-// TODO(gri) should have lexer return this info - no need for separate lookup
-// (issue 13244)
-var prectab = map[int32]struct {
-	prec int // > 0 (0 indicates not found)
-	op   Op
-}{
-	// not an expression anymore, but left in so we can give a good error
-	// message when used in expression context
-	LCOMM: {1, OSEND},
-
-	LOROR: {2, OOROR},
-
-	LANDAND: {3, OANDAND},
-
-	LEQ: {4, OEQ},
-	LNE: {4, ONE},
-	LLE: {4, OLE},
-	LGE: {4, OGE},
-	LLT: {4, OLT},
-	LGT: {4, OGT},
-
-	'+': {5, OADD},
-	'-': {5, OSUB},
-	'|': {5, OOR},
-	'^': {5, OXOR},
-
-	'*':     {6, OMUL},
-	'/':     {6, ODIV},
-	'%':     {6, OMOD},
-	'&':     {6, OAND},
-	LLSH:    {6, OLSH},
-	LRSH:    {6, ORSH},
-	LANDNOT: {6, OANDNOT},
-}
-
 // Expression = UnaryExpr | Expression binary_op Expression .
-func (p *parser) bexpr(prec int) *Node {
+func (p *parser) bexpr(prec OpPrec) *Node {
 	// don't trace bexpr - only leads to overly nested trace output
 
+	// prec is precedence of the prior/enclosing binary operator (if any),
+	// so we only want to parse tokens of greater precedence.
+
 	x := p.uexpr()
-	t := prectab[p.tok]
-	for tprec := t.prec; tprec >= prec; tprec-- {
-		for tprec == prec {
-			p.next()
-			y := p.bexpr(t.prec + 1)
-			x = Nod(t.op, x, y)
-			t = prectab[p.tok]
-			tprec = t.prec
-		}
+	for p.prec > prec {
+		op, prec1 := p.op, p.prec
+		p.next()
+		x = Nod(op, x, p.bexpr(prec1))
 	}
 	return x
 }
@@ -1294,7 +1116,7 @@ func (p *parser) expr() *Node {
 		defer p.trace("expr")()
 	}
 
-	return p.bexpr(1)
+	return p.bexpr(0)
 }
 
 func unparen(x *Node) *Node {
@@ -1338,13 +1160,6 @@ func (p *parser) uexpr() *Node {
 	case '!':
 		op = ONOT
 
-	case '~':
-		// TODO(gri) do this in the lexer instead (issue 13244)
-		p.next()
-		x := p.uexpr()
-		Yyerror("the bitwise complement operator is ^")
-		return Nod(OCOM, x, nil)
-
 	case '^':
 		op = OCOM
 
@@ -1371,17 +1186,17 @@ func (p *parser) uexpr() *Node {
 
 		if x.Op == OTCHAN {
 			// x is a channel type => re-associate <-
-			dir := EType(Csend)
+			dir := Csend
 			t := x
 			for ; t.Op == OTCHAN && dir == Csend; t = t.Left {
-				dir = t.Etype
+				dir = ChanDir(t.Etype)
 				if dir == Crecv {
 					// t is type <-chan E but <-<-chan E is not permitted
 					// (report same error as for "type _ <-<-chan E")
 					p.syntax_error("unexpected <-, expecting chan")
 					// already progressed, no need to advance
 				}
-				t.Etype = Crecv
+				t.Etype = EType(Crecv)
 			}
 			if dir == Csend {
 				// channel dir is <- but channel element E is not a channel
@@ -1592,20 +1407,17 @@ loop:
 				}
 				x = Nod(OINDEX, x, i)
 			case 1:
-				i := index[0]
-				j := index[1]
-				x = Nod(OSLICE, x, Nod(OKEY, i, j))
+				x = Nod(OSLICE, x, nil)
+				x.SetSliceBounds(index[0], index[1], nil)
 			case 2:
-				i := index[0]
-				j := index[1]
-				k := index[2]
-				if j == nil {
+				if index[1] == nil {
 					Yyerror("middle index required in 3-index slice")
 				}
-				if k == nil {
+				if index[2] == nil {
 					Yyerror("final index required in 3-index slice")
 				}
-				x = Nod(OSLICE3, x, Nod(OKEY, i, Nod(OKEY, j, k)))
+				x = Nod(OSLICE3, x, nil)
+				x.SetSliceBounds(index[0], index[1], index[2])
 
 			default:
 				panic("unreachable")
@@ -1617,7 +1429,7 @@ loop:
 
 			// call or conversion
 			x = Nod(OCALL, x, nil)
-			x.List = args
+			x.List.Set(args)
 			x.Isddd = ddd
 
 		case '{':
@@ -1714,9 +1526,9 @@ func (p *parser) complitexpr() *Node {
 	p.want('{')
 	p.xnest++
 
-	var l *NodeList
+	var l []*Node
 	for p.tok != EOF && p.tok != '}' {
-		l = list(l, p.keyval())
+		l = append(l, p.keyval())
 		if !p.ocomma('}') {
 			break
 		}
@@ -1725,7 +1537,7 @@ func (p *parser) complitexpr() *Node {
 	p.xnest--
 	p.want('}')
 
-	n.List = l
+	n.List.Set(l)
 	return n
 }
 
@@ -1743,13 +1555,15 @@ func (p *parser) new_name(sym *Sym) *Node {
 	return nil
 }
 
-func (p *parser) dcl_name(sym *Sym) *Node {
+func (p *parser) dcl_name() *Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("dcl_name")()
 	}
 
+	symlineno := lineno
+	sym := p.sym()
 	if sym == nil {
-		yyerrorl(int(prevlineno), "invalid declaration")
+		yyerrorl(symlineno, "invalid declaration")
 		return nil
 	}
 	return dclname(sym)
@@ -1770,7 +1584,7 @@ func (p *parser) onew_name() *Node {
 func (p *parser) sym() *Sym {
 	switch p.tok {
 	case LNAME:
-		s := p.sym_
+		s := p.sym_ // from localpkg
 		p.next()
 		// during imports, unqualified non-exported identifiers are from builtinpkg
 		if importpkg != nil && !exportname(s.Name) {
@@ -1837,6 +1651,30 @@ func (p *parser) ntype() *Node {
 	return nil
 }
 
+// signature parses a function signature and returns an OTFUNC node.
+//
+// Signature = Parameters [ Result ] .
+func (p *parser) signature(recv *Node) *Node {
+	if trace && Debug['x'] != 0 {
+		defer p.trace("signature")()
+	}
+
+	params := p.param_list(true)
+
+	var result []*Node
+	if p.tok == '(' {
+		result = p.param_list(false)
+	} else if t := p.try_ntype(); t != nil {
+		result = []*Node{Nod(ODCLFIELD, nil, t)}
+	}
+
+	typ := Nod(OTFUNC, recv, nil)
+	typ.List.Set(params)
+	typ.Rlist.Set(result)
+
+	return typ
+}
+
 // try_ntype is like ntype but it returns nil if there was no type
 // instead of reporting an error.
 //
@@ -1855,19 +1693,13 @@ func (p *parser) try_ntype() *Node {
 		p.next()
 		p.want(LCHAN)
 		t := Nod(OTCHAN, p.chan_elem(), nil)
-		t.Etype = Crecv
+		t.Etype = EType(Crecv)
 		return t
 
 	case LFUNC:
 		// fntype
 		p.next()
-		params := p.param_list()
-		result := p.fnres()
-		params = checkarglist(params, 1)
-		t := Nod(OTFUNC, nil, nil)
-		t.List = params
-		t.Rlist = result
-		return t
+		return p.signature(nil)
 
 	case '[':
 		// '[' oexpr ']' ntype
@@ -1890,9 +1722,9 @@ func (p *parser) try_ntype() *Node {
 		// LCHAN non_recvchantype
 		// LCHAN LCOMM ntype
 		p.next()
-		var dir EType = Cboth
+		var dir = EType(Cboth)
 		if p.got(LCOMM) {
-			dir = Csend
+			dir = EType(Csend)
 		}
 		t := Nod(OTCHAN, p.chan_elem(), nil)
 		t.Etype = dir
@@ -1946,19 +1778,18 @@ func (p *parser) chan_elem() *Node {
 	return nil
 }
 
-func (p *parser) new_dotname(pkg *Node) *Node {
+func (p *parser) new_dotname(obj *Node) *Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("new_dotname")()
 	}
 
 	sel := p.sym()
-	if pkg.Op == OPACK {
-		s := restrictlookup(sel.Name, pkg.Name.Pkg)
-		pkg.Used = true
+	if obj.Op == OPACK {
+		s := restrictlookup(sel.Name, obj.Name.Pkg)
+		obj.Used = true
 		return oldname(s)
 	}
-	return Nod(OXDOT, pkg, newname(sel))
-
+	return NodSym(OXDOT, obj, sel)
 }
 
 func (p *parser) dotname() *Node {
@@ -1981,9 +1812,9 @@ func (p *parser) structtype() *Node {
 
 	p.want(LSTRUCT)
 	p.want('{')
-	var l *NodeList
+	var l []*Node
 	for p.tok != EOF && p.tok != '}' {
-		l = concat(l, p.structdcl())
+		l = append(l, p.structdcl()...)
 		if !p.osemi('}') {
 			break
 		}
@@ -1991,7 +1822,7 @@ func (p *parser) structtype() *Node {
 	p.want('}')
 
 	t := Nod(OTSTRUCT, nil, nil)
-	t.List = l
+	t.List.Set(l)
 	return t
 }
 
@@ -2003,9 +1834,9 @@ func (p *parser) interfacetype() *Node {
 
 	p.want(LINTERFACE)
 	p.want('{')
-	var l *NodeList
+	var l []*Node
 	for p.tok != EOF && p.tok != '}' {
-		l = list(l, p.interfacedcl())
+		l = append(l, p.interfacedcl())
 		if !p.osemi('}') {
 			break
 		}
@@ -2013,7 +1844,7 @@ func (p *parser) interfacetype() *Node {
 	p.want('}')
 
 	t := Nod(OTINTER, nil, nil)
-	t.List = l
+	t.List.Set(l)
 	return t
 }
 
@@ -2032,19 +1863,15 @@ func (p *parser) xfndcl() *Node {
 	if f == nil {
 		return nil
 	}
-	if noescape && body != nil {
+
+	f.Nbody.Set(body)
+	f.Noescape = p.pragma&Noescape != 0
+	if f.Noescape && len(body) != 0 {
 		Yyerror("can only use //go:noescape with external func implementations")
 	}
-
-	f.Nbody = body
+	f.Func.Pragma = p.pragma
 	f.Func.Endlineno = lineno
-	f.Noescape = noescape
-	f.Func.Norace = norace
-	f.Func.Nosplit = nosplit
-	f.Func.Noinline = noinline
-	f.Func.Nowritebarrier = nowritebarrier
-	f.Func.Nowritebarrierrec = nowritebarrierrec
-	f.Func.Systemstack = systemstack
+
 	funcbody(f)
 
 	return f
@@ -2062,30 +1889,23 @@ func (p *parser) fndcl() *Node {
 
 	switch p.tok {
 	case LNAME, '@', '?':
-		// sym '(' oarg_type_list_ocomma ')' fnres
+		// FunctionName Signature
 		name := p.sym()
-		params := p.param_list()
-		result := p.fnres()
-
-		params = checkarglist(params, 1)
+		t := p.signature(nil)
 
 		if name.Name == "init" {
 			name = renameinit()
-			if params != nil || result != nil {
+			if t.List.Len() > 0 || t.Rlist.Len() > 0 {
 				Yyerror("func init must have no arguments and no return values")
 			}
 		}
 
 		if localpkg.Name == "main" && name.Name == "main" {
-			if params != nil || result != nil {
+			if t.List.Len() > 0 || t.Rlist.Len() > 0 {
 				Yyerror("func main must have no arguments and no return values")
 			}
 		}
 
-		t := Nod(OTFUNC, nil, nil)
-		t.List = params
-		t.Rlist = result
-
 		f := Nod(ODCLFUNC, nil, nil)
 		f.Func.Nname = newfuncname(name)
 		f.Func.Nname.Name.Defn = f
@@ -2096,41 +1916,36 @@ func (p *parser) fndcl() *Node {
 		return f
 
 	case '(':
-		// '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
-		rparam := p.param_list()
+		// Receiver MethodName Signature
+		rparam := p.param_list(false)
+		var recv *Node
+		if len(rparam) > 0 {
+			recv = rparam[0]
+		}
 		name := p.sym()
-		params := p.param_list()
-		result := p.fnres()
-
-		rparam = checkarglist(rparam, 0)
-		params = checkarglist(params, 1)
+		t := p.signature(recv)
 
-		if rparam == nil {
+		// check after parsing header for fault-tolerance
+		if recv == nil {
 			Yyerror("method has no receiver")
 			return nil
 		}
 
-		if rparam.Next != nil {
+		if len(rparam) > 1 {
 			Yyerror("method has multiple receivers")
 			return nil
 		}
 
-		rcvr := rparam.N
-		if rcvr.Op != ODCLFIELD {
+		if recv.Op != ODCLFIELD {
 			Yyerror("bad receiver in method")
 			return nil
 		}
 
-		t := Nod(OTFUNC, rcvr, nil)
-		t.List = params
-		t.Rlist = result
-
 		f := Nod(ODCLFUNC, nil, nil)
 		f.Func.Shortname = newfuncname(name)
-		f.Func.Nname = methodname1(f.Func.Shortname, rcvr.Right)
+		f.Func.Nname = methodname1(f.Func.Shortname, recv.Right)
 		f.Func.Nname.Name.Defn = f
 		f.Func.Nname.Name.Param.Ntype = t
-		f.Func.Nname.Nointerface = nointerface
 		declare(f.Func.Nname, PFUNC)
 
 		funchdr(f)
@@ -2187,25 +2002,25 @@ func (p *parser) hidden_fndcl() *Node {
 		p.want(')')
 		s8 := p.ohidden_funres()
 
-		ss := methodname1(newname(s4), s2.N.Right)
-		ss.Type = functype(s2.N, s6, s8)
+		ss := methodname1(newname(s4), s2[0].Right)
+		ss.Type = functype(s2[0], s6, s8)
 
 		checkwidth(ss.Type)
-		addmethod(s4, ss.Type, false, nointerface)
-		nointerface = false
+		addmethod(s4, ss.Type, p.structpkg, false, p.pragma&Nointerface != 0)
+		p.pragma = 0
 		funchdr(ss)
 
 		// 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
+		// out by typecheck's lookdot as this $$.ttype. So by providing
 		// this back link here we avoid special casing there.
-		ss.Type.Nname = ss
+		ss.Type.SetNname(ss)
 		return ss
 	}
 }
 
 // FunctionBody = Block .
-func (p *parser) fnbody() *NodeList {
+func (p *parser) fnbody() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("fnbody")()
 	}
@@ -2216,7 +2031,7 @@ func (p *parser) fnbody() *NodeList {
 		p.fnest--
 		p.want('}')
 		if body == nil {
-			body = list1(Nod(OEMPTY, nil, nil))
+			body = []*Node{Nod(OEMPTY, nil, nil)}
 		}
 		return body
 	}
@@ -2224,80 +2039,52 @@ func (p *parser) fnbody() *NodeList {
 	return nil
 }
 
-// Result = Parameters | Type .
-func (p *parser) fnres() *NodeList {
-	if trace && Debug['x'] != 0 {
-		defer p.trace("fnres")()
-	}
-
-	if p.tok == '(' {
-		result := p.param_list()
-		return checkarglist(result, 0)
-	}
-
-	if result := p.try_ntype(); result != nil {
-		return list1(Nod(ODCLFIELD, nil, result))
-	}
-
-	return nil
-}
-
 // Declaration  = ConstDecl | TypeDecl | VarDecl .
 // TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
-func (p *parser) xdcl_list() (l *NodeList) {
+func (p *parser) xdcl_list() (l []*Node) {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("xdcl_list")()
 	}
 
-loop:
 	for p.tok != EOF {
 		switch p.tok {
 		case LVAR, LCONST, LTYPE:
-			l = concat(l, p.common_dcl())
+			l = append(l, p.common_dcl()...)
 
 		case LFUNC:
-			l = list(l, p.xfndcl())
+			l = append(l, p.xfndcl())
 
 		default:
-			if p.tok == '{' && l != nil && l.End.N.Op == ODCLFUNC && l.End.N.Nbody == nil {
+			if p.tok == '{' && len(l) != 0 && l[len(l)-1].Op == ODCLFUNC && l[len(l)-1].Nbody.Len() == 0 {
 				// opening { of function declaration on next line
 				p.syntax_error("unexpected semicolon or newline before {")
 			} else {
 				p.syntax_error("non-declaration statement outside function body")
 			}
 			p.advance(LVAR, LCONST, LTYPE, LFUNC)
-			goto loop
-		}
-
-		if nsyntaxerrors == 0 {
-			testdclstack()
+			continue
 		}
 
-		noescape = false
-		noinline = false
-		nointerface = false
-		norace = false
-		nosplit = false
-		nowritebarrier = false
-		nowritebarrierrec = false
-		systemstack = false
+		// Reset p.pragma BEFORE advancing to the next token (consuming ';')
+		// since comments before may set pragmas for the next function decl.
+		p.pragma = 0
 
-		// Consume ';' AFTER resetting the above flags since
-		// it may read the subsequent comment line which may
-		// set the flags for the next function declaration.
 		if p.tok != EOF && !p.got(';') {
 			p.syntax_error("after top level declaration")
 			p.advance(LVAR, LCONST, LTYPE, LFUNC)
-			goto loop
 		}
 	}
+
+	if nsyntaxerrors == 0 {
+		testdclstack()
+	}
 	return
 }
 
 // FieldDecl      = (IdentifierList Type | AnonymousField) [ Tag ] .
 // AnonymousField = [ "*" ] TypeName .
 // Tag            = string_lit .
-func (p *parser) structdcl() *NodeList {
+func (p *parser) structdcl() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("structdcl")()
 	}
@@ -2316,7 +2103,7 @@ func (p *parser) structdcl() *NodeList {
 			tag := p.oliteral()
 
 			field.SetVal(tag)
-			return list1(field)
+			return []*Node{field}
 		}
 
 		// LNAME belongs to first *Sym of new_name_list
@@ -2336,8 +2123,8 @@ func (p *parser) structdcl() *NodeList {
 		typ := p.ntype()
 		tag := p.oliteral()
 
-		if l := fields; l == nil || l.N.Sym.Name == "?" {
-			// ? symbol, during import (list1(nil) == nil)
+		if len(fields) == 0 || fields[0].Sym.Name == "?" {
+			// ? symbol, during import
 			n := typ
 			if n.Op == OIND {
 				n = n.Left
@@ -2345,12 +2132,12 @@ func (p *parser) structdcl() *NodeList {
 			n = embedded(n.Sym, importpkg)
 			n.Right = typ
 			n.SetVal(tag)
-			return list1(n)
+			return []*Node{n}
 		}
 
-		for l := fields; l != nil; l = l.Next {
-			l.N = Nod(ODCLFIELD, l.N, typ)
-			l.N.SetVal(tag)
+		for i, n := range fields {
+			fields[i] = Nod(ODCLFIELD, n, typ)
+			fields[i].SetVal(tag)
 		}
 		return fields
 
@@ -2365,7 +2152,7 @@ func (p *parser) structdcl() *NodeList {
 			field.Right = Nod(OIND, field.Right, nil)
 			field.SetVal(tag)
 			Yyerror("cannot parenthesize embedded type")
-			return list1(field)
+			return []*Node{field}
 
 		} else {
 			// '(' embed ')' oliteral
@@ -2375,7 +2162,7 @@ func (p *parser) structdcl() *NodeList {
 
 			field.SetVal(tag)
 			Yyerror("cannot parenthesize embedded type")
-			return list1(field)
+			return []*Node{field}
 		}
 
 	case '*':
@@ -2389,7 +2176,7 @@ func (p *parser) structdcl() *NodeList {
 			field.Right = Nod(OIND, field.Right, nil)
 			field.SetVal(tag)
 			Yyerror("cannot parenthesize embedded type")
-			return list1(field)
+			return []*Node{field}
 
 		} else {
 			// '*' embed oliteral
@@ -2398,7 +2185,7 @@ func (p *parser) structdcl() *NodeList {
 
 			field.Right = Nod(OIND, field.Right, nil)
 			field.SetVal(tag)
-			return list1(field)
+			return []*Node{field}
 		}
 
 	default:
@@ -2493,16 +2280,17 @@ func (p *parser) interfacedcl() *Node {
 			return Nod(ODCLFIELD, nil, oldname(pname))
 		}
 
-		// newname indcl
+		// MethodName Signature
 		mname := newname(sym)
-		sig := p.indcl()
+		sig := p.signature(fakethis())
 
 		meth := Nod(ODCLFIELD, mname, sig)
 		ifacedcl(meth)
 		return meth
 
 	case '@', '?':
-		// newname indcl
+		// MethodName Signature
+		//
 		// We arrive here when parsing an interface type declared inside
 		// an exported and inlineable function and the interface declares
 		// unexported methods (which are then package-qualified).
@@ -2513,7 +2301,7 @@ func (p *parser) interfacedcl() *Node {
 		//
 		// See also issue 14164.
 		mname := newname(p.sym())
-		sig := p.indcl()
+		sig := p.signature(fakethis())
 
 		meth := Nod(ODCLFIELD, mname, sig)
 		ifacedcl(meth)
@@ -2534,92 +2322,165 @@ func (p *parser) interfacedcl() *Node {
 	}
 }
 
-// MethodSpec = MethodName Signature .
-// MethodName = identifier .
-func (p *parser) indcl() *Node {
-	if trace && Debug['x'] != 0 {
-		defer p.trace("indcl")()
-	}
-
-	params := p.param_list()
-	result := p.fnres()
-
-	// without func keyword
-	params = checkarglist(params, 1)
-	t := Nod(OTFUNC, fakethis(), nil)
-	t.List = params
-	t.Rlist = result
-
-	return t
-}
-
-// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
-func (p *parser) arg_type() *Node {
+// param parses and returns a function parameter list entry which may be
+// a parameter name and type pair (name, typ), a single type (nil, typ),
+// or a single name (name, nil). In the last case, the name may still be
+// a type name. The result is (nil, nil) in case of a syntax error.
+//
+// [ParameterName] Type
+func (p *parser) param() (name *Sym, typ *Node) {
 	if trace && Debug['x'] != 0 {
-		defer p.trace("arg_type")()
+		defer p.trace("param")()
 	}
 
 	switch p.tok {
 	case LNAME, '@', '?':
-		name := p.sym()
+		name = p.sym() // nil if p.tok == '?' (importing only)
 		switch p.tok {
 		case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', LNAME, '@', '?', '(':
 			// sym name_or_type
-			typ := p.ntype()
-			nn := Nod(ONONAME, nil, nil)
-			nn.Sym = name
-			return Nod(OKEY, nn, typ)
+			typ = p.ntype()
 
 		case LDDD:
 			// sym dotdotdot
-			typ := p.dotdotdot()
-			nn := Nod(ONONAME, nil, nil)
-			nn.Sym = name
-			return Nod(OKEY, nn, typ)
+			typ = p.dotdotdot()
 
 		default:
 			// name_or_type
-			name := mkname(name)
-			// from dotname
 			if p.got('.') {
-				return p.new_dotname(name)
+				// a qualified name cannot be a parameter name
+				typ = p.new_dotname(mkname(name))
+				name = nil
 			}
-			return name
 		}
 
 	case LDDD:
 		// dotdotdot
-		return p.dotdotdot()
+		typ = p.dotdotdot()
 
 	case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', '(':
 		// name_or_type
-		return p.ntype()
+		typ = p.ntype()
 
 	default:
 		p.syntax_error("expecting )")
 		p.advance(',', ')')
-		return nil
 	}
+
+	return
 }
 
 // Parameters    = "(" [ ParameterList [ "," ] ] ")" .
 // ParameterList = ParameterDecl { "," ParameterDecl } .
-func (p *parser) param_list() (l *NodeList) {
+// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
+func (p *parser) param_list(dddOk bool) []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("param_list")()
 	}
 
-	p.want('(')
+	type param struct {
+		name *Sym
+		typ  *Node
+	}
+	var params []param
+	var named int // number of parameters that have a name and type
 
+	p.want('(')
 	for p.tok != EOF && p.tok != ')' {
-		l = list(l, p.arg_type())
+		name, typ := p.param()
+		params = append(params, param{name, typ})
+		if name != nil && typ != nil {
+			named++
+		}
 		if !p.ocomma(')') {
 			break
 		}
 	}
-
 	p.want(')')
-	return
+	// 0 <= named <= len(params)
+
+	// There are 3 cases:
+	//
+	// 1) named == 0:
+	//    No parameter list entry has both a name and a type; i.e. there are only
+	//    unnamed parameters. Any name must be a type name; they are "converted"
+	//    to types when creating the final parameter list.
+	//    In case of a syntax error, there is neither a name nor a type.
+	//    Nil checks take care of this.
+	//
+	// 2) named == len(names):
+	//    All parameter list entries have both a name and a type.
+	//
+	// 3) Otherwise:
+	if named != 0 && named != len(params) {
+		// Some parameter list entries have both a name and a type:
+		// Distribute types backwards and check that there are no
+		// mixed named and unnamed parameters.
+		var T *Node // type T in a parameter sequence: a, b, c T
+		for i := len(params) - 1; i >= 0; i-- {
+			p := &params[i]
+			if t := p.typ; t != nil {
+				// explicit type: use type for earlier parameters
+				T = t
+				// an explicitly typed entry must have a name
+				// TODO(gri) remove extra importpkg == nil check below
+				//           after switch to binary eport format
+				// Exported inlined function bodies containing function
+				// literals may print parameter names as '?' resulting
+				// in nil *Sym and thus nil names. Don't report an error
+				// in this case.
+				if p.name == nil && importpkg == nil {
+					T = nil // error
+				}
+			} else {
+				// no explicit type: use type of next parameter
+				p.typ = T
+			}
+			if T == nil {
+				Yyerror("mixed named and unnamed function parameters")
+				break
+			}
+		}
+		// Unless there was an error, now all parameter entries have a type.
+	}
+
+	// create final parameter list
+	list := make([]*Node, len(params))
+	for i, p := range params {
+		// create dcl node
+		var name, typ *Node
+		if p.typ != nil {
+			typ = p.typ
+			if p.name != nil {
+				// name must be a parameter name
+				name = newname(p.name)
+			}
+		} else if p.name != nil {
+			// p.name must be a type name (or nil in case of syntax error)
+			typ = mkname(p.name)
+		}
+		n := Nod(ODCLFIELD, name, typ)
+
+		// rewrite ...T parameter
+		if typ != nil && typ.Op == ODDD {
+			if !dddOk {
+				Yyerror("cannot use ... in receiver or result parameter list")
+			} else if i+1 < len(params) {
+				Yyerror("can only use ... with final parameter in list")
+			}
+			typ.Op = OTARRAY
+			typ.Right = typ.Left
+			typ.Left = nil
+			n.Isddd = true
+			if n.Left != nil {
+				n.Left.Isddd = true
+			}
+		}
+
+		list[i] = n
+	}
+
+	return list
 }
 
 var missing_stmt = Nod(OXXX, nil, nil)
@@ -2638,14 +2499,14 @@ func (p *parser) stmt() *Node {
 
 	switch p.tok {
 	case '{':
-		return p.compound_stmt(false)
+		return p.compound_stmt()
 
 	case LVAR, LCONST, LTYPE:
 		return liststmt(p.common_dcl())
 
 	case LNAME, '@', '?', LLITERAL, LFUNC, '(', // operands
 		'[', LSTRUCT, LMAP, LCHAN, LINTERFACE, // composite types
-		'+', '-', '*', '&', '^', '~', LCOMM, '!': // unary operators
+		'+', '-', '*', '&', '^', LCOMM, '!': // unary operators
 		return p.simple_stmt(true, false)
 
 	case LFOR:
@@ -2691,23 +2552,23 @@ func (p *parser) stmt() *Node {
 
 	case LRETURN:
 		p.next()
-		var results *NodeList
+		var results []*Node
 		if p.tok != ';' && p.tok != '}' {
 			results = p.expr_list()
 		}
 
 		stmt := Nod(ORETURN, nil, nil)
-		stmt.List = results
-		if stmt.List == nil && Curfn != nil {
-			for l := Curfn.Func.Dcl; l != nil; l = l.Next {
-				if l.N.Class == PPARAM {
+		stmt.List.Set(results)
+		if stmt.List.Len() == 0 && Curfn != nil {
+			for _, ln := range Curfn.Func.Dcl {
+				if ln.Class == PPARAM {
 					continue
 				}
-				if l.N.Class != PPARAMOUT {
+				if ln.Class != PPARAMOUT {
 					break
 				}
-				if l.N.Sym.Def != l.N {
-					Yyerror("%s is shadowed during return", l.N.Sym.Name)
+				if ln.Sym.Def != ln {
+					Yyerror("%s is shadowed during return", ln.Sym.Name)
 				}
 			}
 		}
@@ -2723,7 +2584,7 @@ func (p *parser) stmt() *Node {
 }
 
 // StatementList = { Statement ";" } .
-func (p *parser) stmt_list() (l *NodeList) {
+func (p *parser) stmt_list() (l []*Node) {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("stmt_list")()
 	}
@@ -2733,7 +2594,12 @@ func (p *parser) stmt_list() (l *NodeList) {
 		if s == missing_stmt {
 			break
 		}
-		l = list(l, s)
+		if s == nil {
+		} else if s.Op == OBLOCK && s.Ninit.Len() == 0 {
+			l = append(l, s.List.Slice()...)
+		} else {
+			l = append(l, s)
+		}
 		// customized version of osemi:
 		// ';' is optional before a closing ')' or '}'
 		if p.tok == ')' || p.tok == '}' {
@@ -2750,7 +2616,7 @@ func (p *parser) stmt_list() (l *NodeList) {
 // IdentifierList = identifier { "," identifier } .
 //
 // If first != nil we have the first symbol already.
-func (p *parser) new_name_list(first *Sym) *NodeList {
+func (p *parser) new_name_list(first *Sym) []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("new_name_list")()
 	}
@@ -2758,41 +2624,48 @@ func (p *parser) new_name_list(first *Sym) *NodeList {
 	if first == nil {
 		first = p.sym() // may still be nil
 	}
-	l := list1(p.new_name(first))
+	var l []*Node
+	n := p.new_name(first)
+	if n != nil {
+		l = append(l, n)
+	}
 	for p.got(',') {
-		l = list(l, p.new_name(p.sym()))
+		n = p.new_name(p.sym())
+		if n != nil {
+			l = append(l, n)
+		}
 	}
 	return l
 }
 
 // IdentifierList = identifier { "," identifier } .
-func (p *parser) dcl_name_list() *NodeList {
+func (p *parser) dcl_name_list() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("dcl_name_list")()
 	}
 
-	l := list1(p.dcl_name(p.sym()))
+	s := []*Node{p.dcl_name()}
 	for p.got(',') {
-		l = list(l, p.dcl_name(p.sym()))
+		s = append(s, p.dcl_name())
 	}
-	return l
+	return s
 }
 
 // ExpressionList = Expression { "," Expression } .
-func (p *parser) expr_list() *NodeList {
+func (p *parser) expr_list() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("expr_list")()
 	}
 
-	l := list1(p.expr())
+	l := []*Node{p.expr()}
 	for p.got(',') {
-		l = list(l, p.expr())
+		l = append(l, p.expr())
 	}
 	return l
 }
 
 // Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
-func (p *parser) arg_list() (l *NodeList, ddd bool) {
+func (p *parser) arg_list() (l []*Node, ddd bool) {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("arg_list")()
 	}
@@ -2801,7 +2674,7 @@ func (p *parser) arg_list() (l *NodeList, ddd bool) {
 	p.xnest++
 
 	for p.tok != EOF && p.tok != ')' && !ddd {
-		l = list(l, p.expr()) // expr_or_type
+		l = append(l, p.expr()) // expr_or_type
 		ddd = p.got(LDDD)
 		if !p.ocomma(')') {
 			break
@@ -2914,36 +2787,36 @@ func (p *parser) hidden_importsym() *Sym {
 	}
 }
 
-func (p *parser) ohidden_funarg_list() *NodeList {
+func (p *parser) ohidden_funarg_list() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("ohidden_funarg_list")()
 	}
 
-	var ss *NodeList
+	var ss []*Node
 	if p.tok != ')' {
 		ss = p.hidden_funarg_list()
 	}
 	return ss
 }
 
-func (p *parser) ohidden_structdcl_list() *NodeList {
+func (p *parser) ohidden_structdcl_list() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("ohidden_structdcl_list")()
 	}
 
-	var ss *NodeList
+	var ss []*Node
 	if p.tok != '}' {
 		ss = p.hidden_structdcl_list()
 	}
 	return ss
 }
 
-func (p *parser) ohidden_interfacedcl_list() *NodeList {
+func (p *parser) ohidden_interfacedcl_list() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("ohidden_interfacedcl_list")()
 	}
 
-	var ss *NodeList
+	var ss []*Node
 	if p.tok != '}' {
 		ss = p.hidden_interfacedcl_list()
 	}
@@ -3023,14 +2896,14 @@ func (p *parser) hidden_import() {
 			return
 		}
 
-		s2.Func.Inl = s3
+		s2.Func.Inl.Set(s3)
 
 		funcbody(s2)
 		importlist = append(importlist, s2)
 
 		if Debug['E'] > 0 {
 			fmt.Printf("import [%q] func %v \n", importpkg.Path, s2)
-			if Debug['m'] > 2 && s2.Func.Inl != nil {
+			if Debug['m'] > 2 && s2.Func.Inl.Len() != 0 {
 				fmt.Printf("inl body:%v\n", s2.Func.Inl)
 			}
 		}
@@ -3045,12 +2918,9 @@ func (p *parser) hidden_pkg_importsym() *Sym {
 		defer p.trace("hidden_pkg_importsym")()
 	}
 
-	s1 := p.hidden_importsym()
-
-	ss := s1
-	structpkg = ss.Pkg
-
-	return ss
+	s := p.hidden_importsym()
+	p.structpkg = s.Pkg
+	return s
 }
 
 func (p *parser) hidden_pkgtype() *Type {
@@ -3058,12 +2928,7 @@ func (p *parser) hidden_pkgtype() *Type {
 		defer p.trace("hidden_pkgtype")()
 	}
 
-	s1 := p.hidden_pkg_importsym()
-
-	ss := pkgtype(s1)
-	importsym(s1, OTYPE)
-
-	return ss
+	return pkgtype(p.hidden_pkg_importsym())
 }
 
 // ----------------------------------------------------------------------------
@@ -3144,7 +3009,7 @@ func (p *parser) hidden_type_misc() *Type {
 		p.want(']')
 		s5 := p.hidden_type()
 
-		return maptype(s3, s5)
+		return typMap(s3, s5)
 
 	case LSTRUCT:
 		// LSTRUCT '{' ohidden_structdcl_list '}'
@@ -3176,9 +3041,7 @@ func (p *parser) hidden_type_misc() *Type {
 		default:
 			// LCHAN hidden_type_non_recv_chan
 			s2 := p.hidden_type_non_recv_chan()
-			ss := typ(TCHAN)
-			ss.Type = s2
-			ss.Chan = Cboth
+			ss := typChan(s2, Cboth)
 			return ss
 
 		case '(':
@@ -3186,18 +3049,14 @@ func (p *parser) hidden_type_misc() *Type {
 			p.next()
 			s3 := p.hidden_type_recv_chan()
 			p.want(')')
-			ss := typ(TCHAN)
-			ss.Type = s3
-			ss.Chan = Cboth
+			ss := typChan(s3, Cboth)
 			return ss
 
 		case LCOMM:
 			// LCHAN hidden_type
 			p.next()
 			s3 := p.hidden_type()
-			ss := typ(TCHAN)
-			ss.Type = s3
-			ss.Chan = Csend
+			ss := typChan(s3, Csend)
 			return ss
 		}
 
@@ -3216,9 +3075,7 @@ func (p *parser) hidden_type_recv_chan() *Type {
 	p.want(LCHAN)
 	s3 := p.hidden_type()
 
-	ss := typ(TCHAN)
-	ss.Type = s3
-	ss.Chan = Crecv
+	ss := typChan(s3, Crecv)
 	return ss
 }
 
@@ -3259,11 +3116,7 @@ func (p *parser) hidden_funarg() *Node {
 		s3 := p.hidden_type()
 		s4 := p.oliteral()
 
-		var t *Type
-
-		t = typ(TARRAY)
-		t.Bound = -1
-		t.Type = s3
+		t := typSlice(s3)
 
 		ss := Nod(ODCLFIELD, nil, typenod(t))
 		if s1 != nil {
@@ -3285,19 +3138,16 @@ func (p *parser) hidden_structdcl() *Node {
 	s2 := p.hidden_type()
 	s3 := p.oliteral()
 
-	var s *Sym
-	var pkg *Pkg
-
 	var ss *Node
 	if s1 != nil && s1.Name != "?" {
 		ss = Nod(ODCLFIELD, newname(s1), typenod(s2))
 		ss.SetVal(s3)
 	} else {
-		s = s2.Sym
-		if s == nil && Isptr[s2.Etype] {
-			s = s2.Type.Sym
+		s := s2.Sym
+		if s == nil && s2.IsPtr() {
+			s = s2.Elem().Sym
 		}
-		pkg = importpkg
+		pkg := importpkg
 		if s1 != nil {
 			pkg = s1.Pkg
 		}
@@ -3342,7 +3192,7 @@ func (p *parser) hidden_interfacedcl() *Node {
 	return Nod(ODCLFIELD, newname(s1), typenod(functype(fakethis(), s3, s5)))
 }
 
-func (p *parser) ohidden_funres() *NodeList {
+func (p *parser) ohidden_funres() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("ohidden_funres")()
 	}
@@ -3356,7 +3206,7 @@ func (p *parser) ohidden_funres() *NodeList {
 	}
 }
 
-func (p *parser) hidden_funres() *NodeList {
+func (p *parser) hidden_funres() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("hidden_funres")()
 	}
@@ -3370,7 +3220,7 @@ func (p *parser) hidden_funres() *NodeList {
 
 	default:
 		s1 := p.hidden_type()
-		return list1(Nod(ODCLFIELD, nil, typenod(s1)))
+		return []*Node{Nod(ODCLFIELD, nil, typenod(s1))}
 	}
 }
 
@@ -3393,17 +3243,14 @@ func (p *parser) hidden_literal() *Node {
 		if p.tok == LLITERAL {
 			ss := nodlit(p.val)
 			p.next()
-			switch ss.Val().Ctype() {
-			case CTINT, CTRUNE:
-				mpnegfix(ss.Val().U.(*Mpint))
-				break
-			case CTFLT:
-				mpnegflt(ss.Val().U.(*Mpflt))
-				break
-			case CTCPLX:
-				mpnegflt(&ss.Val().U.(*Mpcplx).Real)
-				mpnegflt(&ss.Val().U.(*Mpcplx).Imag)
-				break
+			switch u := ss.Val().U.(type) {
+			case *Mpint:
+				u.Neg()
+			case *Mpflt:
+				u.Neg()
+			case *Mpcplx:
+				u.Real.Neg()
+				u.Imag.Neg()
 			default:
 				Yyerror("bad negated constant")
 			}
@@ -3444,11 +3291,11 @@ func (p *parser) hidden_constant() *Node {
 
 		if s2.Val().Ctype() == CTRUNE && s4.Val().Ctype() == CTINT {
 			ss := s2
-			mpaddfixfix(s2.Val().U.(*Mpint), s4.Val().U.(*Mpint), 0)
+			s2.Val().U.(*Mpint).Add(s4.Val().U.(*Mpint))
 			return ss
 		}
 		s4.Val().U.(*Mpcplx).Real = s4.Val().U.(*Mpcplx).Imag
-		Mpmovecflt(&s4.Val().U.(*Mpcplx).Imag, 0.0)
+		s4.Val().U.(*Mpcplx).Imag.SetFloat64(0.0)
 		return nodcplxlit(s2.Val(), s4.Val())
 	}
 }
@@ -3463,44 +3310,44 @@ func (p *parser) hidden_import_list() {
 	}
 }
 
-func (p *parser) hidden_funarg_list() *NodeList {
+func (p *parser) hidden_funarg_list() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("hidden_funarg_list")()
 	}
 
 	s1 := p.hidden_funarg()
-	ss := list1(s1)
+	ss := []*Node{s1}
 	for p.got(',') {
 		s3 := p.hidden_funarg()
-		ss = list(ss, s3)
+		ss = append(ss, s3)
 	}
 	return ss
 }
 
-func (p *parser) hidden_structdcl_list() *NodeList {
+func (p *parser) hidden_structdcl_list() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("hidden_structdcl_list")()
 	}
 
 	s1 := p.hidden_structdcl()
-	ss := list1(s1)
+	ss := []*Node{s1}
 	for p.got(';') {
 		s3 := p.hidden_structdcl()
-		ss = list(ss, s3)
+		ss = append(ss, s3)
 	}
 	return ss
 }
 
-func (p *parser) hidden_interfacedcl_list() *NodeList {
+func (p *parser) hidden_interfacedcl_list() []*Node {
 	if trace && Debug['x'] != 0 {
 		defer p.trace("hidden_interfacedcl_list")()
 	}
 
 	s1 := p.hidden_interfacedcl()
-	ss := list1(s1)
+	ss := []*Node{s1}
 	for p.got(';') {
 		s3 := p.hidden_interfacedcl()
-		ss = list(ss, s3)
+		ss = append(ss, s3)
 	}
 	return ss
 }
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index ffc0ab9..da2e675 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -5,20 +5,22 @@
 package gc
 
 import (
+	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
-	"crypto/md5"
+	"cmd/internal/sys"
 	"fmt"
+	"sort"
 	"strings"
 )
 
 // "Portable" code generation.
 
-var makefuncdatasym_nsym int32
+var makefuncdatasym_nsym int
 
-func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
+func makefuncdatasym(nameprefix string, funcdatakind int64) *Sym {
 	var nod Node
 
-	sym := Lookupf(namefmt, makefuncdatasym_nsym)
+	sym := LookupN(nameprefix, makefuncdatasym_nsym)
 	makefuncdatasym_nsym++
 	pnod := newname(sym)
 	pnod.Class = PEXTERN
@@ -83,12 +85,12 @@ func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
 // 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) {
+func gvardefx(n *Node, as obj.As) {
 	if n == nil {
 		Fatalf("gvardef nil")
 	}
 	if n.Op != ONAME {
-		Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), n)
+		Yyerror("gvardef %#v; %v", n.Op, n)
 		return
 	}
 
@@ -106,11 +108,11 @@ func Gvardef(n *Node) {
 	gvardefx(n, obj.AVARDEF)
 }
 
-func gvarkill(n *Node) {
+func Gvarkill(n *Node) {
 	gvardefx(n, obj.AVARKILL)
 }
 
-func gvarlive(n *Node) {
+func Gvarlive(n *Node) {
 	gvardefx(n, obj.AVARLIVE)
 }
 
@@ -127,46 +129,37 @@ func removevardef(firstp *obj.Prog) {
 	}
 }
 
-func gcsymdup(s *Sym) {
-	ls := Linksym(s)
-	if len(ls.R) > 0 {
-		Fatalf("cannot rosymdup %s with relocations", ls.Name)
-	}
-	ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
-	ls.Dupok = 1
-}
-
 func emitptrargsmap() {
 	if Curfn.Func.Nname.Sym.Name == "_" {
 		return
 	}
 	sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
 
-	nptr := int(Curfn.Type.Argwid / int64(Widthptr))
+	nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr))
 	bv := bvalloc(int32(nptr) * 2)
 	nbitmap := 1
-	if Curfn.Type.Outtuple > 0 {
+	if Curfn.Type.Results().NumFields() > 0 {
 		nbitmap = 2
 	}
 	off := duint32(sym, 0, uint32(nbitmap))
 	off = duint32(sym, off, uint32(bv.n))
 	var xoffset int64
-	if Curfn.Type.Thistuple > 0 {
+	if Curfn.Type.Recv() != nil {
 		xoffset = 0
-		onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
+		onebitwalktype1(Curfn.Type.Recvs(), &xoffset, bv)
 	}
 
-	if Curfn.Type.Intuple > 0 {
+	if Curfn.Type.Params().NumFields() > 0 {
 		xoffset = 0
-		onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
+		onebitwalktype1(Curfn.Type.Params(), &xoffset, bv)
 	}
 
 	for j := 0; int32(j) < bv.n; j += 32 {
 		off = duint32(sym, off, bv.b[j/32])
 	}
-	if Curfn.Type.Outtuple > 0 {
+	if Curfn.Type.Results().NumFields() > 0 {
 		xoffset = 0
-		onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
+		onebitwalktype1(Curfn.Type.Results(), &xoffset, bv)
 		for j := 0; int32(j) < bv.n; j += 32 {
 			off = duint32(sym, off, bv.b[j/32])
 		}
@@ -186,21 +179,12 @@ func emitptrargsmap() {
 // the top of the stack and increasing in size.
 // Non-autos sort on offset.
 func cmpstackvarlt(a, b *Node) bool {
-	if a.Class != b.Class {
-		if a.Class == PAUTO {
-			return false
-		}
-		return true
+	if (a.Class == PAUTO) != (b.Class == PAUTO) {
+		return b.Class == PAUTO
 	}
 
 	if a.Class != PAUTO {
-		if a.Xoffset < b.Xoffset {
-			return true
-		}
-		if a.Xoffset > b.Xoffset {
-			return false
-		}
-		return false
+		return a.Xoffset < b.Xoffset
 	}
 
 	if a.Used != b.Used {
@@ -219,16 +203,20 @@ func cmpstackvarlt(a, b *Node) bool {
 		return ap
 	}
 
-	if a.Type.Width < b.Type.Width {
-		return false
-	}
-	if a.Type.Width > b.Type.Width {
-		return true
+	if a.Type.Width != b.Type.Width {
+		return a.Type.Width > b.Type.Width
 	}
 
 	return a.Sym.Name < b.Sym.Name
 }
 
+// byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
+type byStackVar []*Node
+
+func (s byStackVar) Len() int           { return len(s) }
+func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
+func (s byStackVar) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+
 // stkdelta records the stack offset delta for a node
 // during the compaction of the stack frame to remove
 // unused stack slots.
@@ -239,25 +227,23 @@ func allocauto(ptxt *obj.Prog) {
 	Stksize = 0
 	stkptrsize = 0
 
-	if Curfn.Func.Dcl == nil {
+	if len(Curfn.Func.Dcl) == 0 {
 		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
+	for _, ln := range Curfn.Func.Dcl {
+		if ln.Class == PAUTO {
+			ln.Used = false
 		}
 	}
 
 	markautoused(ptxt)
 
-	listsort(&Curfn.Func.Dcl, cmpstackvarlt)
+	sort.Sort(byStackVar(Curfn.Func.Dcl))
 
 	// Unused autos are at the end, chop 'em off.
-	ll := Curfn.Func.Dcl
-
-	n := ll.N
+	n := Curfn.Func.Dcl[0]
 	if n.Class == PAUTO && n.Op == ONAME && !n.Used {
 		// No locals used at all
 		Curfn.Func.Dcl = nil
@@ -266,19 +252,17 @@ func allocauto(ptxt *obj.Prog) {
 		return
 	}
 
-	for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next {
-		n = ll.Next.N
+	for i := 1; i < len(Curfn.Func.Dcl); i++ {
+		n = Curfn.Func.Dcl[i]
 		if n.Class == PAUTO && n.Op == ONAME && !n.Used {
-			ll.Next = nil
-			Curfn.Func.Dcl.End = ll
+			Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
 			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
+	for _, n := range Curfn.Func.Dcl {
 		if n.Class != PAUTO || n.Op != ONAME {
 			continue
 		}
@@ -293,7 +277,7 @@ func allocauto(ptxt *obj.Prog) {
 		if haspointers(n.Type) {
 			stkptrsize = Stksize
 		}
-		if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+		if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
 			Stksize = Rnd(Stksize, int64(Widthptr))
 		}
 		if Stksize >= 1<<31 {
@@ -310,12 +294,12 @@ func allocauto(ptxt *obj.Prog) {
 	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 {
+	for _, ln := range Curfn.Func.Dcl {
+		if ln.Class != PAUTO || ln.Op != ONAME {
 			continue
 		}
-		ll.N.Xoffset += stkdelta[ll.N]
-		delete(stkdelta, ll.N)
+		ln.Xoffset += stkdelta[ln]
+		delete(stkdelta, ln)
 	}
 }
 
@@ -325,12 +309,17 @@ func Cgen_checknil(n *Node) {
 	}
 
 	// 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) {
+	if n.Type == nil || (!n.Type.IsPtr() && !n.Type.IsInteger() && n.Type.Etype != TUNSAFEPTR) {
 		Dump("checknil", n)
 		Fatalf("bad checknil")
 	}
 
-	if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
+	// Most architectures require that the address to be checked is
+	// in a register (it could be in memory).
+	needsReg := !Thearch.LinkArch.InFamily(sys.AMD64, sys.I386)
+
+	// Move the address to be checked into a register if necessary.
+	if (needsReg && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
 		var reg Node
 		Regalloc(&reg, Types[Tptr], n)
 		Cgen(n, &reg)
@@ -349,34 +338,32 @@ func compile(fn *Node) {
 		Deferreturn = Sysfunc("deferreturn")
 		Panicindex = Sysfunc("panicindex")
 		panicslice = Sysfunc("panicslice")
+		panicdivide = Sysfunc("panicdivide")
 		throwreturn = Sysfunc("throwreturn")
+		growslice = Sysfunc("growslice")
+		writebarrierptr = Sysfunc("writebarrierptr")
+		typedmemmove = Sysfunc("typedmemmove")
+		panicdottype = Sysfunc("panicdottype")
 	}
 
-	lno := setlineno(fn)
+	defer func(lno int32) {
+		lineno = 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.") {
+	if fn.Nbody.Len() == 0 {
+		if pure_go || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
 			Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
-			goto ret
+			return
 		}
 
 		if Debug['A'] != 0 {
-			goto ret
+			return
 		}
 		emitptrargsmap()
-		goto ret
+		return
 	}
 
 	saveerrors()
@@ -384,53 +371,55 @@ func compile(fn *Node) {
 	// set up domain for labels
 	clearlabels()
 
-	if Curfn.Type.Outnamed {
+	if Curfn.Type.FuncType().Outnamed {
 		// add clearing of the output parameters
-		var save Iter
-		t := Structfirst(&save, Getoutarg(Curfn.Type))
-
-		for t != nil {
+		for _, t := range Curfn.Type.Results().Fields().Slice() {
 			if t.Nname != nil {
-				n = Nod(OAS, t.Nname, nil)
-				typecheck(&n, Etop)
-				Curfn.Nbody = concat(list1(n), Curfn.Nbody)
+				n := Nod(OAS, t.Nname, nil)
+				n = typecheck(n, Etop)
+				Curfn.Nbody.Set(append([]*Node{n}, Curfn.Nbody.Slice()...))
 			}
-
-			t = structnext(&save)
 		}
 	}
 
 	order(Curfn)
 	if nerrors != 0 {
-		goto ret
+		return
 	}
 
 	hasdefer = false
 	walk(Curfn)
 	if nerrors != 0 {
-		goto ret
+		return
 	}
 	if instrumenting {
 		instrument(Curfn)
 	}
 	if nerrors != 0 {
-		goto ret
+		return
+	}
+
+	// Build an SSA backend function.
+	var ssafn *ssa.Func
+	if shouldssa(Curfn) {
+		ssafn = buildssa(Curfn)
 	}
 
 	continpc = nil
 	breakpc = nil
 
-	pl = newplist()
+	pl := newplist()
 	pl.Name = Linksym(Curfn.Func.Nname.Sym)
 
 	setlineno(Curfn)
 
+	var nod1 Node
 	Nodconst(&nod1, Types[TINT32], 0)
-	nam = Curfn.Func.Nname
+	nam := Curfn.Func.Nname
 	if isblank(nam) {
 		nam = nil
 	}
-	ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
+	ptxt := Thearch.Gins(obj.ATEXT, nam, &nod1)
 	Afunclit(&ptxt.From, Curfn.Func.Nname)
 	ptxt.From3 = new(obj.Addr)
 	if fn.Func.Dupok {
@@ -442,17 +431,20 @@ func compile(fn *Node) {
 	if fn.Func.Needctxt {
 		ptxt.From3.Offset |= obj.NEEDCTXT
 	}
-	if fn.Func.Nosplit {
+	if fn.Func.Pragma&Nosplit != 0 {
 		ptxt.From3.Offset |= obj.NOSPLIT
 	}
-	if fn.Func.Systemstack {
-		ptxt.From.Sym.Cfunc = 1
+	if fn.Func.ReflectMethod {
+		ptxt.From3.Offset |= obj.REFLECTMETHOD
+	}
+	if fn.Func.Pragma&Systemstack != 0 {
+		ptxt.From.Sym.Cfunc = true
 	}
 
 	// 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 myimportpath == "reflect" {
 		if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
 			ptxt.From3.Offset |= obj.WRAPPER
 		}
@@ -460,38 +452,60 @@ func compile(fn *Node) {
 
 	ginit()
 
-	gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
-	gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
+	gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
+	gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)
 
-	for _, t := range Curfn.Func.Fieldtrack {
-		gtrack(tracksym(t))
+	if obj.Fieldtrack_enabled != 0 && len(Curfn.Func.FieldTrack) > 0 {
+		trackSyms := make([]*Sym, 0, len(Curfn.Func.FieldTrack))
+		for sym := range Curfn.Func.FieldTrack {
+			trackSyms = append(trackSyms, sym)
+		}
+		sort.Sort(symByName(trackSyms))
+		for _, sym := range trackSyms {
+			gtrack(sym)
+		}
 	}
 
-	for l := fn.Func.Dcl; l != nil; l = l.Next {
-		n = l.N
+	for _, n := range fn.Func.Dcl {
 		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))
+			Nodconst(&nod1, Types[TUINTPTR], n.Type.Width)
+			p := Thearch.Gins(obj.ATYPE, n, &nod1)
+			p.From.Gotype = Linksym(ngotype(n))
 		}
 	}
 
+	if ssafn != nil {
+		genssa(ssafn, ptxt, gcargs, gclocals)
+		ssafn.Free()
+	} else {
+		genlegacy(ptxt, gcargs, gclocals)
+	}
+}
+
+type symByName []*Sym
+
+func (a symByName) Len() int           { return len(a) }
+func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
+func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+// genlegacy compiles Curfn using the legacy non-SSA code generator.
+func genlegacy(ptxt *obj.Prog, gcargs, gclocals *Sym) {
 	Genlist(Curfn.Func.Enter)
 	Genlist(Curfn.Nbody)
 	gclean()
 	checklabels()
 	if nerrors != 0 {
-		goto ret
+		return
 	}
 	if Curfn.Func.Endlineno != 0 {
 		lineno = Curfn.Func.Endlineno
 	}
 
-	if Curfn.Type.Outtuple != 0 {
+	if Curfn.Type.Results().NumFields() != 0 {
 		Ginscall(throwreturn, 0)
 	}
 
@@ -510,7 +524,7 @@ func compile(fn *Node) {
 
 	gclean()
 	if nerrors != 0 {
-		goto ret
+		return
 	}
 
 	Pc.As = obj.ARET // overwrite AEND
@@ -524,25 +538,17 @@ func compile(fn *Node) {
 
 	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 {
+	if Stksize+Maxarg > 1<<31 {
 		Yyerror("stack frame too large (>2GB)")
-		goto ret
+		return
 	}
 
 	// Emit garbage collection symbols.
 	liveness(Curfn, ptxt, gcargs, gclocals)
 
-	gcsymdup(gcargs)
-	gcsymdup(gclocals)
-
 	Thearch.Defframe(ptxt)
 
 	if Debug['f'] != 0 {
@@ -551,7 +557,4 @@ func compile(fn *Node) {
 
 	// Remove leftover instrumentation from the instruction stream.
 	removevardef(ptxt)
-
-ret:
-	lineno = lno
 }
diff --git a/src/cmd/compile/internal/gc/pgen_test.go b/src/cmd/compile/internal/gc/pgen_test.go
index ebc9101..44dc1db 100644
--- a/src/cmd/compile/internal/gc/pgen_test.go
+++ b/src/cmd/compile/internal/gc/pgen_test.go
@@ -6,9 +6,18 @@ package gc
 
 import (
 	"reflect"
+	"sort"
 	"testing"
 )
 
+func typeWithoutPointers() *Type {
+	return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 1}} // haspointers -> false
+}
+
+func typeWithPointers() *Type {
+	return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 2}} // haspointers -> true
+}
+
 // Test all code paths for cmpstackvarlt.
 func TestCmpstackvar(t *testing.T) {
 	testdata := []struct {
@@ -41,6 +50,16 @@ func TestCmpstackvar(t *testing.T) {
 			false,
 		},
 		{
+			Node{Class: PPARAM, Xoffset: 10},
+			Node{Class: PPARAMOUT, Xoffset: 20},
+			true,
+		},
+		{
+			Node{Class: PPARAMOUT, Xoffset: 10},
+			Node{Class: PPARAM, Xoffset: 20},
+			true,
+		},
+		{
 			Node{Class: PAUTO, Used: true},
 			Node{Class: PAUTO, Used: false},
 			true,
@@ -51,13 +70,13 @@ func TestCmpstackvar(t *testing.T) {
 			false,
 		},
 		{
-			Node{Class: PAUTO, Type: &Type{Haspointers: 1}}, // haspointers -> false
-			Node{Class: PAUTO, Type: &Type{Haspointers: 2}}, // haspointers -> true
+			Node{Class: PAUTO, Type: typeWithoutPointers()},
+			Node{Class: PAUTO, Type: typeWithPointers()},
 			false,
 		},
 		{
-			Node{Class: PAUTO, Type: &Type{Haspointers: 2}}, // haspointers -> true
-			Node{Class: PAUTO, Type: &Type{Haspointers: 1}}, // haspointers -> false
+			Node{Class: PAUTO, Type: typeWithPointers()},
+			Node{Class: PAUTO, Type: typeWithoutPointers()},
 			true,
 		},
 		{
@@ -101,26 +120,14 @@ func TestCmpstackvar(t *testing.T) {
 		if got != d.lt {
 			t.Errorf("want %#v < %#v", d.a, d.b)
 		}
+		// If we expect a < b to be true, check that b < a is false.
+		if d.lt && cmpstackvarlt(&d.b, &d.a) {
+			t.Errorf("unexpected %#v < %#v", d.b, d.a)
+		}
 	}
 }
 
-func slice2nodelist(s []*Node) *NodeList {
-	var nl *NodeList
-	for _, n := range s {
-		nl = list(nl, n)
-	}
-	return nl
-}
-
-func nodelist2slice(nl *NodeList) []*Node {
-	var s []*Node
-	for l := nl; l != nil; l = l.Next {
-		s = append(s, l.N)
-	}
-	return s
-}
-
-func TestListsort(t *testing.T) {
+func TestStackvarSort(t *testing.T) {
 	inp := []*Node{
 		{Class: PFUNC, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
 		{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
@@ -128,7 +135,7 @@ func TestListsort(t *testing.T) {
 		{Class: PFUNC, Xoffset: 10, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
 		{Class: PFUNC, Xoffset: 20, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
 		{Class: PAUTO, Used: true, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
-		{Class: PAUTO, Type: &Type{Haspointers: 1}, Name: &Name{}, Sym: &Sym{}}, // haspointers -> false
+		{Class: PAUTO, Type: typeWithoutPointers(), Name: &Name{}, Sym: &Sym{}},
 		{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
 		{Class: PAUTO, Type: &Type{}, Name: &Name{Needzero: true}, Sym: &Sym{}},
 		{Class: PAUTO, Type: &Type{Width: 1}, Name: &Name{}, Sym: &Sym{}},
@@ -149,7 +156,7 @@ func TestListsort(t *testing.T) {
 		{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
 		{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}},
 		{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "xyz"}},
-		{Class: PAUTO, Type: &Type{Haspointers: 1}, Name: &Name{}, Sym: &Sym{}}, // haspointers -> false
+		{Class: PAUTO, Type: typeWithoutPointers(), Name: &Name{}, Sym: &Sym{}},
 	}
 	// haspointers updates Type.Haspointers as a side effect, so
 	// exercise this function on all inputs so that reflect.DeepEqual
@@ -159,13 +166,11 @@ func TestListsort(t *testing.T) {
 		haspointers(inp[i].Type)
 	}
 
-	nl := slice2nodelist(inp)
-	listsort(&nl, cmpstackvarlt)
-	got := nodelist2slice(nl)
-	if !reflect.DeepEqual(want, got) {
-		t.Error("listsort failed")
-		for i := range got {
-			g := got[i]
+	sort.Sort(byStackVar(inp))
+	if !reflect.DeepEqual(want, inp) {
+		t.Error("sort failed")
+		for i := range inp {
+			g := inp[i]
 			w := want[i]
 			eq := reflect.DeepEqual(w, g)
 			if !eq {
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index feb66f6..ca0421d 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -17,8 +17,11 @@ package gc
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
+	"crypto/md5"
 	"fmt"
 	"sort"
+	"strings"
 )
 
 const (
@@ -28,20 +31,21 @@ const (
 
 // An ordinary basic block.
 //
-// Instructions are threaded together in a doubly-linked list.  To iterate in
+// 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) {
+//   for p = bb.first; ; p = p.link {
 //     ...
-//     if(p == bb->last)
-//       break;
+//     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) {
+//   for p = bb.last; p != nil; p = p.opt {
 //     ...
 //   }
 type BasicBlock struct {
@@ -61,9 +65,9 @@ type BasicBlock struct {
 	//	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
+	uevar    bvec
+	varkill  bvec
+	avarinit bvec
 
 	// Computed during livenesssolve using control flow information:
 	//
@@ -73,10 +77,10 @@ type BasicBlock struct {
 	//		(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
+	livein      bvec
+	liveout     bvec
+	avarinitany bvec
+	avarinitall bvec
 }
 
 // A collection of global state used by liveness analysis.
@@ -88,8 +92,8 @@ type Liveness struct {
 
 	// 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
+	argslivepointers []bvec
+	livepointers     []bvec
 }
 
 // Constructs a new basic block containing a single instruction.
@@ -121,7 +125,7 @@ func addedge(from *BasicBlock, to *BasicBlock) {
 }
 
 // Inserts prev before curr in the instruction
-// stream.  Any control flow, such as branches or fall throughs, that target the
+// 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,
@@ -180,9 +184,9 @@ func printblock(bb *BasicBlock) {
 	}
 }
 
-// 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
+// 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) {
@@ -193,57 +197,44 @@ func blockany(bb *BasicBlock, f func(*obj.Prog) bool) bool {
 	return false
 }
 
-// Collects and returns and array of Node*s for functions arguments and local
-// variables.
+// livenessShouldTrack reports whether the liveness analysis
+// should track the variable n.
+// We don't care about variables that have no pointers,
+// nor do we care about non-local variables,
+// nor do we care about empty structs (handled by the pointer check),
+// nor do we care about the fake PAUTOHEAP variables.
+func livenessShouldTrack(n *Node) bool {
+	return n.Op == ONAME && (n.Class == PAUTO || n.Class == PPARAM || n.Class == PPARAMOUT) && haspointers(n.Type)
+}
+
+// getvariables returns the list of on-stack variables that we need to track.
 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.
-			//
+	var vars []*Node
+	for _, n := range fn.Func.Dcl {
+		if n.Op == ONAME {
 			// 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.
+			// We use it to hold the index of the node in the variables array
+			// (nil means the Node is not in the variables array).
 			// 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
+			// we will check that n.Curfn == Curfn and n.Opt() != nil. Then n.Opt().(int32)
 			// 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)
-				}
+			n.SetOpt(nil)
+			n.Name.Curfn = Curfn
+		}
 
-			case PPARAM, PPARAMOUT:
-				ll.N.SetOpt(int32(len(result)))
-				result = append(result, ll.N)
-			}
+		if livenessShouldTrack(n) {
+			n.SetOpt(int32(len(vars)))
+			vars = append(vars, n)
 		}
 	}
 
-	return result
+	return vars
 }
 
-// A pretty printer for control flow graphs.  Takes an array of BasicBlock*s.
+// A pretty printer for control flow graphs. Takes a slice of *BasicBlocks.
 func printcfg(cfg []*BasicBlock) {
 	for _, bb := range cfg {
 		printblock(bb)
@@ -251,7 +242,7 @@ func printcfg(cfg []*BasicBlock) {
 }
 
 // Assigns a reverse post order number to each connected basic block using the
-// standard algorithm.  Unconnected blocks will not be affected.
+// standard algorithm. Unconnected blocks will not be affected.
 func reversepostorder(root *BasicBlock, rpo *int32) {
 	root.mark = VISITED
 	for _, bb := range root.succ {
@@ -271,7 +262,7 @@ 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
+// 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 {
@@ -339,12 +330,10 @@ func isdeferreturn(prog *obj.Prog) bool {
 }
 
 // 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
+// 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 {
@@ -357,7 +346,7 @@ func addselectgosucc(selectgo *BasicBlock) {
 			if len(pred.succ) != 1 {
 				Fatalf("select comm case has too many successors")
 			}
-			succ = pred.succ[0]
+			succ := pred.succ[0]
 
 			// Its successor should have exactly two successors.
 			// The drop through should flow to the selectgo block
@@ -378,39 +367,39 @@ func addselectgosucc(selectgo *BasicBlock) {
 	}
 }
 
-// The entry point for the missing selectgo control flow algorithm.  Takes an
-// array of BasicBlock*s containing selectgo calls.
+// The entry point for the missing selectgo control flow algorithm. Takes a
+// slice of *BasicBlocks containing selectgo calls.
 func fixselectgo(selectgo []*BasicBlock) {
 	for _, bb := range selectgo {
 		addselectgosucc(bb)
 	}
 }
 
-// Constructs a control flow graph from a sequence of instructions.  This
+// 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
+// not accounted for using the standard cfg construction algorithm. Returns a
+// slice of *BasicBlocks 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
+	// 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
+	// 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.
+	// Allocate a slice to remember where we have seen selectgo calls.
 	// These blocks will be revisited to add successor control flow edges.
-	selectgo := make([]*BasicBlock, 0, 0)
+	var selectgo []*BasicBlock
 
 	// Loop through all instructions identifying branch targets
 	// and fall-throughs and allocate basic blocks.
-	cfg := make([]*BasicBlock, 0, 0)
+	var cfg []*BasicBlock
 
 	bb := newblock(firstp)
 	cfg = append(cfg, bb)
-	for p := firstp; p != nil; p = p.Link {
+	for p := firstp; p != nil && p.As != obj.AEND; p = p.Link {
 		Thearch.Proginfo(p)
 		if p.To.Type == obj.TYPE_BRANCH {
 			if p.To.Val == nil {
@@ -435,10 +424,10 @@ func newcfg(firstp *obj.Prog) []*BasicBlock {
 	}
 
 	// Loop through all basic blocks maximally growing the list of
-	// contained instructions until a label is reached.  Add edges
+	// 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 {
+		for p := bb.last; p != nil && p.As != obj.AEND; p = p.Link {
 			if p.Opt != nil && p != bb.last {
 				break
 			}
@@ -447,6 +436,8 @@ func newcfg(firstp *obj.Prog) []*BasicBlock {
 			// 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 {
+				// TODO: remove after SSA is done. SSA does not
+				// generate any unreachable RET instructions.
 				break
 			}
 
@@ -469,7 +460,7 @@ func newcfg(firstp *obj.Prog) []*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.
+	// backward. This is the final state of the instruction opt field.
 	for _, bb := range cfg {
 		p := bb.first
 		var prev *obj.Prog
@@ -485,7 +476,7 @@ func newcfg(firstp *obj.Prog) []*BasicBlock {
 
 	// Add missing successor edges to the selectgo blocks.
 	if len(selectgo) != 0 {
-		fixselectgo([]*BasicBlock(selectgo))
+		fixselectgo(selectgo)
 	}
 
 	// Find a depth-first order and assign a depth-first number to
@@ -497,13 +488,13 @@ func newcfg(firstp *obj.Prog) []*BasicBlock {
 	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
+	// Sort the basic blocks by their depth first number. The
+	// slice 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
+	// field. If we see these nodes something must have gone wrong in an
 	// upstream compilation phase.
 	bb = cfg[0]
 	if bb.rpo == -1 {
@@ -515,7 +506,7 @@ func newcfg(firstp *obj.Prog) []*BasicBlock {
 	return cfg
 }
 
-// Frees a control flow graph (an array of BasicBlock*s) and all of its leaf
+// Frees a control flow graph (a slice of *BasicBlocks) and all of its leaf
 // data structures.
 func freecfg(cfg []*BasicBlock) {
 	if len(cfg) > 0 {
@@ -533,7 +524,7 @@ func isfunny(n *Node) bool {
 }
 
 // Computes the effects of an instruction on a set of
-// variables.  The vars argument is an array of Node*s.
+// variables. The vars argument is a slice of *Nodes.
 //
 // The output vectors give bits for variables:
 //	uevar - used by this instruction
@@ -546,33 +537,35 @@ func isfunny(n *Node) bool {
 // 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) {
+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
+		// 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
+		// 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 {
+			switch node.Class {
 			case PPARAM:
-				bvset(uevar, int32(i))
+				if !node.NotLiveAtEnd() {
+					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
+			// 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:
@@ -584,12 +577,21 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar Bvec, varkill Bvec, avarini
 
 		return
 	}
+	if prog.As == obj.AJMP && prog.To.Type == obj.TYPE_MEM && prog.To.Name == obj.NAME_EXTERN {
+		// This is a tail call. Ensure the arguments are still alive.
+		// See issue 16016.
+		for i, node := range vars {
+			if node.Class == PPARAM {
+				bvset(uevar, int32(i))
+			}
+		}
+	}
 
 	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 {
+			switch node.Class {
 			case PPARAM:
 				if node.Addrtaken {
 					bvset(avarinit, int32(i))
@@ -603,24 +605,17 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar Bvec, varkill Bvec, avarini
 
 	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 {
-					Fatalf("bad bookkeeping in liveness %v %d", Nconv(from.Node.(*Node), 0), pos)
-				}
-				if ((from.Node).(*Node)).Addrtaken {
+		if from.Node != nil && from.Sym != nil {
+			n := from.Node.(*Node)
+			if pos := liveIndex(n, vars); pos >= 0 {
+				if n.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) {
+						if !Isfat(n.Type) {
 							bvset(varkill, pos)
 						}
 					}
@@ -629,20 +624,12 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar Bvec, varkill Bvec, avarini
 		}
 	}
 
-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 {
-					Fatalf("bad bookkeeping in liveness %v %d", Nconv(to.Node.(*Node), 0), pos)
-				}
-				if ((to.Node).(*Node)).Addrtaken {
+		if to.Node != nil && to.Sym != nil {
+			n := to.Node.(*Node)
+			if pos := liveIndex(n, vars); pos >= 0 {
+				if n.Addrtaken {
 					if prog.As != obj.AVARKILL {
 						bvset(avarinit, pos)
 					}
@@ -662,7 +649,7 @@ Next:
 						bvset(uevar, pos)
 					}
 					if prog.Info.Flags&RightWrite != 0 {
-						if to.Node != nil && (!Isfat(((to.Node).(*Node)).Type) || prog.As == obj.AVARDEF) {
+						if !Isfat(n.Type) || prog.As == obj.AVARDEF {
 							bvset(varkill, pos)
 						}
 					}
@@ -672,15 +659,34 @@ Next:
 	}
 }
 
+// liveIndex returns the index of n in the set of tracked vars.
+// If n is not a tracked var, liveIndex returns -1.
+// If n is not a tracked var but should be tracked, liveIndex crashes.
+func liveIndex(n *Node, vars []*Node) int32 {
+	if n.Name.Curfn != Curfn || !livenessShouldTrack(n) {
+		return -1
+	}
+
+	pos, ok := n.Opt().(int32) // index in vars
+	if !ok {
+		Fatalf("lost track of variable in liveness: %v (%p, %p)", n, n, n.Orig)
+	}
+	if pos >= int32(len(vars)) || vars[pos] != n {
+		Fatalf("bad bookkeeping in liveness: %v (%p, %p)", n, n, n.Orig)
+	}
+	return 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.
+// liveness computation. The cfg argument is a slice of *BasicBlocks and the
+// vars argument is a slice of *Nodes.
 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
+	result := Liveness{
+		fn:   fn,
+		ptxt: ptxt,
+		cfg:  cfg,
+		vars: vars,
+	}
 
 	nblocks := int32(len(cfg))
 	nvars := int32(len(vars))
@@ -694,20 +700,10 @@ func newliveness(fn *Node, ptxt *obj.Prog, cfg []*BasicBlock, vars []*Node) *Liv
 		bb.avarinitany = bulk.next()
 		bb.avarinitall = bulk.next()
 	}
-
-	result.livepointers = make([]Bvec, 0, 0)
-	result.argslivepointers = make([]Bvec, 0, 0)
-	return result
+	return &result
 }
 
-// Frees the liveness structure and all of its leaf data structures.
-func freeliveness(lv *Liveness) {
-	if lv == nil {
-		Fatalf("freeliveness: cannot free nil")
-	}
-}
-
-func printeffects(p *obj.Prog, uevar Bvec, varkill Bvec, avarinit Bvec) {
+func printeffects(p *obj.Prog, uevar bvec, varkill bvec, avarinit bvec) {
 	fmt.Printf("effects of %v", p)
 	fmt.Printf("\nuevar: ")
 	bvprint(uevar)
@@ -718,7 +714,7 @@ func printeffects(p *obj.Prog, uevar Bvec, varkill Bvec, avarinit Bvec) {
 	fmt.Printf("\n")
 }
 
-// Pretty print a variable node.  Uses Pascal like conventions for pointers and
+// 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) {
@@ -733,8 +729,8 @@ func printnode(node *Node) {
 	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) {
+// Pretty print a list of variables. The vars argument is a slice of *Nodes.
+func printvars(name string, bv bvec, vars []*Node) {
 	fmt.Printf("%s:", name)
 	for i, node := range vars {
 		if bvget(bv, int32(i)) != 0 {
@@ -761,13 +757,13 @@ func livenessprintblock(lv *Liveness, bb *BasicBlock) {
 	}
 	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))
+	printvars("\tuevar", bb.uevar, lv.vars)
+	printvars("\tvarkill", bb.varkill, lv.vars)
+	printvars("\tlivein", bb.livein, lv.vars)
+	printvars("\tliveout", bb.liveout, lv.vars)
+	printvars("\tavarinit", bb.avarinit, lv.vars)
+	printvars("\tavarinitany", bb.avarinitany, lv.vars)
+	printvars("\tavarinitall", bb.avarinitall, lv.vars)
 
 	fmt.Printf("\tprog:\n")
 	for prog := bb.first; ; prog = prog.Link {
@@ -795,8 +791,8 @@ func livenessprintcfg(lv *Liveness) {
 }
 
 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 {
+	for _, ln := range fn.Func.Dcl {
+		if ln.Op == ONAME && ln.Class == PAUTO && ln == n {
 			return
 		}
 	}
@@ -807,8 +803,8 @@ func checkauto(fn *Node, p *obj.Prog, n *Node) {
 	}
 
 	fmt.Printf("checkauto %v: %v (%p; class=%d) not found in %p %v\n", funcSym(Curfn), n, n, n.Class, p, 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)
+	for _, ln := range fn.Func.Dcl {
+		fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
 	}
 	Yyerror("checkauto: invariant lost")
 }
@@ -817,19 +813,15 @@ func checkparam(fn *Node, p *obj.Prog, n *Node) {
 	if isfunny(n) {
 		return
 	}
-	var a *Node
-	var class Class
-	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 {
+	for _, a := range fn.Func.Dcl {
+		if a.Op == ONAME && (a.Class == PPARAM || a.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)
+	for _, ln := range fn.Func.Dcl {
+		fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
 	}
 	Yyerror("checkparam: invariant lost")
 }
@@ -849,10 +841,10 @@ func checkprog(fn *Node, p *obj.Prog) {
 	}
 }
 
-// Check instruction invariants.  We assume that the nodes corresponding to the
+// 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
+// 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 {
@@ -863,7 +855,7 @@ func checkptxt(fn *Node, firstp *obj.Prog) {
 		if false {
 			fmt.Printf("analyzing '%v'\n", p)
 		}
-		if p.As != obj.ADATA && p.As != obj.AGLOBL && p.As != obj.ATYPE {
+		if p.As != obj.AGLOBL && p.As != obj.ATYPE {
 			checkprog(fn, p)
 		}
 	}
@@ -873,7 +865,7 @@ func checkptxt(fn *Node, firstp *obj.Prog) {
 // 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) {
+func onebitwalktype1(t *Type, xoffset *int64, bv bvec) {
 	if t.Align > 0 && *xoffset&int64(t.Align-1) != 0 {
 		Fatalf("onebitwalktype1: invalid initial alignment, %v", t)
 	}
@@ -928,30 +920,23 @@ func onebitwalktype1(t *Type, xoffset *int64, bv Bvec) {
 		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 {
-			Fatalf("onebitwalktype1: invalid bound, %v", t)
+	case TSLICE:
+		// struct { byte *array; uintgo len; uintgo cap; }
+		if *xoffset&int64(Widthptr-1) != 0 {
+			Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
 		}
-		if Isslice(t) {
-			// struct { byte *array; uintgo len; uintgo cap; }
-			if *xoffset&int64(Widthptr-1) != 0 {
-				Fatalf("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)
-			}
+		bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer in first slot (BitsPointer)
+		*xoffset += t.Width
+
+	case TARRAY:
+		for i := int64(0); i < t.NumElem(); i++ {
+			onebitwalktype1(t.Elem(), xoffset, bv)
 		}
 
 	case TSTRUCT:
-		o := int64(0)
-		var fieldoffset int64
-		for t1 := t.Type; t1 != nil; t1 = t1.Down {
-			fieldoffset = t1.Width
+		var o int64
+		for _, t1 := range t.Fields().Slice() {
+			fieldoffset := t1.Offset
 			*xoffset += fieldoffset - o
 			onebitwalktype1(t1.Type, xoffset, bv)
 			o = fieldoffset + t1.Type.Width
@@ -971,22 +956,21 @@ func localswords() int32 {
 
 // Returns the number of words of in and out arguments.
 func argswords() int32 {
-	return int32(Curfn.Type.Argwid / int64(Widthptr))
+	return int32(Curfn.Type.ArgWidth() / 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
+// 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 a slice of *Nodes.
+func onebitlivepointermap(lv *Liveness, liveout bvec, vars []*Node, args bvec, locals bvec) {
 	var xoffset int64
 
 	for i := int32(0); ; i++ {
-		i = int32(bvnext(liveout, i))
+		i = bvnext(liveout, i)
 		if i < 0 {
 			break
 		}
-		node = vars[i]
+		node := vars[i]
 		switch node.Class {
 		case PAUTO:
 			xoffset = node.Xoffset + stkptrsize
@@ -997,45 +981,25 @@ func onebitlivepointermap(lv *Liveness, liveout Bvec, vars []*Node, args Bvec, l
 			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 {
+func unlinkedprog(as obj.As) *obj.Prog {
 	p := Ctxt.NewProg()
 	Clearp(p)
-	p.As = int16(as)
+	p.As = 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)
+	pcdata.From.Type = obj.TYPE_CONST
+	pcdata.From.Offset = obj.PCDATA_StackMapIndex
+	pcdata.To.Type = obj.TYPE_CONST
+	pcdata.To.Offset = int64(index)
 	return pcdata
 }
 
@@ -1045,7 +1009,7 @@ 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
+// 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) {
@@ -1057,7 +1021,7 @@ func livenessprologue(lv *Liveness) {
 		// 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)
+			progeffects(p, lv.vars, uevar, varkill, avarinit)
 			if debuglive >= 3 {
 				printeffects(p, uevar, varkill, avarinit)
 			}
@@ -1071,7 +1035,7 @@ func livenessprologue(lv *Liveness) {
 		bvresetall(varkill)
 
 		for p := bb.first; ; p = p.Link {
-			progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit)
+			progeffects(p, lv.vars, uevar, varkill, avarinit)
 			if debuglive >= 3 {
 				printeffects(p, uevar, varkill, avarinit)
 			}
@@ -1107,9 +1071,8 @@ func livenesssolve(lv *Liveness) {
 		bvcopy(bb.avarinitany, bb.avarinit)
 	}
 
-	change := int32(1)
-	for change != 0 {
-		change = 0
+	for change := true; change; {
+		change = false
 		for _, bb := range lv.cfg {
 			bvresetall(any)
 			bvresetall(all)
@@ -1127,27 +1090,26 @@ func livenesssolve(lv *Liveness) {
 			bvandnot(all, all, bb.varkill)
 			bvor(any, any, bb.avarinit)
 			bvor(all, all, bb.avarinit)
-			if bvcmp(any, bb.avarinitany) != 0 {
-				change = 1
+			if !bveq(any, bb.avarinitany) {
+				change = true
 				bvcopy(bb.avarinitany, any)
 			}
 
-			if bvcmp(all, bb.avarinitall) != 0 {
-				change = 1
+			if !bveq(all, bb.avarinitall) {
+				change = true
 				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
+	// 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
+	for change := true; change; {
+		change = false
 
-		// Walk blocks in the general direction of propagation.  This
+		// Walk blocks in the general direction of propagation. This
 		// improves convergence.
 		for i := len(lv.cfg) - 1; i >= 0; i-- {
 			bb := lv.cfg[i]
@@ -1161,8 +1123,8 @@ func livenesssolve(lv *Liveness) {
 				bvor(newliveout, newliveout, succ.livein)
 			}
 
-			if bvcmp(bb.liveout, newliveout) != 0 {
-				change = 1
+			if !bveq(bb.liveout, newliveout) {
+				change = true
 				bvcopy(bb.liveout, newliveout)
 			}
 
@@ -1180,7 +1142,7 @@ func livenesssolve(lv *Liveness) {
 
 // This function is slow but it is only used for generating debug prints.
 // Check whether n is marked live in args/locals.
-func islive(n *Node, args Bvec, locals Bvec) bool {
+func islive(n *Node, args bvec, locals bvec) bool {
 	switch n.Class {
 	case PPARAM, PPARAMOUT:
 		for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
@@ -1203,15 +1165,6 @@ func islive(n *Node, args Bvec, locals Bvec) bool {
 // 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)
@@ -1221,8 +1174,19 @@ func livenessepilogue(lv *Liveness) {
 	any := bvalloc(nvars)
 	all := bvalloc(nvars)
 	ambig := bvalloc(localswords())
-	nmsg := int32(0)
-	startmsg := int32(0)
+
+	// Set ambig bit for the pointers to heap-allocated pparamout variables.
+	// These are implicitly read by post-deferreturn code and thus must be
+	// kept live throughout the function (if there is any defer that recovers).
+	if hasdefer {
+		for _, n := range lv.vars {
+			if n.IsOutputParamHeapAddr() {
+				n.Name.Needzero = true
+				xoffset := n.Xoffset + stkptrsize
+				onebitwalktype1(n.Type, &xoffset, ambig)
+			}
+		}
+	}
 
 	for _, bb := range lv.cfg {
 		// Compute avarinitany and avarinitall for entry to block.
@@ -1231,8 +1195,8 @@ func livenessepilogue(lv *Liveness) {
 		bvresetall(any)
 
 		bvresetall(all)
-		for j = 0; j < int32(len(bb.pred)); j++ {
-			pred = bb.pred[j]
+		for j := 0; j < len(bb.pred); j++ {
+			pred := bb.pred[j]
 			if j == 0 {
 				bvcopy(any, pred.avarinitany)
 				bvcopy(all, pred.avarinitall)
@@ -1245,8 +1209,8 @@ func livenessepilogue(lv *Liveness) {
 		// 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)
+		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)
@@ -1260,20 +1224,20 @@ func livenessepilogue(lv *Liveness) {
 
 				bvandnot(liveout, any, all)
 				if !bvisempty(liveout) {
-					for pos = 0; pos < liveout.n; pos++ {
+					for pos := int32(0); pos < liveout.n; pos++ {
 						if bvget(liveout, pos) == 0 {
 							continue
 						}
 						bvset(all, pos) // silence future warnings in this block
-						n = lv.vars[pos]
+						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))
+								Warnl(p.Lineno, "%v: %v is ambiguously live", Curfn.Func.Nname, Nconv(n, FmtLong))
 							}
 
 							// Record in 'ambiguous' bitmap.
-							xoffset = n.Xoffset + stkptrsize
+							xoffset := n.Xoffset + stkptrsize
 
 							onebitwalktype1(n.Type, &xoffset, ambig)
 						}
@@ -1284,10 +1248,10 @@ func livenessepilogue(lv *Liveness) {
 				// value we are tracking.
 
 				// Live stuff first.
-				args = bvalloc(argswords())
+				args := bvalloc(argswords())
 
 				lv.argslivepointers = append(lv.argslivepointers, args)
-				locals = bvalloc(localswords())
+				locals := bvalloc(localswords())
 				lv.livepointers = append(lv.livepointers, locals)
 
 				if debuglive >= 3 {
@@ -1311,22 +1275,20 @@ func livenessepilogue(lv *Liveness) {
 		bb.lastbitmapindex = len(lv.livepointers) - 1
 	}
 
-	var fmt_ string
-	var next *obj.Prog
-	var numlive int32
 	var msg []string
+	var nmsg, startmsg int
 	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))
+			nmsg = len(lv.livepointers)
 			startmsg = nmsg
 			msg = make([]string, nmsg)
-			for j = 0; j < nmsg; j++ {
+			for j := 0; j < nmsg; j++ {
 				msg[j] = ""
 			}
 		}
 
 		// walk backward, emit pcdata and populate the maps
-		pos = int32(bb.lastbitmapindex)
+		pos := int32(bb.lastbitmapindex)
 
 		if pos < 0 {
 			// the first block we encounter should have the ATEXT so
@@ -1335,8 +1297,9 @@ func livenessepilogue(lv *Liveness) {
 		}
 
 		bvcopy(livein, bb.liveout)
-		for p = bb.last; p != nil; p = next {
-			next = p.Opt.(*obj.Prog) // splicebefore modifies p->opt
+		var next *obj.Prog
+		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)
@@ -1360,21 +1323,21 @@ func livenessepilogue(lv *Liveness) {
 				// the only things that can possibly be live are the
 				// input parameters.
 				if p.As == obj.ATEXT {
-					for j = 0; j < liveout.n; j++ {
+					for j := int32(0); j < liveout.n; j++ {
 						if bvget(liveout, j) == 0 {
 							continue
 						}
-						n = lv.vars[j]
+						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))
+							yyerrorl(p.Lineno, "internal error: %v %v recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, Nconv(n, FmtLong), p.Pc)
 						}
 					}
 				}
 
 				// Record live pointers.
-				args = lv.argslivepointers[pos]
+				args := lv.argslivepointers[pos]
 
-				locals = lv.livepointers[pos]
+				locals := lv.livepointers[pos]
 				onebitlivepointermap(lv, liveout, lv.vars, args, locals)
 
 				// Ambiguously live variables are zeroed immediately after
@@ -1389,18 +1352,22 @@ func livenessepilogue(lv *Liveness) {
 				// 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)
+					fmt_ := fmt.Sprintf("%v: live at ", p.Line())
+					if p.As == obj.ACALL && p.To.Sym != nil {
+						name := p.To.Sym.Name
+						i := strings.Index(name, ".")
+						if i >= 0 {
+							name = name[i+1:]
+						}
+						fmt_ += fmt.Sprintf("call to %s:", 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]
+					numlive := 0
+					for j := 0; j < len(lv.vars); j++ {
+						n := lv.vars[j]
 						if islive(n, args, locals) {
 							fmt_ += fmt.Sprintf(" %v", n)
 							numlive++
@@ -1427,7 +1394,7 @@ func livenessepilogue(lv *Liveness) {
 						// The instruction before a call to deferreturn is always a
 						// no-op, to keep PC-specific data unambiguous.
 						prev := p.Opt.(*obj.Prog)
-						if Ctxt.Arch.Thechar == '9' {
+						if Ctxt.Arch.Family == sys.PPC64 {
 							// On ppc64 there is an additional instruction
 							// (another no-op or reload of toc pointer) before
 							// the call.
@@ -1444,7 +1411,7 @@ func livenessepilogue(lv *Liveness) {
 		}
 
 		if msg != nil {
-			for j = startmsg; j < nmsg; j++ {
+			for j := startmsg; j < nmsg; j++ {
 				if msg[j] != "" {
 					fmt.Printf("%s", msg[j])
 				}
@@ -1465,12 +1432,10 @@ const (
 	Hp = 16777619
 )
 
-func hashbitmap(h uint32, bv Bvec) uint32 {
-	var w uint32
-
+func hashbitmap(h uint32, bv bvec) uint32 {
 	n := int((bv.n + 31) / 32)
 	for i := 0; i < n; i++ {
-		w = bv.b[i]
+		w := bv.b[i]
 		h = (h * Hp) ^ (w & 0xff)
 		h = (h * Hp) ^ ((w >> 8) & 0xff)
 		h = (h * Hp) ^ ((w >> 16) & 0xff)
@@ -1516,28 +1481,22 @@ func livenesscompact(lv *Liveness) {
 
 	// Consider bit vectors in turn.
 	// If new, assign next number using uniq,
-	// record in remap, record in lv->livepointers and lv->argslivepointers
+	// 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)
+		local := lv.livepointers[i]
+		arg := lv.argslivepointers[i]
+		h := hashbitmap(hashbitmap(H0, local), arg) % uint32(tablesize)
 
 		for {
-			j = table[h]
+			j := table[h]
 			if j < 0 {
 				break
 			}
-			jlocal = lv.livepointers[j]
-			jarg = lv.argslivepointers[j]
-			if bvcmp(local, jlocal) == 0 && bvcmp(arg, jarg) == 0 {
+			jlocal := lv.livepointers[j]
+			jarg := lv.argslivepointers[j]
+			if bveq(local, jlocal) && bveq(arg, jarg) {
 				remap[i] = j
 				goto Next
 			}
@@ -1556,21 +1515,20 @@ func livenesscompact(lv *Liveness) {
 	Next:
 	}
 
-	// We've already reordered lv->livepointers[0:uniq]
-	// and lv->argslivepointers[0:uniq] and freed the bitmaps
+	// 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{}
+		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)
+			i := p.To.Offset
 			if i >= 0 {
 				p.To.Offset = int64(remap[i])
 			}
@@ -1578,20 +1536,20 @@ func livenesscompact(lv *Liveness) {
 	}
 }
 
-func printbitset(printed int, name string, vars []*Node, bits Bvec) int {
-	started := 0
+func printbitset(printed bool, name string, vars []*Node, bits bvec) bool {
+	started := false
 	for i, n := range vars {
 		if bvget(bits, int32(i)) == 0 {
 			continue
 		}
-		if started == 0 {
-			if printed == 0 {
+		if !started {
+			if !printed {
 				fmt.Printf("\t")
 			} else {
 				fmt.Printf(" ")
 			}
-			started = 1
-			printed = 1
+			started = true
+			printed = true
 			fmt.Printf("%s=", name)
 		} else {
 			fmt.Printf(",")
@@ -1607,13 +1565,6 @@ func printbitset(printed int, name string, vars []*Node, bits Bvec) int {
 // 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)))
@@ -1629,7 +1580,7 @@ func livenessprintdebug(lv *Liveness) {
 		// bb#0 pred=1,2 succ=3,4
 		fmt.Printf("bb#%d pred=", i)
 
-		for j = 0; j < len(bb.pred); j++ {
+		for j := 0; j < len(bb.pred); j++ {
 			if j > 0 {
 				fmt.Printf(",")
 			}
@@ -1637,7 +1588,7 @@ func livenessprintdebug(lv *Liveness) {
 		}
 
 		fmt.Printf(" succ=")
-		for j = 0; j < len(bb.succ); j++ {
+		for j := 0; j < len(bb.succ); j++ {
 			if j > 0 {
 				fmt.Printf(",")
 			}
@@ -1647,41 +1598,41 @@ func livenessprintdebug(lv *Liveness) {
 		fmt.Printf("\n")
 
 		// initial settings
-		printed = 0
+		var printed bool
 
 		printed = printbitset(printed, "uevar", lv.vars, bb.uevar)
 		printed = printbitset(printed, "livein", lv.vars, bb.livein)
-		if printed != 0 {
+		if printed {
 			fmt.Printf("\n")
 		}
 
 		// program listing, with individual effects listed
-		for p = bb.first; ; p = p.Link {
+		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 = false
 			printed = printbitset(printed, "uevar", lv.vars, uevar)
 			printed = printbitset(printed, "varkill", lv.vars, varkill)
 			printed = printbitset(printed, "avarinit", lv.vars, avarinit)
-			if printed != 0 {
+			if printed {
 				fmt.Printf("\n")
 			}
 			if issafepoint(p) {
-				args = lv.argslivepointers[pcdata]
-				locals = lv.livepointers[pcdata]
+				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]
+				printed = false
+				for j := 0; j < len(lv.vars); j++ {
+					n := lv.vars[j]
 					if islive(n, args, locals) {
-						if printed != 0 {
+						if printed {
 							fmt.Printf(",")
 						}
 						fmt.Printf("%v", n)
-						printed++
+						printed = true
 					}
 				}
 				fmt.Printf("\n")
@@ -1700,7 +1651,7 @@ func livenessprintdebug(lv *Liveness) {
 		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 {
+		if printed {
 			fmt.Printf("\n")
 		}
 	}
@@ -1708,30 +1659,23 @@ func livenessprintdebug(lv *Liveness) {
 	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) {
+// Dumps a slice 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.
+func onebitwritesymbol(arr []bvec, sym *Sym) {
+	off := 4                                  // number of bitmaps, to fill in later
+	off = duint32(sym, off, uint32(arr[0].n)) // number of bits in each bitmap
 	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++ {
+	for i = 0; i < len(arr); i++ {
 		// bitmap words
-		bv = arr[i]
+		bv := arr[i]
 
 		if bv.b == nil {
 			break
 		}
-		for j = 0; int32(j) < bv.n; j += 32 {
-			word = bv.b[j/32]
+		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))
@@ -1743,7 +1687,17 @@ func onebitwritesymbol(arr []Bvec, sym *Sym) {
 	}
 
 	duint32(sym, 0, uint32(i)) // number of bitmaps
-	ggloblsym(sym, int32(off), obj.RODATA)
+	ls := Linksym(sym)
+	ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
+	ls.Dupok = true
+	sv := obj.SymVer{Name: ls.Name, Version: 0}
+	ls2, ok := Ctxt.Hash[sv]
+	if ok {
+		sym.Lsym = ls2
+	} else {
+		Ctxt.Hash[sv] = ls
+		ggloblsym(sym, int32(off), obj.RODATA)
+	}
 }
 
 func printprog(p *obj.Prog) {
@@ -1753,7 +1707,7 @@ func printprog(p *obj.Prog) {
 	}
 }
 
-// Entry pointer for liveness analysis.  Constructs a complete CFG, solves for
+// 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) {
@@ -1776,7 +1730,7 @@ func liveness(fn *Node, firstp *obj.Prog, argssym *Sym, livesym *Sym) {
 	cfg := newcfg(firstp)
 
 	if debuglive >= 3 {
-		printcfg([]*BasicBlock(cfg))
+		printcfg(cfg)
 	}
 	vars := getvariables(fn)
 	lv := newliveness(fn, firstp, cfg, vars)
@@ -1807,14 +1761,13 @@ func liveness(fn *Node, firstp *obj.Prog, argssym *Sym, livesym *Sym) {
 	onebitwritesymbol(lv.argslivepointers, argssym)
 
 	// Free everything.
-	for l := fn.Func.Dcl; l != nil; l = l.Next {
-		if l.N != nil {
-			l.N.SetOpt(nil)
+	for _, ln := range fn.Func.Dcl {
+		if ln != nil {
+			ln.SetOpt(nil)
 		}
 	}
-	freeliveness(lv)
 
-	freecfg([]*BasicBlock(cfg))
+	freecfg(cfg)
 
 	debuglive -= debugdelta
 }
diff --git a/src/cmd/compile/internal/gc/popt.go b/src/cmd/compile/internal/gc/popt.go
index 4d71ab6..8e2a7ba 100644
--- a/src/cmd/compile/internal/gc/popt.go
+++ b/src/cmd/compile/internal/gc/popt.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -138,15 +138,16 @@ func fixjmp(firstp *obj.Prog) {
 			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)
+			if Debug['N'] == 0 {
+				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")
 	}
@@ -186,7 +187,7 @@ func fixjmp(firstp *obj.Prog) {
 
 	// pass 4: elide JMP to next instruction.
 	// only safe if there are no jumps to JMPs anymore.
-	if jmploop == 0 {
+	if jmploop == 0 && Debug['N'] == 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 {
@@ -217,22 +218,50 @@ func fixjmp(firstp *obj.Prog) {
 // Control flow analysis. The Flow structures hold predecessor and successor
 // information as well as basic loop analysis.
 //
-//	graph = flowstart(firstp, 0);
+//	graph = Flowstart(firstp, nil)
 //	... use flow graph ...
-//	flowend(graph); // free 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)
+//	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:
+// f.P1 and this list:
 //
-//	for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+//	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.
+// The second argument (newData) to Flowstart specifies a func to create object
+// for every f.Data field, for use by the client.
+// If newData is nil, f.Data will be nil.
+
+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
+}
+
+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 bool   // diagnostic generated
+
+	Data interface{} // for use by client
+}
 
 var flowmark int
 
@@ -241,6 +270,19 @@ var flowmark int
 // will not have flow graphs and consequently will not be optimized.
 const MaxFlowProg = 50000
 
+var ffcache []Flow // reusable []Flow, to reduce allocation
+
+func growffcache(n int) {
+	if n > cap(ffcache) {
+		n = (n * 5) / 4
+		if n > MaxFlowProg {
+			n = MaxFlowProg
+		}
+		ffcache = make([]Flow, n)
+	}
+	ffcache = ffcache[:n]
+}
+
 func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
 	// Count and mark instructions to annotate.
 	nf := 0
@@ -268,7 +310,9 @@ func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
 
 	// Allocate annotations and assign to instructions.
 	graph := new(Graph)
-	ff := make([]Flow, nf)
+
+	growffcache(nf)
+	ff := ffcache
 	start := &ff[0]
 	id := 0
 	var last *Flow
@@ -331,6 +375,10 @@ func Flowend(graph *Graph) {
 		f.Prog.Info.Flags = 0 // drop cached proginfo
 		f.Prog.Opt = nil
 	}
+	clear := ffcache[:graph.Num]
+	for i := range clear {
+		clear[i] = Flow{}
+	}
 }
 
 // find looping structure
@@ -452,8 +500,8 @@ func flowrpo(g *Graph) {
 		me = r1.Rpo
 		d = -1
 
-		// rpo2r[r->rpo] == r protects against considering dead code,
-		// which has r->rpo == 0.
+		// 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
 		}
@@ -569,8 +617,8 @@ func mergetemp(firstp *obj.Prog) {
 
 	// Build list of all mergeable variables.
 	var vars []*TempVar
-	for l := Curfn.Func.Dcl; l != nil; l = l.Next {
-		if n := l.N; canmerge(n) {
+	for _, n := range Curfn.Func.Dcl {
+		if canmerge(n) {
 			v := &TempVar{}
 			vars = append(vars, v)
 			n.SetOpt(v)
@@ -665,7 +713,7 @@ func mergetemp(firstp *obj.Prog) {
 
 	// 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.
+	// to clear all the r.Active words after each variable.
 	gen := uint32(0)
 
 	for _, v := range vars {
@@ -698,7 +746,7 @@ func mergetemp(firstp *obj.Prog) {
 	nfree := len(bystart)
 	for _, v := range bystart {
 		if debugmerge > 0 && Debug['v'] != 0 {
-			fmt.Printf("consider %v: removed=%t\n", Nconv(v.node, obj.FmtSharp), v.removed)
+			fmt.Printf("consider %v: removed=%t\n", Nconv(v.node, FmtSharp), v.removed)
 		}
 
 		if v.removed {
@@ -713,7 +761,7 @@ func mergetemp(firstp *obj.Prog) {
 		}
 
 		if debugmerge > 0 && Debug['v'] != 0 {
-			fmt.Printf("consider %v: removed=%t nfree=%d nvar=%d\n", Nconv(v.node, obj.FmtSharp), v.removed, nfree, len(bystart))
+			fmt.Printf("consider %v: removed=%t nfree=%d nvar=%d\n", Nconv(v.node, FmtSharp), v.removed, nfree, len(bystart))
 		}
 
 		// Find old temp to reuse if possible.
@@ -722,7 +770,7 @@ func mergetemp(firstp *obj.Prog) {
 		for j := nfree; j < len(inuse); 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)
+				fmt.Printf("consider %v: maybe %v: type=%v,%v addrtaken=%v,%v\n", Nconv(v.node, FmtSharp), Nconv(v1.node, FmtSharp), t, v1.node.Type, v.node.Addrtaken, v1.node.Addrtaken)
 			}
 
 			// Require the types to match but also require the addrtaken bits to match.
@@ -758,7 +806,7 @@ func mergetemp(firstp *obj.Prog) {
 	if debugmerge > 0 && Debug['v'] != 0 {
 		fmt.Printf("%v [%d - %d]\n", Curfn.Func.Nname.Sym, len(vars), nkill)
 		for _, v := range vars {
-			fmt.Printf("var %v %v %d-%d", Nconv(v.node, obj.FmtSharp), v.node.Type, v.start, v.end)
+			fmt.Printf("var %v %v %d-%d", Nconv(v.node, FmtSharp), v.node.Type, v.start, v.end)
 			if v.addr {
 				fmt.Printf(" addr=true")
 			}
@@ -766,7 +814,7 @@ func mergetemp(firstp *obj.Prog) {
 				fmt.Printf(" removed=true")
 			}
 			if v.merge != nil {
-				fmt.Printf(" merge %v", Nconv(v.merge.node, obj.FmtSharp))
+				fmt.Printf(" merge %v", Nconv(v.merge.node, FmtSharp))
 			}
 			if v.start == v.end && v.def != nil {
 				fmt.Printf(" %v", v.def.Prog)
@@ -799,22 +847,15 @@ func mergetemp(firstp *obj.Prog) {
 	}
 
 	// Delete merged nodes from declaration list.
-	for lp := &Curfn.Func.Dcl; ; {
-		l := *lp
-		if l == nil {
-			break
-		}
-
-		Curfn.Func.Dcl.End = l
-		n := l.N
+	dcl := make([]*Node, 0, len(Curfn.Func.Dcl)-nkill)
+	for _, n := range Curfn.Func.Dcl {
 		v, _ := n.Opt().(*TempVar)
 		if v != nil && (v.merge != nil || v.removed) {
-			*lp = l.Next
 			continue
 		}
-
-		lp = &l.Next
+		dcl = append(dcl, n)
 	}
+	Curfn.Func.Dcl = dcl
 
 	// Clear aux structures.
 	for _, v := range vars {
@@ -891,7 +932,7 @@ func varkillwalk(v *TempVar, f0 *Flow, gen uint32) {
 // from memory without being rechecked. Other variables need to be checked on
 // each load.
 
-var killed int // f->data is either nil or &killed
+var killed int // f.Data is either nil or &killed
 
 func nilopt(firstp *obj.Prog) {
 	g := Flowstart(firstp, nil)
@@ -914,7 +955,7 @@ func nilopt(firstp *obj.Prog) {
 		ncheck++
 		if Thearch.Stackaddr(&p.From) {
 			if Debug_checknil != 0 && p.Lineno > 1 {
-				Warnl(int(p.Lineno), "removed nil check of SP address")
+				Warnl(p.Lineno, "removed nil check of SP address")
 			}
 			f.Data = &killed
 			continue
@@ -923,7 +964,7 @@ func nilopt(firstp *obj.Prog) {
 		nilwalkfwd(f)
 		if f.Data != nil {
 			if Debug_checknil != 0 && p.Lineno > 1 {
-				Warnl(int(p.Lineno), "removed nil check before indirect")
+				Warnl(p.Lineno, "removed nil check before indirect")
 			}
 			continue
 		}
@@ -931,7 +972,7 @@ func nilopt(firstp *obj.Prog) {
 		nilwalkback(f)
 		if f.Data != nil {
 			if Debug_checknil != 0 && p.Lineno > 1 {
-				Warnl(int(p.Lineno), "removed repeated nil check")
+				Warnl(p.Lineno, "removed repeated nil check")
 			}
 			continue
 		}
diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
index 8a6eba3..ad2bba9 100644
--- a/src/cmd/compile/internal/gc/racewalk.go
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -13,7 +13,7 @@ import (
 //
 // For flag_race it modifies the function as follows:
 //
-// 1. It inserts a call to racefuncenter at the beginning of each function.
+// 1. It inserts a call to racefuncenterfp 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.
@@ -33,7 +33,7 @@ import (
 // at best instrumentation would cause infinite recursion.
 var omit_pkgs = []string{"runtime/internal/atomic", "runtime/internal/sys", "runtime", "runtime/race", "runtime/msan"}
 
-// Only insert racefuncenter/racefuncexit into the following packages.
+// Only insert racefuncenterfp/racefuncexit into the following packages.
 // Memory accesses in the packages are either uninteresting or will cause false positives.
 var norace_inst_pkgs = []string{"sync", "sync/atomic"}
 
@@ -50,30 +50,28 @@ func ispkgin(pkgs []string) bool {
 }
 
 func instrument(fn *Node) {
-	if ispkgin(omit_pkgs) || fn.Func.Norace {
+	if ispkgin(omit_pkgs) || fn.Func.Pragma&Norace != 0 {
 		return
 	}
 
-	if flag_race == 0 || !ispkgin(norace_inst_pkgs) {
+	if !flag_race || !ispkgin(norace_inst_pkgs) {
 		instrumentlist(fn.Nbody, nil)
 
 		// nothing interesting for race detector in fn->enter
 		instrumentlist(fn.Func.Exit, nil)
 	}
 
-	if flag_race != 0 {
+	if flag_race {
 		// 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 := *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("racefuncenter", nil, nil, &nodpc)
+		fn.Func.Enter.Set(append([]*Node{nd}, fn.Func.Enter.Slice()...))
 		nd = mkcall("racefuncexit", nil, nil)
-		fn.Func.Exit = list(fn.Func.Exit, nd)
+		fn.Func.Exit.Append(nd)
 	}
 
 	if Debug['W'] != 0 {
@@ -86,16 +84,15 @@ func instrument(fn *Node) {
 	}
 }
 
-func instrumentlist(l *NodeList, init **NodeList) {
-	var instr *NodeList
-
-	for ; l != nil; l = l.Next {
-		instr = nil
-		instrumentnode(&l.N, &instr, 0, 0)
+func instrumentlist(l Nodes, init *Nodes) {
+	s := l.Slice()
+	for i := range s {
+		var instr Nodes
+		instrumentnode(&s[i], &instr, 0, 0)
 		if init == nil {
-			l.N.Ninit = concat(l.N.Ninit, instr)
+			s[i].Ninit.AppendNodes(&instr)
 		} else {
-			*init = concat(*init, instr)
+			init.AppendNodes(&instr)
 		}
 	}
 }
@@ -103,7 +100,7 @@ func instrumentlist(l *NodeList, init **NodeList) {
 // walkexpr and walkstmt combined
 // walks the tree and adds calls to the
 // instrumentation code to top-level (statement) nodes' init
-func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
+func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
 	n := *np
 
 	if n == nil {
@@ -123,7 +120,7 @@ func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
 		// nil it out and handle it separately before putting it back.
 		l := n.Ninit
 
-		n.Ninit = nil
+		n.Ninit.Set(nil)
 		instrumentlist(l, nil)
 		instrumentnode(&n, &l, wr, skip) // recurse with nil n->ninit
 		appendinit(&n, l)
@@ -135,7 +132,7 @@ func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
 
 	switch n.Op {
 	default:
-		Fatalf("instrument: unknown node type %v", Oconv(int(n.Op), 0))
+		Fatalf("instrument: unknown node type %v", n.Op)
 
 	case OAS, OASWB, OAS2FUNC:
 		instrumentnode(&n.Left, init, 1, 0)
@@ -147,27 +144,36 @@ func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
 		goto ret
 
 	case OBLOCK:
-		var out *NodeList
-		for l := n.List; l != nil; l = l.Next {
-			switch l.N.Op {
+		var out []*Node
+		ls := n.List.Slice()
+		for i := 0; i < len(ls); i++ {
+			switch ls[i].Op {
 			case OCALLFUNC, OCALLMETH, OCALLINTER:
-				instrumentnode(&l.N, &l.N.Ninit, 0, 0)
-				out = list(out, l.N)
+				instrumentnode(&ls[i], &ls[i].Ninit, 0, 0)
+				out = append(out, ls[i])
 				// 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)
+				for i+1 < len(ls) && ls[i+1].Op == OAS && iscallret(ls[i+1].Right) {
+					i++
+					out = append(out, ls[i])
 				}
 			default:
-				instrumentnode(&l.N, &out, 0, 0)
-				out = list(out, l.N)
+				var outn Nodes
+				outn.Set(out)
+				instrumentnode(&ls[i], &outn, 0, 0)
+				if ls[i].Op != OAS && ls[i].Op != OASWB && ls[i].Op != OAS2FUNC || ls[i].Ninit.Len() == 0 {
+					out = append(outn.Slice(), ls[i])
+				} else {
+					// Splice outn onto end of ls[i].Ninit
+					ls[i].Ninit.AppendNodes(&outn)
+					out = append(out, ls[i])
+				}
 			}
 		}
-		n.List = out
+		n.List.Set(out)
 		goto ret
 
 	case ODEFER:
@@ -222,11 +228,11 @@ func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
 
 	case OSPTR, OLEN, OCAP:
 		instrumentnode(&n.Left, init, 0, 0)
-		if Istype(n.Left.Type, TMAP) {
+		if n.Left.Type.IsMap() {
 			n1 := Nod(OCONVNOP, n.Left, nil)
 			n1.Type = Ptrto(Types[TUINT8])
 			n1 = Nod(OIND, n1, nil)
-			typecheck(&n1, Erv)
+			n1 = typecheck(n1, Erv)
 			callinstr(&n1, init, 0, skip)
 		}
 
@@ -283,7 +289,7 @@ func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
 		goto ret
 
 	case OINDEX:
-		if !Isfixedarray(n.Left.Type) {
+		if !n.Left.Type.IsArray() {
 			instrumentnode(&n.Left, init, 0, 0)
 		} else if !islvalue(n.Left) {
 			// index of unaddressable array, like Map[k][i].
@@ -294,14 +300,18 @@ func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
 		}
 
 		instrumentnode(&n.Right, init, 0, 0)
-		if n.Left.Type.Etype != TSTRING {
+		if !n.Left.Type.IsString() {
 			callinstr(&n, init, wr, skip)
 		}
 		goto ret
 
 	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
 		instrumentnode(&n.Left, init, 0, 0)
-		instrumentnode(&n.Right, init, 0, 0)
+		low, high, max := n.SliceBounds()
+		instrumentnode(&low, init, 0, 0)
+		instrumentnode(&high, init, 0, 0)
+		instrumentnode(&max, init, 0, 0)
+		n.SetSliceBounds(low, high, max)
 		goto ret
 
 	case OKEY:
@@ -364,13 +374,13 @@ func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
 		OAS2RECV,
 		OAS2MAPR,
 		OASOP:
-		Yyerror("instrument: %v must be lowered by now", Oconv(int(n.Op), 0))
+		Yyerror("instrument: %v must be lowered by now", n.Op)
 
 		goto ret
 
 		// impossible nodes: only appear in backend.
 	case ORROTC, OEXTEND:
-		Yyerror("instrument: %v cannot exist now", Oconv(int(n.Op), 0))
+		Yyerror("instrument: %v cannot exist now", n.Op)
 		goto ret
 
 	case OGETG:
@@ -409,7 +419,6 @@ func instrumentnode(np **Node, init **NodeList, wr int, skip int) {
 	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
@@ -460,7 +469,7 @@ func isartificial(n *Node) bool {
 	return false
 }
 
-func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
+func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
 	n := *np
 
 	//print("callinstr for %+N [ %O ] etype=%E class=%d\n",
@@ -486,7 +495,7 @@ func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
 	// 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 {
+	if class == PAUTOHEAP || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
 		hascalls := 0
 		foreach(n, hascallspred, &hascalls)
 		if hascalls != 0 {
@@ -497,7 +506,7 @@ func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
 		n = treecopy(n, 0)
 		makeaddable(n)
 		var f *Node
-		if flag_msan != 0 {
+		if flag_msan {
 			name := "msanread"
 			if wr != 0 {
 				name = "msanwrite"
@@ -509,7 +518,7 @@ func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
 				Fatalf("instrument: %v badwidth", t)
 			}
 			f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(w))
-		} else if flag_race != 0 && (t.Etype == TSTRUCT || Isfixedarray(t)) {
+		} else if flag_race && (t.IsStruct() || t.IsArray()) {
 			name := "racereadrange"
 			if wr != 0 {
 				name = "racewriterange"
@@ -521,7 +530,7 @@ func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
 				Fatalf("instrument: %v badwidth", t)
 			}
 			f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(w))
-		} else if flag_race != 0 {
+		} else if flag_race {
 			name := "raceread"
 			if wr != 0 {
 				name = "racewrite"
@@ -529,7 +538,7 @@ func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
 			f = mkcall(name, nil, init, uintptraddr(n))
 		}
 
-		*init = list(*init, f)
+		init.Append(f)
 		return true
 	}
 
@@ -548,7 +557,7 @@ func makeaddable(n *Node) {
 	// an addressable value.
 	switch n.Op {
 	case OINDEX:
-		if Isfixedarray(n.Left.Type) {
+		if n.Left.Type.IsArray() {
 			makeaddable(n.Left)
 		}
 
@@ -575,16 +584,16 @@ func uintptraddr(n *Node) *Node {
 	return r
 }
 
-func detachexpr(n *Node, init **NodeList) *Node {
+func detachexpr(n *Node, init *Nodes) *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)
+	as = typecheck(as, Etop)
+	as = walkexpr(as, init)
+	init.Append(as)
 	ind := Nod(OIND, l, nil)
-	typecheck(&ind, Erv)
-	walkexpr(&ind, init)
+	ind = typecheck(ind, Erv)
+	ind = walkexpr(ind, init)
 	return ind
 }
 
@@ -594,9 +603,9 @@ func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
 	}
 }
 
-func foreachlist(l *NodeList, f func(*Node, interface{}), c interface{}) {
-	for ; l != nil; l = l.Next {
-		foreachnode(l.N, f, c)
+func foreachlist(l Nodes, f func(*Node, interface{}), c interface{}) {
+	for _, n := range l.Slice() {
+		foreachnode(n, f, c)
 	}
 }
 
@@ -618,8 +627,8 @@ func hascallspred(n *Node, c interface{}) {
 
 // appendinit is like addinit in subr.go
 // but appends rather than prepends.
-func appendinit(np **Node, init *NodeList) {
-	if init == nil {
+func appendinit(np **Node, init Nodes) {
+	if init.Len() == 0 {
 		return
 	}
 
@@ -635,6 +644,6 @@ func appendinit(np **Node, init *NodeList) {
 		*np = n
 	}
 
-	n.Ninit = concat(n.Ninit, init)
+	n.Ninit.AppendNodes(&init)
 	n.Ullman = UINF
 }
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 4386bcf..9d3f79c 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -4,8 +4,6 @@
 
 package gc
 
-import "cmd/internal/obj"
-
 // range
 func typecheckrange(n *Node) {
 	var toomany int
@@ -14,6 +12,7 @@ func typecheckrange(n *Node) {
 	var t2 *Type
 	var v1 *Node
 	var v2 *Node
+	var ls []*Node
 
 	// Typechecking order is important here:
 	// 0. first typecheck range expression (slice/map/chan),
@@ -25,48 +24,48 @@ func typecheckrange(n *Node) {
 	// 3. typecheck body.
 	// 4. decldepth--.
 
-	typecheck(&n.Right, Erv)
+	n.Right = 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)
+	ls = n.List.Slice()
+	for i1, n1 := range ls {
+		if n1.Name == nil || n1.Name.Defn != n {
+			ls[i1] = typecheck(ls[i1], Erv|Easgn)
 		}
 	}
 
-	if Isptr[t.Etype] && Isfixedarray(t.Type) {
-		t = t.Type
+	if t.IsPtr() && t.Elem().IsArray() {
+		t = t.Elem()
 	}
 	n.Type = t
 
 	toomany = 0
 	switch t.Etype {
 	default:
-		Yyerror("cannot range over %v", Nconv(n.Right, obj.FmtLong))
+		Yyerror("cannot range over %v", Nconv(n.Right, FmtLong))
 		goto out
 
-	case TARRAY:
+	case TARRAY, TSLICE:
 		t1 = Types[TINT]
-		t2 = t.Type
+		t2 = t.Elem()
 
 	case TMAP:
-		t1 = t.Down
-		t2 = t.Type
+		t1 = t.Key()
+		t2 = t.Val()
 
 	case TCHAN:
-		if t.Chan&Crecv == 0 {
+		if !t.ChanDir().CanRecv() {
 			Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
 			goto out
 		}
 
-		t1 = t.Type
+		t1 = t.Elem()
 		t2 = nil
-		if count(n.List) == 2 {
+		if n.List.Len() == 2 {
 			toomany = 1
 		}
 
@@ -75,17 +74,17 @@ func typecheckrange(n *Node) {
 		t2 = runetype
 	}
 
-	if count(n.List) > 2 || toomany != 0 {
+	if n.List.Len() > 2 || toomany != 0 {
 		Yyerror("too many variables in range")
 	}
 
 	v1 = nil
-	if n.List != nil {
-		v1 = n.List.N
+	if n.List.Len() != 0 {
+		v1 = n.List.First()
 	}
 	v2 = nil
-	if n.List != nil && n.List.Next != nil {
-		v2 = n.List.Next.N
+	if n.List.Len() > 1 {
+		v2 = n.List.Second()
 	}
 
 	// this is not only a optimization but also a requirement in the spec.
@@ -94,7 +93,7 @@ func typecheckrange(n *Node) {
 	// present."
 	if isblank(v2) {
 		if v1 != nil {
-			n.List = list1(v1)
+			n.List.Set1(v1)
 		}
 		v2 = nil
 	}
@@ -103,7 +102,7 @@ func typecheckrange(n *Node) {
 		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)
+			Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, FmtLong), why)
 		}
 		checkassign(n, v1)
 	}
@@ -112,7 +111,7 @@ func typecheckrange(n *Node) {
 		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)
+			Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, FmtLong), why)
 		}
 		checkassign(n, v2)
 	}
@@ -120,15 +119,15 @@ func typecheckrange(n *Node) {
 	// 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)
+	ls = n.List.Slice()
+	for i1, n1 := range ls {
+		if n1.Typecheck == 0 {
+			ls[i1] = typecheck(ls[i1], Erv|Easgn)
 		}
 	}
 
 	decldepth++
-	typechecklist(n.Nbody, Etop)
+	typecheckslice(n.Nbody.Slice(), Etop)
 	decldepth--
 }
 
@@ -143,31 +142,31 @@ func walkrange(n *Node) {
 	t := n.Type
 
 	a := n.Right
-	lno := int(setlineno(a))
+	lno := setlineno(a)
 	n.Right = nil
 
 	var v1 *Node
-	if n.List != nil {
-		v1 = n.List.N
+	if n.List.Len() != 0 {
+		v1 = n.List.First()
 	}
 	var v2 *Node
-	if n.List != nil && n.List.Next != nil && !isblank(n.List.Next.N) {
-		v2 = n.List.Next.N
+	if n.List.Len() > 1 && !isblank(n.List.Second()) {
+		v2 = n.List.Second()
 	}
 
-	// n->list has no meaning anymore, clear it
+	// n.List has no meaning anymore, clear it
 	// to avoid erroneous processing by racewalk.
-	n.List = nil
+	n.List.Set(nil)
 
-	var body *NodeList
-	var init *NodeList
+	var body []*Node
+	var init []*Node
 	switch t.Etype {
 	default:
 		Fatalf("walkrange")
 
-	case TARRAY:
+	case TARRAY, TSLICE:
 		if memclrrange(n, v1, v2, a) {
-			lineno = int32(lno)
+			lineno = lno
 			return
 		}
 
@@ -178,13 +177,13 @@ func walkrange(n *Node) {
 		hn := temp(Types[TINT])
 		var hp *Node
 
-		init = list(init, Nod(OAS, hv1, nil))
-		init = list(init, Nod(OAS, hn, Nod(OLEN, ha, nil)))
+		init = append(init, Nod(OAS, hv1, nil))
+		init = append(init, Nod(OAS, hn, Nod(OLEN, ha, nil)))
 		if v2 != nil {
-			hp = temp(Ptrto(n.Type.Type))
+			hp = temp(Ptrto(n.Type.Elem()))
 			tmp := Nod(OINDEX, ha, Nodintconst(0))
 			tmp.Bounded = true
-			init = list(init, Nod(OAS, hp, Nod(OADDR, tmp, nil)))
+			init = append(init, Nod(OAS, hp, Nod(OADDR, tmp, nil)))
 		}
 
 		n.Left = Nod(OLT, hv1, hn)
@@ -192,12 +191,12 @@ func walkrange(n *Node) {
 		if v1 == nil {
 			body = nil
 		} else if v2 == nil {
-			body = list1(Nod(OAS, v1, hv1))
+			body = []*Node{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)
+			a.List.Set([]*Node{v1, v2})
+			a.Rlist.Set([]*Node{hv1, Nod(OIND, hp, nil)})
+			body = []*Node{a}
 
 			// Advance pointer as part of increment.
 			// We used to advance the pointer before executing the loop body,
@@ -207,87 +206,91 @@ func walkrange(n *Node) {
 			// 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 := Nod(OADD, hp, Nodintconst(t.Elem().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)
+			a = typecheck(a, Etop)
+			n.Right.Ninit.Set1(a)
 		}
 
-		// orderstmt allocated the iterator for us.
-	// we only use a once, so no copy needed.
 	case TMAP:
+		// orderstmt allocated the iterator for us.
+		// we only use a once, so no copy needed.
 		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
+		keysym := th.Field(0).Sym // depends on layout of iterator struct.  See reflect.go:hiter
+		valsym := th.Field(1).Sym // ditto
 
-		fn := syslook("mapiterinit", 1)
+		fn := syslook("mapiterinit")
 
-		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 = substArgTypes(fn, t.Key(), t.Val(), th)
+		init = append(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
+		n.Left = Nod(ONE, NodSym(ODOT, hit, keysym), nodnil())
 
-		fn = syslook("mapiternext", 1)
-		substArgTypes(fn, th)
+		fn = syslook("mapiternext")
+		fn = substArgTypes(fn, th)
 		n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
 
-		key := Nod(ODOT, hit, keyname)
+		key := NodSym(ODOT, hit, keysym)
 		key = Nod(OIND, key, nil)
 		if v1 == nil {
 			body = nil
 		} else if v2 == nil {
-			body = list1(Nod(OAS, v1, key))
+			body = []*Node{Nod(OAS, v1, key)}
 		} else {
-			val := Nod(ODOT, hit, valname)
+			val := NodSym(ODOT, hit, valsym)
 			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)
+			a.List.Set([]*Node{v1, v2})
+			a.Rlist.Set([]*Node{key, val})
+			body = []*Node{a}
 		}
 
-		// orderstmt arranged for a copy of the channel variable.
 	case TCHAN:
+		// orderstmt arranged for a copy of the channel variable.
 		ha := a
 
 		n.Left = nil
 
-		hv1 := temp(t.Type)
+		hv1 := temp(t.Elem())
 		hv1.Typecheck = 1
-		if haspointers(t.Type) {
-			init = list(init, Nod(OAS, hv1, nil))
+		if haspointers(t.Elem()) {
+			init = append(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)
+		a.List.Set([]*Node{hv1, hb})
+		a.Rlist.Set1(Nod(ORECV, ha, nil))
+		n.Left.Ninit.Set1(a)
 		if v1 == nil {
 			body = nil
 		} else {
-			body = list1(Nod(OAS, v1, hv1))
+			body = []*Node{Nod(OAS, v1, hv1)}
 		}
+		// Zero hv1. This prevents hv1 from being the sole, inaccessible
+		// reference to an otherwise GC-able value during the next channel receive.
+		// See issue 15281.
+		body = append(body, Nod(OAS, hv1, nil))
 
-		// orderstmt arranged for a copy of the string variable.
 	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, nil))
+		init = append(init, Nod(OAS, hv1, nil))
 
 		var a *Node
 		var hv2 *Node
@@ -296,34 +299,34 @@ func walkrange(n *Node) {
 		} 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))
+			a.List.Set([]*Node{hv1, hv2})
+			fn := syslook("stringiter2")
+			a.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, ha, hv1))
 		}
 
 		n.Left = Nod(ONE, hv1, Nodintconst(0))
-		n.Left.Ninit = list(list1(Nod(OAS, ohv1, hv1)), a)
+		n.Left.Ninit.Set([]*Node{Nod(OAS, ohv1, hv1), a})
 
 		body = nil
 		if v1 != nil {
-			body = list1(Nod(OAS, v1, ohv1))
+			body = []*Node{Nod(OAS, v1, ohv1)}
 		}
 		if v2 != nil {
-			body = list(body, Nod(OAS, v2, hv2))
+			body = append(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)
+	typecheckslice(init, Etop)
+	n.Ninit.Append(init...)
+	typecheckslice(n.Left.Ninit.Slice(), Etop)
+	n.Left = typecheck(n.Left, Erv)
+	n.Right = typecheck(n.Right, Etop)
+	typecheckslice(body, Etop)
+	n.Nbody.Set(append(body, n.Nbody.Slice()...))
+	n = walkstmt(n)
+
+	lineno = lno
 }
 
 // Lower n into runtime·memclr if possible, for
@@ -344,17 +347,17 @@ func memclrrange(n, v1, v2, a *Node) bool {
 	if v1 == nil || v2 != nil {
 		return false
 	}
-	if n.Nbody == nil || n.Nbody.N == nil || n.Nbody.Next != nil {
+	if n.Nbody.Len() == 0 || n.Nbody.First() == nil || n.Nbody.Len() > 1 {
 		return false
 	}
-	stmt := n.Nbody.N // only stmt in body
+	stmt := n.Nbody.First() // only stmt in body
 	if stmt.Op != OAS || stmt.Left.Op != OINDEX {
 		return false
 	}
 	if !samesafeexpr(stmt.Left.Left, a) || !samesafeexpr(stmt.Left.Right, v1) {
 		return false
 	}
-	elemsize := n.Type.Type.Width
+	elemsize := n.Type.Elem().Width
 	if elemsize <= 0 || !iszero(stmt.Right) {
 		return false
 	}
@@ -368,7 +371,7 @@ func memclrrange(n, v1, v2, a *Node) bool {
 	// }
 	n.Op = OIF
 
-	n.Nbody = nil
+	n.Nbody.Set(nil)
 	n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0))
 
 	// hp = &a[0]
@@ -379,7 +382,7 @@ func memclrrange(n, v1, v2, a *Node) bool {
 	tmp = Nod(OADDR, tmp, nil)
 	tmp = Nod(OCONVNOP, tmp, nil)
 	tmp.Type = Ptrto(Types[TUINT8])
-	n.Nbody = list(n.Nbody, Nod(OAS, hp, tmp))
+	n.Nbody.Append(Nod(OAS, hp, tmp))
 
 	// hn = len(a) * sizeof(elem(a))
 	hn := temp(Types[TUINTPTR])
@@ -387,20 +390,20 @@ func memclrrange(n, v1, v2, a *Node) bool {
 	tmp = Nod(OLEN, a, nil)
 	tmp = Nod(OMUL, tmp, Nodintconst(elemsize))
 	tmp = conv(tmp, Types[TUINTPTR])
-	n.Nbody = list(n.Nbody, Nod(OAS, hn, tmp))
+	n.Nbody.Append(Nod(OAS, hn, tmp))
 
 	// memclr(hp, hn)
 	fn := mkcall("memclr", nil, nil, hp, hn)
 
-	n.Nbody = list(n.Nbody, fn)
+	n.Nbody.Append(fn)
 
 	// i = len(a) - 1
 	v1 = Nod(OAS, v1, Nod(OSUB, Nod(OLEN, a, nil), Nodintconst(1)))
 
-	n.Nbody = list(n.Nbody, v1)
+	n.Nbody.Append(v1)
 
-	typecheck(&n.Left, Erv)
-	typechecklist(n.Nbody, Etop)
-	walkstmt(&n)
+	n.Left = typecheck(n.Left, Erv)
+	typecheckslice(n.Nbody.Slice(), Etop)
+	n = walkstmt(n)
 	return true
 }
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 264955c..cff1acc 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -10,10 +10,27 @@ import (
 	"fmt"
 	"os"
 	"sort"
+	"strings"
 )
 
+type itabEntry struct {
+	t, itype *Type
+	sym      *Sym
+}
+
 // runtime interface and reflection data structures
-var signatlist *NodeList
+var signatlist []*Node
+var itabs []itabEntry
+
+type Sig struct {
+	name   string
+	pkg    *Pkg
+	isym   *Sym
+	tsym   *Sym
+	type_  *Type
+	mtype  *Type
+	offset int32
+}
 
 // byMethodNameAndPackagePath sorts method signatures by name, then package path.
 type byMethodNameAndPackagePath []*Sig
@@ -42,32 +59,40 @@ func siglt(a, b *Sig) bool {
 }
 
 // Builds a type representing a Bucket structure for
-// the given map type.  This type is not visible to users -
+// 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!
+// 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)
+func structfieldSize() int       { return 3 * Widthptr } // Sizeof(runtime.structfield{})
+func imethodSize() int           { return 4 + 4 }        // Sizeof(runtime.imethod{})
+func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{})
+	if t.Sym == nil && len(methods(t)) == 0 {
+		return 0
+	}
+	return 4 + 2 + 2 + 4 + 4
+}
+
+func makefield(name string, t *Type) *Field {
+	f := newField()
 	f.Type = t
-	f.Sym = new(Sym)
-	f.Sym.Name = name
+	f.Sym = nopkg.Lookup(name)
 	return f
 }
 
 func mapbucket(t *Type) *Type {
-	if t.Bucket != nil {
-		return t.Bucket
+	if t.MapType().Bucket != nil {
+		return t.MapType().Bucket
 	}
 
 	bucket := typ(TSTRUCT)
-	keytype := t.Down
-	valtype := t.Type
+	keytype := t.Key()
+	valtype := t.Val()
 	dowidth(keytype)
 	dowidth(valtype)
 	if keytype.Width > MAXKEYSIZE {
@@ -77,20 +102,18 @@ func mapbucket(t *Type) *Type {
 		valtype = Ptrto(valtype)
 	}
 
-	// The first field is: uint8 topbits[BUCKETSIZE].
-	arr := typ(TARRAY)
+	field := make([]*Field, 0, 5)
 
-	arr.Type = Types[TUINT8]
-	arr.Bound = BUCKETSIZE
-	field := make([]*Type, 0, 5)
+	// The first field is: uint8 topbits[BUCKETSIZE].
+	arr := typArray(Types[TUINT8], BUCKETSIZE)
 	field = append(field, makefield("topbits", arr))
-	arr = typ(TARRAY)
-	arr.Type = keytype
-	arr.Bound = BUCKETSIZE
+
+	arr = typArray(keytype, BUCKETSIZE)
+	arr.Noalg = true
 	field = append(field, makefield("keys", arr))
-	arr = typ(TARRAY)
-	arr.Type = valtype
-	arr.Bound = BUCKETSIZE
+
+	arr = typArray(valtype, BUCKETSIZE)
+	arr.Noalg = true
 	field = append(field, makefield("values", arr))
 
 	// Make sure the overflow pointer is the last memory in the struct,
@@ -110,7 +133,7 @@ func mapbucket(t *Type) *Type {
 	// 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 {
+	if int(t.Val().Align) > Widthptr || int(t.Key().Align) > Widthptr {
 		field = append(field, makefield("pad", Types[TUINTPTR]))
 	}
 
@@ -121,7 +144,7 @@ func mapbucket(t *Type) *Type {
 	// 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 {
+	if !haspointers(t.Val()) && !haspointers(t.Key()) && t.Val().Width <= MAXVALSIZE && t.Key().Width <= MAXKEYSIZE {
 		otyp = Types[TUINTPTR]
 	}
 	ovf := makefield("overflow", otyp)
@@ -130,34 +153,30 @@ func mapbucket(t *Type) *Type {
 	// link up fields
 	bucket.Noalg = true
 	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
+	bucket.SetFields(field[:])
 	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) {
+	if ovf.Offset != bucket.Width-int64(Widthptr) {
 		Yyerror("bad math in mapbucket for %v", t)
 	}
 
-	t.Bucket = bucket
+	t.MapType().Bucket = bucket
 
-	bucket.Map = t
+	bucket.StructType().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!
+// Make sure this stays in sync with ../../../../runtime/hashmap.go!
 func hmap(t *Type) *Type {
-	if t.Hmap != nil {
-		return t.Hmap
+	if t.MapType().Hmap != nil {
+		return t.MapType().Hmap
 	}
 
 	bucket := mapbucket(t)
-	var field [8]*Type
+	var field [8]*Field
 	field[0] = makefield("count", Types[TINT])
 	field[1] = makefield("flags", Types[TUINT8])
 	field[2] = makefield("B", Types[TUINT8])
@@ -170,24 +189,20 @@ func hmap(t *Type) *Type {
 	h := typ(TSTRUCT)
 	h.Noalg = true
 	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
+	h.SetFields(field[:])
 	dowidth(h)
-	t.Hmap = h
-	h.Map = t
+	t.MapType().Hmap = h
+	h.StructType().Map = t
 	return h
 }
 
 func hiter(t *Type) *Type {
-	if t.Hiter != nil {
-		return t.Hiter
+	if t.MapType().Hiter != nil {
+		return t.MapType().Hiter
 	}
 
 	// build a struct:
-	// hash_iter {
+	// hiter {
 	//    key *Key
 	//    val *Value
 	//    t *MapType
@@ -201,11 +216,10 @@ func hiter(t *Type) *Type {
 	//    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))
+	// must match ../../../../runtime/hashmap.go:hiter.
+	var field [12]*Field
+	field[0] = makefield("key", Ptrto(t.Key()))
+	field[1] = makefield("val", Ptrto(t.Val()))
 	field[2] = makefield("t", Ptrto(Types[TUINT8]))
 	field[3] = makefield("h", Ptrto(hmap(t)))
 	field[4] = makefield("buckets", Ptrto(mapbucket(t)))
@@ -219,51 +233,46 @@ func hiter(t *Type) *Type {
 
 	// build iterator struct holding the above fields
 	i := typ(TSTRUCT)
-
 	i.Noalg = true
-	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
+	i.SetFields(field[:])
 	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
+	t.MapType().Hiter = i
+	i.StructType().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
+	var in []*Node
 	if receiver != nil {
 		d := Nod(ODCLFIELD, nil, nil)
 		d.Type = receiver
-		in = list(in, d)
+		in = append(in, d)
 	}
 
 	var d *Node
-	for t := getinargx(f).Type; t != nil; t = t.Down {
+	for _, t := range f.Params().Fields().Slice() {
 		d = Nod(ODCLFIELD, nil, nil)
 		d.Type = t.Type
 		d.Isddd = t.Isddd
-		in = list(in, d)
+		in = append(in, d)
 	}
 
-	var out *NodeList
-	for t := getoutargx(f).Type; t != nil; t = t.Down {
+	var out []*Node
+	for _, t := range f.Results().Fields().Slice() {
 		d = Nod(ODCLFIELD, nil, nil)
 		d.Type = t.Type
-		out = list(out, d)
+		out = append(out, d)
 	}
 
 	t := functype(nil, in, out)
-	if f.Nname != nil {
+	if f.Nname() != nil {
 		// Link to name of original method function.
-		t.Nname = f.Nname
+		t.SetNname(f.Nname())
 	}
 
 	return t
@@ -290,14 +299,11 @@ func methods(t *Type) []*Sig {
 	// make list of methods for t,
 	// generating code if necessary.
 	var ms []*Sig
-	for f := mt.Xmethod; f != nil; f = f.Down {
-		if f.Etype != TFIELD {
-			Fatalf("methods: not field %v", f)
-		}
-		if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
+	for _, f := range mt.AllMethods().Slice() {
+		if f.Type.Etype != TFUNC || f.Type.Recv() == nil {
 			Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f)
 		}
-		if getthisx(f.Type).Type == nil {
+		if f.Type.Recv() == nil {
 			Fatalf("receiver with no type on %v method %v %v\n", mt, f.Sym, f)
 		}
 		if f.Nointerface {
@@ -313,12 +319,12 @@ func methods(t *Type) []*Sig {
 		// 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
+		this := f.Type.Recv().Type
 
-		if Isptr[this.Etype] && this.Type == t {
+		if this.IsPtr() && this.Elem() == t {
 			continue
 		}
-		if Isptr[this.Etype] && !Isptr[t.Etype] && f.Embedded != 2 && !isifacemethod(f.Type) {
+		if this.IsPtr() && !t.IsPtr() && f.Embedded != 2 && !isifacemethod(f.Type) {
 			continue
 		}
 
@@ -364,10 +370,7 @@ func methods(t *Type) []*Sig {
 // imethods returns the methods of the interface type t, sorted by name.
 func imethods(t *Type) []*Sig {
 	var methods []*Sig
-	for f := t.Type; f != nil; f = f.Down {
-		if f.Etype != TFIELD {
-			Fatalf("imethods: not field")
-		}
+	for _, f := range t.Fields().Slice() {
 		if f.Type.Etype != TFUNC || f.Sym == nil {
 			continue
 		}
@@ -414,127 +417,256 @@ func imethods(t *Type) []*Sig {
 	return methods
 }
 
-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
+	// -- 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
-
+	var str string
 	if p == localpkg {
 		// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
-		gdatastring(n, myimportpath)
+		str = myimportpath
 	} else {
-		gdatastring(n, p.Path)
+		str = p.Path
 	}
-	ggloblsym(n.Sym, int32(Types[TSTRING].Width), obj.DUPOK|obj.RODATA)
+
+	s := obj.Linklookup(Ctxt, "type..importpath."+p.Prefix+".", 0)
+	ot := dnameData(s, 0, str, "", nil, false)
+	ggloblLSym(s, int32(ot), obj.DUPOK|obj.RODATA)
+	p.Pathsym = s
 }
 
 func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
+	return dgopkgpathLSym(Linksym(s), ot, pkg)
+}
+
+func dgopkgpathLSym(s *obj.LSym, ot int, pkg *Pkg) int {
 	if pkg == nil {
-		return dgostringptr(s, ot, "")
+		return duintxxLSym(s, ot, 0, Widthptr)
 	}
 
 	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.
+		// If we don't know the full import path of the package being compiled
+		// (i.e. -p was not passed on the compiler command line), emit a reference to
+		// type..importpath.""., which the linker will rewrite using the correct import path.
 		// Every package that imports this one directly defines the symbol.
-		var ns *Sym
+		// See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ.
+		ns := obj.Linklookup(Ctxt, `type..importpath."".`, 0)
+		return dsymptrLSym(s, ot, ns, 0)
+	}
 
-		if ns == nil {
-			ns = Pkglookup("importpath.\"\".", mkpkg("go"))
-		}
-		return dsymptr(s, ot, ns, 0)
+	dimportpath(pkg)
+	return dsymptrLSym(s, ot, pkg.Pathsym, 0)
+}
+
+// dgopkgpathOffLSym writes an offset relocation in s at offset ot to the pkg path symbol.
+func dgopkgpathOffLSym(s *obj.LSym, ot int, pkg *Pkg) int {
+	if pkg == nil {
+		return duintxxLSym(s, ot, 0, 4)
+	}
+	if pkg == localpkg && myimportpath == "" {
+		// If we don't know the full import path of the package being compiled
+		// (i.e. -p was not passed on the compiler command line), emit a reference to
+		// type..importpath.""., which the linker will rewrite using the correct import path.
+		// Every package that imports this one directly defines the symbol.
+		// See also https://groups.google.com/forum/#!topic/golang-dev/myb9s53HxGQ.
+		ns := obj.Linklookup(Ctxt, `type..importpath."".`, 0)
+		return dsymptrOffLSym(s, ot, ns, 0)
 	}
 
 	dimportpath(pkg)
-	return dsymptr(s, ot, pkg.Pathsym, 0)
+	return dsymptrOffLSym(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 && len(m) == 0 {
-		return off
+// isExportedField reports whether a struct field is exported.
+func isExportedField(ft *Field) bool {
+	if ft.Sym != nil && ft.Embedded == 0 {
+		return exportname(ft.Sym.Name)
+	} else {
+		if ft.Type.Sym != nil &&
+			(ft.Type.Sym.Pkg == builtinpkg || !exportname(ft.Type.Sym.Name)) {
+			return false
+		} else {
+			return true
+		}
 	}
+}
 
-	// fill in *extraType pointer in header
-	off = int(Rnd(int64(off), int64(Widthptr)))
+// dnameField dumps a reflect.name for a struct field.
+func dnameField(s *Sym, ot int, ft *Field) int {
+	var name string
+	if ft.Sym != nil && ft.Embedded == 0 {
+		name = ft.Sym.Name
+	}
+	nsym := dname(name, ft.Note, nil, isExportedField(ft))
+	return dsymptrLSym(Linksym(s), ot, nsym, 0)
+}
 
-	dsymptr(sym, ptroff, sym, off)
+// dnameData writes the contents of a reflect.name into s at offset ot.
+func dnameData(s *obj.LSym, ot int, name, tag string, pkg *Pkg, exported bool) int {
+	if len(name) > 1<<16-1 {
+		Fatalf("name too long: %s", name)
+	}
+	if len(tag) > 1<<16-1 {
+		Fatalf("tag too long: %s", tag)
+	}
 
-	for _, a := range m {
-		dtypesym(a.type_)
+	// Encode name and tag. See reflect/type.go for details.
+	var bits byte
+	l := 1 + 2 + len(name)
+	if exported {
+		bits |= 1 << 0
+	}
+	if len(tag) > 0 {
+		l += 2 + len(tag)
+		bits |= 1 << 1
+	}
+	if pkg != nil {
+		bits |= 1 << 2
+	}
+	b := make([]byte, l)
+	b[0] = bits
+	b[1] = uint8(len(name) >> 8)
+	b[2] = uint8(len(name))
+	copy(b[3:], name)
+	if len(tag) > 0 {
+		tb := b[3+len(name):]
+		tb[0] = uint8(len(tag) >> 8)
+		tb[1] = uint8(len(tag))
+		copy(tb[2:], tag)
+	}
+
+	ot = int(s.WriteBytes(Ctxt, int64(ot), b))
+
+	if pkg != nil {
+		ot = dgopkgpathOffLSym(s, ot, pkg)
 	}
 
-	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)
+	return ot
+}
+
+var dnameCount int
+
+// dname creates a reflect.name for a struct field or method.
+func dname(name, tag string, pkg *Pkg, exported bool) *obj.LSym {
+	// Write out data as "type.." to signal two things to the
+	// linker, first that when dynamically linking, the symbol
+	// should be moved to a relro section, and second that the
+	// contents should not be decoded as a type.
+	sname := "type..namedata."
+	if pkg == nil {
+		// In the common case, share data with other packages.
+		if name == "" {
+			if exported {
+				sname += "-noname-exported." + tag
+			} else {
+				sname += "-noname-unexported." + tag
+			}
 		} else {
-			ot = dgostringptr(s, ot, "")
+			sname += name + "." + tag
 		}
 	} else {
-		ot = dgostringptr(s, ot, "")
-		ot = dgostringptr(s, ot, "")
+		sname = fmt.Sprintf(`%s"".%d`, sname, dnameCount)
+		dnameCount++
 	}
+	s := obj.Linklookup(Ctxt, sname, 0)
+	if len(s.P) > 0 {
+		return s
+	}
+	ot := dnameData(s, 0, name, tag, pkg, exported)
+	ggloblLSym(s, int32(ot), obj.DUPOK|obj.RODATA)
+	return s
+}
 
-	// slice header
-	ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
-
-	n := len(m)
-	ot = duintxx(s, ot, uint64(n), Widthint)
-	ot = duintxx(s, ot, uint64(n), Widthint)
+// dextratype dumps the fields of a runtime.uncommontype.
+// dataAdd is the offset in bytes after the header where the
+// backing array of the []method field is written (by dextratypeData).
+func dextratype(s *Sym, ot int, t *Type, dataAdd int) int {
+	m := methods(t)
+	if t.Sym == nil && len(m) == 0 {
+		return ot
+	}
+	noff := int(Rnd(int64(ot), int64(Widthptr)))
+	if noff != ot {
+		Fatalf("unexpected alignment in dextratype for %s", t)
+	}
 
-	// methods
 	for _, a := range m {
-		// 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)
+		dtypesym(a.type_)
+	}
+
+	ot = dgopkgpathOffLSym(Linksym(s), ot, typePkg(t))
+
+	dataAdd += uncommonSize(t)
+	mcount := len(m)
+	if mcount != int(uint16(mcount)) {
+		Fatalf("too many methods on %s: %d", t, mcount)
+	}
+	if dataAdd != int(uint32(dataAdd)) {
+		Fatalf("methods are too far away on %s: %d", t, dataAdd)
+	}
+
+	ot = duint16(s, ot, uint16(mcount))
+	ot = duint16(s, ot, 0)
+	ot = duint32(s, ot, uint32(dataAdd))
+	ot = duint32(s, ot, 0)
+	return ot
+}
+
+func typePkg(t *Type) *Pkg {
+	tsym := t.Sym
+	if tsym == nil {
+		switch t.Etype {
+		case TARRAY, TSLICE, TPTR32, TPTR64, TCHAN:
+			if t.Elem() != nil {
+				tsym = t.Elem().Sym
+			}
 		}
 	}
+	if tsym != nil && t != Types[t.Etype] && t != errortype {
+		return tsym.Pkg
+	}
+	return nil
+}
 
+// dextratypeData dumps the backing array for the []method field of
+// runtime.uncommontype.
+func dextratypeData(s *Sym, ot int, t *Type) int {
+	lsym := Linksym(s)
+	for _, a := range methods(t) {
+		// ../../../../runtime/type.go:/method
+		exported := exportname(a.name)
+		var pkg *Pkg
+		if !exported && a.pkg != typePkg(t) {
+			pkg = a.pkg
+		}
+		nsym := dname(a.name, "", pkg, exported)
+
+		ot = dsymptrOffLSym(lsym, ot, nsym, 0)
+		ot = dmethodptrOffLSym(lsym, ot, Linksym(dtypesym(a.mtype)))
+		ot = dmethodptrOffLSym(lsym, ot, Linksym(a.isym))
+		ot = dmethodptrOffLSym(lsym, ot, Linksym(a.tsym))
+	}
 	return ot
 }
 
+func dmethodptrOffLSym(s *obj.LSym, ot int, x *obj.LSym) int {
+	duintxxLSym(s, ot, 0, 4)
+	r := obj.Addrel(s)
+	r.Off = int32(ot)
+	r.Siz = 4
+	r.Sym = x
+	r.Type = obj.R_METHODOFF
+	return ot + 4
+}
+
 var kinds = []int{
 	TINT:        obj.KindInt,
 	TUINT:       obj.KindUint,
@@ -558,6 +690,7 @@ var kinds = []int{
 	TCHAN:       obj.KindChan,
 	TMAP:        obj.KindMap,
 	TARRAY:      obj.KindArray,
+	TSLICE:      obj.KindSlice,
 	TFUNC:       obj.KindFunc,
 	TCOMPLEX64:  obj.KindComplex64,
 	TCOMPLEX128: obj.KindComplex128,
@@ -565,70 +698,46 @@ var kinds = []int{
 }
 
 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 TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64,
+		TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL:
+		return false
+
+	case TSLICE:
+		return true
 
 	case TARRAY:
-		if t.Bound < 0 { // slice
-			ret = true
-			break
+		at := t.Extra.(*ArrayType)
+		if at.Haspointers != 0 {
+			return at.Haspointers-1 != 0
 		}
 
-		if t.Bound == 0 { // empty array
-			ret = false
-			break
+		ret := false
+		if t.NumElem() != 0 { // non-empty array
+			ret = haspointers(t.Elem())
 		}
 
-		ret = haspointers(t.Type)
+		at.Haspointers = 1 + uint8(obj.Bool2int(ret))
+		return ret
 
 	case TSTRUCT:
-		ret = false
-		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+		st := t.StructType()
+		if st.Haspointers != 0 {
+			return st.Haspointers-1 != 0
+		}
+
+		ret := false
+		for _, t1 := range t.Fields().Slice() {
 			if haspointers(t1.Type) {
 				ret = true
 				break
 			}
 		}
-
-	case TSTRING,
-		TPTR32,
-		TPTR64,
-		TUNSAFEPTR,
-		TINTER,
-		TCHAN,
-		TMAP,
-		TFUNC:
-		fallthrough
-	default:
-		ret = true
-
-	case TFIELD:
-		Fatalf("haspointers: unexpected type, %v", t)
+		st.Haspointers = 1 + uint8(obj.Bool2int(ret))
+		return ret
 	}
 
-	t.Haspointers = 1 + uint8(obj.Bool2int(ret))
-	return ret
+	return true
 }
 
 // typeptrdata returns the length in bytes of the prefix of t
@@ -656,23 +765,23 @@ func typeptrdata(t *Type) int64 {
 		// struct { Type *type; void *data; }
 		return 2 * int64(Widthptr)
 
+	case TSLICE:
+		// struct { byte *array; uintgo len; uintgo cap; }
+		return 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)
+		// haspointers already eliminated t.NumElem() == 0.
+		return (t.NumElem()-1)*t.Elem().Width + typeptrdata(t.Elem())
 
 	case TSTRUCT:
 		// Find the last field that has pointers.
-		var lastPtrField *Type
-		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+		var lastPtrField *Field
+		for _, t1 := range t.Fields().Slice() {
 			if haspointers(t1.Type) {
 				lastPtrField = t1
 			}
 		}
-		return lastPtrField.Width + typeptrdata(lastPtrField.Type)
+		return lastPtrField.Offset + typeptrdata(lastPtrField.Type)
 
 	default:
 		Fatalf("typeptrdata: unexpected type, %v", t)
@@ -680,11 +789,22 @@ func typeptrdata(t *Type) int64 {
 	}
 }
 
-// commonType
-// ../../runtime/type.go:/commonType
+// tflag is documented in reflect/type.go.
+//
+// tflag values must be kept in sync with copies in:
+//	cmd/compile/internal/gc/reflect.go
+//	cmd/link/internal/ld/decodesym.go
+//	reflect/type.go
+//	runtime/type.go
+const (
+	tflagUncommon  = 1 << 0
+	tflagExtraStar = 1 << 1
+	tflagNamed     = 1 << 2
+)
 
 var dcommontype_algarray *Sym
 
+// dcommontype dumps the contents of a reflect.rtype (runtime._type).
 func dcommontype(s *Sym, ot int, t *Type) int {
 	if ot != 0 {
 		Fatalf("dcommontype %d", ot)
@@ -697,41 +817,66 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	dowidth(t)
 	alg := algtype(t)
 	var algsym *Sym
-	if alg < 0 || alg == AMEM {
+	if alg == ASPECIAL || alg == AMEM {
 		algsym = dalgsym(t)
 	}
 
 	var sptr *Sym
 	tptr := Ptrto(t)
-	if !Isptr[t.Etype] && (t.Sym != nil || methods(tptr) != nil) {
+	if !t.IsPtr() && (t.Sym != nil || methods(tptr) != nil) {
 		sptr = dtypesym(tptr)
-	} else {
-		sptr = weaktypesym(tptr)
 	}
 
 	gcsym, useGCProg, ptrdata := dgcsym(t)
 
-	// ../../pkg/reflect/type.go:/^type.commonType
+	// ../../../../reflect/type.go:/^type.rtype
 	// actual type structure
-	//	type commonType struct {
+	//	type rtype struct {
 	//		size          uintptr
-	//		ptrsize       uintptr
+	//		ptrdata       uintptr
 	//		hash          uint32
-	//		_             uint8
+	//		tflag         tflag
 	//		align         uint8
 	//		fieldAlign    uint8
 	//		kind          uint8
-	//		alg           unsafe.Pointer
-	//		gcdata        unsafe.Pointer
-	//		string        *string
-	//		*extraType
-	//		ptrToThis     *Type
+	//		alg           *typeAlg
+	//		gcdata        *byte
+	//		str           nameOff
+	//		ptrToThis     typeOff
 	//	}
 	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
+
+	var tflag uint8
+	if uncommonSize(t) != 0 {
+		tflag |= tflagUncommon
+	}
+	if t.Sym != nil && t.Sym.Name != "" {
+		tflag |= tflagNamed
+	}
+
+	exported := false
+	p := Tconv(t, FmtLeft|FmtUnsigned)
+	// If we're writing out type T,
+	// we are very likely to write out type *T as well.
+	// Use the string "*T"[1:] for "T", so that the two
+	// share storage. This is a cheap way to reduce the
+	// amount of space taken up by reflect strings.
+	if !strings.HasPrefix(p, "*") {
+		p = "*" + p
+		tflag |= tflagExtraStar
+		if t.Sym != nil {
+			exported = exportname(t.Sym.Name)
+		}
+	} else {
+		if t.Elem() != nil && t.Elem().Sym != nil {
+			exported = exportname(t.Elem().Sym.Name)
+		}
+	}
+
+	ot = duint8(s, ot, tflag)
 
 	// runtime (and common sense) expects alignment to be a power of two.
 	i := int(t.Align)
@@ -746,9 +891,6 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	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
 	}
@@ -760,56 +902,40 @@ func dcommontype(s *Sym, ot int, t *Type) int {
 	}
 	ot = duint8(s, ot, uint8(i)) // kind
 	if algsym == nil {
-		ot = dsymptr(s, ot, dcommontype_algarray, alg*sizeofAlg)
+		ot = dsymptr(s, ot, dcommontype_algarray, int(alg)*sizeofAlg)
 	} else {
 		ot = dsymptr(s, ot, algsym, 0)
 	}
-	ot = dsymptr(s, ot, gcsym, 0)
-
-	p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
+	ot = dsymptr(s, ot, gcsym, 0) // gcdata
 
-	//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
+	nsym := dname(p, "", nil, exported)
+	ot = dsymptrOffLSym(Linksym(s), ot, nsym, 0) // str
+	if sptr == nil {
+		ot = duint32(s, ot, 0)
+	} else {
+		ot = dsymptrOffLSym(Linksym(s), ot, Linksym(sptr), 0) // ptrToThis
+	}
 
-	ot = dsymptr(s, ot, sptr, 0) // ptrto type
 	return ot
 }
 
 func typesym(t *Type) *Sym {
-	return Pkglookup(Tconv(t, obj.FmtLeft), typepkg)
+	return Pkglookup(Tconv(t, FmtLeft), typepkg)
 }
 
-func tracksym(t *Type) *Sym {
-	return Pkglookup(Tconv(t.Outer, obj.FmtLeft)+"."+t.Sym.Name, trackpkg)
+// tracksym returns the symbol for tracking use of field/method f, assumed
+// to be a member of struct/interface type t.
+func tracksym(t *Type, f *Field) *Sym {
+	return Pkglookup(Tconv(t, FmtLeft)+"."+f.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 typelinkLSym(t *Type) *obj.LSym {
+	name := "go.typelink." + Tconv(t, FmtLeft) // complete, unambiguous type name
+	return obj.Linklookup(Ctxt, name, 0)
 }
 
 func typesymprefix(prefix string, t *Type) *Sym {
-	p := prefix + "." + Tconv(t, obj.FmtLeft)
+	p := prefix + "." + Tconv(t, FmtLeft)
 	s := Pkglookup(p, typepkg)
 
 	//print("algsym: %s -> %+S\n", p, s);
@@ -818,22 +944,18 @@ func typesymprefix(prefix string, t *Type) *Sym {
 }
 
 func typenamesym(t *Type) *Sym {
-	if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
+	if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
 		Fatalf("typename %v", t)
 	}
 	s := typesym(t)
 	if s.Def == nil {
-		n := Nod(ONAME, nil, nil)
-		n.Sym = s
+		n := newname(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))
+		signatlist = append(signatlist, typenod(t))
 	}
 
 	return s.Def.Sym
@@ -849,13 +971,27 @@ func typename(t *Type) *Node {
 	return n
 }
 
-func weaktypesym(t *Type) *Sym {
-	p := Tconv(t, obj.FmtLeft)
-	s := Pkglookup(p, weaktypepkg)
+func itabname(t, itype *Type) *Node {
+	if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
+		Fatalf("itabname %v", t)
+	}
+	s := Pkglookup(Tconv(t, FmtLeft)+","+Tconv(itype, FmtLeft), itabpkg)
+	if s.Def == nil {
+		n := newname(s)
+		n.Type = Types[TUINT8]
+		n.Class = PEXTERN
+		n.Typecheck = 1
+		s.Def = n
 
-	//print("weaktypesym: %s -> %+S\n", p, s);
+		itabs = append(itabs, itabEntry{t: t, itype: itype, sym: s})
+	}
 
-	return s
+	n := Nod(OADDR, s.Def, nil)
+	n.Type = Ptrto(s.Def.Type)
+	n.Addable = true
+	n.Ullman = 2
+	n.Typecheck = 1
+	return n
 }
 
 // isreflexive reports whether t has a reflexive equality operator.
@@ -889,13 +1025,10 @@ func isreflexive(t *Type) bool {
 		return false
 
 	case TARRAY:
-		if Isslice(t) {
-			Fatalf("slice can't be a map key: %v", t)
-		}
-		return isreflexive(t.Type)
+		return isreflexive(t.Elem())
 
 	case TSTRUCT:
-		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+		for _, t1 := range t.Fields().Slice() {
 			if !isreflexive(t1.Type) {
 				return false
 			}
@@ -939,13 +1072,10 @@ func needkeyupdate(t *Type) bool {
 		return true
 
 	case TARRAY:
-		if Isslice(t) {
-			Fatalf("slice can't be a map key: %v", t)
-		}
-		return needkeyupdate(t.Type)
+		return needkeyupdate(t.Elem())
 
 	case TSTRUCT:
-		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+		for _, t1 := range t.Fields().Slice() {
 			if needkeyupdate(t1.Type) {
 				return true
 			}
@@ -966,7 +1096,7 @@ func dtypesym(t *Type) *Sym {
 		t = Types[t.Etype]
 	}
 
-	if isideal(t) {
+	if t.IsUntyped() {
 		Fatalf("dtypesym %v", t)
 	}
 
@@ -981,8 +1111,8 @@ func dtypesym(t *Type) *Sym {
 	// emit the type structures for int, float, etc.
 	tbase := t
 
-	if Isptr[t.Etype] && t.Sym == nil && t.Type.Sym != nil {
-		tbase = t.Type
+	if t.IsPtr() && t.Sym == nil && t.Elem().Sym != nil {
+		tbase = t.Elem()
 	}
 	dupok := 0
 	if tbase.Sym == nil {
@@ -1003,85 +1133,74 @@ func dtypesym(t *Type) *Sym {
 
 ok:
 	ot := 0
-	xt := 0
 	switch t.Etype {
 	default:
 		ot = dcommontype(s, ot, t)
-		xt = ot - 2*Widthptr
+		ot = dextratype(s, ot, t, 0)
 
 	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 - 2*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)
+		// ../../../../runtime/type.go:/arrayType
+		s1 := dtypesym(t.Elem())
+		t2 := typSlice(t.Elem())
+		s2 := dtypesym(t2)
+		ot = dcommontype(s, ot, t)
+		ot = dsymptr(s, ot, s1, 0)
+		ot = dsymptr(s, ot, s2, 0)
+		ot = duintptr(s, ot, uint64(t.NumElem()))
+		ot = dextratype(s, ot, t, 0)
 
-			ot = dcommontype(s, ot, t)
-			xt = ot - 2*Widthptr
-			ot = dsymptr(s, ot, s1, 0)
-		}
+	case TSLICE:
+		// ../../../../runtime/type.go:/sliceType
+		s1 := dtypesym(t.Elem())
+		ot = dcommontype(s, ot, t)
+		ot = dsymptr(s, ot, s1, 0)
+		ot = dextratype(s, ot, t, 0)
 
-	// ../../runtime/type.go:/ChanType
 	case TCHAN:
-		s1 := dtypesym(t.Type)
-
+		// ../../../../runtime/type.go:/chanType
+		s1 := dtypesym(t.Elem())
 		ot = dcommontype(s, ot, t)
-		xt = ot - 2*Widthptr
 		ot = dsymptr(s, ot, s1, 0)
-		ot = duintptr(s, ot, uint64(t.Chan))
+		ot = duintptr(s, ot, uint64(t.ChanDir()))
+		ot = dextratype(s, ot, t, 0)
 
 	case TFUNC:
-		for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
+		for _, t1 := range t.Recvs().Fields().Slice() {
 			dtypesym(t1.Type)
 		}
 		isddd := false
-		for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
+		for _, t1 := range t.Params().Fields().Slice() {
 			isddd = t1.Isddd
 			dtypesym(t1.Type)
 		}
-
-		for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
+		for _, t1 := range t.Results().Fields().Slice() {
 			dtypesym(t1.Type)
 		}
 
 		ot = dcommontype(s, ot, t)
-		xt = ot - 2*Widthptr
-		ot = duint8(s, ot, uint8(obj.Bool2int(isddd)))
+		inCount := t.Recvs().NumFields() + t.Params().NumFields()
+		outCount := t.Results().NumFields()
+		if isddd {
+			outCount |= 1 << 15
+		}
+		ot = duint16(s, ot, uint16(inCount))
+		ot = duint16(s, ot, uint16(outCount))
+		if Widthptr == 8 {
+			ot += 4 // align for *rtype
+		}
 
-		// two slice headers: in and out.
-		ot = int(Rnd(int64(ot), int64(Widthptr)))
+		dataAdd := (inCount + t.Results().NumFields()) * Widthptr
+		ot = dextratype(s, ot, t, dataAdd)
 
-		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 {
+		// Array of rtype pointers follows funcType.
+		for _, t1 := range t.Recvs().Fields().Slice() {
 			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
-			n++
 		}
-		for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
+		for _, t1 := range t.Params().Fields().Slice() {
 			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
-			n++
 		}
-		for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
+		for _, t1 := range t.Results().Fields().Slice() {
 			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
-			n++
 		}
 
 	case TINTER:
@@ -1091,169 +1210,198 @@ ok:
 			dtypesym(a.type_)
 		}
 
-		// ../../../runtime/type.go:/InterfaceType
+		// ../../../../runtime/type.go:/interfaceType
 		ot = dcommontype(s, ot, t)
 
-		xt = ot - 2*Widthptr
-		ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+		var tpkg *Pkg
+		if t.Sym != nil && t != Types[t.Etype] && t != errortype {
+			tpkg = t.Sym.Pkg
+		}
+		ot = dgopkgpath(s, ot, tpkg)
+
+		ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t))
 		ot = duintxx(s, ot, uint64(n), Widthint)
 		ot = duintxx(s, ot, uint64(n), Widthint)
+		dataAdd := imethodSize() * n
+		ot = dextratype(s, ot, t, dataAdd)
+
+		lsym := Linksym(s)
 		for _, a := range m {
-			// ../../../runtime/type.go:/imethod
-			ot = dgostringptr(s, ot, a.name)
+			// ../../../../runtime/type.go:/imethod
+			exported := exportname(a.name)
+			var pkg *Pkg
+			if !exported && a.pkg != tpkg {
+				pkg = a.pkg
+			}
+			nsym := dname(a.name, "", pkg, exported)
 
-			ot = dgopkgpath(s, ot, a.pkg)
-			ot = dsymptr(s, ot, dtypesym(a.type_), 0)
+			ot = dsymptrOffLSym(lsym, ot, nsym, 0)
+			ot = dsymptrOffLSym(lsym, ot, Linksym(dtypesym(a.type_)), 0)
 		}
 
-	// ../../../runtime/type.go:/MapType
+	// ../../../../runtime/type.go:/mapType
 	case TMAP:
-		s1 := dtypesym(t.Down)
-
-		s2 := dtypesym(t.Type)
+		s1 := dtypesym(t.Key())
+		s2 := dtypesym(t.Val())
 		s3 := dtypesym(mapbucket(t))
 		s4 := dtypesym(hmap(t))
 		ot = dcommontype(s, ot, t)
-		xt = ot - 2*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 {
+		if t.Key().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, uint8(t.Key().Width))
 			ot = duint8(s, ot, 0) // not indirect
 		}
 
-		if t.Type.Width > MAXVALSIZE {
+		if t.Val().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, uint8(t.Val().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))))
-		ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down))))
+		ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Key()))))
+		ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Key()))))
+		ot = dextratype(s, ot, t, 0)
 
 	case TPTR32, TPTR64:
-		if t.Type.Etype == TANY {
-			// ../../runtime/type.go:/UnsafePointerType
+		if t.Elem().Etype == TANY {
+			// ../../../../runtime/type.go:/UnsafePointerType
 			ot = dcommontype(s, ot, t)
+			ot = dextratype(s, ot, t, 0)
 
 			break
 		}
 
-		// ../../runtime/type.go:/PtrType
-		s1 := dtypesym(t.Type)
+		// ../../../../runtime/type.go:/ptrType
+		s1 := dtypesym(t.Elem())
 
 		ot = dcommontype(s, ot, t)
-		xt = ot - 2*Widthptr
 		ot = dsymptr(s, ot, s1, 0)
+		ot = dextratype(s, ot, t, 0)
 
-	// ../../runtime/type.go:/StructType
+	// ../../../../runtime/type.go:/structType
 	// for security, only the exported fields.
 	case TSTRUCT:
 		n := 0
 
-		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+		for _, t1 := range t.Fields().Slice() {
 			dtypesym(t1.Type)
 			n++
 		}
 
 		ot = dcommontype(s, ot, t)
-		xt = ot - 2*Widthptr
-		ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+		pkg := localpkg
+		if t.Sym != nil {
+			pkg = t.Sym.Pkg
+		}
+		ot = dgopkgpath(s, ot, pkg)
+		ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t))
 		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 || !exportname(t1.Type.Sym.Name)) {
-					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
+		dataAdd := n * structfieldSize()
+		ot = dextratype(s, ot, t, dataAdd)
+
+		for _, f := range t.Fields().Slice() {
+			// ../../../../runtime/type.go:/structField
+			ot = dnameField(s, ot, f)
+			ot = dsymptr(s, ot, dtypesym(f.Type), 0)
+			ot = duintptr(s, ot, uint64(f.Offset))
 		}
 	}
 
-	ot = dextratype(s, ot, t, xt)
+	ot = dextratypeData(s, ot, t)
 	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 {
+	// types in the binary, so the runtime can find them.
+	//
+	// When buildmode=shared, all types are in typelinks so the
+	// runtime can deduplicate type pointers.
+	keep := Ctxt.Flag_dynlink
+	if !keep && t.Sym == nil {
+		// For an unnamed type, we only need the link if the type can
+		// be created at run time by reflect.PtrTo and similar
+		// functions. If the type exists in the program, those
+		// functions must return the existing type structure rather
+		// than creating a new one.
 		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))
+		case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRUCT:
+			keep = true
 		}
 	}
+	if keep {
+		slink := typelinkLSym(t)
+		dsymptrOffLSym(slink, 0, Linksym(s), 0)
+		ggloblLSym(slink, 4, int16(dupok|obj.RODATA))
+	}
 
 	return s
 }
 
 func dumptypestructs() {
-	var n *Node
-
 	// copy types from externdcl list to signatlist
 	for _, n := range externdcl {
 		if n.Op != OTYPE {
 			continue
 		}
-		signatlist = list(signatlist, n)
+		signatlist = append(signatlist, n)
 	}
 
-	// process signatlist
-	var t *Type
-	for l := signatlist; l != nil; l = l.Next {
-		n = l.N
+	// Process signatlist.  This can't use range, as entries are
+	// added to the list while it is being processed.
+	for i := 0; i < len(signatlist); i++ {
+		n := signatlist[i]
 		if n.Op != OTYPE {
 			continue
 		}
-		t = n.Type
+		t := n.Type
 		dtypesym(t)
 		if t.Sym != nil {
 			dtypesym(Ptrto(t))
 		}
 	}
 
+	// process itabs
+	for _, i := range itabs {
+		// dump empty itab symbol into i.sym
+		// type itab struct {
+		//   inter  *interfacetype
+		//   _type  *_type
+		//   link   *itab
+		//   bad    int32
+		//   unused int32
+		//   fun    [1]uintptr // variable sized
+		// }
+		o := dsymptr(i.sym, 0, dtypesym(i.itype), 0)
+		o = dsymptr(i.sym, o, dtypesym(i.t), 0)
+		o += Widthptr + 8                      // skip link/bad/unused fields
+		o += len(imethods(i.itype)) * Widthptr // skip fun method pointers
+		// at runtime the itab will contain pointers to types, other itabs and
+		// method functions. None are allocated on heap, so we can use obj.NOPTR.
+		ggloblsym(i.sym, int32(o), int16(obj.DUPOK|obj.NOPTR))
+
+		ilink := Pkglookup(Tconv(i.t, FmtLeft)+","+Tconv(i.itype, FmtLeft), itablinkpkg)
+		dsymptr(ilink, 0, i.sym, 0)
+		ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA))
+	}
+
 	// generate import strings for imported packages
+	if forceObjFileStability {
+		// Sorting the packages is not necessary but to compare binaries created
+		// using textual and binary format we sort by path to reduce differences.
+		sort.Sort(pkgByPath(pkgs))
+	}
 	for _, p := range pkgs {
 		if p.Direct {
 			dimportpath(p)
@@ -1277,21 +1425,27 @@ func dumptypestructs() {
 		// 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])))))
+		dtypesym(functype(nil, []*Node{Nod(ODCLFIELD, nil, typenod(errortype))}, []*Node{Nod(ODCLFIELD, nil, typenod(Types[TSTRING]))}))
 
 		// add paths for runtime and main, which 6l imports implicitly.
 		dimportpath(Runtimepkg)
 
-		if flag_race != 0 {
+		if flag_race {
 			dimportpath(racepkg)
 		}
-		if flag_msan != 0 {
+		if flag_msan {
 			dimportpath(msanpkg)
 		}
 		dimportpath(mkpkg("main"))
 	}
 }
 
+type pkgByPath []*Pkg
+
+func (a pkgByPath) Len() int           { return len(a) }
+func (a pkgByPath) Less(i, j int) bool { return a[i].Path < a[j].Path }
+func (a pkgByPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
 func dalgsym(t *Type) *Sym {
 	var s *Sym
 	var hashfunc *Sym
@@ -1350,7 +1504,7 @@ func dalgsym(t *Type) *Sym {
 		ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
 	}
 
-	// ../../runtime/alg.go:/typeAlg
+	// ../../../../runtime/alg.go:/typeAlg
 	ot := 0
 
 	ot = dsymptr(s, ot, hashfunc, 0)
@@ -1378,7 +1532,7 @@ func dalgsym(t *Type) *Sym {
 // 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
+// for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated
 // is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes
 // must be >= 4.
 //
@@ -1521,22 +1675,21 @@ func (p *GCProg) emit(t *Type, offset int64) {
 		p.w.Ptr(offset / int64(Widthptr))
 		p.w.Ptr(offset/int64(Widthptr) + 1)
 
+	case TSLICE:
+		p.w.Ptr(offset / int64(Widthptr))
+
 	case TARRAY:
-		if Isslice(t) {
-			p.w.Ptr(offset / int64(Widthptr))
-			return
-		}
-		if t.Bound == 0 {
+		if t.NumElem() == 0 {
 			// should have been handled by haspointers check above
 			Fatalf("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
+		count := t.NumElem()
+		elem := t.Elem()
+		for elem.IsArray() {
+			count *= elem.NumElem()
+			elem = elem.Elem()
 		}
 
 		if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) {
@@ -1551,8 +1704,32 @@ func (p *GCProg) emit(t *Type, offset int64) {
 		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)
+		for _, t1 := range t.Fields().Slice() {
+			p.emit(t1.Type, offset+t1.Offset)
 		}
 	}
 }
+
+// zeroaddr returns the address of a symbol with at least
+// size bytes of zeros.
+func zeroaddr(size int64) *Node {
+	if size >= 1<<31 {
+		Fatalf("map value too big %d", size)
+	}
+	if zerosize < size {
+		zerosize = size
+	}
+	s := Pkglookup("zero", mappkg)
+	if s.Def == nil {
+		x := newname(s)
+		x.Type = Types[TUINT8]
+		x.Class = PEXTERN
+		x.Typecheck = 1
+		s.Def = x
+	}
+	z := Nod(OADDR, s.Def, nil)
+	z.Type = Ptrto(Types[TUINT8])
+	z.Addable = true
+	z.Typecheck = 1
+	return z
+}
diff --git a/src/cmd/compile/internal/gc/reg.go b/src/cmd/compile/internal/gc/reg.go
index 14dc03b..a80d72b 100644
--- a/src/cmd/compile/internal/gc/reg.go
+++ b/src/cmd/compile/internal/gc/reg.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -33,6 +33,7 @@ package gc
 import (
 	"bytes"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"sort"
 	"strings"
@@ -246,11 +247,11 @@ func addmove(r *Flow, bn int, rn int, f int) {
 	else if(a->sym == nil)
 		a->type = TYPE_CONST;
 	*/
-	p1.As = int16(Thearch.Optoas(OAS, Types[uint8(v.etype)]))
+	p1.As = Thearch.Optoas(OAS, Types[uint8(v.etype)])
 
 	// TODO(rsc): Remove special case here.
-	if (Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && v.etype == TBOOL {
-		p1.As = int16(Thearch.Optoas(OAS, Types[TUINT8]))
+	if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) && v.etype == TBOOL {
+		p1.As = Thearch.Optoas(OAS, Types[TUINT8])
 	}
 	p1.From.Type = obj.TYPE_REG
 	p1.From.Reg = int16(rn)
@@ -302,7 +303,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
 		// TODO(rsc): Remove special case here.
 	case obj.TYPE_ADDR:
 		var bit Bits
-		if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+		if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) {
 			goto memcase
 		}
 		a.Type = obj.TYPE_MEM
@@ -368,7 +369,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
 				if v.etype == et {
 					if int64(v.width) == w {
 						// TODO(rsc): Remove special case for arm here.
-						if flag == 0 || Thearch.Thechar != '5' {
+						if flag == 0 || Thearch.LinkArch.Family != sys.ARM {
 							return blsh(uint(i))
 						}
 					}
@@ -392,10 +393,10 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
 
 	if nvar >= NVAR {
 		if Debug['w'] > 1 && node != nil {
-			Fatalf("variable not optimized: %v", Nconv(node, obj.FmtSharp))
+			Fatalf("variable not optimized: %v", Nconv(node, FmtSharp))
 		}
 		if Debug['v'] > 0 {
-			Warn("variable not optimized: %v", Nconv(node, obj.FmtSharp))
+			Warn("variable not optimized: %v", Nconv(node, FmtSharp))
 		}
 
 		// If we're not tracking a word in a variable, mark the rest as
@@ -487,7 +488,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits {
 	}
 
 	if Debug['R'] != 0 {
-		fmt.Printf("bit=%2d et=%v w=%d+%d %v %v flag=%d\n", i, Econv(et), o, w, Nconv(node, obj.FmtSharp), Ctxt.Dconv(a), v.addr)
+		fmt.Printf("bit=%2d et=%v w=%d+%d %v %v flag=%d\n", i, et, o, w, Nconv(node, FmtSharp), Ctxt.Dconv(a), v.addr)
 	}
 	Ostats.Nvar++
 
@@ -651,7 +652,7 @@ func allreg(b uint64, r *Rgn) uint64 {
 	r.regno = 0
 	switch v.etype {
 	default:
-		Fatalf("unknown etype %d/%v", Bitno(b), Econv(v.etype))
+		Fatalf("unknown etype %d/%v", Bitno(b), v.etype)
 
 	case TINT8,
 		TUINT8,
@@ -1114,7 +1115,7 @@ func regopt(firstp *obj.Prog) {
 
 		// Currently we never generate three register forms.
 		// If we do, this will need to change.
-		if p.From3Type() != obj.TYPE_NONE {
+		if p.From3Type() != obj.TYPE_NONE && p.From3Type() != obj.TYPE_CONST {
 			Fatalf("regopt not implemented for from3")
 		}
 
@@ -1146,7 +1147,7 @@ func regopt(firstp *obj.Prog) {
 		}
 
 		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(v.etype), v.width, v.node, v.offset)
+			fmt.Printf("bit=%2d addr=%d et=%v w=%-2d s=%v + %d\n", i, v.addr, v.etype, v.width, v.node, v.offset)
 		}
 	}
 
@@ -1286,7 +1287,6 @@ loop2:
 	}
 	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++ {
@@ -1347,20 +1347,18 @@ loop2:
 	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]
+		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)
+		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(v.etype), obj.Rconv(int(rgp.regno)), usedreg, vreg)
+				fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", v.node, v.offset, rgp.varno, v.etype, obj.Rconv(int(rgp.regno)), usedreg, vreg)
 			}
 
 			paint3(rgp.enter, int(rgp.varno), vreg, int(rgp.regno))
@@ -1525,7 +1523,7 @@ func (bits Bits) String() string {
 		} else {
 			fmt.Fprintf(&buf, "%s(%d)", v.node.Sym.Name, i)
 			if v.offset != 0 {
-				fmt.Fprintf(&buf, "%+d", int64(v.offset))
+				fmt.Fprintf(&buf, "%+d", v.offset)
 			}
 		}
 		biclr(&bits, uint(i))
diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
index e770c8f..120a9b8 100644
--- a/src/cmd/compile/internal/gc/select.go
+++ b/src/cmd/compile/internal/gc/select.go
@@ -10,30 +10,31 @@ func typecheckselect(sel *Node) {
 	var n *Node
 
 	var def *Node
-	lno := int(setlineno(sel))
+	lno := setlineno(sel)
 	count := 0
-	typechecklist(sel.Ninit, Etop)
-	for l := sel.List; l != nil; l = l.Next {
+	typecheckslice(sel.Ninit.Slice(), Etop)
+	for _, n1 := range sel.List.Slice() {
 		count++
-		ncase = l.N
+		ncase = n1
 		setlineno(ncase)
 		if ncase.Op != OXCASE {
-			Fatalf("typecheckselect %v", Oconv(int(ncase.Op), 0))
+			Fatalf("typecheckselect %v", ncase.Op)
 		}
 
-		if ncase.List == nil {
+		if ncase.List.Len() == 0 {
 			// default
 			if def != nil {
 				Yyerror("multiple defaults in select (first at %v)", def.Line())
 			} else {
 				def = ncase
 			}
-		} else if ncase.List.Next != nil {
+		} else if ncase.List.Len() > 1 {
 			Yyerror("select cases cannot be lists")
 		} else {
-			n = typecheck(&ncase.List.N, Etop)
+			ncase.List.SetIndex(0, typecheck(ncase.List.Index(0), Etop))
+			n = ncase.List.Index(0)
 			ncase.Left = n
-			ncase.List = nil
+			ncase.List.Set(nil)
 			setlineno(n)
 			switch n.Op {
 			default:
@@ -56,16 +57,16 @@ func typecheckselect(sel *Node) {
 
 				// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
 			case OAS2RECV:
-				if n.Rlist.N.Op != ORECV {
+				if n.Rlist.First().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
+				n.Left = n.List.First()
+				n.List.Set1(n.List.Second())
+				n.Right = n.Rlist.First()
+				n.Rlist.Set(nil)
 
 				// convert <-c into OSELRECV(N, <-c)
 			case ORECV:
@@ -79,30 +80,29 @@ func typecheckselect(sel *Node) {
 			}
 		}
 
-		typechecklist(ncase.Nbody, Etop)
+		typecheckslice(ncase.Nbody.Slice(), Etop)
 	}
 
 	sel.Xoffset = int64(count)
-	lineno = int32(lno)
+	lineno = lno
 }
 
 func walkselect(sel *Node) {
-	if sel.List == nil && sel.Xoffset != 0 {
+	if sel.List.Len() == 0 && sel.Xoffset != 0 {
 		Fatalf("double walkselect") // already rewrote
 	}
 
-	lno := int(setlineno(sel))
-	i := count(sel.List)
+	lno := setlineno(sel)
+	i := sel.List.Len()
 
 	// optimization: zero-case select
-	var init *NodeList
+	var init []*Node
 	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))
+		sel.Nbody.Set1(mkcall("block", nil, nil))
 		goto out
 	}
 
@@ -110,17 +110,17 @@ func walkselect(sel *Node) {
 	// TODO(rsc): Reenable optimization once order.go can handle it.
 	// golang.org/issue/7672.
 	if i == 1 {
-		cas := sel.List.N
+		cas := sel.List.First()
 		setlineno(cas)
-		l := cas.Ninit
+		l := cas.Ninit.Slice()
 		if cas.Left != nil { // not default:
 			n := cas.Left
-			l = concat(l, n.Ninit)
-			n.Ninit = nil
+			l = append(l, n.Ninit.Slice()...)
+			n.Ninit.Set(nil)
 			var ch *Node
 			switch n.Op {
 			default:
-				Fatalf("select %v", Oconv(int(n.Op), 0))
+				Fatalf("select %v", n.Op)
 
 				// ok already
 			case OSEND:
@@ -128,7 +128,7 @@ func walkselect(sel *Node) {
 
 			case OSELRECV, OSELRECV2:
 				ch = n.Right.Left
-				if n.Op == OSELRECV || n.List == nil {
+				if n.Op == OSELRECV || n.List.Len() == 0 {
 					if n.Left == nil {
 						n = n.Right
 					} else {
@@ -138,38 +138,40 @@ func walkselect(sel *Node) {
 				}
 
 				if n.Left == nil {
-					typecheck(&nblank, Erv|Easgn)
+					nblank = typecheck(nblank, Erv|Easgn)
 					n.Left = nblank
 				}
 
 				n.Op = OAS2
-				n.List = concat(list1(n.Left), n.List)
-				n.Rlist = list1(n.Right)
+				n.List.Set(append([]*Node{n.Left}, n.List.Slice()...))
+				n.Rlist.Set1(n.Right)
 				n.Right = nil
 				n.Left = nil
 				n.Typecheck = 0
-				typecheck(&n, Etop)
+				n = 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)
+			var ln Nodes
+			ln.Set(l)
+			a.Nbody.Set1(mkcall("block", nil, &ln))
+			l = ln.Slice()
+			a = typecheck(a, Etop)
+			l = append(l, a)
+			l = append(l, n)
 		}
 
-		l = concat(l, cas.Nbody)
-		sel.Nbody = l
+		l = append(l, cas.Nbody.Slice()...)
+		sel.Nbody.Set(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
+	for _, cas := range sel.List.Slice() {
 		setlineno(cas)
 		n = cas.Left
 		if n == nil {
@@ -178,45 +180,45 @@ func walkselect(sel *Node) {
 		switch n.Op {
 		case OSEND:
 			n.Right = Nod(OADDR, n.Right, nil)
-			typecheck(&n.Right, Erv)
+			n.Right = typecheck(n.Right, Erv)
 
 		case OSELRECV, OSELRECV2:
-			if n.Op == OSELRECV2 && n.List == nil {
+			if n.Op == OSELRECV2 && n.List.Len() == 0 {
 				n.Op = OSELRECV
 			}
 			if n.Op == OSELRECV2 {
-				n.List.N = Nod(OADDR, n.List.N, nil)
-				typecheck(&n.List.N, Erv)
+				n.List.SetIndex(0, Nod(OADDR, n.List.First(), nil))
+				n.List.SetIndex(0, typecheck(n.List.Index(0), Erv))
 			}
 
 			if n.Left == nil {
 				n.Left = nodnil()
 			} else {
 				n.Left = Nod(OADDR, n.Left, nil)
-				typecheck(&n.Left, Erv)
+				n.Left = 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) {
+	if i == 2 && (sel.List.First().Left == nil || sel.List.Second().Left == nil) {
 		var cas *Node
 		var dflt *Node
-		if sel.List.N.Left == nil {
-			cas = sel.List.Next.N
-			dflt = sel.List.N
+		if sel.List.First().Left == nil {
+			cas = sel.List.Second()
+			dflt = sel.List.First()
 		} else {
-			dflt = sel.List.Next.N
-			cas = sel.List.N
+			dflt = sel.List.Second()
+			cas = sel.List.First()
 		}
 
 		n := cas.Left
 		setlineno(n)
 		r := Nod(OIF, nil, nil)
-		r.Ninit = cas.Ninit
+		r.Ninit.Set(cas.Ninit.Slice())
 		switch n.Op {
 		default:
-			Fatalf("select %v", Oconv(int(n.Op), 0))
+			Fatalf("select %v", n.Op)
 
 			// if selectnbsend(c, v) { body } else { default body }
 		case OSEND:
@@ -228,7 +230,7 @@ func walkselect(sel *Node) {
 		case OSELRECV:
 			r = Nod(OIF, nil, nil)
 
-			r.Ninit = cas.Ninit
+			r.Ninit.Set(cas.Ninit.Slice())
 			ch := n.Right.Left
 			r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), Types[TBOOL], &r.Ninit, typename(ch.Type), n.Left, ch)
 
@@ -236,44 +238,42 @@ func walkselect(sel *Node) {
 		case OSELRECV2:
 			r = Nod(OIF, nil, nil)
 
-			r.Ninit = cas.Ninit
+			r.Ninit.Set(cas.Ninit.Slice())
 			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)
+			r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), Types[TBOOL], &r.Ninit, typename(ch.Type), n.Left, n.List.First(), ch)
 		}
 
-		typecheck(&r.Left, Erv)
-		r.Nbody = cas.Nbody
-		r.Rlist = concat(dflt.Ninit, dflt.Nbody)
-		sel.Nbody = list1(r)
+		r.Left = typecheck(r.Left, Erv)
+		r.Nbody.Set(cas.Nbody.Slice())
+		r.Rlist.Set(append(dflt.Ninit.Slice(), dflt.Nbody.Slice()...))
+		sel.Nbody.Set1(r)
 		goto out
 	}
 
-	init = sel.Ninit
-	sel.Ninit = nil
+	init = sel.Ninit.Slice()
+	sel.Ninit.Set(nil)
 
 	// generate sel-struct
 	setlineno(sel)
 
 	selv = temp(selecttype(int32(sel.Xoffset)))
 	r = Nod(OAS, selv, nil)
-	typecheck(&r, Etop)
-	init = list(init, r)
+	r = typecheck(r, Etop)
+	init = append(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)
-
+	r = typecheck(r, Etop)
+	init = append(init, r)
 	// register cases
-	for l := sel.List; l != nil; l = l.Next {
-		cas = l.N
+	for _, cas := range sel.List.Slice() {
 		setlineno(cas)
 		n = cas.Left
 		r = Nod(OIF, nil, nil)
-		r.Ninit = cas.Ninit
-		cas.Ninit = nil
+		r.Ninit.Set(cas.Ninit.Slice())
+		cas.Ninit.Set(nil)
 		if n != nil {
-			r.Ninit = concat(r.Ninit, n.Ninit)
-			n.Ninit = nil
+			r.Ninit.AppendNodes(&n.Ninit)
+			n.Ninit.Set(nil)
 		}
 
 		if n == nil {
@@ -282,7 +282,7 @@ func walkselect(sel *Node) {
 		} else {
 			switch n.Op {
 			default:
-				Fatalf("select %v", Oconv(int(n.Op), 0))
+				Fatalf("select %v", n.Op)
 
 				// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
 			case OSEND:
@@ -294,72 +294,59 @@ func walkselect(sel *Node) {
 
 				// 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)
+				r.Left = mkcall1(chanfn("selectrecv2", 2, n.Right.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Right.Left, n.Left, n.List.First())
 			}
 		}
 
 		// selv is no longer alive after use.
-		r.Nbody = list(r.Nbody, Nod(OVARKILL, selv, nil))
+		r.Nbody.Append(Nod(OVARKILL, selv, nil))
 
-		r.Nbody = concat(r.Nbody, cas.Nbody)
-		r.Nbody = list(r.Nbody, Nod(OBREAK, nil, nil))
-		init = list(init, r)
+		r.Nbody.AppendNodes(&cas.Nbody)
+		r.Nbody.Append(Nod(OBREAK, nil, nil))
+		init = append(init, r)
 	}
 
 	// run the select
 	setlineno(sel)
 
-	init = list(init, mkcall("selectgo", nil, nil, var_))
-	sel.Nbody = init
+	init = append(init, mkcall("selectgo", nil, nil, var_))
+	sel.Nbody.Set(init)
 
 out:
-	sel.List = nil
-	walkstmtlist(sel.Nbody)
-	lineno = int32(lno)
+	sel.List.Set(nil)
+	walkstmtlist(sel.Nbody.Slice())
+	lineno = lno
 }
 
-// Keep in sync with src/runtime/runtime2.go and src/runtime/select.go.
+// Keep in sync with src/runtime/select.go.
 func selecttype(size int32) *Type {
-	// TODO(dvyukov): it's possible to generate SudoG and Scase only once
+	// TODO(dvyukov): it's possible to generate 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 = true
-	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.List.Append(Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8]))))
+	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("chan")), typenod(Ptrto(Types[TUINT8]))))
+	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("pc")), typenod(Types[TUINTPTR])))
+	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("kind")), typenod(Types[TUINT16])))
+	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("so")), typenod(Types[TUINT16])))
+	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("receivedp")), typenod(Ptrto(Types[TUINT8]))))
+	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64])))
+	scase = typecheck(scase, Etype)
 	scase.Type.Noalg = true
 	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]))))
+	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("tcase")), typenod(Types[TUINT16])))
+	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("ncase")), typenod(Types[TUINT16])))
+	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("pollorder")), typenod(Ptrto(Types[TUINT8]))))
+	sel.List.Append(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))
+	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("scase")), arr))
+	arr = Nod(OTARRAY, Nodintconst(int64(size)), typenod(Types[TUINT16]))
+	sel.List.Append(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.List.Append(Nod(ODCLFIELD, newname(Lookup("pollorderarr")), arr))
+	sel = typecheck(sel, Etype)
 	sel.Type.Noalg = true
 	sel.Type.Local = true
 
diff --git a/src/cmd/compile/internal/gc/shift_test.go b/src/cmd/compile/internal/gc/shift_test.go
new file mode 100644
index 0000000..ce2eedf
--- /dev/null
+++ b/src/cmd/compile/internal/gc/shift_test.go
@@ -0,0 +1,1031 @@
+// Copyright 2016 The Go Authors. 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 (
+	"reflect"
+	"testing"
+)
+
+// Tests shifts of zero.
+
+//go:noinline
+func ofz64l64(n uint64) int64 {
+	var x int64
+	return x << n
+}
+
+//go:noinline
+func ofz64l32(n uint32) int64 {
+	var x int64
+	return x << n
+}
+
+//go:noinline
+func ofz64l16(n uint16) int64 {
+	var x int64
+	return x << n
+}
+
+//go:noinline
+func ofz64l8(n uint8) int64 {
+	var x int64
+	return x << n
+}
+
+//go:noinline
+func ofz64r64(n uint64) int64 {
+	var x int64
+	return x >> n
+}
+
+//go:noinline
+func ofz64r32(n uint32) int64 {
+	var x int64
+	return x >> n
+}
+
+//go:noinline
+func ofz64r16(n uint16) int64 {
+	var x int64
+	return x >> n
+}
+
+//go:noinline
+func ofz64r8(n uint8) int64 {
+	var x int64
+	return x >> n
+}
+
+//go:noinline
+func ofz64ur64(n uint64) uint64 {
+	var x uint64
+	return x >> n
+}
+
+//go:noinline
+func ofz64ur32(n uint32) uint64 {
+	var x uint64
+	return x >> n
+}
+
+//go:noinline
+func ofz64ur16(n uint16) uint64 {
+	var x uint64
+	return x >> n
+}
+
+//go:noinline
+func ofz64ur8(n uint8) uint64 {
+	var x uint64
+	return x >> n
+}
+
+//go:noinline
+func ofz32l64(n uint64) int32 {
+	var x int32
+	return x << n
+}
+
+//go:noinline
+func ofz32l32(n uint32) int32 {
+	var x int32
+	return x << n
+}
+
+//go:noinline
+func ofz32l16(n uint16) int32 {
+	var x int32
+	return x << n
+}
+
+//go:noinline
+func ofz32l8(n uint8) int32 {
+	var x int32
+	return x << n
+}
+
+//go:noinline
+func ofz32r64(n uint64) int32 {
+	var x int32
+	return x >> n
+}
+
+//go:noinline
+func ofz32r32(n uint32) int32 {
+	var x int32
+	return x >> n
+}
+
+//go:noinline
+func ofz32r16(n uint16) int32 {
+	var x int32
+	return x >> n
+}
+
+//go:noinline
+func ofz32r8(n uint8) int32 {
+	var x int32
+	return x >> n
+}
+
+//go:noinline
+func ofz32ur64(n uint64) uint32 {
+	var x uint32
+	return x >> n
+}
+
+//go:noinline
+func ofz32ur32(n uint32) uint32 {
+	var x uint32
+	return x >> n
+}
+
+//go:noinline
+func ofz32ur16(n uint16) uint32 {
+	var x uint32
+	return x >> n
+}
+
+//go:noinline
+func ofz32ur8(n uint8) uint32 {
+	var x uint32
+	return x >> n
+}
+
+//go:noinline
+func ofz16l64(n uint64) int16 {
+	var x int16
+	return x << n
+}
+
+//go:noinline
+func ofz16l32(n uint32) int16 {
+	var x int16
+	return x << n
+}
+
+//go:noinline
+func ofz16l16(n uint16) int16 {
+	var x int16
+	return x << n
+}
+
+//go:noinline
+func ofz16l8(n uint8) int16 {
+	var x int16
+	return x << n
+}
+
+//go:noinline
+func ofz16r64(n uint64) int16 {
+	var x int16
+	return x >> n
+}
+
+//go:noinline
+func ofz16r32(n uint32) int16 {
+	var x int16
+	return x >> n
+}
+
+//go:noinline
+func ofz16r16(n uint16) int16 {
+	var x int16
+	return x >> n
+}
+
+//go:noinline
+func ofz16r8(n uint8) int16 {
+	var x int16
+	return x >> n
+}
+
+//go:noinline
+func ofz16ur64(n uint64) uint16 {
+	var x uint16
+	return x >> n
+}
+
+//go:noinline
+func ofz16ur32(n uint32) uint16 {
+	var x uint16
+	return x >> n
+}
+
+//go:noinline
+func ofz16ur16(n uint16) uint16 {
+	var x uint16
+	return x >> n
+}
+
+//go:noinline
+func ofz16ur8(n uint8) uint16 {
+	var x uint16
+	return x >> n
+}
+
+//go:noinline
+func ofz8l64(n uint64) int8 {
+	var x int8
+	return x << n
+}
+
+//go:noinline
+func ofz8l32(n uint32) int8 {
+	var x int8
+	return x << n
+}
+
+//go:noinline
+func ofz8l16(n uint16) int8 {
+	var x int8
+	return x << n
+}
+
+//go:noinline
+func ofz8l8(n uint8) int8 {
+	var x int8
+	return x << n
+}
+
+//go:noinline
+func ofz8r64(n uint64) int8 {
+	var x int8
+	return x >> n
+}
+
+//go:noinline
+func ofz8r32(n uint32) int8 {
+	var x int8
+	return x >> n
+}
+
+//go:noinline
+func ofz8r16(n uint16) int8 {
+	var x int8
+	return x >> n
+}
+
+//go:noinline
+func ofz8r8(n uint8) int8 {
+	var x int8
+	return x >> n
+}
+
+//go:noinline
+func ofz8ur64(n uint64) uint8 {
+	var x uint8
+	return x >> n
+}
+
+//go:noinline
+func ofz8ur32(n uint32) uint8 {
+	var x uint8
+	return x >> n
+}
+
+//go:noinline
+func ofz8ur16(n uint16) uint8 {
+	var x uint8
+	return x >> n
+}
+
+//go:noinline
+func ofz8ur8(n uint8) uint8 {
+	var x uint8
+	return x >> n
+}
+
+func TestShiftOfZero(t *testing.T) {
+	if got := ofz64l64(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz64l32(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz64l16(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz64l8(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz64r64(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz64r32(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz64r16(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz64r8(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz64ur64(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz64ur32(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz64ur16(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz64ur8(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+
+	if got := ofz32l64(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz32l32(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz32l16(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz32l8(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz32r64(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz32r32(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz32r16(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz32r8(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz32ur64(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz32ur32(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz32ur16(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz32ur8(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+
+	if got := ofz16l64(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz16l32(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz16l16(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz16l8(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz16r64(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz16r32(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz16r16(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz16r8(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz16ur64(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz16ur32(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz16ur16(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz16ur8(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+
+	if got := ofz8l64(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz8l32(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz8l16(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz8l8(5); got != 0 {
+		t.Errorf("0<<5 == %d, want 0", got)
+	}
+	if got := ofz8r64(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz8r32(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz8r16(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz8r8(5); got != 0 {
+		t.Errorf("0>>5 == %d, want 0", got)
+	}
+	if got := ofz8ur64(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz8ur32(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz8ur16(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+	if got := ofz8ur8(5); got != 0 {
+		t.Errorf("0>>>5 == %d, want 0", got)
+	}
+}
+
+//go:noinline
+func byz64l(n int64) int64 {
+	return n << 0
+}
+
+//go:noinline
+func byz64r(n int64) int64 {
+	return n >> 0
+}
+
+//go:noinline
+func byz64ur(n uint64) uint64 {
+	return n >> 0
+}
+
+//go:noinline
+func byz32l(n int32) int32 {
+	return n << 0
+}
+
+//go:noinline
+func byz32r(n int32) int32 {
+	return n >> 0
+}
+
+//go:noinline
+func byz32ur(n uint32) uint32 {
+	return n >> 0
+}
+
+//go:noinline
+func byz16l(n int16) int16 {
+	return n << 0
+}
+
+//go:noinline
+func byz16r(n int16) int16 {
+	return n >> 0
+}
+
+//go:noinline
+func byz16ur(n uint16) uint16 {
+	return n >> 0
+}
+
+//go:noinline
+func byz8l(n int8) int8 {
+	return n << 0
+}
+
+//go:noinline
+func byz8r(n int8) int8 {
+	return n >> 0
+}
+
+//go:noinline
+func byz8ur(n uint8) uint8 {
+	return n >> 0
+}
+
+func TestShiftByZero(t *testing.T) {
+	{
+		var n int64 = 0x5555555555555555
+		if got := byz64l(n); got != n {
+			t.Errorf("%x<<0 == %x, want %x", n, got, n)
+		}
+		if got := byz64r(n); got != n {
+			t.Errorf("%x>>0 == %x, want %x", n, got, n)
+		}
+	}
+	{
+		var n uint64 = 0xaaaaaaaaaaaaaaaa
+		if got := byz64ur(n); got != n {
+			t.Errorf("%x>>>0 == %x, want %x", n, got, n)
+		}
+	}
+
+	{
+		var n int32 = 0x55555555
+		if got := byz32l(n); got != n {
+			t.Errorf("%x<<0 == %x, want %x", n, got, n)
+		}
+		if got := byz32r(n); got != n {
+			t.Errorf("%x>>0 == %x, want %x", n, got, n)
+		}
+	}
+	{
+		var n uint32 = 0xaaaaaaaa
+		if got := byz32ur(n); got != n {
+			t.Errorf("%x>>>0 == %x, want %x", n, got, n)
+		}
+	}
+
+	{
+		var n int16 = 0x5555
+		if got := byz16l(n); got != n {
+			t.Errorf("%x<<0 == %x, want %x", n, got, n)
+		}
+		if got := byz16r(n); got != n {
+			t.Errorf("%x>>0 == %x, want %x", n, got, n)
+		}
+	}
+	{
+		var n uint16 = 0xaaaa
+		if got := byz16ur(n); got != n {
+			t.Errorf("%x>>>0 == %x, want %x", n, got, n)
+		}
+	}
+
+	{
+		var n int8 = 0x55
+		if got := byz8l(n); got != n {
+			t.Errorf("%x<<0 == %x, want %x", n, got, n)
+		}
+		if got := byz8r(n); got != n {
+			t.Errorf("%x>>0 == %x, want %x", n, got, n)
+		}
+	}
+	{
+		var n uint8 = 0x55
+		if got := byz8ur(n); got != n {
+			t.Errorf("%x>>>0 == %x, want %x", n, got, n)
+		}
+	}
+}
+
+//go:noinline
+func two64l(x int64) int64 {
+	return x << 1 << 1
+}
+
+//go:noinline
+func two64r(x int64) int64 {
+	return x >> 1 >> 1
+}
+
+//go:noinline
+func two64ur(x uint64) uint64 {
+	return x >> 1 >> 1
+}
+
+//go:noinline
+func two32l(x int32) int32 {
+	return x << 1 << 1
+}
+
+//go:noinline
+func two32r(x int32) int32 {
+	return x >> 1 >> 1
+}
+
+//go:noinline
+func two32ur(x uint32) uint32 {
+	return x >> 1 >> 1
+}
+
+//go:noinline
+func two16l(x int16) int16 {
+	return x << 1 << 1
+}
+
+//go:noinline
+func two16r(x int16) int16 {
+	return x >> 1 >> 1
+}
+
+//go:noinline
+func two16ur(x uint16) uint16 {
+	return x >> 1 >> 1
+}
+
+//go:noinline
+func two8l(x int8) int8 {
+	return x << 1 << 1
+}
+
+//go:noinline
+func two8r(x int8) int8 {
+	return x >> 1 >> 1
+}
+
+//go:noinline
+func two8ur(x uint8) uint8 {
+	return x >> 1 >> 1
+}
+
+func TestShiftCombine(t *testing.T) {
+	if got, want := two64l(4), int64(16); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := two64r(64), int64(16); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := two64ur(64), uint64(16); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := two32l(4), int32(16); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := two32r(64), int32(16); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := two32ur(64), uint32(16); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := two16l(4), int16(16); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := two16r(64), int16(16); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := two16ur(64), uint16(16); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := two8l(4), int8(16); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := two8r(64), int8(16); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := two8ur(64), uint8(16); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+
+}
+
+//go:noinline
+func three64l(x int64) int64 {
+	return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three64ul(x uint64) uint64 {
+	return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three64r(x int64) int64 {
+	return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three64ur(x uint64) uint64 {
+	return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three32l(x int32) int32 {
+	return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three32ul(x uint32) uint32 {
+	return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three32r(x int32) int32 {
+	return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three32ur(x uint32) uint32 {
+	return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three16l(x int16) int16 {
+	return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three16ul(x uint16) uint16 {
+	return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three16r(x int16) int16 {
+	return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three16ur(x uint16) uint16 {
+	return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three8l(x int8) int8 {
+	return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three8ul(x uint8) uint8 {
+	return x << 3 >> 1 << 2
+}
+
+//go:noinline
+func three8r(x int8) int8 {
+	return x >> 3 << 1 >> 2
+}
+
+//go:noinline
+func three8ur(x uint8) uint8 {
+	return x >> 3 << 1 >> 2
+}
+
+func TestShiftCombine3(t *testing.T) {
+	if got, want := three64l(4), int64(64); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := three64ul(4), uint64(64); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := three64r(64), int64(4); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := three64ur(64), uint64(4); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := three32l(4), int32(64); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := three32ul(4), uint32(64); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := three32r(64), int32(4); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := three32ur(64), uint32(4); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := three16l(4), int16(64); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := three16ul(4), uint16(64); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := three16r(64), int16(4); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := three16ur(64), uint16(4); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := three8l(4), int8(64); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := three8ul(4), uint8(64); want != got {
+		t.Errorf("4<<1<<1 == %d, want %d", got, want)
+	}
+	if got, want := three8r(64), int8(4); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+	if got, want := three8ur(64), uint8(4); want != got {
+		t.Errorf("64>>1>>1 == %d, want %d", got, want)
+	}
+}
+
+var (
+	one64  int64  = 1
+	one64u uint64 = 1
+	one32  int32  = 1
+	one32u uint32 = 1
+	one16  int16  = 1
+	one16u uint16 = 1
+	one8   int8   = 1
+	one8u  uint8  = 1
+)
+
+func TestShiftLargeCombine(t *testing.T) {
+	var N uint64 = 0x8000000000000000
+	if one64<<N<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one64>>N>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one64u>>N>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one32<<N<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one32>>N>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one32u>>N>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one16<<N<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one16>>N>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one16u>>N>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one8<<N<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one8>>N>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one8u>>N>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+}
+
+func TestShiftLargeCombine3(t *testing.T) {
+	var N uint64 = 0x8000000000000001
+	if one64<<N>>2<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one64u<<N>>2<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one64>>N<<2>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one64u>>N<<2>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one32<<N>>2<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one32u<<N>>2<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one32>>N<<2>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one32u>>N<<2>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one16<<N>>2<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one16u<<N>>2<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one16>>N<<2>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one16u>>N<<2>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one8<<N>>2<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one8u<<N>>2<<N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one8>>N<<2>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+	if one8u>>N<<2>>N == 1 {
+		t.Errorf("shift overflow mishandled")
+	}
+}
+
+func TestShiftGeneric(t *testing.T) {
+	for _, test := range [...]struct {
+		valueWidth int
+		signed     bool
+		shiftWidth int
+		left       bool
+		f          interface{}
+	}{
+		{64, true, 64, true, func(n int64, s uint64) int64 { return n << s }},
+		{64, true, 64, false, func(n int64, s uint64) int64 { return n >> s }},
+		{64, false, 64, false, func(n uint64, s uint64) uint64 { return n >> s }},
+		{64, true, 32, true, func(n int64, s uint32) int64 { return n << s }},
+		{64, true, 32, false, func(n int64, s uint32) int64 { return n >> s }},
+		{64, false, 32, false, func(n uint64, s uint32) uint64 { return n >> s }},
+		{64, true, 16, true, func(n int64, s uint16) int64 { return n << s }},
+		{64, true, 16, false, func(n int64, s uint16) int64 { return n >> s }},
+		{64, false, 16, false, func(n uint64, s uint16) uint64 { return n >> s }},
+		{64, true, 8, true, func(n int64, s uint8) int64 { return n << s }},
+		{64, true, 8, false, func(n int64, s uint8) int64 { return n >> s }},
+		{64, false, 8, false, func(n uint64, s uint8) uint64 { return n >> s }},
+
+		{32, true, 64, true, func(n int32, s uint64) int32 { return n << s }},
+		{32, true, 64, false, func(n int32, s uint64) int32 { return n >> s }},
+		{32, false, 64, false, func(n uint32, s uint64) uint32 { return n >> s }},
+		{32, true, 32, true, func(n int32, s uint32) int32 { return n << s }},
+		{32, true, 32, false, func(n int32, s uint32) int32 { return n >> s }},
+		{32, false, 32, false, func(n uint32, s uint32) uint32 { return n >> s }},
+		{32, true, 16, true, func(n int32, s uint16) int32 { return n << s }},
+		{32, true, 16, false, func(n int32, s uint16) int32 { return n >> s }},
+		{32, false, 16, false, func(n uint32, s uint16) uint32 { return n >> s }},
+		{32, true, 8, true, func(n int32, s uint8) int32 { return n << s }},
+		{32, true, 8, false, func(n int32, s uint8) int32 { return n >> s }},
+		{32, false, 8, false, func(n uint32, s uint8) uint32 { return n >> s }},
+
+		{16, true, 64, true, func(n int16, s uint64) int16 { return n << s }},
+		{16, true, 64, false, func(n int16, s uint64) int16 { return n >> s }},
+		{16, false, 64, false, func(n uint16, s uint64) uint16 { return n >> s }},
+		{16, true, 32, true, func(n int16, s uint32) int16 { return n << s }},
+		{16, true, 32, false, func(n int16, s uint32) int16 { return n >> s }},
+		{16, false, 32, false, func(n uint16, s uint32) uint16 { return n >> s }},
+		{16, true, 16, true, func(n int16, s uint16) int16 { return n << s }},
+		{16, true, 16, false, func(n int16, s uint16) int16 { return n >> s }},
+		{16, false, 16, false, func(n uint16, s uint16) uint16 { return n >> s }},
+		{16, true, 8, true, func(n int16, s uint8) int16 { return n << s }},
+		{16, true, 8, false, func(n int16, s uint8) int16 { return n >> s }},
+		{16, false, 8, false, func(n uint16, s uint8) uint16 { return n >> s }},
+
+		{8, true, 64, true, func(n int8, s uint64) int8 { return n << s }},
+		{8, true, 64, false, func(n int8, s uint64) int8 { return n >> s }},
+		{8, false, 64, false, func(n uint8, s uint64) uint8 { return n >> s }},
+		{8, true, 32, true, func(n int8, s uint32) int8 { return n << s }},
+		{8, true, 32, false, func(n int8, s uint32) int8 { return n >> s }},
+		{8, false, 32, false, func(n uint8, s uint32) uint8 { return n >> s }},
+		{8, true, 16, true, func(n int8, s uint16) int8 { return n << s }},
+		{8, true, 16, false, func(n int8, s uint16) int8 { return n >> s }},
+		{8, false, 16, false, func(n uint8, s uint16) uint8 { return n >> s }},
+		{8, true, 8, true, func(n int8, s uint8) int8 { return n << s }},
+		{8, true, 8, false, func(n int8, s uint8) int8 { return n >> s }},
+		{8, false, 8, false, func(n uint8, s uint8) uint8 { return n >> s }},
+	} {
+		fv := reflect.ValueOf(test.f)
+		var args [2]reflect.Value
+		for i := 0; i < test.valueWidth; i++ {
+			// Build value to be shifted.
+			var n int64 = 1
+			for j := 0; j < i; j++ {
+				n <<= 1
+			}
+			args[0] = reflect.ValueOf(n).Convert(fv.Type().In(0))
+			for s := 0; s <= test.shiftWidth; s++ {
+				args[1] = reflect.ValueOf(s).Convert(fv.Type().In(1))
+
+				// Compute desired result. We're testing variable shifts
+				// assuming constant shifts are correct.
+				r := n
+				var op string
+				switch {
+				case test.left:
+					op = "<<"
+					for j := 0; j < s; j++ {
+						r <<= 1
+					}
+					switch test.valueWidth {
+					case 32:
+						r = int64(int32(r))
+					case 16:
+						r = int64(int16(r))
+					case 8:
+						r = int64(int8(r))
+					}
+				case test.signed:
+					op = ">>"
+					switch test.valueWidth {
+					case 32:
+						r = int64(int32(r))
+					case 16:
+						r = int64(int16(r))
+					case 8:
+						r = int64(int8(r))
+					}
+					for j := 0; j < s; j++ {
+						r >>= 1
+					}
+				default:
+					op = ">>>"
+					for j := 0; j < s; j++ {
+						r = int64(uint64(r) >> 1)
+					}
+				}
+
+				// Call function.
+				res := fv.Call(args[:])[0].Convert(reflect.ValueOf(r).Type())
+
+				if res.Int() != r {
+					t.Errorf("%s%dx%d(%x,%x)=%x, want %x", op, test.valueWidth, test.shiftWidth, n, s, res.Int(), r)
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index b7f7ea0..4469d71 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -5,7 +5,6 @@
 package gc
 
 import (
-	"cmd/internal/obj"
 	"fmt"
 )
 
@@ -16,6 +15,15 @@ const (
 	InitPending    = 2
 )
 
+type InitEntry struct {
+	Xoffset int64 // struct, array only
+	Expr    *Node // bytes of run-time computed expressions
+}
+
+type InitPlan struct {
+	E []InitEntry
+}
+
 var (
 	initlist  []*Node
 	initplans map[*Node]*InitPlan
@@ -24,20 +32,20 @@ var (
 
 // 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) {
+func init1(n *Node, out *[]*Node) {
 	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)
+	for _, n1 := range n.List.Slice() {
+		init1(n1, 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)
+		init1(n.Type.Nname(), out)
 	}
 
 	if n.Op != ONAME {
@@ -120,7 +128,7 @@ func init1(n *Node, out **NodeList) {
 				if Debug['%'] != 0 {
 					Dump("nonstatic", defn)
 				}
-				*out = list(*out, defn)
+				*out = append(*out, defn)
 			}
 
 		case OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
@@ -128,13 +136,13 @@ func init1(n *Node, out **NodeList) {
 				break
 			}
 			defn.Initorder = InitPending
-			for l := defn.Rlist; l != nil; l = l.Next {
-				init1(l.N, out)
+			for _, n2 := range defn.Rlist.Slice() {
+				init1(n2, out)
 			}
 			if Debug['%'] != 0 {
 				Dump("nonstatic", defn)
 			}
-			*out = list(*out, defn)
+			*out = append(*out, defn)
 			defn.Initorder = InitDone
 		}
 	}
@@ -187,13 +195,13 @@ func foundinitloop(node, visited *Node) {
 }
 
 // recurse over n, doing init1 everywhere.
-func init2(n *Node, out **NodeList) {
+func init2(n *Node, out *[]*Node) {
 	if n == nil || n.Initorder == InitDone {
 		return
 	}
 
-	if n.Op == ONAME && n.Ninit != nil {
-		Fatalf("name %v with ninit: %v\n", n.Sym, Nconv(n, obj.FmtSign))
+	if n.Op == ONAME && n.Ninit.Len() != 0 {
+		Fatalf("name %v with ninit: %v\n", n.Sym, Nconv(n, FmtSign))
 	}
 
 	init1(n, out)
@@ -208,28 +216,26 @@ func init2(n *Node, out **NodeList) {
 		init2list(n.Func.Closure.Nbody, out)
 	}
 	if n.Op == ODOTMETH || n.Op == OCALLPART {
-		init2(n.Type.Nname, out)
+		init2(n.Type.Nname(), out)
 	}
 }
 
-func init2list(l *NodeList, out **NodeList) {
-	for ; l != nil; l = l.Next {
-		init2(l.N, out)
+func init2list(l Nodes, out *[]*Node) {
+	for _, n := range l.Slice() {
+		init2(n, out)
 	}
 }
 
-func initreorder(l *NodeList, out **NodeList) {
+func initreorder(l []*Node, out *[]*Node) {
 	var n *Node
-
-	for ; l != nil; l = l.Next {
-		n = l.N
+	for _, n = range l {
 		switch n.Op {
 		case ODCLFUNC, ODCLCONST, ODCLTYPE:
 			continue
 		}
 
-		initreorder(n.Ninit, out)
-		n.Ninit = nil
+		initreorder(n.Ninit.Slice(), out)
+		n.Ninit.Set(nil)
 		init1(n, out)
 	}
 }
@@ -237,19 +243,19 @@ func initreorder(l *NodeList, out **NodeList) {
 // 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
+func initfix(l []*Node) []*Node {
+	var lout []*Node
 	initplans = make(map[*Node]*InitPlan)
-	lno := int(lineno)
+	lno := lineno
 	initreorder(l, &lout)
-	lineno = int32(lno)
+	lineno = 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 {
+func staticinit(n *Node, out *[]*Node) bool {
 	if n.Op != ONAME || n.Class != PEXTERN || n.Name.Defn == nil || n.Name.Defn.Op != OAS {
 		Fatalf("staticinit")
 	}
@@ -262,7 +268,7 @@ func staticinit(n *Node, out **NodeList) bool {
 
 // like staticassign but we are copying an already
 // initialized value r.
-func staticcopy(l *Node, r *Node, out **NodeList) bool {
+func staticcopy(l *Node, r *Node, out *[]*Node) bool {
 	if r.Op != ONAME {
 		return false
 	}
@@ -291,7 +297,7 @@ func staticcopy(l *Node, r *Node, out **NodeList) bool {
 		if staticcopy(l, r, out) {
 			return true
 		}
-		*out = list(*out, Nod(OAS, l, r))
+		*out = append(*out, Nod(OAS, l, r))
 		return true
 
 	case OLITERAL:
@@ -322,7 +328,7 @@ func staticcopy(l *Node, r *Node, out **NodeList) bool {
 		}
 
 	case OARRAYLIT:
-		if Isslice(r.Type) {
+		if r.Type.IsSlice() {
 			// copy slice
 			a := inittemps[r]
 
@@ -336,8 +342,6 @@ func staticcopy(l *Node, r *Node, out **NodeList) bool {
 			return true
 		}
 		fallthrough
-
-		// fall through
 	case OSTRUCTLIT:
 		p := initplans[r]
 
@@ -362,7 +366,7 @@ func staticcopy(l *Node, r *Node, out **NodeList) bool {
 					rr.Type = ll.Type
 					rr.Xoffset += e.Xoffset
 					setlineno(rr)
-					*out = list(*out, Nod(OAS, ll, rr))
+					*out = append(*out, Nod(OAS, ll, rr))
 				}
 			}
 		}
@@ -373,7 +377,7 @@ func staticcopy(l *Node, r *Node, out **NodeList) bool {
 	return false
 }
 
-func staticassign(l *Node, r *Node, out **NodeList) bool {
+func staticassign(l *Node, r *Node, out *[]*Node) bool {
 	for r.Op == OCONVNOP {
 		r = r.Left
 	}
@@ -410,7 +414,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
 
 			// Init underlying literal.
 			if !staticassign(a, r.Left, out) {
-				*out = list(*out, Nod(OAS, a, r.Left))
+				*out = append(*out, Nod(OAS, a, r.Left))
 			}
 			return true
 		}
@@ -425,12 +429,10 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
 
 	case OARRAYLIT:
 		initplan(r)
-		if Isslice(r.Type) {
+		if r.Type.IsSlice() {
 			// Init slice.
-			ta := typ(TARRAY)
-
-			ta.Type = r.Type.Type
-			ta.Bound = Mpgetfix(r.Right.Val().U.(*Mpint))
+			bound := r.Right.Int64()
+			ta := typArray(r.Type.Elem(), bound)
 			a := staticname(ta, 1)
 			inittemps[r] = a
 			n := *l
@@ -463,7 +465,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
 				*a = n
 				a.Orig = a // completely separate copy
 				if !staticassign(a, e.Expr, out) {
-					*out = list(*out, Nod(OAS, a, e.Expr))
+					*out = append(*out, Nod(OAS, a, e.Expr))
 				}
 			}
 		}
@@ -475,12 +477,17 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
 		break
 
 	case OCLOSURE:
-		if r.Func.Cvars == nil {
+		if hasemptycvars(r) {
+			if Debug_closure > 0 {
+				Warnl(r.Lineno, "closure converted to global")
+			}
 			// Closures with no captured variables are globals,
 			// so the assignment can be done at link time.
 			n := *l
 			gdata(&n, r.Func.Closure.Func.Nname, Widthptr)
 			return true
+		} else {
+			closuredebugruntimecheck(r)
 		}
 	}
 
@@ -494,7 +501,7 @@ func staticassign(l *Node, r *Node, out **NodeList) bool {
 // data statements for the constant
 // part of the composite literal.
 func staticname(t *Type, ctxt int) *Node {
-	n := newname(Lookupf("statictmp_%.4d", statuniqgen))
+	n := newname(LookupN("statictmp_", statuniqgen))
 	statuniqgen++
 	if ctxt == 0 {
 		n.Name.Readonly = true
@@ -504,91 +511,101 @@ func staticname(t *Type, ctxt int) *Node {
 }
 
 func isliteral(n *Node) bool {
-	if n.Op == OLITERAL {
-		if n.Val().Ctype() != CTNIL {
-			return true
-		}
-	}
-	return false
+	// Treat nils as zeros rather than literals.
+	return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
 }
 
-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 (n *Node) isSimpleName() bool {
+	return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP
 }
 
-func litas(l *Node, r *Node, init **NodeList) {
+func litas(l *Node, r *Node, init *Nodes) {
 	a := Nod(OAS, l, r)
-	typecheck(&a, Etop)
-	walkexpr(&a, init)
-	*init = list(*init, a)
+	a = typecheck(a, Etop)
+	a = walkexpr(a, init)
+	init.Append(a)
 }
 
+// initGenType is a bitmap indicating the types of generation that will occur for a static value.
+type initGenType uint8
+
 const (
-	MODEDYNAM = 1
-	MODECONST = 2
+	initDynamic initGenType = 1 << iota // contains some dynamic values, for which init code will be generated
+	initConst                           // contains some constant values, which may be written into data symbols
 )
 
-func getdyn(n *Node, top int) int {
-	mode := 0
+func getdyn(n *Node, top int) initGenType {
 	switch n.Op {
 	default:
 		if isliteral(n) {
-			return MODECONST
+			return initConst
 		}
-		return MODEDYNAM
+		return initDynamic
 
 	case OARRAYLIT:
-		if top == 0 && n.Type.Bound < 0 {
-			return MODEDYNAM
+		if top == 0 && n.Type.IsSlice() {
+			return initDynamic
 		}
-		fallthrough
 
 	case OSTRUCTLIT:
-		break
 	}
 
-	for nl := n.List; nl != nil; nl = nl.Next {
-		value := nl.N.Right
+	var mode initGenType
+	for _, n1 := range n.List.Slice() {
+		value := n1.Right
 		mode |= getdyn(value, 0)
-		if mode == MODEDYNAM|MODECONST {
+		if mode == initDynamic|initConst {
 			break
 		}
 	}
-
 	return mode
 }
 
-func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
-	for nl := n.List; nl != nil; nl = nl.Next {
-		r := nl.N
+// isStaticCompositeLiteral reports whether n is a compile-time constant.
+func isStaticCompositeLiteral(n *Node) bool {
+	switch n.Op {
+	case OARRAYLIT:
+		if n.Type.IsSlice() {
+			return false
+		}
+	case OSTRUCTLIT:
+	case OLITERAL:
+		return true
+	default:
+		return false
+	}
+	for _, r := range n.List.Slice() {
 		if r.Op != OKEY {
-			Fatalf("structlit: rhs not OKEY: %v", r)
+			Fatalf("isStaticCompositeLiteral: rhs not OKEY: %v", r)
 		}
 		index := r.Left
+		if n.Op == OARRAYLIT && index.Op != OLITERAL {
+			return false
+		}
 		value := r.Right
+		if !isStaticCompositeLiteral(value) {
+			return false
+		}
+	}
+	return true
+}
 
-		var a *Node
+func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
+	for _, r := range n.List.Slice() {
+		if r.Op != OKEY {
+			Fatalf("structlit: rhs not OKEY: %v", r)
+		}
+		index := r.Left
+		value := r.Right
 
 		switch value.Op {
 		case OARRAYLIT:
-			if value.Type.Bound < 0 {
+			if value.Type.IsSlice() {
 				if pass == 1 && ctxt != 0 {
-					a = Nod(ODOT, var_, newname(index.Sym))
+					a := NodSym(ODOT, var_, index.Sym)
 					slicelit(ctxt, value, a, init)
 				} else if pass == 2 && ctxt == 0 {
-					a = Nod(ODOT, var_, newname(index.Sym))
+					a := NodSym(ODOT, var_, index.Sym)
 					slicelit(ctxt, value, a, init)
 				} else if pass == 3 {
 					break
@@ -596,12 +613,12 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
 				continue
 			}
 
-			a = Nod(ODOT, var_, newname(index.Sym))
+			a := NodSym(ODOT, var_, index.Sym)
 			arraylit(ctxt, pass, value, a, init)
 			continue
 
 		case OSTRUCTLIT:
-			a = Nod(ODOT, var_, newname(index.Sym))
+			a := NodSym(ODOT, var_, index.Sym)
 			structlit(ctxt, pass, value, a, init)
 			continue
 		}
@@ -616,44 +633,41 @@ func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
 
 		// build list of var.field = expr
 		setlineno(value)
-		a = Nod(ODOT, var_, newname(index.Sym))
+		a := NodSym(ODOT, var_, index.Sym)
 
 		a = Nod(OAS, a, value)
-		typecheck(&a, Etop)
+		a = typecheck(a, Etop)
 		if pass == 1 {
-			walkexpr(&a, init) // add any assignments in r to top
+			a = walkexpr(a, init) // add any assignments in r to top
 			if a.Op != OAS {
 				Fatalf("structlit: not as")
 			}
 			a.Dodata = 2
 		} else {
-			orderstmtinplace(&a)
-			walkstmt(&a)
+			a = orderstmtinplace(a)
+			a = walkstmt(a)
 		}
 
-		*init = list(*init, a)
+		init.Append(a)
 	}
 }
 
-func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
-	for l := n.List; l != nil; l = l.Next {
-		r := l.N
+func arraylit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
+	for _, r := range n.List.Slice() {
 		if r.Op != OKEY {
 			Fatalf("arraylit: rhs not OKEY: %v", r)
 		}
 		index := r.Left
 		value := r.Right
 
-		var a *Node
-
 		switch value.Op {
 		case OARRAYLIT:
-			if value.Type.Bound < 0 {
+			if value.Type.IsSlice() {
 				if pass == 1 && ctxt != 0 {
-					a = Nod(OINDEX, var_, index)
+					a := Nod(OINDEX, var_, index)
 					slicelit(ctxt, value, a, init)
 				} else if pass == 2 && ctxt == 0 {
-					a = Nod(OINDEX, var_, index)
+					a := Nod(OINDEX, var_, index)
 					slicelit(ctxt, value, a, init)
 				} else if pass == 3 {
 					break
@@ -661,12 +675,12 @@ func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
 				continue
 			}
 
-			a = Nod(OINDEX, var_, index)
+			a := Nod(OINDEX, var_, index)
 			arraylit(ctxt, pass, value, a, init)
 			continue
 
 		case OSTRUCTLIT:
-			a = Nod(OINDEX, var_, index)
+			a := Nod(OINDEX, var_, index)
 			structlit(ctxt, pass, value, a, init)
 			continue
 		}
@@ -681,33 +695,28 @@ func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
 
 		// build list of var[index] = value
 		setlineno(value)
-		a = Nod(OINDEX, var_, index)
+		a := Nod(OINDEX, var_, index)
 
 		a = Nod(OAS, a, value)
-		typecheck(&a, Etop)
+		a = typecheck(a, Etop)
 		if pass == 1 {
-			walkexpr(&a, init)
+			a = walkexpr(a, init)
 			if a.Op != OAS {
 				Fatalf("arraylit: not as")
 			}
 			a.Dodata = 2
 		} else {
-			orderstmtinplace(&a)
-			walkstmt(&a)
+			a = orderstmtinplace(a)
+			a = walkstmt(a)
 		}
 
-		*init = list(*init, a)
+		init.Append(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
+func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
+	// make an array type corresponding the number of elements we have
+	t := typArray(n.Type.Elem(), n.Right.Int64())
 	dowidth(t)
 
 	if ctxt != 0 {
@@ -718,12 +727,12 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 		arraylit(ctxt, 2, n, vstat, init)
 
 		// copy static to slice
-		a := Nod(OSLICE, vstat, Nod(OKEY, nil, nil))
+		a := Nod(OSLICE, vstat, nil)
 
 		a = Nod(OAS, var_, a)
-		typecheck(&a, Etop)
+		a = typecheck(a, Etop)
 		a.Dodata = 2
-		*init = list(*init, a)
+		init.Append(a)
 		return
 	}
 
@@ -736,22 +745,22 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 	//	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
+	// 5. for each dynamic part assign to the array
+	//	vauto[i] = dynamic part
+	// 6. assign slice of allocated heap to var
+	//	var = vauto[:]
 	//
 	// 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
+	//	5. vauto[i] = dynamic part
+	//	6. var = vauto[:]
 
 	// if the literal contains constants,
 	// make static initialized array (1),(2)
 	var vstat *Node
 
 	mode := getdyn(n, 1)
-	if mode&MODECONST != 0 {
+	if mode&initConst != 0 {
 		vstat = staticname(t, ctxt)
 		arraylit(ctxt, 1, n, vstat, init)
 	}
@@ -767,8 +776,8 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 
 		if vstat == nil {
 			a = Nod(OAS, x, nil)
-			typecheck(&a, Etop)
-			*init = list(*init, a) // zero new temp
+			a = typecheck(a, Etop)
+			init.Append(a) // zero new temp
 		}
 
 		a = Nod(OADDR, x, nil)
@@ -776,56 +785,47 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 		a = temp(t)
 		if vstat == nil {
 			a = Nod(OAS, temp(t), nil)
-			typecheck(&a, Etop)
-			*init = list(*init, a) // zero new temp
+			a = typecheck(a, Etop)
+			init.Append(a) // zero new temp
 			a = a.Left
 		}
 
 		a = Nod(OADDR, a, nil)
 	} else {
 		a = Nod(ONEW, nil, nil)
-		a.List = list1(typenod(t))
+		a.List.Set1(typenod(t))
 	}
 
 	a = Nod(OAS, vauto, a)
-	typecheck(&a, Etop)
-	walkexpr(&a, init)
-	*init = list(*init, a)
+	a = typecheck(a, Etop)
+	a = walkexpr(a, init)
+	init.Append(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)
+		a = typecheck(a, Etop)
+		a = walkexpr(a, init)
+		init.Append(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)
-	for l := n.List; l != nil; l = l.Next {
-		r := l.N
+	// put dynamics into array (5)
+	for _, r := range n.List.Slice() {
 		if r.Op != OKEY {
 			Fatalf("slicelit: rhs not OKEY: %v", r)
 		}
 		index := r.Left
 		value := r.Right
-		a := Nod(OINDEX, var_, index)
+		a := Nod(OINDEX, vauto, index)
 		a.Bounded = true
 
 		// TODO need to check bounds?
 
 		switch value.Op {
 		case OARRAYLIT:
-			if value.Type.Bound < 0 {
+			if value.Type.IsSlice() {
 				break
 			}
 			arraylit(ctxt, 2, value, a, init)
@@ -840,32 +840,38 @@ func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 			continue
 		}
 
-		// build list of var[c] = expr
+		// build list of vauto[c] = expr
 		setlineno(value)
 		a = Nod(OAS, a, value)
 
-		typecheck(&a, Etop)
-		orderstmtinplace(&a)
-		walkstmt(&a)
-		*init = list(*init, a)
+		a = typecheck(a, Etop)
+		a = orderstmtinplace(a)
+		a = walkstmt(a)
+		init.Append(a)
 	}
+
+	// make slice out of heap (6)
+	a = Nod(OAS, var_, Nod(OSLICE, vauto, nil))
+
+	a = typecheck(a, Etop)
+	a = orderstmtinplace(a)
+	a = walkstmt(a)
+	init.Append(a)
 }
 
-func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
+func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
 	ctxt = 0
 
 	// make the map var
 	nerr := nerrors
 
 	a := Nod(OMAKE, nil, nil)
-	a.List = list1(typenod(n.Type))
+	a.List.Set1(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
+	b := 0
+	for _, r := range n.List.Slice() {
 		if r.Op != OKEY {
 			Fatalf("maplit: rhs not OKEY: %v", r)
 		}
@@ -880,40 +886,33 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 	if b != 0 {
 		// build type [count]struct { a Tindex, b Tvalue }
 		t := n.Type
+		tk := t.Key()
+		tv := t.Val()
 
-		tk := t.Down
-		tv := t.Type
-
+		syma := Lookup("a")
 		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
+		var fields [2]*Field
+		fields[0] = newField()
+		fields[0].Type = tk
+		fields[0].Sym = syma
+		fields[1] = newField()
+		fields[1].Type = tv
+		fields[1].Sym = symb
 
-		t1 = t
-		t = typ(TSTRUCT)
-		t.Type = t1
+		tstruct := typ(TSTRUCT)
+		tstruct.SetFields(fields[:])
 
-		t1 = t
-		t = typ(TARRAY)
-		t.Bound = b
-		t.Type = t1
+		tarr := typArray(tstruct, int64(b))
 
-		dowidth(t)
+		// TODO(josharian): suppress alg generation for these types?
+		dowidth(tarr)
 
 		// make and initialize static array
-		vstat := staticname(t, ctxt)
+		vstat := staticname(tarr, ctxt)
 
 		b := int64(0)
-		for l := n.List; l != nil; l = l.Next {
-			r := l.N
-
+		for _, r := range n.List.Slice() {
 			if r.Op != OKEY {
 				Fatalf("maplit: rhs not OKEY: %v", r)
 			}
@@ -926,24 +925,24 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 				a = Nodintconst(b)
 
 				a = Nod(OINDEX, vstat, a)
-				a = Nod(ODOT, a, newname(syma))
+				a = NodSym(ODOT, a, syma)
 				a = Nod(OAS, a, index)
-				typecheck(&a, Etop)
-				walkexpr(&a, init)
+				a = typecheck(a, Etop)
+				a = walkexpr(a, init)
 				a.Dodata = 2
-				*init = list(*init, a)
+				init.Append(a)
 
 				// build vstat[b].b = value;
 				setlineno(value)
 				a = Nodintconst(b)
 
 				a = Nod(OINDEX, vstat, a)
-				a = Nod(ODOT, a, newname(symb))
+				a = NodSym(ODOT, a, symb)
 				a = Nod(OAS, a, value)
-				typecheck(&a, Etop)
-				walkexpr(&a, init)
+				a = typecheck(a, Etop)
+				a = walkexpr(a, init)
 				a.Dodata = 2
-				*init = list(*init, a)
+				init.Append(a)
 
 				b++
 			}
@@ -957,34 +956,30 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 
 		a = Nod(OINDEX, vstat, index)
 		a.Bounded = true
-		a = Nod(ODOT, a, newname(symb))
+		a = NodSym(ODOT, a, symb)
 
 		r := Nod(OINDEX, vstat, index)
 		r.Bounded = true
-		r = Nod(ODOT, r, newname(syma))
+		r = NodSym(ODOT, r, syma)
 		r = Nod(OINDEX, var_, r)
 
 		r = Nod(OAS, r, a)
 
 		a = Nod(OFOR, nil, nil)
-		a.Nbody = list1(r)
+		a.Nbody.Set1(r)
 
-		a.Ninit = list1(Nod(OAS, index, Nodintconst(0)))
-		a.Left = Nod(OLT, index, Nodintconst(t.Bound))
+		a.Ninit.Set1(Nod(OAS, index, Nodintconst(0)))
+		a.Left = Nod(OLT, index, Nodintconst(tarr.NumElem()))
 		a.Right = Nod(OAS, index, Nod(OADD, index, Nodintconst(1)))
 
-		typecheck(&a, Etop)
-		walkstmt(&a)
-		*init = list(*init, a)
+		a = typecheck(a, Etop)
+		a = walkstmt(a)
+		init.Append(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
-
+	var key, val *Node
+	for _, r := range n.List.Slice() {
 		if r.Op != OKEY {
 			Fatalf("maplit: rhs not OKEY: %v", r)
 		}
@@ -998,26 +993,26 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 		// 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)
+			key = temp(var_.Type.Key())
+			val = temp(var_.Type.Val())
 		}
 
 		setlineno(r.Left)
 		a = Nod(OAS, key, r.Left)
-		typecheck(&a, Etop)
-		walkstmt(&a)
-		*init = list(*init, a)
+		a = typecheck(a, Etop)
+		a = walkstmt(a)
+		init.Append(a)
 		setlineno(r.Right)
 		a = Nod(OAS, val, r.Right)
-		typecheck(&a, Etop)
-		walkstmt(&a)
-		*init = list(*init, a)
+		a = typecheck(a, Etop)
+		a = walkstmt(a)
+		init.Append(a)
 
 		setlineno(val)
 		a = Nod(OAS, Nod(OINDEX, var_, key), val)
-		typecheck(&a, Etop)
-		walkstmt(&a)
-		*init = list(*init, a)
+		a = typecheck(a, Etop)
+		a = walkstmt(a)
+		init.Append(a)
 
 		if nerr != nerrors {
 			break
@@ -1026,29 +1021,29 @@ func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 
 	if key != nil {
 		a = Nod(OVARKILL, key, nil)
-		typecheck(&a, Etop)
-		*init = list(*init, a)
+		a = typecheck(a, Etop)
+		init.Append(a)
 		a = Nod(OVARKILL, val, nil)
-		typecheck(&a, Etop)
-		*init = list(*init, a)
+		a = typecheck(a, Etop)
+		init.Append(a)
 	}
 }
 
-func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) {
+func anylit(ctxt int, n *Node, var_ *Node, init *Nodes) {
 	t := n.Type
 	switch n.Op {
 	default:
-		Fatalf("anylit: not lit")
+		Fatalf("anylit: not lit, op=%v node=%v", n.Op, n)
 
 	case OPTRLIT:
-		if !Isptr[t.Etype] {
+		if !t.IsPtr() {
 			Fatalf("anylit: not ptr")
 		}
 
 		var r *Node
 		if n.Right != nil {
 			r = Nod(OADDR, n.Right, nil)
-			typecheck(&r, Erv)
+			r = typecheck(r, Erv)
 		} else {
 			r = Nod(ONEW, nil, nil)
 			r.Typecheck = 1
@@ -1056,22 +1051,22 @@ func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 			r.Esc = n.Esc
 		}
 
-		walkexpr(&r, init)
+		r = walkexpr(r, init)
 		a := Nod(OAS, var_, r)
 
-		typecheck(&a, Etop)
-		*init = list(*init, a)
+		a = typecheck(a, Etop)
+		init.Append(a)
 
 		var_ = Nod(OIND, var_, nil)
-		typecheck(&var_, Erv|Easgn)
+		var_ = typecheck(var_, Erv|Easgn)
 		anylit(ctxt, n.Left, var_, init)
 
 	case OSTRUCTLIT:
-		if t.Etype != TSTRUCT {
+		if !t.IsStruct() {
 			Fatalf("anylit: not struct")
 		}
 
-		if simplename(var_) && count(n.List) > 4 {
+		if var_.isSimpleName() && n.List.Len() > 4 {
 			if ctxt == 0 {
 				// lay out static data
 				vstat := staticname(t, ctxt)
@@ -1081,9 +1076,9 @@ func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 				// copy static to var
 				a := Nod(OAS, var_, vstat)
 
-				typecheck(&a, Etop)
-				walkexpr(&a, init)
-				*init = list(*init, a)
+				a = typecheck(a, Etop)
+				a = walkexpr(a, init)
+				init.Append(a)
 
 				// add expressions to automatic
 				structlit(ctxt, 2, n, var_, init)
@@ -1097,25 +1092,25 @@ func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 		}
 
 		// initialize of not completely specified
-		if simplename(var_) || count(n.List) < structcount(t) {
+		if var_.isSimpleName() || n.List.Len() < t.NumFields() {
 			a := Nod(OAS, var_, nil)
-			typecheck(&a, Etop)
-			walkexpr(&a, init)
-			*init = list(*init, a)
+			a = typecheck(a, Etop)
+			a = walkexpr(a, init)
+			init.Append(a)
 		}
 
 		structlit(ctxt, 3, n, var_, init)
 
 	case OARRAYLIT:
-		if t.Etype != TARRAY {
-			Fatalf("anylit: not array")
-		}
-		if t.Bound < 0 {
+		if t.IsSlice() {
 			slicelit(ctxt, n, var_, init)
 			break
 		}
+		if !t.IsArray() {
+			Fatalf("anylit: not array")
+		}
 
-		if simplename(var_) && count(n.List) > 4 {
+		if var_.isSimpleName() && n.List.Len() > 4 {
 			if ctxt == 0 {
 				// lay out static data
 				vstat := staticname(t, ctxt)
@@ -1125,9 +1120,9 @@ func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 				// copy static to automatic
 				a := Nod(OAS, var_, vstat)
 
-				typecheck(&a, Etop)
-				walkexpr(&a, init)
-				*init = list(*init, a)
+				a = typecheck(a, Etop)
+				a = walkexpr(a, init)
+				init.Append(a)
 
 				// add expressions to automatic
 				arraylit(ctxt, 2, n, var_, init)
@@ -1141,24 +1136,24 @@ func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) {
 		}
 
 		// initialize of not completely specified
-		if simplename(var_) || int64(count(n.List)) < t.Bound {
+		if var_.isSimpleName() || int64(n.List.Len()) < t.NumElem() {
 			a := Nod(OAS, var_, nil)
-			typecheck(&a, Etop)
-			walkexpr(&a, init)
-			*init = list(*init, a)
+			a = typecheck(a, Etop)
+			a = walkexpr(a, init)
+			init.Append(a)
 		}
 
 		arraylit(ctxt, 3, n, var_, init)
 
 	case OMAPLIT:
-		if t.Etype != TMAP {
+		if !t.IsMap() {
 			Fatalf("anylit: not map")
 		}
 		maplit(ctxt, n, var_, init)
 	}
 }
 
-func oaslit(n *Node, init **NodeList) bool {
+func oaslit(n *Node, init *Nodes) bool {
 	if n.Left == nil || n.Right == nil {
 		// not a special composit literal assignment
 		return false
@@ -1167,7 +1162,7 @@ func oaslit(n *Node, init **NodeList) bool {
 		// not a special composit literal assignment
 		return false
 	}
-	if !simplename(n.Left) {
+	if !n.Left.isSimpleName() {
 		// not a special composit literal assignment
 		return false
 	}
@@ -1204,11 +1199,12 @@ func oaslit(n *Node, init **NodeList) bool {
 
 func getlit(lit *Node) int {
 	if Smallintconst(lit) {
-		return int(Mpgetfix(lit.Val().U.(*Mpint)))
+		return int(lit.Int64())
 	}
 	return -1
 }
 
+// stataddr sets nam to the static address of n and reports whether it succeeeded.
 func stataddr(nam *Node, n *Node) bool {
 	if n == nil {
 		return false
@@ -1228,7 +1224,7 @@ func stataddr(nam *Node, n *Node) bool {
 		return true
 
 	case OINDEX:
-		if n.Left.Type.Bound < 0 {
+		if n.Left.Type.IsSlice() {
 			break
 		}
 		if !stataddr(nam, n.Left) {
@@ -1262,38 +1258,34 @@ func initplan(n *Node) {
 		Fatalf("initplan")
 
 	case OARRAYLIT:
-		for l := n.List; l != nil; l = l.Next {
-			a := l.N
+		for _, a := range n.List.Slice() {
 			if a.Op != OKEY || !Smallintconst(a.Left) {
 				Fatalf("initplan arraylit")
 			}
-			addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val().U.(*Mpint)), nil, a.Right)
+			addvalue(p, n.Type.Elem().Width*a.Left.Int64(), a.Right)
 		}
 
 	case OSTRUCTLIT:
-		for l := n.List; l != nil; l = l.Next {
-			a := l.N
-			if a.Op != OKEY || a.Left.Type == nil {
+		for _, a := range n.List.Slice() {
+			if a.Op != OKEY || a.Left.Type != structkey {
 				Fatalf("initplan structlit")
 			}
-			addvalue(p, a.Left.Type.Width, nil, a.Right)
+			addvalue(p, a.Left.Xoffset, a.Right)
 		}
 
 	case OMAPLIT:
-		for l := n.List; l != nil; l = l.Next {
-			a := l.N
+		for _, a := range n.List.Slice() {
 			if a.Op != OKEY {
 				Fatalf("initplan maplit")
 			}
-			addvalue(p, -1, a.Left, a.Right)
+			addvalue(p, -1, a.Right)
 		}
 	}
 }
 
-func addvalue(p *InitPlan, xoffset int64, key *Node, n *Node) {
+func addvalue(p *InitPlan, xoffset int64, n *Node) {
 	// special case: zero can be dropped entirely
 	if iszero(n) {
-		p.Zero += n.Type.Width
 		return
 	}
 
@@ -1302,62 +1294,46 @@ func addvalue(p *InitPlan, xoffset int64, key *Node, n *Node) {
 		initplan(n)
 		q := initplans[n]
 		for _, qe := range q.E {
-			e := entry(p)
-			*e = qe
-			e.Xoffset += xoffset
+			// qe is a copy; we are not modifying entries in q.E
+			qe.Xoffset += xoffset
+			p.E = append(p.E, qe)
 		}
 		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
+	p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n})
 }
 
 func iszero(n *Node) bool {
 	switch n.Op {
 	case OLITERAL:
-		switch n.Val().Ctype() {
+		switch u := n.Val().U.(type) {
 		default:
 			Dump("unexpected literal", n)
 			Fatalf("iszero")
-
-		case CTNIL:
+		case *NilVal:
 			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 string:
+			return u == ""
+		case bool:
+			return !u
+		case *Mpint:
+			return u.CmpInt64(0) == 0
+		case *Mpflt:
+			return u.CmpFloat64(0) == 0
+		case *Mpcplx:
+			return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0
 		}
 
 	case OARRAYLIT:
-		if Isslice(n.Type) {
+		if n.Type.IsSlice() {
 			break
 		}
 		fallthrough
-
-		// fall through
 	case OSTRUCTLIT:
-		for l := n.List; l != nil; l = l.Next {
-			if !iszero(l.N.Right) {
+		for _, n1 := range n.List.Slice() {
+			if !iszero(n1.Right) {
 				return false
 			}
 		}
@@ -1368,93 +1344,86 @@ func iszero(n *Node) bool {
 }
 
 func isvaluelit(n *Node) bool {
-	return (n.Op == OARRAYLIT && Isfixedarray(n.Type)) || n.Op == OSTRUCTLIT
+	return (n.Op == OARRAYLIT && n.Type.IsArray()) || n.Op == OSTRUCTLIT
 }
 
-func entry(p *InitPlan) *InitEntry {
-	p.E = append(p.E, InitEntry{})
-	return &p.E[len(p.E)-1]
+// gen_as_init attempts to emit static data for n and reports whether it succeeded.
+// If reportOnly is true, it does not emit static data and does not modify the AST.
+func gen_as_init(n *Node, reportOnly bool) bool {
+	success := genAsInitNoCheck(n, reportOnly)
+	if !success && n.Dodata == 2 {
+		Dump("\ngen_as_init", n)
+		Fatalf("gen_as_init couldn't make data statement")
+	}
+	return success
 }
 
-func gen_as_init(n *Node) bool {
-	var nr *Node
-	var nl *Node
-	var nam Node
-
+func genAsInitNoCheck(n *Node, reportOnly bool) bool {
 	if n.Dodata == 0 {
-		goto no
+		return false
 	}
 
-	nr = n.Right
-	nl = n.Left
+	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
+		return stataddr(&nam, nl) && nam.Class == PEXTERN
 	}
 
 	if nr.Type == nil || !Eqtype(nl.Type, nr.Type) {
-		goto no
-	}
-
-	if !stataddr(&nam, nl) {
-		goto no
+		return false
 	}
 
-	if nam.Class != PEXTERN {
-		goto no
+	var nam Node
+	if !stataddr(&nam, nl) || nam.Class != PEXTERN {
+		return false
 	}
 
 	switch nr.Op {
 	default:
-		goto no
+		return false
 
 	case OCONVNOP:
 		nr = nr.Left
 		if nr == nil || nr.Op != OSLICEARR {
-			goto no
+			return false
 		}
 		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
-			}
+		low, high, _ := nr.SliceBounds()
+		if low != nil || high != nil {
+			return false
+		}
+		nr = nr.Left
+		if nr == nil || nr.Op != OADDR {
+			return false
+		}
+		ptr := nr
+		nr = nr.Left
+		if nr == nil || nr.Op != ONAME {
+			return false
+		}
 
-			// nr is the array being converted to a slice
-			if nr.Type == nil || nr.Type.Etype != TARRAY || nr.Type.Bound < 0 {
-				goto no
-			}
+		// nr is the array being converted to a slice
+		if nr.Type == nil || !nr.Type.IsArray() {
+			return false
+		}
 
+		if !reportOnly {
 			nam.Xoffset += int64(Array_array)
-			gdata(&nam, nl, int(Types[Tptr].Width))
+			gdata(&nam, ptr, Widthptr)
 
 			nam.Xoffset += int64(Array_nel) - int64(Array_array)
 			var nod1 Node
-			Nodconst(&nod1, Types[TINT], nr.Type.Bound)
+			Nodconst(&nod1, Types[TINT], nr.Type.NumElem())
 			gdata(&nam, &nod1, Widthint)
 
 			nam.Xoffset += int64(Array_cap) - int64(Array_nel)
 			gdata(&nam, &nod1, Widthint)
-
-			return true
 		}
 
-		goto no
+		return true
 
 	case OLITERAL:
 		break
@@ -1462,40 +1431,27 @@ func gen_as_init(n *Node) bool {
 
 	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))
+		return false
+
+	case TBOOL, TINT8, TUINT8, TINT16, TUINT16,
+		TINT32, TUINT32, TINT64, TUINT64,
+		TINT, TUINT, TUINTPTR,
+		TPTR32, TPTR64,
+		TFLOAT32, TFLOAT64:
+		if !reportOnly {
+			gdata(&nam, nr, int(nr.Type.Width))
+		}
 
 	case TCOMPLEX64, TCOMPLEX128:
-		gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
+		if !reportOnly {
+			gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
+		}
 
 	case TSTRING:
-		gdatastring(&nam, nr.Val().U.(string))
+		if !reportOnly {
+			gdatastring(&nam, nr.Val().U.(string))
+		}
 	}
 
 	return true
-
-no:
-	if n.Dodata == 2 {
-		Dump("\ngen_as_init", n)
-		Fatalf("gen_as_init couldnt make data statement")
-	}
-
-	return false
 }
diff --git a/src/cmd/compile/internal/gc/sizeof_test.go b/src/cmd/compile/internal/gc/sizeof_test.go
new file mode 100644
index 0000000..c474c47
--- /dev/null
+++ b/src/cmd/compile/internal/gc/sizeof_test.go
@@ -0,0 +1,56 @@
+// Copyright 2016 The Go 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
+
+package gc
+
+import (
+	"reflect"
+	"testing"
+	"unsafe"
+)
+
+// Assert that the size of important structures do not change unexpectedly.
+
+func TestSizeof(t *testing.T) {
+	const _64bit = unsafe.Sizeof(uintptr(0)) == 8
+
+	var tests = []struct {
+		val    interface{} // type as a value
+		_32bit uintptr     // size on 32bit platforms
+		_64bit uintptr     // size on 64bit platforms
+	}{
+		{Flow{}, 52, 88},
+		{Func{}, 92, 160},
+		{Name{}, 52, 80},
+		{Node{}, 92, 144},
+		{Sym{}, 60, 112},
+		{Type{}, 52, 80},
+		{MapType{}, 20, 40},
+		{ForwardType{}, 16, 32},
+		{FuncType{}, 28, 48},
+		{StructType{}, 12, 24},
+		{InterType{}, 4, 8},
+		{ChanType{}, 8, 16},
+		{ArrayType{}, 16, 24},
+		{InterMethType{}, 4, 8},
+		{DDDFieldType{}, 4, 8},
+		{FuncArgsType{}, 4, 8},
+		{ChanArgsType{}, 4, 8},
+		{PtrType{}, 4, 8},
+		{SliceType{}, 4, 8},
+	}
+
+	for _, tt := range tests {
+		want := tt._32bit
+		if _64bit {
+			want = tt._64bit
+		}
+		got := reflect.TypeOf(tt.val).Size()
+		if want != got {
+			t.Errorf("unsafe.Sizeof(%T) = %d, want %d", tt.val, got, want)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/sparselocatephifunctions.go b/src/cmd/compile/internal/gc/sparselocatephifunctions.go
new file mode 100644
index 0000000..e15f221
--- /dev/null
+++ b/src/cmd/compile/internal/gc/sparselocatephifunctions.go
@@ -0,0 +1,199 @@
+// Copyright 2016 The Go Authors. 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/ssa"
+	"fmt"
+	"math"
+)
+
+// sparseDefState contains a Go map from ONAMEs (*Node) to sparse definition trees, and
+// a search helper for the CFG's dominator tree in which those definitions are embedded.
+// Once initialized, given a use of an ONAME within a block, the ssa definition for
+// that ONAME can be discovered in time roughly proportional to the log of the number
+// of SSA definitions of that ONAME (thus avoiding pathological quadratic behavior for
+// very large programs).  The helper contains state (a dominator tree numbering) common
+// to all the sparse definition trees, as well as some necessary data obtained from
+// the ssa package.
+//
+// This algorithm has improved asymptotic complexity, but the constant factor is
+// rather large and thus it is only preferred for very large inputs containing
+// 1000s of blocks and variables.
+type sparseDefState struct {
+	helper         *ssa.SparseTreeHelper // contains one copy of information needed to do sparse mapping
+	defmapForOname map[*Node]*onameDefs  // for each ONAME, its definition set (normal and phi)
+}
+
+// onameDefs contains a record of definitions (ordinary and implied phi function) for a single OName.
+// stm is the set of definitions for the OName.
+// firstdef and lastuse are postorder block numberings that
+// conservatively bracket the entire lifetime of the OName.
+type onameDefs struct {
+	stm *ssa.SparseTreeMap
+	// firstdef and lastuse define an interval in the postorder numbering
+	// that is guaranteed to include the entire lifetime of an ONAME.
+	// In the postorder numbering, math.MaxInt32 is before anything,
+	// and 0 is after-or-equal all exit nodes and infinite loops.
+	firstdef int32 // the first definition of this ONAME *in the postorder numbering*
+	lastuse  int32 // the last use of this ONAME *in the postorder numbering*
+}
+
+// defsFor finds or creates-and-inserts-in-map the definition information
+// (sparse tree and live range) for a given OName.
+func (m *sparseDefState) defsFor(n *Node) *onameDefs {
+	d := m.defmapForOname[n]
+	if d != nil {
+		return d
+	}
+	// Reminder: firstdef/lastuse are postorder indices, not block indices,
+	// so these default values define an empty interval, not the entire one.
+	d = &onameDefs{stm: m.helper.NewTree(), firstdef: 0, lastuse: math.MaxInt32}
+	m.defmapForOname[n] = d
+	return d
+}
+
+// Insert adds a definition at b (with specified before/within/after adjustment)
+// to sparse tree onameDefs.  The lifetime is extended as necessary.
+func (m *sparseDefState) Insert(tree *onameDefs, b *ssa.Block, adjust int32) {
+	bponum := m.helper.Ponums[b.ID]
+	if bponum > tree.firstdef {
+		tree.firstdef = bponum
+	}
+	tree.stm.Insert(b, adjust, b, m.helper)
+}
+
+// Use updates tree to record a use within b, extending the lifetime as necessary.
+func (m *sparseDefState) Use(tree *onameDefs, b *ssa.Block) {
+	bponum := m.helper.Ponums[b.ID]
+	if bponum < tree.lastuse {
+		tree.lastuse = bponum
+	}
+}
+
+// locatePotentialPhiFunctions finds all the places where phi functions
+// will be inserted into a program and records those and ordinary definitions
+// in a "map" (not a Go map) that given an OName and use site, returns the
+// SSA definition for that OName that will reach the use site (that is,
+// the use site's nearest def/phi site in the dominator tree.)
+func (s *state) locatePotentialPhiFunctions(fn *Node) *sparseDefState {
+	// s.config.SparsePhiCutoff() is compared with product of numblocks and numvalues,
+	// if product is smaller than cutoff, use old non-sparse method.
+	// cutoff == 0 implies all sparse
+	// cutoff == uint(-1) implies all non-sparse
+	if uint64(s.f.NumValues())*uint64(s.f.NumBlocks()) < s.config.SparsePhiCutoff() {
+		return nil
+	}
+
+	helper := ssa.NewSparseTreeHelper(s.f)
+	po := helper.Po // index by block.ID to obtain postorder # of block.
+	trees := make(map[*Node]*onameDefs)
+	dm := &sparseDefState{defmapForOname: trees, helper: helper}
+
+	// Process params, taking note of their special lifetimes
+	b := s.f.Entry
+	for _, n := range fn.Func.Dcl {
+		switch n.Class {
+		case PPARAM, PPARAMOUT:
+			t := dm.defsFor(n)
+			dm.Insert(t, b, ssa.AdjustBefore) // define param at entry block
+			if n.Class == PPARAMOUT {
+				dm.Use(t, po[0]) // Explicitly use PPARAMOUT at very last block
+			}
+		default:
+		}
+	}
+
+	// Process memory variable.
+	t := dm.defsFor(&memVar)
+	dm.Insert(t, b, ssa.AdjustBefore) // define memory at entry block
+	dm.Use(t, po[0])                  // Explicitly use memory at last block
+
+	// Next load the map w/ basic definitions for ONames recorded per-block
+	// Iterate over po to avoid unreachable blocks.
+	for i := len(po) - 1; i >= 0; i-- {
+		b := po[i]
+		m := s.defvars[b.ID]
+		for n := range m { // no specified order, but per-node trees are independent.
+			t := dm.defsFor(n)
+			dm.Insert(t, b, ssa.AdjustWithin)
+		}
+	}
+
+	// Find last use of each variable
+	for _, v := range s.fwdRefs {
+		b := v.Block
+		name := v.Aux.(*Node)
+		t := dm.defsFor(name)
+		dm.Use(t, b)
+	}
+
+	for _, t := range trees {
+		// iterating over names in the outer loop
+		for change := true; change; {
+			change = false
+			for i := t.firstdef; i >= t.lastuse; i-- {
+				// Iterating in reverse of post-order reduces number of 'change' iterations;
+				// all possible forward flow goes through each time.
+				b := po[i]
+				// Within tree t, would a use at b require a phi function to ensure a single definition?
+				// TODO: perhaps more efficient to record specific use sites instead of range?
+				if len(b.Preds) < 2 {
+					continue // no phi possible
+				}
+				phi := t.stm.Find(b, ssa.AdjustWithin, helper) // Look for defs in earlier block or AdjustBefore in this one.
+				if phi != nil && phi.(*ssa.Block) == b {
+					continue // has a phi already in this block.
+				}
+				var defseen interface{}
+				// Do preds see different definitions? if so, need a phi function.
+				for _, e := range b.Preds {
+					p := e.Block()
+					dm.Use(t, p)                                // always count phi pred as "use"; no-op except for loop edges, which matter.
+					x := t.stm.Find(p, ssa.AdjustAfter, helper) // Look for defs reaching or within predecessors.
+					if defseen == nil {
+						defseen = x
+					}
+					if defseen != x || x == nil { // TODO: too conservative at loops, does better if x == nil -> continue
+						// Need to insert a phi function here because predecessors's definitions differ.
+						change = true
+						// Phi insertion is at AdjustBefore, visible with find in same block at AdjustWithin or AdjustAfter.
+						dm.Insert(t, b, ssa.AdjustBefore)
+						break
+					}
+				}
+			}
+		}
+	}
+	return dm
+}
+
+// FindBetterDefiningBlock tries to find a better block for a definition of OName name
+// reaching (or within) p than p itself.  If it cannot, it returns p instead.
+// This aids in more efficient location of phi functions, since it can skip over
+// branch code that might contain a definition of name if it actually does not.
+func (m *sparseDefState) FindBetterDefiningBlock(name *Node, p *ssa.Block) *ssa.Block {
+	if m == nil {
+		return p
+	}
+	t := m.defmapForOname[name]
+	// For now this is fail-soft, since the old algorithm still works using the unimproved block.
+	if t == nil {
+		return p
+	}
+	x := t.stm.Find(p, ssa.AdjustAfter, m.helper)
+	if x == nil {
+		return p
+	}
+	b := x.(*ssa.Block)
+	if b == nil {
+		return p
+	}
+	return b
+}
+
+func (d *onameDefs) String() string {
+	return fmt.Sprintf("onameDefs:first=%d,last=%d,tree=%s", d.firstdef, d.lastuse, d.stm.String())
+}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
new file mode 100644
index 0000000..62ea44f
--- /dev/null
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -0,0 +1,4468 @@
+// Copyright 2015 The Go Authors. 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"
+	"fmt"
+	"html"
+	"os"
+	"strings"
+
+	"cmd/compile/internal/ssa"
+	"cmd/internal/obj"
+	"cmd/internal/sys"
+)
+
+var ssaEnabled = true
+
+var ssaConfig *ssa.Config
+var ssaExp ssaExport
+
+func initssa() *ssa.Config {
+	ssaExp.unimplemented = false
+	ssaExp.mustImplement = true
+	if ssaConfig == nil {
+		ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0)
+	}
+	return ssaConfig
+}
+
+func shouldssa(fn *Node) bool {
+	switch Thearch.LinkArch.Name {
+	default:
+		// Only available for testing.
+		if os.Getenv("SSATEST") == "" {
+			return false
+		}
+		// Generally available.
+	case "amd64":
+	}
+	if !ssaEnabled {
+		return false
+	}
+
+	// Environment variable control of SSA CG
+	// 1. IF GOSSAFUNC == current function name THEN
+	//       compile this function with SSA and log output to ssa.html
+
+	// 2. IF GOSSAHASH == "" THEN
+	//       compile this function (and everything else) with SSA
+
+	// 3. IF GOSSAHASH == "n" or "N"
+	//       IF GOSSAPKG == current package name THEN
+	//          compile this function (and everything in this package) with SSA
+	//       ELSE
+	//          use the old back end for this function.
+	//       This is for compatibility with existing test harness and should go away.
+
+	// 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
+	//          compile this function with SSA
+	//       ELSE
+	//          compile this function with the old back end.
+
+	// Plan is for 3 to be removed when the tests are revised.
+	// SSA is now default, and is disabled by setting
+	// GOSSAHASH to n or N, or selectively with strings of
+	// 0 and 1.
+
+	name := fn.Func.Nname.Sym.Name
+
+	funcname := os.Getenv("GOSSAFUNC")
+	if funcname != "" {
+		// If GOSSAFUNC is set, compile only that function.
+		return name == funcname
+	}
+
+	pkg := os.Getenv("GOSSAPKG")
+	if pkg != "" {
+		// If GOSSAPKG is set, compile only that package.
+		return localpkg.Name == pkg
+	}
+
+	return initssa().DebugHashMatch("GOSSAHASH", name)
+}
+
+// buildssa builds an SSA function.
+func buildssa(fn *Node) *ssa.Func {
+	name := fn.Func.Nname.Sym.Name
+	printssa := name == os.Getenv("GOSSAFUNC")
+	if printssa {
+		fmt.Println("generating SSA for", name)
+		dumplist("buildssa-enter", fn.Func.Enter)
+		dumplist("buildssa-body", fn.Nbody)
+		dumplist("buildssa-exit", fn.Func.Exit)
+	}
+
+	var s state
+	s.pushLine(fn.Lineno)
+	defer s.popLine()
+
+	if fn.Func.Pragma&CgoUnsafeArgs != 0 {
+		s.cgoUnsafeArgs = true
+	}
+	if fn.Func.Pragma&Nowritebarrier != 0 {
+		s.noWB = true
+	}
+	defer func() {
+		if s.WBLineno != 0 {
+			fn.Func.WBLineno = s.WBLineno
+		}
+	}()
+	// TODO(khr): build config just once at the start of the compiler binary
+
+	ssaExp.log = printssa
+
+	s.config = initssa()
+	s.f = s.config.NewFunc()
+	s.f.Name = name
+	s.exitCode = fn.Func.Exit
+	s.panics = map[funcLine]*ssa.Block{}
+
+	if name == os.Getenv("GOSSAFUNC") {
+		// TODO: tempfile? it is handy to have the location
+		// of this file be stable, so you can just reload in the browser.
+		s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
+		// TODO: generate and print a mapping from nodes to values and blocks
+	}
+	defer func() {
+		if !printssa {
+			s.config.HTML.Close()
+		}
+	}()
+
+	// Allocate starting block
+	s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
+
+	// Allocate starting values
+	s.labels = map[string]*ssaLabel{}
+	s.labeledNodes = map[*Node]*ssaLabel{}
+	s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
+	s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
+	s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
+
+	s.startBlock(s.f.Entry)
+	s.vars[&memVar] = s.startmem
+
+	s.varsyms = map[*Node]interface{}{}
+
+	// Generate addresses of local declarations
+	s.decladdrs = map[*Node]*ssa.Value{}
+	for _, n := range fn.Func.Dcl {
+		switch n.Class {
+		case PPARAM, PPARAMOUT:
+			aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
+			s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
+			if n.Class == PPARAMOUT && s.canSSA(n) {
+				// Save ssa-able PPARAMOUT variables so we can
+				// store them back to the stack at the end of
+				// the function.
+				s.returns = append(s.returns, n)
+			}
+			if n.Class == PPARAM && s.canSSA(n) && n.Type.IsPtrShaped() {
+				s.ptrargs = append(s.ptrargs, n)
+				n.SetNotLiveAtEnd(true) // SSA takes care of this explicitly
+			}
+		case PAUTO:
+			// processed at each use, to prevent Addr coming
+			// before the decl.
+		case PAUTOHEAP:
+			// moved to heap - already handled by frontend
+		case PFUNC:
+			// local function - already handled by frontend
+		default:
+			s.Unimplementedf("local variable with class %s unimplemented", classnames[n.Class])
+		}
+	}
+
+	// Convert the AST-based IR to the SSA-based IR
+	s.stmts(fn.Func.Enter)
+	s.stmts(fn.Nbody)
+
+	// fallthrough to exit
+	if s.curBlock != nil {
+		s.pushLine(fn.Func.Endlineno)
+		s.exit()
+		s.popLine()
+	}
+
+	// Check that we used all labels
+	for name, lab := range s.labels {
+		if !lab.used() && !lab.reported {
+			yyerrorl(lab.defNode.Lineno, "label %v defined and not used", name)
+			lab.reported = true
+		}
+		if lab.used() && !lab.defined() && !lab.reported {
+			yyerrorl(lab.useNode.Lineno, "label %v not defined", name)
+			lab.reported = true
+		}
+	}
+
+	// Check any forward gotos. Non-forward gotos have already been checked.
+	for _, n := range s.fwdGotos {
+		lab := s.labels[n.Left.Sym.Name]
+		// If the label is undefined, we have already have printed an error.
+		if lab.defined() {
+			s.checkgoto(n, lab.defNode)
+		}
+	}
+
+	if nerrors > 0 {
+		s.f.Free()
+		return nil
+	}
+
+	prelinkNumvars := s.f.NumValues()
+	sparseDefState := s.locatePotentialPhiFunctions(fn)
+
+	// Link up variable uses to variable definitions
+	s.linkForwardReferences(sparseDefState)
+
+	if ssa.BuildStats > 0 {
+		s.f.LogStat("build", s.f.NumBlocks(), "blocks", prelinkNumvars, "vars_before",
+			s.f.NumValues(), "vars_after", prelinkNumvars*s.f.NumBlocks(), "ssa_phi_loc_cutoff_score")
+	}
+
+	// Don't carry reference this around longer than necessary
+	s.exitCode = Nodes{}
+
+	// Main call to ssa package to compile function
+	ssa.Compile(s.f)
+
+	return s.f
+}
+
+type state struct {
+	// configuration (arch) information
+	config *ssa.Config
+
+	// function we're building
+	f *ssa.Func
+
+	// labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
+	labels       map[string]*ssaLabel
+	labeledNodes map[*Node]*ssaLabel
+
+	// gotos that jump forward; required for deferred checkgoto calls
+	fwdGotos []*Node
+	// Code that must precede any return
+	// (e.g., copying value of heap-escaped paramout back to true paramout)
+	exitCode Nodes
+
+	// unlabeled break and continue statement tracking
+	breakTo    *ssa.Block // current target for plain break statement
+	continueTo *ssa.Block // current target for plain continue statement
+
+	// current location where we're interpreting the AST
+	curBlock *ssa.Block
+
+	// variable assignments in the current block (map from variable symbol to ssa value)
+	// *Node is the unique identifier (an ONAME Node) for the variable.
+	vars map[*Node]*ssa.Value
+
+	// all defined variables at the end of each block. Indexed by block ID.
+	defvars []map[*Node]*ssa.Value
+
+	// addresses of PPARAM and PPARAMOUT variables.
+	decladdrs map[*Node]*ssa.Value
+
+	// symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
+	varsyms map[*Node]interface{}
+
+	// starting values. Memory, stack pointer, and globals pointer
+	startmem *ssa.Value
+	sp       *ssa.Value
+	sb       *ssa.Value
+
+	// line number stack. The current line number is top of stack
+	line []int32
+
+	// list of panic calls by function name and line number.
+	// Used to deduplicate panic calls.
+	panics map[funcLine]*ssa.Block
+
+	// list of FwdRef values.
+	fwdRefs []*ssa.Value
+
+	// list of PPARAMOUT (return) variables.
+	returns []*Node
+
+	// list of PPARAM SSA-able pointer-shaped args. We ensure these are live
+	// throughout the function to help users avoid premature finalizers.
+	ptrargs []*Node
+
+	cgoUnsafeArgs bool
+	noWB          bool
+	WBLineno      int32 // line number of first write barrier. 0=no write barriers
+}
+
+type funcLine struct {
+	f    *Node
+	line int32
+}
+
+type ssaLabel struct {
+	target         *ssa.Block // block identified by this label
+	breakTarget    *ssa.Block // block to break to in control flow node identified by this label
+	continueTarget *ssa.Block // block to continue to in control flow node identified by this label
+	defNode        *Node      // label definition Node (OLABEL)
+	// Label use Node (OGOTO, OBREAK, OCONTINUE).
+	// Used only for error detection and reporting.
+	// There might be multiple uses, but we only need to track one.
+	useNode  *Node
+	reported bool // reported indicates whether an error has already been reported for this label
+}
+
+// defined reports whether the label has a definition (OLABEL node).
+func (l *ssaLabel) defined() bool { return l.defNode != nil }
+
+// used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
+func (l *ssaLabel) used() bool { return l.useNode != nil }
+
+// label returns the label associated with sym, creating it if necessary.
+func (s *state) label(sym *Sym) *ssaLabel {
+	lab := s.labels[sym.Name]
+	if lab == nil {
+		lab = new(ssaLabel)
+		s.labels[sym.Name] = lab
+	}
+	return lab
+}
+
+func (s *state) Logf(msg string, args ...interface{})   { s.config.Logf(msg, args...) }
+func (s *state) Log() bool                              { return s.config.Log() }
+func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
+func (s *state) Unimplementedf(msg string, args ...interface{}) {
+	s.config.Unimplementedf(s.peekLine(), msg, args...)
+}
+func (s *state) Warnl(line int32, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
+func (s *state) Debug_checknil() bool                              { return s.config.Debug_checknil() }
+
+var (
+	// dummy node for the memory variable
+	memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
+
+	// dummy nodes for temporary variables
+	ptrVar    = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
+	lenVar    = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "len"}}
+	newlenVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "newlen"}}
+	capVar    = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
+	typVar    = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
+	idataVar  = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
+	okVar     = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
+	deltaVar  = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "delta"}}
+)
+
+// startBlock sets the current block we're generating code in to b.
+func (s *state) startBlock(b *ssa.Block) {
+	if s.curBlock != nil {
+		s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
+	}
+	s.curBlock = b
+	s.vars = map[*Node]*ssa.Value{}
+}
+
+// endBlock marks the end of generating code for the current block.
+// Returns the (former) current block. Returns nil if there is no current
+// block, i.e. if no code flows to the current execution point.
+func (s *state) endBlock() *ssa.Block {
+	b := s.curBlock
+	if b == nil {
+		return nil
+	}
+	for len(s.defvars) <= int(b.ID) {
+		s.defvars = append(s.defvars, nil)
+	}
+	s.defvars[b.ID] = s.vars
+	s.curBlock = nil
+	s.vars = nil
+	b.Line = s.peekLine()
+	return b
+}
+
+// pushLine pushes a line number on the line number stack.
+func (s *state) pushLine(line int32) {
+	if line == 0 {
+		// the frontend may emit node with line number missing,
+		// use the parent line number in this case.
+		line = s.peekLine()
+		if Debug['K'] != 0 {
+			Warn("buildssa: line 0")
+		}
+	}
+	s.line = append(s.line, line)
+}
+
+// popLine pops the top of the line number stack.
+func (s *state) popLine() {
+	s.line = s.line[:len(s.line)-1]
+}
+
+// peekLine peek the top of the line number stack.
+func (s *state) peekLine() int32 {
+	return s.line[len(s.line)-1]
+}
+
+func (s *state) Error(msg string, args ...interface{}) {
+	yyerrorl(s.peekLine(), msg, args...)
+}
+
+// newValue0 adds a new value with no arguments to the current block.
+func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
+	return s.curBlock.NewValue0(s.peekLine(), op, t)
+}
+
+// newValue0A adds a new value with no arguments and an aux value to the current block.
+func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
+	return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
+}
+
+// newValue0I adds a new value with no arguments and an auxint value to the current block.
+func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
+	return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
+}
+
+// newValue1 adds a new value with one argument to the current block.
+func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
+}
+
+// newValue1A adds a new value with one argument and an aux value to the current block.
+func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
+}
+
+// newValue1I adds a new value with one argument and an auxint value to the current block.
+func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
+}
+
+// newValue2 adds a new value with two arguments to the current block.
+func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
+}
+
+// newValue2I adds a new value with two arguments and an auxint value to the current block.
+func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
+}
+
+// newValue3 adds a new value with three arguments to the current block.
+func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
+}
+
+// newValue3I adds a new value with three arguments and an auxint value to the current block.
+func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
+	return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
+}
+
+// entryNewValue0 adds a new value with no arguments to the entry block.
+func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
+	return s.f.Entry.NewValue0(s.peekLine(), op, t)
+}
+
+// entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
+func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
+	return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
+}
+
+// entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
+func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
+	return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
+}
+
+// entryNewValue1 adds a new value with one argument to the entry block.
+func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
+	return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
+}
+
+// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
+func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
+	return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
+}
+
+// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
+func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
+	return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
+}
+
+// entryNewValue2 adds a new value with two arguments to the entry block.
+func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
+	return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
+}
+
+// const* routines add a new const value to the entry block.
+func (s *state) constSlice(t ssa.Type) *ssa.Value       { return s.f.ConstSlice(s.peekLine(), t) }
+func (s *state) constInterface(t ssa.Type) *ssa.Value   { return s.f.ConstInterface(s.peekLine(), t) }
+func (s *state) constNil(t ssa.Type) *ssa.Value         { return s.f.ConstNil(s.peekLine(), t) }
+func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekLine(), t) }
+func (s *state) constBool(c bool) *ssa.Value {
+	return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
+}
+func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
+	return s.f.ConstInt8(s.peekLine(), t, c)
+}
+func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
+	return s.f.ConstInt16(s.peekLine(), t, c)
+}
+func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
+	return s.f.ConstInt32(s.peekLine(), t, c)
+}
+func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
+	return s.f.ConstInt64(s.peekLine(), t, c)
+}
+func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
+	return s.f.ConstFloat32(s.peekLine(), t, c)
+}
+func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
+	return s.f.ConstFloat64(s.peekLine(), t, c)
+}
+func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
+	if s.config.IntSize == 8 {
+		return s.constInt64(t, c)
+	}
+	if int64(int32(c)) != c {
+		s.Fatalf("integer constant too big %d", c)
+	}
+	return s.constInt32(t, int32(c))
+}
+
+func (s *state) stmts(a Nodes) {
+	for _, x := range a.Slice() {
+		s.stmt(x)
+	}
+}
+
+// ssaStmtList converts the statement n to SSA and adds it to s.
+func (s *state) stmtList(l Nodes) {
+	for _, n := range l.Slice() {
+		s.stmt(n)
+	}
+}
+
+// ssaStmt converts the statement n to SSA and adds it to s.
+func (s *state) stmt(n *Node) {
+	s.pushLine(n.Lineno)
+	defer s.popLine()
+
+	// If s.curBlock is nil, then we're about to generate dead code.
+	// We can't just short-circuit here, though,
+	// because we check labels and gotos as part of SSA generation.
+	// Provide a block for the dead code so that we don't have
+	// to add special cases everywhere else.
+	if s.curBlock == nil {
+		dead := s.f.NewBlock(ssa.BlockPlain)
+		s.startBlock(dead)
+	}
+
+	s.stmtList(n.Ninit)
+	switch n.Op {
+
+	case OBLOCK:
+		s.stmtList(n.List)
+
+	// No-ops
+	case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
+
+	// Expression statements
+	case OCALLFUNC, OCALLMETH, OCALLINTER:
+		s.call(n, callNormal)
+		if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
+			(compiling_runtime && n.Left.Sym.Name == "throw" ||
+				n.Left.Sym.Pkg == Runtimepkg && (n.Left.Sym.Name == "gopanic" || n.Left.Sym.Name == "selectgo" || n.Left.Sym.Name == "block")) {
+			m := s.mem()
+			b := s.endBlock()
+			b.Kind = ssa.BlockExit
+			b.SetControl(m)
+			// TODO: never rewrite OPANIC to OCALLFUNC in the
+			// first place. Need to wait until all backends
+			// go through SSA.
+		}
+	case ODEFER:
+		s.call(n.Left, callDefer)
+	case OPROC:
+		s.call(n.Left, callGo)
+
+	case OAS2DOTTYPE:
+		res, resok := s.dottype(n.Rlist.First(), true)
+		s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno, 0, false)
+		s.assign(n.List.Second(), resok, false, false, n.Lineno, 0, false)
+		return
+
+	case ODCL:
+		if n.Left.Class == PAUTOHEAP {
+			Fatalf("DCL %v", n)
+		}
+
+	case OLABEL:
+		sym := n.Left.Sym
+
+		if isblanksym(sym) {
+			// Empty identifier is valid but useless.
+			// See issues 11589, 11593.
+			return
+		}
+
+		lab := s.label(sym)
+
+		// Associate label with its control flow node, if any
+		if ctl := n.Name.Defn; ctl != nil {
+			switch ctl.Op {
+			case OFOR, OSWITCH, OSELECT:
+				s.labeledNodes[ctl] = lab
+			}
+		}
+
+		if !lab.defined() {
+			lab.defNode = n
+		} else {
+			s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Lineno))
+			lab.reported = true
+		}
+		// The label might already have a target block via a goto.
+		if lab.target == nil {
+			lab.target = s.f.NewBlock(ssa.BlockPlain)
+		}
+
+		// go to that label (we pretend "label:" is preceded by "goto label")
+		b := s.endBlock()
+		b.AddEdgeTo(lab.target)
+		s.startBlock(lab.target)
+
+	case OGOTO:
+		sym := n.Left.Sym
+
+		lab := s.label(sym)
+		if lab.target == nil {
+			lab.target = s.f.NewBlock(ssa.BlockPlain)
+		}
+		if !lab.used() {
+			lab.useNode = n
+		}
+
+		if lab.defined() {
+			s.checkgoto(n, lab.defNode)
+		} else {
+			s.fwdGotos = append(s.fwdGotos, n)
+		}
+
+		b := s.endBlock()
+		b.AddEdgeTo(lab.target)
+
+	case OAS, OASWB:
+		// Check whether we can generate static data rather than code.
+		// If so, ignore n and defer data generation until codegen.
+		// Failure to do this causes writes to readonly symbols.
+		if gen_as_init(n, true) {
+			var data []*Node
+			if s.f.StaticData != nil {
+				data = s.f.StaticData.([]*Node)
+			}
+			s.f.StaticData = append(data, n)
+			return
+		}
+
+		if n.Left == n.Right && n.Left.Op == ONAME {
+			// An x=x assignment. No point in doing anything
+			// here. In addition, skipping this assignment
+			// prevents generating:
+			//   VARDEF x
+			//   COPY x -> x
+			// which is bad because x is incorrectly considered
+			// dead before the vardef. See issue #14904.
+			return
+		}
+
+		var t *Type
+		if n.Right != nil {
+			t = n.Right.Type
+		} else {
+			t = n.Left.Type
+		}
+
+		// Evaluate RHS.
+		rhs := n.Right
+		if rhs != nil {
+			switch rhs.Op {
+			case OSTRUCTLIT, OARRAYLIT:
+				// All literals with nonzero fields have already been
+				// rewritten during walk. Any that remain are just T{}
+				// or equivalents. Use the zero value.
+				if !iszero(rhs) {
+					Fatalf("literal with nonzero value in SSA: %v", rhs)
+				}
+				rhs = nil
+			case OAPPEND:
+				// If we're writing the result of an append back to the same slice,
+				// handle it specially to avoid write barriers on the fast (non-growth) path.
+				// If the slice can be SSA'd, it'll be on the stack,
+				// so there will be no write barriers,
+				// so there's no need to attempt to prevent them.
+				if samesafeexpr(n.Left, rhs.List.First()) && !s.canSSA(n.Left) {
+					s.append(rhs, true)
+					return
+				}
+			}
+		}
+		var r *ssa.Value
+		var isVolatile bool
+		needwb := n.Op == OASWB && rhs != nil
+		deref := !canSSAType(t)
+		if deref {
+			if rhs == nil {
+				r = nil // Signal assign to use OpZero.
+			} else {
+				r, isVolatile = s.addr(rhs, false)
+			}
+		} else {
+			if rhs == nil {
+				r = s.zeroVal(t)
+			} else {
+				r = s.expr(rhs)
+			}
+		}
+		if rhs != nil && rhs.Op == OAPPEND {
+			// The frontend gets rid of the write barrier to enable the special OAPPEND
+			// handling above, but since this is not a special case, we need it.
+			// TODO: just add a ptr graying to the end of growslice?
+			// TODO: check whether we need to provide special handling and a write barrier
+			// for ODOTTYPE and ORECV also.
+			// They get similar wb-removal treatment in walk.go:OAS.
+			needwb = true
+		}
+
+		var skip skipMask
+		if rhs != nil && (rhs.Op == OSLICE || rhs.Op == OSLICE3 || rhs.Op == OSLICESTR) && samesafeexpr(rhs.Left, n.Left) {
+			// We're assigning a slicing operation back to its source.
+			// Don't write back fields we aren't changing. See issue #14855.
+			i, j, k := rhs.SliceBounds()
+			if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) {
+				// [0:...] is the same as [:...]
+				i = nil
+			}
+			// TODO: detect defaults for len/cap also.
+			// Currently doesn't really work because (*p)[:len(*p)] appears here as:
+			//    tmp = len(*p)
+			//    (*p)[:tmp]
+			//if j != nil && (j.Op == OLEN && samesafeexpr(j.Left, n.Left)) {
+			//      j = nil
+			//}
+			//if k != nil && (k.Op == OCAP && samesafeexpr(k.Left, n.Left)) {
+			//      k = nil
+			//}
+			if i == nil {
+				skip |= skipPtr
+				if j == nil {
+					skip |= skipLen
+				}
+				if k == nil {
+					skip |= skipCap
+				}
+			}
+		}
+
+		s.assign(n.Left, r, needwb, deref, n.Lineno, skip, isVolatile)
+
+	case OIF:
+		bThen := s.f.NewBlock(ssa.BlockPlain)
+		bEnd := s.f.NewBlock(ssa.BlockPlain)
+		var bElse *ssa.Block
+		if n.Rlist.Len() != 0 {
+			bElse = s.f.NewBlock(ssa.BlockPlain)
+			s.condBranch(n.Left, bThen, bElse, n.Likely)
+		} else {
+			s.condBranch(n.Left, bThen, bEnd, n.Likely)
+		}
+
+		s.startBlock(bThen)
+		s.stmts(n.Nbody)
+		if b := s.endBlock(); b != nil {
+			b.AddEdgeTo(bEnd)
+		}
+
+		if n.Rlist.Len() != 0 {
+			s.startBlock(bElse)
+			s.stmtList(n.Rlist)
+			if b := s.endBlock(); b != nil {
+				b.AddEdgeTo(bEnd)
+			}
+		}
+		s.startBlock(bEnd)
+
+	case ORETURN:
+		s.stmtList(n.List)
+		s.exit()
+	case ORETJMP:
+		s.stmtList(n.List)
+		b := s.exit()
+		b.Kind = ssa.BlockRetJmp // override BlockRet
+		b.Aux = n.Left.Sym
+
+	case OCONTINUE, OBREAK:
+		var op string
+		var to *ssa.Block
+		switch n.Op {
+		case OCONTINUE:
+			op = "continue"
+			to = s.continueTo
+		case OBREAK:
+			op = "break"
+			to = s.breakTo
+		}
+		if n.Left == nil {
+			// plain break/continue
+			if to == nil {
+				s.Error("%s is not in a loop", op)
+				return
+			}
+			// nothing to do; "to" is already the correct target
+		} else {
+			// labeled break/continue; look up the target
+			sym := n.Left.Sym
+			lab := s.label(sym)
+			if !lab.used() {
+				lab.useNode = n.Left
+			}
+			if !lab.defined() {
+				s.Error("%s label not defined: %v", op, sym)
+				lab.reported = true
+				return
+			}
+			switch n.Op {
+			case OCONTINUE:
+				to = lab.continueTarget
+			case OBREAK:
+				to = lab.breakTarget
+			}
+			if to == nil {
+				// Valid label but not usable with a break/continue here, e.g.:
+				// for {
+				// 	continue abc
+				// }
+				// abc:
+				// for {}
+				s.Error("invalid %s label %v", op, sym)
+				lab.reported = true
+				return
+			}
+		}
+
+		b := s.endBlock()
+		b.AddEdgeTo(to)
+
+	case OFOR:
+		// OFOR: for Ninit; Left; Right { Nbody }
+		bCond := s.f.NewBlock(ssa.BlockPlain)
+		bBody := s.f.NewBlock(ssa.BlockPlain)
+		bIncr := s.f.NewBlock(ssa.BlockPlain)
+		bEnd := s.f.NewBlock(ssa.BlockPlain)
+
+		// first, jump to condition test
+		b := s.endBlock()
+		b.AddEdgeTo(bCond)
+
+		// generate code to test condition
+		s.startBlock(bCond)
+		if n.Left != nil {
+			s.condBranch(n.Left, bBody, bEnd, 1)
+		} else {
+			b := s.endBlock()
+			b.Kind = ssa.BlockPlain
+			b.AddEdgeTo(bBody)
+		}
+
+		// set up for continue/break in body
+		prevContinue := s.continueTo
+		prevBreak := s.breakTo
+		s.continueTo = bIncr
+		s.breakTo = bEnd
+		lab := s.labeledNodes[n]
+		if lab != nil {
+			// labeled for loop
+			lab.continueTarget = bIncr
+			lab.breakTarget = bEnd
+		}
+
+		// generate body
+		s.startBlock(bBody)
+		s.stmts(n.Nbody)
+
+		// tear down continue/break
+		s.continueTo = prevContinue
+		s.breakTo = prevBreak
+		if lab != nil {
+			lab.continueTarget = nil
+			lab.breakTarget = nil
+		}
+
+		// done with body, goto incr
+		if b := s.endBlock(); b != nil {
+			b.AddEdgeTo(bIncr)
+		}
+
+		// generate incr
+		s.startBlock(bIncr)
+		if n.Right != nil {
+			s.stmt(n.Right)
+		}
+		if b := s.endBlock(); b != nil {
+			b.AddEdgeTo(bCond)
+		}
+		s.startBlock(bEnd)
+
+	case OSWITCH, OSELECT:
+		// These have been mostly rewritten by the front end into their Nbody fields.
+		// Our main task is to correctly hook up any break statements.
+		bEnd := s.f.NewBlock(ssa.BlockPlain)
+
+		prevBreak := s.breakTo
+		s.breakTo = bEnd
+		lab := s.labeledNodes[n]
+		if lab != nil {
+			// labeled
+			lab.breakTarget = bEnd
+		}
+
+		// generate body code
+		s.stmts(n.Nbody)
+
+		s.breakTo = prevBreak
+		if lab != nil {
+			lab.breakTarget = nil
+		}
+
+		// OSWITCH never falls through (s.curBlock == nil here).
+		// OSELECT does not fall through if we're calling selectgo.
+		// OSELECT does fall through if we're calling selectnb{send,recv}[2].
+		// In those latter cases, go to the code after the select.
+		if b := s.endBlock(); b != nil {
+			b.AddEdgeTo(bEnd)
+		}
+		s.startBlock(bEnd)
+
+	case OVARKILL:
+		// Insert a varkill op to record that a variable is no longer live.
+		// We only care about liveness info at call sites, so putting the
+		// varkill in the store chain is enough to keep it correctly ordered
+		// with respect to call ops.
+		if !s.canSSA(n.Left) {
+			s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
+		}
+
+	case OVARLIVE:
+		// Insert a varlive op to record that a variable is still live.
+		if !n.Left.Addrtaken {
+			s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
+		}
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
+
+	case OCHECKNIL:
+		p := s.expr(n.Left)
+		s.nilCheck(p)
+
+	default:
+		s.Unimplementedf("unhandled stmt %s", n.Op)
+	}
+}
+
+// exit processes any code that needs to be generated just before returning.
+// It returns a BlockRet block that ends the control flow. Its control value
+// will be set to the final memory state.
+func (s *state) exit() *ssa.Block {
+	if hasdefer {
+		s.rtcall(Deferreturn, true, nil)
+	}
+
+	// Run exit code. Typically, this code copies heap-allocated PPARAMOUT
+	// variables back to the stack.
+	s.stmts(s.exitCode)
+
+	// Store SSAable PPARAMOUT variables back to stack locations.
+	for _, n := range s.returns {
+		addr := s.decladdrs[n]
+		val := s.variable(n, n.Type)
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, n, s.mem())
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, n.Type.Size(), addr, val, s.mem())
+		// TODO: if val is ever spilled, we'd like to use the
+		// PPARAMOUT slot for spilling it. That won't happen
+		// currently.
+	}
+
+	// Keep input pointer args live until the return. This is a bandaid
+	// fix for 1.7 for what will become in 1.8 explicit runtime.KeepAlive calls.
+	// For <= 1.7 we guarantee that pointer input arguments live to the end of
+	// the function to prevent premature (from the user's point of view)
+	// execution of finalizers. See issue 15277.
+	// TODO: remove for 1.8?
+	for _, n := range s.ptrargs {
+		s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
+	}
+
+	// Do actual return.
+	m := s.mem()
+	b := s.endBlock()
+	b.Kind = ssa.BlockRet
+	b.SetControl(m)
+	return b
+}
+
+type opAndType struct {
+	op    Op
+	etype EType
+}
+
+var opToSSA = map[opAndType]ssa.Op{
+	opAndType{OADD, TINT8}:    ssa.OpAdd8,
+	opAndType{OADD, TUINT8}:   ssa.OpAdd8,
+	opAndType{OADD, TINT16}:   ssa.OpAdd16,
+	opAndType{OADD, TUINT16}:  ssa.OpAdd16,
+	opAndType{OADD, TINT32}:   ssa.OpAdd32,
+	opAndType{OADD, TUINT32}:  ssa.OpAdd32,
+	opAndType{OADD, TPTR32}:   ssa.OpAdd32,
+	opAndType{OADD, TINT64}:   ssa.OpAdd64,
+	opAndType{OADD, TUINT64}:  ssa.OpAdd64,
+	opAndType{OADD, TPTR64}:   ssa.OpAdd64,
+	opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
+	opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
+
+	opAndType{OSUB, TINT8}:    ssa.OpSub8,
+	opAndType{OSUB, TUINT8}:   ssa.OpSub8,
+	opAndType{OSUB, TINT16}:   ssa.OpSub16,
+	opAndType{OSUB, TUINT16}:  ssa.OpSub16,
+	opAndType{OSUB, TINT32}:   ssa.OpSub32,
+	opAndType{OSUB, TUINT32}:  ssa.OpSub32,
+	opAndType{OSUB, TINT64}:   ssa.OpSub64,
+	opAndType{OSUB, TUINT64}:  ssa.OpSub64,
+	opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
+	opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
+
+	opAndType{ONOT, TBOOL}: ssa.OpNot,
+
+	opAndType{OMINUS, TINT8}:    ssa.OpNeg8,
+	opAndType{OMINUS, TUINT8}:   ssa.OpNeg8,
+	opAndType{OMINUS, TINT16}:   ssa.OpNeg16,
+	opAndType{OMINUS, TUINT16}:  ssa.OpNeg16,
+	opAndType{OMINUS, TINT32}:   ssa.OpNeg32,
+	opAndType{OMINUS, TUINT32}:  ssa.OpNeg32,
+	opAndType{OMINUS, TINT64}:   ssa.OpNeg64,
+	opAndType{OMINUS, TUINT64}:  ssa.OpNeg64,
+	opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
+	opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
+
+	opAndType{OCOM, TINT8}:   ssa.OpCom8,
+	opAndType{OCOM, TUINT8}:  ssa.OpCom8,
+	opAndType{OCOM, TINT16}:  ssa.OpCom16,
+	opAndType{OCOM, TUINT16}: ssa.OpCom16,
+	opAndType{OCOM, TINT32}:  ssa.OpCom32,
+	opAndType{OCOM, TUINT32}: ssa.OpCom32,
+	opAndType{OCOM, TINT64}:  ssa.OpCom64,
+	opAndType{OCOM, TUINT64}: ssa.OpCom64,
+
+	opAndType{OIMAG, TCOMPLEX64}:  ssa.OpComplexImag,
+	opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
+	opAndType{OREAL, TCOMPLEX64}:  ssa.OpComplexReal,
+	opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
+
+	opAndType{OMUL, TINT8}:    ssa.OpMul8,
+	opAndType{OMUL, TUINT8}:   ssa.OpMul8,
+	opAndType{OMUL, TINT16}:   ssa.OpMul16,
+	opAndType{OMUL, TUINT16}:  ssa.OpMul16,
+	opAndType{OMUL, TINT32}:   ssa.OpMul32,
+	opAndType{OMUL, TUINT32}:  ssa.OpMul32,
+	opAndType{OMUL, TINT64}:   ssa.OpMul64,
+	opAndType{OMUL, TUINT64}:  ssa.OpMul64,
+	opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
+	opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
+
+	opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
+	opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
+
+	opAndType{OHMUL, TINT8}:   ssa.OpHmul8,
+	opAndType{OHMUL, TUINT8}:  ssa.OpHmul8u,
+	opAndType{OHMUL, TINT16}:  ssa.OpHmul16,
+	opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
+	opAndType{OHMUL, TINT32}:  ssa.OpHmul32,
+	opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
+
+	opAndType{ODIV, TINT8}:   ssa.OpDiv8,
+	opAndType{ODIV, TUINT8}:  ssa.OpDiv8u,
+	opAndType{ODIV, TINT16}:  ssa.OpDiv16,
+	opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
+	opAndType{ODIV, TINT32}:  ssa.OpDiv32,
+	opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
+	opAndType{ODIV, TINT64}:  ssa.OpDiv64,
+	opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
+
+	opAndType{OMOD, TINT8}:   ssa.OpMod8,
+	opAndType{OMOD, TUINT8}:  ssa.OpMod8u,
+	opAndType{OMOD, TINT16}:  ssa.OpMod16,
+	opAndType{OMOD, TUINT16}: ssa.OpMod16u,
+	opAndType{OMOD, TINT32}:  ssa.OpMod32,
+	opAndType{OMOD, TUINT32}: ssa.OpMod32u,
+	opAndType{OMOD, TINT64}:  ssa.OpMod64,
+	opAndType{OMOD, TUINT64}: ssa.OpMod64u,
+
+	opAndType{OAND, TINT8}:   ssa.OpAnd8,
+	opAndType{OAND, TUINT8}:  ssa.OpAnd8,
+	opAndType{OAND, TINT16}:  ssa.OpAnd16,
+	opAndType{OAND, TUINT16}: ssa.OpAnd16,
+	opAndType{OAND, TINT32}:  ssa.OpAnd32,
+	opAndType{OAND, TUINT32}: ssa.OpAnd32,
+	opAndType{OAND, TINT64}:  ssa.OpAnd64,
+	opAndType{OAND, TUINT64}: ssa.OpAnd64,
+
+	opAndType{OOR, TINT8}:   ssa.OpOr8,
+	opAndType{OOR, TUINT8}:  ssa.OpOr8,
+	opAndType{OOR, TINT16}:  ssa.OpOr16,
+	opAndType{OOR, TUINT16}: ssa.OpOr16,
+	opAndType{OOR, TINT32}:  ssa.OpOr32,
+	opAndType{OOR, TUINT32}: ssa.OpOr32,
+	opAndType{OOR, TINT64}:  ssa.OpOr64,
+	opAndType{OOR, TUINT64}: ssa.OpOr64,
+
+	opAndType{OXOR, TINT8}:   ssa.OpXor8,
+	opAndType{OXOR, TUINT8}:  ssa.OpXor8,
+	opAndType{OXOR, TINT16}:  ssa.OpXor16,
+	opAndType{OXOR, TUINT16}: ssa.OpXor16,
+	opAndType{OXOR, TINT32}:  ssa.OpXor32,
+	opAndType{OXOR, TUINT32}: ssa.OpXor32,
+	opAndType{OXOR, TINT64}:  ssa.OpXor64,
+	opAndType{OXOR, TUINT64}: ssa.OpXor64,
+
+	opAndType{OEQ, TBOOL}:      ssa.OpEqB,
+	opAndType{OEQ, TINT8}:      ssa.OpEq8,
+	opAndType{OEQ, TUINT8}:     ssa.OpEq8,
+	opAndType{OEQ, TINT16}:     ssa.OpEq16,
+	opAndType{OEQ, TUINT16}:    ssa.OpEq16,
+	opAndType{OEQ, TINT32}:     ssa.OpEq32,
+	opAndType{OEQ, TUINT32}:    ssa.OpEq32,
+	opAndType{OEQ, TINT64}:     ssa.OpEq64,
+	opAndType{OEQ, TUINT64}:    ssa.OpEq64,
+	opAndType{OEQ, TINTER}:     ssa.OpEqInter,
+	opAndType{OEQ, TSLICE}:     ssa.OpEqSlice,
+	opAndType{OEQ, TFUNC}:      ssa.OpEqPtr,
+	opAndType{OEQ, TMAP}:       ssa.OpEqPtr,
+	opAndType{OEQ, TCHAN}:      ssa.OpEqPtr,
+	opAndType{OEQ, TPTR64}:     ssa.OpEqPtr,
+	opAndType{OEQ, TUINTPTR}:   ssa.OpEqPtr,
+	opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
+	opAndType{OEQ, TFLOAT64}:   ssa.OpEq64F,
+	opAndType{OEQ, TFLOAT32}:   ssa.OpEq32F,
+
+	opAndType{ONE, TBOOL}:      ssa.OpNeqB,
+	opAndType{ONE, TINT8}:      ssa.OpNeq8,
+	opAndType{ONE, TUINT8}:     ssa.OpNeq8,
+	opAndType{ONE, TINT16}:     ssa.OpNeq16,
+	opAndType{ONE, TUINT16}:    ssa.OpNeq16,
+	opAndType{ONE, TINT32}:     ssa.OpNeq32,
+	opAndType{ONE, TUINT32}:    ssa.OpNeq32,
+	opAndType{ONE, TINT64}:     ssa.OpNeq64,
+	opAndType{ONE, TUINT64}:    ssa.OpNeq64,
+	opAndType{ONE, TINTER}:     ssa.OpNeqInter,
+	opAndType{ONE, TSLICE}:     ssa.OpNeqSlice,
+	opAndType{ONE, TFUNC}:      ssa.OpNeqPtr,
+	opAndType{ONE, TMAP}:       ssa.OpNeqPtr,
+	opAndType{ONE, TCHAN}:      ssa.OpNeqPtr,
+	opAndType{ONE, TPTR64}:     ssa.OpNeqPtr,
+	opAndType{ONE, TUINTPTR}:   ssa.OpNeqPtr,
+	opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
+	opAndType{ONE, TFLOAT64}:   ssa.OpNeq64F,
+	opAndType{ONE, TFLOAT32}:   ssa.OpNeq32F,
+
+	opAndType{OLT, TINT8}:    ssa.OpLess8,
+	opAndType{OLT, TUINT8}:   ssa.OpLess8U,
+	opAndType{OLT, TINT16}:   ssa.OpLess16,
+	opAndType{OLT, TUINT16}:  ssa.OpLess16U,
+	opAndType{OLT, TINT32}:   ssa.OpLess32,
+	opAndType{OLT, TUINT32}:  ssa.OpLess32U,
+	opAndType{OLT, TINT64}:   ssa.OpLess64,
+	opAndType{OLT, TUINT64}:  ssa.OpLess64U,
+	opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
+	opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
+
+	opAndType{OGT, TINT8}:    ssa.OpGreater8,
+	opAndType{OGT, TUINT8}:   ssa.OpGreater8U,
+	opAndType{OGT, TINT16}:   ssa.OpGreater16,
+	opAndType{OGT, TUINT16}:  ssa.OpGreater16U,
+	opAndType{OGT, TINT32}:   ssa.OpGreater32,
+	opAndType{OGT, TUINT32}:  ssa.OpGreater32U,
+	opAndType{OGT, TINT64}:   ssa.OpGreater64,
+	opAndType{OGT, TUINT64}:  ssa.OpGreater64U,
+	opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
+	opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
+
+	opAndType{OLE, TINT8}:    ssa.OpLeq8,
+	opAndType{OLE, TUINT8}:   ssa.OpLeq8U,
+	opAndType{OLE, TINT16}:   ssa.OpLeq16,
+	opAndType{OLE, TUINT16}:  ssa.OpLeq16U,
+	opAndType{OLE, TINT32}:   ssa.OpLeq32,
+	opAndType{OLE, TUINT32}:  ssa.OpLeq32U,
+	opAndType{OLE, TINT64}:   ssa.OpLeq64,
+	opAndType{OLE, TUINT64}:  ssa.OpLeq64U,
+	opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
+	opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
+
+	opAndType{OGE, TINT8}:    ssa.OpGeq8,
+	opAndType{OGE, TUINT8}:   ssa.OpGeq8U,
+	opAndType{OGE, TINT16}:   ssa.OpGeq16,
+	opAndType{OGE, TUINT16}:  ssa.OpGeq16U,
+	opAndType{OGE, TINT32}:   ssa.OpGeq32,
+	opAndType{OGE, TUINT32}:  ssa.OpGeq32U,
+	opAndType{OGE, TINT64}:   ssa.OpGeq64,
+	opAndType{OGE, TUINT64}:  ssa.OpGeq64U,
+	opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
+	opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
+
+	opAndType{OLROT, TUINT8}:  ssa.OpLrot8,
+	opAndType{OLROT, TUINT16}: ssa.OpLrot16,
+	opAndType{OLROT, TUINT32}: ssa.OpLrot32,
+	opAndType{OLROT, TUINT64}: ssa.OpLrot64,
+
+	opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
+}
+
+func (s *state) concreteEtype(t *Type) EType {
+	e := t.Etype
+	switch e {
+	default:
+		return e
+	case TINT:
+		if s.config.IntSize == 8 {
+			return TINT64
+		}
+		return TINT32
+	case TUINT:
+		if s.config.IntSize == 8 {
+			return TUINT64
+		}
+		return TUINT32
+	case TUINTPTR:
+		if s.config.PtrSize == 8 {
+			return TUINT64
+		}
+		return TUINT32
+	}
+}
+
+func (s *state) ssaOp(op Op, t *Type) ssa.Op {
+	etype := s.concreteEtype(t)
+	x, ok := opToSSA[opAndType{op, etype}]
+	if !ok {
+		s.Unimplementedf("unhandled binary op %s %s", op, etype)
+	}
+	return x
+}
+
+func floatForComplex(t *Type) *Type {
+	if t.Size() == 8 {
+		return Types[TFLOAT32]
+	} else {
+		return Types[TFLOAT64]
+	}
+}
+
+type opAndTwoTypes struct {
+	op     Op
+	etype1 EType
+	etype2 EType
+}
+
+type twoTypes struct {
+	etype1 EType
+	etype2 EType
+}
+
+type twoOpsAndType struct {
+	op1              ssa.Op
+	op2              ssa.Op
+	intermediateType EType
+}
+
+var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
+
+	twoTypes{TINT8, TFLOAT32}:  twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
+	twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
+	twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
+	twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
+
+	twoTypes{TINT8, TFLOAT64}:  twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
+	twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
+	twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
+	twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
+
+	twoTypes{TFLOAT32, TINT8}:  twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
+	twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
+	twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
+	twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
+
+	twoTypes{TFLOAT64, TINT8}:  twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
+	twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
+	twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
+	twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
+	// unsigned
+	twoTypes{TUINT8, TFLOAT32}:  twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
+	twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
+	twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
+	twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64},            // Cvt64Uto32F, branchy code expansion instead
+
+	twoTypes{TUINT8, TFLOAT64}:  twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
+	twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
+	twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
+	twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64},            // Cvt64Uto64F, branchy code expansion instead
+
+	twoTypes{TFLOAT32, TUINT8}:  twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
+	twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
+	twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
+	twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64},          // Cvt32Fto64U, branchy code expansion instead
+
+	twoTypes{TFLOAT64, TUINT8}:  twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
+	twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
+	twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
+	twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64},          // Cvt64Fto64U, branchy code expansion instead
+
+	// float
+	twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
+	twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
+	twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
+	twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
+}
+
+var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
+	opAndTwoTypes{OLSH, TINT8, TUINT8}:   ssa.OpLsh8x8,
+	opAndTwoTypes{OLSH, TUINT8, TUINT8}:  ssa.OpLsh8x8,
+	opAndTwoTypes{OLSH, TINT8, TUINT16}:  ssa.OpLsh8x16,
+	opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
+	opAndTwoTypes{OLSH, TINT8, TUINT32}:  ssa.OpLsh8x32,
+	opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
+	opAndTwoTypes{OLSH, TINT8, TUINT64}:  ssa.OpLsh8x64,
+	opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
+
+	opAndTwoTypes{OLSH, TINT16, TUINT8}:   ssa.OpLsh16x8,
+	opAndTwoTypes{OLSH, TUINT16, TUINT8}:  ssa.OpLsh16x8,
+	opAndTwoTypes{OLSH, TINT16, TUINT16}:  ssa.OpLsh16x16,
+	opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
+	opAndTwoTypes{OLSH, TINT16, TUINT32}:  ssa.OpLsh16x32,
+	opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
+	opAndTwoTypes{OLSH, TINT16, TUINT64}:  ssa.OpLsh16x64,
+	opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
+
+	opAndTwoTypes{OLSH, TINT32, TUINT8}:   ssa.OpLsh32x8,
+	opAndTwoTypes{OLSH, TUINT32, TUINT8}:  ssa.OpLsh32x8,
+	opAndTwoTypes{OLSH, TINT32, TUINT16}:  ssa.OpLsh32x16,
+	opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
+	opAndTwoTypes{OLSH, TINT32, TUINT32}:  ssa.OpLsh32x32,
+	opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
+	opAndTwoTypes{OLSH, TINT32, TUINT64}:  ssa.OpLsh32x64,
+	opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
+
+	opAndTwoTypes{OLSH, TINT64, TUINT8}:   ssa.OpLsh64x8,
+	opAndTwoTypes{OLSH, TUINT64, TUINT8}:  ssa.OpLsh64x8,
+	opAndTwoTypes{OLSH, TINT64, TUINT16}:  ssa.OpLsh64x16,
+	opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
+	opAndTwoTypes{OLSH, TINT64, TUINT32}:  ssa.OpLsh64x32,
+	opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
+	opAndTwoTypes{OLSH, TINT64, TUINT64}:  ssa.OpLsh64x64,
+	opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
+
+	opAndTwoTypes{ORSH, TINT8, TUINT8}:   ssa.OpRsh8x8,
+	opAndTwoTypes{ORSH, TUINT8, TUINT8}:  ssa.OpRsh8Ux8,
+	opAndTwoTypes{ORSH, TINT8, TUINT16}:  ssa.OpRsh8x16,
+	opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
+	opAndTwoTypes{ORSH, TINT8, TUINT32}:  ssa.OpRsh8x32,
+	opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
+	opAndTwoTypes{ORSH, TINT8, TUINT64}:  ssa.OpRsh8x64,
+	opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
+
+	opAndTwoTypes{ORSH, TINT16, TUINT8}:   ssa.OpRsh16x8,
+	opAndTwoTypes{ORSH, TUINT16, TUINT8}:  ssa.OpRsh16Ux8,
+	opAndTwoTypes{ORSH, TINT16, TUINT16}:  ssa.OpRsh16x16,
+	opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
+	opAndTwoTypes{ORSH, TINT16, TUINT32}:  ssa.OpRsh16x32,
+	opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
+	opAndTwoTypes{ORSH, TINT16, TUINT64}:  ssa.OpRsh16x64,
+	opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
+
+	opAndTwoTypes{ORSH, TINT32, TUINT8}:   ssa.OpRsh32x8,
+	opAndTwoTypes{ORSH, TUINT32, TUINT8}:  ssa.OpRsh32Ux8,
+	opAndTwoTypes{ORSH, TINT32, TUINT16}:  ssa.OpRsh32x16,
+	opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
+	opAndTwoTypes{ORSH, TINT32, TUINT32}:  ssa.OpRsh32x32,
+	opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
+	opAndTwoTypes{ORSH, TINT32, TUINT64}:  ssa.OpRsh32x64,
+	opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
+
+	opAndTwoTypes{ORSH, TINT64, TUINT8}:   ssa.OpRsh64x8,
+	opAndTwoTypes{ORSH, TUINT64, TUINT8}:  ssa.OpRsh64Ux8,
+	opAndTwoTypes{ORSH, TINT64, TUINT16}:  ssa.OpRsh64x16,
+	opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
+	opAndTwoTypes{ORSH, TINT64, TUINT32}:  ssa.OpRsh64x32,
+	opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
+	opAndTwoTypes{ORSH, TINT64, TUINT64}:  ssa.OpRsh64x64,
+	opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
+}
+
+func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
+	etype1 := s.concreteEtype(t)
+	etype2 := s.concreteEtype(u)
+	x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
+	if !ok {
+		s.Unimplementedf("unhandled shift op %s etype=%s/%s", op, etype1, etype2)
+	}
+	return x
+}
+
+func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
+	etype1 := s.concreteEtype(t)
+	x, ok := opToSSA[opAndType{op, etype1}]
+	if !ok {
+		s.Unimplementedf("unhandled rotate op %s etype=%s", op, etype1)
+	}
+	return x
+}
+
+// expr converts the expression n to ssa, adds it to s and returns the ssa result.
+func (s *state) expr(n *Node) *ssa.Value {
+	if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) {
+		// ONAMEs and named OLITERALs have the line number
+		// of the decl, not the use. See issue 14742.
+		s.pushLine(n.Lineno)
+		defer s.popLine()
+	}
+
+	s.stmtList(n.Ninit)
+	switch n.Op {
+	case OCFUNC:
+		aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Left.Sym})
+		return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
+	case ONAME:
+		if n.Class == PFUNC {
+			// "value" of a function is the address of the function's closure
+			sym := funcsym(n.Sym)
+			aux := &ssa.ExternSymbol{Typ: n.Type, Sym: sym}
+			return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
+		}
+		if s.canSSA(n) {
+			return s.variable(n, n.Type)
+		}
+		addr, _ := s.addr(n, false)
+		return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
+	case OCLOSUREVAR:
+		addr, _ := s.addr(n, false)
+		return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
+	case OLITERAL:
+		switch u := n.Val().U.(type) {
+		case *Mpint:
+			i := u.Int64()
+			switch n.Type.Size() {
+			case 1:
+				return s.constInt8(n.Type, int8(i))
+			case 2:
+				return s.constInt16(n.Type, int16(i))
+			case 4:
+				return s.constInt32(n.Type, int32(i))
+			case 8:
+				return s.constInt64(n.Type, i)
+			default:
+				s.Fatalf("bad integer size %d", n.Type.Size())
+				return nil
+			}
+		case string:
+			if u == "" {
+				return s.constEmptyString(n.Type)
+			}
+			return s.entryNewValue0A(ssa.OpConstString, n.Type, u)
+		case bool:
+			return s.constBool(u)
+		case *NilVal:
+			t := n.Type
+			switch {
+			case t.IsSlice():
+				return s.constSlice(t)
+			case t.IsInterface():
+				return s.constInterface(t)
+			default:
+				return s.constNil(t)
+			}
+		case *Mpflt:
+			switch n.Type.Size() {
+			case 4:
+				return s.constFloat32(n.Type, u.Float32())
+			case 8:
+				return s.constFloat64(n.Type, u.Float64())
+			default:
+				s.Fatalf("bad float size %d", n.Type.Size())
+				return nil
+			}
+		case *Mpcplx:
+			r := &u.Real
+			i := &u.Imag
+			switch n.Type.Size() {
+			case 8:
+				pt := Types[TFLOAT32]
+				return s.newValue2(ssa.OpComplexMake, n.Type,
+					s.constFloat32(pt, r.Float32()),
+					s.constFloat32(pt, i.Float32()))
+			case 16:
+				pt := Types[TFLOAT64]
+				return s.newValue2(ssa.OpComplexMake, n.Type,
+					s.constFloat64(pt, r.Float64()),
+					s.constFloat64(pt, i.Float64()))
+			default:
+				s.Fatalf("bad float size %d", n.Type.Size())
+				return nil
+			}
+
+		default:
+			s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
+			return nil
+		}
+	case OCONVNOP:
+		to := n.Type
+		from := n.Left.Type
+
+		// Assume everything will work out, so set up our return value.
+		// Anything interesting that happens from here is a fatal.
+		x := s.expr(n.Left)
+
+		// Special case for not confusing GC and liveness.
+		// We don't want pointers accidentally classified
+		// as not-pointers or vice-versa because of copy
+		// elision.
+		if to.IsPtrShaped() != from.IsPtrShaped() {
+			return s.newValue2(ssa.OpConvert, to, x, s.mem())
+		}
+
+		v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
+
+		// CONVNOP closure
+		if to.Etype == TFUNC && from.IsPtrShaped() {
+			return v
+		}
+
+		// named <--> unnamed type or typed <--> untyped const
+		if from.Etype == to.Etype {
+			return v
+		}
+
+		// unsafe.Pointer <--> *T
+		if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
+			return v
+		}
+
+		dowidth(from)
+		dowidth(to)
+		if from.Width != to.Width {
+			s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
+			return nil
+		}
+		if etypesign(from.Etype) != etypesign(to.Etype) {
+			s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, from.Etype, to, to.Etype)
+			return nil
+		}
+
+		if instrumenting {
+			// These appear to be fine, but they fail the
+			// integer constraint below, so okay them here.
+			// Sample non-integer conversion: map[string]string -> *uint8
+			return v
+		}
+
+		if etypesign(from.Etype) == 0 {
+			s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
+			return nil
+		}
+
+		// integer, same width, same sign
+		return v
+
+	case OCONV:
+		x := s.expr(n.Left)
+		ft := n.Left.Type // from type
+		tt := n.Type      // to type
+		if ft.IsInteger() && tt.IsInteger() {
+			var op ssa.Op
+			if tt.Size() == ft.Size() {
+				op = ssa.OpCopy
+			} else if tt.Size() < ft.Size() {
+				// truncation
+				switch 10*ft.Size() + tt.Size() {
+				case 21:
+					op = ssa.OpTrunc16to8
+				case 41:
+					op = ssa.OpTrunc32to8
+				case 42:
+					op = ssa.OpTrunc32to16
+				case 81:
+					op = ssa.OpTrunc64to8
+				case 82:
+					op = ssa.OpTrunc64to16
+				case 84:
+					op = ssa.OpTrunc64to32
+				default:
+					s.Fatalf("weird integer truncation %s -> %s", ft, tt)
+				}
+			} else if ft.IsSigned() {
+				// sign extension
+				switch 10*ft.Size() + tt.Size() {
+				case 12:
+					op = ssa.OpSignExt8to16
+				case 14:
+					op = ssa.OpSignExt8to32
+				case 18:
+					op = ssa.OpSignExt8to64
+				case 24:
+					op = ssa.OpSignExt16to32
+				case 28:
+					op = ssa.OpSignExt16to64
+				case 48:
+					op = ssa.OpSignExt32to64
+				default:
+					s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
+				}
+			} else {
+				// zero extension
+				switch 10*ft.Size() + tt.Size() {
+				case 12:
+					op = ssa.OpZeroExt8to16
+				case 14:
+					op = ssa.OpZeroExt8to32
+				case 18:
+					op = ssa.OpZeroExt8to64
+				case 24:
+					op = ssa.OpZeroExt16to32
+				case 28:
+					op = ssa.OpZeroExt16to64
+				case 48:
+					op = ssa.OpZeroExt32to64
+				default:
+					s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
+				}
+			}
+			return s.newValue1(op, n.Type, x)
+		}
+
+		if ft.IsFloat() || tt.IsFloat() {
+			conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
+			if !ok {
+				s.Fatalf("weird float conversion %s -> %s", ft, tt)
+			}
+			op1, op2, it := conv.op1, conv.op2, conv.intermediateType
+
+			if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
+				// normal case, not tripping over unsigned 64
+				if op1 == ssa.OpCopy {
+					if op2 == ssa.OpCopy {
+						return x
+					}
+					return s.newValue1(op2, n.Type, x)
+				}
+				if op2 == ssa.OpCopy {
+					return s.newValue1(op1, n.Type, x)
+				}
+				return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
+			}
+			// Tricky 64-bit unsigned cases.
+			if ft.IsInteger() {
+				// therefore tt is float32 or float64, and ft is also unsigned
+				if tt.Size() == 4 {
+					return s.uint64Tofloat32(n, x, ft, tt)
+				}
+				if tt.Size() == 8 {
+					return s.uint64Tofloat64(n, x, ft, tt)
+				}
+				s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
+			}
+			// therefore ft is float32 or float64, and tt is unsigned integer
+			if ft.Size() == 4 {
+				return s.float32ToUint64(n, x, ft, tt)
+			}
+			if ft.Size() == 8 {
+				return s.float64ToUint64(n, x, ft, tt)
+			}
+			s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
+			return nil
+		}
+
+		if ft.IsComplex() && tt.IsComplex() {
+			var op ssa.Op
+			if ft.Size() == tt.Size() {
+				op = ssa.OpCopy
+			} else if ft.Size() == 8 && tt.Size() == 16 {
+				op = ssa.OpCvt32Fto64F
+			} else if ft.Size() == 16 && tt.Size() == 8 {
+				op = ssa.OpCvt64Fto32F
+			} else {
+				s.Fatalf("weird complex conversion %s -> %s", ft, tt)
+			}
+			ftp := floatForComplex(ft)
+			ttp := floatForComplex(tt)
+			return s.newValue2(ssa.OpComplexMake, tt,
+				s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
+				s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
+		}
+
+		s.Unimplementedf("unhandled OCONV %s -> %s", n.Left.Type.Etype, n.Type.Etype)
+		return nil
+
+	case ODOTTYPE:
+		res, _ := s.dottype(n, false)
+		return res
+
+	// binary ops
+	case OLT, OEQ, ONE, OLE, OGE, OGT:
+		a := s.expr(n.Left)
+		b := s.expr(n.Right)
+		if n.Left.Type.IsComplex() {
+			pt := floatForComplex(n.Left.Type)
+			op := s.ssaOp(OEQ, pt)
+			r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
+			i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
+			c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
+			switch n.Op {
+			case OEQ:
+				return c
+			case ONE:
+				return s.newValue1(ssa.OpNot, Types[TBOOL], c)
+			default:
+				s.Fatalf("ordered complex compare %s", n.Op)
+			}
+		}
+		return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
+	case OMUL:
+		a := s.expr(n.Left)
+		b := s.expr(n.Right)
+		if n.Type.IsComplex() {
+			mulop := ssa.OpMul64F
+			addop := ssa.OpAdd64F
+			subop := ssa.OpSub64F
+			pt := floatForComplex(n.Type) // Could be Float32 or Float64
+			wt := Types[TFLOAT64]         // Compute in Float64 to minimize cancelation error
+
+			areal := s.newValue1(ssa.OpComplexReal, pt, a)
+			breal := s.newValue1(ssa.OpComplexReal, pt, b)
+			aimag := s.newValue1(ssa.OpComplexImag, pt, a)
+			bimag := s.newValue1(ssa.OpComplexImag, pt, b)
+
+			if pt != wt { // Widen for calculation
+				areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
+				breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
+				aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
+				bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
+			}
+
+			xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
+			ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
+
+			if pt != wt { // Narrow to store back
+				xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
+				ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
+			}
+
+			return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
+		}
+		return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+
+	case ODIV:
+		a := s.expr(n.Left)
+		b := s.expr(n.Right)
+		if n.Type.IsComplex() {
+			// TODO this is not executed because the front-end substitutes a runtime call.
+			// That probably ought to change; with modest optimization the widen/narrow
+			// conversions could all be elided in larger expression trees.
+			mulop := ssa.OpMul64F
+			addop := ssa.OpAdd64F
+			subop := ssa.OpSub64F
+			divop := ssa.OpDiv64F
+			pt := floatForComplex(n.Type) // Could be Float32 or Float64
+			wt := Types[TFLOAT64]         // Compute in Float64 to minimize cancelation error
+
+			areal := s.newValue1(ssa.OpComplexReal, pt, a)
+			breal := s.newValue1(ssa.OpComplexReal, pt, b)
+			aimag := s.newValue1(ssa.OpComplexImag, pt, a)
+			bimag := s.newValue1(ssa.OpComplexImag, pt, b)
+
+			if pt != wt { // Widen for calculation
+				areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
+				breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
+				aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
+				bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
+			}
+
+			denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
+			xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
+			ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
+
+			// TODO not sure if this is best done in wide precision or narrow
+			// Double-rounding might be an issue.
+			// Note that the pre-SSA implementation does the entire calculation
+			// in wide format, so wide is compatible.
+			xreal = s.newValue2(divop, wt, xreal, denom)
+			ximag = s.newValue2(divop, wt, ximag, denom)
+
+			if pt != wt { // Narrow to store back
+				xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
+				ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
+			}
+			return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
+		}
+		if n.Type.IsFloat() {
+			return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+		} else {
+			// do a size-appropriate check for zero
+			cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
+			s.check(cmp, panicdivide)
+			return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+		}
+	case OMOD:
+		a := s.expr(n.Left)
+		b := s.expr(n.Right)
+		// do a size-appropriate check for zero
+		cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
+		s.check(cmp, panicdivide)
+		return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+	case OADD, OSUB:
+		a := s.expr(n.Left)
+		b := s.expr(n.Right)
+		if n.Type.IsComplex() {
+			pt := floatForComplex(n.Type)
+			op := s.ssaOp(n.Op, pt)
+			return s.newValue2(ssa.OpComplexMake, n.Type,
+				s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
+				s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
+		}
+		return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+	case OAND, OOR, OHMUL, OXOR:
+		a := s.expr(n.Left)
+		b := s.expr(n.Right)
+		return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+	case OLSH, ORSH:
+		a := s.expr(n.Left)
+		b := s.expr(n.Right)
+		return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
+	case OLROT:
+		a := s.expr(n.Left)
+		i := n.Right.Int64()
+		if i <= 0 || i >= n.Type.Size()*8 {
+			s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
+		}
+		return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
+	case OANDAND, OOROR:
+		// To implement OANDAND (and OOROR), we introduce a
+		// new temporary variable to hold the result. The
+		// variable is associated with the OANDAND node in the
+		// s.vars table (normally variables are only
+		// associated with ONAME nodes). We convert
+		//     A && B
+		// to
+		//     var = A
+		//     if var {
+		//         var = B
+		//     }
+		// Using var in the subsequent block introduces the
+		// necessary phi variable.
+		el := s.expr(n.Left)
+		s.vars[n] = el
+
+		b := s.endBlock()
+		b.Kind = ssa.BlockIf
+		b.SetControl(el)
+		// In theory, we should set b.Likely here based on context.
+		// However, gc only gives us likeliness hints
+		// in a single place, for plain OIF statements,
+		// and passing around context is finnicky, so don't bother for now.
+
+		bRight := s.f.NewBlock(ssa.BlockPlain)
+		bResult := s.f.NewBlock(ssa.BlockPlain)
+		if n.Op == OANDAND {
+			b.AddEdgeTo(bRight)
+			b.AddEdgeTo(bResult)
+		} else if n.Op == OOROR {
+			b.AddEdgeTo(bResult)
+			b.AddEdgeTo(bRight)
+		}
+
+		s.startBlock(bRight)
+		er := s.expr(n.Right)
+		s.vars[n] = er
+
+		b = s.endBlock()
+		b.AddEdgeTo(bResult)
+
+		s.startBlock(bResult)
+		return s.variable(n, Types[TBOOL])
+	case OCOMPLEX:
+		r := s.expr(n.Left)
+		i := s.expr(n.Right)
+		return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
+
+	// unary ops
+	case OMINUS:
+		a := s.expr(n.Left)
+		if n.Type.IsComplex() {
+			tp := floatForComplex(n.Type)
+			negop := s.ssaOp(n.Op, tp)
+			return s.newValue2(ssa.OpComplexMake, n.Type,
+				s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
+				s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
+		}
+		return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
+	case ONOT, OCOM, OSQRT:
+		a := s.expr(n.Left)
+		return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
+	case OIMAG, OREAL:
+		a := s.expr(n.Left)
+		return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
+	case OPLUS:
+		return s.expr(n.Left)
+
+	case OADDR:
+		a, _ := s.addr(n.Left, n.Bounded)
+		// Note we know the volatile result is false because you can't write &f() in Go.
+		return a
+
+	case OINDREG:
+		if int(n.Reg) != Thearch.REGSP {
+			s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
+			return nil
+		}
+		addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
+		return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
+
+	case OIND:
+		p := s.exprPtr(n.Left, false, n.Lineno)
+		return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
+
+	case ODOT:
+		t := n.Left.Type
+		if canSSAType(t) {
+			v := s.expr(n.Left)
+			return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v)
+		}
+		p, _ := s.addr(n, false)
+		return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
+
+	case ODOTPTR:
+		p := s.exprPtr(n.Left, false, n.Lineno)
+		p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
+		return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
+
+	case OINDEX:
+		switch {
+		case n.Left.Type.IsString():
+			a := s.expr(n.Left)
+			i := s.expr(n.Right)
+			i = s.extendIndex(i)
+			if !n.Bounded {
+				len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
+				s.boundsCheck(i, len)
+			}
+			ptrtyp := Ptrto(Types[TUINT8])
+			ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
+			if Isconst(n.Right, CTINT) {
+				ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64(), ptr)
+			} else {
+				ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
+			}
+			return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
+		case n.Left.Type.IsSlice():
+			p, _ := s.addr(n, false)
+			return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
+		case n.Left.Type.IsArray():
+			// TODO: fix when we can SSA arrays of length 1.
+			p, _ := s.addr(n, false)
+			return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
+		default:
+			s.Fatalf("bad type for index %v", n.Left.Type)
+			return nil
+		}
+
+	case OLEN, OCAP:
+		switch {
+		case n.Left.Type.IsSlice():
+			op := ssa.OpSliceLen
+			if n.Op == OCAP {
+				op = ssa.OpSliceCap
+			}
+			return s.newValue1(op, Types[TINT], s.expr(n.Left))
+		case n.Left.Type.IsString(): // string; not reachable for OCAP
+			return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
+		case n.Left.Type.IsMap(), n.Left.Type.IsChan():
+			return s.referenceTypeBuiltin(n, s.expr(n.Left))
+		default: // array
+			return s.constInt(Types[TINT], n.Left.Type.NumElem())
+		}
+
+	case OSPTR:
+		a := s.expr(n.Left)
+		if n.Left.Type.IsSlice() {
+			return s.newValue1(ssa.OpSlicePtr, n.Type, a)
+		} else {
+			return s.newValue1(ssa.OpStringPtr, n.Type, a)
+		}
+
+	case OITAB:
+		a := s.expr(n.Left)
+		return s.newValue1(ssa.OpITab, n.Type, a)
+
+	case OEFACE:
+		tab := s.expr(n.Left)
+		data := s.expr(n.Right)
+		// The frontend allows putting things like struct{*byte} in
+		// the data portion of an eface. But we don't want struct{*byte}
+		// as a register type because (among other reasons) the liveness
+		// analysis is confused by the "fat" variables that result from
+		// such types being spilled.
+		// So here we ensure that we are selecting the underlying pointer
+		// when we build an eface.
+		// TODO: get rid of this now that structs can be SSA'd?
+		for !data.Type.IsPtrShaped() {
+			switch {
+			case data.Type.IsArray():
+				data = s.newValue1I(ssa.OpArrayIndex, data.Type.ElemType(), 0, data)
+			case data.Type.IsStruct():
+				for i := data.Type.NumFields() - 1; i >= 0; i-- {
+					f := data.Type.FieldType(i)
+					if f.Size() == 0 {
+						// eface type could also be struct{p *byte; q [0]int}
+						continue
+					}
+					data = s.newValue1I(ssa.OpStructSelect, f, int64(i), data)
+					break
+				}
+			default:
+				s.Fatalf("type being put into an eface isn't a pointer")
+			}
+		}
+		return s.newValue2(ssa.OpIMake, n.Type, tab, data)
+
+	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
+		v := s.expr(n.Left)
+		var i, j, k *ssa.Value
+		low, high, max := n.SliceBounds()
+		if low != nil {
+			i = s.extendIndex(s.expr(low))
+		}
+		if high != nil {
+			j = s.extendIndex(s.expr(high))
+		}
+		if max != nil {
+			k = s.extendIndex(s.expr(max))
+		}
+		p, l, c := s.slice(n.Left.Type, v, i, j, k)
+		return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
+
+	case OSLICESTR:
+		v := s.expr(n.Left)
+		var i, j *ssa.Value
+		low, high, _ := n.SliceBounds()
+		if low != nil {
+			i = s.extendIndex(s.expr(low))
+		}
+		if high != nil {
+			j = s.extendIndex(s.expr(high))
+		}
+		p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
+		return s.newValue2(ssa.OpStringMake, n.Type, p, l)
+
+	case OCALLFUNC:
+		if isIntrinsicCall1(n) {
+			return s.intrinsicCall1(n)
+		}
+		fallthrough
+
+	case OCALLINTER, OCALLMETH:
+		a := s.call(n, callNormal)
+		return s.newValue2(ssa.OpLoad, n.Type, a, s.mem())
+
+	case OGETG:
+		return s.newValue1(ssa.OpGetG, n.Type, s.mem())
+
+	case OAPPEND:
+		return s.append(n, false)
+
+	default:
+		s.Unimplementedf("unhandled expr %s", n.Op)
+		return nil
+	}
+}
+
+// append converts an OAPPEND node to SSA.
+// If inplace is false, it converts the OAPPEND expression n to an ssa.Value,
+// adds it to s, and returns the Value.
+// If inplace is true, it writes the result of the OAPPEND expression n
+// back to the slice being appended to, and returns nil.
+// inplace MUST be set to false if the slice can be SSA'd.
+func (s *state) append(n *Node, inplace bool) *ssa.Value {
+	// If inplace is false, process as expression "append(s, e1, e2, e3)":
+	//
+	// ptr, len, cap := s
+	// newlen := len + 3
+	// if newlen > cap {
+	//     ptr, len, cap = growslice(s, newlen)
+	//     newlen = len + 3 // recalculate to avoid a spill
+	// }
+	// // with write barriers, if needed:
+	// *(ptr+len) = e1
+	// *(ptr+len+1) = e2
+	// *(ptr+len+2) = e3
+	// return makeslice(ptr, newlen, cap)
+	//
+	//
+	// If inplace is true, process as statement "s = append(s, e1, e2, e3)":
+	//
+	// a := &s
+	// ptr, len, cap := s
+	// newlen := len + 3
+	// if newlen > cap {
+	//    newptr, len, newcap = growslice(ptr, len, cap, newlen)
+	//    vardef(a)       // if necessary, advise liveness we are writing a new a
+	//    *a.cap = newcap // write before ptr to avoid a spill
+	//    *a.ptr = newptr // with write barrier
+	// }
+	// newlen = len + 3 // recalculate to avoid a spill
+	// *a.len = newlen
+	// // with write barriers, if needed:
+	// *(ptr+len) = e1
+	// *(ptr+len+1) = e2
+	// *(ptr+len+2) = e3
+
+	et := n.Type.Elem()
+	pt := Ptrto(et)
+
+	// Evaluate slice
+	sn := n.List.First() // the slice node is the first in the list
+
+	var slice, addr *ssa.Value
+	if inplace {
+		addr, _ = s.addr(sn, false)
+		slice = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
+	} else {
+		slice = s.expr(sn)
+	}
+
+	// Allocate new blocks
+	grow := s.f.NewBlock(ssa.BlockPlain)
+	assign := s.f.NewBlock(ssa.BlockPlain)
+
+	// Decide if we need to grow
+	nargs := int64(n.List.Len() - 1)
+	p := s.newValue1(ssa.OpSlicePtr, pt, slice)
+	l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
+	c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
+	nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
+
+	cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
+	s.vars[&ptrVar] = p
+
+	if !inplace {
+		s.vars[&newlenVar] = nl
+		s.vars[&capVar] = c
+	} else {
+		s.vars[&lenVar] = l
+	}
+
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.Likely = ssa.BranchUnlikely
+	b.SetControl(cmp)
+	b.AddEdgeTo(grow)
+	b.AddEdgeTo(assign)
+
+	// Call growslice
+	s.startBlock(grow)
+	taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(n.Type.Elem())}, s.sb)
+
+	r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
+
+	if inplace {
+		if sn.Op == ONAME {
+			// Tell liveness we're about to build a new slice
+			s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, sn, s.mem())
+		}
+		capaddr := s.newValue1I(ssa.OpOffPtr, pt, int64(Array_cap), addr)
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capaddr, r[2], s.mem())
+		s.insertWBstore(pt, addr, r[0], n.Lineno, 0)
+		// load the value we just stored to avoid having to spill it
+		s.vars[&ptrVar] = s.newValue2(ssa.OpLoad, pt, addr, s.mem())
+		s.vars[&lenVar] = r[1] // avoid a spill in the fast path
+	} else {
+		s.vars[&ptrVar] = r[0]
+		s.vars[&newlenVar] = s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], r[1], s.constInt(Types[TINT], nargs))
+		s.vars[&capVar] = r[2]
+	}
+
+	b = s.endBlock()
+	b.AddEdgeTo(assign)
+
+	// assign new elements to slots
+	s.startBlock(assign)
+
+	if inplace {
+		l = s.variable(&lenVar, Types[TINT]) // generates phi for len
+		nl = s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
+		lenaddr := s.newValue1I(ssa.OpOffPtr, pt, int64(Array_nel), addr)
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenaddr, nl, s.mem())
+	}
+
+	// Evaluate args
+	type argRec struct {
+		// if store is true, we're appending the value v.  If false, we're appending the
+		// value at *v.  If store==false, isVolatile reports whether the source
+		// is in the outargs section of the stack frame.
+		v          *ssa.Value
+		store      bool
+		isVolatile bool
+	}
+	args := make([]argRec, 0, nargs)
+	for _, n := range n.List.Slice()[1:] {
+		if canSSAType(n.Type) {
+			args = append(args, argRec{v: s.expr(n), store: true})
+		} else {
+			v, isVolatile := s.addr(n, false)
+			args = append(args, argRec{v: v, isVolatile: isVolatile})
+		}
+	}
+
+	p = s.variable(&ptrVar, pt) // generates phi for ptr
+	if !inplace {
+		nl = s.variable(&newlenVar, Types[TINT]) // generates phi for nl
+		c = s.variable(&capVar, Types[TINT])     // generates phi for cap
+	}
+	p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
+	// TODO: just one write barrier call for all of these writes?
+	// TODO: maybe just one writeBarrier.enabled check?
+	for i, arg := range args {
+		addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
+		if arg.store {
+			if haspointers(et) {
+				s.insertWBstore(et, addr, arg.v, n.Lineno, 0)
+			} else {
+				s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg.v, s.mem())
+			}
+		} else {
+			if haspointers(et) {
+				s.insertWBmove(et, addr, arg.v, n.Lineno, arg.isVolatile)
+			} else {
+				s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg.v, s.mem())
+			}
+		}
+	}
+
+	delete(s.vars, &ptrVar)
+	if inplace {
+		delete(s.vars, &lenVar)
+		return nil
+	}
+	delete(s.vars, &newlenVar)
+	delete(s.vars, &capVar)
+	// make result
+	return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
+}
+
+// condBranch evaluates the boolean expression cond and branches to yes
+// if cond is true and no if cond is false.
+// This function is intended to handle && and || better than just calling
+// s.expr(cond) and branching on the result.
+func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
+	if cond.Op == OANDAND {
+		mid := s.f.NewBlock(ssa.BlockPlain)
+		s.stmtList(cond.Ninit)
+		s.condBranch(cond.Left, mid, no, max8(likely, 0))
+		s.startBlock(mid)
+		s.condBranch(cond.Right, yes, no, likely)
+		return
+		// Note: if likely==1, then both recursive calls pass 1.
+		// If likely==-1, then we don't have enough information to decide
+		// whether the first branch is likely or not. So we pass 0 for
+		// the likeliness of the first branch.
+		// TODO: have the frontend give us branch prediction hints for
+		// OANDAND and OOROR nodes (if it ever has such info).
+	}
+	if cond.Op == OOROR {
+		mid := s.f.NewBlock(ssa.BlockPlain)
+		s.stmtList(cond.Ninit)
+		s.condBranch(cond.Left, yes, mid, min8(likely, 0))
+		s.startBlock(mid)
+		s.condBranch(cond.Right, yes, no, likely)
+		return
+		// Note: if likely==-1, then both recursive calls pass -1.
+		// If likely==1, then we don't have enough info to decide
+		// the likelihood of the first branch.
+	}
+	if cond.Op == ONOT {
+		s.stmtList(cond.Ninit)
+		s.condBranch(cond.Left, no, yes, -likely)
+		return
+	}
+	c := s.expr(cond)
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.SetControl(c)
+	b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
+	b.AddEdgeTo(yes)
+	b.AddEdgeTo(no)
+}
+
+type skipMask uint8
+
+const (
+	skipPtr skipMask = 1 << iota
+	skipLen
+	skipCap
+)
+
+// assign does left = right.
+// Right has already been evaluated to ssa, left has not.
+// If deref is true, then we do left = *right instead (and right has already been nil-checked).
+// If deref is true and right == nil, just do left = 0.
+// If deref is true, rightIsVolatile reports whether right points to volatile (clobbered by a call) storage.
+// Include a write barrier if wb is true.
+// skip indicates assignments (at the top level) that can be avoided.
+func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, skip skipMask, rightIsVolatile bool) {
+	if left.Op == ONAME && isblank(left) {
+		return
+	}
+	t := left.Type
+	dowidth(t)
+	if s.canSSA(left) {
+		if deref {
+			s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
+		}
+		if left.Op == ODOT {
+			// We're assigning to a field of an ssa-able value.
+			// We need to build a new structure with the new value for the
+			// field we're assigning and the old values for the other fields.
+			// For instance:
+			//   type T struct {a, b, c int}
+			//   var T x
+			//   x.b = 5
+			// For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
+
+			// Grab information about the structure type.
+			t := left.Left.Type
+			nf := t.NumFields()
+			idx := fieldIdx(left)
+
+			// Grab old value of structure.
+			old := s.expr(left.Left)
+
+			// Make new structure.
+			new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
+
+			// Add fields as args.
+			for i := 0; i < nf; i++ {
+				if i == idx {
+					new.AddArg(right)
+				} else {
+					new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), int64(i), old))
+				}
+			}
+
+			// Recursively assign the new value we've made to the base of the dot op.
+			s.assign(left.Left, new, false, false, line, 0, rightIsVolatile)
+			// TODO: do we need to update named values here?
+			return
+		}
+		// Update variable assignment.
+		s.vars[left] = right
+		s.addNamedValue(left, right)
+		return
+	}
+	// Left is not ssa-able. Compute its address.
+	addr, _ := s.addr(left, false)
+	if left.Op == ONAME && skip == 0 {
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
+	}
+	if deref {
+		// Treat as a mem->mem move.
+		if right == nil {
+			s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
+			return
+		}
+		if wb {
+			s.insertWBmove(t, addr, right, line, rightIsVolatile)
+			return
+		}
+		s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
+		return
+	}
+	// Treat as a store.
+	if wb {
+		if skip&skipPtr != 0 {
+			// Special case: if we don't write back the pointers, don't bother
+			// doing the write barrier check.
+			s.storeTypeScalars(t, addr, right, skip)
+			return
+		}
+		s.insertWBstore(t, addr, right, line, skip)
+		return
+	}
+	if skip != 0 {
+		if skip&skipPtr == 0 {
+			s.storeTypePtrs(t, addr, right)
+		}
+		s.storeTypeScalars(t, addr, right, skip)
+		return
+	}
+	s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
+}
+
+// zeroVal returns the zero value for type t.
+func (s *state) zeroVal(t *Type) *ssa.Value {
+	switch {
+	case t.IsInteger():
+		switch t.Size() {
+		case 1:
+			return s.constInt8(t, 0)
+		case 2:
+			return s.constInt16(t, 0)
+		case 4:
+			return s.constInt32(t, 0)
+		case 8:
+			return s.constInt64(t, 0)
+		default:
+			s.Fatalf("bad sized integer type %s", t)
+		}
+	case t.IsFloat():
+		switch t.Size() {
+		case 4:
+			return s.constFloat32(t, 0)
+		case 8:
+			return s.constFloat64(t, 0)
+		default:
+			s.Fatalf("bad sized float type %s", t)
+		}
+	case t.IsComplex():
+		switch t.Size() {
+		case 8:
+			z := s.constFloat32(Types[TFLOAT32], 0)
+			return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
+		case 16:
+			z := s.constFloat64(Types[TFLOAT64], 0)
+			return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
+		default:
+			s.Fatalf("bad sized complex type %s", t)
+		}
+
+	case t.IsString():
+		return s.constEmptyString(t)
+	case t.IsPtrShaped():
+		return s.constNil(t)
+	case t.IsBoolean():
+		return s.constBool(false)
+	case t.IsInterface():
+		return s.constInterface(t)
+	case t.IsSlice():
+		return s.constSlice(t)
+	case t.IsStruct():
+		n := t.NumFields()
+		v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
+		for i := 0; i < n; i++ {
+			v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
+		}
+		return v
+	}
+	s.Unimplementedf("zero for type %v not implemented", t)
+	return nil
+}
+
+type callKind int8
+
+const (
+	callNormal callKind = iota
+	callDefer
+	callGo
+)
+
+// isSSAIntrinsic1 returns true if n is a call to a recognized 1-arg intrinsic
+// that can be handled by the SSA backend.
+// SSA uses this, but so does the front end to see if should not
+// inline a function because it is a candidate for intrinsic
+// substitution.
+func isSSAIntrinsic1(s *Sym) bool {
+	// The test below is not quite accurate -- in the event that
+	// a function is disabled on a per-function basis, for example
+	// because of hash-keyed binary failure search, SSA might be
+	// disabled for that function but it would not be noted here,
+	// and thus an inlining would not occur (in practice, inlining
+	// so far has only been noticed for Bswap32 and the 16-bit count
+	// leading/trailing instructions, but heuristics might change
+	// in the future or on different architectures).
+	if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.LinkArch.Family != sys.AMD64 {
+		return false
+	}
+	if s != nil && s.Pkg != nil && s.Pkg.Path == "runtime/internal/sys" {
+		switch s.Name {
+		case
+			"Ctz64", "Ctz32", "Ctz16",
+			"Bswap64", "Bswap32":
+			return true
+		}
+	}
+	return false
+}
+
+func isIntrinsicCall1(n *Node) bool {
+	if n == nil || n.Left == nil {
+		return false
+	}
+	return isSSAIntrinsic1(n.Left.Sym)
+}
+
+// intrinsicFirstArg extracts arg from n.List and eval
+func (s *state) intrinsicFirstArg(n *Node) *ssa.Value {
+	x := n.List.First()
+	if x.Op == OAS {
+		x = x.Right
+	}
+	return s.expr(x)
+}
+
+// intrinsicCall1 converts a call to a recognized 1-arg intrinsic
+// into the intrinsic
+func (s *state) intrinsicCall1(n *Node) *ssa.Value {
+	var result *ssa.Value
+	switch n.Left.Sym.Name {
+	case "Ctz64":
+		result = s.newValue1(ssa.OpCtz64, Types[TUINT64], s.intrinsicFirstArg(n))
+	case "Ctz32":
+		result = s.newValue1(ssa.OpCtz32, Types[TUINT32], s.intrinsicFirstArg(n))
+	case "Ctz16":
+		result = s.newValue1(ssa.OpCtz16, Types[TUINT16], s.intrinsicFirstArg(n))
+	case "Bswap64":
+		result = s.newValue1(ssa.OpBswap64, Types[TUINT64], s.intrinsicFirstArg(n))
+	case "Bswap32":
+		result = s.newValue1(ssa.OpBswap32, Types[TUINT32], s.intrinsicFirstArg(n))
+	}
+	if result == nil {
+		Fatalf("Unknown special call: %v", n.Left.Sym)
+	}
+	if ssa.IntrinsicsDebug > 0 {
+		Warnl(n.Lineno, "intrinsic substitution for %v with %s", n.Left.Sym.Name, result.LongString())
+	}
+	return result
+}
+
+// Calls the function n using the specified call type.
+// Returns the address of the return value (or nil if none).
+func (s *state) call(n *Node, k callKind) *ssa.Value {
+	var sym *Sym           // target symbol (if static)
+	var closure *ssa.Value // ptr to closure to run (if dynamic)
+	var codeptr *ssa.Value // ptr to target code (if dynamic)
+	var rcvr *ssa.Value    // receiver to set
+	fn := n.Left
+	switch n.Op {
+	case OCALLFUNC:
+		if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
+			sym = fn.Sym
+			break
+		}
+		closure = s.expr(fn)
+	case OCALLMETH:
+		if fn.Op != ODOTMETH {
+			Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
+		}
+		if k == callNormal {
+			sym = fn.Sym
+			break
+		}
+		n2 := newname(fn.Sym)
+		n2.Class = PFUNC
+		n2.Lineno = fn.Lineno
+		closure = s.expr(n2)
+		// Note: receiver is already assigned in n.List, so we don't
+		// want to set it here.
+	case OCALLINTER:
+		if fn.Op != ODOTINTER {
+			Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
+		}
+		i := s.expr(fn.Left)
+		itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
+		if k != callNormal {
+			s.nilCheck(itab)
+		}
+		itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
+		itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
+		if k == callNormal {
+			codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
+		} else {
+			closure = itab
+		}
+		rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
+	}
+	dowidth(fn.Type)
+	stksize := fn.Type.ArgWidth() // includes receiver
+
+	// Run all argument assignments. The arg slots have already
+	// been offset by the appropriate amount (+2*widthptr for go/defer,
+	// +widthptr for interface calls).
+	// For OCALLMETH, the receiver is set in these statements.
+	s.stmtList(n.List)
+
+	// Set receiver (for interface calls)
+	if rcvr != nil {
+		argStart := Ctxt.FixedFrameSize()
+		if k != callNormal {
+			argStart += int64(2 * Widthptr)
+		}
+		addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
+	}
+
+	// Defer/go args
+	if k != callNormal {
+		// Write argsize and closure (args to Newproc/Deferproc).
+		argsize := s.constInt32(Types[TUINT32], int32(stksize))
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
+		addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
+		stksize += 2 * int64(Widthptr)
+	}
+
+	// call target
+	bNext := s.f.NewBlock(ssa.BlockPlain)
+	var call *ssa.Value
+	switch {
+	case k == callDefer:
+		call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
+	case k == callGo:
+		call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
+	case closure != nil:
+		codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
+		call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
+	case codeptr != nil:
+		call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
+	case sym != nil:
+		call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
+	default:
+		Fatalf("bad call type %s %v", n.Op, n)
+	}
+	call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
+
+	// Finish call block
+	s.vars[&memVar] = call
+	b := s.endBlock()
+	b.Kind = ssa.BlockCall
+	b.SetControl(call)
+	b.AddEdgeTo(bNext)
+	if k == callDefer {
+		// Add recover edge to exit code.
+		b.Kind = ssa.BlockDefer
+		r := s.f.NewBlock(ssa.BlockPlain)
+		s.startBlock(r)
+		s.exit()
+		b.AddEdgeTo(r)
+		b.Likely = ssa.BranchLikely
+	}
+
+	// Start exit block, find address of result.
+	s.startBlock(bNext)
+	// Keep input pointer args live across calls.  This is a bandaid until 1.8.
+	for _, n := range s.ptrargs {
+		s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
+	}
+	res := n.Left.Type.Results()
+	if res.NumFields() == 0 || k != callNormal {
+		// call has no return value. Continue with the next statement.
+		return nil
+	}
+	fp := res.Field(0)
+	return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Offset+Ctxt.FixedFrameSize(), s.sp)
+}
+
+// etypesign returns the signed-ness of e, for integer/pointer etypes.
+// -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
+func etypesign(e EType) int8 {
+	switch e {
+	case TINT8, TINT16, TINT32, TINT64, TINT:
+		return -1
+	case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
+		return +1
+	}
+	return 0
+}
+
+// lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
+// This improves the effectiveness of cse by using the same Aux values for the
+// same symbols.
+func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
+	switch sym.(type) {
+	default:
+		s.Fatalf("sym %v is of uknown type %T", sym, sym)
+	case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
+		// these are the only valid types
+	}
+
+	if lsym, ok := s.varsyms[n]; ok {
+		return lsym
+	} else {
+		s.varsyms[n] = sym
+		return sym
+	}
+}
+
+// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
+// Also returns a bool reporting whether the returned value is "volatile", that is it
+// points to the outargs section and thus the referent will be clobbered by any call.
+// The value that the returned Value represents is guaranteed to be non-nil.
+// If bounded is true then this address does not require a nil check for its operand
+// even if that would otherwise be implied.
+func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) {
+	t := Ptrto(n.Type)
+	switch n.Op {
+	case ONAME:
+		switch n.Class {
+		case PEXTERN:
+			// global variable
+			aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Sym})
+			v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
+			// TODO: Make OpAddr use AuxInt as well as Aux.
+			if n.Xoffset != 0 {
+				v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
+			}
+			return v, false
+		case PPARAM:
+			// parameter slot
+			v := s.decladdrs[n]
+			if v != nil {
+				return v, false
+			}
+			if n.String() == ".fp" {
+				// Special arg that points to the frame pointer.
+				// (Used by the race detector, others?)
+				aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
+				return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp), false
+			}
+			s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
+			return nil, false
+		case PAUTO:
+			aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
+			return s.newValue1A(ssa.OpAddr, t, aux, s.sp), false
+		case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
+			// ensure that we reuse symbols for out parameters so
+			// that cse works on their addresses
+			aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
+			return s.newValue1A(ssa.OpAddr, t, aux, s.sp), false
+		default:
+			s.Unimplementedf("variable address class %v not implemented", classnames[n.Class])
+			return nil, false
+		}
+	case OINDREG:
+		// indirect off a register
+		// used for storing/loading arguments/returns to/from callees
+		if int(n.Reg) != Thearch.REGSP {
+			s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
+			return nil, false
+		}
+		return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp), true
+	case OINDEX:
+		if n.Left.Type.IsSlice() {
+			a := s.expr(n.Left)
+			i := s.expr(n.Right)
+			i = s.extendIndex(i)
+			len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
+			if !n.Bounded {
+				s.boundsCheck(i, len)
+			}
+			p := s.newValue1(ssa.OpSlicePtr, t, a)
+			return s.newValue2(ssa.OpPtrIndex, t, p, i), false
+		} else { // array
+			a, isVolatile := s.addr(n.Left, bounded)
+			i := s.expr(n.Right)
+			i = s.extendIndex(i)
+			len := s.constInt(Types[TINT], n.Left.Type.NumElem())
+			if !n.Bounded {
+				s.boundsCheck(i, len)
+			}
+			return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i), isVolatile
+		}
+	case OIND:
+		return s.exprPtr(n.Left, bounded, n.Lineno), false
+	case ODOT:
+		p, isVolatile := s.addr(n.Left, bounded)
+		return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), isVolatile
+	case ODOTPTR:
+		p := s.exprPtr(n.Left, bounded, n.Lineno)
+		return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), false
+	case OCLOSUREVAR:
+		return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
+			s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8]))), false
+	case OCONVNOP:
+		addr, isVolatile := s.addr(n.Left, bounded)
+		return s.newValue1(ssa.OpCopy, t, addr), isVolatile // ensure that addr has the right type
+	case OCALLFUNC, OCALLINTER, OCALLMETH:
+		return s.call(n, callNormal), true
+
+	default:
+		s.Unimplementedf("unhandled addr %v", n.Op)
+		return nil, false
+	}
+}
+
+// canSSA reports whether n is SSA-able.
+// n must be an ONAME (or an ODOT sequence with an ONAME base).
+func (s *state) canSSA(n *Node) bool {
+	if Debug['N'] != 0 {
+		return false
+	}
+	for n.Op == ODOT {
+		n = n.Left
+	}
+	if n.Op != ONAME {
+		return false
+	}
+	if n.Addrtaken {
+		return false
+	}
+	if n.isParamHeapCopy() {
+		return false
+	}
+	if n.Class == PAUTOHEAP {
+		Fatalf("canSSA of PAUTOHEAP %v", n)
+	}
+	switch n.Class {
+	case PEXTERN:
+		return false
+	case PPARAMOUT:
+		if hasdefer {
+			// TODO: handle this case?  Named return values must be
+			// in memory so that the deferred function can see them.
+			// Maybe do: if !strings.HasPrefix(n.String(), "~") { return false }
+			return false
+		}
+		if s.cgoUnsafeArgs {
+			// Cgo effectively takes the address of all result args,
+			// but the compiler can't see that.
+			return false
+		}
+	}
+	if n.Class == PPARAM && n.String() == ".this" {
+		// wrappers generated by genwrapper need to update
+		// the .this pointer in place.
+		// TODO: treat as a PPARMOUT?
+		return false
+	}
+	return canSSAType(n.Type)
+	// TODO: try to make more variables SSAable?
+}
+
+// canSSA reports whether variables of type t are SSA-able.
+func canSSAType(t *Type) bool {
+	dowidth(t)
+	if t.Width > int64(4*Widthptr) {
+		// 4*Widthptr is an arbitrary constant. We want it
+		// to be at least 3*Widthptr so slices can be registerized.
+		// Too big and we'll introduce too much register pressure.
+		return false
+	}
+	switch t.Etype {
+	case TARRAY:
+		// We can't do arrays because dynamic indexing is
+		// not supported on SSA variables.
+		// TODO: maybe allow if length is <=1?  All indexes
+		// are constant?  Might be good for the arrays
+		// introduced by the compiler for variadic functions.
+		return false
+	case TSTRUCT:
+		if t.NumFields() > ssa.MaxStruct {
+			return false
+		}
+		for _, t1 := range t.Fields().Slice() {
+			if !canSSAType(t1.Type) {
+				return false
+			}
+		}
+		return true
+	default:
+		return true
+	}
+}
+
+// exprPtr evaluates n to a pointer and nil-checks it.
+func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
+	p := s.expr(n)
+	if bounded || n.NonNil {
+		if s.f.Config.Debug_checknil() && lineno > 1 {
+			s.f.Config.Warnl(lineno, "removed nil check")
+		}
+		return p
+	}
+	s.nilCheck(p)
+	return p
+}
+
+// nilCheck generates nil pointer checking code.
+// Starts a new block on return, unless nil checks are disabled.
+// Used only for automatically inserted nil checks,
+// not for user code like 'x != nil'.
+func (s *state) nilCheck(ptr *ssa.Value) {
+	if Disable_checknil != 0 {
+		return
+	}
+	chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
+	b := s.endBlock()
+	b.Kind = ssa.BlockCheck
+	b.SetControl(chk)
+	bNext := s.f.NewBlock(ssa.BlockPlain)
+	b.AddEdgeTo(bNext)
+	s.startBlock(bNext)
+}
+
+// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
+// Starts a new block on return.
+func (s *state) boundsCheck(idx, len *ssa.Value) {
+	if Debug['B'] != 0 {
+		return
+	}
+	// TODO: convert index to full width?
+	// TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
+
+	// bounds check
+	cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
+	s.check(cmp, Panicindex)
+}
+
+// sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
+// Starts a new block on return.
+func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
+	if Debug['B'] != 0 {
+		return
+	}
+	// TODO: convert index to full width?
+	// TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
+
+	// bounds check
+	cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
+	s.check(cmp, panicslice)
+}
+
+// If cmp (a bool) is true, panic using the given function.
+func (s *state) check(cmp *ssa.Value, fn *Node) {
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.SetControl(cmp)
+	b.Likely = ssa.BranchLikely
+	bNext := s.f.NewBlock(ssa.BlockPlain)
+	line := s.peekLine()
+	bPanic := s.panics[funcLine{fn, line}]
+	if bPanic == nil {
+		bPanic = s.f.NewBlock(ssa.BlockPlain)
+		s.panics[funcLine{fn, line}] = bPanic
+		s.startBlock(bPanic)
+		// The panic call takes/returns memory to ensure that the right
+		// memory state is observed if the panic happens.
+		s.rtcall(fn, false, nil)
+	}
+	b.AddEdgeTo(bNext)
+	b.AddEdgeTo(bPanic)
+	s.startBlock(bNext)
+}
+
+// rtcall issues a call to the given runtime function fn with the listed args.
+// Returns a slice of results of the given result types.
+// The call is added to the end of the current block.
+// If returns is false, the block is marked as an exit block.
+// If returns is true, the block is marked as a call block. A new block
+// is started to load the return values.
+func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
+	// Write args to the stack
+	var off int64 // TODO: arch-dependent starting offset?
+	for _, arg := range args {
+		t := arg.Type
+		off = Rnd(off, t.Alignment())
+		ptr := s.sp
+		if off != 0 {
+			ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
+		}
+		size := t.Size()
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
+		off += size
+	}
+	off = Rnd(off, int64(Widthptr))
+
+	// Issue call
+	call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
+	s.vars[&memVar] = call
+
+	// Finish block
+	b := s.endBlock()
+	if !returns {
+		b.Kind = ssa.BlockExit
+		b.SetControl(call)
+		call.AuxInt = off
+		if len(results) > 0 {
+			Fatalf("panic call can't have results")
+		}
+		return nil
+	}
+	b.Kind = ssa.BlockCall
+	b.SetControl(call)
+	bNext := s.f.NewBlock(ssa.BlockPlain)
+	b.AddEdgeTo(bNext)
+	s.startBlock(bNext)
+
+	// Keep input pointer args live across calls.  This is a bandaid until 1.8.
+	for _, n := range s.ptrargs {
+		s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
+	}
+
+	// Load results
+	res := make([]*ssa.Value, len(results))
+	for i, t := range results {
+		off = Rnd(off, t.Alignment())
+		ptr := s.sp
+		if off != 0 {
+			ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
+		}
+		res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
+		off += t.Size()
+	}
+	off = Rnd(off, int64(Widthptr))
+
+	// Remember how much callee stack space we needed.
+	call.AuxInt = off
+
+	return res
+}
+
+// insertWBmove inserts the assignment *left = *right including a write barrier.
+// t is the type being assigned.
+func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightIsVolatile bool) {
+	// if writeBarrier.enabled {
+	//   typedmemmove(&t, left, right)
+	// } else {
+	//   *left = *right
+	// }
+
+	if s.noWB {
+		s.Fatalf("write barrier prohibited")
+	}
+	if s.WBLineno == 0 {
+		s.WBLineno = left.Line
+	}
+	bThen := s.f.NewBlock(ssa.BlockPlain)
+	bElse := s.f.NewBlock(ssa.BlockPlain)
+	bEnd := s.f.NewBlock(ssa.BlockPlain)
+
+	aux := &ssa.ExternSymbol{Typ: Types[TBOOL], Sym: syslook("writeBarrier").Sym}
+	flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
+	// TODO: select the .enabled field. It is currently first, so not needed for now.
+	// Load word, test byte, avoiding partial register write from load byte.
+	flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
+	flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.Likely = ssa.BranchUnlikely
+	b.SetControl(flag)
+	b.AddEdgeTo(bThen)
+	b.AddEdgeTo(bElse)
+
+	s.startBlock(bThen)
+
+	if !rightIsVolatile {
+		// Issue typedmemmove call.
+		taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb)
+		s.rtcall(typedmemmove, true, nil, taddr, left, right)
+	} else {
+		// Copy to temp location if the source is volatile (will be clobbered by
+		// a function call).  Marshaling the args to typedmemmove might clobber the
+		// value we're trying to move.
+		tmp := temp(t)
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, tmp, s.mem())
+		tmpaddr, _ := s.addr(tmp, true)
+		s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), tmpaddr, right, s.mem())
+		// Issue typedmemmove call.
+		taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb)
+		s.rtcall(typedmemmove, true, nil, taddr, left, tmpaddr)
+		// Mark temp as dead.
+		s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, tmp, s.mem())
+	}
+	s.endBlock().AddEdgeTo(bEnd)
+
+	s.startBlock(bElse)
+	s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
+	s.endBlock().AddEdgeTo(bEnd)
+
+	s.startBlock(bEnd)
+
+	if Debug_wb > 0 {
+		Warnl(line, "write barrier")
+	}
+}
+
+// insertWBstore inserts the assignment *left = right including a write barrier.
+// t is the type being assigned.
+func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip skipMask) {
+	// store scalar fields
+	// if writeBarrier.enabled {
+	//   writebarrierptr for pointer fields
+	// } else {
+	//   store pointer fields
+	// }
+
+	if s.noWB {
+		s.Fatalf("write barrier prohibited")
+	}
+	if s.WBLineno == 0 {
+		s.WBLineno = left.Line
+	}
+	s.storeTypeScalars(t, left, right, skip)
+
+	bThen := s.f.NewBlock(ssa.BlockPlain)
+	bElse := s.f.NewBlock(ssa.BlockPlain)
+	bEnd := s.f.NewBlock(ssa.BlockPlain)
+
+	aux := &ssa.ExternSymbol{Typ: Types[TBOOL], Sym: syslook("writeBarrier").Sym}
+	flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
+	// TODO: select the .enabled field. It is currently first, so not needed for now.
+	// Load word, test byte, avoiding partial register write from load byte.
+	flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
+	flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.Likely = ssa.BranchUnlikely
+	b.SetControl(flag)
+	b.AddEdgeTo(bThen)
+	b.AddEdgeTo(bElse)
+
+	// Issue write barriers for pointer writes.
+	s.startBlock(bThen)
+	s.storeTypePtrsWB(t, left, right)
+	s.endBlock().AddEdgeTo(bEnd)
+
+	// Issue regular stores for pointer writes.
+	s.startBlock(bElse)
+	s.storeTypePtrs(t, left, right)
+	s.endBlock().AddEdgeTo(bEnd)
+
+	s.startBlock(bEnd)
+
+	if Debug_wb > 0 {
+		Warnl(line, "write barrier")
+	}
+}
+
+// do *left = right for all scalar (non-pointer) parts of t.
+func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value, skip skipMask) {
+	switch {
+	case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), left, right, s.mem())
+	case t.IsPtrShaped():
+		// no scalar fields.
+	case t.IsString():
+		if skip&skipLen != 0 {
+			return
+		}
+		len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
+		lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
+	case t.IsSlice():
+		if skip&skipLen == 0 {
+			len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
+			lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
+			s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
+		}
+		if skip&skipCap == 0 {
+			cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
+			capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
+			s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
+		}
+	case t.IsInterface():
+		// itab field doesn't need a write barrier (even though it is a pointer).
+		itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
+	case t.IsStruct():
+		n := t.NumFields()
+		for i := 0; i < n; i++ {
+			ft := t.FieldType(i)
+			addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
+			val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
+			s.storeTypeScalars(ft.(*Type), addr, val, 0)
+		}
+	default:
+		s.Fatalf("bad write barrier type %s", t)
+	}
+}
+
+// do *left = right for all pointer parts of t.
+func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
+	switch {
+	case t.IsPtrShaped():
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
+	case t.IsString():
+		ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
+	case t.IsSlice():
+		ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
+	case t.IsInterface():
+		// itab field is treated as a scalar.
+		idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
+		idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
+		s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
+	case t.IsStruct():
+		n := t.NumFields()
+		for i := 0; i < n; i++ {
+			ft := t.FieldType(i)
+			if !haspointers(ft.(*Type)) {
+				continue
+			}
+			addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
+			val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
+			s.storeTypePtrs(ft.(*Type), addr, val)
+		}
+	default:
+		s.Fatalf("bad write barrier type %s", t)
+	}
+}
+
+// do *left = right with a write barrier for all pointer parts of t.
+func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
+	switch {
+	case t.IsPtrShaped():
+		s.rtcall(writebarrierptr, true, nil, left, right)
+	case t.IsString():
+		ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
+		s.rtcall(writebarrierptr, true, nil, left, ptr)
+	case t.IsSlice():
+		ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
+		s.rtcall(writebarrierptr, true, nil, left, ptr)
+	case t.IsInterface():
+		idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
+		idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
+		s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
+	case t.IsStruct():
+		n := t.NumFields()
+		for i := 0; i < n; i++ {
+			ft := t.FieldType(i)
+			if !haspointers(ft.(*Type)) {
+				continue
+			}
+			addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
+			val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
+			s.storeTypePtrsWB(ft.(*Type), addr, val)
+		}
+	default:
+		s.Fatalf("bad write barrier type %s", t)
+	}
+}
+
+// slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
+// i,j,k may be nil, in which case they are set to their default value.
+// t is a slice, ptr to array, or string type.
+func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
+	var elemtype *Type
+	var ptrtype *Type
+	var ptr *ssa.Value
+	var len *ssa.Value
+	var cap *ssa.Value
+	zero := s.constInt(Types[TINT], 0)
+	switch {
+	case t.IsSlice():
+		elemtype = t.Elem()
+		ptrtype = Ptrto(elemtype)
+		ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
+		len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
+		cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
+	case t.IsString():
+		elemtype = Types[TUINT8]
+		ptrtype = Ptrto(elemtype)
+		ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
+		len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
+		cap = len
+	case t.IsPtr():
+		if !t.Elem().IsArray() {
+			s.Fatalf("bad ptr to array in slice %v\n", t)
+		}
+		elemtype = t.Elem().Elem()
+		ptrtype = Ptrto(elemtype)
+		s.nilCheck(v)
+		ptr = v
+		len = s.constInt(Types[TINT], t.Elem().NumElem())
+		cap = len
+	default:
+		s.Fatalf("bad type in slice %v\n", t)
+	}
+
+	// Set default values
+	if i == nil {
+		i = zero
+	}
+	if j == nil {
+		j = len
+	}
+	if k == nil {
+		k = cap
+	}
+
+	// Panic if slice indices are not in bounds.
+	s.sliceBoundsCheck(i, j)
+	if j != k {
+		s.sliceBoundsCheck(j, k)
+	}
+	if k != cap {
+		s.sliceBoundsCheck(k, cap)
+	}
+
+	// Generate the following code assuming that indexes are in bounds.
+	// The conditional is to make sure that we don't generate a slice
+	// that points to the next object in memory.
+	// rlen = j-i
+	// rcap = k-i
+	// delta = i*elemsize
+	// if rcap == 0 {
+	//    delta = 0
+	// }
+	// rptr = p+delta
+	// result = (SliceMake rptr rlen rcap)
+	subOp := s.ssaOp(OSUB, Types[TINT])
+	eqOp := s.ssaOp(OEQ, Types[TINT])
+	mulOp := s.ssaOp(OMUL, Types[TINT])
+	rlen := s.newValue2(subOp, Types[TINT], j, i)
+	var rcap *ssa.Value
+	switch {
+	case t.IsString():
+		// Capacity of the result is unimportant. However, we use
+		// rcap to test if we've generated a zero-length slice.
+		// Use length of strings for that.
+		rcap = rlen
+	case j == k:
+		rcap = rlen
+	default:
+		rcap = s.newValue2(subOp, Types[TINT], k, i)
+	}
+
+	// delta = # of elements to offset pointer by.
+	s.vars[&deltaVar] = i
+
+	// Generate code to set delta=0 if the resulting capacity is zero.
+	if !((i.Op == ssa.OpConst64 && i.AuxInt == 0) ||
+		(i.Op == ssa.OpConst32 && int32(i.AuxInt) == 0)) {
+		cmp := s.newValue2(eqOp, Types[TBOOL], rcap, zero)
+
+		b := s.endBlock()
+		b.Kind = ssa.BlockIf
+		b.Likely = ssa.BranchUnlikely
+		b.SetControl(cmp)
+
+		// Generate block which zeros the delta variable.
+		nz := s.f.NewBlock(ssa.BlockPlain)
+		b.AddEdgeTo(nz)
+		s.startBlock(nz)
+		s.vars[&deltaVar] = zero
+		s.endBlock()
+
+		// All done.
+		merge := s.f.NewBlock(ssa.BlockPlain)
+		b.AddEdgeTo(merge)
+		nz.AddEdgeTo(merge)
+		s.startBlock(merge)
+
+		// TODO: use conditional moves somehow?
+	}
+
+	// Compute rptr = ptr + delta * elemsize
+	rptr := s.newValue2(ssa.OpAddPtr, ptrtype, ptr, s.newValue2(mulOp, Types[TINT], s.variable(&deltaVar, Types[TINT]), s.constInt(Types[TINT], elemtype.Width)))
+	delete(s.vars, &deltaVar)
+	return rptr, rlen, rcap
+}
+
+type u2fcvtTab struct {
+	geq, cvt2F, and, rsh, or, add ssa.Op
+	one                           func(*state, ssa.Type, int64) *ssa.Value
+}
+
+var u64_f64 u2fcvtTab = u2fcvtTab{
+	geq:   ssa.OpGeq64,
+	cvt2F: ssa.OpCvt64to64F,
+	and:   ssa.OpAnd64,
+	rsh:   ssa.OpRsh64Ux64,
+	or:    ssa.OpOr64,
+	add:   ssa.OpAdd64F,
+	one:   (*state).constInt64,
+}
+
+var u64_f32 u2fcvtTab = u2fcvtTab{
+	geq:   ssa.OpGeq64,
+	cvt2F: ssa.OpCvt64to32F,
+	and:   ssa.OpAnd64,
+	rsh:   ssa.OpRsh64Ux64,
+	or:    ssa.OpOr64,
+	add:   ssa.OpAdd32F,
+	one:   (*state).constInt64,
+}
+
+// Excess generality on a machine with 64-bit integer registers.
+// Not used on AMD64.
+var u32_f32 u2fcvtTab = u2fcvtTab{
+	geq:   ssa.OpGeq32,
+	cvt2F: ssa.OpCvt32to32F,
+	and:   ssa.OpAnd32,
+	rsh:   ssa.OpRsh32Ux32,
+	or:    ssa.OpOr32,
+	add:   ssa.OpAdd32F,
+	one: func(s *state, t ssa.Type, x int64) *ssa.Value {
+		return s.constInt32(t, int32(x))
+	},
+}
+
+func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+	return s.uintTofloat(&u64_f64, n, x, ft, tt)
+}
+
+func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+	return s.uintTofloat(&u64_f32, n, x, ft, tt)
+}
+
+func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+	// if x >= 0 {
+	//    result = (floatY) x
+	// } else {
+	// 	  y = uintX(x) ; y = x & 1
+	// 	  z = uintX(x) ; z = z >> 1
+	// 	  z = z >> 1
+	// 	  z = z | y
+	// 	  result = floatY(z)
+	// 	  result = result + result
+	// }
+	//
+	// Code borrowed from old code generator.
+	// What's going on: large 64-bit "unsigned" looks like
+	// negative number to hardware's integer-to-float
+	// conversion. However, because the mantissa is only
+	// 63 bits, we don't need the LSB, so instead we do an
+	// unsigned right shift (divide by two), convert, and
+	// double. However, before we do that, we need to be
+	// sure that we do not lose a "1" if that made the
+	// difference in the resulting rounding. Therefore, we
+	// preserve it, and OR (not ADD) it back in. The case
+	// that matters is when the eleven discarded bits are
+	// equal to 10000000001; that rounds up, and the 1 cannot
+	// be lost else it would round down if the LSB of the
+	// candidate mantissa is 0.
+	cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.SetControl(cmp)
+	b.Likely = ssa.BranchLikely
+
+	bThen := s.f.NewBlock(ssa.BlockPlain)
+	bElse := s.f.NewBlock(ssa.BlockPlain)
+	bAfter := s.f.NewBlock(ssa.BlockPlain)
+
+	b.AddEdgeTo(bThen)
+	s.startBlock(bThen)
+	a0 := s.newValue1(cvttab.cvt2F, tt, x)
+	s.vars[n] = a0
+	s.endBlock()
+	bThen.AddEdgeTo(bAfter)
+
+	b.AddEdgeTo(bElse)
+	s.startBlock(bElse)
+	one := cvttab.one(s, ft, 1)
+	y := s.newValue2(cvttab.and, ft, x, one)
+	z := s.newValue2(cvttab.rsh, ft, x, one)
+	z = s.newValue2(cvttab.or, ft, z, y)
+	a := s.newValue1(cvttab.cvt2F, tt, z)
+	a1 := s.newValue2(cvttab.add, tt, a, a)
+	s.vars[n] = a1
+	s.endBlock()
+	bElse.AddEdgeTo(bAfter)
+
+	s.startBlock(bAfter)
+	return s.variable(n, n.Type)
+}
+
+// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
+func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
+	if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
+		s.Fatalf("node must be a map or a channel")
+	}
+	// if n == nil {
+	//   return 0
+	// } else {
+	//   // len
+	//   return *((*int)n)
+	//   // cap
+	//   return *(((*int)n)+1)
+	// }
+	lenType := n.Type
+	nilValue := s.constNil(Types[TUINTPTR])
+	cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.SetControl(cmp)
+	b.Likely = ssa.BranchUnlikely
+
+	bThen := s.f.NewBlock(ssa.BlockPlain)
+	bElse := s.f.NewBlock(ssa.BlockPlain)
+	bAfter := s.f.NewBlock(ssa.BlockPlain)
+
+	// length/capacity of a nil map/chan is zero
+	b.AddEdgeTo(bThen)
+	s.startBlock(bThen)
+	s.vars[n] = s.zeroVal(lenType)
+	s.endBlock()
+	bThen.AddEdgeTo(bAfter)
+
+	b.AddEdgeTo(bElse)
+	s.startBlock(bElse)
+	if n.Op == OLEN {
+		// length is stored in the first word for map/chan
+		s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
+	} else if n.Op == OCAP {
+		// capacity is stored in the second word for chan
+		sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
+		s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
+	} else {
+		s.Fatalf("op must be OLEN or OCAP")
+	}
+	s.endBlock()
+	bElse.AddEdgeTo(bAfter)
+
+	s.startBlock(bAfter)
+	return s.variable(n, lenType)
+}
+
+type f2uCvtTab struct {
+	ltf, cvt2U, subf ssa.Op
+	value            func(*state, ssa.Type, float64) *ssa.Value
+}
+
+var f32_u64 f2uCvtTab = f2uCvtTab{
+	ltf:   ssa.OpLess32F,
+	cvt2U: ssa.OpCvt32Fto64,
+	subf:  ssa.OpSub32F,
+	value: (*state).constFloat32,
+}
+
+var f64_u64 f2uCvtTab = f2uCvtTab{
+	ltf:   ssa.OpLess64F,
+	cvt2U: ssa.OpCvt64Fto64,
+	subf:  ssa.OpSub64F,
+	value: (*state).constFloat64,
+}
+
+func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+	return s.floatToUint(&f32_u64, n, x, ft, tt)
+}
+func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+	return s.floatToUint(&f64_u64, n, x, ft, tt)
+}
+
+func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+	// if x < 9223372036854775808.0 {
+	// 	result = uintY(x)
+	// } else {
+	// 	y = x - 9223372036854775808.0
+	// 	z = uintY(y)
+	// 	result = z | -9223372036854775808
+	// }
+	twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
+	cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.SetControl(cmp)
+	b.Likely = ssa.BranchLikely
+
+	bThen := s.f.NewBlock(ssa.BlockPlain)
+	bElse := s.f.NewBlock(ssa.BlockPlain)
+	bAfter := s.f.NewBlock(ssa.BlockPlain)
+
+	b.AddEdgeTo(bThen)
+	s.startBlock(bThen)
+	a0 := s.newValue1(cvttab.cvt2U, tt, x)
+	s.vars[n] = a0
+	s.endBlock()
+	bThen.AddEdgeTo(bAfter)
+
+	b.AddEdgeTo(bElse)
+	s.startBlock(bElse)
+	y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
+	y = s.newValue1(cvttab.cvt2U, tt, y)
+	z := s.constInt64(tt, -9223372036854775808)
+	a1 := s.newValue2(ssa.OpOr64, tt, y, z)
+	s.vars[n] = a1
+	s.endBlock()
+	bElse.AddEdgeTo(bAfter)
+
+	s.startBlock(bAfter)
+	return s.variable(n, n.Type)
+}
+
+// ifaceType returns the value for the word containing the type.
+// n is the node for the interface expression.
+// v is the corresponding value.
+func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
+	byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
+
+	if n.Type.IsEmptyInterface() {
+		// Have *eface. The type is the first word in the struct.
+		return s.newValue1(ssa.OpITab, byteptr, v)
+	}
+
+	// Have *iface.
+	// The first word in the struct is the *itab.
+	// If the *itab is nil, return 0.
+	// Otherwise, the second word in the *itab is the type.
+
+	tab := s.newValue1(ssa.OpITab, byteptr, v)
+	s.vars[&typVar] = tab
+	isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.constNil(byteptr))
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.SetControl(isnonnil)
+	b.Likely = ssa.BranchLikely
+
+	bLoad := s.f.NewBlock(ssa.BlockPlain)
+	bEnd := s.f.NewBlock(ssa.BlockPlain)
+
+	b.AddEdgeTo(bLoad)
+	b.AddEdgeTo(bEnd)
+	bLoad.AddEdgeTo(bEnd)
+
+	s.startBlock(bLoad)
+	off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
+	s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
+	s.endBlock()
+
+	s.startBlock(bEnd)
+	typ := s.variable(&typVar, byteptr)
+	delete(s.vars, &typVar)
+	return typ
+}
+
+// dottype generates SSA for a type assertion node.
+// commaok indicates whether to panic or return a bool.
+// If commaok is false, resok will be nil.
+func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
+	iface := s.expr(n.Left)
+	typ := s.ifaceType(n.Left, iface)  // actual concrete type
+	target := s.expr(typename(n.Type)) // target type
+	if !isdirectiface(n.Type) {
+		// walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
+		Fatalf("dottype needs a direct iface type %s", n.Type)
+	}
+
+	if Debug_typeassert > 0 {
+		Warnl(n.Lineno, "type assertion inlined")
+	}
+
+	// TODO:  If we have a nonempty interface and its itab field is nil,
+	// then this test is redundant and ifaceType should just branch directly to bFail.
+	cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
+	b := s.endBlock()
+	b.Kind = ssa.BlockIf
+	b.SetControl(cond)
+	b.Likely = ssa.BranchLikely
+
+	byteptr := Ptrto(Types[TUINT8])
+
+	bOk := s.f.NewBlock(ssa.BlockPlain)
+	bFail := s.f.NewBlock(ssa.BlockPlain)
+	b.AddEdgeTo(bOk)
+	b.AddEdgeTo(bFail)
+
+	if !commaok {
+		// on failure, panic by calling panicdottype
+		s.startBlock(bFail)
+		taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{Typ: byteptr, Sym: typenamesym(n.Left.Type)}, s.sb)
+		s.rtcall(panicdottype, false, nil, typ, target, taddr)
+
+		// on success, return idata field
+		s.startBlock(bOk)
+		return s.newValue1(ssa.OpIData, n.Type, iface), nil
+	}
+
+	// commaok is the more complicated case because we have
+	// a control flow merge point.
+	bEnd := s.f.NewBlock(ssa.BlockPlain)
+
+	// type assertion succeeded
+	s.startBlock(bOk)
+	s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
+	s.vars[&okVar] = s.constBool(true)
+	s.endBlock()
+	bOk.AddEdgeTo(bEnd)
+
+	// type assertion failed
+	s.startBlock(bFail)
+	s.vars[&idataVar] = s.constNil(byteptr)
+	s.vars[&okVar] = s.constBool(false)
+	s.endBlock()
+	bFail.AddEdgeTo(bEnd)
+
+	// merge point
+	s.startBlock(bEnd)
+	res = s.variable(&idataVar, byteptr)
+	resok = s.variable(&okVar, Types[TBOOL])
+	delete(s.vars, &idataVar)
+	delete(s.vars, &okVar)
+	return res, resok
+}
+
+// checkgoto checks that a goto from from to to does not
+// jump into a block or jump over variable declarations.
+// It is a copy of checkgoto in the pre-SSA backend,
+// modified only for line number handling.
+// TODO: document how this works and why it is designed the way it is.
+func (s *state) 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 {
+		// 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
+		}
+
+		lno := from.Left.Lineno
+		if block != nil {
+			yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
+		} else {
+			yyerrorl(lno, "goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, linestr(dcl.Lastlineno))
+		}
+	}
+}
+
+// variable returns the value of a variable at the current location.
+func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
+	v := s.vars[name]
+	if v == nil {
+		v = s.newValue0A(ssa.OpFwdRef, t, name)
+		s.fwdRefs = append(s.fwdRefs, v)
+		s.vars[name] = v
+		s.addNamedValue(name, v)
+	}
+	return v
+}
+
+func (s *state) mem() *ssa.Value {
+	return s.variable(&memVar, ssa.TypeMem)
+}
+
+func (s *state) linkForwardReferences(dm *sparseDefState) {
+
+	// Build SSA graph. Each variable on its first use in a basic block
+	// leaves a FwdRef in that block representing the incoming value
+	// of that variable. This function links that ref up with possible definitions,
+	// inserting Phi values as needed. This is essentially the algorithm
+	// described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
+	// http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
+	// Differences:
+	//   - We use FwdRef nodes to postpone phi building until the CFG is
+	//     completely built. That way we can avoid the notion of "sealed"
+	//     blocks.
+	//   - Phi optimization is a separate pass (in ../ssa/phielim.go).
+	for len(s.fwdRefs) > 0 {
+		v := s.fwdRefs[len(s.fwdRefs)-1]
+		s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
+		s.resolveFwdRef(v, dm)
+	}
+}
+
+// resolveFwdRef modifies v to be the variable's value at the start of its block.
+// v must be a FwdRef op.
+func (s *state) resolveFwdRef(v *ssa.Value, dm *sparseDefState) {
+	b := v.Block
+	name := v.Aux.(*Node)
+	v.Aux = nil
+	if b == s.f.Entry {
+		// Live variable at start of function.
+		if s.canSSA(name) {
+			if strings.HasPrefix(name.Sym.Name, "autotmp_") {
+				// It's likely that this is an uninitialized variable in the entry block.
+				s.Fatalf("Treating auto as if it were arg, func %s, node %v, value %v", b.Func.Name, name, v)
+			}
+			v.Op = ssa.OpArg
+			v.Aux = name
+			return
+		}
+		// Not SSAable. Load it.
+		addr := s.decladdrs[name]
+		if addr == nil {
+			// TODO: closure args reach here.
+			s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
+		}
+		if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
+			s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
+		}
+		v.Op = ssa.OpLoad
+		v.AddArgs(addr, s.startmem)
+		return
+	}
+	if len(b.Preds) == 0 {
+		// This block is dead; we have no predecessors and we're not the entry block.
+		// It doesn't matter what we use here as long as it is well-formed.
+		v.Op = ssa.OpUnknown
+		return
+	}
+	// Find variable value on each predecessor.
+	var argstore [4]*ssa.Value
+	args := argstore[:0]
+	for _, e := range b.Preds {
+		p := e.Block()
+		p = dm.FindBetterDefiningBlock(name, p) // try sparse improvement on p
+		args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
+	}
+
+	// Decide if we need a phi or not. We need a phi if there
+	// are two different args (which are both not v).
+	var w *ssa.Value
+	for _, a := range args {
+		if a == v {
+			continue // self-reference
+		}
+		if a == w {
+			continue // already have this witness
+		}
+		if w != nil {
+			// two witnesses, need a phi value
+			v.Op = ssa.OpPhi
+			v.AddArgs(args...)
+			return
+		}
+		w = a // save witness
+	}
+	if w == nil {
+		s.Fatalf("no witness for reachable phi %s", v)
+	}
+	// One witness. Make v a copy of w.
+	v.Op = ssa.OpCopy
+	v.AddArg(w)
+}
+
+// lookupVarOutgoing finds the variable's value at the end of block b.
+func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
+	for {
+		if v, ok := s.defvars[b.ID][name]; ok {
+			return v
+		}
+		// The variable is not defined by b and we haven't looked it up yet.
+		// If b has exactly one predecessor, loop to look it up there.
+		// Otherwise, give up and insert a new FwdRef and resolve it later.
+		if len(b.Preds) != 1 {
+			break
+		}
+		b = b.Preds[0].Block()
+	}
+	// Generate a FwdRef for the variable and return that.
+	v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
+	s.fwdRefs = append(s.fwdRefs, v)
+	s.defvars[b.ID][name] = v
+	s.addNamedValue(name, v)
+	return v
+}
+
+func (s *state) addNamedValue(n *Node, v *ssa.Value) {
+	if n.Class == Pxxx {
+		// Don't track our dummy nodes (&memVar etc.).
+		return
+	}
+	if strings.HasPrefix(n.Sym.Name, "autotmp_") {
+		// Don't track autotmp_ variables.
+		return
+	}
+	if n.Class == PPARAMOUT {
+		// Don't track named output values.  This prevents return values
+		// from being assigned too early. See #14591 and #14762. TODO: allow this.
+		return
+	}
+	if n.Class == PAUTO && n.Xoffset != 0 {
+		s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
+	}
+	loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
+	values, ok := s.f.NamedValues[loc]
+	if !ok {
+		s.f.Names = append(s.f.Names, loc)
+	}
+	s.f.NamedValues[loc] = append(values, v)
+}
+
+// Branch is an unresolved branch.
+type Branch struct {
+	P *obj.Prog  // branch instruction
+	B *ssa.Block // target
+}
+
+// SSAGenState contains state needed during Prog generation.
+type SSAGenState struct {
+	// Branches remembers all the branch instructions we've seen
+	// and where they would like to go.
+	Branches []Branch
+
+	// bstart remembers where each block starts (indexed by block ID)
+	bstart []*obj.Prog
+}
+
+// Pc returns the current Prog.
+func (s *SSAGenState) Pc() *obj.Prog {
+	return Pc
+}
+
+// SetLineno sets the current source line number.
+func (s *SSAGenState) SetLineno(l int32) {
+	lineno = l
+}
+
+// genssa appends entries to ptxt for each instruction in f.
+// gcargs and gclocals are filled in with pointer maps for the frame.
+func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
+	var s SSAGenState
+
+	e := f.Config.Frontend().(*ssaExport)
+	// We're about to emit a bunch of Progs.
+	// Since the only way to get here is to explicitly request it,
+	// just fail on unimplemented instead of trying to unwind our mess.
+	e.mustImplement = true
+
+	// Remember where each block starts.
+	s.bstart = make([]*obj.Prog, f.NumBlocks())
+
+	var valueProgs map[*obj.Prog]*ssa.Value
+	var blockProgs map[*obj.Prog]*ssa.Block
+	var logProgs = e.log
+	if logProgs {
+		valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
+		blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
+		f.Logf("genssa %s\n", f.Name)
+		blockProgs[Pc] = f.Blocks[0]
+	}
+
+	// Emit basic blocks
+	for i, b := range f.Blocks {
+		s.bstart[b.ID] = Pc
+		// Emit values in block
+		Thearch.SSAMarkMoves(&s, b)
+		for _, v := range b.Values {
+			x := Pc
+			Thearch.SSAGenValue(&s, v)
+			if logProgs {
+				for ; x != Pc; x = x.Link {
+					valueProgs[x] = v
+				}
+			}
+		}
+		// Emit control flow instructions for block
+		var next *ssa.Block
+		if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
+			// If -N, leave next==nil so every block with successors
+			// ends in a JMP (except call blocks - plive doesn't like
+			// select{send,recv} followed by a JMP call).  Helps keep
+			// line numbers for otherwise empty blocks.
+			next = f.Blocks[i+1]
+		}
+		x := Pc
+		Thearch.SSAGenBlock(&s, b, next)
+		if logProgs {
+			for ; x != Pc; x = x.Link {
+				blockProgs[x] = b
+			}
+		}
+	}
+
+	// Resolve branches
+	for _, br := range s.Branches {
+		br.P.To.Val = s.bstart[br.B.ID]
+	}
+
+	if logProgs {
+		for p := ptxt; p != nil; p = p.Link {
+			var s string
+			if v, ok := valueProgs[p]; ok {
+				s = v.String()
+			} else if b, ok := blockProgs[p]; ok {
+				s = b.String()
+			} else {
+				s = "   " // most value and branch strings are 2-3 characters long
+			}
+			f.Logf("%s\t%s\n", s, p)
+		}
+		if f.Config.HTML != nil {
+			saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
+			ptxt.Ctxt.LineHist.PrintFilenameOnly = true
+			var buf bytes.Buffer
+			buf.WriteString("<code>")
+			buf.WriteString("<dl class=\"ssa-gen\">")
+			for p := ptxt; p != nil; p = p.Link {
+				buf.WriteString("<dt class=\"ssa-prog-src\">")
+				if v, ok := valueProgs[p]; ok {
+					buf.WriteString(v.HTML())
+				} else if b, ok := blockProgs[p]; ok {
+					buf.WriteString(b.HTML())
+				}
+				buf.WriteString("</dt>")
+				buf.WriteString("<dd class=\"ssa-prog\">")
+				buf.WriteString(html.EscapeString(p.String()))
+				buf.WriteString("</dd>")
+				buf.WriteString("</li>")
+			}
+			buf.WriteString("</dl>")
+			buf.WriteString("</code>")
+			f.Config.HTML.WriteColumn("genssa", buf.String())
+			ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
+		}
+	}
+
+	// Emit static data
+	if f.StaticData != nil {
+		for _, n := range f.StaticData.([]*Node) {
+			if !gen_as_init(n, false) {
+				Fatalf("non-static data marked as static: %v\n\n", n)
+			}
+		}
+	}
+
+	// Allocate stack frame
+	allocauto(ptxt)
+
+	// Generate gc bitmaps.
+	liveness(Curfn, ptxt, gcargs, gclocals)
+
+	// Add frame prologue. Zero ambiguously live variables.
+	Thearch.Defframe(ptxt)
+	if Debug['f'] != 0 {
+		frame(0)
+	}
+
+	// Remove leftover instrumentation from the instruction stream.
+	removevardef(ptxt)
+
+	f.Config.HTML.Close()
+}
+
+// movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
+func movZero(as obj.As, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
+	p := Prog(as)
+	// TODO: use zero register on archs that support it.
+	p.From.Type = obj.TYPE_CONST
+	p.From.Offset = 0
+	p.To.Type = obj.TYPE_MEM
+	p.To.Reg = regnum
+	p.To.Offset = offset
+	offset += width
+	nleft = nbytes - width
+	return nleft, offset
+}
+
+type FloatingEQNEJump struct {
+	Jump  obj.As
+	Index int
+}
+
+func oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump, likely ssa.BranchPrediction, branches []Branch) []Branch {
+	p := Prog(jumps.Jump)
+	p.To.Type = obj.TYPE_BRANCH
+	to := jumps.Index
+	branches = append(branches, Branch{p, b.Succs[to].Block()})
+	if to == 1 {
+		likely = -likely
+	}
+	// liblink reorders the instruction stream as it sees fit.
+	// Pass along what we know so liblink can make use of it.
+	// TODO: Once we've fully switched to SSA,
+	// make liblink leave our output alone.
+	switch likely {
+	case ssa.BranchUnlikely:
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 0
+	case ssa.BranchLikely:
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 1
+	}
+	return branches
+}
+
+func SSAGenFPJump(s *SSAGenState, b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) {
+	likely := b.Likely
+	switch next {
+	case b.Succs[0].Block():
+		s.Branches = oneFPJump(b, &jumps[0][0], likely, s.Branches)
+		s.Branches = oneFPJump(b, &jumps[0][1], likely, s.Branches)
+	case b.Succs[1].Block():
+		s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
+		s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
+	default:
+		s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
+		s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
+		q := Prog(obj.AJMP)
+		q.To.Type = obj.TYPE_BRANCH
+		s.Branches = append(s.Branches, Branch{q, b.Succs[1].Block()})
+	}
+}
+
+// AddAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
+func AddAux(a *obj.Addr, v *ssa.Value) {
+	AddAux2(a, v, v.AuxInt)
+}
+func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
+	if a.Type != obj.TYPE_MEM {
+		v.Fatalf("bad AddAux addr %v", a)
+	}
+	// add integer offset
+	a.Offset += offset
+
+	// If no additional symbol offset, we're done.
+	if v.Aux == nil {
+		return
+	}
+	// Add symbol's offset from its base register.
+	switch sym := v.Aux.(type) {
+	case *ssa.ExternSymbol:
+		a.Name = obj.NAME_EXTERN
+		switch s := sym.Sym.(type) {
+		case *Sym:
+			a.Sym = Linksym(s)
+		case *obj.LSym:
+			a.Sym = s
+		default:
+			v.Fatalf("ExternSymbol.Sym is %T", s)
+		}
+	case *ssa.ArgSymbol:
+		n := sym.Node.(*Node)
+		a.Name = obj.NAME_PARAM
+		a.Node = n
+		a.Sym = Linksym(n.Orig.Sym)
+		a.Offset += n.Xoffset // TODO: why do I have to add this here?  I don't for auto variables.
+	case *ssa.AutoSymbol:
+		n := sym.Node.(*Node)
+		a.Name = obj.NAME_AUTO
+		a.Node = n
+		a.Sym = Linksym(n.Sym)
+	default:
+		v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
+	}
+}
+
+// extendIndex extends v to a full int width.
+func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
+	size := v.Type.Size()
+	if size == s.config.IntSize {
+		return v
+	}
+	if size > s.config.IntSize {
+		// TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
+		// the high word and branch to out-of-bounds failure if it is not 0.
+		s.Unimplementedf("64->32 index truncation not implemented")
+		return v
+	}
+
+	// Extend value to the required size
+	var op ssa.Op
+	if v.Type.IsSigned() {
+		switch 10*size + s.config.IntSize {
+		case 14:
+			op = ssa.OpSignExt8to32
+		case 18:
+			op = ssa.OpSignExt8to64
+		case 24:
+			op = ssa.OpSignExt16to32
+		case 28:
+			op = ssa.OpSignExt16to64
+		case 48:
+			op = ssa.OpSignExt32to64
+		default:
+			s.Fatalf("bad signed index extension %s", v.Type)
+		}
+	} else {
+		switch 10*size + s.config.IntSize {
+		case 14:
+			op = ssa.OpZeroExt8to32
+		case 18:
+			op = ssa.OpZeroExt8to64
+		case 24:
+			op = ssa.OpZeroExt16to32
+		case 28:
+			op = ssa.OpZeroExt16to64
+		case 48:
+			op = ssa.OpZeroExt32to64
+		default:
+			s.Fatalf("bad unsigned index extension %s", v.Type)
+		}
+	}
+	return s.newValue1(op, Types[TINT], v)
+}
+
+// SSARegNum returns the register (in cmd/internal/obj numbering) to
+// which v has been allocated. Panics if v is not assigned to a
+// register.
+// TODO: Make this panic again once it stops happening routinely.
+func SSARegNum(v *ssa.Value) int16 {
+	reg := v.Block.Func.RegAlloc[v.ID]
+	if reg == nil {
+		v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
+		return 0
+	}
+	return Thearch.SSARegToReg[reg.(*ssa.Register).Num]
+}
+
+// AutoVar returns a *Node and int64 representing the auto variable and offset within it
+// where v should be spilled.
+func AutoVar(v *ssa.Value) (*Node, int64) {
+	loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
+	if v.Type.Size() > loc.Type.Size() {
+		v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
+	}
+	return loc.N.(*Node), loc.Off
+}
+
+// fieldIdx finds the index of the field referred to by the ODOT node n.
+func fieldIdx(n *Node) int {
+	t := n.Left.Type
+	f := n.Sym
+	if !t.IsStruct() {
+		panic("ODOT's LHS is not a struct")
+	}
+
+	var i int
+	for _, t1 := range t.Fields().Slice() {
+		if t1.Sym != f {
+			i++
+			continue
+		}
+		if t1.Offset != n.Xoffset {
+			panic("field offset doesn't match")
+		}
+		return i
+	}
+	panic(fmt.Sprintf("can't find field in expr %s\n", n))
+
+	// TODO: keep the result of this function somewhere in the ODOT Node
+	// so we don't have to recompute it each time we need it.
+}
+
+// ssaExport exports a bunch of compiler services for the ssa backend.
+type ssaExport struct {
+	log           bool
+	unimplemented bool
+	mustImplement bool
+}
+
+func (s *ssaExport) TypeBool() ssa.Type    { return Types[TBOOL] }
+func (s *ssaExport) TypeInt8() ssa.Type    { return Types[TINT8] }
+func (s *ssaExport) TypeInt16() ssa.Type   { return Types[TINT16] }
+func (s *ssaExport) TypeInt32() ssa.Type   { return Types[TINT32] }
+func (s *ssaExport) TypeInt64() ssa.Type   { return Types[TINT64] }
+func (s *ssaExport) TypeUInt8() ssa.Type   { return Types[TUINT8] }
+func (s *ssaExport) TypeUInt16() ssa.Type  { return Types[TUINT16] }
+func (s *ssaExport) TypeUInt32() ssa.Type  { return Types[TUINT32] }
+func (s *ssaExport) TypeUInt64() ssa.Type  { return Types[TUINT64] }
+func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
+func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
+func (s *ssaExport) TypeInt() ssa.Type     { return Types[TINT] }
+func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
+func (s *ssaExport) TypeString() ssa.Type  { return Types[TSTRING] }
+func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
+
+// StringData returns a symbol (a *Sym wrapped in an interface) which
+// is the data component of a global string constant containing s.
+func (*ssaExport) StringData(s string) interface{} {
+	// TODO: is idealstring correct?  It might not matter...
+	_, data := stringsym(s)
+	return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
+}
+
+func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
+	n := temp(t.(*Type))   // Note: adds new auto to Curfn.Func.Dcl list
+	e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
+	return n
+}
+
+func (e *ssaExport) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+	n := name.N.(*Node)
+	ptrType := Ptrto(Types[TUINT8])
+	lenType := Types[TINT]
+	if n.Class == PAUTO && !n.Addrtaken {
+		// Split this string up into two separate variables.
+		p := e.namedAuto(n.Sym.Name+".ptr", ptrType)
+		l := e.namedAuto(n.Sym.Name+".len", lenType)
+		return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}
+	}
+	// Return the two parts of the larger variable.
+	return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
+}
+
+func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+	n := name.N.(*Node)
+	t := Ptrto(Types[TUINT8])
+	if n.Class == PAUTO && !n.Addrtaken {
+		// Split this interface up into two separate variables.
+		f := ".itab"
+		if n.Type.IsEmptyInterface() {
+			f = ".type"
+		}
+		c := e.namedAuto(n.Sym.Name+f, t)
+		d := e.namedAuto(n.Sym.Name+".data", t)
+		return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
+	}
+	// Return the two parts of the larger variable.
+	return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
+}
+
+func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
+	n := name.N.(*Node)
+	ptrType := Ptrto(name.Type.ElemType().(*Type))
+	lenType := Types[TINT]
+	if n.Class == PAUTO && !n.Addrtaken {
+		// Split this slice up into three separate variables.
+		p := e.namedAuto(n.Sym.Name+".ptr", ptrType)
+		l := e.namedAuto(n.Sym.Name+".len", lenType)
+		c := e.namedAuto(n.Sym.Name+".cap", lenType)
+		return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}, ssa.LocalSlot{N: c, Type: lenType, Off: 0}
+	}
+	// Return the three parts of the larger variable.
+	return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
+		ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)},
+		ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(2*Widthptr)}
+}
+
+func (e *ssaExport) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
+	n := name.N.(*Node)
+	s := name.Type.Size() / 2
+	var t *Type
+	if s == 8 {
+		t = Types[TFLOAT64]
+	} else {
+		t = Types[TFLOAT32]
+	}
+	if n.Class == PAUTO && !n.Addrtaken {
+		// Split this complex up into two separate variables.
+		c := e.namedAuto(n.Sym.Name+".real", t)
+		d := e.namedAuto(n.Sym.Name+".imag", t)
+		return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
+	}
+	// Return the two parts of the larger variable.
+	return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
+}
+
+func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
+	n := name.N.(*Node)
+	st := name.Type
+	ft := st.FieldType(i)
+	if n.Class == PAUTO && !n.Addrtaken {
+		// Note: the _ field may appear several times.  But
+		// have no fear, identically-named but distinct Autos are
+		// ok, albeit maybe confusing for a debugger.
+		x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft)
+		return ssa.LocalSlot{N: x, Type: ft, Off: 0}
+	}
+	return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
+}
+
+// namedAuto returns a new AUTO variable with the given name and type.
+func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
+	t := typ.(*Type)
+	s := &Sym{Name: name, Pkg: autopkg}
+	n := Nod(ONAME, nil, nil)
+	s.Def = n
+	s.Def.Used = true
+	n.Sym = s
+	n.Type = t
+	n.Class = PAUTO
+	n.Addable = true
+	n.Ullman = 1
+	n.Esc = EscNever
+	n.Xoffset = 0
+	n.Name.Curfn = Curfn
+	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
+
+	dowidth(t)
+	e.mustImplement = true
+
+	return n
+}
+
+func (e *ssaExport) CanSSA(t ssa.Type) bool {
+	return canSSAType(t.(*Type))
+}
+
+func (e *ssaExport) Line(line int32) string {
+	return linestr(line)
+}
+
+// Log logs a message from the compiler.
+func (e *ssaExport) Logf(msg string, args ...interface{}) {
+	// If e was marked as unimplemented, anything could happen. Ignore.
+	if e.log && !e.unimplemented {
+		fmt.Printf(msg, args...)
+	}
+}
+
+func (e *ssaExport) Log() bool {
+	return e.log
+}
+
+// Fatal reports a compiler error and exits.
+func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
+	// If e was marked as unimplemented, anything could happen. Ignore.
+	if !e.unimplemented {
+		lineno = line
+		Fatalf(msg, args...)
+	}
+}
+
+// Unimplemented reports that the function cannot be compiled.
+// It will be removed once SSA work is complete.
+func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
+	if e.mustImplement {
+		lineno = line
+		Fatalf(msg, args...)
+	}
+	const alwaysLog = false // enable to calculate top unimplemented features
+	if !e.unimplemented && (e.log || alwaysLog) {
+		// first implementation failure, print explanation
+		fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
+	}
+	e.unimplemented = true
+}
+
+// Warnl reports a "warning", which is usually flag-triggered
+// logging output for the benefit of tests.
+func (e *ssaExport) Warnl(line int32, fmt_ string, args ...interface{}) {
+	Warnl(line, fmt_, args...)
+}
+
+func (e *ssaExport) Debug_checknil() bool {
+	return Debug_checknil != 0
+}
+
+func (n *Node) Typ() ssa.Type {
+	return n.Type
+}
diff --git a/src/cmd/compile/internal/gc/ssa_test.go b/src/cmd/compile/internal/gc/ssa_test.go
new file mode 100644
index 0000000..c89917d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/ssa_test.go
@@ -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.
+
+package gc
+
+import (
+	"bytes"
+	"internal/testenv"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+)
+
+// TODO: move all these tests elsewhere?
+// Perhaps teach test/run.go how to run them with a new action verb.
+func runTest(t *testing.T, filename string) {
+	doTest(t, filename, "run")
+}
+func buildTest(t *testing.T, filename string) {
+	doTest(t, filename, "build")
+}
+func doTest(t *testing.T, filename string, kind string) {
+	testenv.MustHaveGoBuild(t)
+	var stdout, stderr bytes.Buffer
+	cmd := exec.Command("go", kind, filepath.Join("testdata", filename))
+	cmd.Stdout = &stdout
+	cmd.Stderr = &stderr
+	if err := cmd.Run(); err != nil {
+		t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr)
+	}
+	if s := stdout.String(); s != "" {
+		t.Errorf("Stdout = %s\nWant empty", s)
+	}
+	if s := stderr.String(); strings.Contains(s, "SSA unimplemented") {
+		t.Errorf("Unimplemented message found in stderr:\n%s", s)
+	}
+}
+
+// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting.
+func TestShortCircuit(t *testing.T) { runTest(t, "short_ssa.go") }
+
+// TestBreakContinue tests that continue and break statements do what they say.
+func TestBreakContinue(t *testing.T) { runTest(t, "break_ssa.go") }
+
+// TestTypeAssertion tests type assertions.
+func TestTypeAssertion(t *testing.T) { runTest(t, "assert_ssa.go") }
+
+// TestArithmetic tests that both backends have the same result for arithmetic expressions.
+func TestArithmetic(t *testing.T) {
+	if runtime.GOARCH == "386" {
+		t.Skip("legacy 386 compiler can't handle this test")
+	}
+	runTest(t, "arith_ssa.go")
+}
+
+// TestFP tests that both backends have the same result for floating point expressions.
+func TestFP(t *testing.T) { runTest(t, "fp_ssa.go") }
+
+// TestArithmeticBoundary tests boundary results for arithmetic operations.
+func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary_ssa.go") }
+
+// TestArithmeticConst tests results for arithmetic operations against constants.
+func TestArithmeticConst(t *testing.T) { runTest(t, "arithConst_ssa.go") }
+
+func TestChan(t *testing.T) { runTest(t, "chan_ssa.go") }
+
+func TestCompound(t *testing.T) { runTest(t, "compound_ssa.go") }
+
+func TestCtl(t *testing.T) { runTest(t, "ctl_ssa.go") }
+
+func TestLoadStore(t *testing.T) { runTest(t, "loadstore_ssa.go") }
+
+func TestMap(t *testing.T) { runTest(t, "map_ssa.go") }
+
+func TestRegalloc(t *testing.T) { runTest(t, "regalloc_ssa.go") }
+
+func TestString(t *testing.T) { runTest(t, "string_ssa.go") }
+
+func TestDeferNoReturn(t *testing.T) { buildTest(t, "deferNoReturn_ssa.go") }
+
+// TestClosure tests closure related behavior.
+func TestClosure(t *testing.T) { runTest(t, "closure_ssa.go") }
+
+func TestArray(t *testing.T) { runTest(t, "array_ssa.go") }
+
+func TestAppend(t *testing.T) { runTest(t, "append_ssa.go") }
+
+func TestZero(t *testing.T) { runTest(t, "zero_ssa.go") }
+
+func TestAddressed(t *testing.T) { runTest(t, "addressed_ssa.go") }
+
+func TestCopy(t *testing.T) { runTest(t, "copy_ssa.go") }
+
+func TestUnsafe(t *testing.T) { runTest(t, "unsafe_ssa.go") }
+
+func TestPhi(t *testing.T) { runTest(t, "phi_ssa.go") }
+
+func TestSlice(t *testing.T) { runTest(t, "slice.go") }
+
+func TestNamedReturn(t *testing.T) { runTest(t, "namedReturn.go") }
+
+func TestDuplicateLoad(t *testing.T) { runTest(t, "dupLoad.go") }
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 0d25ddf..1db1cba 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -11,15 +11,16 @@ import (
 	"encoding/binary"
 	"fmt"
 	"os"
+	"runtime/debug"
 	"sort"
+	"strconv"
 	"strings"
 	"unicode"
 	"unicode/utf8"
 )
 
 type Error struct {
-	lineno int
-	seq    int
+	lineno int32
 	msg    string
 }
 
@@ -33,51 +34,36 @@ func errorexit() {
 	os.Exit(2)
 }
 
-func parserline() int {
-	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 {
+	if len(errors) > 0 && 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{}) {
+func adderr(line int32, 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...)),
+		msg:    fmt.Sprintf("%v: %s\n", linestr(line), fmt.Sprintf(format, args...)),
 	})
 }
 
-// errcmp sorts errors by line, then seq, then message.
-type errcmp []Error
+// byLineno sorts errors by lineno.
+type byLineno []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
-	}
-	if a.seq != b.seq {
-		return a.seq < b.seq
-	}
-	return a.msg < b.msg
-}
+func (x byLineno) Len() int           { return len(x) }
+func (x byLineno) Less(i, j int) bool { return x[i].lineno < x[j].lineno }
+func (x byLineno) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
 
 func Flusherrors() {
 	bstdout.Flush()
 	if len(errors) == 0 {
 		return
 	}
-	sort.Sort(errcmp(errors))
+	sort.Stable(byLineno(errors))
 	for i := 0; i < len(errors); i++ {
 		if i == 0 || errors[i].msg != errors[i-1].msg {
 			fmt.Printf("%s", errors[i].msg)
@@ -97,65 +83,64 @@ func hcrash() {
 	}
 }
 
-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()
-	}
+func linestr(line int32) string {
+	return Ctxt.Line(int(line))
 }
 
-var yyerror_lastsyntax int
+// lasterror keeps track of the most recently issued error.
+// It is used to avoid multiple error messages on the same
+// line.
+var lasterror struct {
+	syntax int32  // line of last syntax error
+	other  int32  // line of last non-syntax error
+	msg    string // error message of last non-syntax error
+}
 
-func Yyerror(format string, args ...interface{}) {
+func yyerrorl(line int32, 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 {
-			lexlineno = prevlineno
-		}
-
-		// only one syntax error per line
-		if int32(yyerror_lastsyntax) == lexlineno {
+		// only one syntax error per line, no matter what error
+		if lasterror.syntax == line {
 			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())
+		lasterror.syntax = line
+	} else {
+		// only one of multiple equal non-syntax errors per line
+		// (Flusherrors shows only one of them, so we filter them
+		// here as best as we can (they may not appear in order)
+		// so that we don't count them here and exit early, and
+		// then have nothing to show for.)
+		if lasterror.other == line && lasterror.msg == msg {
 			return
 		}
-
-		yyerrorl(int(lexlineno), "%s", msg)
-		return
+		lasterror.other = line
+		lasterror.msg = msg
 	}
 
-	adderr(parserline(), "%s", msg)
+	adderr(line, "%s", msg)
 
 	hcrash()
 	nerrors++
 	if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
 		Flusherrors()
-		fmt.Printf("%v: too many errors\n", Ctxt.Line(parserline()))
+		fmt.Printf("%v: too many errors\n", linestr(line))
 		errorexit()
 	}
 }
 
+func Yyerror(format string, args ...interface{}) {
+	yyerrorl(lineno, format, args...)
+}
+
 func Warn(fmt_ string, args ...interface{}) {
-	adderr(parserline(), fmt_, args...)
+	adderr(lineno, fmt_, args...)
 
 	hcrash()
 }
 
-func Warnl(line int, fmt_ string, args ...interface{}) {
+func Warnl(line int32, fmt_ string, args ...interface{}) {
 	adderr(line, fmt_, args...)
 	if Debug['m'] != 0 {
 		Flusherrors()
@@ -165,7 +150,7 @@ func Warnl(line int, fmt_ string, args ...interface{}) {
 func Fatalf(fmt_ string, args ...interface{}) {
 	Flusherrors()
 
-	fmt.Printf("%v: internal compiler error: ", Ctxt.Line(int(lineno)))
+	fmt.Printf("%v: internal compiler error: ", linestr(lineno))
 	fmt.Printf(fmt_, args...)
 	fmt.Printf("\n")
 
@@ -174,6 +159,11 @@ func Fatalf(fmt_ string, args ...interface{}) {
 		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")
+	} else {
+		// Not a release; dump a stack trace, too.
+		fmt.Println()
+		os.Stdout.Write(debug.Stack())
+		fmt.Println()
 	}
 
 	hcrash()
@@ -182,28 +172,28 @@ func Fatalf(fmt_ string, args ...interface{}) {
 
 func linehistpragma(file string) {
 	if Debug['i'] != 0 {
-		fmt.Printf("pragma %s at line %v\n", file, Ctxt.Line(int(lexlineno)))
+		fmt.Printf("pragma %s at line %v\n", file, linestr(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)))
+		fmt.Printf("import %s at line %v\n", file, linestr(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)))
+		fmt.Printf("end of import at line %v\n", linestr(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)))
+		fmt.Printf("line %s at line %v\n", file, linestr(lexlineno))
 	}
 	Ctxt.LineHist.Update(int(lexlineno), file, off)
 }
@@ -247,6 +237,15 @@ func LookupBytes(name []byte) *Sym {
 	return localpkg.LookupBytes(name)
 }
 
+// LookupN looks up the symbol starting with prefix and ending with
+// the decimal n. If prefix is too long, LookupN panics.
+func LookupN(prefix string, n int) *Sym {
+	var buf [20]byte // plenty long enough for all current users
+	copy(buf[:], prefix)
+	b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
+	return LookupBytes(b)
+}
+
 var initSyms []*Sym
 
 var nopkg = &Pkg{
@@ -262,9 +261,8 @@ func (pkg *Pkg) Lookup(name string) *Sym {
 	}
 
 	s := &Sym{
-		Name:    name,
-		Pkg:     pkg,
-		Lexical: LNAME,
+		Name: name,
+		Pkg:  pkg,
 	}
 	if name == "init" {
 		initSyms = append(initSyms, s)
@@ -329,7 +327,7 @@ func importdot(opkg *Pkg, pack *Node) {
 
 	if n == 0 {
 		// can't possibly be used - there were no symbols
-		yyerrorl(int(pack.Lineno), "imported and not used: %q", opkg.Path)
+		yyerrorl(pack.Lineno, "imported and not used: %q", opkg.Path)
 	}
 }
 
@@ -338,7 +336,7 @@ func Nod(op Op, nleft *Node, nright *Node) *Node {
 	n.Op = op
 	n.Left = nleft
 	n.Right = nright
-	n.Lineno = int32(parserline())
+	n.Lineno = lineno
 	n.Xoffset = BADWIDTH
 	n.Orig = n
 	switch op {
@@ -364,6 +362,14 @@ func Nod(op Op, nleft *Node, nright *Node) *Node {
 	return n
 }
 
+// NodSym makes a Node with Op op and with the Left field set to left
+// and the Sym field set to sym. This is for ODOT and friends.
+func NodSym(op Op, left *Node, sym *Sym) *Node {
+	n := Nod(op, left, nil)
+	n.Sym = sym
+	return n
+}
+
 func saveorignode(n *Node) {
 	if n.Orig != nil {
 		return
@@ -373,211 +379,8 @@ func saveorignode(n *Node) {
 	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 {
-		Fatalf("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 {
-		return AMEM
-	}
-	if t.Noalg {
-		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
-	}
-
-	Fatalf("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 EType
-		if bad == nil {
-			mtype = key.Etype
-		} else {
-			mtype = 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 EType) *Type {
-	t := new(Type)
-	t.Etype = et
-	t.Width = BADWIDTH
-	t.Lineno = int(lineno)
-	t.Orig = t
-	return t
-}
-
 // methcmp sorts by symbol, then by package path for unexported symbols.
-type methcmp []*Type
+type methcmp []*Field
 
 func (x methcmp) Len() int      { return len(x) }
 func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
@@ -605,32 +408,11 @@ func (x methcmp) Less(i, j int) bool {
 	return false
 }
 
-func sortinter(t *Type) *Type {
-	if t.Type == nil || t.Type.Down == nil {
-		return t
-	}
-
-	var a []*Type
-	for f := t.Type; f != nil; f = f.Down {
-		a = append(a, f)
-	}
-	sort.Sort(methcmp(a))
-
-	n := len(a) // n > 0 due to initial conditions.
-	for i := 0; i < n-1; i++ {
-		a[i].Down = a[i+1]
-	}
-	a[n-1].Down = nil
-
-	t.Type = a[0]
-	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.Val().U.(*Mpint).SetInt64(v)
 	c.Type = Types[TIDEAL]
 	ullmancalc(c)
 	return c
@@ -640,7 +422,7 @@ func nodfltconst(v *Mpflt) *Node {
 	c := Nod(OLITERAL, nil, nil)
 	c.Addable = true
 	c.SetVal(Val{newMpflt()})
-	mpmovefltflt(c.Val().U.(*Mpflt), v)
+	c.Val().U.(*Mpflt).Set(v)
 	c.Type = Types[TIDEAL]
 	ullmancalc(c)
 	return c
@@ -652,10 +434,10 @@ func Nodconst(n *Node, t *Type, v int64) {
 	n.Addable = true
 	ullmancalc(n)
 	n.SetVal(Val{new(Mpint)})
-	Mpmovecfix(n.Val().U.(*Mpint), v)
+	n.Val().U.(*Mpint).SetInt64(v)
 	n.Type = t
 
-	if Isfloat[t.Etype] {
+	if t.IsFloat() {
 		Fatalf("nodconst: bad type %v", t)
 	}
 }
@@ -675,27 +457,27 @@ func Nodbool(b bool) *Node {
 }
 
 func aindex(b *Node, t *Type) *Type {
-	bound := int64(-1) // open bound
-	typecheck(&b, Erv)
+	hasbound := false
+	var bound int64
+	b = 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))
+			hasbound = true
+			bound = b.Int64()
 			if bound < 0 {
 				Yyerror("array bound must be non negative")
 			}
 		}
 	}
 
-	// fixed array
-	r := typ(TARRAY)
-
-	r.Type = t
-	r.Bound = bound
-	return r
+	if !hasbound {
+		return typSlice(t)
+	}
+	return typArray(t, bound)
 }
 
 // treecopy recursively copies n, with the exception of
@@ -708,15 +490,13 @@ func treecopy(n *Node, lineno int32) *Node {
 		return nil
 	}
 
-	var m *Node
 	switch n.Op {
 	default:
-		m = Nod(OXXX, nil, nil)
-		*m = *n
-		m.Orig = m
+		m := *n
+		m.Orig = &m
 		m.Left = treecopy(n.Left, lineno)
 		m.Right = treecopy(n.Right, lineno)
-		m.List = listtreecopy(n.List, lineno)
+		m.List.Set(listtreecopy(n.List.Slice(), lineno))
 		if lineno != 0 {
 			m.Lineno = lineno
 		}
@@ -724,6 +504,7 @@ func treecopy(n *Node, lineno int32) *Node {
 			Dump("treecopy", n)
 			Fatalf("treecopy Name")
 		}
+		return &m
 
 	case ONONAME:
 		if n.Sym == Lookup("iota") {
@@ -731,23 +512,27 @@ func treecopy(n *Node, lineno int32) *Node {
 			// 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
+			m := *n
 			if lineno != 0 {
 				m.Lineno = lineno
 			}
 			m.Name = new(Name)
 			*m.Name = *n.Name
 			m.Name.Iota = iota_
-			break
+			return &m
 		}
+		return n
+
+	case OPACK:
+		// OPACK nodes are never valid in const value declarations,
+		// but allow them like any other declared symbol to avoid
+		// crashing (golang.org/issue/11361).
 		fallthrough
 
 	case ONAME, OLITERAL, OTYPE:
-		m = n
-	}
+		return n
 
-	return m
+	}
 }
 
 // isnil reports whether n represents the universal untyped zero value "nil".
@@ -761,10 +546,10 @@ func isptrto(t *Type, et EType) bool {
 	if t == nil {
 		return false
 	}
-	if !Isptr[t.Etype] {
+	if !t.IsPtr() {
 		return false
 	}
-	t = t.Type
+	t = t.Elem()
 	if t == nil {
 		return false
 	}
@@ -774,18 +559,6 @@ func isptrto(t *Type, et EType) bool {
 	return true
 }
 
-func Istype(t *Type, et EType) bool {
-	return t != nil && 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
@@ -797,35 +570,6 @@ 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 {
@@ -834,18 +578,18 @@ func methtype(t *Type, mustname int) *Type {
 	}
 
 	// strip away pointer if it's there
-	if Isptr[t.Etype] {
+	if t.IsPtr() {
 		if t.Sym != nil {
 			return nil
 		}
-		t = t.Type
+		t = t.Elem()
 		if t == nil {
 			return nil
 		}
 	}
 
 	// need a type name
-	if t.Sym == nil && (mustname != 0 || t.Etype != TSTRUCT) {
+	if t.Sym == nil && (mustname != 0 || !t.IsStruct()) {
 		return nil
 	}
 
@@ -857,6 +601,7 @@ func methtype(t *Type, mustname int) *Type {
 
 		case TSTRUCT,
 			TARRAY,
+			TSLICE,
 			TMAP,
 			TCHAN,
 			TSTRING,
@@ -877,81 +622,58 @@ func cplxsubtype(et EType) EType {
 		return TFLOAT64
 	}
 
-	Fatalf("cplxsubtype: %v\n", Econv(et))
+	Fatalf("cplxsubtype: %v\n", et)
 	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.
+// Eqtype reports whether 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 {
+func Eqtype(t1, t2 *Type) bool {
 	return eqtype1(t1, t2, nil)
 }
 
-func eqtype1(t1 *Type, t2 *Type, assumed_equal *TypePairList) bool {
+type typePair struct {
+	t1 *Type
+	t2 *Type
+}
+
+func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool {
 	if t1 == t2 {
 		return true
 	}
-	if t1 == nil || t2 == nil || t1.Etype != t2.Etype {
+	if t1 == nil || t2 == nil || t1.Etype != t2.Etype || t1.Broke || t2.Broke {
 		return false
 	}
 	if t1.Sym != nil || t2.Sym != nil {
-		// Special case: we keep byte and uint8 separate
-		// for error messages.  Treat them as equal.
+		// Special case: we keep byte/uint8 and rune/int32
+		// 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 (t1 == Types[TUINT8] || t1 == bytetype) && (t2 == Types[TUINT8] || t2 == bytetype)
+		case TINT32:
+			return (t1 == Types[TINT32] || t1 == runetype) && (t2 == Types[TINT32] || t2 == runetype)
+		default:
+			return false
 		}
-
-		return false
 	}
 
-	if onlist(assumed_equal, t1, t2) {
+	if assumedEqual == nil {
+		assumedEqual = make(map[typePair]struct{})
+	} else if _, ok := assumedEqual[typePair{t1, t2}]; ok {
 		return true
 	}
-	var l TypePairList
-	l.next = assumed_equal
-	l.t1 = t1
-	l.t2 = t2
+	assumedEqual[typePair{t1, t2}] = struct{}{}
 
 	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 {
-				Fatalf("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) {
+		t1, i1 := IterFields(t1)
+		t2, i2 := IterFields(t2)
+		for ; t1 != nil && t2 != nil; t1, t2 = i1.Next(), i2.Next() {
+			if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, assumedEqual) || t1.Note != t2.Note {
 				return false
 			}
 		}
@@ -961,73 +683,64 @@ func eqtype1(t1 *Type, t2 *Type, assumed_equal *TypePairList) bool {
 		}
 		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 {
-				Fatalf("func missing struct: %v %v", t1, t2)
-			}
-
+		// Check parameters and result parameters for type equality.
+		// We intentionally ignore receiver parameters for type
+		// equality, because they're never relevant.
+		for _, f := range paramsResults {
 			// 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 {
-					Fatalf("func struct missing field: %v %v", ta, tb)
-				}
-				if ta.Isddd != tb.Isddd || !eqtype1(ta.Type, tb.Type, &l) {
+			ta, ia := IterFields(f(t1))
+			tb, ib := IterFields(f(t2))
+			for ; ta != nil && tb != nil; ta, tb = ia.Next(), ib.Next() {
+				if ta.Isddd != tb.Isddd || !eqtype1(ta.Type, tb.Type, assumedEqual) {
 					return false
 				}
 			}
-
 			if ta != nil || tb != nil {
 				return false
 			}
 		}
-
-		if t1 == nil && t2 == nil {
-			return true
-		}
-		return false
+		return true
 
 	case TARRAY:
-		if t1.Bound != t2.Bound {
+		if t1.NumElem() != t2.NumElem() {
 			return false
 		}
 
 	case TCHAN:
-		if t1.Chan != t2.Chan {
+		if t1.ChanDir() != t2.ChanDir() {
 			return false
 		}
-	}
 
-	if eqtype1(t1.Down, t2.Down, &l) && eqtype1(t1.Type, t2.Type, &l) {
-		return true
+	case TMAP:
+		if !eqtype1(t1.Key(), t2.Key(), assumedEqual) {
+			return false
+		}
+		return eqtype1(t1.Val(), t2.Val(), assumedEqual)
 	}
-	return false
+
+	return eqtype1(t1.Elem(), t2.Elem(), assumedEqual)
 }
 
 // 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 {
+	if t1 == nil || t2 == nil || !t1.IsStruct() || !t2.IsStruct() {
 		return false
 	}
 
-	t1 = t1.Type
-	t2 = t2.Type
+	f1, i1 := IterFields(t1)
+	f2, i2 := IterFields(t2)
 	for {
-		if !Eqtype(t1, t2) {
+		if !Eqtype(f1.Type, f2.Type) {
 			return false
 		}
-		if t1 == nil {
+		if f1 == nil {
 			return true
 		}
-		t1 = t1.Down
-		t2 = t2.Down
+		f1 = i1.Next()
+		f2 = i2.Next()
 	}
 }
 
@@ -1041,7 +754,7 @@ func assignop(src *Type, dst *Type, why *string) Op {
 
 	// 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 {
+	if safemode && importpkg == nil && src != nil && src.Etype == TUNSAFEPTR {
 		Yyerror("cannot use unsafe.Pointer")
 		errorexit()
 	}
@@ -1063,15 +776,14 @@ func assignop(src *Type, dst *Type, why *string) Op {
 	// 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)) {
+	if Eqtype(src.Orig, dst.Orig) && (src.Sym == nil || dst.Sym == nil || src.IsEmptyInterface()) {
 		return OCONVNOP
 	}
 
 	// 3. dst is an interface type and src implements dst.
-	if dst.Etype == TINTER && src.Etype != TNIL {
-		var missing *Type
+	if dst.IsInterface() && src.Etype != TNIL {
+		var missing, have *Field
 		var ptr int
-		var have *Type
 		if implements(src, dst, &missing, &have, &ptr) {
 			return OCONVIFACE
 		}
@@ -1087,11 +799,11 @@ func assignop(src *Type, dst *Type, why *string) Op {
 			} 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))
+				*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, FmtShort|FmtByte), missing.Sym, Tconv(missing.Type, FmtShort|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))
+				*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, FmtShort|FmtByte), missing.Sym, Tconv(missing.Type, FmtShort|FmtByte))
 			} else {
 				*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
 			}
@@ -1107,10 +819,9 @@ func assignop(src *Type, dst *Type, why *string) Op {
 		return 0
 	}
 
-	if src.Etype == TINTER && dst.Etype != TBLANK {
-		var have *Type
+	if src.IsInterface() && dst.Etype != TBLANK {
+		var missing, have *Field
 		var ptr int
-		var missing *Type
 		if why != nil && implements(dst, src, &missing, &have, &ptr) {
 			*why = ": need type assertion"
 		}
@@ -1120,8 +831,8 @@ func assignop(src *Type, dst *Type, why *string) Op {
 	// 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) {
+	if src.IsChan() && src.ChanDir() == Cboth && dst.IsChan() {
+		if Eqtype(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
 			return OCONVNOP
 		}
 	}
@@ -1129,18 +840,13 @@ func assignop(src *Type, dst *Type, why *string) Op {
 	// 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:
+			TINTER,
+			TSLICE:
 			return OCONVNOP
 		}
 	}
@@ -1177,10 +883,10 @@ func convertop(src *Type, dst *Type, why *string) Op {
 	}
 
 	// The rules for interfaces are no different in conversions
-	// than assignments.  If interfaces are involved, stop now
+	// 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 {
+	if src.IsInterface() || dst.IsInterface() {
 		return 0
 	}
 	if why != nil {
@@ -1194,14 +900,14 @@ func convertop(src *Type, dst *Type, why *string) Op {
 
 	// 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) {
+	if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil {
+		if Eqtype(src.Elem().Orig, dst.Elem().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 (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
 		if Simtype[src.Etype] == Simtype[dst.Etype] {
 			return OCONVNOP
 		}
@@ -1209,7 +915,7 @@ func convertop(src *Type, dst *Type, why *string) Op {
 	}
 
 	// 5. src and dst are both complex types.
-	if Iscomplex[src.Etype] && Iscomplex[dst.Etype] {
+	if src.IsComplex() && dst.IsComplex() {
 		if Simtype[src.Etype] == Simtype[dst.Etype] {
 			return OCONVNOP
 		}
@@ -1218,37 +924,37 @@ func convertop(src *Type, dst *Type, why *string) Op {
 
 	// 6. src is an integer or has type []byte or []rune
 	// and dst is a string type.
-	if Isint[src.Etype] && dst.Etype == TSTRING {
+	if src.IsInteger() && dst.IsString() {
 		return ORUNESTR
 	}
 
-	if Isslice(src) && dst.Etype == TSTRING {
-		if src.Type.Etype == bytetype.Etype {
+	if src.IsSlice() && dst.IsString() {
+		if src.Elem().Etype == bytetype.Etype {
 			return OARRAYBYTESTR
 		}
-		if src.Type.Etype == runetype.Etype {
+		if src.Elem().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 {
+	if src.IsString() && dst.IsSlice() {
+		if dst.Elem().Etype == bytetype.Etype {
 			return OSTRARRAYBYTE
 		}
-		if dst.Type.Etype == runetype.Etype {
+		if dst.Elem().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 {
+	if (src.IsPtr() || 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) {
+	if src.Etype == TUNSAFEPTR && (dst.IsPtr() || dst.Etype == TUINTPTR) {
 		return OCONVNOP
 	}
 
@@ -1271,7 +977,7 @@ func assignconvfn(n *Node, t *Type, context func() string) *Node {
 
 	old := n
 	old.Diag++ // silence errors about n; we'll issue one below
-	defaultlit(&n, t)
+	n = defaultlit(n, t)
 	old.Diag--
 	if t.Etype == TBLANK {
 		return n
@@ -1279,7 +985,7 @@ func assignconvfn(n *Node, t *Type, context func() string) *Node {
 
 	// 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.Type == idealbool && !t.IsBoolean() {
 		if n.Op == ONAME || n.Op == OLITERAL {
 			r := Nod(OCONVNOP, n, nil)
 			r.Type = Types[TBOOL]
@@ -1296,7 +1002,7 @@ func assignconvfn(n *Node, t *Type, context func() string) *Node {
 	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)
+		Yyerror("cannot use %v as type %v in %s%s", Nconv(n, FmtLong), t, context(), why)
 		op = OCONV
 	}
 
@@ -1308,69 +1014,78 @@ func assignconvfn(n *Node, t *Type, context func() string) *Node {
 	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)
+// Is this a 64-bit type?
+func Is64(t *Type) bool {
+	if t == nil {
+		return false
 	}
-	substAny(&n.Type, &types)
-	if len(types) > 0 {
-		Fatalf("substArgTypes: too many argument types")
+	switch Simtype[t.Etype] {
+	case TINT64, TUINT64, TPTR64:
+		return true
 	}
+
+	return false
 }
 
-// substAny walks *tp, replacing instances of "any" with successive
-// elements removed from types.
-func substAny(tp **Type, types *[]*Type) {
-	for {
-		t := *tp
-		if t == nil {
-			return
+// SliceBounds returns n's slice bounds: low, high, and max in expr[low:high:max].
+// n must be a slice expression. max is nil if n is a simple slice expression.
+func (n *Node) SliceBounds() (low, high, max *Node) {
+	switch n.Op {
+	case OSLICE, OSLICEARR, OSLICESTR:
+		if n.Right == nil {
+			return nil, nil, nil
 		}
-		if t.Etype == TANY && t.Copyany {
-			if len(*types) == 0 {
-				Fatalf("substArgTypes: not enough argument types")
-			}
-			*tp = (*types)[0]
-			*types = (*types)[1:]
+		if n.Right.Op != OKEY {
+			Fatalf("SliceBounds right %s", opnames[n.Right.Op])
 		}
+		return n.Right.Left, n.Right.Right, nil
+	case OSLICE3, OSLICE3ARR:
+		if n.Right.Op != OKEY || n.Right.Right.Op != OKEY {
+			Fatalf("SliceBounds right %s %s", opnames[n.Right.Op], opnames[n.Right.Right.Op])
+		}
+		return n.Right.Left, n.Right.Right.Left, n.Right.Right.Right
+	}
+	Fatalf("SliceBounds op %s: %v", n.Op, n)
+	return nil, nil, nil
+}
 
-		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)
-			}
+// SetSliceBounds sets n's slice bounds, where n is a slice expression.
+// n must be a slice expression. If max is non-nil, n must be a full slice expression.
+func (n *Node) SetSliceBounds(low, high, max *Node) {
+	switch n.Op {
+	case OSLICE, OSLICEARR, OSLICESTR:
+		if max != nil {
+			Fatalf("SetSliceBounds %s given three bounds", n.Op)
 		}
+		if n.Right == nil {
+			n.Right = Nod(OKEY, low, high)
+			return
+		}
+		n.Right.Left = low
+		n.Right.Right = high
+		return
+	case OSLICE3, OSLICE3ARR:
+		if n.Right == nil {
+			n.Right = Nod(OKEY, low, Nod(OKEY, high, max))
+		}
+		n.Right.Left = low
+		n.Right.Right.Left = high
+		n.Right.Right.Right = max
 		return
 	}
+	Fatalf("SetSliceBounds op %s: %v", n.Op, n)
 }
 
-// Is this a 64-bit type?
-func Is64(t *Type) bool {
-	if t == nil {
+// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).
+// o must be a slicing op.
+func (o Op) IsSlice3() bool {
+	switch o {
+	case OSLICE, OSLICEARR, OSLICESTR:
 		return false
-	}
-	switch Simtype[t.Etype] {
-	case TINT64, TUINT64, TPTR64:
+	case OSLICE3, OSLICE3ARR:
 		return true
 	}
-
+	Fatalf("IsSlice3 op %v", o)
 	return false
 }
 
@@ -1402,108 +1117,28 @@ func Noconv(t1 *Type, t2 *Type) bool {
 	return false
 }
 
-func shallow(t *Type) *Type {
-	if t == nil {
-		return nil
-	}
-	nt := typ(0)
-	*nt = *t
-	if t.Orig == t {
-		nt.Orig = nt
+func syslook(name string) *Node {
+	s := Pkglookup(name, Runtimepkg)
+	if s == nil || s.Def == nil {
+		Fatalf("syslook: can't find runtime.%s", name)
 	}
-	return nt
+	return s.Def
 }
 
-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 = true
-
-	case TPTR32, TPTR64, TCHAN, TARRAY:
-		nt = shallow(t)
-		nt.Type = deep(t.Type)
+// typehash computes a hash value for type t to use in type switch
+// statements.
+func typehash(t *Type) uint32 {
+	// Tconv already contains all the necessary logic to generate
+	// a representation that completely describes the type, so using
+	// it here avoids duplicating that code.
+	p := Tconv(t, FmtLeft|FmtUnsigned)
 
-	case TMAP:
-		nt = shallow(t)
-		nt.Down = deep(t.Down)
-		nt.Type = deep(t.Type)
+	// Using MD5 is overkill, but reduces accidental collisions.
+	h := md5.Sum([]byte(p))
+	return binary.LittleEndian.Uint32(h[:4])
+}
 
-	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 {
-		Fatalf("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 initPtrtoDone bool
 
 var (
 	ptrToUint8  *Type
@@ -1514,19 +1149,11 @@ var (
 )
 
 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
+	ptrToUint8 = typPtr(Types[TUINT8])
+	ptrToAny = typPtr(Types[TANY])
+	ptrToString = typPtr(Types[TSTRING])
+	ptrToBool = typPtr(Types[TBOOL])
+	ptrToInt32 = typPtr(Types[TINT32])
 }
 
 // Ptrto returns the Type *t.
@@ -1552,7 +1179,7 @@ func Ptrto(t *Type) *Type {
 	case Types[TBOOL]:
 		return ptrToBool
 	}
-	return ptrto1(t)
+	return typPtr(t)
 }
 
 func frame(context int) {
@@ -1566,8 +1193,8 @@ func frame(context int) {
 
 	if Curfn != nil {
 		fmt.Printf("--- %v frame ---\n", Curfn.Func.Nname.Sym)
-		for l := Curfn.Func.Dcl; l != nil; l = l.Next {
-			printframenode(l.N)
+		for _, ln := range Curfn.Func.Dcl {
+			printframenode(ln)
 		}
 	}
 }
@@ -1579,9 +1206,9 @@ func printframenode(n *Node) {
 	}
 	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)
+		fmt.Printf("%v %v G%d %v width=%d\n", n.Op, 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)
+		fmt.Printf("%v %v width=%d\n", n.Op, n.Type, w)
 	}
 }
 
@@ -1596,7 +1223,7 @@ func ullmancalc(n *Node) {
 
 	var ul int
 	var ur int
-	if n.Ninit != nil {
+	if n.Ninit.Len() != 0 {
 		ul = UINF
 		goto out
 	}
@@ -1604,7 +1231,7 @@ func ullmancalc(n *Node) {
 	switch n.Op {
 	case OREGISTER, OLITERAL, ONAME:
 		ul = 1
-		if n.Class == PPARAMREF || (n.Class&PHEAP != 0) {
+		if n.Class == PAUTOHEAP {
 			ul++
 		}
 		goto out
@@ -1653,138 +1280,16 @@ func badtype(op Op, tl *Type, tr *Type) {
 	}
 
 	// 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 {
+	if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
+		if tl.Elem().IsStruct() && tr.Elem().IsInterface() {
 			fmt_ += "\n\t(*struct vs *interface)"
-		} else if tl.Type.Etype == TINTER && tr.Type.Etype == TSTRUCT {
+		} else if tl.Elem().IsInterface() && tr.Elem().IsStruct() {
 			fmt_ += "\n\t(*interface vs *struct)"
 		}
 	}
 
 	s := fmt_
-	Yyerror("illegal types for operand: %v%s", Oconv(int(op), 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 {
-		Fatalf("structfirst: not field %v", t)
-	}
-
-	s.T = t
-	return t
-
-bad:
-	Fatalf("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 {
-		Fatalf("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:
-	Fatalf("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 {
-		Fatalf("getthis: not a func %v", t)
-	}
-	return &t.Type
-}
-
-func Getoutarg(t *Type) **Type {
-	if t.Etype != TFUNC {
-		Fatalf("getoutarg: not a func %v", t)
-	}
-	return &t.Type.Down
-}
-
-func getinarg(t *Type) **Type {
-	if t.Etype != TFUNC {
-		Fatalf("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)
+	Yyerror("illegal types for operand: %v%s", op, s)
 }
 
 // Brcom returns !(op).
@@ -1804,7 +1309,7 @@ func Brcom(op Op) Op {
 	case OGE:
 		return OLT
 	}
-	Fatalf("brcom: no com for %v\n", Oconv(int(op), 0))
+	Fatalf("brcom: no com for %v\n", op)
 	return op
 }
 
@@ -1825,21 +1330,20 @@ func Brrev(op Op) Op {
 	case OGE:
 		return OLE
 	}
-	Fatalf("brrev: no rev for %v\n", Oconv(int(op), 0))
+	Fatalf("brrev: no rev for %v\n", op)
 	return op
 }
 
 // return side effect-free n, appending side effects to init.
 // result is assignable if n is.
-func safeexpr(n *Node, init **NodeList) *Node {
+func safeexpr(n *Node, init *Nodes) *Node {
 	if n == nil {
 		return nil
 	}
 
-	if n.Ninit != nil {
-		walkstmtlist(n.Ninit)
-		*init = concat(*init, n.Ninit)
-		n.Ninit = nil
+	if n.Ninit.Len() != 0 {
+		walkstmtlist(n.Ninit.Slice())
+		init.AppendNodes(&n.Ninit)
 	}
 
 	switch n.Op {
@@ -1854,8 +1358,8 @@ func safeexpr(n *Node, init **NodeList) *Node {
 		r := Nod(OXXX, nil, nil)
 		*r = *n
 		r.Left = l
-		typecheck(&r, Erv)
-		walkexpr(&r, init)
+		r = typecheck(r, Erv)
+		r = walkexpr(r, init)
 		return r
 
 	case ODOTPTR, OIND:
@@ -1866,7 +1370,7 @@ func safeexpr(n *Node, init **NodeList) *Node {
 		a := Nod(OXXX, nil, nil)
 		*a = *n
 		a.Left = l
-		walkexpr(&a, init)
+		a = walkexpr(a, init)
 		return a
 
 	case OINDEX, OINDEXMAP:
@@ -1879,8 +1383,13 @@ func safeexpr(n *Node, init **NodeList) *Node {
 		*a = *n
 		a.Left = l
 		a.Right = r
-		walkexpr(&a, init)
+		a = walkexpr(a, init)
 		return a
+
+	case OSTRUCTLIT, OARRAYLIT:
+		if isStaticCompositeLiteral(n) {
+			return n
+		}
 	}
 
 	// make a copy; must not be used as an lvalue
@@ -1890,18 +1399,18 @@ func safeexpr(n *Node, init **NodeList) *Node {
 	return cheapexpr(n, init)
 }
 
-func copyexpr(n *Node, t *Type, init **NodeList) *Node {
+func copyexpr(n *Node, t *Type, init *Nodes) *Node {
 	l := temp(t)
 	a := Nod(OAS, l, n)
-	typecheck(&a, Etop)
-	walkexpr(&a, init)
-	*init = list(*init, a)
+	a = typecheck(a, Etop)
+	a = walkexpr(a, init)
+	init.Append(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 {
+func cheapexpr(n *Node, init *Nodes) *Node {
 	switch n.Op {
 	case ONAME, OLITERAL:
 		return n
@@ -1912,7 +1421,7 @@ func cheapexpr(n *Node, init **NodeList) *Node {
 
 func Setmaxarg(t *Type, extra int32) {
 	dowidth(t)
-	w := t.Argwid
+	w := t.ArgWidth()
 	if w >= Thearch.MAXWIDTH {
 		Fatalf("bad argwid %v", t)
 	}
@@ -1925,24 +1434,32 @@ func Setmaxarg(t *Type, extra int32) {
 	}
 }
 
-// unicode-aware case-insensitive strcmp
+// Code to resolve elided DOTs in embedded types.
+
+// A Dlist stores a pointer to a TFIELD Type embedded within
+// a TSTRUCT or TINTER Type.
+type Dlist struct {
+	field *Field
+}
 
-// code to resolve elided DOTs
-// in embedded types
+// dotlist is used by adddot1 to record the path of embedded fields
+// used to access a target field or method.
+// Must be non-nil so that dotpath returns a non-nil slice even if d is zero.
+var dotlist = make([]Dlist, 10)
 
-// search depth 0 --
-// return count of fields+methods
-// found with a given name
-func lookdot0(s *Sym, t *Type, save **Type, ignorecase int) int {
+// lookdot0 returns the number of fields or methods named s associated
+// with Type t. If exactly one exists, it will be returned in *save
+// (if save is not nil).
+func lookdot0(s *Sym, t *Type, save **Field, ignorecase bool) int {
 	u := t
-	if Isptr[u.Etype] {
-		u = u.Type
+	if u.IsPtr() {
+		u = u.Elem()
 	}
 
 	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 u.IsStruct() || u.IsInterface() {
+		for _, f := range u.Fields().Slice() {
+			if f.Sym == s || (ignorecase && f.Type.Etype == TFUNC && f.Type.Recv() != nil && strings.EqualFold(f.Sym.Name, s.Name)) {
 				if save != nil {
 					*save = f
 				}
@@ -1953,8 +1470,8 @@ func lookdot0(s *Sym, t *Type, save **Type, ignorecase int) int {
 
 	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))) {
+		for _, f := range u.Methods().Slice() {
+			if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
 				if save != nil {
 					*save = f
 				}
@@ -1966,52 +1483,85 @@ func lookdot0(s *Sym, t *Type, save **Type, ignorecase int) int {
 	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 {
+// adddot1 returns the number of fields or methods named s at depth d in Type t.
+// If exactly one exists, it will be returned in *save (if save is not nil),
+// and dotlist will contain the path of embedded fields traversed to find it,
+// in reverse order. If none exist, more will indicate whether t contains any
+// embedded fields at depth d, so callers can decide whether to retry at
+// a greater depth.
+func adddot1(s *Sym, t *Type, d int, save **Field, ignorecase bool) (c int, more bool) {
 	if t.Trecur != 0 {
-		return 0
+		return
 	}
 	t.Trecur = 1
 
-	var c int
 	var u *Type
-	var a int
-	if d == 0 {
+	d--
+	if d < 0 {
+		// We've reached our target depth. If t has any fields/methods
+		// named s, then we're done. Otherwise, we still need to check
+		// below for embedded fields.
 		c = lookdot0(s, t, save, ignorecase)
-		goto out
+		if c != 0 {
+			goto out
+		}
 	}
 
-	c = 0
 	u = t
-	if Isptr[u.Etype] {
-		u = u.Type
+	if u.IsPtr() {
+		u = u.Elem()
 	}
-	if u.Etype != TSTRUCT && u.Etype != TINTER {
+	if !u.IsStruct() && !u.IsInterface() {
 		goto out
 	}
 
-	d--
-	for f := u.Type; f != nil; f = f.Down {
-		if f.Embedded == 0 {
+	for _, f := range u.Fields().Slice() {
+		if f.Embedded == 0 || f.Sym == nil {
 			continue
 		}
-		if f.Sym == nil {
-			continue
+		if d < 0 {
+			// Found an embedded field at target depth.
+			more = true
+			goto out
 		}
-		a = adddot1(s, f.Type, d, save, ignorecase)
+		a, more1 := adddot1(s, f.Type, d, save, ignorecase)
 		if a != 0 && c == 0 {
 			dotlist[d].field = f
 		}
 		c += a
+		if more1 {
+			more = true
+		}
 	}
 
 out:
 	t.Trecur = 0
-	return c
+	return c, more
+}
+
+// dotpath computes the unique shortest explicit selector path to fully qualify
+// a selection expression x.f, where x is of type t and f is the symbol s.
+// If no such path exists, dotpath returns nil.
+// If there are multiple shortest paths to the same depth, ambig is true.
+func dotpath(s *Sym, t *Type, save **Field, ignorecase bool) (path []Dlist, ambig bool) {
+	// The embedding of types within structs imposes a tree structure onto
+	// types: structs parent the types they embed, and types parent their
+	// fields or methods. Our goal here is to find the shortest path to
+	// a field or method named s in the subtree rooted at t. To accomplish
+	// that, we iteratively perform depth-first searches of increasing depth
+	// until we either find the named field/method or exhaust the tree.
+	for d := 0; ; d++ {
+		if d > len(dotlist) {
+			dotlist = append(dotlist, Dlist{})
+		}
+		if c, more := adddot1(s, t, d, save, ignorecase); c == 1 {
+			return dotlist[:d], false
+		} else if c > 1 {
+			return nil, true
+		} else if !more {
+			return nil, false
+		}
+	}
 }
 
 // in T.field
@@ -2019,7 +1569,7 @@ out:
 // will give shortest unique addressing.
 // modify the tree with missing type names.
 func adddot(n *Node) *Node {
-	typecheck(&n.Left, Etype|Erv)
+	n.Left = typecheck(n.Left, Etype|Erv)
 	n.Diag |= n.Left.Diag
 	t := n.Left.Type
 	if t == nil {
@@ -2030,32 +1580,21 @@ func adddot(n *Node) *Node {
 		return n
 	}
 
-	if n.Right.Op != ONAME {
-		return n
-	}
-	s := n.Right.Sym
+	s := n.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
+	switch path, ambig := dotpath(s, t, nil, false); {
+	case path != nil:
+		// rebuild elided dots
+		for c := len(path) - 1; c >= 0; c-- {
+			n.Left = NodSym(ODOT, n.Left, path[c].field.Sym)
+			n.Left.Implicit = true
 		}
+	case ambig:
+		Yyerror("ambiguous selector %v", n)
+		n.Left = nil
 	}
 
 	return n
@@ -2070,33 +1609,26 @@ func adddot(n *Node) *Node {
 // with unique tasks and they return
 // the actual methods.
 type Symlink struct {
-	field     *Type
-	link      *Symlink
-	good      bool
+	field     *Field
 	followptr bool
 }
 
-var slist *Symlink
+var slist []Symlink
 
 func expand0(t *Type, followptr bool) {
 	u := t
-	if Isptr[u.Etype] {
+	if u.IsPtr() {
 		followptr = true
-		u = u.Type
+		u = u.Elem()
 	}
 
-	if u.Etype == TINTER {
-		var sl *Symlink
-		for f := u.Type; f != nil; f = f.Down {
+	if u.IsInterface() {
+		for _, f := range u.Fields().Slice() {
 			if f.Sym.Flags&SymUniq != 0 {
 				continue
 			}
 			f.Sym.Flags |= SymUniq
-			sl = new(Symlink)
-			sl.field = f
-			sl.link = slist
-			sl.followptr = followptr
-			slist = sl
+			slist = append(slist, Symlink{field: f, followptr: followptr})
 		}
 
 		return
@@ -2104,52 +1636,44 @@ func expand0(t *Type, followptr bool) {
 
 	u = methtype(t, 0)
 	if u != nil {
-		var sl *Symlink
-		for f := u.Method; f != nil; f = f.Down {
+		for _, f := range u.Methods().Slice() {
 			if f.Sym.Flags&SymUniq != 0 {
 				continue
 			}
 			f.Sym.Flags |= SymUniq
-			sl = new(Symlink)
-			sl.field = f
-			sl.link = slist
-			sl.followptr = followptr
-			slist = sl
+			slist = append(slist, Symlink{field: f, followptr: followptr})
 		}
 	}
 }
 
-func expand1(t *Type, d int, followptr bool) {
+func expand1(t *Type, top, followptr bool) {
 	if t.Trecur != 0 {
 		return
 	}
-	if d == 0 {
-		return
-	}
 	t.Trecur = 1
 
-	if d != len(dotlist)-1 {
+	if !top {
 		expand0(t, followptr)
 	}
 
 	u := t
-	if Isptr[u.Etype] {
+	if u.IsPtr() {
 		followptr = true
-		u = u.Type
+		u = u.Elem()
 	}
 
-	if u.Etype != TSTRUCT && u.Etype != TINTER {
+	if !u.IsStruct() && !u.IsInterface() {
 		goto out
 	}
 
-	for f := u.Type; f != nil; f = f.Down {
+	for _, f := range u.Fields().Slice() {
 		if f.Embedded == 0 {
 			continue
 		}
 		if f.Sym == nil {
 			continue
 		}
-		expand1(f.Type, d-1, followptr)
+		expand1(f.Type, false, followptr)
 	}
 
 out:
@@ -2157,91 +1681,73 @@ out:
 }
 
 func expandmeth(t *Type) {
-	if t == nil || t.Xmethod != nil {
+	if t == nil || t.AllMethods().Len() != 0 {
 		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 {
+	for _, f := range t.Methods().Slice() {
 		f.Sym.Flags |= SymUniq
 	}
 
 	// generate all reachable methods
-	slist = nil
-
-	expand1(t, len(dotlist)-1, false)
+	slist = slist[:0]
+	expand1(t, true, false)
 
 	// check each method to be uniquely reachable
-	var c int
-	var d int
-	for sl := slist; sl != nil; sl = sl.link {
+	var ms []*Field
+	for i, sl := range slist {
+		slist[i].field = nil
 		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 = true
-					sl.field = f
-				}
-			}
 
-			break
+		var f *Field
+		if path, _ := dotpath(sl.field.Sym, t, &f, false); path == nil {
+			continue
 		}
+
+		// dotpath may have dug out arbitrary fields, we only want methods.
+		if f.Type.Etype != TFUNC || f.Type.Recv() == nil {
+			continue
+		}
+
+		// add it to the base type method list
+		f = f.Copy()
+		f.Embedded = 1 // needs a trampoline
+		if sl.followptr {
+			f.Embedded = 2
+		}
+		ms = append(ms, f)
 	}
 
-	for f = t.Method; f != nil; f = f.Down {
+	for _, f := range t.Methods().Slice() {
 		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
-		}
-	}
+	ms = append(ms, t.Methods().Slice()...)
+	t.AllMethods().Set(ms)
 }
 
 // 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
+func structargs(tl *Type, mustname bool) []*Node {
+	var args []*Node
 	gen := 0
-	for t := Structfirst(&savet, tl); t != nil; t = structnext(&savet) {
-		n = nil
-		if mustname != 0 && (t.Sym == nil || t.Sym.Name == "_") {
+	for _, t := range tl.Fields().Slice() {
+		var n *Node
+		if mustname && (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)
+			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 := Nod(ODCLFIELD, n, typenod(t.Type))
 		a.Isddd = t.Isddd
 		if n != nil {
 			n.Isddd = t.Isddd
 		}
-		args = list(args, a)
+		args = append(args, a)
 	}
 
 	return args
@@ -2271,7 +1777,7 @@ func structargs(tl **Type, mustname int) *NodeList {
 
 var genwrapper_linehistdone int = 0
 
-func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
+func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
 	if false && Debug['r'] != 0 {
 		fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
 	}
@@ -2290,27 +1796,24 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
 
 	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)
+	in := structargs(method.Type.Params(), true)
+	out := structargs(method.Type.Results(), false)
 
 	t := Nod(OTFUNC, nil, nil)
-	l := list1(this)
+	l := []*Node{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
+		tpad := typArray(Types[TUINT8], Types[Tptr].Width-rcvr.Width)
 		pad := Nod(ODCLFIELD, newname(Lookup(".pad")), typenod(tpad))
-		l = list(l, pad)
+		l = append(l, pad)
 	}
 
-	t.List = concat(l, in)
-	t.Rlist = out
+	t.List.Set(append(l, in...))
+	t.Rlist.Set(out)
 
 	fn := Nod(ODCLFUNC, nil, nil)
 	fn.Func.Nname = newname(newnam)
@@ -2320,18 +1823,18 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
 	funchdr(fn)
 
 	// arg list
-	var args *NodeList
+	var args []*Node
 
 	isddd := false
-	for l := in; l != nil; l = l.Next {
-		args = list(args, l.N.Left)
-		isddd = l.N.Left.Isddd
+	for _, n := range in {
+		args = append(args, n.Left)
+		isddd = n.Left.Isddd
 	}
 
-	methodrcvr := getthisx(method.Type).Type.Type
+	methodrcvr := method.Type.Recv().Type
 
 	// generate nil pointer check for better error
-	if Isptr[rcvr.Etype] && rcvr.Type == methodrcvr {
+	if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
 		// generating wrapper from *T to T.
 		n := Nod(OIF, nil, nil)
 
@@ -2339,48 +1842,55 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
 
 		// these strings are already in the reflect tables,
 		// so no space cost to use them here.
-		var l *NodeList
+		var l []*Node
 
 		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 = rcvr.Elem().Sym.Pkg.Name // package name
+		l = append(l, nodlit(v))
+		v.U = rcvr.Elem().Sym.Name // type name
+		l = append(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)
+		l = append(l, nodlit(v)) // method name
+		call := Nod(OCALL, syslook("panicwrap"), nil)
+		call.List.Set(l)
+		n.Nbody.Set1(call)
+		fn.Nbody.Append(n)
 	}
 
-	dot := adddot(Nod(OXDOT, this.Left, newname(method.Sym)))
+	dot := adddot(NodSym(OXDOT, this.Left, method.Sym))
 
 	// generate call
-	if !instrumenting && Isptr[rcvr.Etype] && Isptr[methodrcvr.Etype] && method.Embedded != 0 && !isifacemethod(method.Type) {
+	// It's not possible to use a tail call when dynamic linking on ppc64le. The
+	// bad scenario is when a local call is made to the wrapper: the wrapper will
+	// call the implementation, which might be in a different module and so set
+	// the TOC to the appropriate value for that module. But if it returns
+	// directly to the wrapper's caller, nothing will reset it to the correct
+	// value for that function.
+	if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) && !(Thearch.LinkArch.Name == "ppc64le" && Ctxt.Flag_dynlink) {
 		// generate tail call: adjust pointer receiver and jump to embedded method.
 		dot = dot.Left // skip final .M
-		if !Isptr[dotlist[0].field.Type.Etype] {
+		// TODO(mdempsky): Remove dependency on dotlist.
+		if !dotlist[0].field.Type.IsPtr() {
 			dot = Nod(OADDR, dot, nil)
 		}
 		as := Nod(OAS, this.Left, Nod(OCONVNOP, dot, nil))
 		as.Right.Type = rcvr
-		fn.Nbody = list(fn.Nbody, as)
+		fn.Nbody.Append(as)
 		n := Nod(ORETJMP, nil, nil)
 		n.Left = newname(methodsym(method.Sym, methodrcvr, 0))
-		fn.Nbody = list(fn.Nbody, n)
+		fn.Nbody.Append(n)
 	} else {
 		fn.Func.Wrapper = true // ignore frame for panic+recover matching
 		call := Nod(OCALL, dot, nil)
-		call.List = args
+		call.List.Set(args)
 		call.Isddd = isddd
-		if method.Type.Outtuple > 0 {
+		if method.Type.Results().NumFields() > 0 {
 			n := Nod(ORETURN, nil, nil)
-			n.List = list1(call)
+			n.List.Set1(call)
 			call = n
 		}
 
-		fn.Nbody = list(fn.Nbody, call)
+		fn.Nbody.Append(call)
 	}
 
 	if false && Debug['r'] != 0 {
@@ -2389,13 +1899,15 @@ func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
 
 	funcbody(fn)
 	Curfn = fn
+	popdcl()
+	testdclstack()
 
 	// 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 {
+	if rcvr.IsStruct() || rcvr.IsInterface() || rcvr.IsPtr() && rcvr.Elem().IsStruct() {
 		fn.Func.Dupok = true
 	}
-	typecheck(&fn, Etop)
-	typechecklist(fn.Nbody, Etop)
+	fn = typecheck(fn, Etop)
+	typecheckslice(fn.Nbody.Slice(), Etop)
 
 	inlcalls(fn)
 	escAnalyze([]*Node{fn}, false)
@@ -2410,487 +1922,47 @@ func hashmem(t *Type) *Node {
 	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:
-		Fatalf("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)
+	tfn.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
+	tfn.List.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	tfn.List.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	tfn.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	tfn = 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:
-		Fatalf("genhash %v", t)
-
-	case TARRAY:
-		if Isslice(t) {
-			Fatalf("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
-
-		// 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:
-		Fatalf("geneq %v", t)
-
-	case TARRAY:
-		if Isslice(t) {
-			Fatalf("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 *bool, ignorecase int) *Type {
+func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase bool) *Field {
 	*followptr = false
 
 	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 {
+	var m *Field
+	path, ambig := dotpath(s, t, &m, ignorecase)
+	if path == nil {
+		if ambig {
 			Yyerror("%v.%v is ambiguous", t, s)
-			return nil
 		}
+		return nil
+	}
 
-		if c == 1 {
-			for i = 0; i < d; i++ {
-				if Isptr[dotlist[i].field.Type.Etype] {
-					*followptr = true
-					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
+	for _, d := range path {
+		if d.field.Type.IsPtr() {
+			*followptr = true
+			break
 		}
 	}
 
-	return nil
+	if m.Type.Etype != TFUNC || m.Type.Recv() == nil {
+		Yyerror("%v.%v is a field, not a method", t, s)
+		return nil
+	}
+
+	return m
 }
 
-func implements(t *Type, iface *Type, m **Type, samename **Type, ptr *int) bool {
+func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
 	t0 := t
 	if t == nil {
 		return false
@@ -2900,10 +1972,9 @@ func implements(t *Type, iface *Type, m **Type, samename **Type, ptr *int) bool
 	// 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 t.IsInterface() {
+		for _, im := range iface.Fields().Slice() {
+			for _, tm := range t.Fields().Slice() {
 				if tm.Sym == im.Sym {
 					if Eqtype(tm.Type, im.Type) {
 						goto found
@@ -2929,19 +2000,15 @@ func implements(t *Type, iface *Type, m **Type, samename **Type, ptr *int) bool
 	if t != nil {
 		expandmeth(t)
 	}
-	var tm *Type
-	var imtype *Type
-	var followptr bool
-	var rcvr *Type
-	for im := iface.Type; im != nil; im = im.Down {
+	for _, im := range iface.Fields().Slice() {
 		if im.Broke {
 			continue
 		}
-		imtype = methodfunc(im.Type, nil)
-		tm = ifacelookdot(im.Sym, t, &followptr, 0)
-		if tm == nil || tm.Nointerface || !Eqtype(methodfunc(tm.Type, nil), imtype) {
+		var followptr bool
+		tm := ifacelookdot(im.Sym, t, &followptr, false)
+		if tm == nil || tm.Nointerface || !Eqtype(tm.Type, im.Type) {
 			if tm == nil {
-				tm = ifacelookdot(im.Sym, t, &followptr, 1)
+				tm = ifacelookdot(im.Sym, t, &followptr, true)
 			}
 			*m = im
 			*samename = tm
@@ -2951,9 +2018,9 @@ func implements(t *Type, iface *Type, m **Type, samename **Type, ptr *int) bool
 
 		// if pointer receiver in method,
 		// the method does not exist for value types.
-		rcvr = getthisx(tm.Type).Type.Type
+		rcvr := tm.Type.Recv().Type
 
-		if Isptr[rcvr.Etype] && !Isptr[t0.Etype] && !followptr && !isifacemethod(tm.Type) {
+		if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
 			if false && Debug['r'] != 0 {
 				Yyerror("interface pointer mismatch")
 			}
@@ -2991,34 +2058,23 @@ func Simsimtype(t *Type) EType {
 	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))
+func listtreecopy(l []*Node, lineno int32) []*Node {
+	var out []*Node
+	for _, n := range l {
+		out = append(out, treecopy(n, lineno))
 	}
 	return out
 }
 
-func liststmt(l *NodeList) *Node {
+func liststmt(l []*Node) *Node {
 	n := Nod(OBLOCK, nil, nil)
-	n.List = l
-	if l != nil {
-		n.Lineno = l.N.Lineno
+	n.List.Set(l)
+	if len(l) != 0 {
+		n.Lineno = l[0].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)
@@ -3026,11 +2082,11 @@ func powtwo(n *Node) int {
 	if n == nil || n.Op != OLITERAL || n.Type == nil {
 		return -1
 	}
-	if !Isint[n.Type.Etype] {
+	if !n.Type.IsInteger() {
 		return -1
 	}
 
-	v := uint64(Mpgetfix(n.Val().U.(*Mpint)))
+	v := uint64(n.Int64())
 	b := uint64(1)
 	for i := 0; i < 64; i++ {
 		if b == v {
@@ -3039,7 +2095,7 @@ func powtwo(n *Node) int {
 		b = b << 1
 	}
 
-	if !Issigned[n.Type.Etype] {
+	if !n.Type.IsSigned() {
 		return -1
 	}
 
@@ -3086,202 +2142,6 @@ func tounsigned(t *Type) *Type {
 	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)
@@ -3290,8 +2150,8 @@ func ngotype(n *Node) *Sym {
 }
 
 // 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
+// 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.
 //
@@ -3333,25 +2193,25 @@ func mkpkg(path string) *Pkg {
 	return p
 }
 
-func addinit(np **Node, init *NodeList) {
-	if init == nil {
-		return
+// The result of addinit MUST be assigned back to n, e.g.
+// 	n.Left = addinit(n.Left, init)
+func addinit(n *Node, init []*Node) *Node {
+	if len(init) == 0 {
+		return n
 	}
 
-	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.Ninit.Set(append(init, n.Ninit.Slice()...))
 	n.Ullman = UINF
+	return n
 }
 
 var reservedimports = []string{
@@ -3388,7 +2248,7 @@ func isbadimport(path string) bool {
 			return true
 		}
 
-		if unicode.IsSpace(rune(r)) {
+		if unicode.IsSpace(r) {
 			Yyerror("import path contains space character: %q", path)
 			return true
 		}
@@ -3402,15 +2262,16 @@ func isbadimport(path string) bool {
 	return false
 }
 
-func checknil(x *Node, init **NodeList) {
-	if Isinter(x.Type) {
+func checknil(x *Node, init *Nodes) {
+	x = walkexpr(x, nil) // caller has not done this yet
+	if x.Type.IsInterface() {
 		x = Nod(OITAB, x, nil)
-		typecheck(&x, Erv)
+		x = typecheck(x, Erv)
 	}
 
 	n := Nod(OCHECKNIL, x, nil)
 	n.Typecheck = 1
-	*init = list(*init, n)
+	init.Append(n)
 }
 
 // Can this type be stored directly in an interface word?
@@ -3425,27 +2286,27 @@ func isdirectiface(t *Type) bool {
 		TUNSAFEPTR:
 		return true
 
-		// Array of 1 direct iface type can be direct.
 	case TARRAY:
-		return t.Bound == 1 && isdirectiface(t.Type)
+		// Array of 1 direct iface type can be direct.
+		return t.NumElem() == 1 && isdirectiface(t.Elem())
 
-		// 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)
+		// Struct with 1 field of direct iface type can be direct.
+		return t.NumFields() == 1 && isdirectiface(t.Field(0).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.
+// iet 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"
+func (t *Type) iet() byte {
+	if t.IsEmptyInterface() {
+		return 'E'
 	}
-	if Isinter(t) {
-		return "I"
+	if t.IsInterface() {
+		return 'I'
 	}
-	return "T"
+	return 'T'
 }
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index f0433f3..4940c97 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -5,7 +5,6 @@
 package gc
 
 import (
-	"cmd/internal/obj"
 	"sort"
 	"strconv"
 )
@@ -58,8 +57,8 @@ type caseClause struct {
 
 // typecheckswitch typechecks a switch statement.
 func typecheckswitch(n *Node) {
-	lno := int(lineno)
-	typechecklist(n.Ninit, Etop)
+	lno := lineno
+	typecheckslice(n.Ninit.Slice(), Etop)
 
 	var nilonly string
 	var top int
@@ -68,35 +67,36 @@ func typecheckswitch(n *Node) {
 	if n.Left != nil && n.Left.Op == OTYPESW {
 		// type switch
 		top = Etype
-		typecheck(&n.Left.Right, Erv)
+		n.Left.Right = 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))
+		if t != nil && !t.IsInterface() {
+			Yyerror("cannot type switch on non-interface value %v", Nconv(n.Left.Right, FmtLong))
 		}
 	} else {
 		// expression switch
 		top = Erv
 		if n.Left != nil {
-			typecheck(&n.Left, Erv)
-			defaultlit(&n.Left, nil)
+			n.Left = typecheck(n.Left, Erv)
+			n.Left = 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):
+				Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
+			case t.IsSlice():
 				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.IsArray() && !t.IsComparable():
+				Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
+			case t.IsStruct():
+				if f := t.IncomparableField(); f != nil {
+					Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, FmtLong), f.Type)
+				}
 			case t.Etype == TFUNC:
 				nilonly = "func"
-			case t.Etype == TMAP:
+			case t.IsMap():
 				nilonly = "map"
 			}
 		}
@@ -104,12 +104,10 @@ func typecheckswitch(n *Node) {
 
 	n.Type = t
 
-	var def *Node
-	var ll *NodeList
-	for l := n.List; l != nil; l = l.Next {
-		ncase := l.N
+	var def, niltype *Node
+	for _, ncase := range n.List.Slice() {
 		setlineno(n)
-		if ncase.List == nil {
+		if ncase.List.Len() == 0 {
 			// default
 			if def != nil {
 				Yyerror("multiple defaults in switch (first at %v)", def.Line())
@@ -117,47 +115,57 @@ func typecheckswitch(n *Node) {
 				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 {
+			ls := ncase.List.Slice()
+			for i1, n1 := range ls {
+				setlineno(n1)
+				ls[i1] = typecheck(ls[i1], Erv|Etype)
+				n1 = ls[i1]
+				if n1.Type == nil || t == nil {
 					continue
 				}
 				setlineno(ncase)
 				switch top {
 				// expression switch
 				case Erv:
-					defaultlit(&ll.N, t)
+					ls[i1] = defaultlit(ls[i1], t)
+					n1 = ls[i1]
 					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:
+					case n1.Op == OTYPE:
+						Yyerror("type %v is not an expression", n1.Type)
+					case n1.Type != nil && assignop(n1.Type, t, nil) == 0 && assignop(t, n1.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)
+							Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
 						} else {
-							Yyerror("invalid case %v in switch (mismatched types %v and bool)", ll.N, ll.N.Type)
+							Yyerror("invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
 						}
-					case nilonly != "" && !isnil(ll.N):
-						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", ll.N, nilonly, n.Left)
-					case Isinter(t) && !Isinter(ll.N.Type) && algtype1(ll.N.Type, nil) == ANOEQ:
-						Yyerror("invalid case %v in switch (incomparable type)", Nconv(ll.N, obj.FmtLong))
+					case nilonly != "" && !isnil(n1):
+						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
+					case t.IsInterface() && !n1.Type.IsInterface() && !n1.Type.IsComparable():
+						Yyerror("invalid case %v in switch (incomparable type)", Nconv(n1, FmtLong))
 					}
 
 				// type switch
 				case Etype:
-					var missing, have *Type
+					var missing, have *Field
 					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))
+					case n1.Op == OLITERAL && n1.Type.IsKind(TNIL):
+						// case nil:
+						if niltype != nil {
+							Yyerror("multiple nil cases in type switch (first at %v)", niltype.Line())
+						} else {
+							niltype = ncase
+						}
+					case n1.Op != OTYPE && n1.Type != nil: // should this be ||?
+						Yyerror("%v is not a type", Nconv(n1, 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):
+						n1 = n.Left.Right
+						ls[i1] = n1
+					case !n1.Type.IsInterface() && t.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr):
 						if have != nil && !missing.Broke && !have.Broke {
-							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))
+							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, FmtLong), n1.Type, missing.Sym, have.Sym, Tconv(have.Type, FmtShort), missing.Sym, Tconv(missing.Type, FmtShort))
 						} else if !missing.Broke {
-							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)
+							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Left.Right, FmtLong), n1.Type, missing.Sym)
 						}
 					}
 				}
@@ -165,26 +173,26 @@ func typecheckswitch(n *Node) {
 		}
 
 		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) {
+			ll := ncase.List
+			if ncase.Rlist.Len() != 0 {
+				nvar := ncase.Rlist.First()
+				if ll.Len() == 1 && ll.First().Type != nil && !ll.First().Type.IsKind(TNIL) {
 					// single entry type switch
-					nvar.Name.Param.Ntype = typenod(ll.N.Type)
+					nvar.Name.Param.Ntype = typenod(ll.First().Type)
 				} else {
 					// multiple entry type switch or default
 					nvar.Name.Param.Ntype = typenod(n.Type)
 				}
 
-				typecheck(&nvar, Erv|Easgn)
-				ncase.Rlist.N = nvar
+				nvar = typecheck(nvar, Erv|Easgn)
+				ncase.Rlist.SetIndex(0, nvar)
 			}
 		}
 
-		typechecklist(ncase.Nbody, Etop)
+		typecheckslice(ncase.Nbody.Slice(), Etop)
 	}
 
-	lineno = int32(lno)
+	lineno = lno
 }
 
 // walkswitch walks a switch statement.
@@ -192,7 +200,7 @@ func walkswitch(sw *Node) {
 	// convert switch {...} to switch true {...}
 	if sw.Left == nil {
 		sw.Left = Nodbool(true)
-		typecheck(&sw.Left, Erv)
+		sw.Left = typecheck(sw.Left, Erv)
 	}
 
 	if sw.Left.Op == OTYPESW {
@@ -223,14 +231,14 @@ func (s *exprSwitch) walk(sw *Node) {
 		}
 	}
 
-	walkexpr(&cond, &sw.Ninit)
+	cond = walkexpr(cond, &sw.Ninit)
 	t := sw.Type
 	if t == nil {
 		return
 	}
 
 	// convert the switch into OIF statements
-	var cas *NodeList
+	var cas []*Node
 	if s.kind == switchKindTrue || s.kind == switchKindFalse {
 		s.exprname = Nodbool(s.kind == switchKindTrue)
 	} else if consttype(cond) >= 0 {
@@ -238,13 +246,13 @@ func (s *exprSwitch) walk(sw *Node) {
 		s.exprname = cond
 	} else {
 		s.exprname = temp(cond.Type)
-		cas = list1(Nod(OAS, s.exprname, cond))
-		typechecklist(cas, Etop)
+		cas = []*Node{Nod(OAS, s.exprname, cond)}
+		typecheckslice(cas, Etop)
 	}
 
 	// enumerate the cases, and lop off the default case
 	cc := caseClauses(sw, s.kind)
-	sw.List = nil
+	sw.List.Set(nil)
 	var def *Node
 	if len(cc) > 0 && cc[0].typ == caseKindDefault {
 		def = cc[0].node.Right
@@ -258,7 +266,7 @@ func (s *exprSwitch) walk(sw *Node) {
 		// deal with expressions one at a time
 		if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst {
 			a := s.walkCases(cc[:1])
-			cas = list(cas, a)
+			cas = append(cas, a)
 			cc = cc[1:]
 			continue
 		}
@@ -271,15 +279,15 @@ func (s *exprSwitch) walk(sw *Node) {
 		// sort and compile constants
 		sort.Sort(caseClauseByExpr(cc[:run]))
 		a := s.walkCases(cc[:run])
-		cas = list(cas, a)
+		cas = append(cas, a)
 		cc = cc[run:]
 	}
 
 	// handle default case
 	if nerrors == 0 {
-		cas = list(cas, def)
-		sw.Nbody = concat(cas, sw.Nbody)
-		walkstmtlist(sw.Nbody)
+		cas = append(cas, def)
+		sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
+		walkstmtlist(sw.Nbody.Slice())
 	}
 }
 
@@ -287,26 +295,26 @@ func (s *exprSwitch) walk(sw *Node) {
 func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
 	if len(cc) < binarySearchMin {
 		// linear search
-		var cas *NodeList
+		var cas []*Node
 		for _, c := range cc {
 			n := c.node
-			lno := int(setlineno(n))
+			lno := 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)
+				a.Left = 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.Left = typecheck(a.Left, Erv)
 			}
-			a.Nbody = list1(n.Right) // goto l
+			a.Nbody.Set1(n.Right) // goto l
 
-			cas = list(cas, a)
-			lineno = int32(lno)
+			cas = append(cas, a)
+			lineno = lno
 		}
 		return liststmt(cas)
 	}
@@ -324,9 +332,9 @@ func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
 	} else {
 		a.Left = le
 	}
-	typecheck(&a.Left, Erv)
-	a.Nbody = list1(s.walkCases(cc[:half]))
-	a.Rlist = list1(s.walkCases(cc[half:]))
+	a.Left = typecheck(a.Left, Erv)
+	a.Nbody.Set1(s.walkCases(cc[:half]))
+	a.Rlist.Set1(s.walkCases(cc[half:]))
 	return a
 }
 
@@ -334,28 +342,27 @@ func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
 // 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 {
+	if sw.List.Len() == 0 {
 		return
 	}
 
 	lno := setlineno(sw)
 
-	var cas *NodeList  // cases
-	var stat *NodeList // statements
-	var def *Node      // defaults
+	var cas []*Node  // cases
+	var stat []*Node // statements
+	var def *Node    // defaults
 	br := Nod(OBREAK, nil, nil)
 
-	for l := sw.List; l != nil; l = l.Next {
-		n := l.N
+	for i, n := range sw.List.Slice() {
 		setlineno(n)
 		if n.Op != OXCASE {
-			Fatalf("casebody %v", Oconv(int(n.Op), 0))
+			Fatalf("casebody %v", n.Op)
 		}
 		n.Op = OCASE
-		needvar := count(n.List) != 1 || n.List.N.Op == OLITERAL
+		needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL
 
 		jmp := Nod(OGOTO, newCaseLabel(), nil)
-		if n.List == nil {
+		if n.List.Len() == 0 {
 			if def != nil {
 				Yyerror("more than one default case")
 			}
@@ -364,54 +371,56 @@ func casebody(sw *Node, typeswvar *Node) {
 			def = n
 		}
 
-		if n.List != nil && n.List.Next == nil {
+		if n.List.Len() == 1 {
 			// one case -- reuse OCASE node
-			n.Left = n.List.N
+			n.Left = n.List.First()
 			n.Right = jmp
-			n.List = nil
-			cas = list(cas, n)
+			n.List.Set(nil)
+			cas = append(cas, n)
 		} else {
 			// expand multi-valued cases
-			for lc := n.List; lc != nil; lc = lc.Next {
-				cas = list(cas, Nod(OCASE, lc.N, jmp))
+			for _, n1 := range n.List.Slice() {
+				cas = append(cas, Nod(OCASE, n1, 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 = append(stat, Nod(OLABEL, jmp.Left, nil))
+		if typeswvar != nil && needvar && n.Rlist.Len() != 0 {
+			l := []*Node{
+				Nod(ODCL, n.Rlist.First(), nil),
+				Nod(OAS, n.Rlist.First(), typeswvar),
+			}
+			typecheckslice(l, Etop)
+			stat = append(stat, l...)
 		}
-		stat = concat(stat, n.Nbody)
+		stat = append(stat, n.Nbody.Slice()...)
 
-		// botch - shouldn't fall thru declaration
-		last := stat.End.N
+		// botch - shouldn't fall through declaration
+		last := stat[len(stat)-1]
 		if last.Xoffset == n.Xoffset && last.Op == OXFALL {
 			if typeswvar != nil {
 				setlineno(last)
 				Yyerror("cannot fallthrough in type switch")
 			}
 
-			if l.Next == nil {
+			if i+1 >= sw.List.Len() {
 				setlineno(last)
 				Yyerror("cannot fallthrough final case in switch")
 			}
 
 			last.Op = OFALL
 		} else {
-			stat = list(stat, br)
+			stat = append(stat, br)
 		}
 	}
 
-	stat = list(stat, br)
+	stat = append(stat, br)
 	if def != nil {
-		cas = list(cas, def)
+		cas = append(cas, def)
 	}
 
-	sw.List = cas
-	sw.Nbody = stat
+	sw.List.Set(cas)
+	sw.Nbody.Set(stat)
 	lineno = lno
 }
 
@@ -430,8 +439,7 @@ func newCaseLabel() *Node {
 // 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
+	for _, n := range sw.List.Slice() {
 		c := new(caseClause)
 		cc = append(cc, c)
 		c.ordinal = len(cc)
@@ -447,7 +455,7 @@ func caseClauses(sw *Node, kind int) []*caseClause {
 			switch {
 			case n.Left.Op == OLITERAL:
 				c.typ = caseKindTypeNil
-			case Istype(n.Left.Type, TINTER):
+			case n.Left.Type.IsInterface():
 				c.typ = caseKindTypeVar
 			default:
 				c.typ = caseKindTypeConst
@@ -481,7 +489,7 @@ func caseClauses(sw *Node, kind int) []*caseClause {
 					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())
+					yyerrorl(c2.node.Lineno, "duplicate case %v in type switch\n\tprevious case at %v", c2.node.Left.Type, c1.node.Line())
 				}
 			}
 		}
@@ -516,7 +524,7 @@ func (s *typeSwitch) walk(sw *Node) {
 	sw.Left = nil
 
 	if cond == nil {
-		sw.List = nil
+		sw.List.Set(nil)
 		return
 	}
 	if cond.Right == nil {
@@ -525,46 +533,32 @@ func (s *typeSwitch) walk(sw *Node) {
 		return
 	}
 
-	walkexpr(&cond.Right, &sw.Ninit)
-	if !Istype(cond.Right.Type, TINTER) {
+	cond.Right = walkexpr(cond.Right, &sw.Ninit)
+	if !cond.Right.Type.IsInterface() {
 		Yyerror("type switch must be on an interface")
 		return
 	}
 
-	var cas *NodeList
+	var cas []*Node
 
 	// 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)
+	a = typecheck(a, Etop)
+	cas = append(cas, a)
 
 	s.okname = temp(Types[TBOOL])
-	typecheck(&s.okname, Erv)
+	s.okname = typecheck(s.okname, Erv)
 
 	s.hashname = temp(Types[TUINT32])
-	typecheck(&s.hashname, Erv)
+	s.hashname = 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
+	sw.List.Set(nil)
 	var def *Node
 	if len(cc) > 0 && cc[0].typ == caseKindDefault {
 		def = cc[0].node.Right
@@ -572,22 +566,66 @@ func (s *typeSwitch) walk(sw *Node) {
 	} else {
 		def = Nod(OBREAK, nil, nil)
 	}
+	var typenil *Node
+	if len(cc) > 0 && cc[0].typ == caseKindTypeNil {
+		typenil = cc[0].node.Right
+		cc = cc[1:]
+	}
+
+	// For empty interfaces, do:
+	//     if e._type == nil {
+	//         do nil case if it exists, otherwise default
+	//     }
+	//     h := e._type.hash
+	// Use a similar strategy for non-empty interfaces.
+
+	// Get interface descriptor word.
+	typ := Nod(OITAB, s.facename, nil)
+
+	// Check for nil first.
+	i := Nod(OIF, nil, nil)
+	i.Left = Nod(OEQ, typ, nodnil())
+	if typenil != nil {
+		// Do explicit nil case right here.
+		i.Nbody.Set1(typenil)
+	} else {
+		// Jump to default case.
+		lbl := newCaseLabel()
+		i.Nbody.Set1(Nod(OGOTO, lbl, nil))
+		// Wrap default case with label.
+		blk := Nod(OBLOCK, nil, nil)
+		blk.List.Set([]*Node{Nod(OLABEL, lbl, nil), def})
+		def = blk
+	}
+	i.Left = typecheck(i.Left, Erv)
+	cas = append(cas, i)
+
+	if !cond.Right.Type.IsEmptyInterface() {
+		// Load type from itab.
+		typ = NodSym(ODOTPTR, typ, nil)
+		typ.Type = Ptrto(Types[TUINT8])
+		typ.Typecheck = 1
+		typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
+		typ.Bounded = true            // guaranteed not to fault
+	}
+	// Load hash from type.
+	h := NodSym(ODOTPTR, typ, nil)
+	h.Type = Types[TUINT32]
+	h.Typecheck = 1
+	h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
+	h.Bounded = true                // guaranteed not to fault
+	a = Nod(OAS, s.hashname, h)
+	a = typecheck(a, Etop)
+	cas = append(cas, a)
 
 	// 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)
+		default:
+			Fatalf("typeSwitch with bad kind: %d", c.typ)
 		}
 	}
 
@@ -595,7 +633,7 @@ func (s *typeSwitch) walk(sw *Node) {
 	for len(cc) > 0 {
 		if cc[0].typ != caseKindTypeConst {
 			n := cc[0].node
-			cas = list(cas, n.Right)
+			cas = append(cas, n.Right)
 			cc = cc[1:]
 			continue
 		}
@@ -612,7 +650,7 @@ func (s *typeSwitch) walk(sw *Node) {
 		if false {
 			for i := 0; i < run; i++ {
 				n := cc[i].node
-				cas = list(cas, n.Right)
+				cas = append(cas, n.Right)
 			}
 			continue
 		}
@@ -621,24 +659,24 @@ func (s *typeSwitch) walk(sw *Node) {
 		ncase := 0
 		for i := 0; i < run; i++ {
 			ncase++
-			hash := list1(cc[i].node.Right)
+			hash := []*Node{cc[i].node.Right}
 			for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ {
-				hash = list(hash, cc[j].node.Right)
+				hash = append(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]))
+		cas = append(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)
+		cas = append(cas, def)
+		sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
+		sw.List.Set(nil)
+		walkstmtlist(sw.Nbody.Slice())
 	}
 }
 
@@ -646,37 +684,37 @@ func (s *typeSwitch) walk(sw *Node) {
 // 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 {
+	var init []*Node
+	if t.Rlist.Len() == 0 {
 		name = nblank
-		typecheck(&nblank, Erv|Easgn)
+		nblank = typecheck(nblank, Erv|Easgn)
 	} else {
-		name = t.Rlist.N
-		init = list1(Nod(ODCL, name, nil))
+		name = t.Rlist.First()
+		init = []*Node{Nod(ODCL, name, nil)}
 		a := Nod(OAS, name, nil)
-		typecheck(&a, Etop)
-		init = list(init, a)
+		a = typecheck(a, Etop)
+		init = append(init, a)
 	}
 
 	a := Nod(OAS2, nil, nil)
-	a.List = list(list1(name), s.okname) // name, ok =
+	a.List.Set([]*Node{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)
+	a.Rlist.Set1(b)
+	a = typecheck(a, Etop)
+	init = append(init, a)
 
 	c := Nod(OIF, nil, nil)
 	c.Left = s.okname
-	c.Nbody = list1(t.Right) // if ok { goto l }
+	c.Nbody.Set1(t.Right) // if ok { goto l }
 
-	return liststmt(list(init, c))
+	return liststmt(append(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
+		var cas []*Node
 		for _, c := range cc {
 			n := c.node
 			if c.typ != caseKindTypeConst {
@@ -684,9 +722,9 @@ func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
 			}
 			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)
+			a.Left = typecheck(a.Left, Erv)
+			a.Nbody.Set1(n.Right)
+			cas = append(cas, a)
 		}
 		return liststmt(cas)
 	}
@@ -695,9 +733,9 @@ func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
 	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:]))
+	a.Left = typecheck(a.Left, Erv)
+	a.Nbody.Set1(s.walkCases(cc[:half]))
+	a.Rlist.Set1(s.walkCases(cc[half:]))
 	return a
 }
 
@@ -764,9 +802,9 @@ func exprcmp(c1, c2 *caseClause) int {
 	// sort by constant value to enable binary search
 	switch ct {
 	case CTFLT:
-		return mpcmpfltflt(n1.Val().U.(*Mpflt), n2.Val().U.(*Mpflt))
+		return n1.Val().U.(*Mpflt).Cmp(n2.Val().U.(*Mpflt))
 	case CTINT, CTRUNE:
-		return Mpcmpfixfix(n1.Val().U.(*Mpint), n2.Val().U.(*Mpint))
+		return n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint))
 	case CTSTR:
 		// Sort strings by length and then by value.
 		// It is much cheaper to compare lengths than values,
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index a11b37e..fab8697 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -15,10 +15,10 @@ type Node struct {
 	// Generic recursive walks should follow these fields.
 	Left  *Node
 	Right *Node
-	Ninit *NodeList
-	Nbody *NodeList
-	List  *NodeList
-	Rlist *NodeList
+	Ninit Nodes
+	Nbody Nodes
+	List  Nodes
+	Rlist Nodes
 
 	// most nodes
 	Type *Type
@@ -33,6 +33,13 @@ type Node struct {
 	Sym *Sym        // various
 	E   interface{} // Opt or Val, see methods below
 
+	// Various. Usually an offset into a struct. For example, ONAME nodes
+	// that refer to local variables use it to identify their stack frame
+	// position. ODOT, ODOTPTR, and OINDREG use it to indicate offset
+	// relative to their base address. ONAME nodes on the left side of an
+	// OKEY within an OSTRUCTLIT use it to store the named field's offset.
+	// OXCASE and OXFALL use it to validate the use of fallthrough.
+	// Possibly still more uses. If you find any, document them.
 	Xoffset int64
 
 	Lineno int32
@@ -42,30 +49,79 @@ type Node struct {
 
 	Esc uint16 // EscXXX
 
-	Op          Op
-	Nointerface bool
-	Ullman      uint8 // sethi/ullman number
-	Addable     bool  // addressable
-	Etype       EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg
-	Bounded     bool  // bounds check unnecessary
-	Class       Class // 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
+	Op        Op
+	Ullman    uint8 // sethi/ullman number
+	Addable   bool  // addressable
+	Etype     EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg, ChanDir for OTCHAN
+	Bounded   bool  // bounds check unnecessary
+	NonNil    bool  // guaranteed to be non-nil
+	Class     Class // 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
+	hasVal    int8  // +1 for Val, -1 for Opt, 0 for not yet set
+	flags     uint8 // TODO: store more bool fields in this flag field
+}
+
+const (
+	hasBreak = 1 << iota
+	notLiveAtEnd
+	isClosureVar
+	isOutputParamHeapAddr
+)
+
+func (n *Node) HasBreak() bool {
+	return n.flags&hasBreak != 0
+}
+func (n *Node) SetHasBreak(b bool) {
+	if b {
+		n.flags |= hasBreak
+	} else {
+		n.flags &^= hasBreak
+	}
+}
+func (n *Node) NotLiveAtEnd() bool {
+	return n.flags&notLiveAtEnd != 0
+}
+func (n *Node) SetNotLiveAtEnd(b bool) {
+	if b {
+		n.flags |= notLiveAtEnd
+	} else {
+		n.flags &^= notLiveAtEnd
+	}
+}
+func (n *Node) isClosureVar() bool {
+	return n.flags&isClosureVar != 0
+}
+func (n *Node) setIsClosureVar(b bool) {
+	if b {
+		n.flags |= isClosureVar
+	} else {
+		n.flags &^= isClosureVar
+	}
+}
+
+func (n *Node) IsOutputParamHeapAddr() bool {
+	return n.flags&isOutputParamHeapAddr != 0
+}
+func (n *Node) setIsOutputParamHeapAddr(b bool) {
+	if b {
+		n.flags |= isOutputParamHeapAddr
+	} else {
+		n.flags &^= isOutputParamHeapAddr
+	}
 }
 
 // Val returns the Val for the node.
@@ -110,18 +166,18 @@ func (n *Node) SetOpt(x interface{}) {
 	n.E = x
 }
 
-// Name holds Node fields used only by named nodes (ONAME, OPACK, some OLITERAL).
+// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, ODCLFIELD, 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
+	Pack      *Node  // real package for import . names
+	Pkg       *Pkg   // pkg for OPACK nodes
+	Heapaddr  *Node  // temp holding heap address of param (could move to Param?)
+	Inlvar    *Node  // ONAME substitute while inlining (could move to Param?)
+	Defn      *Node  // initializing assignment
+	Curfn     *Node  // function for local variables
+	Param     *Param // additional fields for ONAME, ODCLFIELD
+	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
@@ -134,53 +190,114 @@ type Name struct {
 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 PAUTOHEAP
+	Stackcopy *Node // the PPARAM/PPARAMOUT on-stack slot (moved func params only)
 
 	// 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
+	Field *Field // TFIELD in arg struct
+
+	// ONAME closure linkage
+	// Consider:
+	//
+	//	func f() {
+	//		x := 1 // x1
+	//		func() {
+	//			use(x) // x2
+	//			func() {
+	//				use(x) // x3
+	//				--- parser is here ---
+	//			}()
+	//		}()
+	//	}
+	//
+	// There is an original declaration of x and then a chain of mentions of x
+	// leading into the current function. Each time x is mentioned in a new closure,
+	// we create a variable representing x for use in that specific closure,
+	// since the way you get to x is different in each closure.
+	//
+	// Let's number the specific variables as shown in the code:
+	// x1 is the original x, x2 is when mentioned in the closure,
+	// and x3 is when mentioned in the closure in the closure.
+	//
+	// We keep these linked (assume N > 1):
+	//
+	//   - x1.Defn = original declaration statement for x (like most variables)
+	//   - x1.Innermost = current innermost closure x (in this case x3), or nil for none
+	//   - x1.isClosureVar() = false
+	//
+	//   - xN.Defn = x1, N > 1
+	//   - xN.isClosureVar() = true, N > 1
+	//   - x2.Outer = nil
+	//   - xN.Outer = x(N-1), N > 2
+	//
+	//
+	// When we look up x in the symbol table, we always get x1.
+	// Then we can use x1.Innermost (if not nil) to get the x
+	// for the innermost known closure function,
+	// but the first reference in a closure will find either no x1.Innermost
+	// or an x1.Innermost with .Funcdepth < Funcdepth.
+	// In that case, a new xN must be created, linked in with:
+	//
+	//     xN.Defn = x1
+	//     xN.Outer = x1.Innermost
+	//     x1.Innermost = xN
+	//
+	// When we finish the function, we'll process its closure variables
+	// and find xN and pop it off the list using:
+	//
+	//     x1 := xN.Defn
+	//     x1.Innermost = xN.Outer
+	//
+	// We leave xN.Innermost set so that we can still get to the original
+	// variable quickly. Not shown here, but once we're
+	// done parsing a function and no longer need xN.Outer for the
+	// lexical x reference links as described above, closurebody
+	// recomputes xN.Outer as the semantic x reference link tree,
+	// even filling in x in intermediate closures that might not
+	// have mentioned it along the way to inner closures that did.
+	// See closurebody for details.
+	//
+	// During the eventual compilation, then, for closure variables we have:
+	//
+	//     xN.Defn = original variable
+	//     xN.Outer = variable captured in next outward scope
+	//                to make closure where xN appears
+	//
+	// Because of the sharding of pieces of the node, x.Defn means x.Name.Defn
+	// and x.Innermost/Outer means x.Name.Param.Innermost/Outer.
+	Innermost *Node
+	Outer     *Node
 }
 
 // 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
+	Enter      Nodes // for example, allocate and initialize memory for escaping parameters
+	Exit       Nodes
+	Cvars      Nodes   // closure params
+	Dcl        []*Node // autodcl for this func/closure
+	Inldcl     Nodes   // copy of dcl for use in inlining
 	Closgen    int
-	Outerfunc  *Node
-	Fieldtrack []*Type
-	Outer      *Node // outer func for closure
+	Outerfunc  *Node // outer function (for closure)
+	FieldTrack map[*Sym]struct{}
 	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
+	Inl     Nodes // copy of the body for use in inlining
 	InlCost int32
 	Depth   int32
 
 	Endlineno int32
+	WBLineno  int32 // line number of first write barrier
 
-	Norace            bool // func must not have race detector annotations
-	Nosplit           bool // func should not execute on separate stack
-	Noinline          bool // func should not be inlined
-	Nowritebarrier    bool // emit compiler error instead of write barrier
-	Nowritebarrierrec bool // error on write barrier in this or recursive callees
-	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
-
-	WBLineno int32 // line number of first write barrier
+	Pragma        Pragma // go:xxx function annotations
+	Dupok         bool   // duplicate definitions ok
+	Wrapper       bool   // is method wrapper
+	Needctxt      bool   // function uses context register (has closure variables)
+	ReflectMethod bool   // function calls reflect.Type.Method or MethodByName
 }
 
 type Op uint8
@@ -201,7 +318,7 @@ const (
 	OSUB             // Left - Right
 	OOR              // Left | Right
 	OXOR             // Left ^ Right
-	OADDSTR          // Left + Right (string addition)
+	OADDSTR          // +{List} (string addition, list elements are strings)
 	OADDR            // &Left
 	OANDAND          // Left && Right
 	OAPPEND          // append(List)
@@ -247,11 +364,11 @@ const (
 	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)
+	ODOT       // Left.Sym (Left is of struct type)
+	ODOTPTR    // Left.Sym (Left is of pointer to struct type)
+	ODOTMETH   // Left.Sym (Left is non-interface, Right is method name)
+	ODOTINTER  // Left.Sym (Left is interface, Right is method name)
+	OXDOT      // Left.Sym (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
@@ -264,7 +381,7 @@ const (
 	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.
+	_          // was OPARAM, but cannot remove without breaking binary blob in builtin.go
 	OLEN       // len(Left)
 	OMAKE      // make(List) (before type checking converts to one of the following)
 	OMAKECHAN  // make(Type, Left) (type is chan)
@@ -366,128 +483,104 @@ const (
 	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
-}
+// Nodes is a pointer to a slice of *Node.
+// For fields that are not used in most nodes, this is used instead of
+// a slice to save space.
+type Nodes struct{ slice *[]*Node }
 
-// list1 returns a one-element list containing n.
-func list1(n *Node) *NodeList {
-	if n == nil {
+// Slice returns the entries in Nodes as a slice.
+// Changes to the slice entries (as in s[i] = n) will be reflected in
+// the Nodes.
+func (n Nodes) Slice() []*Node {
+	if n.slice == nil {
 		return nil
 	}
-	if n.Op == OBLOCK && n.Ninit == nil {
-		// Flatten list and steal storage.
-		// Poison pointer to catch errant uses.
-		l := n.List
+	return *n.slice
+}
 
-		n.List = nil
-		return l
+// Len returns the number of entries in Nodes.
+func (n Nodes) Len() int {
+	if n.slice == nil {
+		return 0
 	}
-
-	l := new(NodeList)
-	l.N = n
-	l.End = l
-	return l
+	return len(*n.slice)
 }
 
-// list returns the result of appending n to l.
-func list(l *NodeList, n *Node) *NodeList {
-	return concat(l, list1(n))
+// Index returns the i'th element of Nodes.
+// It panics if n does not have at least i+1 elements.
+func (n Nodes) Index(i int) *Node {
+	return (*n.slice)[i]
 }
 
-// listsort sorts *l in place according to the comparison function lt.
-// The algorithm expects lt(a, b) to be equivalent to a < b.
-// The algorithm is mergesort, so it is guaranteed to be O(n log n).
-func listsort(l **NodeList, lt func(*Node, *Node) bool) {
-	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
+// First returns the first element of Nodes (same as n.Index(0)).
+// It panics if n has no elements.
+func (n Nodes) First() *Node {
+	return (*n.slice)[0]
+}
 
-	l1 = *l
-	listsort(&l1, lt)
-	listsort(&l2, lt)
+// Second returns the second element of Nodes (same as n.Index(1)).
+// It panics if n has fewer than two elements.
+func (n Nodes) Second() *Node {
+	return (*n.slice)[1]
+}
 
-	if lt(l1.N, l2.N) {
-		*l = l1
+// Set sets n to a slice.
+// This takes ownership of the slice.
+func (n *Nodes) Set(s []*Node) {
+	if len(s) == 0 {
+		n.slice = nil
 	} else {
-		*l = l2
-		l2 = l1
-		l1 = *l
+		// Copy s and take address of t rather than s to avoid
+		// allocation in the case where len(s) == 0 (which is
+		// over 3x more common, dynamically, for make.bash).
+		t := s
+		n.slice = &t
 	}
+}
 
-	// now l1 == *l; and l1 < l2
+// Set1 sets n to a slice containing a single node.
+func (n *Nodes) Set1(node *Node) {
+	n.slice = &[]*Node{node}
+}
 
-	var le *NodeList
-	for (l1 != nil) && (l2 != nil) {
-		for (l1.Next != nil) && lt(l1.Next.N, l2.N) {
-			l1 = l1.Next
-		}
+// MoveNodes sets n to the contents of n2, then clears n2.
+func (n *Nodes) MoveNodes(n2 *Nodes) {
+	n.slice = n2.slice
+	n2.slice = nil
+}
 
-		// 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
-		}
+// SetIndex sets the i'th element of Nodes to node.
+// It panics if n does not have at least i+1 elements.
+func (n Nodes) SetIndex(i int, node *Node) {
+	(*n.slice)[i] = node
+}
 
-		(*l).End = l1       // cut *l at l1
-		*l = concat(*l, l2) // glue l2 to *l's tail
+// Addr returns the address of the i'th element of Nodes.
+// It panics if n does not have at least i+1 elements.
+func (n Nodes) Addr(i int) **Node {
+	return &(*n.slice)[i]
+}
 
-		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
+// Append appends entries to Nodes.
+// If a slice is passed in, this will take ownership of it.
+func (n *Nodes) Append(a ...*Node) {
+	if n.slice == nil {
+		if len(a) > 0 {
+			n.slice = &a
+		}
+	} else {
+		*n.slice = append(*n.slice, a...)
 	}
-
-	*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")
+// AppendNodes appends the contents of *n2 to n, then clears n2.
+func (n *Nodes) AppendNodes(n2 *Nodes) {
+	switch {
+	case n2.slice == nil:
+	case n.slice == nil:
+		n.slice = n2.slice
+	default:
+		*n.slice = append(*n.slice, *n2.slice...)
 	}
-	return int(n)
+	n2.slice = nil
 }
diff --git a/src/cmd/compile/internal/gc/testdata/addressed_ssa.go b/src/cmd/compile/internal/gc/testdata/addressed_ssa.go
new file mode 100644
index 0000000..59cf238
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/addressed_ssa.go
@@ -0,0 +1,207 @@
+// Copyright 2015 The Go Authors. 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"
+
+var output string
+
+func mypanic(s string) {
+	fmt.Printf(output)
+	panic(s)
+}
+
+func assertEqual(x, y int) {
+	if x != y {
+		mypanic("assertEqual failed")
+	}
+}
+
+func main() {
+	x := f1_ssa(2, 3)
+	output += fmt.Sprintln("*x is", *x)
+	output += fmt.Sprintln("Gratuitously use some stack")
+	output += fmt.Sprintln("*x is", *x)
+	assertEqual(*x, 9)
+
+	w := f3a_ssa(6)
+	output += fmt.Sprintln("*w is", *w)
+	output += fmt.Sprintln("Gratuitously use some stack")
+	output += fmt.Sprintln("*w is", *w)
+	assertEqual(*w, 6)
+
+	y := f3b_ssa(12)
+	output += fmt.Sprintln("*y.(*int) is", *y.(*int))
+	output += fmt.Sprintln("Gratuitously use some stack")
+	output += fmt.Sprintln("*y.(*int) is", *y.(*int))
+	assertEqual(*y.(*int), 12)
+
+	z := f3c_ssa(8)
+	output += fmt.Sprintln("*z.(*int) is", *z.(*int))
+	output += fmt.Sprintln("Gratuitously use some stack")
+	output += fmt.Sprintln("*z.(*int) is", *z.(*int))
+	assertEqual(*z.(*int), 8)
+
+	args()
+	test_autos()
+}
+
+//go:noinline
+func f1_ssa(x, y int) *int {
+	x = x*y + y
+	return &x
+}
+
+//go:noinline
+func f3a_ssa(x int) *int {
+	return &x
+}
+
+//go:noinline
+func f3b_ssa(x int) interface{} { // ./foo.go:15: internal error: f3b_ssa ~r1 (type interface {}) recorded as live on entry
+	return &x
+}
+
+//go:noinline
+func f3c_ssa(y int) interface{} {
+	x := y
+	return &x
+}
+
+type V struct {
+	p    *V
+	w, x int64
+}
+
+func args() {
+	v := V{p: nil, w: 1, x: 1}
+	a := V{p: &v, w: 2, x: 2}
+	b := V{p: &v, w: 0, x: 0}
+	i := v.args_ssa(a, b)
+	output += fmt.Sprintln("i=", i)
+	assertEqual(int(i), 2)
+}
+
+//go:noinline
+func (v V) args_ssa(a, b V) int64 {
+	if v.w == 0 {
+		return v.x
+	}
+	if v.w == 1 {
+		return a.x
+	}
+	if v.w == 2 {
+		return b.x
+	}
+	b.p.p = &a // v.p in caller = &a
+
+	return -1
+}
+
+func test_autos() {
+	test(11)
+	test(12)
+	test(13)
+	test(21)
+	test(22)
+	test(23)
+	test(31)
+	test(32)
+}
+
+func test(which int64) {
+	output += fmt.Sprintln("test", which)
+	v1 := V{w: 30, x: 3, p: nil}
+	v2, v3 := v1.autos_ssa(which, 10, 1, 20, 2)
+	if which != v2.val() {
+		output += fmt.Sprintln("Expected which=", which, "got v2.val()=", v2.val())
+		mypanic("Failure of expected V value")
+	}
+	if v2.p.val() != v3.val() {
+		output += fmt.Sprintln("Expected v2.p.val()=", v2.p.val(), "got v3.val()=", v3.val())
+		mypanic("Failure of expected V.p value")
+	}
+	if which != v3.p.p.p.p.p.p.p.val() {
+		output += fmt.Sprintln("Expected which=", which, "got v3.p.p.p.p.p.p.p.val()=", v3.p.p.p.p.p.p.p.val())
+		mypanic("Failure of expected V.p value")
+	}
+}
+
+func (v V) val() int64 {
+	return v.w + v.x
+}
+
+// autos_ssa uses contents of v and parameters w1, w2, x1, x2
+// to initialize a bunch of locals, all of which have their
+// address taken to force heap allocation, and then based on
+// the value of which a pair of those locals are copied in
+// various ways to the two results y, and z, which are also
+// addressed. Which is expected to be one of 11-13, 21-23, 31, 32,
+// and y.val() should be equal to which and y.p.val() should
+// be equal to z.val().  Also, x(.p)**8 == x; that is, the
+// autos are all linked into a ring.
+//go:noinline
+func (v V) autos_ssa(which, w1, x1, w2, x2 int64) (y, z V) {
+	fill_ssa(v.w, v.x, &v, v.p) // gratuitous no-op to force addressing
+	var a, b, c, d, e, f, g, h V
+	fill_ssa(w1, x1, &a, &b)
+	fill_ssa(w1, x2, &b, &c)
+	fill_ssa(w1, v.x, &c, &d)
+	fill_ssa(w2, x1, &d, &e)
+	fill_ssa(w2, x2, &e, &f)
+	fill_ssa(w2, v.x, &f, &g)
+	fill_ssa(v.w, x1, &g, &h)
+	fill_ssa(v.w, x2, &h, &a)
+	switch which {
+	case 11:
+		y = a
+		z.getsI(&b)
+	case 12:
+		y.gets(&b)
+		z = c
+	case 13:
+		y.gets(&c)
+		z = d
+	case 21:
+		y.getsI(&d)
+		z.gets(&e)
+	case 22:
+		y = e
+		z = f
+	case 23:
+		y.gets(&f)
+		z.getsI(&g)
+	case 31:
+		y = g
+		z.gets(&h)
+	case 32:
+		y.getsI(&h)
+		z = a
+	default:
+
+		panic("")
+	}
+	return
+}
+
+// gets is an address-mentioning way of implementing
+// structure assignment.
+//go:noinline
+func (to *V) gets(from *V) {
+	*to = *from
+}
+
+// gets is an address-and-interface-mentioning way of
+// implementing structure assignment.
+//go:noinline
+func (to *V) getsI(from interface{}) {
+	*to = *from.(*V)
+}
+
+// fill_ssa initializes r with V{w:w, x:x, p:p}
+//go:noinline
+func fill_ssa(w, x int64, r, p *V) {
+	*r = V{w: w, x: x, p: p}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/append_ssa.go b/src/cmd/compile/internal/gc/testdata/append_ssa.go
new file mode 100644
index 0000000..03cd219
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/append_ssa.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.
+
+// append_ssa.go tests append operations.
+package main
+
+import "fmt"
+
+var failed = false
+
+//go:noinline
+func appendOne_ssa(a []int, x int) []int {
+	return append(a, x)
+}
+
+//go:noinline
+func appendThree_ssa(a []int, x, y, z int) []int {
+	return append(a, x, y, z)
+}
+
+func eq(a, b []int) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i := range a {
+		if a[i] != b[i] {
+			return false
+		}
+	}
+	return true
+}
+
+func expect(got, want []int) {
+	if eq(got, want) {
+		return
+	}
+	fmt.Printf("expected %v, got %v\n", want, got)
+	failed = true
+}
+
+func testAppend() {
+	var store [7]int
+	a := store[:0]
+
+	a = appendOne_ssa(a, 1)
+	expect(a, []int{1})
+	a = appendThree_ssa(a, 2, 3, 4)
+	expect(a, []int{1, 2, 3, 4})
+	a = appendThree_ssa(a, 5, 6, 7)
+	expect(a, []int{1, 2, 3, 4, 5, 6, 7})
+	if &a[0] != &store[0] {
+		fmt.Println("unnecessary grow")
+		failed = true
+	}
+	a = appendOne_ssa(a, 8)
+	expect(a, []int{1, 2, 3, 4, 5, 6, 7, 8})
+	if &a[0] == &store[0] {
+		fmt.Println("didn't grow")
+		failed = true
+	}
+}
+
+func main() {
+	testAppend()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/arithBoundary_ssa.go b/src/cmd/compile/internal/gc/testdata/arithBoundary_ssa.go
new file mode 100644
index 0000000..929e4e1
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/arithBoundary_ssa.go
@@ -0,0 +1,735 @@
+package main
+
+import "fmt"
+
+type utd64 struct {
+	a, b                    uint64
+	add, sub, mul, div, mod uint64
+}
+type itd64 struct {
+	a, b                    int64
+	add, sub, mul, div, mod int64
+}
+type utd32 struct {
+	a, b                    uint32
+	add, sub, mul, div, mod uint32
+}
+type itd32 struct {
+	a, b                    int32
+	add, sub, mul, div, mod int32
+}
+type utd16 struct {
+	a, b                    uint16
+	add, sub, mul, div, mod uint16
+}
+type itd16 struct {
+	a, b                    int16
+	add, sub, mul, div, mod int16
+}
+type utd8 struct {
+	a, b                    uint8
+	add, sub, mul, div, mod uint8
+}
+type itd8 struct {
+	a, b                    int8
+	add, sub, mul, div, mod int8
+}
+
+//go:noinline
+func add_uint64_ssa(a, b uint64) uint64 {
+	return a + b
+}
+
+//go:noinline
+func sub_uint64_ssa(a, b uint64) uint64 {
+	return a - b
+}
+
+//go:noinline
+func div_uint64_ssa(a, b uint64) uint64 {
+	return a / b
+}
+
+//go:noinline
+func mod_uint64_ssa(a, b uint64) uint64 {
+	return a % b
+}
+
+//go:noinline
+func mul_uint64_ssa(a, b uint64) uint64 {
+	return a * b
+}
+
+//go:noinline
+func add_int64_ssa(a, b int64) int64 {
+	return a + b
+}
+
+//go:noinline
+func sub_int64_ssa(a, b int64) int64 {
+	return a - b
+}
+
+//go:noinline
+func div_int64_ssa(a, b int64) int64 {
+	return a / b
+}
+
+//go:noinline
+func mod_int64_ssa(a, b int64) int64 {
+	return a % b
+}
+
+//go:noinline
+func mul_int64_ssa(a, b int64) int64 {
+	return a * b
+}
+
+//go:noinline
+func add_uint32_ssa(a, b uint32) uint32 {
+	return a + b
+}
+
+//go:noinline
+func sub_uint32_ssa(a, b uint32) uint32 {
+	return a - b
+}
+
+//go:noinline
+func div_uint32_ssa(a, b uint32) uint32 {
+	return a / b
+}
+
+//go:noinline
+func mod_uint32_ssa(a, b uint32) uint32 {
+	return a % b
+}
+
+//go:noinline
+func mul_uint32_ssa(a, b uint32) uint32 {
+	return a * b
+}
+
+//go:noinline
+func add_int32_ssa(a, b int32) int32 {
+	return a + b
+}
+
+//go:noinline
+func sub_int32_ssa(a, b int32) int32 {
+	return a - b
+}
+
+//go:noinline
+func div_int32_ssa(a, b int32) int32 {
+	return a / b
+}
+
+//go:noinline
+func mod_int32_ssa(a, b int32) int32 {
+	return a % b
+}
+
+//go:noinline
+func mul_int32_ssa(a, b int32) int32 {
+	return a * b
+}
+
+//go:noinline
+func add_uint16_ssa(a, b uint16) uint16 {
+	return a + b
+}
+
+//go:noinline
+func sub_uint16_ssa(a, b uint16) uint16 {
+	return a - b
+}
+
+//go:noinline
+func div_uint16_ssa(a, b uint16) uint16 {
+	return a / b
+}
+
+//go:noinline
+func mod_uint16_ssa(a, b uint16) uint16 {
+	return a % b
+}
+
+//go:noinline
+func mul_uint16_ssa(a, b uint16) uint16 {
+	return a * b
+}
+
+//go:noinline
+func add_int16_ssa(a, b int16) int16 {
+	return a + b
+}
+
+//go:noinline
+func sub_int16_ssa(a, b int16) int16 {
+	return a - b
+}
+
+//go:noinline
+func div_int16_ssa(a, b int16) int16 {
+	return a / b
+}
+
+//go:noinline
+func mod_int16_ssa(a, b int16) int16 {
+	return a % b
+}
+
+//go:noinline
+func mul_int16_ssa(a, b int16) int16 {
+	return a * b
+}
+
+//go:noinline
+func add_uint8_ssa(a, b uint8) uint8 {
+	return a + b
+}
+
+//go:noinline
+func sub_uint8_ssa(a, b uint8) uint8 {
+	return a - b
+}
+
+//go:noinline
+func div_uint8_ssa(a, b uint8) uint8 {
+	return a / b
+}
+
+//go:noinline
+func mod_uint8_ssa(a, b uint8) uint8 {
+	return a % b
+}
+
+//go:noinline
+func mul_uint8_ssa(a, b uint8) uint8 {
+	return a * b
+}
+
+//go:noinline
+func add_int8_ssa(a, b int8) int8 {
+	return a + b
+}
+
+//go:noinline
+func sub_int8_ssa(a, b int8) int8 {
+	return a - b
+}
+
+//go:noinline
+func div_int8_ssa(a, b int8) int8 {
+	return a / b
+}
+
+//go:noinline
+func mod_int8_ssa(a, b int8) int8 {
+	return a % b
+}
+
+//go:noinline
+func mul_int8_ssa(a, b int8) int8 {
+	return a * b
+}
+
+var uint64_data []utd64 = []utd64{utd64{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+	utd64{a: 0, b: 1, add: 1, sub: 18446744073709551615, mul: 0, div: 0, mod: 0},
+	utd64{a: 0, b: 4294967296, add: 4294967296, sub: 18446744069414584320, mul: 0, div: 0, mod: 0},
+	utd64{a: 0, b: 18446744073709551615, add: 18446744073709551615, sub: 1, mul: 0, div: 0, mod: 0},
+	utd64{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+	utd64{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	utd64{a: 1, b: 4294967296, add: 4294967297, sub: 18446744069414584321, mul: 4294967296, div: 0, mod: 1},
+	utd64{a: 1, b: 18446744073709551615, add: 0, sub: 2, mul: 18446744073709551615, div: 0, mod: 1},
+	utd64{a: 4294967296, b: 0, add: 4294967296, sub: 4294967296, mul: 0},
+	utd64{a: 4294967296, b: 1, add: 4294967297, sub: 4294967295, mul: 4294967296, div: 4294967296, mod: 0},
+	utd64{a: 4294967296, b: 4294967296, add: 8589934592, sub: 0, mul: 0, div: 1, mod: 0},
+	utd64{a: 4294967296, b: 18446744073709551615, add: 4294967295, sub: 4294967297, mul: 18446744069414584320, div: 0, mod: 4294967296},
+	utd64{a: 18446744073709551615, b: 0, add: 18446744073709551615, sub: 18446744073709551615, mul: 0},
+	utd64{a: 18446744073709551615, b: 1, add: 0, sub: 18446744073709551614, mul: 18446744073709551615, div: 18446744073709551615, mod: 0},
+	utd64{a: 18446744073709551615, b: 4294967296, add: 4294967295, sub: 18446744069414584319, mul: 18446744069414584320, div: 4294967295, mod: 4294967295},
+	utd64{a: 18446744073709551615, b: 18446744073709551615, add: 18446744073709551614, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var int64_data []itd64 = []itd64{itd64{a: -9223372036854775808, b: -9223372036854775808, add: 0, sub: 0, mul: 0, div: 1, mod: 0},
+	itd64{a: -9223372036854775808, b: -9223372036854775807, add: 1, sub: -1, mul: -9223372036854775808, div: 1, mod: -1},
+	itd64{a: -9223372036854775808, b: -4294967296, add: 9223372032559808512, sub: -9223372032559808512, mul: 0, div: 2147483648, mod: 0},
+	itd64{a: -9223372036854775808, b: -1, add: 9223372036854775807, sub: -9223372036854775807, mul: -9223372036854775808, div: -9223372036854775808, mod: 0},
+	itd64{a: -9223372036854775808, b: 0, add: -9223372036854775808, sub: -9223372036854775808, mul: 0},
+	itd64{a: -9223372036854775808, b: 1, add: -9223372036854775807, sub: 9223372036854775807, mul: -9223372036854775808, div: -9223372036854775808, mod: 0},
+	itd64{a: -9223372036854775808, b: 4294967296, add: -9223372032559808512, sub: 9223372032559808512, mul: 0, div: -2147483648, mod: 0},
+	itd64{a: -9223372036854775808, b: 9223372036854775806, add: -2, sub: 2, mul: 0, div: -1, mod: -2},
+	itd64{a: -9223372036854775808, b: 9223372036854775807, add: -1, sub: 1, mul: -9223372036854775808, div: -1, mod: -1},
+	itd64{a: -9223372036854775807, b: -9223372036854775808, add: 1, sub: 1, mul: -9223372036854775808, div: 0, mod: -9223372036854775807},
+	itd64{a: -9223372036854775807, b: -9223372036854775807, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd64{a: -9223372036854775807, b: -4294967296, add: 9223372032559808513, sub: -9223372032559808511, mul: -4294967296, div: 2147483647, mod: -4294967295},
+	itd64{a: -9223372036854775807, b: -1, add: -9223372036854775808, sub: -9223372036854775806, mul: 9223372036854775807, div: 9223372036854775807, mod: 0},
+	itd64{a: -9223372036854775807, b: 0, add: -9223372036854775807, sub: -9223372036854775807, mul: 0},
+	itd64{a: -9223372036854775807, b: 1, add: -9223372036854775806, sub: -9223372036854775808, mul: -9223372036854775807, div: -9223372036854775807, mod: 0},
+	itd64{a: -9223372036854775807, b: 4294967296, add: -9223372032559808511, sub: 9223372032559808513, mul: 4294967296, div: -2147483647, mod: -4294967295},
+	itd64{a: -9223372036854775807, b: 9223372036854775806, add: -1, sub: 3, mul: 9223372036854775806, div: -1, mod: -1},
+	itd64{a: -9223372036854775807, b: 9223372036854775807, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+	itd64{a: -4294967296, b: -9223372036854775808, add: 9223372032559808512, sub: 9223372032559808512, mul: 0, div: 0, mod: -4294967296},
+	itd64{a: -4294967296, b: -9223372036854775807, add: 9223372032559808513, sub: 9223372032559808511, mul: -4294967296, div: 0, mod: -4294967296},
+	itd64{a: -4294967296, b: -4294967296, add: -8589934592, sub: 0, mul: 0, div: 1, mod: 0},
+	itd64{a: -4294967296, b: -1, add: -4294967297, sub: -4294967295, mul: 4294967296, div: 4294967296, mod: 0},
+	itd64{a: -4294967296, b: 0, add: -4294967296, sub: -4294967296, mul: 0},
+	itd64{a: -4294967296, b: 1, add: -4294967295, sub: -4294967297, mul: -4294967296, div: -4294967296, mod: 0},
+	itd64{a: -4294967296, b: 4294967296, add: 0, sub: -8589934592, mul: 0, div: -1, mod: 0},
+	itd64{a: -4294967296, b: 9223372036854775806, add: 9223372032559808510, sub: 9223372032559808514, mul: 8589934592, div: 0, mod: -4294967296},
+	itd64{a: -4294967296, b: 9223372036854775807, add: 9223372032559808511, sub: 9223372032559808513, mul: 4294967296, div: 0, mod: -4294967296},
+	itd64{a: -1, b: -9223372036854775808, add: 9223372036854775807, sub: 9223372036854775807, mul: -9223372036854775808, div: 0, mod: -1},
+	itd64{a: -1, b: -9223372036854775807, add: -9223372036854775808, sub: 9223372036854775806, mul: 9223372036854775807, div: 0, mod: -1},
+	itd64{a: -1, b: -4294967296, add: -4294967297, sub: 4294967295, mul: 4294967296, div: 0, mod: -1},
+	itd64{a: -1, b: -1, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd64{a: -1, b: 0, add: -1, sub: -1, mul: 0},
+	itd64{a: -1, b: 1, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+	itd64{a: -1, b: 4294967296, add: 4294967295, sub: -4294967297, mul: -4294967296, div: 0, mod: -1},
+	itd64{a: -1, b: 9223372036854775806, add: 9223372036854775805, sub: -9223372036854775807, mul: -9223372036854775806, div: 0, mod: -1},
+	itd64{a: -1, b: 9223372036854775807, add: 9223372036854775806, sub: -9223372036854775808, mul: -9223372036854775807, div: 0, mod: -1},
+	itd64{a: 0, b: -9223372036854775808, add: -9223372036854775808, sub: -9223372036854775808, mul: 0, div: 0, mod: 0},
+	itd64{a: 0, b: -9223372036854775807, add: -9223372036854775807, sub: 9223372036854775807, mul: 0, div: 0, mod: 0},
+	itd64{a: 0, b: -4294967296, add: -4294967296, sub: 4294967296, mul: 0, div: 0, mod: 0},
+	itd64{a: 0, b: -1, add: -1, sub: 1, mul: 0, div: 0, mod: 0},
+	itd64{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+	itd64{a: 0, b: 1, add: 1, sub: -1, mul: 0, div: 0, mod: 0},
+	itd64{a: 0, b: 4294967296, add: 4294967296, sub: -4294967296, mul: 0, div: 0, mod: 0},
+	itd64{a: 0, b: 9223372036854775806, add: 9223372036854775806, sub: -9223372036854775806, mul: 0, div: 0, mod: 0},
+	itd64{a: 0, b: 9223372036854775807, add: 9223372036854775807, sub: -9223372036854775807, mul: 0, div: 0, mod: 0},
+	itd64{a: 1, b: -9223372036854775808, add: -9223372036854775807, sub: -9223372036854775807, mul: -9223372036854775808, div: 0, mod: 1},
+	itd64{a: 1, b: -9223372036854775807, add: -9223372036854775806, sub: -9223372036854775808, mul: -9223372036854775807, div: 0, mod: 1},
+	itd64{a: 1, b: -4294967296, add: -4294967295, sub: 4294967297, mul: -4294967296, div: 0, mod: 1},
+	itd64{a: 1, b: -1, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+	itd64{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+	itd64{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd64{a: 1, b: 4294967296, add: 4294967297, sub: -4294967295, mul: 4294967296, div: 0, mod: 1},
+	itd64{a: 1, b: 9223372036854775806, add: 9223372036854775807, sub: -9223372036854775805, mul: 9223372036854775806, div: 0, mod: 1},
+	itd64{a: 1, b: 9223372036854775807, add: -9223372036854775808, sub: -9223372036854775806, mul: 9223372036854775807, div: 0, mod: 1},
+	itd64{a: 4294967296, b: -9223372036854775808, add: -9223372032559808512, sub: -9223372032559808512, mul: 0, div: 0, mod: 4294967296},
+	itd64{a: 4294967296, b: -9223372036854775807, add: -9223372032559808511, sub: -9223372032559808513, mul: 4294967296, div: 0, mod: 4294967296},
+	itd64{a: 4294967296, b: -4294967296, add: 0, sub: 8589934592, mul: 0, div: -1, mod: 0},
+	itd64{a: 4294967296, b: -1, add: 4294967295, sub: 4294967297, mul: -4294967296, div: -4294967296, mod: 0},
+	itd64{a: 4294967296, b: 0, add: 4294967296, sub: 4294967296, mul: 0},
+	itd64{a: 4294967296, b: 1, add: 4294967297, sub: 4294967295, mul: 4294967296, div: 4294967296, mod: 0},
+	itd64{a: 4294967296, b: 4294967296, add: 8589934592, sub: 0, mul: 0, div: 1, mod: 0},
+	itd64{a: 4294967296, b: 9223372036854775806, add: -9223372032559808514, sub: -9223372032559808510, mul: -8589934592, div: 0, mod: 4294967296},
+	itd64{a: 4294967296, b: 9223372036854775807, add: -9223372032559808513, sub: -9223372032559808511, mul: -4294967296, div: 0, mod: 4294967296},
+	itd64{a: 9223372036854775806, b: -9223372036854775808, add: -2, sub: -2, mul: 0, div: 0, mod: 9223372036854775806},
+	itd64{a: 9223372036854775806, b: -9223372036854775807, add: -1, sub: -3, mul: 9223372036854775806, div: 0, mod: 9223372036854775806},
+	itd64{a: 9223372036854775806, b: -4294967296, add: 9223372032559808510, sub: -9223372032559808514, mul: 8589934592, div: -2147483647, mod: 4294967294},
+	itd64{a: 9223372036854775806, b: -1, add: 9223372036854775805, sub: 9223372036854775807, mul: -9223372036854775806, div: -9223372036854775806, mod: 0},
+	itd64{a: 9223372036854775806, b: 0, add: 9223372036854775806, sub: 9223372036854775806, mul: 0},
+	itd64{a: 9223372036854775806, b: 1, add: 9223372036854775807, sub: 9223372036854775805, mul: 9223372036854775806, div: 9223372036854775806, mod: 0},
+	itd64{a: 9223372036854775806, b: 4294967296, add: -9223372032559808514, sub: 9223372032559808510, mul: -8589934592, div: 2147483647, mod: 4294967294},
+	itd64{a: 9223372036854775806, b: 9223372036854775806, add: -4, sub: 0, mul: 4, div: 1, mod: 0},
+	itd64{a: 9223372036854775806, b: 9223372036854775807, add: -3, sub: -1, mul: -9223372036854775806, div: 0, mod: 9223372036854775806},
+	itd64{a: 9223372036854775807, b: -9223372036854775808, add: -1, sub: -1, mul: -9223372036854775808, div: 0, mod: 9223372036854775807},
+	itd64{a: 9223372036854775807, b: -9223372036854775807, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+	itd64{a: 9223372036854775807, b: -4294967296, add: 9223372032559808511, sub: -9223372032559808513, mul: 4294967296, div: -2147483647, mod: 4294967295},
+	itd64{a: 9223372036854775807, b: -1, add: 9223372036854775806, sub: -9223372036854775808, mul: -9223372036854775807, div: -9223372036854775807, mod: 0},
+	itd64{a: 9223372036854775807, b: 0, add: 9223372036854775807, sub: 9223372036854775807, mul: 0},
+	itd64{a: 9223372036854775807, b: 1, add: -9223372036854775808, sub: 9223372036854775806, mul: 9223372036854775807, div: 9223372036854775807, mod: 0},
+	itd64{a: 9223372036854775807, b: 4294967296, add: -9223372032559808513, sub: 9223372032559808511, mul: -4294967296, div: 2147483647, mod: 4294967295},
+	itd64{a: 9223372036854775807, b: 9223372036854775806, add: -3, sub: 1, mul: -9223372036854775806, div: 1, mod: 1},
+	itd64{a: 9223372036854775807, b: 9223372036854775807, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var uint32_data []utd32 = []utd32{utd32{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+	utd32{a: 0, b: 1, add: 1, sub: 4294967295, mul: 0, div: 0, mod: 0},
+	utd32{a: 0, b: 4294967295, add: 4294967295, sub: 1, mul: 0, div: 0, mod: 0},
+	utd32{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+	utd32{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	utd32{a: 1, b: 4294967295, add: 0, sub: 2, mul: 4294967295, div: 0, mod: 1},
+	utd32{a: 4294967295, b: 0, add: 4294967295, sub: 4294967295, mul: 0},
+	utd32{a: 4294967295, b: 1, add: 0, sub: 4294967294, mul: 4294967295, div: 4294967295, mod: 0},
+	utd32{a: 4294967295, b: 4294967295, add: 4294967294, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var int32_data []itd32 = []itd32{itd32{a: -2147483648, b: -2147483648, add: 0, sub: 0, mul: 0, div: 1, mod: 0},
+	itd32{a: -2147483648, b: -2147483647, add: 1, sub: -1, mul: -2147483648, div: 1, mod: -1},
+	itd32{a: -2147483648, b: -1, add: 2147483647, sub: -2147483647, mul: -2147483648, div: -2147483648, mod: 0},
+	itd32{a: -2147483648, b: 0, add: -2147483648, sub: -2147483648, mul: 0},
+	itd32{a: -2147483648, b: 1, add: -2147483647, sub: 2147483647, mul: -2147483648, div: -2147483648, mod: 0},
+	itd32{a: -2147483648, b: 2147483647, add: -1, sub: 1, mul: -2147483648, div: -1, mod: -1},
+	itd32{a: -2147483647, b: -2147483648, add: 1, sub: 1, mul: -2147483648, div: 0, mod: -2147483647},
+	itd32{a: -2147483647, b: -2147483647, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd32{a: -2147483647, b: -1, add: -2147483648, sub: -2147483646, mul: 2147483647, div: 2147483647, mod: 0},
+	itd32{a: -2147483647, b: 0, add: -2147483647, sub: -2147483647, mul: 0},
+	itd32{a: -2147483647, b: 1, add: -2147483646, sub: -2147483648, mul: -2147483647, div: -2147483647, mod: 0},
+	itd32{a: -2147483647, b: 2147483647, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+	itd32{a: -1, b: -2147483648, add: 2147483647, sub: 2147483647, mul: -2147483648, div: 0, mod: -1},
+	itd32{a: -1, b: -2147483647, add: -2147483648, sub: 2147483646, mul: 2147483647, div: 0, mod: -1},
+	itd32{a: -1, b: -1, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd32{a: -1, b: 0, add: -1, sub: -1, mul: 0},
+	itd32{a: -1, b: 1, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+	itd32{a: -1, b: 2147483647, add: 2147483646, sub: -2147483648, mul: -2147483647, div: 0, mod: -1},
+	itd32{a: 0, b: -2147483648, add: -2147483648, sub: -2147483648, mul: 0, div: 0, mod: 0},
+	itd32{a: 0, b: -2147483647, add: -2147483647, sub: 2147483647, mul: 0, div: 0, mod: 0},
+	itd32{a: 0, b: -1, add: -1, sub: 1, mul: 0, div: 0, mod: 0},
+	itd32{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+	itd32{a: 0, b: 1, add: 1, sub: -1, mul: 0, div: 0, mod: 0},
+	itd32{a: 0, b: 2147483647, add: 2147483647, sub: -2147483647, mul: 0, div: 0, mod: 0},
+	itd32{a: 1, b: -2147483648, add: -2147483647, sub: -2147483647, mul: -2147483648, div: 0, mod: 1},
+	itd32{a: 1, b: -2147483647, add: -2147483646, sub: -2147483648, mul: -2147483647, div: 0, mod: 1},
+	itd32{a: 1, b: -1, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+	itd32{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+	itd32{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd32{a: 1, b: 2147483647, add: -2147483648, sub: -2147483646, mul: 2147483647, div: 0, mod: 1},
+	itd32{a: 2147483647, b: -2147483648, add: -1, sub: -1, mul: -2147483648, div: 0, mod: 2147483647},
+	itd32{a: 2147483647, b: -2147483647, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+	itd32{a: 2147483647, b: -1, add: 2147483646, sub: -2147483648, mul: -2147483647, div: -2147483647, mod: 0},
+	itd32{a: 2147483647, b: 0, add: 2147483647, sub: 2147483647, mul: 0},
+	itd32{a: 2147483647, b: 1, add: -2147483648, sub: 2147483646, mul: 2147483647, div: 2147483647, mod: 0},
+	itd32{a: 2147483647, b: 2147483647, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var uint16_data []utd16 = []utd16{utd16{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+	utd16{a: 0, b: 1, add: 1, sub: 65535, mul: 0, div: 0, mod: 0},
+	utd16{a: 0, b: 65535, add: 65535, sub: 1, mul: 0, div: 0, mod: 0},
+	utd16{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+	utd16{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	utd16{a: 1, b: 65535, add: 0, sub: 2, mul: 65535, div: 0, mod: 1},
+	utd16{a: 65535, b: 0, add: 65535, sub: 65535, mul: 0},
+	utd16{a: 65535, b: 1, add: 0, sub: 65534, mul: 65535, div: 65535, mod: 0},
+	utd16{a: 65535, b: 65535, add: 65534, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var int16_data []itd16 = []itd16{itd16{a: -32768, b: -32768, add: 0, sub: 0, mul: 0, div: 1, mod: 0},
+	itd16{a: -32768, b: -32767, add: 1, sub: -1, mul: -32768, div: 1, mod: -1},
+	itd16{a: -32768, b: -1, add: 32767, sub: -32767, mul: -32768, div: -32768, mod: 0},
+	itd16{a: -32768, b: 0, add: -32768, sub: -32768, mul: 0},
+	itd16{a: -32768, b: 1, add: -32767, sub: 32767, mul: -32768, div: -32768, mod: 0},
+	itd16{a: -32768, b: 32766, add: -2, sub: 2, mul: 0, div: -1, mod: -2},
+	itd16{a: -32768, b: 32767, add: -1, sub: 1, mul: -32768, div: -1, mod: -1},
+	itd16{a: -32767, b: -32768, add: 1, sub: 1, mul: -32768, div: 0, mod: -32767},
+	itd16{a: -32767, b: -32767, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd16{a: -32767, b: -1, add: -32768, sub: -32766, mul: 32767, div: 32767, mod: 0},
+	itd16{a: -32767, b: 0, add: -32767, sub: -32767, mul: 0},
+	itd16{a: -32767, b: 1, add: -32766, sub: -32768, mul: -32767, div: -32767, mod: 0},
+	itd16{a: -32767, b: 32766, add: -1, sub: 3, mul: 32766, div: -1, mod: -1},
+	itd16{a: -32767, b: 32767, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+	itd16{a: -1, b: -32768, add: 32767, sub: 32767, mul: -32768, div: 0, mod: -1},
+	itd16{a: -1, b: -32767, add: -32768, sub: 32766, mul: 32767, div: 0, mod: -1},
+	itd16{a: -1, b: -1, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd16{a: -1, b: 0, add: -1, sub: -1, mul: 0},
+	itd16{a: -1, b: 1, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+	itd16{a: -1, b: 32766, add: 32765, sub: -32767, mul: -32766, div: 0, mod: -1},
+	itd16{a: -1, b: 32767, add: 32766, sub: -32768, mul: -32767, div: 0, mod: -1},
+	itd16{a: 0, b: -32768, add: -32768, sub: -32768, mul: 0, div: 0, mod: 0},
+	itd16{a: 0, b: -32767, add: -32767, sub: 32767, mul: 0, div: 0, mod: 0},
+	itd16{a: 0, b: -1, add: -1, sub: 1, mul: 0, div: 0, mod: 0},
+	itd16{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+	itd16{a: 0, b: 1, add: 1, sub: -1, mul: 0, div: 0, mod: 0},
+	itd16{a: 0, b: 32766, add: 32766, sub: -32766, mul: 0, div: 0, mod: 0},
+	itd16{a: 0, b: 32767, add: 32767, sub: -32767, mul: 0, div: 0, mod: 0},
+	itd16{a: 1, b: -32768, add: -32767, sub: -32767, mul: -32768, div: 0, mod: 1},
+	itd16{a: 1, b: -32767, add: -32766, sub: -32768, mul: -32767, div: 0, mod: 1},
+	itd16{a: 1, b: -1, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+	itd16{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+	itd16{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd16{a: 1, b: 32766, add: 32767, sub: -32765, mul: 32766, div: 0, mod: 1},
+	itd16{a: 1, b: 32767, add: -32768, sub: -32766, mul: 32767, div: 0, mod: 1},
+	itd16{a: 32766, b: -32768, add: -2, sub: -2, mul: 0, div: 0, mod: 32766},
+	itd16{a: 32766, b: -32767, add: -1, sub: -3, mul: 32766, div: 0, mod: 32766},
+	itd16{a: 32766, b: -1, add: 32765, sub: 32767, mul: -32766, div: -32766, mod: 0},
+	itd16{a: 32766, b: 0, add: 32766, sub: 32766, mul: 0},
+	itd16{a: 32766, b: 1, add: 32767, sub: 32765, mul: 32766, div: 32766, mod: 0},
+	itd16{a: 32766, b: 32766, add: -4, sub: 0, mul: 4, div: 1, mod: 0},
+	itd16{a: 32766, b: 32767, add: -3, sub: -1, mul: -32766, div: 0, mod: 32766},
+	itd16{a: 32767, b: -32768, add: -1, sub: -1, mul: -32768, div: 0, mod: 32767},
+	itd16{a: 32767, b: -32767, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+	itd16{a: 32767, b: -1, add: 32766, sub: -32768, mul: -32767, div: -32767, mod: 0},
+	itd16{a: 32767, b: 0, add: 32767, sub: 32767, mul: 0},
+	itd16{a: 32767, b: 1, add: -32768, sub: 32766, mul: 32767, div: 32767, mod: 0},
+	itd16{a: 32767, b: 32766, add: -3, sub: 1, mul: -32766, div: 1, mod: 1},
+	itd16{a: 32767, b: 32767, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var uint8_data []utd8 = []utd8{utd8{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+	utd8{a: 0, b: 1, add: 1, sub: 255, mul: 0, div: 0, mod: 0},
+	utd8{a: 0, b: 255, add: 255, sub: 1, mul: 0, div: 0, mod: 0},
+	utd8{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+	utd8{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	utd8{a: 1, b: 255, add: 0, sub: 2, mul: 255, div: 0, mod: 1},
+	utd8{a: 255, b: 0, add: 255, sub: 255, mul: 0},
+	utd8{a: 255, b: 1, add: 0, sub: 254, mul: 255, div: 255, mod: 0},
+	utd8{a: 255, b: 255, add: 254, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var int8_data []itd8 = []itd8{itd8{a: -128, b: -128, add: 0, sub: 0, mul: 0, div: 1, mod: 0},
+	itd8{a: -128, b: -127, add: 1, sub: -1, mul: -128, div: 1, mod: -1},
+	itd8{a: -128, b: -1, add: 127, sub: -127, mul: -128, div: -128, mod: 0},
+	itd8{a: -128, b: 0, add: -128, sub: -128, mul: 0},
+	itd8{a: -128, b: 1, add: -127, sub: 127, mul: -128, div: -128, mod: 0},
+	itd8{a: -128, b: 126, add: -2, sub: 2, mul: 0, div: -1, mod: -2},
+	itd8{a: -128, b: 127, add: -1, sub: 1, mul: -128, div: -1, mod: -1},
+	itd8{a: -127, b: -128, add: 1, sub: 1, mul: -128, div: 0, mod: -127},
+	itd8{a: -127, b: -127, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd8{a: -127, b: -1, add: -128, sub: -126, mul: 127, div: 127, mod: 0},
+	itd8{a: -127, b: 0, add: -127, sub: -127, mul: 0},
+	itd8{a: -127, b: 1, add: -126, sub: -128, mul: -127, div: -127, mod: 0},
+	itd8{a: -127, b: 126, add: -1, sub: 3, mul: 126, div: -1, mod: -1},
+	itd8{a: -127, b: 127, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+	itd8{a: -1, b: -128, add: 127, sub: 127, mul: -128, div: 0, mod: -1},
+	itd8{a: -1, b: -127, add: -128, sub: 126, mul: 127, div: 0, mod: -1},
+	itd8{a: -1, b: -1, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd8{a: -1, b: 0, add: -1, sub: -1, mul: 0},
+	itd8{a: -1, b: 1, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+	itd8{a: -1, b: 126, add: 125, sub: -127, mul: -126, div: 0, mod: -1},
+	itd8{a: -1, b: 127, add: 126, sub: -128, mul: -127, div: 0, mod: -1},
+	itd8{a: 0, b: -128, add: -128, sub: -128, mul: 0, div: 0, mod: 0},
+	itd8{a: 0, b: -127, add: -127, sub: 127, mul: 0, div: 0, mod: 0},
+	itd8{a: 0, b: -1, add: -1, sub: 1, mul: 0, div: 0, mod: 0},
+	itd8{a: 0, b: 0, add: 0, sub: 0, mul: 0},
+	itd8{a: 0, b: 1, add: 1, sub: -1, mul: 0, div: 0, mod: 0},
+	itd8{a: 0, b: 126, add: 126, sub: -126, mul: 0, div: 0, mod: 0},
+	itd8{a: 0, b: 127, add: 127, sub: -127, mul: 0, div: 0, mod: 0},
+	itd8{a: 1, b: -128, add: -127, sub: -127, mul: -128, div: 0, mod: 1},
+	itd8{a: 1, b: -127, add: -126, sub: -128, mul: -127, div: 0, mod: 1},
+	itd8{a: 1, b: -1, add: 0, sub: 2, mul: -1, div: -1, mod: 0},
+	itd8{a: 1, b: 0, add: 1, sub: 1, mul: 0},
+	itd8{a: 1, b: 1, add: 2, sub: 0, mul: 1, div: 1, mod: 0},
+	itd8{a: 1, b: 126, add: 127, sub: -125, mul: 126, div: 0, mod: 1},
+	itd8{a: 1, b: 127, add: -128, sub: -126, mul: 127, div: 0, mod: 1},
+	itd8{a: 126, b: -128, add: -2, sub: -2, mul: 0, div: 0, mod: 126},
+	itd8{a: 126, b: -127, add: -1, sub: -3, mul: 126, div: 0, mod: 126},
+	itd8{a: 126, b: -1, add: 125, sub: 127, mul: -126, div: -126, mod: 0},
+	itd8{a: 126, b: 0, add: 126, sub: 126, mul: 0},
+	itd8{a: 126, b: 1, add: 127, sub: 125, mul: 126, div: 126, mod: 0},
+	itd8{a: 126, b: 126, add: -4, sub: 0, mul: 4, div: 1, mod: 0},
+	itd8{a: 126, b: 127, add: -3, sub: -1, mul: -126, div: 0, mod: 126},
+	itd8{a: 127, b: -128, add: -1, sub: -1, mul: -128, div: 0, mod: 127},
+	itd8{a: 127, b: -127, add: 0, sub: -2, mul: -1, div: -1, mod: 0},
+	itd8{a: 127, b: -1, add: 126, sub: -128, mul: -127, div: -127, mod: 0},
+	itd8{a: 127, b: 0, add: 127, sub: 127, mul: 0},
+	itd8{a: 127, b: 1, add: -128, sub: 126, mul: 127, div: 127, mod: 0},
+	itd8{a: 127, b: 126, add: -3, sub: 1, mul: -126, div: 1, mod: 1},
+	itd8{a: 127, b: 127, add: -2, sub: 0, mul: 1, div: 1, mod: 0},
+}
+var failed bool
+
+func main() {
+
+	for _, v := range uint64_data {
+		if got := add_uint64_ssa(v.a, v.b); got != v.add {
+			fmt.Printf("add_uint64 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+			failed = true
+		}
+		if got := sub_uint64_ssa(v.a, v.b); got != v.sub {
+			fmt.Printf("sub_uint64 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+			failed = true
+		}
+		if v.b != 0 {
+			if got := div_uint64_ssa(v.a, v.b); got != v.div {
+				fmt.Printf("div_uint64 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+				failed = true
+			}
+
+		}
+		if v.b != 0 {
+			if got := mod_uint64_ssa(v.a, v.b); got != v.mod {
+				fmt.Printf("mod_uint64 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+				failed = true
+			}
+
+		}
+		if got := mul_uint64_ssa(v.a, v.b); got != v.mul {
+			fmt.Printf("mul_uint64 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+			failed = true
+		}
+	}
+	for _, v := range int64_data {
+		if got := add_int64_ssa(v.a, v.b); got != v.add {
+			fmt.Printf("add_int64 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+			failed = true
+		}
+		if got := sub_int64_ssa(v.a, v.b); got != v.sub {
+			fmt.Printf("sub_int64 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+			failed = true
+		}
+		if v.b != 0 {
+			if got := div_int64_ssa(v.a, v.b); got != v.div {
+				fmt.Printf("div_int64 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+				failed = true
+			}
+
+		}
+		if v.b != 0 {
+			if got := mod_int64_ssa(v.a, v.b); got != v.mod {
+				fmt.Printf("mod_int64 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+				failed = true
+			}
+
+		}
+		if got := mul_int64_ssa(v.a, v.b); got != v.mul {
+			fmt.Printf("mul_int64 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+			failed = true
+		}
+	}
+	for _, v := range uint32_data {
+		if got := add_uint32_ssa(v.a, v.b); got != v.add {
+			fmt.Printf("add_uint32 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+			failed = true
+		}
+		if got := sub_uint32_ssa(v.a, v.b); got != v.sub {
+			fmt.Printf("sub_uint32 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+			failed = true
+		}
+		if v.b != 0 {
+			if got := div_uint32_ssa(v.a, v.b); got != v.div {
+				fmt.Printf("div_uint32 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+				failed = true
+			}
+
+		}
+		if v.b != 0 {
+			if got := mod_uint32_ssa(v.a, v.b); got != v.mod {
+				fmt.Printf("mod_uint32 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+				failed = true
+			}
+
+		}
+		if got := mul_uint32_ssa(v.a, v.b); got != v.mul {
+			fmt.Printf("mul_uint32 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+			failed = true
+		}
+	}
+	for _, v := range int32_data {
+		if got := add_int32_ssa(v.a, v.b); got != v.add {
+			fmt.Printf("add_int32 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+			failed = true
+		}
+		if got := sub_int32_ssa(v.a, v.b); got != v.sub {
+			fmt.Printf("sub_int32 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+			failed = true
+		}
+		if v.b != 0 {
+			if got := div_int32_ssa(v.a, v.b); got != v.div {
+				fmt.Printf("div_int32 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+				failed = true
+			}
+
+		}
+		if v.b != 0 {
+			if got := mod_int32_ssa(v.a, v.b); got != v.mod {
+				fmt.Printf("mod_int32 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+				failed = true
+			}
+
+		}
+		if got := mul_int32_ssa(v.a, v.b); got != v.mul {
+			fmt.Printf("mul_int32 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+			failed = true
+		}
+	}
+	for _, v := range uint16_data {
+		if got := add_uint16_ssa(v.a, v.b); got != v.add {
+			fmt.Printf("add_uint16 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+			failed = true
+		}
+		if got := sub_uint16_ssa(v.a, v.b); got != v.sub {
+			fmt.Printf("sub_uint16 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+			failed = true
+		}
+		if v.b != 0 {
+			if got := div_uint16_ssa(v.a, v.b); got != v.div {
+				fmt.Printf("div_uint16 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+				failed = true
+			}
+
+		}
+		if v.b != 0 {
+			if got := mod_uint16_ssa(v.a, v.b); got != v.mod {
+				fmt.Printf("mod_uint16 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+				failed = true
+			}
+
+		}
+		if got := mul_uint16_ssa(v.a, v.b); got != v.mul {
+			fmt.Printf("mul_uint16 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+			failed = true
+		}
+	}
+	for _, v := range int16_data {
+		if got := add_int16_ssa(v.a, v.b); got != v.add {
+			fmt.Printf("add_int16 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+			failed = true
+		}
+		if got := sub_int16_ssa(v.a, v.b); got != v.sub {
+			fmt.Printf("sub_int16 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+			failed = true
+		}
+		if v.b != 0 {
+			if got := div_int16_ssa(v.a, v.b); got != v.div {
+				fmt.Printf("div_int16 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+				failed = true
+			}
+
+		}
+		if v.b != 0 {
+			if got := mod_int16_ssa(v.a, v.b); got != v.mod {
+				fmt.Printf("mod_int16 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+				failed = true
+			}
+
+		}
+		if got := mul_int16_ssa(v.a, v.b); got != v.mul {
+			fmt.Printf("mul_int16 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+			failed = true
+		}
+	}
+	for _, v := range uint8_data {
+		if got := add_uint8_ssa(v.a, v.b); got != v.add {
+			fmt.Printf("add_uint8 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+			failed = true
+		}
+		if got := sub_uint8_ssa(v.a, v.b); got != v.sub {
+			fmt.Printf("sub_uint8 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+			failed = true
+		}
+		if v.b != 0 {
+			if got := div_uint8_ssa(v.a, v.b); got != v.div {
+				fmt.Printf("div_uint8 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+				failed = true
+			}
+
+		}
+		if v.b != 0 {
+			if got := mod_uint8_ssa(v.a, v.b); got != v.mod {
+				fmt.Printf("mod_uint8 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+				failed = true
+			}
+
+		}
+		if got := mul_uint8_ssa(v.a, v.b); got != v.mul {
+			fmt.Printf("mul_uint8 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+			failed = true
+		}
+	}
+	for _, v := range int8_data {
+		if got := add_int8_ssa(v.a, v.b); got != v.add {
+			fmt.Printf("add_int8 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add)
+			failed = true
+		}
+		if got := sub_int8_ssa(v.a, v.b); got != v.sub {
+			fmt.Printf("sub_int8 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub)
+			failed = true
+		}
+		if v.b != 0 {
+			if got := div_int8_ssa(v.a, v.b); got != v.div {
+				fmt.Printf("div_int8 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div)
+				failed = true
+			}
+
+		}
+		if v.b != 0 {
+			if got := mod_int8_ssa(v.a, v.b); got != v.mod {
+				fmt.Printf("mod_int8 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod)
+				failed = true
+			}
+
+		}
+		if got := mul_int8_ssa(v.a, v.b); got != v.mul {
+			fmt.Printf("mul_int8 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul)
+			failed = true
+		}
+	}
+	if failed {
+		panic("tests failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/arithConst_ssa.go b/src/cmd/compile/internal/gc/testdata/arithConst_ssa.go
new file mode 100644
index 0000000..21bcd63
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/arithConst_ssa.go
@@ -0,0 +1,15211 @@
+package main
+
+import "fmt"
+
+//go:noinline
+func add_uint64_0_ssa(a uint64) uint64 {
+	return a + 0
+}
+
+//go:noinline
+func add_0_uint64_ssa(a uint64) uint64 {
+	return 0 + a
+}
+
+//go:noinline
+func add_uint64_1_ssa(a uint64) uint64 {
+	return a + 1
+}
+
+//go:noinline
+func add_1_uint64_ssa(a uint64) uint64 {
+	return 1 + a
+}
+
+//go:noinline
+func add_uint64_4294967296_ssa(a uint64) uint64 {
+	return a + 4294967296
+}
+
+//go:noinline
+func add_4294967296_uint64_ssa(a uint64) uint64 {
+	return 4294967296 + a
+}
+
+//go:noinline
+func add_uint64_18446744073709551615_ssa(a uint64) uint64 {
+	return a + 18446744073709551615
+}
+
+//go:noinline
+func add_18446744073709551615_uint64_ssa(a uint64) uint64 {
+	return 18446744073709551615 + a
+}
+
+//go:noinline
+func sub_uint64_0_ssa(a uint64) uint64 {
+	return a - 0
+}
+
+//go:noinline
+func sub_0_uint64_ssa(a uint64) uint64 {
+	return 0 - a
+}
+
+//go:noinline
+func sub_uint64_1_ssa(a uint64) uint64 {
+	return a - 1
+}
+
+//go:noinline
+func sub_1_uint64_ssa(a uint64) uint64 {
+	return 1 - a
+}
+
+//go:noinline
+func sub_uint64_4294967296_ssa(a uint64) uint64 {
+	return a - 4294967296
+}
+
+//go:noinline
+func sub_4294967296_uint64_ssa(a uint64) uint64 {
+	return 4294967296 - a
+}
+
+//go:noinline
+func sub_uint64_18446744073709551615_ssa(a uint64) uint64 {
+	return a - 18446744073709551615
+}
+
+//go:noinline
+func sub_18446744073709551615_uint64_ssa(a uint64) uint64 {
+	return 18446744073709551615 - a
+}
+
+//go:noinline
+func div_0_uint64_ssa(a uint64) uint64 {
+	return 0 / a
+}
+
+//go:noinline
+func div_uint64_1_ssa(a uint64) uint64 {
+	return a / 1
+}
+
+//go:noinline
+func div_1_uint64_ssa(a uint64) uint64 {
+	return 1 / a
+}
+
+//go:noinline
+func div_uint64_4294967296_ssa(a uint64) uint64 {
+	return a / 4294967296
+}
+
+//go:noinline
+func div_4294967296_uint64_ssa(a uint64) uint64 {
+	return 4294967296 / a
+}
+
+//go:noinline
+func div_uint64_18446744073709551615_ssa(a uint64) uint64 {
+	return a / 18446744073709551615
+}
+
+//go:noinline
+func div_18446744073709551615_uint64_ssa(a uint64) uint64 {
+	return 18446744073709551615 / a
+}
+
+//go:noinline
+func mul_uint64_0_ssa(a uint64) uint64 {
+	return a * 0
+}
+
+//go:noinline
+func mul_0_uint64_ssa(a uint64) uint64 {
+	return 0 * a
+}
+
+//go:noinline
+func mul_uint64_1_ssa(a uint64) uint64 {
+	return a * 1
+}
+
+//go:noinline
+func mul_1_uint64_ssa(a uint64) uint64 {
+	return 1 * a
+}
+
+//go:noinline
+func mul_uint64_4294967296_ssa(a uint64) uint64 {
+	return a * 4294967296
+}
+
+//go:noinline
+func mul_4294967296_uint64_ssa(a uint64) uint64 {
+	return 4294967296 * a
+}
+
+//go:noinline
+func mul_uint64_18446744073709551615_ssa(a uint64) uint64 {
+	return a * 18446744073709551615
+}
+
+//go:noinline
+func mul_18446744073709551615_uint64_ssa(a uint64) uint64 {
+	return 18446744073709551615 * a
+}
+
+//go:noinline
+func lsh_uint64_0_ssa(a uint64) uint64 {
+	return a << 0
+}
+
+//go:noinline
+func lsh_0_uint64_ssa(a uint64) uint64 {
+	return 0 << a
+}
+
+//go:noinline
+func lsh_uint64_1_ssa(a uint64) uint64 {
+	return a << 1
+}
+
+//go:noinline
+func lsh_1_uint64_ssa(a uint64) uint64 {
+	return 1 << a
+}
+
+//go:noinline
+func lsh_uint64_4294967296_ssa(a uint64) uint64 {
+	return a << uint64(4294967296)
+}
+
+//go:noinline
+func lsh_4294967296_uint64_ssa(a uint64) uint64 {
+	return 4294967296 << a
+}
+
+//go:noinline
+func lsh_uint64_18446744073709551615_ssa(a uint64) uint64 {
+	return a << uint64(18446744073709551615)
+}
+
+//go:noinline
+func lsh_18446744073709551615_uint64_ssa(a uint64) uint64 {
+	return 18446744073709551615 << a
+}
+
+//go:noinline
+func rsh_uint64_0_ssa(a uint64) uint64 {
+	return a >> 0
+}
+
+//go:noinline
+func rsh_0_uint64_ssa(a uint64) uint64 {
+	return 0 >> a
+}
+
+//go:noinline
+func rsh_uint64_1_ssa(a uint64) uint64 {
+	return a >> 1
+}
+
+//go:noinline
+func rsh_1_uint64_ssa(a uint64) uint64 {
+	return 1 >> a
+}
+
+//go:noinline
+func rsh_uint64_4294967296_ssa(a uint64) uint64 {
+	return a >> uint64(4294967296)
+}
+
+//go:noinline
+func rsh_4294967296_uint64_ssa(a uint64) uint64 {
+	return 4294967296 >> a
+}
+
+//go:noinline
+func rsh_uint64_18446744073709551615_ssa(a uint64) uint64 {
+	return a >> uint64(18446744073709551615)
+}
+
+//go:noinline
+func rsh_18446744073709551615_uint64_ssa(a uint64) uint64 {
+	return 18446744073709551615 >> a
+}
+
+//go:noinline
+func mod_0_uint64_ssa(a uint64) uint64 {
+	return 0 % a
+}
+
+//go:noinline
+func mod_uint64_1_ssa(a uint64) uint64 {
+	return a % 1
+}
+
+//go:noinline
+func mod_1_uint64_ssa(a uint64) uint64 {
+	return 1 % a
+}
+
+//go:noinline
+func mod_uint64_4294967296_ssa(a uint64) uint64 {
+	return a % 4294967296
+}
+
+//go:noinline
+func mod_4294967296_uint64_ssa(a uint64) uint64 {
+	return 4294967296 % a
+}
+
+//go:noinline
+func mod_uint64_18446744073709551615_ssa(a uint64) uint64 {
+	return a % 18446744073709551615
+}
+
+//go:noinline
+func mod_18446744073709551615_uint64_ssa(a uint64) uint64 {
+	return 18446744073709551615 % a
+}
+
+//go:noinline
+func add_int64_Neg9223372036854775808_ssa(a int64) int64 {
+	return a + -9223372036854775808
+}
+
+//go:noinline
+func add_Neg9223372036854775808_int64_ssa(a int64) int64 {
+	return -9223372036854775808 + a
+}
+
+//go:noinline
+func add_int64_Neg9223372036854775807_ssa(a int64) int64 {
+	return a + -9223372036854775807
+}
+
+//go:noinline
+func add_Neg9223372036854775807_int64_ssa(a int64) int64 {
+	return -9223372036854775807 + a
+}
+
+//go:noinline
+func add_int64_Neg4294967296_ssa(a int64) int64 {
+	return a + -4294967296
+}
+
+//go:noinline
+func add_Neg4294967296_int64_ssa(a int64) int64 {
+	return -4294967296 + a
+}
+
+//go:noinline
+func add_int64_Neg1_ssa(a int64) int64 {
+	return a + -1
+}
+
+//go:noinline
+func add_Neg1_int64_ssa(a int64) int64 {
+	return -1 + a
+}
+
+//go:noinline
+func add_int64_0_ssa(a int64) int64 {
+	return a + 0
+}
+
+//go:noinline
+func add_0_int64_ssa(a int64) int64 {
+	return 0 + a
+}
+
+//go:noinline
+func add_int64_1_ssa(a int64) int64 {
+	return a + 1
+}
+
+//go:noinline
+func add_1_int64_ssa(a int64) int64 {
+	return 1 + a
+}
+
+//go:noinline
+func add_int64_4294967296_ssa(a int64) int64 {
+	return a + 4294967296
+}
+
+//go:noinline
+func add_4294967296_int64_ssa(a int64) int64 {
+	return 4294967296 + a
+}
+
+//go:noinline
+func add_int64_9223372036854775806_ssa(a int64) int64 {
+	return a + 9223372036854775806
+}
+
+//go:noinline
+func add_9223372036854775806_int64_ssa(a int64) int64 {
+	return 9223372036854775806 + a
+}
+
+//go:noinline
+func add_int64_9223372036854775807_ssa(a int64) int64 {
+	return a + 9223372036854775807
+}
+
+//go:noinline
+func add_9223372036854775807_int64_ssa(a int64) int64 {
+	return 9223372036854775807 + a
+}
+
+//go:noinline
+func sub_int64_Neg9223372036854775808_ssa(a int64) int64 {
+	return a - -9223372036854775808
+}
+
+//go:noinline
+func sub_Neg9223372036854775808_int64_ssa(a int64) int64 {
+	return -9223372036854775808 - a
+}
+
+//go:noinline
+func sub_int64_Neg9223372036854775807_ssa(a int64) int64 {
+	return a - -9223372036854775807
+}
+
+//go:noinline
+func sub_Neg9223372036854775807_int64_ssa(a int64) int64 {
+	return -9223372036854775807 - a
+}
+
+//go:noinline
+func sub_int64_Neg4294967296_ssa(a int64) int64 {
+	return a - -4294967296
+}
+
+//go:noinline
+func sub_Neg4294967296_int64_ssa(a int64) int64 {
+	return -4294967296 - a
+}
+
+//go:noinline
+func sub_int64_Neg1_ssa(a int64) int64 {
+	return a - -1
+}
+
+//go:noinline
+func sub_Neg1_int64_ssa(a int64) int64 {
+	return -1 - a
+}
+
+//go:noinline
+func sub_int64_0_ssa(a int64) int64 {
+	return a - 0
+}
+
+//go:noinline
+func sub_0_int64_ssa(a int64) int64 {
+	return 0 - a
+}
+
+//go:noinline
+func sub_int64_1_ssa(a int64) int64 {
+	return a - 1
+}
+
+//go:noinline
+func sub_1_int64_ssa(a int64) int64 {
+	return 1 - a
+}
+
+//go:noinline
+func sub_int64_4294967296_ssa(a int64) int64 {
+	return a - 4294967296
+}
+
+//go:noinline
+func sub_4294967296_int64_ssa(a int64) int64 {
+	return 4294967296 - a
+}
+
+//go:noinline
+func sub_int64_9223372036854775806_ssa(a int64) int64 {
+	return a - 9223372036854775806
+}
+
+//go:noinline
+func sub_9223372036854775806_int64_ssa(a int64) int64 {
+	return 9223372036854775806 - a
+}
+
+//go:noinline
+func sub_int64_9223372036854775807_ssa(a int64) int64 {
+	return a - 9223372036854775807
+}
+
+//go:noinline
+func sub_9223372036854775807_int64_ssa(a int64) int64 {
+	return 9223372036854775807 - a
+}
+
+//go:noinline
+func div_int64_Neg9223372036854775808_ssa(a int64) int64 {
+	return a / -9223372036854775808
+}
+
+//go:noinline
+func div_Neg9223372036854775808_int64_ssa(a int64) int64 {
+	return -9223372036854775808 / a
+}
+
+//go:noinline
+func div_int64_Neg9223372036854775807_ssa(a int64) int64 {
+	return a / -9223372036854775807
+}
+
+//go:noinline
+func div_Neg9223372036854775807_int64_ssa(a int64) int64 {
+	return -9223372036854775807 / a
+}
+
+//go:noinline
+func div_int64_Neg4294967296_ssa(a int64) int64 {
+	return a / -4294967296
+}
+
+//go:noinline
+func div_Neg4294967296_int64_ssa(a int64) int64 {
+	return -4294967296 / a
+}
+
+//go:noinline
+func div_int64_Neg1_ssa(a int64) int64 {
+	return a / -1
+}
+
+//go:noinline
+func div_Neg1_int64_ssa(a int64) int64 {
+	return -1 / a
+}
+
+//go:noinline
+func div_0_int64_ssa(a int64) int64 {
+	return 0 / a
+}
+
+//go:noinline
+func div_int64_1_ssa(a int64) int64 {
+	return a / 1
+}
+
+//go:noinline
+func div_1_int64_ssa(a int64) int64 {
+	return 1 / a
+}
+
+//go:noinline
+func div_int64_4294967296_ssa(a int64) int64 {
+	return a / 4294967296
+}
+
+//go:noinline
+func div_4294967296_int64_ssa(a int64) int64 {
+	return 4294967296 / a
+}
+
+//go:noinline
+func div_int64_9223372036854775806_ssa(a int64) int64 {
+	return a / 9223372036854775806
+}
+
+//go:noinline
+func div_9223372036854775806_int64_ssa(a int64) int64 {
+	return 9223372036854775806 / a
+}
+
+//go:noinline
+func div_int64_9223372036854775807_ssa(a int64) int64 {
+	return a / 9223372036854775807
+}
+
+//go:noinline
+func div_9223372036854775807_int64_ssa(a int64) int64 {
+	return 9223372036854775807 / a
+}
+
+//go:noinline
+func mul_int64_Neg9223372036854775808_ssa(a int64) int64 {
+	return a * -9223372036854775808
+}
+
+//go:noinline
+func mul_Neg9223372036854775808_int64_ssa(a int64) int64 {
+	return -9223372036854775808 * a
+}
+
+//go:noinline
+func mul_int64_Neg9223372036854775807_ssa(a int64) int64 {
+	return a * -9223372036854775807
+}
+
+//go:noinline
+func mul_Neg9223372036854775807_int64_ssa(a int64) int64 {
+	return -9223372036854775807 * a
+}
+
+//go:noinline
+func mul_int64_Neg4294967296_ssa(a int64) int64 {
+	return a * -4294967296
+}
+
+//go:noinline
+func mul_Neg4294967296_int64_ssa(a int64) int64 {
+	return -4294967296 * a
+}
+
+//go:noinline
+func mul_int64_Neg1_ssa(a int64) int64 {
+	return a * -1
+}
+
+//go:noinline
+func mul_Neg1_int64_ssa(a int64) int64 {
+	return -1 * a
+}
+
+//go:noinline
+func mul_int64_0_ssa(a int64) int64 {
+	return a * 0
+}
+
+//go:noinline
+func mul_0_int64_ssa(a int64) int64 {
+	return 0 * a
+}
+
+//go:noinline
+func mul_int64_1_ssa(a int64) int64 {
+	return a * 1
+}
+
+//go:noinline
+func mul_1_int64_ssa(a int64) int64 {
+	return 1 * a
+}
+
+//go:noinline
+func mul_int64_4294967296_ssa(a int64) int64 {
+	return a * 4294967296
+}
+
+//go:noinline
+func mul_4294967296_int64_ssa(a int64) int64 {
+	return 4294967296 * a
+}
+
+//go:noinline
+func mul_int64_9223372036854775806_ssa(a int64) int64 {
+	return a * 9223372036854775806
+}
+
+//go:noinline
+func mul_9223372036854775806_int64_ssa(a int64) int64 {
+	return 9223372036854775806 * a
+}
+
+//go:noinline
+func mul_int64_9223372036854775807_ssa(a int64) int64 {
+	return a * 9223372036854775807
+}
+
+//go:noinline
+func mul_9223372036854775807_int64_ssa(a int64) int64 {
+	return 9223372036854775807 * a
+}
+
+//go:noinline
+func mod_int64_Neg9223372036854775808_ssa(a int64) int64 {
+	return a % -9223372036854775808
+}
+
+//go:noinline
+func mod_Neg9223372036854775808_int64_ssa(a int64) int64 {
+	return -9223372036854775808 % a
+}
+
+//go:noinline
+func mod_int64_Neg9223372036854775807_ssa(a int64) int64 {
+	return a % -9223372036854775807
+}
+
+//go:noinline
+func mod_Neg9223372036854775807_int64_ssa(a int64) int64 {
+	return -9223372036854775807 % a
+}
+
+//go:noinline
+func mod_int64_Neg4294967296_ssa(a int64) int64 {
+	return a % -4294967296
+}
+
+//go:noinline
+func mod_Neg4294967296_int64_ssa(a int64) int64 {
+	return -4294967296 % a
+}
+
+//go:noinline
+func mod_int64_Neg1_ssa(a int64) int64 {
+	return a % -1
+}
+
+//go:noinline
+func mod_Neg1_int64_ssa(a int64) int64 {
+	return -1 % a
+}
+
+//go:noinline
+func mod_0_int64_ssa(a int64) int64 {
+	return 0 % a
+}
+
+//go:noinline
+func mod_int64_1_ssa(a int64) int64 {
+	return a % 1
+}
+
+//go:noinline
+func mod_1_int64_ssa(a int64) int64 {
+	return 1 % a
+}
+
+//go:noinline
+func mod_int64_4294967296_ssa(a int64) int64 {
+	return a % 4294967296
+}
+
+//go:noinline
+func mod_4294967296_int64_ssa(a int64) int64 {
+	return 4294967296 % a
+}
+
+//go:noinline
+func mod_int64_9223372036854775806_ssa(a int64) int64 {
+	return a % 9223372036854775806
+}
+
+//go:noinline
+func mod_9223372036854775806_int64_ssa(a int64) int64 {
+	return 9223372036854775806 % a
+}
+
+//go:noinline
+func mod_int64_9223372036854775807_ssa(a int64) int64 {
+	return a % 9223372036854775807
+}
+
+//go:noinline
+func mod_9223372036854775807_int64_ssa(a int64) int64 {
+	return 9223372036854775807 % a
+}
+
+//go:noinline
+func add_uint32_0_ssa(a uint32) uint32 {
+	return a + 0
+}
+
+//go:noinline
+func add_0_uint32_ssa(a uint32) uint32 {
+	return 0 + a
+}
+
+//go:noinline
+func add_uint32_1_ssa(a uint32) uint32 {
+	return a + 1
+}
+
+//go:noinline
+func add_1_uint32_ssa(a uint32) uint32 {
+	return 1 + a
+}
+
+//go:noinline
+func add_uint32_4294967295_ssa(a uint32) uint32 {
+	return a + 4294967295
+}
+
+//go:noinline
+func add_4294967295_uint32_ssa(a uint32) uint32 {
+	return 4294967295 + a
+}
+
+//go:noinline
+func sub_uint32_0_ssa(a uint32) uint32 {
+	return a - 0
+}
+
+//go:noinline
+func sub_0_uint32_ssa(a uint32) uint32 {
+	return 0 - a
+}
+
+//go:noinline
+func sub_uint32_1_ssa(a uint32) uint32 {
+	return a - 1
+}
+
+//go:noinline
+func sub_1_uint32_ssa(a uint32) uint32 {
+	return 1 - a
+}
+
+//go:noinline
+func sub_uint32_4294967295_ssa(a uint32) uint32 {
+	return a - 4294967295
+}
+
+//go:noinline
+func sub_4294967295_uint32_ssa(a uint32) uint32 {
+	return 4294967295 - a
+}
+
+//go:noinline
+func div_0_uint32_ssa(a uint32) uint32 {
+	return 0 / a
+}
+
+//go:noinline
+func div_uint32_1_ssa(a uint32) uint32 {
+	return a / 1
+}
+
+//go:noinline
+func div_1_uint32_ssa(a uint32) uint32 {
+	return 1 / a
+}
+
+//go:noinline
+func div_uint32_4294967295_ssa(a uint32) uint32 {
+	return a / 4294967295
+}
+
+//go:noinline
+func div_4294967295_uint32_ssa(a uint32) uint32 {
+	return 4294967295 / a
+}
+
+//go:noinline
+func mul_uint32_0_ssa(a uint32) uint32 {
+	return a * 0
+}
+
+//go:noinline
+func mul_0_uint32_ssa(a uint32) uint32 {
+	return 0 * a
+}
+
+//go:noinline
+func mul_uint32_1_ssa(a uint32) uint32 {
+	return a * 1
+}
+
+//go:noinline
+func mul_1_uint32_ssa(a uint32) uint32 {
+	return 1 * a
+}
+
+//go:noinline
+func mul_uint32_4294967295_ssa(a uint32) uint32 {
+	return a * 4294967295
+}
+
+//go:noinline
+func mul_4294967295_uint32_ssa(a uint32) uint32 {
+	return 4294967295 * a
+}
+
+//go:noinline
+func lsh_uint32_0_ssa(a uint32) uint32 {
+	return a << 0
+}
+
+//go:noinline
+func lsh_0_uint32_ssa(a uint32) uint32 {
+	return 0 << a
+}
+
+//go:noinline
+func lsh_uint32_1_ssa(a uint32) uint32 {
+	return a << 1
+}
+
+//go:noinline
+func lsh_1_uint32_ssa(a uint32) uint32 {
+	return 1 << a
+}
+
+//go:noinline
+func lsh_uint32_4294967295_ssa(a uint32) uint32 {
+	return a << 4294967295
+}
+
+//go:noinline
+func lsh_4294967295_uint32_ssa(a uint32) uint32 {
+	return 4294967295 << a
+}
+
+//go:noinline
+func rsh_uint32_0_ssa(a uint32) uint32 {
+	return a >> 0
+}
+
+//go:noinline
+func rsh_0_uint32_ssa(a uint32) uint32 {
+	return 0 >> a
+}
+
+//go:noinline
+func rsh_uint32_1_ssa(a uint32) uint32 {
+	return a >> 1
+}
+
+//go:noinline
+func rsh_1_uint32_ssa(a uint32) uint32 {
+	return 1 >> a
+}
+
+//go:noinline
+func rsh_uint32_4294967295_ssa(a uint32) uint32 {
+	return a >> 4294967295
+}
+
+//go:noinline
+func rsh_4294967295_uint32_ssa(a uint32) uint32 {
+	return 4294967295 >> a
+}
+
+//go:noinline
+func mod_0_uint32_ssa(a uint32) uint32 {
+	return 0 % a
+}
+
+//go:noinline
+func mod_uint32_1_ssa(a uint32) uint32 {
+	return a % 1
+}
+
+//go:noinline
+func mod_1_uint32_ssa(a uint32) uint32 {
+	return 1 % a
+}
+
+//go:noinline
+func mod_uint32_4294967295_ssa(a uint32) uint32 {
+	return a % 4294967295
+}
+
+//go:noinline
+func mod_4294967295_uint32_ssa(a uint32) uint32 {
+	return 4294967295 % a
+}
+
+//go:noinline
+func add_int32_Neg2147483648_ssa(a int32) int32 {
+	return a + -2147483648
+}
+
+//go:noinline
+func add_Neg2147483648_int32_ssa(a int32) int32 {
+	return -2147483648 + a
+}
+
+//go:noinline
+func add_int32_Neg2147483647_ssa(a int32) int32 {
+	return a + -2147483647
+}
+
+//go:noinline
+func add_Neg2147483647_int32_ssa(a int32) int32 {
+	return -2147483647 + a
+}
+
+//go:noinline
+func add_int32_Neg1_ssa(a int32) int32 {
+	return a + -1
+}
+
+//go:noinline
+func add_Neg1_int32_ssa(a int32) int32 {
+	return -1 + a
+}
+
+//go:noinline
+func add_int32_0_ssa(a int32) int32 {
+	return a + 0
+}
+
+//go:noinline
+func add_0_int32_ssa(a int32) int32 {
+	return 0 + a
+}
+
+//go:noinline
+func add_int32_1_ssa(a int32) int32 {
+	return a + 1
+}
+
+//go:noinline
+func add_1_int32_ssa(a int32) int32 {
+	return 1 + a
+}
+
+//go:noinline
+func add_int32_2147483647_ssa(a int32) int32 {
+	return a + 2147483647
+}
+
+//go:noinline
+func add_2147483647_int32_ssa(a int32) int32 {
+	return 2147483647 + a
+}
+
+//go:noinline
+func sub_int32_Neg2147483648_ssa(a int32) int32 {
+	return a - -2147483648
+}
+
+//go:noinline
+func sub_Neg2147483648_int32_ssa(a int32) int32 {
+	return -2147483648 - a
+}
+
+//go:noinline
+func sub_int32_Neg2147483647_ssa(a int32) int32 {
+	return a - -2147483647
+}
+
+//go:noinline
+func sub_Neg2147483647_int32_ssa(a int32) int32 {
+	return -2147483647 - a
+}
+
+//go:noinline
+func sub_int32_Neg1_ssa(a int32) int32 {
+	return a - -1
+}
+
+//go:noinline
+func sub_Neg1_int32_ssa(a int32) int32 {
+	return -1 - a
+}
+
+//go:noinline
+func sub_int32_0_ssa(a int32) int32 {
+	return a - 0
+}
+
+//go:noinline
+func sub_0_int32_ssa(a int32) int32 {
+	return 0 - a
+}
+
+//go:noinline
+func sub_int32_1_ssa(a int32) int32 {
+	return a - 1
+}
+
+//go:noinline
+func sub_1_int32_ssa(a int32) int32 {
+	return 1 - a
+}
+
+//go:noinline
+func sub_int32_2147483647_ssa(a int32) int32 {
+	return a - 2147483647
+}
+
+//go:noinline
+func sub_2147483647_int32_ssa(a int32) int32 {
+	return 2147483647 - a
+}
+
+//go:noinline
+func div_int32_Neg2147483648_ssa(a int32) int32 {
+	return a / -2147483648
+}
+
+//go:noinline
+func div_Neg2147483648_int32_ssa(a int32) int32 {
+	return -2147483648 / a
+}
+
+//go:noinline
+func div_int32_Neg2147483647_ssa(a int32) int32 {
+	return a / -2147483647
+}
+
+//go:noinline
+func div_Neg2147483647_int32_ssa(a int32) int32 {
+	return -2147483647 / a
+}
+
+//go:noinline
+func div_int32_Neg1_ssa(a int32) int32 {
+	return a / -1
+}
+
+//go:noinline
+func div_Neg1_int32_ssa(a int32) int32 {
+	return -1 / a
+}
+
+//go:noinline
+func div_0_int32_ssa(a int32) int32 {
+	return 0 / a
+}
+
+//go:noinline
+func div_int32_1_ssa(a int32) int32 {
+	return a / 1
+}
+
+//go:noinline
+func div_1_int32_ssa(a int32) int32 {
+	return 1 / a
+}
+
+//go:noinline
+func div_int32_2147483647_ssa(a int32) int32 {
+	return a / 2147483647
+}
+
+//go:noinline
+func div_2147483647_int32_ssa(a int32) int32 {
+	return 2147483647 / a
+}
+
+//go:noinline
+func mul_int32_Neg2147483648_ssa(a int32) int32 {
+	return a * -2147483648
+}
+
+//go:noinline
+func mul_Neg2147483648_int32_ssa(a int32) int32 {
+	return -2147483648 * a
+}
+
+//go:noinline
+func mul_int32_Neg2147483647_ssa(a int32) int32 {
+	return a * -2147483647
+}
+
+//go:noinline
+func mul_Neg2147483647_int32_ssa(a int32) int32 {
+	return -2147483647 * a
+}
+
+//go:noinline
+func mul_int32_Neg1_ssa(a int32) int32 {
+	return a * -1
+}
+
+//go:noinline
+func mul_Neg1_int32_ssa(a int32) int32 {
+	return -1 * a
+}
+
+//go:noinline
+func mul_int32_0_ssa(a int32) int32 {
+	return a * 0
+}
+
+//go:noinline
+func mul_0_int32_ssa(a int32) int32 {
+	return 0 * a
+}
+
+//go:noinline
+func mul_int32_1_ssa(a int32) int32 {
+	return a * 1
+}
+
+//go:noinline
+func mul_1_int32_ssa(a int32) int32 {
+	return 1 * a
+}
+
+//go:noinline
+func mul_int32_2147483647_ssa(a int32) int32 {
+	return a * 2147483647
+}
+
+//go:noinline
+func mul_2147483647_int32_ssa(a int32) int32 {
+	return 2147483647 * a
+}
+
+//go:noinline
+func mod_int32_Neg2147483648_ssa(a int32) int32 {
+	return a % -2147483648
+}
+
+//go:noinline
+func mod_Neg2147483648_int32_ssa(a int32) int32 {
+	return -2147483648 % a
+}
+
+//go:noinline
+func mod_int32_Neg2147483647_ssa(a int32) int32 {
+	return a % -2147483647
+}
+
+//go:noinline
+func mod_Neg2147483647_int32_ssa(a int32) int32 {
+	return -2147483647 % a
+}
+
+//go:noinline
+func mod_int32_Neg1_ssa(a int32) int32 {
+	return a % -1
+}
+
+//go:noinline
+func mod_Neg1_int32_ssa(a int32) int32 {
+	return -1 % a
+}
+
+//go:noinline
+func mod_0_int32_ssa(a int32) int32 {
+	return 0 % a
+}
+
+//go:noinline
+func mod_int32_1_ssa(a int32) int32 {
+	return a % 1
+}
+
+//go:noinline
+func mod_1_int32_ssa(a int32) int32 {
+	return 1 % a
+}
+
+//go:noinline
+func mod_int32_2147483647_ssa(a int32) int32 {
+	return a % 2147483647
+}
+
+//go:noinline
+func mod_2147483647_int32_ssa(a int32) int32 {
+	return 2147483647 % a
+}
+
+//go:noinline
+func add_uint16_0_ssa(a uint16) uint16 {
+	return a + 0
+}
+
+//go:noinline
+func add_0_uint16_ssa(a uint16) uint16 {
+	return 0 + a
+}
+
+//go:noinline
+func add_uint16_1_ssa(a uint16) uint16 {
+	return a + 1
+}
+
+//go:noinline
+func add_1_uint16_ssa(a uint16) uint16 {
+	return 1 + a
+}
+
+//go:noinline
+func add_uint16_65535_ssa(a uint16) uint16 {
+	return a + 65535
+}
+
+//go:noinline
+func add_65535_uint16_ssa(a uint16) uint16 {
+	return 65535 + a
+}
+
+//go:noinline
+func sub_uint16_0_ssa(a uint16) uint16 {
+	return a - 0
+}
+
+//go:noinline
+func sub_0_uint16_ssa(a uint16) uint16 {
+	return 0 - a
+}
+
+//go:noinline
+func sub_uint16_1_ssa(a uint16) uint16 {
+	return a - 1
+}
+
+//go:noinline
+func sub_1_uint16_ssa(a uint16) uint16 {
+	return 1 - a
+}
+
+//go:noinline
+func sub_uint16_65535_ssa(a uint16) uint16 {
+	return a - 65535
+}
+
+//go:noinline
+func sub_65535_uint16_ssa(a uint16) uint16 {
+	return 65535 - a
+}
+
+//go:noinline
+func div_0_uint16_ssa(a uint16) uint16 {
+	return 0 / a
+}
+
+//go:noinline
+func div_uint16_1_ssa(a uint16) uint16 {
+	return a / 1
+}
+
+//go:noinline
+func div_1_uint16_ssa(a uint16) uint16 {
+	return 1 / a
+}
+
+//go:noinline
+func div_uint16_65535_ssa(a uint16) uint16 {
+	return a / 65535
+}
+
+//go:noinline
+func div_65535_uint16_ssa(a uint16) uint16 {
+	return 65535 / a
+}
+
+//go:noinline
+func mul_uint16_0_ssa(a uint16) uint16 {
+	return a * 0
+}
+
+//go:noinline
+func mul_0_uint16_ssa(a uint16) uint16 {
+	return 0 * a
+}
+
+//go:noinline
+func mul_uint16_1_ssa(a uint16) uint16 {
+	return a * 1
+}
+
+//go:noinline
+func mul_1_uint16_ssa(a uint16) uint16 {
+	return 1 * a
+}
+
+//go:noinline
+func mul_uint16_65535_ssa(a uint16) uint16 {
+	return a * 65535
+}
+
+//go:noinline
+func mul_65535_uint16_ssa(a uint16) uint16 {
+	return 65535 * a
+}
+
+//go:noinline
+func lsh_uint16_0_ssa(a uint16) uint16 {
+	return a << 0
+}
+
+//go:noinline
+func lsh_0_uint16_ssa(a uint16) uint16 {
+	return 0 << a
+}
+
+//go:noinline
+func lsh_uint16_1_ssa(a uint16) uint16 {
+	return a << 1
+}
+
+//go:noinline
+func lsh_1_uint16_ssa(a uint16) uint16 {
+	return 1 << a
+}
+
+//go:noinline
+func lsh_uint16_65535_ssa(a uint16) uint16 {
+	return a << 65535
+}
+
+//go:noinline
+func lsh_65535_uint16_ssa(a uint16) uint16 {
+	return 65535 << a
+}
+
+//go:noinline
+func rsh_uint16_0_ssa(a uint16) uint16 {
+	return a >> 0
+}
+
+//go:noinline
+func rsh_0_uint16_ssa(a uint16) uint16 {
+	return 0 >> a
+}
+
+//go:noinline
+func rsh_uint16_1_ssa(a uint16) uint16 {
+	return a >> 1
+}
+
+//go:noinline
+func rsh_1_uint16_ssa(a uint16) uint16 {
+	return 1 >> a
+}
+
+//go:noinline
+func rsh_uint16_65535_ssa(a uint16) uint16 {
+	return a >> 65535
+}
+
+//go:noinline
+func rsh_65535_uint16_ssa(a uint16) uint16 {
+	return 65535 >> a
+}
+
+//go:noinline
+func mod_0_uint16_ssa(a uint16) uint16 {
+	return 0 % a
+}
+
+//go:noinline
+func mod_uint16_1_ssa(a uint16) uint16 {
+	return a % 1
+}
+
+//go:noinline
+func mod_1_uint16_ssa(a uint16) uint16 {
+	return 1 % a
+}
+
+//go:noinline
+func mod_uint16_65535_ssa(a uint16) uint16 {
+	return a % 65535
+}
+
+//go:noinline
+func mod_65535_uint16_ssa(a uint16) uint16 {
+	return 65535 % a
+}
+
+//go:noinline
+func add_int16_Neg32768_ssa(a int16) int16 {
+	return a + -32768
+}
+
+//go:noinline
+func add_Neg32768_int16_ssa(a int16) int16 {
+	return -32768 + a
+}
+
+//go:noinline
+func add_int16_Neg32767_ssa(a int16) int16 {
+	return a + -32767
+}
+
+//go:noinline
+func add_Neg32767_int16_ssa(a int16) int16 {
+	return -32767 + a
+}
+
+//go:noinline
+func add_int16_Neg1_ssa(a int16) int16 {
+	return a + -1
+}
+
+//go:noinline
+func add_Neg1_int16_ssa(a int16) int16 {
+	return -1 + a
+}
+
+//go:noinline
+func add_int16_0_ssa(a int16) int16 {
+	return a + 0
+}
+
+//go:noinline
+func add_0_int16_ssa(a int16) int16 {
+	return 0 + a
+}
+
+//go:noinline
+func add_int16_1_ssa(a int16) int16 {
+	return a + 1
+}
+
+//go:noinline
+func add_1_int16_ssa(a int16) int16 {
+	return 1 + a
+}
+
+//go:noinline
+func add_int16_32766_ssa(a int16) int16 {
+	return a + 32766
+}
+
+//go:noinline
+func add_32766_int16_ssa(a int16) int16 {
+	return 32766 + a
+}
+
+//go:noinline
+func add_int16_32767_ssa(a int16) int16 {
+	return a + 32767
+}
+
+//go:noinline
+func add_32767_int16_ssa(a int16) int16 {
+	return 32767 + a
+}
+
+//go:noinline
+func sub_int16_Neg32768_ssa(a int16) int16 {
+	return a - -32768
+}
+
+//go:noinline
+func sub_Neg32768_int16_ssa(a int16) int16 {
+	return -32768 - a
+}
+
+//go:noinline
+func sub_int16_Neg32767_ssa(a int16) int16 {
+	return a - -32767
+}
+
+//go:noinline
+func sub_Neg32767_int16_ssa(a int16) int16 {
+	return -32767 - a
+}
+
+//go:noinline
+func sub_int16_Neg1_ssa(a int16) int16 {
+	return a - -1
+}
+
+//go:noinline
+func sub_Neg1_int16_ssa(a int16) int16 {
+	return -1 - a
+}
+
+//go:noinline
+func sub_int16_0_ssa(a int16) int16 {
+	return a - 0
+}
+
+//go:noinline
+func sub_0_int16_ssa(a int16) int16 {
+	return 0 - a
+}
+
+//go:noinline
+func sub_int16_1_ssa(a int16) int16 {
+	return a - 1
+}
+
+//go:noinline
+func sub_1_int16_ssa(a int16) int16 {
+	return 1 - a
+}
+
+//go:noinline
+func sub_int16_32766_ssa(a int16) int16 {
+	return a - 32766
+}
+
+//go:noinline
+func sub_32766_int16_ssa(a int16) int16 {
+	return 32766 - a
+}
+
+//go:noinline
+func sub_int16_32767_ssa(a int16) int16 {
+	return a - 32767
+}
+
+//go:noinline
+func sub_32767_int16_ssa(a int16) int16 {
+	return 32767 - a
+}
+
+//go:noinline
+func div_int16_Neg32768_ssa(a int16) int16 {
+	return a / -32768
+}
+
+//go:noinline
+func div_Neg32768_int16_ssa(a int16) int16 {
+	return -32768 / a
+}
+
+//go:noinline
+func div_int16_Neg32767_ssa(a int16) int16 {
+	return a / -32767
+}
+
+//go:noinline
+func div_Neg32767_int16_ssa(a int16) int16 {
+	return -32767 / a
+}
+
+//go:noinline
+func div_int16_Neg1_ssa(a int16) int16 {
+	return a / -1
+}
+
+//go:noinline
+func div_Neg1_int16_ssa(a int16) int16 {
+	return -1 / a
+}
+
+//go:noinline
+func div_0_int16_ssa(a int16) int16 {
+	return 0 / a
+}
+
+//go:noinline
+func div_int16_1_ssa(a int16) int16 {
+	return a / 1
+}
+
+//go:noinline
+func div_1_int16_ssa(a int16) int16 {
+	return 1 / a
+}
+
+//go:noinline
+func div_int16_32766_ssa(a int16) int16 {
+	return a / 32766
+}
+
+//go:noinline
+func div_32766_int16_ssa(a int16) int16 {
+	return 32766 / a
+}
+
+//go:noinline
+func div_int16_32767_ssa(a int16) int16 {
+	return a / 32767
+}
+
+//go:noinline
+func div_32767_int16_ssa(a int16) int16 {
+	return 32767 / a
+}
+
+//go:noinline
+func mul_int16_Neg32768_ssa(a int16) int16 {
+	return a * -32768
+}
+
+//go:noinline
+func mul_Neg32768_int16_ssa(a int16) int16 {
+	return -32768 * a
+}
+
+//go:noinline
+func mul_int16_Neg32767_ssa(a int16) int16 {
+	return a * -32767
+}
+
+//go:noinline
+func mul_Neg32767_int16_ssa(a int16) int16 {
+	return -32767 * a
+}
+
+//go:noinline
+func mul_int16_Neg1_ssa(a int16) int16 {
+	return a * -1
+}
+
+//go:noinline
+func mul_Neg1_int16_ssa(a int16) int16 {
+	return -1 * a
+}
+
+//go:noinline
+func mul_int16_0_ssa(a int16) int16 {
+	return a * 0
+}
+
+//go:noinline
+func mul_0_int16_ssa(a int16) int16 {
+	return 0 * a
+}
+
+//go:noinline
+func mul_int16_1_ssa(a int16) int16 {
+	return a * 1
+}
+
+//go:noinline
+func mul_1_int16_ssa(a int16) int16 {
+	return 1 * a
+}
+
+//go:noinline
+func mul_int16_32766_ssa(a int16) int16 {
+	return a * 32766
+}
+
+//go:noinline
+func mul_32766_int16_ssa(a int16) int16 {
+	return 32766 * a
+}
+
+//go:noinline
+func mul_int16_32767_ssa(a int16) int16 {
+	return a * 32767
+}
+
+//go:noinline
+func mul_32767_int16_ssa(a int16) int16 {
+	return 32767 * a
+}
+
+//go:noinline
+func mod_int16_Neg32768_ssa(a int16) int16 {
+	return a % -32768
+}
+
+//go:noinline
+func mod_Neg32768_int16_ssa(a int16) int16 {
+	return -32768 % a
+}
+
+//go:noinline
+func mod_int16_Neg32767_ssa(a int16) int16 {
+	return a % -32767
+}
+
+//go:noinline
+func mod_Neg32767_int16_ssa(a int16) int16 {
+	return -32767 % a
+}
+
+//go:noinline
+func mod_int16_Neg1_ssa(a int16) int16 {
+	return a % -1
+}
+
+//go:noinline
+func mod_Neg1_int16_ssa(a int16) int16 {
+	return -1 % a
+}
+
+//go:noinline
+func mod_0_int16_ssa(a int16) int16 {
+	return 0 % a
+}
+
+//go:noinline
+func mod_int16_1_ssa(a int16) int16 {
+	return a % 1
+}
+
+//go:noinline
+func mod_1_int16_ssa(a int16) int16 {
+	return 1 % a
+}
+
+//go:noinline
+func mod_int16_32766_ssa(a int16) int16 {
+	return a % 32766
+}
+
+//go:noinline
+func mod_32766_int16_ssa(a int16) int16 {
+	return 32766 % a
+}
+
+//go:noinline
+func mod_int16_32767_ssa(a int16) int16 {
+	return a % 32767
+}
+
+//go:noinline
+func mod_32767_int16_ssa(a int16) int16 {
+	return 32767 % a
+}
+
+//go:noinline
+func add_uint8_0_ssa(a uint8) uint8 {
+	return a + 0
+}
+
+//go:noinline
+func add_0_uint8_ssa(a uint8) uint8 {
+	return 0 + a
+}
+
+//go:noinline
+func add_uint8_1_ssa(a uint8) uint8 {
+	return a + 1
+}
+
+//go:noinline
+func add_1_uint8_ssa(a uint8) uint8 {
+	return 1 + a
+}
+
+//go:noinline
+func add_uint8_255_ssa(a uint8) uint8 {
+	return a + 255
+}
+
+//go:noinline
+func add_255_uint8_ssa(a uint8) uint8 {
+	return 255 + a
+}
+
+//go:noinline
+func sub_uint8_0_ssa(a uint8) uint8 {
+	return a - 0
+}
+
+//go:noinline
+func sub_0_uint8_ssa(a uint8) uint8 {
+	return 0 - a
+}
+
+//go:noinline
+func sub_uint8_1_ssa(a uint8) uint8 {
+	return a - 1
+}
+
+//go:noinline
+func sub_1_uint8_ssa(a uint8) uint8 {
+	return 1 - a
+}
+
+//go:noinline
+func sub_uint8_255_ssa(a uint8) uint8 {
+	return a - 255
+}
+
+//go:noinline
+func sub_255_uint8_ssa(a uint8) uint8 {
+	return 255 - a
+}
+
+//go:noinline
+func div_0_uint8_ssa(a uint8) uint8 {
+	return 0 / a
+}
+
+//go:noinline
+func div_uint8_1_ssa(a uint8) uint8 {
+	return a / 1
+}
+
+//go:noinline
+func div_1_uint8_ssa(a uint8) uint8 {
+	return 1 / a
+}
+
+//go:noinline
+func div_uint8_255_ssa(a uint8) uint8 {
+	return a / 255
+}
+
+//go:noinline
+func div_255_uint8_ssa(a uint8) uint8 {
+	return 255 / a
+}
+
+//go:noinline
+func mul_uint8_0_ssa(a uint8) uint8 {
+	return a * 0
+}
+
+//go:noinline
+func mul_0_uint8_ssa(a uint8) uint8 {
+	return 0 * a
+}
+
+//go:noinline
+func mul_uint8_1_ssa(a uint8) uint8 {
+	return a * 1
+}
+
+//go:noinline
+func mul_1_uint8_ssa(a uint8) uint8 {
+	return 1 * a
+}
+
+//go:noinline
+func mul_uint8_255_ssa(a uint8) uint8 {
+	return a * 255
+}
+
+//go:noinline
+func mul_255_uint8_ssa(a uint8) uint8 {
+	return 255 * a
+}
+
+//go:noinline
+func lsh_uint8_0_ssa(a uint8) uint8 {
+	return a << 0
+}
+
+//go:noinline
+func lsh_0_uint8_ssa(a uint8) uint8 {
+	return 0 << a
+}
+
+//go:noinline
+func lsh_uint8_1_ssa(a uint8) uint8 {
+	return a << 1
+}
+
+//go:noinline
+func lsh_1_uint8_ssa(a uint8) uint8 {
+	return 1 << a
+}
+
+//go:noinline
+func lsh_uint8_255_ssa(a uint8) uint8 {
+	return a << 255
+}
+
+//go:noinline
+func lsh_255_uint8_ssa(a uint8) uint8 {
+	return 255 << a
+}
+
+//go:noinline
+func rsh_uint8_0_ssa(a uint8) uint8 {
+	return a >> 0
+}
+
+//go:noinline
+func rsh_0_uint8_ssa(a uint8) uint8 {
+	return 0 >> a
+}
+
+//go:noinline
+func rsh_uint8_1_ssa(a uint8) uint8 {
+	return a >> 1
+}
+
+//go:noinline
+func rsh_1_uint8_ssa(a uint8) uint8 {
+	return 1 >> a
+}
+
+//go:noinline
+func rsh_uint8_255_ssa(a uint8) uint8 {
+	return a >> 255
+}
+
+//go:noinline
+func rsh_255_uint8_ssa(a uint8) uint8 {
+	return 255 >> a
+}
+
+//go:noinline
+func mod_0_uint8_ssa(a uint8) uint8 {
+	return 0 % a
+}
+
+//go:noinline
+func mod_uint8_1_ssa(a uint8) uint8 {
+	return a % 1
+}
+
+//go:noinline
+func mod_1_uint8_ssa(a uint8) uint8 {
+	return 1 % a
+}
+
+//go:noinline
+func mod_uint8_255_ssa(a uint8) uint8 {
+	return a % 255
+}
+
+//go:noinline
+func mod_255_uint8_ssa(a uint8) uint8 {
+	return 255 % a
+}
+
+//go:noinline
+func add_int8_Neg128_ssa(a int8) int8 {
+	return a + -128
+}
+
+//go:noinline
+func add_Neg128_int8_ssa(a int8) int8 {
+	return -128 + a
+}
+
+//go:noinline
+func add_int8_Neg127_ssa(a int8) int8 {
+	return a + -127
+}
+
+//go:noinline
+func add_Neg127_int8_ssa(a int8) int8 {
+	return -127 + a
+}
+
+//go:noinline
+func add_int8_Neg1_ssa(a int8) int8 {
+	return a + -1
+}
+
+//go:noinline
+func add_Neg1_int8_ssa(a int8) int8 {
+	return -1 + a
+}
+
+//go:noinline
+func add_int8_0_ssa(a int8) int8 {
+	return a + 0
+}
+
+//go:noinline
+func add_0_int8_ssa(a int8) int8 {
+	return 0 + a
+}
+
+//go:noinline
+func add_int8_1_ssa(a int8) int8 {
+	return a + 1
+}
+
+//go:noinline
+func add_1_int8_ssa(a int8) int8 {
+	return 1 + a
+}
+
+//go:noinline
+func add_int8_126_ssa(a int8) int8 {
+	return a + 126
+}
+
+//go:noinline
+func add_126_int8_ssa(a int8) int8 {
+	return 126 + a
+}
+
+//go:noinline
+func add_int8_127_ssa(a int8) int8 {
+	return a + 127
+}
+
+//go:noinline
+func add_127_int8_ssa(a int8) int8 {
+	return 127 + a
+}
+
+//go:noinline
+func sub_int8_Neg128_ssa(a int8) int8 {
+	return a - -128
+}
+
+//go:noinline
+func sub_Neg128_int8_ssa(a int8) int8 {
+	return -128 - a
+}
+
+//go:noinline
+func sub_int8_Neg127_ssa(a int8) int8 {
+	return a - -127
+}
+
+//go:noinline
+func sub_Neg127_int8_ssa(a int8) int8 {
+	return -127 - a
+}
+
+//go:noinline
+func sub_int8_Neg1_ssa(a int8) int8 {
+	return a - -1
+}
+
+//go:noinline
+func sub_Neg1_int8_ssa(a int8) int8 {
+	return -1 - a
+}
+
+//go:noinline
+func sub_int8_0_ssa(a int8) int8 {
+	return a - 0
+}
+
+//go:noinline
+func sub_0_int8_ssa(a int8) int8 {
+	return 0 - a
+}
+
+//go:noinline
+func sub_int8_1_ssa(a int8) int8 {
+	return a - 1
+}
+
+//go:noinline
+func sub_1_int8_ssa(a int8) int8 {
+	return 1 - a
+}
+
+//go:noinline
+func sub_int8_126_ssa(a int8) int8 {
+	return a - 126
+}
+
+//go:noinline
+func sub_126_int8_ssa(a int8) int8 {
+	return 126 - a
+}
+
+//go:noinline
+func sub_int8_127_ssa(a int8) int8 {
+	return a - 127
+}
+
+//go:noinline
+func sub_127_int8_ssa(a int8) int8 {
+	return 127 - a
+}
+
+//go:noinline
+func div_int8_Neg128_ssa(a int8) int8 {
+	return a / -128
+}
+
+//go:noinline
+func div_Neg128_int8_ssa(a int8) int8 {
+	return -128 / a
+}
+
+//go:noinline
+func div_int8_Neg127_ssa(a int8) int8 {
+	return a / -127
+}
+
+//go:noinline
+func div_Neg127_int8_ssa(a int8) int8 {
+	return -127 / a
+}
+
+//go:noinline
+func div_int8_Neg1_ssa(a int8) int8 {
+	return a / -1
+}
+
+//go:noinline
+func div_Neg1_int8_ssa(a int8) int8 {
+	return -1 / a
+}
+
+//go:noinline
+func div_0_int8_ssa(a int8) int8 {
+	return 0 / a
+}
+
+//go:noinline
+func div_int8_1_ssa(a int8) int8 {
+	return a / 1
+}
+
+//go:noinline
+func div_1_int8_ssa(a int8) int8 {
+	return 1 / a
+}
+
+//go:noinline
+func div_int8_126_ssa(a int8) int8 {
+	return a / 126
+}
+
+//go:noinline
+func div_126_int8_ssa(a int8) int8 {
+	return 126 / a
+}
+
+//go:noinline
+func div_int8_127_ssa(a int8) int8 {
+	return a / 127
+}
+
+//go:noinline
+func div_127_int8_ssa(a int8) int8 {
+	return 127 / a
+}
+
+//go:noinline
+func mul_int8_Neg128_ssa(a int8) int8 {
+	return a * -128
+}
+
+//go:noinline
+func mul_Neg128_int8_ssa(a int8) int8 {
+	return -128 * a
+}
+
+//go:noinline
+func mul_int8_Neg127_ssa(a int8) int8 {
+	return a * -127
+}
+
+//go:noinline
+func mul_Neg127_int8_ssa(a int8) int8 {
+	return -127 * a
+}
+
+//go:noinline
+func mul_int8_Neg1_ssa(a int8) int8 {
+	return a * -1
+}
+
+//go:noinline
+func mul_Neg1_int8_ssa(a int8) int8 {
+	return -1 * a
+}
+
+//go:noinline
+func mul_int8_0_ssa(a int8) int8 {
+	return a * 0
+}
+
+//go:noinline
+func mul_0_int8_ssa(a int8) int8 {
+	return 0 * a
+}
+
+//go:noinline
+func mul_int8_1_ssa(a int8) int8 {
+	return a * 1
+}
+
+//go:noinline
+func mul_1_int8_ssa(a int8) int8 {
+	return 1 * a
+}
+
+//go:noinline
+func mul_int8_126_ssa(a int8) int8 {
+	return a * 126
+}
+
+//go:noinline
+func mul_126_int8_ssa(a int8) int8 {
+	return 126 * a
+}
+
+//go:noinline
+func mul_int8_127_ssa(a int8) int8 {
+	return a * 127
+}
+
+//go:noinline
+func mul_127_int8_ssa(a int8) int8 {
+	return 127 * a
+}
+
+//go:noinline
+func mod_int8_Neg128_ssa(a int8) int8 {
+	return a % -128
+}
+
+//go:noinline
+func mod_Neg128_int8_ssa(a int8) int8 {
+	return -128 % a
+}
+
+//go:noinline
+func mod_int8_Neg127_ssa(a int8) int8 {
+	return a % -127
+}
+
+//go:noinline
+func mod_Neg127_int8_ssa(a int8) int8 {
+	return -127 % a
+}
+
+//go:noinline
+func mod_int8_Neg1_ssa(a int8) int8 {
+	return a % -1
+}
+
+//go:noinline
+func mod_Neg1_int8_ssa(a int8) int8 {
+	return -1 % a
+}
+
+//go:noinline
+func mod_0_int8_ssa(a int8) int8 {
+	return 0 % a
+}
+
+//go:noinline
+func mod_int8_1_ssa(a int8) int8 {
+	return a % 1
+}
+
+//go:noinline
+func mod_1_int8_ssa(a int8) int8 {
+	return 1 % a
+}
+
+//go:noinline
+func mod_int8_126_ssa(a int8) int8 {
+	return a % 126
+}
+
+//go:noinline
+func mod_126_int8_ssa(a int8) int8 {
+	return 126 % a
+}
+
+//go:noinline
+func mod_int8_127_ssa(a int8) int8 {
+	return a % 127
+}
+
+//go:noinline
+func mod_127_int8_ssa(a int8) int8 {
+	return 127 % a
+}
+
+var failed bool
+
+func main() {
+
+	if got := add_0_uint64_ssa(0); got != 0 {
+		fmt.Printf("add_uint64 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_0_ssa(0); got != 0 {
+		fmt.Printf("add_uint64 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_uint64_ssa(1); got != 1 {
+		fmt.Printf("add_uint64 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_0_ssa(1); got != 1 {
+		fmt.Printf("add_uint64 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_uint64_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("add_uint64 0%s4294967296 = %d, wanted 4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_0_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("add_uint64 4294967296%s0 = %d, wanted 4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_uint64_ssa(18446744073709551615); got != 18446744073709551615 {
+		fmt.Printf("add_uint64 0%s18446744073709551615 = %d, wanted 18446744073709551615\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_0_ssa(18446744073709551615); got != 18446744073709551615 {
+		fmt.Printf("add_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint64_ssa(0); got != 1 {
+		fmt.Printf("add_uint64 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_1_ssa(0); got != 1 {
+		fmt.Printf("add_uint64 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint64_ssa(1); got != 2 {
+		fmt.Printf("add_uint64 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_1_ssa(1); got != 2 {
+		fmt.Printf("add_uint64 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint64_ssa(4294967296); got != 4294967297 {
+		fmt.Printf("add_uint64 1%s4294967296 = %d, wanted 4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_1_ssa(4294967296); got != 4294967297 {
+		fmt.Printf("add_uint64 4294967296%s1 = %d, wanted 4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("add_uint64 1%s18446744073709551615 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_1_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("add_uint64 18446744073709551615%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_uint64_ssa(0); got != 4294967296 {
+		fmt.Printf("add_uint64 4294967296%s0 = %d, wanted 4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_4294967296_ssa(0); got != 4294967296 {
+		fmt.Printf("add_uint64 0%s4294967296 = %d, wanted 4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_uint64_ssa(1); got != 4294967297 {
+		fmt.Printf("add_uint64 4294967296%s1 = %d, wanted 4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_4294967296_ssa(1); got != 4294967297 {
+		fmt.Printf("add_uint64 1%s4294967296 = %d, wanted 4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_uint64_ssa(4294967296); got != 8589934592 {
+		fmt.Printf("add_uint64 4294967296%s4294967296 = %d, wanted 8589934592\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_4294967296_ssa(4294967296); got != 8589934592 {
+		fmt.Printf("add_uint64 4294967296%s4294967296 = %d, wanted 8589934592\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_uint64_ssa(18446744073709551615); got != 4294967295 {
+		fmt.Printf("add_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_4294967296_ssa(18446744073709551615); got != 4294967295 {
+		fmt.Printf("add_uint64 18446744073709551615%s4294967296 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
+		fmt.Printf("add_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_18446744073709551615_ssa(0); got != 18446744073709551615 {
+		fmt.Printf("add_uint64 0%s18446744073709551615 = %d, wanted 18446744073709551615\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_18446744073709551615_uint64_ssa(1); got != 0 {
+		fmt.Printf("add_uint64 18446744073709551615%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_18446744073709551615_ssa(1); got != 0 {
+		fmt.Printf("add_uint64 1%s18446744073709551615 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_18446744073709551615_uint64_ssa(4294967296); got != 4294967295 {
+		fmt.Printf("add_uint64 18446744073709551615%s4294967296 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_18446744073709551615_ssa(4294967296); got != 4294967295 {
+		fmt.Printf("add_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_18446744073709551615_uint64_ssa(18446744073709551615); got != 18446744073709551614 {
+		fmt.Printf("add_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 18446744073709551614\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint64_18446744073709551615_ssa(18446744073709551615); got != 18446744073709551614 {
+		fmt.Printf("add_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 18446744073709551614\n", `+`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint64_ssa(0); got != 0 {
+		fmt.Printf("sub_uint64 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_0_ssa(0); got != 0 {
+		fmt.Printf("sub_uint64 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint64_ssa(1); got != 18446744073709551615 {
+		fmt.Printf("sub_uint64 0%s1 = %d, wanted 18446744073709551615\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_0_ssa(1); got != 1 {
+		fmt.Printf("sub_uint64 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint64_ssa(4294967296); got != 18446744069414584320 {
+		fmt.Printf("sub_uint64 0%s4294967296 = %d, wanted 18446744069414584320\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_0_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("sub_uint64 4294967296%s0 = %d, wanted 4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint64_ssa(18446744073709551615); got != 1 {
+		fmt.Printf("sub_uint64 0%s18446744073709551615 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_0_ssa(18446744073709551615); got != 18446744073709551615 {
+		fmt.Printf("sub_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint64_ssa(0); got != 1 {
+		fmt.Printf("sub_uint64 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_1_ssa(0); got != 18446744073709551615 {
+		fmt.Printf("sub_uint64 0%s1 = %d, wanted 18446744073709551615\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint64_ssa(1); got != 0 {
+		fmt.Printf("sub_uint64 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_1_ssa(1); got != 0 {
+		fmt.Printf("sub_uint64 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint64_ssa(4294967296); got != 18446744069414584321 {
+		fmt.Printf("sub_uint64 1%s4294967296 = %d, wanted 18446744069414584321\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_1_ssa(4294967296); got != 4294967295 {
+		fmt.Printf("sub_uint64 4294967296%s1 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint64_ssa(18446744073709551615); got != 2 {
+		fmt.Printf("sub_uint64 1%s18446744073709551615 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_1_ssa(18446744073709551615); got != 18446744073709551614 {
+		fmt.Printf("sub_uint64 18446744073709551615%s1 = %d, wanted 18446744073709551614\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_uint64_ssa(0); got != 4294967296 {
+		fmt.Printf("sub_uint64 4294967296%s0 = %d, wanted 4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_4294967296_ssa(0); got != 18446744069414584320 {
+		fmt.Printf("sub_uint64 0%s4294967296 = %d, wanted 18446744069414584320\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_uint64_ssa(1); got != 4294967295 {
+		fmt.Printf("sub_uint64 4294967296%s1 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_4294967296_ssa(1); got != 18446744069414584321 {
+		fmt.Printf("sub_uint64 1%s4294967296 = %d, wanted 18446744069414584321\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("sub_uint64 4294967296%s4294967296 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("sub_uint64 4294967296%s4294967296 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_uint64_ssa(18446744073709551615); got != 4294967297 {
+		fmt.Printf("sub_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_4294967296_ssa(18446744073709551615); got != 18446744069414584319 {
+		fmt.Printf("sub_uint64 18446744073709551615%s4294967296 = %d, wanted 18446744069414584319\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
+		fmt.Printf("sub_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_18446744073709551615_ssa(0); got != 1 {
+		fmt.Printf("sub_uint64 0%s18446744073709551615 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_18446744073709551615_uint64_ssa(1); got != 18446744073709551614 {
+		fmt.Printf("sub_uint64 18446744073709551615%s1 = %d, wanted 18446744073709551614\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_18446744073709551615_ssa(1); got != 2 {
+		fmt.Printf("sub_uint64 1%s18446744073709551615 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_18446744073709551615_uint64_ssa(4294967296); got != 18446744069414584319 {
+		fmt.Printf("sub_uint64 18446744073709551615%s4294967296 = %d, wanted 18446744069414584319\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_18446744073709551615_ssa(4294967296); got != 4294967297 {
+		fmt.Printf("sub_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("sub_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint64_18446744073709551615_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("sub_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := div_0_uint64_ssa(1); got != 0 {
+		fmt.Printf("div_uint64 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("div_uint64 0%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("div_uint64 0%s18446744073709551615 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_1_ssa(0); got != 0 {
+		fmt.Printf("div_uint64 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_uint64_ssa(1); got != 1 {
+		fmt.Printf("div_uint64 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_1_ssa(1); got != 1 {
+		fmt.Printf("div_uint64 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("div_uint64 1%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_1_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("div_uint64 4294967296%s1 = %d, wanted 4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("div_uint64 1%s18446744073709551615 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_1_ssa(18446744073709551615); got != 18446744073709551615 {
+		fmt.Printf("div_uint64 18446744073709551615%s1 = %d, wanted 18446744073709551615\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_4294967296_ssa(0); got != 0 {
+		fmt.Printf("div_uint64 0%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_uint64_ssa(1); got != 4294967296 {
+		fmt.Printf("div_uint64 4294967296%s1 = %d, wanted 4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_4294967296_ssa(1); got != 0 {
+		fmt.Printf("div_uint64 1%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_uint64_ssa(4294967296); got != 1 {
+		fmt.Printf("div_uint64 4294967296%s4294967296 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_4294967296_ssa(4294967296); got != 1 {
+		fmt.Printf("div_uint64 4294967296%s4294967296 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("div_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_4294967296_ssa(18446744073709551615); got != 4294967295 {
+		fmt.Printf("div_uint64 18446744073709551615%s4294967296 = %d, wanted 4294967295\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_18446744073709551615_ssa(0); got != 0 {
+		fmt.Printf("div_uint64 0%s18446744073709551615 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_18446744073709551615_uint64_ssa(1); got != 18446744073709551615 {
+		fmt.Printf("div_uint64 18446744073709551615%s1 = %d, wanted 18446744073709551615\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_18446744073709551615_ssa(1); got != 0 {
+		fmt.Printf("div_uint64 1%s18446744073709551615 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_18446744073709551615_uint64_ssa(4294967296); got != 4294967295 {
+		fmt.Printf("div_uint64 18446744073709551615%s4294967296 = %d, wanted 4294967295\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_18446744073709551615_ssa(4294967296); got != 0 {
+		fmt.Printf("div_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_18446744073709551615_uint64_ssa(18446744073709551615); got != 1 {
+		fmt.Printf("div_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint64_18446744073709551615_ssa(18446744073709551615); got != 1 {
+		fmt.Printf("div_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint64_ssa(0); got != 0 {
+		fmt.Printf("mul_uint64 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_0_ssa(0); got != 0 {
+		fmt.Printf("mul_uint64 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint64_ssa(1); got != 0 {
+		fmt.Printf("mul_uint64 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_0_ssa(1); got != 0 {
+		fmt.Printf("mul_uint64 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_uint64 0%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_0_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_uint64 4294967296%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("mul_uint64 0%s18446744073709551615 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_0_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("mul_uint64 18446744073709551615%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint64_ssa(0); got != 0 {
+		fmt.Printf("mul_uint64 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_1_ssa(0); got != 0 {
+		fmt.Printf("mul_uint64 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint64_ssa(1); got != 1 {
+		fmt.Printf("mul_uint64 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_1_ssa(1); got != 1 {
+		fmt.Printf("mul_uint64 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint64_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mul_uint64 1%s4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_1_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mul_uint64 4294967296%s1 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint64_ssa(18446744073709551615); got != 18446744073709551615 {
+		fmt.Printf("mul_uint64 1%s18446744073709551615 = %d, wanted 18446744073709551615\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_1_ssa(18446744073709551615); got != 18446744073709551615 {
+		fmt.Printf("mul_uint64 18446744073709551615%s1 = %d, wanted 18446744073709551615\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_uint64_ssa(0); got != 0 {
+		fmt.Printf("mul_uint64 4294967296%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_4294967296_ssa(0); got != 0 {
+		fmt.Printf("mul_uint64 0%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_uint64_ssa(1); got != 4294967296 {
+		fmt.Printf("mul_uint64 4294967296%s1 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_4294967296_ssa(1); got != 4294967296 {
+		fmt.Printf("mul_uint64 1%s4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_uint64 4294967296%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_uint64 4294967296%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_uint64_ssa(18446744073709551615); got != 18446744069414584320 {
+		fmt.Printf("mul_uint64 4294967296%s18446744073709551615 = %d, wanted 18446744069414584320\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_4294967296_ssa(18446744073709551615); got != 18446744069414584320 {
+		fmt.Printf("mul_uint64 18446744073709551615%s4294967296 = %d, wanted 18446744069414584320\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_18446744073709551615_uint64_ssa(0); got != 0 {
+		fmt.Printf("mul_uint64 18446744073709551615%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_18446744073709551615_ssa(0); got != 0 {
+		fmt.Printf("mul_uint64 0%s18446744073709551615 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_18446744073709551615_uint64_ssa(1); got != 18446744073709551615 {
+		fmt.Printf("mul_uint64 18446744073709551615%s1 = %d, wanted 18446744073709551615\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_18446744073709551615_ssa(1); got != 18446744073709551615 {
+		fmt.Printf("mul_uint64 1%s18446744073709551615 = %d, wanted 18446744073709551615\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_18446744073709551615_uint64_ssa(4294967296); got != 18446744069414584320 {
+		fmt.Printf("mul_uint64 18446744073709551615%s4294967296 = %d, wanted 18446744069414584320\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_18446744073709551615_ssa(4294967296); got != 18446744069414584320 {
+		fmt.Printf("mul_uint64 4294967296%s18446744073709551615 = %d, wanted 18446744069414584320\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_18446744073709551615_uint64_ssa(18446744073709551615); got != 1 {
+		fmt.Printf("mul_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint64_18446744073709551615_ssa(18446744073709551615); got != 1 {
+		fmt.Printf("mul_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint64_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint64 0%s0 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_0_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint64 0%s0 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint64_ssa(1); got != 0 {
+		fmt.Printf("lsh_uint64 0%s1 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_0_ssa(1); got != 1 {
+		fmt.Printf("lsh_uint64 1%s0 = %d, wanted 1\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("lsh_uint64 0%s4294967296 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_0_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("lsh_uint64 4294967296%s0 = %d, wanted 4294967296\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("lsh_uint64 0%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_0_ssa(18446744073709551615); got != 18446744073709551615 {
+		fmt.Printf("lsh_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint64_ssa(0); got != 1 {
+		fmt.Printf("lsh_uint64 1%s0 = %d, wanted 1\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_1_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint64 0%s1 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint64_ssa(1); got != 2 {
+		fmt.Printf("lsh_uint64 1%s1 = %d, wanted 2\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_1_ssa(1); got != 2 {
+		fmt.Printf("lsh_uint64 1%s1 = %d, wanted 2\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("lsh_uint64 1%s4294967296 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_1_ssa(4294967296); got != 8589934592 {
+		fmt.Printf("lsh_uint64 4294967296%s1 = %d, wanted 8589934592\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("lsh_uint64 1%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_1_ssa(18446744073709551615); got != 18446744073709551614 {
+		fmt.Printf("lsh_uint64 18446744073709551615%s1 = %d, wanted 18446744073709551614\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_4294967296_uint64_ssa(0); got != 4294967296 {
+		fmt.Printf("lsh_uint64 4294967296%s0 = %d, wanted 4294967296\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_4294967296_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint64 0%s4294967296 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_4294967296_uint64_ssa(1); got != 8589934592 {
+		fmt.Printf("lsh_uint64 4294967296%s1 = %d, wanted 8589934592\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_4294967296_ssa(1); got != 0 {
+		fmt.Printf("lsh_uint64 1%s4294967296 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_4294967296_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("lsh_uint64 4294967296%s4294967296 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("lsh_uint64 4294967296%s4294967296 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_4294967296_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("lsh_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_4294967296_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("lsh_uint64 18446744073709551615%s4294967296 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
+		fmt.Printf("lsh_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_18446744073709551615_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint64 0%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_18446744073709551615_uint64_ssa(1); got != 18446744073709551614 {
+		fmt.Printf("lsh_uint64 18446744073709551615%s1 = %d, wanted 18446744073709551614\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_18446744073709551615_ssa(1); got != 0 {
+		fmt.Printf("lsh_uint64 1%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_18446744073709551615_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("lsh_uint64 18446744073709551615%s4294967296 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_18446744073709551615_ssa(4294967296); got != 0 {
+		fmt.Printf("lsh_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("lsh_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint64_18446744073709551615_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("lsh_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint64_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint64 0%s0 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_0_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint64 0%s0 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint64_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint64 0%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_0_ssa(1); got != 1 {
+		fmt.Printf("rsh_uint64 1%s0 = %d, wanted 1\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("rsh_uint64 0%s4294967296 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_0_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("rsh_uint64 4294967296%s0 = %d, wanted 4294967296\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("rsh_uint64 0%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_0_ssa(18446744073709551615); got != 18446744073709551615 {
+		fmt.Printf("rsh_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint64_ssa(0); got != 1 {
+		fmt.Printf("rsh_uint64 1%s0 = %d, wanted 1\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_1_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint64 0%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint64_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint64 1%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_1_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint64 1%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("rsh_uint64 1%s4294967296 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_1_ssa(4294967296); got != 2147483648 {
+		fmt.Printf("rsh_uint64 4294967296%s1 = %d, wanted 2147483648\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("rsh_uint64 1%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_1_ssa(18446744073709551615); got != 9223372036854775807 {
+		fmt.Printf("rsh_uint64 18446744073709551615%s1 = %d, wanted 9223372036854775807\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_4294967296_uint64_ssa(0); got != 4294967296 {
+		fmt.Printf("rsh_uint64 4294967296%s0 = %d, wanted 4294967296\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_4294967296_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint64 0%s4294967296 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_4294967296_uint64_ssa(1); got != 2147483648 {
+		fmt.Printf("rsh_uint64 4294967296%s1 = %d, wanted 2147483648\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_4294967296_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint64 1%s4294967296 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_4294967296_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("rsh_uint64 4294967296%s4294967296 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("rsh_uint64 4294967296%s4294967296 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_4294967296_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("rsh_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_4294967296_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("rsh_uint64 18446744073709551615%s4294967296 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_18446744073709551615_uint64_ssa(0); got != 18446744073709551615 {
+		fmt.Printf("rsh_uint64 18446744073709551615%s0 = %d, wanted 18446744073709551615\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_18446744073709551615_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint64 0%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_18446744073709551615_uint64_ssa(1); got != 9223372036854775807 {
+		fmt.Printf("rsh_uint64 18446744073709551615%s1 = %d, wanted 9223372036854775807\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_18446744073709551615_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint64 1%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_18446744073709551615_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("rsh_uint64 18446744073709551615%s4294967296 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_18446744073709551615_ssa(4294967296); got != 0 {
+		fmt.Printf("rsh_uint64 4294967296%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("rsh_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint64_18446744073709551615_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("rsh_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := mod_0_uint64_ssa(1); got != 0 {
+		fmt.Printf("mod_uint64 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_uint64 0%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("mod_uint64 0%s18446744073709551615 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_1_ssa(0); got != 0 {
+		fmt.Printf("mod_uint64 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_uint64_ssa(1); got != 0 {
+		fmt.Printf("mod_uint64 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_1_ssa(1); got != 0 {
+		fmt.Printf("mod_uint64 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_uint64_ssa(4294967296); got != 1 {
+		fmt.Printf("mod_uint64 1%s4294967296 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_1_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_uint64 4294967296%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_uint64_ssa(18446744073709551615); got != 1 {
+		fmt.Printf("mod_uint64 1%s18446744073709551615 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_1_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("mod_uint64 18446744073709551615%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_4294967296_ssa(0); got != 0 {
+		fmt.Printf("mod_uint64 0%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_uint64_ssa(1); got != 0 {
+		fmt.Printf("mod_uint64 4294967296%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_4294967296_ssa(1); got != 1 {
+		fmt.Printf("mod_uint64 1%s4294967296 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_uint64_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_uint64 4294967296%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_uint64 4294967296%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_uint64_ssa(18446744073709551615); got != 4294967296 {
+		fmt.Printf("mod_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_4294967296_ssa(18446744073709551615); got != 4294967295 {
+		fmt.Printf("mod_uint64 18446744073709551615%s4294967296 = %d, wanted 4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_18446744073709551615_ssa(0); got != 0 {
+		fmt.Printf("mod_uint64 0%s18446744073709551615 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_18446744073709551615_uint64_ssa(1); got != 0 {
+		fmt.Printf("mod_uint64 18446744073709551615%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_18446744073709551615_ssa(1); got != 1 {
+		fmt.Printf("mod_uint64 1%s18446744073709551615 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_18446744073709551615_uint64_ssa(4294967296); got != 4294967295 {
+		fmt.Printf("mod_uint64 18446744073709551615%s4294967296 = %d, wanted 4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_18446744073709551615_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mod_uint64 4294967296%s18446744073709551615 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_18446744073709551615_uint64_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("mod_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint64_18446744073709551615_ssa(18446744073709551615); got != 0 {
+		fmt.Printf("mod_uint64 18446744073709551615%s18446744073709551615 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775808_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("add_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775808_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("add_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775808_int64_ssa(-9223372036854775807); got != 1 {
+		fmt.Printf("add_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775808_ssa(-9223372036854775807); got != 1 {
+		fmt.Printf("add_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775808_int64_ssa(-4294967296); got != 9223372032559808512 {
+		fmt.Printf("add_int64 -9223372036854775808%s-4294967296 = %d, wanted 9223372032559808512\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775808_ssa(-4294967296); got != 9223372032559808512 {
+		fmt.Printf("add_int64 -4294967296%s-9223372036854775808 = %d, wanted 9223372032559808512\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775808_int64_ssa(-1); got != 9223372036854775807 {
+		fmt.Printf("add_int64 -9223372036854775808%s-1 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775808_ssa(-1); got != 9223372036854775807 {
+		fmt.Printf("add_int64 -1%s-9223372036854775808 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775808_int64_ssa(0); got != -9223372036854775808 {
+		fmt.Printf("add_int64 -9223372036854775808%s0 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775808_ssa(0); got != -9223372036854775808 {
+		fmt.Printf("add_int64 0%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775808_int64_ssa(1); got != -9223372036854775807 {
+		fmt.Printf("add_int64 -9223372036854775808%s1 = %d, wanted -9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775808_ssa(1); got != -9223372036854775807 {
+		fmt.Printf("add_int64 1%s-9223372036854775808 = %d, wanted -9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775808_int64_ssa(4294967296); got != -9223372032559808512 {
+		fmt.Printf("add_int64 -9223372036854775808%s4294967296 = %d, wanted -9223372032559808512\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775808_ssa(4294967296); got != -9223372032559808512 {
+		fmt.Printf("add_int64 4294967296%s-9223372036854775808 = %d, wanted -9223372032559808512\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775808_int64_ssa(9223372036854775806); got != -2 {
+		fmt.Printf("add_int64 -9223372036854775808%s9223372036854775806 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775808_ssa(9223372036854775806); got != -2 {
+		fmt.Printf("add_int64 9223372036854775806%s-9223372036854775808 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775808_int64_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("add_int64 -9223372036854775808%s9223372036854775807 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775808_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("add_int64 9223372036854775807%s-9223372036854775808 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775807_int64_ssa(-9223372036854775808); got != 1 {
+		fmt.Printf("add_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775807_ssa(-9223372036854775808); got != 1 {
+		fmt.Printf("add_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775807_int64_ssa(-9223372036854775807); got != 2 {
+		fmt.Printf("add_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775807_ssa(-9223372036854775807); got != 2 {
+		fmt.Printf("add_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775807_int64_ssa(-4294967296); got != 9223372032559808513 {
+		fmt.Printf("add_int64 -9223372036854775807%s-4294967296 = %d, wanted 9223372032559808513\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775807_ssa(-4294967296); got != 9223372032559808513 {
+		fmt.Printf("add_int64 -4294967296%s-9223372036854775807 = %d, wanted 9223372032559808513\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775807_int64_ssa(-1); got != -9223372036854775808 {
+		fmt.Printf("add_int64 -9223372036854775807%s-1 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775807_ssa(-1); got != -9223372036854775808 {
+		fmt.Printf("add_int64 -1%s-9223372036854775807 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775807_int64_ssa(0); got != -9223372036854775807 {
+		fmt.Printf("add_int64 -9223372036854775807%s0 = %d, wanted -9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775807_ssa(0); got != -9223372036854775807 {
+		fmt.Printf("add_int64 0%s-9223372036854775807 = %d, wanted -9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775807_int64_ssa(1); got != -9223372036854775806 {
+		fmt.Printf("add_int64 -9223372036854775807%s1 = %d, wanted -9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775807_ssa(1); got != -9223372036854775806 {
+		fmt.Printf("add_int64 1%s-9223372036854775807 = %d, wanted -9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775807_int64_ssa(4294967296); got != -9223372032559808511 {
+		fmt.Printf("add_int64 -9223372036854775807%s4294967296 = %d, wanted -9223372032559808511\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775807_ssa(4294967296); got != -9223372032559808511 {
+		fmt.Printf("add_int64 4294967296%s-9223372036854775807 = %d, wanted -9223372032559808511\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775807_int64_ssa(9223372036854775806); got != -1 {
+		fmt.Printf("add_int64 -9223372036854775807%s9223372036854775806 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775807_ssa(9223372036854775806); got != -1 {
+		fmt.Printf("add_int64 9223372036854775806%s-9223372036854775807 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg9223372036854775807_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("add_int64 -9223372036854775807%s9223372036854775807 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg9223372036854775807_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("add_int64 9223372036854775807%s-9223372036854775807 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg4294967296_int64_ssa(-9223372036854775808); got != 9223372032559808512 {
+		fmt.Printf("add_int64 -4294967296%s-9223372036854775808 = %d, wanted 9223372032559808512\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg4294967296_ssa(-9223372036854775808); got != 9223372032559808512 {
+		fmt.Printf("add_int64 -9223372036854775808%s-4294967296 = %d, wanted 9223372032559808512\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg4294967296_int64_ssa(-9223372036854775807); got != 9223372032559808513 {
+		fmt.Printf("add_int64 -4294967296%s-9223372036854775807 = %d, wanted 9223372032559808513\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg4294967296_ssa(-9223372036854775807); got != 9223372032559808513 {
+		fmt.Printf("add_int64 -9223372036854775807%s-4294967296 = %d, wanted 9223372032559808513\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg4294967296_int64_ssa(-4294967296); got != -8589934592 {
+		fmt.Printf("add_int64 -4294967296%s-4294967296 = %d, wanted -8589934592\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg4294967296_ssa(-4294967296); got != -8589934592 {
+		fmt.Printf("add_int64 -4294967296%s-4294967296 = %d, wanted -8589934592\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg4294967296_int64_ssa(-1); got != -4294967297 {
+		fmt.Printf("add_int64 -4294967296%s-1 = %d, wanted -4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg4294967296_ssa(-1); got != -4294967297 {
+		fmt.Printf("add_int64 -1%s-4294967296 = %d, wanted -4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg4294967296_int64_ssa(0); got != -4294967296 {
+		fmt.Printf("add_int64 -4294967296%s0 = %d, wanted -4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg4294967296_ssa(0); got != -4294967296 {
+		fmt.Printf("add_int64 0%s-4294967296 = %d, wanted -4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg4294967296_int64_ssa(1); got != -4294967295 {
+		fmt.Printf("add_int64 -4294967296%s1 = %d, wanted -4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg4294967296_ssa(1); got != -4294967295 {
+		fmt.Printf("add_int64 1%s-4294967296 = %d, wanted -4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg4294967296_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("add_int64 -4294967296%s4294967296 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("add_int64 4294967296%s-4294967296 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg4294967296_int64_ssa(9223372036854775806); got != 9223372032559808510 {
+		fmt.Printf("add_int64 -4294967296%s9223372036854775806 = %d, wanted 9223372032559808510\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg4294967296_ssa(9223372036854775806); got != 9223372032559808510 {
+		fmt.Printf("add_int64 9223372036854775806%s-4294967296 = %d, wanted 9223372032559808510\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg4294967296_int64_ssa(9223372036854775807); got != 9223372032559808511 {
+		fmt.Printf("add_int64 -4294967296%s9223372036854775807 = %d, wanted 9223372032559808511\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg4294967296_ssa(9223372036854775807); got != 9223372032559808511 {
+		fmt.Printf("add_int64 9223372036854775807%s-4294967296 = %d, wanted 9223372032559808511\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int64_ssa(-9223372036854775808); got != 9223372036854775807 {
+		fmt.Printf("add_int64 -1%s-9223372036854775808 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg1_ssa(-9223372036854775808); got != 9223372036854775807 {
+		fmt.Printf("add_int64 -9223372036854775808%s-1 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int64_ssa(-9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("add_int64 -1%s-9223372036854775807 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg1_ssa(-9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("add_int64 -9223372036854775807%s-1 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int64_ssa(-4294967296); got != -4294967297 {
+		fmt.Printf("add_int64 -1%s-4294967296 = %d, wanted -4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg1_ssa(-4294967296); got != -4294967297 {
+		fmt.Printf("add_int64 -4294967296%s-1 = %d, wanted -4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int64_ssa(-1); got != -2 {
+		fmt.Printf("add_int64 -1%s-1 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg1_ssa(-1); got != -2 {
+		fmt.Printf("add_int64 -1%s-1 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int64_ssa(0); got != -1 {
+		fmt.Printf("add_int64 -1%s0 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg1_ssa(0); got != -1 {
+		fmt.Printf("add_int64 0%s-1 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int64_ssa(1); got != 0 {
+		fmt.Printf("add_int64 -1%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg1_ssa(1); got != 0 {
+		fmt.Printf("add_int64 1%s-1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int64_ssa(4294967296); got != 4294967295 {
+		fmt.Printf("add_int64 -1%s4294967296 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg1_ssa(4294967296); got != 4294967295 {
+		fmt.Printf("add_int64 4294967296%s-1 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int64_ssa(9223372036854775806); got != 9223372036854775805 {
+		fmt.Printf("add_int64 -1%s9223372036854775806 = %d, wanted 9223372036854775805\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg1_ssa(9223372036854775806); got != 9223372036854775805 {
+		fmt.Printf("add_int64 9223372036854775806%s-1 = %d, wanted 9223372036854775805\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int64_ssa(9223372036854775807); got != 9223372036854775806 {
+		fmt.Printf("add_int64 -1%s9223372036854775807 = %d, wanted 9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_Neg1_ssa(9223372036854775807); got != 9223372036854775806 {
+		fmt.Printf("add_int64 9223372036854775807%s-1 = %d, wanted 9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int64_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("add_int64 0%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_0_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("add_int64 -9223372036854775808%s0 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int64_ssa(-9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("add_int64 0%s-9223372036854775807 = %d, wanted -9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_0_ssa(-9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("add_int64 -9223372036854775807%s0 = %d, wanted -9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int64_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("add_int64 0%s-4294967296 = %d, wanted -4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_0_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("add_int64 -4294967296%s0 = %d, wanted -4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int64_ssa(-1); got != -1 {
+		fmt.Printf("add_int64 0%s-1 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_0_ssa(-1); got != -1 {
+		fmt.Printf("add_int64 -1%s0 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int64_ssa(0); got != 0 {
+		fmt.Printf("add_int64 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_0_ssa(0); got != 0 {
+		fmt.Printf("add_int64 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int64_ssa(1); got != 1 {
+		fmt.Printf("add_int64 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_0_ssa(1); got != 1 {
+		fmt.Printf("add_int64 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int64_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("add_int64 0%s4294967296 = %d, wanted 4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_0_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("add_int64 4294967296%s0 = %d, wanted 4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int64_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("add_int64 0%s9223372036854775806 = %d, wanted 9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_0_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("add_int64 9223372036854775806%s0 = %d, wanted 9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int64_ssa(9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("add_int64 0%s9223372036854775807 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_0_ssa(9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("add_int64 9223372036854775807%s0 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int64_ssa(-9223372036854775808); got != -9223372036854775807 {
+		fmt.Printf("add_int64 1%s-9223372036854775808 = %d, wanted -9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_1_ssa(-9223372036854775808); got != -9223372036854775807 {
+		fmt.Printf("add_int64 -9223372036854775808%s1 = %d, wanted -9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int64_ssa(-9223372036854775807); got != -9223372036854775806 {
+		fmt.Printf("add_int64 1%s-9223372036854775807 = %d, wanted -9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_1_ssa(-9223372036854775807); got != -9223372036854775806 {
+		fmt.Printf("add_int64 -9223372036854775807%s1 = %d, wanted -9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int64_ssa(-4294967296); got != -4294967295 {
+		fmt.Printf("add_int64 1%s-4294967296 = %d, wanted -4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_1_ssa(-4294967296); got != -4294967295 {
+		fmt.Printf("add_int64 -4294967296%s1 = %d, wanted -4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int64_ssa(-1); got != 0 {
+		fmt.Printf("add_int64 1%s-1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_1_ssa(-1); got != 0 {
+		fmt.Printf("add_int64 -1%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int64_ssa(0); got != 1 {
+		fmt.Printf("add_int64 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_1_ssa(0); got != 1 {
+		fmt.Printf("add_int64 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int64_ssa(1); got != 2 {
+		fmt.Printf("add_int64 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_1_ssa(1); got != 2 {
+		fmt.Printf("add_int64 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int64_ssa(4294967296); got != 4294967297 {
+		fmt.Printf("add_int64 1%s4294967296 = %d, wanted 4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_1_ssa(4294967296); got != 4294967297 {
+		fmt.Printf("add_int64 4294967296%s1 = %d, wanted 4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int64_ssa(9223372036854775806); got != 9223372036854775807 {
+		fmt.Printf("add_int64 1%s9223372036854775806 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_1_ssa(9223372036854775806); got != 9223372036854775807 {
+		fmt.Printf("add_int64 9223372036854775806%s1 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int64_ssa(9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("add_int64 1%s9223372036854775807 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_1_ssa(9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("add_int64 9223372036854775807%s1 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_int64_ssa(-9223372036854775808); got != -9223372032559808512 {
+		fmt.Printf("add_int64 4294967296%s-9223372036854775808 = %d, wanted -9223372032559808512\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_4294967296_ssa(-9223372036854775808); got != -9223372032559808512 {
+		fmt.Printf("add_int64 -9223372036854775808%s4294967296 = %d, wanted -9223372032559808512\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_int64_ssa(-9223372036854775807); got != -9223372032559808511 {
+		fmt.Printf("add_int64 4294967296%s-9223372036854775807 = %d, wanted -9223372032559808511\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_4294967296_ssa(-9223372036854775807); got != -9223372032559808511 {
+		fmt.Printf("add_int64 -9223372036854775807%s4294967296 = %d, wanted -9223372032559808511\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("add_int64 4294967296%s-4294967296 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_4294967296_ssa(-4294967296); got != 0 {
+		fmt.Printf("add_int64 -4294967296%s4294967296 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_int64_ssa(-1); got != 4294967295 {
+		fmt.Printf("add_int64 4294967296%s-1 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_4294967296_ssa(-1); got != 4294967295 {
+		fmt.Printf("add_int64 -1%s4294967296 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_int64_ssa(0); got != 4294967296 {
+		fmt.Printf("add_int64 4294967296%s0 = %d, wanted 4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_4294967296_ssa(0); got != 4294967296 {
+		fmt.Printf("add_int64 0%s4294967296 = %d, wanted 4294967296\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_int64_ssa(1); got != 4294967297 {
+		fmt.Printf("add_int64 4294967296%s1 = %d, wanted 4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_4294967296_ssa(1); got != 4294967297 {
+		fmt.Printf("add_int64 1%s4294967296 = %d, wanted 4294967297\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_int64_ssa(4294967296); got != 8589934592 {
+		fmt.Printf("add_int64 4294967296%s4294967296 = %d, wanted 8589934592\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_4294967296_ssa(4294967296); got != 8589934592 {
+		fmt.Printf("add_int64 4294967296%s4294967296 = %d, wanted 8589934592\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_int64_ssa(9223372036854775806); got != -9223372032559808514 {
+		fmt.Printf("add_int64 4294967296%s9223372036854775806 = %d, wanted -9223372032559808514\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_4294967296_ssa(9223372036854775806); got != -9223372032559808514 {
+		fmt.Printf("add_int64 9223372036854775806%s4294967296 = %d, wanted -9223372032559808514\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967296_int64_ssa(9223372036854775807); got != -9223372032559808513 {
+		fmt.Printf("add_int64 4294967296%s9223372036854775807 = %d, wanted -9223372032559808513\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_4294967296_ssa(9223372036854775807); got != -9223372032559808513 {
+		fmt.Printf("add_int64 9223372036854775807%s4294967296 = %d, wanted -9223372032559808513\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775806_int64_ssa(-9223372036854775808); got != -2 {
+		fmt.Printf("add_int64 9223372036854775806%s-9223372036854775808 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775806_ssa(-9223372036854775808); got != -2 {
+		fmt.Printf("add_int64 -9223372036854775808%s9223372036854775806 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775806_int64_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("add_int64 9223372036854775806%s-9223372036854775807 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775806_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("add_int64 -9223372036854775807%s9223372036854775806 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775806_int64_ssa(-4294967296); got != 9223372032559808510 {
+		fmt.Printf("add_int64 9223372036854775806%s-4294967296 = %d, wanted 9223372032559808510\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775806_ssa(-4294967296); got != 9223372032559808510 {
+		fmt.Printf("add_int64 -4294967296%s9223372036854775806 = %d, wanted 9223372032559808510\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775806_int64_ssa(-1); got != 9223372036854775805 {
+		fmt.Printf("add_int64 9223372036854775806%s-1 = %d, wanted 9223372036854775805\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775806_ssa(-1); got != 9223372036854775805 {
+		fmt.Printf("add_int64 -1%s9223372036854775806 = %d, wanted 9223372036854775805\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775806_int64_ssa(0); got != 9223372036854775806 {
+		fmt.Printf("add_int64 9223372036854775806%s0 = %d, wanted 9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775806_ssa(0); got != 9223372036854775806 {
+		fmt.Printf("add_int64 0%s9223372036854775806 = %d, wanted 9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775806_int64_ssa(1); got != 9223372036854775807 {
+		fmt.Printf("add_int64 9223372036854775806%s1 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775806_ssa(1); got != 9223372036854775807 {
+		fmt.Printf("add_int64 1%s9223372036854775806 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775806_int64_ssa(4294967296); got != -9223372032559808514 {
+		fmt.Printf("add_int64 9223372036854775806%s4294967296 = %d, wanted -9223372032559808514\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775806_ssa(4294967296); got != -9223372032559808514 {
+		fmt.Printf("add_int64 4294967296%s9223372036854775806 = %d, wanted -9223372032559808514\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775806_int64_ssa(9223372036854775806); got != -4 {
+		fmt.Printf("add_int64 9223372036854775806%s9223372036854775806 = %d, wanted -4\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775806_ssa(9223372036854775806); got != -4 {
+		fmt.Printf("add_int64 9223372036854775806%s9223372036854775806 = %d, wanted -4\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775806_int64_ssa(9223372036854775807); got != -3 {
+		fmt.Printf("add_int64 9223372036854775806%s9223372036854775807 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775806_ssa(9223372036854775807); got != -3 {
+		fmt.Printf("add_int64 9223372036854775807%s9223372036854775806 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775807_int64_ssa(-9223372036854775808); got != -1 {
+		fmt.Printf("add_int64 9223372036854775807%s-9223372036854775808 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775807_ssa(-9223372036854775808); got != -1 {
+		fmt.Printf("add_int64 -9223372036854775808%s9223372036854775807 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775807_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("add_int64 9223372036854775807%s-9223372036854775807 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775807_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("add_int64 -9223372036854775807%s9223372036854775807 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775807_int64_ssa(-4294967296); got != 9223372032559808511 {
+		fmt.Printf("add_int64 9223372036854775807%s-4294967296 = %d, wanted 9223372032559808511\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775807_ssa(-4294967296); got != 9223372032559808511 {
+		fmt.Printf("add_int64 -4294967296%s9223372036854775807 = %d, wanted 9223372032559808511\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775807_int64_ssa(-1); got != 9223372036854775806 {
+		fmt.Printf("add_int64 9223372036854775807%s-1 = %d, wanted 9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775807_ssa(-1); got != 9223372036854775806 {
+		fmt.Printf("add_int64 -1%s9223372036854775807 = %d, wanted 9223372036854775806\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775807_int64_ssa(0); got != 9223372036854775807 {
+		fmt.Printf("add_int64 9223372036854775807%s0 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775807_ssa(0); got != 9223372036854775807 {
+		fmt.Printf("add_int64 0%s9223372036854775807 = %d, wanted 9223372036854775807\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775807_int64_ssa(1); got != -9223372036854775808 {
+		fmt.Printf("add_int64 9223372036854775807%s1 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775807_ssa(1); got != -9223372036854775808 {
+		fmt.Printf("add_int64 1%s9223372036854775807 = %d, wanted -9223372036854775808\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775807_int64_ssa(4294967296); got != -9223372032559808513 {
+		fmt.Printf("add_int64 9223372036854775807%s4294967296 = %d, wanted -9223372032559808513\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775807_ssa(4294967296); got != -9223372032559808513 {
+		fmt.Printf("add_int64 4294967296%s9223372036854775807 = %d, wanted -9223372032559808513\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775807_int64_ssa(9223372036854775806); got != -3 {
+		fmt.Printf("add_int64 9223372036854775807%s9223372036854775806 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775807_ssa(9223372036854775806); got != -3 {
+		fmt.Printf("add_int64 9223372036854775806%s9223372036854775807 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_9223372036854775807_int64_ssa(9223372036854775807); got != -2 {
+		fmt.Printf("add_int64 9223372036854775807%s9223372036854775807 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int64_9223372036854775807_ssa(9223372036854775807); got != -2 {
+		fmt.Printf("add_int64 9223372036854775807%s9223372036854775807 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775808_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("sub_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775808_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("sub_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775808_int64_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("sub_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775808_ssa(-9223372036854775807); got != 1 {
+		fmt.Printf("sub_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775808_int64_ssa(-4294967296); got != -9223372032559808512 {
+		fmt.Printf("sub_int64 -9223372036854775808%s-4294967296 = %d, wanted -9223372032559808512\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775808_ssa(-4294967296); got != 9223372032559808512 {
+		fmt.Printf("sub_int64 -4294967296%s-9223372036854775808 = %d, wanted 9223372032559808512\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775808_int64_ssa(-1); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 -9223372036854775808%s-1 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775808_ssa(-1); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 -1%s-9223372036854775808 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775808_int64_ssa(0); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 -9223372036854775808%s0 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775808_ssa(0); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 0%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775808_int64_ssa(1); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 -9223372036854775808%s1 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775808_ssa(1); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 1%s-9223372036854775808 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775808_int64_ssa(4294967296); got != 9223372032559808512 {
+		fmt.Printf("sub_int64 -9223372036854775808%s4294967296 = %d, wanted 9223372032559808512\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775808_ssa(4294967296); got != -9223372032559808512 {
+		fmt.Printf("sub_int64 4294967296%s-9223372036854775808 = %d, wanted -9223372032559808512\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775808_int64_ssa(9223372036854775806); got != 2 {
+		fmt.Printf("sub_int64 -9223372036854775808%s9223372036854775806 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775808_ssa(9223372036854775806); got != -2 {
+		fmt.Printf("sub_int64 9223372036854775806%s-9223372036854775808 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775808_int64_ssa(9223372036854775807); got != 1 {
+		fmt.Printf("sub_int64 -9223372036854775808%s9223372036854775807 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775808_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("sub_int64 9223372036854775807%s-9223372036854775808 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775807_int64_ssa(-9223372036854775808); got != 1 {
+		fmt.Printf("sub_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775807_ssa(-9223372036854775808); got != -1 {
+		fmt.Printf("sub_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775807_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("sub_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775807_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("sub_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775807_int64_ssa(-4294967296); got != -9223372032559808511 {
+		fmt.Printf("sub_int64 -9223372036854775807%s-4294967296 = %d, wanted -9223372032559808511\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775807_ssa(-4294967296); got != 9223372032559808511 {
+		fmt.Printf("sub_int64 -4294967296%s-9223372036854775807 = %d, wanted 9223372032559808511\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775807_int64_ssa(-1); got != -9223372036854775806 {
+		fmt.Printf("sub_int64 -9223372036854775807%s-1 = %d, wanted -9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775807_ssa(-1); got != 9223372036854775806 {
+		fmt.Printf("sub_int64 -1%s-9223372036854775807 = %d, wanted 9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775807_int64_ssa(0); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 -9223372036854775807%s0 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775807_ssa(0); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 0%s-9223372036854775807 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775807_int64_ssa(1); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 -9223372036854775807%s1 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775807_ssa(1); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 1%s-9223372036854775807 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775807_int64_ssa(4294967296); got != 9223372032559808513 {
+		fmt.Printf("sub_int64 -9223372036854775807%s4294967296 = %d, wanted 9223372032559808513\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775807_ssa(4294967296); got != -9223372032559808513 {
+		fmt.Printf("sub_int64 4294967296%s-9223372036854775807 = %d, wanted -9223372032559808513\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775807_int64_ssa(9223372036854775806); got != 3 {
+		fmt.Printf("sub_int64 -9223372036854775807%s9223372036854775806 = %d, wanted 3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775807_ssa(9223372036854775806); got != -3 {
+		fmt.Printf("sub_int64 9223372036854775806%s-9223372036854775807 = %d, wanted -3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg9223372036854775807_int64_ssa(9223372036854775807); got != 2 {
+		fmt.Printf("sub_int64 -9223372036854775807%s9223372036854775807 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg9223372036854775807_ssa(9223372036854775807); got != -2 {
+		fmt.Printf("sub_int64 9223372036854775807%s-9223372036854775807 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg4294967296_int64_ssa(-9223372036854775808); got != 9223372032559808512 {
+		fmt.Printf("sub_int64 -4294967296%s-9223372036854775808 = %d, wanted 9223372032559808512\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg4294967296_ssa(-9223372036854775808); got != -9223372032559808512 {
+		fmt.Printf("sub_int64 -9223372036854775808%s-4294967296 = %d, wanted -9223372032559808512\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg4294967296_int64_ssa(-9223372036854775807); got != 9223372032559808511 {
+		fmt.Printf("sub_int64 -4294967296%s-9223372036854775807 = %d, wanted 9223372032559808511\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg4294967296_ssa(-9223372036854775807); got != -9223372032559808511 {
+		fmt.Printf("sub_int64 -9223372036854775807%s-4294967296 = %d, wanted -9223372032559808511\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg4294967296_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("sub_int64 -4294967296%s-4294967296 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg4294967296_ssa(-4294967296); got != 0 {
+		fmt.Printf("sub_int64 -4294967296%s-4294967296 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg4294967296_int64_ssa(-1); got != -4294967295 {
+		fmt.Printf("sub_int64 -4294967296%s-1 = %d, wanted -4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg4294967296_ssa(-1); got != 4294967295 {
+		fmt.Printf("sub_int64 -1%s-4294967296 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg4294967296_int64_ssa(0); got != -4294967296 {
+		fmt.Printf("sub_int64 -4294967296%s0 = %d, wanted -4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg4294967296_ssa(0); got != 4294967296 {
+		fmt.Printf("sub_int64 0%s-4294967296 = %d, wanted 4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg4294967296_int64_ssa(1); got != -4294967297 {
+		fmt.Printf("sub_int64 -4294967296%s1 = %d, wanted -4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg4294967296_ssa(1); got != 4294967297 {
+		fmt.Printf("sub_int64 1%s-4294967296 = %d, wanted 4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg4294967296_int64_ssa(4294967296); got != -8589934592 {
+		fmt.Printf("sub_int64 -4294967296%s4294967296 = %d, wanted -8589934592\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg4294967296_ssa(4294967296); got != 8589934592 {
+		fmt.Printf("sub_int64 4294967296%s-4294967296 = %d, wanted 8589934592\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg4294967296_int64_ssa(9223372036854775806); got != 9223372032559808514 {
+		fmt.Printf("sub_int64 -4294967296%s9223372036854775806 = %d, wanted 9223372032559808514\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg4294967296_ssa(9223372036854775806); got != -9223372032559808514 {
+		fmt.Printf("sub_int64 9223372036854775806%s-4294967296 = %d, wanted -9223372032559808514\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg4294967296_int64_ssa(9223372036854775807); got != 9223372032559808513 {
+		fmt.Printf("sub_int64 -4294967296%s9223372036854775807 = %d, wanted 9223372032559808513\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg4294967296_ssa(9223372036854775807); got != -9223372032559808513 {
+		fmt.Printf("sub_int64 9223372036854775807%s-4294967296 = %d, wanted -9223372032559808513\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int64_ssa(-9223372036854775808); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 -1%s-9223372036854775808 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg1_ssa(-9223372036854775808); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 -9223372036854775808%s-1 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int64_ssa(-9223372036854775807); got != 9223372036854775806 {
+		fmt.Printf("sub_int64 -1%s-9223372036854775807 = %d, wanted 9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg1_ssa(-9223372036854775807); got != -9223372036854775806 {
+		fmt.Printf("sub_int64 -9223372036854775807%s-1 = %d, wanted -9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int64_ssa(-4294967296); got != 4294967295 {
+		fmt.Printf("sub_int64 -1%s-4294967296 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg1_ssa(-4294967296); got != -4294967295 {
+		fmt.Printf("sub_int64 -4294967296%s-1 = %d, wanted -4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int64_ssa(-1); got != 0 {
+		fmt.Printf("sub_int64 -1%s-1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg1_ssa(-1); got != 0 {
+		fmt.Printf("sub_int64 -1%s-1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int64_ssa(0); got != -1 {
+		fmt.Printf("sub_int64 -1%s0 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg1_ssa(0); got != 1 {
+		fmt.Printf("sub_int64 0%s-1 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int64_ssa(1); got != -2 {
+		fmt.Printf("sub_int64 -1%s1 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg1_ssa(1); got != 2 {
+		fmt.Printf("sub_int64 1%s-1 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int64_ssa(4294967296); got != -4294967297 {
+		fmt.Printf("sub_int64 -1%s4294967296 = %d, wanted -4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg1_ssa(4294967296); got != 4294967297 {
+		fmt.Printf("sub_int64 4294967296%s-1 = %d, wanted 4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int64_ssa(9223372036854775806); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 -1%s9223372036854775806 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg1_ssa(9223372036854775806); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 9223372036854775806%s-1 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int64_ssa(9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 -1%s9223372036854775807 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_Neg1_ssa(9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 9223372036854775807%s-1 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int64_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 0%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_0_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 -9223372036854775808%s0 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int64_ssa(-9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 0%s-9223372036854775807 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_0_ssa(-9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 -9223372036854775807%s0 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int64_ssa(-4294967296); got != 4294967296 {
+		fmt.Printf("sub_int64 0%s-4294967296 = %d, wanted 4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_0_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("sub_int64 -4294967296%s0 = %d, wanted -4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int64_ssa(-1); got != 1 {
+		fmt.Printf("sub_int64 0%s-1 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_0_ssa(-1); got != -1 {
+		fmt.Printf("sub_int64 -1%s0 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int64_ssa(0); got != 0 {
+		fmt.Printf("sub_int64 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_0_ssa(0); got != 0 {
+		fmt.Printf("sub_int64 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int64_ssa(1); got != -1 {
+		fmt.Printf("sub_int64 0%s1 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_0_ssa(1); got != 1 {
+		fmt.Printf("sub_int64 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int64_ssa(4294967296); got != -4294967296 {
+		fmt.Printf("sub_int64 0%s4294967296 = %d, wanted -4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_0_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("sub_int64 4294967296%s0 = %d, wanted 4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int64_ssa(9223372036854775806); got != -9223372036854775806 {
+		fmt.Printf("sub_int64 0%s9223372036854775806 = %d, wanted -9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_0_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("sub_int64 9223372036854775806%s0 = %d, wanted 9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int64_ssa(9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 0%s9223372036854775807 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_0_ssa(9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 9223372036854775807%s0 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int64_ssa(-9223372036854775808); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 1%s-9223372036854775808 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_1_ssa(-9223372036854775808); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 -9223372036854775808%s1 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int64_ssa(-9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 1%s-9223372036854775807 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_1_ssa(-9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 -9223372036854775807%s1 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int64_ssa(-4294967296); got != 4294967297 {
+		fmt.Printf("sub_int64 1%s-4294967296 = %d, wanted 4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_1_ssa(-4294967296); got != -4294967297 {
+		fmt.Printf("sub_int64 -4294967296%s1 = %d, wanted -4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int64_ssa(-1); got != 2 {
+		fmt.Printf("sub_int64 1%s-1 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_1_ssa(-1); got != -2 {
+		fmt.Printf("sub_int64 -1%s1 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int64_ssa(0); got != 1 {
+		fmt.Printf("sub_int64 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_1_ssa(0); got != -1 {
+		fmt.Printf("sub_int64 0%s1 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int64_ssa(1); got != 0 {
+		fmt.Printf("sub_int64 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_1_ssa(1); got != 0 {
+		fmt.Printf("sub_int64 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int64_ssa(4294967296); got != -4294967295 {
+		fmt.Printf("sub_int64 1%s4294967296 = %d, wanted -4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_1_ssa(4294967296); got != 4294967295 {
+		fmt.Printf("sub_int64 4294967296%s1 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int64_ssa(9223372036854775806); got != -9223372036854775805 {
+		fmt.Printf("sub_int64 1%s9223372036854775806 = %d, wanted -9223372036854775805\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_1_ssa(9223372036854775806); got != 9223372036854775805 {
+		fmt.Printf("sub_int64 9223372036854775806%s1 = %d, wanted 9223372036854775805\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int64_ssa(9223372036854775807); got != -9223372036854775806 {
+		fmt.Printf("sub_int64 1%s9223372036854775807 = %d, wanted -9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_1_ssa(9223372036854775807); got != 9223372036854775806 {
+		fmt.Printf("sub_int64 9223372036854775807%s1 = %d, wanted 9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_int64_ssa(-9223372036854775808); got != -9223372032559808512 {
+		fmt.Printf("sub_int64 4294967296%s-9223372036854775808 = %d, wanted -9223372032559808512\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_4294967296_ssa(-9223372036854775808); got != 9223372032559808512 {
+		fmt.Printf("sub_int64 -9223372036854775808%s4294967296 = %d, wanted 9223372032559808512\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_int64_ssa(-9223372036854775807); got != -9223372032559808513 {
+		fmt.Printf("sub_int64 4294967296%s-9223372036854775807 = %d, wanted -9223372032559808513\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_4294967296_ssa(-9223372036854775807); got != 9223372032559808513 {
+		fmt.Printf("sub_int64 -9223372036854775807%s4294967296 = %d, wanted 9223372032559808513\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_int64_ssa(-4294967296); got != 8589934592 {
+		fmt.Printf("sub_int64 4294967296%s-4294967296 = %d, wanted 8589934592\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_4294967296_ssa(-4294967296); got != -8589934592 {
+		fmt.Printf("sub_int64 -4294967296%s4294967296 = %d, wanted -8589934592\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_int64_ssa(-1); got != 4294967297 {
+		fmt.Printf("sub_int64 4294967296%s-1 = %d, wanted 4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_4294967296_ssa(-1); got != -4294967297 {
+		fmt.Printf("sub_int64 -1%s4294967296 = %d, wanted -4294967297\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_int64_ssa(0); got != 4294967296 {
+		fmt.Printf("sub_int64 4294967296%s0 = %d, wanted 4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_4294967296_ssa(0); got != -4294967296 {
+		fmt.Printf("sub_int64 0%s4294967296 = %d, wanted -4294967296\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_int64_ssa(1); got != 4294967295 {
+		fmt.Printf("sub_int64 4294967296%s1 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_4294967296_ssa(1); got != -4294967295 {
+		fmt.Printf("sub_int64 1%s4294967296 = %d, wanted -4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("sub_int64 4294967296%s4294967296 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("sub_int64 4294967296%s4294967296 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_int64_ssa(9223372036854775806); got != -9223372032559808510 {
+		fmt.Printf("sub_int64 4294967296%s9223372036854775806 = %d, wanted -9223372032559808510\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_4294967296_ssa(9223372036854775806); got != 9223372032559808510 {
+		fmt.Printf("sub_int64 9223372036854775806%s4294967296 = %d, wanted 9223372032559808510\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967296_int64_ssa(9223372036854775807); got != -9223372032559808511 {
+		fmt.Printf("sub_int64 4294967296%s9223372036854775807 = %d, wanted -9223372032559808511\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_4294967296_ssa(9223372036854775807); got != 9223372032559808511 {
+		fmt.Printf("sub_int64 9223372036854775807%s4294967296 = %d, wanted 9223372032559808511\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775806_int64_ssa(-9223372036854775808); got != -2 {
+		fmt.Printf("sub_int64 9223372036854775806%s-9223372036854775808 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775806_ssa(-9223372036854775808); got != 2 {
+		fmt.Printf("sub_int64 -9223372036854775808%s9223372036854775806 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775806_int64_ssa(-9223372036854775807); got != -3 {
+		fmt.Printf("sub_int64 9223372036854775806%s-9223372036854775807 = %d, wanted -3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775806_ssa(-9223372036854775807); got != 3 {
+		fmt.Printf("sub_int64 -9223372036854775807%s9223372036854775806 = %d, wanted 3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775806_int64_ssa(-4294967296); got != -9223372032559808514 {
+		fmt.Printf("sub_int64 9223372036854775806%s-4294967296 = %d, wanted -9223372032559808514\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775806_ssa(-4294967296); got != 9223372032559808514 {
+		fmt.Printf("sub_int64 -4294967296%s9223372036854775806 = %d, wanted 9223372032559808514\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775806_int64_ssa(-1); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 9223372036854775806%s-1 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775806_ssa(-1); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 -1%s9223372036854775806 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775806_int64_ssa(0); got != 9223372036854775806 {
+		fmt.Printf("sub_int64 9223372036854775806%s0 = %d, wanted 9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775806_ssa(0); got != -9223372036854775806 {
+		fmt.Printf("sub_int64 0%s9223372036854775806 = %d, wanted -9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775806_int64_ssa(1); got != 9223372036854775805 {
+		fmt.Printf("sub_int64 9223372036854775806%s1 = %d, wanted 9223372036854775805\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775806_ssa(1); got != -9223372036854775805 {
+		fmt.Printf("sub_int64 1%s9223372036854775806 = %d, wanted -9223372036854775805\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775806_int64_ssa(4294967296); got != 9223372032559808510 {
+		fmt.Printf("sub_int64 9223372036854775806%s4294967296 = %d, wanted 9223372032559808510\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775806_ssa(4294967296); got != -9223372032559808510 {
+		fmt.Printf("sub_int64 4294967296%s9223372036854775806 = %d, wanted -9223372032559808510\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775806_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("sub_int64 9223372036854775806%s9223372036854775806 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775806_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("sub_int64 9223372036854775806%s9223372036854775806 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775806_int64_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("sub_int64 9223372036854775806%s9223372036854775807 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775806_ssa(9223372036854775807); got != 1 {
+		fmt.Printf("sub_int64 9223372036854775807%s9223372036854775806 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775807_int64_ssa(-9223372036854775808); got != -1 {
+		fmt.Printf("sub_int64 9223372036854775807%s-9223372036854775808 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775807_ssa(-9223372036854775808); got != 1 {
+		fmt.Printf("sub_int64 -9223372036854775808%s9223372036854775807 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775807_int64_ssa(-9223372036854775807); got != -2 {
+		fmt.Printf("sub_int64 9223372036854775807%s-9223372036854775807 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775807_ssa(-9223372036854775807); got != 2 {
+		fmt.Printf("sub_int64 -9223372036854775807%s9223372036854775807 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775807_int64_ssa(-4294967296); got != -9223372032559808513 {
+		fmt.Printf("sub_int64 9223372036854775807%s-4294967296 = %d, wanted -9223372032559808513\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775807_ssa(-4294967296); got != 9223372032559808513 {
+		fmt.Printf("sub_int64 -4294967296%s9223372036854775807 = %d, wanted 9223372032559808513\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775807_int64_ssa(-1); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 9223372036854775807%s-1 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775807_ssa(-1); got != -9223372036854775808 {
+		fmt.Printf("sub_int64 -1%s9223372036854775807 = %d, wanted -9223372036854775808\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775807_int64_ssa(0); got != 9223372036854775807 {
+		fmt.Printf("sub_int64 9223372036854775807%s0 = %d, wanted 9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775807_ssa(0); got != -9223372036854775807 {
+		fmt.Printf("sub_int64 0%s9223372036854775807 = %d, wanted -9223372036854775807\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775807_int64_ssa(1); got != 9223372036854775806 {
+		fmt.Printf("sub_int64 9223372036854775807%s1 = %d, wanted 9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775807_ssa(1); got != -9223372036854775806 {
+		fmt.Printf("sub_int64 1%s9223372036854775807 = %d, wanted -9223372036854775806\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775807_int64_ssa(4294967296); got != 9223372032559808511 {
+		fmt.Printf("sub_int64 9223372036854775807%s4294967296 = %d, wanted 9223372032559808511\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775807_ssa(4294967296); got != -9223372032559808511 {
+		fmt.Printf("sub_int64 4294967296%s9223372036854775807 = %d, wanted -9223372032559808511\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775807_int64_ssa(9223372036854775806); got != 1 {
+		fmt.Printf("sub_int64 9223372036854775807%s9223372036854775806 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775807_ssa(9223372036854775806); got != -1 {
+		fmt.Printf("sub_int64 9223372036854775806%s9223372036854775807 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_9223372036854775807_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("sub_int64 9223372036854775807%s9223372036854775807 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int64_9223372036854775807_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("sub_int64 9223372036854775807%s9223372036854775807 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775808_int64_ssa(-9223372036854775808); got != 1 {
+		fmt.Printf("div_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775808_ssa(-9223372036854775808); got != 1 {
+		fmt.Printf("div_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775808_int64_ssa(-9223372036854775807); got != 1 {
+		fmt.Printf("div_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775808_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775808_int64_ssa(-4294967296); got != 2147483648 {
+		fmt.Printf("div_int64 -9223372036854775808%s-4294967296 = %d, wanted 2147483648\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775808_ssa(-4294967296); got != 0 {
+		fmt.Printf("div_int64 -4294967296%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775808_int64_ssa(-1); got != -9223372036854775808 {
+		fmt.Printf("div_int64 -9223372036854775808%s-1 = %d, wanted -9223372036854775808\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775808_ssa(-1); got != 0 {
+		fmt.Printf("div_int64 -1%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775808_ssa(0); got != 0 {
+		fmt.Printf("div_int64 0%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775808_int64_ssa(1); got != -9223372036854775808 {
+		fmt.Printf("div_int64 -9223372036854775808%s1 = %d, wanted -9223372036854775808\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775808_ssa(1); got != 0 {
+		fmt.Printf("div_int64 1%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775808_int64_ssa(4294967296); got != -2147483648 {
+		fmt.Printf("div_int64 -9223372036854775808%s4294967296 = %d, wanted -2147483648\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775808_ssa(4294967296); got != 0 {
+		fmt.Printf("div_int64 4294967296%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775808_int64_ssa(9223372036854775806); got != -1 {
+		fmt.Printf("div_int64 -9223372036854775808%s9223372036854775806 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775808_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("div_int64 9223372036854775806%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775808_int64_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("div_int64 -9223372036854775808%s9223372036854775807 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775808_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 9223372036854775807%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775807_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("div_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775807_ssa(-9223372036854775808); got != 1 {
+		fmt.Printf("div_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775807_int64_ssa(-9223372036854775807); got != 1 {
+		fmt.Printf("div_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775807_ssa(-9223372036854775807); got != 1 {
+		fmt.Printf("div_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775807_int64_ssa(-4294967296); got != 2147483647 {
+		fmt.Printf("div_int64 -9223372036854775807%s-4294967296 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775807_ssa(-4294967296); got != 0 {
+		fmt.Printf("div_int64 -4294967296%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775807_int64_ssa(-1); got != 9223372036854775807 {
+		fmt.Printf("div_int64 -9223372036854775807%s-1 = %d, wanted 9223372036854775807\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775807_ssa(-1); got != 0 {
+		fmt.Printf("div_int64 -1%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775807_ssa(0); got != 0 {
+		fmt.Printf("div_int64 0%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775807_int64_ssa(1); got != -9223372036854775807 {
+		fmt.Printf("div_int64 -9223372036854775807%s1 = %d, wanted -9223372036854775807\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775807_ssa(1); got != 0 {
+		fmt.Printf("div_int64 1%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775807_int64_ssa(4294967296); got != -2147483647 {
+		fmt.Printf("div_int64 -9223372036854775807%s4294967296 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775807_ssa(4294967296); got != 0 {
+		fmt.Printf("div_int64 4294967296%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775807_int64_ssa(9223372036854775806); got != -1 {
+		fmt.Printf("div_int64 -9223372036854775807%s9223372036854775806 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775807_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("div_int64 9223372036854775806%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg9223372036854775807_int64_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("div_int64 -9223372036854775807%s9223372036854775807 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg9223372036854775807_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("div_int64 9223372036854775807%s-9223372036854775807 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg4294967296_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("div_int64 -4294967296%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg4294967296_ssa(-9223372036854775808); got != 2147483648 {
+		fmt.Printf("div_int64 -9223372036854775808%s-4294967296 = %d, wanted 2147483648\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg4294967296_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 -4294967296%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg4294967296_ssa(-9223372036854775807); got != 2147483647 {
+		fmt.Printf("div_int64 -9223372036854775807%s-4294967296 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg4294967296_int64_ssa(-4294967296); got != 1 {
+		fmt.Printf("div_int64 -4294967296%s-4294967296 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg4294967296_ssa(-4294967296); got != 1 {
+		fmt.Printf("div_int64 -4294967296%s-4294967296 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg4294967296_int64_ssa(-1); got != 4294967296 {
+		fmt.Printf("div_int64 -4294967296%s-1 = %d, wanted 4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg4294967296_ssa(-1); got != 0 {
+		fmt.Printf("div_int64 -1%s-4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg4294967296_ssa(0); got != 0 {
+		fmt.Printf("div_int64 0%s-4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg4294967296_int64_ssa(1); got != -4294967296 {
+		fmt.Printf("div_int64 -4294967296%s1 = %d, wanted -4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg4294967296_ssa(1); got != 0 {
+		fmt.Printf("div_int64 1%s-4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg4294967296_int64_ssa(4294967296); got != -1 {
+		fmt.Printf("div_int64 -4294967296%s4294967296 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg4294967296_ssa(4294967296); got != -1 {
+		fmt.Printf("div_int64 4294967296%s-4294967296 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg4294967296_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("div_int64 -4294967296%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg4294967296_ssa(9223372036854775806); got != -2147483647 {
+		fmt.Printf("div_int64 9223372036854775806%s-4294967296 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg4294967296_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 -4294967296%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg4294967296_ssa(9223372036854775807); got != -2147483647 {
+		fmt.Printf("div_int64 9223372036854775807%s-4294967296 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("div_int64 -1%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg1_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("div_int64 -9223372036854775808%s-1 = %d, wanted -9223372036854775808\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 -1%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg1_ssa(-9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("div_int64 -9223372036854775807%s-1 = %d, wanted 9223372036854775807\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("div_int64 -1%s-4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg1_ssa(-4294967296); got != 4294967296 {
+		fmt.Printf("div_int64 -4294967296%s-1 = %d, wanted 4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int64_ssa(-1); got != 1 {
+		fmt.Printf("div_int64 -1%s-1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg1_ssa(-1); got != 1 {
+		fmt.Printf("div_int64 -1%s-1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg1_ssa(0); got != 0 {
+		fmt.Printf("div_int64 0%s-1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int64_ssa(1); got != -1 {
+		fmt.Printf("div_int64 -1%s1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg1_ssa(1); got != -1 {
+		fmt.Printf("div_int64 1%s-1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("div_int64 -1%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg1_ssa(4294967296); got != -4294967296 {
+		fmt.Printf("div_int64 4294967296%s-1 = %d, wanted -4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("div_int64 -1%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg1_ssa(9223372036854775806); got != -9223372036854775806 {
+		fmt.Printf("div_int64 9223372036854775806%s-1 = %d, wanted -9223372036854775806\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 -1%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_Neg1_ssa(9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("div_int64 9223372036854775807%s-1 = %d, wanted -9223372036854775807\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("div_int64 0%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 0%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("div_int64 0%s-4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int64_ssa(-1); got != 0 {
+		fmt.Printf("div_int64 0%s-1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int64_ssa(1); got != 0 {
+		fmt.Printf("div_int64 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("div_int64 0%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("div_int64 0%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 0%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("div_int64 1%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_1_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("div_int64 -9223372036854775808%s1 = %d, wanted -9223372036854775808\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 1%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_1_ssa(-9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("div_int64 -9223372036854775807%s1 = %d, wanted -9223372036854775807\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("div_int64 1%s-4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_1_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("div_int64 -4294967296%s1 = %d, wanted -4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int64_ssa(-1); got != -1 {
+		fmt.Printf("div_int64 1%s-1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_1_ssa(-1); got != -1 {
+		fmt.Printf("div_int64 -1%s1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_1_ssa(0); got != 0 {
+		fmt.Printf("div_int64 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int64_ssa(1); got != 1 {
+		fmt.Printf("div_int64 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_1_ssa(1); got != 1 {
+		fmt.Printf("div_int64 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("div_int64 1%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_1_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("div_int64 4294967296%s1 = %d, wanted 4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("div_int64 1%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_1_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("div_int64 9223372036854775806%s1 = %d, wanted 9223372036854775806\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 1%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_1_ssa(9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("div_int64 9223372036854775807%s1 = %d, wanted 9223372036854775807\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("div_int64 4294967296%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_4294967296_ssa(-9223372036854775808); got != -2147483648 {
+		fmt.Printf("div_int64 -9223372036854775808%s4294967296 = %d, wanted -2147483648\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 4294967296%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_4294967296_ssa(-9223372036854775807); got != -2147483647 {
+		fmt.Printf("div_int64 -9223372036854775807%s4294967296 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_int64_ssa(-4294967296); got != -1 {
+		fmt.Printf("div_int64 4294967296%s-4294967296 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_4294967296_ssa(-4294967296); got != -1 {
+		fmt.Printf("div_int64 -4294967296%s4294967296 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_int64_ssa(-1); got != -4294967296 {
+		fmt.Printf("div_int64 4294967296%s-1 = %d, wanted -4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_4294967296_ssa(-1); got != 0 {
+		fmt.Printf("div_int64 -1%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_4294967296_ssa(0); got != 0 {
+		fmt.Printf("div_int64 0%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_int64_ssa(1); got != 4294967296 {
+		fmt.Printf("div_int64 4294967296%s1 = %d, wanted 4294967296\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_4294967296_ssa(1); got != 0 {
+		fmt.Printf("div_int64 1%s4294967296 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_int64_ssa(4294967296); got != 1 {
+		fmt.Printf("div_int64 4294967296%s4294967296 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_4294967296_ssa(4294967296); got != 1 {
+		fmt.Printf("div_int64 4294967296%s4294967296 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("div_int64 4294967296%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_4294967296_ssa(9223372036854775806); got != 2147483647 {
+		fmt.Printf("div_int64 9223372036854775806%s4294967296 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967296_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 4294967296%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_4294967296_ssa(9223372036854775807); got != 2147483647 {
+		fmt.Printf("div_int64 9223372036854775807%s4294967296 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775806_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("div_int64 9223372036854775806%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775806_ssa(-9223372036854775808); got != -1 {
+		fmt.Printf("div_int64 -9223372036854775808%s9223372036854775806 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775806_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 9223372036854775806%s-9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775806_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("div_int64 -9223372036854775807%s9223372036854775806 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775806_int64_ssa(-4294967296); got != -2147483647 {
+		fmt.Printf("div_int64 9223372036854775806%s-4294967296 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775806_ssa(-4294967296); got != 0 {
+		fmt.Printf("div_int64 -4294967296%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775806_int64_ssa(-1); got != -9223372036854775806 {
+		fmt.Printf("div_int64 9223372036854775806%s-1 = %d, wanted -9223372036854775806\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775806_ssa(-1); got != 0 {
+		fmt.Printf("div_int64 -1%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775806_ssa(0); got != 0 {
+		fmt.Printf("div_int64 0%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775806_int64_ssa(1); got != 9223372036854775806 {
+		fmt.Printf("div_int64 9223372036854775806%s1 = %d, wanted 9223372036854775806\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775806_ssa(1); got != 0 {
+		fmt.Printf("div_int64 1%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775806_int64_ssa(4294967296); got != 2147483647 {
+		fmt.Printf("div_int64 9223372036854775806%s4294967296 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775806_ssa(4294967296); got != 0 {
+		fmt.Printf("div_int64 4294967296%s9223372036854775806 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775806_int64_ssa(9223372036854775806); got != 1 {
+		fmt.Printf("div_int64 9223372036854775806%s9223372036854775806 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775806_ssa(9223372036854775806); got != 1 {
+		fmt.Printf("div_int64 9223372036854775806%s9223372036854775806 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775806_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("div_int64 9223372036854775806%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775806_ssa(9223372036854775807); got != 1 {
+		fmt.Printf("div_int64 9223372036854775807%s9223372036854775806 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775807_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("div_int64 9223372036854775807%s-9223372036854775808 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775807_ssa(-9223372036854775808); got != -1 {
+		fmt.Printf("div_int64 -9223372036854775808%s9223372036854775807 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775807_int64_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("div_int64 9223372036854775807%s-9223372036854775807 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775807_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("div_int64 -9223372036854775807%s9223372036854775807 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775807_int64_ssa(-4294967296); got != -2147483647 {
+		fmt.Printf("div_int64 9223372036854775807%s-4294967296 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775807_ssa(-4294967296); got != 0 {
+		fmt.Printf("div_int64 -4294967296%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775807_int64_ssa(-1); got != -9223372036854775807 {
+		fmt.Printf("div_int64 9223372036854775807%s-1 = %d, wanted -9223372036854775807\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775807_ssa(-1); got != 0 {
+		fmt.Printf("div_int64 -1%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775807_ssa(0); got != 0 {
+		fmt.Printf("div_int64 0%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775807_int64_ssa(1); got != 9223372036854775807 {
+		fmt.Printf("div_int64 9223372036854775807%s1 = %d, wanted 9223372036854775807\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775807_ssa(1); got != 0 {
+		fmt.Printf("div_int64 1%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775807_int64_ssa(4294967296); got != 2147483647 {
+		fmt.Printf("div_int64 9223372036854775807%s4294967296 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775807_ssa(4294967296); got != 0 {
+		fmt.Printf("div_int64 4294967296%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775807_int64_ssa(9223372036854775806); got != 1 {
+		fmt.Printf("div_int64 9223372036854775807%s9223372036854775806 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775807_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("div_int64 9223372036854775806%s9223372036854775807 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_9223372036854775807_int64_ssa(9223372036854775807); got != 1 {
+		fmt.Printf("div_int64 9223372036854775807%s9223372036854775807 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int64_9223372036854775807_ssa(9223372036854775807); got != 1 {
+		fmt.Printf("div_int64 9223372036854775807%s9223372036854775807 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775808_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775808_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775808_int64_ssa(-9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775808_ssa(-9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775808_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s-4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775808_ssa(-4294967296); got != 0 {
+		fmt.Printf("mul_int64 -4294967296%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775808_int64_ssa(-1); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775808%s-1 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775808_ssa(-1); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -1%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775808_int64_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775808_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775808_int64_ssa(1); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775808%s1 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775808_ssa(1); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 1%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775808_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775808_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_int64 4294967296%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775808_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s9223372036854775806 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775808_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("mul_int64 9223372036854775806%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775808_int64_ssa(9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775808%s9223372036854775807 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775808_ssa(9223372036854775807); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 9223372036854775807%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775807_int64_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775807_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775807_int64_ssa(-9223372036854775807); got != 1 {
+		fmt.Printf("mul_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775807_ssa(-9223372036854775807); got != 1 {
+		fmt.Printf("mul_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775807_int64_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("mul_int64 -9223372036854775807%s-4294967296 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775807_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("mul_int64 -4294967296%s-9223372036854775807 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775807_int64_ssa(-1); got != 9223372036854775807 {
+		fmt.Printf("mul_int64 -9223372036854775807%s-1 = %d, wanted 9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775807_ssa(-1); got != 9223372036854775807 {
+		fmt.Printf("mul_int64 -1%s-9223372036854775807 = %d, wanted 9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775807_int64_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775807%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775807_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s-9223372036854775807 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775807_int64_ssa(1); got != -9223372036854775807 {
+		fmt.Printf("mul_int64 -9223372036854775807%s1 = %d, wanted -9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775807_ssa(1); got != -9223372036854775807 {
+		fmt.Printf("mul_int64 1%s-9223372036854775807 = %d, wanted -9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775807_int64_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mul_int64 -9223372036854775807%s4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775807_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mul_int64 4294967296%s-9223372036854775807 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775807_int64_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("mul_int64 -9223372036854775807%s9223372036854775806 = %d, wanted 9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775807_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775806%s-9223372036854775807 = %d, wanted 9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg9223372036854775807_int64_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("mul_int64 -9223372036854775807%s9223372036854775807 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg9223372036854775807_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("mul_int64 9223372036854775807%s-9223372036854775807 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg4294967296_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 -4294967296%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg4294967296_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s-4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg4294967296_int64_ssa(-9223372036854775807); got != -4294967296 {
+		fmt.Printf("mul_int64 -4294967296%s-9223372036854775807 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg4294967296_ssa(-9223372036854775807); got != -4294967296 {
+		fmt.Printf("mul_int64 -9223372036854775807%s-4294967296 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg4294967296_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("mul_int64 -4294967296%s-4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg4294967296_ssa(-4294967296); got != 0 {
+		fmt.Printf("mul_int64 -4294967296%s-4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg4294967296_int64_ssa(-1); got != 4294967296 {
+		fmt.Printf("mul_int64 -4294967296%s-1 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg4294967296_ssa(-1); got != 4294967296 {
+		fmt.Printf("mul_int64 -1%s-4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg4294967296_int64_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 -4294967296%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg4294967296_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s-4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg4294967296_int64_ssa(1); got != -4294967296 {
+		fmt.Printf("mul_int64 -4294967296%s1 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg4294967296_ssa(1); got != -4294967296 {
+		fmt.Printf("mul_int64 1%s-4294967296 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg4294967296_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_int64 -4294967296%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_int64 4294967296%s-4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg4294967296_int64_ssa(9223372036854775806); got != 8589934592 {
+		fmt.Printf("mul_int64 -4294967296%s9223372036854775806 = %d, wanted 8589934592\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg4294967296_ssa(9223372036854775806); got != 8589934592 {
+		fmt.Printf("mul_int64 9223372036854775806%s-4294967296 = %d, wanted 8589934592\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg4294967296_int64_ssa(9223372036854775807); got != 4294967296 {
+		fmt.Printf("mul_int64 -4294967296%s9223372036854775807 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg4294967296_ssa(9223372036854775807); got != 4294967296 {
+		fmt.Printf("mul_int64 9223372036854775807%s-4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int64_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -1%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg1_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775808%s-1 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int64_ssa(-9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("mul_int64 -1%s-9223372036854775807 = %d, wanted 9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg1_ssa(-9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("mul_int64 -9223372036854775807%s-1 = %d, wanted 9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int64_ssa(-4294967296); got != 4294967296 {
+		fmt.Printf("mul_int64 -1%s-4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg1_ssa(-4294967296); got != 4294967296 {
+		fmt.Printf("mul_int64 -4294967296%s-1 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int64_ssa(-1); got != 1 {
+		fmt.Printf("mul_int64 -1%s-1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg1_ssa(-1); got != 1 {
+		fmt.Printf("mul_int64 -1%s-1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int64_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 -1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg1_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s-1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int64_ssa(1); got != -1 {
+		fmt.Printf("mul_int64 -1%s1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg1_ssa(1); got != -1 {
+		fmt.Printf("mul_int64 1%s-1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int64_ssa(4294967296); got != -4294967296 {
+		fmt.Printf("mul_int64 -1%s4294967296 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg1_ssa(4294967296); got != -4294967296 {
+		fmt.Printf("mul_int64 4294967296%s-1 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int64_ssa(9223372036854775806); got != -9223372036854775806 {
+		fmt.Printf("mul_int64 -1%s9223372036854775806 = %d, wanted -9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg1_ssa(9223372036854775806); got != -9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775806%s-1 = %d, wanted -9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int64_ssa(9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("mul_int64 -1%s9223372036854775807 = %d, wanted -9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_Neg1_ssa(9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("mul_int64 9223372036854775807%s-1 = %d, wanted -9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 0%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_0_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("mul_int64 0%s-9223372036854775807 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_0_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775807%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("mul_int64 0%s-4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_0_ssa(-4294967296); got != 0 {
+		fmt.Printf("mul_int64 -4294967296%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int64_ssa(-1); got != 0 {
+		fmt.Printf("mul_int64 0%s-1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_0_ssa(-1); got != 0 {
+		fmt.Printf("mul_int64 -1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int64_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_0_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int64_ssa(1); got != 0 {
+		fmt.Printf("mul_int64 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_0_ssa(1); got != 0 {
+		fmt.Printf("mul_int64 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_int64 0%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_0_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_int64 4294967296%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("mul_int64 0%s9223372036854775806 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_0_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("mul_int64 9223372036854775806%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("mul_int64 0%s9223372036854775807 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_0_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("mul_int64 9223372036854775807%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int64_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 1%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_1_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775808%s1 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int64_ssa(-9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("mul_int64 1%s-9223372036854775807 = %d, wanted -9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_1_ssa(-9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("mul_int64 -9223372036854775807%s1 = %d, wanted -9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int64_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("mul_int64 1%s-4294967296 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_1_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("mul_int64 -4294967296%s1 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int64_ssa(-1); got != -1 {
+		fmt.Printf("mul_int64 1%s-1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_1_ssa(-1); got != -1 {
+		fmt.Printf("mul_int64 -1%s1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int64_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_1_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int64_ssa(1); got != 1 {
+		fmt.Printf("mul_int64 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_1_ssa(1); got != 1 {
+		fmt.Printf("mul_int64 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int64_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mul_int64 1%s4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_1_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mul_int64 4294967296%s1 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int64_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("mul_int64 1%s9223372036854775806 = %d, wanted 9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_1_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775806%s1 = %d, wanted 9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int64_ssa(9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("mul_int64 1%s9223372036854775807 = %d, wanted 9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_1_ssa(9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("mul_int64 9223372036854775807%s1 = %d, wanted 9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 4294967296%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_4294967296_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_int64_ssa(-9223372036854775807); got != 4294967296 {
+		fmt.Printf("mul_int64 4294967296%s-9223372036854775807 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_4294967296_ssa(-9223372036854775807); got != 4294967296 {
+		fmt.Printf("mul_int64 -9223372036854775807%s4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("mul_int64 4294967296%s-4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_4294967296_ssa(-4294967296); got != 0 {
+		fmt.Printf("mul_int64 -4294967296%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_int64_ssa(-1); got != -4294967296 {
+		fmt.Printf("mul_int64 4294967296%s-1 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_4294967296_ssa(-1); got != -4294967296 {
+		fmt.Printf("mul_int64 -1%s4294967296 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_int64_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 4294967296%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_4294967296_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_int64_ssa(1); got != 4294967296 {
+		fmt.Printf("mul_int64 4294967296%s1 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_4294967296_ssa(1); got != 4294967296 {
+		fmt.Printf("mul_int64 1%s4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_int64 4294967296%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("mul_int64 4294967296%s4294967296 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_int64_ssa(9223372036854775806); got != -8589934592 {
+		fmt.Printf("mul_int64 4294967296%s9223372036854775806 = %d, wanted -8589934592\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_4294967296_ssa(9223372036854775806); got != -8589934592 {
+		fmt.Printf("mul_int64 9223372036854775806%s4294967296 = %d, wanted -8589934592\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967296_int64_ssa(9223372036854775807); got != -4294967296 {
+		fmt.Printf("mul_int64 4294967296%s9223372036854775807 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_4294967296_ssa(9223372036854775807); got != -4294967296 {
+		fmt.Printf("mul_int64 9223372036854775807%s4294967296 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775806_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 9223372036854775806%s-9223372036854775808 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775806_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mul_int64 -9223372036854775808%s9223372036854775806 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775806_int64_ssa(-9223372036854775807); got != 9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775806%s-9223372036854775807 = %d, wanted 9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775806_ssa(-9223372036854775807); got != 9223372036854775806 {
+		fmt.Printf("mul_int64 -9223372036854775807%s9223372036854775806 = %d, wanted 9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775806_int64_ssa(-4294967296); got != 8589934592 {
+		fmt.Printf("mul_int64 9223372036854775806%s-4294967296 = %d, wanted 8589934592\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775806_ssa(-4294967296); got != 8589934592 {
+		fmt.Printf("mul_int64 -4294967296%s9223372036854775806 = %d, wanted 8589934592\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775806_int64_ssa(-1); got != -9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775806%s-1 = %d, wanted -9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775806_ssa(-1); got != -9223372036854775806 {
+		fmt.Printf("mul_int64 -1%s9223372036854775806 = %d, wanted -9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775806_int64_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 9223372036854775806%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775806_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s9223372036854775806 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775806_int64_ssa(1); got != 9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775806%s1 = %d, wanted 9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775806_ssa(1); got != 9223372036854775806 {
+		fmt.Printf("mul_int64 1%s9223372036854775806 = %d, wanted 9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775806_int64_ssa(4294967296); got != -8589934592 {
+		fmt.Printf("mul_int64 9223372036854775806%s4294967296 = %d, wanted -8589934592\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775806_ssa(4294967296); got != -8589934592 {
+		fmt.Printf("mul_int64 4294967296%s9223372036854775806 = %d, wanted -8589934592\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775806_int64_ssa(9223372036854775806); got != 4 {
+		fmt.Printf("mul_int64 9223372036854775806%s9223372036854775806 = %d, wanted 4\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775806_ssa(9223372036854775806); got != 4 {
+		fmt.Printf("mul_int64 9223372036854775806%s9223372036854775806 = %d, wanted 4\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775806_int64_ssa(9223372036854775807); got != -9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775806%s9223372036854775807 = %d, wanted -9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775806_ssa(9223372036854775807); got != -9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775807%s9223372036854775806 = %d, wanted -9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775807_int64_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 9223372036854775807%s-9223372036854775808 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775807_ssa(-9223372036854775808); got != -9223372036854775808 {
+		fmt.Printf("mul_int64 -9223372036854775808%s9223372036854775807 = %d, wanted -9223372036854775808\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775807_int64_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("mul_int64 9223372036854775807%s-9223372036854775807 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775807_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("mul_int64 -9223372036854775807%s9223372036854775807 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775807_int64_ssa(-4294967296); got != 4294967296 {
+		fmt.Printf("mul_int64 9223372036854775807%s-4294967296 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775807_ssa(-4294967296); got != 4294967296 {
+		fmt.Printf("mul_int64 -4294967296%s9223372036854775807 = %d, wanted 4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775807_int64_ssa(-1); got != -9223372036854775807 {
+		fmt.Printf("mul_int64 9223372036854775807%s-1 = %d, wanted -9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775807_ssa(-1); got != -9223372036854775807 {
+		fmt.Printf("mul_int64 -1%s9223372036854775807 = %d, wanted -9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775807_int64_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 9223372036854775807%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775807_ssa(0); got != 0 {
+		fmt.Printf("mul_int64 0%s9223372036854775807 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775807_int64_ssa(1); got != 9223372036854775807 {
+		fmt.Printf("mul_int64 9223372036854775807%s1 = %d, wanted 9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775807_ssa(1); got != 9223372036854775807 {
+		fmt.Printf("mul_int64 1%s9223372036854775807 = %d, wanted 9223372036854775807\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775807_int64_ssa(4294967296); got != -4294967296 {
+		fmt.Printf("mul_int64 9223372036854775807%s4294967296 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775807_ssa(4294967296); got != -4294967296 {
+		fmt.Printf("mul_int64 4294967296%s9223372036854775807 = %d, wanted -4294967296\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775807_int64_ssa(9223372036854775806); got != -9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775807%s9223372036854775806 = %d, wanted -9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775807_ssa(9223372036854775806); got != -9223372036854775806 {
+		fmt.Printf("mul_int64 9223372036854775806%s9223372036854775807 = %d, wanted -9223372036854775806\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_9223372036854775807_int64_ssa(9223372036854775807); got != 1 {
+		fmt.Printf("mul_int64 9223372036854775807%s9223372036854775807 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int64_9223372036854775807_ssa(9223372036854775807); got != 1 {
+		fmt.Printf("mul_int64 9223372036854775807%s9223372036854775807 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775808_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775808_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s-9223372036854775808 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775808_int64_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("mod_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775808_ssa(-9223372036854775807); got != -9223372036854775807 {
+		fmt.Printf("mod_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted -9223372036854775807\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775808_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s-4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775808_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("mod_int64 -4294967296%s-9223372036854775808 = %d, wanted -4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775808_int64_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775808_ssa(-1); got != -1 {
+		fmt.Printf("mod_int64 -1%s-9223372036854775808 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775808_ssa(0); got != 0 {
+		fmt.Printf("mod_int64 0%s-9223372036854775808 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775808_int64_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775808_ssa(1); got != 1 {
+		fmt.Printf("mod_int64 1%s-9223372036854775808 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775808_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775808_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mod_int64 4294967296%s-9223372036854775808 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775808_int64_ssa(9223372036854775806); got != -2 {
+		fmt.Printf("mod_int64 -9223372036854775808%s9223372036854775806 = %d, wanted -2\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775808_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("mod_int64 9223372036854775806%s-9223372036854775808 = %d, wanted 9223372036854775806\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775808_int64_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("mod_int64 -9223372036854775808%s9223372036854775807 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775808_ssa(9223372036854775807); got != 9223372036854775807 {
+		fmt.Printf("mod_int64 9223372036854775807%s-9223372036854775808 = %d, wanted 9223372036854775807\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775807_int64_ssa(-9223372036854775808); got != -9223372036854775807 {
+		fmt.Printf("mod_int64 -9223372036854775807%s-9223372036854775808 = %d, wanted -9223372036854775807\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775807_ssa(-9223372036854775808); got != -1 {
+		fmt.Printf("mod_int64 -9223372036854775808%s-9223372036854775807 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775807_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775807_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775807%s-9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775807_int64_ssa(-4294967296); got != -4294967295 {
+		fmt.Printf("mod_int64 -9223372036854775807%s-4294967296 = %d, wanted -4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775807_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("mod_int64 -4294967296%s-9223372036854775807 = %d, wanted -4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775807_int64_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775807%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775807_ssa(-1); got != -1 {
+		fmt.Printf("mod_int64 -1%s-9223372036854775807 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775807_ssa(0); got != 0 {
+		fmt.Printf("mod_int64 0%s-9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775807_int64_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775807%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775807_ssa(1); got != 1 {
+		fmt.Printf("mod_int64 1%s-9223372036854775807 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775807_int64_ssa(4294967296); got != -4294967295 {
+		fmt.Printf("mod_int64 -9223372036854775807%s4294967296 = %d, wanted -4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775807_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mod_int64 4294967296%s-9223372036854775807 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775807_int64_ssa(9223372036854775806); got != -1 {
+		fmt.Printf("mod_int64 -9223372036854775807%s9223372036854775806 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775807_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("mod_int64 9223372036854775806%s-9223372036854775807 = %d, wanted 9223372036854775806\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg9223372036854775807_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775807%s9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg9223372036854775807_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775807%s-9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg4294967296_int64_ssa(-9223372036854775808); got != -4294967296 {
+		fmt.Printf("mod_int64 -4294967296%s-9223372036854775808 = %d, wanted -4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg4294967296_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s-4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg4294967296_int64_ssa(-9223372036854775807); got != -4294967296 {
+		fmt.Printf("mod_int64 -4294967296%s-9223372036854775807 = %d, wanted -4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg4294967296_ssa(-9223372036854775807); got != -4294967295 {
+		fmt.Printf("mod_int64 -9223372036854775807%s-4294967296 = %d, wanted -4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg4294967296_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("mod_int64 -4294967296%s-4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg4294967296_ssa(-4294967296); got != 0 {
+		fmt.Printf("mod_int64 -4294967296%s-4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg4294967296_int64_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 -4294967296%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg4294967296_ssa(-1); got != -1 {
+		fmt.Printf("mod_int64 -1%s-4294967296 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg4294967296_ssa(0); got != 0 {
+		fmt.Printf("mod_int64 0%s-4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg4294967296_int64_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 -4294967296%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg4294967296_ssa(1); got != 1 {
+		fmt.Printf("mod_int64 1%s-4294967296 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg4294967296_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_int64 -4294967296%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_int64 4294967296%s-4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg4294967296_int64_ssa(9223372036854775806); got != -4294967296 {
+		fmt.Printf("mod_int64 -4294967296%s9223372036854775806 = %d, wanted -4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg4294967296_ssa(9223372036854775806); got != 4294967294 {
+		fmt.Printf("mod_int64 9223372036854775806%s-4294967296 = %d, wanted 4294967294\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg4294967296_int64_ssa(9223372036854775807); got != -4294967296 {
+		fmt.Printf("mod_int64 -4294967296%s9223372036854775807 = %d, wanted -4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg4294967296_ssa(9223372036854775807); got != 4294967295 {
+		fmt.Printf("mod_int64 9223372036854775807%s-4294967296 = %d, wanted 4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int64_ssa(-9223372036854775808); got != -1 {
+		fmt.Printf("mod_int64 -1%s-9223372036854775808 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg1_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int64_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("mod_int64 -1%s-9223372036854775807 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg1_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775807%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int64_ssa(-4294967296); got != -1 {
+		fmt.Printf("mod_int64 -1%s-4294967296 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg1_ssa(-4294967296); got != 0 {
+		fmt.Printf("mod_int64 -4294967296%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int64_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 -1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg1_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 -1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg1_ssa(0); got != 0 {
+		fmt.Printf("mod_int64 0%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int64_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 -1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg1_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int64_ssa(4294967296); got != -1 {
+		fmt.Printf("mod_int64 -1%s4294967296 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg1_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_int64 4294967296%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int64_ssa(9223372036854775806); got != -1 {
+		fmt.Printf("mod_int64 -1%s9223372036854775806 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg1_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775806%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int64_ssa(9223372036854775807); got != -1 {
+		fmt.Printf("mod_int64 -1%s9223372036854775807 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_Neg1_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775807%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int64_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mod_int64 0%s-9223372036854775808 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 0%s-9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("mod_int64 0%s-4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int64_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 0%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int64_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_int64 0%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("mod_int64 0%s9223372036854775806 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 0%s9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int64_ssa(-9223372036854775808); got != 1 {
+		fmt.Printf("mod_int64 1%s-9223372036854775808 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_1_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int64_ssa(-9223372036854775807); got != 1 {
+		fmt.Printf("mod_int64 1%s-9223372036854775807 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_1_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775807%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int64_ssa(-4294967296); got != 1 {
+		fmt.Printf("mod_int64 1%s-4294967296 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_1_ssa(-4294967296); got != 0 {
+		fmt.Printf("mod_int64 -4294967296%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int64_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_1_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 -1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_1_ssa(0); got != 0 {
+		fmt.Printf("mod_int64 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int64_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_1_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int64_ssa(4294967296); got != 1 {
+		fmt.Printf("mod_int64 1%s4294967296 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_1_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_int64 4294967296%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int64_ssa(9223372036854775806); got != 1 {
+		fmt.Printf("mod_int64 1%s9223372036854775806 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_1_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775806%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int64_ssa(9223372036854775807); got != 1 {
+		fmt.Printf("mod_int64 1%s9223372036854775807 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_1_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775807%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_int64_ssa(-9223372036854775808); got != 4294967296 {
+		fmt.Printf("mod_int64 4294967296%s-9223372036854775808 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_4294967296_ssa(-9223372036854775808); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775808%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_int64_ssa(-9223372036854775807); got != 4294967296 {
+		fmt.Printf("mod_int64 4294967296%s-9223372036854775807 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_4294967296_ssa(-9223372036854775807); got != -4294967295 {
+		fmt.Printf("mod_int64 -9223372036854775807%s4294967296 = %d, wanted -4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_int64_ssa(-4294967296); got != 0 {
+		fmt.Printf("mod_int64 4294967296%s-4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_4294967296_ssa(-4294967296); got != 0 {
+		fmt.Printf("mod_int64 -4294967296%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_int64_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 4294967296%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_4294967296_ssa(-1); got != -1 {
+		fmt.Printf("mod_int64 -1%s4294967296 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_4294967296_ssa(0); got != 0 {
+		fmt.Printf("mod_int64 0%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_int64_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 4294967296%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_4294967296_ssa(1); got != 1 {
+		fmt.Printf("mod_int64 1%s4294967296 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_int64_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_int64 4294967296%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_4294967296_ssa(4294967296); got != 0 {
+		fmt.Printf("mod_int64 4294967296%s4294967296 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_int64_ssa(9223372036854775806); got != 4294967296 {
+		fmt.Printf("mod_int64 4294967296%s9223372036854775806 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_4294967296_ssa(9223372036854775806); got != 4294967294 {
+		fmt.Printf("mod_int64 9223372036854775806%s4294967296 = %d, wanted 4294967294\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967296_int64_ssa(9223372036854775807); got != 4294967296 {
+		fmt.Printf("mod_int64 4294967296%s9223372036854775807 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_4294967296_ssa(9223372036854775807); got != 4294967295 {
+		fmt.Printf("mod_int64 9223372036854775807%s4294967296 = %d, wanted 4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775806_int64_ssa(-9223372036854775808); got != 9223372036854775806 {
+		fmt.Printf("mod_int64 9223372036854775806%s-9223372036854775808 = %d, wanted 9223372036854775806\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775806_ssa(-9223372036854775808); got != -2 {
+		fmt.Printf("mod_int64 -9223372036854775808%s9223372036854775806 = %d, wanted -2\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775806_int64_ssa(-9223372036854775807); got != 9223372036854775806 {
+		fmt.Printf("mod_int64 9223372036854775806%s-9223372036854775807 = %d, wanted 9223372036854775806\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775806_ssa(-9223372036854775807); got != -1 {
+		fmt.Printf("mod_int64 -9223372036854775807%s9223372036854775806 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775806_int64_ssa(-4294967296); got != 4294967294 {
+		fmt.Printf("mod_int64 9223372036854775806%s-4294967296 = %d, wanted 4294967294\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775806_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("mod_int64 -4294967296%s9223372036854775806 = %d, wanted -4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775806_int64_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775806%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775806_ssa(-1); got != -1 {
+		fmt.Printf("mod_int64 -1%s9223372036854775806 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775806_ssa(0); got != 0 {
+		fmt.Printf("mod_int64 0%s9223372036854775806 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775806_int64_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775806%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775806_ssa(1); got != 1 {
+		fmt.Printf("mod_int64 1%s9223372036854775806 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775806_int64_ssa(4294967296); got != 4294967294 {
+		fmt.Printf("mod_int64 9223372036854775806%s4294967296 = %d, wanted 4294967294\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775806_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mod_int64 4294967296%s9223372036854775806 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775806_int64_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775806%s9223372036854775806 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775806_ssa(9223372036854775806); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775806%s9223372036854775806 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775806_int64_ssa(9223372036854775807); got != 9223372036854775806 {
+		fmt.Printf("mod_int64 9223372036854775806%s9223372036854775807 = %d, wanted 9223372036854775806\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775806_ssa(9223372036854775807); got != 1 {
+		fmt.Printf("mod_int64 9223372036854775807%s9223372036854775806 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775807_int64_ssa(-9223372036854775808); got != 9223372036854775807 {
+		fmt.Printf("mod_int64 9223372036854775807%s-9223372036854775808 = %d, wanted 9223372036854775807\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775807_ssa(-9223372036854775808); got != -1 {
+		fmt.Printf("mod_int64 -9223372036854775808%s9223372036854775807 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775807_int64_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775807%s-9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775807_ssa(-9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 -9223372036854775807%s9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775807_int64_ssa(-4294967296); got != 4294967295 {
+		fmt.Printf("mod_int64 9223372036854775807%s-4294967296 = %d, wanted 4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775807_ssa(-4294967296); got != -4294967296 {
+		fmt.Printf("mod_int64 -4294967296%s9223372036854775807 = %d, wanted -4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775807_int64_ssa(-1); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775807%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775807_ssa(-1); got != -1 {
+		fmt.Printf("mod_int64 -1%s9223372036854775807 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775807_ssa(0); got != 0 {
+		fmt.Printf("mod_int64 0%s9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775807_int64_ssa(1); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775807%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775807_ssa(1); got != 1 {
+		fmt.Printf("mod_int64 1%s9223372036854775807 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775807_int64_ssa(4294967296); got != 4294967295 {
+		fmt.Printf("mod_int64 9223372036854775807%s4294967296 = %d, wanted 4294967295\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775807_ssa(4294967296); got != 4294967296 {
+		fmt.Printf("mod_int64 4294967296%s9223372036854775807 = %d, wanted 4294967296\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775807_int64_ssa(9223372036854775806); got != 1 {
+		fmt.Printf("mod_int64 9223372036854775807%s9223372036854775806 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775807_ssa(9223372036854775806); got != 9223372036854775806 {
+		fmt.Printf("mod_int64 9223372036854775806%s9223372036854775807 = %d, wanted 9223372036854775806\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_9223372036854775807_int64_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775807%s9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int64_9223372036854775807_ssa(9223372036854775807); got != 0 {
+		fmt.Printf("mod_int64 9223372036854775807%s9223372036854775807 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := add_0_uint32_ssa(0); got != 0 {
+		fmt.Printf("add_uint32 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint32_0_ssa(0); got != 0 {
+		fmt.Printf("add_uint32 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_uint32_ssa(1); got != 1 {
+		fmt.Printf("add_uint32 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint32_0_ssa(1); got != 1 {
+		fmt.Printf("add_uint32 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_uint32_ssa(4294967295); got != 4294967295 {
+		fmt.Printf("add_uint32 0%s4294967295 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint32_0_ssa(4294967295); got != 4294967295 {
+		fmt.Printf("add_uint32 4294967295%s0 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint32_ssa(0); got != 1 {
+		fmt.Printf("add_uint32 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint32_1_ssa(0); got != 1 {
+		fmt.Printf("add_uint32 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint32_ssa(1); got != 2 {
+		fmt.Printf("add_uint32 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint32_1_ssa(1); got != 2 {
+		fmt.Printf("add_uint32 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("add_uint32 1%s4294967295 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint32_1_ssa(4294967295); got != 0 {
+		fmt.Printf("add_uint32 4294967295%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967295_uint32_ssa(0); got != 4294967295 {
+		fmt.Printf("add_uint32 4294967295%s0 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint32_4294967295_ssa(0); got != 4294967295 {
+		fmt.Printf("add_uint32 0%s4294967295 = %d, wanted 4294967295\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967295_uint32_ssa(1); got != 0 {
+		fmt.Printf("add_uint32 4294967295%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint32_4294967295_ssa(1); got != 0 {
+		fmt.Printf("add_uint32 1%s4294967295 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_4294967295_uint32_ssa(4294967295); got != 4294967294 {
+		fmt.Printf("add_uint32 4294967295%s4294967295 = %d, wanted 4294967294\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint32_4294967295_ssa(4294967295); got != 4294967294 {
+		fmt.Printf("add_uint32 4294967295%s4294967295 = %d, wanted 4294967294\n", `+`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint32_ssa(0); got != 0 {
+		fmt.Printf("sub_uint32 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint32_0_ssa(0); got != 0 {
+		fmt.Printf("sub_uint32 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint32_ssa(1); got != 4294967295 {
+		fmt.Printf("sub_uint32 0%s1 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint32_0_ssa(1); got != 1 {
+		fmt.Printf("sub_uint32 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint32_ssa(4294967295); got != 1 {
+		fmt.Printf("sub_uint32 0%s4294967295 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint32_0_ssa(4294967295); got != 4294967295 {
+		fmt.Printf("sub_uint32 4294967295%s0 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint32_ssa(0); got != 1 {
+		fmt.Printf("sub_uint32 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint32_1_ssa(0); got != 4294967295 {
+		fmt.Printf("sub_uint32 0%s1 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint32_ssa(1); got != 0 {
+		fmt.Printf("sub_uint32 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint32_1_ssa(1); got != 0 {
+		fmt.Printf("sub_uint32 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint32_ssa(4294967295); got != 2 {
+		fmt.Printf("sub_uint32 1%s4294967295 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint32_1_ssa(4294967295); got != 4294967294 {
+		fmt.Printf("sub_uint32 4294967295%s1 = %d, wanted 4294967294\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967295_uint32_ssa(0); got != 4294967295 {
+		fmt.Printf("sub_uint32 4294967295%s0 = %d, wanted 4294967295\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint32_4294967295_ssa(0); got != 1 {
+		fmt.Printf("sub_uint32 0%s4294967295 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967295_uint32_ssa(1); got != 4294967294 {
+		fmt.Printf("sub_uint32 4294967295%s1 = %d, wanted 4294967294\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint32_4294967295_ssa(1); got != 2 {
+		fmt.Printf("sub_uint32 1%s4294967295 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_4294967295_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("sub_uint32 4294967295%s4294967295 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint32_4294967295_ssa(4294967295); got != 0 {
+		fmt.Printf("sub_uint32 4294967295%s4294967295 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := div_0_uint32_ssa(1); got != 0 {
+		fmt.Printf("div_uint32 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("div_uint32 0%s4294967295 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint32_1_ssa(0); got != 0 {
+		fmt.Printf("div_uint32 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_uint32_ssa(1); got != 1 {
+		fmt.Printf("div_uint32 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint32_1_ssa(1); got != 1 {
+		fmt.Printf("div_uint32 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("div_uint32 1%s4294967295 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint32_1_ssa(4294967295); got != 4294967295 {
+		fmt.Printf("div_uint32 4294967295%s1 = %d, wanted 4294967295\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint32_4294967295_ssa(0); got != 0 {
+		fmt.Printf("div_uint32 0%s4294967295 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967295_uint32_ssa(1); got != 4294967295 {
+		fmt.Printf("div_uint32 4294967295%s1 = %d, wanted 4294967295\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint32_4294967295_ssa(1); got != 0 {
+		fmt.Printf("div_uint32 1%s4294967295 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_4294967295_uint32_ssa(4294967295); got != 1 {
+		fmt.Printf("div_uint32 4294967295%s4294967295 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint32_4294967295_ssa(4294967295); got != 1 {
+		fmt.Printf("div_uint32 4294967295%s4294967295 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint32_ssa(0); got != 0 {
+		fmt.Printf("mul_uint32 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint32_0_ssa(0); got != 0 {
+		fmt.Printf("mul_uint32 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint32_ssa(1); got != 0 {
+		fmt.Printf("mul_uint32 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint32_0_ssa(1); got != 0 {
+		fmt.Printf("mul_uint32 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("mul_uint32 0%s4294967295 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint32_0_ssa(4294967295); got != 0 {
+		fmt.Printf("mul_uint32 4294967295%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint32_ssa(0); got != 0 {
+		fmt.Printf("mul_uint32 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint32_1_ssa(0); got != 0 {
+		fmt.Printf("mul_uint32 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint32_ssa(1); got != 1 {
+		fmt.Printf("mul_uint32 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint32_1_ssa(1); got != 1 {
+		fmt.Printf("mul_uint32 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint32_ssa(4294967295); got != 4294967295 {
+		fmt.Printf("mul_uint32 1%s4294967295 = %d, wanted 4294967295\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint32_1_ssa(4294967295); got != 4294967295 {
+		fmt.Printf("mul_uint32 4294967295%s1 = %d, wanted 4294967295\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967295_uint32_ssa(0); got != 0 {
+		fmt.Printf("mul_uint32 4294967295%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint32_4294967295_ssa(0); got != 0 {
+		fmt.Printf("mul_uint32 0%s4294967295 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967295_uint32_ssa(1); got != 4294967295 {
+		fmt.Printf("mul_uint32 4294967295%s1 = %d, wanted 4294967295\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint32_4294967295_ssa(1); got != 4294967295 {
+		fmt.Printf("mul_uint32 1%s4294967295 = %d, wanted 4294967295\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_4294967295_uint32_ssa(4294967295); got != 1 {
+		fmt.Printf("mul_uint32 4294967295%s4294967295 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint32_4294967295_ssa(4294967295); got != 1 {
+		fmt.Printf("mul_uint32 4294967295%s4294967295 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint32_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint32 0%s0 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint32_0_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint32 0%s0 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint32_ssa(1); got != 0 {
+		fmt.Printf("lsh_uint32 0%s1 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint32_0_ssa(1); got != 1 {
+		fmt.Printf("lsh_uint32 1%s0 = %d, wanted 1\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("lsh_uint32 0%s4294967295 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint32_0_ssa(4294967295); got != 4294967295 {
+		fmt.Printf("lsh_uint32 4294967295%s0 = %d, wanted 4294967295\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint32_ssa(0); got != 1 {
+		fmt.Printf("lsh_uint32 1%s0 = %d, wanted 1\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint32_1_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint32 0%s1 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint32_ssa(1); got != 2 {
+		fmt.Printf("lsh_uint32 1%s1 = %d, wanted 2\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint32_1_ssa(1); got != 2 {
+		fmt.Printf("lsh_uint32 1%s1 = %d, wanted 2\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("lsh_uint32 1%s4294967295 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint32_1_ssa(4294967295); got != 4294967294 {
+		fmt.Printf("lsh_uint32 4294967295%s1 = %d, wanted 4294967294\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_4294967295_uint32_ssa(0); got != 4294967295 {
+		fmt.Printf("lsh_uint32 4294967295%s0 = %d, wanted 4294967295\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint32_4294967295_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint32 0%s4294967295 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_4294967295_uint32_ssa(1); got != 4294967294 {
+		fmt.Printf("lsh_uint32 4294967295%s1 = %d, wanted 4294967294\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint32_4294967295_ssa(1); got != 0 {
+		fmt.Printf("lsh_uint32 1%s4294967295 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_4294967295_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("lsh_uint32 4294967295%s4294967295 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint32_4294967295_ssa(4294967295); got != 0 {
+		fmt.Printf("lsh_uint32 4294967295%s4294967295 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint32_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint32 0%s0 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint32_0_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint32 0%s0 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint32_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint32 0%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint32_0_ssa(1); got != 1 {
+		fmt.Printf("rsh_uint32 1%s0 = %d, wanted 1\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("rsh_uint32 0%s4294967295 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint32_0_ssa(4294967295); got != 4294967295 {
+		fmt.Printf("rsh_uint32 4294967295%s0 = %d, wanted 4294967295\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint32_ssa(0); got != 1 {
+		fmt.Printf("rsh_uint32 1%s0 = %d, wanted 1\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint32_1_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint32 0%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint32_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint32 1%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint32_1_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint32 1%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("rsh_uint32 1%s4294967295 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint32_1_ssa(4294967295); got != 2147483647 {
+		fmt.Printf("rsh_uint32 4294967295%s1 = %d, wanted 2147483647\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_4294967295_uint32_ssa(0); got != 4294967295 {
+		fmt.Printf("rsh_uint32 4294967295%s0 = %d, wanted 4294967295\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint32_4294967295_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint32 0%s4294967295 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_4294967295_uint32_ssa(1); got != 2147483647 {
+		fmt.Printf("rsh_uint32 4294967295%s1 = %d, wanted 2147483647\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint32_4294967295_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint32 1%s4294967295 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_4294967295_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("rsh_uint32 4294967295%s4294967295 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint32_4294967295_ssa(4294967295); got != 0 {
+		fmt.Printf("rsh_uint32 4294967295%s4294967295 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := mod_0_uint32_ssa(1); got != 0 {
+		fmt.Printf("mod_uint32 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("mod_uint32 0%s4294967295 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint32_1_ssa(0); got != 0 {
+		fmt.Printf("mod_uint32 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_uint32_ssa(1); got != 0 {
+		fmt.Printf("mod_uint32 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint32_1_ssa(1); got != 0 {
+		fmt.Printf("mod_uint32 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_uint32_ssa(4294967295); got != 1 {
+		fmt.Printf("mod_uint32 1%s4294967295 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint32_1_ssa(4294967295); got != 0 {
+		fmt.Printf("mod_uint32 4294967295%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint32_4294967295_ssa(0); got != 0 {
+		fmt.Printf("mod_uint32 0%s4294967295 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967295_uint32_ssa(1); got != 0 {
+		fmt.Printf("mod_uint32 4294967295%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint32_4294967295_ssa(1); got != 1 {
+		fmt.Printf("mod_uint32 1%s4294967295 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_4294967295_uint32_ssa(4294967295); got != 0 {
+		fmt.Printf("mod_uint32 4294967295%s4294967295 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint32_4294967295_ssa(4294967295); got != 0 {
+		fmt.Printf("mod_uint32 4294967295%s4294967295 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483648_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("add_int32 -2147483648%s-2147483648 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483648_ssa(-2147483648); got != 0 {
+		fmt.Printf("add_int32 -2147483648%s-2147483648 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483648_int32_ssa(-2147483647); got != 1 {
+		fmt.Printf("add_int32 -2147483648%s-2147483647 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483648_ssa(-2147483647); got != 1 {
+		fmt.Printf("add_int32 -2147483647%s-2147483648 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483648_int32_ssa(-1); got != 2147483647 {
+		fmt.Printf("add_int32 -2147483648%s-1 = %d, wanted 2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483648_ssa(-1); got != 2147483647 {
+		fmt.Printf("add_int32 -1%s-2147483648 = %d, wanted 2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483648_int32_ssa(0); got != -2147483648 {
+		fmt.Printf("add_int32 -2147483648%s0 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483648_ssa(0); got != -2147483648 {
+		fmt.Printf("add_int32 0%s-2147483648 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483648_int32_ssa(1); got != -2147483647 {
+		fmt.Printf("add_int32 -2147483648%s1 = %d, wanted -2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483648_ssa(1); got != -2147483647 {
+		fmt.Printf("add_int32 1%s-2147483648 = %d, wanted -2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483648_int32_ssa(2147483647); got != -1 {
+		fmt.Printf("add_int32 -2147483648%s2147483647 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483648_ssa(2147483647); got != -1 {
+		fmt.Printf("add_int32 2147483647%s-2147483648 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483647_int32_ssa(-2147483648); got != 1 {
+		fmt.Printf("add_int32 -2147483647%s-2147483648 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483647_ssa(-2147483648); got != 1 {
+		fmt.Printf("add_int32 -2147483648%s-2147483647 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483647_int32_ssa(-2147483647); got != 2 {
+		fmt.Printf("add_int32 -2147483647%s-2147483647 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483647_ssa(-2147483647); got != 2 {
+		fmt.Printf("add_int32 -2147483647%s-2147483647 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483647_int32_ssa(-1); got != -2147483648 {
+		fmt.Printf("add_int32 -2147483647%s-1 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483647_ssa(-1); got != -2147483648 {
+		fmt.Printf("add_int32 -1%s-2147483647 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483647_int32_ssa(0); got != -2147483647 {
+		fmt.Printf("add_int32 -2147483647%s0 = %d, wanted -2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483647_ssa(0); got != -2147483647 {
+		fmt.Printf("add_int32 0%s-2147483647 = %d, wanted -2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483647_int32_ssa(1); got != -2147483646 {
+		fmt.Printf("add_int32 -2147483647%s1 = %d, wanted -2147483646\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483647_ssa(1); got != -2147483646 {
+		fmt.Printf("add_int32 1%s-2147483647 = %d, wanted -2147483646\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg2147483647_int32_ssa(2147483647); got != 0 {
+		fmt.Printf("add_int32 -2147483647%s2147483647 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg2147483647_ssa(2147483647); got != 0 {
+		fmt.Printf("add_int32 2147483647%s-2147483647 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int32_ssa(-2147483648); got != 2147483647 {
+		fmt.Printf("add_int32 -1%s-2147483648 = %d, wanted 2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg1_ssa(-2147483648); got != 2147483647 {
+		fmt.Printf("add_int32 -2147483648%s-1 = %d, wanted 2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int32_ssa(-2147483647); got != -2147483648 {
+		fmt.Printf("add_int32 -1%s-2147483647 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg1_ssa(-2147483647); got != -2147483648 {
+		fmt.Printf("add_int32 -2147483647%s-1 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int32_ssa(-1); got != -2 {
+		fmt.Printf("add_int32 -1%s-1 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg1_ssa(-1); got != -2 {
+		fmt.Printf("add_int32 -1%s-1 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int32_ssa(0); got != -1 {
+		fmt.Printf("add_int32 -1%s0 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg1_ssa(0); got != -1 {
+		fmt.Printf("add_int32 0%s-1 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int32_ssa(1); got != 0 {
+		fmt.Printf("add_int32 -1%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg1_ssa(1); got != 0 {
+		fmt.Printf("add_int32 1%s-1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int32_ssa(2147483647); got != 2147483646 {
+		fmt.Printf("add_int32 -1%s2147483647 = %d, wanted 2147483646\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_Neg1_ssa(2147483647); got != 2147483646 {
+		fmt.Printf("add_int32 2147483647%s-1 = %d, wanted 2147483646\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int32_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("add_int32 0%s-2147483648 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_0_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("add_int32 -2147483648%s0 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int32_ssa(-2147483647); got != -2147483647 {
+		fmt.Printf("add_int32 0%s-2147483647 = %d, wanted -2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_0_ssa(-2147483647); got != -2147483647 {
+		fmt.Printf("add_int32 -2147483647%s0 = %d, wanted -2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int32_ssa(-1); got != -1 {
+		fmt.Printf("add_int32 0%s-1 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_0_ssa(-1); got != -1 {
+		fmt.Printf("add_int32 -1%s0 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int32_ssa(0); got != 0 {
+		fmt.Printf("add_int32 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_0_ssa(0); got != 0 {
+		fmt.Printf("add_int32 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int32_ssa(1); got != 1 {
+		fmt.Printf("add_int32 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_0_ssa(1); got != 1 {
+		fmt.Printf("add_int32 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int32_ssa(2147483647); got != 2147483647 {
+		fmt.Printf("add_int32 0%s2147483647 = %d, wanted 2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_0_ssa(2147483647); got != 2147483647 {
+		fmt.Printf("add_int32 2147483647%s0 = %d, wanted 2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int32_ssa(-2147483648); got != -2147483647 {
+		fmt.Printf("add_int32 1%s-2147483648 = %d, wanted -2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_1_ssa(-2147483648); got != -2147483647 {
+		fmt.Printf("add_int32 -2147483648%s1 = %d, wanted -2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int32_ssa(-2147483647); got != -2147483646 {
+		fmt.Printf("add_int32 1%s-2147483647 = %d, wanted -2147483646\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_1_ssa(-2147483647); got != -2147483646 {
+		fmt.Printf("add_int32 -2147483647%s1 = %d, wanted -2147483646\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int32_ssa(-1); got != 0 {
+		fmt.Printf("add_int32 1%s-1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_1_ssa(-1); got != 0 {
+		fmt.Printf("add_int32 -1%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int32_ssa(0); got != 1 {
+		fmt.Printf("add_int32 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_1_ssa(0); got != 1 {
+		fmt.Printf("add_int32 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int32_ssa(1); got != 2 {
+		fmt.Printf("add_int32 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_1_ssa(1); got != 2 {
+		fmt.Printf("add_int32 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int32_ssa(2147483647); got != -2147483648 {
+		fmt.Printf("add_int32 1%s2147483647 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_1_ssa(2147483647); got != -2147483648 {
+		fmt.Printf("add_int32 2147483647%s1 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_2147483647_int32_ssa(-2147483648); got != -1 {
+		fmt.Printf("add_int32 2147483647%s-2147483648 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_2147483647_ssa(-2147483648); got != -1 {
+		fmt.Printf("add_int32 -2147483648%s2147483647 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_2147483647_int32_ssa(-2147483647); got != 0 {
+		fmt.Printf("add_int32 2147483647%s-2147483647 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_2147483647_ssa(-2147483647); got != 0 {
+		fmt.Printf("add_int32 -2147483647%s2147483647 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_2147483647_int32_ssa(-1); got != 2147483646 {
+		fmt.Printf("add_int32 2147483647%s-1 = %d, wanted 2147483646\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_2147483647_ssa(-1); got != 2147483646 {
+		fmt.Printf("add_int32 -1%s2147483647 = %d, wanted 2147483646\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_2147483647_int32_ssa(0); got != 2147483647 {
+		fmt.Printf("add_int32 2147483647%s0 = %d, wanted 2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_2147483647_ssa(0); got != 2147483647 {
+		fmt.Printf("add_int32 0%s2147483647 = %d, wanted 2147483647\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_2147483647_int32_ssa(1); got != -2147483648 {
+		fmt.Printf("add_int32 2147483647%s1 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_2147483647_ssa(1); got != -2147483648 {
+		fmt.Printf("add_int32 1%s2147483647 = %d, wanted -2147483648\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_2147483647_int32_ssa(2147483647); got != -2 {
+		fmt.Printf("add_int32 2147483647%s2147483647 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int32_2147483647_ssa(2147483647); got != -2 {
+		fmt.Printf("add_int32 2147483647%s2147483647 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483648_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("sub_int32 -2147483648%s-2147483648 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483648_ssa(-2147483648); got != 0 {
+		fmt.Printf("sub_int32 -2147483648%s-2147483648 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483648_int32_ssa(-2147483647); got != -1 {
+		fmt.Printf("sub_int32 -2147483648%s-2147483647 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483648_ssa(-2147483647); got != 1 {
+		fmt.Printf("sub_int32 -2147483647%s-2147483648 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483648_int32_ssa(-1); got != -2147483647 {
+		fmt.Printf("sub_int32 -2147483648%s-1 = %d, wanted -2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483648_ssa(-1); got != 2147483647 {
+		fmt.Printf("sub_int32 -1%s-2147483648 = %d, wanted 2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483648_int32_ssa(0); got != -2147483648 {
+		fmt.Printf("sub_int32 -2147483648%s0 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483648_ssa(0); got != -2147483648 {
+		fmt.Printf("sub_int32 0%s-2147483648 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483648_int32_ssa(1); got != 2147483647 {
+		fmt.Printf("sub_int32 -2147483648%s1 = %d, wanted 2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483648_ssa(1); got != -2147483647 {
+		fmt.Printf("sub_int32 1%s-2147483648 = %d, wanted -2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483648_int32_ssa(2147483647); got != 1 {
+		fmt.Printf("sub_int32 -2147483648%s2147483647 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483648_ssa(2147483647); got != -1 {
+		fmt.Printf("sub_int32 2147483647%s-2147483648 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483647_int32_ssa(-2147483648); got != 1 {
+		fmt.Printf("sub_int32 -2147483647%s-2147483648 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483647_ssa(-2147483648); got != -1 {
+		fmt.Printf("sub_int32 -2147483648%s-2147483647 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483647_int32_ssa(-2147483647); got != 0 {
+		fmt.Printf("sub_int32 -2147483647%s-2147483647 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483647_ssa(-2147483647); got != 0 {
+		fmt.Printf("sub_int32 -2147483647%s-2147483647 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483647_int32_ssa(-1); got != -2147483646 {
+		fmt.Printf("sub_int32 -2147483647%s-1 = %d, wanted -2147483646\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483647_ssa(-1); got != 2147483646 {
+		fmt.Printf("sub_int32 -1%s-2147483647 = %d, wanted 2147483646\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483647_int32_ssa(0); got != -2147483647 {
+		fmt.Printf("sub_int32 -2147483647%s0 = %d, wanted -2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483647_ssa(0); got != 2147483647 {
+		fmt.Printf("sub_int32 0%s-2147483647 = %d, wanted 2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483647_int32_ssa(1); got != -2147483648 {
+		fmt.Printf("sub_int32 -2147483647%s1 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483647_ssa(1); got != -2147483648 {
+		fmt.Printf("sub_int32 1%s-2147483647 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg2147483647_int32_ssa(2147483647); got != 2 {
+		fmt.Printf("sub_int32 -2147483647%s2147483647 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg2147483647_ssa(2147483647); got != -2 {
+		fmt.Printf("sub_int32 2147483647%s-2147483647 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int32_ssa(-2147483648); got != 2147483647 {
+		fmt.Printf("sub_int32 -1%s-2147483648 = %d, wanted 2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg1_ssa(-2147483648); got != -2147483647 {
+		fmt.Printf("sub_int32 -2147483648%s-1 = %d, wanted -2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int32_ssa(-2147483647); got != 2147483646 {
+		fmt.Printf("sub_int32 -1%s-2147483647 = %d, wanted 2147483646\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg1_ssa(-2147483647); got != -2147483646 {
+		fmt.Printf("sub_int32 -2147483647%s-1 = %d, wanted -2147483646\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int32_ssa(-1); got != 0 {
+		fmt.Printf("sub_int32 -1%s-1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg1_ssa(-1); got != 0 {
+		fmt.Printf("sub_int32 -1%s-1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int32_ssa(0); got != -1 {
+		fmt.Printf("sub_int32 -1%s0 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg1_ssa(0); got != 1 {
+		fmt.Printf("sub_int32 0%s-1 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int32_ssa(1); got != -2 {
+		fmt.Printf("sub_int32 -1%s1 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg1_ssa(1); got != 2 {
+		fmt.Printf("sub_int32 1%s-1 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int32_ssa(2147483647); got != -2147483648 {
+		fmt.Printf("sub_int32 -1%s2147483647 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_Neg1_ssa(2147483647); got != -2147483648 {
+		fmt.Printf("sub_int32 2147483647%s-1 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int32_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("sub_int32 0%s-2147483648 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_0_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("sub_int32 -2147483648%s0 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int32_ssa(-2147483647); got != 2147483647 {
+		fmt.Printf("sub_int32 0%s-2147483647 = %d, wanted 2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_0_ssa(-2147483647); got != -2147483647 {
+		fmt.Printf("sub_int32 -2147483647%s0 = %d, wanted -2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int32_ssa(-1); got != 1 {
+		fmt.Printf("sub_int32 0%s-1 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_0_ssa(-1); got != -1 {
+		fmt.Printf("sub_int32 -1%s0 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int32_ssa(0); got != 0 {
+		fmt.Printf("sub_int32 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_0_ssa(0); got != 0 {
+		fmt.Printf("sub_int32 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int32_ssa(1); got != -1 {
+		fmt.Printf("sub_int32 0%s1 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_0_ssa(1); got != 1 {
+		fmt.Printf("sub_int32 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int32_ssa(2147483647); got != -2147483647 {
+		fmt.Printf("sub_int32 0%s2147483647 = %d, wanted -2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_0_ssa(2147483647); got != 2147483647 {
+		fmt.Printf("sub_int32 2147483647%s0 = %d, wanted 2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int32_ssa(-2147483648); got != -2147483647 {
+		fmt.Printf("sub_int32 1%s-2147483648 = %d, wanted -2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_1_ssa(-2147483648); got != 2147483647 {
+		fmt.Printf("sub_int32 -2147483648%s1 = %d, wanted 2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int32_ssa(-2147483647); got != -2147483648 {
+		fmt.Printf("sub_int32 1%s-2147483647 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_1_ssa(-2147483647); got != -2147483648 {
+		fmt.Printf("sub_int32 -2147483647%s1 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int32_ssa(-1); got != 2 {
+		fmt.Printf("sub_int32 1%s-1 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_1_ssa(-1); got != -2 {
+		fmt.Printf("sub_int32 -1%s1 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int32_ssa(0); got != 1 {
+		fmt.Printf("sub_int32 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_1_ssa(0); got != -1 {
+		fmt.Printf("sub_int32 0%s1 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int32_ssa(1); got != 0 {
+		fmt.Printf("sub_int32 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_1_ssa(1); got != 0 {
+		fmt.Printf("sub_int32 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int32_ssa(2147483647); got != -2147483646 {
+		fmt.Printf("sub_int32 1%s2147483647 = %d, wanted -2147483646\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_1_ssa(2147483647); got != 2147483646 {
+		fmt.Printf("sub_int32 2147483647%s1 = %d, wanted 2147483646\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_2147483647_int32_ssa(-2147483648); got != -1 {
+		fmt.Printf("sub_int32 2147483647%s-2147483648 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_2147483647_ssa(-2147483648); got != 1 {
+		fmt.Printf("sub_int32 -2147483648%s2147483647 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_2147483647_int32_ssa(-2147483647); got != -2 {
+		fmt.Printf("sub_int32 2147483647%s-2147483647 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_2147483647_ssa(-2147483647); got != 2 {
+		fmt.Printf("sub_int32 -2147483647%s2147483647 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_2147483647_int32_ssa(-1); got != -2147483648 {
+		fmt.Printf("sub_int32 2147483647%s-1 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_2147483647_ssa(-1); got != -2147483648 {
+		fmt.Printf("sub_int32 -1%s2147483647 = %d, wanted -2147483648\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_2147483647_int32_ssa(0); got != 2147483647 {
+		fmt.Printf("sub_int32 2147483647%s0 = %d, wanted 2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_2147483647_ssa(0); got != -2147483647 {
+		fmt.Printf("sub_int32 0%s2147483647 = %d, wanted -2147483647\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_2147483647_int32_ssa(1); got != 2147483646 {
+		fmt.Printf("sub_int32 2147483647%s1 = %d, wanted 2147483646\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_2147483647_ssa(1); got != -2147483646 {
+		fmt.Printf("sub_int32 1%s2147483647 = %d, wanted -2147483646\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_2147483647_int32_ssa(2147483647); got != 0 {
+		fmt.Printf("sub_int32 2147483647%s2147483647 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int32_2147483647_ssa(2147483647); got != 0 {
+		fmt.Printf("sub_int32 2147483647%s2147483647 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483648_int32_ssa(-2147483648); got != 1 {
+		fmt.Printf("div_int32 -2147483648%s-2147483648 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483648_ssa(-2147483648); got != 1 {
+		fmt.Printf("div_int32 -2147483648%s-2147483648 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483648_int32_ssa(-2147483647); got != 1 {
+		fmt.Printf("div_int32 -2147483648%s-2147483647 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483648_ssa(-2147483647); got != 0 {
+		fmt.Printf("div_int32 -2147483647%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483648_int32_ssa(-1); got != -2147483648 {
+		fmt.Printf("div_int32 -2147483648%s-1 = %d, wanted -2147483648\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483648_ssa(-1); got != 0 {
+		fmt.Printf("div_int32 -1%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483648_ssa(0); got != 0 {
+		fmt.Printf("div_int32 0%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483648_int32_ssa(1); got != -2147483648 {
+		fmt.Printf("div_int32 -2147483648%s1 = %d, wanted -2147483648\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483648_ssa(1); got != 0 {
+		fmt.Printf("div_int32 1%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483648_int32_ssa(2147483647); got != -1 {
+		fmt.Printf("div_int32 -2147483648%s2147483647 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483648_ssa(2147483647); got != 0 {
+		fmt.Printf("div_int32 2147483647%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483647_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("div_int32 -2147483647%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483647_ssa(-2147483648); got != 1 {
+		fmt.Printf("div_int32 -2147483648%s-2147483647 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483647_int32_ssa(-2147483647); got != 1 {
+		fmt.Printf("div_int32 -2147483647%s-2147483647 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483647_ssa(-2147483647); got != 1 {
+		fmt.Printf("div_int32 -2147483647%s-2147483647 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483647_int32_ssa(-1); got != 2147483647 {
+		fmt.Printf("div_int32 -2147483647%s-1 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483647_ssa(-1); got != 0 {
+		fmt.Printf("div_int32 -1%s-2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483647_ssa(0); got != 0 {
+		fmt.Printf("div_int32 0%s-2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483647_int32_ssa(1); got != -2147483647 {
+		fmt.Printf("div_int32 -2147483647%s1 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483647_ssa(1); got != 0 {
+		fmt.Printf("div_int32 1%s-2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg2147483647_int32_ssa(2147483647); got != -1 {
+		fmt.Printf("div_int32 -2147483647%s2147483647 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg2147483647_ssa(2147483647); got != -1 {
+		fmt.Printf("div_int32 2147483647%s-2147483647 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("div_int32 -1%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg1_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("div_int32 -2147483648%s-1 = %d, wanted -2147483648\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int32_ssa(-2147483647); got != 0 {
+		fmt.Printf("div_int32 -1%s-2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg1_ssa(-2147483647); got != 2147483647 {
+		fmt.Printf("div_int32 -2147483647%s-1 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int32_ssa(-1); got != 1 {
+		fmt.Printf("div_int32 -1%s-1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg1_ssa(-1); got != 1 {
+		fmt.Printf("div_int32 -1%s-1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg1_ssa(0); got != 0 {
+		fmt.Printf("div_int32 0%s-1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int32_ssa(1); got != -1 {
+		fmt.Printf("div_int32 -1%s1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg1_ssa(1); got != -1 {
+		fmt.Printf("div_int32 1%s-1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int32_ssa(2147483647); got != 0 {
+		fmt.Printf("div_int32 -1%s2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_Neg1_ssa(2147483647); got != -2147483647 {
+		fmt.Printf("div_int32 2147483647%s-1 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("div_int32 0%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int32_ssa(-2147483647); got != 0 {
+		fmt.Printf("div_int32 0%s-2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int32_ssa(-1); got != 0 {
+		fmt.Printf("div_int32 0%s-1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int32_ssa(1); got != 0 {
+		fmt.Printf("div_int32 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int32_ssa(2147483647); got != 0 {
+		fmt.Printf("div_int32 0%s2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("div_int32 1%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_1_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("div_int32 -2147483648%s1 = %d, wanted -2147483648\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int32_ssa(-2147483647); got != 0 {
+		fmt.Printf("div_int32 1%s-2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_1_ssa(-2147483647); got != -2147483647 {
+		fmt.Printf("div_int32 -2147483647%s1 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int32_ssa(-1); got != -1 {
+		fmt.Printf("div_int32 1%s-1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_1_ssa(-1); got != -1 {
+		fmt.Printf("div_int32 -1%s1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_1_ssa(0); got != 0 {
+		fmt.Printf("div_int32 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int32_ssa(1); got != 1 {
+		fmt.Printf("div_int32 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_1_ssa(1); got != 1 {
+		fmt.Printf("div_int32 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int32_ssa(2147483647); got != 0 {
+		fmt.Printf("div_int32 1%s2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_1_ssa(2147483647); got != 2147483647 {
+		fmt.Printf("div_int32 2147483647%s1 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_2147483647_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("div_int32 2147483647%s-2147483648 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_2147483647_ssa(-2147483648); got != -1 {
+		fmt.Printf("div_int32 -2147483648%s2147483647 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_2147483647_int32_ssa(-2147483647); got != -1 {
+		fmt.Printf("div_int32 2147483647%s-2147483647 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_2147483647_ssa(-2147483647); got != -1 {
+		fmt.Printf("div_int32 -2147483647%s2147483647 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_2147483647_int32_ssa(-1); got != -2147483647 {
+		fmt.Printf("div_int32 2147483647%s-1 = %d, wanted -2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_2147483647_ssa(-1); got != 0 {
+		fmt.Printf("div_int32 -1%s2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_2147483647_ssa(0); got != 0 {
+		fmt.Printf("div_int32 0%s2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_2147483647_int32_ssa(1); got != 2147483647 {
+		fmt.Printf("div_int32 2147483647%s1 = %d, wanted 2147483647\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_2147483647_ssa(1); got != 0 {
+		fmt.Printf("div_int32 1%s2147483647 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_2147483647_int32_ssa(2147483647); got != 1 {
+		fmt.Printf("div_int32 2147483647%s2147483647 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int32_2147483647_ssa(2147483647); got != 1 {
+		fmt.Printf("div_int32 2147483647%s2147483647 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483648_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("mul_int32 -2147483648%s-2147483648 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483648_ssa(-2147483648); got != 0 {
+		fmt.Printf("mul_int32 -2147483648%s-2147483648 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483648_int32_ssa(-2147483647); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483648%s-2147483647 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483648_ssa(-2147483647); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483647%s-2147483648 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483648_int32_ssa(-1); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483648%s-1 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483648_ssa(-1); got != -2147483648 {
+		fmt.Printf("mul_int32 -1%s-2147483648 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483648_int32_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 -2147483648%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483648_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 0%s-2147483648 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483648_int32_ssa(1); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483648%s1 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483648_ssa(1); got != -2147483648 {
+		fmt.Printf("mul_int32 1%s-2147483648 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483648_int32_ssa(2147483647); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483648%s2147483647 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483648_ssa(2147483647); got != -2147483648 {
+		fmt.Printf("mul_int32 2147483647%s-2147483648 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483647_int32_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483647%s-2147483648 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483647_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483648%s-2147483647 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483647_int32_ssa(-2147483647); got != 1 {
+		fmt.Printf("mul_int32 -2147483647%s-2147483647 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483647_ssa(-2147483647); got != 1 {
+		fmt.Printf("mul_int32 -2147483647%s-2147483647 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483647_int32_ssa(-1); got != 2147483647 {
+		fmt.Printf("mul_int32 -2147483647%s-1 = %d, wanted 2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483647_ssa(-1); got != 2147483647 {
+		fmt.Printf("mul_int32 -1%s-2147483647 = %d, wanted 2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483647_int32_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 -2147483647%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483647_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 0%s-2147483647 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483647_int32_ssa(1); got != -2147483647 {
+		fmt.Printf("mul_int32 -2147483647%s1 = %d, wanted -2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483647_ssa(1); got != -2147483647 {
+		fmt.Printf("mul_int32 1%s-2147483647 = %d, wanted -2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg2147483647_int32_ssa(2147483647); got != -1 {
+		fmt.Printf("mul_int32 -2147483647%s2147483647 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg2147483647_ssa(2147483647); got != -1 {
+		fmt.Printf("mul_int32 2147483647%s-2147483647 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int32_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("mul_int32 -1%s-2147483648 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg1_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483648%s-1 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int32_ssa(-2147483647); got != 2147483647 {
+		fmt.Printf("mul_int32 -1%s-2147483647 = %d, wanted 2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg1_ssa(-2147483647); got != 2147483647 {
+		fmt.Printf("mul_int32 -2147483647%s-1 = %d, wanted 2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int32_ssa(-1); got != 1 {
+		fmt.Printf("mul_int32 -1%s-1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg1_ssa(-1); got != 1 {
+		fmt.Printf("mul_int32 -1%s-1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int32_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 -1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg1_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 0%s-1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int32_ssa(1); got != -1 {
+		fmt.Printf("mul_int32 -1%s1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg1_ssa(1); got != -1 {
+		fmt.Printf("mul_int32 1%s-1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int32_ssa(2147483647); got != -2147483647 {
+		fmt.Printf("mul_int32 -1%s2147483647 = %d, wanted -2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_Neg1_ssa(2147483647); got != -2147483647 {
+		fmt.Printf("mul_int32 2147483647%s-1 = %d, wanted -2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("mul_int32 0%s-2147483648 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_0_ssa(-2147483648); got != 0 {
+		fmt.Printf("mul_int32 -2147483648%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int32_ssa(-2147483647); got != 0 {
+		fmt.Printf("mul_int32 0%s-2147483647 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_0_ssa(-2147483647); got != 0 {
+		fmt.Printf("mul_int32 -2147483647%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int32_ssa(-1); got != 0 {
+		fmt.Printf("mul_int32 0%s-1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_0_ssa(-1); got != 0 {
+		fmt.Printf("mul_int32 -1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int32_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_0_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int32_ssa(1); got != 0 {
+		fmt.Printf("mul_int32 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_0_ssa(1); got != 0 {
+		fmt.Printf("mul_int32 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int32_ssa(2147483647); got != 0 {
+		fmt.Printf("mul_int32 0%s2147483647 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_0_ssa(2147483647); got != 0 {
+		fmt.Printf("mul_int32 2147483647%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int32_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("mul_int32 1%s-2147483648 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_1_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483648%s1 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int32_ssa(-2147483647); got != -2147483647 {
+		fmt.Printf("mul_int32 1%s-2147483647 = %d, wanted -2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_1_ssa(-2147483647); got != -2147483647 {
+		fmt.Printf("mul_int32 -2147483647%s1 = %d, wanted -2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int32_ssa(-1); got != -1 {
+		fmt.Printf("mul_int32 1%s-1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_1_ssa(-1); got != -1 {
+		fmt.Printf("mul_int32 -1%s1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int32_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_1_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int32_ssa(1); got != 1 {
+		fmt.Printf("mul_int32 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_1_ssa(1); got != 1 {
+		fmt.Printf("mul_int32 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int32_ssa(2147483647); got != 2147483647 {
+		fmt.Printf("mul_int32 1%s2147483647 = %d, wanted 2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_1_ssa(2147483647); got != 2147483647 {
+		fmt.Printf("mul_int32 2147483647%s1 = %d, wanted 2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_2147483647_int32_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("mul_int32 2147483647%s-2147483648 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_2147483647_ssa(-2147483648); got != -2147483648 {
+		fmt.Printf("mul_int32 -2147483648%s2147483647 = %d, wanted -2147483648\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_2147483647_int32_ssa(-2147483647); got != -1 {
+		fmt.Printf("mul_int32 2147483647%s-2147483647 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_2147483647_ssa(-2147483647); got != -1 {
+		fmt.Printf("mul_int32 -2147483647%s2147483647 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_2147483647_int32_ssa(-1); got != -2147483647 {
+		fmt.Printf("mul_int32 2147483647%s-1 = %d, wanted -2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_2147483647_ssa(-1); got != -2147483647 {
+		fmt.Printf("mul_int32 -1%s2147483647 = %d, wanted -2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_2147483647_int32_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 2147483647%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_2147483647_ssa(0); got != 0 {
+		fmt.Printf("mul_int32 0%s2147483647 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_2147483647_int32_ssa(1); got != 2147483647 {
+		fmt.Printf("mul_int32 2147483647%s1 = %d, wanted 2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_2147483647_ssa(1); got != 2147483647 {
+		fmt.Printf("mul_int32 1%s2147483647 = %d, wanted 2147483647\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_2147483647_int32_ssa(2147483647); got != 1 {
+		fmt.Printf("mul_int32 2147483647%s2147483647 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int32_2147483647_ssa(2147483647); got != 1 {
+		fmt.Printf("mul_int32 2147483647%s2147483647 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483648_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("mod_int32 -2147483648%s-2147483648 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483648_ssa(-2147483648); got != 0 {
+		fmt.Printf("mod_int32 -2147483648%s-2147483648 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483648_int32_ssa(-2147483647); got != -1 {
+		fmt.Printf("mod_int32 -2147483648%s-2147483647 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483648_ssa(-2147483647); got != -2147483647 {
+		fmt.Printf("mod_int32 -2147483647%s-2147483648 = %d, wanted -2147483647\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483648_int32_ssa(-1); got != 0 {
+		fmt.Printf("mod_int32 -2147483648%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483648_ssa(-1); got != -1 {
+		fmt.Printf("mod_int32 -1%s-2147483648 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483648_ssa(0); got != 0 {
+		fmt.Printf("mod_int32 0%s-2147483648 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483648_int32_ssa(1); got != 0 {
+		fmt.Printf("mod_int32 -2147483648%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483648_ssa(1); got != 1 {
+		fmt.Printf("mod_int32 1%s-2147483648 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483648_int32_ssa(2147483647); got != -1 {
+		fmt.Printf("mod_int32 -2147483648%s2147483647 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483648_ssa(2147483647); got != 2147483647 {
+		fmt.Printf("mod_int32 2147483647%s-2147483648 = %d, wanted 2147483647\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483647_int32_ssa(-2147483648); got != -2147483647 {
+		fmt.Printf("mod_int32 -2147483647%s-2147483648 = %d, wanted -2147483647\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483647_ssa(-2147483648); got != -1 {
+		fmt.Printf("mod_int32 -2147483648%s-2147483647 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483647_int32_ssa(-2147483647); got != 0 {
+		fmt.Printf("mod_int32 -2147483647%s-2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483647_ssa(-2147483647); got != 0 {
+		fmt.Printf("mod_int32 -2147483647%s-2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483647_int32_ssa(-1); got != 0 {
+		fmt.Printf("mod_int32 -2147483647%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483647_ssa(-1); got != -1 {
+		fmt.Printf("mod_int32 -1%s-2147483647 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483647_ssa(0); got != 0 {
+		fmt.Printf("mod_int32 0%s-2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483647_int32_ssa(1); got != 0 {
+		fmt.Printf("mod_int32 -2147483647%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483647_ssa(1); got != 1 {
+		fmt.Printf("mod_int32 1%s-2147483647 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg2147483647_int32_ssa(2147483647); got != 0 {
+		fmt.Printf("mod_int32 -2147483647%s2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg2147483647_ssa(2147483647); got != 0 {
+		fmt.Printf("mod_int32 2147483647%s-2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int32_ssa(-2147483648); got != -1 {
+		fmt.Printf("mod_int32 -1%s-2147483648 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg1_ssa(-2147483648); got != 0 {
+		fmt.Printf("mod_int32 -2147483648%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int32_ssa(-2147483647); got != -1 {
+		fmt.Printf("mod_int32 -1%s-2147483647 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg1_ssa(-2147483647); got != 0 {
+		fmt.Printf("mod_int32 -2147483647%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int32_ssa(-1); got != 0 {
+		fmt.Printf("mod_int32 -1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg1_ssa(-1); got != 0 {
+		fmt.Printf("mod_int32 -1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg1_ssa(0); got != 0 {
+		fmt.Printf("mod_int32 0%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int32_ssa(1); got != 0 {
+		fmt.Printf("mod_int32 -1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg1_ssa(1); got != 0 {
+		fmt.Printf("mod_int32 1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int32_ssa(2147483647); got != -1 {
+		fmt.Printf("mod_int32 -1%s2147483647 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_Neg1_ssa(2147483647); got != 0 {
+		fmt.Printf("mod_int32 2147483647%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int32_ssa(-2147483648); got != 0 {
+		fmt.Printf("mod_int32 0%s-2147483648 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int32_ssa(-2147483647); got != 0 {
+		fmt.Printf("mod_int32 0%s-2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int32_ssa(-1); got != 0 {
+		fmt.Printf("mod_int32 0%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int32_ssa(1); got != 0 {
+		fmt.Printf("mod_int32 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int32_ssa(2147483647); got != 0 {
+		fmt.Printf("mod_int32 0%s2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int32_ssa(-2147483648); got != 1 {
+		fmt.Printf("mod_int32 1%s-2147483648 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_1_ssa(-2147483648); got != 0 {
+		fmt.Printf("mod_int32 -2147483648%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int32_ssa(-2147483647); got != 1 {
+		fmt.Printf("mod_int32 1%s-2147483647 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_1_ssa(-2147483647); got != 0 {
+		fmt.Printf("mod_int32 -2147483647%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int32_ssa(-1); got != 0 {
+		fmt.Printf("mod_int32 1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_1_ssa(-1); got != 0 {
+		fmt.Printf("mod_int32 -1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_1_ssa(0); got != 0 {
+		fmt.Printf("mod_int32 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int32_ssa(1); got != 0 {
+		fmt.Printf("mod_int32 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_1_ssa(1); got != 0 {
+		fmt.Printf("mod_int32 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int32_ssa(2147483647); got != 1 {
+		fmt.Printf("mod_int32 1%s2147483647 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_1_ssa(2147483647); got != 0 {
+		fmt.Printf("mod_int32 2147483647%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_2147483647_int32_ssa(-2147483648); got != 2147483647 {
+		fmt.Printf("mod_int32 2147483647%s-2147483648 = %d, wanted 2147483647\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_2147483647_ssa(-2147483648); got != -1 {
+		fmt.Printf("mod_int32 -2147483648%s2147483647 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_2147483647_int32_ssa(-2147483647); got != 0 {
+		fmt.Printf("mod_int32 2147483647%s-2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_2147483647_ssa(-2147483647); got != 0 {
+		fmt.Printf("mod_int32 -2147483647%s2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_2147483647_int32_ssa(-1); got != 0 {
+		fmt.Printf("mod_int32 2147483647%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_2147483647_ssa(-1); got != -1 {
+		fmt.Printf("mod_int32 -1%s2147483647 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_2147483647_ssa(0); got != 0 {
+		fmt.Printf("mod_int32 0%s2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_2147483647_int32_ssa(1); got != 0 {
+		fmt.Printf("mod_int32 2147483647%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_2147483647_ssa(1); got != 1 {
+		fmt.Printf("mod_int32 1%s2147483647 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_2147483647_int32_ssa(2147483647); got != 0 {
+		fmt.Printf("mod_int32 2147483647%s2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int32_2147483647_ssa(2147483647); got != 0 {
+		fmt.Printf("mod_int32 2147483647%s2147483647 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := add_0_uint16_ssa(0); got != 0 {
+		fmt.Printf("add_uint16 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint16_0_ssa(0); got != 0 {
+		fmt.Printf("add_uint16 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_uint16_ssa(1); got != 1 {
+		fmt.Printf("add_uint16 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint16_0_ssa(1); got != 1 {
+		fmt.Printf("add_uint16 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_uint16_ssa(65535); got != 65535 {
+		fmt.Printf("add_uint16 0%s65535 = %d, wanted 65535\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint16_0_ssa(65535); got != 65535 {
+		fmt.Printf("add_uint16 65535%s0 = %d, wanted 65535\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint16_ssa(0); got != 1 {
+		fmt.Printf("add_uint16 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint16_1_ssa(0); got != 1 {
+		fmt.Printf("add_uint16 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint16_ssa(1); got != 2 {
+		fmt.Printf("add_uint16 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint16_1_ssa(1); got != 2 {
+		fmt.Printf("add_uint16 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint16_ssa(65535); got != 0 {
+		fmt.Printf("add_uint16 1%s65535 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint16_1_ssa(65535); got != 0 {
+		fmt.Printf("add_uint16 65535%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_65535_uint16_ssa(0); got != 65535 {
+		fmt.Printf("add_uint16 65535%s0 = %d, wanted 65535\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint16_65535_ssa(0); got != 65535 {
+		fmt.Printf("add_uint16 0%s65535 = %d, wanted 65535\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_65535_uint16_ssa(1); got != 0 {
+		fmt.Printf("add_uint16 65535%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint16_65535_ssa(1); got != 0 {
+		fmt.Printf("add_uint16 1%s65535 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_65535_uint16_ssa(65535); got != 65534 {
+		fmt.Printf("add_uint16 65535%s65535 = %d, wanted 65534\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint16_65535_ssa(65535); got != 65534 {
+		fmt.Printf("add_uint16 65535%s65535 = %d, wanted 65534\n", `+`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint16_ssa(0); got != 0 {
+		fmt.Printf("sub_uint16 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint16_0_ssa(0); got != 0 {
+		fmt.Printf("sub_uint16 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint16_ssa(1); got != 65535 {
+		fmt.Printf("sub_uint16 0%s1 = %d, wanted 65535\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint16_0_ssa(1); got != 1 {
+		fmt.Printf("sub_uint16 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint16_ssa(65535); got != 1 {
+		fmt.Printf("sub_uint16 0%s65535 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint16_0_ssa(65535); got != 65535 {
+		fmt.Printf("sub_uint16 65535%s0 = %d, wanted 65535\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint16_ssa(0); got != 1 {
+		fmt.Printf("sub_uint16 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint16_1_ssa(0); got != 65535 {
+		fmt.Printf("sub_uint16 0%s1 = %d, wanted 65535\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint16_ssa(1); got != 0 {
+		fmt.Printf("sub_uint16 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint16_1_ssa(1); got != 0 {
+		fmt.Printf("sub_uint16 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint16_ssa(65535); got != 2 {
+		fmt.Printf("sub_uint16 1%s65535 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint16_1_ssa(65535); got != 65534 {
+		fmt.Printf("sub_uint16 65535%s1 = %d, wanted 65534\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_65535_uint16_ssa(0); got != 65535 {
+		fmt.Printf("sub_uint16 65535%s0 = %d, wanted 65535\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint16_65535_ssa(0); got != 1 {
+		fmt.Printf("sub_uint16 0%s65535 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_65535_uint16_ssa(1); got != 65534 {
+		fmt.Printf("sub_uint16 65535%s1 = %d, wanted 65534\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint16_65535_ssa(1); got != 2 {
+		fmt.Printf("sub_uint16 1%s65535 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_65535_uint16_ssa(65535); got != 0 {
+		fmt.Printf("sub_uint16 65535%s65535 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint16_65535_ssa(65535); got != 0 {
+		fmt.Printf("sub_uint16 65535%s65535 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := div_0_uint16_ssa(1); got != 0 {
+		fmt.Printf("div_uint16 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_uint16_ssa(65535); got != 0 {
+		fmt.Printf("div_uint16 0%s65535 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint16_1_ssa(0); got != 0 {
+		fmt.Printf("div_uint16 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_uint16_ssa(1); got != 1 {
+		fmt.Printf("div_uint16 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint16_1_ssa(1); got != 1 {
+		fmt.Printf("div_uint16 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_uint16_ssa(65535); got != 0 {
+		fmt.Printf("div_uint16 1%s65535 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint16_1_ssa(65535); got != 65535 {
+		fmt.Printf("div_uint16 65535%s1 = %d, wanted 65535\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint16_65535_ssa(0); got != 0 {
+		fmt.Printf("div_uint16 0%s65535 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_65535_uint16_ssa(1); got != 65535 {
+		fmt.Printf("div_uint16 65535%s1 = %d, wanted 65535\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint16_65535_ssa(1); got != 0 {
+		fmt.Printf("div_uint16 1%s65535 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_65535_uint16_ssa(65535); got != 1 {
+		fmt.Printf("div_uint16 65535%s65535 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint16_65535_ssa(65535); got != 1 {
+		fmt.Printf("div_uint16 65535%s65535 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint16_ssa(0); got != 0 {
+		fmt.Printf("mul_uint16 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint16_0_ssa(0); got != 0 {
+		fmt.Printf("mul_uint16 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint16_ssa(1); got != 0 {
+		fmt.Printf("mul_uint16 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint16_0_ssa(1); got != 0 {
+		fmt.Printf("mul_uint16 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint16_ssa(65535); got != 0 {
+		fmt.Printf("mul_uint16 0%s65535 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint16_0_ssa(65535); got != 0 {
+		fmt.Printf("mul_uint16 65535%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint16_ssa(0); got != 0 {
+		fmt.Printf("mul_uint16 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint16_1_ssa(0); got != 0 {
+		fmt.Printf("mul_uint16 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint16_ssa(1); got != 1 {
+		fmt.Printf("mul_uint16 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint16_1_ssa(1); got != 1 {
+		fmt.Printf("mul_uint16 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint16_ssa(65535); got != 65535 {
+		fmt.Printf("mul_uint16 1%s65535 = %d, wanted 65535\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint16_1_ssa(65535); got != 65535 {
+		fmt.Printf("mul_uint16 65535%s1 = %d, wanted 65535\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_65535_uint16_ssa(0); got != 0 {
+		fmt.Printf("mul_uint16 65535%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint16_65535_ssa(0); got != 0 {
+		fmt.Printf("mul_uint16 0%s65535 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_65535_uint16_ssa(1); got != 65535 {
+		fmt.Printf("mul_uint16 65535%s1 = %d, wanted 65535\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint16_65535_ssa(1); got != 65535 {
+		fmt.Printf("mul_uint16 1%s65535 = %d, wanted 65535\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_65535_uint16_ssa(65535); got != 1 {
+		fmt.Printf("mul_uint16 65535%s65535 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint16_65535_ssa(65535); got != 1 {
+		fmt.Printf("mul_uint16 65535%s65535 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint16_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint16 0%s0 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint16_0_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint16 0%s0 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint16_ssa(1); got != 0 {
+		fmt.Printf("lsh_uint16 0%s1 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint16_0_ssa(1); got != 1 {
+		fmt.Printf("lsh_uint16 1%s0 = %d, wanted 1\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint16_ssa(65535); got != 0 {
+		fmt.Printf("lsh_uint16 0%s65535 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint16_0_ssa(65535); got != 65535 {
+		fmt.Printf("lsh_uint16 65535%s0 = %d, wanted 65535\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint16_ssa(0); got != 1 {
+		fmt.Printf("lsh_uint16 1%s0 = %d, wanted 1\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint16_1_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint16 0%s1 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint16_ssa(1); got != 2 {
+		fmt.Printf("lsh_uint16 1%s1 = %d, wanted 2\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint16_1_ssa(1); got != 2 {
+		fmt.Printf("lsh_uint16 1%s1 = %d, wanted 2\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint16_ssa(65535); got != 0 {
+		fmt.Printf("lsh_uint16 1%s65535 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint16_1_ssa(65535); got != 65534 {
+		fmt.Printf("lsh_uint16 65535%s1 = %d, wanted 65534\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_65535_uint16_ssa(0); got != 65535 {
+		fmt.Printf("lsh_uint16 65535%s0 = %d, wanted 65535\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint16_65535_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint16 0%s65535 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_65535_uint16_ssa(1); got != 65534 {
+		fmt.Printf("lsh_uint16 65535%s1 = %d, wanted 65534\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint16_65535_ssa(1); got != 0 {
+		fmt.Printf("lsh_uint16 1%s65535 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_65535_uint16_ssa(65535); got != 0 {
+		fmt.Printf("lsh_uint16 65535%s65535 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint16_65535_ssa(65535); got != 0 {
+		fmt.Printf("lsh_uint16 65535%s65535 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint16_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint16 0%s0 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint16_0_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint16 0%s0 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint16_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint16 0%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint16_0_ssa(1); got != 1 {
+		fmt.Printf("rsh_uint16 1%s0 = %d, wanted 1\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint16_ssa(65535); got != 0 {
+		fmt.Printf("rsh_uint16 0%s65535 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint16_0_ssa(65535); got != 65535 {
+		fmt.Printf("rsh_uint16 65535%s0 = %d, wanted 65535\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint16_ssa(0); got != 1 {
+		fmt.Printf("rsh_uint16 1%s0 = %d, wanted 1\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint16_1_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint16 0%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint16_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint16 1%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint16_1_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint16 1%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint16_ssa(65535); got != 0 {
+		fmt.Printf("rsh_uint16 1%s65535 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint16_1_ssa(65535); got != 32767 {
+		fmt.Printf("rsh_uint16 65535%s1 = %d, wanted 32767\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_65535_uint16_ssa(0); got != 65535 {
+		fmt.Printf("rsh_uint16 65535%s0 = %d, wanted 65535\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint16_65535_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint16 0%s65535 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_65535_uint16_ssa(1); got != 32767 {
+		fmt.Printf("rsh_uint16 65535%s1 = %d, wanted 32767\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint16_65535_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint16 1%s65535 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_65535_uint16_ssa(65535); got != 0 {
+		fmt.Printf("rsh_uint16 65535%s65535 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint16_65535_ssa(65535); got != 0 {
+		fmt.Printf("rsh_uint16 65535%s65535 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := mod_0_uint16_ssa(1); got != 0 {
+		fmt.Printf("mod_uint16 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_uint16_ssa(65535); got != 0 {
+		fmt.Printf("mod_uint16 0%s65535 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint16_1_ssa(0); got != 0 {
+		fmt.Printf("mod_uint16 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_uint16_ssa(1); got != 0 {
+		fmt.Printf("mod_uint16 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint16_1_ssa(1); got != 0 {
+		fmt.Printf("mod_uint16 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_uint16_ssa(65535); got != 1 {
+		fmt.Printf("mod_uint16 1%s65535 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint16_1_ssa(65535); got != 0 {
+		fmt.Printf("mod_uint16 65535%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint16_65535_ssa(0); got != 0 {
+		fmt.Printf("mod_uint16 0%s65535 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_65535_uint16_ssa(1); got != 0 {
+		fmt.Printf("mod_uint16 65535%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint16_65535_ssa(1); got != 1 {
+		fmt.Printf("mod_uint16 1%s65535 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_65535_uint16_ssa(65535); got != 0 {
+		fmt.Printf("mod_uint16 65535%s65535 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint16_65535_ssa(65535); got != 0 {
+		fmt.Printf("mod_uint16 65535%s65535 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := add_Neg32768_int16_ssa(-32768); got != 0 {
+		fmt.Printf("add_int16 -32768%s-32768 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32768_ssa(-32768); got != 0 {
+		fmt.Printf("add_int16 -32768%s-32768 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32768_int16_ssa(-32767); got != 1 {
+		fmt.Printf("add_int16 -32768%s-32767 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32768_ssa(-32767); got != 1 {
+		fmt.Printf("add_int16 -32767%s-32768 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32768_int16_ssa(-1); got != 32767 {
+		fmt.Printf("add_int16 -32768%s-1 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32768_ssa(-1); got != 32767 {
+		fmt.Printf("add_int16 -1%s-32768 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32768_int16_ssa(0); got != -32768 {
+		fmt.Printf("add_int16 -32768%s0 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32768_ssa(0); got != -32768 {
+		fmt.Printf("add_int16 0%s-32768 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32768_int16_ssa(1); got != -32767 {
+		fmt.Printf("add_int16 -32768%s1 = %d, wanted -32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32768_ssa(1); got != -32767 {
+		fmt.Printf("add_int16 1%s-32768 = %d, wanted -32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32768_int16_ssa(32766); got != -2 {
+		fmt.Printf("add_int16 -32768%s32766 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32768_ssa(32766); got != -2 {
+		fmt.Printf("add_int16 32766%s-32768 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32768_int16_ssa(32767); got != -1 {
+		fmt.Printf("add_int16 -32768%s32767 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32768_ssa(32767); got != -1 {
+		fmt.Printf("add_int16 32767%s-32768 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32767_int16_ssa(-32768); got != 1 {
+		fmt.Printf("add_int16 -32767%s-32768 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32767_ssa(-32768); got != 1 {
+		fmt.Printf("add_int16 -32768%s-32767 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32767_int16_ssa(-32767); got != 2 {
+		fmt.Printf("add_int16 -32767%s-32767 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32767_ssa(-32767); got != 2 {
+		fmt.Printf("add_int16 -32767%s-32767 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32767_int16_ssa(-1); got != -32768 {
+		fmt.Printf("add_int16 -32767%s-1 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32767_ssa(-1); got != -32768 {
+		fmt.Printf("add_int16 -1%s-32767 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32767_int16_ssa(0); got != -32767 {
+		fmt.Printf("add_int16 -32767%s0 = %d, wanted -32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32767_ssa(0); got != -32767 {
+		fmt.Printf("add_int16 0%s-32767 = %d, wanted -32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32767_int16_ssa(1); got != -32766 {
+		fmt.Printf("add_int16 -32767%s1 = %d, wanted -32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32767_ssa(1); got != -32766 {
+		fmt.Printf("add_int16 1%s-32767 = %d, wanted -32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32767_int16_ssa(32766); got != -1 {
+		fmt.Printf("add_int16 -32767%s32766 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32767_ssa(32766); got != -1 {
+		fmt.Printf("add_int16 32766%s-32767 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg32767_int16_ssa(32767); got != 0 {
+		fmt.Printf("add_int16 -32767%s32767 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg32767_ssa(32767); got != 0 {
+		fmt.Printf("add_int16 32767%s-32767 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int16_ssa(-32768); got != 32767 {
+		fmt.Printf("add_int16 -1%s-32768 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg1_ssa(-32768); got != 32767 {
+		fmt.Printf("add_int16 -32768%s-1 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int16_ssa(-32767); got != -32768 {
+		fmt.Printf("add_int16 -1%s-32767 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg1_ssa(-32767); got != -32768 {
+		fmt.Printf("add_int16 -32767%s-1 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int16_ssa(-1); got != -2 {
+		fmt.Printf("add_int16 -1%s-1 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg1_ssa(-1); got != -2 {
+		fmt.Printf("add_int16 -1%s-1 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int16_ssa(0); got != -1 {
+		fmt.Printf("add_int16 -1%s0 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg1_ssa(0); got != -1 {
+		fmt.Printf("add_int16 0%s-1 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int16_ssa(1); got != 0 {
+		fmt.Printf("add_int16 -1%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg1_ssa(1); got != 0 {
+		fmt.Printf("add_int16 1%s-1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int16_ssa(32766); got != 32765 {
+		fmt.Printf("add_int16 -1%s32766 = %d, wanted 32765\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg1_ssa(32766); got != 32765 {
+		fmt.Printf("add_int16 32766%s-1 = %d, wanted 32765\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int16_ssa(32767); got != 32766 {
+		fmt.Printf("add_int16 -1%s32767 = %d, wanted 32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_Neg1_ssa(32767); got != 32766 {
+		fmt.Printf("add_int16 32767%s-1 = %d, wanted 32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int16_ssa(-32768); got != -32768 {
+		fmt.Printf("add_int16 0%s-32768 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_0_ssa(-32768); got != -32768 {
+		fmt.Printf("add_int16 -32768%s0 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int16_ssa(-32767); got != -32767 {
+		fmt.Printf("add_int16 0%s-32767 = %d, wanted -32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_0_ssa(-32767); got != -32767 {
+		fmt.Printf("add_int16 -32767%s0 = %d, wanted -32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int16_ssa(-1); got != -1 {
+		fmt.Printf("add_int16 0%s-1 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_0_ssa(-1); got != -1 {
+		fmt.Printf("add_int16 -1%s0 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int16_ssa(0); got != 0 {
+		fmt.Printf("add_int16 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_0_ssa(0); got != 0 {
+		fmt.Printf("add_int16 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int16_ssa(1); got != 1 {
+		fmt.Printf("add_int16 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_0_ssa(1); got != 1 {
+		fmt.Printf("add_int16 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int16_ssa(32766); got != 32766 {
+		fmt.Printf("add_int16 0%s32766 = %d, wanted 32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_0_ssa(32766); got != 32766 {
+		fmt.Printf("add_int16 32766%s0 = %d, wanted 32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int16_ssa(32767); got != 32767 {
+		fmt.Printf("add_int16 0%s32767 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_0_ssa(32767); got != 32767 {
+		fmt.Printf("add_int16 32767%s0 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int16_ssa(-32768); got != -32767 {
+		fmt.Printf("add_int16 1%s-32768 = %d, wanted -32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_1_ssa(-32768); got != -32767 {
+		fmt.Printf("add_int16 -32768%s1 = %d, wanted -32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int16_ssa(-32767); got != -32766 {
+		fmt.Printf("add_int16 1%s-32767 = %d, wanted -32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_1_ssa(-32767); got != -32766 {
+		fmt.Printf("add_int16 -32767%s1 = %d, wanted -32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int16_ssa(-1); got != 0 {
+		fmt.Printf("add_int16 1%s-1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_1_ssa(-1); got != 0 {
+		fmt.Printf("add_int16 -1%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int16_ssa(0); got != 1 {
+		fmt.Printf("add_int16 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_1_ssa(0); got != 1 {
+		fmt.Printf("add_int16 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int16_ssa(1); got != 2 {
+		fmt.Printf("add_int16 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_1_ssa(1); got != 2 {
+		fmt.Printf("add_int16 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int16_ssa(32766); got != 32767 {
+		fmt.Printf("add_int16 1%s32766 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_1_ssa(32766); got != 32767 {
+		fmt.Printf("add_int16 32766%s1 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int16_ssa(32767); got != -32768 {
+		fmt.Printf("add_int16 1%s32767 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_1_ssa(32767); got != -32768 {
+		fmt.Printf("add_int16 32767%s1 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32766_int16_ssa(-32768); got != -2 {
+		fmt.Printf("add_int16 32766%s-32768 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32766_ssa(-32768); got != -2 {
+		fmt.Printf("add_int16 -32768%s32766 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32766_int16_ssa(-32767); got != -1 {
+		fmt.Printf("add_int16 32766%s-32767 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32766_ssa(-32767); got != -1 {
+		fmt.Printf("add_int16 -32767%s32766 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32766_int16_ssa(-1); got != 32765 {
+		fmt.Printf("add_int16 32766%s-1 = %d, wanted 32765\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32766_ssa(-1); got != 32765 {
+		fmt.Printf("add_int16 -1%s32766 = %d, wanted 32765\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32766_int16_ssa(0); got != 32766 {
+		fmt.Printf("add_int16 32766%s0 = %d, wanted 32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32766_ssa(0); got != 32766 {
+		fmt.Printf("add_int16 0%s32766 = %d, wanted 32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32766_int16_ssa(1); got != 32767 {
+		fmt.Printf("add_int16 32766%s1 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32766_ssa(1); got != 32767 {
+		fmt.Printf("add_int16 1%s32766 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32766_int16_ssa(32766); got != -4 {
+		fmt.Printf("add_int16 32766%s32766 = %d, wanted -4\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32766_ssa(32766); got != -4 {
+		fmt.Printf("add_int16 32766%s32766 = %d, wanted -4\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32766_int16_ssa(32767); got != -3 {
+		fmt.Printf("add_int16 32766%s32767 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32766_ssa(32767); got != -3 {
+		fmt.Printf("add_int16 32767%s32766 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32767_int16_ssa(-32768); got != -1 {
+		fmt.Printf("add_int16 32767%s-32768 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32767_ssa(-32768); got != -1 {
+		fmt.Printf("add_int16 -32768%s32767 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32767_int16_ssa(-32767); got != 0 {
+		fmt.Printf("add_int16 32767%s-32767 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32767_ssa(-32767); got != 0 {
+		fmt.Printf("add_int16 -32767%s32767 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32767_int16_ssa(-1); got != 32766 {
+		fmt.Printf("add_int16 32767%s-1 = %d, wanted 32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32767_ssa(-1); got != 32766 {
+		fmt.Printf("add_int16 -1%s32767 = %d, wanted 32766\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32767_int16_ssa(0); got != 32767 {
+		fmt.Printf("add_int16 32767%s0 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32767_ssa(0); got != 32767 {
+		fmt.Printf("add_int16 0%s32767 = %d, wanted 32767\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32767_int16_ssa(1); got != -32768 {
+		fmt.Printf("add_int16 32767%s1 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32767_ssa(1); got != -32768 {
+		fmt.Printf("add_int16 1%s32767 = %d, wanted -32768\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32767_int16_ssa(32766); got != -3 {
+		fmt.Printf("add_int16 32767%s32766 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32767_ssa(32766); got != -3 {
+		fmt.Printf("add_int16 32766%s32767 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_32767_int16_ssa(32767); got != -2 {
+		fmt.Printf("add_int16 32767%s32767 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int16_32767_ssa(32767); got != -2 {
+		fmt.Printf("add_int16 32767%s32767 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32768_int16_ssa(-32768); got != 0 {
+		fmt.Printf("sub_int16 -32768%s-32768 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32768_ssa(-32768); got != 0 {
+		fmt.Printf("sub_int16 -32768%s-32768 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32768_int16_ssa(-32767); got != -1 {
+		fmt.Printf("sub_int16 -32768%s-32767 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32768_ssa(-32767); got != 1 {
+		fmt.Printf("sub_int16 -32767%s-32768 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32768_int16_ssa(-1); got != -32767 {
+		fmt.Printf("sub_int16 -32768%s-1 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32768_ssa(-1); got != 32767 {
+		fmt.Printf("sub_int16 -1%s-32768 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32768_int16_ssa(0); got != -32768 {
+		fmt.Printf("sub_int16 -32768%s0 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32768_ssa(0); got != -32768 {
+		fmt.Printf("sub_int16 0%s-32768 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32768_int16_ssa(1); got != 32767 {
+		fmt.Printf("sub_int16 -32768%s1 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32768_ssa(1); got != -32767 {
+		fmt.Printf("sub_int16 1%s-32768 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32768_int16_ssa(32766); got != 2 {
+		fmt.Printf("sub_int16 -32768%s32766 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32768_ssa(32766); got != -2 {
+		fmt.Printf("sub_int16 32766%s-32768 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32768_int16_ssa(32767); got != 1 {
+		fmt.Printf("sub_int16 -32768%s32767 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32768_ssa(32767); got != -1 {
+		fmt.Printf("sub_int16 32767%s-32768 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32767_int16_ssa(-32768); got != 1 {
+		fmt.Printf("sub_int16 -32767%s-32768 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32767_ssa(-32768); got != -1 {
+		fmt.Printf("sub_int16 -32768%s-32767 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32767_int16_ssa(-32767); got != 0 {
+		fmt.Printf("sub_int16 -32767%s-32767 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32767_ssa(-32767); got != 0 {
+		fmt.Printf("sub_int16 -32767%s-32767 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32767_int16_ssa(-1); got != -32766 {
+		fmt.Printf("sub_int16 -32767%s-1 = %d, wanted -32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32767_ssa(-1); got != 32766 {
+		fmt.Printf("sub_int16 -1%s-32767 = %d, wanted 32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32767_int16_ssa(0); got != -32767 {
+		fmt.Printf("sub_int16 -32767%s0 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32767_ssa(0); got != 32767 {
+		fmt.Printf("sub_int16 0%s-32767 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32767_int16_ssa(1); got != -32768 {
+		fmt.Printf("sub_int16 -32767%s1 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32767_ssa(1); got != -32768 {
+		fmt.Printf("sub_int16 1%s-32767 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32767_int16_ssa(32766); got != 3 {
+		fmt.Printf("sub_int16 -32767%s32766 = %d, wanted 3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32767_ssa(32766); got != -3 {
+		fmt.Printf("sub_int16 32766%s-32767 = %d, wanted -3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg32767_int16_ssa(32767); got != 2 {
+		fmt.Printf("sub_int16 -32767%s32767 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg32767_ssa(32767); got != -2 {
+		fmt.Printf("sub_int16 32767%s-32767 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int16_ssa(-32768); got != 32767 {
+		fmt.Printf("sub_int16 -1%s-32768 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg1_ssa(-32768); got != -32767 {
+		fmt.Printf("sub_int16 -32768%s-1 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int16_ssa(-32767); got != 32766 {
+		fmt.Printf("sub_int16 -1%s-32767 = %d, wanted 32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg1_ssa(-32767); got != -32766 {
+		fmt.Printf("sub_int16 -32767%s-1 = %d, wanted -32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int16_ssa(-1); got != 0 {
+		fmt.Printf("sub_int16 -1%s-1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg1_ssa(-1); got != 0 {
+		fmt.Printf("sub_int16 -1%s-1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int16_ssa(0); got != -1 {
+		fmt.Printf("sub_int16 -1%s0 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg1_ssa(0); got != 1 {
+		fmt.Printf("sub_int16 0%s-1 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int16_ssa(1); got != -2 {
+		fmt.Printf("sub_int16 -1%s1 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg1_ssa(1); got != 2 {
+		fmt.Printf("sub_int16 1%s-1 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int16_ssa(32766); got != -32767 {
+		fmt.Printf("sub_int16 -1%s32766 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg1_ssa(32766); got != 32767 {
+		fmt.Printf("sub_int16 32766%s-1 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int16_ssa(32767); got != -32768 {
+		fmt.Printf("sub_int16 -1%s32767 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_Neg1_ssa(32767); got != -32768 {
+		fmt.Printf("sub_int16 32767%s-1 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int16_ssa(-32768); got != -32768 {
+		fmt.Printf("sub_int16 0%s-32768 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_0_ssa(-32768); got != -32768 {
+		fmt.Printf("sub_int16 -32768%s0 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int16_ssa(-32767); got != 32767 {
+		fmt.Printf("sub_int16 0%s-32767 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_0_ssa(-32767); got != -32767 {
+		fmt.Printf("sub_int16 -32767%s0 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int16_ssa(-1); got != 1 {
+		fmt.Printf("sub_int16 0%s-1 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_0_ssa(-1); got != -1 {
+		fmt.Printf("sub_int16 -1%s0 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int16_ssa(0); got != 0 {
+		fmt.Printf("sub_int16 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_0_ssa(0); got != 0 {
+		fmt.Printf("sub_int16 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int16_ssa(1); got != -1 {
+		fmt.Printf("sub_int16 0%s1 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_0_ssa(1); got != 1 {
+		fmt.Printf("sub_int16 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int16_ssa(32766); got != -32766 {
+		fmt.Printf("sub_int16 0%s32766 = %d, wanted -32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_0_ssa(32766); got != 32766 {
+		fmt.Printf("sub_int16 32766%s0 = %d, wanted 32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int16_ssa(32767); got != -32767 {
+		fmt.Printf("sub_int16 0%s32767 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_0_ssa(32767); got != 32767 {
+		fmt.Printf("sub_int16 32767%s0 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int16_ssa(-32768); got != -32767 {
+		fmt.Printf("sub_int16 1%s-32768 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_1_ssa(-32768); got != 32767 {
+		fmt.Printf("sub_int16 -32768%s1 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int16_ssa(-32767); got != -32768 {
+		fmt.Printf("sub_int16 1%s-32767 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_1_ssa(-32767); got != -32768 {
+		fmt.Printf("sub_int16 -32767%s1 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int16_ssa(-1); got != 2 {
+		fmt.Printf("sub_int16 1%s-1 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_1_ssa(-1); got != -2 {
+		fmt.Printf("sub_int16 -1%s1 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int16_ssa(0); got != 1 {
+		fmt.Printf("sub_int16 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_1_ssa(0); got != -1 {
+		fmt.Printf("sub_int16 0%s1 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int16_ssa(1); got != 0 {
+		fmt.Printf("sub_int16 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_1_ssa(1); got != 0 {
+		fmt.Printf("sub_int16 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int16_ssa(32766); got != -32765 {
+		fmt.Printf("sub_int16 1%s32766 = %d, wanted -32765\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_1_ssa(32766); got != 32765 {
+		fmt.Printf("sub_int16 32766%s1 = %d, wanted 32765\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int16_ssa(32767); got != -32766 {
+		fmt.Printf("sub_int16 1%s32767 = %d, wanted -32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_1_ssa(32767); got != 32766 {
+		fmt.Printf("sub_int16 32767%s1 = %d, wanted 32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32766_int16_ssa(-32768); got != -2 {
+		fmt.Printf("sub_int16 32766%s-32768 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32766_ssa(-32768); got != 2 {
+		fmt.Printf("sub_int16 -32768%s32766 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32766_int16_ssa(-32767); got != -3 {
+		fmt.Printf("sub_int16 32766%s-32767 = %d, wanted -3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32766_ssa(-32767); got != 3 {
+		fmt.Printf("sub_int16 -32767%s32766 = %d, wanted 3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32766_int16_ssa(-1); got != 32767 {
+		fmt.Printf("sub_int16 32766%s-1 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32766_ssa(-1); got != -32767 {
+		fmt.Printf("sub_int16 -1%s32766 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32766_int16_ssa(0); got != 32766 {
+		fmt.Printf("sub_int16 32766%s0 = %d, wanted 32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32766_ssa(0); got != -32766 {
+		fmt.Printf("sub_int16 0%s32766 = %d, wanted -32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32766_int16_ssa(1); got != 32765 {
+		fmt.Printf("sub_int16 32766%s1 = %d, wanted 32765\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32766_ssa(1); got != -32765 {
+		fmt.Printf("sub_int16 1%s32766 = %d, wanted -32765\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32766_int16_ssa(32766); got != 0 {
+		fmt.Printf("sub_int16 32766%s32766 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32766_ssa(32766); got != 0 {
+		fmt.Printf("sub_int16 32766%s32766 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32766_int16_ssa(32767); got != -1 {
+		fmt.Printf("sub_int16 32766%s32767 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32766_ssa(32767); got != 1 {
+		fmt.Printf("sub_int16 32767%s32766 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32767_int16_ssa(-32768); got != -1 {
+		fmt.Printf("sub_int16 32767%s-32768 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32767_ssa(-32768); got != 1 {
+		fmt.Printf("sub_int16 -32768%s32767 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32767_int16_ssa(-32767); got != -2 {
+		fmt.Printf("sub_int16 32767%s-32767 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32767_ssa(-32767); got != 2 {
+		fmt.Printf("sub_int16 -32767%s32767 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32767_int16_ssa(-1); got != -32768 {
+		fmt.Printf("sub_int16 32767%s-1 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32767_ssa(-1); got != -32768 {
+		fmt.Printf("sub_int16 -1%s32767 = %d, wanted -32768\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32767_int16_ssa(0); got != 32767 {
+		fmt.Printf("sub_int16 32767%s0 = %d, wanted 32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32767_ssa(0); got != -32767 {
+		fmt.Printf("sub_int16 0%s32767 = %d, wanted -32767\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32767_int16_ssa(1); got != 32766 {
+		fmt.Printf("sub_int16 32767%s1 = %d, wanted 32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32767_ssa(1); got != -32766 {
+		fmt.Printf("sub_int16 1%s32767 = %d, wanted -32766\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32767_int16_ssa(32766); got != 1 {
+		fmt.Printf("sub_int16 32767%s32766 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32767_ssa(32766); got != -1 {
+		fmt.Printf("sub_int16 32766%s32767 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_32767_int16_ssa(32767); got != 0 {
+		fmt.Printf("sub_int16 32767%s32767 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int16_32767_ssa(32767); got != 0 {
+		fmt.Printf("sub_int16 32767%s32767 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := div_Neg32768_int16_ssa(-32768); got != 1 {
+		fmt.Printf("div_int16 -32768%s-32768 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32768_ssa(-32768); got != 1 {
+		fmt.Printf("div_int16 -32768%s-32768 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32768_int16_ssa(-32767); got != 1 {
+		fmt.Printf("div_int16 -32768%s-32767 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32768_ssa(-32767); got != 0 {
+		fmt.Printf("div_int16 -32767%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32768_int16_ssa(-1); got != -32768 {
+		fmt.Printf("div_int16 -32768%s-1 = %d, wanted -32768\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32768_ssa(-1); got != 0 {
+		fmt.Printf("div_int16 -1%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32768_ssa(0); got != 0 {
+		fmt.Printf("div_int16 0%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32768_int16_ssa(1); got != -32768 {
+		fmt.Printf("div_int16 -32768%s1 = %d, wanted -32768\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32768_ssa(1); got != 0 {
+		fmt.Printf("div_int16 1%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32768_int16_ssa(32766); got != -1 {
+		fmt.Printf("div_int16 -32768%s32766 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32768_ssa(32766); got != 0 {
+		fmt.Printf("div_int16 32766%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32768_int16_ssa(32767); got != -1 {
+		fmt.Printf("div_int16 -32768%s32767 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32768_ssa(32767); got != 0 {
+		fmt.Printf("div_int16 32767%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32767_int16_ssa(-32768); got != 0 {
+		fmt.Printf("div_int16 -32767%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32767_ssa(-32768); got != 1 {
+		fmt.Printf("div_int16 -32768%s-32767 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32767_int16_ssa(-32767); got != 1 {
+		fmt.Printf("div_int16 -32767%s-32767 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32767_ssa(-32767); got != 1 {
+		fmt.Printf("div_int16 -32767%s-32767 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32767_int16_ssa(-1); got != 32767 {
+		fmt.Printf("div_int16 -32767%s-1 = %d, wanted 32767\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32767_ssa(-1); got != 0 {
+		fmt.Printf("div_int16 -1%s-32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32767_ssa(0); got != 0 {
+		fmt.Printf("div_int16 0%s-32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32767_int16_ssa(1); got != -32767 {
+		fmt.Printf("div_int16 -32767%s1 = %d, wanted -32767\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32767_ssa(1); got != 0 {
+		fmt.Printf("div_int16 1%s-32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32767_int16_ssa(32766); got != -1 {
+		fmt.Printf("div_int16 -32767%s32766 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32767_ssa(32766); got != 0 {
+		fmt.Printf("div_int16 32766%s-32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg32767_int16_ssa(32767); got != -1 {
+		fmt.Printf("div_int16 -32767%s32767 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg32767_ssa(32767); got != -1 {
+		fmt.Printf("div_int16 32767%s-32767 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int16_ssa(-32768); got != 0 {
+		fmt.Printf("div_int16 -1%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg1_ssa(-32768); got != -32768 {
+		fmt.Printf("div_int16 -32768%s-1 = %d, wanted -32768\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int16_ssa(-32767); got != 0 {
+		fmt.Printf("div_int16 -1%s-32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg1_ssa(-32767); got != 32767 {
+		fmt.Printf("div_int16 -32767%s-1 = %d, wanted 32767\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int16_ssa(-1); got != 1 {
+		fmt.Printf("div_int16 -1%s-1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg1_ssa(-1); got != 1 {
+		fmt.Printf("div_int16 -1%s-1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg1_ssa(0); got != 0 {
+		fmt.Printf("div_int16 0%s-1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int16_ssa(1); got != -1 {
+		fmt.Printf("div_int16 -1%s1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg1_ssa(1); got != -1 {
+		fmt.Printf("div_int16 1%s-1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int16_ssa(32766); got != 0 {
+		fmt.Printf("div_int16 -1%s32766 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg1_ssa(32766); got != -32766 {
+		fmt.Printf("div_int16 32766%s-1 = %d, wanted -32766\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int16_ssa(32767); got != 0 {
+		fmt.Printf("div_int16 -1%s32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_Neg1_ssa(32767); got != -32767 {
+		fmt.Printf("div_int16 32767%s-1 = %d, wanted -32767\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int16_ssa(-32768); got != 0 {
+		fmt.Printf("div_int16 0%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int16_ssa(-32767); got != 0 {
+		fmt.Printf("div_int16 0%s-32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int16_ssa(-1); got != 0 {
+		fmt.Printf("div_int16 0%s-1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int16_ssa(1); got != 0 {
+		fmt.Printf("div_int16 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int16_ssa(32766); got != 0 {
+		fmt.Printf("div_int16 0%s32766 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int16_ssa(32767); got != 0 {
+		fmt.Printf("div_int16 0%s32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int16_ssa(-32768); got != 0 {
+		fmt.Printf("div_int16 1%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_1_ssa(-32768); got != -32768 {
+		fmt.Printf("div_int16 -32768%s1 = %d, wanted -32768\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int16_ssa(-32767); got != 0 {
+		fmt.Printf("div_int16 1%s-32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_1_ssa(-32767); got != -32767 {
+		fmt.Printf("div_int16 -32767%s1 = %d, wanted -32767\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int16_ssa(-1); got != -1 {
+		fmt.Printf("div_int16 1%s-1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_1_ssa(-1); got != -1 {
+		fmt.Printf("div_int16 -1%s1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_1_ssa(0); got != 0 {
+		fmt.Printf("div_int16 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int16_ssa(1); got != 1 {
+		fmt.Printf("div_int16 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_1_ssa(1); got != 1 {
+		fmt.Printf("div_int16 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int16_ssa(32766); got != 0 {
+		fmt.Printf("div_int16 1%s32766 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_1_ssa(32766); got != 32766 {
+		fmt.Printf("div_int16 32766%s1 = %d, wanted 32766\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int16_ssa(32767); got != 0 {
+		fmt.Printf("div_int16 1%s32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_1_ssa(32767); got != 32767 {
+		fmt.Printf("div_int16 32767%s1 = %d, wanted 32767\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32766_int16_ssa(-32768); got != 0 {
+		fmt.Printf("div_int16 32766%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32766_ssa(-32768); got != -1 {
+		fmt.Printf("div_int16 -32768%s32766 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32766_int16_ssa(-32767); got != 0 {
+		fmt.Printf("div_int16 32766%s-32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32766_ssa(-32767); got != -1 {
+		fmt.Printf("div_int16 -32767%s32766 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32766_int16_ssa(-1); got != -32766 {
+		fmt.Printf("div_int16 32766%s-1 = %d, wanted -32766\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32766_ssa(-1); got != 0 {
+		fmt.Printf("div_int16 -1%s32766 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32766_ssa(0); got != 0 {
+		fmt.Printf("div_int16 0%s32766 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32766_int16_ssa(1); got != 32766 {
+		fmt.Printf("div_int16 32766%s1 = %d, wanted 32766\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32766_ssa(1); got != 0 {
+		fmt.Printf("div_int16 1%s32766 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32766_int16_ssa(32766); got != 1 {
+		fmt.Printf("div_int16 32766%s32766 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32766_ssa(32766); got != 1 {
+		fmt.Printf("div_int16 32766%s32766 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32766_int16_ssa(32767); got != 0 {
+		fmt.Printf("div_int16 32766%s32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32766_ssa(32767); got != 1 {
+		fmt.Printf("div_int16 32767%s32766 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32767_int16_ssa(-32768); got != 0 {
+		fmt.Printf("div_int16 32767%s-32768 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32767_ssa(-32768); got != -1 {
+		fmt.Printf("div_int16 -32768%s32767 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32767_int16_ssa(-32767); got != -1 {
+		fmt.Printf("div_int16 32767%s-32767 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32767_ssa(-32767); got != -1 {
+		fmt.Printf("div_int16 -32767%s32767 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32767_int16_ssa(-1); got != -32767 {
+		fmt.Printf("div_int16 32767%s-1 = %d, wanted -32767\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32767_ssa(-1); got != 0 {
+		fmt.Printf("div_int16 -1%s32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32767_ssa(0); got != 0 {
+		fmt.Printf("div_int16 0%s32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32767_int16_ssa(1); got != 32767 {
+		fmt.Printf("div_int16 32767%s1 = %d, wanted 32767\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32767_ssa(1); got != 0 {
+		fmt.Printf("div_int16 1%s32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32767_int16_ssa(32766); got != 1 {
+		fmt.Printf("div_int16 32767%s32766 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32767_ssa(32766); got != 0 {
+		fmt.Printf("div_int16 32766%s32767 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_32767_int16_ssa(32767); got != 1 {
+		fmt.Printf("div_int16 32767%s32767 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int16_32767_ssa(32767); got != 1 {
+		fmt.Printf("div_int16 32767%s32767 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32768_int16_ssa(-32768); got != 0 {
+		fmt.Printf("mul_int16 -32768%s-32768 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32768_ssa(-32768); got != 0 {
+		fmt.Printf("mul_int16 -32768%s-32768 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32768_int16_ssa(-32767); got != -32768 {
+		fmt.Printf("mul_int16 -32768%s-32767 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32768_ssa(-32767); got != -32768 {
+		fmt.Printf("mul_int16 -32767%s-32768 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32768_int16_ssa(-1); got != -32768 {
+		fmt.Printf("mul_int16 -32768%s-1 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32768_ssa(-1); got != -32768 {
+		fmt.Printf("mul_int16 -1%s-32768 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32768_int16_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 -32768%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32768_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 0%s-32768 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32768_int16_ssa(1); got != -32768 {
+		fmt.Printf("mul_int16 -32768%s1 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32768_ssa(1); got != -32768 {
+		fmt.Printf("mul_int16 1%s-32768 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32768_int16_ssa(32766); got != 0 {
+		fmt.Printf("mul_int16 -32768%s32766 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32768_ssa(32766); got != 0 {
+		fmt.Printf("mul_int16 32766%s-32768 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32768_int16_ssa(32767); got != -32768 {
+		fmt.Printf("mul_int16 -32768%s32767 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32768_ssa(32767); got != -32768 {
+		fmt.Printf("mul_int16 32767%s-32768 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32767_int16_ssa(-32768); got != -32768 {
+		fmt.Printf("mul_int16 -32767%s-32768 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32767_ssa(-32768); got != -32768 {
+		fmt.Printf("mul_int16 -32768%s-32767 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32767_int16_ssa(-32767); got != 1 {
+		fmt.Printf("mul_int16 -32767%s-32767 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32767_ssa(-32767); got != 1 {
+		fmt.Printf("mul_int16 -32767%s-32767 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32767_int16_ssa(-1); got != 32767 {
+		fmt.Printf("mul_int16 -32767%s-1 = %d, wanted 32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32767_ssa(-1); got != 32767 {
+		fmt.Printf("mul_int16 -1%s-32767 = %d, wanted 32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32767_int16_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 -32767%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32767_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 0%s-32767 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32767_int16_ssa(1); got != -32767 {
+		fmt.Printf("mul_int16 -32767%s1 = %d, wanted -32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32767_ssa(1); got != -32767 {
+		fmt.Printf("mul_int16 1%s-32767 = %d, wanted -32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32767_int16_ssa(32766); got != 32766 {
+		fmt.Printf("mul_int16 -32767%s32766 = %d, wanted 32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32767_ssa(32766); got != 32766 {
+		fmt.Printf("mul_int16 32766%s-32767 = %d, wanted 32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg32767_int16_ssa(32767); got != -1 {
+		fmt.Printf("mul_int16 -32767%s32767 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg32767_ssa(32767); got != -1 {
+		fmt.Printf("mul_int16 32767%s-32767 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int16_ssa(-32768); got != -32768 {
+		fmt.Printf("mul_int16 -1%s-32768 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg1_ssa(-32768); got != -32768 {
+		fmt.Printf("mul_int16 -32768%s-1 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int16_ssa(-32767); got != 32767 {
+		fmt.Printf("mul_int16 -1%s-32767 = %d, wanted 32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg1_ssa(-32767); got != 32767 {
+		fmt.Printf("mul_int16 -32767%s-1 = %d, wanted 32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int16_ssa(-1); got != 1 {
+		fmt.Printf("mul_int16 -1%s-1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg1_ssa(-1); got != 1 {
+		fmt.Printf("mul_int16 -1%s-1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int16_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 -1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg1_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 0%s-1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int16_ssa(1); got != -1 {
+		fmt.Printf("mul_int16 -1%s1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg1_ssa(1); got != -1 {
+		fmt.Printf("mul_int16 1%s-1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int16_ssa(32766); got != -32766 {
+		fmt.Printf("mul_int16 -1%s32766 = %d, wanted -32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg1_ssa(32766); got != -32766 {
+		fmt.Printf("mul_int16 32766%s-1 = %d, wanted -32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int16_ssa(32767); got != -32767 {
+		fmt.Printf("mul_int16 -1%s32767 = %d, wanted -32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_Neg1_ssa(32767); got != -32767 {
+		fmt.Printf("mul_int16 32767%s-1 = %d, wanted -32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int16_ssa(-32768); got != 0 {
+		fmt.Printf("mul_int16 0%s-32768 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_0_ssa(-32768); got != 0 {
+		fmt.Printf("mul_int16 -32768%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int16_ssa(-32767); got != 0 {
+		fmt.Printf("mul_int16 0%s-32767 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_0_ssa(-32767); got != 0 {
+		fmt.Printf("mul_int16 -32767%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int16_ssa(-1); got != 0 {
+		fmt.Printf("mul_int16 0%s-1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_0_ssa(-1); got != 0 {
+		fmt.Printf("mul_int16 -1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int16_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_0_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int16_ssa(1); got != 0 {
+		fmt.Printf("mul_int16 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_0_ssa(1); got != 0 {
+		fmt.Printf("mul_int16 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int16_ssa(32766); got != 0 {
+		fmt.Printf("mul_int16 0%s32766 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_0_ssa(32766); got != 0 {
+		fmt.Printf("mul_int16 32766%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int16_ssa(32767); got != 0 {
+		fmt.Printf("mul_int16 0%s32767 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_0_ssa(32767); got != 0 {
+		fmt.Printf("mul_int16 32767%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int16_ssa(-32768); got != -32768 {
+		fmt.Printf("mul_int16 1%s-32768 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_1_ssa(-32768); got != -32768 {
+		fmt.Printf("mul_int16 -32768%s1 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int16_ssa(-32767); got != -32767 {
+		fmt.Printf("mul_int16 1%s-32767 = %d, wanted -32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_1_ssa(-32767); got != -32767 {
+		fmt.Printf("mul_int16 -32767%s1 = %d, wanted -32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int16_ssa(-1); got != -1 {
+		fmt.Printf("mul_int16 1%s-1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_1_ssa(-1); got != -1 {
+		fmt.Printf("mul_int16 -1%s1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int16_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_1_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int16_ssa(1); got != 1 {
+		fmt.Printf("mul_int16 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_1_ssa(1); got != 1 {
+		fmt.Printf("mul_int16 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int16_ssa(32766); got != 32766 {
+		fmt.Printf("mul_int16 1%s32766 = %d, wanted 32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_1_ssa(32766); got != 32766 {
+		fmt.Printf("mul_int16 32766%s1 = %d, wanted 32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int16_ssa(32767); got != 32767 {
+		fmt.Printf("mul_int16 1%s32767 = %d, wanted 32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_1_ssa(32767); got != 32767 {
+		fmt.Printf("mul_int16 32767%s1 = %d, wanted 32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32766_int16_ssa(-32768); got != 0 {
+		fmt.Printf("mul_int16 32766%s-32768 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32766_ssa(-32768); got != 0 {
+		fmt.Printf("mul_int16 -32768%s32766 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32766_int16_ssa(-32767); got != 32766 {
+		fmt.Printf("mul_int16 32766%s-32767 = %d, wanted 32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32766_ssa(-32767); got != 32766 {
+		fmt.Printf("mul_int16 -32767%s32766 = %d, wanted 32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32766_int16_ssa(-1); got != -32766 {
+		fmt.Printf("mul_int16 32766%s-1 = %d, wanted -32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32766_ssa(-1); got != -32766 {
+		fmt.Printf("mul_int16 -1%s32766 = %d, wanted -32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32766_int16_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 32766%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32766_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 0%s32766 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32766_int16_ssa(1); got != 32766 {
+		fmt.Printf("mul_int16 32766%s1 = %d, wanted 32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32766_ssa(1); got != 32766 {
+		fmt.Printf("mul_int16 1%s32766 = %d, wanted 32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32766_int16_ssa(32766); got != 4 {
+		fmt.Printf("mul_int16 32766%s32766 = %d, wanted 4\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32766_ssa(32766); got != 4 {
+		fmt.Printf("mul_int16 32766%s32766 = %d, wanted 4\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32766_int16_ssa(32767); got != -32766 {
+		fmt.Printf("mul_int16 32766%s32767 = %d, wanted -32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32766_ssa(32767); got != -32766 {
+		fmt.Printf("mul_int16 32767%s32766 = %d, wanted -32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32767_int16_ssa(-32768); got != -32768 {
+		fmt.Printf("mul_int16 32767%s-32768 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32767_ssa(-32768); got != -32768 {
+		fmt.Printf("mul_int16 -32768%s32767 = %d, wanted -32768\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32767_int16_ssa(-32767); got != -1 {
+		fmt.Printf("mul_int16 32767%s-32767 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32767_ssa(-32767); got != -1 {
+		fmt.Printf("mul_int16 -32767%s32767 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32767_int16_ssa(-1); got != -32767 {
+		fmt.Printf("mul_int16 32767%s-1 = %d, wanted -32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32767_ssa(-1); got != -32767 {
+		fmt.Printf("mul_int16 -1%s32767 = %d, wanted -32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32767_int16_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 32767%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32767_ssa(0); got != 0 {
+		fmt.Printf("mul_int16 0%s32767 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32767_int16_ssa(1); got != 32767 {
+		fmt.Printf("mul_int16 32767%s1 = %d, wanted 32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32767_ssa(1); got != 32767 {
+		fmt.Printf("mul_int16 1%s32767 = %d, wanted 32767\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32767_int16_ssa(32766); got != -32766 {
+		fmt.Printf("mul_int16 32767%s32766 = %d, wanted -32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32767_ssa(32766); got != -32766 {
+		fmt.Printf("mul_int16 32766%s32767 = %d, wanted -32766\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_32767_int16_ssa(32767); got != 1 {
+		fmt.Printf("mul_int16 32767%s32767 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int16_32767_ssa(32767); got != 1 {
+		fmt.Printf("mul_int16 32767%s32767 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32768_int16_ssa(-32768); got != 0 {
+		fmt.Printf("mod_int16 -32768%s-32768 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32768_ssa(-32768); got != 0 {
+		fmt.Printf("mod_int16 -32768%s-32768 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32768_int16_ssa(-32767); got != -1 {
+		fmt.Printf("mod_int16 -32768%s-32767 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32768_ssa(-32767); got != -32767 {
+		fmt.Printf("mod_int16 -32767%s-32768 = %d, wanted -32767\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32768_int16_ssa(-1); got != 0 {
+		fmt.Printf("mod_int16 -32768%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32768_ssa(-1); got != -1 {
+		fmt.Printf("mod_int16 -1%s-32768 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32768_ssa(0); got != 0 {
+		fmt.Printf("mod_int16 0%s-32768 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32768_int16_ssa(1); got != 0 {
+		fmt.Printf("mod_int16 -32768%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32768_ssa(1); got != 1 {
+		fmt.Printf("mod_int16 1%s-32768 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32768_int16_ssa(32766); got != -2 {
+		fmt.Printf("mod_int16 -32768%s32766 = %d, wanted -2\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32768_ssa(32766); got != 32766 {
+		fmt.Printf("mod_int16 32766%s-32768 = %d, wanted 32766\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32768_int16_ssa(32767); got != -1 {
+		fmt.Printf("mod_int16 -32768%s32767 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32768_ssa(32767); got != 32767 {
+		fmt.Printf("mod_int16 32767%s-32768 = %d, wanted 32767\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32767_int16_ssa(-32768); got != -32767 {
+		fmt.Printf("mod_int16 -32767%s-32768 = %d, wanted -32767\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32767_ssa(-32768); got != -1 {
+		fmt.Printf("mod_int16 -32768%s-32767 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32767_int16_ssa(-32767); got != 0 {
+		fmt.Printf("mod_int16 -32767%s-32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32767_ssa(-32767); got != 0 {
+		fmt.Printf("mod_int16 -32767%s-32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32767_int16_ssa(-1); got != 0 {
+		fmt.Printf("mod_int16 -32767%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32767_ssa(-1); got != -1 {
+		fmt.Printf("mod_int16 -1%s-32767 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32767_ssa(0); got != 0 {
+		fmt.Printf("mod_int16 0%s-32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32767_int16_ssa(1); got != 0 {
+		fmt.Printf("mod_int16 -32767%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32767_ssa(1); got != 1 {
+		fmt.Printf("mod_int16 1%s-32767 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32767_int16_ssa(32766); got != -1 {
+		fmt.Printf("mod_int16 -32767%s32766 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32767_ssa(32766); got != 32766 {
+		fmt.Printf("mod_int16 32766%s-32767 = %d, wanted 32766\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg32767_int16_ssa(32767); got != 0 {
+		fmt.Printf("mod_int16 -32767%s32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg32767_ssa(32767); got != 0 {
+		fmt.Printf("mod_int16 32767%s-32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int16_ssa(-32768); got != -1 {
+		fmt.Printf("mod_int16 -1%s-32768 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg1_ssa(-32768); got != 0 {
+		fmt.Printf("mod_int16 -32768%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int16_ssa(-32767); got != -1 {
+		fmt.Printf("mod_int16 -1%s-32767 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg1_ssa(-32767); got != 0 {
+		fmt.Printf("mod_int16 -32767%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int16_ssa(-1); got != 0 {
+		fmt.Printf("mod_int16 -1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg1_ssa(-1); got != 0 {
+		fmt.Printf("mod_int16 -1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg1_ssa(0); got != 0 {
+		fmt.Printf("mod_int16 0%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int16_ssa(1); got != 0 {
+		fmt.Printf("mod_int16 -1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg1_ssa(1); got != 0 {
+		fmt.Printf("mod_int16 1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int16_ssa(32766); got != -1 {
+		fmt.Printf("mod_int16 -1%s32766 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg1_ssa(32766); got != 0 {
+		fmt.Printf("mod_int16 32766%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int16_ssa(32767); got != -1 {
+		fmt.Printf("mod_int16 -1%s32767 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_Neg1_ssa(32767); got != 0 {
+		fmt.Printf("mod_int16 32767%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int16_ssa(-32768); got != 0 {
+		fmt.Printf("mod_int16 0%s-32768 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int16_ssa(-32767); got != 0 {
+		fmt.Printf("mod_int16 0%s-32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int16_ssa(-1); got != 0 {
+		fmt.Printf("mod_int16 0%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int16_ssa(1); got != 0 {
+		fmt.Printf("mod_int16 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int16_ssa(32766); got != 0 {
+		fmt.Printf("mod_int16 0%s32766 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int16_ssa(32767); got != 0 {
+		fmt.Printf("mod_int16 0%s32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int16_ssa(-32768); got != 1 {
+		fmt.Printf("mod_int16 1%s-32768 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_1_ssa(-32768); got != 0 {
+		fmt.Printf("mod_int16 -32768%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int16_ssa(-32767); got != 1 {
+		fmt.Printf("mod_int16 1%s-32767 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_1_ssa(-32767); got != 0 {
+		fmt.Printf("mod_int16 -32767%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int16_ssa(-1); got != 0 {
+		fmt.Printf("mod_int16 1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_1_ssa(-1); got != 0 {
+		fmt.Printf("mod_int16 -1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_1_ssa(0); got != 0 {
+		fmt.Printf("mod_int16 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int16_ssa(1); got != 0 {
+		fmt.Printf("mod_int16 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_1_ssa(1); got != 0 {
+		fmt.Printf("mod_int16 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int16_ssa(32766); got != 1 {
+		fmt.Printf("mod_int16 1%s32766 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_1_ssa(32766); got != 0 {
+		fmt.Printf("mod_int16 32766%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int16_ssa(32767); got != 1 {
+		fmt.Printf("mod_int16 1%s32767 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_1_ssa(32767); got != 0 {
+		fmt.Printf("mod_int16 32767%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32766_int16_ssa(-32768); got != 32766 {
+		fmt.Printf("mod_int16 32766%s-32768 = %d, wanted 32766\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32766_ssa(-32768); got != -2 {
+		fmt.Printf("mod_int16 -32768%s32766 = %d, wanted -2\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32766_int16_ssa(-32767); got != 32766 {
+		fmt.Printf("mod_int16 32766%s-32767 = %d, wanted 32766\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32766_ssa(-32767); got != -1 {
+		fmt.Printf("mod_int16 -32767%s32766 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32766_int16_ssa(-1); got != 0 {
+		fmt.Printf("mod_int16 32766%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32766_ssa(-1); got != -1 {
+		fmt.Printf("mod_int16 -1%s32766 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32766_ssa(0); got != 0 {
+		fmt.Printf("mod_int16 0%s32766 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32766_int16_ssa(1); got != 0 {
+		fmt.Printf("mod_int16 32766%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32766_ssa(1); got != 1 {
+		fmt.Printf("mod_int16 1%s32766 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32766_int16_ssa(32766); got != 0 {
+		fmt.Printf("mod_int16 32766%s32766 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32766_ssa(32766); got != 0 {
+		fmt.Printf("mod_int16 32766%s32766 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32766_int16_ssa(32767); got != 32766 {
+		fmt.Printf("mod_int16 32766%s32767 = %d, wanted 32766\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32766_ssa(32767); got != 1 {
+		fmt.Printf("mod_int16 32767%s32766 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32767_int16_ssa(-32768); got != 32767 {
+		fmt.Printf("mod_int16 32767%s-32768 = %d, wanted 32767\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32767_ssa(-32768); got != -1 {
+		fmt.Printf("mod_int16 -32768%s32767 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32767_int16_ssa(-32767); got != 0 {
+		fmt.Printf("mod_int16 32767%s-32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32767_ssa(-32767); got != 0 {
+		fmt.Printf("mod_int16 -32767%s32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32767_int16_ssa(-1); got != 0 {
+		fmt.Printf("mod_int16 32767%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32767_ssa(-1); got != -1 {
+		fmt.Printf("mod_int16 -1%s32767 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32767_ssa(0); got != 0 {
+		fmt.Printf("mod_int16 0%s32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32767_int16_ssa(1); got != 0 {
+		fmt.Printf("mod_int16 32767%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32767_ssa(1); got != 1 {
+		fmt.Printf("mod_int16 1%s32767 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32767_int16_ssa(32766); got != 1 {
+		fmt.Printf("mod_int16 32767%s32766 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32767_ssa(32766); got != 32766 {
+		fmt.Printf("mod_int16 32766%s32767 = %d, wanted 32766\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_32767_int16_ssa(32767); got != 0 {
+		fmt.Printf("mod_int16 32767%s32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int16_32767_ssa(32767); got != 0 {
+		fmt.Printf("mod_int16 32767%s32767 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := add_0_uint8_ssa(0); got != 0 {
+		fmt.Printf("add_uint8 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint8_0_ssa(0); got != 0 {
+		fmt.Printf("add_uint8 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_uint8_ssa(1); got != 1 {
+		fmt.Printf("add_uint8 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint8_0_ssa(1); got != 1 {
+		fmt.Printf("add_uint8 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_uint8_ssa(255); got != 255 {
+		fmt.Printf("add_uint8 0%s255 = %d, wanted 255\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint8_0_ssa(255); got != 255 {
+		fmt.Printf("add_uint8 255%s0 = %d, wanted 255\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint8_ssa(0); got != 1 {
+		fmt.Printf("add_uint8 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint8_1_ssa(0); got != 1 {
+		fmt.Printf("add_uint8 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint8_ssa(1); got != 2 {
+		fmt.Printf("add_uint8 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint8_1_ssa(1); got != 2 {
+		fmt.Printf("add_uint8 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_uint8_ssa(255); got != 0 {
+		fmt.Printf("add_uint8 1%s255 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint8_1_ssa(255); got != 0 {
+		fmt.Printf("add_uint8 255%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_255_uint8_ssa(0); got != 255 {
+		fmt.Printf("add_uint8 255%s0 = %d, wanted 255\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint8_255_ssa(0); got != 255 {
+		fmt.Printf("add_uint8 0%s255 = %d, wanted 255\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_255_uint8_ssa(1); got != 0 {
+		fmt.Printf("add_uint8 255%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint8_255_ssa(1); got != 0 {
+		fmt.Printf("add_uint8 1%s255 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_255_uint8_ssa(255); got != 254 {
+		fmt.Printf("add_uint8 255%s255 = %d, wanted 254\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_uint8_255_ssa(255); got != 254 {
+		fmt.Printf("add_uint8 255%s255 = %d, wanted 254\n", `+`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint8_ssa(0); got != 0 {
+		fmt.Printf("sub_uint8 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint8_0_ssa(0); got != 0 {
+		fmt.Printf("sub_uint8 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint8_ssa(1); got != 255 {
+		fmt.Printf("sub_uint8 0%s1 = %d, wanted 255\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint8_0_ssa(1); got != 1 {
+		fmt.Printf("sub_uint8 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_uint8_ssa(255); got != 1 {
+		fmt.Printf("sub_uint8 0%s255 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint8_0_ssa(255); got != 255 {
+		fmt.Printf("sub_uint8 255%s0 = %d, wanted 255\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint8_ssa(0); got != 1 {
+		fmt.Printf("sub_uint8 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint8_1_ssa(0); got != 255 {
+		fmt.Printf("sub_uint8 0%s1 = %d, wanted 255\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint8_ssa(1); got != 0 {
+		fmt.Printf("sub_uint8 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint8_1_ssa(1); got != 0 {
+		fmt.Printf("sub_uint8 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_uint8_ssa(255); got != 2 {
+		fmt.Printf("sub_uint8 1%s255 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint8_1_ssa(255); got != 254 {
+		fmt.Printf("sub_uint8 255%s1 = %d, wanted 254\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_255_uint8_ssa(0); got != 255 {
+		fmt.Printf("sub_uint8 255%s0 = %d, wanted 255\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint8_255_ssa(0); got != 1 {
+		fmt.Printf("sub_uint8 0%s255 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_255_uint8_ssa(1); got != 254 {
+		fmt.Printf("sub_uint8 255%s1 = %d, wanted 254\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint8_255_ssa(1); got != 2 {
+		fmt.Printf("sub_uint8 1%s255 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_255_uint8_ssa(255); got != 0 {
+		fmt.Printf("sub_uint8 255%s255 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_uint8_255_ssa(255); got != 0 {
+		fmt.Printf("sub_uint8 255%s255 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := div_0_uint8_ssa(1); got != 0 {
+		fmt.Printf("div_uint8 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_uint8_ssa(255); got != 0 {
+		fmt.Printf("div_uint8 0%s255 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint8_1_ssa(0); got != 0 {
+		fmt.Printf("div_uint8 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_uint8_ssa(1); got != 1 {
+		fmt.Printf("div_uint8 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint8_1_ssa(1); got != 1 {
+		fmt.Printf("div_uint8 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_uint8_ssa(255); got != 0 {
+		fmt.Printf("div_uint8 1%s255 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint8_1_ssa(255); got != 255 {
+		fmt.Printf("div_uint8 255%s1 = %d, wanted 255\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint8_255_ssa(0); got != 0 {
+		fmt.Printf("div_uint8 0%s255 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_255_uint8_ssa(1); got != 255 {
+		fmt.Printf("div_uint8 255%s1 = %d, wanted 255\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint8_255_ssa(1); got != 0 {
+		fmt.Printf("div_uint8 1%s255 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_255_uint8_ssa(255); got != 1 {
+		fmt.Printf("div_uint8 255%s255 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_uint8_255_ssa(255); got != 1 {
+		fmt.Printf("div_uint8 255%s255 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint8_ssa(0); got != 0 {
+		fmt.Printf("mul_uint8 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint8_0_ssa(0); got != 0 {
+		fmt.Printf("mul_uint8 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint8_ssa(1); got != 0 {
+		fmt.Printf("mul_uint8 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint8_0_ssa(1); got != 0 {
+		fmt.Printf("mul_uint8 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_uint8_ssa(255); got != 0 {
+		fmt.Printf("mul_uint8 0%s255 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint8_0_ssa(255); got != 0 {
+		fmt.Printf("mul_uint8 255%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint8_ssa(0); got != 0 {
+		fmt.Printf("mul_uint8 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint8_1_ssa(0); got != 0 {
+		fmt.Printf("mul_uint8 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint8_ssa(1); got != 1 {
+		fmt.Printf("mul_uint8 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint8_1_ssa(1); got != 1 {
+		fmt.Printf("mul_uint8 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_uint8_ssa(255); got != 255 {
+		fmt.Printf("mul_uint8 1%s255 = %d, wanted 255\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint8_1_ssa(255); got != 255 {
+		fmt.Printf("mul_uint8 255%s1 = %d, wanted 255\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_255_uint8_ssa(0); got != 0 {
+		fmt.Printf("mul_uint8 255%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint8_255_ssa(0); got != 0 {
+		fmt.Printf("mul_uint8 0%s255 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_255_uint8_ssa(1); got != 255 {
+		fmt.Printf("mul_uint8 255%s1 = %d, wanted 255\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint8_255_ssa(1); got != 255 {
+		fmt.Printf("mul_uint8 1%s255 = %d, wanted 255\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_255_uint8_ssa(255); got != 1 {
+		fmt.Printf("mul_uint8 255%s255 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_uint8_255_ssa(255); got != 1 {
+		fmt.Printf("mul_uint8 255%s255 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint8_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint8 0%s0 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint8_0_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint8 0%s0 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint8_ssa(1); got != 0 {
+		fmt.Printf("lsh_uint8 0%s1 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint8_0_ssa(1); got != 1 {
+		fmt.Printf("lsh_uint8 1%s0 = %d, wanted 1\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_0_uint8_ssa(255); got != 0 {
+		fmt.Printf("lsh_uint8 0%s255 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint8_0_ssa(255); got != 255 {
+		fmt.Printf("lsh_uint8 255%s0 = %d, wanted 255\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint8_ssa(0); got != 1 {
+		fmt.Printf("lsh_uint8 1%s0 = %d, wanted 1\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint8_1_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint8 0%s1 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint8_ssa(1); got != 2 {
+		fmt.Printf("lsh_uint8 1%s1 = %d, wanted 2\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint8_1_ssa(1); got != 2 {
+		fmt.Printf("lsh_uint8 1%s1 = %d, wanted 2\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_1_uint8_ssa(255); got != 0 {
+		fmt.Printf("lsh_uint8 1%s255 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint8_1_ssa(255); got != 254 {
+		fmt.Printf("lsh_uint8 255%s1 = %d, wanted 254\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_255_uint8_ssa(0); got != 255 {
+		fmt.Printf("lsh_uint8 255%s0 = %d, wanted 255\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint8_255_ssa(0); got != 0 {
+		fmt.Printf("lsh_uint8 0%s255 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_255_uint8_ssa(1); got != 254 {
+		fmt.Printf("lsh_uint8 255%s1 = %d, wanted 254\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint8_255_ssa(1); got != 0 {
+		fmt.Printf("lsh_uint8 1%s255 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_255_uint8_ssa(255); got != 0 {
+		fmt.Printf("lsh_uint8 255%s255 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := lsh_uint8_255_ssa(255); got != 0 {
+		fmt.Printf("lsh_uint8 255%s255 = %d, wanted 0\n", `<<`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint8_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint8 0%s0 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint8_0_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint8 0%s0 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint8_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint8 0%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint8_0_ssa(1); got != 1 {
+		fmt.Printf("rsh_uint8 1%s0 = %d, wanted 1\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_0_uint8_ssa(255); got != 0 {
+		fmt.Printf("rsh_uint8 0%s255 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint8_0_ssa(255); got != 255 {
+		fmt.Printf("rsh_uint8 255%s0 = %d, wanted 255\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint8_ssa(0); got != 1 {
+		fmt.Printf("rsh_uint8 1%s0 = %d, wanted 1\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint8_1_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint8 0%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint8_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint8 1%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint8_1_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint8 1%s1 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_1_uint8_ssa(255); got != 0 {
+		fmt.Printf("rsh_uint8 1%s255 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint8_1_ssa(255); got != 127 {
+		fmt.Printf("rsh_uint8 255%s1 = %d, wanted 127\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_255_uint8_ssa(0); got != 255 {
+		fmt.Printf("rsh_uint8 255%s0 = %d, wanted 255\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint8_255_ssa(0); got != 0 {
+		fmt.Printf("rsh_uint8 0%s255 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_255_uint8_ssa(1); got != 127 {
+		fmt.Printf("rsh_uint8 255%s1 = %d, wanted 127\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint8_255_ssa(1); got != 0 {
+		fmt.Printf("rsh_uint8 1%s255 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_255_uint8_ssa(255); got != 0 {
+		fmt.Printf("rsh_uint8 255%s255 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := rsh_uint8_255_ssa(255); got != 0 {
+		fmt.Printf("rsh_uint8 255%s255 = %d, wanted 0\n", `>>`, got)
+		failed = true
+	}
+
+	if got := mod_0_uint8_ssa(1); got != 0 {
+		fmt.Printf("mod_uint8 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_uint8_ssa(255); got != 0 {
+		fmt.Printf("mod_uint8 0%s255 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint8_1_ssa(0); got != 0 {
+		fmt.Printf("mod_uint8 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_uint8_ssa(1); got != 0 {
+		fmt.Printf("mod_uint8 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint8_1_ssa(1); got != 0 {
+		fmt.Printf("mod_uint8 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_uint8_ssa(255); got != 1 {
+		fmt.Printf("mod_uint8 1%s255 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint8_1_ssa(255); got != 0 {
+		fmt.Printf("mod_uint8 255%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint8_255_ssa(0); got != 0 {
+		fmt.Printf("mod_uint8 0%s255 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_255_uint8_ssa(1); got != 0 {
+		fmt.Printf("mod_uint8 255%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint8_255_ssa(1); got != 1 {
+		fmt.Printf("mod_uint8 1%s255 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_255_uint8_ssa(255); got != 0 {
+		fmt.Printf("mod_uint8 255%s255 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_uint8_255_ssa(255); got != 0 {
+		fmt.Printf("mod_uint8 255%s255 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := add_Neg128_int8_ssa(-128); got != 0 {
+		fmt.Printf("add_int8 -128%s-128 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg128_ssa(-128); got != 0 {
+		fmt.Printf("add_int8 -128%s-128 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg128_int8_ssa(-127); got != 1 {
+		fmt.Printf("add_int8 -128%s-127 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg128_ssa(-127); got != 1 {
+		fmt.Printf("add_int8 -127%s-128 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg128_int8_ssa(-1); got != 127 {
+		fmt.Printf("add_int8 -128%s-1 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg128_ssa(-1); got != 127 {
+		fmt.Printf("add_int8 -1%s-128 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg128_int8_ssa(0); got != -128 {
+		fmt.Printf("add_int8 -128%s0 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg128_ssa(0); got != -128 {
+		fmt.Printf("add_int8 0%s-128 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg128_int8_ssa(1); got != -127 {
+		fmt.Printf("add_int8 -128%s1 = %d, wanted -127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg128_ssa(1); got != -127 {
+		fmt.Printf("add_int8 1%s-128 = %d, wanted -127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg128_int8_ssa(126); got != -2 {
+		fmt.Printf("add_int8 -128%s126 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg128_ssa(126); got != -2 {
+		fmt.Printf("add_int8 126%s-128 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg128_int8_ssa(127); got != -1 {
+		fmt.Printf("add_int8 -128%s127 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg128_ssa(127); got != -1 {
+		fmt.Printf("add_int8 127%s-128 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg127_int8_ssa(-128); got != 1 {
+		fmt.Printf("add_int8 -127%s-128 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg127_ssa(-128); got != 1 {
+		fmt.Printf("add_int8 -128%s-127 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg127_int8_ssa(-127); got != 2 {
+		fmt.Printf("add_int8 -127%s-127 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg127_ssa(-127); got != 2 {
+		fmt.Printf("add_int8 -127%s-127 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg127_int8_ssa(-1); got != -128 {
+		fmt.Printf("add_int8 -127%s-1 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg127_ssa(-1); got != -128 {
+		fmt.Printf("add_int8 -1%s-127 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg127_int8_ssa(0); got != -127 {
+		fmt.Printf("add_int8 -127%s0 = %d, wanted -127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg127_ssa(0); got != -127 {
+		fmt.Printf("add_int8 0%s-127 = %d, wanted -127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg127_int8_ssa(1); got != -126 {
+		fmt.Printf("add_int8 -127%s1 = %d, wanted -126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg127_ssa(1); got != -126 {
+		fmt.Printf("add_int8 1%s-127 = %d, wanted -126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg127_int8_ssa(126); got != -1 {
+		fmt.Printf("add_int8 -127%s126 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg127_ssa(126); got != -1 {
+		fmt.Printf("add_int8 126%s-127 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg127_int8_ssa(127); got != 0 {
+		fmt.Printf("add_int8 -127%s127 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg127_ssa(127); got != 0 {
+		fmt.Printf("add_int8 127%s-127 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int8_ssa(-128); got != 127 {
+		fmt.Printf("add_int8 -1%s-128 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg1_ssa(-128); got != 127 {
+		fmt.Printf("add_int8 -128%s-1 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int8_ssa(-127); got != -128 {
+		fmt.Printf("add_int8 -1%s-127 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg1_ssa(-127); got != -128 {
+		fmt.Printf("add_int8 -127%s-1 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int8_ssa(-1); got != -2 {
+		fmt.Printf("add_int8 -1%s-1 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg1_ssa(-1); got != -2 {
+		fmt.Printf("add_int8 -1%s-1 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int8_ssa(0); got != -1 {
+		fmt.Printf("add_int8 -1%s0 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg1_ssa(0); got != -1 {
+		fmt.Printf("add_int8 0%s-1 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int8_ssa(1); got != 0 {
+		fmt.Printf("add_int8 -1%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg1_ssa(1); got != 0 {
+		fmt.Printf("add_int8 1%s-1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int8_ssa(126); got != 125 {
+		fmt.Printf("add_int8 -1%s126 = %d, wanted 125\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg1_ssa(126); got != 125 {
+		fmt.Printf("add_int8 126%s-1 = %d, wanted 125\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_Neg1_int8_ssa(127); got != 126 {
+		fmt.Printf("add_int8 -1%s127 = %d, wanted 126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_Neg1_ssa(127); got != 126 {
+		fmt.Printf("add_int8 127%s-1 = %d, wanted 126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int8_ssa(-128); got != -128 {
+		fmt.Printf("add_int8 0%s-128 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_0_ssa(-128); got != -128 {
+		fmt.Printf("add_int8 -128%s0 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int8_ssa(-127); got != -127 {
+		fmt.Printf("add_int8 0%s-127 = %d, wanted -127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_0_ssa(-127); got != -127 {
+		fmt.Printf("add_int8 -127%s0 = %d, wanted -127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int8_ssa(-1); got != -1 {
+		fmt.Printf("add_int8 0%s-1 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_0_ssa(-1); got != -1 {
+		fmt.Printf("add_int8 -1%s0 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int8_ssa(0); got != 0 {
+		fmt.Printf("add_int8 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_0_ssa(0); got != 0 {
+		fmt.Printf("add_int8 0%s0 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int8_ssa(1); got != 1 {
+		fmt.Printf("add_int8 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_0_ssa(1); got != 1 {
+		fmt.Printf("add_int8 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int8_ssa(126); got != 126 {
+		fmt.Printf("add_int8 0%s126 = %d, wanted 126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_0_ssa(126); got != 126 {
+		fmt.Printf("add_int8 126%s0 = %d, wanted 126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_0_int8_ssa(127); got != 127 {
+		fmt.Printf("add_int8 0%s127 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_0_ssa(127); got != 127 {
+		fmt.Printf("add_int8 127%s0 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int8_ssa(-128); got != -127 {
+		fmt.Printf("add_int8 1%s-128 = %d, wanted -127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_1_ssa(-128); got != -127 {
+		fmt.Printf("add_int8 -128%s1 = %d, wanted -127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int8_ssa(-127); got != -126 {
+		fmt.Printf("add_int8 1%s-127 = %d, wanted -126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_1_ssa(-127); got != -126 {
+		fmt.Printf("add_int8 -127%s1 = %d, wanted -126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int8_ssa(-1); got != 0 {
+		fmt.Printf("add_int8 1%s-1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_1_ssa(-1); got != 0 {
+		fmt.Printf("add_int8 -1%s1 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int8_ssa(0); got != 1 {
+		fmt.Printf("add_int8 1%s0 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_1_ssa(0); got != 1 {
+		fmt.Printf("add_int8 0%s1 = %d, wanted 1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int8_ssa(1); got != 2 {
+		fmt.Printf("add_int8 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_1_ssa(1); got != 2 {
+		fmt.Printf("add_int8 1%s1 = %d, wanted 2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int8_ssa(126); got != 127 {
+		fmt.Printf("add_int8 1%s126 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_1_ssa(126); got != 127 {
+		fmt.Printf("add_int8 126%s1 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_1_int8_ssa(127); got != -128 {
+		fmt.Printf("add_int8 1%s127 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_1_ssa(127); got != -128 {
+		fmt.Printf("add_int8 127%s1 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_126_int8_ssa(-128); got != -2 {
+		fmt.Printf("add_int8 126%s-128 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_126_ssa(-128); got != -2 {
+		fmt.Printf("add_int8 -128%s126 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_126_int8_ssa(-127); got != -1 {
+		fmt.Printf("add_int8 126%s-127 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_126_ssa(-127); got != -1 {
+		fmt.Printf("add_int8 -127%s126 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_126_int8_ssa(-1); got != 125 {
+		fmt.Printf("add_int8 126%s-1 = %d, wanted 125\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_126_ssa(-1); got != 125 {
+		fmt.Printf("add_int8 -1%s126 = %d, wanted 125\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_126_int8_ssa(0); got != 126 {
+		fmt.Printf("add_int8 126%s0 = %d, wanted 126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_126_ssa(0); got != 126 {
+		fmt.Printf("add_int8 0%s126 = %d, wanted 126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_126_int8_ssa(1); got != 127 {
+		fmt.Printf("add_int8 126%s1 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_126_ssa(1); got != 127 {
+		fmt.Printf("add_int8 1%s126 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_126_int8_ssa(126); got != -4 {
+		fmt.Printf("add_int8 126%s126 = %d, wanted -4\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_126_ssa(126); got != -4 {
+		fmt.Printf("add_int8 126%s126 = %d, wanted -4\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_126_int8_ssa(127); got != -3 {
+		fmt.Printf("add_int8 126%s127 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_126_ssa(127); got != -3 {
+		fmt.Printf("add_int8 127%s126 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_127_int8_ssa(-128); got != -1 {
+		fmt.Printf("add_int8 127%s-128 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_127_ssa(-128); got != -1 {
+		fmt.Printf("add_int8 -128%s127 = %d, wanted -1\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_127_int8_ssa(-127); got != 0 {
+		fmt.Printf("add_int8 127%s-127 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_127_ssa(-127); got != 0 {
+		fmt.Printf("add_int8 -127%s127 = %d, wanted 0\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_127_int8_ssa(-1); got != 126 {
+		fmt.Printf("add_int8 127%s-1 = %d, wanted 126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_127_ssa(-1); got != 126 {
+		fmt.Printf("add_int8 -1%s127 = %d, wanted 126\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_127_int8_ssa(0); got != 127 {
+		fmt.Printf("add_int8 127%s0 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_127_ssa(0); got != 127 {
+		fmt.Printf("add_int8 0%s127 = %d, wanted 127\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_127_int8_ssa(1); got != -128 {
+		fmt.Printf("add_int8 127%s1 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_127_ssa(1); got != -128 {
+		fmt.Printf("add_int8 1%s127 = %d, wanted -128\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_127_int8_ssa(126); got != -3 {
+		fmt.Printf("add_int8 127%s126 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_127_ssa(126); got != -3 {
+		fmt.Printf("add_int8 126%s127 = %d, wanted -3\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_127_int8_ssa(127); got != -2 {
+		fmt.Printf("add_int8 127%s127 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := add_int8_127_ssa(127); got != -2 {
+		fmt.Printf("add_int8 127%s127 = %d, wanted -2\n", `+`, got)
+		failed = true
+	}
+
+	if got := sub_Neg128_int8_ssa(-128); got != 0 {
+		fmt.Printf("sub_int8 -128%s-128 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg128_ssa(-128); got != 0 {
+		fmt.Printf("sub_int8 -128%s-128 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg128_int8_ssa(-127); got != -1 {
+		fmt.Printf("sub_int8 -128%s-127 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg128_ssa(-127); got != 1 {
+		fmt.Printf("sub_int8 -127%s-128 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg128_int8_ssa(-1); got != -127 {
+		fmt.Printf("sub_int8 -128%s-1 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg128_ssa(-1); got != 127 {
+		fmt.Printf("sub_int8 -1%s-128 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg128_int8_ssa(0); got != -128 {
+		fmt.Printf("sub_int8 -128%s0 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg128_ssa(0); got != -128 {
+		fmt.Printf("sub_int8 0%s-128 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg128_int8_ssa(1); got != 127 {
+		fmt.Printf("sub_int8 -128%s1 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg128_ssa(1); got != -127 {
+		fmt.Printf("sub_int8 1%s-128 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg128_int8_ssa(126); got != 2 {
+		fmt.Printf("sub_int8 -128%s126 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg128_ssa(126); got != -2 {
+		fmt.Printf("sub_int8 126%s-128 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg128_int8_ssa(127); got != 1 {
+		fmt.Printf("sub_int8 -128%s127 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg128_ssa(127); got != -1 {
+		fmt.Printf("sub_int8 127%s-128 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg127_int8_ssa(-128); got != 1 {
+		fmt.Printf("sub_int8 -127%s-128 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg127_ssa(-128); got != -1 {
+		fmt.Printf("sub_int8 -128%s-127 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg127_int8_ssa(-127); got != 0 {
+		fmt.Printf("sub_int8 -127%s-127 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg127_ssa(-127); got != 0 {
+		fmt.Printf("sub_int8 -127%s-127 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg127_int8_ssa(-1); got != -126 {
+		fmt.Printf("sub_int8 -127%s-1 = %d, wanted -126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg127_ssa(-1); got != 126 {
+		fmt.Printf("sub_int8 -1%s-127 = %d, wanted 126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg127_int8_ssa(0); got != -127 {
+		fmt.Printf("sub_int8 -127%s0 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg127_ssa(0); got != 127 {
+		fmt.Printf("sub_int8 0%s-127 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg127_int8_ssa(1); got != -128 {
+		fmt.Printf("sub_int8 -127%s1 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg127_ssa(1); got != -128 {
+		fmt.Printf("sub_int8 1%s-127 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg127_int8_ssa(126); got != 3 {
+		fmt.Printf("sub_int8 -127%s126 = %d, wanted 3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg127_ssa(126); got != -3 {
+		fmt.Printf("sub_int8 126%s-127 = %d, wanted -3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg127_int8_ssa(127); got != 2 {
+		fmt.Printf("sub_int8 -127%s127 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg127_ssa(127); got != -2 {
+		fmt.Printf("sub_int8 127%s-127 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int8_ssa(-128); got != 127 {
+		fmt.Printf("sub_int8 -1%s-128 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg1_ssa(-128); got != -127 {
+		fmt.Printf("sub_int8 -128%s-1 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int8_ssa(-127); got != 126 {
+		fmt.Printf("sub_int8 -1%s-127 = %d, wanted 126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg1_ssa(-127); got != -126 {
+		fmt.Printf("sub_int8 -127%s-1 = %d, wanted -126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int8_ssa(-1); got != 0 {
+		fmt.Printf("sub_int8 -1%s-1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg1_ssa(-1); got != 0 {
+		fmt.Printf("sub_int8 -1%s-1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int8_ssa(0); got != -1 {
+		fmt.Printf("sub_int8 -1%s0 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg1_ssa(0); got != 1 {
+		fmt.Printf("sub_int8 0%s-1 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int8_ssa(1); got != -2 {
+		fmt.Printf("sub_int8 -1%s1 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg1_ssa(1); got != 2 {
+		fmt.Printf("sub_int8 1%s-1 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int8_ssa(126); got != -127 {
+		fmt.Printf("sub_int8 -1%s126 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg1_ssa(126); got != 127 {
+		fmt.Printf("sub_int8 126%s-1 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_Neg1_int8_ssa(127); got != -128 {
+		fmt.Printf("sub_int8 -1%s127 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_Neg1_ssa(127); got != -128 {
+		fmt.Printf("sub_int8 127%s-1 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int8_ssa(-128); got != -128 {
+		fmt.Printf("sub_int8 0%s-128 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_0_ssa(-128); got != -128 {
+		fmt.Printf("sub_int8 -128%s0 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int8_ssa(-127); got != 127 {
+		fmt.Printf("sub_int8 0%s-127 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_0_ssa(-127); got != -127 {
+		fmt.Printf("sub_int8 -127%s0 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int8_ssa(-1); got != 1 {
+		fmt.Printf("sub_int8 0%s-1 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_0_ssa(-1); got != -1 {
+		fmt.Printf("sub_int8 -1%s0 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int8_ssa(0); got != 0 {
+		fmt.Printf("sub_int8 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_0_ssa(0); got != 0 {
+		fmt.Printf("sub_int8 0%s0 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int8_ssa(1); got != -1 {
+		fmt.Printf("sub_int8 0%s1 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_0_ssa(1); got != 1 {
+		fmt.Printf("sub_int8 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int8_ssa(126); got != -126 {
+		fmt.Printf("sub_int8 0%s126 = %d, wanted -126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_0_ssa(126); got != 126 {
+		fmt.Printf("sub_int8 126%s0 = %d, wanted 126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_0_int8_ssa(127); got != -127 {
+		fmt.Printf("sub_int8 0%s127 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_0_ssa(127); got != 127 {
+		fmt.Printf("sub_int8 127%s0 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int8_ssa(-128); got != -127 {
+		fmt.Printf("sub_int8 1%s-128 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_1_ssa(-128); got != 127 {
+		fmt.Printf("sub_int8 -128%s1 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int8_ssa(-127); got != -128 {
+		fmt.Printf("sub_int8 1%s-127 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_1_ssa(-127); got != -128 {
+		fmt.Printf("sub_int8 -127%s1 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int8_ssa(-1); got != 2 {
+		fmt.Printf("sub_int8 1%s-1 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_1_ssa(-1); got != -2 {
+		fmt.Printf("sub_int8 -1%s1 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int8_ssa(0); got != 1 {
+		fmt.Printf("sub_int8 1%s0 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_1_ssa(0); got != -1 {
+		fmt.Printf("sub_int8 0%s1 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int8_ssa(1); got != 0 {
+		fmt.Printf("sub_int8 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_1_ssa(1); got != 0 {
+		fmt.Printf("sub_int8 1%s1 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int8_ssa(126); got != -125 {
+		fmt.Printf("sub_int8 1%s126 = %d, wanted -125\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_1_ssa(126); got != 125 {
+		fmt.Printf("sub_int8 126%s1 = %d, wanted 125\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_1_int8_ssa(127); got != -126 {
+		fmt.Printf("sub_int8 1%s127 = %d, wanted -126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_1_ssa(127); got != 126 {
+		fmt.Printf("sub_int8 127%s1 = %d, wanted 126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_126_int8_ssa(-128); got != -2 {
+		fmt.Printf("sub_int8 126%s-128 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_126_ssa(-128); got != 2 {
+		fmt.Printf("sub_int8 -128%s126 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_126_int8_ssa(-127); got != -3 {
+		fmt.Printf("sub_int8 126%s-127 = %d, wanted -3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_126_ssa(-127); got != 3 {
+		fmt.Printf("sub_int8 -127%s126 = %d, wanted 3\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_126_int8_ssa(-1); got != 127 {
+		fmt.Printf("sub_int8 126%s-1 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_126_ssa(-1); got != -127 {
+		fmt.Printf("sub_int8 -1%s126 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_126_int8_ssa(0); got != 126 {
+		fmt.Printf("sub_int8 126%s0 = %d, wanted 126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_126_ssa(0); got != -126 {
+		fmt.Printf("sub_int8 0%s126 = %d, wanted -126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_126_int8_ssa(1); got != 125 {
+		fmt.Printf("sub_int8 126%s1 = %d, wanted 125\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_126_ssa(1); got != -125 {
+		fmt.Printf("sub_int8 1%s126 = %d, wanted -125\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_126_int8_ssa(126); got != 0 {
+		fmt.Printf("sub_int8 126%s126 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_126_ssa(126); got != 0 {
+		fmt.Printf("sub_int8 126%s126 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_126_int8_ssa(127); got != -1 {
+		fmt.Printf("sub_int8 126%s127 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_126_ssa(127); got != 1 {
+		fmt.Printf("sub_int8 127%s126 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_127_int8_ssa(-128); got != -1 {
+		fmt.Printf("sub_int8 127%s-128 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_127_ssa(-128); got != 1 {
+		fmt.Printf("sub_int8 -128%s127 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_127_int8_ssa(-127); got != -2 {
+		fmt.Printf("sub_int8 127%s-127 = %d, wanted -2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_127_ssa(-127); got != 2 {
+		fmt.Printf("sub_int8 -127%s127 = %d, wanted 2\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_127_int8_ssa(-1); got != -128 {
+		fmt.Printf("sub_int8 127%s-1 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_127_ssa(-1); got != -128 {
+		fmt.Printf("sub_int8 -1%s127 = %d, wanted -128\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_127_int8_ssa(0); got != 127 {
+		fmt.Printf("sub_int8 127%s0 = %d, wanted 127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_127_ssa(0); got != -127 {
+		fmt.Printf("sub_int8 0%s127 = %d, wanted -127\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_127_int8_ssa(1); got != 126 {
+		fmt.Printf("sub_int8 127%s1 = %d, wanted 126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_127_ssa(1); got != -126 {
+		fmt.Printf("sub_int8 1%s127 = %d, wanted -126\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_127_int8_ssa(126); got != 1 {
+		fmt.Printf("sub_int8 127%s126 = %d, wanted 1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_127_ssa(126); got != -1 {
+		fmt.Printf("sub_int8 126%s127 = %d, wanted -1\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_127_int8_ssa(127); got != 0 {
+		fmt.Printf("sub_int8 127%s127 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := sub_int8_127_ssa(127); got != 0 {
+		fmt.Printf("sub_int8 127%s127 = %d, wanted 0\n", `-`, got)
+		failed = true
+	}
+
+	if got := div_Neg128_int8_ssa(-128); got != 1 {
+		fmt.Printf("div_int8 -128%s-128 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg128_ssa(-128); got != 1 {
+		fmt.Printf("div_int8 -128%s-128 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg128_int8_ssa(-127); got != 1 {
+		fmt.Printf("div_int8 -128%s-127 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg128_ssa(-127); got != 0 {
+		fmt.Printf("div_int8 -127%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg128_int8_ssa(-1); got != -128 {
+		fmt.Printf("div_int8 -128%s-1 = %d, wanted -128\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg128_ssa(-1); got != 0 {
+		fmt.Printf("div_int8 -1%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg128_ssa(0); got != 0 {
+		fmt.Printf("div_int8 0%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg128_int8_ssa(1); got != -128 {
+		fmt.Printf("div_int8 -128%s1 = %d, wanted -128\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg128_ssa(1); got != 0 {
+		fmt.Printf("div_int8 1%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg128_int8_ssa(126); got != -1 {
+		fmt.Printf("div_int8 -128%s126 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg128_ssa(126); got != 0 {
+		fmt.Printf("div_int8 126%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg128_int8_ssa(127); got != -1 {
+		fmt.Printf("div_int8 -128%s127 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg128_ssa(127); got != 0 {
+		fmt.Printf("div_int8 127%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg127_int8_ssa(-128); got != 0 {
+		fmt.Printf("div_int8 -127%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg127_ssa(-128); got != 1 {
+		fmt.Printf("div_int8 -128%s-127 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg127_int8_ssa(-127); got != 1 {
+		fmt.Printf("div_int8 -127%s-127 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg127_ssa(-127); got != 1 {
+		fmt.Printf("div_int8 -127%s-127 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg127_int8_ssa(-1); got != 127 {
+		fmt.Printf("div_int8 -127%s-1 = %d, wanted 127\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg127_ssa(-1); got != 0 {
+		fmt.Printf("div_int8 -1%s-127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg127_ssa(0); got != 0 {
+		fmt.Printf("div_int8 0%s-127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg127_int8_ssa(1); got != -127 {
+		fmt.Printf("div_int8 -127%s1 = %d, wanted -127\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg127_ssa(1); got != 0 {
+		fmt.Printf("div_int8 1%s-127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg127_int8_ssa(126); got != -1 {
+		fmt.Printf("div_int8 -127%s126 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg127_ssa(126); got != 0 {
+		fmt.Printf("div_int8 126%s-127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg127_int8_ssa(127); got != -1 {
+		fmt.Printf("div_int8 -127%s127 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg127_ssa(127); got != -1 {
+		fmt.Printf("div_int8 127%s-127 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int8_ssa(-128); got != 0 {
+		fmt.Printf("div_int8 -1%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg1_ssa(-128); got != -128 {
+		fmt.Printf("div_int8 -128%s-1 = %d, wanted -128\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int8_ssa(-127); got != 0 {
+		fmt.Printf("div_int8 -1%s-127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg1_ssa(-127); got != 127 {
+		fmt.Printf("div_int8 -127%s-1 = %d, wanted 127\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int8_ssa(-1); got != 1 {
+		fmt.Printf("div_int8 -1%s-1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg1_ssa(-1); got != 1 {
+		fmt.Printf("div_int8 -1%s-1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg1_ssa(0); got != 0 {
+		fmt.Printf("div_int8 0%s-1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int8_ssa(1); got != -1 {
+		fmt.Printf("div_int8 -1%s1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg1_ssa(1); got != -1 {
+		fmt.Printf("div_int8 1%s-1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int8_ssa(126); got != 0 {
+		fmt.Printf("div_int8 -1%s126 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg1_ssa(126); got != -126 {
+		fmt.Printf("div_int8 126%s-1 = %d, wanted -126\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_Neg1_int8_ssa(127); got != 0 {
+		fmt.Printf("div_int8 -1%s127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_Neg1_ssa(127); got != -127 {
+		fmt.Printf("div_int8 127%s-1 = %d, wanted -127\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int8_ssa(-128); got != 0 {
+		fmt.Printf("div_int8 0%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int8_ssa(-127); got != 0 {
+		fmt.Printf("div_int8 0%s-127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int8_ssa(-1); got != 0 {
+		fmt.Printf("div_int8 0%s-1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int8_ssa(1); got != 0 {
+		fmt.Printf("div_int8 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int8_ssa(126); got != 0 {
+		fmt.Printf("div_int8 0%s126 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_0_int8_ssa(127); got != 0 {
+		fmt.Printf("div_int8 0%s127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int8_ssa(-128); got != 0 {
+		fmt.Printf("div_int8 1%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_1_ssa(-128); got != -128 {
+		fmt.Printf("div_int8 -128%s1 = %d, wanted -128\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int8_ssa(-127); got != 0 {
+		fmt.Printf("div_int8 1%s-127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_1_ssa(-127); got != -127 {
+		fmt.Printf("div_int8 -127%s1 = %d, wanted -127\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int8_ssa(-1); got != -1 {
+		fmt.Printf("div_int8 1%s-1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_1_ssa(-1); got != -1 {
+		fmt.Printf("div_int8 -1%s1 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_1_ssa(0); got != 0 {
+		fmt.Printf("div_int8 0%s1 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int8_ssa(1); got != 1 {
+		fmt.Printf("div_int8 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_1_ssa(1); got != 1 {
+		fmt.Printf("div_int8 1%s1 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int8_ssa(126); got != 0 {
+		fmt.Printf("div_int8 1%s126 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_1_ssa(126); got != 126 {
+		fmt.Printf("div_int8 126%s1 = %d, wanted 126\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_1_int8_ssa(127); got != 0 {
+		fmt.Printf("div_int8 1%s127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_1_ssa(127); got != 127 {
+		fmt.Printf("div_int8 127%s1 = %d, wanted 127\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_126_int8_ssa(-128); got != 0 {
+		fmt.Printf("div_int8 126%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_126_ssa(-128); got != -1 {
+		fmt.Printf("div_int8 -128%s126 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_126_int8_ssa(-127); got != 0 {
+		fmt.Printf("div_int8 126%s-127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_126_ssa(-127); got != -1 {
+		fmt.Printf("div_int8 -127%s126 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_126_int8_ssa(-1); got != -126 {
+		fmt.Printf("div_int8 126%s-1 = %d, wanted -126\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_126_ssa(-1); got != 0 {
+		fmt.Printf("div_int8 -1%s126 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_126_ssa(0); got != 0 {
+		fmt.Printf("div_int8 0%s126 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_126_int8_ssa(1); got != 126 {
+		fmt.Printf("div_int8 126%s1 = %d, wanted 126\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_126_ssa(1); got != 0 {
+		fmt.Printf("div_int8 1%s126 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_126_int8_ssa(126); got != 1 {
+		fmt.Printf("div_int8 126%s126 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_126_ssa(126); got != 1 {
+		fmt.Printf("div_int8 126%s126 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_126_int8_ssa(127); got != 0 {
+		fmt.Printf("div_int8 126%s127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_126_ssa(127); got != 1 {
+		fmt.Printf("div_int8 127%s126 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_127_int8_ssa(-128); got != 0 {
+		fmt.Printf("div_int8 127%s-128 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_127_ssa(-128); got != -1 {
+		fmt.Printf("div_int8 -128%s127 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_127_int8_ssa(-127); got != -1 {
+		fmt.Printf("div_int8 127%s-127 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_127_ssa(-127); got != -1 {
+		fmt.Printf("div_int8 -127%s127 = %d, wanted -1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_127_int8_ssa(-1); got != -127 {
+		fmt.Printf("div_int8 127%s-1 = %d, wanted -127\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_127_ssa(-1); got != 0 {
+		fmt.Printf("div_int8 -1%s127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_127_ssa(0); got != 0 {
+		fmt.Printf("div_int8 0%s127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_127_int8_ssa(1); got != 127 {
+		fmt.Printf("div_int8 127%s1 = %d, wanted 127\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_127_ssa(1); got != 0 {
+		fmt.Printf("div_int8 1%s127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_127_int8_ssa(126); got != 1 {
+		fmt.Printf("div_int8 127%s126 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_127_ssa(126); got != 0 {
+		fmt.Printf("div_int8 126%s127 = %d, wanted 0\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_127_int8_ssa(127); got != 1 {
+		fmt.Printf("div_int8 127%s127 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := div_int8_127_ssa(127); got != 1 {
+		fmt.Printf("div_int8 127%s127 = %d, wanted 1\n", `/`, got)
+		failed = true
+	}
+
+	if got := mul_Neg128_int8_ssa(-128); got != 0 {
+		fmt.Printf("mul_int8 -128%s-128 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg128_ssa(-128); got != 0 {
+		fmt.Printf("mul_int8 -128%s-128 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg128_int8_ssa(-127); got != -128 {
+		fmt.Printf("mul_int8 -128%s-127 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg128_ssa(-127); got != -128 {
+		fmt.Printf("mul_int8 -127%s-128 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg128_int8_ssa(-1); got != -128 {
+		fmt.Printf("mul_int8 -128%s-1 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg128_ssa(-1); got != -128 {
+		fmt.Printf("mul_int8 -1%s-128 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg128_int8_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 -128%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg128_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 0%s-128 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg128_int8_ssa(1); got != -128 {
+		fmt.Printf("mul_int8 -128%s1 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg128_ssa(1); got != -128 {
+		fmt.Printf("mul_int8 1%s-128 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg128_int8_ssa(126); got != 0 {
+		fmt.Printf("mul_int8 -128%s126 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg128_ssa(126); got != 0 {
+		fmt.Printf("mul_int8 126%s-128 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg128_int8_ssa(127); got != -128 {
+		fmt.Printf("mul_int8 -128%s127 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg128_ssa(127); got != -128 {
+		fmt.Printf("mul_int8 127%s-128 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg127_int8_ssa(-128); got != -128 {
+		fmt.Printf("mul_int8 -127%s-128 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg127_ssa(-128); got != -128 {
+		fmt.Printf("mul_int8 -128%s-127 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg127_int8_ssa(-127); got != 1 {
+		fmt.Printf("mul_int8 -127%s-127 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg127_ssa(-127); got != 1 {
+		fmt.Printf("mul_int8 -127%s-127 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg127_int8_ssa(-1); got != 127 {
+		fmt.Printf("mul_int8 -127%s-1 = %d, wanted 127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg127_ssa(-1); got != 127 {
+		fmt.Printf("mul_int8 -1%s-127 = %d, wanted 127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg127_int8_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 -127%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg127_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 0%s-127 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg127_int8_ssa(1); got != -127 {
+		fmt.Printf("mul_int8 -127%s1 = %d, wanted -127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg127_ssa(1); got != -127 {
+		fmt.Printf("mul_int8 1%s-127 = %d, wanted -127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg127_int8_ssa(126); got != 126 {
+		fmt.Printf("mul_int8 -127%s126 = %d, wanted 126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg127_ssa(126); got != 126 {
+		fmt.Printf("mul_int8 126%s-127 = %d, wanted 126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg127_int8_ssa(127); got != -1 {
+		fmt.Printf("mul_int8 -127%s127 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg127_ssa(127); got != -1 {
+		fmt.Printf("mul_int8 127%s-127 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int8_ssa(-128); got != -128 {
+		fmt.Printf("mul_int8 -1%s-128 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg1_ssa(-128); got != -128 {
+		fmt.Printf("mul_int8 -128%s-1 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int8_ssa(-127); got != 127 {
+		fmt.Printf("mul_int8 -1%s-127 = %d, wanted 127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg1_ssa(-127); got != 127 {
+		fmt.Printf("mul_int8 -127%s-1 = %d, wanted 127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int8_ssa(-1); got != 1 {
+		fmt.Printf("mul_int8 -1%s-1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg1_ssa(-1); got != 1 {
+		fmt.Printf("mul_int8 -1%s-1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int8_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 -1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg1_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 0%s-1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int8_ssa(1); got != -1 {
+		fmt.Printf("mul_int8 -1%s1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg1_ssa(1); got != -1 {
+		fmt.Printf("mul_int8 1%s-1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int8_ssa(126); got != -126 {
+		fmt.Printf("mul_int8 -1%s126 = %d, wanted -126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg1_ssa(126); got != -126 {
+		fmt.Printf("mul_int8 126%s-1 = %d, wanted -126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_Neg1_int8_ssa(127); got != -127 {
+		fmt.Printf("mul_int8 -1%s127 = %d, wanted -127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_Neg1_ssa(127); got != -127 {
+		fmt.Printf("mul_int8 127%s-1 = %d, wanted -127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int8_ssa(-128); got != 0 {
+		fmt.Printf("mul_int8 0%s-128 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_0_ssa(-128); got != 0 {
+		fmt.Printf("mul_int8 -128%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int8_ssa(-127); got != 0 {
+		fmt.Printf("mul_int8 0%s-127 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_0_ssa(-127); got != 0 {
+		fmt.Printf("mul_int8 -127%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int8_ssa(-1); got != 0 {
+		fmt.Printf("mul_int8 0%s-1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_0_ssa(-1); got != 0 {
+		fmt.Printf("mul_int8 -1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int8_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_0_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 0%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int8_ssa(1); got != 0 {
+		fmt.Printf("mul_int8 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_0_ssa(1); got != 0 {
+		fmt.Printf("mul_int8 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int8_ssa(126); got != 0 {
+		fmt.Printf("mul_int8 0%s126 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_0_ssa(126); got != 0 {
+		fmt.Printf("mul_int8 126%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_0_int8_ssa(127); got != 0 {
+		fmt.Printf("mul_int8 0%s127 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_0_ssa(127); got != 0 {
+		fmt.Printf("mul_int8 127%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int8_ssa(-128); got != -128 {
+		fmt.Printf("mul_int8 1%s-128 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_1_ssa(-128); got != -128 {
+		fmt.Printf("mul_int8 -128%s1 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int8_ssa(-127); got != -127 {
+		fmt.Printf("mul_int8 1%s-127 = %d, wanted -127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_1_ssa(-127); got != -127 {
+		fmt.Printf("mul_int8 -127%s1 = %d, wanted -127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int8_ssa(-1); got != -1 {
+		fmt.Printf("mul_int8 1%s-1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_1_ssa(-1); got != -1 {
+		fmt.Printf("mul_int8 -1%s1 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int8_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 1%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_1_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 0%s1 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int8_ssa(1); got != 1 {
+		fmt.Printf("mul_int8 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_1_ssa(1); got != 1 {
+		fmt.Printf("mul_int8 1%s1 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int8_ssa(126); got != 126 {
+		fmt.Printf("mul_int8 1%s126 = %d, wanted 126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_1_ssa(126); got != 126 {
+		fmt.Printf("mul_int8 126%s1 = %d, wanted 126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_1_int8_ssa(127); got != 127 {
+		fmt.Printf("mul_int8 1%s127 = %d, wanted 127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_1_ssa(127); got != 127 {
+		fmt.Printf("mul_int8 127%s1 = %d, wanted 127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_126_int8_ssa(-128); got != 0 {
+		fmt.Printf("mul_int8 126%s-128 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_126_ssa(-128); got != 0 {
+		fmt.Printf("mul_int8 -128%s126 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_126_int8_ssa(-127); got != 126 {
+		fmt.Printf("mul_int8 126%s-127 = %d, wanted 126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_126_ssa(-127); got != 126 {
+		fmt.Printf("mul_int8 -127%s126 = %d, wanted 126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_126_int8_ssa(-1); got != -126 {
+		fmt.Printf("mul_int8 126%s-1 = %d, wanted -126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_126_ssa(-1); got != -126 {
+		fmt.Printf("mul_int8 -1%s126 = %d, wanted -126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_126_int8_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 126%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_126_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 0%s126 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_126_int8_ssa(1); got != 126 {
+		fmt.Printf("mul_int8 126%s1 = %d, wanted 126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_126_ssa(1); got != 126 {
+		fmt.Printf("mul_int8 1%s126 = %d, wanted 126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_126_int8_ssa(126); got != 4 {
+		fmt.Printf("mul_int8 126%s126 = %d, wanted 4\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_126_ssa(126); got != 4 {
+		fmt.Printf("mul_int8 126%s126 = %d, wanted 4\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_126_int8_ssa(127); got != -126 {
+		fmt.Printf("mul_int8 126%s127 = %d, wanted -126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_126_ssa(127); got != -126 {
+		fmt.Printf("mul_int8 127%s126 = %d, wanted -126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_127_int8_ssa(-128); got != -128 {
+		fmt.Printf("mul_int8 127%s-128 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_127_ssa(-128); got != -128 {
+		fmt.Printf("mul_int8 -128%s127 = %d, wanted -128\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_127_int8_ssa(-127); got != -1 {
+		fmt.Printf("mul_int8 127%s-127 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_127_ssa(-127); got != -1 {
+		fmt.Printf("mul_int8 -127%s127 = %d, wanted -1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_127_int8_ssa(-1); got != -127 {
+		fmt.Printf("mul_int8 127%s-1 = %d, wanted -127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_127_ssa(-1); got != -127 {
+		fmt.Printf("mul_int8 -1%s127 = %d, wanted -127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_127_int8_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 127%s0 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_127_ssa(0); got != 0 {
+		fmt.Printf("mul_int8 0%s127 = %d, wanted 0\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_127_int8_ssa(1); got != 127 {
+		fmt.Printf("mul_int8 127%s1 = %d, wanted 127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_127_ssa(1); got != 127 {
+		fmt.Printf("mul_int8 1%s127 = %d, wanted 127\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_127_int8_ssa(126); got != -126 {
+		fmt.Printf("mul_int8 127%s126 = %d, wanted -126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_127_ssa(126); got != -126 {
+		fmt.Printf("mul_int8 126%s127 = %d, wanted -126\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_127_int8_ssa(127); got != 1 {
+		fmt.Printf("mul_int8 127%s127 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mul_int8_127_ssa(127); got != 1 {
+		fmt.Printf("mul_int8 127%s127 = %d, wanted 1\n", `*`, got)
+		failed = true
+	}
+
+	if got := mod_Neg128_int8_ssa(-128); got != 0 {
+		fmt.Printf("mod_int8 -128%s-128 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg128_ssa(-128); got != 0 {
+		fmt.Printf("mod_int8 -128%s-128 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg128_int8_ssa(-127); got != -1 {
+		fmt.Printf("mod_int8 -128%s-127 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg128_ssa(-127); got != -127 {
+		fmt.Printf("mod_int8 -127%s-128 = %d, wanted -127\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg128_int8_ssa(-1); got != 0 {
+		fmt.Printf("mod_int8 -128%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg128_ssa(-1); got != -1 {
+		fmt.Printf("mod_int8 -1%s-128 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg128_ssa(0); got != 0 {
+		fmt.Printf("mod_int8 0%s-128 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg128_int8_ssa(1); got != 0 {
+		fmt.Printf("mod_int8 -128%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg128_ssa(1); got != 1 {
+		fmt.Printf("mod_int8 1%s-128 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg128_int8_ssa(126); got != -2 {
+		fmt.Printf("mod_int8 -128%s126 = %d, wanted -2\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg128_ssa(126); got != 126 {
+		fmt.Printf("mod_int8 126%s-128 = %d, wanted 126\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg128_int8_ssa(127); got != -1 {
+		fmt.Printf("mod_int8 -128%s127 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg128_ssa(127); got != 127 {
+		fmt.Printf("mod_int8 127%s-128 = %d, wanted 127\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg127_int8_ssa(-128); got != -127 {
+		fmt.Printf("mod_int8 -127%s-128 = %d, wanted -127\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg127_ssa(-128); got != -1 {
+		fmt.Printf("mod_int8 -128%s-127 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg127_int8_ssa(-127); got != 0 {
+		fmt.Printf("mod_int8 -127%s-127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg127_ssa(-127); got != 0 {
+		fmt.Printf("mod_int8 -127%s-127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg127_int8_ssa(-1); got != 0 {
+		fmt.Printf("mod_int8 -127%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg127_ssa(-1); got != -1 {
+		fmt.Printf("mod_int8 -1%s-127 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg127_ssa(0); got != 0 {
+		fmt.Printf("mod_int8 0%s-127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg127_int8_ssa(1); got != 0 {
+		fmt.Printf("mod_int8 -127%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg127_ssa(1); got != 1 {
+		fmt.Printf("mod_int8 1%s-127 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg127_int8_ssa(126); got != -1 {
+		fmt.Printf("mod_int8 -127%s126 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg127_ssa(126); got != 126 {
+		fmt.Printf("mod_int8 126%s-127 = %d, wanted 126\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg127_int8_ssa(127); got != 0 {
+		fmt.Printf("mod_int8 -127%s127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg127_ssa(127); got != 0 {
+		fmt.Printf("mod_int8 127%s-127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int8_ssa(-128); got != -1 {
+		fmt.Printf("mod_int8 -1%s-128 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg1_ssa(-128); got != 0 {
+		fmt.Printf("mod_int8 -128%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int8_ssa(-127); got != -1 {
+		fmt.Printf("mod_int8 -1%s-127 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg1_ssa(-127); got != 0 {
+		fmt.Printf("mod_int8 -127%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int8_ssa(-1); got != 0 {
+		fmt.Printf("mod_int8 -1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg1_ssa(-1); got != 0 {
+		fmt.Printf("mod_int8 -1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg1_ssa(0); got != 0 {
+		fmt.Printf("mod_int8 0%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int8_ssa(1); got != 0 {
+		fmt.Printf("mod_int8 -1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg1_ssa(1); got != 0 {
+		fmt.Printf("mod_int8 1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int8_ssa(126); got != -1 {
+		fmt.Printf("mod_int8 -1%s126 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg1_ssa(126); got != 0 {
+		fmt.Printf("mod_int8 126%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_Neg1_int8_ssa(127); got != -1 {
+		fmt.Printf("mod_int8 -1%s127 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_Neg1_ssa(127); got != 0 {
+		fmt.Printf("mod_int8 127%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int8_ssa(-128); got != 0 {
+		fmt.Printf("mod_int8 0%s-128 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int8_ssa(-127); got != 0 {
+		fmt.Printf("mod_int8 0%s-127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int8_ssa(-1); got != 0 {
+		fmt.Printf("mod_int8 0%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int8_ssa(1); got != 0 {
+		fmt.Printf("mod_int8 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int8_ssa(126); got != 0 {
+		fmt.Printf("mod_int8 0%s126 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_0_int8_ssa(127); got != 0 {
+		fmt.Printf("mod_int8 0%s127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int8_ssa(-128); got != 1 {
+		fmt.Printf("mod_int8 1%s-128 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_1_ssa(-128); got != 0 {
+		fmt.Printf("mod_int8 -128%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int8_ssa(-127); got != 1 {
+		fmt.Printf("mod_int8 1%s-127 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_1_ssa(-127); got != 0 {
+		fmt.Printf("mod_int8 -127%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int8_ssa(-1); got != 0 {
+		fmt.Printf("mod_int8 1%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_1_ssa(-1); got != 0 {
+		fmt.Printf("mod_int8 -1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_1_ssa(0); got != 0 {
+		fmt.Printf("mod_int8 0%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int8_ssa(1); got != 0 {
+		fmt.Printf("mod_int8 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_1_ssa(1); got != 0 {
+		fmt.Printf("mod_int8 1%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int8_ssa(126); got != 1 {
+		fmt.Printf("mod_int8 1%s126 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_1_ssa(126); got != 0 {
+		fmt.Printf("mod_int8 126%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_1_int8_ssa(127); got != 1 {
+		fmt.Printf("mod_int8 1%s127 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_1_ssa(127); got != 0 {
+		fmt.Printf("mod_int8 127%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_126_int8_ssa(-128); got != 126 {
+		fmt.Printf("mod_int8 126%s-128 = %d, wanted 126\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_126_ssa(-128); got != -2 {
+		fmt.Printf("mod_int8 -128%s126 = %d, wanted -2\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_126_int8_ssa(-127); got != 126 {
+		fmt.Printf("mod_int8 126%s-127 = %d, wanted 126\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_126_ssa(-127); got != -1 {
+		fmt.Printf("mod_int8 -127%s126 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_126_int8_ssa(-1); got != 0 {
+		fmt.Printf("mod_int8 126%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_126_ssa(-1); got != -1 {
+		fmt.Printf("mod_int8 -1%s126 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_126_ssa(0); got != 0 {
+		fmt.Printf("mod_int8 0%s126 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_126_int8_ssa(1); got != 0 {
+		fmt.Printf("mod_int8 126%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_126_ssa(1); got != 1 {
+		fmt.Printf("mod_int8 1%s126 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_126_int8_ssa(126); got != 0 {
+		fmt.Printf("mod_int8 126%s126 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_126_ssa(126); got != 0 {
+		fmt.Printf("mod_int8 126%s126 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_126_int8_ssa(127); got != 126 {
+		fmt.Printf("mod_int8 126%s127 = %d, wanted 126\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_126_ssa(127); got != 1 {
+		fmt.Printf("mod_int8 127%s126 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_127_int8_ssa(-128); got != 127 {
+		fmt.Printf("mod_int8 127%s-128 = %d, wanted 127\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_127_ssa(-128); got != -1 {
+		fmt.Printf("mod_int8 -128%s127 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_127_int8_ssa(-127); got != 0 {
+		fmt.Printf("mod_int8 127%s-127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_127_ssa(-127); got != 0 {
+		fmt.Printf("mod_int8 -127%s127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_127_int8_ssa(-1); got != 0 {
+		fmt.Printf("mod_int8 127%s-1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_127_ssa(-1); got != -1 {
+		fmt.Printf("mod_int8 -1%s127 = %d, wanted -1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_127_ssa(0); got != 0 {
+		fmt.Printf("mod_int8 0%s127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_127_int8_ssa(1); got != 0 {
+		fmt.Printf("mod_int8 127%s1 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_127_ssa(1); got != 1 {
+		fmt.Printf("mod_int8 1%s127 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_127_int8_ssa(126); got != 1 {
+		fmt.Printf("mod_int8 127%s126 = %d, wanted 1\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_127_ssa(126); got != 126 {
+		fmt.Printf("mod_int8 126%s127 = %d, wanted 126\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_127_int8_ssa(127); got != 0 {
+		fmt.Printf("mod_int8 127%s127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+
+	if got := mod_int8_127_ssa(127); got != 0 {
+		fmt.Printf("mod_int8 127%s127 = %d, wanted 0\n", `%`, got)
+		failed = true
+	}
+	if failed {
+		panic("tests failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/arith_ssa.go b/src/cmd/compile/internal/gc/testdata/arith_ssa.go
new file mode 100644
index 0000000..7c82bbd
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/arith_ssa.go
@@ -0,0 +1,580 @@
+// 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.
+
+// Tests arithmetic expressions
+
+package main
+
+import "fmt"
+
+const (
+	y = 0x0fffFFFF
+)
+
+//go:noinline
+func lshNop1(x uint64) uint64 {
+	// two outer shifts should be removed
+	return (((x << 5) >> 2) << 2)
+}
+
+//go:noinline
+func lshNop2(x uint64) uint64 {
+	return (((x << 5) >> 2) << 3)
+}
+
+//go:noinline
+func lshNop3(x uint64) uint64 {
+	return (((x << 5) >> 2) << 6)
+}
+
+//go:noinline
+func lshNotNop(x uint64) uint64 {
+	// outer shift can't be removed
+	return (((x << 5) >> 2) << 1)
+}
+
+//go:noinline
+func rshNop1(x uint64) uint64 {
+	return (((x >> 5) << 2) >> 2)
+}
+
+//go:noinline
+func rshNop2(x uint64) uint64 {
+	return (((x >> 5) << 2) >> 3)
+}
+
+//go:noinline
+func rshNop3(x uint64) uint64 {
+	return (((x >> 5) << 2) >> 6)
+}
+
+//go:noinline
+func rshNotNop(x uint64) uint64 {
+	return (((x >> 5) << 2) >> 1)
+}
+
+func testShiftRemoval() {
+	allSet := ^uint64(0)
+	if want, got := uint64(0x7ffffffffffffff), rshNop1(allSet); want != got {
+		println("testShiftRemoval rshNop1 failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint64(0x3ffffffffffffff), rshNop2(allSet); want != got {
+		println("testShiftRemoval rshNop2 failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint64(0x7fffffffffffff), rshNop3(allSet); want != got {
+		println("testShiftRemoval rshNop3 failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint64(0xffffffffffffffe), rshNotNop(allSet); want != got {
+		println("testShiftRemoval rshNotNop failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint64(0xffffffffffffffe0), lshNop1(allSet); want != got {
+		println("testShiftRemoval lshNop1 failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint64(0xffffffffffffffc0), lshNop2(allSet); want != got {
+		println("testShiftRemoval lshNop2 failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint64(0xfffffffffffffe00), lshNop3(allSet); want != got {
+		println("testShiftRemoval lshNop3 failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint64(0x7ffffffffffffff0), lshNotNop(allSet); want != got {
+		println("testShiftRemoval lshNotNop failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+//go:noinline
+func parseLE64(b []byte) uint64 {
+	// skip the first two bytes, and parse the remaining 8 as a uint64
+	return uint64(b[2]) | uint64(b[3])<<8 | uint64(b[4])<<16 | uint64(b[5])<<24 |
+		uint64(b[6])<<32 | uint64(b[7])<<40 | uint64(b[8])<<48 | uint64(b[9])<<56
+}
+
+//go:noinline
+func parseLE32(b []byte) uint32 {
+	return uint32(b[2]) | uint32(b[3])<<8 | uint32(b[4])<<16 | uint32(b[5])<<24
+}
+
+//go:noinline
+func parseLE16(b []byte) uint16 {
+	return uint16(b[2]) | uint16(b[3])<<8
+}
+
+// testLoadCombine tests for issue #14694 where load combining didn't respect the pointer offset.
+func testLoadCombine() {
+	testData := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}
+	if want, got := uint64(0x0908070605040302), parseLE64(testData); want != got {
+		println("testLoadCombine failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint32(0x05040302), parseLE32(testData); want != got {
+		println("testLoadCombine failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint16(0x0302), parseLE16(testData); want != got {
+		println("testLoadCombine failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+var loadSymData = [...]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
+
+func testLoadSymCombine() {
+	w2 := uint16(0x0201)
+	g2 := uint16(loadSymData[0]) | uint16(loadSymData[1])<<8
+	if g2 != w2 {
+		println("testLoadSymCombine failed, wanted", w2, "got", g2)
+		failed = true
+	}
+	w4 := uint32(0x04030201)
+	g4 := uint32(loadSymData[0]) | uint32(loadSymData[1])<<8 |
+		uint32(loadSymData[2])<<16 | uint32(loadSymData[3])<<24
+	if g4 != w4 {
+		println("testLoadSymCombine failed, wanted", w4, "got", g4)
+		failed = true
+	}
+	w8 := uint64(0x0807060504030201)
+	g8 := uint64(loadSymData[0]) | uint64(loadSymData[1])<<8 |
+		uint64(loadSymData[2])<<16 | uint64(loadSymData[3])<<24 |
+		uint64(loadSymData[4])<<32 | uint64(loadSymData[5])<<40 |
+		uint64(loadSymData[6])<<48 | uint64(loadSymData[7])<<56
+	if g8 != w8 {
+		println("testLoadSymCombine failed, wanted", w8, "got", g8)
+		failed = true
+	}
+}
+
+//go:noinline
+func invalidAdd_ssa(x uint32) uint32 {
+	return x + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y
+}
+
+//go:noinline
+func invalidSub_ssa(x uint32) uint32 {
+	return x - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y
+}
+
+//go:noinline
+func invalidMul_ssa(x uint32) uint32 {
+	return x * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y
+}
+
+// testLargeConst tests a situation where larger than 32 bit consts were passed to ADDL
+// causing an invalid instruction error.
+func testLargeConst() {
+	if want, got := uint32(268435440), invalidAdd_ssa(1); want != got {
+		println("testLargeConst add failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint32(4026531858), invalidSub_ssa(1); want != got {
+		println("testLargeConst sub failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint32(268435455), invalidMul_ssa(1); want != got {
+		println("testLargeConst mul failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+// testArithRshConst ensures that "const >> const" right shifts correctly perform
+// sign extension on the lhs constant
+func testArithRshConst() {
+	wantu := uint64(0x4000000000000000)
+	if got := arithRshuConst_ssa(); got != wantu {
+		println("arithRshuConst failed, wanted", wantu, "got", got)
+		failed = true
+	}
+
+	wants := int64(-0x4000000000000000)
+	if got := arithRshConst_ssa(); got != wants {
+		println("arithRshuConst failed, wanted", wants, "got", got)
+		failed = true
+	}
+}
+
+//go:noinline
+func arithRshuConst_ssa() uint64 {
+	y := uint64(0x8000000000000001)
+	z := uint64(1)
+	return uint64(y >> z)
+}
+
+//go:noinline
+func arithRshConst_ssa() int64 {
+	y := int64(-0x8000000000000000)
+	z := uint64(1)
+	return int64(y >> z)
+}
+
+//go:noinline
+func arithConstShift_ssa(x int64) int64 {
+	return x >> 100
+}
+
+// testArithConstShift tests that right shift by large constants preserve
+// the sign of the input.
+func testArithConstShift() {
+	want := int64(-1)
+	if got := arithConstShift_ssa(-1); want != got {
+		println("arithConstShift_ssa(-1) failed, wanted", want, "got", got)
+		failed = true
+	}
+	want = 0
+	if got := arithConstShift_ssa(1); want != got {
+		println("arithConstShift_ssa(1) failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+// overflowConstShift_ssa verifes that constant folding for shift
+// doesn't wrap (i.e. x << MAX_INT << 1 doesn't get folded to x << 0).
+//go:noinline
+func overflowConstShift64_ssa(x int64) int64 {
+	return x << uint64(0xffffffffffffffff) << uint64(1)
+}
+
+//go:noinline
+func overflowConstShift32_ssa(x int64) int32 {
+	return int32(x) << uint32(0xffffffff) << uint32(1)
+}
+
+//go:noinline
+func overflowConstShift16_ssa(x int64) int16 {
+	return int16(x) << uint16(0xffff) << uint16(1)
+}
+
+//go:noinline
+func overflowConstShift8_ssa(x int64) int8 {
+	return int8(x) << uint8(0xff) << uint8(1)
+}
+
+func testOverflowConstShift() {
+	want := int64(0)
+	for x := int64(-127); x < int64(127); x++ {
+		got := overflowConstShift64_ssa(x)
+		if want != got {
+			fmt.Printf("overflowShift64 failed, wanted %d got %d\n", want, got)
+		}
+		got = int64(overflowConstShift32_ssa(x))
+		if want != got {
+			fmt.Printf("overflowShift32 failed, wanted %d got %d\n", want, got)
+		}
+		got = int64(overflowConstShift16_ssa(x))
+		if want != got {
+			fmt.Printf("overflowShift16 failed, wanted %d got %d\n", want, got)
+		}
+		got = int64(overflowConstShift8_ssa(x))
+		if want != got {
+			fmt.Printf("overflowShift8 failed, wanted %d got %d\n", want, got)
+		}
+	}
+}
+
+// test64BitConstMult tests that rewrite rules don't fold 64 bit constants
+// into multiply instructions.
+func test64BitConstMult() {
+	want := int64(103079215109)
+	if got := test64BitConstMult_ssa(1, 2); want != got {
+		println("test64BitConstMult failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+//go:noinline
+func test64BitConstMult_ssa(a, b int64) int64 {
+	return 34359738369*a + b*34359738370
+}
+
+// test64BitConstAdd tests that rewrite rules don't fold 64 bit constants
+// into add instructions.
+func test64BitConstAdd() {
+	want := int64(3567671782835376650)
+	if got := test64BitConstAdd_ssa(1, 2); want != got {
+		println("test64BitConstAdd failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+//go:noinline
+func test64BitConstAdd_ssa(a, b int64) int64 {
+	return a + 575815584948629622 + b + 2991856197886747025
+}
+
+// testRegallocCVSpill tests that regalloc spills a value whose last use is the
+// current value.
+func testRegallocCVSpill() {
+	want := int8(-9)
+	if got := testRegallocCVSpill_ssa(1, 2, 3, 4); want != got {
+		println("testRegallocCVSpill failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+//go:noinline
+func testRegallocCVSpill_ssa(a, b, c, d int8) int8 {
+	return a + -32 + b + 63*c*-87*d
+}
+
+func testBitwiseLogic() {
+	a, b := uint32(57623283), uint32(1314713839)
+	if want, got := uint32(38551779), testBitwiseAnd_ssa(a, b); want != got {
+		println("testBitwiseAnd failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint32(1333785343), testBitwiseOr_ssa(a, b); want != got {
+		println("testBitwiseOr failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint32(1295233564), testBitwiseXor_ssa(a, b); want != got {
+		println("testBitwiseXor failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := int32(832), testBitwiseLsh_ssa(13, 4, 2); want != got {
+		println("testBitwiseLsh failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := int32(0), testBitwiseLsh_ssa(13, 25, 15); want != got {
+		println("testBitwiseLsh failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := int32(0), testBitwiseLsh_ssa(-13, 25, 15); want != got {
+		println("testBitwiseLsh failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := int32(-13), testBitwiseRsh_ssa(-832, 4, 2); want != got {
+		println("testBitwiseRsh failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := int32(0), testBitwiseRsh_ssa(13, 25, 15); want != got {
+		println("testBitwiseRsh failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := int32(-1), testBitwiseRsh_ssa(-13, 25, 15); want != got {
+		println("testBitwiseRsh failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint32(0x3ffffff), testBitwiseRshU_ssa(0xffffffff, 4, 2); want != got {
+		println("testBitwiseRshU failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint32(0), testBitwiseRshU_ssa(13, 25, 15); want != got {
+		println("testBitwiseRshU failed, wanted", want, "got", got)
+		failed = true
+	}
+	if want, got := uint32(0), testBitwiseRshU_ssa(0x8aaaaaaa, 25, 15); want != got {
+		println("testBitwiseRshU failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+//go:noinline
+func testBitwiseAnd_ssa(a, b uint32) uint32 {
+	return a & b
+}
+
+//go:noinline
+func testBitwiseOr_ssa(a, b uint32) uint32 {
+	return a | b
+}
+
+//go:noinline
+func testBitwiseXor_ssa(a, b uint32) uint32 {
+	return a ^ b
+}
+
+//go:noinline
+func testBitwiseLsh_ssa(a int32, b, c uint32) int32 {
+	return a << b << c
+}
+
+//go:noinline
+func testBitwiseRsh_ssa(a int32, b, c uint32) int32 {
+	return a >> b >> c
+}
+
+//go:noinline
+func testBitwiseRshU_ssa(a uint32, b, c uint32) uint32 {
+	return a >> b >> c
+}
+
+//go:noinline
+func testShiftCX_ssa() int {
+	v1 := uint8(3)
+	v4 := (v1 * v1) ^ v1 | v1 - v1 - v1&v1 ^ uint8(3+2) + v1*1>>0 - v1 | 1 | v1<<(2*3|0-0*0^1)
+	v5 := v4>>(3-0-uint(3)) | v1 | v1 + v1 ^ v4<<(0+1|3&1)<<(uint64(1)<<0*2*0<<0) ^ v1
+	v6 := v5 ^ (v1+v1)*v1 | v1 | v1*v1>>(v1&v1)>>(uint(1)<<0*uint(3)>>1)*v1<<2*v1<<v1 - v1>>2 | (v4 - v1) ^ v1 + v1 ^ v1>>1 | v1 + v1 - v1 ^ v1
+	v7 := v6 & v5 << 0
+	v1++
+	v11 := 2&1 ^ 0 + 3 | int(0^0)<<1>>(1*0*3) ^ 0*0 ^ 3&0*3&3 ^ 3*3 ^ 1 ^ int(2)<<(2*3) + 2 | 2 | 2 ^ 2 + 1 | 3 | 0 ^ int(1)>>1 ^ 2 // int
+	v7--
+	return int(uint64(2*1)<<(3-2)<<uint(3>>v7)-2)&v11 | v11 - int(2)<<0>>(2-1)*(v11*0&v11<<1<<(uint8(2)+v4))
+}
+
+func testShiftCX() {
+	want := 141
+	if got := testShiftCX_ssa(); want != got {
+		println("testShiftCX failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+// testSubqToNegq ensures that the SUBQ -> NEGQ translation works correctly.
+func testSubqToNegq() {
+	want := int64(-318294940372190156)
+	if got := testSubqToNegq_ssa(1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2); want != got {
+		println("testSubqToNegq failed, wanted", want, "got", got)
+		failed = true
+	}
+}
+
+//go:noinline
+func testSubqToNegq_ssa(a, b, c, d, e, f, g, h, i, j, k int64) int64 {
+	return a + 8207351403619448057 - b - 1779494519303207690 + c*8810076340510052032*d - 4465874067674546219 - e*4361839741470334295 - f + 8688847565426072650*g*8065564729145417479
+}
+
+func testOcom() {
+	want1, want2 := int32(0x55555555), int32(-0x55555556)
+	if got1, got2 := testOcom_ssa(0x55555555, 0x55555555); want1 != got1 || want2 != got2 {
+		println("testSubqToNegq failed, wanted", want1, "and", want2,
+			"got", got1, "and", got2)
+		failed = true
+	}
+}
+
+//go:noinline
+func testOcom_ssa(a, b int32) (int32, int32) {
+	return ^^^^a, ^^^^^b
+}
+
+func lrot1_ssa(w uint8, x uint16, y uint32, z uint64) (a uint8, b uint16, c uint32, d uint64) {
+	a = (w << 5) | (w >> 3)
+	b = (x << 13) | (x >> 3)
+	c = (y << 29) | (y >> 3)
+	d = (z << 61) | (z >> 3)
+	return
+}
+
+//go:noinline
+func lrot2_ssa(w, n uint32) uint32 {
+	// Want to be sure that a "rotate by 32" which
+	// is really 0 | (w >> 0) == w
+	// is correctly compiled.
+	return (w << n) | (w >> (32 - n))
+}
+
+//go:noinline
+func lrot3_ssa(w uint32) uint32 {
+	// Want to be sure that a "rotate by 32" which
+	// is really 0 | (w >> 0) == w
+	// is correctly compiled.
+	return (w << 32) | (w >> (32 - 32))
+}
+
+func testLrot() {
+	wantA, wantB, wantC, wantD := uint8(0xe1), uint16(0xe001),
+		uint32(0xe0000001), uint64(0xe000000000000001)
+	a, b, c, d := lrot1_ssa(0xf, 0xf, 0xf, 0xf)
+	if a != wantA || b != wantB || c != wantC || d != wantD {
+		println("lrot1_ssa(0xf, 0xf, 0xf, 0xf)=",
+			wantA, wantB, wantC, wantD, ", got", a, b, c, d)
+		failed = true
+	}
+	x := lrot2_ssa(0xb0000001, 32)
+	wantX := uint32(0xb0000001)
+	if x != wantX {
+		println("lrot2_ssa(0xb0000001, 32)=",
+			wantX, ", got", x)
+		failed = true
+	}
+	x = lrot3_ssa(0xb0000001)
+	if x != wantX {
+		println("lrot3_ssa(0xb0000001)=",
+			wantX, ", got", x)
+		failed = true
+	}
+
+}
+
+//go:noinline
+func sub1_ssa() uint64 {
+	v1 := uint64(3) // uint64
+	return v1*v1 - (v1&v1)&v1
+}
+
+//go:noinline
+func sub2_ssa() uint8 {
+	v1 := uint8(0)
+	v3 := v1 + v1 + v1 ^ v1 | 3 + v1 ^ v1 | v1 ^ v1
+	v1-- // dev.ssa doesn't see this one
+	return v1 ^ v1*v1 - v3
+}
+
+func testSubConst() {
+	x1 := sub1_ssa()
+	want1 := uint64(6)
+	if x1 != want1 {
+		println("sub1_ssa()=", want1, ", got", x1)
+		failed = true
+	}
+	x2 := sub2_ssa()
+	want2 := uint8(251)
+	if x2 != want2 {
+		println("sub2_ssa()=", want2, ", got", x2)
+		failed = true
+	}
+}
+
+//go:noinline
+func orPhi_ssa(a bool, x int) int {
+	v := 0
+	if a {
+		v = -1
+	} else {
+		v = -1
+	}
+	return x | v
+}
+
+func testOrPhi() {
+	if want, got := -1, orPhi_ssa(true, 4); got != want {
+		println("orPhi_ssa(true, 4)=", got, " want ", want)
+	}
+	if want, got := -1, orPhi_ssa(false, 0); got != want {
+		println("orPhi_ssa(false, 0)=", got, " want ", want)
+	}
+}
+
+var failed = false
+
+func main() {
+
+	test64BitConstMult()
+	test64BitConstAdd()
+	testRegallocCVSpill()
+	testSubqToNegq()
+	testBitwiseLogic()
+	testOcom()
+	testLrot()
+	testShiftCX()
+	testSubConst()
+	testOverflowConstShift()
+	testArithConstShift()
+	testArithRshConst()
+	testLargeConst()
+	testLoadCombine()
+	testLoadSymCombine()
+	testShiftRemoval()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/array_ssa.go b/src/cmd/compile/internal/gc/testdata/array_ssa.go
new file mode 100644
index 0000000..0334339
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/array_ssa.go
@@ -0,0 +1,142 @@
+package main
+
+var failed = false
+
+//go:noinline
+func testSliceLenCap12_ssa(a [10]int, i, j int) (int, int) {
+	b := a[i:j]
+	return len(b), cap(b)
+}
+
+//go:noinline
+func testSliceLenCap1_ssa(a [10]int, i, j int) (int, int) {
+	b := a[i:]
+	return len(b), cap(b)
+}
+
+//go:noinline
+func testSliceLenCap2_ssa(a [10]int, i, j int) (int, int) {
+	b := a[:j]
+	return len(b), cap(b)
+}
+
+func testSliceLenCap() {
+	a := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+	tests := [...]struct {
+		fn   func(a [10]int, i, j int) (int, int)
+		i, j int // slice range
+		l, c int // len, cap
+	}{
+		// -1 means the value is not used.
+		{testSliceLenCap12_ssa, 0, 0, 0, 10},
+		{testSliceLenCap12_ssa, 0, 1, 1, 10},
+		{testSliceLenCap12_ssa, 0, 10, 10, 10},
+		{testSliceLenCap12_ssa, 10, 10, 0, 0},
+		{testSliceLenCap12_ssa, 0, 5, 5, 10},
+		{testSliceLenCap12_ssa, 5, 5, 0, 5},
+		{testSliceLenCap12_ssa, 5, 10, 5, 5},
+		{testSliceLenCap1_ssa, 0, -1, 0, 10},
+		{testSliceLenCap1_ssa, 5, -1, 5, 5},
+		{testSliceLenCap1_ssa, 10, -1, 0, 0},
+		{testSliceLenCap2_ssa, -1, 0, 0, 10},
+		{testSliceLenCap2_ssa, -1, 5, 5, 10},
+		{testSliceLenCap2_ssa, -1, 10, 10, 10},
+	}
+
+	for i, t := range tests {
+		if l, c := t.fn(a, t.i, t.j); l != t.l && c != t.c {
+			println("#", i, " len(a[", t.i, ":", t.j, "]), cap(a[", t.i, ":", t.j, "]) =", l, c,
+				", want", t.l, t.c)
+			failed = true
+		}
+	}
+}
+
+//go:noinline
+func testSliceGetElement_ssa(a [10]int, i, j, p int) int {
+	return a[i:j][p]
+}
+
+func testSliceGetElement() {
+	a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
+	tests := [...]struct {
+		i, j, p int
+		want    int // a[i:j][p]
+	}{
+		{0, 10, 2, 20},
+		{0, 5, 4, 40},
+		{5, 10, 3, 80},
+		{1, 9, 7, 80},
+	}
+
+	for i, t := range tests {
+		if got := testSliceGetElement_ssa(a, t.i, t.j, t.p); got != t.want {
+			println("#", i, " a[", t.i, ":", t.j, "][", t.p, "] = ", got, " wanted ", t.want)
+			failed = true
+		}
+	}
+}
+
+//go:noinline
+func testSliceSetElement_ssa(a *[10]int, i, j, p, x int) {
+	(*a)[i:j][p] = x
+}
+
+func testSliceSetElement() {
+	a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
+	tests := [...]struct {
+		i, j, p int
+		want    int // a[i:j][p]
+	}{
+		{0, 10, 2, 17},
+		{0, 5, 4, 11},
+		{5, 10, 3, 28},
+		{1, 9, 7, 99},
+	}
+
+	for i, t := range tests {
+		testSliceSetElement_ssa(&a, t.i, t.j, t.p, t.want)
+		if got := a[t.i+t.p]; got != t.want {
+			println("#", i, " a[", t.i, ":", t.j, "][", t.p, "] = ", got, " wanted ", t.want)
+			failed = true
+		}
+	}
+}
+
+func testSlicePanic1() {
+	defer func() {
+		if r := recover(); r != nil {
+			println("paniced as expected")
+		}
+	}()
+
+	a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
+	testSliceLenCap12_ssa(a, 3, 12)
+	println("expected to panic, but didn't")
+	failed = true
+}
+
+func testSlicePanic2() {
+	defer func() {
+		if r := recover(); r != nil {
+			println("paniced as expected")
+		}
+	}()
+
+	a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}
+	testSliceGetElement_ssa(a, 3, 7, 4)
+	println("expected to panic, but didn't")
+	failed = true
+}
+
+func main() {
+	testSliceLenCap()
+	testSliceGetElement()
+	testSliceSetElement()
+	testSlicePanic1()
+	testSlicePanic2()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/assert_ssa.go b/src/cmd/compile/internal/gc/testdata/assert_ssa.go
new file mode 100644
index 0000000..d64d4fc
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/assert_ssa.go
@@ -0,0 +1,147 @@
+// 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.
+
+// Tests type assertion expressions and statements
+
+package main
+
+import (
+	"fmt"
+	"runtime"
+)
+
+type (
+	S struct{}
+	T struct{}
+
+	I interface {
+		F()
+	}
+)
+
+var (
+	s *S
+	t *T
+)
+
+func (s *S) F() {}
+func (t *T) F() {}
+
+func e2t_ssa(e interface{}) *T {
+	return e.(*T)
+}
+
+func i2t_ssa(i I) *T {
+	return i.(*T)
+}
+
+func testAssertE2TOk() {
+	if got := e2t_ssa(t); got != t {
+		fmt.Printf("e2t_ssa(t)=%v want %v", got, t)
+		failed = true
+	}
+}
+
+func testAssertE2TPanic() {
+	var got *T
+	defer func() {
+		if got != nil {
+			fmt.Printf("e2t_ssa(s)=%v want nil", got)
+			failed = true
+		}
+		e := recover()
+		err, ok := e.(*runtime.TypeAssertionError)
+		if !ok {
+			fmt.Printf("e2t_ssa(s) panic type %T", e)
+			failed = true
+		}
+		want := "interface conversion: interface {} is *main.S, not *main.T"
+		if err.Error() != want {
+			fmt.Printf("e2t_ssa(s) wrong error, want '%s', got '%s'\n", want, err.Error())
+			failed = true
+		}
+	}()
+	got = e2t_ssa(s)
+	fmt.Printf("e2t_ssa(s) should panic")
+	failed = true
+}
+
+func testAssertI2TOk() {
+	if got := i2t_ssa(t); got != t {
+		fmt.Printf("i2t_ssa(t)=%v want %v", got, t)
+		failed = true
+	}
+}
+
+func testAssertI2TPanic() {
+	var got *T
+	defer func() {
+		if got != nil {
+			fmt.Printf("i2t_ssa(s)=%v want nil", got)
+			failed = true
+		}
+		e := recover()
+		err, ok := e.(*runtime.TypeAssertionError)
+		if !ok {
+			fmt.Printf("i2t_ssa(s) panic type %T", e)
+			failed = true
+		}
+		want := "interface conversion: main.I is *main.S, not *main.T"
+		if err.Error() != want {
+			fmt.Printf("i2t_ssa(s) wrong error, want '%s', got '%s'\n", want, err.Error())
+			failed = true
+		}
+	}()
+	got = i2t_ssa(s)
+	fmt.Printf("i2t_ssa(s) should panic")
+	failed = true
+}
+
+func e2t2_ssa(e interface{}) (*T, bool) {
+	t, ok := e.(*T)
+	return t, ok
+}
+
+func i2t2_ssa(i I) (*T, bool) {
+	t, ok := i.(*T)
+	return t, ok
+}
+
+func testAssertE2T2() {
+	if got, ok := e2t2_ssa(t); !ok || got != t {
+		fmt.Printf("e2t2_ssa(t)=(%v, %v) want (%v, %v)", got, ok, t, true)
+		failed = true
+	}
+	if got, ok := e2t2_ssa(s); ok || got != nil {
+		fmt.Printf("e2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false)
+		failed = true
+	}
+}
+
+func testAssertI2T2() {
+	if got, ok := i2t2_ssa(t); !ok || got != t {
+		fmt.Printf("i2t2_ssa(t)=(%v, %v) want (%v, %v)", got, ok, t, true)
+		failed = true
+	}
+	if got, ok := i2t2_ssa(s); ok || got != nil {
+		fmt.Printf("i2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false)
+		failed = true
+	}
+}
+
+var failed = false
+
+func main() {
+	testAssertE2TOk()
+	testAssertE2TPanic()
+	testAssertI2TOk()
+	testAssertI2TPanic()
+	testAssertE2T2()
+	testAssertI2T2()
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/break_ssa.go b/src/cmd/compile/internal/gc/testdata/break_ssa.go
new file mode 100644
index 0000000..855ef70
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/break_ssa.go
@@ -0,0 +1,255 @@
+// 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.
+
+// Tests continue and break.
+
+package main
+
+func continuePlain_ssa() int {
+	var n int
+	for i := 0; i < 10; i++ {
+		if i == 6 {
+			continue
+		}
+		n = i
+	}
+	return n
+}
+
+func continueLabeled_ssa() int {
+	var n int
+Next:
+	for i := 0; i < 10; i++ {
+		if i == 6 {
+			continue Next
+		}
+		n = i
+	}
+	return n
+}
+
+func continuePlainInner_ssa() int {
+	var n int
+	for j := 0; j < 30; j += 10 {
+		for i := 0; i < 10; i++ {
+			if i == 6 {
+				continue
+			}
+			n = i
+		}
+		n += j
+	}
+	return n
+}
+
+func continueLabeledInner_ssa() int {
+	var n int
+	for j := 0; j < 30; j += 10 {
+	Next:
+		for i := 0; i < 10; i++ {
+			if i == 6 {
+				continue Next
+			}
+			n = i
+		}
+		n += j
+	}
+	return n
+}
+
+func continueLabeledOuter_ssa() int {
+	var n int
+Next:
+	for j := 0; j < 30; j += 10 {
+		for i := 0; i < 10; i++ {
+			if i == 6 {
+				continue Next
+			}
+			n = i
+		}
+		n += j
+	}
+	return n
+}
+
+func breakPlain_ssa() int {
+	var n int
+	for i := 0; i < 10; i++ {
+		if i == 6 {
+			break
+		}
+		n = i
+	}
+	return n
+}
+
+func breakLabeled_ssa() int {
+	var n int
+Next:
+	for i := 0; i < 10; i++ {
+		if i == 6 {
+			break Next
+		}
+		n = i
+	}
+	return n
+}
+
+func breakPlainInner_ssa() int {
+	var n int
+	for j := 0; j < 30; j += 10 {
+		for i := 0; i < 10; i++ {
+			if i == 6 {
+				break
+			}
+			n = i
+		}
+		n += j
+	}
+	return n
+}
+
+func breakLabeledInner_ssa() int {
+	var n int
+	for j := 0; j < 30; j += 10 {
+	Next:
+		for i := 0; i < 10; i++ {
+			if i == 6 {
+				break Next
+			}
+			n = i
+		}
+		n += j
+	}
+	return n
+}
+
+func breakLabeledOuter_ssa() int {
+	var n int
+Next:
+	for j := 0; j < 30; j += 10 {
+		for i := 0; i < 10; i++ {
+			if i == 6 {
+				break Next
+			}
+			n = i
+		}
+		n += j
+	}
+	return n
+}
+
+var g, h int // globals to ensure optimizations don't collapse our switch statements
+
+func switchPlain_ssa() int {
+	var n int
+	switch g {
+	case 0:
+		n = 1
+		break
+		n = 2
+	}
+	return n
+}
+
+func switchLabeled_ssa() int {
+	var n int
+Done:
+	switch g {
+	case 0:
+		n = 1
+		break Done
+		n = 2
+	}
+	return n
+}
+
+func switchPlainInner_ssa() int {
+	var n int
+	switch g {
+	case 0:
+		n = 1
+		switch h {
+		case 0:
+			n += 10
+			break
+		}
+		n = 2
+	}
+	return n
+}
+
+func switchLabeledInner_ssa() int {
+	var n int
+	switch g {
+	case 0:
+		n = 1
+	Done:
+		switch h {
+		case 0:
+			n += 10
+			break Done
+		}
+		n = 2
+	}
+	return n
+}
+
+func switchLabeledOuter_ssa() int {
+	var n int
+Done:
+	switch g {
+	case 0:
+		n = 1
+		switch h {
+		case 0:
+			n += 10
+			break Done
+		}
+		n = 2
+	}
+	return n
+}
+
+func main() {
+	tests := [...]struct {
+		name string
+		fn   func() int
+		want int
+	}{
+		{"continuePlain_ssa", continuePlain_ssa, 9},
+		{"continueLabeled_ssa", continueLabeled_ssa, 9},
+		{"continuePlainInner_ssa", continuePlainInner_ssa, 29},
+		{"continueLabeledInner_ssa", continueLabeledInner_ssa, 29},
+		{"continueLabeledOuter_ssa", continueLabeledOuter_ssa, 5},
+
+		{"breakPlain_ssa", breakPlain_ssa, 5},
+		{"breakLabeled_ssa", breakLabeled_ssa, 5},
+		{"breakPlainInner_ssa", breakPlainInner_ssa, 25},
+		{"breakLabeledInner_ssa", breakLabeledInner_ssa, 25},
+		{"breakLabeledOuter_ssa", breakLabeledOuter_ssa, 5},
+
+		{"switchPlain_ssa", switchPlain_ssa, 1},
+		{"switchLabeled_ssa", switchLabeled_ssa, 1},
+		{"switchPlainInner_ssa", switchPlainInner_ssa, 2},
+		{"switchLabeledInner_ssa", switchLabeledInner_ssa, 2},
+		{"switchLabeledOuter_ssa", switchLabeledOuter_ssa, 11},
+
+		// no select tests; they're identical to switch
+	}
+
+	var failed bool
+	for _, test := range tests {
+		if got := test.fn(); test.fn() != test.want {
+			print(test.name, "()=", got, ", want ", test.want, "\n")
+			failed = true
+		}
+	}
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/chan_ssa.go b/src/cmd/compile/internal/gc/testdata/chan_ssa.go
new file mode 100644
index 0000000..0766fcd
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/chan_ssa.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.
+
+// chan_ssa.go tests chan operations.
+package main
+
+import "fmt"
+
+var failed = false
+
+//go:noinline
+func lenChan_ssa(v chan int) int {
+	return len(v)
+}
+
+//go:noinline
+func capChan_ssa(v chan int) int {
+	return cap(v)
+}
+
+func testLenChan() {
+
+	v := make(chan int, 10)
+	v <- 1
+	v <- 1
+	v <- 1
+
+	if want, got := 3, lenChan_ssa(v); got != want {
+		fmt.Printf("expected len(chan) = %d, got %d", want, got)
+		failed = true
+	}
+}
+
+func testLenNilChan() {
+
+	var v chan int
+	if want, got := 0, lenChan_ssa(v); got != want {
+		fmt.Printf("expected len(nil) = %d, got %d", want, got)
+		failed = true
+	}
+}
+
+func testCapChan() {
+
+	v := make(chan int, 25)
+
+	if want, got := 25, capChan_ssa(v); got != want {
+		fmt.Printf("expected cap(chan) = %d, got %d", want, got)
+		failed = true
+	}
+}
+
+func testCapNilChan() {
+
+	var v chan int
+	if want, got := 0, capChan_ssa(v); got != want {
+		fmt.Printf("expected cap(nil) = %d, got %d", want, got)
+		failed = true
+	}
+}
+
+func main() {
+	testLenChan()
+	testLenNilChan()
+
+	testCapChan()
+	testCapNilChan()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/closure_ssa.go b/src/cmd/compile/internal/gc/testdata/closure_ssa.go
new file mode 100644
index 0000000..70181bc
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/closure_ssa.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.
+
+// map_ssa.go tests map operations.
+package main
+
+import "fmt"
+
+var failed = false
+
+//go:noinline
+func testCFunc_ssa() int {
+	a := 0
+	b := func() {
+		switch {
+		}
+		a++
+	}
+	b()
+	b()
+	return a
+}
+
+func testCFunc() {
+	if want, got := 2, testCFunc_ssa(); got != want {
+		fmt.Printf("expected %d, got %d", want, got)
+		failed = true
+	}
+}
+
+func main() {
+	testCFunc()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/cmp_ssa.go b/src/cmd/compile/internal/gc/testdata/cmp_ssa.go
new file mode 100644
index 0000000..ba420f2
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/cmp_ssa.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.
+
+// cmp_ssa.go tests compare simplification operations.
+package main
+
+import "fmt"
+
+var failed = false
+
+//go:noinline
+func eq_ssa(a int64) bool {
+	return 4+a == 10
+}
+
+//go:noinline
+func neq_ssa(a int64) bool {
+	return 10 != a+4
+}
+
+func testCmp() {
+	if wanted, got := true, eq_ssa(6); wanted != got {
+		fmt.Printf("eq_ssa: expected %v, got %v\n", wanted, got)
+		failed = true
+	}
+	if wanted, got := false, eq_ssa(7); wanted != got {
+		fmt.Printf("eq_ssa: expected %v, got %v\n", wanted, got)
+		failed = true
+	}
+
+	if wanted, got := false, neq_ssa(6); wanted != got {
+		fmt.Printf("neq_ssa: expected %v, got %v\n", wanted, got)
+		failed = true
+	}
+	if wanted, got := true, neq_ssa(7); wanted != got {
+		fmt.Printf("neq_ssa: expected %v, got %v\n", wanted, got)
+		failed = true
+	}
+}
+
+func main() {
+	testCmp()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/compound_ssa.go b/src/cmd/compile/internal/gc/testdata/compound_ssa.go
new file mode 100644
index 0000000..de10cdc
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/compound_ssa.go
@@ -0,0 +1,143 @@
+// 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 compound objects
+
+package main
+
+import "fmt"
+
+func string_ssa(a, b string, x bool) string {
+	s := ""
+	if x {
+		s = a
+	} else {
+		s = b
+	}
+	return s
+}
+
+func testString() {
+	a := "foo"
+	b := "barz"
+	if want, got := a, string_ssa(a, b, true); got != want {
+		fmt.Printf("string_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+	if want, got := b, string_ssa(a, b, false); got != want {
+		fmt.Printf("string_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+}
+
+//go:noinline
+func complex64_ssa(a, b complex64, x bool) complex64 {
+	var c complex64
+	if x {
+		c = a
+	} else {
+		c = b
+	}
+	return c
+}
+
+//go:noinline
+func complex128_ssa(a, b complex128, x bool) complex128 {
+	var c complex128
+	if x {
+		c = a
+	} else {
+		c = b
+	}
+	return c
+}
+
+func testComplex64() {
+	var a complex64 = 1 + 2i
+	var b complex64 = 3 + 4i
+
+	if want, got := a, complex64_ssa(a, b, true); got != want {
+		fmt.Printf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+	if want, got := b, complex64_ssa(a, b, false); got != want {
+		fmt.Printf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+}
+
+func testComplex128() {
+	var a complex128 = 1 + 2i
+	var b complex128 = 3 + 4i
+
+	if want, got := a, complex128_ssa(a, b, true); got != want {
+		fmt.Printf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+	if want, got := b, complex128_ssa(a, b, false); got != want {
+		fmt.Printf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+}
+
+func slice_ssa(a, b []byte, x bool) []byte {
+	var s []byte
+	if x {
+		s = a
+	} else {
+		s = b
+	}
+	return s
+}
+
+func testSlice() {
+	a := []byte{3, 4, 5}
+	b := []byte{7, 8, 9}
+	if want, got := byte(3), slice_ssa(a, b, true)[0]; got != want {
+		fmt.Printf("slice_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+	if want, got := byte(7), slice_ssa(a, b, false)[0]; got != want {
+		fmt.Printf("slice_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+}
+
+func interface_ssa(a, b interface{}, x bool) interface{} {
+	var s interface{}
+	if x {
+		s = a
+	} else {
+		s = b
+	}
+	return s
+}
+
+func testInterface() {
+	a := interface{}(3)
+	b := interface{}(4)
+	if want, got := 3, interface_ssa(a, b, true).(int); got != want {
+		fmt.Printf("interface_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+	if want, got := 4, interface_ssa(a, b, false).(int); got != want {
+		fmt.Printf("interface_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
+		failed = true
+	}
+}
+
+var failed = false
+
+func main() {
+	testString()
+	testSlice()
+	testInterface()
+	testComplex64()
+	testComplex128()
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/copy_ssa.go b/src/cmd/compile/internal/gc/testdata/copy_ssa.go
new file mode 100644
index 0000000..0b6f878
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/copy_ssa.go
@@ -0,0 +1,695 @@
+// run
+// autogenerated from gen/copyGen.go - do not edit!
+package main
+
+import "fmt"
+
+type T1 struct {
+	pre  [8]byte
+	mid  [1]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1copy_ssa(y, x *[1]byte) {
+	*y = *x
+}
+func testCopy1() {
+	a := T1{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1]byte{0}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [1]byte{100}
+	t1copy_ssa(&a.mid, &x)
+	want := T1{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1]byte{100}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t1copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T2 struct {
+	pre  [8]byte
+	mid  [2]byte
+	post [8]byte
+}
+
+//go:noinline
+func t2copy_ssa(y, x *[2]byte) {
+	*y = *x
+}
+func testCopy2() {
+	a := T2{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [2]byte{0, 1}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [2]byte{100, 101}
+	t2copy_ssa(&a.mid, &x)
+	want := T2{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [2]byte{100, 101}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t2copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T3 struct {
+	pre  [8]byte
+	mid  [3]byte
+	post [8]byte
+}
+
+//go:noinline
+func t3copy_ssa(y, x *[3]byte) {
+	*y = *x
+}
+func testCopy3() {
+	a := T3{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [3]byte{0, 1, 2}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [3]byte{100, 101, 102}
+	t3copy_ssa(&a.mid, &x)
+	want := T3{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [3]byte{100, 101, 102}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t3copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T4 struct {
+	pre  [8]byte
+	mid  [4]byte
+	post [8]byte
+}
+
+//go:noinline
+func t4copy_ssa(y, x *[4]byte) {
+	*y = *x
+}
+func testCopy4() {
+	a := T4{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [4]byte{0, 1, 2, 3}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [4]byte{100, 101, 102, 103}
+	t4copy_ssa(&a.mid, &x)
+	want := T4{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [4]byte{100, 101, 102, 103}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t4copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T5 struct {
+	pre  [8]byte
+	mid  [5]byte
+	post [8]byte
+}
+
+//go:noinline
+func t5copy_ssa(y, x *[5]byte) {
+	*y = *x
+}
+func testCopy5() {
+	a := T5{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [5]byte{0, 1, 2, 3, 4}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [5]byte{100, 101, 102, 103, 104}
+	t5copy_ssa(&a.mid, &x)
+	want := T5{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [5]byte{100, 101, 102, 103, 104}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t5copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T6 struct {
+	pre  [8]byte
+	mid  [6]byte
+	post [8]byte
+}
+
+//go:noinline
+func t6copy_ssa(y, x *[6]byte) {
+	*y = *x
+}
+func testCopy6() {
+	a := T6{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [6]byte{0, 1, 2, 3, 4, 5}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [6]byte{100, 101, 102, 103, 104, 105}
+	t6copy_ssa(&a.mid, &x)
+	want := T6{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [6]byte{100, 101, 102, 103, 104, 105}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t6copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T7 struct {
+	pre  [8]byte
+	mid  [7]byte
+	post [8]byte
+}
+
+//go:noinline
+func t7copy_ssa(y, x *[7]byte) {
+	*y = *x
+}
+func testCopy7() {
+	a := T7{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [7]byte{0, 1, 2, 3, 4, 5, 6}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [7]byte{100, 101, 102, 103, 104, 105, 106}
+	t7copy_ssa(&a.mid, &x)
+	want := T7{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [7]byte{100, 101, 102, 103, 104, 105, 106}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t7copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T8 struct {
+	pre  [8]byte
+	mid  [8]byte
+	post [8]byte
+}
+
+//go:noinline
+func t8copy_ssa(y, x *[8]byte) {
+	*y = *x
+}
+func testCopy8() {
+	a := T8{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [8]byte{0, 1, 2, 3, 4, 5, 6, 7}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [8]byte{100, 101, 102, 103, 104, 105, 106, 107}
+	t8copy_ssa(&a.mid, &x)
+	want := T8{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [8]byte{100, 101, 102, 103, 104, 105, 106, 107}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t8copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T9 struct {
+	pre  [8]byte
+	mid  [9]byte
+	post [8]byte
+}
+
+//go:noinline
+func t9copy_ssa(y, x *[9]byte) {
+	*y = *x
+}
+func testCopy9() {
+	a := T9{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [9]byte{0, 1, 2, 3, 4, 5, 6, 7, 8}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [9]byte{100, 101, 102, 103, 104, 105, 106, 107, 108}
+	t9copy_ssa(&a.mid, &x)
+	want := T9{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [9]byte{100, 101, 102, 103, 104, 105, 106, 107, 108}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t9copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T10 struct {
+	pre  [8]byte
+	mid  [10]byte
+	post [8]byte
+}
+
+//go:noinline
+func t10copy_ssa(y, x *[10]byte) {
+	*y = *x
+}
+func testCopy10() {
+	a := T10{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [10]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109}
+	t10copy_ssa(&a.mid, &x)
+	want := T10{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [10]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t10copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T15 struct {
+	pre  [8]byte
+	mid  [15]byte
+	post [8]byte
+}
+
+//go:noinline
+func t15copy_ssa(y, x *[15]byte) {
+	*y = *x
+}
+func testCopy15() {
+	a := T15{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [15]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [15]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114}
+	t15copy_ssa(&a.mid, &x)
+	want := T15{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [15]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t15copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T16 struct {
+	pre  [8]byte
+	mid  [16]byte
+	post [8]byte
+}
+
+//go:noinline
+func t16copy_ssa(y, x *[16]byte) {
+	*y = *x
+}
+func testCopy16() {
+	a := T16{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [16]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115}
+	t16copy_ssa(&a.mid, &x)
+	want := T16{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [16]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t16copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T17 struct {
+	pre  [8]byte
+	mid  [17]byte
+	post [8]byte
+}
+
+//go:noinline
+func t17copy_ssa(y, x *[17]byte) {
+	*y = *x
+}
+func testCopy17() {
+	a := T17{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [17]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [17]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116}
+	t17copy_ssa(&a.mid, &x)
+	want := T17{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [17]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t17copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T23 struct {
+	pre  [8]byte
+	mid  [23]byte
+	post [8]byte
+}
+
+//go:noinline
+func t23copy_ssa(y, x *[23]byte) {
+	*y = *x
+}
+func testCopy23() {
+	a := T23{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [23]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [23]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122}
+	t23copy_ssa(&a.mid, &x)
+	want := T23{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [23]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t23copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T24 struct {
+	pre  [8]byte
+	mid  [24]byte
+	post [8]byte
+}
+
+//go:noinline
+func t24copy_ssa(y, x *[24]byte) {
+	*y = *x
+}
+func testCopy24() {
+	a := T24{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [24]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [24]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123}
+	t24copy_ssa(&a.mid, &x)
+	want := T24{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [24]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t24copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T25 struct {
+	pre  [8]byte
+	mid  [25]byte
+	post [8]byte
+}
+
+//go:noinline
+func t25copy_ssa(y, x *[25]byte) {
+	*y = *x
+}
+func testCopy25() {
+	a := T25{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [25]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [25]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124}
+	t25copy_ssa(&a.mid, &x)
+	want := T25{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [25]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t25copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T31 struct {
+	pre  [8]byte
+	mid  [31]byte
+	post [8]byte
+}
+
+//go:noinline
+func t31copy_ssa(y, x *[31]byte) {
+	*y = *x
+}
+func testCopy31() {
+	a := T31{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [31]byte{0, 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}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [31]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130}
+	t31copy_ssa(&a.mid, &x)
+	want := T31{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [31]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t31copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T32 struct {
+	pre  [8]byte
+	mid  [32]byte
+	post [8]byte
+}
+
+//go:noinline
+func t32copy_ssa(y, x *[32]byte) {
+	*y = *x
+}
+func testCopy32() {
+	a := T32{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [32]byte{0, 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}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [32]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131}
+	t32copy_ssa(&a.mid, &x)
+	want := T32{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [32]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t32copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T33 struct {
+	pre  [8]byte
+	mid  [33]byte
+	post [8]byte
+}
+
+//go:noinline
+func t33copy_ssa(y, x *[33]byte) {
+	*y = *x
+}
+func testCopy33() {
+	a := T33{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [33]byte{0, 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}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [33]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}
+	t33copy_ssa(&a.mid, &x)
+	want := T33{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [33]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t33copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T63 struct {
+	pre  [8]byte
+	mid  [63]byte
+	post [8]byte
+}
+
+//go:noinline
+func t63copy_ssa(y, x *[63]byte) {
+	*y = *x
+}
+func testCopy63() {
+	a := T63{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [63]byte{0, 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, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [63]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162}
+	t63copy_ssa(&a.mid, &x)
+	want := T63{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [63]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t63copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T64 struct {
+	pre  [8]byte
+	mid  [64]byte
+	post [8]byte
+}
+
+//go:noinline
+func t64copy_ssa(y, x *[64]byte) {
+	*y = *x
+}
+func testCopy64() {
+	a := T64{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [64]byte{0, 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, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [64]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163}
+	t64copy_ssa(&a.mid, &x)
+	want := T64{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [64]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t64copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T65 struct {
+	pre  [8]byte
+	mid  [65]byte
+	post [8]byte
+}
+
+//go:noinline
+func t65copy_ssa(y, x *[65]byte) {
+	*y = *x
+}
+func testCopy65() {
+	a := T65{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [65]byte{0, 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, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	x := [65]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164}
+	t65copy_ssa(&a.mid, &x)
+	want := T65{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [65]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}}
+	if a != want {
+		fmt.Printf("t65copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1023 struct {
+	pre  [8]byte
+	mid  [1023]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1023copy_ssa(y, x *[1023]byte) {
+	*y = *x
+}
+func testCopy1023() {
+	a := T1023{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1023]byte{0, 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, 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, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  [...]
+	x := [1023]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,  [...]
+	t1023copy_ssa(&a.mid, &x)
+	want := T1023{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1023]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 18 [...]
+	if a != want {
+		fmt.Printf("t1023copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1024 struct {
+	pre  [8]byte
+	mid  [1024]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1024copy_ssa(y, x *[1024]byte) {
+	*y = *x
+}
+func testCopy1024() {
+	a := T1024{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1024]byte{0, 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, 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, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  [...]
+	x := [1024]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,  [...]
+	t1024copy_ssa(&a.mid, &x)
+	want := T1024{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1024]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 18 [...]
+	if a != want {
+		fmt.Printf("t1024copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1025 struct {
+	pre  [8]byte
+	mid  [1025]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1025copy_ssa(y, x *[1025]byte) {
+	*y = *x
+}
+func testCopy1025() {
+	a := T1025{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1025]byte{0, 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, 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, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  [...]
+	x := [1025]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,  [...]
+	t1025copy_ssa(&a.mid, &x)
+	want := T1025{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1025]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 18 [...]
+	if a != want {
+		fmt.Printf("t1025copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1031 struct {
+	pre  [8]byte
+	mid  [1031]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1031copy_ssa(y, x *[1031]byte) {
+	*y = *x
+}
+func testCopy1031() {
+	a := T1031{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1031]byte{0, 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, 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, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  [...]
+	x := [1031]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,  [...]
+	t1031copy_ssa(&a.mid, &x)
+	want := T1031{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1031]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 18 [...]
+	if a != want {
+		fmt.Printf("t1031copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1032 struct {
+	pre  [8]byte
+	mid  [1032]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1032copy_ssa(y, x *[1032]byte) {
+	*y = *x
+}
+func testCopy1032() {
+	a := T1032{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1032]byte{0, 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, 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, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  [...]
+	x := [1032]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,  [...]
+	t1032copy_ssa(&a.mid, &x)
+	want := T1032{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1032]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 18 [...]
+	if a != want {
+		fmt.Printf("t1032copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1033 struct {
+	pre  [8]byte
+	mid  [1033]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1033copy_ssa(y, x *[1033]byte) {
+	*y = *x
+}
+func testCopy1033() {
+	a := T1033{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1033]byte{0, 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, 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, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  [...]
+	x := [1033]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,  [...]
+	t1033copy_ssa(&a.mid, &x)
+	want := T1033{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1033]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 18 [...]
+	if a != want {
+		fmt.Printf("t1033copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1039 struct {
+	pre  [8]byte
+	mid  [1039]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1039copy_ssa(y, x *[1039]byte) {
+	*y = *x
+}
+func testCopy1039() {
+	a := T1039{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1039]byte{0, 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, 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, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  [...]
+	x := [1039]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,  [...]
+	t1039copy_ssa(&a.mid, &x)
+	want := T1039{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1039]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 18 [...]
+	if a != want {
+		fmt.Printf("t1039copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1040 struct {
+	pre  [8]byte
+	mid  [1040]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1040copy_ssa(y, x *[1040]byte) {
+	*y = *x
+}
+func testCopy1040() {
+	a := T1040{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1040]byte{0, 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, 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, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  [...]
+	x := [1040]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,  [...]
+	t1040copy_ssa(&a.mid, &x)
+	want := T1040{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1040]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 18 [...]
+	if a != want {
+		fmt.Printf("t1040copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1041 struct {
+	pre  [8]byte
+	mid  [1041]byte
+	post [8]byte
+}
+
+//go:noinline
+func t1041copy_ssa(y, x *[1041]byte) {
+	*y = *x
+}
+func testCopy1041() {
+	a := T1041{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1041]byte{0, 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, 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, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  [...]
+	x := [1041]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,  [...]
+	t1041copy_ssa(&a.mid, &x)
+	want := T1041{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1041]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 18 [...]
+	if a != want {
+		fmt.Printf("t1041copy got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+var failed bool
+
+func main() {
+	testCopy1()
+	testCopy2()
+	testCopy3()
+	testCopy4()
+	testCopy5()
+	testCopy6()
+	testCopy7()
+	testCopy8()
+	testCopy9()
+	testCopy10()
+	testCopy15()
+	testCopy16()
+	testCopy17()
+	testCopy23()
+	testCopy24()
+	testCopy25()
+	testCopy31()
+	testCopy32()
+	testCopy33()
+	testCopy63()
+	testCopy64()
+	testCopy65()
+	testCopy1023()
+	testCopy1024()
+	testCopy1025()
+	testCopy1031()
+	testCopy1032()
+	testCopy1033()
+	testCopy1039()
+	testCopy1040()
+	testCopy1041()
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/ctl_ssa.go b/src/cmd/compile/internal/gc/testdata/ctl_ssa.go
new file mode 100644
index 0000000..0656cb4
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/ctl_ssa.go
@@ -0,0 +1,160 @@
+// 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 control flow
+
+package main
+
+// nor_ssa calculates NOR(a, b).
+// It is implemented in a way that generates
+// phi control values.
+func nor_ssa(a, b bool) bool {
+	var c bool
+	if a {
+		c = true
+	}
+	if b {
+		c = true
+	}
+	if c {
+		return false
+	}
+	return true
+}
+
+func testPhiControl() {
+	tests := [...][3]bool{ // a, b, want
+		{false, false, true},
+		{true, false, false},
+		{false, true, false},
+		{true, true, false},
+	}
+	for _, test := range tests {
+		a, b := test[0], test[1]
+		got := nor_ssa(a, b)
+		want := test[2]
+		if want != got {
+			print("nor(", a, ", ", b, ")=", want, " got ", got, "\n")
+			failed = true
+		}
+	}
+}
+
+func emptyRange_ssa(b []byte) bool {
+	for _, x := range b {
+		_ = x
+	}
+	return true
+}
+
+func testEmptyRange() {
+	if !emptyRange_ssa([]byte{}) {
+		println("emptyRange_ssa([]byte{})=false, want true")
+		failed = true
+	}
+}
+
+func switch_ssa(a int) int {
+	ret := 0
+	switch a {
+	case 5:
+		ret += 5
+	case 4:
+		ret += 4
+	case 3:
+		ret += 3
+	case 2:
+		ret += 2
+	case 1:
+		ret += 1
+	}
+	return ret
+
+}
+
+func fallthrough_ssa(a int) int {
+	ret := 0
+	switch a {
+	case 5:
+		ret++
+		fallthrough
+	case 4:
+		ret++
+		fallthrough
+	case 3:
+		ret++
+		fallthrough
+	case 2:
+		ret++
+		fallthrough
+	case 1:
+		ret++
+	}
+	return ret
+
+}
+
+func testFallthrough() {
+	for i := 0; i < 6; i++ {
+		if got := fallthrough_ssa(i); got != i {
+			println("fallthrough_ssa(i) =", got, "wanted", i)
+			failed = true
+		}
+	}
+}
+
+func testSwitch() {
+	for i := 0; i < 6; i++ {
+		if got := switch_ssa(i); got != i {
+			println("switch_ssa(i) =", got, "wanted", i)
+			failed = true
+		}
+	}
+}
+
+type junk struct {
+	step int
+}
+
+// flagOverwrite_ssa is intended to reproduce an issue seen where a XOR
+// was scheduled between a compare and branch, clearing flags.
+//go:noinline
+func flagOverwrite_ssa(s *junk, c int) int {
+	if '0' <= c && c <= '9' {
+		s.step = 0
+		return 1
+	}
+	if c == 'e' || c == 'E' {
+		s.step = 0
+		return 2
+	}
+	s.step = 0
+	return 3
+}
+
+func testFlagOverwrite() {
+	j := junk{}
+	if got := flagOverwrite_ssa(&j, ' '); got != 3 {
+		println("flagOverwrite_ssa =", got, "wanted 3")
+		failed = true
+	}
+}
+
+var failed = false
+
+func main() {
+	testPhiControl()
+	testEmptyRange()
+
+	testSwitch()
+	testFallthrough()
+
+	testFlagOverwrite()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/deferNoReturn_ssa.go b/src/cmd/compile/internal/gc/testdata/deferNoReturn_ssa.go
new file mode 100644
index 0000000..7578dd5
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/deferNoReturn_ssa.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.
+
+// Test that a defer in a function with no return
+// statement will compile correctly.
+
+package foo
+
+func deferNoReturn_ssa() {
+	defer func() { println("returned") }()
+	for {
+		println("loop")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/divbyzero_ssa.go b/src/cmd/compile/internal/gc/testdata/divbyzero_ssa.go
new file mode 100644
index 0000000..2165a19
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/divbyzero_ssa.go
@@ -0,0 +1,58 @@
+package main
+
+import (
+	"fmt"
+	"runtime"
+)
+
+var failed = false
+
+func checkDivByZero(f func()) (divByZero bool) {
+	defer func() {
+		if r := recover(); r != nil {
+			if e, ok := r.(runtime.Error); ok && e.Error() == "runtime error: integer divide by zero" {
+				divByZero = true
+			}
+		}
+	}()
+	f()
+	return false
+}
+
+//go:noinline
+func a(i uint, s []int) int {
+	return s[i%uint(len(s))]
+}
+
+//go:noinline
+func b(i uint, j uint) uint {
+	return i / j
+}
+
+//go:noinline
+func c(i int) int {
+	return 7 / (i - i)
+}
+
+func main() {
+	if got := checkDivByZero(func() { b(7, 0) }); !got {
+		fmt.Printf("expected div by zero for b(7, 0), got no error\n")
+		failed = true
+	}
+	if got := checkDivByZero(func() { b(7, 7) }); got {
+		fmt.Printf("expected no error for b(7, 7), got div by zero\n")
+		failed = true
+	}
+	if got := checkDivByZero(func() { a(4, nil) }); !got {
+		fmt.Printf("expected div by zero for a(4, nil), got no error\n")
+		failed = true
+	}
+	if got := checkDivByZero(func() { c(5) }); !got {
+		fmt.Printf("expected div by zero for c(5), got no error\n")
+		failed = true
+	}
+
+	if failed {
+		panic("tests failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/dupLoad.go b/src/cmd/compile/internal/gc/testdata/dupLoad.go
new file mode 100644
index 0000000..d18dc73
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/dupLoad.go
@@ -0,0 +1,83 @@
+// run
+
+// Copyright 2016 The Go 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 makes sure that we don't split a single
+// load up into two separate loads.
+
+package main
+
+import "fmt"
+
+//go:noinline
+func read1(b []byte) (uint16, uint16) {
+	// There is only a single read of b[0].  The two
+	// returned values must have the same low byte.
+	v := b[0]
+	return uint16(v), uint16(v) | uint16(b[1])<<8
+}
+
+const N = 100000
+
+func main1() {
+	done := make(chan struct{})
+	b := make([]byte, 2)
+	go func() {
+		for i := 0; i < N; i++ {
+			b[0] = byte(i)
+			b[1] = byte(i)
+		}
+		done <- struct{}{}
+	}()
+	go func() {
+		for i := 0; i < N; i++ {
+			x, y := read1(b)
+			if byte(x) != byte(y) {
+				fmt.Printf("x=%x y=%x\n", x, y)
+				panic("bad")
+			}
+		}
+		done <- struct{}{}
+	}()
+	<-done
+	<-done
+}
+
+//go:noinline
+func read2(b []byte) (uint16, uint16) {
+	// There is only a single read of b[1].  The two
+	// returned values must have the same high byte.
+	v := uint16(b[1]) << 8
+	return v, uint16(b[0]) | v
+}
+
+func main2() {
+	done := make(chan struct{})
+	b := make([]byte, 2)
+	go func() {
+		for i := 0; i < N; i++ {
+			b[0] = byte(i)
+			b[1] = byte(i)
+		}
+		done <- struct{}{}
+	}()
+	go func() {
+		for i := 0; i < N; i++ {
+			x, y := read2(b)
+			if x&0xff00 != y&0xff00 {
+				fmt.Printf("x=%x y=%x\n", x, y)
+				panic("bad")
+			}
+		}
+		done <- struct{}{}
+	}()
+	<-done
+	<-done
+}
+
+func main() {
+	main1()
+	main2()
+}
diff --git a/src/cmd/compile/internal/gc/testdata/fp_ssa.go b/src/cmd/compile/internal/gc/testdata/fp_ssa.go
new file mode 100644
index 0000000..91656be
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/fp_ssa.go
@@ -0,0 +1,1702 @@
+// 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.
+
+// Tests floating point arithmetic expressions
+
+package main
+
+import "fmt"
+
+// manysub_ssa is designed to tickle bugs that depend on register
+// pressure or unfriendly operand ordering in registers (and at
+// least once it succeeded in this).
+//go:noinline
+func manysub_ssa(a, b, c, d float64) (aa, ab, ac, ad, ba, bb, bc, bd, ca, cb, cc, cd, da, db, dc, dd float64) {
+	aa = a + 11.0 - a
+	ab = a - b
+	ac = a - c
+	ad = a - d
+	ba = b - a
+	bb = b + 22.0 - b
+	bc = b - c
+	bd = b - d
+	ca = c - a
+	cb = c - b
+	cc = c + 33.0 - c
+	cd = c - d
+	da = d - a
+	db = d - b
+	dc = d - c
+	dd = d + 44.0 - d
+	return
+}
+
+// fpspill_ssa attempts to trigger a bug where phis with floating point values
+// were stored in non-fp registers causing an error in doasm.
+//go:noinline
+func fpspill_ssa(a int) float64 {
+
+	ret := -1.0
+	switch a {
+	case 0:
+		ret = 1.0
+	case 1:
+		ret = 1.1
+	case 2:
+		ret = 1.2
+	case 3:
+		ret = 1.3
+	case 4:
+		ret = 1.4
+	case 5:
+		ret = 1.5
+	case 6:
+		ret = 1.6
+	case 7:
+		ret = 1.7
+	case 8:
+		ret = 1.8
+	case 9:
+		ret = 1.9
+	case 10:
+		ret = 1.10
+	case 11:
+		ret = 1.11
+	case 12:
+		ret = 1.12
+	case 13:
+		ret = 1.13
+	case 14:
+		ret = 1.14
+	case 15:
+		ret = 1.15
+	case 16:
+		ret = 1.16
+	}
+	return ret
+}
+
+//go:noinline
+func add64_ssa(a, b float64) float64 {
+	return a + b
+}
+
+//go:noinline
+func mul64_ssa(a, b float64) float64 {
+	return a * b
+}
+
+//go:noinline
+func sub64_ssa(a, b float64) float64 {
+	return a - b
+}
+
+//go:noinline
+func div64_ssa(a, b float64) float64 {
+	return a / b
+}
+
+//go:noinline
+func neg64_ssa(a, b float64) float64 {
+	return -a + -1*b
+}
+
+//go:noinline
+func add32_ssa(a, b float32) float32 {
+	return a + b
+}
+
+//go:noinline
+func mul32_ssa(a, b float32) float32 {
+	return a * b
+}
+
+//go:noinline
+func sub32_ssa(a, b float32) float32 {
+	return a - b
+}
+
+//go:noinline
+func div32_ssa(a, b float32) float32 {
+	return a / b
+}
+
+//go:noinline
+func neg32_ssa(a, b float32) float32 {
+	return -a + -1*b
+}
+
+//go:noinline
+func conv2Float64_ssa(a int8, b uint8, c int16, d uint16,
+	e int32, f uint32, g int64, h uint64, i float32) (aa, bb, cc, dd, ee, ff, gg, hh, ii float64) {
+	aa = float64(a)
+	bb = float64(b)
+	cc = float64(c)
+	hh = float64(h)
+	dd = float64(d)
+	ee = float64(e)
+	ff = float64(f)
+	gg = float64(g)
+	ii = float64(i)
+	return
+}
+
+//go:noinline
+func conv2Float32_ssa(a int8, b uint8, c int16, d uint16,
+	e int32, f uint32, g int64, h uint64, i float64) (aa, bb, cc, dd, ee, ff, gg, hh, ii float32) {
+	aa = float32(a)
+	bb = float32(b)
+	cc = float32(c)
+	dd = float32(d)
+	ee = float32(e)
+	ff = float32(f)
+	gg = float32(g)
+	hh = float32(h)
+	ii = float32(i)
+	return
+}
+
+func integer2floatConversions() int {
+	fails := 0
+	{
+		a, b, c, d, e, f, g, h, i := conv2Float64_ssa(0, 0, 0, 0, 0, 0, 0, 0, 0)
+		fails += expectAll64("zero64", 0, a, b, c, d, e, f, g, h, i)
+	}
+	{
+		a, b, c, d, e, f, g, h, i := conv2Float64_ssa(1, 1, 1, 1, 1, 1, 1, 1, 1)
+		fails += expectAll64("one64", 1, a, b, c, d, e, f, g, h, i)
+	}
+	{
+		a, b, c, d, e, f, g, h, i := conv2Float32_ssa(0, 0, 0, 0, 0, 0, 0, 0, 0)
+		fails += expectAll32("zero32", 0, a, b, c, d, e, f, g, h, i)
+	}
+	{
+		a, b, c, d, e, f, g, h, i := conv2Float32_ssa(1, 1, 1, 1, 1, 1, 1, 1, 1)
+		fails += expectAll32("one32", 1, a, b, c, d, e, f, g, h, i)
+	}
+	{
+		// Check maximum values
+		a, b, c, d, e, f, g, h, i := conv2Float64_ssa(127, 255, 32767, 65535, 0x7fffffff, 0xffffffff, 0x7fffFFFFffffFFFF, 0xffffFFFFffffFFFF, 3.402823E38)
+		fails += expect64("a", a, 127)
+		fails += expect64("b", b, 255)
+		fails += expect64("c", c, 32767)
+		fails += expect64("d", d, 65535)
+		fails += expect64("e", e, float64(int32(0x7fffffff)))
+		fails += expect64("f", f, float64(uint32(0xffffffff)))
+		fails += expect64("g", g, float64(int64(0x7fffffffffffffff)))
+		fails += expect64("h", h, float64(uint64(0xffffffffffffffff)))
+		fails += expect64("i", i, float64(float32(3.402823E38)))
+	}
+	{
+		// Check minimum values (and tweaks for unsigned)
+		a, b, c, d, e, f, g, h, i := conv2Float64_ssa(-128, 254, -32768, 65534, ^0x7fffffff, 0xfffffffe, ^0x7fffFFFFffffFFFF, 0xffffFFFFffffF401, 1.5E-45)
+		fails += expect64("a", a, -128)
+		fails += expect64("b", b, 254)
+		fails += expect64("c", c, -32768)
+		fails += expect64("d", d, 65534)
+		fails += expect64("e", e, float64(^int32(0x7fffffff)))
+		fails += expect64("f", f, float64(uint32(0xfffffffe)))
+		fails += expect64("g", g, float64(^int64(0x7fffffffffffffff)))
+		fails += expect64("h", h, float64(uint64(0xfffffffffffff401)))
+		fails += expect64("i", i, float64(float32(1.5E-45)))
+	}
+	{
+		// Check maximum values
+		a, b, c, d, e, f, g, h, i := conv2Float32_ssa(127, 255, 32767, 65535, 0x7fffffff, 0xffffffff, 0x7fffFFFFffffFFFF, 0xffffFFFFffffFFFF, 3.402823E38)
+		fails += expect32("a", a, 127)
+		fails += expect32("b", b, 255)
+		fails += expect32("c", c, 32767)
+		fails += expect32("d", d, 65535)
+		fails += expect32("e", e, float32(int32(0x7fffffff)))
+		fails += expect32("f", f, float32(uint32(0xffffffff)))
+		fails += expect32("g", g, float32(int64(0x7fffffffffffffff)))
+		fails += expect32("h", h, float32(uint64(0xffffffffffffffff)))
+		fails += expect32("i", i, float32(float64(3.402823E38)))
+	}
+	{
+		// Check minimum values (and tweaks for unsigned)
+		a, b, c, d, e, f, g, h, i := conv2Float32_ssa(-128, 254, -32768, 65534, ^0x7fffffff, 0xfffffffe, ^0x7fffFFFFffffFFFF, 0xffffFFFFffffF401, 1.5E-45)
+		fails += expect32("a", a, -128)
+		fails += expect32("b", b, 254)
+		fails += expect32("c", c, -32768)
+		fails += expect32("d", d, 65534)
+		fails += expect32("e", e, float32(^int32(0x7fffffff)))
+		fails += expect32("f", f, float32(uint32(0xfffffffe)))
+		fails += expect32("g", g, float32(^int64(0x7fffffffffffffff)))
+		fails += expect32("h", h, float32(uint64(0xfffffffffffff401)))
+		fails += expect32("i", i, float32(float64(1.5E-45)))
+	}
+	return fails
+}
+
+const (
+	aa = 0x1000000000000000
+	ab = 0x100000000000000
+	ac = 0x10000000000000
+	ad = 0x1000000000000
+	ba = 0x100000000000
+	bb = 0x10000000000
+	bc = 0x1000000000
+	bd = 0x100000000
+	ca = 0x10000000
+	cb = 0x1000000
+	cc = 0x100000
+	cd = 0x10000
+	da = 0x1000
+	db = 0x100
+	dc = 0x10
+	dd = 0x1
+)
+
+//go:noinline
+func compares64_ssa(a, b, c, d float64) (lt, le, eq, ne, ge, gt uint64) {
+	if a < a {
+		lt += aa
+	}
+	if a < b {
+		lt += ab
+	}
+	if a < c {
+		lt += ac
+	}
+	if a < d {
+		lt += ad
+	}
+
+	if b < a {
+		lt += ba
+	}
+	if b < b {
+		lt += bb
+	}
+	if b < c {
+		lt += bc
+	}
+	if b < d {
+		lt += bd
+	}
+
+	if c < a {
+		lt += ca
+	}
+	if c < b {
+		lt += cb
+	}
+	if c < c {
+		lt += cc
+	}
+	if c < d {
+		lt += cd
+	}
+
+	if d < a {
+		lt += da
+	}
+	if d < b {
+		lt += db
+	}
+	if d < c {
+		lt += dc
+	}
+	if d < d {
+		lt += dd
+	}
+
+	if a <= a {
+		le += aa
+	}
+	if a <= b {
+		le += ab
+	}
+	if a <= c {
+		le += ac
+	}
+	if a <= d {
+		le += ad
+	}
+
+	if b <= a {
+		le += ba
+	}
+	if b <= b {
+		le += bb
+	}
+	if b <= c {
+		le += bc
+	}
+	if b <= d {
+		le += bd
+	}
+
+	if c <= a {
+		le += ca
+	}
+	if c <= b {
+		le += cb
+	}
+	if c <= c {
+		le += cc
+	}
+	if c <= d {
+		le += cd
+	}
+
+	if d <= a {
+		le += da
+	}
+	if d <= b {
+		le += db
+	}
+	if d <= c {
+		le += dc
+	}
+	if d <= d {
+		le += dd
+	}
+
+	if a == a {
+		eq += aa
+	}
+	if a == b {
+		eq += ab
+	}
+	if a == c {
+		eq += ac
+	}
+	if a == d {
+		eq += ad
+	}
+
+	if b == a {
+		eq += ba
+	}
+	if b == b {
+		eq += bb
+	}
+	if b == c {
+		eq += bc
+	}
+	if b == d {
+		eq += bd
+	}
+
+	if c == a {
+		eq += ca
+	}
+	if c == b {
+		eq += cb
+	}
+	if c == c {
+		eq += cc
+	}
+	if c == d {
+		eq += cd
+	}
+
+	if d == a {
+		eq += da
+	}
+	if d == b {
+		eq += db
+	}
+	if d == c {
+		eq += dc
+	}
+	if d == d {
+		eq += dd
+	}
+
+	if a != a {
+		ne += aa
+	}
+	if a != b {
+		ne += ab
+	}
+	if a != c {
+		ne += ac
+	}
+	if a != d {
+		ne += ad
+	}
+
+	if b != a {
+		ne += ba
+	}
+	if b != b {
+		ne += bb
+	}
+	if b != c {
+		ne += bc
+	}
+	if b != d {
+		ne += bd
+	}
+
+	if c != a {
+		ne += ca
+	}
+	if c != b {
+		ne += cb
+	}
+	if c != c {
+		ne += cc
+	}
+	if c != d {
+		ne += cd
+	}
+
+	if d != a {
+		ne += da
+	}
+	if d != b {
+		ne += db
+	}
+	if d != c {
+		ne += dc
+	}
+	if d != d {
+		ne += dd
+	}
+
+	if a >= a {
+		ge += aa
+	}
+	if a >= b {
+		ge += ab
+	}
+	if a >= c {
+		ge += ac
+	}
+	if a >= d {
+		ge += ad
+	}
+
+	if b >= a {
+		ge += ba
+	}
+	if b >= b {
+		ge += bb
+	}
+	if b >= c {
+		ge += bc
+	}
+	if b >= d {
+		ge += bd
+	}
+
+	if c >= a {
+		ge += ca
+	}
+	if c >= b {
+		ge += cb
+	}
+	if c >= c {
+		ge += cc
+	}
+	if c >= d {
+		ge += cd
+	}
+
+	if d >= a {
+		ge += da
+	}
+	if d >= b {
+		ge += db
+	}
+	if d >= c {
+		ge += dc
+	}
+	if d >= d {
+		ge += dd
+	}
+
+	if a > a {
+		gt += aa
+	}
+	if a > b {
+		gt += ab
+	}
+	if a > c {
+		gt += ac
+	}
+	if a > d {
+		gt += ad
+	}
+
+	if b > a {
+		gt += ba
+	}
+	if b > b {
+		gt += bb
+	}
+	if b > c {
+		gt += bc
+	}
+	if b > d {
+		gt += bd
+	}
+
+	if c > a {
+		gt += ca
+	}
+	if c > b {
+		gt += cb
+	}
+	if c > c {
+		gt += cc
+	}
+	if c > d {
+		gt += cd
+	}
+
+	if d > a {
+		gt += da
+	}
+	if d > b {
+		gt += db
+	}
+	if d > c {
+		gt += dc
+	}
+	if d > d {
+		gt += dd
+	}
+
+	return
+}
+
+//go:noinline
+func compares32_ssa(a, b, c, d float32) (lt, le, eq, ne, ge, gt uint64) {
+	if a < a {
+		lt += aa
+	}
+	if a < b {
+		lt += ab
+	}
+	if a < c {
+		lt += ac
+	}
+	if a < d {
+		lt += ad
+	}
+
+	if b < a {
+		lt += ba
+	}
+	if b < b {
+		lt += bb
+	}
+	if b < c {
+		lt += bc
+	}
+	if b < d {
+		lt += bd
+	}
+
+	if c < a {
+		lt += ca
+	}
+	if c < b {
+		lt += cb
+	}
+	if c < c {
+		lt += cc
+	}
+	if c < d {
+		lt += cd
+	}
+
+	if d < a {
+		lt += da
+	}
+	if d < b {
+		lt += db
+	}
+	if d < c {
+		lt += dc
+	}
+	if d < d {
+		lt += dd
+	}
+
+	if a <= a {
+		le += aa
+	}
+	if a <= b {
+		le += ab
+	}
+	if a <= c {
+		le += ac
+	}
+	if a <= d {
+		le += ad
+	}
+
+	if b <= a {
+		le += ba
+	}
+	if b <= b {
+		le += bb
+	}
+	if b <= c {
+		le += bc
+	}
+	if b <= d {
+		le += bd
+	}
+
+	if c <= a {
+		le += ca
+	}
+	if c <= b {
+		le += cb
+	}
+	if c <= c {
+		le += cc
+	}
+	if c <= d {
+		le += cd
+	}
+
+	if d <= a {
+		le += da
+	}
+	if d <= b {
+		le += db
+	}
+	if d <= c {
+		le += dc
+	}
+	if d <= d {
+		le += dd
+	}
+
+	if a == a {
+		eq += aa
+	}
+	if a == b {
+		eq += ab
+	}
+	if a == c {
+		eq += ac
+	}
+	if a == d {
+		eq += ad
+	}
+
+	if b == a {
+		eq += ba
+	}
+	if b == b {
+		eq += bb
+	}
+	if b == c {
+		eq += bc
+	}
+	if b == d {
+		eq += bd
+	}
+
+	if c == a {
+		eq += ca
+	}
+	if c == b {
+		eq += cb
+	}
+	if c == c {
+		eq += cc
+	}
+	if c == d {
+		eq += cd
+	}
+
+	if d == a {
+		eq += da
+	}
+	if d == b {
+		eq += db
+	}
+	if d == c {
+		eq += dc
+	}
+	if d == d {
+		eq += dd
+	}
+
+	if a != a {
+		ne += aa
+	}
+	if a != b {
+		ne += ab
+	}
+	if a != c {
+		ne += ac
+	}
+	if a != d {
+		ne += ad
+	}
+
+	if b != a {
+		ne += ba
+	}
+	if b != b {
+		ne += bb
+	}
+	if b != c {
+		ne += bc
+	}
+	if b != d {
+		ne += bd
+	}
+
+	if c != a {
+		ne += ca
+	}
+	if c != b {
+		ne += cb
+	}
+	if c != c {
+		ne += cc
+	}
+	if c != d {
+		ne += cd
+	}
+
+	if d != a {
+		ne += da
+	}
+	if d != b {
+		ne += db
+	}
+	if d != c {
+		ne += dc
+	}
+	if d != d {
+		ne += dd
+	}
+
+	if a >= a {
+		ge += aa
+	}
+	if a >= b {
+		ge += ab
+	}
+	if a >= c {
+		ge += ac
+	}
+	if a >= d {
+		ge += ad
+	}
+
+	if b >= a {
+		ge += ba
+	}
+	if b >= b {
+		ge += bb
+	}
+	if b >= c {
+		ge += bc
+	}
+	if b >= d {
+		ge += bd
+	}
+
+	if c >= a {
+		ge += ca
+	}
+	if c >= b {
+		ge += cb
+	}
+	if c >= c {
+		ge += cc
+	}
+	if c >= d {
+		ge += cd
+	}
+
+	if d >= a {
+		ge += da
+	}
+	if d >= b {
+		ge += db
+	}
+	if d >= c {
+		ge += dc
+	}
+	if d >= d {
+		ge += dd
+	}
+
+	if a > a {
+		gt += aa
+	}
+	if a > b {
+		gt += ab
+	}
+	if a > c {
+		gt += ac
+	}
+	if a > d {
+		gt += ad
+	}
+
+	if b > a {
+		gt += ba
+	}
+	if b > b {
+		gt += bb
+	}
+	if b > c {
+		gt += bc
+	}
+	if b > d {
+		gt += bd
+	}
+
+	if c > a {
+		gt += ca
+	}
+	if c > b {
+		gt += cb
+	}
+	if c > c {
+		gt += cc
+	}
+	if c > d {
+		gt += cd
+	}
+
+	if d > a {
+		gt += da
+	}
+	if d > b {
+		gt += db
+	}
+	if d > c {
+		gt += dc
+	}
+	if d > d {
+		gt += dd
+	}
+
+	return
+}
+
+//go:noinline
+func le64_ssa(x, y float64) bool {
+	return x <= y
+}
+
+//go:noinline
+func ge64_ssa(x, y float64) bool {
+	return x >= y
+}
+
+//go:noinline
+func lt64_ssa(x, y float64) bool {
+	return x < y
+}
+
+//go:noinline
+func gt64_ssa(x, y float64) bool {
+	return x > y
+}
+
+//go:noinline
+func eq64_ssa(x, y float64) bool {
+	return x == y
+}
+
+//go:noinline
+func ne64_ssa(x, y float64) bool {
+	return x != y
+}
+
+//go:noinline
+func eqbr64_ssa(x, y float64) float64 {
+	if x == y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func nebr64_ssa(x, y float64) float64 {
+	if x != y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func gebr64_ssa(x, y float64) float64 {
+	if x >= y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func lebr64_ssa(x, y float64) float64 {
+	if x <= y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func ltbr64_ssa(x, y float64) float64 {
+	if x < y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func gtbr64_ssa(x, y float64) float64 {
+	if x > y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func le32_ssa(x, y float32) bool {
+	return x <= y
+}
+
+//go:noinline
+func ge32_ssa(x, y float32) bool {
+	return x >= y
+}
+
+//go:noinline
+func lt32_ssa(x, y float32) bool {
+	return x < y
+}
+
+//go:noinline
+func gt32_ssa(x, y float32) bool {
+	return x > y
+}
+
+//go:noinline
+func eq32_ssa(x, y float32) bool {
+	return x == y
+}
+
+//go:noinline
+func ne32_ssa(x, y float32) bool {
+	return x != y
+}
+
+//go:noinline
+func eqbr32_ssa(x, y float32) float32 {
+	if x == y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func nebr32_ssa(x, y float32) float32 {
+	if x != y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func gebr32_ssa(x, y float32) float32 {
+	if x >= y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func lebr32_ssa(x, y float32) float32 {
+	if x <= y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func ltbr32_ssa(x, y float32) float32 {
+	if x < y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func gtbr32_ssa(x, y float32) float32 {
+	if x > y {
+		return 17
+	}
+	return 42
+}
+
+//go:noinline
+func F32toU8_ssa(x float32) uint8 {
+	return uint8(x)
+}
+
+//go:noinline
+func F32toI8_ssa(x float32) int8 {
+	return int8(x)
+}
+
+//go:noinline
+func F32toU16_ssa(x float32) uint16 {
+	return uint16(x)
+}
+
+//go:noinline
+func F32toI16_ssa(x float32) int16 {
+	return int16(x)
+}
+
+//go:noinline
+func F32toU32_ssa(x float32) uint32 {
+	return uint32(x)
+}
+
+//go:noinline
+func F32toI32_ssa(x float32) int32 {
+	return int32(x)
+}
+
+//go:noinline
+func F32toU64_ssa(x float32) uint64 {
+	return uint64(x)
+}
+
+//go:noinline
+func F32toI64_ssa(x float32) int64 {
+	return int64(x)
+}
+
+//go:noinline
+func F64toU8_ssa(x float64) uint8 {
+	return uint8(x)
+}
+
+//go:noinline
+func F64toI8_ssa(x float64) int8 {
+	return int8(x)
+}
+
+//go:noinline
+func F64toU16_ssa(x float64) uint16 {
+	return uint16(x)
+}
+
+//go:noinline
+func F64toI16_ssa(x float64) int16 {
+	return int16(x)
+}
+
+//go:noinline
+func F64toU32_ssa(x float64) uint32 {
+	return uint32(x)
+}
+
+//go:noinline
+func F64toI32_ssa(x float64) int32 {
+	return int32(x)
+}
+
+//go:noinline
+func F64toU64_ssa(x float64) uint64 {
+	return uint64(x)
+}
+
+//go:noinline
+func F64toI64_ssa(x float64) int64 {
+	return int64(x)
+}
+
+func floatsToInts(x float64, expected int64) int {
+	y := float32(x)
+	fails := 0
+	fails += expectInt64("F64toI8", int64(F64toI8_ssa(x)), expected)
+	fails += expectInt64("F64toI16", int64(F64toI16_ssa(x)), expected)
+	fails += expectInt64("F64toI32", int64(F64toI32_ssa(x)), expected)
+	fails += expectInt64("F64toI64", int64(F64toI64_ssa(x)), expected)
+	fails += expectInt64("F32toI8", int64(F32toI8_ssa(y)), expected)
+	fails += expectInt64("F32toI16", int64(F32toI16_ssa(y)), expected)
+	fails += expectInt64("F32toI32", int64(F32toI32_ssa(y)), expected)
+	fails += expectInt64("F32toI64", int64(F32toI64_ssa(y)), expected)
+	return fails
+}
+
+func floatsToUints(x float64, expected uint64) int {
+	y := float32(x)
+	fails := 0
+	fails += expectUint64("F64toU8", uint64(F64toU8_ssa(x)), expected)
+	fails += expectUint64("F64toU16", uint64(F64toU16_ssa(x)), expected)
+	fails += expectUint64("F64toU32", uint64(F64toU32_ssa(x)), expected)
+	fails += expectUint64("F64toU64", uint64(F64toU64_ssa(x)), expected)
+	fails += expectUint64("F32toU8", uint64(F32toU8_ssa(y)), expected)
+	fails += expectUint64("F32toU16", uint64(F32toU16_ssa(y)), expected)
+	fails += expectUint64("F32toU32", uint64(F32toU32_ssa(y)), expected)
+	fails += expectUint64("F32toU64", uint64(F32toU64_ssa(y)), expected)
+	return fails
+}
+
+func floatingToIntegerConversionsTest() int {
+	fails := 0
+	fails += floatsToInts(0.0, 0)
+	fails += floatsToInts(0.5, 0)
+	fails += floatsToInts(0.9, 0)
+	fails += floatsToInts(1.0, 1)
+	fails += floatsToInts(1.5, 1)
+	fails += floatsToInts(127.0, 127)
+	fails += floatsToInts(-1.0, -1)
+	fails += floatsToInts(-128.0, -128)
+
+	fails += floatsToUints(0.0, 0)
+	fails += floatsToUints(1.0, 1)
+	fails += floatsToUints(255.0, 255)
+
+	for j := uint(0); j < 24; j++ {
+		// Avoid hard cases in the construction
+		// of the test inputs.
+		v := int64(1<<62) | int64(1<<(62-j))
+		w := uint64(v)
+		f := float32(v)
+		d := float64(v)
+		fails += expectUint64("2**62...", F32toU64_ssa(f), w)
+		fails += expectUint64("2**62...", F64toU64_ssa(d), w)
+		fails += expectInt64("2**62...", F32toI64_ssa(f), v)
+		fails += expectInt64("2**62...", F64toI64_ssa(d), v)
+		fails += expectInt64("2**62...", F32toI64_ssa(-f), -v)
+		fails += expectInt64("2**62...", F64toI64_ssa(-d), -v)
+		w += w
+		f += f
+		d += d
+		fails += expectUint64("2**63...", F32toU64_ssa(f), w)
+		fails += expectUint64("2**63...", F64toU64_ssa(d), w)
+	}
+
+	for j := uint(0); j < 16; j++ {
+		// Avoid hard cases in the construction
+		// of the test inputs.
+		v := int32(1<<30) | int32(1<<(30-j))
+		w := uint32(v)
+		f := float32(v)
+		d := float64(v)
+		fails += expectUint32("2**30...", F32toU32_ssa(f), w)
+		fails += expectUint32("2**30...", F64toU32_ssa(d), w)
+		fails += expectInt32("2**30...", F32toI32_ssa(f), v)
+		fails += expectInt32("2**30...", F64toI32_ssa(d), v)
+		fails += expectInt32("2**30...", F32toI32_ssa(-f), -v)
+		fails += expectInt32("2**30...", F64toI32_ssa(-d), -v)
+		w += w
+		f += f
+		d += d
+		fails += expectUint32("2**31...", F32toU32_ssa(f), w)
+		fails += expectUint32("2**31...", F64toU32_ssa(d), w)
+	}
+
+	for j := uint(0); j < 15; j++ {
+		// Avoid hard cases in the construction
+		// of the test inputs.
+		v := int16(1<<14) | int16(1<<(14-j))
+		w := uint16(v)
+		f := float32(v)
+		d := float64(v)
+		fails += expectUint16("2**14...", F32toU16_ssa(f), w)
+		fails += expectUint16("2**14...", F64toU16_ssa(d), w)
+		fails += expectInt16("2**14...", F32toI16_ssa(f), v)
+		fails += expectInt16("2**14...", F64toI16_ssa(d), v)
+		fails += expectInt16("2**14...", F32toI16_ssa(-f), -v)
+		fails += expectInt16("2**14...", F64toI16_ssa(-d), -v)
+		w += w
+		f += f
+		d += d
+		fails += expectUint16("2**15...", F32toU16_ssa(f), w)
+		fails += expectUint16("2**15...", F64toU16_ssa(d), w)
+	}
+
+	fails += expectInt32("-2147483648", F32toI32_ssa(-2147483648), -2147483648)
+
+	fails += expectInt32("-2147483648", F64toI32_ssa(-2147483648), -2147483648)
+	fails += expectInt32("-2147483647", F64toI32_ssa(-2147483647), -2147483647)
+	fails += expectUint32("4294967295", F64toU32_ssa(4294967295), 4294967295)
+
+	fails += expectInt16("-32768", F64toI16_ssa(-32768), -32768)
+	fails += expectInt16("-32768", F32toI16_ssa(-32768), -32768)
+
+	// NB more of a pain to do these for 32-bit because of lost bits in Float32 mantissa
+	fails += expectInt16("32767", F64toI16_ssa(32767), 32767)
+	fails += expectInt16("32767", F32toI16_ssa(32767), 32767)
+	fails += expectUint16("32767", F64toU16_ssa(32767), 32767)
+	fails += expectUint16("32767", F32toU16_ssa(32767), 32767)
+	fails += expectUint16("65535", F64toU16_ssa(65535), 65535)
+	fails += expectUint16("65535", F32toU16_ssa(65535), 65535)
+
+	return fails
+}
+
+func fail64(s string, f func(a, b float64) float64, a, b, e float64) int {
+	d := f(a, b)
+	if d != e {
+		fmt.Printf("For (float64) %v %v %v, expected %v, got %v\n", a, s, b, e, d)
+		return 1
+	}
+	return 0
+}
+
+func fail64bool(s string, f func(a, b float64) bool, a, b float64, e bool) int {
+	d := f(a, b)
+	if d != e {
+		fmt.Printf("For (float64) %v %v %v, expected %v, got %v\n", a, s, b, e, d)
+		return 1
+	}
+	return 0
+}
+
+func fail32(s string, f func(a, b float32) float32, a, b, e float32) int {
+	d := f(a, b)
+	if d != e {
+		fmt.Printf("For (float32) %v %v %v, expected %v, got %v\n", a, s, b, e, d)
+		return 1
+	}
+	return 0
+}
+
+func fail32bool(s string, f func(a, b float32) bool, a, b float32, e bool) int {
+	d := f(a, b)
+	if d != e {
+		fmt.Printf("For (float32) %v %v %v, expected %v, got %v\n", a, s, b, e, d)
+		return 1
+	}
+	return 0
+}
+
+func expect64(s string, x, expected float64) int {
+	if x != expected {
+		println("F64 Expected", expected, "for", s, ", got", x)
+		return 1
+	}
+	return 0
+}
+
+func expect32(s string, x, expected float32) int {
+	if x != expected {
+		println("F32 Expected", expected, "for", s, ", got", x)
+		return 1
+	}
+	return 0
+}
+
+func expectUint64(s string, x, expected uint64) int {
+	if x != expected {
+		fmt.Printf("U64 Expected 0x%016x for %s, got 0x%016x\n", expected, s, x)
+		return 1
+	}
+	return 0
+}
+
+func expectInt64(s string, x, expected int64) int {
+	if x != expected {
+		fmt.Printf("%s: Expected 0x%016x, got 0x%016x\n", s, expected, x)
+		return 1
+	}
+	return 0
+}
+
+func expectUint32(s string, x, expected uint32) int {
+	if x != expected {
+		fmt.Printf("U32 %s: Expected 0x%08x, got 0x%08x\n", s, expected, x)
+		return 1
+	}
+	return 0
+}
+
+func expectInt32(s string, x, expected int32) int {
+	if x != expected {
+		fmt.Printf("I32 %s: Expected 0x%08x, got 0x%08x\n", s, expected, x)
+		return 1
+	}
+	return 0
+}
+
+func expectUint16(s string, x, expected uint16) int {
+	if x != expected {
+		fmt.Printf("U16 %s: Expected 0x%04x, got 0x%04x\n", s, expected, x)
+		return 1
+	}
+	return 0
+}
+
+func expectInt16(s string, x, expected int16) int {
+	if x != expected {
+		fmt.Printf("I16 %s: Expected 0x%04x, got 0x%04x\n", s, expected, x)
+		return 1
+	}
+	return 0
+}
+
+func expectAll64(s string, expected, a, b, c, d, e, f, g, h, i float64) int {
+	fails := 0
+	fails += expect64(s+":a", a, expected)
+	fails += expect64(s+":b", b, expected)
+	fails += expect64(s+":c", c, expected)
+	fails += expect64(s+":d", d, expected)
+	fails += expect64(s+":e", e, expected)
+	fails += expect64(s+":f", f, expected)
+	fails += expect64(s+":g", g, expected)
+	return fails
+}
+
+func expectAll32(s string, expected, a, b, c, d, e, f, g, h, i float32) int {
+	fails := 0
+	fails += expect32(s+":a", a, expected)
+	fails += expect32(s+":b", b, expected)
+	fails += expect32(s+":c", c, expected)
+	fails += expect32(s+":d", d, expected)
+	fails += expect32(s+":e", e, expected)
+	fails += expect32(s+":f", f, expected)
+	fails += expect32(s+":g", g, expected)
+	return fails
+}
+
+var ev64 [2]float64 = [2]float64{42.0, 17.0}
+var ev32 [2]float32 = [2]float32{42.0, 17.0}
+
+func cmpOpTest(s string,
+	f func(a, b float64) bool,
+	g func(a, b float64) float64,
+	ff func(a, b float32) bool,
+	gg func(a, b float32) float32,
+	zero, one, inf, nan float64, result uint) int {
+	fails := 0
+	fails += fail64bool(s, f, zero, zero, result>>16&1 == 1)
+	fails += fail64bool(s, f, zero, one, result>>12&1 == 1)
+	fails += fail64bool(s, f, zero, inf, result>>8&1 == 1)
+	fails += fail64bool(s, f, zero, nan, result>>4&1 == 1)
+	fails += fail64bool(s, f, nan, nan, result&1 == 1)
+
+	fails += fail64(s, g, zero, zero, ev64[result>>16&1])
+	fails += fail64(s, g, zero, one, ev64[result>>12&1])
+	fails += fail64(s, g, zero, inf, ev64[result>>8&1])
+	fails += fail64(s, g, zero, nan, ev64[result>>4&1])
+	fails += fail64(s, g, nan, nan, ev64[result>>0&1])
+
+	{
+		zero := float32(zero)
+		one := float32(one)
+		inf := float32(inf)
+		nan := float32(nan)
+		fails += fail32bool(s, ff, zero, zero, (result>>16)&1 == 1)
+		fails += fail32bool(s, ff, zero, one, (result>>12)&1 == 1)
+		fails += fail32bool(s, ff, zero, inf, (result>>8)&1 == 1)
+		fails += fail32bool(s, ff, zero, nan, (result>>4)&1 == 1)
+		fails += fail32bool(s, ff, nan, nan, result&1 == 1)
+
+		fails += fail32(s, gg, zero, zero, ev32[(result>>16)&1])
+		fails += fail32(s, gg, zero, one, ev32[(result>>12)&1])
+		fails += fail32(s, gg, zero, inf, ev32[(result>>8)&1])
+		fails += fail32(s, gg, zero, nan, ev32[(result>>4)&1])
+		fails += fail32(s, gg, nan, nan, ev32[(result>>0)&1])
+	}
+
+	return fails
+}
+
+func expectCx128(s string, x, expected complex128) int {
+	if x != expected {
+		println("Cx 128 Expected", expected, "for", s, ", got", x)
+		return 1
+	}
+	return 0
+}
+
+func expectCx64(s string, x, expected complex64) int {
+	if x != expected {
+		println("Cx 64 Expected", expected, "for", s, ", got", x)
+		return 1
+	}
+	return 0
+}
+
+//go:noinline
+func cx128sum_ssa(a, b complex128) complex128 {
+	return a + b
+}
+
+//go:noinline
+func cx128diff_ssa(a, b complex128) complex128 {
+	return a - b
+}
+
+//go:noinline
+func cx128prod_ssa(a, b complex128) complex128 {
+	return a * b
+}
+
+//go:noinline
+func cx128quot_ssa(a, b complex128) complex128 {
+	return a / b
+}
+
+//go:noinline
+func cx128neg_ssa(a complex128) complex128 {
+	return -a
+}
+
+//go:noinline
+func cx128real_ssa(a complex128) float64 {
+	return real(a)
+}
+
+//go:noinline
+func cx128imag_ssa(a complex128) float64 {
+	return imag(a)
+}
+
+//go:noinline
+func cx128cnst_ssa(a complex128) complex128 {
+	b := 2 + 3i
+	return a * b
+}
+
+//go:noinline
+func cx64sum_ssa(a, b complex64) complex64 {
+	return a + b
+}
+
+//go:noinline
+func cx64diff_ssa(a, b complex64) complex64 {
+	return a - b
+}
+
+//go:noinline
+func cx64prod_ssa(a, b complex64) complex64 {
+	return a * b
+}
+
+//go:noinline
+func cx64quot_ssa(a, b complex64) complex64 {
+	return a / b
+}
+
+//go:noinline
+func cx64neg_ssa(a complex64) complex64 {
+	return -a
+}
+
+//go:noinline
+func cx64real_ssa(a complex64) float32 {
+	return real(a)
+}
+
+//go:noinline
+func cx64imag_ssa(a complex64) float32 {
+	return imag(a)
+}
+
+//go:noinline
+func cx128eq_ssa(a, b complex128) bool {
+	return a == b
+}
+
+//go:noinline
+func cx128ne_ssa(a, b complex128) bool {
+	return a != b
+}
+
+//go:noinline
+func cx64eq_ssa(a, b complex64) bool {
+	return a == b
+}
+
+//go:noinline
+func cx64ne_ssa(a, b complex64) bool {
+	return a != b
+}
+
+func expectTrue(s string, b bool) int {
+	if !b {
+		println("expected true for", s, ", got false")
+		return 1
+	}
+	return 0
+}
+func expectFalse(s string, b bool) int {
+	if b {
+		println("expected false for", s, ", got true")
+		return 1
+	}
+	return 0
+}
+
+func complexTest128() int {
+	fails := 0
+	var a complex128 = 1 + 2i
+	var b complex128 = 3 + 6i
+	sum := cx128sum_ssa(b, a)
+	diff := cx128diff_ssa(b, a)
+	prod := cx128prod_ssa(b, a)
+	quot := cx128quot_ssa(b, a)
+	neg := cx128neg_ssa(a)
+	r := cx128real_ssa(a)
+	i := cx128imag_ssa(a)
+	cnst := cx128cnst_ssa(a)
+	c1 := cx128eq_ssa(a, a)
+	c2 := cx128eq_ssa(a, b)
+	c3 := cx128ne_ssa(a, a)
+	c4 := cx128ne_ssa(a, b)
+
+	fails += expectCx128("sum", sum, 4+8i)
+	fails += expectCx128("diff", diff, 2+4i)
+	fails += expectCx128("prod", prod, -9+12i)
+	fails += expectCx128("quot", quot, 3+0i)
+	fails += expectCx128("neg", neg, -1-2i)
+	fails += expect64("real", r, 1)
+	fails += expect64("imag", i, 2)
+	fails += expectCx128("cnst", cnst, -4+7i)
+	fails += expectTrue(fmt.Sprintf("%v==%v", a, a), c1)
+	fails += expectFalse(fmt.Sprintf("%v==%v", a, b), c2)
+	fails += expectFalse(fmt.Sprintf("%v!=%v", a, a), c3)
+	fails += expectTrue(fmt.Sprintf("%v!=%v", a, b), c4)
+
+	return fails
+}
+
+func complexTest64() int {
+	fails := 0
+	var a complex64 = 1 + 2i
+	var b complex64 = 3 + 6i
+	sum := cx64sum_ssa(b, a)
+	diff := cx64diff_ssa(b, a)
+	prod := cx64prod_ssa(b, a)
+	quot := cx64quot_ssa(b, a)
+	neg := cx64neg_ssa(a)
+	r := cx64real_ssa(a)
+	i := cx64imag_ssa(a)
+	c1 := cx64eq_ssa(a, a)
+	c2 := cx64eq_ssa(a, b)
+	c3 := cx64ne_ssa(a, a)
+	c4 := cx64ne_ssa(a, b)
+
+	fails += expectCx64("sum", sum, 4+8i)
+	fails += expectCx64("diff", diff, 2+4i)
+	fails += expectCx64("prod", prod, -9+12i)
+	fails += expectCx64("quot", quot, 3+0i)
+	fails += expectCx64("neg", neg, -1-2i)
+	fails += expect32("real", r, 1)
+	fails += expect32("imag", i, 2)
+	fails += expectTrue(fmt.Sprintf("%v==%v", a, a), c1)
+	fails += expectFalse(fmt.Sprintf("%v==%v", a, b), c2)
+	fails += expectFalse(fmt.Sprintf("%v!=%v", a, a), c3)
+	fails += expectTrue(fmt.Sprintf("%v!=%v", a, b), c4)
+
+	return fails
+}
+
+func main() {
+
+	a := 3.0
+	b := 4.0
+
+	c := float32(3.0)
+	d := float32(4.0)
+
+	tiny := float32(1.5E-45) // smallest f32 denorm = 2**(-149)
+	dtiny := float64(tiny)   // well within range of f64
+
+	fails := 0
+	fails += fail64("+", add64_ssa, a, b, 7.0)
+	fails += fail64("*", mul64_ssa, a, b, 12.0)
+	fails += fail64("-", sub64_ssa, a, b, -1.0)
+	fails += fail64("/", div64_ssa, a, b, 0.75)
+	fails += fail64("neg", neg64_ssa, a, b, -7)
+
+	fails += fail32("+", add32_ssa, c, d, 7.0)
+	fails += fail32("*", mul32_ssa, c, d, 12.0)
+	fails += fail32("-", sub32_ssa, c, d, -1.0)
+	fails += fail32("/", div32_ssa, c, d, 0.75)
+	fails += fail32("neg", neg32_ssa, c, d, -7)
+
+	// denorm-squared should underflow to zero.
+	fails += fail32("*", mul32_ssa, tiny, tiny, 0)
+
+	// but should not underflow in float and in fact is exactly representable.
+	fails += fail64("*", mul64_ssa, dtiny, dtiny, 1.9636373861190906e-90)
+
+	// Intended to create register pressure which forces
+	// asymmetric op into different code paths.
+	aa, ab, ac, ad, ba, bb, bc, bd, ca, cb, cc, cd, da, db, dc, dd := manysub_ssa(1000.0, 100.0, 10.0, 1.0)
+
+	fails += expect64("aa", aa, 11.0)
+	fails += expect64("ab", ab, 900.0)
+	fails += expect64("ac", ac, 990.0)
+	fails += expect64("ad", ad, 999.0)
+
+	fails += expect64("ba", ba, -900.0)
+	fails += expect64("bb", bb, 22.0)
+	fails += expect64("bc", bc, 90.0)
+	fails += expect64("bd", bd, 99.0)
+
+	fails += expect64("ca", ca, -990.0)
+	fails += expect64("cb", cb, -90.0)
+	fails += expect64("cc", cc, 33.0)
+	fails += expect64("cd", cd, 9.0)
+
+	fails += expect64("da", da, -999.0)
+	fails += expect64("db", db, -99.0)
+	fails += expect64("dc", dc, -9.0)
+	fails += expect64("dd", dd, 44.0)
+
+	fails += integer2floatConversions()
+
+	var zero64 float64 = 0.0
+	var one64 float64 = 1.0
+	var inf64 float64 = 1.0 / zero64
+	var nan64 float64 = sub64_ssa(inf64, inf64)
+
+	fails += cmpOpTest("!=", ne64_ssa, nebr64_ssa, ne32_ssa, nebr32_ssa, zero64, one64, inf64, nan64, 0x01111)
+	fails += cmpOpTest("==", eq64_ssa, eqbr64_ssa, eq32_ssa, eqbr32_ssa, zero64, one64, inf64, nan64, 0x10000)
+	fails += cmpOpTest("<=", le64_ssa, lebr64_ssa, le32_ssa, lebr32_ssa, zero64, one64, inf64, nan64, 0x11100)
+	fails += cmpOpTest("<", lt64_ssa, ltbr64_ssa, lt32_ssa, ltbr32_ssa, zero64, one64, inf64, nan64, 0x01100)
+	fails += cmpOpTest(">", gt64_ssa, gtbr64_ssa, gt32_ssa, gtbr32_ssa, zero64, one64, inf64, nan64, 0x00000)
+	fails += cmpOpTest(">=", ge64_ssa, gebr64_ssa, ge32_ssa, gebr32_ssa, zero64, one64, inf64, nan64, 0x10000)
+
+	{
+		lt, le, eq, ne, ge, gt := compares64_ssa(0.0, 1.0, inf64, nan64)
+		fails += expectUint64("lt", lt, 0x0110001000000000)
+		fails += expectUint64("le", le, 0x1110011000100000)
+		fails += expectUint64("eq", eq, 0x1000010000100000)
+		fails += expectUint64("ne", ne, 0x0111101111011111)
+		fails += expectUint64("ge", ge, 0x1000110011100000)
+		fails += expectUint64("gt", gt, 0x0000100011000000)
+		// fmt.Printf("lt=0x%016x, le=0x%016x, eq=0x%016x, ne=0x%016x, ge=0x%016x, gt=0x%016x\n",
+		// 	lt, le, eq, ne, ge, gt)
+	}
+	{
+		lt, le, eq, ne, ge, gt := compares32_ssa(0.0, 1.0, float32(inf64), float32(nan64))
+		fails += expectUint64("lt", lt, 0x0110001000000000)
+		fails += expectUint64("le", le, 0x1110011000100000)
+		fails += expectUint64("eq", eq, 0x1000010000100000)
+		fails += expectUint64("ne", ne, 0x0111101111011111)
+		fails += expectUint64("ge", ge, 0x1000110011100000)
+		fails += expectUint64("gt", gt, 0x0000100011000000)
+	}
+
+	fails += floatingToIntegerConversionsTest()
+	fails += complexTest128()
+	fails += complexTest64()
+
+	if fails > 0 {
+		fmt.Printf("Saw %v failures\n", fails)
+		panic("Failed.")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
new file mode 100644
index 0000000..be0aad5
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
@@ -0,0 +1,214 @@
+// Copyright 2015 The Go 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 generates a test to verify that the standard arithmetic
+// operators properly handle some special cases. The test file should be
+// generated with a known working version of go.
+// launch with `go run arithBoundaryGen.go` a file called arithBoundary_ssa.go
+// will be written into the parent directory containing the tests
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/format"
+	"io/ioutil"
+	"log"
+	"text/template"
+)
+
+// used for interpolation in a text template
+type tmplData struct {
+	Name, Stype, Symbol string
+}
+
+// used to work around an issue with the mod symbol being
+// interpreted as part of a format string
+func (s tmplData) SymFirst() string {
+	return string(s.Symbol[0])
+}
+
+// ucast casts an unsigned int to the size in s
+func ucast(i uint64, s sizedTestData) uint64 {
+	switch s.name {
+	case "uint32":
+		return uint64(uint32(i))
+	case "uint16":
+		return uint64(uint16(i))
+	case "uint8":
+		return uint64(uint8(i))
+	}
+	return i
+}
+
+// icast casts a signed int to the size in s
+func icast(i int64, s sizedTestData) int64 {
+	switch s.name {
+	case "int32":
+		return int64(int32(i))
+	case "int16":
+		return int64(int16(i))
+	case "int8":
+		return int64(int8(i))
+	}
+	return i
+}
+
+type sizedTestData struct {
+	name string
+	sn   string
+	u    []uint64
+	i    []int64
+}
+
+// values to generate tests. these should include the smallest and largest values, along
+// with any other values that might cause issues. we generate n^2 tests for each size to
+// cover all cases.
+var szs = []sizedTestData{
+	sizedTestData{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
+	sizedTestData{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+		-4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},
+
+	sizedTestData{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}},
+	sizedTestData{name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0,
+		1, 0x7FFFFFFF}},
+
+	sizedTestData{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}},
+	sizedTestData{name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}},
+
+	sizedTestData{name: "uint8", sn: "8", u: []uint64{0, 1, 255}},
+	sizedTestData{name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}},
+}
+
+type op struct {
+	name, symbol string
+}
+
+// ops that we will be generating tests for
+var ops = []op{op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mod", "%%"}, op{"mul", "*"}}
+
+func main() {
+
+	w := new(bytes.Buffer)
+	fmt.Fprintf(w, "package main;\n")
+	fmt.Fprintf(w, "import \"fmt\"\n")
+
+	for _, sz := range []int{64, 32, 16, 8} {
+		fmt.Fprintf(w, "type utd%d struct {\n", sz)
+		fmt.Fprintf(w, "  a,b uint%d\n", sz)
+		fmt.Fprintf(w, "  add,sub,mul,div,mod uint%d\n", sz)
+		fmt.Fprintf(w, "}\n")
+
+		fmt.Fprintf(w, "type itd%d struct {\n", sz)
+		fmt.Fprintf(w, "  a,b int%d\n", sz)
+		fmt.Fprintf(w, "  add,sub,mul,div,mod int%d\n", sz)
+		fmt.Fprintf(w, "}\n")
+	}
+
+	// the function being tested
+	testFunc, err := template.New("testFunc").Parse(
+		`//go:noinline
+		func {{.Name}}_{{.Stype}}_ssa(a, b {{.Stype}}) {{.Stype}} {
+	return a {{.SymFirst}} b
+}
+`)
+	if err != nil {
+		panic(err)
+	}
+
+	// generate our functions to be tested
+	for _, s := range szs {
+		for _, o := range ops {
+			fd := tmplData{o.name, s.name, o.symbol}
+			err = testFunc.Execute(w, fd)
+			if err != nil {
+				panic(err)
+			}
+		}
+	}
+
+	// generate the test data
+	for _, s := range szs {
+		if len(s.u) > 0 {
+			fmt.Fprintf(w, "var %s_data []utd%s = []utd%s{", s.name, s.sn, s.sn)
+			for _, i := range s.u {
+				for _, j := range s.u {
+					fmt.Fprintf(w, "utd%s{a: %d, b: %d, add: %d, sub: %d, mul: %d", s.sn, i, j, ucast(i+j, s), ucast(i-j, s), ucast(i*j, s))
+					if j != 0 {
+						fmt.Fprintf(w, ", div: %d, mod: %d", ucast(i/j, s), ucast(i%j, s))
+					}
+					fmt.Fprint(w, "},\n")
+				}
+			}
+			fmt.Fprintf(w, "}\n")
+		} else {
+			// TODO: clean up this duplication
+			fmt.Fprintf(w, "var %s_data []itd%s = []itd%s{", s.name, s.sn, s.sn)
+			for _, i := range s.i {
+				for _, j := range s.i {
+					fmt.Fprintf(w, "itd%s{a: %d, b: %d, add: %d, sub: %d, mul: %d", s.sn, i, j, icast(i+j, s), icast(i-j, s), icast(i*j, s))
+					if j != 0 {
+						fmt.Fprintf(w, ", div: %d, mod: %d", icast(i/j, s), icast(i%j, s))
+					}
+					fmt.Fprint(w, "},\n")
+				}
+			}
+			fmt.Fprintf(w, "}\n")
+		}
+	}
+
+	fmt.Fprintf(w, "var failed bool\n\n")
+	fmt.Fprintf(w, "func main() {\n\n")
+
+	verify, err := template.New("tst").Parse(
+		`if got := {{.Name}}_{{.Stype}}_ssa(v.a, v.b); got != v.{{.Name}} {
+       fmt.Printf("{{.Name}}_{{.Stype}} %d{{.Symbol}}%d = %d, wanted %d\n",v.a,v.b,got,v.{{.Name}})
+       failed = true
+}
+`)
+
+	for _, s := range szs {
+		fmt.Fprintf(w, "for _, v := range %s_data {\n", s.name)
+
+		for _, o := range ops {
+			// avoid generating tests that divide by zero
+			if o.name == "div" || o.name == "mod" {
+				fmt.Fprint(w, "if v.b != 0 {")
+			}
+
+			err = verify.Execute(w, tmplData{o.name, s.name, o.symbol})
+
+			if o.name == "div" || o.name == "mod" {
+				fmt.Fprint(w, "\n}\n")
+			}
+
+			if err != nil {
+				panic(err)
+			}
+
+		}
+		fmt.Fprint(w, "    }\n")
+	}
+
+	fmt.Fprintf(w, `if failed {
+        panic("tests failed")
+    }
+`)
+	fmt.Fprintf(w, "}\n")
+
+	// gofmt result
+	b := w.Bytes()
+	src, err := format.Source(b)
+	if err != nil {
+		fmt.Printf("%s\n", b)
+		panic(err)
+	}
+
+	// write to file
+	err = ioutil.WriteFile("../arithBoundary_ssa.go", src, 0666)
+	if err != nil {
+		log.Fatalf("can't write output: %v\n", err)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
new file mode 100644
index 0000000..5559050
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
@@ -0,0 +1,302 @@
+// Copyright 2016 The Go 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 generates a test to verify that the standard arithmetic
+// operators properly handle const cases. The test file should be
+// generated with a known working version of go.
+// launch with `go run arithConstGen.go` a file called arithConst_ssa.go
+// will be written into the parent directory containing the tests
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/format"
+	"io/ioutil"
+	"log"
+	"strings"
+	"text/template"
+)
+
+type op struct {
+	name, symbol string
+}
+type szD struct {
+	name string
+	sn   string
+	u    []uint64
+	i    []int64
+}
+
+var szs []szD = []szD{
+	szD{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
+	szD{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+		-4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},
+
+	szD{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}},
+	szD{name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0,
+		1, 0x7FFFFFFF}},
+
+	szD{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}},
+	szD{name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}},
+
+	szD{name: "uint8", sn: "8", u: []uint64{0, 1, 255}},
+	szD{name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}},
+}
+
+var ops []op = []op{op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mul", "*"},
+	op{"lsh", "<<"}, op{"rsh", ">>"}, op{"mod", "%"}}
+
+// compute the result of i op j, cast as type t.
+func ansU(i, j uint64, t, op string) string {
+	var ans uint64
+	switch op {
+	case "+":
+		ans = i + j
+	case "-":
+		ans = i - j
+	case "*":
+		ans = i * j
+	case "/":
+		if j != 0 {
+			ans = i / j
+		}
+	case "%":
+		if j != 0 {
+			ans = i % j
+		}
+	case "<<":
+		ans = i << j
+	case ">>":
+		ans = i >> j
+	}
+	switch t {
+	case "uint32":
+		ans = uint64(uint32(ans))
+	case "uint16":
+		ans = uint64(uint16(ans))
+	case "uint8":
+		ans = uint64(uint8(ans))
+	}
+	return fmt.Sprintf("%d", ans)
+}
+
+// compute the result of i op j, cast as type t.
+func ansS(i, j int64, t, op string) string {
+	var ans int64
+	switch op {
+	case "+":
+		ans = i + j
+	case "-":
+		ans = i - j
+	case "*":
+		ans = i * j
+	case "/":
+		if j != 0 {
+			ans = i / j
+		}
+	case "%":
+		if j != 0 {
+			ans = i % j
+		}
+	case "<<":
+		ans = i << uint64(j)
+	case ">>":
+		ans = i >> uint64(j)
+	}
+	switch t {
+	case "int32":
+		ans = int64(int32(ans))
+	case "int16":
+		ans = int64(int16(ans))
+	case "int8":
+		ans = int64(int8(ans))
+	}
+	return fmt.Sprintf("%d", ans)
+}
+
+func main() {
+
+	w := new(bytes.Buffer)
+
+	fmt.Fprintf(w, "package main;\n")
+	fmt.Fprintf(w, "import \"fmt\"\n")
+
+	fncCnst1, err := template.New("fnc").Parse(
+		`//go:noinline
+		func {{.Name}}_{{.Type_}}_{{.FNumber}}_ssa(a {{.Type_}}) {{.Type_}} {
+	return a {{.Symbol}} {{.Number}}
+}
+`)
+	if err != nil {
+		panic(err)
+	}
+	fncCnst2, err := template.New("fnc").Parse(
+		`//go:noinline
+		func {{.Name}}_{{.FNumber}}_{{.Type_}}_ssa(a {{.Type_}}) {{.Type_}} {
+	return {{.Number}} {{.Symbol}} a
+}
+
+`)
+	if err != nil {
+		panic(err)
+	}
+
+	type fncData struct {
+		Name, Type_, Symbol, FNumber, Number string
+	}
+
+	for _, s := range szs {
+		for _, o := range ops {
+			fd := fncData{o.name, s.name, o.symbol, "", ""}
+
+			// unsigned test cases
+			if len(s.u) > 0 {
+				for _, i := range s.u {
+					fd.Number = fmt.Sprintf("%d", i)
+					fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1)
+
+					// avoid division by zero
+					if o.name != "mod" && o.name != "div" || i != 0 {
+						fncCnst1.Execute(w, fd)
+					}
+
+					fncCnst2.Execute(w, fd)
+				}
+			}
+
+			// signed test cases
+			if len(s.i) > 0 {
+				// don't generate tests for shifts by signed integers
+				if o.name == "lsh" || o.name == "rsh" {
+					continue
+				}
+				for _, i := range s.i {
+					fd.Number = fmt.Sprintf("%d", i)
+					fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1)
+
+					// avoid division by zero
+					if o.name != "mod" && o.name != "div" || i != 0 {
+						fncCnst1.Execute(w, fd)
+					}
+					fncCnst2.Execute(w, fd)
+				}
+			}
+		}
+	}
+
+	fmt.Fprintf(w, "var failed bool\n\n")
+	fmt.Fprintf(w, "func main() {\n\n")
+
+	vrf1, _ := template.New("vrf1").Parse(`
+  if got := {{.Name}}_{{.FNumber}}_{{.Type_}}_ssa({{.Input}}); got != {{.Ans}} {
+  	fmt.Printf("{{.Name}}_{{.Type_}} {{.Number}}%s{{.Input}} = %d, wanted {{.Ans}}\n", ` + "`{{.Symbol}}`" + `, got)
+  	failed = true
+  }
+`)
+
+	vrf2, _ := template.New("vrf2").Parse(`
+  if got := {{.Name}}_{{.Type_}}_{{.FNumber}}_ssa({{.Input}}); got != {{.Ans}} {
+    fmt.Printf("{{.Name}}_{{.Type_}} {{.Input}}%s{{.Number}} = %d, wanted {{.Ans}}\n", ` + "`{{.Symbol}}`" + `, got)
+    failed = true
+  }
+`)
+
+	type cfncData struct {
+		Name, Type_, Symbol, FNumber, Number string
+		Ans, Input                           string
+	}
+	for _, s := range szs {
+		if len(s.u) > 0 {
+			for _, o := range ops {
+				fd := cfncData{o.name, s.name, o.symbol, "", "", "", ""}
+				for _, i := range s.u {
+					fd.Number = fmt.Sprintf("%d", i)
+					fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1)
+
+					// unsigned
+					for _, j := range s.u {
+
+						if o.name != "mod" && o.name != "div" || j != 0 {
+							fd.Ans = ansU(i, j, s.name, o.symbol)
+							fd.Input = fmt.Sprintf("%d", j)
+							err = vrf1.Execute(w, fd)
+							if err != nil {
+								panic(err)
+							}
+						}
+
+						if o.name != "mod" && o.name != "div" || i != 0 {
+							fd.Ans = ansU(j, i, s.name, o.symbol)
+							fd.Input = fmt.Sprintf("%d", j)
+							err = vrf2.Execute(w, fd)
+							if err != nil {
+								panic(err)
+							}
+						}
+
+					}
+				}
+
+			}
+		}
+
+		// signed
+		if len(s.i) > 0 {
+			for _, o := range ops {
+				// don't generate tests for shifts by signed integers
+				if o.name == "lsh" || o.name == "rsh" {
+					continue
+				}
+				fd := cfncData{o.name, s.name, o.symbol, "", "", "", ""}
+				for _, i := range s.i {
+					fd.Number = fmt.Sprintf("%d", i)
+					fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1)
+					for _, j := range s.i {
+						if o.name != "mod" && o.name != "div" || j != 0 {
+							fd.Ans = ansS(i, j, s.name, o.symbol)
+							fd.Input = fmt.Sprintf("%d", j)
+							err = vrf1.Execute(w, fd)
+							if err != nil {
+								panic(err)
+							}
+						}
+
+						if o.name != "mod" && o.name != "div" || i != 0 {
+							fd.Ans = ansS(j, i, s.name, o.symbol)
+							fd.Input = fmt.Sprintf("%d", j)
+							err = vrf2.Execute(w, fd)
+							if err != nil {
+								panic(err)
+							}
+						}
+
+					}
+				}
+
+			}
+		}
+	}
+
+	fmt.Fprintf(w, `if failed {
+        panic("tests failed")
+    }
+`)
+	fmt.Fprintf(w, "}\n")
+
+	// gofmt result
+	b := w.Bytes()
+	src, err := format.Source(b)
+	if err != nil {
+		fmt.Printf("%s\n", b)
+		panic(err)
+	}
+
+	// write to file
+	err = ioutil.WriteFile("../arithConst_ssa.go", src, 0666)
+	if err != nil {
+		log.Fatalf("can't write output: %v\n", err)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
new file mode 100644
index 0000000..28cdcc3
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
@@ -0,0 +1,307 @@
+// Copyright 2016 The Go 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 generates a test to verify that the standard arithmetic
+// operators properly handle constant folding. The test file should be
+// generated with a known working version of go.
+// launch with `go run constFoldGen.go` a file called constFold_test.go
+// will be written into the grandparent directory containing the tests.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/format"
+	"io/ioutil"
+	"log"
+)
+
+type op struct {
+	name, symbol string
+}
+type szD struct {
+	name string
+	sn   string
+	u    []uint64
+	i    []int64
+}
+
+var szs []szD = []szD{
+	szD{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
+	szD{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+		-4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},
+
+	szD{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}},
+	szD{name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0,
+		1, 0x7FFFFFFF}},
+
+	szD{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}},
+	szD{name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}},
+
+	szD{name: "uint8", sn: "8", u: []uint64{0, 1, 255}},
+	szD{name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}},
+}
+
+var ops = []op{
+	op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mul", "*"},
+	op{"lsh", "<<"}, op{"rsh", ">>"}, op{"mod", "%"},
+}
+
+// compute the result of i op j, cast as type t.
+func ansU(i, j uint64, t, op string) string {
+	var ans uint64
+	switch op {
+	case "+":
+		ans = i + j
+	case "-":
+		ans = i - j
+	case "*":
+		ans = i * j
+	case "/":
+		if j != 0 {
+			ans = i / j
+		}
+	case "%":
+		if j != 0 {
+			ans = i % j
+		}
+	case "<<":
+		ans = i << j
+	case ">>":
+		ans = i >> j
+	}
+	switch t {
+	case "uint32":
+		ans = uint64(uint32(ans))
+	case "uint16":
+		ans = uint64(uint16(ans))
+	case "uint8":
+		ans = uint64(uint8(ans))
+	}
+	return fmt.Sprintf("%d", ans)
+}
+
+// compute the result of i op j, cast as type t.
+func ansS(i, j int64, t, op string) string {
+	var ans int64
+	switch op {
+	case "+":
+		ans = i + j
+	case "-":
+		ans = i - j
+	case "*":
+		ans = i * j
+	case "/":
+		if j != 0 {
+			ans = i / j
+		}
+	case "%":
+		if j != 0 {
+			ans = i % j
+		}
+	case "<<":
+		ans = i << uint64(j)
+	case ">>":
+		ans = i >> uint64(j)
+	}
+	switch t {
+	case "int32":
+		ans = int64(int32(ans))
+	case "int16":
+		ans = int64(int16(ans))
+	case "int8":
+		ans = int64(int8(ans))
+	}
+	return fmt.Sprintf("%d", ans)
+}
+
+func main() {
+
+	w := new(bytes.Buffer)
+
+	fmt.Fprintf(w, "package gc\n")
+	fmt.Fprintf(w, "import \"testing\"\n")
+
+	for _, s := range szs {
+		for _, o := range ops {
+			if o.symbol == "<<" || o.symbol == ">>" {
+				// shifts handled separately below, as they can have
+				// different types on the LHS and RHS.
+				continue
+			}
+			fmt.Fprintf(w, "func TestConstFold%s%s(t *testing.T) {\n", s.name, o.name)
+			fmt.Fprintf(w, "\tvar x, y, r %s\n", s.name)
+			// unsigned test cases
+			for _, c := range s.u {
+				fmt.Fprintf(w, "\tx = %d\n", c)
+				for _, d := range s.u {
+					if d == 0 && (o.symbol == "/" || o.symbol == "%") {
+						continue
+					}
+					fmt.Fprintf(w, "\ty = %d\n", d)
+					fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
+					want := ansU(c, d, s.name, o.symbol)
+					fmt.Fprintf(w, "\tif r != %s {\n", want)
+					fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
+					fmt.Fprintf(w, "\t}\n")
+				}
+			}
+			// signed test cases
+			for _, c := range s.i {
+				fmt.Fprintf(w, "\tx = %d\n", c)
+				for _, d := range s.i {
+					if d == 0 && (o.symbol == "/" || o.symbol == "%") {
+						continue
+					}
+					fmt.Fprintf(w, "\ty = %d\n", d)
+					fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
+					want := ansS(c, d, s.name, o.symbol)
+					fmt.Fprintf(w, "\tif r != %s {\n", want)
+					fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
+					fmt.Fprintf(w, "\t}\n")
+				}
+			}
+			fmt.Fprintf(w, "}\n")
+		}
+	}
+
+	// Special signed/unsigned cases for shifts
+	for _, ls := range szs {
+		for _, rs := range szs {
+			if rs.name[0] != 'u' {
+				continue
+			}
+			for _, o := range ops {
+				if o.symbol != "<<" && o.symbol != ">>" {
+					continue
+				}
+				fmt.Fprintf(w, "func TestConstFold%s%s%s(t *testing.T) {\n", ls.name, rs.name, o.name)
+				fmt.Fprintf(w, "\tvar x, r %s\n", ls.name)
+				fmt.Fprintf(w, "\tvar y %s\n", rs.name)
+				// unsigned LHS
+				for _, c := range ls.u {
+					fmt.Fprintf(w, "\tx = %d\n", c)
+					for _, d := range rs.u {
+						fmt.Fprintf(w, "\ty = %d\n", d)
+						fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
+						want := ansU(c, d, ls.name, o.symbol)
+						fmt.Fprintf(w, "\tif r != %s {\n", want)
+						fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
+						fmt.Fprintf(w, "\t}\n")
+					}
+				}
+				// signed LHS
+				for _, c := range ls.i {
+					fmt.Fprintf(w, "\tx = %d\n", c)
+					for _, d := range rs.u {
+						fmt.Fprintf(w, "\ty = %d\n", d)
+						fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
+						want := ansS(c, int64(d), ls.name, o.symbol)
+						fmt.Fprintf(w, "\tif r != %s {\n", want)
+						fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
+						fmt.Fprintf(w, "\t}\n")
+					}
+				}
+				fmt.Fprintf(w, "}\n")
+			}
+		}
+	}
+
+	// Constant folding for comparisons
+	for _, s := range szs {
+		fmt.Fprintf(w, "func TestConstFoldCompare%s(t *testing.T) {\n", s.name)
+		for _, x := range s.i {
+			for _, y := range s.i {
+				fmt.Fprintf(w, "\t{\n")
+				fmt.Fprintf(w, "\t\tvar x %s = %d\n", s.name, x)
+				fmt.Fprintf(w, "\t\tvar y %s = %d\n", s.name, y)
+				if x == y {
+					fmt.Fprintf(w, "\t\tif !(x == y) { t.Errorf(\"!(%%d == %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x == y { t.Errorf(\"%%d == %%d\", x, y) }\n")
+				}
+				if x != y {
+					fmt.Fprintf(w, "\t\tif !(x != y) { t.Errorf(\"!(%%d != %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x != y { t.Errorf(\"%%d != %%d\", x, y) }\n")
+				}
+				if x < y {
+					fmt.Fprintf(w, "\t\tif !(x < y) { t.Errorf(\"!(%%d < %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x < y { t.Errorf(\"%%d < %%d\", x, y) }\n")
+				}
+				if x > y {
+					fmt.Fprintf(w, "\t\tif !(x > y) { t.Errorf(\"!(%%d > %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x > y { t.Errorf(\"%%d > %%d\", x, y) }\n")
+				}
+				if x <= y {
+					fmt.Fprintf(w, "\t\tif !(x <= y) { t.Errorf(\"!(%%d <= %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x <= y { t.Errorf(\"%%d <= %%d\", x, y) }\n")
+				}
+				if x >= y {
+					fmt.Fprintf(w, "\t\tif !(x >= y) { t.Errorf(\"!(%%d >= %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x >= y { t.Errorf(\"%%d >= %%d\", x, y) }\n")
+				}
+				fmt.Fprintf(w, "\t}\n")
+			}
+		}
+		for _, x := range s.u {
+			for _, y := range s.u {
+				fmt.Fprintf(w, "\t{\n")
+				fmt.Fprintf(w, "\t\tvar x %s = %d\n", s.name, x)
+				fmt.Fprintf(w, "\t\tvar y %s = %d\n", s.name, y)
+				if x == y {
+					fmt.Fprintf(w, "\t\tif !(x == y) { t.Errorf(\"!(%%d == %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x == y { t.Errorf(\"%%d == %%d\", x, y) }\n")
+				}
+				if x != y {
+					fmt.Fprintf(w, "\t\tif !(x != y) { t.Errorf(\"!(%%d != %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x != y { t.Errorf(\"%%d != %%d\", x, y) }\n")
+				}
+				if x < y {
+					fmt.Fprintf(w, "\t\tif !(x < y) { t.Errorf(\"!(%%d < %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x < y { t.Errorf(\"%%d < %%d\", x, y) }\n")
+				}
+				if x > y {
+					fmt.Fprintf(w, "\t\tif !(x > y) { t.Errorf(\"!(%%d > %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x > y { t.Errorf(\"%%d > %%d\", x, y) }\n")
+				}
+				if x <= y {
+					fmt.Fprintf(w, "\t\tif !(x <= y) { t.Errorf(\"!(%%d <= %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x <= y { t.Errorf(\"%%d <= %%d\", x, y) }\n")
+				}
+				if x >= y {
+					fmt.Fprintf(w, "\t\tif !(x >= y) { t.Errorf(\"!(%%d >= %%d)\", x, y) }\n")
+				} else {
+					fmt.Fprintf(w, "\t\tif x >= y { t.Errorf(\"%%d >= %%d\", x, y) }\n")
+				}
+				fmt.Fprintf(w, "\t}\n")
+			}
+		}
+		fmt.Fprintf(w, "}\n")
+	}
+
+	// gofmt result
+	b := w.Bytes()
+	src, err := format.Source(b)
+	if err != nil {
+		fmt.Printf("%s\n", b)
+		panic(err)
+	}
+
+	// write to file
+	err = ioutil.WriteFile("../../constFold_test.go", src, 0666)
+	if err != nil {
+		log.Fatalf("can't write output: %v\n", err)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/copyGen.go b/src/cmd/compile/internal/gc/testdata/gen/copyGen.go
new file mode 100644
index 0000000..a699fac
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/copyGen.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.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/format"
+	"io/ioutil"
+	"log"
+)
+
+// This program generates tests to verify that copying operations
+// copy the data they are supposed to and clobber no adjacent values.
+
+// run as `go run copyGen.go`.  A file called copy_ssa.go
+// will be written into the parent directory containing the tests.
+
+var sizes = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64, 65, 1023, 1024, 1025, 1024 + 7, 1024 + 8, 1024 + 9, 1024 + 15, 1024 + 16, 1024 + 17}
+
+func main() {
+	w := new(bytes.Buffer)
+	fmt.Fprintf(w, "// run\n")
+	fmt.Fprintf(w, "// autogenerated from gen/copyGen.go - do not edit!\n")
+	fmt.Fprintf(w, "package main\n")
+	fmt.Fprintf(w, "import \"fmt\"\n")
+
+	for _, s := range sizes {
+		// type for test
+		fmt.Fprintf(w, "type T%d struct {\n", s)
+		fmt.Fprintf(w, "  pre [8]byte\n")
+		fmt.Fprintf(w, "  mid [%d]byte\n", s)
+		fmt.Fprintf(w, "  post [8]byte\n")
+		fmt.Fprintf(w, "}\n")
+
+		// function being tested
+		fmt.Fprintf(w, "func t%dcopy_ssa(y, x *[%d]byte) {\n", s, s)
+		fmt.Fprintf(w, "  switch{}\n")
+		fmt.Fprintf(w, "  *y = *x\n")
+		fmt.Fprintf(w, "}\n")
+
+		// testing harness
+		fmt.Fprintf(w, "func testCopy%d() {\n", s)
+		fmt.Fprintf(w, "  a := T%d{[8]byte{201, 202, 203, 204, 205, 206, 207, 208},[%d]byte{", s, s)
+		for i := 0; i < s; i++ {
+			fmt.Fprintf(w, "%d,", i%100)
+		}
+		fmt.Fprintf(w, "},[8]byte{211, 212, 213, 214, 215, 216, 217, 218}}\n")
+		fmt.Fprintf(w, "  x := [%d]byte{", s)
+		for i := 0; i < s; i++ {
+			fmt.Fprintf(w, "%d,", 100+i%100)
+		}
+		fmt.Fprintf(w, "}\n")
+		fmt.Fprintf(w, "  t%dcopy_ssa(&a.mid, &x)\n", s)
+		fmt.Fprintf(w, "  want := T%d{[8]byte{201, 202, 203, 204, 205, 206, 207, 208},[%d]byte{", s, s)
+		for i := 0; i < s; i++ {
+			fmt.Fprintf(w, "%d,", 100+i%100)
+		}
+		fmt.Fprintf(w, "},[8]byte{211, 212, 213, 214, 215, 216, 217, 218}}\n")
+		fmt.Fprintf(w, "  if a != want {\n")
+		fmt.Fprintf(w, "    fmt.Printf(\"t%dcopy got=%%v, want %%v\\n\", a, want)\n", s)
+		fmt.Fprintf(w, "    failed=true\n")
+		fmt.Fprintf(w, "  }\n")
+		fmt.Fprintf(w, "}\n")
+	}
+
+	// boilerplate at end
+	fmt.Fprintf(w, "var failed bool\n")
+	fmt.Fprintf(w, "func main() {\n")
+	for _, s := range sizes {
+		fmt.Fprintf(w, "  testCopy%d()\n", s)
+	}
+	fmt.Fprintf(w, "  if failed {\n")
+	fmt.Fprintf(w, "    panic(\"failed\")\n")
+	fmt.Fprintf(w, "  }\n")
+	fmt.Fprintf(w, "}\n")
+
+	// gofmt result
+	b := w.Bytes()
+	src, err := format.Source(b)
+	if err != nil {
+		fmt.Printf("%s\n", b)
+		panic(err)
+	}
+
+	// write to file
+	err = ioutil.WriteFile("../copy_ssa.go", src, 0666)
+	if err != nil {
+		log.Fatalf("can't write output: %v\n", err)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
new file mode 100644
index 0000000..90e8029
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
@@ -0,0 +1,88 @@
+// Copyright 2015 The Go Authors. 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/format"
+	"io/ioutil"
+	"log"
+)
+
+// This program generates tests to verify that zeroing operations
+// zero the data they are supposed to and clobber no adjacent values.
+
+// run as `go run zeroGen.go`.  A file called zero_ssa.go
+// will be written into the parent directory containing the tests.
+
+var sizes = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64, 65, 1023, 1024, 1025}
+
+func main() {
+	w := new(bytes.Buffer)
+	fmt.Fprintf(w, "// run\n")
+	fmt.Fprintf(w, "// autogenerated from gen/zeroGen.go - do not edit!\n")
+	fmt.Fprintf(w, "package main\n")
+	fmt.Fprintf(w, "import \"fmt\"\n")
+
+	for _, s := range sizes {
+		// type for test
+		fmt.Fprintf(w, "type T%d struct {\n", s)
+		fmt.Fprintf(w, "  pre [8]byte\n")
+		fmt.Fprintf(w, "  mid [%d]byte\n", s)
+		fmt.Fprintf(w, "  post [8]byte\n")
+		fmt.Fprintf(w, "}\n")
+
+		// function being tested
+		fmt.Fprintf(w, "func zero%d_ssa(x *[%d]byte) {\n", s, s)
+		fmt.Fprintf(w, "  switch{}\n")
+		fmt.Fprintf(w, "  *x = [%d]byte{}\n", s)
+		fmt.Fprintf(w, "}\n")
+
+		// testing harness
+		fmt.Fprintf(w, "func testZero%d() {\n", s)
+		fmt.Fprintf(w, "  a := T%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s)
+		for i := 0; i < s; i++ {
+			fmt.Fprintf(w, "255,")
+		}
+		fmt.Fprintf(w, "},[8]byte{255,255,255,255,255,255,255,255}}\n")
+		fmt.Fprintf(w, "  zero%d_ssa(&a.mid)\n", s)
+		fmt.Fprintf(w, "  want := T%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s)
+		for i := 0; i < s; i++ {
+			fmt.Fprintf(w, "0,")
+		}
+		fmt.Fprintf(w, "},[8]byte{255,255,255,255,255,255,255,255}}\n")
+		fmt.Fprintf(w, "  if a != want {\n")
+		fmt.Fprintf(w, "    fmt.Printf(\"zero%d got=%%v, want %%v\\n\", a, want)\n", s)
+		fmt.Fprintf(w, "    failed=true\n")
+		fmt.Fprintf(w, "  }\n")
+		fmt.Fprintf(w, "}\n")
+	}
+
+	// boilerplate at end
+	fmt.Fprintf(w, "var failed bool\n")
+	fmt.Fprintf(w, "func main() {\n")
+	for _, s := range sizes {
+		fmt.Fprintf(w, "  testZero%d()\n", s)
+	}
+	fmt.Fprintf(w, "  if failed {\n")
+	fmt.Fprintf(w, "    panic(\"failed\")\n")
+	fmt.Fprintf(w, "  }\n")
+	fmt.Fprintf(w, "}\n")
+
+	// gofmt result
+	b := w.Bytes()
+	src, err := format.Source(b)
+	if err != nil {
+		fmt.Printf("%s\n", b)
+		panic(err)
+	}
+
+	// write to file
+	err = ioutil.WriteFile("../zero_ssa.go", src, 0666)
+	if err != nil {
+		log.Fatalf("can't write output: %v\n", err)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/loadstore_ssa.go b/src/cmd/compile/internal/gc/testdata/loadstore_ssa.go
new file mode 100644
index 0000000..4d67864
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/loadstore_ssa.go
@@ -0,0 +1,115 @@
+// 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.
+
+// Tests load/store ordering
+
+package main
+
+import "fmt"
+
+// testLoadStoreOrder tests for reordering of stores/loads.
+func testLoadStoreOrder() {
+	z := uint32(1000)
+	if testLoadStoreOrder_ssa(&z, 100) == 0 {
+		println("testLoadStoreOrder failed")
+		failed = true
+	}
+}
+
+//go:noinline
+func testLoadStoreOrder_ssa(z *uint32, prec uint) int {
+	old := *z         // load
+	*z = uint32(prec) // store
+	if *z < old {     // load
+		return 1
+	}
+	return 0
+}
+
+func testStoreSize() {
+	a := [4]uint16{11, 22, 33, 44}
+	testStoreSize_ssa(&a[0], &a[2], 77)
+	want := [4]uint16{77, 22, 33, 44}
+	if a != want {
+		fmt.Println("testStoreSize failed.  want =", want, ", got =", a)
+		failed = true
+	}
+}
+
+//go:noinline
+func testStoreSize_ssa(p *uint16, q *uint16, v uint32) {
+	// Test to make sure that (Store ptr (Trunc32to16 val) mem)
+	// does not end up as a 32-bit store. It must stay a 16 bit store
+	// even when Trunc32to16 is rewritten to be a nop.
+	// To ensure that we get rewrite the Trunc32to16 before
+	// we rewrite the Store, we force the truncate into an
+	// earlier basic block by using it on both branches.
+	w := uint16(v)
+	if p != nil {
+		*p = w
+	} else {
+		*q = w
+	}
+}
+
+var failed = false
+
+//go:noinline
+func testExtStore_ssa(p *byte, b bool) int {
+	x := *p
+	*p = 7
+	if b {
+		return int(x)
+	}
+	return 0
+}
+
+func testExtStore() {
+	const start = 8
+	var b byte = start
+	if got := testExtStore_ssa(&b, true); got != start {
+		fmt.Println("testExtStore failed.  want =", start, ", got =", got)
+		failed = true
+	}
+}
+
+var b int
+
+// testDeadStorePanic_ssa ensures that we don't optimize away stores
+// that could be read by after recover().  Modeled after fixedbugs/issue1304.
+//go:noinline
+func testDeadStorePanic_ssa(a int) (r int) {
+	defer func() {
+		recover()
+		r = a
+	}()
+	a = 2      // store
+	b := a - a // optimized to zero
+	c := 4
+	a = c / b // store, but panics
+	a = 3     // store
+	r = a
+	return
+}
+
+func testDeadStorePanic() {
+	if want, got := 2, testDeadStorePanic_ssa(1); want != got {
+		fmt.Println("testDeadStorePanic failed.  want =", want, ", got =", got)
+		failed = true
+	}
+}
+
+func main() {
+
+	testLoadStoreOrder()
+	testStoreSize()
+	testExtStore()
+	testDeadStorePanic()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/map_ssa.go b/src/cmd/compile/internal/gc/testdata/map_ssa.go
new file mode 100644
index 0000000..4a46600
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/map_ssa.go
@@ -0,0 +1,45 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// map_ssa.go tests map operations.
+package main
+
+import "fmt"
+
+var failed = false
+
+//go:noinline
+func lenMap_ssa(v map[int]int) int {
+	return len(v)
+}
+
+func testLenMap() {
+
+	v := make(map[int]int)
+	v[0] = 0
+	v[1] = 0
+	v[2] = 0
+
+	if want, got := 3, lenMap_ssa(v); got != want {
+		fmt.Printf("expected len(map) = %d, got %d", want, got)
+		failed = true
+	}
+}
+
+func testLenNilMap() {
+
+	var v map[int]int
+	if want, got := 0, lenMap_ssa(v); got != want {
+		fmt.Printf("expected len(nil) = %d, got %d", want, got)
+		failed = true
+	}
+}
+func main() {
+	testLenMap()
+	testLenNilMap()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/namedReturn.go b/src/cmd/compile/internal/gc/testdata/namedReturn.go
new file mode 100644
index 0000000..19ef8a7
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/namedReturn.go
@@ -0,0 +1,105 @@
+// run
+
+// Copyright 2016 The Go 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 makes sure that naming named
+// return variables in a return statement works.
+// See issue #14904.
+
+package main
+
+import (
+	"fmt"
+	"runtime"
+)
+
+// Our heap-allocated object that will be GC'd incorrectly.
+// Note that we always check the second word because that's
+// where 0xdeaddeaddeaddead is written.
+type B [4]int
+
+// small (SSAable) array
+type T1 [3]*B
+
+//go:noinline
+func f1() (t T1) {
+	t[0] = &B{91, 92, 93, 94}
+	runtime.GC()
+	return t
+}
+
+// large (non-SSAable) array
+type T2 [8]*B
+
+//go:noinline
+func f2() (t T2) {
+	t[0] = &B{91, 92, 93, 94}
+	runtime.GC()
+	return t
+}
+
+// small (SSAable) struct
+type T3 struct {
+	a, b, c *B
+}
+
+//go:noinline
+func f3() (t T3) {
+	t.a = &B{91, 92, 93, 94}
+	runtime.GC()
+	return t
+}
+
+// large (non-SSAable) struct
+type T4 struct {
+	a, b, c, d, e, f *B
+}
+
+//go:noinline
+func f4() (t T4) {
+	t.a = &B{91, 92, 93, 94}
+	runtime.GC()
+	return t
+}
+
+var sink *B
+
+func f5() int {
+	b := &B{91, 92, 93, 94}
+	t := T4{b, nil, nil, nil, nil, nil}
+	sink = b   // make sure b is heap allocated ...
+	sink = nil // ... but not live
+	runtime.GC()
+	t = t
+	return t.a[1]
+}
+
+func main() {
+	failed := false
+
+	if v := f1()[0][1]; v != 92 {
+		fmt.Printf("f1()[0][1]=%d, want 92\n", v)
+		failed = true
+	}
+	if v := f2()[0][1]; v != 92 {
+		fmt.Printf("f2()[0][1]=%d, want 92\n", v)
+		failed = true
+	}
+	if v := f3().a[1]; v != 92 {
+		fmt.Printf("f3().a[1]=%d, want 92\n", v)
+		failed = true
+	}
+	if v := f4().a[1]; v != 92 {
+		fmt.Printf("f4().a[1]=%d, want 92\n", v)
+		failed = true
+	}
+	if v := f5(); v != 92 {
+		fmt.Printf("f5()=%d, want 92\n", v)
+		failed = true
+	}
+	if failed {
+		panic("bad")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/phi_ssa.go b/src/cmd/compile/internal/gc/testdata/phi_ssa.go
new file mode 100644
index 0000000..6469bfe
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/phi_ssa.go
@@ -0,0 +1,103 @@
+// Copyright 2016 The Go Authors. 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 to make sure spills of cast-shortened values
+// don't end up spilling the pre-shortened size instead
+// of the post-shortened size.
+
+import (
+	"fmt"
+	"runtime"
+)
+
+// unfoldable true
+var true_ = true
+
+var data1 [26]int32
+var data2 [26]int64
+
+func init() {
+	for i := 0; i < 26; i++ {
+		// If we spill all 8 bytes of this datum, the 1 in the high-order 4 bytes
+		// will overwrite some other variable in the stack frame.
+		data2[i] = 0x100000000
+	}
+}
+
+func foo() int32 {
+	var a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int32
+	if true_ {
+		a = data1[0]
+		b = data1[1]
+		c = data1[2]
+		d = data1[3]
+		e = data1[4]
+		f = data1[5]
+		g = data1[6]
+		h = data1[7]
+		i = data1[8]
+		j = data1[9]
+		k = data1[10]
+		l = data1[11]
+		m = data1[12]
+		n = data1[13]
+		o = data1[14]
+		p = data1[15]
+		q = data1[16]
+		r = data1[17]
+		s = data1[18]
+		t = data1[19]
+		u = data1[20]
+		v = data1[21]
+		w = data1[22]
+		x = data1[23]
+		y = data1[24]
+		z = data1[25]
+	} else {
+		a = int32(data2[0])
+		b = int32(data2[1])
+		c = int32(data2[2])
+		d = int32(data2[3])
+		e = int32(data2[4])
+		f = int32(data2[5])
+		g = int32(data2[6])
+		h = int32(data2[7])
+		i = int32(data2[8])
+		j = int32(data2[9])
+		k = int32(data2[10])
+		l = int32(data2[11])
+		m = int32(data2[12])
+		n = int32(data2[13])
+		o = int32(data2[14])
+		p = int32(data2[15])
+		q = int32(data2[16])
+		r = int32(data2[17])
+		s = int32(data2[18])
+		t = int32(data2[19])
+		u = int32(data2[20])
+		v = int32(data2[21])
+		w = int32(data2[22])
+		x = int32(data2[23])
+		y = int32(data2[24])
+		z = int32(data2[25])
+	}
+	// Lots of phis of the form phi(int32,int64) of type int32 happen here.
+	// Some will be stack phis. For those stack phis, make sure the spill
+	// of the second argument uses the phi's width (4 bytes), not its width
+	// (8 bytes).  Otherwise, a random stack slot gets clobbered.
+
+	runtime.Gosched()
+	return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r + s + t + u + v + w + x + y + z
+}
+
+func main() {
+	want := int32(0)
+	got := foo()
+	if got != want {
+		fmt.Printf("want %d, got %d\n", want, got)
+		panic("bad")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/regalloc_ssa.go b/src/cmd/compile/internal/gc/testdata/regalloc_ssa.go
new file mode 100644
index 0000000..f752692
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/regalloc_ssa.go
@@ -0,0 +1,57 @@
+// 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.
+
+// Tests phi implementation
+
+package main
+
+func phiOverwrite_ssa() int {
+	var n int
+	for i := 0; i < 10; i++ {
+		if i == 6 {
+			break
+		}
+		n = i
+	}
+	return n
+}
+
+func phiOverwrite() {
+	want := 5
+	got := phiOverwrite_ssa()
+	if got != want {
+		println("phiOverwrite_ssa()=", want, ", got", got)
+		failed = true
+	}
+}
+
+func phiOverwriteBig_ssa() int {
+	var a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int
+	a = 1
+	for idx := 0; idx < 26; idx++ {
+		a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z = b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, a
+	}
+	return a*1 + b*2 + c*3 + d*4 + e*5 + f*6 + g*7 + h*8 + i*9 + j*10 + k*11 + l*12 + m*13 + n*14 + o*15 + p*16 + q*17 + r*18 + s*19 + t*20 + u*21 + v*22 + w*23 + x*24 + y*25 + z*26
+}
+
+func phiOverwriteBig() {
+	want := 1
+	got := phiOverwriteBig_ssa()
+	if got != want {
+		println("phiOverwriteBig_ssa()=", want, ", got", got)
+		failed = true
+	}
+}
+
+var failed = false
+
+func main() {
+	phiOverwrite()
+	phiOverwriteBig()
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/short_ssa.go b/src/cmd/compile/internal/gc/testdata/short_ssa.go
new file mode 100644
index 0000000..fcec1ba
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/short_ssa.go
@@ -0,0 +1,60 @@
+// 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.
+
+// Tests short circuiting.
+
+package main
+
+func and_ssa(arg1, arg2 bool) bool {
+	return arg1 && rightCall(arg2)
+}
+
+func or_ssa(arg1, arg2 bool) bool {
+	return arg1 || rightCall(arg2)
+}
+
+var rightCalled bool
+
+//go:noinline
+func rightCall(v bool) bool {
+	rightCalled = true
+	return v
+	panic("unreached")
+}
+
+func testAnd(arg1, arg2, wantRes bool) { testShortCircuit("AND", arg1, arg2, and_ssa, arg1, wantRes) }
+func testOr(arg1, arg2, wantRes bool)  { testShortCircuit("OR", arg1, arg2, or_ssa, !arg1, wantRes) }
+
+func testShortCircuit(opName string, arg1, arg2 bool, fn func(bool, bool) bool, wantRightCall, wantRes bool) {
+	rightCalled = false
+	got := fn(arg1, arg2)
+	if rightCalled != wantRightCall {
+		println("failed for", arg1, opName, arg2, "; rightCalled=", rightCalled, "want=", wantRightCall)
+		failed = true
+	}
+	if wantRes != got {
+		println("failed for", arg1, opName, arg2, "; res=", got, "want=", wantRes)
+		failed = true
+	}
+}
+
+var failed = false
+
+func main() {
+	testAnd(false, false, false)
+	testAnd(false, true, false)
+	testAnd(true, false, false)
+	testAnd(true, true, true)
+
+	testOr(false, false, false)
+	testOr(false, true, true)
+	testOr(true, false, true)
+	testOr(true, true, true)
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/slice.go b/src/cmd/compile/internal/gc/testdata/slice.go
new file mode 100644
index 0000000..a02e4a4
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/slice.go
@@ -0,0 +1,50 @@
+// run
+
+// This test makes sure that t.s = t.s[0:x] doesn't write
+// either the slice pointer or the capacity.
+// See issue #14855.
+
+package main
+
+import "fmt"
+
+const N = 1000000
+
+type T struct {
+	s []int
+}
+
+func main() {
+	done := make(chan struct{})
+	a := make([]int, N+10)
+
+	t := &T{a}
+
+	go func() {
+		for i := 0; i < N; i++ {
+			t.s = t.s[1:9]
+		}
+		done <- struct{}{}
+	}()
+	go func() {
+		for i := 0; i < N; i++ {
+			t.s = t.s[0:8] // should only write len
+		}
+		done <- struct{}{}
+	}()
+	<-done
+	<-done
+
+	ok := true
+	if cap(t.s) != cap(a)-N {
+		fmt.Printf("wanted cap=%d, got %d\n", cap(a)-N, cap(t.s))
+		ok = false
+	}
+	if &t.s[0] != &a[N] {
+		fmt.Printf("wanted ptr=%p, got %p\n", &a[N], &t.s[0])
+		ok = false
+	}
+	if !ok {
+		panic("bad")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/string_ssa.go b/src/cmd/compile/internal/gc/testdata/string_ssa.go
new file mode 100644
index 0000000..b47c2f1
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/string_ssa.go
@@ -0,0 +1,160 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// string_ssa.go tests string operations.
+package main
+
+var failed = false
+
+//go:noinline
+func testStringSlice1_ssa(a string, i, j int) string {
+	return a[i:]
+}
+
+//go:noinline
+func testStringSlice2_ssa(a string, i, j int) string {
+	return a[:j]
+}
+
+//go:noinline
+func testStringSlice12_ssa(a string, i, j int) string {
+	return a[i:j]
+}
+
+func testStringSlice() {
+	tests := [...]struct {
+		fn        func(string, int, int) string
+		s         string
+		low, high int
+		want      string
+	}{
+		// -1 means the value is not used.
+		{testStringSlice1_ssa, "foobar", 0, -1, "foobar"},
+		{testStringSlice1_ssa, "foobar", 3, -1, "bar"},
+		{testStringSlice1_ssa, "foobar", 6, -1, ""},
+		{testStringSlice2_ssa, "foobar", -1, 0, ""},
+		{testStringSlice2_ssa, "foobar", -1, 3, "foo"},
+		{testStringSlice2_ssa, "foobar", -1, 6, "foobar"},
+		{testStringSlice12_ssa, "foobar", 0, 6, "foobar"},
+		{testStringSlice12_ssa, "foobar", 0, 0, ""},
+		{testStringSlice12_ssa, "foobar", 6, 6, ""},
+		{testStringSlice12_ssa, "foobar", 1, 5, "ooba"},
+		{testStringSlice12_ssa, "foobar", 3, 3, ""},
+		{testStringSlice12_ssa, "", 0, 0, ""},
+	}
+
+	for i, t := range tests {
+		if got := t.fn(t.s, t.low, t.high); t.want != got {
+			println("#", i, " ", t.s, "[", t.low, ":", t.high, "] = ", got, " want ", t.want)
+			failed = true
+		}
+	}
+}
+
+type prefix struct {
+	prefix string
+}
+
+func (p *prefix) slice_ssa() {
+	p.prefix = p.prefix[:3]
+}
+
+//go:noinline
+func testStructSlice() {
+	p := &prefix{"prefix"}
+	p.slice_ssa()
+	if "pre" != p.prefix {
+		println("wrong field slice: wanted %s got %s", "pre", p.prefix)
+		failed = true
+	}
+}
+
+func testStringSlicePanic() {
+	defer func() {
+		if r := recover(); r != nil {
+			println("paniced as expected")
+		}
+	}()
+
+	str := "foobar"
+	println("got ", testStringSlice12_ssa(str, 3, 9))
+	println("expected to panic, but didn't")
+	failed = true
+}
+
+const _Accuracy_name = "BelowExactAbove"
+
+var _Accuracy_index = [...]uint8{0, 5, 10, 15}
+
+//go:noinline
+func testSmallIndexType_ssa(i int) string {
+	return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]]
+}
+
+func testSmallIndexType() {
+	tests := []struct {
+		i    int
+		want string
+	}{
+		{0, "Below"},
+		{1, "Exact"},
+		{2, "Above"},
+	}
+
+	for i, t := range tests {
+		if got := testSmallIndexType_ssa(t.i); got != t.want {
+			println("#", i, "got ", got, ", wanted", t.want)
+			failed = true
+		}
+	}
+}
+
+//go:noinline
+func testStringElem_ssa(s string, i int) byte {
+	return s[i]
+}
+
+func testStringElem() {
+	tests := []struct {
+		s string
+		i int
+		n byte
+	}{
+		{"foobar", 3, 98},
+		{"foobar", 0, 102},
+		{"foobar", 5, 114},
+	}
+	for _, t := range tests {
+		if got := testStringElem_ssa(t.s, t.i); got != t.n {
+			print("testStringElem \"", t.s, "\"[", t.i, "]=", got, ", wanted ", t.n, "\n")
+			failed = true
+		}
+	}
+}
+
+//go:noinline
+func testStringElemConst_ssa(i int) byte {
+	s := "foobar"
+	return s[i]
+}
+
+func testStringElemConst() {
+	if got := testStringElemConst_ssa(3); got != 98 {
+		println("testStringElemConst=", got, ", wanted 98")
+		failed = true
+	}
+}
+
+func main() {
+	testStringSlice()
+	testStringSlicePanic()
+	testStructSlice()
+	testSmallIndexType()
+	testStringElem()
+	testStringElemConst()
+
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/testdata/unsafe_ssa.go b/src/cmd/compile/internal/gc/testdata/unsafe_ssa.go
new file mode 100644
index 0000000..a3d9dbc
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/unsafe_ssa.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 main
+
+import (
+	"fmt"
+	"runtime"
+	"unsafe"
+)
+
+// global pointer slot
+var a *[8]uint
+
+// unfoldable true
+var b = true
+
+// Test to make sure that a pointer value which is alive
+// across a call is retained, even when there are matching
+// conversions to/from uintptr around the call.
+// We arrange things very carefully to have to/from
+// conversions on either side of the call which cannot be
+// combined with any other conversions.
+func f_ssa() *[8]uint {
+	// Make x a uintptr pointing to where a points.
+	var x uintptr
+	if b {
+		x = uintptr(unsafe.Pointer(a))
+	} else {
+		x = 0
+	}
+	// Clobber the global pointer. The only live ref
+	// to the allocated object is now x.
+	a = nil
+
+	// Convert to pointer so it should hold
+	// the object live across GC call.
+	p := unsafe.Pointer(x)
+
+	// Call gc.
+	runtime.GC()
+
+	// Convert back to uintptr.
+	y := uintptr(p)
+
+	// Mess with y so that the subsequent cast
+	// to unsafe.Pointer can't be combined with the
+	// uintptr cast above.
+	var z uintptr
+	if b {
+		z = y
+	} else {
+		z = 0
+	}
+	return (*[8]uint)(unsafe.Pointer(z))
+}
+
+// g_ssa is the same as f_ssa, but with a bit of pointer
+// arithmetic for added insanity.
+func g_ssa() *[7]uint {
+	// Make x a uintptr pointing to where a points.
+	var x uintptr
+	if b {
+		x = uintptr(unsafe.Pointer(a))
+	} else {
+		x = 0
+	}
+	// Clobber the global pointer. The only live ref
+	// to the allocated object is now x.
+	a = nil
+
+	// Offset x by one int.
+	x += unsafe.Sizeof(int(0))
+
+	// Convert to pointer so it should hold
+	// the object live across GC call.
+	p := unsafe.Pointer(x)
+
+	// Call gc.
+	runtime.GC()
+
+	// Convert back to uintptr.
+	y := uintptr(p)
+
+	// Mess with y so that the subsequent cast
+	// to unsafe.Pointer can't be combined with the
+	// uintptr cast above.
+	var z uintptr
+	if b {
+		z = y
+	} else {
+		z = 0
+	}
+	return (*[7]uint)(unsafe.Pointer(z))
+}
+
+func testf() {
+	a = new([8]uint)
+	for i := 0; i < 8; i++ {
+		a[i] = 0xabcd
+	}
+	c := f_ssa()
+	for i := 0; i < 8; i++ {
+		if c[i] != 0xabcd {
+			fmt.Printf("%d:%x\n", i, c[i])
+			panic("bad c")
+		}
+	}
+}
+
+func testg() {
+	a = new([8]uint)
+	for i := 0; i < 8; i++ {
+		a[i] = 0xabcd
+	}
+	c := g_ssa()
+	for i := 0; i < 7; i++ {
+		if c[i] != 0xabcd {
+			fmt.Printf("%d:%x\n", i, c[i])
+			panic("bad c")
+		}
+	}
+}
+
+func alias_ssa(ui64 *uint64, ui32 *uint32) uint32 {
+	*ui32 = 0xffffffff
+	*ui64 = 0                  // store
+	ret := *ui32               // load from same address, should be zero
+	*ui64 = 0xffffffffffffffff // store
+	return ret
+}
+func testdse() {
+	x := int64(-1)
+	// construct two pointers that alias one another
+	ui64 := (*uint64)(unsafe.Pointer(&x))
+	ui32 := (*uint32)(unsafe.Pointer(&x))
+	if want, got := uint32(0), alias_ssa(ui64, ui32); got != want {
+		fmt.Printf("alias_ssa: wanted %d, got %d\n", want, got)
+		panic("alias_ssa")
+	}
+}
+
+func main() {
+	testf()
+	testg()
+	testdse()
+}
diff --git a/src/cmd/compile/internal/gc/testdata/zero_ssa.go b/src/cmd/compile/internal/gc/testdata/zero_ssa.go
new file mode 100644
index 0000000..68334db
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/zero_ssa.go
@@ -0,0 +1,538 @@
+// run
+// autogenerated from gen/zeroGen.go - do not edit!
+package main
+
+import "fmt"
+
+type T1 struct {
+	pre  [8]byte
+	mid  [1]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero1_ssa(x *[1]byte) {
+	*x = [1]byte{}
+}
+func testZero1() {
+	a := T1{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1]byte{255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero1_ssa(&a.mid)
+	want := T1{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1]byte{0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero1 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T2 struct {
+	pre  [8]byte
+	mid  [2]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero2_ssa(x *[2]byte) {
+	*x = [2]byte{}
+}
+func testZero2() {
+	a := T2{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [2]byte{255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero2_ssa(&a.mid)
+	want := T2{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [2]byte{0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero2 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T3 struct {
+	pre  [8]byte
+	mid  [3]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero3_ssa(x *[3]byte) {
+	*x = [3]byte{}
+}
+func testZero3() {
+	a := T3{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [3]byte{255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero3_ssa(&a.mid)
+	want := T3{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [3]byte{0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero3 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T4 struct {
+	pre  [8]byte
+	mid  [4]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero4_ssa(x *[4]byte) {
+	*x = [4]byte{}
+}
+func testZero4() {
+	a := T4{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [4]byte{255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero4_ssa(&a.mid)
+	want := T4{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [4]byte{0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero4 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T5 struct {
+	pre  [8]byte
+	mid  [5]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero5_ssa(x *[5]byte) {
+	*x = [5]byte{}
+}
+func testZero5() {
+	a := T5{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [5]byte{255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero5_ssa(&a.mid)
+	want := T5{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [5]byte{0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero5 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T6 struct {
+	pre  [8]byte
+	mid  [6]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero6_ssa(x *[6]byte) {
+	*x = [6]byte{}
+}
+func testZero6() {
+	a := T6{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [6]byte{255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero6_ssa(&a.mid)
+	want := T6{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [6]byte{0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero6 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T7 struct {
+	pre  [8]byte
+	mid  [7]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero7_ssa(x *[7]byte) {
+	*x = [7]byte{}
+}
+func testZero7() {
+	a := T7{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [7]byte{255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero7_ssa(&a.mid)
+	want := T7{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [7]byte{0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero7 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T8 struct {
+	pre  [8]byte
+	mid  [8]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero8_ssa(x *[8]byte) {
+	*x = [8]byte{}
+}
+func testZero8() {
+	a := T8{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero8_ssa(&a.mid)
+	want := T8{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero8 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T9 struct {
+	pre  [8]byte
+	mid  [9]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero9_ssa(x *[9]byte) {
+	*x = [9]byte{}
+}
+func testZero9() {
+	a := T9{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [9]byte{255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero9_ssa(&a.mid)
+	want := T9{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [9]byte{0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero9 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T10 struct {
+	pre  [8]byte
+	mid  [10]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero10_ssa(x *[10]byte) {
+	*x = [10]byte{}
+}
+func testZero10() {
+	a := T10{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [10]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero10_ssa(&a.mid)
+	want := T10{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [10]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero10 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T15 struct {
+	pre  [8]byte
+	mid  [15]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero15_ssa(x *[15]byte) {
+	*x = [15]byte{}
+}
+func testZero15() {
+	a := T15{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [15]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero15_ssa(&a.mid)
+	want := T15{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [15]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero15 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T16 struct {
+	pre  [8]byte
+	mid  [16]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero16_ssa(x *[16]byte) {
+	*x = [16]byte{}
+}
+func testZero16() {
+	a := T16{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero16_ssa(&a.mid)
+	want := T16{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero16 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T17 struct {
+	pre  [8]byte
+	mid  [17]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero17_ssa(x *[17]byte) {
+	*x = [17]byte{}
+}
+func testZero17() {
+	a := T17{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [17]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero17_ssa(&a.mid)
+	want := T17{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [17]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero17 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T23 struct {
+	pre  [8]byte
+	mid  [23]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero23_ssa(x *[23]byte) {
+	*x = [23]byte{}
+}
+func testZero23() {
+	a := T23{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [23]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero23_ssa(&a.mid)
+	want := T23{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [23]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero23 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T24 struct {
+	pre  [8]byte
+	mid  [24]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero24_ssa(x *[24]byte) {
+	*x = [24]byte{}
+}
+func testZero24() {
+	a := T24{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero24_ssa(&a.mid)
+	want := T24{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero24 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T25 struct {
+	pre  [8]byte
+	mid  [25]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero25_ssa(x *[25]byte) {
+	*x = [25]byte{}
+}
+func testZero25() {
+	a := T25{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [25]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero25_ssa(&a.mid)
+	want := T25{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [25]byte{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}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero25 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T31 struct {
+	pre  [8]byte
+	mid  [31]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero31_ssa(x *[31]byte) {
+	*x = [31]byte{}
+}
+func testZero31() {
+	a := T31{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [31]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero31_ssa(&a.mid)
+	want := T31{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [31]byte{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}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero31 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T32 struct {
+	pre  [8]byte
+	mid  [32]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero32_ssa(x *[32]byte) {
+	*x = [32]byte{}
+}
+func testZero32() {
+	a := T32{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero32_ssa(&a.mid)
+	want := T32{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [32]byte{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}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero32 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T33 struct {
+	pre  [8]byte
+	mid  [33]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero33_ssa(x *[33]byte) {
+	*x = [33]byte{}
+}
+func testZero33() {
+	a := T33{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [33]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero33_ssa(&a.mid)
+	want := T33{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [33]byte{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, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero33 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T63 struct {
+	pre  [8]byte
+	mid  [63]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero63_ssa(x *[63]byte) {
+	*x = [63]byte{}
+}
+func testZero63() {
+	a := T63{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [63]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero63_ssa(&a.mid)
+	want := T63{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [63]byte{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, 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}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero63 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T64 struct {
+	pre  [8]byte
+	mid  [64]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero64_ssa(x *[64]byte) {
+	*x = [64]byte{}
+}
+func testZero64() {
+	a := T64{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero64_ssa(&a.mid)
+	want := T64{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [64]byte{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, 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}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero64 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T65 struct {
+	pre  [8]byte
+	mid  [65]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero65_ssa(x *[65]byte) {
+	*x = [65]byte{}
+}
+func testZero65() {
+	a := T65{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [65]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	zero65_ssa(&a.mid)
+	want := T65{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [65]byte{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, 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, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}}
+	if a != want {
+		fmt.Printf("zero65 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1023 struct {
+	pre  [8]byte
+	mid  [1023]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero1023_ssa(x *[1023]byte) {
+	*x = [1023]byte{}
+}
+func testZero1023() {
+	a := T1023{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1023]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  [...]
+	zero1023_ssa(&a.mid)
+	want := T1023{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1023]byte{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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  [...]
+	if a != want {
+		fmt.Printf("zero1023 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1024 struct {
+	pre  [8]byte
+	mid  [1024]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero1024_ssa(x *[1024]byte) {
+	*x = [1024]byte{}
+}
+func testZero1024() {
+	a := T1024{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1024]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  [...]
+	zero1024_ssa(&a.mid)
+	want := T1024{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1024]byte{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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  [...]
+	if a != want {
+		fmt.Printf("zero1024 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+type T1025 struct {
+	pre  [8]byte
+	mid  [1025]byte
+	post [8]byte
+}
+
+//go:noinline
+func zero1025_ssa(x *[1025]byte) {
+	*x = [1025]byte{}
+}
+func testZero1025() {
+	a := T1025{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1025]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,  [...]
+	zero1025_ssa(&a.mid)
+	want := T1025{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1025]byte{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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  [...]
+	if a != want {
+		fmt.Printf("zero1025 got=%v, want %v\n", a, want)
+		failed = true
+	}
+}
+
+var failed bool
+
+func main() {
+	testZero1()
+	testZero2()
+	testZero3()
+	testZero4()
+	testZero5()
+	testZero6()
+	testZero7()
+	testZero8()
+	testZero9()
+	testZero10()
+	testZero15()
+	testZero16()
+	testZero17()
+	testZero23()
+	testZero24()
+	testZero25()
+	testZero31()
+	testZero32()
+	testZero33()
+	testZero63()
+	testZero64()
+	testZero65()
+	testZero1023()
+	testZero1024()
+	testZero1025()
+	if failed {
+		panic("failed")
+	}
+}
diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go
new file mode 100644
index 0000000..ab13df6
--- /dev/null
+++ b/src/cmd/compile/internal/gc/type.go
@@ -0,0 +1,1224 @@
+// Copyright 2015 The Go 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 methods that let us export a Type as an ../ssa:Type.
+// We don't export this package's Type directly because it would lead
+// to an import cycle with this package and ../ssa.
+// TODO: move Type to its own package, then we don't need to dance around import cycles.
+
+package gc
+
+import (
+	"cmd/compile/internal/ssa"
+	"fmt"
+)
+
+// EType describes a kind of type.
+type EType uint8
+
+const (
+	Txxx = iota
+
+	TINT8
+	TUINT8
+	TINT16
+	TUINT16
+	TINT32
+	TUINT32
+	TINT64
+	TUINT64
+	TINT
+	TUINT
+	TUINTPTR
+
+	TCOMPLEX64
+	TCOMPLEX128
+
+	TFLOAT32
+	TFLOAT64
+
+	TBOOL
+
+	TPTR32
+	TPTR64
+
+	TFUNC
+	TSLICE
+	TARRAY
+	TSTRUCT
+	TCHAN
+	TMAP
+	TINTER
+	TFORW
+	TANY
+	TSTRING
+	TUNSAFEPTR
+
+	// pseudo-types for literals
+	TIDEAL
+	TNIL
+	TBLANK
+
+	// pseudo-types for frame layout
+	TFUNCARGS
+	TCHANARGS
+	TINTERMETH
+
+	// pseudo-types for import/export
+	TDDDFIELD // wrapper: contained type is a ... field
+
+	NTYPE
+)
+
+// ChanDir is whether a channel can send, receive, or both.
+type ChanDir uint8
+
+func (c ChanDir) CanRecv() bool { return c&Crecv != 0 }
+func (c ChanDir) CanSend() bool { return c&Csend != 0 }
+
+const (
+	// types of channel
+	// must match ../../../../reflect/type.go:/ChanDir
+	Crecv ChanDir = 1 << 0
+	Csend ChanDir = 1 << 1
+	Cboth ChanDir = Crecv | Csend
+)
+
+// Types stores pointers to predeclared named types.
+//
+// It also stores pointers to several special types:
+//   - Types[TANY] is the placeholder "any" type recognized by substArgTypes.
+//   - Types[TBLANK] represents the blank variable's type.
+//   - Types[TIDEAL] represents untyped numeric constants.
+//   - Types[TNIL] represents the predeclared "nil" value's type.
+//   - Types[TUNSAFEPTR] is package unsafe's Pointer type.
+var Types [NTYPE]*Type
+
+var (
+	// Predeclared alias types. Kept separate for better error messages.
+	bytetype *Type
+	runetype *Type
+
+	// Predeclared error interface type.
+	errortype *Type
+
+	// Types to represent untyped string and boolean constants.
+	idealstring *Type
+	idealbool   *Type
+
+	// Types to represent untyped numeric constants.
+	// Note: Currently these are only used within the binary export
+	// data format. The rest of the compiler only uses Types[TIDEAL].
+	idealint     = typ(TIDEAL)
+	idealrune    = typ(TIDEAL)
+	idealfloat   = typ(TIDEAL)
+	idealcomplex = typ(TIDEAL)
+)
+
+// A Type represents a Go type.
+type Type struct {
+	// Extra contains extra etype-specific fields.
+	// As an optimization, those etype-specific structs which contain exactly
+	// one pointer-shaped field are stored as values rather than pointers when possible.
+	//
+	// TMAP: *MapType
+	// TFORW: *ForwardType
+	// TFUNC: *FuncType
+	// TINTERMETHOD: InterMethType
+	// TSTRUCT: *StructType
+	// TINTER: *InterType
+	// TDDDFIELD: DDDFieldType
+	// TFUNCARGS: FuncArgsType
+	// TCHANARGS: ChanArgsType
+	// TCHAN: *ChanType
+	// TPTR32, TPTR64: PtrType
+	// TARRAY: *ArrayType
+	// TSLICE: SliceType
+	Extra interface{}
+
+	// Width is the width of this Type in bytes.
+	Width int64
+
+	methods    Fields
+	allMethods Fields
+
+	Nod  *Node // canonical OTYPE node
+	Orig *Type // original type (type literal or predefined type)
+
+	Sym    *Sym  // symbol containing name, for named types
+	Vargen int32 // unique name for OTYPE/ONAME
+	Lineno int32 // line at which this type was declared, implicitly or explicitly
+
+	Etype      EType // kind of type
+	Noalg      bool  // suppress hash and eq algorithm generation
+	Trecur     uint8 // to detect loops
+	Printed    bool  // prevent duplicate export printing
+	Local      bool  // created in this file
+	Deferwidth bool
+	Broke      bool  // broken type definition.
+	Align      uint8 // the required alignment of this type, in bytes
+}
+
+// MapType contains Type fields specific to maps.
+type MapType struct {
+	Key *Type // Key type
+	Val *Type // Val (elem) type
+
+	Bucket *Type // internal struct type representing a hash bucket
+	Hmap   *Type // internal struct type representing the Hmap (map header object)
+	Hiter  *Type // internal struct type representing hash iterator state
+}
+
+// MapType returns t's extra map-specific fields.
+func (t *Type) MapType() *MapType {
+	t.wantEtype(TMAP)
+	return t.Extra.(*MapType)
+}
+
+// ForwardType contains Type fields specific to forward types.
+type ForwardType struct {
+	Copyto      []*Node // where to copy the eventual value to
+	Embedlineno int32   // first use of this type as an embedded type
+}
+
+// ForwardType returns t's extra forward-type-specific fields.
+func (t *Type) ForwardType() *ForwardType {
+	t.wantEtype(TFORW)
+	return t.Extra.(*ForwardType)
+}
+
+// FuncType contains Type fields specific to func types.
+type FuncType struct {
+	Receiver *Type // function receiver
+	Results  *Type // function results
+	Params   *Type // function params
+
+	Nname *Node
+
+	// Argwid is the total width of the function receiver, params, and results.
+	// It gets calculated via a temporary TFUNCARGS type.
+	// Note that TFUNC's Width is Widthptr.
+	Argwid int64
+
+	Outnamed bool
+}
+
+// FuncType returns t's extra func-specific fields.
+func (t *Type) FuncType() *FuncType {
+	t.wantEtype(TFUNC)
+	return t.Extra.(*FuncType)
+}
+
+// InterMethType contains Type fields specific to interface method psuedo-types.
+type InterMethType struct {
+	Nname *Node
+}
+
+// StructType contains Type fields specific to struct types.
+type StructType struct {
+	fields Fields
+
+	// Maps have three associated internal structs (see struct MapType).
+	// Map links such structs back to their map type.
+	Map *Type
+
+	Funarg      Funarg // type of function arguments for arg struct
+	Haspointers uint8  // 0 unknown, 1 no, 2 yes
+}
+
+// Fnstruct records the kind of function argument
+type Funarg uint8
+
+const (
+	FunargNone    Funarg = iota
+	FunargRcvr           // receiver
+	FunargParams         // input parameters
+	FunargResults        // output results
+)
+
+// StructType returns t's extra struct-specific fields.
+func (t *Type) StructType() *StructType {
+	t.wantEtype(TSTRUCT)
+	return t.Extra.(*StructType)
+}
+
+// InterType contains Type fields specific to interface types.
+type InterType struct {
+	fields Fields
+}
+
+// PtrType contains Type fields specific to pointer types.
+type PtrType struct {
+	Elem *Type // element type
+}
+
+// DDDFieldType contains Type fields specific to TDDDFIELD types.
+type DDDFieldType struct {
+	T *Type // reference to a slice type for ... args
+}
+
+// ChanArgsType contains Type fields specific to TCHANARGS types.
+type ChanArgsType struct {
+	T *Type // reference to a chan type whose elements need a width check
+}
+
+// // FuncArgsType contains Type fields specific to TFUNCARGS types.
+type FuncArgsType struct {
+	T *Type // reference to a func type whose elements need a width check
+}
+
+// ChanType contains Type fields specific to channel types.
+type ChanType struct {
+	Elem *Type   // element type
+	Dir  ChanDir // channel direction
+}
+
+// ChanType returns t's extra channel-specific fields.
+func (t *Type) ChanType() *ChanType {
+	t.wantEtype(TCHAN)
+	return t.Extra.(*ChanType)
+}
+
+// ArrayType contains Type fields specific to array types.
+type ArrayType struct {
+	Elem        *Type // element type
+	Bound       int64 // number of elements; <0 if unknown yet
+	Haspointers uint8 // 0 unknown, 1 no, 2 yes
+}
+
+// SliceType contains Type fields specific to slice types.
+type SliceType struct {
+	Elem *Type // element type
+}
+
+// A Field represents a field in a struct or a method in an interface or
+// associated with a named type.
+type Field struct {
+	Nointerface bool
+	Embedded    uint8 // embedded field
+	Funarg      Funarg
+	Broke       bool // broken field definition
+	Isddd       bool // field is ... argument
+
+	Sym   *Sym
+	Nname *Node
+
+	Type *Type // field type
+
+	// Offset in bytes of this field or method within its enclosing struct
+	// or interface Type.
+	Offset int64
+
+	Note string // literal string annotation
+}
+
+// End returns the offset of the first byte immediately after this field.
+func (f *Field) End() int64 {
+	return f.Offset + f.Type.Width
+}
+
+// Fields is a pointer to a slice of *Field.
+// This saves space in Types that do not have fields or methods
+// compared to a simple slice of *Field.
+type Fields struct {
+	s *[]*Field
+}
+
+// Len returns the number of entries in f.
+func (f *Fields) Len() int {
+	if f.s == nil {
+		return 0
+	}
+	return len(*f.s)
+}
+
+// Slice returns the entries in f as a slice.
+// Changes to the slice entries will be reflected in f.
+func (f *Fields) Slice() []*Field {
+	if f.s == nil {
+		return nil
+	}
+	return *f.s
+}
+
+// Index returns the i'th element of Fields.
+// It panics if f does not have at least i+1 elements.
+func (f *Fields) Index(i int) *Field {
+	return (*f.s)[i]
+}
+
+// Set sets f to a slice.
+// This takes ownership of the slice.
+func (f *Fields) Set(s []*Field) {
+	if len(s) == 0 {
+		f.s = nil
+	} else {
+		// Copy s and take address of t rather than s to avoid
+		// allocation in the case where len(s) == 0.
+		t := s
+		f.s = &t
+	}
+}
+
+// Append appends entries to f.
+func (f *Fields) Append(s ...*Field) {
+	if f.s == nil {
+		f.s = new([]*Field)
+	}
+	*f.s = append(*f.s, s...)
+}
+
+// typ returns a new Type of the specified kind.
+func typ(et EType) *Type {
+	t := &Type{
+		Etype:  et,
+		Width:  BADWIDTH,
+		Lineno: lineno,
+	}
+	t.Orig = t
+	// TODO(josharian): lazily initialize some of these?
+	switch t.Etype {
+	case TMAP:
+		t.Extra = new(MapType)
+	case TFORW:
+		t.Extra = new(ForwardType)
+	case TFUNC:
+		t.Extra = new(FuncType)
+	case TINTERMETH:
+		t.Extra = InterMethType{}
+	case TSTRUCT:
+		t.Extra = new(StructType)
+	case TINTER:
+		t.Extra = new(InterType)
+	case TPTR32, TPTR64:
+		t.Extra = PtrType{}
+	case TCHANARGS:
+		t.Extra = ChanArgsType{}
+	case TFUNCARGS:
+		t.Extra = FuncArgsType{}
+	case TDDDFIELD:
+		t.Extra = DDDFieldType{}
+	case TCHAN:
+		t.Extra = new(ChanType)
+	}
+	return t
+}
+
+// typArray returns a new fixed-length array Type.
+func typArray(elem *Type, bound int64) *Type {
+	if bound < 0 {
+		Fatalf("typArray: invalid bound %v", bound)
+	}
+	t := typ(TARRAY)
+	t.Extra = &ArrayType{Elem: elem, Bound: bound}
+	return t
+}
+
+// typSlice returns a new slice Type.
+func typSlice(elem *Type) *Type {
+	t := typ(TSLICE)
+	t.Extra = SliceType{Elem: elem}
+	return t
+}
+
+// typDDDArray returns a new [...]T array Type.
+func typDDDArray(elem *Type) *Type {
+	t := typ(TARRAY)
+	t.Extra = &ArrayType{Elem: elem, Bound: -1}
+	return t
+}
+
+// typChan returns a new chan Type with direction dir.
+func typChan(elem *Type, dir ChanDir) *Type {
+	t := typ(TCHAN)
+	ct := t.ChanType()
+	ct.Elem = elem
+	ct.Dir = dir
+	return t
+}
+
+// typMap returns a new map Type with key type k and element (aka value) type v.
+func typMap(k, v *Type) *Type {
+	t := typ(TMAP)
+	mt := t.MapType()
+	mt.Key = k
+	mt.Val = v
+	return t
+}
+
+// typPtr returns a new pointer type pointing to t.
+func typPtr(elem *Type) *Type {
+	t := typ(Tptr)
+	t.Extra = PtrType{Elem: elem}
+	t.Width = int64(Widthptr)
+	t.Align = uint8(Widthptr)
+	return t
+}
+
+// typDDDField returns a new TDDDFIELD type for slice type s.
+func typDDDField(s *Type) *Type {
+	t := typ(TDDDFIELD)
+	t.Extra = DDDFieldType{T: s}
+	return t
+}
+
+// typChanArgs returns a new TCHANARGS type for channel type c.
+func typChanArgs(c *Type) *Type {
+	t := typ(TCHANARGS)
+	t.Extra = ChanArgsType{T: c}
+	return t
+}
+
+// typFuncArgs returns a new TFUNCARGS type for func type f.
+func typFuncArgs(f *Type) *Type {
+	t := typ(TFUNCARGS)
+	t.Extra = FuncArgsType{T: f}
+	return t
+}
+
+func newField() *Field {
+	return &Field{
+		Offset: BADWIDTH,
+	}
+}
+
+// substArgTypes substitutes the given list of types for
+// successive occurrences of the "any" placeholder in the
+// type syntax expression n.Type.
+// The result of substArgTypes MUST be assigned back to old, e.g.
+// 	n.Left = substArgTypes(n.Left, t1, t2)
+func substArgTypes(old *Node, types ...*Type) *Node {
+	n := *old // make shallow copy
+
+	for _, t := range types {
+		dowidth(t)
+	}
+	n.Type = substAny(n.Type, &types)
+	if len(types) > 0 {
+		Fatalf("substArgTypes: too many argument types")
+	}
+	return &n
+}
+
+// substAny walks t, replacing instances of "any" with successive
+// elements removed from types.  It returns the substituted type.
+func substAny(t *Type, types *[]*Type) *Type {
+	if t == nil {
+		return nil
+	}
+
+	switch t.Etype {
+	default:
+		// Leave the type unchanged.
+
+	case TANY:
+		if len(*types) == 0 {
+			Fatalf("substArgTypes: not enough argument types")
+		}
+		t = (*types)[0]
+		*types = (*types)[1:]
+
+	case TPTR32, TPTR64:
+		elem := substAny(t.Elem(), types)
+		if elem != t.Elem() {
+			t = t.Copy()
+			t.Extra = PtrType{Elem: elem}
+		}
+
+	case TARRAY:
+		elem := substAny(t.Elem(), types)
+		if elem != t.Elem() {
+			t = t.Copy()
+			t.Extra.(*ArrayType).Elem = elem
+		}
+
+	case TSLICE:
+		elem := substAny(t.Elem(), types)
+		if elem != t.Elem() {
+			t = t.Copy()
+			t.Extra = SliceType{Elem: elem}
+		}
+
+	case TCHAN:
+		elem := substAny(t.Elem(), types)
+		if elem != t.Elem() {
+			t = t.Copy()
+			t.Extra.(*ChanType).Elem = elem
+		}
+
+	case TMAP:
+		key := substAny(t.Key(), types)
+		val := substAny(t.Val(), types)
+		if key != t.Key() || val != t.Val() {
+			t = t.Copy()
+			t.Extra.(*MapType).Key = key
+			t.Extra.(*MapType).Val = val
+		}
+
+	case TFUNC:
+		recvs := substAny(t.Recvs(), types)
+		params := substAny(t.Params(), types)
+		results := substAny(t.Results(), types)
+		if recvs != t.Recvs() || params != t.Params() || results != t.Results() {
+			// Note that this code has to be aware of the
+			// representation underlying Recvs/Results/Params.
+			if recvs == t.Recvs() {
+				recvs = recvs.Copy()
+			}
+			if results == t.Results() {
+				results = results.Copy()
+			}
+			t = t.Copy()
+			*t.RecvsP() = recvs
+			*t.ResultsP() = results
+			*t.ParamsP() = params
+		}
+
+	case TSTRUCT:
+		fields := t.FieldSlice()
+		var nfs []*Field
+		for i, f := range fields {
+			nft := substAny(f.Type, types)
+			if nft == f.Type {
+				continue
+			}
+			if nfs == nil {
+				nfs = append([]*Field(nil), fields...)
+			}
+			nfs[i] = f.Copy()
+			nfs[i].Type = nft
+		}
+		if nfs != nil {
+			t = t.Copy()
+			t.SetFields(nfs)
+		}
+	}
+
+	return t
+}
+
+// Copy returns a shallow copy of the Type.
+func (t *Type) Copy() *Type {
+	if t == nil {
+		return nil
+	}
+	nt := *t
+	// copy any *T Extra fields, to avoid aliasing
+	switch t.Etype {
+	case TMAP:
+		x := *t.Extra.(*MapType)
+		nt.Extra = &x
+	case TFORW:
+		x := *t.Extra.(*ForwardType)
+		nt.Extra = &x
+	case TFUNC:
+		x := *t.Extra.(*FuncType)
+		nt.Extra = &x
+	case TSTRUCT:
+		x := *t.Extra.(*StructType)
+		nt.Extra = &x
+	case TINTER:
+		x := *t.Extra.(*InterType)
+		nt.Extra = &x
+	case TCHAN:
+		x := *t.Extra.(*ChanType)
+		nt.Extra = &x
+	case TARRAY:
+		x := *t.Extra.(*ArrayType)
+		nt.Extra = &x
+	}
+	// TODO(mdempsky): Find out why this is necessary and explain.
+	if t.Orig == t {
+		nt.Orig = &nt
+	}
+	return &nt
+}
+
+func (f *Field) Copy() *Field {
+	nf := *f
+	return &nf
+}
+
+// Iter provides an abstraction for iterating across struct fields and
+// interface methods.
+type Iter struct {
+	s []*Field
+}
+
+// IterFields returns the first field or method in struct or interface type t
+// and an Iter value to continue iterating across the rest.
+func IterFields(t *Type) (*Field, Iter) {
+	return t.Fields().Iter()
+}
+
+// Iter returns the first field in fs and an Iter value to continue iterating
+// across its successor fields.
+// Deprecated: New code should use Slice instead.
+func (fs *Fields) Iter() (*Field, Iter) {
+	i := Iter{s: fs.Slice()}
+	f := i.Next()
+	return f, i
+}
+
+// Next returns the next field or method, if any.
+func (i *Iter) Next() *Field {
+	if len(i.s) == 0 {
+		return nil
+	}
+	f := i.s[0]
+	i.s = i.s[1:]
+	return f
+}
+
+func (t *Type) wantEtype(et EType) {
+	if t.Etype != et {
+		Fatalf("want %v, but have %v", et, t)
+	}
+}
+
+func (t *Type) wantEtype2(et1, et2 EType) {
+	if t.Etype != et1 && t.Etype != et2 {
+		Fatalf("want %v or %v, but have %v", et1, et2, t)
+	}
+}
+
+func (t *Type) RecvsP() **Type {
+	t.wantEtype(TFUNC)
+	return &t.Extra.(*FuncType).Receiver
+}
+
+func (t *Type) ParamsP() **Type {
+	t.wantEtype(TFUNC)
+	return &t.Extra.(*FuncType).Params
+}
+
+func (t *Type) ResultsP() **Type {
+	t.wantEtype(TFUNC)
+	return &t.Extra.(*FuncType).Results
+}
+
+func (t *Type) Recvs() *Type   { return *t.RecvsP() }
+func (t *Type) Params() *Type  { return *t.ParamsP() }
+func (t *Type) Results() *Type { return *t.ResultsP() }
+
+// Recv returns the receiver of function type t, if any.
+func (t *Type) Recv() *Field {
+	s := t.Recvs()
+	if s.NumFields() == 0 {
+		return nil
+	}
+	return s.Field(0)
+}
+
+// recvsParamsResults stores the accessor functions for a function Type's
+// receiver, parameters, and result parameters, in that order.
+// It can be used to iterate over all of a function's parameter lists.
+var recvsParamsResults = [3]func(*Type) *Type{
+	(*Type).Recvs, (*Type).Params, (*Type).Results,
+}
+
+// paramsResults is like recvsParamsResults, but omits receiver parameters.
+var paramsResults = [2]func(*Type) *Type{
+	(*Type).Params, (*Type).Results,
+}
+
+// Key returns the key type of map type t.
+func (t *Type) Key() *Type {
+	t.wantEtype(TMAP)
+	return t.Extra.(*MapType).Key
+}
+
+// Val returns the value type of map type t.
+func (t *Type) Val() *Type {
+	t.wantEtype(TMAP)
+	return t.Extra.(*MapType).Val
+}
+
+// Elem returns the type of elements of t.
+// Usable with pointers, channels, arrays, and slices.
+func (t *Type) Elem() *Type {
+	switch t.Etype {
+	case TPTR32, TPTR64:
+		return t.Extra.(PtrType).Elem
+	case TARRAY:
+		return t.Extra.(*ArrayType).Elem
+	case TSLICE:
+		return t.Extra.(SliceType).Elem
+	case TCHAN:
+		return t.Extra.(*ChanType).Elem
+	}
+	Fatalf("Type.Elem %s", t.Etype)
+	return nil
+}
+
+// DDDField returns the slice ... type for TDDDFIELD type t.
+func (t *Type) DDDField() *Type {
+	t.wantEtype(TDDDFIELD)
+	return t.Extra.(DDDFieldType).T
+}
+
+// ChanArgs returns the channel type for TCHANARGS type t.
+func (t *Type) ChanArgs() *Type {
+	t.wantEtype(TCHANARGS)
+	return t.Extra.(ChanArgsType).T
+}
+
+// FuncArgs returns the channel type for TFUNCARGS type t.
+func (t *Type) FuncArgs() *Type {
+	t.wantEtype(TFUNCARGS)
+	return t.Extra.(FuncArgsType).T
+}
+
+// Nname returns the associated function's nname.
+func (t *Type) Nname() *Node {
+	switch t.Etype {
+	case TFUNC:
+		return t.Extra.(*FuncType).Nname
+	case TINTERMETH:
+		return t.Extra.(InterMethType).Nname
+	}
+	Fatalf("Type.Nname %v %v", t.Etype, t)
+	return nil
+}
+
+// Nname sets the associated function's nname.
+func (t *Type) SetNname(n *Node) {
+	switch t.Etype {
+	case TFUNC:
+		t.Extra.(*FuncType).Nname = n
+	case TINTERMETH:
+		t.Extra = InterMethType{Nname: n}
+	default:
+		Fatalf("Type.SetNname %v %v", t.Etype, t)
+	}
+}
+
+// IsFuncArgStruct reports whether t is a struct representing function parameters.
+func (t *Type) IsFuncArgStruct() bool {
+	return t.Etype == TSTRUCT && t.Extra.(*StructType).Funarg != FunargNone
+}
+
+func (t *Type) Methods() *Fields {
+	// TODO(mdempsky): Validate t?
+	return &t.methods
+}
+
+func (t *Type) AllMethods() *Fields {
+	// TODO(mdempsky): Validate t?
+	return &t.allMethods
+}
+
+func (t *Type) Fields() *Fields {
+	switch t.Etype {
+	case TSTRUCT:
+		return &t.Extra.(*StructType).fields
+	case TINTER:
+		return &t.Extra.(*InterType).fields
+	}
+	Fatalf("Fields: type %v does not have fields", t)
+	return nil
+}
+
+// Field returns the i'th field/method of struct/interface type t.
+func (t *Type) Field(i int) *Field {
+	return t.Fields().Slice()[i]
+}
+
+// FieldSlice returns a slice of containing all fields/methods of
+// struct/interface type t.
+func (t *Type) FieldSlice() []*Field {
+	return t.Fields().Slice()
+}
+
+// SetFields sets struct/interface type t's fields/methods to fields.
+func (t *Type) SetFields(fields []*Field) {
+	t.Fields().Set(fields)
+}
+
+func (t *Type) isDDDArray() bool {
+	if t.Etype != TARRAY {
+		return false
+	}
+	return t.Extra.(*ArrayType).Bound < 0
+}
+
+// ArgWidth returns the total aligned argument size for a function.
+// It includes the receiver, parameters, and results.
+func (t *Type) ArgWidth() int64 {
+	t.wantEtype(TFUNC)
+	return t.Extra.(*FuncType).Argwid
+}
+
+func (t *Type) Size() int64 {
+	dowidth(t)
+	return t.Width
+}
+
+func (t *Type) Alignment() int64 {
+	dowidth(t)
+	return int64(t.Align)
+}
+
+func (t *Type) SimpleString() string {
+	return t.Etype.String()
+}
+
+// Compare compares types for purposes of the SSA back
+// end, returning an ssa.Cmp (one of CMPlt, CMPeq, CMPgt).
+// The answers are correct for an optimizer
+// or code generator, but not necessarily typechecking.
+// The order chosen is arbitrary, only consistency and division
+// into equivalence classes (Types that compare CMPeq) matters.
+func (t *Type) Compare(u ssa.Type) ssa.Cmp {
+	x, ok := u.(*Type)
+	// ssa.CompilerType is smaller than gc.Type
+	// bare pointer equality is easy.
+	if !ok {
+		return ssa.CMPgt
+	}
+	if x == t {
+		return ssa.CMPeq
+	}
+	return t.cmp(x)
+}
+
+func cmpForNe(x bool) ssa.Cmp {
+	if x {
+		return ssa.CMPlt
+	}
+	return ssa.CMPgt
+}
+
+func (r *Sym) cmpsym(s *Sym) ssa.Cmp {
+	if r == s {
+		return ssa.CMPeq
+	}
+	if r == nil {
+		return ssa.CMPlt
+	}
+	if s == nil {
+		return ssa.CMPgt
+	}
+	// Fast sort, not pretty sort
+	if len(r.Name) != len(s.Name) {
+		return cmpForNe(len(r.Name) < len(s.Name))
+	}
+	if r.Pkg != s.Pkg {
+		if len(r.Pkg.Prefix) != len(s.Pkg.Prefix) {
+			return cmpForNe(len(r.Pkg.Prefix) < len(s.Pkg.Prefix))
+		}
+		if r.Pkg.Prefix != s.Pkg.Prefix {
+			return cmpForNe(r.Pkg.Prefix < s.Pkg.Prefix)
+		}
+	}
+	if r.Name != s.Name {
+		return cmpForNe(r.Name < s.Name)
+	}
+	return ssa.CMPeq
+}
+
+// cmp compares two *Types t and x, returning ssa.CMPlt,
+// ssa.CMPeq, ssa.CMPgt as t<x, t==x, t>x, for an arbitrary
+// and optimizer-centric notion of comparison.
+func (t *Type) cmp(x *Type) ssa.Cmp {
+	// This follows the structure of Eqtype in subr.go
+	// with two exceptions.
+	// 1. Symbols are compared more carefully because a <,=,> result is desired.
+	// 2. Maps are treated specially to avoid endless recursion -- maps
+	//    contain an internal data type not expressible in Go source code.
+	if t == x {
+		return ssa.CMPeq
+	}
+	if t == nil {
+		return ssa.CMPlt
+	}
+	if x == nil {
+		return ssa.CMPgt
+	}
+
+	if t.Etype != x.Etype {
+		return cmpForNe(t.Etype < x.Etype)
+	}
+
+	if t.Sym != nil || x.Sym != nil {
+		// Special case: we keep byte and uint8 separate
+		// for error messages. Treat them as equal.
+		switch t.Etype {
+		case TUINT8:
+			if (t == Types[TUINT8] || t == bytetype) && (x == Types[TUINT8] || x == bytetype) {
+				return ssa.CMPeq
+			}
+
+		case TINT32:
+			if (t == Types[runetype.Etype] || t == runetype) && (x == Types[runetype.Etype] || x == runetype) {
+				return ssa.CMPeq
+			}
+		}
+	}
+
+	if c := t.Sym.cmpsym(x.Sym); c != ssa.CMPeq {
+		return c
+	}
+
+	if x.Sym != nil {
+		// Syms non-nil, if vargens match then equal.
+		if t.Vargen != x.Vargen {
+			return cmpForNe(t.Vargen < x.Vargen)
+		}
+		return ssa.CMPeq
+	}
+	// both syms nil, look at structure below.
+
+	switch t.Etype {
+	case TBOOL, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TUNSAFEPTR, TUINTPTR,
+		TINT8, TINT16, TINT32, TINT64, TINT, TUINT8, TUINT16, TUINT32, TUINT64, TUINT:
+		return ssa.CMPeq
+	}
+
+	switch t.Etype {
+	case TMAP:
+		if c := t.Key().cmp(x.Key()); c != ssa.CMPeq {
+			return c
+		}
+		return t.Val().cmp(x.Val())
+
+	case TPTR32, TPTR64, TSLICE:
+		// No special cases for these, they are handled
+		// by the general code after the switch.
+
+	case TSTRUCT:
+		if t.StructType().Map == nil {
+			if x.StructType().Map != nil {
+				return ssa.CMPlt // nil < non-nil
+			}
+			// to the fallthrough
+		} else if x.StructType().Map == nil {
+			return ssa.CMPgt // nil > non-nil
+		} else if t.StructType().Map.MapType().Bucket == t {
+			// Both have non-nil Map
+			// Special case for Maps which include a recursive type where the recursion is not broken with a named type
+			if x.StructType().Map.MapType().Bucket != x {
+				return ssa.CMPlt // bucket maps are least
+			}
+			return t.StructType().Map.cmp(x.StructType().Map)
+		} else if x.StructType().Map.MapType().Bucket == x {
+			return ssa.CMPgt // bucket maps are least
+		} // If t != t.Map.Bucket, fall through to general case
+
+		fallthrough
+	case TINTER:
+		t1, ti := IterFields(t)
+		x1, xi := IterFields(x)
+		for ; t1 != nil && x1 != nil; t1, x1 = ti.Next(), xi.Next() {
+			if t1.Embedded != x1.Embedded {
+				return cmpForNe(t1.Embedded < x1.Embedded)
+			}
+			if t1.Note != x1.Note {
+				return cmpForNe(t1.Note < x1.Note)
+			}
+			if c := t1.Sym.cmpsym(x1.Sym); c != ssa.CMPeq {
+				return c
+			}
+			if c := t1.Type.cmp(x1.Type); c != ssa.CMPeq {
+				return c
+			}
+		}
+		if t1 != x1 {
+			return cmpForNe(t1 == nil)
+		}
+		return ssa.CMPeq
+
+	case TFUNC:
+		for _, f := range recvsParamsResults {
+			// Loop over fields in structs, ignoring argument names.
+			ta, ia := IterFields(f(t))
+			tb, ib := IterFields(f(x))
+			for ; ta != nil && tb != nil; ta, tb = ia.Next(), ib.Next() {
+				if ta.Isddd != tb.Isddd {
+					return cmpForNe(!ta.Isddd)
+				}
+				if c := ta.Type.cmp(tb.Type); c != ssa.CMPeq {
+					return c
+				}
+			}
+			if ta != tb {
+				return cmpForNe(ta == nil)
+			}
+		}
+		return ssa.CMPeq
+
+	case TARRAY:
+		if t.NumElem() != x.NumElem() {
+			return cmpForNe(t.NumElem() < x.NumElem())
+		}
+
+	case TCHAN:
+		if t.ChanDir() != x.ChanDir() {
+			return cmpForNe(t.ChanDir() < x.ChanDir())
+		}
+
+	default:
+		e := fmt.Sprintf("Do not know how to compare %s with %s", t, x)
+		panic(e)
+	}
+
+	// Common element type comparison for TARRAY, TCHAN, TPTR32, TPTR64, and TSLICE.
+	return t.Elem().cmp(x.Elem())
+}
+
+// IsKind reports whether t is a Type of the specified kind.
+func (t *Type) IsKind(et EType) bool {
+	return t != nil && t.Etype == et
+}
+
+func (t *Type) IsBoolean() bool {
+	return t.Etype == TBOOL
+}
+
+func (t *Type) IsInteger() bool {
+	switch t.Etype {
+	case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TINT, TUINT, TUINTPTR:
+		return true
+	}
+	return false
+}
+
+func (t *Type) IsSigned() bool {
+	switch t.Etype {
+	case TINT8, TINT16, TINT32, TINT64, TINT:
+		return true
+	}
+	return false
+}
+
+func (t *Type) IsFloat() bool {
+	return t.Etype == TFLOAT32 || t.Etype == TFLOAT64
+}
+
+func (t *Type) IsComplex() bool {
+	return t.Etype == TCOMPLEX64 || t.Etype == TCOMPLEX128
+}
+
+// IsPtr reports whether t is a regular Go pointer type.
+// This does not include unsafe.Pointer.
+func (t *Type) IsPtr() bool {
+	return t.Etype == TPTR32 || t.Etype == TPTR64
+}
+
+// IsUnsafePtr reports whether t is an unsafe pointer.
+func (t *Type) IsUnsafePtr() bool {
+	return t.Etype == TUNSAFEPTR
+}
+
+// IsPtrShaped reports whether t is represented by a single machine pointer.
+// In addition to regular Go pointer types, this includes map, channel, and
+// function types and unsafe.Pointer. It does not include array or struct types
+// that consist of a single pointer shaped type.
+// TODO(mdempsky): Should it? See golang.org/issue/15028.
+func (t *Type) IsPtrShaped() bool {
+	return t.Etype == TPTR32 || t.Etype == TPTR64 || t.Etype == TUNSAFEPTR ||
+		t.Etype == TMAP || t.Etype == TCHAN || t.Etype == TFUNC
+}
+
+func (t *Type) IsString() bool {
+	return t.Etype == TSTRING
+}
+
+func (t *Type) IsMap() bool {
+	return t.Etype == TMAP
+}
+
+func (t *Type) IsChan() bool {
+	return t.Etype == TCHAN
+}
+
+func (t *Type) IsSlice() bool {
+	return t.Etype == TSLICE
+}
+
+func (t *Type) IsArray() bool {
+	return t.Etype == TARRAY
+}
+
+func (t *Type) IsStruct() bool {
+	return t.Etype == TSTRUCT
+}
+
+func (t *Type) IsInterface() bool {
+	return t.Etype == TINTER
+}
+
+// IsEmptyInterface reports whether t is an empty interface type.
+func (t *Type) IsEmptyInterface() bool {
+	return t.IsInterface() && t.NumFields() == 0
+}
+
+func (t *Type) ElemType() ssa.Type {
+	// TODO(josharian): If Type ever moves to a shared
+	// internal package, remove this silly wrapper.
+	return t.Elem()
+}
+func (t *Type) PtrTo() ssa.Type {
+	return Ptrto(t)
+}
+
+func (t *Type) NumFields() int {
+	return t.Fields().Len()
+}
+func (t *Type) FieldType(i int) ssa.Type {
+	return t.Field(i).Type
+}
+func (t *Type) FieldOff(i int) int64 {
+	return t.Field(i).Offset
+}
+func (t *Type) FieldName(i int) string {
+	return t.Field(i).Sym.Name
+}
+
+func (t *Type) NumElem() int64 {
+	t.wantEtype(TARRAY)
+	at := t.Extra.(*ArrayType)
+	if at.Bound < 0 {
+		Fatalf("NumElem array %v does not have bound yet", t)
+	}
+	return at.Bound
+}
+
+// SetNumElem sets the number of elements in an array type.
+// The only allowed use is on array types created with typDDDArray.
+// For other uses, create a new array with typArray instead.
+func (t *Type) SetNumElem(n int64) {
+	t.wantEtype(TARRAY)
+	at := t.Extra.(*ArrayType)
+	if at.Bound >= 0 {
+		Fatalf("SetNumElem array %v already has bound %d", t, at.Bound)
+	}
+	at.Bound = n
+}
+
+// ChanDir returns the direction of a channel type t.
+// The direction will be one of Crecv, Csend, or Cboth.
+func (t *Type) ChanDir() ChanDir {
+	t.wantEtype(TCHAN)
+	return t.Extra.(*ChanType).Dir
+}
+
+func (t *Type) IsMemory() bool { return false }
+func (t *Type) IsFlags() bool  { return false }
+func (t *Type) IsVoid() bool   { return false }
+
+// IsUntyped reports whether t is an untyped type.
+func (t *Type) IsUntyped() bool {
+	if t == nil {
+		return false
+	}
+	if t == idealstring || t == idealbool {
+		return true
+	}
+	switch t.Etype {
+	case TNIL, TIDEAL:
+		return true
+	}
+	return false
+}
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index f74bb33..c8ee941 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -11,6 +11,16 @@ import (
 	"strings"
 )
 
+const (
+	Etop      = 1 << iota // evaluated at statement level
+	Erv                   // evaluated in value context
+	Etype                 // evaluated in type context
+	Ecall                 // call-only expressions are ok
+	Efnstruct             // multivalue function returns are ok
+	Easgn                 // assigning to expression
+	Ecomplit              // type in composite literal
+)
+
 // type check the whole tree of an expression.
 // calculates expression types.
 // evaluates compile time constants.
@@ -34,9 +44,9 @@ func resolve(n *Node) *Node {
 	return n
 }
 
-func typechecklist(l *NodeList, top int) {
-	for ; l != nil; l = l.Next {
-		typecheck(&l.N, top)
+func typecheckslice(l []*Node, top int) {
+	for i := range l {
+		l[i] = typecheck(l[i], top)
 	}
 }
 
@@ -66,13 +76,14 @@ var _typekind = []string{
 	TCHAN:       "chan",
 	TMAP:        "map",
 	TARRAY:      "array",
+	TSLICE:      "slice",
 	TFUNC:       "func",
 	TNIL:        "nil",
 	TIDEAL:      "untyped number",
 }
 
 func typekind(t *Type) string {
-	if Isslice(t) {
+	if t.IsSlice() {
 		return "slice"
 	}
 	et := t.Etype
@@ -102,21 +113,20 @@ func sprint_depchain(fmt_ *string, stack []*Node, cur *Node, first *Node) {
 
 var typecheck_tcstack []*Node
 
-// typecheck type checks node *np.
-// It replaces *np with a new pointer in some cases.
-// It returns the final value of *np as a convenience.
-func typecheck(np **Node, top int) *Node {
+// typecheck type checks node n.
+// The result of typecheck MUST be assigned back to n, e.g.
+// 	n.Left = typecheck(n.Left, top)
+func typecheck(n *Node, top int) *Node {
 	// cannot type check until all the source has been parsed
 	if !typecheckok {
 		Fatalf("early typecheck")
 	}
 
-	n := *np
 	if n == nil {
 		return nil
 	}
 
-	lno := int(setlineno(n))
+	lno := setlineno(n)
 
 	// Skip over parens.
 	for n.Op == OPAREN {
@@ -126,8 +136,6 @@ func typecheck(np **Node, top int) *Node {
 	// 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 {
@@ -136,7 +144,7 @@ func typecheck(np **Node, top int) *Node {
 			break
 
 		default:
-			lineno = int32(lno)
+			lineno = lno
 			return n
 		}
 	}
@@ -158,7 +166,7 @@ func typecheck(np **Node, top int) *Node {
 				break
 			}
 			sprint_depchain(&fmt_, typecheck_tcstack, n, n)
-			yyerrorl(int(n.Lineno), "constant definition loop%s", fmt_)
+			yyerrorl(n.Lineno, "constant definition loop%s", fmt_)
 		}
 
 		if nsavederrors+nerrors == 0 {
@@ -170,15 +178,14 @@ func typecheck(np **Node, top int) *Node {
 			Yyerror("typechecking loop involving %v%s", n, fmt_)
 		}
 
-		lineno = int32(lno)
+		lineno = lno
 		return n
 	}
 
 	n.Typecheck = 2
 
 	typecheck_tcstack = append(typecheck_tcstack, n)
-	typecheck1(&n, top)
-	*np = n
+	n = typecheck1(n, top)
 
 	n.Typecheck = 1
 
@@ -186,7 +193,7 @@ func typecheck(np **Node, top int) *Node {
 	typecheck_tcstack[last] = nil
 	typecheck_tcstack = typecheck_tcstack[:last]
 
-	lineno = int32(lno)
+	lineno = lno
 	return n
 }
 
@@ -214,9 +221,9 @@ func callrecv(n *Node) bool {
 	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) {
+func callrecvlist(l Nodes) bool {
+	for _, n := range l.Slice() {
+		if callrecv(n) {
 			return true
 		}
 	}
@@ -227,36 +234,40 @@ func callrecvlist(l *NodeList) bool {
 // 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
+// The result of indexlit MUST be assigned back to n, e.g.
+// 	n.Left = indexlit(n.Left)
+func indexlit(n *Node) *Node {
+	if n == nil || !n.Type.IsUntyped() {
+		return n
 	}
 	switch consttype(n) {
 	case CTINT, CTRUNE, CTFLT, CTCPLX:
-		defaultlit(np, Types[TINT])
+		n = defaultlit(n, Types[TINT])
 	}
 
-	defaultlit(np, nil)
+	n = defaultlit(n, nil)
+	return n
 }
 
-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
-		}
+// The result of typecheck1 MUST be assigned back to n, e.g.
+// 	n.Left = typecheck1(n.Left, top)
+func typecheck1(n *Node, top int) *Node {
+	switch n.Op {
+	case OXDOT, ODOT, ODOTPTR, ODOTMETH, ODOTINTER:
+		// n.Sym is a field/method name, not a variable.
+	default:
+		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 n
+			}
 
-		typecheckdef(n)
-		if n.Op == ONONAME {
-			n.Type = nil
-			return
+			typecheckdef(n)
+			if n.Op == ONONAME {
+				n.Type = nil
+				return n
+			}
 		}
 	}
 
@@ -267,7 +278,7 @@ OpSwitch:
 	default:
 		Dump("typecheck", n)
 
-		Fatalf("typecheck %v", Oconv(int(n.Op), 0))
+		Fatalf("typecheck %v", n.Op)
 
 	// names
 	case OLITERAL:
@@ -296,7 +307,7 @@ OpSwitch:
 			if isblank(n) {
 				Yyerror("cannot use _ as value")
 				n.Type = nil
-				return
+				return n
 			}
 
 			n.Used = true
@@ -305,7 +316,7 @@ OpSwitch:
 		if top&Ecall == 0 && isunsafebuiltin(n) {
 			Yyerror("%v is not an expression, must be called", n)
 			n.Type = nil
-			return
+			return n
 		}
 
 		ok |= Erv
@@ -314,7 +325,7 @@ OpSwitch:
 	case OPACK:
 		Yyerror("use of package %v without selector", n.Sym)
 		n.Type = nil
-		return
+		return n
 
 	case ODDD:
 		break
@@ -324,26 +335,32 @@ OpSwitch:
 		ok |= Etype
 
 		if n.Type == nil {
-			n.Type = nil
-			return
+			return n
 		}
 
 	case OTARRAY:
 		ok |= Etype
-		t := typ(TARRAY)
+		var t *Type
 		l := n.Left
 		r := n.Right
+		r = typecheck(r, Etype)
+		if r.Type == nil {
+			n.Type = nil
+			return n
+		}
+
 		if l == nil {
-			t.Bound = -1 // slice
+			t = typSlice(r.Type)
 		} else if l.Op == ODDD {
-			t.Bound = -100 // to be filled in
+			t = typDDDArray(r.Type)
 			if top&Ecomplit == 0 && n.Diag == 0 {
 				t.Broke = true
 				n.Diag = 1
 				Yyerror("use of [...] array outside of array literal")
 			}
 		} else {
-			l := typecheck(&n.Left, Erv)
+			n.Left = typecheck(n.Left, Erv)
+			l := n.Left
 			var v Val
 			switch consttype(l) {
 			case CTINT, CTRUNE:
@@ -353,65 +370,73 @@ OpSwitch:
 				v = toint(l.Val())
 
 			default:
-				if l.Type != nil && Isint[l.Type.Etype] && l.Op != OLITERAL {
+				if l.Type != nil && l.Type.IsInteger() && l.Op != OLITERAL {
 					Yyerror("non-constant array bound %v", l)
 				} else {
 					Yyerror("invalid array bound %v", l)
 				}
 				n.Type = nil
-				return
+				return n
 			}
 
-			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 {
+				return n
+			}
+			bound := v.U.(*Mpint).Int64()
+			if bound < 0 {
 				Yyerror("array bound must be non-negative")
 				n.Type = nil
-				return
+				return n
 			}
+			t = typArray(r.Type, bound)
 		}
 
-		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 {
+		if !t.isDDDArray() {
 			checkwidth(t)
 		}
 
 	case OTMAP:
 		ok |= Etype
-		l := typecheck(&n.Left, Etype)
-		r := typecheck(&n.Right, Etype)
+		n.Left = typecheck(n.Left, Etype)
+		n.Right = typecheck(n.Right, Etype)
+		l := n.Left
+		r := n.Right
 		if l.Type == nil || r.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		n.Op = OTYPE
-		n.Type = maptype(l.Type, r.Type)
+		n.Type = typMap(l.Type, r.Type)
+
+		// map key validation
+		alg, bad := algtype1(l.Type)
+		if alg == ANOEQ {
+			if bad.Etype == TFORW {
+				// queue check for map until all the types are done settling.
+				mapqueue = append(mapqueue, mapqueueval{l, n.Lineno})
+			} else if bad.Etype != TANY {
+				// no need to queue, key is already bad
+				Yyerror("invalid map key type %v", l.Type)
+			}
+		}
 		n.Left = nil
 		n.Right = nil
 
 	case OTCHAN:
 		ok |= Etype
-		l := typecheck(&n.Left, Etype)
+		n.Left = typecheck(n.Left, Etype)
+		l := n.Left
 		if l.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		t := typ(TCHAN)
-		t.Type = l.Type
-		// TODO(marvin): Fix Node.EType type union.
-		t.Chan = uint8(n.Etype)
+		t := typChan(l.Type, ChanDir(n.Etype)) // TODO(marvin): Fix Node.EType type union.
 		n.Op = OTYPE
 		n.Type = t
 		n.Left = nil
@@ -420,44 +445,40 @@ OpSwitch:
 	case OTSTRUCT:
 		ok |= Etype
 		n.Op = OTYPE
-		n.Type = tostruct(n.List)
+		n.Type = tostruct(n.List.Slice())
 		if n.Type == nil || n.Type.Broke {
 			n.Type = nil
-			return
+			return n
 		}
-		n.List = nil
+		n.List.Set(nil)
 
 	case OTINTER:
 		ok |= Etype
 		n.Op = OTYPE
-		n.Type = tointerface(n.List)
+		n.Type = tointerface(n.List.Slice())
 		if n.Type == nil {
-			n.Type = nil
-			return
+			return n
 		}
 
 	case OTFUNC:
 		ok |= Etype
 		n.Op = OTYPE
-		n.Type = functype(n.Left, n.List, n.Rlist)
+		n.Type = functype(n.Left, n.List.Slice(), n.Rlist.Slice())
 		if n.Type == nil {
-			n.Type = nil
-			return
+			return n
 		}
+		n.Left = nil
+		n.List.Set(nil)
+		n.Rlist.Set(nil)
 
 	// 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)
+		n.Left = typecheck(n.Left, Erv|Etype|top&Ecomplit)
+		l := n.Left
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		if l.Op == OTYPE {
 			ok |= Etype
@@ -467,18 +488,18 @@ OpSwitch:
 			break OpSwitch
 		}
 
-		if !Isptr[t.Etype] {
+		if !t.IsPtr() {
 			if top&(Erv|Etop) != 0 {
-				Yyerror("invalid indirect of %v", Nconv(n.Left, obj.FmtLong))
+				Yyerror("invalid indirect of %v", Nconv(n.Left, FmtLong))
 				n.Type = nil
-				return
+				return n
 			}
 
 			break OpSwitch
 		}
 
 		ok |= Erv
-		n.Type = t.Type
+		n.Type = t.Elem()
 		break OpSwitch
 
 	// arithmetic exprs
@@ -508,40 +529,49 @@ OpSwitch:
 		var r *Node
 		if n.Op == OASOP {
 			ok |= Etop
-			l = typecheck(&n.Left, Erv)
-			r = typecheck(&n.Right, Erv)
+			n.Left = typecheck(n.Left, Erv)
+			n.Right = typecheck(n.Right, Erv)
+			l = n.Left
+			r = n.Right
 			checkassign(n, n.Left)
 			if l.Type == nil || r.Type == nil {
 				n.Type = nil
-				return
+				return n
+			}
+			if n.Implicit && !okforarith[l.Type.Etype] {
+				Yyerror("invalid operation: %v (non-numeric type %v)", n, l.Type)
+				n.Type = nil
+				return n
 			}
 			// TODO(marvin): Fix Node.EType type union.
 			op = Op(n.Etype)
 		} else {
 			ok |= Erv
-			l = typecheck(&n.Left, Erv|top&Eiota)
-			r = typecheck(&n.Right, Erv|top&Eiota)
+			n.Left = typecheck(n.Left, Erv)
+			n.Right = typecheck(n.Right, Erv)
+			l = n.Left
+			r = n.Right
 			if l.Type == nil || r.Type == nil {
 				n.Type = nil
-				return
+				return n
 			}
 			op = n.Op
 		}
 		if op == OLSH || op == ORSH {
-			defaultlit(&r, Types[TUINT])
+			r = defaultlit(r, Types[TUINT])
 			n.Right = r
 			t := r.Type
-			if !Isint[t.Etype] || Issigned[t.Etype] {
+			if !t.IsInteger() || t.IsSigned() {
 				Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", n, r.Type)
 				n.Type = nil
-				return
+				return n
 			}
 
 			t = l.Type
-			if t != nil && t.Etype != TIDEAL && !Isint[t.Etype] {
+			if t != nil && t.Etype != TIDEAL && !t.IsInteger() {
 				Yyerror("invalid operation: %v (shift of type %v)", n, t)
 				n.Type = nil
-				return
+				return n
 			}
 
 			// no defaultlit for left
@@ -552,13 +582,13 @@ OpSwitch:
 		}
 
 		// ideal mixed with non-ideal
-		defaultlit2(&l, &r, 0)
+		l, r = defaultlit2(l, r, false)
 
 		n.Left = l
 		n.Right = r
 		if l.Type == nil || r.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		t := l.Type
 		if t.Etype == TIDEAL {
@@ -580,14 +610,14 @@ OpSwitch:
 			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))
+					if r.Type.IsInterface() && !l.Type.IsInterface() && !l.Type.IsComparable() {
+						Yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
 						n.Type = nil
-						return
+						return n
 					}
 
 					dowidth(l.Type)
-					if Isinter(r.Type) == Isinter(l.Type) || l.Type.Width >= 1<<16 {
+					if r.Type.IsInterface() == l.Type.IsInterface() || l.Type.Width >= 1<<16 {
 						l = Nod(aop, l, nil)
 						l.Type = r.Type
 						l.Typecheck = 1
@@ -602,14 +632,14 @@ OpSwitch:
 			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))
+					if l.Type.IsInterface() && !r.Type.IsInterface() && !r.Type.IsComparable() {
+						Yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
 						n.Type = nil
-						return
+						return n
 					}
 
 					dowidth(r.Type)
-					if Isinter(r.Type) == Isinter(l.Type) || r.Type.Width >= 1<<16 {
+					if r.Type.IsInterface() == l.Type.IsInterface() || r.Type.Width >= 1<<16 {
 						r = Nod(aop, r, nil)
 						r.Type = l.Type
 						r.Typecheck = 1
@@ -625,57 +655,52 @@ OpSwitch:
 		}
 
 		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 {
+			l, r = defaultlit2(l, r, true)
+			if r.Type.IsInterface() == l.Type.IsInterface() || aop == 0 {
 				Yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
 				n.Type = nil
-				return
+				return n
 			}
 		}
 
 		if !okfor[op][et] {
-			Yyerror("invalid operation: %v (operator %v not defined on %s)", n, Oconv(int(op), 0), typekind(t))
+			Yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
 			n.Type = nil
-			return
+			return n
 		}
 
 		// 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 {
+		if l.Type.IsArray() && !l.Type.IsComparable() {
 			Yyerror("invalid operation: %v (%v cannot be compared)", n, l.Type)
 			n.Type = nil
-			return
+			return n
 		}
 
-		if Isslice(l.Type) && !isnil(l) && !isnil(r) {
+		if l.Type.IsSlice() && !isnil(l) && !isnil(r) {
 			Yyerror("invalid operation: %v (slice can only be compared to nil)", n)
 			n.Type = nil
-			return
+			return n
 		}
 
-		if l.Type.Etype == TMAP && !isnil(l) && !isnil(r) {
+		if l.Type.IsMap() && !isnil(l) && !isnil(r) {
 			Yyerror("invalid operation: %v (map can only be compared to nil)", n)
 			n.Type = nil
-			return
+			return n
 		}
 
 		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
+			return n
 		}
 
-		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
+		if l.Type.IsStruct() {
+			if f := l.Type.IncomparableField(); f != nil {
+				Yyerror("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
+				n.Type = nil
+				return n
+			}
 		}
 
 		t = l.Type
@@ -683,7 +708,7 @@ OpSwitch:
 			evconst(n)
 			t = idealbool
 			if n.Op != OLITERAL {
-				defaultlit2(&l, &r, 1)
+				l, r = defaultlit2(l, r, true)
 				n.Left = l
 				n.Right = r
 			}
@@ -699,14 +724,14 @@ OpSwitch:
 				n.Op = OADDSTR
 
 				if l.Op == OADDSTR {
-					n.List = l.List
+					n.List.Set(l.List.Slice())
 				} else {
-					n.List = list1(l)
+					n.List.Set1(l)
 				}
 				if r.Op == OADDSTR {
-					n.List = concat(n.List, r.List)
+					n.List.AppendNodes(&r.List)
 				} else {
-					n.List = list(n.List, r)
+					n.List.Append(r)
 				}
 				n.Left = nil
 				n.Right = nil
@@ -721,7 +746,7 @@ OpSwitch:
 				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) {
+			if r.Type.IsInterface() == l.Type.IsInterface() {
 				// TODO(marvin): Fix Node.EType type union.
 				n.Etype = EType(n.Op)
 				n.Op = OCMPIFACE
@@ -729,10 +754,10 @@ OpSwitch:
 		}
 
 		if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
-			if mpcmpfixc(r.Val().U.(*Mpint), 0) == 0 {
+			if r.Val().U.(*Mpint).CmpInt64(0) == 0 {
 				Yyerror("division by zero")
 				n.Type = nil
-				return
+				return n
 			}
 		}
 
@@ -741,16 +766,17 @@ OpSwitch:
 
 	case OCOM, OMINUS, ONOT, OPLUS:
 		ok |= Erv
-		l := typecheck(&n.Left, Erv|top&Eiota)
+		n.Left = typecheck(n.Left, Erv)
+		l := n.Left
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		if !okfor[n.Op][t.Etype] {
-			Yyerror("invalid operation: %v %v", Oconv(int(n.Op), 0), t)
+			Yyerror("invalid operation: %v %v", n.Op, t)
 			n.Type = nil
-			return
+			return n
 		}
 
 		n.Type = t
@@ -760,18 +786,18 @@ OpSwitch:
 	case OADDR:
 		ok |= Erv
 
-		typecheck(&n.Left, Erv|Eaddr)
+		n.Left = typecheck(n.Left, Erv)
 		if n.Left.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		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.isClosureVar() {
+				l.Name.Defn.Addrtaken = true
 			}
 		}
 
@@ -779,25 +805,24 @@ OpSwitch:
 			Fatalf("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
+		if l.isClosureVar() {
+			l.Name.Defn.Addrtaken = true
 		}
-		defaultlit(&n.Left, nil)
+		n.Left = defaultlit(n.Left, nil)
 		l = n.Left
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		n.Type = Ptrto(t)
 		break OpSwitch
 
 	case OCOMPLIT:
 		ok |= Erv
-		typecheckcomplit(&n)
+		n = typecheckcomplit(n)
 		if n.Type == nil {
-			n.Type = nil
-			return
+			return n
 		}
 		break OpSwitch
 
@@ -807,51 +832,45 @@ OpSwitch:
 			n.Op = ODOT
 			if n.Left == nil {
 				n.Type = nil
-				return
+				return n
 			}
 		}
 
-		typecheck(&n.Left, Erv|Etype)
+		n.Left = 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
-		}
+		n.Left = defaultlit(n.Left, nil)
 
 		t := n.Left.Type
 		if t == nil {
 			adderrorname(n)
 			n.Type = nil
-			return
+			return n
 		}
 
-		r := n.Right
+		s := n.Sym
 
 		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)
+					Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Sym)
 				} else {
-					Yyerror("%v undefined (type %v has no method %v)", n, t, n.Right.Sym)
+					Yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
 				}
 				n.Type = nil
-				return
+				return n
 			}
 
-			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
+			if n.Type.Etype != TFUNC || n.Type.Recv() == nil {
+				Yyerror("type %v has no method %v", n.Left.Type, sconv(n.Right.Sym, FmtShort))
 				n.Type = nil
-				return
+				return n
 			}
 
 			n.Op = ONAME
 			if n.Name == nil {
 				n.Name = new(Name)
 			}
-			n.Sym = n.Right.Sym
+			n.Right = newname(n.Sym)
 			n.Type = methodfunc(n.Type, n.Left.Type)
 			n.Xoffset = 0
 			n.Class = PFUNC
@@ -859,45 +878,45 @@ OpSwitch:
 			break OpSwitch
 		}
 
-		if Isptr[t.Etype] && t.Type.Etype != TINTER {
-			t = t.Type
+		if t.IsPtr() && !t.Elem().IsInterface() {
+			t = t.Elem()
 			if t == nil {
 				n.Type = nil
-				return
+				return n
 			}
 			n.Op = ODOTPTR
 			checkwidth(t)
 		}
 
-		if isblank(n.Right) {
+		if isblanksym(n.Sym) {
 			Yyerror("cannot refer to blank field or method")
 			n.Type = nil
-			return
+			return n
 		}
 
 		if lookdot(n, t, 0) == nil {
 			// Legitimate field or method lookup failed, try to explain the error
 			switch {
-			case isnilinter(t):
+			case t.IsEmptyInterface():
 				Yyerror("%v undefined (type %v is interface with no methods)", n, n.Left.Type)
 
-			case Isptr[t.Etype] && Isinter(t.Type):
+			case t.IsPtr() && t.Elem().IsInterface():
 				// 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)
+				Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.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)
+					Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Sym, mt.Sym)
 				} else {
-					Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Right.Sym)
+					Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Sym)
 				}
 			}
 			n.Type = nil
-			return
+			return n
 		}
 
 		switch n.Op {
@@ -905,7 +924,7 @@ OpSwitch:
 			if top&Ecall != 0 {
 				ok |= Ecall
 			} else {
-				typecheckpartialcall(n, r)
+				typecheckpartialcall(n, s)
 				ok |= Erv
 			}
 
@@ -917,46 +936,44 @@ OpSwitch:
 
 	case ODOTTYPE:
 		ok |= Erv
-		typecheck(&n.Left, Erv)
-		defaultlit(&n.Left, nil)
+		n.Left = typecheck(n.Left, Erv)
+		n.Left = defaultlit(n.Left, nil)
 		l := n.Left
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		if !Isinter(t) {
+		if !t.IsInterface() {
 			Yyerror("invalid type assertion: %v (non-interface type %v on left)", n, t)
 			n.Type = nil
-			return
+			return n
 		}
 
 		if n.Right != nil {
-			typecheck(&n.Right, Etype)
+			n.Right = typecheck(n.Right, Etype)
 			n.Type = n.Right.Type
 			n.Right = nil
 			if n.Type == nil {
-				n.Type = nil
-				return
+				return n
 			}
 		}
 
-		if n.Type != nil && n.Type.Etype != TINTER {
-			var have *Type
-			var missing *Type
+		if n.Type != nil && !n.Type.IsInterface() {
+			var missing, have *Field
 			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))
+					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, FmtShort|FmtByte), missing.Sym, Tconv(missing.Type, FmtShort|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))
+					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, FmtShort|FmtByte), missing.Sym, Tconv(missing.Type, FmtShort|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
+				return n
 			}
 		}
 
@@ -964,64 +981,62 @@ OpSwitch:
 
 	case OINDEX:
 		ok |= Erv
-		typecheck(&n.Left, Erv)
-		defaultlit(&n.Left, nil)
-		implicitstar(&n.Left)
+		n.Left = typecheck(n.Left, Erv)
+		n.Left = defaultlit(n.Left, nil)
+		n.Left = implicitstar(n.Left)
 		l := n.Left
-		typecheck(&n.Right, Erv)
+		n.Right = typecheck(n.Right, Erv)
 		r := n.Right
 		t := l.Type
 		if t == nil || r.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		switch t.Etype {
 		default:
 			Yyerror("invalid operation: %v (type %v does not support indexing)", n, t)
 			n.Type = nil
-			return
+			return n
 
-		case TSTRING, TARRAY:
-			indexlit(&n.Right)
-			if t.Etype == TSTRING {
+		case TSTRING, TARRAY, TSLICE:
+			n.Right = indexlit(n.Right)
+			if t.IsString() {
 				n.Type = bytetype
 			} else {
-				n.Type = t.Type
+				n.Type = t.Elem()
 			}
 			why := "string"
-			if t.Etype == TARRAY {
-				if Isfixedarray(t) {
-					why = "array"
-				} else {
-					why = "slice"
-				}
+			if t.IsArray() {
+				why = "array"
+			} else if t.IsSlice() {
+				why = "slice"
 			}
 
-			if n.Right.Type != nil && !Isint[n.Right.Type.Etype] {
+			if n.Right.Type != nil && !n.Right.Type.IsInteger() {
 				Yyerror("non-integer %s index %v", why, n.Right)
 				break
 			}
 
 			if !n.Bounded && Isconst(n.Right, CTINT) {
-				x := Mpgetfix(n.Right.Val().U.(*Mpint))
+				x := n.Right.Int64()
 				if x < 0 {
 					Yyerror("invalid %s index %v (index must be non-negative)", why, n.Right)
-				} else if Isfixedarray(t) && x >= t.Bound {
-					Yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.Bound)
+				} else if t.IsArray() && x >= t.NumElem() {
+					Yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem())
 				} 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 {
+				} else if n.Right.Val().U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
 					Yyerror("invalid %s index %v (index too large)", why, n.Right)
 				}
 			}
 
 		case TMAP:
 			n.Etype = 0
-			defaultlit(&n.Right, t.Down)
+			n.Right = defaultlit(n.Right, t.Key())
 			if n.Right.Type != nil {
-				n.Right = assignconv(n.Right, t.Down, "map index")
+				n.Right = assignconv(n.Right, t.Key(), "map index")
 			}
-			n.Type = t.Type
+			n.Type = t.Val()
 			n.Op = OINDEXMAP
 		}
 
@@ -1029,59 +1044,60 @@ OpSwitch:
 
 	case ORECV:
 		ok |= Etop | Erv
-		typecheck(&n.Left, Erv)
-		defaultlit(&n.Left, nil)
+		n.Left = typecheck(n.Left, Erv)
+		n.Left = defaultlit(n.Left, nil)
 		l := n.Left
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		if t.Etype != TCHAN {
+		if !t.IsChan() {
 			Yyerror("invalid operation: %v (receive from non-chan type %v)", n, t)
 			n.Type = nil
-			return
+			return n
 		}
 
-		if t.Chan&Crecv == 0 {
+		if !t.ChanDir().CanRecv() {
 			Yyerror("invalid operation: %v (receive from send-only type %v)", n, t)
 			n.Type = nil
-			return
+			return n
 		}
 
-		n.Type = t.Type
+		n.Type = t.Elem()
 		break OpSwitch
 
 	case OSEND:
 		ok |= Etop
-		l := typecheck(&n.Left, Erv)
-		typecheck(&n.Right, Erv)
-		defaultlit(&n.Left, nil)
+		n.Left = typecheck(n.Left, Erv)
+		l := n.Left
+		n.Right = typecheck(n.Right, Erv)
+		n.Left = defaultlit(n.Left, nil)
 		l = n.Left
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		if t.Etype != TCHAN {
+		if !t.IsChan() {
 			Yyerror("invalid operation: %v (send to non-chan type %v)", n, t)
 			n.Type = nil
-			return
+			return n
 		}
 
-		if t.Chan&Csend == 0 {
+		if !t.ChanDir().CanSend() {
 			Yyerror("invalid operation: %v (send to receive-only type %v)", n, t)
 			n.Type = nil
-			return
+			return n
 		}
 
-		defaultlit(&n.Right, t.Type)
+		n.Right = defaultlit(n.Right, t.Elem())
 		r := n.Right
 		if r.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		n.Right = assignconv(r, l.Type.Type, "send")
+		n.Right = assignconv(r, l.Type.Elem(), "send")
 
 		// TODO: more aggressive
 		n.Etype = 0
@@ -1089,137 +1105,79 @@ OpSwitch:
 		n.Type = nil
 		break OpSwitch
 
-	case OSLICE:
+	case OSLICE, OSLICE3:
 		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)
+		n.Left = typecheck(n.Left, top)
+		low, high, max := n.SliceBounds()
+		hasmax := n.Op.IsSlice3()
+		low = typecheck(low, Erv)
+		high = typecheck(high, Erv)
+		max = typecheck(max, Erv)
+		n.Left = defaultlit(n.Left, nil)
+		low = indexlit(low)
+		high = indexlit(high)
+		max = indexlit(max)
+		n.SetSliceBounds(low, high, max)
 		l := n.Left
-		if Isfixedarray(l.Type) {
+		if l.Type.IsArray() {
 			if !islvalue(n.Left) {
 				Yyerror("invalid operation %v (slice of unaddressable value)", n)
 				n.Type = nil
-				return
+				return n
 			}
 
 			n.Left = Nod(OADDR, n.Left, nil)
 			n.Left.Implicit = true
-			typecheck(&n.Left, Erv)
+			n.Left = typecheck(n.Left, Erv)
 			l = n.Left
 		}
 
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		var tp *Type
-		if Istype(t, TSTRING) {
+		if t.IsString() {
+			if hasmax {
+				Yyerror("invalid operation %v (3-index slice of string)", n)
+				n.Type = nil
+				return n
+			}
 			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
+		} else if t.IsPtr() && t.Elem().IsArray() {
+			tp = t.Elem()
+			n.Type = typSlice(tp.Elem())
 			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) {
-			n.Type = nil
-			return
-		}
-		hi := n.Right.Right
-		if hi != nil && !checksliceindex(l, hi, tp) {
-			n.Type = nil
-			return
-		}
-		if !checksliceconst(lo, hi) {
-			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
+			if hasmax {
+				n.Op = OSLICE3ARR
+			} else {
+				n.Op = OSLICEARR
 			}
-
-			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) {
+		} else if t.IsSlice() {
 			n.Type = t
 		} else {
 			Yyerror("cannot slice %v (type %v)", l, t)
 			n.Type = nil
-			return
+			return n
 		}
 
-		lo := n.Right.Left
-		if lo != nil && !checksliceindex(l, lo, tp) {
+		if low != nil && !checksliceindex(l, low, tp) {
 			n.Type = nil
-			return
+			return n
 		}
-		mid := n.Right.Right.Left
-		if mid != nil && !checksliceindex(l, mid, tp) {
+		if high != nil && !checksliceindex(l, high, tp) {
 			n.Type = nil
-			return
+			return n
 		}
-		hi := n.Right.Right.Right
-		if hi != nil && !checksliceindex(l, hi, tp) {
+		if max != nil && !checksliceindex(l, max, tp) {
 			n.Type = nil
-			return
+			return n
 		}
-		if !checksliceconst(lo, hi) || !checksliceconst(lo, mid) || !checksliceconst(mid, hi) {
+		if !checksliceconst(low, high) || !checksliceconst(low, max) || !checksliceconst(high, max) {
 			n.Type = nil
-			return
+			return n
 		}
 		break OpSwitch
 
@@ -1234,12 +1192,12 @@ OpSwitch:
 					Yyerror("invalid use of ... with builtin %v", l)
 				}
 				n = r
-				typecheck1(&n, top)
-				return
+				n = typecheck1(n, top)
+				return n
 			}
 		}
 
-		typecheck(&n.Left, Erv|Etype|Ecall|top&Eproc)
+		n.Left = typecheck(n.Left, Erv|Etype|Ecall)
 		n.Diag |= n.Left.Diag
 		l = n.Left
 		if l.Op == ONAME && l.Etype != 0 {
@@ -1254,14 +1212,14 @@ OpSwitch:
 
 			n.Left = n.Right
 			n.Right = nil
-			typecheck1(&n, top)
-			return
+			n = typecheck1(n, top)
+			return n
 		}
 
-		defaultlit(&n.Left, nil)
+		n.Left = defaultlit(n.Left, nil)
 		l = n.Left
 		if l.Op == OTYPE {
-			if n.Isddd || l.Type.Bound == -100 {
+			if n.Isddd || l.Type.isDDDArray() {
 				if !l.Type.Broke {
 					Yyerror("invalid use of ... in type conversion to %v", l.Type)
 				}
@@ -1278,21 +1236,21 @@ OpSwitch:
 			n.Type = l.Type
 			if !onearg(n, "conversion to %v", l.Type) {
 				n.Type = nil
-				return
+				return n
 			}
-			typecheck1(&n, top)
-			return
+			n = typecheck1(n, top)
+			return n
 		}
 
-		if count(n.List) == 1 && !n.Isddd {
-			typecheck(&n.List.N, Erv|Efnstruct)
+		if n.List.Len() == 1 && !n.Isddd {
+			n.List.SetIndex(0, typecheck(n.List.Index(0), Erv|Efnstruct))
 		} else {
-			typechecklist(n.List, Erv)
+			typecheckslice(n.List.Slice(), Erv)
 		}
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		checkwidth(t)
 
@@ -1307,7 +1265,7 @@ OpSwitch:
 			// 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
+			tp := t.Recv().Type
 
 			if l.Left == nil || !Eqtype(l.Left.Type, tp) {
 				Fatalf("method receiver")
@@ -1318,28 +1276,20 @@ OpSwitch:
 			if t.Etype != TFUNC {
 				Yyerror("cannot call non-function %v (type %v)", l, t)
 				n.Type = nil
-				return
+				return n
 			}
 		}
 
-		typecheckaste(OCALL, n.Left, n.Isddd, getinargx(t), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) })
+		typecheckaste(OCALL, n.Left, n.Isddd, t.Params(), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) })
 		ok |= Etop
-		if t.Outtuple == 0 {
+		if t.Results().NumFields() == 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 t.Results().NumFields() == 1 {
+			n.Type = l.Type.Results().Field(0).Type
 
-			if n.Op == OCALLFUNC && n.Left.Op == ONAME && (compiling_runtime != 0 || n.Left.Sym.Pkg == Runtimepkg) && n.Left.Sym.Name == "getg" {
+			if n.Op == OCALLFUNC && n.Left.Op == ONAME && (compiling_runtime || 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
@@ -1358,24 +1308,24 @@ OpSwitch:
 			break OpSwitch
 		}
 
-		n.Type = getoutargx(l.Type)
+		n.Type = l.Type.Results()
 
 		break OpSwitch
 
 	case OCAP, OLEN, OREAL, OIMAG:
 		ok |= Erv
-		if !onearg(n, "%v", Oconv(int(n.Op), 0)) {
+		if !onearg(n, "%v", n.Op) {
 			n.Type = nil
-			return
+			return n
 		}
-		typecheck(&n.Left, Erv)
-		defaultlit(&n.Left, nil)
-		implicitstar(&n.Left)
+		n.Left = typecheck(n.Left, Erv)
+		n.Left = defaultlit(n.Left, nil)
+		n.Left = implicitstar(n.Left)
 		l := n.Left
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		switch n.Op {
 		case OCAP:
@@ -1389,7 +1339,7 @@ OpSwitch:
 			}
 
 		case OREAL, OIMAG:
-			if !Iscomplex[t.Etype] {
+			if !t.IsComplex() {
 				goto badcall1
 			}
 			if Isconst(l, CTCPLX) {
@@ -1410,70 +1360,69 @@ OpSwitch:
 		switch t.Etype {
 		case TSTRING:
 			if Isconst(l, CTSTR) {
-				r := Nod(OXXX, nil, nil)
-				Nodconst(r, Types[TINT], int64(len(l.Val().U.(string))))
+				var r Node
+				Nodconst(&r, Types[TINT], int64(len(l.Val().U.(string))))
 				r.Orig = n
-				n = r
+				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)
+			var r Node
+			Nodconst(&r, Types[TINT], t.NumElem())
 			r.Orig = n
-			n = r
+			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))
+		Yyerror("invalid argument %v for %v", Nconv(n.Left, FmtLong), n.Op)
 		n.Type = nil
-		return
+		return n
 
 	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 {
+		if n.List.Len() == 1 {
+			typecheckslice(n.List.Slice(), Efnstruct)
+			if n.List.First().Op != OCALLFUNC && n.List.First().Op != OCALLMETH {
 				Yyerror("invalid operation: complex expects two arguments")
 				n.Type = nil
-				return
+				return n
 			}
 
-			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)
+			t := n.List.First().Left.Type
+			if t.Results().NumFields() != 2 {
+				Yyerror("invalid operation: complex expects two arguments, %v returns %d results", n.List.First(), t.Results().NumFields())
 				n.Type = nil
-				return
+				return n
 			}
 
-			t = n.List.N.Type.Type
-			l = t.Nname
-			r = t.Down.Nname
+			t = n.List.First().Type
+			l = t.Field(0).Nname
+			r = t.Field(1).Nname
 		} else {
 			if !twoarg(n) {
 				n.Type = nil
-				return
+				return n
 			}
-			l = typecheck(&n.Left, Erv|top&Eiota)
-			r = typecheck(&n.Right, Erv|top&Eiota)
+			n.Left = typecheck(n.Left, Erv)
+			n.Right = typecheck(n.Right, Erv)
+			l = n.Left
+			r = n.Right
 			if l.Type == nil || r.Type == nil {
 				n.Type = nil
-				return
+				return n
 			}
-			defaultlit2(&l, &r, 0)
+			l, r = defaultlit2(l, r, false)
 			if l.Type == nil || r.Type == nil {
 				n.Type = nil
-				return
+				return n
 			}
 			n.Left = l
 			n.Right = r
@@ -1482,7 +1431,7 @@ OpSwitch:
 		if !Eqtype(l.Type, r.Type) {
 			Yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
 			n.Type = nil
-			return
+			return n
 		}
 
 		var t *Type
@@ -1490,7 +1439,7 @@ OpSwitch:
 		default:
 			Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type)
 			n.Type = nil
-			return
+			return n
 
 		case TIDEAL:
 			t = Types[TIDEAL]
@@ -1514,28 +1463,28 @@ OpSwitch:
 		break OpSwitch
 
 	case OCLOSE:
-		if !onearg(n, "%v", Oconv(int(n.Op), 0)) {
+		if !onearg(n, "%v", n.Op) {
 			n.Type = nil
-			return
+			return n
 		}
-		typecheck(&n.Left, Erv)
-		defaultlit(&n.Left, nil)
+		n.Left = typecheck(n.Left, Erv)
+		n.Left = defaultlit(n.Left, nil)
 		l := n.Left
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		if t.Etype != TCHAN {
+		if !t.IsChan() {
 			Yyerror("invalid operation: %v (non-chan type %v)", n, t)
 			n.Type = nil
-			return
+			return n
 		}
 
-		if t.Chan&Csend == 0 {
+		if !t.ChanDir().CanSend() {
 			Yyerror("invalid operation: %v (cannot close receive-only channel)", n)
 			n.Type = nil
-			return
+			return n
 		}
 
 		ok |= Etop
@@ -1543,112 +1492,114 @@ OpSwitch:
 
 	case ODELETE:
 		args := n.List
-		if args == nil {
+		if args.Len() == 0 {
 			Yyerror("missing arguments to delete")
 			n.Type = nil
-			return
+			return n
 		}
 
-		if args.Next == nil {
+		if args.Len() == 1 {
 			Yyerror("missing second (key) argument to delete")
 			n.Type = nil
-			return
+			return n
 		}
 
-		if args.Next.Next != nil {
+		if args.Len() != 2 {
 			Yyerror("too many arguments to delete")
 			n.Type = nil
-			return
+			return n
 		}
 
 		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))
+		typecheckslice(args.Slice(), Erv)
+		l := args.First()
+		r := args.Second()
+		if l.Type != nil && !l.Type.IsMap() {
+			Yyerror("first argument to delete must be map; have %v", Tconv(l.Type, FmtLong))
 			n.Type = nil
-			return
+			return n
 		}
 
-		args.Next.N = assignconv(r, l.Type.Down, "delete")
+		args.SetIndex(1, assignconv(r, l.Type.Key(), "delete"))
 		break OpSwitch
 
 	case OAPPEND:
 		ok |= Erv
 		args := n.List
-		if args == nil {
+		if args.Len() == 0 {
 			Yyerror("missing arguments to append")
 			n.Type = nil
-			return
+			return n
 		}
 
-		if count(args) == 1 && !n.Isddd {
-			typecheck(&args.N, Erv|Efnstruct)
+		if args.Len() == 1 && !n.Isddd {
+			args.SetIndex(0, typecheck(args.Index(0), Erv|Efnstruct))
 		} else {
-			typechecklist(args, Erv)
+			typecheckslice(args.Slice(), Erv)
 		}
 
-		t := args.N.Type
+		t := args.First().Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
 
 		// Unpack multiple-return result before type-checking.
 		var funarg *Type
-		if Istype(t, TSTRUCT) && t.Funarg {
+		if t.IsFuncArgStruct() {
 			funarg = t
-			t = t.Type.Type
+			t = t.Field(0).Type
 		}
 
 		n.Type = t
-		if !Isslice(t) {
-			if Isconst(args.N, CTNIL) {
+		if !t.IsSlice() {
+			if Isconst(args.First(), CTNIL) {
 				Yyerror("first argument to append must be typed slice; have untyped nil")
 				n.Type = nil
-				return
+				return n
 			}
 
-			Yyerror("first argument to append must be slice; have %v", Tconv(t, obj.FmtLong))
+			Yyerror("first argument to append must be slice; have %v", Tconv(t, FmtLong))
 			n.Type = nil
-			return
+			return n
 		}
 
 		if n.Isddd {
-			if args.Next == nil {
+			if args.Len() == 1 {
 				Yyerror("cannot use ... on first argument to append")
 				n.Type = nil
-				return
+				return n
 			}
 
-			if args.Next.Next != nil {
+			if args.Len() != 2 {
 				Yyerror("too many arguments to append")
 				n.Type = nil
-				return
+				return n
 			}
 
-			if Istype(t.Type, TUINT8) && Istype(args.Next.N.Type, TSTRING) {
-				defaultlit(&args.Next.N, Types[TSTRING])
+			if t.Elem().IsKind(TUINT8) && args.Second().Type.IsString() {
+				args.SetIndex(1, defaultlit(args.Index(1), Types[TSTRING]))
 				break OpSwitch
 			}
 
-			args.Next.N = assignconv(args.Next.N, t.Orig, "append")
+			args.SetIndex(1, assignconv(args.Index(1), 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)
+			_, it := IterFields(funarg) // Skip first field
+			for t := it.Next(); t != nil; t = it.Next() {
+				if assignop(t.Type, n.Type.Elem(), nil) == 0 {
+					Yyerror("cannot append %v value to []%v", t.Type, n.Type.Elem())
 				}
 			}
 		} else {
-			for args = args.Next; args != nil; args = args.Next {
-				if args.N.Type == nil {
+			as := args.Slice()[1:]
+			for i, n := range as {
+				if n.Type == nil {
 					continue
 				}
-				args.N = assignconv(args.N, t.Type, "append")
+				as[i] = assignconv(n, t.Elem(), "append")
 			}
 		}
 
@@ -1657,61 +1608,61 @@ OpSwitch:
 	case OCOPY:
 		ok |= Etop | Erv
 		args := n.List
-		if args == nil || args.Next == nil {
+		if args.Len() < 2 {
 			Yyerror("missing arguments to copy")
 			n.Type = nil
-			return
+			return n
 		}
 
-		if args.Next.Next != nil {
+		if args.Len() > 2 {
 			Yyerror("too many arguments to copy")
 			n.Type = nil
-			return
+			return n
 		}
 
-		n.Left = args.N
-		n.Right = args.Next.N
-		n.List = nil
+		n.Left = args.First()
+		n.Right = args.Second()
+		n.List.Set(nil)
 		n.Type = Types[TINT]
-		typecheck(&n.Left, Erv)
-		typecheck(&n.Right, Erv)
+		n.Left = typecheck(n.Left, Erv)
+		n.Right = typecheck(n.Right, Erv)
 		if n.Left.Type == nil || n.Right.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		defaultlit(&n.Left, nil)
-		defaultlit(&n.Right, nil)
+		n.Left = defaultlit(n.Left, nil)
+		n.Right = defaultlit(n.Right, nil)
 		if n.Left.Type == nil || n.Right.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
 
 		// copy([]byte, string)
-		if Isslice(n.Left.Type) && n.Right.Type.Etype == TSTRING {
-			if Eqtype(n.Left.Type.Type, bytetype) {
+		if n.Left.Type.IsSlice() && n.Right.Type.IsString() {
+			if Eqtype(n.Left.Type.Elem(), bytetype) {
 				break OpSwitch
 			}
-			Yyerror("arguments to copy have different element types: %v and string", Tconv(n.Left.Type, obj.FmtLong))
+			Yyerror("arguments to copy have different element types: %v and string", Tconv(n.Left.Type, FmtLong))
 			n.Type = nil
-			return
+			return n
 		}
 
-		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))
+		if !n.Left.Type.IsSlice() || !n.Right.Type.IsSlice() {
+			if !n.Left.Type.IsSlice() && !n.Right.Type.IsSlice() {
+				Yyerror("arguments to copy must be slices; have %v, %v", Tconv(n.Left.Type, FmtLong), Tconv(n.Right.Type, FmtLong))
+			} else if !n.Left.Type.IsSlice() {
+				Yyerror("first argument to copy should be slice; have %v", Tconv(n.Left.Type, FmtLong))
 			} else {
-				Yyerror("second argument to copy should be slice or string; have %v", Tconv(n.Right.Type, obj.FmtLong))
+				Yyerror("second argument to copy should be slice or string; have %v", Tconv(n.Right.Type, FmtLong))
 			}
 			n.Type = nil
-			return
+			return n
 		}
 
-		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))
+		if !Eqtype(n.Left.Type.Elem(), n.Right.Type.Elem()) {
+			Yyerror("arguments to copy have different element types: %v and %v", Tconv(n.Left.Type, FmtLong), Tconv(n.Right.Type, FmtLong))
 			n.Type = nil
-			return
+			return n
 		}
 
 		break OpSwitch
@@ -1719,18 +1670,18 @@ OpSwitch:
 	case OCONV:
 		ok |= Erv
 		saveorignode(n)
-		typecheck(&n.Left, Erv|top&(Eindir|Eiota))
-		convlit1(&n.Left, n.Type, true)
+		n.Left = typecheck(n.Left, Erv)
+		n.Left = convlit1(n.Left, n.Type, true, noReuse)
 		t := n.Left.Type
 		if t == nil || n.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		var why string
 		n.Op = convertop(t, n.Type, &why)
 		if n.Op == 0 {
 			if n.Diag == 0 && !n.Type.Broke {
-				Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, obj.FmtLong), n.Type, why)
+				Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, FmtLong), n.Type, why)
 				n.Diag = 1
 			}
 
@@ -1755,7 +1706,7 @@ OpSwitch:
 
 		case OSTRARRAYRUNE:
 			if n.Left.Op == OLITERAL {
-				stringtoarraylit(&n)
+				n = stringtoarraylit(n)
 			}
 		}
 
@@ -1763,64 +1714,58 @@ OpSwitch:
 
 	case OMAKE:
 		ok |= Erv
-		args := n.List
-		if args == nil {
+		args := n.List.Slice()
+		if len(args) == 0 {
 			Yyerror("missing argument to make")
 			n.Type = nil
-			return
+			return n
 		}
 
-		n.List = nil
-		l := args.N
-		args = args.Next
-		typecheck(&l, Etype)
+		n.List.Set(nil)
+		l := args[0]
+		l = typecheck(l, Etype)
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
 
+		i := 1
 		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
-			}
+			return n
 
-			if args == nil {
+		case TSLICE:
+			if i >= len(args) {
 				Yyerror("missing len argument to make(%v)", t)
 				n.Type = nil
-				return
+				return n
 			}
 
-			l = args.N
-			args = args.Next
-			typecheck(&l, Erv)
+			l = args[i]
+			i++
+			l = typecheck(l, Erv)
 			var r *Node
-			if args != nil {
-				r = args.N
-				args = args.Next
-				typecheck(&r, Erv)
+			if i < len(args) {
+				r = args[i]
+				i++
+				r = typecheck(r, Erv)
 			}
 
 			if l.Type == nil || (r != nil && r.Type == nil) {
 				n.Type = nil
-				return
+				return n
 			}
 			if !checkmake(t, "len", l) || r != nil && !checkmake(t, "cap", r) {
 				n.Type = nil
-				return
+				return n
 			}
-			if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val().U.(*Mpint), r.Val().U.(*Mpint)) > 0 {
+			if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && l.Val().U.(*Mpint).Cmp(r.Val().U.(*Mpint)) > 0 {
 				Yyerror("len larger than cap in make(%v)", t)
 				n.Type = nil
-				return
+				return n
 			}
 
 			n.Left = l
@@ -1828,18 +1773,18 @@ OpSwitch:
 			n.Op = OMAKESLICE
 
 		case TMAP:
-			if args != nil {
-				l = args.N
-				args = args.Next
-				typecheck(&l, Erv)
-				defaultlit(&l, Types[TINT])
+			if i < len(args) {
+				l = args[i]
+				i++
+				l = typecheck(l, Erv)
+				l = defaultlit(l, Types[TINT])
 				if l.Type == nil {
 					n.Type = nil
-					return
+					return n
 				}
 				if !checkmake(t, "size", l) {
 					n.Type = nil
-					return
+					return n
 				}
 				n.Left = l
 			} else {
@@ -1849,18 +1794,18 @@ OpSwitch:
 
 		case TCHAN:
 			l = nil
-			if args != nil {
-				l = args.N
-				args = args.Next
-				typecheck(&l, Erv)
-				defaultlit(&l, Types[TINT])
+			if i < len(args) {
+				l = args[i]
+				i++
+				l = typecheck(l, Erv)
+				l = defaultlit(l, Types[TINT])
 				if l.Type == nil {
 					n.Type = nil
-					return
+					return n
 				}
 				if !checkmake(t, "buffer", l) {
 					n.Type = nil
-					return
+					return n
 				}
 				n.Left = l
 			} else {
@@ -1869,11 +1814,11 @@ OpSwitch:
 			n.Op = OMAKECHAN
 		}
 
-		if args != nil {
+		if i < len(args) {
 			Yyerror("too many arguments to make(%v)", t)
 			n.Op = OMAKE
 			n.Type = nil
-			return
+			return n
 		}
 
 		n.Type = t
@@ -1882,23 +1827,23 @@ OpSwitch:
 	case ONEW:
 		ok |= Erv
 		args := n.List
-		if args == nil {
+		if args.Len() == 0 {
 			Yyerror("missing argument to new")
 			n.Type = nil
-			return
+			return n
 		}
 
-		l := args.N
-		typecheck(&l, Etype)
+		l := args.First()
+		l = typecheck(l, Etype)
 		t := l.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		if args.Next != nil {
+		if args.Len() > 1 {
 			Yyerror("too many arguments to new(%v)", t)
 			n.Type = nil
-			return
+			return n
 		}
 
 		n.Left = l
@@ -1907,13 +1852,14 @@ 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 {
+		typecheckslice(n.List.Slice(), Erv)
+		ls := n.List.Slice()
+		for i1, n1 := range ls {
 			// Special case for print: int constant is int64, not int.
-			if Isconst(args.N, CTINT) {
-				defaultlit(&args.N, Types[TINT64])
+			if Isconst(n1, CTINT) {
+				ls[i1] = defaultlit(ls[i1], Types[TINT64])
 			} else {
-				defaultlit(&args.N, nil)
+				ls[i1] = defaultlit(ls[i1], nil)
 			}
 		}
 
@@ -1923,22 +1869,22 @@ OpSwitch:
 		ok |= Etop
 		if !onearg(n, "panic") {
 			n.Type = nil
-			return
+			return n
 		}
-		typecheck(&n.Left, Erv)
-		defaultlit(&n.Left, Types[TINTER])
+		n.Left = typecheck(n.Left, Erv)
+		n.Left = defaultlit(n.Left, Types[TINTER])
 		if n.Left.Type == nil {
 			n.Type = nil
-			return
+			return n
 		}
 		break OpSwitch
 
 	case ORECOVER:
 		ok |= Erv | Etop
-		if n.List != nil {
+		if n.List.Len() != 0 {
 			Yyerror("too many arguments to recover")
 			n.Type = nil
-			return
+			return n
 		}
 
 		n.Type = Types[TINTER]
@@ -1948,20 +1894,19 @@ OpSwitch:
 		ok |= Erv
 		typecheckclosure(n, top)
 		if n.Type == nil {
-			n.Type = nil
-			return
+			return n
 		}
 		break OpSwitch
 
 	case OITAB:
 		ok |= Erv
-		typecheck(&n.Left, Erv)
+		n.Left = typecheck(n.Left, Erv)
 		t := n.Left.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		if t.Etype != TINTER {
+		if !t.IsInterface() {
 			Fatalf("OITAB of %v", t)
 		}
 		n.Type = Ptrto(Types[TUINTPTR])
@@ -1969,19 +1914,19 @@ OpSwitch:
 
 	case OSPTR:
 		ok |= Erv
-		typecheck(&n.Left, Erv)
+		n.Left = typecheck(n.Left, Erv)
 		t := n.Left.Type
 		if t == nil {
 			n.Type = nil
-			return
+			return n
 		}
-		if !Isslice(t) && t.Etype != TSTRING {
+		if !t.IsSlice() && !t.IsString() {
 			Fatalf("OSPTR of %v", t)
 		}
-		if t.Etype == TSTRING {
+		if t.IsString() {
 			n.Type = Ptrto(Types[TUINT8])
 		} else {
-			n.Type = Ptrto(t.Type)
+			n.Type = Ptrto(t.Elem())
 		}
 		break OpSwitch
 
@@ -1991,13 +1936,13 @@ OpSwitch:
 
 	case OCFUNC:
 		ok |= Erv
-		typecheck(&n.Left, Erv)
+		n.Left = typecheck(n.Left, Erv)
 		n.Type = Types[TUINTPTR]
 		break OpSwitch
 
 	case OCONVNOP:
 		ok |= Erv
-		typecheck(&n.Left, Erv)
+		n.Left = typecheck(n.Left, Erv)
 		break OpSwitch
 
 	// statements
@@ -2035,7 +1980,7 @@ OpSwitch:
 
 	case ODEFER:
 		ok |= Etop
-		typecheck(&n.Left, Etop|Erv)
+		n.Left = typecheck(n.Left, Etop|Erv)
 		if n.Left.Diag == 0 {
 			checkdefergo(n)
 		}
@@ -2043,57 +1988,57 @@ OpSwitch:
 
 	case OPROC:
 		ok |= Etop
-		typecheck(&n.Left, Etop|Eproc|Erv)
+		n.Left = typecheck(n.Left, Etop|Erv)
 		checkdefergo(n)
 		break OpSwitch
 
 	case OFOR:
 		ok |= Etop
-		typechecklist(n.Ninit, Etop)
+		typecheckslice(n.Ninit.Slice(), Etop)
 		decldepth++
-		typecheck(&n.Left, Erv)
+		n.Left = 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))
+			if t != nil && !t.IsBoolean() {
+				Yyerror("non-bool %v used as for condition", Nconv(n.Left, FmtLong))
 			}
 		}
-		typecheck(&n.Right, Etop)
-		typechecklist(n.Nbody, Etop)
+		n.Right = typecheck(n.Right, Etop)
+		typecheckslice(n.Nbody.Slice(), Etop)
 		decldepth--
 		break OpSwitch
 
 	case OIF:
 		ok |= Etop
-		typechecklist(n.Ninit, Etop)
-		typecheck(&n.Left, Erv)
+		typecheckslice(n.Ninit.Slice(), Etop)
+		n.Left = 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))
+			if t != nil && !t.IsBoolean() {
+				Yyerror("non-bool %v used as if condition", Nconv(n.Left, FmtLong))
 			}
 		}
-		typechecklist(n.Nbody, Etop)
-		typechecklist(n.Rlist, Etop)
+		typecheckslice(n.Nbody.Slice(), Etop)
+		typecheckslice(n.Rlist.Slice(), Etop)
 		break OpSwitch
 
 	case ORETURN:
 		ok |= Etop
-		if count(n.List) == 1 {
-			typechecklist(n.List, Erv|Efnstruct)
+		if n.List.Len() == 1 {
+			typecheckslice(n.List.Slice(), Erv|Efnstruct)
 		} else {
-			typechecklist(n.List, Erv)
+			typecheckslice(n.List.Slice(), Erv)
 		}
 		if Curfn == nil {
 			Yyerror("return outside function")
 			n.Type = nil
-			return
+			return n
 		}
 
-		if Curfn.Type.Outnamed && n.List == nil {
+		if Curfn.Type.FuncType().Outnamed && n.List.Len() == 0 {
 			break OpSwitch
 		}
-		typecheckaste(ORETURN, nil, false, getoutargx(Curfn.Type), n.List, func() string { return "return argument" })
+		typecheckaste(ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" })
 		break OpSwitch
 
 	case ORETJMP:
@@ -2118,12 +2063,12 @@ OpSwitch:
 	case OTYPESW:
 		Yyerror("use of .(type) outside type switch")
 		n.Type = nil
-		return
+		return n
 
 	case OXCASE:
 		ok |= Etop
-		typechecklist(n.List, Erv)
-		typechecklist(n.Nbody, Etop)
+		typecheckslice(n.List.Slice(), Erv)
+		typecheckslice(n.Nbody.Slice(), Etop)
 		break OpSwitch
 
 	case ODCLFUNC:
@@ -2133,12 +2078,12 @@ OpSwitch:
 
 	case ODCLCONST:
 		ok |= Etop
-		typecheck(&n.Left, Erv)
+		n.Left = typecheck(n.Left, Erv)
 		break OpSwitch
 
 	case ODCLTYPE:
 		ok |= Etop
-		typecheck(&n.Left, Etype)
+		n.Left = typecheck(n.Left, Etype)
 		if incannedimport == 0 {
 			checkwidth(n.Left.Type)
 		}
@@ -2146,14 +2091,10 @@ OpSwitch:
 	}
 
 	t := n.Type
-	if t != nil && !t.Funarg && n.Op != OTYPE {
+	if t != nil && !t.IsFuncArgStruct() && n.Op != OTYPE {
 		switch t.Etype {
-		case TFUNC, // might have TANY; wait until its called
-			TANY,
-			TFORW,
-			TIDEAL,
-			TNIL,
-			TBLANK:
+		case TFUNC, // might have TANY; wait until it's called
+			TANY, TFORW, TIDEAL, TNIL, TBLANK:
 			break
 
 		default:
@@ -2161,7 +2102,7 @@ OpSwitch:
 		}
 	}
 
-	if safemode != 0 && incannedimport == 0 && importpkg == nil && compiling_wrappers == 0 && t != nil && t.Etype == TUNSAFEPTR {
+	if safemode && incannedimport == 0 && importpkg == nil && compiling_wrappers == 0 && t != nil && t.Etype == TUNSAFEPTR {
 		Yyerror("cannot use unsafe.Pointer")
 	}
 
@@ -2169,20 +2110,20 @@ OpSwitch:
 	if n.Op == OTYPE && top&Etype == 0 {
 		Yyerror("type %v is not an expression", n.Type)
 		n.Type = nil
-		return
+		return n
 	}
 
 	if top&(Erv|Etype) == Etype && n.Op != OTYPE {
 		Yyerror("%v is not a type", n)
 		n.Type = nil
-		return
+		return n
 	}
 
 	// 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
+		return n
 	}
 
 	if (top&Etop != 0) && top&(Ecall|Erv|Etype) == 0 && ok&Etop == 0 {
@@ -2192,13 +2133,14 @@ OpSwitch:
 		}
 
 		n.Type = nil
-		return
+		return n
 	}
 
 	/* TODO
 	if(n->type == T)
 		fatal("typecheck nil type");
 	*/
+	return n
 }
 
 func checksliceindex(l *Node, r *Node, tp *Type) bool {
@@ -2206,22 +2148,22 @@ func checksliceindex(l *Node, r *Node, tp *Type) bool {
 	if t == nil {
 		return false
 	}
-	if !Isint[t.Etype] {
+	if !t.IsInteger() {
 		Yyerror("invalid slice index %v (type %v)", r, t)
 		return false
 	}
 
 	if r.Op == OLITERAL {
-		if Mpgetfix(r.Val().U.(*Mpint)) < 0 {
+		if r.Int64() < 0 {
 			Yyerror("invalid slice index %v (index must be non-negative)", r)
 			return false
-		} 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)
+		} else if tp != nil && tp.NumElem() > 0 && r.Int64() > tp.NumElem() {
+			Yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem())
 			return false
-		} else if Isconst(l, CTSTR) && Mpgetfix(r.Val().U.(*Mpint)) > int64(len(l.Val().U.(string))) {
+		} else if Isconst(l, CTSTR) && r.Int64() > 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 false
-		} else if Mpcmpfixfix(r.Val().U.(*Mpint), Maxintval[TINT]) > 0 {
+		} else if r.Val().U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
 			Yyerror("invalid slice index %v (index too large)", r)
 			return false
 		}
@@ -2231,7 +2173,7 @@ func checksliceindex(l *Node, r *Node, tp *Type) bool {
 }
 
 func checksliceconst(lo *Node, hi *Node) bool {
-	if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && Mpcmpfixfix(lo.Val().U.(*Mpint), hi.Val().U.(*Mpint)) > 0 {
+	if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && lo.Val().U.(*Mpint).Cmp(hi.Val().U.(*Mpint)) > 0 {
 		Yyerror("invalid slice index: %v > %v", lo, hi)
 		return false
 	}
@@ -2293,47 +2235,47 @@ func checkdefergo(n *Node) {
 	}
 }
 
-func implicitstar(nn **Node) {
+// The result of implicitstar MUST be assigned back to n, e.g.
+// 	n.Left = implicitstar(n.Left)
+func implicitstar(n *Node) *Node {
 	// insert implicit * if needed for fixed array
-	n := *nn
-
 	t := n.Type
-	if t == nil || !Isptr[t.Etype] {
-		return
+	if t == nil || !t.IsPtr() {
+		return n
 	}
-	t = t.Type
+	t = t.Elem()
 	if t == nil {
-		return
+		return n
 	}
-	if !Isfixedarray(t) {
-		return
+	if !t.IsArray() {
+		return n
 	}
 	n = Nod(OIND, n, nil)
 	n.Implicit = true
-	typecheck(&n, Erv)
-	*nn = n
+	n = typecheck(n, Erv)
+	return n
 }
 
 func onearg(n *Node, f string, args ...interface{}) bool {
 	if n.Left != nil {
 		return true
 	}
-	if n.List == nil {
+	if n.List.Len() == 0 {
 		p := fmt.Sprintf(f, args...)
 		Yyerror("missing argument to %s: %v", p, n)
 		return false
 	}
 
-	if n.List.Next != nil {
+	if n.List.Len() > 1 {
 		p := fmt.Sprintf(f, args...)
 		Yyerror("too many arguments to %s: %v", p, n)
-		n.Left = n.List.N
-		n.List = nil
+		n.Left = n.List.First()
+		n.List.Set(nil)
 		return false
 	}
 
-	n.Left = n.List.N
-	n.List = nil
+	n.Left = n.List.First()
+	n.List.Set(nil)
 	return true
 }
 
@@ -2341,32 +2283,32 @@ func twoarg(n *Node) bool {
 	if n.Left != nil {
 		return true
 	}
-	if n.List == nil {
-		Yyerror("missing argument to %v - %v", Oconv(int(n.Op), 0), n)
+	if n.List.Len() == 0 {
+		Yyerror("missing argument to %v - %v", n.Op, n)
 		return false
 	}
 
-	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
+	n.Left = n.List.First()
+	if n.List.Len() == 1 {
+		Yyerror("missing argument to %v - %v", n.Op, n)
+		n.List.Set(nil)
 		return false
 	}
 
-	if n.List.Next.Next != nil {
-		Yyerror("too many arguments to %v - %v", Oconv(int(n.Op), 0), n)
-		n.List = nil
+	if n.List.Len() > 2 {
+		Yyerror("too many arguments to %v - %v", n.Op, n)
+		n.List.Set(nil)
 		return false
 	}
 
-	n.Right = n.List.Next.N
-	n.List = nil
+	n.Right = n.List.Second()
+	n.List.Set(nil)
 	return true
 }
 
-func lookdot1(errnode *Node, s *Sym, t *Type, f *Type, dostrcmp int) *Type {
-	var r *Type
-	for ; f != nil; f = f.Down {
+func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field {
+	var r *Field
+	for _, f := range fs.Slice() {
 		if dostrcmp != 0 && f.Sym.Name == s.Name {
 			return f
 		}
@@ -2379,7 +2321,7 @@ func lookdot1(errnode *Node, s *Sym, t *Type, f *Type, dostrcmp int) *Type {
 		if r != nil {
 			if errnode != nil {
 				Yyerror("ambiguous selector %v", errnode)
-			} else if Isptr[t.Etype] {
+			} else if t.IsPtr() {
 				Yyerror("ambiguous selector (%v).%v", t, s)
 			} else {
 				Yyerror("ambiguous selector %v.%v", t, s)
@@ -2394,16 +2336,16 @@ func lookdot1(errnode *Node, s *Sym, t *Type, f *Type, dostrcmp int) *Type {
 }
 
 func looktypedot(n *Node, t *Type, dostrcmp int) bool {
-	s := n.Right.Sym
+	s := n.Sym
 
-	if t.Etype == TINTER {
-		f1 := lookdot1(n, s, t, t.Type, dostrcmp)
+	if t.IsInterface() {
+		f1 := lookdot1(n, s, t, t.Fields(), dostrcmp)
 		if f1 == nil {
 			return false
 		}
 
-		n.Right = methodname(n.Right, t)
-		n.Xoffset = f1.Width
+		n.Sym = methodsym(n.Sym, t, 0)
+		n.Xoffset = f1.Offset
 		n.Type = f1.Type
 		n.Op = ODOTINTER
 		return true
@@ -2411,26 +2353,25 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
 
 	// Find the base type: methtype will fail if t
 	// is not of the form T or *T.
-	f2 := methtype(t, 0)
-
-	if f2 == nil {
+	mt := methtype(t, 0)
+	if mt == nil {
 		return false
 	}
 
-	expandmeth(f2)
-	f2 = lookdot1(n, s, f2, f2.Xmethod, dostrcmp)
+	expandmeth(mt)
+	f2 := lookdot1(n, s, mt, mt.AllMethods(), 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))
+	if f2.Type.Recv().Type.IsPtr() && !t.IsPtr() && f2.Embedded != 2 && !isifacemethod(f2.Type) {
+		Yyerror("invalid method expression %v (needs pointer receiver: (*%v).%v)", n, t, sconv(f2.Sym, FmtShort))
 		return false
 	}
 
-	n.Right = methodname(n.Right, t)
-	n.Xoffset = f2.Width
+	n.Sym = methodsym(n.Sym, t, 0)
+	n.Xoffset = f2.Offset
 	n.Type = f2.Type
 	n.Op = ODOTMETH
 	return true
@@ -2438,7 +2379,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
 
 func derefall(t *Type) *Type {
 	for t != nil && t.Etype == Tptr {
-		t = t.Type
+		t = t.Elem()
 	}
 	return t
 }
@@ -2450,24 +2391,24 @@ type typeSym struct {
 
 // 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{}
+var dotField = map[typeSym]*Field{}
 
-func lookdot(n *Node, t *Type, dostrcmp int) *Type {
-	s := n.Right.Sym
+func lookdot(n *Node, t *Type, dostrcmp int) *Field {
+	s := n.Sym
 
 	dowidth(t)
-	var f1 *Type
-	if t.Etype == TSTRUCT || t.Etype == TINTER {
-		f1 = lookdot1(n, s, t, t.Type, dostrcmp)
+	var f1 *Field
+	if t.IsStruct() || t.IsInterface() {
+		f1 = lookdot1(n, s, t, t.Fields(), dostrcmp)
 	}
 
-	var f2 *Type
+	var f2 *Field
 	if n.Left.Type == t || n.Left.Type.Sym == nil {
-		f2 = methtype(t, 0)
-		if f2 != nil {
+		mt := methtype(t, 0)
+		if mt != nil {
 			// Use f2->method, not f2->xmethod: adddot has
 			// already inserted all the necessary embedded dots.
-			f2 = lookdot1(n, s, f2, f2.Method, dostrcmp)
+			f2 = lookdot1(n, s, mt, mt.Methods(), dostrcmp)
 		}
 	}
 
@@ -2477,21 +2418,21 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Type {
 			return f1
 		}
 		if f2 != nil {
-			Yyerror("%v is both field and method", n.Right.Sym)
+			Yyerror("%v is both field and method", n.Sym)
 		}
-		if f1.Width == BADWIDTH {
+		if f1.Offset == BADWIDTH {
 			Fatalf("lookdot badwidth %v %p", f1, f1)
 		}
-		n.Xoffset = f1.Width
+		n.Xoffset = f1.Offset
 		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] {
+		if t.IsInterface() {
+			if n.Left.Type.IsPtr() {
 				n.Left = Nod(OIND, n.Left, nil) // implicitstar
 				n.Left.Implicit = true
-				typecheck(&n.Left, Erv)
+				n.Left = typecheck(n.Left, Erv)
 			}
 
 			n.Op = ODOTINTER
@@ -2507,28 +2448,28 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Type {
 		}
 		tt := n.Left.Type
 		dowidth(tt)
-		rcvr := getthisx(f2.Type).Type.Type
+		rcvr := f2.Type.Recv().Type
 		if !Eqtype(rcvr, tt) {
-			if rcvr.Etype == Tptr && Eqtype(rcvr.Type, tt) {
+			if rcvr.Etype == Tptr && Eqtype(rcvr.Elem(), 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 tt.Etype == Tptr && rcvr.Etype != Tptr && Eqtype(tt.Type, rcvr) {
+				n.Left = typecheck(n.Left, Etype|Erv)
+			} else if tt.Etype == Tptr && rcvr.Etype != Tptr && Eqtype(tt.Elem(), rcvr) {
 				n.Left = Nod(OIND, n.Left, nil)
 				n.Left.Implicit = true
-				typecheck(&n.Left, Etype|Erv)
-			} else if tt.Etype == Tptr && 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))
+				n.Left = typecheck(n.Left, Etype|Erv)
+			} else if tt.Etype == Tptr && tt.Elem().Etype == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
+				Yyerror("calling method %v with receiver %v requires explicit dereference", n.Sym, Nconv(n.Left, FmtLong))
 				for tt.Etype == Tptr {
 					// Stop one level early for method with pointer receiver.
-					if rcvr.Etype == Tptr && tt.Type.Etype != Tptr {
+					if rcvr.Etype == Tptr && tt.Elem().Etype != Tptr {
 						break
 					}
 					n.Left = Nod(OIND, n.Left, nil)
 					n.Left.Implicit = true
-					typecheck(&n.Left, Etype|Erv)
-					tt = tt.Type
+					n.Left = typecheck(n.Left, Etype|Erv)
+					tt = tt.Elem()
 				}
 			} else {
 				Fatalf("method mismatch: %v for %v", rcvr, tt)
@@ -2541,15 +2482,15 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Type {
 			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 {
+		if pll.Implicit && ll.Type.IsPtr() && 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.Sym = methodsym(n.Sym, n.Left.Type, 0)
+		n.Xoffset = f2.Offset
 		n.Type = f2.Type
 
 		//		print("lookdot found [%p] %T\n", f2->type, f2->type);
@@ -2561,9 +2502,9 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Type {
 	return nil
 }
 
-func nokeys(l *NodeList) bool {
-	for ; l != nil; l = l.Next {
-		if l.N.Op == OKEY {
+func nokeys(l Nodes) bool {
+	for _, n := range l.Slice() {
+		if n.Op == OKEY {
 			return false
 		}
 	}
@@ -2571,7 +2512,7 @@ func nokeys(l *NodeList) bool {
 }
 
 func hasddd(t *Type) bool {
-	for tl := t.Type; tl != nil; tl = tl.Down {
+	for _, tl := range t.Fields().Slice() {
 		if tl.Isddd {
 			return true
 		}
@@ -2580,38 +2521,28 @@ func hasddd(t *Type) bool {
 	return false
 }
 
-// downcount is the same as countfield
-// TODO decide if we want both (for semantic reasons)
-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 Op, call *Node, isddd bool, tstruct *Type, nl *NodeList, desc func() string) {
+func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc func() string) {
 	var t *Type
 	var n *Node
 	var n1 int
 	var n2 int
+	var i int
 
-	lno := int(lineno)
+	lno := lineno
 
 	if tstruct.Broke {
 		goto out
 	}
 
 	n = nil
-	if nl != nil && nl.Next == nil {
-		n = nl.N
+	if nl.Len() == 1 {
+		n = nl.First()
 		if n.Type != nil {
-			if n.Type.Etype == TSTRUCT && n.Type.Funarg {
+			if n.Type.IsFuncArgStruct() {
 				if !hasddd(tstruct) {
-					n1 := downcount(tstruct)
-					n2 := downcount(n.Type)
+					n1 := tstruct.NumFields()
+					n2 := n.Type.NumFields()
 					if n2 > n1 {
 						goto toomany
 					}
@@ -2620,16 +2551,16 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl *NodeList, d
 					}
 				}
 
-				tn := n.Type.Type
+				tn, it := IterFields(n.Type)
 				var why string
-				for tl := tstruct.Type; tl != nil; tl = tl.Down {
+				for _, tl := range tstruct.Fields().Slice() {
 					if tl.Isddd {
-						for ; tn != nil; tn = tn.Down {
-							if assignop(tn.Type, tl.Type.Type, &why) == 0 {
+						for ; tn != nil; tn = it.Next() {
+							if assignop(tn.Type, tl.Type.Elem(), &why) == 0 {
 								if call != nil {
-									Yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Type, call, why)
+									Yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Elem(), call, why)
 								} else {
-									Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type.Type, desc(), why)
+									Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type.Elem(), desc(), why)
 								}
 							}
 						}
@@ -2648,7 +2579,7 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl *NodeList, d
 						}
 					}
 
-					tn = tn.Down
+					tn = it.Next()
 				}
 
 				if tn != nil {
@@ -2659,8 +2590,8 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl *NodeList, d
 		}
 	}
 
-	n1 = downcount(tstruct)
-	n2 = count(nl)
+	n1 = tstruct.NumFields()
+	n2 = nl.Len()
 	if !hasddd(tstruct) {
 		if n2 > n1 {
 			goto toomany
@@ -2683,59 +2614,60 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl *NodeList, d
 		}
 	}
 
-	for tl := tstruct.Type; tl != nil; tl = tl.Down {
+	i = 0
+	for _, tl := range tstruct.Fields().Slice() {
 		t = tl.Type
 		if tl.Isddd {
 			if isddd {
-				if nl == nil {
+				if i >= nl.Len() {
 					goto notenough
 				}
-				if nl.Next != nil {
+				if nl.Len()-i > 1 {
 					goto toomany
 				}
-				n = nl.N
+				n = nl.Index(i)
 				setlineno(n)
 				if n.Type != nil {
-					nl.N = assignconvfn(n, t, desc)
+					nl.SetIndex(i, assignconvfn(n, t, desc))
 				}
 				goto out
 			}
 
-			for ; nl != nil; nl = nl.Next {
-				n = nl.N
-				setlineno(nl.N)
+			for ; i < nl.Len(); i++ {
+				n = nl.Index(i)
+				setlineno(n)
 				if n.Type != nil {
-					nl.N = assignconvfn(n, t.Type, desc)
+					nl.SetIndex(i, assignconvfn(n, t.Elem(), desc))
 				}
 			}
 
 			goto out
 		}
 
-		if nl == nil {
+		if i >= nl.Len() {
 			goto notenough
 		}
-		n = nl.N
+		n = nl.Index(i)
 		setlineno(n)
 		if n.Type != nil {
-			nl.N = assignconvfn(n, t, desc)
+			nl.SetIndex(i, assignconvfn(n, t, desc))
 		}
-		nl = nl.Next
+		i++
 	}
 
-	if nl != nil {
+	if i < nl.Len() {
 		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))
+			Yyerror("invalid use of ... in %v", op)
 		}
 	}
 
 out:
-	lineno = int32(lno)
+	lineno = lno
 	return
 
 notenough:
@@ -2750,7 +2682,7 @@ notenough:
 				Yyerror("not enough arguments in call to %v", call)
 			}
 		} else {
-			Yyerror("not enough arguments to %v", Oconv(int(op), 0))
+			Yyerror("not enough arguments to %v", op)
 		}
 		if n != nil {
 			n.Diag = 1
@@ -2763,7 +2695,7 @@ toomany:
 	if call != nil {
 		Yyerror("too many arguments in call to %v", call)
 	} else {
-		Yyerror("too many arguments to %v", Oconv(int(op), 0))
+		Yyerror("too many arguments to %v", op)
 	}
 	goto out
 }
@@ -2791,28 +2723,26 @@ func keydup(n *Node, hash map[uint32][]*Node) {
 		return // we don't check variables
 	}
 
+	const PRIME1 = 3
+
 	var h uint32
-	switch n.Val().Ctype() {
+	switch v := n.Val().U.(type) {
 	default: // unknown, bool, nil
 		h = 23
 
-	case CTINT, CTRUNE:
-		h = uint32(Mpgetfix(n.Val().U.(*Mpint)))
+	case *Mpint:
+		h = uint32(v.Int64())
 
-	case CTFLT:
-		d := mpgetflt(n.Val().U.(*Mpflt))
-		x := math.Float64bits(d)
+	case *Mpflt:
+		x := math.Float64bits(v.Float64())
 		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:]
+	case string:
+		for i := 0; i < len(v); i++ {
+			h = h*PRIME1 + uint32(v[i])
 		}
 	}
 
@@ -2820,25 +2750,19 @@ func keydup(n *Node, hash map[uint32][]*Node) {
 	for _, a := range hash[h] {
 		cmp.Op = OEQ
 		cmp.Left = n
-		b := false
 		if a.Op == OCONVIFACE && orign.Op == OCONVIFACE {
-			if Eqtype(a.Left.Type, n.Type) {
-				cmp.Right = a.Left
-				evconst(&cmp)
-				if cmp.Op == OLITERAL {
-					// Sometimes evconst fails.  See issue 12536.
-					b = cmp.Val().U.(bool)
-				}
-			}
-		} else if Eqtype(a.Type, n.Type) {
-			cmp.Right = a
-			evconst(&cmp)
-			if cmp.Op == OLITERAL {
-				b = cmp.Val().U.(bool)
-			}
+			a = a.Left
 		}
-
-		if b {
+		if !Eqtype(a.Type, n.Type) {
+			continue
+		}
+		cmp.Right = a
+		evconst(&cmp)
+		if cmp.Op != OLITERAL {
+			// Sometimes evconst fails. See issue 12536.
+			continue
+		}
+		if cmp.Val().U.(bool) {
 			Yyerror("duplicate key %v in map literal", n)
 			return
 		}
@@ -2852,7 +2776,7 @@ func indexdup(n *Node, hash map[int64]*Node) {
 		Fatalf("indexdup: not OLITERAL")
 	}
 
-	v := Mpgetfix(n.Val().U.(*Mpint))
+	v := n.Int64()
 	if hash[v] != nil {
 		Yyerror("duplicate index in array literal: %d", v)
 		return
@@ -2860,19 +2784,19 @@ func indexdup(n *Node, hash map[int64]*Node) {
 	hash[v] = n
 }
 
+// iscomptype reports whether type t is a composite literal type
+// or a pointer to one.
 func iscomptype(t *Type) bool {
+	if t.IsPtr() {
+		t = t.Elem()
+	}
+
 	switch t.Etype {
-	case TARRAY, TSTRUCT, TMAP:
+	case TARRAY, TSLICE, TSTRUCT, TMAP:
 		return true
-
-	case TPTR32, TPTR64:
-		switch t.Type.Etype {
-		case TARRAY, TSTRUCT, TMAP:
-			return true
-		}
+	default:
+		return false
 	}
-
-	return false
 }
 
 func pushtype(n *Node, t *Type) {
@@ -2885,28 +2809,33 @@ func pushtype(n *Node, t *Type) {
 		n.Implicit = true       // don't print
 		n.Right.Implicit = true // * is okay
 	} else if Debug['s'] != 0 {
-		typecheck(&n.Right, Etype)
+		n.Right = 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
+// Marker type so esc, fmt, and sinit can recognize the LHS of an OKEY node
+// in a struct literal.
+// TODO(mdempsky): Find a nicer solution.
+var structkey = typ(Txxx)
+
+// The result of typecheckcomplit MUST be assigned back to n, e.g.
+// 	n.Left = typecheckcomplit(n.Left)
+func typecheckcomplit(n *Node) *Node {
 	lno := lineno
 	defer func() {
 		lineno = lno
-		*np = n
 	}()
 
 	if n.Right == nil {
-		if n.List != nil {
-			setlineno(n.List.N)
+		if n.List.Len() != 0 {
+			setlineno(n.List.First())
 		}
 		Yyerror("missing type in composite literal")
 		n.Type = nil
-		return
+		return n
 	}
 
 	// Save original node (including n->right)
@@ -2915,32 +2844,33 @@ func typecheckcomplit(np **Node) {
 	*norig = *n
 
 	setlineno(n.Right)
-	l := typecheck(&n.Right, Etype|Ecomplit) // sic
+	n.Right = typecheck(n.Right, Etype|Ecomplit)
+	l := n.Right // sic
 	t := l.Type
 	if t == nil {
 		n.Type = nil
-		return
+		return n
 	}
 	nerr := nerrors
 	n.Type = t
 
-	if Isptr[t.Etype] {
+	if t.IsPtr() {
 		// 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)
+			Yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Elem())
 			n.Type = nil
-			return
+			return n
 		}
 
 		// 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
+			return n
 		}
 
-		t = t.Type
+		t = t.Elem()
 	}
 
 	var r *Node
@@ -2949,28 +2879,29 @@ func typecheckcomplit(np **Node) {
 		Yyerror("invalid type for composite literal: %v", t)
 		n.Type = nil
 
-	case TARRAY:
+	case TARRAY, TSLICE:
 		// 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 {
+		for _, n1 := range n.List.Slice() {
+			if n1.Op == OKEY {
 				hash = make(map[int64]*Node)
 				break
 			}
 		}
 		length := int64(0)
 		i := 0
-		for ll := n.List; ll != nil; ll = ll.Next {
-			l := ll.N
+		checkBounds := t.IsArray() && !t.isDDDArray()
+		for i2, n2 := range n.List.Slice() {
+			l := n2
 			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
+				n.List.SetIndex(i2, l)
 			}
 
-			typecheck(&l.Left, Erv)
+			l.Left = typecheck(l.Left, Erv)
 			evconst(l.Left)
 			i = nonnegconst(l.Left)
 			if i < 0 && l.Left.Diag == 0 {
@@ -2985,24 +2916,24 @@ func typecheckcomplit(np **Node) {
 			i++
 			if int64(i) > length {
 				length = int64(i)
-				if t.Bound >= 0 && length > t.Bound {
+				if checkBounds && length > t.NumElem() {
 					setlineno(l)
-					Yyerror("array index %d out of bounds [0:%d]", length-1, t.Bound)
-					t.Bound = -1 // no more errors
+					Yyerror("array index %d out of bounds [0:%d]", length-1, t.NumElem())
+					checkBounds = false
 				}
 			}
 
 			r = l.Right
-			pushtype(r, t.Type)
-			typecheck(&r, Erv)
-			defaultlit(&r, t.Type)
-			l.Right = assignconv(r, t.Type, "array or slice literal")
+			pushtype(r, t.Elem())
+			r = typecheck(r, Erv)
+			r = defaultlit(r, t.Elem())
+			l.Right = assignconv(r, t.Elem(), "array or slice literal")
 		}
 
-		if t.Bound == -100 {
-			t.Bound = length
+		if t.isDDDArray() {
+			t.SetNumElem(length)
 		}
-		if t.Bound < 0 {
+		if t.IsSlice() {
 			n.Right = Nodintconst(length)
 		}
 		n.Op = OARRAYLIT
@@ -3010,43 +2941,48 @@ func typecheckcomplit(np **Node) {
 	case TMAP:
 		hash := make(map[uint32][]*Node)
 		var l *Node
-		for ll := n.List; ll != nil; ll = ll.Next {
-			l = ll.N
+		for i3, n3 := range n.List.Slice() {
+			l = n3
 			setlineno(l)
 			if l.Op != OKEY {
-				typecheck(&ll.N, Erv)
+				n.List.SetIndex(i3, typecheck(n.List.Index(i3), 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")
+			pushtype(r, t.Key())
+			r = typecheck(r, Erv)
+			r = defaultlit(r, t.Key())
+			l.Left = assignconv(r, t.Key(), "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")
+			pushtype(r, t.Val())
+			r = typecheck(r, Erv)
+			r = defaultlit(r, t.Val())
+			l.Right = assignconv(r, t.Val(), "map value")
 		}
 
 		n.Op = OMAPLIT
 
 	case TSTRUCT:
+		// Need valid field offsets for Xoffset below.
+		dowidth(t)
+
 		bad := 0
-		if n.List != nil && nokeys(n.List) {
+		if n.List.Len() != 0 && nokeys(n.List) {
 			// simple list of variables
-			f := t.Type
+			f, it := IterFields(t)
 
 			var s *Sym
-			for ll := n.List; ll != nil; ll = ll.Next {
-				setlineno(ll.N)
-				typecheck(&ll.N, Erv)
+			ls := n.List.Slice()
+			for i1, n1 := range ls {
+				setlineno(n1)
+				ls[i1] = typecheck(ls[i1], Erv)
+				n1 = ls[i1]
 				if f == nil {
 					if bad == 0 {
 						Yyerror("too many values in struct initializer")
@@ -3059,14 +2995,14 @@ func typecheckcomplit(np **Node) {
 				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
+				// No pushtype allowed here. Must name fields for that.
+				n1 = assignconv(n1, f.Type, "field value")
+				n1 = Nod(OKEY, newname(f.Sym), n1)
+				n1.Left.Type = structkey
+				n1.Left.Xoffset = f.Offset
+				n1.Left.Typecheck = 1
+				ls[i1] = n1
+				f = it.Next()
 			}
 
 			if f != nil {
@@ -3076,54 +3012,56 @@ func typecheckcomplit(np **Node) {
 			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
+			ls := n.List.Slice()
+			for i, l := range ls {
 				setlineno(l)
 				if l.Op != OKEY {
 					if bad == 0 {
 						Yyerror("mixture of field:value and value initializers")
 					}
 					bad++
-					typecheck(&ll.N, Erv)
+					ls[i] = typecheck(ls[i], Erv)
 					continue
 				}
 
-				s = l.Left.Sym
-				if s == nil {
+				s := l.Left.Sym
+
+				// An OXDOT uses the Sym field to hold
+				// the field to the right of the dot,
+				// so s will be non-nil, but an OXDOT
+				// is never a valid struct literal key.
+				if s == nil || l.Left.Op == OXDOT {
 					Yyerror("invalid field name %v in struct initializer", l.Left)
-					typecheck(&l.Right, Erv)
+					l.Right = typecheck(l.Right, Erv)
 					continue
 				}
 
 				// Sym might have resolved to name in other top-level
-				// package, because of import dot.  Redirect to correct sym
+				// 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)
+					s1 := Lookup(s.Name)
 					if s1.Origpkg == s.Pkg {
 						s = s1
 					}
 				}
 
-				f = lookdot1(nil, s, t, t.Type, 0)
+				f := lookdot1(nil, s, t, t.Fields(), 0)
 				if f == nil {
 					Yyerror("unknown %v field '%v' in struct literal", t, s)
 					continue
 				}
 
 				l.Left = newname(s)
+				l.Left.Type = structkey
+				l.Left.Xoffset = f.Offset
 				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)
+				// No pushtype allowed here. Tried and rejected.
+				r = typecheck(r, Erv)
 
 				l.Right = assignconv(r, f.Type, "field value")
 			}
@@ -3134,11 +3072,11 @@ func typecheckcomplit(np **Node) {
 
 	if nerr != nerrors {
 		n.Type = nil
-		return
+		return n
 	}
 
 	n.Orig = norig
-	if Isptr[n.Type.Etype] {
+	if n.Type.IsPtr() {
 		n = Nod(OPTRLIT, n, nil)
 		n.Typecheck = 1
 		n.Type = n.Left.Type
@@ -3147,23 +3085,21 @@ func typecheckcomplit(np **Node) {
 	}
 
 	n.Orig = norig
-	return
+	return n
 }
 
 // lvalue etc
 func islvalue(n *Node) bool {
 	switch n.Op {
 	case OINDEX:
-		if Isfixedarray(n.Left.Type) {
+		if n.Left.Type != nil && n.Left.Type.IsArray() {
 			return islvalue(n.Left)
 		}
-		if n.Left.Type != nil && n.Left.Type.Etype == TSTRING {
+		if n.Left.Type != nil && n.Left.Type.IsString() {
 			return false
 		}
 		fallthrough
-
-		// fall through
-	case OIND, ODOTPTR, OCLOSUREVAR, OPARAM:
+	case OIND, ODOTPTR, OCLOSUREVAR:
 		return true
 
 	case ODOT:
@@ -3192,14 +3128,14 @@ func checkassign(stmt *Node, n *Node) {
 		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
+			if l.isClosureVar() {
+				l.Name.Defn.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 l.isClosureVar() {
+			l.Name.Defn.Assigned = true
 		}
 	}
 
@@ -3216,12 +3152,17 @@ func checkassign(stmt *Node, n *Node) {
 		return
 	}
 
+	if n.Op == ODOT && n.Left.Op == OINDEXMAP {
+		Yyerror("cannot assign to struct field %v in map", n)
+		return
+	}
+
 	Yyerror("cannot assign to %v", n)
 }
 
-func checkassignlist(stmt *Node, l *NodeList) {
-	for ; l != nil; l = l.Next {
-		checkassign(stmt, l.N)
+func checkassignlist(stmt *Node, l Nodes) {
+	for _, n := range l.Slice() {
+		checkassign(stmt, n)
 	}
 }
 
@@ -3237,7 +3178,7 @@ func samesafeexpr(l *Node, r *Node) bool {
 		return l == r
 
 	case ODOT, ODOTPTR:
-		return l.Right != nil && r.Right != nil && l.Right.Sym == r.Right.Sym && samesafeexpr(l.Left, r.Left)
+		return l.Sym != nil && r.Sym != nil && l.Sym == r.Sym && samesafeexpr(l.Left, r.Left)
 
 	case OIND:
 		return samesafeexpr(l.Left, r.Left)
@@ -3263,10 +3204,10 @@ func typecheckas(n *Node) {
 	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)
+		n.Left = typecheck(n.Left, Erv|Easgn)
 	}
 
-	typecheck(&n.Right, Erv)
+	n.Right = typecheck(n.Right, Erv)
 	checkassign(n, n.Left)
 	if n.Right != nil && n.Right.Type != nil {
 		if n.Left.Type != nil {
@@ -3275,7 +3216,7 @@ func typecheckas(n *Node) {
 	}
 
 	if n.Left.Name != nil && n.Left.Name.Defn == n && n.Left.Name.Param.Ntype == nil {
-		defaultlit(&n.Right, nil)
+		n.Right = defaultlit(n.Right, nil)
 		n.Left.Type = n.Right.Type
 	}
 
@@ -3285,7 +3226,7 @@ func typecheckas(n *Node) {
 	n.Typecheck = 1
 
 	if n.Left.Typecheck == 0 {
-		typecheck(&n.Left, Erv|Easgn)
+		n.Left = typecheck(n.Left, Erv|Easgn)
 	}
 }
 
@@ -3293,27 +3234,29 @@ 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)
+		Yyerror("cannot assign %v to %v in multiple assignment%s", src, Nconv(dst, FmtLong), why)
 		return
 	}
 }
 
 func typecheckas2(n *Node) {
-	for ll := n.List; ll != nil; ll = ll.Next {
+	ls := n.List.Slice()
+	for i1, n1 := range ls {
 		// delicate little dance.
-		ll.N = resolve(ll.N)
+		n1 = resolve(n1)
+		ls[i1] = n1
 
-		if ll.N.Name == nil || ll.N.Name.Defn != n || ll.N.Name.Param.Ntype != nil {
-			typecheck(&ll.N, Erv|Easgn)
+		if n1.Name == nil || n1.Name.Defn != n || n1.Name.Param.Ntype != nil {
+			ls[i1] = typecheck(ls[i1], Erv|Easgn)
 		}
 	}
 
-	cl := count(n.List)
-	cr := count(n.Rlist)
+	cl := n.List.Len()
+	cr := n.Rlist.Len()
 	if cl > 1 && cr == 1 {
-		typecheck(&n.Rlist.N, Erv|Efnstruct)
+		n.Rlist.SetIndex(0, typecheck(n.Rlist.Index(0), Erv|Efnstruct))
 	} else {
-		typechecklist(n.Rlist, Erv)
+		typecheckslice(n.Rlist.Slice(), Erv)
 	}
 	checkassignlist(n, n.List)
 
@@ -3321,23 +3264,24 @@ func typecheckas2(n *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")
+		ls := n.List.Slice()
+		rs := n.Rlist.Slice()
+		for il, nl := range ls {
+			nr := rs[il]
+			if nl.Type != nil && nr.Type != nil {
+				rs[il] = assignconv(nr, nl.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
+			if nl.Name != nil && nl.Name.Defn == n && nl.Name.Param.Ntype == nil {
+				rs[il] = defaultlit(rs[il], nil)
+				nl.Type = rs[il].Type
 			}
 		}
 
 		goto out
 	}
 
-	l = n.List.N
-	r = n.Rlist.N
+	l = n.List.First()
+	r = n.Rlist.First()
 
 	// x,y,z = f()
 	if cr == 1 {
@@ -3346,24 +3290,23 @@ func typecheckas2(n *Node) {
 		}
 		switch r.Op {
 		case OCALLMETH, OCALLINTER, OCALLFUNC:
-			if r.Type.Etype != TSTRUCT || !r.Type.Funarg {
+			if !r.Type.IsFuncArgStruct() {
 				break
 			}
-			cr = structcount(r.Type)
+			cr = r.Type.NumFields()
 			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)
+			t, s := IterFields(r.Type)
+			for _, n3 := range n.List.Slice() {
+				if t.Type != nil && n3.Type != nil {
+					checkassignto(t.Type, n3)
 				}
-				if ll.N.Name != nil && ll.N.Name.Defn == n && ll.N.Name.Param.Ntype == nil {
-					ll.N.Type = t.Type
+				if n3.Name != nil && n3.Name.Defn == n && n3.Name.Param.Ntype == nil {
+					n3.Type = t.Type
 				}
-				t = structnext(&s)
+				t = s.Next()
 			}
 
 			goto out
@@ -3395,8 +3338,8 @@ func typecheckas2(n *Node) {
 			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 {
+			l := n.List.Second()
+			if l.Type != nil && !l.Type.IsBoolean() {
 				checkassignto(Types[TBOOL], l)
 			}
 			if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil {
@@ -3412,74 +3355,75 @@ mismatch:
 	// 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)
+	ls = n.List.Slice()
+	for i1, n1 := range ls {
+		if n1.Typecheck == 0 {
+			ls[i1] = typecheck(ls[i1], Erv|Easgn)
 		}
 	}
 }
 
 // type check function definition
 func typecheckfunc(n *Node) {
-	typecheck(&n.Func.Nname, Erv|Easgn)
+	n.Func.Nname = 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
+	t.SetNname(n.Func.Nname)
+	rcvr := t.Recv()
 	if rcvr != nil && n.Func.Shortname != nil {
-		addmethod(n.Func.Shortname.Sym, t, true, n.Func.Nname.Nointerface)
+		addmethod(n.Func.Shortname.Sym, t, nil, true, n.Func.Pragma&Nointerface != 0)
 	}
 
-	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
+	for _, ln := range n.Func.Dcl {
+		if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
+			ln.Name.Decldepth = 1
 		}
 	}
 }
 
-func stringtoarraylit(np **Node) {
-	n := *np
+// The result of stringtoarraylit MUST be assigned back to n, e.g.
+// 	n.Left = stringtoarraylit(n.Left)
+func stringtoarraylit(n *Node) *Node {
 	if n.Left.Op != OLITERAL || n.Left.Val().Ctype() != CTSTR {
 		Fatalf("stringtoarraylit %v", n)
 	}
 
 	s := n.Left.Val().U.(string)
-	var l *NodeList
-	if n.Type.Type.Etype == TUINT8 {
+	var l []*Node
+	if n.Type.Elem().Etype == TUINT8 {
 		// []byte
 		for i := 0; i < len(s); i++ {
-			l = list(l, Nod(OKEY, Nodintconst(int64(i)), Nodintconst(int64(s[0]))))
+			l = append(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))))
+			l = append(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
+	nn.List.Set(l)
+	nn = typecheck(nn, Erv)
+	return nn
 }
 
 var ntypecheckdeftype int
 
-var methodqueue *NodeList
+var methodqueue []*Node
 
 func domethod(n *Node) {
-	nt := n.Type.Nname
-	typecheck(&nt, Etype)
+	nt := n.Type.Nname()
+	nt = typecheck(nt, Etype)
 	if nt.Type == nil {
 		// type check failed; leave empty func
+		// TODO(mdempsky): Fix Type rekinding.
 		n.Type.Etype = TFUNC
-
 		n.Type.Nod = nil
 		return
 	}
@@ -3490,33 +3434,39 @@ func domethod(n *Node) {
 	//	}
 	// 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
+	// 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 {
+	for _, t := range nt.Type.Params().Fields().Slice() {
 		if t.Sym != nil && t.Sym.Name == "_" {
 			t.Sym = nil
 		}
 	}
 
+	// TODO(mdempsky): Fix Type rekinding.
 	*n.Type = *nt.Type
 	n.Type.Nod = nil
 	checkwidth(n.Type)
 }
 
-var mapqueue *NodeList
+type mapqueueval struct {
+	n   *Node
+	lno int32
+}
+
+// tracks the line numbers at which forward types are first used as map keys
+var mapqueue []mapqueueval
 
 func copytype(n *Node, t *Type) {
 	if t.Etype == TFORW {
 		// This type isn't computed yet; when it is, update n.
-		t.Copyto = append(t.Copyto, n)
-
+		t.ForwardType().Copyto = append(t.ForwardType().Copyto, n)
 		return
 	}
 
-	maplineno := int(n.Type.Maplineno)
-	embedlineno := int(n.Type.Embedlineno)
+	embedlineno := n.Type.ForwardType().Embedlineno
+	l := n.Type.ForwardType().Copyto
 
-	l := n.Type.Copyto
+	// TODO(mdempsky): Fix Type rekinding.
 	*n.Type = *t
 
 	t = n.Type
@@ -3525,12 +3475,11 @@ func copytype(n *Node, t *Type) {
 	if n.Name != nil {
 		t.Vargen = n.Name.Vargen
 	}
-	t.Method = nil
-	t.Xmethod = nil
+	t.methods = Fields{}
+	t.allMethods = Fields{}
 	t.Nod = nil
 	t.Printed = false
 	t.Deferwidth = false
-	t.Copyto = nil
 
 	// Update nodes waiting on this type.
 	for _, n := range l {
@@ -3538,31 +3487,25 @@ func copytype(n *Node, t *Type) {
 	}
 
 	// Double-check use of type as embedded type.
-	lno := int(lineno)
+	lno := lineno
 
 	if embedlineno != 0 {
-		lineno = int32(embedlineno)
-		if Isptr[t.Etype] {
+		lineno = embedlineno
+		if t.IsPtr() || t.IsUnsafePtr() {
 			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)
-	}
+	lineno = lno
 }
 
 func typecheckdeftype(n *Node) {
 	ntypecheckdeftype++
-	lno := int(lineno)
+	lno := lineno
 	setlineno(n)
 	n.Type.Sym = n.Sym
 	n.Typecheck = 1
-	typecheck(&n.Name.Param.Ntype, Etype)
+	n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
 	t := n.Name.Param.Ntype.Type
 	if t == nil {
 		n.Diag = 1
@@ -3582,30 +3525,30 @@ func typecheckdeftype(n *Node) {
 	copytype(n, t)
 
 ret:
-	lineno = int32(lno)
+	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 {
-		var l *NodeList
 		for {
-			l = methodqueue
-			if l == nil {
+			s := methodqueue
+			if len(s) == 0 {
 				break
 			}
 			methodqueue = nil
-			for ; l != nil; l = l.Next {
-				domethod(l.N)
+			for _, n := range s {
+				domethod(n)
 			}
 		}
-
-		for l := mapqueue; l != nil; l = l.Next {
-			lineno = l.N.Type.Maplineno
-			maptype(l.N.Type, Types[TBOOL])
+		for _, e := range mapqueue {
+			lineno = e.lno
+			if !e.n.Type.IsComparable() {
+				Yyerror("invalid map key type %v", e.n.Type)
+			}
 		}
-
-		lineno = int32(lno)
+		mapqueue = nil
+		lineno = lno
 	}
 
 	ntypecheckdeftype--
@@ -3617,11 +3560,11 @@ func queuemethod(n *Node) {
 		return
 	}
 
-	methodqueue = list(methodqueue, n)
+	methodqueue = append(methodqueue, n)
 }
 
 func typecheckdef(n *Node) *Node {
-	lno := int(lineno)
+	lno := lineno
 	setlineno(n)
 
 	if n.Op == ONONAME {
@@ -3663,7 +3606,7 @@ func typecheckdef(n *Node) *Node {
 
 	switch n.Op {
 	default:
-		Fatalf("typecheckdef %v", Oconv(int(n.Op), 0))
+		Fatalf("typecheckdef %v", n.Op)
 
 		// not really syms
 	case OGOTO, OLABEL:
@@ -3671,7 +3614,7 @@ func typecheckdef(n *Node) *Node {
 
 	case OLITERAL:
 		if n.Name.Param.Ntype != nil {
-			typecheck(&n.Name.Param.Ntype, Etype)
+			n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
 			n.Type = n.Name.Param.Ntype.Type
 			n.Name.Param.Ntype = nil
 			if n.Type == nil {
@@ -3688,7 +3631,7 @@ func typecheckdef(n *Node) *Node {
 			Yyerror("xxx")
 		}
 
-		typecheck(&e, Erv|Eiota)
+		e = typecheck(e, Erv)
 		if Isconst(e, CTNIL) {
 			Yyerror("const initializer cannot be nil")
 			goto ret
@@ -3710,12 +3653,12 @@ func typecheckdef(n *Node) *Node {
 				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)
+			if !e.Type.IsUntyped() && !Eqtype(t, e.Type) {
+				Yyerror("cannot use %v as type %v in const initializer", Nconv(e, FmtLong), t)
 				goto ret
 			}
 
-			Convlit(&e, t)
+			e = convlit(e, t)
 		}
 
 		n.SetVal(e.Val())
@@ -3723,7 +3666,7 @@ func typecheckdef(n *Node) *Node {
 
 	case ONAME:
 		if n.Name.Param.Ntype != nil {
-			typecheck(&n.Name.Param.Ntype, Etype)
+			n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
 			n.Type = n.Name.Param.Ntype.Type
 			if n.Type == nil {
 				n.Diag = 1
@@ -3750,12 +3693,12 @@ func typecheckdef(n *Node) *Node {
 		}
 
 		if n.Name.Defn.Op == ONAME {
-			typecheck(&n.Name.Defn, Erv)
+			n.Name.Defn = typecheck(n.Name.Defn, Erv)
 			n.Type = n.Name.Defn.Type
 			break
 		}
 
-		typecheck(&n.Name.Defn, Etop) // fills in n->type
+		n.Name.Defn = typecheck(n.Name.Defn, Etop) // fills in n->type
 
 	case OTYPE:
 		if Curfn != nil {
@@ -3782,7 +3725,7 @@ func typecheckdef(n *Node) *Node {
 	}
 
 ret:
-	if n.Op != OLITERAL && n.Type != nil && isideal(n.Type) {
+	if n.Op != OLITERAL && n.Type != nil && n.Type.IsUntyped() {
 		Fatalf("got %v for %v", n.Type, n)
 	}
 	last := len(typecheckdefstack) - 1
@@ -3792,7 +3735,7 @@ ret:
 	typecheckdefstack[last] = nil
 	typecheckdefstack = typecheckdefstack[:last]
 
-	lineno = int32(lno)
+	lineno = lno
 	n.Walkdef = 1
 	return n
 }
@@ -3802,19 +3745,19 @@ func checkmake(t *Type, arg string, n *Node) bool {
 		switch n.Val().Ctype() {
 		case CTINT, CTRUNE, CTFLT, CTCPLX:
 			n.SetVal(toint(n.Val()))
-			if mpcmpfixc(n.Val().U.(*Mpint), 0) < 0 {
+			if n.Val().U.(*Mpint).CmpInt64(0) < 0 {
 				Yyerror("negative %s argument in make(%v)", arg, t)
 				return false
 			}
 
-			if Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT]) > 0 {
+			if n.Val().U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
 				Yyerror("%s argument too large in make(%v)", arg, t)
 				return false
 			}
 
 			// Delay defaultlit until after we've checked range, to avoid
 			// a redundant "constant NNN overflows int" error.
-			defaultlit(&n, Types[TINT])
+			n = defaultlit(n, Types[TINT])
 
 			return true
 
@@ -3823,13 +3766,13 @@ func checkmake(t *Type, arg string, n *Node) bool {
 		}
 	}
 
-	if !Isint[n.Type.Etype] && n.Type.Etype != TIDEAL {
+	if !n.Type.IsInteger() && n.Type.Etype != TIDEAL {
 		Yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type)
 		return false
 	}
 
 	// Defaultlit still necessary for non-constant: n might be 1<<k.
-	defaultlit(&n, Types[TINT])
+	n = defaultlit(n, Types[TINT])
 
 	return true
 }
@@ -3843,12 +3786,12 @@ func markbreak(n *Node, implicit *Node) {
 	case OBREAK:
 		if n.Left == nil {
 			if implicit != nil {
-				implicit.Hasbreak = true
+				implicit.SetHasBreak(true)
 			}
 		} else {
 			lab := n.Left.Sym.Label
 			if lab != nil {
-				lab.Def.Hasbreak = true
+				lab.Def.SetHasBreak(true)
 			}
 		}
 
@@ -3859,11 +3802,8 @@ func markbreak(n *Node, implicit *Node) {
 		ORANGE:
 		implicit = n
 		fallthrough
-
-		// fall through
 	default:
 		markbreak(n.Left, implicit)
-
 		markbreak(n.Right, implicit)
 		markbreaklist(n.Ninit, implicit)
 		markbreaklist(n.Nbody, implicit)
@@ -3872,25 +3812,19 @@ func markbreak(n *Node, implicit *Node) {
 	}
 }
 
-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 {
+func markbreaklist(l Nodes, implicit *Node) {
+	s := l.Slice()
+	for i := 0; i < len(s); i++ {
+		n := s[i]
+		if n.Op == OLABEL && i+1 < len(s) && n.Name.Defn == s[i+1] {
 			switch n.Name.Defn.Op {
-			case OFOR,
-				OSWITCH,
-				OTYPESW,
-				OSELECT,
-				ORANGE:
-				lab = new(Label)
+			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
+				i++
 				continue
 			}
 		}
@@ -3899,26 +3833,20 @@ func markbreaklist(l *NodeList, implicit *Node) {
 	}
 }
 
-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 {
+// Isterminating whether the Nodes list ends with a terminating
+// statement.
+func (l Nodes) isterminating() bool {
+	s := l.Slice()
+	c := len(s)
+	if c == 0 {
 		return false
 	}
+	return s[c-1].isterminating()
+}
 
+// Isterminating returns whether the node n, the last one in a
+// statement list, is a terminating statement.
+func (n *Node) isterminating() bool {
 	switch n.Op {
 	// NOTE: OLABEL is treated as a separate statement,
 	// not a separate prefix, so skipping to the last statement
@@ -3926,7 +3854,7 @@ func isterminating(l *NodeList, top int) bool {
 	// skipping over the label. No case OLABEL here.
 
 	case OBLOCK:
-		return isterminating(n.List, 0)
+		return n.List.isterminating()
 
 	case OGOTO,
 		ORETURN,
@@ -3939,24 +3867,24 @@ func isterminating(l *NodeList, top int) bool {
 		if n.Left != nil {
 			return false
 		}
-		if n.Hasbreak {
+		if n.HasBreak() {
 			return false
 		}
 		return true
 
 	case OIF:
-		return isterminating(n.Nbody, 0) && isterminating(n.Rlist, 0)
+		return n.Nbody.isterminating() && n.Rlist.isterminating()
 
 	case OSWITCH, OTYPESW, OSELECT:
-		if n.Hasbreak {
+		if n.HasBreak() {
 			return false
 		}
 		def := 0
-		for l = n.List; l != nil; l = l.Next {
-			if !isterminating(l.N.Nbody, 0) {
+		for _, n1 := range n.List.Slice() {
+			if !n1.Nbody.isterminating() {
 				return false
 			}
-			if l.N.List == nil { // default
+			if n1.List.Len() == 0 { // default
 				def = 1
 			}
 		}
@@ -3971,9 +3899,10 @@ func isterminating(l *NodeList, top int) bool {
 }
 
 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")
+	if fn.Type.Results().NumFields() != 0 && fn.Nbody.Len() != 0 {
+		markbreaklist(fn.Nbody, nil)
+		if !fn.Nbody.isterminating() {
+			yyerrorl(fn.Func.Endlineno, "missing return at end of function")
 		}
 	}
 }
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
new file mode 100644
index 0000000..270d4c3
--- /dev/null
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -0,0 +1,466 @@
+// 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
+
+// builtinpkg is a fake package that declares the universe block.
+var builtinpkg *Pkg
+
+var itable *Type // distinguished *byte
+
+var basicTypes = [...]struct {
+	name  string
+	etype EType
+}{
+	{"int8", TINT8},
+	{"int16", TINT16},
+	{"int32", TINT32},
+	{"int64", TINT64},
+	{"uint8", TUINT8},
+	{"uint16", TUINT16},
+	{"uint32", TUINT32},
+	{"uint64", TUINT64},
+	{"float32", TFLOAT32},
+	{"float64", TFLOAT64},
+	{"complex64", TCOMPLEX64},
+	{"complex128", TCOMPLEX128},
+	{"bool", TBOOL},
+	{"string", TSTRING},
+	{"any", TANY},
+}
+
+var typedefs = [...]struct {
+	name     string
+	etype    EType
+	width    *int
+	sameas32 EType
+	sameas64 EType
+}{
+	{"int", TINT, &Widthint, TINT32, TINT64},
+	{"uint", TUINT, &Widthint, TUINT32, TUINT64},
+	{"uintptr", TUINTPTR, &Widthptr, TUINT32, TUINT64},
+}
+
+var builtinFuncs = [...]struct {
+	name string
+	op   Op
+}{
+	{"append", OAPPEND},
+	{"cap", OCAP},
+	{"close", OCLOSE},
+	{"complex", OCOMPLEX},
+	{"copy", OCOPY},
+	{"delete", ODELETE},
+	{"imag", OIMAG},
+	{"len", OLEN},
+	{"make", OMAKE},
+	{"new", ONEW},
+	{"panic", OPANIC},
+	{"print", OPRINT},
+	{"println", OPRINTN},
+	{"real", OREAL},
+	{"recover", ORECOVER},
+}
+
+// initUniverse initializes the universe block.
+func initUniverse() {
+	lexinit()
+	typeinit()
+	lexinit1()
+}
+
+// lexinit initializes known symbols and the basic types.
+func lexinit() {
+	for _, s := range basicTypes {
+		etype := s.etype
+		if int(etype) >= len(Types) {
+			Fatalf("lexinit: %s bad etype", s.name)
+		}
+		s2 := Pkglookup(s.name, builtinpkg)
+		t := Types[etype]
+		if t == nil {
+			t = typ(etype)
+			t.Sym = s2
+			if etype != TANY && etype != TSTRING {
+				dowidth(t)
+			}
+			Types[etype] = t
+		}
+		s2.Def = typenod(t)
+		s2.Def.Name = new(Name)
+	}
+
+	for _, s := range builtinFuncs {
+		// TODO(marvin): Fix Node.EType type union.
+		s2 := Pkglookup(s.name, builtinpkg)
+		s2.Def = Nod(ONAME, nil, nil)
+		s2.Def.Sym = s2
+		s2.Def.Etype = EType(s.op)
+	}
+
+	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)
+
+	s = Pkglookup("iota", builtinpkg)
+	s.Def = Nod(OIOTA, nil, nil)
+	s.Def.Sym = s
+	s.Def.Name = new(Name)
+}
+
+func typeinit() {
+	if Widthptr == 0 {
+		Fatalf("typeinit before betypeinit")
+	}
+
+	for et := EType(0); et < NTYPE; et++ {
+		Simtype[et] = et
+	}
+
+	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 et := TINT8; et <= TUINT64; et++ {
+		Isint[et] = true
+	}
+	Isint[TINT] = true
+	Isint[TUINT] = true
+	Isint[TUINTPTR] = true
+
+	Isfloat[TFLOAT32] = true
+	Isfloat[TFLOAT64] = true
+
+	Iscomplex[TCOMPLEX64] = true
+	Iscomplex[TCOMPLEX128] = true
+
+	isforw[TFORW] = true
+
+	// initialize okfor
+	for et := EType(0); et < NTYPE; et++ {
+		if Isint[et] || et == TIDEAL {
+			okforeq[et] = true
+			okforcmp[et] = true
+			okforarith[et] = true
+			okforadd[et] = true
+			okforand[et] = true
+			okforconst[et] = true
+			issimple[et] = true
+			Minintval[et] = new(Mpint)
+			Maxintval[et] = new(Mpint)
+		}
+
+		if Isfloat[et] {
+			okforeq[et] = true
+			okforcmp[et] = true
+			okforadd[et] = true
+			okforarith[et] = true
+			okforconst[et] = true
+			issimple[et] = true
+			minfltval[et] = newMpflt()
+			maxfltval[et] = newMpflt()
+		}
+
+		if Iscomplex[et] {
+			okforeq[et] = true
+			okforadd[et] = true
+			okforarith[et] = true
+			okforconst[et] = true
+			issimple[et] = true
+		}
+	}
+
+	issimple[TBOOL] = true
+
+	okforadd[TSTRING] = true
+
+	okforbool[TBOOL] = true
+
+	okforcap[TARRAY] = true
+	okforcap[TCHAN] = true
+	okforcap[TSLICE] = true
+
+	okforconst[TBOOL] = true
+	okforconst[TSTRING] = true
+
+	okforlen[TARRAY] = true
+	okforlen[TCHAN] = true
+	okforlen[TMAP] = true
+	okforlen[TSLICE] = 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[TSLICE] = true  // nil only; refined in typecheck
+	okforeq[TARRAY] = true  // only if element type is comparable; refined in typecheck
+	okforeq[TSTRUCT] = true // only if all struct fields are comparable; 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
+
+	Maxintval[TINT8].SetString("0x7f")
+	Minintval[TINT8].SetString("-0x80")
+	Maxintval[TINT16].SetString("0x7fff")
+	Minintval[TINT16].SetString("-0x8000")
+	Maxintval[TINT32].SetString("0x7fffffff")
+	Minintval[TINT32].SetString("-0x80000000")
+	Maxintval[TINT64].SetString("0x7fffffffffffffff")
+	Minintval[TINT64].SetString("-0x8000000000000000")
+
+	Maxintval[TUINT8].SetString("0xff")
+	Maxintval[TUINT16].SetString("0xffff")
+	Maxintval[TUINT32].SetString("0xffffffff")
+	Maxintval[TUINT64].SetString("0xffffffffffffffff")
+
+	// f is valid float if min < f < max.  (min and max are not themselves valid.)
+	maxfltval[TFLOAT32].SetString("33554431p103") // 2^24-1 p (127-23) + 1/2 ulp
+	minfltval[TFLOAT32].SetString("-33554431p103")
+	maxfltval[TFLOAT64].SetString("18014398509481983p970") // 2^53-1 p (1023-52) + 1/2 ulp
+	minfltval[TFLOAT64].SetString("-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] = Tptr
+
+	Simtype[TCHAN] = Tptr
+	Simtype[TFUNC] = Tptr
+	Simtype[TUNSAFEPTR] = Tptr
+
+	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 = typPtr(Types[TUINT8])
+}
+
+func makeErrorInterface() *Type {
+	rcvr := typ(TSTRUCT)
+	rcvr.StructType().Funarg = FunargRcvr
+	field := newField()
+	field.Type = Ptrto(typ(TSTRUCT))
+	rcvr.SetFields([]*Field{field})
+
+	in := typ(TSTRUCT)
+	in.StructType().Funarg = FunargParams
+
+	out := typ(TSTRUCT)
+	out.StructType().Funarg = FunargResults
+	field = newField()
+	field.Type = Types[TSTRING]
+	out.SetFields([]*Field{field})
+
+	f := typ(TFUNC)
+	*f.RecvsP() = rcvr
+	*f.ResultsP() = out
+	*f.ParamsP() = in
+
+	t := typ(TINTER)
+	field = newField()
+	field.Sym = Lookup("Error")
+	field.Type = f
+	t.SetFields([]*Field{field})
+
+	return t
+}
+
+func lexinit1() {
+	// error type
+	s := Pkglookup("error", builtinpkg)
+	errortype = makeErrorInterface()
+	errortype.Sym = s
+	// TODO: If we can prove that it's safe to set errortype.Orig here
+	// than we don't need the special errortype/errorInterface case in
+	// bexport.go. See also issue #15920.
+	// errortype.Orig = makeErrorInterface()
+	s.Def = typenod(errortype)
+
+	// byte alias
+	s = Pkglookup("byte", builtinpkg)
+	bytetype = typ(TUINT8)
+	bytetype.Sym = s
+	s.Def = typenod(bytetype)
+	s.Def.Name = new(Name)
+
+	// rune alias
+	s = Pkglookup("rune", builtinpkg)
+	runetype = typ(TINT32)
+	runetype.Sym = s
+	s.Def = typenod(runetype)
+	s.Def.Name = new(Name)
+
+	// backend-dependent builtin types (e.g. int).
+	for _, s := range typedefs {
+		s1 := Pkglookup(s.name, builtinpkg)
+
+		sameas := s.sameas32
+		if *s.width == 8 {
+			sameas = s.sameas64
+		}
+
+		Simtype[s.etype] = sameas
+		minfltval[s.etype] = minfltval[sameas]
+		maxfltval[s.etype] = maxfltval[sameas]
+		Minintval[s.etype] = Minintval[sameas]
+		Maxintval[s.etype] = Maxintval[sameas]
+
+		t := typ(s.etype)
+		t.Sym = s1
+		Types[s.etype] = t
+		s1.Def = typenod(t)
+		s1.Def.Name = new(Name)
+		s1.Origpkg = builtinpkg
+
+		dowidth(t)
+	}
+}
+
+// finishUniverse makes the universe block visible within the current package.
+func finishUniverse() {
+	// Operationally, this is similar to a dot import of builtinpkg, except
+	// that we silently skip symbols that are already declared in the
+	// package block rather than emitting a redeclared symbol error.
+
+	for _, s := range builtinpkg.Syms {
+		if s.Def == nil || (s.Name == "any" && Debug['A'] == 0) {
+			continue
+		}
+		s1 := Lookup(s.Name)
+		if s1.Def != nil {
+			continue
+		}
+
+		s1.Def = s.Def
+		s1.Block = s.Block
+	}
+
+	nodfp = Nod(ONAME, nil, nil)
+	nodfp.Type = Types[TINT32]
+	nodfp.Xoffset = 0
+	nodfp.Class = PPARAM
+	nodfp.Sym = Lookup(".fp")
+}
diff --git a/src/cmd/compile/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go
index 8884374..fc6ed1f 100644
--- a/src/cmd/compile/internal/gc/unsafe.go
+++ b/src/cmd/compile/internal/gc/unsafe.go
@@ -4,18 +4,12 @@
 
 package gc
 
-import "cmd/internal/obj"
-
-// look for
-//	unsafe.Sizeof
-//	unsafe.Offsetof
-//	unsafe.Alignof
-// rewrite with a constant
+// unsafenmagic rewrites calls to package unsafe's functions into constants.
 func unsafenmagic(nn *Node) *Node {
 	fn := nn.Left
 	args := nn.List
 
-	if safemode != 0 || fn == nil || fn.Op != ONAME {
+	if safemode || fn == nil || fn.Op != ONAME {
 		return nil
 	}
 	s := fn.Sym
@@ -26,27 +20,30 @@ func unsafenmagic(nn *Node) *Node {
 		return nil
 	}
 
-	if args == nil {
+	if args.Len() == 0 {
 		Yyerror("missing argument for %v", s)
 		return nil
 	}
 
-	r := args.N
+	r := args.First()
 
 	var v int64
-	if s.Name == "Sizeof" {
-		typecheck(&r, Erv)
-		defaultlit(&r, nil)
+	switch s.Name {
+	case "Alignof", "Sizeof":
+		r = typecheck(r, Erv)
+		r = defaultlit(r, nil)
 		tr := r.Type
 		if tr == nil {
 			goto bad
 		}
 		dowidth(tr)
-		v = tr.Width
-		goto yes
-	}
+		if s.Name == "Alignof" {
+			v = int64(tr.Align)
+		} else {
+			v = tr.Width
+		}
 
-	if s.Name == "Offsetof" {
+	case "Offsetof":
 		// must be a selector.
 		if r.Op != OXDOT {
 			goto bad
@@ -55,89 +52,58 @@ func unsafenmagic(nn *Node) *Node {
 		// 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)
-
+		r.Left = typecheck(r.Left, Erv)
 		base := r.Left
-		typecheck(&r, Erv)
+
+		r = 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 {
+		// Sum offsets for dots until we reach base.
+		for r1 := r; r1 != base; r1 = r1.Left {
 			switch r1.Op {
+			case ODOTPTR:
+				// For Offsetof(s.f), s may itself be a pointer,
+				// but accessing f must not otherwise involve
+				// indirection via embedded pointer types.
+				if r1.Left != base {
+					Yyerror("invalid expression %v: selector implies indirection of embedded %v", nn, r1.Left)
+					goto ret
+				}
+				fallthrough
 			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)
-				Fatalf("impossible %v node after dot insertion", Oconv(int(r1.Op), obj.FmtSharp))
+				Fatalf("impossible %#v node after dot insertion", r1.Op)
 				goto bad
 			}
 		}
 
-		v += r1.Xoffset
-		goto yes
+	default:
+		return nil
 	}
 
-	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
+	if args.Len() > 1 {
+		Yyerror("extra arguments for %v", s)
 	}
-
-	return nil
+	goto ret
 
 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:
+	// any side effects disappear; ignore init
 	var val Val
 	val.U = new(Mpint)
-	Mpmovecfix(val.U.(*Mpint), v)
+	val.U.(*Mpint).SetInt64(v)
 	n := Nod(OLITERAL, nil, nil)
 	n.Orig = nn
 	n.SetVal(val)
diff --git a/src/cmd/compile/internal/gc/util.go b/src/cmd/compile/internal/gc/util.go
index 7ed3b39..18e990a 100644
--- a/src/cmd/compile/internal/gc/util.go
+++ b/src/cmd/compile/internal/gc/util.go
@@ -1,3 +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.
+
 package gc
 
 import (
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index e008317..66eb7e9 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -6,12 +6,11 @@ package gc
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"strings"
 )
 
-var mpzero Mpint
-
 // The constant is known to runtime.
 const (
 	tmpstringbufsize = 32
@@ -25,82 +24,85 @@ func walk(fn *Node) {
 		dumplist(s, Curfn.Nbody)
 	}
 
-	lno := int(lineno)
+	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.Func.Dcl; l != nil; l = l.Next {
-		if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO {
-			typecheck(&l.N, Erv|Easgn)
+	for i, ln := range fn.Func.Dcl {
+		if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) {
+			ln = typecheck(ln, Erv|Easgn)
+			fn.Func.Dcl[i] = ln
 		}
 	}
 
 	// 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 _, ln := range fn.Func.Dcl {
+		if ln.Op == ONAME && (ln.Class == PAUTO || ln.Class == PAUTOHEAP) && ln.Name.Defn != nil && ln.Name.Defn.Op == OTYPESW && ln.Used {
+			ln.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 {
+	for _, ln := range fn.Func.Dcl {
+		if ln.Op != ONAME || (ln.Class != PAUTO && ln.Class != PAUTOHEAP) || ln.Sym.Name[0] == '&' || ln.Used {
 			continue
 		}
-		if defn := l.N.Name.Defn; defn != nil && defn.Op == OTYPESW {
+		if defn := ln.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)
+			Yyerror("%v declared and not used", ln.Sym)
 			defn.Left.Used = true // suppress repeats
 		} else {
-			lineno = l.N.Lineno
-			Yyerror("%v declared and not used", l.N.Sym)
+			lineno = ln.Lineno
+			Yyerror("%v declared and not used", ln.Sym)
 		}
 	}
 
-	lineno = int32(lno)
+	lineno = lno
 	if nerrors != 0 {
 		return
 	}
-	walkstmtlist(Curfn.Nbody)
+	walkstmtlist(Curfn.Nbody.Slice())
 	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 {
+	if Debug['W'] != 0 && Curfn.Func.Enter.Len() > 0 {
 		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 walkstmtlist(s []*Node) {
+	for i := range s {
+		s[i] = walkstmt(s[i])
 	}
 }
 
-func samelist(a *NodeList, b *NodeList) bool {
-	for ; a != nil && b != nil; a, b = a.Next, b.Next {
-		if a.N != b.N {
+func samelist(a, b []*Node) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i, n := range a {
+		if n != b[i] {
 			return false
 		}
 	}
-	return a == b
+	return true
 }
 
 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
+	for _, ln := range fn.Func.Dcl {
+		switch ln.Class {
+		case PPARAMOUT:
+			if ln.isParamStackCopy() || ln.Addrtaken {
+				return true
+			}
 
+		case PAUTO:
 			// stop early - parameters are over
-		case PAUTO,
-			PAUTO | PHEAP:
 			return false
 		}
 	}
@@ -115,8 +117,7 @@ func adjustargs(n *Node, adjust int) {
 	var lhs *Node
 
 	callfunc := n.Left
-	for args := callfunc.List; args != nil; args = args.Next {
-		arg = args.N
+	for _, arg = range callfunc.List.Slice() {
 		if arg.Op != OAS {
 			Yyerror("call arg not assignment")
 		}
@@ -138,25 +139,26 @@ func adjustargs(n *Node, adjust int) {
 	}
 }
 
-func walkstmt(np **Node) {
-	n := *np
+// The result of walkstmt MUST be assigned back to n, e.g.
+// 	n.Left = walkstmt(n.Left)
+func walkstmt(n *Node) *Node {
 	if n == nil {
-		return
+		return n
 	}
 	if n.Dodata == 2 { // don't walk, generated by anylit.
-		return
+		return n
 	}
 
 	setlineno(n)
 
-	walkstmtlist(n.Ninit)
+	walkstmtlist(n.Ninit.Slice())
 
 	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))
+			Yyerror("%v is not a top level statement", n.Op)
 		}
 		Dump("nottop", n)
 
@@ -182,13 +184,14 @@ func walkstmt(np **Node) {
 		ORECOVER,
 		OGETG:
 		if n.Typecheck == 0 {
-			Fatalf("missing typecheck: %v", Nconv(n, obj.FmtSign))
+			Fatalf("missing typecheck: %v", Nconv(n, FmtSign))
 		}
+		wascopy := n.Op == OCOPY
 		init := n.Ninit
-		n.Ninit = nil
-		walkexpr(&n, &init)
-		addinit(&n, init)
-		if (*np).Op == OCOPY && n.Op == OCONVNOP {
+		n.Ninit.Set(nil)
+		n = walkexpr(n, &init)
+		n = addinit(n, init.Slice())
+		if wascopy && n.Op == OCONVNOP {
 			n.Op = OEMPTY // don't leave plain values as statements.
 		}
 
@@ -196,19 +199,18 @@ func walkstmt(np **Node) {
 	// the value received.
 	case ORECV:
 		if n.Typecheck == 0 {
-			Fatalf("missing typecheck: %v", Nconv(n, obj.FmtSign))
+			Fatalf("missing typecheck: %v", Nconv(n, FmtSign))
 		}
 		init := n.Ninit
-		n.Ninit = nil
+		n.Ninit.Set(nil)
 
-		walkexpr(&n.Left, &init)
+		n.Left = walkexpr(n.Left, &init)
 		n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
-		walkexpr(&n, &init)
+		n = walkexpr(n, &init)
 
-		addinit(&n, init)
+		n = addinit(n, init.Slice())
 
 	case OBREAK,
-		ODCL,
 		OCONTINUE,
 		OFALL,
 		OGOTO,
@@ -220,8 +222,23 @@ func walkstmt(np **Node) {
 		OVARLIVE:
 		break
 
+	case ODCL:
+		v := n.Left
+		if v.Class == PAUTOHEAP {
+			if compiling_runtime {
+				Yyerror("%v escapes to heap, not allowed in runtime.", v)
+			}
+			if prealloc[v] == nil {
+				prealloc[v] = callnew(v.Type)
+			}
+			nn := Nod(OAS, v.Name.Heapaddr, prealloc[v])
+			nn.Colas = true
+			nn = typecheck(nn, Etop)
+			return walkstmt(nn)
+		}
+
 	case OBLOCK:
-		walkstmtlist(n.List)
+		walkstmtlist(n.List.Slice())
 
 	case OXCASE:
 		Yyerror("case statement out of place")
@@ -229,19 +246,19 @@ func walkstmt(np **Node) {
 		fallthrough
 
 	case OCASE:
-		walkstmt(&n.Right)
+		n.Right = walkstmt(n.Right)
 
 	case ODEFER:
 		hasdefer = true
 		switch n.Left.Op {
 		case OPRINT, OPRINTN:
-			walkprintfunc(&n.Left, &n.Ninit)
+			n.Left = walkprintfunc(n.Left, &n.Ninit)
 
 		case OCOPY:
 			n.Left = copyany(n.Left, &n.Ninit, true)
 
 		default:
-			walkexpr(&n.Left, &n.Ninit)
+			n.Left = walkexpr(n.Left, &n.Ninit)
 		}
 
 		// make room for size & fn arguments.
@@ -249,83 +266,87 @@ func walkstmt(np **Node) {
 
 	case OFOR:
 		if n.Left != nil {
-			walkstmtlist(n.Left.Ninit)
+			walkstmtlist(n.Left.Ninit.Slice())
 			init := n.Left.Ninit
-			n.Left.Ninit = nil
-			walkexpr(&n.Left, &init)
-			addinit(&n.Left, init)
+			n.Left.Ninit.Set(nil)
+			n.Left = walkexpr(n.Left, &init)
+			n.Left = addinit(n.Left, init.Slice())
 		}
 
-		walkstmt(&n.Right)
-		walkstmtlist(n.Nbody)
+		n.Right = walkstmt(n.Right)
+		walkstmtlist(n.Nbody.Slice())
 
 	case OIF:
-		walkexpr(&n.Left, &n.Ninit)
-		walkstmtlist(n.Nbody)
-		walkstmtlist(n.Rlist)
+		n.Left = walkexpr(n.Left, &n.Ninit)
+		walkstmtlist(n.Nbody.Slice())
+		walkstmtlist(n.Rlist.Slice())
 
 	case OPROC:
 		switch n.Left.Op {
 		case OPRINT, OPRINTN:
-			walkprintfunc(&n.Left, &n.Ninit)
+			n.Left = walkprintfunc(n.Left, &n.Ninit)
 
 		case OCOPY:
 			n.Left = copyany(n.Left, &n.Ninit, true)
 
 		default:
-			walkexpr(&n.Left, &n.Ninit)
+			n.Left = 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 {
+		walkexprlist(n.List.Slice(), &n.Ninit)
+		if n.List.Len() == 0 {
 			break
 		}
-		if (Curfn.Type.Outnamed && count(n.List) > 1) || paramoutheap(Curfn) {
+		if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
 			// assign to the function out parameters,
 			// so that reorder3 can fix up conflicts
-			var rl *NodeList
+			var rl []*Node
 
 			var cl Class
-			for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
-				cl = ll.N.Class &^ PHEAP
-				if cl == PAUTO {
+			for _, ln := range Curfn.Func.Dcl {
+				cl = ln.Class
+				if cl == PAUTO || cl == PAUTOHEAP {
 					break
 				}
 				if cl == PPARAMOUT {
-					rl = list(rl, ll.N)
+					if ln.isParamStackCopy() {
+						ln = walkexpr(typecheck(Nod(OIND, ln.Name.Heapaddr, nil), Erv), nil)
+					}
+					rl = append(rl, ln)
 				}
 			}
 
-			if got, want := count(n.List), count(rl); got != want {
+			if got, want := n.List.Len(), len(rl); got != want {
 				// order should have rewritten multi-value function calls
 				// with explicit OAS2FUNC nodes.
 				Fatalf("expected %v return arguments, have %v", want, got)
 			}
 
-			if samelist(rl, n.List) {
+			if samelist(rl, n.List.Slice()) {
 				// special return in disguise
-				n.List = nil
+				n.List.Set(nil)
 
 				break
 			}
 
 			// move function calls out, to make reorder3's job easier.
-			walkexprlistsafe(n.List, &n.Ninit)
+			walkexprlistsafe(n.List.Slice(), &n.Ninit)
 
-			ll := ascompatee(n.Op, rl, n.List, &n.Ninit)
-			n.List = reorder3(ll)
-			for lr := n.List; lr != nil; lr = lr.Next {
-				lr.N = applywritebarrier(lr.N, &n.Ninit)
+			ll := ascompatee(n.Op, rl, n.List.Slice(), &n.Ninit)
+			n.List.Set(reorder3(ll))
+			ls := n.List.Slice()
+			for i, n := range ls {
+				ls[i] = applywritebarrier(n)
 			}
 			break
 		}
 
-		ll := ascompatte(n.Op, nil, false, Getoutarg(Curfn.Type), n.List, 1, &n.Ninit)
-		n.List = ll
+		ll := ascompatte(n.Op, nil, false, Curfn.Type.Results(), n.List.Slice(), 1, &n.Ninit)
+		n.List.Set(ll)
 
 	case ORETJMP:
 		break
@@ -345,10 +366,9 @@ func walkstmt(np **Node) {
 	}
 
 	if n.Op == ONAME {
-		Fatalf("walkstmt ended up with name: %v", Nconv(n, obj.FmtSign))
+		Fatalf("walkstmt ended up with name: %v", Nconv(n, FmtSign))
 	}
-
-	*np = n
+	return n
 }
 
 func isSmallMakeSlice(n *Node) bool {
@@ -362,7 +382,7 @@ func isSmallMakeSlice(n *Node) bool {
 	}
 	t := n.Type
 
-	return Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val().U.(*Mpint)) < (1<<16)/t.Type.Width)
+	return Smallintconst(l) && Smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < (1<<16)/t.Elem().Width)
 }
 
 // walk the whole tree of the body of an
@@ -370,31 +390,88 @@ func isSmallMakeSlice(n *Node) bool {
 // 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 walkexprlist(s []*Node, init *Nodes) {
+	for i := range s {
+		s[i] = walkexpr(s[i], init)
 	}
 }
 
-func walkexprlistsafe(l *NodeList, init **NodeList) {
-	for ; l != nil; l = l.Next {
-		l.N = safeexpr(l.N, init)
-		walkexpr(&l.N, init)
+func walkexprlistsafe(s []*Node, init *Nodes) {
+	for i, n := range s {
+		s[i] = safeexpr(n, init)
+		s[i] = walkexpr(s[i], init)
 	}
 }
 
-func walkexprlistcheap(l *NodeList, init **NodeList) {
-	for ; l != nil; l = l.Next {
-		l.N = cheapexpr(l.N, init)
-		walkexpr(&l.N, init)
+func walkexprlistcheap(s []*Node, init *Nodes) {
+	for i, n := range s {
+		s[i] = cheapexpr(n, init)
+		s[i] = walkexpr(s[i], init)
 	}
 }
 
-func walkexpr(np **Node, init **NodeList) {
-	n := *np
+// Build name of function: convI2E etc.
+// Not all names are possible
+// (e.g., we'll never generate convE2E or convE2I).
+func convFuncName(from, to *Type) string {
+	tkind := to.iet()
+	switch from.iet() {
+	case 'I':
+		switch tkind {
+		case 'E':
+			return "convI2E"
+		case 'I':
+			return "convI2I"
+		}
+	case 'T':
+		switch tkind {
+		case 'E':
+			return "convT2E"
+		case 'I':
+			return "convT2I"
+		}
+	}
+	Fatalf("unknown conv func %c2%c", from.iet(), to.iet())
+	panic("unreachable")
+}
 
+// Build name of function: assertI2E etc.
+// If with2suffix is true, the form ending in "2" is returned".
+func assertFuncName(from, to *Type, with2suffix bool) string {
+	l := len("assertX2X2")
+	if !with2suffix {
+		l--
+	}
+	tkind := to.iet()
+	switch from.iet() {
+	case 'E':
+		switch tkind {
+		case 'I':
+			return "assertE2I2"[:l]
+		case 'E':
+			return "assertE2E2"[:l]
+		case 'T':
+			return "assertE2T2"[:l]
+		}
+	case 'I':
+		switch tkind {
+		case 'I':
+			return "assertI2I2"[:l]
+		case 'E':
+			return "assertI2E2"[:l]
+		case 'T':
+			return "assertI2T2"[:l]
+		}
+	}
+	Fatalf("unknown assert func %c2%c", from.iet(), to.iet())
+	panic("unreachable")
+}
+
+// The result of walkexpr MUST be assigned back to n, e.g.
+// 	n.Left = walkexpr(n.Left, init)
+func walkexpr(n *Node, init *Nodes) *Node {
 	if n == nil {
-		return
+		return n
 	}
 
 	if init == &n.Ninit {
@@ -404,17 +481,16 @@ func walkexpr(np **Node, init **NodeList) {
 		Fatalf("walkexpr init == &n->ninit")
 	}
 
-	if n.Ninit != nil {
-		walkstmtlist(n.Ninit)
-		*init = concat(*init, n.Ninit)
-		n.Ninit = nil
+	if n.Ninit.Len() != 0 {
+		walkstmtlist(n.Ninit.Slice())
+		init.AppendNodes(&n.Ninit)
 	}
 
 	// annoying case - not typechecked
 	if n.Op == OKEY {
-		walkexpr(&n.Left, init)
-		walkexpr(&n.Right, init)
-		return
+		n.Left = walkexpr(n.Left, init)
+		n.Right = walkexpr(n.Right, init)
+		return n
 	}
 
 	lno := setlineno(n)
@@ -424,20 +500,25 @@ func walkexpr(np **Node, init **NodeList) {
 	}
 
 	if n.Typecheck != 1 {
-		Fatalf("missed typecheck: %v\n", Nconv(n, obj.FmtSign))
+		Fatalf("missed typecheck: %v\n", Nconv(n, FmtSign))
+	}
+
+	if n.Op == ONAME && n.Class == PAUTOHEAP {
+		nn := Nod(OIND, n.Name.Heapaddr, nil)
+		nn = typecheck(nn, Erv)
+		return walkexpr(nn, init)
 	}
 
 opswitch:
 	switch n.Op {
 	default:
 		Dump("walk", n)
-		Fatalf("walkexpr: switch 1 unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
+		Fatalf("walkexpr: switch 1 unknown op %v", Nconv(n, FmtShort|FmtSign))
 
 	case OTYPE,
 		ONONAME,
 		OINDREG,
 		OEMPTY,
-		OPARAM,
 		OGETG:
 
 	case ONOT,
@@ -448,52 +529,52 @@ opswitch:
 		OIMAG,
 		ODOTMETH,
 		ODOTINTER:
-		walkexpr(&n.Left, init)
+		n.Left = walkexpr(n.Left, init)
 
 	case OIND:
-		walkexpr(&n.Left, init)
+		n.Left = walkexpr(n.Left, init)
 
 	case ODOT:
 		usefield(n)
-		walkexpr(&n.Left, init)
+		n.Left = walkexpr(n.Left, init)
 
 	case ODOTPTR:
 		usefield(n)
-		if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
+		if n.Op == ODOTPTR && n.Left.Type.Elem().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)
+		n.Left = walkexpr(n.Left, init)
 
 	case OEFACE:
-		walkexpr(&n.Left, init)
-		walkexpr(&n.Right, init)
+		n.Left = walkexpr(n.Left, init)
+		n.Right = walkexpr(n.Right, init)
 
 	case OSPTR, OITAB:
-		walkexpr(&n.Left, init)
+		n.Left = walkexpr(n.Left, init)
 
 	case OLEN, OCAP:
-		walkexpr(&n.Left, init)
+		n.Left = 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 t.IsPtr() {
+			t = t.Elem()
 		}
-		if Isfixedarray(t) {
+		if t.IsArray() {
 			safeexpr(n.Left, init)
-			Nodconst(n, n.Type, t.Bound)
+			Nodconst(n, n.Type, t.NumElem())
 			n.Typecheck = 1
 		}
 
 	case OLSH, ORSH:
-		walkexpr(&n.Left, init)
-		walkexpr(&n.Right, init)
+		n.Left = walkexpr(n.Left, init)
+		n.Right = 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) {
@@ -512,21 +593,21 @@ opswitch:
 		OCOMPLEX,
 		OLROT:
 		if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
-			n.Left = n.List.N
-			n.Right = n.List.Next.N
+			n.Left = n.List.First()
+			n.Right = n.List.Second()
 		}
 
-		walkexpr(&n.Left, init)
-		walkexpr(&n.Right, init)
+		n.Left = walkexpr(n.Left, init)
+		n.Right = walkexpr(n.Right, init)
 
 	case OOR, OXOR:
-		walkexpr(&n.Left, init)
-		walkexpr(&n.Right, init)
-		walkrotate(&n)
+		n.Left = walkexpr(n.Left, init)
+		n.Right = walkexpr(n.Right, init)
+		n = walkrotate(n)
 
 	case OEQ, ONE:
-		walkexpr(&n.Left, init)
-		walkexpr(&n.Right, init)
+		n.Left = walkexpr(n.Left, init)
+		n.Right = walkexpr(n.Right, init)
 
 		// Disable safemode while compiling this code: the code we
 		// generate internally can refer to unsafe.Pointer.
@@ -534,24 +615,23 @@ opswitch:
 		// 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 = false
+		n = walkcompare(n, init)
 		safemode = old_safemode
 
 	case OANDAND, OOROR:
-		walkexpr(&n.Left, init)
+		n.Left = 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
+		var ll Nodes
 
-		walkexpr(&n.Right, &ll)
-		addinit(&n.Right, ll)
+		n.Right = walkexpr(n.Right, &ll)
+		n.Right = addinit(n.Right, ll.Slice())
 
 	case OPRINT, OPRINTN:
-		walkexprlist(n.List, init)
+		walkexprlist(n.List.Slice(), init)
 		n = walkprint(n, init)
 
 	case OPANIC:
@@ -567,19 +647,18 @@ opswitch:
 		n.Addable = true
 
 	case ONAME:
-		if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
-			n.Addable = true
-		}
+		n.Addable = true
 
 	case OCALLINTER:
+		usemethod(n)
 		t := n.Left.Type
-		if n.List != nil && n.List.N.Op == OAS {
+		if n.List.Len() != 0 && n.List.First().Op == OAS {
 			break
 		}
-		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)
+		n.Left = walkexpr(n.Left, init)
+		walkexprlist(n.List.Slice(), init)
+		ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
+		n.List.Set(reorder1(ll))
 
 	case OCALLFUNC:
 		if n.Left.Op == OCLOSURE {
@@ -587,66 +666,60 @@ opswitch:
 			// transformclosure already did all preparation work.
 
 			// Prepend captured variables to argument list.
-			n.List = concat(n.Left.Func.Enter, n.List)
+			n.List.Set(append(n.Left.Func.Enter.Slice(), n.List.Slice()...))
 
-			n.Left.Func.Enter = nil
+			n.Left.Func.Enter.Set(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
+			if n.Left.Type.Results().NumFields() == 1 {
+				n.Type = n.Left.Type.Results().Field(0).Type
 			} else {
-				n.Type = getoutargx(n.Left.Type)
+				n.Type = n.Left.Type.Results()
 			}
 		}
 
 		t := n.Left.Type
-		if n.List != nil && n.List.N.Op == OAS {
+		if n.List.Len() != 0 && n.List.First().Op == OAS {
 			break
 		}
 
-		walkexpr(&n.Left, init)
-		walkexprlist(n.List, init)
+		n.Left = walkexpr(n.Left, init)
+		walkexprlist(n.List.Slice(), init)
 
 		if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
-			switch Thearch.Thechar {
-			case '5', '6', '7':
+			if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
 				n.Op = OSQRT
-				n.Left = n.List.N
-				n.List = nil
+				n.Left = n.List.First()
+				n.List.Set(nil)
 				break opswitch
 			}
 		}
 
-		ll := ascompatte(n.Op, n, n.Isddd, getinarg(t), n.List, 0, init)
-		n.List = reorder1(ll)
+		ll := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
+		n.List.Set(reorder1(ll))
 
 	case OCALLMETH:
 		t := n.Left.Type
-		if n.List != nil && n.List.N.Op == OAS {
+		if n.List.Len() != 0 && n.List.First().Op == OAS {
 			break
 		}
-		walkexpr(&n.Left, init)
-		walkexprlist(n.List, init)
-		ll := ascompatte(n.Op, n, false, 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 = walkexpr(n.Left, init)
+		walkexprlist(n.List.Slice(), init)
+		ll := ascompatte(n.Op, n, false, t.Recvs(), []*Node{n.Left.Left}, 0, init)
+		lr := ascompatte(n.Op, n, n.Isddd, t.Params(), n.List.Slice(), 0, init)
+		ll = append(ll, lr...)
 		n.Left.Left = nil
 		ullmancalc(n.Left)
-		n.List = reorder1(ll)
+		n.List.Set(reorder1(ll))
 
 	case OAS:
-		*init = concat(*init, n.Ninit)
-		n.Ninit = nil
+		init.AppendNodes(&n.Ninit)
 
-		walkexpr(&n.Left, init)
+		n.Left = walkexpr(n.Left, init)
 		n.Left = safeexpr(n.Left, init)
 
 		if oaslit(n, init) {
@@ -659,7 +732,7 @@ opswitch:
 
 		switch n.Right.Op {
 		default:
-			walkexpr(&n.Right, init)
+			n.Right = walkexpr(n.Right, init)
 
 		case ODOTTYPE:
 			// TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
@@ -667,13 +740,13 @@ opswitch:
 			// That would allow inlining x.(struct{*int}) the same as x.(*int).
 			if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && !instrumenting {
 				// handled directly during cgen
-				walkexpr(&n.Right, init)
+				n.Right = 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)
+			n.Right.Left = walkexpr(n.Right.Left, init)
 
 			n1 := Nod(OADDR, n.Left, nil)
 			r := n.Right // i.(T)
@@ -682,23 +755,22 @@ opswitch:
 				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)
+			fn := syslook(assertFuncName(r.Left.Type, r.Type, false))
+			fn = substArgTypes(fn, r.Left.Type, r.Type)
 
 			n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
-			walkexpr(&n, init)
+			n = walkexpr(n, init)
 			break opswitch
 
 		case ORECV:
 			// x = <-c; n.Left is x, n.Right.Left is c.
 			// orderstmt made sure x is addressable.
-			walkexpr(&n.Right.Left, init)
+			n.Right.Left = 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)
+			n = walkexpr(n, init)
 			break opswitch
 
 		case OAPPEND:
@@ -720,73 +792,69 @@ opswitch:
 		}
 
 		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)
+			dd := n.Dodata
+			n = convas(n, init)
+			n.Dodata = dd
+			n = applywritebarrier(n)
 		}
 
 	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)
+		init.AppendNodes(&n.Ninit)
+		walkexprlistsafe(n.List.Slice(), init)
+		walkexprlistsafe(n.Rlist.Slice(), init)
+		ll := ascompatee(OAS, n.List.Slice(), n.Rlist.Slice(), init)
 		ll = reorder3(ll)
-		for lr := ll; lr != nil; lr = lr.Next {
-			lr.N = applywritebarrier(lr.N, init)
+		for i, n := range ll {
+			ll[i] = applywritebarrier(n)
 		}
 		n = liststmt(ll)
 
 		// a,b,... = fn()
 	case OAS2FUNC:
-		*init = concat(*init, n.Ninit)
+		init.AppendNodes(&n.Ninit)
 
-		n.Ninit = nil
-		r := n.Rlist.N
-		walkexprlistsafe(n.List, init)
-		walkexpr(&r, init)
+		r := n.Rlist.First()
+		walkexprlistsafe(n.List.Slice(), init)
+		r = 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)
+		ll := ascompatet(n.Op, n.List, r.Type, 0, init)
+		for i, n := range ll {
+			ll[i] = applywritebarrier(n)
 		}
-		n = liststmt(concat(list1(r), ll))
+		n = liststmt(append([]*Node{r}, ll...))
 
 		// x, y = <-c
 	// orderstmt made sure x is addressable.
 	case OAS2RECV:
-		*init = concat(*init, n.Ninit)
+		init.AppendNodes(&n.Ninit)
 
-		n.Ninit = nil
-		r := n.Rlist.N
-		walkexprlistsafe(n.List, init)
-		walkexpr(&r.Left, init)
+		r := n.Rlist.First()
+		walkexprlistsafe(n.List.Slice(), init)
+		r.Left = walkexpr(r.Left, init)
 		var n1 *Node
-		if isblank(n.List.N) {
+		if isblank(n.List.First()) {
 			n1 = nodnil()
 		} else {
-			n1 = Nod(OADDR, n.List.N, nil)
+			n1 = Nod(OADDR, n.List.First(), 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)
+		r = mkcall1(fn, n.List.Second().Type, init, typename(r.Left.Type), r.Left, n1)
+		n = Nod(OAS, n.List.Second(), r)
+		n = typecheck(n, Etop)
 
 		// a,b = m[i];
 	case OAS2MAPR:
-		*init = concat(*init, n.Ninit)
+		init.AppendNodes(&n.Ninit)
 
-		n.Ninit = nil
-		r := n.Rlist.N
-		walkexprlistsafe(n.List, init)
-		walkexpr(&r.Left, init)
-		walkexpr(&r.Right, init)
+		r := n.Rlist.First()
+		walkexprlistsafe(n.List.Slice(), init)
+		r.Left = walkexpr(r.Left, init)
+		r.Right = walkexpr(r.Right, init)
 		t := r.Left.Type
 		p := ""
-		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
-			switch algtype(t.Down) {
+		if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
+			switch algtype(t.Key()) {
 			case AMEM32:
 				p = "mapaccess2_fast32"
 			case AMEM64:
@@ -813,42 +881,46 @@ opswitch:
 		// to:
 		//   var,b = mapaccess2*(t, m, i)
 		//   a = *var
-		a := n.List.N
+		a := n.List.First()
 
-		fn := mapfn(p, t)
-		r = mkcall1(fn, getoutargx(fn.Type), init, typename(t), r.Left, key)
+		if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
+			fn := mapfn(p, t)
+			r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key)
+		} else {
+			fn := mapfn("mapaccess2_fat", t)
+			z := zeroaddr(w)
+			r = mkcall1(fn, fn.Type.Results(), init, typename(t), r.Left, key, z)
+		}
 
 		// 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
+		if !isblank(n.List.Second()) {
+			r.Type.Field(1).Type = n.List.Second().Type
 		}
-		n.Rlist = list1(r)
+		n.Rlist.Set1(r)
 		n.Op = OAS2FUNC
 
 		// don't generate a = *var if a is _
 		if !isblank(a) {
-			var_ := temp(Ptrto(t.Type))
+			var_ := temp(Ptrto(t.Val()))
 			var_.Typecheck = 1
-			n.List.N = var_
-			walkexpr(&n, init)
-			*init = list(*init, n)
+			var_.NonNil = true // mapaccess always returns a non-nil pointer
+			n.List.SetIndex(0, var_)
+			n = walkexpr(n, init)
+			init.Append(n)
 			n = Nod(OAS, a, Nod(OIND, var_, nil))
 		}
 
-		typecheck(&n, Etop)
-		walkexpr(&n, init)
-
-		// TODO: ptr is always non-nil, so disable nil check for this OIND op.
+		n = typecheck(n, Etop)
+		n = walkexpr(n, init)
 
 	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)
+		init.AppendNodes(&n.Ninit)
+		map_ := n.List.First()
+		key := n.List.Second()
+		map_ = walkexpr(map_, init)
+		key = walkexpr(key, init)
 
 		// orderstmt made sure key is addressable.
 		key = Nod(OADDR, key, nil)
@@ -857,49 +929,48 @@ opswitch:
 		n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
 
 	case OAS2DOTTYPE:
-		e := n.Rlist.N // i.(T)
+		e := n.Rlist.First() // 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) && !instrumenting {
 			// handled directly during gen.
-			walkexprlistsafe(n.List, init)
-			walkexpr(&e.Left, init)
+			walkexprlistsafe(n.List.Slice(), init)
+			e.Left = walkexpr(e.Left, init)
 			break
 		}
 
 		// res, ok = i.(T)
 		// orderstmt made sure a is addressable.
-		*init = concat(*init, n.Ninit)
-		n.Ninit = nil
+		init.AppendNodes(&n.Ninit)
 
-		walkexprlistsafe(n.List, init)
-		walkexpr(&e.Left, init)
+		walkexprlistsafe(n.List.Slice(), init)
+		e.Left = walkexpr(e.Left, init)
 		t := e.Type    // T
 		from := e.Left // i
 
 		oktype := Types[TBOOL]
-		ok := n.List.Next.N
+		ok := n.List.Second()
 		if !isblank(ok) {
 			oktype = ok.Type
 		}
 
-		fromKind := type2IET(from.Type)
-		toKind := type2IET(t)
+		fromKind := from.Type.iet()
+		toKind := t.iet()
 
 		// 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) {
+		if isblank(n.List.First()) {
 			var fast *Node
 			switch {
-			case fromKind == "E" && toKind == "T":
+			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":
+			case fromKind == 'I' && toKind == 'E',
+				fromKind == 'E' && toKind == 'E':
 				tab := Nod(OITAB, from, nil)
 				fast = Nod(ONE, nodnil(), tab)
 			}
@@ -908,115 +979,67 @@ opswitch:
 					Warn("type assertion (ok only) inlined")
 				}
 				n = Nod(OAS, ok, fast)
-				typecheck(&n, Etop)
+				n = typecheck(n, Etop)
 				break
 			}
 		}
 
 		var resptr *Node // &res
-		if isblank(n.List.N) {
+		if isblank(n.List.First()) {
 			resptr = nodnil()
 		} else {
-			resptr = Nod(OADDR, n.List.N, nil)
+			resptr = Nod(OADDR, n.List.First(), 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)
+		fn := syslook(assertFuncName(from.Type, t, true))
+		fn = substArgTypes(fn, from.Type, t)
 		call := mkcall1(fn, oktype, init, typename(t), from, resptr)
 		n = Nod(OAS, ok, call)
-		typecheck(&n, Etop)
+		n = typecheck(n, Etop)
 
 	case ODOTTYPE, ODOTTYPE2:
 		if !isdirectiface(n.Type) || Isfat(n.Type) {
 			Fatalf("walkexpr ODOTTYPE") // should see inside OAS only
 		}
-		walkexpr(&n.Left, init)
+		n.Left = walkexpr(n.Left, init)
 
 	case OCONVIFACE:
-		walkexpr(&n.Left, init)
+		n.Left = 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)
+		// Optimize convT2E or convT2I as a two-word copy when T is pointer-shaped.
+		if isdirectiface(n.Left.Type) {
+			var t *Node
+			if n.Type.IsEmptyInterface() {
+				t = typename(n.Left.Type)
+			} else {
+				t = itabname(n.Left.Type, n.Type)
+			}
+			l := Nod(OEFACE, t, n.Left)
 			l.Type = n.Type
 			l.Typecheck = n.Typecheck
 			n = l
 			break
 		}
 
-		// 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
-				break
+		var ll []*Node
+		if n.Type.IsEmptyInterface() {
+			if !n.Left.Type.IsInterface() {
+				ll = append(ll, typename(n.Left.Type))
+			}
+		} else {
+			if n.Left.Type.IsInterface() {
+				ll = append(ll, typename(n.Type))
+			} else {
+				ll = append(ll, itabname(n.Left.Type, n.Type))
 			}
 		}
 
-		if Isinter(n.Left.Type) {
-			ll = list(ll, n.Left)
+		if n.Left.Type.IsInterface() {
+			ll = append(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
@@ -1025,9 +1048,9 @@ opswitch:
 			// 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))
+				ll = append(ll, Nod(OADDR, n.Left, nil))
 			} else {
-				ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
+				ll = append(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
 			}
 			dowidth(n.Left.Type)
 			r := nodnil()
@@ -1035,28 +1058,29 @@ opswitch:
 				// 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 = typecheck(r, Etop)
+				init.Append(r)
 				r = Nod(OADDR, r.Left, nil)
-				typecheck(&r, Erv)
+				r = typecheck(r, Erv)
 			}
-			ll = list(ll, r)
+			ll = append(ll, r)
 		}
 
-		if !Isinter(n.Left.Type) {
-			substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
+		fn := syslook(convFuncName(n.Left.Type, n.Type))
+		if !n.Left.Type.IsInterface() {
+			fn = substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
 		} else {
-			substArgTypes(fn, n.Left.Type, n.Type)
+			fn = substArgTypes(fn, n.Left.Type, n.Type)
 		}
 		dowidth(fn.Type)
 		n = Nod(OCALL, fn, nil)
-		n.List = ll
-		typecheck(&n, Erv)
-		walkexpr(&n, init)
+		n.List.Set(ll)
+		n = typecheck(n, Erv)
+		n = walkexpr(n, init)
 
 	case OCONV, OCONVNOP:
-		if Thearch.Thechar == '5' {
-			if Isfloat[n.Left.Type.Etype] {
+		if Thearch.LinkArch.Family == sys.ARM {
+			if n.Left.Type.IsFloat() {
 				if n.Type.Etype == TINT64 {
 					n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
 					break
@@ -1068,7 +1092,7 @@ opswitch:
 				}
 			}
 
-			if Isfloat[n.Type.Etype] {
+			if n.Type.IsFloat() {
 				if n.Left.Type.Etype == TINT64 {
 					n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
 					break
@@ -1081,23 +1105,23 @@ opswitch:
 			}
 		}
 
-		walkexpr(&n.Left, init)
+		n.Left = walkexpr(n.Left, init)
 
 	case OANDNOT:
-		walkexpr(&n.Left, init)
+		n.Left = walkexpr(n.Left, init)
 		n.Op = OAND
 		n.Right = Nod(OCOM, n.Right, nil)
-		typecheck(&n.Right, Erv)
-		walkexpr(&n.Right, init)
+		n.Right = typecheck(n.Right, Erv)
+		n.Right = walkexpr(n.Right, init)
 
 	case OMUL:
-		walkexpr(&n.Left, init)
-		walkexpr(&n.Right, init)
-		walkmul(&n, init)
+		n.Left = walkexpr(n.Left, init)
+		n.Right = walkexpr(n.Right, init)
+		n = walkmul(n, init)
 
 	case ODIV, OMOD:
-		walkexpr(&n.Left, init)
-		walkexpr(&n.Right, init)
+		n.Left = walkexpr(n.Left, init)
+		n.Right = walkexpr(n.Right, init)
 
 		// rewrite complex div into function call.
 		et := n.Left.Type.Etype
@@ -1115,7 +1139,7 @@ opswitch:
 		}
 
 		// Try rewriting as shifts or magic multiplies.
-		walkdiv(&n, init)
+		n = walkdiv(n, init)
 
 		// rewrite 64-bit div and mod into function calls
 		// on 32-bit architectures.
@@ -1139,13 +1163,13 @@ opswitch:
 		}
 
 	case OINDEX:
-		walkexpr(&n.Left, init)
+		n.Left = 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)
+		n.Right = walkexpr(n.Right, init)
 
 		// if range of type cannot exceed static array bound,
 		// disable bounds check.
@@ -1153,11 +1177,11 @@ opswitch:
 			break
 		}
 		t := n.Left.Type
-		if t != nil && Isptr[t.Etype] {
-			t = t.Type
+		if t != nil && t.IsPtr() {
+			t = t.Elem()
 		}
-		if Isfixedarray(t) {
-			n.Bounded = bounded(r, t.Bound)
+		if t.IsArray() {
+			n.Bounded = bounded(r, t.NumElem())
 			if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
 				Warn("index bounds check elided")
 			}
@@ -1176,7 +1200,7 @@ opswitch:
 					// replace "abc"[1] with 'b'.
 					// delayed until now because "abc"[1] is not
 					// an ideal constant.
-					v := Mpgetfix(n.Right.Val().U.(*Mpint))
+					v := n.Right.Int64()
 
 					Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
 					n.Typecheck = 1
@@ -1185,7 +1209,7 @@ opswitch:
 		}
 
 		if Isconst(n.Right, CTINT) {
-			if Mpcmpfixfix(n.Right.Val().U.(*Mpint), &mpzero) < 0 || Mpcmpfixfix(n.Right.Val().U.(*Mpint), Maxintval[TINT]) > 0 {
+			if n.Right.Val().U.(*Mpint).CmpInt64(0) < 0 || n.Right.Val().U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
 				Yyerror("index out of bounds")
 			}
 		}
@@ -1194,13 +1218,13 @@ opswitch:
 		if n.Etype == 1 {
 			break
 		}
-		walkexpr(&n.Left, init)
-		walkexpr(&n.Right, init)
+		n.Left = walkexpr(n.Left, init)
+		n.Right = walkexpr(n.Right, init)
 
 		t := n.Left.Type
 		p := ""
-		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
-			switch algtype(t.Down) {
+		if t.Val().Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
+			switch algtype(t.Key()) {
 			case AMEM32:
 				p = "mapaccess1_fast32"
 			case AMEM64:
@@ -1218,67 +1242,66 @@ opswitch:
 			// 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)
+		if w := t.Val().Width; w <= 1024 { // 1024 must match ../../../../runtime/hashmap.go:maxZero
+			n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key)
+		} else {
+			p = "mapaccess1_fat"
+			z := zeroaddr(w)
+			n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key, z)
+		}
+		n.NonNil = true // mapaccess always returns a non-nil pointer
 		n = Nod(OIND, n, nil)
-		n.Type = t.Type
+		n.Type = t.Val()
 		n.Typecheck = 1
 
 	case ORECV:
 		Fatalf("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)
-
-	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
+	case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
+		n.Left = walkexpr(n.Left, init)
+		low, high, max := n.SliceBounds()
+		low = walkexpr(low, init)
+		if low != nil && iszero(low) {
+			// Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k].
+			low = nil
+		}
+		high = walkexpr(high, init)
+		max = walkexpr(max, init)
+		n.SetSliceBounds(low, high, max)
+		if n.Op.IsSlice3() {
+			if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) {
+				// Reduce x[i:j:cap(x)] to x[i:j].
+				if n.Op == OSLICE3 {
+					n.Op = OSLICE
+				} else {
+					n.Op = OSLICEARR
+				}
+				n = reduceSlice(n)
 			}
+		} else {
 			n = reduceSlice(n)
 		}
 
 	case OADDR:
-		walkexpr(&n.Left, init)
+		n.Left = walkexpr(n.Left, init)
 
 	case ONEW:
 		if n.Esc == EscNone {
-			if n.Type.Type.Width >= 1<<16 {
+			if n.Type.Elem().Width >= 1<<16 {
 				Fatalf("large ONEW with EscNone: %v", n)
 			}
-			r := temp(n.Type.Type)
+			r := temp(n.Type.Elem())
 			r = Nod(OAS, r, nil) // zero temp
-			typecheck(&r, Etop)
-			*init = list(*init, r)
+			r = typecheck(r, Etop)
+			init.Append(r)
 			r = Nod(OADDR, r.Left, nil)
-			typecheck(&r, Erv)
+			r = typecheck(r, Erv)
 			n = r
 		} else {
-			n = callnew(n.Type.Type)
+			n = callnew(n.Type.Elem())
 		}
 
 		// If one argument to the comparison is an empty string,
@@ -1288,19 +1311,19 @@ opswitch:
 		if (Isconst(n.Left, CTSTR) && len(n.Left.Val().U.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val().U.(string)) == 0) {
 			// TODO(marvin): Fix Node.EType type union.
 			r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
-			typecheck(&r, Erv)
-			walkexpr(&r, init)
+			r = typecheck(r, Erv)
+			r = walkexpr(r, init)
 			r.Type = n.Type
 			n = r
 			break
 		}
 
 		// s + "badgerbadgerbadger" == "badgerbadgerbadger"
-		if (Op(n.Etype) == OEQ || Op(n.Etype) == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && count(n.Left.List) == 2 && Isconst(n.Left.List.Next.N, CTSTR) && strlit(n.Right) == strlit(n.Left.List.Next.N) {
+		if (Op(n.Etype) == OEQ || Op(n.Etype) == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && n.Left.List.Len() == 2 && Isconst(n.Left.List.Second(), CTSTR) && strlit(n.Right) == strlit(n.Left.List.Second()) {
 			// TODO(marvin): Fix Node.EType type union.
-			r := Nod(Op(n.Etype), Nod(OLEN, n.Left.List.N, nil), Nodintconst(0))
-			typecheck(&r, Erv)
-			walkexpr(&r, init)
+			r := Nod(Op(n.Etype), Nod(OLEN, n.Left.List.First(), nil), Nodintconst(0))
+			r = typecheck(r, Erv)
+			r = walkexpr(r, init)
 			r.Type = n.Type
 			n = r
 			break
@@ -1329,8 +1352,8 @@ opswitch:
 				r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
 			}
 
-			typecheck(&r, Erv)
-			walkexpr(&r, nil)
+			r = typecheck(r, Erv)
+			r = 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]))
@@ -1339,8 +1362,8 @@ opswitch:
 			r = Nod(Op(n.Etype), r, Nodintconst(0))
 		}
 
-		typecheck(&r, Erv)
-		if n.Type.Etype != TBOOL {
+		r = typecheck(r, Erv)
+		if !n.Type.IsBoolean() {
 			Fatalf("cmp %v", n.Type)
 		}
 		r.Type = n.Type
@@ -1358,9 +1381,9 @@ opswitch:
 
 		// cannot use chanfn - closechan takes any, not chan any
 	case OCLOSE:
-		fn := syslook("closechan", 1)
+		fn := syslook("closechan")
 
-		substArgTypes(fn, n.Left.Type)
+		fn = substArgTypes(fn, n.Left.Type)
 		n = mkcall1(fn, nil, init, n.Left)
 
 	case OMAKECHAN:
@@ -1369,8 +1392,6 @@ opswitch:
 	case OMAKEMAP:
 		t := n.Type
 
-		fn := syslook("makemap", 1)
-
 		a := nodnil() // hmap buffer
 		r := nodnil() // bucket buffer
 		if n.Esc == EscNone {
@@ -1378,8 +1399,8 @@ opswitch:
 			var_ := temp(hmap(t))
 
 			a = Nod(OAS, var_, nil) // zero temp
-			typecheck(&a, Etop)
-			*init = list(*init, a)
+			a = typecheck(a, Etop)
+			init.Append(a)
 			a = Nod(OADDR, var_, nil)
 
 			// Allocate one bucket on stack.
@@ -1388,12 +1409,13 @@ opswitch:
 			var_ = temp(mapbucket(t))
 
 			r = Nod(OAS, var_, nil) // zero temp
-			typecheck(&r, Etop)
-			*init = list(*init, r)
+			r = typecheck(r, Etop)
+			init.Append(r)
 			r = Nod(OADDR, var_, nil)
 		}
 
-		substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type)
+		fn := syslook("makemap")
+		fn = substArgTypes(fn, hmap(t), mapbucket(t), t.Key(), t.Val())
 		n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
 
 	case OMAKESLICE:
@@ -1410,22 +1432,23 @@ opswitch:
 			}
 			// var arr [r]T
 			// n = arr[:l]
-			t = aindex(r, t.Type) // [r]T
+			t = aindex(r, t.Elem()) // [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)
+			a = typecheck(a, Etop)
+			init.Append(a)
+			r := Nod(OSLICE, var_, nil) // arr[:l]
+			r.SetSliceBounds(nil, l, nil)
+			r = conv(r, n.Type) // in case n.Type is named.
+			r = typecheck(r, Erv)
+			r = walkexpr(r, init)
 			n = r
 		} else {
-			// makeslice(t *Type, nel int64, max int64) (ary []any)
-			fn := syslook("makeslice", 1)
+			// makeslice(et *Type, nel int64, max int64) (ary []any)
+			fn := syslook("makeslice")
 
-			substArgTypes(fn, t.Type) // any-1
-			n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
+			fn = substArgTypes(fn, t.Elem()) // any-1
+			n = mkcall1(fn, n.Type, init, typename(t.Elem()), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
 		}
 
 	case ORUNESTR:
@@ -1501,18 +1524,18 @@ opswitch:
 		// ifaceeq(i1 any-1, i2 any-2) (ret bool);
 	case OCMPIFACE:
 		if !Eqtype(n.Left.Type, n.Right.Type) {
-			Fatalf("ifaceeq %v %v %v", Oconv(int(n.Op), 0), n.Left.Type, n.Right.Type)
+			Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type)
 		}
 		var fn *Node
-		if isnilinter(n.Left.Type) {
-			fn = syslook("efaceeq", 1)
+		if n.Left.Type.IsEmptyInterface() {
+			fn = syslook("efaceeq")
 		} else {
-			fn = syslook("ifaceeq", 1)
+			fn = syslook("ifaceeq")
 		}
 
 		n.Right = cheapexpr(n.Right, init)
 		n.Left = cheapexpr(n.Left, init)
-		substArgTypes(fn, n.Right.Type, n.Left.Type)
+		fn = substArgTypes(fn, n.Right.Type, n.Left.Type)
 		r := mkcall1(fn, n.Type, init, n.Left, n.Right)
 		// TODO(marvin): Fix Node.EType type union.
 		if Op(n.Etype) == ONE {
@@ -1526,20 +1549,33 @@ opswitch:
 		} else {
 			r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
 		}
-		typecheck(&r, Erv)
-		walkexpr(&r, init)
+		r = typecheck(r, Erv)
+		r = walkexpr(r, init)
 		r.Type = n.Type
 		n = r
 
 	case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
+		if isStaticCompositeLiteral(n) {
+			// n can be directly represented in the read-only data section.
+			// Make direct reference to the static data. See issue 12841.
+			vstat := staticname(n.Type, 0)
+			if n.Op == OSTRUCTLIT {
+				structlit(0, 1, n, vstat, init)
+			} else {
+				arraylit(0, 1, n, vstat, init)
+			}
+			n = vstat
+			n = typecheck(n, Erv)
+			break
+		}
 		var_ := temp(n.Type)
 		anylit(0, n, var_, init)
 		n = var_
 
 	case OSEND:
 		n1 := n.Right
-		n1 = assignconv(n1, n.Left.Type.Type, "chan send")
-		walkexpr(&n1, init)
+		n1 = assignconv(n1, n.Left.Type.Elem(), "chan send")
+		n1 = 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)
 
@@ -1560,7 +1596,7 @@ opswitch:
 	evconst(n)
 	n.Type = t
 	if n.Op == OLITERAL {
-		typecheck(&n, Erv)
+		n = typecheck(n, Erv)
 	}
 
 	ullmancalc(n)
@@ -1570,16 +1606,18 @@ opswitch:
 	}
 
 	lineno = lno
-	*np = n
+	return n
 }
 
+// TODO(josharian): combine this with its caller and simplify
 func reduceSlice(n *Node) *Node {
-	r := n.Right.Right
-	if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
+	low, high, max := n.SliceBounds()
+	if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) {
 		// Reduce x[i:len(x)] to x[i:].
-		n.Right.Right = nil
+		high = nil
 	}
-	if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
+	n.SetSliceBounds(low, high, max)
+	if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil {
 		// Reduce x[:] to x.
 		if Debug_slice > 0 {
 			Warn("slice: omit slice operation")
@@ -1589,7 +1627,7 @@ func reduceSlice(n *Node) *Node {
 	return n
 }
 
-func ascompatee1(op Op, l *Node, r *Node, init **NodeList) *Node {
+func ascompatee1(op Op, l *Node, r *Node, init *Nodes) *Node {
 	// convas will turn map assigns into function calls,
 	// making it impossible for reorder3 to work.
 	n := Nod(OAS, l, r)
@@ -1601,33 +1639,38 @@ func ascompatee1(op Op, l *Node, r *Node, init **NodeList) *Node {
 	return convas(n, init)
 }
 
-func ascompatee(op Op, nl *NodeList, nr *NodeList, init **NodeList) *NodeList {
+func ascompatee(op Op, nl, nr []*Node, init *Nodes) []*Node {
 	// 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 i := range nl {
+		nl[i] = safeexpr(nl[i], init)
 	}
-	for lr := nr; lr != nil; lr = lr.Next {
-		lr.N = safeexpr(lr.N, init)
+	for i1 := range nr {
+		nr[i1] = safeexpr(nr[i1], init)
 	}
 
-	var nn *NodeList
-	ll := nl
-	lr := nr
-	for ; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
+	var nn []*Node
+	i := 0
+	for ; i < len(nl); i++ {
+		if i >= len(nr) {
+			break
+		}
 		// Do not generate 'x = x' during return. See issue 4014.
-		if op == ORETURN && ll.N == lr.N {
+		if op == ORETURN && samesafeexpr(nl[i], nr[i]) {
 			continue
 		}
-		nn = list(nn, ascompatee1(op, ll.N, lr.N, init))
+		nn = append(nn, ascompatee1(op, nl[i], nr[i], 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)
+	if i < len(nl) || i < len(nr) {
+		var nln, nrn Nodes
+		nln.Set(nl)
+		nrn.Set(nr)
+		Yyerror("error in shape across %v %v %v / %d %d [%s]", hconv(nln, FmtSign), op, hconv(nrn, FmtSign), len(nl), len(nr), Curfn.Func.Nname.Sym.Name)
 	}
 	return nn
 }
@@ -1650,28 +1693,22 @@ func fncall(l *Node, rt *Type) bool {
 	return true
 }
 
-func ascompatet(op Op, 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)
+// check assign type list to
+// a expression list. called in
+//	expr-list = func()
+func ascompatet(op Op, nl Nodes, nr *Type, fp int, init *Nodes) []*Node {
+	r, saver := IterFields(nr)
 
-	var nn *NodeList
-	var mm *NodeList
-	ucount := 0
-	for ll = nl; ll != nil; ll = ll.Next {
+	var nn, mm []*Node
+	var ullmanOverflow bool
+	var i int
+	for i = 0; i < nl.Len(); i++ {
 		if r == nil {
 			break
 		}
-		l = ll.N
+		l := nl.Index(i)
 		if isblank(l) {
-			r = structnext(&saver)
+			r = saver.Next()
 			continue
 		}
 
@@ -1679,49 +1716,48 @@ func ascompatet(op Op, nl *NodeList, nr **Type, fp int, init **NodeList) *NodeLi
 		// 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)
+			tmp := temp(r.Type)
+			tmp = typecheck(tmp, Erv)
+			a := Nod(OAS, l, tmp)
 			a = convas(a, init)
-			mm = list(mm, a)
+			mm = append(mm, a)
 			l = tmp
 		}
 
-		a = Nod(OAS, l, nodarg(r, fp))
+		a := Nod(OAS, l, nodarg(r, fp))
 		a = convas(a, init)
 		ullmancalc(a)
 		if a.Ullman >= UINF {
 			Dump("ascompatet ucount", a)
-			ucount++
+			ullmanOverflow = true
 		}
 
-		nn = list(nn, a)
-		r = structnext(&saver)
+		nn = append(nn, a)
+		r = saver.Next()
 	}
 
-	if ll != nil || r != nil {
-		Yyerror("ascompatet: assignment count mismatch: %d = %d", count(nl), structcount(*nr))
+	if i < nl.Len() || r != nil {
+		Yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
 	}
 
-	if ucount != 0 {
+	if ullmanOverflow {
 		Fatalf("ascompatet: too many function calls evaluating parameters")
 	}
-	return concat(nn, mm)
+	return append(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 {
+func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []*Node {
 	esc := uint16(EscUnknown)
 	if ddd != nil {
 		esc = ddd.Esc
 	}
 
-	tslice := typ(TARRAY)
-	tslice.Type = l.Type.Type
-	tslice.Bound = -1
+	tslice := typSlice(l.Type.Elem())
+	tslice.Noalg = true
 
 	var n *Node
-	if count(lr0) == 0 {
+	if len(lr0) == 0 {
 		n = nodnil()
 		n.Type = tslice
 	} else {
@@ -1729,177 +1765,156 @@ func mkdotargslice(lr0 *NodeList, nn *NodeList, l *Type, fp int, init **NodeList
 		if ddd != nil && prealloc[ddd] != nil {
 			prealloc[n] = prealloc[ddd] // temporary to use
 		}
-		n.List = lr0
+		n.List.Set(lr0)
 		n.Esc = esc
-		typecheck(&n, Erv)
+		n = typecheck(n, Erv)
 		if n.Type == nil {
 			Fatalf("mkdotargslice: typecheck failed")
 		}
-		walkexpr(&n, init)
+		n = walkexpr(n, init)
 	}
 
 	a := Nod(OAS, nodarg(l, fp), n)
-	nn = list(nn, convas(a, init))
+	nn = append(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_ += ", "
+func dumptypes(nl *Type, what string) string {
+	s := ""
+	for _, l := range nl.Fields().Slice() {
+		if s != "" {
+			s += ", "
 		}
-		fmt_ += Tconv(l, 0)
+		s += Fldconv(l, 0)
 	}
-
-	if first != 0 {
-		fmt_ += fmt.Sprintf("[no arguments %s]", what)
+	if s == "" {
+		s = fmt.Sprintf("[no arguments %s]", what)
 	}
-	return fmt_
+	return s
 }
 
-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_ += ", "
+func dumpnodetypes(l []*Node, what string) string {
+	s := ""
+	for _, r := range l {
+		if s != "" {
+			s += ", "
 		}
-		fmt_ += Tconv(r.Type, 0)
+		s += Tconv(r.Type, 0)
 	}
-
-	if first != 0 {
-		fmt_ += fmt.Sprintf("[no arguments %s]", what)
+	if s == "" {
+		s = fmt.Sprintf("[no arguments %s]", what)
 	}
-	return fmt_
+	return s
 }
 
 // check assign expression list to
 // a type list. called in
 //	return expr-list
 //	func(expr-list)
-func ascompatte(op Op, call *Node, isddd bool, nl **Type, lr *NodeList, fp int, init **NodeList) *NodeList {
-	var savel Iter
-
+func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, init *Nodes) []*Node {
 	lr0 := lr
-	l := Structfirst(&savel, nl)
+	l, savel := IterFields(nl)
 	var r *Node
-	if lr != nil {
-		r = lr.N
+	if len(lr) > 0 {
+		r = lr[0]
 	}
-	var nn *NodeList
+	var nn []*Node
 
 	// 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 {
+	if r != nil && len(lr) <= 1 && r.Type.IsFuncArgStruct() {
 		// optimization - can do block copy
-		if eqtypenoname(r.Type, *nl) {
-			a := nodarg(*nl, fp)
+		if eqtypenoname(r.Type, nl) {
+			arg := nodarg(nl, fp)
 			r = Nod(OCONVNOP, r, nil)
-			r.Type = a.Type
-			nn = list1(convas(Nod(OAS, a, r), init))
+			r.Type = arg.Type
+			nn = []*Node{convas(Nod(OAS, arg, r), init)}
 			goto ret
 		}
 
 		// conversions involved.
 		// copy into temporaries.
-		var alist *NodeList
+		var alist []*Node
 
-		for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
-			a = temp(l.Type)
-			alist = list(alist, a)
+		for _, l := range r.Type.Fields().Slice() {
+			tmp := temp(l.Type)
+			alist = append(alist, tmp)
 		}
 
-		a = Nod(OAS2, nil, nil)
-		a.List = alist
-		a.Rlist = lr
-		typecheck(&a, Etop)
-		walkstmt(&a)
-		*init = list(*init, a)
+		a := Nod(OAS2, nil, nil)
+		a.List.Set(alist)
+		a.Rlist.Set(lr)
+		a = typecheck(a, Etop)
+		a = walkstmt(a)
+		init.Append(a)
 		lr = alist
-		r = lr.N
-		l = Structfirst(&savel, nl)
+		r = lr[0]
+		l, savel = IterFields(nl)
 	}
 
-loop:
-	if l != nil && l.Isddd {
-		// the ddd parameter must be last
-		ll = structnext(&savel)
+	for {
+		if l != nil && l.Isddd {
+			// the ddd parameter must be last
+			ll := savel.Next()
 
-		if ll != nil {
-			Yyerror("... must be last argument")
-		}
+			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
-		}
+			// special case --
+			// only if we are assigning a single ddd
+			// argument to a ddd parameter then it is
+			// passed through unencapsulated
+			if r != nil && len(lr) <= 1 && isddd && Eqtype(l.Type, r.Type) {
+				a := Nod(OAS, nodarg(l, fp), r)
+				a = convas(a, init)
+				nn = append(nn, a)
+				break
+			}
 
-		// 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)
+			// 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
-	}
+			break
+		}
 
-	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)
+		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\t%s\n\t%s", op, l1, l2)
+				} else {
+					Yyerror("too many arguments to %v\n\t%s\n\t%s", op, l1, l2)
+				}
 			}
-		}
 
-		goto ret
-	}
+			break
+		}
 
-	a = Nod(OAS, nodarg(l, fp), r)
-	a = convas(a, init)
-	nn = list(nn, a)
+		a := Nod(OAS, nodarg(l, fp), r)
+		a = convas(a, init)
+		nn = append(nn, a)
 
-	l = structnext(&savel)
-	r = nil
-	lr = lr.Next
-	if lr != nil {
-		r = lr.N
+		l = savel.Next()
+		r = nil
+		lr = lr[1:]
+		if len(lr) > 0 {
+			r = lr[0]
+		}
 	}
-	goto loop
 
 ret:
-	for lr = nn; lr != nil; lr = lr.Next {
-		lr.N.Typecheck = 1
+	for _, n := range nn {
+		n.Typecheck = 1
 	}
 	return nn
 }
 
 // generate code for print
-func walkprint(nn *Node, init **NodeList) *Node {
+func walkprint(nn *Node, init *Nodes) *Node {
 	var r *Node
 	var n *Node
 	var on *Node
@@ -1908,89 +1923,82 @@ func walkprint(nn *Node, init **NodeList) *Node {
 
 	op := nn.Op
 	all := nn.List
-	var calls *NodeList
+	var calls []*Node
 	notfirst := false
 
 	// Hoist all the argument evaluation up before the lock.
-	walkexprlistcheap(all, init)
+	walkexprlistcheap(all.Slice(), init)
 
-	calls = list(calls, mkcall("printlock", nil, init))
-
-	for l := all; l != nil; l = l.Next {
+	calls = append(calls, mkcall("printlock", nil, init))
+	for i1, n1 := range all.Slice() {
 		if notfirst {
-			calls = list(calls, mkcall("printsp", nil, init))
+			calls = append(calls, mkcall("printsp", nil, init))
 		}
 
 		notfirst = op == OPRINTN
 
-		n = l.N
+		n = n1
 		if n.Op == OLITERAL {
 			switch n.Val().Ctype() {
 			case CTRUNE:
-				defaultlit(&n, runetype)
+				n = defaultlit(n, runetype)
 
 			case CTINT:
-				defaultlit(&n, Types[TINT64])
+				n = defaultlit(n, Types[TINT64])
 
 			case CTFLT:
-				defaultlit(&n, Types[TFLOAT64])
+				n = defaultlit(n, Types[TFLOAT64])
 			}
 		}
 
 		if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
-			defaultlit(&n, Types[TINT64])
+			n = defaultlit(n, Types[TINT64])
 		}
-		defaultlit(&n, nil)
-		l.N = n
+		n = defaultlit(n, nil)
+		all.SetIndex(i1, n)
 		if n.Type == nil || n.Type.Etype == TFORW {
 			continue
 		}
 
 		t = n.Type
 		et = n.Type.Etype
-		if Isinter(n.Type) {
-			if isnilinter(n.Type) {
-				on = syslook("printeface", 1)
+		if n.Type.IsInterface() {
+			if n.Type.IsEmptyInterface() {
+				on = syslook("printeface")
 			} 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
+				on = syslook("printiface")
+			}
+			on = substArgTypes(on, n.Type) // any-1
+		} else if n.Type.IsPtr() || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
+			on = syslook("printpointer")
+			on = substArgTypes(on, n.Type) // any-1
+		} else if n.Type.IsSlice() {
+			on = syslook("printslice")
+			on = 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)
+				if (t.Sym.Pkg == Runtimepkg || compiling_runtime) && t.Sym.Name == "hex" {
+					on = syslook("printhex")
 				} else {
-					on = syslook("printuint", 0)
+					on = syslook("printuint")
 				}
 			} else {
-				on = syslook("printint", 0)
+				on = syslook("printint")
 			}
 		} else if Isfloat[et] {
-			on = syslook("printfloat", 0)
+			on = syslook("printfloat")
 		} else if Iscomplex[et] {
-			on = syslook("printcomplex", 0)
+			on = syslook("printcomplex")
 		} else if et == TBOOL {
-			on = syslook("printbool", 0)
+			on = syslook("printbool")
 		} else if et == TSTRING {
-			on = syslook("printstring", 0)
+			on = syslook("printstring")
 		} else {
 			badtype(OPRINT, n.Type, nil)
 			continue
 		}
 
-		t = *getinarg(on.Type)
-		if t != nil {
-			t = t.Type
-		}
-		if t != nil {
-			t = t.Type
-		}
+		t = on.Type.Params().Field(0).Type
 
 		if !Eqtype(t, n.Type) {
 			n = Nod(OCONV, n, nil)
@@ -1998,31 +2006,33 @@ func walkprint(nn *Node, init **NodeList) *Node {
 		}
 
 		r = Nod(OCALL, on, nil)
-		r.List = list1(n)
-		calls = list(calls, r)
+		r.List.Append(n)
+		calls = append(calls, r)
 	}
 
 	if op == OPRINTN {
-		calls = list(calls, mkcall("printnl", nil, nil))
+		calls = append(calls, mkcall("printnl", nil, nil))
 	}
 
-	calls = list(calls, mkcall("printunlock", nil, init))
+	calls = append(calls, mkcall("printunlock", nil, init))
 
-	typechecklist(calls, Etop)
+	typecheckslice(calls, Etop)
 	walkexprlist(calls, init)
 
 	r = Nod(OEMPTY, nil, nil)
-	typecheck(&r, Etop)
-	walkexpr(&r, init)
-	r.Ninit = calls
+	r = typecheck(r, Etop)
+	r = walkexpr(r, init)
+	r.Ninit.Set(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))
+	fn := syslook("newobject")
+	fn = substArgTypes(fn, t)
+	v := mkcall1(fn, Ptrto(t), nil, typename(t))
+	v.NonNil = true
+	return v
 }
 
 func iscallret(n *Node) bool {
@@ -2072,7 +2082,7 @@ func isglobal(n *Node) bool {
 
 // Do we need a write barrier for the assignment l = r?
 func needwritebarrier(l *Node, r *Node) bool {
-	if use_writebarrier == 0 {
+	if !use_writebarrier {
 		return false
 	}
 
@@ -2126,16 +2136,22 @@ func needwritebarrier(l *Node, r *Node) bool {
 		return false
 	}
 
+	// No write barrier for storing global function, which is live
+	// no matter what.
+	if r.Op == ONAME && r.Class == PFUNC {
+		return false
+	}
+
 	// Otherwise, be conservative and use write barrier.
 	return true
 }
 
 // TODO(rsc): Perhaps componentgen should run before this.
 
-func applywritebarrier(n *Node, init **NodeList) *Node {
+func applywritebarrier(n *Node) *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))
+			Warnl(n.Lineno, "marking %v for barrier", Nconv(n.Left, 0))
 		}
 		n.Op = OASWB
 		return n
@@ -2143,9 +2159,9 @@ func applywritebarrier(n *Node, init **NodeList) *Node {
 	return n
 }
 
-func convas(n *Node, init **NodeList) *Node {
+func convas(n *Node, init *Nodes) *Node {
 	if n.Op != OAS {
-		Fatalf("convas: not OAS %v", Oconv(int(n.Op), 0))
+		Fatalf("convas: not OAS %v", n.Op)
 	}
 
 	n.Typecheck = 1
@@ -2163,7 +2179,7 @@ func convas(n *Node, init **NodeList) *Node {
 	}
 
 	if isblank(n.Left) {
-		defaultlit(&n.Right, nil)
+		n.Right = defaultlit(n.Right, nil)
 		goto out
 	}
 
@@ -2171,9 +2187,9 @@ func convas(n *Node, init **NodeList) *Node {
 		map_ := n.Left.Left
 		key := n.Left.Right
 		val := n.Right
-		walkexpr(&map_, init)
-		walkexpr(&key, init)
-		walkexpr(&val, init)
+		map_ = walkexpr(map_, init)
+		key = walkexpr(key, init)
+		val = walkexpr(val, init)
 
 		// orderexpr made sure key and val are addressable.
 		key = Nod(OADDR, key, nil)
@@ -2185,7 +2201,7 @@ func convas(n *Node, init **NodeList) *Node {
 
 	if !Eqtype(lt, rt) {
 		n.Right = assignconv(n.Right, lt, "assignment")
-		walkexpr(&n.Right, init)
+		n.Right = walkexpr(n.Right, init)
 	}
 
 out:
@@ -2199,14 +2215,11 @@ out:
 // 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
-
+func reorder1(all []*Node) []*Node {
 	c := 0 // function calls
 	t := 0 // total parameters
 
-	for l := all; l != nil; l = l.Next {
-		n = l.N
+	for _, n := range all {
 		t++
 		ullmancalc(n)
 		if n.Ullman >= UINF {
@@ -2218,15 +2231,14 @@ func reorder1(all *NodeList) *NodeList {
 		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
+	var g []*Node // fncalls assigned to tempnames
+	var f *Node   // last fncall assigned to stack
+	var r []*Node // non fncalls and tempnames assigned to stack
 	d := 0
 	var a *Node
-	for l := all; l != nil; l = l.Next {
-		n = l.N
+	for _, n := range all {
 		if n.Ullman < UINF {
-			r = list(r, n)
+			r = append(r, n)
 			continue
 		}
 
@@ -2240,19 +2252,19 @@ func reorder1(all *NodeList) *NodeList {
 		a = temp(n.Right.Type)
 
 		a = Nod(OAS, a, n.Right)
-		g = list(g, a)
+		g = append(g, a)
 
 		// put normal arg assignment on list
 		// with fncall replaced by tempname
 		n.Right = a.Left
 
-		r = list(r, n)
+		r = append(r, n)
 	}
 
 	if f != nil {
-		g = list(g, f)
+		g = append(g, f)
 	}
-	return concat(g, r)
+	return append(g, r...)
 }
 
 // from ascompat[ee]
@@ -2261,17 +2273,17 @@ func reorder1(all *NodeList) *NodeList {
 // be later use of an earlier lvalue.
 //
 // function calls have been removed.
-func reorder3(all *NodeList) *NodeList {
+func reorder3(all []*Node) []*Node {
 	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 early []*Node
 
-	var mapinit *NodeList
-	for list := all; list != nil; list = list.Next {
-		l = list.N.Left
+	var mapinit Nodes
+	for i, n := range all {
+		l = n.Left
 
 		// Save subexpressions needed on left side.
 		// Drill through non-dereferences.
@@ -2281,8 +2293,8 @@ func reorder3(all *NodeList) *NodeList {
 				continue
 			}
 
-			if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
-				reorder3save(&l.Right, all, list, &early)
+			if l.Op == OINDEX && l.Left.Type.IsArray() {
+				l.Right = reorder3save(l.Right, all, i, &early)
 				l = l.Left
 				continue
 			}
@@ -2292,45 +2304,46 @@ func reorder3(all *NodeList) *NodeList {
 
 		switch l.Op {
 		default:
-			Fatalf("reorder3 unexpected lvalue %v", Oconv(int(l.Op), obj.FmtSharp))
+			Fatalf("reorder3 unexpected lvalue %#v", l.Op)
 
 		case ONAME:
 			break
 
 		case OINDEX, OINDEXMAP:
-			reorder3save(&l.Left, all, list, &early)
-			reorder3save(&l.Right, all, list, &early)
+			l.Left = reorder3save(l.Left, all, i, &early)
+			l.Right = reorder3save(l.Right, all, i, &early)
 			if l.Op == OINDEXMAP {
-				list.N = convas(list.N, &mapinit)
+				all[i] = convas(all[i], &mapinit)
 			}
 
 		case OIND, ODOTPTR:
-			reorder3save(&l.Left, all, list, &early)
+			l.Left = reorder3save(l.Left, all, i, &early)
 		}
 
 		// Save expression on right side.
-		reorder3save(&list.N.Right, all, list, &early)
+		all[i].Right = reorder3save(all[i].Right, all, i, &early)
 	}
 
-	early = concat(mapinit, early)
-	return concat(early, all)
+	early = append(mapinit.Slice(), early...)
+	return append(early, all...)
 }
 
 // if the evaluation of *np would be affected by the
-// assignments in all up to but not including stop,
+// assignments in all up to but not including the ith assignment,
 // 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
+// The result of reorder3save MUST be assigned back to n, e.g.
+// 	n.Left = reorder3save(n.Left, all, i, early)
+func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
+	if !aliased(n, all, i) {
+		return n
 	}
 
 	q := temp(n.Type)
 	q = Nod(OAS, q, n)
-	typecheck(&q, Etop)
-	*early = list(*early, q)
-	*np = q.Left
+	q = typecheck(q, Etop)
+	*early = append(*early, q)
+	return q.Left
 }
 
 // what's the outer value that a write to n affects?
@@ -2345,7 +2358,7 @@ func outervalue(n *Node) *Node {
 			continue
 		}
 
-		if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
+		if n.Op == OINDEX && n.Left.Type != nil && n.Left.Type.IsArray() {
 			n = n.Left
 			continue
 		}
@@ -2357,12 +2370,18 @@ func outervalue(n *Node) *Node {
 }
 
 // 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 {
+// affected by writes in as up to but not including the ith element?
+func aliased(n *Node, all []*Node, i int) bool {
 	if n == nil {
 		return false
 	}
 
+	// Treat all fields of a struct as referring to the whole struct.
+	// We could do better but we would have to keep track of the fields.
+	for n.Op == ODOT {
+		n = n.Left
+	}
+
 	// 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.
@@ -2372,8 +2391,13 @@ func aliased(n *Node, all *NodeList, stop *NodeList) bool {
 
 	varwrite := 0
 	var a *Node
-	for l := all; l != stop; l = l.Next {
-		a = outervalue(l.N.Left)
+	for _, an := range all[:i] {
+		a = outervalue(an.Left)
+
+		for a.Op == ODOT {
+			a = a.Left
+		}
+
 		if a.Op != ONAME {
 			memwrite = 1
 			continue
@@ -2457,12 +2481,15 @@ func varexpr(n *Node) bool {
 		OPAREN,
 		OANDAND,
 		OOROR,
-		ODOT, // but not ODOTPTR
 		OCONV,
 		OCONVNOP,
 		OCONVIFACE,
 		ODOTTYPE:
 		return varexpr(n.Left) && varexpr(n.Right)
+
+	case ODOT: // but not ODOTPTR
+		// Should have been handled in aliased.
+		Fatalf("varexpr unexpected ODOT")
 	}
 
 	// Be conservative.
@@ -2489,8 +2516,8 @@ func vmatch2(l *Node, r *Node) bool {
 	if vmatch2(l, r.Right) {
 		return true
 	}
-	for ll := r.List; ll != nil; ll = ll.Next {
-		if vmatch2(l, ll.N) {
+	for _, n := range r.List.Slice() {
+		if vmatch2(l, n) {
 			return true
 		}
 	}
@@ -2507,7 +2534,7 @@ func vmatch1(l *Node, r *Node) bool {
 	switch l.Op {
 	case ONAME:
 		switch l.Class {
-		case PPARAM, PPARAMREF, PAUTO:
+		case PPARAM, PAUTO:
 			break
 
 			// assignment to non-stack variable
@@ -2530,122 +2557,105 @@ func vmatch1(l *Node, r *Node) bool {
 	if vmatch1(l.Right, r) {
 		return true
 	}
-	for ll := l.List; ll != nil; ll = ll.Next {
-		if vmatch1(ll.N, r) {
+	for _, n := range l.List.Slice() {
+		if vmatch1(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
-		}
-
+// paramstoheap returns code to allocate memory for heap-escaped parameters
+// and to copy non-result prameters' values from the stack.
+// If out is true, then code is also produced to zero-initialize their
+// stack memory addresses.
+func paramstoheap(params *Type) []*Node {
+	var nn []*Node
+	for _, t := range params.Fields().Slice() {
 		// For precise stacks, the garbage collector assumes results
 		// are always live, so zero them always.
-		if out != 0 {
+		if params.StructType().Funarg == FunargResults {
 			// 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))
+			nn = append(nn, Nod(OAS, nodarg(t, 1), nil))
 		}
 
-		if v == nil || v.Class&PHEAP == 0 {
+		v := t.Nname
+		if v != nil && v.Sym != nil && strings.HasPrefix(v.Sym.Name, "~r") { // unnamed result
+			v = nil
+		}
+		if v == nil {
 			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)
+		if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
+			nn = append(nn, walkstmt(Nod(ODCL, v, nil)))
+			if stackcopy.Class == PPARAM {
+				nn = append(nn, walkstmt(typecheck(Nod(OAS, v, stackcopy), Etop)))
+			}
 		}
 	}
 
 	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 {
+// returnsfromheap returns code to copy values for heap-escaped parameters
+// back to the stack.
+func returnsfromheap(params *Type) []*Node {
+	var nn []*Node
+	for _, t := range params.Fields().Slice() {
+		v := t.Nname
+		if v == nil {
 			continue
 		}
-		nn = list(nn, Nod(OAS, v.Name.Param.Stackparam, v))
+		if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class == PPARAMOUT {
+			nn = append(nn, walkstmt(typecheck(Nod(OAS, stackcopy, v), Etop)))
+		}
 	}
 
 	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.
+// heapmoves generates code to handle migrating heap-escaped parameters
+// between the stack and the heap. The generated code is added to Curfn's
+// Enter and Exit 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)
+	nn := paramstoheap(Curfn.Type.Recvs())
+	nn = append(nn, paramstoheap(Curfn.Type.Params())...)
+	nn = append(nn, paramstoheap(Curfn.Type.Results())...)
+	Curfn.Func.Enter.Append(nn...)
 	lineno = Curfn.Func.Endlineno
-	Curfn.Func.Exit = returnsfromheap(Getoutarg(Curfn.Type))
+	Curfn.Func.Exit.Append(returnsfromheap(Curfn.Type.Results())...)
 	lineno = lno
 }
 
-func vmkcall(fn *Node, t *Type, init **NodeList, va []*Node) *Node {
+func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
 	if fn.Type == nil || fn.Type.Etype != TFUNC {
 		Fatalf("mkcall %v %v", fn, fn.Type)
 	}
 
-	var args *NodeList
-	n := fn.Type.Intuple
-	for i := 0; i < n; i++ {
-		args = list(args, va[i])
-	}
+	n := fn.Type.Params().NumFields()
 
 	r := Nod(OCALL, fn, nil)
-	r.List = args
-	if fn.Type.Outtuple > 0 {
-		typecheck(&r, Erv|Efnstruct)
+	r.List.Set(va[:n])
+	if fn.Type.Results().NumFields() > 0 {
+		r = typecheck(r, Erv|Efnstruct)
 	} else {
-		typecheck(&r, Etop)
+		r = typecheck(r, Etop)
 	}
-	walkexpr(&r, init)
+	r = 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 mkcall(name string, t *Type, init *Nodes, args ...*Node) *Node {
+	return vmkcall(syslook(name), t, init, args)
 }
 
-func mkcall1(fn *Node, t *Type, init **NodeList, args ...*Node) *Node {
+func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
 	return vmkcall(fn, t, init, args)
 }
 
@@ -2655,53 +2665,53 @@ func conv(n *Node, t *Type) *Node {
 	}
 	n = Nod(OCONV, n, nil)
 	n.Type = t
-	typecheck(&n, Erv)
+	n = typecheck(n, Erv)
 	return n
 }
 
 func chanfn(name string, n int, t *Type) *Node {
-	if t.Etype != TCHAN {
+	if !t.IsChan() {
 		Fatalf("chanfn %v", t)
 	}
-	fn := syslook(name, 1)
+	fn := syslook(name)
 	switch n {
 	default:
 		Fatalf("chanfn %d", n)
 	case 1:
-		substArgTypes(fn, t.Type)
+		fn = substArgTypes(fn, t.Elem())
 	case 2:
-		substArgTypes(fn, t.Type, t.Type)
+		fn = substArgTypes(fn, t.Elem(), t.Elem())
 	}
 	return fn
 }
 
 func mapfn(name string, t *Type) *Node {
-	if t.Etype != TMAP {
+	if !t.IsMap() {
 		Fatalf("mapfn %v", t)
 	}
-	fn := syslook(name, 1)
-	substArgTypes(fn, t.Down, t.Type, t.Down, t.Type)
+	fn := syslook(name)
+	fn = substArgTypes(fn, t.Key(), t.Val(), t.Key(), t.Val())
 	return fn
 }
 
 func mapfndel(name string, t *Type) *Node {
-	if t.Etype != TMAP {
+	if !t.IsMap() {
 		Fatalf("mapfn %v", t)
 	}
-	fn := syslook(name, 1)
-	substArgTypes(fn, t.Down, t.Type, t.Down)
+	fn := syslook(name)
+	fn = substArgTypes(fn, t.Key(), t.Val(), t.Key())
 	return fn
 }
 
 func writebarrierfn(name string, l *Type, r *Type) *Node {
-	fn := syslook(name, 1)
-	substArgTypes(fn, l, r)
+	fn := syslook(name)
+	fn = substArgTypes(fn, l, r)
 	return fn
 }
 
-func addstr(n *Node, init **NodeList) *Node {
+func addstr(n *Node, init *Nodes) *Node {
 	// orderexpr rewrote OADDSTR to have a list of strings.
-	c := count(n.List)
+	c := n.List.Len()
 
 	if c < 2 {
 		Yyerror("addstr count %d too small", c)
@@ -2710,9 +2720,9 @@ func addstr(n *Node, init **NodeList) *Node {
 	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)))
+		for _, n1 := range n.List.Slice() {
+			if n1.Op == OLITERAL {
+				sz += int64(len(n1.Val().U.(string)))
 			}
 		}
 
@@ -2726,10 +2736,9 @@ func addstr(n *Node, init **NodeList) *Node {
 	}
 
 	// 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]))
+	args := []*Node{buf}
+	for _, n2 := range n.List.Slice() {
+		args = append(args, conv(n2, Types[TSTRING]))
 	}
 
 	var fn string
@@ -2741,24 +2750,21 @@ func addstr(n *Node, init **NodeList) *Node {
 		// large numbers of strings are passed to the runtime as a slice.
 		fn = "concatstrings"
 
-		t := typ(TARRAY)
-		t.Type = Types[TSTRING]
-		t.Bound = -1
+		t := typSlice(Types[TSTRING])
 		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.List.Set(args[1:]) // skip buf arg
+		args = []*Node{buf, slice}
 		slice.Esc = EscNone
 	}
 
-	cat := syslook(fn, 1)
+	cat := syslook(fn)
 	r := Nod(OCALL, cat, nil)
-	r.List = args
-	typecheck(&r, Erv)
-	walkexpr(&r, init)
+	r.List.Set(args)
+	r = typecheck(r, Erv)
+	r = walkexpr(r, init)
 	r.Type = n.Type
 
 	return r
@@ -2767,105 +2773,115 @@ func addstr(n *Node, init **NodeList) *Node {
 // expand append(l1, l2...) to
 //   init {
 //     s := l1
-//     if n := len(l1) + len(l2) - cap(s); n > 0 {
-//       s = growslice_n(s, n)
+//     n := len(s) + len(l2)
+//     // Compare as uint so growslice can panic on overflow.
+//     if uint(n) > uint(cap(s)) {
+//       s = growslice(s, n)
 //     }
-//     s = s[:len(l1)+len(l2)]
+//     s = s[:n]
 //     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)
+func appendslice(n *Node, init *Nodes) *Node {
+	walkexprlistsafe(n.List.Slice(), 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)
+	// modifying here. Fix explicitly.
+	ls := n.List.Slice()
+	for i1, n1 := range ls {
+		ls[i1] = cheapexpr(n1, 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
+	l1 := n.List.First()
+	l2 := n.List.Second()
 
-	nt := temp(Types[TINT])
+	var l []*Node
 
-	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))))
+	// var s []T
+	s := temp(l1.Type)
+	l = append(l, Nod(OAS, s, l1)) // s = l1
 
-	nif.Left = Nod(OGT, nt, Nodintconst(0))
+	// n := len(s) + len(l2)
+	nn := temp(Types[TINT])
+	l = append(l, Nod(OAS, nn, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil))))
 
-	// 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)
+	// if uint(n) > uint(cap(s))
+	nif := Nod(OIF, nil, nil)
+	nif.Left = Nod(OGT, Nod(OCONV, nn, nil), Nod(OCONV, Nod(OCAP, s, nil), nil))
+	nif.Left.Left.Type = Types[TUINT]
+	nif.Left.Right.Type = Types[TUINT]
 
-	// s = growslice_n(T, s, n)
-	nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt)))
+	// instantiate growslice(Type*, []any, int) []any
+	fn := syslook("growslice")
+	fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
 
-	l = list(l, nif)
+	// s = growslice(T, s, n)
+	nif.Nbody.Set1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type.Elem()), s, nn)))
+	l = append(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))))
+	// s = s[:n]
+	nt := Nod(OSLICE, s, nil)
+	nt.SetSliceBounds(nil, nn, nil)
+	nt.Etype = 1
+	l = append(l, Nod(OAS, s, nt))
 
+	if haspointers(l1.Type.Elem()) {
+		// copy(s[len(l1):], l2)
+		nptr1 := Nod(OSLICE, s, nil)
+		nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, 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)
+		fn := syslook("typedslicecopy")
+		fn = substArgTypes(fn, l1.Type, l2.Type)
+		var ln Nodes
+		ln.Set(l)
+		nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2)
+		l = append(ln.Slice(), nt)
 	} else if instrumenting {
 		// 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))))
-
+		// copy(s[len(l1):], l2)
+		nptr1 := Nod(OSLICE, s, nil)
+		nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
 		nptr1.Etype = 1
 		nptr2 := l2
 		var fn *Node
-		if l2.Type.Etype == TSTRING {
-			fn = syslook("slicestringcopy", 1)
+		if l2.Type.IsString() {
+			fn = syslook("slicestringcopy")
 		} else {
-			fn = syslook("slicecopy", 1)
+			fn = syslook("slicecopy")
 		}
-		substArgTypes(fn, l1.Type, l2.Type)
-		nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
-		l = list(l, nt)
+		fn = substArgTypes(fn, l1.Type, l2.Type)
+		var ln Nodes
+		ln.Set(l)
+		nt := mkcall1(fn, Types[TINT], &ln, nptr1, nptr2, Nodintconst(s.Type.Elem().Width))
+		l = append(ln.Slice(), 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)
+		fn := syslook("memmove")
+		fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
 
-		nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l)
+		var ln Nodes
+		ln.Set(l)
+		nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
 
-		nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
-		nt := mkcall1(fn, nil, &l, nptr1, nptr2, nwid)
-		l = list(l, nt)
+		nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Elem().Width))
+		nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
+		l = append(ln.Slice(), 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)
+	typecheckslice(l, Etop)
 	walkstmtlist(l)
-	*init = concat(*init, l)
+	init.Append(l...)
 	return s
 }
 
@@ -2890,31 +2906,27 @@ func appendslice(n *Node, init **NodeList) *Node {
 //     ...
 //   }
 //   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)
+func walkappend(n *Node, init *Nodes, dst *Node) *Node {
+	if !samesafeexpr(dst, n.List.First()) {
+		n.List.SetIndex(0, safeexpr(n.List.Index(0), init))
+		n.List.SetIndex(0, walkexpr(n.List.Index(0), init))
 	}
-	walkexprlistsafe(n.List.Next, init)
+	walkexprlistsafe(n.List.Slice()[1:], 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.
+	// 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)
+	ls := n.List.Slice()[1:]
+	for i, n := range ls {
+		ls[i] = cheapexpr(n, init)
 	}
 
-	nsrc := n.List.N
+	nsrc := n.List.First()
 
-	// Resolve slice type of multi-valued return.
-	if Istype(nsrc.Type, TSTRUCT) {
-		nsrc.Type = nsrc.Type.Type.Type
-	}
-	argc := count(n.List) - 1
+	argc := n.List.Len() - 1
 	if argc < 1 {
 		return nsrc
 	}
@@ -2925,41 +2937,45 @@ func walkappend(n *Node, init **NodeList, dst *Node) *Node {
 		return n
 	}
 
-	var l *NodeList
+	var l []*Node
 
 	ns := temp(nsrc.Type)
-	l = list(l, Nod(OAS, ns, nsrc)) // s = src
+	l = append(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)
+	fn := syslook("growslice") //   growslice(<type>, old []T, mincap int) (ret []T)
+	fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
 
-	nx.Nbody = list1(Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, Nod(OADD, Nod(OLEN, ns, nil), na))))
+	nx.Nbody.Set1(Nod(OAS, ns,
+		mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns,
+			Nod(OADD, Nod(OLEN, ns, nil), na))))
 
-	l = list(l, nx)
+	l = append(l, nx)
 
 	nn := temp(Types[TINT])
-	l = list(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
+	l = append(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 = Nod(OSLICE, ns, nil) // ...s[:n+argc]
+	nx.SetSliceBounds(nil, Nod(OADD, nn, na), nil)
 	nx.Etype = 1
-	l = list(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
+	l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
 
-	for a := n.List.Next; a != nil; a = a.Next {
+	ls = n.List.Slice()[1:]
+	for i, n := range ls {
 		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
+		l = append(l, Nod(OAS, nx, n)) // s[n] = arg
+		if i+1 < len(ls) {
+			l = append(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
 		}
 	}
 
-	typechecklist(l, Etop)
+	typecheckslice(l, Etop)
 	walkstmtlist(l)
-	*init = concat(*init, l)
+	init.Append(l...)
 	return ns
 }
 
@@ -2974,30 +2990,30 @@ func walkappend(n *Node, init **NodeList, dst *Node) *Node {
 //
 // Also works if b is a string.
 //
-func copyany(n *Node, init **NodeList, runtimecall bool) *Node {
-	if haspointers(n.Left.Type.Type) {
+func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
+	if haspointers(n.Left.Type.Elem()) {
 		fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
-		return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
+		return mkcall1(fn, n.Type, init, typename(n.Left.Type.Elem()), n.Left, n.Right)
 	}
 
 	if runtimecall {
 		var fn *Node
-		if n.Right.Type.Etype == TSTRING {
-			fn = syslook("slicestringcopy", 1)
+		if n.Right.Type.IsString() {
+			fn = syslook("slicestringcopy")
 		} else {
-			fn = syslook("slicecopy", 1)
+			fn = syslook("slicecopy")
 		}
-		substArgTypes(fn, n.Left.Type, n.Right.Type)
-		return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
+		fn = substArgTypes(fn, n.Left.Type, n.Right.Type)
+		return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Elem().Width))
 	}
 
-	walkexpr(&n.Left, init)
-	walkexpr(&n.Right, init)
+	n.Left = walkexpr(n.Left, init)
+	n.Right = 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))
+	var l []*Node
+	l = append(l, Nod(OAS, nl, n.Left))
+	l = append(l, Nod(OAS, nr, n.Right))
 
 	nfrm := Nod(OSPTR, nr, nil)
 	nto := Nod(OSPTR, nl, nil)
@@ -3005,27 +3021,27 @@ func copyany(n *Node, init **NodeList, runtimecall bool) *Node {
 	nlen := temp(Types[TINT])
 
 	// n = len(to)
-	l = list(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
+	l = append(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)
+	nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
+	l = append(l, nif)
 
 	// Call memmove.
-	fn := syslook("memmove", 1)
+	fn := syslook("memmove")
 
-	substArgTypes(fn, nl.Type.Type, nl.Type.Type)
+	fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
 	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))
+	l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
+	nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Elem().Width))
+	l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
 
-	typechecklist(l, Etop)
+	typecheckslice(l, Etop)
 	walkstmtlist(l)
-	*init = concat(*init, l)
+	init.Append(l...)
 	return nlen
 }
 
@@ -3034,43 +3050,32 @@ func eqfor(t *Type, needsize *int) *Node {
 	// 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 {
-		Fatalf("eqfor %v", t)
-	}
-
-	if a == AMEM {
-		n := syslook("memequal", 1)
-		substArgTypes(n, t, t)
+	switch a, _ := algtype1(t); a {
+	case AMEM:
+		n := syslook("memequal")
+		n = substArgTypes(n, t, t)
 		*needsize = 1
 		return n
+	case ASPECIAL:
+		sym := typesymprefix(".eq", t)
+		n := newname(sym)
+		n.Class = PFUNC
+		ntype := Nod(OTFUNC, nil, nil)
+		ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
+		ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
+		ntype.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
+		ntype = typecheck(ntype, Etype)
+		n.Type = ntype.Type
+		*needsize = 0
+		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
+	Fatalf("eqfor %v", t)
+	return nil
 }
 
-func walkcompare(np **Node, init **NodeList) {
-	n := *np
-
+// The result of walkcompare MUST be assigned back to n, e.g.
+// 	n.Left = walkcompare(n.Left, init)
+func walkcompare(n *Node, init *Nodes) *Node {
 	// Given interface value l and concrete value r, rewrite
 	//   l == r
 	// to
@@ -3081,10 +3086,10 @@ func walkcompare(np **Node, init **NodeList) {
 	var l *Node
 
 	var r *Node
-	if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
+	if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() {
 		l = n.Left
 		r = n.Right
-	} else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
+	} else if !n.Left.Type.IsInterface() && n.Right.Type.IsInterface() {
 		l = n.Right
 		r = n.Left
 	}
@@ -3093,8 +3098,8 @@ func walkcompare(np **Node, init **NodeList) {
 		x := temp(r.Type)
 		if haspointers(r.Type) {
 			a := Nod(OAS, x, nil)
-			typecheck(&a, Etop)
-			*init = list(*init, a)
+			a = typecheck(a, Etop)
+			init.Append(a)
 		}
 		ok := temp(Types[TBOOL])
 
@@ -3106,20 +3111,20 @@ func walkcompare(np **Node, init **NodeList) {
 		// 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)
+		expr.List.Append(x)
+		expr.List.Append(ok)
+		expr.Rlist.Append(a)
+		expr = typecheck(expr, Etop)
+		expr = 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
+		init.Append(expr)
+		n = finishcompare(n, r, init)
+		return n
 	}
 
 	// Must be comparison of array or struct.
@@ -3128,14 +3133,9 @@ func walkcompare(np **Node, init **NodeList) {
 
 	switch t.Etype {
 	default:
-		return
-
-	case TARRAY:
-		if Isslice(t) {
-			return
-		}
+		return n
 
-	case TSTRUCT:
+	case TARRAY, TSTRUCT:
 		break
 	}
 
@@ -3155,14 +3155,14 @@ func walkcompare(np **Node, init **NodeList) {
 	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)
+	a = typecheck(a, Etop)
+	init.Append(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)
+	a = typecheck(a, Etop)
+	init.Append(a)
 
 	var andor Op = OANDAND
 	if n.Op == ONE {
@@ -3170,12 +3170,12 @@ func walkcompare(np **Node, init **NodeList) {
 	}
 
 	var expr *Node
-	if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
+	if t.Etype == TARRAY && t.NumElem() <= 4 && issimple[t.Elem().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++ {
+		for i := 0; int64(i) < t.NumElem(); i++ {
 			li = Nod(OINDEX, l, Nodintconst(int64(i)))
 			ri = Nod(OINDEX, r, Nodintconst(int64(i)))
 			a = Nod(n.Op, li, ri)
@@ -3189,21 +3189,36 @@ func walkcompare(np **Node, init **NodeList) {
 		if expr == nil {
 			expr = Nodbool(n.Op == OEQ)
 		}
-		finishcompare(np, n, expr, init)
-		return
+		n = finishcompare(n, expr, init)
+		return n
 	}
 
-	if t.Etype == TSTRUCT && countfield(t) <= 4 {
+	if t.Etype == TARRAY {
+		// Zero- or single-element array, of any type.
+		switch t.NumElem() {
+		case 0:
+			n = finishcompare(n, Nodbool(n.Op == OEQ), init)
+			return n
+		case 1:
+			l0 := Nod(OINDEX, l, Nodintconst(0))
+			r0 := Nod(OINDEX, r, Nodintconst(0))
+			a := Nod(n.Op, l0, r0)
+			n = finishcompare(n, a, init)
+			return n
+		}
+	}
+
+	if t.IsStruct() && t.NumFields() <= 4 {
 		// Struct of four or fewer fields.
 		// Inline comparisons.
 		var li *Node
 		var ri *Node
-		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+		for _, t1 := range t.Fields().Slice() {
 			if isblanksym(t1.Sym) {
 				continue
 			}
-			li = Nod(OXDOT, l, newname(t1.Sym))
-			ri = Nod(OXDOT, r, newname(t1.Sym))
+			li = NodSym(OXDOT, l, t1.Sym)
+			ri = NodSym(OXDOT, r, t1.Sym)
 			a = Nod(n.Op, li, ri)
 			if expr == nil {
 				expr = a
@@ -3215,40 +3230,43 @@ func walkcompare(np **Node, init **NodeList) {
 		if expr == nil {
 			expr = Nodbool(n.Op == OEQ)
 		}
-		finishcompare(np, n, expr, init)
-		return
+		n = finishcompare(n, expr, init)
+		return n
 	}
 
-	// Chose not to inline.  Call equality function directly.
+	// 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)
+	call.List.Append(l)
+	call.List.Append(r)
 	if needsize != 0 {
-		call.List = list(call.List, Nodintconst(t.Width))
+		call.List.Append(Nodintconst(t.Width))
 	}
 	r = call
 	if n.Op != OEQ {
 		r = Nod(ONOT, r, nil)
 	}
 
-	finishcompare(np, n, r, init)
-	return
+	n = finishcompare(n, r, init)
+	return n
 }
 
-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
+// The result of finishcompare MUST be assigned back to n, e.g.
+// 	n.Left = finishcompare(n.Left, x, r, init)
+func finishcompare(n, r *Node, init *Nodes) *Node {
+	// Use nn here to avoid passing r to typecheck.
+	nn := r
+	nn = typecheck(nn, Erv)
+	nn = walkexpr(nn, init)
+	r = nn
 	if r.Type != n.Type {
 		r = Nod(OCONVNOP, r, nil)
 		r.Type = n.Type
 		r.Typecheck = 1
-		*np = r
+		nn = r
 	}
+	return nn
 }
 
 func samecheap(a *Node, b *Node) bool {
@@ -3263,16 +3281,14 @@ func samecheap(a *Node, b *Node) bool {
 			return a == b
 
 		case ODOT, ODOTPTR:
-			ar = a.Right
-			br = b.Right
-			if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
+			if a.Sym != b.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 {
+			if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || ar.Val().U.(*Mpint).Cmp(br.Val().U.(*Mpint)) != 0 {
 				return false
 			}
 		}
@@ -3284,33 +3300,38 @@ func samecheap(a *Node, b *Node) bool {
 	return false
 }
 
-func walkrotate(np **Node) {
-	if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
-		return
+// The result of walkrotate MUST be assigned back to n, e.g.
+// 	n.Left = walkrotate(n.Left)
+func walkrotate(n *Node) *Node {
+	if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
+		return 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 == nil || Issigned[n.Type.Etype] || l.Op == r.Op {
-		return
+	if (n.Op != OOR && n.Op != OXOR) || (l.Op != OLSH && l.Op != ORSH) || (r.Op != OLSH && r.Op != ORSH) || n.Type == nil || n.Type.IsSigned() || l.Op == r.Op {
+		return n
 	}
 
 	// Want same, side effect-free expression on lhs of both shifts.
 	if !samecheap(l.Left, r.Left) {
-		return
+		return n
 	}
 
 	// Constants adding to width?
 	w := int(l.Type.Width * 8)
 
+	if Thearch.LinkArch.Family == sys.S390X && w != 32 && w != 64 {
+		// only supports 32-bit and 64-bit rotates
+		return n
+	}
+
 	if Smallintconst(l.Right) && Smallintconst(r.Right) {
-		sl := int(Mpgetfix(l.Right.Val().U.(*Mpint)))
+		sl := int(l.Right.Int64())
 		if sl >= 0 {
-			sr := int(Mpgetfix(r.Right.Val().U.(*Mpint)))
+			sr := int(r.Right.Int64())
 			if sr >= 0 && sl+sr == w {
 				// Rewrite left shift half to left rotate.
 				if l.Op == OLSH {
@@ -3321,28 +3342,27 @@ func walkrotate(np **Node) {
 				n.Op = OLROT
 
 				// Remove rotate 0 and rotate w.
-				s := int(Mpgetfix(n.Right.Val().U.(*Mpint)))
+				s := int(n.Right.Int64())
 
 				if s == 0 || s == w {
 					n = n.Left
 				}
-
-				*np = n
-				return
+				return n
 			}
 		}
-		return
+		return n
 	}
 
 	// TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
-	return
+	return n
 }
 
 // walkmul rewrites integer multiplication by powers of two as shifts.
-func walkmul(np **Node, init **NodeList) {
-	n := *np
-	if !Isint[n.Type.Etype] {
-		return
+// The result of walkmul MUST be assigned back to n, e.g.
+// 	n.Left = walkmul(n.Left, init)
+func walkmul(n *Node, init *Nodes) *Node {
+	if !n.Type.IsInteger() {
+		return n
 	}
 
 	var nr *Node
@@ -3354,7 +3374,7 @@ func walkmul(np **Node, init **NodeList) {
 		nl = n.Right
 		nr = n.Left
 	} else {
-		return
+		return n
 	}
 
 	neg := 0
@@ -3362,7 +3382,7 @@ func walkmul(np **Node, init **NodeList) {
 	// x*0 is 0 (and side effects of x).
 	var pow int
 	var w int
-	if Mpgetfix(nr.Val().U.(*Mpint)) == 0 {
+	if nr.Int64() == 0 {
 		cheapexpr(nl, init)
 		Nodconst(n, n.Type, 0)
 		goto ret
@@ -3372,7 +3392,7 @@ func walkmul(np **Node, init **NodeList) {
 	pow = powtwo(nr)
 
 	if pow < 0 {
-		return
+		return n
 	}
 	if pow >= 1000 {
 		// negative power of 2, like -16
@@ -3383,7 +3403,7 @@ func walkmul(np **Node, init **NodeList) {
 
 	w = int(nl.Type.Width * 8)
 	if pow+1 >= w { // too big, shouldn't happen
-		return
+		return n
 	}
 
 	nl = cheapexpr(nl, init)
@@ -3402,24 +3422,25 @@ ret:
 		n = Nod(OMINUS, n, nil)
 	}
 
-	typecheck(&n, Erv)
-	walkexpr(&n, init)
-	*np = n
+	n = typecheck(n, Erv)
+	n = walkexpr(n, init)
+	return n
 }
 
 // walkdiv rewrites division by a constant as less expensive
 // operations.
-func walkdiv(np **Node, init **NodeList) {
+// The result of walkdiv MUST be assigned back to n, e.g.
+// 	n.Left = walkdiv(n.Left, init)
+func walkdiv(n *Node, init *Nodes) *Node {
 	// if >= 0, nr is 1<<pow // 1 if nr is negative.
 
 	// TODO(minux)
-	if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
-		return
+	if Thearch.LinkArch.InFamily(sys.MIPS64, sys.PPC64) {
+		return n
 	}
 
-	n := *np
 	if n.Right.Op != OLITERAL {
-		return
+		return n
 	}
 
 	// nr is a constant.
@@ -3442,7 +3463,7 @@ func walkdiv(np **Node, init **NodeList) {
 
 	if pow+1 >= w {
 		// divisor too large.
-		return
+		return n
 	}
 
 	if pow < 0 {
@@ -3452,16 +3473,16 @@ func walkdiv(np **Node, init **NodeList) {
 		var m Magic
 		m.W = w
 
-		if Issigned[nl.Type.Etype] {
-			m.Sd = Mpgetfix(nr.Val().U.(*Mpint))
+		if nl.Type.IsSigned() {
+			m.Sd = nr.Int64()
 			Smagic(&m)
 		} else {
-			m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
+			m.Ud = uint64(nr.Int64())
 			Umagic(&m)
 		}
 
 		if m.Bad != 0 {
-			return
+			return n
 		}
 
 		// We have a quick division method so use it
@@ -3475,23 +3496,33 @@ func walkdiv(np **Node, init **NodeList) {
 			goto ret
 		}
 
+		// TODO(zhongwei) Test shows that TUINT8, TINT8, TUINT16 and TINT16's "quick division" method
+		// on current arm64 backend is slower than hardware div instruction on ARM64 due to unnecessary
+		// data movement between registers. It could be enabled when generated code is good enough.
+		if Thearch.LinkArch.Family == sys.ARM64 {
+			switch Simtype[nl.Type.Etype] {
+			case TUINT8, TINT8, TUINT16, TINT16:
+				return n
+			}
+		}
+
 		switch Simtype[nl.Type.Etype] {
 		default:
-			return
+			return n
 
 			// n1 = nl * magic >> w (HMUL)
 		case TUINT8, TUINT16, TUINT32:
-			nc := Nod(OXXX, nil, nil)
+			var nc Node
 
-			Nodconst(nc, nl.Type, int64(m.Um))
-			n1 := Nod(OHMUL, nl, nc)
-			typecheck(&n1, Erv)
+			Nodconst(&nc, nl.Type, int64(m.Um))
+			n1 := Nod(OHMUL, nl, &nc)
+			n1 = 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
+					return n
 
 				case TUINT8, TUINT16:
 					twide = Types[TUINT32]
@@ -3511,41 +3542,41 @@ func walkdiv(np **Node, init **NodeList) {
 				n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
 
 				// shift by m.s
-				nc := Nod(OXXX, nil, nil)
+				var nc Node
 
-				Nodconst(nc, Types[TUINT], int64(m.S))
-				n = conv(Nod(ORSH, n2, nc), nl.Type)
+				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)
+				var nc Node
 
-				Nodconst(nc, Types[TUINT], int64(m.S))
-				n = Nod(ORSH, n1, nc)
+				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)
+			var nc Node
 
-			Nodconst(nc, nl.Type, m.Sm)
-			n1 := Nod(OHMUL, nl, nc)
-			typecheck(&n1, Erv)
+			Nodconst(&nc, nl.Type, m.Sm)
+			n1 := Nod(OHMUL, nl, &nc)
+			n1 = typecheck(n1, Erv)
 			if m.Sm < 0 {
 				// add the numerator.
 				n1 = Nod(OADD, n1, nl)
 			}
 
 			// shift by m.s
-			nc = Nod(OXXX, nil, nil)
+			var ns Node
 
-			Nodconst(nc, Types[TUINT], int64(m.S))
-			n2 := conv(Nod(ORSH, n1, nc), nl.Type)
+			Nodconst(&ns, Types[TUINT], int64(m.S))
+			n2 := conv(Nod(ORSH, n1, &ns), nl.Type)
 
 			// add 1 iff n1 is negative.
-			nc = Nod(OXXX, nil, nil)
+			var nneg Node
 
-			Nodconst(nc, Types[TUINT], int64(w)-1)
-			n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
+			Nodconst(&nneg, Types[TUINT], int64(w)-1)
+			n3 := Nod(ORSH, nl, &nneg) // n4 = -1 iff n1 is negative.
 			n = Nod(OSUB, n2, n3)
 
 			// apply sign.
@@ -3573,37 +3604,37 @@ func walkdiv(np **Node, init **NodeList) {
 		}
 
 	default:
-		if Issigned[n.Type.Etype] {
+		if n.Type.IsSigned() {
 			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)
+				var nc Node
 
-				Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
-				n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
+				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 = 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)
+					var nc Node
+					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)
+					var nc Node
 
-					Nodconst(nc, nl.Type, (1<<uint(pow))-1)
-					n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
-					typecheck(&n2, Erv)
+					Nodconst(&nc, nl.Type, (1<<uint(pow))-1)
+					n2 := Nod(OAND, n1, &nc) // n2 = 2^pow-1 iff nl<0.
+					n2 = typecheck(n2, Erv)
 					n2 = cheapexpr(n2, init)
 
 					n3 := Nod(OADD, nl, n2)
-					n4 := Nod(OAND, n3, nc)
+					n4 := Nod(OAND, n3, &nc)
 					n = Nod(OSUB, n4, n2)
 				}
 
@@ -3612,28 +3643,28 @@ func walkdiv(np **Node, init **NodeList) {
 				// 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)
+				var nc Node
 
-				Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
-				n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
+				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)
+					var nc Node
 
-					Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
-					n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
+					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
+				var n2 Node
+				Nodconst(&n2, Types[Simtype[TUINT]], int64(pow))
+				n.Right = &n2
 				n.Typecheck = 0
 			}
 
@@ -3643,42 +3674,42 @@ func walkdiv(np **Node, init **NodeList) {
 			break
 		}
 
-		nc := Nod(OXXX, nil, nil)
+		var nc Node
 		if n.Op == OMOD {
 			// n = nl & (nr-1)
 			n.Op = OAND
 
-			Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1)
+			Nodconst(&nc, nl.Type, nr.Int64()-1)
 		} else {
 			// n = nl >> pow
 			n.Op = ORSH
 
-			Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
+			Nodconst(&nc, Types[Simtype[TUINT]], int64(pow))
 		}
 
 		n.Typecheck = 0
-		n.Right = nc
+		n.Right = &nc
 	}
 
 	goto ret
 
 ret:
-	typecheck(&n, Erv)
-	walkexpr(&n, init)
-	*np = n
+	n = typecheck(n, Erv)
+	n = walkexpr(n, init)
+	return 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] {
+	if n.Type == nil || !n.Type.IsInteger() {
 		return false
 	}
 
-	sign := Issigned[n.Type.Etype]
+	sign := n.Type.IsSigned()
 	bits := int32(8 * n.Type.Width)
 
 	if Smallintconst(n) {
-		v := Mpgetfix(n.Val().U.(*Mpint))
+		v := n.Int64()
 		return 0 <= v && v < max
 	}
 
@@ -3686,9 +3717,9 @@ func bounded(n *Node, max int64) bool {
 	case OAND:
 		v := int64(-1)
 		if Smallintconst(n.Left) {
-			v = Mpgetfix(n.Left.Val().U.(*Mpint))
+			v = n.Left.Int64()
 		} else if Smallintconst(n.Right) {
-			v = Mpgetfix(n.Right.Val().U.(*Mpint))
+			v = n.Right.Int64()
 		}
 
 		if 0 <= v && v < max {
@@ -3697,7 +3728,7 @@ func bounded(n *Node, max int64) bool {
 
 	case OMOD:
 		if !sign && Smallintconst(n.Right) {
-			v := Mpgetfix(n.Right.Val().U.(*Mpint))
+			v := n.Right.Int64()
 			if 0 <= v && v <= max {
 				return true
 			}
@@ -3705,7 +3736,7 @@ func bounded(n *Node, max int64) bool {
 
 	case ODIV:
 		if !sign && Smallintconst(n.Right) {
-			v := Mpgetfix(n.Right.Val().U.(*Mpint))
+			v := n.Right.Int64()
 			for bits > 0 && v >= 2 {
 				bits--
 				v >>= 1
@@ -3714,7 +3745,7 @@ func bounded(n *Node, max int64) bool {
 
 	case ORSH:
 		if !sign && Smallintconst(n.Right) {
-			v := Mpgetfix(n.Right.Val().U.(*Mpint))
+			v := n.Right.Int64()
 			if v > int64(bits) {
 				return true
 			}
@@ -3729,6 +3760,48 @@ func bounded(n *Node, max int64) bool {
 	return false
 }
 
+// usemethod check interface method calls for uses of reflect.Type.Method.
+func usemethod(n *Node) {
+	t := n.Left.Type
+
+	// Looking for either of:
+	//	Method(int) reflect.Method
+	//	MethodByName(string) (reflect.Method, bool)
+	//
+	// TODO(crawshaw): improve precision of match by working out
+	//                 how to check the method name.
+	if n := t.Params().NumFields(); n != 1 {
+		return
+	}
+	if n := t.Results().NumFields(); n != 1 && n != 2 {
+		return
+	}
+	p0 := t.Params().Field(0)
+	res0 := t.Results().Field(0)
+	var res1 *Field
+	if t.Results().NumFields() == 2 {
+		res1 = t.Results().Field(1)
+	}
+
+	if res1 == nil {
+		if p0.Type.Etype != TINT {
+			return
+		}
+	} else {
+		if !p0.Type.IsString() {
+			return
+		}
+		if !res1.Type.IsBoolean() {
+			return
+		}
+	}
+	if Tconv(res0.Type, 0) != "reflect.Method" {
+		return
+	}
+
+	Curfn.Func.ReflectMethod = true
+}
+
 func usefield(n *Node) {
 	if obj.Fieldtrack_enabled == 0 {
 		return
@@ -3736,46 +3809,50 @@ func usefield(n *Node) {
 
 	switch n.Op {
 	default:
-		Fatalf("usefield %v", Oconv(int(n.Op), 0))
+		Fatalf("usefield %v", n.Op)
 
 	case ODOT, ODOTPTR:
 		break
 	}
+	if n.Sym == nil {
+		// No field name.  This DOTPTR was built by the compiler for access
+		// to runtime data structures.  Ignore.
+		return
+	}
 
 	t := n.Left.Type
-	if Isptr[t.Etype] {
-		t = t.Type
+	if t.IsPtr() {
+		t = t.Elem()
 	}
-	field := dotField[typeSym{t.Orig, n.Right.Sym}]
+	field := dotField[typeSym{t.Orig, n.Sym}]
 	if field == nil {
-		Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
+		Fatalf("usefield %v %v without paramfld", n.Left.Type, n.Sym)
 	}
-	if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
+	if !strings.Contains(field.Note, "go:\"track\"") {
 		return
 	}
 
-	// dedup on list
-	if field.Lastfn == Curfn {
-		return
+	outer := n.Left.Type
+	if outer.IsPtr() {
+		outer = outer.Elem()
 	}
-	field.Lastfn = Curfn
-	field.Outer = n.Left.Type
-	if Isptr[field.Outer.Etype] {
-		field.Outer = field.Outer.Type
-	}
-	if field.Outer.Sym == nil {
+	if 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)
+	sym := tracksym(outer, field)
+	if Curfn.Func.FieldTrack == nil {
+		Curfn.Func.FieldTrack = make(map[*Sym]struct{})
+	}
+	Curfn.Func.FieldTrack[sym] = struct{}{}
 }
 
-func candiscardlist(l *NodeList) bool {
-	for ; l != nil; l = l.Next {
-		if !candiscard(l.N) {
+func candiscardlist(l Nodes) bool {
+	for _, n := range l.Slice() {
+		if !candiscard(n) {
 			return false
 		}
 	}
@@ -3848,17 +3925,17 @@ func candiscard(n *Node) bool {
 
 		// 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 {
+		if Isconst(n.Right, CTINT) && n.Right.Val().U.(*Mpint).CmpInt64(0) != 0 {
 			break
 		}
-		if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 {
+		if Isconst(n.Right, CTFLT) && n.Right.Val().U.(*Mpflt).CmpFloat64(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 {
+		if Isconst(n.Left, CTINT) && n.Left.Val().U.(*Mpint).CmpInt64(0) == 0 {
 			break
 		}
 		return false
@@ -3885,26 +3962,25 @@ func candiscard(n *Node) bool {
 
 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
+// The result of walkprintfunc MUST be assigned back to n, e.g.
+// 	n.Left = walkprintfunc(n.Left, init)
+func walkprintfunc(n *Node, init *Nodes) *Node {
+	if n.Ninit.Len() != 0 {
+		walkstmtlist(n.Ninit.Slice())
+		init.AppendNodes(&n.Ninit)
 	}
 
 	t := Nod(OTFUNC, nil, nil)
 	num := 0
-	var printargs *NodeList
+	var printargs []*Node
 	var a *Node
 	var buf string
-	for l := n.List; l != nil; l = l.Next {
+	for _, n1 := range n.List.Slice() {
 		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)
+		a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(n1.Type))
+		t.List.Append(a)
+		printargs = append(printargs, a.Left)
 	}
 
 	fn := Nod(ODCLFUNC, nil, nil)
@@ -3920,23 +3996,23 @@ func walkprintfunc(np **Node, init **NodeList) {
 	funchdr(fn)
 
 	a = Nod(n.Op, nil, nil)
-	a.List = printargs
-	typecheck(&a, Etop)
-	walkstmt(&a)
+	a.List.Set(printargs)
+	a = typecheck(a, Etop)
+	a = walkstmt(a)
 
-	fn.Nbody = list1(a)
+	fn.Nbody.Set1(a)
 
 	funcbody(fn)
 
-	typecheck(&fn, Etop)
-	typechecklist(fn.Nbody, Etop)
-	xtop = list(xtop, fn)
+	fn = typecheck(fn, Etop)
+	typecheckslice(fn.Nbody.Slice(), Etop)
+	xtop = append(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
+	a.List.Set(n.List.Slice())
+	a = typecheck(a, Etop)
+	a = walkexpr(a, init)
+	return a
 }
diff --git a/src/cmd/compile/internal/mips64/cgen.go b/src/cmd/compile/internal/mips64/cgen.go
index 434bfc7..998afea 100644
--- a/src/cmd/compile/internal/mips64/cgen.go
+++ b/src/cmd/compile/internal/mips64/cgen.go
@@ -17,7 +17,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// for example moving [4]byte must use 4 MOVB not 1 MOVW.
 	align := int(n.Type.Align)
 
-	var op int
+	var op obj.As
 	switch align {
 	default:
 		gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
@@ -44,7 +44,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// the src and dst overlap, then reverse direction
 	dir := align
 
-	if osrc < odst && int64(odst) < int64(osrc)+w {
+	if osrc < odst && odst < osrc+w {
 		dir = -dir
 	}
 
@@ -129,7 +129,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 		// TODO: Instead of generating ADDV $-8,R8; ADDV
 		// $-8,R7; n*(MOVV 8(R8),R9; ADDV $8,R8; MOVV R9,8(R7);
 		// ADDV $8,R7;) just generate the offsets directly and
-		// eliminate the ADDs.  That will produce shorter, more
+		// eliminate the ADDs. That will produce shorter, more
 		// pipeline-able code.
 		var p *obj.Prog
 		for ; c > 0; c-- {
diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go
index 00ffe17..22890c8 100644
--- a/src/cmd/compile/internal/mips64/galign.go
+++ b/src/cmd/compile/internal/mips64/galign.go
@@ -10,46 +10,14 @@ import (
 	"cmd/internal/obj/mips"
 )
 
-var thechar int = '0'
-
-var thestring string = "mips64"
-
-var thelinkarch *obj.LinkArch
-
-func linkarchinit() {
-	thestring = obj.Getgoarch()
-	gc.Thearch.Thestring = thestring
-	if thestring == "mips64le" {
-		thelinkarch = &mips.Linkmips64le
-	} else {
-		thelinkarch = &mips.Linkmips64
-	}
-	gc.Thearch.Thelinkarch = thelinkarch
-}
-
-var MAXWIDTH int64 = 1 << 50
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, and uintptr
- */
-var typedefs = []gc.Typedef{
-	{"int", gc.TINT, gc.TINT64},
-	{"uint", gc.TUINT, gc.TUINT64},
-	{"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.LinkArch = &mips.Linkmips64
+	if obj.Getgoarch() == "mips64le" {
+		gc.Thearch.LinkArch = &mips.Linkmips64le
+	}
 	gc.Thearch.REGSP = mips.REGSP
 	gc.Thearch.REGCTXT = mips.REGCTXT
 	gc.Thearch.REGCALLX = mips.REG_R1
@@ -59,7 +27,7 @@ func Main() {
 	gc.Thearch.REGMAX = mips.REG_R31
 	gc.Thearch.FREGMIN = mips.REG_F0
 	gc.Thearch.FREGMAX = mips.REG_F31
-	gc.Thearch.MAXWIDTH = MAXWIDTH
+	gc.Thearch.MAXWIDTH = 1 << 50
 	gc.Thearch.ReservedRegs = resvd
 
 	gc.Thearch.Betypeinit = betypeinit
@@ -76,7 +44,6 @@ func Main() {
 	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
diff --git a/src/cmd/compile/internal/mips64/ggen.go b/src/cmd/compile/internal/mips64/ggen.go
index 8c285a2..e0c4de2 100644
--- a/src/cmd/compile/internal/mips64/ggen.go
+++ b/src/cmd/compile/internal/mips64/ggen.go
@@ -12,12 +12,10 @@ import (
 )
 
 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)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 	ptxt.To.Offset = int64(frame)
 
@@ -30,8 +28,7 @@ func defframe(ptxt *obj.Prog) {
 	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
+	for _, n := range gc.Curfn.Func.Dcl {
 		if !n.Name.Needzero {
 			continue
 		}
@@ -39,7 +36,7 @@ func defframe(ptxt *obj.Prog) {
 			gc.Fatalf("needzero class %d", n.Class)
 		}
 		if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
-			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
+			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
 		}
 
 		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
@@ -104,15 +101,15 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
 	return p
 }
 
-func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
+func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
 	q := gc.Ctxt.NewProg()
 	gc.Clearp(q)
-	q.As = int16(as)
+	q.As = as
 	q.Lineno = p.Lineno
-	q.From.Type = int16(ftype)
+	q.From.Type = ftype
 	q.From.Reg = int16(freg)
 	q.From.Offset = foffset
-	q.To.Type = int16(ttype)
+	q.To.Type = ttype
 	q.To.Reg = int16(treg)
 	q.To.Offset = toffset
 	q.Link = p.Link
@@ -141,7 +138,7 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	t0 := t
 
 	if t.Width < 8 {
-		if gc.Issigned[t.Etype] {
+		if t.IsSigned() {
 			t = gc.Types[gc.TINT64]
 		} else {
 			t = gc.Types[gc.TUINT64]
@@ -206,8 +203,8 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
 		nl, nr = nr, nl
 	}
 
-	t := (*gc.Type)(nl.Type)
-	w := int(int(t.Width * 8))
+	t := nl.Type
+	w := t.Width * 8
 	var n1 gc.Node
 	gc.Cgenr(nl, &n1, res)
 	var n2 gc.Node
@@ -220,9 +217,9 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
 		var lo gc.Node
 		gc.Nodreg(&lo, gc.Types[gc.TUINT64], mips.REG_LO)
 		gins(mips.AMOVV, &lo, &n1)
-		p := (*obj.Prog)(gins(mips.ASRAV, nil, &n1))
+		p := gins(mips.ASRAV, nil, &n1)
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(w)
+		p.From.Offset = w
 
 	case gc.TUINT8,
 		gc.TUINT16,
@@ -231,13 +228,13 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
 		var lo gc.Node
 		gc.Nodreg(&lo, gc.Types[gc.TUINT64], mips.REG_LO)
 		gins(mips.AMOVV, &lo, &n1)
-		p := (*obj.Prog)(gins(mips.ASRLV, nil, &n1))
+		p := gins(mips.ASRLV, nil, &n1)
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(w)
+		p.From.Offset = w
 
 	case gc.TINT64,
 		gc.TUINT64:
-		if gc.Issigned[t.Etype] {
+		if t.IsSigned() {
 			gins3(mips.AMULV, &n2, &n1, nil)
 		} else {
 			gins3(mips.AMULVU, &n2, &n1, nil)
@@ -261,13 +258,13 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
  *	res = nl >> nr
  */
 func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
-	a := int(optoas(op, nl.Type))
+	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())
+		sc := uint64(nr.Int64())
 		if sc >= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
 			var n3 gc.Node
@@ -333,7 +330,7 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 		gc.Nodconst(&n3, tcount, nl.Type.Width*8)
 		gins3(mips.ASGTU, &n3, &n1, &rtmp)
 		p1 := ginsbranch(mips.ABNE, nil, &rtmp, nil, 0)
-		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
+		if op == gc.ORSH && nl.Type.IsSigned() {
 			gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
 			gins(a, &n3, &n2)
 		} else {
@@ -358,15 +355,15 @@ func clearfat(nl *gc.Node) {
 		fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
 	}
 
-	w := uint64(uint64(nl.Type.Width))
+	w := 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
+	c := w % 8 // bytes
+	q := w / 8 // dwords
 
 	if gc.Reginuse(mips.REGRT1) {
 		gc.Fatalf("%v in use during clearfat", obj.Rconv(mips.REGRT1))
@@ -394,7 +391,7 @@ func clearfat(nl *gc.Node) {
 		p = gins(mips.AMOVV, &r0, &dst)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Offset = 8
-		pl := (*obj.Prog)(p)
+		pl := p
 
 		p = gins(mips.AADDV, nil, &dst)
 		p.From.Type = obj.TYPE_CONST
@@ -413,7 +410,7 @@ func clearfat(nl *gc.Node) {
 		p := gins(mips.ASUBV, nil, &dst)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 8
-		f := (*gc.Node)(gc.Sysfunc("duffzero"))
+		f := gc.Sysfunc("duffzero")
 		p = gins(obj.ADUFFZERO, nil, f)
 		gc.Afunclit(&p.To, f)
 
@@ -448,7 +445,7 @@ func clearfat(nl *gc.Node) {
 func expandchecks(firstp *obj.Prog) {
 	var p1 *obj.Prog
 
-	for p := (*obj.Prog)(firstp); p != nil; p = p.Link {
+	for p := firstp; p != nil; p = p.Link {
 		if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
 			fmt.Printf("expandchecks: %v\n", p)
 		}
@@ -456,7 +453,7 @@ func expandchecks(firstp *obj.Prog) {
 			continue
 		}
 		if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
-			gc.Warnl(int(p.Lineno), "generated nil check")
+			gc.Warnl(p.Lineno, "generated nil check")
 		}
 		if p.From.Type != obj.TYPE_REG {
 			gc.Fatalf("invalid nil check %v\n", p)
diff --git a/src/cmd/compile/internal/mips64/gsubr.go b/src/cmd/compile/internal/mips64/gsubr.go
index d2065d9..eb56d8b 100644
--- a/src/cmd/compile/internal/mips64/gsubr.go
+++ b/src/cmd/compile/internal/mips64/gsubr.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -41,6 +41,7 @@ import (
 var resvd = []int{
 	mips.REGZERO,
 	mips.REGSP,   // reserved for SP
+	mips.REGSB,   // reserved for SB
 	mips.REGLINK, // reserved for link
 	mips.REGG,
 	mips.REGTMP,
@@ -56,7 +57,7 @@ var resvd = []int{
  * generate
  *	as $c, n
  */
-func ginscon(as int, c int64, n2 *gc.Node) {
+func ginscon(as obj.As, c int64, n2 *gc.Node) {
 	var n1 gc.Node
 
 	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
@@ -78,7 +79,7 @@ func ginscon(as int, c int64, n2 *gc.Node) {
 
 // generate branch
 // n1, n2 are registers
-func ginsbranch(as int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+func ginsbranch(as obj.As, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 	p := gc.Gbranch(as, t, likely)
 	gc.Naddr(&p.From, n1)
 	if n2 != nil {
@@ -88,11 +89,11 @@ func ginsbranch(as int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 }
 
 func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
-	if !gc.Isfloat[t.Etype] && (op == gc.OLT || op == gc.OGE) {
+	if !t.IsFloat() && (op == gc.OLT || op == gc.OGE) {
 		// swap nodes to fit SGT instruction
 		n1, n2 = n2, n1
 	}
-	if gc.Isfloat[t.Etype] && (op == gc.OLT || op == gc.OLE) {
+	if t.IsFloat() && (op == gc.OLT || op == gc.OLE) {
 		// swap nodes to fit CMPGT, CMPGE instructions and reverse relation
 		n1, n2 = n2, n1
 		if op == gc.OLT {
@@ -148,7 +149,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 	case gc.TFLOAT32:
 		switch op {
 		default:
-			gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
+			gc.Fatalf("ginscmp: no entry for op=%s type=%v", op, t)
 
 		case gc.OEQ,
 			gc.ONE:
@@ -165,7 +166,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 	case gc.TFLOAT64:
 		switch op {
 		default:
-			gc.Fatalf("ginscmp: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
+			gc.Fatalf("ginscmp: no entry for op=%s type=%v", op, t)
 
 		case gc.OEQ,
 			gc.ONE:
@@ -218,12 +219,12 @@ func bignodes() {
  */
 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))
+		fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
 	}
 
 	ft := int(gc.Simsimtype(f.Type))
 	tt := int(gc.Simsimtype(t.Type))
-	cvt := (*gc.Type)(t.Type)
+	cvt := t.Type
 
 	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
 		gc.Complexmove(f, t)
@@ -233,7 +234,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 	// cannot have two memory operands
 	var r2 gc.Node
 	var r1 gc.Node
-	var a int
+	var a obj.As
 	if gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
 	}
@@ -296,7 +297,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
-		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong))
+		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
 
 		/*
 		 * integer copy and truncate
@@ -465,7 +466,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 	//return;
 	// algorithm is:
 	//	if small enough, use native int64 -> float64 conversion.
-	//	otherwise, halve (rounding to odd?), convert, and double.
+	//	otherwise, halve (x -> (x>>1)|(x&1)), convert, and double.
 	/*
 	 * integer to float
 	 */
@@ -495,9 +496,16 @@ func gmove(f *gc.Node, t *gc.Node) {
 			gmove(&bigi, &rtmp)
 			gins(mips.AAND, &r1, &rtmp)
 			p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0)
-			p2 := gins(mips.ASRLV, nil, &r1)
+			var r3 gc.Node
+			gc.Regalloc(&r3, gc.Types[gc.TUINT64], nil)
+			p2 := gins3(mips.AAND, nil, &r1, &r3)
 			p2.From.Type = obj.TYPE_CONST
 			p2.From.Offset = 1
+			p3 := gins(mips.ASRLV, nil, &r1)
+			p3.From.Type = obj.TYPE_CONST
+			p3.From.Offset = 1
+			gins(mips.AOR, &r3, &r1)
+			gc.Regfree(&r3)
 			gc.Patch(p1, gc.Pc)
 		}
 
@@ -562,7 +570,7 @@ hard:
 // 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 {
+func gins(as obj.As, f, t *gc.Node) *obj.Prog {
 	if as >= obj.A_ARCHSPECIFIC {
 		if x, ok := f.IntLiteral(); ok {
 			ginscon(as, x, t)
@@ -577,7 +585,7 @@ func gins(as int, f, t *gc.Node) *obj.Prog {
  *	as f, r, t
  * r must be register, if not nil
  */
-func gins3(as int, f, r, t *gc.Node) *obj.Prog {
+func gins3(as obj.As, f, r, t *gc.Node) *obj.Prog {
 	p := rawgins(as, f, t)
 	if r != nil {
 		p.Reg = r.Reg
@@ -589,7 +597,7 @@ func gins3(as int, f, r, t *gc.Node) *obj.Prog {
  * generate one instruction:
  *	as f, t
  */
-func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
 	// TODO(austin): Add self-move test like in 6g (but be careful
 	// of truncation moves)
 
@@ -684,7 +692,7 @@ func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
 /*
  * return Axxx for Oxxx on type t.
  */
-func optoas(op gc.Op, t *gc.Type) int {
+func optoas(op gc.Op, t *gc.Type) obj.As {
 	if t == nil {
 		gc.Fatalf("optoas: t is nil")
 	}
@@ -712,10 +720,10 @@ func optoas(op gc.Op, t *gc.Type) int {
 		OHMUL_  = uint32(gc.OHMUL) << 16
 	)
 
-	a := int(obj.AXXX)
+	a := obj.AXXX
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
+		gc.Fatalf("optoas: no entry for op=%s type=%v", op, t)
 
 	case OEQ_ | gc.TBOOL,
 		OEQ_ | gc.TINT8,
@@ -1055,7 +1063,7 @@ func sudoclean() {
  * after successful sudoaddable,
  * to release the register used for a.
  */
-func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
+func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
 	// TODO(minux)
 
 	*a = obj.Addr{}
diff --git a/src/cmd/compile/internal/mips64/peep.go b/src/cmd/compile/internal/mips64/peep.go
index f97be60..6bb5158 100644
--- a/src/cmd/compile/internal/mips64/peep.go
+++ b/src/cmd/compile/internal/mips64/peep.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -40,7 +40,7 @@ import (
 var gactive uint32
 
 func peep(firstp *obj.Prog) {
-	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	g := gc.Flowstart(firstp, nil)
 	if g == nil {
 		return
 	}
@@ -62,7 +62,7 @@ loop1:
 		// 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
+		// breaking moves that do care. This might let us
 		// simplify or remove the next peep loop, too.
 		if p.As == mips.AMOVV || p.As == mips.AMOVF || p.As == mips.AMOVD {
 			if regtyp(&p.To) {
@@ -81,7 +81,7 @@ loop1:
 
 				// Convert uses to $0 to uses of R0 and
 				// propagate R0
-				if regzer(&p.From) != 0 {
+				if regzer(&p.From) {
 					if p.To.Type == obj.TYPE_REG && !isfreg(&p.To) {
 						p.From.Type = obj.TYPE_REG
 						p.From.Reg = mips.REGZERO
@@ -107,7 +107,7 @@ loop1:
 	 */
 	var p1 *obj.Prog
 	var r1 *gc.Flow
-	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
 		default:
@@ -145,7 +145,7 @@ loop1:
 }
 
 func excise(r *gc.Flow) {
-	p := (*obj.Prog)(r.Prog)
+	p := r.Prog
 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("%v ===delete===\n", p)
 	}
@@ -153,23 +153,16 @@ func excise(r *gc.Flow) {
 	gc.Ostats.Ndelmov++
 }
 
-/*
- * regzer returns 1 if a's value is 0 (a is R0 or $0)
- */
-func regzer(a *obj.Addr) int {
+// regzer returns true if a's value is 0 (a is R0 or $0)
+func regzer(a *obj.Addr) bool {
 	if a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_ADDR {
 		if a.Sym == nil && a.Reg == 0 {
 			if a.Offset == 0 {
-				return 1
+				return true
 			}
 		}
 	}
-	if a.Type == obj.TYPE_REG {
-		if a.Reg == mips.REGZERO {
-			return 1
-		}
-	}
-	return 0
+	return a.Type == obj.TYPE_REG && a.Reg == mips.REGZERO
 }
 
 func regtyp(a *obj.Addr) bool {
@@ -199,12 +192,12 @@ func isfreg(a *obj.Addr) bool {
  * 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)
+	p := r0.Prog
+	v1 := &p.From
 	if !regtyp(v1) {
 		return false
 	}
-	v2 := (*obj.Addr)(&p.To)
+	v2 := &p.To
 	if !regtyp(v2) {
 		return false
 	}
@@ -223,7 +216,7 @@ func subprop(r0 *gc.Flow) bool {
 		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)
+					copysub(&p.To, v1, v2, true)
 					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 {
@@ -234,17 +227,15 @@ func subprop(r0 *gc.Flow) bool {
 
 					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)
+						copysub(&p.From, v1, v2, true)
+						copysub1(p, v1, v2, true)
+						copysub(&p.To, v1, v2, true)
 						if gc.Debug['P'] != 0 {
 							fmt.Printf("%v\n", r.Prog)
 						}
 					}
 
-					t := int(int(v1.Reg))
-					v1.Reg = v2.Reg
-					v2.Reg = int16(t)
+					v1.Reg, v2.Reg = v2.Reg, v1.Reg
 					if gc.Debug['P'] != 0 {
 						fmt.Printf("%v last\n", r.Prog)
 					}
@@ -256,7 +247,7 @@ func subprop(r0 *gc.Flow) bool {
 		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 {
+		if copysub(&p.From, v1, v2, false) || copysub1(p, v1, v2, false) || copysub(&p.To, v1, v2, false) {
 			break
 		}
 	}
@@ -277,9 +268,9 @@ func subprop(r0 *gc.Flow) bool {
  *	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)
+	p := r0.Prog
+	v1 := &p.From
+	v2 := &p.To
 	if copyas(v1, v2) {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("eliminating self-move: %v\n", r0.Prog)
@@ -291,12 +282,12 @@ func copyprop(r0 *gc.Flow) bool {
 	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)
+	return copy1(v1, v2, r0.S1, false)
 }
 
-// copy1 replaces uses of v2 with v1 starting at r and returns 1 if
+// copy1 replaces uses of v2 with v1 starting at r and returns true if
 // all uses were rewritten.
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
 	if uint32(r.Active) == gactive {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("act set; return 1\n")
@@ -306,27 +297,24 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 	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)
+		fmt.Printf("copy1 replace %v with %v f=%v\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
+		p := r.Prog
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("%v", p)
 		}
-		if f == 0 && gc.Uniqp(r) == nil {
+		if !f && gc.Uniqp(r) == nil {
 			// Multiple predecessors; conservatively
 			// assume v1 was set on other path
-			f = 1
+			f = true
 
 			if gc.Debug['P'] != 0 {
-				fmt.Printf("; merge; f=%d", f)
+				fmt.Printf("; merge; f=%v", f)
 			}
 		}
 
-		t = copyu(p, v2, nil)
-		switch t {
+		switch t := copyu(p, v2, nil); t {
 		case 2: /* rar, can't split */
 			if gc.Debug['P'] != 0 {
 				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
@@ -341,14 +329,14 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 		case 1, /* used, substitute */
 			4: /* use and set */
-			if f != 0 {
+			if f {
 				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)
+					fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				} else {
-					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+					fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				}
 				return false
 			}
@@ -371,12 +359,12 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 
-		if f == 0 {
-			t = copyu(p, v1, nil)
-			if f == 0 && (t == 2 || t == 3 || t == 4) {
-				f = 1
+		if !f {
+			t := copyu(p, v1, nil)
+			if t == 2 || t == 3 || t == 4 {
+				f = true
 				if gc.Debug['P'] != 0 {
-					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+					fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
 				}
 			}
 		}
@@ -414,7 +402,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 
 	switch p.As {
 	default:
-		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
 		return 2
 
 	case obj.ANOP, /* read p->from, write p->to */
@@ -442,13 +430,13 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		mips.ATRUNCFW,
 		mips.ATRUNCDW:
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
 
 			// Update only indirect uses of v in p->to
 			if !copyas(&p.To, v) {
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 			}
@@ -508,16 +496,16 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		mips.ADIVF,
 		mips.ADIVD:
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
-			if copysub1(p, v, s, 1) != 0 {
+			if copysub1(p, v, s, true) {
 				return 1
 			}
 
 			// Update only indirect uses of v in p->to
 			if !copyas(&p.To, v) {
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 			}
@@ -578,10 +566,13 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		mips.ADIVV,
 		mips.ADIVVU:
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
-			return copysub1(p, v, s, 1)
+			if copysub1(p, v, s, true) {
+				return 1
+			}
+			return 0
 		}
 
 		if copyau(&p.From, v) {
@@ -594,7 +585,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 
 	case mips.AJMP: /* read p->to */
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -637,7 +628,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		}
 
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -697,7 +688,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 // 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
+// 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) {
@@ -714,7 +705,7 @@ func copyas(a *obj.Addr, v *obj.Addr) bool {
 // 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
+// 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 {
@@ -731,37 +722,30 @@ func copyau(a *obj.Addr, v *obj.Addr) bool {
 	return false
 }
 
-// copyau1 returns 1 if p->reg references the same register as v and v
+// copyau1 returns true 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
+	return regtyp(v) && v.Reg != 0 && p.Reg == v.Reg
 }
 
-// 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 mips).
-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
-		}
+// copysub replaces v with s in a if f==true or indicates it if could if f==false.
+// Returns true on failure to substitute (it always succeeds on mips).
+// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
+	if f && copyau(a, v) {
+		a.Reg = s.Reg
 	}
-	return 0
+	return false
 }
 
-// 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 mips).
-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
-		}
+// copysub1 replaces v with s in p1->reg if f==true or indicates if it could if f==false.
+// Returns true on failure to substitute (it always succeeds on mips).
+// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
+func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f bool) bool {
+	if f && copyau1(p1, v) {
+		p1.Reg = s.Reg
 	}
-	return 0
+	return false
 }
 
 func sameaddr(a *obj.Addr, v *obj.Addr) bool {
diff --git a/src/cmd/compile/internal/mips64/prog.go b/src/cmd/compile/internal/mips64/prog.go
index b07c7fe..caf8482 100644
--- a/src/cmd/compile/internal/mips64/prog.go
+++ b/src/cmd/compile/internal/mips64/prog.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -24,7 +24,7 @@ const (
 // size variants of an operation even if we just use a subset.
 //
 // The table is formatted for 8-space tabs.
-var progtable = [mips.ALAST]obj.ProgInfo{
+var progtable = [mips.ALAST & obj.AMask]obj.ProgInfo{
 	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
 	obj.ATEXT:     {Flags: gc.Pseudo},
 	obj.AFUNCDATA: {Flags: gc.Pseudo},
@@ -41,103 +41,103 @@ var progtable = [mips.ALAST]obj.ProgInfo{
 	obj.ANOP: {Flags: gc.LeftRead | gc.RightWrite},
 
 	// Integer
-	mips.AADD:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AADDU:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AADDV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AADDVU: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASUB:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASUBU:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASUBV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASUBVU: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AAND:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AOR:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AXOR:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ANOR:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AMUL:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
-	mips.AMULU:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
-	mips.AMULV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
-	mips.AMULVU: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
-	mips.ADIV:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
-	mips.ADIVU:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
-	mips.ADIVV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
-	mips.ADIVVU: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
-	mips.AREM:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
-	mips.AREMU:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
-	mips.AREMV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
-	mips.AREMVU: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
-	mips.ASLL:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASLLV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASRA:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASRAV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASRL:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASRLV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASGT:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASGTU:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AADD & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AADDU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AADDV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AADDVU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASUB & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASUBU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASUBV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASUBVU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AAND & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AOR & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AXOR & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ANOR & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AMUL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
+	mips.AMULU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
+	mips.AMULV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
+	mips.AMULVU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
+	mips.ADIV & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
+	mips.ADIVU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
+	mips.ADIVV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
+	mips.ADIVVU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
+	mips.AREM & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
+	mips.AREMU & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
+	mips.AREMV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
+	mips.AREMVU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
+	mips.ASLL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASLLV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASRA & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASRAV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASRL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASRLV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASGT & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASGTU & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
 
 	// Floating point.
-	mips.AADDF:    {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AADDD:    {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASUBF:    {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ASUBD:    {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AMULF:    {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AMULD:    {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ADIVF:    {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.ADIVD:    {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	mips.AABSF:    {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite},
-	mips.AABSD:    {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
-	mips.ANEGF:    {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite},
-	mips.ANEGD:    {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
-	mips.ACMPEQF:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead},
-	mips.ACMPEQD:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead},
-	mips.ACMPGTF:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead},
-	mips.ACMPGTD:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead},
-	mips.ACMPGEF:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead},
-	mips.ACMPGED:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead},
-	mips.AMOVFD:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.AMOVDF:   {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.AMOVFW:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.AMOVWF:   {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.AMOVDW:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.AMOVWD:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.AMOVFV:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.AMOVVF:   {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.AMOVDV:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.AMOVVD:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.ATRUNCFW: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.ATRUNCDW: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.ATRUNCFV: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
-	mips.ATRUNCDV: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AADDF & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AADDD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASUBF & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ASUBD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AMULF & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AMULD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ADIVF & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.ADIVD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	mips.AABSF & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite},
+	mips.AABSD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
+	mips.ANEGF & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite},
+	mips.ANEGD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
+	mips.ACMPEQF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead},
+	mips.ACMPEQD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead},
+	mips.ACMPGTF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead},
+	mips.ACMPGTD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead},
+	mips.ACMPGEF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead},
+	mips.ACMPGED & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead},
+	mips.AMOVFD & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AMOVDF & obj.AMask:   {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AMOVFW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AMOVWF & obj.AMask:   {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AMOVDW & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AMOVWD & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AMOVFV & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AMOVVF & obj.AMask:   {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AMOVDV & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.AMOVVD & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.ATRUNCFW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.ATRUNCDW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.ATRUNCFV & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	mips.ATRUNCDV & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
 
 	// Moves
-	mips.AMOVB:  {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	mips.AMOVBU: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	mips.AMOVH:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	mips.AMOVHU: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	mips.AMOVW:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	mips.AMOVWU: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	mips.AMOVV:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	mips.AMOVF:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	mips.AMOVD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+	mips.AMOVB & obj.AMask:  {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	mips.AMOVBU & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	mips.AMOVH & obj.AMask:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	mips.AMOVHU & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	mips.AMOVW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	mips.AMOVWU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	mips.AMOVV & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
+	mips.AMOVF & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	mips.AMOVD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
 
 	// Jumps
-	mips.AJMP:     {Flags: gc.Jump | gc.Break},
-	mips.AJAL:     {Flags: gc.Call},
-	mips.ABEQ:     {Flags: gc.Cjmp},
-	mips.ABNE:     {Flags: gc.Cjmp},
-	mips.ABGEZ:    {Flags: gc.Cjmp},
-	mips.ABLTZ:    {Flags: gc.Cjmp},
-	mips.ABGTZ:    {Flags: gc.Cjmp},
-	mips.ABLEZ:    {Flags: gc.Cjmp},
-	mips.ABFPF:    {Flags: gc.Cjmp},
-	mips.ABFPT:    {Flags: gc.Cjmp},
-	mips.ARET:     {Flags: gc.Break},
-	obj.ADUFFZERO: {Flags: gc.Call},
-	obj.ADUFFCOPY: {Flags: gc.Call},
+	mips.AJMP & obj.AMask:  {Flags: gc.Jump | gc.Break},
+	mips.AJAL & obj.AMask:  {Flags: gc.Call},
+	mips.ABEQ & obj.AMask:  {Flags: gc.Cjmp},
+	mips.ABNE & obj.AMask:  {Flags: gc.Cjmp},
+	mips.ABGEZ & obj.AMask: {Flags: gc.Cjmp},
+	mips.ABLTZ & obj.AMask: {Flags: gc.Cjmp},
+	mips.ABGTZ & obj.AMask: {Flags: gc.Cjmp},
+	mips.ABLEZ & obj.AMask: {Flags: gc.Cjmp},
+	mips.ABFPF & obj.AMask: {Flags: gc.Cjmp},
+	mips.ABFPT & obj.AMask: {Flags: gc.Cjmp},
+	mips.ARET & obj.AMask:  {Flags: gc.Break},
+	obj.ADUFFZERO:          {Flags: gc.Call},
+	obj.ADUFFCOPY:          {Flags: gc.Call},
 }
 
 func proginfo(p *obj.Prog) {
 	info := &p.Info
-	*info = progtable[p.As]
+	*info = progtable[p.As&obj.AMask]
 	if info.Flags == 0 {
 		gc.Fatalf("proginfo: unknown instruction %v", p)
 	}
diff --git a/src/cmd/compile/internal/mips64/reg.go b/src/cmd/compile/internal/mips64/reg.go
index 5c46588..2d2a773 100644
--- a/src/cmd/compile/internal/mips64/reg.go
+++ b/src/cmd/compile/internal/mips64/reg.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -111,7 +111,7 @@ func regnames(n *int) []string {
 
 func excludedregs() uint64 {
 	// Exclude registers with fixed functions
-	regbits := uint64(1<<0 | RtoB(mips.REGSP) | RtoB(mips.REGG) | RtoB(mips.REGTMP) | RtoB(mips.REGLINK) | RtoB(mips.REG_R26) | RtoB(mips.REG_R27))
+	regbits := 1<<0 | RtoB(mips.REGSP) | RtoB(mips.REGG) | RtoB(mips.REGSB) | RtoB(mips.REGTMP) | RtoB(mips.REGLINK) | RtoB(mips.REG_R26) | RtoB(mips.REG_R27)
 
 	// Also exclude floating point registers with fixed constants
 	regbits |= RtoB(mips.FREGZERO) | RtoB(mips.FREGHALF) | RtoB(mips.FREGONE) | RtoB(mips.FREGTWO)
diff --git a/src/cmd/compile/internal/ppc64/cgen.go b/src/cmd/compile/internal/ppc64/cgen.go
index 740e64c..f4cc9c4 100644
--- a/src/cmd/compile/internal/ppc64/cgen.go
+++ b/src/cmd/compile/internal/ppc64/cgen.go
@@ -17,7 +17,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// for example moving [4]byte must use 4 MOVB not 1 MOVW.
 	align := int(n.Type.Align)
 
-	var op int
+	var op obj.As
 	switch align {
 	default:
 		gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
@@ -44,7 +44,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 	// the src and dst overlap, then reverse direction
 	dir := align
 
-	if osrc < odst && int64(odst) < int64(osrc)+w {
+	if osrc < odst && odst < osrc+w {
 		dir = -dir
 	}
 
@@ -123,7 +123,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 		// 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
+		// ADDs. That will produce shorter, more
 		// pipeline-able code.
 		var p *obj.Prog
 		for ; c > 0; c-- {
diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go
index 2bd49fd..a83dff9 100644
--- a/src/cmd/compile/internal/ppc64/galign.go
+++ b/src/cmd/compile/internal/ppc64/galign.go
@@ -10,51 +10,18 @@ import (
 	"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{
-	{"int", gc.TINT, gc.TINT64},
-	{"uint", gc.TUINT, gc.TUINT64},
-	{"uintptr", gc.TUINTPTR, gc.TUINT64},
-}
-
 func betypeinit() {
-	gc.Widthptr = 8
-	gc.Widthint = 8
-	gc.Widthreg = 8
-
-	if gc.Ctxt.Flag_shared != 0 {
+	if gc.Ctxt.Flag_shared {
 		gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R2)
 		gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R12)
 	}
 }
 
 func Main() {
-	gc.Thearch.Thechar = thechar
-	gc.Thearch.Thestring = thestring
-	gc.Thearch.Thelinkarch = thelinkarch
-	gc.Thearch.Typedefs = typedefs
+	gc.Thearch.LinkArch = &ppc64.Linkppc64
+	if obj.Getgoarch() == "ppc64le" {
+		gc.Thearch.LinkArch = &ppc64.Linkppc64le
+	}
 	gc.Thearch.REGSP = ppc64.REGSP
 	gc.Thearch.REGCTXT = ppc64.REGCTXT
 	gc.Thearch.REGCALLX = ppc64.REG_R3
@@ -64,7 +31,7 @@ func Main() {
 	gc.Thearch.REGMAX = ppc64.REG_R31
 	gc.Thearch.FREGMIN = ppc64.REG_F0
 	gc.Thearch.FREGMAX = ppc64.REG_F31
-	gc.Thearch.MAXWIDTH = MAXWIDTH
+	gc.Thearch.MAXWIDTH = 1 << 50
 	gc.Thearch.ReservedRegs = resvd
 
 	gc.Thearch.Betypeinit = betypeinit
@@ -81,7 +48,6 @@ func Main() {
 	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
@@ -100,6 +66,9 @@ func Main() {
 	gc.Thearch.Doregbits = doregbits
 	gc.Thearch.Regnames = regnames
 
+	initvariants()
+	initproginfo()
+
 	gc.Main()
 	gc.Exit(0)
 }
diff --git a/src/cmd/compile/internal/ppc64/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go
index 28fcecf..a89ed8f 100644
--- a/src/cmd/compile/internal/ppc64/ggen.go
+++ b/src/cmd/compile/internal/ppc64/ggen.go
@@ -12,12 +12,10 @@ import (
 )
 
 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)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 	ptxt.To.Offset = int64(frame)
 
@@ -30,8 +28,7 @@ func defframe(ptxt *obj.Prog) {
 	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
+	for _, n := range gc.Curfn.Func.Dcl {
 		if !n.Name.Needzero {
 			continue
 		}
@@ -39,7 +36,7 @@ func defframe(ptxt *obj.Prog) {
 			gc.Fatalf("needzero class %d", n.Class)
 		}
 		if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
-			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
+			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
 		}
 
 		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
@@ -96,15 +93,15 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
 	return p
 }
 
-func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
+func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
 	q := gc.Ctxt.NewProg()
 	gc.Clearp(q)
-	q.As = int16(as)
+	q.As = as
 	q.Lineno = p.Lineno
-	q.From.Type = int16(ftype)
+	q.From.Type = ftype
 	q.From.Reg = int16(freg)
 	q.From.Offset = foffset
-	q.To.Type = int16(ttype)
+	q.To.Type = ttype
 	q.To.Reg = int16(treg)
 	q.To.Offset = toffset
 	q.Link = p.Link
@@ -133,23 +130,23 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	// 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,
+	// DIVW will leave unpredictable result in higher 32-bit,
 	// so always use DIVD/DIVDU.
 	t := nl.Type
 
 	t0 := t
 	check := false
-	if gc.Issigned[t.Etype] {
+	if t.IsSigned() {
 		check = true
-		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
+		if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -(1<<uint64(t.Width*8-1)) {
 			check = false
-		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
 			check = false
 		}
 	}
 
 	if t.Width < 8 {
-		if gc.Issigned[t.Etype] {
+		if t.IsSigned() {
 			t = gc.Types[gc.TINT64]
 		} else {
 			t = gc.Types[gc.TUINT64]
@@ -254,8 +251,8 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
 		nl, nr = nr, nl
 	}
 
-	t := (*gc.Type)(nl.Type)
-	w := int(int(t.Width * 8))
+	t := nl.Type
+	w := t.Width * 8
 	var n1 gc.Node
 	gc.Cgenr(nl, &n1, res)
 	var n2 gc.Node
@@ -265,21 +262,21 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
 		gc.TINT16,
 		gc.TINT32:
 		gins(optoas(gc.OMUL, t), &n2, &n1)
-		p := (*obj.Prog)(gins(ppc64.ASRAD, nil, &n1))
+		p := gins(ppc64.ASRAD, nil, &n1)
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(w)
+		p.From.Offset = w
 
 	case gc.TUINT8,
 		gc.TUINT16,
 		gc.TUINT32:
 		gins(optoas(gc.OMUL, t), &n2, &n1)
-		p := (*obj.Prog)(gins(ppc64.ASRD, nil, &n1))
+		p := gins(ppc64.ASRD, nil, &n1)
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(w)
+		p.From.Offset = w
 
 	case gc.TINT64,
 		gc.TUINT64:
-		if gc.Issigned[t.Etype] {
+		if t.IsSigned() {
 			gins(ppc64.AMULHD, &n2, &n1)
 		} else {
 			gins(ppc64.AMULHDU, &n2, &n1)
@@ -300,13 +297,13 @@ func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
  *	res = nl >> nr
  */
 func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
-	a := int(optoas(op, nl.Type))
+	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())
+		sc := uint64(nr.Int64())
 		if sc >= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
 			var n3 gc.Node
@@ -369,8 +366,8 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 	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] {
+		p1 := gc.Gbranch(optoas(gc.OLT, tcount), nil, +1)
+		if op == gc.ORSH && nl.Type.IsSigned() {
 			gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
 			gins(a, &n3, &n2)
 		} else {
@@ -395,15 +392,15 @@ func clearfat(nl *gc.Node) {
 		fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
 	}
 
-	w := uint64(uint64(nl.Type.Width))
+	w := 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
+	c := w % 8 // bytes
+	q := w / 8 // dwords
 
 	if gc.Reginuse(ppc64.REGRT1) {
 		gc.Fatalf("%v in use during clearfat", obj.Rconv(ppc64.REGRT1))
@@ -431,7 +428,7 @@ func clearfat(nl *gc.Node) {
 		p = gins(ppc64.AMOVDU, &r0, &dst)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Offset = 8
-		pl := (*obj.Prog)(p)
+		pl := p
 
 		p = gins(ppc64.ACMP, &dst, &end)
 		gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl)
@@ -444,7 +441,7 @@ func clearfat(nl *gc.Node) {
 		p := gins(ppc64.ASUB, nil, &dst)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 8
-		f := (*gc.Node)(gc.Sysfunc("duffzero"))
+		f := gc.Sysfunc("duffzero")
 		p = gins(obj.ADUFFZERO, nil, f)
 		gc.Afunclit(&p.To, f)
 
@@ -480,7 +477,7 @@ func expandchecks(firstp *obj.Prog) {
 	var p1 *obj.Prog
 	var p2 *obj.Prog
 
-	for p := (*obj.Prog)(firstp); p != nil; p = p.Link {
+	for p := firstp; p != nil; p = p.Link {
 		if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
 			fmt.Printf("expandchecks: %v\n", p)
 		}
@@ -488,7 +485,7 @@ func expandchecks(firstp *obj.Prog) {
 			continue
 		}
 		if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
-			gc.Warnl(int(p.Lineno), "generated nil check")
+			gc.Warnl(p.Lineno, "generated nil check")
 		}
 		if p.From.Type != obj.TYPE_REG {
 			gc.Fatalf("invalid nil check %v\n", p)
diff --git a/src/cmd/compile/internal/ppc64/gsubr.go b/src/cmd/compile/internal/ppc64/gsubr.go
index 534ea62..f875999 100644
--- a/src/cmd/compile/internal/ppc64/gsubr.go
+++ b/src/cmd/compile/internal/ppc64/gsubr.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -42,9 +42,9 @@ 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
+	// 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,
+	// won't know which convention to use. By preserving REGTLS,
 	// we can just retrieve g from TLS when we aren't sure.
 	ppc64.REGTLS,
 
@@ -62,7 +62,7 @@ var resvd = []int{
  * generate
  *	as $c, n
  */
-func ginscon(as int, c int64, n2 *gc.Node) {
+func ginscon(as obj.As, c int64, n2 *gc.Node) {
 	var n1 gc.Node
 
 	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
@@ -86,7 +86,7 @@ func ginscon(as int, c int64, n2 *gc.Node) {
  * generate
  *	as n, $c (CMP/CMPU)
  */
-func ginscon2(as int, n2 *gc.Node, c int64) {
+func ginscon2(as obj.As, n2 *gc.Node, c int64) {
 	var n1 gc.Node
 
 	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
@@ -118,7 +118,7 @@ func ginscon2(as int, n2 *gc.Node, c int64) {
 }
 
 func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
-	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
+	if t.IsInteger() && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
 		// Reverse comparison to place constant last.
 		op = gc.Brrev(op)
 		n1, n2 = n2, n1
@@ -129,8 +129,8 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 	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())
+	if t.IsInteger() && gc.Isconst(n2, gc.CTINT) {
+		ginscon2(optoas(gc.OCMP, t), &r1, n2.Int64())
 	} else {
 		gc.Regalloc(&r2, t, n2)
 		gc.Regalloc(&g2, n1.Type, &r2)
@@ -175,12 +175,12 @@ func bignodes() {
  */
 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))
+		fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
 	}
 
 	ft := int(gc.Simsimtype(f.Type))
 	tt := int(gc.Simsimtype(t.Type))
-	cvt := (*gc.Type)(t.Type)
+	cvt := t.Type
 
 	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
 		gc.Complexmove(f, t)
@@ -190,7 +190,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 	// cannot have two memory operands
 	var r2 gc.Node
 	var r1 gc.Node
-	var a int
+	var a obj.As
 	if gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
 	}
@@ -261,7 +261,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
-		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong))
+		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
 
 		/*
 		 * integer copy and truncate
@@ -409,7 +409,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 			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))
+			p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1)
 			gins(ppc64.AFSUB, &r2, &r1)
 			gc.Patch(p1, gc.Pc)
 			gc.Regfree(&r2)
@@ -419,7 +419,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 		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 := gins(ppc64.AFMOVD, &r2, nil)
 		p1.To.Type = obj.TYPE_MEM
 		p1.To.Reg = ppc64.REGSP
 		p1.To.Offset = -8
@@ -430,7 +430,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 		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
+			p1 := 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)
@@ -441,11 +441,6 @@ func gmove(f *gc.Node, t *gc.Node) {
 		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
 	 */
@@ -467,6 +462,10 @@ func gmove(f *gc.Node, t *gc.Node) {
 		gc.TUINT64<<16 | gc.TFLOAT64:
 		bignodes()
 
+		// The algorithm is:
+		//	if small enough, use native int64 -> float64 conversion,
+		//	otherwise halve (x -> (x>>1)|(x&1)), convert, and double.
+		// Note: could use FCFIDU instead if target supports it.
 		var r1 gc.Node
 		gc.Regalloc(&r1, gc.Types[gc.TINT64], nil)
 		gmove(f, &r1)
@@ -474,15 +473,22 @@ func gmove(f *gc.Node, t *gc.Node) {
 			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))
+			p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1)
+			var r3 gc.Node
+			gc.Regalloc(&r3, gc.Types[gc.TUINT64], nil)
+			p2 := gins(ppc64.AANDCC, nil, &r3) // andi.
+			p2.Reg = r1.Reg
 			p2.From.Type = obj.TYPE_CONST
 			p2.From.Offset = 1
+			p3 := gins(ppc64.ASRD, nil, &r1)
+			p3.From.Type = obj.TYPE_CONST
+			p3.From.Offset = 1
+			gins(ppc64.AOR, &r3, &r1)
+			gc.Regfree(&r3)
 			gc.Patch(p1, gc.Pc)
 		}
-
 		gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
-		p1 := (*obj.Prog)(gins(ppc64.AMOVD, &r1, nil))
+		p1 := gins(ppc64.AMOVD, &r1, nil)
 		p1.To.Type = obj.TYPE_MEM
 		p1.To.Reg = ppc64.REGSP
 		p1.To.Offset = -8
@@ -493,12 +499,11 @@ func gmove(f *gc.Node, t *gc.Node) {
 		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
+			p1 := 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
@@ -548,7 +553,7 @@ hard:
 // 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 {
+func gins(as obj.As, f, t *gc.Node) *obj.Prog {
 	if as >= obj.A_ARCHSPECIFIC {
 		if x, ok := f.IntLiteral(); ok {
 			ginscon(as, x, t)
@@ -568,7 +573,7 @@ func gins(as int, f, t *gc.Node) *obj.Prog {
  * generate one instruction:
  *	as f, t
  */
-func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
 	// TODO(austin): Add self-move test like in 6g (but be careful
 	// of truncation moves)
 
@@ -580,7 +585,7 @@ func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
 	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.
-			if gc.Ctxt.Flag_shared != 0 {
+			if gc.Ctxt.Flag_shared {
 				// Make sure function pointer is in R12 as well when
 				// compiling Go into PIC.
 				// TODO(mwhudson): it would obviously be better to
@@ -602,7 +607,7 @@ func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = ppc64.REG_CTR
 
-			if gc.Ctxt.Flag_shared != 0 {
+			if gc.Ctxt.Flag_shared {
 				// When compiling Go into PIC, the function we just
 				// called via pointer might have been implemented in
 				// a separate module and so overwritten the TOC
@@ -680,7 +685,7 @@ func rawgins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
 /*
  * return Axxx for Oxxx on type t.
  */
-func optoas(op gc.Op, t *gc.Type) int {
+func optoas(op gc.Op, t *gc.Type) obj.As {
 	if t == nil {
 		gc.Fatalf("optoas: t is nil")
 	}
@@ -706,12 +711,13 @@ func optoas(op gc.Op, t *gc.Type) int {
 		OCMP_   = uint32(gc.OCMP) << 16
 		OAS_    = uint32(gc.OAS) << 16
 		OHMUL_  = uint32(gc.OHMUL) << 16
+		OSQRT_  = uint32(gc.OSQRT) << 16
 	)
 
-	a := int(obj.AXXX)
+	a := obj.AXXX
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatalf("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), t)
+		gc.Fatalf("optoas: no entry for op=%v type=%v", op, t)
 
 	case OEQ_ | gc.TBOOL,
 		OEQ_ | gc.TINT8,
@@ -1028,6 +1034,9 @@ func optoas(op gc.Op, t *gc.Type) int {
 
 	case ODIV_ | gc.TFLOAT64:
 		a = ppc64.AFDIV
+
+	case OSQRT_ | gc.TFLOAT64:
+		a = ppc64.AFSQRT
 	}
 
 	return a
@@ -1059,7 +1068,7 @@ func sudoclean() {
  * after successful sudoaddable,
  * to release the register used for a.
  */
-func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
+func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
 	// TODO(minux)
 
 	*a = obj.Addr{}
diff --git a/src/cmd/compile/internal/ppc64/opt.go b/src/cmd/compile/internal/ppc64/opt.go
index 1704f63..4f81aa9 100644
--- a/src/cmd/compile/internal/ppc64/opt.go
+++ b/src/cmd/compile/internal/ppc64/opt.go
@@ -1,11 +1,11 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
+// 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
index 1ff3109..6efe0b7 100644
--- a/src/cmd/compile/internal/ppc64/peep.go
+++ b/src/cmd/compile/internal/ppc64/peep.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -40,7 +40,7 @@ import (
 var gactive uint32
 
 func peep(firstp *obj.Prog) {
-	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	g := gc.Flowstart(firstp, nil)
 	if g == nil {
 		return
 	}
@@ -48,7 +48,7 @@ func peep(firstp *obj.Prog) {
 
 	var p *obj.Prog
 	var r *gc.Flow
-	var t int
+	var t obj.As
 loop1:
 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		gc.Dumpit("loop1", g.Start, 0)
@@ -62,7 +62,7 @@ loop1:
 		// 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
+		// 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) {
@@ -81,7 +81,7 @@ loop1:
 
 				// Convert uses to $0 to uses of R0 and
 				// propagate R0
-				if regzer(&p.From) != 0 {
+				if regzer(&p.From) {
 					if p.To.Type == obj.TYPE_REG {
 						p.From.Type = obj.TYPE_REG
 						p.From.Reg = ppc64.REGZERO
@@ -107,7 +107,7 @@ loop1:
 	 */
 	var p1 *obj.Prog
 	var r1 *gc.Flow
-	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
 		default:
@@ -149,12 +149,12 @@ loop1:
 	 * 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 {
+	for r := 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 {
+			if !regzer(&p.To) {
 				continue
 			}
 			r1 = r.S1
@@ -328,13 +328,13 @@ loop1:
 				ppc64.ASUBZE,
 				ppc64.ASUBZEV,
 				ppc64.AXOR:
-				t = variant2as(int(p1.As), as2variant(int(p1.As))|V_CC)
+				t = variant2as(p1.As, as2variant(p1.As)|V_CC)
 			}
 
 			if gc.Debug['D'] != 0 {
 				fmt.Printf("cmp %v; %v -> ", p1, p)
 			}
-			p1.As = int16(t)
+			p1.As = t
 			if gc.Debug['D'] != 0 {
 				fmt.Printf("%v\n", p1)
 			}
@@ -348,7 +348,7 @@ ret:
 }
 
 func excise(r *gc.Flow) {
-	p := (*obj.Prog)(r.Prog)
+	p := r.Prog
 	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("%v ===delete===\n", p)
 	}
@@ -356,23 +356,16 @@ func excise(r *gc.Flow) {
 	gc.Ostats.Ndelmov++
 }
 
-/*
- * regzer returns 1 if a's value is 0 (a is R0 or $0)
- */
-func regzer(a *obj.Addr) int {
+// regzer returns true if a's value is 0 (a is R0 or $0)
+func regzer(a *obj.Addr) bool {
 	if a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_ADDR {
 		if a.Sym == nil && a.Reg == 0 {
 			if a.Offset == 0 {
-				return 1
+				return true
 			}
 		}
 	}
-	if a.Type == obj.TYPE_REG {
-		if a.Reg == ppc64.REGZERO {
-			return 1
-		}
-	}
-	return 0
+	return a.Type == obj.TYPE_REG && a.Reg == ppc64.REGZERO
 }
 
 func regtyp(a *obj.Addr) bool {
@@ -398,12 +391,12 @@ func regtyp(a *obj.Addr) bool {
  * 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)
+	p := r0.Prog
+	v1 := &p.From
 	if !regtyp(v1) {
 		return false
 	}
-	v2 := (*obj.Addr)(&p.To)
+	v2 := &p.To
 	if !regtyp(v2) {
 		return false
 	}
@@ -422,7 +415,7 @@ func subprop(r0 *gc.Flow) bool {
 		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)
+					copysub(&p.To, v1, v2, true)
 					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 {
@@ -433,17 +426,15 @@ func subprop(r0 *gc.Flow) bool {
 
 					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)
+						copysub(&p.From, v1, v2, true)
+						copysub1(p, v1, v2, true)
+						copysub(&p.To, v1, v2, true)
 						if gc.Debug['P'] != 0 {
 							fmt.Printf("%v\n", r.Prog)
 						}
 					}
 
-					t := int(int(v1.Reg))
-					v1.Reg = v2.Reg
-					v2.Reg = int16(t)
+					v1.Reg, v2.Reg = v2.Reg, v1.Reg
 					if gc.Debug['P'] != 0 {
 						fmt.Printf("%v last\n", r.Prog)
 					}
@@ -455,7 +446,7 @@ func subprop(r0 *gc.Flow) bool {
 		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 {
+		if copysub(&p.From, v1, v2, false) || copysub1(p, v1, v2, false) || copysub(&p.To, v1, v2, false) {
 			break
 		}
 	}
@@ -476,9 +467,9 @@ func subprop(r0 *gc.Flow) bool {
  *	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)
+	p := r0.Prog
+	v1 := &p.From
+	v2 := &p.To
 	if copyas(v1, v2) {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("eliminating self-move: %v\n", r0.Prog)
@@ -490,12 +481,12 @@ func copyprop(r0 *gc.Flow) bool {
 	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)
+	return copy1(v1, v2, r0.S1, false)
 }
 
 // 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 {
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
 	if uint32(r.Active) == gactive {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("act set; return 1\n")
@@ -505,27 +496,24 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 	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)
+		fmt.Printf("copy1 replace %v with %v f=%v\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
+		p := r.Prog
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("%v", p)
 		}
-		if f == 0 && gc.Uniqp(r) == nil {
+		if !f && gc.Uniqp(r) == nil {
 			// Multiple predecessors; conservatively
 			// assume v1 was set on other path
-			f = 1
+			f = true
 
 			if gc.Debug['P'] != 0 {
-				fmt.Printf("; merge; f=%d", f)
+				fmt.Printf("; merge; f=%v", f)
 			}
 		}
 
-		t = copyu(p, v2, nil)
-		switch t {
+		switch t := copyu(p, v2, nil); t {
 		case 2: /* rar, can't split */
 			if gc.Debug['P'] != 0 {
 				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
@@ -540,14 +528,14 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 		case 1, /* used, substitute */
 			4: /* use and set */
-			if f != 0 {
+			if f {
 				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)
+					fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				} else {
-					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+					fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				}
 				return false
 			}
@@ -570,12 +558,12 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 
-		if f == 0 {
-			t = copyu(p, v1, nil)
-			if f == 0 && (t == 2 || t == 3 || t == 4) {
-				f = 1
+		if !f {
+			t := copyu(p, v1, nil)
+			if t == 2 || t == 3 || t == 4 {
+				f = true
 				if gc.Debug['P'] != 0 {
-					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+					fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
 				}
 			}
 		}
@@ -613,7 +601,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 
 	switch p.As {
 	default:
-		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
 		return 2
 
 	case obj.ANOP, /* read p->from, write p->to */
@@ -640,19 +628,22 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		ppc64.AFCTIDZ,
 		ppc64.AFCFID,
 		ppc64.AFCFIDCC,
+		ppc64.AFCFIDU,
+		ppc64.AFCFIDUCC,
 		ppc64.AFMOVS,
 		ppc64.AFMOVD,
 		ppc64.AFRSP,
 		ppc64.AFNEG,
-		ppc64.AFNEGCC:
+		ppc64.AFNEGCC,
+		ppc64.AFSQRT:
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
 
 			// Update only indirect uses of v in p->to
 			if !copyas(&p.To, v) {
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 			}
@@ -694,7 +685,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 			}
 
 			if s != nil {
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 				return 0
@@ -708,7 +699,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 				return 2
 			}
 			if s != nil {
-				if copysub(&p.From, v, s, 1) != 0 {
+				if copysub(&p.From, v, s, true) {
 					return 1
 				}
 				return 0
@@ -778,16 +769,16 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		ppc64.AFDIVS,
 		ppc64.AFDIV:
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
-			if copysub1(p, v, s, 1) != 0 {
+			if copysub1(p, v, s, true) {
 				return 1
 			}
 
 			// Update only indirect uses of v in p->to
 			if !copyas(&p.To, v) {
-				if copysub(&p.To, v, s, 1) != 0 {
+				if copysub(&p.To, v, s, true) {
 					return 1
 				}
 			}
@@ -840,10 +831,13 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		ppc64.AFCMPO,
 		ppc64.AFCMPU:
 		if s != nil {
-			if copysub(&p.From, v, s, 1) != 0 {
+			if copysub(&p.From, v, s, true) {
+				return 1
+			}
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
-			return copysub(&p.To, v, s, 1)
+			return 0
 		}
 
 		if copyau(&p.From, v) {
@@ -859,7 +853,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 	// mov and a branch).
 	case ppc64.ABR: /* read p->to */
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -902,12 +896,11 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		}
 
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
 		}
-
 		if copyau(&p.To, v) {
 			return 4
 		}
@@ -959,27 +952,20 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 	}
 }
 
-// copyas returns 1 if a and v address the same register.
+// copyas returns true 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
+// 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
+	return regtyp(v) && a.Type == v.Type && a.Reg == v.Reg
 }
 
-// copyau returns 1 if a either directly or indirectly addresses the
+// copyau returns true 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
+// 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 {
@@ -996,37 +982,30 @@ func copyau(a *obj.Addr, v *obj.Addr) bool {
 	return false
 }
 
-// copyau1 returns 1 if p->reg references the same register as v and v
+// copyau1 returns true 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
+	return regtyp(v) && v.Reg != 0 && p.Reg == v.Reg
 }
 
-// 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
-		}
+// copysub replaces v with s in a if f==true or indicates it if could if f==false.
+// Returns true on failure to substitute (it always succeeds on ppc64).
+// TODO(dfc) remove unused return value and callers where f=false.
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
+	if f && copyau(a, v) {
+		a.Reg = s.Reg
 	}
-	return 0
+	return false
 }
 
-// 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
-		}
+// copysub1 replaces v with s in p1->reg if f==true or indicates if it could if f==false.
+// Returns true on failure to substitute (it always succeeds on ppc64).
+// TODO(dfc) remove unused return value and callers where f=false.
+func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f bool) bool {
+	if f && copyau1(p1, v) {
+		p1.Reg = s.Reg
 	}
-	return 0
+	return false
 }
 
 func sameaddr(a *obj.Addr, v *obj.Addr) bool {
diff --git a/src/cmd/compile/internal/ppc64/prog.go b/src/cmd/compile/internal/ppc64/prog.go
index 6b48256..e2d81ae 100644
--- a/src/cmd/compile/internal/ppc64/prog.go
+++ b/src/cmd/compile/internal/ppc64/prog.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -24,7 +24,7 @@ const (
 // 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{
+var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{
 	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
 	obj.ATEXT:     {Flags: gc.Pseudo},
 	obj.AFUNCDATA: {Flags: gc.Pseudo},
@@ -41,104 +41,95 @@ var progtable = [ppc64.ALAST]obj.ProgInfo{
 	obj.ANOP: {Flags: gc.LeftRead | gc.RightWrite},
 
 	// Integer
-	ppc64.AADD:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ASUB:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ANEG:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AAND:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AOR:     {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AXOR:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AMULLD:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AMULLW:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AMULHD:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AMULHDU: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ADIVD:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ADIVDU:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ASLD:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ASRD:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ASRAD:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.ACMP:    {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
-	ppc64.ACMPU:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
-	ppc64.ATD:     {Flags: gc.SizeQ | gc.RightRead},
+	ppc64.AADD & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.ASUB & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.ANEG & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AAND & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AOR & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AXOR & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AMULLD & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AMULLW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AMULHD & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AMULHDU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.ADIVD & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.ADIVDU & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.ASLD & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.ASRD & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.ASRAD & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.ACMP & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
+	ppc64.ACMPU & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
+	ppc64.ATD & obj.AMask:     {Flags: gc.SizeQ | gc.RightRead},
 
 	// Floating point.
-	ppc64.AFADD:   {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFADDS:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFSUB:   {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFSUBS:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFMUL:   {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFMULS:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFDIV:   {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFDIVS:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFCTIDZ: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFCFID:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
-	ppc64.AFCMPU:  {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
-	ppc64.AFRSP:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	ppc64.AFADD & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFADDS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFSUB & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFSUBS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFMUL & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFMULS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFDIV & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFDIVS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFCTIDZ & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFCFID & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFCFIDU & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	ppc64.AFCMPU & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
+	ppc64.AFRSP & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	ppc64.AFSQRT & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
 
 	// Moves
-	ppc64.AMOVB:  {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	ppc64.AMOVBU: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
-	ppc64.AMOVBZ: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	ppc64.AMOVH:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	ppc64.AMOVHU: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
-	ppc64.AMOVHZ: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	ppc64.AMOVW:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	ppc64.AMOVB & obj.AMask:  {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	ppc64.AMOVBU & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
+	ppc64.AMOVBZ & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	ppc64.AMOVH & obj.AMask:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	ppc64.AMOVHU & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
+	ppc64.AMOVHZ & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	ppc64.AMOVW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
 
 	// there is no AMOVWU.
-	ppc64.AMOVWZU: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
-	ppc64.AMOVWZ:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	ppc64.AMOVD:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
-	ppc64.AMOVDU:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move | gc.PostInc},
-	ppc64.AFMOVS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
-	ppc64.AFMOVD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+	ppc64.AMOVWZU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
+	ppc64.AMOVWZ & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	ppc64.AMOVD & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
+	ppc64.AMOVDU & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move | gc.PostInc},
+	ppc64.AFMOVS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	ppc64.AFMOVD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
 
 	// Jumps
-	ppc64.ABR:     {Flags: gc.Jump | gc.Break},
-	ppc64.ABL:     {Flags: gc.Call},
-	ppc64.ABEQ:    {Flags: gc.Cjmp},
-	ppc64.ABNE:    {Flags: gc.Cjmp},
-	ppc64.ABGE:    {Flags: gc.Cjmp},
-	ppc64.ABLT:    {Flags: gc.Cjmp},
-	ppc64.ABGT:    {Flags: gc.Cjmp},
-	ppc64.ABLE:    {Flags: gc.Cjmp},
-	obj.ARET:      {Flags: gc.Break},
-	obj.ADUFFZERO: {Flags: gc.Call},
-	obj.ADUFFCOPY: {Flags: gc.Call},
+	ppc64.ABR & obj.AMask:  {Flags: gc.Jump | gc.Break},
+	ppc64.ABL & obj.AMask:  {Flags: gc.Call},
+	ppc64.ABEQ & obj.AMask: {Flags: gc.Cjmp},
+	ppc64.ABNE & obj.AMask: {Flags: gc.Cjmp},
+	ppc64.ABGE & obj.AMask: {Flags: gc.Cjmp},
+	ppc64.ABLT & obj.AMask: {Flags: gc.Cjmp},
+	ppc64.ABGT & obj.AMask: {Flags: gc.Cjmp},
+	ppc64.ABLE & obj.AMask: {Flags: gc.Cjmp},
+	obj.ARET:               {Flags: gc.Break},
+	obj.ADUFFZERO:          {Flags: gc.Call},
+	obj.ADUFFCOPY:          {Flags: gc.Call},
 }
 
-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++ {
+	for i := range progtable {
+		as := obj.As(i)
 		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]
+		variant := as2variant(as)
+		for i := range addvariant {
+			as2 := variant2as(as, variant|addvariant[i])
+			if as2 != 0 && progtable[as2&obj.AMask].Flags == 0 {
+				progtable[as2&obj.AMask] = progtable[as]
 			}
 		}
 	}
 }
 
 func proginfo(p *obj.Prog) {
-	initproginfo()
-
 	info := &p.Info
-	*info = progtable[p.As]
+	*info = progtable[p.As&obj.AMask]
 	if info.Flags == 0 {
 		gc.Fatalf("proginfo: unknown instruction %v", p)
 	}
@@ -180,136 +171,138 @@ func proginfo(p *obj.Prog) {
 	}
 }
 
-// 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:     {ppc64.AADD, ppc64.AADDCC, ppc64.AADDV, ppc64.AADDVCC},
-	ppc64.AADDC:    {ppc64.AADDC, ppc64.AADDCCC, ppc64.AADDCV, ppc64.AADDCVCC},
-	ppc64.AADDE:    {ppc64.AADDE, ppc64.AADDECC, ppc64.AADDEV, ppc64.AADDEVCC},
-	ppc64.AADDME:   {ppc64.AADDME, ppc64.AADDMECC, ppc64.AADDMEV, ppc64.AADDMEVCC},
-	ppc64.AADDZE:   {ppc64.AADDZE, ppc64.AADDZECC, ppc64.AADDZEV, ppc64.AADDZEVCC},
-	ppc64.AAND:     {ppc64.AAND, ppc64.AANDCC, 0, 0},
-	ppc64.AANDN:    {ppc64.AANDN, ppc64.AANDNCC, 0, 0},
-	ppc64.ACNTLZD:  {ppc64.ACNTLZD, ppc64.ACNTLZDCC, 0, 0},
-	ppc64.ACNTLZW:  {ppc64.ACNTLZW, ppc64.ACNTLZWCC, 0, 0},
-	ppc64.ADIVD:    {ppc64.ADIVD, ppc64.ADIVDCC, ppc64.ADIVDV, ppc64.ADIVDVCC},
-	ppc64.ADIVDU:   {ppc64.ADIVDU, ppc64.ADIVDUCC, ppc64.ADIVDUV, ppc64.ADIVDUVCC},
-	ppc64.ADIVW:    {ppc64.ADIVW, ppc64.ADIVWCC, ppc64.ADIVWV, ppc64.ADIVWVCC},
-	ppc64.ADIVWU:   {ppc64.ADIVWU, ppc64.ADIVWUCC, ppc64.ADIVWUV, ppc64.ADIVWUVCC},
-	ppc64.AEQV:     {ppc64.AEQV, ppc64.AEQVCC, 0, 0},
-	ppc64.AEXTSB:   {ppc64.AEXTSB, ppc64.AEXTSBCC, 0, 0},
-	ppc64.AEXTSH:   {ppc64.AEXTSH, ppc64.AEXTSHCC, 0, 0},
-	ppc64.AEXTSW:   {ppc64.AEXTSW, ppc64.AEXTSWCC, 0, 0},
-	ppc64.AFABS:    {ppc64.AFABS, ppc64.AFABSCC, 0, 0},
-	ppc64.AFADD:    {ppc64.AFADD, ppc64.AFADDCC, 0, 0},
-	ppc64.AFADDS:   {ppc64.AFADDS, ppc64.AFADDSCC, 0, 0},
-	ppc64.AFCFID:   {ppc64.AFCFID, ppc64.AFCFIDCC, 0, 0},
-	ppc64.AFCTID:   {ppc64.AFCTID, ppc64.AFCTIDCC, 0, 0},
-	ppc64.AFCTIDZ:  {ppc64.AFCTIDZ, ppc64.AFCTIDZCC, 0, 0},
-	ppc64.AFCTIW:   {ppc64.AFCTIW, ppc64.AFCTIWCC, 0, 0},
-	ppc64.AFCTIWZ:  {ppc64.AFCTIWZ, ppc64.AFCTIWZCC, 0, 0},
-	ppc64.AFDIV:    {ppc64.AFDIV, ppc64.AFDIVCC, 0, 0},
-	ppc64.AFDIVS:   {ppc64.AFDIVS, ppc64.AFDIVSCC, 0, 0},
-	ppc64.AFMADD:   {ppc64.AFMADD, ppc64.AFMADDCC, 0, 0},
-	ppc64.AFMADDS:  {ppc64.AFMADDS, ppc64.AFMADDSCC, 0, 0},
-	ppc64.AFMOVD:   {ppc64.AFMOVD, ppc64.AFMOVDCC, 0, 0},
-	ppc64.AFMSUB:   {ppc64.AFMSUB, ppc64.AFMSUBCC, 0, 0},
-	ppc64.AFMSUBS:  {ppc64.AFMSUBS, ppc64.AFMSUBSCC, 0, 0},
-	ppc64.AFMUL:    {ppc64.AFMUL, ppc64.AFMULCC, 0, 0},
-	ppc64.AFMULS:   {ppc64.AFMULS, ppc64.AFMULSCC, 0, 0},
-	ppc64.AFNABS:   {ppc64.AFNABS, ppc64.AFNABSCC, 0, 0},
-	ppc64.AFNEG:    {ppc64.AFNEG, ppc64.AFNEGCC, 0, 0},
-	ppc64.AFNMADD:  {ppc64.AFNMADD, ppc64.AFNMADDCC, 0, 0},
-	ppc64.AFNMADDS: {ppc64.AFNMADDS, ppc64.AFNMADDSCC, 0, 0},
-	ppc64.AFNMSUB:  {ppc64.AFNMSUB, ppc64.AFNMSUBCC, 0, 0},
-	ppc64.AFNMSUBS: {ppc64.AFNMSUBS, ppc64.AFNMSUBSCC, 0, 0},
-	ppc64.AFRES:    {ppc64.AFRES, ppc64.AFRESCC, 0, 0},
-	ppc64.AFRSP:    {ppc64.AFRSP, ppc64.AFRSPCC, 0, 0},
-	ppc64.AFRSQRTE: {ppc64.AFRSQRTE, ppc64.AFRSQRTECC, 0, 0},
-	ppc64.AFSEL:    {ppc64.AFSEL, ppc64.AFSELCC, 0, 0},
-	ppc64.AFSQRT:   {ppc64.AFSQRT, ppc64.AFSQRTCC, 0, 0},
-	ppc64.AFSQRTS:  {ppc64.AFSQRTS, ppc64.AFSQRTSCC, 0, 0},
-	ppc64.AFSUB:    {ppc64.AFSUB, ppc64.AFSUBCC, 0, 0},
-	ppc64.AFSUBS:   {ppc64.AFSUBS, ppc64.AFSUBSCC, 0, 0},
-	ppc64.AMTFSB0:  {ppc64.AMTFSB0, ppc64.AMTFSB0CC, 0, 0},
-	ppc64.AMTFSB1:  {ppc64.AMTFSB1, ppc64.AMTFSB1CC, 0, 0},
-	ppc64.AMULHD:   {ppc64.AMULHD, ppc64.AMULHDCC, 0, 0},
-	ppc64.AMULHDU:  {ppc64.AMULHDU, ppc64.AMULHDUCC, 0, 0},
-	ppc64.AMULHW:   {ppc64.AMULHW, ppc64.AMULHWCC, 0, 0},
-	ppc64.AMULHWU:  {ppc64.AMULHWU, ppc64.AMULHWUCC, 0, 0},
-	ppc64.AMULLD:   {ppc64.AMULLD, ppc64.AMULLDCC, ppc64.AMULLDV, ppc64.AMULLDVCC},
-	ppc64.AMULLW:   {ppc64.AMULLW, ppc64.AMULLWCC, ppc64.AMULLWV, ppc64.AMULLWVCC},
-	ppc64.ANAND:    {ppc64.ANAND, ppc64.ANANDCC, 0, 0},
-	ppc64.ANEG:     {ppc64.ANEG, ppc64.ANEGCC, ppc64.ANEGV, ppc64.ANEGVCC},
-	ppc64.ANOR:     {ppc64.ANOR, ppc64.ANORCC, 0, 0},
-	ppc64.AOR:      {ppc64.AOR, ppc64.AORCC, 0, 0},
-	ppc64.AORN:     {ppc64.AORN, ppc64.AORNCC, 0, 0},
-	ppc64.AREM:     {ppc64.AREM, ppc64.AREMCC, ppc64.AREMV, ppc64.AREMVCC},
-	ppc64.AREMD:    {ppc64.AREMD, ppc64.AREMDCC, ppc64.AREMDV, ppc64.AREMDVCC},
-	ppc64.AREMDU:   {ppc64.AREMDU, ppc64.AREMDUCC, ppc64.AREMDUV, ppc64.AREMDUVCC},
-	ppc64.AREMU:    {ppc64.AREMU, ppc64.AREMUCC, ppc64.AREMUV, ppc64.AREMUVCC},
-	ppc64.ARLDC:    {ppc64.ARLDC, ppc64.ARLDCCC, 0, 0},
-	ppc64.ARLDCL:   {ppc64.ARLDCL, ppc64.ARLDCLCC, 0, 0},
-	ppc64.ARLDCR:   {ppc64.ARLDCR, ppc64.ARLDCRCC, 0, 0},
-	ppc64.ARLDMI:   {ppc64.ARLDMI, ppc64.ARLDMICC, 0, 0},
-	ppc64.ARLWMI:   {ppc64.ARLWMI, ppc64.ARLWMICC, 0, 0},
-	ppc64.ARLWNM:   {ppc64.ARLWNM, ppc64.ARLWNMCC, 0, 0},
-	ppc64.ASLD:     {ppc64.ASLD, ppc64.ASLDCC, 0, 0},
-	ppc64.ASLW:     {ppc64.ASLW, ppc64.ASLWCC, 0, 0},
-	ppc64.ASRAD:    {ppc64.ASRAD, ppc64.ASRADCC, 0, 0},
-	ppc64.ASRAW:    {ppc64.ASRAW, ppc64.ASRAWCC, 0, 0},
-	ppc64.ASRD:     {ppc64.ASRD, ppc64.ASRDCC, 0, 0},
-	ppc64.ASRW:     {ppc64.ASRW, ppc64.ASRWCC, 0, 0},
-	ppc64.ASUB:     {ppc64.ASUB, ppc64.ASUBCC, ppc64.ASUBV, ppc64.ASUBVCC},
-	ppc64.ASUBC:    {ppc64.ASUBC, ppc64.ASUBCCC, ppc64.ASUBCV, ppc64.ASUBCVCC},
-	ppc64.ASUBE:    {ppc64.ASUBE, ppc64.ASUBECC, ppc64.ASUBEV, ppc64.ASUBEVCC},
-	ppc64.ASUBME:   {ppc64.ASUBME, ppc64.ASUBMECC, ppc64.ASUBMEV, ppc64.ASUBMEVCC},
-	ppc64.ASUBZE:   {ppc64.ASUBZE, ppc64.ASUBZECC, ppc64.ASUBZEV, ppc64.ASUBZEVCC},
-	ppc64.AXOR:     {ppc64.AXOR, ppc64.AXORCC, 0, 0},
-}
+// Instruction variants table, populated by initvariants via Main.
+// The index is the base form of the instruction, masked by obj.AMask.
+// The 4 values are the unmasked base form, then the unmasked CC, V,
+// and VCC variants, respectively.
+var varianttable = [ppc64.ALAST & obj.AMask][4]obj.As{}
 
-var initvariants_initialized int
+func initvariant(as obj.As, variants ...obj.As) {
+	vv := &varianttable[as&obj.AMask]
+	vv[0] = as
+	for i, v := range variants {
+		vv[i+1] = v
+	}
+}
 
 func initvariants() {
-	if initvariants_initialized != 0 {
-		return
-	}
-	initvariants_initialized = 1
+	initvariant(ppc64.AADD, ppc64.AADDCC, ppc64.AADDV, ppc64.AADDVCC)
+	initvariant(ppc64.AADDC, ppc64.AADDCCC, ppc64.AADDCV, ppc64.AADDCVCC)
+	initvariant(ppc64.AADDE, ppc64.AADDECC, ppc64.AADDEV, ppc64.AADDEVCC)
+	initvariant(ppc64.AADDME, ppc64.AADDMECC, ppc64.AADDMEV, ppc64.AADDMEVCC)
+	initvariant(ppc64.AADDZE, ppc64.AADDZECC, ppc64.AADDZEV, ppc64.AADDZEVCC)
+	initvariant(ppc64.AAND, ppc64.AANDCC)
+	initvariant(ppc64.AANDN, ppc64.AANDNCC)
+	initvariant(ppc64.ACNTLZD, ppc64.ACNTLZDCC)
+	initvariant(ppc64.ACNTLZW, ppc64.ACNTLZWCC)
+	initvariant(ppc64.ADIVD, ppc64.ADIVDCC, ppc64.ADIVDV, ppc64.ADIVDVCC)
+	initvariant(ppc64.ADIVDU, ppc64.ADIVDUCC, ppc64.ADIVDUV, ppc64.ADIVDUVCC)
+	initvariant(ppc64.ADIVW, ppc64.ADIVWCC, ppc64.ADIVWV, ppc64.ADIVWVCC)
+	initvariant(ppc64.ADIVWU, ppc64.ADIVWUCC, ppc64.ADIVWUV, ppc64.ADIVWUVCC)
+	initvariant(ppc64.AEQV, ppc64.AEQVCC)
+	initvariant(ppc64.AEXTSB, ppc64.AEXTSBCC)
+	initvariant(ppc64.AEXTSH, ppc64.AEXTSHCC)
+	initvariant(ppc64.AEXTSW, ppc64.AEXTSWCC)
+	initvariant(ppc64.AFABS, ppc64.AFABSCC)
+	initvariant(ppc64.AFADD, ppc64.AFADDCC)
+	initvariant(ppc64.AFADDS, ppc64.AFADDSCC)
+	initvariant(ppc64.AFCFID, ppc64.AFCFIDCC)
+	initvariant(ppc64.AFCFIDU, ppc64.AFCFIDUCC)
+	initvariant(ppc64.AFCTID, ppc64.AFCTIDCC)
+	initvariant(ppc64.AFCTIDZ, ppc64.AFCTIDZCC)
+	initvariant(ppc64.AFCTIW, ppc64.AFCTIWCC)
+	initvariant(ppc64.AFCTIWZ, ppc64.AFCTIWZCC)
+	initvariant(ppc64.AFDIV, ppc64.AFDIVCC)
+	initvariant(ppc64.AFDIVS, ppc64.AFDIVSCC)
+	initvariant(ppc64.AFMADD, ppc64.AFMADDCC)
+	initvariant(ppc64.AFMADDS, ppc64.AFMADDSCC)
+	initvariant(ppc64.AFMOVD, ppc64.AFMOVDCC)
+	initvariant(ppc64.AFMSUB, ppc64.AFMSUBCC)
+	initvariant(ppc64.AFMSUBS, ppc64.AFMSUBSCC)
+	initvariant(ppc64.AFMUL, ppc64.AFMULCC)
+	initvariant(ppc64.AFMULS, ppc64.AFMULSCC)
+	initvariant(ppc64.AFNABS, ppc64.AFNABSCC)
+	initvariant(ppc64.AFNEG, ppc64.AFNEGCC)
+	initvariant(ppc64.AFNMADD, ppc64.AFNMADDCC)
+	initvariant(ppc64.AFNMADDS, ppc64.AFNMADDSCC)
+	initvariant(ppc64.AFNMSUB, ppc64.AFNMSUBCC)
+	initvariant(ppc64.AFNMSUBS, ppc64.AFNMSUBSCC)
+	initvariant(ppc64.AFRES, ppc64.AFRESCC)
+	initvariant(ppc64.AFRSP, ppc64.AFRSPCC)
+	initvariant(ppc64.AFRSQRTE, ppc64.AFRSQRTECC)
+	initvariant(ppc64.AFSEL, ppc64.AFSELCC)
+	initvariant(ppc64.AFSQRT, ppc64.AFSQRTCC)
+	initvariant(ppc64.AFSQRTS, ppc64.AFSQRTSCC)
+	initvariant(ppc64.AFSUB, ppc64.AFSUBCC)
+	initvariant(ppc64.AFSUBS, ppc64.AFSUBSCC)
+	initvariant(ppc64.AMTFSB0, ppc64.AMTFSB0CC)
+	initvariant(ppc64.AMTFSB1, ppc64.AMTFSB1CC)
+	initvariant(ppc64.AMULHD, ppc64.AMULHDCC)
+	initvariant(ppc64.AMULHDU, ppc64.AMULHDUCC)
+	initvariant(ppc64.AMULHW, ppc64.AMULHWCC)
+	initvariant(ppc64.AMULHWU, ppc64.AMULHWUCC)
+	initvariant(ppc64.AMULLD, ppc64.AMULLDCC, ppc64.AMULLDV, ppc64.AMULLDVCC)
+	initvariant(ppc64.AMULLW, ppc64.AMULLWCC, ppc64.AMULLWV, ppc64.AMULLWVCC)
+	initvariant(ppc64.ANAND, ppc64.ANANDCC)
+	initvariant(ppc64.ANEG, ppc64.ANEGCC, ppc64.ANEGV, ppc64.ANEGVCC)
+	initvariant(ppc64.ANOR, ppc64.ANORCC)
+	initvariant(ppc64.AOR, ppc64.AORCC)
+	initvariant(ppc64.AORN, ppc64.AORNCC)
+	initvariant(ppc64.AREM, ppc64.AREMCC, ppc64.AREMV, ppc64.AREMVCC)
+	initvariant(ppc64.AREMD, ppc64.AREMDCC, ppc64.AREMDV, ppc64.AREMDVCC)
+	initvariant(ppc64.AREMDU, ppc64.AREMDUCC, ppc64.AREMDUV, ppc64.AREMDUVCC)
+	initvariant(ppc64.AREMU, ppc64.AREMUCC, ppc64.AREMUV, ppc64.AREMUVCC)
+	initvariant(ppc64.ARLDC, ppc64.ARLDCCC)
+	initvariant(ppc64.ARLDCL, ppc64.ARLDCLCC)
+	initvariant(ppc64.ARLDCR, ppc64.ARLDCRCC)
+	initvariant(ppc64.ARLDMI, ppc64.ARLDMICC)
+	initvariant(ppc64.ARLWMI, ppc64.ARLWMICC)
+	initvariant(ppc64.ARLWNM, ppc64.ARLWNMCC)
+	initvariant(ppc64.ASLD, ppc64.ASLDCC)
+	initvariant(ppc64.ASLW, ppc64.ASLWCC)
+	initvariant(ppc64.ASRAD, ppc64.ASRADCC)
+	initvariant(ppc64.ASRAW, ppc64.ASRAWCC)
+	initvariant(ppc64.ASRD, ppc64.ASRDCC)
+	initvariant(ppc64.ASRW, ppc64.ASRWCC)
+	initvariant(ppc64.ASUB, ppc64.ASUBCC, ppc64.ASUBV, ppc64.ASUBVCC)
+	initvariant(ppc64.ASUBC, ppc64.ASUBCCC, ppc64.ASUBCV, ppc64.ASUBCVCC)
+	initvariant(ppc64.ASUBE, ppc64.ASUBECC, ppc64.ASUBEV, ppc64.ASUBEVCC)
+	initvariant(ppc64.ASUBME, ppc64.ASUBMECC, ppc64.ASUBMEV, ppc64.ASUBMEVCC)
+	initvariant(ppc64.ASUBZE, ppc64.ASUBZECC, ppc64.ASUBZEV, ppc64.ASUBZEVCC)
+	initvariant(ppc64.AXOR, ppc64.AXORCC)
 
-	var j int
-	for i := int(0); i < len(varianttable); i++ {
-		if varianttable[i][0] == 0 {
+	for i := range varianttable {
+		vv := &varianttable[i]
+		if vv[0] == 0 {
 			// Instruction has no variants
-			varianttable[i][0] = i
-
+			varianttable[i][0] = obj.As(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]
+		if vv[0]&obj.AMask == obj.As(i) {
+			for _, v := range vv {
+				if v != 0 {
+					varianttable[v&obj.AMask] = 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 {
+func as2variant(as obj.As) int {
+	for i, v := range varianttable[as&obj.AMask] {
+		if v&obj.AMask == as&obj.AMask {
 			return i
 		}
 	}
-	gc.Fatalf("as2variant: instruction %v is not a variant of itself", obj.Aconv(as))
+	gc.Fatalf("as2variant: instruction %v is not a variant of itself", obj.Aconv(as&obj.AMask))
 	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]
+func variant2as(as obj.As, flags int) obj.As {
+	return varianttable[as&obj.AMask][flags]
 }
diff --git a/src/cmd/compile/internal/ppc64/reg.go b/src/cmd/compile/internal/ppc64/reg.go
index da3f34a..215c9b5 100644
--- a/src/cmd/compile/internal/ppc64/reg.go
+++ b/src/cmd/compile/internal/ppc64/reg.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -111,9 +111,9 @@ func regnames(n *int) []string {
 
 func excludedregs() uint64 {
 	// Exclude registers with fixed functions
-	regbits := uint64(1<<0 | RtoB(ppc64.REGSP) | RtoB(ppc64.REGG) | RtoB(ppc64.REGTLS) | RtoB(ppc64.REGTMP))
+	regbits := 1<<0 | RtoB(ppc64.REGSP) | RtoB(ppc64.REGG) | RtoB(ppc64.REGTLS) | RtoB(ppc64.REGTMP)
 
-	if gc.Ctxt.Flag_shared != 0 {
+	if gc.Ctxt.Flag_shared {
 		// When compiling Go into PIC, R2 is reserved to be the TOC pointer
 		// and R12 so that calls via function pointer can stomp on it.
 		regbits |= RtoB(ppc64.REG_R2)
diff --git a/src/cmd/compile/internal/s390x/cgen.go b/src/cmd/compile/internal/s390x/cgen.go
new file mode 100644
index 0000000..28bb34e
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/cgen.go
@@ -0,0 +1,178 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s390x
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/s390x"
+)
+
+type direction int
+
+const (
+	_FORWARDS direction = iota
+	_BACKWARDS
+)
+
+// blockcopy copies w bytes from &n to &res
+func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
+	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(s390x.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)
+	}
+	defer gc.Regfree(&src)
+	defer gc.Regfree(&dst)
+
+	var tmp gc.Node
+	gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
+	defer gc.Regfree(&tmp)
+
+	offset := int64(0)
+	dir := _FORWARDS
+	if osrc < odst && odst < osrc+w {
+		// Reverse. Can't use MVC, fall back onto basic moves.
+		dir = _BACKWARDS
+		const copiesPerIter = 2
+		if w >= 8*copiesPerIter {
+			cnt := w - (w % (8 * copiesPerIter))
+			ginscon(s390x.AADD, w, &src)
+			ginscon(s390x.AADD, w, &dst)
+
+			var end gc.Node
+			gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
+			p := gins(s390x.ASUB, nil, &end)
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = cnt
+			p.Reg = src.Reg
+
+			var label *obj.Prog
+			for i := 0; i < copiesPerIter; i++ {
+				offset := int64(-8 * (i + 1))
+				p := gins(s390x.AMOVD, &src, &tmp)
+				p.From.Type = obj.TYPE_MEM
+				p.From.Offset = offset
+				if i == 0 {
+					label = p
+				}
+				p = gins(s390x.AMOVD, &tmp, &dst)
+				p.To.Type = obj.TYPE_MEM
+				p.To.Offset = offset
+			}
+
+			ginscon(s390x.ASUB, 8*copiesPerIter, &src)
+			ginscon(s390x.ASUB, 8*copiesPerIter, &dst)
+			gins(s390x.ACMP, &src, &end)
+			gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), label)
+			gc.Regfree(&end)
+
+			w -= cnt
+		} else {
+			offset = w
+		}
+	}
+
+	if dir == _FORWARDS && w > 1024 {
+		// Loop over MVCs
+		cnt := w - (w % 256)
+
+		var end gc.Node
+		gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
+		add := gins(s390x.AADD, nil, &end)
+		add.From.Type = obj.TYPE_CONST
+		add.From.Offset = cnt
+		add.Reg = src.Reg
+
+		mvc := gins(s390x.AMVC, &src, &dst)
+		mvc.From.Type = obj.TYPE_MEM
+		mvc.From.Offset = 0
+		mvc.To.Type = obj.TYPE_MEM
+		mvc.To.Offset = 0
+		mvc.From3 = new(obj.Addr)
+		mvc.From3.Type = obj.TYPE_CONST
+		mvc.From3.Offset = 256
+
+		ginscon(s390x.AADD, 256, &src)
+		ginscon(s390x.AADD, 256, &dst)
+		gins(s390x.ACMP, &src, &end)
+		gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), mvc)
+		gc.Regfree(&end)
+
+		w -= cnt
+	}
+
+	for w > 0 {
+		cnt := w
+		// If in reverse we can only do 8, 4, 2 or 1 bytes at a time.
+		if dir == _BACKWARDS {
+			switch {
+			case cnt >= 8:
+				cnt = 8
+			case cnt >= 4:
+				cnt = 4
+			case cnt >= 2:
+				cnt = 2
+			}
+		} else if cnt > 256 {
+			cnt = 256
+		}
+
+		switch cnt {
+		case 8, 4, 2, 1:
+			op := s390x.AMOVB
+			switch cnt {
+			case 8:
+				op = s390x.AMOVD
+			case 4:
+				op = s390x.AMOVW
+			case 2:
+				op = s390x.AMOVH
+			}
+			load := gins(op, &src, &tmp)
+			load.From.Type = obj.TYPE_MEM
+			load.From.Offset = offset
+
+			store := gins(op, &tmp, &dst)
+			store.To.Type = obj.TYPE_MEM
+			store.To.Offset = offset
+
+			if dir == _BACKWARDS {
+				load.From.Offset -= cnt
+				store.To.Offset -= cnt
+			}
+
+		default:
+			p := gins(s390x.AMVC, &src, &dst)
+			p.From.Type = obj.TYPE_MEM
+			p.From.Offset = offset
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = offset
+			p.From3 = new(obj.Addr)
+			p.From3.Type = obj.TYPE_CONST
+			p.From3.Offset = cnt
+		}
+
+		switch dir {
+		case _FORWARDS:
+			offset += cnt
+		case _BACKWARDS:
+			offset -= cnt
+		}
+		w -= cnt
+	}
+}
diff --git a/src/cmd/compile/internal/s390x/galign.go b/src/cmd/compile/internal/s390x/galign.go
new file mode 100644
index 0000000..d0d621e
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/galign.go
@@ -0,0 +1,66 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s390x
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj/s390x"
+)
+
+func betypeinit() {
+	gc.Widthptr = 8
+	gc.Widthint = 8
+	gc.Widthreg = 8
+}
+
+func Main() {
+	gc.Thearch.LinkArch = &s390x.Links390x
+	gc.Thearch.REGSP = s390x.REGSP
+	gc.Thearch.REGCTXT = s390x.REGCTXT
+	gc.Thearch.REGCALLX = s390x.REG_R3
+	gc.Thearch.REGCALLX2 = s390x.REG_R4
+	gc.Thearch.REGRETURN = s390x.REG_R3
+	gc.Thearch.REGMIN = s390x.REG_R0
+	gc.Thearch.REGMAX = s390x.REG_R15
+	gc.Thearch.FREGMIN = s390x.REG_F0
+	gc.Thearch.FREGMAX = s390x.REG_F15
+	gc.Thearch.MAXWIDTH = 1 << 50
+	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.Peep = peep
+	gc.Thearch.Proginfo = proginfo
+	gc.Thearch.Regtyp = isReg
+	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/s390x/ggen.go b/src/cmd/compile/internal/s390x/ggen.go
new file mode 100644
index 0000000..39885ba
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/ggen.go
@@ -0,0 +1,577 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s390x
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/s390x"
+	"fmt"
+)
+
+// clearLoopCutOff is the (somewhat arbitrary) value above which it is better
+// to have a loop of clear instructions (e.g. XCs) rather than just generating
+// multiple instructions (i.e. loop unrolling).
+// Must be between 256 and 4096.
+const clearLoopCutoff = 1024
+
+func defframe(ptxt *obj.Prog) {
+	// fill in argument size, stack size
+	ptxt.To.Type = obj.TYPE_TEXTSIZE
+
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), 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 _, n := range gc.Curfn.Func.Dcl {
+		if !n.Name.Needzero {
+			continue
+		}
+		if n.Class != gc.PAUTO {
+			gc.Fatalf("needzero class %d", n.Class)
+		}
+		if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
+			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.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)
+}
+
+// zerorange clears the stack in the given range.
+func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
+	cnt := hi - lo
+	if cnt == 0 {
+		return p
+	}
+
+	// Adjust the frame to account for LR.
+	frame += gc.Ctxt.FixedFrameSize()
+	offset := frame + lo
+	reg := int16(s390x.REGSP)
+
+	// If the offset cannot fit in a 12-bit unsigned displacement then we
+	// need to create a copy of the stack pointer that we can adjust.
+	// We also need to do this if we are going to loop.
+	if offset < 0 || offset > 4096-clearLoopCutoff || cnt > clearLoopCutoff {
+		p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset, obj.TYPE_REG, s390x.REGRT1, 0)
+		p.Reg = int16(s390x.REGSP)
+		reg = s390x.REGRT1
+		offset = 0
+	}
+
+	// Generate a loop of large clears.
+	if cnt > clearLoopCutoff {
+		n := cnt - (cnt % 256)
+		end := int16(s390x.REGRT2)
+		p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset+n, obj.TYPE_REG, end, 0)
+		p.Reg = reg
+		p = appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
+		p.From3 = new(obj.Addr)
+		p.From3.Type = obj.TYPE_CONST
+		p.From3.Offset = 256
+		pl := p
+		p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, 256, obj.TYPE_REG, reg, 0)
+		p = appendpp(p, s390x.ACMP, obj.TYPE_REG, reg, 0, obj.TYPE_REG, end, 0)
+		p = appendpp(p, s390x.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+		gc.Patch(p, pl)
+
+		cnt -= n
+	}
+
+	// Generate remaining clear instructions without a loop.
+	for cnt > 0 {
+		n := cnt
+
+		// Can clear at most 256 bytes per instruction.
+		if n > 256 {
+			n = 256
+		}
+
+		switch n {
+		// Handle very small clears with move instructions.
+		case 8, 4, 2, 1:
+			ins := s390x.AMOVB
+			switch n {
+			case 8:
+				ins = s390x.AMOVD
+			case 4:
+				ins = s390x.AMOVW
+			case 2:
+				ins = s390x.AMOVH
+			}
+			p = appendpp(p, ins, obj.TYPE_CONST, 0, 0, obj.TYPE_MEM, reg, offset)
+
+		// Handle clears that would require multiple move instructions with XC.
+		default:
+			p = appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
+			p.From3 = new(obj.Addr)
+			p.From3.Type = obj.TYPE_CONST
+			p.From3.Offset = n
+		}
+
+		cnt -= n
+		offset += n
+	}
+
+	return p
+}
+
+func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset int64, ttype obj.AddrType, treg int16, toffset int64) *obj.Prog {
+	q := gc.Ctxt.NewProg()
+	gc.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
+}
+
+func ginsnop() {
+	var reg gc.Node
+	gc.Nodreg(&reg, gc.Types[gc.TINT], s390x.REG_R0)
+	gins(s390x.AOR, &reg, &reg)
+}
+
+var panicdiv *gc.Node
+
+/*
+ * generate division.
+ * generates one of:
+ *	res = nl / nr
+ *	res = nl % nr
+ * according to op.
+ */
+func dodiv(op gc.Op, 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 t.IsSigned() {
+		check = 1
+		if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -(1<<uint64(t.Width*8-1)) {
+			check = 0
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
+			check = 0
+		}
+	}
+
+	if t.Width < 8 {
+		if t.IsSigned() {
+			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 = s390x.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 {
+		nl, nr = nr, nl
+	}
+
+	t := nl.Type
+	w := 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 := gins(s390x.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 := gins(s390x.ASRD, nil, &n1)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(w)
+
+	case gc.TINT64:
+		gins(s390x.AMULHD, &n2, &n1)
+
+	case gc.TUINT64:
+		gins(s390x.AMULHDU, &n2, &n1)
+
+	default:
+		gc.Fatalf("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 gc.Op, 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.Int64())
+		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 := gc.Gbranch(optoas(gc.OLT, tcount), nil, 1)
+		if op == gc.ORSH && nl.Type.IsSigned() {
+			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)
+}
+
+// clearfat clears (i.e. replaces with zeros) the value pointed to by nl.
+func clearfat(nl *gc.Node) {
+	if gc.Debug['g'] != 0 {
+		fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
+	}
+
+	// Avoid taking the address for simple enough types.
+	if gc.Componentgen(nil, nl) {
+		return
+	}
+
+	var dst gc.Node
+	gc.Regalloc(&dst, gc.Types[gc.Tptr], nil)
+	gc.Agen(nl, &dst)
+
+	var boff int64
+	w := nl.Type.Width
+	if w > clearLoopCutoff {
+		// Generate a loop clearing 256 bytes per iteration using XCs.
+		var end gc.Node
+		gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
+		p := gins(s390x.AMOVD, &dst, &end)
+		p.From.Type = obj.TYPE_ADDR
+		p.From.Offset = w - (w % 256)
+
+		p = gins(s390x.AXC, &dst, &dst)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Offset = 0
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = 0
+		p.From3 = new(obj.Addr)
+		p.From3.Offset = 256
+		p.From3.Type = obj.TYPE_CONST
+		pl := p
+
+		ginscon(s390x.AADD, 256, &dst)
+		gins(s390x.ACMP, &dst, &end)
+		gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), pl)
+		gc.Regfree(&end)
+		w = w % 256
+	}
+
+	// Generate instructions to clear the remaining memory.
+	for w > 0 {
+		n := w
+
+		// Can clear at most 256 bytes per instruction.
+		if n > 256 {
+			n = 256
+		}
+
+		switch n {
+		// Handle very small clears using moves.
+		case 8, 4, 2, 1:
+			ins := s390x.AMOVB
+			switch n {
+			case 8:
+				ins = s390x.AMOVD
+			case 4:
+				ins = s390x.AMOVW
+			case 2:
+				ins = s390x.AMOVH
+			}
+			p := gins(ins, nil, &dst)
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = 0
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = boff
+
+		// Handle clears that would require multiple moves with a XC.
+		default:
+			p := gins(s390x.AXC, &dst, &dst)
+			p.From.Type = obj.TYPE_MEM
+			p.From.Offset = boff
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = boff
+			p.From3 = new(obj.Addr)
+			p.From3.Offset = n
+			p.From3.Type = obj.TYPE_CONST
+		}
+
+		boff += n
+		w -= n
+	}
+
+	gc.Regfree(&dst)
+}
+
+// Called after regopt and peep have run.
+// Expand CHECKNIL pseudo-op into actual nil pointer check.
+func expandchecks(firstp *obj.Prog) {
+	for p := 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(p.Lineno, "generated nil check")
+		}
+		if p.From.Type != obj.TYPE_REG {
+			gc.Fatalf("invalid nil check %v\n", p)
+		}
+
+		// check is
+		//	CMPBNE arg, $0, 2(PC) [likely]
+		//	MOVD   R0, 0(R0)
+		p1 := gc.Ctxt.NewProg()
+
+		gc.Clearp(p1)
+		p1.Link = p.Link
+		p.Link = p1
+		p1.Lineno = p.Lineno
+		p1.Pc = 9999
+		p.As = s390x.ACMPBNE
+		p.From3 = new(obj.Addr)
+		p.From3.Type = obj.TYPE_CONST
+		p.From3.Offset = 0
+
+		p.To.Type = obj.TYPE_BRANCH
+		p.To.Val = p1.Link
+
+		// crash by write to memory address 0.
+		p1.As = s390x.AMOVD
+
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = s390x.REGZERO
+		p1.To.Type = obj.TYPE_MEM
+		p1.To.Reg = s390x.REGZERO
+		p1.To.Offset = 0
+	}
+}
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Nodreg(&n1, res.Type, s390x.REGG)
+	gmove(&n1, res)
+}
diff --git a/src/cmd/compile/internal/s390x/gsubr.go b/src/cmd/compile/internal/s390x/gsubr.go
new file mode 100644
index 0000000..7760812
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/gsubr.go
@@ -0,0 +1,1110 @@
+// 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 s390x
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/s390x"
+	"fmt"
+)
+
+var resvd = []int{
+	s390x.REGZERO, // R0
+	s390x.REGTMP,  // R10
+	s390x.REGTMP2, // R11
+	s390x.REGCTXT, // R12
+	s390x.REGG,    // R13
+	s390x.REG_LR,  // R14
+	s390x.REGSP,   // R15
+}
+
+// generate
+//	as $c, n
+func ginscon(as obj.As, c int64, n2 *gc.Node) {
+	var n1 gc.Node
+
+	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
+
+	if as != s390x.AMOVD && (c < -s390x.BIG || c > s390x.BIG) || 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)
+
+		rawgins(s390x.AMOVD, &n1, &ntmp)
+		rawgins(as, &ntmp, n2)
+		gc.Regfree(&ntmp)
+		return
+	}
+
+	rawgins(as, &n1, n2)
+}
+
+// generate
+//	as n, $c (CMP/CMPU)
+func ginscon2(as obj.As, n2 *gc.Node, c int64) {
+	var n1 gc.Node
+
+	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
+
+	switch as {
+	default:
+		gc.Fatalf("ginscon2")
+
+	case s390x.ACMP:
+		if -s390x.BIG <= c && c <= s390x.BIG {
+			rawgins(as, n2, &n1)
+			return
+		}
+
+	case s390x.ACMPU:
+		if 0 <= c && c <= 2*s390x.BIG {
+			rawgins(as, n2, &n1)
+			return
+		}
+	}
+
+	// MOV n1 into register first
+	var ntmp gc.Node
+	gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+
+	rawgins(s390x.AMOVD, &n1, &ntmp)
+	rawgins(as, n2, &ntmp)
+	gc.Regfree(&ntmp)
+}
+
+func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if t.IsInteger() && 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 t.IsInteger() && gc.Isconst(n2, gc.CTINT) {
+		ginscon2(optoas(gc.OCMP, t), &r1, n2.Int64())
+	} 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)
+}
+
+// gmvc tries to move f to t using a mvc instruction.
+// If successful it returns true, otherwise it returns false.
+func gmvc(f, t *gc.Node) bool {
+	ft := int(gc.Simsimtype(f.Type))
+	tt := int(gc.Simsimtype(t.Type))
+
+	if ft != tt {
+		return false
+	}
+
+	if f.Op != gc.OINDREG || t.Op != gc.OINDREG {
+		return false
+	}
+
+	if f.Xoffset < 0 || f.Xoffset >= 4096-8 {
+		return false
+	}
+
+	if t.Xoffset < 0 || t.Xoffset >= 4096-8 {
+		return false
+	}
+
+	var len int64
+	switch ft {
+	case gc.TUINT8, gc.TINT8, gc.TBOOL:
+		len = 1
+	case gc.TUINT16, gc.TINT16:
+		len = 2
+	case gc.TUINT32, gc.TINT32, gc.TFLOAT32:
+		len = 4
+	case gc.TUINT64, gc.TINT64, gc.TFLOAT64, gc.TPTR64:
+		len = 8
+	case gc.TUNSAFEPTR:
+		len = int64(gc.Widthptr)
+	default:
+		return false
+	}
+
+	p := gc.Prog(s390x.AMVC)
+	gc.Naddr(&p.From, f)
+	gc.Naddr(&p.To, t)
+	p.From3 = new(obj.Addr)
+	p.From3.Offset = len
+	p.From3.Type = obj.TYPE_CONST
+	return true
+}
+
+// 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, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
+	}
+
+	ft := int(gc.Simsimtype(f.Type))
+	tt := int(gc.Simsimtype(t.Type))
+	cvt := t.Type
+
+	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
+		gc.Complexmove(f, t)
+		return
+	}
+
+	var a obj.As
+
+	// cannot have two memory operands
+	if gc.Ismem(f) && gc.Ismem(t) {
+		if gmvc(f, t) {
+			return
+		}
+		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 t.Type.IsFloat() {
+				goto hard
+			}
+
+			// all immediates are 16-bit sign-extended
+			// unless moving into a register.
+			if t.Type.IsInteger() {
+				if i := con.Int64(); int64(int16(i)) != i {
+					goto hard
+				}
+			}
+
+			// immediate moves to memory have a 12-bit unsigned displacement
+			if t.Xoffset < 0 || t.Xoffset >= 4096-8 {
+				goto hard
+			}
+		}
+	}
+
+	// a float-to-int or int-to-float conversion requires the source operand in a register
+	if gc.Ismem(f) && ((f.Type.IsFloat() && t.Type.IsInteger()) || (f.Type.IsInteger() && t.Type.IsFloat())) {
+		cvt = f.Type
+		goto hard
+	}
+
+	// a float32-to-float64 or float64-to-float32 conversion requires the source operand in a register
+	if gc.Ismem(f) && f.Type.IsFloat() && t.Type.IsFloat() && (ft != tt) {
+		cvt = f.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:
+		gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
+
+	// integer copy and truncate
+	case gc.TINT8<<16 | gc.TINT8,
+		gc.TUINT8<<16 | gc.TINT8,
+		gc.TINT16<<16 | gc.TINT8,
+		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 = s390x.AMOVB
+
+	case gc.TINT8<<16 | gc.TUINT8,
+		gc.TUINT8<<16 | gc.TUINT8,
+		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 = s390x.AMOVBZ
+
+	case gc.TINT16<<16 | gc.TINT16,
+		gc.TUINT16<<16 | gc.TINT16,
+		gc.TINT32<<16 | gc.TINT16,
+		gc.TUINT32<<16 | gc.TINT16,
+		gc.TINT64<<16 | gc.TINT16,
+		gc.TUINT64<<16 | gc.TINT16:
+		a = s390x.AMOVH
+
+	case gc.TINT16<<16 | gc.TUINT16,
+		gc.TUINT16<<16 | gc.TUINT16,
+		gc.TINT32<<16 | gc.TUINT16,
+		gc.TUINT32<<16 | gc.TUINT16,
+		gc.TINT64<<16 | gc.TUINT16,
+		gc.TUINT64<<16 | gc.TUINT16:
+		a = s390x.AMOVHZ
+
+	case gc.TINT32<<16 | gc.TINT32,
+		gc.TUINT32<<16 | gc.TINT32,
+		gc.TINT64<<16 | gc.TINT32,
+		gc.TUINT64<<16 | gc.TINT32:
+		a = s390x.AMOVW
+
+	case gc.TINT32<<16 | gc.TUINT32,
+		gc.TUINT32<<16 | gc.TUINT32,
+		gc.TINT64<<16 | gc.TUINT32,
+		gc.TUINT64<<16 | gc.TUINT32:
+		a = s390x.AMOVWZ
+
+	case gc.TINT64<<16 | gc.TINT64,
+		gc.TINT64<<16 | gc.TUINT64,
+		gc.TUINT64<<16 | gc.TINT64,
+		gc.TUINT64<<16 | gc.TUINT64:
+		a = s390x.AMOVD
+
+	// sign extend int8
+	case gc.TINT8<<16 | gc.TINT16,
+		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 = s390x.AMOVB
+		goto rdst
+
+	// sign extend uint8
+	case gc.TUINT8<<16 | gc.TINT16,
+		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 = s390x.AMOVBZ
+		goto rdst
+
+	// sign extend int16
+	case gc.TINT16<<16 | gc.TINT32,
+		gc.TINT16<<16 | gc.TUINT32,
+		gc.TINT16<<16 | gc.TINT64,
+		gc.TINT16<<16 | gc.TUINT64:
+		a = s390x.AMOVH
+		goto rdst
+
+	// zero extend uint16
+	case gc.TUINT16<<16 | gc.TINT32,
+		gc.TUINT16<<16 | gc.TUINT32,
+		gc.TUINT16<<16 | gc.TINT64,
+		gc.TUINT16<<16 | gc.TUINT64:
+		a = s390x.AMOVHZ
+		goto rdst
+
+	// sign extend int32
+	case gc.TINT32<<16 | gc.TINT64,
+		gc.TINT32<<16 | gc.TUINT64:
+		a = s390x.AMOVW
+		goto rdst
+
+	// zero extend uint32
+	case gc.TUINT32<<16 | gc.TINT64,
+		gc.TUINT32<<16 | gc.TUINT64:
+		a = s390x.AMOVWZ
+		goto rdst
+
+	// float to integer
+	case gc.TFLOAT32<<16 | gc.TUINT8,
+		gc.TFLOAT32<<16 | gc.TUINT16:
+		cvt = gc.Types[gc.TUINT32]
+		goto hard
+
+	case gc.TFLOAT32<<16 | gc.TUINT32:
+		a = s390x.ACLFEBR
+		goto rdst
+
+	case gc.TFLOAT32<<16 | gc.TUINT64:
+		a = s390x.ACLGEBR
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TUINT8,
+		gc.TFLOAT64<<16 | gc.TUINT16:
+		cvt = gc.Types[gc.TUINT32]
+		goto hard
+
+	case gc.TFLOAT64<<16 | gc.TUINT32:
+		a = s390x.ACLFDBR
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TUINT64:
+		a = s390x.ACLGDBR
+		goto rdst
+
+	case gc.TFLOAT32<<16 | gc.TINT8,
+		gc.TFLOAT32<<16 | gc.TINT16:
+		cvt = gc.Types[gc.TINT32]
+		goto hard
+
+	case gc.TFLOAT32<<16 | gc.TINT32:
+		a = s390x.ACFEBRA
+		goto rdst
+
+	case gc.TFLOAT32<<16 | gc.TINT64:
+		a = s390x.ACGEBRA
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TINT8,
+		gc.TFLOAT64<<16 | gc.TINT16:
+		cvt = gc.Types[gc.TINT32]
+		goto hard
+
+	case gc.TFLOAT64<<16 | gc.TINT32:
+		a = s390x.ACFDBRA
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TINT64:
+		a = s390x.ACGDBRA
+		goto rdst
+
+	// integer to float
+	case gc.TUINT8<<16 | gc.TFLOAT32,
+		gc.TUINT16<<16 | gc.TFLOAT32:
+		cvt = gc.Types[gc.TUINT32]
+		goto hard
+
+	case gc.TUINT32<<16 | gc.TFLOAT32:
+		a = s390x.ACELFBR
+		goto rdst
+
+	case gc.TUINT64<<16 | gc.TFLOAT32:
+		a = s390x.ACELGBR
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TFLOAT64,
+		gc.TUINT16<<16 | gc.TFLOAT64:
+		cvt = gc.Types[gc.TUINT32]
+		goto hard
+
+	case gc.TUINT32<<16 | gc.TFLOAT64:
+		a = s390x.ACDLFBR
+		goto rdst
+
+	case gc.TUINT64<<16 | gc.TFLOAT64:
+		a = s390x.ACDLGBR
+		goto rdst
+
+	case gc.TINT8<<16 | gc.TFLOAT32,
+		gc.TINT16<<16 | gc.TFLOAT32:
+		cvt = gc.Types[gc.TINT32]
+		goto hard
+
+	case gc.TINT32<<16 | gc.TFLOAT32:
+		a = s390x.ACEFBRA
+		goto rdst
+
+	case gc.TINT64<<16 | gc.TFLOAT32:
+		a = s390x.ACEGBRA
+		goto rdst
+
+	case gc.TINT8<<16 | gc.TFLOAT64,
+		gc.TINT16<<16 | gc.TFLOAT64:
+		cvt = gc.Types[gc.TINT32]
+		goto hard
+
+	case gc.TINT32<<16 | gc.TFLOAT64:
+		a = s390x.ACDFBRA
+		goto rdst
+
+	case gc.TINT64<<16 | gc.TFLOAT64:
+		a = s390x.ACDGBRA
+		goto rdst
+
+	// float to float
+	case gc.TFLOAT32<<16 | gc.TFLOAT32:
+		a = s390x.AFMOVS
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT64:
+		a = s390x.AFMOVD
+
+	case gc.TFLOAT32<<16 | gc.TFLOAT64:
+		a = s390x.ALDEBR
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT32:
+		a = s390x.ALEDBR
+		goto rdst
+	}
+
+	gins(a, f, t)
+	return
+
+	// requires register destination
+rdst:
+	if t != nil && t.Op == gc.OREGISTER {
+		gins(a, f, t)
+		return
+	} else {
+		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 intLiteral(n *gc.Node) (x int64, ok bool) {
+	switch {
+	case n == nil:
+		return
+	case gc.Isconst(n, gc.CTINT):
+		return n.Int64(), 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 obj.As, f, t *gc.Node) *obj.Prog {
+	if t != nil {
+		if as >= obj.A_ARCHSPECIFIC {
+			if x, ok := intLiteral(f); ok {
+				ginscon(as, x, t)
+				return nil // caller must not use
+			}
+		}
+		if as == s390x.ACMP || as == s390x.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 obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
+	// self move check
+	// TODO(mundaym): use sized math and extend to MOVB, MOVWZ etc.
+	switch as {
+	case s390x.AMOVD, s390x.AFMOVS, s390x.AFMOVD:
+		if f != nil && t != nil &&
+			f.Op == gc.OREGISTER && t.Op == gc.OREGISTER &&
+			f.Reg == t.Reg {
+			return nil
+		}
+	}
+
+	p := gc.Prog(as)
+	gc.Naddr(&p.From, f)
+	gc.Naddr(&p.To, t)
+
+	switch as {
+	// Bad things the front end has done to us. Crash to find call stack.
+	case s390x.ACMP, s390x.ACMPU:
+		if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
+			gc.Debug['h'] = 1
+			gc.Fatalf("bad inst: %v", p)
+		}
+	}
+
+	if gc.Debug['g'] != 0 {
+		fmt.Printf("%v\n", p)
+	}
+
+	w := int32(0)
+	switch as {
+	case s390x.AMOVB, s390x.AMOVBZ:
+		w = 1
+
+	case s390x.AMOVH, s390x.AMOVHZ:
+		w = 2
+
+	case s390x.AMOVW, s390x.AMOVWZ:
+		w = 4
+
+	case s390x.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.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
+	}
+
+	return p
+}
+
+// optoas returns the Axxx equivalent of Oxxx for type t
+func optoas(op gc.Op, t *gc.Type) obj.As {
+	if t == nil {
+		gc.Fatalf("optoas: t is nil")
+	}
+
+	// avoid constant conversions in switches below
+	const (
+		OMINUS_ = uint32(gc.OMINUS) << 16
+		OLSH_   = uint32(gc.OLSH) << 16
+		ORSH_   = uint32(gc.ORSH) << 16
+		OADD_   = uint32(gc.OADD) << 16
+		OSUB_   = uint32(gc.OSUB) << 16
+		OMUL_   = uint32(gc.OMUL) << 16
+		ODIV_   = uint32(gc.ODIV) << 16
+		OOR_    = uint32(gc.OOR) << 16
+		OAND_   = uint32(gc.OAND) << 16
+		OXOR_   = uint32(gc.OXOR) << 16
+		OEQ_    = uint32(gc.OEQ) << 16
+		ONE_    = uint32(gc.ONE) << 16
+		OLT_    = uint32(gc.OLT) << 16
+		OLE_    = uint32(gc.OLE) << 16
+		OGE_    = uint32(gc.OGE) << 16
+		OGT_    = uint32(gc.OGT) << 16
+		OCMP_   = uint32(gc.OCMP) << 16
+		OAS_    = uint32(gc.OAS) << 16
+		OHMUL_  = uint32(gc.OHMUL) << 16
+		OSQRT_  = uint32(gc.OSQRT) << 16
+		OLROT_  = uint32(gc.OLROT) << 16
+	)
+
+	a := obj.AXXX
+	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
+	default:
+		gc.Fatalf("optoas: no entry for op=%v type=%v", op, t)
+
+	case OEQ_ | gc.TBOOL,
+		OEQ_ | gc.TINT8,
+		OEQ_ | gc.TUINT8,
+		OEQ_ | gc.TINT16,
+		OEQ_ | gc.TUINT16,
+		OEQ_ | gc.TINT32,
+		OEQ_ | gc.TUINT32,
+		OEQ_ | gc.TINT64,
+		OEQ_ | gc.TUINT64,
+		OEQ_ | gc.TPTR32,
+		OEQ_ | gc.TPTR64,
+		OEQ_ | gc.TFLOAT32,
+		OEQ_ | gc.TFLOAT64:
+		a = s390x.ABEQ
+
+	case ONE_ | gc.TBOOL,
+		ONE_ | gc.TINT8,
+		ONE_ | gc.TUINT8,
+		ONE_ | gc.TINT16,
+		ONE_ | gc.TUINT16,
+		ONE_ | gc.TINT32,
+		ONE_ | gc.TUINT32,
+		ONE_ | gc.TINT64,
+		ONE_ | gc.TUINT64,
+		ONE_ | gc.TPTR32,
+		ONE_ | gc.TPTR64,
+		ONE_ | gc.TFLOAT32,
+		ONE_ | gc.TFLOAT64:
+		a = s390x.ABNE
+
+	case OLT_ | gc.TINT8, // ACMP
+		OLT_ | gc.TINT16,
+		OLT_ | gc.TINT32,
+		OLT_ | gc.TINT64,
+		OLT_ | gc.TUINT8,
+		// ACMPU
+		OLT_ | gc.TUINT16,
+		OLT_ | gc.TUINT32,
+		OLT_ | gc.TUINT64,
+		OLT_ | gc.TFLOAT32,
+		// AFCMPU
+		OLT_ | gc.TFLOAT64:
+		a = s390x.ABLT
+
+	case OLE_ | gc.TINT8, // ACMP
+		OLE_ | gc.TINT16,
+		OLE_ | gc.TINT32,
+		OLE_ | gc.TINT64,
+		OLE_ | gc.TUINT8,
+		// ACMPU
+		OLE_ | gc.TUINT16,
+		OLE_ | gc.TUINT32,
+		OLE_ | gc.TUINT64,
+		OLE_ | gc.TFLOAT32,
+		OLE_ | gc.TFLOAT64:
+		a = s390x.ABLE
+
+	case OGT_ | gc.TINT8,
+		OGT_ | gc.TINT16,
+		OGT_ | gc.TINT32,
+		OGT_ | gc.TINT64,
+		OGT_ | gc.TUINT8,
+		OGT_ | gc.TUINT16,
+		OGT_ | gc.TUINT32,
+		OGT_ | gc.TUINT64,
+		OGT_ | gc.TFLOAT32,
+		OGT_ | gc.TFLOAT64:
+		a = s390x.ABGT
+
+	case OGE_ | gc.TINT8,
+		OGE_ | gc.TINT16,
+		OGE_ | gc.TINT32,
+		OGE_ | gc.TINT64,
+		OGE_ | gc.TUINT8,
+		OGE_ | gc.TUINT16,
+		OGE_ | gc.TUINT32,
+		OGE_ | gc.TUINT64,
+		OGE_ | gc.TFLOAT32,
+		OGE_ | gc.TFLOAT64:
+		a = s390x.ABGE
+
+	case OCMP_ | gc.TBOOL,
+		OCMP_ | gc.TINT8,
+		OCMP_ | gc.TINT16,
+		OCMP_ | gc.TINT32,
+		OCMP_ | gc.TPTR32,
+		OCMP_ | gc.TINT64:
+		a = s390x.ACMP
+
+	case OCMP_ | gc.TUINT8,
+		OCMP_ | gc.TUINT16,
+		OCMP_ | gc.TUINT32,
+		OCMP_ | gc.TUINT64,
+		OCMP_ | gc.TPTR64:
+		a = s390x.ACMPU
+
+	case OCMP_ | gc.TFLOAT32:
+		a = s390x.ACEBR
+
+	case OCMP_ | gc.TFLOAT64:
+		a = s390x.AFCMPU
+
+	case OAS_ | gc.TBOOL,
+		OAS_ | gc.TINT8:
+		a = s390x.AMOVB
+
+	case OAS_ | gc.TUINT8:
+		a = s390x.AMOVBZ
+
+	case OAS_ | gc.TINT16:
+		a = s390x.AMOVH
+
+	case OAS_ | gc.TUINT16:
+		a = s390x.AMOVHZ
+
+	case OAS_ | gc.TINT32:
+		a = s390x.AMOVW
+
+	case OAS_ | gc.TUINT32,
+		OAS_ | gc.TPTR32:
+		a = s390x.AMOVWZ
+
+	case OAS_ | gc.TINT64,
+		OAS_ | gc.TUINT64,
+		OAS_ | gc.TPTR64:
+		a = s390x.AMOVD
+
+	case OAS_ | gc.TFLOAT32:
+		a = s390x.AFMOVS
+
+	case OAS_ | gc.TFLOAT64:
+		a = s390x.AFMOVD
+
+	case OADD_ | gc.TINT8,
+		OADD_ | gc.TUINT8,
+		OADD_ | gc.TINT16,
+		OADD_ | gc.TUINT16,
+		OADD_ | gc.TINT32,
+		OADD_ | gc.TUINT32,
+		OADD_ | gc.TPTR32,
+		OADD_ | gc.TINT64,
+		OADD_ | gc.TUINT64,
+		OADD_ | gc.TPTR64:
+		a = s390x.AADD
+
+	case OADD_ | gc.TFLOAT32:
+		a = s390x.AFADDS
+
+	case OADD_ | gc.TFLOAT64:
+		a = s390x.AFADD
+
+	case OSUB_ | gc.TINT8,
+		OSUB_ | gc.TUINT8,
+		OSUB_ | gc.TINT16,
+		OSUB_ | gc.TUINT16,
+		OSUB_ | gc.TINT32,
+		OSUB_ | gc.TUINT32,
+		OSUB_ | gc.TPTR32,
+		OSUB_ | gc.TINT64,
+		OSUB_ | gc.TUINT64,
+		OSUB_ | gc.TPTR64:
+		a = s390x.ASUB
+
+	case OSUB_ | gc.TFLOAT32:
+		a = s390x.AFSUBS
+
+	case OSUB_ | gc.TFLOAT64:
+		a = s390x.AFSUB
+
+	case OMINUS_ | gc.TINT8,
+		OMINUS_ | gc.TUINT8,
+		OMINUS_ | gc.TINT16,
+		OMINUS_ | gc.TUINT16,
+		OMINUS_ | gc.TINT32,
+		OMINUS_ | gc.TUINT32,
+		OMINUS_ | gc.TPTR32,
+		OMINUS_ | gc.TINT64,
+		OMINUS_ | gc.TUINT64,
+		OMINUS_ | gc.TPTR64:
+		a = s390x.ANEG
+
+	case OAND_ | gc.TINT8,
+		OAND_ | gc.TUINT8,
+		OAND_ | gc.TINT16,
+		OAND_ | gc.TUINT16,
+		OAND_ | gc.TINT32,
+		OAND_ | gc.TUINT32,
+		OAND_ | gc.TPTR32,
+		OAND_ | gc.TINT64,
+		OAND_ | gc.TUINT64,
+		OAND_ | gc.TPTR64:
+		a = s390x.AAND
+
+	case OOR_ | gc.TINT8,
+		OOR_ | gc.TUINT8,
+		OOR_ | gc.TINT16,
+		OOR_ | gc.TUINT16,
+		OOR_ | gc.TINT32,
+		OOR_ | gc.TUINT32,
+		OOR_ | gc.TPTR32,
+		OOR_ | gc.TINT64,
+		OOR_ | gc.TUINT64,
+		OOR_ | gc.TPTR64:
+		a = s390x.AOR
+
+	case OXOR_ | gc.TINT8,
+		OXOR_ | gc.TUINT8,
+		OXOR_ | gc.TINT16,
+		OXOR_ | gc.TUINT16,
+		OXOR_ | gc.TINT32,
+		OXOR_ | gc.TUINT32,
+		OXOR_ | gc.TPTR32,
+		OXOR_ | gc.TINT64,
+		OXOR_ | gc.TUINT64,
+		OXOR_ | gc.TPTR64:
+		a = s390x.AXOR
+
+	case OLSH_ | gc.TINT8,
+		OLSH_ | gc.TUINT8,
+		OLSH_ | gc.TINT16,
+		OLSH_ | gc.TUINT16,
+		OLSH_ | gc.TINT32,
+		OLSH_ | gc.TUINT32,
+		OLSH_ | gc.TPTR32,
+		OLSH_ | gc.TINT64,
+		OLSH_ | gc.TUINT64,
+		OLSH_ | gc.TPTR64:
+		a = s390x.ASLD
+
+	case ORSH_ | gc.TUINT8,
+		ORSH_ | gc.TUINT16,
+		ORSH_ | gc.TUINT32,
+		ORSH_ | gc.TPTR32,
+		ORSH_ | gc.TUINT64,
+		ORSH_ | gc.TPTR64:
+		a = s390x.ASRD
+
+	case ORSH_ | gc.TINT8,
+		ORSH_ | gc.TINT16,
+		ORSH_ | gc.TINT32,
+		ORSH_ | gc.TINT64:
+		a = s390x.ASRAD
+
+	case OHMUL_ | gc.TINT64:
+		a = s390x.AMULHD
+
+	case OHMUL_ | gc.TUINT64,
+		OHMUL_ | gc.TPTR64:
+		a = s390x.AMULHDU
+
+	case OMUL_ | gc.TINT8,
+		OMUL_ | gc.TINT16,
+		OMUL_ | gc.TINT32,
+		OMUL_ | gc.TINT64:
+		a = s390x.AMULLD
+
+	case OMUL_ | gc.TUINT8,
+		OMUL_ | gc.TUINT16,
+		OMUL_ | gc.TUINT32,
+		OMUL_ | gc.TPTR32,
+		// don't use word multiply, the high 32-bit are undefined.
+		OMUL_ | gc.TUINT64,
+		OMUL_ | gc.TPTR64:
+		// for 64-bit multiplies, signedness doesn't matter.
+		a = s390x.AMULLD
+
+	case OMUL_ | gc.TFLOAT32:
+		a = s390x.AFMULS
+
+	case OMUL_ | gc.TFLOAT64:
+		a = s390x.AFMUL
+
+	case ODIV_ | gc.TINT8,
+		ODIV_ | gc.TINT16,
+		ODIV_ | gc.TINT32,
+		ODIV_ | gc.TINT64:
+		a = s390x.ADIVD
+
+	case ODIV_ | gc.TUINT8,
+		ODIV_ | gc.TUINT16,
+		ODIV_ | gc.TUINT32,
+		ODIV_ | gc.TPTR32,
+		ODIV_ | gc.TUINT64,
+		ODIV_ | gc.TPTR64:
+		a = s390x.ADIVDU
+
+	case ODIV_ | gc.TFLOAT32:
+		a = s390x.AFDIVS
+
+	case ODIV_ | gc.TFLOAT64:
+		a = s390x.AFDIV
+
+	case OSQRT_ | gc.TFLOAT64:
+		a = s390x.AFSQRT
+
+	case OLROT_ | gc.TUINT32,
+		OLROT_ | gc.TPTR32,
+		OLROT_ | gc.TINT32:
+		a = s390x.ARLL
+
+	case OLROT_ | gc.TUINT64,
+		OLROT_ | gc.TPTR64,
+		OLROT_ | gc.TINT64:
+		a = s390x.ARLLG
+	}
+
+	return a
+}
+
+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 obj.As, 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) {
+			return false
+		}
+		v := n.Int64()
+		switch as {
+		default:
+			return false
+
+		// operations that can cope with a 32-bit immediate
+		// TODO(mundaym): logical operations can work on high bits
+		case s390x.AADD,
+			s390x.AADDC,
+			s390x.ASUB,
+			s390x.AMULLW,
+			s390x.AAND,
+			s390x.AOR,
+			s390x.AXOR,
+			s390x.ASLD,
+			s390x.ASLW,
+			s390x.ASRAW,
+			s390x.ASRAD,
+			s390x.ASRW,
+			s390x.ASRD,
+			s390x.AMOVB,
+			s390x.AMOVBZ,
+			s390x.AMOVH,
+			s390x.AMOVHZ,
+			s390x.AMOVW,
+			s390x.AMOVWZ,
+			s390x.AMOVD:
+			if int64(int32(v)) != v {
+				return false
+			}
+
+		// for comparisons avoid immediates unless they can
+		// fit into a int8/uint8
+		// this favours combined compare and branch instructions
+		case s390x.ACMP:
+			if int64(int8(v)) != v {
+				return false
+			}
+		case s390x.ACMPU:
+			if int64(uint8(v)) != v {
+				return false
+			}
+		}
+
+		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]
+			// check that the offset fits into a 12-bit displacement
+			if n1.Xoffset < 0 || n1.Xoffset >= (1<<12)-8 {
+				sudoclean()
+				return false
+			}
+			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.Fatalf("can't happen")
+			}
+			gins(s390x.AMOVD, &n1, reg)
+			gc.Cgen_checknil(reg)
+			n1.Xoffset = -(oary[i] + 1)
+		}
+
+		a.Type = obj.TYPE_NONE
+		a.Index = 0
+		// check that the offset fits into a 12-bit displacement
+		if n1.Xoffset < 0 || n1.Xoffset >= (1<<12)-8 {
+			tmp := n1
+			tmp.Op = gc.OREGISTER
+			tmp.Type = gc.Types[gc.Tptr]
+			tmp.Xoffset = 0
+			gc.Cgen_checknil(&tmp)
+			ginscon(s390x.AADD, n1.Xoffset, &tmp)
+			n1.Xoffset = 0
+		}
+		gc.Naddr(a, &n1)
+		return true
+	}
+
+	return false
+}
diff --git a/src/cmd/compile/internal/s390x/peep.go b/src/cmd/compile/internal/s390x/peep.go
new file mode 100644
index 0000000..cd6a8c5
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/peep.go
@@ -0,0 +1,1664 @@
+// 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 s390x
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/s390x"
+	"fmt"
+)
+
+type usage int
+
+const (
+	_None          usage = iota // no usage found
+	_Read                       // only read from
+	_ReadWriteSame              // both read from and written to in a single operand
+	_Write                      // only written to
+	_ReadWriteDiff              // both read from and written to in different operands
+)
+
+var gactive uint32
+
+func peep(firstp *obj.Prog) {
+	g := gc.Flowstart(firstp, nil)
+	if g == nil {
+		return
+	}
+	gactive = 0
+
+	run := func(name string, pass func(r *gc.Flow) int) int {
+		n := pass(g.Start)
+		if gc.Debug['P'] != 0 {
+			fmt.Println(name, ":", n)
+		}
+		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+			gc.Dumpit(name, g.Start, 0)
+		}
+		return n
+	}
+
+	for {
+		n := 0
+		n += run("constant propagation", constantPropagation)
+		n += run("copy propagation", copyPropagation)
+		n += run("cast propagation", castPropagation)
+		n += run("remove load-hit-stores", removeLoadHitStores)
+		n += run("dead code elimination", deadCodeElimination)
+		if n == 0 {
+			break
+		}
+	}
+	run("fuse op moves", fuseOpMoves)
+	run("fuse clears", fuseClear)
+	run("load pipelining", loadPipelining)
+	run("fuse compare branch", fuseCompareBranch)
+	run("simplify ops", simplifyOps)
+	run("dead code elimination", deadCodeElimination)
+
+	// TODO(mundaym): load/store multiple aren't currently handled by copyu
+	// so this pass must be last.
+	run("fuse multiple", fuseMultiple)
+
+	gc.Flowend(g)
+}
+
+func pushback(r0 *gc.Flow) {
+	var r *gc.Flow
+
+	var b *gc.Flow
+	p0 := 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 !(isReg(&p.From) || isConst(&p.From)) || !isReg(&p.To) {
+				break
+			}
+			if copyu(p, &p0.To, nil) != _None || copyu(p0, &p.To, nil) != _None {
+				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 := b; ; r = r.Link {
+			fmt.Printf("\t%v\n", r.Prog)
+			if r == r0 {
+				break
+			}
+		}
+	}
+
+	t := *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
+		p0.From3 = p.From3
+		p0.Reg = p.Reg
+		p0.RegTo2 = p.RegTo2
+		if r == b {
+			break
+		}
+	}
+
+	p0 = r.Prog
+	p0.As = t.As
+	p0.Lineno = t.Lineno
+	p0.From = t.From
+	p0.To = t.To
+	p0.From3 = t.From3
+	p0.Reg = t.Reg
+	p0.RegTo2 = t.RegTo2
+
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		fmt.Printf("\tafter\n")
+		for r := b; ; r = r.Link {
+			fmt.Printf("\t%v\n", r.Prog)
+			if r == r0 {
+				break
+			}
+		}
+	}
+}
+
+// excise replaces the given instruction with a NOP and clears
+// its operands.
+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++
+}
+
+// isZero returns true if a is either the constant 0 or the register
+// REGZERO.
+func isZero(a *obj.Addr) bool {
+	if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+		return true
+	}
+	if a.Type == obj.TYPE_REG && a.Reg == s390x.REGZERO {
+		return true
+	}
+	return false
+}
+
+// isReg returns true if a is a general purpose or floating point
+// register (GPR or FPR).
+//
+// TODO(mundaym): currently this excludes REGZER0, but not other
+// special registers.
+func isReg(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_REG &&
+		s390x.REG_R0 <= a.Reg &&
+		a.Reg <= s390x.REG_F15 &&
+		a.Reg != s390x.REGZERO
+}
+
+// isGPR returns true if a is a general purpose register (GPR).
+// REGZERO is treated as a GPR.
+func isGPR(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_REG &&
+		s390x.REG_R0 <= a.Reg &&
+		a.Reg <= s390x.REG_R15
+}
+
+// isFPR returns true if a is a floating point register (FPR).
+func isFPR(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_REG &&
+		s390x.REG_F0 <= a.Reg &&
+		a.Reg <= s390x.REG_F15
+}
+
+// isConst returns true if a refers to a constant (integer or
+// floating point, not string currently).
+func isConst(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_FCONST
+}
+
+// isBDMem returns true if a refers to a memory location addressable by a
+// base register (B) and a displacement (D), such as:
+// 	x+8(R1)
+// and
+//	0(R10)
+// It returns false if the address contains an index register (X) such as:
+// 	16(R1)(R2*1)
+// or if a relocation is required.
+func isBDMem(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_MEM &&
+		a.Index == 0 &&
+		(a.Name == obj.NAME_NONE || a.Name == obj.NAME_AUTO || a.Name == obj.NAME_PARAM)
+}
+
+// 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. subprop returns true if it modified any instructions.
+func subprop(r0 *gc.Flow) bool {
+	p := r0.Prog
+	v1 := &p.From
+	if !isReg(v1) {
+		return false
+	}
+	v2 := &p.To
+	if !isReg(v2) {
+		return false
+	}
+	cast := false
+	switch p.As {
+	case s390x.AMOVW, s390x.AMOVWZ,
+		s390x.AMOVH, s390x.AMOVHZ,
+		s390x.AMOVB, s390x.AMOVBZ:
+		cast = true
+	}
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+		if gc.Uniqs(r) == nil {
+			break
+		}
+		p = r.Prog
+		switch copyu(p, v1, nil) {
+		case _Write, _ReadWriteDiff:
+			if p.As == obj.ACALL {
+				return false
+			}
+			if (!cast || p.As == r0.Prog.As) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
+				copysub(&p.To, v1, v2)
+				for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
+					p = r.Prog
+					copysub(&p.From, v1, v2)
+					copysub1(p, v1, v2)
+					copysub(&p.To, v1, v2)
+				}
+				v1.Reg, v2.Reg = v2.Reg, v1.Reg
+				return true
+			}
+			if cast {
+				return false
+			}
+		case _ReadWriteSame:
+			if cast {
+				return false
+			}
+		}
+		if copyu(p, v2, nil) != _None {
+			return false
+		}
+	}
+	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(r *gc.Flow) bool {
+	p := r.Prog
+
+	canSub := false
+	switch p.As {
+	case s390x.AFMOVS, s390x.AFMOVD, s390x.AMOVD:
+		canSub = true
+	default:
+		for rr := gc.Uniqp(r); rr != nil; rr = gc.Uniqp(rr) {
+			if gc.Uniqs(rr) == nil {
+				break
+			}
+			switch copyu(rr.Prog, &p.From, nil) {
+			case _Read, _None:
+				continue
+			}
+			// write
+			if rr.Prog.As == p.As {
+				canSub = true
+			}
+			break
+		}
+	}
+	if !canSub {
+		return false
+	}
+	if copyas(&p.From, &p.To) {
+		return true
+	}
+
+	gactive++
+	return copy1(&p.From, &p.To, r.S1, 0)
+}
+
+// copy1 replaces uses of v2 with v1 starting at r and returns true if
+// all uses were rewritten.
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+	if uint32(r.Active) == gactive {
+		return true
+	}
+	r.Active = int32(gactive)
+	for ; r != nil; r = r.S1 {
+		p := r.Prog
+		if f == 0 && gc.Uniqp(r) == nil {
+			// Multiple predecessors; conservatively
+			// assume v1 was set on other path
+			f = 1
+		}
+		t := copyu(p, v2, nil)
+		switch t {
+		case _ReadWriteSame:
+			return false
+		case _Write:
+			return true
+		case _Read, _ReadWriteDiff:
+			if f != 0 {
+				return false
+			}
+			if copyu(p, v2, v1) != 0 {
+				return false
+			}
+			if t == _ReadWriteDiff {
+				return true
+			}
+		}
+		if f == 0 {
+			switch copyu(p, v1, nil) {
+			case _ReadWriteSame, _ReadWriteDiff, _Write:
+				f = 1
+			}
+		}
+		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:
+// 	_Read           if v only used
+//	_ReadWriteSame  if v is set and used in one address (read-alter-rewrite;
+// 	                can't substitute)
+//	_Write          if v is only set
+//	_ReadWriteDiff  if v is set in one address and used in another (so addresses
+// 	                can be rewritten independently)
+//	_None           otherwise (not touched)
+func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) usage {
+	if p.From3Type() != obj.TYPE_NONE && p.From3Type() != obj.TYPE_CONST {
+		// Currently we never generate a From3 with anything other than a constant in it.
+		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(p.As))
+		return _ReadWriteSame
+
+	case // read p.From, write p.To
+		s390x.AMOVH,
+		s390x.AMOVHZ,
+		s390x.AMOVB,
+		s390x.AMOVBZ,
+		s390x.AMOVW,
+		s390x.AMOVWZ,
+		s390x.AMOVD,
+		s390x.ANEG,
+		s390x.AADDME,
+		s390x.AADDZE,
+		s390x.ASUBME,
+		s390x.ASUBZE,
+		s390x.AFMOVS,
+		s390x.AFMOVD,
+		s390x.ALEDBR,
+		s390x.AFNEG,
+		s390x.ALDEBR,
+		s390x.ACLFEBR,
+		s390x.ACLGEBR,
+		s390x.ACLFDBR,
+		s390x.ACLGDBR,
+		s390x.ACFEBRA,
+		s390x.ACGEBRA,
+		s390x.ACFDBRA,
+		s390x.ACGDBRA,
+		s390x.ACELFBR,
+		s390x.ACELGBR,
+		s390x.ACDLFBR,
+		s390x.ACDLGBR,
+		s390x.ACEFBRA,
+		s390x.ACEGBRA,
+		s390x.ACDFBRA,
+		s390x.ACDGBRA,
+		s390x.AFSQRT:
+
+		if s != nil {
+			copysub(&p.From, v, s)
+
+			// Update only indirect uses of v in p.To
+			if !copyas(&p.To, v) {
+				copysub(&p.To, v, s)
+			}
+			return _None
+		}
+
+		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 _ReadWriteDiff
+			}
+			return _Write
+		}
+
+		if copyau(&p.From, v) {
+			return _Read
+		}
+		if copyau(&p.To, v) {
+			// p.To only indirectly uses v
+			return _Read
+		}
+
+		return _None
+
+	// read p.From, read p.Reg, write p.To
+	case s390x.AADD,
+		s390x.AADDC,
+		s390x.AADDE,
+		s390x.ASUB,
+		s390x.ASLW,
+		s390x.ASRW,
+		s390x.ASRAW,
+		s390x.ASLD,
+		s390x.ASRD,
+		s390x.ASRAD,
+		s390x.ARLL,
+		s390x.ARLLG,
+		s390x.AOR,
+		s390x.AORN,
+		s390x.AAND,
+		s390x.AANDN,
+		s390x.ANAND,
+		s390x.ANOR,
+		s390x.AXOR,
+		s390x.AMULLW,
+		s390x.AMULLD,
+		s390x.AMULHD,
+		s390x.AMULHDU,
+		s390x.ADIVW,
+		s390x.ADIVD,
+		s390x.ADIVWU,
+		s390x.ADIVDU,
+		s390x.AFADDS,
+		s390x.AFADD,
+		s390x.AFSUBS,
+		s390x.AFSUB,
+		s390x.AFMULS,
+		s390x.AFMUL,
+		s390x.AFDIVS,
+		s390x.AFDIV:
+		if s != nil {
+			copysub(&p.From, v, s)
+			copysub1(p, v, s)
+
+			// Update only indirect uses of v in p.To
+			if !copyas(&p.To, v) {
+				copysub(&p.To, v, s)
+			}
+		}
+
+		if copyas(&p.To, v) {
+			if p.Reg == 0 {
+				p.Reg = p.To.Reg
+			}
+			if copyau(&p.From, v) || copyau1(p, v) {
+				return _ReadWriteDiff
+			}
+			return _Write
+		}
+
+		if copyau(&p.From, v) {
+			return _Read
+		}
+		if copyau1(p, v) {
+			return _Read
+		}
+		if copyau(&p.To, v) {
+			return _Read
+		}
+		return _None
+
+	case s390x.ABEQ,
+		s390x.ABGT,
+		s390x.ABGE,
+		s390x.ABLT,
+		s390x.ABLE,
+		s390x.ABNE,
+		s390x.ABVC,
+		s390x.ABVS:
+		return _None
+
+	case obj.ACHECKNIL, // read p.From
+		s390x.ACMP, // read p.From, read p.To
+		s390x.ACMPU,
+		s390x.ACMPW,
+		s390x.ACMPWU,
+		s390x.AFCMPO,
+		s390x.AFCMPU,
+		s390x.ACEBR,
+		s390x.AMVC,
+		s390x.ACLC,
+		s390x.AXC,
+		s390x.AOC,
+		s390x.ANC:
+		if s != nil {
+			copysub(&p.From, v, s)
+			copysub(&p.To, v, s)
+			return _None
+		}
+
+		if copyau(&p.From, v) {
+			return _Read
+		}
+		if copyau(&p.To, v) {
+			return _Read
+		}
+		return _None
+
+	case s390x.ACMPBNE, s390x.ACMPBEQ,
+		s390x.ACMPBLT, s390x.ACMPBLE,
+		s390x.ACMPBGT, s390x.ACMPBGE,
+		s390x.ACMPUBNE, s390x.ACMPUBEQ,
+		s390x.ACMPUBLT, s390x.ACMPUBLE,
+		s390x.ACMPUBGT, s390x.ACMPUBGE:
+		if s != nil {
+			copysub(&p.From, v, s)
+			copysub1(p, v, s)
+			return _None
+		}
+		if copyau(&p.From, v) {
+			return _Read
+		}
+		if copyau1(p, v) {
+			return _Read
+		}
+		return _None
+
+	case s390x.ACLEAR:
+		if s != nil {
+			copysub(&p.To, v, s)
+			return _None
+		}
+		if copyau(&p.To, v) {
+			return _Read
+		}
+		return _None
+
+	// go never generates a branch to a GPR
+	// read p.To
+	case s390x.ABR:
+		if s != nil {
+			copysub(&p.To, v, s)
+			return _None
+		}
+
+		if copyau(&p.To, v) {
+			return _Read
+		}
+		return _None
+
+	case obj.ARET, obj.AUNDEF:
+		if s != nil {
+			return _None
+		}
+
+		// All registers die at this point, so claim
+		// everything is set (and not used).
+		return _Write
+
+	case s390x.ABL:
+		if v.Type == obj.TYPE_REG {
+			if s390x.REGARG != -1 && v.Reg == s390x.REGARG {
+				return _ReadWriteSame
+			}
+			if p.From.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
+				return _ReadWriteSame
+			}
+			if v.Reg == s390x.REGZERO {
+				// Deliberately inserted nops set R0.
+				return _ReadWriteSame
+			}
+			if v.Reg == s390x.REGCTXT {
+				// Context register for closures.
+				// TODO(mundaym): not sure if we need to exclude this.
+				return _ReadWriteSame
+			}
+		}
+		if s != nil {
+			copysub(&p.To, v, s)
+			return _None
+		}
+		if copyau(&p.To, v) {
+			return _ReadWriteDiff
+		}
+		return _Write
+
+	case obj.ATEXT:
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == s390x.REGARG {
+				return _Write
+			}
+		}
+		return _None
+
+	case obj.APCDATA,
+		obj.AFUNCDATA,
+		obj.AVARDEF,
+		obj.AVARKILL,
+		obj.AVARLIVE,
+		obj.AUSEFIELD,
+		obj.ANOP:
+		return _None
+	}
+}
+
+// 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 isReg(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 isReg(v) && v.Reg != 0 {
+		if p.Reg == v.Reg {
+			return true
+		}
+	}
+	return false
+}
+
+// copysub replaces v.Reg with s.Reg if a.Reg and v.Reg are direct
+// references to the same register.
+func copysub(a, v, s *obj.Addr) {
+	if copyau(a, v) {
+		a.Reg = s.Reg
+	}
+}
+
+// copysub1 replaces p.Reg with s.Reg if p.Reg and v.Reg are direct
+// references to the same register.
+func copysub1(p *obj.Prog, v, s *obj.Addr) {
+	if copyau1(p, v) {
+		p.Reg = s.Reg
+	}
+}
+
+func sameaddr(a *obj.Addr, v *obj.Addr) bool {
+	if a.Type != v.Type {
+		return false
+	}
+	if isReg(v) && a.Reg == v.Reg {
+		return true
+	}
+	if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM {
+		// TODO(mundaym): is the offset enough here? Node?
+		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 {
+	// TODO(mundaym): the name implies this should check
+	// for TYPE_ADDR with a base register REGSP.
+	return a.Type == obj.TYPE_REG && a.Reg == s390x.REGSP
+}
+
+// isMove returns true if p is a move. Moves may imply
+// sign/zero extension.
+func isMove(p *obj.Prog) bool {
+	switch p.As {
+	case s390x.AMOVD,
+		s390x.AMOVW, s390x.AMOVWZ,
+		s390x.AMOVH, s390x.AMOVHZ,
+		s390x.AMOVB, s390x.AMOVBZ,
+		s390x.AFMOVD, s390x.AFMOVS:
+		return true
+	}
+	return false
+}
+
+// isLoad returns true if p is a move from memory to a register.
+func isLoad(p *obj.Prog) bool {
+	if !isMove(p) {
+		return false
+	}
+	if !(isGPR(&p.To) || isFPR(&p.To)) {
+		return false
+	}
+	if p.From.Type != obj.TYPE_MEM {
+		return false
+	}
+	return true
+}
+
+// isStore returns true if p is a move from a register to memory.
+func isStore(p *obj.Prog) bool {
+	if !isMove(p) {
+		return false
+	}
+	if !(isGPR(&p.From) || isFPR(&p.From) || isConst(&p.From)) {
+		return false
+	}
+	if p.To.Type != obj.TYPE_MEM {
+		return false
+	}
+	return true
+}
+
+// sameStackMem returns true if a and b are both memory operands
+// and address the same location which must reside on the stack.
+func sameStackMem(a, b *obj.Addr) bool {
+	if a.Type != obj.TYPE_MEM ||
+		b.Type != obj.TYPE_MEM ||
+		a.Name != b.Name ||
+		a.Sym != b.Sym ||
+		a.Node != b.Node ||
+		a.Reg != b.Reg ||
+		a.Index != b.Index ||
+		a.Offset != b.Offset {
+		return false
+	}
+	switch a.Name {
+	case obj.NAME_NONE:
+		return a.Reg == s390x.REGSP
+	case obj.NAME_PARAM, obj.NAME_AUTO:
+		// params and autos are always on the stack
+		return true
+	}
+	return false
+}
+
+// removeLoadHitStores trys to remove loads that take place
+// immediately after a store to the same location. Returns
+// true if load-hit-stores were removed.
+//
+// For example:
+// 	MOVD	R1, 0(R15)
+// 	MOVD	0(R15), R2
+// Would become:
+// 	MOVD	R1, 0(R15)
+// 	MOVD	R1, R2
+func removeLoadHitStores(r *gc.Flow) int {
+	n := 0
+	for ; r != nil; r = r.Link {
+		p := r.Prog
+		if !isStore(p) {
+			continue
+		}
+		for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
+			pp := rr.Prog
+			if gc.Uniqp(rr) == nil {
+				break
+			}
+			if pp.As == obj.ANOP {
+				continue
+			}
+			if isLoad(pp) && sameStackMem(&p.To, &pp.From) {
+				if size(p.As) >= size(pp.As) && isGPR(&p.From) == isGPR(&pp.To) {
+					pp.From = p.From
+				}
+			}
+			if !isMove(pp) || isStore(pp) {
+				break
+			}
+			if copyau(&p.From, &pp.To) {
+				break
+			}
+		}
+	}
+	return n
+}
+
+// size returns the width of the given move.
+func size(as obj.As) int {
+	switch as {
+	case s390x.AMOVD, s390x.AFMOVD:
+		return 8
+	case s390x.AMOVW, s390x.AMOVWZ, s390x.AFMOVS:
+		return 4
+	case s390x.AMOVH, s390x.AMOVHZ:
+		return 2
+	case s390x.AMOVB, s390x.AMOVBZ:
+		return 1
+	}
+	return -1
+}
+
+// castPropagation tries to eliminate unecessary casts.
+//
+// For example:
+// 	MOVHZ	R1, R2     // uint16
+//	MOVB	R2, 0(R15) // int8
+// Can be simplified to:
+//	MOVB	R1, 0(R15)
+func castPropagation(r *gc.Flow) int {
+	n := 0
+	for ; r != nil; r = r.Link {
+		p := r.Prog
+		if !isMove(p) || !isGPR(&p.To) {
+			continue
+		}
+
+		// r is a move with a destination register
+		var move *gc.Flow
+		for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
+			if gc.Uniqp(rr) == nil {
+				// branch target: leave alone
+				break
+			}
+			pp := rr.Prog
+			if isMove(pp) && copyas(&pp.From, &p.To) {
+				if pp.To.Type == obj.TYPE_MEM {
+					if p.From.Type == obj.TYPE_MEM ||
+						p.From.Type == obj.TYPE_ADDR {
+						break
+					}
+					if p.From.Type == obj.TYPE_CONST &&
+						int64(int16(p.From.Offset)) != p.From.Offset {
+						break
+					}
+				}
+				move = rr
+				break
+			}
+			if pp.As == obj.ANOP {
+				continue
+			}
+			break
+		}
+		if move == nil {
+			continue
+		}
+
+		// we have a move that reads from our destination reg, check if any future
+		// instructions also read from the reg
+		mp := move.Prog
+		if !copyas(&mp.From, &mp.To) {
+			safe := false
+			for rr := gc.Uniqs(move); rr != nil; rr = gc.Uniqs(rr) {
+				if gc.Uniqp(rr) == nil {
+					break
+				}
+				switch copyu(rr.Prog, &p.To, nil) {
+				case _None:
+					continue
+				case _Write:
+					safe = true
+				}
+				break
+			}
+			if !safe {
+				continue
+			}
+		}
+
+		// at this point we have something like:
+		// MOV* const/mem/reg, reg
+		// MOV* reg, reg/mem
+		// now check if this is a cast that cannot be forward propagated
+		execute := false
+		if p.As == mp.As || isZero(&p.From) || size(p.As) == size(mp.As) {
+			execute = true
+		} else if isGPR(&p.From) && size(p.As) >= size(mp.As) {
+			execute = true
+		}
+
+		if execute {
+			mp.From = p.From
+			excise(r)
+			n++
+		}
+	}
+	return n
+}
+
+// fuseClear merges memory clear operations.
+//
+// Looks for this pattern (sequence of clears):
+// 	MOVD	R0, n(R15)
+// 	MOVD	R0, n+8(R15)
+// 	MOVD	R0, n+16(R15)
+// Replaces with:
+//	CLEAR	$24, n(R15)
+func fuseClear(r *gc.Flow) int {
+	n := 0
+	var align int64
+	var clear *obj.Prog
+	for ; r != nil; r = r.Link {
+		// If there is a branch into the instruction stream then
+		// we can't fuse into previous instructions.
+		if gc.Uniqp(r) == nil {
+			clear = nil
+		}
+
+		p := r.Prog
+		if p.As == obj.ANOP {
+			continue
+		}
+		if p.As == s390x.AXC {
+			if p.From.Reg == p.To.Reg && p.From.Offset == p.To.Offset {
+				// TODO(mundaym): merge clears?
+				p.As = s390x.ACLEAR
+				p.From.Offset = p.From3.Offset
+				p.From3 = nil
+				p.From.Type = obj.TYPE_CONST
+				p.From.Reg = 0
+				clear = p
+			} else {
+				clear = nil
+			}
+			continue
+		}
+
+		// Is our source a constant zero?
+		if !isZero(&p.From) {
+			clear = nil
+			continue
+		}
+
+		// Are we moving to memory?
+		if p.To.Type != obj.TYPE_MEM ||
+			p.To.Index != 0 ||
+			p.To.Offset >= 4096 ||
+			!(p.To.Name == obj.NAME_NONE || p.To.Name == obj.NAME_AUTO || p.To.Name == obj.NAME_PARAM) {
+			clear = nil
+			continue
+		}
+
+		size := int64(0)
+		switch p.As {
+		default:
+			clear = nil
+			continue
+		case s390x.AMOVB, s390x.AMOVBZ:
+			size = 1
+		case s390x.AMOVH, s390x.AMOVHZ:
+			size = 2
+		case s390x.AMOVW, s390x.AMOVWZ:
+			size = 4
+		case s390x.AMOVD:
+			size = 8
+		}
+
+		// doubleword aligned clears should be kept doubleword
+		// aligned
+		if (size == 8 && align != 8) || (size != 8 && align == 8) {
+			clear = nil
+		}
+
+		if clear != nil &&
+			clear.To.Reg == p.To.Reg &&
+			clear.To.Name == p.To.Name &&
+			clear.To.Node == p.To.Node &&
+			clear.To.Sym == p.To.Sym {
+
+			min := clear.To.Offset
+			max := clear.To.Offset + clear.From.Offset
+
+			// previous clear is already clearing this region
+			if min <= p.To.Offset && max >= p.To.Offset+size {
+				excise(r)
+				n++
+				continue
+			}
+
+			// merge forwards
+			if max == p.To.Offset {
+				clear.From.Offset += size
+				excise(r)
+				n++
+				continue
+			}
+
+			// merge backwards
+			if min-size == p.To.Offset {
+				clear.From.Offset += size
+				clear.To.Offset -= size
+				excise(r)
+				n++
+				continue
+			}
+		}
+
+		// transform into clear
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = size
+		p.From.Reg = 0
+		p.As = s390x.ACLEAR
+		clear = p
+		align = size
+	}
+	return n
+}
+
+// fuseMultiple merges memory loads and stores into load multiple and
+// store multiple operations.
+//
+// Looks for this pattern (sequence of loads or stores):
+// 	MOVD	R1, 0(R15)
+//	MOVD	R2, 8(R15)
+//	MOVD	R3, 16(R15)
+// Replaces with:
+//	STMG	R1, R3, 0(R15)
+func fuseMultiple(r *gc.Flow) int {
+	n := 0
+	var fused *obj.Prog
+	for ; r != nil; r = r.Link {
+		// If there is a branch into the instruction stream then
+		// we can't fuse into previous instructions.
+		if gc.Uniqp(r) == nil {
+			fused = nil
+		}
+
+		p := r.Prog
+
+		isStore := isGPR(&p.From) && isBDMem(&p.To)
+		isLoad := isGPR(&p.To) && isBDMem(&p.From)
+
+		// are we a candidate?
+		size := int64(0)
+		switch p.As {
+		default:
+			fused = nil
+			continue
+		case obj.ANOP:
+			// skip over nops
+			continue
+		case s390x.AMOVW, s390x.AMOVWZ:
+			size = 4
+			// TODO(mundaym): 32-bit load multiple is currently not supported
+			// as it requires sign/zero extension.
+			if !isStore {
+				fused = nil
+				continue
+			}
+		case s390x.AMOVD:
+			size = 8
+			if !isLoad && !isStore {
+				fused = nil
+				continue
+			}
+		}
+
+		// If we merge two loads/stores with different source/destination Nodes
+		// then we will lose a reference the second Node which means that the
+		// compiler might mark the Node as unused and free its slot on the stack.
+		// TODO(mundaym): allow this by adding a dummy reference to the Node.
+		if fused == nil ||
+			fused.From.Node != p.From.Node ||
+			fused.From.Type != p.From.Type ||
+			fused.To.Node != p.To.Node ||
+			fused.To.Type != p.To.Type {
+			fused = p
+			continue
+		}
+
+		// check two addresses
+		ca := func(a, b *obj.Addr, offset int64) bool {
+			return a.Reg == b.Reg && a.Offset+offset == b.Offset &&
+				a.Sym == b.Sym && a.Name == b.Name
+		}
+
+		switch fused.As {
+		default:
+			fused = p
+		case s390x.AMOVW, s390x.AMOVWZ:
+			if size == 4 && fused.From.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, 4) {
+				fused.As = s390x.ASTMY
+				fused.Reg = p.From.Reg
+				excise(r)
+				n++
+			} else {
+				fused = p
+			}
+		case s390x.AMOVD:
+			if size == 8 && fused.From.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, 8) {
+				fused.As = s390x.ASTMG
+				fused.Reg = p.From.Reg
+				excise(r)
+				n++
+			} else if size == 8 && fused.To.Reg+1 == p.To.Reg && ca(&fused.From, &p.From, 8) {
+				fused.As = s390x.ALMG
+				fused.Reg = fused.To.Reg
+				fused.To.Reg = p.To.Reg
+				excise(r)
+				n++
+			} else {
+				fused = p
+			}
+		case s390x.ASTMG, s390x.ASTMY:
+			if (fused.As == s390x.ASTMY && size != 4) ||
+				(fused.As == s390x.ASTMG && size != 8) {
+				fused = p
+				continue
+			}
+			offset := size * int64(fused.Reg-fused.From.Reg+1)
+			if fused.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, offset) {
+				fused.Reg = p.From.Reg
+				excise(r)
+				n++
+			} else {
+				fused = p
+			}
+		case s390x.ALMG:
+			offset := 8 * int64(fused.To.Reg-fused.Reg+1)
+			if size == 8 && fused.To.Reg+1 == p.To.Reg && ca(&fused.From, &p.From, offset) {
+				fused.To.Reg = p.To.Reg
+				excise(r)
+				n++
+			} else {
+				fused = p
+			}
+		}
+	}
+	return n
+}
+
+// simplifyOps looks for side-effect free ops that can be removed or
+// replaced with moves.
+//
+// For example:
+// 	XOR $0, R1 => NOP
+//	ADD $0, R1, R2 => MOVD R1, R2
+func simplifyOps(r *gc.Flow) int {
+	n := 0
+	for ; r != nil; r = r.Link {
+		p := r.Prog
+
+		// if the target is R0 then this is a required NOP
+		if isGPR(&p.To) && p.To.Reg == s390x.REGZERO {
+			continue
+		}
+
+		switch p.As {
+		case s390x.AADD, s390x.ASUB,
+			s390x.AOR, s390x.AXOR,
+			s390x.ASLW, s390x.ASRW, s390x.ASRAW,
+			s390x.ASLD, s390x.ASRD, s390x.ASRAD,
+			s390x.ARLL, s390x.ARLLG:
+			if isZero(&p.From) && isGPR(&p.To) {
+				if p.Reg == 0 || p.Reg == p.To.Reg {
+					excise(r)
+					n++
+				} else {
+					p.As = s390x.AMOVD
+					p.From.Type = obj.TYPE_REG
+					p.From.Reg = p.Reg
+					p.Reg = 0
+				}
+			}
+		case s390x.AMULLW, s390x.AAND:
+			if isZero(&p.From) && isGPR(&p.To) {
+				p.As = s390x.AMOVD
+				p.From.Type = obj.TYPE_REG
+				p.From.Reg = s390x.REGZERO
+				p.Reg = 0
+			}
+		}
+	}
+	return n
+}
+
+// fuseOpMoves looks for moves following 2-operand operations and trys to merge them into
+// a 3-operand operation.
+//
+// For example:
+//	ADD R1, R2
+//	MOVD R2, R3
+// might become
+//	ADD R1, R2, R3
+func fuseOpMoves(r *gc.Flow) int {
+	n := 0
+	for ; r != nil; r = r.Link {
+		p := r.Prog
+		switch p.As {
+		case s390x.AADD:
+		case s390x.ASUB:
+			if isConst(&p.From) && int64(int16(p.From.Offset)) != p.From.Offset {
+				continue
+			}
+		case s390x.ASLW,
+			s390x.ASRW,
+			s390x.ASRAW,
+			s390x.ASLD,
+			s390x.ASRD,
+			s390x.ASRAD,
+			s390x.ARLL,
+			s390x.ARLLG:
+			// ok - p.From will be a reg or a constant
+		case s390x.AOR,
+			s390x.AORN,
+			s390x.AAND,
+			s390x.AANDN,
+			s390x.ANAND,
+			s390x.ANOR,
+			s390x.AXOR,
+			s390x.AMULLW,
+			s390x.AMULLD:
+			if isConst(&p.From) {
+				// these instructions can either use 3 register form
+				// or have an immediate but not both
+				continue
+			}
+		default:
+			continue
+		}
+
+		if p.Reg != 0 && p.Reg != p.To.Reg {
+			continue
+		}
+
+		var move *gc.Flow
+		rr := gc.Uniqs(r)
+		for {
+			if rr == nil || gc.Uniqp(rr) == nil || rr == r {
+				break
+			}
+			pp := rr.Prog
+			switch copyu(pp, &p.To, nil) {
+			case _None:
+				rr = gc.Uniqs(rr)
+				continue
+			case _Read:
+				if move == nil && pp.As == s390x.AMOVD && isGPR(&pp.From) && isGPR(&pp.To) {
+					move = rr
+					rr = gc.Uniqs(rr)
+					continue
+				}
+			case _Write:
+				if move == nil {
+					// dead code
+					excise(r)
+					n++
+				} else {
+					for prev := gc.Uniqp(move); prev != r; prev = gc.Uniqp(prev) {
+						if copyu(prev.Prog, &move.Prog.To, nil) != 0 {
+							move = nil
+							break
+						}
+					}
+					if move == nil {
+						break
+					}
+					p.Reg, p.To.Reg = p.To.Reg, move.Prog.To.Reg
+					excise(move)
+					n++
+
+					// clean up
+					if p.From.Reg == p.To.Reg && isCommutative(p.As) {
+						p.From.Reg, p.Reg = p.Reg, 0
+					}
+					if p.To.Reg == p.Reg {
+						p.Reg = 0
+					}
+					// we could try again if p has become a 2-operand op
+					// but in testing nothing extra was extracted
+				}
+			}
+			break
+		}
+	}
+	return n
+}
+
+// isCommutative returns true if the order of input operands
+// does not affect the result. For example:
+//	x + y == y + x so ADD is commutative
+//	x ^ y == y ^ x so XOR is commutative
+func isCommutative(as obj.As) bool {
+	switch as {
+	case s390x.AADD,
+		s390x.AOR,
+		s390x.AAND,
+		s390x.AXOR,
+		s390x.AMULLW,
+		s390x.AMULLD:
+		return true
+	}
+	return false
+}
+
+// applyCast applies the cast implied by the given move
+// instruction to v and returns the result.
+func applyCast(cast obj.As, v int64) int64 {
+	switch cast {
+	case s390x.AMOVWZ:
+		return int64(uint32(v))
+	case s390x.AMOVHZ:
+		return int64(uint16(v))
+	case s390x.AMOVBZ:
+		return int64(uint8(v))
+	case s390x.AMOVW:
+		return int64(int32(v))
+	case s390x.AMOVH:
+		return int64(int16(v))
+	case s390x.AMOVB:
+		return int64(int8(v))
+	}
+	return v
+}
+
+// constantPropagation removes redundant constant copies.
+func constantPropagation(r *gc.Flow) int {
+	n := 0
+	// find MOV $con,R followed by
+	// another MOV $con,R without
+	// setting R in the interim
+	for ; r != nil; r = r.Link {
+		p := r.Prog
+		if isMove(p) {
+			if !isReg(&p.To) {
+				continue
+			}
+			if !isConst(&p.From) {
+				continue
+			}
+		} else {
+			continue
+		}
+
+		rr := r
+		for {
+			rr = gc.Uniqs(rr)
+			if rr == nil || rr == r {
+				break
+			}
+			if gc.Uniqp(rr) == nil {
+				break
+			}
+
+			pp := rr.Prog
+			t := copyu(pp, &p.To, nil)
+			switch t {
+			case _None:
+				continue
+			case _Read:
+				if !isGPR(&pp.From) || !isMove(pp) {
+					continue
+				}
+				if p.From.Type == obj.TYPE_CONST {
+					v := applyCast(p.As, p.From.Offset)
+					if isGPR(&pp.To) {
+						if int64(int32(v)) == v || ((v>>32)<<32) == v {
+							pp.From.Reg = 0
+							pp.From.Offset = v
+							pp.From.Type = obj.TYPE_CONST
+							n++
+						}
+					} else if int64(int16(v)) == v {
+						pp.From.Reg = 0
+						pp.From.Offset = v
+						pp.From.Type = obj.TYPE_CONST
+						n++
+					}
+				}
+				continue
+			case _Write:
+				if p.As != pp.As || p.From.Type != pp.From.Type {
+					break
+				}
+				if p.From.Type == obj.TYPE_CONST && p.From.Offset == pp.From.Offset {
+					excise(rr)
+					n++
+					continue
+				} else if p.From.Type == obj.TYPE_FCONST {
+					if p.From.Val.(float64) == pp.From.Val.(float64) {
+						excise(rr)
+						n++
+						continue
+					}
+				}
+			}
+			break
+		}
+	}
+	return n
+}
+
+// copyPropagation tries to eliminate register-to-register moves.
+func copyPropagation(r *gc.Flow) int {
+	n := 0
+	for ; r != nil; r = r.Link {
+		p := r.Prog
+		if isMove(p) && isReg(&p.To) {
+			// Convert uses to $0 to uses of R0 and
+			// propagate R0
+			if isGPR(&p.To) && isZero(&p.From) {
+				p.From.Type = obj.TYPE_REG
+				p.From.Reg = s390x.REGZERO
+			}
+
+			// Try to eliminate reg->reg moves
+			if isGPR(&p.From) || isFPR(&p.From) {
+				if copyprop(r) || (subprop(r) && copyprop(r)) {
+					excise(r)
+					n++
+				}
+			}
+		}
+	}
+	return n
+}
+
+// loadPipelining pushes any load from memory as early as possible.
+func loadPipelining(r *gc.Flow) int {
+	for ; r != nil; r = r.Link {
+		p := r.Prog
+		if isLoad(p) {
+			pushback(r)
+		}
+	}
+	return 0
+}
+
+// fuseCompareBranch finds comparisons followed by a branch and converts
+// them into a compare-and-branch instruction (which avoid setting the
+// condition code).
+func fuseCompareBranch(r *gc.Flow) int {
+	n := 0
+	for ; r != nil; r = r.Link {
+		p := r.Prog
+		r1 := gc.Uniqs(r)
+		if r1 == nil {
+			continue
+		}
+		p1 := r1.Prog
+
+		var ins obj.As
+		switch p.As {
+		case s390x.ACMP:
+			switch p1.As {
+			case s390x.ABCL, s390x.ABC:
+				continue
+			case s390x.ABEQ:
+				ins = s390x.ACMPBEQ
+			case s390x.ABGE:
+				ins = s390x.ACMPBGE
+			case s390x.ABGT:
+				ins = s390x.ACMPBGT
+			case s390x.ABLE:
+				ins = s390x.ACMPBLE
+			case s390x.ABLT:
+				ins = s390x.ACMPBLT
+			case s390x.ABNE:
+				ins = s390x.ACMPBNE
+			default:
+				continue
+			}
+
+		case s390x.ACMPU:
+			switch p1.As {
+			case s390x.ABCL, s390x.ABC:
+				continue
+			case s390x.ABEQ:
+				ins = s390x.ACMPUBEQ
+			case s390x.ABGE:
+				ins = s390x.ACMPUBGE
+			case s390x.ABGT:
+				ins = s390x.ACMPUBGT
+			case s390x.ABLE:
+				ins = s390x.ACMPUBLE
+			case s390x.ABLT:
+				ins = s390x.ACMPUBLT
+			case s390x.ABNE:
+				ins = s390x.ACMPUBNE
+			default:
+				continue
+			}
+
+		case s390x.ACMPW, s390x.ACMPWU:
+			continue
+
+		default:
+			continue
+		}
+
+		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+			fmt.Printf("cnb %v; %v  ", p, p1)
+		}
+
+		if p1.To.Sym != nil {
+			continue
+		}
+
+		if p.To.Type == obj.TYPE_REG {
+			p1.As = ins
+			p1.From = p.From
+			p1.Reg = p.To.Reg
+			p1.From3 = nil
+		} else if p.To.Type == obj.TYPE_CONST {
+			switch p.As {
+			case s390x.ACMP, s390x.ACMPW:
+				if (p.To.Offset < -(1 << 7)) || (p.To.Offset >= ((1 << 7) - 1)) {
+					continue
+				}
+			case s390x.ACMPU, s390x.ACMPWU:
+				if p.To.Offset >= (1 << 8) {
+					continue
+				}
+			default:
+			}
+			p1.As = ins
+			p1.From = p.From
+			p1.Reg = 0
+			p1.From3 = new(obj.Addr)
+			*(p1.From3) = p.To
+		} else {
+			continue
+		}
+
+		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+			fmt.Printf("%v\n", p1)
+		}
+		excise(r)
+		n++
+	}
+	return n
+}
+
+// deadCodeElimination removes writes to registers which are written
+// to again before they are next read.
+func deadCodeElimination(r *gc.Flow) int {
+	n := 0
+	for ; r != nil; r = r.Link {
+		p := r.Prog
+		// Currently there are no instructions which write to multiple
+		// registers in copyu. This check will need to change if there
+		// ever are.
+		if !(isGPR(&p.To) || isFPR(&p.To)) || copyu(p, &p.To, nil) != _Write {
+			continue
+		}
+		for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
+			t := copyu(rr.Prog, &p.To, nil)
+			if t == _None {
+				continue
+			}
+			if t == _Write {
+				excise(r)
+				n++
+			}
+			break
+		}
+	}
+	return n
+}
diff --git a/src/cmd/compile/internal/s390x/prog.go b/src/cmd/compile/internal/s390x/prog.go
new file mode 100644
index 0000000..306adf8
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/prog.go
@@ -0,0 +1,179 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s390x
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/s390x"
+)
+
+// 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.
+var progtable = [s390x.ALAST & obj.AMask]obj.ProgInfo{
+	obj.ATYPE & obj.AMask:     {Flags: gc.Pseudo | gc.Skip},
+	obj.ATEXT & obj.AMask:     {Flags: gc.Pseudo},
+	obj.AFUNCDATA & obj.AMask: {Flags: gc.Pseudo},
+	obj.APCDATA & obj.AMask:   {Flags: gc.Pseudo},
+	obj.AUNDEF & obj.AMask:    {Flags: gc.Break},
+	obj.AUSEFIELD & obj.AMask: {Flags: gc.OK},
+	obj.ACHECKNIL & obj.AMask: {Flags: gc.LeftRead},
+	obj.AVARDEF & obj.AMask:   {Flags: gc.Pseudo | gc.RightWrite},
+	obj.AVARKILL & obj.AMask:  {Flags: gc.Pseudo | gc.RightWrite},
+	obj.AVARLIVE & obj.AMask:  {Flags: gc.Pseudo | gc.LeftRead},
+
+	// NOP is an internal no-op that also stands
+	// for USED and SET annotations.
+	obj.ANOP & obj.AMask: {Flags: gc.LeftRead | gc.RightWrite},
+
+	// Integer
+	s390x.AADD & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ASUB & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ANEG & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AAND & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AOR & obj.AMask:     {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AXOR & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AMULLD & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AMULLW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AMULHD & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AMULHDU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ADIVD & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ADIVDU & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ASLD & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ASRD & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ASRAD & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ARLL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ARLLG & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.ACMP & obj.AMask:    {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
+	s390x.ACMPU & obj.AMask:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
+
+	// Floating point.
+	s390x.AFADD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AFADDS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AFSUB & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AFSUBS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AFMUL & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AFMULS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AFDIV & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AFDIVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
+	s390x.AFCMPU & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
+	s390x.ACEBR & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightRead},
+	s390x.ALEDBR & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ALDEBR & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.AFSQRT & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
+
+	// Conversions
+	s390x.ACEFBRA & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACDFBRA & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACEGBRA & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACDGBRA & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACFEBRA & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACFDBRA & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACGEBRA & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACGDBRA & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACELFBR & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACDLFBR & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACELGBR & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACDLGBR & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACLFEBR & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACLFDBR & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACLGEBR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+	s390x.ACLGDBR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
+
+	// Moves
+	s390x.AMOVB & obj.AMask:  {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	s390x.AMOVBZ & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	s390x.AMOVH & obj.AMask:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	s390x.AMOVHZ & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	s390x.AMOVW & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	s390x.AMOVWZ & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	s390x.AMOVD & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
+	s390x.AFMOVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
+	s390x.AFMOVD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+
+	// Storage operations
+	s390x.AMVC & obj.AMask: {Flags: gc.LeftRead | gc.LeftAddr | gc.RightWrite | gc.RightAddr},
+	s390x.ACLC & obj.AMask: {Flags: gc.LeftRead | gc.LeftAddr | gc.RightRead | gc.RightAddr},
+	s390x.AXC & obj.AMask:  {Flags: gc.LeftRead | gc.LeftAddr | gc.RightWrite | gc.RightAddr},
+	s390x.AOC & obj.AMask:  {Flags: gc.LeftRead | gc.LeftAddr | gc.RightWrite | gc.RightAddr},
+	s390x.ANC & obj.AMask:  {Flags: gc.LeftRead | gc.LeftAddr | gc.RightWrite | gc.RightAddr},
+
+	// Jumps
+	s390x.ABR & obj.AMask:      {Flags: gc.Jump | gc.Break},
+	s390x.ABL & obj.AMask:      {Flags: gc.Call},
+	s390x.ABEQ & obj.AMask:     {Flags: gc.Cjmp},
+	s390x.ABNE & obj.AMask:     {Flags: gc.Cjmp},
+	s390x.ABGE & obj.AMask:     {Flags: gc.Cjmp},
+	s390x.ABLT & obj.AMask:     {Flags: gc.Cjmp},
+	s390x.ABGT & obj.AMask:     {Flags: gc.Cjmp},
+	s390x.ABLE & obj.AMask:     {Flags: gc.Cjmp},
+	s390x.ACMPBEQ & obj.AMask:  {Flags: gc.Cjmp},
+	s390x.ACMPBNE & obj.AMask:  {Flags: gc.Cjmp},
+	s390x.ACMPBGE & obj.AMask:  {Flags: gc.Cjmp},
+	s390x.ACMPBLT & obj.AMask:  {Flags: gc.Cjmp},
+	s390x.ACMPBGT & obj.AMask:  {Flags: gc.Cjmp},
+	s390x.ACMPBLE & obj.AMask:  {Flags: gc.Cjmp},
+	s390x.ACMPUBEQ & obj.AMask: {Flags: gc.Cjmp},
+	s390x.ACMPUBNE & obj.AMask: {Flags: gc.Cjmp},
+	s390x.ACMPUBGE & obj.AMask: {Flags: gc.Cjmp},
+	s390x.ACMPUBLT & obj.AMask: {Flags: gc.Cjmp},
+	s390x.ACMPUBGT & obj.AMask: {Flags: gc.Cjmp},
+	s390x.ACMPUBLE & obj.AMask: {Flags: gc.Cjmp},
+
+	// Macros
+	s390x.ACLEAR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightAddr | gc.RightWrite},
+
+	// Load/store multiple
+	s390x.ASTMG & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightAddr | gc.RightWrite},
+	s390x.ASTMY & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightAddr | gc.RightWrite},
+	s390x.ALMG & obj.AMask:  {Flags: gc.SizeQ | gc.LeftAddr | gc.LeftRead | gc.RightWrite},
+	s390x.ALMY & obj.AMask:  {Flags: gc.SizeL | gc.LeftAddr | gc.LeftRead | gc.RightWrite},
+
+	obj.ARET & obj.AMask: {Flags: gc.Break},
+}
+
+func proginfo(p *obj.Prog) {
+	info := &p.Info
+	*info = progtable[p.As&obj.AMask]
+	if info.Flags == 0 {
+		gc.Fatalf("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.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 {
+		info.Regindex |= 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
+	}
+
+	switch p.As {
+	// load multiple sets a range of registers
+	case s390x.ALMG, s390x.ALMY:
+		for r := p.Reg; r <= p.To.Reg; r++ {
+			info.Regset |= RtoB(int(r))
+		}
+	// store multiple reads a range of registers
+	case s390x.ASTMG, s390x.ASTMY:
+		for r := p.From.Reg; r <= p.Reg; r++ {
+			info.Reguse |= RtoB(int(r))
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/s390x/reg.go b/src/cmd/compile/internal/s390x/reg.go
new file mode 100644
index 0000000..4cb8a9d
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/reg.go
@@ -0,0 +1,130 @@
+// 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 s390x
+
+import "cmd/internal/obj/s390x"
+import "cmd/compile/internal/gc"
+
+const (
+	NREGVAR = 32 /* 16 general + 16 floating */
+)
+
+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 {
+	// Exclude registers with fixed functions
+	return RtoB(s390x.REG_R0) |
+		RtoB(s390x.REGSP) |
+		RtoB(s390x.REGG) |
+		RtoB(s390x.REGTMP) |
+		RtoB(s390x.REGTMP2) |
+		RtoB(s390x.REG_LR)
+}
+
+func doregbits(r int) uint64 {
+	return 0
+}
+
+/*
+ * track register variables including external registers:
+ *	bit	reg
+ *	0	R0
+ *	...	...
+ *	15	R15
+ *	16+0	F0
+ *	16+1	F1
+ *	...	...
+ *	16+15	F15
+ */
+func RtoB(r int) uint64 {
+	if r >= s390x.REG_R0 && r <= s390x.REG_R15 {
+		return 1 << uint(r-s390x.REG_R0)
+	}
+	if r >= s390x.REG_F0 && r <= s390x.REG_F15 {
+		return 1 << uint(16+r-s390x.REG_F0)
+	}
+	return 0
+}
+
+func BtoR(b uint64) int {
+	b &= 0xffff
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) + s390x.REG_R0
+}
+
+func BtoF(b uint64) int {
+	b >>= 16
+	b &= 0xffff
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) + s390x.REG_F0
+}
diff --git a/src/cmd/compile/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO
new file mode 100644
index 0000000..dad4880
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/TODO
@@ -0,0 +1,46 @@
+This is a list of things that need to be worked on.  It will hopefully
+be complete soon.
+
+Correctness
+-----------
+- Debugging info (check & fix as much as we can)
+
+Optimizations (better compiled code)
+------------------------------------
+- Reduce register pressure in scheduler
+- More strength reduction: multiply -> shift/add combos (Worth doing?)
+- Add a value range propagation pass (for bounds elim & bitwidth reduction)
+- Make dead store pass inter-block
+- If there are a lot of MOVQ $0, ..., then load
+  0 into a register and use the register as the source instead.
+- Allow arrays of length 1 (or longer, with all constant indexes?) to be SSAable.
+- If strings are being passed around without being interpreted (ptr
+  and len fields being accessed) pass them in xmm registers?
+  Same for interfaces?
+- Non-constant rotate detection.
+- Do 0 <= x && x < n with one unsigned compare
+- nil-check removal in indexed load/store case:
+    lea    (%rdx,%rax,1),%rcx
+    test   %al,(%rcx)           // nil check
+    mov    (%rdx,%rax,1),%cl    // load to same address
+- any pointer generated by unsafe arithmetic must be non-nil?
+  (Of course that may not be true in general, but it is for all uses
+   in the runtime, and we can play games with unsafe.)
+
+Optimizations (better compiler)
+-------------------------------
+- Handle signed division overflow and sign extension earlier
+
+Regalloc
+--------
+- Make less arch-dependent
+- Handle 2-address instructions
+- Make liveness analysis non-quadratic
+
+Future/other
+------------
+- Start another architecture (arm?)
+- 64-bit ops on 32-bit machines
+- Should we get rid of named types in favor of underlying types during SSA generation?
+- Infrastructure for enabling/disabling/configuring passes
+- Modify logging for at least pass=1, to be Warnl compatible
diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go
new file mode 100644
index 0000000..77f8306
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/block.go
@@ -0,0 +1,203 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "fmt"
+
+// Block represents a basic block in the control flow graph of a function.
+type Block struct {
+	// A unique identifier for the block. The system will attempt to allocate
+	// these IDs densely, but no guarantees.
+	ID ID
+
+	// Line number for block's control operation
+	Line int32
+
+	// The kind of block this is.
+	Kind BlockKind
+
+	// Likely direction for branches.
+	// If BranchLikely, Succs[0] is the most likely branch taken.
+	// If BranchUnlikely, Succs[1] is the most likely branch taken.
+	// Ignored if len(Succs) < 2.
+	// Fatal if not BranchUnknown and len(Succs) > 2.
+	Likely BranchPrediction
+
+	// After flagalloc, records whether flags are live at the end of the block.
+	FlagsLiveAtEnd bool
+
+	// Subsequent blocks, if any. The number and order depend on the block kind.
+	Succs []Edge
+
+	// Inverse of successors.
+	// The order is significant to Phi nodes in the block.
+	// TODO: predecessors is a pain to maintain. Can we somehow order phi
+	// arguments by block id and have this field computed explicitly when needed?
+	Preds []Edge
+
+	// A value that determines how the block is exited. Its value depends on the kind
+	// of the block. For instance, a BlockIf has a boolean control value and BlockExit
+	// has a memory control value.
+	Control *Value
+
+	// Auxiliary info for the block. Its value depends on the Kind.
+	Aux interface{}
+
+	// The unordered set of Values that define the operation of this block.
+	// The list must include the control value, if any. (TODO: need this last condition?)
+	// After the scheduling pass, this list is ordered.
+	Values []*Value
+
+	// The containing function
+	Func *Func
+
+	// Storage for Succs, Preds, and Values
+	succstorage [2]Edge
+	predstorage [4]Edge
+	valstorage  [9]*Value
+}
+
+// Edge represents a CFG edge.
+// Example edges for b branching to either c or d.
+// (c and d have other predecessors.)
+//   b.Succs = [{c,3}, {d,1}]
+//   c.Preds = [?, ?, ?, {b,0}]
+//   d.Preds = [?, {b,1}, ?]
+// These indexes allow us to edit the CFG in constant time.
+// In addition, it informs phi ops in degenerate cases like:
+// b:
+//    if k then c else c
+// c:
+//    v = Phi(x, y)
+// Then the indexes tell you whether x is chosen from
+// the if or else branch from b.
+//   b.Succs = [{c,0},{c,1}]
+//   c.Preds = [{b,0},{b,1}]
+// means x is chosen if k is true.
+type Edge struct {
+	// block edge goes to (in a Succs list) or from (in a Preds list)
+	b *Block
+	// index of reverse edge.  Invariant:
+	//   e := x.Succs[idx]
+	//   e.b.Preds[e.i] = Edge{x,idx}
+	// and similarly for predecessors.
+	i int
+}
+
+func (e Edge) Block() *Block {
+	return e.b
+}
+
+//     kind           control    successors
+//   ------------------------------------------
+//     Exit        return mem                []
+//    Plain               nil            [next]
+//       If   a boolean Value      [then, else]
+//     Call               mem  [nopanic, panic]  (control opcode should be OpCall or OpStaticCall)
+type BlockKind int8
+
+// short form print
+func (b *Block) String() string {
+	return fmt.Sprintf("b%d", b.ID)
+}
+
+// long form print
+func (b *Block) LongString() string {
+	s := b.Kind.String()
+	if b.Aux != nil {
+		s += fmt.Sprintf(" %s", b.Aux)
+	}
+	if b.Control != nil {
+		s += fmt.Sprintf(" %s", b.Control)
+	}
+	if len(b.Succs) > 0 {
+		s += " ->"
+		for _, c := range b.Succs {
+			s += " " + c.b.String()
+		}
+	}
+	switch b.Likely {
+	case BranchUnlikely:
+		s += " (unlikely)"
+	case BranchLikely:
+		s += " (likely)"
+	}
+	return s
+}
+
+func (b *Block) SetControl(v *Value) {
+	if w := b.Control; w != nil {
+		w.Uses--
+	}
+	b.Control = v
+	if v != nil {
+		v.Uses++
+	}
+}
+
+// AddEdgeTo adds an edge from block b to block c. Used during building of the
+// SSA graph; do not use on an already-completed SSA graph.
+func (b *Block) AddEdgeTo(c *Block) {
+	i := len(b.Succs)
+	j := len(c.Preds)
+	b.Succs = append(b.Succs, Edge{c, j})
+	c.Preds = append(c.Preds, Edge{b, i})
+}
+
+// removePred removes the ith input edge from b.
+// It is the responsibility of the caller to remove
+// the corresponding successor edge.
+func (b *Block) removePred(i int) {
+	n := len(b.Preds) - 1
+	if i != n {
+		e := b.Preds[n]
+		b.Preds[i] = e
+		// Update the other end of the edge we moved.
+		e.b.Succs[e.i].i = i
+	}
+	b.Preds[n] = Edge{}
+	b.Preds = b.Preds[:n]
+}
+
+// removeSucc removes the ith output edge from b.
+// It is the responsibility of the caller to remove
+// the corresponding predecessor edge.
+func (b *Block) removeSucc(i int) {
+	n := len(b.Succs) - 1
+	if i != n {
+		e := b.Succs[n]
+		b.Succs[i] = e
+		// Update the other end of the edge we moved.
+		e.b.Preds[e.i].i = i
+	}
+	b.Succs[n] = Edge{}
+	b.Succs = b.Succs[:n]
+}
+
+func (b *Block) swapSuccessors() {
+	if len(b.Succs) != 2 {
+		b.Fatalf("swapSuccessors with len(Succs)=%d", len(b.Succs))
+	}
+	e0 := b.Succs[0]
+	e1 := b.Succs[1]
+	b.Succs[0] = e1
+	b.Succs[1] = e0
+	e0.b.Preds[e0.i].i = 1
+	e1.b.Preds[e1.i].i = 0
+	b.Likely *= -1
+}
+
+func (b *Block) Logf(msg string, args ...interface{})           { b.Func.Logf(msg, args...) }
+func (b *Block) Log() bool                                      { return b.Func.Log() }
+func (b *Block) Fatalf(msg string, args ...interface{})         { b.Func.Fatalf(msg, args...) }
+func (b *Block) Unimplementedf(msg string, args ...interface{}) { b.Func.Unimplementedf(msg, args...) }
+
+type BranchPrediction int8
+
+const (
+	BranchUnlikely = BranchPrediction(-1)
+	BranchUnknown  = BranchPrediction(0)
+	BranchLikely   = BranchPrediction(+1)
+)
diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go
new file mode 100644
index 0000000..bfedd47
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/check.go
@@ -0,0 +1,330 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// checkFunc checks invariants of f.
+func checkFunc(f *Func) {
+	blockMark := make([]bool, f.NumBlocks())
+	valueMark := make([]bool, f.NumValues())
+
+	for _, b := range f.Blocks {
+		if blockMark[b.ID] {
+			f.Fatalf("block %s appears twice in %s!", b, f.Name)
+		}
+		blockMark[b.ID] = true
+		if b.Func != f {
+			f.Fatalf("%s.Func=%s, want %s", b, b.Func.Name, f.Name)
+		}
+
+		for i, e := range b.Preds {
+			if se := e.b.Succs[e.i]; se.b != b || se.i != i {
+				f.Fatalf("block pred/succ not crosslinked correctly %d:%s %d:%s", i, b, se.i, se.b)
+			}
+		}
+		for i, e := range b.Succs {
+			if pe := e.b.Preds[e.i]; pe.b != b || pe.i != i {
+				f.Fatalf("block succ/pred not crosslinked correctly %d:%s %d:%s", i, b, pe.i, pe.b)
+			}
+		}
+
+		switch b.Kind {
+		case BlockExit:
+			if len(b.Succs) != 0 {
+				f.Fatalf("exit block %s has successors", b)
+			}
+			if b.Control == nil {
+				f.Fatalf("exit block %s has no control value", b)
+			}
+			if !b.Control.Type.IsMemory() {
+				f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString())
+			}
+		case BlockRet:
+			if len(b.Succs) != 0 {
+				f.Fatalf("ret block %s has successors", b)
+			}
+			if b.Control == nil {
+				f.Fatalf("ret block %s has nil control", b)
+			}
+			if !b.Control.Type.IsMemory() {
+				f.Fatalf("ret block %s has non-memory control value %s", b, b.Control.LongString())
+			}
+		case BlockRetJmp:
+			if len(b.Succs) != 0 {
+				f.Fatalf("retjmp block %s len(Succs)==%d, want 0", b, len(b.Succs))
+			}
+			if b.Control == nil {
+				f.Fatalf("retjmp block %s has nil control", b)
+			}
+			if !b.Control.Type.IsMemory() {
+				f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Control.LongString())
+			}
+			if b.Aux == nil {
+				f.Fatalf("retjmp block %s has nil Aux field", b)
+			}
+		case BlockPlain:
+			if len(b.Succs) != 1 {
+				f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs))
+			}
+			if b.Control != nil {
+				f.Fatalf("plain block %s has non-nil control %s", b, b.Control.LongString())
+			}
+		case BlockIf:
+			if len(b.Succs) != 2 {
+				f.Fatalf("if block %s len(Succs)==%d, want 2", b, len(b.Succs))
+			}
+			if b.Control == nil {
+				f.Fatalf("if block %s has no control value", b)
+			}
+			if !b.Control.Type.IsBoolean() {
+				f.Fatalf("if block %s has non-bool control value %s", b, b.Control.LongString())
+			}
+		case BlockCall:
+			if len(b.Succs) != 1 {
+				f.Fatalf("call block %s len(Succs)==%d, want 1", b, len(b.Succs))
+			}
+			if b.Control == nil {
+				f.Fatalf("call block %s has no control value", b)
+			}
+			if !b.Control.Type.IsMemory() {
+				f.Fatalf("call block %s has non-memory control value %s", b, b.Control.LongString())
+			}
+		case BlockDefer:
+			if len(b.Succs) != 2 {
+				f.Fatalf("defer block %s len(Succs)==%d, want 2", b, len(b.Succs))
+			}
+			if b.Control == nil {
+				f.Fatalf("defer block %s has no control value", b)
+			}
+			if !b.Control.Type.IsMemory() {
+				f.Fatalf("defer block %s has non-memory control value %s", b, b.Control.LongString())
+			}
+		case BlockCheck:
+			if len(b.Succs) != 1 {
+				f.Fatalf("check block %s len(Succs)==%d, want 1", b, len(b.Succs))
+			}
+			if b.Control == nil {
+				f.Fatalf("check block %s has no control value", b)
+			}
+			if !b.Control.Type.IsVoid() {
+				f.Fatalf("check block %s has non-void control value %s", b, b.Control.LongString())
+			}
+		case BlockFirst:
+			if len(b.Succs) != 2 {
+				f.Fatalf("plain/dead block %s len(Succs)==%d, want 2", b, len(b.Succs))
+			}
+			if b.Control != nil {
+				f.Fatalf("plain/dead block %s has a control value", b)
+			}
+		}
+		if len(b.Succs) > 2 && b.Likely != BranchUnknown {
+			f.Fatalf("likeliness prediction %d for block %s with %d successors", b.Likely, b, len(b.Succs))
+		}
+
+		for _, v := range b.Values {
+			// Check to make sure argument count makes sense (argLen of -1 indicates
+			// variable length args)
+			nArgs := opcodeTable[v.Op].argLen
+			if nArgs != -1 && int32(len(v.Args)) != nArgs {
+				f.Fatalf("value %s has %d args, expected %d", v.LongString(),
+					len(v.Args), nArgs)
+			}
+
+			// Check to make sure aux values make sense.
+			canHaveAux := false
+			canHaveAuxInt := false
+			switch opcodeTable[v.Op].auxType {
+			case auxNone:
+			case auxBool:
+				if v.AuxInt < 0 || v.AuxInt > 1 {
+					f.Fatalf("bad bool AuxInt value for %v", v)
+				}
+				canHaveAuxInt = true
+			case auxInt8:
+				if v.AuxInt != int64(int8(v.AuxInt)) {
+					f.Fatalf("bad int8 AuxInt value for %v", v)
+				}
+				canHaveAuxInt = true
+			case auxInt16:
+				if v.AuxInt != int64(int16(v.AuxInt)) {
+					f.Fatalf("bad int16 AuxInt value for %v", v)
+				}
+				canHaveAuxInt = true
+			case auxInt32:
+				if v.AuxInt != int64(int32(v.AuxInt)) {
+					f.Fatalf("bad int32 AuxInt value for %v", v)
+				}
+				canHaveAuxInt = true
+			case auxInt64, auxFloat64:
+				canHaveAuxInt = true
+			case auxInt128:
+				// AuxInt must be zero, so leave canHaveAuxInt set to false.
+			case auxFloat32:
+				canHaveAuxInt = true
+				if !isExactFloat32(v) {
+					f.Fatalf("value %v has an AuxInt value that is not an exact float32", v)
+				}
+			case auxString, auxSym:
+				canHaveAux = true
+			case auxSymOff, auxSymValAndOff:
+				canHaveAuxInt = true
+				canHaveAux = true
+			case auxSymInt32:
+				if v.AuxInt != int64(int32(v.AuxInt)) {
+					f.Fatalf("bad int32 AuxInt value for %v", v)
+				}
+				canHaveAuxInt = true
+				canHaveAux = true
+			default:
+				f.Fatalf("unknown aux type for %s", v.Op)
+			}
+			if !canHaveAux && v.Aux != nil {
+				f.Fatalf("value %s has an Aux value %v but shouldn't", v.LongString(), v.Aux)
+			}
+			if !canHaveAuxInt && v.AuxInt != 0 {
+				f.Fatalf("value %s has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt)
+			}
+
+			for i, arg := range v.Args {
+				if arg == nil {
+					f.Fatalf("value %s has nil arg", v.LongString())
+				}
+				if v.Op != OpPhi {
+					// For non-Phi ops, memory args must be last, if present
+					if arg.Type.IsMemory() && i != len(v.Args)-1 {
+						f.Fatalf("value %s has non-final memory arg (%d < %d)", v.LongString(), i, len(v.Args)-1)
+					}
+				}
+			}
+
+			if valueMark[v.ID] {
+				f.Fatalf("value %s appears twice!", v.LongString())
+			}
+			valueMark[v.ID] = true
+
+			if v.Block != b {
+				f.Fatalf("%s.block != %s", v, b)
+			}
+			if v.Op == OpPhi && len(v.Args) != len(b.Preds) {
+				f.Fatalf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b)
+			}
+
+			if v.Op == OpAddr {
+				if len(v.Args) == 0 {
+					f.Fatalf("no args for OpAddr %s", v.LongString())
+				}
+				if v.Args[0].Op != OpSP && v.Args[0].Op != OpSB {
+					f.Fatalf("bad arg to OpAddr %v", v)
+				}
+			}
+
+			// TODO: check for cycles in values
+			// TODO: check type
+		}
+	}
+
+	// Check to make sure all Blocks referenced are in the function.
+	if !blockMark[f.Entry.ID] {
+		f.Fatalf("entry block %v is missing", f.Entry)
+	}
+	for _, b := range f.Blocks {
+		for _, c := range b.Preds {
+			if !blockMark[c.b.ID] {
+				f.Fatalf("predecessor block %v for %v is missing", c, b)
+			}
+		}
+		for _, c := range b.Succs {
+			if !blockMark[c.b.ID] {
+				f.Fatalf("successor block %v for %v is missing", c, b)
+			}
+		}
+	}
+
+	if len(f.Entry.Preds) > 0 {
+		f.Fatalf("entry block %s of %s has predecessor(s) %v", f.Entry, f.Name, f.Entry.Preds)
+	}
+
+	// Check to make sure all Values referenced are in the function.
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			for i, a := range v.Args {
+				if !valueMark[a.ID] {
+					f.Fatalf("%v, arg %d of %s, is missing", a, i, v.LongString())
+				}
+			}
+		}
+		if b.Control != nil && !valueMark[b.Control.ID] {
+			f.Fatalf("control value for %s is missing: %v", b, b.Control)
+		}
+	}
+	for b := f.freeBlocks; b != nil; b = b.succstorage[0].b {
+		if blockMark[b.ID] {
+			f.Fatalf("used block b%d in free list", b.ID)
+		}
+	}
+	for v := f.freeValues; v != nil; v = v.argstorage[0] {
+		if valueMark[v.ID] {
+			f.Fatalf("used value v%d in free list", v.ID)
+		}
+	}
+
+	// Check to make sure all args dominate uses.
+	if f.RegAlloc == nil {
+		// Note: regalloc introduces non-dominating args.
+		// See TODO in regalloc.go.
+		idom := dominators(f)
+		sdom := newSparseTree(f, idom)
+		for _, b := range f.Blocks {
+			for _, v := range b.Values {
+				for i, arg := range v.Args {
+					x := arg.Block
+					y := b
+					if v.Op == OpPhi {
+						y = b.Preds[i].b
+					}
+					if !domCheck(f, sdom, x, y) {
+						f.Fatalf("arg %d of value %s does not dominate, arg=%s", i, v.LongString(), arg.LongString())
+					}
+				}
+			}
+			if b.Control != nil && !domCheck(f, sdom, b.Control.Block, b) {
+				f.Fatalf("control value %s for %s doesn't dominate", b.Control, b)
+			}
+		}
+	}
+
+	// Check use counts
+	uses := make([]int32, f.NumValues())
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			for _, a := range v.Args {
+				uses[a.ID]++
+			}
+		}
+		if b.Control != nil {
+			uses[b.Control.ID]++
+		}
+	}
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if v.Uses != uses[v.ID] {
+				f.Fatalf("%s has %d uses, but has Uses=%d", v, uses[v.ID], v.Uses)
+			}
+		}
+	}
+}
+
+// domCheck reports whether x dominates y (including x==y).
+func domCheck(f *Func, sdom SparseTree, x, y *Block) bool {
+	if !sdom.isAncestorEq(f.Entry, y) {
+		// unreachable - ignore
+		return true
+	}
+	return sdom.isAncestorEq(x, y)
+}
+
+// isExactFloat32 reoprts whether v has an AuxInt that can be exactly represented as a float32.
+func isExactFloat32(v *Value) bool {
+	return v.AuxFloat() == float64(float32(v.AuxFloat()))
+}
diff --git a/src/cmd/compile/internal/ssa/checkbce.go b/src/cmd/compile/internal/ssa/checkbce.go
new file mode 100644
index 0000000..820ea6e
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/checkbce.go
@@ -0,0 +1,23 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// checkbce prints all bounds checks that are present in the function.
+// Useful to find regressions. checkbce is only activated when with
+// corresponsing debug options, so it's off by default.
+// See test/checkbce.go
+func checkbce(f *Func) {
+	if f.pass.debug <= 0 {
+		return
+	}
+
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if v.Op == OpIsInBounds || v.Op == OpIsSliceInBounds {
+				f.Config.Warnl(v.Line, "Found %v", v.Op)
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
new file mode 100644
index 0000000..b3c7544
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -0,0 +1,362 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"fmt"
+	"log"
+	"regexp"
+	"runtime"
+	"strings"
+	"time"
+)
+
+// Compile is the main entry point for this package.
+// Compile modifies f so that on return:
+//   · all Values in f map to 0 or 1 assembly instructions of the target architecture
+//   · the order of f.Blocks is the order to emit the Blocks
+//   · the order of b.Values is the order to emit the Values in each Block
+//   · f has a non-nil regAlloc field
+func Compile(f *Func) {
+	// TODO: debugging - set flags to control verbosity of compiler,
+	// which phases to dump IR before/after, etc.
+	if f.Log() {
+		f.Logf("compiling %s\n", f.Name)
+	}
+
+	// hook to print function & phase if panic happens
+	phaseName := "init"
+	defer func() {
+		if phaseName != "" {
+			err := recover()
+			stack := make([]byte, 16384)
+			n := runtime.Stack(stack, false)
+			stack = stack[:n]
+			f.Fatalf("panic during %s while compiling %s:\n\n%v\n\n%s\n", phaseName, f.Name, err, stack)
+		}
+	}()
+
+	// Run all the passes
+	printFunc(f)
+	f.Config.HTML.WriteFunc("start", f)
+	if checkEnabled {
+		checkFunc(f)
+	}
+	const logMemStats = false
+	for _, p := range passes {
+		if !f.Config.optimize && !p.required || p.disabled {
+			continue
+		}
+		f.pass = &p
+		phaseName = p.name
+		if f.Log() {
+			f.Logf("  pass %s begin\n", p.name)
+		}
+		// TODO: capture logging during this pass, add it to the HTML
+		var mStart runtime.MemStats
+		if logMemStats || p.mem {
+			runtime.ReadMemStats(&mStart)
+		}
+
+		tStart := time.Now()
+		p.fn(f)
+		tEnd := time.Now()
+
+		// Need something less crude than "Log the whole intermediate result".
+		if f.Log() || f.Config.HTML != nil {
+			time := tEnd.Sub(tStart).Nanoseconds()
+			var stats string
+			if logMemStats {
+				var mEnd runtime.MemStats
+				runtime.ReadMemStats(&mEnd)
+				nBytes := mEnd.TotalAlloc - mStart.TotalAlloc
+				nAllocs := mEnd.Mallocs - mStart.Mallocs
+				stats = fmt.Sprintf("[%d ns %d allocs %d bytes]", time, nAllocs, nBytes)
+			} else {
+				stats = fmt.Sprintf("[%d ns]", time)
+			}
+
+			f.Logf("  pass %s end %s\n", p.name, stats)
+			printFunc(f)
+			f.Config.HTML.WriteFunc(fmt.Sprintf("after %s <span class=\"stats\">%s</span>", phaseName, stats), f)
+		}
+		if p.time || p.mem {
+			// Surround timing information w/ enough context to allow comparisons.
+			time := tEnd.Sub(tStart).Nanoseconds()
+			if p.time {
+				f.LogStat("TIME(ns)", time)
+			}
+			if p.mem {
+				var mEnd runtime.MemStats
+				runtime.ReadMemStats(&mEnd)
+				nBytes := mEnd.TotalAlloc - mStart.TotalAlloc
+				nAllocs := mEnd.Mallocs - mStart.Mallocs
+				f.LogStat("TIME(ns):BYTES:ALLOCS", time, nBytes, nAllocs)
+			}
+		}
+		if checkEnabled {
+			checkFunc(f)
+		}
+	}
+
+	// Squash error printing defer
+	phaseName = ""
+}
+
+type pass struct {
+	name     string
+	fn       func(*Func)
+	required bool
+	disabled bool
+	time     bool // report time to run pass
+	mem      bool // report mem stats to run pass
+	stats    int  // pass reports own "stats" (e.g., branches removed)
+	debug    int  // pass performs some debugging. =1 should be in error-testing-friendly Warnl format.
+	test     int  // pass-specific ad-hoc option, perhaps useful in development
+}
+
+// Run consistency checker between each phase
+var checkEnabled = false
+
+// Debug output
+var IntrinsicsDebug int
+var IntrinsicsDisable bool
+
+var BuildDebug int
+var BuildTest int
+var BuildStats int
+
+// PhaseOption sets the specified flag in the specified ssa phase,
+// returning empty string if this was successful or a string explaining
+// the error if it was not.
+// A version of the phase name with "_" replaced by " " is also checked for a match.
+// If the phase name begins a '~' then the rest of the underscores-replaced-with-blanks
+// version is used as a regular expression to match the phase name(s).
+//
+// Special cases that have turned out to be useful:
+//  ssa/check/on enables checking after each phase
+//  ssa/all/time enables time reporting for all phases
+//
+// See gc/lex.go for dissection of the option string.
+// Example uses:
+//
+// GO_GCFLAGS=-d=ssa/generic_cse/time,ssa/generic_cse/stats,ssa/generic_cse/debug=3 ./make.bash
+//
+// BOOT_GO_GCFLAGS=-d='ssa/~^.*scc$/off' GO_GCFLAGS='-d=ssa/~^.*scc$/off' ./make.bash
+//
+func PhaseOption(phase, flag string, val int) string {
+	if phase == "check" && flag == "on" {
+		checkEnabled = val != 0
+		return ""
+	}
+	if phase == "check" && flag == "off" {
+		checkEnabled = val == 0
+		return ""
+	}
+
+	alltime := false
+	if phase == "all" {
+		if flag == "time" {
+			alltime = val != 0
+		} else {
+			return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
+		}
+	}
+
+	if phase == "intrinsics" {
+		switch flag {
+		case "on":
+			IntrinsicsDisable = val == 0
+		case "off":
+			IntrinsicsDisable = val != 0
+		case "debug":
+			IntrinsicsDebug = val
+		default:
+			return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
+		}
+		return ""
+	}
+	if phase == "build" {
+		switch flag {
+		case "debug":
+			BuildDebug = val
+		case "test":
+			BuildTest = val
+		case "stats":
+			BuildStats = val
+		default:
+			return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
+		}
+		return ""
+	}
+
+	underphase := strings.Replace(phase, "_", " ", -1)
+	var re *regexp.Regexp
+	if phase[0] == '~' {
+		r, ok := regexp.Compile(underphase[1:])
+		if ok != nil {
+			return fmt.Sprintf("Error %s in regexp for phase %s, flag %s", ok.Error(), phase, flag)
+		}
+		re = r
+	}
+	matchedOne := false
+	for i, p := range passes {
+		if phase == "all" {
+			p.time = alltime
+			passes[i] = p
+			matchedOne = true
+		} else if p.name == phase || p.name == underphase || re != nil && re.MatchString(p.name) {
+			switch flag {
+			case "on":
+				p.disabled = val == 0
+			case "off":
+				p.disabled = val != 0
+			case "time":
+				p.time = val != 0
+			case "mem":
+				p.mem = val != 0
+			case "debug":
+				p.debug = val
+			case "stats":
+				p.stats = val
+			case "test":
+				p.test = val
+			default:
+				return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
+			}
+			if p.disabled && p.required {
+				return fmt.Sprintf("Cannot disable required SSA phase %s using -d=ssa/%s debug option", phase, phase)
+			}
+			passes[i] = p
+			matchedOne = true
+		}
+	}
+	if matchedOne {
+		return ""
+	}
+	return fmt.Sprintf("Did not find a phase matching %s in -d=ssa/... debug option", phase)
+}
+
+// list of passes for the compiler
+var passes = [...]pass{
+	// TODO: combine phielim and copyelim into a single pass?
+	{name: "early phielim", fn: phielim},
+	{name: "early copyelim", fn: copyelim},
+	{name: "early deadcode", fn: deadcode}, // remove generated dead code to avoid doing pointless work during opt
+	{name: "short circuit", fn: shortcircuit},
+	{name: "decompose user", fn: decomposeUser, required: true},
+	{name: "opt", fn: opt, required: true},               // TODO: split required rules and optimizing rules
+	{name: "zero arg cse", fn: zcse, required: true},     // required to merge OpSB values
+	{name: "opt deadcode", fn: deadcode, required: true}, // remove any blocks orphaned during opt
+	{name: "generic domtree", fn: domTree},
+	{name: "generic cse", fn: cse},
+	{name: "phiopt", fn: phiopt},
+	{name: "nilcheckelim", fn: nilcheckelim},
+	{name: "prove", fn: prove},
+	{name: "loopbce", fn: loopbce},
+	{name: "decompose builtin", fn: decomposeBuiltIn, required: true},
+	{name: "dec", fn: dec, required: true},
+	{name: "late opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
+	{name: "generic deadcode", fn: deadcode},
+	{name: "check bce", fn: checkbce},
+	{name: "fuse", fn: fuse},
+	{name: "dse", fn: dse},
+	{name: "tighten", fn: tighten}, // move values closer to their uses
+	{name: "lower", fn: lower, required: true},
+	{name: "lowered cse", fn: cse},
+	{name: "lowered deadcode", fn: deadcode, required: true},
+	{name: "checkLower", fn: checkLower, required: true},
+	{name: "late phielim", fn: phielim},
+	{name: "late copyelim", fn: copyelim},
+	{name: "late deadcode", fn: deadcode},
+	{name: "critical", fn: critical, required: true}, // remove critical edges
+	{name: "likelyadjust", fn: likelyadjust},
+	{name: "layout", fn: layout, required: true},       // schedule blocks
+	{name: "schedule", fn: schedule, required: true},   // schedule values
+	{name: "flagalloc", fn: flagalloc, required: true}, // allocate flags register
+	{name: "regalloc", fn: regalloc, required: true},   // allocate int & float registers + stack slots
+	{name: "trim", fn: trim},                           // remove empty blocks
+}
+
+// Double-check phase ordering constraints.
+// This code is intended to document the ordering requirements
+// between different phases. It does not override the passes
+// list above.
+type constraint struct {
+	a, b string // a must come before b
+}
+
+var passOrder = [...]constraint{
+	// prove reliese on common-subexpression elimination for maximum benefits.
+	{"generic cse", "prove"},
+	// deadcode after prove to eliminate all new dead blocks.
+	{"prove", "generic deadcode"},
+	// common-subexpression before dead-store elim, so that we recognize
+	// when two address expressions are the same.
+	{"generic cse", "dse"},
+	// cse substantially improves nilcheckelim efficacy
+	{"generic cse", "nilcheckelim"},
+	// allow deadcode to clean up after nilcheckelim
+	{"nilcheckelim", "generic deadcode"},
+	// nilcheckelim generates sequences of plain basic blocks
+	{"nilcheckelim", "fuse"},
+	// nilcheckelim relies on opt to rewrite user nil checks
+	{"opt", "nilcheckelim"},
+	// tighten should happen before lowering to avoid splitting naturally paired instructions such as CMP/SET
+	{"tighten", "lower"},
+	// cse, phiopt, nilcheckelim, prove and loopbce share idom.
+	{"generic domtree", "generic cse"},
+	{"generic domtree", "phiopt"},
+	{"generic domtree", "nilcheckelim"},
+	{"generic domtree", "prove"},
+	{"generic domtree", "loopbce"},
+	// tighten will be most effective when as many values have been removed as possible
+	{"generic deadcode", "tighten"},
+	{"generic cse", "tighten"},
+	// checkbce needs the values removed
+	{"generic deadcode", "check bce"},
+	// don't run optimization pass until we've decomposed builtin objects
+	{"decompose builtin", "late opt"},
+	// don't layout blocks until critical edges have been removed
+	{"critical", "layout"},
+	// regalloc requires the removal of all critical edges
+	{"critical", "regalloc"},
+	// regalloc requires all the values in a block to be scheduled
+	{"schedule", "regalloc"},
+	// checkLower must run after lowering & subsequent dead code elim
+	{"lower", "checkLower"},
+	{"lowered deadcode", "checkLower"},
+	// flagalloc needs instructions to be scheduled.
+	{"schedule", "flagalloc"},
+	// regalloc needs flags to be allocated first.
+	{"flagalloc", "regalloc"},
+	// trim needs regalloc to be done first.
+	{"regalloc", "trim"},
+}
+
+func init() {
+	for _, c := range passOrder {
+		a, b := c.a, c.b
+		i := -1
+		j := -1
+		for k, p := range passes {
+			if p.name == a {
+				i = k
+			}
+			if p.name == b {
+				j = k
+			}
+		}
+		if i < 0 {
+			log.Panicf("pass %s not found", a)
+		}
+		if j < 0 {
+			log.Panicf("pass %s not found", b)
+		}
+		if i >= j {
+			log.Panicf("passes %s and %s out of order", a, b)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
new file mode 100644
index 0000000..e8ab178
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -0,0 +1,284 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"cmd/internal/obj"
+	"crypto/sha1"
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+)
+
+type Config struct {
+	arch            string                     // "amd64", etc.
+	IntSize         int64                      // 4 or 8
+	PtrSize         int64                      // 4 or 8
+	lowerBlock      func(*Block) bool          // lowering function
+	lowerValue      func(*Value, *Config) bool // lowering function
+	registers       []Register                 // machine registers
+	fe              Frontend                   // callbacks into compiler frontend
+	HTML            *HTMLWriter                // html writer, for debugging
+	ctxt            *obj.Link                  // Generic arch information
+	optimize        bool                       // Do optimization
+	noDuffDevice    bool                       // Don't use Duff's device
+	sparsePhiCutoff uint64                     // Sparse phi location algorithm used above this #blocks*#variables score
+	curFunc         *Func
+
+	// TODO: more stuff. Compiler flags of interest, ...
+
+	// Given an environment variable used for debug hash match,
+	// what file (if any) receives the yes/no logging?
+	logfiles map[string]*os.File
+
+	// Storage for low-numbered values and blocks.
+	values [2000]Value
+	blocks [200]Block
+
+	// Reusable stackAllocState.
+	// See stackalloc.go's {new,put}StackAllocState.
+	stackAllocState *stackAllocState
+
+	domblockstore []ID         // scratch space for computing dominators
+	scrSparse     []*sparseSet // scratch sparse sets to be re-used.
+}
+
+type TypeSource interface {
+	TypeBool() Type
+	TypeInt8() Type
+	TypeInt16() Type
+	TypeInt32() Type
+	TypeInt64() Type
+	TypeUInt8() Type
+	TypeUInt16() Type
+	TypeUInt32() Type
+	TypeUInt64() Type
+	TypeInt() Type
+	TypeFloat32() Type
+	TypeFloat64() Type
+	TypeUintptr() Type
+	TypeString() Type
+	TypeBytePtr() Type // TODO: use unsafe.Pointer instead?
+
+	CanSSA(t Type) bool
+}
+
+type Logger interface {
+	// Logf logs a message from the compiler.
+	Logf(string, ...interface{})
+
+	// Log returns true if logging is not a no-op
+	// some logging calls account for more than a few heap allocations.
+	Log() bool
+
+	// Fatal reports a compiler error and exits.
+	Fatalf(line int32, msg string, args ...interface{})
+
+	// Unimplemented reports that the function cannot be compiled.
+	// It will be removed once SSA work is complete.
+	Unimplementedf(line int32, msg string, args ...interface{})
+
+	// Warnl writes compiler messages in the form expected by "errorcheck" tests
+	Warnl(line int32, fmt_ string, args ...interface{})
+
+	// Fowards the Debug_checknil flag from gc
+	Debug_checknil() bool
+}
+
+type Frontend interface {
+	TypeSource
+	Logger
+
+	// StringData returns a symbol pointing to the given string's contents.
+	StringData(string) interface{} // returns *gc.Sym
+
+	// Auto returns a Node for an auto variable of the given type.
+	// The SSA compiler uses this function to allocate space for spills.
+	Auto(Type) GCNode
+
+	// Given the name for a compound type, returns the name we should use
+	// for the parts of that compound type.
+	SplitString(LocalSlot) (LocalSlot, LocalSlot)
+	SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
+	SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
+	SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
+	SplitStruct(LocalSlot, int) LocalSlot
+
+	// Line returns a string describing the given line number.
+	Line(int32) string
+}
+
+// interface used to hold *gc.Node. We'd use *gc.Node directly but
+// that would lead to an import cycle.
+type GCNode interface {
+	Typ() Type
+	String() string
+}
+
+// NewConfig returns a new configuration object for the given architecture.
+func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config {
+	c := &Config{arch: arch, fe: fe}
+	switch arch {
+	case "amd64":
+		c.IntSize = 8
+		c.PtrSize = 8
+		c.lowerBlock = rewriteBlockAMD64
+		c.lowerValue = rewriteValueAMD64
+		c.registers = registersAMD64[:]
+	case "386":
+		c.IntSize = 4
+		c.PtrSize = 4
+		c.lowerBlock = rewriteBlockAMD64
+		c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support
+	case "arm":
+		c.IntSize = 4
+		c.PtrSize = 4
+		c.lowerBlock = rewriteBlockARM
+		c.lowerValue = rewriteValueARM
+		c.registers = registersARM[:]
+	default:
+		fe.Unimplementedf(0, "arch %s not implemented", arch)
+	}
+	c.ctxt = ctxt
+	c.optimize = optimize
+
+	// Don't use Duff's device on Plan 9, because floating
+	// point operations are not allowed in note handler.
+	if obj.Getgoos() == "plan9" {
+		c.noDuffDevice = true
+	}
+
+	// Assign IDs to preallocated values/blocks.
+	for i := range c.values {
+		c.values[i].ID = ID(i)
+	}
+	for i := range c.blocks {
+		c.blocks[i].ID = ID(i)
+	}
+
+	c.logfiles = make(map[string]*os.File)
+
+	// cutoff is compared with product of numblocks and numvalues,
+	// if product is smaller than cutoff, use old non-sparse method.
+	// cutoff == 0 implies all sparse.
+	// cutoff == -1 implies none sparse.
+	// Good cutoff values seem to be O(million) depending on constant factor cost of sparse.
+	// TODO: get this from a flag, not an environment variable
+	c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash
+	ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF")
+	if ev != "" {
+		v, err := strconv.ParseInt(ev, 10, 64)
+		if err != nil {
+			fe.Fatalf(0, "Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
+		}
+		c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
+	}
+
+	return c
+}
+
+func (c *Config) Frontend() Frontend      { return c.fe }
+func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff }
+
+// NewFunc returns a new, empty function object.
+// Caller must call f.Free() before calling NewFunc again.
+func (c *Config) NewFunc() *Func {
+	// TODO(khr): should this function take name, type, etc. as arguments?
+	if c.curFunc != nil {
+		c.Fatalf(0, "NewFunc called without previous Free")
+	}
+	f := &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}}
+	c.curFunc = f
+	return f
+}
+
+func (c *Config) Logf(msg string, args ...interface{})               { c.fe.Logf(msg, args...) }
+func (c *Config) Log() bool                                          { return c.fe.Log() }
+func (c *Config) Fatalf(line int32, msg string, args ...interface{}) { c.fe.Fatalf(line, msg, args...) }
+func (c *Config) Unimplementedf(line int32, msg string, args ...interface{}) {
+	c.fe.Unimplementedf(line, msg, args...)
+}
+func (c *Config) Warnl(line int32, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) }
+func (c *Config) Debug_checknil() bool                              { return c.fe.Debug_checknil() }
+
+func (c *Config) logDebugHashMatch(evname, name string) {
+	file := c.logfiles[evname]
+	if file == nil {
+		file = os.Stdout
+		tmpfile := os.Getenv("GSHS_LOGFILE")
+		if tmpfile != "" {
+			var ok error
+			file, ok = os.Create(tmpfile)
+			if ok != nil {
+				c.Fatalf(0, "Could not open hash-testing logfile %s", tmpfile)
+			}
+		}
+		c.logfiles[evname] = file
+	}
+	s := fmt.Sprintf("%s triggered %s\n", evname, name)
+	file.WriteString(s)
+	file.Sync()
+}
+
+// DebugHashMatch returns true if environment variable evname
+// 1) is empty (this is a special more-quickly implemented case of 3)
+// 2) is "y" or "Y"
+// 3) is a suffix of the sha1 hash of name
+// 4) is a suffix of the environment variable
+//    fmt.Sprintf("%s%d", evname, n)
+//    provided that all such variables are nonempty for 0 <= i <= n
+// Otherwise it returns false.
+// When true is returned the message
+//  "%s triggered %s\n", evname, name
+// is printed on the file named in environment variable
+//  GSHS_LOGFILE
+// or standard out if that is empty or there is an error
+// opening the file.
+
+func (c *Config) DebugHashMatch(evname, name string) bool {
+	evhash := os.Getenv(evname)
+	if evhash == "" {
+		return true // default behavior with no EV is "on"
+	}
+	if evhash == "y" || evhash == "Y" {
+		c.logDebugHashMatch(evname, name)
+		return true
+	}
+	if evhash == "n" || evhash == "N" {
+		return false
+	}
+	// Check the hash of the name against a partial input hash.
+	// We use this feature to do a binary search to
+	// find a function that is incorrectly compiled.
+	hstr := ""
+	for _, b := range sha1.Sum([]byte(name)) {
+		hstr += fmt.Sprintf("%08b", b)
+	}
+
+	if strings.HasSuffix(hstr, evhash) {
+		c.logDebugHashMatch(evname, name)
+		return true
+	}
+
+	// Iteratively try additional hashes to allow tests for multi-point
+	// failure.
+	for i := 0; true; i++ {
+		ev := fmt.Sprintf("%s%d", evname, i)
+		evv := os.Getenv(ev)
+		if evv == "" {
+			break
+		}
+		if strings.HasSuffix(hstr, evv) {
+			c.logDebugHashMatch(ev, name)
+			return true
+		}
+	}
+	return false
+}
+
+func (c *Config) DebugNameMatch(evname, name string) bool {
+	return os.Getenv(evname) == name
+}
diff --git a/src/cmd/compile/internal/ssa/copyelim.go b/src/cmd/compile/internal/ssa/copyelim.go
new file mode 100644
index 0000000..5cbb448
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/copyelim.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 ssa
+
+// copyelim removes all uses of OpCopy values from f.
+// A subsequent deadcode pass is needed to actually remove the copies.
+func copyelim(f *Func) {
+	// Modify all values so no arg (including args
+	// of OpCopy) is a copy.
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			copyelimValue(v)
+		}
+	}
+
+	// Update block control values.
+	for _, b := range f.Blocks {
+		if v := b.Control; v != nil && v.Op == OpCopy {
+			b.SetControl(v.Args[0])
+		}
+	}
+
+	// Update named values.
+	for _, name := range f.Names {
+		values := f.NamedValues[name]
+		for i, v := range values {
+			if v.Op == OpCopy {
+				values[i] = v.Args[0]
+			}
+		}
+	}
+}
+
+// copySource returns the (non-copy) op which is the
+// ultimate source of v.  v must be a copy op.
+func copySource(v *Value) *Value {
+	w := v.Args[0]
+
+	// This loop is just:
+	// for w.Op == OpCopy {
+	//     w = w.Args[0]
+	// }
+	// but we take some extra care to make sure we
+	// don't get stuck in an infinite loop.
+	// Infinite copy loops may happen in unreachable code.
+	// (TODO: or can they?  Needs a test.)
+	slow := w
+	var advance bool
+	for w.Op == OpCopy {
+		w = w.Args[0]
+		if w == slow {
+			w.reset(OpUnknown)
+			break
+		}
+		if advance {
+			slow = slow.Args[0]
+		}
+		advance = !advance
+	}
+
+	// The answer is w.  Update all the copies we saw
+	// to point directly to w.  Doing this update makes
+	// sure that we don't end up doing O(n^2) work
+	// for a chain of n copies.
+	for v != w {
+		x := v.Args[0]
+		v.SetArg(0, w)
+		v = x
+	}
+	return w
+}
+
+// copyelimValue ensures that no args of v are copies.
+func copyelimValue(v *Value) {
+	for i, a := range v.Args {
+		if a.Op == OpCopy {
+			v.SetArg(i, copySource(a))
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/copyelim_test.go b/src/cmd/compile/internal/ssa/copyelim_test.go
new file mode 100644
index 0000000..96f5846
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/copyelim_test.go
@@ -0,0 +1,41 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"fmt"
+	"testing"
+)
+
+func BenchmarkCopyElim1(b *testing.B)      { benchmarkCopyElim(b, 1) }
+func BenchmarkCopyElim10(b *testing.B)     { benchmarkCopyElim(b, 10) }
+func BenchmarkCopyElim100(b *testing.B)    { benchmarkCopyElim(b, 100) }
+func BenchmarkCopyElim1000(b *testing.B)   { benchmarkCopyElim(b, 1000) }
+func BenchmarkCopyElim10000(b *testing.B)  { benchmarkCopyElim(b, 10000) }
+func BenchmarkCopyElim100000(b *testing.B) { benchmarkCopyElim(b, 100000) }
+
+func benchmarkCopyElim(b *testing.B, n int) {
+	c := testConfig(b)
+
+	values := make([]interface{}, 0, n+2)
+	values = append(values, Valu("mem", OpInitMem, TypeMem, 0, nil))
+	last := "mem"
+	for i := 0; i < n; i++ {
+		name := fmt.Sprintf("copy%d", i)
+		values = append(values, Valu(name, OpCopy, TypeMem, 0, nil, last))
+		last = name
+	}
+	values = append(values, Exit(last))
+	// Reverse values array to make it hard
+	for i := 0; i < len(values)/2; i++ {
+		values[i], values[len(values)-1-i] = values[len(values)-1-i], values[i]
+	}
+
+	for i := 0; i < b.N; i++ {
+		fun := Fun(c, "entry", Bloc("entry", values...))
+		Copyelim(fun.f)
+		fun.f.Free()
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/critical.go b/src/cmd/compile/internal/ssa/critical.go
new file mode 100644
index 0000000..38cd3cb
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/critical.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 ssa
+
+// critical splits critical edges (those that go from a block with
+// more than one outedge to a block with more than one inedge).
+// Regalloc wants a critical-edge-free CFG so it can implement phi values.
+func critical(f *Func) {
+	// maps from phi arg ID to the new block created for that argument
+	blocks := make([]*Block, f.NumValues())
+	// need to iterate over f.Blocks without range, as we might
+	// need to split critical edges on newly constructed blocks
+	for j := 0; j < len(f.Blocks); j++ {
+		b := f.Blocks[j]
+		if len(b.Preds) <= 1 {
+			continue
+		}
+
+		var phi *Value
+		// determine if we've only got a single phi in this
+		// block, this is easier to handle than the general
+		// case of a block with multiple phi values.
+		for _, v := range b.Values {
+			if v.Op == OpPhi {
+				if phi != nil {
+					phi = nil
+					break
+				}
+				phi = v
+			}
+		}
+
+		// reset our block map
+		if phi != nil {
+			for _, v := range phi.Args {
+				blocks[v.ID] = nil
+			}
+		}
+
+		// split input edges coming from multi-output blocks.
+		for i := 0; i < len(b.Preds); {
+			e := b.Preds[i]
+			p := e.b
+			pi := e.i
+			if p.Kind == BlockPlain {
+				i++
+				continue // only single output block
+			}
+
+			var d *Block         // new block used to remove critical edge
+			reusedBlock := false // if true, then this is not the first use of this block
+			if phi != nil {
+				argID := phi.Args[i].ID
+				// find or record the block that we used to split
+				// critical edges for this argument
+				if d = blocks[argID]; d == nil {
+					// splitting doesn't necessarily remove the critical edge,
+					// since we're iterating over len(f.Blocks) above, this forces
+					// the new blocks to be re-examined.
+					d = f.NewBlock(BlockPlain)
+					d.Line = p.Line
+					blocks[argID] = d
+					if f.pass.debug > 0 {
+						f.Config.Warnl(p.Line, "split critical edge")
+					}
+				} else {
+					reusedBlock = true
+				}
+			} else {
+				// no existing block, so allocate a new block
+				// to place on the edge
+				d = f.NewBlock(BlockPlain)
+				d.Line = p.Line
+				if f.pass.debug > 0 {
+					f.Config.Warnl(p.Line, "split critical edge")
+				}
+			}
+
+			// if this not the first argument for the
+			// block, then we need to remove the
+			// corresponding elements from the block
+			// predecessors and phi args
+			if reusedBlock {
+				// Add p->d edge
+				p.Succs[pi] = Edge{d, len(d.Preds)}
+				d.Preds = append(d.Preds, Edge{p, pi})
+
+				// Remove p as a predecessor from b.
+				b.removePred(i)
+
+				// Update corresponding phi args
+				n := len(b.Preds)
+				phi.Args[i].Uses--
+				phi.Args[i] = phi.Args[n]
+				phi.Args[n] = nil
+				phi.Args = phi.Args[:n]
+				// splitting occasionally leads to a phi having
+				// a single argument (occurs with -N)
+				if n == 1 {
+					phi.Op = OpCopy
+				}
+				// Don't increment i in this case because we moved
+				// an unprocessed predecessor down into slot i.
+			} else {
+				// splice it in
+				p.Succs[pi] = Edge{d, 0}
+				b.Preds[i] = Edge{d, 0}
+				d.Preds = append(d.Preds, Edge{p, pi})
+				d.Succs = append(d.Succs, Edge{b, i})
+				i++
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go
new file mode 100644
index 0000000..ad4e416
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/cse.go
@@ -0,0 +1,322 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"fmt"
+	"sort"
+)
+
+const (
+	cmpDepth = 4
+)
+
+// cse does common-subexpression elimination on the Function.
+// Values are just relinked, nothing is deleted. A subsequent deadcode
+// pass is required to actually remove duplicate expressions.
+func cse(f *Func) {
+	// Two values are equivalent if they satisfy the following definition:
+	// equivalent(v, w):
+	//   v.op == w.op
+	//   v.type == w.type
+	//   v.aux == w.aux
+	//   v.auxint == w.auxint
+	//   len(v.args) == len(w.args)
+	//   v.block == w.block if v.op == OpPhi
+	//   equivalent(v.args[i], w.args[i]) for i in 0..len(v.args)-1
+
+	// The algorithm searches for a partition of f's values into
+	// equivalence classes using the above definition.
+	// It starts with a coarse partition and iteratively refines it
+	// until it reaches a fixed point.
+
+	// Make initial coarse partitions by using a subset of the conditions above.
+	a := make([]*Value, 0, f.NumValues())
+	auxIDs := auxmap{}
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if auxIDs[v.Aux] == 0 {
+				auxIDs[v.Aux] = int32(len(auxIDs)) + 1
+			}
+			if v.Type.IsMemory() {
+				continue // memory values can never cse
+			}
+			if opcodeTable[v.Op].commutative && len(v.Args) == 2 && v.Args[1].ID < v.Args[0].ID {
+				// Order the arguments of binary commutative operations.
+				v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
+			}
+			a = append(a, v)
+		}
+	}
+	partition := partitionValues(a, auxIDs)
+
+	// map from value id back to eqclass id
+	valueEqClass := make([]ID, f.NumValues())
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			// Use negative equivalence class #s for unique values.
+			valueEqClass[v.ID] = -v.ID
+		}
+	}
+	for i, e := range partition {
+		if f.pass.debug > 1 && len(e) > 500 {
+			fmt.Printf("CSE.large partition (%d): ", len(e))
+			for j := 0; j < 3; j++ {
+				fmt.Printf("%s ", e[j].LongString())
+			}
+			fmt.Println()
+		}
+
+		for _, v := range e {
+			valueEqClass[v.ID] = ID(i)
+		}
+		if f.pass.debug > 2 && len(e) > 1 {
+			fmt.Printf("CSE.partition #%d:", i)
+			for _, v := range e {
+				fmt.Printf(" %s", v.String())
+			}
+			fmt.Printf("\n")
+		}
+	}
+
+	// Find an equivalence class where some members of the class have
+	// non-equivalent arguments. Split the equivalence class appropriately.
+	// Repeat until we can't find any more splits.
+	for {
+		changed := false
+
+		// partition can grow in the loop. By not using a range loop here,
+		// we process new additions as they arrive, avoiding O(n^2) behavior.
+		for i := 0; i < len(partition); i++ {
+			e := partition[i]
+			v := e[0]
+			// all values in this equiv class that are not equivalent to v get moved
+			// into another equiv class.
+			// To avoid allocating while building that equivalence class,
+			// move the values equivalent to v to the beginning of e
+			// and other values to the end of e.
+			allvals := e
+		eqloop:
+			for j := 1; j < len(e); {
+				w := e[j]
+				equivalent := true
+				for i := 0; i < len(v.Args); i++ {
+					if valueEqClass[v.Args[i].ID] != valueEqClass[w.Args[i].ID] {
+						equivalent = false
+						break
+					}
+				}
+				if !equivalent || v.Type.Compare(w.Type) != CMPeq {
+					// w is not equivalent to v.
+					// move it to the end and shrink e.
+					e[j], e[len(e)-1] = e[len(e)-1], e[j]
+					e = e[:len(e)-1]
+					valueEqClass[w.ID] = ID(len(partition))
+					changed = true
+					continue eqloop
+				}
+				// v and w are equivalent. Keep w in e.
+				j++
+			}
+			partition[i] = e
+			if len(e) < len(allvals) {
+				partition = append(partition, allvals[len(e):])
+			}
+		}
+
+		if !changed {
+			break
+		}
+	}
+
+	// Dominator tree (f.sdom) is computed by the generic domtree pass.
+
+	// Compute substitutions we would like to do. We substitute v for w
+	// if v and w are in the same equivalence class and v dominates w.
+	rewrite := make([]*Value, f.NumValues())
+	for _, e := range partition {
+		sort.Sort(partitionByDom{e, f.sdom})
+		for i := 0; i < len(e)-1; i++ {
+			// e is sorted by domorder, so a maximal dominant element is first in the slice
+			v := e[i]
+			if v == nil {
+				continue
+			}
+
+			e[i] = nil
+			// Replace all elements of e which v dominates
+			for j := i + 1; j < len(e); j++ {
+				w := e[j]
+				if w == nil {
+					continue
+				}
+				if f.sdom.isAncestorEq(v.Block, w.Block) {
+					rewrite[w.ID] = v
+					e[j] = nil
+				} else {
+					// e is sorted by domorder, so v.Block doesn't dominate any subsequent blocks in e
+					break
+				}
+			}
+		}
+	}
+
+	rewrites := int64(0)
+
+	// Apply substitutions
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			for i, w := range v.Args {
+				if x := rewrite[w.ID]; x != nil {
+					v.SetArg(i, x)
+					rewrites++
+				}
+			}
+		}
+		if v := b.Control; v != nil {
+			if x := rewrite[v.ID]; x != nil {
+				if v.Op == OpNilCheck {
+					// nilcheck pass will remove the nil checks and log
+					// them appropriately, so don't mess with them here.
+					continue
+				}
+				b.SetControl(x)
+			}
+		}
+	}
+	if f.pass.stats > 0 {
+		f.LogStat("CSE REWRITES", rewrites)
+	}
+}
+
+// An eqclass approximates an equivalence class. During the
+// algorithm it may represent the union of several of the
+// final equivalence classes.
+type eqclass []*Value
+
+// partitionValues partitions the values into equivalence classes
+// based on having all the following features match:
+//  - opcode
+//  - type
+//  - auxint
+//  - aux
+//  - nargs
+//  - block # if a phi op
+//  - first two arg's opcodes and auxint
+//  - NOT first two arg's aux; that can break CSE.
+// partitionValues returns a list of equivalence classes, each
+// being a sorted by ID list of *Values. The eqclass slices are
+// backed by the same storage as the input slice.
+// Equivalence classes of size 1 are ignored.
+func partitionValues(a []*Value, auxIDs auxmap) []eqclass {
+	sort.Sort(sortvalues{a, auxIDs})
+
+	var partition []eqclass
+	for len(a) > 0 {
+		v := a[0]
+		j := 1
+		for ; j < len(a); j++ {
+			w := a[j]
+			if cmpVal(v, w, auxIDs, cmpDepth) != CMPeq {
+				break
+			}
+		}
+		if j > 1 {
+			partition = append(partition, a[:j])
+		}
+		a = a[j:]
+	}
+
+	return partition
+}
+func lt2Cmp(isLt bool) Cmp {
+	if isLt {
+		return CMPlt
+	}
+	return CMPgt
+}
+
+type auxmap map[interface{}]int32
+
+func cmpVal(v, w *Value, auxIDs auxmap, depth int) Cmp {
+	// Try to order these comparison by cost (cheaper first)
+	if v.Op != w.Op {
+		return lt2Cmp(v.Op < w.Op)
+	}
+	if v.AuxInt != w.AuxInt {
+		return lt2Cmp(v.AuxInt < w.AuxInt)
+	}
+	if len(v.Args) != len(w.Args) {
+		return lt2Cmp(len(v.Args) < len(w.Args))
+	}
+	if v.Op == OpPhi && v.Block != w.Block {
+		return lt2Cmp(v.Block.ID < w.Block.ID)
+	}
+	if v.Type.IsMemory() {
+		// We will never be able to CSE two values
+		// that generate memory.
+		return lt2Cmp(v.ID < w.ID)
+	}
+
+	if tc := v.Type.Compare(w.Type); tc != CMPeq {
+		return tc
+	}
+
+	if v.Aux != w.Aux {
+		if v.Aux == nil {
+			return CMPlt
+		}
+		if w.Aux == nil {
+			return CMPgt
+		}
+		return lt2Cmp(auxIDs[v.Aux] < auxIDs[w.Aux])
+	}
+
+	if depth > 0 {
+		for i := range v.Args {
+			if v.Args[i] == w.Args[i] {
+				// skip comparing equal args
+				continue
+			}
+			if ac := cmpVal(v.Args[i], w.Args[i], auxIDs, depth-1); ac != CMPeq {
+				return ac
+			}
+		}
+	}
+
+	return CMPeq
+}
+
+// Sort values to make the initial partition.
+type sortvalues struct {
+	a      []*Value // array of values
+	auxIDs auxmap   // aux -> aux ID map
+}
+
+func (sv sortvalues) Len() int      { return len(sv.a) }
+func (sv sortvalues) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
+func (sv sortvalues) Less(i, j int) bool {
+	v := sv.a[i]
+	w := sv.a[j]
+	if cmp := cmpVal(v, w, sv.auxIDs, cmpDepth); cmp != CMPeq {
+		return cmp == CMPlt
+	}
+
+	// Sort by value ID last to keep the sort result deterministic.
+	return v.ID < w.ID
+}
+
+type partitionByDom struct {
+	a    []*Value // array of values
+	sdom SparseTree
+}
+
+func (sv partitionByDom) Len() int      { return len(sv.a) }
+func (sv partitionByDom) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
+func (sv partitionByDom) Less(i, j int) bool {
+	v := sv.a[i]
+	w := sv.a[j]
+	return sv.sdom.domorder(v.Block) < sv.sdom.domorder(w.Block)
+}
diff --git a/src/cmd/compile/internal/ssa/cse_test.go b/src/cmd/compile/internal/ssa/cse_test.go
new file mode 100644
index 0000000..d5be2b5
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/cse_test.go
@@ -0,0 +1,124 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "testing"
+
+type tstAux struct {
+	s string
+}
+
+// This tests for a bug found when partitioning, but not sorting by the Aux value.
+func TestCSEAuxPartitionBug(t *testing.T) {
+	c := testConfig(t)
+	arg1Aux := &tstAux{"arg1-aux"}
+	arg2Aux := &tstAux{"arg2-aux"}
+	arg3Aux := &tstAux{"arg3-aux"}
+
+	// construct lots of values with args that have aux values and place
+	// them in an order that triggers the bug
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("start", OpInitMem, TypeMem, 0, nil),
+			Valu("sp", OpSP, TypeBytePtr, 0, nil),
+			Valu("r7", OpAdd64, TypeInt64, 0, nil, "arg3", "arg1"),
+			Valu("r1", OpAdd64, TypeInt64, 0, nil, "arg1", "arg2"),
+			Valu("arg1", OpArg, TypeInt64, 0, arg1Aux),
+			Valu("arg2", OpArg, TypeInt64, 0, arg2Aux),
+			Valu("arg3", OpArg, TypeInt64, 0, arg3Aux),
+			Valu("r9", OpAdd64, TypeInt64, 0, nil, "r7", "r8"),
+			Valu("r4", OpAdd64, TypeInt64, 0, nil, "r1", "r2"),
+			Valu("r8", OpAdd64, TypeInt64, 0, nil, "arg3", "arg2"),
+			Valu("r2", OpAdd64, TypeInt64, 0, nil, "arg1", "arg2"),
+			Valu("raddr", OpAddr, TypeInt64Ptr, 0, nil, "sp"),
+			Valu("raddrdef", OpVarDef, TypeMem, 0, nil, "start"),
+			Valu("r6", OpAdd64, TypeInt64, 0, nil, "r4", "r5"),
+			Valu("r3", OpAdd64, TypeInt64, 0, nil, "arg1", "arg2"),
+			Valu("r5", OpAdd64, TypeInt64, 0, nil, "r2", "r3"),
+			Valu("r10", OpAdd64, TypeInt64, 0, nil, "r6", "r9"),
+			Valu("rstore", OpStore, TypeMem, 8, nil, "raddr", "r10", "raddrdef"),
+			Goto("exit")),
+		Bloc("exit",
+			Exit("rstore")))
+
+	CheckFunc(fun.f)
+	domTree(fun.f)
+	cse(fun.f)
+	deadcode(fun.f)
+	CheckFunc(fun.f)
+
+	s1Cnt := 2
+	// r1 == r2 == r3, needs to remove two of this set
+	s2Cnt := 1
+	// r4 == r5, needs to remove one of these
+	for k, v := range fun.values {
+		if v.Op == OpInvalid {
+			switch k {
+			case "r1":
+				fallthrough
+			case "r2":
+				fallthrough
+			case "r3":
+				if s1Cnt == 0 {
+					t.Errorf("cse removed all of r1,r2,r3")
+				}
+				s1Cnt--
+
+			case "r4":
+				fallthrough
+			case "r5":
+				if s2Cnt == 0 {
+					t.Errorf("cse removed all of r4,r5")
+				}
+				s2Cnt--
+			default:
+				t.Errorf("cse removed %s, but shouldn't have", k)
+			}
+		}
+	}
+
+	if s1Cnt != 0 || s2Cnt != 0 {
+		t.Errorf("%d values missed during cse", s1Cnt+s2Cnt)
+	}
+}
+
+// TestZCSE tests the zero arg cse.
+func TestZCSE(t *testing.T) {
+	c := testConfig(t)
+
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("start", OpInitMem, TypeMem, 0, nil),
+			Valu("sp", OpSP, TypeBytePtr, 0, nil),
+			Valu("sb1", OpSB, TypeBytePtr, 0, nil),
+			Valu("sb2", OpSB, TypeBytePtr, 0, nil),
+			Valu("addr1", OpAddr, TypeInt64Ptr, 0, nil, "sb1"),
+			Valu("addr2", OpAddr, TypeInt64Ptr, 0, nil, "sb2"),
+			Valu("a1ld", OpLoad, TypeInt64, 0, nil, "addr1", "start"),
+			Valu("a2ld", OpLoad, TypeInt64, 0, nil, "addr2", "start"),
+			Valu("c1", OpConst64, TypeInt64, 1, nil),
+			Valu("r1", OpAdd64, TypeInt64, 0, nil, "a1ld", "c1"),
+			Valu("c2", OpConst64, TypeInt64, 1, nil),
+			Valu("r2", OpAdd64, TypeInt64, 0, nil, "a2ld", "c2"),
+			Valu("r3", OpAdd64, TypeInt64, 0, nil, "r1", "r2"),
+			Valu("raddr", OpAddr, TypeInt64Ptr, 0, nil, "sp"),
+			Valu("raddrdef", OpVarDef, TypeMem, 0, nil, "start"),
+			Valu("rstore", OpStore, TypeMem, 8, nil, "raddr", "r3", "raddrdef"),
+			Goto("exit")),
+		Bloc("exit",
+			Exit("rstore")))
+
+	CheckFunc(fun.f)
+	zcse(fun.f)
+	deadcode(fun.f)
+	CheckFunc(fun.f)
+
+	if fun.values["c1"].Op != OpInvalid && fun.values["c2"].Op != OpInvalid {
+		t.Errorf("zsce should have removed c1 or c2")
+	}
+	if fun.values["sb1"].Op != OpInvalid && fun.values["sb2"].Op != OpInvalid {
+		t.Errorf("zsce should have removed sb1 or sb2")
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go
new file mode 100644
index 0000000..5ccf390
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/deadcode.go
@@ -0,0 +1,273 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// findlive returns the reachable blocks and live values in f.
+func findlive(f *Func) (reachable []bool, live []bool) {
+	reachable = reachableBlocks(f)
+	live = liveValues(f, reachable)
+	return
+}
+
+// reachableBlocks returns the reachable blocks in f.
+func reachableBlocks(f *Func) []bool {
+	reachable := make([]bool, f.NumBlocks())
+	reachable[f.Entry.ID] = true
+	p := []*Block{f.Entry} // stack-like worklist
+	for len(p) > 0 {
+		// Pop a reachable block
+		b := p[len(p)-1]
+		p = p[:len(p)-1]
+		// Mark successors as reachable
+		s := b.Succs
+		if b.Kind == BlockFirst {
+			s = s[:1]
+		}
+		for _, e := range s {
+			c := e.b
+			if !reachable[c.ID] {
+				reachable[c.ID] = true
+				p = append(p, c) // push
+			}
+		}
+	}
+	return reachable
+}
+
+// liveValues returns the live values in f.
+// reachable is a map from block ID to whether the block is reachable.
+func liveValues(f *Func, reachable []bool) []bool {
+	live := make([]bool, f.NumValues())
+
+	// After regalloc, consider all values to be live.
+	// See the comment at the top of regalloc.go and in deadcode for details.
+	if f.RegAlloc != nil {
+		for i := range live {
+			live[i] = true
+		}
+		return live
+	}
+
+	// Find all live values
+	var q []*Value // stack-like worklist of unscanned values
+
+	// Starting set: all control values of reachable blocks are live.
+	for _, b := range f.Blocks {
+		if !reachable[b.ID] {
+			continue
+		}
+		if v := b.Control; v != nil && !live[v.ID] {
+			live[v.ID] = true
+			q = append(q, v)
+		}
+	}
+
+	// Compute transitive closure of live values.
+	for len(q) > 0 {
+		// pop a reachable value
+		v := q[len(q)-1]
+		q = q[:len(q)-1]
+		for i, x := range v.Args {
+			if v.Op == OpPhi && !reachable[v.Block.Preds[i].b.ID] {
+				continue
+			}
+			if !live[x.ID] {
+				live[x.ID] = true
+				q = append(q, x) // push
+			}
+		}
+	}
+
+	return live
+}
+
+// deadcode removes dead code from f.
+func deadcode(f *Func) {
+	// deadcode after regalloc is forbidden for now. Regalloc
+	// doesn't quite generate legal SSA which will lead to some
+	// required moves being eliminated. See the comment at the
+	// top of regalloc.go for details.
+	if f.RegAlloc != nil {
+		f.Fatalf("deadcode after regalloc")
+	}
+
+	// Find reachable blocks.
+	reachable := reachableBlocks(f)
+
+	// Get rid of edges from dead to live code.
+	for _, b := range f.Blocks {
+		if reachable[b.ID] {
+			continue
+		}
+		for i := 0; i < len(b.Succs); {
+			e := b.Succs[i]
+			if reachable[e.b.ID] {
+				b.removeEdge(i)
+			} else {
+				i++
+			}
+		}
+	}
+
+	// Get rid of dead edges from live code.
+	for _, b := range f.Blocks {
+		if !reachable[b.ID] {
+			continue
+		}
+		if b.Kind != BlockFirst {
+			continue
+		}
+		b.removeEdge(1)
+		b.Kind = BlockPlain
+		b.Likely = BranchUnknown
+	}
+
+	// Splice out any copies introduced during dead block removal.
+	copyelim(f)
+
+	// Find live values.
+	live := liveValues(f, reachable)
+
+	// Remove dead & duplicate entries from namedValues map.
+	s := f.newSparseSet(f.NumValues())
+	defer f.retSparseSet(s)
+	i := 0
+	for _, name := range f.Names {
+		j := 0
+		s.clear()
+		values := f.NamedValues[name]
+		for _, v := range values {
+			if live[v.ID] && !s.contains(v.ID) {
+				values[j] = v
+				j++
+				s.add(v.ID)
+			}
+		}
+		if j == 0 {
+			delete(f.NamedValues, name)
+		} else {
+			f.Names[i] = name
+			i++
+			for k := len(values) - 1; k >= j; k-- {
+				values[k] = nil
+			}
+			f.NamedValues[name] = values[:j]
+		}
+	}
+	for k := len(f.Names) - 1; k >= i; k-- {
+		f.Names[k] = LocalSlot{}
+	}
+	f.Names = f.Names[:i]
+
+	// Unlink values.
+	for _, b := range f.Blocks {
+		if !reachable[b.ID] {
+			b.SetControl(nil)
+		}
+		for _, v := range b.Values {
+			if !live[v.ID] {
+				v.resetArgs()
+			}
+		}
+	}
+
+	// Remove dead values from blocks' value list. Return dead
+	// values to the allocator.
+	for _, b := range f.Blocks {
+		i := 0
+		for _, v := range b.Values {
+			if live[v.ID] {
+				b.Values[i] = v
+				i++
+			} else {
+				f.freeValue(v)
+			}
+		}
+		// aid GC
+		tail := b.Values[i:]
+		for j := range tail {
+			tail[j] = nil
+		}
+		b.Values = b.Values[:i]
+	}
+
+	// Remove unreachable blocks. Return dead blocks to allocator.
+	i = 0
+	for _, b := range f.Blocks {
+		if reachable[b.ID] {
+			f.Blocks[i] = b
+			i++
+		} else {
+			if len(b.Values) > 0 {
+				b.Fatalf("live values in unreachable block %v: %v", b, b.Values)
+			}
+			f.freeBlock(b)
+		}
+	}
+	// zero remainder to help GC
+	tail := f.Blocks[i:]
+	for j := range tail {
+		tail[j] = nil
+	}
+	f.Blocks = f.Blocks[:i]
+}
+
+// removeEdge removes the i'th outgoing edge from b (and
+// the corresponding incoming edge from b.Succs[i].b).
+func (b *Block) removeEdge(i int) {
+	e := b.Succs[i]
+	c := e.b
+	j := e.i
+
+	// Adjust b.Succs
+	b.removeSucc(i)
+
+	// Adjust c.Preds
+	c.removePred(j)
+
+	// Remove phi args from c's phis.
+	n := len(c.Preds)
+	for _, v := range c.Values {
+		if v.Op != OpPhi {
+			continue
+		}
+		v.Args[j].Uses--
+		v.Args[j] = v.Args[n]
+		v.Args[n] = nil
+		v.Args = v.Args[:n]
+		phielimValue(v)
+		// Note: this is trickier than it looks. Replacing
+		// a Phi with a Copy can in general cause problems because
+		// Phi and Copy don't have exactly the same semantics.
+		// Phi arguments always come from a predecessor block,
+		// whereas copies don't. This matters in loops like:
+		// 1: x = (Phi y)
+		//    y = (Add x 1)
+		//    goto 1
+		// If we replace Phi->Copy, we get
+		// 1: x = (Copy y)
+		//    y = (Add x 1)
+		//    goto 1
+		// (Phi y) refers to the *previous* value of y, whereas
+		// (Copy y) refers to the *current* value of y.
+		// The modified code has a cycle and the scheduler
+		// will barf on it.
+		//
+		// Fortunately, this situation can only happen for dead
+		// code loops. We know the code we're working with is
+		// not dead, so we're ok.
+		// Proof: If we have a potential bad cycle, we have a
+		// situation like this:
+		//   x = (Phi z)
+		//   y = (op1 x ...)
+		//   z = (op2 y ...)
+		// Where opX are not Phi ops. But such a situation
+		// implies a cycle in the dominator graph. In the
+		// example, x.Block dominates y.Block, y.Block dominates
+		// z.Block, and z.Block dominates x.Block (treating
+		// "dominates" as reflexive).  Cycles in the dominator
+		// graph can only happen in an unreachable cycle.
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go
new file mode 100644
index 0000000..b1d8d0f
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/deadcode_test.go
@@ -0,0 +1,161 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"fmt"
+	"strconv"
+	"testing"
+)
+
+func TestDeadLoop(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")),
+		// dead loop
+		Bloc("deadblock",
+			// dead value in dead block
+			Valu("deadval", OpConstBool, TypeBool, 1, nil),
+			If("deadval", "deadblock", "exit")))
+
+	CheckFunc(fun.f)
+	Deadcode(fun.f)
+	CheckFunc(fun.f)
+
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["deadblock"] {
+			t.Errorf("dead block not removed")
+		}
+		for _, v := range b.Values {
+			if v == fun.values["deadval"] {
+				t.Errorf("control value of dead block not removed")
+			}
+		}
+	}
+}
+
+func TestDeadValue(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("deadval", OpConst64, TypeInt64, 37, nil),
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	Deadcode(fun.f)
+	CheckFunc(fun.f)
+
+	for _, b := range fun.f.Blocks {
+		for _, v := range b.Values {
+			if v == fun.values["deadval"] {
+				t.Errorf("dead value not removed")
+			}
+		}
+	}
+}
+
+func TestNeverTaken(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("cond", OpConstBool, TypeBool, 0, nil),
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			If("cond", "then", "else")),
+		Bloc("then",
+			Goto("exit")),
+		Bloc("else",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	Opt(fun.f)
+	Deadcode(fun.f)
+	CheckFunc(fun.f)
+
+	if fun.blocks["entry"].Kind != BlockPlain {
+		t.Errorf("if(false) not simplified")
+	}
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["then"] {
+			t.Errorf("then block still present")
+		}
+		for _, v := range b.Values {
+			if v == fun.values["cond"] {
+				t.Errorf("constant condition still present")
+			}
+		}
+	}
+
+}
+
+func TestNestedDeadBlocks(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("cond", OpConstBool, TypeBool, 0, nil),
+			If("cond", "b2", "b4")),
+		Bloc("b2",
+			If("cond", "b3", "b4")),
+		Bloc("b3",
+			If("cond", "b3", "b4")),
+		Bloc("b4",
+			If("cond", "b3", "exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	Opt(fun.f)
+	CheckFunc(fun.f)
+	Deadcode(fun.f)
+	CheckFunc(fun.f)
+	if fun.blocks["entry"].Kind != BlockPlain {
+		t.Errorf("if(false) not simplified")
+	}
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["b2"] {
+			t.Errorf("b2 block still present")
+		}
+		if b == fun.blocks["b3"] {
+			t.Errorf("b3 block still present")
+		}
+		for _, v := range b.Values {
+			if v == fun.values["cond"] {
+				t.Errorf("constant condition still present")
+			}
+		}
+	}
+}
+
+func BenchmarkDeadCode(b *testing.B) {
+	for _, n := range [...]int{1, 10, 100, 1000, 10000, 100000, 200000} {
+		b.Run(strconv.Itoa(n), func(b *testing.B) {
+			c := testConfig(b)
+			blocks := make([]bloc, 0, n+2)
+			blocks = append(blocks,
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Goto("exit")))
+			blocks = append(blocks, Bloc("exit", Exit("mem")))
+			for i := 0; i < n; i++ {
+				blocks = append(blocks, Bloc(fmt.Sprintf("dead%d", i), Goto("exit")))
+			}
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				fun := Fun(c, "entry", blocks...)
+				Deadcode(fun.f)
+				fun.f.Free()
+			}
+		})
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go
new file mode 100644
index 0000000..5129c17
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/deadstore.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 ssa
+
+// dse does dead-store elimination on the Function.
+// Dead stores are those which are unconditionally followed by
+// another store to the same location, with no intervening load.
+// This implementation only works within a basic block. TODO: use something more global.
+func dse(f *Func) {
+	var stores []*Value
+	loadUse := f.newSparseSet(f.NumValues())
+	defer f.retSparseSet(loadUse)
+	storeUse := f.newSparseSet(f.NumValues())
+	defer f.retSparseSet(storeUse)
+	shadowed := f.newSparseSet(f.NumValues())
+	defer f.retSparseSet(shadowed)
+	for _, b := range f.Blocks {
+		// Find all the stores in this block. Categorize their uses:
+		//  loadUse contains stores which are used by a subsequent load.
+		//  storeUse contains stores which are used by a subsequent store.
+		loadUse.clear()
+		storeUse.clear()
+		stores = stores[:0]
+		for _, v := range b.Values {
+			if v.Op == OpPhi {
+				// Ignore phis - they will always be first and can't be eliminated
+				continue
+			}
+			if v.Type.IsMemory() {
+				stores = append(stores, v)
+				for _, a := range v.Args {
+					if a.Block == b && a.Type.IsMemory() {
+						storeUse.add(a.ID)
+						if v.Op != OpStore && v.Op != OpZero && v.Op != OpVarDef && v.Op != OpVarKill {
+							// CALL, DUFFCOPY, etc. are both
+							// reads and writes.
+							loadUse.add(a.ID)
+						}
+					}
+				}
+			} else {
+				for _, a := range v.Args {
+					if a.Block == b && a.Type.IsMemory() {
+						loadUse.add(a.ID)
+					}
+				}
+			}
+		}
+		if len(stores) == 0 {
+			continue
+		}
+
+		// find last store in the block
+		var last *Value
+		for _, v := range stores {
+			if storeUse.contains(v.ID) {
+				continue
+			}
+			if last != nil {
+				b.Fatalf("two final stores - simultaneous live stores %s %s", last, v)
+			}
+			last = v
+		}
+		if last == nil {
+			b.Fatalf("no last store found - cycle?")
+		}
+
+		// Walk backwards looking for dead stores. Keep track of shadowed addresses.
+		// An "address" is an SSA Value which encodes both the address and size of
+		// the write. This code will not remove dead stores to the same address
+		// of different types.
+		shadowed.clear()
+		v := last
+
+	walkloop:
+		if loadUse.contains(v.ID) {
+			// Someone might be reading this memory state.
+			// Clear all shadowed addresses.
+			shadowed.clear()
+		}
+		if v.Op == OpStore || v.Op == OpZero {
+			if shadowed.contains(v.Args[0].ID) {
+				// Modify store into a copy
+				if v.Op == OpStore {
+					// store addr value mem
+					v.SetArgs1(v.Args[2])
+				} else {
+					// zero addr mem
+					sz := v.Args[0].Type.ElemType().Size()
+					if v.AuxInt != sz {
+						f.Fatalf("mismatched zero/store sizes: %d and %d [%s]",
+							v.AuxInt, sz, v.LongString())
+					}
+					v.SetArgs1(v.Args[1])
+				}
+				v.Aux = nil
+				v.AuxInt = 0
+				v.Op = OpCopy
+			} else {
+				shadowed.add(v.Args[0].ID)
+			}
+		}
+		// walk to previous store
+		if v.Op == OpPhi {
+			continue // At start of block.  Move on to next block.
+		}
+		for _, a := range v.Args {
+			if a.Block == b && a.Type.IsMemory() {
+				v = a
+				goto walkloop
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go
new file mode 100644
index 0000000..c38f1cd
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/deadstore_test.go
@@ -0,0 +1,97 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "testing"
+
+func TestDeadStore(t *testing.T) {
+	c := testConfig(t)
+	elemType := &TypeImpl{Size_: 8, Name: "testtype"}
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("start", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("v", OpConstBool, TypeBool, 1, nil),
+			Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
+			Valu("addr2", OpAddr, ptrType, 0, nil, "sb"),
+			Valu("addr3", OpAddr, ptrType, 0, nil, "sb"),
+			Valu("zero1", OpZero, TypeMem, 8, nil, "addr3", "start"),
+			Valu("store1", OpStore, TypeMem, 1, nil, "addr1", "v", "zero1"),
+			Valu("store2", OpStore, TypeMem, 1, nil, "addr2", "v", "store1"),
+			Valu("store3", OpStore, TypeMem, 1, nil, "addr1", "v", "store2"),
+			Valu("store4", OpStore, TypeMem, 1, nil, "addr3", "v", "store3"),
+			Goto("exit")),
+		Bloc("exit",
+			Exit("store3")))
+
+	CheckFunc(fun.f)
+	dse(fun.f)
+	CheckFunc(fun.f)
+
+	v1 := fun.values["store1"]
+	if v1.Op != OpCopy {
+		t.Errorf("dead store not removed")
+	}
+
+	v2 := fun.values["zero1"]
+	if v2.Op != OpCopy {
+		t.Errorf("dead store (zero) not removed")
+	}
+}
+func TestDeadStorePhi(t *testing.T) {
+	// make sure we don't get into an infinite loop with phi values.
+	c := testConfig(t)
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("start", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("v", OpConstBool, TypeBool, 1, nil),
+			Valu("addr", OpAddr, ptrType, 0, nil, "sb"),
+			Goto("loop")),
+		Bloc("loop",
+			Valu("phi", OpPhi, TypeMem, 0, nil, "start", "store"),
+			Valu("store", OpStore, TypeMem, 1, nil, "addr", "v", "phi"),
+			If("v", "loop", "exit")),
+		Bloc("exit",
+			Exit("store")))
+
+	CheckFunc(fun.f)
+	dse(fun.f)
+	CheckFunc(fun.f)
+}
+
+func TestDeadStoreTypes(t *testing.T) {
+	// Make sure a narrow store can't shadow a wider one. We test an even
+	// stronger restriction, that one store can't shadow another unless the
+	// types of the address fields are identical (where identicalness is
+	// decided by the CSE pass).
+	c := testConfig(t)
+	t1 := &TypeImpl{Size_: 8, Ptr: true, Name: "t1"}
+	t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"}
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("start", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("v", OpConstBool, TypeBool, 1, nil),
+			Valu("addr1", OpAddr, t1, 0, nil, "sb"),
+			Valu("addr2", OpAddr, t2, 0, nil, "sb"),
+			Valu("store1", OpStore, TypeMem, 1, nil, "addr1", "v", "start"),
+			Valu("store2", OpStore, TypeMem, 1, nil, "addr2", "v", "store1"),
+			Goto("exit")),
+		Bloc("exit",
+			Exit("store2")))
+
+	CheckFunc(fun.f)
+	cse(fun.f)
+	dse(fun.f)
+	CheckFunc(fun.f)
+
+	v := fun.values["store1"]
+	if v.Op == OpCopy {
+		t.Errorf("store %s incorrectly removed", v)
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go
new file mode 100644
index 0000000..53116ba
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/decompose.go
@@ -0,0 +1,271 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// decompose converts phi ops on compound builtin types into phi
+// ops on simple types.
+// (The remaining compound ops are decomposed with rewrite rules.)
+func decomposeBuiltIn(f *Func) {
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if v.Op != OpPhi {
+				continue
+			}
+			decomposeBuiltInPhi(v)
+		}
+	}
+
+	// Split up named values into their components.
+	// NOTE: the component values we are making are dead at this point.
+	// We must do the opt pass before any deadcode elimination or we will
+	// lose the name->value correspondence.
+	var newNames []LocalSlot
+	for _, name := range f.Names {
+		t := name.Type
+		switch {
+		case t.IsComplex():
+			var elemType Type
+			if t.Size() == 16 {
+				elemType = f.Config.fe.TypeFloat64()
+			} else {
+				elemType = f.Config.fe.TypeFloat32()
+			}
+			rName, iName := f.Config.fe.SplitComplex(name)
+			newNames = append(newNames, rName, iName)
+			for _, v := range f.NamedValues[name] {
+				r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v)
+				i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v)
+				f.NamedValues[rName] = append(f.NamedValues[rName], r)
+				f.NamedValues[iName] = append(f.NamedValues[iName], i)
+			}
+			delete(f.NamedValues, name)
+		case t.IsString():
+			ptrType := f.Config.fe.TypeBytePtr()
+			lenType := f.Config.fe.TypeInt()
+			ptrName, lenName := f.Config.fe.SplitString(name)
+			newNames = append(newNames, ptrName, lenName)
+			for _, v := range f.NamedValues[name] {
+				ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v)
+				len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v)
+				f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
+				f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
+			}
+			delete(f.NamedValues, name)
+		case t.IsSlice():
+			ptrType := f.Config.fe.TypeBytePtr()
+			lenType := f.Config.fe.TypeInt()
+			ptrName, lenName, capName := f.Config.fe.SplitSlice(name)
+			newNames = append(newNames, ptrName, lenName, capName)
+			for _, v := range f.NamedValues[name] {
+				ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v)
+				len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v)
+				cap := v.Block.NewValue1(v.Line, OpSliceCap, lenType, v)
+				f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr)
+				f.NamedValues[lenName] = append(f.NamedValues[lenName], len)
+				f.NamedValues[capName] = append(f.NamedValues[capName], cap)
+			}
+			delete(f.NamedValues, name)
+		case t.IsInterface():
+			ptrType := f.Config.fe.TypeBytePtr()
+			typeName, dataName := f.Config.fe.SplitInterface(name)
+			newNames = append(newNames, typeName, dataName)
+			for _, v := range f.NamedValues[name] {
+				typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v)
+				data := v.Block.NewValue1(v.Line, OpIData, ptrType, v)
+				f.NamedValues[typeName] = append(f.NamedValues[typeName], typ)
+				f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
+			}
+			delete(f.NamedValues, name)
+		case t.Size() > f.Config.IntSize:
+			f.Unimplementedf("undecomposed named type %s %s", name, t)
+		default:
+			newNames = append(newNames, name)
+		}
+	}
+	f.Names = newNames
+}
+
+func decomposeBuiltInPhi(v *Value) {
+	// TODO: decompose 64-bit ops on 32-bit archs?
+	switch {
+	case v.Type.IsComplex():
+		decomposeComplexPhi(v)
+	case v.Type.IsString():
+		decomposeStringPhi(v)
+	case v.Type.IsSlice():
+		decomposeSlicePhi(v)
+	case v.Type.IsInterface():
+		decomposeInterfacePhi(v)
+	case v.Type.Size() > v.Block.Func.Config.IntSize:
+		v.Unimplementedf("undecomposed type %s", v.Type)
+	}
+}
+
+func decomposeStringPhi(v *Value) {
+	fe := v.Block.Func.Config.fe
+	ptrType := fe.TypeBytePtr()
+	lenType := fe.TypeInt()
+
+	ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
+	len := v.Block.NewValue0(v.Line, OpPhi, lenType)
+	for _, a := range v.Args {
+		ptr.AddArg(a.Block.NewValue1(v.Line, OpStringPtr, ptrType, a))
+		len.AddArg(a.Block.NewValue1(v.Line, OpStringLen, lenType, a))
+	}
+	v.reset(OpStringMake)
+	v.AddArg(ptr)
+	v.AddArg(len)
+}
+
+func decomposeSlicePhi(v *Value) {
+	fe := v.Block.Func.Config.fe
+	ptrType := fe.TypeBytePtr()
+	lenType := fe.TypeInt()
+
+	ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
+	len := v.Block.NewValue0(v.Line, OpPhi, lenType)
+	cap := v.Block.NewValue0(v.Line, OpPhi, lenType)
+	for _, a := range v.Args {
+		ptr.AddArg(a.Block.NewValue1(v.Line, OpSlicePtr, ptrType, a))
+		len.AddArg(a.Block.NewValue1(v.Line, OpSliceLen, lenType, a))
+		cap.AddArg(a.Block.NewValue1(v.Line, OpSliceCap, lenType, a))
+	}
+	v.reset(OpSliceMake)
+	v.AddArg(ptr)
+	v.AddArg(len)
+	v.AddArg(cap)
+}
+
+func decomposeComplexPhi(v *Value) {
+	fe := v.Block.Func.Config.fe
+	var partType Type
+	switch z := v.Type.Size(); z {
+	case 8:
+		partType = fe.TypeFloat32()
+	case 16:
+		partType = fe.TypeFloat64()
+	default:
+		v.Fatalf("decomposeComplexPhi: bad complex size %d", z)
+	}
+
+	real := v.Block.NewValue0(v.Line, OpPhi, partType)
+	imag := v.Block.NewValue0(v.Line, OpPhi, partType)
+	for _, a := range v.Args {
+		real.AddArg(a.Block.NewValue1(v.Line, OpComplexReal, partType, a))
+		imag.AddArg(a.Block.NewValue1(v.Line, OpComplexImag, partType, a))
+	}
+	v.reset(OpComplexMake)
+	v.AddArg(real)
+	v.AddArg(imag)
+}
+
+func decomposeInterfacePhi(v *Value) {
+	ptrType := v.Block.Func.Config.fe.TypeBytePtr()
+
+	itab := v.Block.NewValue0(v.Line, OpPhi, ptrType)
+	data := v.Block.NewValue0(v.Line, OpPhi, ptrType)
+	for _, a := range v.Args {
+		itab.AddArg(a.Block.NewValue1(v.Line, OpITab, ptrType, a))
+		data.AddArg(a.Block.NewValue1(v.Line, OpIData, ptrType, a))
+	}
+	v.reset(OpIMake)
+	v.AddArg(itab)
+	v.AddArg(data)
+}
+
+func decomposeUser(f *Func) {
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if v.Op != OpPhi {
+				continue
+			}
+			decomposeUserPhi(v)
+		}
+	}
+	// Split up named values into their components.
+	// NOTE: the component values we are making are dead at this point.
+	// We must do the opt pass before any deadcode elimination or we will
+	// lose the name->value correspondence.
+	i := 0
+	var fnames []LocalSlot
+	var newNames []LocalSlot
+	for _, name := range f.Names {
+		t := name.Type
+		switch {
+		case t.IsStruct():
+			n := t.NumFields()
+			fnames = fnames[:0]
+			for i := 0; i < n; i++ {
+				fnames = append(fnames, f.Config.fe.SplitStruct(name, i))
+			}
+			for _, v := range f.NamedValues[name] {
+				for i := 0; i < n; i++ {
+					x := v.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), v)
+					f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], x)
+				}
+			}
+			delete(f.NamedValues, name)
+			newNames = append(newNames, fnames...)
+		default:
+			f.Names[i] = name
+			i++
+		}
+	}
+	f.Names = f.Names[:i]
+	f.Names = append(f.Names, newNames...)
+}
+
+func decomposeUserPhi(v *Value) {
+	switch {
+	case v.Type.IsStruct():
+		decomposeStructPhi(v)
+	}
+	// TODO: Arrays of length 1?
+}
+
+func decomposeStructPhi(v *Value) {
+	t := v.Type
+	n := t.NumFields()
+	var fields [MaxStruct]*Value
+	for i := 0; i < n; i++ {
+		fields[i] = v.Block.NewValue0(v.Line, OpPhi, t.FieldType(i))
+	}
+	for _, a := range v.Args {
+		for i := 0; i < n; i++ {
+			fields[i].AddArg(a.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), a))
+		}
+	}
+	v.reset(StructMakeOp(n))
+	v.AddArgs(fields[:n]...)
+
+	// Recursively decompose phis for each field.
+	for _, f := range fields[:n] {
+		if f.Type.IsStruct() {
+			decomposeStructPhi(f)
+		}
+	}
+}
+
+// MaxStruct is the maximum number of fields a struct
+// can have and still be SSAable.
+const MaxStruct = 4
+
+// StructMakeOp returns the opcode to construct a struct with the
+// given number of fields.
+func StructMakeOp(nf int) Op {
+	switch nf {
+	case 0:
+		return OpStructMake0
+	case 1:
+		return OpStructMake1
+	case 2:
+		return OpStructMake2
+	case 3:
+		return OpStructMake3
+	case 4:
+		return OpStructMake4
+	}
+	panic("too many fields in an SSAable struct")
+}
diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go
new file mode 100644
index 0000000..0c532c8
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/dom.go
@@ -0,0 +1,314 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// mark values
+type markKind uint8
+
+const (
+	notFound    markKind = 0 // block has not been discovered yet
+	notExplored markKind = 1 // discovered and in queue, outedges not processed yet
+	explored    markKind = 2 // discovered and in queue, outedges processed
+	done        markKind = 3 // all done, in output ordering
+)
+
+// This file contains code to compute the dominator tree
+// of a control-flow graph.
+
+// postorder computes a postorder traversal ordering for the
+// basic blocks in f. Unreachable blocks will not appear.
+func postorder(f *Func) []*Block {
+	return postorderWithNumbering(f, []int32{})
+}
+func postorderWithNumbering(f *Func, ponums []int32) []*Block {
+	mark := make([]markKind, f.NumBlocks())
+
+	// result ordering
+	var order []*Block
+
+	// stack of blocks
+	var s []*Block
+	s = append(s, f.Entry)
+	mark[f.Entry.ID] = notExplored
+	for len(s) > 0 {
+		b := s[len(s)-1]
+		switch mark[b.ID] {
+		case explored:
+			// Children have all been visited. Pop & output block.
+			s = s[:len(s)-1]
+			mark[b.ID] = done
+			if len(ponums) > 0 {
+				ponums[b.ID] = int32(len(order))
+			}
+			order = append(order, b)
+		case notExplored:
+			// Children have not been visited yet. Mark as explored
+			// and queue any children we haven't seen yet.
+			mark[b.ID] = explored
+			for _, e := range b.Succs {
+				c := e.b
+				if mark[c.ID] == notFound {
+					mark[c.ID] = notExplored
+					s = append(s, c)
+				}
+			}
+		default:
+			b.Fatalf("bad stack state %v %d", b, mark[b.ID])
+		}
+	}
+	return order
+}
+
+type linkedBlocks func(*Block) []Edge
+
+const nscratchslices = 7
+
+// experimentally, functions with 512 or fewer blocks account
+// for 75% of memory (size) allocation for dominator computation
+// in make.bash.
+const minscratchblocks = 512
+
+func (cfg *Config) scratchBlocksForDom(maxBlockID int) (a, b, c, d, e, f, g []ID) {
+	tot := maxBlockID * nscratchslices
+	scratch := cfg.domblockstore
+	if len(scratch) < tot {
+		// req = min(1.5*tot, nscratchslices*minscratchblocks)
+		// 50% padding allows for graph growth in later phases.
+		req := (tot * 3) >> 1
+		if req < nscratchslices*minscratchblocks {
+			req = nscratchslices * minscratchblocks
+		}
+		scratch = make([]ID, req)
+		cfg.domblockstore = scratch
+	} else {
+		// Clear as much of scratch as we will (re)use
+		scratch = scratch[0:tot]
+		for i := range scratch {
+			scratch[i] = 0
+		}
+	}
+
+	a = scratch[0*maxBlockID : 1*maxBlockID]
+	b = scratch[1*maxBlockID : 2*maxBlockID]
+	c = scratch[2*maxBlockID : 3*maxBlockID]
+	d = scratch[3*maxBlockID : 4*maxBlockID]
+	e = scratch[4*maxBlockID : 5*maxBlockID]
+	f = scratch[5*maxBlockID : 6*maxBlockID]
+	g = scratch[6*maxBlockID : 7*maxBlockID]
+
+	return
+}
+
+func dominators(f *Func) []*Block {
+	preds := func(b *Block) []Edge { return b.Preds }
+	succs := func(b *Block) []Edge { return b.Succs }
+
+	//TODO: benchmark and try to find criteria for swapping between
+	// dominatorsSimple and dominatorsLT
+	return f.dominatorsLTOrig(f.Entry, preds, succs)
+}
+
+// dominatorsLTOrig runs Lengauer-Tarjan to compute a dominator tree starting at
+// entry and using predFn/succFn to find predecessors/successors to allow
+// computing both dominator and post-dominator trees.
+func (f *Func) dominatorsLTOrig(entry *Block, predFn linkedBlocks, succFn linkedBlocks) []*Block {
+	// Adapted directly from the original TOPLAS article's "simple" algorithm
+
+	maxBlockID := entry.Func.NumBlocks()
+	semi, vertex, label, parent, ancestor, bucketHead, bucketLink := f.Config.scratchBlocksForDom(maxBlockID)
+
+	// This version uses integers for most of the computation,
+	// to make the work arrays smaller and pointer-free.
+	// fromID translates from ID to *Block where that is needed.
+	fromID := make([]*Block, maxBlockID)
+	for _, v := range f.Blocks {
+		fromID[v.ID] = v
+	}
+	idom := make([]*Block, maxBlockID)
+
+	// Step 1. Carry out a depth first search of the problem graph. Number
+	// the vertices from 1 to n as they are reached during the search.
+	n := f.dfsOrig(entry, succFn, semi, vertex, label, parent)
+
+	for i := n; i >= 2; i-- {
+		w := vertex[i]
+
+		// step2 in TOPLAS paper
+		for _, e := range predFn(fromID[w]) {
+			v := e.b
+			if semi[v.ID] == 0 {
+				// skip unreachable predecessor
+				// not in original, but we're using existing pred instead of building one.
+				continue
+			}
+			u := evalOrig(v.ID, ancestor, semi, label)
+			if semi[u] < semi[w] {
+				semi[w] = semi[u]
+			}
+		}
+
+		// add w to bucket[vertex[semi[w]]]
+		// implement bucket as a linked list implemented
+		// in a pair of arrays.
+		vsw := vertex[semi[w]]
+		bucketLink[w] = bucketHead[vsw]
+		bucketHead[vsw] = w
+
+		linkOrig(parent[w], w, ancestor)
+
+		// step3 in TOPLAS paper
+		for v := bucketHead[parent[w]]; v != 0; v = bucketLink[v] {
+			u := evalOrig(v, ancestor, semi, label)
+			if semi[u] < semi[v] {
+				idom[v] = fromID[u]
+			} else {
+				idom[v] = fromID[parent[w]]
+			}
+		}
+	}
+	// step 4 in toplas paper
+	for i := ID(2); i <= n; i++ {
+		w := vertex[i]
+		if idom[w].ID != vertex[semi[w]] {
+			idom[w] = idom[idom[w].ID]
+		}
+	}
+
+	return idom
+}
+
+// dfs performs a depth first search over the blocks starting at entry block
+// (in arbitrary order).  This is a de-recursed version of dfs from the
+// original Tarjan-Lengauer TOPLAS article.  It's important to return the
+// same values for parent as the original algorithm.
+func (f *Func) dfsOrig(entry *Block, succFn linkedBlocks, semi, vertex, label, parent []ID) ID {
+	n := ID(0)
+	s := make([]*Block, 0, 256)
+	s = append(s, entry)
+
+	for len(s) > 0 {
+		v := s[len(s)-1]
+		s = s[:len(s)-1]
+		// recursing on v
+
+		if semi[v.ID] != 0 {
+			continue // already visited
+		}
+		n++
+		semi[v.ID] = n
+		vertex[n] = v.ID
+		label[v.ID] = v.ID
+		// ancestor[v] already zero
+		for _, e := range succFn(v) {
+			w := e.b
+			// if it has a dfnum, we've already visited it
+			if semi[w.ID] == 0 {
+				// yes, w can be pushed multiple times.
+				s = append(s, w)
+				parent[w.ID] = v.ID // keep overwriting this till it is visited.
+			}
+		}
+	}
+	return n
+}
+
+// compressOrig is the "simple" compress function from LT paper
+func compressOrig(v ID, ancestor, semi, label []ID) {
+	if ancestor[ancestor[v]] != 0 {
+		compressOrig(ancestor[v], ancestor, semi, label)
+		if semi[label[ancestor[v]]] < semi[label[v]] {
+			label[v] = label[ancestor[v]]
+		}
+		ancestor[v] = ancestor[ancestor[v]]
+	}
+}
+
+// evalOrig is the "simple" eval function from LT paper
+func evalOrig(v ID, ancestor, semi, label []ID) ID {
+	if ancestor[v] == 0 {
+		return v
+	}
+	compressOrig(v, ancestor, semi, label)
+	return label[v]
+}
+
+func linkOrig(v, w ID, ancestor []ID) {
+	ancestor[w] = v
+}
+
+// dominators computes the dominator tree for f. It returns a slice
+// which maps block ID to the immediate dominator of that block.
+// Unreachable blocks map to nil. The entry block maps to nil.
+func dominatorsSimple(f *Func) []*Block {
+	// A simple algorithm for now
+	// Cooper, Harvey, Kennedy
+	idom := make([]*Block, f.NumBlocks())
+
+	// Compute postorder walk
+	post := postorder(f)
+
+	// Make map from block id to order index (for intersect call)
+	postnum := make([]int, f.NumBlocks())
+	for i, b := range post {
+		postnum[b.ID] = i
+	}
+
+	// Make the entry block a self-loop
+	idom[f.Entry.ID] = f.Entry
+	if postnum[f.Entry.ID] != len(post)-1 {
+		f.Fatalf("entry block %v not last in postorder", f.Entry)
+	}
+
+	// Compute relaxation of idom entries
+	for {
+		changed := false
+
+		for i := len(post) - 2; i >= 0; i-- {
+			b := post[i]
+			var d *Block
+			for _, e := range b.Preds {
+				p := e.b
+				if idom[p.ID] == nil {
+					continue
+				}
+				if d == nil {
+					d = p
+					continue
+				}
+				d = intersect(d, p, postnum, idom)
+			}
+			if d != idom[b.ID] {
+				idom[b.ID] = d
+				changed = true
+			}
+		}
+		if !changed {
+			break
+		}
+	}
+	// Set idom of entry block to nil instead of itself.
+	idom[f.Entry.ID] = nil
+	return idom
+}
+
+// intersect finds the closest dominator of both b and c.
+// It requires a postorder numbering of all the blocks.
+func intersect(b, c *Block, postnum []int, idom []*Block) *Block {
+	// TODO: This loop is O(n^2). See BenchmarkNilCheckDeep*.
+	for b != c {
+		if postnum[b.ID] < postnum[c.ID] {
+			b = idom[b.ID]
+		} else {
+			c = idom[c.ID]
+		}
+	}
+	return b
+}
+
+// build immediate dominators.
+func domTree(f *Func) {
+	f.idom = dominators(f)
+	f.sdom = newSparseTree(f, f.idom)
+}
diff --git a/src/cmd/compile/internal/ssa/dom_test.go b/src/cmd/compile/internal/ssa/dom_test.go
new file mode 100644
index 0000000..6ecbe92
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/dom_test.go
@@ -0,0 +1,572 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "testing"
+
+func BenchmarkDominatorsLinear(b *testing.B)     { benchmarkDominators(b, 10000, genLinear) }
+func BenchmarkDominatorsFwdBack(b *testing.B)    { benchmarkDominators(b, 10000, genFwdBack) }
+func BenchmarkDominatorsManyPred(b *testing.B)   { benchmarkDominators(b, 10000, genManyPred) }
+func BenchmarkDominatorsMaxPred(b *testing.B)    { benchmarkDominators(b, 10000, genMaxPred) }
+func BenchmarkDominatorsMaxPredVal(b *testing.B) { benchmarkDominators(b, 10000, genMaxPredValue) }
+
+type blockGen func(size int) []bloc
+
+// genLinear creates an array of blocks that succeed one another
+// b_n -> [b_n+1].
+func genLinear(size int) []bloc {
+	var blocs []bloc
+	blocs = append(blocs,
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Goto(blockn(0)),
+		),
+	)
+	for i := 0; i < size; i++ {
+		blocs = append(blocs, Bloc(blockn(i),
+			Goto(blockn(i+1))))
+	}
+
+	blocs = append(blocs,
+		Bloc(blockn(size), Goto("exit")),
+		Bloc("exit", Exit("mem")),
+	)
+
+	return blocs
+}
+
+// genLinear creates an array of blocks that alternate between
+// b_n -> [b_n+1], b_n -> [b_n+1, b_n-1] , b_n -> [b_n+1, b_n+2]
+func genFwdBack(size int) []bloc {
+	var blocs []bloc
+	blocs = append(blocs,
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Goto(blockn(0)),
+		),
+	)
+	for i := 0; i < size; i++ {
+		switch i % 2 {
+		case 0:
+			blocs = append(blocs, Bloc(blockn(i),
+				If("p", blockn(i+1), blockn(i+2))))
+		case 1:
+			blocs = append(blocs, Bloc(blockn(i),
+				If("p", blockn(i+1), blockn(i-1))))
+		}
+	}
+
+	blocs = append(blocs,
+		Bloc(blockn(size), Goto("exit")),
+		Bloc("exit", Exit("mem")),
+	)
+
+	return blocs
+}
+
+// genManyPred creates an array of blocks where 1/3rd have a successor of the
+// first block, 1/3rd the last block, and the remaining third are plain.
+func genManyPred(size int) []bloc {
+	var blocs []bloc
+	blocs = append(blocs,
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Goto(blockn(0)),
+		),
+	)
+
+	// We want predecessor lists to be long, so 2/3rds of the blocks have a
+	// successor of the first or last block.
+	for i := 0; i < size; i++ {
+		switch i % 3 {
+		case 0:
+			blocs = append(blocs, Bloc(blockn(i),
+				Valu("a", OpConstBool, TypeBool, 1, nil),
+				Goto(blockn(i+1))))
+		case 1:
+			blocs = append(blocs, Bloc(blockn(i),
+				Valu("a", OpConstBool, TypeBool, 1, nil),
+				If("p", blockn(i+1), blockn(0))))
+		case 2:
+			blocs = append(blocs, Bloc(blockn(i),
+				Valu("a", OpConstBool, TypeBool, 1, nil),
+				If("p", blockn(i+1), blockn(size))))
+		}
+	}
+
+	blocs = append(blocs,
+		Bloc(blockn(size), Goto("exit")),
+		Bloc("exit", Exit("mem")),
+	)
+
+	return blocs
+}
+
+// genMaxPred maximizes the size of the 'exit' predecessor list.
+func genMaxPred(size int) []bloc {
+	var blocs []bloc
+	blocs = append(blocs,
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Goto(blockn(0)),
+		),
+	)
+
+	for i := 0; i < size; i++ {
+		blocs = append(blocs, Bloc(blockn(i),
+			If("p", blockn(i+1), "exit")))
+	}
+
+	blocs = append(blocs,
+		Bloc(blockn(size), Goto("exit")),
+		Bloc("exit", Exit("mem")),
+	)
+
+	return blocs
+}
+
+// genMaxPredValue is identical to genMaxPred but contains an
+// additional value.
+func genMaxPredValue(size int) []bloc {
+	var blocs []bloc
+	blocs = append(blocs,
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Goto(blockn(0)),
+		),
+	)
+
+	for i := 0; i < size; i++ {
+		blocs = append(blocs, Bloc(blockn(i),
+			Valu("a", OpConstBool, TypeBool, 1, nil),
+			If("p", blockn(i+1), "exit")))
+	}
+
+	blocs = append(blocs,
+		Bloc(blockn(size), Goto("exit")),
+		Bloc("exit", Exit("mem")),
+	)
+
+	return blocs
+}
+
+// sink for benchmark
+var domBenchRes []*Block
+
+func benchmarkDominators(b *testing.B, size int, bg blockGen) {
+	c := NewConfig("amd64", DummyFrontend{b}, nil, true)
+	fun := Fun(c, "entry", bg(size)...)
+
+	CheckFunc(fun.f)
+	b.SetBytes(int64(size))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		domBenchRes = dominators(fun.f)
+	}
+}
+
+type domFunc func(f *Func) []*Block
+
+// verifyDominators verifies that the dominators of fut (function under test)
+// as determined by domFn, match the map node->dominator
+func verifyDominators(t *testing.T, fut fun, domFn domFunc, doms map[string]string) {
+	blockNames := map[*Block]string{}
+	for n, b := range fut.blocks {
+		blockNames[b] = n
+	}
+
+	calcDom := domFn(fut.f)
+
+	for n, d := range doms {
+		nblk, ok := fut.blocks[n]
+		if !ok {
+			t.Errorf("invalid block name %s", n)
+		}
+		dblk, ok := fut.blocks[d]
+		if !ok {
+			t.Errorf("invalid block name %s", d)
+		}
+
+		domNode := calcDom[nblk.ID]
+		switch {
+		case calcDom[nblk.ID] == dblk:
+			calcDom[nblk.ID] = nil
+			continue
+		case calcDom[nblk.ID] != dblk:
+			t.Errorf("expected %s as dominator of %s, found %s", d, n, blockNames[domNode])
+		default:
+			t.Fatal("unexpected dominator condition")
+		}
+	}
+
+	for id, d := range calcDom {
+		// If nil, we've already verified it
+		if d == nil {
+			continue
+		}
+		for _, b := range fut.blocks {
+			if int(b.ID) == id {
+				t.Errorf("unexpected dominator of %s for %s", blockNames[d], blockNames[b])
+			}
+		}
+	}
+
+}
+
+func TestDominatorsSingleBlock(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Exit("mem")))
+
+	doms := map[string]string{}
+
+	CheckFunc(fun.f)
+	verifyDominators(t, fun, dominators, doms)
+	verifyDominators(t, fun, dominatorsSimple, doms)
+
+}
+
+func TestDominatorsSimple(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Goto("a")),
+		Bloc("a",
+			Goto("b")),
+		Bloc("b",
+			Goto("c")),
+		Bloc("c",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	doms := map[string]string{
+		"a":    "entry",
+		"b":    "a",
+		"c":    "b",
+		"exit": "c",
+	}
+
+	CheckFunc(fun.f)
+	verifyDominators(t, fun, dominators, doms)
+	verifyDominators(t, fun, dominatorsSimple, doms)
+
+}
+
+func TestDominatorsMultPredFwd(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 1, nil),
+			If("p", "a", "c")),
+		Bloc("a",
+			If("p", "b", "c")),
+		Bloc("b",
+			Goto("c")),
+		Bloc("c",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	doms := map[string]string{
+		"a":    "entry",
+		"b":    "a",
+		"c":    "entry",
+		"exit": "c",
+	}
+
+	CheckFunc(fun.f)
+	verifyDominators(t, fun, dominators, doms)
+	verifyDominators(t, fun, dominatorsSimple, doms)
+}
+
+func TestDominatorsDeadCode(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 0, nil),
+			If("p", "b3", "b5")),
+		Bloc("b2", Exit("mem")),
+		Bloc("b3", Goto("b2")),
+		Bloc("b4", Goto("b2")),
+		Bloc("b5", Goto("b2")))
+
+	doms := map[string]string{
+		"b2": "entry",
+		"b3": "entry",
+		"b5": "entry",
+	}
+
+	CheckFunc(fun.f)
+	verifyDominators(t, fun, dominators, doms)
+	verifyDominators(t, fun, dominatorsSimple, doms)
+}
+
+func TestDominatorsMultPredRev(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Goto("first")),
+		Bloc("first",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Goto("a")),
+		Bloc("a",
+			If("p", "b", "first")),
+		Bloc("b",
+			Goto("c")),
+		Bloc("c",
+			If("p", "exit", "b")),
+		Bloc("exit",
+			Exit("mem")))
+
+	doms := map[string]string{
+		"first": "entry",
+		"a":     "first",
+		"b":     "a",
+		"c":     "b",
+		"exit":  "c",
+	}
+
+	CheckFunc(fun.f)
+	verifyDominators(t, fun, dominators, doms)
+	verifyDominators(t, fun, dominatorsSimple, doms)
+}
+
+func TestDominatorsMultPred(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 1, nil),
+			If("p", "a", "c")),
+		Bloc("a",
+			If("p", "b", "c")),
+		Bloc("b",
+			Goto("c")),
+		Bloc("c",
+			If("p", "b", "exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	doms := map[string]string{
+		"a":    "entry",
+		"b":    "entry",
+		"c":    "entry",
+		"exit": "c",
+	}
+
+	CheckFunc(fun.f)
+	verifyDominators(t, fun, dominators, doms)
+	verifyDominators(t, fun, dominatorsSimple, doms)
+}
+
+func TestInfiniteLoop(t *testing.T) {
+	c := testConfig(t)
+	// note lack of an exit block
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 1, nil),
+			Goto("a")),
+		Bloc("a",
+			Goto("b")),
+		Bloc("b",
+			Goto("a")))
+
+	CheckFunc(fun.f)
+	doms := map[string]string{"a": "entry",
+		"b": "a"}
+	verifyDominators(t, fun, dominators, doms)
+}
+
+func TestDomTricky(t *testing.T) {
+	doms := map[string]string{
+		"4":  "1",
+		"2":  "4",
+		"5":  "4",
+		"11": "4",
+		"15": "4", // the incorrect answer is "5"
+		"10": "15",
+		"19": "15",
+	}
+
+	if4 := [2]string{"2", "5"}
+	if5 := [2]string{"15", "11"}
+	if15 := [2]string{"19", "10"}
+
+	for i := 0; i < 8; i++ {
+		a := 1 & i
+		b := 1 & i >> 1
+		c := 1 & i >> 2
+
+		fun := Fun(testConfig(t), "1",
+			Bloc("1",
+				Valu("mem", OpInitMem, TypeMem, 0, nil),
+				Valu("p", OpConstBool, TypeBool, 1, nil),
+				Goto("4")),
+			Bloc("2",
+				Goto("11")),
+			Bloc("4",
+				If("p", if4[a], if4[1-a])), // 2, 5
+			Bloc("5",
+				If("p", if5[b], if5[1-b])), //15, 11
+			Bloc("10",
+				Exit("mem")),
+			Bloc("11",
+				Goto("15")),
+			Bloc("15",
+				If("p", if15[c], if15[1-c])), //19, 10
+			Bloc("19",
+				Goto("10")))
+		CheckFunc(fun.f)
+		verifyDominators(t, fun, dominators, doms)
+		verifyDominators(t, fun, dominatorsSimple, doms)
+	}
+}
+
+// generateDominatorMap uses dominatorsSimple to obtain a
+// reference dominator tree for testing faster algorithms.
+func generateDominatorMap(fut fun) map[string]string {
+	blockNames := map[*Block]string{}
+	for n, b := range fut.blocks {
+		blockNames[b] = n
+	}
+	referenceDom := dominatorsSimple(fut.f)
+	doms := make(map[string]string)
+	for _, b := range fut.f.Blocks {
+		if d := referenceDom[b.ID]; d != nil {
+			doms[blockNames[b]] = blockNames[d]
+		}
+	}
+	return doms
+}
+
+func TestDominatorsPostTricky(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "b1",
+		Bloc("b1",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("p", OpConstBool, TypeBool, 1, nil),
+			If("p", "b3", "b2")),
+		Bloc("b3",
+			If("p", "b5", "b6")),
+		Bloc("b5",
+			Goto("b7")),
+		Bloc("b7",
+			If("p", "b8", "b11")),
+		Bloc("b8",
+			Goto("b13")),
+		Bloc("b13",
+			If("p", "b14", "b15")),
+		Bloc("b14",
+			Goto("b10")),
+		Bloc("b15",
+			Goto("b16")),
+		Bloc("b16",
+			Goto("b9")),
+		Bloc("b9",
+			Goto("b7")),
+		Bloc("b11",
+			Goto("b12")),
+		Bloc("b12",
+			If("p", "b10", "b8")),
+		Bloc("b10",
+			Goto("b6")),
+		Bloc("b6",
+			Goto("b17")),
+		Bloc("b17",
+			Goto("b18")),
+		Bloc("b18",
+			If("p", "b22", "b19")),
+		Bloc("b22",
+			Goto("b23")),
+		Bloc("b23",
+			If("p", "b21", "b19")),
+		Bloc("b19",
+			If("p", "b24", "b25")),
+		Bloc("b24",
+			Goto("b26")),
+		Bloc("b26",
+			Goto("b25")),
+		Bloc("b25",
+			If("p", "b27", "b29")),
+		Bloc("b27",
+			Goto("b30")),
+		Bloc("b30",
+			Goto("b28")),
+		Bloc("b29",
+			Goto("b31")),
+		Bloc("b31",
+			Goto("b28")),
+		Bloc("b28",
+			If("p", "b32", "b33")),
+		Bloc("b32",
+			Goto("b21")),
+		Bloc("b21",
+			Goto("b47")),
+		Bloc("b47",
+			If("p", "b45", "b46")),
+		Bloc("b45",
+			Goto("b48")),
+		Bloc("b48",
+			Goto("b49")),
+		Bloc("b49",
+			If("p", "b50", "b51")),
+		Bloc("b50",
+			Goto("b52")),
+		Bloc("b52",
+			Goto("b53")),
+		Bloc("b53",
+			Goto("b51")),
+		Bloc("b51",
+			Goto("b54")),
+		Bloc("b54",
+			Goto("b46")),
+		Bloc("b46",
+			Exit("mem")),
+		Bloc("b33",
+			Goto("b34")),
+		Bloc("b34",
+			Goto("b37")),
+		Bloc("b37",
+			If("p", "b35", "b36")),
+		Bloc("b35",
+			Goto("b38")),
+		Bloc("b38",
+			Goto("b39")),
+		Bloc("b39",
+			If("p", "b40", "b41")),
+		Bloc("b40",
+			Goto("b42")),
+		Bloc("b42",
+			Goto("b43")),
+		Bloc("b43",
+			Goto("b41")),
+		Bloc("b41",
+			Goto("b44")),
+		Bloc("b44",
+			Goto("b36")),
+		Bloc("b36",
+			Goto("b20")),
+		Bloc("b20",
+			Goto("b18")),
+		Bloc("b2",
+			Goto("b4")),
+		Bloc("b4",
+			Exit("mem")))
+	CheckFunc(fun.f)
+	doms := generateDominatorMap(fun)
+	verifyDominators(t, fun, dominators, doms)
+}
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
new file mode 100644
index 0000000..27892a8
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -0,0 +1,88 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"cmd/internal/obj"
+	"testing"
+)
+
+var CheckFunc = checkFunc
+var PrintFunc = printFunc
+var Opt = opt
+var Deadcode = deadcode
+var Copyelim = copyelim
+
+func testConfig(t testing.TB) *Config {
+	testCtxt := &obj.Link{}
+	return NewConfig("amd64", DummyFrontend{t}, testCtxt, true)
+}
+
+// DummyFrontend is a test-only frontend.
+// It assumes 64 bit integers and pointers.
+type DummyFrontend struct {
+	t testing.TB
+}
+
+func (DummyFrontend) StringData(s string) interface{} {
+	return nil
+}
+func (DummyFrontend) Auto(t Type) GCNode {
+	return nil
+}
+func (d DummyFrontend) SplitString(s LocalSlot) (LocalSlot, LocalSlot) {
+	return LocalSlot{s.N, d.TypeBytePtr(), s.Off}, LocalSlot{s.N, d.TypeInt(), s.Off + 8}
+}
+func (d DummyFrontend) SplitInterface(s LocalSlot) (LocalSlot, LocalSlot) {
+	return LocalSlot{s.N, d.TypeBytePtr(), s.Off}, LocalSlot{s.N, d.TypeBytePtr(), s.Off + 8}
+}
+func (d DummyFrontend) SplitSlice(s LocalSlot) (LocalSlot, LocalSlot, LocalSlot) {
+	return LocalSlot{s.N, s.Type.ElemType().PtrTo(), s.Off},
+		LocalSlot{s.N, d.TypeInt(), s.Off + 8},
+		LocalSlot{s.N, d.TypeInt(), s.Off + 16}
+}
+func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
+	if s.Type.Size() == 16 {
+		return LocalSlot{s.N, d.TypeFloat64(), s.Off}, LocalSlot{s.N, d.TypeFloat64(), s.Off + 8}
+	}
+	return LocalSlot{s.N, d.TypeFloat32(), s.Off}, LocalSlot{s.N, d.TypeFloat32(), s.Off + 4}
+}
+func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
+	return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)}
+}
+func (DummyFrontend) Line(line int32) string {
+	return "unknown.go:0"
+}
+
+func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
+func (d DummyFrontend) Log() bool                            { return true }
+
+func (d DummyFrontend) Fatalf(line int32, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
+func (d DummyFrontend) Unimplementedf(line int32, msg string, args ...interface{}) {
+	d.t.Fatalf(msg, args...)
+}
+func (d DummyFrontend) Warnl(line int32, msg string, args ...interface{}) { d.t.Logf(msg, args...) }
+func (d DummyFrontend) Debug_checknil() bool                              { return false }
+
+func (d DummyFrontend) TypeBool() Type    { return TypeBool }
+func (d DummyFrontend) TypeInt8() Type    { return TypeInt8 }
+func (d DummyFrontend) TypeInt16() Type   { return TypeInt16 }
+func (d DummyFrontend) TypeInt32() Type   { return TypeInt32 }
+func (d DummyFrontend) TypeInt64() Type   { return TypeInt64 }
+func (d DummyFrontend) TypeUInt8() Type   { return TypeUInt8 }
+func (d DummyFrontend) TypeUInt16() Type  { return TypeUInt16 }
+func (d DummyFrontend) TypeUInt32() Type  { return TypeUInt32 }
+func (d DummyFrontend) TypeUInt64() Type  { return TypeUInt64 }
+func (d DummyFrontend) TypeFloat32() Type { return TypeFloat32 }
+func (d DummyFrontend) TypeFloat64() Type { return TypeFloat64 }
+func (d DummyFrontend) TypeInt() Type     { return TypeInt64 }
+func (d DummyFrontend) TypeUintptr() Type { return TypeUInt64 }
+func (d DummyFrontend) TypeString() Type  { panic("unimplemented") }
+func (d DummyFrontend) TypeBytePtr() Type { return TypeBytePtr }
+
+func (d DummyFrontend) CanSSA(t Type) bool {
+	// There are no un-SSAable types in dummy land.
+	return true
+}
diff --git a/src/cmd/compile/internal/ssa/flagalloc.go b/src/cmd/compile/internal/ssa/flagalloc.go
new file mode 100644
index 0000000..f6c457d
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/flagalloc.go
@@ -0,0 +1,137 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+const flagRegMask = regMask(1) << 33 // TODO: arch-specific
+
+// flagalloc allocates the flag register among all the flag-generating
+// instructions. Flag values are recomputed if they need to be
+// spilled/restored.
+func flagalloc(f *Func) {
+	// Compute the in-register flag value we want at the end of
+	// each block. This is basically a best-effort live variable
+	// analysis, so it can be much simpler than a full analysis.
+	// TODO: do we really need to keep flag values live across blocks?
+	// Could we force the flags register to be unused at basic block
+	// boundaries?  Then we wouldn't need this computation.
+	end := make([]*Value, f.NumBlocks())
+	for n := 0; n < 2; n++ {
+		// Walk blocks backwards. Poor-man's postorder traversal.
+		for i := len(f.Blocks) - 1; i >= 0; i-- {
+			b := f.Blocks[i]
+			// Walk values backwards to figure out what flag
+			// value we want in the flag register at the start
+			// of the block.
+			flag := end[b.ID]
+			if b.Control != nil && b.Control.Type.IsFlags() {
+				flag = b.Control
+			}
+			for j := len(b.Values) - 1; j >= 0; j-- {
+				v := b.Values[j]
+				if v == flag {
+					flag = nil
+				}
+				if opcodeTable[v.Op].reg.clobbers&flagRegMask != 0 {
+					flag = nil
+				}
+				for _, a := range v.Args {
+					if a.Type.IsFlags() {
+						flag = a
+					}
+				}
+			}
+			if flag != nil {
+				for _, e := range b.Preds {
+					p := e.b
+					end[p.ID] = flag
+				}
+			}
+		}
+	}
+
+	// For blocks which have a flags control value, that's the only value
+	// we can leave in the flags register at the end of the block. (There
+	// is no place to put a flag regeneration instruction.)
+	for _, b := range f.Blocks {
+		v := b.Control
+		if v != nil && v.Type.IsFlags() && end[b.ID] != v {
+			end[b.ID] = nil
+		}
+		if b.Kind == BlockDefer {
+			// Defer blocks internally use/clobber the flags value.
+			end[b.ID] = nil
+		}
+	}
+
+	// Add flag recomputations where they are needed.
+	// TODO: Remove original instructions if they are never used.
+	var oldSched []*Value
+	for _, b := range f.Blocks {
+		oldSched = append(oldSched[:0], b.Values...)
+		b.Values = b.Values[:0]
+		// The current live flag value the pre-flagalloc copy).
+		var flag *Value
+		if len(b.Preds) > 0 {
+			flag = end[b.Preds[0].b.ID]
+			// Note: the following condition depends on the lack of critical edges.
+			for _, e := range b.Preds[1:] {
+				p := e.b
+				if end[p.ID] != flag {
+					f.Fatalf("live flag in %s's predecessors not consistent", b)
+				}
+			}
+		}
+		for _, v := range oldSched {
+			if v.Op == OpPhi && v.Type.IsFlags() {
+				f.Fatalf("phi of flags not supported: %s", v.LongString())
+			}
+			// Make sure any flag arg of v is in the flags register.
+			// If not, recompute it.
+			for i, a := range v.Args {
+				if !a.Type.IsFlags() {
+					continue
+				}
+				if a == flag {
+					continue
+				}
+				// Recalculate a
+				c := a.copyInto(b)
+				// Update v.
+				v.SetArg(i, c)
+				// Remember the most-recently computed flag value.
+				flag = a
+			}
+			// Issue v.
+			b.Values = append(b.Values, v)
+			if opcodeTable[v.Op].reg.clobbers&flagRegMask != 0 {
+				flag = nil
+			}
+			if v.Type.IsFlags() {
+				flag = v
+			}
+		}
+		if v := b.Control; v != nil && v != flag && v.Type.IsFlags() {
+			// Recalculate control value.
+			c := v.copyInto(b)
+			b.SetControl(c)
+			flag = v
+		}
+		if v := end[b.ID]; v != nil && v != flag {
+			// Need to reissue flag generator for use by
+			// subsequent blocks.
+			_ = v.copyInto(b)
+			// Note: this flag generator is not properly linked up
+			// with the flag users. This breaks the SSA representation.
+			// We could fix up the users with another pass, but for now
+			// we'll just leave it.  (Regalloc has the same issue for
+			// standard regs, and it runs next.)
+		}
+	}
+
+	// Save live flag state for later.
+	for _, b := range f.Blocks {
+		b.FlagsLiveAtEnd = end[b.ID] != nil
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
new file mode 100644
index 0000000..1d60bb6
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -0,0 +1,429 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"fmt"
+	"math"
+)
+
+// A Func represents a Go func declaration (or function literal) and
+// its body. This package compiles each Func independently.
+type Func struct {
+	Config     *Config     // architecture information
+	pass       *pass       // current pass information (name, options, etc.)
+	Name       string      // e.g. bytes·Compare
+	Type       Type        // type signature of the function.
+	StaticData interface{} // associated static data, untouched by the ssa package
+	Blocks     []*Block    // unordered set of all basic blocks (note: not indexable by ID)
+	Entry      *Block      // the entry basic block
+	bid        idAlloc     // block ID allocator
+	vid        idAlloc     // value ID allocator
+
+	scheduled bool // Values in Blocks are in final order
+
+	// when register allocation is done, maps value ids to locations
+	RegAlloc []Location
+
+	// map from LocalSlot to set of Values that we want to store in that slot.
+	NamedValues map[LocalSlot][]*Value
+	// Names is a copy of NamedValues.Keys. We keep a separate list
+	// of keys to make iteration order deterministic.
+	Names []LocalSlot
+
+	freeValues *Value // free Values linked by argstorage[0].  All other fields except ID are 0/nil.
+	freeBlocks *Block // free Blocks linked by succstorage[0].b.  All other fields except ID are 0/nil.
+
+	idom []*Block   // precomputed immediate dominators
+	sdom SparseTree // precomputed dominator tree
+
+	constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
+}
+
+// NumBlocks returns an integer larger than the id of any Block in the Func.
+func (f *Func) NumBlocks() int {
+	return f.bid.num()
+}
+
+// NumValues returns an integer larger than the id of any Value in the Func.
+func (f *Func) NumValues() int {
+	return f.vid.num()
+}
+
+// newSparseSet returns a sparse set that can store at least up to n integers.
+func (f *Func) newSparseSet(n int) *sparseSet {
+	for i, scr := range f.Config.scrSparse {
+		if scr != nil && scr.cap() >= n {
+			f.Config.scrSparse[i] = nil
+			scr.clear()
+			return scr
+		}
+	}
+	return newSparseSet(n)
+}
+
+// retSparseSet returns a sparse set to the config's cache of sparse sets to be reused by f.newSparseSet.
+func (f *Func) retSparseSet(ss *sparseSet) {
+	for i, scr := range f.Config.scrSparse {
+		if scr == nil {
+			f.Config.scrSparse[i] = ss
+			return
+		}
+	}
+	f.Config.scrSparse = append(f.Config.scrSparse, ss)
+}
+
+// newValue allocates a new Value with the given fields and places it at the end of b.Values.
+func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
+	var v *Value
+	if f.freeValues != nil {
+		v = f.freeValues
+		f.freeValues = v.argstorage[0]
+		v.argstorage[0] = nil
+	} else {
+		ID := f.vid.get()
+		if int(ID) < len(f.Config.values) {
+			v = &f.Config.values[ID]
+		} else {
+			v = &Value{ID: ID}
+		}
+	}
+	v.Op = op
+	v.Type = t
+	v.Block = b
+	v.Line = line
+	b.Values = append(b.Values, v)
+	return v
+}
+
+// logPassStat writes a string key and int value as a warning in a
+// tab-separated format easily handled by spreadsheets or awk.
+// file names, lines, and function names are included to provide enough (?)
+// context to allow item-by-item comparisons across runs.
+// For example:
+// awk 'BEGIN {FS="\t"} $3~/TIME/{sum+=$4} END{print "t(ns)=",sum}' t.log
+func (f *Func) LogStat(key string, args ...interface{}) {
+	value := ""
+	for _, a := range args {
+		value += fmt.Sprintf("\t%v", a)
+	}
+	n := "missing_pass"
+	if f.pass != nil {
+		n = f.pass.name
+	}
+	f.Config.Warnl(f.Entry.Line, "\t%s\t%s%s\t%s", n, key, value, f.Name)
+}
+
+// freeValue frees a value. It must no longer be referenced.
+func (f *Func) freeValue(v *Value) {
+	if v.Block == nil {
+		f.Fatalf("trying to free an already freed value")
+	}
+	if v.Uses != 0 {
+		f.Fatalf("value %s still has %d uses", v, v.Uses)
+	}
+	// Clear everything but ID (which we reuse).
+	id := v.ID
+
+	// Zero argument values might be cached, so remove them there.
+	nArgs := opcodeTable[v.Op].argLen
+	if nArgs == 0 {
+		vv := f.constants[v.AuxInt]
+		for i, cv := range vv {
+			if v == cv {
+				vv[i] = vv[len(vv)-1]
+				f.constants[v.AuxInt] = vv[0 : len(vv)-1]
+				break
+			}
+		}
+	}
+	*v = Value{}
+	v.ID = id
+	v.argstorage[0] = f.freeValues
+	f.freeValues = v
+}
+
+// newBlock allocates a new Block of the given kind and places it at the end of f.Blocks.
+func (f *Func) NewBlock(kind BlockKind) *Block {
+	var b *Block
+	if f.freeBlocks != nil {
+		b = f.freeBlocks
+		f.freeBlocks = b.succstorage[0].b
+		b.succstorage[0].b = nil
+	} else {
+		ID := f.bid.get()
+		if int(ID) < len(f.Config.blocks) {
+			b = &f.Config.blocks[ID]
+		} else {
+			b = &Block{ID: ID}
+		}
+	}
+	b.Kind = kind
+	b.Func = f
+	b.Preds = b.predstorage[:0]
+	b.Succs = b.succstorage[:0]
+	b.Values = b.valstorage[:0]
+	f.Blocks = append(f.Blocks, b)
+	return b
+}
+
+func (f *Func) freeBlock(b *Block) {
+	if b.Func == nil {
+		f.Fatalf("trying to free an already freed block")
+	}
+	// Clear everything but ID (which we reuse).
+	id := b.ID
+	*b = Block{}
+	b.ID = id
+	b.succstorage[0].b = f.freeBlocks
+	f.freeBlocks = b
+}
+
+// NewValue0 returns a new value in the block with no arguments and zero aux values.
+func (b *Block) NewValue0(line int32, op Op, t Type) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = 0
+	v.Args = v.argstorage[:0]
+	return v
+}
+
+// NewValue returns a new value in the block with no arguments and an auxint value.
+func (b *Block) NewValue0I(line int32, op Op, t Type, auxint int64) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = auxint
+	v.Args = v.argstorage[:0]
+	return v
+}
+
+// NewValue returns a new value in the block with no arguments and an aux value.
+func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value {
+	if _, ok := aux.(int64); ok {
+		// Disallow int64 aux values. They should be in the auxint field instead.
+		// Maybe we want to allow this at some point, but for now we disallow it
+		// to prevent errors like using NewValue1A instead of NewValue1I.
+		b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux)
+	}
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = 0
+	v.Aux = aux
+	v.Args = v.argstorage[:0]
+	return v
+}
+
+// NewValue returns a new value in the block with no arguments and both an auxint and aux values.
+func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interface{}) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = auxint
+	v.Aux = aux
+	v.Args = v.argstorage[:0]
+	return v
+}
+
+// NewValue1 returns a new value in the block with one argument and zero aux values.
+func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = 0
+	v.Args = v.argstorage[:1]
+	v.argstorage[0] = arg
+	arg.Uses++
+	return v
+}
+
+// NewValue1I returns a new value in the block with one argument and an auxint value.
+func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = auxint
+	v.Args = v.argstorage[:1]
+	v.argstorage[0] = arg
+	arg.Uses++
+	return v
+}
+
+// NewValue1A returns a new value in the block with one argument and an aux value.
+func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Value) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = 0
+	v.Aux = aux
+	v.Args = v.argstorage[:1]
+	v.argstorage[0] = arg
+	arg.Uses++
+	return v
+}
+
+// NewValue1IA returns a new value in the block with one argument and both an auxint and aux values.
+func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = auxint
+	v.Aux = aux
+	v.Args = v.argstorage[:1]
+	v.argstorage[0] = arg
+	arg.Uses++
+	return v
+}
+
+// NewValue2 returns a new value in the block with two arguments and zero aux values.
+func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = 0
+	v.Args = v.argstorage[:2]
+	v.argstorage[0] = arg0
+	v.argstorage[1] = arg1
+	arg0.Uses++
+	arg1.Uses++
+	return v
+}
+
+// NewValue2I returns a new value in the block with two arguments and an auxint value.
+func (b *Block) NewValue2I(line int32, op Op, t Type, auxint int64, arg0, arg1 *Value) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = auxint
+	v.Args = v.argstorage[:2]
+	v.argstorage[0] = arg0
+	v.argstorage[1] = arg1
+	arg0.Uses++
+	arg1.Uses++
+	return v
+}
+
+// NewValue3 returns a new value in the block with three arguments and zero aux values.
+func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = 0
+	v.Args = v.argstorage[:3]
+	v.argstorage[0] = arg0
+	v.argstorage[1] = arg1
+	v.argstorage[2] = arg2
+	arg0.Uses++
+	arg1.Uses++
+	arg2.Uses++
+	return v
+}
+
+// NewValue3I returns a new value in the block with three arguments and an auxint value.
+func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
+	v := b.Func.newValue(op, t, b, line)
+	v.AuxInt = auxint
+	v.Args = v.argstorage[:3]
+	v.argstorage[0] = arg0
+	v.argstorage[1] = arg1
+	v.argstorage[2] = arg2
+	arg0.Uses++
+	arg1.Uses++
+	arg2.Uses++
+	return v
+}
+
+// constVal returns a constant value for c.
+func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value {
+	if f.constants == nil {
+		f.constants = make(map[int64][]*Value)
+	}
+	vv := f.constants[c]
+	for _, v := range vv {
+		if v.Op == op && v.Type.Compare(t) == CMPeq {
+			if setAux && v.AuxInt != c {
+				panic(fmt.Sprintf("cached const %s should have AuxInt of %d", v.LongString(), c))
+			}
+			return v
+		}
+	}
+	var v *Value
+	if setAux {
+		v = f.Entry.NewValue0I(line, op, t, c)
+	} else {
+		v = f.Entry.NewValue0(line, op, t)
+	}
+	f.constants[c] = append(vv, v)
+	return v
+}
+
+// These magic auxint values let us easily cache non-numeric constants
+// using the same constants map while making collisions unlikely.
+// These values are unlikely to occur in regular code and
+// are easy to grep for in case of bugs.
+const (
+	constSliceMagic       = 1122334455
+	constInterfaceMagic   = 2233445566
+	constNilMagic         = 3344556677
+	constEmptyStringMagic = 4455667788
+)
+
+// ConstInt returns an int constant representing its argument.
+func (f *Func) ConstBool(line int32, t Type, c bool) *Value {
+	i := int64(0)
+	if c {
+		i = 1
+	}
+	return f.constVal(line, OpConstBool, t, i, true)
+}
+func (f *Func) ConstInt8(line int32, t Type, c int8) *Value {
+	return f.constVal(line, OpConst8, t, int64(c), true)
+}
+func (f *Func) ConstInt16(line int32, t Type, c int16) *Value {
+	return f.constVal(line, OpConst16, t, int64(c), true)
+}
+func (f *Func) ConstInt32(line int32, t Type, c int32) *Value {
+	return f.constVal(line, OpConst32, t, int64(c), true)
+}
+func (f *Func) ConstInt64(line int32, t Type, c int64) *Value {
+	return f.constVal(line, OpConst64, t, c, true)
+}
+func (f *Func) ConstFloat32(line int32, t Type, c float64) *Value {
+	return f.constVal(line, OpConst32F, t, int64(math.Float64bits(float64(float32(c)))), true)
+}
+func (f *Func) ConstFloat64(line int32, t Type, c float64) *Value {
+	return f.constVal(line, OpConst64F, t, int64(math.Float64bits(c)), true)
+}
+
+func (f *Func) ConstSlice(line int32, t Type) *Value {
+	return f.constVal(line, OpConstSlice, t, constSliceMagic, false)
+}
+func (f *Func) ConstInterface(line int32, t Type) *Value {
+	return f.constVal(line, OpConstInterface, t, constInterfaceMagic, false)
+}
+func (f *Func) ConstNil(line int32, t Type) *Value {
+	return f.constVal(line, OpConstNil, t, constNilMagic, false)
+}
+func (f *Func) ConstEmptyString(line int32, t Type) *Value {
+	v := f.constVal(line, OpConstString, t, constEmptyStringMagic, false)
+	v.Aux = ""
+	return v
+}
+
+func (f *Func) Logf(msg string, args ...interface{})   { f.Config.Logf(msg, args...) }
+func (f *Func) Log() bool                              { return f.Config.Log() }
+func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry.Line, msg, args...) }
+func (f *Func) Unimplementedf(msg string, args ...interface{}) {
+	f.Config.Unimplementedf(f.Entry.Line, msg, args...)
+}
+
+func (f *Func) Free() {
+	// Clear values.
+	n := f.vid.num()
+	if n > len(f.Config.values) {
+		n = len(f.Config.values)
+	}
+	for i := 1; i < n; i++ {
+		f.Config.values[i] = Value{}
+		f.Config.values[i].ID = ID(i)
+	}
+
+	// Clear blocks.
+	n = f.bid.num()
+	if n > len(f.Config.blocks) {
+		n = len(f.Config.blocks)
+	}
+	for i := 1; i < n; i++ {
+		f.Config.blocks[i] = Block{}
+		f.Config.blocks[i].ID = ID(i)
+	}
+
+	// Unregister from config.
+	if f.Config.curFunc != f {
+		f.Fatalf("free of function which isn't the last one allocated")
+	}
+	f.Config.curFunc = nil
+	*f = Func{} // just in case
+}
diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go
new file mode 100644
index 0000000..7136d8f
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/func_test.go
@@ -0,0 +1,467 @@
+// Copyright 2015 The Go 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 some utility functions to help define Funcs for testing.
+// As an example, the following func
+//
+//   b1:
+//     v1 = InitMem <mem>
+//     Plain -> b2
+//   b2:
+//     Exit v1
+//   b3:
+//     v2 = Const <bool> [true]
+//     If v2 -> b3 b2
+//
+// can be defined as
+//
+//   fun := Fun("entry",
+//       Bloc("entry",
+//           Valu("mem", OpInitMem, TypeMem, 0, nil),
+//           Goto("exit")),
+//       Bloc("exit",
+//           Exit("mem")),
+//       Bloc("deadblock",
+//          Valu("deadval", OpConstBool, TypeBool, 0, true),
+//          If("deadval", "deadblock", "exit")))
+//
+// and the Blocks or Values used in the Func can be accessed
+// like this:
+//   fun.blocks["entry"] or fun.values["deadval"]
+
+package ssa
+
+// TODO(matloob): Choose better names for Fun, Bloc, Goto, etc.
+// TODO(matloob): Write a parser for the Func disassembly. Maybe
+//                the parser can be used instead of Fun.
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+)
+
+// Compare two Funcs for equivalence. Their CFGs must be isomorphic,
+// and their values must correspond.
+// Requires that values and predecessors are in the same order, even
+// though Funcs could be equivalent when they are not.
+// TODO(matloob): Allow values and predecessors to be in different
+// orders if the CFG are otherwise equivalent.
+func Equiv(f, g *Func) bool {
+	valcor := make(map[*Value]*Value)
+	var checkVal func(fv, gv *Value) bool
+	checkVal = func(fv, gv *Value) bool {
+		if fv == nil && gv == nil {
+			return true
+		}
+		if valcor[fv] == nil && valcor[gv] == nil {
+			valcor[fv] = gv
+			valcor[gv] = fv
+			// Ignore ids. Ops and Types are compared for equality.
+			// TODO(matloob): Make sure types are canonical and can
+			// be compared for equality.
+			if fv.Op != gv.Op || fv.Type != gv.Type || fv.AuxInt != gv.AuxInt {
+				return false
+			}
+			if !reflect.DeepEqual(fv.Aux, gv.Aux) {
+				// This makes the assumption that aux values can be compared
+				// using DeepEqual.
+				// TODO(matloob): Aux values may be *gc.Sym pointers in the near
+				// future. Make sure they are canonical.
+				return false
+			}
+			if len(fv.Args) != len(gv.Args) {
+				return false
+			}
+			for i := range fv.Args {
+				if !checkVal(fv.Args[i], gv.Args[i]) {
+					return false
+				}
+			}
+		}
+		return valcor[fv] == gv && valcor[gv] == fv
+	}
+	blkcor := make(map[*Block]*Block)
+	var checkBlk func(fb, gb *Block) bool
+	checkBlk = func(fb, gb *Block) bool {
+		if blkcor[fb] == nil && blkcor[gb] == nil {
+			blkcor[fb] = gb
+			blkcor[gb] = fb
+			// ignore ids
+			if fb.Kind != gb.Kind {
+				return false
+			}
+			if len(fb.Values) != len(gb.Values) {
+				return false
+			}
+			for i := range fb.Values {
+				if !checkVal(fb.Values[i], gb.Values[i]) {
+					return false
+				}
+			}
+			if len(fb.Succs) != len(gb.Succs) {
+				return false
+			}
+			for i := range fb.Succs {
+				if !checkBlk(fb.Succs[i].b, gb.Succs[i].b) {
+					return false
+				}
+			}
+			if len(fb.Preds) != len(gb.Preds) {
+				return false
+			}
+			for i := range fb.Preds {
+				if !checkBlk(fb.Preds[i].b, gb.Preds[i].b) {
+					return false
+				}
+			}
+			return true
+
+		}
+		return blkcor[fb] == gb && blkcor[gb] == fb
+	}
+
+	return checkBlk(f.Entry, g.Entry)
+}
+
+// fun is the return type of Fun. It contains the created func
+// itself as well as indexes from block and value names into the
+// corresponding Blocks and Values.
+type fun struct {
+	f      *Func
+	blocks map[string]*Block
+	values map[string]*Value
+}
+
+var emptyPass pass = pass{
+	name: "empty pass",
+}
+
+// Fun takes the name of an entry bloc and a series of Bloc calls, and
+// returns a fun containing the composed Func. entry must be a name
+// supplied to one of the Bloc functions. Each of the bloc names and
+// valu names should be unique across the Fun.
+func Fun(c *Config, entry string, blocs ...bloc) fun {
+	f := c.NewFunc()
+	f.pass = &emptyPass
+
+	blocks := make(map[string]*Block)
+	values := make(map[string]*Value)
+	// Create all the blocks and values.
+	for _, bloc := range blocs {
+		b := f.NewBlock(bloc.control.kind)
+		blocks[bloc.name] = b
+		for _, valu := range bloc.valus {
+			// args are filled in the second pass.
+			values[valu.name] = b.NewValue0IA(0, valu.op, valu.t, valu.auxint, valu.aux)
+		}
+	}
+	// Connect the blocks together and specify control values.
+	f.Entry = blocks[entry]
+	for _, bloc := range blocs {
+		b := blocks[bloc.name]
+		c := bloc.control
+		// Specify control values.
+		if c.control != "" {
+			cval, ok := values[c.control]
+			if !ok {
+				f.Fatalf("control value for block %s missing", bloc.name)
+			}
+			b.SetControl(cval)
+		}
+		// Fill in args.
+		for _, valu := range bloc.valus {
+			v := values[valu.name]
+			for _, arg := range valu.args {
+				a, ok := values[arg]
+				if !ok {
+					b.Fatalf("arg %s missing for value %s in block %s",
+						arg, valu.name, bloc.name)
+				}
+				v.AddArg(a)
+			}
+		}
+		// Connect to successors.
+		for _, succ := range c.succs {
+			b.AddEdgeTo(blocks[succ])
+		}
+	}
+	return fun{f, blocks, values}
+}
+
+// Bloc defines a block for Fun. The bloc name should be unique
+// across the containing Fun. entries should consist of calls to valu,
+// as well as one call to Goto, If, or Exit to specify the block kind.
+func Bloc(name string, entries ...interface{}) bloc {
+	b := bloc{}
+	b.name = name
+	seenCtrl := false
+	for _, e := range entries {
+		switch v := e.(type) {
+		case ctrl:
+			// there should be exactly one Ctrl entry.
+			if seenCtrl {
+				panic(fmt.Sprintf("already seen control for block %s", name))
+			}
+			b.control = v
+			seenCtrl = true
+		case valu:
+			b.valus = append(b.valus, v)
+		}
+	}
+	if !seenCtrl {
+		panic(fmt.Sprintf("block %s doesn't have control", b.name))
+	}
+	return b
+}
+
+// Valu defines a value in a block.
+func Valu(name string, op Op, t Type, auxint int64, aux interface{}, args ...string) valu {
+	return valu{name, op, t, auxint, aux, args}
+}
+
+// Goto specifies that this is a BlockPlain and names the single successor.
+// TODO(matloob): choose a better name.
+func Goto(succ string) ctrl {
+	return ctrl{BlockPlain, "", []string{succ}}
+}
+
+// If specifies a BlockIf.
+func If(cond, sub, alt string) ctrl {
+	return ctrl{BlockIf, cond, []string{sub, alt}}
+}
+
+// Exit specifies a BlockExit.
+func Exit(arg string) ctrl {
+	return ctrl{BlockExit, arg, []string{}}
+}
+
+// Eq specifies a BlockAMD64EQ.
+func Eq(cond, sub, alt string) ctrl {
+	return ctrl{BlockAMD64EQ, cond, []string{sub, alt}}
+}
+
+// bloc, ctrl, and valu are internal structures used by Bloc, Valu, Goto,
+// If, and Exit to help define blocks.
+
+type bloc struct {
+	name    string
+	control ctrl
+	valus   []valu
+}
+
+type ctrl struct {
+	kind    BlockKind
+	control string
+	succs   []string
+}
+
+type valu struct {
+	name   string
+	op     Op
+	t      Type
+	auxint int64
+	aux    interface{}
+	args   []string
+}
+
+func TestArgs(t *testing.T) {
+	c := testConfig(t)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("a", OpConst64, TypeInt64, 14, nil),
+			Valu("b", OpConst64, TypeInt64, 26, nil),
+			Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+	sum := fun.values["sum"]
+	for i, name := range []string{"a", "b"} {
+		if sum.Args[i] != fun.values[name] {
+			t.Errorf("arg %d for sum is incorrect: want %s, got %s",
+				i, sum.Args[i], fun.values[name])
+		}
+	}
+}
+
+func TestEquiv(t *testing.T) {
+	equivalentCases := []struct{ f, g fun }{
+		// simple case
+		{
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Valu("b", OpConst64, TypeInt64, 26, nil),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Goto("exit")),
+				Bloc("exit",
+					Exit("mem"))),
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Valu("b", OpConst64, TypeInt64, 26, nil),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Goto("exit")),
+				Bloc("exit",
+					Exit("mem"))),
+		},
+		// block order changed
+		{
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Valu("b", OpConst64, TypeInt64, 26, nil),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Goto("exit")),
+				Bloc("exit",
+					Exit("mem"))),
+			Fun(testConfig(t), "entry",
+				Bloc("exit",
+					Exit("mem")),
+				Bloc("entry",
+					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Valu("b", OpConst64, TypeInt64, 26, nil),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Goto("exit"))),
+		},
+	}
+	for _, c := range equivalentCases {
+		if !Equiv(c.f.f, c.g.f) {
+			t.Error("expected equivalence. Func definitions:")
+			t.Error(c.f.f)
+			t.Error(c.g.f)
+		}
+	}
+
+	differentCases := []struct{ f, g fun }{
+		// different shape
+		{
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Goto("exit")),
+				Bloc("exit",
+					Exit("mem"))),
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Exit("mem"))),
+		},
+		// value order changed
+		{
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("b", OpConst64, TypeInt64, 26, nil),
+					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Exit("mem"))),
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Valu("b", OpConst64, TypeInt64, 26, nil),
+					Exit("mem"))),
+		},
+		// value auxint different
+		{
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Exit("mem"))),
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("a", OpConst64, TypeInt64, 26, nil),
+					Exit("mem"))),
+		},
+		// value aux different
+		{
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("a", OpConst64, TypeInt64, 0, 14),
+					Exit("mem"))),
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("a", OpConst64, TypeInt64, 0, 26),
+					Exit("mem"))),
+		},
+		// value args different
+		{
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("a", OpConst64, TypeInt64, 14, nil),
+					Valu("b", OpConst64, TypeInt64, 26, nil),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
+					Exit("mem"))),
+			Fun(testConfig(t), "entry",
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("a", OpConst64, TypeInt64, 0, nil),
+					Valu("b", OpConst64, TypeInt64, 14, nil),
+					Valu("sum", OpAdd64, TypeInt64, 0, nil, "b", "a"),
+					Exit("mem"))),
+		},
+	}
+	for _, c := range differentCases {
+		if Equiv(c.f.f, c.g.f) {
+			t.Error("expected difference. Func definitions:")
+			t.Error(c.f.f)
+			t.Error(c.g.f)
+		}
+	}
+}
+
+// TestConstCache ensures that the cache will not return
+// reused free'd values with a non-matching AuxInt
+func TestConstCache(t *testing.T) {
+	f := Fun(testConfig(t), "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Exit("mem")))
+	v1 := f.f.ConstBool(0, TypeBool, false)
+	v2 := f.f.ConstBool(0, TypeBool, true)
+	f.f.freeValue(v1)
+	f.f.freeValue(v2)
+	v3 := f.f.ConstBool(0, TypeBool, false)
+	v4 := f.f.ConstBool(0, TypeBool, true)
+	if v3.AuxInt != 0 {
+		t.Errorf("expected %s to have auxint of 0\n", v3.LongString())
+	}
+	if v4.AuxInt != 1 {
+		t.Errorf("expected %s to have auxint of 1\n", v4.LongString())
+	}
+
+}
+
+// opcodeMap returns a map from opcode to the number of times that opcode
+// appears in the function.
+func opcodeMap(f *Func) map[Op]int {
+	m := map[Op]int{}
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			m[v.Op]++
+		}
+	}
+	return m
+}
+
+// opcodeCounts checks that the number of opcodes listed in m agree with the
+// number of opcodes that appear in the function.
+func checkOpcodeCounts(t *testing.T, f *Func, m map[Op]int) {
+	n := opcodeMap(f)
+	for op, cnt := range m {
+		if n[op] != cnt {
+			t.Errorf("%s appears %d times, want %d times", op, n[op], cnt)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go
new file mode 100644
index 0000000..afb8bb2
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/fuse.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 ssa
+
+// fuse simplifies control flow by joining basic blocks.
+func fuse(f *Func) {
+	for changed := true; changed; {
+		changed = false
+		for _, b := range f.Blocks {
+			changed = fuseBlockIf(b) || changed
+			changed = fuseBlockPlain(b) || changed
+		}
+	}
+}
+
+// fuseBlockIf handles the following cases where s0 and s1 are empty blocks.
+//
+//   b        b        b      b
+//  / \      | \      / |    | |
+// s0  s1    |  s1   s0 |    | |
+//  \ /      | /      \ |    | |
+//   ss      ss        ss     ss
+//
+// If all Phi ops in ss have identical variables for slots corresponding to
+// s0, s1 and b then the branch can be dropped.
+// This optimization often comes up in switch statements with multiple
+// expressions in a case clause:
+//   switch n {
+//     case 1,2,3: return 4
+//   }
+// TODO: If ss doesn't contain any OpPhis, are s0 and s1 dead code anyway.
+func fuseBlockIf(b *Block) bool {
+	if b.Kind != BlockIf {
+		return false
+	}
+
+	var ss0, ss1 *Block
+	s0 := b.Succs[0].b
+	i0 := b.Succs[0].i
+	if s0.Kind != BlockPlain || len(s0.Preds) != 1 || len(s0.Values) != 0 {
+		s0, ss0 = b, s0
+	} else {
+		ss0 = s0.Succs[0].b
+		i0 = s0.Succs[0].i
+	}
+	s1 := b.Succs[1].b
+	i1 := b.Succs[1].i
+	if s1.Kind != BlockPlain || len(s1.Preds) != 1 || len(s1.Values) != 0 {
+		s1, ss1 = b, s1
+	} else {
+		ss1 = s1.Succs[0].b
+		i1 = s1.Succs[0].i
+	}
+
+	if ss0 != ss1 {
+		return false
+	}
+	ss := ss0
+
+	// s0 and s1 are equal with b if the corresponding block is missing
+	// (2nd, 3rd and 4th case in the figure).
+
+	for _, v := range ss.Values {
+		if v.Op == OpPhi && v.Uses > 0 && v.Args[i0] != v.Args[i1] {
+			return false
+		}
+	}
+
+	// Now we have two of following b->ss, b->s0->ss and b->s1->ss,
+	// with s0 and s1 empty if exist.
+	// We can replace it with b->ss without if all OpPhis in ss
+	// have identical predecessors (verified above).
+	// No critical edge is introduced because b will have one successor.
+	if s0 != b && s1 != b {
+		// Replace edge b->s0->ss with b->ss.
+		// We need to keep a slot for Phis corresponding to b.
+		b.Succs[0] = Edge{ss, i0}
+		ss.Preds[i0] = Edge{b, 0}
+		b.removeEdge(1)
+		s1.removeEdge(0)
+	} else if s0 != b {
+		b.removeEdge(0)
+		s0.removeEdge(0)
+	} else if s1 != b {
+		b.removeEdge(1)
+		s1.removeEdge(0)
+	} else {
+		b.removeEdge(1)
+	}
+	b.Kind = BlockPlain
+	b.SetControl(nil)
+
+	// Trash the empty blocks s0 & s1.
+	if s0 != b {
+		s0.Kind = BlockInvalid
+		s0.Values = nil
+		s0.Succs = nil
+		s0.Preds = nil
+	}
+	if s1 != b {
+		s1.Kind = BlockInvalid
+		s1.Values = nil
+		s1.Succs = nil
+		s1.Preds = nil
+	}
+	return true
+}
+
+func fuseBlockPlain(b *Block) bool {
+	if b.Kind != BlockPlain {
+		return false
+	}
+
+	c := b.Succs[0].b
+	if len(c.Preds) != 1 {
+		return false
+	}
+
+	// move all of b's values to c.
+	for _, v := range b.Values {
+		v.Block = c
+		c.Values = append(c.Values, v)
+	}
+
+	// replace b->c edge with preds(b) -> c
+	c.predstorage[0] = Edge{}
+	if len(b.Preds) > len(b.predstorage) {
+		c.Preds = b.Preds
+	} else {
+		c.Preds = append(c.predstorage[:0], b.Preds...)
+	}
+	for i, e := range c.Preds {
+		p := e.b
+		p.Succs[e.i] = Edge{c, i}
+	}
+	if f := b.Func; f.Entry == b {
+		f.Entry = c
+	}
+
+	// trash b, just in case
+	b.Kind = BlockInvalid
+	b.Values = nil
+	b.Preds = nil
+	b.Succs = nil
+	return true
+}
diff --git a/src/cmd/compile/internal/ssa/fuse_test.go b/src/cmd/compile/internal/ssa/fuse_test.go
new file mode 100644
index 0000000..b316a48
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/fuse_test.go
@@ -0,0 +1,169 @@
+package ssa
+
+import (
+	"fmt"
+	"strconv"
+	"testing"
+)
+
+func TestFuseEliminatesOneBranch(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("nilptr", OpConstNil, ptrType, 0, nil),
+			Valu("bool1", OpNeqPtr, TypeBool, 0, nil, "ptr1", "nilptr"),
+			If("bool1", "then", "exit")),
+		Bloc("then",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	fuse(fun.f)
+
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["then"] && b.Kind != BlockInvalid {
+			t.Errorf("then was not eliminated, but should have")
+		}
+	}
+}
+
+func TestFuseEliminatesBothBranches(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("nilptr", OpConstNil, ptrType, 0, nil),
+			Valu("bool1", OpNeqPtr, TypeBool, 0, nil, "ptr1", "nilptr"),
+			If("bool1", "then", "else")),
+		Bloc("then",
+			Goto("exit")),
+		Bloc("else",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	fuse(fun.f)
+
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["then"] && b.Kind != BlockInvalid {
+			t.Errorf("then was not eliminated, but should have")
+		}
+		if b == fun.blocks["else"] && b.Kind != BlockInvalid {
+			t.Errorf("then was not eliminated, but should have")
+		}
+	}
+}
+
+func TestFuseHandlesPhis(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("nilptr", OpConstNil, ptrType, 0, nil),
+			Valu("bool1", OpNeqPtr, TypeBool, 0, nil, "ptr1", "nilptr"),
+			If("bool1", "then", "else")),
+		Bloc("then",
+			Goto("exit")),
+		Bloc("else",
+			Goto("exit")),
+		Bloc("exit",
+			Valu("phi", OpPhi, ptrType, 0, nil, "ptr1", "ptr1"),
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	fuse(fun.f)
+
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["then"] && b.Kind != BlockInvalid {
+			t.Errorf("then was not eliminated, but should have")
+		}
+		if b == fun.blocks["else"] && b.Kind != BlockInvalid {
+			t.Errorf("then was not eliminated, but should have")
+		}
+	}
+}
+
+func TestFuseEliminatesEmptyBlocks(t *testing.T) {
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("z0")),
+		Bloc("z1",
+			Goto("z2")),
+		Bloc("z3",
+			Goto("exit")),
+		Bloc("z2",
+			Goto("z3")),
+		Bloc("z0",
+			Goto("z1")),
+		Bloc("exit",
+			Exit("mem"),
+		))
+
+	CheckFunc(fun.f)
+	fuse(fun.f)
+
+	for k, b := range fun.blocks {
+		if k[:1] == "z" && b.Kind != BlockInvalid {
+			t.Errorf("%s was not eliminated, but should have", k)
+		}
+	}
+}
+
+func BenchmarkFuse(b *testing.B) {
+	for _, n := range [...]int{1, 10, 100, 1000, 10000} {
+		b.Run(strconv.Itoa(n), func(b *testing.B) {
+			c := testConfig(b)
+
+			blocks := make([]bloc, 0, 2*n+3)
+			blocks = append(blocks,
+				Bloc("entry",
+					Valu("mem", OpInitMem, TypeMem, 0, nil),
+					Valu("cond", OpArg, TypeBool, 0, nil),
+					Valu("x", OpArg, TypeInt64, 0, nil),
+					Goto("exit")))
+
+			phiArgs := make([]string, 0, 2*n)
+			for i := 0; i < n; i++ {
+				cname := fmt.Sprintf("c%d", i)
+				blocks = append(blocks,
+					Bloc(fmt.Sprintf("b%d", i), If("cond", cname, "merge")),
+					Bloc(cname, Goto("merge")))
+				phiArgs = append(phiArgs, "x", "x")
+			}
+			blocks = append(blocks,
+				Bloc("merge",
+					Valu("phi", OpPhi, TypeMem, 0, nil, phiArgs...),
+					Goto("exit")),
+				Bloc("exit",
+					Exit("mem")))
+
+			b.ResetTimer()
+			for i := 0; i < b.N; i++ {
+				fun := Fun(c, "entry", blocks...)
+				fuse(fun.f)
+				fun.f.Free()
+			}
+		})
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
new file mode 100644
index 0000000..db274d7
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -0,0 +1,1566 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Lowering arithmetic
+(Add64  x y) -> (ADDQ  x y)
+(AddPtr x y) -> (ADDQ  x y)
+(Add32  x y) -> (ADDL  x y)
+(Add16  x y) -> (ADDL  x y)
+(Add8   x y) -> (ADDL  x y)
+(Add32F x y) -> (ADDSS x y)
+(Add64F x y) -> (ADDSD x y)
+
+(Sub64  x y) -> (SUBQ  x y)
+(SubPtr x y) -> (SUBQ  x y)
+(Sub32  x y) -> (SUBL  x y)
+(Sub16  x y) -> (SUBL  x y)
+(Sub8   x y) -> (SUBL  x y)
+(Sub32F x y) -> (SUBSS x y)
+(Sub64F x y) -> (SUBSD x y)
+
+(Mul64  x y) -> (MULQ  x y)
+(Mul32  x y) -> (MULL  x y)
+(Mul16  x y) -> (MULL  x y)
+(Mul8   x y) -> (MULL  x y)
+(Mul32F x y) -> (MULSS x y)
+(Mul64F x y) -> (MULSD x y)
+
+(Div32F x y) -> (DIVSS x y)
+(Div64F x y) -> (DIVSD x y)
+
+(Div64  x y) -> (DIVQ  x y)
+(Div64u x y) -> (DIVQU x y)
+(Div32  x y) -> (DIVL  x y)
+(Div32u x y) -> (DIVLU x y)
+(Div16  x y) -> (DIVW  x y)
+(Div16u x y) -> (DIVWU x y)
+(Div8   x y) -> (DIVW  (SignExt8to16 x) (SignExt8to16 y))
+(Div8u  x y) -> (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+
+(Hmul64  x y) -> (HMULQ  x y)
+(Hmul64u x y) -> (HMULQU x y)
+(Hmul32  x y) -> (HMULL  x y)
+(Hmul32u x y) -> (HMULLU x y)
+(Hmul16  x y) -> (HMULW  x y)
+(Hmul16u x y) -> (HMULWU x y)
+(Hmul8   x y) -> (HMULB  x y)
+(Hmul8u  x y) -> (HMULBU x y)
+
+(Avg64u x y) -> (AVGQU x y)
+
+(Mod64  x y) -> (MODQ  x y)
+(Mod64u x y) -> (MODQU x y)
+(Mod32  x y) -> (MODL  x y)
+(Mod32u x y) -> (MODLU x y)
+(Mod16  x y) -> (MODW  x y)
+(Mod16u x y) -> (MODWU x y)
+(Mod8   x y) -> (MODW  (SignExt8to16 x) (SignExt8to16 y))
+(Mod8u  x y) -> (MODWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+
+(And64 x y) -> (ANDQ x y)
+(And32 x y) -> (ANDL x y)
+(And16 x y) -> (ANDL x y)
+(And8  x y) -> (ANDL x y)
+
+(Or64 x y) -> (ORQ x y)
+(Or32 x y) -> (ORL x y)
+(Or16 x y) -> (ORL x y)
+(Or8  x y) -> (ORL x y)
+
+(Xor64 x y) -> (XORQ x y)
+(Xor32 x y) -> (XORL x y)
+(Xor16 x y) -> (XORL x y)
+(Xor8  x y) -> (XORL x y)
+
+(Neg64  x) -> (NEGQ x)
+(Neg32  x) -> (NEGL x)
+(Neg16  x) -> (NEGL x)
+(Neg8   x) -> (NEGL x)
+(Neg32F x) -> (PXOR x (MOVSSconst <config.Frontend().TypeFloat32()> [f2i(math.Copysign(0, -1))]))
+(Neg64F x) -> (PXOR x (MOVSDconst <config.Frontend().TypeFloat64()> [f2i(math.Copysign(0, -1))]))
+
+(Com64 x) -> (NOTQ x)
+(Com32 x) -> (NOTL x)
+(Com16 x) -> (NOTL x)
+(Com8  x) -> (NOTL x)
+
+// Lowering boolean ops
+(AndB x y) -> (ANDL x y)
+(OrB x y) -> (ORL x y)
+(Not x) -> (XORLconst [1] x)
+
+// Lowering pointer arithmetic
+(OffPtr [off] ptr) && is32Bit(off) -> (ADDQconst [off] ptr)
+(OffPtr [off] ptr) -> (ADDQ (MOVQconst [off]) ptr)
+
+// Lowering other arithmetic
+// TODO: CMPQconst 0 below is redundant because BSF sets Z but how to remove?
+(Ctz64 <t> x) -> (CMOVQEQconst (BSFQ <t> x) (CMPQconst x [0]) [64])
+(Ctz32 <t> x) -> (CMOVLEQconst (BSFL <t> x) (CMPLconst x [0]) [32])
+(Ctz16 <t> x) -> (CMOVWEQconst (BSFW <t> x) (CMPWconst x [0]) [16])
+
+(Bswap64 x) -> (BSWAPQ x)
+(Bswap32 x) -> (BSWAPL x)
+
+(Sqrt x) -> (SQRTSD x)
+
+// Lowering extension
+// Note: we always extend to 64 bits even though some ops don't need that many result bits.
+(SignExt8to16  x) -> (MOVBQSX x)
+(SignExt8to32  x) -> (MOVBQSX x)
+(SignExt8to64  x) -> (MOVBQSX x)
+(SignExt16to32 x) -> (MOVWQSX x)
+(SignExt16to64 x) -> (MOVWQSX x)
+(SignExt32to64 x) -> (MOVLQSX x)
+
+(ZeroExt8to16  x) -> (MOVBQZX x)
+(ZeroExt8to32  x) -> (MOVBQZX x)
+(ZeroExt8to64  x) -> (MOVBQZX x)
+(ZeroExt16to32 x) -> (MOVWQZX x)
+(ZeroExt16to64 x) -> (MOVWQZX x)
+(ZeroExt32to64 x) -> (MOVLQZX x)
+
+// Lowering truncation
+// Because we ignore high parts of registers, truncates are just copies.
+(Trunc16to8  x) -> x
+(Trunc32to8  x) -> x
+(Trunc32to16 x) -> x
+(Trunc64to8  x) -> x
+(Trunc64to16 x) -> x
+(Trunc64to32 x) -> x
+
+// Lowering float <-> int
+(Cvt32to32F x) -> (CVTSL2SS x)
+(Cvt32to64F x) -> (CVTSL2SD x)
+(Cvt64to32F x) -> (CVTSQ2SS x)
+(Cvt64to64F x) -> (CVTSQ2SD x)
+
+(Cvt32Fto32 x) -> (CVTTSS2SL x)
+(Cvt32Fto64 x) -> (CVTTSS2SQ x)
+(Cvt64Fto32 x) -> (CVTTSD2SL x)
+(Cvt64Fto64 x) -> (CVTTSD2SQ x)
+
+(Cvt32Fto64F x) -> (CVTSS2SD x)
+(Cvt64Fto32F x) -> (CVTSD2SS x)
+
+// Lowering shifts
+// Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
+//   result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff)
+(Lsh64x64 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
+(Lsh64x32 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
+(Lsh64x16 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
+(Lsh64x8  <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPBconst y [64])))
+
+(Lsh32x64 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+(Lsh32x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+(Lsh32x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+(Lsh32x8  <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+
+(Lsh16x64 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+(Lsh16x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+(Lsh16x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+(Lsh16x8  <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+
+(Lsh8x64 <t> x y)  -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+(Lsh8x32 <t> x y)  -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+(Lsh8x16 <t> x y)  -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+(Lsh8x8  <t> x y)  -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+
+(Lrot64 <t> x [c]) -> (ROLQconst <t> [c&63] x)
+(Lrot32 <t> x [c]) -> (ROLLconst <t> [c&31] x)
+(Lrot16 <t> x [c]) -> (ROLWconst <t> [c&15] x)
+(Lrot8  <t> x [c]) -> (ROLBconst <t> [c&7] x)
+
+(Rsh64Ux64 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
+(Rsh64Ux32 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
+(Rsh64Ux16 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
+(Rsh64Ux8  <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPBconst y [64])))
+
+(Rsh32Ux64 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+(Rsh32Ux32 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+(Rsh32Ux16 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+(Rsh32Ux8  <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+
+(Rsh16Ux64 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
+(Rsh16Ux32 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
+(Rsh16Ux16 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
+(Rsh16Ux8  <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
+
+(Rsh8Ux64 <t> x y)  -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
+(Rsh8Ux32 <t> x y)  -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
+(Rsh8Ux16 <t> x y)  -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
+(Rsh8Ux8  <t> x y)  -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
+
+// Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
+// We implement this by setting the shift value to -1 (all ones) if the shift value is >= width.
+(Rsh64x64 <t> x y) -> (SARQ <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [64])))))
+(Rsh64x32 <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [64])))))
+(Rsh64x16 <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [64])))))
+(Rsh64x8  <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [64])))))
+
+(Rsh32x64 <t> x y) -> (SARL <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [32])))))
+(Rsh32x32 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [32])))))
+(Rsh32x16 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
+(Rsh32x8  <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
+
+(Rsh16x64 <t> x y) -> (SARW <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [16])))))
+(Rsh16x32 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [16])))))
+(Rsh16x16 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
+(Rsh16x8  <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
+
+(Rsh8x64 <t> x y)  -> (SARB <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [8])))))
+(Rsh8x32 <t> x y)  -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [8])))))
+(Rsh8x16 <t> x y)  -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
+(Rsh8x8  <t> x y)  -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
+
+// Lowering comparisons
+(Less64  x y) -> (SETL (CMPQ x y))
+(Less32  x y) -> (SETL (CMPL x y))
+(Less16  x y) -> (SETL (CMPW x y))
+(Less8   x y) -> (SETL (CMPB x y))
+(Less64U x y) -> (SETB (CMPQ x y))
+(Less32U x y) -> (SETB (CMPL x y))
+(Less16U x y) -> (SETB (CMPW x y))
+(Less8U  x y) -> (SETB (CMPB x y))
+// Use SETGF with reversed operands to dodge NaN case
+(Less64F x y) -> (SETGF (UCOMISD y x))
+(Less32F x y) -> (SETGF (UCOMISS y x))
+
+(Leq64  x y) -> (SETLE (CMPQ x y))
+(Leq32  x y) -> (SETLE (CMPL x y))
+(Leq16  x y) -> (SETLE (CMPW x y))
+(Leq8   x y) -> (SETLE (CMPB x y))
+(Leq64U x y) -> (SETBE (CMPQ x y))
+(Leq32U x y) -> (SETBE (CMPL x y))
+(Leq16U x y) -> (SETBE (CMPW x y))
+(Leq8U  x y) -> (SETBE (CMPB x y))
+// Use SETGEF with reversed operands to dodge NaN case
+(Leq64F x y) -> (SETGEF (UCOMISD y x))
+(Leq32F x y) -> (SETGEF (UCOMISS y x))
+
+(Greater64  x y) -> (SETG (CMPQ x y))
+(Greater32  x y) -> (SETG (CMPL x y))
+(Greater16  x y) -> (SETG (CMPW x y))
+(Greater8   x y) -> (SETG (CMPB x y))
+(Greater64U x y) -> (SETA (CMPQ x y))
+(Greater32U x y) -> (SETA (CMPL x y))
+(Greater16U x y) -> (SETA (CMPW x y))
+(Greater8U  x y) -> (SETA (CMPB x y))
+// Note Go assembler gets UCOMISx operand order wrong, but it is right here
+// Bug is accommodated at generation of assembly language.
+(Greater64F x y) -> (SETGF (UCOMISD x y))
+(Greater32F x y) -> (SETGF (UCOMISS x y))
+
+(Geq64  x y) -> (SETGE (CMPQ x y))
+(Geq32  x y) -> (SETGE (CMPL x y))
+(Geq16  x y) -> (SETGE (CMPW x y))
+(Geq8   x y) -> (SETGE (CMPB x y))
+(Geq64U x y) -> (SETAE (CMPQ x y))
+(Geq32U x y) -> (SETAE (CMPL x y))
+(Geq16U x y) -> (SETAE (CMPW x y))
+(Geq8U  x y) -> (SETAE (CMPB x y))
+// Note Go assembler gets UCOMISx operand order wrong, but it is right here
+// Bug is accommodated at generation of assembly language.
+(Geq64F x y) -> (SETGEF (UCOMISD x y))
+(Geq32F x y) -> (SETGEF (UCOMISS x y))
+
+(Eq64  x y) -> (SETEQ (CMPQ x y))
+(Eq32  x y) -> (SETEQ (CMPL x y))
+(Eq16  x y) -> (SETEQ (CMPW x y))
+(Eq8   x y) -> (SETEQ (CMPB x y))
+(EqB   x y) -> (SETEQ (CMPB x y))
+(EqPtr x y) -> (SETEQ (CMPQ x y))
+(Eq64F x y) -> (SETEQF (UCOMISD x y))
+(Eq32F x y) -> (SETEQF (UCOMISS x y))
+
+(Neq64  x y) -> (SETNE (CMPQ x y))
+(Neq32  x y) -> (SETNE (CMPL x y))
+(Neq16  x y) -> (SETNE (CMPW x y))
+(Neq8   x y) -> (SETNE (CMPB x y))
+(NeqB   x y) -> (SETNE (CMPB x y))
+(NeqPtr x y) -> (SETNE (CMPQ x y))
+(Neq64F x y) -> (SETNEF (UCOMISD x y))
+(Neq32F x y) -> (SETNEF (UCOMISS x y))
+
+// Lowering loads
+(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVQload ptr mem)
+(Load <t> ptr mem) && is32BitInt(t) -> (MOVLload ptr mem)
+(Load <t> ptr mem) && is16BitInt(t) -> (MOVWload ptr mem)
+(Load <t> ptr mem) && (t.IsBoolean() || is8BitInt(t)) -> (MOVBload ptr mem)
+(Load <t> ptr mem) && is32BitFloat(t) -> (MOVSSload ptr mem)
+(Load <t> ptr mem) && is64BitFloat(t) -> (MOVSDload ptr mem)
+
+// Lowering stores
+// These more-specific FP versions of Store pattern should come first.
+(Store [8] ptr val mem) && is64BitFloat(val.Type) -> (MOVSDstore ptr val mem)
+(Store [4] ptr val mem) && is32BitFloat(val.Type) -> (MOVSSstore ptr val mem)
+
+(Store [8] ptr val mem) -> (MOVQstore ptr val mem)
+(Store [4] ptr val mem) -> (MOVLstore ptr val mem)
+(Store [2] ptr val mem) -> (MOVWstore ptr val mem)
+(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
+
+// Lowering moves
+(Move [0] _ _ mem) -> mem
+(Move [1] dst src mem) -> (MOVBstore dst (MOVBload src mem) mem)
+(Move [2] dst src mem) -> (MOVWstore dst (MOVWload src mem) mem)
+(Move [4] dst src mem) -> (MOVLstore dst (MOVLload src mem) mem)
+(Move [8] dst src mem) -> (MOVQstore dst (MOVQload src mem) mem)
+(Move [16] dst src mem) -> (MOVOstore dst (MOVOload src mem) mem)
+(Move [3] dst src mem) ->
+	(MOVBstore [2] dst (MOVBload [2] src mem)
+		(MOVWstore dst (MOVWload src mem) mem))
+(Move [5] dst src mem) ->
+	(MOVBstore [4] dst (MOVBload [4] src mem)
+		(MOVLstore dst (MOVLload src mem) mem))
+(Move [6] dst src mem) ->
+	(MOVWstore [4] dst (MOVWload [4] src mem)
+		(MOVLstore dst (MOVLload src mem) mem))
+(Move [7] dst src mem) ->
+	(MOVLstore [3] dst (MOVLload [3] src mem)
+		(MOVLstore dst (MOVLload src mem) mem))
+(Move [size] dst src mem) && size > 8 && size < 16 ->
+	(MOVQstore [size-8] dst (MOVQload [size-8] src mem)
+		(MOVQstore dst (MOVQload src mem) mem))
+
+// Adjust moves to be a multiple of 16 bytes.
+(Move [size] dst src mem) && size > 16 && size%16 != 0 && size%16 <= 8 ->
+	(Move [size-size%16] (ADDQconst <dst.Type> dst [size%16]) (ADDQconst <src.Type> src [size%16])
+		(MOVQstore dst (MOVQload src mem) mem))
+(Move [size] dst src mem) && size > 16 && size%16 != 0 && size%16 > 8 ->
+	(Move [size-size%16] (ADDQconst <dst.Type> dst [size%16]) (ADDQconst <src.Type> src [size%16])
+		(MOVOstore dst (MOVOload src mem) mem))
+
+// Medium copying uses a duff device.
+(Move [size] dst src mem) && size >= 32 && size <= 16*64 && size%16 == 0 && !config.noDuffDevice ->
+	(DUFFCOPY [14*(64-size/16)] dst src mem)
+// 14 and 64 are magic constants.  14 is the number of bytes to encode:
+//	MOVUPS	(SI), X0
+//	ADDQ	$16, SI
+//	MOVUPS	X0, (DI)
+//	ADDQ	$16, DI
+// and 64 is the number of such blocks. See src/runtime/duff_amd64.s:duffcopy.
+
+// Large copying uses REP MOVSQ.
+(Move [size] dst src mem) && (size > 16*64 || config.noDuffDevice) && size%8 == 0 ->
+	(REPMOVSQ dst src (MOVQconst [size/8]) mem)
+
+// Lowering Zero instructions
+(Zero [0] _ mem) -> mem
+(Zero [1] destptr mem) -> (MOVBstoreconst [0] destptr mem)
+(Zero [2] destptr mem) -> (MOVWstoreconst [0] destptr mem)
+(Zero [4] destptr mem) -> (MOVLstoreconst [0] destptr mem)
+(Zero [8] destptr mem) -> (MOVQstoreconst [0] destptr mem)
+
+(Zero [3] destptr mem) ->
+	(MOVBstoreconst [makeValAndOff(0,2)] destptr
+		(MOVWstoreconst [0] destptr mem))
+(Zero [5] destptr mem) ->
+	(MOVBstoreconst [makeValAndOff(0,4)] destptr
+		(MOVLstoreconst [0] destptr mem))
+(Zero [6] destptr mem) ->
+	(MOVWstoreconst [makeValAndOff(0,4)] destptr
+		(MOVLstoreconst [0] destptr mem))
+(Zero [7] destptr mem) ->
+	(MOVLstoreconst [makeValAndOff(0,3)] destptr
+		(MOVLstoreconst [0] destptr mem))
+
+// Strip off any fractional word zeroing.
+(Zero [size] destptr mem) && size%8 != 0 && size > 8 ->
+	(Zero [size-size%8] (ADDQconst destptr [size%8])
+		(MOVQstoreconst [0] destptr mem))
+
+// Zero small numbers of words directly.
+(Zero [16] destptr mem) ->
+	(MOVQstoreconst [makeValAndOff(0,8)] destptr
+		(MOVQstoreconst [0] destptr mem))
+(Zero [24] destptr mem) ->
+	(MOVQstoreconst [makeValAndOff(0,16)] destptr
+		(MOVQstoreconst [makeValAndOff(0,8)] destptr
+			(MOVQstoreconst [0] destptr mem)))
+(Zero [32] destptr mem) ->
+	(MOVQstoreconst [makeValAndOff(0,24)] destptr
+		(MOVQstoreconst [makeValAndOff(0,16)] destptr
+			(MOVQstoreconst [makeValAndOff(0,8)] destptr
+				(MOVQstoreconst [0] destptr mem))))
+
+// Medium zeroing uses a duff device.
+(Zero [size] destptr mem) && size <= 1024 && size%8 == 0 && size%16 != 0 && !config.noDuffDevice ->
+	(Zero [size-8] (ADDQconst [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
+(Zero [size] destptr mem) && size <= 1024 && size%16 == 0 && !config.noDuffDevice ->
+	(DUFFZERO [duffStart(size)] (ADDQconst [duffAdj(size)] destptr) (MOVOconst [0]) mem)
+
+// Large zeroing uses REP STOSQ.
+(Zero [size] destptr mem) && (size > 1024 || (config.noDuffDevice && size > 32)) && size%8 == 0 ->
+	(REPSTOSQ destptr (MOVQconst [size/8]) (MOVQconst [0]) mem)
+
+// Lowering constants
+(Const8   [val]) -> (MOVLconst [val])
+(Const16  [val]) -> (MOVLconst [val])
+(Const32  [val]) -> (MOVLconst [val])
+(Const64  [val]) -> (MOVQconst [val])
+(Const32F [val]) -> (MOVSSconst [val])
+(Const64F [val]) -> (MOVSDconst [val])
+(ConstNil) -> (MOVQconst [0])
+(ConstBool [b]) -> (MOVLconst [b])
+
+// Lowering calls
+(StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
+(ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem)
+(DeferCall [argwid] mem) -> (CALLdefer [argwid] mem)
+(GoCall [argwid] mem) -> (CALLgo [argwid] mem)
+(InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem)
+
+// Miscellaneous
+(Convert <t> x mem) -> (MOVQconvert <t> x mem)
+(IsNonNil p) -> (SETNE (TESTQ p p))
+(IsInBounds idx len) -> (SETB (CMPQ idx len))
+(IsSliceInBounds idx len) -> (SETBE (CMPQ idx len))
+(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
+(GetG mem) -> (LoweredGetG mem)
+(GetClosurePtr) -> (LoweredGetClosurePtr)
+(Addr {sym} base) -> (LEAQ {sym} base)
+(ITab (Load ptr mem)) -> (MOVQload ptr mem)
+
+// block rewrites
+(If (SETL  cmp) yes no) -> (LT  cmp yes no)
+(If (SETLE cmp) yes no) -> (LE  cmp yes no)
+(If (SETG  cmp) yes no) -> (GT  cmp yes no)
+(If (SETGE cmp) yes no) -> (GE  cmp yes no)
+(If (SETEQ cmp) yes no) -> (EQ  cmp yes no)
+(If (SETNE cmp) yes no) -> (NE  cmp yes no)
+(If (SETB  cmp) yes no) -> (ULT cmp yes no)
+(If (SETBE cmp) yes no) -> (ULE cmp yes no)
+(If (SETA  cmp) yes no) -> (UGT cmp yes no)
+(If (SETAE cmp) yes no) -> (UGE cmp yes no)
+
+// Special case for floating point - LF/LEF not generated
+(If (SETGF  cmp) yes no) -> (UGT  cmp yes no)
+(If (SETGEF cmp) yes no) -> (UGE  cmp yes no)
+(If (SETEQF cmp) yes no) -> (EQF  cmp yes no)
+(If (SETNEF cmp) yes no) -> (NEF  cmp yes no)
+
+(If cond yes no) -> (NE (TESTB cond cond) yes no)
+
+// ***************************
+// Above: lowering rules
+// Below: optimizations
+// ***************************
+// TODO: Should the optimizations be a separate pass?
+
+// Fold boolean tests into blocks
+(NE (TESTB (SETL  cmp) (SETL  cmp)) yes no) -> (LT  cmp yes no)
+(NE (TESTB (SETLE cmp) (SETLE cmp)) yes no) -> (LE  cmp yes no)
+(NE (TESTB (SETG  cmp) (SETG  cmp)) yes no) -> (GT  cmp yes no)
+(NE (TESTB (SETGE cmp) (SETGE cmp)) yes no) -> (GE  cmp yes no)
+(NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no) -> (EQ  cmp yes no)
+(NE (TESTB (SETNE cmp) (SETNE cmp)) yes no) -> (NE  cmp yes no)
+(NE (TESTB (SETB  cmp) (SETB  cmp)) yes no) -> (ULT cmp yes no)
+(NE (TESTB (SETBE cmp) (SETBE cmp)) yes no) -> (ULE cmp yes no)
+(NE (TESTB (SETA  cmp) (SETA  cmp)) yes no) -> (UGT cmp yes no)
+(NE (TESTB (SETAE cmp) (SETAE cmp)) yes no) -> (UGE cmp yes no)
+
+// Special case for floating point - LF/LEF not generated
+(NE (TESTB (SETGF  cmp) (SETGF  cmp)) yes no) -> (UGT  cmp yes no)
+(NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no) -> (UGE  cmp yes no)
+(NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no) -> (EQF  cmp yes no)
+(NE (TESTB (SETNEF cmp) (SETNEF cmp)) yes no) -> (NEF  cmp yes no)
+
+// Disabled because it interferes with the pattern match above and makes worse code.
+// (SETNEF x) -> (ORQ (SETNE <config.Frontend().TypeInt8()> x) (SETNAN <config.Frontend().TypeInt8()> x))
+// (SETEQF x) -> (ANDQ (SETEQ <config.Frontend().TypeInt8()> x) (SETORD <config.Frontend().TypeInt8()> x))
+
+// fold constants into instructions
+(ADDQ x (MOVQconst [c])) && is32Bit(c) -> (ADDQconst [c] x)
+(ADDQ (MOVQconst [c]) x) && is32Bit(c) -> (ADDQconst [c] x)
+(ADDL x (MOVLconst [c])) -> (ADDLconst [c] x)
+(ADDL (MOVLconst [c]) x) -> (ADDLconst [c] x)
+
+(SUBQ x (MOVQconst [c])) && is32Bit(c) -> (SUBQconst x [c])
+(SUBQ (MOVQconst [c]) x) && is32Bit(c) -> (NEGQ (SUBQconst <v.Type> x [c]))
+(SUBL x (MOVLconst [c])) -> (SUBLconst x [c])
+(SUBL (MOVLconst [c]) x) -> (NEGL (SUBLconst <v.Type> x [c]))
+
+(MULQ x (MOVQconst [c])) && is32Bit(c) -> (MULQconst [c] x)
+(MULQ (MOVQconst [c]) x) && is32Bit(c) -> (MULQconst [c] x)
+(MULL x (MOVLconst [c])) -> (MULLconst [c] x)
+(MULL (MOVLconst [c]) x) -> (MULLconst [c] x)
+
+(ANDQ x (MOVQconst [c])) && is32Bit(c) -> (ANDQconst [c] x)
+(ANDQ (MOVQconst [c]) x) && is32Bit(c) -> (ANDQconst [c] x)
+(ANDL x (MOVLconst [c])) -> (ANDLconst [c] x)
+(ANDL (MOVLconst [c]) x) -> (ANDLconst [c] x)
+
+(ANDLconst [c] (ANDLconst [d] x)) -> (ANDLconst [c & d] x)
+(ANDQconst [c] (ANDQconst [d] x)) -> (ANDQconst [c & d] x)
+
+(ORQ x (MOVQconst [c])) && is32Bit(c) -> (ORQconst [c] x)
+(ORQ (MOVQconst [c]) x) && is32Bit(c) -> (ORQconst [c] x)
+(ORL x (MOVLconst [c])) -> (ORLconst [c] x)
+(ORL (MOVLconst [c]) x) -> (ORLconst [c] x)
+
+(XORQ x (MOVQconst [c])) && is32Bit(c) -> (XORQconst [c] x)
+(XORQ (MOVQconst [c]) x) && is32Bit(c) -> (XORQconst [c] x)
+(XORL x (MOVLconst [c])) -> (XORLconst [c] x)
+(XORL (MOVLconst [c]) x) -> (XORLconst [c] x)
+
+(SHLQ x (MOVQconst [c])) -> (SHLQconst [c&63] x)
+(SHLQ x (MOVLconst [c])) -> (SHLQconst [c&63] x)
+
+(SHLL x (MOVQconst [c])) -> (SHLLconst [c&31] x)
+(SHLL x (MOVLconst [c])) -> (SHLLconst [c&31] x)
+
+(SHRQ x (MOVQconst [c])) -> (SHRQconst [c&63] x)
+(SHRQ x (MOVLconst [c])) -> (SHRQconst [c&63] x)
+
+(SHRL x (MOVQconst [c])) -> (SHRLconst [c&31] x)
+(SHRL x (MOVLconst [c])) -> (SHRLconst [c&31] x)
+
+(SHRW x (MOVQconst [c])) -> (SHRWconst [c&31] x)
+(SHRW x (MOVLconst [c])) -> (SHRWconst [c&31] x)
+
+(SHRB x (MOVQconst [c])) -> (SHRBconst [c&31] x)
+(SHRB x (MOVLconst [c])) -> (SHRBconst [c&31] x)
+
+(SARQ x (MOVQconst [c])) -> (SARQconst [c&63] x)
+(SARQ x (MOVLconst [c])) -> (SARQconst [c&63] x)
+
+(SARL x (MOVQconst [c])) -> (SARLconst [c&31] x)
+(SARL x (MOVLconst [c])) -> (SARLconst [c&31] x)
+
+(SARW x (MOVQconst [c])) -> (SARWconst [c&31] x)
+(SARW x (MOVLconst [c])) -> (SARWconst [c&31] x)
+
+(SARB x (MOVQconst [c])) -> (SARBconst [c&31] x)
+(SARB x (MOVLconst [c])) -> (SARBconst [c&31] x)
+
+(SARL x (ANDLconst [31] y)) -> (SARL x y)
+(SARQ x (ANDQconst [63] y)) -> (SARQ x y)
+
+(SHLL x (ANDLconst [31] y)) -> (SHLL x y)
+(SHLQ x (ANDQconst [63] y)) -> (SHLQ x y)
+
+(SHRL x (ANDLconst [31] y)) -> (SHRL x y)
+(SHRQ x (ANDQconst [63] y)) -> (SHRQ x y)
+
+// Note: the word and byte shifts keep the low 5 bits (not the low 4 or 3 bits)
+// because the x86 instructions are defined to use all 5 bits of the shift even
+// for the small shifts. I don't think we'll ever generate a weird shift (e.g.
+// (SHRW x (MOVLconst [24])), but just in case.
+
+(CMPQ x (MOVQconst [c])) && is32Bit(c) -> (CMPQconst x [c])
+(CMPQ (MOVQconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPQconst x [c]))
+(CMPL x (MOVLconst [c])) -> (CMPLconst x [c])
+(CMPL (MOVLconst [c]) x) -> (InvertFlags (CMPLconst x [c]))
+(CMPW x (MOVLconst [c])) -> (CMPWconst x [int64(int16(c))])
+(CMPW (MOVLconst [c]) x) -> (InvertFlags (CMPWconst x [int64(int16(c))]))
+(CMPB x (MOVLconst [c])) -> (CMPBconst x [int64(int8(c))])
+(CMPB (MOVLconst [c]) x) -> (InvertFlags (CMPBconst x [int64(int8(c))]))
+
+// Using MOVBQZX instead of ANDQ is cheaper.
+(ANDQconst [0xFF] x) -> (MOVBQZX x)
+(ANDQconst [0xFFFF] x) -> (MOVWQZX x)
+(ANDQconst [0xFFFFFFFF] x) -> (MOVLQZX x)
+
+// strength reduction
+// Assumes that the following costs from https://gmplib.org/~tege/x86-timing.pdf:
+//    1 - addq, shlq, leaq, negq
+//    3 - imulq
+// This limits the rewrites to two instructions.
+// TODO: 27, 81
+(MULQconst [-1] x) -> (NEGQ x)
+(MULQconst [0] _) -> (MOVQconst [0])
+(MULQconst [1] x) -> x
+(MULQconst [3] x) -> (LEAQ2 x x)
+(MULQconst [5] x) -> (LEAQ4 x x)
+(MULQconst [7] x) -> (LEAQ8 (NEGQ <v.Type> x) x)
+(MULQconst [9] x) -> (LEAQ8 x x)
+(MULQconst [11] x) -> (LEAQ2 x (LEAQ4 <v.Type> x x))
+(MULQconst [13] x) -> (LEAQ4 x (LEAQ2 <v.Type> x x))
+(MULQconst [21] x) -> (LEAQ4 x (LEAQ4 <v.Type> x x))
+(MULQconst [25] x) -> (LEAQ8 x (LEAQ2 <v.Type> x x))
+(MULQconst [37] x) -> (LEAQ4 x (LEAQ8 <v.Type> x x))
+(MULQconst [41] x) -> (LEAQ8 x (LEAQ4 <v.Type> x x))
+(MULQconst [73] x) -> (LEAQ8 x (LEAQ8 <v.Type> x x))
+
+(MULQconst [c] x) && isPowerOfTwo(c) -> (SHLQconst [log2(c)] x)
+(MULQconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUBQ (SHLQconst <v.Type> [log2(c+1)] x) x)
+(MULQconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (LEAQ1 (SHLQconst <v.Type> [log2(c-1)] x) x)
+(MULQconst [c] x) && isPowerOfTwo(c-2) && c >= 34 -> (LEAQ2 (SHLQconst <v.Type> [log2(c-2)] x) x)
+(MULQconst [c] x) && isPowerOfTwo(c-4) && c >= 68 -> (LEAQ4 (SHLQconst <v.Type> [log2(c-4)] x) x)
+(MULQconst [c] x) && isPowerOfTwo(c-8) && c >= 136 -> (LEAQ8 (SHLQconst <v.Type> [log2(c-8)] x) x)
+(MULQconst [c] x) && c%3 == 0 && isPowerOfTwo(c/3)-> (SHLQconst [log2(c/3)] (LEAQ2 <v.Type> x x))
+(MULQconst [c] x) && c%5 == 0 && isPowerOfTwo(c/5)-> (SHLQconst [log2(c/5)] (LEAQ4 <v.Type> x x))
+(MULQconst [c] x) && c%9 == 0 && isPowerOfTwo(c/9)-> (SHLQconst [log2(c/9)] (LEAQ8 <v.Type> x x))
+
+// combine add/shift into LEAQ
+(ADDQ x (SHLQconst [3] y)) -> (LEAQ8 x y)
+(ADDQ x (SHLQconst [2] y)) -> (LEAQ4 x y)
+(ADDQ x (SHLQconst [1] y)) -> (LEAQ2 x y)
+(ADDQ x (ADDQ y y)) -> (LEAQ2 x y)
+(ADDQ x (ADDQ x y)) -> (LEAQ2 y x)
+(ADDQ x (ADDQ y x)) -> (LEAQ2 y x)
+
+// combine ADDQ/ADDQconst into LEAQ1
+(ADDQconst [c] (ADDQ x y)) -> (LEAQ1 [c] x y)
+(ADDQ (ADDQconst [c] x) y) -> (LEAQ1 [c] x y)
+(ADDQ x (ADDQconst [c] y)) -> (LEAQ1 [c] x y)
+
+// fold ADDQ into LEAQ
+(ADDQconst [c] (LEAQ [d] {s} x)) && is32Bit(c+d) -> (LEAQ [c+d] {s} x)
+(LEAQ [c] {s} (ADDQconst [d] x)) && is32Bit(c+d) -> (LEAQ [c+d] {s} x)
+(LEAQ [c] {s} (ADDQ x y)) && x.Op != OpSB && y.Op != OpSB -> (LEAQ1 [c] {s} x y)
+(ADDQ x (LEAQ [c] {s} y)) && x.Op != OpSB && y.Op != OpSB -> (LEAQ1 [c] {s} x y)
+(ADDQ (LEAQ [c] {s} x) y) && x.Op != OpSB && y.Op != OpSB -> (LEAQ1 [c] {s} x y)
+
+// fold ADDQconst into LEAQx
+(ADDQconst [c] (LEAQ1 [d] {s} x y)) && is32Bit(c+d) -> (LEAQ1 [c+d] {s} x y)
+(ADDQconst [c] (LEAQ2 [d] {s} x y)) && is32Bit(c+d) -> (LEAQ2 [c+d] {s} x y)
+(ADDQconst [c] (LEAQ4 [d] {s} x y)) && is32Bit(c+d) -> (LEAQ4 [c+d] {s} x y)
+(ADDQconst [c] (LEAQ8 [d] {s} x y)) && is32Bit(c+d) -> (LEAQ8 [c+d] {s} x y)
+(LEAQ1 [c] {s} (ADDQconst [d] x) y) && is32Bit(c+d)   && x.Op != OpSB -> (LEAQ1 [c+d] {s} x y)
+(LEAQ1 [c] {s} x (ADDQconst [d] y)) && is32Bit(c+d)   && y.Op != OpSB -> (LEAQ1 [c+d] {s} x y)
+(LEAQ2 [c] {s} (ADDQconst [d] x) y) && is32Bit(c+d)   && x.Op != OpSB -> (LEAQ2 [c+d] {s} x y)
+(LEAQ2 [c] {s} x (ADDQconst [d] y)) && is32Bit(c+2*d) && y.Op != OpSB -> (LEAQ2 [c+2*d] {s} x y)
+(LEAQ4 [c] {s} (ADDQconst [d] x) y) && is32Bit(c+d)   && x.Op != OpSB -> (LEAQ4 [c+d] {s} x y)
+(LEAQ4 [c] {s} x (ADDQconst [d] y)) && is32Bit(c+4*d) && y.Op != OpSB -> (LEAQ4 [c+4*d] {s} x y)
+(LEAQ8 [c] {s} (ADDQconst [d] x) y) && is32Bit(c+d)   && x.Op != OpSB -> (LEAQ8 [c+d] {s} x y)
+(LEAQ8 [c] {s} x (ADDQconst [d] y)) && is32Bit(c+8*d) && y.Op != OpSB -> (LEAQ8 [c+8*d] {s} x y)
+
+// fold shifts into LEAQx
+(LEAQ1 [c] {s} x (SHLQconst [1] y)) -> (LEAQ2 [c] {s} x y)
+(LEAQ1 [c] {s} (SHLQconst [1] x) y) -> (LEAQ2 [c] {s} y x)
+(LEAQ1 [c] {s} x (SHLQconst [2] y)) -> (LEAQ4 [c] {s} x y)
+(LEAQ1 [c] {s} (SHLQconst [2] x) y) -> (LEAQ4 [c] {s} y x)
+(LEAQ1 [c] {s} x (SHLQconst [3] y)) -> (LEAQ8 [c] {s} x y)
+(LEAQ1 [c] {s} (SHLQconst [3] x) y) -> (LEAQ8 [c] {s} y x)
+
+(LEAQ2 [c] {s} x (SHLQconst [1] y)) -> (LEAQ4 [c] {s} x y)
+(LEAQ2 [c] {s} x (SHLQconst [2] y)) -> (LEAQ8 [c] {s} x y)
+(LEAQ4 [c] {s} x (SHLQconst [1] y)) -> (LEAQ8 [c] {s} x y)
+
+// reverse ordering of compare instruction
+(SETL (InvertFlags x)) -> (SETG x)
+(SETG (InvertFlags x)) -> (SETL x)
+(SETB (InvertFlags x)) -> (SETA x)
+(SETA (InvertFlags x)) -> (SETB x)
+(SETLE (InvertFlags x)) -> (SETGE x)
+(SETGE (InvertFlags x)) -> (SETLE x)
+(SETBE (InvertFlags x)) -> (SETAE x)
+(SETAE (InvertFlags x)) -> (SETBE x)
+(SETEQ (InvertFlags x)) -> (SETEQ x)
+(SETNE (InvertFlags x)) -> (SETNE x)
+
+// sign extended loads
+// Note: The combined instruction must end up in the same block
+// as the original load. If not, we end up making a value with
+// memory type live in two different blocks, which can lead to
+// multiple memory values alive simultaneously.
+// Make sure we don't combine these ops if the load has another use.
+// This prevents a single load from being split into multiple loads
+// which then might return different values.  See test/atomicload.go.
+(MOVBQSX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
+(MOVBQZX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+(MOVWQSX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
+(MOVWQZX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+(MOVLQSX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
+(MOVLQZX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
+
+(MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
+(MOVWQZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
+(MOVWQZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
+(MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
+(MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
+
+// replace load from same location as preceding store with copy
+(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+(MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+
+// Fold extensions and ANDs together.
+(MOVBQZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
+(MOVWQZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xffff] x)
+(MOVLQZX (ANDLconst [c] x)) -> (ANDLconst [c] x)
+(MOVBQSX (ANDLconst [c] x)) && c & 0x80 == 0 -> (ANDLconst [c & 0x7f] x)
+(MOVWQSX (ANDLconst [c] x)) && c & 0x8000 == 0 -> (ANDLconst [c & 0x7fff] x)
+(MOVLQSX (ANDLconst [c] x)) && c & 0x80000000 == 0 -> (ANDLconst [c & 0x7fffffff] x)
+
+// Don't extend before storing
+(MOVLstore [off] {sym} ptr (MOVLQSX x) mem) -> (MOVLstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWQSX x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBQSX x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVLstore [off] {sym} ptr (MOVLQZX x) mem) -> (MOVLstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWQZX x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBQZX x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+
+// fold constants into memory operations
+// Note that this is not always a good idea because if not all the uses of
+// the ADDQconst get eliminated, we still have to compute the ADDQconst and we now
+// have potentially two live values (ptr and (ADDQconst [off] ptr)) instead of one.
+// Nevertheless, let's do it!
+(MOVQload  [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVQload  [off1+off2] {sym} ptr mem)
+(MOVLload  [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVLload  [off1+off2] {sym} ptr mem)
+(MOVWload  [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWload  [off1+off2] {sym} ptr mem)
+(MOVBload  [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBload  [off1+off2] {sym} ptr mem)
+(MOVSSload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVSSload [off1+off2] {sym} ptr mem)
+(MOVSDload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVSDload [off1+off2] {sym} ptr mem)
+(MOVOload  [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVOload  [off1+off2] {sym} ptr mem)
+
+(MOVQstore  [off1] {sym} (ADDQconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVQstore  [off1+off2] {sym} ptr val mem)
+(MOVLstore  [off1] {sym} (ADDQconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVLstore  [off1+off2] {sym} ptr val mem)
+(MOVWstore  [off1] {sym} (ADDQconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVWstore  [off1+off2] {sym} ptr val mem)
+(MOVBstore  [off1] {sym} (ADDQconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVBstore  [off1+off2] {sym} ptr val mem)
+(MOVSSstore [off1] {sym} (ADDQconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVSSstore [off1+off2] {sym} ptr val mem)
+(MOVSDstore [off1] {sym} (ADDQconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVSDstore [off1+off2] {sym} ptr val mem)
+(MOVOstore  [off1] {sym} (ADDQconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVOstore  [off1+off2] {sym} ptr val mem)
+
+// Fold constants into stores.
+(MOVQstore [off] {sym} ptr (MOVQconst [c]) mem) && validValAndOff(c,off) ->
+	(MOVQstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
+(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
+	(MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
+(MOVWstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
+	(MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
+(MOVBstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
+	(MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
+
+// Fold address offsets into constant stores.
+(MOVQstoreconst [sc] {s} (ADDQconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+	(MOVQstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVLstoreconst [sc] {s} (ADDQconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+	(MOVLstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVWstoreconst [sc] {s} (ADDQconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+	(MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVBstoreconst [sc] {s} (ADDQconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+	(MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+
+// We need to fold LEAQ into the MOVx ops so that the live variable analysis knows
+// what variables are being read/written by the ops.
+(MOVQload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVQload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVLload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVLload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVWload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVWload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVBload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVBload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVSSload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVSDload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVOload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVOload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+
+(MOVBQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVBQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVWQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVWQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVLQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVLQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+
+(MOVQstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVQstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVLstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVLstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVWstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVWstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVBstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVBstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVSSstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVSDstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVOstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVOstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+
+(MOVQstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+	(MOVQstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+(MOVLstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+	(MOVLstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+(MOVWstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+	(MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+(MOVBstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+	(MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+
+// generating indexed loads and stores
+(MOVBload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVBloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVWload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVWloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVWload [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVLload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVLloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVLload [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVQload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVQloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVQload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVQloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVSSload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSSloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVSSload [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSSloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVSDload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVSDload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+
+(MOVBstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVBstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVWstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVWstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVWstore [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVLstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVLstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVLstore [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVLstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVQstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVQstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVQstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVQstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVSSstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSSstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVSSstore [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVSDstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVSDstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+	(MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+
+(MOVBload [off] {sym} (ADDQ ptr idx) mem) && ptr.Op != OpSB -> (MOVBloadidx1 [off] {sym} ptr idx mem)
+(MOVWload [off] {sym} (ADDQ ptr idx) mem) && ptr.Op != OpSB -> (MOVWloadidx1 [off] {sym} ptr idx mem)
+(MOVLload [off] {sym} (ADDQ ptr idx) mem) && ptr.Op != OpSB -> (MOVLloadidx1 [off] {sym} ptr idx mem)
+(MOVQload [off] {sym} (ADDQ ptr idx) mem) && ptr.Op != OpSB -> (MOVQloadidx1 [off] {sym} ptr idx mem)
+(MOVSSload [off] {sym} (ADDQ ptr idx) mem) && ptr.Op != OpSB -> (MOVSSloadidx1 [off] {sym} ptr idx mem)
+(MOVSDload [off] {sym} (ADDQ ptr idx) mem) && ptr.Op != OpSB -> (MOVSDloadidx1 [off] {sym} ptr idx mem)
+(MOVBstore [off] {sym} (ADDQ ptr idx) val mem) && ptr.Op != OpSB -> (MOVBstoreidx1 [off] {sym} ptr idx val mem)
+(MOVWstore [off] {sym} (ADDQ ptr idx) val mem) && ptr.Op != OpSB -> (MOVWstoreidx1 [off] {sym} ptr idx val mem)
+(MOVLstore [off] {sym} (ADDQ ptr idx) val mem) && ptr.Op != OpSB -> (MOVLstoreidx1 [off] {sym} ptr idx val mem)
+(MOVQstore [off] {sym} (ADDQ ptr idx) val mem) && ptr.Op != OpSB -> (MOVQstoreidx1 [off] {sym} ptr idx val mem)
+(MOVSSstore [off] {sym} (ADDQ ptr idx) val mem) && ptr.Op != OpSB -> (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
+(MOVSDstore [off] {sym} (ADDQ ptr idx) val mem) && ptr.Op != OpSB -> (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
+
+(MOVBstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+	(MOVBstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVWstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+	(MOVWstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVWstoreconst [x] {sym1} (LEAQ2 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+	(MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVLstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+	(MOVLstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVLstoreconst [x] {sym1} (LEAQ4 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+	(MOVLstoreconstidx4 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVQstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+	(MOVQstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVQstoreconst [x] {sym1} (LEAQ8 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+	(MOVQstoreconstidx8 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+
+(MOVBstoreconst [x] {sym} (ADDQ ptr idx) mem) -> (MOVBstoreconstidx1 [x] {sym} ptr idx mem)
+(MOVWstoreconst [x] {sym} (ADDQ ptr idx) mem) -> (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
+(MOVLstoreconst [x] {sym} (ADDQ ptr idx) mem) -> (MOVLstoreconstidx1 [x] {sym} ptr idx mem)
+(MOVQstoreconst [x] {sym} (ADDQ ptr idx) mem) -> (MOVQstoreconstidx1 [x] {sym} ptr idx mem)
+
+// combine SHLQ into indexed loads and stores
+(MOVWloadidx1 [c] {sym} ptr (SHLQconst [1] idx) mem) -> (MOVWloadidx2 [c] {sym} ptr idx mem)
+(MOVLloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem) -> (MOVLloadidx4 [c] {sym} ptr idx mem)
+(MOVQloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem) -> (MOVQloadidx8 [c] {sym} ptr idx mem)
+(MOVWstoreidx1 [c] {sym} ptr (SHLQconst [1] idx) val mem) -> (MOVWstoreidx2 [c] {sym} ptr idx val mem)
+(MOVLstoreidx1 [c] {sym} ptr (SHLQconst [2] idx) val mem) -> (MOVLstoreidx4 [c] {sym} ptr idx val mem)
+(MOVQstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem) -> (MOVQstoreidx8 [c] {sym} ptr idx val mem)
+(MOVWstoreconstidx1 [c] {sym} ptr (SHLQconst [1] idx) mem) -> (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
+(MOVLstoreconstidx1 [c] {sym} ptr (SHLQconst [2] idx) mem) -> (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
+(MOVQstoreconstidx1 [c] {sym} ptr (SHLQconst [3] idx) mem) -> (MOVQstoreconstidx8 [c] {sym} ptr idx mem)
+
+// combine ADDQ into indexed loads and stores
+(MOVBloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+(MOVWloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+(MOVWloadidx2 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVWloadidx2 [c+d] {sym} ptr idx mem)
+(MOVLloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+(MOVLloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVLloadidx4 [c+d] {sym} ptr idx mem)
+(MOVQloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVQloadidx1 [c+d] {sym} ptr idx mem)
+(MOVQloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVQloadidx8 [c+d] {sym} ptr idx mem)
+(MOVSSloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+(MOVSSloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVSSloadidx4 [c+d] {sym} ptr idx mem)
+(MOVSDloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+(MOVSDloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem) -> (MOVSDloadidx8 [c+d] {sym} ptr idx mem)
+
+(MOVBstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx2 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVWstoreidx2 [c+d] {sym} ptr idx val mem)
+(MOVLstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVLstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVLstoreidx4 [c+d] {sym} ptr idx val mem)
+(MOVQstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVQstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVQstoreidx8 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVQstoreidx8 [c+d] {sym} ptr idx val mem)
+(MOVSSstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVSSstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVSSstoreidx4 [c+d] {sym} ptr idx val mem)
+(MOVSDstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVSDstoreidx8 [c] {sym} (ADDQconst [d] ptr) idx val mem) -> (MOVSDstoreidx8 [c+d] {sym} ptr idx val mem)
+
+(MOVBloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+(MOVWloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+(MOVWloadidx2 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
+(MOVLloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+(MOVLloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVLloadidx4 [c+4*d] {sym} ptr idx mem)
+(MOVQloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVQloadidx1 [c+d] {sym} ptr idx mem)
+(MOVQloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVQloadidx8 [c+8*d] {sym} ptr idx mem)
+(MOVSSloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+(MOVSSloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVSSloadidx4 [c+4*d] {sym} ptr idx mem)
+(MOVSDloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+(MOVSDloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem) -> (MOVSDloadidx8 [c+8*d] {sym} ptr idx mem)
+
+(MOVBstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx2 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVWstoreidx2 [c+2*d] {sym} ptr idx val mem)
+(MOVLstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVLstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVLstoreidx4 [c+4*d] {sym} ptr idx val mem)
+(MOVQstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVQstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVQstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVQstoreidx8 [c+8*d] {sym} ptr idx val mem)
+(MOVSSstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVSSstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVSSstoreidx4 [c+4*d] {sym} ptr idx val mem)
+(MOVSDstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVSDstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem) -> (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val mem)
+
+(MOVBstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem) ->
+	(MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVWstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem) ->
+	(MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVWstoreconstidx2 [x] {sym} (ADDQconst [c] ptr) idx mem) ->
+	(MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVLstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem) ->
+	(MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVLstoreconstidx4 [x] {sym} (ADDQconst [c] ptr) idx mem) ->
+	(MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVQstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem) ->
+	(MOVQstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVQstoreconstidx8 [x] {sym} (ADDQconst [c] ptr) idx mem) ->
+	(MOVQstoreconstidx8 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+
+(MOVBstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem) ->
+	(MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVWstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem) ->
+	(MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVWstoreconstidx2 [x] {sym} ptr (ADDQconst [c] idx) mem) ->
+	(MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
+(MOVLstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem) ->
+	(MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVLstoreconstidx4 [x] {sym} ptr (ADDQconst [c] idx) mem) ->
+	(MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
+(MOVQstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem) ->
+	(MOVQstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVQstoreconstidx8 [x] {sym} ptr (ADDQconst [c] idx) mem) ->
+	(MOVQstoreconstidx8 [ValAndOff(x).add(8*c)] {sym} ptr idx mem)
+
+// fold LEAQs together
+(LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+      (LEAQ [off1+off2] {mergeSym(sym1,sym2)} x)
+
+// LEAQ into LEAQ1
+(LEAQ1 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
+       (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+(LEAQ1 [off1] {sym1} x (LEAQ [off2] {sym2} y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB ->
+       (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+
+// LEAQ1 into LEAQ
+(LEAQ [off1] {sym1} (LEAQ1 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+       (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+
+// LEAQ into LEAQ[248]
+(LEAQ2 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
+       (LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
+(LEAQ4 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
+       (LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+(LEAQ8 [off1] {sym1} (LEAQ [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
+       (LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+
+// LEAQ[248] into LEAQ
+(LEAQ [off1] {sym1} (LEAQ2 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+      (LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
+(LEAQ [off1] {sym1} (LEAQ4 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+      (LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+(LEAQ [off1] {sym1} (LEAQ8 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+      (LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+
+// Absorb InvertFlags into branches.
+(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
+(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
+(LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
+(GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
+(ULT (InvertFlags cmp) yes no) -> (UGT cmp yes no)
+(UGT (InvertFlags cmp) yes no) -> (ULT cmp yes no)
+(ULE (InvertFlags cmp) yes no) -> (UGE cmp yes no)
+(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
+(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
+(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
+
+// Constant comparisons.
+(CMPQconst (MOVQconst [x]) [y]) && x==y -> (FlagEQ)
+(CMPQconst (MOVQconst [x]) [y]) && x<y && uint64(x)<uint64(y) -> (FlagLT_ULT)
+(CMPQconst (MOVQconst [x]) [y]) && x<y && uint64(x)>uint64(y) -> (FlagLT_UGT)
+(CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x)<uint64(y) -> (FlagGT_ULT)
+(CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT)
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)==int16(y) -> (FlagEQ)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)<int16(y) && uint16(x)<uint16(y) -> (FlagLT_ULT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)<int16(y) && uint16(x)>uint16(y) -> (FlagLT_UGT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)>int16(y) && uint16(x)<uint16(y) -> (FlagGT_ULT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)>int16(y) && uint16(x)>uint16(y) -> (FlagGT_UGT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)==int8(y) -> (FlagEQ)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)<int8(y) && uint8(x)<uint8(y) -> (FlagLT_ULT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)<int8(y) && uint8(x)>uint8(y) -> (FlagLT_UGT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)>int8(y) && uint8(x)<uint8(y) -> (FlagGT_ULT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)>int8(y) && uint8(x)>uint8(y) -> (FlagGT_UGT)
+
+// Other known comparisons.
+(CMPQconst (MOVBQZX _) [c]) && 0xFF < c -> (FlagLT_ULT)
+(CMPQconst (MOVWQZX _) [c]) && 0xFFFF < c -> (FlagLT_ULT)
+(CMPQconst (MOVLQZX _) [c]) && 0xFFFFFFFF < c -> (FlagLT_ULT)
+(CMPLconst (SHRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n) -> (FlagLT_ULT)
+(CMPQconst (SHRQconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n) -> (FlagLT_ULT)
+(CMPQconst (ANDQconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT_ULT)
+(CMPLconst (ANDLconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT_ULT)
+(CMPWconst (ANDLconst _ [m]) [n]) && 0 <= int16(m) && int16(m) < int16(n) -> (FlagLT_ULT)
+(CMPBconst (ANDLconst _ [m]) [n]) && 0 <= int8(m) && int8(m) < int8(n) -> (FlagLT_ULT)
+// TODO: DIVxU also.
+
+// Absorb flag constants into SBB ops.
+(SBBQcarrymask (FlagEQ)) -> (MOVQconst [0])
+(SBBQcarrymask (FlagLT_ULT)) -> (MOVQconst [-1])
+(SBBQcarrymask (FlagLT_UGT)) -> (MOVQconst [0])
+(SBBQcarrymask (FlagGT_ULT)) -> (MOVQconst [-1])
+(SBBQcarrymask (FlagGT_UGT)) -> (MOVQconst [0])
+(SBBLcarrymask (FlagEQ)) -> (MOVLconst [0])
+(SBBLcarrymask (FlagLT_ULT)) -> (MOVLconst [-1])
+(SBBLcarrymask (FlagLT_UGT)) -> (MOVLconst [0])
+(SBBLcarrymask (FlagGT_ULT)) -> (MOVLconst [-1])
+(SBBLcarrymask (FlagGT_UGT)) -> (MOVLconst [0])
+
+// Absorb flag constants into branches.
+(EQ (FlagEQ) yes no) -> (First nil yes no)
+(EQ (FlagLT_ULT) yes no) -> (First nil no yes)
+(EQ (FlagLT_UGT) yes no) -> (First nil no yes)
+(EQ (FlagGT_ULT) yes no) -> (First nil no yes)
+(EQ (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(NE (FlagEQ) yes no) -> (First nil no yes)
+(NE (FlagLT_ULT) yes no) -> (First nil yes no)
+(NE (FlagLT_UGT) yes no) -> (First nil yes no)
+(NE (FlagGT_ULT) yes no) -> (First nil yes no)
+(NE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(LT (FlagEQ) yes no) -> (First nil no yes)
+(LT (FlagLT_ULT) yes no) -> (First nil yes no)
+(LT (FlagLT_UGT) yes no) -> (First nil yes no)
+(LT (FlagGT_ULT) yes no) -> (First nil no yes)
+(LT (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(LE (FlagEQ) yes no) -> (First nil yes no)
+(LE (FlagLT_ULT) yes no) -> (First nil yes no)
+(LE (FlagLT_UGT) yes no) -> (First nil yes no)
+(LE (FlagGT_ULT) yes no) -> (First nil no yes)
+(LE (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(GT (FlagEQ) yes no) -> (First nil no yes)
+(GT (FlagLT_ULT) yes no) -> (First nil no yes)
+(GT (FlagLT_UGT) yes no) -> (First nil no yes)
+(GT (FlagGT_ULT) yes no) -> (First nil yes no)
+(GT (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(GE (FlagEQ) yes no) -> (First nil yes no)
+(GE (FlagLT_ULT) yes no) -> (First nil no yes)
+(GE (FlagLT_UGT) yes no) -> (First nil no yes)
+(GE (FlagGT_ULT) yes no) -> (First nil yes no)
+(GE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(ULT (FlagEQ) yes no) -> (First nil no yes)
+(ULT (FlagLT_ULT) yes no) -> (First nil yes no)
+(ULT (FlagLT_UGT) yes no) -> (First nil no yes)
+(ULT (FlagGT_ULT) yes no) -> (First nil yes no)
+(ULT (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(ULE (FlagEQ) yes no) -> (First nil yes no)
+(ULE (FlagLT_ULT) yes no) -> (First nil yes no)
+(ULE (FlagLT_UGT) yes no) -> (First nil no yes)
+(ULE (FlagGT_ULT) yes no) -> (First nil yes no)
+(ULE (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(UGT (FlagEQ) yes no) -> (First nil no yes)
+(UGT (FlagLT_ULT) yes no) -> (First nil no yes)
+(UGT (FlagLT_UGT) yes no) -> (First nil yes no)
+(UGT (FlagGT_ULT) yes no) -> (First nil no yes)
+(UGT (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(UGE (FlagEQ) yes no) -> (First nil yes no)
+(UGE (FlagLT_ULT) yes no) -> (First nil no yes)
+(UGE (FlagLT_UGT) yes no) -> (First nil yes no)
+(UGE (FlagGT_ULT) yes no) -> (First nil no yes)
+(UGE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+// Absorb flag constants into SETxx ops.
+(SETEQ (FlagEQ)) -> (MOVLconst [1])
+(SETEQ (FlagLT_ULT)) -> (MOVLconst [0])
+(SETEQ (FlagLT_UGT)) -> (MOVLconst [0])
+(SETEQ (FlagGT_ULT)) -> (MOVLconst [0])
+(SETEQ (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETNE (FlagEQ)) -> (MOVLconst [0])
+(SETNE (FlagLT_ULT)) -> (MOVLconst [1])
+(SETNE (FlagLT_UGT)) -> (MOVLconst [1])
+(SETNE (FlagGT_ULT)) -> (MOVLconst [1])
+(SETNE (FlagGT_UGT)) -> (MOVLconst [1])
+
+(SETL (FlagEQ)) -> (MOVLconst [0])
+(SETL (FlagLT_ULT)) -> (MOVLconst [1])
+(SETL (FlagLT_UGT)) -> (MOVLconst [1])
+(SETL (FlagGT_ULT)) -> (MOVLconst [0])
+(SETL (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETLE (FlagEQ)) -> (MOVLconst [1])
+(SETLE (FlagLT_ULT)) -> (MOVLconst [1])
+(SETLE (FlagLT_UGT)) -> (MOVLconst [1])
+(SETLE (FlagGT_ULT)) -> (MOVLconst [0])
+(SETLE (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETG (FlagEQ)) -> (MOVLconst [0])
+(SETG (FlagLT_ULT)) -> (MOVLconst [0])
+(SETG (FlagLT_UGT)) -> (MOVLconst [0])
+(SETG (FlagGT_ULT)) -> (MOVLconst [1])
+(SETG (FlagGT_UGT)) -> (MOVLconst [1])
+
+(SETGE (FlagEQ)) -> (MOVLconst [1])
+(SETGE (FlagLT_ULT)) -> (MOVLconst [0])
+(SETGE (FlagLT_UGT)) -> (MOVLconst [0])
+(SETGE (FlagGT_ULT)) -> (MOVLconst [1])
+(SETGE (FlagGT_UGT)) -> (MOVLconst [1])
+
+(SETB (FlagEQ)) -> (MOVLconst [0])
+(SETB (FlagLT_ULT)) -> (MOVLconst [1])
+(SETB (FlagLT_UGT)) -> (MOVLconst [0])
+(SETB (FlagGT_ULT)) -> (MOVLconst [1])
+(SETB (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETBE (FlagEQ)) -> (MOVLconst [1])
+(SETBE (FlagLT_ULT)) -> (MOVLconst [1])
+(SETBE (FlagLT_UGT)) -> (MOVLconst [0])
+(SETBE (FlagGT_ULT)) -> (MOVLconst [1])
+(SETBE (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETA (FlagEQ)) -> (MOVLconst [0])
+(SETA (FlagLT_ULT)) -> (MOVLconst [0])
+(SETA (FlagLT_UGT)) -> (MOVLconst [1])
+(SETA (FlagGT_ULT)) -> (MOVLconst [0])
+(SETA (FlagGT_UGT)) -> (MOVLconst [1])
+
+(SETAE (FlagEQ)) -> (MOVLconst [1])
+(SETAE (FlagLT_ULT)) -> (MOVLconst [0])
+(SETAE (FlagLT_UGT)) -> (MOVLconst [1])
+(SETAE (FlagGT_ULT)) -> (MOVLconst [0])
+(SETAE (FlagGT_UGT)) -> (MOVLconst [1])
+
+// Remove redundant *const ops
+(ADDQconst [0] x) -> x
+(ADDLconst [c] x) && int32(c)==0 -> x
+(SUBQconst [0] x) -> x
+(SUBLconst [c] x) && int32(c) == 0 -> x
+(ANDQconst [0] _)                 -> (MOVQconst [0])
+(ANDLconst [c] _) && int32(c)==0  -> (MOVLconst [0])
+(ANDQconst [-1] x)                -> x
+(ANDLconst [c] x) && int32(c)==-1 -> x
+(ORQconst [0] x)                  -> x
+(ORLconst [c] x) && int32(c)==0   -> x
+(ORQconst [-1] _)                 -> (MOVQconst [-1])
+(ORLconst [c] _) && int32(c)==-1  -> (MOVLconst [-1])
+(XORQconst [0] x)                  -> x
+(XORLconst [c] x) && int32(c)==0   -> x
+// TODO: since we got rid of the W/B versions, we might miss
+// things like (ANDLconst [0x100] x) which were formerly
+// (ANDBconst [0] x).  Probably doesn't happen very often.
+// If we cared, we might do:
+//  (ANDLconst <t> [c] x) && t.Size()==1 && int8(x)==0 -> (MOVLconst [0])
+
+// Convert constant subtracts to constant adds
+(SUBQconst [c] x) && c != -(1<<31) -> (ADDQconst [-c] x)
+(SUBLconst [c] x) -> (ADDLconst [int64(int32(-c))] x)
+
+// generic constant folding
+// TODO: more of this
+(ADDQconst [c] (MOVQconst [d])) -> (MOVQconst [c+d])
+(ADDLconst [c] (MOVLconst [d])) -> (MOVLconst [int64(int32(c+d))])
+(ADDQconst [c] (ADDQconst [d] x)) && is32Bit(c+d) -> (ADDQconst [c+d] x)
+(ADDLconst [c] (ADDLconst [d] x)) -> (ADDLconst [int64(int32(c+d))] x)
+(SUBQconst (MOVQconst [d]) [c]) -> (MOVQconst [d-c])
+(SUBQconst (SUBQconst x [d]) [c]) && is32Bit(-c-d) -> (ADDQconst [-c-d] x)
+(SARQconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
+(SARLconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
+(SARWconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
+(SARBconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
+(NEGQ (MOVQconst [c])) -> (MOVQconst [-c])
+(NEGL (MOVLconst [c])) -> (MOVLconst [int64(int32(-c))])
+(MULQconst [c] (MOVQconst [d])) -> (MOVQconst [c*d])
+(MULLconst [c] (MOVLconst [d])) -> (MOVLconst [int64(int32(c*d))])
+(ANDQconst [c] (MOVQconst [d])) -> (MOVQconst [c&d])
+(ANDLconst [c] (MOVLconst [d])) -> (MOVLconst [c&d])
+(ORQconst [c] (MOVQconst [d])) -> (MOVQconst [c|d])
+(ORLconst [c] (MOVLconst [d])) -> (MOVLconst [c|d])
+(XORQconst [c] (MOVQconst [d])) -> (MOVQconst [c^d])
+(XORLconst [c] (MOVLconst [d])) -> (MOVLconst [c^d])
+(NOTQ (MOVQconst [c])) -> (MOVQconst [^c])
+(NOTL (MOVLconst [c])) -> (MOVLconst [^c])
+
+// generic simplifications
+// TODO: more of this
+(ADDQ x (NEGQ y)) -> (SUBQ x y)
+(ADDL x (NEGL y)) -> (SUBL x y)
+(SUBQ x x) -> (MOVQconst [0])
+(SUBL x x) -> (MOVLconst [0])
+(ANDQ x x) -> x
+(ANDL x x) -> x
+(ORQ x x) -> x
+(ORL x x) -> x
+(XORQ x x) -> (MOVQconst [0])
+(XORL x x) -> (MOVLconst [0])
+
+// checking AND against 0.
+(CMPQconst (ANDQ x y) [0]) -> (TESTQ x y)
+(CMPLconst (ANDL x y) [0]) -> (TESTL x y)
+(CMPWconst (ANDL x y) [0]) -> (TESTW x y)
+(CMPBconst (ANDL x y) [0]) -> (TESTB x y)
+(CMPQconst (ANDQconst [c] x) [0]) -> (TESTQconst [c] x)
+(CMPLconst (ANDLconst [c] x) [0]) -> (TESTLconst [c] x)
+(CMPWconst (ANDLconst [c] x) [0]) -> (TESTWconst [int64(int16(c))] x)
+(CMPBconst (ANDLconst [c] x) [0]) -> (TESTBconst [int64(int8(c))] x)
+
+// TEST %reg,%reg is shorter than CMP
+(CMPQconst x [0]) -> (TESTQ x x)
+(CMPLconst x [0]) -> (TESTL x x)
+(CMPWconst x [0]) -> (TESTW x x)
+(CMPBconst x [0]) -> (TESTB x x)
+
+// Optimizing conditional moves
+(CMOVQEQconst x (InvertFlags y) [c]) -> (CMOVQNEconst x y [c])
+(CMOVLEQconst x (InvertFlags y) [c]) -> (CMOVLNEconst x y [c])
+(CMOVWEQconst x (InvertFlags y) [c]) -> (CMOVWNEconst x y [c])
+
+(CMOVQEQconst _ (FlagEQ) [c]) -> (Const64 [c])
+(CMOVLEQconst _ (FlagEQ) [c]) -> (Const32 [c])
+(CMOVWEQconst _ (FlagEQ) [c]) -> (Const16 [c])
+
+(CMOVQEQconst x (FlagLT_ULT)) -> x
+(CMOVLEQconst x (FlagLT_ULT)) -> x
+(CMOVWEQconst x (FlagLT_ULT)) -> x
+
+(CMOVQEQconst x (FlagLT_UGT)) -> x
+(CMOVLEQconst x (FlagLT_UGT)) -> x
+(CMOVWEQconst x (FlagLT_UGT)) -> x
+
+(CMOVQEQconst x (FlagGT_ULT)) -> x
+(CMOVLEQconst x (FlagGT_ULT)) -> x
+(CMOVWEQconst x (FlagGT_ULT)) -> x
+
+(CMOVQEQconst x (FlagGT_UGT)) -> x
+(CMOVLEQconst x (FlagGT_UGT)) -> x
+(CMOVWEQconst x (FlagGT_UGT)) -> x
+
+// Combining byte loads into larger (unaligned) loads.
+// There are many ways these combinations could occur.  This is
+// designed to match the way encoding/binary.LittleEndian does it.
+(ORL                  x0:(MOVBload [i]   {s} p mem)
+    s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && s0.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(s0)
+  -> @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
+
+(ORL o0:(ORL o1:(ORL
+                       x0:(MOVBload [i]   {s} p mem)
+    s0:(SHLLconst [8]  x1:(MOVBload [i+1] {s} p mem)))
+    s1:(SHLLconst [16] x2:(MOVBload [i+2] {s} p mem)))
+    s2:(SHLLconst [24] x3:(MOVBload [i+3] {s} p mem)))
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && x2.Uses == 1
+  && x3.Uses == 1
+  && s0.Uses == 1
+  && s1.Uses == 1
+  && s2.Uses == 1
+  && o0.Uses == 1
+  && o1.Uses == 1
+  && mergePoint(b,x0,x1,x2,x3) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(x2)
+  && clobber(x3)
+  && clobber(s0)
+  && clobber(s1)
+  && clobber(s2)
+  && clobber(o0)
+  && clobber(o1)
+  -> @mergePoint(b,x0,x1,x2,x3) (MOVLload [i] {s} p mem)
+
+(ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ
+                       x0:(MOVBload [i]   {s} p mem)
+    s0:(SHLQconst [8]  x1:(MOVBload [i+1] {s} p mem)))
+    s1:(SHLQconst [16] x2:(MOVBload [i+2] {s} p mem)))
+    s2:(SHLQconst [24] x3:(MOVBload [i+3] {s} p mem)))
+    s3:(SHLQconst [32] x4:(MOVBload [i+4] {s} p mem)))
+    s4:(SHLQconst [40] x5:(MOVBload [i+5] {s} p mem)))
+    s5:(SHLQconst [48] x6:(MOVBload [i+6] {s} p mem)))
+    s6:(SHLQconst [56] x7:(MOVBload [i+7] {s} p mem)))
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && x2.Uses == 1
+  && x3.Uses == 1
+  && x4.Uses == 1
+  && x5.Uses == 1
+  && x6.Uses == 1
+  && x7.Uses == 1
+  && s0.Uses == 1
+  && s1.Uses == 1
+  && s2.Uses == 1
+  && s3.Uses == 1
+  && s4.Uses == 1
+  && s5.Uses == 1
+  && s6.Uses == 1
+  && o0.Uses == 1
+  && o1.Uses == 1
+  && o2.Uses == 1
+  && o3.Uses == 1
+  && o4.Uses == 1
+  && o5.Uses == 1
+  && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(x2)
+  && clobber(x3)
+  && clobber(x4)
+  && clobber(x5)
+  && clobber(x6)
+  && clobber(x7)
+  && clobber(s0)
+  && clobber(s1)
+  && clobber(s2)
+  && clobber(s3)
+  && clobber(s4)
+  && clobber(s5)
+  && clobber(s6)
+  && clobber(o0)
+  && clobber(o1)
+  && clobber(o2)
+  && clobber(o3)
+  && clobber(o4)
+  && clobber(o5)
+  -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQload [i] {s} p mem)
+
+(ORL                  x0:(MOVBloadidx1 [i]   {s} p idx mem)
+    s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && s0.Uses == 1
+  && mergePoint(b,x0,x1) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(s0)
+  -> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
+
+(ORL o0:(ORL o1:(ORL
+                       x0:(MOVBloadidx1 [i]   {s} p idx mem)
+    s0:(SHLLconst [8]  x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+    s1:(SHLLconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem)))
+    s2:(SHLLconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && x2.Uses == 1
+  && x3.Uses == 1
+  && s0.Uses == 1
+  && s1.Uses == 1
+  && s2.Uses == 1
+  && o0.Uses == 1
+  && o1.Uses == 1
+  && mergePoint(b,x0,x1,x2,x3) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(x2)
+  && clobber(x3)
+  && clobber(s0)
+  && clobber(s1)
+  && clobber(s2)
+  && clobber(o0)
+  && clobber(o1)
+  -> @mergePoint(b,x0,x1,x2,x3) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+
+(ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ
+                       x0:(MOVBloadidx1 [i]   {s} p idx mem)
+    s0:(SHLQconst [8]  x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+    s1:(SHLQconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem)))
+    s2:(SHLQconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
+    s3:(SHLQconst [32] x4:(MOVBloadidx1 [i+4] {s} p idx mem)))
+    s4:(SHLQconst [40] x5:(MOVBloadidx1 [i+5] {s} p idx mem)))
+    s5:(SHLQconst [48] x6:(MOVBloadidx1 [i+6] {s} p idx mem)))
+    s6:(SHLQconst [56] x7:(MOVBloadidx1 [i+7] {s} p idx mem)))
+  && x0.Uses == 1
+  && x1.Uses == 1
+  && x2.Uses == 1
+  && x3.Uses == 1
+  && x4.Uses == 1
+  && x5.Uses == 1
+  && x6.Uses == 1
+  && x7.Uses == 1
+  && s0.Uses == 1
+  && s1.Uses == 1
+  && s2.Uses == 1
+  && s3.Uses == 1
+  && s4.Uses == 1
+  && s5.Uses == 1
+  && s6.Uses == 1
+  && o0.Uses == 1
+  && o1.Uses == 1
+  && o2.Uses == 1
+  && o3.Uses == 1
+  && o4.Uses == 1
+  && o5.Uses == 1
+  && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+  && clobber(x0)
+  && clobber(x1)
+  && clobber(x2)
+  && clobber(x3)
+  && clobber(x4)
+  && clobber(x5)
+  && clobber(x6)
+  && clobber(x7)
+  && clobber(s0)
+  && clobber(s1)
+  && clobber(s2)
+  && clobber(s3)
+  && clobber(s4)
+  && clobber(s5)
+  && clobber(s6)
+  && clobber(o0)
+  && clobber(o1)
+  && clobber(o2)
+  && clobber(o3)
+  && clobber(o4)
+  && clobber(o5)
+  -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQloadidx1 <v.Type> [i] {s} p idx mem)
+
+// Combine constant stores into larger (unaligned) stores.
+(MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
+  && x.Uses == 1
+  && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
+  && clobber(x)
+  -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
+(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
+  && x.Uses == 1
+  && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
+  && clobber(x)
+  -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
+(MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem))
+  && x.Uses == 1
+  && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
+  && clobber(x)
+  -> (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
+
+(MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
+  && x.Uses == 1
+  && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
+  && clobber(x)
+  -> (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
+(MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
+  && x.Uses == 1
+  && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
+  && clobber(x)
+  -> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
+(MOVLstoreconstidx1 [c] {s} p i x:(MOVLstoreconstidx1 [a] {s} p i mem))
+  && x.Uses == 1
+  && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
+  && clobber(x)
+  -> (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p i (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
+
+(MOVWstoreconstidx2 [c] {s} p i x:(MOVWstoreconstidx2 [a] {s} p i mem))
+  && x.Uses == 1
+  && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
+  && clobber(x)
+  -> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLQconst <i.Type> [1] i) mem)
+(MOVLstoreconstidx4 [c] {s} p i x:(MOVLstoreconstidx4 [a] {s} p i mem))
+  && x.Uses == 1
+  && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
+  && clobber(x)
+  -> (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p (SHLQconst <i.Type> [2] i) (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
+
+// Combine stores into larger (unaligned) stores.
+(MOVBstore [i] {s} p (SHRQconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVWstore [i-1] {s} p w mem)
+(MOVBstore [i] {s} p (SHRQconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRQconst [j-8] w) mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVWstore [i-1] {s} p w0 mem)
+(MOVWstore [i] {s} p (SHRQconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVLstore [i-2] {s} p w mem)
+(MOVWstore [i] {s} p (SHRQconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRQconst [j-16] w) mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVLstore [i-2] {s} p w0 mem)
+(MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVQstore [i-4] {s} p w mem)
+(MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVQstore [i-4] {s} p w0 mem)
+
+(MOVBstoreidx1 [i] {s} p idx (SHRQconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVWstoreidx1 [i-1] {s} p idx w mem)
+(MOVBstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRQconst [j-8] w) mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
+(MOVWstoreidx1 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVLstoreidx1 [i-2] {s} p idx w mem)
+(MOVWstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVLstoreidx1 [i-2] {s} p idx w0 mem)
+(MOVLstoreidx1 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx1 [i-4] {s} p idx w mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVQstoreidx1 [i-4] {s} p idx w mem)
+(MOVLstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx1 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVQstoreidx1 [i-4] {s} p idx w0 mem)
+
+(MOVWstoreidx2 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w mem)
+(MOVWstoreidx2 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w0 mem)
+(MOVLstoreidx4 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx4 [i-4] {s} p idx w mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w mem)
+(MOVLstoreidx4 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx4 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
+  && x.Uses == 1
+  && clobber(x)
+  -> (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w0 mem)
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
new file mode 100644
index 0000000..b684b9c
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -0,0 +1,555 @@
+// Copyright 2015 The Go 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 "strings"
+
+// Notes:
+//  - Integer types live in the low portion of registers. Upper portions are junk.
+//  - Boolean types use the low-order byte of a register. 0=false, 1=true.
+//    Upper bytes are junk.
+//  - Floating-point types live in the low natural slot of an sse2 register.
+//    Unused portions are junk.
+//  - We do not use AH,BH,CH,DH registers.
+//  - When doing sub-register operations, we try to write the whole
+//    destination register to avoid a partial-register write.
+//  - Unused portions of AuxInt (or the Val portion of ValAndOff) are
+//    filled by sign-extending the used portion.  Users of AuxInt which interpret
+//    AuxInt as unsigned (e.g. shifts) must be careful.
+
+// Suffixes encode the bit width of various instructions.
+// Q (quad word) = 64 bit
+// L (long word) = 32 bit
+// W (word)      = 16 bit
+// B (byte)      = 8 bit
+
+// copied from ../../amd64/reg.go
+var regNamesAMD64 = []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",
+
+	// pseudo-registers
+	"SB",
+	"FLAGS",
+}
+
+func init() {
+	// Make map from reg names to reg integers.
+	if len(regNamesAMD64) > 64 {
+		panic("too many registers")
+	}
+	num := map[string]int{}
+	for i, name := range regNamesAMD64 {
+		num[name] = i
+	}
+	buildReg := func(s string) regMask {
+		m := regMask(0)
+		for _, r := range strings.Split(s, " ") {
+			if n, ok := num[r]; ok {
+				m |= regMask(1) << uint(n)
+				continue
+			}
+			panic("register " + r + " not found")
+		}
+		return m
+	}
+
+	// Common individual register masks
+	var (
+		ax         = buildReg("AX")
+		cx         = buildReg("CX")
+		dx         = buildReg("DX")
+		x15        = buildReg("X15")
+		gp         = buildReg("AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15")
+		fp         = buildReg("X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15")
+		gpsp       = gp | buildReg("SP")
+		gpspsb     = gpsp | buildReg("SB")
+		flags      = buildReg("FLAGS")
+		callerSave = gp | fp | flags
+	)
+	// Common slices of register masks
+	var (
+		gponly    = []regMask{gp}
+		fponly    = []regMask{fp}
+		flagsonly = []regMask{flags}
+	)
+
+	// Common regInfo
+	var (
+		gp01      = regInfo{inputs: []regMask{}, outputs: gponly}
+		gp11      = regInfo{inputs: []regMask{gp}, outputs: gponly, clobbers: flags}
+		gp11sp    = regInfo{inputs: []regMask{gpsp}, outputs: gponly, clobbers: flags}
+		gp11nf    = regInfo{inputs: []regMask{gpsp}, outputs: gponly} // nf: no flags clobbered
+		gp11sb    = regInfo{inputs: []regMask{gpspsb}, outputs: gponly}
+		gp21      = regInfo{inputs: []regMask{gp, gp}, outputs: gponly, clobbers: flags}
+		gp21sp    = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly, clobbers: flags}
+		gp21sb    = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly}
+		gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}, clobbers: flags}
+		gp11div   = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax},
+			clobbers: dx | flags}
+		gp11hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx},
+			clobbers: ax | flags}
+		gp11mod = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{dx},
+			clobbers: ax | flags}
+
+		gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}, outputs: flagsonly}
+		gp1flags = regInfo{inputs: []regMask{gpsp}, outputs: flagsonly}
+		flagsgp  = regInfo{inputs: flagsonly, outputs: gponly}
+
+		// for CMOVconst -- uses AX to hold constant temporary.
+		gp1flagsgp = regInfo{inputs: []regMask{gp &^ ax, flags}, clobbers: ax | flags, outputs: []regMask{gp &^ ax}}
+
+		readflags = regInfo{inputs: flagsonly, outputs: gponly}
+		flagsgpax = regInfo{inputs: flagsonly, clobbers: ax | flags, outputs: []regMask{gp &^ ax}}
+
+		gpload    = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly}
+		gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly}
+
+		gpstore         = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
+		gpstoreconst    = regInfo{inputs: []regMask{gpspsb, 0}}
+		gpstoreidx      = regInfo{inputs: []regMask{gpspsb, gpsp, gpsp, 0}}
+		gpstoreconstidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
+
+		fp01    = regInfo{inputs: []regMask{}, outputs: fponly}
+		fp21    = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
+		fp21x15 = regInfo{inputs: []regMask{fp &^ x15, fp &^ x15},
+			clobbers: x15, outputs: []regMask{fp &^ x15}}
+		fpgp     = regInfo{inputs: fponly, outputs: gponly}
+		gpfp     = regInfo{inputs: gponly, outputs: fponly}
+		fp11     = regInfo{inputs: fponly, outputs: fponly}
+		fp2flags = regInfo{inputs: []regMask{fp, fp}, outputs: flagsonly}
+
+		fpload    = regInfo{inputs: []regMask{gpspsb, 0}, outputs: fponly}
+		fploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: fponly}
+
+		fpstore    = regInfo{inputs: []regMask{gpspsb, fp, 0}}
+		fpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, fp, 0}}
+	)
+
+	var AMD64ops = []opData{
+		// fp ops
+		{name: "ADDSS", argLength: 2, reg: fp21, asm: "ADDSS", commutative: true, resultInArg0: true}, // fp32 add
+		{name: "ADDSD", argLength: 2, reg: fp21, asm: "ADDSD", commutative: true, resultInArg0: true}, // fp64 add
+		{name: "SUBSS", argLength: 2, reg: fp21x15, asm: "SUBSS", resultInArg0: true},                 // fp32 sub
+		{name: "SUBSD", argLength: 2, reg: fp21x15, asm: "SUBSD", resultInArg0: true},                 // fp64 sub
+		{name: "MULSS", argLength: 2, reg: fp21, asm: "MULSS", commutative: true, resultInArg0: true}, // fp32 mul
+		{name: "MULSD", argLength: 2, reg: fp21, asm: "MULSD", commutative: true, resultInArg0: true}, // fp64 mul
+		{name: "DIVSS", argLength: 2, reg: fp21x15, asm: "DIVSS", resultInArg0: true},                 // fp32 div
+		{name: "DIVSD", argLength: 2, reg: fp21x15, asm: "DIVSD", resultInArg0: true},                 // fp64 div
+
+		{name: "MOVSSload", argLength: 2, reg: fpload, asm: "MOVSS", aux: "SymOff"},            // fp32 load
+		{name: "MOVSDload", argLength: 2, reg: fpload, asm: "MOVSD", aux: "SymOff"},            // fp64 load
+		{name: "MOVSSconst", reg: fp01, asm: "MOVSS", aux: "Float32", rematerializeable: true}, // fp32 constant
+		{name: "MOVSDconst", reg: fp01, asm: "MOVSD", aux: "Float64", rematerializeable: true}, // fp64 constant
+		{name: "MOVSSloadidx1", argLength: 3, reg: fploadidx, asm: "MOVSS", aux: "SymOff"},     // fp32 load indexed by i
+		{name: "MOVSSloadidx4", argLength: 3, reg: fploadidx, asm: "MOVSS", aux: "SymOff"},     // fp32 load indexed by 4*i
+		{name: "MOVSDloadidx1", argLength: 3, reg: fploadidx, asm: "MOVSD", aux: "SymOff"},     // fp64 load indexed by i
+		{name: "MOVSDloadidx8", argLength: 3, reg: fploadidx, asm: "MOVSD", aux: "SymOff"},     // fp64 load indexed by 8*i
+
+		{name: "MOVSSstore", argLength: 3, reg: fpstore, asm: "MOVSS", aux: "SymOff"},        // fp32 store
+		{name: "MOVSDstore", argLength: 3, reg: fpstore, asm: "MOVSD", aux: "SymOff"},        // fp64 store
+		{name: "MOVSSstoreidx1", argLength: 4, reg: fpstoreidx, asm: "MOVSS", aux: "SymOff"}, // fp32 indexed by i store
+		{name: "MOVSSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "MOVSS", aux: "SymOff"}, // fp32 indexed by 4i store
+		{name: "MOVSDstoreidx1", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff"}, // fp64 indexed by i store
+		{name: "MOVSDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff"}, // fp64 indexed by 8i store
+
+		// binary ops
+		{name: "ADDQ", argLength: 2, reg: gp21sp, asm: "ADDQ", commutative: true},                // arg0 + arg1
+		{name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true},                // arg0 + arg1
+		{name: "ADDQconst", argLength: 1, reg: gp11sp, asm: "ADDQ", aux: "Int64", typ: "UInt64"}, // arg0 + auxint
+		{name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32"},                // arg0 + auxint
+
+		{name: "SUBQ", argLength: 2, reg: gp21, asm: "SUBQ", resultInArg0: true},                    // arg0 - arg1
+		{name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true},                    // arg0 - arg1
+		{name: "SUBQconst", argLength: 1, reg: gp11, asm: "SUBQ", aux: "Int64", resultInArg0: true}, // arg0 - auxint
+		{name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true}, // arg0 - auxint
+
+		{name: "MULQ", argLength: 2, reg: gp21, asm: "IMULQ", commutative: true, resultInArg0: true}, // arg0 * arg1
+		{name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true}, // arg0 * arg1
+		{name: "MULQconst", argLength: 1, reg: gp11, asm: "IMULQ", aux: "Int64", resultInArg0: true}, // arg0 * auxint
+		{name: "MULLconst", argLength: 1, reg: gp11, asm: "IMULL", aux: "Int32", resultInArg0: true}, // arg0 * auxint
+
+		{name: "HMULQ", argLength: 2, reg: gp11hmul, asm: "IMULQ"}, // (arg0 * arg1) >> width
+		{name: "HMULL", argLength: 2, reg: gp11hmul, asm: "IMULL"}, // (arg0 * arg1) >> width
+		{name: "HMULW", argLength: 2, reg: gp11hmul, asm: "IMULW"}, // (arg0 * arg1) >> width
+		{name: "HMULB", argLength: 2, reg: gp11hmul, asm: "IMULB"}, // (arg0 * arg1) >> width
+		{name: "HMULQU", argLength: 2, reg: gp11hmul, asm: "MULQ"}, // (arg0 * arg1) >> width
+		{name: "HMULLU", argLength: 2, reg: gp11hmul, asm: "MULL"}, // (arg0 * arg1) >> width
+		{name: "HMULWU", argLength: 2, reg: gp11hmul, asm: "MULW"}, // (arg0 * arg1) >> width
+		{name: "HMULBU", argLength: 2, reg: gp11hmul, asm: "MULB"}, // (arg0 * arg1) >> width
+
+		{name: "AVGQU", argLength: 2, reg: gp21, commutative: true, resultInArg0: true}, // (arg0 + arg1) / 2 as unsigned, all 64 result bits
+
+		{name: "DIVQ", argLength: 2, reg: gp11div, asm: "IDIVQ"}, // arg0 / arg1
+		{name: "DIVL", argLength: 2, reg: gp11div, asm: "IDIVL"}, // arg0 / arg1
+		{name: "DIVW", argLength: 2, reg: gp11div, asm: "IDIVW"}, // arg0 / arg1
+		{name: "DIVQU", argLength: 2, reg: gp11div, asm: "DIVQ"}, // arg0 / arg1
+		{name: "DIVLU", argLength: 2, reg: gp11div, asm: "DIVL"}, // arg0 / arg1
+		{name: "DIVWU", argLength: 2, reg: gp11div, asm: "DIVW"}, // arg0 / arg1
+
+		{name: "MODQ", argLength: 2, reg: gp11mod, asm: "IDIVQ"}, // arg0 % arg1
+		{name: "MODL", argLength: 2, reg: gp11mod, asm: "IDIVL"}, // arg0 % arg1
+		{name: "MODW", argLength: 2, reg: gp11mod, asm: "IDIVW"}, // arg0 % arg1
+		{name: "MODQU", argLength: 2, reg: gp11mod, asm: "DIVQ"}, // arg0 % arg1
+		{name: "MODLU", argLength: 2, reg: gp11mod, asm: "DIVL"}, // arg0 % arg1
+		{name: "MODWU", argLength: 2, reg: gp11mod, asm: "DIVW"}, // arg0 % arg1
+
+		{name: "ANDQ", argLength: 2, reg: gp21, asm: "ANDQ", commutative: true, resultInArg0: true}, // arg0 & arg1
+		{name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true}, // arg0 & arg1
+		{name: "ANDQconst", argLength: 1, reg: gp11, asm: "ANDQ", aux: "Int64", resultInArg0: true}, // arg0 & auxint
+		{name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true}, // arg0 & auxint
+
+		{name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ", commutative: true, resultInArg0: true}, // arg0 | arg1
+		{name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true}, // arg0 | arg1
+		{name: "ORQconst", argLength: 1, reg: gp11, asm: "ORQ", aux: "Int64", resultInArg0: true}, // arg0 | auxint
+		{name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true}, // arg0 | auxint
+
+		{name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ", commutative: true, resultInArg0: true}, // arg0 ^ arg1
+		{name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true}, // arg0 ^ arg1
+		{name: "XORQconst", argLength: 1, reg: gp11, asm: "XORQ", aux: "Int64", resultInArg0: true}, // arg0 ^ auxint
+		{name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true}, // arg0 ^ auxint
+
+		{name: "CMPQ", argLength: 2, reg: gp2flags, asm: "CMPQ", typ: "Flags"},                    // arg0 compare to arg1
+		{name: "CMPL", argLength: 2, reg: gp2flags, asm: "CMPL", typ: "Flags"},                    // arg0 compare to arg1
+		{name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"},                    // arg0 compare to arg1
+		{name: "CMPB", argLength: 2, reg: gp2flags, asm: "CMPB", typ: "Flags"},                    // arg0 compare to arg1
+		{name: "CMPQconst", argLength: 1, reg: gp1flags, asm: "CMPQ", typ: "Flags", aux: "Int64"}, // arg0 compare to auxint
+		{name: "CMPLconst", argLength: 1, reg: gp1flags, asm: "CMPL", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint
+		{name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", typ: "Flags", aux: "Int16"}, // arg0 compare to auxint
+		{name: "CMPBconst", argLength: 1, reg: gp1flags, asm: "CMPB", typ: "Flags", aux: "Int8"},  // arg0 compare to auxint
+
+		{name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32
+		{name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64
+
+		{name: "TESTQ", argLength: 2, reg: gp2flags, asm: "TESTQ", typ: "Flags"},                    // (arg0 & arg1) compare to 0
+		{name: "TESTL", argLength: 2, reg: gp2flags, asm: "TESTL", typ: "Flags"},                    // (arg0 & arg1) compare to 0
+		{name: "TESTW", argLength: 2, reg: gp2flags, asm: "TESTW", typ: "Flags"},                    // (arg0 & arg1) compare to 0
+		{name: "TESTB", argLength: 2, reg: gp2flags, asm: "TESTB", typ: "Flags"},                    // (arg0 & arg1) compare to 0
+		{name: "TESTQconst", argLength: 1, reg: gp1flags, asm: "TESTQ", typ: "Flags", aux: "Int64"}, // (arg0 & auxint) compare to 0
+		{name: "TESTLconst", argLength: 1, reg: gp1flags, asm: "TESTL", typ: "Flags", aux: "Int32"}, // (arg0 & auxint) compare to 0
+		{name: "TESTWconst", argLength: 1, reg: gp1flags, asm: "TESTW", typ: "Flags", aux: "Int16"}, // (arg0 & auxint) compare to 0
+		{name: "TESTBconst", argLength: 1, reg: gp1flags, asm: "TESTB", typ: "Flags", aux: "Int8"},  // (arg0 & auxint) compare to 0
+
+		{name: "SHLQ", argLength: 2, reg: gp21shift, asm: "SHLQ", resultInArg0: true},               // arg0 << arg1, shift amount is mod 64
+		{name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true},               // arg0 << arg1, shift amount is mod 32
+		{name: "SHLQconst", argLength: 1, reg: gp11, asm: "SHLQ", aux: "Int64", resultInArg0: true}, // arg0 << auxint, shift amount 0-63
+		{name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int32", resultInArg0: true}, // arg0 << auxint, shift amount 0-31
+		// Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
+
+		{name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true},               // unsigned arg0 >> arg1, shift amount is mod 64
+		{name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true},               // unsigned arg0 >> arg1, shift amount is mod 32
+		{name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true},               // unsigned arg0 >> arg1, shift amount is mod 32
+		{name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true},               // unsigned arg0 >> arg1, shift amount is mod 32
+		{name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int64", resultInArg0: true}, // unsigned arg0 >> auxint, shift amount 0-63
+		{name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int32", resultInArg0: true}, // unsigned arg0 >> auxint, shift amount 0-31
+		{name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int16", resultInArg0: true}, // unsigned arg0 >> auxint, shift amount 0-31
+		{name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true},  // unsigned arg0 >> auxint, shift amount 0-31
+
+		{name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true},               // signed arg0 >> arg1, shift amount is mod 64
+		{name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true},               // signed arg0 >> arg1, shift amount is mod 32
+		{name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true},               // signed arg0 >> arg1, shift amount is mod 32
+		{name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true},               // signed arg0 >> arg1, shift amount is mod 32
+		{name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int64", resultInArg0: true}, // signed arg0 >> auxint, shift amount 0-63
+		{name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int32", resultInArg0: true}, // signed arg0 >> auxint, shift amount 0-31
+		{name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int16", resultInArg0: true}, // signed arg0 >> auxint, shift amount 0-31
+		{name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true},  // signed arg0 >> auxint, shift amount 0-31
+
+		{name: "ROLQconst", argLength: 1, reg: gp11, asm: "ROLQ", aux: "Int64", resultInArg0: true}, // arg0 rotate left auxint, rotate amount 0-63
+		{name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int32", resultInArg0: true}, // arg0 rotate left auxint, rotate amount 0-31
+		{name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int16", resultInArg0: true}, // arg0 rotate left auxint, rotate amount 0-15
+		{name: "ROLBconst", argLength: 1, reg: gp11, asm: "ROLB", aux: "Int8", resultInArg0: true},  // arg0 rotate left auxint, rotate amount 0-7
+
+		// unary ops
+		{name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ", resultInArg0: true}, // -arg0
+		{name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true}, // -arg0
+
+		{name: "NOTQ", argLength: 1, reg: gp11, asm: "NOTQ", resultInArg0: true}, // ^arg0
+		{name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true}, // ^arg0
+
+		{name: "BSFQ", argLength: 1, reg: gp11, asm: "BSFQ"}, // arg0 # of low-order zeroes ; undef if zero
+		{name: "BSFL", argLength: 1, reg: gp11, asm: "BSFL"}, // arg0 # of low-order zeroes ; undef if zero
+		{name: "BSFW", argLength: 1, reg: gp11, asm: "BSFW"}, // arg0 # of low-order zeroes ; undef if zero
+
+		{name: "BSRQ", argLength: 1, reg: gp11, asm: "BSRQ"}, // arg0 # of high-order zeroes ; undef if zero
+		{name: "BSRL", argLength: 1, reg: gp11, asm: "BSRL"}, // arg0 # of high-order zeroes ; undef if zero
+		{name: "BSRW", argLength: 1, reg: gp11, asm: "BSRW"}, // arg0 # of high-order zeroes ; undef if zero
+
+		// Note ASM for ops moves whole register
+		{name: "CMOVQEQconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVQEQ", typ: "UInt64", aux: "Int64", resultInArg0: true}, // replace arg0 w/ constant if Z set
+		{name: "CMOVLEQconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVLEQ", typ: "UInt32", aux: "Int32", resultInArg0: true}, // replace arg0 w/ constant if Z set
+		{name: "CMOVWEQconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVLEQ", typ: "UInt16", aux: "Int16", resultInArg0: true}, // replace arg0 w/ constant if Z set
+		{name: "CMOVQNEconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVQNE", typ: "UInt64", aux: "Int64", resultInArg0: true}, // replace arg0 w/ constant if Z not set
+		{name: "CMOVLNEconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVLNE", typ: "UInt32", aux: "Int32", resultInArg0: true}, // replace arg0 w/ constant if Z not set
+		{name: "CMOVWNEconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVLNE", typ: "UInt16", aux: "Int16", resultInArg0: true}, // replace arg0 w/ constant if Z not set
+
+		{name: "BSWAPQ", argLength: 1, reg: gp11, asm: "BSWAPQ", resultInArg0: true}, // arg0 swap bytes
+		{name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true}, // arg0 swap bytes
+
+		{name: "SQRTSD", argLength: 1, reg: fp11, asm: "SQRTSD"}, // sqrt(arg0)
+
+		{name: "SBBQcarrymask", argLength: 1, reg: flagsgp, asm: "SBBQ"}, // (int64)(-1) if carry is set, 0 if carry is clear.
+		{name: "SBBLcarrymask", argLength: 1, reg: flagsgp, asm: "SBBL"}, // (int32)(-1) if carry is set, 0 if carry is clear.
+		// Note: SBBW and SBBB are subsumed by SBBL
+
+		{name: "SETEQ", argLength: 1, reg: readflags, asm: "SETEQ"}, // extract == condition from arg0
+		{name: "SETNE", argLength: 1, reg: readflags, asm: "SETNE"}, // extract != condition from arg0
+		{name: "SETL", argLength: 1, reg: readflags, asm: "SETLT"},  // extract signed < condition from arg0
+		{name: "SETLE", argLength: 1, reg: readflags, asm: "SETLE"}, // extract signed <= condition from arg0
+		{name: "SETG", argLength: 1, reg: readflags, asm: "SETGT"},  // extract signed > condition from arg0
+		{name: "SETGE", argLength: 1, reg: readflags, asm: "SETGE"}, // extract signed >= condition from arg0
+		{name: "SETB", argLength: 1, reg: readflags, asm: "SETCS"},  // extract unsigned < condition from arg0
+		{name: "SETBE", argLength: 1, reg: readflags, asm: "SETLS"}, // extract unsigned <= condition from arg0
+		{name: "SETA", argLength: 1, reg: readflags, asm: "SETHI"},  // extract unsigned > condition from arg0
+		{name: "SETAE", argLength: 1, reg: readflags, asm: "SETCC"}, // extract unsigned >= condition from arg0
+		// Need different opcodes for floating point conditions because
+		// any comparison involving a NaN is always FALSE and thus
+		// the patterns for inverting conditions cannot be used.
+		{name: "SETEQF", argLength: 1, reg: flagsgpax, asm: "SETEQ"}, // extract == condition from arg0
+		{name: "SETNEF", argLength: 1, reg: flagsgpax, asm: "SETNE"}, // extract != condition from arg0
+		{name: "SETORD", argLength: 1, reg: flagsgp, asm: "SETPC"},   // extract "ordered" (No Nan present) condition from arg0
+		{name: "SETNAN", argLength: 1, reg: flagsgp, asm: "SETPS"},   // extract "unordered" (Nan present) condition from arg0
+
+		{name: "SETGF", argLength: 1, reg: flagsgp, asm: "SETHI"},  // extract floating > condition from arg0
+		{name: "SETGEF", argLength: 1, reg: flagsgp, asm: "SETCC"}, // extract floating >= condition from arg0
+
+		{name: "MOVBQSX", argLength: 1, reg: gp11nf, asm: "MOVBQSX"}, // sign extend arg0 from int8 to int64
+		{name: "MOVBQZX", argLength: 1, reg: gp11nf, asm: "MOVBQZX"}, // zero extend arg0 from int8 to int64
+		{name: "MOVWQSX", argLength: 1, reg: gp11nf, asm: "MOVWQSX"}, // sign extend arg0 from int16 to int64
+		{name: "MOVWQZX", argLength: 1, reg: gp11nf, asm: "MOVWQZX"}, // zero extend arg0 from int16 to int64
+		{name: "MOVLQSX", argLength: 1, reg: gp11nf, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64
+		{name: "MOVLQZX", argLength: 1, reg: gp11nf, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64
+
+		{name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint
+		{name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
+
+		{name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL"}, // convert float64 to int32
+		{name: "CVTTSD2SQ", argLength: 1, reg: fpgp, asm: "CVTTSD2SQ"}, // convert float64 to int64
+		{name: "CVTTSS2SL", argLength: 1, reg: fpgp, asm: "CVTTSS2SL"}, // convert float32 to int32
+		{name: "CVTTSS2SQ", argLength: 1, reg: fpgp, asm: "CVTTSS2SQ"}, // convert float32 to int64
+		{name: "CVTSL2SS", argLength: 1, reg: gpfp, asm: "CVTSL2SS"},   // convert int32 to float32
+		{name: "CVTSL2SD", argLength: 1, reg: gpfp, asm: "CVTSL2SD"},   // convert int32 to float64
+		{name: "CVTSQ2SS", argLength: 1, reg: gpfp, asm: "CVTSQ2SS"},   // convert int64 to float32
+		{name: "CVTSQ2SD", argLength: 1, reg: gpfp, asm: "CVTSQ2SD"},   // convert int64 to float64
+		{name: "CVTSD2SS", argLength: 1, reg: fp11, asm: "CVTSD2SS"},   // convert float64 to float32
+		{name: "CVTSS2SD", argLength: 1, reg: fp11, asm: "CVTSS2SD"},   // convert float32 to float64
+
+		{name: "PXOR", argLength: 2, reg: fp21, asm: "PXOR", commutative: true, resultInArg0: true}, // exclusive or, applied to X regs for float negation.
+
+		{name: "LEAQ", argLength: 1, reg: gp11sb, aux: "SymOff", rematerializeable: true}, // arg0 + auxint + offset encoded in aux
+		{name: "LEAQ1", argLength: 2, reg: gp21sb, aux: "SymOff"},                         // arg0 + arg1 + auxint + aux
+		{name: "LEAQ2", argLength: 2, reg: gp21sb, aux: "SymOff"},                         // arg0 + 2*arg1 + auxint + aux
+		{name: "LEAQ4", argLength: 2, reg: gp21sb, aux: "SymOff"},                         // arg0 + 4*arg1 + auxint + aux
+		{name: "LEAQ8", argLength: 2, reg: gp21sb, aux: "SymOff"},                         // arg0 + 8*arg1 + auxint + aux
+		// Note: LEAQ{1,2,4,8} must not have OpSB as either argument.
+
+		// auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address
+		{name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8"},  // load byte from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVBQSXload", argLength: 2, reg: gpload, asm: "MOVBQSX", aux: "SymOff"},             // ditto, sign extend to int64
+		{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16"}, // load 2 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVWQSXload", argLength: 2, reg: gpload, asm: "MOVWQSX", aux: "SymOff"},             // ditto, sign extend to int64
+		{name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32"},    // load 4 bytes from arg0+auxint+aux. arg1=mem.  Zero extend.
+		{name: "MOVLQSXload", argLength: 2, reg: gpload, asm: "MOVLQSX", aux: "SymOff"},             // ditto, sign extend to int64
+		{name: "MOVQload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64"},    // load 8 bytes from arg0+auxint+aux. arg1=mem
+		{name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem"},     // store byte in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem"},     // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem"},     // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVQstore", argLength: 3, reg: gpstore, asm: "MOVQ", aux: "SymOff", typ: "Mem"},     // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
+		{name: "MOVOload", argLength: 2, reg: fpload, asm: "MOVUPS", aux: "SymOff", typ: "Int128"},  // load 16 bytes from arg0+auxint+aux. arg1=mem
+		{name: "MOVOstore", argLength: 3, reg: fpstore, asm: "MOVUPS", aux: "SymOff", typ: "Mem"},   // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem
+
+		// indexed loads/stores
+		{name: "MOVBloadidx1", argLength: 3, reg: gploadidx, asm: "MOVBLZX", aux: "SymOff"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVWloadidx1", argLength: 3, reg: gploadidx, asm: "MOVWLZX", aux: "SymOff"}, // load 2 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVWloadidx2", argLength: 3, reg: gploadidx, asm: "MOVWLZX", aux: "SymOff"}, // load 2 bytes from arg0+2*arg1+auxint+aux. arg2=mem
+		{name: "MOVLloadidx1", argLength: 3, reg: gploadidx, asm: "MOVL", aux: "SymOff"},    // load 4 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVLloadidx4", argLength: 3, reg: gploadidx, asm: "MOVL", aux: "SymOff"},    // load 4 bytes from arg0+4*arg1+auxint+aux. arg2=mem
+		{name: "MOVQloadidx1", argLength: 3, reg: gploadidx, asm: "MOVQ", aux: "SymOff"},    // load 8 bytes from arg0+arg1+auxint+aux. arg2=mem
+		{name: "MOVQloadidx8", argLength: 3, reg: gploadidx, asm: "MOVQ", aux: "SymOff"},    // load 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem
+		// TODO: sign-extending indexed loads
+		{name: "MOVBstoreidx1", argLength: 4, reg: gpstoreidx, asm: "MOVB", aux: "SymOff"}, // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVWstoreidx1", argLength: 4, reg: gpstoreidx, asm: "MOVW", aux: "SymOff"}, // store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVWstoreidx2", argLength: 4, reg: gpstoreidx, asm: "MOVW", aux: "SymOff"}, // store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem
+		{name: "MOVLstoreidx1", argLength: 4, reg: gpstoreidx, asm: "MOVL", aux: "SymOff"}, // store 4 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVLstoreidx4", argLength: 4, reg: gpstoreidx, asm: "MOVL", aux: "SymOff"}, // store 4 bytes in arg2 to arg0+4*arg1+auxint+aux. arg3=mem
+		{name: "MOVQstoreidx1", argLength: 4, reg: gpstoreidx, asm: "MOVQ", aux: "SymOff"}, // store 8 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem
+		{name: "MOVQstoreidx8", argLength: 4, reg: gpstoreidx, asm: "MOVQ", aux: "SymOff"}, // store 8 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem
+		// TODO: add size-mismatched indexed loads, like MOVBstoreidx4.
+
+		// For storeconst ops, the AuxInt field encodes both
+		// the value to store and an address offset of the store.
+		// Cast AuxInt to a ValAndOff to extract Val and Off fields.
+		{name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux.  arg1=mem
+		{name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem"}, // store low 2 bytes of ...
+		{name: "MOVLstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem"}, // store low 4 bytes of ...
+		{name: "MOVQstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ...
+
+		{name: "MOVBstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVB", aux: "SymValAndOff", typ: "Mem"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+1*arg1+ValAndOff(AuxInt).Off()+aux.  arg2=mem
+		{name: "MOVWstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVW", aux: "SymValAndOff", typ: "Mem"}, // store low 2 bytes of ... arg1 ...
+		{name: "MOVWstoreconstidx2", argLength: 3, reg: gpstoreconstidx, asm: "MOVW", aux: "SymValAndOff", typ: "Mem"}, // store low 2 bytes of ... 2*arg1 ...
+		{name: "MOVLstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVL", aux: "SymValAndOff", typ: "Mem"}, // store low 4 bytes of ... arg1 ...
+		{name: "MOVLstoreconstidx4", argLength: 3, reg: gpstoreconstidx, asm: "MOVL", aux: "SymValAndOff", typ: "Mem"}, // store low 4 bytes of ... 4*arg1 ...
+		{name: "MOVQstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ... arg1 ...
+		{name: "MOVQstoreconstidx8", argLength: 3, reg: gpstoreconstidx, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ... 8*arg1 ...
+
+		// arg0 = (duff-adjusted) pointer to start of memory to zero
+		// arg1 = value to store (will always be zero)
+		// arg2 = mem
+		// auxint = offset into duffzero code to start executing
+		// returns mem
+		{
+			name:      "DUFFZERO",
+			aux:       "Int64",
+			argLength: 3,
+			reg: regInfo{
+				inputs:   []regMask{buildReg("DI"), buildReg("X0")},
+				clobbers: buildReg("DI FLAGS"),
+			},
+		},
+		{name: "MOVOconst", reg: regInfo{nil, 0, []regMask{fp}}, typ: "Int128", aux: "Int128", rematerializeable: true},
+
+		// arg0 = address of memory to zero
+		// arg1 = # of 8-byte words to zero
+		// arg2 = value to store (will always be zero)
+		// arg3 = mem
+		// returns mem
+		{
+			name:      "REPSTOSQ",
+			argLength: 4,
+			reg: regInfo{
+				inputs:   []regMask{buildReg("DI"), buildReg("CX"), buildReg("AX")},
+				clobbers: buildReg("DI CX"),
+			},
+		},
+
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"},                                // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLclosure", argLength: 3, reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, callerSave, nil}, aux: "Int64"}, // call function via closure.  arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
+		{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64"},                                  // call deferproc.  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64"},                                     // call newproc.  arg0=mem, auxint=argsize, returns mem
+		{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64"},           // call fn by pointer.  arg0=codeptr, arg1=mem, auxint=argsize, returns mem
+
+		// arg0 = destination pointer
+		// arg1 = source pointer
+		// arg2 = mem
+		// auxint = offset from duffcopy symbol to call
+		// returns memory
+		{
+			name:      "DUFFCOPY",
+			aux:       "Int64",
+			argLength: 3,
+			reg: regInfo{
+				inputs:   []regMask{buildReg("DI"), buildReg("SI")},
+				clobbers: buildReg("DI SI X0 FLAGS"), // uses X0 as a temporary
+			},
+		},
+
+		// arg0 = destination pointer
+		// arg1 = source pointer
+		// arg2 = # of 8-byte words to copy
+		// arg3 = mem
+		// returns memory
+		{
+			name:      "REPMOVSQ",
+			argLength: 4,
+			reg: regInfo{
+				inputs:   []regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")},
+				clobbers: buildReg("DI SI CX"),
+			},
+		},
+
+		// (InvertFlags (CMPQ a b)) == (CMPQ b a)
+		// So if we want (SETL (CMPQ a b)) but we can't do that because a is a constant,
+		// then we do (SETL (InvertFlags (CMPQ b a))) instead.
+		// Rewrites will convert this to (SETG (CMPQ b a)).
+		// InvertFlags is a pseudo-op which can't appear in assembly output.
+		{name: "InvertFlags", argLength: 1}, // reverse direction of arg0
+
+		// Pseudo-ops
+		{name: "LoweredGetG", argLength: 1, reg: gp01}, // arg0=mem
+		// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
+		// and sorts it to the very beginning of the block to prevent other
+		// use of DX (the closure pointer)
+		{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("DX")}}},
+		//arg0=ptr,arg1=mem, returns void.  Faults if ptr is nil.
+		{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpsp}, clobbers: flags}},
+
+		// MOVQconvert converts between pointers and integers.
+		// We have a special op for this so as to not confuse GC
+		// (particularly stack maps).  It takes a memory arg so it
+		// gets correctly ordered with respect to GC safepoints.
+		// arg0=ptr/int arg1=mem, output=int/ptr
+		{name: "MOVQconvert", argLength: 2, reg: gp11nf, asm: "MOVQ"},
+
+		// Constant flag values. For any comparison, there are 5 possible
+		// outcomes: the three from the signed total order (<,==,>) and the
+		// three from the unsigned total order. The == cases overlap.
+		// Note: there's a sixth "unordered" outcome for floating-point
+		// comparisons, but we don't use such a beast yet.
+		// These ops are for temporary use by rewrite rules. They
+		// cannot appear in the generated assembly.
+		{name: "FlagEQ"},     // equal
+		{name: "FlagLT_ULT"}, // signed < and unsigned <
+		{name: "FlagLT_UGT"}, // signed < and unsigned >
+		{name: "FlagGT_UGT"}, // signed > and unsigned <
+		{name: "FlagGT_ULT"}, // signed > and unsigned >
+	}
+
+	var AMD64blocks = []blockData{
+		{name: "EQ"},
+		{name: "NE"},
+		{name: "LT"},
+		{name: "LE"},
+		{name: "GT"},
+		{name: "GE"},
+		{name: "ULT"},
+		{name: "ULE"},
+		{name: "UGT"},
+		{name: "UGE"},
+		{name: "EQF"},
+		{name: "NEF"},
+		{name: "ORD"}, // FP, ordered comparison (parity zero)
+		{name: "NAN"}, // FP, unordered comparison (parity one)
+	}
+
+	archs = append(archs, arch{
+		name:     "AMD64",
+		pkg:      "cmd/internal/obj/x86",
+		genfile:  "../../amd64/ssa.go",
+		ops:      AMD64ops,
+		blocks:   AMD64blocks,
+		regnames: regNamesAMD64,
+	})
+}
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
new file mode 100644
index 0000000..273500f
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -0,0 +1,32 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+(Add32 x y) -> (ADD x y)
+
+(Const32 [val]) -> (MOVWconst [val])
+
+(Less32 x y) -> (LessThan (CMP x y))
+
+(OffPtr [off] ptr) -> (ADD (MOVWconst <config.Frontend().TypeInt32()> [off]) ptr)
+
+(Addr {sym} base) -> (ADDconst {sym} base)
+
+(Load <t> ptr mem) && is32BitInt(t) -> (MOVWload ptr mem)
+(Store [4] ptr val mem) -> (MOVWstore ptr val mem)
+
+(StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
+
+// Absorb LessThan into blocks.
+(If (LessThan cc) yes no) -> (LT cc yes no)
+
+
+
+// Optimizations
+
+(ADD (MOVWconst [c]) x) -> (ADDconst [c] x)
+(ADD x (MOVWconst [c])) -> (ADDconst [c] x)
+(MOVWload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+  (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+  (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go
new file mode 100644
index 0000000..23e8f63
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go
@@ -0,0 +1,68 @@
+// Copyright 2016 The Go 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
+
+func init() {
+	var (
+		gp01       = regInfo{inputs: []regMask{}, outputs: []regMask{31}}
+		gp11       = regInfo{inputs: []regMask{31}, outputs: []regMask{31}}
+		gp21       = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{31}}
+		gp2flags   = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{32}}
+		gpload     = regInfo{inputs: []regMask{31}, outputs: []regMask{31}}
+		gpstore    = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{}}
+		flagsgp    = regInfo{inputs: []regMask{32}, outputs: []regMask{31}}
+		callerSave = regMask(15)
+	)
+	ops := []opData{
+		{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true},  // arg0 + arg1
+		{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "SymOff"}, // arg0 + auxInt + aux.(*gc.Sym)
+
+		{name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", rematerializeable: true}, // 32 low bits of auxint
+
+		{name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
+
+		{name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW"},   // load from arg0 + auxInt + aux.  arg1=mem.
+		{name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW"}, // store 4 bytes of arg1 to arg0 + auxInt + aux.  arg2=mem.
+
+		{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym).  arg0=mem, auxint=argsize, returns mem
+
+		// pseudo-ops
+		{name: "LessThan", argLength: 1, reg: flagsgp}, // bool, 1 flags encode x<y 0 otherwise.
+	}
+
+	blocks := []blockData{
+		{name: "EQ"},
+		{name: "NE"},
+		{name: "LT"},
+		{name: "LE"},
+		{name: "GT"},
+		{name: "GE"},
+		{name: "ULT"},
+		{name: "ULE"},
+		{name: "UGT"},
+		{name: "UGE"},
+	}
+
+	regNames := []string{
+		"R0",
+		"R1",
+		"R2",
+		"R3",
+		"SP",
+		"FLAGS",
+		"SB",
+	}
+
+	archs = append(archs, arch{
+		name:     "ARM",
+		pkg:      "cmd/internal/obj/arm",
+		genfile:  "../../arm/ssa.go",
+		ops:      ops,
+		blocks:   blocks,
+		regnames: regNames,
+	})
+}
diff --git a/src/cmd/compile/internal/ssa/gen/README b/src/cmd/compile/internal/ssa/gen/README
new file mode 100644
index 0000000..6731b97
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/README
@@ -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.
+
+This package generates opcode tables, rewrite rules, etc. for the ssa compiler.
+Run it with:
+   go run *.go
diff --git a/src/cmd/compile/internal/ssa/gen/dec.rules b/src/cmd/compile/internal/ssa/gen/dec.rules
new file mode 100644
index 0000000..401fba8
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/dec.rules
@@ -0,0 +1,92 @@
+// Copyright 2016 The Go 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 rules to decompose builtin compound types
+// (complex,string,slice,interface) into their constituent
+// types.  These rules work together with the decomposeBuiltIn
+// pass which handles phis of these types.
+
+// complex ops
+(ComplexReal (ComplexMake real _  )) -> real
+(ComplexImag (ComplexMake _ imag )) -> imag
+
+(Load <t> ptr mem) && t.IsComplex() && t.Size() == 8 ->
+  (ComplexMake
+    (Load <config.fe.TypeFloat32()> ptr mem)
+    (Load <config.fe.TypeFloat32()>
+      (OffPtr <config.fe.TypeFloat32().PtrTo()> [4] ptr)
+      mem)
+    )
+(Store [8] dst (ComplexMake real imag) mem) ->
+  (Store [4]
+    (OffPtr <config.fe.TypeFloat32().PtrTo()> [4] dst)
+    imag
+    (Store [4] dst real mem))
+(Load <t> ptr mem) && t.IsComplex() && t.Size() == 16 ->
+  (ComplexMake
+    (Load <config.fe.TypeFloat64()> ptr mem)
+    (Load <config.fe.TypeFloat64()>
+      (OffPtr <config.fe.TypeFloat64().PtrTo()> [8] ptr)
+      mem)
+    )
+(Store [16] dst (ComplexMake real imag) mem) ->
+  (Store [8]
+    (OffPtr <config.fe.TypeFloat64().PtrTo()> [8] dst)
+    imag
+    (Store [8] dst real mem))
+
+// string ops
+(StringPtr (StringMake ptr _)) -> ptr
+(StringLen (StringMake _ len)) -> len
+
+(Load <t> ptr mem) && t.IsString() ->
+  (StringMake
+    (Load <config.fe.TypeBytePtr()> ptr mem)
+    (Load <config.fe.TypeInt()>
+      (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] ptr)
+      mem))
+(Store [2*config.PtrSize] dst (StringMake ptr len) mem) ->
+  (Store [config.PtrSize]
+    (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] dst)
+    len
+    (Store [config.PtrSize] dst ptr mem))
+
+// slice ops
+(SlicePtr (SliceMake ptr _ _ )) -> ptr
+(SliceLen (SliceMake _ len _)) -> len
+(SliceCap (SliceMake _ _ cap)) -> cap
+
+(Load <t> ptr mem) && t.IsSlice() ->
+  (SliceMake
+    (Load <t.ElemType().PtrTo()> ptr mem)
+    (Load <config.fe.TypeInt()>
+      (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] ptr)
+      mem)
+    (Load <config.fe.TypeInt()>
+      (OffPtr <config.fe.TypeInt().PtrTo()> [2*config.PtrSize] ptr)
+      mem))
+(Store [3*config.PtrSize] dst (SliceMake ptr len cap) mem) ->
+  (Store [config.PtrSize]
+    (OffPtr <config.fe.TypeInt().PtrTo()> [2*config.PtrSize] dst)
+    cap
+    (Store [config.PtrSize]
+      (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] dst)
+      len
+      (Store [config.PtrSize] dst ptr mem)))
+
+// interface ops
+(ITab (IMake itab _)) -> itab
+(IData (IMake _ data)) -> data
+
+(Load <t> ptr mem) && t.IsInterface() ->
+  (IMake
+    (Load <config.fe.TypeBytePtr()> ptr mem)
+    (Load <config.fe.TypeBytePtr()>
+      (OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] ptr)
+      mem))
+(Store [2*config.PtrSize] dst (IMake itab data) mem) ->
+  (Store [config.PtrSize]
+    (OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] dst)
+    data
+    (Store [config.PtrSize] dst itab mem))
diff --git a/src/cmd/compile/internal/ssa/gen/decOps.go b/src/cmd/compile/internal/ssa/gen/decOps.go
new file mode 100644
index 0000000..b826481
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/decOps.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 ignore
+
+package main
+
+var decOps = []opData{}
+
+var decBlocks = []blockData{}
+
+func init() {
+	archs = append(archs, arch{
+		name:    "dec",
+		ops:     decOps,
+		blocks:  decBlocks,
+		generic: true,
+	})
+}
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
new file mode 100644
index 0000000..f5d1c98
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -0,0 +1,834 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// values are specified using the following format:
+// (op <type> [auxint] {aux} arg0 arg1 ...)
+// the type, aux, and auxint fields are optional
+// on the matching side
+//  - the type, aux, and auxint fields must match if they are specified.
+//  - the first occurrence of a variable defines that variable.  Subsequent
+//    uses must match (be == to) the first use.
+//  - v is defined to be the value matched.
+//  - an additional conditional can be provided after the match pattern with "&&".
+// on the generated side
+//  - the type of the top-level expression is the same as the one on the left-hand side.
+//  - the type of any subexpressions must be specified explicitly (or
+//    be specified in the op's type field).
+//  - auxint will be 0 if not specified.
+//  - aux will be nil if not specified.
+
+// blocks are specified using the following format:
+// (kind controlvalue succ0 succ1 ...)
+// controlvalue must be "nil" or a value expression
+// succ* fields must be variables
+// For now, the generated successors must be a permutation of the matched successors.
+
+// constant folding
+(Trunc16to8  (Const16 [c]))  -> (Const8   [int64(int8(c))])
+(Trunc32to8  (Const32 [c]))  -> (Const8   [int64(int8(c))])
+(Trunc32to16 (Const32 [c]))  -> (Const16  [int64(int16(c))])
+(Trunc64to8  (Const64 [c]))  -> (Const8   [int64(int8(c))])
+(Trunc64to16 (Const64 [c]))  -> (Const16  [int64(int16(c))])
+(Trunc64to32 (Const64 [c]))  -> (Const32  [int64(int32(c))])
+(Cvt64Fto32F (Const64F [c])) -> (Const32F [f2i(float64(i2f32(c)))])
+(Cvt32Fto64F (Const32F [c])) -> (Const64F [c]) // c is already a 64 bit float
+
+// const negation is currently handled by frontend
+//(Neg8 (Const8 [c])) -> (Const8 [-c])
+//(Neg16 (Const16 [c])) -> (Const16 [-c])
+//(Neg32 (Const32 [c])) -> (Const32 [-c])
+//(Neg64 (Const64 [c])) -> (Const64 [-c])
+//(Neg32F (Const32F [c])) -> (Const32F [f2i(-i2f(c))])
+//(Neg64F (Const64F [c])) -> (Const64F [f2i(-i2f(c))])
+
+(Add8   (Const8 [c])   (Const8 [d]))   -> (Const8  [int64(int8(c+d))])
+(Add16  (Const16 [c])  (Const16 [d]))  -> (Const16 [int64(int16(c+d))])
+(Add32  (Const32 [c])  (Const32 [d]))  -> (Const32 [int64(int32(c+d))])
+(Add64  (Const64 [c])  (Const64 [d]))  -> (Const64 [c+d])
+(Add32F (Const32F [c]) (Const32F [d])) -> 
+        (Const32F [f2i(float64(i2f32(c) + i2f32(d)))]) // ensure we combine the operands with 32 bit precision
+(Add64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) + i2f(d))])
+(AddPtr <t> x (Const64 [c])) -> (OffPtr <t> x [c])
+
+(Sub8   (Const8 [c]) (Const8 [d]))     -> (Const8 [int64(int8(c-d))])
+(Sub16  (Const16 [c]) (Const16 [d]))   -> (Const16 [int64(int16(c-d))])
+(Sub32  (Const32 [c]) (Const32 [d]))   -> (Const32 [int64(int32(c-d))])
+(Sub64  (Const64 [c]) (Const64 [d]))   -> (Const64 [c-d])
+(Sub32F (Const32F [c]) (Const32F [d])) -> 
+        (Const32F [f2i(float64(i2f32(c) - i2f32(d)))])
+(Sub64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) - i2f(d))])
+
+(Mul8   (Const8 [c])   (Const8 [d]))   -> (Const8  [int64(int8(c*d))])
+(Mul16  (Const16 [c])  (Const16 [d]))  -> (Const16 [int64(int16(c*d))])
+(Mul32  (Const32 [c])  (Const32 [d]))  -> (Const32 [int64(int32(c*d))])
+(Mul64  (Const64 [c])  (Const64 [d]))  -> (Const64 [c*d])
+(Mul32F (Const32F [c]) (Const32F [d])) -> 
+        (Const32F [f2i(float64(i2f32(c) * i2f32(d)))])
+(Mul64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) * i2f(d))])
+
+(Mod8  (Const8  [c]) (Const8  [d])) && d != 0 -> (Const8  [int64(int8(c % d))])
+(Mod16 (Const16 [c]) (Const16 [d])) && d != 0 -> (Const16 [int64(int16(c % d))])
+(Mod32 (Const32 [c]) (Const32 [d])) && d != 0 -> (Const32 [int64(int32(c % d))])
+(Mod64 (Const64 [c]) (Const64 [d])) && d != 0 -> (Const64 [c % d])
+
+(Mod8u  (Const8 [c])  (Const8  [d])) && d != 0 -> (Const8  [int64(uint8(c) % uint8(d))])
+(Mod16u (Const16 [c]) (Const16 [d])) && d != 0 -> (Const16 [int64(uint16(c) % uint16(d))])
+(Mod32u (Const32 [c]) (Const32 [d])) && d != 0 -> (Const32 [int64(uint32(c) % uint32(d))])
+(Mod64u (Const64 [c]) (Const64 [d])) && d != 0 -> (Const64 [int64(uint64(c) % uint64(d))])
+
+(Lsh64x64  (Const64 [c]) (Const64 [d])) -> (Const64 [c << uint64(d)])
+(Rsh64x64  (Const64 [c]) (Const64 [d])) -> (Const64 [c >> uint64(d)])
+(Rsh64Ux64 (Const64 [c]) (Const64 [d])) -> (Const64 [int64(uint64(c) >> uint64(d))])
+(Lsh32x64  (Const32 [c]) (Const64 [d])) -> (Const32 [int64(int32(c) << uint64(d))])
+(Rsh32x64  (Const32 [c]) (Const64 [d])) -> (Const32 [int64(int32(c) >> uint64(d))])
+(Rsh32Ux64 (Const32 [c]) (Const64 [d])) -> (Const32 [int64(int32(uint32(c) >> uint64(d)))])
+(Lsh16x64  (Const16 [c]) (Const64 [d])) -> (Const16 [int64(int16(c) << uint64(d))])
+(Rsh16x64  (Const16 [c]) (Const64 [d])) -> (Const16 [int64(int16(c) >> uint64(d))])
+(Rsh16Ux64 (Const16 [c]) (Const64 [d])) -> (Const16 [int64(int16(uint16(c) >> uint64(d)))])
+(Lsh8x64   (Const8  [c]) (Const64 [d])) -> (Const8  [int64(int8(c) << uint64(d))])
+(Rsh8x64   (Const8  [c]) (Const64 [d])) -> (Const8  [int64(int8(c) >> uint64(d))])
+(Rsh8Ux64  (Const8  [c]) (Const64 [d])) -> (Const8  [int64(int8(uint8(c) >> uint64(d)))])
+
+// Fold IsInBounds when the range of the index cannot exceed the limit.
+(IsInBounds (ZeroExt8to32  _) (Const32 [c])) && (1 << 8)  <= c -> (ConstBool [1])
+(IsInBounds (ZeroExt8to64  _) (Const64 [c])) && (1 << 8)  <= c -> (ConstBool [1])
+(IsInBounds (ZeroExt16to32 _) (Const32 [c])) && (1 << 16) <= c -> (ConstBool [1])
+(IsInBounds (ZeroExt16to64 _) (Const64 [c])) && (1 << 16) <= c -> (ConstBool [1])
+(IsInBounds x x) -> (ConstBool [0])
+(IsInBounds (And32 (Const32 [c]) _) (Const32 [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds (And64 (Const64 [c]) _) (Const64 [d])) && 0 <= c && c < d -> (ConstBool [1])
+(IsInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(0 <= c && c < d)])
+(IsInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(0 <= c && c < d)])
+// (Mod64u x y) is always between 0 (inclusive) and y (exclusive).
+(IsInBounds (Mod32u _ y) y) -> (ConstBool [1])
+(IsInBounds (Mod64u _ y) y) -> (ConstBool [1])
+
+(IsSliceInBounds x x) -> (ConstBool [1])
+(IsSliceInBounds (And32 (Const32 [c]) _) (Const32 [d])) && 0 <= c && c <= d -> (ConstBool [1])
+(IsSliceInBounds (And64 (Const64 [c]) _) (Const64 [d])) && 0 <= c && c <= d -> (ConstBool [1])
+(IsSliceInBounds (Const32 [0]) _) -> (ConstBool [1])
+(IsSliceInBounds (Const64 [0]) _) -> (ConstBool [1])
+(IsSliceInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(0 <= c && c <= d)])
+(IsSliceInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(0 <= c && c <= d)])
+(IsSliceInBounds (SliceLen x) (SliceCap x)) -> (ConstBool [1])
+
+(Eq64 x x) -> (ConstBool [1])
+(Eq32 x x) -> (ConstBool [1])
+(Eq16 x x) -> (ConstBool [1])
+(Eq8  x x) -> (ConstBool [1])
+(EqB (ConstBool [c]) (ConstBool [d])) -> (ConstBool [b2i(c == d)])
+(EqB (ConstBool [0]) x) -> (Not x)
+(EqB (ConstBool [1]) x) -> x
+
+(Neq64 x x) -> (ConstBool [0])
+(Neq32 x x) -> (ConstBool [0])
+(Neq16 x x) -> (ConstBool [0])
+(Neq8  x x) -> (ConstBool [0])
+(NeqB (ConstBool [c]) (ConstBool [d])) -> (ConstBool [b2i(c != d)])
+(NeqB (ConstBool [0]) x) -> x
+(NeqB (ConstBool [1]) x) -> (Not x)
+
+(Eq64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x)) -> (Eq64 (Const64 <t> [c-d]) x)
+(Eq32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x)) -> (Eq32 (Const32 <t> [int64(int32(c-d))]) x)
+(Eq16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x)) -> (Eq16 (Const16 <t> [int64(int16(c-d))]) x)
+(Eq8  (Const8  <t> [c]) (Add8  (Const8  <t> [d]) x)) -> (Eq8  (Const8 <t> [int64(int8(c-d))]) x)
+
+(Neq64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x)) -> (Neq64 (Const64 <t> [c-d]) x)
+(Neq32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x)) -> (Neq32 (Const32 <t> [int64(int32(c-d))]) x)
+(Neq16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x)) -> (Neq16 (Const16 <t> [int64(int16(c-d))]) x)
+(Neq8  (Const8  <t> [c]) (Add8  (Const8  <t> [d]) x)) -> (Neq8 (Const8 <t> [int64(int8(c-d))]) x)
+
+// canonicalize: swap arguments for commutative operations when one argument is a constant.
+(Eq64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Eq64 (Const64 <t> [c]) x)
+(Eq32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Eq32 (Const32 <t> [c]) x)
+(Eq16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Eq16 (Const16 <t> [c]) x)
+(Eq8  x (Const8  <t> [c])) && x.Op != OpConst8  -> (Eq8  (Const8  <t> [c]) x)
+
+(Neq64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Neq64 (Const64 <t> [c]) x)
+(Neq32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Neq32 (Const32 <t> [c]) x)
+(Neq16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Neq16 (Const16 <t> [c]) x)
+(Neq8  x (Const8 <t>  [c])) && x.Op != OpConst8  -> (Neq8  (Const8  <t> [c]) x)
+
+// AddPtr is not canonicalized because nilcheck ptr checks the first argument to be non-nil.
+(Add64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Add64 (Const64 <t> [c]) x)
+(Add32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Add32 (Const32 <t> [c]) x)
+(Add16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Add16 (Const16 <t> [c]) x)
+(Add8  x (Const8  <t> [c])) && x.Op != OpConst8  -> (Add8  (Const8  <t> [c]) x)
+
+(Mul64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Mul64 (Const64 <t> [c]) x)
+(Mul32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Mul32 (Const32 <t> [c]) x)
+(Mul16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Mul16 (Const16 <t> [c]) x)
+(Mul8  x (Const8  <t> [c])) && x.Op != OpConst8  -> (Mul8  (Const8  <t> [c]) x)
+
+(Sub64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Add64 (Const64 <t> [-c]) x)
+(Sub32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Add32 (Const32 <t> [int64(int32(-c))]) x)
+(Sub16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Add16 (Const16 <t> [int64(int16(-c))]) x)
+(Sub8  x (Const8  <t> [c])) && x.Op != OpConst8  -> (Add8  (Const8  <t> [int64(int8(-c))]) x)
+
+(And64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (And64 (Const64 <t> [c]) x)
+(And32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (And32 (Const32 <t> [c]) x)
+(And16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (And16 (Const16 <t> [c]) x)
+(And8  x (Const8  <t> [c])) && x.Op != OpConst8  -> (And8  (Const8  <t> [c]) x)
+
+(Or64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Or64 (Const64 <t> [c]) x)
+(Or32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Or32 (Const32 <t> [c]) x)
+(Or16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Or16 (Const16 <t> [c]) x)
+(Or8  x (Const8  <t> [c])) && x.Op != OpConst8  -> (Or8  (Const8  <t> [c]) x)
+
+(Xor64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Xor64 (Const64 <t> [c]) x)
+(Xor32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Xor32 (Const32 <t> [c]) x)
+(Xor16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Xor16 (Const16 <t> [c]) x)
+(Xor8  x (Const8  <t> [c])) && x.Op != OpConst8  -> (Xor8  (Const8  <t> [c]) x)
+
+// Distribute multiplication c * (d+x) -> c*d + c*x. Useful for:
+// a[i].b = ...; a[i+1].b = ...
+(Mul64 (Const64 <t> [c]) (Add64 <t> (Const64 <t> [d]) x)) ->
+  (Add64 (Const64 <t> [c*d]) (Mul64 <t> (Const64 <t> [c]) x))
+(Mul32 (Const32 <t> [c]) (Add32 <t> (Const32 <t> [d]) x)) ->
+  (Add32 (Const32 <t> [int64(int32(c*d))]) (Mul32 <t> (Const32 <t> [c]) x))
+
+// rewrite shifts of 8/16/32 bit consts into 64 bit consts to reduce
+// the number of the other rewrite rules for const shifts
+(Lsh64x32  <t> x (Const32 [c])) -> (Lsh64x64  x (Const64 <t> [int64(uint32(c))]))
+(Lsh64x16  <t> x (Const16 [c])) -> (Lsh64x64  x (Const64 <t> [int64(uint16(c))]))
+(Lsh64x8   <t> x (Const8  [c])) -> (Lsh64x64  x (Const64 <t> [int64(uint8(c))]))
+(Rsh64x32  <t> x (Const32 [c])) -> (Rsh64x64  x (Const64 <t> [int64(uint32(c))]))
+(Rsh64x16  <t> x (Const16 [c])) -> (Rsh64x64  x (Const64 <t> [int64(uint16(c))]))
+(Rsh64x8   <t> x (Const8  [c])) -> (Rsh64x64  x (Const64 <t> [int64(uint8(c))]))
+(Rsh64Ux32 <t> x (Const32 [c])) -> (Rsh64Ux64 x (Const64 <t> [int64(uint32(c))]))
+(Rsh64Ux16 <t> x (Const16 [c])) -> (Rsh64Ux64 x (Const64 <t> [int64(uint16(c))]))
+(Rsh64Ux8  <t> x (Const8  [c])) -> (Rsh64Ux64 x (Const64 <t> [int64(uint8(c))]))
+
+(Lsh32x32  <t> x (Const32 [c])) -> (Lsh32x64  x (Const64 <t> [int64(uint32(c))]))
+(Lsh32x16  <t> x (Const16 [c])) -> (Lsh32x64  x (Const64 <t> [int64(uint16(c))]))
+(Lsh32x8   <t> x (Const8  [c])) -> (Lsh32x64  x (Const64 <t> [int64(uint8(c))]))
+(Rsh32x32  <t> x (Const32 [c])) -> (Rsh32x64  x (Const64 <t> [int64(uint32(c))]))
+(Rsh32x16  <t> x (Const16 [c])) -> (Rsh32x64  x (Const64 <t> [int64(uint16(c))]))
+(Rsh32x8   <t> x (Const8  [c])) -> (Rsh32x64  x (Const64 <t> [int64(uint8(c))]))
+(Rsh32Ux32 <t> x (Const32 [c])) -> (Rsh32Ux64 x (Const64 <t> [int64(uint32(c))]))
+(Rsh32Ux16 <t> x (Const16 [c])) -> (Rsh32Ux64 x (Const64 <t> [int64(uint16(c))]))
+(Rsh32Ux8  <t> x (Const8  [c])) -> (Rsh32Ux64 x (Const64 <t> [int64(uint8(c))]))
+
+(Lsh16x32  <t> x (Const32 [c])) -> (Lsh16x64  x (Const64 <t> [int64(uint32(c))]))
+(Lsh16x16  <t> x (Const16 [c])) -> (Lsh16x64  x (Const64 <t> [int64(uint16(c))]))
+(Lsh16x8   <t> x (Const8  [c])) -> (Lsh16x64  x (Const64 <t> [int64(uint8(c))]))
+(Rsh16x32  <t> x (Const32 [c])) -> (Rsh16x64  x (Const64 <t> [int64(uint32(c))]))
+(Rsh16x16  <t> x (Const16 [c])) -> (Rsh16x64  x (Const64 <t> [int64(uint16(c))]))
+(Rsh16x8   <t> x (Const8  [c])) -> (Rsh16x64  x (Const64 <t> [int64(uint8(c))]))
+(Rsh16Ux32 <t> x (Const32 [c])) -> (Rsh16Ux64 x (Const64 <t> [int64(uint32(c))]))
+(Rsh16Ux16 <t> x (Const16 [c])) -> (Rsh16Ux64 x (Const64 <t> [int64(uint16(c))]))
+(Rsh16Ux8  <t> x (Const8  [c])) -> (Rsh16Ux64 x (Const64 <t> [int64(uint8(c))]))
+
+(Lsh8x32  <t> x (Const32 [c])) -> (Lsh8x64  x (Const64 <t> [int64(uint32(c))]))
+(Lsh8x16  <t> x (Const16 [c])) -> (Lsh8x64  x (Const64 <t> [int64(uint16(c))]))
+(Lsh8x8   <t> x (Const8  [c])) -> (Lsh8x64  x (Const64 <t> [int64(uint8(c))]))
+(Rsh8x32  <t> x (Const32 [c])) -> (Rsh8x64  x (Const64 <t> [int64(uint32(c))]))
+(Rsh8x16  <t> x (Const16 [c])) -> (Rsh8x64  x (Const64 <t> [int64(uint16(c))]))
+(Rsh8x8   <t> x (Const8  [c])) -> (Rsh8x64  x (Const64 <t> [int64(uint8(c))]))
+(Rsh8Ux32 <t> x (Const32 [c])) -> (Rsh8Ux64 x (Const64 <t> [int64(uint32(c))]))
+(Rsh8Ux16 <t> x (Const16 [c])) -> (Rsh8Ux64 x (Const64 <t> [int64(uint16(c))]))
+(Rsh8Ux8  <t> x (Const8  [c])) -> (Rsh8Ux64 x (Const64 <t> [int64(uint8(c))]))
+
+// shifts by zero
+(Lsh64x64  x (Const64 [0])) -> x
+(Rsh64x64  x (Const64 [0])) -> x
+(Rsh64Ux64 x (Const64 [0])) -> x
+(Lsh32x64  x (Const64 [0])) -> x
+(Rsh32x64  x (Const64 [0])) -> x
+(Rsh32Ux64 x (Const64 [0])) -> x
+(Lsh16x64  x (Const64 [0])) -> x
+(Rsh16x64  x (Const64 [0])) -> x
+(Rsh16Ux64 x (Const64 [0])) -> x
+(Lsh8x64   x (Const64 [0])) -> x
+(Rsh8x64   x (Const64 [0])) -> x
+(Rsh8Ux64  x (Const64 [0])) -> x
+
+// zero shifted.
+(Lsh64x64  (Const64 [0]) _) -> (Const64 [0])
+(Lsh64x32  (Const64 [0]) _) -> (Const64 [0])
+(Lsh64x16  (Const64 [0]) _) -> (Const64 [0])
+(Lsh64x8  (Const64 [0]) _) -> (Const64 [0])
+(Rsh64x64  (Const64 [0]) _) -> (Const64 [0])
+(Rsh64x32  (Const64 [0]) _) -> (Const64 [0])
+(Rsh64x16  (Const64 [0]) _) -> (Const64 [0])
+(Rsh64x8  (Const64 [0]) _) -> (Const64 [0])
+(Rsh64Ux64 (Const64 [0]) _) -> (Const64 [0])
+(Rsh64Ux32 (Const64 [0]) _) -> (Const64 [0])
+(Rsh64Ux16 (Const64 [0]) _) -> (Const64 [0])
+(Rsh64Ux8 (Const64 [0]) _) -> (Const64 [0])
+(Lsh32x64  (Const32 [0]) _) -> (Const32 [0])
+(Lsh32x32  (Const32 [0]) _) -> (Const32 [0])
+(Lsh32x16  (Const32 [0]) _) -> (Const32 [0])
+(Lsh32x8  (Const32 [0]) _) -> (Const32 [0])
+(Rsh32x64  (Const32 [0]) _) -> (Const32 [0])
+(Rsh32x32  (Const32 [0]) _) -> (Const32 [0])
+(Rsh32x16  (Const32 [0]) _) -> (Const32 [0])
+(Rsh32x8  (Const32 [0]) _) -> (Const32 [0])
+(Rsh32Ux64 (Const32 [0]) _) -> (Const32 [0])
+(Rsh32Ux32 (Const32 [0]) _) -> (Const32 [0])
+(Rsh32Ux16 (Const32 [0]) _) -> (Const32 [0])
+(Rsh32Ux8 (Const32 [0]) _) -> (Const32 [0])
+(Lsh16x64  (Const16 [0]) _) -> (Const16 [0])
+(Lsh16x32  (Const16 [0]) _) -> (Const16 [0])
+(Lsh16x16  (Const16 [0]) _) -> (Const16 [0])
+(Lsh16x8  (Const16 [0]) _) -> (Const16 [0])
+(Rsh16x64  (Const16 [0]) _) -> (Const16 [0])
+(Rsh16x32  (Const16 [0]) _) -> (Const16 [0])
+(Rsh16x16  (Const16 [0]) _) -> (Const16 [0])
+(Rsh16x8  (Const16 [0]) _) -> (Const16 [0])
+(Rsh16Ux64 (Const16 [0]) _) -> (Const16 [0])
+(Rsh16Ux32 (Const16 [0]) _) -> (Const16 [0])
+(Rsh16Ux16 (Const16 [0]) _) -> (Const16 [0])
+(Rsh16Ux8 (Const16 [0]) _) -> (Const16 [0])
+(Lsh8x64   (Const8 [0]) _) -> (Const8  [0])
+(Lsh8x32   (Const8 [0]) _) -> (Const8  [0])
+(Lsh8x16   (Const8 [0]) _) -> (Const8  [0])
+(Lsh8x8   (Const8 [0]) _) -> (Const8  [0])
+(Rsh8x64   (Const8 [0]) _) -> (Const8  [0])
+(Rsh8x32   (Const8 [0]) _) -> (Const8  [0])
+(Rsh8x16   (Const8 [0]) _) -> (Const8  [0])
+(Rsh8x8   (Const8 [0]) _) -> (Const8  [0])
+(Rsh8Ux64  (Const8 [0]) _) -> (Const8  [0])
+(Rsh8Ux32  (Const8 [0]) _) -> (Const8  [0])
+(Rsh8Ux16  (Const8 [0]) _) -> (Const8  [0])
+(Rsh8Ux8  (Const8 [0]) _) -> (Const8  [0])
+
+// large left shifts of all values, and right shifts of unsigned values
+(Lsh64x64  _ (Const64 [c])) && uint64(c) >= 64 -> (Const64 [0])
+(Rsh64Ux64 _ (Const64 [c])) && uint64(c) >= 64 -> (Const64 [0])
+(Lsh32x64  _ (Const64 [c])) && uint64(c) >= 32 -> (Const32 [0])
+(Rsh32Ux64 _ (Const64 [c])) && uint64(c) >= 32 -> (Const32 [0])
+(Lsh16x64  _ (Const64 [c])) && uint64(c) >= 16 -> (Const16 [0])
+(Rsh16Ux64 _ (Const64 [c])) && uint64(c) >= 16 -> (Const16 [0])
+(Lsh8x64   _ (Const64 [c])) && uint64(c) >= 8  -> (Const8  [0])
+(Rsh8Ux64  _ (Const64 [c])) && uint64(c) >= 8  -> (Const8  [0])
+
+// combine const shifts
+(Lsh64x64 <t> (Lsh64x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Lsh64x64 x (Const64 <t> [c+d]))
+(Lsh32x64 <t> (Lsh32x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Lsh32x64 x (Const64 <t> [c+d]))
+(Lsh16x64 <t> (Lsh16x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Lsh16x64 x (Const64 <t> [c+d]))
+(Lsh8x64  <t> (Lsh8x64  x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Lsh8x64  x (Const64 <t> [c+d]))
+
+(Rsh64x64 <t> (Rsh64x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh64x64 x (Const64 <t> [c+d]))
+(Rsh32x64 <t> (Rsh32x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh32x64 x (Const64 <t> [c+d]))
+(Rsh16x64 <t> (Rsh16x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh16x64 x (Const64 <t> [c+d]))
+(Rsh8x64  <t> (Rsh8x64  x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh8x64  x (Const64 <t> [c+d]))
+
+(Rsh64Ux64 <t> (Rsh64Ux64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh64Ux64 x (Const64 <t> [c+d]))
+(Rsh32Ux64 <t> (Rsh32Ux64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh32Ux64 x (Const64 <t> [c+d]))
+(Rsh16Ux64 <t> (Rsh16Ux64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh16Ux64 x (Const64 <t> [c+d]))
+(Rsh8Ux64  <t> (Rsh8Ux64  x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh8Ux64  x (Const64 <t> [c+d]))
+
+// ((x >> c1) << c2) >> c3
+(Rsh64Ux64 (Lsh64x64 (Rsh64Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+  && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+  -> (Rsh64Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+(Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+  && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+  -> (Rsh32Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+(Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+  && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+  -> (Rsh16Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+(Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+  && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+  -> (Rsh8Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+
+// ((x << c1) >> c2) << c3
+(Lsh64x64 (Rsh64Ux64 (Lsh64x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+  && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+  -> (Lsh64x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+(Lsh32x64 (Rsh32Ux64 (Lsh32x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+  && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+  -> (Lsh32x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+(Lsh16x64 (Rsh16Ux64 (Lsh16x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+  && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+  -> (Lsh16x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+(Lsh8x64 (Rsh8Ux64 (Lsh8x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+  && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+  -> (Lsh8x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+
+// constant comparisons
+(Eq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c == d)])
+(Eq32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c == d)])
+(Eq16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c == d)])
+(Eq8  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(c == d)])
+
+(Neq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c != d)])
+(Neq32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c != d)])
+(Neq16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c != d)])
+(Neq8  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(c != d)])
+
+(Greater64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c > d)])
+(Greater32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c > d)])
+(Greater16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c > d)])
+(Greater8  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(c > d)])
+
+(Greater64U (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(uint64(c) > uint64(d))])
+(Greater32U (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(uint32(c) > uint32(d))])
+(Greater16U (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(uint16(c) > uint16(d))])
+(Greater8U  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(uint8(c)  > uint8(d))])
+
+(Geq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c >= d)])
+(Geq32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c >= d)])
+(Geq16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c >= d)])
+(Geq8  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(c >= d)])
+
+(Geq64U (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(uint64(c) >= uint64(d))])
+(Geq32U (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(uint32(c) >= uint32(d))])
+(Geq16U (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(uint16(c) >= uint16(d))])
+(Geq8U  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(uint8(c)  >= uint8(d))])
+
+(Less64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c < d)])
+(Less32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c < d)])
+(Less16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c < d)])
+(Less8  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(c < d)])
+
+(Less64U (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(uint64(c) < uint64(d))])
+(Less32U (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(uint32(c) < uint32(d))])
+(Less16U (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(uint16(c) < uint16(d))])
+(Less8U  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(uint8(c)  < uint8(d))])
+
+(Leq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c <= d)])
+(Leq32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c <= d)])
+(Leq16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c <= d)])
+(Leq8  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(c <= d)])
+
+(Leq64U (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(uint64(c) <= uint64(d))])
+(Leq32U (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(uint32(c) <= uint32(d))])
+(Leq16U (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(uint16(c) <= uint16(d))])
+(Leq8U  (Const8  [c]) (Const8  [d])) -> (ConstBool [b2i(uint8(c)  <= uint8(d))])
+
+// simplifications
+(Or64 x x) -> x
+(Or32 x x) -> x
+(Or16 x x) -> x
+(Or8  x x) -> x
+(Or64 (Const64 [0]) x) -> x
+(Or32 (Const32 [0]) x) -> x
+(Or16 (Const16 [0]) x) -> x
+(Or8  (Const8  [0]) x) -> x
+(Or64 (Const64 [-1]) _) -> (Const64 [-1])
+(Or32 (Const32 [-1]) _) -> (Const32 [-1])
+(Or16 (Const16 [-1]) _) -> (Const16 [-1])
+(Or8  (Const8  [-1]) _) -> (Const8  [-1])
+(And64 x x) -> x
+(And32 x x) -> x
+(And16 x x) -> x
+(And8  x x) -> x
+(And64 (Const64 [-1]) x) -> x
+(And32 (Const32 [-1]) x) -> x
+(And16 (Const16 [-1]) x) -> x
+(And8  (Const8  [-1]) x) -> x
+(And64 (Const64 [0]) _) -> (Const64 [0])
+(And32 (Const32 [0]) _) -> (Const32 [0])
+(And16 (Const16 [0]) _) -> (Const16 [0])
+(And8  (Const8  [0]) _) -> (Const8  [0])
+(Xor64 x x) -> (Const64 [0])
+(Xor32 x x) -> (Const32 [0])
+(Xor16 x x) -> (Const16 [0])
+(Xor8  x x) -> (Const8  [0])
+(Xor64 (Const64 [0]) x) -> x
+(Xor32 (Const32 [0]) x) -> x
+(Xor16 (Const16 [0]) x) -> x
+(Xor8  (Const8  [0]) x) -> x
+(Add64 (Const64 [0]) x) -> x
+(Add32 (Const32 [0]) x) -> x
+(Add16 (Const16 [0]) x) -> x
+(Add8  (Const8  [0]) x) -> x
+(Sub64 x x) -> (Const64 [0])
+(Sub32 x x) -> (Const32 [0])
+(Sub16 x x) -> (Const16 [0])
+(Sub8  x x) -> (Const8  [0])
+(Mul64 (Const64 [0]) _) -> (Const64 [0])
+(Mul32 (Const32 [0]) _) -> (Const32 [0])
+(Mul16 (Const16 [0]) _) -> (Const16 [0])
+(Mul8  (Const8  [0]) _) -> (Const8  [0])
+(Com8  (Com8  x)) -> x
+(Com16 (Com16 x)) -> x
+(Com32 (Com32 x)) -> x
+(Com64 (Com64 x)) -> x
+(Neg8  (Sub8  x y)) -> (Sub8  y x)
+(Neg16 (Sub16 x y)) -> (Sub16 y x)
+(Neg32 (Sub32 x y)) -> (Sub32 y x)
+(Neg64 (Sub64 x y)) -> (Sub64 y x)
+
+(And64 x (And64 x y)) -> (And64 x y)
+(And32 x (And32 x y)) -> (And32 x y)
+(And16 x (And16 x y)) -> (And16 x y)
+(And8  x (And8  x y)) -> (And8  x y)
+(And64 x (And64 y x)) -> (And64 x y)
+(And32 x (And32 y x)) -> (And32 x y)
+(And16 x (And16 y x)) -> (And16 x y)
+(And8  x (And8  y x)) -> (And8  x y)
+(And64 (And64 x y) x) -> (And64 x y)
+(And32 (And32 x y) x) -> (And32 x y)
+(And16 (And16 x y) x) -> (And16 x y)
+(And8  (And8  x y) x) -> (And8  x y)
+(And64 (And64 x y) y) -> (And64 x y)
+(And32 (And32 x y) y) -> (And32 x y)
+(And16 (And16 x y) y) -> (And16 x y)
+(And8  (And8  x y) y) -> (And8  x y)
+(Or64 x (Or64 x y)) -> (Or64 x y)
+(Or32 x (Or32 x y)) -> (Or32 x y)
+(Or16 x (Or16 x y)) -> (Or16 x y)
+(Or8  x (Or8  x y)) -> (Or8  x y)
+(Or64 x (Or64 y x)) -> (Or64 x y)
+(Or32 x (Or32 y x)) -> (Or32 x y)
+(Or16 x (Or16 y x)) -> (Or16 x y)
+(Or8  x (Or8  y x)) -> (Or8  x y)
+(Or64 (Or64 x y) x) -> (Or64 x y)
+(Or32 (Or32 x y) x) -> (Or32 x y)
+(Or16 (Or16 x y) x) -> (Or16 x y)
+(Or8  (Or8  x y) x) -> (Or8  x y)
+(Or64 (Or64 x y) y) -> (Or64 x y)
+(Or32 (Or32 x y) y) -> (Or32 x y)
+(Or16 (Or16 x y) y) -> (Or16 x y)
+(Or8  (Or8  x y) y) -> (Or8  x y)
+(Xor64 x (Xor64 x y)) -> y
+(Xor32 x (Xor32 x y)) -> y
+(Xor16 x (Xor16 x y)) -> y
+(Xor8  x (Xor8  x y)) -> y
+(Xor64 x (Xor64 y x)) -> y
+(Xor32 x (Xor32 y x)) -> y
+(Xor16 x (Xor16 y x)) -> y
+(Xor8  x (Xor8  y x)) -> y
+(Xor64 (Xor64 x y) x) -> y
+(Xor32 (Xor32 x y) x) -> y
+(Xor16 (Xor16 x y) x) -> y
+(Xor8  (Xor8  x y) x) -> y
+(Xor64 (Xor64 x y) y) -> x
+(Xor32 (Xor32 x y) y) -> x
+(Xor16 (Xor16 x y) y) -> x
+(Xor8  (Xor8  x y) y) -> x
+
+(Trunc64to8  (And64 (Const64 [y]) x)) && y&0xFF == 0xFF -> (Trunc64to8 x)
+(Trunc64to16 (And64 (Const64 [y]) x)) && y&0xFFFF == 0xFFFF -> (Trunc64to16 x)
+(Trunc64to32 (And64 (Const64 [y]) x)) && y&0xFFFFFFFF == 0xFFFFFFFF -> (Trunc64to32 x)
+(Trunc32to8  (And32 (Const32 [y]) x)) && y&0xFF == 0xFF -> (Trunc32to8 x)
+(Trunc32to16 (And32 (Const32 [y]) x)) && y&0xFFFF == 0xFFFF -> (Trunc32to16 x)
+(Trunc16to8  (And16 (Const16 [y]) x)) && y&0xFF == 0xFF -> (Trunc16to8 x)
+
+// Rewrite AND of consts as shifts if possible, slightly faster for 64 bit operands
+// leading zeros can be shifted left, then right
+(And64 <t> (Const64 [y]) x) && nlz(y) + nto(y) == 64 && nto(y) >= 32
+  -> (Rsh64Ux64 (Lsh64x64 <t> x (Const64 <t> [nlz(y)])) (Const64 <t> [nlz(y)]))
+// trailing zeros can be shifted right, then left
+(And64 <t> (Const64 [y]) x) && nlo(y) + ntz(y) == 64 && ntz(y) >= 32
+  -> (Lsh64x64 (Rsh64Ux64 <t> x (Const64 <t> [ntz(y)])) (Const64 <t> [ntz(y)]))
+
+// simplifications often used for lengths.  e.g. len(s[i:i+5])==5
+(Sub64 (Add64 x y) x) -> y
+(Sub64 (Add64 x y) y) -> x
+(Sub32 (Add32 x y) x) -> y
+(Sub32 (Add32 x y) y) -> x
+(Sub16 (Add16 x y) x) -> y
+(Sub16 (Add16 x y) y) -> x
+(Sub8  (Add8  x y) x) -> y
+(Sub8  (Add8  x y) y) -> x
+
+// basic phi simplifications
+(Phi (Const8  [c]) (Const8  [c])) -> (Const8  [c])
+(Phi (Const16 [c]) (Const16 [c])) -> (Const16 [c])
+(Phi (Const32 [c]) (Const32 [c])) -> (Const32 [c])
+(Phi (Const64 [c]) (Const64 [c])) -> (Const64 [c])
+
+// user nil checks
+(NeqPtr p (ConstNil)) -> (IsNonNil p)
+(NeqPtr (ConstNil) p) -> (IsNonNil p)
+(EqPtr p (ConstNil)) -> (Not (IsNonNil p))
+(EqPtr (ConstNil) p) -> (Not (IsNonNil p))
+
+// slice and interface comparisons
+// The frontend ensures that we can only compare against nil,
+// so we need only compare the first word (interface type or slice ptr).
+(EqInter x y)  -> (EqPtr  (ITab x) (ITab y))
+(NeqInter x y) -> (NeqPtr (ITab x) (ITab y))
+(EqSlice x y)  -> (EqPtr  (SlicePtr x) (SlicePtr y))
+(NeqSlice x y) -> (NeqPtr (SlicePtr x) (SlicePtr y))
+
+// Load of store of same address, with compatibly typed value and same size
+(Load <t1> p1 (Store [w] p2 x _)) && isSamePtr(p1,p2) && t1.Compare(x.Type)==CMPeq && w == t1.Size() -> x
+
+// Collapse OffPtr
+(OffPtr (OffPtr p [b]) [a]) -> (OffPtr p [a+b])
+(OffPtr p [0]) && v.Type.Compare(p.Type) == CMPeq -> p
+
+// indexing operations
+// Note: bounds check has already been done
+(ArrayIndex <t> [0] x:(Load ptr mem)) -> @x.Block (Load <t> ptr mem)
+(PtrIndex <t> ptr idx) && config.PtrSize == 4 -> (AddPtr ptr (Mul32 <config.fe.TypeInt()> idx (Const32 <config.fe.TypeInt()> [t.ElemType().Size()])))
+(PtrIndex <t> ptr idx) && config.PtrSize == 8 -> (AddPtr ptr (Mul64 <config.fe.TypeInt()> idx (Const64 <config.fe.TypeInt()> [t.ElemType().Size()])))
+
+// struct operations
+(StructSelect (StructMake1 x)) -> x
+(StructSelect [0] (StructMake2 x _)) -> x
+(StructSelect [1] (StructMake2 _ x)) -> x
+(StructSelect [0] (StructMake3 x _ _)) -> x
+(StructSelect [1] (StructMake3 _ x _)) -> x
+(StructSelect [2] (StructMake3 _ _ x)) -> x
+(StructSelect [0] (StructMake4 x _ _ _)) -> x
+(StructSelect [1] (StructMake4 _ x _ _)) -> x
+(StructSelect [2] (StructMake4 _ _ x _)) -> x
+(StructSelect [3] (StructMake4 _ _ _ x)) -> x
+
+(Load <t> _ _) && t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t) ->
+  (StructMake0)
+(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t) ->
+  (StructMake1
+    (Load <t.FieldType(0)> ptr mem))
+(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t) ->
+  (StructMake2
+    (Load <t.FieldType(0)> ptr mem)
+    (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem))
+(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t) ->
+  (StructMake3
+    (Load <t.FieldType(0)> ptr mem)
+    (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)
+    (Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem))
+(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t) ->
+  (StructMake4
+    (Load <t.FieldType(0)> ptr mem)
+    (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)
+    (Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem)
+    (Load <t.FieldType(3)> (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] ptr) mem))
+
+(StructSelect [i] x:(Load <t> ptr mem)) && !config.fe.CanSSA(t) ->
+  @x.Block (Load <v.Type> (OffPtr <v.Type.PtrTo()> [t.FieldOff(int(i))] ptr) mem)
+
+(Store _ (StructMake0) mem) -> mem
+(Store dst (StructMake1 <t> f0) mem) ->
+  (Store [t.FieldType(0).Size()] dst f0 mem)
+(Store dst (StructMake2 <t> f0 f1) mem) ->
+  (Store [t.FieldType(1).Size()]
+    (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
+    f1
+    (Store [t.FieldType(0).Size()] dst f0 mem))
+(Store dst (StructMake3 <t> f0 f1 f2) mem) ->
+  (Store [t.FieldType(2).Size()]
+    (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
+    f2
+    (Store [t.FieldType(1).Size()]
+      (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
+      f1
+      (Store [t.FieldType(0).Size()] dst f0 mem)))
+(Store dst (StructMake4 <t> f0 f1 f2 f3) mem) ->
+  (Store [t.FieldType(3).Size()]
+    (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst)
+    f3
+    (Store [t.FieldType(2).Size()]
+      (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
+      f2
+      (Store [t.FieldType(1).Size()]
+        (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
+        f1
+        (Store [t.FieldType(0).Size()] dst f0 mem))))
+
+// un-SSAable values use mem->mem copies
+(Store [size] dst (Load <t> src mem) mem) && !config.fe.CanSSA(t) -> (Move [size] dst src mem)
+(Store [size] dst (Load <t> src mem) (VarDef {x} mem)) && !config.fe.CanSSA(t) -> (Move [size] dst src (VarDef {x} mem))
+
+// string ops
+// Decomposing StringMake and lowering of StringPtr and StringLen
+// happens in a later pass, dec, so that these operations are available
+// to other passes for optimizations.
+(StringPtr (StringMake (Const64 <t> [c]) _)) -> (Const64 <t> [c])
+(StringLen (StringMake _ (Const64 <t> [c]))) -> (Const64 <t> [c])
+(ConstString {s}) && config.PtrSize == 4 && s.(string) == "" ->
+  (StringMake (ConstNil) (Const32 <config.fe.TypeInt()> [0]))
+(ConstString {s}) && config.PtrSize == 8 && s.(string) == "" ->
+  (StringMake (ConstNil) (Const64 <config.fe.TypeInt()> [0]))
+(ConstString {s}) && config.PtrSize == 4 && s.(string) != "" ->
+  (StringMake
+    (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
+      (SB))
+    (Const32 <config.fe.TypeInt()> [int64(len(s.(string)))]))
+(ConstString {s}) && config.PtrSize == 8 && s.(string) != "" ->
+  (StringMake
+    (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
+      (SB))
+    (Const64 <config.fe.TypeInt()> [int64(len(s.(string)))]))
+
+// slice ops
+// Only a few slice rules are provided here.  See dec.rules for
+// a more comprehensive set.
+(SliceLen (SliceMake _ (Const64 <t> [c]) _)) -> (Const64 <t> [c])
+(SliceCap (SliceMake _ _ (Const64 <t> [c]))) -> (Const64 <t> [c])
+(SlicePtr (SliceMake (SlicePtr x) _ _)) -> (SlicePtr x)
+(SliceLen (SliceMake _ (SliceLen x) _)) -> (SliceLen x)
+(SliceCap (SliceMake _ _ (SliceCap x))) -> (SliceCap x)
+(SliceCap (SliceMake _ _ (SliceLen x))) -> (SliceLen x)
+(ConstSlice) && config.PtrSize == 4 ->
+  (SliceMake
+    (ConstNil <v.Type.ElemType().PtrTo()>)
+    (Const32 <config.fe.TypeInt()> [0])
+    (Const32 <config.fe.TypeInt()> [0]))
+(ConstSlice) && config.PtrSize == 8 ->
+  (SliceMake
+    (ConstNil <v.Type.ElemType().PtrTo()>)
+    (Const64 <config.fe.TypeInt()> [0])
+    (Const64 <config.fe.TypeInt()> [0]))
+
+// interface ops
+(ConstInterface) ->
+  (IMake
+    (ConstNil <config.fe.TypeBytePtr()>)
+    (ConstNil <config.fe.TypeBytePtr()>))
+
+(Check (NilCheck (GetG _) _) next) -> (Plain nil next)
+
+(If (Not cond) yes no) -> (If cond no yes)
+(If (ConstBool [c]) yes no) && c == 1 -> (First nil yes no)
+(If (ConstBool [c]) yes no) && c == 0 -> (First nil no yes)
+
+// Get rid of Convert ops for pointer arithmetic on unsafe.Pointer.
+(Convert (Add64 (Convert ptr mem) off) mem) -> (Add64 ptr off)
+(Convert (Add64 off (Convert ptr mem)) mem) -> (Add64 ptr off)
+(Convert (Convert ptr mem) mem) -> ptr
+
+// Decompose compound argument values
+(Arg {n} [off]) && v.Type.IsString() ->
+  (StringMake
+    (Arg <config.fe.TypeBytePtr()> {n} [off])
+    (Arg <config.fe.TypeInt()> {n} [off+config.PtrSize]))
+
+(Arg {n} [off]) && v.Type.IsSlice() ->
+  (SliceMake
+    (Arg <v.Type.ElemType().PtrTo()> {n} [off])
+    (Arg <config.fe.TypeInt()> {n} [off+config.PtrSize])
+    (Arg <config.fe.TypeInt()> {n} [off+2*config.PtrSize]))
+
+(Arg {n} [off]) && v.Type.IsInterface() ->
+  (IMake
+    (Arg <config.fe.TypeBytePtr()> {n} [off])
+    (Arg <config.fe.TypeBytePtr()> {n} [off+config.PtrSize]))
+
+(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 16 ->
+  (ComplexMake
+    (Arg <config.fe.TypeFloat64()> {n} [off])
+    (Arg <config.fe.TypeFloat64()> {n} [off+8]))
+
+(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 8 ->
+  (ComplexMake
+    (Arg <config.fe.TypeFloat32()> {n} [off])
+    (Arg <config.fe.TypeFloat32()> {n} [off+4]))
+
+(Arg <t>) && t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t) ->
+  (StructMake0)
+(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t) ->
+  (StructMake1
+    (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)]))
+(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t) ->
+  (StructMake2
+    (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])
+    (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)]))
+(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t) ->
+  (StructMake3
+    (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])
+    (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)])
+    (Arg <t.FieldType(2)> {n} [off+t.FieldOff(2)]))
+(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t) ->
+  (StructMake4
+    (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])
+    (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)])
+    (Arg <t.FieldType(2)> {n} [off+t.FieldOff(2)])
+    (Arg <t.FieldType(3)> {n} [off+t.FieldOff(3)]))
+
+// strength reduction of divide by a constant.
+// Note: frontend does <=32 bits. We only need to do 64 bits here.
+// TODO: Do them all here?
+
+// Div/mod by 1.  Currently handled by frontend.
+//(Div64 n (Const64 [1])) -> n
+//(Div64u n (Const64 [1])) -> n
+//(Mod64 n (Const64 [1])) -> (Const64 [0])
+//(Mod64u n (Const64 [1])) -> (Const64 [0])
+
+// Unsigned divide by power of 2.
+(Div64u <t> n (Const64 [c])) && isPowerOfTwo(c) -> (Rsh64Ux64 n (Const64 <t> [log2(c)]))
+(Mod64u <t> n (Const64 [c])) && isPowerOfTwo(c) -> (And64 n (Const64 <t> [c-1]))
+
+// Signed divide by power of 2.  Currently handled by frontend.
+// n / c = n >> log(c)       if n >= 0
+//       = (n+c-1) >> log(c) if n < 0
+// We conditionally add c-1 by adding n>>63>>(64-log(c)) (first shift signed, second shift unsigned).
+//(Div64 <t> n (Const64 [c])) && isPowerOfTwo(c) ->
+//  (Rsh64x64
+//    (Add64 <t>
+//      n
+//      (Rsh64Ux64 <t>
+//        (Rsh64x64 <t> n (Const64 <t> [63]))
+//        (Const64 <t> [64-log2(c)])))
+//    (Const64 <t> [log2(c)]))
+
+// Unsigned divide, not a power of 2.  Strength reduce to a multiply.
+(Div64u <t> x (Const64 [c])) && umagic64ok(c) && !umagic64a(c) ->
+  (Rsh64Ux64
+    (Hmul64u <t>
+      (Const64 <t> [umagic64m(c)])
+      x)
+    (Const64 <t> [umagic64s(c)]))
+(Div64u <t> x (Const64 [c])) && umagic64ok(c) && umagic64a(c) ->
+  (Rsh64Ux64
+    (Avg64u <t>
+      (Hmul64u <t>
+        x
+        (Const64 <t> [umagic64m(c)]))
+      x)
+    (Const64 <t> [umagic64s(c)-1]))
+
+// Signed divide, not a power of 2.  Strength reduce to a multiply.
+(Div64 <t> x (Const64 [c])) && c > 0 && smagic64ok(c) && smagic64m(c) > 0 ->
+  (Sub64 <t>
+    (Rsh64x64 <t>
+      (Hmul64 <t>
+        (Const64 <t> [smagic64m(c)])
+        x)
+      (Const64 <t> [smagic64s(c)]))
+    (Rsh64x64 <t>
+      x
+      (Const64 <t> [63])))
+(Div64 <t> x (Const64 [c])) && c > 0 && smagic64ok(c) && smagic64m(c) < 0 ->
+  (Sub64 <t>
+    (Rsh64x64 <t>
+      (Add64 <t>
+        (Hmul64 <t>
+          (Const64 <t> [smagic64m(c)])
+          x)
+        x)
+      (Const64 <t> [smagic64s(c)]))
+    (Rsh64x64 <t>
+      x
+      (Const64 <t> [63])))
+(Div64 <t> x (Const64 [c])) && c < 0 && smagic64ok(c) && smagic64m(c) > 0 ->
+  (Neg64 <t>
+    (Sub64 <t>
+      (Rsh64x64 <t>
+        (Hmul64 <t>
+          (Const64 <t> [smagic64m(c)])
+          x)
+        (Const64 <t> [smagic64s(c)]))
+      (Rsh64x64 <t>
+        x
+        (Const64 <t> [63]))))
+(Div64 <t> x (Const64 [c])) && c < 0 && smagic64ok(c) && smagic64m(c) < 0 ->
+  (Neg64 <t>
+    (Sub64 <t>
+      (Rsh64x64 <t>
+        (Add64 <t>
+          (Hmul64 <t>
+            (Const64 <t> [smagic64m(c)])
+            x)
+          x)
+        (Const64 <t> [smagic64s(c)]))
+      (Rsh64x64 <t>
+        x
+        (Const64 <t> [63]))))
+
+// A%B = A-(A/B*B).
+// This implements % with two * and a bunch of ancillary ops.
+// One of the * is free if the user's code also computes A/B.
+(Mod64  <t> x (Const64 [c])) && x.Op != OpConst64 && smagic64ok(c)
+  -> (Sub64 x (Mul64 <t> (Div64  <t> x (Const64 <t> [c])) (Const64 <t> [c])))
+(Mod64u <t> x (Const64 [c])) && x.Op != OpConst64 && umagic64ok(c)
+  -> (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
new file mode 100644
index 0000000..8388ea8
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.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.
+
+// +build ignore
+
+package main
+
+// Generic opcodes typically specify a width. The inputs and outputs
+// of that op are the given number of bits wide. There is no notion of
+// "sign", so Add32 can be used both for signed and unsigned 32-bit
+// addition.
+
+// Signed/unsigned is explicit with the extension ops
+// (SignExt*/ZeroExt*) and implicit as the arg to some opcodes
+// (e.g. the second argument to shifts is unsigned). If not mentioned,
+// all args take signed inputs, or don't care whether their inputs
+// are signed or unsigned.
+
+// Unused portions of AuxInt are filled by sign-extending the used portion.
+// Users of AuxInt which interpret AuxInt as unsigned (e.g. shifts) must be careful.
+var genericOps = []opData{
+	// 2-input arithmetic
+	// Types must be consistent with Go typing. Add, for example, must take two values
+	// of the same type and produces that same type.
+	{name: "Add8", argLength: 2, commutative: true}, // arg0 + arg1
+	{name: "Add16", argLength: 2, commutative: true},
+	{name: "Add32", argLength: 2, commutative: true},
+	{name: "Add64", argLength: 2, commutative: true},
+	{name: "AddPtr", argLength: 2}, // For address calculations.  arg0 is a pointer and arg1 is an int.
+	{name: "Add32F", argLength: 2},
+	{name: "Add64F", argLength: 2},
+
+	{name: "Sub8", argLength: 2}, // arg0 - arg1
+	{name: "Sub16", argLength: 2},
+	{name: "Sub32", argLength: 2},
+	{name: "Sub64", argLength: 2},
+	{name: "SubPtr", argLength: 2},
+	{name: "Sub32F", argLength: 2},
+	{name: "Sub64F", argLength: 2},
+
+	{name: "Mul8", argLength: 2, commutative: true}, // arg0 * arg1
+	{name: "Mul16", argLength: 2, commutative: true},
+	{name: "Mul32", argLength: 2, commutative: true},
+	{name: "Mul64", argLength: 2, commutative: true},
+	{name: "Mul32F", argLength: 2},
+	{name: "Mul64F", argLength: 2},
+
+	{name: "Div32F", argLength: 2}, // arg0 / arg1
+	{name: "Div64F", argLength: 2},
+
+	{name: "Hmul8", argLength: 2},  // (arg0 * arg1) >> width, signed
+	{name: "Hmul8u", argLength: 2}, // (arg0 * arg1) >> width, unsigned
+	{name: "Hmul16", argLength: 2},
+	{name: "Hmul16u", argLength: 2},
+	{name: "Hmul32", argLength: 2},
+	{name: "Hmul32u", argLength: 2},
+	{name: "Hmul64", argLength: 2},
+	{name: "Hmul64u", argLength: 2},
+
+	// Weird special instruction for strength reduction of divides.
+	{name: "Avg64u", argLength: 2}, // (uint64(arg0) + uint64(arg1)) / 2, correct to all 64 bits.
+
+	{name: "Div8", argLength: 2},  // arg0 / arg1, signed
+	{name: "Div8u", argLength: 2}, // arg0 / arg1, unsigned
+	{name: "Div16", argLength: 2},
+	{name: "Div16u", argLength: 2},
+	{name: "Div32", argLength: 2},
+	{name: "Div32u", argLength: 2},
+	{name: "Div64", argLength: 2},
+	{name: "Div64u", argLength: 2},
+
+	{name: "Mod8", argLength: 2},  // arg0 % arg1, signed
+	{name: "Mod8u", argLength: 2}, // arg0 % arg1, unsigned
+	{name: "Mod16", argLength: 2},
+	{name: "Mod16u", argLength: 2},
+	{name: "Mod32", argLength: 2},
+	{name: "Mod32u", argLength: 2},
+	{name: "Mod64", argLength: 2},
+	{name: "Mod64u", argLength: 2},
+
+	{name: "And8", argLength: 2, commutative: true}, // arg0 & arg1
+	{name: "And16", argLength: 2, commutative: true},
+	{name: "And32", argLength: 2, commutative: true},
+	{name: "And64", argLength: 2, commutative: true},
+
+	{name: "Or8", argLength: 2, commutative: true}, // arg0 | arg1
+	{name: "Or16", argLength: 2, commutative: true},
+	{name: "Or32", argLength: 2, commutative: true},
+	{name: "Or64", argLength: 2, commutative: true},
+
+	{name: "Xor8", argLength: 2, commutative: true}, // arg0 ^ arg1
+	{name: "Xor16", argLength: 2, commutative: true},
+	{name: "Xor32", argLength: 2, commutative: true},
+	{name: "Xor64", argLength: 2, commutative: true},
+
+	// For shifts, AxB means the shifted value has A bits and the shift amount has B bits.
+	// Shift amounts are considered unsigned.
+	{name: "Lsh8x8", argLength: 2}, // arg0 << arg1
+	{name: "Lsh8x16", argLength: 2},
+	{name: "Lsh8x32", argLength: 2},
+	{name: "Lsh8x64", argLength: 2},
+	{name: "Lsh16x8", argLength: 2},
+	{name: "Lsh16x16", argLength: 2},
+	{name: "Lsh16x32", argLength: 2},
+	{name: "Lsh16x64", argLength: 2},
+	{name: "Lsh32x8", argLength: 2},
+	{name: "Lsh32x16", argLength: 2},
+	{name: "Lsh32x32", argLength: 2},
+	{name: "Lsh32x64", argLength: 2},
+	{name: "Lsh64x8", argLength: 2},
+	{name: "Lsh64x16", argLength: 2},
+	{name: "Lsh64x32", argLength: 2},
+	{name: "Lsh64x64", argLength: 2},
+
+	{name: "Rsh8x8", argLength: 2}, // arg0 >> arg1, signed
+	{name: "Rsh8x16", argLength: 2},
+	{name: "Rsh8x32", argLength: 2},
+	{name: "Rsh8x64", argLength: 2},
+	{name: "Rsh16x8", argLength: 2},
+	{name: "Rsh16x16", argLength: 2},
+	{name: "Rsh16x32", argLength: 2},
+	{name: "Rsh16x64", argLength: 2},
+	{name: "Rsh32x8", argLength: 2},
+	{name: "Rsh32x16", argLength: 2},
+	{name: "Rsh32x32", argLength: 2},
+	{name: "Rsh32x64", argLength: 2},
+	{name: "Rsh64x8", argLength: 2},
+	{name: "Rsh64x16", argLength: 2},
+	{name: "Rsh64x32", argLength: 2},
+	{name: "Rsh64x64", argLength: 2},
+
+	{name: "Rsh8Ux8", argLength: 2}, // arg0 >> arg1, unsigned
+	{name: "Rsh8Ux16", argLength: 2},
+	{name: "Rsh8Ux32", argLength: 2},
+	{name: "Rsh8Ux64", argLength: 2},
+	{name: "Rsh16Ux8", argLength: 2},
+	{name: "Rsh16Ux16", argLength: 2},
+	{name: "Rsh16Ux32", argLength: 2},
+	{name: "Rsh16Ux64", argLength: 2},
+	{name: "Rsh32Ux8", argLength: 2},
+	{name: "Rsh32Ux16", argLength: 2},
+	{name: "Rsh32Ux32", argLength: 2},
+	{name: "Rsh32Ux64", argLength: 2},
+	{name: "Rsh64Ux8", argLength: 2},
+	{name: "Rsh64Ux16", argLength: 2},
+	{name: "Rsh64Ux32", argLength: 2},
+	{name: "Rsh64Ux64", argLength: 2},
+
+	// (Left) rotates replace pattern matches in the front end
+	// of (arg0 << arg1) ^ (arg0 >> (A-arg1))
+	// where A is the bit width of arg0 and result.
+	// Note that because rotates are pattern-matched from
+	// shifts, that a rotate of arg1=A+k (k > 0) bits originated from
+	//    (arg0 << A+k) ^ (arg0 >> -k) =
+	//    0 ^ arg0>>huge_unsigned =
+	//    0 ^ 0 = 0
+	// which is not the same as a rotation by A+k
+	//
+	// However, in the specific case of k = 0, the result of
+	// the shift idiom is the same as the result for the
+	// rotate idiom, i.e., result=arg0.
+	// This is different from shifts, where
+	// arg0 << A is defined to be zero.
+	//
+	// Because of this, and also because the primary use case
+	// for rotates is hashing and crypto code with constant
+	// distance, rotate instructions are only substituted
+	// when arg1 is a constant between 1 and A-1, inclusive.
+	{name: "Lrot8", argLength: 1, aux: "Int64"},
+	{name: "Lrot16", argLength: 1, aux: "Int64"},
+	{name: "Lrot32", argLength: 1, aux: "Int64"},
+	{name: "Lrot64", argLength: 1, aux: "Int64"},
+
+	// 2-input comparisons
+	{name: "Eq8", argLength: 2, commutative: true}, // arg0 == arg1
+	{name: "Eq16", argLength: 2, commutative: true},
+	{name: "Eq32", argLength: 2, commutative: true},
+	{name: "Eq64", argLength: 2, commutative: true},
+	{name: "EqPtr", argLength: 2, commutative: true},
+	{name: "EqInter", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
+	{name: "EqSlice", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
+	{name: "Eq32F", argLength: 2},
+	{name: "Eq64F", argLength: 2},
+
+	{name: "Neq8", argLength: 2, commutative: true}, // arg0 != arg1
+	{name: "Neq16", argLength: 2, commutative: true},
+	{name: "Neq32", argLength: 2, commutative: true},
+	{name: "Neq64", argLength: 2, commutative: true},
+	{name: "NeqPtr", argLength: 2, commutative: true},
+	{name: "NeqInter", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
+	{name: "NeqSlice", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
+	{name: "Neq32F", argLength: 2},
+	{name: "Neq64F", argLength: 2},
+
+	{name: "Less8", argLength: 2},  // arg0 < arg1, signed
+	{name: "Less8U", argLength: 2}, // arg0 < arg1, unsigned
+	{name: "Less16", argLength: 2},
+	{name: "Less16U", argLength: 2},
+	{name: "Less32", argLength: 2},
+	{name: "Less32U", argLength: 2},
+	{name: "Less64", argLength: 2},
+	{name: "Less64U", argLength: 2},
+	{name: "Less32F", argLength: 2},
+	{name: "Less64F", argLength: 2},
+
+	{name: "Leq8", argLength: 2},  // arg0 <= arg1, signed
+	{name: "Leq8U", argLength: 2}, // arg0 <= arg1, unsigned
+	{name: "Leq16", argLength: 2},
+	{name: "Leq16U", argLength: 2},
+	{name: "Leq32", argLength: 2},
+	{name: "Leq32U", argLength: 2},
+	{name: "Leq64", argLength: 2},
+	{name: "Leq64U", argLength: 2},
+	{name: "Leq32F", argLength: 2},
+	{name: "Leq64F", argLength: 2},
+
+	{name: "Greater8", argLength: 2},  // arg0 > arg1, signed
+	{name: "Greater8U", argLength: 2}, // arg0 > arg1, unsigned
+	{name: "Greater16", argLength: 2},
+	{name: "Greater16U", argLength: 2},
+	{name: "Greater32", argLength: 2},
+	{name: "Greater32U", argLength: 2},
+	{name: "Greater64", argLength: 2},
+	{name: "Greater64U", argLength: 2},
+	{name: "Greater32F", argLength: 2},
+	{name: "Greater64F", argLength: 2},
+
+	{name: "Geq8", argLength: 2},  // arg0 <= arg1, signed
+	{name: "Geq8U", argLength: 2}, // arg0 <= arg1, unsigned
+	{name: "Geq16", argLength: 2},
+	{name: "Geq16U", argLength: 2},
+	{name: "Geq32", argLength: 2},
+	{name: "Geq32U", argLength: 2},
+	{name: "Geq64", argLength: 2},
+	{name: "Geq64U", argLength: 2},
+	{name: "Geq32F", argLength: 2},
+	{name: "Geq64F", argLength: 2},
+
+	// boolean ops
+	{name: "AndB", argLength: 2}, // arg0 && arg1 (not shortcircuited)
+	{name: "OrB", argLength: 2},  // arg0 || arg1 (not shortcircuited)
+	{name: "EqB", argLength: 2},  // arg0 == arg1
+	{name: "NeqB", argLength: 2}, // arg0 != arg1
+	{name: "Not", argLength: 1},  // !arg0, boolean
+
+	// 1-input ops
+	{name: "Neg8", argLength: 1}, // -arg0
+	{name: "Neg16", argLength: 1},
+	{name: "Neg32", argLength: 1},
+	{name: "Neg64", argLength: 1},
+	{name: "Neg32F", argLength: 1},
+	{name: "Neg64F", argLength: 1},
+
+	{name: "Com8", argLength: 1}, // ^arg0
+	{name: "Com16", argLength: 1},
+	{name: "Com32", argLength: 1},
+	{name: "Com64", argLength: 1},
+
+	{name: "Ctz16", argLength: 1}, // Count trailing (low  order) zeroes (returns 0-16)
+	{name: "Ctz32", argLength: 1}, // Count trailing zeroes (returns 0-32)
+	{name: "Ctz64", argLength: 1}, // Count trailing zeroes (returns 0-64)
+
+	{name: "Clz16", argLength: 1}, // Count leading (high order) zeroes (returns 0-16)
+	{name: "Clz32", argLength: 1}, // Count leading zeroes (returns 0-32)
+	{name: "Clz64", argLength: 1}, // Count leading zeroes (returns 0-64)
+
+	{name: "Bswap32", argLength: 1}, // Swap bytes
+	{name: "Bswap64", argLength: 1}, // Swap bytes
+
+	{name: "Sqrt", argLength: 1}, // sqrt(arg0), float64 only
+
+	// Data movement, max argument length for Phi is indefinite so just pick
+	// a really large number
+	{name: "Phi", argLength: -1}, // select an argument based on which predecessor block we came from
+	{name: "Copy", argLength: 1}, // output = arg0
+	// Convert converts between pointers and integers.
+	// We have a special op for this so as to not confuse GC
+	// (particularly stack maps).  It takes a memory arg so it
+	// gets correctly ordered with respect to GC safepoints.
+	// arg0=ptr/int arg1=mem, output=int/ptr
+	{name: "Convert", argLength: 2},
+
+	// constants. Constant values are stored in the aux or
+	// auxint fields.
+	{name: "ConstBool", aux: "Bool"},     // auxint is 0 for false and 1 for true
+	{name: "ConstString", aux: "String"}, // value is aux.(string)
+	{name: "ConstNil", typ: "BytePtr"},   // nil pointer
+	{name: "Const8", aux: "Int8"},        // auxint is sign-extended 8 bits
+	{name: "Const16", aux: "Int16"},      // auxint is sign-extended 16 bits
+	{name: "Const32", aux: "Int32"},      // auxint is sign-extended 32 bits
+	{name: "Const64", aux: "Int64"},      // value is auxint
+	{name: "Const32F", aux: "Float32"},   // value is math.Float64frombits(uint64(auxint)) and is exactly prepresentable as float 32
+	{name: "Const64F", aux: "Float64"},   // value is math.Float64frombits(uint64(auxint))
+	{name: "ConstInterface"},             // nil interface
+	{name: "ConstSlice"},                 // nil slice
+
+	// Constant-like things
+	{name: "InitMem"},            // memory input to the function.
+	{name: "Arg", aux: "SymOff"}, // argument to the function.  aux=GCNode of arg, off = offset in that arg.
+
+	// The address of a variable.  arg0 is the base pointer (SB or SP, depending
+	// on whether it is a global or stack variable).  The Aux field identifies the
+	// variable. It will be either an *ExternSymbol (with arg0=SB), *ArgSymbol (arg0=SP),
+	// or *AutoSymbol (arg0=SP).
+	{name: "Addr", argLength: 1, aux: "Sym"}, // Address of a variable.  Arg0=SP or SB.  Aux identifies the variable.
+
+	{name: "SP"},                 // stack pointer
+	{name: "SB", typ: "Uintptr"}, // static base pointer (a.k.a. globals pointer)
+	{name: "Func", aux: "Sym"},   // entry address of a function
+
+	// Memory operations
+	{name: "Load", argLength: 2},                            // Load from arg0.  arg1=memory
+	{name: "Store", argLength: 3, typ: "Mem", aux: "Int64"}, // Store arg1 to arg0.  arg2=memory, auxint=size.  Returns memory.
+	{name: "Move", argLength: 3, aux: "Int64"},              // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size.  Returns memory.
+	{name: "Zero", argLength: 2, aux: "Int64"},              // arg0=destptr, arg1=mem, auxint=size. Returns memory.
+
+	// Function calls. Arguments to the call have already been written to the stack.
+	// Return values appear on the stack. The method receiver, if any, is treated
+	// as a phantom first argument.
+	{name: "ClosureCall", argLength: 3, aux: "Int64"}, // arg0=code pointer, arg1=context ptr, arg2=memory.  auxint=arg size.  Returns memory.
+	{name: "StaticCall", argLength: 1, aux: "SymOff"}, // call function aux.(*gc.Sym), arg0=memory.  auxint=arg size.  Returns memory.
+	{name: "DeferCall", argLength: 1, aux: "Int64"},   // defer call.  arg0=memory, auxint=arg size.  Returns memory.
+	{name: "GoCall", argLength: 1, aux: "Int64"},      // go call.  arg0=memory, auxint=arg size.  Returns memory.
+	{name: "InterCall", argLength: 2, aux: "Int64"},   // interface call.  arg0=code pointer, arg1=memory, auxint=arg size.  Returns memory.
+
+	// Conversions: signed extensions, zero (unsigned) extensions, truncations
+	{name: "SignExt8to16", argLength: 1, typ: "Int16"},
+	{name: "SignExt8to32", argLength: 1},
+	{name: "SignExt8to64", argLength: 1},
+	{name: "SignExt16to32", argLength: 1},
+	{name: "SignExt16to64", argLength: 1},
+	{name: "SignExt32to64", argLength: 1},
+	{name: "ZeroExt8to16", argLength: 1, typ: "UInt16"},
+	{name: "ZeroExt8to32", argLength: 1},
+	{name: "ZeroExt8to64", argLength: 1},
+	{name: "ZeroExt16to32", argLength: 1},
+	{name: "ZeroExt16to64", argLength: 1},
+	{name: "ZeroExt32to64", argLength: 1},
+	{name: "Trunc16to8", argLength: 1},
+	{name: "Trunc32to8", argLength: 1},
+	{name: "Trunc32to16", argLength: 1},
+	{name: "Trunc64to8", argLength: 1},
+	{name: "Trunc64to16", argLength: 1},
+	{name: "Trunc64to32", argLength: 1},
+
+	{name: "Cvt32to32F", argLength: 1},
+	{name: "Cvt32to64F", argLength: 1},
+	{name: "Cvt64to32F", argLength: 1},
+	{name: "Cvt64to64F", argLength: 1},
+	{name: "Cvt32Fto32", argLength: 1},
+	{name: "Cvt32Fto64", argLength: 1},
+	{name: "Cvt64Fto32", argLength: 1},
+	{name: "Cvt64Fto64", argLength: 1},
+	{name: "Cvt32Fto64F", argLength: 1},
+	{name: "Cvt64Fto32F", argLength: 1},
+
+	// Automatically inserted safety checks
+	{name: "IsNonNil", argLength: 1, typ: "Bool"},        // arg0 != nil
+	{name: "IsInBounds", argLength: 2, typ: "Bool"},      // 0 <= arg0 < arg1. arg1 is guaranteed >= 0.
+	{name: "IsSliceInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 <= arg1. arg1 is guaranteed >= 0.
+	{name: "NilCheck", argLength: 2, typ: "Void"},        // arg0=ptr, arg1=mem. Panics if arg0 is nil, returns void.
+
+	// Pseudo-ops
+	{name: "GetG", argLength: 1}, // runtime.getg() (read g pointer). arg0=mem
+	{name: "GetClosurePtr"},      // get closure pointer from dedicated register
+
+	// Indexing operations
+	{name: "ArrayIndex", aux: "Int64", argLength: 1}, // arg0=array, auxint=index. Returns a[i]
+	{name: "PtrIndex", argLength: 2},                 // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
+	{name: "OffPtr", argLength: 1, aux: "Int64"},     // arg0 + auxint (arg0 and result are pointers)
+
+	// Slices
+	{name: "SliceMake", argLength: 3},                // arg0=ptr, arg1=len, arg2=cap
+	{name: "SlicePtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0)
+	{name: "SliceLen", argLength: 1},                 // len(arg0)
+	{name: "SliceCap", argLength: 1},                 // cap(arg0)
+
+	// Complex (part/whole)
+	{name: "ComplexMake", argLength: 2}, // arg0=real, arg1=imag
+	{name: "ComplexReal", argLength: 1}, // real(arg0)
+	{name: "ComplexImag", argLength: 1}, // imag(arg0)
+
+	// Strings
+	{name: "StringMake", argLength: 2},                // arg0=ptr, arg1=len
+	{name: "StringPtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0)
+	{name: "StringLen", argLength: 1, typ: "Int"},     // len(arg0)
+
+	// Interfaces
+	{name: "IMake", argLength: 2},                // arg0=itab, arg1=data
+	{name: "ITab", argLength: 1, typ: "BytePtr"}, // arg0=interface, returns itable field
+	{name: "IData", argLength: 1},                // arg0=interface, returns data field
+
+	// Structs
+	{name: "StructMake0"},                              // Returns struct with 0 fields.
+	{name: "StructMake1", argLength: 1},                // arg0=field0.  Returns struct.
+	{name: "StructMake2", argLength: 2},                // arg0,arg1=field0,field1.  Returns struct.
+	{name: "StructMake3", argLength: 3},                // arg0..2=field0..2.  Returns struct.
+	{name: "StructMake4", argLength: 4},                // arg0..3=field0..3.  Returns struct.
+	{name: "StructSelect", argLength: 1, aux: "Int64"}, // arg0=struct, auxint=field index.  Returns the auxint'th field.
+
+	// Spill&restore ops for the register allocator. These are
+	// semantically identical to OpCopy; they do not take/return
+	// stores like regular memory ops do. We can get away without memory
+	// args because we know there is no aliasing of spill slots on the stack.
+	{name: "StoreReg", argLength: 1},
+	{name: "LoadReg", argLength: 1},
+
+	// Used during ssa construction. Like Copy, but the arg has not been specified yet.
+	{name: "FwdRef", aux: "Sym"},
+
+	// Unknown value. Used for Values whose values don't matter because they are dead code.
+	{name: "Unknown"},
+
+	{name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized.  arg0=mem, returns mem
+	{name: "VarKill", argLength: 1, aux: "Sym"},            // aux is a *gc.Node of a variable that is known to be dead.  arg0=mem, returns mem
+	{name: "VarLive", argLength: 1, aux: "Sym"},            // aux is a *gc.Node of a variable that must be kept live.  arg0=mem, returns mem
+	{name: "KeepAlive", argLength: 2, typ: "Mem"},          // arg[0] is a value that must be kept alive until this mark.  arg[1]=mem, returns mem
+}
+
+//     kind           control    successors       implicit exit
+//   ----------------------------------------------------------
+//     Exit        return mem                []             yes
+//      Ret        return mem                []             yes
+//   RetJmp        return mem                []             yes
+//    Plain               nil            [next]
+//       If   a boolean Value      [then, else]
+//     Call               mem            [next]             yes  (control opcode should be OpCall or OpStaticCall)
+//    Check              void            [next]             yes  (control opcode should be Op{Lowered}NilCheck)
+//    First               nil    [always,never]
+
+var genericBlocks = []blockData{
+	{name: "Plain"},  // a single successor
+	{name: "If"},     // 2 successors, if control goto Succs[0] else goto Succs[1]
+	{name: "Call"},   // 1 successor, control is call op (of memory type)
+	{name: "Defer"},  // 2 successors, Succs[0]=defer queued, Succs[1]=defer recovered. control is call op (of memory type)
+	{name: "Check"},  // 1 successor, control is nilcheck op (of void type)
+	{name: "Ret"},    // no successors, control value is memory result
+	{name: "RetJmp"}, // no successors, jumps to b.Aux.(*gc.Sym)
+	{name: "Exit"},   // no successors, control value generates a panic
+
+	// transient block state used for dead code removal
+	{name: "First"}, // 2 successors, always takes the first one (second is dead)
+}
+
+func init() {
+	archs = append(archs, arch{
+		name:    "generic",
+		ops:     genericOps,
+		blocks:  genericBlocks,
+		generic: true,
+	})
+}
diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go
new file mode 100644
index 0000000..2aec4a3
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/main.go
@@ -0,0 +1,300 @@
+// Copyright 2015 The Go 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
+
+// The gen command generates Go code (in the parent directory) for all
+// the architecture-specific opcodes, blocks, and rewrites.
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/format"
+	"io/ioutil"
+	"log"
+	"path"
+	"regexp"
+	"sort"
+)
+
+type arch struct {
+	name     string
+	pkg      string // obj package to import for this arch.
+	genfile  string // source file containing opcode code generation.
+	ops      []opData
+	blocks   []blockData
+	regnames []string
+	generic  bool
+}
+
+type opData struct {
+	name              string
+	reg               regInfo
+	asm               string
+	typ               string // default result type
+	aux               string
+	rematerializeable bool
+	argLength         int32 // number of arguments, if -1, then this operation has a variable number of arguments
+	commutative       bool  // this operation is commutative (e.g. addition)
+	resultInArg0      bool  // v and v.Args[0] must be allocated to the same register
+}
+
+type blockData struct {
+	name string
+}
+
+type regInfo struct {
+	inputs   []regMask
+	clobbers regMask
+	outputs  []regMask
+}
+
+type regMask uint64
+
+func (a arch) regMaskComment(r regMask) string {
+	var buf bytes.Buffer
+	for i := uint64(0); r != 0; i++ {
+		if r&1 != 0 {
+			if buf.Len() == 0 {
+				buf.WriteString(" //")
+			}
+			buf.WriteString(" ")
+			buf.WriteString(a.regnames[i])
+		}
+		r >>= 1
+	}
+	return buf.String()
+}
+
+var archs []arch
+
+func main() {
+	flag.Parse()
+	genOp()
+	genLower()
+}
+
+func genOp() {
+	w := new(bytes.Buffer)
+	fmt.Fprintf(w, "// autogenerated: do not edit!\n")
+	fmt.Fprintf(w, "// generated from gen/*Ops.go\n")
+	fmt.Fprintln(w)
+	fmt.Fprintln(w, "package ssa")
+
+	fmt.Fprintln(w, "import (")
+	fmt.Fprintln(w, "\"cmd/internal/obj\"")
+	for _, a := range archs {
+		if a.pkg != "" {
+			fmt.Fprintf(w, "%q\n", a.pkg)
+		}
+	}
+	fmt.Fprintln(w, ")")
+
+	// generate Block* declarations
+	fmt.Fprintln(w, "const (")
+	fmt.Fprintln(w, "BlockInvalid BlockKind = iota")
+	for _, a := range archs {
+		fmt.Fprintln(w)
+		for _, d := range a.blocks {
+			fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name)
+		}
+	}
+	fmt.Fprintln(w, ")")
+
+	// generate block kind string method
+	fmt.Fprintln(w, "var blockString = [...]string{")
+	fmt.Fprintln(w, "BlockInvalid:\"BlockInvalid\",")
+	for _, a := range archs {
+		fmt.Fprintln(w)
+		for _, b := range a.blocks {
+			fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name)
+		}
+	}
+	fmt.Fprintln(w, "}")
+	fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}")
+
+	// generate Op* declarations
+	fmt.Fprintln(w, "const (")
+	fmt.Fprintln(w, "OpInvalid Op = iota")
+	for _, a := range archs {
+		fmt.Fprintln(w)
+		for _, v := range a.ops {
+			fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name)
+		}
+	}
+	fmt.Fprintln(w, ")")
+
+	// generate OpInfo table
+	fmt.Fprintln(w, "var opcodeTable = [...]opInfo{")
+	fmt.Fprintln(w, " { name: \"OpInvalid\" },")
+	for _, a := range archs {
+		fmt.Fprintln(w)
+
+		pkg := path.Base(a.pkg)
+		for _, v := range a.ops {
+			fmt.Fprintln(w, "{")
+			fmt.Fprintf(w, "name:\"%s\",\n", v.name)
+
+			// flags
+			if v.aux != "" {
+				fmt.Fprintf(w, "auxType: aux%s,\n", v.aux)
+			}
+			fmt.Fprintf(w, "argLen: %d,\n", v.argLength)
+
+			if v.rematerializeable {
+				if v.reg.clobbers != 0 {
+					log.Fatalf("%s is rematerializeable and clobbers registers", v.name)
+				}
+				fmt.Fprintln(w, "rematerializeable: true,")
+			}
+			if v.commutative {
+				fmt.Fprintln(w, "commutative: true,")
+			}
+			if v.resultInArg0 {
+				fmt.Fprintln(w, "resultInArg0: true,")
+				if v.reg.inputs[0] != v.reg.outputs[0] {
+					log.Fatalf("input[0] and output registers must be equal for %s", v.name)
+				}
+				if v.commutative && v.reg.inputs[1] != v.reg.outputs[0] {
+					log.Fatalf("input[1] and output registers must be equal for %s", v.name)
+				}
+			}
+			if a.name == "generic" {
+				fmt.Fprintln(w, "generic:true,")
+				fmt.Fprintln(w, "},") // close op
+				// generic ops have no reg info or asm
+				continue
+			}
+			if v.asm != "" {
+				fmt.Fprintf(w, "asm: %s.A%s,\n", pkg, v.asm)
+			}
+			fmt.Fprintln(w, "reg:regInfo{")
+
+			// Compute input allocation order. We allocate from the
+			// most to the least constrained input. This order guarantees
+			// that we will always be able to find a register.
+			var s []intPair
+			for i, r := range v.reg.inputs {
+				if r != 0 {
+					s = append(s, intPair{countRegs(r), i})
+				}
+			}
+			if len(s) > 0 {
+				sort.Sort(byKey(s))
+				fmt.Fprintln(w, "inputs: []inputInfo{")
+				for _, p := range s {
+					r := v.reg.inputs[p.val]
+					fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
+				}
+				fmt.Fprintln(w, "},")
+			}
+			if v.reg.clobbers > 0 {
+				fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
+			}
+			// reg outputs
+			if len(v.reg.outputs) > 0 {
+				fmt.Fprintln(w, "outputs: []regMask{")
+				for _, r := range v.reg.outputs {
+					fmt.Fprintf(w, "%d,%s\n", r, a.regMaskComment(r))
+				}
+				fmt.Fprintln(w, "},")
+			}
+			fmt.Fprintln(w, "},") // close reg info
+			fmt.Fprintln(w, "},") // close op
+		}
+	}
+	fmt.Fprintln(w, "}")
+
+	fmt.Fprintln(w, "func (o Op) Asm() obj.As {return opcodeTable[o].asm}")
+
+	// generate op string method
+	fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
+
+	// generate registers
+	for _, a := range archs {
+		if a.generic {
+			continue
+		}
+		fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name)
+		for i, r := range a.regnames {
+			fmt.Fprintf(w, "  {%d, \"%s\"},\n", i, r)
+		}
+		fmt.Fprintln(w, "}")
+	}
+
+	// gofmt result
+	b := w.Bytes()
+	var err error
+	b, err = format.Source(b)
+	if err != nil {
+		fmt.Printf("%s\n", w.Bytes())
+		panic(err)
+	}
+
+	err = ioutil.WriteFile("../opGen.go", b, 0666)
+	if err != nil {
+		log.Fatalf("can't write output: %v\n", err)
+	}
+
+	// Check that the arch genfile handles all the arch-specific opcodes.
+	// This is very much a hack, but it is better than nothing.
+	for _, a := range archs {
+		if a.genfile == "" {
+			continue
+		}
+
+		src, err := ioutil.ReadFile(a.genfile)
+		if err != nil {
+			log.Fatalf("can't read %s: %v", a.genfile, err)
+		}
+
+		for _, v := range a.ops {
+			pattern := fmt.Sprintf("\\Wssa[.]Op%s%s\\W", a.name, v.name)
+			match, err := regexp.Match(pattern, src)
+			if err != nil {
+				log.Fatalf("bad opcode regexp %s: %v", pattern, err)
+			}
+			if !match {
+				log.Fatalf("Op%s%s has no code generation in %s", a.name, v.name, a.genfile)
+			}
+		}
+	}
+}
+
+// Name returns the name of the architecture for use in Op* and Block* enumerations.
+func (a arch) Name() string {
+	s := a.name
+	if s == "generic" {
+		s = ""
+	}
+	return s
+}
+
+func genLower() {
+	for _, a := range archs {
+		genRules(a)
+	}
+}
+
+// countRegs returns the number of set bits in the register mask.
+func countRegs(r regMask) int {
+	n := 0
+	for r != 0 {
+		n += int(r & 1)
+		r >>= 1
+	}
+	return n
+}
+
+// for sorting a pair of integers by key
+type intPair struct {
+	key, val int
+}
+type byKey []intPair
+
+func (a byKey) Len() int           { return len(a) }
+func (a byKey) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }
diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
new file mode 100644
index 0000000..0fc5749
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -0,0 +1,721 @@
+// Copyright 2015 The Go 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 gen
+
+// This program generates Go code that applies rewrite rules to a Value.
+// The generated code implements a function of type func (v *Value) bool
+// which returns true iff if did something.
+// Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
+
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"flag"
+	"fmt"
+	"go/format"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"regexp"
+	"sort"
+	"strings"
+)
+
+// rule syntax:
+//  sexpr [&& extra conditions] -> [@block] sexpr
+//
+// sexpr are s-expressions (lisp-like parenthesized groupings)
+// sexpr ::= (opcode sexpr*)
+//         | variable
+//         | <type>
+//         | [auxint]
+//         | {aux}
+//
+// aux      ::= variable | {code}
+// type     ::= variable | {code}
+// variable ::= some token
+// opcode   ::= one of the opcodes from ../op.go (without the Op prefix)
+
+// extra conditions is just a chunk of Go that evaluates to a boolean. It may use
+// variables declared in the matching sexpr. The variable "v" is predefined to be
+// the value matched by the entire rule.
+
+// If multiple rules match, the first one in file order is selected.
+
+var (
+	genLog = flag.Bool("log", false, "generate code that logs; for debugging only")
+)
+
+type Rule struct {
+	rule string
+	loc  string // file name & line number
+}
+
+func (r Rule) String() string {
+	return fmt.Sprintf("rule %q at %s", r.rule, r.loc)
+}
+
+// parse returns the matching part of the rule, additional conditions, and the result.
+func (r Rule) parse() (match, cond, result string) {
+	s := strings.Split(r.rule, "->")
+	if len(s) != 2 {
+		log.Fatalf("no arrow in %s", r)
+	}
+	match = strings.TrimSpace(s[0])
+	result = strings.TrimSpace(s[1])
+	cond = ""
+	if i := strings.Index(match, "&&"); i >= 0 {
+		cond = strings.TrimSpace(match[i+2:])
+		match = strings.TrimSpace(match[:i])
+	}
+	return match, cond, result
+}
+
+func genRules(arch arch) {
+	// Open input file.
+	text, err := os.Open(arch.name + ".rules")
+	if err != nil {
+		log.Fatalf("can't read rule file: %v", err)
+	}
+
+	// oprules contains a list of rules for each block and opcode
+	blockrules := map[string][]Rule{}
+	oprules := map[string][]Rule{}
+
+	// read rule file
+	scanner := bufio.NewScanner(text)
+	rule := ""
+	var lineno int
+	var ruleLineno int // line number of "->"
+	for scanner.Scan() {
+		lineno++
+		line := scanner.Text()
+		if i := strings.Index(line, "//"); i >= 0 {
+			// Remove comments. Note that this isn't string safe, so
+			// it will truncate lines with // inside strings. Oh well.
+			line = line[:i]
+		}
+		rule += " " + line
+		rule = strings.TrimSpace(rule)
+		if rule == "" {
+			continue
+		}
+		if !strings.Contains(rule, "->") {
+			continue
+		}
+		if ruleLineno == 0 {
+			ruleLineno = lineno
+		}
+		if strings.HasSuffix(rule, "->") {
+			continue
+		}
+		if unbalanced(rule) {
+			continue
+		}
+		op := strings.Split(rule, " ")[0][1:]
+		if op[len(op)-1] == ')' {
+			op = op[:len(op)-1] // rule has only opcode, e.g. (ConstNil) -> ...
+		}
+		loc := fmt.Sprintf("%s.rules:%d", arch.name, ruleLineno)
+		if isBlock(op, arch) {
+			blockrules[op] = append(blockrules[op], Rule{rule: rule, loc: loc})
+		} else {
+			oprules[op] = append(oprules[op], Rule{rule: rule, loc: loc})
+		}
+		rule = ""
+		ruleLineno = 0
+	}
+	if err := scanner.Err(); err != nil {
+		log.Fatalf("scanner failed: %v\n", err)
+	}
+	if unbalanced(rule) {
+		log.Fatalf("%s.rules:%d: unbalanced rule: %v\n", arch.name, lineno, rule)
+	}
+
+	// Order all the ops.
+	var ops []string
+	for op := range oprules {
+		ops = append(ops, op)
+	}
+	sort.Strings(ops)
+
+	// Start output buffer, write header.
+	w := new(bytes.Buffer)
+	fmt.Fprintf(w, "// autogenerated from gen/%s.rules: do not edit!\n", arch.name)
+	fmt.Fprintln(w, "// generated with: cd gen; go run *.go")
+	fmt.Fprintln(w)
+	fmt.Fprintln(w, "package ssa")
+	fmt.Fprintln(w, "import \"math\"")
+	fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used")
+
+	// Main rewrite routine is a switch on v.Op.
+	fmt.Fprintf(w, "func rewriteValue%s(v *Value, config *Config) bool {\n", arch.name)
+	fmt.Fprintf(w, "switch v.Op {\n")
+	for _, op := range ops {
+		fmt.Fprintf(w, "case %s:\n", opName(op, arch))
+		fmt.Fprintf(w, "return rewriteValue%s_%s(v, config)\n", arch.name, opName(op, arch))
+	}
+	fmt.Fprintf(w, "}\n")
+	fmt.Fprintf(w, "return false\n")
+	fmt.Fprintf(w, "}\n")
+
+	// Generate a routine per op. Note that we don't make one giant routine
+	// because it is too big for some compilers.
+	for _, op := range ops {
+		fmt.Fprintf(w, "func rewriteValue%s_%s(v *Value, config *Config) bool {\n", arch.name, opName(op, arch))
+		fmt.Fprintln(w, "b := v.Block")
+		fmt.Fprintln(w, "_ = b")
+		var canFail bool
+		for i, rule := range oprules[op] {
+			match, cond, result := rule.parse()
+			fmt.Fprintf(w, "// match: %s\n", match)
+			fmt.Fprintf(w, "// cond: %s\n", cond)
+			fmt.Fprintf(w, "// result: %s\n", result)
+
+			canFail = false
+			fmt.Fprintf(w, "for {\n")
+			if genMatch(w, arch, match, rule.loc) {
+				canFail = true
+			}
+
+			if cond != "" {
+				fmt.Fprintf(w, "if !(%s) {\nbreak\n}\n", cond)
+				canFail = true
+			}
+			if !canFail && i != len(oprules[op])-1 {
+				log.Fatalf("unconditional rule %s is followed by other rules", match)
+			}
+
+			genResult(w, arch, result, rule.loc)
+			if *genLog {
+				fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc)
+			}
+			fmt.Fprintf(w, "return true\n")
+
+			fmt.Fprintf(w, "}\n")
+		}
+		if canFail {
+			fmt.Fprintf(w, "return false\n")
+		}
+		fmt.Fprintf(w, "}\n")
+	}
+
+	// Generate block rewrite function. There are only a few block types
+	// so we can make this one function with a switch.
+	fmt.Fprintf(w, "func rewriteBlock%s(b *Block) bool {\n", arch.name)
+	fmt.Fprintf(w, "switch b.Kind {\n")
+	ops = nil
+	for op := range blockrules {
+		ops = append(ops, op)
+	}
+	sort.Strings(ops)
+	for _, op := range ops {
+		fmt.Fprintf(w, "case %s:\n", blockName(op, arch))
+		for _, rule := range blockrules[op] {
+			match, cond, result := rule.parse()
+			fmt.Fprintf(w, "// match: %s\n", match)
+			fmt.Fprintf(w, "// cond: %s\n", cond)
+			fmt.Fprintf(w, "// result: %s\n", result)
+
+			fmt.Fprintf(w, "for {\n")
+
+			s := split(match[1 : len(match)-1]) // remove parens, then split
+
+			// check match of control value
+			if s[1] != "nil" {
+				fmt.Fprintf(w, "v := b.Control\n")
+				if strings.Contains(s[1], "(") {
+					genMatch0(w, arch, s[1], "v", map[string]struct{}{}, false, rule.loc)
+				} else {
+					fmt.Fprintf(w, "%s := b.Control\n", s[1])
+				}
+			}
+
+			// assign successor names
+			succs := s[2:]
+			for i, a := range succs {
+				if a != "_" {
+					fmt.Fprintf(w, "%s := b.Succs[%d]\n", a, i)
+				}
+			}
+
+			if cond != "" {
+				fmt.Fprintf(w, "if !(%s) {\nbreak\n}\n", cond)
+			}
+
+			// Rule matches. Generate result.
+			t := split(result[1 : len(result)-1]) // remove parens, then split
+			newsuccs := t[2:]
+
+			// Check if newsuccs is the same set as succs.
+			m := map[string]bool{}
+			for _, succ := range succs {
+				if m[succ] {
+					log.Fatalf("can't have a repeat successor name %s in %s", succ, rule)
+				}
+				m[succ] = true
+			}
+			for _, succ := range newsuccs {
+				if !m[succ] {
+					log.Fatalf("unknown successor %s in %s", succ, rule)
+				}
+				delete(m, succ)
+			}
+			if len(m) != 0 {
+				log.Fatalf("unmatched successors %v in %s", m, rule)
+			}
+
+			fmt.Fprintf(w, "b.Kind = %s\n", blockName(t[0], arch))
+			if t[1] == "nil" {
+				fmt.Fprintf(w, "b.SetControl(nil)\n")
+			} else {
+				fmt.Fprintf(w, "b.SetControl(%s)\n", genResult0(w, arch, t[1], new(int), false, false, rule.loc))
+			}
+
+			succChanged := false
+			for i := 0; i < len(succs); i++ {
+				if succs[i] != newsuccs[i] {
+					succChanged = true
+				}
+			}
+			if succChanged {
+				if len(succs) != 2 {
+					log.Fatalf("changed successors, len!=2 in %s", rule)
+				}
+				if succs[0] != newsuccs[1] || succs[1] != newsuccs[0] {
+					log.Fatalf("can only handle swapped successors in %s", rule)
+				}
+				fmt.Fprintln(w, "b.swapSuccessors()")
+			}
+			for i := 0; i < len(succs); i++ {
+				fmt.Fprintf(w, "_ = %s\n", newsuccs[i])
+			}
+
+			if *genLog {
+				fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc)
+			}
+			fmt.Fprintf(w, "return true\n")
+
+			fmt.Fprintf(w, "}\n")
+		}
+	}
+	fmt.Fprintf(w, "}\n")
+	fmt.Fprintf(w, "return false\n")
+	fmt.Fprintf(w, "}\n")
+
+	// gofmt result
+	b := w.Bytes()
+	src, err := format.Source(b)
+	if err != nil {
+		fmt.Printf("%s\n", b)
+		panic(err)
+	}
+
+	// Write to file
+	err = ioutil.WriteFile("../rewrite"+arch.name+".go", src, 0666)
+	if err != nil {
+		log.Fatalf("can't write output: %v\n", err)
+	}
+}
+
+// genMatch returns true if the match can fail.
+func genMatch(w io.Writer, arch arch, match string, loc string) bool {
+	return genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc)
+}
+
+func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, top bool, loc string) bool {
+	if match[0] != '(' || match[len(match)-1] != ')' {
+		panic("non-compound expr in genMatch0: " + match)
+	}
+	canFail := false
+
+	// split body up into regions. Split by spaces/tabs, except those
+	// contained in () or {}.
+	s := split(match[1 : len(match)-1]) // remove parens, then split
+
+	// Find op record
+	var op opData
+	for _, x := range genericOps {
+		if x.name == s[0] {
+			op = x
+			break
+		}
+	}
+	for _, x := range arch.ops {
+		if x.name == s[0] {
+			op = x
+			break
+		}
+	}
+	if op.name == "" {
+		log.Fatalf("%s: unknown op %s", loc, s[0])
+	}
+
+	// check op
+	if !top {
+		fmt.Fprintf(w, "if %s.Op != %s {\nbreak\n}\n", v, opName(s[0], arch))
+		canFail = true
+	}
+
+	// check type/aux/args
+	argnum := 0
+	for _, a := range s[1:] {
+		if a[0] == '<' {
+			// type restriction
+			t := a[1 : len(a)-1] // remove <>
+			if !isVariable(t) {
+				// code. We must match the results of this code.
+				fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, t)
+				canFail = true
+			} else {
+				// variable
+				if _, ok := m[t]; ok {
+					// must match previous variable
+					fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, t)
+					canFail = true
+				} else {
+					m[t] = struct{}{}
+					fmt.Fprintf(w, "%s := %s.Type\n", t, v)
+				}
+			}
+		} else if a[0] == '[' {
+			// auxint restriction
+			switch op.aux {
+			case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32":
+			default:
+				log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
+			}
+			x := a[1 : len(a)-1] // remove []
+			if !isVariable(x) {
+				// code
+				fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, x)
+				canFail = true
+			} else {
+				// variable
+				if _, ok := m[x]; ok {
+					fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, x)
+					canFail = true
+				} else {
+					m[x] = struct{}{}
+					fmt.Fprintf(w, "%s := %s.AuxInt\n", x, v)
+				}
+			}
+		} else if a[0] == '{' {
+			// aux restriction
+			switch op.aux {
+			case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32":
+			default:
+				log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
+			}
+			x := a[1 : len(a)-1] // remove {}
+			if !isVariable(x) {
+				// code
+				fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, x)
+				canFail = true
+			} else {
+				// variable
+				if _, ok := m[x]; ok {
+					fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, x)
+					canFail = true
+				} else {
+					m[x] = struct{}{}
+					fmt.Fprintf(w, "%s := %s.Aux\n", x, v)
+				}
+			}
+		} else if a == "_" {
+			argnum++
+		} else if !strings.Contains(a, "(") {
+			// leaf variable
+			if _, ok := m[a]; ok {
+				// variable already has a definition. Check whether
+				// the old definition and the new definition match.
+				// For example, (add x x).  Equality is just pointer equality
+				// on Values (so cse is important to do before lowering).
+				fmt.Fprintf(w, "if %s != %s.Args[%d] {\nbreak\n}\n", a, v, argnum)
+				canFail = true
+			} else {
+				// remember that this variable references the given value
+				m[a] = struct{}{}
+				fmt.Fprintf(w, "%s := %s.Args[%d]\n", a, v, argnum)
+			}
+			argnum++
+		} else {
+			// compound sexpr
+			var argname string
+			colon := strings.Index(a, ":")
+			openparen := strings.Index(a, "(")
+			if colon >= 0 && openparen >= 0 && colon < openparen {
+				// rule-specified name
+				argname = a[:colon]
+				a = a[colon+1:]
+			} else {
+				// autogenerated name
+				argname = fmt.Sprintf("%s_%d", v, argnum)
+			}
+			fmt.Fprintf(w, "%s := %s.Args[%d]\n", argname, v, argnum)
+			if genMatch0(w, arch, a, argname, m, false, loc) {
+				canFail = true
+			}
+			argnum++
+		}
+	}
+	if op.argLength == -1 {
+		fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, argnum)
+		canFail = true
+	} else if int(op.argLength) != argnum {
+		log.Fatalf("%s: op %s should have %d args, has %d", loc, op.name, op.argLength, argnum)
+	}
+	return canFail
+}
+
+func genResult(w io.Writer, arch arch, result string, loc string) {
+	move := false
+	if result[0] == '@' {
+		// parse @block directive
+		s := strings.SplitN(result[1:], " ", 2)
+		fmt.Fprintf(w, "b = %s\n", s[0])
+		result = s[1]
+		move = true
+	}
+	genResult0(w, arch, result, new(int), true, move, loc)
+}
+func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move bool, loc string) string {
+	// TODO: when generating a constant result, use f.constVal to avoid
+	// introducing copies just to clean them up again.
+	if result[0] != '(' {
+		// variable
+		if top {
+			// It in not safe in general to move a variable between blocks
+			// (and particularly not a phi node).
+			// Introduce a copy.
+			fmt.Fprintf(w, "v.reset(OpCopy)\n")
+			fmt.Fprintf(w, "v.Type = %s.Type\n", result)
+			fmt.Fprintf(w, "v.AddArg(%s)\n", result)
+		}
+		return result
+	}
+
+	s := split(result[1 : len(result)-1]) // remove parens, then split
+
+	// Find op record
+	var op opData
+	for _, x := range genericOps {
+		if x.name == s[0] {
+			op = x
+			break
+		}
+	}
+	for _, x := range arch.ops {
+		if x.name == s[0] {
+			op = x
+			break
+		}
+	}
+	if op.name == "" {
+		log.Fatalf("%s: unknown op %s", loc, s[0])
+	}
+
+	// Find the type of the variable.
+	var opType string
+	var typeOverride bool
+	for _, a := range s[1:] {
+		if a[0] == '<' {
+			// type restriction
+			opType = a[1 : len(a)-1] // remove <>
+			typeOverride = true
+			break
+		}
+	}
+	if opType == "" {
+		// find default type, if any
+		for _, op := range arch.ops {
+			if op.name == s[0] && op.typ != "" {
+				opType = typeName(op.typ)
+				break
+			}
+		}
+	}
+	if opType == "" {
+		for _, op := range genericOps {
+			if op.name == s[0] && op.typ != "" {
+				opType = typeName(op.typ)
+				break
+			}
+		}
+	}
+	var v string
+	if top && !move {
+		v = "v"
+		fmt.Fprintf(w, "v.reset(%s)\n", opName(s[0], arch))
+		if typeOverride {
+			fmt.Fprintf(w, "v.Type = %s\n", opType)
+		}
+	} else {
+		if opType == "" {
+			log.Fatalf("sub-expression %s (op=%s) must have a type", result, s[0])
+		}
+		v = fmt.Sprintf("v%d", *alloc)
+		*alloc++
+		fmt.Fprintf(w, "%s := b.NewValue0(v.Line, %s, %s)\n", v, opName(s[0], arch), opType)
+		if move && top {
+			// Rewrite original into a copy
+			fmt.Fprintf(w, "v.reset(OpCopy)\n")
+			fmt.Fprintf(w, "v.AddArg(%s)\n", v)
+		}
+	}
+	argnum := 0
+	for _, a := range s[1:] {
+		if a[0] == '<' {
+			// type restriction, handled above
+		} else if a[0] == '[' {
+			// auxint restriction
+			switch op.aux {
+			case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32":
+			default:
+				log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
+			}
+			x := a[1 : len(a)-1] // remove []
+			fmt.Fprintf(w, "%s.AuxInt = %s\n", v, x)
+		} else if a[0] == '{' {
+			// aux restriction
+			switch op.aux {
+			case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32":
+			default:
+				log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
+			}
+			x := a[1 : len(a)-1] // remove {}
+			fmt.Fprintf(w, "%s.Aux = %s\n", v, x)
+		} else {
+			// regular argument (sexpr or variable)
+			x := genResult0(w, arch, a, alloc, false, move, loc)
+			fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
+			argnum++
+		}
+	}
+	if op.argLength != -1 && int(op.argLength) != argnum {
+		log.Fatalf("%s: op %s should have %d args, has %d", loc, op.name, op.argLength, argnum)
+	}
+
+	return v
+}
+
+func split(s string) []string {
+	var r []string
+
+outer:
+	for s != "" {
+		d := 0               // depth of ({[<
+		var open, close byte // opening and closing markers ({[< or )}]>
+		nonsp := false       // found a non-space char so far
+		for i := 0; i < len(s); i++ {
+			switch {
+			case d == 0 && s[i] == '(':
+				open, close = '(', ')'
+				d++
+			case d == 0 && s[i] == '<':
+				open, close = '<', '>'
+				d++
+			case d == 0 && s[i] == '[':
+				open, close = '[', ']'
+				d++
+			case d == 0 && s[i] == '{':
+				open, close = '{', '}'
+				d++
+			case d == 0 && (s[i] == ' ' || s[i] == '\t'):
+				if nonsp {
+					r = append(r, strings.TrimSpace(s[:i]))
+					s = s[i:]
+					continue outer
+				}
+			case d > 0 && s[i] == open:
+				d++
+			case d > 0 && s[i] == close:
+				d--
+			default:
+				nonsp = true
+			}
+		}
+		if d != 0 {
+			panic("imbalanced expression: " + s)
+		}
+		if nonsp {
+			r = append(r, strings.TrimSpace(s))
+		}
+		break
+	}
+	return r
+}
+
+// isBlock returns true if this op is a block opcode.
+func isBlock(name string, arch arch) bool {
+	for _, b := range genericBlocks {
+		if b.name == name {
+			return true
+		}
+	}
+	for _, b := range arch.blocks {
+		if b.name == name {
+			return true
+		}
+	}
+	return false
+}
+
+// opName converts from an op name specified in a rule file to an Op enum.
+// if the name matches a generic op, returns "Op" plus the specified name.
+// Otherwise, returns "Op" plus arch name plus op name.
+func opName(name string, arch arch) string {
+	for _, op := range genericOps {
+		if op.name == name {
+			return "Op" + name
+		}
+	}
+	return "Op" + arch.name + name
+}
+
+func blockName(name string, arch arch) string {
+	for _, b := range genericBlocks {
+		if b.name == name {
+			return "Block" + name
+		}
+	}
+	return "Block" + arch.name + name
+}
+
+// typeName returns the string to use to generate a type.
+func typeName(typ string) string {
+	switch typ {
+	case "Flags", "Mem", "Void", "Int128":
+		return "Type" + typ
+	default:
+		return "config.fe.Type" + typ + "()"
+	}
+}
+
+// unbalanced returns true if there aren't the same number of ( and ) in the string.
+func unbalanced(s string) bool {
+	var left, right int
+	for _, c := range s {
+		if c == '(' {
+			left++
+		}
+		if c == ')' {
+			right++
+		}
+	}
+	return left != right
+}
+
+// isVariable reports whether s is a single Go alphanumeric identifier.
+func isVariable(s string) bool {
+	b, err := regexp.MatchString("^[A-Za-z_][A-Za-z_0-9]*$", s)
+	if err != nil {
+		panic("bad variable regexp")
+	}
+	return b
+}
diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go
new file mode 100644
index 0000000..7432a07
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/html.go
@@ -0,0 +1,471 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"bytes"
+	"fmt"
+	"html"
+	"io"
+	"os"
+)
+
+type HTMLWriter struct {
+	Logger
+	*os.File
+}
+
+func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter {
+	out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+	if err != nil {
+		logger.Fatalf(0, "%v", err)
+	}
+	html := HTMLWriter{File: out, Logger: logger}
+	html.start(funcname)
+	return &html
+}
+
+func (w *HTMLWriter) start(name string) {
+	if w == nil {
+		return
+	}
+	w.WriteString("<html>")
+	w.WriteString(`<head>
+<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+<style>
+
+#helplink {
+    margin-bottom: 15px;
+    display: block;
+    margin-top: -15px;
+}
+
+#help {
+    display: none;
+}
+
+.stats {
+	font-size: 60%;
+}
+
+table {
+    border: 1px solid black;
+    table-layout: fixed;
+    width: 300px;
+}
+
+th, td {
+    border: 1px solid black;
+    overflow: hidden;
+    width: 400px;
+    vertical-align: top;
+    padding: 5px;
+}
+
+li {
+    list-style-type: none;
+}
+
+li.ssa-long-value {
+    text-indent: -2em;  /* indent wrapped lines */
+}
+
+li.ssa-value-list {
+    display: inline;
+}
+
+li.ssa-start-block {
+    padding: 0;
+    margin: 0;
+}
+
+li.ssa-end-block {
+    padding: 0;
+    margin: 0;
+}
+
+ul.ssa-print-func {
+    padding-left: 0;
+}
+
+dl.ssa-gen {
+    padding-left: 0;
+}
+
+dt.ssa-prog-src {
+    padding: 0;
+    margin: 0;
+    float: left;
+    width: 4em;
+}
+
+dd.ssa-prog {
+    padding: 0;
+    margin-right: 0;
+    margin-left: 4em;
+}
+
+.dead-value {
+    color: gray;
+}
+
+.dead-block {
+    opacity: 0.5;
+}
+
+.depcycle {
+    font-style: italic;
+}
+
+.highlight-yellow         { background-color: yellow; }
+.highlight-aquamarine     { background-color: aquamarine; }
+.highlight-coral          { background-color: coral; }
+.highlight-lightpink      { background-color: lightpink; }
+.highlight-lightsteelblue { background-color: lightsteelblue; }
+.highlight-palegreen      { background-color: palegreen; }
+.highlight-powderblue     { background-color: powderblue; }
+.highlight-lightgray      { background-color: lightgray; }
+
+.outline-blue           { outline: blue solid 2px; }
+.outline-red            { outline: red solid 2px; }
+.outline-blueviolet     { outline: blueviolet solid 2px; }
+.outline-darkolivegreen { outline: darkolivegreen solid 2px; }
+.outline-fuchsia        { outline: fuchsia solid 2px; }
+.outline-sienna         { outline: sienna solid 2px; }
+.outline-gold           { outline: gold solid 2px; }
+
+</style>
+
+<script type="text/javascript">
+// ordered list of all available highlight colors
+var highlights = [
+    "highlight-yellow",
+    "highlight-aquamarine",
+    "highlight-coral",
+    "highlight-lightpink",
+    "highlight-lightsteelblue",
+    "highlight-palegreen",
+    "highlight-lightgray"
+];
+
+// state: which value is highlighted this color?
+var highlighted = {};
+for (var i = 0; i < highlights.length; i++) {
+    highlighted[highlights[i]] = "";
+}
+
+// ordered list of all available outline colors
+var outlines = [
+    "outline-blue",
+    "outline-red",
+    "outline-blueviolet",
+    "outline-darkolivegreen",
+    "outline-fuchsia",
+    "outline-sienna",
+    "outline-gold"
+];
+
+// state: which value is outlined this color?
+var outlined = {};
+for (var i = 0; i < outlines.length; i++) {
+    outlined[outlines[i]] = "";
+}
+
+window.onload = function() {
+    var ssaElemClicked = function(elem, event, selections, selected) {
+        event.stopPropagation()
+
+        // TODO: pushState with updated state and read it on page load,
+        // so that state can survive across reloads
+
+        // find all values with the same name
+        var c = elem.classList.item(0);
+        var x = document.getElementsByClassName(c);
+
+        // if selected, remove selections from all of them
+        // otherwise, attempt to add
+
+        var remove = "";
+        for (var i = 0; i < selections.length; i++) {
+            var color = selections[i];
+            if (selected[color] == c) {
+                remove = color;
+                break;
+            }
+        }
+
+        if (remove != "") {
+            for (var i = 0; i < x.length; i++) {
+                x[i].classList.remove(remove);
+            }
+            selected[remove] = "";
+            return;
+        }
+
+        // we're adding a selection
+        // find first available color
+        var avail = "";
+        for (var i = 0; i < selections.length; i++) {
+            var color = selections[i];
+            if (selected[color] == "") {
+                avail = color;
+                break;
+            }
+        }
+        if (avail == "") {
+            alert("out of selection colors; go add more");
+            return;
+        }
+
+        // set that as the selection
+        for (var i = 0; i < x.length; i++) {
+            x[i].classList.add(avail);
+        }
+        selected[avail] = c;
+    };
+
+    var ssaValueClicked = function(event) {
+        ssaElemClicked(this, event, highlights, highlighted);
+    }
+
+    var ssaBlockClicked = function(event) {
+        ssaElemClicked(this, event, outlines, outlined);
+    }
+
+    var ssavalues = document.getElementsByClassName("ssa-value");
+    for (var i = 0; i < ssavalues.length; i++) {
+        ssavalues[i].addEventListener('click', ssaValueClicked);
+    }
+
+    var ssalongvalues = document.getElementsByClassName("ssa-long-value");
+    for (var i = 0; i < ssalongvalues.length; i++) {
+        // don't attach listeners to li nodes, just the spans they contain
+        if (ssalongvalues[i].nodeName == "SPAN") {
+            ssalongvalues[i].addEventListener('click', ssaValueClicked);
+        }
+    }
+
+    var ssablocks = document.getElementsByClassName("ssa-block");
+    for (var i = 0; i < ssablocks.length; i++) {
+        ssablocks[i].addEventListener('click', ssaBlockClicked);
+    }
+};
+
+function toggle_visibility(id) {
+   var e = document.getElementById(id);
+   if(e.style.display == 'block')
+      e.style.display = 'none';
+   else
+      e.style.display = 'block';
+}
+</script>
+
+</head>`)
+	// TODO: Add javascript click handlers for blocks
+	// to outline that block across all phases
+	w.WriteString("<body>")
+	w.WriteString("<h1>")
+	w.WriteString(html.EscapeString(name))
+	w.WriteString("</h1>")
+	w.WriteString(`
+<a href="#" onclick="toggle_visibility('help');" id="helplink">help</a>
+<div id="help">
+
+<p>
+Click on a value or block to toggle highlighting of that value/block and its uses.
+Values and blocks are highlighted by ID, which may vary across passes.
+(TODO: Fix this.)
+</p>
+
+<p>
+Faded out values and blocks are dead code that has not been eliminated.
+</p>
+
+<p>
+Values printed in italics have a dependency cycle.
+</p>
+
+</div>
+`)
+	w.WriteString("<table>")
+	w.WriteString("<tr>")
+}
+
+func (w *HTMLWriter) Close() {
+	if w == nil {
+		return
+	}
+	w.WriteString("</tr>")
+	w.WriteString("</table>")
+	w.WriteString("</body>")
+	w.WriteString("</html>")
+	w.File.Close()
+}
+
+// WriteFunc writes f in a column headed by title.
+func (w *HTMLWriter) WriteFunc(title string, f *Func) {
+	if w == nil {
+		return // avoid generating HTML just to discard it
+	}
+	w.WriteColumn(title, f.HTML())
+	// TODO: Add visual representation of f's CFG.
+}
+
+// WriteColumn writes raw HTML in a column headed by title.
+// It is intended for pre- and post-compilation log output.
+func (w *HTMLWriter) WriteColumn(title string, html string) {
+	if w == nil {
+		return
+	}
+	w.WriteString("<td>")
+	w.WriteString("<h2>" + title + "</h2>")
+	w.WriteString(html)
+	w.WriteString("</td>")
+}
+
+func (w *HTMLWriter) Printf(msg string, v ...interface{}) {
+	if _, err := fmt.Fprintf(w.File, msg, v...); err != nil {
+		w.Fatalf(0, "%v", err)
+	}
+}
+
+func (w *HTMLWriter) WriteString(s string) {
+	if _, err := w.File.WriteString(s); err != nil {
+		w.Fatalf(0, "%v", err)
+	}
+}
+
+func (v *Value) HTML() string {
+	// TODO: Using the value ID as the class ignores the fact
+	// that value IDs get recycled and that some values
+	// are transmuted into other values.
+	return fmt.Sprintf("<span class=\"%[1]s ssa-value\">%[1]s</span>", v.String())
+}
+
+func (v *Value) LongHTML() string {
+	// TODO: Any intra-value formatting?
+	// I'm wary of adding too much visual noise,
+	// but a little bit might be valuable.
+	// We already have visual noise in the form of punctuation
+	// maybe we could replace some of that with formatting.
+	s := fmt.Sprintf("<span class=\"%s ssa-long-value\">", v.String())
+	s += fmt.Sprintf("%s = %s", v.HTML(), v.Op.String())
+	s += " <" + html.EscapeString(v.Type.String()) + ">"
+	s += html.EscapeString(v.auxString())
+	for _, a := range v.Args {
+		s += fmt.Sprintf(" %s", a.HTML())
+	}
+	r := v.Block.Func.RegAlloc
+	if int(v.ID) < len(r) && r[v.ID] != nil {
+		s += " : " + r[v.ID].Name()
+	}
+	s += "</span>"
+	return s
+}
+
+func (b *Block) HTML() string {
+	// TODO: Using the value ID as the class ignores the fact
+	// that value IDs get recycled and that some values
+	// are transmuted into other values.
+	return fmt.Sprintf("<span class=\"%[1]s ssa-block\">%[1]s</span>", html.EscapeString(b.String()))
+}
+
+func (b *Block) LongHTML() string {
+	// TODO: improve this for HTML?
+	s := fmt.Sprintf("<span class=\"%s ssa-block\">%s</span>", html.EscapeString(b.String()), html.EscapeString(b.Kind.String()))
+	if b.Aux != nil {
+		s += html.EscapeString(fmt.Sprintf(" {%v}", b.Aux))
+	}
+	if b.Control != nil {
+		s += fmt.Sprintf(" %s", b.Control.HTML())
+	}
+	if len(b.Succs) > 0 {
+		s += " →" // right arrow
+		for _, e := range b.Succs {
+			c := e.b
+			s += " " + c.HTML()
+		}
+	}
+	switch b.Likely {
+	case BranchUnlikely:
+		s += " (unlikely)"
+	case BranchLikely:
+		s += " (likely)"
+	}
+	return s
+}
+
+func (f *Func) HTML() string {
+	var buf bytes.Buffer
+	fmt.Fprint(&buf, "<code>")
+	p := htmlFuncPrinter{w: &buf}
+	fprintFunc(p, f)
+
+	// fprintFunc(&buf, f) // TODO: HTML, not text, <br /> for line breaks, etc.
+	fmt.Fprint(&buf, "</code>")
+	return buf.String()
+}
+
+type htmlFuncPrinter struct {
+	w io.Writer
+}
+
+func (p htmlFuncPrinter) header(f *Func) {}
+
+func (p htmlFuncPrinter) startBlock(b *Block, reachable bool) {
+	// TODO: Make blocks collapsable?
+	var dead string
+	if !reachable {
+		dead = "dead-block"
+	}
+	fmt.Fprintf(p.w, "<ul class=\"%s ssa-print-func %s\">", b, dead)
+	fmt.Fprintf(p.w, "<li class=\"ssa-start-block\">%s:", b.HTML())
+	if len(b.Preds) > 0 {
+		io.WriteString(p.w, " ←") // left arrow
+		for _, e := range b.Preds {
+			pred := e.b
+			fmt.Fprintf(p.w, " %s", pred.HTML())
+		}
+	}
+	io.WriteString(p.w, "</li>")
+	if len(b.Values) > 0 { // start list of values
+		io.WriteString(p.w, "<li class=\"ssa-value-list\">")
+		io.WriteString(p.w, "<ul>")
+	}
+}
+
+func (p htmlFuncPrinter) endBlock(b *Block) {
+	if len(b.Values) > 0 { // end list of values
+		io.WriteString(p.w, "</ul>")
+		io.WriteString(p.w, "</li>")
+	}
+	io.WriteString(p.w, "<li class=\"ssa-end-block\">")
+	fmt.Fprint(p.w, b.LongHTML())
+	io.WriteString(p.w, "</li>")
+	io.WriteString(p.w, "</ul>")
+	// io.WriteString(p.w, "</span>")
+}
+
+func (p htmlFuncPrinter) value(v *Value, live bool) {
+	var dead string
+	if !live {
+		dead = "dead-value"
+	}
+	fmt.Fprintf(p.w, "<li class=\"ssa-long-value %s\">", dead)
+	fmt.Fprint(p.w, v.LongHTML())
+	io.WriteString(p.w, "</li>")
+}
+
+func (p htmlFuncPrinter) startDepCycle() {
+	fmt.Fprintln(p.w, "<span class=\"depcycle\">")
+}
+
+func (p htmlFuncPrinter) endDepCycle() {
+	fmt.Fprintln(p.w, "</span>")
+}
+
+func (p htmlFuncPrinter) named(n LocalSlot, vals []*Value) {
+	// TODO
+}
diff --git a/src/cmd/compile/internal/ssa/id.go b/src/cmd/compile/internal/ssa/id.go
new file mode 100644
index 0000000..725279e
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/id.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 ssa
+
+type ID int32
+
+// idAlloc provides an allocator for unique integers.
+type idAlloc struct {
+	last ID
+}
+
+// get allocates an ID and returns it. IDs are always > 0.
+func (a *idAlloc) get() ID {
+	x := a.last
+	x++
+	if x == 1<<31-1 {
+		panic("too many ids for this function")
+	}
+	a.last = x
+	return x
+}
+
+// num returns the maximum ID ever returned + 1.
+func (a *idAlloc) num() int {
+	return int(a.last + 1)
+}
diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go
new file mode 100644
index 0000000..5545444
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/layout.go
@@ -0,0 +1,103 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// layout orders basic blocks in f with the goal of minimizing control flow instructions.
+// After this phase returns, the order of f.Blocks matters and is the order
+// in which those blocks will appear in the assembly output.
+func layout(f *Func) {
+	order := make([]*Block, 0, f.NumBlocks())
+	scheduled := make([]bool, f.NumBlocks())
+	idToBlock := make([]*Block, f.NumBlocks())
+	indegree := make([]int, f.NumBlocks())
+	posdegree := f.newSparseSet(f.NumBlocks()) // blocks with positive remaining degree
+	defer f.retSparseSet(posdegree)
+	zerodegree := f.newSparseSet(f.NumBlocks()) // blocks with zero remaining degree
+	defer f.retSparseSet(zerodegree)
+
+	// Initialize indegree of each block
+	for _, b := range f.Blocks {
+		idToBlock[b.ID] = b
+		indegree[b.ID] = len(b.Preds)
+		if len(b.Preds) == 0 {
+			zerodegree.add(b.ID)
+		} else {
+			posdegree.add(b.ID)
+		}
+	}
+
+	bid := f.Entry.ID
+blockloop:
+	for {
+		// add block to schedule
+		b := idToBlock[bid]
+		order = append(order, b)
+		scheduled[bid] = true
+		if len(order) == len(f.Blocks) {
+			break
+		}
+
+		for _, e := range b.Succs {
+			c := e.b
+			indegree[c.ID]--
+			if indegree[c.ID] == 0 {
+				posdegree.remove(c.ID)
+				zerodegree.add(c.ID)
+			}
+		}
+
+		// Pick the next block to schedule
+		// Pick among the successor blocks that have not been scheduled yet.
+
+		// Use likely direction if we have it.
+		var likely *Block
+		switch b.Likely {
+		case BranchLikely:
+			likely = b.Succs[0].b
+		case BranchUnlikely:
+			likely = b.Succs[1].b
+		}
+		if likely != nil && !scheduled[likely.ID] {
+			bid = likely.ID
+			continue
+		}
+
+		// Use degree for now.
+		bid = 0
+		mindegree := f.NumBlocks()
+		for _, e := range order[len(order)-1].Succs {
+			c := e.b
+			if scheduled[c.ID] {
+				continue
+			}
+			if indegree[c.ID] < mindegree {
+				mindegree = indegree[c.ID]
+				bid = c.ID
+			}
+		}
+		if bid != 0 {
+			continue
+		}
+		// TODO: improve this part
+		// No successor of the previously scheduled block works.
+		// Pick a zero-degree block if we can.
+		for zerodegree.size() > 0 {
+			cid := zerodegree.pop()
+			if !scheduled[cid] {
+				bid = cid
+				continue blockloop
+			}
+		}
+		// Still nothing, pick any block.
+		for {
+			cid := posdegree.pop()
+			if !scheduled[cid] {
+				bid = cid
+				continue blockloop
+			}
+		}
+	}
+	f.Blocks = order
+}
diff --git a/src/cmd/compile/internal/ssa/likelyadjust.go b/src/cmd/compile/internal/ssa/likelyadjust.go
new file mode 100644
index 0000000..cb2d82f
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/likelyadjust.go
@@ -0,0 +1,449 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"fmt"
+)
+
+type loop struct {
+	header *Block // The header node of this (reducible) loop
+	outer  *loop  // loop containing this loop
+
+	// By default, children exits, and depth are not initialized.
+	children []*loop  // loops nested directly within this loop. Initialized by assembleChildren().
+	exits    []*Block // exits records blocks reached by exits from this loop. Initialized by findExits().
+
+	// Loops aren't that common, so rather than force regalloc to keep
+	// a map or slice for its data, just put it here.
+	spills  []*Value
+	scratch int32
+
+	// Next three fields used by regalloc and/or
+	// aid in computation of inner-ness and list of blocks.
+	nBlocks int32 // Number of blocks in this loop but not within inner loops
+	depth   int16 // Nesting depth of the loop; 1 is outermost. Initialized by calculateDepths().
+	isInner bool  // True if never discovered to contain a loop
+
+	// register allocation uses this.
+	containsCall bool // if any block in this loop or any loop it contains is a BlockCall or BlockDefer
+}
+
+// outerinner records that outer contains inner
+func (sdom SparseTree) outerinner(outer, inner *loop) {
+	oldouter := inner.outer
+	if oldouter == nil || sdom.isAncestorEq(oldouter.header, outer.header) {
+		inner.outer = outer
+		outer.isInner = false
+		if inner.containsCall {
+			outer.setContainsCall()
+		}
+	}
+}
+
+func (l *loop) setContainsCall() {
+	for ; l != nil && !l.containsCall; l = l.outer {
+		l.containsCall = true
+	}
+
+}
+func (l *loop) checkContainsCall(bb *Block) {
+	if bb.Kind == BlockCall || bb.Kind == BlockDefer {
+		l.setContainsCall()
+	}
+}
+
+type loopnest struct {
+	f     *Func
+	b2l   []*loop
+	po    []*Block
+	sdom  SparseTree
+	loops []*loop
+
+	// Record which of the lazily initialized fields have actually been initialized.
+	initializedChildren, initializedDepth, initializedExits bool
+}
+
+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
+}
+
+const (
+	blDEFAULT = 0
+	blMin     = blDEFAULT
+	blCALL    = 1
+	blRET     = 2
+	blEXIT    = 3
+)
+
+var bllikelies [4]string = [4]string{"default", "call", "ret", "exit"}
+
+func describePredictionAgrees(b *Block, prediction BranchPrediction) string {
+	s := ""
+	if prediction == b.Likely {
+		s = " (agrees with previous)"
+	} else if b.Likely != BranchUnknown {
+		s = " (disagrees with previous, ignored)"
+	}
+	return s
+}
+
+func describeBranchPrediction(f *Func, b *Block, likely, not int8, prediction BranchPrediction) {
+	f.Config.Warnl(b.Line, "Branch prediction rule %s < %s%s",
+		bllikelies[likely-blMin], bllikelies[not-blMin], describePredictionAgrees(b, prediction))
+}
+
+func likelyadjust(f *Func) {
+	// The values assigned to certain and local only matter
+	// in their rank order.  0 is default, more positive
+	// is less likely. It's possible to assign a negative
+	// unlikeliness (though not currently the case).
+	certain := make([]int8, f.NumBlocks()) // In the long run, all outcomes are at least this bad. Mainly for Exit
+	local := make([]int8, f.NumBlocks())   // for our immediate predecessors.
+
+	nest := loopnestfor(f)
+	po := nest.po
+	b2l := nest.b2l
+
+	for _, b := range po {
+		switch b.Kind {
+		case BlockExit:
+			// Very unlikely.
+			local[b.ID] = blEXIT
+			certain[b.ID] = blEXIT
+
+			// Ret, it depends.
+		case BlockRet, BlockRetJmp:
+			local[b.ID] = blRET
+			certain[b.ID] = blRET
+
+			// Calls. TODO not all calls are equal, names give useful clues.
+			// Any name-based heuristics are only relative to other calls,
+			// and less influential than inferences from loop structure.
+		case BlockCall, BlockDefer:
+			local[b.ID] = blCALL
+			certain[b.ID] = max8(blCALL, certain[b.Succs[0].b.ID])
+
+		default:
+			if len(b.Succs) == 1 {
+				certain[b.ID] = certain[b.Succs[0].b.ID]
+			} else if len(b.Succs) == 2 {
+				// If successor is an unvisited backedge, it's in loop and we don't care.
+				// Its default unlikely is also zero which is consistent with favoring loop edges.
+				// Notice that this can act like a "reset" on unlikeliness at loops; the
+				// default "everything returns" unlikeliness is erased by min with the
+				// backedge likeliness; however a loop with calls on every path will be
+				// tagged with call cost. Net effect is that loop entry is favored.
+				b0 := b.Succs[0].b.ID
+				b1 := b.Succs[1].b.ID
+				certain[b.ID] = min8(certain[b0], certain[b1])
+
+				l := b2l[b.ID]
+				l0 := b2l[b0]
+				l1 := b2l[b1]
+
+				prediction := b.Likely
+				// Weak loop heuristic -- both source and at least one dest are in loops,
+				// and there is a difference in the destinations.
+				// TODO what is best arrangement for nested loops?
+				if l != nil && l0 != l1 {
+					noprediction := false
+					switch {
+					// prefer not to exit loops
+					case l1 == nil:
+						prediction = BranchLikely
+					case l0 == nil:
+						prediction = BranchUnlikely
+
+						// prefer to stay in loop, not exit to outer.
+					case l == l0:
+						prediction = BranchLikely
+					case l == l1:
+						prediction = BranchUnlikely
+					default:
+						noprediction = true
+					}
+					if f.pass.debug > 0 && !noprediction {
+						f.Config.Warnl(b.Line, "Branch prediction rule stay in loop%s",
+							describePredictionAgrees(b, prediction))
+					}
+
+				} else {
+					// Lacking loop structure, fall back on heuristics.
+					if certain[b1] > certain[b0] {
+						prediction = BranchLikely
+						if f.pass.debug > 0 {
+							describeBranchPrediction(f, b, certain[b0], certain[b1], prediction)
+						}
+					} else if certain[b0] > certain[b1] {
+						prediction = BranchUnlikely
+						if f.pass.debug > 0 {
+							describeBranchPrediction(f, b, certain[b1], certain[b0], prediction)
+						}
+					} else if local[b1] > local[b0] {
+						prediction = BranchLikely
+						if f.pass.debug > 0 {
+							describeBranchPrediction(f, b, local[b0], local[b1], prediction)
+						}
+					} else if local[b0] > local[b1] {
+						prediction = BranchUnlikely
+						if f.pass.debug > 0 {
+							describeBranchPrediction(f, b, local[b1], local[b0], prediction)
+						}
+					}
+				}
+				if b.Likely != prediction {
+					if b.Likely == BranchUnknown {
+						b.Likely = prediction
+					}
+				}
+			}
+		}
+		if f.pass.debug > 2 {
+			f.Config.Warnl(b.Line, "BP: Block %s, local=%s, certain=%s", b, bllikelies[local[b.ID]-blMin], bllikelies[certain[b.ID]-blMin])
+		}
+
+	}
+}
+
+func (l *loop) String() string {
+	return fmt.Sprintf("hdr:%s", l.header)
+}
+
+func (l *loop) LongString() string {
+	i := ""
+	o := ""
+	if l.isInner {
+		i = ", INNER"
+	}
+	if l.outer != nil {
+		o = ", o=" + l.outer.header.String()
+	}
+	return fmt.Sprintf("hdr:%s%s%s", l.header, i, o)
+}
+
+// nearestOuterLoop returns the outer loop of loop most nearly
+// containing block b; the header must dominate b.  loop itself
+// is assumed to not be that loop. For acceptable performance,
+// we're relying on loop nests to not be terribly deep.
+func (l *loop) nearestOuterLoop(sdom SparseTree, b *Block) *loop {
+	var o *loop
+	for o = l.outer; o != nil && !sdom.isAncestorEq(o.header, b); o = o.outer {
+	}
+	return o
+}
+
+func loopnestfor(f *Func) *loopnest {
+	po := postorder(f)
+	dom := dominators(f)
+	sdom := newSparseTree(f, dom)
+	b2l := make([]*loop, f.NumBlocks())
+	loops := make([]*loop, 0)
+
+	// Reducible-loop-nest-finding.
+	for _, b := range po {
+		if f.pass.debug > 3 {
+			fmt.Printf("loop finding (0) at %s\n", b)
+		}
+
+		var innermost *loop // innermost header reachable from this block
+
+		// IF any successor s of b is in a loop headed by h
+		// AND h dominates b
+		// THEN b is in the loop headed by h.
+		//
+		// Choose the first/innermost such h.
+		//
+		// IF s itself dominates b, the s is a loop header;
+		// and there may be more than one such s.
+		// Since there's at most 2 successors, the inner/outer ordering
+		// between them can be established with simple comparisons.
+		for _, e := range b.Succs {
+			bb := e.b
+			l := b2l[bb.ID]
+
+			if sdom.isAncestorEq(bb, b) { // Found a loop header
+				if l == nil {
+					l = &loop{header: bb, isInner: true}
+					loops = append(loops, l)
+					b2l[bb.ID] = l
+					l.checkContainsCall(bb)
+				}
+			} else { // Perhaps a loop header is inherited.
+				// is there any loop containing our successor whose
+				// header dominates b?
+				if l != nil && !sdom.isAncestorEq(l.header, b) {
+					l = l.nearestOuterLoop(sdom, b)
+				}
+			}
+
+			if l == nil || innermost == l {
+				continue
+			}
+
+			if innermost == nil {
+				innermost = l
+				continue
+			}
+
+			if sdom.isAncestor(innermost.header, l.header) {
+				sdom.outerinner(innermost, l)
+				innermost = l
+			} else if sdom.isAncestor(l.header, innermost.header) {
+				sdom.outerinner(l, innermost)
+			}
+		}
+
+		if innermost != nil {
+			b2l[b.ID] = innermost
+			innermost.checkContainsCall(b)
+			innermost.nBlocks++
+		}
+	}
+
+	ln := &loopnest{f: f, b2l: b2l, po: po, sdom: sdom, loops: loops}
+
+	// Curious about the loopiness? "-d=ssa/likelyadjust/stats"
+	if f.pass.stats > 0 && len(loops) > 0 {
+		ln.assembleChildren()
+		ln.calculateDepths()
+		ln.findExits()
+
+		// Note stats for non-innermost loops are slightly flawed because
+		// they don't account for inner loop exits that span multiple levels.
+
+		for _, l := range loops {
+			x := len(l.exits)
+			cf := 0
+			if !l.containsCall {
+				cf = 1
+			}
+			inner := 0
+			if l.isInner {
+				inner++
+			}
+
+			f.LogStat("loopstats:",
+				l.depth, "depth", x, "exits",
+				inner, "is_inner", cf, "is_callfree", l.nBlocks, "n_blocks")
+		}
+	}
+
+	if f.pass.debug > 1 && len(loops) > 0 {
+		fmt.Printf("Loops in %s:\n", f.Name)
+		for _, l := range loops {
+			fmt.Printf("%s, b=", l.LongString())
+			for _, b := range f.Blocks {
+				if b2l[b.ID] == l {
+					fmt.Printf(" %s", b)
+				}
+			}
+			fmt.Print("\n")
+		}
+		fmt.Printf("Nonloop blocks in %s:", f.Name)
+		for _, b := range f.Blocks {
+			if b2l[b.ID] == nil {
+				fmt.Printf(" %s", b)
+			}
+		}
+		fmt.Print("\n")
+	}
+	return ln
+}
+
+// assembleChildren initializes the children field of each
+// loop in the nest.  Loop A is a child of loop B if A is
+// directly nested within B (based on the reducible-loops
+// detection above)
+func (ln *loopnest) assembleChildren() {
+	if ln.initializedChildren {
+		return
+	}
+	for _, l := range ln.loops {
+		if l.outer != nil {
+			l.outer.children = append(l.outer.children, l)
+		}
+	}
+	ln.initializedChildren = true
+}
+
+// calculateDepths uses the children field of loops
+// to determine the nesting depth (outer=1) of each
+// loop.  This is helpful for finding exit edges.
+func (ln *loopnest) calculateDepths() {
+	if ln.initializedDepth {
+		return
+	}
+	ln.assembleChildren()
+	for _, l := range ln.loops {
+		if l.outer == nil {
+			l.setDepth(1)
+		}
+	}
+	ln.initializedDepth = true
+}
+
+// findExits uses loop depth information to find the
+// exits from a loop.
+func (ln *loopnest) findExits() {
+	if ln.initializedExits {
+		return
+	}
+	ln.calculateDepths()
+	b2l := ln.b2l
+	for _, b := range ln.po {
+		l := b2l[b.ID]
+		if l != nil && len(b.Succs) == 2 {
+			sl := b2l[b.Succs[0].b.ID]
+			if recordIfExit(l, sl, b.Succs[0].b) {
+				continue
+			}
+			sl = b2l[b.Succs[1].b.ID]
+			if recordIfExit(l, sl, b.Succs[1].b) {
+				continue
+			}
+		}
+	}
+	ln.initializedExits = true
+}
+
+// recordIfExit checks sl (the loop containing b) to see if it
+// is outside of loop l, and if so, records b as an exit block
+// from l and returns true.
+func recordIfExit(l, sl *loop, b *Block) bool {
+	if sl != l {
+		if sl == nil || sl.depth <= l.depth {
+			l.exits = append(l.exits, b)
+			return true
+		}
+		// sl is not nil, and is deeper than l
+		// it's possible for this to be a goto into an irreducible loop made from gotos.
+		for sl.depth > l.depth {
+			sl = sl.outer
+		}
+		if sl != l {
+			l.exits = append(l.exits, b)
+			return true
+		}
+	}
+	return false
+}
+
+func (l *loop) setDepth(d int16) {
+	l.depth = d
+	for _, c := range l.children {
+		c.setDepth(d + 1)
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go
new file mode 100644
index 0000000..85f5255
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/location.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 ssa
+
+import "fmt"
+
+// A place that an ssa variable can reside.
+type Location interface {
+	Name() string // name to use in assembly templates: %rax, 16(%rsp), ...
+}
+
+// A Register is a machine register, like %rax.
+// They are numbered densely from 0 (for each architecture).
+type Register struct {
+	Num  int32
+	name string
+}
+
+func (r *Register) Name() string {
+	return r.name
+}
+
+// A LocalSlot is a location in the stack frame.
+// It is (possibly a subpiece of) a PPARAM, PPARAMOUT, or PAUTO ONAME node.
+type LocalSlot struct {
+	N    GCNode // an ONAME *gc.Node representing a variable on the stack
+	Type Type   // type of slot
+	Off  int64  // offset of slot in N
+}
+
+func (s LocalSlot) Name() string {
+	if s.Off == 0 {
+		return fmt.Sprintf("%s[%s]", s.N, s.Type)
+	}
+	return fmt.Sprintf("%s+%d[%s]", s.N, s.Off, s.Type)
+}
diff --git a/src/cmd/compile/internal/ssa/loopbce.go b/src/cmd/compile/internal/ssa/loopbce.go
new file mode 100644
index 0000000..e94781b
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/loopbce.go
@@ -0,0 +1,299 @@
+package ssa
+
+type indVar struct {
+	ind   *Value // induction variable
+	inc   *Value // increment, a constant
+	nxt   *Value // ind+inc variable
+	min   *Value // minimum value. inclusive,
+	max   *Value // maximum value. exclusive.
+	entry *Block // entry block in the loop.
+	// Invariants: for all blocks dominated by entry:
+	//	min <= ind < max
+	//	min <= nxt <= max
+}
+
+// findIndVar finds induction variables in a function.
+//
+// Look for variables and blocks that satisfy the following
+//
+// loop:
+//   ind = (Phi min nxt),
+//   if ind < max
+//     then goto enter_loop
+//     else goto exit_loop
+//
+//   enter_loop:
+//	do something
+//      nxt = inc + ind
+//	goto loop
+//
+// exit_loop:
+//
+//
+// TODO: handle 32 bit operations
+func findIndVar(f *Func) []indVar {
+	var iv []indVar
+
+nextb:
+	for _, b := range f.Blocks {
+		if b.Kind != BlockIf || len(b.Preds) != 2 {
+			continue
+		}
+
+		var ind, max *Value // induction, and maximum
+		entry := -1         // which successor of b enters the loop
+
+		// Check thet the control if it either ind < max or max > ind.
+		// TODO: Handle Leq64, Geq64.
+		switch b.Control.Op {
+		case OpLess64:
+			entry = 0
+			ind, max = b.Control.Args[0], b.Control.Args[1]
+		case OpGreater64:
+			entry = 0
+			ind, max = b.Control.Args[1], b.Control.Args[0]
+		default:
+			continue nextb
+		}
+
+		// Check that the induction variable is a phi that depends on itself.
+		if ind.Op != OpPhi {
+			continue
+		}
+
+		// Extract min and nxt knowing that nxt is an addition (e.g. Add64).
+		var min, nxt *Value // minimum, and next value
+		if n := ind.Args[0]; n.Op == OpAdd64 && (n.Args[0] == ind || n.Args[1] == ind) {
+			min, nxt = ind.Args[1], n
+		} else if n := ind.Args[1]; n.Op == OpAdd64 && (n.Args[0] == ind || n.Args[1] == ind) {
+			min, nxt = ind.Args[0], n
+		} else {
+			// Not a recognized induction variable.
+			continue
+		}
+
+		var inc *Value
+		if nxt.Args[0] == ind { // nxt = ind + inc
+			inc = nxt.Args[1]
+		} else if nxt.Args[1] == ind { // nxt = inc + ind
+			inc = nxt.Args[0]
+		} else {
+			panic("unreachable") // one of the cases must be true from the above.
+		}
+
+		// Expect the increment to be a positive constant.
+		// TODO: handle negative increment.
+		if inc.Op != OpConst64 || inc.AuxInt <= 0 {
+			continue
+		}
+
+		// Up to now we extracted the induction variable (ind),
+		// the increment delta (inc), the temporary sum (nxt),
+		// the mininum value (min) and the maximum value (max).
+		//
+		// We also know that ind has the form (Phi min nxt) where
+		// nxt is (Add inc nxt) which means: 1) inc dominates nxt
+		// and 2) there is a loop starting at inc and containing nxt.
+		//
+		// We need to prove that the induction variable is incremented
+		// only when it's smaller than the maximum value.
+		// Two conditions must happen listed below to accept ind
+		// as an induction variable.
+
+		// First condition: loop entry has a single predecessor, which
+		// is the header block.  This implies that b.Succs[entry] is
+		// reached iff ind < max.
+		if len(b.Succs[entry].b.Preds) != 1 {
+			// b.Succs[1-entry] must exit the loop.
+			continue
+		}
+
+		// Second condition: b.Succs[entry] dominates nxt so that
+		// nxt is computed when inc < max, meaning nxt <= max.
+		if !f.sdom.isAncestorEq(b.Succs[entry].b, nxt.Block) {
+			// inc+ind can only be reached through the branch that enters the loop.
+			continue
+		}
+
+		// If max is c + SliceLen with c <= 0 then we drop c.
+		// Makes sure c + SliceLen doesn't overflow when SliceLen == 0.
+		// TODO: save c as an offset from max.
+		if w, c := dropAdd64(max); (w.Op == OpStringLen || w.Op == OpSliceLen) && 0 >= c && -c >= 0 {
+			max = w
+		}
+
+		// We can only guarantee that the loops runs within limits of induction variable
+		// if the increment is 1 or when the limits are constants.
+		if inc.AuxInt != 1 {
+			ok := false
+			if min.Op == OpConst64 && max.Op == OpConst64 {
+				if max.AuxInt > min.AuxInt && max.AuxInt%inc.AuxInt == min.AuxInt%inc.AuxInt { // handle overflow
+					ok = true
+				}
+			}
+			if !ok {
+				continue
+			}
+		}
+
+		if f.pass.debug > 1 {
+			if min.Op == OpConst64 {
+				b.Func.Config.Warnl(b.Line, "Induction variable with minimum %d and increment %d", min.AuxInt, inc.AuxInt)
+			} else {
+				b.Func.Config.Warnl(b.Line, "Induction variable with non-const minimum and increment %d", inc.AuxInt)
+			}
+		}
+
+		iv = append(iv, indVar{
+			ind:   ind,
+			inc:   inc,
+			nxt:   nxt,
+			min:   min,
+			max:   max,
+			entry: b.Succs[entry].b,
+		})
+		b.Logf("found induction variable %v (inc = %v, min = %v, max = %v)\n", ind, inc, min, max)
+	}
+
+	return iv
+}
+
+// loopbce performs loop based bounds check elimination.
+func loopbce(f *Func) {
+	ivList := findIndVar(f)
+
+	m := make(map[*Value]indVar)
+	for _, iv := range ivList {
+		m[iv.ind] = iv
+	}
+
+	removeBoundsChecks(f, m)
+}
+
+// removesBoundsChecks remove IsInBounds and IsSliceInBounds based on the induction variables.
+func removeBoundsChecks(f *Func, m map[*Value]indVar) {
+	for _, b := range f.Blocks {
+		if b.Kind != BlockIf {
+			continue
+		}
+
+		v := b.Control
+
+		// Simplify:
+		// (IsInBounds ind max) where 0 <= const == min <= ind < max.
+		// (IsSliceInBounds ind max) where 0 <= const == min <= ind < max.
+		// Found in:
+		//	for i := range a {
+		//		use a[i]
+		//		use a[i:]
+		//		use a[:i]
+		//	}
+		if v.Op == OpIsInBounds || v.Op == OpIsSliceInBounds {
+			ind, add := dropAdd64(v.Args[0])
+			if ind.Op != OpPhi {
+				goto skip1
+			}
+			if v.Op == OpIsInBounds && add != 0 {
+				goto skip1
+			}
+			if v.Op == OpIsSliceInBounds && (0 > add || add > 1) {
+				goto skip1
+			}
+
+			if iv, has := m[ind]; has && f.sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
+				if v.Args[1] == iv.max {
+					if f.pass.debug > 0 {
+						f.Config.Warnl(b.Line, "Found redundant %s", v.Op)
+					}
+					goto simplify
+				}
+			}
+		}
+	skip1:
+
+		// Simplify:
+		// (IsSliceInBounds ind (SliceCap a)) where 0 <= min <= ind < max == (SliceLen a)
+		// Found in:
+		//	for i := range a {
+		//		use a[:i]
+		//		use a[:i+1]
+		//	}
+		if v.Op == OpIsSliceInBounds {
+			ind, add := dropAdd64(v.Args[0])
+			if ind.Op != OpPhi {
+				goto skip2
+			}
+			if 0 > add || add > 1 {
+				goto skip2
+			}
+
+			if iv, has := m[ind]; has && f.sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
+				if v.Args[1].Op == OpSliceCap && iv.max.Op == OpSliceLen && v.Args[1].Args[0] == iv.max.Args[0] {
+					if f.pass.debug > 0 {
+						f.Config.Warnl(b.Line, "Found redundant %s (len promoted to cap)", v.Op)
+					}
+					goto simplify
+				}
+			}
+		}
+	skip2:
+
+		// Simplify
+		// (IsInBounds (Add64 ind) (Const64 [c])) where 0 <= min <= ind < max <= (Const64 [c])
+		// (IsSliceInBounds ind (Const64 [c])) where 0 <= min <= ind < max <= (Const64 [c])
+		if v.Op == OpIsInBounds || v.Op == OpIsSliceInBounds {
+			ind, add := dropAdd64(v.Args[0])
+			if ind.Op != OpPhi {
+				goto skip3
+			}
+
+			// ind + add >= 0 <-> min + add >= 0 <-> min >= -add
+			if iv, has := m[ind]; has && f.sdom.isAncestorEq(iv.entry, b) && isGreaterOrEqualThan(iv.min, -add) {
+				if !v.Args[1].isGenericIntConst() || !iv.max.isGenericIntConst() {
+					goto skip3
+				}
+
+				limit := v.Args[1].AuxInt
+				if v.Op == OpIsSliceInBounds {
+					// If limit++ overflows signed integer then 0 <= max && max <= limit will be false.
+					limit++
+				}
+
+				if max := iv.max.AuxInt + add; 0 <= max && max <= limit { // handle overflow
+					if f.pass.debug > 0 {
+						f.Config.Warnl(b.Line, "Found redundant (%s ind %d), ind < %d", v.Op, v.Args[1].AuxInt, iv.max.AuxInt+add)
+					}
+					goto simplify
+				}
+			}
+		}
+	skip3:
+
+		continue
+
+	simplify:
+		f.Logf("removing bounds check %v at %v in %s\n", b.Control, b, f.Name)
+		b.Kind = BlockFirst
+		b.SetControl(nil)
+	}
+}
+
+func dropAdd64(v *Value) (*Value, int64) {
+	if v.Op == OpAdd64 && v.Args[0].Op == OpConst64 {
+		return v.Args[1], v.Args[0].AuxInt
+	}
+	if v.Op == OpAdd64 && v.Args[1].Op == OpConst64 {
+		return v.Args[0], v.Args[1].AuxInt
+	}
+	return v, 0
+}
+
+func isGreaterOrEqualThan(v *Value, c int64) bool {
+	if c == 0 {
+		return isNonNegative(v)
+	}
+	if v.isGenericIntConst() && v.AuxInt >= c {
+		return true
+	}
+	return false
+}
diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go
new file mode 100644
index 0000000..e271ed4
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/lower.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 ssa
+
+// convert to machine-dependent ops
+func lower(f *Func) {
+	// repeat rewrites until we find no more rewrites
+	applyRewrite(f, f.Config.lowerBlock, f.Config.lowerValue)
+}
+
+// checkLower checks for unlowered opcodes and fails if we find one.
+func checkLower(f *Func) {
+	// Needs to be a separate phase because it must run after both
+	// lowering and a subsequent dead code elimination (because lowering
+	// rules may leave dead generic ops behind).
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if !opcodeTable[v.Op].generic {
+				continue // lowered
+			}
+			switch v.Op {
+			case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive:
+				continue // ok not to lower
+			}
+			s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString()
+			for _, a := range v.Args {
+				s += " " + a.Type.SimpleString()
+			}
+			f.Unimplementedf("%s", s)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/magic.go b/src/cmd/compile/internal/ssa/magic.go
new file mode 100644
index 0000000..f6297fd
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/magic.go
@@ -0,0 +1,260 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// A copy of the code in ../gc/subr.go.
+// We can't use it directly because it would generate
+// an import cycle. TODO: move to a common support package.
+
+// 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
+}
+
+// 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
+}
+
+// adaptors for use by rewrite rules
+func smagic64ok(d int64) bool {
+	m := magic{W: 64, Sd: d}
+	smagic(&m)
+	return m.Bad == 0
+}
+func smagic64m(d int64) int64 {
+	m := magic{W: 64, Sd: d}
+	smagic(&m)
+	return m.Sm
+}
+func smagic64s(d int64) int64 {
+	m := magic{W: 64, Sd: d}
+	smagic(&m)
+	return int64(m.S)
+}
+
+func umagic64ok(d int64) bool {
+	m := magic{W: 64, Ud: uint64(d)}
+	umagic(&m)
+	return m.Bad == 0
+}
+func umagic64m(d int64) int64 {
+	m := magic{W: 64, Ud: uint64(d)}
+	umagic(&m)
+	return int64(m.Um)
+}
+func umagic64s(d int64) int64 {
+	m := magic{W: 64, Ud: uint64(d)}
+	umagic(&m)
+	return int64(m.S)
+}
+func umagic64a(d int64) bool {
+	m := magic{W: 64, Ud: uint64(d)}
+	umagic(&m)
+	return m.Ua != 0
+}
diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go
new file mode 100644
index 0000000..00cb75e
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/nilcheck.go
@@ -0,0 +1,161 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// nilcheckelim eliminates unnecessary nil checks.
+func nilcheckelim(f *Func) {
+	// A nil check is redundant if the same nil check was successful in a
+	// dominating block. The efficacy of this pass depends heavily on the
+	// efficacy of the cse pass.
+	idom := f.idom
+	domTree := make([][]*Block, f.NumBlocks())
+
+	// Create a block ID -> [dominees] mapping
+	for _, b := range f.Blocks {
+		if dom := idom[b.ID]; dom != nil {
+			domTree[dom.ID] = append(domTree[dom.ID], b)
+		}
+	}
+
+	// TODO: Eliminate more nil checks.
+	// We can recursively remove any chain of fixed offset calculations,
+	// i.e. struct fields and array elements, even with non-constant
+	// indices: x is non-nil iff x.a.b[i].c is.
+
+	type walkState int
+	const (
+		Work   walkState = iota // clear nil check if we should and traverse to dominees regardless
+		RecPtr                  // record the pointer as being nil checked
+		ClearPtr
+	)
+
+	type bp struct {
+		block *Block // block, or nil in RecPtr/ClearPtr state
+		ptr   *Value // if non-nil, ptr that is to be set/cleared in RecPtr/ClearPtr state
+		op    walkState
+	}
+
+	work := make([]bp, 0, 256)
+	work = append(work, bp{block: f.Entry})
+
+	// map from value ID to bool indicating if value is known to be non-nil
+	// in the current dominator path being walked. This slice is updated by
+	// walkStates to maintain the known non-nil values.
+	nonNilValues := make([]bool, f.NumValues())
+
+	// make an initial pass identifying any non-nil values
+	for _, b := range f.Blocks {
+		// a value resulting from taking the address of a
+		// value, or a value constructed from an offset of a
+		// non-nil ptr (OpAddPtr) implies it is non-nil
+		for _, v := range b.Values {
+			if v.Op == OpAddr || v.Op == OpAddPtr {
+				nonNilValues[v.ID] = true
+			} else if v.Op == OpPhi {
+				// phis whose arguments are all non-nil
+				// are non-nil
+				argsNonNil := true
+				for _, a := range v.Args {
+					if !nonNilValues[a.ID] {
+						argsNonNil = false
+					}
+				}
+				if argsNonNil {
+					nonNilValues[v.ID] = true
+				}
+			}
+		}
+	}
+
+	// perform a depth first walk of the dominee tree
+	for len(work) > 0 {
+		node := work[len(work)-1]
+		work = work[:len(work)-1]
+
+		switch node.op {
+		case Work:
+			checked := checkedptr(node.block) // ptr being checked for nil/non-nil
+			nonnil := nonnilptr(node.block)   // ptr that is non-nil due to this blocks pred
+
+			if checked != nil {
+				// already have a nilcheck in the dominator path, or this block is a success
+				// block for the same value it is checking
+				if nonNilValues[checked.ID] || checked == nonnil {
+					// Eliminate the nil check.
+					// The deadcode pass will remove vestigial values,
+					// and the fuse pass will join this block with its successor.
+
+					// Logging in the style of the former compiler -- and omit line 1,
+					// which is usually in generated code.
+					if f.Config.Debug_checknil() && node.block.Control.Line > 1 {
+						f.Config.Warnl(node.block.Control.Line, "removed nil check")
+					}
+
+					switch node.block.Kind {
+					case BlockIf:
+						node.block.Kind = BlockFirst
+						node.block.SetControl(nil)
+					case BlockCheck:
+						node.block.Kind = BlockPlain
+						node.block.SetControl(nil)
+					default:
+						f.Fatalf("bad block kind in nilcheck %s", node.block.Kind)
+					}
+				}
+			}
+
+			if nonnil != nil && !nonNilValues[nonnil.ID] {
+				// this is a new nilcheck so add a ClearPtr node to clear the
+				// ptr from the map of nil checks once we traverse
+				// back up the tree
+				work = append(work, bp{op: ClearPtr, ptr: nonnil})
+			}
+
+			// add all dominated blocks to the work list
+			for _, w := range domTree[node.block.ID] {
+				work = append(work, bp{block: w})
+			}
+
+			if nonnil != nil && !nonNilValues[nonnil.ID] {
+				work = append(work, bp{op: RecPtr, ptr: nonnil})
+			}
+		case RecPtr:
+			nonNilValues[node.ptr.ID] = true
+			continue
+		case ClearPtr:
+			nonNilValues[node.ptr.ID] = false
+			continue
+		}
+	}
+}
+
+// checkedptr returns the Value, if any,
+// that is used in a nil check in b's Control op.
+func checkedptr(b *Block) *Value {
+	if b.Kind == BlockCheck {
+		return b.Control.Args[0]
+	}
+	if b.Kind == BlockIf && b.Control.Op == OpIsNonNil {
+		return b.Control.Args[0]
+	}
+	return nil
+}
+
+// nonnilptr returns the Value, if any,
+// that is non-nil due to b being the successor block
+// of an OpIsNonNil or OpNilCheck block for the value and having a single
+// predecessor.
+func nonnilptr(b *Block) *Value {
+	if len(b.Preds) == 1 {
+		bp := b.Preds[0].b
+		if bp.Kind == BlockCheck {
+			return bp.Control.Args[0]
+		}
+		if bp.Kind == BlockIf && bp.Control.Op == OpIsNonNil && bp.Succs[0].b == b {
+			return bp.Control.Args[0]
+		}
+	}
+	return nil
+}
diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go
new file mode 100644
index 0000000..af6cbe8
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/nilcheck_test.go
@@ -0,0 +1,443 @@
+package ssa
+
+import (
+	"strconv"
+	"testing"
+)
+
+func BenchmarkNilCheckDeep1(b *testing.B)     { benchmarkNilCheckDeep(b, 1) }
+func BenchmarkNilCheckDeep10(b *testing.B)    { benchmarkNilCheckDeep(b, 10) }
+func BenchmarkNilCheckDeep100(b *testing.B)   { benchmarkNilCheckDeep(b, 100) }
+func BenchmarkNilCheckDeep1000(b *testing.B)  { benchmarkNilCheckDeep(b, 1000) }
+func BenchmarkNilCheckDeep10000(b *testing.B) { benchmarkNilCheckDeep(b, 10000) }
+
+// benchmarkNilCheckDeep is a stress test of nilcheckelim.
+// It uses the worst possible input: A linear string of
+// nil checks, none of which can be eliminated.
+// Run with multiple depths to observe big-O behavior.
+func benchmarkNilCheckDeep(b *testing.B, depth int) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+
+	var blocs []bloc
+	blocs = append(blocs,
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto(blockn(0)),
+		),
+	)
+	for i := 0; i < depth; i++ {
+		blocs = append(blocs,
+			Bloc(blockn(i),
+				Valu(ptrn(i), OpAddr, ptrType, 0, nil, "sb"),
+				Valu(booln(i), OpIsNonNil, TypeBool, 0, nil, ptrn(i)),
+				If(booln(i), blockn(i+1), "exit"),
+			),
+		)
+	}
+	blocs = append(blocs,
+		Bloc(blockn(depth), Goto("exit")),
+		Bloc("exit", Exit("mem")),
+	)
+
+	c := NewConfig("amd64", DummyFrontend{b}, nil, true)
+	fun := Fun(c, "entry", blocs...)
+
+	CheckFunc(fun.f)
+	b.SetBytes(int64(depth)) // helps for eyeballing linearity
+	b.ResetTimer()
+	b.ReportAllocs()
+
+	for i := 0; i < b.N; i++ {
+		domTree(fun.f)
+		nilcheckelim(fun.f)
+	}
+}
+
+func blockn(n int) string { return "b" + strconv.Itoa(n) }
+func ptrn(n int) string   { return "p" + strconv.Itoa(n) }
+func booln(n int) string  { return "c" + strconv.Itoa(n) }
+
+func isNilCheck(b *Block) bool {
+	return b.Kind == BlockIf && b.Control.Op == OpIsNonNil
+}
+
+// TestNilcheckSimple verifies that a second repeated nilcheck is removed.
+func TestNilcheckSimple(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool1", "secondCheck", "exit")),
+		Bloc("secondCheck",
+			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool2", "extra", "exit")),
+		Bloc("extra",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	domTree(fun.f)
+	nilcheckelim(fun.f)
+
+	// clean up the removed nil check
+	fuse(fun.f)
+	deadcode(fun.f)
+
+	CheckFunc(fun.f)
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["secondCheck"] && isNilCheck(b) {
+			t.Errorf("secondCheck was not eliminated")
+		}
+	}
+}
+
+// TestNilcheckDomOrder ensures that the nil check elimination isn't dependent
+// on the order of the dominees.
+func TestNilcheckDomOrder(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool1", "secondCheck", "exit")),
+		Bloc("exit",
+			Exit("mem")),
+		Bloc("secondCheck",
+			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool2", "extra", "exit")),
+		Bloc("extra",
+			Goto("exit")))
+
+	CheckFunc(fun.f)
+	domTree(fun.f)
+	nilcheckelim(fun.f)
+
+	// clean up the removed nil check
+	fuse(fun.f)
+	deadcode(fun.f)
+
+	CheckFunc(fun.f)
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["secondCheck"] && isNilCheck(b) {
+			t.Errorf("secondCheck was not eliminated")
+		}
+	}
+}
+
+// TestNilcheckAddr verifies that nilchecks of OpAddr constructed values are removed.
+func TestNilcheckAddr(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpAddr, ptrType, 0, nil, "sb"),
+			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool1", "extra", "exit")),
+		Bloc("extra",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	domTree(fun.f)
+	nilcheckelim(fun.f)
+
+	// clean up the removed nil check
+	fuse(fun.f)
+	deadcode(fun.f)
+
+	CheckFunc(fun.f)
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["checkPtr"] && isNilCheck(b) {
+			t.Errorf("checkPtr was not eliminated")
+		}
+	}
+}
+
+// TestNilcheckAddPtr verifies that nilchecks of OpAddPtr constructed values are removed.
+func TestNilcheckAddPtr(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("off", OpConst64, TypeInt64, 20, nil),
+			Valu("ptr1", OpAddPtr, ptrType, 0, nil, "sb", "off"),
+			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool1", "extra", "exit")),
+		Bloc("extra",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	domTree(fun.f)
+	nilcheckelim(fun.f)
+
+	// clean up the removed nil check
+	fuse(fun.f)
+	deadcode(fun.f)
+
+	CheckFunc(fun.f)
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["checkPtr"] && isNilCheck(b) {
+			t.Errorf("checkPtr was not eliminated")
+		}
+	}
+}
+
+// TestNilcheckPhi tests that nil checks of phis, for which all values are known to be
+// non-nil are removed.
+func TestNilcheckPhi(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Valu("sp", OpSP, TypeInvalid, 0, nil),
+			Valu("baddr", OpAddr, TypeBool, 0, "b", "sp"),
+			Valu("bool1", OpLoad, TypeBool, 0, nil, "baddr", "mem"),
+			If("bool1", "b1", "b2")),
+		Bloc("b1",
+			Valu("ptr1", OpAddr, ptrType, 0, nil, "sb"),
+			Goto("checkPtr")),
+		Bloc("b2",
+			Valu("ptr2", OpAddr, ptrType, 0, nil, "sb"),
+			Goto("checkPtr")),
+		// both ptr1 and ptr2 are guaranteed non-nil here
+		Bloc("checkPtr",
+			Valu("phi", OpPhi, ptrType, 0, nil, "ptr1", "ptr2"),
+			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "phi"),
+			If("bool2", "extra", "exit")),
+		Bloc("extra",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	domTree(fun.f)
+	nilcheckelim(fun.f)
+
+	// clean up the removed nil check
+	fuse(fun.f)
+	deadcode(fun.f)
+
+	CheckFunc(fun.f)
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["checkPtr"] && isNilCheck(b) {
+			t.Errorf("checkPtr was not eliminated")
+		}
+	}
+}
+
+// TestNilcheckKeepRemove verifies that duplicate checks of the same pointer
+// are removed, but checks of different pointers are not.
+func TestNilcheckKeepRemove(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool1", "differentCheck", "exit")),
+		Bloc("differentCheck",
+			Valu("ptr2", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr2"),
+			If("bool2", "secondCheck", "exit")),
+		Bloc("secondCheck",
+			Valu("bool3", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool3", "extra", "exit")),
+		Bloc("extra",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	domTree(fun.f)
+	nilcheckelim(fun.f)
+
+	// clean up the removed nil check
+	fuse(fun.f)
+	deadcode(fun.f)
+
+	CheckFunc(fun.f)
+	foundDifferentCheck := false
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["secondCheck"] && isNilCheck(b) {
+			t.Errorf("secondCheck was not eliminated")
+		}
+		if b == fun.blocks["differentCheck"] && isNilCheck(b) {
+			foundDifferentCheck = true
+		}
+	}
+	if !foundDifferentCheck {
+		t.Errorf("removed differentCheck, but shouldn't have")
+	}
+}
+
+// TestNilcheckInFalseBranch tests that nil checks in the false branch of an nilcheck
+// block are *not* removed.
+func TestNilcheckInFalseBranch(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("bool1", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool1", "extra", "secondCheck")),
+		Bloc("secondCheck",
+			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool2", "extra", "thirdCheck")),
+		Bloc("thirdCheck",
+			Valu("bool3", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool3", "extra", "exit")),
+		Bloc("extra",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	domTree(fun.f)
+	nilcheckelim(fun.f)
+
+	// clean up the removed nil check
+	fuse(fun.f)
+	deadcode(fun.f)
+
+	CheckFunc(fun.f)
+	foundSecondCheck := false
+	foundThirdCheck := false
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["secondCheck"] && isNilCheck(b) {
+			foundSecondCheck = true
+		}
+		if b == fun.blocks["thirdCheck"] && isNilCheck(b) {
+			foundThirdCheck = true
+		}
+	}
+	if !foundSecondCheck {
+		t.Errorf("removed secondCheck, but shouldn't have [false branch]")
+	}
+	if !foundThirdCheck {
+		t.Errorf("removed thirdCheck, but shouldn't have [false branch]")
+	}
+}
+
+// TestNilcheckUser verifies that a user nil check that dominates a generated nil check
+// wil remove the generated nil check.
+func TestNilcheckUser(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("nilptr", OpConstNil, ptrType, 0, nil),
+			Valu("bool1", OpNeqPtr, TypeBool, 0, nil, "ptr1", "nilptr"),
+			If("bool1", "secondCheck", "exit")),
+		Bloc("secondCheck",
+			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool2", "extra", "exit")),
+		Bloc("extra",
+			Goto("exit")),
+		Bloc("exit",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	// we need the opt here to rewrite the user nilcheck
+	opt(fun.f)
+	domTree(fun.f)
+	nilcheckelim(fun.f)
+
+	// clean up the removed nil check
+	fuse(fun.f)
+	deadcode(fun.f)
+
+	CheckFunc(fun.f)
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["secondCheck"] && isNilCheck(b) {
+			t.Errorf("secondCheck was not eliminated")
+		}
+	}
+}
+
+// TestNilcheckBug reproduces a bug in nilcheckelim found by compiling math/big
+func TestNilcheckBug(t *testing.T) {
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
+	c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto("checkPtr")),
+		Bloc("checkPtr",
+			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
+			Valu("nilptr", OpConstNil, ptrType, 0, nil),
+			Valu("bool1", OpNeqPtr, TypeBool, 0, nil, "ptr1", "nilptr"),
+			If("bool1", "secondCheck", "couldBeNil")),
+		Bloc("couldBeNil",
+			Goto("secondCheck")),
+		Bloc("secondCheck",
+			Valu("bool2", OpIsNonNil, TypeBool, 0, nil, "ptr1"),
+			If("bool2", "extra", "exit")),
+		Bloc("extra",
+			// prevent fuse from eliminating this block
+			Valu("store", OpStore, TypeMem, 8, nil, "ptr1", "nilptr", "mem"),
+			Goto("exit")),
+		Bloc("exit",
+			Valu("phi", OpPhi, TypeMem, 0, nil, "mem", "store"),
+			Exit("phi")))
+
+	CheckFunc(fun.f)
+	// we need the opt here to rewrite the user nilcheck
+	opt(fun.f)
+	domTree(fun.f)
+	nilcheckelim(fun.f)
+
+	// clean up the removed nil check
+	fuse(fun.f)
+	deadcode(fun.f)
+
+	CheckFunc(fun.f)
+	foundSecondCheck := false
+	for _, b := range fun.f.Blocks {
+		if b == fun.blocks["secondCheck"] && isNilCheck(b) {
+			foundSecondCheck = true
+		}
+	}
+	if !foundSecondCheck {
+		t.Errorf("secondCheck was eliminated, but shouldn't have")
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go
new file mode 100644
index 0000000..cadbc7c
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/op.go
@@ -0,0 +1,126 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+)
+
+// An Op encodes the specific operation that a Value performs.
+// Opcodes' semantics can be modified by the type and aux fields of the Value.
+// For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type.
+// Semantics of each op are described in the opcode files in gen/*Ops.go.
+// There is one file for generic (architecture-independent) ops and one file
+// for each architecture.
+type Op int32
+
+type opInfo struct {
+	name              string
+	reg               regInfo
+	auxType           auxType
+	argLen            int32 // the number of arugments, -1 if variable length
+	asm               obj.As
+	generic           bool // this is a generic (arch-independent) opcode
+	rematerializeable bool // this op is rematerializeable
+	commutative       bool // this operation is commutative (e.g. addition)
+	resultInArg0      bool // v and v.Args[0] must be allocated to the same register
+}
+
+type inputInfo struct {
+	idx  int     // index in Args array
+	regs regMask // allowed input registers
+}
+
+type regInfo struct {
+	inputs   []inputInfo // ordered in register allocation order
+	clobbers regMask
+	outputs  []regMask // NOTE: values can only have 1 output for now.
+}
+
+type auxType int8
+
+const (
+	auxNone         auxType = iota
+	auxBool                 // auxInt is 0/1 for false/true
+	auxInt8                 // auxInt is an 8-bit integer
+	auxInt16                // auxInt is a 16-bit integer
+	auxInt32                // auxInt is a 32-bit integer
+	auxInt64                // auxInt is a 64-bit integer
+	auxInt128               // auxInt represents a 128-bit integer.  Always 0.
+	auxFloat32              // auxInt is a float32 (encoded with math.Float64bits)
+	auxFloat64              // auxInt is a float64 (encoded with math.Float64bits)
+	auxString               // aux is a string
+	auxSym                  // aux is a symbol
+	auxSymOff               // aux is a symbol, auxInt is an offset
+	auxSymValAndOff         // aux is a symbol, auxInt is a ValAndOff
+
+	auxSymInt32 // aux is a symbol, auxInt is a 32-bit integer
+)
+
+// A ValAndOff is used by the several opcodes. It holds
+// both a value and a pointer offset.
+// A ValAndOff is intended to be encoded into an AuxInt field.
+// The zero ValAndOff encodes a value of 0 and an offset of 0.
+// The high 32 bits hold a value.
+// The low 32 bits hold a pointer offset.
+type ValAndOff int64
+
+func (x ValAndOff) Val() int64 {
+	return int64(x) >> 32
+}
+func (x ValAndOff) Off() int64 {
+	return int64(int32(x))
+}
+func (x ValAndOff) Int64() int64 {
+	return int64(x)
+}
+func (x ValAndOff) String() string {
+	return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
+}
+
+// validVal reports whether the value can be used
+// as an argument to makeValAndOff.
+func validVal(val int64) bool {
+	return val == int64(int32(val))
+}
+
+// validOff reports whether the offset can be used
+// as an argument to makeValAndOff.
+func validOff(off int64) bool {
+	return off == int64(int32(off))
+}
+
+// validValAndOff reports whether we can fit the value and offset into
+// a ValAndOff value.
+func validValAndOff(val, off int64) bool {
+	if !validVal(val) {
+		return false
+	}
+	if !validOff(off) {
+		return false
+	}
+	return true
+}
+
+// makeValAndOff encodes a ValAndOff into an int64 suitable for storing in an AuxInt field.
+func makeValAndOff(val, off int64) int64 {
+	if !validValAndOff(val, off) {
+		panic("invalid makeValAndOff")
+	}
+	return ValAndOff(val<<32 + int64(uint32(off))).Int64()
+}
+
+func (x ValAndOff) canAdd(off int64) bool {
+	newoff := x.Off() + off
+	return newoff == int64(int32(newoff))
+}
+
+func (x ValAndOff) add(off int64) int64 {
+	if !x.canAdd(off) {
+		panic("invalid ValAndOff.add")
+	}
+	return makeValAndOff(x.Val(), x.Off()+off)
+}
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
new file mode 100644
index 0000000..383f1ae
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -0,0 +1,5442 @@
+// autogenerated: do not edit!
+// generated from gen/*Ops.go
+
+package ssa
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+	"cmd/internal/obj/x86"
+)
+
+const (
+	BlockInvalid BlockKind = iota
+
+	BlockAMD64EQ
+	BlockAMD64NE
+	BlockAMD64LT
+	BlockAMD64LE
+	BlockAMD64GT
+	BlockAMD64GE
+	BlockAMD64ULT
+	BlockAMD64ULE
+	BlockAMD64UGT
+	BlockAMD64UGE
+	BlockAMD64EQF
+	BlockAMD64NEF
+	BlockAMD64ORD
+	BlockAMD64NAN
+
+	BlockARMEQ
+	BlockARMNE
+	BlockARMLT
+	BlockARMLE
+	BlockARMGT
+	BlockARMGE
+	BlockARMULT
+	BlockARMULE
+	BlockARMUGT
+	BlockARMUGE
+
+	BlockPlain
+	BlockIf
+	BlockCall
+	BlockDefer
+	BlockCheck
+	BlockRet
+	BlockRetJmp
+	BlockExit
+	BlockFirst
+)
+
+var blockString = [...]string{
+	BlockInvalid: "BlockInvalid",
+
+	BlockAMD64EQ:  "EQ",
+	BlockAMD64NE:  "NE",
+	BlockAMD64LT:  "LT",
+	BlockAMD64LE:  "LE",
+	BlockAMD64GT:  "GT",
+	BlockAMD64GE:  "GE",
+	BlockAMD64ULT: "ULT",
+	BlockAMD64ULE: "ULE",
+	BlockAMD64UGT: "UGT",
+	BlockAMD64UGE: "UGE",
+	BlockAMD64EQF: "EQF",
+	BlockAMD64NEF: "NEF",
+	BlockAMD64ORD: "ORD",
+	BlockAMD64NAN: "NAN",
+
+	BlockARMEQ:  "EQ",
+	BlockARMNE:  "NE",
+	BlockARMLT:  "LT",
+	BlockARMLE:  "LE",
+	BlockARMGT:  "GT",
+	BlockARMGE:  "GE",
+	BlockARMULT: "ULT",
+	BlockARMULE: "ULE",
+	BlockARMUGT: "UGT",
+	BlockARMUGE: "UGE",
+
+	BlockPlain:  "Plain",
+	BlockIf:     "If",
+	BlockCall:   "Call",
+	BlockDefer:  "Defer",
+	BlockCheck:  "Check",
+	BlockRet:    "Ret",
+	BlockRetJmp: "RetJmp",
+	BlockExit:   "Exit",
+	BlockFirst:  "First",
+}
+
+func (k BlockKind) String() string { return blockString[k] }
+
+const (
+	OpInvalid Op = iota
+
+	OpAMD64ADDSS
+	OpAMD64ADDSD
+	OpAMD64SUBSS
+	OpAMD64SUBSD
+	OpAMD64MULSS
+	OpAMD64MULSD
+	OpAMD64DIVSS
+	OpAMD64DIVSD
+	OpAMD64MOVSSload
+	OpAMD64MOVSDload
+	OpAMD64MOVSSconst
+	OpAMD64MOVSDconst
+	OpAMD64MOVSSloadidx1
+	OpAMD64MOVSSloadidx4
+	OpAMD64MOVSDloadidx1
+	OpAMD64MOVSDloadidx8
+	OpAMD64MOVSSstore
+	OpAMD64MOVSDstore
+	OpAMD64MOVSSstoreidx1
+	OpAMD64MOVSSstoreidx4
+	OpAMD64MOVSDstoreidx1
+	OpAMD64MOVSDstoreidx8
+	OpAMD64ADDQ
+	OpAMD64ADDL
+	OpAMD64ADDQconst
+	OpAMD64ADDLconst
+	OpAMD64SUBQ
+	OpAMD64SUBL
+	OpAMD64SUBQconst
+	OpAMD64SUBLconst
+	OpAMD64MULQ
+	OpAMD64MULL
+	OpAMD64MULQconst
+	OpAMD64MULLconst
+	OpAMD64HMULQ
+	OpAMD64HMULL
+	OpAMD64HMULW
+	OpAMD64HMULB
+	OpAMD64HMULQU
+	OpAMD64HMULLU
+	OpAMD64HMULWU
+	OpAMD64HMULBU
+	OpAMD64AVGQU
+	OpAMD64DIVQ
+	OpAMD64DIVL
+	OpAMD64DIVW
+	OpAMD64DIVQU
+	OpAMD64DIVLU
+	OpAMD64DIVWU
+	OpAMD64MODQ
+	OpAMD64MODL
+	OpAMD64MODW
+	OpAMD64MODQU
+	OpAMD64MODLU
+	OpAMD64MODWU
+	OpAMD64ANDQ
+	OpAMD64ANDL
+	OpAMD64ANDQconst
+	OpAMD64ANDLconst
+	OpAMD64ORQ
+	OpAMD64ORL
+	OpAMD64ORQconst
+	OpAMD64ORLconst
+	OpAMD64XORQ
+	OpAMD64XORL
+	OpAMD64XORQconst
+	OpAMD64XORLconst
+	OpAMD64CMPQ
+	OpAMD64CMPL
+	OpAMD64CMPW
+	OpAMD64CMPB
+	OpAMD64CMPQconst
+	OpAMD64CMPLconst
+	OpAMD64CMPWconst
+	OpAMD64CMPBconst
+	OpAMD64UCOMISS
+	OpAMD64UCOMISD
+	OpAMD64TESTQ
+	OpAMD64TESTL
+	OpAMD64TESTW
+	OpAMD64TESTB
+	OpAMD64TESTQconst
+	OpAMD64TESTLconst
+	OpAMD64TESTWconst
+	OpAMD64TESTBconst
+	OpAMD64SHLQ
+	OpAMD64SHLL
+	OpAMD64SHLQconst
+	OpAMD64SHLLconst
+	OpAMD64SHRQ
+	OpAMD64SHRL
+	OpAMD64SHRW
+	OpAMD64SHRB
+	OpAMD64SHRQconst
+	OpAMD64SHRLconst
+	OpAMD64SHRWconst
+	OpAMD64SHRBconst
+	OpAMD64SARQ
+	OpAMD64SARL
+	OpAMD64SARW
+	OpAMD64SARB
+	OpAMD64SARQconst
+	OpAMD64SARLconst
+	OpAMD64SARWconst
+	OpAMD64SARBconst
+	OpAMD64ROLQconst
+	OpAMD64ROLLconst
+	OpAMD64ROLWconst
+	OpAMD64ROLBconst
+	OpAMD64NEGQ
+	OpAMD64NEGL
+	OpAMD64NOTQ
+	OpAMD64NOTL
+	OpAMD64BSFQ
+	OpAMD64BSFL
+	OpAMD64BSFW
+	OpAMD64BSRQ
+	OpAMD64BSRL
+	OpAMD64BSRW
+	OpAMD64CMOVQEQconst
+	OpAMD64CMOVLEQconst
+	OpAMD64CMOVWEQconst
+	OpAMD64CMOVQNEconst
+	OpAMD64CMOVLNEconst
+	OpAMD64CMOVWNEconst
+	OpAMD64BSWAPQ
+	OpAMD64BSWAPL
+	OpAMD64SQRTSD
+	OpAMD64SBBQcarrymask
+	OpAMD64SBBLcarrymask
+	OpAMD64SETEQ
+	OpAMD64SETNE
+	OpAMD64SETL
+	OpAMD64SETLE
+	OpAMD64SETG
+	OpAMD64SETGE
+	OpAMD64SETB
+	OpAMD64SETBE
+	OpAMD64SETA
+	OpAMD64SETAE
+	OpAMD64SETEQF
+	OpAMD64SETNEF
+	OpAMD64SETORD
+	OpAMD64SETNAN
+	OpAMD64SETGF
+	OpAMD64SETGEF
+	OpAMD64MOVBQSX
+	OpAMD64MOVBQZX
+	OpAMD64MOVWQSX
+	OpAMD64MOVWQZX
+	OpAMD64MOVLQSX
+	OpAMD64MOVLQZX
+	OpAMD64MOVLconst
+	OpAMD64MOVQconst
+	OpAMD64CVTTSD2SL
+	OpAMD64CVTTSD2SQ
+	OpAMD64CVTTSS2SL
+	OpAMD64CVTTSS2SQ
+	OpAMD64CVTSL2SS
+	OpAMD64CVTSL2SD
+	OpAMD64CVTSQ2SS
+	OpAMD64CVTSQ2SD
+	OpAMD64CVTSD2SS
+	OpAMD64CVTSS2SD
+	OpAMD64PXOR
+	OpAMD64LEAQ
+	OpAMD64LEAQ1
+	OpAMD64LEAQ2
+	OpAMD64LEAQ4
+	OpAMD64LEAQ8
+	OpAMD64MOVBload
+	OpAMD64MOVBQSXload
+	OpAMD64MOVWload
+	OpAMD64MOVWQSXload
+	OpAMD64MOVLload
+	OpAMD64MOVLQSXload
+	OpAMD64MOVQload
+	OpAMD64MOVBstore
+	OpAMD64MOVWstore
+	OpAMD64MOVLstore
+	OpAMD64MOVQstore
+	OpAMD64MOVOload
+	OpAMD64MOVOstore
+	OpAMD64MOVBloadidx1
+	OpAMD64MOVWloadidx1
+	OpAMD64MOVWloadidx2
+	OpAMD64MOVLloadidx1
+	OpAMD64MOVLloadidx4
+	OpAMD64MOVQloadidx1
+	OpAMD64MOVQloadidx8
+	OpAMD64MOVBstoreidx1
+	OpAMD64MOVWstoreidx1
+	OpAMD64MOVWstoreidx2
+	OpAMD64MOVLstoreidx1
+	OpAMD64MOVLstoreidx4
+	OpAMD64MOVQstoreidx1
+	OpAMD64MOVQstoreidx8
+	OpAMD64MOVBstoreconst
+	OpAMD64MOVWstoreconst
+	OpAMD64MOVLstoreconst
+	OpAMD64MOVQstoreconst
+	OpAMD64MOVBstoreconstidx1
+	OpAMD64MOVWstoreconstidx1
+	OpAMD64MOVWstoreconstidx2
+	OpAMD64MOVLstoreconstidx1
+	OpAMD64MOVLstoreconstidx4
+	OpAMD64MOVQstoreconstidx1
+	OpAMD64MOVQstoreconstidx8
+	OpAMD64DUFFZERO
+	OpAMD64MOVOconst
+	OpAMD64REPSTOSQ
+	OpAMD64CALLstatic
+	OpAMD64CALLclosure
+	OpAMD64CALLdefer
+	OpAMD64CALLgo
+	OpAMD64CALLinter
+	OpAMD64DUFFCOPY
+	OpAMD64REPMOVSQ
+	OpAMD64InvertFlags
+	OpAMD64LoweredGetG
+	OpAMD64LoweredGetClosurePtr
+	OpAMD64LoweredNilCheck
+	OpAMD64MOVQconvert
+	OpAMD64FlagEQ
+	OpAMD64FlagLT_ULT
+	OpAMD64FlagLT_UGT
+	OpAMD64FlagGT_UGT
+	OpAMD64FlagGT_ULT
+
+	OpARMADD
+	OpARMADDconst
+	OpARMMOVWconst
+	OpARMCMP
+	OpARMMOVWload
+	OpARMMOVWstore
+	OpARMCALLstatic
+	OpARMLessThan
+
+	OpAdd8
+	OpAdd16
+	OpAdd32
+	OpAdd64
+	OpAddPtr
+	OpAdd32F
+	OpAdd64F
+	OpSub8
+	OpSub16
+	OpSub32
+	OpSub64
+	OpSubPtr
+	OpSub32F
+	OpSub64F
+	OpMul8
+	OpMul16
+	OpMul32
+	OpMul64
+	OpMul32F
+	OpMul64F
+	OpDiv32F
+	OpDiv64F
+	OpHmul8
+	OpHmul8u
+	OpHmul16
+	OpHmul16u
+	OpHmul32
+	OpHmul32u
+	OpHmul64
+	OpHmul64u
+	OpAvg64u
+	OpDiv8
+	OpDiv8u
+	OpDiv16
+	OpDiv16u
+	OpDiv32
+	OpDiv32u
+	OpDiv64
+	OpDiv64u
+	OpMod8
+	OpMod8u
+	OpMod16
+	OpMod16u
+	OpMod32
+	OpMod32u
+	OpMod64
+	OpMod64u
+	OpAnd8
+	OpAnd16
+	OpAnd32
+	OpAnd64
+	OpOr8
+	OpOr16
+	OpOr32
+	OpOr64
+	OpXor8
+	OpXor16
+	OpXor32
+	OpXor64
+	OpLsh8x8
+	OpLsh8x16
+	OpLsh8x32
+	OpLsh8x64
+	OpLsh16x8
+	OpLsh16x16
+	OpLsh16x32
+	OpLsh16x64
+	OpLsh32x8
+	OpLsh32x16
+	OpLsh32x32
+	OpLsh32x64
+	OpLsh64x8
+	OpLsh64x16
+	OpLsh64x32
+	OpLsh64x64
+	OpRsh8x8
+	OpRsh8x16
+	OpRsh8x32
+	OpRsh8x64
+	OpRsh16x8
+	OpRsh16x16
+	OpRsh16x32
+	OpRsh16x64
+	OpRsh32x8
+	OpRsh32x16
+	OpRsh32x32
+	OpRsh32x64
+	OpRsh64x8
+	OpRsh64x16
+	OpRsh64x32
+	OpRsh64x64
+	OpRsh8Ux8
+	OpRsh8Ux16
+	OpRsh8Ux32
+	OpRsh8Ux64
+	OpRsh16Ux8
+	OpRsh16Ux16
+	OpRsh16Ux32
+	OpRsh16Ux64
+	OpRsh32Ux8
+	OpRsh32Ux16
+	OpRsh32Ux32
+	OpRsh32Ux64
+	OpRsh64Ux8
+	OpRsh64Ux16
+	OpRsh64Ux32
+	OpRsh64Ux64
+	OpLrot8
+	OpLrot16
+	OpLrot32
+	OpLrot64
+	OpEq8
+	OpEq16
+	OpEq32
+	OpEq64
+	OpEqPtr
+	OpEqInter
+	OpEqSlice
+	OpEq32F
+	OpEq64F
+	OpNeq8
+	OpNeq16
+	OpNeq32
+	OpNeq64
+	OpNeqPtr
+	OpNeqInter
+	OpNeqSlice
+	OpNeq32F
+	OpNeq64F
+	OpLess8
+	OpLess8U
+	OpLess16
+	OpLess16U
+	OpLess32
+	OpLess32U
+	OpLess64
+	OpLess64U
+	OpLess32F
+	OpLess64F
+	OpLeq8
+	OpLeq8U
+	OpLeq16
+	OpLeq16U
+	OpLeq32
+	OpLeq32U
+	OpLeq64
+	OpLeq64U
+	OpLeq32F
+	OpLeq64F
+	OpGreater8
+	OpGreater8U
+	OpGreater16
+	OpGreater16U
+	OpGreater32
+	OpGreater32U
+	OpGreater64
+	OpGreater64U
+	OpGreater32F
+	OpGreater64F
+	OpGeq8
+	OpGeq8U
+	OpGeq16
+	OpGeq16U
+	OpGeq32
+	OpGeq32U
+	OpGeq64
+	OpGeq64U
+	OpGeq32F
+	OpGeq64F
+	OpAndB
+	OpOrB
+	OpEqB
+	OpNeqB
+	OpNot
+	OpNeg8
+	OpNeg16
+	OpNeg32
+	OpNeg64
+	OpNeg32F
+	OpNeg64F
+	OpCom8
+	OpCom16
+	OpCom32
+	OpCom64
+	OpCtz16
+	OpCtz32
+	OpCtz64
+	OpClz16
+	OpClz32
+	OpClz64
+	OpBswap32
+	OpBswap64
+	OpSqrt
+	OpPhi
+	OpCopy
+	OpConvert
+	OpConstBool
+	OpConstString
+	OpConstNil
+	OpConst8
+	OpConst16
+	OpConst32
+	OpConst64
+	OpConst32F
+	OpConst64F
+	OpConstInterface
+	OpConstSlice
+	OpInitMem
+	OpArg
+	OpAddr
+	OpSP
+	OpSB
+	OpFunc
+	OpLoad
+	OpStore
+	OpMove
+	OpZero
+	OpClosureCall
+	OpStaticCall
+	OpDeferCall
+	OpGoCall
+	OpInterCall
+	OpSignExt8to16
+	OpSignExt8to32
+	OpSignExt8to64
+	OpSignExt16to32
+	OpSignExt16to64
+	OpSignExt32to64
+	OpZeroExt8to16
+	OpZeroExt8to32
+	OpZeroExt8to64
+	OpZeroExt16to32
+	OpZeroExt16to64
+	OpZeroExt32to64
+	OpTrunc16to8
+	OpTrunc32to8
+	OpTrunc32to16
+	OpTrunc64to8
+	OpTrunc64to16
+	OpTrunc64to32
+	OpCvt32to32F
+	OpCvt32to64F
+	OpCvt64to32F
+	OpCvt64to64F
+	OpCvt32Fto32
+	OpCvt32Fto64
+	OpCvt64Fto32
+	OpCvt64Fto64
+	OpCvt32Fto64F
+	OpCvt64Fto32F
+	OpIsNonNil
+	OpIsInBounds
+	OpIsSliceInBounds
+	OpNilCheck
+	OpGetG
+	OpGetClosurePtr
+	OpArrayIndex
+	OpPtrIndex
+	OpOffPtr
+	OpSliceMake
+	OpSlicePtr
+	OpSliceLen
+	OpSliceCap
+	OpComplexMake
+	OpComplexReal
+	OpComplexImag
+	OpStringMake
+	OpStringPtr
+	OpStringLen
+	OpIMake
+	OpITab
+	OpIData
+	OpStructMake0
+	OpStructMake1
+	OpStructMake2
+	OpStructMake3
+	OpStructMake4
+	OpStructSelect
+	OpStoreReg
+	OpLoadReg
+	OpFwdRef
+	OpUnknown
+	OpVarDef
+	OpVarKill
+	OpVarLive
+	OpKeepAlive
+)
+
+var opcodeTable = [...]opInfo{
+	{name: "OpInvalid"},
+
+	{
+		name:         "ADDSS",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AADDSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:         "ADDSD",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AADDSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:         "SUBSS",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASUBSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+				{1, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+			},
+			clobbers: 2147483648, // X15
+			outputs: []regMask{
+				2147418112, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+			},
+		},
+	},
+	{
+		name:         "SUBSD",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASUBSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+				{1, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+			},
+			clobbers: 2147483648, // X15
+			outputs: []regMask{
+				2147418112, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+			},
+		},
+	},
+	{
+		name:         "MULSS",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AMULSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:         "MULSD",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AMULSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:         "DIVSS",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ADIVSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+				{1, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+			},
+			clobbers: 2147483648, // X15
+			outputs: []regMask{
+				2147418112, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+			},
+		},
+	},
+	{
+		name:         "DIVSD",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ADIVSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+				{1, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+			},
+			clobbers: 2147483648, // X15
+			outputs: []regMask{
+				2147418112, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+			},
+		},
+	},
+	{
+		name:    "MOVSSload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:    "MOVSDload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:              "MOVSSconst",
+		auxType:           auxFloat32,
+		argLen:            0,
+		rematerializeable: true,
+		asm:               x86.AMOVSS,
+		reg: regInfo{
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:              "MOVSDconst",
+		auxType:           auxFloat64,
+		argLen:            0,
+		rematerializeable: true,
+		asm:               x86.AMOVSD,
+		reg: regInfo{
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:    "MOVSSloadidx1",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:    "MOVSSloadidx4",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:    "MOVSDloadidx1",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:    "MOVSDloadidx8",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:    "MOVSSstore",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVSDstore",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVSSstoreidx1",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVSSstoreidx4",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVSS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVSDstoreidx1",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVSDstoreidx8",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:        "ADDQ",
+		argLen:      2,
+		commutative: true,
+		asm:         x86.AADDQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:        "ADDL",
+		argLen:      2,
+		commutative: true,
+		asm:         x86.AADDL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "ADDQconst",
+		auxType: auxInt64,
+		argLen:  1,
+		asm:     x86.AADDQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "ADDLconst",
+		auxType: auxInt32,
+		argLen:  1,
+		asm:     x86.AADDL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SUBQ",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASUBQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SUBL",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASUBL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SUBQconst",
+		auxType:      auxInt64,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASUBQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SUBLconst",
+		auxType:      auxInt32,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASUBL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "MULQ",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AIMULQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "MULL",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AIMULL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "MULQconst",
+		auxType:      auxInt64,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AIMULQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "MULLconst",
+		auxType:      auxInt32,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AIMULL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "HMULQ",
+		argLen: 2,
+		asm:    x86.AIMULQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "HMULL",
+		argLen: 2,
+		asm:    x86.AIMULL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "HMULW",
+		argLen: 2,
+		asm:    x86.AIMULW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "HMULB",
+		argLen: 2,
+		asm:    x86.AIMULB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "HMULQU",
+		argLen: 2,
+		asm:    x86.AMULQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "HMULLU",
+		argLen: 2,
+		asm:    x86.AMULL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "HMULWU",
+		argLen: 2,
+		asm:    x86.AMULW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "HMULBU",
+		argLen: 2,
+		asm:    x86.AMULB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:         "AVGQU",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "DIVQ",
+		argLen: 2,
+		asm:    x86.AIDIVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934596, // DX FLAGS
+			outputs: []regMask{
+				1, // AX
+			},
+		},
+	},
+	{
+		name:   "DIVL",
+		argLen: 2,
+		asm:    x86.AIDIVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934596, // DX FLAGS
+			outputs: []regMask{
+				1, // AX
+			},
+		},
+	},
+	{
+		name:   "DIVW",
+		argLen: 2,
+		asm:    x86.AIDIVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934596, // DX FLAGS
+			outputs: []regMask{
+				1, // AX
+			},
+		},
+	},
+	{
+		name:   "DIVQU",
+		argLen: 2,
+		asm:    x86.ADIVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934596, // DX FLAGS
+			outputs: []regMask{
+				1, // AX
+			},
+		},
+	},
+	{
+		name:   "DIVLU",
+		argLen: 2,
+		asm:    x86.ADIVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934596, // DX FLAGS
+			outputs: []regMask{
+				1, // AX
+			},
+		},
+	},
+	{
+		name:   "DIVWU",
+		argLen: 2,
+		asm:    x86.ADIVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934596, // DX FLAGS
+			outputs: []regMask{
+				1, // AX
+			},
+		},
+	},
+	{
+		name:   "MODQ",
+		argLen: 2,
+		asm:    x86.AIDIVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "MODL",
+		argLen: 2,
+		asm:    x86.AIDIVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "MODW",
+		argLen: 2,
+		asm:    x86.AIDIVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "MODQU",
+		argLen: 2,
+		asm:    x86.ADIVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "MODLU",
+		argLen: 2,
+		asm:    x86.ADIVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "MODWU",
+		argLen: 2,
+		asm:    x86.ADIVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 1},     // AX
+				{1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:         "ANDQ",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AANDQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ANDL",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AANDL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ANDQconst",
+		auxType:      auxInt64,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AANDQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ANDLconst",
+		auxType:      auxInt32,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AANDL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ORQ",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AORQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ORL",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AORL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ORQconst",
+		auxType:      auxInt64,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AORQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ORLconst",
+		auxType:      auxInt32,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AORL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "XORQ",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AXORQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "XORL",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.AXORL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "XORQconst",
+		auxType:      auxInt64,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AXORQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "XORLconst",
+		auxType:      auxInt32,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AXORL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "CMPQ",
+		argLen: 2,
+		asm:    x86.ACMPQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:   "CMPL",
+		argLen: 2,
+		asm:    x86.ACMPL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:   "CMPW",
+		argLen: 2,
+		asm:    x86.ACMPW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:   "CMPB",
+		argLen: 2,
+		asm:    x86.ACMPB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:    "CMPQconst",
+		auxType: auxInt64,
+		argLen:  1,
+		asm:     x86.ACMPQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:    "CMPLconst",
+		auxType: auxInt32,
+		argLen:  1,
+		asm:     x86.ACMPL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:    "CMPWconst",
+		auxType: auxInt16,
+		argLen:  1,
+		asm:     x86.ACMPW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:    "CMPBconst",
+		auxType: auxInt8,
+		argLen:  1,
+		asm:     x86.ACMPB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:   "UCOMISS",
+		argLen: 2,
+		asm:    x86.AUCOMISS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:   "UCOMISD",
+		argLen: 2,
+		asm:    x86.AUCOMISD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:   "TESTQ",
+		argLen: 2,
+		asm:    x86.ATESTQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:   "TESTL",
+		argLen: 2,
+		asm:    x86.ATESTL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:   "TESTW",
+		argLen: 2,
+		asm:    x86.ATESTW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:   "TESTB",
+		argLen: 2,
+		asm:    x86.ATESTB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:    "TESTQconst",
+		auxType: auxInt64,
+		argLen:  1,
+		asm:     x86.ATESTQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:    "TESTLconst",
+		auxType: auxInt32,
+		argLen:  1,
+		asm:     x86.ATESTL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:    "TESTWconst",
+		auxType: auxInt16,
+		argLen:  1,
+		asm:     x86.ATESTW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:    "TESTBconst",
+		auxType: auxInt8,
+		argLen:  1,
+		asm:     x86.ATESTB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				8589934592, // FLAGS
+			},
+		},
+	},
+	{
+		name:         "SHLQ",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASHLQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHLL",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASHLL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHLQconst",
+		auxType:      auxInt64,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASHLQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHLLconst",
+		auxType:      auxInt32,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASHLL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHRQ",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASHRQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHRL",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASHRL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHRW",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASHRW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHRB",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASHRB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHRQconst",
+		auxType:      auxInt64,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASHRQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHRLconst",
+		auxType:      auxInt32,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASHRL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHRWconst",
+		auxType:      auxInt16,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASHRW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SHRBconst",
+		auxType:      auxInt8,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASHRB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SARQ",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASARQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SARL",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASARL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SARW",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASARW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SARB",
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ASARB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 2},     // CX
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SARQconst",
+		auxType:      auxInt64,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASARQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SARLconst",
+		auxType:      auxInt32,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASARL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SARWconst",
+		auxType:      auxInt16,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASARW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "SARBconst",
+		auxType:      auxInt8,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ASARB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ROLQconst",
+		auxType:      auxInt64,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AROLQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ROLLconst",
+		auxType:      auxInt32,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AROLL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ROLWconst",
+		auxType:      auxInt16,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AROLW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "ROLBconst",
+		auxType:      auxInt8,
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.AROLB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "NEGQ",
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ANEGQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "NEGL",
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ANEGL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "NOTQ",
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ANOTQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "NOTL",
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ANOTL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "BSFQ",
+		argLen: 1,
+		asm:    x86.ABSFQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "BSFL",
+		argLen: 1,
+		asm:    x86.ABSFL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "BSFW",
+		argLen: 1,
+		asm:    x86.ABSFW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "BSRQ",
+		argLen: 1,
+		asm:    x86.ABSRQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "BSRL",
+		argLen: 1,
+		asm:    x86.ABSRL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "BSRW",
+		argLen: 1,
+		asm:    x86.ABSRW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "CMOVQEQconst",
+		auxType:      auxInt64,
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ACMOVQEQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 8589934592}, // FLAGS
+				{0, 65518},      // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "CMOVLEQconst",
+		auxType:      auxInt32,
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ACMOVLEQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 8589934592}, // FLAGS
+				{0, 65518},      // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "CMOVWEQconst",
+		auxType:      auxInt16,
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ACMOVLEQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 8589934592}, // FLAGS
+				{0, 65518},      // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "CMOVQNEconst",
+		auxType:      auxInt64,
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ACMOVQNE,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 8589934592}, // FLAGS
+				{0, 65518},      // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "CMOVLNEconst",
+		auxType:      auxInt32,
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ACMOVLNE,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 8589934592}, // FLAGS
+				{0, 65518},      // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "CMOVWNEconst",
+		auxType:      auxInt16,
+		argLen:       2,
+		resultInArg0: true,
+		asm:          x86.ACMOVLNE,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 8589934592}, // FLAGS
+				{0, 65518},      // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "BSWAPQ",
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ABSWAPQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:         "BSWAPL",
+		argLen:       1,
+		resultInArg0: true,
+		asm:          x86.ABSWAPL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SQRTSD",
+		argLen: 1,
+		asm:    x86.ASQRTSD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:   "SBBQcarrymask",
+		argLen: 1,
+		asm:    x86.ASBBQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SBBLcarrymask",
+		argLen: 1,
+		asm:    x86.ASBBL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETEQ",
+		argLen: 1,
+		asm:    x86.ASETEQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETNE",
+		argLen: 1,
+		asm:    x86.ASETNE,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETL",
+		argLen: 1,
+		asm:    x86.ASETLT,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETLE",
+		argLen: 1,
+		asm:    x86.ASETLE,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETG",
+		argLen: 1,
+		asm:    x86.ASETGT,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETGE",
+		argLen: 1,
+		asm:    x86.ASETGE,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETB",
+		argLen: 1,
+		asm:    x86.ASETCS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETBE",
+		argLen: 1,
+		asm:    x86.ASETLS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETA",
+		argLen: 1,
+		asm:    x86.ASETHI,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETAE",
+		argLen: 1,
+		asm:    x86.ASETCC,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETEQF",
+		argLen: 1,
+		asm:    x86.ASETEQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETNEF",
+		argLen: 1,
+		asm:    x86.ASETNE,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			clobbers: 8589934593, // AX FLAGS
+			outputs: []regMask{
+				65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETORD",
+		argLen: 1,
+		asm:    x86.ASETPC,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETNAN",
+		argLen: 1,
+		asm:    x86.ASETPS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETGF",
+		argLen: 1,
+		asm:    x86.ASETHI,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "SETGEF",
+		argLen: 1,
+		asm:    x86.ASETCC,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 8589934592}, // FLAGS
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "MOVBQSX",
+		argLen: 1,
+		asm:    x86.AMOVBQSX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "MOVBQZX",
+		argLen: 1,
+		asm:    x86.AMOVBQZX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "MOVWQSX",
+		argLen: 1,
+		asm:    x86.AMOVWQSX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "MOVWQZX",
+		argLen: 1,
+		asm:    x86.AMOVWQZX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "MOVLQSX",
+		argLen: 1,
+		asm:    x86.AMOVLQSX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "MOVLQZX",
+		argLen: 1,
+		asm:    x86.AMOVLQZX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:              "MOVLconst",
+		auxType:           auxInt32,
+		argLen:            0,
+		rematerializeable: true,
+		asm:               x86.AMOVL,
+		reg: regInfo{
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:              "MOVQconst",
+		auxType:           auxInt64,
+		argLen:            0,
+		rematerializeable: true,
+		asm:               x86.AMOVQ,
+		reg: regInfo{
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "CVTTSD2SL",
+		argLen: 1,
+		asm:    x86.ACVTTSD2SL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "CVTTSD2SQ",
+		argLen: 1,
+		asm:    x86.ACVTTSD2SQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "CVTTSS2SL",
+		argLen: 1,
+		asm:    x86.ACVTTSS2SL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "CVTTSS2SQ",
+		argLen: 1,
+		asm:    x86.ACVTTSS2SQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "CVTSL2SS",
+		argLen: 1,
+		asm:    x86.ACVTSL2SS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:   "CVTSL2SD",
+		argLen: 1,
+		asm:    x86.ACVTSL2SD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:   "CVTSQ2SS",
+		argLen: 1,
+		asm:    x86.ACVTSQ2SS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:   "CVTSQ2SD",
+		argLen: 1,
+		asm:    x86.ACVTSQ2SD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:   "CVTSD2SS",
+		argLen: 1,
+		asm:    x86.ACVTSD2SS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:   "CVTSS2SD",
+		argLen: 1,
+		asm:    x86.ACVTSS2SD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:         "PXOR",
+		argLen:       2,
+		commutative:  true,
+		resultInArg0: true,
+		asm:          x86.APXOR,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:              "LEAQ",
+		auxType:           auxSymOff,
+		argLen:            1,
+		rematerializeable: true,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "LEAQ1",
+		auxType: auxSymOff,
+		argLen:  2,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "LEAQ2",
+		auxType: auxSymOff,
+		argLen:  2,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "LEAQ4",
+		auxType: auxSymOff,
+		argLen:  2,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "LEAQ8",
+		auxType: auxSymOff,
+		argLen:  2,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVBload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVBLZX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVBQSXload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVBQSX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVWload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVWLZX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVWQSXload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVWQSX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVLload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVLQSXload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVLQSX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVQload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVBstore",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVWstore",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVLstore",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVQstore",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVOload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     x86.AMOVUPS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:    "MOVOstore",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVUPS,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVBloadidx1",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVBLZX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVWloadidx1",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVWLZX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVWloadidx2",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVWLZX,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVLloadidx1",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVLloadidx4",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVQloadidx1",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVQloadidx8",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:    "MOVBstoreidx1",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVWstoreidx1",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVWstoreidx2",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVLstoreidx1",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVLstoreidx4",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVQstoreidx1",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVQstoreidx8",
+		auxType: auxSymOff,
+		argLen:  4,
+		asm:     x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{2, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVBstoreconst",
+		auxType: auxSymValAndOff,
+		argLen:  2,
+		asm:     x86.AMOVB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVWstoreconst",
+		auxType: auxSymValAndOff,
+		argLen:  2,
+		asm:     x86.AMOVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVLstoreconst",
+		auxType: auxSymValAndOff,
+		argLen:  2,
+		asm:     x86.AMOVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVQstoreconst",
+		auxType: auxSymValAndOff,
+		argLen:  2,
+		asm:     x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVBstoreconstidx1",
+		auxType: auxSymValAndOff,
+		argLen:  3,
+		asm:     x86.AMOVB,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVWstoreconstidx1",
+		auxType: auxSymValAndOff,
+		argLen:  3,
+		asm:     x86.AMOVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVWstoreconstidx2",
+		auxType: auxSymValAndOff,
+		argLen:  3,
+		asm:     x86.AMOVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVLstoreconstidx1",
+		auxType: auxSymValAndOff,
+		argLen:  3,
+		asm:     x86.AMOVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVLstoreconstidx4",
+		auxType: auxSymValAndOff,
+		argLen:  3,
+		asm:     x86.AMOVL,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVQstoreconstidx1",
+		auxType: auxSymValAndOff,
+		argLen:  3,
+		asm:     x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "MOVQstoreconstidx8",
+		auxType: auxSymValAndOff,
+		argLen:  3,
+		asm:     x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 65535},      // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+				{0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+			},
+		},
+	},
+	{
+		name:    "DUFFZERO",
+		auxType: auxInt64,
+		argLen:  3,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 128},   // DI
+				{1, 65536}, // X0
+			},
+			clobbers: 8589934720, // DI FLAGS
+		},
+	},
+	{
+		name:              "MOVOconst",
+		auxType:           auxInt128,
+		argLen:            0,
+		rematerializeable: true,
+		reg: regInfo{
+			outputs: []regMask{
+				4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+			},
+		},
+	},
+	{
+		name:   "REPSTOSQ",
+		argLen: 4,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 128}, // DI
+				{1, 2},   // CX
+				{2, 1},   // AX
+			},
+			clobbers: 130, // CX DI
+		},
+	},
+	{
+		name:    "CALLstatic",
+		auxType: auxSymOff,
+		argLen:  1,
+		reg: regInfo{
+			clobbers: 12884901871, // AX CX DX BX 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 FLAGS
+		},
+	},
+	{
+		name:    "CALLclosure",
+		auxType: auxInt64,
+		argLen:  3,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{1, 4},     // DX
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 12884901871, // AX CX DX BX 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 FLAGS
+		},
+	},
+	{
+		name:    "CALLdefer",
+		auxType: auxInt64,
+		argLen:  1,
+		reg: regInfo{
+			clobbers: 12884901871, // AX CX DX BX 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 FLAGS
+		},
+	},
+	{
+		name:    "CALLgo",
+		auxType: auxInt64,
+		argLen:  1,
+		reg: regInfo{
+			clobbers: 12884901871, // AX CX DX BX 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 FLAGS
+		},
+	},
+	{
+		name:    "CALLinter",
+		auxType: auxInt64,
+		argLen:  2,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 12884901871, // AX CX DX BX 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 FLAGS
+		},
+	},
+	{
+		name:    "DUFFCOPY",
+		auxType: auxInt64,
+		argLen:  3,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 128}, // DI
+				{1, 64},  // SI
+			},
+			clobbers: 8590000320, // SI DI X0 FLAGS
+		},
+	},
+	{
+		name:   "REPMOVSQ",
+		argLen: 4,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 128}, // DI
+				{1, 64},  // SI
+				{2, 2},   // CX
+			},
+			clobbers: 194, // CX SI DI
+		},
+	},
+	{
+		name:   "InvertFlags",
+		argLen: 1,
+		reg:    regInfo{},
+	},
+	{
+		name:   "LoweredGetG",
+		argLen: 1,
+		reg: regInfo{
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "LoweredGetClosurePtr",
+		argLen: 0,
+		reg: regInfo{
+			outputs: []regMask{
+				4, // DX
+			},
+		},
+	},
+	{
+		name:   "LoweredNilCheck",
+		argLen: 2,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			clobbers: 8589934592, // FLAGS
+		},
+	},
+	{
+		name:   "MOVQconvert",
+		argLen: 2,
+		asm:    x86.AMOVQ,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+			outputs: []regMask{
+				65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+			},
+		},
+	},
+	{
+		name:   "FlagEQ",
+		argLen: 0,
+		reg:    regInfo{},
+	},
+	{
+		name:   "FlagLT_ULT",
+		argLen: 0,
+		reg:    regInfo{},
+	},
+	{
+		name:   "FlagLT_UGT",
+		argLen: 0,
+		reg:    regInfo{},
+	},
+	{
+		name:   "FlagGT_UGT",
+		argLen: 0,
+		reg:    regInfo{},
+	},
+	{
+		name:   "FlagGT_ULT",
+		argLen: 0,
+		reg:    regInfo{},
+	},
+
+	{
+		name:        "ADD",
+		argLen:      2,
+		commutative: true,
+		asm:         arm.AADD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 31}, // R0 R1 R2 R3 SP
+				{1, 31}, // R0 R1 R2 R3 SP
+			},
+			outputs: []regMask{
+				31, // R0 R1 R2 R3 SP
+			},
+		},
+	},
+	{
+		name:    "ADDconst",
+		auxType: auxSymOff,
+		argLen:  1,
+		asm:     arm.AADD,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 31}, // R0 R1 R2 R3 SP
+			},
+			outputs: []regMask{
+				31, // R0 R1 R2 R3 SP
+			},
+		},
+	},
+	{
+		name:              "MOVWconst",
+		auxType:           auxInt32,
+		argLen:            0,
+		rematerializeable: true,
+		asm:               arm.AMOVW,
+		reg: regInfo{
+			outputs: []regMask{
+				31, // R0 R1 R2 R3 SP
+			},
+		},
+	},
+	{
+		name:   "CMP",
+		argLen: 2,
+		asm:    arm.ACMP,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 31}, // R0 R1 R2 R3 SP
+				{1, 31}, // R0 R1 R2 R3 SP
+			},
+			outputs: []regMask{
+				32, // FLAGS
+			},
+		},
+	},
+	{
+		name:    "MOVWload",
+		auxType: auxSymOff,
+		argLen:  2,
+		asm:     arm.AMOVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 31}, // R0 R1 R2 R3 SP
+			},
+			outputs: []regMask{
+				31, // R0 R1 R2 R3 SP
+			},
+		},
+	},
+	{
+		name:    "MOVWstore",
+		auxType: auxSymOff,
+		argLen:  3,
+		asm:     arm.AMOVW,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 31}, // R0 R1 R2 R3 SP
+				{1, 31}, // R0 R1 R2 R3 SP
+			},
+		},
+	},
+	{
+		name:    "CALLstatic",
+		auxType: auxSymOff,
+		argLen:  1,
+		reg: regInfo{
+			clobbers: 15, // R0 R1 R2 R3
+		},
+	},
+	{
+		name:   "LessThan",
+		argLen: 1,
+		reg: regInfo{
+			inputs: []inputInfo{
+				{0, 32}, // FLAGS
+			},
+			outputs: []regMask{
+				31, // R0 R1 R2 R3 SP
+			},
+		},
+	},
+
+	{
+		name:        "Add8",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Add16",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Add32",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Add64",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:    "AddPtr",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Add32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Add64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Sub8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Sub16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Sub32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Sub64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "SubPtr",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Sub32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Sub64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:        "Mul8",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Mul16",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Mul32",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Mul64",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:    "Mul32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Mul64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Hmul8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Hmul8u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Hmul16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Hmul16u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Hmul32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Hmul32u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Hmul64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Hmul64u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Avg64u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div8u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div16u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div32u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Div64u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Mod8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Mod8u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Mod16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Mod16u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Mod32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Mod32u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Mod64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Mod64u",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:        "And8",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "And16",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "And32",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "And64",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Or8",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Or16",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Or32",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Or64",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Xor8",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Xor16",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Xor32",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Xor64",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:    "Lsh8x8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh8x16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh8x32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh8x64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh16x8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh16x16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh16x32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh16x64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh32x8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh32x16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh32x32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh32x64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh64x8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh64x16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh64x32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lsh64x64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh8x8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh8x16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh8x32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh8x64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh16x8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh16x16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh16x32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh16x64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh32x8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh32x16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh32x32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh32x64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh64x8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh64x16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh64x32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh64x64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh8Ux8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh8Ux16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh8Ux32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh8Ux64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh16Ux8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh16Ux16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh16Ux32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh16Ux64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh32Ux8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh32Ux16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh32Ux32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh32Ux64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh64Ux8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh64Ux16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh64Ux32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Rsh64Ux64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Lrot8",
+		auxType: auxInt64,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Lrot16",
+		auxType: auxInt64,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Lrot32",
+		auxType: auxInt64,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Lrot64",
+		auxType: auxInt64,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:        "Eq8",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Eq16",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Eq32",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Eq64",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "EqPtr",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:    "EqInter",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "EqSlice",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Eq32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Eq64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:        "Neq8",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Neq16",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Neq32",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "Neq64",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:        "NeqPtr",
+		argLen:      2,
+		commutative: true,
+		generic:     true,
+	},
+	{
+		name:    "NeqInter",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "NeqSlice",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Neq32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Neq64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less8U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less16U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less32U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less64U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Less64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq8U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq16U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq32U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq64U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Leq64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater8U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater16U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater32U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater64U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Greater64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq8",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq8U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq16",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq16U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq32",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq32U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq64",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq64U",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq32F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Geq64F",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "AndB",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "OrB",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "EqB",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "NeqB",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Not",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Neg8",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Neg16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Neg32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Neg64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Neg32F",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Neg64F",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Com8",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Com16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Com32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Com64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Ctz16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Ctz32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Ctz64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Clz16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Clz32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Clz64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Bswap32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Bswap64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Sqrt",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Phi",
+		argLen:  -1,
+		generic: true,
+	},
+	{
+		name:    "Copy",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Convert",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "ConstBool",
+		auxType: auxBool,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "ConstString",
+		auxType: auxString,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "ConstNil",
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Const8",
+		auxType: auxInt8,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Const16",
+		auxType: auxInt16,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Const32",
+		auxType: auxInt32,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Const64",
+		auxType: auxInt64,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Const32F",
+		auxType: auxFloat32,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Const64F",
+		auxType: auxFloat64,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "ConstInterface",
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "ConstSlice",
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "InitMem",
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Arg",
+		auxType: auxSymOff,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Addr",
+		auxType: auxSym,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "SP",
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "SB",
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Func",
+		auxType: auxSym,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Load",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "Store",
+		auxType: auxInt64,
+		argLen:  3,
+		generic: true,
+	},
+	{
+		name:    "Move",
+		auxType: auxInt64,
+		argLen:  3,
+		generic: true,
+	},
+	{
+		name:    "Zero",
+		auxType: auxInt64,
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "ClosureCall",
+		auxType: auxInt64,
+		argLen:  3,
+		generic: true,
+	},
+	{
+		name:    "StaticCall",
+		auxType: auxSymOff,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "DeferCall",
+		auxType: auxInt64,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "GoCall",
+		auxType: auxInt64,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "InterCall",
+		auxType: auxInt64,
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "SignExt8to16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "SignExt8to32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "SignExt8to64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "SignExt16to32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "SignExt16to64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "SignExt32to64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "ZeroExt8to16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "ZeroExt8to32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "ZeroExt8to64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "ZeroExt16to32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "ZeroExt16to64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "ZeroExt32to64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Trunc16to8",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Trunc32to8",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Trunc32to16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Trunc64to8",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Trunc64to16",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Trunc64to32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt32to32F",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt32to64F",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt64to32F",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt64to64F",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt32Fto32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt32Fto64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt64Fto32",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt64Fto64",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt32Fto64F",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "Cvt64Fto32F",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "IsNonNil",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "IsInBounds",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "IsSliceInBounds",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "NilCheck",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "GetG",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "GetClosurePtr",
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "ArrayIndex",
+		auxType: auxInt64,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "PtrIndex",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "OffPtr",
+		auxType: auxInt64,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "SliceMake",
+		argLen:  3,
+		generic: true,
+	},
+	{
+		name:    "SlicePtr",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "SliceLen",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "SliceCap",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "ComplexMake",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "ComplexReal",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "ComplexImag",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "StringMake",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "StringPtr",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "StringLen",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "IMake",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "ITab",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "IData",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "StructMake0",
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "StructMake1",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "StructMake2",
+		argLen:  2,
+		generic: true,
+	},
+	{
+		name:    "StructMake3",
+		argLen:  3,
+		generic: true,
+	},
+	{
+		name:    "StructMake4",
+		argLen:  4,
+		generic: true,
+	},
+	{
+		name:    "StructSelect",
+		auxType: auxInt64,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "StoreReg",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "LoadReg",
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "FwdRef",
+		auxType: auxSym,
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "Unknown",
+		argLen:  0,
+		generic: true,
+	},
+	{
+		name:    "VarDef",
+		auxType: auxSym,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "VarKill",
+		auxType: auxSym,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "VarLive",
+		auxType: auxSym,
+		argLen:  1,
+		generic: true,
+	},
+	{
+		name:    "KeepAlive",
+		argLen:  2,
+		generic: true,
+	},
+}
+
+func (o Op) Asm() obj.As    { return opcodeTable[o].asm }
+func (o Op) String() string { return opcodeTable[o].name }
+
+var registersAMD64 = [...]Register{
+	{0, "AX"},
+	{1, "CX"},
+	{2, "DX"},
+	{3, "BX"},
+	{4, "SP"},
+	{5, "BP"},
+	{6, "SI"},
+	{7, "DI"},
+	{8, "R8"},
+	{9, "R9"},
+	{10, "R10"},
+	{11, "R11"},
+	{12, "R12"},
+	{13, "R13"},
+	{14, "R14"},
+	{15, "R15"},
+	{16, "X0"},
+	{17, "X1"},
+	{18, "X2"},
+	{19, "X3"},
+	{20, "X4"},
+	{21, "X5"},
+	{22, "X6"},
+	{23, "X7"},
+	{24, "X8"},
+	{25, "X9"},
+	{26, "X10"},
+	{27, "X11"},
+	{28, "X12"},
+	{29, "X13"},
+	{30, "X14"},
+	{31, "X15"},
+	{32, "SB"},
+	{33, "FLAGS"},
+}
+var registersARM = [...]Register{
+	{0, "R0"},
+	{1, "R1"},
+	{2, "R2"},
+	{3, "R3"},
+	{4, "SP"},
+	{5, "FLAGS"},
+	{6, "SB"},
+}
diff --git a/src/cmd/compile/internal/ssa/opt.go b/src/cmd/compile/internal/ssa/opt.go
new file mode 100644
index 0000000..caf8cca
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/opt.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.
+
+package ssa
+
+// machine-independent optimization
+func opt(f *Func) {
+	applyRewrite(f, rewriteBlockgeneric, rewriteValuegeneric)
+}
+
+func dec(f *Func) {
+	applyRewrite(f, rewriteBlockdec, rewriteValuedec)
+}
diff --git a/src/cmd/compile/internal/ssa/passbm_test.go b/src/cmd/compile/internal/ssa/passbm_test.go
new file mode 100644
index 0000000..87069ab
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/passbm_test.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 ssa
+
+import (
+	"fmt"
+	"testing"
+)
+
+const (
+	blockCount = 1000
+	passCount  = 15000
+)
+
+type passFunc func(*Func)
+
+func BenchmarkDSEPass(b *testing.B)           { benchFnPass(b, dse, blockCount, genFunction) }
+func BenchmarkDSEPassBlock(b *testing.B)      { benchFnBlock(b, dse, genFunction) }
+func BenchmarkCSEPass(b *testing.B)           { benchFnPass(b, cse, blockCount, genFunction) }
+func BenchmarkCSEPassBlock(b *testing.B)      { benchFnBlock(b, cse, genFunction) }
+func BenchmarkDeadcodePass(b *testing.B)      { benchFnPass(b, deadcode, blockCount, genFunction) }
+func BenchmarkDeadcodePassBlock(b *testing.B) { benchFnBlock(b, deadcode, genFunction) }
+
+func multi(f *Func) {
+	cse(f)
+	dse(f)
+	deadcode(f)
+}
+func BenchmarkMultiPass(b *testing.B)      { benchFnPass(b, multi, blockCount, genFunction) }
+func BenchmarkMultiPassBlock(b *testing.B) { benchFnBlock(b, multi, genFunction) }
+
+// benchFnPass runs passFunc b.N times across a single function.
+func benchFnPass(b *testing.B, fn passFunc, size int, bg blockGen) {
+	b.ReportAllocs()
+	c := NewConfig("amd64", DummyFrontend{b}, nil, true)
+	fun := Fun(c, "entry", bg(size)...)
+	domTree(fun.f)
+	CheckFunc(fun.f)
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		fn(fun.f)
+		b.StopTimer()
+		CheckFunc(fun.f)
+		b.StartTimer()
+	}
+}
+
+// benchFnPass runs passFunc across a function with b.N blocks.
+func benchFnBlock(b *testing.B, fn passFunc, bg blockGen) {
+	b.ReportAllocs()
+	c := NewConfig("amd64", DummyFrontend{b}, nil, true)
+	fun := Fun(c, "entry", bg(b.N)...)
+	domTree(fun.f)
+	CheckFunc(fun.f)
+	b.ResetTimer()
+	for i := 0; i < passCount; i++ {
+		fn(fun.f)
+	}
+	b.StopTimer()
+}
+
+func genFunction(size int) []bloc {
+	var blocs []bloc
+	elemType := &TypeImpl{Size_: 8, Name: "testtype"}
+	ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing
+
+	valn := func(s string, m, n int) string { return fmt.Sprintf("%s%d-%d", s, m, n) }
+	blocs = append(blocs,
+		Bloc("entry",
+			Valu(valn("store", 0, 4), OpInitMem, TypeMem, 0, nil),
+			Valu("sb", OpSB, TypeInvalid, 0, nil),
+			Goto(blockn(1)),
+		),
+	)
+	for i := 1; i < size+1; i++ {
+		blocs = append(blocs, Bloc(blockn(i),
+			Valu(valn("v", i, 0), OpConstBool, TypeBool, 1, nil),
+			Valu(valn("addr", i, 1), OpAddr, ptrType, 0, nil, "sb"),
+			Valu(valn("addr", i, 2), OpAddr, ptrType, 0, nil, "sb"),
+			Valu(valn("addr", i, 3), OpAddr, ptrType, 0, nil, "sb"),
+			Valu(valn("zero", i, 1), OpZero, TypeMem, 8, nil, valn("addr", i, 3),
+				valn("store", i-1, 4)),
+			Valu(valn("store", i, 1), OpStore, TypeMem, 0, nil, valn("addr", i, 1),
+				valn("v", i, 0), valn("zero", i, 1)),
+			Valu(valn("store", i, 2), OpStore, TypeMem, 0, nil, valn("addr", i, 2),
+				valn("v", i, 0), valn("store", i, 1)),
+			Valu(valn("store", i, 3), OpStore, TypeMem, 0, nil, valn("addr", i, 1),
+				valn("v", i, 0), valn("store", i, 2)),
+			Valu(valn("store", i, 4), OpStore, TypeMem, 0, nil, valn("addr", i, 3),
+				valn("v", i, 0), valn("store", i, 3)),
+			Goto(blockn(i+1))))
+	}
+
+	blocs = append(blocs,
+		Bloc(blockn(size+1), Goto("exit")),
+		Bloc("exit", Exit("store0-4")),
+	)
+
+	return blocs
+}
diff --git a/src/cmd/compile/internal/ssa/phielim.go b/src/cmd/compile/internal/ssa/phielim.go
new file mode 100644
index 0000000..5fccab9
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/phielim.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 ssa
+
+// phielim eliminates redundant phi values from f.
+// A phi is redundant if its arguments are all equal. For
+// purposes of counting, ignore the phi itself. Both of
+// these phis are redundant:
+//   v = phi(x,x,x)
+//   v = phi(x,v,x,v)
+// We repeat this process to also catch situations like:
+//   v = phi(x, phi(x, x), phi(x, v))
+// TODO: Can we also simplify cases like:
+//   v = phi(v, w, x)
+//   w = phi(v, w, x)
+// and would that be useful?
+func phielim(f *Func) {
+	for {
+		change := false
+		for _, b := range f.Blocks {
+			for _, v := range b.Values {
+				copyelimValue(v)
+				change = phielimValue(v) || change
+			}
+		}
+		if !change {
+			break
+		}
+	}
+}
+
+// phielimValue tries to convert the phi v to a copy.
+func phielimValue(v *Value) bool {
+	if v.Op != OpPhi {
+		return false
+	}
+
+	// If there are two distinct args of v which
+	// are not v itself, then the phi must remain.
+	// Otherwise, we can replace it with a copy.
+	var w *Value
+	for _, x := range v.Args {
+		if x == v {
+			continue
+		}
+		if x == w {
+			continue
+		}
+		if w != nil {
+			return false
+		}
+		w = x
+	}
+
+	if w == nil {
+		// v references only itself. It must be in
+		// a dead code loop. Don't bother modifying it.
+		return false
+	}
+	v.Op = OpCopy
+	v.SetArgs1(w)
+	f := v.Block.Func
+	if f.pass.debug > 0 {
+		f.Config.Warnl(v.Line, "eliminated phi")
+	}
+	return true
+}
diff --git a/src/cmd/compile/internal/ssa/phiopt.go b/src/cmd/compile/internal/ssa/phiopt.go
new file mode 100644
index 0000000..d6272b4
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/phiopt.go
@@ -0,0 +1,114 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// phiopt eliminates boolean Phis based on the previous if.
+//
+// Main use case is to transform:
+//   x := false
+//   if b {
+//     x = true
+//   }
+// into x = b.
+//
+// In SSA code this appears as
+//
+// b0
+//   If b -> b1 b2
+// b1
+//   Plain -> b2
+// b2
+//   x = (OpPhi (ConstBool [true]) (ConstBool [false]))
+//
+// In this case we can replace x with a copy of b.
+func phiopt(f *Func) {
+	for _, b := range f.Blocks {
+		if len(b.Preds) != 2 || len(b.Values) == 0 {
+			// TODO: handle more than 2 predecessors, e.g. a || b || c.
+			continue
+		}
+
+		pb0, b0 := b, b.Preds[0].b
+		for len(b0.Succs) == 1 && len(b0.Preds) == 1 {
+			pb0, b0 = b0, b0.Preds[0].b
+		}
+		if b0.Kind != BlockIf {
+			continue
+		}
+		pb1, b1 := b, b.Preds[1].b
+		for len(b1.Succs) == 1 && len(b1.Preds) == 1 {
+			pb1, b1 = b1, b1.Preds[0].b
+		}
+		if b1 != b0 {
+			continue
+		}
+		// b0 is the if block giving the boolean value.
+
+		// reverse is the predecessor from which the truth value comes.
+		var reverse int
+		if b0.Succs[0].b == pb0 && b0.Succs[1].b == pb1 {
+			reverse = 0
+		} else if b0.Succs[0].b == pb1 && b0.Succs[1].b == pb0 {
+			reverse = 1
+		} else {
+			b.Fatalf("invalid predecessors\n")
+		}
+
+		for _, v := range b.Values {
+			if v.Op != OpPhi || !v.Type.IsBoolean() {
+				continue
+			}
+
+			// Replaces
+			//   if a { x = true } else { x = false } with x = a
+			// and
+			//   if a { x = false } else { x = true } with x = !a
+			if v.Args[0].Op == OpConstBool && v.Args[1].Op == OpConstBool {
+				if v.Args[reverse].AuxInt != v.Args[1-reverse].AuxInt {
+					ops := [2]Op{OpNot, OpCopy}
+					v.reset(ops[v.Args[reverse].AuxInt])
+					v.AddArg(b0.Control)
+					if f.pass.debug > 0 {
+						f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
+					}
+					continue
+				}
+			}
+
+			// Replaces
+			//   if a { x = true } else { x = value } with x = a || value.
+			// Requires that value dominates x, meaning that regardless of a,
+			// value is always computed. This guarantees that the side effects
+			// of value are not seen if a is false.
+			if v.Args[reverse].Op == OpConstBool && v.Args[reverse].AuxInt == 1 {
+				if tmp := v.Args[1-reverse]; f.sdom.isAncestorEq(tmp.Block, b) {
+					v.reset(OpOrB)
+					v.SetArgs2(b0.Control, tmp)
+					if f.pass.debug > 0 {
+						f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
+					}
+					continue
+				}
+			}
+
+			// Replaces
+			//   if a { x = value } else { x = false } with x = a && value.
+			// Requires that value dominates x, meaning that regardless of a,
+			// value is always computed. This guarantees that the side effects
+			// of value are not seen if a is false.
+			if v.Args[1-reverse].Op == OpConstBool && v.Args[1-reverse].AuxInt == 0 {
+				if tmp := v.Args[reverse]; f.sdom.isAncestorEq(tmp.Block, b) {
+					v.reset(OpAndB)
+					v.SetArgs2(b0.Control, tmp)
+					if f.pass.debug > 0 {
+						f.Config.Warnl(b.Line, "converted OpPhi to %v", v.Op)
+					}
+					continue
+				}
+			}
+		}
+	}
+
+}
diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go
new file mode 100644
index 0000000..21e293c
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/print.go
@@ -0,0 +1,150 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+)
+
+func printFunc(f *Func) {
+	f.Logf("%s", f)
+}
+
+func (f *Func) String() string {
+	var buf bytes.Buffer
+	p := stringFuncPrinter{w: &buf}
+	fprintFunc(p, f)
+	return buf.String()
+}
+
+type funcPrinter interface {
+	header(f *Func)
+	startBlock(b *Block, reachable bool)
+	endBlock(b *Block)
+	value(v *Value, live bool)
+	startDepCycle()
+	endDepCycle()
+	named(n LocalSlot, vals []*Value)
+}
+
+type stringFuncPrinter struct {
+	w io.Writer
+}
+
+func (p stringFuncPrinter) header(f *Func) {
+	fmt.Fprint(p.w, f.Name)
+	fmt.Fprint(p.w, " ")
+	fmt.Fprintln(p.w, f.Type)
+}
+
+func (p stringFuncPrinter) startBlock(b *Block, reachable bool) {
+	fmt.Fprintf(p.w, "  b%d:", b.ID)
+	if len(b.Preds) > 0 {
+		io.WriteString(p.w, " <-")
+		for _, e := range b.Preds {
+			pred := e.b
+			fmt.Fprintf(p.w, " b%d", pred.ID)
+		}
+	}
+	if !reachable {
+		fmt.Fprint(p.w, " DEAD")
+	}
+	io.WriteString(p.w, "\n")
+}
+
+func (p stringFuncPrinter) endBlock(b *Block) {
+	fmt.Fprintln(p.w, "    "+b.LongString())
+}
+
+func (p stringFuncPrinter) value(v *Value, live bool) {
+	fmt.Fprint(p.w, "    ")
+	//fmt.Fprint(p.w, v.Block.Func.Config.fe.Line(v.Line))
+	//fmt.Fprint(p.w, ": ")
+	fmt.Fprint(p.w, v.LongString())
+	if !live {
+		fmt.Fprint(p.w, " DEAD")
+	}
+	fmt.Fprintln(p.w)
+}
+
+func (p stringFuncPrinter) startDepCycle() {
+	fmt.Fprintln(p.w, "dependency cycle!")
+}
+
+func (p stringFuncPrinter) endDepCycle() {}
+
+func (p stringFuncPrinter) named(n LocalSlot, vals []*Value) {
+	fmt.Fprintf(p.w, "name %s: %v\n", n.Name(), vals)
+}
+
+func fprintFunc(p funcPrinter, f *Func) {
+	reachable, live := findlive(f)
+	p.header(f)
+	printed := make([]bool, f.NumValues())
+	for _, b := range f.Blocks {
+		p.startBlock(b, reachable[b.ID])
+
+		if f.scheduled {
+			// Order of Values has been decided - print in that order.
+			for _, v := range b.Values {
+				p.value(v, live[v.ID])
+				printed[v.ID] = true
+			}
+			p.endBlock(b)
+			continue
+		}
+
+		// print phis first since all value cycles contain a phi
+		n := 0
+		for _, v := range b.Values {
+			if v.Op != OpPhi {
+				continue
+			}
+			p.value(v, live[v.ID])
+			printed[v.ID] = true
+			n++
+		}
+
+		// print rest of values in dependency order
+		for n < len(b.Values) {
+			m := n
+		outer:
+			for _, v := range b.Values {
+				if printed[v.ID] {
+					continue
+				}
+				for _, w := range v.Args {
+					// w == nil shouldn't happen, but if it does,
+					// don't panic; we'll get a better diagnosis later.
+					if w != nil && w.Block == b && !printed[w.ID] {
+						continue outer
+					}
+				}
+				p.value(v, live[v.ID])
+				printed[v.ID] = true
+				n++
+			}
+			if m == n {
+				p.startDepCycle()
+				for _, v := range b.Values {
+					if printed[v.ID] {
+						continue
+					}
+					p.value(v, live[v.ID])
+					printed[v.ID] = true
+					n++
+				}
+				p.endDepCycle()
+			}
+		}
+
+		p.endBlock(b)
+	}
+	for _, name := range f.Names {
+		p.named(name, f.NamedValues[name])
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
new file mode 100644
index 0000000..4416fa2
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -0,0 +1,644 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "math"
+
+type branch int
+
+const (
+	unknown = iota
+	positive
+	negative
+)
+
+// relation represents the set of possible relations between
+// pairs of variables (v, w). Without a priori knowledge the
+// mask is lt | eq | gt meaning v can be less than, equal to or
+// greater than w. When the execution path branches on the condition
+// `v op w` the set of relations is updated to exclude any
+// relation not possible due to `v op w` being true (or false).
+//
+// E.g.
+//
+// r := relation(...)
+//
+// if v < w {
+//   newR := r & lt
+// }
+// if v >= w {
+//   newR := r & (eq|gt)
+// }
+// if v != w {
+//   newR := r & (lt|gt)
+// }
+type relation uint
+
+const (
+	lt relation = 1 << iota
+	eq
+	gt
+)
+
+// domain represents the domain of a variable pair in which a set
+// of relations is known.  For example, relations learned for unsigned
+// pairs cannot be transferred to signed pairs because the same bit
+// representation can mean something else.
+type domain uint
+
+const (
+	signed domain = 1 << iota
+	unsigned
+	pointer
+	boolean
+)
+
+type pair struct {
+	v, w *Value // a pair of values, ordered by ID.
+	// v can be nil, to mean the zero value.
+	// for booleans the zero value (v == nil) is false.
+	d domain
+}
+
+// fact is a pair plus a relation for that pair.
+type fact struct {
+	p pair
+	r relation
+}
+
+// a limit records known upper and lower bounds for a value.
+type limit struct {
+	min, max   int64  // min <= value <= max, signed
+	umin, umax uint64 // umin <= value <= umax, unsigned
+}
+
+var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64}
+
+// a limitFact is a limit known for a particular value.
+type limitFact struct {
+	vid   ID
+	limit limit
+}
+
+// factsTable keeps track of relations between pairs of values.
+type factsTable struct {
+	facts map[pair]relation // current known set of relation
+	stack []fact            // previous sets of relations
+
+	// known lower and upper bounds on individual values.
+	limits     map[ID]limit
+	limitStack []limitFact // previous entries
+}
+
+// checkpointFact is an invalid value used for checkpointing
+// and restoring factsTable.
+var checkpointFact = fact{}
+var checkpointBound = limitFact{}
+
+func newFactsTable() *factsTable {
+	ft := &factsTable{}
+	ft.facts = make(map[pair]relation)
+	ft.stack = make([]fact, 4)
+	ft.limits = make(map[ID]limit)
+	ft.limitStack = make([]limitFact, 4)
+	return ft
+}
+
+// get returns the known possible relations between v and w.
+// If v and w are not in the map it returns lt|eq|gt, i.e. any order.
+func (ft *factsTable) get(v, w *Value, d domain) relation {
+	if v.isGenericIntConst() || w.isGenericIntConst() {
+		reversed := false
+		if v.isGenericIntConst() {
+			v, w = w, v
+			reversed = true
+		}
+		r := lt | eq | gt
+		lim, ok := ft.limits[v.ID]
+		if !ok {
+			return r
+		}
+		c := w.AuxInt
+		switch d {
+		case signed:
+			switch {
+			case c < lim.min:
+				r = gt
+			case c > lim.max:
+				r = lt
+			case c == lim.min && c == lim.max:
+				r = eq
+			case c == lim.min:
+				r = gt | eq
+			case c == lim.max:
+				r = lt | eq
+			}
+		case unsigned:
+			// TODO: also use signed data if lim.min >= 0?
+			var uc uint64
+			switch w.Op {
+			case OpConst64:
+				uc = uint64(c)
+			case OpConst32:
+				uc = uint64(uint32(c))
+			case OpConst16:
+				uc = uint64(uint16(c))
+			case OpConst8:
+				uc = uint64(uint8(c))
+			}
+			switch {
+			case uc < lim.umin:
+				r = gt
+			case uc > lim.umax:
+				r = lt
+			case uc == lim.umin && uc == lim.umax:
+				r = eq
+			case uc == lim.umin:
+				r = gt | eq
+			case uc == lim.umax:
+				r = lt | eq
+			}
+		}
+		if reversed {
+			return reverseBits[r]
+		}
+		return r
+	}
+
+	reversed := false
+	if lessByID(w, v) {
+		v, w = w, v
+		reversed = !reversed
+	}
+
+	p := pair{v, w, d}
+	r, ok := ft.facts[p]
+	if !ok {
+		if p.v == p.w {
+			r = eq
+		} else {
+			r = lt | eq | gt
+		}
+	}
+
+	if reversed {
+		return reverseBits[r]
+	}
+	return r
+}
+
+// update updates the set of relations between v and w in domain d
+// restricting it to r.
+func (ft *factsTable) update(v, w *Value, d domain, r relation) {
+	if lessByID(w, v) {
+		v, w = w, v
+		r = reverseBits[r]
+	}
+
+	p := pair{v, w, d}
+	oldR := ft.get(v, w, d)
+	ft.stack = append(ft.stack, fact{p, oldR})
+	ft.facts[p] = oldR & r
+
+	// Extract bounds when comparing against constants
+	if v.isGenericIntConst() {
+		v, w = w, v
+		r = reverseBits[r]
+	}
+	if v != nil && w.isGenericIntConst() {
+		c := w.AuxInt
+		// Note: all the +1/-1 below could overflow/underflow. Either will
+		// still generate correct results, it will just lead to imprecision.
+		// In fact if there is overflow/underflow, the corresponding
+		// code is unreachable because the known range is outside the range
+		// of the value's type.
+		old, ok := ft.limits[v.ID]
+		if !ok {
+			old = noLimit
+		}
+		lim := old
+		// Update lim with the new information we know.
+		switch d {
+		case signed:
+			switch r {
+			case lt:
+				if c-1 < lim.max {
+					lim.max = c - 1
+				}
+			case lt | eq:
+				if c < lim.max {
+					lim.max = c
+				}
+			case gt | eq:
+				if c > lim.min {
+					lim.min = c
+				}
+			case gt:
+				if c+1 > lim.min {
+					lim.min = c + 1
+				}
+			case lt | gt:
+				if c == lim.min {
+					lim.min++
+				}
+				if c == lim.max {
+					lim.max--
+				}
+			case eq:
+				lim.min = c
+				lim.max = c
+			}
+		case unsigned:
+			var uc uint64
+			switch w.Op {
+			case OpConst64:
+				uc = uint64(c)
+			case OpConst32:
+				uc = uint64(uint32(c))
+			case OpConst16:
+				uc = uint64(uint16(c))
+			case OpConst8:
+				uc = uint64(uint8(c))
+			}
+			switch r {
+			case lt:
+				if uc-1 < lim.umax {
+					lim.umax = uc - 1
+				}
+			case lt | eq:
+				if uc < lim.umax {
+					lim.umax = uc
+				}
+			case gt | eq:
+				if uc > lim.umin {
+					lim.umin = uc
+				}
+			case gt:
+				if uc+1 > lim.umin {
+					lim.umin = uc + 1
+				}
+			case lt | gt:
+				if uc == lim.umin {
+					lim.umin++
+				}
+				if uc == lim.umax {
+					lim.umax--
+				}
+			case eq:
+				lim.umin = uc
+				lim.umax = uc
+			}
+		}
+		ft.limitStack = append(ft.limitStack, limitFact{v.ID, old})
+		ft.limits[v.ID] = lim
+	}
+}
+
+// isNonNegative returns true if v is known to be non-negative.
+func (ft *factsTable) isNonNegative(v *Value) bool {
+	if isNonNegative(v) {
+		return true
+	}
+	l, has := ft.limits[v.ID]
+	return has && (l.min >= 0 || l.umax <= math.MaxInt64)
+}
+
+// checkpoint saves the current state of known relations.
+// Called when descending on a branch.
+func (ft *factsTable) checkpoint() {
+	ft.stack = append(ft.stack, checkpointFact)
+	ft.limitStack = append(ft.limitStack, checkpointBound)
+}
+
+// restore restores known relation to the state just
+// before the previous checkpoint.
+// Called when backing up on a branch.
+func (ft *factsTable) restore() {
+	for {
+		old := ft.stack[len(ft.stack)-1]
+		ft.stack = ft.stack[:len(ft.stack)-1]
+		if old == checkpointFact {
+			break
+		}
+		if old.r == lt|eq|gt {
+			delete(ft.facts, old.p)
+		} else {
+			ft.facts[old.p] = old.r
+		}
+	}
+	for {
+		old := ft.limitStack[len(ft.limitStack)-1]
+		ft.limitStack = ft.limitStack[:len(ft.limitStack)-1]
+		if old.vid == 0 { // checkpointBound
+			break
+		}
+		if old.limit == noLimit {
+			delete(ft.limits, old.vid)
+		} else {
+			ft.limits[old.vid] = old.limit
+		}
+	}
+}
+
+func lessByID(v, w *Value) bool {
+	if v == nil && w == nil {
+		// Should not happen, but just in case.
+		return false
+	}
+	if v == nil {
+		return true
+	}
+	return w != nil && v.ID < w.ID
+}
+
+var (
+	reverseBits = [...]relation{0, 4, 2, 6, 1, 5, 3, 7}
+
+	// maps what we learn when the positive branch is taken.
+	// For example:
+	//      OpLess8:   {signed, lt},
+	//	v1 = (OpLess8 v2 v3).
+	// If v1 branch is taken than we learn that the rangeMaks
+	// can be at most lt.
+	domainRelationTable = map[Op]struct {
+		d domain
+		r relation
+	}{
+		OpEq8:   {signed | unsigned, eq},
+		OpEq16:  {signed | unsigned, eq},
+		OpEq32:  {signed | unsigned, eq},
+		OpEq64:  {signed | unsigned, eq},
+		OpEqPtr: {pointer, eq},
+
+		OpNeq8:   {signed | unsigned, lt | gt},
+		OpNeq16:  {signed | unsigned, lt | gt},
+		OpNeq32:  {signed | unsigned, lt | gt},
+		OpNeq64:  {signed | unsigned, lt | gt},
+		OpNeqPtr: {pointer, lt | gt},
+
+		OpLess8:   {signed, lt},
+		OpLess8U:  {unsigned, lt},
+		OpLess16:  {signed, lt},
+		OpLess16U: {unsigned, lt},
+		OpLess32:  {signed, lt},
+		OpLess32U: {unsigned, lt},
+		OpLess64:  {signed, lt},
+		OpLess64U: {unsigned, lt},
+
+		OpLeq8:   {signed, lt | eq},
+		OpLeq8U:  {unsigned, lt | eq},
+		OpLeq16:  {signed, lt | eq},
+		OpLeq16U: {unsigned, lt | eq},
+		OpLeq32:  {signed, lt | eq},
+		OpLeq32U: {unsigned, lt | eq},
+		OpLeq64:  {signed, lt | eq},
+		OpLeq64U: {unsigned, lt | eq},
+
+		OpGeq8:   {signed, eq | gt},
+		OpGeq8U:  {unsigned, eq | gt},
+		OpGeq16:  {signed, eq | gt},
+		OpGeq16U: {unsigned, eq | gt},
+		OpGeq32:  {signed, eq | gt},
+		OpGeq32U: {unsigned, eq | gt},
+		OpGeq64:  {signed, eq | gt},
+		OpGeq64U: {unsigned, eq | gt},
+
+		OpGreater8:   {signed, gt},
+		OpGreater8U:  {unsigned, gt},
+		OpGreater16:  {signed, gt},
+		OpGreater16U: {unsigned, gt},
+		OpGreater32:  {signed, gt},
+		OpGreater32U: {unsigned, gt},
+		OpGreater64:  {signed, gt},
+		OpGreater64U: {unsigned, gt},
+
+		// TODO: OpIsInBounds actually test 0 <= a < b. This means
+		// that the positive branch learns signed/LT and unsigned/LT
+		// but the negative branch only learns unsigned/GE.
+		OpIsInBounds:      {unsigned, lt},
+		OpIsSliceInBounds: {unsigned, lt | eq},
+	}
+)
+
+// prove removes redundant BlockIf controls that can be inferred in a straight line.
+//
+// By far, the most common redundant pair are generated by bounds checking.
+// For example for the code:
+//
+//    a[i] = 4
+//    foo(a[i])
+//
+// The compiler will generate the following code:
+//
+//    if i >= len(a) {
+//        panic("not in bounds")
+//    }
+//    a[i] = 4
+//    if i >= len(a) {
+//        panic("not in bounds")
+//    }
+//    foo(a[i])
+//
+// The second comparison i >= len(a) is clearly redundant because if the
+// else branch of the first comparison is executed, we already know that i < len(a).
+// The code for the second panic can be removed.
+func prove(f *Func) {
+	// current node state
+	type walkState int
+	const (
+		descend walkState = iota
+		simplify
+	)
+	// work maintains the DFS stack.
+	type bp struct {
+		block *Block    // current handled block
+		state walkState // what's to do
+	}
+	work := make([]bp, 0, 256)
+	work = append(work, bp{
+		block: f.Entry,
+		state: descend,
+	})
+
+	ft := newFactsTable()
+
+	// DFS on the dominator tree.
+	for len(work) > 0 {
+		node := work[len(work)-1]
+		work = work[:len(work)-1]
+		parent := f.idom[node.block.ID]
+		branch := getBranch(f.sdom, parent, node.block)
+
+		switch node.state {
+		case descend:
+			if branch != unknown {
+				ft.checkpoint()
+				c := parent.Control
+				updateRestrictions(ft, boolean, nil, c, lt|gt, branch)
+				if tr, has := domainRelationTable[parent.Control.Op]; has {
+					// When we branched from parent we learned a new set of
+					// restrictions. Update the factsTable accordingly.
+					updateRestrictions(ft, tr.d, c.Args[0], c.Args[1], tr.r, branch)
+				}
+			}
+
+			work = append(work, bp{
+				block: node.block,
+				state: simplify,
+			})
+			for s := f.sdom.Child(node.block); s != nil; s = f.sdom.Sibling(s) {
+				work = append(work, bp{
+					block: s,
+					state: descend,
+				})
+			}
+
+		case simplify:
+			succ := simplifyBlock(ft, node.block)
+			if succ != unknown {
+				b := node.block
+				b.Kind = BlockFirst
+				b.SetControl(nil)
+				if succ == negative {
+					b.swapSuccessors()
+				}
+			}
+
+			if branch != unknown {
+				ft.restore()
+			}
+		}
+	}
+}
+
+// getBranch returns the range restrictions added by p
+// when reaching b. p is the immediate dominator of b.
+func getBranch(sdom SparseTree, p *Block, b *Block) branch {
+	if p == nil || p.Kind != BlockIf {
+		return unknown
+	}
+	// If p and p.Succs[0] are dominators it means that every path
+	// from entry to b passes through p and p.Succs[0]. We care that
+	// no path from entry to b passes through p.Succs[1]. If p.Succs[0]
+	// has one predecessor then (apart from the degenerate case),
+	// there is no path from entry that can reach b through p.Succs[1].
+	// TODO: how about p->yes->b->yes, i.e. a loop in yes.
+	if sdom.isAncestorEq(p.Succs[0].b, b) && len(p.Succs[0].b.Preds) == 1 {
+		return positive
+	}
+	if sdom.isAncestorEq(p.Succs[1].b, b) && len(p.Succs[1].b.Preds) == 1 {
+		return negative
+	}
+	return unknown
+}
+
+// updateRestrictions updates restrictions from the immediate
+// dominating block (p) using r. r is adjusted according to the branch taken.
+func updateRestrictions(ft *factsTable, t domain, v, w *Value, r relation, branch branch) {
+	if t == 0 || branch == unknown {
+		// Trivial case: nothing to do, or branch unknown.
+		// Shoult not happen, but just in case.
+		return
+	}
+	if branch == negative {
+		// Negative branch taken, complement the relations.
+		r = (lt | eq | gt) ^ r
+	}
+	for i := domain(1); i <= t; i <<= 1 {
+		if t&i != 0 {
+			ft.update(v, w, i, r)
+		}
+	}
+}
+
+// simplifyBlock simplifies block known the restrictions in ft.
+// Returns which branch must always be taken.
+func simplifyBlock(ft *factsTable, b *Block) branch {
+	if b.Kind != BlockIf {
+		return unknown
+	}
+
+	// First, checks if the condition itself is redundant.
+	m := ft.get(nil, b.Control, boolean)
+	if m == lt|gt {
+		if b.Func.pass.debug > 0 {
+			b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op)
+		}
+		return positive
+	}
+	if m == eq {
+		if b.Func.pass.debug > 0 {
+			b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op)
+		}
+		return negative
+	}
+
+	// Next look check equalities.
+	c := b.Control
+	tr, has := domainRelationTable[c.Op]
+	if !has {
+		return unknown
+	}
+
+	a0, a1 := c.Args[0], c.Args[1]
+	for d := domain(1); d <= tr.d; d <<= 1 {
+		if d&tr.d == 0 {
+			continue
+		}
+
+		// tr.r represents in which case the positive branch is taken.
+		// m represents which cases are possible because of previous relations.
+		// If the set of possible relations m is included in the set of relations
+		// need to take the positive branch (or negative) then that branch will
+		// always be taken.
+		// For shortcut, if m == 0 then this block is dead code.
+		m := ft.get(a0, a1, d)
+		if m != 0 && tr.r&m == m {
+			if b.Func.pass.debug > 0 {
+				b.Func.Config.Warnl(b.Line, "Proved %s", c.Op)
+			}
+			return positive
+		}
+		if m != 0 && ((lt|eq|gt)^tr.r)&m == m {
+			if b.Func.pass.debug > 0 {
+				b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op)
+			}
+			return negative
+		}
+	}
+
+	// HACK: If the first argument of IsInBounds or IsSliceInBounds
+	// is a constant and we already know that constant is smaller (or equal)
+	// to the upper bound than this is proven. Most useful in cases such as:
+	// if len(a) <= 1 { return }
+	// do something with a[1]
+	if (c.Op == OpIsInBounds || c.Op == OpIsSliceInBounds) && ft.isNonNegative(c.Args[0]) {
+		m := ft.get(a0, a1, signed)
+		if m != 0 && tr.r&m == m {
+			if b.Func.pass.debug > 0 {
+				b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op)
+			}
+			return positive
+		}
+	}
+
+	return unknown
+}
+
+// isNonNegative returns true is v is known to be greater or equal to zero.
+func isNonNegative(v *Value) bool {
+	switch v.Op {
+	case OpConst64:
+		return v.AuxInt >= 0
+
+	case OpStringLen, OpSliceLen, OpSliceCap,
+		OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64:
+		return true
+
+	case OpRsh64x64:
+		return isNonNegative(v.Args[0])
+	}
+	return false
+}
diff --git a/src/cmd/compile/internal/ssa/redblack32.go b/src/cmd/compile/internal/ssa/redblack32.go
new file mode 100644
index 0000000..ae1ec35
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/redblack32.go
@@ -0,0 +1,429 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "fmt"
+
+const (
+	rankLeaf rbrank = 1
+	rankZero rbrank = 0
+)
+
+type rbrank int8
+
+// RBTint32 is a red-black tree with data stored at internal nodes,
+// following Tarjan, Data Structures and Network Algorithms,
+// pp 48-52, using explicit rank instead of red and black.
+// Deletion is not yet implemented because it is not yet needed.
+// Extra operations glb, lub, glbEq, lubEq are provided for
+// use in sparse lookup algorithms.
+type RBTint32 struct {
+	root *node32
+	// An extra-clever implementation will have special cases
+	// for small sets, but we are not extra-clever today.
+}
+
+func (t *RBTint32) String() string {
+	if t.root == nil {
+		return "[]"
+	}
+	return "[" + t.root.String() + "]"
+}
+
+func (t *node32) String() string {
+	s := ""
+	if t.left != nil {
+		s = t.left.String() + " "
+	}
+	s = s + fmt.Sprintf("k=%d,d=%v", t.key, t.data)
+	if t.right != nil {
+		s = s + " " + t.right.String()
+	}
+	return s
+}
+
+type node32 struct {
+	// Standard conventions hold for left = smaller, right = larger
+	left, right, parent *node32
+	data                interface{}
+	key                 int32
+	rank                rbrank // From Tarjan pp 48-49:
+	// If x is a node with a parent, then x.rank <= x.parent.rank <= x.rank+1.
+	// If x is a node with a grandparent, then x.rank < x.parent.parent.rank.
+	// If x is an "external [null] node", then x.rank = 0 && x.parent.rank = 1.
+	// Any node with one or more null children should have rank = 1.
+}
+
+// makeNode returns a new leaf node with the given key and nil data.
+func (t *RBTint32) makeNode(key int32) *node32 {
+	return &node32{key: key, rank: rankLeaf}
+}
+
+// IsEmpty reports whether t is empty.
+func (t *RBTint32) IsEmpty() bool {
+	return t.root == nil
+}
+
+// IsSingle reports whether t is a singleton (leaf).
+func (t *RBTint32) IsSingle() bool {
+	return t.root != nil && t.root.isLeaf()
+}
+
+// VisitInOrder applies f to the key and data pairs in t,
+// with keys ordered from smallest to largest.
+func (t *RBTint32) VisitInOrder(f func(int32, interface{})) {
+	if t.root == nil {
+		return
+	}
+	t.root.visitInOrder(f)
+}
+
+func (n *node32) Data() interface{} {
+	if n == nil {
+		return nil
+	}
+	return n.data
+}
+
+func (n *node32) keyAndData() (k int32, d interface{}) {
+	if n == nil {
+		k = 0
+		d = nil
+	} else {
+		k = n.key
+		d = n.data
+	}
+	return
+}
+
+func (n *node32) Rank() rbrank {
+	if n == nil {
+		return 0
+	}
+	return n.rank
+}
+
+// Find returns the data associated with key in the tree, or
+// nil if key is not in the tree.
+func (t *RBTint32) Find(key int32) interface{} {
+	return t.root.find(key).Data()
+}
+
+// Insert adds key to the tree and associates key with data.
+// If key was already in the tree, it updates the associated data.
+// Insert returns the previous data associated with key,
+// or nil if key was not present.
+// Insert panics if data is nil.
+func (t *RBTint32) Insert(key int32, data interface{}) interface{} {
+	if data == nil {
+		panic("Cannot insert nil data into tree")
+	}
+	n := t.root
+	var newroot *node32
+	if n == nil {
+		n = t.makeNode(key)
+		newroot = n
+	} else {
+		newroot, n = n.insert(key, t)
+	}
+	r := n.data
+	n.data = data
+	t.root = newroot
+	return r
+}
+
+// Min returns the minimum element of t and its associated data.
+// If t is empty, then (0, nil) is returned.
+func (t *RBTint32) Min() (k int32, d interface{}) {
+	return t.root.min().keyAndData()
+}
+
+// Max returns the maximum element of t and its associated data.
+// If t is empty, then (0, nil) is returned.
+func (t *RBTint32) Max() (k int32, d interface{}) {
+	return t.root.max().keyAndData()
+}
+
+// Glb returns the greatest-lower-bound-exclusive of x and its associated
+// data.  If x has no glb in the tree, then (0, nil) is returned.
+func (t *RBTint32) Glb(x int32) (k int32, d interface{}) {
+	return t.root.glb(x, false).keyAndData()
+}
+
+// GlbEq returns the greatest-lower-bound-inclusive of x and its associated
+// data.  If x has no glbEQ in the tree, then (0, nil) is returned.
+func (t *RBTint32) GlbEq(x int32) (k int32, d interface{}) {
+	return t.root.glb(x, true).keyAndData()
+}
+
+// Lub returns the least-upper-bound-exclusive of x and its associated
+// data.  If x has no lub in the tree, then (0, nil) is returned.
+func (t *RBTint32) Lub(x int32) (k int32, d interface{}) {
+	return t.root.lub(x, false).keyAndData()
+}
+
+// LubEq returns the least-upper-bound-inclusive of x and its associated
+// data.  If x has no lubEq in the tree, then (0, nil) is returned.
+func (t *RBTint32) LubEq(x int32) (k int32, d interface{}) {
+	return t.root.lub(x, true).keyAndData()
+}
+
+func (t *node32) isLeaf() bool {
+	return t.left == nil && t.right == nil
+}
+
+func (t *node32) visitInOrder(f func(int32, interface{})) {
+	if t.left != nil {
+		t.left.visitInOrder(f)
+	}
+	f(t.key, t.data)
+	if t.right != nil {
+		t.right.visitInOrder(f)
+	}
+}
+
+func (t *node32) maxChildRank() rbrank {
+	if t.left == nil {
+		if t.right == nil {
+			return rankZero
+		}
+		return t.right.rank
+	}
+	if t.right == nil {
+		return t.left.rank
+	}
+	if t.right.rank > t.left.rank {
+		return t.right.rank
+	}
+	return t.left.rank
+}
+
+func (t *node32) minChildRank() rbrank {
+	if t.left == nil || t.right == nil {
+		return rankZero
+	}
+	if t.right.rank < t.left.rank {
+		return t.right.rank
+	}
+	return t.left.rank
+}
+
+func (t *node32) find(key int32) *node32 {
+	for t != nil {
+		if key < t.key {
+			t = t.left
+		} else if key > t.key {
+			t = t.right
+		} else {
+			return t
+		}
+	}
+	return nil
+}
+
+func (t *node32) min() *node32 {
+	if t == nil {
+		return t
+	}
+	for t.left != nil {
+		t = t.left
+	}
+	return t
+}
+
+func (t *node32) max() *node32 {
+	if t == nil {
+		return t
+	}
+	for t.right != nil {
+		t = t.right
+	}
+	return t
+}
+
+func (t *node32) glb(key int32, allow_eq bool) *node32 {
+	var best *node32 = nil
+	for t != nil {
+		if key <= t.key {
+			if key == t.key && allow_eq {
+				return t
+			}
+			// t is too big, glb is to left.
+			t = t.left
+		} else {
+			// t is a lower bound, record it and seek a better one.
+			best = t
+			t = t.right
+		}
+	}
+	return best
+}
+
+func (t *node32) lub(key int32, allow_eq bool) *node32 {
+	var best *node32 = nil
+	for t != nil {
+		if key >= t.key {
+			if key == t.key && allow_eq {
+				return t
+			}
+			// t is too small, lub is to right.
+			t = t.right
+		} else {
+			// t is a upper bound, record it and seek a better one.
+			best = t
+			t = t.left
+		}
+	}
+	return best
+}
+
+func (t *node32) insert(x int32, w *RBTint32) (newroot, newnode *node32) {
+	// defaults
+	newroot = t
+	newnode = t
+	if x == t.key {
+		return
+	}
+	if x < t.key {
+		if t.left == nil {
+			n := w.makeNode(x)
+			n.parent = t
+			t.left = n
+			newnode = n
+			return
+		}
+		var new_l *node32
+		new_l, newnode = t.left.insert(x, w)
+		t.left = new_l
+		new_l.parent = t
+		newrank := 1 + new_l.maxChildRank()
+		if newrank > t.rank {
+			if newrank > 1+t.right.Rank() { // rotations required
+				if new_l.left.Rank() < new_l.right.Rank() {
+					// double rotation
+					t.left = new_l.rightToRoot()
+				}
+				newroot = t.leftToRoot()
+				return
+			} else {
+				t.rank = newrank
+			}
+		}
+	} else { // x > t.key
+		if t.right == nil {
+			n := w.makeNode(x)
+			n.parent = t
+			t.right = n
+			newnode = n
+			return
+		}
+		var new_r *node32
+		new_r, newnode = t.right.insert(x, w)
+		t.right = new_r
+		new_r.parent = t
+		newrank := 1 + new_r.maxChildRank()
+		if newrank > t.rank {
+			if newrank > 1+t.left.Rank() { // rotations required
+				if new_r.right.Rank() < new_r.left.Rank() {
+					// double rotation
+					t.right = new_r.leftToRoot()
+				}
+				newroot = t.rightToRoot()
+				return
+			} else {
+				t.rank = newrank
+			}
+		}
+	}
+	return
+}
+
+func (t *node32) rightToRoot() *node32 {
+	//    this
+	// left  right
+	//      rl   rr
+	//
+	// becomes
+	//
+	//       right
+	//    this   rr
+	// left  rl
+	//
+	right := t.right
+	rl := right.left
+	right.parent = t.parent
+	right.left = t
+	t.parent = right
+	// parent's child ptr fixed in caller
+	t.right = rl
+	if rl != nil {
+		rl.parent = t
+	}
+	return right
+}
+
+func (t *node32) leftToRoot() *node32 {
+	//     this
+	//  left  right
+	// ll  lr
+	//
+	// becomes
+	//
+	//    left
+	//   ll  this
+	//      lr  right
+	//
+	left := t.left
+	lr := left.right
+	left.parent = t.parent
+	left.right = t
+	t.parent = left
+	// parent's child ptr fixed in caller
+	t.left = lr
+	if lr != nil {
+		lr.parent = t
+	}
+	return left
+}
+
+// next returns the successor of t in a left-to-right
+// walk of the tree in which t is embedded.
+func (t *node32) next() *node32 {
+	// If there is a right child, it is to the right
+	r := t.right
+	if r != nil {
+		return r.min()
+	}
+	// if t is p.left, then p, else repeat.
+	p := t.parent
+	for p != nil {
+		if p.left == t {
+			return p
+		}
+		t = p
+		p = t.parent
+	}
+	return nil
+}
+
+// prev returns the predecessor of t in a left-to-right
+// walk of the tree in which t is embedded.
+func (t *node32) prev() *node32 {
+	// If there is a left child, it is to the left
+	l := t.left
+	if l != nil {
+		return l.max()
+	}
+	// if t is p.right, then p, else repeat.
+	p := t.parent
+	for p != nil {
+		if p.right == t {
+			return p
+		}
+		t = p
+		p = t.parent
+	}
+	return nil
+}
diff --git a/src/cmd/compile/internal/ssa/redblack32_test.go b/src/cmd/compile/internal/ssa/redblack32_test.go
new file mode 100644
index 0000000..6d72a3e
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/redblack32_test.go
@@ -0,0 +1,276 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"fmt"
+	"testing"
+)
+
+type sstring string
+
+func (s sstring) String() string {
+	return string(s)
+}
+
+// wellFormed ensures that a red-black tree meets
+// all of its invariants and returns a string identifying
+// the first problem encountered. If there is no problem
+// then the returned string is empty. The size is also
+// returned to allow comparison of calculated tree size
+// with expected.
+func (t *RBTint32) wellFormed() (s string, i int) {
+	if t.root == nil {
+		s = ""
+		i = 0
+		return
+	}
+	return t.root.wellFormedSubtree(nil, -0x80000000, 0x7fffffff)
+}
+
+// wellFormedSubtree ensures that a red-black subtree meets
+// all of its invariants and returns a string identifying
+// the first problem encountered. If there is no problem
+// then the returned string is empty. The size is also
+// returned to allow comparison of calculated tree size
+// with expected.
+func (t *node32) wellFormedSubtree(parent *node32, min, max int32) (s string, i int) {
+	i = -1 // initialize to a failing value
+	s = "" // s is the reason for failure; empty means okay.
+
+	if t.parent != parent {
+		s = "t.parent != parent"
+		return
+	}
+
+	if min >= t.key {
+		s = "min >= t.key"
+		return
+	}
+
+	if max <= t.key {
+		s = "max <= t.key"
+		return
+	}
+
+	l := t.left
+	r := t.right
+	if l == nil && r == nil {
+		if t.rank != rankLeaf {
+			s = "leaf rank wrong"
+			return
+		}
+	}
+	if l != nil {
+		if t.rank < l.rank {
+			s = "t.rank < l.rank"
+		} else if t.rank > 1+l.rank {
+			s = "t.rank > 1+l.rank"
+		} else if t.rank <= l.maxChildRank() {
+			s = "t.rank <= l.maxChildRank()"
+		} else if t.key <= l.key {
+			s = "t.key <= l.key"
+		}
+		if s != "" {
+			return
+		}
+	} else {
+		if t.rank != 1 {
+			s = "t w/ left nil has rank != 1"
+			return
+		}
+	}
+	if r != nil {
+		if t.rank < r.rank {
+			s = "t.rank < r.rank"
+		} else if t.rank > 1+r.rank {
+			s = "t.rank > 1+r.rank"
+		} else if t.rank <= r.maxChildRank() {
+			s = "t.rank <= r.maxChildRank()"
+		} else if t.key >= r.key {
+			s = "t.key >= r.key"
+		}
+		if s != "" {
+			return
+		}
+	} else {
+		if t.rank != 1 {
+			s = "t w/ right nil has rank != 1"
+			return
+		}
+	}
+	ii := 1
+	if l != nil {
+		res, il := l.wellFormedSubtree(t, min, t.key)
+		if res != "" {
+			s = "L." + res
+			return
+		}
+		ii += il
+	}
+	if r != nil {
+		res, ir := r.wellFormedSubtree(t, t.key, max)
+		if res != "" {
+			s = "R." + res
+			return
+		}
+		ii += ir
+	}
+	i = ii
+	return
+}
+
+func (t *RBTint32) DebugString() string {
+	if t.root == nil {
+		return ""
+	}
+	return t.root.DebugString()
+}
+
+// DebugString prints the tree with nested information
+// to allow an eyeball check on the tree balance.
+func (t *node32) DebugString() string {
+	s := ""
+	if t.left != nil {
+		s = s + "["
+		s = s + t.left.DebugString()
+		s = s + "]"
+	}
+	s = s + fmt.Sprintf("%v=%v:%d", t.key, t.data, t.rank)
+	if t.right != nil {
+		s = s + "["
+		s = s + t.right.DebugString()
+		s = s + "]"
+	}
+	return s
+}
+
+func allRBT32Ops(te *testing.T, x []int32) {
+	t := &RBTint32{}
+	for i, d := range x {
+		x[i] = d + d // Double everything for glb/lub testing
+	}
+
+	// fmt.Printf("Inserting double of %v", x)
+	k := 0
+	min := int32(0x7fffffff)
+	max := int32(-0x80000000)
+	for _, d := range x {
+		if d < min {
+			min = d
+		}
+
+		if d > max {
+			max = d
+		}
+
+		t.Insert(d, sstring(fmt.Sprintf("%v", d)))
+		k++
+		s, i := t.wellFormed()
+		if i != k {
+			te.Errorf("Wrong tree size %v, expected %v for %v", i, k, t.DebugString())
+		}
+		if s != "" {
+			te.Errorf("Tree consistency problem at %v", s)
+			return
+		} else {
+			// fmt.Printf("%s", t.DebugString())
+		}
+	}
+
+	oops := false
+
+	for _, d := range x {
+		s := fmt.Sprintf("%v", d)
+		f := t.Find(d)
+
+		// data
+		if s != fmt.Sprintf("%v", f) {
+			te.Errorf("s(%v) != f(%v)", s, f)
+			oops = true
+		}
+	}
+
+	if !oops {
+		for _, d := range x {
+			s := fmt.Sprintf("%v", d)
+
+			kg, g := t.Glb(d + 1)
+			kge, ge := t.GlbEq(d)
+			kl, l := t.Lub(d - 1)
+			kle, le := t.LubEq(d)
+
+			// keys
+			if d != kg {
+				te.Errorf("d(%v) != kg(%v)", d, kg)
+			}
+			if d != kl {
+				te.Errorf("d(%v) != kl(%v)", d, kl)
+			}
+			if d != kge {
+				te.Errorf("d(%v) != kge(%v)", d, kge)
+			}
+			if d != kle {
+				te.Errorf("d(%v) != kle(%v)", d, kle)
+			}
+			// data
+			if s != fmt.Sprintf("%v", g) {
+				te.Errorf("s(%v) != g(%v)", s, g)
+			}
+			if s != fmt.Sprintf("%v", l) {
+				te.Errorf("s(%v) != l(%v)", s, l)
+			}
+			if s != fmt.Sprintf("%v", ge) {
+				te.Errorf("s(%v) != ge(%v)", s, ge)
+			}
+			if s != fmt.Sprintf("%v", le) {
+				te.Errorf("s(%v) != le(%v)", s, le)
+			}
+		}
+
+		for _, d := range x {
+			s := fmt.Sprintf("%v", d)
+			kge, ge := t.GlbEq(d + 1)
+			kle, le := t.LubEq(d - 1)
+			if d != kge {
+				te.Errorf("d(%v) != kge(%v)", d, kge)
+			}
+			if d != kle {
+				te.Errorf("d(%v) != kle(%v)", d, kle)
+			}
+			if s != fmt.Sprintf("%v", ge) {
+				te.Errorf("s(%v) != ge(%v)", s, ge)
+			}
+			if s != fmt.Sprintf("%v", le) {
+				te.Errorf("s(%v) != le(%v)", s, le)
+			}
+		}
+
+		kg, g := t.Glb(min)
+		kge, ge := t.GlbEq(min - 1)
+		kl, l := t.Lub(max)
+		kle, le := t.LubEq(max + 1)
+		fmin := t.Find(min - 1)
+		fmax := t.Find(min + 11)
+
+		if kg != 0 || kge != 0 || kl != 0 || kle != 0 {
+			te.Errorf("Got non-zero-key for missing query")
+		}
+
+		if g != nil || ge != nil || l != nil || le != nil || fmin != nil || fmax != nil {
+			te.Errorf("Got non-error-data for missing query")
+		}
+
+	}
+}
+
+func TestAllRBTreeOps(t *testing.T) {
+	allRBT32Ops(t, []int32{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})
+	allRBT32Ops(t, []int32{22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 3, 2, 1, 25, 24, 23, 12, 11, 10, 9, 8, 7, 6, 5, 4})
+	allRBT32Ops(t, []int32{25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1})
+	allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24})
+	allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2})
+	allRBT32Ops(t, []int32{24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25})
+}
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
new file mode 100644
index 0000000..1eecd49
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/regalloc.go
@@ -0,0 +1,2360 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Register allocation.
+//
+// We use a version of a linear scan register allocator. We treat the
+// whole function as a single long basic block and run through
+// it using a greedy register allocator. Then all merge edges
+// (those targeting a block with len(Preds)>1) are processed to
+// shuffle data into the place that the target of the edge expects.
+//
+// The greedy allocator moves values into registers just before they
+// are used, spills registers only when necessary, and spills the
+// value whose next use is farthest in the future.
+//
+// The register allocator requires that a block is not scheduled until
+// at least one of its predecessors have been scheduled. The most recent
+// such predecessor provides the starting register state for a block.
+//
+// It also requires that there are no critical edges (critical =
+// comes from a block with >1 successor and goes to a block with >1
+// predecessor).  This makes it easy to add fixup code on merge edges -
+// the source of a merge edge has only one successor, so we can add
+// fixup code to the end of that block.
+
+// Spilling
+//
+// For every value, we generate a spill immediately after the value itself.
+//     x = Op y z    : AX
+//     x2 = StoreReg x
+// While AX still holds x, any uses of x will use that value. When AX is needed
+// for another value, we simply reuse AX.  Spill code has already been generated
+// so there is no code generated at "spill" time. When x is referenced
+// subsequently, we issue a load to restore x to a register using x2 as
+//  its argument:
+//    x3 = Restore x2 : CX
+// x3 can then be used wherever x is referenced again.
+// If the spill (x2) is never used, it will be removed at the end of regalloc.
+//
+// Phi values are special, as always. We define two kinds of phis, those
+// where the merge happens in a register (a "register" phi) and those where
+// the merge happens in a stack location (a "stack" phi).
+//
+// A register phi must have the phi and all of its inputs allocated to the
+// same register. Register phis are spilled similarly to regular ops:
+//     b1: y = ... : AX        b2: z = ... : AX
+//         goto b3                 goto b3
+//     b3: x = phi(y, z) : AX
+//         x2 = StoreReg x
+//
+// A stack phi must have the phi and all of its inputs allocated to the same
+// stack location. Stack phis start out life already spilled - each phi
+// input must be a store (using StoreReg) at the end of the corresponding
+// predecessor block.
+//     b1: y = ... : AX        b2: z = ... : BX
+//         y2 = StoreReg y         z2 = StoreReg z
+//         goto b3                 goto b3
+//     b3: x = phi(y2, z2)
+// The stack allocator knows that StoreReg args of stack-allocated phis
+// must be allocated to the same stack slot as the phi that uses them.
+// x is now a spilled value and a restore must appear before its first use.
+
+// TODO
+
+// Use an affinity graph to mark two values which should use the
+// same register. This affinity graph will be used to prefer certain
+// registers for allocation. This affinity helps eliminate moves that
+// are required for phi implementations and helps generate allocations
+// for 2-register architectures.
+
+// Note: regalloc generates a not-quite-SSA output. If we have:
+//
+//             b1: x = ... : AX
+//                 x2 = StoreReg x
+//                 ... AX gets reused for something else ...
+//                 if ... goto b3 else b4
+//
+//   b3: x3 = LoadReg x2 : BX       b4: x4 = LoadReg x2 : CX
+//       ... use x3 ...                 ... use x4 ...
+//
+//             b2: ... use x3 ...
+//
+// If b3 is the primary predecessor of b2, then we use x3 in b2 and
+// add a x4:CX->BX copy at the end of b4.
+// But the definition of x3 doesn't dominate b2.  We should really
+// insert a dummy phi at the start of b2 (x5=phi(x3,x4):BX) to keep
+// SSA form. For now, we ignore this problem as remaining in strict
+// SSA form isn't needed after regalloc. We'll just leave the use
+// of x3 not dominated by the definition of x3, and the CX->BX copy
+// will have no use (so don't run deadcode after regalloc!).
+// TODO: maybe we should introduce these extra phis?
+
+// Additional not-quite-SSA output occurs when spills are sunk out
+// of loops to the targets of exit edges from the loop.  Before sinking,
+// there is one spill site (one StoreReg) targeting stack slot X, after
+// sinking there may be multiple spill sites targeting stack slot X,
+// with no phi functions at any join points reachable by the multiple
+// spill sites.  In addition, uses of the spill from copies of the original
+// will not name the copy in their reference; instead they will name
+// the original, though both will have the same spill location.  The
+// first sunk spill will be the original, but moved, to an exit block,
+// thus ensuring that there is a definition somewhere corresponding to
+// the original spill's uses.
+
+package ssa
+
+import (
+	"fmt"
+	"unsafe"
+)
+
+const (
+	moveSpills = iota
+	logSpills
+	regDebug
+	stackDebug
+)
+
+// distance is a measure of how far into the future values are used.
+// distance is measured in units of instructions.
+const (
+	likelyDistance   = 1
+	normalDistance   = 10
+	unlikelyDistance = 100
+)
+
+// regalloc performs register allocation on f. It sets f.RegAlloc
+// to the resulting allocation.
+func regalloc(f *Func) {
+	var s regAllocState
+	s.init(f)
+	s.regalloc(f)
+}
+
+type register uint8
+
+const noRegister register = 255
+
+type regMask uint64
+
+func (m regMask) String() string {
+	s := ""
+	for r := register(0); m != 0; r++ {
+		if m>>r&1 == 0 {
+			continue
+		}
+		m &^= regMask(1) << r
+		if s != "" {
+			s += " "
+		}
+		s += fmt.Sprintf("r%d", r)
+	}
+	return s
+}
+
+// countRegs returns the number of set bits in the register mask.
+func countRegs(r regMask) int {
+	n := 0
+	for r != 0 {
+		n += int(r & 1)
+		r >>= 1
+	}
+	return n
+}
+
+// pickReg picks an arbitrary register from the register mask.
+func pickReg(r regMask) register {
+	// pick the lowest one
+	if r == 0 {
+		panic("can't pick a register from an empty set")
+	}
+	for i := register(0); ; i++ {
+		if r&1 != 0 {
+			return i
+		}
+		r >>= 1
+	}
+}
+
+type use struct {
+	dist int32 // distance from start of the block to a use of a value
+	next *use  // linked list of uses of a value in nondecreasing dist order
+}
+
+type valState struct {
+	regs              regMask // the set of registers holding a Value (usually just one)
+	uses              *use    // list of uses in this block
+	spill             *Value  // spilled copy of the Value
+	spillUsed         bool
+	spillUsedShuffle  bool // true if used in shuffling, after ordinary uses
+	needReg           bool // cached value of !v.Type.IsMemory() && !v.Type.IsVoid() && !.v.Type.IsFlags()
+	rematerializeable bool // cached value of v.rematerializeable()
+}
+
+type regState struct {
+	v *Value // Original (preregalloc) Value stored in this register.
+	c *Value // A Value equal to v which is currently in a register.  Might be v or a copy of it.
+	// If a register is unused, v==c==nil
+}
+
+type regAllocState struct {
+	f *Func
+
+	registers   []Register
+	numRegs     register
+	SPReg       register
+	SBReg       register
+	allocatable regMask
+
+	// for each block, its primary predecessor.
+	// A predecessor of b is primary if it is the closest
+	// predecessor that appears before b in the layout order.
+	// We record the index in the Preds list where the primary predecessor sits.
+	primary []int32
+
+	// live values at the end of each block.  live[b.ID] is a list of value IDs
+	// which are live at the end of b, together with a count of how many instructions
+	// forward to the next use.
+	live [][]liveInfo
+	// desired register assignments at the end of each block.
+	// Note that this is a static map computed before allocation occurs. Dynamic
+	// register desires (from partially completed allocations) will trump
+	// this information.
+	desired []desiredState
+
+	// current state of each (preregalloc) Value
+	values []valState
+
+	// For each Value, map from its value ID back to the
+	// preregalloc Value it was derived from.
+	orig []*Value
+
+	// current state of each register
+	regs []regState
+
+	// registers that contain values which can't be kicked out
+	nospill regMask
+
+	// mask of registers currently in use
+	used regMask
+
+	// current block we're working on
+	curBlock *Block
+
+	// cache of use records
+	freeUseRecords *use
+
+	// endRegs[blockid] is the register state at the end of each block.
+	// encoded as a set of endReg records.
+	endRegs [][]endReg
+
+	// startRegs[blockid] is the register state at the start of merge blocks.
+	// saved state does not include the state of phi ops in the block.
+	startRegs [][]startReg
+
+	// spillLive[blockid] is the set of live spills at the end of each block
+	spillLive [][]ID
+
+	loopnest *loopnest
+}
+
+type spillToSink struct {
+	spill *Value // Spill instruction to move (a StoreReg)
+	dests int32  // Bitmask indicating exit blocks from loop in which spill/val is defined. 1<<i set means val is live into loop.exitBlocks[i]
+}
+
+func (sts *spillToSink) spilledValue() *Value {
+	return sts.spill.Args[0]
+}
+
+type endReg struct {
+	r register
+	v *Value // pre-regalloc value held in this register (TODO: can we use ID here?)
+	c *Value // cached version of the value
+}
+
+type startReg struct {
+	r   register
+	vid ID // pre-regalloc value needed in this register
+}
+
+// freeReg frees up register r. Any current user of r is kicked out.
+func (s *regAllocState) freeReg(r register) {
+	v := s.regs[r].v
+	if v == nil {
+		s.f.Fatalf("tried to free an already free register %d\n", r)
+	}
+
+	// Mark r as unused.
+	if s.f.pass.debug > regDebug {
+		fmt.Printf("freeReg %s (dump %s/%s)\n", s.registers[r].Name(), v, s.regs[r].c)
+	}
+	s.regs[r] = regState{}
+	s.values[v.ID].regs &^= regMask(1) << r
+	s.used &^= regMask(1) << r
+}
+
+// freeRegs frees up all registers listed in m.
+func (s *regAllocState) freeRegs(m regMask) {
+	for m&s.used != 0 {
+		s.freeReg(pickReg(m & s.used))
+	}
+}
+
+// setOrig records that c's original value is the same as
+// v's original value.
+func (s *regAllocState) setOrig(c *Value, v *Value) {
+	for int(c.ID) >= len(s.orig) {
+		s.orig = append(s.orig, nil)
+	}
+	if s.orig[c.ID] != nil {
+		s.f.Fatalf("orig value set twice %s %s", c, v)
+	}
+	s.orig[c.ID] = s.orig[v.ID]
+}
+
+// assignReg assigns register r to hold c, a copy of v.
+// r must be unused.
+func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
+	if s.f.pass.debug > regDebug {
+		fmt.Printf("assignReg %s %s/%s\n", s.registers[r].Name(), v, c)
+	}
+	if s.regs[r].v != nil {
+		s.f.Fatalf("tried to assign register %d to %s/%s but it is already used by %s", r, v, c, s.regs[r].v)
+	}
+
+	// Update state.
+	s.regs[r] = regState{v, c}
+	s.values[v.ID].regs |= regMask(1) << r
+	s.used |= regMask(1) << r
+	s.f.setHome(c, &s.registers[r])
+}
+
+// allocReg chooses a register for v from the set of registers in mask.
+// If there is no unused register, a Value will be kicked out of
+// a register to make room.
+func (s *regAllocState) allocReg(v *Value, mask regMask) register {
+	mask &= s.allocatable
+	mask &^= s.nospill
+	if mask == 0 {
+		s.f.Fatalf("no register available")
+	}
+
+	// Pick an unused register if one is available.
+	if mask&^s.used != 0 {
+		return pickReg(mask &^ s.used)
+	}
+
+	// Pick a value to spill. Spill the value with the
+	// farthest-in-the-future use.
+	// TODO: Prefer registers with already spilled Values?
+	// TODO: Modify preference using affinity graph.
+	// TODO: if a single value is in multiple registers, spill one of them
+	// before spilling a value in just a single register.
+
+	// Find a register to spill. We spill the register containing the value
+	// whose next use is as far in the future as possible.
+	// https://en.wikipedia.org/wiki/Page_replacement_algorithm#The_theoretically_optimal_page_replacement_algorithm
+	var r register
+	maxuse := int32(-1)
+	for t := register(0); t < s.numRegs; t++ {
+		if mask>>t&1 == 0 {
+			continue
+		}
+		v := s.regs[t].v
+		if n := s.values[v.ID].uses.dist; n > maxuse {
+			// v's next use is farther in the future than any value
+			// we've seen so far. A new best spill candidate.
+			r = t
+			maxuse = n
+		}
+	}
+	if maxuse == -1 {
+		s.f.Unimplementedf("couldn't find register to spill")
+	}
+	s.freeReg(r)
+	return r
+}
+
+// allocValToReg allocates v to a register selected from regMask and
+// returns the register copy of v. Any previous user is kicked out and spilled
+// (if necessary). Load code is added at the current pc. If nospill is set the
+// allocated register is marked nospill so the assignment cannot be
+// undone until the caller allows it by clearing nospill. Returns a
+// *Value which is either v or a copy of v allocated to the chosen register.
+func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line int32) *Value {
+	vi := &s.values[v.ID]
+
+	// Check if v is already in a requested register.
+	if mask&vi.regs != 0 {
+		r := pickReg(mask & vi.regs)
+		if s.regs[r].v != v || s.regs[r].c == nil {
+			panic("bad register state")
+		}
+		if nospill {
+			s.nospill |= regMask(1) << r
+		}
+		return s.regs[r].c
+	}
+
+	// Allocate a register.
+	r := s.allocReg(v, mask)
+
+	// Allocate v to the new register.
+	var c *Value
+	if vi.regs != 0 {
+		// Copy from a register that v is already in.
+		r2 := pickReg(vi.regs)
+		if s.regs[r2].v != v {
+			panic("bad register state")
+		}
+		c = s.curBlock.NewValue1(line, OpCopy, v.Type, s.regs[r2].c)
+	} else if v.rematerializeable() {
+		// Rematerialize instead of loading from the spill location.
+		c = v.copyInto(s.curBlock)
+	} else {
+		switch {
+		// Load v from its spill location.
+		case vi.spill != nil:
+			if s.f.pass.debug > logSpills {
+				s.f.Config.Warnl(vi.spill.Line, "load spill for %v from %v", v, vi.spill)
+			}
+			c = s.curBlock.NewValue1(line, OpLoadReg, v.Type, vi.spill)
+			vi.spillUsed = true
+		default:
+			s.f.Fatalf("attempt to load unspilled value %v", v.LongString())
+		}
+	}
+	s.setOrig(c, v)
+	s.assignReg(r, v, c)
+	if nospill {
+		s.nospill |= regMask(1) << r
+	}
+	return c
+}
+
+func (s *regAllocState) init(f *Func) {
+	s.f = f
+	s.registers = f.Config.registers
+	s.numRegs = register(len(s.registers))
+	if s.numRegs > noRegister || s.numRegs > register(unsafe.Sizeof(regMask(0))*8) {
+		panic("too many registers")
+	}
+	for r := register(0); r < s.numRegs; r++ {
+		if s.registers[r].Name() == "SP" {
+			s.SPReg = r
+		}
+		if s.registers[r].Name() == "SB" {
+			s.SBReg = r
+		}
+	}
+
+	// Figure out which registers we're allowed to use.
+	s.allocatable = regMask(1)<<s.numRegs - 1
+	s.allocatable &^= 1 << s.SPReg
+	s.allocatable &^= 1 << s.SBReg
+	if s.f.Config.ctxt.Framepointer_enabled {
+		s.allocatable &^= 1 << 5 // BP
+	}
+	if s.f.Config.ctxt.Flag_dynlink {
+		s.allocatable &^= 1 << 15 // R15
+	}
+
+	s.regs = make([]regState, s.numRegs)
+	s.values = make([]valState, f.NumValues())
+	s.orig = make([]*Value, f.NumValues())
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() {
+				s.values[v.ID].needReg = true
+				s.values[v.ID].rematerializeable = v.rematerializeable()
+				s.orig[v.ID] = v
+			}
+		}
+	}
+	s.computeLive()
+
+	// Compute block order. This array allows us to distinguish forward edges
+	// from backward edges and compute how far they go.
+	blockOrder := make([]int32, f.NumBlocks())
+	for i, b := range f.Blocks {
+		blockOrder[b.ID] = int32(i)
+	}
+
+	// Compute primary predecessors.
+	s.primary = make([]int32, f.NumBlocks())
+	for _, b := range f.Blocks {
+		best := -1
+		for i, e := range b.Preds {
+			p := e.b
+			if blockOrder[p.ID] >= blockOrder[b.ID] {
+				continue // backward edge
+			}
+			if best == -1 || blockOrder[p.ID] > blockOrder[b.Preds[best].b.ID] {
+				best = i
+			}
+		}
+		s.primary[b.ID] = int32(best)
+	}
+
+	s.endRegs = make([][]endReg, f.NumBlocks())
+	s.startRegs = make([][]startReg, f.NumBlocks())
+	s.spillLive = make([][]ID, f.NumBlocks())
+}
+
+// Adds a use record for id at distance dist from the start of the block.
+// All calls to addUse must happen with nonincreasing dist.
+func (s *regAllocState) addUse(id ID, dist int32) {
+	r := s.freeUseRecords
+	if r != nil {
+		s.freeUseRecords = r.next
+	} else {
+		r = &use{}
+	}
+	r.dist = dist
+	r.next = s.values[id].uses
+	s.values[id].uses = r
+	if r.next != nil && dist > r.next.dist {
+		s.f.Fatalf("uses added in wrong order")
+	}
+}
+
+// advanceUses advances the uses of v's args from the state before v to the state after v.
+// Any values which have no more uses are deallocated from registers.
+func (s *regAllocState) advanceUses(v *Value) {
+	for _, a := range v.Args {
+		if !s.values[a.ID].needReg {
+			continue
+		}
+		ai := &s.values[a.ID]
+		r := ai.uses
+		ai.uses = r.next
+		if r.next == nil {
+			// Value is dead, free all registers that hold it.
+			s.freeRegs(ai.regs)
+		}
+		r.next = s.freeUseRecords
+		s.freeUseRecords = r
+	}
+}
+
+// liveAfterCurrentInstruction reports whether v is live after
+// the current instruction is completed.  v must be used by the
+// current instruction.
+func (s *regAllocState) liveAfterCurrentInstruction(v *Value) bool {
+	u := s.values[v.ID].uses
+	d := u.dist
+	for u != nil && u.dist == d {
+		u = u.next
+	}
+	return u != nil && u.dist > d
+}
+
+// Sets the state of the registers to that encoded in regs.
+func (s *regAllocState) setState(regs []endReg) {
+	s.freeRegs(s.used)
+	for _, x := range regs {
+		s.assignReg(x.r, x.v, x.c)
+	}
+}
+
+// compatRegs returns the set of registers which can store a type t.
+func (s *regAllocState) compatRegs(t Type) regMask {
+	var m regMask
+	if t.IsFloat() || t == TypeInt128 {
+		m = 0xffff << 16 // X0-X15
+	} else {
+		m = 0xffff << 0 // AX-R15
+	}
+	return m & s.allocatable
+}
+
+// loopForBlock returns the loop containing block b,
+// provided that the loop is "interesting" for purposes
+// of improving register allocation (= is inner, and does
+// not contain a call)
+func (s *regAllocState) loopForBlock(b *Block) *loop {
+	loop := s.loopnest.b2l[b.ID]
+
+	// Minor for-the-time-being optimization: nothing happens
+	// unless a loop is both inner and call-free, therefore
+	// don't bother with other loops.
+	if loop != nil && (loop.containsCall || !loop.isInner) {
+		loop = nil
+	}
+	return loop
+}
+
+func (s *regAllocState) regalloc(f *Func) {
+	liveSet := f.newSparseSet(f.NumValues())
+	defer f.retSparseSet(liveSet)
+	var oldSched []*Value
+	var phis []*Value
+	var phiRegs []register
+	var args []*Value
+
+	// statistics
+	var nSpills int               // # of spills remaining
+	var nSpillsInner int          // # of spills remaining in inner loops
+	var nSpillsSunk int           // # of sunk spills remaining
+	var nSpillsChanged int        // # of sunk spills lost because of register use change
+	var nSpillsSunkUnused int     // # of spills not sunk because they were removed completely
+	var nSpillsNotSunkLateUse int // # of spills not sunk because of very late use (in shuffle)
+
+	// Data structure used for computing desired registers.
+	var desired desiredState
+
+	// Desired registers for inputs & outputs for each instruction in the block.
+	type dentry struct {
+		out [4]register    // desired output registers
+		in  [3][4]register // desired input registers (for inputs 0,1, and 2)
+	}
+	var dinfo []dentry
+
+	if f.Entry != f.Blocks[0] {
+		f.Fatalf("entry block must be first")
+	}
+
+	// Get loop nest so that spills in inner loops can be
+	// tracked.  When the last block of a loop is processed,
+	// attempt to move spills out of the loop.
+	s.loopnest.findExits()
+
+	// Spills are moved from one block's slice of values to another's.
+	// This confuses register allocation if it occurs before it is
+	// complete, so candidates are recorded, then rechecked and
+	// moved after all allocation (register and stack) is complete.
+	// Because movement is only within a stack slot's lifetime, it
+	// is safe to do this.
+	var toSink []spillToSink
+	// Will be used to figure out live inputs to exit blocks of inner loops.
+	entryCandidates := newSparseMap(f.NumValues())
+
+	for _, b := range f.Blocks {
+		s.curBlock = b
+		loop := s.loopForBlock(b)
+
+		// Initialize liveSet and uses fields for this block.
+		// Walk backwards through the block doing liveness analysis.
+		liveSet.clear()
+		d := int32(len(b.Values))
+		if b.Kind == BlockCall || b.Kind == BlockDefer {
+			d += unlikelyDistance
+		}
+		for _, e := range s.live[b.ID] {
+			s.addUse(e.ID, d+e.dist) // pseudo-uses from beyond end of block
+			liveSet.add(e.ID)
+		}
+		if v := b.Control; v != nil && s.values[v.ID].needReg {
+			s.addUse(v.ID, int32(len(b.Values))) // psuedo-use by control value
+			liveSet.add(v.ID)
+		}
+		for i := len(b.Values) - 1; i >= 0; i-- {
+			v := b.Values[i]
+			liveSet.remove(v.ID)
+			if v.Op == OpPhi {
+				// Remove v from the live set, but don't add
+				// any inputs. This is the state the len(b.Preds)>1
+				// case below desires; it wants to process phis specially.
+				continue
+			}
+			for _, a := range v.Args {
+				if !s.values[a.ID].needReg {
+					continue
+				}
+				s.addUse(a.ID, int32(i))
+				liveSet.add(a.ID)
+			}
+		}
+		if s.f.pass.debug > regDebug {
+			fmt.Printf("uses for %s:%s\n", s.f.Name, b)
+			for i := range s.values {
+				vi := &s.values[i]
+				u := vi.uses
+				if u == nil {
+					continue
+				}
+				fmt.Printf("  v%d:", i)
+				for u != nil {
+					fmt.Printf(" %d", u.dist)
+					u = u.next
+				}
+				fmt.Println()
+			}
+		}
+
+		// Make a copy of the block schedule so we can generate a new one in place.
+		// We make a separate copy for phis and regular values.
+		nphi := 0
+		for _, v := range b.Values {
+			if v.Op != OpPhi {
+				break
+			}
+			nphi++
+		}
+		phis = append(phis[:0], b.Values[:nphi]...)
+		oldSched = append(oldSched[:0], b.Values[nphi:]...)
+		b.Values = b.Values[:0]
+
+		// Initialize start state of block.
+		if b == f.Entry {
+			// Regalloc state is empty to start.
+			if nphi > 0 {
+				f.Fatalf("phis in entry block")
+			}
+		} else if len(b.Preds) == 1 {
+			// Start regalloc state with the end state of the previous block.
+			s.setState(s.endRegs[b.Preds[0].b.ID])
+			if nphi > 0 {
+				f.Fatalf("phis in single-predecessor block")
+			}
+			// Drop any values which are no longer live.
+			// This may happen because at the end of p, a value may be
+			// live but only used by some other successor of p.
+			for r := register(0); r < s.numRegs; r++ {
+				v := s.regs[r].v
+				if v != nil && !liveSet.contains(v.ID) {
+					s.freeReg(r)
+				}
+			}
+		} else {
+			// This is the complicated case. We have more than one predecessor,
+			// which means we may have Phi ops.
+
+			// Copy phi ops into new schedule.
+			b.Values = append(b.Values, phis...)
+
+			// Start with the final register state of the primary predecessor
+			idx := s.primary[b.ID]
+			if idx < 0 {
+				f.Fatalf("block with no primary predecessor %s", b)
+			}
+			p := b.Preds[idx].b
+			s.setState(s.endRegs[p.ID])
+
+			if s.f.pass.debug > regDebug {
+				fmt.Printf("starting merge block %s with end state of %s:\n", b, p)
+				for _, x := range s.endRegs[p.ID] {
+					fmt.Printf("  %s: orig:%s cache:%s\n", s.registers[x.r].Name(), x.v, x.c)
+				}
+			}
+
+			// Decide on registers for phi ops. Use the registers determined
+			// by the primary predecessor if we can.
+			// TODO: pick best of (already processed) predecessors?
+			// Majority vote?  Deepest nesting level?
+			phiRegs = phiRegs[:0]
+			var phiUsed regMask
+			for _, v := range phis {
+				if !s.values[v.ID].needReg {
+					phiRegs = append(phiRegs, noRegister)
+					continue
+				}
+				a := v.Args[idx]
+				m := s.values[a.ID].regs &^ phiUsed
+				if m != 0 {
+					r := pickReg(m)
+					s.freeReg(r)
+					phiUsed |= regMask(1) << r
+					phiRegs = append(phiRegs, r)
+				} else {
+					phiRegs = append(phiRegs, noRegister)
+				}
+			}
+
+			// Second pass - deallocate any phi inputs which are now dead.
+			for _, v := range phis {
+				if !s.values[v.ID].needReg {
+					continue
+				}
+				a := v.Args[idx]
+				if !liveSet.contains(a.ID) {
+					// Input is dead beyond the phi, deallocate
+					// anywhere else it might live.
+					s.freeRegs(s.values[a.ID].regs)
+				}
+			}
+
+			// Third pass - pick registers for phis whose inputs
+			// were not in a register.
+			for i, v := range phis {
+				if !s.values[v.ID].needReg {
+					continue
+				}
+				if phiRegs[i] != noRegister {
+					continue
+				}
+				m := s.compatRegs(v.Type) &^ phiUsed &^ s.used
+				if m != 0 {
+					r := pickReg(m)
+					phiRegs[i] = r
+					phiUsed |= regMask(1) << r
+				}
+			}
+
+			// Set registers for phis. Add phi spill code.
+			for i, v := range phis {
+				if !s.values[v.ID].needReg {
+					continue
+				}
+				r := phiRegs[i]
+				if r == noRegister {
+					// stack-based phi
+					// Spills will be inserted in all the predecessors below.
+					s.values[v.ID].spill = v        // v starts life spilled
+					s.values[v.ID].spillUsed = true // use is guaranteed
+					continue
+				}
+				// register-based phi
+				s.assignReg(r, v, v)
+				// Spill the phi in case we need to restore it later.
+				spill := b.NewValue1(v.Line, OpStoreReg, v.Type, v)
+				s.setOrig(spill, v)
+				s.values[v.ID].spill = spill
+				s.values[v.ID].spillUsed = false
+				if loop != nil {
+					loop.spills = append(loop.spills, v)
+					nSpillsInner++
+				}
+				nSpills++
+			}
+
+			// Save the starting state for use by merge edges.
+			var regList []startReg
+			for r := register(0); r < s.numRegs; r++ {
+				v := s.regs[r].v
+				if v == nil {
+					continue
+				}
+				if phiUsed>>r&1 != 0 {
+					// Skip registers that phis used, we'll handle those
+					// specially during merge edge processing.
+					continue
+				}
+				regList = append(regList, startReg{r, v.ID})
+			}
+			s.startRegs[b.ID] = regList
+
+			if s.f.pass.debug > regDebug {
+				fmt.Printf("after phis\n")
+				for _, x := range s.startRegs[b.ID] {
+					fmt.Printf("  %s: v%d\n", s.registers[x.r].Name(), x.vid)
+				}
+			}
+		}
+
+		// Allocate space to record the desired registers for each value.
+		dinfo = dinfo[:0]
+		for i := 0; i < len(oldSched); i++ {
+			dinfo = append(dinfo, dentry{})
+		}
+
+		// Load static desired register info at the end of the block.
+		desired.copy(&s.desired[b.ID])
+
+		// Check actual assigned registers at the start of the next block(s).
+		// Dynamically assigned registers will trump the static
+		// desired registers computed during liveness analysis.
+		// Note that we do this phase after startRegs is set above, so that
+		// we get the right behavior for a block which branches to itself.
+		for _, e := range b.Succs {
+			succ := e.b
+			// TODO: prioritize likely successor?
+			for _, x := range s.startRegs[succ.ID] {
+				desired.add(x.vid, x.r)
+			}
+			// Process phi ops in succ.
+			pidx := e.i
+			for _, v := range succ.Values {
+				if v.Op != OpPhi {
+					break
+				}
+				if !s.values[v.ID].needReg {
+					continue
+				}
+				rp, ok := s.f.getHome(v.ID).(*Register)
+				if !ok {
+					continue
+				}
+				desired.add(v.Args[pidx].ID, register(rp.Num))
+			}
+		}
+		// Walk values backwards computing desired register info.
+		// See computeLive for more comments.
+		for i := len(oldSched) - 1; i >= 0; i-- {
+			v := oldSched[i]
+			prefs := desired.remove(v.ID)
+			desired.clobber(opcodeTable[v.Op].reg.clobbers)
+			for _, j := range opcodeTable[v.Op].reg.inputs {
+				if countRegs(j.regs) != 1 {
+					continue
+				}
+				desired.clobber(j.regs)
+				desired.add(v.Args[j.idx].ID, pickReg(j.regs))
+			}
+			if opcodeTable[v.Op].resultInArg0 {
+				if opcodeTable[v.Op].commutative {
+					desired.addList(v.Args[1].ID, prefs)
+				}
+				desired.addList(v.Args[0].ID, prefs)
+			}
+			// Save desired registers for this value.
+			dinfo[i].out = prefs
+			for j, a := range v.Args {
+				if j >= len(dinfo[i].in) {
+					break
+				}
+				dinfo[i].in[j] = desired.get(a.ID)
+			}
+		}
+
+		// Process all the non-phi values.
+		for idx, v := range oldSched {
+			if s.f.pass.debug > regDebug {
+				fmt.Printf("  processing %s\n", v.LongString())
+			}
+			if v.Op == OpPhi {
+				f.Fatalf("phi %s not at start of block", v)
+			}
+			if v.Op == OpSP {
+				s.assignReg(s.SPReg, v, v)
+				b.Values = append(b.Values, v)
+				s.advanceUses(v)
+				continue
+			}
+			if v.Op == OpSB {
+				s.assignReg(s.SBReg, v, v)
+				b.Values = append(b.Values, v)
+				s.advanceUses(v)
+				continue
+			}
+			if v.Op == OpArg {
+				// Args are "pre-spilled" values. We don't allocate
+				// any register here. We just set up the spill pointer to
+				// point at itself and any later user will restore it to use it.
+				s.values[v.ID].spill = v
+				s.values[v.ID].spillUsed = true // use is guaranteed
+				b.Values = append(b.Values, v)
+				s.advanceUses(v)
+				continue
+			}
+			if v.Op == OpKeepAlive {
+				// Make sure the argument to v is still live here.
+				s.advanceUses(v)
+				vi := &s.values[v.Args[0].ID]
+				if vi.spillUsed {
+					// Use the spill location.
+					v.SetArg(0, vi.spill)
+				} else {
+					// No need to keep unspilled values live.
+					// These are typically rematerializeable constants like nil,
+					// or values of a variable that were modified since the last call.
+					v.Op = OpCopy
+					v.SetArgs1(v.Args[1])
+				}
+				b.Values = append(b.Values, v)
+				continue
+			}
+			regspec := opcodeTable[v.Op].reg
+			if len(regspec.inputs) == 0 && len(regspec.outputs) == 0 {
+				// No register allocation required (or none specified yet)
+				s.freeRegs(regspec.clobbers)
+				b.Values = append(b.Values, v)
+				s.advanceUses(v)
+				continue
+			}
+
+			if s.values[v.ID].rematerializeable {
+				// Value is rematerializeable, don't issue it here.
+				// It will get issued just before each use (see
+				// allocValueToReg).
+				for _, a := range v.Args {
+					a.Uses--
+				}
+				s.advanceUses(v)
+				continue
+			}
+
+			if s.f.pass.debug > regDebug {
+				fmt.Printf("value %s\n", v.LongString())
+				fmt.Printf("  out:")
+				for _, r := range dinfo[idx].out {
+					if r != noRegister {
+						fmt.Printf(" %s", s.registers[r].Name())
+					}
+				}
+				fmt.Println()
+				for i := 0; i < len(v.Args) && i < 3; i++ {
+					fmt.Printf("  in%d:", i)
+					for _, r := range dinfo[idx].in[i] {
+						if r != noRegister {
+							fmt.Printf(" %s", s.registers[r].Name())
+						}
+					}
+					fmt.Println()
+				}
+			}
+
+			// Move arguments to registers. Process in an ordering defined
+			// by the register specification (most constrained first).
+			args = append(args[:0], v.Args...)
+			for _, i := range regspec.inputs {
+				mask := i.regs
+				if mask == flagRegMask {
+					// TODO: remove flag input from regspec.inputs.
+					continue
+				}
+				if mask&s.values[args[i.idx].ID].regs == 0 {
+					// Need a new register for the input.
+					mask &= s.allocatable
+					mask &^= s.nospill
+					// Used desired register if available.
+					if i.idx < 3 {
+						for _, r := range dinfo[idx].in[i.idx] {
+							if r != noRegister && (mask&^s.used)>>r&1 != 0 {
+								// Desired register is allowed and unused.
+								mask = regMask(1) << r
+								break
+							}
+						}
+					}
+					// Avoid registers we're saving for other values.
+					if mask&^desired.avoid != 0 {
+						mask &^= desired.avoid
+					}
+				}
+				args[i.idx] = s.allocValToReg(args[i.idx], mask, true, v.Line)
+			}
+
+			// If the output clobbers the input register, make sure we have
+			// at least two copies of the input register so we don't
+			// have to reload the value from the spill location.
+			if opcodeTable[v.Op].resultInArg0 {
+				var m regMask
+				if !s.liveAfterCurrentInstruction(v.Args[0]) {
+					// arg0 is dead.  We can clobber its register.
+					goto ok
+				}
+				if countRegs(s.values[v.Args[0].ID].regs) >= 2 {
+					// we have at least 2 copies of arg0.  We can afford to clobber one.
+					goto ok
+				}
+				if opcodeTable[v.Op].commutative {
+					if !s.liveAfterCurrentInstruction(v.Args[1]) {
+						args[0], args[1] = args[1], args[0]
+						goto ok
+					}
+					if countRegs(s.values[v.Args[1].ID].regs) >= 2 {
+						args[0], args[1] = args[1], args[0]
+						goto ok
+					}
+				}
+
+				// We can't overwrite arg0 (or arg1, if commutative).  So we
+				// need to make a copy of an input so we have a register we can modify.
+
+				// Possible new registers to copy into.
+				m = s.compatRegs(v.Args[0].Type) &^ s.used
+				if m == 0 {
+					// No free registers.  In this case we'll just clobber
+					// an input and future uses of that input must use a restore.
+					// TODO(khr): We should really do this like allocReg does it,
+					// spilling the value with the most distant next use.
+					goto ok
+				}
+
+				// Try to move an input to the desired output.
+				for _, r := range dinfo[idx].out {
+					if r != noRegister && m>>r&1 != 0 {
+						m = regMask(1) << r
+						args[0] = s.allocValToReg(v.Args[0], m, true, v.Line)
+						// Note: we update args[0] so the instruction will
+						// use the register copy we just made.
+						goto ok
+					}
+				}
+				// Try to copy input to its desired location & use its old
+				// location as the result register.
+				for _, r := range dinfo[idx].in[0] {
+					if r != noRegister && m>>r&1 != 0 {
+						m = regMask(1) << r
+						s.allocValToReg(v.Args[0], m, true, v.Line)
+						// Note: no update to args[0] so the instruction will
+						// use the original copy.
+						goto ok
+					}
+				}
+				if opcodeTable[v.Op].commutative {
+					for _, r := range dinfo[idx].in[1] {
+						if r != noRegister && m>>r&1 != 0 {
+							m = regMask(1) << r
+							s.allocValToReg(v.Args[1], m, true, v.Line)
+							args[0], args[1] = args[1], args[0]
+							goto ok
+						}
+					}
+				}
+				// Avoid future fixed uses if we can.
+				if m&^desired.avoid != 0 {
+					m &^= desired.avoid
+				}
+				// Save input 0 to a new register so we can clobber it.
+				s.allocValToReg(v.Args[0], m, true, v.Line)
+			ok:
+			}
+
+			// Now that all args are in regs, we're ready to issue the value itself.
+			// Before we pick a register for the output value, allow input registers
+			// to be deallocated. We do this here so that the output can use the
+			// same register as a dying input.
+			s.nospill = 0
+			s.advanceUses(v) // frees any registers holding args that are no longer live
+
+			// Dump any registers which will be clobbered
+			s.freeRegs(regspec.clobbers)
+
+			// Pick register for output.
+			if s.values[v.ID].needReg {
+				mask := regspec.outputs[0] & s.allocatable
+				if opcodeTable[v.Op].resultInArg0 {
+					if !opcodeTable[v.Op].commutative {
+						// Output must use the same register as input 0.
+						r := register(s.f.getHome(args[0].ID).(*Register).Num)
+						mask = regMask(1) << r
+					} else {
+						// Output must use the same register as input 0 or 1.
+						r0 := register(s.f.getHome(args[0].ID).(*Register).Num)
+						r1 := register(s.f.getHome(args[1].ID).(*Register).Num)
+						// Check r0 and r1 for desired output register.
+						found := false
+						for _, r := range dinfo[idx].out {
+							if (r == r0 || r == r1) && (mask&^s.used)>>r&1 != 0 {
+								mask = regMask(1) << r
+								found = true
+								if r == r1 {
+									args[0], args[1] = args[1], args[0]
+								}
+								break
+							}
+						}
+						if !found {
+							// Neither are desired, pick r0.
+							mask = regMask(1) << r0
+						}
+					}
+				}
+				for _, r := range dinfo[idx].out {
+					if r != noRegister && (mask&^s.used)>>r&1 != 0 {
+						// Desired register is allowed and unused.
+						mask = regMask(1) << r
+						break
+					}
+				}
+				// Avoid registers we're saving for other values.
+				if mask&^desired.avoid != 0 {
+					mask &^= desired.avoid
+				}
+				r := s.allocReg(v, mask)
+				s.assignReg(r, v, v)
+			}
+
+			// Issue the Value itself.
+			for i, a := range args {
+				v.SetArg(i, a) // use register version of arguments
+			}
+			b.Values = append(b.Values, v)
+
+			// Issue a spill for this value. We issue spills unconditionally,
+			// then at the end of regalloc delete the ones we never use.
+			// TODO: schedule the spill at a point that dominates all restores.
+			// The restore may be off in an unlikely branch somewhere and it
+			// would be better to have the spill in that unlikely branch as well.
+			// v := ...
+			// if unlikely {
+			//     f()
+			// }
+			// It would be good to have both spill and restore inside the IF.
+			if s.values[v.ID].needReg {
+				spill := b.NewValue1(v.Line, OpStoreReg, v.Type, v)
+				s.setOrig(spill, v)
+				s.values[v.ID].spill = spill
+				s.values[v.ID].spillUsed = false
+				if loop != nil {
+					loop.spills = append(loop.spills, v)
+					nSpillsInner++
+				}
+				nSpills++
+			}
+		}
+
+		// Load control value into reg.
+		if v := b.Control; v != nil && s.values[v.ID].needReg {
+			if s.f.pass.debug > regDebug {
+				fmt.Printf("  processing control %s\n", v.LongString())
+			}
+			// TODO: regspec for block control values, instead of using
+			// register set from the control op's output.
+			s.allocValToReg(v, opcodeTable[v.Op].reg.outputs[0], false, b.Line)
+			// Remove this use from the uses list.
+			vi := &s.values[v.ID]
+			u := vi.uses
+			vi.uses = u.next
+			if u.next == nil {
+				s.freeRegs(vi.regs) // value is dead
+			}
+			u.next = s.freeUseRecords
+			s.freeUseRecords = u
+		}
+
+		// If we are approaching a merge point and we are the primary
+		// predecessor of it, find live values that we use soon after
+		// the merge point and promote them to registers now.
+		if len(b.Succs) == 1 {
+			// For this to be worthwhile, the loop must have no calls in it.
+			top := b.Succs[0].b
+			loop := s.loopnest.b2l[top.ID]
+			if loop == nil || loop.header != top || loop.containsCall {
+				goto badloop
+			}
+
+			// TODO: sort by distance, pick the closest ones?
+			for _, live := range s.live[b.ID] {
+				if live.dist >= unlikelyDistance {
+					// Don't preload anything live after the loop.
+					continue
+				}
+				vid := live.ID
+				vi := &s.values[vid]
+				if vi.regs != 0 {
+					continue
+				}
+				v := s.orig[vid]
+				m := s.compatRegs(v.Type) &^ s.used
+				if m&^desired.avoid != 0 {
+					m &^= desired.avoid
+				}
+				if m != 0 {
+					s.allocValToReg(v, m, false, b.Line)
+				}
+			}
+		}
+	badloop:
+		;
+
+		// Save end-of-block register state.
+		// First count how many, this cuts allocations in half.
+		k := 0
+		for r := register(0); r < s.numRegs; r++ {
+			v := s.regs[r].v
+			if v == nil {
+				continue
+			}
+			k++
+		}
+		regList := make([]endReg, 0, k)
+		for r := register(0); r < s.numRegs; r++ {
+			v := s.regs[r].v
+			if v == nil {
+				continue
+			}
+			regList = append(regList, endReg{r, v, s.regs[r].c})
+		}
+		s.endRegs[b.ID] = regList
+
+		// Check. TODO: remove
+		{
+			liveSet.clear()
+			for _, x := range s.live[b.ID] {
+				liveSet.add(x.ID)
+			}
+			for r := register(0); r < s.numRegs; r++ {
+				v := s.regs[r].v
+				if v == nil {
+					continue
+				}
+				if !liveSet.contains(v.ID) {
+					s.f.Fatalf("val %s is in reg but not live at end of %s", v, b)
+				}
+			}
+		}
+
+		// If a value is live at the end of the block and
+		// isn't in a register, remember that its spill location
+		// is live. We need to remember this information so that
+		// the liveness analysis in stackalloc is correct.
+		for _, e := range s.live[b.ID] {
+			if s.values[e.ID].regs != 0 {
+				// in a register, we'll use that source for the merge.
+				continue
+			}
+			spill := s.values[e.ID].spill
+			if spill == nil {
+				// rematerializeable values will have spill==nil.
+				continue
+			}
+			s.spillLive[b.ID] = append(s.spillLive[b.ID], spill.ID)
+			s.values[e.ID].spillUsed = true
+		}
+
+		// Keep track of values that are spilled in the loop, but whose spill
+		// is not used in the loop.  It may be possible to move ("sink") the
+		// spill out of the loop into one or more exit blocks.
+		if loop != nil {
+			loop.scratch++                    // increment count of blocks in this loop that have been processed
+			if loop.scratch == loop.nBlocks { // just processed last block of loop, if it is an inner loop.
+				// This check is redundant with code at the top of the loop.
+				// This is definitive; the one at the top of the loop is an optimization.
+				if loop.isInner && // Common case, easier, most likely to be profitable
+					!loop.containsCall && // Calls force spills, also lead to puzzling spill info.
+					len(loop.exits) <= 32 { // Almost no inner loops have more than 32 exits,
+					// and this allows use of a bitvector and a sparseMap.
+
+					// TODO: exit calculation is messed up for non-inner loops
+					// because of multilevel exits that are not part of the "exit"
+					// count.
+
+					// Compute the set of spill-movement candidates live at entry to exit blocks.
+					// isLoopSpillCandidate filters for
+					// (1) defined in appropriate loop
+					// (2) needs a register
+					// (3) spill not already used (in the loop)
+					// Condition (3) === "in a register at all loop exits"
+
+					entryCandidates.clear()
+
+					for whichExit, ss := range loop.exits {
+						// Start with live at end.
+						for _, li := range s.live[ss.ID] {
+							if s.isLoopSpillCandidate(loop, s.orig[li.ID]) {
+								// s.live contains original IDs, use s.orig above to map back to *Value
+								entryCandidates.setBit(li.ID, uint(whichExit))
+							}
+						}
+						// Control can also be live.
+						if ss.Control != nil && s.orig[ss.Control.ID] != nil && s.isLoopSpillCandidate(loop, s.orig[ss.Control.ID]) {
+							entryCandidates.setBit(s.orig[ss.Control.ID].ID, uint(whichExit))
+						}
+						// Walk backwards, filling in locally live values, removing those defined.
+						for i := len(ss.Values) - 1; i >= 0; i-- {
+							v := ss.Values[i]
+							vorig := s.orig[v.ID]
+							if vorig != nil {
+								entryCandidates.remove(vorig.ID) // Cannot be an issue, only keeps the sets smaller.
+							}
+							for _, a := range v.Args {
+								aorig := s.orig[a.ID]
+								if aorig != nil && s.isLoopSpillCandidate(loop, aorig) {
+									entryCandidates.setBit(aorig.ID, uint(whichExit))
+								}
+							}
+						}
+					}
+
+					for _, e := range loop.spills {
+						whichblocks := entryCandidates.get(e.ID)
+						oldSpill := s.values[e.ID].spill
+						if whichblocks != 0 && whichblocks != -1 { // -1 = not in map.
+							toSink = append(toSink, spillToSink{spill: oldSpill, dests: whichblocks})
+						}
+					}
+
+				} // loop is inner etc
+				loop.scratch = 0 // Don't leave a mess, just in case.
+				loop.spills = nil
+			} // if scratch == nBlocks
+		} // if loop is not nil
+
+		// Clear any final uses.
+		// All that is left should be the pseudo-uses added for values which
+		// are live at the end of b.
+		for _, e := range s.live[b.ID] {
+			u := s.values[e.ID].uses
+			if u == nil {
+				f.Fatalf("live at end, no uses v%d", e.ID)
+			}
+			if u.next != nil {
+				f.Fatalf("live at end, too many uses v%d", e.ID)
+			}
+			s.values[e.ID].uses = nil
+			u.next = s.freeUseRecords
+			s.freeUseRecords = u
+		}
+	}
+
+	// Erase any spills we never used
+	for i := range s.values {
+		vi := s.values[i]
+		if vi.spillUsed {
+			if s.f.pass.debug > logSpills {
+				s.f.Config.Warnl(vi.spill.Line, "spilled value at %v remains", vi.spill)
+			}
+			continue
+		}
+		spill := vi.spill
+		if spill == nil {
+			// Constants, SP, SB, ...
+			continue
+		}
+		loop := s.loopForBlock(spill.Block)
+		if loop != nil {
+			nSpillsInner--
+		}
+
+		spill.Args[0].Uses--
+		f.freeValue(spill)
+		nSpills--
+	}
+
+	for _, b := range f.Blocks {
+		i := 0
+		for _, v := range b.Values {
+			if v.Op == OpInvalid {
+				continue
+			}
+			b.Values[i] = v
+			i++
+		}
+		b.Values = b.Values[:i]
+		// TODO: zero b.Values[i:], recycle Values
+		// Not important now because this is the last phase that manipulates Values
+	}
+
+	// Must clear these out before any potential recycling, though that's
+	// not currently implemented.
+	for i, ts := range toSink {
+		vsp := ts.spill
+		if vsp.Op == OpInvalid { // This spill was completely eliminated
+			toSink[i].spill = nil
+		}
+	}
+
+	// Anything that didn't get a register gets a stack location here.
+	// (StoreReg, stack-based phis, inputs, ...)
+	stacklive := stackalloc(s.f, s.spillLive)
+
+	// Fix up all merge edges.
+	s.shuffle(stacklive)
+
+	// Insert moved spills (that have not been marked invalid above)
+	// at start of appropriate block and remove the originals from their
+	// location within loops.  Notice that this can break SSA form;
+	// if a spill is sunk to multiple exits, there will be no phi for that
+	// spill at a join point downstream of those two exits, though the
+	// two spills will target the same stack slot.  Notice also that this
+	// takes place after stack allocation, so the stack allocator does
+	// not need to process these malformed flow graphs.
+sinking:
+	for _, ts := range toSink {
+		vsp := ts.spill
+		if vsp == nil { // This spill was completely eliminated
+			nSpillsSunkUnused++
+			continue sinking
+		}
+		e := ts.spilledValue()
+		if s.values[e.ID].spillUsedShuffle {
+			nSpillsNotSunkLateUse++
+			continue sinking
+		}
+
+		// move spills to a better (outside of loop) block.
+		// This would be costly if it occurred very often, but it doesn't.
+		b := vsp.Block
+		loop := s.loopnest.b2l[b.ID]
+		dests := ts.dests
+
+		// Pre-check to be sure that spilled value is still in expected register on all exits where live.
+	check_val_still_in_reg:
+		for i := uint(0); i < 32 && dests != 0; i++ {
+
+			if dests&(1<<i) == 0 {
+				continue
+			}
+			dests ^= 1 << i
+			d := loop.exits[i]
+			if len(d.Preds) > 1 {
+				panic("Should be impossible given critical edges removed")
+			}
+			p := d.Preds[0].b // block in loop exiting to d.
+
+			endregs := s.endRegs[p.ID]
+			for _, regrec := range endregs {
+				if regrec.v == e && regrec.r != noRegister && regrec.c == e { // TODO: regrec.c != e implies different spill possible.
+					continue check_val_still_in_reg
+				}
+			}
+			// If here, the register assignment was lost down at least one exit and it can't be sunk
+			if s.f.pass.debug > moveSpills {
+				s.f.Config.Warnl(e.Line, "lost register assignment for spill %v in %v at exit %v to %v",
+					vsp, b, p, d)
+			}
+			nSpillsChanged++
+			continue sinking
+		}
+
+		nSpillsSunk++
+		nSpillsInner--
+		// don't update nSpills, since spill is only moved, and if it is duplicated, the spills-on-a-path is not increased.
+
+		dests = ts.dests
+
+		// remove vsp from b.Values
+		i := 0
+		for _, w := range b.Values {
+			if vsp == w {
+				continue
+			}
+			b.Values[i] = w
+			i++
+		}
+		b.Values = b.Values[:i]
+
+		first := true
+		for i := uint(0); i < 32 && dests != 0; i++ {
+
+			if dests&(1<<i) == 0 {
+				continue
+			}
+
+			dests ^= 1 << i
+
+			d := loop.exits[i]
+			vspnew := vsp // reuse original for first sunk spill, saves tracking down and renaming uses
+			if !first {   // any sunk spills after first must make a copy
+				vspnew = d.NewValue1(e.Line, OpStoreReg, e.Type, e)
+				f.setHome(vspnew, f.getHome(vsp.ID)) // copy stack home
+				if s.f.pass.debug > moveSpills {
+					s.f.Config.Warnl(e.Line, "copied spill %v in %v for %v to %v in %v",
+						vsp, b, e, vspnew, d)
+				}
+			} else {
+				first = false
+				vspnew.Block = d
+				d.Values = append(d.Values, vspnew)
+				if s.f.pass.debug > moveSpills {
+					s.f.Config.Warnl(e.Line, "moved spill %v in %v for %v to %v in %v",
+						vsp, b, e, vspnew, d)
+				}
+			}
+
+			// shuffle vspnew to the beginning of its block
+			copy(d.Values[1:], d.Values[0:len(d.Values)-1])
+			d.Values[0] = vspnew
+
+		}
+	}
+
+	if f.pass.stats > 0 {
+		f.LogStat("spills_info",
+			nSpills, "spills", nSpillsInner, "inner_spills_remaining", nSpillsSunk, "inner_spills_sunk", nSpillsSunkUnused, "inner_spills_unused", nSpillsNotSunkLateUse, "inner_spills_shuffled", nSpillsChanged, "inner_spills_changed")
+	}
+}
+
+// isLoopSpillCandidate indicates whether the spill for v satisfies preliminary
+// spill-sinking conditions just after the last block of loop has been processed.
+// In particular:
+//   v needs a register.
+//   v's spill is not (YET) used.
+//   v's definition is within loop.
+// The spill may be used in the future, either by an outright use
+// in the code, or by shuffling code inserted after stack allocation.
+// Outright uses cause sinking; shuffling (within the loop) inhibits it.
+func (s *regAllocState) isLoopSpillCandidate(loop *loop, v *Value) bool {
+	return s.values[v.ID].needReg && !s.values[v.ID].spillUsed && s.loopnest.b2l[v.Block.ID] == loop
+}
+
+// lateSpillUse notes a late (after stack allocation) use of the spill of value with ID vid.
+// This will inhibit spill sinking.
+func (s *regAllocState) lateSpillUse(vid ID) {
+	// TODO investigate why this is necessary.
+	// It appears that an outside-the-loop use of
+	// an otherwise sinkable spill makes the spill
+	// a candidate for shuffling, when it would not
+	// otherwise have been the case (spillUsed was not
+	// true when isLoopSpillCandidate was called, yet
+	// it was shuffled).  Such shuffling cuts the amount
+	// of spill sinking by more than half (in make.bash)
+	s.values[vid].spillUsedShuffle = true
+}
+
+// shuffle fixes up all the merge edges (those going into blocks of indegree > 1).
+func (s *regAllocState) shuffle(stacklive [][]ID) {
+	var e edgeState
+	e.s = s
+	e.cache = map[ID][]*Value{}
+	e.contents = map[Location]contentRecord{}
+	if s.f.pass.debug > regDebug {
+		fmt.Printf("shuffle %s\n", s.f.Name)
+		fmt.Println(s.f.String())
+	}
+
+	for _, b := range s.f.Blocks {
+		if len(b.Preds) <= 1 {
+			continue
+		}
+		e.b = b
+		for i, edge := range b.Preds {
+			p := edge.b
+			e.p = p
+			e.setup(i, s.endRegs[p.ID], s.startRegs[b.ID], stacklive[p.ID])
+			e.process()
+		}
+	}
+}
+
+type edgeState struct {
+	s    *regAllocState
+	p, b *Block // edge goes from p->b.
+
+	// for each pre-regalloc value, a list of equivalent cached values
+	cache      map[ID][]*Value
+	cachedVals []ID // (superset of) keys of the above map, for deterministic iteration
+
+	// map from location to the value it contains
+	contents map[Location]contentRecord
+
+	// desired destination locations
+	destinations []dstRecord
+	extra        []dstRecord
+
+	usedRegs   regMask // registers currently holding something
+	uniqueRegs regMask // registers holding the only copy of a value
+	finalRegs  regMask // registers holding final target
+}
+
+type contentRecord struct {
+	vid   ID     // pre-regalloc value
+	c     *Value // cached value
+	final bool   // this is a satisfied destination
+}
+
+type dstRecord struct {
+	loc    Location // register or stack slot
+	vid    ID       // pre-regalloc value it should contain
+	splice **Value  // place to store reference to the generating instruction
+}
+
+// setup initializes the edge state for shuffling.
+func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive []ID) {
+	if e.s.f.pass.debug > regDebug {
+		fmt.Printf("edge %s->%s\n", e.p, e.b)
+	}
+
+	// Clear state.
+	for _, vid := range e.cachedVals {
+		delete(e.cache, vid)
+	}
+	e.cachedVals = e.cachedVals[:0]
+	for k := range e.contents {
+		delete(e.contents, k)
+	}
+	e.usedRegs = 0
+	e.uniqueRegs = 0
+	e.finalRegs = 0
+
+	// Live registers can be sources.
+	for _, x := range srcReg {
+		e.set(&e.s.registers[x.r], x.v.ID, x.c, false)
+	}
+	// So can all of the spill locations.
+	for _, spillID := range stacklive {
+		v := e.s.orig[spillID]
+		spill := e.s.values[v.ID].spill
+		e.set(e.s.f.getHome(spillID), v.ID, spill, false)
+	}
+
+	// Figure out all the destinations we need.
+	dsts := e.destinations[:0]
+	for _, x := range dstReg {
+		dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil})
+	}
+	// Phis need their args to end up in a specific location.
+	for _, v := range e.b.Values {
+		if v.Op != OpPhi {
+			break
+		}
+		loc := e.s.f.getHome(v.ID)
+		if loc == nil {
+			continue
+		}
+		dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx]})
+	}
+	e.destinations = dsts
+
+	if e.s.f.pass.debug > regDebug {
+		for _, vid := range e.cachedVals {
+			a := e.cache[vid]
+			for _, c := range a {
+				fmt.Printf("src %s: v%d cache=%s\n", e.s.f.getHome(c.ID).Name(), vid, c)
+			}
+		}
+		for _, d := range e.destinations {
+			fmt.Printf("dst %s: v%d\n", d.loc.Name(), d.vid)
+		}
+	}
+}
+
+// process generates code to move all the values to the right destination locations.
+func (e *edgeState) process() {
+	dsts := e.destinations
+
+	// Process the destinations until they are all satisfied.
+	for len(dsts) > 0 {
+		i := 0
+		for _, d := range dsts {
+			if !e.processDest(d.loc, d.vid, d.splice) {
+				// Failed - save for next iteration.
+				dsts[i] = d
+				i++
+			}
+		}
+		if i < len(dsts) {
+			// Made some progress. Go around again.
+			dsts = dsts[:i]
+
+			// Append any extras destinations we generated.
+			dsts = append(dsts, e.extra...)
+			e.extra = e.extra[:0]
+			continue
+		}
+
+		// We made no progress. That means that any
+		// remaining unsatisfied moves are in simple cycles.
+		// For example, A -> B -> C -> D -> A.
+		//   A ----> B
+		//   ^       |
+		//   |       |
+		//   |       v
+		//   D <---- C
+
+		// To break the cycle, we pick an unused register, say R,
+		// and put a copy of B there.
+		//   A ----> B
+		//   ^       |
+		//   |       |
+		//   |       v
+		//   D <---- C <---- R=copyofB
+		// When we resume the outer loop, the A->B move can now proceed,
+		// and eventually the whole cycle completes.
+
+		// Copy any cycle location to a temp register. This duplicates
+		// one of the cycle entries, allowing the just duplicated value
+		// to be overwritten and the cycle to proceed.
+		loc := dsts[0].loc
+		vid := e.contents[loc].vid
+		c := e.contents[loc].c
+		r := e.findRegFor(c.Type)
+		if e.s.f.pass.debug > regDebug {
+			fmt.Printf("breaking cycle with v%d in %s:%s\n", vid, loc.Name(), c)
+		}
+		if _, isReg := loc.(*Register); isReg {
+			c = e.p.NewValue1(c.Line, OpCopy, c.Type, c)
+		} else {
+			e.s.lateSpillUse(vid)
+			c = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
+		}
+		e.set(r, vid, c, false)
+	}
+}
+
+// processDest generates code to put value vid into location loc. Returns true
+// if progress was made.
+func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool {
+	occupant := e.contents[loc]
+	if occupant.vid == vid {
+		// Value is already in the correct place.
+		e.contents[loc] = contentRecord{vid, occupant.c, true}
+		if splice != nil {
+			(*splice).Uses--
+			*splice = occupant.c
+			occupant.c.Uses++
+		}
+		// Note: if splice==nil then c will appear dead. This is
+		// non-SSA formed code, so be careful after this pass not to run
+		// deadcode elimination.
+		return true
+	}
+
+	// Check if we're allowed to clobber the destination location.
+	if len(e.cache[occupant.vid]) == 1 && !e.s.values[occupant.vid].rematerializeable {
+		// We can't overwrite the last copy
+		// of a value that needs to survive.
+		return false
+	}
+
+	// Copy from a source of v, register preferred.
+	v := e.s.orig[vid]
+	var c *Value
+	var src Location
+	if e.s.f.pass.debug > regDebug {
+		fmt.Printf("moving v%d to %s\n", vid, loc.Name())
+		fmt.Printf("sources of v%d:", vid)
+	}
+	for _, w := range e.cache[vid] {
+		h := e.s.f.getHome(w.ID)
+		if e.s.f.pass.debug > regDebug {
+			fmt.Printf(" %s:%s", h.Name(), w)
+		}
+		_, isreg := h.(*Register)
+		if src == nil || isreg {
+			c = w
+			src = h
+		}
+	}
+	if e.s.f.pass.debug > regDebug {
+		if src != nil {
+			fmt.Printf(" [use %s]\n", src.Name())
+		} else {
+			fmt.Printf(" [no source]\n")
+		}
+	}
+	_, dstReg := loc.(*Register)
+	var x *Value
+	if c == nil {
+		if !e.s.values[vid].rematerializeable {
+			e.s.f.Fatalf("can't find source for %s->%s: v%d\n", e.p, e.b, vid)
+		}
+		if dstReg {
+			x = v.copyInto(e.p)
+		} else {
+			// Rematerialize into stack slot. Need a free
+			// register to accomplish this.
+			e.erase(loc) // see pre-clobber comment below
+			r := e.findRegFor(v.Type)
+			x = v.copyInto(e.p)
+			e.set(r, vid, x, false)
+			// Make sure we spill with the size of the slot, not the
+			// size of x (which might be wider due to our dropping
+			// of narrowing conversions).
+			x = e.p.NewValue1(x.Line, OpStoreReg, loc.(LocalSlot).Type, x)
+		}
+	} else {
+		// Emit move from src to dst.
+		_, srcReg := src.(*Register)
+		if srcReg {
+			if dstReg {
+				x = e.p.NewValue1(c.Line, OpCopy, c.Type, c)
+			} else {
+				x = e.p.NewValue1(c.Line, OpStoreReg, loc.(LocalSlot).Type, c)
+			}
+		} else {
+			if dstReg {
+				e.s.lateSpillUse(vid)
+				x = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
+			} else {
+				// mem->mem. Use temp register.
+
+				// Pre-clobber destination. This avoids the
+				// following situation:
+				//   - v is currently held in R0 and stacktmp0.
+				//   - We want to copy stacktmp1 to stacktmp0.
+				//   - We choose R0 as the temporary register.
+				// During the copy, both R0 and stacktmp0 are
+				// clobbered, losing both copies of v. Oops!
+				// Erasing the destination early means R0 will not
+				// be chosen as the temp register, as it will then
+				// be the last copy of v.
+				e.erase(loc)
+
+				r := e.findRegFor(c.Type)
+				e.s.lateSpillUse(vid)
+				t := e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
+				e.set(r, vid, t, false)
+				x = e.p.NewValue1(c.Line, OpStoreReg, loc.(LocalSlot).Type, t)
+			}
+		}
+	}
+	e.set(loc, vid, x, true)
+	if splice != nil {
+		(*splice).Uses--
+		*splice = x
+		x.Uses++
+	}
+	return true
+}
+
+// set changes the contents of location loc to hold the given value and its cached representative.
+func (e *edgeState) set(loc Location, vid ID, c *Value, final bool) {
+	e.s.f.setHome(c, loc)
+	e.erase(loc)
+	e.contents[loc] = contentRecord{vid, c, final}
+	a := e.cache[vid]
+	if len(a) == 0 {
+		e.cachedVals = append(e.cachedVals, vid)
+	}
+	a = append(a, c)
+	e.cache[vid] = a
+	if r, ok := loc.(*Register); ok {
+		e.usedRegs |= regMask(1) << uint(r.Num)
+		if final {
+			e.finalRegs |= regMask(1) << uint(r.Num)
+		}
+		if len(a) == 1 {
+			e.uniqueRegs |= regMask(1) << uint(r.Num)
+		}
+		if len(a) == 2 {
+			if t, ok := e.s.f.getHome(a[0].ID).(*Register); ok {
+				e.uniqueRegs &^= regMask(1) << uint(t.Num)
+			}
+		}
+	}
+	if e.s.f.pass.debug > regDebug {
+		fmt.Printf("%s\n", c.LongString())
+		fmt.Printf("v%d now available in %s:%s\n", vid, loc.Name(), c)
+	}
+}
+
+// erase removes any user of loc.
+func (e *edgeState) erase(loc Location) {
+	cr := e.contents[loc]
+	if cr.c == nil {
+		return
+	}
+	vid := cr.vid
+
+	if cr.final {
+		// Add a destination to move this value back into place.
+		// Make sure it gets added to the tail of the destination queue
+		// so we make progress on other moves first.
+		e.extra = append(e.extra, dstRecord{loc, cr.vid, nil})
+	}
+
+	// Remove c from the list of cached values.
+	a := e.cache[vid]
+	for i, c := range a {
+		if e.s.f.getHome(c.ID) == loc {
+			if e.s.f.pass.debug > regDebug {
+				fmt.Printf("v%d no longer available in %s:%s\n", vid, loc.Name(), c)
+			}
+			a[i], a = a[len(a)-1], a[:len(a)-1]
+			break
+		}
+	}
+	e.cache[vid] = a
+
+	// Update register masks.
+	if r, ok := loc.(*Register); ok {
+		e.usedRegs &^= regMask(1) << uint(r.Num)
+		if cr.final {
+			e.finalRegs &^= regMask(1) << uint(r.Num)
+		}
+	}
+	if len(a) == 1 {
+		if r, ok := e.s.f.getHome(a[0].ID).(*Register); ok {
+			e.uniqueRegs |= regMask(1) << uint(r.Num)
+		}
+	}
+}
+
+// findRegFor finds a register we can use to make a temp copy of type typ.
+func (e *edgeState) findRegFor(typ Type) Location {
+	// Which registers are possibilities.
+	var m regMask
+	if typ.IsFloat() {
+		m = e.s.compatRegs(e.s.f.Config.fe.TypeFloat64())
+	} else {
+		m = e.s.compatRegs(e.s.f.Config.fe.TypeInt64())
+	}
+
+	// Pick a register. In priority order:
+	// 1) an unused register
+	// 2) a non-unique register not holding a final value
+	// 3) a non-unique register
+	x := m &^ e.usedRegs
+	if x != 0 {
+		return &e.s.registers[pickReg(x)]
+	}
+	x = m &^ e.uniqueRegs &^ e.finalRegs
+	if x != 0 {
+		return &e.s.registers[pickReg(x)]
+	}
+	x = m &^ e.uniqueRegs
+	if x != 0 {
+		return &e.s.registers[pickReg(x)]
+	}
+
+	// No register is available. Allocate a temp location to spill a register to.
+	// The type of the slot is immaterial - it will not be live across
+	// any safepoint. Just use a type big enough to hold any register.
+	typ = e.s.f.Config.fe.TypeInt64()
+	t := LocalSlot{e.s.f.Config.fe.Auto(typ), typ, 0}
+	// TODO: reuse these slots.
+
+	// Pick a register to spill.
+	for _, vid := range e.cachedVals {
+		a := e.cache[vid]
+		for _, c := range a {
+			if r, ok := e.s.f.getHome(c.ID).(*Register); ok && m>>uint(r.Num)&1 != 0 {
+				x := e.p.NewValue1(c.Line, OpStoreReg, c.Type, c)
+				e.set(t, vid, x, false)
+				if e.s.f.pass.debug > regDebug {
+					fmt.Printf("  SPILL %s->%s %s\n", r.Name(), t.Name(), x.LongString())
+				}
+				// r will now be overwritten by the caller. At some point
+				// later, the newly saved value will be moved back to its
+				// final destination in processDest.
+				return r
+			}
+		}
+	}
+
+	fmt.Printf("m:%d unique:%d final:%d\n", m, e.uniqueRegs, e.finalRegs)
+	for _, vid := range e.cachedVals {
+		a := e.cache[vid]
+		for _, c := range a {
+			fmt.Printf("v%d: %s %s\n", vid, c, e.s.f.getHome(c.ID).Name())
+		}
+	}
+	e.s.f.Fatalf("can't find empty register on edge %s->%s", e.p, e.b)
+	return nil
+}
+
+func (v *Value) rematerializeable() bool {
+	if !opcodeTable[v.Op].rematerializeable {
+		return false
+	}
+	for _, a := range v.Args {
+		// SP and SB (generated by OpSP and OpSB) are always available.
+		if a.Op != OpSP && a.Op != OpSB {
+			return false
+		}
+	}
+	return true
+}
+
+type liveInfo struct {
+	ID   ID    // ID of value
+	dist int32 // # of instructions before next use
+}
+
+// dblock contains information about desired & avoid registers at the end of a block.
+type dblock struct {
+	prefers []desiredStateEntry
+	avoid   regMask
+}
+
+// computeLive computes a map from block ID to a list of value IDs live at the end
+// of that block. Together with the value ID is a count of how many instructions
+// to the next use of that value. The resulting map is stored in s.live.
+// computeLive also computes the desired register information at the end of each block.
+// This desired register information is stored in s.desired.
+// TODO: this could be quadratic if lots of variables are live across lots of
+// basic blocks. Figure out a way to make this function (or, more precisely, the user
+// of this function) require only linear size & time.
+func (s *regAllocState) computeLive() {
+	f := s.f
+	s.live = make([][]liveInfo, f.NumBlocks())
+	s.desired = make([]desiredState, f.NumBlocks())
+	var phis []*Value
+
+	live := newSparseMap(f.NumValues())
+	t := newSparseMap(f.NumValues())
+
+	// Keep track of which value we want in each register.
+	var desired desiredState
+
+	// Instead of iterating over f.Blocks, iterate over their postordering.
+	// Liveness information flows backward, so starting at the end
+	// increases the probability that we will stabilize quickly.
+	// TODO: Do a better job yet. Here's one possibility:
+	// Calculate the dominator tree and locate all strongly connected components.
+	// If a value is live in one block of an SCC, it is live in all.
+	// Walk the dominator tree from end to beginning, just once, treating SCC
+	// components as single blocks, duplicated calculated liveness information
+	// out to all of them.
+	s.loopnest = loopnestfor(f)
+	po := s.loopnest.po
+	for {
+		changed := false
+
+		for _, b := range po {
+			// Start with known live values at the end of the block.
+			// Add len(b.Values) to adjust from end-of-block distance
+			// to beginning-of-block distance.
+			live.clear()
+			d := int32(len(b.Values))
+			if b.Kind == BlockCall || b.Kind == BlockDefer {
+				// Because we keep no values in registers across a call,
+				// make every use past a call appear very far away.
+				d += unlikelyDistance
+			}
+			for _, e := range s.live[b.ID] {
+				live.set(e.ID, e.dist+d)
+			}
+
+			// Mark control value as live
+			if b.Control != nil && s.values[b.Control.ID].needReg {
+				live.set(b.Control.ID, int32(len(b.Values)))
+			}
+
+			// Propagate backwards to the start of the block
+			// Assumes Values have been scheduled.
+			phis = phis[:0]
+			for i := len(b.Values) - 1; i >= 0; i-- {
+				v := b.Values[i]
+				live.remove(v.ID)
+				if v.Op == OpPhi {
+					// save phi ops for later
+					phis = append(phis, v)
+					continue
+				}
+				for _, a := range v.Args {
+					if s.values[a.ID].needReg {
+						live.set(a.ID, int32(i))
+					}
+				}
+			}
+			// Propagate desired registers backwards.
+			desired.copy(&s.desired[b.ID])
+			for i := len(b.Values) - 1; i >= 0; i-- {
+				v := b.Values[i]
+				prefs := desired.remove(v.ID)
+				if v.Op == OpPhi {
+					// TODO: if v is a phi, save desired register for phi inputs.
+					// For now, we just drop it and don't propagate
+					// desired registers back though phi nodes.
+					continue
+				}
+				// Cancel desired registers if they get clobbered.
+				desired.clobber(opcodeTable[v.Op].reg.clobbers)
+				// Update desired registers if there are any fixed register inputs.
+				for _, j := range opcodeTable[v.Op].reg.inputs {
+					if countRegs(j.regs) != 1 {
+						continue
+					}
+					desired.clobber(j.regs)
+					desired.add(v.Args[j.idx].ID, pickReg(j.regs))
+				}
+				// Set desired register of input 0 if this is a 2-operand instruction.
+				if opcodeTable[v.Op].resultInArg0 {
+					if opcodeTable[v.Op].commutative {
+						desired.addList(v.Args[1].ID, prefs)
+					}
+					desired.addList(v.Args[0].ID, prefs)
+				}
+			}
+
+			// For each predecessor of b, expand its list of live-at-end values.
+			// invariant: live contains the values live at the start of b (excluding phi inputs)
+			for i, e := range b.Preds {
+				p := e.b
+				// Compute additional distance for the edge.
+				// Note: delta must be at least 1 to distinguish the control
+				// value use from the first user in a successor block.
+				delta := int32(normalDistance)
+				if len(p.Succs) == 2 {
+					if p.Succs[0].b == b && p.Likely == BranchLikely ||
+						p.Succs[1].b == b && p.Likely == BranchUnlikely {
+						delta = likelyDistance
+					}
+					if p.Succs[0].b == b && p.Likely == BranchUnlikely ||
+						p.Succs[1].b == b && p.Likely == BranchLikely {
+						delta = unlikelyDistance
+					}
+				}
+
+				// Update any desired registers at the end of p.
+				s.desired[p.ID].merge(&desired)
+
+				// Start t off with the previously known live values at the end of p.
+				t.clear()
+				for _, e := range s.live[p.ID] {
+					t.set(e.ID, e.dist)
+				}
+				update := false
+
+				// Add new live values from scanning this block.
+				for _, e := range live.contents() {
+					d := e.val + delta
+					if !t.contains(e.key) || d < t.get(e.key) {
+						update = true
+						t.set(e.key, d)
+					}
+				}
+				// Also add the correct arg from the saved phi values.
+				// All phis are at distance delta (we consider them
+				// simultaneously happening at the start of the block).
+				for _, v := range phis {
+					id := v.Args[i].ID
+					if s.values[id].needReg && (!t.contains(id) || delta < t.get(id)) {
+						update = true
+						t.set(id, delta)
+					}
+				}
+
+				if !update {
+					continue
+				}
+				// The live set has changed, update it.
+				l := s.live[p.ID][:0]
+				if cap(l) < t.size() {
+					l = make([]liveInfo, 0, t.size())
+				}
+				for _, e := range t.contents() {
+					l = append(l, liveInfo{e.key, e.val})
+				}
+				s.live[p.ID] = l
+				changed = true
+			}
+		}
+
+		if !changed {
+			break
+		}
+	}
+	if f.pass.debug > regDebug {
+		fmt.Println("live values at end of each block")
+		for _, b := range f.Blocks {
+			fmt.Printf("  %s:", b)
+			for _, x := range s.live[b.ID] {
+				fmt.Printf(" v%d", x.ID)
+				for _, e := range s.desired[b.ID].entries {
+					if e.ID != x.ID {
+						continue
+					}
+					fmt.Printf("[")
+					first := true
+					for _, r := range e.regs {
+						if r == noRegister {
+							continue
+						}
+						if !first {
+							fmt.Printf(",")
+						}
+						fmt.Print(s.registers[r].Name())
+						first = false
+					}
+					fmt.Printf("]")
+				}
+			}
+			fmt.Printf(" avoid=%x", int64(s.desired[b.ID].avoid))
+			fmt.Println()
+		}
+	}
+}
+
+// A desiredState represents desired register assignments.
+type desiredState struct {
+	// Desired assignments will be small, so we just use a list
+	// of valueID+registers entries.
+	entries []desiredStateEntry
+	// Registers that other values want to be in.  This value will
+	// contain at least the union of the regs fields of entries, but
+	// may contain additional entries for values that were once in
+	// this data structure but are no longer.
+	avoid regMask
+}
+type desiredStateEntry struct {
+	// (pre-regalloc) value
+	ID ID
+	// Registers it would like to be in, in priority order.
+	// Unused slots are filled with noRegister.
+	regs [4]register
+}
+
+func (d *desiredState) clear() {
+	d.entries = d.entries[:0]
+	d.avoid = 0
+}
+
+// get returns a list of desired registers for value vid.
+func (d *desiredState) get(vid ID) [4]register {
+	for _, e := range d.entries {
+		if e.ID == vid {
+			return e.regs
+		}
+	}
+	return [4]register{noRegister, noRegister, noRegister, noRegister}
+}
+
+// add records that we'd like value vid to be in register r.
+func (d *desiredState) add(vid ID, r register) {
+	d.avoid |= regMask(1) << r
+	for i := range d.entries {
+		e := &d.entries[i]
+		if e.ID != vid {
+			continue
+		}
+		if e.regs[0] == r {
+			// Already known and highest priority
+			return
+		}
+		for j := 1; j < len(e.regs); j++ {
+			if e.regs[j] == r {
+				// Move from lower priority to top priority
+				copy(e.regs[1:], e.regs[:j])
+				e.regs[0] = r
+				return
+			}
+		}
+		copy(e.regs[1:], e.regs[:])
+		e.regs[0] = r
+		return
+	}
+	d.entries = append(d.entries, desiredStateEntry{vid, [4]register{r, noRegister, noRegister, noRegister}})
+}
+
+func (d *desiredState) addList(vid ID, regs [4]register) {
+	// regs is in priority order, so iterate in reverse order.
+	for i := len(regs) - 1; i >= 0; i-- {
+		r := regs[i]
+		if r != noRegister {
+			d.add(vid, r)
+		}
+	}
+}
+
+// clobber erases any desired registers in the set m.
+func (d *desiredState) clobber(m regMask) {
+	for i := 0; i < len(d.entries); {
+		e := &d.entries[i]
+		j := 0
+		for _, r := range e.regs {
+			if r != noRegister && m>>r&1 == 0 {
+				e.regs[j] = r
+				j++
+			}
+		}
+		if j == 0 {
+			// No more desired registers for this value.
+			d.entries[i] = d.entries[len(d.entries)-1]
+			d.entries = d.entries[:len(d.entries)-1]
+			continue
+		}
+		for ; j < len(e.regs); j++ {
+			e.regs[j] = noRegister
+		}
+		i++
+	}
+	d.avoid &^= m
+}
+
+// copy copies a desired state from another desiredState x.
+func (d *desiredState) copy(x *desiredState) {
+	d.entries = append(d.entries[:0], x.entries...)
+	d.avoid = x.avoid
+}
+
+// remove removes the desired registers for vid and returns them.
+func (d *desiredState) remove(vid ID) [4]register {
+	for i := range d.entries {
+		if d.entries[i].ID == vid {
+			regs := d.entries[i].regs
+			d.entries[i] = d.entries[len(d.entries)-1]
+			d.entries = d.entries[:len(d.entries)-1]
+			return regs
+		}
+	}
+	return [4]register{noRegister, noRegister, noRegister, noRegister}
+}
+
+// merge merges another desired state x into d.
+func (d *desiredState) merge(x *desiredState) {
+	d.avoid |= x.avoid
+	// There should only be a few desired registers, so
+	// linear insert is ok.
+	for _, e := range x.entries {
+		d.addList(e.ID, e.regs)
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/regalloc_test.go b/src/cmd/compile/internal/ssa/regalloc_test.go
new file mode 100644
index 0000000..cf8f452
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/regalloc_test.go
@@ -0,0 +1,33 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "testing"
+
+func TestLiveControlOps(t *testing.T) {
+	c := testConfig(t)
+	f := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("x", OpAMD64MOVLconst, TypeInt8, 1, nil),
+			Valu("y", OpAMD64MOVLconst, TypeInt8, 2, nil),
+			Valu("a", OpAMD64TESTB, TypeFlags, 0, nil, "x", "y"),
+			Valu("b", OpAMD64TESTB, TypeFlags, 0, nil, "y", "x"),
+			Eq("a", "if", "exit"),
+		),
+		Bloc("if",
+			Eq("b", "plain", "exit"),
+		),
+		Bloc("plain",
+			Goto("exit"),
+		),
+		Bloc("exit",
+			Exit("mem"),
+		),
+	)
+	flagalloc(f.f)
+	regalloc(f.f)
+	checkFunc(f.f)
+}
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
new file mode 100644
index 0000000..03c3882
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -0,0 +1,386 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"fmt"
+	"math"
+	"os"
+	"path/filepath"
+)
+
+func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
+	// repeat rewrites until we find no more rewrites
+	var curb *Block
+	var curv *Value
+	defer func() {
+		if curb != nil {
+			curb.Fatalf("panic during rewrite of block %s\n", curb.LongString())
+		}
+		if curv != nil {
+			curv.Fatalf("panic during rewrite of value %s\n", curv.LongString())
+			// TODO(khr): print source location also
+		}
+	}()
+	config := f.Config
+	for {
+		change := false
+		for _, b := range f.Blocks {
+			if b.Control != nil && b.Control.Op == OpCopy {
+				for b.Control.Op == OpCopy {
+					b.SetControl(b.Control.Args[0])
+				}
+			}
+			curb = b
+			if rb(b) {
+				change = true
+			}
+			curb = nil
+			for _, v := range b.Values {
+				change = phielimValue(v) || change
+
+				// Eliminate copy inputs.
+				// If any copy input becomes unused, mark it
+				// as invalid and discard its argument. Repeat
+				// recursively on the discarded argument.
+				// This phase helps remove phantom "dead copy" uses
+				// of a value so that a x.Uses==1 rule condition
+				// fires reliably.
+				for i, a := range v.Args {
+					if a.Op != OpCopy {
+						continue
+					}
+					v.SetArg(i, copySource(a))
+					change = true
+					for a.Uses == 0 {
+						b := a.Args[0]
+						a.reset(OpInvalid)
+						a = b
+					}
+				}
+
+				// apply rewrite function
+				curv = v
+				if rv(v, config) {
+					change = true
+				}
+				curv = nil
+			}
+		}
+		if !change {
+			break
+		}
+	}
+	// remove clobbered values
+	for _, b := range f.Blocks {
+		j := 0
+		for i, v := range b.Values {
+			if v.Op == OpInvalid {
+				f.freeValue(v)
+				continue
+			}
+			if i != j {
+				b.Values[j] = v
+			}
+			j++
+		}
+		if j != len(b.Values) {
+			tail := b.Values[j:]
+			for j := range tail {
+				tail[j] = nil
+			}
+			b.Values = b.Values[:j]
+		}
+	}
+}
+
+// Common functions called from rewriting rules
+
+func is64BitFloat(t Type) bool {
+	return t.Size() == 8 && t.IsFloat()
+}
+
+func is32BitFloat(t Type) bool {
+	return t.Size() == 4 && t.IsFloat()
+}
+
+func is64BitInt(t Type) bool {
+	return t.Size() == 8 && t.IsInteger()
+}
+
+func is32BitInt(t Type) bool {
+	return t.Size() == 4 && t.IsInteger()
+}
+
+func is16BitInt(t Type) bool {
+	return t.Size() == 2 && t.IsInteger()
+}
+
+func is8BitInt(t Type) bool {
+	return t.Size() == 1 && t.IsInteger()
+}
+
+func isPtr(t Type) bool {
+	return t.IsPtrShaped()
+}
+
+func isSigned(t Type) bool {
+	return t.IsSigned()
+}
+
+func typeSize(t Type) int64 {
+	return t.Size()
+}
+
+// mergeSym merges two symbolic offsets. There is no real merging of
+// offsets, we just pick the non-nil one.
+func mergeSym(x, y interface{}) interface{} {
+	if x == nil {
+		return y
+	}
+	if y == nil {
+		return x
+	}
+	panic(fmt.Sprintf("mergeSym with two non-nil syms %s %s", x, y))
+}
+func canMergeSym(x, y interface{}) bool {
+	return x == nil || y == nil
+}
+
+// nlz returns the number of leading zeros.
+func nlz(x int64) int64 {
+	// log2(0) == 1, so nlz(0) == 64
+	return 63 - log2(x)
+}
+
+// ntz returns the number of trailing zeros.
+func ntz(x int64) int64 {
+	return 64 - nlz(^x&(x-1))
+}
+
+// nlo returns the number of leading ones.
+func nlo(x int64) int64 {
+	return nlz(^x)
+}
+
+// nto returns the number of trailing ones.
+func nto(x int64) int64 {
+	return ntz(^x)
+}
+
+// log2 returns logarithm in base of uint64(n), with log2(0) = -1.
+func log2(n int64) (l int64) {
+	l = -1
+	x := uint64(n)
+	for ; x >= 0x8000; x >>= 16 {
+		l += 16
+	}
+	if x >= 0x80 {
+		x >>= 8
+		l += 8
+	}
+	if x >= 0x8 {
+		x >>= 4
+		l += 4
+	}
+	if x >= 0x2 {
+		x >>= 2
+		l += 2
+	}
+	if x >= 0x1 {
+		l++
+	}
+	return
+}
+
+// isPowerOfTwo reports whether n is a power of 2.
+func isPowerOfTwo(n int64) bool {
+	return n > 0 && n&(n-1) == 0
+}
+
+// is32Bit reports whether n can be represented as a signed 32 bit integer.
+func is32Bit(n int64) bool {
+	return n == int64(int32(n))
+}
+
+// b2i translates a boolean value to 0 or 1 for assigning to auxInt.
+func b2i(b bool) int64 {
+	if b {
+		return 1
+	}
+	return 0
+}
+
+// i2f is used in rules for converting from an AuxInt to a float.
+func i2f(i int64) float64 {
+	return math.Float64frombits(uint64(i))
+}
+
+// i2f32 is used in rules for converting from an AuxInt to a float32.
+func i2f32(i int64) float32 {
+	return float32(math.Float64frombits(uint64(i)))
+}
+
+// f2i is used in the rules for storing a float in AuxInt.
+func f2i(f float64) int64 {
+	return int64(math.Float64bits(f))
+}
+
+// uaddOvf returns true if unsigned a+b would overflow.
+func uaddOvf(a, b int64) bool {
+	return uint64(a)+uint64(b) < uint64(a)
+}
+
+// isSamePtr reports whether p1 and p2 point to the same address.
+func isSamePtr(p1, p2 *Value) bool {
+	if p1 == p2 {
+		return true
+	}
+	if p1.Op != p2.Op {
+		return false
+	}
+	switch p1.Op {
+	case OpOffPtr:
+		return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0])
+	case OpAddr:
+		// OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op.
+		// Checking for value equality only works after [z]cse has run.
+		return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op
+	case OpAddPtr:
+		return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0])
+	}
+	return false
+}
+
+// DUFFZERO consists of repeated blocks of 4 MOVUPSs + ADD,
+// See runtime/mkduff.go.
+const (
+	dzBlocks    = 16 // 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
+	dzClearStep = 16 // number of bytes cleared by each MOV instruction
+
+	dzTailLen  = 4 // number of final STOSQ instructions
+	dzTailSize = 2 // size of single STOSQ instruction
+
+	dzClearLen = dzClearStep * dzBlockLen // bytes cleared by one block
+	dzSize     = dzBlocks * dzBlockSize
+)
+
+func duffStart(size int64) int64 {
+	x, _ := duff(size)
+	return x
+}
+func duffAdj(size int64) int64 {
+	_, x := duff(size)
+	return x
+}
+
+// duff returns the offset (from duffzero, in bytes) and pointer adjust (in bytes)
+// required to use the duffzero mechanism for a block of the given size.
+func duff(size int64) (int64, int64) {
+	if size < 32 || size > 1024 || size%dzClearStep != 0 {
+		panic("bad duffzero size")
+	}
+	// TODO: arch-dependent
+	steps := size / dzClearStep
+	blocks := steps / dzBlockLen
+	steps %= dzBlockLen
+	off := dzBlockSize * (dzBlocks - blocks)
+	var adj int64
+	if steps != 0 {
+		off -= dzAddSize
+		off -= dzMovSize * steps
+		adj -= dzClearStep * (dzBlockLen - steps)
+	}
+	return off, adj
+}
+
+// mergePoint finds a block among a's blocks which dominates b and is itself
+// dominated by all of a's blocks. Returns nil if it can't find one.
+// Might return nil even if one does exist.
+func mergePoint(b *Block, a ...*Value) *Block {
+	// Walk backward from b looking for one of the a's blocks.
+
+	// Max distance
+	d := 100
+
+	for d > 0 {
+		for _, x := range a {
+			if b == x.Block {
+				goto found
+			}
+		}
+		if len(b.Preds) > 1 {
+			// Don't know which way to go back. Abort.
+			return nil
+		}
+		b = b.Preds[0].b
+		d--
+	}
+	return nil // too far away
+found:
+	// At this point, r is the first value in a that we find by walking backwards.
+	// if we return anything, r will be it.
+	r := b
+
+	// Keep going, counting the other a's that we find. They must all dominate r.
+	na := 0
+	for d > 0 {
+		for _, x := range a {
+			if b == x.Block {
+				na++
+			}
+		}
+		if na == len(a) {
+			// Found all of a in a backwards walk. We can return r.
+			return r
+		}
+		if len(b.Preds) > 1 {
+			return nil
+		}
+		b = b.Preds[0].b
+		d--
+
+	}
+	return nil // too far away
+}
+
+// clobber invalidates v.  Returns true.
+// clobber is used by rewrite rules to:
+//   A) make sure v is really dead and never used again.
+//   B) decrement use counts of v's args.
+func clobber(v *Value) bool {
+	v.reset(OpInvalid)
+	// Note: leave v.Block intact.  The Block field is used after clobber.
+	return true
+}
+
+// logRule logs the use of the rule s. This will only be enabled if
+// rewrite rules were generated with the -log option, see gen/rulegen.go.
+func logRule(s string) {
+	if ruleFile == nil {
+		// Open a log file to write log to. We open in append
+		// mode because all.bash runs the compiler lots of times,
+		// and we want the concatenation of all of those logs.
+		// This means, of course, that users need to rm the old log
+		// to get fresh data.
+		// TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow?
+		w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
+			os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
+		if err != nil {
+			panic(err)
+		}
+		ruleFile = w
+	}
+	_, err := fmt.Fprintf(ruleFile, "rewrite %s\n", s)
+	if err != nil {
+		panic(err)
+	}
+}
+
+var ruleFile *os.File
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
new file mode 100644
index 0000000..cefd50c
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -0,0 +1,18956 @@
+// autogenerated from gen/AMD64.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValueAMD64(v *Value, config *Config) bool {
+	switch v.Op {
+	case OpAMD64ADDL:
+		return rewriteValueAMD64_OpAMD64ADDL(v, config)
+	case OpAMD64ADDLconst:
+		return rewriteValueAMD64_OpAMD64ADDLconst(v, config)
+	case OpAMD64ADDQ:
+		return rewriteValueAMD64_OpAMD64ADDQ(v, config)
+	case OpAMD64ADDQconst:
+		return rewriteValueAMD64_OpAMD64ADDQconst(v, config)
+	case OpAMD64ANDL:
+		return rewriteValueAMD64_OpAMD64ANDL(v, config)
+	case OpAMD64ANDLconst:
+		return rewriteValueAMD64_OpAMD64ANDLconst(v, config)
+	case OpAMD64ANDQ:
+		return rewriteValueAMD64_OpAMD64ANDQ(v, config)
+	case OpAMD64ANDQconst:
+		return rewriteValueAMD64_OpAMD64ANDQconst(v, config)
+	case OpAdd16:
+		return rewriteValueAMD64_OpAdd16(v, config)
+	case OpAdd32:
+		return rewriteValueAMD64_OpAdd32(v, config)
+	case OpAdd32F:
+		return rewriteValueAMD64_OpAdd32F(v, config)
+	case OpAdd64:
+		return rewriteValueAMD64_OpAdd64(v, config)
+	case OpAdd64F:
+		return rewriteValueAMD64_OpAdd64F(v, config)
+	case OpAdd8:
+		return rewriteValueAMD64_OpAdd8(v, config)
+	case OpAddPtr:
+		return rewriteValueAMD64_OpAddPtr(v, config)
+	case OpAddr:
+		return rewriteValueAMD64_OpAddr(v, config)
+	case OpAnd16:
+		return rewriteValueAMD64_OpAnd16(v, config)
+	case OpAnd32:
+		return rewriteValueAMD64_OpAnd32(v, config)
+	case OpAnd64:
+		return rewriteValueAMD64_OpAnd64(v, config)
+	case OpAnd8:
+		return rewriteValueAMD64_OpAnd8(v, config)
+	case OpAndB:
+		return rewriteValueAMD64_OpAndB(v, config)
+	case OpAvg64u:
+		return rewriteValueAMD64_OpAvg64u(v, config)
+	case OpBswap32:
+		return rewriteValueAMD64_OpBswap32(v, config)
+	case OpBswap64:
+		return rewriteValueAMD64_OpBswap64(v, config)
+	case OpAMD64CMOVLEQconst:
+		return rewriteValueAMD64_OpAMD64CMOVLEQconst(v, config)
+	case OpAMD64CMOVQEQconst:
+		return rewriteValueAMD64_OpAMD64CMOVQEQconst(v, config)
+	case OpAMD64CMOVWEQconst:
+		return rewriteValueAMD64_OpAMD64CMOVWEQconst(v, config)
+	case OpAMD64CMPB:
+		return rewriteValueAMD64_OpAMD64CMPB(v, config)
+	case OpAMD64CMPBconst:
+		return rewriteValueAMD64_OpAMD64CMPBconst(v, config)
+	case OpAMD64CMPL:
+		return rewriteValueAMD64_OpAMD64CMPL(v, config)
+	case OpAMD64CMPLconst:
+		return rewriteValueAMD64_OpAMD64CMPLconst(v, config)
+	case OpAMD64CMPQ:
+		return rewriteValueAMD64_OpAMD64CMPQ(v, config)
+	case OpAMD64CMPQconst:
+		return rewriteValueAMD64_OpAMD64CMPQconst(v, config)
+	case OpAMD64CMPW:
+		return rewriteValueAMD64_OpAMD64CMPW(v, config)
+	case OpAMD64CMPWconst:
+		return rewriteValueAMD64_OpAMD64CMPWconst(v, config)
+	case OpClosureCall:
+		return rewriteValueAMD64_OpClosureCall(v, config)
+	case OpCom16:
+		return rewriteValueAMD64_OpCom16(v, config)
+	case OpCom32:
+		return rewriteValueAMD64_OpCom32(v, config)
+	case OpCom64:
+		return rewriteValueAMD64_OpCom64(v, config)
+	case OpCom8:
+		return rewriteValueAMD64_OpCom8(v, config)
+	case OpConst16:
+		return rewriteValueAMD64_OpConst16(v, config)
+	case OpConst32:
+		return rewriteValueAMD64_OpConst32(v, config)
+	case OpConst32F:
+		return rewriteValueAMD64_OpConst32F(v, config)
+	case OpConst64:
+		return rewriteValueAMD64_OpConst64(v, config)
+	case OpConst64F:
+		return rewriteValueAMD64_OpConst64F(v, config)
+	case OpConst8:
+		return rewriteValueAMD64_OpConst8(v, config)
+	case OpConstBool:
+		return rewriteValueAMD64_OpConstBool(v, config)
+	case OpConstNil:
+		return rewriteValueAMD64_OpConstNil(v, config)
+	case OpConvert:
+		return rewriteValueAMD64_OpConvert(v, config)
+	case OpCtz16:
+		return rewriteValueAMD64_OpCtz16(v, config)
+	case OpCtz32:
+		return rewriteValueAMD64_OpCtz32(v, config)
+	case OpCtz64:
+		return rewriteValueAMD64_OpCtz64(v, config)
+	case OpCvt32Fto32:
+		return rewriteValueAMD64_OpCvt32Fto32(v, config)
+	case OpCvt32Fto64:
+		return rewriteValueAMD64_OpCvt32Fto64(v, config)
+	case OpCvt32Fto64F:
+		return rewriteValueAMD64_OpCvt32Fto64F(v, config)
+	case OpCvt32to32F:
+		return rewriteValueAMD64_OpCvt32to32F(v, config)
+	case OpCvt32to64F:
+		return rewriteValueAMD64_OpCvt32to64F(v, config)
+	case OpCvt64Fto32:
+		return rewriteValueAMD64_OpCvt64Fto32(v, config)
+	case OpCvt64Fto32F:
+		return rewriteValueAMD64_OpCvt64Fto32F(v, config)
+	case OpCvt64Fto64:
+		return rewriteValueAMD64_OpCvt64Fto64(v, config)
+	case OpCvt64to32F:
+		return rewriteValueAMD64_OpCvt64to32F(v, config)
+	case OpCvt64to64F:
+		return rewriteValueAMD64_OpCvt64to64F(v, config)
+	case OpDeferCall:
+		return rewriteValueAMD64_OpDeferCall(v, config)
+	case OpDiv16:
+		return rewriteValueAMD64_OpDiv16(v, config)
+	case OpDiv16u:
+		return rewriteValueAMD64_OpDiv16u(v, config)
+	case OpDiv32:
+		return rewriteValueAMD64_OpDiv32(v, config)
+	case OpDiv32F:
+		return rewriteValueAMD64_OpDiv32F(v, config)
+	case OpDiv32u:
+		return rewriteValueAMD64_OpDiv32u(v, config)
+	case OpDiv64:
+		return rewriteValueAMD64_OpDiv64(v, config)
+	case OpDiv64F:
+		return rewriteValueAMD64_OpDiv64F(v, config)
+	case OpDiv64u:
+		return rewriteValueAMD64_OpDiv64u(v, config)
+	case OpDiv8:
+		return rewriteValueAMD64_OpDiv8(v, config)
+	case OpDiv8u:
+		return rewriteValueAMD64_OpDiv8u(v, config)
+	case OpEq16:
+		return rewriteValueAMD64_OpEq16(v, config)
+	case OpEq32:
+		return rewriteValueAMD64_OpEq32(v, config)
+	case OpEq32F:
+		return rewriteValueAMD64_OpEq32F(v, config)
+	case OpEq64:
+		return rewriteValueAMD64_OpEq64(v, config)
+	case OpEq64F:
+		return rewriteValueAMD64_OpEq64F(v, config)
+	case OpEq8:
+		return rewriteValueAMD64_OpEq8(v, config)
+	case OpEqB:
+		return rewriteValueAMD64_OpEqB(v, config)
+	case OpEqPtr:
+		return rewriteValueAMD64_OpEqPtr(v, config)
+	case OpGeq16:
+		return rewriteValueAMD64_OpGeq16(v, config)
+	case OpGeq16U:
+		return rewriteValueAMD64_OpGeq16U(v, config)
+	case OpGeq32:
+		return rewriteValueAMD64_OpGeq32(v, config)
+	case OpGeq32F:
+		return rewriteValueAMD64_OpGeq32F(v, config)
+	case OpGeq32U:
+		return rewriteValueAMD64_OpGeq32U(v, config)
+	case OpGeq64:
+		return rewriteValueAMD64_OpGeq64(v, config)
+	case OpGeq64F:
+		return rewriteValueAMD64_OpGeq64F(v, config)
+	case OpGeq64U:
+		return rewriteValueAMD64_OpGeq64U(v, config)
+	case OpGeq8:
+		return rewriteValueAMD64_OpGeq8(v, config)
+	case OpGeq8U:
+		return rewriteValueAMD64_OpGeq8U(v, config)
+	case OpGetClosurePtr:
+		return rewriteValueAMD64_OpGetClosurePtr(v, config)
+	case OpGetG:
+		return rewriteValueAMD64_OpGetG(v, config)
+	case OpGoCall:
+		return rewriteValueAMD64_OpGoCall(v, config)
+	case OpGreater16:
+		return rewriteValueAMD64_OpGreater16(v, config)
+	case OpGreater16U:
+		return rewriteValueAMD64_OpGreater16U(v, config)
+	case OpGreater32:
+		return rewriteValueAMD64_OpGreater32(v, config)
+	case OpGreater32F:
+		return rewriteValueAMD64_OpGreater32F(v, config)
+	case OpGreater32U:
+		return rewriteValueAMD64_OpGreater32U(v, config)
+	case OpGreater64:
+		return rewriteValueAMD64_OpGreater64(v, config)
+	case OpGreater64F:
+		return rewriteValueAMD64_OpGreater64F(v, config)
+	case OpGreater64U:
+		return rewriteValueAMD64_OpGreater64U(v, config)
+	case OpGreater8:
+		return rewriteValueAMD64_OpGreater8(v, config)
+	case OpGreater8U:
+		return rewriteValueAMD64_OpGreater8U(v, config)
+	case OpHmul16:
+		return rewriteValueAMD64_OpHmul16(v, config)
+	case OpHmul16u:
+		return rewriteValueAMD64_OpHmul16u(v, config)
+	case OpHmul32:
+		return rewriteValueAMD64_OpHmul32(v, config)
+	case OpHmul32u:
+		return rewriteValueAMD64_OpHmul32u(v, config)
+	case OpHmul64:
+		return rewriteValueAMD64_OpHmul64(v, config)
+	case OpHmul64u:
+		return rewriteValueAMD64_OpHmul64u(v, config)
+	case OpHmul8:
+		return rewriteValueAMD64_OpHmul8(v, config)
+	case OpHmul8u:
+		return rewriteValueAMD64_OpHmul8u(v, config)
+	case OpITab:
+		return rewriteValueAMD64_OpITab(v, config)
+	case OpInterCall:
+		return rewriteValueAMD64_OpInterCall(v, config)
+	case OpIsInBounds:
+		return rewriteValueAMD64_OpIsInBounds(v, config)
+	case OpIsNonNil:
+		return rewriteValueAMD64_OpIsNonNil(v, config)
+	case OpIsSliceInBounds:
+		return rewriteValueAMD64_OpIsSliceInBounds(v, config)
+	case OpAMD64LEAQ:
+		return rewriteValueAMD64_OpAMD64LEAQ(v, config)
+	case OpAMD64LEAQ1:
+		return rewriteValueAMD64_OpAMD64LEAQ1(v, config)
+	case OpAMD64LEAQ2:
+		return rewriteValueAMD64_OpAMD64LEAQ2(v, config)
+	case OpAMD64LEAQ4:
+		return rewriteValueAMD64_OpAMD64LEAQ4(v, config)
+	case OpAMD64LEAQ8:
+		return rewriteValueAMD64_OpAMD64LEAQ8(v, config)
+	case OpLeq16:
+		return rewriteValueAMD64_OpLeq16(v, config)
+	case OpLeq16U:
+		return rewriteValueAMD64_OpLeq16U(v, config)
+	case OpLeq32:
+		return rewriteValueAMD64_OpLeq32(v, config)
+	case OpLeq32F:
+		return rewriteValueAMD64_OpLeq32F(v, config)
+	case OpLeq32U:
+		return rewriteValueAMD64_OpLeq32U(v, config)
+	case OpLeq64:
+		return rewriteValueAMD64_OpLeq64(v, config)
+	case OpLeq64F:
+		return rewriteValueAMD64_OpLeq64F(v, config)
+	case OpLeq64U:
+		return rewriteValueAMD64_OpLeq64U(v, config)
+	case OpLeq8:
+		return rewriteValueAMD64_OpLeq8(v, config)
+	case OpLeq8U:
+		return rewriteValueAMD64_OpLeq8U(v, config)
+	case OpLess16:
+		return rewriteValueAMD64_OpLess16(v, config)
+	case OpLess16U:
+		return rewriteValueAMD64_OpLess16U(v, config)
+	case OpLess32:
+		return rewriteValueAMD64_OpLess32(v, config)
+	case OpLess32F:
+		return rewriteValueAMD64_OpLess32F(v, config)
+	case OpLess32U:
+		return rewriteValueAMD64_OpLess32U(v, config)
+	case OpLess64:
+		return rewriteValueAMD64_OpLess64(v, config)
+	case OpLess64F:
+		return rewriteValueAMD64_OpLess64F(v, config)
+	case OpLess64U:
+		return rewriteValueAMD64_OpLess64U(v, config)
+	case OpLess8:
+		return rewriteValueAMD64_OpLess8(v, config)
+	case OpLess8U:
+		return rewriteValueAMD64_OpLess8U(v, config)
+	case OpLoad:
+		return rewriteValueAMD64_OpLoad(v, config)
+	case OpLrot16:
+		return rewriteValueAMD64_OpLrot16(v, config)
+	case OpLrot32:
+		return rewriteValueAMD64_OpLrot32(v, config)
+	case OpLrot64:
+		return rewriteValueAMD64_OpLrot64(v, config)
+	case OpLrot8:
+		return rewriteValueAMD64_OpLrot8(v, config)
+	case OpLsh16x16:
+		return rewriteValueAMD64_OpLsh16x16(v, config)
+	case OpLsh16x32:
+		return rewriteValueAMD64_OpLsh16x32(v, config)
+	case OpLsh16x64:
+		return rewriteValueAMD64_OpLsh16x64(v, config)
+	case OpLsh16x8:
+		return rewriteValueAMD64_OpLsh16x8(v, config)
+	case OpLsh32x16:
+		return rewriteValueAMD64_OpLsh32x16(v, config)
+	case OpLsh32x32:
+		return rewriteValueAMD64_OpLsh32x32(v, config)
+	case OpLsh32x64:
+		return rewriteValueAMD64_OpLsh32x64(v, config)
+	case OpLsh32x8:
+		return rewriteValueAMD64_OpLsh32x8(v, config)
+	case OpLsh64x16:
+		return rewriteValueAMD64_OpLsh64x16(v, config)
+	case OpLsh64x32:
+		return rewriteValueAMD64_OpLsh64x32(v, config)
+	case OpLsh64x64:
+		return rewriteValueAMD64_OpLsh64x64(v, config)
+	case OpLsh64x8:
+		return rewriteValueAMD64_OpLsh64x8(v, config)
+	case OpLsh8x16:
+		return rewriteValueAMD64_OpLsh8x16(v, config)
+	case OpLsh8x32:
+		return rewriteValueAMD64_OpLsh8x32(v, config)
+	case OpLsh8x64:
+		return rewriteValueAMD64_OpLsh8x64(v, config)
+	case OpLsh8x8:
+		return rewriteValueAMD64_OpLsh8x8(v, config)
+	case OpAMD64MOVBQSX:
+		return rewriteValueAMD64_OpAMD64MOVBQSX(v, config)
+	case OpAMD64MOVBQSXload:
+		return rewriteValueAMD64_OpAMD64MOVBQSXload(v, config)
+	case OpAMD64MOVBQZX:
+		return rewriteValueAMD64_OpAMD64MOVBQZX(v, config)
+	case OpAMD64MOVBload:
+		return rewriteValueAMD64_OpAMD64MOVBload(v, config)
+	case OpAMD64MOVBloadidx1:
+		return rewriteValueAMD64_OpAMD64MOVBloadidx1(v, config)
+	case OpAMD64MOVBstore:
+		return rewriteValueAMD64_OpAMD64MOVBstore(v, config)
+	case OpAMD64MOVBstoreconst:
+		return rewriteValueAMD64_OpAMD64MOVBstoreconst(v, config)
+	case OpAMD64MOVBstoreconstidx1:
+		return rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v, config)
+	case OpAMD64MOVBstoreidx1:
+		return rewriteValueAMD64_OpAMD64MOVBstoreidx1(v, config)
+	case OpAMD64MOVLQSX:
+		return rewriteValueAMD64_OpAMD64MOVLQSX(v, config)
+	case OpAMD64MOVLQSXload:
+		return rewriteValueAMD64_OpAMD64MOVLQSXload(v, config)
+	case OpAMD64MOVLQZX:
+		return rewriteValueAMD64_OpAMD64MOVLQZX(v, config)
+	case OpAMD64MOVLload:
+		return rewriteValueAMD64_OpAMD64MOVLload(v, config)
+	case OpAMD64MOVLloadidx1:
+		return rewriteValueAMD64_OpAMD64MOVLloadidx1(v, config)
+	case OpAMD64MOVLloadidx4:
+		return rewriteValueAMD64_OpAMD64MOVLloadidx4(v, config)
+	case OpAMD64MOVLstore:
+		return rewriteValueAMD64_OpAMD64MOVLstore(v, config)
+	case OpAMD64MOVLstoreconst:
+		return rewriteValueAMD64_OpAMD64MOVLstoreconst(v, config)
+	case OpAMD64MOVLstoreconstidx1:
+		return rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v, config)
+	case OpAMD64MOVLstoreconstidx4:
+		return rewriteValueAMD64_OpAMD64MOVLstoreconstidx4(v, config)
+	case OpAMD64MOVLstoreidx1:
+		return rewriteValueAMD64_OpAMD64MOVLstoreidx1(v, config)
+	case OpAMD64MOVLstoreidx4:
+		return rewriteValueAMD64_OpAMD64MOVLstoreidx4(v, config)
+	case OpAMD64MOVOload:
+		return rewriteValueAMD64_OpAMD64MOVOload(v, config)
+	case OpAMD64MOVOstore:
+		return rewriteValueAMD64_OpAMD64MOVOstore(v, config)
+	case OpAMD64MOVQload:
+		return rewriteValueAMD64_OpAMD64MOVQload(v, config)
+	case OpAMD64MOVQloadidx1:
+		return rewriteValueAMD64_OpAMD64MOVQloadidx1(v, config)
+	case OpAMD64MOVQloadidx8:
+		return rewriteValueAMD64_OpAMD64MOVQloadidx8(v, config)
+	case OpAMD64MOVQstore:
+		return rewriteValueAMD64_OpAMD64MOVQstore(v, config)
+	case OpAMD64MOVQstoreconst:
+		return rewriteValueAMD64_OpAMD64MOVQstoreconst(v, config)
+	case OpAMD64MOVQstoreconstidx1:
+		return rewriteValueAMD64_OpAMD64MOVQstoreconstidx1(v, config)
+	case OpAMD64MOVQstoreconstidx8:
+		return rewriteValueAMD64_OpAMD64MOVQstoreconstidx8(v, config)
+	case OpAMD64MOVQstoreidx1:
+		return rewriteValueAMD64_OpAMD64MOVQstoreidx1(v, config)
+	case OpAMD64MOVQstoreidx8:
+		return rewriteValueAMD64_OpAMD64MOVQstoreidx8(v, config)
+	case OpAMD64MOVSDload:
+		return rewriteValueAMD64_OpAMD64MOVSDload(v, config)
+	case OpAMD64MOVSDloadidx1:
+		return rewriteValueAMD64_OpAMD64MOVSDloadidx1(v, config)
+	case OpAMD64MOVSDloadidx8:
+		return rewriteValueAMD64_OpAMD64MOVSDloadidx8(v, config)
+	case OpAMD64MOVSDstore:
+		return rewriteValueAMD64_OpAMD64MOVSDstore(v, config)
+	case OpAMD64MOVSDstoreidx1:
+		return rewriteValueAMD64_OpAMD64MOVSDstoreidx1(v, config)
+	case OpAMD64MOVSDstoreidx8:
+		return rewriteValueAMD64_OpAMD64MOVSDstoreidx8(v, config)
+	case OpAMD64MOVSSload:
+		return rewriteValueAMD64_OpAMD64MOVSSload(v, config)
+	case OpAMD64MOVSSloadidx1:
+		return rewriteValueAMD64_OpAMD64MOVSSloadidx1(v, config)
+	case OpAMD64MOVSSloadidx4:
+		return rewriteValueAMD64_OpAMD64MOVSSloadidx4(v, config)
+	case OpAMD64MOVSSstore:
+		return rewriteValueAMD64_OpAMD64MOVSSstore(v, config)
+	case OpAMD64MOVSSstoreidx1:
+		return rewriteValueAMD64_OpAMD64MOVSSstoreidx1(v, config)
+	case OpAMD64MOVSSstoreidx4:
+		return rewriteValueAMD64_OpAMD64MOVSSstoreidx4(v, config)
+	case OpAMD64MOVWQSX:
+		return rewriteValueAMD64_OpAMD64MOVWQSX(v, config)
+	case OpAMD64MOVWQSXload:
+		return rewriteValueAMD64_OpAMD64MOVWQSXload(v, config)
+	case OpAMD64MOVWQZX:
+		return rewriteValueAMD64_OpAMD64MOVWQZX(v, config)
+	case OpAMD64MOVWload:
+		return rewriteValueAMD64_OpAMD64MOVWload(v, config)
+	case OpAMD64MOVWloadidx1:
+		return rewriteValueAMD64_OpAMD64MOVWloadidx1(v, config)
+	case OpAMD64MOVWloadidx2:
+		return rewriteValueAMD64_OpAMD64MOVWloadidx2(v, config)
+	case OpAMD64MOVWstore:
+		return rewriteValueAMD64_OpAMD64MOVWstore(v, config)
+	case OpAMD64MOVWstoreconst:
+		return rewriteValueAMD64_OpAMD64MOVWstoreconst(v, config)
+	case OpAMD64MOVWstoreconstidx1:
+		return rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v, config)
+	case OpAMD64MOVWstoreconstidx2:
+		return rewriteValueAMD64_OpAMD64MOVWstoreconstidx2(v, config)
+	case OpAMD64MOVWstoreidx1:
+		return rewriteValueAMD64_OpAMD64MOVWstoreidx1(v, config)
+	case OpAMD64MOVWstoreidx2:
+		return rewriteValueAMD64_OpAMD64MOVWstoreidx2(v, config)
+	case OpAMD64MULL:
+		return rewriteValueAMD64_OpAMD64MULL(v, config)
+	case OpAMD64MULLconst:
+		return rewriteValueAMD64_OpAMD64MULLconst(v, config)
+	case OpAMD64MULQ:
+		return rewriteValueAMD64_OpAMD64MULQ(v, config)
+	case OpAMD64MULQconst:
+		return rewriteValueAMD64_OpAMD64MULQconst(v, config)
+	case OpMod16:
+		return rewriteValueAMD64_OpMod16(v, config)
+	case OpMod16u:
+		return rewriteValueAMD64_OpMod16u(v, config)
+	case OpMod32:
+		return rewriteValueAMD64_OpMod32(v, config)
+	case OpMod32u:
+		return rewriteValueAMD64_OpMod32u(v, config)
+	case OpMod64:
+		return rewriteValueAMD64_OpMod64(v, config)
+	case OpMod64u:
+		return rewriteValueAMD64_OpMod64u(v, config)
+	case OpMod8:
+		return rewriteValueAMD64_OpMod8(v, config)
+	case OpMod8u:
+		return rewriteValueAMD64_OpMod8u(v, config)
+	case OpMove:
+		return rewriteValueAMD64_OpMove(v, config)
+	case OpMul16:
+		return rewriteValueAMD64_OpMul16(v, config)
+	case OpMul32:
+		return rewriteValueAMD64_OpMul32(v, config)
+	case OpMul32F:
+		return rewriteValueAMD64_OpMul32F(v, config)
+	case OpMul64:
+		return rewriteValueAMD64_OpMul64(v, config)
+	case OpMul64F:
+		return rewriteValueAMD64_OpMul64F(v, config)
+	case OpMul8:
+		return rewriteValueAMD64_OpMul8(v, config)
+	case OpAMD64NEGL:
+		return rewriteValueAMD64_OpAMD64NEGL(v, config)
+	case OpAMD64NEGQ:
+		return rewriteValueAMD64_OpAMD64NEGQ(v, config)
+	case OpAMD64NOTL:
+		return rewriteValueAMD64_OpAMD64NOTL(v, config)
+	case OpAMD64NOTQ:
+		return rewriteValueAMD64_OpAMD64NOTQ(v, config)
+	case OpNeg16:
+		return rewriteValueAMD64_OpNeg16(v, config)
+	case OpNeg32:
+		return rewriteValueAMD64_OpNeg32(v, config)
+	case OpNeg32F:
+		return rewriteValueAMD64_OpNeg32F(v, config)
+	case OpNeg64:
+		return rewriteValueAMD64_OpNeg64(v, config)
+	case OpNeg64F:
+		return rewriteValueAMD64_OpNeg64F(v, config)
+	case OpNeg8:
+		return rewriteValueAMD64_OpNeg8(v, config)
+	case OpNeq16:
+		return rewriteValueAMD64_OpNeq16(v, config)
+	case OpNeq32:
+		return rewriteValueAMD64_OpNeq32(v, config)
+	case OpNeq32F:
+		return rewriteValueAMD64_OpNeq32F(v, config)
+	case OpNeq64:
+		return rewriteValueAMD64_OpNeq64(v, config)
+	case OpNeq64F:
+		return rewriteValueAMD64_OpNeq64F(v, config)
+	case OpNeq8:
+		return rewriteValueAMD64_OpNeq8(v, config)
+	case OpNeqB:
+		return rewriteValueAMD64_OpNeqB(v, config)
+	case OpNeqPtr:
+		return rewriteValueAMD64_OpNeqPtr(v, config)
+	case OpNilCheck:
+		return rewriteValueAMD64_OpNilCheck(v, config)
+	case OpNot:
+		return rewriteValueAMD64_OpNot(v, config)
+	case OpAMD64ORL:
+		return rewriteValueAMD64_OpAMD64ORL(v, config)
+	case OpAMD64ORLconst:
+		return rewriteValueAMD64_OpAMD64ORLconst(v, config)
+	case OpAMD64ORQ:
+		return rewriteValueAMD64_OpAMD64ORQ(v, config)
+	case OpAMD64ORQconst:
+		return rewriteValueAMD64_OpAMD64ORQconst(v, config)
+	case OpOffPtr:
+		return rewriteValueAMD64_OpOffPtr(v, config)
+	case OpOr16:
+		return rewriteValueAMD64_OpOr16(v, config)
+	case OpOr32:
+		return rewriteValueAMD64_OpOr32(v, config)
+	case OpOr64:
+		return rewriteValueAMD64_OpOr64(v, config)
+	case OpOr8:
+		return rewriteValueAMD64_OpOr8(v, config)
+	case OpOrB:
+		return rewriteValueAMD64_OpOrB(v, config)
+	case OpRsh16Ux16:
+		return rewriteValueAMD64_OpRsh16Ux16(v, config)
+	case OpRsh16Ux32:
+		return rewriteValueAMD64_OpRsh16Ux32(v, config)
+	case OpRsh16Ux64:
+		return rewriteValueAMD64_OpRsh16Ux64(v, config)
+	case OpRsh16Ux8:
+		return rewriteValueAMD64_OpRsh16Ux8(v, config)
+	case OpRsh16x16:
+		return rewriteValueAMD64_OpRsh16x16(v, config)
+	case OpRsh16x32:
+		return rewriteValueAMD64_OpRsh16x32(v, config)
+	case OpRsh16x64:
+		return rewriteValueAMD64_OpRsh16x64(v, config)
+	case OpRsh16x8:
+		return rewriteValueAMD64_OpRsh16x8(v, config)
+	case OpRsh32Ux16:
+		return rewriteValueAMD64_OpRsh32Ux16(v, config)
+	case OpRsh32Ux32:
+		return rewriteValueAMD64_OpRsh32Ux32(v, config)
+	case OpRsh32Ux64:
+		return rewriteValueAMD64_OpRsh32Ux64(v, config)
+	case OpRsh32Ux8:
+		return rewriteValueAMD64_OpRsh32Ux8(v, config)
+	case OpRsh32x16:
+		return rewriteValueAMD64_OpRsh32x16(v, config)
+	case OpRsh32x32:
+		return rewriteValueAMD64_OpRsh32x32(v, config)
+	case OpRsh32x64:
+		return rewriteValueAMD64_OpRsh32x64(v, config)
+	case OpRsh32x8:
+		return rewriteValueAMD64_OpRsh32x8(v, config)
+	case OpRsh64Ux16:
+		return rewriteValueAMD64_OpRsh64Ux16(v, config)
+	case OpRsh64Ux32:
+		return rewriteValueAMD64_OpRsh64Ux32(v, config)
+	case OpRsh64Ux64:
+		return rewriteValueAMD64_OpRsh64Ux64(v, config)
+	case OpRsh64Ux8:
+		return rewriteValueAMD64_OpRsh64Ux8(v, config)
+	case OpRsh64x16:
+		return rewriteValueAMD64_OpRsh64x16(v, config)
+	case OpRsh64x32:
+		return rewriteValueAMD64_OpRsh64x32(v, config)
+	case OpRsh64x64:
+		return rewriteValueAMD64_OpRsh64x64(v, config)
+	case OpRsh64x8:
+		return rewriteValueAMD64_OpRsh64x8(v, config)
+	case OpRsh8Ux16:
+		return rewriteValueAMD64_OpRsh8Ux16(v, config)
+	case OpRsh8Ux32:
+		return rewriteValueAMD64_OpRsh8Ux32(v, config)
+	case OpRsh8Ux64:
+		return rewriteValueAMD64_OpRsh8Ux64(v, config)
+	case OpRsh8Ux8:
+		return rewriteValueAMD64_OpRsh8Ux8(v, config)
+	case OpRsh8x16:
+		return rewriteValueAMD64_OpRsh8x16(v, config)
+	case OpRsh8x32:
+		return rewriteValueAMD64_OpRsh8x32(v, config)
+	case OpRsh8x64:
+		return rewriteValueAMD64_OpRsh8x64(v, config)
+	case OpRsh8x8:
+		return rewriteValueAMD64_OpRsh8x8(v, config)
+	case OpAMD64SARB:
+		return rewriteValueAMD64_OpAMD64SARB(v, config)
+	case OpAMD64SARBconst:
+		return rewriteValueAMD64_OpAMD64SARBconst(v, config)
+	case OpAMD64SARL:
+		return rewriteValueAMD64_OpAMD64SARL(v, config)
+	case OpAMD64SARLconst:
+		return rewriteValueAMD64_OpAMD64SARLconst(v, config)
+	case OpAMD64SARQ:
+		return rewriteValueAMD64_OpAMD64SARQ(v, config)
+	case OpAMD64SARQconst:
+		return rewriteValueAMD64_OpAMD64SARQconst(v, config)
+	case OpAMD64SARW:
+		return rewriteValueAMD64_OpAMD64SARW(v, config)
+	case OpAMD64SARWconst:
+		return rewriteValueAMD64_OpAMD64SARWconst(v, config)
+	case OpAMD64SBBLcarrymask:
+		return rewriteValueAMD64_OpAMD64SBBLcarrymask(v, config)
+	case OpAMD64SBBQcarrymask:
+		return rewriteValueAMD64_OpAMD64SBBQcarrymask(v, config)
+	case OpAMD64SETA:
+		return rewriteValueAMD64_OpAMD64SETA(v, config)
+	case OpAMD64SETAE:
+		return rewriteValueAMD64_OpAMD64SETAE(v, config)
+	case OpAMD64SETB:
+		return rewriteValueAMD64_OpAMD64SETB(v, config)
+	case OpAMD64SETBE:
+		return rewriteValueAMD64_OpAMD64SETBE(v, config)
+	case OpAMD64SETEQ:
+		return rewriteValueAMD64_OpAMD64SETEQ(v, config)
+	case OpAMD64SETG:
+		return rewriteValueAMD64_OpAMD64SETG(v, config)
+	case OpAMD64SETGE:
+		return rewriteValueAMD64_OpAMD64SETGE(v, config)
+	case OpAMD64SETL:
+		return rewriteValueAMD64_OpAMD64SETL(v, config)
+	case OpAMD64SETLE:
+		return rewriteValueAMD64_OpAMD64SETLE(v, config)
+	case OpAMD64SETNE:
+		return rewriteValueAMD64_OpAMD64SETNE(v, config)
+	case OpAMD64SHLL:
+		return rewriteValueAMD64_OpAMD64SHLL(v, config)
+	case OpAMD64SHLQ:
+		return rewriteValueAMD64_OpAMD64SHLQ(v, config)
+	case OpAMD64SHRB:
+		return rewriteValueAMD64_OpAMD64SHRB(v, config)
+	case OpAMD64SHRL:
+		return rewriteValueAMD64_OpAMD64SHRL(v, config)
+	case OpAMD64SHRQ:
+		return rewriteValueAMD64_OpAMD64SHRQ(v, config)
+	case OpAMD64SHRW:
+		return rewriteValueAMD64_OpAMD64SHRW(v, config)
+	case OpAMD64SUBL:
+		return rewriteValueAMD64_OpAMD64SUBL(v, config)
+	case OpAMD64SUBLconst:
+		return rewriteValueAMD64_OpAMD64SUBLconst(v, config)
+	case OpAMD64SUBQ:
+		return rewriteValueAMD64_OpAMD64SUBQ(v, config)
+	case OpAMD64SUBQconst:
+		return rewriteValueAMD64_OpAMD64SUBQconst(v, config)
+	case OpSignExt16to32:
+		return rewriteValueAMD64_OpSignExt16to32(v, config)
+	case OpSignExt16to64:
+		return rewriteValueAMD64_OpSignExt16to64(v, config)
+	case OpSignExt32to64:
+		return rewriteValueAMD64_OpSignExt32to64(v, config)
+	case OpSignExt8to16:
+		return rewriteValueAMD64_OpSignExt8to16(v, config)
+	case OpSignExt8to32:
+		return rewriteValueAMD64_OpSignExt8to32(v, config)
+	case OpSignExt8to64:
+		return rewriteValueAMD64_OpSignExt8to64(v, config)
+	case OpSqrt:
+		return rewriteValueAMD64_OpSqrt(v, config)
+	case OpStaticCall:
+		return rewriteValueAMD64_OpStaticCall(v, config)
+	case OpStore:
+		return rewriteValueAMD64_OpStore(v, config)
+	case OpSub16:
+		return rewriteValueAMD64_OpSub16(v, config)
+	case OpSub32:
+		return rewriteValueAMD64_OpSub32(v, config)
+	case OpSub32F:
+		return rewriteValueAMD64_OpSub32F(v, config)
+	case OpSub64:
+		return rewriteValueAMD64_OpSub64(v, config)
+	case OpSub64F:
+		return rewriteValueAMD64_OpSub64F(v, config)
+	case OpSub8:
+		return rewriteValueAMD64_OpSub8(v, config)
+	case OpSubPtr:
+		return rewriteValueAMD64_OpSubPtr(v, config)
+	case OpTrunc16to8:
+		return rewriteValueAMD64_OpTrunc16to8(v, config)
+	case OpTrunc32to16:
+		return rewriteValueAMD64_OpTrunc32to16(v, config)
+	case OpTrunc32to8:
+		return rewriteValueAMD64_OpTrunc32to8(v, config)
+	case OpTrunc64to16:
+		return rewriteValueAMD64_OpTrunc64to16(v, config)
+	case OpTrunc64to32:
+		return rewriteValueAMD64_OpTrunc64to32(v, config)
+	case OpTrunc64to8:
+		return rewriteValueAMD64_OpTrunc64to8(v, config)
+	case OpAMD64XORL:
+		return rewriteValueAMD64_OpAMD64XORL(v, config)
+	case OpAMD64XORLconst:
+		return rewriteValueAMD64_OpAMD64XORLconst(v, config)
+	case OpAMD64XORQ:
+		return rewriteValueAMD64_OpAMD64XORQ(v, config)
+	case OpAMD64XORQconst:
+		return rewriteValueAMD64_OpAMD64XORQconst(v, config)
+	case OpXor16:
+		return rewriteValueAMD64_OpXor16(v, config)
+	case OpXor32:
+		return rewriteValueAMD64_OpXor32(v, config)
+	case OpXor64:
+		return rewriteValueAMD64_OpXor64(v, config)
+	case OpXor8:
+		return rewriteValueAMD64_OpXor8(v, config)
+	case OpZero:
+		return rewriteValueAMD64_OpZero(v, config)
+	case OpZeroExt16to32:
+		return rewriteValueAMD64_OpZeroExt16to32(v, config)
+	case OpZeroExt16to64:
+		return rewriteValueAMD64_OpZeroExt16to64(v, config)
+	case OpZeroExt32to64:
+		return rewriteValueAMD64_OpZeroExt32to64(v, config)
+	case OpZeroExt8to16:
+		return rewriteValueAMD64_OpZeroExt8to16(v, config)
+	case OpZeroExt8to32:
+		return rewriteValueAMD64_OpZeroExt8to32(v, config)
+	case OpZeroExt8to64:
+		return rewriteValueAMD64_OpZeroExt8to64(v, config)
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ADDL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ADDL x (MOVLconst [c]))
+	// cond:
+	// result: (ADDLconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ADDLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL (MOVLconst [c]) x)
+	// cond:
+	// result: (ADDLconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64ADDLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDL x (NEGL y))
+	// cond:
+	// result: (SUBL x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGL {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64SUBL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ADDLconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ADDLconst [c] x)
+	// cond: int32(c)==0
+	// result: x
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(int32(c) == 0) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDLconst [c] (MOVLconst [d]))
+	// cond:
+	// result: (MOVLconst [int64(int32(c+d))])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = int64(int32(c + d))
+		return true
+	}
+	// match: (ADDLconst [c] (ADDLconst [d] x))
+	// cond:
+	// result: (ADDLconst [int64(int32(c+d))] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ADDLconst)
+		v.AuxInt = int64(int32(c + d))
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ADDQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (ADDQconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64ADDQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (ADDQconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64ADDQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDQ x (SHLQconst [3] y))
+	// cond:
+	// result: (LEAQ8 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 3 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ x (SHLQconst [2] y))
+	// cond:
+	// result: (LEAQ4 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 2 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ x (SHLQconst [1] y))
+	// cond:
+	// result: (LEAQ2 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ x (ADDQ y y))
+	// cond:
+	// result: (LEAQ2 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQ {
+			break
+		}
+		y := v_1.Args[0]
+		if y != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ x (ADDQ x y))
+	// cond:
+	// result: (LEAQ2 y x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQ {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDQ x (ADDQ y x))
+	// cond:
+	// result: (LEAQ2 y x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQ {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDQ (ADDQconst [c] x) y)
+	// cond:
+	// result: (LEAQ1 [c] x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ x (ADDQconst [c] y))
+	// cond:
+	// result: (LEAQ1 [c] x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ x (LEAQ [c] {s} y))
+	// cond: x.Op != OpSB && y.Op != OpSB
+	// result: (LEAQ1 [c] {s} x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64LEAQ {
+			break
+		}
+		c := v_1.AuxInt
+		s := v_1.Aux
+		y := v_1.Args[0]
+		if !(x.Op != OpSB && y.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ (LEAQ [c] {s} x) y)
+	// cond: x.Op != OpSB && y.Op != OpSB
+	// result: (LEAQ1 [c] {s} x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		c := v_0.AuxInt
+		s := v_0.Aux
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(x.Op != OpSB && y.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQ x (NEGQ y))
+	// cond:
+	// result: (SUBQ x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64NEGQ {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64SUBQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ADDQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ADDQconst [c] (ADDQ x y))
+	// cond:
+	// result: (LEAQ1 [c] x y)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = c
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQconst [c] (LEAQ [d] {s} x))
+	// cond: is32Bit(c+d)
+	// result: (LEAQ [c+d] {s} x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		d := v_0.AuxInt
+		s := v_0.Aux
+		x := v_0.Args[0]
+		if !(is32Bit(c + d)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDQconst [c] (LEAQ1 [d] {s} x y))
+	// cond: is32Bit(c+d)
+	// result: (LEAQ1 [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		d := v_0.AuxInt
+		s := v_0.Aux
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if !(is32Bit(c + d)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQconst [c] (LEAQ2 [d] {s} x y))
+	// cond: is32Bit(c+d)
+	// result: (LEAQ2 [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ2 {
+			break
+		}
+		d := v_0.AuxInt
+		s := v_0.Aux
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if !(is32Bit(c + d)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ2)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQconst [c] (LEAQ4 [d] {s} x y))
+	// cond: is32Bit(c+d)
+	// result: (LEAQ4 [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ4 {
+			break
+		}
+		d := v_0.AuxInt
+		s := v_0.Aux
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if !(is32Bit(c + d)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ4)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQconst [c] (LEAQ8 [d] {s} x y))
+	// cond: is32Bit(c+d)
+	// result: (LEAQ8 [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ8 {
+			break
+		}
+		d := v_0.AuxInt
+		s := v_0.Aux
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if !(is32Bit(c + d)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ8)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (ADDQconst [0] x)
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADDQconst [c] (MOVQconst [d]))
+	// cond:
+	// result: (MOVQconst [c+d])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = c + d
+		return true
+	}
+	// match: (ADDQconst [c] (ADDQconst [d] x))
+	// cond: is32Bit(c+d)
+	// result: (ADDQconst [c+d] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(is32Bit(c + d)) {
+			break
+		}
+		v.reset(OpAMD64ADDQconst)
+		v.AuxInt = c + d
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ANDL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ANDL x (MOVLconst [c]))
+	// cond:
+	// result: (ANDLconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDL (MOVLconst [c]) x)
+	// cond:
+	// result: (ANDLconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDL x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ANDLconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ANDLconst [c] (ANDLconst [d] x))
+	// cond:
+	// result: (ANDLconst [c & d] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c & d
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDLconst [c] _)
+	// cond: int32(c)==0
+	// result: (MOVLconst [0])
+	for {
+		c := v.AuxInt
+		if !(int32(c) == 0) {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (ANDLconst [c] x)
+	// cond: int32(c)==-1
+	// result: x
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(int32(c) == -1) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDLconst [c] (MOVLconst [d]))
+	// cond:
+	// result: (MOVLconst [c&d])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = c & d
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ANDQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ANDQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (ANDQconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64ANDQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (ANDQconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64ANDQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDQ x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ANDQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ANDQconst [c] (ANDQconst [d] x))
+	// cond:
+	// result: (ANDQconst [c & d] x)
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ANDQconst)
+		v.AuxInt = c & d
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDQconst [0xFF] x)
+	// cond:
+	// result: (MOVBQZX x)
+	for {
+		if v.AuxInt != 0xFF {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQZX)
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDQconst [0xFFFF] x)
+	// cond:
+	// result: (MOVWQZX x)
+	for {
+		if v.AuxInt != 0xFFFF {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64MOVWQZX)
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDQconst [0xFFFFFFFF] x)
+	// cond:
+	// result: (MOVLQZX x)
+	for {
+		if v.AuxInt != 0xFFFFFFFF {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64MOVLQZX)
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDQconst [0] _)
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (ANDQconst [-1] x)
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != -1 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (ANDQconst [c] (MOVQconst [d]))
+	// cond:
+	// result: (MOVQconst [c&d])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = c & d
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAdd16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add16  x y)
+	// cond:
+	// result: (ADDL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add32  x y)
+	// cond:
+	// result: (ADDL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add32F x y)
+	// cond:
+	// result: (ADDSS x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDSS)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add64  x y)
+	// cond:
+	// result: (ADDQ  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add64F x y)
+	// cond:
+	// result: (ADDSD x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDSD)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAdd8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add8   x y)
+	// cond:
+	// result: (ADDL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAddPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (AddPtr x y)
+	// cond:
+	// result: (ADDQ  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ADDQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAddr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Addr {sym} base)
+	// cond:
+	// result: (LEAQ {sym} base)
+	for {
+		sym := v.Aux
+		base := v.Args[0]
+		v.reset(OpAMD64LEAQ)
+		v.Aux = sym
+		v.AddArg(base)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAnd16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (And16 x y)
+	// cond:
+	// result: (ANDL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAnd32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (And32 x y)
+	// cond:
+	// result: (ANDL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAnd64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (And64 x y)
+	// cond:
+	// result: (ANDQ x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAnd8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (And8  x y)
+	// cond:
+	// result: (ANDL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAndB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (AndB x y)
+	// cond:
+	// result: (ANDL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAvg64u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Avg64u x y)
+	// cond:
+	// result: (AVGQU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64AVGQU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpBswap32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Bswap32 x)
+	// cond:
+	// result: (BSWAPL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64BSWAPL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpBswap64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Bswap64 x)
+	// cond:
+	// result: (BSWAPQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64BSWAPQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAMD64CMOVLEQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMOVLEQconst x (InvertFlags y) [c])
+	// cond:
+	// result: (CMOVLNEconst x y [c])
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64InvertFlags {
+			break
+		}
+		y := v_1.Args[0]
+		c := v.AuxInt
+		v.reset(OpAMD64CMOVLNEconst)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AuxInt = c
+		return true
+	}
+	// match: (CMOVLEQconst _ (FlagEQ) [c])
+	// cond:
+	// result: (Const32 [c])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagEQ {
+			break
+		}
+		c := v.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = c
+		return true
+	}
+	// match: (CMOVLEQconst x (FlagLT_ULT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMOVLEQconst x (FlagLT_UGT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMOVLEQconst x (FlagGT_ULT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMOVLEQconst x (FlagGT_UGT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMOVQEQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMOVQEQconst x (InvertFlags y) [c])
+	// cond:
+	// result: (CMOVQNEconst x y [c])
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64InvertFlags {
+			break
+		}
+		y := v_1.Args[0]
+		c := v.AuxInt
+		v.reset(OpAMD64CMOVQNEconst)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AuxInt = c
+		return true
+	}
+	// match: (CMOVQEQconst _ (FlagEQ) [c])
+	// cond:
+	// result: (Const64 [c])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagEQ {
+			break
+		}
+		c := v.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c
+		return true
+	}
+	// match: (CMOVQEQconst x (FlagLT_ULT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMOVQEQconst x (FlagLT_UGT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMOVQEQconst x (FlagGT_ULT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMOVQEQconst x (FlagGT_UGT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMOVWEQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMOVWEQconst x (InvertFlags y) [c])
+	// cond:
+	// result: (CMOVWNEconst x y [c])
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64InvertFlags {
+			break
+		}
+		y := v_1.Args[0]
+		c := v.AuxInt
+		v.reset(OpAMD64CMOVWNEconst)
+		v.AddArg(x)
+		v.AddArg(y)
+		v.AuxInt = c
+		return true
+	}
+	// match: (CMOVWEQconst _ (FlagEQ) [c])
+	// cond:
+	// result: (Const16 [c])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagEQ {
+			break
+		}
+		c := v.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = c
+		return true
+	}
+	// match: (CMOVWEQconst x (FlagLT_ULT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMOVWEQconst x (FlagLT_UGT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMOVWEQconst x (FlagGT_ULT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMOVWEQconst x (FlagGT_UGT))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMPB x (MOVLconst [c]))
+	// cond:
+	// result: (CMPBconst x [int64(int8(c))])
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64CMPBconst)
+		v.AddArg(x)
+		v.AuxInt = int64(int8(c))
+		return true
+	}
+	// match: (CMPB (MOVLconst [c]) x)
+	// cond:
+	// result: (InvertFlags (CMPBconst x [int64(int8(c))]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64InvertFlags)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v0.AddArg(x)
+		v0.AuxInt = int64(int8(c))
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMPBconst (MOVLconst [x]) [y])
+	// cond: int8(x)==int8(y)
+	// result: (FlagEQ)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int8(x) == int8(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagEQ)
+		return true
+	}
+	// match: (CMPBconst (MOVLconst [x]) [y])
+	// cond: int8(x)<int8(y) && uint8(x)<uint8(y)
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int8(x) < int8(y) && uint8(x) < uint8(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPBconst (MOVLconst [x]) [y])
+	// cond: int8(x)<int8(y) && uint8(x)>uint8(y)
+	// result: (FlagLT_UGT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int8(x) < int8(y) && uint8(x) > uint8(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_UGT)
+		return true
+	}
+	// match: (CMPBconst (MOVLconst [x]) [y])
+	// cond: int8(x)>int8(y) && uint8(x)<uint8(y)
+	// result: (FlagGT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int8(x) > int8(y) && uint8(x) < uint8(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagGT_ULT)
+		return true
+	}
+	// match: (CMPBconst (MOVLconst [x]) [y])
+	// cond: int8(x)>int8(y) && uint8(x)>uint8(y)
+	// result: (FlagGT_UGT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int8(x) > int8(y) && uint8(x) > uint8(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagGT_UGT)
+		return true
+	}
+	// match: (CMPBconst (ANDLconst _ [m]) [n])
+	// cond: 0 <= int8(m) && int8(m) < int8(n)
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		m := v_0.AuxInt
+		n := v.AuxInt
+		if !(0 <= int8(m) && int8(m) < int8(n)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPBconst (ANDL x y) [0])
+	// cond:
+	// result: (TESTB x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (CMPBconst (ANDLconst [c] x) [0])
+	// cond:
+	// result: (TESTBconst [int64(int8(c))] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTBconst)
+		v.AuxInt = int64(int8(c))
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMPBconst x [0])
+	// cond:
+	// result: (TESTB x x)
+	for {
+		x := v.Args[0]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTB)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMPL x (MOVLconst [c]))
+	// cond:
+	// result: (CMPLconst x [c])
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64CMPLconst)
+		v.AddArg(x)
+		v.AuxInt = c
+		return true
+	}
+	// match: (CMPL (MOVLconst [c]) x)
+	// cond:
+	// result: (InvertFlags (CMPLconst x [c]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64InvertFlags)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v0.AddArg(x)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPLconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMPLconst (MOVLconst [x]) [y])
+	// cond: int32(x)==int32(y)
+	// result: (FlagEQ)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int32(x) == int32(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagEQ)
+		return true
+	}
+	// match: (CMPLconst (MOVLconst [x]) [y])
+	// cond: int32(x)<int32(y) && uint32(x)<uint32(y)
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int32(x) < int32(y) && uint32(x) < uint32(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPLconst (MOVLconst [x]) [y])
+	// cond: int32(x)<int32(y) && uint32(x)>uint32(y)
+	// result: (FlagLT_UGT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int32(x) < int32(y) && uint32(x) > uint32(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_UGT)
+		return true
+	}
+	// match: (CMPLconst (MOVLconst [x]) [y])
+	// cond: int32(x)>int32(y) && uint32(x)<uint32(y)
+	// result: (FlagGT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int32(x) > int32(y) && uint32(x) < uint32(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagGT_ULT)
+		return true
+	}
+	// match: (CMPLconst (MOVLconst [x]) [y])
+	// cond: int32(x)>int32(y) && uint32(x)>uint32(y)
+	// result: (FlagGT_UGT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int32(x) > int32(y) && uint32(x) > uint32(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagGT_UGT)
+		return true
+	}
+	// match: (CMPLconst (SHRLconst _ [c]) [n])
+	// cond: 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRLconst {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.AuxInt
+		if !(0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPLconst (ANDLconst _ [m]) [n])
+	// cond: 0 <= int32(m) && int32(m) < int32(n)
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		m := v_0.AuxInt
+		n := v.AuxInt
+		if !(0 <= int32(m) && int32(m) < int32(n)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPLconst (ANDL x y) [0])
+	// cond:
+	// result: (TESTL x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (CMPLconst (ANDLconst [c] x) [0])
+	// cond:
+	// result: (TESTLconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMPLconst x [0])
+	// cond:
+	// result: (TESTL x x)
+	for {
+		x := v.Args[0]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTL)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMPQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (CMPQconst x [c])
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64CMPQconst)
+		v.AddArg(x)
+		v.AuxInt = c
+		return true
+	}
+	// match: (CMPQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (InvertFlags (CMPQconst x [c]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64InvertFlags)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v0.AddArg(x)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMPQconst (MOVQconst [x]) [y])
+	// cond: x==y
+	// result: (FlagEQ)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(x == y) {
+			break
+		}
+		v.reset(OpAMD64FlagEQ)
+		return true
+	}
+	// match: (CMPQconst (MOVQconst [x]) [y])
+	// cond: x<y && uint64(x)<uint64(y)
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(x < y && uint64(x) < uint64(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPQconst (MOVQconst [x]) [y])
+	// cond: x<y && uint64(x)>uint64(y)
+	// result: (FlagLT_UGT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(x < y && uint64(x) > uint64(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_UGT)
+		return true
+	}
+	// match: (CMPQconst (MOVQconst [x]) [y])
+	// cond: x>y && uint64(x)<uint64(y)
+	// result: (FlagGT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(x > y && uint64(x) < uint64(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagGT_ULT)
+		return true
+	}
+	// match: (CMPQconst (MOVQconst [x]) [y])
+	// cond: x>y && uint64(x)>uint64(y)
+	// result: (FlagGT_UGT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(x > y && uint64(x) > uint64(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagGT_UGT)
+		return true
+	}
+	// match: (CMPQconst (MOVBQZX _) [c])
+	// cond: 0xFF < c
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVBQZX {
+			break
+		}
+		c := v.AuxInt
+		if !(0xFF < c) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPQconst (MOVWQZX _) [c])
+	// cond: 0xFFFF < c
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVWQZX {
+			break
+		}
+		c := v.AuxInt
+		if !(0xFFFF < c) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPQconst (MOVLQZX _) [c])
+	// cond: 0xFFFFFFFF < c
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLQZX {
+			break
+		}
+		c := v.AuxInt
+		if !(0xFFFFFFFF < c) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPQconst (SHRQconst _ [c]) [n])
+	// cond: 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHRQconst {
+			break
+		}
+		c := v_0.AuxInt
+		n := v.AuxInt
+		if !(0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPQconst (ANDQconst _ [m]) [n])
+	// cond: 0 <= m && m < n
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		m := v_0.AuxInt
+		n := v.AuxInt
+		if !(0 <= m && m < n) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPQconst (ANDQ x y) [0])
+	// cond:
+	// result: (TESTQ x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQ {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (CMPQconst (ANDQconst [c] x) [0])
+	// cond:
+	// result: (TESTQconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMPQconst x [0])
+	// cond:
+	// result: (TESTQ x x)
+	for {
+		x := v.Args[0]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTQ)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMPW x (MOVLconst [c]))
+	// cond:
+	// result: (CMPWconst x [int64(int16(c))])
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64CMPWconst)
+		v.AddArg(x)
+		v.AuxInt = int64(int16(c))
+		return true
+	}
+	// match: (CMPW (MOVLconst [c]) x)
+	// cond:
+	// result: (InvertFlags (CMPWconst x [int64(int16(c))]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64InvertFlags)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v0.AddArg(x)
+		v0.AuxInt = int64(int16(c))
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (CMPWconst (MOVLconst [x]) [y])
+	// cond: int16(x)==int16(y)
+	// result: (FlagEQ)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int16(x) == int16(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagEQ)
+		return true
+	}
+	// match: (CMPWconst (MOVLconst [x]) [y])
+	// cond: int16(x)<int16(y) && uint16(x)<uint16(y)
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int16(x) < int16(y) && uint16(x) < uint16(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPWconst (MOVLconst [x]) [y])
+	// cond: int16(x)<int16(y) && uint16(x)>uint16(y)
+	// result: (FlagLT_UGT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int16(x) < int16(y) && uint16(x) > uint16(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_UGT)
+		return true
+	}
+	// match: (CMPWconst (MOVLconst [x]) [y])
+	// cond: int16(x)>int16(y) && uint16(x)<uint16(y)
+	// result: (FlagGT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int16(x) > int16(y) && uint16(x) < uint16(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagGT_ULT)
+		return true
+	}
+	// match: (CMPWconst (MOVLconst [x]) [y])
+	// cond: int16(x)>int16(y) && uint16(x)>uint16(y)
+	// result: (FlagGT_UGT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		x := v_0.AuxInt
+		y := v.AuxInt
+		if !(int16(x) > int16(y) && uint16(x) > uint16(y)) {
+			break
+		}
+		v.reset(OpAMD64FlagGT_UGT)
+		return true
+	}
+	// match: (CMPWconst (ANDLconst _ [m]) [n])
+	// cond: 0 <= int16(m) && int16(m) < int16(n)
+	// result: (FlagLT_ULT)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		m := v_0.AuxInt
+		n := v.AuxInt
+		if !(0 <= int16(m) && int16(m) < int16(n)) {
+			break
+		}
+		v.reset(OpAMD64FlagLT_ULT)
+		return true
+	}
+	// match: (CMPWconst (ANDL x y) [0])
+	// cond:
+	// result: (TESTW x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDL {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTW)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (CMPWconst (ANDLconst [c] x) [0])
+	// cond:
+	// result: (TESTWconst [int64(int16(c))] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTWconst)
+		v.AuxInt = int64(int16(c))
+		v.AddArg(x)
+		return true
+	}
+	// match: (CMPWconst x [0])
+	// cond:
+	// result: (TESTW x x)
+	for {
+		x := v.Args[0]
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64TESTW)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpClosureCall(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ClosureCall [argwid] entry closure mem)
+	// cond:
+	// result: (CALLclosure [argwid] entry closure mem)
+	for {
+		argwid := v.AuxInt
+		entry := v.Args[0]
+		closure := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64CALLclosure)
+		v.AuxInt = argwid
+		v.AddArg(entry)
+		v.AddArg(closure)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCom16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Com16 x)
+	// cond:
+	// result: (NOTL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NOTL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCom32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Com32 x)
+	// cond:
+	// result: (NOTL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NOTL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCom64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Com64 x)
+	// cond:
+	// result: (NOTQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NOTQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCom8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Com8  x)
+	// cond:
+	// result: (NOTL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NOTL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Const16  [val])
+	// cond:
+	// result: (MOVLconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Const32  [val])
+	// cond:
+	// result: (MOVLconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Const32F [val])
+	// cond:
+	// result: (MOVSSconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVSSconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Const64  [val])
+	// cond:
+	// result: (MOVQconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Const64F [val])
+	// cond:
+	// result: (MOVSDconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVSDconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConst8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Const8   [val])
+	// cond:
+	// result: (MOVLconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueAMD64_OpConstBool(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ConstBool [b])
+	// cond:
+	// result: (MOVLconst [b])
+	for {
+		b := v.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = b
+		return true
+	}
+}
+func rewriteValueAMD64_OpConstNil(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ConstNil)
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+}
+func rewriteValueAMD64_OpConvert(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Convert <t> x mem)
+	// cond:
+	// result: (MOVQconvert <t> x mem)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQconvert)
+		v.Type = t
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCtz16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Ctz16 <t> x)
+	// cond:
+	// result: (CMOVWEQconst (BSFW <t> x) (CMPWconst x [0]) [16])
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v.reset(OpAMD64CMOVWEQconst)
+		v0 := b.NewValue0(v.Line, OpAMD64BSFW, t)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v1.AddArg(x)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v.AuxInt = 16
+		return true
+	}
+}
+func rewriteValueAMD64_OpCtz32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Ctz32 <t> x)
+	// cond:
+	// result: (CMOVLEQconst (BSFL <t> x) (CMPLconst x [0]) [32])
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v.reset(OpAMD64CMOVLEQconst)
+		v0 := b.NewValue0(v.Line, OpAMD64BSFL, t)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v1.AddArg(x)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v.AuxInt = 32
+		return true
+	}
+}
+func rewriteValueAMD64_OpCtz64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Ctz64 <t> x)
+	// cond:
+	// result: (CMOVQEQconst (BSFQ <t> x) (CMPQconst x [0]) [64])
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v.reset(OpAMD64CMOVQEQconst)
+		v0 := b.NewValue0(v.Line, OpAMD64BSFQ, t)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v1.AddArg(x)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v.AuxInt = 64
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32Fto32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt32Fto32 x)
+	// cond:
+	// result: (CVTTSS2SL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTTSS2SL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32Fto64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt32Fto64 x)
+	// cond:
+	// result: (CVTTSS2SQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTTSS2SQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32Fto64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt32Fto64F x)
+	// cond:
+	// result: (CVTSS2SD x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSS2SD)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32to32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt32to32F x)
+	// cond:
+	// result: (CVTSL2SS x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSL2SS)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt32to64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt32to64F x)
+	// cond:
+	// result: (CVTSL2SD x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSL2SD)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64Fto32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt64Fto32 x)
+	// cond:
+	// result: (CVTTSD2SL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTTSD2SL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64Fto32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt64Fto32F x)
+	// cond:
+	// result: (CVTSD2SS x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSD2SS)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64Fto64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt64Fto64 x)
+	// cond:
+	// result: (CVTTSD2SQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTTSD2SQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64to32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt64to32F x)
+	// cond:
+	// result: (CVTSQ2SS x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSQ2SS)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpCvt64to64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt64to64F x)
+	// cond:
+	// result: (CVTSQ2SD x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64CVTSQ2SD)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDeferCall(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (DeferCall [argwid] mem)
+	// cond:
+	// result: (CALLdefer [argwid] mem)
+	for {
+		argwid := v.AuxInt
+		mem := v.Args[0]
+		v.reset(OpAMD64CALLdefer)
+		v.AuxInt = argwid
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div16  x y)
+	// cond:
+	// result: (DIVW  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVW)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv16u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div16u x y)
+	// cond:
+	// result: (DIVWU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVWU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div32  x y)
+	// cond:
+	// result: (DIVL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div32F x y)
+	// cond:
+	// result: (DIVSS x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVSS)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv32u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div32u x y)
+	// cond:
+	// result: (DIVLU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVLU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div64  x y)
+	// cond:
+	// result: (DIVQ  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div64F x y)
+	// cond:
+	// result: (DIVSD x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVSD)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv64u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div64u x y)
+	// cond:
+	// result: (DIVQU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVQU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div8   x y)
+	// cond:
+	// result: (DIVW  (SignExt8to16 x) (SignExt8to16 y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVW)
+		v0 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpDiv8u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div8u  x y)
+	// cond:
+	// result: (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64DIVWU)
+		v0 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq16  x y)
+	// cond:
+	// result: (SETEQ (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq32  x y)
+	// cond:
+	// result: (SETEQ (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq32F x y)
+	// cond:
+	// result: (SETEQF (UCOMISS x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq64  x y)
+	// cond:
+	// result: (SETEQ (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq64F x y)
+	// cond:
+	// result: (SETEQF (UCOMISD x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEq8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq8   x y)
+	// cond:
+	// result: (SETEQ (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEqB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (EqB   x y)
+	// cond:
+	// result: (SETEQ (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpEqPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (EqPtr x y)
+	// cond:
+	// result: (SETEQ (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETEQ)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq16  x y)
+	// cond:
+	// result: (SETGE (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq16U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq16U x y)
+	// cond:
+	// result: (SETAE (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq32  x y)
+	// cond:
+	// result: (SETGE (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq32F x y)
+	// cond:
+	// result: (SETGEF (UCOMISS x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGEF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq32U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq32U x y)
+	// cond:
+	// result: (SETAE (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq64  x y)
+	// cond:
+	// result: (SETGE (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq64F x y)
+	// cond:
+	// result: (SETGEF (UCOMISD x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGEF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq64U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq64U x y)
+	// cond:
+	// result: (SETAE (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq8   x y)
+	// cond:
+	// result: (SETGE (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGeq8U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq8U  x y)
+	// cond:
+	// result: (SETAE (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETAE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGetClosurePtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (GetClosurePtr)
+	// cond:
+	// result: (LoweredGetClosurePtr)
+	for {
+		v.reset(OpAMD64LoweredGetClosurePtr)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGetG(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (GetG mem)
+	// cond:
+	// result: (LoweredGetG mem)
+	for {
+		mem := v.Args[0]
+		v.reset(OpAMD64LoweredGetG)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGoCall(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (GoCall [argwid] mem)
+	// cond:
+	// result: (CALLgo [argwid] mem)
+	for {
+		argwid := v.AuxInt
+		mem := v.Args[0]
+		v.reset(OpAMD64CALLgo)
+		v.AuxInt = argwid
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater16  x y)
+	// cond:
+	// result: (SETG (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETG)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater16U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater16U x y)
+	// cond:
+	// result: (SETA (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETA)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater32  x y)
+	// cond:
+	// result: (SETG (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETG)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater32F x y)
+	// cond:
+	// result: (SETGF (UCOMISS x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater32U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater32U x y)
+	// cond:
+	// result: (SETA (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETA)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater64  x y)
+	// cond:
+	// result: (SETG (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETG)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater64F x y)
+	// cond:
+	// result: (SETGF (UCOMISD x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater64U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater64U x y)
+	// cond:
+	// result: (SETA (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETA)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater8   x y)
+	// cond:
+	// result: (SETG (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETG)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpGreater8U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater8U  x y)
+	// cond:
+	// result: (SETA (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETA)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Hmul16  x y)
+	// cond:
+	// result: (HMULW  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULW)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul16u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Hmul16u x y)
+	// cond:
+	// result: (HMULWU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULWU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Hmul32  x y)
+	// cond:
+	// result: (HMULL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul32u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Hmul32u x y)
+	// cond:
+	// result: (HMULLU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULLU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Hmul64  x y)
+	// cond:
+	// result: (HMULQ  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul64u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Hmul64u x y)
+	// cond:
+	// result: (HMULQU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULQU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Hmul8   x y)
+	// cond:
+	// result: (HMULB  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULB)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpHmul8u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Hmul8u  x y)
+	// cond:
+	// result: (HMULBU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64HMULBU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpITab(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ITab (Load ptr mem))
+	// cond:
+	// result: (MOVQload ptr mem)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLoad {
+			break
+		}
+		ptr := v_0.Args[0]
+		mem := v_0.Args[1]
+		v.reset(OpAMD64MOVQload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpInterCall(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (InterCall [argwid] entry mem)
+	// cond:
+	// result: (CALLinter [argwid] entry mem)
+	for {
+		argwid := v.AuxInt
+		entry := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64CALLinter)
+		v.AuxInt = argwid
+		v.AddArg(entry)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpIsInBounds(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (IsInBounds idx len)
+	// cond:
+	// result: (SETB (CMPQ idx len))
+	for {
+		idx := v.Args[0]
+		len := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(idx)
+		v0.AddArg(len)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpIsNonNil(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (IsNonNil p)
+	// cond:
+	// result: (SETNE (TESTQ p p))
+	for {
+		p := v.Args[0]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Line, OpAMD64TESTQ, TypeFlags)
+		v0.AddArg(p)
+		v0.AddArg(p)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpIsSliceInBounds(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (IsSliceInBounds idx len)
+	// cond:
+	// result: (SETBE (CMPQ idx len))
+	for {
+		idx := v.Args[0]
+		len := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(idx)
+		v0.AddArg(len)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (LEAQ [c] {s} (ADDQconst [d] x))
+	// cond: is32Bit(c+d)
+	// result: (LEAQ [c+d] {s} x)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(is32Bit(c + d)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		return true
+	}
+	// match: (LEAQ [c] {s} (ADDQ x y))
+	// cond: x.Op != OpSB && y.Op != OpSB
+	// result: (LEAQ1 [c] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if !(x.Op != OpSB && y.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x))
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (LEAQ [off1+off2] {mergeSym(sym1,sym2)} x)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		x := v_0.Args[0]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		return true
+	}
+	// match: (LEAQ [off1] {sym1} (LEAQ1 [off2] {sym2} x y))
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ [off1] {sym1} (LEAQ2 [off2] {sym2} x y))
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ2 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ2)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ [off1] {sym1} (LEAQ4 [off2] {sym2} x y))
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ4 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ4)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ [off1] {sym1} (LEAQ8 [off2] {sym2} x y))
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ8 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64LEAQ8)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (LEAQ1 [c] {s} (ADDQconst [d] x) y)
+	// cond: is32Bit(c+d)   && x.Op != OpSB
+	// result: (LEAQ1 [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(is32Bit(c+d) && x.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ1 [c] {s} x (ADDQconst [d] y))
+	// cond: is32Bit(c+d)   && y.Op != OpSB
+	// result: (LEAQ1 [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(is32Bit(c+d) && y.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ1 [c] {s} x (SHLQconst [1] y))
+	// cond:
+	// result: (LEAQ2 [c] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ2)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ1 [c] {s} (SHLQconst [1] x) y)
+	// cond:
+	// result: (LEAQ2 [c] {s} y x)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_0.AuxInt != 1 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64LEAQ2)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	// match: (LEAQ1 [c] {s} x (SHLQconst [2] y))
+	// cond:
+	// result: (LEAQ4 [c] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 2 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ1 [c] {s} (SHLQconst [2] x) y)
+	// cond:
+	// result: (LEAQ4 [c] {s} y x)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_0.AuxInt != 2 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64LEAQ4)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	// match: (LEAQ1 [c] {s} x (SHLQconst [3] y))
+	// cond:
+	// result: (LEAQ8 [c] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 3 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ1 [c] {s} (SHLQconst [3] x) y)
+	// cond:
+	// result: (LEAQ8 [c] {s} y x)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_0.AuxInt != 3 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64LEAQ8)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	// match: (LEAQ1 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+	// result: (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ1 [off1] {sym1} x (LEAQ [off2] {sym2} y))
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB
+	// result: (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		y := v_1.Args[0]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64LEAQ2(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (LEAQ2 [c] {s} (ADDQconst [d] x) y)
+	// cond: is32Bit(c+d)   && x.Op != OpSB
+	// result: (LEAQ2 [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(is32Bit(c+d) && x.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ2)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ2 [c] {s} x (ADDQconst [d] y))
+	// cond: is32Bit(c+2*d) && y.Op != OpSB
+	// result: (LEAQ2 [c+2*d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(is32Bit(c+2*d) && y.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ2)
+		v.AuxInt = c + 2*d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ2 [c] {s} x (SHLQconst [1] y))
+	// cond:
+	// result: (LEAQ4 [c] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ2 [c] {s} x (SHLQconst [2] y))
+	// cond:
+	// result: (LEAQ8 [c] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 2 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ2 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+	// result: (LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ2)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64LEAQ4(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (LEAQ4 [c] {s} (ADDQconst [d] x) y)
+	// cond: is32Bit(c+d)   && x.Op != OpSB
+	// result: (LEAQ4 [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(is32Bit(c+d) && x.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ4)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ4 [c] {s} x (ADDQconst [d] y))
+	// cond: is32Bit(c+4*d) && y.Op != OpSB
+	// result: (LEAQ4 [c+4*d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(is32Bit(c+4*d) && y.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ4)
+		v.AuxInt = c + 4*d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ4 [c] {s} x (SHLQconst [1] y))
+	// cond:
+	// result: (LEAQ8 [c] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AuxInt = c
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ4 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+	// result: (LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ4)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64LEAQ8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (LEAQ8 [c] {s} (ADDQconst [d] x) y)
+	// cond: is32Bit(c+d)   && x.Op != OpSB
+	// result: (LEAQ8 [c+d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(is32Bit(c+d) && x.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ8)
+		v.AuxInt = c + d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ8 [c] {s} x (ADDQconst [d] y))
+	// cond: is32Bit(c+8*d) && y.Op != OpSB
+	// result: (LEAQ8 [c+8*d] {s} x y)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		y := v_1.Args[0]
+		if !(is32Bit(c+8*d) && y.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ8)
+		v.AuxInt = c + 8*d
+		v.Aux = s
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (LEAQ8 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+	// result: (LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		x := v_0.Args[0]
+		y := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64LEAQ8)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpLeq16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq16  x y)
+	// cond:
+	// result: (SETLE (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETLE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq16U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq16U x y)
+	// cond:
+	// result: (SETBE (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq32  x y)
+	// cond:
+	// result: (SETLE (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETLE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq32F x y)
+	// cond:
+	// result: (SETGEF (UCOMISS y x))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGEF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+		v0.AddArg(y)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq32U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq32U x y)
+	// cond:
+	// result: (SETBE (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq64  x y)
+	// cond:
+	// result: (SETLE (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETLE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq64F x y)
+	// cond:
+	// result: (SETGEF (UCOMISD y x))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGEF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+		v0.AddArg(y)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq64U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq64U x y)
+	// cond:
+	// result: (SETBE (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq8   x y)
+	// cond:
+	// result: (SETLE (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETLE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLeq8U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq8U  x y)
+	// cond:
+	// result: (SETBE (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETBE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less16  x y)
+	// cond:
+	// result: (SETL (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETL)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess16U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less16U x y)
+	// cond:
+	// result: (SETB (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less32  x y)
+	// cond:
+	// result: (SETL (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETL)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less32F x y)
+	// cond:
+	// result: (SETGF (UCOMISS y x))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+		v0.AddArg(y)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess32U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less32U x y)
+	// cond:
+	// result: (SETB (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less64  x y)
+	// cond:
+	// result: (SETL (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETL)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less64F x y)
+	// cond:
+	// result: (SETGF (UCOMISD y x))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETGF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+		v0.AddArg(y)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess64U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less64U x y)
+	// cond:
+	// result: (SETB (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less8   x y)
+	// cond:
+	// result: (SETL (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETL)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLess8U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less8U  x y)
+	// cond:
+	// result: (SETB (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETB)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLoad(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Load <t> ptr mem)
+	// cond: (is64BitInt(t) || isPtr(t))
+	// result: (MOVQload ptr mem)
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is64BitInt(t) || isPtr(t)) {
+			break
+		}
+		v.reset(OpAMD64MOVQload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: is32BitInt(t)
+	// result: (MOVLload ptr mem)
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is32BitInt(t)) {
+			break
+		}
+		v.reset(OpAMD64MOVLload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: is16BitInt(t)
+	// result: (MOVWload ptr mem)
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is16BitInt(t)) {
+			break
+		}
+		v.reset(OpAMD64MOVWload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: (t.IsBoolean() || is8BitInt(t))
+	// result: (MOVBload ptr mem)
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsBoolean() || is8BitInt(t)) {
+			break
+		}
+		v.reset(OpAMD64MOVBload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: is32BitFloat(t)
+	// result: (MOVSSload ptr mem)
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is32BitFloat(t)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: is64BitFloat(t)
+	// result: (MOVSDload ptr mem)
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is64BitFloat(t)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpLrot16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lrot16 <t> x [c])
+	// cond:
+	// result: (ROLWconst <t> [c&15] x)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		c := v.AuxInt
+		v.reset(OpAMD64ROLWconst)
+		v.Type = t
+		v.AuxInt = c & 15
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLrot32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lrot32 <t> x [c])
+	// cond:
+	// result: (ROLLconst <t> [c&31] x)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		c := v.AuxInt
+		v.reset(OpAMD64ROLLconst)
+		v.Type = t
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLrot64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lrot64 <t> x [c])
+	// cond:
+	// result: (ROLQconst <t> [c&63] x)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		c := v.AuxInt
+		v.reset(OpAMD64ROLQconst)
+		v.Type = t
+		v.AuxInt = c & 63
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLrot8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lrot8  <t> x [c])
+	// cond:
+	// result: (ROLBconst <t> [c&7] x)
+	for {
+		t := v.Type
+		x := v.Args[0]
+		c := v.AuxInt
+		v.reset(OpAMD64ROLBconst)
+		v.Type = t
+		v.AuxInt = c & 7
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh16x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x16 <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh16x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x32 <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh16x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x64 <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh16x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x8  <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh32x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x16 <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh32x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x32 <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh32x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x64 <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh32x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x8  <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh64x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x16 <t> x y)
+	// cond:
+	// result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 64
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh64x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x32 <t> x y)
+	// cond:
+	// result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 64
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh64x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x64 <t> x y)
+	// cond:
+	// result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 64
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh64x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x8  <t> x y)
+	// cond:
+	// result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPBconst y [64])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 64
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh8x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x16 <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh8x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x32 <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh8x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x64 <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpLsh8x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x8  <t> x y)
+	// cond:
+	// result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVBQSX x:(MOVBload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVBload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVBQSXload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVBQSX (ANDLconst [c] x))
+	// cond: c & 0x80 == 0
+	// result: (ANDLconst [c & 0x7f] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(c&0x80 == 0) {
+			break
+		}
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c & 0x7f
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVBQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVBQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVBQSXload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVBQZX x:(MOVBload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVBload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVBload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		idx := x.Args[1]
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVBloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVBQZX (ANDLconst [c] x))
+	// cond:
+	// result: (ANDLconst [c & 0xff] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c & 0xff
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: x
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVBstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVBload  [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVBload  [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVBload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVBload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVBload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVBloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVBloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBload [off] {sym} (ADDQ ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVBloadidx1 [off] {sym} ptr idx mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVBloadidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBloadidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVBloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVBstore [off] {sym} ptr (MOVBQSX x) mem)
+	// cond:
+	// result: (MOVBstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVBQSX {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstore [off] {sym} ptr (MOVBQZX x) mem)
+	// cond:
+	// result: (MOVBstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVBQZX {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstore  [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVBstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVBstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstore [off] {sym} ptr (MOVLconst [c]) mem)
+	// cond: validOff(off)
+	// result: (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(validOff(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVBstoreconst)
+		v.AuxInt = makeValAndOff(int64(int8(c)), off)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVBstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVBstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVBstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVBstoreidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstore [off] {sym} (ADDQ ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVBstoreidx1 [off] {sym} ptr idx val mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVBstoreidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstore [i] {s} p (SHRQconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstore [i-1] {s} p w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
+			break
+		}
+		if v_1.AuxInt != 8 {
+			break
+		}
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVBstore {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if w != x.Args[1] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstore [i] {s} p (SHRQconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRQconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstore [i-1] {s} p w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
+			break
+		}
+		j := v_1.AuxInt
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVBstore {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		if w0.Op != OpAMD64SHRQconst {
+			break
+		}
+		if w0.AuxInt != j-8 {
+			break
+		}
+		if w != w0.Args[0] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVBstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	for {
+		sc := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVBstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
+	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+	// result: (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	for {
+		sc := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVBstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVBstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVBstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreconst [x] {sym} (ADDQ ptr idx) mem)
+	// cond:
+	// result: (MOVBstoreconstidx1 [x] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVBstoreconstidx1)
+		v.AuxInt = x
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
+	// cond: x.Uses == 1   && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		x := v.Args[1]
+		if x.Op != OpAMD64MOVBstoreconst {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		mem := x.Args[1]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVBstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// cond:
+	// result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
+	// cond: x.Uses == 1   && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVBstoreconstidx1 {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if i != x.Args[1] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreconstidx1)
+		v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(i)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVBstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVBstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVBstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx1 [i] {s} p idx (SHRQconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		if v_2.AuxInt != 8 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVBstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreidx1)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVBstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRQconst [j-8] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVBstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-1 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpAMD64SHRQconst {
+			break
+		}
+		if w0.AuxInt != j-8 {
+			break
+		}
+		if w != w0.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreidx1)
+		v.AuxInt = i - 1
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLQSX x:(MOVLload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLQSXload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVLQSX (ANDLconst [c] x))
+	// cond: c & 0x80000000 == 0
+	// result: (ANDLconst [c & 0x7fffffff] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(c&0x80000000 == 0) {
+			break
+		}
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c & 0x7fffffff
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLQSXload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVLQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLQSXload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLQZX x:(MOVLload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLloadidx1 {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		idx := x.Args[1]
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVLloadidx4 {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		idx := x.Args[1]
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx4, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVLQZX (ANDLconst [c] x))
+	// cond:
+	// result: (ANDLconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: x
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVLload  [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVLload  [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVLload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVLloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLload [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ4 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLloadidx4)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLload [off] {sym} (ADDQ ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVLloadidx1 [off] {sym} ptr idx mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVLloadidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLloadidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
+	// cond:
+	// result: (MOVLloadidx4 [c] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 2 {
+			break
+		}
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLloadidx4)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLloadidx4(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVLloadidx4 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLloadidx4)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVLloadidx4 [c+4*d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLloadidx4)
+		v.AuxInt = c + 4*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLstore [off] {sym} ptr (MOVLQSX x) mem)
+	// cond:
+	// result: (MOVLstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLQSX {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstore [off] {sym} ptr (MOVLQZX x) mem)
+	// cond:
+	// result: (MOVLstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLQZX {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstore  [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVLstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstore [off] {sym} ptr (MOVLconst [c]) mem)
+	// cond: validOff(off)
+	// result: (MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(validOff(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = makeValAndOff(int64(int32(c)), off)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVLstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVLstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstore [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVLstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ4 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreidx4)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstore [off] {sym} (ADDQ ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVLstoreidx1 [off] {sym} ptr idx val mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstore [i] {s} p (SHRQconst [32] w) x:(MOVLstore [i-4] {s} p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVQstore [i-4] {s} p w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
+			break
+		}
+		if v_1.AuxInt != 32 {
+			break
+		}
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVLstore {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if w != x.Args[1] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstore)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstore [i] {s} p (SHRQconst [j] w) x:(MOVLstore [i-4] {s} p w0:(SHRQconst [j-32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVQstore [i-4] {s} p w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
+			break
+		}
+		j := v_1.AuxInt
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVLstore {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		if w0.Op != OpAMD64SHRQconst {
+			break
+		}
+		if w0.AuxInt != j-32 {
+			break
+		}
+		if w != w0.Args[0] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstore)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVLstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	for {
+		sc := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
+	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+	// result: (MOVLstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	for {
+		sc := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconst [x] {sym1} (LEAQ4 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ4 {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreconstidx4)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconst [x] {sym} (ADDQ ptr idx) mem)
+	// cond:
+	// result: (MOVLstoreconstidx1 [x] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVLstoreconstidx1)
+		v.AuxInt = x
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem))
+	// cond: x.Uses == 1   && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		x := v.Args[1]
+		if x.Op != OpAMD64MOVLstoreconst {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		mem := x.Args[1]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstore)
+		v.AuxInt = ValAndOff(a).Off()
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+		v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLstoreconstidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
+	// cond:
+	// result: (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 2 {
+			break
+		}
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstoreconstidx4)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// cond:
+	// result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconstidx1 [c] {s} p i x:(MOVLstoreconstidx1 [a] {s} p i mem))
+	// cond: x.Uses == 1   && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p i (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVLstoreconstidx1 {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if i != x.Args[1] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = ValAndOff(a).Off()
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(i)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+		v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstoreconstidx4(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLstoreconstidx4 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstoreconstidx4)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconstidx4 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// cond:
+	// result: (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstoreconstidx4)
+		v.AuxInt = ValAndOff(x).add(4 * c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreconstidx4 [c] {s} p i x:(MOVLstoreconstidx4 [a] {s} p i mem))
+	// cond: x.Uses == 1   && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVQstoreidx1 [ValAndOff(a).Off()] {s} p (SHLQconst <i.Type> [2] i) (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVLstoreconstidx4 {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if i != x.Args[1] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = ValAndOff(a).Off()
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, i.Type)
+		v0.AuxInt = 2
+		v0.AddArg(i)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+		v1.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+		v.AddArg(v1)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstoreidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLstoreidx1 [c] {sym} ptr (SHLQconst [2] idx) val mem)
+	// cond:
+	// result: (MOVLstoreidx4 [c] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 2 {
+			break
+		}
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVLstoreidx4)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreidx1 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx1 [i-4] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVQstoreidx1 [i-4] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		if v_2.AuxInt != 32 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVLstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx1 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVQstoreidx1 [i-4] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVLstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpAMD64SHRQconst {
+			break
+		}
+		if w0.AuxInt != j-32 {
+			break
+		}
+		if w != w0.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstoreidx4(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVLstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVLstoreidx4 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVLstoreidx4)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVLstoreidx4 [c+4*d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVLstoreidx4)
+		v.AuxInt = c + 4*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreidx4 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx4 [i-4] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		if v_2.AuxInt != 32 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVLstoreidx4 {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+		v0.AuxInt = 2
+		v0.AddArg(idx)
+		v.AddArg(v0)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVLstoreidx4 [i] {s} p idx (SHRQconst [j] w) x:(MOVLstoreidx4 [i-4] {s} p idx w0:(SHRQconst [j-32] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVLstoreidx4 {
+			break
+		}
+		if x.AuxInt != i-4 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpAMD64SHRQconst {
+			break
+		}
+		if w0.AuxInt != j-32 {
+			break
+		}
+		if w != w0.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = i - 4
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+		v0.AuxInt = 2
+		v0.AddArg(idx)
+		v.AddArg(v0)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVOload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVOload  [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVOload  [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVOload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVOload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVOload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVOload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVOstore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVOstore  [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVOstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVOstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVOstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVOstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVOstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: x
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVQload  [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVQload  [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVQload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVQloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVQloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ8 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQloadidx8)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQload [off] {sym} (ADDQ ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVQloadidx1 [off] {sym} ptr idx mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVQloadidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQloadidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVQloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
+	// cond:
+	// result: (MOVQloadidx8 [c] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 3 {
+			break
+		}
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQloadidx8)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVQloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVQloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQloadidx8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVQloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVQloadidx8 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQloadidx8)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVQloadidx8 [c+8*d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQloadidx8)
+		v.AuxInt = c + 8*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVQstore  [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVQstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstore [off] {sym} ptr (MOVQconst [c]) mem)
+	// cond: validValAndOff(c,off)
+	// result: (MOVQstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(validValAndOff(c, off)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = makeValAndOff(c, off)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVQstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVQstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVQstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ8 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx8)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstore [off] {sym} (ADDQ ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVQstoreidx1 [off] {sym} ptr idx val mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVQstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVQstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	for {
+		sc := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
+	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+	// result: (MOVQstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	for {
+		sc := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVQstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreconst [x] {sym1} (LEAQ8 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVQstoreconstidx8 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ8 {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVQstoreconstidx8)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreconst [x] {sym} (ADDQ ptr idx) mem)
+	// cond:
+	// result: (MOVQstoreconstidx1 [x] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQstoreconstidx1)
+		v.AuxInt = x
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreconstidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVQstoreconstidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
+	// cond:
+	// result: (MOVQstoreconstidx8 [c] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 3 {
+			break
+		}
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQstoreconstidx8)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVQstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// cond:
+	// result: (MOVQstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreconstidx8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVQstoreconstidx8 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVQstoreconstidx8 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQstoreconstidx8)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreconstidx8 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// cond:
+	// result: (MOVQstoreconstidx8 [ValAndOff(x).add(8*c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQstoreconstidx8)
+		v.AuxInt = ValAndOff(x).add(8 * c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVQstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem)
+	// cond:
+	// result: (MOVQstoreidx8 [c] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 3 {
+			break
+		}
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVQstoreidx8)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVQstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVQstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVQstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreidx8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVQstoreidx8 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVQstoreidx8 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVQstoreidx8)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVQstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVQstoreidx8 [c+8*d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVQstoreidx8)
+		v.AuxInt = c + 8*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSDload [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVSDload [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ8 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDloadidx8)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDload [off] {sym} (ADDQ ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVSDloadidx1 [off] {sym} ptr idx mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVSDloadidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDloadidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSDloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVSDloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVSDloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDloadidx8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSDloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVSDloadidx8 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVSDloadidx8)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVSDloadidx8 [c+8*d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVSDloadidx8)
+		v.AuxInt = c + 8*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDstore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSDstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVSDstore [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDstoreidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ8 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDstoreidx8)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDstore [off] {sym} (ADDQ ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVSDstoreidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDstoreidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSDstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVSDstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVSDstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDstoreidx8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSDstoreidx8 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVSDstoreidx8 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVSDstoreidx8)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSDstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVSDstoreidx8)
+		v.AuxInt = c + 8*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSSload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSSload [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVSSload [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSSloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSload [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSSloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ4 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSloadidx4)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSload [off] {sym} (ADDQ ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVSSloadidx1 [off] {sym} ptr idx mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVSSloadidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSSloadidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSSloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVSSloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVSSloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSSloadidx4(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSSloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVSSloadidx4 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVSSloadidx4)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVSSloadidx4 [c+4*d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVSSloadidx4)
+		v.AuxInt = c + 4*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSSstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVSSstore [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSSstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSstoreidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSstore [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ4 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSstoreidx4)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSstore [off] {sym} (ADDQ ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVSSstoreidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSSstoreidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSSstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVSSstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVSSstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVSSstoreidx4(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVSSstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVSSstoreidx4 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVSSstoreidx4)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVSSstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVSSstoreidx4 [c+4*d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVSSstoreidx4)
+		v.AuxInt = c + 4*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWQSX x:(MOVWload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVWload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVWQSXload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVWQSX (ANDLconst [c] x))
+	// cond: c & 0x8000 == 0
+	// result: (ANDLconst [c & 0x7fff] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		if !(c&0x8000 == 0) {
+			break
+		}
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c & 0x7fff
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWQSXload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWQSXload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWQZX x:(MOVWload [off] {sym} ptr mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVWload {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVWload, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVWQZX x:(MOVWloadidx1 [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVWloadidx1 {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		idx := x.Args[1]
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVWQZX x:(MOVWloadidx2 [off] {sym} ptr idx mem))
+	// cond: x.Uses == 1 && clobber(x)
+	// result: @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
+	for {
+		x := v.Args[0]
+		if x.Op != OpAMD64MOVWloadidx2 {
+			break
+		}
+		off := x.AuxInt
+		sym := x.Aux
+		ptr := x.Args[0]
+		idx := x.Args[1]
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpAMD64MOVWloadidx2, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = off
+		v0.Aux = sym
+		v0.AddArg(ptr)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (MOVWQZX (ANDLconst [c] x))
+	// cond:
+	// result: (ANDLconst [c & 0xffff] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ANDLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v_0.Args[0]
+		v.reset(OpAMD64ANDLconst)
+		v.AuxInt = c & 0xffff
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+	// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+	// result: x
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVWstore {
+			break
+		}
+		off2 := v_1.AuxInt
+		sym2 := v_1.Aux
+		ptr2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MOVWload  [off1] {sym} (ADDQconst [off2] ptr) mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVWload  [off1+off2] {sym} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWload)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWload  [off1+off2] {mergeSym(sym1,sym2)} base mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWloadidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWload [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ2 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWloadidx2)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWload [off] {sym} (ADDQ ptr idx) mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVWloadidx1 [off] {sym} ptr idx mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVWloadidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWloadidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWloadidx1 [c] {sym} ptr (SHLQconst [1] idx) mem)
+	// cond:
+	// result: (MOVWloadidx2 [c] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWloadidx2)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWloadidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWloadidx2(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWloadidx2 [c] {sym} (ADDQconst [d] ptr) idx mem)
+	// cond:
+	// result: (MOVWloadidx2 [c+d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWloadidx2)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWloadidx2 [c] {sym} ptr (ADDQconst [d] idx) mem)
+	// cond:
+	// result: (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWloadidx2)
+		v.AuxInt = c + 2*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWstore [off] {sym} ptr (MOVWQSX x) mem)
+	// cond:
+	// result: (MOVWstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVWQSX {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off] {sym} ptr (MOVWQZX x) mem)
+	// cond:
+	// result: (MOVWstore [off] {sym} ptr x mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVWQZX {
+			break
+		}
+		x := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(x)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore  [off1] {sym} (ADDQconst [off2] ptr) val mem)
+	// cond: is32Bit(off1+off2)
+	// result: (MOVWstore  [off1+off2] {sym} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1 + off2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = off1 + off2
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem)
+	// cond: validOff(off)
+	// result: (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		mem := v.Args[2]
+		if !(validOff(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = makeValAndOff(int64(int16(c)), off)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWstore  [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		base := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(base)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreidx1)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) val mem)
+	// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+	// result: (MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ2 {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreidx2)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [off] {sym} (ADDQ ptr idx) val mem)
+	// cond: ptr.Op != OpSB
+	// result: (MOVWstoreidx1 [off] {sym} ptr idx val mem)
+	for {
+		off := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(ptr.Op != OpSB) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreidx1)
+		v.AuxInt = off
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [i] {s} p (SHRQconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstore [i-2] {s} p w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
+			break
+		}
+		if v_1.AuxInt != 16 {
+			break
+		}
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVWstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if w != x.Args[1] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstore [i] {s} p (SHRQconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRQconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstore [i-2] {s} p w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHRQconst {
+			break
+		}
+		j := v_1.AuxInt
+		w := v_1.Args[0]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVWstore {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		w0 := x.Args[1]
+		if w0.Op != OpAMD64SHRQconst {
+			break
+		}
+		if w0.AuxInt != j-16 {
+			break
+		}
+		if w != w0.Args[0] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstore)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
+	// cond: ValAndOff(sc).canAdd(off)
+	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+	for {
+		sc := v.AuxInt
+		s := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		off := v_0.AuxInt
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = s
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
+	// cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+	// result: (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+	for {
+		sc := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = ValAndOff(sc).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ1 {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconst [x] {sym1} (LEAQ2 [off] {sym2} ptr idx) mem)
+	// cond: canMergeSym(sym1, sym2)
+	// result: (MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64LEAQ2 {
+			break
+		}
+		off := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpAMD64MOVWstoreconstidx2)
+		v.AuxInt = ValAndOff(x).add(off)
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconst [x] {sym} (ADDQ ptr idx) mem)
+	// cond:
+	// result: (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQ {
+			break
+		}
+		ptr := v_0.Args[0]
+		idx := v_0.Args[1]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVWstoreconstidx1)
+		v.AuxInt = x
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
+	// cond: x.Uses == 1   && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		x := v.Args[1]
+		if x.Op != OpAMD64MOVWstoreconst {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		mem := x.Args[1]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWstoreconstidx1 [c] {sym} ptr (SHLQconst [1] idx) mem)
+	// cond:
+	// result: (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstoreconstidx2)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// cond:
+	// result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstoreconstidx1)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
+	// cond: x.Uses == 1   && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVWstoreconstidx1 {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if i != x.Args[1] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreconstidx1)
+		v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(i)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreconstidx2(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWstoreconstidx2 [x] {sym} (ADDQconst [c] ptr) idx mem)
+	// cond:
+	// result: (MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstoreconstidx2)
+		v.AuxInt = ValAndOff(x).add(c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconstidx2 [x] {sym} ptr (ADDQconst [c] idx) mem)
+	// cond:
+	// result: (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
+	for {
+		x := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		c := v_1.AuxInt
+		idx := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstoreconstidx2)
+		v.AuxInt = ValAndOff(x).add(2 * c)
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreconstidx2 [c] {s} p i x:(MOVWstoreconstidx2 [a] {s} p i mem))
+	// cond: x.Uses == 1   && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()   && clobber(x)
+	// result: (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLQconst <i.Type> [1] i) mem)
+	for {
+		c := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		i := v.Args[1]
+		x := v.Args[2]
+		if x.Op != OpAMD64MOVWstoreconstidx2 {
+			break
+		}
+		a := x.AuxInt
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if i != x.Args[1] {
+			break
+		}
+		mem := x.Args[2]
+		if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreconstidx1)
+		v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, i.Type)
+		v0.AuxInt = 1
+		v0.AddArg(i)
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWstoreidx1 [c] {sym} ptr (SHLQconst [1] idx) val mem)
+	// cond:
+	// result: (MOVWstoreidx2 [c] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if v_1.AuxInt != 1 {
+			break
+		}
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVWstoreidx2)
+		v.AuxInt = c
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVWstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVWstoreidx1)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx1 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstoreidx1 [i-2] {s} p idx w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstoreidx1 [i-2] {s} p idx w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVWstoreidx1 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpAMD64SHRQconst {
+			break
+		}
+		if w0.AuxInt != j-16 {
+			break
+		}
+		if w != w0.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v.AddArg(idx)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreidx2(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWstoreidx2 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+	// cond:
+	// result: (MOVWstoreidx2 [c+d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_0.AuxInt
+		ptr := v_0.Args[0]
+		idx := v.Args[1]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVWstoreidx2)
+		v.AuxInt = c + d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx2 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+	// cond:
+	// result: (MOVWstoreidx2 [c+2*d] {sym} ptr idx val mem)
+	for {
+		c := v.AuxInt
+		sym := v.Aux
+		ptr := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ADDQconst {
+			break
+		}
+		d := v_1.AuxInt
+		idx := v_1.Args[0]
+		val := v.Args[2]
+		mem := v.Args[3]
+		v.reset(OpAMD64MOVWstoreidx2)
+		v.AuxInt = c + 2*d
+		v.Aux = sym
+		v.AddArg(ptr)
+		v.AddArg(idx)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx2 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		if v_2.AuxInt != 16 {
+			break
+		}
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVWstoreidx2 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		if w != x.Args[2] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+		v0.AuxInt = 1
+		v0.AddArg(idx)
+		v.AddArg(v0)
+		v.AddArg(w)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (MOVWstoreidx2 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
+	// cond: x.Uses == 1   && clobber(x)
+	// result: (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w0 mem)
+	for {
+		i := v.AuxInt
+		s := v.Aux
+		p := v.Args[0]
+		idx := v.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpAMD64SHRQconst {
+			break
+		}
+		j := v_2.AuxInt
+		w := v_2.Args[0]
+		x := v.Args[3]
+		if x.Op != OpAMD64MOVWstoreidx2 {
+			break
+		}
+		if x.AuxInt != i-2 {
+			break
+		}
+		if x.Aux != s {
+			break
+		}
+		if p != x.Args[0] {
+			break
+		}
+		if idx != x.Args[1] {
+			break
+		}
+		w0 := x.Args[2]
+		if w0.Op != OpAMD64SHRQconst {
+			break
+		}
+		if w0.AuxInt != j-16 {
+			break
+		}
+		if w != w0.Args[0] {
+			break
+		}
+		mem := x.Args[3]
+		if !(x.Uses == 1 && clobber(x)) {
+			break
+		}
+		v.reset(OpAMD64MOVLstoreidx1)
+		v.AuxInt = i - 2
+		v.Aux = s
+		v.AddArg(p)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+		v0.AuxInt = 1
+		v0.AddArg(idx)
+		v.AddArg(v0)
+		v.AddArg(w0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MULL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MULL x (MOVLconst [c]))
+	// cond:
+	// result: (MULLconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64MULLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULL (MOVLconst [c]) x)
+	// cond:
+	// result: (MULLconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64MULLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MULLconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MULLconst [c] (MOVLconst [d]))
+	// cond:
+	// result: (MOVLconst [int64(int32(c*d))])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = int64(int32(c * d))
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MULQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MULQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (MULQconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64MULQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (MULQconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64MULQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64MULQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MULQconst [-1] x)
+	// cond:
+	// result: (NEGQ x)
+	for {
+		if v.AuxInt != -1 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64NEGQ)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [0] _)
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (MULQconst [1] x)
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [3] x)
+	// cond:
+	// result: (LEAQ2 x x)
+	for {
+		if v.AuxInt != 3 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [5] x)
+	// cond:
+	// result: (LEAQ4 x x)
+	for {
+		if v.AuxInt != 5 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [7] x)
+	// cond:
+	// result: (LEAQ8 (NEGQ <v.Type> x) x)
+	for {
+		if v.AuxInt != 7 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v0 := b.NewValue0(v.Line, OpAMD64NEGQ, v.Type)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [9] x)
+	// cond:
+	// result: (LEAQ8 x x)
+	for {
+		if v.AuxInt != 9 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AddArg(x)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [11] x)
+	// cond:
+	// result: (LEAQ2 x (LEAQ4 <v.Type> x x))
+	for {
+		if v.AuxInt != 11 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ2)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [13] x)
+	// cond:
+	// result: (LEAQ4 x (LEAQ2 <v.Type> x x))
+	for {
+		if v.AuxInt != 13 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ2, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [21] x)
+	// cond:
+	// result: (LEAQ4 x (LEAQ4 <v.Type> x x))
+	for {
+		if v.AuxInt != 21 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [25] x)
+	// cond:
+	// result: (LEAQ8 x (LEAQ2 <v.Type> x x))
+	for {
+		if v.AuxInt != 25 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ2, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [37] x)
+	// cond:
+	// result: (LEAQ4 x (LEAQ8 <v.Type> x x))
+	for {
+		if v.AuxInt != 37 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ4)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ8, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [41] x)
+	// cond:
+	// result: (LEAQ8 x (LEAQ4 <v.Type> x x))
+	for {
+		if v.AuxInt != 41 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [73] x)
+	// cond:
+	// result: (LEAQ8 x (LEAQ8 <v.Type> x x))
+	for {
+		if v.AuxInt != 73 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpAMD64LEAQ8)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ8, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [c] x)
+	// cond: isPowerOfTwo(c)
+	// result: (SHLQconst [log2(c)] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpAMD64SHLQconst)
+		v.AuxInt = log2(c)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [c] x)
+	// cond: isPowerOfTwo(c+1) && c >= 15
+	// result: (SUBQ (SHLQconst <v.Type> [log2(c+1)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c+1) && c >= 15) {
+			break
+		}
+		v.reset(OpAMD64SUBQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
+		v0.AuxInt = log2(c + 1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [c] x)
+	// cond: isPowerOfTwo(c-1) && c >= 17
+	// result: (LEAQ1 (SHLQconst <v.Type> [log2(c-1)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-1) && c >= 17) {
+			break
+		}
+		v.reset(OpAMD64LEAQ1)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
+		v0.AuxInt = log2(c - 1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [c] x)
+	// cond: isPowerOfTwo(c-2) && c >= 34
+	// result: (LEAQ2 (SHLQconst <v.Type> [log2(c-2)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-2) && c >= 34) {
+			break
+		}
+		v.reset(OpAMD64LEAQ2)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
+		v0.AuxInt = log2(c - 2)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [c] x)
+	// cond: isPowerOfTwo(c-4) && c >= 68
+	// result: (LEAQ4 (SHLQconst <v.Type> [log2(c-4)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-4) && c >= 68) {
+			break
+		}
+		v.reset(OpAMD64LEAQ4)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
+		v0.AuxInt = log2(c - 4)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [c] x)
+	// cond: isPowerOfTwo(c-8) && c >= 136
+	// result: (LEAQ8 (SHLQconst <v.Type> [log2(c-8)] x) x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(isPowerOfTwo(c-8) && c >= 136) {
+			break
+		}
+		v.reset(OpAMD64LEAQ8)
+		v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
+		v0.AuxInt = log2(c - 8)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (MULQconst [c] x)
+	// cond: c%3 == 0 && isPowerOfTwo(c/3)
+	// result: (SHLQconst [log2(c/3)] (LEAQ2 <v.Type> x x))
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+			break
+		}
+		v.reset(OpAMD64SHLQconst)
+		v.AuxInt = log2(c / 3)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ2, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [c] x)
+	// cond: c%5 == 0 && isPowerOfTwo(c/5)
+	// result: (SHLQconst [log2(c/5)] (LEAQ4 <v.Type> x x))
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+			break
+		}
+		v.reset(OpAMD64SHLQconst)
+		v.AuxInt = log2(c / 5)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [c] x)
+	// cond: c%9 == 0 && isPowerOfTwo(c/9)
+	// result: (SHLQconst [log2(c/9)] (LEAQ8 <v.Type> x x))
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+			break
+		}
+		v.reset(OpAMD64SHLQconst)
+		v.AuxInt = log2(c / 9)
+		v0 := b.NewValue0(v.Line, OpAMD64LEAQ8, v.Type)
+		v0.AddArg(x)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (MULQconst [c] (MOVQconst [d]))
+	// cond:
+	// result: (MOVQconst [c*d])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = c * d
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpMod16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod16  x y)
+	// cond:
+	// result: (MODW  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MODW)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod16u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod16u x y)
+	// cond:
+	// result: (MODWU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MODWU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod32  x y)
+	// cond:
+	// result: (MODL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MODL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod32u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod32u x y)
+	// cond:
+	// result: (MODLU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MODLU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod64  x y)
+	// cond:
+	// result: (MODQ  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MODQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod64u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod64u x y)
+	// cond:
+	// result: (MODQU x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MODQU)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod8   x y)
+	// cond:
+	// result: (MODW  (SignExt8to16 x) (SignExt8to16 y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MODW)
+		v0 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMod8u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod8u  x y)
+	// cond:
+	// result: (MODWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MODWU)
+		v0 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMove(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Move [0] _ _ mem)
+	// cond:
+	// result: mem
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		mem := v.Args[2]
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Move [1] dst src mem)
+	// cond:
+	// result: (MOVBstore dst (MOVBload src mem) mem)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVBload, config.fe.TypeUInt8())
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Move [2] dst src mem)
+	// cond:
+	// result: (MOVWstore dst (MOVWload src mem) mem)
+	for {
+		if v.AuxInt != 2 {
+			break
+		}
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Move [4] dst src mem)
+	// cond:
+	// result: (MOVLstore dst (MOVLload src mem) mem)
+	for {
+		if v.AuxInt != 4 {
+			break
+		}
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Move [8] dst src mem)
+	// cond:
+	// result: (MOVQstore dst (MOVQload src mem) mem)
+	for {
+		if v.AuxInt != 8 {
+			break
+		}
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Move [16] dst src mem)
+	// cond:
+	// result: (MOVOstore dst (MOVOload src mem) mem)
+	for {
+		if v.AuxInt != 16 {
+			break
+		}
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVOstore)
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVOload, TypeInt128)
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Move [3] dst src mem)
+	// cond:
+	// result: (MOVBstore [2] dst (MOVBload [2] src mem) 		(MOVWstore dst (MOVWload src mem) mem))
+	for {
+		if v.AuxInt != 3 {
+			break
+		}
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBstore)
+		v.AuxInt = 2
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVBload, config.fe.TypeUInt8())
+		v0.AuxInt = 2
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVWstore, TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
+		v2.AddArg(src)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Move [5] dst src mem)
+	// cond:
+	// result: (MOVBstore [4] dst (MOVBload [4] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
+	for {
+		if v.AuxInt != 5 {
+			break
+		}
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBstore)
+		v.AuxInt = 4
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVBload, config.fe.TypeUInt8())
+		v0.AuxInt = 4
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVLstore, TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+		v2.AddArg(src)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Move [6] dst src mem)
+	// cond:
+	// result: (MOVWstore [4] dst (MOVWload [4] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
+	for {
+		if v.AuxInt != 6 {
+			break
+		}
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstore)
+		v.AuxInt = 4
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
+		v0.AuxInt = 4
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVLstore, TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+		v2.AddArg(src)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Move [7] dst src mem)
+	// cond:
+	// result: (MOVLstore [3] dst (MOVLload [3] src mem) 		(MOVLstore dst (MOVLload src mem) mem))
+	for {
+		if v.AuxInt != 7 {
+			break
+		}
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstore)
+		v.AuxInt = 3
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+		v0.AuxInt = 3
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVLstore, TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+		v2.AddArg(src)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Move [size] dst src mem)
+	// cond: size > 8 && size < 16
+	// result: (MOVQstore [size-8] dst (MOVQload [size-8] src mem) 		(MOVQstore dst (MOVQload src mem) mem))
+	for {
+		size := v.AuxInt
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !(size > 8 && size < 16) {
+			break
+		}
+		v.reset(OpAMD64MOVQstore)
+		v.AuxInt = size - 8
+		v.AddArg(dst)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
+		v0.AuxInt = size - 8
+		v0.AddArg(src)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVQstore, TypeMem)
+		v1.AddArg(dst)
+		v2 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
+		v2.AddArg(src)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Move [size] dst src mem)
+	// cond: size > 16 && size%16 != 0 && size%16 <= 8
+	// result: (Move [size-size%16] (ADDQconst <dst.Type> dst [size%16]) (ADDQconst <src.Type> src [size%16]) 		(MOVQstore dst (MOVQload src mem) mem))
+	for {
+		size := v.AuxInt
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !(size > 16 && size%16 != 0 && size%16 <= 8) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = size - size%16
+		v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, dst.Type)
+		v0.AddArg(dst)
+		v0.AuxInt = size % 16
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64ADDQconst, src.Type)
+		v1.AddArg(src)
+		v1.AuxInt = size % 16
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Line, OpAMD64MOVQstore, TypeMem)
+		v2.AddArg(dst)
+		v3 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
+		v3.AddArg(src)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v2.AddArg(mem)
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Move [size] dst src mem)
+	// cond: size > 16 && size%16 != 0 && size%16 > 8
+	// result: (Move [size-size%16] (ADDQconst <dst.Type> dst [size%16]) (ADDQconst <src.Type> src [size%16]) 		(MOVOstore dst (MOVOload src mem) mem))
+	for {
+		size := v.AuxInt
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !(size > 16 && size%16 != 0 && size%16 > 8) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = size - size%16
+		v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, dst.Type)
+		v0.AddArg(dst)
+		v0.AuxInt = size % 16
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64ADDQconst, src.Type)
+		v1.AddArg(src)
+		v1.AuxInt = size % 16
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Line, OpAMD64MOVOstore, TypeMem)
+		v2.AddArg(dst)
+		v3 := b.NewValue0(v.Line, OpAMD64MOVOload, TypeInt128)
+		v3.AddArg(src)
+		v3.AddArg(mem)
+		v2.AddArg(v3)
+		v2.AddArg(mem)
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Move [size] dst src mem)
+	// cond: size >= 32 && size <= 16*64 && size%16 == 0 && !config.noDuffDevice
+	// result: (DUFFCOPY [14*(64-size/16)] dst src mem)
+	for {
+		size := v.AuxInt
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !(size >= 32 && size <= 16*64 && size%16 == 0 && !config.noDuffDevice) {
+			break
+		}
+		v.reset(OpAMD64DUFFCOPY)
+		v.AuxInt = 14 * (64 - size/16)
+		v.AddArg(dst)
+		v.AddArg(src)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Move [size] dst src mem)
+	// cond: (size > 16*64 || config.noDuffDevice) && size%8 == 0
+	// result: (REPMOVSQ dst src (MOVQconst [size/8]) mem)
+	for {
+		size := v.AuxInt
+		dst := v.Args[0]
+		src := v.Args[1]
+		mem := v.Args[2]
+		if !((size > 16*64 || config.noDuffDevice) && size%8 == 0) {
+			break
+		}
+		v.reset(OpAMD64REPMOVSQ)
+		v.AddArg(dst)
+		v.AddArg(src)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+		v0.AuxInt = size / 8
+		v.AddArg(v0)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpMul16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul16  x y)
+	// cond:
+	// result: (MULL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul32  x y)
+	// cond:
+	// result: (MULL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul32F x y)
+	// cond:
+	// result: (MULSS x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULSS)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul64  x y)
+	// cond:
+	// result: (MULQ  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul64F x y)
+	// cond:
+	// result: (MULSD x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULSD)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpMul8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul8   x y)
+	// cond:
+	// result: (MULL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64MULL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAMD64NEGL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NEGL (MOVLconst [c]))
+	// cond:
+	// result: (MOVLconst [int64(int32(-c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = int64(int32(-c))
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64NEGQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NEGQ (MOVQconst [c]))
+	// cond:
+	// result: (MOVQconst [-c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = -c
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64NOTL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NOTL (MOVLconst [c]))
+	// cond:
+	// result: (MOVLconst [^c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = ^c
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64NOTQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NOTQ (MOVQconst [c]))
+	// cond:
+	// result: (MOVQconst [^c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = ^c
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpNeg16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg16  x)
+	// cond:
+	// result: (NEGL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NEGL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg32  x)
+	// cond:
+	// result: (NEGL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NEGL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg32F x)
+	// cond:
+	// result: (PXOR x (MOVSSconst <config.Frontend().TypeFloat32()> [f2i(math.Copysign(0, -1))]))
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64PXOR)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVSSconst, config.Frontend().TypeFloat32())
+		v0.AuxInt = f2i(math.Copysign(0, -1))
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg64  x)
+	// cond:
+	// result: (NEGQ x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NEGQ)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg64F x)
+	// cond:
+	// result: (PXOR x (MOVSDconst <config.Frontend().TypeFloat64()> [f2i(math.Copysign(0, -1))]))
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64PXOR)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVSDconst, config.Frontend().TypeFloat64())
+		v0.AuxInt = f2i(math.Copysign(0, -1))
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeg8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg8   x)
+	// cond:
+	// result: (NEGL x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64NEGL)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq16  x y)
+	// cond:
+	// result: (SETNE (CMPW x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq32  x y)
+	// cond:
+	// result: (SETNE (CMPL x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq32F x y)
+	// cond:
+	// result: (SETNEF (UCOMISS x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNEF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq64  x y)
+	// cond:
+	// result: (SETNE (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq64F x y)
+	// cond:
+	// result: (SETNEF (UCOMISD x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNEF)
+		v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeq8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq8   x y)
+	// cond:
+	// result: (SETNE (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeqB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NeqB   x y)
+	// cond:
+	// result: (SETNE (CMPB x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNeqPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NeqPtr x y)
+	// cond:
+	// result: (SETNE (CMPQ x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SETNE)
+		v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNilCheck(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NilCheck ptr mem)
+	// cond:
+	// result: (LoweredNilCheck ptr mem)
+	for {
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64LoweredNilCheck)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpNot(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Not x)
+	// cond:
+	// result: (XORLconst [1] x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64XORLconst)
+		v.AuxInt = 1
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ORL x (MOVLconst [c]))
+	// cond:
+	// result: (ORLconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64ORLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL (MOVLconst [c]) x)
+	// cond:
+	// result: (ORLconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64ORLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORL                  x0:(MOVBload [i]   {s} p mem)     s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
+	// cond: x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)
+	// result: @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
+	for {
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i := x0.AuxInt
+		s := x0.Aux
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		if x1.AuxInt != i+1 {
+			break
+		}
+		if x1.Aux != s {
+			break
+		}
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL o1:(ORL                        x0:(MOVBload [i]   {s} p mem)     s0:(SHLLconst [8]  x1:(MOVBload [i+1] {s} p mem)))     s1:(SHLLconst [16] x2:(MOVBload [i+2] {s} p mem)))     s2:(SHLLconst [24] x3:(MOVBload [i+3] {s} p mem)))
+	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && x3.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && s2.Uses == 1   && o0.Uses == 1   && o1.Uses == 1   && mergePoint(b,x0,x1,x2,x3) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(x3)   && clobber(s0)   && clobber(s1)   && clobber(s2)   && clobber(o0)   && clobber(o1)
+	// result: @mergePoint(b,x0,x1,x2,x3) (MOVLload [i] {s} p mem)
+	for {
+		o0 := v.Args[0]
+		if o0.Op != OpAMD64ORL {
+			break
+		}
+		o1 := o0.Args[0]
+		if o1.Op != OpAMD64ORL {
+			break
+		}
+		x0 := o1.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i := x0.AuxInt
+		s := x0.Aux
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s0 := o1.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		if x1.AuxInt != i+1 {
+			break
+		}
+		if x1.Aux != s {
+			break
+		}
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		s1 := o0.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		if s1.AuxInt != 16 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != OpAMD64MOVBload {
+			break
+		}
+		if x2.AuxInt != i+2 {
+			break
+		}
+		if x2.Aux != s {
+			break
+		}
+		if p != x2.Args[0] {
+			break
+		}
+		if mem != x2.Args[1] {
+			break
+		}
+		s2 := v.Args[1]
+		if s2.Op != OpAMD64SHLLconst {
+			break
+		}
+		if s2.AuxInt != 24 {
+			break
+		}
+		x3 := s2.Args[0]
+		if x3.Op != OpAMD64MOVBload {
+			break
+		}
+		if x3.AuxInt != i+3 {
+			break
+		}
+		if x3.Aux != s {
+			break
+		}
+		if p != x3.Args[0] {
+			break
+		}
+		if mem != x3.Args[1] {
+			break
+		}
+		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2, x3)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL                  x0:(MOVBloadidx1 [i]   {s} p idx mem)     s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+	// cond: x0.Uses == 1   && x1.Uses == 1   && s0.Uses == 1   && mergePoint(b,x0,x1) != nil   && clobber(x0)   && clobber(x1)   && clobber(s0)
+	// result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
+	for {
+		x0 := v.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i := x0.AuxInt
+		s := x0.Aux
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := v.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x1.AuxInt != i+1 {
+			break
+		}
+		if x1.Aux != s {
+			break
+		}
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+			break
+		}
+		b = mergePoint(b, x0, x1)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVWloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORL o0:(ORL o1:(ORL                        x0:(MOVBloadidx1 [i]   {s} p idx mem)     s0:(SHLLconst [8]  x1:(MOVBloadidx1 [i+1] {s} p idx mem)))     s1:(SHLLconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem)))     s2:(SHLLconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
+	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && x3.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && s2.Uses == 1   && o0.Uses == 1   && o1.Uses == 1   && mergePoint(b,x0,x1,x2,x3) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clobber(x3)   && clobber(s0)   && clobber(s1)   && clobber(s2)   && clobber(o0)   && clobber(o1)
+	// result: @mergePoint(b,x0,x1,x2,x3) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+	for {
+		o0 := v.Args[0]
+		if o0.Op != OpAMD64ORL {
+			break
+		}
+		o1 := o0.Args[0]
+		if o1.Op != OpAMD64ORL {
+			break
+		}
+		x0 := o1.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i := x0.AuxInt
+		s := x0.Aux
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o1.Args[1]
+		if s0.Op != OpAMD64SHLLconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x1.AuxInt != i+1 {
+			break
+		}
+		if x1.Aux != s {
+			break
+		}
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := o0.Args[1]
+		if s1.Op != OpAMD64SHLLconst {
+			break
+		}
+		if s1.AuxInt != 16 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x2.AuxInt != i+2 {
+			break
+		}
+		if x2.Aux != s {
+			break
+		}
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		s2 := v.Args[1]
+		if s2.Op != OpAMD64SHLLconst {
+			break
+		}
+		if s2.AuxInt != 24 {
+			break
+		}
+		x3 := s2.Args[0]
+		if x3.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x3.AuxInt != i+3 {
+			break
+		}
+		if x3.Aux != s {
+			break
+		}
+		if p != x3.Args[0] {
+			break
+		}
+		if idx != x3.Args[1] {
+			break
+		}
+		if mem != x3.Args[2] {
+			break
+		}
+		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)) {
+			break
+		}
+		b = mergePoint(b, x0, x1, x2, x3)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORLconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ORLconst [c] x)
+	// cond: int32(c)==0
+	// result: x
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(int32(c) == 0) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORLconst [c] _)
+	// cond: int32(c)==-1
+	// result: (MOVLconst [-1])
+	for {
+		c := v.AuxInt
+		if !(int32(c) == -1) {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (ORLconst [c] (MOVLconst [d]))
+	// cond:
+	// result: (MOVLconst [c|d])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = c | d
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ORQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (ORQconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64ORQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (ORQconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64ORQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORQ x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ                        x0:(MOVBload [i]   {s} p mem)     s0:(SHLQconst [8]  x1:(MOVBload [i+1] {s} p mem)))     s1:(SHLQconst [16] x2:(MOVBload [i+2] {s} p mem)))     s2:(SHLQconst [24] x3:(MOVBload [i+3] {s} p mem)))     s3:(SHLQconst [32] x4:(MOVBload [i+4] {s} p mem)))     s4:(SHLQconst [40] x5:(MOVBload [i+5] {s} p mem)))     s5:(SHLQconst [48] x6:(MOVBload [i+6] {s} p mem)))     s6:(SHLQconst [56] x7:(MOVBload [i+7] {s} [...]
+	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && x3.Uses == 1   && x4.Uses == 1   && x5.Uses == 1   && x6.Uses == 1   && x7.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && s2.Uses == 1   && s3.Uses == 1   && s4.Uses == 1   && s5.Uses == 1   && s6.Uses == 1   && o0.Uses == 1   && o1.Uses == 1   && o2.Uses == 1   && o3.Uses == 1   && o4.Uses == 1   && o5.Uses == 1   && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clo [...]
+	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQload [i] {s} p mem)
+	for {
+		o0 := v.Args[0]
+		if o0.Op != OpAMD64ORQ {
+			break
+		}
+		o1 := o0.Args[0]
+		if o1.Op != OpAMD64ORQ {
+			break
+		}
+		o2 := o1.Args[0]
+		if o2.Op != OpAMD64ORQ {
+			break
+		}
+		o3 := o2.Args[0]
+		if o3.Op != OpAMD64ORQ {
+			break
+		}
+		o4 := o3.Args[0]
+		if o4.Op != OpAMD64ORQ {
+			break
+		}
+		o5 := o4.Args[0]
+		if o5.Op != OpAMD64ORQ {
+			break
+		}
+		x0 := o5.Args[0]
+		if x0.Op != OpAMD64MOVBload {
+			break
+		}
+		i := x0.AuxInt
+		s := x0.Aux
+		p := x0.Args[0]
+		mem := x0.Args[1]
+		s0 := o5.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != OpAMD64MOVBload {
+			break
+		}
+		if x1.AuxInt != i+1 {
+			break
+		}
+		if x1.Aux != s {
+			break
+		}
+		if p != x1.Args[0] {
+			break
+		}
+		if mem != x1.Args[1] {
+			break
+		}
+		s1 := o4.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s1.AuxInt != 16 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != OpAMD64MOVBload {
+			break
+		}
+		if x2.AuxInt != i+2 {
+			break
+		}
+		if x2.Aux != s {
+			break
+		}
+		if p != x2.Args[0] {
+			break
+		}
+		if mem != x2.Args[1] {
+			break
+		}
+		s2 := o3.Args[1]
+		if s2.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s2.AuxInt != 24 {
+			break
+		}
+		x3 := s2.Args[0]
+		if x3.Op != OpAMD64MOVBload {
+			break
+		}
+		if x3.AuxInt != i+3 {
+			break
+		}
+		if x3.Aux != s {
+			break
+		}
+		if p != x3.Args[0] {
+			break
+		}
+		if mem != x3.Args[1] {
+			break
+		}
+		s3 := o2.Args[1]
+		if s3.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s3.AuxInt != 32 {
+			break
+		}
+		x4 := s3.Args[0]
+		if x4.Op != OpAMD64MOVBload {
+			break
+		}
+		if x4.AuxInt != i+4 {
+			break
+		}
+		if x4.Aux != s {
+			break
+		}
+		if p != x4.Args[0] {
+			break
+		}
+		if mem != x4.Args[1] {
+			break
+		}
+		s4 := o1.Args[1]
+		if s4.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s4.AuxInt != 40 {
+			break
+		}
+		x5 := s4.Args[0]
+		if x5.Op != OpAMD64MOVBload {
+			break
+		}
+		if x5.AuxInt != i+5 {
+			break
+		}
+		if x5.Aux != s {
+			break
+		}
+		if p != x5.Args[0] {
+			break
+		}
+		if mem != x5.Args[1] {
+			break
+		}
+		s5 := o0.Args[1]
+		if s5.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s5.AuxInt != 48 {
+			break
+		}
+		x6 := s5.Args[0]
+		if x6.Op != OpAMD64MOVBload {
+			break
+		}
+		if x6.AuxInt != i+6 {
+			break
+		}
+		if x6.Aux != s {
+			break
+		}
+		if p != x6.Args[0] {
+			break
+		}
+		if mem != x6.Args[1] {
+			break
+		}
+		s6 := v.Args[1]
+		if s6.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s6.AuxInt != 56 {
+			break
+		}
+		x7 := s6.Args[0]
+		if x7.Op != OpAMD64MOVBload {
+			break
+		}
+		if x7.AuxInt != i+7 {
+			break
+		}
+		if x7.Aux != s {
+			break
+		}
+		if p != x7.Args[0] {
+			break
+		}
+		if mem != x7.Args[1] {
+			break
+		}
+		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clo [...]
+			break
+		}
+		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(mem)
+		return true
+	}
+	// match: (ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ                        x0:(MOVBloadidx1 [i]   {s} p idx mem)     s0:(SHLQconst [8]  x1:(MOVBloadidx1 [i+1] {s} p idx mem)))     s1:(SHLQconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem)))     s2:(SHLQconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))     s3:(SHLQconst [32] x4:(MOVBloadidx1 [i+4] {s} p idx mem)))     s4:(SHLQconst [40] x5:(MOVBloadidx1 [i+5] {s} p idx mem)))     s5:(SHLQconst [48] x6:(MOVBloadidx1 [i+6] {s} p  [...]
+	// cond: x0.Uses == 1   && x1.Uses == 1   && x2.Uses == 1   && x3.Uses == 1   && x4.Uses == 1   && x5.Uses == 1   && x6.Uses == 1   && x7.Uses == 1   && s0.Uses == 1   && s1.Uses == 1   && s2.Uses == 1   && s3.Uses == 1   && s4.Uses == 1   && s5.Uses == 1   && s6.Uses == 1   && o0.Uses == 1   && o1.Uses == 1   && o2.Uses == 1   && o3.Uses == 1   && o4.Uses == 1   && o5.Uses == 1   && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil   && clobber(x0)   && clobber(x1)   && clobber(x2)   && clo [...]
+	// result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQloadidx1 <v.Type> [i] {s} p idx mem)
+	for {
+		o0 := v.Args[0]
+		if o0.Op != OpAMD64ORQ {
+			break
+		}
+		o1 := o0.Args[0]
+		if o1.Op != OpAMD64ORQ {
+			break
+		}
+		o2 := o1.Args[0]
+		if o2.Op != OpAMD64ORQ {
+			break
+		}
+		o3 := o2.Args[0]
+		if o3.Op != OpAMD64ORQ {
+			break
+		}
+		o4 := o3.Args[0]
+		if o4.Op != OpAMD64ORQ {
+			break
+		}
+		o5 := o4.Args[0]
+		if o5.Op != OpAMD64ORQ {
+			break
+		}
+		x0 := o5.Args[0]
+		if x0.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		i := x0.AuxInt
+		s := x0.Aux
+		p := x0.Args[0]
+		idx := x0.Args[1]
+		mem := x0.Args[2]
+		s0 := o5.Args[1]
+		if s0.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s0.AuxInt != 8 {
+			break
+		}
+		x1 := s0.Args[0]
+		if x1.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x1.AuxInt != i+1 {
+			break
+		}
+		if x1.Aux != s {
+			break
+		}
+		if p != x1.Args[0] {
+			break
+		}
+		if idx != x1.Args[1] {
+			break
+		}
+		if mem != x1.Args[2] {
+			break
+		}
+		s1 := o4.Args[1]
+		if s1.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s1.AuxInt != 16 {
+			break
+		}
+		x2 := s1.Args[0]
+		if x2.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x2.AuxInt != i+2 {
+			break
+		}
+		if x2.Aux != s {
+			break
+		}
+		if p != x2.Args[0] {
+			break
+		}
+		if idx != x2.Args[1] {
+			break
+		}
+		if mem != x2.Args[2] {
+			break
+		}
+		s2 := o3.Args[1]
+		if s2.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s2.AuxInt != 24 {
+			break
+		}
+		x3 := s2.Args[0]
+		if x3.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x3.AuxInt != i+3 {
+			break
+		}
+		if x3.Aux != s {
+			break
+		}
+		if p != x3.Args[0] {
+			break
+		}
+		if idx != x3.Args[1] {
+			break
+		}
+		if mem != x3.Args[2] {
+			break
+		}
+		s3 := o2.Args[1]
+		if s3.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s3.AuxInt != 32 {
+			break
+		}
+		x4 := s3.Args[0]
+		if x4.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x4.AuxInt != i+4 {
+			break
+		}
+		if x4.Aux != s {
+			break
+		}
+		if p != x4.Args[0] {
+			break
+		}
+		if idx != x4.Args[1] {
+			break
+		}
+		if mem != x4.Args[2] {
+			break
+		}
+		s4 := o1.Args[1]
+		if s4.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s4.AuxInt != 40 {
+			break
+		}
+		x5 := s4.Args[0]
+		if x5.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x5.AuxInt != i+5 {
+			break
+		}
+		if x5.Aux != s {
+			break
+		}
+		if p != x5.Args[0] {
+			break
+		}
+		if idx != x5.Args[1] {
+			break
+		}
+		if mem != x5.Args[2] {
+			break
+		}
+		s5 := o0.Args[1]
+		if s5.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s5.AuxInt != 48 {
+			break
+		}
+		x6 := s5.Args[0]
+		if x6.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x6.AuxInt != i+6 {
+			break
+		}
+		if x6.Aux != s {
+			break
+		}
+		if p != x6.Args[0] {
+			break
+		}
+		if idx != x6.Args[1] {
+			break
+		}
+		if mem != x6.Args[2] {
+			break
+		}
+		s6 := v.Args[1]
+		if s6.Op != OpAMD64SHLQconst {
+			break
+		}
+		if s6.AuxInt != 56 {
+			break
+		}
+		x7 := s6.Args[0]
+		if x7.Op != OpAMD64MOVBloadidx1 {
+			break
+		}
+		if x7.AuxInt != i+7 {
+			break
+		}
+		if x7.Aux != s {
+			break
+		}
+		if p != x7.Args[0] {
+			break
+		}
+		if idx != x7.Args[1] {
+			break
+		}
+		if mem != x7.Args[2] {
+			break
+		}
+		if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clo [...]
+			break
+		}
+		b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQloadidx1, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AuxInt = i
+		v0.Aux = s
+		v0.AddArg(p)
+		v0.AddArg(idx)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64ORQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ORQconst [0] x)
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (ORQconst [-1] _)
+	// cond:
+	// result: (MOVQconst [-1])
+	for {
+		if v.AuxInt != -1 {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (ORQconst [c] (MOVQconst [d]))
+	// cond:
+	// result: (MOVQconst [c|d])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = c | d
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpOffPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (OffPtr [off] ptr)
+	// cond: is32Bit(off)
+	// result: (ADDQconst [off] ptr)
+	for {
+		off := v.AuxInt
+		ptr := v.Args[0]
+		if !(is32Bit(off)) {
+			break
+		}
+		v.reset(OpAMD64ADDQconst)
+		v.AuxInt = off
+		v.AddArg(ptr)
+		return true
+	}
+	// match: (OffPtr [off] ptr)
+	// cond:
+	// result: (ADDQ (MOVQconst [off]) ptr)
+	for {
+		off := v.AuxInt
+		ptr := v.Args[0]
+		v.reset(OpAMD64ADDQ)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+		v0.AuxInt = off
+		v.AddArg(v0)
+		v.AddArg(ptr)
+		return true
+	}
+}
+func rewriteValueAMD64_OpOr16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Or16 x y)
+	// cond:
+	// result: (ORL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpOr32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Or32 x y)
+	// cond:
+	// result: (ORL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpOr64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Or64 x y)
+	// cond:
+	// result: (ORQ x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpOr8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Or8  x y)
+	// cond:
+	// result: (ORL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpOrB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (OrB x y)
+	// cond:
+	// result: (ORL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16Ux16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux16 <t> x y)
+	// cond:
+	// result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 16
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16Ux32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux32 <t> x y)
+	// cond:
+	// result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 16
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16Ux64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux64 <t> x y)
+	// cond:
+	// result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 16
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16Ux8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux8  <t> x y)
+	// cond:
+	// result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 16
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x16 <t> x y)
+	// cond:
+	// result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARW)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 16
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x32 <t> x y)
+	// cond:
+	// result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [16])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARW)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 16
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x64 <t> x y)
+	// cond:
+	// result: (SARW <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [16])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARW)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORQ, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTQ, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 16
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh16x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x8  <t> x y)
+	// cond:
+	// result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARW)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 16
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32Ux16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux16 <t> x y)
+	// cond:
+	// result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32Ux32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux32 <t> x y)
+	// cond:
+	// result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32Ux64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux64 <t> x y)
+	// cond:
+	// result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32Ux8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux8  <t> x y)
+	// cond:
+	// result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 32
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x16 <t> x y)
+	// cond:
+	// result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARL)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 32
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x32 <t> x y)
+	// cond:
+	// result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [32])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARL)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 32
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x64 <t> x y)
+	// cond:
+	// result: (SARL <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [32])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARL)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORQ, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTQ, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 32
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh32x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x8  <t> x y)
+	// cond:
+	// result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARL)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 32
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64Ux16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux16 <t> x y)
+	// cond:
+	// result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 64
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64Ux32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux32 <t> x y)
+	// cond:
+	// result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 64
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64Ux64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux64 <t> x y)
+	// cond:
+	// result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 64
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64Ux8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux8  <t> x y)
+	// cond:
+	// result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPBconst y [64])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 64
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x16 <t> x y)
+	// cond:
+	// result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [64])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARQ)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 64
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x32 <t> x y)
+	// cond:
+	// result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [64])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARQ)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 64
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x64 <t> x y)
+	// cond:
+	// result: (SARQ <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [64])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARQ)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORQ, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTQ, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 64
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh64x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x8  <t> x y)
+	// cond:
+	// result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [64])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARQ)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 64
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8Ux16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8Ux16 <t> x y)
+	// cond:
+	// result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 8
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8Ux32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8Ux32 <t> x y)
+	// cond:
+	// result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 8
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8Ux64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8Ux64 <t> x y)
+	// cond:
+	// result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 8
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8Ux8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8Ux8  <t> x y)
+	// cond:
+	// result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64ANDL)
+		v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+		v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v2.AddArg(y)
+		v2.AuxInt = 8
+		v1.AddArg(v2)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x16 <t> x y)
+	// cond:
+	// result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARB)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 8
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x32 <t> x y)
+	// cond:
+	// result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [8])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARB)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 8
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x64 <t> x y)
+	// cond:
+	// result: (SARB <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [8])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARB)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORQ, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTQ, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 8
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpRsh8x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x8  <t> x y)
+	// cond:
+	// result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SARB)
+		v.Type = t
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+		v0.AddArg(y)
+		v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
+		v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
+		v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+		v3.AddArg(y)
+		v3.AuxInt = 8
+		v2.AddArg(v3)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAMD64SARB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SARB x (MOVQconst [c]))
+	// cond:
+	// result: (SARBconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARBconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SARB x (MOVLconst [c]))
+	// cond:
+	// result: (SARBconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARBconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARBconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SARBconst [c] (MOVQconst [d]))
+	// cond:
+	// result: (MOVQconst [d>>uint64(c)])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = d >> uint64(c)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SARL x (MOVQconst [c]))
+	// cond:
+	// result: (SARLconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARLconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SARL x (MOVLconst [c]))
+	// cond:
+	// result: (SARLconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARLconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SARL x (ANDLconst [31] y))
+	// cond:
+	// result: (SARL x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1.AuxInt != 31 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64SARL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARLconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SARLconst [c] (MOVQconst [d]))
+	// cond:
+	// result: (MOVQconst [d>>uint64(c)])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = d >> uint64(c)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SARQ x (MOVQconst [c]))
+	// cond:
+	// result: (SARQconst [c&63] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARQconst)
+		v.AuxInt = c & 63
+		v.AddArg(x)
+		return true
+	}
+	// match: (SARQ x (MOVLconst [c]))
+	// cond:
+	// result: (SARQconst [c&63] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARQconst)
+		v.AuxInt = c & 63
+		v.AddArg(x)
+		return true
+	}
+	// match: (SARQ x (ANDQconst [63] y))
+	// cond:
+	// result: (SARQ x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1.AuxInt != 63 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64SARQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SARQconst [c] (MOVQconst [d]))
+	// cond:
+	// result: (MOVQconst [d>>uint64(c)])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = d >> uint64(c)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARW(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SARW x (MOVQconst [c]))
+	// cond:
+	// result: (SARWconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARWconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SARW x (MOVLconst [c]))
+	// cond:
+	// result: (SARWconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SARWconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SARWconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SARWconst [c] (MOVQconst [d]))
+	// cond:
+	// result: (MOVQconst [d>>uint64(c)])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = d >> uint64(c)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SBBLcarrymask(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SBBLcarrymask (FlagEQ))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SBBLcarrymask (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (SBBLcarrymask (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SBBLcarrymask (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (SBBLcarrymask (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SBBQcarrymask(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SBBQcarrymask (FlagEQ))
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SBBQcarrymask (FlagLT_ULT))
+	// cond:
+	// result: (MOVQconst [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (SBBQcarrymask (FlagLT_UGT))
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SBBQcarrymask (FlagGT_ULT))
+	// cond:
+	// result: (MOVQconst [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (SBBQcarrymask (FlagGT_UGT))
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETA(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETA (InvertFlags x))
+	// cond:
+	// result: (SETB x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETB)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETA (FlagEQ))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETA (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETA (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETA (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETA (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETAE(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETAE (InvertFlags x))
+	// cond:
+	// result: (SETBE x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETBE)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETAE (FlagEQ))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETAE (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETAE (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETAE (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETAE (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETB (InvertFlags x))
+	// cond:
+	// result: (SETA x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETA)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETB (FlagEQ))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETB (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETB (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETB (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETB (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETBE(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETBE (InvertFlags x))
+	// cond:
+	// result: (SETAE x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETAE)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETBE (FlagEQ))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETBE (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETBE (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETBE (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETBE (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETEQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETEQ (InvertFlags x))
+	// cond:
+	// result: (SETEQ x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETEQ)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETEQ (FlagEQ))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETEQ (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETEQ (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETEQ (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETEQ (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETG(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETG (InvertFlags x))
+	// cond:
+	// result: (SETL x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETL)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETG (FlagEQ))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETG (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETG (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETG (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETG (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETGE(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETGE (InvertFlags x))
+	// cond:
+	// result: (SETLE x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETLE)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETGE (FlagEQ))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETGE (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETGE (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETGE (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETGE (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETL (InvertFlags x))
+	// cond:
+	// result: (SETG x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETG)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETL (FlagEQ))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETL (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETL (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETL (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETL (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETLE(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETLE (InvertFlags x))
+	// cond:
+	// result: (SETGE x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETGE)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETLE (FlagEQ))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETLE (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETLE (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETLE (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETLE (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SETNE(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SETNE (InvertFlags x))
+	// cond:
+	// result: (SETNE x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64InvertFlags {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpAMD64SETNE)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SETNE (FlagEQ))
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagEQ {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (SETNE (FlagLT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETNE (FlagLT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagLT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETNE (FlagGT_ULT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_ULT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (SETNE (FlagGT_UGT))
+	// cond:
+	// result: (MOVLconst [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64FlagGT_UGT {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 1
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHLL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SHLL x (MOVQconst [c]))
+	// cond:
+	// result: (SHLLconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHLLconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHLL x (MOVLconst [c]))
+	// cond:
+	// result: (SHLLconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHLLconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHLL x (ANDLconst [31] y))
+	// cond:
+	// result: (SHLL x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1.AuxInt != 31 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64SHLL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHLQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SHLQ x (MOVQconst [c]))
+	// cond:
+	// result: (SHLQconst [c&63] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHLQconst)
+		v.AuxInt = c & 63
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHLQ x (MOVLconst [c]))
+	// cond:
+	// result: (SHLQconst [c&63] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHLQconst)
+		v.AuxInt = c & 63
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHLQ x (ANDQconst [63] y))
+	// cond:
+	// result: (SHLQ x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1.AuxInt != 63 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64SHLQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SHRB x (MOVQconst [c]))
+	// cond:
+	// result: (SHRBconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHRBconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRB x (MOVLconst [c]))
+	// cond:
+	// result: (SHRBconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHRBconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SHRL x (MOVQconst [c]))
+	// cond:
+	// result: (SHRLconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHRLconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRL x (MOVLconst [c]))
+	// cond:
+	// result: (SHRLconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHRLconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRL x (ANDLconst [31] y))
+	// cond:
+	// result: (SHRL x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDLconst {
+			break
+		}
+		if v_1.AuxInt != 31 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64SHRL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SHRQ x (MOVQconst [c]))
+	// cond:
+	// result: (SHRQconst [c&63] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHRQconst)
+		v.AuxInt = c & 63
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRQ x (MOVLconst [c]))
+	// cond:
+	// result: (SHRQconst [c&63] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHRQconst)
+		v.AuxInt = c & 63
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRQ x (ANDQconst [63] y))
+	// cond:
+	// result: (SHRQ x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64ANDQconst {
+			break
+		}
+		if v_1.AuxInt != 63 {
+			break
+		}
+		y := v_1.Args[0]
+		v.reset(OpAMD64SHRQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SHRW(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SHRW x (MOVQconst [c]))
+	// cond:
+	// result: (SHRWconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHRWconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	// match: (SHRW x (MOVLconst [c]))
+	// cond:
+	// result: (SHRWconst [c&31] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SHRWconst)
+		v.AuxInt = c & 31
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SUBL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SUBL x (MOVLconst [c]))
+	// cond:
+	// result: (SUBLconst x [c])
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64SUBLconst)
+		v.AddArg(x)
+		v.AuxInt = c
+		return true
+	}
+	// match: (SUBL (MOVLconst [c]) x)
+	// cond:
+	// result: (NEGL (SUBLconst <v.Type> x [c]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64NEGL)
+		v0 := b.NewValue0(v.Line, OpAMD64SUBLconst, v.Type)
+		v0.AddArg(x)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SUBL x x)
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SUBLconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SUBLconst [c] x)
+	// cond: int32(c) == 0
+	// result: x
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(int32(c) == 0) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (SUBLconst [c] x)
+	// cond:
+	// result: (ADDLconst [int64(int32(-c))] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		v.reset(OpAMD64ADDLconst)
+		v.AuxInt = int64(int32(-c))
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAMD64SUBQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SUBQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (SUBQconst x [c])
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64SUBQconst)
+		v.AddArg(x)
+		v.AuxInt = c
+		return true
+	}
+	// match: (SUBQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (NEGQ (SUBQconst <v.Type> x [c]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64NEGQ)
+		v0 := b.NewValue0(v.Line, OpAMD64SUBQconst, v.Type)
+		v0.AddArg(x)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		return true
+	}
+	// match: (SUBQ x x)
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64SUBQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SUBQconst [0] x)
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (SUBQconst [c] x)
+	// cond: c != -(1<<31)
+	// result: (ADDQconst [-c] x)
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(c != -(1 << 31)) {
+			break
+		}
+		v.reset(OpAMD64ADDQconst)
+		v.AuxInt = -c
+		v.AddArg(x)
+		return true
+	}
+	// match: (SUBQconst (MOVQconst [d]) [c])
+	// cond:
+	// result: (MOVQconst [d-c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		c := v.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = d - c
+		return true
+	}
+	// match: (SUBQconst (SUBQconst x [d]) [c])
+	// cond: is32Bit(-c-d)
+	// result: (ADDQconst [-c-d] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64SUBQconst {
+			break
+		}
+		x := v_0.Args[0]
+		d := v_0.AuxInt
+		c := v.AuxInt
+		if !(is32Bit(-c - d)) {
+			break
+		}
+		v.reset(OpAMD64ADDQconst)
+		v.AuxInt = -c - d
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpSignExt16to32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SignExt16to32 x)
+	// cond:
+	// result: (MOVWQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVWQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt16to64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SignExt16to64 x)
+	// cond:
+	// result: (MOVWQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVWQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt32to64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SignExt32to64 x)
+	// cond:
+	// result: (MOVLQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVLQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt8to16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SignExt8to16  x)
+	// cond:
+	// result: (MOVBQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt8to32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SignExt8to32  x)
+	// cond:
+	// result: (MOVBQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSignExt8to64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SignExt8to64  x)
+	// cond:
+	// result: (MOVBQSX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQSX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSqrt(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sqrt x)
+	// cond:
+	// result: (SQRTSD x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64SQRTSD)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpStaticCall(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (StaticCall [argwid] {target} mem)
+	// cond:
+	// result: (CALLstatic [argwid] {target} mem)
+	for {
+		argwid := v.AuxInt
+		target := v.Aux
+		mem := v.Args[0]
+		v.reset(OpAMD64CALLstatic)
+		v.AuxInt = argwid
+		v.Aux = target
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueAMD64_OpStore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Store [8] ptr val mem)
+	// cond: is64BitFloat(val.Type)
+	// result: (MOVSDstore ptr val mem)
+	for {
+		if v.AuxInt != 8 {
+			break
+		}
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is64BitFloat(val.Type)) {
+			break
+		}
+		v.reset(OpAMD64MOVSDstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store [4] ptr val mem)
+	// cond: is32BitFloat(val.Type)
+	// result: (MOVSSstore ptr val mem)
+	for {
+		if v.AuxInt != 4 {
+			break
+		}
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(is32BitFloat(val.Type)) {
+			break
+		}
+		v.reset(OpAMD64MOVSSstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store [8] ptr val mem)
+	// cond:
+	// result: (MOVQstore ptr val mem)
+	for {
+		if v.AuxInt != 8 {
+			break
+		}
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVQstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store [4] ptr val mem)
+	// cond:
+	// result: (MOVLstore ptr val mem)
+	for {
+		if v.AuxInt != 4 {
+			break
+		}
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVLstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store [2] ptr val mem)
+	// cond:
+	// result: (MOVWstore ptr val mem)
+	for {
+		if v.AuxInt != 2 {
+			break
+		}
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVWstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store [1] ptr val mem)
+	// cond:
+	// result: (MOVBstore ptr val mem)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpAMD64MOVBstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpSub16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub16  x y)
+	// cond:
+	// result: (SUBL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub32  x y)
+	// cond:
+	// result: (SUBL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub32F x y)
+	// cond:
+	// result: (SUBSS x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBSS)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub64  x y)
+	// cond:
+	// result: (SUBQ  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub64F x y)
+	// cond:
+	// result: (SUBSD x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBSD)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSub8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub8   x y)
+	// cond:
+	// result: (SUBL  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpSubPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SubPtr x y)
+	// cond:
+	// result: (SUBQ  x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64SUBQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpTrunc16to8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc16to8  x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpTrunc32to16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc32to16 x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpTrunc32to8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc32to8  x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpTrunc64to16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc64to16 x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpTrunc64to32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc64to32 x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpTrunc64to8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc64to8  x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpAMD64XORL(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (XORL x (MOVLconst [c]))
+	// cond:
+	// result: (XORLconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpAMD64XORLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL (MOVLconst [c]) x)
+	// cond:
+	// result: (XORLconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpAMD64XORLconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORL x x)
+	// cond:
+	// result: (MOVLconst [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XORLconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (XORLconst [c] x)
+	// cond: int32(c)==0
+	// result: x
+	for {
+		c := v.AuxInt
+		x := v.Args[0]
+		if !(int32(c) == 0) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORLconst [c] (MOVLconst [d]))
+	// cond:
+	// result: (MOVLconst [c^d])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVLconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVLconst)
+		v.AuxInt = c ^ d
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XORQ(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (XORQ x (MOVQconst [c]))
+	// cond: is32Bit(c)
+	// result: (XORQconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_1.AuxInt
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64XORQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORQ (MOVQconst [c]) x)
+	// cond: is32Bit(c)
+	// result: (XORQconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		if !(is32Bit(c)) {
+			break
+		}
+		v.reset(OpAMD64XORQconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORQ x x)
+	// cond:
+	// result: (MOVQconst [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpAMD64XORQconst(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (XORQconst [0] x)
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		x := v.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (XORQconst [c] (MOVQconst [d]))
+	// cond:
+	// result: (MOVQconst [c^d])
+	for {
+		c := v.AuxInt
+		v_0 := v.Args[0]
+		if v_0.Op != OpAMD64MOVQconst {
+			break
+		}
+		d := v_0.AuxInt
+		v.reset(OpAMD64MOVQconst)
+		v.AuxInt = c ^ d
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpXor16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Xor16 x y)
+	// cond:
+	// result: (XORL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64XORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpXor32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Xor32 x y)
+	// cond:
+	// result: (XORL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64XORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpXor64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Xor64 x y)
+	// cond:
+	// result: (XORQ x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64XORQ)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpXor8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Xor8  x y)
+	// cond:
+	// result: (XORL x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpAMD64XORL)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Zero [0] _ mem)
+	// cond:
+	// result: mem
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		mem := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Zero [1] destptr mem)
+	// cond:
+	// result: (MOVBstoreconst [0] destptr mem)
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVBstoreconst)
+		v.AuxInt = 0
+		v.AddArg(destptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Zero [2] destptr mem)
+	// cond:
+	// result: (MOVWstoreconst [0] destptr mem)
+	for {
+		if v.AuxInt != 2 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = 0
+		v.AddArg(destptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Zero [4] destptr mem)
+	// cond:
+	// result: (MOVLstoreconst [0] destptr mem)
+	for {
+		if v.AuxInt != 4 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = 0
+		v.AddArg(destptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Zero [8] destptr mem)
+	// cond:
+	// result: (MOVQstoreconst [0] destptr mem)
+	for {
+		if v.AuxInt != 8 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = 0
+		v.AddArg(destptr)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Zero [3] destptr mem)
+	// cond:
+	// result: (MOVBstoreconst [makeValAndOff(0,2)] destptr 		(MOVWstoreconst [0] destptr mem))
+	for {
+		if v.AuxInt != 3 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVBstoreconst)
+		v.AuxInt = makeValAndOff(0, 2)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVWstoreconst, TypeMem)
+		v0.AuxInt = 0
+		v0.AddArg(destptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [5] destptr mem)
+	// cond:
+	// result: (MOVBstoreconst [makeValAndOff(0,4)] destptr 		(MOVLstoreconst [0] destptr mem))
+	for {
+		if v.AuxInt != 5 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVBstoreconst)
+		v.AuxInt = makeValAndOff(0, 4)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLstoreconst, TypeMem)
+		v0.AuxInt = 0
+		v0.AddArg(destptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [6] destptr mem)
+	// cond:
+	// result: (MOVWstoreconst [makeValAndOff(0,4)] destptr 		(MOVLstoreconst [0] destptr mem))
+	for {
+		if v.AuxInt != 6 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVWstoreconst)
+		v.AuxInt = makeValAndOff(0, 4)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLstoreconst, TypeMem)
+		v0.AuxInt = 0
+		v0.AddArg(destptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [7] destptr mem)
+	// cond:
+	// result: (MOVLstoreconst [makeValAndOff(0,3)] destptr 		(MOVLstoreconst [0] destptr mem))
+	for {
+		if v.AuxInt != 7 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVLstoreconst)
+		v.AuxInt = makeValAndOff(0, 3)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVLstoreconst, TypeMem)
+		v0.AuxInt = 0
+		v0.AddArg(destptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [size] destptr mem)
+	// cond: size%8 != 0 && size > 8
+	// result: (Zero [size-size%8] (ADDQconst destptr [size%8]) 		(MOVQstoreconst [0] destptr mem))
+	for {
+		size := v.AuxInt
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		if !(size%8 != 0 && size > 8) {
+			break
+		}
+		v.reset(OpZero)
+		v.AuxInt = size - size%8
+		v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, config.fe.TypeUInt64())
+		v0.AddArg(destptr)
+		v0.AuxInt = size % 8
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVQstoreconst, TypeMem)
+		v1.AuxInt = 0
+		v1.AddArg(destptr)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Zero [16] destptr mem)
+	// cond:
+	// result: (MOVQstoreconst [makeValAndOff(0,8)] destptr 		(MOVQstoreconst [0] destptr mem))
+	for {
+		if v.AuxInt != 16 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = makeValAndOff(0, 8)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQstoreconst, TypeMem)
+		v0.AuxInt = 0
+		v0.AddArg(destptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [24] destptr mem)
+	// cond:
+	// result: (MOVQstoreconst [makeValAndOff(0,16)] destptr 		(MOVQstoreconst [makeValAndOff(0,8)] destptr 			(MOVQstoreconst [0] destptr mem)))
+	for {
+		if v.AuxInt != 24 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = makeValAndOff(0, 16)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQstoreconst, TypeMem)
+		v0.AuxInt = makeValAndOff(0, 8)
+		v0.AddArg(destptr)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVQstoreconst, TypeMem)
+		v1.AuxInt = 0
+		v1.AddArg(destptr)
+		v1.AddArg(mem)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [32] destptr mem)
+	// cond:
+	// result: (MOVQstoreconst [makeValAndOff(0,24)] destptr 		(MOVQstoreconst [makeValAndOff(0,16)] destptr 			(MOVQstoreconst [makeValAndOff(0,8)] destptr 				(MOVQstoreconst [0] destptr mem))))
+	for {
+		if v.AuxInt != 32 {
+			break
+		}
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		v.reset(OpAMD64MOVQstoreconst)
+		v.AuxInt = makeValAndOff(0, 24)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQstoreconst, TypeMem)
+		v0.AuxInt = makeValAndOff(0, 16)
+		v0.AddArg(destptr)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVQstoreconst, TypeMem)
+		v1.AuxInt = makeValAndOff(0, 8)
+		v1.AddArg(destptr)
+		v2 := b.NewValue0(v.Line, OpAMD64MOVQstoreconst, TypeMem)
+		v2.AuxInt = 0
+		v2.AddArg(destptr)
+		v2.AddArg(mem)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Zero [size] destptr mem)
+	// cond: size <= 1024 && size%8 == 0 && size%16 != 0 && !config.noDuffDevice
+	// result: (Zero [size-8] (ADDQconst [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
+	for {
+		size := v.AuxInt
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		if !(size <= 1024 && size%8 == 0 && size%16 != 0 && !config.noDuffDevice) {
+			break
+		}
+		v.reset(OpZero)
+		v.AuxInt = size - 8
+		v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, config.fe.TypeUInt64())
+		v0.AuxInt = 8
+		v0.AddArg(destptr)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVQstore, TypeMem)
+		v1.AddArg(destptr)
+		v2 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+		v2.AuxInt = 0
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Zero [size] destptr mem)
+	// cond: size <= 1024 && size%16 == 0 && !config.noDuffDevice
+	// result: (DUFFZERO [duffStart(size)] (ADDQconst [duffAdj(size)] destptr) (MOVOconst [0]) mem)
+	for {
+		size := v.AuxInt
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		if !(size <= 1024 && size%16 == 0 && !config.noDuffDevice) {
+			break
+		}
+		v.reset(OpAMD64DUFFZERO)
+		v.AuxInt = duffStart(size)
+		v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, config.fe.TypeUInt64())
+		v0.AuxInt = duffAdj(size)
+		v0.AddArg(destptr)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVOconst, TypeInt128)
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Zero [size] destptr mem)
+	// cond: (size > 1024 || (config.noDuffDevice && size > 32)) && size%8 == 0
+	// result: (REPSTOSQ destptr (MOVQconst [size/8]) (MOVQconst [0]) mem)
+	for {
+		size := v.AuxInt
+		destptr := v.Args[0]
+		mem := v.Args[1]
+		if !((size > 1024 || (config.noDuffDevice && size > 32)) && size%8 == 0) {
+			break
+		}
+		v.reset(OpAMD64REPSTOSQ)
+		v.AddArg(destptr)
+		v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+		v0.AuxInt = size / 8
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueAMD64_OpZeroExt16to32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ZeroExt16to32 x)
+	// cond:
+	// result: (MOVWQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVWQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt16to64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ZeroExt16to64 x)
+	// cond:
+	// result: (MOVWQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVWQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt32to64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ZeroExt32to64 x)
+	// cond:
+	// result: (MOVLQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVLQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt8to16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ZeroExt8to16  x)
+	// cond:
+	// result: (MOVBQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt8to32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ZeroExt8to32  x)
+	// cond:
+	// result: (MOVBQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteValueAMD64_OpZeroExt8to64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ZeroExt8to64  x)
+	// cond:
+	// result: (MOVBQZX x)
+	for {
+		x := v.Args[0]
+		v.reset(OpAMD64MOVBQZX)
+		v.AddArg(x)
+		return true
+	}
+}
+func rewriteBlockAMD64(b *Block) bool {
+	switch b.Kind {
+	case BlockAMD64EQ:
+		// match: (EQ (InvertFlags cmp) yes no)
+		// cond:
+		// result: (EQ cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64EQ
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (EQ (FlagEQ) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (EQ (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (EQ (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (EQ (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (EQ (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+	case BlockAMD64GE:
+		// match: (GE (InvertFlags cmp) yes no)
+		// cond:
+		// result: (LE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64LE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (GE (FlagEQ) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (GE (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (GE (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (GE (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (GE (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+	case BlockAMD64GT:
+		// match: (GT (InvertFlags cmp) yes no)
+		// cond:
+		// result: (LT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64LT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (GT (FlagEQ) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (GT (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (GT (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (GT (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (GT (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+	case BlockIf:
+		// match: (If (SETL  cmp) yes no)
+		// cond:
+		// result: (LT  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETL {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64LT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETLE cmp) yes no)
+		// cond:
+		// result: (LE  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETLE {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64LE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETG  cmp) yes no)
+		// cond:
+		// result: (GT  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETG {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64GT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETGE cmp) yes no)
+		// cond:
+		// result: (GE  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETGE {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64GE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETEQ cmp) yes no)
+		// cond:
+		// result: (EQ  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETEQ {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64EQ
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETNE cmp) yes no)
+		// cond:
+		// result: (NE  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETNE {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64NE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETB  cmp) yes no)
+		// cond:
+		// result: (ULT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETB {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64ULT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETBE cmp) yes no)
+		// cond:
+		// result: (ULE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETBE {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64ULE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETA  cmp) yes no)
+		// cond:
+		// result: (UGT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETA {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETAE cmp) yes no)
+		// cond:
+		// result: (UGE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETAE {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETGF  cmp) yes no)
+		// cond:
+		// result: (UGT  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETGF {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETGEF cmp) yes no)
+		// cond:
+		// result: (UGE  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETGEF {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETEQF cmp) yes no)
+		// cond:
+		// result: (EQF  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETEQF {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64EQF
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (SETNEF cmp) yes no)
+		// cond:
+		// result: (NEF  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64SETNEF {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64NEF
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If cond yes no)
+		// cond:
+		// result: (NE (TESTB cond cond) yes no)
+		for {
+			v := b.Control
+			cond := b.Control
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64NE
+			v0 := b.NewValue0(v.Line, OpAMD64TESTB, TypeFlags)
+			v0.AddArg(cond)
+			v0.AddArg(cond)
+			b.SetControl(v0)
+			_ = yes
+			_ = no
+			return true
+		}
+	case BlockAMD64LE:
+		// match: (LE (InvertFlags cmp) yes no)
+		// cond:
+		// result: (GE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64GE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (LE (FlagEQ) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (LE (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (LE (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (LE (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (LE (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+	case BlockAMD64LT:
+		// match: (LT (InvertFlags cmp) yes no)
+		// cond:
+		// result: (GT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64GT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (LT (FlagEQ) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (LT (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (LT (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (LT (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (LT (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+	case BlockAMD64NE:
+		// match: (NE (TESTB (SETL  cmp) (SETL  cmp)) yes no)
+		// cond:
+		// result: (LT  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETL {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETL {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64LT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
+		// cond:
+		// result: (LE  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETLE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETLE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64LE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETG  cmp) (SETG  cmp)) yes no)
+		// cond:
+		// result: (GT  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETG {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETG {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64GT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
+		// cond:
+		// result: (GE  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETGE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETGE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64GE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
+		// cond:
+		// result: (EQ  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETEQ {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETEQ {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64EQ
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
+		// cond:
+		// result: (NE  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETNE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETNE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64NE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETB  cmp) (SETB  cmp)) yes no)
+		// cond:
+		// result: (ULT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETB {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETB {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64ULT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
+		// cond:
+		// result: (ULE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETBE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETBE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64ULE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETA  cmp) (SETA  cmp)) yes no)
+		// cond:
+		// result: (UGT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETA {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETA {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETAE cmp) (SETAE cmp)) yes no)
+		// cond:
+		// result: (UGE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETAE {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETAE {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETGF  cmp) (SETGF  cmp)) yes no)
+		// cond:
+		// result: (UGT  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETGF {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETGF {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no)
+		// cond:
+		// result: (UGE  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETGEF {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETGEF {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no)
+		// cond:
+		// result: (EQF  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETEQF {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETEQF {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64EQF
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (TESTB (SETNEF cmp) (SETNEF cmp)) yes no)
+		// cond:
+		// result: (NEF  cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64TESTB {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpAMD64SETNEF {
+				break
+			}
+			cmp := v_0.Args[0]
+			v_1 := v.Args[1]
+			if v_1.Op != OpAMD64SETNEF {
+				break
+			}
+			if cmp != v_1.Args[0] {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64NEF
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (InvertFlags cmp) yes no)
+		// cond:
+		// result: (NE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64NE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (FlagEQ) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (NE (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (NE (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+	case BlockAMD64UGE:
+		// match: (UGE (InvertFlags cmp) yes no)
+		// cond:
+		// result: (ULE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64ULE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (UGE (FlagEQ) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (UGE (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (UGE (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (UGE (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (UGE (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+	case BlockAMD64UGT:
+		// match: (UGT (InvertFlags cmp) yes no)
+		// cond:
+		// result: (ULT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64ULT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (UGT (FlagEQ) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (UGT (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (UGT (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (UGT (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (UGT (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+	case BlockAMD64ULE:
+		// match: (ULE (InvertFlags cmp) yes no)
+		// cond:
+		// result: (UGE cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGE
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (ULE (FlagEQ) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (ULE (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (ULE (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (ULE (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (ULE (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+	case BlockAMD64ULT:
+		// match: (ULT (InvertFlags cmp) yes no)
+		// cond:
+		// result: (UGT cmp yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64InvertFlags {
+				break
+			}
+			cmp := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockAMD64UGT
+			b.SetControl(cmp)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (ULT (FlagEQ) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagEQ {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (ULT (FlagLT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (ULT (FlagLT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagLT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (ULT (FlagGT_ULT) yes no)
+		// cond:
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_ULT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (ULT (FlagGT_UGT) yes no)
+		// cond:
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpAMD64FlagGT_UGT {
+				break
+			}
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
new file mode 100644
index 0000000..b57283e
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -0,0 +1,288 @@
+// autogenerated from gen/ARM.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValueARM(v *Value, config *Config) bool {
+	switch v.Op {
+	case OpARMADD:
+		return rewriteValueARM_OpARMADD(v, config)
+	case OpAdd32:
+		return rewriteValueARM_OpAdd32(v, config)
+	case OpAddr:
+		return rewriteValueARM_OpAddr(v, config)
+	case OpConst32:
+		return rewriteValueARM_OpConst32(v, config)
+	case OpLess32:
+		return rewriteValueARM_OpLess32(v, config)
+	case OpLoad:
+		return rewriteValueARM_OpLoad(v, config)
+	case OpARMMOVWload:
+		return rewriteValueARM_OpARMMOVWload(v, config)
+	case OpARMMOVWstore:
+		return rewriteValueARM_OpARMMOVWstore(v, config)
+	case OpOffPtr:
+		return rewriteValueARM_OpOffPtr(v, config)
+	case OpStaticCall:
+		return rewriteValueARM_OpStaticCall(v, config)
+	case OpStore:
+		return rewriteValueARM_OpStore(v, config)
+	}
+	return false
+}
+func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ADD (MOVWconst [c]) x)
+	// cond:
+	// result: (ADDconst [c] x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMMOVWconst {
+			break
+		}
+		c := v_0.AuxInt
+		x := v.Args[1]
+		v.reset(OpARMADDconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	// match: (ADD x (MOVWconst [c]))
+	// cond:
+	// result: (ADDconst [c] x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpARMMOVWconst {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpARMADDconst)
+		v.AuxInt = c
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValueARM_OpAdd32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add32 x y)
+	// cond:
+	// result: (ADD x y)
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpARMADD)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+}
+func rewriteValueARM_OpAddr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Addr {sym} base)
+	// cond:
+	// result: (ADDconst {sym} base)
+	for {
+		sym := v.Aux
+		base := v.Args[0]
+		v.reset(OpARMADDconst)
+		v.Aux = sym
+		v.AddArg(base)
+		return true
+	}
+}
+func rewriteValueARM_OpConst32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Const32 [val])
+	// cond:
+	// result: (MOVWconst [val])
+	for {
+		val := v.AuxInt
+		v.reset(OpARMMOVWconst)
+		v.AuxInt = val
+		return true
+	}
+}
+func rewriteValueARM_OpLess32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less32 x y)
+	// cond:
+	// result: (LessThan (CMP x y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpARMLessThan)
+		v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+		v0.AddArg(x)
+		v0.AddArg(y)
+		v.AddArg(v0)
+		return true
+	}
+}
+func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Load <t> ptr mem)
+	// cond: is32BitInt(t)
+	// result: (MOVWload ptr mem)
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(is32BitInt(t)) {
+			break
+		}
+		v.reset(OpARMMOVWload)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem)
+	// cond: canMergeSym(sym1,sym2)
+	// result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		mem := v.Args[1]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpARMMOVWload)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (MOVWstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem)
+	// cond: canMergeSym(sym1,sym2)
+	// result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+	for {
+		off1 := v.AuxInt
+		sym1 := v.Aux
+		v_0 := v.Args[0]
+		if v_0.Op != OpARMADDconst {
+			break
+		}
+		off2 := v_0.AuxInt
+		sym2 := v_0.Aux
+		ptr := v_0.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		if !(canMergeSym(sym1, sym2)) {
+			break
+		}
+		v.reset(OpARMMOVWstore)
+		v.AuxInt = off1 + off2
+		v.Aux = mergeSym(sym1, sym2)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValueARM_OpOffPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (OffPtr [off] ptr)
+	// cond:
+	// result: (ADD (MOVWconst <config.Frontend().TypeInt32()> [off]) ptr)
+	for {
+		off := v.AuxInt
+		ptr := v.Args[0]
+		v.reset(OpARMADD)
+		v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.Frontend().TypeInt32())
+		v0.AuxInt = off
+		v.AddArg(v0)
+		v.AddArg(ptr)
+		return true
+	}
+}
+func rewriteValueARM_OpStaticCall(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (StaticCall [argwid] {target} mem)
+	// cond:
+	// result: (CALLstatic [argwid] {target} mem)
+	for {
+		argwid := v.AuxInt
+		target := v.Aux
+		mem := v.Args[0]
+		v.reset(OpARMCALLstatic)
+		v.AuxInt = argwid
+		v.Aux = target
+		v.AddArg(mem)
+		return true
+	}
+}
+func rewriteValueARM_OpStore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Store [4] ptr val mem)
+	// cond:
+	// result: (MOVWstore ptr val mem)
+	for {
+		if v.AuxInt != 4 {
+			break
+		}
+		ptr := v.Args[0]
+		val := v.Args[1]
+		mem := v.Args[2]
+		v.reset(OpARMMOVWstore)
+		v.AddArg(ptr)
+		v.AddArg(val)
+		v.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteBlockARM(b *Block) bool {
+	switch b.Kind {
+	case BlockIf:
+		// match: (If (LessThan cc) yes no)
+		// cond:
+		// result: (LT cc yes no)
+		for {
+			v := b.Control
+			if v.Op != OpARMLessThan {
+				break
+			}
+			cc := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockARMLT
+			b.SetControl(cc)
+			_ = yes
+			_ = no
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewrite_test.go b/src/cmd/compile/internal/ssa/rewrite_test.go
new file mode 100644
index 0000000..b786df8
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewrite_test.go
@@ -0,0 +1,102 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "testing"
+
+// TestNlzNto tests nlz/nto of the same number which is used in some of
+// the rewrite rules.
+func TestNlzNto(t *testing.T) {
+	// construct the bit pattern 000...111, nlz(x) + nto(0) = 64
+	var x int64
+	for i := int64(0); i < 64; i++ {
+		if got := nto(x); got != i {
+			t.Errorf("expected nto(0x%X) = %d, got %d", x, i, got)
+		}
+		if got := nlz(x); got != 64-i {
+			t.Errorf("expected nlz(0x%X) = %d, got %d", x, 64-i, got)
+		}
+		x = (x << 1) | 1
+	}
+
+	x = 0
+	// construct the bit pattern 000...111, with bit 33 set as well.
+	for i := int64(0); i < 64; i++ {
+		tx := x | (1 << 32)
+		// nto should be the the number of bits we've shifted on, with an extra bit
+		// at iter 32
+		ntoExp := i
+		if ntoExp == 32 {
+			ntoExp = 33
+		}
+		if got := nto(tx); got != ntoExp {
+			t.Errorf("expected nto(0x%X) = %d, got %d", tx, ntoExp, got)
+		}
+
+		// sinec bit 33 is set, nlz can be no greater than 31
+		nlzExp := 64 - i
+		if nlzExp > 31 {
+			nlzExp = 31
+		}
+		if got := nlz(tx); got != nlzExp {
+			t.Errorf("expected nlz(0x%X) = %d, got %d", tx, nlzExp, got)
+		}
+		x = (x << 1) | 1
+	}
+
+}
+
+func TestNlz(t *testing.T) {
+	var nlzTests = []struct {
+		v   int64
+		exp int64
+	}{{0x00, 64},
+		{0x01, 63},
+		{0x0F, 60},
+		{0xFF, 56},
+		{0xffffFFFF, 32},
+		{-0x01, 0}}
+
+	for _, tc := range nlzTests {
+		if got := nlz(tc.v); got != tc.exp {
+			t.Errorf("expected nlz(0x%X) = %d, got %d", tc.v, tc.exp, got)
+		}
+	}
+}
+
+func TestNto(t *testing.T) {
+	var ntoTests = []struct {
+		v   int64
+		exp int64
+	}{{0x00, 0},
+		{0x01, 1},
+		{0x0F, 4},
+		{0xFF, 8},
+		{0xffffFFFF, 32},
+		{-0x01, 64}}
+
+	for _, tc := range ntoTests {
+		if got := nto(tc.v); got != tc.exp {
+			t.Errorf("expected nto(0x%X) = %d, got %d", tc.v, tc.exp, got)
+		}
+	}
+}
+
+func TestLog2(t *testing.T) {
+	var log2Tests = []struct {
+		v   int64
+		exp int64
+	}{{0, -1}, // nlz expects log2(0) == -1
+		{1, 0},
+		{2, 1},
+		{4, 2},
+		{1024, 10}}
+
+	for _, tc := range log2Tests {
+		if got := log2(tc.v); got != tc.exp {
+			t.Errorf("expected log2(%d) = %d, got %d", tc.v, tc.exp, got)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/rewritedec.go b/src/cmd/compile/internal/ssa/rewritedec.go
new file mode 100644
index 0000000..c32d54e
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewritedec.go
@@ -0,0 +1,507 @@
+// autogenerated from gen/dec.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValuedec(v *Value, config *Config) bool {
+	switch v.Op {
+	case OpComplexImag:
+		return rewriteValuedec_OpComplexImag(v, config)
+	case OpComplexReal:
+		return rewriteValuedec_OpComplexReal(v, config)
+	case OpIData:
+		return rewriteValuedec_OpIData(v, config)
+	case OpITab:
+		return rewriteValuedec_OpITab(v, config)
+	case OpLoad:
+		return rewriteValuedec_OpLoad(v, config)
+	case OpSliceCap:
+		return rewriteValuedec_OpSliceCap(v, config)
+	case OpSliceLen:
+		return rewriteValuedec_OpSliceLen(v, config)
+	case OpSlicePtr:
+		return rewriteValuedec_OpSlicePtr(v, config)
+	case OpStore:
+		return rewriteValuedec_OpStore(v, config)
+	case OpStringLen:
+		return rewriteValuedec_OpStringLen(v, config)
+	case OpStringPtr:
+		return rewriteValuedec_OpStringPtr(v, config)
+	}
+	return false
+}
+func rewriteValuedec_OpComplexImag(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ComplexImag (ComplexMake _ imag ))
+	// cond:
+	// result: imag
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpComplexMake {
+			break
+		}
+		imag := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = imag.Type
+		v.AddArg(imag)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpComplexReal(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ComplexReal (ComplexMake real _  ))
+	// cond:
+	// result: real
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpComplexMake {
+			break
+		}
+		real := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = real.Type
+		v.AddArg(real)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpIData(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (IData (IMake _ data))
+	// cond:
+	// result: data
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpIMake {
+			break
+		}
+		data := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = data.Type
+		v.AddArg(data)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpITab(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ITab (IMake itab _))
+	// cond:
+	// result: itab
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpIMake {
+			break
+		}
+		itab := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = itab.Type
+		v.AddArg(itab)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpLoad(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Load <t> ptr mem)
+	// cond: t.IsComplex() && t.Size() == 8
+	// result: (ComplexMake     (Load <config.fe.TypeFloat32()> ptr mem)     (Load <config.fe.TypeFloat32()>       (OffPtr <config.fe.TypeFloat32().PtrTo()> [4] ptr)       mem)     )
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsComplex() && t.Size() == 8) {
+			break
+		}
+		v.reset(OpComplexMake)
+		v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat32())
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat32())
+		v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat32().PtrTo())
+		v2.AuxInt = 4
+		v2.AddArg(ptr)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsComplex() && t.Size() == 16
+	// result: (ComplexMake     (Load <config.fe.TypeFloat64()> ptr mem)     (Load <config.fe.TypeFloat64()>       (OffPtr <config.fe.TypeFloat64().PtrTo()> [8] ptr)       mem)     )
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsComplex() && t.Size() == 16) {
+			break
+		}
+		v.reset(OpComplexMake)
+		v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat64())
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeFloat64())
+		v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat64().PtrTo())
+		v2.AuxInt = 8
+		v2.AddArg(ptr)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsString()
+	// result: (StringMake     (Load <config.fe.TypeBytePtr()> ptr mem)     (Load <config.fe.TypeInt()>       (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] ptr)       mem))
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsString()) {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeBytePtr())
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt())
+		v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
+		v2.AuxInt = config.PtrSize
+		v2.AddArg(ptr)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsSlice()
+	// result: (SliceMake     (Load <t.ElemType().PtrTo()> ptr mem)     (Load <config.fe.TypeInt()>       (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] ptr)       mem)     (Load <config.fe.TypeInt()>       (OffPtr <config.fe.TypeInt().PtrTo()> [2*config.PtrSize] ptr)       mem))
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsSlice()) {
+			break
+		}
+		v.reset(OpSliceMake)
+		v0 := b.NewValue0(v.Line, OpLoad, t.ElemType().PtrTo())
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt())
+		v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
+		v2.AuxInt = config.PtrSize
+		v2.AddArg(ptr)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		v3 := b.NewValue0(v.Line, OpLoad, config.fe.TypeInt())
+		v4 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
+		v4.AuxInt = 2 * config.PtrSize
+		v4.AddArg(ptr)
+		v3.AddArg(v4)
+		v3.AddArg(mem)
+		v.AddArg(v3)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsInterface()
+	// result: (IMake     (Load <config.fe.TypeBytePtr()> ptr mem)     (Load <config.fe.TypeBytePtr()>       (OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] ptr)       mem))
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsInterface()) {
+			break
+		}
+		v.reset(OpIMake)
+		v0 := b.NewValue0(v.Line, OpLoad, config.fe.TypeBytePtr())
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpLoad, config.fe.TypeBytePtr())
+		v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeBytePtr().PtrTo())
+		v2.AuxInt = config.PtrSize
+		v2.AddArg(ptr)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpSliceCap(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SliceCap (SliceMake _ _ cap))
+	// cond:
+	// result: cap
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
+			break
+		}
+		cap := v_0.Args[2]
+		v.reset(OpCopy)
+		v.Type = cap.Type
+		v.AddArg(cap)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpSliceLen(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SliceLen (SliceMake _ len _))
+	// cond:
+	// result: len
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
+			break
+		}
+		len := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = len.Type
+		v.AddArg(len)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpSlicePtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SlicePtr (SliceMake ptr _ _ ))
+	// cond:
+	// result: ptr
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
+			break
+		}
+		ptr := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = ptr.Type
+		v.AddArg(ptr)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpStore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Store [8] dst (ComplexMake real imag) mem)
+	// cond:
+	// result: (Store [4]     (OffPtr <config.fe.TypeFloat32().PtrTo()> [4] dst)     imag     (Store [4] dst real mem))
+	for {
+		if v.AuxInt != 8 {
+			break
+		}
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpComplexMake {
+			break
+		}
+		real := v_1.Args[0]
+		imag := v_1.Args[1]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.AuxInt = 4
+		v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat32().PtrTo())
+		v0.AuxInt = 4
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(imag)
+		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v1.AuxInt = 4
+		v1.AddArg(dst)
+		v1.AddArg(real)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Store [16] dst (ComplexMake real imag) mem)
+	// cond:
+	// result: (Store [8]     (OffPtr <config.fe.TypeFloat64().PtrTo()> [8] dst)     imag     (Store [8] dst real mem))
+	for {
+		if v.AuxInt != 16 {
+			break
+		}
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpComplexMake {
+			break
+		}
+		real := v_1.Args[0]
+		imag := v_1.Args[1]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.AuxInt = 8
+		v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeFloat64().PtrTo())
+		v0.AuxInt = 8
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(imag)
+		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v1.AuxInt = 8
+		v1.AddArg(dst)
+		v1.AddArg(real)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Store [2*config.PtrSize] dst (StringMake ptr len) mem)
+	// cond:
+	// result: (Store [config.PtrSize]     (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] dst)     len     (Store [config.PtrSize] dst ptr mem))
+	for {
+		if v.AuxInt != 2*config.PtrSize {
+			break
+		}
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStringMake {
+			break
+		}
+		ptr := v_1.Args[0]
+		len := v_1.Args[1]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.AuxInt = config.PtrSize
+		v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
+		v0.AuxInt = config.PtrSize
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(len)
+		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v1.AuxInt = config.PtrSize
+		v1.AddArg(dst)
+		v1.AddArg(ptr)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Store [3*config.PtrSize] dst (SliceMake ptr len cap) mem)
+	// cond:
+	// result: (Store [config.PtrSize]     (OffPtr <config.fe.TypeInt().PtrTo()> [2*config.PtrSize] dst)     cap     (Store [config.PtrSize]       (OffPtr <config.fe.TypeInt().PtrTo()> [config.PtrSize] dst)       len       (Store [config.PtrSize] dst ptr mem)))
+	for {
+		if v.AuxInt != 3*config.PtrSize {
+			break
+		}
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSliceMake {
+			break
+		}
+		ptr := v_1.Args[0]
+		len := v_1.Args[1]
+		cap := v_1.Args[2]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.AuxInt = config.PtrSize
+		v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
+		v0.AuxInt = 2 * config.PtrSize
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(cap)
+		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v1.AuxInt = config.PtrSize
+		v2 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeInt().PtrTo())
+		v2.AuxInt = config.PtrSize
+		v2.AddArg(dst)
+		v1.AddArg(v2)
+		v1.AddArg(len)
+		v3 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v3.AuxInt = config.PtrSize
+		v3.AddArg(dst)
+		v3.AddArg(ptr)
+		v3.AddArg(mem)
+		v1.AddArg(v3)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Store [2*config.PtrSize] dst (IMake itab data) mem)
+	// cond:
+	// result: (Store [config.PtrSize]     (OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] dst)     data     (Store [config.PtrSize] dst itab mem))
+	for {
+		if v.AuxInt != 2*config.PtrSize {
+			break
+		}
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpIMake {
+			break
+		}
+		itab := v_1.Args[0]
+		data := v_1.Args[1]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.AuxInt = config.PtrSize
+		v0 := b.NewValue0(v.Line, OpOffPtr, config.fe.TypeBytePtr().PtrTo())
+		v0.AuxInt = config.PtrSize
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(data)
+		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v1.AuxInt = config.PtrSize
+		v1.AddArg(dst)
+		v1.AddArg(itab)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpStringLen(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (StringLen (StringMake _ len))
+	// cond:
+	// result: len
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStringMake {
+			break
+		}
+		len := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = len.Type
+		v.AddArg(len)
+		return true
+	}
+	return false
+}
+func rewriteValuedec_OpStringPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (StringPtr (StringMake ptr _))
+	// cond:
+	// result: ptr
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStringMake {
+			break
+		}
+		ptr := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = ptr.Type
+		v.AddArg(ptr)
+		return true
+	}
+	return false
+}
+func rewriteBlockdec(b *Block) bool {
+	switch b.Kind {
+	}
+	return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
new file mode 100644
index 0000000..9f08b3c
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -0,0 +1,10385 @@
+// autogenerated from gen/generic.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValuegeneric(v *Value, config *Config) bool {
+	switch v.Op {
+	case OpAdd16:
+		return rewriteValuegeneric_OpAdd16(v, config)
+	case OpAdd32:
+		return rewriteValuegeneric_OpAdd32(v, config)
+	case OpAdd32F:
+		return rewriteValuegeneric_OpAdd32F(v, config)
+	case OpAdd64:
+		return rewriteValuegeneric_OpAdd64(v, config)
+	case OpAdd64F:
+		return rewriteValuegeneric_OpAdd64F(v, config)
+	case OpAdd8:
+		return rewriteValuegeneric_OpAdd8(v, config)
+	case OpAddPtr:
+		return rewriteValuegeneric_OpAddPtr(v, config)
+	case OpAnd16:
+		return rewriteValuegeneric_OpAnd16(v, config)
+	case OpAnd32:
+		return rewriteValuegeneric_OpAnd32(v, config)
+	case OpAnd64:
+		return rewriteValuegeneric_OpAnd64(v, config)
+	case OpAnd8:
+		return rewriteValuegeneric_OpAnd8(v, config)
+	case OpArg:
+		return rewriteValuegeneric_OpArg(v, config)
+	case OpArrayIndex:
+		return rewriteValuegeneric_OpArrayIndex(v, config)
+	case OpCom16:
+		return rewriteValuegeneric_OpCom16(v, config)
+	case OpCom32:
+		return rewriteValuegeneric_OpCom32(v, config)
+	case OpCom64:
+		return rewriteValuegeneric_OpCom64(v, config)
+	case OpCom8:
+		return rewriteValuegeneric_OpCom8(v, config)
+	case OpConstInterface:
+		return rewriteValuegeneric_OpConstInterface(v, config)
+	case OpConstSlice:
+		return rewriteValuegeneric_OpConstSlice(v, config)
+	case OpConstString:
+		return rewriteValuegeneric_OpConstString(v, config)
+	case OpConvert:
+		return rewriteValuegeneric_OpConvert(v, config)
+	case OpCvt32Fto64F:
+		return rewriteValuegeneric_OpCvt32Fto64F(v, config)
+	case OpCvt64Fto32F:
+		return rewriteValuegeneric_OpCvt64Fto32F(v, config)
+	case OpDiv64:
+		return rewriteValuegeneric_OpDiv64(v, config)
+	case OpDiv64u:
+		return rewriteValuegeneric_OpDiv64u(v, config)
+	case OpEq16:
+		return rewriteValuegeneric_OpEq16(v, config)
+	case OpEq32:
+		return rewriteValuegeneric_OpEq32(v, config)
+	case OpEq64:
+		return rewriteValuegeneric_OpEq64(v, config)
+	case OpEq8:
+		return rewriteValuegeneric_OpEq8(v, config)
+	case OpEqB:
+		return rewriteValuegeneric_OpEqB(v, config)
+	case OpEqInter:
+		return rewriteValuegeneric_OpEqInter(v, config)
+	case OpEqPtr:
+		return rewriteValuegeneric_OpEqPtr(v, config)
+	case OpEqSlice:
+		return rewriteValuegeneric_OpEqSlice(v, config)
+	case OpGeq16:
+		return rewriteValuegeneric_OpGeq16(v, config)
+	case OpGeq16U:
+		return rewriteValuegeneric_OpGeq16U(v, config)
+	case OpGeq32:
+		return rewriteValuegeneric_OpGeq32(v, config)
+	case OpGeq32U:
+		return rewriteValuegeneric_OpGeq32U(v, config)
+	case OpGeq64:
+		return rewriteValuegeneric_OpGeq64(v, config)
+	case OpGeq64U:
+		return rewriteValuegeneric_OpGeq64U(v, config)
+	case OpGeq8:
+		return rewriteValuegeneric_OpGeq8(v, config)
+	case OpGeq8U:
+		return rewriteValuegeneric_OpGeq8U(v, config)
+	case OpGreater16:
+		return rewriteValuegeneric_OpGreater16(v, config)
+	case OpGreater16U:
+		return rewriteValuegeneric_OpGreater16U(v, config)
+	case OpGreater32:
+		return rewriteValuegeneric_OpGreater32(v, config)
+	case OpGreater32U:
+		return rewriteValuegeneric_OpGreater32U(v, config)
+	case OpGreater64:
+		return rewriteValuegeneric_OpGreater64(v, config)
+	case OpGreater64U:
+		return rewriteValuegeneric_OpGreater64U(v, config)
+	case OpGreater8:
+		return rewriteValuegeneric_OpGreater8(v, config)
+	case OpGreater8U:
+		return rewriteValuegeneric_OpGreater8U(v, config)
+	case OpIsInBounds:
+		return rewriteValuegeneric_OpIsInBounds(v, config)
+	case OpIsSliceInBounds:
+		return rewriteValuegeneric_OpIsSliceInBounds(v, config)
+	case OpLeq16:
+		return rewriteValuegeneric_OpLeq16(v, config)
+	case OpLeq16U:
+		return rewriteValuegeneric_OpLeq16U(v, config)
+	case OpLeq32:
+		return rewriteValuegeneric_OpLeq32(v, config)
+	case OpLeq32U:
+		return rewriteValuegeneric_OpLeq32U(v, config)
+	case OpLeq64:
+		return rewriteValuegeneric_OpLeq64(v, config)
+	case OpLeq64U:
+		return rewriteValuegeneric_OpLeq64U(v, config)
+	case OpLeq8:
+		return rewriteValuegeneric_OpLeq8(v, config)
+	case OpLeq8U:
+		return rewriteValuegeneric_OpLeq8U(v, config)
+	case OpLess16:
+		return rewriteValuegeneric_OpLess16(v, config)
+	case OpLess16U:
+		return rewriteValuegeneric_OpLess16U(v, config)
+	case OpLess32:
+		return rewriteValuegeneric_OpLess32(v, config)
+	case OpLess32U:
+		return rewriteValuegeneric_OpLess32U(v, config)
+	case OpLess64:
+		return rewriteValuegeneric_OpLess64(v, config)
+	case OpLess64U:
+		return rewriteValuegeneric_OpLess64U(v, config)
+	case OpLess8:
+		return rewriteValuegeneric_OpLess8(v, config)
+	case OpLess8U:
+		return rewriteValuegeneric_OpLess8U(v, config)
+	case OpLoad:
+		return rewriteValuegeneric_OpLoad(v, config)
+	case OpLsh16x16:
+		return rewriteValuegeneric_OpLsh16x16(v, config)
+	case OpLsh16x32:
+		return rewriteValuegeneric_OpLsh16x32(v, config)
+	case OpLsh16x64:
+		return rewriteValuegeneric_OpLsh16x64(v, config)
+	case OpLsh16x8:
+		return rewriteValuegeneric_OpLsh16x8(v, config)
+	case OpLsh32x16:
+		return rewriteValuegeneric_OpLsh32x16(v, config)
+	case OpLsh32x32:
+		return rewriteValuegeneric_OpLsh32x32(v, config)
+	case OpLsh32x64:
+		return rewriteValuegeneric_OpLsh32x64(v, config)
+	case OpLsh32x8:
+		return rewriteValuegeneric_OpLsh32x8(v, config)
+	case OpLsh64x16:
+		return rewriteValuegeneric_OpLsh64x16(v, config)
+	case OpLsh64x32:
+		return rewriteValuegeneric_OpLsh64x32(v, config)
+	case OpLsh64x64:
+		return rewriteValuegeneric_OpLsh64x64(v, config)
+	case OpLsh64x8:
+		return rewriteValuegeneric_OpLsh64x8(v, config)
+	case OpLsh8x16:
+		return rewriteValuegeneric_OpLsh8x16(v, config)
+	case OpLsh8x32:
+		return rewriteValuegeneric_OpLsh8x32(v, config)
+	case OpLsh8x64:
+		return rewriteValuegeneric_OpLsh8x64(v, config)
+	case OpLsh8x8:
+		return rewriteValuegeneric_OpLsh8x8(v, config)
+	case OpMod16:
+		return rewriteValuegeneric_OpMod16(v, config)
+	case OpMod16u:
+		return rewriteValuegeneric_OpMod16u(v, config)
+	case OpMod32:
+		return rewriteValuegeneric_OpMod32(v, config)
+	case OpMod32u:
+		return rewriteValuegeneric_OpMod32u(v, config)
+	case OpMod64:
+		return rewriteValuegeneric_OpMod64(v, config)
+	case OpMod64u:
+		return rewriteValuegeneric_OpMod64u(v, config)
+	case OpMod8:
+		return rewriteValuegeneric_OpMod8(v, config)
+	case OpMod8u:
+		return rewriteValuegeneric_OpMod8u(v, config)
+	case OpMul16:
+		return rewriteValuegeneric_OpMul16(v, config)
+	case OpMul32:
+		return rewriteValuegeneric_OpMul32(v, config)
+	case OpMul32F:
+		return rewriteValuegeneric_OpMul32F(v, config)
+	case OpMul64:
+		return rewriteValuegeneric_OpMul64(v, config)
+	case OpMul64F:
+		return rewriteValuegeneric_OpMul64F(v, config)
+	case OpMul8:
+		return rewriteValuegeneric_OpMul8(v, config)
+	case OpNeg16:
+		return rewriteValuegeneric_OpNeg16(v, config)
+	case OpNeg32:
+		return rewriteValuegeneric_OpNeg32(v, config)
+	case OpNeg64:
+		return rewriteValuegeneric_OpNeg64(v, config)
+	case OpNeg8:
+		return rewriteValuegeneric_OpNeg8(v, config)
+	case OpNeq16:
+		return rewriteValuegeneric_OpNeq16(v, config)
+	case OpNeq32:
+		return rewriteValuegeneric_OpNeq32(v, config)
+	case OpNeq64:
+		return rewriteValuegeneric_OpNeq64(v, config)
+	case OpNeq8:
+		return rewriteValuegeneric_OpNeq8(v, config)
+	case OpNeqB:
+		return rewriteValuegeneric_OpNeqB(v, config)
+	case OpNeqInter:
+		return rewriteValuegeneric_OpNeqInter(v, config)
+	case OpNeqPtr:
+		return rewriteValuegeneric_OpNeqPtr(v, config)
+	case OpNeqSlice:
+		return rewriteValuegeneric_OpNeqSlice(v, config)
+	case OpOffPtr:
+		return rewriteValuegeneric_OpOffPtr(v, config)
+	case OpOr16:
+		return rewriteValuegeneric_OpOr16(v, config)
+	case OpOr32:
+		return rewriteValuegeneric_OpOr32(v, config)
+	case OpOr64:
+		return rewriteValuegeneric_OpOr64(v, config)
+	case OpOr8:
+		return rewriteValuegeneric_OpOr8(v, config)
+	case OpPhi:
+		return rewriteValuegeneric_OpPhi(v, config)
+	case OpPtrIndex:
+		return rewriteValuegeneric_OpPtrIndex(v, config)
+	case OpRsh16Ux16:
+		return rewriteValuegeneric_OpRsh16Ux16(v, config)
+	case OpRsh16Ux32:
+		return rewriteValuegeneric_OpRsh16Ux32(v, config)
+	case OpRsh16Ux64:
+		return rewriteValuegeneric_OpRsh16Ux64(v, config)
+	case OpRsh16Ux8:
+		return rewriteValuegeneric_OpRsh16Ux8(v, config)
+	case OpRsh16x16:
+		return rewriteValuegeneric_OpRsh16x16(v, config)
+	case OpRsh16x32:
+		return rewriteValuegeneric_OpRsh16x32(v, config)
+	case OpRsh16x64:
+		return rewriteValuegeneric_OpRsh16x64(v, config)
+	case OpRsh16x8:
+		return rewriteValuegeneric_OpRsh16x8(v, config)
+	case OpRsh32Ux16:
+		return rewriteValuegeneric_OpRsh32Ux16(v, config)
+	case OpRsh32Ux32:
+		return rewriteValuegeneric_OpRsh32Ux32(v, config)
+	case OpRsh32Ux64:
+		return rewriteValuegeneric_OpRsh32Ux64(v, config)
+	case OpRsh32Ux8:
+		return rewriteValuegeneric_OpRsh32Ux8(v, config)
+	case OpRsh32x16:
+		return rewriteValuegeneric_OpRsh32x16(v, config)
+	case OpRsh32x32:
+		return rewriteValuegeneric_OpRsh32x32(v, config)
+	case OpRsh32x64:
+		return rewriteValuegeneric_OpRsh32x64(v, config)
+	case OpRsh32x8:
+		return rewriteValuegeneric_OpRsh32x8(v, config)
+	case OpRsh64Ux16:
+		return rewriteValuegeneric_OpRsh64Ux16(v, config)
+	case OpRsh64Ux32:
+		return rewriteValuegeneric_OpRsh64Ux32(v, config)
+	case OpRsh64Ux64:
+		return rewriteValuegeneric_OpRsh64Ux64(v, config)
+	case OpRsh64Ux8:
+		return rewriteValuegeneric_OpRsh64Ux8(v, config)
+	case OpRsh64x16:
+		return rewriteValuegeneric_OpRsh64x16(v, config)
+	case OpRsh64x32:
+		return rewriteValuegeneric_OpRsh64x32(v, config)
+	case OpRsh64x64:
+		return rewriteValuegeneric_OpRsh64x64(v, config)
+	case OpRsh64x8:
+		return rewriteValuegeneric_OpRsh64x8(v, config)
+	case OpRsh8Ux16:
+		return rewriteValuegeneric_OpRsh8Ux16(v, config)
+	case OpRsh8Ux32:
+		return rewriteValuegeneric_OpRsh8Ux32(v, config)
+	case OpRsh8Ux64:
+		return rewriteValuegeneric_OpRsh8Ux64(v, config)
+	case OpRsh8Ux8:
+		return rewriteValuegeneric_OpRsh8Ux8(v, config)
+	case OpRsh8x16:
+		return rewriteValuegeneric_OpRsh8x16(v, config)
+	case OpRsh8x32:
+		return rewriteValuegeneric_OpRsh8x32(v, config)
+	case OpRsh8x64:
+		return rewriteValuegeneric_OpRsh8x64(v, config)
+	case OpRsh8x8:
+		return rewriteValuegeneric_OpRsh8x8(v, config)
+	case OpSliceCap:
+		return rewriteValuegeneric_OpSliceCap(v, config)
+	case OpSliceLen:
+		return rewriteValuegeneric_OpSliceLen(v, config)
+	case OpSlicePtr:
+		return rewriteValuegeneric_OpSlicePtr(v, config)
+	case OpStore:
+		return rewriteValuegeneric_OpStore(v, config)
+	case OpStringLen:
+		return rewriteValuegeneric_OpStringLen(v, config)
+	case OpStringPtr:
+		return rewriteValuegeneric_OpStringPtr(v, config)
+	case OpStructSelect:
+		return rewriteValuegeneric_OpStructSelect(v, config)
+	case OpSub16:
+		return rewriteValuegeneric_OpSub16(v, config)
+	case OpSub32:
+		return rewriteValuegeneric_OpSub32(v, config)
+	case OpSub32F:
+		return rewriteValuegeneric_OpSub32F(v, config)
+	case OpSub64:
+		return rewriteValuegeneric_OpSub64(v, config)
+	case OpSub64F:
+		return rewriteValuegeneric_OpSub64F(v, config)
+	case OpSub8:
+		return rewriteValuegeneric_OpSub8(v, config)
+	case OpTrunc16to8:
+		return rewriteValuegeneric_OpTrunc16to8(v, config)
+	case OpTrunc32to16:
+		return rewriteValuegeneric_OpTrunc32to16(v, config)
+	case OpTrunc32to8:
+		return rewriteValuegeneric_OpTrunc32to8(v, config)
+	case OpTrunc64to16:
+		return rewriteValuegeneric_OpTrunc64to16(v, config)
+	case OpTrunc64to32:
+		return rewriteValuegeneric_OpTrunc64to32(v, config)
+	case OpTrunc64to8:
+		return rewriteValuegeneric_OpTrunc64to8(v, config)
+	case OpXor16:
+		return rewriteValuegeneric_OpXor16(v, config)
+	case OpXor32:
+		return rewriteValuegeneric_OpXor32(v, config)
+	case OpXor64:
+		return rewriteValuegeneric_OpXor64(v, config)
+	case OpXor8:
+		return rewriteValuegeneric_OpXor8(v, config)
+	}
+	return false
+}
+func rewriteValuegeneric_OpAdd16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add16  (Const16 [c])  (Const16 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(c+d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c + d))
+		return true
+	}
+	// match: (Add16 x (Const16 <t> [c]))
+	// cond: x.Op != OpConst16
+	// result: (Add16 (Const16 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Add16 (Const16 [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAdd32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add32  (Const32 [c])  (Const32 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(c+d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c + d))
+		return true
+	}
+	// match: (Add32 x (Const32 <t> [c]))
+	// cond: x.Op != OpConst32
+	// result: (Add32 (Const32 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Add32 (Const32 [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAdd32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add32F (Const32F [c]) (Const32F [d]))
+	// cond:
+	// result: (Const32F [f2i(float64(i2f32(c) + i2f32(d)))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst32F)
+		v.AuxInt = f2i(float64(i2f32(c) + i2f32(d)))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAdd64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add64  (Const64 [c])  (Const64 [d]))
+	// cond:
+	// result: (Const64 [c+d])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c + d
+		return true
+	}
+	// match: (Add64 x (Const64 <t> [c]))
+	// cond: x.Op != OpConst64
+	// result: (Add64 (Const64 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Add64 (Const64 [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAdd64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add64F (Const64F [c]) (Const64F [d]))
+	// cond:
+	// result: (Const64F [f2i(i2f(c) + i2f(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64F {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst64F)
+		v.AuxInt = f2i(i2f(c) + i2f(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAdd8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Add8   (Const8 [c])   (Const8 [d]))
+	// cond:
+	// result: (Const8  [int64(int8(c+d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c + d))
+		return true
+	}
+	// match: (Add8  x (Const8  <t> [c]))
+	// cond: x.Op != OpConst8
+	// result: (Add8  (Const8  <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Add8  (Const8  [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAddPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (AddPtr <t> x (Const64 [c]))
+	// cond:
+	// result: (OffPtr <t> x [c])
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpOffPtr)
+		v.Type = t
+		v.AddArg(x)
+		v.AuxInt = c
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAnd16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (And16 x (Const16 <t> [c]))
+	// cond: x.Op != OpConst16
+	// result: (And16 (Const16 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAnd16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (And16 x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (And16 (Const16 [-1]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (And16 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (And16 x (And16 x y))
+	// cond:
+	// result: (And16 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd16 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpAnd16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And16 x (And16 y x))
+	// cond:
+	// result: (And16 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd16 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAnd16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And16 (And16 x y) x)
+	// cond:
+	// result: (And16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And16 (And16 x y) y)
+	// cond:
+	// result: (And16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAnd32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (And32 x (Const32 <t> [c]))
+	// cond: x.Op != OpConst32
+	// result: (And32 (Const32 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAnd32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (And32 x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (And32 (Const32 [-1]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (And32 (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (And32 x (And32 x y))
+	// cond:
+	// result: (And32 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd32 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpAnd32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And32 x (And32 y x))
+	// cond:
+	// result: (And32 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd32 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAnd32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And32 (And32 x y) x)
+	// cond:
+	// result: (And32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And32 (And32 x y) y)
+	// cond:
+	// result: (And32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAnd64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (And64 x (Const64 <t> [c]))
+	// cond: x.Op != OpConst64
+	// result: (And64 (Const64 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAnd64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (And64 x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (And64 (Const64 [-1]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (And64 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (And64 x (And64 x y))
+	// cond:
+	// result: (And64 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd64 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpAnd64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And64 x (And64 y x))
+	// cond:
+	// result: (And64 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd64 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAnd64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And64 (And64 x y) x)
+	// cond:
+	// result: (And64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And64 (And64 x y) y)
+	// cond:
+	// result: (And64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And64 <t> (Const64 [y]) x)
+	// cond: nlz(y) + nto(y) == 64 && nto(y) >= 32
+	// result: (Rsh64Ux64 (Lsh64x64 <t> x (Const64 <t> [nlz(y)])) (Const64 <t> [nlz(y)]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		y := v_0.AuxInt
+		x := v.Args[1]
+		if !(nlz(y)+nto(y) == 64 && nto(y) >= 32) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v0 := b.NewValue0(v.Line, OpLsh64x64, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Line, OpConst64, t)
+		v1.AuxInt = nlz(y)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2.AuxInt = nlz(y)
+		v.AddArg(v2)
+		return true
+	}
+	// match: (And64 <t> (Const64 [y]) x)
+	// cond: nlo(y) + ntz(y) == 64 && ntz(y) >= 32
+	// result: (Lsh64x64 (Rsh64Ux64 <t> x (Const64 <t> [ntz(y)])) (Const64 <t> [ntz(y)]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		y := v_0.AuxInt
+		x := v.Args[1]
+		if !(nlo(y)+ntz(y) == 64 && ntz(y) >= 32) {
+			break
+		}
+		v.reset(OpLsh64x64)
+		v0 := b.NewValue0(v.Line, OpRsh64Ux64, t)
+		v0.AddArg(x)
+		v1 := b.NewValue0(v.Line, OpConst64, t)
+		v1.AuxInt = ntz(y)
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2.AuxInt = ntz(y)
+		v.AddArg(v2)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpAnd8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (And8  x (Const8  <t> [c]))
+	// cond: x.Op != OpConst8
+	// result: (And8  (Const8  <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAnd8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (And8  x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (And8  (Const8  [-1]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (And8  (Const8  [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (And8  x (And8  x y))
+	// cond:
+	// result: (And8  x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd8 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpAnd8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And8  x (And8  y x))
+	// cond:
+	// result: (And8  x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpAnd8 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpAnd8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And8  (And8  x y) x)
+	// cond:
+	// result: (And8  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd8 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (And8  (And8  x y) y)
+	// cond:
+	// result: (And8  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd8 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpAnd8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsString()
+	// result: (StringMake     (Arg <config.fe.TypeBytePtr()> {n} [off])     (Arg <config.fe.TypeInt()> {n} [off+config.PtrSize]))
+	for {
+		n := v.Aux
+		off := v.AuxInt
+		if !(v.Type.IsString()) {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeBytePtr())
+		v0.Aux = n
+		v0.AuxInt = off
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt())
+		v1.Aux = n
+		v1.AuxInt = off + config.PtrSize
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsSlice()
+	// result: (SliceMake     (Arg <v.Type.ElemType().PtrTo()> {n} [off])     (Arg <config.fe.TypeInt()> {n} [off+config.PtrSize])     (Arg <config.fe.TypeInt()> {n} [off+2*config.PtrSize]))
+	for {
+		n := v.Aux
+		off := v.AuxInt
+		if !(v.Type.IsSlice()) {
+			break
+		}
+		v.reset(OpSliceMake)
+		v0 := b.NewValue0(v.Line, OpArg, v.Type.ElemType().PtrTo())
+		v0.Aux = n
+		v0.AuxInt = off
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt())
+		v1.Aux = n
+		v1.AuxInt = off + config.PtrSize
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt())
+		v2.Aux = n
+		v2.AuxInt = off + 2*config.PtrSize
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsInterface()
+	// result: (IMake     (Arg <config.fe.TypeBytePtr()> {n} [off])     (Arg <config.fe.TypeBytePtr()> {n} [off+config.PtrSize]))
+	for {
+		n := v.Aux
+		off := v.AuxInt
+		if !(v.Type.IsInterface()) {
+			break
+		}
+		v.reset(OpIMake)
+		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeBytePtr())
+		v0.Aux = n
+		v0.AuxInt = off
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeBytePtr())
+		v1.Aux = n
+		v1.AuxInt = off + config.PtrSize
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsComplex() && v.Type.Size() == 16
+	// result: (ComplexMake     (Arg <config.fe.TypeFloat64()> {n} [off])     (Arg <config.fe.TypeFloat64()> {n} [off+8]))
+	for {
+		n := v.Aux
+		off := v.AuxInt
+		if !(v.Type.IsComplex() && v.Type.Size() == 16) {
+			break
+		}
+		v.reset(OpComplexMake)
+		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat64())
+		v0.Aux = n
+		v0.AuxInt = off
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat64())
+		v1.Aux = n
+		v1.AuxInt = off + 8
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Arg {n} [off])
+	// cond: v.Type.IsComplex() && v.Type.Size() == 8
+	// result: (ComplexMake     (Arg <config.fe.TypeFloat32()> {n} [off])     (Arg <config.fe.TypeFloat32()> {n} [off+4]))
+	for {
+		n := v.Aux
+		off := v.AuxInt
+		if !(v.Type.IsComplex() && v.Type.Size() == 8) {
+			break
+		}
+		v.reset(OpComplexMake)
+		v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat32())
+		v0.Aux = n
+		v0.AuxInt = off
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat32())
+		v1.Aux = n
+		v1.AuxInt = off + 4
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Arg <t>)
+	// cond: t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t)
+	// result: (StructMake0)
+	for {
+		t := v.Type
+		if !(t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake0)
+		return true
+	}
+	// match: (Arg <t> {n} [off])
+	// cond: t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t)
+	// result: (StructMake1     (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)]))
+	for {
+		t := v.Type
+		n := v.Aux
+		off := v.AuxInt
+		if !(t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake1)
+		v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
+		v0.Aux = n
+		v0.AuxInt = off + t.FieldOff(0)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Arg <t> {n} [off])
+	// cond: t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t)
+	// result: (StructMake2     (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])     (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)]))
+	for {
+		t := v.Type
+		n := v.Aux
+		off := v.AuxInt
+		if !(t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake2)
+		v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
+		v0.Aux = n
+		v0.AuxInt = off + t.FieldOff(0)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpArg, t.FieldType(1))
+		v1.Aux = n
+		v1.AuxInt = off + t.FieldOff(1)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Arg <t> {n} [off])
+	// cond: t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t)
+	// result: (StructMake3     (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])     (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)])     (Arg <t.FieldType(2)> {n} [off+t.FieldOff(2)]))
+	for {
+		t := v.Type
+		n := v.Aux
+		off := v.AuxInt
+		if !(t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake3)
+		v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
+		v0.Aux = n
+		v0.AuxInt = off + t.FieldOff(0)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpArg, t.FieldType(1))
+		v1.Aux = n
+		v1.AuxInt = off + t.FieldOff(1)
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Line, OpArg, t.FieldType(2))
+		v2.Aux = n
+		v2.AuxInt = off + t.FieldOff(2)
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Arg <t> {n} [off])
+	// cond: t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t)
+	// result: (StructMake4     (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])     (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)])     (Arg <t.FieldType(2)> {n} [off+t.FieldOff(2)])     (Arg <t.FieldType(3)> {n} [off+t.FieldOff(3)]))
+	for {
+		t := v.Type
+		n := v.Aux
+		off := v.AuxInt
+		if !(t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake4)
+		v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
+		v0.Aux = n
+		v0.AuxInt = off + t.FieldOff(0)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpArg, t.FieldType(1))
+		v1.Aux = n
+		v1.AuxInt = off + t.FieldOff(1)
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Line, OpArg, t.FieldType(2))
+		v2.Aux = n
+		v2.AuxInt = off + t.FieldOff(2)
+		v.AddArg(v2)
+		v3 := b.NewValue0(v.Line, OpArg, t.FieldType(3))
+		v3.Aux = n
+		v3.AuxInt = off + t.FieldOff(3)
+		v.AddArg(v3)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpArrayIndex(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ArrayIndex <t> [0] x:(Load ptr mem))
+	// cond:
+	// result: @x.Block (Load <t> ptr mem)
+	for {
+		t := v.Type
+		if v.AuxInt != 0 {
+			break
+		}
+		x := v.Args[0]
+		if x.Op != OpLoad {
+			break
+		}
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpLoad, t)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCom16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Com16 (Com16 x))
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpCom16 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCom32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Com32 (Com32 x))
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpCom32 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCom64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Com64 (Com64 x))
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpCom64 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCom8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Com8  (Com8  x))
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpCom8 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpConstInterface(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ConstInterface)
+	// cond:
+	// result: (IMake     (ConstNil <config.fe.TypeBytePtr()>)     (ConstNil <config.fe.TypeBytePtr()>))
+	for {
+		v.reset(OpIMake)
+		v0 := b.NewValue0(v.Line, OpConstNil, config.fe.TypeBytePtr())
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpConstNil, config.fe.TypeBytePtr())
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpConstSlice(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ConstSlice)
+	// cond: config.PtrSize == 4
+	// result: (SliceMake     (ConstNil <v.Type.ElemType().PtrTo()>)     (Const32 <config.fe.TypeInt()> [0])     (Const32 <config.fe.TypeInt()> [0]))
+	for {
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpSliceMake)
+		v0 := b.NewValue0(v.Line, OpConstNil, v.Type.ElemType().PtrTo())
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpConst32, config.fe.TypeInt())
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Line, OpConst32, config.fe.TypeInt())
+		v2.AuxInt = 0
+		v.AddArg(v2)
+		return true
+	}
+	// match: (ConstSlice)
+	// cond: config.PtrSize == 8
+	// result: (SliceMake     (ConstNil <v.Type.ElemType().PtrTo()>)     (Const64 <config.fe.TypeInt()> [0])     (Const64 <config.fe.TypeInt()> [0]))
+	for {
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpSliceMake)
+		v0 := b.NewValue0(v.Line, OpConstNil, v.Type.ElemType().PtrTo())
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpConst64, config.fe.TypeInt())
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeInt())
+		v2.AuxInt = 0
+		v.AddArg(v2)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpConstString(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (ConstString {s})
+	// cond: config.PtrSize == 4 && s.(string) == ""
+	// result: (StringMake (ConstNil) (Const32 <config.fe.TypeInt()> [0]))
+	for {
+		s := v.Aux
+		if !(config.PtrSize == 4 && s.(string) == "") {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Line, OpConstNil, config.fe.TypeBytePtr())
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpConst32, config.fe.TypeInt())
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		return true
+	}
+	// match: (ConstString {s})
+	// cond: config.PtrSize == 8 && s.(string) == ""
+	// result: (StringMake (ConstNil) (Const64 <config.fe.TypeInt()> [0]))
+	for {
+		s := v.Aux
+		if !(config.PtrSize == 8 && s.(string) == "") {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Line, OpConstNil, config.fe.TypeBytePtr())
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpConst64, config.fe.TypeInt())
+		v1.AuxInt = 0
+		v.AddArg(v1)
+		return true
+	}
+	// match: (ConstString {s})
+	// cond: config.PtrSize == 4 && s.(string) != ""
+	// result: (StringMake     (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}       (SB))     (Const32 <config.fe.TypeInt()> [int64(len(s.(string)))]))
+	for {
+		s := v.Aux
+		if !(config.PtrSize == 4 && s.(string) != "") {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Line, OpAddr, config.fe.TypeBytePtr())
+		v0.Aux = config.fe.StringData(s.(string))
+		v1 := b.NewValue0(v.Line, OpSB, config.fe.TypeUintptr())
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Line, OpConst32, config.fe.TypeInt())
+		v2.AuxInt = int64(len(s.(string)))
+		v.AddArg(v2)
+		return true
+	}
+	// match: (ConstString {s})
+	// cond: config.PtrSize == 8 && s.(string) != ""
+	// result: (StringMake     (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}       (SB))     (Const64 <config.fe.TypeInt()> [int64(len(s.(string)))]))
+	for {
+		s := v.Aux
+		if !(config.PtrSize == 8 && s.(string) != "") {
+			break
+		}
+		v.reset(OpStringMake)
+		v0 := b.NewValue0(v.Line, OpAddr, config.fe.TypeBytePtr())
+		v0.Aux = config.fe.StringData(s.(string))
+		v1 := b.NewValue0(v.Line, OpSB, config.fe.TypeUintptr())
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Line, OpConst64, config.fe.TypeInt())
+		v2.AuxInt = int64(len(s.(string)))
+		v.AddArg(v2)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpConvert(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Convert (Add64 (Convert ptr mem) off) mem)
+	// cond:
+	// result: (Add64 ptr off)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConvert {
+			break
+		}
+		ptr := v_0_0.Args[0]
+		mem := v_0_0.Args[1]
+		off := v_0.Args[1]
+		if mem != v.Args[1] {
+			break
+		}
+		v.reset(OpAdd64)
+		v.AddArg(ptr)
+		v.AddArg(off)
+		return true
+	}
+	// match: (Convert (Add64 off (Convert ptr mem)) mem)
+	// cond:
+	// result: (Add64 ptr off)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		off := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConvert {
+			break
+		}
+		ptr := v_0_1.Args[0]
+		mem := v_0_1.Args[1]
+		if mem != v.Args[1] {
+			break
+		}
+		v.reset(OpAdd64)
+		v.AddArg(ptr)
+		v.AddArg(off)
+		return true
+	}
+	// match: (Convert (Convert ptr mem) mem)
+	// cond:
+	// result: ptr
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConvert {
+			break
+		}
+		ptr := v_0.Args[0]
+		mem := v_0.Args[1]
+		if mem != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = ptr.Type
+		v.AddArg(ptr)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCvt32Fto64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt32Fto64F (Const32F [c]))
+	// cond:
+	// result: (Const64F [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst64F)
+		v.AuxInt = c
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpCvt64Fto32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Cvt64Fto32F (Const64F [c]))
+	// cond:
+	// result: (Const32F [f2i(float64(i2f32(c)))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64F {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst32F)
+		v.AuxInt = f2i(float64(i2f32(c)))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div64 <t> x (Const64 [c]))
+	// cond: c > 0 && smagic64ok(c) && smagic64m(c) > 0
+	// result: (Sub64 <t>     (Rsh64x64 <t>       (Hmul64 <t>         (Const64 <t> [smagic64m(c)])         x)       (Const64 <t> [smagic64s(c)]))     (Rsh64x64 <t>       x       (Const64 <t> [63])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c > 0 && smagic64ok(c) && smagic64m(c) > 0) {
+			break
+		}
+		v.reset(OpSub64)
+		v.Type = t
+		v0 := b.NewValue0(v.Line, OpRsh64x64, t)
+		v1 := b.NewValue0(v.Line, OpHmul64, t)
+		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2.AuxInt = smagic64m(c)
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3.AuxInt = smagic64s(c)
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		v4 := b.NewValue0(v.Line, OpRsh64x64, t)
+		v4.AddArg(x)
+		v5 := b.NewValue0(v.Line, OpConst64, t)
+		v5.AuxInt = 63
+		v4.AddArg(v5)
+		v.AddArg(v4)
+		return true
+	}
+	// match: (Div64 <t> x (Const64 [c]))
+	// cond: c > 0 && smagic64ok(c) && smagic64m(c) < 0
+	// result: (Sub64 <t>     (Rsh64x64 <t>       (Add64 <t>         (Hmul64 <t>           (Const64 <t> [smagic64m(c)])           x)         x)       (Const64 <t> [smagic64s(c)]))     (Rsh64x64 <t>       x       (Const64 <t> [63])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c > 0 && smagic64ok(c) && smagic64m(c) < 0) {
+			break
+		}
+		v.reset(OpSub64)
+		v.Type = t
+		v0 := b.NewValue0(v.Line, OpRsh64x64, t)
+		v1 := b.NewValue0(v.Line, OpAdd64, t)
+		v2 := b.NewValue0(v.Line, OpHmul64, t)
+		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3.AuxInt = smagic64m(c)
+		v2.AddArg(v3)
+		v2.AddArg(x)
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v0.AddArg(v1)
+		v4 := b.NewValue0(v.Line, OpConst64, t)
+		v4.AuxInt = smagic64s(c)
+		v0.AddArg(v4)
+		v.AddArg(v0)
+		v5 := b.NewValue0(v.Line, OpRsh64x64, t)
+		v5.AddArg(x)
+		v6 := b.NewValue0(v.Line, OpConst64, t)
+		v6.AuxInt = 63
+		v5.AddArg(v6)
+		v.AddArg(v5)
+		return true
+	}
+	// match: (Div64 <t> x (Const64 [c]))
+	// cond: c < 0 && smagic64ok(c) && smagic64m(c) > 0
+	// result: (Neg64 <t>     (Sub64 <t>       (Rsh64x64 <t>         (Hmul64 <t>           (Const64 <t> [smagic64m(c)])           x)         (Const64 <t> [smagic64s(c)]))       (Rsh64x64 <t>         x         (Const64 <t> [63]))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && smagic64ok(c) && smagic64m(c) > 0) {
+			break
+		}
+		v.reset(OpNeg64)
+		v.Type = t
+		v0 := b.NewValue0(v.Line, OpSub64, t)
+		v1 := b.NewValue0(v.Line, OpRsh64x64, t)
+		v2 := b.NewValue0(v.Line, OpHmul64, t)
+		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3.AuxInt = smagic64m(c)
+		v2.AddArg(v3)
+		v2.AddArg(x)
+		v1.AddArg(v2)
+		v4 := b.NewValue0(v.Line, OpConst64, t)
+		v4.AuxInt = smagic64s(c)
+		v1.AddArg(v4)
+		v0.AddArg(v1)
+		v5 := b.NewValue0(v.Line, OpRsh64x64, t)
+		v5.AddArg(x)
+		v6 := b.NewValue0(v.Line, OpConst64, t)
+		v6.AuxInt = 63
+		v5.AddArg(v6)
+		v0.AddArg(v5)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div64 <t> x (Const64 [c]))
+	// cond: c < 0 && smagic64ok(c) && smagic64m(c) < 0
+	// result: (Neg64 <t>     (Sub64 <t>       (Rsh64x64 <t>         (Add64 <t>           (Hmul64 <t>             (Const64 <t> [smagic64m(c)])             x)           x)         (Const64 <t> [smagic64s(c)]))       (Rsh64x64 <t>         x         (Const64 <t> [63]))))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(c < 0 && smagic64ok(c) && smagic64m(c) < 0) {
+			break
+		}
+		v.reset(OpNeg64)
+		v.Type = t
+		v0 := b.NewValue0(v.Line, OpSub64, t)
+		v1 := b.NewValue0(v.Line, OpRsh64x64, t)
+		v2 := b.NewValue0(v.Line, OpAdd64, t)
+		v3 := b.NewValue0(v.Line, OpHmul64, t)
+		v4 := b.NewValue0(v.Line, OpConst64, t)
+		v4.AuxInt = smagic64m(c)
+		v3.AddArg(v4)
+		v3.AddArg(x)
+		v2.AddArg(v3)
+		v2.AddArg(x)
+		v1.AddArg(v2)
+		v5 := b.NewValue0(v.Line, OpConst64, t)
+		v5.AuxInt = smagic64s(c)
+		v1.AddArg(v5)
+		v0.AddArg(v1)
+		v6 := b.NewValue0(v.Line, OpRsh64x64, t)
+		v6.AddArg(x)
+		v7 := b.NewValue0(v.Line, OpConst64, t)
+		v7.AuxInt = 63
+		v6.AddArg(v7)
+		v0.AddArg(v6)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpDiv64u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Div64u <t> n (Const64 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (Rsh64Ux64 n (Const64 <t> [log2(c)]))
+	for {
+		t := v.Type
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = log2(c)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Div64u <t> x (Const64 [c]))
+	// cond: umagic64ok(c) && !umagic64a(c)
+	// result: (Rsh64Ux64     (Hmul64u <t>       (Const64 <t> [umagic64m(c)])       x)     (Const64 <t> [umagic64s(c)]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagic64ok(c) && !umagic64a(c)) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v0 := b.NewValue0(v.Line, OpHmul64u, t)
+		v1 := b.NewValue0(v.Line, OpConst64, t)
+		v1.AuxInt = umagic64m(c)
+		v0.AddArg(v1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2.AuxInt = umagic64s(c)
+		v.AddArg(v2)
+		return true
+	}
+	// match: (Div64u <t> x (Const64 [c]))
+	// cond: umagic64ok(c) && umagic64a(c)
+	// result: (Rsh64Ux64     (Avg64u <t>       (Hmul64u <t>         x         (Const64 <t> [umagic64m(c)]))       x)     (Const64 <t> [umagic64s(c)-1]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(umagic64ok(c) && umagic64a(c)) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v0 := b.NewValue0(v.Line, OpAvg64u, t)
+		v1 := b.NewValue0(v.Line, OpHmul64u, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2.AuxInt = umagic64m(c)
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3.AuxInt = umagic64s(c) - 1
+		v.AddArg(v3)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEq16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq16 x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (Eq16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x))
+	// cond:
+	// result: (Eq16 (Const16 <t> [int64(int16(c-d))]) x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd16 {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst16 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpEq16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq16 x (Const16 <t> [c]))
+	// cond: x.Op != OpConst16
+	// result: (Eq16 (Const16 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpEq16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEq32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq32 x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (Eq32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x))
+	// cond:
+	// result: (Eq32 (Const32 <t> [int64(int32(c-d))]) x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd32 {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst32 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpEq32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq32 x (Const32 <t> [c]))
+	// cond: x.Op != OpConst32
+	// result: (Eq32 (Const32 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpEq32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEq64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq64 x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (Eq64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x))
+	// cond:
+	// result: (Eq64 (Const64 <t> [c-d]) x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd64 {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst64 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpEq64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq64 x (Const64 <t> [c]))
+	// cond: x.Op != OpConst64
+	// result: (Eq64 (Const64 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpEq64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEq8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Eq8  x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (Eq8  (Const8  <t> [c]) (Add8  (Const8  <t> [d]) x))
+	// cond:
+	// result: (Eq8  (Const8 <t> [int64(int8(c-d))]) x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd8 {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst8 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpEq8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq8  x (Const8  <t> [c]))
+	// cond: x.Op != OpConst8
+	// result: (Eq8  (Const8  <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpEq8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Eq8  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEqB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (EqB (ConstBool [c]) (ConstBool [d]))
+	// cond:
+	// result: (ConstBool [b2i(c == d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstBool {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstBool {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c == d)
+		return true
+	}
+	// match: (EqB (ConstBool [0]) x)
+	// cond:
+	// result: (Not x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstBool {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpNot)
+		v.AddArg(x)
+		return true
+	}
+	// match: (EqB (ConstBool [1]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstBool {
+			break
+		}
+		if v_0.AuxInt != 1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEqInter(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (EqInter x y)
+	// cond:
+	// result: (EqPtr  (ITab x) (ITab y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpEqPtr)
+		v0 := b.NewValue0(v.Line, OpITab, config.fe.TypeBytePtr())
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpITab, config.fe.TypeBytePtr())
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpEqPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (EqPtr p (ConstNil))
+	// cond:
+	// result: (Not (IsNonNil p))
+	for {
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstNil {
+			break
+		}
+		v.reset(OpNot)
+		v0 := b.NewValue0(v.Line, OpIsNonNil, config.fe.TypeBool())
+		v0.AddArg(p)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (EqPtr (ConstNil) p)
+	// cond:
+	// result: (Not (IsNonNil p))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstNil {
+			break
+		}
+		p := v.Args[1]
+		v.reset(OpNot)
+		v0 := b.NewValue0(v.Line, OpIsNonNil, config.fe.TypeBool())
+		v0.AddArg(p)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpEqSlice(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (EqSlice x y)
+	// cond:
+	// result: (EqPtr  (SlicePtr x) (SlicePtr y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpEqPtr)
+		v0 := b.NewValue0(v.Line, OpSlicePtr, config.fe.TypeBytePtr())
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpSlicePtr, config.fe.TypeBytePtr())
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpGeq16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c >= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c >= d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGeq16U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq16U (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint16(c) >= uint16(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint16(c) >= uint16(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGeq32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c >= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c >= d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGeq32U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq32U (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint32(c) >= uint32(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint32(c) >= uint32(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGeq64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c >= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c >= d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGeq64U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq64U (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint64(c) >= uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint64(c) >= uint64(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGeq8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq8  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(c >= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c >= d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGeq8U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Geq8U  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint8(c)  >= uint8(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint8(c) >= uint8(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGreater16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c > d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c > d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGreater16U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater16U (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint16(c) > uint16(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint16(c) > uint16(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGreater32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c > d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c > d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGreater32U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater32U (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint32(c) > uint32(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint32(c) > uint32(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGreater64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c > d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c > d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGreater64U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater64U (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint64(c) > uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint64(c) > uint64(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGreater8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater8  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(c > d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c > d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpGreater8U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Greater8U  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint8(c)  > uint8(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint8(c) > uint8(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpIsInBounds(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (IsInBounds (ZeroExt8to32  _) (Const32 [c]))
+	// cond: (1 << 8)  <= c
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to32 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !((1 << 8) <= c) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (ZeroExt8to64  _) (Const64 [c]))
+	// cond: (1 << 8)  <= c
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt8to64 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !((1 << 8) <= c) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (ZeroExt16to32 _) (Const32 [c]))
+	// cond: (1 << 16) <= c
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt16to32 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		if !((1 << 16) <= c) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (ZeroExt16to64 _) (Const64 [c]))
+	// cond: (1 << 16) <= c
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpZeroExt16to64 {
+			break
+		}
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !((1 << 16) <= c) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds x x)
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (IsInBounds (And32 (Const32 [c]) _) (Const32 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		c := v_0_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c < d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (And64 (Const64 [c]) _) (Const64 [d]))
+	// cond: 0 <= c && c < d
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		c := v_0_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c < d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(0 <= c && c < d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(0 <= c && c < d)
+		return true
+	}
+	// match: (IsInBounds (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(0 <= c && c < d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(0 <= c && c < d)
+		return true
+	}
+	// match: (IsInBounds (Mod32u _ y) y)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMod32u {
+			break
+		}
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsInBounds (Mod64u _ y) y)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpMod64u {
+			break
+		}
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpIsSliceInBounds(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (IsSliceInBounds x x)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsSliceInBounds (And32 (Const32 [c]) _) (Const32 [d]))
+	// cond: 0 <= c && c <= d
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		c := v_0_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c <= d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsSliceInBounds (And64 (Const64 [c]) _) (Const64 [d]))
+	// cond: 0 <= c && c <= d
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		c := v_0_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(0 <= c && c <= d) {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsSliceInBounds (Const32 [0]) _)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsSliceInBounds (Const64 [0]) _)
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	// match: (IsSliceInBounds (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(0 <= c && c <= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(0 <= c && c <= d)
+		return true
+	}
+	// match: (IsSliceInBounds (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(0 <= c && c <= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(0 <= c && c <= d)
+		return true
+	}
+	// match: (IsSliceInBounds (SliceLen x) (SliceCap x))
+	// cond:
+	// result: (ConstBool [1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceLen {
+			break
+		}
+		x := v_0.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpSliceCap {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 1
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLeq16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c <= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c <= d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLeq16U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq16U (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint16(c) <= uint16(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint16(c) <= uint16(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLeq32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c <= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c <= d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLeq32U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq32U (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint32(c) <= uint32(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint32(c) <= uint32(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLeq64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c <= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c <= d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLeq64U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq64U (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint64(c) <= uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint64(c) <= uint64(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLeq8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq8  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(c <= d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c <= d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLeq8U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Leq8U  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint8(c)  <= uint8(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint8(c) <= uint8(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLess16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c < d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c < d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLess16U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less16U (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint16(c) < uint16(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint16(c) < uint16(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLess32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c < d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c < d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLess32U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less32U (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint32(c) < uint32(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint32(c) < uint32(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLess64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c < d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c < d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLess64U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less64U (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint64(c) < uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint64(c) < uint64(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLess8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less8  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(c < d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c < d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLess8U(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Less8U  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(uint8(c)  < uint8(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(uint8(c) < uint8(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLoad(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Load <t1> p1 (Store [w] p2 x _))
+	// cond: isSamePtr(p1,p2) && t1.Compare(x.Type)==CMPeq && w == t1.Size()
+	// result: x
+	for {
+		t1 := v.Type
+		p1 := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStore {
+			break
+		}
+		w := v_1.AuxInt
+		p2 := v_1.Args[0]
+		x := v_1.Args[1]
+		if !(isSamePtr(p1, p2) && t1.Compare(x.Type) == CMPeq && w == t1.Size()) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Load <t> _ _)
+	// cond: t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t)
+	// result: (StructMake0)
+	for {
+		t := v.Type
+		if !(t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake0)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t)
+	// result: (StructMake1     (Load <t.FieldType(0)> ptr mem))
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake1)
+		v0 := b.NewValue0(v.Line, OpLoad, t.FieldType(0))
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t)
+	// result: (StructMake2     (Load <t.FieldType(0)> ptr mem)     (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem))
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake2)
+		v0 := b.NewValue0(v.Line, OpLoad, t.FieldType(0))
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpLoad, t.FieldType(1))
+		v2 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(1).PtrTo())
+		v2.AuxInt = t.FieldOff(1)
+		v2.AddArg(ptr)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t)
+	// result: (StructMake3     (Load <t.FieldType(0)> ptr mem)     (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)     (Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem))
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake3)
+		v0 := b.NewValue0(v.Line, OpLoad, t.FieldType(0))
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpLoad, t.FieldType(1))
+		v2 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(1).PtrTo())
+		v2.AuxInt = t.FieldOff(1)
+		v2.AddArg(ptr)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		v3 := b.NewValue0(v.Line, OpLoad, t.FieldType(2))
+		v4 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(2).PtrTo())
+		v4.AuxInt = t.FieldOff(2)
+		v4.AddArg(ptr)
+		v3.AddArg(v4)
+		v3.AddArg(mem)
+		v.AddArg(v3)
+		return true
+	}
+	// match: (Load <t> ptr mem)
+	// cond: t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t)
+	// result: (StructMake4     (Load <t.FieldType(0)> ptr mem)     (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)     (Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem)     (Load <t.FieldType(3)> (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] ptr) mem))
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		mem := v.Args[1]
+		if !(t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpStructMake4)
+		v0 := b.NewValue0(v.Line, OpLoad, t.FieldType(0))
+		v0.AddArg(ptr)
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpLoad, t.FieldType(1))
+		v2 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(1).PtrTo())
+		v2.AuxInt = t.FieldOff(1)
+		v2.AddArg(ptr)
+		v1.AddArg(v2)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		v3 := b.NewValue0(v.Line, OpLoad, t.FieldType(2))
+		v4 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(2).PtrTo())
+		v4.AuxInt = t.FieldOff(2)
+		v4.AddArg(ptr)
+		v3.AddArg(v4)
+		v3.AddArg(mem)
+		v.AddArg(v3)
+		v5 := b.NewValue0(v.Line, OpLoad, t.FieldType(3))
+		v6 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(3).PtrTo())
+		v6.AuxInt = t.FieldOff(3)
+		v6.AddArg(ptr)
+		v5.AddArg(v6)
+		v5.AddArg(mem)
+		v.AddArg(v5)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh16x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x16  <t> x (Const16 [c]))
+	// cond:
+	// result: (Lsh16x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh16x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh16x16  (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh16x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x32  <t> x (Const32 [c]))
+	// cond:
+	// result: (Lsh16x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh16x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh16x32  (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh16x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x64  (Const16 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(c) << uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c) << uint64(d))
+		return true
+	}
+	// match: (Lsh16x64  x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Lsh16x64  (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Lsh16x64  _ (Const64 [c]))
+	// cond: uint64(c) >= 16
+	// result: (Const16 [0])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(uint64(c) >= 16) {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Lsh16x64 <t> (Lsh16x64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Lsh16x64 x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh16x64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpLsh16x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh16x64 (Rsh16Ux64 (Lsh16x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+	// cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+	// result: (Lsh16x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh16Ux64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLsh16x64 {
+			break
+		}
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst64 {
+			break
+		}
+		c1 := v_0_0_1.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+			break
+		}
+		v.reset(OpLsh16x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh16x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh16x8   <t> x (Const8  [c]))
+	// cond:
+	// result: (Lsh16x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh16x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh16x8  (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh32x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x16  <t> x (Const16 [c]))
+	// cond:
+	// result: (Lsh32x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh32x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh32x16  (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh32x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x32  <t> x (Const32 [c]))
+	// cond:
+	// result: (Lsh32x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh32x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh32x32  (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh32x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x64  (Const32 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(c) << uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c) << uint64(d))
+		return true
+	}
+	// match: (Lsh32x64  x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Lsh32x64  (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Lsh32x64  _ (Const64 [c]))
+	// cond: uint64(c) >= 32
+	// result: (Const32 [0])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(uint64(c) >= 32) {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Lsh32x64 <t> (Lsh32x64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Lsh32x64 x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh32x64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpLsh32x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh32x64 (Rsh32Ux64 (Lsh32x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+	// cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+	// result: (Lsh32x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh32Ux64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLsh32x64 {
+			break
+		}
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst64 {
+			break
+		}
+		c1 := v_0_0_1.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+			break
+		}
+		v.reset(OpLsh32x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh32x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh32x8   <t> x (Const8  [c]))
+	// cond:
+	// result: (Lsh32x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh32x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh32x8  (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh64x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x16  <t> x (Const16 [c]))
+	// cond:
+	// result: (Lsh64x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh64x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh64x16  (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh64x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x32  <t> x (Const32 [c]))
+	// cond:
+	// result: (Lsh64x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh64x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh64x32  (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh64x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x64  (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [c << uint64(d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c << uint64(d)
+		return true
+	}
+	// match: (Lsh64x64  x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Lsh64x64  (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Lsh64x64  _ (Const64 [c]))
+	// cond: uint64(c) >= 64
+	// result: (Const64 [0])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(uint64(c) >= 64) {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Lsh64x64 <t> (Lsh64x64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Lsh64x64 x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh64x64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpLsh64x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh64x64 (Rsh64Ux64 (Lsh64x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+	// cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+	// result: (Lsh64x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh64Ux64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLsh64x64 {
+			break
+		}
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst64 {
+			break
+		}
+		c1 := v_0_0_1.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+			break
+		}
+		v.reset(OpLsh64x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh64x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh64x8   <t> x (Const8  [c]))
+	// cond:
+	// result: (Lsh64x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh64x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh64x8  (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh8x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x16  <t> x (Const16 [c]))
+	// cond:
+	// result: (Lsh8x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh8x16   (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh8x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x32  <t> x (Const32 [c]))
+	// cond:
+	// result: (Lsh8x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh8x32   (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh8x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x64   (Const8  [c]) (Const64 [d]))
+	// cond:
+	// result: (Const8  [int64(int8(c) << uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c) << uint64(d))
+		return true
+	}
+	// match: (Lsh8x64   x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Lsh8x64   (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Lsh8x64   _ (Const64 [c]))
+	// cond: uint64(c) >= 8
+	// result: (Const8  [0])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(uint64(c) >= 8) {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Lsh8x64  <t> (Lsh8x64  x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Lsh8x64  x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh8x64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpLsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh8x64 (Rsh8Ux64 (Lsh8x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+	// cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+	// result: (Lsh8x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh8Ux64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpLsh8x64 {
+			break
+		}
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst64 {
+			break
+		}
+		c1 := v_0_0_1.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+			break
+		}
+		v.reset(OpLsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpLsh8x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Lsh8x8   <t> x (Const8  [c]))
+	// cond:
+	// result: (Lsh8x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpLsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Lsh8x8   (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod16 (Const16 [c]) (Const16 [d]))
+	// cond: d != 0
+	// result: (Const16 [int64(int16(c % d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(d != 0) {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c % d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod16u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod16u (Const16 [c]) (Const16 [d]))
+	// cond: d != 0
+	// result: (Const16 [int64(uint16(c) % uint16(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(d != 0) {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = int64(uint16(c) % uint16(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod32 (Const32 [c]) (Const32 [d]))
+	// cond: d != 0
+	// result: (Const32 [int64(int32(c % d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(d != 0) {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c % d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod32u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod32u (Const32 [c]) (Const32 [d]))
+	// cond: d != 0
+	// result: (Const32 [int64(uint32(c) % uint32(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(d != 0) {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = int64(uint32(c) % uint32(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod64 (Const64 [c]) (Const64 [d]))
+	// cond: d != 0
+	// result: (Const64 [c % d])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(d != 0) {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = c % d
+		return true
+	}
+	// match: (Mod64  <t> x (Const64 [c]))
+	// cond: x.Op != OpConst64 && smagic64ok(c)
+	// result: (Sub64 x (Mul64 <t> (Div64  <t> x (Const64 <t> [c])) (Const64 <t> [c])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64 && smagic64ok(c)) {
+			break
+		}
+		v.reset(OpSub64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpMul64, t)
+		v1 := b.NewValue0(v.Line, OpDiv64, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod64u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod64u (Const64 [c]) (Const64 [d]))
+	// cond: d != 0
+	// result: (Const64 [int64(uint64(c) % uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(d != 0) {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = int64(uint64(c) % uint64(d))
+		return true
+	}
+	// match: (Mod64u <t> n (Const64 [c]))
+	// cond: isPowerOfTwo(c)
+	// result: (And64 n (Const64 <t> [c-1]))
+	for {
+		t := v.Type
+		n := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(isPowerOfTwo(c)) {
+			break
+		}
+		v.reset(OpAnd64)
+		v.AddArg(n)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c - 1
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Mod64u <t> x (Const64 [c]))
+	// cond: x.Op != OpConst64 && umagic64ok(c)
+	// result: (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64 && umagic64ok(c)) {
+			break
+		}
+		v.reset(OpSub64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpMul64, t)
+		v1 := b.NewValue0(v.Line, OpDiv64u, t)
+		v1.AddArg(x)
+		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v0.AddArg(v1)
+		v3 := b.NewValue0(v.Line, OpConst64, t)
+		v3.AuxInt = c
+		v0.AddArg(v3)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod8  (Const8  [c]) (Const8  [d]))
+	// cond: d != 0
+	// result: (Const8  [int64(int8(c % d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(d != 0) {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c % d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMod8u(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mod8u  (Const8 [c])  (Const8  [d]))
+	// cond: d != 0
+	// result: (Const8  [int64(uint8(c) % uint8(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(d != 0) {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = int64(uint8(c) % uint8(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul16  (Const16 [c])  (Const16 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(c*d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c * d))
+		return true
+	}
+	// match: (Mul16 x (Const16 <t> [c]))
+	// cond: x.Op != OpConst16
+	// result: (Mul16 (Const16 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpMul16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul16 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul32  (Const32 [c])  (Const32 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(c*d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c * d))
+		return true
+	}
+	// match: (Mul32 x (Const32 <t> [c]))
+	// cond: x.Op != OpConst32
+	// result: (Mul32 (Const32 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpMul32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul32 (Const32 <t> [c]) (Add32 <t> (Const32 <t> [d]) x))
+	// cond:
+	// result: (Add32 (Const32 <t> [int64(int32(c*d))]) (Mul32 <t> (Const32 <t> [c]) x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd32 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst32 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = int64(int32(c * d))
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpMul32, t)
+		v2 := b.NewValue0(v.Line, OpConst32, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Mul32 (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul32F (Const32F [c]) (Const32F [d]))
+	// cond:
+	// result: (Const32F [f2i(float64(i2f32(c) * i2f32(d)))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst32F)
+		v.AuxInt = f2i(float64(i2f32(c) * i2f32(d)))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul64  (Const64 [c])  (Const64 [d]))
+	// cond:
+	// result: (Const64 [c*d])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c * d
+		return true
+	}
+	// match: (Mul64 x (Const64 <t> [c]))
+	// cond: x.Op != OpConst64
+	// result: (Mul64 (Const64 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpMul64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul64 (Const64 <t> [c]) (Add64 <t> (Const64 <t> [d]) x))
+	// cond:
+	// result: (Add64 (Const64 <t> [c*d]) (Mul64 <t> (Const64 <t> [c]) x))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd64 {
+			break
+		}
+		if v_1.Type != t {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst64 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c * d
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpMul64, t)
+		v2 := b.NewValue0(v.Line, OpConst64, t)
+		v2.AuxInt = c
+		v1.AddArg(v2)
+		v1.AddArg(x)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Mul64 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul64F (Const64F [c]) (Const64F [d]))
+	// cond:
+	// result: (Const64F [f2i(i2f(c) * i2f(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64F {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst64F)
+		v.AuxInt = f2i(i2f(c) * i2f(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpMul8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Mul8   (Const8 [c])   (Const8 [d]))
+	// cond:
+	// result: (Const8  [int64(int8(c*d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c * d))
+		return true
+	}
+	// match: (Mul8  x (Const8  <t> [c]))
+	// cond: x.Op != OpConst8
+	// result: (Mul8  (Const8  <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpMul8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Mul8  (Const8  [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeg16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg16 (Sub16 x y))
+	// cond:
+	// result: (Sub16 y x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub16 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpSub16)
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeg32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg32 (Sub32 x y))
+	// cond:
+	// result: (Sub32 y x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub32 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpSub32)
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeg64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg64 (Sub64 x y))
+	// cond:
+	// result: (Sub64 y x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub64 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpSub64)
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeg8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neg8  (Sub8  x y))
+	// cond:
+	// result: (Sub8  y x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSub8 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		v.reset(OpSub8)
+		v.AddArg(y)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeq16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq16 x x)
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Neq16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x))
+	// cond:
+	// result: (Neq16 (Const16 <t> [int64(int16(c-d))]) x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd16 {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst16 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpNeq16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = int64(int16(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq16 x (Const16 <t> [c]))
+	// cond: x.Op != OpConst16
+	// result: (Neq16 (Const16 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpNeq16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq16 (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeq32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq32 x x)
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Neq32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x))
+	// cond:
+	// result: (Neq32 (Const32 <t> [int64(int32(c-d))]) x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd32 {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst32 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpNeq32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = int64(int32(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq32 x (Const32 <t> [c]))
+	// cond: x.Op != OpConst32
+	// result: (Neq32 (Const32 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpNeq32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq32 (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeq64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq64 x x)
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Neq64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x))
+	// cond:
+	// result: (Neq64 (Const64 <t> [c-d]) x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd64 {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst64 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpNeq64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c - d
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq64 x (Const64 <t> [c]))
+	// cond: x.Op != OpConst64
+	// result: (Neq64 (Const64 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpNeq64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeq8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Neq8  x x)
+	// cond:
+	// result: (ConstBool [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConstBool)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Neq8  (Const8  <t> [c]) (Add8  (Const8  <t> [d]) x))
+	// cond:
+	// result: (Neq8 (Const8 <t> [int64(int8(c-d))]) x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		t := v_0.Type
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpAdd8 {
+			break
+		}
+		v_1_0 := v_1.Args[0]
+		if v_1_0.Op != OpConst8 {
+			break
+		}
+		if v_1_0.Type != t {
+			break
+		}
+		d := v_1_0.AuxInt
+		x := v_1.Args[1]
+		v.reset(OpNeq8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = int64(int8(c - d))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq8  x (Const8 <t>  [c]))
+	// cond: x.Op != OpConst8
+	// result: (Neq8  (Const8  <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpNeq8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Neq8  (Const8  [c]) (Const8  [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeqB(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NeqB (ConstBool [c]) (ConstBool [d]))
+	// cond:
+	// result: (ConstBool [b2i(c != d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstBool {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstBool {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConstBool)
+		v.AuxInt = b2i(c != d)
+		return true
+	}
+	// match: (NeqB (ConstBool [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstBool {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (NeqB (ConstBool [1]) x)
+	// cond:
+	// result: (Not x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstBool {
+			break
+		}
+		if v_0.AuxInt != 1 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpNot)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeqInter(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NeqInter x y)
+	// cond:
+	// result: (NeqPtr (ITab x) (ITab y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpNeqPtr)
+		v0 := b.NewValue0(v.Line, OpITab, config.fe.TypeBytePtr())
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpITab, config.fe.TypeBytePtr())
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpNeqPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NeqPtr p (ConstNil))
+	// cond:
+	// result: (IsNonNil p)
+	for {
+		p := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConstNil {
+			break
+		}
+		v.reset(OpIsNonNil)
+		v.AddArg(p)
+		return true
+	}
+	// match: (NeqPtr (ConstNil) p)
+	// cond:
+	// result: (IsNonNil p)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConstNil {
+			break
+		}
+		p := v.Args[1]
+		v.reset(OpIsNonNil)
+		v.AddArg(p)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpNeqSlice(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (NeqSlice x y)
+	// cond:
+	// result: (NeqPtr (SlicePtr x) (SlicePtr y))
+	for {
+		x := v.Args[0]
+		y := v.Args[1]
+		v.reset(OpNeqPtr)
+		v0 := b.NewValue0(v.Line, OpSlicePtr, config.fe.TypeBytePtr())
+		v0.AddArg(x)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpSlicePtr, config.fe.TypeBytePtr())
+		v1.AddArg(y)
+		v.AddArg(v1)
+		return true
+	}
+}
+func rewriteValuegeneric_OpOffPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (OffPtr (OffPtr p [b]) [a])
+	// cond:
+	// result: (OffPtr p [a+b])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpOffPtr {
+			break
+		}
+		p := v_0.Args[0]
+		b := v_0.AuxInt
+		a := v.AuxInt
+		v.reset(OpOffPtr)
+		v.AddArg(p)
+		v.AuxInt = a + b
+		return true
+	}
+	// match: (OffPtr p [0])
+	// cond: v.Type.Compare(p.Type) == CMPeq
+	// result: p
+	for {
+		p := v.Args[0]
+		if v.AuxInt != 0 {
+			break
+		}
+		if !(v.Type.Compare(p.Type) == CMPeq) {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = p.Type
+		v.AddArg(p)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpOr16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Or16 x (Const16 <t> [c]))
+	// cond: x.Op != OpConst16
+	// result: (Or16 (Const16 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpOr16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 (Const16 [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or16 (Const16 [-1]) _)
+	// cond:
+	// result: (Const16 [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (Or16 x (Or16 x y))
+	// cond:
+	// result: (Or16 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr16 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpOr16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or16 x (Or16 y x))
+	// cond:
+	// result: (Or16 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr16 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpOr16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or16 (Or16 x y) x)
+	// cond:
+	// result: (Or16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr16 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpOr16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or16 (Or16 x y) y)
+	// cond:
+	// result: (Or16 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr16 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpOr16)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpOr32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Or32 x (Const32 <t> [c]))
+	// cond: x.Op != OpConst32
+	// result: (Or32 (Const32 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpOr32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or32 x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or32 (Const32 [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or32 (Const32 [-1]) _)
+	// cond:
+	// result: (Const32 [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (Or32 x (Or32 x y))
+	// cond:
+	// result: (Or32 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr32 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpOr32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or32 x (Or32 y x))
+	// cond:
+	// result: (Or32 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr32 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpOr32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or32 (Or32 x y) x)
+	// cond:
+	// result: (Or32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr32 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpOr32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or32 (Or32 x y) y)
+	// cond:
+	// result: (Or32 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr32 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpOr32)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpOr64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Or64 x (Const64 <t> [c]))
+	// cond: x.Op != OpConst64
+	// result: (Or64 (Const64 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpOr64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or64 x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or64 (Const64 [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or64 (Const64 [-1]) _)
+	// cond:
+	// result: (Const64 [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (Or64 x (Or64 x y))
+	// cond:
+	// result: (Or64 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr64 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpOr64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or64 x (Or64 y x))
+	// cond:
+	// result: (Or64 x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr64 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpOr64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or64 (Or64 x y) x)
+	// cond:
+	// result: (Or64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr64 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpOr64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or64 (Or64 x y) y)
+	// cond:
+	// result: (Or64 x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr64 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpOr64)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpOr8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Or8  x (Const8  <t> [c]))
+	// cond: x.Op != OpConst8
+	// result: (Or8  (Const8  <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpOr8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or8  x x)
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or8  (Const8  [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Or8  (Const8  [-1]) _)
+	// cond:
+	// result: (Const8  [-1])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != -1 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = -1
+		return true
+	}
+	// match: (Or8  x (Or8  x y))
+	// cond:
+	// result: (Or8  x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr8 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpOr8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or8  x (Or8  y x))
+	// cond:
+	// result: (Or8  x y)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpOr8 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpOr8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or8  (Or8  x y) x)
+	// cond:
+	// result: (Or8  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr8 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpOr8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	// match: (Or8  (Or8  x y) y)
+	// cond:
+	// result: (Or8  x y)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpOr8 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpOr8)
+		v.AddArg(x)
+		v.AddArg(y)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpPhi(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Phi (Const8  [c]) (Const8  [c]))
+	// cond:
+	// result: (Const8  [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		if v_1.AuxInt != c {
+			break
+		}
+		if len(v.Args) != 2 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = c
+		return true
+	}
+	// match: (Phi (Const16 [c]) (Const16 [c]))
+	// cond:
+	// result: (Const16 [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		if v_1.AuxInt != c {
+			break
+		}
+		if len(v.Args) != 2 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = c
+		return true
+	}
+	// match: (Phi (Const32 [c]) (Const32 [c]))
+	// cond:
+	// result: (Const32 [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		if v_1.AuxInt != c {
+			break
+		}
+		if len(v.Args) != 2 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = c
+		return true
+	}
+	// match: (Phi (Const64 [c]) (Const64 [c]))
+	// cond:
+	// result: (Const64 [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != c {
+			break
+		}
+		if len(v.Args) != 2 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = c
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpPtrIndex(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (PtrIndex <t> ptr idx)
+	// cond: config.PtrSize == 4
+	// result: (AddPtr ptr (Mul32 <config.fe.TypeInt()> idx (Const32 <config.fe.TypeInt()> [t.ElemType().Size()])))
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		idx := v.Args[1]
+		if !(config.PtrSize == 4) {
+			break
+		}
+		v.reset(OpAddPtr)
+		v.AddArg(ptr)
+		v0 := b.NewValue0(v.Line, OpMul32, config.fe.TypeInt())
+		v0.AddArg(idx)
+		v1 := b.NewValue0(v.Line, OpConst32, config.fe.TypeInt())
+		v1.AuxInt = t.ElemType().Size()
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	// match: (PtrIndex <t> ptr idx)
+	// cond: config.PtrSize == 8
+	// result: (AddPtr ptr (Mul64 <config.fe.TypeInt()> idx (Const64 <config.fe.TypeInt()> [t.ElemType().Size()])))
+	for {
+		t := v.Type
+		ptr := v.Args[0]
+		idx := v.Args[1]
+		if !(config.PtrSize == 8) {
+			break
+		}
+		v.reset(OpAddPtr)
+		v.AddArg(ptr)
+		v0 := b.NewValue0(v.Line, OpMul64, config.fe.TypeInt())
+		v0.AddArg(idx)
+		v1 := b.NewValue0(v.Line, OpConst64, config.fe.TypeInt())
+		v1.AuxInt = t.ElemType().Size()
+		v0.AddArg(v1)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh16Ux16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux16 <t> x (Const16 [c]))
+	// cond:
+	// result: (Rsh16Ux64 x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh16Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh16Ux16 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh16Ux32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux32 <t> x (Const32 [c]))
+	// cond:
+	// result: (Rsh16Ux64 x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh16Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh16Ux32 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh16Ux64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux64 (Const16 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(uint16(c) >> uint64(d)))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(uint16(c) >> uint64(d)))
+		return true
+	}
+	// match: (Rsh16Ux64 x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Rsh16Ux64 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh16Ux64 _ (Const64 [c]))
+	// cond: uint64(c) >= 16
+	// result: (Const16 [0])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(uint64(c) >= 16) {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh16Ux64 <t> (Rsh16Ux64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Rsh16Ux64 x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh16Ux64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpRsh16Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+	// cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+	// result: (Rsh16Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh16x64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpRsh16Ux64 {
+			break
+		}
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst64 {
+			break
+		}
+		c1 := v_0_0_1.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+			break
+		}
+		v.reset(OpRsh16Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh16Ux8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16Ux8  <t> x (Const8  [c]))
+	// cond:
+	// result: (Rsh16Ux64 x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh16Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh16Ux8 (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh16x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x16  <t> x (Const16 [c]))
+	// cond:
+	// result: (Rsh16x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh16x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh16x16  (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh16x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x32  <t> x (Const32 [c]))
+	// cond:
+	// result: (Rsh16x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh16x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh16x32  (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh16x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x64  (Const16 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(c) >> uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c) >> uint64(d))
+		return true
+	}
+	// match: (Rsh16x64  x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Rsh16x64  (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh16x64 <t> (Rsh16x64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Rsh16x64 x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh16x64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpRsh16x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh16x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh16x8   <t> x (Const8  [c]))
+	// cond:
+	// result: (Rsh16x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh16x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh16x8  (Const16 [0]) _)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh32Ux16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux16 <t> x (Const16 [c]))
+	// cond:
+	// result: (Rsh32Ux64 x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh32Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh32Ux16 (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh32Ux32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux32 <t> x (Const32 [c]))
+	// cond:
+	// result: (Rsh32Ux64 x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh32Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh32Ux32 (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh32Ux64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux64 (Const32 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(uint32(c) >> uint64(d)))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(uint32(c) >> uint64(d)))
+		return true
+	}
+	// match: (Rsh32Ux64 x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Rsh32Ux64 (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh32Ux64 _ (Const64 [c]))
+	// cond: uint64(c) >= 32
+	// result: (Const32 [0])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(uint64(c) >= 32) {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh32Ux64 <t> (Rsh32Ux64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Rsh32Ux64 x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh32Ux64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpRsh32Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+	// cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+	// result: (Rsh32Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh32x64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpRsh32Ux64 {
+			break
+		}
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst64 {
+			break
+		}
+		c1 := v_0_0_1.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+			break
+		}
+		v.reset(OpRsh32Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh32Ux8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32Ux8  <t> x (Const8  [c]))
+	// cond:
+	// result: (Rsh32Ux64 x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh32Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh32Ux8 (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh32x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x16  <t> x (Const16 [c]))
+	// cond:
+	// result: (Rsh32x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh32x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh32x16  (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh32x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x32  <t> x (Const32 [c]))
+	// cond:
+	// result: (Rsh32x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh32x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh32x32  (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh32x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x64  (Const32 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(c) >> uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c) >> uint64(d))
+		return true
+	}
+	// match: (Rsh32x64  x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Rsh32x64  (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh32x64 <t> (Rsh32x64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Rsh32x64 x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh32x64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpRsh32x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh32x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh32x8   <t> x (Const8  [c]))
+	// cond:
+	// result: (Rsh32x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh32x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh32x8  (Const32 [0]) _)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh64Ux16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux16 <t> x (Const16 [c]))
+	// cond:
+	// result: (Rsh64Ux64 x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh64Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh64Ux16 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh64Ux32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux32 <t> x (Const32 [c]))
+	// cond:
+	// result: (Rsh64Ux64 x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh64Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh64Ux32 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh64Ux64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux64 (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [int64(uint64(c) >> uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = int64(uint64(c) >> uint64(d))
+		return true
+	}
+	// match: (Rsh64Ux64 x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Rsh64Ux64 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh64Ux64 _ (Const64 [c]))
+	// cond: uint64(c) >= 64
+	// result: (Const64 [0])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(uint64(c) >= 64) {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh64Ux64 <t> (Rsh64Ux64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Rsh64Ux64 x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh64Ux64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh64Ux64 (Lsh64x64 (Rsh64Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+	// cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+	// result: (Rsh64Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh64x64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpRsh64Ux64 {
+			break
+		}
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst64 {
+			break
+		}
+		c1 := v_0_0_1.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+			break
+		}
+		v.reset(OpRsh64Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh64Ux8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64Ux8  <t> x (Const8  [c]))
+	// cond:
+	// result: (Rsh64Ux64 x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh64Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh64Ux8 (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh64x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x16  <t> x (Const16 [c]))
+	// cond:
+	// result: (Rsh64x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh64x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh64x16  (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh64x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x32  <t> x (Const32 [c]))
+	// cond:
+	// result: (Rsh64x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh64x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh64x32  (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh64x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x64  (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [c >> uint64(d)])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c >> uint64(d)
+		return true
+	}
+	// match: (Rsh64x64  x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Rsh64x64  (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh64x64 <t> (Rsh64x64 x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Rsh64x64 x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh64x64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpRsh64x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh64x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh64x8   <t> x (Const8  [c]))
+	// cond:
+	// result: (Rsh64x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh64x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh64x8  (Const64 [0]) _)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh8Ux16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8Ux16 <t> x (Const16 [c]))
+	// cond:
+	// result: (Rsh8Ux64 x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh8Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8Ux16  (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh8Ux32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8Ux32 <t> x (Const32 [c]))
+	// cond:
+	// result: (Rsh8Ux64 x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh8Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8Ux32  (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh8Ux64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8Ux64  (Const8  [c]) (Const64 [d]))
+	// cond:
+	// result: (Const8  [int64(int8(uint8(c) >> uint64(d)))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(uint8(c) >> uint64(d)))
+		return true
+	}
+	// match: (Rsh8Ux64  x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Rsh8Ux64  (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh8Ux64  _ (Const64 [c]))
+	// cond: uint64(c) >= 8
+	// result: (Const8  [0])
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c := v_1.AuxInt
+		if !(uint64(c) >= 8) {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh8Ux64  <t> (Rsh8Ux64  x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Rsh8Ux64  x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh8Ux64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpRsh8Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
+	// cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
+	// result: (Rsh8Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpLsh8x64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpRsh8Ux64 {
+			break
+		}
+		x := v_0_0.Args[0]
+		v_0_0_1 := v_0_0.Args[1]
+		if v_0_0_1.Op != OpConst64 {
+			break
+		}
+		c1 := v_0_0_1.AuxInt
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c2 := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		c3 := v_1.AuxInt
+		if !(uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)) {
+			break
+		}
+		v.reset(OpRsh8Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+		v0.AuxInt = c1 - c2 + c3
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh8Ux8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8Ux8  <t> x (Const8  [c]))
+	// cond:
+	// result: (Rsh8Ux64 x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh8Ux64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8Ux8  (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh8x16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x16  <t> x (Const16 [c]))
+	// cond:
+	// result: (Rsh8x64  x (Const64 <t> [int64(uint16(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint16(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8x16   (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh8x32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x32  <t> x (Const32 [c]))
+	// cond:
+	// result: (Rsh8x64  x (Const64 <t> [int64(uint32(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint32(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8x32   (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh8x64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x64   (Const8  [c]) (Const64 [d]))
+	// cond:
+	// result: (Const8  [int64(int8(c) >> uint64(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c) >> uint64(d))
+		return true
+	}
+	// match: (Rsh8x64   x (Const64 [0]))
+	// cond:
+	// result: x
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		if v_1.AuxInt != 0 {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Rsh8x64   (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Rsh8x64  <t> (Rsh8x64  x (Const64 [c])) (Const64 [d]))
+	// cond: !uaddOvf(c,d)
+	// result: (Rsh8x64  x (Const64 <t> [c+d]))
+	for {
+		t := v.Type
+		v_0 := v.Args[0]
+		if v_0.Op != OpRsh8x64 {
+			break
+		}
+		x := v_0.Args[0]
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		c := v_0_1.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		if !(!uaddOvf(c, d)) {
+			break
+		}
+		v.reset(OpRsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c + d
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpRsh8x8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Rsh8x8   <t> x (Const8  [c]))
+	// cond:
+	// result: (Rsh8x64  x (Const64 <t> [int64(uint8(c))]))
+	for {
+		t := v.Type
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		c := v_1.AuxInt
+		v.reset(OpRsh8x64)
+		v.AddArg(x)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = int64(uint8(c))
+		v.AddArg(v0)
+		return true
+	}
+	// match: (Rsh8x8   (Const8 [0]) _)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpSliceCap(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SliceCap (SliceMake _ _ (Const64 <t> [c])))
+	// cond:
+	// result: (Const64 <t> [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
+			break
+		}
+		v_0_2 := v_0.Args[2]
+		if v_0_2.Op != OpConst64 {
+			break
+		}
+		t := v_0_2.Type
+		c := v_0_2.AuxInt
+		v.reset(OpConst64)
+		v.Type = t
+		v.AuxInt = c
+		return true
+	}
+	// match: (SliceCap (SliceMake _ _ (SliceCap x)))
+	// cond:
+	// result: (SliceCap x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
+			break
+		}
+		v_0_2 := v_0.Args[2]
+		if v_0_2.Op != OpSliceCap {
+			break
+		}
+		x := v_0_2.Args[0]
+		v.reset(OpSliceCap)
+		v.AddArg(x)
+		return true
+	}
+	// match: (SliceCap (SliceMake _ _ (SliceLen x)))
+	// cond:
+	// result: (SliceLen x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
+			break
+		}
+		v_0_2 := v_0.Args[2]
+		if v_0_2.Op != OpSliceLen {
+			break
+		}
+		x := v_0_2.Args[0]
+		v.reset(OpSliceLen)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpSliceLen(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SliceLen (SliceMake _ (Const64 <t> [c]) _))
+	// cond:
+	// result: (Const64 <t> [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
+			break
+		}
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		t := v_0_1.Type
+		c := v_0_1.AuxInt
+		v.reset(OpConst64)
+		v.Type = t
+		v.AuxInt = c
+		return true
+	}
+	// match: (SliceLen (SliceMake _ (SliceLen x) _))
+	// cond:
+	// result: (SliceLen x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
+			break
+		}
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpSliceLen {
+			break
+		}
+		x := v_0_1.Args[0]
+		v.reset(OpSliceLen)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpSlicePtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (SlicePtr (SliceMake (SlicePtr x) _ _))
+	// cond:
+	// result: (SlicePtr x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpSliceMake {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpSlicePtr {
+			break
+		}
+		x := v_0_0.Args[0]
+		v.reset(OpSlicePtr)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpStore(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Store _ (StructMake0) mem)
+	// cond:
+	// result: mem
+	for {
+		v_1 := v.Args[1]
+		if v_1.Op != OpStructMake0 {
+			break
+		}
+		mem := v.Args[2]
+		v.reset(OpCopy)
+		v.Type = mem.Type
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store dst (StructMake1 <t> f0) mem)
+	// cond:
+	// result: (Store [t.FieldType(0).Size()] dst f0 mem)
+	for {
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStructMake1 {
+			break
+		}
+		t := v_1.Type
+		f0 := v_1.Args[0]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.AuxInt = t.FieldType(0).Size()
+		v.AddArg(dst)
+		v.AddArg(f0)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store dst (StructMake2 <t> f0 f1) mem)
+	// cond:
+	// result: (Store [t.FieldType(1).Size()]     (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)     f1     (Store [t.FieldType(0).Size()] dst f0 mem))
+	for {
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStructMake2 {
+			break
+		}
+		t := v_1.Type
+		f0 := v_1.Args[0]
+		f1 := v_1.Args[1]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.AuxInt = t.FieldType(1).Size()
+		v0 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(1).PtrTo())
+		v0.AuxInt = t.FieldOff(1)
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(f1)
+		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v1.AuxInt = t.FieldType(0).Size()
+		v1.AddArg(dst)
+		v1.AddArg(f0)
+		v1.AddArg(mem)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Store dst (StructMake3 <t> f0 f1 f2) mem)
+	// cond:
+	// result: (Store [t.FieldType(2).Size()]     (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)     f2     (Store [t.FieldType(1).Size()]       (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)       f1       (Store [t.FieldType(0).Size()] dst f0 mem)))
+	for {
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStructMake3 {
+			break
+		}
+		t := v_1.Type
+		f0 := v_1.Args[0]
+		f1 := v_1.Args[1]
+		f2 := v_1.Args[2]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.AuxInt = t.FieldType(2).Size()
+		v0 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(2).PtrTo())
+		v0.AuxInt = t.FieldOff(2)
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(f2)
+		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v1.AuxInt = t.FieldType(1).Size()
+		v2 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(1).PtrTo())
+		v2.AuxInt = t.FieldOff(1)
+		v2.AddArg(dst)
+		v1.AddArg(v2)
+		v1.AddArg(f1)
+		v3 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v3.AuxInt = t.FieldType(0).Size()
+		v3.AddArg(dst)
+		v3.AddArg(f0)
+		v3.AddArg(mem)
+		v1.AddArg(v3)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Store dst (StructMake4 <t> f0 f1 f2 f3) mem)
+	// cond:
+	// result: (Store [t.FieldType(3).Size()]     (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst)     f3     (Store [t.FieldType(2).Size()]       (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)       f2       (Store [t.FieldType(1).Size()]         (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)         f1         (Store [t.FieldType(0).Size()] dst f0 mem))))
+	for {
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpStructMake4 {
+			break
+		}
+		t := v_1.Type
+		f0 := v_1.Args[0]
+		f1 := v_1.Args[1]
+		f2 := v_1.Args[2]
+		f3 := v_1.Args[3]
+		mem := v.Args[2]
+		v.reset(OpStore)
+		v.AuxInt = t.FieldType(3).Size()
+		v0 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(3).PtrTo())
+		v0.AuxInt = t.FieldOff(3)
+		v0.AddArg(dst)
+		v.AddArg(v0)
+		v.AddArg(f3)
+		v1 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v1.AuxInt = t.FieldType(2).Size()
+		v2 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(2).PtrTo())
+		v2.AuxInt = t.FieldOff(2)
+		v2.AddArg(dst)
+		v1.AddArg(v2)
+		v1.AddArg(f2)
+		v3 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v3.AuxInt = t.FieldType(1).Size()
+		v4 := b.NewValue0(v.Line, OpOffPtr, t.FieldType(1).PtrTo())
+		v4.AuxInt = t.FieldOff(1)
+		v4.AddArg(dst)
+		v3.AddArg(v4)
+		v3.AddArg(f1)
+		v5 := b.NewValue0(v.Line, OpStore, TypeMem)
+		v5.AuxInt = t.FieldType(0).Size()
+		v5.AddArg(dst)
+		v5.AddArg(f0)
+		v5.AddArg(mem)
+		v3.AddArg(v5)
+		v1.AddArg(v3)
+		v.AddArg(v1)
+		return true
+	}
+	// match: (Store [size] dst (Load <t> src mem) mem)
+	// cond: !config.fe.CanSSA(t)
+	// result: (Move [size] dst src mem)
+	for {
+		size := v.AuxInt
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpLoad {
+			break
+		}
+		t := v_1.Type
+		src := v_1.Args[0]
+		mem := v_1.Args[1]
+		if mem != v.Args[2] {
+			break
+		}
+		if !(!config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = size
+		v.AddArg(dst)
+		v.AddArg(src)
+		v.AddArg(mem)
+		return true
+	}
+	// match: (Store [size] dst (Load <t> src mem) (VarDef {x} mem))
+	// cond: !config.fe.CanSSA(t)
+	// result: (Move [size] dst src (VarDef {x} mem))
+	for {
+		size := v.AuxInt
+		dst := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpLoad {
+			break
+		}
+		t := v_1.Type
+		src := v_1.Args[0]
+		mem := v_1.Args[1]
+		v_2 := v.Args[2]
+		if v_2.Op != OpVarDef {
+			break
+		}
+		x := v_2.Aux
+		if mem != v_2.Args[0] {
+			break
+		}
+		if !(!config.fe.CanSSA(t)) {
+			break
+		}
+		v.reset(OpMove)
+		v.AuxInt = size
+		v.AddArg(dst)
+		v.AddArg(src)
+		v0 := b.NewValue0(v.Line, OpVarDef, TypeMem)
+		v0.Aux = x
+		v0.AddArg(mem)
+		v.AddArg(v0)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpStringLen(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (StringLen (StringMake _ (Const64 <t> [c])))
+	// cond:
+	// result: (Const64 <t> [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStringMake {
+			break
+		}
+		v_0_1 := v_0.Args[1]
+		if v_0_1.Op != OpConst64 {
+			break
+		}
+		t := v_0_1.Type
+		c := v_0_1.AuxInt
+		v.reset(OpConst64)
+		v.Type = t
+		v.AuxInt = c
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpStringPtr(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (StringPtr (StringMake (Const64 <t> [c]) _))
+	// cond:
+	// result: (Const64 <t> [c])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStringMake {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		t := v_0_0.Type
+		c := v_0_0.AuxInt
+		v.reset(OpConst64)
+		v.Type = t
+		v.AuxInt = c
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpStructSelect(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (StructSelect (StructMake1 x))
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake1 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [0] (StructMake2 x _))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake2 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [1] (StructMake2 _ x))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake2 {
+			break
+		}
+		x := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [0] (StructMake3 x _ _))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake3 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [1] (StructMake3 _ x _))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake3 {
+			break
+		}
+		x := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [2] (StructMake3 _ _ x))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 2 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake3 {
+			break
+		}
+		x := v_0.Args[2]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [0] (StructMake4 x _ _ _))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 0 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake4 {
+			break
+		}
+		x := v_0.Args[0]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [1] (StructMake4 _ x _ _))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 1 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake4 {
+			break
+		}
+		x := v_0.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [2] (StructMake4 _ _ x _))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 2 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake4 {
+			break
+		}
+		x := v_0.Args[2]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [3] (StructMake4 _ _ _ x))
+	// cond:
+	// result: x
+	for {
+		if v.AuxInt != 3 {
+			break
+		}
+		v_0 := v.Args[0]
+		if v_0.Op != OpStructMake4 {
+			break
+		}
+		x := v_0.Args[3]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (StructSelect [i] x:(Load <t> ptr mem))
+	// cond: !config.fe.CanSSA(t)
+	// result: @x.Block (Load <v.Type> (OffPtr <v.Type.PtrTo()> [t.FieldOff(int(i))] ptr) mem)
+	for {
+		i := v.AuxInt
+		x := v.Args[0]
+		if x.Op != OpLoad {
+			break
+		}
+		t := x.Type
+		ptr := x.Args[0]
+		mem := x.Args[1]
+		if !(!config.fe.CanSSA(t)) {
+			break
+		}
+		b = x.Block
+		v0 := b.NewValue0(v.Line, OpLoad, v.Type)
+		v.reset(OpCopy)
+		v.AddArg(v0)
+		v1 := b.NewValue0(v.Line, OpOffPtr, v.Type.PtrTo())
+		v1.AuxInt = t.FieldOff(int(i))
+		v1.AddArg(ptr)
+		v0.AddArg(v1)
+		v0.AddArg(mem)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpSub16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub16  (Const16 [c]) (Const16 [d]))
+	// cond:
+	// result: (Const16 [int64(int16(c-d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c - d))
+		return true
+	}
+	// match: (Sub16 x (Const16 <t> [c]))
+	// cond: x.Op != OpConst16
+	// result: (Add16 (Const16 <t> [int64(int16(-c))]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpAdd16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = int64(int16(-c))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Sub16 x x)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Sub16 (Add16 x y) x)
+	// cond:
+	// result: y
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd16 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Sub16 (Add16 x y) y)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd16 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpSub32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub32  (Const32 [c]) (Const32 [d]))
+	// cond:
+	// result: (Const32 [int64(int32(c-d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c - d))
+		return true
+	}
+	// match: (Sub32 x (Const32 <t> [c]))
+	// cond: x.Op != OpConst32
+	// result: (Add32 (Const32 <t> [int64(int32(-c))]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpAdd32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = int64(int32(-c))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Sub32 x x)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Sub32 (Add32 x y) x)
+	// cond:
+	// result: y
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Sub32 (Add32 x y) y)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd32 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpSub32F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub32F (Const32F [c]) (Const32F [d]))
+	// cond:
+	// result: (Const32F [f2i(float64(i2f32(c) - i2f32(d)))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32F {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32F {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst32F)
+		v.AuxInt = f2i(float64(i2f32(c) - i2f32(d)))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpSub64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub64  (Const64 [c]) (Const64 [d]))
+	// cond:
+	// result: (Const64 [c-d])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst64)
+		v.AuxInt = c - d
+		return true
+	}
+	// match: (Sub64 x (Const64 <t> [c]))
+	// cond: x.Op != OpConst64
+	// result: (Add64 (Const64 <t> [-c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpAdd64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = -c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Sub64 x x)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Sub64 (Add64 x y) x)
+	// cond:
+	// result: y
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Sub64 (Add64 x y) y)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd64 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpSub64F(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub64F (Const64F [c]) (Const64F [d]))
+	// cond:
+	// result: (Const64F [f2i(i2f(c) - i2f(d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64F {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64F {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst64F)
+		v.AuxInt = f2i(i2f(c) - i2f(d))
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpSub8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Sub8   (Const8 [c]) (Const8 [d]))
+	// cond:
+	// result: (Const8 [int64(int8(c-d))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		c := v_0.AuxInt
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		d := v_1.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c - d))
+		return true
+	}
+	// match: (Sub8  x (Const8  <t> [c]))
+	// cond: x.Op != OpConst8
+	// result: (Add8  (Const8  <t> [int64(int8(-c))]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpAdd8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = int64(int8(-c))
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Sub8  x x)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Sub8  (Add8  x y) x)
+	// cond:
+	// result: y
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd8 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Sub8  (Add8  x y) y)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAdd8 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpTrunc16to8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc16to8  (Const16 [c]))
+	// cond:
+	// result: (Const8   [int64(int8(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c))
+		return true
+	}
+	// match: (Trunc16to8  (And16 (Const16 [y]) x))
+	// cond: y&0xFF == 0xFF
+	// result: (Trunc16to8 x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd16 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst16 {
+			break
+		}
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFF == 0xFF) {
+			break
+		}
+		v.reset(OpTrunc16to8)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpTrunc32to16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc32to16 (Const32 [c]))
+	// cond:
+	// result: (Const16  [int64(int16(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c))
+		return true
+	}
+	// match: (Trunc32to16 (And32 (Const32 [y]) x))
+	// cond: y&0xFFFF == 0xFFFF
+	// result: (Trunc32to16 x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFFFF == 0xFFFF) {
+			break
+		}
+		v.reset(OpTrunc32to16)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpTrunc32to8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc32to8  (Const32 [c]))
+	// cond:
+	// result: (Const8   [int64(int8(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c))
+		return true
+	}
+	// match: (Trunc32to8  (And32 (Const32 [y]) x))
+	// cond: y&0xFF == 0xFF
+	// result: (Trunc32to8 x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd32 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst32 {
+			break
+		}
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFF == 0xFF) {
+			break
+		}
+		v.reset(OpTrunc32to8)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpTrunc64to16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc64to16 (Const64 [c]))
+	// cond:
+	// result: (Const16  [int64(int16(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst16)
+		v.AuxInt = int64(int16(c))
+		return true
+	}
+	// match: (Trunc64to16 (And64 (Const64 [y]) x))
+	// cond: y&0xFFFF == 0xFFFF
+	// result: (Trunc64to16 x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFFFF == 0xFFFF) {
+			break
+		}
+		v.reset(OpTrunc64to16)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpTrunc64to32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc64to32 (Const64 [c]))
+	// cond:
+	// result: (Const32  [int64(int32(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst32)
+		v.AuxInt = int64(int32(c))
+		return true
+	}
+	// match: (Trunc64to32 (And64 (Const64 [y]) x))
+	// cond: y&0xFFFFFFFF == 0xFFFFFFFF
+	// result: (Trunc64to32 x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFFFFFFFF == 0xFFFFFFFF) {
+			break
+		}
+		v.reset(OpTrunc64to32)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpTrunc64to8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Trunc64to8  (Const64 [c]))
+	// cond:
+	// result: (Const8   [int64(int8(c))])
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		c := v_0.AuxInt
+		v.reset(OpConst8)
+		v.AuxInt = int64(int8(c))
+		return true
+	}
+	// match: (Trunc64to8  (And64 (Const64 [y]) x))
+	// cond: y&0xFF == 0xFF
+	// result: (Trunc64to8 x)
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpAnd64 {
+			break
+		}
+		v_0_0 := v_0.Args[0]
+		if v_0_0.Op != OpConst64 {
+			break
+		}
+		y := v_0_0.AuxInt
+		x := v_0.Args[1]
+		if !(y&0xFF == 0xFF) {
+			break
+		}
+		v.reset(OpTrunc64to8)
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpXor16(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Xor16 x (Const16 <t> [c]))
+	// cond: x.Op != OpConst16
+	// result: (Xor16 (Const16 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst16 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst16) {
+			break
+		}
+		v.reset(OpXor16)
+		v0 := b.NewValue0(v.Line, OpConst16, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Xor16 x x)
+	// cond:
+	// result: (Const16 [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConst16)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Xor16 (Const16 [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst16 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Xor16 x (Xor16 x y))
+	// cond:
+	// result: y
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor16 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor16 x (Xor16 y x))
+	// cond:
+	// result: y
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor16 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor16 (Xor16 x y) x)
+	// cond:
+	// result: y
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor16 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor16 (Xor16 x y) y)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor16 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpXor32(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Xor32 x (Const32 <t> [c]))
+	// cond: x.Op != OpConst32
+	// result: (Xor32 (Const32 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst32 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst32) {
+			break
+		}
+		v.reset(OpXor32)
+		v0 := b.NewValue0(v.Line, OpConst32, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Xor32 x x)
+	// cond:
+	// result: (Const32 [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConst32)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Xor32 (Const32 [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst32 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Xor32 x (Xor32 x y))
+	// cond:
+	// result: y
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor32 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor32 x (Xor32 y x))
+	// cond:
+	// result: y
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor32 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor32 (Xor32 x y) x)
+	// cond:
+	// result: y
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor32 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor32 (Xor32 x y) y)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor32 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpXor64(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Xor64 x (Const64 <t> [c]))
+	// cond: x.Op != OpConst64
+	// result: (Xor64 (Const64 <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst64 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst64) {
+			break
+		}
+		v.reset(OpXor64)
+		v0 := b.NewValue0(v.Line, OpConst64, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Xor64 x x)
+	// cond:
+	// result: (Const64 [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConst64)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Xor64 (Const64 [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst64 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Xor64 x (Xor64 x y))
+	// cond:
+	// result: y
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor64 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor64 x (Xor64 y x))
+	// cond:
+	// result: y
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor64 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor64 (Xor64 x y) x)
+	// cond:
+	// result: y
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor64 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor64 (Xor64 x y) y)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor64 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteValuegeneric_OpXor8(v *Value, config *Config) bool {
+	b := v.Block
+	_ = b
+	// match: (Xor8  x (Const8  <t> [c]))
+	// cond: x.Op != OpConst8
+	// result: (Xor8  (Const8  <t> [c]) x)
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpConst8 {
+			break
+		}
+		t := v_1.Type
+		c := v_1.AuxInt
+		if !(x.Op != OpConst8) {
+			break
+		}
+		v.reset(OpXor8)
+		v0 := b.NewValue0(v.Line, OpConst8, t)
+		v0.AuxInt = c
+		v.AddArg(v0)
+		v.AddArg(x)
+		return true
+	}
+	// match: (Xor8  x x)
+	// cond:
+	// result: (Const8  [0])
+	for {
+		x := v.Args[0]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpConst8)
+		v.AuxInt = 0
+		return true
+	}
+	// match: (Xor8  (Const8  [0]) x)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpConst8 {
+			break
+		}
+		if v_0.AuxInt != 0 {
+			break
+		}
+		x := v.Args[1]
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	// match: (Xor8  x (Xor8  x y))
+	// cond:
+	// result: y
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor8 {
+			break
+		}
+		if x != v_1.Args[0] {
+			break
+		}
+		y := v_1.Args[1]
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor8  x (Xor8  y x))
+	// cond:
+	// result: y
+	for {
+		x := v.Args[0]
+		v_1 := v.Args[1]
+		if v_1.Op != OpXor8 {
+			break
+		}
+		y := v_1.Args[0]
+		if x != v_1.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor8  (Xor8  x y) x)
+	// cond:
+	// result: y
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor8 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if x != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = y.Type
+		v.AddArg(y)
+		return true
+	}
+	// match: (Xor8  (Xor8  x y) y)
+	// cond:
+	// result: x
+	for {
+		v_0 := v.Args[0]
+		if v_0.Op != OpXor8 {
+			break
+		}
+		x := v_0.Args[0]
+		y := v_0.Args[1]
+		if y != v.Args[1] {
+			break
+		}
+		v.reset(OpCopy)
+		v.Type = x.Type
+		v.AddArg(x)
+		return true
+	}
+	return false
+}
+func rewriteBlockgeneric(b *Block) bool {
+	switch b.Kind {
+	case BlockCheck:
+		// match: (Check (NilCheck (GetG _) _) next)
+		// cond:
+		// result: (Plain nil next)
+		for {
+			v := b.Control
+			if v.Op != OpNilCheck {
+				break
+			}
+			v_0 := v.Args[0]
+			if v_0.Op != OpGetG {
+				break
+			}
+			next := b.Succs[0]
+			b.Kind = BlockPlain
+			b.SetControl(nil)
+			_ = next
+			return true
+		}
+	case BlockIf:
+		// match: (If (Not cond) yes no)
+		// cond:
+		// result: (If cond no yes)
+		for {
+			v := b.Control
+			if v.Op != OpNot {
+				break
+			}
+			cond := v.Args[0]
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			b.Kind = BlockIf
+			b.SetControl(cond)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+		// match: (If (ConstBool [c]) yes no)
+		// cond: c == 1
+		// result: (First nil yes no)
+		for {
+			v := b.Control
+			if v.Op != OpConstBool {
+				break
+			}
+			c := v.AuxInt
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			if !(c == 1) {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			_ = yes
+			_ = no
+			return true
+		}
+		// match: (If (ConstBool [c]) yes no)
+		// cond: c == 0
+		// result: (First nil no yes)
+		for {
+			v := b.Control
+			if v.Op != OpConstBool {
+				break
+			}
+			c := v.AuxInt
+			yes := b.Succs[0]
+			no := b.Succs[1]
+			if !(c == 0) {
+				break
+			}
+			b.Kind = BlockFirst
+			b.SetControl(nil)
+			b.swapSuccessors()
+			_ = no
+			_ = yes
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go
new file mode 100644
index 0000000..765f0c1
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/schedule.go
@@ -0,0 +1,232 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "container/heap"
+
+const (
+	ScorePhi = iota // towards top of block
+	ScoreVarDef
+	ScoreMemory
+	ScoreDefault
+	ScoreFlags
+	ScoreControl // towards bottom of block
+)
+
+type ValHeap struct {
+	a     []*Value
+	score []int8
+}
+
+func (h ValHeap) Len() int      { return len(h.a) }
+func (h ValHeap) Swap(i, j int) { a := h.a; a[i], a[j] = a[j], a[i] }
+
+func (h *ValHeap) Push(x interface{}) {
+	// Push and Pop use pointer receivers because they modify the slice's length,
+	// not just its contents.
+	v := x.(*Value)
+	h.a = append(h.a, v)
+}
+func (h *ValHeap) Pop() interface{} {
+	old := h.a
+	n := len(old)
+	x := old[n-1]
+	h.a = old[0 : n-1]
+	return x
+}
+func (h ValHeap) Less(i, j int) bool {
+	x := h.a[i]
+	y := h.a[j]
+	sx := h.score[x.ID]
+	sy := h.score[y.ID]
+	if c := sx - sy; c != 0 {
+		return c > 0 // higher score comes later.
+	}
+	if x.Line != y.Line { // Favor in-order line stepping
+		return x.Line > y.Line
+	}
+	if x.Op != OpPhi {
+		if c := len(x.Args) - len(y.Args); c != 0 {
+			return c < 0 // smaller args comes later
+		}
+	}
+	return x.ID > y.ID
+}
+
+// Schedule the Values in each Block. After this phase returns, the
+// order of b.Values matters and is the order in which those values
+// will appear in the assembly output. For now it generates a
+// reasonable valid schedule using a priority queue. TODO(khr):
+// schedule smarter.
+func schedule(f *Func) {
+	// For each value, the number of times it is used in the block
+	// by values that have not been scheduled yet.
+	uses := make([]int32, f.NumValues())
+
+	// reusable priority queue
+	priq := new(ValHeap)
+
+	// "priority" for a value
+	score := make([]int8, f.NumValues())
+
+	// scheduling order. We queue values in this list in reverse order.
+	var order []*Value
+
+	// maps mem values to the next live memory value
+	nextMem := make([]*Value, f.NumValues())
+	// additional pretend arguments for each Value. Used to enforce load/store ordering.
+	additionalArgs := make([][]*Value, f.NumValues())
+
+	for _, b := range f.Blocks {
+		// Compute score. Larger numbers are scheduled closer to the end of the block.
+		for _, v := range b.Values {
+			switch {
+			case v.Op == OpAMD64LoweredGetClosurePtr:
+				// We also score GetLoweredClosurePtr as early as possible to ensure that the
+				// context register is not stomped. GetLoweredClosurePtr should only appear
+				// in the entry block where there are no phi functions, so there is no
+				// conflict or ambiguity here.
+				if b != f.Entry {
+					f.Fatalf("LoweredGetClosurePtr appeared outside of entry block, b=%s", b.String())
+				}
+				score[v.ID] = ScorePhi
+			case v.Op == OpPhi:
+				// We want all the phis first.
+				score[v.ID] = ScorePhi
+			case v.Op == OpVarDef:
+				// We want all the vardefs next.
+				score[v.ID] = ScoreVarDef
+			case v.Type.IsMemory():
+				// Schedule stores as early as possible. This tends to
+				// reduce register pressure. It also helps make sure
+				// VARDEF ops are scheduled before the corresponding LEA.
+				score[v.ID] = ScoreMemory
+			case v.Type.IsFlags():
+				// Schedule flag register generation as late as possible.
+				// This makes sure that we only have one live flags
+				// value at a time.
+				score[v.ID] = ScoreFlags
+			default:
+				score[v.ID] = ScoreDefault
+			}
+		}
+	}
+
+	for _, b := range f.Blocks {
+		// Find store chain for block.
+		// Store chains for different blocks overwrite each other, so
+		// the calculated store chain is good only for this block.
+		for _, v := range b.Values {
+			if v.Op != OpPhi && v.Type.IsMemory() {
+				for _, w := range v.Args {
+					if w.Type.IsMemory() {
+						nextMem[w.ID] = v
+					}
+				}
+			}
+		}
+
+		// Compute uses.
+		for _, v := range b.Values {
+			if v.Op == OpPhi {
+				// If a value is used by a phi, it does not induce
+				// a scheduling edge because that use is from the
+				// previous iteration.
+				continue
+			}
+			for _, w := range v.Args {
+				if w.Block == b {
+					uses[w.ID]++
+				}
+				// Any load must come before the following store.
+				if v.Type.IsMemory() || !w.Type.IsMemory() {
+					continue // not a load
+				}
+				s := nextMem[w.ID]
+				if s == nil || s.Block != b {
+					continue
+				}
+				additionalArgs[s.ID] = append(additionalArgs[s.ID], v)
+				uses[v.ID]++
+			}
+		}
+
+		if b.Control != nil && b.Control.Op != OpPhi {
+			// Force the control value to be scheduled at the end,
+			// unless it is a phi value (which must be first).
+			score[b.Control.ID] = ScoreControl
+
+			// Schedule values dependent on the control value at the end.
+			// This reduces the number of register spills. We don't find
+			// all values that depend on the control, just values with a
+			// direct dependency. This is cheaper and in testing there
+			// was no difference in the number of spills.
+			for _, v := range b.Values {
+				if v.Op != OpPhi {
+					for _, a := range v.Args {
+						if a == b.Control {
+							score[v.ID] = ScoreControl
+						}
+					}
+				}
+			}
+		}
+
+		// To put things into a priority queue
+		// The values that should come last are least.
+		priq.score = score
+		priq.a = priq.a[:0]
+
+		// Initialize priority queue with schedulable values.
+		for _, v := range b.Values {
+			if uses[v.ID] == 0 {
+				heap.Push(priq, v)
+			}
+		}
+
+		// Schedule highest priority value, update use counts, repeat.
+		order = order[:0]
+		for {
+			// Find highest priority schedulable value.
+			// Note that schedule is assembled backwards.
+
+			if priq.Len() == 0 {
+				break
+			}
+
+			v := heap.Pop(priq).(*Value)
+
+			// Add it to the schedule.
+			order = append(order, v)
+
+			// Update use counts of arguments.
+			for _, w := range v.Args {
+				if w.Block != b {
+					continue
+				}
+				uses[w.ID]--
+				if uses[w.ID] == 0 {
+					// All uses scheduled, w is now schedulable.
+					heap.Push(priq, w)
+				}
+			}
+			for _, w := range additionalArgs[v.ID] {
+				uses[w.ID]--
+				if uses[w.ID] == 0 {
+					// All uses scheduled, w is now schedulable.
+					heap.Push(priq, w)
+				}
+			}
+		}
+		if len(order) != len(b.Values) {
+			f.Fatalf("schedule does not include all values")
+		}
+		for i := 0; i < len(b.Values); i++ {
+			b.Values[i] = order[len(b.Values)-1-i]
+		}
+	}
+
+	f.scheduled = true
+}
diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go
new file mode 100644
index 0000000..0ff57e3
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/schedule_test.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 ssa
+
+import "testing"
+
+func TestSchedule(t *testing.T) {
+	c := testConfig(t)
+	cases := []fun{
+		Fun(c, "entry",
+			Bloc("entry",
+				Valu("mem0", OpInitMem, TypeMem, 0, nil),
+				Valu("ptr", OpConst64, TypeInt64, 0xABCD, nil),
+				Valu("v", OpConst64, TypeInt64, 12, nil),
+				Valu("mem1", OpStore, TypeMem, 8, nil, "ptr", "v", "mem0"),
+				Valu("mem2", OpStore, TypeMem, 8, nil, "ptr", "v", "mem1"),
+				Valu("mem3", OpStore, TypeInt64, 8, nil, "ptr", "sum", "mem2"),
+				Valu("l1", OpLoad, TypeInt64, 0, nil, "ptr", "mem1"),
+				Valu("l2", OpLoad, TypeInt64, 0, nil, "ptr", "mem2"),
+				Valu("sum", OpAdd64, TypeInt64, 0, nil, "l1", "l2"),
+				Goto("exit")),
+			Bloc("exit",
+				Exit("mem3"))),
+	}
+	for _, c := range cases {
+		schedule(c.f)
+		if !isSingleLiveMem(c.f) {
+			t.Error("single-live-mem restriction not enforced by schedule for func:")
+			printFunc(c.f)
+		}
+	}
+}
+
+func isSingleLiveMem(f *Func) bool {
+	for _, b := range f.Blocks {
+		var liveMem *Value
+		for _, v := range b.Values {
+			for _, w := range v.Args {
+				if w.Type.IsMemory() {
+					if liveMem == nil {
+						liveMem = w
+						continue
+					}
+					if w != liveMem {
+						return false
+					}
+				}
+			}
+			if v.Type.IsMemory() {
+				liveMem = v
+			}
+		}
+	}
+	return true
+}
diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go
new file mode 100644
index 0000000..8d5e62f
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/shift_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.
+
+package ssa
+
+import (
+	"testing"
+)
+
+func TestShiftConstAMD64(t *testing.T) {
+	c := testConfig(t)
+	fun := makeConstShiftFunc(c, 18, OpLsh64x64, TypeUInt64)
+	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
+	fun.f.Free()
+	fun = makeConstShiftFunc(c, 66, OpLsh64x64, TypeUInt64)
+	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 0, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
+	fun.f.Free()
+	fun = makeConstShiftFunc(c, 18, OpRsh64Ux64, TypeUInt64)
+	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHRQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
+	fun.f.Free()
+	fun = makeConstShiftFunc(c, 66, OpRsh64Ux64, TypeUInt64)
+	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHRQconst: 0, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0})
+	fun.f.Free()
+	fun = makeConstShiftFunc(c, 18, OpRsh64x64, TypeInt64)
+	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SARQconst: 1, OpAMD64CMPQconst: 0})
+	fun.f.Free()
+	fun = makeConstShiftFunc(c, 66, OpRsh64x64, TypeInt64)
+	checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SARQconst: 1, OpAMD64CMPQconst: 0})
+	fun.f.Free()
+}
+
+func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun {
+	ptyp := &TypeImpl{Size_: 8, Ptr: true, Name: "ptr"}
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("SP", OpSP, TypeUInt64, 0, nil),
+			Valu("argptr", OpOffPtr, ptyp, 8, nil, "SP"),
+			Valu("resptr", OpOffPtr, ptyp, 16, nil, "SP"),
+			Valu("load", OpLoad, typ, 0, nil, "argptr", "mem"),
+			Valu("c", OpConst64, TypeUInt64, amount, nil),
+			Valu("shift", op, typ, 0, nil, "load", "c"),
+			Valu("store", OpStore, TypeMem, 8, nil, "resptr", "shift", "mem"),
+			Exit("store")))
+	Compile(fun.f)
+	return fun
+}
diff --git a/src/cmd/compile/internal/ssa/shortcircuit.go b/src/cmd/compile/internal/ssa/shortcircuit.go
new file mode 100644
index 0000000..ff05a04
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/shortcircuit.go
@@ -0,0 +1,133 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// Shortcircuit finds situations where branch directions
+// are always correlated and rewrites the CFG to take
+// advantage of that fact.
+// This optimization is useful for compiling && and || expressions.
+func shortcircuit(f *Func) {
+	// Step 1: Replace a phi arg with a constant if that arg
+	// is the control value of a preceding If block.
+	// b1:
+	//    If a goto b2 else b3
+	// b2: <- b1 ...
+	//    x = phi(a, ...)
+	//
+	// We can replace the "a" in the phi with the constant true.
+	ct := f.ConstBool(f.Entry.Line, f.Config.fe.TypeBool(), true)
+	cf := f.ConstBool(f.Entry.Line, f.Config.fe.TypeBool(), false)
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if v.Op != OpPhi {
+				continue
+			}
+			if !v.Type.IsBoolean() {
+				continue
+			}
+			for i, a := range v.Args {
+				e := b.Preds[i]
+				p := e.b
+				if p.Kind != BlockIf {
+					continue
+				}
+				if p.Control != a {
+					continue
+				}
+				if e.i == 0 {
+					v.SetArg(i, ct)
+				} else {
+					v.SetArg(i, cf)
+				}
+			}
+		}
+	}
+
+	// Step 2: Compute which values are live across blocks.
+	live := make([]bool, f.NumValues())
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			for _, a := range v.Args {
+				if a.Block != v.Block {
+					live[a.ID] = true
+				}
+			}
+		}
+		if b.Control != nil && b.Control.Block != b {
+			live[b.Control.ID] = true
+		}
+	}
+
+	// Step 3: Redirect control flow around known branches.
+	// p:
+	//   ... goto b ...
+	// b: <- p ...
+	//   v = phi(true, ...)
+	//   if v goto t else u
+	// We can redirect p to go directly to t instead of b.
+	// (If v is not live after b).
+	for _, b := range f.Blocks {
+		if b.Kind != BlockIf {
+			continue
+		}
+		if len(b.Values) != 1 {
+			continue
+		}
+		v := b.Values[0]
+		if v.Op != OpPhi {
+			continue
+		}
+		if b.Control != v {
+			continue
+		}
+		if live[v.ID] {
+			continue
+		}
+		for i := 0; i < len(v.Args); i++ {
+			a := v.Args[i]
+			if a.Op != OpConstBool {
+				continue
+			}
+
+			// The predecessor we come in from.
+			e1 := b.Preds[i]
+			p := e1.b
+			pi := e1.i
+
+			// The successor we always go to when coming in
+			// from that predecessor.
+			e2 := b.Succs[1-a.AuxInt]
+			t := e2.b
+			ti := e2.i
+
+			// Remove b's incoming edge from p.
+			b.removePred(i)
+			n := len(b.Preds)
+			v.Args[i].Uses--
+			v.Args[i] = v.Args[n]
+			v.Args[n] = nil
+			v.Args = v.Args[:n]
+
+			// Redirect p's outgoing edge to t.
+			p.Succs[pi] = Edge{t, len(t.Preds)}
+
+			// Fix up t to have one more predecessor.
+			t.Preds = append(t.Preds, Edge{p, pi})
+			for _, w := range t.Values {
+				if w.Op != OpPhi {
+					continue
+				}
+				w.AddArg(w.Args[ti])
+			}
+
+			if len(b.Preds) == 1 {
+				v.Op = OpCopy
+				// No longer a phi, stop optimizing here.
+				break
+			}
+			i--
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/shortcircuit_test.go b/src/cmd/compile/internal/ssa/shortcircuit_test.go
new file mode 100644
index 0000000..f208801
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/shortcircuit_test.go
@@ -0,0 +1,50 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "testing"
+
+func TestShortCircuit(t *testing.T) {
+	c := testConfig(t)
+
+	fun := Fun(c, "entry",
+		Bloc("entry",
+			Valu("mem", OpInitMem, TypeMem, 0, nil),
+			Valu("arg1", OpArg, TypeInt64, 0, nil),
+			Valu("arg2", OpArg, TypeInt64, 0, nil),
+			Valu("arg3", OpArg, TypeInt64, 0, nil),
+			Goto("b1")),
+		Bloc("b1",
+			Valu("cmp1", OpLess64, TypeBool, 0, nil, "arg1", "arg2"),
+			If("cmp1", "b2", "b3")),
+		Bloc("b2",
+			Valu("cmp2", OpLess64, TypeBool, 0, nil, "arg2", "arg3"),
+			Goto("b3")),
+		Bloc("b3",
+			Valu("phi2", OpPhi, TypeBool, 0, nil, "cmp1", "cmp2"),
+			If("phi2", "b4", "b5")),
+		Bloc("b4",
+			Valu("cmp3", OpLess64, TypeBool, 0, nil, "arg3", "arg1"),
+			Goto("b5")),
+		Bloc("b5",
+			Valu("phi3", OpPhi, TypeBool, 0, nil, "phi2", "cmp3"),
+			If("phi3", "b6", "b7")),
+		Bloc("b6",
+			Exit("mem")),
+		Bloc("b7",
+			Exit("mem")))
+
+	CheckFunc(fun.f)
+	shortcircuit(fun.f)
+	CheckFunc(fun.f)
+
+	for _, b := range fun.f.Blocks {
+		for _, v := range b.Values {
+			if v.Op == OpPhi {
+				t.Errorf("phi %s remains", v)
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/sizeof_test.go b/src/cmd/compile/internal/ssa/sizeof_test.go
new file mode 100644
index 0000000..4aab923
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/sizeof_test.go
@@ -0,0 +1,39 @@
+// Copyright 2016 The Go 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
+
+package ssa
+
+import (
+	"reflect"
+	"testing"
+	"unsafe"
+)
+
+// Assert that the size of important structures do not change unexpectedly.
+
+func TestSizeof(t *testing.T) {
+	const _64bit = unsafe.Sizeof(uintptr(0)) == 8
+
+	var tests = []struct {
+		val    interface{} // type as a value
+		_32bit uintptr     // size on 32bit platforms
+		_64bit uintptr     // size on 64bit platforms
+	}{
+		{Value{}, 68, 112},
+		{Block{}, 148, 288},
+	}
+
+	for _, tt := range tests {
+		want := tt._32bit
+		if _64bit {
+			want = tt._64bit
+		}
+		got := reflect.TypeOf(tt.val).Size()
+		if want != got {
+			t.Errorf("unsafe.Sizeof(%T) = %d, want %d", tt.val, got, want)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/sparsemap.go b/src/cmd/compile/internal/ssa/sparsemap.go
new file mode 100644
index 0000000..afb9f60
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/sparsemap.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.
+
+package ssa
+
+// from http://research.swtch.com/sparse
+// in turn, from Briggs and Torczon
+
+type sparseEntry struct {
+	key ID
+	val int32
+}
+
+type sparseMap struct {
+	dense  []sparseEntry
+	sparse []int32
+}
+
+// newSparseMap returns a sparseMap that can map
+// integers between 0 and n-1 to int32s.
+func newSparseMap(n int) *sparseMap {
+	return &sparseMap{dense: nil, sparse: make([]int32, n)}
+}
+
+func (s *sparseMap) size() int {
+	return len(s.dense)
+}
+
+func (s *sparseMap) contains(k ID) bool {
+	i := s.sparse[k]
+	return i < int32(len(s.dense)) && s.dense[i].key == k
+}
+
+// get returns the value for key k, or -1 if k does
+// not appear in the map.
+func (s *sparseMap) get(k ID) int32 {
+	i := s.sparse[k]
+	if i < int32(len(s.dense)) && s.dense[i].key == k {
+		return s.dense[i].val
+	}
+	return -1
+}
+
+func (s *sparseMap) set(k ID, v int32) {
+	i := s.sparse[k]
+	if i < int32(len(s.dense)) && s.dense[i].key == k {
+		s.dense[i].val = v
+		return
+	}
+	s.dense = append(s.dense, sparseEntry{k, v})
+	s.sparse[k] = int32(len(s.dense)) - 1
+}
+
+// setBit sets the v'th bit of k's value, where 0 <= v < 32
+func (s *sparseMap) setBit(k ID, v uint) {
+	if v >= 32 {
+		panic("bit index too large.")
+	}
+	i := s.sparse[k]
+	if i < int32(len(s.dense)) && s.dense[i].key == k {
+		s.dense[i].val |= 1 << v
+		return
+	}
+	s.dense = append(s.dense, sparseEntry{k, 1 << v})
+	s.sparse[k] = int32(len(s.dense)) - 1
+}
+
+func (s *sparseMap) remove(k ID) {
+	i := s.sparse[k]
+	if i < int32(len(s.dense)) && s.dense[i].key == k {
+		y := s.dense[len(s.dense)-1]
+		s.dense[i] = y
+		s.sparse[y.key] = i
+		s.dense = s.dense[:len(s.dense)-1]
+	}
+}
+
+func (s *sparseMap) clear() {
+	s.dense = s.dense[:0]
+}
+
+func (s *sparseMap) contents() []sparseEntry {
+	return s.dense
+}
diff --git a/src/cmd/compile/internal/ssa/sparseset.go b/src/cmd/compile/internal/ssa/sparseset.go
new file mode 100644
index 0000000..b5cabfb
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/sparseset.go
@@ -0,0 +1,79 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// from http://research.swtch.com/sparse
+// in turn, from Briggs and Torczon
+
+type sparseSet struct {
+	dense  []ID
+	sparse []int32
+}
+
+// newSparseSet returns a sparseSet that can represent
+// integers between 0 and n-1
+func newSparseSet(n int) *sparseSet {
+	return &sparseSet{dense: nil, sparse: make([]int32, n)}
+}
+
+func (s *sparseSet) cap() int {
+	return len(s.sparse)
+}
+
+func (s *sparseSet) size() int {
+	return len(s.dense)
+}
+
+func (s *sparseSet) contains(x ID) bool {
+	i := s.sparse[x]
+	return i < int32(len(s.dense)) && s.dense[i] == x
+}
+
+func (s *sparseSet) add(x ID) {
+	i := s.sparse[x]
+	if i < int32(len(s.dense)) && s.dense[i] == x {
+		return
+	}
+	s.dense = append(s.dense, x)
+	s.sparse[x] = int32(len(s.dense)) - 1
+}
+
+func (s *sparseSet) addAll(a []ID) {
+	for _, x := range a {
+		s.add(x)
+	}
+}
+
+func (s *sparseSet) addAllValues(a []*Value) {
+	for _, v := range a {
+		s.add(v.ID)
+	}
+}
+
+func (s *sparseSet) remove(x ID) {
+	i := s.sparse[x]
+	if i < int32(len(s.dense)) && s.dense[i] == x {
+		y := s.dense[len(s.dense)-1]
+		s.dense[i] = y
+		s.sparse[y] = i
+		s.dense = s.dense[:len(s.dense)-1]
+	}
+}
+
+// pop removes an arbitrary element from the set.
+// The set must be nonempty.
+func (s *sparseSet) pop() ID {
+	x := s.dense[len(s.dense)-1]
+	s.dense = s.dense[:len(s.dense)-1]
+	return x
+}
+
+func (s *sparseSet) clear() {
+	s.dense = s.dense[:0]
+}
+
+func (s *sparseSet) contents() []ID {
+	return s.dense
+}
diff --git a/src/cmd/compile/internal/ssa/sparsetree.go b/src/cmd/compile/internal/ssa/sparsetree.go
new file mode 100644
index 0000000..7c82a60
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/sparsetree.go
@@ -0,0 +1,186 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "fmt"
+
+type SparseTreeNode struct {
+	child   *Block
+	sibling *Block
+	parent  *Block
+
+	// Every block has 6 numbers associated with it:
+	// entry-1, entry, entry+1, exit-1, and exit, exit+1.
+	// entry and exit are conceptually the top of the block (phi functions)
+	// entry+1 and exit-1 are conceptually the bottom of the block (ordinary defs)
+	// entry-1 and exit+1 are conceptually "just before" the block (conditions flowing in)
+	//
+	// This simplifies life if we wish to query information about x
+	// when x is both an input to and output of a block.
+	entry, exit int32
+}
+
+func (s *SparseTreeNode) String() string {
+	return fmt.Sprintf("[%d,%d]", s.entry, s.exit)
+}
+
+func (s *SparseTreeNode) Entry() int32 {
+	return s.entry
+}
+
+func (s *SparseTreeNode) Exit() int32 {
+	return s.exit
+}
+
+const (
+	// When used to lookup up definitions in a sparse tree,
+	// these adjustments to a block's entry (+adjust) and
+	// exit (-adjust) numbers allow a distinction to be made
+	// between assignments (typically branch-dependent
+	// conditionals) occurring "before" the block (e.g., as inputs
+	// to the block and its phi functions), "within" the block,
+	// and "after" the block.
+	AdjustBefore = -1 // defined before phi
+	AdjustWithin = 0  // defined by phi
+	AdjustAfter  = 1  // defined within block
+)
+
+// A SparseTree is a tree of Blocks.
+// It allows rapid ancestor queries,
+// such as whether one block dominates another.
+type SparseTree []SparseTreeNode
+
+// newSparseTree creates a SparseTree from a block-to-parent map (array indexed by Block.ID)
+func newSparseTree(f *Func, parentOf []*Block) SparseTree {
+	t := make(SparseTree, f.NumBlocks())
+	for _, b := range f.Blocks {
+		n := &t[b.ID]
+		if p := parentOf[b.ID]; p != nil {
+			n.parent = p
+			n.sibling = t[p.ID].child
+			t[p.ID].child = b
+		}
+	}
+	t.numberBlock(f.Entry, 1)
+	return t
+}
+
+// numberBlock assigns entry and exit numbers for b and b's
+// children in an in-order walk from a gappy sequence, where n
+// is the first number not yet assigned or reserved. N should
+// be larger than zero. For each entry and exit number, the
+// values one larger and smaller are reserved to indicate
+// "strictly above" and "strictly below". numberBlock returns
+// the smallest number not yet assigned or reserved (i.e., the
+// exit number of the last block visited, plus two, because
+// last.exit+1 is a reserved value.)
+//
+// examples:
+//
+// single node tree Root, call with n=1
+//         entry=2 Root exit=5; returns 7
+//
+// two node tree, Root->Child, call with n=1
+//         entry=2 Root exit=11; returns 13
+//         entry=5 Child exit=8
+//
+// three node tree, Root->(Left, Right), call with n=1
+//         entry=2 Root exit=17; returns 19
+// entry=5 Left exit=8;  entry=11 Right exit=14
+//
+// This is the in-order sequence of assigned and reserved numbers
+// for the last example:
+//   root     left     left      right       right       root
+//  1 2e 3 | 4 5e 6 | 7 8x 9 | 10 11e 12 | 13 14x 15 | 16 17x 18
+
+func (t SparseTree) numberBlock(b *Block, n int32) int32 {
+	// reserve n for entry-1, assign n+1 to entry
+	n++
+	t[b.ID].entry = n
+	// reserve n+1 for entry+1, n+2 is next free number
+	n += 2
+	for c := t[b.ID].child; c != nil; c = t[c.ID].sibling {
+		n = t.numberBlock(c, n) // preserves n = next free number
+	}
+	// reserve n for exit-1, assign n+1 to exit
+	n++
+	t[b.ID].exit = n
+	// reserve n+1 for exit+1, n+2 is next free number, returned.
+	return n + 2
+}
+
+// Sibling returns a sibling of x in the dominator tree (i.e.,
+// a node with the same immediate dominator) or nil if there
+// are no remaining siblings in the arbitrary but repeatable
+// order chosen. Because the Child-Sibling order is used
+// to assign entry and exit numbers in the treewalk, those
+// numbers are also consistent with this order (i.e.,
+// Sibling(x) has entry number larger than x's exit number).
+func (t SparseTree) Sibling(x *Block) *Block {
+	return t[x.ID].sibling
+}
+
+// Child returns a child of x in the dominator tree, or
+// nil if there are none. The choice of first child is
+// arbitrary but repeatable.
+func (t SparseTree) Child(x *Block) *Block {
+	return t[x.ID].child
+}
+
+// isAncestorEq reports whether x is an ancestor of or equal to y.
+func (t SparseTree) isAncestorEq(x, y *Block) bool {
+	if x == y {
+		return true
+	}
+	xx := &t[x.ID]
+	yy := &t[y.ID]
+	return xx.entry <= yy.entry && yy.exit <= xx.exit
+}
+
+// isAncestor reports whether x is a strict ancestor of y.
+func (t SparseTree) isAncestor(x, y *Block) bool {
+	if x == y {
+		return false
+	}
+	xx := &t[x.ID]
+	yy := &t[y.ID]
+	return xx.entry < yy.entry && yy.exit < xx.exit
+}
+
+// domorder returns a value for dominator-oriented sorting.
+// Block domination does not provide a total ordering,
+// but domorder two has useful properties.
+// (1) If domorder(x) > domorder(y) then x does not dominate y.
+// (2) If domorder(x) < domorder(y) and domorder(y) < domorder(z) and x does not dominate y,
+//     then x does not dominate z.
+// Property (1) means that blocks sorted by domorder always have a maximal dominant block first.
+// Property (2) allows searches for dominated blocks to exit early.
+func (t SparseTree) domorder(x *Block) int32 {
+	// Here is an argument that entry(x) provides the properties documented above.
+	//
+	// Entry and exit values are assigned in a depth-first dominator tree walk.
+	// For all blocks x and y, one of the following holds:
+	//
+	// (x-dom-y) x dominates y => entry(x) < entry(y) < exit(y) < exit(x)
+	// (y-dom-x) y dominates x => entry(y) < entry(x) < exit(x) < exit(y)
+	// (x-then-y) neither x nor y dominates the other and x walked before y => entry(x) < exit(x) < entry(y) < exit(y)
+	// (y-then-x) neither x nor y dominates the other and y walked before y => entry(y) < exit(y) < entry(x) < exit(x)
+	//
+	// entry(x) > entry(y) eliminates case x-dom-y. This provides property (1) above.
+	//
+	// For property (2), assume entry(x) < entry(y) and entry(y) < entry(z) and x does not dominate y.
+	// entry(x) < entry(y) allows cases x-dom-y and x-then-y.
+	// But by supposition, x does not dominate y. So we have x-then-y.
+	//
+	// For contractidion, assume x dominates z.
+	// Then entry(x) < entry(z) < exit(z) < exit(x).
+	// But we know x-then-y, so entry(x) < exit(x) < entry(y) < exit(y).
+	// Combining those, entry(x) < entry(z) < exit(z) < exit(x) < entry(y) < exit(y).
+	// By supposition, entry(y) < entry(z), which allows cases y-dom-z and y-then-z.
+	// y-dom-z requires entry(y) < entry(z), but we have entry(z) < entry(y).
+	// y-then-z requires exit(y) < entry(z), but we have entry(z) < exit(y).
+	// We have a contradiction, so x does not dominate z, as required.
+	return t[x.ID].entry
+}
diff --git a/src/cmd/compile/internal/ssa/sparsetreemap.go b/src/cmd/compile/internal/ssa/sparsetreemap.go
new file mode 100644
index 0000000..6127698
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/sparsetreemap.go
@@ -0,0 +1,169 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "fmt"
+
+// A SparseTreeMap encodes a subset of nodes within a tree
+// used for sparse-ancestor queries.
+//
+// Combined with a SparseTreeHelper, this supports an Insert
+// to add a tree node to the set and a Find operation to locate
+// the nearest tree ancestor of a given node such that the
+// ancestor is also in the set.
+//
+// Given a set of blocks {B1, B2, B3} within the dominator tree, established by
+// stm.Insert()ing B1, B2, B3, etc, a query at block B
+// (performed with stm.Find(stm, B, adjust, helper))
+// will return the member of the set that is the nearest strict
+// ancestor of B within the dominator tree, or nil if none exists.
+// The expected complexity of this operation is the log of the size
+// the set, given certain assumptions about sparsity (the log complexity
+// could be guaranteed with additional data structures whose constant-
+// factor overhead has not yet been justified.)
+//
+// The adjust parameter allows positioning of the insertion
+// and lookup points within a block -- one of
+// AdjustBefore, AdjustWithin, AdjustAfter,
+// where lookups at AdjustWithin can find insertions at
+// AdjustBefore in the same block, and lookups at AdjustAfter
+// can find insertions at either AdjustBefore or AdjustWithin
+// in the same block.  (Note that this assumes a gappy numbering
+// such that exit number or exit number is separated from its
+// nearest neighbor by at least 3).
+//
+// The Sparse Tree lookup algorithm is described by
+// Paul F. Dietz. Maintaining order in a linked list. In
+// Proceedings of the Fourteenth Annual ACM Symposium on
+// Theory of Computing, pages 122–127, May 1982.
+// and by
+// Ben Wegbreit. Faster retrieval from context trees.
+// Communications of the ACM, 19(9):526–529, September 1976.
+type SparseTreeMap RBTint32
+
+// A SparseTreeHelper contains indexing and allocation data
+// structures common to a collection of SparseTreeMaps, as well
+// as exposing some useful control-flow-related data to other
+// packages, such as gc.
+type SparseTreeHelper struct {
+	Sdom   []SparseTreeNode // indexed by block.ID
+	Po     []*Block         // exported data
+	Dom    []*Block         // exported data
+	Ponums []int32          // exported data
+}
+
+// NewSparseTreeHelper returns a SparseTreeHelper for use
+// in the gc package, for example in phi-function placement.
+func NewSparseTreeHelper(f *Func) *SparseTreeHelper {
+	dom := dominators(f)
+	ponums := make([]int32, f.NumBlocks())
+	po := postorderWithNumbering(f, ponums)
+	return makeSparseTreeHelper(newSparseTree(f, dom), dom, po, ponums)
+}
+
+func (h *SparseTreeHelper) NewTree() *SparseTreeMap {
+	return &SparseTreeMap{}
+}
+
+func makeSparseTreeHelper(sdom SparseTree, dom, po []*Block, ponums []int32) *SparseTreeHelper {
+	helper := &SparseTreeHelper{Sdom: []SparseTreeNode(sdom),
+		Dom:    dom,
+		Po:     po,
+		Ponums: ponums,
+	}
+	return helper
+}
+
+// A sparseTreeMapEntry contains the data stored in a binary search
+// data structure indexed by (dominator tree walk) entry and exit numbers.
+// Each entry is added twice, once keyed by entry-1/entry/entry+1 and
+// once keyed by exit+1/exit/exit-1. (there are three choices of paired indices, not 9, and they properly nest)
+type sparseTreeMapEntry struct {
+	index *SparseTreeNode
+	block *Block // TODO: store this in a separate index.
+	data  interface{}
+}
+
+// Insert creates a definition within b with data x.
+// adjust indicates where in the block should be inserted:
+// AdjustBefore means defined at a phi function (visible Within or After in the same block)
+// AdjustWithin means defined within the block (visible After in the same block)
+// AdjustAfter means after the block (visible within child blocks)
+func (m *SparseTreeMap) Insert(b *Block, adjust int32, x interface{}, helper *SparseTreeHelper) {
+	rbtree := (*RBTint32)(m)
+	blockIndex := &helper.Sdom[b.ID]
+	if blockIndex.entry == 0 {
+		// assert unreachable
+		return
+	}
+	entry := &sparseTreeMapEntry{index: blockIndex, data: x}
+	right := blockIndex.exit - adjust
+	_ = rbtree.Insert(right, entry)
+
+	left := blockIndex.entry + adjust
+	_ = rbtree.Insert(left, entry)
+}
+
+// Find returns the definition visible from block b, or nil if none can be found.
+// Adjust indicates where the block should be searched.
+// AdjustBefore searches before the phi functions of b.
+// AdjustWithin searches starting at the phi functions of b.
+// AdjustAfter searches starting at the exit from the block, including normal within-block definitions.
+//
+// Note that Finds are properly nested with Inserts:
+// m.Insert(b, a) followed by m.Find(b, a) will not return the result of the insert,
+// but m.Insert(b, AdjustBefore) followed by m.Find(b, AdjustWithin) will.
+//
+// Another way to think of this is that Find searches for inputs, Insert defines outputs.
+func (m *SparseTreeMap) Find(b *Block, adjust int32, helper *SparseTreeHelper) interface{} {
+	rbtree := (*RBTint32)(m)
+	if rbtree == nil {
+		return nil
+	}
+	blockIndex := &helper.Sdom[b.ID]
+	_, v := rbtree.Glb(blockIndex.entry + adjust)
+	for v != nil {
+		otherEntry := v.(*sparseTreeMapEntry)
+		otherIndex := otherEntry.index
+		// Two cases -- either otherIndex brackets blockIndex,
+		// or it doesn't.
+		//
+		// Note that if otherIndex and blockIndex are
+		// the same block, then the glb test only passed
+		// because the definition is "before",
+		// i.e., k == blockIndex.entry-1
+		// allowing equality is okay on the blocks check.
+		if otherIndex.exit >= blockIndex.exit {
+			// bracketed.
+			return otherEntry.data
+		}
+		// In the not-bracketed case, we could memoize the results of
+		// walking up the tree, but for now we won't.
+		// Memoize plan is to take the gap (inclusive)
+		// from otherIndex.exit+1 to blockIndex.entry-1
+		// and insert it into this or a second tree.
+		// Said tree would then need adjusting whenever
+		// an insertion occurred.
+
+		// Expectation is that per-variable tree is sparse,
+		// therefore probe siblings instead of climbing up.
+		// Note that each sibling encountered in this walk
+		// to find a defining ancestor shares that ancestor
+		// because the walk skips over the interior -- each
+		// Glb will be an exit, and the iteration is to the
+		// Glb of the entry.
+		_, v = rbtree.Glb(otherIndex.entry - 1)
+	}
+	return nil // nothing found
+}
+
+func (m *SparseTreeMap) String() string {
+	tree := (*RBTint32)(m)
+	return tree.String()
+}
+
+func (e *sparseTreeMapEntry) String() string {
+	return fmt.Sprintf("index=%v, data=%v", e.index, e.data)
+}
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
new file mode 100644
index 0000000..83f65d0
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/stackalloc.go
@@ -0,0 +1,409 @@
+// Copyright 2015 The Go 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: live at start of block instead?
+
+package ssa
+
+import "fmt"
+
+type stackAllocState struct {
+	f *Func
+
+	// live is the output of stackalloc.
+	// live[b.id] = live values at the end of block b.
+	live [][]ID
+
+	// The following slices are reused across multiple users
+	// of stackAllocState.
+	values    []stackValState
+	interfere [][]ID // interfere[v.id] = values that interfere with v.
+	names     []LocalSlot
+	slots     []int
+	used      []bool
+
+	nArgSlot, // Number of Values sourced to arg slot
+	nNotNeed, // Number of Values not needing a stack slot
+	nNamedSlot, // Number of Values using a named stack slot
+	nReuse, // Number of values reusing a stack slot
+	nAuto, // Number of autos allocated for stack slots.
+	nSelfInterfere int32 // Number of self-interferences
+}
+
+func newStackAllocState(f *Func) *stackAllocState {
+	s := f.Config.stackAllocState
+	if s == nil {
+		return new(stackAllocState)
+	}
+	if s.f != nil {
+		f.Config.Fatalf(0, "newStackAllocState called without previous free")
+	}
+	return s
+}
+
+func putStackAllocState(s *stackAllocState) {
+	for i := range s.values {
+		s.values[i] = stackValState{}
+	}
+	for i := range s.interfere {
+		s.interfere[i] = nil
+	}
+	for i := range s.names {
+		s.names[i] = LocalSlot{}
+	}
+	for i := range s.slots {
+		s.slots[i] = 0
+	}
+	for i := range s.used {
+		s.used[i] = false
+	}
+	s.f.Config.stackAllocState = s
+	s.f = nil
+	s.live = nil
+	s.nArgSlot, s.nNotNeed, s.nNamedSlot, s.nReuse, s.nAuto, s.nSelfInterfere = 0, 0, 0, 0, 0, 0
+}
+
+type stackValState struct {
+	typ      Type
+	spill    *Value
+	needSlot bool
+}
+
+// stackalloc allocates storage in the stack frame for
+// all Values that did not get a register.
+// Returns a map from block ID to the stack values live at the end of that block.
+func stackalloc(f *Func, spillLive [][]ID) [][]ID {
+	if f.pass.debug > stackDebug {
+		fmt.Println("before stackalloc")
+		fmt.Println(f.String())
+	}
+	s := newStackAllocState(f)
+	s.init(f, spillLive)
+	defer putStackAllocState(s)
+
+	s.stackalloc()
+	if f.pass.stats > 0 {
+		f.LogStat("stack_alloc_stats",
+			s.nArgSlot, "arg_slots", s.nNotNeed, "slot_not_needed",
+			s.nNamedSlot, "named_slots", s.nAuto, "auto_slots",
+			s.nReuse, "reused_slots", s.nSelfInterfere, "self_interfering")
+	}
+
+	return s.live
+}
+
+func (s *stackAllocState) init(f *Func, spillLive [][]ID) {
+	s.f = f
+
+	// Initialize value information.
+	if n := f.NumValues(); cap(s.values) >= n {
+		s.values = s.values[:n]
+	} else {
+		s.values = make([]stackValState, n)
+	}
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			s.values[v.ID].typ = v.Type
+			s.values[v.ID].needSlot = !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && f.getHome(v.ID) == nil && !v.rematerializeable()
+			if f.pass.debug > stackDebug && s.values[v.ID].needSlot {
+				fmt.Printf("%s needs a stack slot\n", v)
+			}
+			if v.Op == OpStoreReg {
+				s.values[v.Args[0].ID].spill = v
+			}
+		}
+	}
+
+	// Compute liveness info for values needing a slot.
+	s.computeLive(spillLive)
+
+	// Build interference graph among values needing a slot.
+	s.buildInterferenceGraph()
+}
+
+func (s *stackAllocState) stackalloc() {
+	f := s.f
+
+	// Build map from values to their names, if any.
+	// A value may be associated with more than one name (e.g. after
+	// the assignment i=j). This step picks one name per value arbitrarily.
+	if n := f.NumValues(); cap(s.names) >= n {
+		s.names = s.names[:n]
+	} else {
+		s.names = make([]LocalSlot, n)
+	}
+	names := s.names
+	for _, name := range f.Names {
+		// Note: not "range f.NamedValues" above, because
+		// that would be nondeterministic.
+		for _, v := range f.NamedValues[name] {
+			names[v.ID] = name
+		}
+	}
+
+	// Allocate args to their assigned locations.
+	for _, v := range f.Entry.Values {
+		if v.Op != OpArg {
+			continue
+		}
+		loc := LocalSlot{v.Aux.(GCNode), v.Type, v.AuxInt}
+		if f.pass.debug > stackDebug {
+			fmt.Printf("stackalloc %s to %s\n", v, loc.Name())
+		}
+		f.setHome(v, loc)
+	}
+
+	// For each type, we keep track of all the stack slots we
+	// have allocated for that type.
+	// TODO: share slots among equivalent types. We would need to
+	// only share among types with the same GC signature. See the
+	// type.Equal calls below for where this matters.
+	locations := map[Type][]LocalSlot{}
+
+	// Each time we assign a stack slot to a value v, we remember
+	// the slot we used via an index into locations[v.Type].
+	slots := s.slots
+	if n := f.NumValues(); cap(slots) >= n {
+		slots = slots[:n]
+	} else {
+		slots = make([]int, n)
+		s.slots = slots
+	}
+	for i := range slots {
+		slots[i] = -1
+	}
+
+	// Pick a stack slot for each value needing one.
+	var used []bool
+	if n := f.NumValues(); cap(s.used) >= n {
+		used = s.used[:n]
+	} else {
+		used = make([]bool, n)
+		s.used = used
+	}
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			if !s.values[v.ID].needSlot {
+				s.nNotNeed++
+				continue
+			}
+			if v.Op == OpArg {
+				s.nArgSlot++
+				continue // already picked
+			}
+
+			// If this is a named value, try to use the name as
+			// the spill location.
+			var name LocalSlot
+			if v.Op == OpStoreReg {
+				name = names[v.Args[0].ID]
+			} else {
+				name = names[v.ID]
+			}
+			if name.N != nil && v.Type.Compare(name.Type) == CMPeq {
+				for _, id := range s.interfere[v.ID] {
+					h := f.getHome(id)
+					if h != nil && h.(LocalSlot).N == name.N && h.(LocalSlot).Off == name.Off {
+						// A variable can interfere with itself.
+						// It is rare, but but it can happen.
+						s.nSelfInterfere++
+						goto noname
+					}
+				}
+				if f.pass.debug > stackDebug {
+					fmt.Printf("stackalloc %s to %s\n", v, name.Name())
+				}
+				s.nNamedSlot++
+				f.setHome(v, name)
+				continue
+			}
+
+		noname:
+			// Set of stack slots we could reuse.
+			locs := locations[v.Type]
+			// Mark all positions in locs used by interfering values.
+			for i := 0; i < len(locs); i++ {
+				used[i] = false
+			}
+			for _, xid := range s.interfere[v.ID] {
+				slot := slots[xid]
+				if slot >= 0 {
+					used[slot] = true
+				}
+			}
+			// Find an unused stack slot.
+			var i int
+			for i = 0; i < len(locs); i++ {
+				if !used[i] {
+					s.nReuse++
+					break
+				}
+			}
+			// If there is no unused stack slot, allocate a new one.
+			if i == len(locs) {
+				s.nAuto++
+				locs = append(locs, LocalSlot{N: f.Config.fe.Auto(v.Type), Type: v.Type, Off: 0})
+				locations[v.Type] = locs
+			}
+			// Use the stack variable at that index for v.
+			loc := locs[i]
+			if f.pass.debug > stackDebug {
+				fmt.Printf("stackalloc %s to %s\n", v, loc.Name())
+			}
+			f.setHome(v, loc)
+			slots[v.ID] = i
+		}
+	}
+}
+
+// computeLive computes a map from block ID to a list of
+// stack-slot-needing value IDs live at the end of that block.
+// TODO: this could be quadratic if lots of variables are live across lots of
+// basic blocks. Figure out a way to make this function (or, more precisely, the user
+// of this function) require only linear size & time.
+func (s *stackAllocState) computeLive(spillLive [][]ID) {
+	s.live = make([][]ID, s.f.NumBlocks())
+	var phis []*Value
+	live := s.f.newSparseSet(s.f.NumValues())
+	defer s.f.retSparseSet(live)
+	t := s.f.newSparseSet(s.f.NumValues())
+	defer s.f.retSparseSet(t)
+
+	// Instead of iterating over f.Blocks, iterate over their postordering.
+	// Liveness information flows backward, so starting at the end
+	// increases the probability that we will stabilize quickly.
+	po := postorder(s.f)
+	for {
+		changed := false
+		for _, b := range po {
+			// Start with known live values at the end of the block
+			live.clear()
+			live.addAll(s.live[b.ID])
+
+			// Propagate backwards to the start of the block
+			phis = phis[:0]
+			for i := len(b.Values) - 1; i >= 0; i-- {
+				v := b.Values[i]
+				live.remove(v.ID)
+				if v.Op == OpPhi {
+					// Save phi for later.
+					// Note: its args might need a stack slot even though
+					// the phi itself doesn't. So don't use needSlot.
+					if !v.Type.IsMemory() && !v.Type.IsVoid() {
+						phis = append(phis, v)
+					}
+					continue
+				}
+				for _, a := range v.Args {
+					if s.values[a.ID].needSlot {
+						live.add(a.ID)
+					}
+				}
+			}
+
+			// for each predecessor of b, expand its list of live-at-end values
+			// invariant: s contains the values live at the start of b (excluding phi inputs)
+			for i, e := range b.Preds {
+				p := e.b
+				t.clear()
+				t.addAll(s.live[p.ID])
+				t.addAll(live.contents())
+				t.addAll(spillLive[p.ID])
+				for _, v := range phis {
+					a := v.Args[i]
+					if s.values[a.ID].needSlot {
+						t.add(a.ID)
+					}
+					if spill := s.values[a.ID].spill; spill != nil {
+						//TODO: remove?  Subsumed by SpillUse?
+						t.add(spill.ID)
+					}
+				}
+				if t.size() == len(s.live[p.ID]) {
+					continue
+				}
+				// grow p's live set
+				s.live[p.ID] = append(s.live[p.ID][:0], t.contents()...)
+				changed = true
+			}
+		}
+
+		if !changed {
+			break
+		}
+	}
+	if s.f.pass.debug > stackDebug {
+		for _, b := range s.f.Blocks {
+			fmt.Printf("stacklive %s %v\n", b, s.live[b.ID])
+		}
+	}
+}
+
+func (f *Func) getHome(vid ID) Location {
+	if int(vid) >= len(f.RegAlloc) {
+		return nil
+	}
+	return f.RegAlloc[vid]
+}
+
+func (f *Func) setHome(v *Value, loc Location) {
+	for v.ID >= ID(len(f.RegAlloc)) {
+		f.RegAlloc = append(f.RegAlloc, nil)
+	}
+	f.RegAlloc[v.ID] = loc
+}
+
+func (s *stackAllocState) buildInterferenceGraph() {
+	f := s.f
+	if n := f.NumValues(); cap(s.interfere) >= n {
+		s.interfere = s.interfere[:n]
+	} else {
+		s.interfere = make([][]ID, n)
+	}
+	live := f.newSparseSet(f.NumValues())
+	defer f.retSparseSet(live)
+	for _, b := range f.Blocks {
+		// Propagate liveness backwards to the start of the block.
+		// Two values interfere if one is defined while the other is live.
+		live.clear()
+		live.addAll(s.live[b.ID])
+		for i := len(b.Values) - 1; i >= 0; i-- {
+			v := b.Values[i]
+			if s.values[v.ID].needSlot {
+				live.remove(v.ID)
+				for _, id := range live.contents() {
+					if s.values[v.ID].typ.Compare(s.values[id].typ) == CMPeq {
+						s.interfere[v.ID] = append(s.interfere[v.ID], id)
+						s.interfere[id] = append(s.interfere[id], v.ID)
+					}
+				}
+			}
+			for _, a := range v.Args {
+				if s.values[a.ID].needSlot {
+					live.add(a.ID)
+				}
+			}
+			if v.Op == OpArg && s.values[v.ID].needSlot {
+				// OpArg is an input argument which is pre-spilled.
+				// We add back v.ID here because we want this value
+				// to appear live even before this point. Being live
+				// all the way to the start of the entry block prevents other
+				// values from being allocated to the same slot and clobbering
+				// the input value before we have a chance to load it.
+				live.add(v.ID)
+			}
+		}
+	}
+	if f.pass.debug > stackDebug {
+		for vid, i := range s.interfere {
+			if len(i) > 0 {
+				fmt.Printf("v%d interferes with", vid)
+				for _, x := range i {
+					fmt.Printf(" v%d", x)
+				}
+				fmt.Println()
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go
new file mode 100644
index 0000000..ecb43c1
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/tighten.go
@@ -0,0 +1,88 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// tighten moves Values closer to the Blocks in which they are used.
+// This can reduce the amount of register spilling required,
+// if it doesn't also create more live values.
+// For now, it handles only the trivial case in which a
+// Value with one or fewer args is only used in a single Block,
+// and not in a phi value.
+// TODO: Do something smarter.
+// A Value can be moved to any block that
+// dominates all blocks in which it is used.
+// Figure out when that will be an improvement.
+func tighten(f *Func) {
+	// For each value, the number of blocks in which it is used.
+	uses := make([]int32, f.NumValues())
+
+	// For each value, whether that value is ever an arg to a phi value.
+	phi := make([]bool, f.NumValues())
+
+	// For each value, one block in which that value is used.
+	home := make([]*Block, f.NumValues())
+
+	changed := true
+	for changed {
+		changed = false
+
+		// Reset uses
+		for i := range uses {
+			uses[i] = 0
+		}
+		// No need to reset home; any relevant values will be written anew anyway.
+		// No need to reset phi; once used in a phi, always used in a phi.
+
+		for _, b := range f.Blocks {
+			for _, v := range b.Values {
+				for _, w := range v.Args {
+					if v.Op == OpPhi {
+						phi[w.ID] = true
+					}
+					uses[w.ID]++
+					home[w.ID] = b
+				}
+			}
+			if b.Control != nil {
+				uses[b.Control.ID]++
+				home[b.Control.ID] = b
+			}
+		}
+
+		for _, b := range f.Blocks {
+			for i := 0; i < len(b.Values); i++ {
+				v := b.Values[i]
+				if v.Op == OpPhi || v.Op == OpGetClosurePtr || v.Op == OpConvert || v.Op == OpArg {
+					// GetClosurePtr & Arg must stay in entry block.
+					// OpConvert must not float over call sites.
+					// TODO do we instead need a dependence edge of some sort for OpConvert?
+					// Would memory do the trick, or do we need something else that relates
+					// to safe point operations?
+					continue
+				}
+				if len(v.Args) > 0 && v.Args[len(v.Args)-1].Type.IsMemory() {
+					// We can't move values which have a memory arg - it might
+					// make two memory values live across a block boundary.
+					continue
+				}
+				if uses[v.ID] == 1 && !phi[v.ID] && home[v.ID] != b && len(v.Args) < 2 {
+					// v is used in exactly one block, and it is not b.
+					// Furthermore, it takes at most one input,
+					// so moving it will not increase the
+					// number of live values anywhere.
+					// Move v to that block.
+					c := home[v.ID]
+					c.Values = append(c.Values, v)
+					v.Block = c
+					last := len(b.Values) - 1
+					b.Values[i] = b.Values[last]
+					b.Values[last] = nil
+					b.Values = b.Values[:last]
+					changed = true
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/ssa/trim.go b/src/cmd/compile/internal/ssa/trim.go
new file mode 100644
index 0000000..8ffb459
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/trim.go
@@ -0,0 +1,32 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// trim removes blocks with no code in them.
+// These blocks were inserted to remove critical edges.
+func trim(f *Func) {
+	n := 0
+	for _, b := range f.Blocks {
+		if b.Kind != BlockPlain || len(b.Values) != 0 || len(b.Preds) != 1 {
+			f.Blocks[n] = b
+			n++
+			continue
+		}
+		// TODO: handle len(b.Preds)>1 case.
+
+		// Splice b out of the graph.
+		p := b.Preds[0].b
+		i := b.Preds[0].i
+		s := b.Succs[0].b
+		j := b.Succs[0].i
+		p.Succs[i] = Edge{s, j}
+		s.Preds[j] = Edge{p, i}
+	}
+	tail := f.Blocks[n:]
+	for i := range tail {
+		tail[i] = nil
+	}
+	f.Blocks = f.Blocks[:n]
+}
diff --git a/src/cmd/compile/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go
new file mode 100644
index 0000000..91a4efe
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/type.go
@@ -0,0 +1,125 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// TODO: use go/types instead?
+
+// A type interface used to import cmd/internal/gc:Type
+// Type instances are not guaranteed to be canonical.
+type Type interface {
+	Size() int64 // return the size in bytes
+	Alignment() int64
+
+	IsBoolean() bool // is a named or unnamed boolean type
+	IsInteger() bool //  ... ditto for the others
+	IsSigned() bool
+	IsFloat() bool
+	IsComplex() bool
+	IsPtrShaped() bool
+	IsString() bool
+	IsSlice() bool
+	IsArray() bool
+	IsStruct() bool
+	IsInterface() bool
+
+	IsMemory() bool // special ssa-package-only types
+	IsFlags() bool
+	IsVoid() bool
+
+	ElemType() Type // given []T or *T or [n]T, return T
+	PtrTo() Type    // given T, return *T
+
+	NumFields() int         // # of fields of a struct
+	FieldType(i int) Type   // type of ith field of the struct
+	FieldOff(i int) int64   // offset of ith field of the struct
+	FieldName(i int) string // name of ith field of the struct
+
+	NumElem() int64 // # of elements of an array
+
+	String() string
+	SimpleString() string // a coarser generic description of T, e.g. T's underlying type
+	Compare(Type) Cmp     // compare types, returning one of CMPlt, CMPeq, CMPgt.
+}
+
+// Special compiler-only types.
+type CompilerType struct {
+	Name   string
+	size   int64
+	Memory bool
+	Flags  bool
+	Void   bool
+	Int128 bool
+}
+
+func (t *CompilerType) Size() int64            { return t.size } // Size in bytes
+func (t *CompilerType) Alignment() int64       { return 0 }
+func (t *CompilerType) IsBoolean() bool        { return false }
+func (t *CompilerType) IsInteger() bool        { return false }
+func (t *CompilerType) IsSigned() bool         { return false }
+func (t *CompilerType) IsFloat() bool          { return false }
+func (t *CompilerType) IsComplex() bool        { return false }
+func (t *CompilerType) IsPtrShaped() bool      { return false }
+func (t *CompilerType) IsString() bool         { return false }
+func (t *CompilerType) IsSlice() bool          { return false }
+func (t *CompilerType) IsArray() bool          { return false }
+func (t *CompilerType) IsStruct() bool         { return false }
+func (t *CompilerType) IsInterface() bool      { return false }
+func (t *CompilerType) IsMemory() bool         { return t.Memory }
+func (t *CompilerType) IsFlags() bool          { return t.Flags }
+func (t *CompilerType) IsVoid() bool           { return t.Void }
+func (t *CompilerType) String() string         { return t.Name }
+func (t *CompilerType) SimpleString() string   { return t.Name }
+func (t *CompilerType) ElemType() Type         { panic("not implemented") }
+func (t *CompilerType) PtrTo() Type            { panic("not implemented") }
+func (t *CompilerType) NumFields() int         { panic("not implemented") }
+func (t *CompilerType) FieldType(i int) Type   { panic("not implemented") }
+func (t *CompilerType) FieldOff(i int) int64   { panic("not implemented") }
+func (t *CompilerType) FieldName(i int) string { panic("not implemented") }
+func (t *CompilerType) NumElem() int64         { panic("not implemented") }
+
+// Cmp is a comparison between values a and b.
+// -1 if a < b
+//  0 if a == b
+//  1 if a > b
+type Cmp int8
+
+const (
+	CMPlt = Cmp(-1)
+	CMPeq = Cmp(0)
+	CMPgt = Cmp(1)
+)
+
+func (t *CompilerType) Compare(u Type) Cmp {
+	x, ok := u.(*CompilerType)
+	// ssa.CompilerType is smaller than any other type
+	if !ok {
+		return CMPlt
+	}
+	if t == x {
+		return CMPeq
+	}
+	// desire fast sorting, not pretty sorting.
+	if len(t.Name) == len(x.Name) {
+		if t.Name == x.Name {
+			return CMPeq
+		}
+		if t.Name < x.Name {
+			return CMPlt
+		}
+		return CMPgt
+	}
+	if len(t.Name) > len(x.Name) {
+		return CMPgt
+	}
+	return CMPlt
+}
+
+var (
+	TypeInvalid = &CompilerType{Name: "invalid"}
+	TypeMem     = &CompilerType{Name: "mem", Memory: true}
+	TypeFlags   = &CompilerType{Name: "flags", Flags: true}
+	TypeVoid    = &CompilerType{Name: "void", Void: true}
+	TypeInt128  = &CompilerType{Name: "int128", size: 16, Int128: true}
+)
diff --git a/src/cmd/compile/internal/ssa/type_test.go b/src/cmd/compile/internal/ssa/type_test.go
new file mode 100644
index 0000000..3b1a892
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/type_test.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 ssa
+
+// Stub implementation used for testing.
+type TypeImpl struct {
+	Size_   int64
+	Align   int64
+	Boolean bool
+	Integer bool
+	Signed  bool
+	Float   bool
+	Complex bool
+	Ptr     bool
+	string  bool
+	slice   bool
+	array   bool
+	struct_ bool
+	inter   bool
+	Elem_   Type
+
+	Name string
+}
+
+func (t *TypeImpl) Size() int64            { return t.Size_ }
+func (t *TypeImpl) Alignment() int64       { return t.Align }
+func (t *TypeImpl) IsBoolean() bool        { return t.Boolean }
+func (t *TypeImpl) IsInteger() bool        { return t.Integer }
+func (t *TypeImpl) IsSigned() bool         { return t.Signed }
+func (t *TypeImpl) IsFloat() bool          { return t.Float }
+func (t *TypeImpl) IsComplex() bool        { return t.Complex }
+func (t *TypeImpl) IsPtrShaped() bool      { return t.Ptr }
+func (t *TypeImpl) IsString() bool         { return t.string }
+func (t *TypeImpl) IsSlice() bool          { return t.slice }
+func (t *TypeImpl) IsArray() bool          { return t.array }
+func (t *TypeImpl) IsStruct() bool         { return t.struct_ }
+func (t *TypeImpl) IsInterface() bool      { return t.inter }
+func (t *TypeImpl) IsMemory() bool         { return false }
+func (t *TypeImpl) IsFlags() bool          { return false }
+func (t *TypeImpl) IsVoid() bool           { return false }
+func (t *TypeImpl) String() string         { return t.Name }
+func (t *TypeImpl) SimpleString() string   { return t.Name }
+func (t *TypeImpl) ElemType() Type         { return t.Elem_ }
+func (t *TypeImpl) PtrTo() Type            { panic("not implemented") }
+func (t *TypeImpl) NumFields() int         { panic("not implemented") }
+func (t *TypeImpl) FieldType(i int) Type   { panic("not implemented") }
+func (t *TypeImpl) FieldOff(i int) int64   { panic("not implemented") }
+func (t *TypeImpl) FieldName(i int) string { panic("not implemented") }
+func (t *TypeImpl) NumElem() int64         { panic("not implemented") }
+
+func (t *TypeImpl) Equal(u Type) bool {
+	x, ok := u.(*TypeImpl)
+	if !ok {
+		return false
+	}
+	return x == t
+}
+
+func (t *TypeImpl) Compare(u Type) Cmp {
+	x, ok := u.(*TypeImpl)
+	// ssa.CompilerType < ssa.TypeImpl < gc.Type
+	if !ok {
+		_, ok := u.(*CompilerType)
+		if ok {
+			return CMPgt
+		}
+		return CMPlt
+	}
+	if t == x {
+		return CMPeq
+	}
+	if t.Name < x.Name {
+		return CMPlt
+	}
+	if t.Name > x.Name {
+		return CMPgt
+	}
+	return CMPeq
+
+}
+
+var (
+	// shortcuts for commonly used basic types
+	TypeInt8       = &TypeImpl{Size_: 1, Align: 1, Integer: true, Signed: true, Name: "int8"}
+	TypeInt16      = &TypeImpl{Size_: 2, Align: 2, Integer: true, Signed: true, Name: "int16"}
+	TypeInt32      = &TypeImpl{Size_: 4, Align: 4, Integer: true, Signed: true, Name: "int32"}
+	TypeInt64      = &TypeImpl{Size_: 8, Align: 8, Integer: true, Signed: true, Name: "int64"}
+	TypeFloat32    = &TypeImpl{Size_: 4, Align: 4, Float: true, Name: "float32"}
+	TypeFloat64    = &TypeImpl{Size_: 8, Align: 8, Float: true, Name: "float64"}
+	TypeComplex64  = &TypeImpl{Size_: 8, Align: 4, Complex: true, Name: "complex64"}
+	TypeComplex128 = &TypeImpl{Size_: 16, Align: 8, Complex: true, Name: "complex128"}
+	TypeUInt8      = &TypeImpl{Size_: 1, Align: 1, Integer: true, Name: "uint8"}
+	TypeUInt16     = &TypeImpl{Size_: 2, Align: 2, Integer: true, Name: "uint16"}
+	TypeUInt32     = &TypeImpl{Size_: 4, Align: 4, Integer: true, Name: "uint32"}
+	TypeUInt64     = &TypeImpl{Size_: 8, Align: 8, Integer: true, Name: "uint64"}
+	TypeBool       = &TypeImpl{Size_: 1, Align: 1, Boolean: true, Name: "bool"}
+	TypeBytePtr    = &TypeImpl{Size_: 8, Align: 8, Ptr: true, Name: "*byte"}
+	TypeInt64Ptr   = &TypeImpl{Size_: 8, Align: 8, Ptr: true, Name: "*int64"}
+)
diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
new file mode 100644
index 0000000..867221b
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -0,0 +1,270 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import (
+	"fmt"
+	"math"
+)
+
+// A Value represents a value in the SSA representation of the program.
+// The ID and Type fields must not be modified. The remainder may be modified
+// if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)).
+type Value struct {
+	// A unique identifier for the value. For performance we allocate these IDs
+	// densely starting at 1.  There is no guarantee that there won't be occasional holes, though.
+	ID ID
+
+	// The operation that computes this value. See op.go.
+	Op Op
+
+	// The type of this value. Normally this will be a Go type, but there
+	// are a few other pseudo-types, see type.go.
+	Type Type
+
+	// Auxiliary info for this value. The type of this information depends on the opcode and type.
+	// AuxInt is used for integer values, Aux is used for other values.
+	AuxInt int64
+	Aux    interface{}
+
+	// Arguments of this value
+	Args []*Value
+
+	// Containing basic block
+	Block *Block
+
+	// Source line number
+	Line int32
+
+	// Use count. Each appearance in Value.Args and Block.Control counts once.
+	Uses int32
+
+	// Storage for the first three args
+	argstorage [3]*Value
+}
+
+// Examples:
+// Opcode          aux   args
+//  OpAdd          nil      2
+//  OpConst     string      0    string constant
+//  OpConst      int64      0    int64 constant
+//  OpAddcq      int64      1    amd64 op: v = arg[0] + constant
+
+// short form print. Just v#.
+func (v *Value) String() string {
+	if v == nil {
+		return "nil" // should never happen, but not panicking helps with debugging
+	}
+	return fmt.Sprintf("v%d", v.ID)
+}
+
+func (v *Value) AuxInt8() int8 {
+	if opcodeTable[v.Op].auxType != auxInt8 {
+		v.Fatalf("op %s doesn't have an int8 aux field", v.Op)
+	}
+	return int8(v.AuxInt)
+}
+
+func (v *Value) AuxInt16() int16 {
+	if opcodeTable[v.Op].auxType != auxInt16 {
+		v.Fatalf("op %s doesn't have an int16 aux field", v.Op)
+	}
+	return int16(v.AuxInt)
+}
+
+func (v *Value) AuxInt32() int32 {
+	if opcodeTable[v.Op].auxType != auxInt32 {
+		v.Fatalf("op %s doesn't have an int32 aux field", v.Op)
+	}
+	return int32(v.AuxInt)
+}
+
+func (v *Value) AuxFloat() float64 {
+	if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 {
+		v.Fatalf("op %s doesn't have a float aux field", v.Op)
+	}
+	return math.Float64frombits(uint64(v.AuxInt))
+}
+func (v *Value) AuxValAndOff() ValAndOff {
+	if opcodeTable[v.Op].auxType != auxSymValAndOff {
+		v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
+	}
+	return ValAndOff(v.AuxInt)
+}
+
+// long form print.  v# = opcode <type> [aux] args [: reg]
+func (v *Value) LongString() string {
+	s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String())
+	s += " <" + v.Type.String() + ">"
+	s += v.auxString()
+	for _, a := range v.Args {
+		s += fmt.Sprintf(" %v", a)
+	}
+	r := v.Block.Func.RegAlloc
+	if int(v.ID) < len(r) && r[v.ID] != nil {
+		s += " : " + r[v.ID].Name()
+	}
+	return s
+}
+
+func (v *Value) auxString() string {
+	switch opcodeTable[v.Op].auxType {
+	case auxBool:
+		if v.AuxInt == 0 {
+			return " [false]"
+		} else {
+			return " [true]"
+		}
+	case auxInt8:
+		return fmt.Sprintf(" [%d]", v.AuxInt8())
+	case auxInt16:
+		return fmt.Sprintf(" [%d]", v.AuxInt16())
+	case auxInt32:
+		return fmt.Sprintf(" [%d]", v.AuxInt32())
+	case auxInt64, auxInt128:
+		return fmt.Sprintf(" [%d]", v.AuxInt)
+	case auxFloat32, auxFloat64:
+		return fmt.Sprintf(" [%g]", v.AuxFloat())
+	case auxString:
+		return fmt.Sprintf(" {%q}", v.Aux)
+	case auxSym:
+		if v.Aux != nil {
+			return fmt.Sprintf(" {%s}", v.Aux)
+		}
+	case auxSymOff, auxSymInt32:
+		s := ""
+		if v.Aux != nil {
+			s = fmt.Sprintf(" {%s}", v.Aux)
+		}
+		if v.AuxInt != 0 {
+			s += fmt.Sprintf(" [%v]", v.AuxInt)
+		}
+		return s
+	case auxSymValAndOff:
+		s := ""
+		if v.Aux != nil {
+			s = fmt.Sprintf(" {%s}", v.Aux)
+		}
+		return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
+	}
+	return ""
+}
+
+func (v *Value) AddArg(w *Value) {
+	if v.Args == nil {
+		v.resetArgs() // use argstorage
+	}
+	v.Args = append(v.Args, w)
+	w.Uses++
+}
+func (v *Value) AddArgs(a ...*Value) {
+	if v.Args == nil {
+		v.resetArgs() // use argstorage
+	}
+	v.Args = append(v.Args, a...)
+	for _, x := range a {
+		x.Uses++
+	}
+}
+func (v *Value) SetArg(i int, w *Value) {
+	v.Args[i].Uses--
+	v.Args[i] = w
+	w.Uses++
+}
+func (v *Value) RemoveArg(i int) {
+	v.Args[i].Uses--
+	copy(v.Args[i:], v.Args[i+1:])
+	v.Args[len(v.Args)-1] = nil // aid GC
+	v.Args = v.Args[:len(v.Args)-1]
+}
+func (v *Value) SetArgs1(a *Value) {
+	v.resetArgs()
+	v.AddArg(a)
+}
+func (v *Value) SetArgs2(a *Value, b *Value) {
+	v.resetArgs()
+	v.AddArg(a)
+	v.AddArg(b)
+}
+
+func (v *Value) resetArgs() {
+	for _, a := range v.Args {
+		a.Uses--
+	}
+	v.argstorage[0] = nil
+	v.argstorage[1] = nil
+	v.argstorage[2] = nil
+	v.Args = v.argstorage[:0]
+}
+
+func (v *Value) reset(op Op) {
+	v.Op = op
+	v.resetArgs()
+	v.AuxInt = 0
+	v.Aux = nil
+}
+
+// copyInto makes a new value identical to v and adds it to the end of b.
+func (v *Value) copyInto(b *Block) *Value {
+	c := b.NewValue0(v.Line, v.Op, v.Type)
+	c.Aux = v.Aux
+	c.AuxInt = v.AuxInt
+	c.AddArgs(v.Args...)
+	for _, a := range v.Args {
+		if a.Type.IsMemory() {
+			v.Fatalf("can't move a value with a memory arg %s", v.LongString())
+		}
+	}
+	return c
+}
+
+func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) }
+func (v *Value) Log() bool                            { return v.Block.Log() }
+func (v *Value) Fatalf(msg string, args ...interface{}) {
+	v.Block.Func.Config.Fatalf(v.Line, msg, args...)
+}
+func (v *Value) Unimplementedf(msg string, args ...interface{}) {
+	v.Block.Func.Config.Unimplementedf(v.Line, msg, args...)
+}
+
+// isGenericIntConst returns whether v is a generic integer constant.
+func (v *Value) isGenericIntConst() bool {
+	return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8)
+}
+
+// ExternSymbol is an aux value that encodes a variable's
+// constant offset from the static base pointer.
+type ExternSymbol struct {
+	Typ Type         // Go type
+	Sym fmt.Stringer // A *gc.Sym referring to a global variable
+	// Note: the offset for an external symbol is not
+	// calculated until link time.
+}
+
+// ArgSymbol is an aux value that encodes an argument or result
+// variable's constant offset from FP (FP = SP + framesize).
+type ArgSymbol struct {
+	Typ  Type   // Go type
+	Node GCNode // A *gc.Node referring to the argument/result variable.
+}
+
+// AutoSymbol is an aux value that encodes a local variable's
+// constant offset from SP.
+type AutoSymbol struct {
+	Typ  Type   // Go type
+	Node GCNode // A *gc.Node referring to a local (auto) variable.
+}
+
+func (s *ExternSymbol) String() string {
+	return s.Sym.String()
+}
+
+func (s *ArgSymbol) String() string {
+	return s.Node.String()
+}
+
+func (s *AutoSymbol) String() string {
+	return s.Node.String()
+}
diff --git a/src/cmd/compile/internal/ssa/zcse.go b/src/cmd/compile/internal/ssa/zcse.go
new file mode 100644
index 0000000..16d5c10
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/zcse.go
@@ -0,0 +1,82 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// zcse does an initial pass of common-subexpression elimination on the
+// function for values with zero arguments to allow the more expensive cse
+// to begin with a reduced number of values. Values are just relinked,
+// nothing is deleted. A subsequent deadcode pass is required to actually
+// remove duplicate expressions.
+func zcse(f *Func) {
+	vals := make(map[vkey]*Value)
+
+	for _, b := range f.Blocks {
+		for i := 0; i < len(b.Values); {
+			v := b.Values[i]
+			next := true
+			if opcodeTable[v.Op].argLen == 0 {
+				key := vkey{v.Op, keyFor(v), v.Aux, v.Type}
+				if vals[key] == nil {
+					vals[key] = v
+					if b != f.Entry {
+						// Move v to the entry block so it will dominate every block
+						// where we might use it. This prevents the need for any dominator
+						// calculations in this pass.
+						v.Block = f.Entry
+						f.Entry.Values = append(f.Entry.Values, v)
+						last := len(b.Values) - 1
+						b.Values[i] = b.Values[last]
+						b.Values[last] = nil
+						b.Values = b.Values[:last]
+
+						// process b.Values[i] again
+						next = false
+					}
+				}
+			}
+			if next {
+				i++
+			}
+		}
+	}
+
+	for _, b := range f.Blocks {
+		for _, v := range b.Values {
+			for i, a := range v.Args {
+				if opcodeTable[a.Op].argLen == 0 {
+					key := vkey{a.Op, keyFor(a), a.Aux, a.Type}
+					if rv, ok := vals[key]; ok {
+						v.SetArg(i, rv)
+					}
+				}
+			}
+		}
+	}
+}
+
+// vkey is a type used to uniquely identify a zero arg value.
+type vkey struct {
+	op Op
+	ai int64       // aux int
+	ax interface{} // aux
+	t  Type        // type
+}
+
+// keyFor returns the AuxInt portion of a  key structure uniquely identifying a
+// zero arg value for the supported ops.
+func keyFor(v *Value) int64 {
+	switch v.Op {
+	case OpConst64, OpConst64F, OpConst32F:
+		return v.AuxInt
+	case OpConst32:
+		return int64(int32(v.AuxInt))
+	case OpConst16:
+		return int64(int16(v.AuxInt))
+	case OpConst8, OpConstBool:
+		return int64(int8(v.AuxInt))
+	default:
+		return v.AuxInt
+	}
+}
diff --git a/src/cmd/compile/internal/test/README b/src/cmd/compile/internal/test/README
new file mode 100644
index 0000000..242ff79
--- /dev/null
+++ b/src/cmd/compile/internal/test/README
@@ -0,0 +1,4 @@
+This directory holds small tests and benchmarks of code
+generated by the compiler.  This code is not for importing,
+and the tests are intended to verify that specific optimzations
+are applied and correct.
diff --git a/src/cmd/compile/internal/test/divconst_test.go b/src/cmd/compile/internal/test/divconst_test.go
new file mode 100644
index 0000000..f585a5b
--- /dev/null
+++ b/src/cmd/compile/internal/test/divconst_test.go
@@ -0,0 +1,73 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package test
+
+import (
+	"testing"
+)
+
+var i64res int64
+
+func BenchmarkDivconstI64(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		i64res = int64(i) / 7
+	}
+}
+
+var u64res uint64
+
+func BenchmarkDivconstU64(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		u64res = uint64(i) / 7
+	}
+}
+
+var i32res int32
+
+func BenchmarkDivconstI32(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		i32res = int32(i) / 7
+	}
+}
+
+var u32res uint32
+
+func BenchmarkDivconstU32(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		u32res = uint32(i) / 7
+	}
+}
+
+var i16res int16
+
+func BenchmarkDivconstI16(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		i16res = int16(i) / 7
+	}
+}
+
+var u16res uint16
+
+func BenchmarkDivconstU16(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		u16res = uint16(i) / 7
+	}
+}
+
+var i8res int8
+
+func BenchmarkDivconstI8(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		i8res = int8(i) / 7
+	}
+}
+
+var u8res uint8
+
+func BenchmarkDivconstU8(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		u8res = uint8(i) / 7
+	}
+}
diff --git a/src/cmd/compile/internal/test/test.go b/src/cmd/compile/internal/test/test.go
new file mode 100644
index 0000000..56e5404
--- /dev/null
+++ b/src/cmd/compile/internal/test/test.go
@@ -0,0 +1 @@
+package test
diff --git a/src/cmd/compile/internal/x86/cgen.go b/src/cmd/compile/internal/x86/cgen.go
index 1768674..90a773d 100644
--- a/src/cmd/compile/internal/x86/cgen.go
+++ b/src/cmd/compile/internal/x86/cgen.go
@@ -85,7 +85,7 @@ func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
 
 	// 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 {
+	if osrc < odst && odst < osrc+w {
 		// reverse direction
 		gins(x86.ASTD, nil, nil) // set direction flag
 		if c > 0 {
diff --git a/src/cmd/compile/internal/x86/cgen64.go b/src/cmd/compile/internal/x86/cgen64.go
index 7e40a32..ea52d69 100644
--- a/src/cmd/compile/internal/x86/cgen64.go
+++ b/src/cmd/compile/internal/x86/cgen64.go
@@ -19,12 +19,12 @@ 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.Fatalf("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0))
+		gc.Fatalf("cgen64 %v of %v", n.Op, res.Op)
 	}
 
 	switch n.Op {
 	default:
-		gc.Fatalf("cgen64 %v", gc.Oconv(int(n.Op), 0))
+		gc.Fatalf("cgen64 %v", n.Op)
 
 	case gc.OMINUS:
 		gc.Cgen(n.Left, res)
@@ -95,7 +95,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 		split64(r, &lo2, &hi2)
 	}
 
-	// Do op.  Leave result in DX:AX.
+	// Do op. Leave result in DX:AX.
 	switch n.Op {
 	// TODO: Constants
 	case gc.OADD:
@@ -162,7 +162,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 	//	shld hi:lo, c
 	//	shld lo:t, c
 	case gc.OLROT:
-		v := uint64(r.Int())
+		v := uint64(r.Int64())
 
 		if v >= 32 {
 			// reverse during load to do the first 32 bits of rotate
@@ -189,7 +189,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 
 	case gc.OLSH:
 		if r.Op == gc.OLITERAL {
-			v := uint64(r.Int())
+			v := uint64(r.Int64())
 			if v >= 64 {
 				if gc.Is64(r.Type) {
 					splitclean()
@@ -278,7 +278,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
 
 	case gc.ORSH:
 		if r.Op == gc.OLITERAL {
-			v := uint64(r.Int())
+			v := uint64(r.Int64())
 			if v >= 64 {
 				if gc.Is64(r.Type) {
 					splitclean()
@@ -400,8 +400,8 @@ func cgen64(n *gc.Node, res *gc.Node) {
 
 		if lo2.Op == gc.OLITERAL {
 			// special cases for constants.
-			lv := uint32(lo2.Int())
-			hv := uint32(hi2.Int())
+			lv := uint32(lo2.Int64())
+			hv := uint32(hi2.Int64())
 			splitclean() // right side
 			split64(res, &lo2, &hi2)
 			switch n.Op {
@@ -531,7 +531,7 @@ func cmp64(nl *gc.Node, nr *gc.Node, op gc.Op, likely int, to *obj.Prog) {
 	var br *obj.Prog
 	switch op {
 	default:
-		gc.Fatalf("cmp64 %v %v", gc.Oconv(int(op), 0), t)
+		gc.Fatalf("cmp64 %v %v", op, t)
 
 		// cmp hi
 	// jne L
diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go
index 2535e3e..738d887 100644
--- a/src/cmd/compile/internal/x86/galign.go
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -12,38 +12,11 @@ import (
 	"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{
-	{"int", gc.TINT, gc.TINT32},
-	{"uint", gc.TUINT, gc.TUINT32},
-	{"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.LinkArch = &x86.Link386
 	gc.Thearch.REGSP = x86.REGSP
 	gc.Thearch.REGCTXT = x86.REGCTXT
 	gc.Thearch.REGCALLX = x86.REG_BX
@@ -63,7 +36,7 @@ func Main() {
 		fmt.Fprintf(os.Stderr, "unsupported setting GO386=%s\n", v)
 		gc.Exit(1)
 	}
-	gc.Thearch.MAXWIDTH = MAXWIDTH
+	gc.Thearch.MAXWIDTH = (1 << 32) - 1
 	gc.Thearch.ReservedRegs = resvd
 
 	gc.Thearch.Betypeinit = betypeinit
@@ -86,7 +59,6 @@ func Main() {
 	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
diff --git a/src/cmd/compile/internal/x86/ggen.go b/src/cmd/compile/internal/x86/ggen.go
index 139b199..21d989c 100644
--- a/src/cmd/compile/internal/x86/ggen.go
+++ b/src/cmd/compile/internal/x86/ggen.go
@@ -11,12 +11,10 @@ import (
 )
 
 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)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.ArgWidth(), int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 	ptxt.To.Offset = int64(frame)
 
@@ -28,8 +26,7 @@ func defframe(ptxt *obj.Prog) {
 	hi := int64(0)
 	lo := hi
 	ax := uint32(0)
-	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
-		n = l.N
+	for _, n := range gc.Curfn.Func.Dcl {
 		if !n.Name.Needzero {
 			continue
 		}
@@ -37,7 +34,7 @@ func defframe(ptxt *obj.Prog) {
 			gc.Fatalf("needzero class %d", n.Class)
 		}
 		if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
-			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
+			gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.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
@@ -87,15 +84,15 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Pr
 	return p
 }
 
-func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
+func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
 	q := gc.Ctxt.NewProg()
 	gc.Clearp(q)
-	q.As = int16(as)
+	q.As = as
 	q.Lineno = p.Lineno
-	q.From.Type = int16(ftype)
+	q.From.Type = ftype
 	q.From.Reg = int16(freg)
 	q.From.Offset = foffset
-	q.To.Type = int16(ttype)
+	q.To.Type = ttype
 	q.To.Reg = int16(treg)
 	q.To.Offset = toffset
 	q.Link = p.Link
@@ -204,17 +201,17 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node, ax *gc.Node, dx *gc
 
 	t0 := t
 	check := false
-	if gc.Issigned[t.Etype] {
+	if t.IsSigned() {
 		check = true
-		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -1<<uint64(t.Width*8-1) {
+		if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -1<<uint64(t.Width*8-1) {
 			check = false
-		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
 			check = false
 		}
 	}
 
 	if t.Width < 4 {
-		if gc.Issigned[t.Etype] {
+		if t.IsSigned() {
 			t = gc.Types[gc.TINT32]
 		} else {
 			t = gc.Types[gc.TUINT32]
@@ -288,7 +285,7 @@ func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node, ax *gc.Node, dx *gc
 		gc.Patch(p1, gc.Pc)
 	}
 
-	if !gc.Issigned[t.Etype] {
+	if !t.IsSigned() {
 		var nz gc.Node
 		gc.Nodconst(&nz, t, 0)
 		gmove(&nz, dx)
@@ -344,7 +341,7 @@ func cgen_div(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
 	}
 
 	var t *gc.Type
-	if gc.Issigned[nl.Type.Etype] {
+	if nl.Type.IsSigned() {
 		t = gc.Types[gc.TINT32]
 	} else {
 		t = gc.Types[gc.TUINT32]
@@ -381,7 +378,7 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 		var n1 gc.Node
 		gc.Regalloc(&n1, nl.Type, res)
 		gmove(&n2, &n1)
-		sc := uint64(nr.Int())
+		sc := uint64(nr.Int64())
 		if sc >= uint64(nl.Type.Width*8) {
 			// large shift gets 2 shifts by width-1
 			gins(a, ncon(uint32(w)-1), &n1)
@@ -462,7 +459,7 @@ func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node)
 			p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
 		}
 
-		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
+		if op == gc.ORSH && nl.Type.IsSigned() {
 			gins(a, ncon(uint32(w)-1), &n2)
 		} else {
 			gmove(ncon(0), &n2)
@@ -497,7 +494,7 @@ func cgen_bmul(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) bool {
 	// copy from byte to full registers
 	t := gc.Types[gc.TUINT32]
 
-	if gc.Issigned[nl.Type.Etype] {
+	if nl.Type.IsSigned() {
 		t = gc.Types[gc.TINT32]
 	}
 
@@ -657,20 +654,19 @@ func cgen_float387(n *gc.Node, res *gc.Node) {
 }
 
 func cgen_floatsse(n *gc.Node, res *gc.Node) {
-	var a int
+	var a obj.As
 
 	nl := n.Left
 	nr := n.Right
 	switch n.Op {
 	default:
 		gc.Dump("cgen_floatsse", n)
-		gc.Fatalf("cgen_floatsse %v", gc.Oconv(int(n.Op), 0))
+		gc.Fatalf("cgen_floatsse %v", n.Op)
 		return
 
 	case gc.OMINUS,
 		gc.OCOM:
-		nr = gc.Nodintconst(-1)
-		gc.Convlit(&nr, n.Type)
+		nr = gc.NegOne(n.Type)
 		a = foptoas(gc.OMUL, nl.Type, 0)
 		goto sbop
 
@@ -846,7 +842,7 @@ func expandchecks(firstp *obj.Prog) {
 			continue
 		}
 		if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
-			gc.Warnl(int(p.Lineno), "generated nil check")
+			gc.Warnl(p.Lineno, "generated nil check")
 		}
 
 		// check is
diff --git a/src/cmd/compile/internal/x86/gsubr.go b/src/cmd/compile/internal/x86/gsubr.go
index 9859571..6406326 100644
--- a/src/cmd/compile/internal/x86/gsubr.go
+++ b/src/cmd/compile/internal/x86/gsubr.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -53,7 +53,7 @@ const (
 /*
  * return Axxx for Oxxx on type t.
  */
-func optoas(op gc.Op, t *gc.Type) int {
+func optoas(op gc.Op, t *gc.Type) obj.As {
 	if t == nil {
 		gc.Fatalf("optoas: t is nil")
 	}
@@ -91,7 +91,7 @@ func optoas(op gc.Op, t *gc.Type) int {
 	a := obj.AXXX
 	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
 	default:
-		gc.Fatalf("optoas: no entry %v-%v", gc.Oconv(int(op), 0), t)
+		gc.Fatalf("optoas: no entry %v-%v", op, t)
 
 	case OADDR_ | gc.TPTR32:
 		a = x86.ALEAL
@@ -436,7 +436,7 @@ func optoas(op gc.Op, t *gc.Type) int {
 	return a
 }
 
-func foptoas(op gc.Op, t *gc.Type, flg int) int {
+func foptoas(op gc.Op, t *gc.Type, flg int) obj.As {
 	a := obj.AXXX
 	et := gc.Simtype[t.Etype]
 
@@ -454,7 +454,7 @@ func foptoas(op gc.Op, t *gc.Type, flg int) int {
 	if !gc.Thearch.Use387 {
 		switch uint32(op)<<16 | uint32(et) {
 		default:
-			gc.Fatalf("foptoas-sse: no entry %v-%v", gc.Oconv(int(op), 0), t)
+			gc.Fatalf("foptoas-sse: no entry %v-%v", op, t)
 
 		case OCMP_ | gc.TFLOAT32:
 			a = x86.AUCOMISS
@@ -587,7 +587,7 @@ func foptoas(op gc.Op, t *gc.Type, flg int) int {
 		return x86.AFCHS
 	}
 
-	gc.Fatalf("foptoas %v %v %#x", gc.Oconv(int(op), 0), t, flg)
+	gc.Fatalf("foptoas %v %v %#x", op, t, flg)
 	return 0
 }
 
@@ -605,7 +605,7 @@ var resvd = []int{
  * generate
  *	as $c, reg
  */
-func gconreg(as int, c int64, reg int) {
+func gconreg(as obj.As, c int64, reg int) {
 	var n1 gc.Node
 	var n2 gc.Node
 
@@ -618,14 +618,14 @@ func gconreg(as int, c int64, reg int) {
  * generate
  *	as $c, n
  */
-func ginscon(as int, c int64, n2 *gc.Node) {
+func ginscon(as obj.As, c int64, n2 *gc.Node) {
 	var n1 gc.Node
 	gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
 	gins(as, &n1, n2)
 }
 
 func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
-	if gc.Isint[t.Etype] || t.Etype == gc.Tptr {
+	if t.IsInteger() || 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)
@@ -639,11 +639,11 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 	// A special case to make write barriers more efficient.
 	// Comparing the first field of a named struct can be done directly.
 	base := n1
-	if n1.Op == gc.ODOT && n1.Left.Type.Etype == gc.TSTRUCT && n1.Left.Type.Type.Sym == n1.Right.Sym {
+	if n1.Op == gc.ODOT && n1.Left.Type.IsStruct() && n1.Left.Type.Field(0).Sym == n1.Sym {
 		base = n1.Left
 	}
 
-	if base.Op == gc.ONAME && base.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
+	if base.Op == gc.ONAME && base.Class != gc.PAUTOHEAP || n1.Op == gc.OINDREG {
 		r1 = *n1
 	} else {
 		gc.Regalloc(&r1, t, n1)
@@ -651,7 +651,7 @@ func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
 		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 {
+	if n2.Op == gc.OLITERAL && t.IsInteger() || n2.Op == gc.OADDR && n2.Left.Op == gc.ONAME && n2.Left.Class == gc.PEXTERN {
 		r2 = *n2
 	} else {
 		gc.Regalloc(&r2, t, n2)
@@ -724,17 +724,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 
 			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
-			}
-
+		case gc.ONAME, gc.OINDREG:
 			// nothing
-		case gc.OINDREG:
-			break
 		}
 
 		*lo = *n
@@ -750,7 +741,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
 	case gc.OLITERAL:
 		var n1 gc.Node
 		n.Convconst(&n1, n.Type)
-		i := n1.Int()
+		i := n1.Int64()
 		gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
 		i >>= 32
 		if n.Type.Etype == gc.TINT64 {
@@ -831,7 +822,7 @@ func gmove(f *gc.Node, t *gc.Node) {
 	// cannot have two integer memory operands;
 	// except 64-bit, which always copies via registers anyway.
 	var r1 gc.Node
-	var a int
+	var a obj.As
 	if gc.Isint[ft] && gc.Isint[tt] && !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
 	}
@@ -1360,7 +1351,7 @@ hardmem:
 
 func floatmove_387(f *gc.Node, t *gc.Node) {
 	var r1 gc.Node
-	var a int
+	var a obj.As
 
 	ft := gc.Simsimtype(f.Type)
 	tt := gc.Simsimtype(t.Type)
@@ -1511,7 +1502,7 @@ func floatmove_387(f *gc.Node, t *gc.Node) {
 		// 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.
+	// 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.
 	/*
@@ -1603,7 +1594,7 @@ hardmem:
 
 	// should not happen
 fatal:
-	gc.Fatalf("gmove %v -> %v", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong))
+	gc.Fatalf("gmove %v -> %v", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
 
 	return
 }
@@ -1611,7 +1602,7 @@ fatal:
 func floatmove_sse(f *gc.Node, t *gc.Node) {
 	var r1 gc.Node
 	var cvt *gc.Type
-	var a int
+	var a obj.As
 
 	ft := gc.Simsimtype(f.Type)
 	tt := gc.Simsimtype(t.Type)
@@ -1753,7 +1744,7 @@ func samaddr(f *gc.Node, t *gc.Node) bool {
  * generate one instruction:
  *	as f, t
  */
-func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+func gins(as obj.As, 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.Fatalf("gins MOVF reg, reg")
 	}
@@ -1847,7 +1838,7 @@ func dotaddable(n *gc.Node, n1 *gc.Node) bool {
 func sudoclean() {
 }
 
-func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
+func sudoaddable(as obj.As, 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
index 63e64cb..e70c10f 100644
--- a/src/cmd/compile/internal/x86/peep.go
+++ b/src/cmd/compile/internal/x86/peep.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -221,7 +221,7 @@ 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
+	// 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
@@ -249,6 +249,10 @@ func excise(r *gc.Flow) {
 }
 
 func regtyp(a *obj.Addr) bool {
+	if gc.Ctxt.Flag_shared && a.Type == obj.TYPE_REG && a.Reg == x86.REG_CX {
+		// don't propagate CX, it is used implicitly by PIC global references
+		return false
+	}
 	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)
 }
 
@@ -284,7 +288,7 @@ func elimshortmov(g *gc.Graph) {
 			}
 
 			if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
-				// move or artihmetic into partial register.
+				// move or arithmetic 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).
@@ -387,7 +391,7 @@ func subprop(r0 *gc.Flow) bool {
 		}
 
 		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)
+			copysub(&p.To, v1, v2, true)
 			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 {
@@ -398,8 +402,8 @@ func subprop(r0 *gc.Flow) bool {
 
 			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)
+				copysub(&p.From, v1, v2, true)
+				copysub(&p.To, v1, v2, true)
 				if gc.Debug['P'] != 0 {
 					fmt.Printf("%v\n", r.Prog)
 				}
@@ -417,7 +421,7 @@ func subprop(r0 *gc.Flow) bool {
 		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 {
+		if copysub(&p.From, v1, v2, false) || copysub(&p.To, v1, v2, false) {
 			break
 		}
 	}
@@ -445,10 +449,10 @@ func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
 		return true
 	}
 	gactive++
-	return copy1(v1, v2, r0.S1, 0)
+	return copy1(v1, v2, r0.S1, false)
 }
 
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
 	if uint32(r.Active) == gactive {
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("act set; return 1\n")
@@ -458,24 +462,21 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 	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)
+		fmt.Printf("copy %v->%v f=%v\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
+		p := r.Prog
 		if gc.Debug['P'] != 0 {
 			fmt.Printf("%v", p)
 		}
-		if f == 0 && gc.Uniqp(r) == nil {
-			f = 1
+		if !f && gc.Uniqp(r) == nil {
+			f = true
 			if gc.Debug['P'] != 0 {
-				fmt.Printf("; merge; f=%d", f)
+				fmt.Printf("; merge; f=%v", f)
 			}
 		}
 
-		t = copyu(p, v2, nil)
-		switch t {
+		switch t := copyu(p, v2, nil); t {
 		case 2: /* rar, can't split */
 			if gc.Debug['P'] != 0 {
 				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
@@ -490,14 +491,14 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 
 		case 1, /* used, substitute */
 			4: /* use and set */
-			if f != 0 {
+			if f {
 				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)
+					fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				} else {
-					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+					fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
 				}
 				return false
 			}
@@ -520,12 +521,12 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 
-		if f == 0 {
-			t = copyu(p, v1, nil)
-			if f == 0 && (t == 2 || t == 3 || t == 4) {
-				f = 1
+		if !f {
+			t := copyu(p, v1, nil)
+			if t == 2 || t == 3 || t == 4 {
+				f = true
 				if gc.Debug['P'] != 0 {
-					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+					fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
 				}
 			}
 		}
@@ -539,7 +540,6 @@ func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
 			}
 		}
 	}
-
 	return true
 }
 
@@ -555,7 +555,7 @@ 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 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -584,7 +584,7 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 		}
 
 		if s != nil {
-			if copysub(&p.To, v, s, 1) != 0 {
+			if copysub(&p.To, v, s, true) {
 				return 1
 			}
 			return 0
@@ -625,7 +625,10 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 	if p.Info.Flags&gc.RightWrite != 0 {
 		if copyas(&p.To, v) {
 			if s != nil {
-				return copysub(&p.From, v, s, 1)
+				if copysub(&p.From, v, s, true) {
+					return 1
+				}
+				return 0
 			}
 			if copyau(&p.From, v) {
 				return 4
@@ -636,12 +639,14 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 
 	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 {
+			if copysub(&p.From, v, s, true) {
 				return 1
 			}
-			return copysub(&p.To, v, s, 1)
+			if copysub(&p.To, v, s, true) {
+				return 1
+			}
+			return 0
 		}
-
 		if copyau(&p.From, v) {
 			return 1
 		}
@@ -649,7 +654,6 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 			return 1
 		}
 	}
-
 	return 0
 }
 
@@ -714,50 +718,40 @@ func copyau(a *obj.Addr, v *obj.Addr) bool {
 	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 {
+// copysub substitute s for v in a.
+// copysub returns true on failure to substitute.
+// TODO(dfc) reverse this logic to return false on sunstitution failure.
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
 	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)
+		if s.Reg >= x86.REG_AX && s.Reg <= x86.REG_DI || s.Reg >= x86.REG_X0 && s.Reg <= x86.REG_X7 {
+			if f {
+				a.Reg = s.Reg
 			}
 		}
-
-		return 0
+		return false
 	}
 
 	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 (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == v.Reg {
+			if (s.Reg == x86.REG_BP) && a.Index != x86.REG_NONE {
+				return true /* can't use BP-base with index */
 			}
-			if f != 0 {
+			if f {
 				a.Reg = s.Reg
 			}
 		}
 
-		//			return 0;
-		if int(a.Index) == reg {
-			if f != 0 {
+		if a.Index == v.Reg {
+			if f {
 				a.Index = s.Reg
 			}
-			return 0
 		}
-
-		return 0
 	}
-
-	return 0
+	return false
 }
 
 func conprop(r0 *gc.Flow) {
 	var p *obj.Prog
-	var t int
 
 	p0 := r0.Prog
 	v0 := &p0.To
@@ -773,8 +767,7 @@ loop:
 	}
 
 	p = r.Prog
-	t = copyu(p, v0, nil)
-	switch t {
+	switch copyu(p, v0, nil) {
 	case 0, // miss
 		1: // use
 		goto loop
diff --git a/src/cmd/compile/internal/x86/prog.go b/src/cmd/compile/internal/x86/prog.go
index ccac290..f2b4a65 100644
--- a/src/cmd/compile/internal/x86/prog.go
+++ b/src/cmd/compile/internal/x86/prog.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -30,7 +30,7 @@ var (
 // 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{
+var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
 	obj.ATYPE:     {Flags: gc.Pseudo | gc.Skip},
 	obj.ATEXT:     {Flags: gc.Pseudo},
 	obj.AFUNCDATA: {Flags: gc.Pseudo},
@@ -44,226 +44,228 @@ var progtable = [x86.ALAST]obj.ProgInfo{
 
 	// NOP is an internal no-op that also stands
 	// for USED and SET annotations, not the Intel opcode.
-	obj.ANOP:       {Flags: gc.LeftRead | gc.RightWrite},
-	x86.AADCL:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.AADCW:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.AADDB:      {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AADDL:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AADDW:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AADDSD:     {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	x86.AADDSS:     {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	x86.AANDB:      {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AANDL:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AANDW:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
-	obj.ACALL:      {Flags: gc.RightAddr | gc.Call | gc.KillCarry},
-	x86.ACDQ:       {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
-	x86.ACWD:       {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
-	x86.ACLD:       {Flags: gc.OK},
-	x86.ASTD:       {Flags: gc.OK},
-	x86.ACMPB:      {Flags: gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACMPL:      {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACMPW:      {Flags: gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACOMISD:    {Flags: gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACOMISS:    {Flags: gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ACVTSD2SL:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSD2SS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSL2SD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSL2SS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSS2SD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTSS2SL:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTTSD2SL: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ACVTTSS2SL: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.ADECB:      {Flags: gc.SizeB | RightRdwr},
-	x86.ADECL:      {Flags: gc.SizeL | RightRdwr},
-	x86.ADECW:      {Flags: gc.SizeW | RightRdwr},
-	x86.ADIVB:      {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
-	x86.ADIVL:      {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.ADIVW:      {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.ADIVSD:     {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	x86.ADIVSS:     {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	x86.AFLDCW:     {Flags: gc.SizeW | gc.LeftAddr},
-	x86.AFSTCW:     {Flags: gc.SizeW | gc.RightAddr},
-	x86.AFSTSW:     {Flags: gc.SizeW | gc.RightAddr | gc.RightWrite},
-	x86.AFADDD:     {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFADDDP:    {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFADDF:     {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
-	x86.AFCOMD:     {Flags: gc.SizeD | gc.LeftAddr | gc.RightRead},
-	x86.AFCOMDP:    {Flags: gc.SizeD | gc.LeftAddr | gc.RightRead},
-	x86.AFCOMDPP:   {Flags: gc.SizeD | gc.LeftAddr | gc.RightRead},
-	x86.AFCOMF:     {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
-	x86.AFCOMFP:    {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
+	obj.ANOP:                   {Flags: gc.LeftRead | gc.RightWrite},
+	x86.AADCL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.AADCW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.AADDB & obj.AMask:      {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AADDL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AADDW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AADDSD & obj.AMask:     {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.AADDSS & obj.AMask:     {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	x86.AANDB & obj.AMask:      {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AANDL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AANDW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+	obj.ACALL:                  {Flags: gc.RightAddr | gc.Call | gc.KillCarry},
+	x86.ACDQ & obj.AMask:       {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
+	x86.ACWD & obj.AMask:       {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
+	x86.ACLD & obj.AMask:       {Flags: gc.OK},
+	x86.ASTD & obj.AMask:       {Flags: gc.OK},
+	x86.ACMPB & obj.AMask:      {Flags: gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACMPL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACMPW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACOMISD & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACOMISS & obj.AMask:    {Flags: gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ACVTSD2SL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSD2SS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSL2SD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSL2SS & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSS2SD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTSS2SL & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTTSD2SL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ACVTTSS2SL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.ADECB & obj.AMask:      {Flags: gc.SizeB | RightRdwr},
+	x86.ADECL & obj.AMask:      {Flags: gc.SizeL | RightRdwr},
+	x86.ADECW & obj.AMask:      {Flags: gc.SizeW | RightRdwr},
+	x86.ADIVB & obj.AMask:      {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+	x86.ADIVL & obj.AMask:      {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.ADIVW & obj.AMask:      {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.ADIVSD & obj.AMask:     {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.ADIVSS & obj.AMask:     {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	x86.AFLDCW & obj.AMask:     {Flags: gc.SizeW | gc.LeftAddr},
+	x86.AFSTCW & obj.AMask:     {Flags: gc.SizeW | gc.RightAddr},
+	x86.AFSTSW & obj.AMask:     {Flags: gc.SizeW | gc.RightAddr | gc.RightWrite},
+	x86.AFADDD & obj.AMask:     {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFADDDP & obj.AMask:    {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFADDF & obj.AMask:     {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
+	x86.AFCOMD & obj.AMask:     {Flags: gc.SizeD | gc.LeftAddr | gc.RightRead},
+	x86.AFCOMDP & obj.AMask:    {Flags: gc.SizeD | gc.LeftAddr | gc.RightRead},
+	x86.AFCOMDPP & obj.AMask:   {Flags: gc.SizeD | gc.LeftAddr | gc.RightRead},
+	x86.AFCOMF & obj.AMask:     {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
+	x86.AFCOMFP & obj.AMask:    {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
 	// NOTE(khr): don't use FUCOMI* instructions, not available
 	// on Pentium MMX.  See issue 13923.
-	//x86.AFUCOMIP:   {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
-	x86.AFUCOMP:  {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
-	x86.AFUCOMPP: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
-	x86.AFCHS:    {Flags: gc.SizeD | RightRdwr}, // also SizeF
+	//x86.AFUCOMIP&obj.AMask:   {Flags: gc.SizeF | gc.LeftAddr | gc.RightRead},
+	x86.AFUCOMP & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
+	x86.AFUCOMPP & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
+	x86.AFCHS & obj.AMask:    {Flags: gc.SizeD | RightRdwr}, // also SizeF
 
-	x86.AFDIVDP:  {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFDIVF:   {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
-	x86.AFDIVD:   {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFDIVRDP: {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFDIVRF:  {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
-	x86.AFDIVRD:  {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFXCHD:   {Flags: gc.SizeD | LeftRdwr | RightRdwr},
-	x86.AFSUBD:   {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFSUBDP:  {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFSUBF:   {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
-	x86.AFSUBRD:  {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFSUBRDP: {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFSUBRF:  {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
-	x86.AFMOVD:   {Flags: gc.SizeD | gc.LeftAddr | gc.RightWrite},
-	x86.AFMOVF:   {Flags: gc.SizeF | gc.LeftAddr | gc.RightWrite},
-	x86.AFMOVL:   {Flags: gc.SizeL | gc.LeftAddr | gc.RightWrite},
-	x86.AFMOVW:   {Flags: gc.SizeW | gc.LeftAddr | gc.RightWrite},
-	x86.AFMOVV:   {Flags: gc.SizeQ | gc.LeftAddr | gc.RightWrite},
+	x86.AFDIVDP & obj.AMask:  {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFDIVF & obj.AMask:   {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
+	x86.AFDIVD & obj.AMask:   {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFDIVRDP & obj.AMask: {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFDIVRF & obj.AMask:  {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
+	x86.AFDIVRD & obj.AMask:  {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFXCHD & obj.AMask:   {Flags: gc.SizeD | LeftRdwr | RightRdwr},
+	x86.AFSUBD & obj.AMask:   {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFSUBDP & obj.AMask:  {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFSUBF & obj.AMask:   {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
+	x86.AFSUBRD & obj.AMask:  {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFSUBRDP & obj.AMask: {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFSUBRF & obj.AMask:  {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
+	x86.AFMOVD & obj.AMask:   {Flags: gc.SizeD | gc.LeftAddr | gc.RightWrite},
+	x86.AFMOVF & obj.AMask:   {Flags: gc.SizeF | gc.LeftAddr | gc.RightWrite},
+	x86.AFMOVL & obj.AMask:   {Flags: gc.SizeL | gc.LeftAddr | gc.RightWrite},
+	x86.AFMOVW & obj.AMask:   {Flags: gc.SizeW | gc.LeftAddr | gc.RightWrite},
+	x86.AFMOVV & obj.AMask:   {Flags: gc.SizeQ | gc.LeftAddr | gc.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.
-	x86.AFMOVDP:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.RightAddr},
-	x86.AFMOVFP:   {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.RightAddr},
-	x86.AFMOVLP:   {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.RightAddr},
-	x86.AFMOVWP:   {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.RightAddr},
-	x86.AFMOVVP:   {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.RightAddr},
-	x86.AFMULD:    {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFMULDP:   {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
-	x86.AFMULF:    {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
-	x86.AIDIVB:    {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
-	x86.AIDIVL:    {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.AIDIVW:    {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
-	x86.AIMULB:    {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
-	x86.AIMULL:    {Flags: gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
-	x86.AIMULW:    {Flags: gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
-	x86.AINCB:     {Flags: gc.SizeB | RightRdwr},
-	x86.AINCL:     {Flags: gc.SizeL | RightRdwr},
-	x86.AINCW:     {Flags: gc.SizeW | RightRdwr},
-	x86.AJCC:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJCS:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJEQ:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJGE:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJGT:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJHI:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJLE:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJLS:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJLT:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJMI:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJNE:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJOC:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJOS:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJPC:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJPL:      {Flags: gc.Cjmp | gc.UseCarry},
-	x86.AJPS:      {Flags: gc.Cjmp | gc.UseCarry},
-	obj.AJMP:      {Flags: gc.Jump | gc.Break | gc.KillCarry},
-	x86.ALEAL:     {Flags: gc.LeftAddr | gc.RightWrite},
-	x86.AMOVBLSX:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVBLZX:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVBWSX:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVBWZX:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVWLSX:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVWLZX:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
-	x86.AMOVB:     {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVL:     {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVW:     {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVSB:    {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
-	x86.AMOVSL:    {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
-	x86.AMOVSW:    {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
-	obj.ADUFFCOPY: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI | CX},
-	x86.AMOVSD:    {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMOVSS:    {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AFMOVDP & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.RightAddr},
+	x86.AFMOVFP & obj.AMask:  {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.RightAddr},
+	x86.AFMOVLP & obj.AMask:  {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.RightAddr},
+	x86.AFMOVWP & obj.AMask:  {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.RightAddr},
+	x86.AFMOVVP & obj.AMask:  {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.RightAddr},
+	x86.AFMULD & obj.AMask:   {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFMULDP & obj.AMask:  {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
+	x86.AFMULF & obj.AMask:   {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
+	x86.AIDIVB & obj.AMask:   {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+	x86.AIDIVL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.AIDIVW & obj.AMask:   {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+	x86.AIMULB & obj.AMask:   {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+	x86.AIMULL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
+	x86.AIMULW & obj.AMask:   {Flags: gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry},
+	x86.AINCB & obj.AMask:    {Flags: gc.SizeB | RightRdwr},
+	x86.AINCL & obj.AMask:    {Flags: gc.SizeL | RightRdwr},
+	x86.AINCW & obj.AMask:    {Flags: gc.SizeW | RightRdwr},
+	x86.AJCC & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJCS & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJEQ & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJGE & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJGT & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJHI & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJLE & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJLS & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJLT & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJMI & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJNE & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJOC & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJOS & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJPC & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJPL & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	x86.AJPS & obj.AMask:     {Flags: gc.Cjmp | gc.UseCarry},
+	obj.AJMP:                 {Flags: gc.Jump | gc.Break | gc.KillCarry},
+	x86.ALEAW & obj.AMask:    {Flags: gc.LeftAddr | gc.RightWrite},
+	x86.ALEAL & obj.AMask:    {Flags: gc.LeftAddr | gc.RightWrite},
+	x86.AMOVBLSX & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVBLZX & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVBWSX & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVBWZX & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVWLSX & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVWLZX & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv},
+	x86.AMOVB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVSB & obj.AMask:   {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
+	x86.AMOVSL & obj.AMask:   {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
+	x86.AMOVSW & obj.AMask:   {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
+	obj.ADUFFCOPY:            {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI | CX},
+	x86.AMOVSD & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMOVSS & obj.AMask:   {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move},
 
 	// We use MOVAPD as a faster synonym for MOVSD.
-	x86.AMOVAPD:   {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
-	x86.AMULB:     {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
-	x86.AMULL:     {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
-	x86.AMULW:     {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
-	x86.AMULSD:    {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	x86.AMULSS:    {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	x86.ANEGB:     {Flags: gc.SizeB | RightRdwr | gc.SetCarry},
-	x86.ANEGL:     {Flags: gc.SizeL | RightRdwr | gc.SetCarry},
-	x86.ANEGW:     {Flags: gc.SizeW | RightRdwr | gc.SetCarry},
-	x86.ANOTB:     {Flags: gc.SizeB | RightRdwr},
-	x86.ANOTL:     {Flags: gc.SizeL | RightRdwr},
-	x86.ANOTW:     {Flags: gc.SizeW | RightRdwr},
-	x86.AORB:      {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AORL:      {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AORW:      {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.APOPL:     {Flags: gc.SizeL | gc.RightWrite},
-	x86.APUSHL:    {Flags: gc.SizeL | gc.LeftRead},
-	x86.ARCLB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCLL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCLW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCRB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCRL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.ARCRW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
-	x86.AREP:      {Flags: gc.OK, Reguse: CX, Regset: CX},
-	x86.AREPN:     {Flags: gc.OK, Reguse: CX, Regset: CX},
-	obj.ARET:      {Flags: gc.Break | gc.KillCarry},
-	x86.AROLB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.AROLL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.AROLW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ARORB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ARORL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ARORW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASAHF:     {Flags: gc.OK, Reguse: AX, Regset: AX},
-	x86.ASALB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASALL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASALW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASARB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASARL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASARW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASBBB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.ASBBL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.ASBBW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
-	x86.ASETCC:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETCS:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETEQ:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETGE:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETGT:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETHI:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETLE:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETLS:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETLT:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETMI:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETNE:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETOC:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETOS:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETPC:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETPL:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASETPS:    {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
-	x86.ASHLB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHLL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHLW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHRB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHRL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASHRW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
-	x86.ASTOSB:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
-	x86.ASTOSL:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
-	x86.ASTOSW:    {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
-	obj.ADUFFZERO: {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
-	x86.ASUBB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.ASUBL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.ASUBW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.ASUBSD:    {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
-	x86.ASUBSS:    {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
-	x86.ATESTB:    {Flags: gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ATESTL:    {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.ATESTW:    {Flags: gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry},
-	x86.AUCOMISD:  {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
-	x86.AUCOMISS:  {Flags: gc.SizeF | gc.LeftRead | gc.RightRead},
-	x86.AXCHGB:    {Flags: gc.SizeB | LeftRdwr | RightRdwr},
-	x86.AXCHGL:    {Flags: gc.SizeL | LeftRdwr | RightRdwr},
-	x86.AXCHGW:    {Flags: gc.SizeW | LeftRdwr | RightRdwr},
-	x86.AXORB:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AXORL:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
-	x86.AXORW:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AMOVAPD & obj.AMask:  {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+	x86.AMULB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+	x86.AMULL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
+	x86.AMULW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
+	x86.AMULSD & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.AMULSS & obj.AMask:   {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	x86.ANEGB & obj.AMask:    {Flags: gc.SizeB | RightRdwr | gc.SetCarry},
+	x86.ANEGL & obj.AMask:    {Flags: gc.SizeL | RightRdwr | gc.SetCarry},
+	x86.ANEGW & obj.AMask:    {Flags: gc.SizeW | RightRdwr | gc.SetCarry},
+	x86.ANOTB & obj.AMask:    {Flags: gc.SizeB | RightRdwr},
+	x86.ANOTL & obj.AMask:    {Flags: gc.SizeL | RightRdwr},
+	x86.ANOTW & obj.AMask:    {Flags: gc.SizeW | RightRdwr},
+	x86.AORB & obj.AMask:     {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AORL & obj.AMask:     {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AORW & obj.AMask:     {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.APOPL & obj.AMask:    {Flags: gc.SizeL | gc.RightWrite},
+	x86.APUSHL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead},
+	x86.APXOR & obj.AMask:    {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.ARCLB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCLL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCLW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCRB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCRL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.ARCRW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
+	x86.AREP & obj.AMask:     {Flags: gc.OK, Reguse: CX, Regset: CX},
+	x86.AREPN & obj.AMask:    {Flags: gc.OK, Reguse: CX, Regset: CX},
+	obj.ARET:                 {Flags: gc.Break | gc.KillCarry},
+	x86.AROLB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.AROLL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.AROLW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ARORB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ARORL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ARORW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASAHF & obj.AMask:    {Flags: gc.OK, Reguse: AX, Regset: AX},
+	x86.ASALB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASALL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASALW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASARB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASARL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASARW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASBBB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.ASBBL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.ASBBW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry},
+	x86.ASETCC & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETCS & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETEQ & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETGE & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETGT & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETHI & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETLE & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETLS & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETLT & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETMI & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETNE & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETOC & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETOS & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETPC & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETPL & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASETPS & obj.AMask:   {Flags: gc.SizeB | RightRdwr | gc.UseCarry},
+	x86.ASHLB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHLL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHLW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHRB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHRL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASHRW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
+	x86.ASTOSB & obj.AMask:   {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
+	x86.ASTOSL & obj.AMask:   {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
+	x86.ASTOSW & obj.AMask:   {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
+	obj.ADUFFZERO:            {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
+	x86.ASUBB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.ASUBL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.ASUBW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.ASUBSD & obj.AMask:   {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
+	x86.ASUBSS & obj.AMask:   {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
+	x86.ATESTB & obj.AMask:   {Flags: gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ATESTL & obj.AMask:   {Flags: gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.ATESTW & obj.AMask:   {Flags: gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry},
+	x86.AUCOMISD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
+	x86.AUCOMISS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightRead},
+	x86.AXCHGB & obj.AMask:   {Flags: gc.SizeB | LeftRdwr | RightRdwr},
+	x86.AXCHGL & obj.AMask:   {Flags: gc.SizeL | LeftRdwr | RightRdwr},
+	x86.AXCHGW & obj.AMask:   {Flags: gc.SizeW | LeftRdwr | RightRdwr},
+	x86.AXORB & obj.AMask:    {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AXORL & obj.AMask:    {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
+	x86.AXORW & obj.AMask:    {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
 }
 
 func proginfo(p *obj.Prog) {
 	info := &p.Info
-	*info = progtable[p.As]
+	*info = progtable[p.As&obj.AMask]
 	if info.Flags == 0 {
 		gc.Fatalf("unknown instruction %v", p)
 	}
diff --git a/src/cmd/compile/internal/x86/reg.go b/src/cmd/compile/internal/x86/reg.go
index 76d90b8..cc94d72 100644
--- a/src/cmd/compile/internal/x86/reg.go
+++ b/src/cmd/compile/internal/x86/reg.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -62,7 +62,7 @@ func regnames(n *int) []string {
 }
 
 func excludedregs() uint64 {
-	if gc.Ctxt.Flag_shared != 0 {
+	if gc.Ctxt.Flag_shared {
 		return RtoB(x86.REG_SP) | RtoB(x86.REG_CX)
 	} else {
 		return RtoB(x86.REG_SP)
diff --git a/src/cmd/compile/main.go b/src/cmd/compile/main.go
index 3d11f51..8b8161e 100644
--- a/src/cmd/compile/main.go
+++ b/src/cmd/compile/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -10,6 +10,7 @@ import (
 	"cmd/compile/internal/arm64"
 	"cmd/compile/internal/mips64"
 	"cmd/compile/internal/ppc64"
+	"cmd/compile/internal/s390x"
 	"cmd/compile/internal/x86"
 	"cmd/internal/obj"
 	"fmt"
@@ -38,5 +39,7 @@ func main() {
 		mips64.Main()
 	case "ppc64", "ppc64le":
 		ppc64.Main()
+	case "s390x":
+		s390x.Main()
 	}
 }
diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go
index 31ec434..a9ed66e 100644
--- a/src/cmd/cover/cover.go
+++ b/src/cmd/cover/cover.go
@@ -181,6 +181,10 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
 		}
 		n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace.
 	case *ast.IfStmt:
+		if n.Init != nil {
+			ast.Walk(f, n.Init)
+		}
+		ast.Walk(f, n.Cond)
 		ast.Walk(f, n.Body)
 		if n.Else == nil {
 			return nil
@@ -219,11 +223,21 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
 	case *ast.SwitchStmt:
 		// Don't annotate an empty switch - creates a syntax error.
 		if n.Body == nil || len(n.Body.List) == 0 {
+			if n.Init != nil {
+				ast.Walk(f, n.Init)
+			}
+			if n.Tag != nil {
+				ast.Walk(f, n.Tag)
+			}
 			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 {
+			if n.Init != nil {
+				ast.Walk(f, n.Init)
+			}
+			ast.Walk(f, n.Assign)
 			return nil
 		}
 	}
@@ -297,8 +311,8 @@ func (f *File) addImport(path string) string {
 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
+// 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 {
@@ -374,7 +388,7 @@ func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup {
 			}
 		}
 		if list != nil {
-			comments = append(comments, &ast.CommentGroup{list})
+			comments = append(comments, &ast.CommentGroup{List: list})
 		}
 	}
 	return comments
diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go
index f01f138..68e9e9f 100644
--- a/src/cmd/cover/cover_test.go
+++ b/src/cmd/cover/cover_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/cmd/cover/testdata/test.go b/src/cmd/cover/testdata/test.go
index 9013950..c4c0e15 100644
--- a/src/cmd/cover/testdata/test.go
+++ b/src/cmd/cover/testdata/test.go
@@ -24,6 +24,7 @@ func testAll() {
 	testSelect2()
 	testPanic()
 	testEmptySwitches()
+	testFunctionLiteral()
 }
 
 // The indexes of the counters in testPanic are known to main.go
@@ -216,3 +217,32 @@ func testEmptySwitches() {
 	<-c
 	check(LINE, 1)
 }
+
+func testFunctionLiteral() {
+	a := func(f func()) error {
+		f()
+		f()
+		return nil
+	}
+
+	b := func(f func()) bool {
+		f()
+		f()
+		return true
+	}
+
+	check(LINE, 1)
+	a(func() {
+		check(LINE, 2)
+	})
+
+	if err := a(func() {
+		check(LINE, 2)
+	}); err != nil {
+	}
+
+	switch b(func() {
+		check(LINE, 2)
+	}) {
+	}
+}
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 39a88cc..9eb9caf 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,6 +6,7 @@ package main
 
 import (
 	"bytes"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"os"
@@ -30,6 +31,7 @@ var (
 	goroot           string
 	goroot_final     string
 	goextlinkenabled string
+	gogcflags        string // For running built compiler
 	workdir          string
 	tooldir          string
 	oldgoos          string
@@ -58,6 +60,7 @@ var okgoarch = []string{
 	"mips64le",
 	"ppc64",
 	"ppc64le",
+	"s390x",
 }
 
 // The known operating systems.
@@ -165,6 +168,8 @@ func xinit() {
 		goextlinkenabled = b
 	}
 
+	gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
+
 	b = os.Getenv("CC")
 	if b == "" {
 		// Use clang on OS X, because gcc is deprecated there.
@@ -283,7 +288,7 @@ func findgoversion() string {
 	}
 
 	// The $GOROOT/VERSION.cache file is a cache to avoid invoking
-	// git every time we run this command.  Unlike VERSION, it gets
+	// 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) {
@@ -398,8 +403,8 @@ func setup() {
 
 	// 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
+	// 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))
@@ -459,10 +464,14 @@ var deptab = []struct {
 }{
 	{"cmd/go", []string{
 		"zdefaultcc.go",
+		"zosarch.go",
 	}},
 	{"runtime/internal/sys", []string{
 		"zversion.go",
 	}},
+	{"go/build", []string{
+		"zcgo.go",
+	}},
 }
 
 // depsuffix records the allowed suffixes for source files.
@@ -477,7 +486,9 @@ var gentab = []struct {
 	gen        func(string, string)
 }{
 	{"zdefaultcc.go", mkzdefaultcc},
+	{"zosarch.go", mkzosarch},
 	{"zversion.go", mkzversion},
+	{"zcgo.go", mkzcgo},
 
 	// not generated anymore, but delete the file if we see it
 	{"enam.c", nil},
@@ -682,6 +693,9 @@ func install(dir string) {
 		archive = b
 	}
 	compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg}
+	if gogcflags != "" {
+		compile = append(compile, strings.Fields(gogcflags)...)
+	}
 	if dir == "runtime" {
 		compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir))
 	}
@@ -754,7 +768,7 @@ func matchtag(tag string) bool {
 		}
 		return !matchtag(tag[1:])
 	}
-	return tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
+	return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
 }
 
 // shouldbuild reports whether we should build this file.
@@ -798,10 +812,15 @@ func shouldbuild(file, dir string) bool {
 		if p == "" {
 			continue
 		}
-		if strings.Contains(p, "package documentation") {
+		code := p
+		i := strings.Index(code, "//")
+		if i > 0 {
+			code = strings.TrimSpace(code[:i])
+		}
+		if code == "package documentation" {
 			return false
 		}
-		if strings.Contains(p, "package main") && dir != "cmd/go" && dir != "cmd/cgo" {
+		if code == "package main" && dir != "cmd/go" && dir != "cmd/cgo" {
 			return false
 		}
 		if !strings.HasPrefix(p, "//") {
@@ -810,11 +829,11 @@ func shouldbuild(file, dir string) bool {
 		if !strings.Contains(p, "+build") {
 			continue
 		}
-		fields := splitfields(p)
-		if len(fields) < 2 || fields[1] != "+build" {
+		fields := splitfields(p[2:])
+		if len(fields) < 1 || fields[0] != "+build" {
 			continue
 		}
-		for _, p := range fields[2:] {
+		for _, p := range fields[1:] {
 			if matchfield(p) {
 				goto fieldmatch
 			}
@@ -928,6 +947,7 @@ func usage() {
 		"clean          deletes all built files\n" +
 		"env [-p]       print environment (-p: include $PATH)\n" +
 		"install [dir]  install individual directory\n" +
+		"list [-json]   list all supported platforms\n" +
 		"test [-h]      run Go test(s)\n" +
 		"version        print Go version\n" +
 		"\n" +
@@ -1056,9 +1076,13 @@ func cmdbootstrap() {
 	}
 }
 
-// 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.
+// To reduce duplication, we generate the list for go/build from this.
+//
+// We list all supported platforms in this list, so that this is the
+// single point of truth for supported platforms. This list is used
+// by 'go tool dist list'.
 var cgoEnabled = map[string]bool{
 	"darwin/386":      true,
 	"darwin/amd64":    true,
@@ -1067,19 +1091,32 @@ var cgoEnabled = map[string]bool{
 	"dragonfly/amd64": true,
 	"freebsd/386":     true,
 	"freebsd/amd64":   true,
+	"freebsd/arm":     false,
 	"linux/386":       true,
 	"linux/amd64":     true,
 	"linux/arm":       true,
 	"linux/arm64":     true,
+	"linux/ppc64":     false,
 	"linux/ppc64le":   true,
+	"linux/mips64":    true,
+	"linux/mips64le":  true,
+	"linux/s390x":     true,
 	"android/386":     true,
 	"android/amd64":   true,
 	"android/arm":     true,
+	"android/arm64":   true,
+	"nacl/386":        false,
+	"nacl/amd64p32":   false,
+	"nacl/arm":        false,
 	"netbsd/386":      true,
 	"netbsd/amd64":    true,
 	"netbsd/arm":      true,
 	"openbsd/386":     true,
 	"openbsd/amd64":   true,
+	"openbsd/arm":     false,
+	"plan9/386":       false,
+	"plan9/amd64":     false,
+	"plan9/arm":       false,
 	"solaris/amd64":   true,
 	"windows/386":     true,
 	"windows/amd64":   true,
@@ -1106,8 +1143,8 @@ func checkCC() {
 		}
 		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%s%s", defaultcc, err, outputHdr, output)
+			"To set a C compiler, set CC=the-compiler.\n"+
+			"To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output)
 	}
 }
 
@@ -1123,7 +1160,7 @@ func defaulttarg() string {
 		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 /
+	// guard against xrealwd returning the directory without the trailing /
 	pwd = strings.TrimPrefix(pwd, "/")
 
 	return pwd
@@ -1190,3 +1227,43 @@ func cmdversion() {
 	xflagparse(0)
 	xprintf("%s\n", findgoversion())
 }
+
+// cmdlist lists all supported platforms.
+func cmdlist() {
+	jsonFlag := flag.Bool("json", false, "produce JSON output")
+	xflagparse(0)
+
+	var plats []string
+	for p := range cgoEnabled {
+		plats = append(plats, p)
+	}
+	sort.Strings(plats)
+
+	if !*jsonFlag {
+		for _, p := range plats {
+			xprintf("%s\n", p)
+		}
+		return
+	}
+
+	type jsonResult struct {
+		GOOS         string
+		GOARCH       string
+		CgoSupported bool
+	}
+	var results []jsonResult
+	for _, p := range plats {
+		fields := strings.Split(p, "/")
+		results = append(results, jsonResult{
+			GOOS:         fields[0],
+			GOARCH:       fields[1],
+			CgoSupported: cgoEnabled[p]})
+	}
+	out, err := json.MarshalIndent(results, "", "\t")
+	if err != nil {
+		fatal("json marshal error: %v", err)
+	}
+	if _, err := os.Stdout.Write(out); err != nil {
+		fatal("write failed: %v", err)
+	}
+}
diff --git a/src/cmd/dist/buildgo.go b/src/cmd/dist/buildgo.go
index 437e9dd..3fab235 100644
--- a/src/cmd/dist/buildgo.go
+++ b/src/cmd/dist/buildgo.go
@@ -1,10 +1,14 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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"
+import (
+	"bytes"
+	"fmt"
+	"sort"
+)
 
 /*
  * Helpers for building cmd/go and cmd/cgo.
@@ -19,9 +23,7 @@ import "fmt"
 // 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(
+	out := fmt.Sprintf(
 		"// auto generated by go tool dist\n"+
 			"\n"+
 			"package main\n"+
@@ -37,3 +39,55 @@ func mkzdefaultcc(dir, file string) {
 	file = file[:i] + "c" + file[i:]
 	writefile(out, file, writeSkipSame)
 }
+
+// mkzcgo writes zosarch.go for cmd/go.
+func mkzosarch(dir, file string) {
+	// sort for deterministic zosarch.go file
+	var list []string
+	for plat := range cgoEnabled {
+		list = append(list, plat)
+	}
+	sort.Strings(list)
+
+	var buf bytes.Buffer
+	buf.WriteString("// auto generated by go tool dist\n\n")
+	buf.WriteString("package main\n\n")
+	fmt.Fprintf(&buf, "var osArchSupportsCgo = map[string]bool{\n")
+	for _, plat := range list {
+		fmt.Fprintf(&buf, "\t%q: %v,\n", plat, cgoEnabled[plat])
+	}
+	fmt.Fprintf(&buf, "}\n")
+	writefile(buf.String(), file, writeSkipSame)
+}
+
+// mkzcgo writes zcgo.go for the go/build package:
+//
+//	package build
+//  var cgoEnabled = map[string]bool{}
+//
+// It is invoked to write go/build/zcgo.go.
+func mkzcgo(dir, file string) {
+	// sort for deterministic zcgo.go file
+	var list []string
+	for plat, hasCgo := range cgoEnabled {
+		if hasCgo {
+			list = append(list, plat)
+		}
+	}
+	sort.Strings(list)
+
+	var buf bytes.Buffer
+
+	fmt.Fprintf(&buf,
+		"// auto generated by go tool dist\n"+
+			"\n"+
+			"package build\n"+
+			"\n"+
+			"var cgoEnabled = map[string]bool{\n")
+	for _, plat := range list {
+		fmt.Fprintf(&buf, "\t%q: true,\n", plat)
+	}
+	fmt.Fprintf(&buf, "}")
+
+	writefile(buf.String(), file, writeSkipSame)
+}
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
index 6e80221..d696beb 100644
--- a/src/cmd/dist/buildruntime.go
+++ b/src/cmd/dist/buildruntime.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -82,7 +82,7 @@ func mkzbootstrap(file string) {
 }
 
 // stackGuardMultiplier returns a multiplier to apply to the default
-// stack guard size.  Larger multipliers are used for non-optimized
+// 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"), " ") {
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index 20d9535..a535316 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -36,14 +36,19 @@ var bootstrapDirs = []string{
 	"compile/internal/gc",
 	"compile/internal/mips64",
 	"compile/internal/ppc64",
+	"compile/internal/ssa",
 	"compile/internal/x86",
+	"compile/internal/s390x",
+	"internal/bio",
 	"internal/gcprog",
 	"internal/obj",
 	"internal/obj/arm",
 	"internal/obj/arm64",
 	"internal/obj/mips",
 	"internal/obj/ppc64",
+	"internal/obj/s390x",
 	"internal/obj/x86",
+	"internal/sys",
 	"link",
 	"link/internal/amd64",
 	"link/internal/arm",
@@ -51,6 +56,7 @@ var bootstrapDirs = []string{
 	"link/internal/ld",
 	"link/internal/mips64",
 	"link/internal/ppc64",
+	"link/internal/s390x",
 	"link/internal/x86",
 }
 
@@ -110,8 +116,10 @@ func bootstrapBuildTools() {
 	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/...")
+	// Run Go 1.4 to build binaries. Use -gcflags=-l to disable inlining to
+	// workaround bugs in Go 1.4's compiler. See discussion thread:
+	// https://groups.google.com/d/msg/golang-dev/Ss7mCKsvk8w/Gsq7VYI0AwAJ
+	run(workspace, ShowOutput|CheckExit, pathf("%s/bin/go", goroot_bootstrap), "install", "-gcflags=-l", "-v", "bootstrap/...")
 
 	// Copy binaries into tool binary directory.
 	for _, name := range bootstrapDirs {
diff --git a/src/cmd/dist/cpuid_386.s b/src/cmd/dist/cpuid_386.s
index ed4fb52..65fbb2d 100644
--- a/src/cmd/dist/cpuid_386.s
+++ b/src/cmd/dist/cpuid_386.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/dist/cpuid_amd64.s b/src/cmd/dist/cpuid_amd64.s
index b6cdfed..ea0b9d4 100644
--- a/src/cmd/dist/cpuid_amd64.s
+++ b/src/cmd/dist/cpuid_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/dist/cpuid_default.s b/src/cmd/dist/cpuid_default.s
index 165b4a9..6412a50 100644
--- a/src/cmd/dist/cpuid_default.s
+++ b/src/cmd/dist/cpuid_default.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/dist/deps.go b/src/cmd/dist/deps.go
index 0838914..e8dd6cf 100644
--- a/src/cmd/dist/deps.go
+++ b/src/cmd/dist/deps.go
@@ -8,6 +8,7 @@ var builddeps = map[string][]string{
 	"compress/flate":                    {"bufio", "bytes", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
 	"compress/zlib":                     {"bufio", "bytes", "compress/flate", "errors", "fmt", "hash", "hash/adler32", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
 	"container/heap":                    {"runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort"},
+	"context":                           {"errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
 	"crypto":                            {"errors", "hash", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
 	"crypto/sha1":                       {"crypto", "errors", "hash", "internal/race", "io", "math", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strconv", "sync", "sync/atomic", "unicode/utf8"},
 	"debug/dwarf":                       {"encoding/binary", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
@@ -39,7 +40,7 @@ var builddeps = map[string][]string{
 	"math":                    {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
 	"net/url":                 {"bytes", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
 	"os":                      {"errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
-	"os/exec":                 {"bytes", "errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+	"os/exec":                 {"bytes", "context", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
 	"os/signal":               {"errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "os", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
 	"path":                    {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
 	"path/filepath":           {"errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "os", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
@@ -61,5 +62,5 @@ var builddeps = map[string][]string{
 	"unicode":                 {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
 	"unicode/utf16":           {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
 	"unicode/utf8":            {"runtime", "runtime/internal/atomic", "runtime/internal/sys"},
-	"cmd/go":                  {"bufio", "bytes", "compress/flate", "compress/zlib", "container/heap", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/singleflight", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysd [...]
+	"cmd/go":                  {"bufio", "bytes", "compress/flate", "compress/zlib", "container/heap", "context", "crypto", "crypto/sha1", "debug/dwarf", "debug/elf", "debug/macho", "encoding", "encoding/base64", "encoding/binary", "encoding/json", "errors", "flag", "fmt", "go/ast", "go/build", "go/doc", "go/parser", "go/scanner", "go/token", "hash", "hash/adler32", "internal/race", "internal/singleflight", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/w [...]
 }
diff --git a/src/cmd/dist/main.go b/src/cmd/dist/main.go
index 1f19a7c..b0471bd 100644
--- a/src/cmd/dist/main.go
+++ b/src/cmd/dist/main.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -21,6 +21,7 @@ var cmdtab = []struct {
 	{"clean", cmdclean},
 	{"env", cmdenv},
 	{"install", cmdinstall},
+	{"list", cmdlist},
 	{"test", cmdtest},
 	{"version", cmdversion},
 }
diff --git a/src/cmd/dist/sys_default.go b/src/cmd/dist/sys_default.go
index d7bc464..821dc27 100644
--- a/src/cmd/dist/sys_default.go
+++ b/src/cmd/dist/sys_default.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/dist/sys_windows.go b/src/cmd/dist/sys_windows.go
index e9bfe9e..05cb3e2 100644
--- a/src/cmd/dist/sys_windows.go
+++ b/src/cmd/dist/sys_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 36c829d..e56d108 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -28,6 +28,7 @@ func cmdtest() {
 	flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)")
 	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.BoolVar(&t.compileOnly, "compile-only", false, "compile tests, but don't run them. This is for some builders. Not all dist tests respect this flag, but most do.")
 	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. "+
@@ -46,6 +47,7 @@ type tester struct {
 	rebuild     bool
 	failed      bool
 	keepGoing   bool
+	compileOnly bool // just try to compile all tests, but no need to run
 	runRxStr    string
 	runRx       *regexp.Regexp
 	runRxWant   bool     // want runRx to match (true) or not match (false)
@@ -279,6 +281,9 @@ func (t *tester) registerStdTest(pkg string) {
 			if t.race {
 				args = append(args, "-race")
 			}
+			if t.compileOnly {
+				args = append(args, "-run=^$")
+			}
 			args = append(args, stdMatches...)
 			cmd := exec.Command("go", args...)
 			cmd.Stdout = os.Stdout
@@ -307,10 +312,12 @@ func (t *tester) registerRaceBenchTest(pkg string) {
 				"-short",
 				"-race",
 				"-run=^$", // nothing. only benchmarks.
-				"-bench=.*",
 				"-benchtime=.1s",
 				"-cpu=4",
 			}
+			if !t.compileOnly {
+				args = append(args, "-bench=.*")
+			}
 			args = append(args, benchMatches...)
 			cmd := exec.Command("go", args...)
 			cmd.Stdout = os.Stdout
@@ -364,21 +371,23 @@ func (t *tester) registerTests() {
 	}
 
 	// Runtime CPU tests.
-	testName := "runtime:cpu124"
-	t.tests = append(t.tests, distTest{
-		name:    testName,
-		heading: "GOMAXPROCS=2 runtime -cpu=1,2,4",
-		fn: func(dt *distTest) error {
-			cmd := t.addCmd(dt, "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 nil
-		},
-	})
+	if !t.compileOnly {
+		testName := "runtime:cpu124"
+		t.tests = append(t.tests, distTest{
+			name:    testName,
+			heading: "GOMAXPROCS=2 runtime -cpu=1,2,4",
+			fn: func(dt *distTest) error {
+				cmd := t.addCmd(dt, "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 nil
+			},
+		})
+	}
 
 	// Test that internal linking of standard packages does not
-	// require libgcc.  This ensures that we can install a Go
+	// require libgcc. This ensures that we can install a Go
 	// release on a system that does not have a C compiler
 	// installed and still build Go programs (that don't use cgo).
 	for _, pkg := range cgoPackages {
@@ -407,7 +416,7 @@ func (t *tester) registerTests() {
 			name:    "nolibgcc:" + pkg,
 			heading: "Testing without libgcc.",
 			fn: func(dt *distTest) error {
-				t.addCmd(dt, "src", "go", "test", "-short", "-ldflags=-linkmode=internal -libgcc=none", t.tags(), pkg, "-run="+run)
+				t.addCmd(dt, "src", "go", "test", "-short", "-ldflags=-linkmode=internal -libgcc=none", t.tags(), pkg, t.runFlag(run))
 				return nil
 			},
 		})
@@ -418,13 +427,13 @@ func (t *tester) registerTests() {
 		name:    "sync_cpu",
 		heading: "sync -cpu=10",
 		fn: func(dt *distTest) error {
-			t.addCmd(dt, "src", "go", "test", "sync", "-short", t.timeout(120), t.tags(), "-cpu=10")
+			t.addCmd(dt, "src", "go", "test", "sync", "-short", t.timeout(120), t.tags(), "-cpu=10", t.runFlag(""))
 			return nil
 		},
 	})
 
-	if t.cgoEnabled && t.goos != "android" && !t.iOS() {
-		// Disabled on android and iOS. golang.org/issue/8345
+	if t.cgoEnabled && !t.iOS() {
+		// Disabled on iOS. golang.org/issue/15919
 		t.tests = append(t.tests, distTest{
 			name:    "cgo_stdio",
 			heading: "../misc/cgo/stdio",
@@ -441,12 +450,22 @@ func (t *tester) registerTests() {
 				return nil
 			},
 		})
+		fortran := os.Getenv("FC")
+		if fortran == "" {
+			fortran, _ = exec.LookPath("gfortran")
+		}
+		if t.hasBash() && fortran != "" {
+			t.tests = append(t.tests, distTest{
+				name:    "cgo_fortran",
+				heading: "../misc/cgo/fortran",
+				fn: func(dt *distTest) error {
+					t.addCmd(dt, "misc/cgo/fortran", "./test.bash", fortran)
+					return nil
+				},
+			})
+		}
 	}
-	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.
+	if t.cgoEnabled {
 		t.tests = append(t.tests, distTest{
 			name:    "cgo_test",
 			heading: "../misc/cgo/test",
@@ -483,7 +502,7 @@ func (t *tester) registerTests() {
 			})
 		}
 		if t.supportedBuildmode("c-archive") {
-			t.registerTest("testcarchive", "../misc/cgo/testcarchive", "./test.bash")
+			t.registerHostTest("testcarchive", "misc/cgo/testcarchive", "carchive_test.go")
 		}
 		if t.supportedBuildmode("c-shared") {
 			t.registerTest("testcshared", "../misc/cgo/testcshared", "./test.bash")
@@ -514,7 +533,7 @@ func (t *tester) registerTests() {
 	}
 
 	if t.goos != "android" && !t.iOS() {
-		t.registerTest("bench_go1", "../test/bench/go1", "go", "test", t.timeout(600))
+		t.registerTest("bench_go1", "../test/bench/go1", "go", "test", t.timeout(600), t.runFlag(""))
 	}
 	if t.goos != "android" && !t.iOS() {
 		const nShards = 5
@@ -532,6 +551,10 @@ func (t *tester) registerTests() {
 			name:    "api",
 			heading: "API check",
 			fn: func(dt *distTest) error {
+				if t.compileOnly {
+					t.addCmd(dt, "src", "go", "build", filepath.Join(t.goroot, "src/cmd/api/run.go"))
+					return nil
+				}
 				t.addCmd(dt, "src", "go", "run", filepath.Join(t.goroot, "src/cmd/api/run.go"))
 				return nil
 			},
@@ -626,7 +649,7 @@ func (t *tester) extLink() bool {
 		"darwin-arm", "darwin-arm64",
 		"dragonfly-386", "dragonfly-amd64",
 		"freebsd-386", "freebsd-amd64", "freebsd-arm",
-		"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le",
+		"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le",
 		"netbsd-386", "netbsd-amd64",
 		"openbsd-386", "openbsd-amd64",
 		"windows-386", "windows-amd64":
@@ -653,7 +676,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
 		}
 		switch pair {
 		case "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64",
-			"linux-amd64", "linux-386":
+			"linux-amd64", "linux-386", "windows-amd64", "windows-386":
 			return true
 		}
 		return false
@@ -667,31 +690,49 @@ func (t *tester) supportedBuildmode(mode string) bool {
 		return false
 	case "shared":
 		switch pair {
-		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le":
+		case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x":
 			return true
 		}
 		return false
 	default:
-		log.Fatal("internal error: unknown buildmode %s", mode)
+		log.Fatalf("internal error: unknown buildmode %s", mode)
 		return false
 	}
 }
 
-func (t *tester) cgoTest(dt *distTest) error {
-	env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
+func (t *tester) registerHostTest(name, dirBanner, pkg string) {
+	t.tests = append(t.tests, distTest{
+		name:    name,
+		heading: dirBanner,
+		fn: func(dt *distTest) error {
+			t.runPending(dt)
+			return t.runHostTest(dirBanner, pkg)
+		},
+	})
+}
 
-	if t.goos == "android" || t.iOS() {
-		cmd := t.dirCmd("misc/cgo/test", "go", "test", t.tags())
-		cmd.Env = env
-		return cmd.Run()
+func (t *tester) runHostTest(dirBanner, pkg string) error {
+	env := mergeEnvLists([]string{"GOARCH=" + t.gohostarch, "GOOS=" + t.gohostos}, os.Environ())
+	defer os.Remove(filepath.Join(t.goroot, dirBanner, "test.test"))
+	cmd := t.dirCmd(dirBanner, "go", "test", t.tags(), "-c", "-o", "test.test", pkg)
+	cmd.Env = env
+	if err := cmd.Run(); err != nil {
+		return err
 	}
+	return t.dirCmd(dirBanner, "./test.test").Run()
+}
 
-	cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto")
+func (t *tester) cgoTest(dt *distTest) error {
+	env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
+
+	cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto", t.runFlag(""))
 	cmd.Env = env
 
-	if t.gohostos != "dragonfly" {
+	if t.gohostos != "dragonfly" && t.gohostarch != "ppc64le" && t.goos != "android" && (t.goos != "darwin" || t.goarch != "arm") {
 		// linkmode=internal fails on dragonfly since errno is a TLS relocation.
-		cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=internal")
+		// linkmode=internal fails on ppc64le because cmd/link doesn't
+		// handle the TOC correctly (issue 15409).
+		cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=internal", t.runFlag(""))
 		cmd.Env = env
 	}
 
@@ -711,7 +752,7 @@ func (t *tester) cgoTest(dt *distTest) error {
 	case "android-arm",
 		"dragonfly-386", "dragonfly-amd64",
 		"freebsd-386", "freebsd-amd64", "freebsd-arm",
-		"linux-386", "linux-amd64", "linux-arm",
+		"linux-386", "linux-amd64", "linux-arm", "linux-s390x",
 		"netbsd-386", "netbsd-amd64":
 
 		cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external")
@@ -741,8 +782,10 @@ func (t *tester) cgoTest(dt *distTest) error {
 			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.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
-				cmd.Env = env
+				if t.goos != "android" {
+					cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
+					cmd.Env = env
+				}
 
 				cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test")
 				cmd.Env = env
@@ -750,8 +793,10 @@ func (t *tester) cgoTest(dt *distTest) error {
 				cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external`)
 				cmd.Env = env
 
-				cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
-				cmd.Env = env
+				if t.goos != "android" {
+					cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
+					cmd.Env = env
+				}
 			}
 
 			if pair != "freebsd-amd64" { // clang -pie fails to link misc/cgo/test
@@ -943,10 +988,17 @@ func (t *tester) raceDetectorSupported() bool {
 	return false
 }
 
+func (t *tester) runFlag(rx string) string {
+	if t.compileOnly {
+		return "-run=^$"
+	}
+	return "-run=" + rx
+}
+
 func (t *tester) raceTest(dt *distTest) error {
 	t.addCmd(dt, "src", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec")
-	t.addCmd(dt, "src", "go", "test", "-race", "-run=Output", "runtime/race")
-	t.addCmd(dt, "src", "go", "test", "-race", "-short", "-run=TestParse|TestEcho", "flag", "os/exec")
+	t.addCmd(dt, "src", "go", "test", "-race", t.runFlag("Output"), "runtime/race")
+	t.addCmd(dt, "src", "go", "test", "-race", "-short", t.runFlag("TestParse|TestEcho"), "flag", "os/exec")
 	// We don't want the following line, because it
 	// slows down all.bash (by 10 seconds on my laptop).
 	// The race builder should catch any error here, but doesn't.
@@ -954,12 +1006,12 @@ func (t *tester) raceTest(dt *distTest) error {
 	// t.addCmd(dt, "src", "go", "test", "-race", "-run=TestParallelTest", "cmd/go")
 	if t.cgoEnabled {
 		env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
-		cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-race", "-short")
+		cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-race", "-short", t.runFlag(""))
 		cmd.Env = env
 	}
 	if t.extLink() {
 		// Test with external linking; see issue 9133.
-		t.addCmd(dt, "src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", "-run=TestParse|TestEcho", "flag", "os/exec")
+		t.addCmd(dt, "src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho"), "flag", "os/exec")
 	}
 	return nil
 }
@@ -987,7 +1039,9 @@ func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
 	if runtest.err != nil {
 		return runtest.err
 	}
-
+	if t.compileOnly {
+		return nil
+	}
 	t.addCmd(dt, "test", runtest.exe,
 		fmt.Sprintf("--shard=%d", shard),
 		fmt.Sprintf("--shards=%d", shards),
diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go
index 1b5d1f9..bbf3b75 100644
--- a/src/cmd/dist/util.go
+++ b/src/cmd/dist/util.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,9 +6,8 @@ package main
 
 import (
 	"bytes"
-	"debug/elf"
-	"encoding/binary"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -131,7 +130,6 @@ var maxbg = 4 /* maximum number of jobs to run at once */
 
 var (
 	bgwork = make(chan func(), 1e5)
-	bgdone = make(chan struct{}, 1e5)
 
 	bghelpers sync.WaitGroup
 
@@ -443,15 +441,12 @@ func main() {
 		case strings.Contains(out, "ppc64"):
 			gohostarch = "ppc64"
 		case strings.Contains(out, "mips64"):
-			file, err := elf.Open(os.Args[0])
-			if err != nil {
-				fatal("failed to open %s to determine endianness: %v", os.Args[0], err)
-			}
-			if file.FileHeader.ByteOrder == binary.BigEndian {
-				gohostarch = "mips64"
-			} else {
+			gohostarch = "mips64"
+			if elfIsLittleEndian(os.Args[0]) {
 				gohostarch = "mips64le"
 			}
+		case strings.Contains(out, "s390x"):
+			gohostarch = "s390x"
 		case gohostos == "darwin":
 			if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM_") {
 				gohostarch = "arm"
@@ -555,3 +550,28 @@ func min(a, b int) int {
 	}
 	return b
 }
+
+// elfIsLittleEndian detects if the ELF file is little endian.
+func elfIsLittleEndian(fn string) bool {
+	// read the ELF file header to determine the endianness without using the
+	// debug/elf package.
+	file, err := os.Open(fn)
+	if err != nil {
+		fatal("failed to open file to determine endianness: %v", err)
+	}
+	defer file.Close()
+	var hdr [16]byte
+	if _, err := io.ReadFull(file, hdr[:]); err != nil {
+		fatal("failed to read ELF header to determine endianness: %v", err)
+	}
+	// hdr[5] is EI_DATA byte, 1 is ELFDATA2LSB and 2 is ELFDATA2MSB
+	switch hdr[5] {
+	default:
+		fatal("unknown ELF endianness of %s: EI_DATA = %d", fn, hdr[5])
+	case 1:
+		return true
+	case 2:
+		return false
+	}
+	panic("unreachable")
+}
diff --git a/src/cmd/dist/util_gc.go b/src/cmd/dist/util_gc.go
index 81e52b6..6e099e5 100644
--- a/src/cmd/dist/util_gc.go
+++ b/src/cmd/dist/util_gc.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/dist/util_gccgo.go b/src/cmd/dist/util_gccgo.go
index 18e328f..5edb473 100644
--- a/src/cmd/dist/util_gccgo.go
+++ b/src/cmd/dist/util_gccgo.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/dist/vfp_arm.s b/src/cmd/dist/vfp_arm.s
index 647c439..c42b593 100644
--- a/src/cmd/dist/vfp_arm.s
+++ b/src/cmd/dist/vfp_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/dist/vfp_default.s b/src/cmd/dist/vfp_default.s
index 5cf9997..95ccbe3 100644
--- a/src/cmd/dist/vfp_default.s
+++ b/src/cmd/dist/vfp_default.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index ed1d0e7..5cb1ec9 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -22,11 +22,6 @@ func maybeSkip(t *testing.T) {
 	}
 }
 
-const (
-	dataDir = "testdata"
-	binary  = "testdoc"
-)
-
 type test struct {
 	name string
 	args []string // Arguments to "[go] doc".
@@ -221,6 +216,7 @@ var tests = []test{
 			`type ExportedType struct`,    // Type definition.
 			`Comment before exported field.*\n.*ExportedField +int` +
 				`.*Comment on line with exported field.`,
+			`ExportedEmbeddedType.*Comment on line with exported embedded field.`,
 			`Has unexported fields`,
 			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
 			`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
@@ -228,6 +224,7 @@ var tests = []test{
 		},
 		[]string{
 			`unexportedField`,                // No unexported field.
+			`int.*embedded`,                  // No unexported embedded field.
 			`Comment about exported method.`, // No comment about exported method.
 			`unexportedMethod`,               // No unexported method.
 			`unexportedTypedConstant`,        // No unexported constant.
@@ -241,7 +238,11 @@ var tests = []test{
 			`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.`,
+			`unexportedField.*int.*Comment on line with unexported field.`,
+			`ExportedEmbeddedType.*Comment on line with exported embedded field.`,
+			`\*ExportedEmbeddedType.*Comment on line with exported embedded \*field.`,
+			`unexportedType.*Comment on line with unexported embedded field.`,
+			`\*unexportedType.*Comment on line with unexported embedded \*field.`,
 			`func \(ExportedType\) unexportedMethod\(a int\) bool`,
 			`unexportedTypedConstant`,
 		},
@@ -448,7 +449,6 @@ var trimTests = []trimTest{
 	{"", "", "", true},
 	{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
 	{"/usr/gopher/bar", "/usr/gopher", "bar", true},
-	{"/usr/gopher", "/usr/gopher", "/usr/gopher", true},
 	{"/usr/gopherflakes", "/usr/gopher", "/usr/gopherflakes", false},
 	{"/usr/gopher/bar", "/usr/zot", "/usr/gopher/bar", false},
 }
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index 0b07f7c..efd681d 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -29,17 +29,15 @@ const (
 )
 
 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
+	writer   io.Writer    // Destination for output.
+	name     string       // Package name, json for encoding/json.
+	userPath string       // String the user used to find this package.
+	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.
@@ -270,7 +268,7 @@ func (pkg *Package) packageDoc() {
 	pkg.newlines(2) // Guarantee blank line before the components.
 	pkg.valueSummary(pkg.doc.Consts)
 	pkg.valueSummary(pkg.doc.Vars)
-	pkg.funcSummary(pkg.doc.Funcs)
+	pkg.funcSummary(pkg.doc.Funcs, false)
 	pkg.typeSummary()
 	pkg.bugs()
 }
@@ -310,24 +308,44 @@ func (pkg *Package) valueSummary(values []*doc.Value) {
 	}
 }
 
-// funcSummary prints a one-line summary for each function.
-func (pkg *Package) funcSummary(funcs []*doc.Func) {
+// funcSummary prints a one-line summary for each function. Constructors
+// are printed by typeSummary, below, and so can be suppressed here.
+func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
+	// First, identify the constructors. Don't bother figuring out if they're exported.
+	var isConstructor map[*doc.Func]bool
+	if !showConstructors {
+		isConstructor = make(map[*doc.Func]bool)
+		for _, typ := range pkg.doc.Types {
+			for _, constructor := range typ.Funcs {
+				isConstructor[constructor] = true
+			}
+		}
+	}
 	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)
+			if !isConstructor[fun] {
+				pkg.oneLineFunc(decl)
+			}
 		}
 	}
 }
 
-// typeSummary prints a one-line summary for each type.
+// typeSummary prints a one-line summary for each type, followed by its constructors.
 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)
+				// Now print the constructors.
+				for _, constructor := range typ.Funcs {
+					if isExported(constructor.Name) {
+						pkg.Printf(indent)
+						pkg.oneLineFunc(constructor.Decl)
+					}
+				}
 			}
 		}
 	}
@@ -455,8 +473,8 @@ func (pkg *Package) symbolDoc(symbol string) bool {
 		}
 		pkg.valueSummary(typ.Consts)
 		pkg.valueSummary(typ.Vars)
-		pkg.funcSummary(typ.Funcs)
-		pkg.funcSummary(typ.Methods)
+		pkg.funcSummary(typ.Funcs, true)
+		pkg.funcSummary(typ.Methods, true)
 		found = true
 	}
 	if !found {
@@ -487,9 +505,27 @@ func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList {
 	trimmed := false
 	list := make([]*ast.Field, 0, len(fields.List))
 	for _, field := range fields.List {
+		names := field.Names
+		if len(names) == 0 {
+			// Embedded type. Use the name of the type. It must be of type ident or *ident.
+			// Nothing else is allowed.
+			switch ident := field.Type.(type) {
+			case *ast.Ident:
+				names = []*ast.Ident{ident}
+			case *ast.StarExpr:
+				// Must have the form *identifier.
+				if ident, ok := ident.X.(*ast.Ident); ok {
+					names = []*ast.Ident{ident}
+				}
+			}
+			if names == nil {
+				// Can only happen if AST is incorrect. Safe to continue with a nil list.
+				log.Print("invalid program: unexpected type for embedded field")
+			}
+		}
 		// Trims if any is unexported. Good enough in practice.
 		ok := true
-		for _, name := range field.Names {
+		for _, name := range names {
 			if !isExported(name.Name) {
 				trimmed = true
 				ok = false
diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go
index 3e7acee..5f79414 100644
--- a/src/cmd/doc/testdata/pkg.go
+++ b/src/cmd/doc/testdata/pkg.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -60,8 +60,12 @@ func internalFunc(a int) bool
 // Comment about exported type.
 type ExportedType struct {
 	// Comment before exported field.
-	ExportedField   int // Comment on line with exported field.
-	unexportedField int // Comment on line with unexported field.
+	ExportedField         int // Comment on line with exported field.
+	unexportedField       int // Comment on line with unexported field.
+	ExportedEmbeddedType      // Comment on line with exported embedded field.
+	*ExportedEmbeddedType     // Comment on line with exported embedded *field.
+	unexportedType            // Comment on line with unexported embedded field.
+	*unexportedType           // Comment on line with unexported embedded *field.
 }
 
 // Comment about exported method.
diff --git a/src/cmd/fix/fix.go b/src/cmd/fix/fix.go
index 160336c..ab16a21 100644
--- a/src/cmd/fix/fix.go
+++ b/src/cmd/fix/fix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/fix/gotypes.go b/src/cmd/fix/gotypes.go
index 8c7b466..bb29a0c 100644
--- a/src/cmd/fix/gotypes.go
+++ b/src/cmd/fix/gotypes.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/fix/gotypes_test.go b/src/cmd/fix/gotypes_test.go
index 1ecb7a2..9248fff 100644
--- a/src/cmd/fix/gotypes_test.go
+++ b/src/cmd/fix/gotypes_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/cmd/fix/import_test.go b/src/cmd/fix/import_test.go
index 7301192..8644e28 100644
--- a/src/cmd/fix/import_test.go
+++ b/src/cmd/fix/import_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/fix/main.go b/src/cmd/fix/main.go
index dc10d6b..8b62346 100644
--- a/src/cmd/fix/main.go
+++ b/src/cmd/fix/main.go
@@ -168,7 +168,7 @@ func processFile(filename string, useStdin bool) error {
 
 	// Print AST.  We did that after each fix, so this appears
 	// redundant, but it is necessary to generate gofmt-compatible
-	// source code in a few cases.  The official gofmt style is the
+	// source code in a few cases. The official gofmt style is the
 	// output of the printer run on a standard AST generated by the parser,
 	// but the source we generated inside the loop above is the
 	// output of the printer run on a mangled AST generated by a fixer.
diff --git a/src/cmd/fix/main_test.go b/src/cmd/fix/main_test.go
index 2151bf2..c2ace28 100644
--- a/src/cmd/fix/main_test.go
+++ b/src/cmd/fix/main_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/fix/netipv6zone.go b/src/cmd/fix/netipv6zone.go
index 195c218..49cd307 100644
--- a/src/cmd/fix/netipv6zone.go
+++ b/src/cmd/fix/netipv6zone.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/cmd/fix/netipv6zone_test.go b/src/cmd/fix/netipv6zone_test.go
index 142880a..5b8d964 100644
--- a/src/cmd/fix/netipv6zone_test.go
+++ b/src/cmd/fix/netipv6zone_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/cmd/fix/printerconfig.go b/src/cmd/fix/printerconfig.go
index 432e18b..286c5f2 100644
--- a/src/cmd/fix/printerconfig.go
+++ b/src/cmd/fix/printerconfig.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/cmd/fix/printerconfig_test.go b/src/cmd/fix/printerconfig_test.go
index 72e2bdc..e485c13 100644
--- a/src/cmd/fix/printerconfig_test.go
+++ b/src/cmd/fix/printerconfig_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/cmd/fix/typecheck.go b/src/cmd/fix/typecheck.go
index d33b69f..0352c49 100644
--- a/src/cmd/fix/typecheck.go
+++ b/src/cmd/fix/typecheck.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -18,9 +18,9 @@ import (
 // The fact that it is partial is very important: the input is
 // an AST and a description of some type information to
 // assume about one or more packages, but not all the
-// packages that the program imports.  The checker is
+// packages that the program imports. The checker is
 // expected to do as much as it can with what it has been
-// given.  There is not enough information supplied to do
+// given. There is not enough information supplied to do
 // a full type check, but the type checker is expected to
 // apply information that can be derived from variable
 // declarations, function and method returns, and type switches
@@ -30,14 +30,14 @@ import (
 // TODO(rsc,gri): Replace with go/typechecker.
 // Doing that could be an interesting test case for go/typechecker:
 // the constraints about working with partial information will
-// likely exercise it in interesting ways.  The ideal interface would
+// likely exercise it in interesting ways. The ideal interface would
 // be to pass typecheck a map from importpath to package API text
 // (Go source code), but for now we use data structures (TypeConfig, Type).
 //
 // The strings mostly use gofmt form.
 //
 // A Field or FieldList has as its type a comma-separated list
-// of the types of the fields.  For example, the field list
+// of the types of the fields. For example, the field list
 //	x, y, z int
 // has type "int, int, int".
 
@@ -242,7 +242,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
 		// propagate the type to all the uses.
 		// The !isDecl case is a cheat here, but it makes
 		// up in some cases for not paying attention to
-		// struct fields.  The real type checker will be
+		// struct fields. The real type checker will be
 		// more accurate so we won't need the cheat.
 		if id, ok := n.(*ast.Ident); ok && id.Obj != nil && (isDecl || typeof[id.Obj] == "") {
 			typeof[id.Obj] = typ
@@ -367,7 +367,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
 			typeof[n] = all
 
 		case *ast.ValueSpec:
-			// var declaration.  Use type if present.
+			// var declaration. Use type if present.
 			if n.Type != nil {
 				t := typeof[n.Type]
 				if !isType(t) {
@@ -586,7 +586,7 @@ func typecheck1(cfg *TypeConfig, f interface{}, typeof map[interface{}]string, a
 
 // Convert between function type strings and lists of types.
 // Using strings makes this a little harder, but it makes
-// a lot of the rest of the code easier.  This will all go away
+// a lot of the rest of the code easier. This will all go away
 // when we can use go/typechecker directly.
 
 // splitFunc splits "func(x,y,z) (a,b,c)" into ["x", "y", "z"] and ["a", "b", "c"].
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index c81bd40..58b0d16 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -1,1575 +1,1591 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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 programs, such as build commands or
-		test binaries, 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.
-	-msan
-		enable interoperation with memory sanitizer.
-		Supported only on linux/amd64,
-		and only with Clang/LLVM as the host C compiler.
-	-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.  Likewise for the -msan
-		flag.  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>]
-	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.) However, if the argument starts with a capital
-letter it is assumed to identify a symbol or method in the current directory.
-
-For packages, the order of scanning is determined lexically in breadth-first order.
-That is, the package presented is the one that matches the search and is nearest
-the root and lexically first at its level of the hierarchy.  The GOROOT tree is
-always scanned in its entirety 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.
-
-	At least in the current tree, these invocations all print the
-	documentation for json.Decoder's Decode method:
-
-	go doc json.Decoder.Decode
-	go doc json.decoder.decode
-	go doc json.decode
-	cd go/src/encoding/json; go doc decode
-
-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] [-n] [-v] [-x] [build flags] [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 including -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 build flags, see 'go help build'.
-
-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 a new package, get creates the target directory
-GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
-get uses the first one. See 'go help gopath'.
-
-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.
-
-Unless vendoring support is disabled (see 'go help gopath'),
-when go get checks out or updates a Git repository,
-it also updates any git submodules referenced by the repository.
-
-Get never checks out or updates code stored in vendor directories.
-
-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 error information, if any, is
-
-    type PackageError struct {
-        ImportStack   []string // shortest path from package named on command line to this one
-        Pos           string   // position of error (if present, file:line:col)
-        Err           string   // the error itself
-    }
-
-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 [build/test flags] [packages] [build/test flags & test binary flags]
-
-'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:
-
-	-args
-	    Pass the remainder of the command line (everything after -args)
-	    to the test binary, uninterpreted and unchanged.
-	    Because this flag consumes the remainder of the command line,
-	    the package list (if present) must appear before this flag.
-
-	-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.
-
-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.
-
-	-buildmode=pie
-		Build the listed main packages and everything they import into
-		position independent executables (PIE). 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. GOBIN must be an absolute path.
-
-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.6 includes support for using local copies of external dependencies
-to satisfy imports of those dependencies, often referred to as vendoring.
-
-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 'go get' checks out or updates a git repository, it now also
-updates submodules.
-
-Vendor directories do not affect the placement of new repositories
-being checked out for the first time by 'go get': those are always
-placed in the main GOPATH, never in a vendor subtree.
-
-In Go 1.5, as an experiment, setting the environment variable
-GO15VENDOREXPERIMENT=1 enabled these features.
-As of Go 1.6 they are on by default. To turn them off, set
-GO15VENDOREXPERIMENT=0. In Go 1.7, the environment
-variable will stop having any effect.
-
-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 0 to disable vendoring semantics.
-	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 vendoring 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'.
-
-Packages in a program need not have unique package names,
-but there are two reserved package names with special meaning.
-The name main indicates a command, not a library.
-Commands are built into binaries and cannot be imported.
-The name documentation indicates documentation for
-a non-Go program in the directory. Files in package documentation
-are ignored by the go command.
-
-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.
-	    Note that -parallel only applies within a single test binary.
-	    The 'go test' command may run tests for different packages
-	    in parallel as well, according to the setting of the -p flag
-	    (see 'go help build').
-
-	-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.
-
-Each of these flags is also recognized with an optional 'test.' prefix,
-as in -test.v. When invoking the generated test binary (the result of
-'go test -c') directly, however, the prefix is mandatory.
-
-The 'go test' command rewrites or removes recognized flags,
-as appropriate, both before and after the optional package list,
-before invoking the test binary.
-
-For instance, the command
-
-	go test -v -myflag testdata -cpuprofile=prof.out -x
-
-will compile the test binary and then run it as
-
-	pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out
-
-(The -x flag is removed because it applies only to the go command's
-execution, not to the test itself.)
-
-The test flags that generate profiles (other than for coverage) also
-leave the test binary in pkg.test for use when analyzing the profiles.
-
-When 'go test' runs a test binary, it does so from within the
-corresponding package's source code directory. Depending on the test,
-it may be necessary to do the same when invoking a generated test
-binary directly.
-
-The command-line package list, if present, must appear before any
-flag not known to the go test command. Continuing the example above,
-the package list would have to appear before -myflag, but could appear
-on either side of -v.
-
-To keep an argument for a test binary from being interpreted as a
-known flag or a package name, use -args (see 'go help test') which
-passes the remainder of the command line through to the test binary
-uninterpreted and unaltered.
-
-For instance, the command
-
-	go test -v -args -x -v
-
-will compile the test binary and then run it as
-
-	pkg.test -test.v -x -v
-
-Similarly,
-
-	go test -args math
-
-will compile the test binary and then run it as
-
-	pkg.test math
-
-In the first example, the -x and the second -v are passed through to the
-test binary unchanged and with no effect on the go command itself.
-In the second example, the argument math is passed through to the test
-binary, instead of being interpreted as the package list.
-
-
-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.
-
-
-*/
+// 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.
+//
+// When compiling packages, build ignores files that end in '_test.go'.
+//
+// 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 programs, such as build commands or
+// 		test binaries, 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.
+// 	-msan
+// 		enable interoperation with memory sanitizer.
+// 		Supported only on linux/amd64,
+// 		and only with Clang/LLVM as the host C compiler.
+// 	-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.  Likewise for the -msan
+// 		flag.  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>]
+// 	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.) However, if the argument starts with a capital
+// letter it is assumed to identify a symbol or method in the current directory.
+//
+// For packages, the order of scanning is determined lexically in breadth-first order.
+// That is, the package presented is the one that matches the search and is nearest
+// the root and lexically first at its level of the hierarchy.  The GOROOT tree is
+// always scanned in its entirety 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.
+//
+// 	At least in the current tree, these invocations all print the
+// 	documentation for json.Decoder's Decode method:
+//
+// 	go doc json.Decoder.Decode
+// 	go doc json.decoder.decode
+// 	go doc json.decode
+// 	cd go/src/encoding/json; go doc decode
+//
+// 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] [-n] [-v] [-x] [build flags] [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 including -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 build flags, see 'go help build'.
+//
+// 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 the packages named by the import paths, along with their
+// dependencies. It then installs the named packages, like 'go install'.
+//
+// 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 a new package, get creates the target directory
+// GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
+// get uses the first one. See 'go help gopath'.
+//
+// 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.
+//
+// When go get checks out or updates a Git repository,
+// it also updates any git submodules referenced by the repository.
+//
+// Get never checks out or updates code stored in vendor directories.
+//
+// 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?
+//         StaleReason   string // explanation for Stale==true
+//         Root          string // Go root or Go path dir containing this package
+//         ConflictDir   string // this directory shadows Dir in $GOPATH
+//         BinaryOnly    bool   // binary-only package: cannot be recompiled from sources
+//
+//         // 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
+//         FFiles         []string // .f, .F, .for and .f90 Fortran 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
+//         CgoFFLAGS    []string // cgo: flags for Fortran 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 error information, if any, is
+//
+//     type PackageError struct {
+//         ImportStack   []string // shortest path from package named on command line to this one
+//         Pos           string   // position of error (if present, file:line:col)
+//         Err           string   // the error itself
+//     }
+//
+// 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 [build/test flags] [packages] [build/test flags & test binary flags]
+//
+// '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.
+//
+// The go tool will ignore a directory named "testdata", making it available
+// to hold ancillary data needed by the tests.
+//
+// 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:
+//
+// 	-args
+// 	    Pass the remainder of the command line (everything after -args)
+// 	    to the test binary, uninterpreted and unchanged.
+// 	    Because this flag consumes the remainder of the command line,
+// 	    the package list (if present) must appear before this flag.
+//
+// 	-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.
+//
+// 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.
+//
+// 	-buildmode=pie
+// 		Build the listed main packages and everything they import into
+// 		position independent executables (PIE). 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. See the go/build package documentation for
+// more details.
+//
+// Non-test Go source files can also include a //go:binary-only-package
+// comment, indicating that the package sources are included
+// for documentation only and must not be used to build the
+// package binary. This enables distribution of Go packages in
+// their compiled form alone. See the go/build package documentation
+// for more details.
+//
+//
+// 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. GOBIN must be an absolute path.
+//
+// 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.6 includes support for using local copies of external dependencies
+// to satisfy imports of those dependencies, often referred to as vendoring.
+//
+// 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 'go get' checks out or updates a git repository, it now also
+// updates submodules.
+//
+// Vendor directories do not affect the placement of new repositories
+// being checked out for the first time by 'go get': those are always
+// placed in the main GOPATH, never in a vendor subtree.
+//
+// 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.
+// 	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"
+//
+// 	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.
+//
+// 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'.
+//
+// Packages in a program need not have unique package names,
+// but there are two reserved package names with special meaning.
+// The name main indicates a command, not a library.
+// Commands are built into binaries and cannot be imported.
+// The name documentation indicates documentation for
+// a non-Go program in the directory. Files in package documentation
+// are ignored by the go command.
+//
+// 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 (sub)benchmarks matching a regular expression.
+// 	    The given regular expression is split into smaller ones by
+// 	    top-level '/', where each must match the corresponding part of a
+// 	    benchmark's identifier.
+// 	    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.
+// 	    Note that -parallel only applies within a single test binary.
+// 	    The 'go test' command may run tests for different packages
+// 	    in parallel as well, according to the setting of the -p flag
+// 	    (see 'go help build').
+//
+// 	-run regexp
+// 	    Run only those tests and examples matching the regular expression.
+// 	    For tests the regular expression is split into smaller ones by
+// 	    top-level '/', where each must match the corresponding part of a
+// 	    test's identifier.
+//
+// 	-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.
+//
+// 	-v
+// 	    Verbose output: log all tests as they are run. Also print all
+// 	    text from Log and Logf calls even if the test succeeds.
+//
+// Each of these flags is also recognized with an optional 'test.' prefix,
+// as in -test.v. When invoking the generated test binary (the result of
+// 'go test -c') directly, however, the prefix is mandatory.
+//
+// The 'go test' command rewrites or removes recognized flags,
+// as appropriate, both before and after the optional package list,
+// before invoking the test binary.
+//
+// For instance, the command
+//
+// 	go test -v -myflag testdata -cpuprofile=prof.out -x
+//
+// will compile the test binary and then run it as
+//
+// 	pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out
+//
+// (The -x flag is removed because it applies only to the go command's
+// execution, not to the test itself.)
+//
+// The test flags that generate profiles (other than for coverage) also
+// leave the test binary in pkg.test for use when analyzing the profiles.
+//
+// When 'go test' runs a test binary, it does so from within the
+// corresponding package's source code directory. Depending on the test,
+// it may be necessary to do the same when invoking a generated test
+// binary directly.
+//
+// The command-line package list, if present, must appear before any
+// flag not known to the go test command. Continuing the example above,
+// the package list would have to appear before -myflag, but could appear
+// on either side of -v.
+//
+// To keep an argument for a test binary from being interpreted as a
+// known flag or a package name, use -args (see 'go help test') which
+// passes the remainder of the command line through to the test binary
+// uninterpreted and unaltered.
+//
+// For instance, the command
+//
+// 	go test -v -args -x -v
+//
+// will compile the test binary and then run it as
+//
+// 	pkg.test -test.v -x -v
+//
+// Similarly,
+//
+// 	go test -args math
+//
+// will compile the test binary and then run it as
+//
+// 	pkg.test math
+//
+// In the first example, the -x and the second -v are passed through to the
+// test binary unchanged and with no effect on the go command itself.
+// In the second example, the argument math is passed through to the test
+// binary, instead of being interpreted as the package list.
+//
+//
+// 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.
+// If the last comment in the function starts with "Output:" then the output
+// is compared exactly against the comment (see examples below). If the last
+// comment begins with "Unordered output:" then the output is compared to the
+// comment, however the order of the lines is ignored. 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.
+// 	}
+//
+// Here is another example where the ordering of the output is ignored:
+//
+// 	func ExamplePerm() {
+// 		for _, value := range Perm(4) {
+// 			fmt.Println(value)
+// 		}
+//
+// 		// Unordered output: 4
+// 		// 2
+// 		// 1
+// 		// 3
+// 		// 0
+// 	}
+//
+// 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 1686df7..caa9676 100644
--- a/src/cmd/go/bootstrap.go
+++ b/src/cmd/go/bootstrap.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/build.go b/src/cmd/go/build.go
index f2a2a60..11a4eab 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -48,6 +48,8 @@ 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.
 
+When compiling packages, build ignores files that end in '_test.go'.
+
 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
@@ -65,8 +67,7 @@ and test commands:
 	-p n
 		the number of programs, such as build commands or
 		test binaries, that can be run in parallel.
-		The default is the number of CPUs available, except
-		on darwin/arm which defaults to 1.
+		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.
@@ -145,17 +146,6 @@ 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.
@@ -344,6 +334,11 @@ func buildModeInit() {
 			}
 			return p
 		}
+		switch platform {
+		case "darwin/arm", "darwin/arm64":
+			codegenArg = "-shared"
+		default:
+		}
 		exeSuffix = ".a"
 		ldBuildmode = "c-archive"
 	case "c-shared":
@@ -366,6 +361,9 @@ func buildModeInit() {
 		case "android/arm", "android/arm64", "android/amd64", "android/386":
 			codegenArg = "-shared"
 			ldBuildmode = "pie"
+		case "darwin/arm", "darwin/arm64":
+			codegenArg = "-shared"
+			fallthrough
 		default:
 			ldBuildmode = "exe"
 		}
@@ -377,7 +375,7 @@ func buildModeInit() {
 			fatalf("-buildmode=pie not supported by gccgo")
 		} else {
 			switch platform {
-			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le",
+			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
 				"android/amd64", "android/arm", "android/arm64", "android/386":
 				codegenArg = "-shared"
 			default:
@@ -391,7 +389,7 @@ func buildModeInit() {
 			codegenArg = "-fPIC"
 		} else {
 			switch platform {
-			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le":
+			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
 			default:
 				fatalf("-buildmode=shared not supported on %s\n", platform)
 			}
@@ -409,7 +407,7 @@ func buildModeInit() {
 			codegenArg = "-fPIC"
 		} else {
 			switch platform {
-			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le":
+			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x":
 				buildAsmflags = append(buildAsmflags, "-D=GOBUILDMODE_shared=1")
 			default:
 				fatalf("-linkshared not supported on %s\n", platform)
@@ -475,6 +473,7 @@ func runBuild(cmd *Command, args []string) {
 		p := pkgs[0]
 		p.target = *buildO
 		p.Stale = true // must build - not up to date
+		p.StaleReason = "build -o flag in use"
 		a := b.action(modeInstall, depMode, p)
 		b.do(a)
 		return
@@ -517,7 +516,7 @@ func isMetaPackage(name string) bool {
 }
 
 // libname returns the filename to use for the shared library when using
-// -buildmode=shared.  The rules we use are:
+// -buildmode=shared. The rules we use are:
 // Use arguments for special 'meta' packages:
 //	std --> libstd.so
 //	std cmd --> libstd,cmd.so
@@ -673,6 +672,12 @@ var (
 func init() {
 	goarch = buildContext.GOARCH
 	goos = buildContext.GOOS
+
+	if _, ok := osArchSupportsCgo[goos+"/"+goarch]; !ok {
+		fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", goos, goarch)
+		os.Exit(2)
+	}
+
 	if goos == "windows" {
 		exeSuffix = ".exe"
 	}
@@ -686,6 +691,7 @@ type builder struct {
 	work        string               // the temporary work directory (ends in filepath.Separator)
 	actionCache map[cacheKey]*action // a cache of already-constructed actions
 	mkdirCache  map[string]bool      // a cache of created directories
+	flagCache   map[string]bool      // a cache of supported compiler flags
 	print       func(args ...interface{}) (int, error)
 
 	output    sync.Mutex
@@ -787,7 +793,7 @@ func goFilesPackage(gofiles []string) *Package {
 
 	// Synthesize fake "directory" that only shows the named files,
 	// to make it look like this is a standard package or
-	// command directory.  So that local imports resolve
+	// command directory. So that local imports resolve
 	// consistently, the files must all be in the same directory.
 	var dirent []os.FileInfo
 	var dir string
@@ -845,6 +851,7 @@ func goFilesPackage(gofiles []string) *Package {
 
 	pkg.Target = pkg.target
 	pkg.Stale = true
+	pkg.StaleReason = "files named on command line"
 
 	computeStale(pkg)
 	return pkg
@@ -949,7 +956,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
 	// If we are not doing a cross-build, then record the binary we'll
 	// generate for cgo as a dependency of the build of any package
 	// using cgo, to make sure we do not overwrite the binary while
-	// a package is using it.  If this is a cross-build, then the cgo we
+	// 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 && !buildMSan {
 		if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !buildLinkshared && buildBuildmode != "shared" {
@@ -985,7 +992,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
 	}
 
 	if p.local && p.target == "" {
-		// Imported via local path.  No permanent target.
+		// Imported via local path. No permanent target.
 		mode = modeBuild
 	}
 	work := p.pkgdir
@@ -1033,7 +1040,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
 			// the name will show up in ps listings. If the caller has specified
 			// a name, use that instead of a.out. The binary is generated
 			// in an otherwise empty subdirectory named exe to avoid
-			// naming conflicts.  The only possible conflict is if we were
+			// naming conflicts. The only possible conflict is if we were
 			// to create a top-level package named exe.
 			name := "a.out"
 			if p.exeName != "" {
@@ -1223,10 +1230,10 @@ func (b *builder) do(root *action) {
 	// The original implementation here was a true queue
 	// (using a channel) but it had the effect of getting
 	// distracted by low-level leaf actions to the detriment
-	// of completing higher-level actions.  The order of
+	// of completing higher-level actions. The order of
 	// work does not matter much to overall execution time,
 	// but when running "go test std" it is nice to see each test
-	// results as soon as possible.  The priorities assigned
+	// results as soon as possible. The priorities assigned
 	// ensure that, all else being equal, the execution prefers
 	// to do what it would have done first in a simple depth-first
 	// dependency order traversal.
@@ -1323,18 +1330,15 @@ func (b *builder) do(root *action) {
 	wg.Wait()
 }
 
-// hasString reports whether s appears in the list of strings.
-func hasString(strings []string, s string) bool {
-	for _, t := range strings {
-		if s == t {
-			return true
-		}
-	}
-	return false
-}
-
 // build is the action for building a single package or command.
 func (b *builder) build(a *action) (err error) {
+	// Return an error for binary-only package.
+	// We only reach this if isStale believes the binary form is
+	// either not present or not usable.
+	if a.p.BinaryOnly {
+		return fmt.Errorf("missing or invalid package binary for binary-only package %s", a.p.ImportPath)
+	}
+
 	// 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.
@@ -1347,6 +1351,12 @@ func (b *builder) build(a *action) (err error) {
 		return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
 			a.p.ImportPath, strings.Join(a.p.MFiles, ","))
 	}
+	// Same as above for Fortran files
+	if len(a.p.FFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
+		return fmt.Errorf("can't build package %s because it contains Fortran files (%s) but it's not using cgo nor SWIG",
+			a.p.ImportPath, strings.Join(a.p.FFiles, ","))
+	}
+
 	defer func() {
 		if err != nil && err != errPrintedOutput {
 			err = fmt.Errorf("go build %s: %v", a.p.ImportPath, err)
@@ -1413,6 +1423,8 @@ func (b *builder) build(a *action) (err error) {
 		// cgo and non-cgo worlds, so it necessarily has files in both.
 		// In that case gcc only gets the gcc_* files.
 		var gccfiles []string
+		gccfiles = append(gccfiles, cfiles...)
+		cfiles = nil
 		if a.p.Standard && a.p.ImportPath == "runtime/cgo" {
 			filter := func(files, nongcc, gcc []string) ([]string, []string) {
 				for _, f := range files {
@@ -1424,11 +1436,9 @@ func (b *builder) build(a *action) (err error) {
 				}
 				return nongcc, gcc
 			}
-			cfiles, gccfiles = filter(cfiles, cfiles[:0], gccfiles)
 			sfiles, gccfiles = filter(sfiles, sfiles[:0], gccfiles)
 		} else {
-			gccfiles = append(cfiles, sfiles...)
-			cfiles = nil
+			gccfiles = append(gccfiles, sfiles...)
 			sfiles = nil
 		}
 
@@ -1436,10 +1446,13 @@ 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, cgofiles, gccfiles, cxxfiles, a.p.MFiles)
+		outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles, a.p.FFiles)
 		if err != nil {
 			return err
 		}
+		if _, ok := buildToolchain.(gccgoToolchain); ok {
+			cgoObjects = append(cgoObjects, filepath.Join(a.objdir, "_cgo_flags"))
+		}
 		cgoObjects = append(cgoObjects, outObj...)
 		gofiles = append(gofiles, outGo...)
 	}
@@ -1541,7 +1554,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.
+	// objects in the archive. I do not know why this is.
 	// https://golang.org/issue/2601
 	objects = append(objects, cgoObjects...)
 
@@ -1647,7 +1660,7 @@ func (b *builder) install(a *action) (err error) {
 	}
 
 	// remove object dir to keep the amount of
-	// garbage down in a large build.  On an operating system
+	// garbage down in a large build. On an operating system
 	// with aggressive buffering, cleaning incrementally like
 	// this keeps the intermediate objects from hitting the disk.
 	if !buildWork {
@@ -1792,7 +1805,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b
 	df, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
 	if err != nil && toolIsWindows {
 		// Windows does not allow deletion of a binary file
-		// while it is executing.  Try to move it out of the way.
+		// while it is executing. Try to move it out of the way.
 		// If the move fails, which is likely, we'll try again the
 		// next time we do an install of this binary.
 		if err := os.Rename(dst, dst+"~"); err == nil {
@@ -1922,7 +1935,7 @@ func (b *builder) showcmd(dir string, format string, args ...interface{}) {
 // The output is expected to contain references to 'dir', usually
 // the source directory for the package that has failed to build.
 // showOutput rewrites mentions of dir with a relative path to dir
-// when the relative path is shorter.  This is usually more pleasant.
+// when the relative path is shorter. This is usually more pleasant.
 // For example, if fmt doesn't compile and we are in src/html,
 // the output is
 //
@@ -1980,7 +1993,7 @@ func relPaths(paths []string) []string {
 // errPrintedOutput is a special error indicating that a command failed
 // but that it generated output as well, and that output has already
 // been printed, so there's no point showing 'exit status 1' or whatever
-// the wait status was.  The main executor, builder.do, knows not to
+// the wait status was. The main executor, builder.do, knows not to
 // print this error.
 var errPrintedOutput = errors.New("already printed output - no need to show error")
 
@@ -2049,7 +2062,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
 		err := cmd.Run()
 
 		// cmd.Run will fail on Unix if some other process has the binary
-		// we want to run open for writing.  This can happen here because
+		// we want to run open for writing. This can happen here because
 		// we build and install the cgo command and then run it.
 		// If another command was kicked off while we were writing the
 		// cgo binary, the child process for that command may be holding
@@ -2061,27 +2074,27 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
 		// The answer is that running a command is fork and exec.
 		// A child forked while the cgo fd is open inherits that fd.
 		// Until the child has called exec, it holds the fd open and the
-		// kernel will not let us run cgo.  Even if the child were to close
+		// kernel will not let us run cgo. Even if the child were to close
 		// the fd explicitly, it would still be open from the time of the fork
 		// until the time of the explicit close, and the race would remain.
 		//
 		// On Unix systems, this results in ETXTBSY, which formats
 		// as "text file busy".  Rather than hard-code specific error cases,
-		// we just look for that string.  If this happens, sleep a little
-		// and try again.  We let this happen three times, with increasing
+		// we just look for that string. If this happens, sleep a little
+		// and try again. We let this happen three times, with increasing
 		// sleep lengths: 100+200+400 ms = 0.7 seconds.
 		//
 		// An alternate solution might be to split the cmd.Run into
 		// separate cmd.Start and cmd.Wait, and then use an RWLock
 		// to make sure that copyFile only executes when no cmd.Start
-		// call is in progress.  However, cmd.Start (really syscall.forkExec)
+		// call is in progress. However, cmd.Start (really syscall.forkExec)
 		// only guarantees that when it returns, the exec is committed to
-		// happen and succeed.  It uses a close-on-exec file descriptor
+		// happen and succeed. It uses a close-on-exec file descriptor
 		// itself to determine this, so we know that when cmd.Start returns,
 		// at least one close-on-exec file descriptor has been closed.
 		// However, we cannot be sure that all of them have been closed,
 		// so the program might still encounter ETXTBSY even with such
-		// an RWLock.  The race window would be smaller, perhaps, but not
+		// an RWLock. The race window would be smaller, perhaps, but not
 		// guaranteed to be gone.
 		//
 		// Sleeping when we observe the race seems to be the most reliable
@@ -2131,7 +2144,7 @@ func (b *builder) mkdir(dir string) error {
 	b.exec.Lock()
 	defer b.exec.Unlock()
 	// We can be a little aggressive about being
-	// sure directories exist.  Skip repeated calls.
+	// sure directories exist. Skip repeated calls.
 	if b.mkdirCache[dir] {
 		return nil
 	}
@@ -2169,7 +2182,6 @@ func mkAbs(dir, f string) string {
 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, 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.
@@ -2271,7 +2283,7 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
 	// so that it can give good error messages about forward declarations.
 	// Exceptions: a few standard packages have forward declarations for
 	// pieces supplied behind-the-scenes by package runtime.
-	extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
+	extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
 	if p.Standard {
 		switch p.ImportPath {
 		case "bytes", "net", "os", "runtime/pprof", "sync", "time":
@@ -2315,7 +2327,15 @@ 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", "include")
 	sfile = mkAbs(p.Dir, sfile)
-	args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags, sfile}
+	args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
+	if p.ImportPath == "runtime" && goarch == "386" {
+		for _, arg := range buildAsmflags {
+			if arg == "-dynlink" {
+				args = append(args, "-D=GOBUILDMODE_shared=1")
+			}
+		}
+	}
+	args = append(args, sfile)
 	if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
 		return err
 	}
@@ -2362,8 +2382,10 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
 
 	// The archive file should have been created by the compiler.
 	// Since it used to not work that way, verify.
-	if _, err := os.Stat(absAfile); err != nil {
-		fatalf("os.Stat of archive file failed: %v", err)
+	if !buildN {
+		if _, err := os.Stat(absAfile); err != nil {
+			fatalf("os.Stat of archive file failed: %v", err)
+		}
 	}
 
 	if buildN || buildX {
@@ -2610,18 +2632,83 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
 	return b.run(p.Dir, p.ImportPath, nil, "ar", "rc", mkAbs(objDir, afile), absOfiles)
 }
 
-func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
+func (tools gccgoToolchain) link(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string, buildmode, desc string) error {
 	// gccgo needs explicit linking with all package dependencies,
 	// and all LDFLAGS from cgo dependencies.
-	apackagesSeen := make(map[*Package]bool)
+	apackagePathsSeen := make(map[string]bool)
 	afiles := []string{}
 	shlibs := []string{}
-	xfiles := []string{}
 	ldflags := b.gccArchArgs()
 	cgoldflags := []string{}
 	usesCgo := false
-	cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
-	objc := len(root.p.MFiles) > 0
+	cxx := false
+	objc := false
+	fortran := false
+	if root.p != nil {
+		cxx = len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
+		objc = len(root.p.MFiles) > 0
+		fortran = len(root.p.FFiles) > 0
+	}
+
+	readCgoFlags := func(flagsFile string) error {
+		flags, err := ioutil.ReadFile(flagsFile)
+		if err != nil {
+			return err
+		}
+		const ldflagsPrefix = "_CGO_LDFLAGS="
+		for _, line := range strings.Split(string(flags), "\n") {
+			if strings.HasPrefix(line, ldflagsPrefix) {
+				newFlags := strings.Fields(line[len(ldflagsPrefix):])
+				for _, flag := range newFlags {
+					// Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS
+					// but they don't mean anything to the linker so filter
+					// them out.
+					if flag != "-g" && !strings.HasPrefix(flag, "-O") {
+						cgoldflags = append(cgoldflags, flag)
+					}
+				}
+			}
+		}
+		return nil
+	}
+
+	readAndRemoveCgoFlags := func(archive string) (string, error) {
+		newa, err := ioutil.TempFile(b.work, filepath.Base(archive))
+		if err != nil {
+			return "", err
+		}
+		olda, err := os.Open(archive)
+		if err != nil {
+			return "", err
+		}
+		_, err = io.Copy(newa, olda)
+		if err != nil {
+			return "", err
+		}
+		err = olda.Close()
+		if err != nil {
+			return "", err
+		}
+		err = newa.Close()
+		if err != nil {
+			return "", err
+		}
+
+		newarchive := newa.Name()
+		err = b.run(b.work, desc, nil, "ar", "x", newarchive, "_cgo_flags")
+		if err != nil {
+			return "", err
+		}
+		err = b.run(".", desc, nil, "ar", "d", newarchive, "_cgo_flags")
+		if err != nil {
+			return "", err
+		}
+		err = readCgoFlags(filepath.Join(b.work, "_cgo_flags"))
+		if err != nil {
+			return "", err
+		}
+		return newarchive, nil
+	}
 
 	actionsSeen := make(map[*action]bool)
 	// Make a pre-order depth-first traversal of the action graph, taking note of
@@ -2629,6 +2716,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 	// 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)
+	var err error
 	walk = func(a *action, seenShlib bool) {
 		if actionsSeen[a] {
 			return
@@ -2643,21 +2731,18 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 			// 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 }
+			// if apackagePathsSeen[a.p.ImportPath] { return }
 			// doesn't work.
-			if !apackagesSeen[a.p] {
-				apackagesSeen[a.p] = true
-				if a.p.fake && a.p.external {
-					// external _tests, if present must come before
-					// internal _tests. Store these on a 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 {
-					afiles = append(afiles, a.target)
+			if !apackagePathsSeen[a.p.ImportPath] {
+				apackagePathsSeen[a.p.ImportPath] = true
+				target := a.target
+				if len(a.p.CgoFiles) > 0 {
+					target, err = readAndRemoveCgoFlags(target)
+					if err != nil {
+						return
+					}
 				}
+				afiles = append(afiles, target)
 			}
 		}
 		if strings.HasSuffix(a.target, ".so") {
@@ -2666,12 +2751,17 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 		}
 		for _, a1 := range a.deps {
 			walk(a1, seenShlib)
+			if err != nil {
+				return
+			}
 		}
 	}
 	for _, a1 := range root.deps {
 		walk(a1, false)
+		if err != nil {
+			return err
+		}
 	}
-	afiles = append(xfiles, afiles...)
 
 	for _, a := range allactions {
 		// Gather CgoLDFLAGS, but not from standard packages.
@@ -2696,6 +2786,17 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 		if len(a.p.MFiles) > 0 {
 			objc = true
 		}
+		if len(a.p.FFiles) > 0 {
+			fortran = true
+		}
+	}
+
+	for i, o := range ofiles {
+		if filepath.Base(o) == "_cgo_flags" {
+			readCgoFlags(o)
+			ofiles = append(ofiles[:i], ofiles[i+1:]...)
+			break
+		}
 	}
 
 	ldflags = append(ldflags, "-Wl,--whole-archive")
@@ -2704,7 +2805,9 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 
 	ldflags = append(ldflags, cgoldflags...)
 	ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
-	ldflags = append(ldflags, root.p.CgoLDFLAGS...)
+	if root.p != nil {
+		ldflags = append(ldflags, root.p.CgoLDFLAGS...)
+	}
 
 	ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
 
@@ -2719,7 +2822,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 	}
 
 	var realOut string
-	switch ldBuildmode {
+	switch buildmode {
 	case "exe":
 		if usesCgo && goos == "linux" {
 			ldflags = append(ldflags, "-Wl,-E")
@@ -2735,7 +2838,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 		// initialization code.
 		//
 		// The user remains responsible for linking against
-		// -lgo -lpthread -lm in the final link.  We can't use
+		// -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
@@ -2754,12 +2857,14 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 
 	case "c-shared":
 		ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc")
+	case "shared":
+		ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
 
 	default:
-		fatalf("-buildmode=%s not supported for gccgo", ldBuildmode)
+		fatalf("-buildmode=%s not supported for gccgo", buildmode)
 	}
 
-	switch ldBuildmode {
+	switch buildmode {
 	case "exe", "c-shared":
 		if cxx {
 			ldflags = append(ldflags, "-lstdc++")
@@ -2767,43 +2872,40 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 		if objc {
 			ldflags = append(ldflags, "-lobjc")
 		}
+		if fortran {
+			fc := os.Getenv("FC")
+			if fc == "" {
+				fc = "gfortran"
+			}
+			// support gfortran out of the box and let others pass the correct link options
+			// via CGO_LDFLAGS
+			if strings.Contains(fc, "gfortran") {
+				ldflags = append(ldflags, "-lgfortran")
+			}
+		}
 	}
 
-	if err := b.run(".", root.p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
+	if err := b.run(".", desc, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
 		return err
 	}
 
-	switch ldBuildmode {
+	switch buildmode {
 	case "c-archive":
-		if err := b.run(".", root.p.ImportPath, nil, "ar", "rc", realOut, out); err != nil {
+		if err := b.run(".", desc, nil, "ar", "rc", realOut, out); err != nil {
 			return err
 		}
 	}
 	return nil
 }
 
+func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
+	return tools.link(b, root, out, allactions, mainpkg, ofiles, ldBuildmode, root.p.ImportPath)
+}
+
 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)
-		}
-	}
-	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)
+	fakeRoot := &action{}
+	fakeRoot.deps = toplevelactions
+	return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out)
 }
 
 func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
@@ -2861,6 +2963,11 @@ func (b *builder) gxx(p *Package, out string, flags []string, cxxfile string) er
 	return b.ccompile(p, out, flags, cxxfile, b.gxxCmd(p.Dir))
 }
 
+// gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file.
+func (b *builder) gfortran(p *Package, out string, flags []string, ffile string) error {
+	return b.ccompile(p, out, flags, ffile, b.gfortranCmd(p.Dir))
+}
+
 // ccompile runs the given C or C++ compiler and creates an object from a single source file.
 func (b *builder) ccompile(p *Package, out string, flags []string, file string, compiler []string) error {
 	file = mkAbs(p.Dir, file)
@@ -2890,6 +2997,11 @@ func (b *builder) gxxCmd(objdir string) []string {
 	return b.ccompilerCmd("CXX", defaultCXX, objdir)
 }
 
+// gfortranCmd returns a gfortran command line prefix.
+func (b *builder) gfortranCmd(objdir string) []string {
+	return b.ccompilerCmd("FC", "gfortran", objdir)
+}
+
 // ccompilerCmd returns a command line prefix for the given environment
 // variable and using the default command when the variable is empty.
 func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
@@ -2927,6 +3039,17 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
 	// disable word wrapping in error messages
 	a = append(a, "-fmessage-length=0")
 
+	// Tell gcc not to include the work directory in object files.
+	if b.gccSupportsFlag("-fdebug-prefix-map=a=b") {
+		a = append(a, "-fdebug-prefix-map="+b.work+"=/tmp/go-build")
+	}
+
+	// Tell gcc not to include flags in object files, which defeats the
+	// point of -fdebug-prefix-map above.
+	if b.gccSupportsFlag("-gno-record-gcc-switches") {
+		a = append(a, "-gno-record-gcc-switches")
+	}
+
 	// 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 https://golang.org/issue/3253.
@@ -2941,19 +3064,24 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
 // -no-pie must be passed when doing a partial link with -Wl,-r. But -no-pie is
 // not supported by all compilers.
 func (b *builder) gccSupportsNoPie() bool {
-	if goos != "linux" {
-		// On some BSD platforms, error messages from the
-		// compiler make it to the console despite cmd.Std*
-		// all being nil. As -no-pie is only required on linux
-		// systems so far, we only test there.
-		return false
+	return b.gccSupportsFlag("-no-pie")
+}
+
+// gccSupportsFlag checks to see if the compiler supports a flag.
+func (b *builder) gccSupportsFlag(flag string) bool {
+	b.exec.Lock()
+	defer b.exec.Unlock()
+	if b, ok := b.flagCache[flag]; ok {
+		return b
 	}
-	src := filepath.Join(b.work, "trivial.c")
-	if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
-		return false
+	if b.flagCache == nil {
+		src := filepath.Join(b.work, "trivial.c")
+		if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
+			return false
+		}
+		b.flagCache = make(map[string]bool)
 	}
-	cmdArgs := b.gccCmd(b.work)
-	cmdArgs = append(cmdArgs, "-no-pie", "-c", "trivial.c")
+	cmdArgs := append(envList("CC", defaultCC), flag, "-c", "trivial.c")
 	if buildN || buildX {
 		b.showcmd(b.work, "%s", joinUnambiguously(cmdArgs))
 		if buildN {
@@ -2962,9 +3090,11 @@ func (b *builder) gccSupportsNoPie() bool {
 	}
 	cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
 	cmd.Dir = b.work
-	cmd.Env = envForDir(cmd.Dir, os.Environ())
+	cmd.Env = mergeEnvLists([]string{"LC_ALL=C"}, envForDir(cmd.Dir, os.Environ()))
 	out, err := cmd.CombinedOutput()
-	return err == nil && !bytes.Contains(out, []byte("unrecognized"))
+	supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
+	b.flagCache[flag] = supported
+	return supported
 }
 
 // gccArchArgs returns arguments to pass to gcc based on the architecture.
@@ -2976,6 +3106,10 @@ func (b *builder) gccArchArgs() []string {
 		return []string{"-m64"}
 	case "arm":
 		return []string{"-marm"} // not thumb
+	case "s390x":
+		return []string{"-m64", "-march=z196"}
+	case "mips64", "mips64le":
+		return []string{"-mabi=64"}
 	}
 	return nil
 }
@@ -2990,8 +3124,8 @@ func envList(key, def string) []string {
 	return strings.Fields(v)
 }
 
-// Return the flags to use when invoking the C or C++ compilers, or cgo.
-func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
+// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
+func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
 	var defaults string
 	if def {
 		defaults = "-g -O2"
@@ -3000,15 +3134,16 @@ func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldfl
 	cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
 	cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
 	cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
+	fflags = stringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS)
 	ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
 	return
 }
 
 var cgoRe = regexp.MustCompile(`[/\\:]`)
 
-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)
+func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
+	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p, true)
+	_, cgoexeCFLAGS, _, _, _ := b.cflags(p, false)
 	cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
 	cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
 	// If we are compiling Objective-C code, then we need to link against libobjc
@@ -3016,6 +3151,19 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 		cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
 	}
 
+	// Likewise for Fortran, except there are many Fortran compilers.
+	// Support gfortran out of the box and let others pass the correct link options
+	// via CGO_LDFLAGS
+	if len(ffiles) > 0 {
+		fc := os.Getenv("FC")
+		if fc == "" {
+			fc = "gfortran"
+		}
+		if strings.Contains(fc, "gfortran") {
+			cgoLDFLAGS = append(cgoLDFLAGS, "-lgfortran")
+		}
+	}
+
 	if buildMSan && p.ImportPath != "runtime/cgo" {
 		cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
 		cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
@@ -3120,7 +3268,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 		case strings.HasPrefix(f, "-fsanitize="):
 			continue
 		// runpath flags not applicable unless building a shared
-		// object or executable; see issue 12115 for details.  This
+		// object or executable; see issue 12115 for details. This
 		// is necessary as Go currently does not offer a way to
 		// specify the set of LDFLAGS that only apply to shared
 		// objects.
@@ -3183,6 +3331,17 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 		outObj = append(outObj, ofile)
 	}
 
+	fflags := stringList(cgoCPPFLAGS, cgoFFLAGS)
+	for _, file := range ffiles {
+		// Append .o to the file, just in case the pkg has file.c and file.f
+		ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+		if err := b.gfortran(p, ofile, fflags, file); err != nil {
+			return nil, nil, err
+		}
+		linkobj = append(linkobj, ofile)
+		outObj = append(outObj, ofile)
+	}
+
 	linkobj = append(linkobj, p.SysoFiles...)
 	dynobj := obj + "_cgo_.o"
 	pie := (goarch == "arm" && goos == "linux") || goos == "android"
@@ -3348,6 +3507,13 @@ func (b *builder) swigVersionCheck() error {
 	return swigCheck
 }
 
+// Find the value to pass for the -intgosize option to swig.
+var (
+	swigIntSizeOnce  sync.Once
+	swigIntSize      string
+	swigIntSizeError error
+)
+
 // This code fails to build if sizeof(int) <= 32
 const swigIntSizeCode = `
 package main
@@ -3355,8 +3521,8 @@ const i int = 1 << 32
 `
 
 // Determine the size of int on the target system for the -intgosize option
-// of swig >= 2.0.9
-func (b *builder) swigIntSize(obj string) (intsize string, err error) {
+// of swig >= 2.0.9.  Run only once.
+func (b *builder) swigDoIntSize(obj string) (intsize string, err error) {
 	if buildN {
 		return "$INTBITS", nil
 	}
@@ -3374,9 +3540,18 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
 	return "64", nil
 }
 
+// Determine the size of int on the target system for the -intgosize option
+// of swig >= 2.0.9.
+func (b *builder) swigIntSize(obj string) (intsize string, err error) {
+	swigIntSizeOnce.Do(func() {
+		swigIntSize, swigIntSizeError = b.swigDoIntSize(obj)
+	})
+	return swigIntSize, swigIntSizeError
+}
+
 // Run SWIG on one SWIG input file.
 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)
+	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p, true)
 	var cflags []string
 	if cxx {
 		cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
@@ -3444,12 +3619,12 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
 
 // 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
+// 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
+// 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
+// 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 {
diff --git a/src/cmd/go/clean.go b/src/cmd/go/clean.go
index 16054a5..7b07150 100644
--- a/src/cmd/go/clean.go
+++ b/src/cmd/go/clean.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/context.go b/src/cmd/go/context.go
index 68e5182..94cd54d 100644
--- a/src/cmd/go/context.go
+++ b/src/cmd/go/context.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -26,6 +26,7 @@ func newContext(c *build.Context) *Context {
 		GOARCH:        c.GOARCH,
 		GOOS:          c.GOOS,
 		GOROOT:        c.GOROOT,
+		GOPATH:        c.GOPATH,
 		CgoEnabled:    c.CgoEnabled,
 		UseAllFiles:   c.UseAllFiles,
 		Compiler:      c.Compiler,
diff --git a/src/cmd/go/discovery.go b/src/cmd/go/discovery.go
index f6992e9..b60eaef 100644
--- a/src/cmd/go/discovery.go
+++ b/src/cmd/go/discovery.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 9b8b8df..8299839 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -1,7 +1,9 @@
-// Copyright 2015 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.
 
+//go:generate ./mkalldocs.sh
+
 package main
 
 var cmdDoc = &Command{
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 24f6127..8aaaf46 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -33,11 +33,6 @@ func mkEnv() []envVar {
 	var b builder
 	b.init()
 
-	vendorExpValue := "0"
-	if go15VendorExperiment {
-		vendorExpValue = "1"
-	}
-
 	env := []envVar{
 		{"GOARCH", goarch},
 		{"GOBIN", gobin},
@@ -49,7 +44,6 @@ func mkEnv() []envVar {
 		{"GORACE", os.Getenv("GORACE")},
 		{"GOROOT", goroot},
 		{"GOTOOLDIR", toolDir},
-		{"GO15VENDOREXPERIMENT", vendorExpValue},
 
 		// disable escape codes in clang errors
 		{"TERM", "dumb"},
diff --git a/src/cmd/go/fix.go b/src/cmd/go/fix.go
index 94fd22e..3af7adb 100644
--- a/src/cmd/go/fix.go
+++ b/src/cmd/go/fix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/go/fmt.go b/src/cmd/go/fmt.go
index 57c02ad..4ed7722 100644
--- a/src/cmd/go/fmt.go
+++ b/src/cmd/go/fmt.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/go/generate.go b/src/cmd/go/generate.go
index cb54018..3c6065e 100644
--- a/src/cmd/go/generate.go
+++ b/src/cmd/go/generate.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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,10 +14,8 @@ import (
 	"os/exec"
 	"path/filepath"
 	"regexp"
-	"runtime"
 	"strconv"
 	"strings"
-	"unicode"
 )
 
 var cmdGenerate = &Command{
@@ -277,8 +275,8 @@ func isGoGenerate(buf []byte) bool {
 // single go:generate command.
 func (g *Generator) setEnv() {
 	g.env = []string{
-		"GOARCH=" + runtime.GOARCH,
-		"GOOS=" + runtime.GOOS,
+		"GOARCH=" + buildContext.GOARCH,
+		"GOOS=" + buildContext.GOOS,
 		"GOFILE=" + g.file,
 		"GOLINE=" + strconv.Itoa(g.lineNum),
 		"GOPACKAGE=" + g.pkg,
@@ -371,17 +369,6 @@ func (g *Generator) expandVar(word string) string {
 	return os.Getenv(word)
 }
 
-// identLength returns the length of the identifier beginning the string.
-func (g *Generator) identLength(word string) int {
-	for i, r := range word {
-		if r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) {
-			continue
-		}
-		return i
-	}
-	return len(word)
-}
-
 // setShorthand installs a new shorthand as defined by a -command directive.
 func (g *Generator) setShorthand(words []string) {
 	// Create command shorthand.
diff --git a/src/cmd/go/generate_test.go b/src/cmd/go/generate_test.go
index ba06692..dd116e6 100644
--- a/src/cmd/go/generate_test.go
+++ b/src/cmd/go/generate_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/go/get.go b/src/cmd/go/get.go
index 9d4b94a..19858f7 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -19,8 +19,8 @@ var cmdGet = &Command{
 	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,
-along with their dependencies.
+Get downloads the packages named by the import paths, along with their
+dependencies. It then installs the named packages, like 'go install'.
 
 The -d flag instructs get to stop after downloading the packages; that is,
 it instructs get not to install the packages.
@@ -45,7 +45,7 @@ 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 a new package, get creates the target directory 
+When checking out a new package, get creates the target directory
 GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
 get uses the first one. See 'go help gopath'.
 
@@ -55,8 +55,7 @@ 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.
 
-Unless vendoring support is disabled (see 'go help gopath'),
-when go get checks out or updates a Git repository,
+When go get checks out or updates a Git repository,
 it also updates any git submodules referenced by the repository.
 
 Get never checks out or updates code stored in vendor directories.
@@ -112,7 +111,7 @@ func runGet(cmd *Command, args []string) {
 
 	// Code we downloaded and all code that depends on it
 	// needs to be evicted from the package cache so that
-	// the information will be recomputed.  Instead of keeping
+	// the information will be recomputed. Instead of keeping
 	// track of the reverse dependency information, evict
 	// everything.
 	for name := range packageCache {
@@ -142,7 +141,7 @@ func runGet(cmd *Command, args []string) {
 }
 
 // downloadPaths prepares the list of paths to pass to download.
-// It expands ... patterns that can be expanded.  If there is no match
+// It expands ... patterns that can be expanded. If there is no match
 // for a particular pattern, downloadPaths leaves it in the result list,
 // in the hope that we can figure out the repository from the
 // initial ...-free prefix.
@@ -153,7 +152,7 @@ func downloadPaths(args []string) []string {
 		if strings.Contains(a, "...") {
 			var expand []string
 			// Use matchPackagesInFS to avoid printing
-			// warnings.  They will be printed by the
+			// warnings. They will be printed by the
 			// eventual call to importPaths instead.
 			if build.IsLocalImport(a) {
 				expand = matchPackagesInFS(a)
@@ -236,16 +235,6 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
 			stk.pop()
 			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}
@@ -355,8 +344,8 @@ func downloadPackage(p *Package) error {
 	}
 
 	if p.build.SrcRoot != "" {
-		// Directory exists.  Look for checkout along path to src.
-		vcs, rootPath, err = vcsForDir(p)
+		// Directory exists. Look for checkout along path to src.
+		vcs, rootPath, err = vcsFromDir(p.Dir, p.build.SrcRoot)
 		if err != nil {
 			return err
 		}
@@ -364,7 +353,7 @@ func downloadPackage(p *Package) error {
 
 		// Double-check where it came from.
 		if *getU && vcs.remoteRepo != nil {
-			dir := filepath.Join(p.build.SrcRoot, rootPath)
+			dir := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
 			remote, err := vcs.remoteRepo(vcs, dir)
 			if err != nil {
 				return err
@@ -399,7 +388,7 @@ func downloadPackage(p *Package) error {
 	}
 
 	if p.build.SrcRoot == "" {
-		// Package not found.  Put in first directory of $GOPATH.
+		// Package not found. Put in first directory of $GOPATH.
 		list := filepath.SplitList(buildContext.GOPATH)
 		if len(list) == 0 {
 			return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath")
@@ -411,7 +400,7 @@ func downloadPackage(p *Package) error {
 		p.build.SrcRoot = filepath.Join(list[0], "src")
 		p.build.PkgRoot = filepath.Join(list[0], "pkg")
 	}
-	root := filepath.Join(p.build.SrcRoot, rootPath)
+	root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
 	// If we've considered this repository already, don't do it again.
 	if downloadRootCache[root] {
 		return nil
@@ -430,7 +419,7 @@ func downloadPackage(p *Package) error {
 		return fmt.Errorf("%s exists but is not a directory", meta)
 	}
 	if err != nil {
-		// Metadata directory does not exist.  Prepare to checkout new copy.
+		// Metadata directory does not exist. Prepare to checkout new copy.
 		// Some version control tools require the target directory not to exist.
 		// We require that too, just to avoid stepping on existing work.
 		if _, err := os.Stat(root); err == nil {
diff --git a/src/cmd/go/go11.go b/src/cmd/go/go11.go
index 8a434df..7e383f4 100644
--- a/src/cmd/go/go11.go
+++ b/src/cmd/go/go11.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index acf4a39..66c6413 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -109,7 +109,7 @@ func TestMain(m *testing.M) {
 	os.Exit(r)
 }
 
-// The length of an mtime tick on this system.  This is an estimate of
+// 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.
 // We used to try to be clever but that didn't always work (see golang.org/issue/12205).
@@ -181,7 +181,7 @@ func (tg *testgoData) pwd() string {
 	return wd
 }
 
-// cd changes the current directory to the named directory.  Note that
+// 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) {
@@ -325,7 +325,7 @@ func (tg *testgoData) getStderr() string {
 }
 
 // doGrepMatch looks for a regular expression in a buffer, and returns
-// whether it is found.  The regular expression is matched against
+// 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 {
@@ -341,7 +341,7 @@ func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool {
 }
 
 // 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
+// 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) {
@@ -375,7 +375,7 @@ func (tg *testgoData) grepBoth(match, msg string) {
 }
 
 // doGrepNot looks for a regular expression in a buffer and fails if
-// it is found.  The name and msg arguments are as for doGrep.
+// 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)
@@ -421,18 +421,6 @@ func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int {
 	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 {
@@ -440,8 +428,8 @@ func (tg *testgoData) grepCountBoth(match string) int {
 }
 
 // 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
+// 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) {
@@ -457,7 +445,7 @@ func (tg *testgoData) creatingTemp(path string) {
 	tg.temps = append(tg.temps, path)
 }
 
-// makeTempdir makes a temporary directory for a run of testgo.  If
+// 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 == "" {
@@ -501,6 +489,16 @@ func (tg *testgoData) path(name string) string {
 	return filepath.Join(tg.tempdir, name)
 }
 
+// mustExist fails if path does not exist.
+func (tg *testgoData) mustExist(path string) {
+	if _, err := os.Stat(path); err != nil {
+		if os.IsNotExist(err) {
+			tg.t.Fatalf("%s does not exist but should", path)
+		}
+		tg.t.Fatalf("%s stat failed: %v", path, err)
+	}
+}
+
 // mustNotExist fails if path exists.
 func (tg *testgoData) mustNotExist(path string) {
 	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
@@ -536,32 +534,43 @@ func (tg *testgoData) wantArchive(path string) {
 	}
 }
 
-// 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")
+// isStale reports whether pkg is stale, and why
+func (tg *testgoData) isStale(pkg string) (bool, string) {
+	tg.run("list", "-f", "{{.Stale}}:{{.StaleReason}}", pkg)
+	v := strings.TrimSpace(tg.getStdout())
+	f := strings.SplitN(v, ":", 2)
+	if len(f) == 2 {
+		switch f[0] {
+		case "true":
+			return true, f[1]
+		case "false":
+			return false, f[1]
+		}
 	}
+	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) {
+func (tg *testgoData) wantStale(pkg, reason, msg string) {
+	stale, why := tg.isStale(pkg)
+	if !stale {
 		tg.t.Fatal(msg)
 	}
+	if reason == "" && why != "" || !strings.Contains(why, reason) {
+		tg.t.Errorf("wrong reason for Stale=true: %q, want %q", why, reason)
+	}
 }
 
 // wantNotStale fails with msg if pkg is stale.
-func (tg *testgoData) wantNotStale(pkg, msg string) {
-	if tg.isStale(pkg) {
+func (tg *testgoData) wantNotStale(pkg, reason, msg string) {
+	stale, why := tg.isStale(pkg)
+	if stale {
 		tg.t.Fatal(msg)
 	}
+	if reason == "" && why != "" || !strings.Contains(why, reason) {
+		tg.t.Errorf("wrong reason for Stale=false: %q, want %q", why, reason)
+	}
 }
 
 // cleanup cleans up a test that runs testgo.
@@ -581,32 +590,6 @@ func (tg *testgoData) cleanup() {
 	}
 }
 
-// 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() {
@@ -720,7 +703,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
 	tg.tempFile("d1/src/p1/p1.go", `package p1`)
 	tg.setenv("GOPATH", tg.path("d1"))
 	tg.run("install", "-a", "p1")
-	tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly")
+	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly")
 	tg.sleep()
 
 	// Changing mtime and content of runtime/internal/sys/sys.go
@@ -729,28 +712,28 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
 	sys := runtime.GOROOT() + "/src/runtime/internal/sys/sys.go"
 	restore := addNL(sys)
 	defer restore()
-	tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly, after updating runtime/internal/sys/sys.go")
+	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after updating runtime/internal/sys/sys.go")
 	restore()
-	tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly, after restoring runtime/internal/sys/sys.go")
+	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after restoring runtime/internal/sys/sys.go")
 
 	// But changing runtime/internal/sys/zversion.go should have an effect:
 	// that's how we tell when we flip from one release to another.
 	zversion := runtime.GOROOT() + "/src/runtime/internal/sys/zversion.go"
 	restore = addNL(zversion)
 	defer restore()
-	tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly, after changing to new release")
+	tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to new release")
 	restore()
-	tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")
+	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly, after changing back to old release")
 	addNL(zversion)
-	tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly, after changing again to new release")
+	tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing again to new release")
 	tg.run("install", "p1")
-	tg.wantNotStale("p1", "./testgo list claims p1 is stale after building with new release")
+	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with new release")
 
 	// Restore to "old" release.
 	restore()
-	tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly, after changing to old release after new build")
+	tg.wantStale("p1", "build ID mismatch", "./testgo list claims p1 is NOT stale, incorrectly, after changing to old release after new build")
 	tg.run("install", "p1")
-	tg.wantNotStale("p1", "./testgo list claims p1 is stale after building with old release")
+	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release")
 
 	// Everything is out of date. Rebuild to leave things in a better state.
 	tg.run("install", "std")
@@ -833,8 +816,8 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
 	sep := string(filepath.ListSeparator)
 	tg.setenv("GOPATH", tg.path("d1")+sep+tg.path("d2"))
 	tg.run("install", "p1")
-	tg.wantNotStale("p1", "./testgo list claims p1 is stale, incorrectly")
-	tg.wantNotStale("p2", "./testgo list claims p2 is stale, incorrectly")
+	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale, incorrectly")
+	tg.wantNotStale("p2", "", "./testgo list 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)
@@ -843,12 +826,12 @@ func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
 	} else {
 		tg.must(f.Close())
 	}
-	tg.wantStale("p2", "./testgo list claims p2 is NOT stale, incorrectly")
-	tg.wantStale("p1", "./testgo list claims p1 is NOT stale, incorrectly")
+	tg.wantStale("p2", "newer source file", "./testgo list claims p2 is NOT stale, incorrectly")
+	tg.wantStale("p1", "stale dependency", "./testgo list claims p1 is NOT stale, incorrectly")
 
 	tg.run("install", "p1")
-	tg.wantNotStale("p2", "./testgo list claims p2 is stale after reinstall, incorrectly")
-	tg.wantNotStale("p1", "./testgo list claims p1 is stale after reinstall, incorrectly")
+	tg.wantNotStale("p2", "", "./testgo list claims p2 is stale after reinstall, incorrectly")
+	tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after reinstall, incorrectly")
 }
 
 func TestGoInstallDetectsRemovedFiles(t *testing.T) {
@@ -862,13 +845,13 @@ func TestGoInstallDetectsRemovedFiles(t *testing.T) {
 		package mypkg`)
 	tg.setenv("GOPATH", tg.path("."))
 	tg.run("install", "mypkg")
-	tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale, incorrectly")
+	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")
+	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")
+	tg.wantStale("mypkg", "build ID mismatch", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
 }
 
 func TestWildcardMatchesSyntaxErrorDirs(t *testing.T) {
@@ -931,13 +914,13 @@ func TestGoInstallDetectsRemovedFilesInPackageMain(t *testing.T) {
 		package main`)
 	tg.setenv("GOPATH", tg.path("."))
 	tg.run("install", "mycmd")
-	tg.wantNotStale("mycmd", "./testgo list mypkg claims mycmd is stale, incorrectly")
+	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")
+	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")
+	tg.wantStale("mycmd", "build ID mismatch", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale")
 }
 
 func testLocalRun(tg *testgoData, exepath, local, match string) {
@@ -1105,8 +1088,8 @@ func testMove(t *testing.T, vcs, url, base, config string) {
 	}
 	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
+		// 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() {}`)
@@ -1178,7 +1161,7 @@ func TestImportCommentConflict(t *testing.T) {
 	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.
+// cmd/go: custom import path checking should not apply to Go packages without import comment.
 func TestIssue10952(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 	if _, err := exec.LookPath("git"); err != nil {
@@ -1193,11 +1176,38 @@ func TestIssue10952(t *testing.T) {
 	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)
 }
 
+// Test git clone URL that uses SCP-like syntax and custom import path checking.
+func TestIssue11457(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/rsc/go-get-issue-11457"
+	tg.run("get", "-d", "-u", importPath)
+	repoDir := tg.path("src/" + importPath)
+	tg.runGit(repoDir, "remote", "set-url", "origin", "git at github.com:rsc/go-get-issue-11457")
+
+	// At this time, custom import path checking compares remotes verbatim (rather than
+	// just the host and path, skipping scheme and user), so we expect go get -u to fail.
+	// However, the goal of this test is to verify that gitRemoteRepo correctly parsed
+	// the SCP-like syntax, and we expect it to appear in the error message.
+	tg.runFail("get", "-d", "-u", importPath)
+	want := " is checked out from ssh://git@github.com/rsc/go-get-issue-11457"
+	if !strings.HasSuffix(strings.TrimSpace(tg.getStderr()), want) {
+		t.Error("expected clone URL to appear in stderr")
+	}
+}
+
 func TestGetGitDefaultBranch(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 	if _, err := exec.LookPath("git"); err != nil {
@@ -1217,7 +1227,6 @@ func TestGetGitDefaultBranch(t *testing.T) {
 
 	tg.run("get", "-d", importPath)
 	repoDir := tg.path("src/" + importPath)
-	defer tg.resetReadOnlyFlagAll(repoDir)
 	tg.runGit(repoDir, "branch", "--contains", "HEAD")
 	tg.grepStdout(`\* another-branch`, "not on correct default branch")
 
@@ -1226,14 +1235,6 @@ func TestGetGitDefaultBranch(t *testing.T) {
 	tg.grepStdout(`\* another-branch`, "not on correct default branch")
 }
 
-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()
@@ -1337,19 +1338,35 @@ func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
 	tg.sleep()
 	tg.run("test", "main_test")
 	tg.run("install", "main_test")
-	tg.wantNotStale("main_test", "after go install, main listed as stale")
+	tg.wantNotStale("main_test", "", "after go install, main listed as stale")
 	tg.run("test", "main_test")
 }
 
+// The runtime version string takes one of two forms:
+// "go1.X[.Y]" for Go releases, and "devel +hash" at tip.
+// Determine whether we are in a released copy by
+// inspecting the version.
+var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
+
 // Issue 12690
 func TestPackageNotStaleWithTrailingSlash(t *testing.T) {
 	tg := testgo(t)
 	defer tg.cleanup()
+
+	// Make sure the packages below are not stale.
+	tg.run("install", "runtime", "os", "io")
+
 	goroot := runtime.GOROOT()
 	tg.setenv("GOROOT", goroot+"/")
-	tg.wantNotStale("runtime", "with trailing slash in GOROOT, runtime listed as stale")
-	tg.wantNotStale("os", "with trailing slash in GOROOT, os listed as stale")
-	tg.wantNotStale("io", "with trailing slash in GOROOT, io listed as stale")
+
+	want := ""
+	if isGoRelease {
+		want = "standard package in Go release distribution"
+	}
+
+	tg.wantNotStale("runtime", want, "with trailing slash in GOROOT, runtime listed as stale")
+	tg.wantNotStale("os", want, "with trailing slash in GOROOT, os listed as stale")
+	tg.wantNotStale("io", want, "with trailing slash in GOROOT, io listed as stale")
 }
 
 // With $GOBIN set, binaries get installed to $GOBIN.
@@ -1397,28 +1414,6 @@ func TestInstallToGOBINCommandLinePackage(t *testing.T) {
 	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)
 
@@ -1508,7 +1503,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
 	defer tg.cleanup()
 	tg.parallel()
 	tg.run("test", "errors", "errors", "errors", "errors", "errors")
-	if strings.Index(strings.TrimSpace(tg.getStdout()), "\n") != -1 {
+	if strings.Contains(strings.TrimSpace(tg.getStdout()), "\n") {
 		t.Error("go test errors errors errors errors errors tested the same package multiple times")
 	}
 }
@@ -1537,7 +1532,7 @@ func TestGoListCmdOnlyShowsCommands(t *testing.T) {
 	tg.run("list", "cmd")
 	out := strings.TrimSpace(tg.getStdout())
 	for _, line := range strings.Split(out, "\n") {
-		if strings.Index(line, "cmd/") == -1 {
+		if !strings.Contains(line, "cmd/") {
 			t.Error("go list cmd shows non-commands")
 			break
 		}
@@ -1657,8 +1652,8 @@ func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
 		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`)
+	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) {
@@ -1726,7 +1721,6 @@ func TestSymlinksVendor(t *testing.T) {
 
 	tg := testgo(t)
 	defer tg.cleanup()
-	tg.setenv("GO15VENDOREXPERIMENT", "1")
 	tg.tempDir("gopath/src/dir1/vendor/v")
 	tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `v`\nfunc main(){}")
 	tg.tempFile("gopath/src/dir1/vendor/v/v.go", "package v")
@@ -1879,7 +1873,9 @@ func TestShadowingLogic(t *testing.T) {
 	}
 	// The output will have makeImportValid applies, but we only
 	// bother to deal with characters we might reasonably see.
-	pwdForwardSlash = strings.Replace(pwdForwardSlash, ":", "_", -1)
+	for _, r := range " :" {
+		pwdForwardSlash = strings.Replace(pwdForwardSlash, string(r), "_", -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)
@@ -2001,6 +1997,27 @@ func TestCoverageUsesActualSettingToOverrideEvenForRace(t *testing.T) {
 	checkCoverage(tg, data)
 }
 
+func TestBuildDryRunWithCgo(t *testing.T) {
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempFile("foo.go", `package main
+
+/*
+#include <limits.h>
+*/
+import "C"
+
+func main() {
+        println(C.INT_MAX)
+}`)
+	tg.run("build", "-n", tg.path("foo.go"))
+	tg.grepStderrNot(`os.Stat .* no such file or directory`, "unexpected stat of archive file")
+}
+
 func TestCoverageWithCgo(t *testing.T) {
 	if !canCgo {
 		t.Skip("skipping because cgo not enabled")
@@ -2106,10 +2123,33 @@ func main() { C.f() }`)
 	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}}")
+func TestListTemplateContextFunction(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	for _, tt := range []struct {
+		v    string
+		want string
+	}{
+		{"GOARCH", runtime.GOARCH},
+		{"GOOS", runtime.GOOS},
+		{"GOROOT", filepath.Clean(runtime.GOROOT())},
+		{"GOPATH", os.Getenv("GOPATH")},
+		{"CgoEnabled", ""},
+		{"UseAllFiles", ""},
+		{"Compiler", ""},
+		{"BuildTags", ""},
+		{"ReleaseTags", ""},
+		{"InstallSuffix", ""},
+	} {
+		tmpl := "{{context." + tt.v + "}}"
+		tg.run("list", "-f", tmpl)
+		if tt.want == "" {
+			continue
+		}
+		if got := strings.TrimSpace(tg.getStdout()); got != tt.want {
+			t.Errorf("go list -f %q: got %q; want %q", tmpl, got, tt.want)
+		}
+	}
 }
 
 // cmd/go: "go test" should fail if package does not build
@@ -2123,7 +2163,7 @@ func TestIssue7108(t *testing.T) {
 // 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")
+		t.Skip("don't rebuild the standard library in short mode")
 	}
 
 	tg := testgo(t)
@@ -2295,8 +2335,7 @@ func TestGoVetWithExternalTests(t *testing.T) {
 	tg := testgo(t)
 	defer tg.cleanup()
 	tg.makeTempdir()
-	tg.setenv("GOPATH", tg.path("."))
-	tg.run("get", "golang.org/x/tools/cmd/vet")
+	tg.run("install", "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")
@@ -2308,8 +2347,7 @@ func TestGoVetWithTags(t *testing.T) {
 	tg := testgo(t)
 	defer tg.cleanup()
 	tg.makeTempdir()
-	tg.setenv("GOPATH", tg.path("."))
-	tg.run("get", "golang.org/x/tools/cmd/vet")
+	tg.run("install", "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")
@@ -2330,6 +2368,11 @@ func TestGoGetRscIoToolstash(t *testing.T) {
 // Issue 13037: Was not parsing <meta> tags in 404 served over HTTPS
 func TestGoGetHTTPS404(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
+	switch runtime.GOOS {
+	case "darwin", "linux", "freebsd":
+	default:
+		t.Skipf("test case does not work on %s", runtime.GOOS)
+	}
 
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -2338,7 +2381,7 @@ func TestGoGetHTTPS404(t *testing.T) {
 	tg.run("get", "bazil.org/fuse/fs/fstestutil")
 }
 
-// Test that you can not import a main package.
+// Test that you cannot import a main package.
 func TestIssue4210(t *testing.T) {
 	tg := testgo(t)
 	defer tg.cleanup()
@@ -2359,6 +2402,8 @@ func TestIssue4210(t *testing.T) {
 func TestGoGetInsecure(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
+	t.Skip("golang.org/issue/15410")
+
 	tg := testgo(t)
 	defer tg.cleanup()
 	tg.makeTempdir()
@@ -2414,22 +2459,6 @@ func TestGoGetInsecureCustomDomain(t *testing.T) {
 	tg.run("get", "-d", "-insecure", repo)
 }
 
-func TestIssue10193(t *testing.T) {
-	t.Skip("depends on code.google.com")
-	testenv.MustHaveExternalNetwork(t)
-	if _, err := exec.LookPath("hg"); err != nil {
-		t.Skip("skipping because hg binary not found")
-	}
-
-	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()
@@ -2760,6 +2789,37 @@ func TestParallelTest(t *testing.T) {
 	tg.run("test", "-p=4", "p1", "p2", "p3", "p4")
 }
 
+func TestCgoConsistentResults(t *testing.T) {
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+	if runtime.GOOS == "solaris" {
+		// See https://golang.org/issue/13247
+		t.Skip("skipping because Solaris builds are known to be inconsistent; see #13247")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	exe1 := tg.path("cgotest1" + exeSuffix)
+	exe2 := tg.path("cgotest2" + exeSuffix)
+	tg.run("build", "-o", exe1, "cgotest")
+	tg.run("build", "-x", "-o", exe2, "cgotest")
+	b1, err := ioutil.ReadFile(exe1)
+	tg.must(err)
+	b2, err := ioutil.ReadFile(exe2)
+	tg.must(err)
+
+	if !tg.doGrepMatch(`-fdebug-prefix-map=\$WORK`, &tg.stderr) {
+		t.Skip("skipping because C compiler does not support -fdebug-prefix-map")
+	}
+	if !bytes.Equal(b1, b2) {
+		t.Error("building cgotest twice did not produce the same output")
+	}
+}
+
 // Issue 14444: go get -u .../ duplicate loads errors
 func TestGoGetUpdateAllDoesNotTryToLoadDuplicates(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
@@ -2771,3 +2831,126 @@ func TestGoGetUpdateAllDoesNotTryToLoadDuplicates(t *testing.T) {
 	tg.run("get", "-u", ".../")
 	tg.grepStderrNot("duplicate loads of", "did not remove old packages from cache")
 }
+
+func TestFatalInBenchmarkCauseNonZeroExitStatus(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.runFail("test", "-bench", ".", "./testdata/src/benchfatal")
+	tg.grepBothNot("^ok", "test passed unexpectedly")
+	tg.grepBoth("FAIL.*benchfatal", "test did not run everything")
+}
+
+func TestBinaryOnlyPackages(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+
+	tg.tempFile("src/p1/p1.go", `//go:binary-only-package
+
+		package p1
+	`)
+	tg.wantStale("p1", "cannot access install target", "p1 is binary-only but has no binary, should be stale")
+	tg.runFail("install", "p1")
+	tg.grepStderr("missing or invalid package binary", "did not report attempt to compile binary-only package")
+
+	tg.tempFile("src/p1/p1.go", `
+		package p1
+		import "fmt"
+		func F(b bool) { fmt.Printf("hello from p1\n"); if b { F(false) } }
+	`)
+	tg.run("install", "p1")
+	os.Remove(tg.path("src/p1/p1.go"))
+	tg.mustNotExist(tg.path("src/p1/p1.go"))
+
+	tg.tempFile("src/p2/p2.go", `//go:binary-only-packages-are-not-great
+
+		package p2
+		import "p1"
+		func F() { p1.F(true) }
+	`)
+	tg.runFail("install", "p2")
+	tg.grepStderr("no buildable Go source files", "did not complain about missing sources")
+
+	tg.tempFile("src/p1/missing.go", `//go:binary-only-package
+
+		package p1
+		func G()
+	`)
+	tg.wantNotStale("p1", "no source code", "should NOT want to rebuild p1 (first)")
+	tg.run("install", "-x", "p1") // no-op, up to date
+	tg.grepBothNot("/compile", "should not have run compiler")
+	tg.run("install", "p2") // does not rebuild p1 (or else p2 will fail)
+	tg.wantNotStale("p2", "", "should NOT want to rebuild p2")
+
+	// changes to the non-source-code do not matter,
+	// and only one file needs the special comment.
+	tg.tempFile("src/p1/missing2.go", `
+		package p1
+		func H()
+	`)
+	tg.wantNotStale("p1", "no source code", "should NOT want to rebuild p1 (second)")
+	tg.wantNotStale("p2", "", "should NOT want to rebuild p2")
+
+	tg.tempFile("src/p3/p3.go", `
+		package main
+		import (
+			"p1"
+			"p2"
+		)
+		func main() {
+			p1.F(false)
+			p2.F()
+		}
+	`)
+	tg.run("install", "p3")
+
+	tg.run("run", tg.path("src/p3/p3.go"))
+	tg.grepStdout("hello from p1", "did not see message from p1")
+}
+
+// Issue 16050.
+func TestAlwaysLinkSysoFiles(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("src/syso")
+	tg.tempFile("src/syso/a.syso", ``)
+	tg.tempFile("src/syso/b.go", `package syso`)
+	tg.setenv("GOPATH", tg.path("."))
+
+	// We should see the .syso file regardless of the setting of
+	// CGO_ENABLED.
+
+	tg.setenv("CGO_ENABLED", "1")
+	tg.run("list", "-f", "{{.SysoFiles}}", "syso")
+	tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=1")
+
+	tg.setenv("CGO_ENABLED", "0")
+	tg.run("list", "-f", "{{.SysoFiles}}", "syso")
+	tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")
+}
+
+// Issue 16120.
+func TestGenerateUsesBuildContext(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("this test won't run under Windows")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("src/gen")
+	tg.tempFile("src/gen/gen.go", "package gen\n//go:generate echo $GOOS $GOARCH\n")
+	tg.setenv("GOPATH", tg.path("."))
+
+	tg.setenv("GOOS", "linux")
+	tg.setenv("GOARCH", "amd64")
+	tg.run("generate", "gen")
+	tg.grepStdout("linux amd64", "unexpected GOOS/GOARCH combination")
+
+	tg.setenv("GOOS", "darwin")
+	tg.setenv("GOARCH", "386")
+	tg.run("generate", "gen")
+	tg.grepStdout("darwin 386", "unexpected GOOS/GOARCH combination")
+}
diff --git a/src/cmd/go/go_unix_test.go b/src/cmd/go/go_unix_test.go
index 0d85859..c445a2e 100644
--- a/src/cmd/go/go_unix_test.go
+++ b/src/cmd/go/go_unix_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index d8e7efe..056a0af 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -149,14 +149,6 @@ A few common code hosting sites have special syntax:
 		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"
@@ -269,10 +261,9 @@ 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 vendoring 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.
+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.
 	`,
@@ -421,12 +412,6 @@ Vendor directories do not affect the placement of new repositories
 being checked out for the first time by 'go get': those are always
 placed in the main GOPATH, never in a vendor subtree.
 
-In Go 1.5, as an experiment, setting the environment variable
-GO15VENDOREXPERIMENT=1 enabled these features.
-As of Go 1.6 they are on by default. To turn them off, set
-GO15VENDOREXPERIMENT=0. In Go 1.7, the environment
-variable will stop having any effect.
-
 See https://golang.org/s/go15vendor for details.
 	`,
 }
@@ -497,8 +482,6 @@ Special-purpose environment variables:
 		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 0 to disable vendoring semantics.
 	GO_EXTLINK_ENABLED
 		Whether the linker should use external linking mode
 		when using -linkmode=auto with code that uses cgo.
@@ -540,7 +523,15 @@ the extension of the file name. These extensions are:
 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.
+line comment. See the go/build package documentation for
+more details.
+
+Non-test Go source files can also include a //go:binary-only-package
+comment, indicating that the package sources are included
+for documentation only and must not be used to build the
+package binary. This enables distribution of Go packages in
+their compiled form alone. See the go/build package documentation
+for more details.
 	`,
 }
 
diff --git a/src/cmd/go/http.go b/src/cmd/go/http.go
index 3a6f19d..05ea503 100644
--- a/src/cmd/go/http.go
+++ b/src/cmd/go/http.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -30,7 +30,7 @@ var httpClient = http.DefaultClient
 // when we're connecting to https servers that might not be there
 // or might be using self-signed certificates.
 var impatientInsecureHTTPClient = &http.Client{
-	Timeout: time.Duration(5 * time.Second),
+	Timeout: 5 * time.Second,
 	Transport: &http.Transport{
 		TLSClientConfig: &tls.Config{
 			InsecureSkipVerify: true,
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index 8f741a6..48678e7 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -41,7 +41,10 @@ syntax of package template.  The default output is equivalent to -f
         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?
+        StaleReason   string // explanation for Stale==true
         Root          string // Go root or Go path dir containing this package
+        ConflictDir   string // this directory shadows Dir in $GOPATH
+        BinaryOnly    bool   // binary-only package: cannot be recompiled from sources
 
         // Source files
         GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
@@ -51,6 +54,7 @@ syntax of package template.  The default output is equivalent to -f
         CXXFiles       []string // .cc, .cxx and .cpp source files
         MFiles         []string // .m source files
         HFiles         []string // .h, .hh, .hpp and .hxx source files
+        FFiles         []string // .f, .F, .for and .f90 Fortran source files
         SFiles         []string // .s source files
         SwigFiles      []string // .swig files
         SwigCXXFiles   []string // .swigcxx files
@@ -60,6 +64,7 @@ syntax of package template.  The default output is equivalent to -f
         CgoCFLAGS    []string // cgo: flags for C compiler
         CgoCPPFLAGS  []string // cgo: flags for C preprocessor
         CgoCXXFLAGS  []string // cgo: flags for C++ compiler
+        CgoFFLAGS    []string // cgo: flags for Fortran compiler
         CgoLDFLAGS   []string // cgo: flags for linker
         CgoPkgConfig []string // cgo: pkg-config names
 
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index f9b979d..65ec61b 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -214,15 +214,7 @@ var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
 {{end}}{{.Long | trim}}
 `
 
-var documentationTemplate = `// 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.
-
-/*
-{{range .}}{{if .Short}}{{.Short | capitalize}}
+var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
 
 {{end}}{{if .Runnable}}Usage:
 
@@ -231,9 +223,39 @@ var documentationTemplate = `// Copyright 2011 The Go Authors.  All rights reser
 {{end}}{{.Long | trim}}
 
 
-{{end}}*/
-package main
-`
+{{end}}`
+
+// commentWriter writes a Go comment to the underlying io.Writer,
+// using line comment form (//).
+type commentWriter struct {
+	W            io.Writer
+	wroteSlashes bool // Wrote "//" at the beginning of the current line.
+}
+
+func (c *commentWriter) Write(p []byte) (int, error) {
+	var n int
+	for i, b := range p {
+		if !c.wroteSlashes {
+			s := "//"
+			if b != '\n' {
+				s = "// "
+			}
+			if _, err := io.WriteString(c.W, s); err != nil {
+				return n, err
+			}
+			c.wroteSlashes = true
+		}
+		n0, err := c.W.Write(p[i : i+1])
+		n += n0
+		if err != nil {
+			return n, err
+		}
+		if b == '\n' {
+			c.wroteSlashes = false
+		}
+	}
+	return len(p), nil
+}
 
 // An errWriter wraps a writer, recording whether a write error occurred.
 type errWriter struct {
@@ -310,10 +332,18 @@ func help(args []string) {
 
 	// 'go help documentation' generates doc.go.
 	if arg == "documentation" {
+		fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.")
+		fmt.Println("// Use of this source code is governed by a BSD-style")
+		fmt.Println("// license that can be found in the LICENSE file.")
+		fmt.Println()
+		fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.")
+		fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
+		fmt.Println()
 		buf := new(bytes.Buffer)
 		printUsage(buf)
 		usage := &Command{Long: buf.String()}
-		tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
+		tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*Command{usage}, commands...))
+		fmt.Println("package main")
 		return
 	}
 
@@ -339,7 +369,7 @@ func importPathsNoDotExpansion(args []string) []string {
 	for _, a := range args {
 		// Arguments are supposed to be import paths, but
 		// as a courtesy to Windows developers, rewrite \ to /
-		// in command-line arguments.  Handles .\... and so on.
+		// in command-line arguments. Handles .\... and so on.
 		if filepath.Separator == '\\' {
 			a = strings.Replace(a, `\`, `/`, -1)
 		}
@@ -403,8 +433,6 @@ func errorf(format string, args ...interface{}) {
 	setExitStatus(1)
 }
 
-var logf = log.Printf
-
 func exitIfErrors() {
 	if exitStatus != 0 {
 		exit()
@@ -428,19 +456,6 @@ func run(cmdargs ...interface{}) {
 	}
 }
 
-func runOut(dir string, cmdargs ...interface{}) []byte {
-	cmdline := stringList(cmdargs...)
-	cmd := exec.Command(cmdline[0], cmdline[1:]...)
-	cmd.Dir = dir
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		os.Stderr.Write(out)
-		errorf("%v", err)
-		out = nil
-	}
-	return out
-}
-
 // envForDir returns a copy of the environment
 // suitable for running in the given directory.
 // The environment is the current process's environment
@@ -472,7 +487,7 @@ NextVar:
 }
 
 // matchPattern(pattern)(name) reports whether
-// name matches pattern.  Pattern is a limited glob
+// name matches pattern. Pattern is a limited glob
 // pattern in which '...' means 'any string' and there
 // is no other special syntax.
 func matchPattern(pattern string) func(name string) bool {
@@ -629,7 +644,7 @@ func matchPackages(pattern string) []string {
 
 // allPackagesInFS is like allPackages but is passed a pattern
 // beginning ./ or ../, meaning it should scan the tree rooted
-// at the given directory.  There are ... in the pattern too.
+// at the given directory. There are ... in the pattern too.
 func allPackagesInFS(pattern string) []string {
 	pkgs := matchPackagesInFS(pattern)
 	if len(pkgs) == 0 {
diff --git a/src/cmd/go/match_test.go b/src/cmd/go/match_test.go
index 38b9b11..e0ad562 100644
--- a/src/cmd/go/match_test.go
+++ b/src/cmd/go/match_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/mkalldocs.sh b/src/cmd/go/mkalldocs.sh
index 74e3125..72886db 100755
--- a/src/cmd/go/mkalldocs.sh
+++ b/src/cmd/go/mkalldocs.sh
@@ -1,12 +1,11 @@
 #!/bin/bash
-# Copyright 2012 The Go Authors.  All rights reserved.
+# 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
+./go.latest help documentation >alldocs.go
 gofmt -w alldocs.go
 rm go.latest
-
diff --git a/src/cmd/go/note.go b/src/cmd/go/note.go
index f846eeb..fae9536 100644
--- a/src/cmd/go/note.go
+++ b/src/cmd/go/note.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -71,7 +71,7 @@ func readELFNote(filename, name string, typ int32) ([]byte, error) {
 var elfGoNote = []byte("Go\x00\x00")
 
 // 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
+// header. The caller has already opened filename, to get f, and read
 // at least 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 data, already read.
@@ -110,7 +110,7 @@ func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string,
 			// or even the first few megabytes of the file
 			// due to differences in note segment placement;
 			// in that case, extract the note data manually.
-			_, err = f.Seek(int64(p.Off), 0)
+			_, err = f.Seek(int64(p.Off), io.SeekStart)
 			if err != nil {
 				return "", err
 			}
diff --git a/src/cmd/go/note_test.go b/src/cmd/go/note_test.go
index 811734b..2ee013f 100644
--- a/src/cmd/go/note_test.go
+++ b/src/cmd/go/note_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -47,8 +47,6 @@ func testNoteReading(t *testing.T) {
 		t.Skipf("skipping - no cgo, so assuming external linking not available")
 	case runtime.GOOS == "linux" && (runtime.GOARCH == "ppc64le" || runtime.GOARCH == "ppc64"):
 		t.Skipf("skipping - external linking not supported, golang.org/issue/11184")
-	case runtime.GOOS == "linux" && (runtime.GOARCH == "mips64le" || runtime.GOARCH == "mips64"):
-		t.Skipf("skipping - external linking not supported, golang.org/issue/12560")
 	case runtime.GOOS == "openbsd" && runtime.GOARCH == "arm":
 		t.Skipf("skipping - external linking not supported, golang.org/issue/10619")
 	case runtime.GOOS == "plan9":
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 599c2b4..07aa3ff 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -27,8 +27,8 @@ import (
 // A Package describes a single package found in a directory.
 type Package struct {
 	// Note: These fields are part of the go command's public API.
-	// See list.go.  It is okay to add fields, but not to change or
-	// remove existing ones.  Keep in sync with list.go
+	// See list.go. It is okay to add fields, but not to change or
+	// remove existing ones. Keep in sync with list.go
 	Dir           string `json:",omitempty"` // directory containing package sources
 	ImportPath    string `json:",omitempty"` // import path of package in dir
 	ImportComment string `json:",omitempty"` // path in import comment on package statement
@@ -39,8 +39,10 @@ type Package struct {
 	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?
+	StaleReason   string `json:",omitempty"` // why is Stale true?
 	Root          string `json:",omitempty"` // Go root or Go path dir containing this package
 	ConflictDir   string `json:",omitempty"` // Dir is hidden by this other directory
+	BinaryOnly    bool   `json:",omitempty"` // package cannot be recompiled
 
 	// Source files
 	GoFiles        []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
@@ -50,6 +52,7 @@ type Package struct {
 	CXXFiles       []string `json:",omitempty"` // .cc, .cpp and .cxx source files
 	MFiles         []string `json:",omitempty"` // .m source files
 	HFiles         []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files
+	FFiles         []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files
 	SFiles         []string `json:",omitempty"` // .s source files
 	SwigFiles      []string `json:",omitempty"` // .swig files
 	SwigCXXFiles   []string `json:",omitempty"` // .swigcxx files
@@ -59,6 +62,7 @@ type Package struct {
 	CgoCFLAGS    []string `json:",omitempty"` // cgo: flags for C compiler
 	CgoCPPFLAGS  []string `json:",omitempty"` // cgo: flags for C preprocessor
 	CgoCXXFLAGS  []string `json:",omitempty"` // cgo: flags for C++ compiler
+	CgoFFLAGS    []string `json:",omitempty"` // cgo: flags for Fortran compiler
 	CgoLDFLAGS   []string `json:",omitempty"` // cgo: flags for linker
 	CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names
 
@@ -88,7 +92,6 @@ type Package struct {
 	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
 	local        bool                 // imported via local path (./ or ../)
@@ -151,6 +154,8 @@ func (p *Package) copyBuild(pp *build.Package) {
 	p.Doc = pp.Doc
 	p.Root = pp.Root
 	p.ConflictDir = pp.ConflictDir
+	p.BinaryOnly = pp.BinaryOnly
+
 	// TODO? Target
 	p.Goroot = pp.Goroot
 	p.Standard = p.Goroot && p.ImportPath != "" && isStandardImportPath(p.ImportPath)
@@ -161,6 +166,7 @@ func (p *Package) copyBuild(pp *build.Package) {
 	p.CXXFiles = pp.CXXFiles
 	p.MFiles = pp.MFiles
 	p.HFiles = pp.HFiles
+	p.FFiles = pp.FFiles
 	p.SFiles = pp.SFiles
 	p.SwigFiles = pp.SwigFiles
 	p.SwigCXXFiles = pp.SwigCXXFiles
@@ -205,7 +211,7 @@ func (p *PackageError) Error() string {
 		return fmt.Sprintf("%s\npackage %s\n", p.Err, strings.Join(p.ImportStack, "\n\timports "))
 	}
 	if p.Pos != "" {
-		// Omit import stack.  The full path to the file where the error
+		// Omit import stack. The full path to the file where the error
 		// is the most important thing.
 		return p.Pos + ": " + p.Err
 	}
@@ -263,18 +269,9 @@ func reloadPackage(arg string, stk *importStack) *Package {
 	return loadPackage(arg, stk)
 }
 
-// The Go 1.5 vendoring experiment was enabled by setting GO15VENDOREXPERIMENT=1.
-// In Go 1.6 this is on by default and is disabled by setting GO15VENDOREXPERIMENT=0.
-// In Go 1.7 the variable will stop having any effect.
-// 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.
-// There is a copy of this variable in src/go/build/build.go. Delete that one when this one goes away.
-var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") != "0"
-
 // 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
+// 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
 // the pseudo-import path is _/c_/home/gopher/my/pkg.
 // Using a pseudo-import path like this makes the ./ imports no longer
 // a special case, so that all the code to deal with ordinary imports works
@@ -361,7 +358,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
 	// TODO: After Go 1, decide when to pass build.AllowBinary here.
 	// See issue 3268 for mistakes to avoid.
 	buildMode := build.ImportComment
-	if !go15VendorExperiment || mode&useVendor == 0 || path != origPath {
+	if mode&useVendor == 0 || path != origPath {
 		// Not vendoring, or we already found the vendored path.
 		buildMode |= build.IgnoreVendor
 	}
@@ -371,7 +368,7 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
 		bp.BinDir = gobin
 	}
 	if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
-		(!go15VendorExperiment || (!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/"))) {
+		!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)
@@ -412,7 +409,7 @@ func isDir(path string) bool {
 // x/vendor/path, vendor/path, or else stay path if none of those exist.
 // vendoredImportPath returns the expanded path or, if no expansion is found, the original.
 func vendoredImportPath(parent *Package, path string) (found string) {
-	if parent == nil || parent.Root == "" || !go15VendorExperiment {
+	if parent == nil || parent.Root == "" {
 		return path
 	}
 
@@ -484,7 +481,7 @@ func hasGoFiles(dir string) bool {
 }
 
 // reusePackage reuses package p to satisfy the import at the top
-// of the import stack stk.  If this use causes an import loop,
+// of the import stack stk. If this use causes an import loop,
 // reusePackage updates p's error information to record the loop.
 func reusePackage(p *Package, stk *importStack) *Package {
 	// We use p.imports==nil to detect a package that
@@ -530,7 +527,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
 		return p
 	}
 
-	// Check for "internal" element: four cases depending on begin of string and/or end of string.
+	// Check for "internal" element: three cases depending on begin of string and/or end of string.
 	i, ok := findInternal(p.ImportPath)
 	if !ok {
 		return p
@@ -567,7 +564,7 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
 // If there isn't one, findInternal returns ok=false.
 // Otherwise, findInternal returns ok=true and the index of the "internal".
 func findInternal(path string) (index int, ok bool) {
-	// Four cases, depending on internal at start/end of string or not.
+	// Three cases, depending on internal at start/end of string or not.
 	// The order matters: we must return the index of the final element,
 	// because the final one produces the most restrictive requirement
 	// on the importer.
@@ -586,10 +583,6 @@ func findInternal(path string) (index int, ok bool) {
 // 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
@@ -669,7 +662,7 @@ func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Pack
 
 // 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".
+// Otherwise, findVendor 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).
@@ -693,7 +686,6 @@ type targetDir int
 const (
 	toRoot    targetDir = iota // to bin dir inside package root (default)
 	toTool                     // GOROOT/pkg/tool
-	toBin                      // GOROOT/bin
 	stalePath                  // the old import path; fail to build
 )
 
@@ -717,7 +709,6 @@ var goTools = map[string]targetDir{
 	"cmd/trace":                            toTool,
 	"cmd/vet":                              toTool,
 	"cmd/yacc":                             toTool,
-	"golang.org/x/tools/cmd/godoc":         toBin,
 	"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,
@@ -731,7 +722,7 @@ func expandScanner(err error) error {
 		// Prepare error with \n before each message.
 		// When printed in something like context: %v
 		// this will put the leading file positions each on
-		// its own line.  It will also show all the errors
+		// its own line. It will also show all the errors
 		// instead of just the first, as err.Error does.
 		var buf bytes.Buffer
 		for _, e := range err {
@@ -804,12 +795,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 			// Install cross-compiled binaries to subdirectories of bin.
 			elem = full
 		}
-		if p.build.BinDir != gobin && goTools[p.ImportPath] == toBin {
-			// Override BinDir.
-			// This is from a subrepo but installs to $GOROOT/bin
-			// by default anyway (like godoc).
-			p.target = filepath.Join(gorootBin, elem)
-		} else if p.build.BinDir != "" {
+		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 != "" {
@@ -928,6 +914,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		p.CXXFiles,
 		p.MFiles,
 		p.HFiles,
+		p.FFiles,
 		p.SFiles,
 		p.SysoFiles,
 		p.SwigFiles,
@@ -1027,6 +1014,20 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 	}
 	p.Target = p.target
 
+	// If cgo is not enabled, ignore cgo supporting sources
+	// just as we ignore go files containing import "C".
+	if !buildContext.CgoEnabled {
+		p.CFiles = nil
+		p.CXXFiles = nil
+		p.MFiles = nil
+		p.SwigFiles = nil
+		p.SwigCXXFiles = nil
+		// Note that SFiles are okay (they go to the Go assembler)
+		// and HFiles are okay (they might be used by the SFiles).
+		// Also Sysofiles are okay (they might not contain object
+		// code; see issue #16050).
+	}
+
 	// 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{
@@ -1049,7 +1050,15 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		}
 	}
 
-	computeBuildID(p)
+	if p.BinaryOnly {
+		// For binary-only package, use build ID from supplied package binary.
+		buildID, err := readBuildID(p)
+		if err == nil {
+			p.buildID = buildID
+		}
+	} else {
+		computeBuildID(p)
+	}
 	return p
 }
 
@@ -1089,7 +1098,7 @@ func packageList(roots []*Package) []*Package {
 // at the named pkgs (command-line arguments).
 func computeStale(pkgs ...*Package) {
 	for _, p := range packageList(pkgs) {
-		p.Stale = isStale(p)
+		p.Stale, p.StaleReason = isStale(p)
 	}
 }
 
@@ -1235,7 +1244,7 @@ var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
 // 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
+// recompute the build 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.
 //
@@ -1360,40 +1369,50 @@ var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
 // 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) bool {
+// isStale reports whether package p needs to be rebuilt,
+// along with the reason why.
+func isStale(p *Package) (bool, string) {
 	if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
 		// fake, builtin package
-		return false
+		return false, "builtin package"
 	}
 	if p.Error != nil {
-		return true
+		return true, "errors loading package"
+	}
+	if p.Stale {
+		return true, p.StaleReason
 	}
 
-	// A package without Go sources means we only found
-	// the installed .a file.  Since we don't know how to rebuild
-	// it, it can't be stale, even if -a is set.  This enables binary-only
-	// distributions of Go packages, although such binaries are
-	// only useful with the specific version of the toolchain that
-	// created them.
-	if len(p.gofiles) == 0 && !p.usesSwig() {
-		return false
+	// If this is a package with no source code, it cannot be rebuilt.
+	// If the binary is missing, we mark the package stale so that
+	// if a rebuild is needed, that rebuild attempt will produce a useful error.
+	// (Some commands, such as 'go list', do not attempt to rebuild.)
+	if p.BinaryOnly {
+		if p.target == "" {
+			// Fail if a build is attempted.
+			return true, "no source code for package, but no install target"
+		}
+		if _, err := os.Stat(p.target); err != nil {
+			// Fail if a build is attempted.
+			return true, "no source code for package, but cannot access install target: " + err.Error()
+		}
+		return false, "no source code for package"
 	}
 
 	// If the -a flag is given, rebuild everything.
 	if buildA {
-		return true
+		return true, "build -a flag in use"
 	}
 
-	// If there's no install target or it's already marked stale, we have to rebuild.
-	if p.target == "" || p.Stale {
-		return true
+	// If there's no install target, we have to rebuild.
+	if p.target == "" {
+		return true, "no install target"
 	}
 
 	// Package is stale if completely unbuilt.
 	fi, err := os.Stat(p.target)
 	if err != nil {
-		return true
+		return true, "cannot stat install target"
 	}
 
 	// Package is stale if the expected build ID differs from the
@@ -1406,13 +1425,13 @@ func isStale(p *Package) bool {
 	// See issue 8290 and issue 10702.
 	targetBuildID, err := readBuildID(p)
 	if err == nil && targetBuildID != p.buildID {
-		return true
+		return true, "build ID mismatch"
 	}
 
 	// Package is stale if a dependency is.
 	for _, p1 := range p.deps {
 		if p1.Stale {
-			return true
+			return true, "stale dependency"
 		}
 	}
 
@@ -1435,7 +1454,7 @@ func isStale(p *Package) bool {
 	// install is to run make.bash, which will remove the old package archives
 	// before rebuilding.)
 	if p.Standard && isGoRelease {
-		return false
+		return false, "standard package in Go release distribution"
 	}
 
 	// Time-based staleness.
@@ -1450,14 +1469,14 @@ func isStale(p *Package) bool {
 	// Package is stale if a dependency is, or if a dependency is newer.
 	for _, p1 := range p.deps {
 		if p1.target != "" && olderThan(p1.target) {
-			return true
+			return true, "newer dependency"
 		}
 	}
 
 	// As a courtesy to developers installing new versions of the compiler
 	// frequently, define that packages are stale if they are
 	// older than the compiler, and commands if they are older than
-	// the linker.  This heuristic will not work if the binaries are
+	// the linker. This heuristic will not work if the binaries are
 	// back-dated, as some binary distributions may do, but it does handle
 	// a very common case.
 	// See issue 3036.
@@ -1469,10 +1488,10 @@ func isStale(p *Package) bool {
 	// taken care of above (at least when the installed Go is a released version).
 	if p.Root != goroot {
 		if olderThan(buildToolchain.compiler()) {
-			return true
+			return true, "newer compiler"
 		}
 		if p.build.IsCommand() && olderThan(buildToolchain.linker()) {
-			return true
+			return true, "newer linker"
 		}
 	}
 
@@ -1514,14 +1533,14 @@ func isStale(p *Package) bool {
 	// 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)
+	srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.FFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
 	for _, src := range srcs {
 		if olderThan(filepath.Join(p.Dir, src)) {
-			return true
+			return true, "newer source file"
 		}
 	}
 
-	return false
+	return false, ""
 }
 
 // computeBuildID computes the build ID for p, leaving it in p.buildID.
@@ -1579,7 +1598,7 @@ var cwd, _ = os.Getwd()
 var cmdCache = map[string]*Package{}
 
 // loadPackage is like loadImport but is used for command-line arguments,
-// not for paths found in import statements.  In addition to ordinary import paths,
+// not for paths found in import statements. In addition to ordinary import paths,
 // loadPackage accepts pseudo-paths beginning with cmd/ to denote commands
 // in the Go command directory, as well as paths to those directories.
 func loadPackage(arg string, stk *importStack) *Package {
@@ -1643,7 +1662,7 @@ func loadPackage(arg string, stk *importStack) *Package {
 // command line arguments 'args'.  If a named package
 // cannot be loaded at all (for example, if the directory does not exist),
 // then packages prints an error and does not include that
-// package in the results.  However, if errors occur trying
+// package in the results. However, if errors occur trying
 // to load dependencies of a named package, the named
 // package is still returned, with p.Incomplete = true
 // and details in p.DepsErrors.
diff --git a/src/cmd/go/pkg_test.go b/src/cmd/go/pkg_test.go
index 1e7ca2c..fba1363 100644
--- a/src/cmd/go/pkg_test.go
+++ b/src/cmd/go/pkg_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -161,9 +161,12 @@ func TestSharedLibName(t *testing.T) {
 				}
 				oldGopath := buildContext.GOPATH
 				defer func() {
-					os.RemoveAll(tmpGopath)
 					buildContext.GOPATH = oldGopath
 					os.Chdir(cwd)
+					err := os.RemoveAll(tmpGopath)
+					if err != nil {
+						t.Error(err)
+					}
 				}()
 				root := filepath.Join(tmpGopath, "src", data.rootedAt)
 				err = os.MkdirAll(root, 0755)
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
index bf10f4f..18387b5 100644
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -128,7 +128,7 @@ func runRun(cmd *Command, args []string) {
 }
 
 // runProgram is the action for running a binary that has already
-// been compiled.  We ignore exit status.
+// been compiled. We ignore exit status.
 func (b *builder) runProgram(a *action) error {
 	cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
 	if buildN || buildX {
diff --git a/src/cmd/go/tag_test.go b/src/cmd/go/tag_test.go
index ffe218c..6649bd6 100644
--- a/src/cmd/go/tag_test.go
+++ b/src/cmd/go/tag_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/go/test.go b/src/cmd/go/test.go
index 995ba14..e1527da 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -59,6 +59,9 @@ 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.
 
+The go tool will ignore a directory named "testdata", making it available
+to hold ancillary data needed by the tests.
+
 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.
 
@@ -125,7 +128,10 @@ control the execution of any test:
 
 const testFlag2 = `
 	-bench regexp
-	    Run benchmarks matching the regular expression.
+	    Run (sub)benchmarks matching a regular expression.
+	    The given regular expression is split into smaller ones by
+	    top-level '/', where each must match the corresponding part of a
+	    benchmark's identifier.
 	    By default, no benchmarks run. To run all benchmarks,
 	    use '-bench .' or '-bench=.'.
 
@@ -213,8 +219,10 @@ const testFlag2 = `
 	    (see 'go help build').
 
 	-run regexp
-	    Run only those tests and examples matching the regular
-	    expression.
+	    Run only those tests and examples matching the regular expression.
+	    For tests the regular expression is split into smaller ones by
+	    top-level '/', where each must match the corresponding part of a
+	    test's identifier.
 
 	-short
 	    Tell long-running tests to shorten their run time.
@@ -228,7 +236,6 @@ const testFlag2 = `
 
 	-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
@@ -256,7 +263,7 @@ execution, not to the test itself.)
 The test flags that generate profiles (other than for coverage) also
 leave the test binary in pkg.test for use when analyzing the profiles.
 
-When 'go test' runs a test binary, it does so from within the 
+When 'go test' runs a test binary, it does so from within the
 corresponding package's source code directory. Depending on the test,
 it may be necessary to do the same when invoking a generated test
 binary directly.
@@ -311,10 +318,11 @@ A benchmark function is one named BenchmarkXXX and should have the signature,
 
 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.
+If the last comment in the function starts with "Output:" then the output
+is compared exactly against the comment (see examples below). If the last
+comment begins with "Unordered output:" then the output is compared to the
+comment, however the order of the lines is ignored. 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
@@ -330,6 +338,20 @@ Here is an example of an example:
 		// this example.
 	}
 
+Here is another example where the ordering of the output is ignored:
+
+	func ExamplePerm() {
+		for _, value := range Perm(4) {
+			fmt.Println(value)
+		}
+
+		// Unordered output: 4
+		// 2
+		// 1
+		// 3
+		// 0
+	}
+
 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.
@@ -388,7 +410,7 @@ func runTest(cmd *Command, args []string) {
 	}
 
 	// If a test timeout was given and is parseable, set our kill timeout
-	// to that timeout plus one minute.  This is a backup alarm in case
+	// to that timeout plus one minute. This is a backup alarm in case
 	// the test wedges with a goroutine spinning and its background
 	// timer does not get a chance to fire.
 	if dt, err := time.ParseDuration(testTimeout); err == nil && dt > 0 {
@@ -492,7 +514,8 @@ func runTest(cmd *Command, args []string) {
 				continue
 			}
 			p.Stale = true // rebuild
-			p.fake = true  // do not warn about rebuild
+			p.StaleReason = "rebuild for coverage"
+			p.fake = true // do not warn about rebuild
 			p.coverMode = testCoverMode
 			var coverFiles []string
 			coverFiles = append(coverFiles, p.GoFiles...)
@@ -691,7 +714,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 	// the usual place in the temporary tree, because then
 	// other tests will see it as the real package.
 	// Instead we make a _test directory under the import path
-	// and then repeat the import path there.  We tell the
+	// and then repeat the import path there. We tell the
 	// compiler and linker to look in that _test directory first.
 	//
 	// That is, if the package under test is unicode/utf8,
@@ -729,6 +752,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 		ptest.fake = true
 		ptest.forceLibrary = true
 		ptest.Stale = true
+		ptest.StaleReason = "rebuild for test"
 		ptest.build = new(build.Package)
 		*ptest.build = *p.build
 		m := map[string][]token.Position{}
@@ -1007,6 +1031,7 @@ func recompileForTest(pmain, preal, ptest *Package, testDir string) {
 				p.target = ""
 				p.fake = true
 				p.Stale = true
+				p.StaleReason = "depends on package being tested"
 			}
 		}
 
@@ -1206,11 +1231,11 @@ func (b *builder) notest(a *action) error {
 	return nil
 }
 
-// isTestMain tells whether fn is a TestMain(m *testing.M) function.
-func isTestMain(fn *ast.FuncDecl) bool {
-	if fn.Name.String() != "TestMain" ||
-		fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
-		fn.Type.Params == nil ||
+// isTestFunc tells whether fn has the type of a testing function. arg
+// specifies the parameter type we look for: B, M or T.
+func isTestFunc(fn *ast.FuncDecl, arg string) bool {
+	if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
+		fn.Type.Params.List == nil ||
 		len(fn.Type.Params.List) != 1 ||
 		len(fn.Type.Params.List[0].Names) > 1 {
 		return false
@@ -1222,10 +1247,11 @@ func isTestMain(fn *ast.FuncDecl) bool {
 	// We can't easily check that the type is *testing.M
 	// because we don't know how testing has been imported,
 	// but at least check that it's *M or *something.M.
-	if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" {
+	// Same applies for B and T.
+	if name, ok := ptr.X.(*ast.Ident); ok && name.Name == arg {
 		return true
 	}
-	if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" {
+	if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == arg {
 		return true
 	}
 	return false
@@ -1322,9 +1348,10 @@ func (t *testFuncs) Tested() string {
 }
 
 type testFunc struct {
-	Package string // imported package name (_test or _xtest)
-	Name    string // function name
-	Output  string // output, for examples
+	Package   string // imported package name (_test or _xtest)
+	Name      string // function name
+	Output    string // output, for examples
+	Unordered bool   // output is allowed to be unordered.
 }
 
 var testFileSet = token.NewFileSet()
@@ -1344,17 +1371,25 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
 		}
 		name := n.Name.String()
 		switch {
-		case isTestMain(n):
+		case name == "TestMain" && isTestFunc(n, "M"):
 			if t.TestMain != nil {
 				return errors.New("multiple definitions of TestMain")
 			}
-			t.TestMain = &testFunc{pkg, name, ""}
+			t.TestMain = &testFunc{pkg, name, "", false}
 			*doImport, *seen = true, true
 		case isTest(name, "Test"):
-			t.Tests = append(t.Tests, testFunc{pkg, name, ""})
+			err := checkTestFunc(n, "T")
+			if err != nil {
+				return err
+			}
+			t.Tests = append(t.Tests, testFunc{pkg, name, "", false})
 			*doImport, *seen = true, true
 		case isTest(name, "Benchmark"):
-			t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
+			err := checkTestFunc(n, "B")
+			if err != nil {
+				return err
+			}
+			t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, "", false})
 			*doImport, *seen = true, true
 		}
 	}
@@ -1366,12 +1401,21 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
 			// Don't run examples with no output.
 			continue
 		}
-		t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output})
+		t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output, e.Unordered})
 		*seen = true
 	}
 	return nil
 }
 
+func checkTestFunc(fn *ast.FuncDecl, arg string) error {
+	if !isTestFunc(fn, arg) {
+		name := fn.Name.String()
+		pos := testFileSet.Position(fn.Pos())
+		return fmt.Errorf("%s: wrong signature for %s, must be: func %s(%s *testing.%s)", pos, name, name, strings.ToLower(arg), arg)
+	}
+	return nil
+}
+
 type byOrder []*doc.Example
 
 func (x byOrder) Len() int           { return len(x) }
@@ -1417,7 +1461,7 @@ var benchmarks = []testing.InternalBenchmark{
 
 var examples = []testing.InternalExample{
 {{range .Examples}}
-	{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}},
+	{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
 {{end}}
 }
 
diff --git a/src/cmd/go/testdata/dep_test.go b/src/cmd/go/testdata/dep_test.go
index 0c53ac4..ac39a5b 100644
--- a/src/cmd/go/testdata/dep_test.go
+++ b/src/cmd/go/testdata/dep_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/testdata/example1_test.go b/src/cmd/go/testdata/example1_test.go
index ec7092e..87e6c0a 100644
--- a/src/cmd/go/testdata/example1_test.go
+++ b/src/cmd/go/testdata/example1_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/testdata/example2_test.go b/src/cmd/go/testdata/example2_test.go
index 1e0e80b..5d13426 100644
--- a/src/cmd/go/testdata/example2_test.go
+++ b/src/cmd/go/testdata/example2_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/testdata/generate/test1.go b/src/cmd/go/testdata/generate/test1.go
index 1f05734..168cfb7 100644
--- a/src/cmd/go/testdata/generate/test1.go
+++ b/src/cmd/go/testdata/generate/test1.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/testdata/generate/test2.go b/src/cmd/go/testdata/generate/test2.go
index ef1a3d9..829244a 100644
--- a/src/cmd/go/testdata/generate/test2.go
+++ b/src/cmd/go/testdata/generate/test2.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/testdata/generate/test3.go b/src/cmd/go/testdata/generate/test3.go
index 3d6a8a5..e950da5 100644
--- a/src/cmd/go/testdata/generate/test3.go
+++ b/src/cmd/go/testdata/generate/test3.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/testdata/generate/test4.go b/src/cmd/go/testdata/generate/test4.go
index a7631c4..6dae048 100644
--- a/src/cmd/go/testdata/generate/test4.go
+++ b/src/cmd/go/testdata/generate/test4.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/go/testdata/src/benchfatal/x_test.go b/src/cmd/go/testdata/src/benchfatal/x_test.go
new file mode 100644
index 0000000..8d3a5de
--- /dev/null
+++ b/src/cmd/go/testdata/src/benchfatal/x_test.go
@@ -0,0 +1,7 @@
+package benchfatal
+
+import "testing"
+
+func BenchmarkThatCallsFatal(b *testing.B) {
+	b.Fatal("called by benchmark")
+}
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index 873df1f..a65ed1f 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -149,9 +149,11 @@ func testFlags(args []string) (packageNames, passToTest []string) {
 				testBench = true
 			case "timeout":
 				testTimeout = value
-			case "blockprofile", "cpuprofile", "memprofile", "trace":
+			case "blockprofile", "cpuprofile", "memprofile":
 				testProfile = true
 				testNeedBinary = true
+			case "trace":
+				testProfile = true
 			case "coverpkg":
 				testCover = true
 				if value == "" {
diff --git a/src/cmd/go/testgo.go b/src/cmd/go/testgo.go
index 01923f7..e507f34 100644
--- a/src/cmd/go/testgo.go
+++ b/src/cmd/go/testgo.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/cmd/go/tool.go b/src/cmd/go/tool.go
index 9ff0dcf..b829037 100644
--- a/src/cmd/go/tool.go
+++ b/src/cmd/go/tool.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 342edee..53ddbe6 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -93,7 +93,7 @@ var vcsHg = &vcsCmd{
 	downloadCmd: []string{"pull"},
 
 	// We allow both tag and branch names as 'tags'
-	// for selecting a version.  This lets people have
+	// for selecting a version. This lets people have
 	// a go.release.r60 branch and a go1 branch
 	// and make changes in both, without constantly
 	// editing .hgtags.
@@ -171,10 +171,10 @@ func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error
 		// 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],
+			Scheme: "ssh",
+			User:   url.User(m[1]),
+			Host:   m[2],
+			Path:   m[3],
 		}
 	} else {
 		repoURL, err = url.Parse(out)
@@ -253,7 +253,7 @@ func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string
 		return "", fmt.Errorf("unable to parse output of bzr info")
 	}
 	out = out[:i]
-	return strings.TrimSpace(string(out)), nil
+	return strings.TrimSpace(out), nil
 }
 
 // vcsSvn describes how to use Subversion.
@@ -294,7 +294,7 @@ func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error
 		return "", fmt.Errorf("unable to parse output of svn info")
 	}
 	out = out[:i]
-	return strings.TrimSpace(string(out)), nil
+	return strings.TrimSpace(out), nil
 }
 
 func (v *vcsCmd) String() string {
@@ -383,9 +383,6 @@ func (v *vcsCmd) ping(scheme, repo string) error {
 // The parent of dir must exist; dir must not.
 func (v *vcsCmd) create(dir, repo string) error {
 	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
 		}
@@ -396,9 +393,6 @@ func (v *vcsCmd) create(dir, repo string) error {
 // download downloads any new changes for the repo in dir.
 func (v *vcsCmd) download(dir string) error {
 	for _, cmd := range v.downloadCmd {
-		if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
-			continue
-		}
 		if err := v.run(dir, cmd); err != nil {
 			return err
 		}
@@ -445,9 +439,6 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
 
 	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
 			}
@@ -456,9 +447,6 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
 	}
 
 	for _, cmd := range v.tagSyncCmd {
-		if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
-			continue
-		}
 		if err := v.run(dir, cmd, "tag", tag); err != nil {
 			return err
 		}
@@ -479,15 +467,14 @@ type vcsPath struct {
 	regexp *regexp.Regexp // cached compiled form of re
 }
 
-// vcsForDir inspects dir and its parents to determine the
+// vcsFromDir inspects dir and its parents to determine the
 // version control system and code repository to use.
 // On return, root is the import path
-// corresponding to the root of the repository
-// (thus root is a prefix of importPath).
-func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
+// corresponding to the root of the repository.
+func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
 	// Clean and double-check that dir is in (a subdirectory of) srcRoot.
-	dir := filepath.Clean(p.Dir)
-	srcRoot := filepath.Clean(p.build.SrcRoot)
+	dir = filepath.Clean(dir)
+	srcRoot = filepath.Clean(srcRoot)
 	if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
 		return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
 	}
@@ -496,7 +483,7 @@ func vcsForDir(p *Package) (vcs *vcsCmd, root string, err error) {
 	for len(dir) > len(srcRoot) {
 		for _, vcs := range vcsList {
 			if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
-				return vcs, dir[len(srcRoot)+1:], nil
+				return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
 			}
 		}
 
@@ -780,15 +767,31 @@ type metaImport struct {
 // errNoMatch is returned from matchGoImport when there's no applicable match.
 var errNoMatch = errors.New("no import match")
 
+func splitPathHasPrefix(path, prefix []string) bool {
+	if len(path) < len(prefix) {
+		return false
+	}
+	for i, p := range prefix {
+		if path[i] != p {
+			return false
+		}
+	}
+	return true
+}
+
 // matchGoImport returns the metaImport from imports matching importPath.
 // An error is returned if there are multiple matches.
 // errNoMatch is returned if none match.
 func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
 	match := -1
+	imp := strings.Split(importPath, "/")
 	for i, im := range imports {
-		if !strings.HasPrefix(importPath, im.Prefix) {
+		pre := strings.Split(im.Prefix, "/")
+
+		if !splitPathHasPrefix(imp, pre) {
 			continue
 		}
+
 		if match != -1 {
 			err = fmt.Errorf("multiple meta tags match import path %q", importPath)
 			return
@@ -815,20 +818,6 @@ func expand(match map[string]string, s string) string {
 // 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
-	{
-		prefix: "code.google.com/",
-		re:     `^(?P<root>code\.google\.com/p/(?P<project>[a-z0-9\-]+)(\.(?P<subrepo>[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`,
-		repo:   "https://{root}",
-		check:  googleCodeVCS,
-	},
-
-	// Google Code - old syntax
-	{
-		re:    `^(?P<project>[a-z0-9_\-.]+)\.googlecode\.com/(git|hg|svn)(?P<path>/.*)?$`,
-		check: oldGoogleCode,
-	},
-
 	// Github
 	{
 		prefix: "github.com/",
@@ -863,6 +852,14 @@ var vcsPaths = []*vcsPath{
 		repo:   "https://{root}",
 	},
 
+	// Git at OpenStack
+	{
+		prefix: "git.openstack.org",
+		re:     `^(?P<root>git\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`,
+		vcs:    "git",
+		repo:   "https://{root}",
+	},
+
 	// General syntax for any server.
 	// Must be last.
 	{
@@ -911,45 +908,6 @@ func noVCSSuffix(match map[string]string) error {
 	return nil
 }
 
-var googleCheckout = regexp.MustCompile(`id="checkoutcmd">(hg|git|svn)`)
-
-// googleCodeVCS determines the version control system for
-// a code.google.com repository, by scraping the project's
-// /source/checkout page.
-func googleCodeVCS(match map[string]string) error {
-	if err := noVCSSuffix(match); err != nil {
-		return err
-	}
-	data, err := httpGET(expand(match, "https://code.google.com/p/{project}/source/checkout?repo={subrepo}"))
-	if err != nil {
-		return err
-	}
-
-	if m := googleCheckout.FindSubmatch(data); m != nil {
-		if vcs := vcsByCmd(string(m[1])); vcs != nil {
-			// Subversion requires the old URLs.
-			// TODO: Test.
-			if vcs == vcsSvn {
-				if match["subrepo"] != "" {
-					return fmt.Errorf("sub-repositories not supported in Google Code Subversion projects")
-				}
-				match["repo"] = expand(match, "https://{project}.googlecode.com/svn")
-			}
-			match["vcs"] = vcs.cmd
-			return nil
-		}
-	}
-
-	return fmt.Errorf("unable to detect version control system for code.google.com/ path")
-}
-
-// oldGoogleCode is invoked for old-style foo.googlecode.com paths.
-// It prints an error giving the equivalent new path.
-func oldGoogleCode(match map[string]string) error {
-	return fmt.Errorf("invalid Google Code import path: use %s instead",
-		expand(match, "code.google.com/p/{project}{path}"))
-}
-
 // bitbucketVCS determines the version control system for a
 // Bitbucket repository, by using the Bitbucket API.
 func bitbucketVCS(match map[string]string) error {
diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go
index a90c206..25e3866 100644
--- a/src/cmd/go/vcs_test.go
+++ b/src/cmd/go/vcs_test.go
@@ -1,11 +1,16 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 (
+	"errors"
 	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"path"
+	"path/filepath"
 	"testing"
 )
 
@@ -18,20 +23,6 @@ func TestRepoRootForImportPath(t *testing.T) {
 		path string
 		want *repoRoot
 	}{
-		/*{
-			"code.google.com/p/go",
-			&repoRoot{
-				vcs:  vcsHg,
-				repo: "https://code.google.com/p/go",
-			},
-		},
-		{
-		        "code.google.com/r/go",
-		        &repoRoot{
-		                vcs:  vcsHg,
-		                repo: "https://code.google.com/r/go",
-		        },
-		},*/
 		{
 			"github.com/golang/groupcache",
 			&repoRoot{
@@ -96,6 +87,39 @@ func TestRepoRootForImportPath(t *testing.T) {
 			"hub.jazz.net/git/USER/pkgname",
 			nil,
 		},
+		// OpenStack tests
+		{
+			"git.openstack.org/openstack/swift",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://git.openstack.org/openstack/swift",
+			},
+		},
+		// Trailing .git is less preferred but included for
+		// compatibility purposes while the same source needs to
+		// be compilable on both old and new go
+		{
+			"git.openstack.org/openstack/swift.git",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://git.openstack.org/openstack/swift",
+			},
+		},
+		{
+			"git.openstack.org/openstack/swift/go/hummingbird",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://git.openstack.org/openstack/swift",
+			},
+		},
+		{
+			"git.openstack.org",
+			nil,
+		},
+		{
+			"git.openstack.org/openstack",
+			nil,
+		},
 		// Spaces are not valid in package name
 		{
 			"git.apache.org/package name/path/to/lib",
@@ -142,6 +166,37 @@ func TestRepoRootForImportPath(t *testing.T) {
 	}
 }
 
+// Test that vcsFromDir correctly inspects a given directory and returns the right VCS and root.
+func TestFromDir(t *testing.T) {
+	tempDir, err := ioutil.TempDir("", "vcstest")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tempDir)
+
+	for _, vcs := range vcsList {
+		dir := filepath.Join(tempDir, "example.com", vcs.name, "."+vcs.cmd)
+		err := os.MkdirAll(dir, 0755)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		want := repoRoot{
+			vcs:  vcs,
+			root: path.Join("example.com", vcs.name),
+		}
+		var got repoRoot
+		got.vcs, got.root, err = vcsFromDir(dir, tempDir)
+		if err != nil {
+			t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err)
+			continue
+		}
+		if got.vcs.name != want.vcs.name || got.root != want.root {
+			t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.vcs, got.root, want.vcs, want.root)
+		}
+	}
+}
+
 func TestIsSecure(t *testing.T) {
 	tests := []struct {
 		vcs    *vcsCmd
@@ -173,3 +228,96 @@ func TestIsSecure(t *testing.T) {
 		}
 	}
 }
+
+func TestMatchGoImport(t *testing.T) {
+	tests := []struct {
+		imports []metaImport
+		path    string
+		mi      metaImport
+		err     error
+	}{
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "example.com/user/foo",
+			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+		},
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "example.com/user/foo/",
+			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+		},
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+				{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "example.com/user/foo",
+			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+		},
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+				{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "example.com/user/fooa",
+			mi:   metaImport{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+		},
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "example.com/user/foo/bar",
+			err:  errors.New("should not be allowed to create nested repo"),
+		},
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "example.com/user/foo/bar/baz",
+			err:  errors.New("should not be allowed to create nested repo"),
+		},
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "example.com/user/foo/bar/baz/qux",
+			err:  errors.New("should not be allowed to create nested repo"),
+		},
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "example.com/user/foo/bar/baz/",
+			err:  errors.New("should not be allowed to create nested repo"),
+		},
+		{
+			imports: []metaImport{
+				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
+			},
+			path: "example.com",
+			err:  errors.New("pathologically short path"),
+		},
+	}
+
+	for _, test := range tests {
+		mi, err := matchGoImport(test.imports, test.path)
+		if mi != test.mi {
+			t.Errorf("unexpected metaImport; got %v, want %v", mi, test.mi)
+		}
+
+		got := err
+		want := test.err
+		if (got == nil) != (want == nil) {
+			t.Errorf("unexpected error; got %v, want %v", got, want)
+		}
+	}
+}
diff --git a/src/cmd/go/vendor_test.go b/src/cmd/go/vendor_test.go
index 4cf2b0c..226b537 100644
--- a/src/cmd/go/vendor_test.go
+++ b/src/cmd/go/vendor_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -20,7 +20,6 @@ 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]
@@ -51,7 +50,6 @@ func TestVendorBuild(t *testing.T) {
 	tg := testgo(t)
 	defer tg.cleanup()
 	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
-	tg.setenv("GO15VENDOREXPERIMENT", "1")
 	tg.run("build", "vend/x")
 }
 
@@ -59,7 +57,6 @@ 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")
@@ -74,7 +71,6 @@ func TestVendorGOPATH(t *testing.T) {
 	}
 	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")
@@ -85,7 +81,6 @@ 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")
@@ -96,7 +91,6 @@ 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")
@@ -106,7 +100,6 @@ 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")
 
@@ -173,7 +166,6 @@ func TestVendorGet(t *testing.T) {
 		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")
@@ -192,7 +184,6 @@ func TestVendorGetUpdate(t *testing.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")
 }
@@ -204,16 +195,15 @@ func TestGetSubmodules(t *testing.T) {
 	defer tg.cleanup()
 	tg.makeTempdir()
 	tg.setenv("GOPATH", tg.path("."))
-	tg.setenv("GO15VENDOREXPERIMENT", "1")
 	tg.run("get", "-d", "github.com/rsc/go-get-issue-12612")
 	tg.run("get", "-u", "-d", "github.com/rsc/go-get-issue-12612")
+	tg.mustExist(tg.path("src/github.com/rsc/go-get-issue-12612/vendor/golang.org/x/crypto/.git"))
 }
 
 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")
 }
@@ -225,7 +215,6 @@ func TestVendorTest2(t *testing.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
@@ -253,7 +242,7 @@ func TestVendorTest3(t *testing.T) {
 	tg.setenv("GOPATH", tg.path("."))
 	tg.run("get", "github.com/clsung/go-vendor-issue-14613")
 
-	tg.run("build", "-i", "github.com/clsung/go-vendor-issue-14613")
+	tg.run("build", "-o", tg.path("a.out"), "-i", "github.com/clsung/go-vendor-issue-14613")
 
 	// test folder should work
 	tg.run("test", "-i", "github.com/clsung/go-vendor-issue-14613")
@@ -277,7 +266,6 @@ func TestVendorList(t *testing.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")
@@ -298,7 +286,6 @@ func TestVendor12156(t *testing.T) {
 	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")
diff --git a/src/cmd/go/version.go b/src/cmd/go/version.go
index a41f4a7..3045f35 100644
--- a/src/cmd/go/version.go
+++ b/src/cmd/go/version.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/go/vet.go b/src/cmd/go/vet.go
index 81b978e..8e296c8 100644
--- a/src/cmd/go/vet.go
+++ b/src/cmd/go/vet.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index cfebeff..b10b804 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -143,7 +143,9 @@ func visitFile(path string, f os.FileInfo, err error) error {
 	if err == nil && isGoFile(f) {
 		err = processFile(path, nil, os.Stdout, false)
 	}
-	if err != nil {
+	// Don't complain if a file was deleted in the meantime (i.e.
+	// the directory changed concurrently while running gofmt).
+	if err != nil && !os.IsNotExist(err) {
 		report(err)
 	}
 	return nil
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index d1edb7b..dea0127 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -159,7 +159,7 @@ func TestCRLF(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
-	if bytes.Index(data, []byte("\r\n")) < 0 {
+	if !bytes.Contains(data, []byte("\r\n")) {
 		t.Errorf("%s contains no CR/LF's", input)
 	}
 
@@ -167,7 +167,7 @@ func TestCRLF(t *testing.T) {
 	if err != nil {
 		t.Error(err)
 	}
-	if bytes.Index(data, []byte("\r")) >= 0 {
+	if bytes.Contains(data, []byte("\r")) {
 		t.Errorf("%s contains CR's", golden)
 	}
 }
diff --git a/src/cmd/gofmt/internal.go b/src/cmd/gofmt/internal.go
index f764b10..cbc6983 100644
--- a/src/cmd/gofmt/internal.go
+++ b/src/cmd/gofmt/internal.go
@@ -28,9 +28,9 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
 ) {
 	// 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
+	// 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.
+	// try as a source fragment. Stop and return on any other error.
 	if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
 		return
 	}
@@ -59,7 +59,7 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
 
 	// 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.
+	// 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 '}'.
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index 069f966..550492b 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -158,7 +158,7 @@ func isWildcard(s string) bool {
 // 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 {
-	// Wildcard matches any expression.  If it appears multiple
+	// Wildcard matches any expression. If it appears multiple
 	// times in the pattern, it must match the same expression
 	// each time.
 	if m != nil && pattern.IsValid() && pattern.Type() == identType {
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
index 69f7bf2..2ebf4cd 100644
--- a/src/cmd/gofmt/simplify.go
+++ b/src/cmd/gofmt/simplify.go
@@ -10,11 +10,9 @@ import (
 	"reflect"
 )
 
-type simplifier struct {
-	hasDotImport bool // package file contains: import . "some/import/path"
-}
+type simplifier struct{}
 
-func (s *simplifier) Visit(node ast.Node) ast.Visitor {
+func (s simplifier) Visit(node ast.Node) ast.Visitor {
 	switch n := node.(type) {
 	case *ast.CompositeLit:
 		// array, slice, and map composite literals may be simplified
@@ -68,10 +66,13 @@ func (s *simplifier) Visit(node ast.Node) ast.Visitor {
 		// a slice expression of the form: s[a:len(s)]
 		// can be simplified to: s[a:]
 		// if s is "simple enough" (for now we only accept identifiers)
-		if n.Max != nil || s.hasDotImport {
+		//
+		// Note: This may not be correct because len may have been redeclared in another
+		//       file belonging to the same package. However, this is extremely unlikely
+		//       and so far (April 2016, after years of supporting this rewrite feature)
+		//       has never come up, so let's keep it working as is (see also #15153).
+		if n.Max != nil {
 			// - 3-index slices always require the 2nd and 3rd index
-			// - if dot imports are present, we cannot be certain that an
-			//   unresolved "len" identifier refers to the predefined len()
 			break
 		}
 		if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil {
@@ -118,20 +119,11 @@ func isBlank(x ast.Expr) bool {
 }
 
 func simplify(f *ast.File) {
-	var s simplifier
-
-	// determine if f contains dot imports
-	for _, imp := range f.Imports {
-		if imp.Name != nil && imp.Name.Name == "." {
-			s.hasDotImport = true
-			break
-		}
-	}
-
 	// remove empty declarations such as "const ()", etc
 	removeEmptyDeclGroups(f)
 
-	ast.Walk(&s, f)
+	var s simplifier
+	ast.Walk(s, f)
 }
 
 func removeEmptyDeclGroups(f *ast.File) {
diff --git a/src/cmd/gofmt/testdata/slices2.golden b/src/cmd/gofmt/testdata/slices2.golden
deleted file mode 100644
index ab65700..0000000
--- a/src/cmd/gofmt/testdata/slices2.golden
+++ /dev/null
@@ -1,63 +0,0 @@
-//gofmt -s
-
-// Test cases for slice expression simplification.
-// Because of a dot import, these slices must remain untouched.
-package p
-
-import . "math"
-
-var (
-	a [10]byte
-	b [20]float32
-	s []int
-	t struct {
-		s []byte
-	}
-
-	_ = a[0:]
-	_ = a[1:10]
-	_ = a[2:len(a)]
-	_ = a[3:(len(a))]
-	_ = a[len(a) : len(a)-1]
-	_ = a[0:len(b)]
-
-	_ = a[:]
-	_ = a[:10]
-	_ = a[:len(a)]
-	_ = a[:(len(a))]
-	_ = a[:len(a)-1]
-	_ = a[:len(b)]
-
-	_ = s[0:]
-	_ = s[1:10]
-	_ = s[2:len(s)]
-	_ = s[3:(len(s))]
-	_ = s[len(a) : len(s)-1]
-	_ = s[0:len(b)]
-
-	_ = s[:]
-	_ = s[:10]
-	_ = s[:len(s)]
-	_ = s[:(len(s))]
-	_ = s[:len(s)-1]
-	_ = s[:len(b)]
-
-	_ = t.s[0:]
-	_ = t.s[1:10]
-	_ = t.s[2:len(t.s)]
-	_ = t.s[3:(len(t.s))]
-	_ = t.s[len(a) : len(t.s)-1]
-	_ = t.s[0:len(b)]
-
-	_ = t.s[:]
-	_ = t.s[:10]
-	_ = t.s[:len(t.s)]
-	_ = t.s[:(len(t.s))]
-	_ = t.s[:len(t.s)-1]
-	_ = t.s[:len(b)]
-)
-
-func _() {
-	s := s[0:len(s)]
-	_ = s
-}
diff --git a/src/cmd/gofmt/testdata/slices2.input b/src/cmd/gofmt/testdata/slices2.input
deleted file mode 100644
index ab65700..0000000
--- a/src/cmd/gofmt/testdata/slices2.input
+++ /dev/null
@@ -1,63 +0,0 @@
-//gofmt -s
-
-// Test cases for slice expression simplification.
-// Because of a dot import, these slices must remain untouched.
-package p
-
-import . "math"
-
-var (
-	a [10]byte
-	b [20]float32
-	s []int
-	t struct {
-		s []byte
-	}
-
-	_ = a[0:]
-	_ = a[1:10]
-	_ = a[2:len(a)]
-	_ = a[3:(len(a))]
-	_ = a[len(a) : len(a)-1]
-	_ = a[0:len(b)]
-
-	_ = a[:]
-	_ = a[:10]
-	_ = a[:len(a)]
-	_ = a[:(len(a))]
-	_ = a[:len(a)-1]
-	_ = a[:len(b)]
-
-	_ = s[0:]
-	_ = s[1:10]
-	_ = s[2:len(s)]
-	_ = s[3:(len(s))]
-	_ = s[len(a) : len(s)-1]
-	_ = s[0:len(b)]
-
-	_ = s[:]
-	_ = s[:10]
-	_ = s[:len(s)]
-	_ = s[:(len(s))]
-	_ = s[:len(s)-1]
-	_ = s[:len(b)]
-
-	_ = t.s[0:]
-	_ = t.s[1:10]
-	_ = t.s[2:len(t.s)]
-	_ = t.s[3:(len(t.s))]
-	_ = t.s[len(a) : len(t.s)-1]
-	_ = t.s[0:len(b)]
-
-	_ = t.s[:]
-	_ = t.s[:10]
-	_ = t.s[:len(t.s)]
-	_ = t.s[:(len(t.s))]
-	_ = t.s[:len(t.s)-1]
-	_ = t.s[:len(b)]
-)
-
-func _() {
-	s := s[0:len(s)]
-	_ = s
-}
diff --git a/src/cmd/internal/bio/buf.go b/src/cmd/internal/bio/buf.go
new file mode 100644
index 0000000..54ce3c7
--- /dev/null
+++ b/src/cmd/internal/bio/buf.go
@@ -0,0 +1,99 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bio implements common I/O abstractions used within the Go toolchain.
+package bio
+
+import (
+	"bufio"
+	"log"
+	"os"
+)
+
+// Reader implements a seekable buffered io.Reader.
+type Reader struct {
+	f *os.File
+	*bufio.Reader
+}
+
+// Writer implements a seekable buffered io.Writer.
+type Writer struct {
+	f *os.File
+	*bufio.Writer
+}
+
+// Create creates the file named name and returns a Writer
+// for that file.
+func Create(name string) (*Writer, error) {
+	f, err := os.Create(name)
+	if err != nil {
+		return nil, err
+	}
+	return &Writer{f: f, Writer: bufio.NewWriter(f)}, nil
+}
+
+// Open returns a Reader for the file named name.
+func Open(name string) (*Reader, error) {
+	f, err := os.Open(name)
+	if err != nil {
+		return nil, err
+	}
+	return &Reader{f: f, Reader: bufio.NewReader(f)}, nil
+}
+
+func (r *Reader) Seek(offset int64, whence int) int64 {
+	if whence == 1 {
+		offset -= int64(r.Buffered())
+	}
+	off, err := r.f.Seek(offset, whence)
+	if err != nil {
+		log.Fatalf("seeking in output: %v", err)
+	}
+	r.Reset(r.f)
+	return off
+}
+
+func (w *Writer) Seek(offset int64, whence int) int64 {
+	if err := w.Flush(); err != nil {
+		log.Fatalf("writing output: %v", err)
+	}
+	off, err := w.f.Seek(offset, whence)
+	if err != nil {
+		log.Fatalf("seeking in output: %v", err)
+	}
+	return off
+}
+
+func (r *Reader) Offset() int64 {
+	off, err := r.f.Seek(0, 1)
+	if err != nil {
+		log.Fatalf("seeking in output [0, 1]: %v", err)
+	}
+	off -= int64(r.Buffered())
+	return off
+}
+
+func (w *Writer) Offset() int64 {
+	if err := w.Flush(); err != nil {
+		log.Fatalf("writing output: %v", err)
+	}
+	off, err := w.f.Seek(0, 1)
+	if err != nil {
+		log.Fatalf("seeking in output [0, 1]: %v", err)
+	}
+	return off
+}
+
+func (r *Reader) Close() error {
+	return r.f.Close()
+}
+
+func (w *Writer) Close() error {
+	err := w.Flush()
+	err1 := w.f.Close()
+	if err == nil {
+		err = err1
+	}
+	return err
+}
diff --git a/src/cmd/internal/bio/must.go b/src/cmd/internal/bio/must.go
new file mode 100644
index 0000000..3604b29
--- /dev/null
+++ b/src/cmd/internal/bio/must.go
@@ -0,0 +1,43 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bio
+
+import (
+	"io"
+	"log"
+)
+
+// MustClose closes Closer c and calls log.Fatal if it returns a non-nil error.
+func MustClose(c io.Closer) {
+	if err := c.Close(); err != nil {
+		log.Fatal(err)
+	}
+}
+
+// MustWriter returns a Writer that wraps the provided Writer,
+// except that it calls log.Fatal instead of returning a non-nil error.
+func MustWriter(w io.Writer) io.Writer {
+	return mustWriter{w}
+}
+
+type mustWriter struct {
+	w io.Writer
+}
+
+func (w mustWriter) Write(b []byte) (int, error) {
+	n, err := w.w.Write(b)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return n, nil
+}
+
+func (w mustWriter) WriteString(s string) (int, error) {
+	n, err := io.WriteString(w.w, s)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return n, nil
+}
diff --git a/src/cmd/internal/gcprog/gcprog.go b/src/cmd/internal/gcprog/gcprog.go
index 5845f7d..7880917 100644
--- a/src/cmd/internal/gcprog/gcprog.go
+++ b/src/cmd/internal/gcprog/gcprog.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go
index 7fdaf55..214f65c 100644
--- a/src/cmd/internal/goobj/read.go
+++ b/src/cmd/internal/goobj/read.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -43,6 +43,7 @@ const (
 	SRODATA    SymKind = obj.SRODATA
 	SFUNCTAB   SymKind = obj.SFUNCTAB
 	STYPELINK  SymKind = obj.STYPELINK
+	SITABLINK  SymKind = obj.SITABLINK
 	SSYMTAB    SymKind = obj.SSYMTAB // TODO: move to unmapped section
 	SPCLNTAB   SymKind = obj.SPCLNTAB
 	SELFROSECT SymKind = obj.SELFROSECT
@@ -106,6 +107,7 @@ var symKindStrings = []string{
 	STLSBSS:           "STLSBSS",
 	STYPE:             "STYPE",
 	STYPELINK:         "STYPELINK",
+	SITABLINK:         "SITABLINK",
 	SWINDOWS:          "SWINDOWS",
 	SXREF:             "SXREF",
 }
@@ -215,6 +217,7 @@ type FuncData struct {
 type Package struct {
 	ImportPath string   // import path denoting this package
 	Imports    []string // packages imported by this package
+	SymRefs    []SymID  // list of symbol names and versions referred to by this pack
 	Syms       []*Sym   // symbols defined by this package
 	MaxVersion int      // maximum Version in any SymID in Syms
 }
@@ -226,24 +229,22 @@ var (
 
 	errCorruptArchive   = errors.New("corrupt archive")
 	errTruncatedArchive = errors.New("truncated archive")
-	errNotArchive       = errors.New("unrecognized archive format")
-
-	errCorruptObject   = errors.New("corrupt object file")
-	errTruncatedObject = errors.New("truncated object file")
-	errNotObject       = errors.New("unrecognized object file format")
+	errCorruptObject    = errors.New("corrupt object file")
+	errNotObject        = errors.New("unrecognized object file format")
 )
 
 // An objReader is an object file reader.
 type objReader struct {
-	p         *Package
-	b         *bufio.Reader
-	f         io.ReadSeeker
-	err       error
-	offset    int64
-	limit     int64
-	tmp       [256]byte
-	pkg       string
-	pkgprefix string
+	p          *Package
+	b          *bufio.Reader
+	f          io.ReadSeeker
+	err        error
+	offset     int64
+	dataOffset int64
+	limit      int64
+	tmp        [256]byte
+	pkg        string
+	pkgprefix  string
 }
 
 // importPathToPrefix returns the prefix that will be used in the
@@ -289,9 +290,9 @@ func importPathToPrefix(s string) string {
 func (r *objReader) init(f io.ReadSeeker, p *Package) {
 	r.f = f
 	r.p = p
-	r.offset, _ = f.Seek(0, 1)
-	r.limit, _ = f.Seek(0, 2)
-	f.Seek(r.offset, 0)
+	r.offset, _ = f.Seek(0, io.SeekCurrent)
+	r.limit, _ = f.Seek(0, io.SeekEnd)
+	f.Seek(r.offset, io.SeekStart)
 	r.b = bufio.NewReader(f)
 	r.pkgprefix = importPathToPrefix(p.ImportPath) + "."
 }
@@ -390,6 +391,11 @@ func (r *objReader) readString() string {
 
 // readSymID reads a SymID from the input file.
 func (r *objReader) readSymID() SymID {
+	i := r.readInt()
+	return r.p.SymRefs[i]
+}
+
+func (r *objReader) readRef() {
 	name, vers := r.readString(), r.readInt()
 
 	// In a symbol name in an object file, "". denotes the
@@ -404,15 +410,14 @@ func (r *objReader) readSymID() SymID {
 	if vers != 0 {
 		vers = r.p.MaxVersion
 	}
-
-	return SymID{name, vers}
+	r.p.SymRefs = append(r.p.SymRefs, SymID{name, vers})
 }
 
 // readData reads a data reference from the input file.
 func (r *objReader) readData() Data {
 	n := r.readInt()
-	d := Data{Offset: r.offset, Size: int64(n)}
-	r.skip(int64(n))
+	d := Data{Offset: r.dataOffset, Size: int64(n)}
+	r.dataOffset += int64(n)
 	return d
 }
 
@@ -435,7 +440,7 @@ func (r *objReader) skip(n int64) {
 		r.readFull(r.tmp[:n])
 	} else {
 		// Seek, giving up buffered data.
-		_, err := r.f.Seek(r.offset+n, 0)
+		_, err := r.f.Seek(r.offset+n, io.SeekStart)
 		if err != nil {
 			r.error(err)
 		}
@@ -530,7 +535,7 @@ func (r *objReader) parseArchive() error {
 			return errCorruptArchive
 		}
 		switch name {
-		case "__.SYMDEF", "__.GOSYMDEF", "__.PKGDEF":
+		case "__.PKGDEF":
 			r.skip(size)
 		default:
 			oldLimit := r.limit
@@ -575,7 +580,7 @@ func (r *objReader) parseObject(prefix []byte) error {
 	}
 
 	r.readFull(r.tmp[:8])
-	if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go13ld")) {
+	if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go17ld")) {
 		return r.error(errCorruptObject)
 	}
 
@@ -593,6 +598,28 @@ func (r *objReader) parseObject(prefix []byte) error {
 		r.p.Imports = append(r.p.Imports, s)
 	}
 
+	r.p.SymRefs = []SymID{{"", 0}}
+	for {
+		if b := r.readByte(); b != 0xfe {
+			if b != 0xff {
+				return r.error(errCorruptObject)
+			}
+			break
+		}
+
+		r.readRef()
+	}
+
+	dataLength := r.readInt()
+	r.readInt() // n relocations - ignore
+	r.readInt() // n pcdata - ignore
+	r.readInt() // n autom - ignore
+	r.readInt() // n funcdata - ignore
+	r.readInt() // n files - ignore
+
+	r.dataOffset = r.offset
+	r.skip(int64(dataLength))
+
 	// Symbols.
 	for {
 		if b := r.readByte(); b != 0xfe {
@@ -618,9 +645,7 @@ func (r *objReader) parseObject(prefix []byte) error {
 			rel.Size = r.readInt()
 			rel.Type = r.readInt()
 			rel.Add = r.readInt()
-			r.readInt() // Xadd - ignored
 			rel.Sym = r.readSymID()
-			r.readSymID() // Xsym - ignored
 		}
 
 		if s.Kind == STEXT {
@@ -662,7 +687,7 @@ func (r *objReader) parseObject(prefix []byte) error {
 	}
 
 	r.readFull(r.tmp[:7])
-	if !bytes.Equal(r.tmp[:7], []byte("\xffgo13ld")) {
+	if !bytes.Equal(r.tmp[:7], []byte("\xffgo17ld")) {
 		return r.error(errCorruptObject)
 	}
 
diff --git a/src/cmd/internal/goobj/read_test.go b/src/cmd/internal/goobj/read_test.go
index cc991e5..ff165e8 100644
--- a/src/cmd/internal/goobj/read_test.go
+++ b/src/cmd/internal/goobj/read_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/cmd/internal/obj/ar.go b/src/cmd/internal/obj/ar.go
deleted file mode 100644
index 56bb959..0000000
--- a/src/cmd/internal/obj/ar.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.
-
-package obj
-
-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
index ca166e1..4234b59 100644
--- a/src/cmd/internal/obj/arm/a.out.go
+++ b/src/cmd/internal/obj/arm/a.out.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
index d75a163..d37091f 100644
--- a/src/cmd/internal/obj/arm/asm5.go
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -39,7 +39,7 @@ import (
 )
 
 type Optab struct {
-	as       uint16
+	as       obj.As
 	a1       uint8
 	a2       int8
 	a3       uint8
@@ -50,11 +50,6 @@ type Optab struct {
 	pcrelsiz uint8
 }
 
-type Oprang struct {
-	start []Optab
-	stop  []Optab
-}
-
 type Opcross [32][2][32]uint8
 
 const (
@@ -270,9 +265,9 @@ var pool struct {
 	extra uint32
 }
 
-var oprange [ALAST & obj.AMask]Oprang
+var oprange [ALAST & obj.AMask][]Optab
 
-var xcmp [C_GOK + 1][C_GOK + 1]uint8
+var xcmp [C_GOK + 1][C_GOK + 1]bool
 
 var deferreturn *obj.LSym
 
@@ -424,8 +419,8 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 			} else {
 				a2 = &q.From
 			}
-			obj.Nocache(q)
-			obj.Nocache(p)
+			nocache(q)
+			nocache(p)
 
 			// insert q after p
 			q.Link = p.Link
@@ -501,8 +496,8 @@ func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint3
 				} else {
 					a2 = &q.From
 				}
-				obj.Nocache(q)
-				obj.Nocache(p)
+				nocache(q)
+				nocache(p)
 
 				// insert q after p
 				q.Link = p.Link
@@ -563,7 +558,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 		return
 	}
 
-	if oprange[AAND&obj.AMask].start == nil {
+	if oprange[AAND&obj.AMask] == nil {
 		buildop(ctxt)
 	}
 
@@ -742,7 +737,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
 
 	p = cursym.Text
 	ctxt.Autosize = int32(p.To.Offset + 4)
-	obj.Symgrow(ctxt, cursym, cursym.Size)
+	cursym.Grow(cursym.Size)
 
 	bp := cursym.P
 	c = int32(p.Pc) // even p->link might need extra padding
@@ -875,7 +870,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 		t.To.Type = a.Type
 		t.To.Name = a.Name
 
-		if ctxt.Flag_shared != 0 && t.To.Sym != nil {
+		if ctxt.Flag_shared && t.To.Sym != nil {
 			t.Rel = p
 		}
 
@@ -1020,7 +1015,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 
 			ctxt.Instoffset = 0 // s.b. unused but just in case
 			if a.Sym.Type == obj.STLSBSS {
-				if ctxt.Flag_shared != 0 {
+				if ctxt.Flag_shared {
 					return C_TLS_IE
 				} else {
 					return C_TLS_LE
@@ -1067,7 +1062,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 
 			return C_LAUTO
 
-		case obj.TYPE_NONE:
+		case obj.NAME_NONE:
 			ctxt.Instoffset = a.Offset
 			t := int(immaddr(int32(ctxt.Instoffset)))
 			if t != 0 {
@@ -1115,7 +1110,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 	case obj.TYPE_CONST,
 		obj.TYPE_ADDR:
 		switch a.Name {
-		case obj.TYPE_NONE:
+		case obj.NAME_NONE:
 			ctxt.Instoffset = a.Offset
 			if a.Reg != 0 {
 				return aconsize(ctxt)
@@ -1174,7 +1169,7 @@ func prasm(p *obj.Prog) {
 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	a1 := int(p.Optab)
 	if a1 != 0 {
-		return &optab[a1-1:][0]
+		return &optab[a1-1]
 	}
 	a1 = int(p.From.Class)
 	if a1 == 0 {
@@ -1194,38 +1189,30 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	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("oplook %v %v %v %v\n", obj.Aconv(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]
-				}
-			}
+	ops := oprange[p.As&obj.AMask]
+	c1 := &xcmp[a1]
+	c3 := &xcmp[a3]
+	for i := range ops {
+		op := &ops[i]
+		if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] {
+			p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
+			return op
 		}
 	}
 
 	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
+	if ops == nil {
+		ops = optab
 	}
-	return &o[0]
+	return &ops[0]
 }
 
 func cmp(a int, b int) bool {
@@ -1319,7 +1306,7 @@ func (x ocmp) Less(i, j int) bool {
 	return false
 }
 
-func opset(a, b0 uint16) {
+func opset(a, b0 obj.As) {
 	oprange[a&obj.AMask] = oprange[b0]
 }
 
@@ -1329,13 +1316,13 @@ func buildop(ctxt *obj.Link) {
 	for i := 0; i < C_GOK; i++ {
 		for n = 0; n < C_GOK; n++ {
 			if cmp(n, i) {
-				xcmp[i][n] = 1
+				xcmp[i][n] = true
 			}
 		}
 	}
 	for n = 0; optab[n].as != obj.AXXX; n++ {
 		if optab[n].flag&LPCREL != 0 {
-			if ctxt.Flag_shared != 0 {
+			if ctxt.Flag_shared {
 				optab[n].size += int8(optab[n].pcrelsiz)
 			} else {
 				optab[n].flag &^= LPCREL
@@ -1347,16 +1334,16 @@ func buildop(ctxt *obj.Link) {
 	for i := 0; i < n; i++ {
 		r := optab[i].as
 		r0 := r & obj.AMask
-		oprange[r0].start = optab[i:]
+		start := i
 		for optab[i].as == r {
 			i++
 		}
-		oprange[r0].stop = optab[i:]
+		oprange[r0] = optab[start:i]
 		i--
 
 		switch r {
 		default:
-			ctxt.Diag("unknown op in build: %v", obj.Aconv(int(r)))
+			ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
 			log.Fatalf("bad code")
 
 		case AADD:
@@ -1513,7 +1500,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 1: /* op R,[R],R */
-		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o1 = oprrr(ctxt, p.As, int(p.Scond))
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -1531,7 +1518,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	case 2: /* movbu $I,[R],R */
 		aclass(ctxt, &p.From)
 
-		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o1 = oprrr(ctxt, p.As, int(p.Scond))
 		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
 		rt := int(p.To.Reg)
 		r := int(p.Reg)
@@ -1561,7 +1548,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= (uint32(p.To.Reg) & 15) << 12
 
 	case 5: /* bra s */
-		o1 = opbra(ctxt, p, int(p.As), int(p.Scond))
+		o1 = opbra(ctxt, p, p.As, int(p.Scond))
 
 		v := int32(-8)
 		if p.To.Sym != nil {
@@ -1604,7 +1591,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	case 8: /* sll $c,[R],R -> mov (R<<$c),R */
 		aclass(ctxt, &p.From)
 
-		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o1 = oprrr(ctxt, p.As, int(p.Scond))
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
@@ -1614,7 +1601,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = oprrr(ctxt, p.As, int(p.Scond))
 
 		r := int(p.Reg)
 		if r == 0 {
@@ -1625,7 +1612,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= (uint32(p.To.Reg) & 15) << 12
 
 	case 10: /* swi [$con] */
-		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o1 = oprrr(ctxt, p.As, int(p.Scond))
 
 		if p.To.Type != obj.TYPE_NONE {
 			aclass(ctxt, &p.To)
@@ -1646,7 +1633,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			rel.Sym = p.To.Sym
 			rel.Add = p.To.Offset
 
-			if ctxt.Flag_shared != 0 {
+			if ctxt.Flag_shared {
 				if p.To.Name == obj.NAME_GOTREF {
 					rel.Type = obj.R_GOTPCREL
 				} else {
@@ -1672,7 +1659,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if o1 == 0 {
 			break
 		}
-		o2 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o2 = oprrr(ctxt, p.As, int(p.Scond))
 		o2 |= REGTMP & 15
 		r := int(p.Reg)
 		if p.As == AMOVW || p.As == AMVN {
@@ -1706,7 +1693,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 15: /* mul r,[r,]r */
-		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o1 = oprrr(ctxt, p.As, int(p.Scond))
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -1734,7 +1721,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o2 = 0
 
 	case 17:
-		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o1 = oprrr(ctxt, p.As, int(p.Scond))
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
 		rt2 := int(p.To.Offset)
@@ -1748,7 +1735,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = osr(ctxt, int(p.As), int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
+		o1 = osr(ctxt, 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)
@@ -1898,7 +1885,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = ofsr(ctxt, int(p.As), int(p.From.Reg), v, r, int(p.Scond), p)
+		o1 = ofsr(ctxt, p.As, int(p.From.Reg), v, r, int(p.Scond), p)
 
 	case 51: /* floating point load */
 		v := regoff(ctxt, &p.From)
@@ -1907,7 +1894,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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
+		o1 = ofsr(ctxt, 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)
@@ -1920,7 +1907,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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)
+		o3 = ofsr(ctxt, 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)
@@ -1933,10 +1920,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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
+		o3 = ofsr(ctxt, 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))
+		o1 = oprrr(ctxt, p.As, int(p.Scond))
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -2020,7 +2007,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if o1 == 0 {
 			break
 		}
-		o2 = osr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond))
+		o2 = osr(ctxt, 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
@@ -2091,7 +2078,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if o1 == 0 {
 			break
 		}
-		o2 = ofsr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
+		o2 = ofsr(ctxt, 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
@@ -2103,7 +2090,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if o1 == 0 {
 			break
 		}
-		o2 = ofsr(ctxt, int(p.As), int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
+		o2 = ofsr(ctxt, 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
@@ -2245,65 +2232,65 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= (uint32(v) & 0xf0) << 12
 
 	case 82: /* fcmp freg,freg, */
-		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o1 = oprrr(ctxt, 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 = oprrr(ctxt, 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 = oprrr(ctxt, 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 = oprrr(ctxt, 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 = oprrr(ctxt, 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 = oprrr(ctxt, -AMOVFW, 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 = oprrr(ctxt, -AMOVWF, int(p.Scond))
 
 		o1 |= (uint32(p.From.Reg) & 15) << 12
 		o1 |= (FREGTMP & 15) << 16
-		o2 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o2 = oprrr(ctxt, 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 = oprrr(ctxt, -AMOVWF, 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 = oprrr(ctxt, -AMOVFW, 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 = oprrr(ctxt, -ACMP, int(p.Scond))
 
 		o1 |= (uint32(p.From.Reg) & 15) << 16
 
@@ -2372,27 +2359,27 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 		// 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
+	// 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 = oprrr(ctxt, 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 = oprrr(ctxt, 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 = oprrr(ctxt, p.As, int(p.Scond))
 
 		o1 |= (uint32(p.To.Reg) & 15) << 12
 		o1 |= (uint32(p.From.Reg) & 15) << 8
@@ -2418,7 +2405,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
 	aclass(ctxt, &p.From)
-	o1 := oprrr(ctxt, int(p.As), int(p.Scond))
+	o1 := oprrr(ctxt, p.As, int(p.Scond))
 	o1 |= uint32(p.From.Offset)
 	rt := int(p.To.Reg)
 	if p.To.Type == obj.TYPE_NONE {
@@ -2434,7 +2421,7 @@ func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
 	return o1
 }
 
-func oprrr(ctxt *obj.Link, a int, sc int) uint32 {
+func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
 	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
 	if sc&C_SBIT != 0 {
 		o |= 1 << 20
@@ -2560,13 +2547,13 @@ func oprrr(ctxt *obj.Link, a int, sc int) uint32 {
 		}
 		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
+	case -AMOVWF: // copy WtoF
 		return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
 
-	case AMOVFW + ALAST: // copy FtoW
+	case -AMOVFW: // copy FtoW
 		return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
 
-	case ACMP + ALAST: // cmp imm
+	case -ACMP: // cmp imm
 		return o | 0x3<<24 | 0x5<<20
 
 		// CLZ doesn't support .nil
@@ -2594,7 +2581,7 @@ func oprrr(ctxt *obj.Link, a int, sc int) uint32 {
 	return 0
 }
 
-func opbra(ctxt *obj.Link, p *obj.Prog, a int, sc int) uint32 {
+func opbra(ctxt *obj.Link, p *obj.Prog, a obj.As, sc int) uint32 {
 	if sc&(C_SBIT|C_PBIT|C_WBIT) != 0 {
 		ctxt.Diag("%v: .nil/.nil/.W on bra instruction", p)
 	}
@@ -2706,7 +2693,7 @@ func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
 	return o
 }
 
-func osr(ctxt *obj.Link, a int, r int, v int32, b int, sc int) uint32 {
+func osr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int) uint32 {
 	o := olr(ctxt, v, b, r, sc) ^ (1 << 20)
 	if a != AMOVW {
 		o |= 1 << 22
@@ -2735,7 +2722,7 @@ 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 {
+func ofsr(ctxt *obj.Link, a obj.As, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
 	if sc&C_SBIT != 0 {
 		ctxt.Diag(".nil on FLDR/FSTR instruction: %v", p)
 	}
@@ -2842,3 +2829,12 @@ func chipfloat5(ctxt *obj.Link, e float64) int {
 	//print("match %.8lux %.8lux %d\n", l, h, n);
 	return n
 }
+
+func nocache(p *obj.Prog) {
+	p.Optab = 0
+	p.From.Class = 0
+	if p.From3 != nil {
+		p.From3.Class = 0
+	}
+	p.To.Class = 0
+}
diff --git a/src/cmd/internal/obj/arm/list5.go b/src/cmd/internal/obj/arm/list5.go
index bb2ac20..a0c210e 100644
--- a/src/cmd/internal/obj/arm/list5.go
+++ b/src/cmd/internal/obj/arm/list5.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 19a70e1..9cf2f29 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,7 +32,7 @@ package arm
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"math"
@@ -55,12 +55,12 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		}
 	}
 
-	// Replace TLS register fetches on older ARM procesors.
+	// Replace TLS register fetches on older ARM processors.
 	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
+			// Because the instruction might be rewritten 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())
@@ -342,12 +342,11 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		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)
+		o := p.As
 		switch o {
 		case obj.ATEXT:
 			autosize = int32(p.To.Offset + 4)
@@ -368,7 +367,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 			if cursym.Text.Mark&LEAF != 0 {
-				cursym.Leaf = 1
+				cursym.Leaf = true
 				if autosize == 0 {
 					break
 				}
@@ -413,7 +412,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				p.As = AMOVW
 				p.From.Type = obj.TYPE_MEM
 				p.From.Reg = REGG
-				p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = REG_R1
 
@@ -479,7 +478,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 		case obj.ARET:
-			obj.Nocache(p)
+			nocache(p)
 			if cursym.Text.Mark&LEAF != 0 {
 				if autosize == 0 {
 					p.As = AB
@@ -709,9 +708,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	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.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
+	if ctxt.Cursym.Cfunc {
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R1
@@ -823,7 +822,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	call.To.Type = obj.TYPE_BRANCH
 	morestack := "runtime.morestack"
 	switch {
-	case ctxt.Cursym.Cfunc != 0:
+	case ctxt.Cursym.Cfunc:
 		morestack = "runtime.morestackc"
 	case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0:
 		morestack = "runtime.morestack_noctxt"
@@ -860,7 +859,7 @@ func follow(ctxt *obj.Link, s *obj.LSym) {
 	s.Text = firstp.Link
 }
 
-func relinv(a int) int {
+func relinv(a obj.As) obj.As {
 	switch a {
 	case ABEQ:
 		return ABNE
@@ -903,14 +902,13 @@ func relinv(a int) int {
 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)
+	a := p.As
 	if a == AB {
 		q = p.Pcond
 		if q != nil && q.As != obj.ATEXT {
@@ -929,7 +927,7 @@ loop:
 			if q == *last || q == nil {
 				break
 			}
-			a = int(q.As)
+			a = q.As
 			if a == obj.ANOP {
 				i--
 				continue
@@ -983,7 +981,7 @@ loop:
 
 		a = AB
 		q = ctxt.NewProg()
-		q.As = int16(a)
+		q.As = a
 		q.Lineno = p.Lineno
 		q.To.Type = obj.TYPE_BRANCH
 		q.To.Offset = p.Pc
@@ -1003,7 +1001,7 @@ loop:
 			q = obj.Brchain(ctxt, p.Link)
 			if a != obj.ATEXT {
 				if q != nil && (q.Mark&FOLL != 0) {
-					p.As = int16(relinv(a))
+					p.As = relinv(a)
 					p.Link = p.Pcond
 					p.Pcond = q
 				}
@@ -1028,21 +1026,16 @@ loop:
 	goto loop
 }
 
-var unaryDst = map[int]bool{
+var unaryDst = map[obj.As]bool{
 	ASWI:  true,
 	AWORD: true,
 }
 
 var Linkarm = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "arm",
-	Thechar:    '5',
+	Arch:       sys.ArchARM,
 	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
index f459483..ab05894 100644
--- a/src/cmd/internal/obj/arm64/a.out.go
+++ b/src/cmd/internal/obj/arm64/a.out.go
@@ -1,14 +1,14 @@
 // 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.
+// 	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.
+// 	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
@@ -167,7 +167,7 @@ const (
 )
 
 // Not registers, but flags that can be combined with regular register
-// constants to indicate extended register conversion.  When checking,
+// 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
diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go
index 2d17d17..eb348d4 100644
--- a/src/cmd/internal/obj/arm64/anames7.go
+++ b/src/cmd/internal/obj/arm64/anames7.go
@@ -1,3 +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.
+
 package arm64
 
 var cnames7 = []string{
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 162acd2..28bebaa 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -1,14 +1,14 @@
 // 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.
+// 	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.
+// 	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
@@ -47,7 +47,7 @@ const (
 )
 
 type Optab struct {
-	as    uint16
+	as    obj.As
 	a1    uint8
 	a2    uint8
 	a3    uint8
@@ -58,14 +58,9 @@ type Optab struct {
 	scond uint16
 }
 
-type Oprange struct {
-	start []Optab
-	stop  []Optab
-}
-
-var oprange [ALAST]Oprange
+var oprange [ALAST & obj.AMask][]Optab
 
-var xcmp [C_NCLASS][C_NCLASS]uint8
+var xcmp [C_NCLASS][C_NCLASS]bool
 
 const (
 	S32     = 0 << 31
@@ -160,6 +155,7 @@ var optab = []Optab{
 	{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},
+	{ANEG, C_NONE, 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},
@@ -532,7 +528,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
 	ctxt.Cursym = cursym
 	ctxt.Autosize = int32(p.To.Offset&0xffffffff) + 8
 
-	if oprange[AAND].start == nil {
+	if oprange[AAND&obj.AMask] == nil {
 		buildop(ctxt)
 	}
 
@@ -634,7 +630,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
 	/*
 	 * lay out the code, emitting code and data relocations.
 	 */
-	obj.Symgrow(ctxt, cursym, cursym.Size)
+	cursym.Grow(cursym.Size)
 	bp := cursym.P
 	psz := int32(0)
 	var i int
@@ -970,15 +966,14 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 
 	case obj.TYPE_MEM:
 		switch a.Name {
-		case obj.NAME_EXTERN,
-			obj.NAME_STATIC:
+		case obj.NAME_EXTERN, obj.NAME_STATIC:
 			if a.Sym == nil {
 				break
 			}
 			ctxt.Instoffset = a.Offset
 			if a.Sym != nil { // use relocation
 				if a.Sym.Type == obj.STLSBSS {
-					if ctxt.Flag_shared != 0 {
+					if ctxt.Flag_shared {
 						return C_TLS_IE
 					} else {
 						return C_TLS_LE
@@ -999,7 +994,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
 			return autoclass(ctxt.Instoffset)
 
-		case obj.TYPE_NONE:
+		case obj.NAME_NONE:
 			ctxt.Instoffset = a.Offset
 			return oregclass(ctxt.Instoffset)
 		}
@@ -1011,10 +1006,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 	case obj.TYPE_TEXTSIZE:
 		return C_TEXTSIZE
 
-	case obj.TYPE_CONST,
-		obj.TYPE_ADDR:
+	case obj.TYPE_CONST, obj.TYPE_ADDR:
 		switch a.Name {
-		case obj.TYPE_NONE:
+		case obj.NAME_NONE:
 			ctxt.Instoffset = a.Offset
 			if a.Reg != 0 && a.Reg != REGZERO {
 				goto aconsize
@@ -1058,8 +1052,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			}
 			return C_VCON
 
-		case obj.NAME_EXTERN,
-			obj.NAME_STATIC:
+		case obj.NAME_EXTERN, obj.NAME_STATIC:
 			if a.Sym == nil {
 				break
 			}
@@ -1095,7 +1088,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	a1 := int(p.Optab)
 	if a1 != 0 {
-		return &optab[a1-1:][0]
+		return &optab[a1-1]
 	}
 	a1 = int(p.From.Class)
 	if a1 == 0 {
@@ -1115,41 +1108,31 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	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("oplook %v %d %d %d\n", obj.Aconv(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]
-					}
-				}
-			}
+	ops := oprange[p.As&obj.AMask]
+	c1 := &xcmp[a1]
+	c2 := &xcmp[a2]
+	c3 := &xcmp[a3]
+	c4 := &xcmp[p.Scond>>5]
+	for i := range ops {
+		op := &ops[i]
+		if (int(op.a2) == a2 || c2[op.a2]) && c4[op.scond>>5] && c1[op.a1] && c3[op.a3] {
+			p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
+			return op
 		}
 	}
 
 	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
+	if ops == nil {
+		ops = optab
 	}
-	return &o[0]
+	return &ops[0]
 }
 
 func cmp(a int, b int) bool {
@@ -1308,274 +1291,271 @@ func (x ocmp) Swap(i, j int) {
 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
+	if p1.as != p2.as {
+		return p1.as < p2.as
 	}
-	n = int(p1.a1) - int(p2.a1)
-	if n != 0 {
-		return n < 0
+	if p1.a1 != p2.a1 {
+		return p1.a1 < p2.a1
 	}
-	n = int(p1.a2) - int(p2.a2)
-	if n != 0 {
-		return n < 0
+	if p1.a2 != p2.a2 {
+		return p1.a2 < p2.a2
 	}
-	n = int(p1.a3) - int(p2.a3)
-	if n != 0 {
-		return n < 0
+	if p1.a3 != p2.a3 {
+		return p1.a3 < p2.a3
 	}
-	n = int(p1.scond) - int(p2.scond)
-	if n != 0 {
-		return n < 0
+	if p1.scond != p2.scond {
+		return p1.scond < p2.scond
 	}
 	return false
 }
 
+func oprangeset(a obj.As, t []Optab) {
+	oprange[a&obj.AMask] = t
+}
+
 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
+				xcmp[i][n] = true
 			}
 		}
 	}
 	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 {
+		r := optab[i].as
+		start := i
+		for optab[i].as == r {
 			i++
 		}
-		oprange[r].stop = optab[i:]
+		t := optab[start:i]
 		i--
-		t = oprange[r]
+		oprangeset(r, t)
 		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
+			oprangeset(AADDS, t)
+			oprangeset(ASUB, t)
+			oprangeset(ASUBS, t)
+			oprangeset(AADDW, t)
+			oprangeset(AADDSW, t)
+			oprangeset(ASUBW, t)
+			oprangeset(ASUBSW, t)
 
 		case AAND: /* logical immediate, logical shifted register */
-			oprange[AANDS] = t
+			oprangeset(AANDS, t)
 
-			oprange[AANDSW] = t
-			oprange[AANDW] = t
-			oprange[AEOR] = t
-			oprange[AEORW] = t
-			oprange[AORR] = t
-			oprange[AORRW] = t
+			oprangeset(AANDSW, t)
+			oprangeset(AANDW, t)
+			oprangeset(AEOR, t)
+			oprangeset(AEORW, t)
+			oprangeset(AORR, t)
+			oprangeset(AORRW, t)
 
 		case ABIC: /* only logical shifted register */
-			oprange[ABICS] = t
+			oprangeset(ABICS, t)
 
-			oprange[ABICSW] = t
-			oprange[ABICW] = t
-			oprange[AEON] = t
-			oprange[AEONW] = t
-			oprange[AORN] = t
-			oprange[AORNW] = t
+			oprangeset(ABICSW, t)
+			oprangeset(ABICW, t)
+			oprangeset(AEON, t)
+			oprangeset(AEONW, t)
+			oprangeset(AORN, t)
+			oprangeset(AORNW, t)
 
 		case ANEG:
-			oprange[ANEGS] = t
-			oprange[ANEGSW] = t
-			oprange[ANEGW] = t
+			oprangeset(ANEGS, t)
+			oprangeset(ANEGSW, t)
+			oprangeset(ANEGW, t)
 
 		case AADC: /* rn=Rd */
-			oprange[AADCW] = t
+			oprangeset(AADCW, t)
 
-			oprange[AADCS] = t
-			oprange[AADCSW] = t
-			oprange[ASBC] = t
-			oprange[ASBCW] = t
-			oprange[ASBCS] = t
-			oprange[ASBCSW] = t
+			oprangeset(AADCS, t)
+			oprangeset(AADCSW, t)
+			oprangeset(ASBC, t)
+			oprangeset(ASBCW, t)
+			oprangeset(ASBCS, t)
+			oprangeset(ASBCSW, t)
 
 		case ANGC: /* rn=REGZERO */
-			oprange[ANGCW] = t
+			oprangeset(ANGCW, t)
 
-			oprange[ANGCS] = t
-			oprange[ANGCSW] = t
+			oprangeset(ANGCS, t)
+			oprangeset(ANGCSW, t)
 
 		case ACMP:
-			oprange[ACMPW] = t
-			oprange[ACMN] = t
-			oprange[ACMNW] = t
+			oprangeset(ACMPW, t)
+			oprangeset(ACMN, t)
+			oprangeset(ACMNW, t)
 
 		case ATST:
-			oprange[ATSTW] = t
+			oprangeset(ATSTW, t)
 
 			/* register/register, and shifted */
 		case AMVN:
-			oprange[AMVNW] = t
+			oprangeset(AMVNW, t)
 
 		case AMOVK:
-			oprange[AMOVKW] = t
-			oprange[AMOVN] = t
-			oprange[AMOVNW] = t
-			oprange[AMOVZ] = t
-			oprange[AMOVZW] = t
+			oprangeset(AMOVKW, t)
+			oprangeset(AMOVN, t)
+			oprangeset(AMOVNW, t)
+			oprangeset(AMOVZ, t)
+			oprangeset(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
+			oprangeset(ABNE, t)
+			oprangeset(ABCS, t)
+			oprangeset(ABHS, t)
+			oprangeset(ABCC, t)
+			oprangeset(ABLO, t)
+			oprangeset(ABMI, t)
+			oprangeset(ABPL, t)
+			oprangeset(ABVS, t)
+			oprangeset(ABVC, t)
+			oprangeset(ABHI, t)
+			oprangeset(ABLS, t)
+			oprangeset(ABGE, t)
+			oprangeset(ABLT, t)
+			oprangeset(ABGT, t)
+			oprangeset(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
+			oprangeset(ALSLW, t)
+			oprangeset(ALSR, t)
+			oprangeset(ALSRW, t)
+			oprangeset(AASR, t)
+			oprangeset(AASRW, t)
+			oprangeset(AROR, t)
+			oprangeset(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
+			oprangeset(ACLSW, t)
+			oprangeset(ACLZ, t)
+			oprangeset(ACLZW, t)
+			oprangeset(ARBIT, t)
+			oprangeset(ARBITW, t)
+			oprangeset(AREV, t)
+			oprangeset(AREVW, t)
+			oprangeset(AREV16, t)
+			oprangeset(AREV16W, t)
+			oprangeset(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
+			oprangeset(ASDIVW, t)
+			oprangeset(AUDIV, t)
+			oprangeset(AUDIVW, t)
+			oprangeset(ACRC32B, t)
+			oprangeset(ACRC32CB, t)
+			oprangeset(ACRC32CH, t)
+			oprangeset(ACRC32CW, t)
+			oprangeset(ACRC32CX, t)
+			oprangeset(ACRC32H, t)
+			oprangeset(ACRC32W, t)
+			oprangeset(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
+			oprangeset(AMADDW, t)
+			oprangeset(AMSUB, t)
+			oprangeset(AMSUBW, t)
+			oprangeset(ASMADDL, t)
+			oprangeset(ASMSUBL, t)
+			oprangeset(AUMADDL, t)
+			oprangeset(AUMSUBL, t)
 
 		case AREM:
-			oprange[AREMW] = t
-			oprange[AUREM] = t
-			oprange[AUREMW] = t
+			oprangeset(AREMW, t)
+			oprangeset(AUREM, t)
+			oprangeset(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
+			oprangeset(AMULW, t)
+			oprangeset(AMNEG, t)
+			oprangeset(AMNEGW, t)
+			oprangeset(ASMNEGL, t)
+			oprangeset(ASMULL, t)
+			oprangeset(ASMULH, t)
+			oprangeset(AUMNEGL, t)
+			oprangeset(AUMULH, t)
+			oprangeset(AUMULL, t)
 
 		case AMOVB:
-			oprange[AMOVBU] = t
+			oprangeset(AMOVBU, t)
 
 		case AMOVH:
-			oprange[AMOVHU] = t
+			oprangeset(AMOVHU, t)
 
 		case AMOVW:
-			oprange[AMOVWU] = t
+			oprangeset(AMOVWU, t)
 
 		case ABFM:
-			oprange[ABFMW] = t
-			oprange[ASBFM] = t
-			oprange[ASBFMW] = t
-			oprange[AUBFM] = t
-			oprange[AUBFMW] = t
+			oprangeset(ABFMW, t)
+			oprangeset(ASBFM, t)
+			oprangeset(ASBFMW, t)
+			oprangeset(AUBFM, t)
+			oprangeset(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
+			oprangeset(ABFIW, t)
+			oprangeset(ABFXIL, t)
+			oprangeset(ABFXILW, t)
+			oprangeset(ASBFIZ, t)
+			oprangeset(ASBFIZW, t)
+			oprangeset(ASBFX, t)
+			oprangeset(ASBFXW, t)
+			oprangeset(AUBFIZ, t)
+			oprangeset(AUBFIZW, t)
+			oprangeset(AUBFX, t)
+			oprangeset(AUBFXW, t)
 
 		case AEXTR:
-			oprange[AEXTRW] = t
+			oprangeset(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
+			oprangeset(ASXTBW, t)
+			oprangeset(ASXTH, t)
+			oprangeset(ASXTHW, t)
+			oprangeset(ASXTW, t)
+			oprangeset(AUXTB, t)
+			oprangeset(AUXTH, t)
+			oprangeset(AUXTW, t)
+			oprangeset(AUXTBW, t)
+			oprangeset(AUXTHW, t)
 
 		case ACCMN:
-			oprange[ACCMNW] = t
-			oprange[ACCMP] = t
-			oprange[ACCMPW] = t
+			oprangeset(ACCMNW, t)
+			oprangeset(ACCMP, t)
+			oprangeset(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
+			oprangeset(ACSELW, t)
+			oprangeset(ACSINC, t)
+			oprangeset(ACSINCW, t)
+			oprangeset(ACSINV, t)
+			oprangeset(ACSINVW, t)
+			oprangeset(ACSNEG, t)
+			oprangeset(ACSNEGW, t)
 
 			// aliases Rm=Rn, !cond
-			oprange[ACINC] = t
+			oprangeset(ACINC, t)
 
-			oprange[ACINCW] = t
-			oprange[ACINV] = t
-			oprange[ACINVW] = t
-			oprange[ACNEG] = t
-			oprange[ACNEGW] = t
+			oprangeset(ACINCW, t)
+			oprangeset(ACINV, t)
+			oprangeset(ACINVW, t)
+			oprangeset(ACNEG, t)
+			oprangeset(ACNEGW, t)
 
 			// aliases, Rm=Rn=REGZERO, !cond
 		case ACSET:
-			oprange[ACSETW] = t
+			oprangeset(ACSETW, t)
 
-			oprange[ACSETM] = t
-			oprange[ACSETMW] = t
+			oprangeset(ACSETM, t)
+			oprangeset(ACSETMW, t)
 
 		case AMOVD,
 			AMOVBU,
@@ -1590,20 +1570,20 @@ func buildop(ctxt *obj.Link) {
 			break
 
 		case AERET:
-			oprange[AWFE] = t
-			oprange[AWFI] = t
-			oprange[AYIELD] = t
-			oprange[ASEV] = t
-			oprange[ASEVL] = t
-			oprange[ADRPS] = t
+			oprangeset(AWFE, t)
+			oprangeset(AWFI, t)
+			oprangeset(AYIELD, t)
+			oprangeset(ASEV, t)
+			oprangeset(ASEVL, t)
+			oprangeset(ADRPS, t)
 
 		case ACBZ:
-			oprange[ACBZW] = t
-			oprange[ACBNZ] = t
-			oprange[ACBNZW] = t
+			oprangeset(ACBZW, t)
+			oprangeset(ACBNZ, t)
+			oprangeset(ACBNZW, t)
 
 		case ATBZ:
-			oprange[ATBNZ] = t
+			oprangeset(ATBNZ, t)
 
 		case AADR, AADRP:
 			break
@@ -1612,154 +1592,154 @@ func buildop(ctxt *obj.Link) {
 			break
 
 		case ASVC:
-			oprange[AHLT] = t
-			oprange[AHVC] = t
-			oprange[ASMC] = t
-			oprange[ABRK] = t
-			oprange[ADCPS1] = t
-			oprange[ADCPS2] = t
-			oprange[ADCPS3] = t
+			oprangeset(AHLT, t)
+			oprangeset(AHVC, t)
+			oprangeset(ASMC, t)
+			oprangeset(ABRK, t)
+			oprangeset(ADCPS1, t)
+			oprangeset(ADCPS2, t)
+			oprangeset(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
+			oprangeset(AFADDD, t)
+			oprangeset(AFSUBS, t)
+			oprangeset(AFSUBD, t)
+			oprangeset(AFMULS, t)
+			oprangeset(AFMULD, t)
+			oprangeset(AFNMULS, t)
+			oprangeset(AFNMULD, t)
+			oprangeset(AFDIVS, t)
+			oprangeset(AFMAXD, t)
+			oprangeset(AFMAXS, t)
+			oprangeset(AFMIND, t)
+			oprangeset(AFMINS, t)
+			oprangeset(AFMAXNMD, t)
+			oprangeset(AFMAXNMS, t)
+			oprangeset(AFMINNMD, t)
+			oprangeset(AFMINNMS, t)
+			oprangeset(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
+			oprangeset(AFCVTDS, t)
+			oprangeset(AFABSD, t)
+			oprangeset(AFABSS, t)
+			oprangeset(AFNEGD, t)
+			oprangeset(AFNEGS, t)
+			oprangeset(AFSQRTD, t)
+			oprangeset(AFSQRTS, t)
+			oprangeset(AFRINTNS, t)
+			oprangeset(AFRINTND, t)
+			oprangeset(AFRINTPS, t)
+			oprangeset(AFRINTPD, t)
+			oprangeset(AFRINTMS, t)
+			oprangeset(AFRINTMD, t)
+			oprangeset(AFRINTZS, t)
+			oprangeset(AFRINTZD, t)
+			oprangeset(AFRINTAS, t)
+			oprangeset(AFRINTAD, t)
+			oprangeset(AFRINTXS, t)
+			oprangeset(AFRINTXD, t)
+			oprangeset(AFRINTIS, t)
+			oprangeset(AFRINTID, t)
+			oprangeset(AFCVTDH, t)
+			oprangeset(AFCVTHS, t)
+			oprangeset(AFCVTHD, t)
+			oprangeset(AFCVTSH, t)
 
 		case AFCMPS:
-			oprange[AFCMPD] = t
-			oprange[AFCMPES] = t
-			oprange[AFCMPED] = t
+			oprangeset(AFCMPD, t)
+			oprangeset(AFCMPES, t)
+			oprangeset(AFCMPED, t)
 
 		case AFCCMPS:
-			oprange[AFCCMPD] = t
-			oprange[AFCCMPES] = t
-			oprange[AFCCMPED] = t
+			oprangeset(AFCCMPD, t)
+			oprangeset(AFCCMPES, t)
+			oprangeset(AFCCMPED, t)
 
 		case AFCSELD:
-			oprange[AFCSELS] = t
+			oprangeset(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
+			oprangeset(AFCVTZSDW, t)
+			oprangeset(AFCVTZSS, t)
+			oprangeset(AFCVTZSSW, t)
+			oprangeset(AFCVTZUD, t)
+			oprangeset(AFCVTZUDW, t)
+			oprangeset(AFCVTZUS, t)
+			oprangeset(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
+			oprangeset(ASCVTFS, t)
+			oprangeset(ASCVTFWD, t)
+			oprangeset(ASCVTFWS, t)
+			oprangeset(AUCVTFD, t)
+			oprangeset(AUCVTFS, t)
+			oprangeset(AUCVTFWD, t)
+			oprangeset(AUCVTFWS, t)
 
 		case ASYS:
-			oprange[AAT] = t
-			oprange[ADC] = t
-			oprange[AIC] = t
-			oprange[ATLBI] = t
+			oprangeset(AAT, t)
+			oprangeset(ADC, t)
+			oprangeset(AIC, t)
+			oprangeset(ATLBI, t)
 
 		case ASYSL, AHINT:
 			break
 
 		case ADMB:
-			oprange[ADSB] = t
-			oprange[AISB] = t
+			oprangeset(ADSB, t)
+			oprangeset(AISB, t)
 
 		case AMRS, AMSR:
 			break
 
 		case ALDAR:
-			oprange[ALDARW] = t
+			oprangeset(ALDARW, t)
 			fallthrough
 
 		case ALDXR:
-			oprange[ALDXRB] = t
-			oprange[ALDXRH] = t
-			oprange[ALDXRW] = t
+			oprangeset(ALDXRB, t)
+			oprangeset(ALDXRH, t)
+			oprangeset(ALDXRW, t)
 
 		case ALDAXR:
-			oprange[ALDAXRW] = t
+			oprangeset(ALDAXRW, t)
 
 		case ALDXP:
-			oprange[ALDXPW] = t
+			oprangeset(ALDXPW, t)
 
 		case ASTLR:
-			oprange[ASTLRW] = t
+			oprangeset(ASTLRW, t)
 
 		case ASTXR:
-			oprange[ASTXRB] = t
-			oprange[ASTXRH] = t
-			oprange[ASTXRW] = t
+			oprangeset(ASTXRB, t)
+			oprangeset(ASTXRH, t)
+			oprangeset(ASTXRW, t)
 
 		case ASTLXR:
-			oprange[ASTLXRW] = t
+			oprangeset(ASTLXRW, t)
 
 		case ASTXP:
-			oprange[ASTXPW] = t
+			oprangeset(ASTXPW, t)
 
 		case AAESD:
-			oprange[AAESE] = t
-			oprange[AAESMC] = t
-			oprange[AAESIMC] = t
-			oprange[ASHA1H] = t
-			oprange[ASHA1SU1] = t
-			oprange[ASHA256SU0] = t
+			oprangeset(AAESE, t)
+			oprangeset(AAESMC, t)
+			oprangeset(AAESIMC, t)
+			oprangeset(ASHA1H, t)
+			oprangeset(ASHA1SU1, t)
+			oprangeset(ASHA256SU0, t)
 
 		case ASHA1C:
-			oprange[ASHA1P] = t
-			oprange[ASHA1M] = t
-			oprange[ASHA1SU0] = t
-			oprange[ASHA256H] = t
-			oprange[ASHA256H2] = t
-			oprange[ASHA256SU1] = t
+			oprangeset(ASHA1P, t)
+			oprangeset(ASHA1M, t)
+			oprangeset(ASHA1SU0, t)
+			oprangeset(ASHA256H, t)
+			oprangeset(ASHA256H2, t)
+			oprangeset(ASHA256SU1, t)
 
 		case obj.ANOP,
 			obj.AUNDEF,
@@ -1831,7 +1811,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		break
 
 	case 1: /* op Rm,[Rn],Rd; default Rn=Rd -> op Rm<<0,[Rn,]Rd (shifted register) */
-		o1 = oprrr(ctxt, int(p.As))
+		o1 = oprrr(ctxt, p.As)
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -1845,7 +1825,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = opirr(ctxt, p.As)
 
 		rt := int(p.To.Reg)
 		if p.To.Type == obj.TYPE_NONE {
@@ -1863,7 +1843,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 = oaddi(ctxt, int32(o1), v, r, rt)
 
 	case 3: /* op R<<n[,R],R (shifted register) */
-		o1 = oprrr(ctxt, int(p.As))
+		o1 = oprrr(ctxt, p.As)
 
 		o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
 		rt := int(p.To.Reg)
@@ -1879,7 +1859,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = opirr(ctxt, p.As)
 
 		rt := int(p.To.Reg)
 		r := int(o.param)
@@ -1900,7 +1880,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= ((uint32(v) & 0xFFF) << 10) | (uint32(r&31) << 5) | uint32(rt&31)
 
 	case 5: /* b s; bl s */
-		o1 = opbra(ctxt, int(p.As))
+		o1 = opbra(ctxt, p.As)
 
 		if p.To.Sym == nil {
 			o1 |= uint32(brdist(ctxt, p, 0, 26, 2))
@@ -1915,7 +1895,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		rel.Type = obj.R_CALLARM64
 
 	case 6: /* b ,O(R); bl ,O(R) */
-		o1 = opbrr(ctxt, int(p.As))
+		o1 = opbrr(ctxt, p.As)
 
 		o1 |= uint32(p.To.Reg&31) << 5
 		rel := obj.Addrel(ctxt.Cursym)
@@ -1924,7 +1904,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		rel.Type = obj.R_CALLIND
 
 	case 7: /* beq s */
-		o1 = opbra(ctxt, int(p.As))
+		o1 = opbra(ctxt, p.As)
 
 		o1 |= uint32(brdist(ctxt, p, 0, 19, 2) << 5)
 
@@ -1967,7 +1947,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 9: /* lsl Rm,[Rn],Rd -> lslv Rm, Rn, Rd */
-		o1 = oprrr(ctxt, int(p.As))
+		o1 = oprrr(ctxt, p.As)
 
 		r := int(p.Reg)
 		if r == 0 {
@@ -1976,7 +1956,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = opimm(ctxt, p.As)
 
 		if p.To.Type != obj.TYPE_NONE {
 			o1 |= uint32((p.To.Offset & 0xffff) << 5)
@@ -1999,7 +1979,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 12: /* movT $vcon, reg */
-		o1 = omovlit(ctxt, int(p.As), p, &p.From, int(p.To.Reg))
+		o1 = omovlit(ctxt, 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)
@@ -2016,11 +1996,11 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			r = rt
 		}
 		if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
-			o2 = opxrrr(ctxt, int(p.As))
+			o2 = opxrrr(ctxt, p.As)
 			o2 |= REGTMP & 31 << 16
 			o2 |= LSL0_64
 		} else {
-			o2 = oprrr(ctxt, int(p.As))
+			o2 = oprrr(ctxt, p.As)
 			o2 |= REGTMP & 31 << 16 /* shift is 0 */
 		}
 
@@ -2046,7 +2026,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 15: /* mul/mneg/umulh/umull r,[r,]r; madd/msub Rm,Rn,Ra,Rd */
-		o1 = oprrr(ctxt, int(p.As))
+		o1 = oprrr(ctxt, p.As)
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -2069,7 +2049,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = oprrr(ctxt, p.As)
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -2083,7 +2063,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = oprrr(ctxt, p.As)
 
 		rf := int(p.From.Reg)
 		rt := int(p.To.Reg)
@@ -2097,7 +2077,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = oprrr(ctxt, p.As)
 
 		cond := int(p.From.Reg)
 		r := int(p.Reg)
@@ -2130,10 +2110,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		cond := int(p.From.Reg)
 		var rf int
 		if p.From3.Type == obj.TYPE_REG {
-			o1 = oprrr(ctxt, int(p.As))
+			o1 = oprrr(ctxt, p.As)
 			rf = int(p.From3.Reg) /* Rm */
 		} else {
-			o1 = opirr(ctxt, int(p.As))
+			o1 = opirr(ctxt, p.As)
 			rf = int(p.From3.Offset & 0x1F)
 		}
 
@@ -2147,10 +2127,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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))
+			o1 = olsr9s(ctxt, int32(opstr9(ctxt, 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))
+			o1 = olsr12u(ctxt, int32(opstr12(ctxt, p.As)), v, r, int(p.From.Reg))
 		}
 
 	case 21: /* movT O(R),R -> ldrT */
@@ -2161,12 +2141,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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))
+			o1 = olsr9s(ctxt, int32(opldr9(ctxt, 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))
+			o1 = olsr12u(ctxt, int32(opldr12(ctxt, p.As)), v, r, int(p.To.Reg))
 		}
 
 	case 22: /* movT (R)O!,R; movT O(R)!, R -> ldrT */
@@ -2175,7 +2155,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if v < -256 || v > 255 {
 			ctxt.Diag("offset out of range\n%v", p)
 		}
-		o1 = opldrpp(ctxt, int(p.As))
+		o1 = opldrpp(ctxt, p.As)
 		if o.scond == C_XPOST {
 			o1 |= 1 << 10
 		} else {
@@ -2189,7 +2169,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if v < -256 || v > 255 {
 			ctxt.Diag("offset out of range\n%v", p)
 		}
-		o1 = LD2STR(opldrpp(ctxt, int(p.As)))
+		o1 = LD2STR(opldrpp(ctxt, p.As))
 		if o.scond == C_XPOST {
 			o1 |= 1 << 10
 		} else {
@@ -2205,32 +2185,35 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			if s {
 				ctxt.Diag("illegal SP reference\n%v", p)
 			}
-			o1 = oprrr(ctxt, int(p.As))
+			o1 = oprrr(ctxt, p.As)
 			o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
 		} else if s {
-			o1 = opirr(ctxt, int(p.As))
+			o1 = opirr(ctxt, p.As)
 			o1 |= (uint32(rf&31) << 5) | uint32(rt&31)
 		} else {
-			o1 = oprrr(ctxt, int(p.As))
+			o1 = oprrr(ctxt, 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))
+		o1 = oprrr(ctxt, p.As)
 
 		rf := int(p.From.Reg)
+		if rf == C_NONE {
+			rf = int(p.To.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 = oprrr(ctxt, 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))
+		o1 = opxrrr(ctxt, p.As)
 
 		if (p.From.Reg-obj.RBaseARM64)&REG_EXT != 0 {
 			ctxt.Diag("extended register not implemented\n%v", p)
@@ -2258,21 +2241,21 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o2 = oprrr(ctxt, int(p.As))
+		o2 = oprrr(ctxt, 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 = oprrr(ctxt, 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))
+		s := movesize(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)
+			ctxt.Diag("unexpected long move, op %v tab %v\n%v", obj.Aconv(p.As), obj.Aconv(o.as), p)
 		}
 		v := int32(regoff(ctxt, &p.To))
 		if v < 0 {
@@ -2293,13 +2276,13 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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))
+		o2 = olsr12u(ctxt, int32(opstr12(ctxt, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.From.Reg))
 
 	case 31: /* movT L(R), R -> ldrT */
-		s := movesize(int(o.as))
+		s := movesize(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)
+			ctxt.Diag("unexpected long move, op %v tab %v\n%v", obj.Aconv(p.As), obj.Aconv(o.as), p)
 		}
 		v := int32(regoff(ctxt, &p.From))
 		if v < 0 {
@@ -2320,7 +2303,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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))
+		o2 = olsr12u(ctxt, int32(opldr12(ctxt, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
 
 	case 32: /* mov $con, R -> movz/movn */
 		r := 32
@@ -2353,7 +2336,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = opirr(ctxt, p.As)
 
 		d := p.From.Offset
 		if (d >> 16) != 0 {
@@ -2429,7 +2412,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= uint32(v)
 
 	case 38: /* clrex [$imm] */
-		o1 = opimm(ctxt, int(p.As))
+		o1 = opimm(ctxt, p.As)
 
 		if p.To.Type == obj.TYPE_NONE {
 			o1 |= 0xF << 8
@@ -2438,13 +2421,13 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 39: /* cbz R, rel */
-		o1 = opirr(ctxt, int(p.As))
+		o1 = opirr(ctxt, 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))
+		o1 = opirr(ctxt, p.As)
 
 		v := int32(p.From.Offset)
 		if v < 0 || v > 63 {
@@ -2455,10 +2438,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= uint32(p.Reg)
 
 	case 41: /* eret, nop, others with no operands */
-		o1 = op0(ctxt, int(p.As))
+		o1 = op0(ctxt, 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))
+		o1 = opbfm(ctxt, 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)
@@ -2512,13 +2495,13 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	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))
+		o1 = opextr(ctxt, 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)
+		as := p.As
 		if rf == REGZERO {
 			as = AMOVWU /* clearer in disassembly */
 		}
@@ -2562,7 +2545,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 46: /* cls */
-		o1 = opbit(ctxt, int(p.As))
+		o1 = opbit(ctxt, p.As)
 
 		o1 |= uint32(p.From.Reg&31) << 5
 		o1 |= uint32(p.To.Reg & 31)
@@ -2577,7 +2560,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o2 = olsxrr(ctxt, int(p.As), REGTMP, r, int(p.From.Reg))
+		o2 = olsxrr(ctxt, 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)
@@ -2589,10 +2572,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o2 = olsxrr(ctxt, int(p.As), REGTMP, r, int(p.To.Reg))
+		o2 = olsxrr(ctxt, p.As, REGTMP, r, int(p.To.Reg))
 
 	case 50: /* sys/sysl */
-		o1 = opirr(ctxt, int(p.As))
+		o1 = opirr(ctxt, p.As)
 
 		if (p.From.Offset &^ int64(SYSARG4(0x7, 0xF, 0xF, 0x7))) != 0 {
 			ctxt.Diag("illegal SYS argument\n%v", p)
@@ -2607,14 +2590,14 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 51: /* dmb */
-		o1 = opirr(ctxt, int(p.As))
+		o1 = opirr(ctxt, 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 = opirr(ctxt, p.As)
 
 		o1 |= uint32((p.From.Offset & 0x7F) << 5)
 
@@ -2622,7 +2605,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		ctxt.Diag("bitmask immediate not implemented\n%v", p)
 
 	case 54: /* floating point arith */
-		o1 = oprrr(ctxt, int(p.As))
+		o1 = oprrr(ctxt, p.As)
 
 		var rf int
 		if p.From.Type == obj.TYPE_CONST {
@@ -2647,7 +2630,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
 
 	case 56: /* floating point compare */
-		o1 = oprrr(ctxt, int(p.As))
+		o1 = oprrr(ctxt, p.As)
 
 		var rf int
 		if p.From.Type == obj.TYPE_CONST {
@@ -2660,7 +2643,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= uint32(rf&31)<<16 | uint32(rt&31)<<5
 
 	case 57: /* floating point conditional compare */
-		o1 = oprrr(ctxt, int(p.As))
+		o1 = oprrr(ctxt, p.As)
 
 		cond := int(p.From.Reg)
 		nzcv := int(p.To.Offset)
@@ -2676,7 +2659,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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 = opload(ctxt, p.As)
 
 		o1 |= 0x1F << 16
 		o1 |= uint32(p.From.Reg) << 5
@@ -2688,7 +2671,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 |= uint32(p.To.Reg & 31)
 
 	case 59: /* stxr/stlxr */
-		o1 = opstore(ctxt, int(p.As))
+		o1 = opstore(ctxt, p.As)
 
 		if p.RegTo2 != obj.REG_NONE {
 			o1 |= uint32(p.RegTo2&31) << 16
@@ -2721,7 +2704,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o3 = olsr12u(ctxt, int32(opstr12(ctxt, p.As)), 0, REGTMP, int(p.From.Reg))
 
 	case 65: /* movT addr,R -> adrp + add + movT (REGTMP), R */
 		o1 = ADR(1, 0, REGTMP)
@@ -2732,7 +2715,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o3 = olsr12u(ctxt, int32(opldr12(ctxt, 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)
@@ -2811,7 +2794,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	// 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
+	// like to be able to tell how we got there. Assemble as
 	// 0xbea71700 which is guaranteed to raise undefined instruction
 	// exception.
 	case 90:
@@ -2833,7 +2816,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
  * also op Rn -> Rt
  * also Rm*Rn op Ra -> Rd
  */
-func oprrr(ctxt *obj.Link, a int) uint32 {
+func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AADC:
 		return S64 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10
@@ -3356,7 +3339,7 @@ func oprrr(ctxt *obj.Link, a int) uint32 {
  * imm -> Rd
  * imm op Rn -> Rd
  */
-func opirr(ctxt *obj.Link, a int) uint32 {
+func opirr(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	/* op $addcon, Rn, Rd */
 	case AMOVD, AADD:
@@ -3539,7 +3522,7 @@ func opirr(ctxt *obj.Link, a int) uint32 {
 	return 0
 }
 
-func opbit(ctxt *obj.Link, a int) uint32 {
+func opbit(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case ACLS:
 		return S64 | OPBIT(5)
@@ -3583,7 +3566,7 @@ func opbit(ctxt *obj.Link, a int) uint32 {
 /*
  * add/subtract extended register
  */
-func opxrrr(ctxt *obj.Link, a int) uint32 {
+func opxrrr(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AADD:
 		return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
@@ -3614,7 +3597,7 @@ func opxrrr(ctxt *obj.Link, a int) uint32 {
 	return 0
 }
 
-func opimm(ctxt *obj.Link, a int) uint32 {
+func opimm(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case ASVC:
 		return 0xD4<<24 | 0<<21 | 1 /* imm16<<5 */
@@ -3671,7 +3654,7 @@ func brdist(ctxt *obj.Link, p *obj.Prog, preshift int, flen int, shift int) int6
 /*
  * pc-relative branches
  */
-func opbra(ctxt *obj.Link, a int) uint32 {
+func opbra(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case ABEQ:
 		return OPBcc(0x0)
@@ -3734,7 +3717,7 @@ func opbra(ctxt *obj.Link, a int) uint32 {
 	return 0
 }
 
-func opbrr(ctxt *obj.Link, a int) uint32 {
+func opbrr(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case ABL:
 		return OPBLR(1) /* BLR */
@@ -3751,7 +3734,7 @@ func opbrr(ctxt *obj.Link, a int) uint32 {
 	return 0
 }
 
-func op0(ctxt *obj.Link, a int) uint32 {
+func op0(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case ADRPS:
 		return 0x6B<<25 | 5<<21 | 0x1F<<16 | 0x1F<<5
@@ -3786,7 +3769,7 @@ func op0(ctxt *obj.Link, a int) uint32 {
 /*
  * register offset
  */
-func opload(ctxt *obj.Link, a int) uint32 {
+func opload(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case ALDAR:
 		return LDSTX(3, 1, 1, 0, 1) | 0x1F<<10
@@ -3847,7 +3830,7 @@ func opload(ctxt *obj.Link, a int) uint32 {
 	return 0
 }
 
-func opstore(ctxt *obj.Link, a int) uint32 {
+func opstore(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case ASTLR:
 		return LDSTX(3, 1, 0, 0, 1) | 0x1F<<10
@@ -3928,7 +3911,7 @@ func olsr12u(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 {
 	return uint32(o)
 }
 
-func opldr12(ctxt *obj.Link, a int) uint32 {
+func opldr12(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AMOVD:
 		return LDSTR12U(3, 0, 1) /* imm12<<10 | Rn<<5 | Rt */
@@ -3962,7 +3945,7 @@ func opldr12(ctxt *obj.Link, a int) uint32 {
 	return 0
 }
 
-func opstr12(ctxt *obj.Link, a int) uint32 {
+func opstr12(ctxt *obj.Link, a obj.As) uint32 {
 	return LD2STR(opldr12(ctxt, a))
 }
 
@@ -3979,7 +3962,7 @@ func olsr9s(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 {
 	return uint32(o)
 }
 
-func opldr9(ctxt *obj.Link, a int) uint32 {
+func opldr9(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AMOVD:
 		return LDSTR9S(3, 0, 1) /* simm9<<12 | Rn<<5 | Rt */
@@ -4013,11 +3996,11 @@ func opldr9(ctxt *obj.Link, a int) uint32 {
 	return 0
 }
 
-func opstr9(ctxt *obj.Link, a int) uint32 {
+func opstr9(ctxt *obj.Link, a obj.As) uint32 {
 	return LD2STR(opldr9(ctxt, a))
 }
 
-func opldrpp(ctxt *obj.Link, a int) uint32 {
+func opldrpp(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AMOVD:
 		return 3<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 /* simm9<<12 | Rn<<5 | Rt */
@@ -4048,7 +4031,7 @@ func opldrpp(ctxt *obj.Link, a int) uint32 {
 /*
  * load/store register (extended register)
  */
-func olsxrr(ctxt *obj.Link, as int, rt int, r1 int, r2 int) uint32 {
+func olsxrr(ctxt *obj.Link, as obj.As, rt int, r1 int, r2 int) uint32 {
 	ctxt.Diag("need load/store extended register\n%v", ctxt.Curp)
 	return 0xffffffff
 }
@@ -4069,7 +4052,7 @@ func oaddi(ctxt *obj.Link, o1 int32, v int32, r int, rt int) uint32 {
 /*
  * load a a literal value into dr
  */
-func omovlit(ctxt *obj.Link, as int, p *obj.Prog, a *obj.Addr, dr int) uint32 {
+func omovlit(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32 {
 	var o1 int32
 	if p.Pcond == nil { /* not in literal pool */
 		aclass(ctxt, a)
@@ -4117,7 +4100,7 @@ func omovlit(ctxt *obj.Link, as int, p *obj.Prog, a *obj.Addr, dr int) uint32 {
 	return uint32(o1)
 }
 
-func opbfm(ctxt *obj.Link, a int, r int, s int, rf int, rt int) uint32 {
+func opbfm(ctxt *obj.Link, a obj.As, r int, s int, rf int, rt int) uint32 {
 	var c uint32
 	o := opirr(ctxt, a)
 	if (o & (1 << 31)) == 0 {
@@ -4137,7 +4120,7 @@ func opbfm(ctxt *obj.Link, a int, r int, s int, rf int, rt int) uint32 {
 	return o
 }
 
-func opextr(ctxt *obj.Link, a int, v int32, rn int, rm int, rt int) uint32 {
+func opextr(ctxt *obj.Link, a obj.As, v int32, rn int, rm int, rt int) uint32 {
 	var c uint32
 	o := opirr(ctxt, a)
 	if (o & (1 << 31)) != 0 {
@@ -4158,7 +4141,7 @@ func opextr(ctxt *obj.Link, a int, v int32, rn int, rm int, rt int) uint32 {
 /*
  * size in log2(bytes)
  */
-func movesize(a int) int {
+func movesize(a obj.As) int {
 	switch a {
 	case AMOVD:
 		return 3
diff --git a/src/cmd/internal/obj/arm64/list7.go b/src/cmd/internal/obj/arm64/list7.go
index 53d67c9..ad9ff09 100644
--- a/src/cmd/internal/obj/arm64/list7.go
+++ b/src/cmd/internal/obj/arm64/list7.go
@@ -1,14 +1,14 @@
 // 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.
+// 	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.
+// 	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
@@ -71,7 +71,7 @@ func Rconv(r int) string {
 	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)
+		return fmt.Sprintf("V%d", r-REG_V0)
 	case COND_EQ <= r && r <= COND_NV:
 		return strcond[r-COND_EQ]
 	case r == REGSP:
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 93c4b1a..ffa1b41 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -1,14 +1,14 @@
 // 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.
+// 	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.
+// 	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
@@ -32,13 +32,13 @@ package arm64
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"math"
 )
 
-var complements = []int16{
+var complements = []obj.As{
 	AADD:  ASUB,
 	AADDW: ASUBW,
 	ASUB:  AADD,
@@ -56,9 +56,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	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.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
+	if ctxt.Cursym.Cfunc {
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R1
@@ -193,7 +193,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	call.To.Type = obj.TYPE_BRANCH
 	morestack := "runtime.morestack"
 	switch {
-	case ctxt.Cursym.Cfunc != 0:
+	case ctxt.Cursym.Cfunc:
 		morestack = "runtime.morestackc"
 	case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0:
 		morestack = "runtime.morestack_noctxt"
@@ -250,7 +250,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		if p.From.Type == obj.TYPE_FCONST {
 			f32 := float32(p.From.Val.(float64))
 			i32 := math.Float32bits(f32)
-			literal := fmt.Sprintf("$f32.%08x", uint32(i32))
+			literal := fmt.Sprintf("$f32.%08x", i32)
 			s := obj.Linklookup(ctxt, literal, 0)
 			s.Size = 4
 			p.From.Type = obj.TYPE_MEM
@@ -263,7 +263,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	case AFMOVD:
 		if p.From.Type == obj.TYPE_FCONST {
 			i64 := math.Float64bits(p.From.Val.(float64))
-			literal := fmt.Sprintf("$f64.%016x", uint64(i64))
+			literal := fmt.Sprintf("$f64.%016x", i64)
 			s := obj.Linklookup(ctxt, literal, 0)
 			s.Size = 8
 			p.From.Type = obj.TYPE_MEM
@@ -421,7 +421,7 @@ func follow(ctxt *obj.Link, s *obj.LSym) {
 	s.Text = firstp.Link
 }
 
-func relinv(a int) int {
+func relinv(a obj.As) obj.As {
 	switch a {
 	case ABEQ:
 		return ABNE
@@ -464,14 +464,13 @@ func relinv(a int) int {
 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)
+	a := p.As
 	if a == AB {
 		q = p.Pcond
 		if q != nil {
@@ -490,7 +489,7 @@ loop:
 			if q == *last || q == nil {
 				break
 			}
-			a = int(q.As)
+			a = q.As
 			if a == obj.ANOP {
 				i--
 				continue
@@ -511,7 +510,7 @@ loop:
 				r = ctxt.NewProg()
 				*r = *p
 				if !(r.Mark&FOLL != 0) {
-					fmt.Printf("cant happen 1\n")
+					fmt.Printf("can't happen 1\n")
 				}
 				r.Mark |= FOLL
 				if p != q {
@@ -537,7 +536,7 @@ loop:
 					xfol(ctxt, r.Link, last)
 				}
 				if !(r.Pcond.Mark&FOLL != 0) {
-					fmt.Printf("cant happen 2\n")
+					fmt.Printf("can't happen 2\n")
 				}
 				return
 			}
@@ -545,7 +544,7 @@ loop:
 
 		a = AB
 		q = ctxt.NewProg()
-		q.As = int16(a)
+		q.As = a
 		q.Lineno = p.Lineno
 		q.To.Type = obj.TYPE_BRANCH
 		q.To.Offset = p.Pc
@@ -564,7 +563,7 @@ loop:
 			q = obj.Brchain(ctxt, p.Link)
 			if a != obj.ATEXT {
 				if q != nil && (q.Mark&FOLL != 0) {
-					p.As = int16(relinv(a))
+					p.As = relinv(a)
 					p.Link = p.Pcond
 					p.Pcond = q
 				}
@@ -671,11 +670,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		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)
+		o := p.As
 		switch o {
 		case obj.ATEXT:
 			cursym.Text = p
@@ -720,7 +718,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				aoffset = 0xF0
 			}
 			if cursym.Text.Mark&LEAF != 0 {
-				cursym.Leaf = 1
+				cursym.Leaf = true
 				if ctxt.Autosize == 0 {
 					break
 				}
@@ -780,7 +778,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REGG
-				q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R1
 
@@ -934,7 +932,7 @@ func nocache(p *obj.Prog) {
 	p.To.Class = 0
 }
 
-var unaryDst = map[int]bool{
+var unaryDst = map[obj.As]bool{
 	AWORD:  true,
 	ADWORD: true,
 	ABL:    true,
@@ -943,15 +941,10 @@ var unaryDst = map[int]bool{
 }
 
 var Linkarm64 = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "arm64",
-	Thechar:    '7',
+	Arch:       sys.ArchARM64,
 	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
index 96129fd..29530fa 100644
--- a/src/cmd/internal/obj/data.go
+++ b/src/cmd/internal/obj/data.go
@@ -9,7 +9,7 @@
 //	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.
+//	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
@@ -36,10 +36,11 @@ import (
 	"math"
 )
 
-func Symgrow(ctxt *Link, s *LSym, lsiz int64) {
+// Grow increases the length of s.P to lsiz.
+func (s *LSym) Grow(lsiz int64) {
 	siz := int(lsiz)
 	if int64(siz) != lsiz {
-		log.Fatalf("Symgrow size %d too long", lsiz)
+		log.Fatalf("LSym.Grow size %d too long", lsiz)
 	}
 	if len(s.P) >= siz {
 		return
@@ -52,65 +53,112 @@ func Symgrow(ctxt *Link, s *LSym, lsiz int64) {
 	s.P = s.P[:siz]
 }
 
-func savedata(ctxt *Link, s *LSym, p *Prog, file string) {
-	off := int32(p.From.Offset)
-	siz := int32(p.From3.Offset)
-	if off < 0 || siz < 0 || off >= 1<<30 || siz >= 100 {
-		log.Fatalf("%s: mangled input file", file)
+// GrowCap increases the capacity of s.P to c.
+func (s *LSym) GrowCap(c int64) {
+	if int64(cap(s.P)) >= c {
+		return
 	}
-	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)
+	if s.P == nil {
+		s.P = make([]byte, 0, c)
+		return
+	}
+	b := make([]byte, len(s.P), c)
+	copy(b, s.P)
+	s.P = b
+}
+
+// prepwrite prepares to write data of size siz into s at offset off.
+func (s *LSym) prepwrite(ctxt *Link, off int64, siz int) {
+	if off < 0 || siz < 0 || off >= 1<<30 {
+		log.Fatalf("prepwrite: bad off=%d siz=%d", off, siz)
 	}
 	if s.Type == SBSS || s.Type == STLSBSS {
 		ctxt.Diag("cannot supply data for BSS var")
 	}
-	Symgrow(ctxt, s, int64(off+siz))
+	l := off + int64(siz)
+	s.Grow(l)
+	if l > s.Size {
+		s.Size = l
+	}
+}
 
-	switch int(p.To.Type) {
+// WriteFloat32 writes f into s at offset off.
+func (s *LSym) WriteFloat32(ctxt *Link, off int64, f float32) {
+	s.prepwrite(ctxt, off, 4)
+	ctxt.Arch.ByteOrder.PutUint32(s.P[off:], math.Float32bits(f))
+}
+
+// WriteFloat64 writes f into s at offset off.
+func (s *LSym) WriteFloat64(ctxt *Link, off int64, f float64) {
+	s.prepwrite(ctxt, off, 8)
+	ctxt.Arch.ByteOrder.PutUint64(s.P[off:], math.Float64bits(f))
+}
+
+// WriteInt writes an integer i of size siz into s at offset off.
+func (s *LSym) WriteInt(ctxt *Link, off int64, siz int, i int64) {
+	s.prepwrite(ctxt, off, siz)
+	switch siz {
 	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))
-		}
+		ctxt.Diag("WriteInt: bad integer size: %d", siz)
+	case 1:
+		s.P[off] = byte(i)
+	case 2:
+		ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i))
+	case 4:
+		ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(i))
+	case 8:
+		ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(i))
+	}
+}
+
+// WriteAddr writes an address of size siz into s at offset off.
+// rsym and roff specify the relocation for the address.
+func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
+	if siz != ctxt.Arch.PtrSize {
+		ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name)
 	}
+	s.prepwrite(ctxt, off, siz)
+	r := Addrel(s)
+	r.Off = int32(off)
+	if int64(r.Off) != off {
+		ctxt.Diag("WriteAddr: off overflow %d in %s", off, s.Name)
+	}
+	r.Siz = uint8(siz)
+	r.Sym = rsym
+	r.Type = R_ADDR
+	r.Add = roff
+}
+
+// WriteOff writes a 4 byte offset to rsym+roff into s at offset off.
+// After linking the 4 bytes stored at s+off will be
+// rsym+roff-(start of section that s is in).
+func (s *LSym) WriteOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
+	s.prepwrite(ctxt, off, 4)
+	r := Addrel(s)
+	r.Off = int32(off)
+	if int64(r.Off) != off {
+		ctxt.Diag("WriteOff: off overflow %d in %s", off, s.Name)
+	}
+	r.Siz = 4
+	r.Sym = rsym
+	r.Type = R_ADDROFF
+	r.Add = roff
+}
+
+// WriteString writes a string of size siz into s at offset off.
+func (s *LSym) WriteString(ctxt *Link, off int64, siz int, str string) {
+	if siz < len(str) {
+		ctxt.Diag("WriteString: bad string size: %d < %d", siz, len(str))
+	}
+	s.prepwrite(ctxt, off, siz)
+	copy(s.P[off:off+int64(siz)], str)
+}
+
+// WriteBytes writes a slice of bytes into s at offset off.
+func (s *LSym) WriteBytes(ctxt *Link, off int64, b []byte) int64 {
+	s.prepwrite(ctxt, off, len(b))
+	copy(s.P[off:], b)
+	return off + int64(len(b))
 }
 
 func Addrel(s *LSym) *Reloc {
@@ -124,7 +172,7 @@ func Setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
 	}
 	if s.Size < off+wid {
 		s.Size = off + wid
-		Symgrow(ctxt, s, s.Size)
+		s.Grow(s.Size)
 	}
 
 	switch wid {
@@ -135,7 +183,7 @@ func Setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
 	case 4:
 		ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
 	case 8:
-		ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(v))
+		ctxt.Arch.ByteOrder.PutUint64(s.P[off:], v)
 	}
 
 	return off + wid
diff --git a/src/cmd/internal/obj/flag.go b/src/cmd/internal/obj/flag.go
index 0664f5c..ff69fd9 100644
--- a/src/cmd/internal/obj/flag.go
+++ b/src/cmd/internal/obj/flag.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -80,11 +80,6 @@ func (c *count) IsBoolFlag() bool {
 
 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)
diff --git a/src/cmd/internal/obj/fmt.go b/src/cmd/internal/obj/fmt.go
deleted file mode 100644
index f98bc6d..0000000
--- a/src/cmd/internal/obj/fmt.go
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- *              Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-package obj
-
-const (
-	FmtWidth = 1 << iota
-	FmtLeft
-	FmtSharp
-	FmtSign
-	FmtUnsigned
-	FmtShort
-	FmtLong
-	FmtComma
-	FmtByte
-	FmtBody // for printing export bodies
-)
diff --git a/src/cmd/internal/obj/funcdata.go b/src/cmd/internal/obj/funcdata.go
index 5291302..62256a3 100644
--- a/src/cmd/internal/obj/funcdata.go
+++ b/src/cmd/internal/obj/funcdata.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/cmd/internal/obj/go.go b/src/cmd/internal/obj/go.go
index 3e6cd21..1852dc7 100644
--- a/src/cmd/internal/obj/go.go
+++ b/src/cmd/internal/obj/go.go
@@ -13,7 +13,7 @@ import (
 // go-specific code shared across loaders (5l, 6l, 8l).
 
 var (
-	Framepointer_enabled int
+	framepointer_enabled int
 	Fieldtrack_enabled   int
 )
 
@@ -26,14 +26,21 @@ var exper = []struct {
 	val  *int
 }{
 	{"fieldtrack", &Fieldtrack_enabled},
-	{"framepointer", &Framepointer_enabled},
+	{"framepointer", &framepointer_enabled},
 }
 
 func addexp(s string) {
+	// Could do general integer parsing here, but the runtime copy doesn't yet.
+	v := 1
+	name := s
+	if len(name) > 2 && name[:2] == "no" {
+		v = 0
+		name = name[2:]
+	}
 	for i := 0; i < len(exper); i++ {
-		if exper[i].name == s {
+		if exper[i].name == name {
 			if exper[i].val != nil {
-				*exper[i].val = 1
+				*exper[i].val = v
 			}
 			return
 		}
@@ -44,6 +51,7 @@ func addexp(s string) {
 }
 
 func init() {
+	framepointer_enabled = 1 // default
 	for _, f := range strings.Split(goexperiment, ",") {
 		if f != "" {
 			addexp(f)
@@ -51,6 +59,10 @@ func init() {
 	}
 }
 
+func Framepointer_enabled(goos, goarch string) bool {
+	return framepointer_enabled != 0 && goarch == "amd64" && goos != "nacl"
+}
+
 func Nopout(p *Prog) {
 	p.As = ANOP
 	p.Scond = 0
@@ -60,15 +72,6 @@ func Nopout(p *Prog) {
 	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 {
diff --git a/src/cmd/internal/obj/ld.go b/src/cmd/internal/obj/ld.go
index 4d2e429..81a16d1 100644
--- a/src/cmd/internal/obj/ld.go
+++ b/src/cmd/internal/obj/ld.go
@@ -9,7 +9,7 @@
 //	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.
+//	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
diff --git a/src/cmd/internal/obj/line_test.go b/src/cmd/internal/obj/line_test.go
index 5486f0d..8f9bcd1 100644
--- a/src/cmd/internal/obj/line_test.go
+++ b/src/cmd/internal/obj/line_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -40,9 +40,7 @@ func TestLineHist(t *testing.T) {
 	}
 
 	for i, want := range expect {
-		var f *LSym
-		var l int32
-		linkgetline(ctxt, int32(i), &f, &l)
+		f, l := linkgetline(ctxt, int32(i))
 		have := fmt.Sprintf("%s:%d", f.Name, l)
 		if have != want {
 			t.Errorf("linkgetline(%d) = %q, want %q", i, have, want)
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 762a49e..b6861f4 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -30,7 +30,10 @@
 
 package obj
 
-import "encoding/binary"
+import (
+	"bufio"
+	"cmd/internal/sys"
+)
 
 // An Addr is an argument to an instruction.
 // The general forms and their encodings are:
@@ -144,10 +147,10 @@ import "encoding/binary"
 //			scale = 1
 //
 type Addr struct {
-	Type   int16
 	Reg    int16
 	Index  int16
 	Scale  int16 // Sometimes holds a register.
+	Type   AddrType
 	Name   int8
 	Class  int8
 	Etype  uint8
@@ -166,6 +169,8 @@ type Addr struct {
 	Node interface{} // for use by compiler
 }
 
+type AddrType uint8
+
 const (
 	NAME_NONE = 0 + iota
 	NAME_EXTERN
@@ -178,11 +183,9 @@ const (
 )
 
 const (
-	TYPE_NONE = 0
-)
+	TYPE_NONE AddrType = 0
 
-const (
-	TYPE_BRANCH = 5 + iota
+	TYPE_BRANCH AddrType = 5 + iota
 	TYPE_TEXTSIZE
 	TYPE_MEM
 	TYPE_CONST
@@ -198,7 +201,7 @@ const (
 )
 
 // TODO(rsc): Describe prog.
-// TODO(rsc): Describe TEXT/GLOBL flag in from3, DATA width in from3.
+// TODO(rsc): Describe TEXT/GLOBL flag in from3
 type Prog struct {
 	Ctxt   *Link
 	Link   *Prog
@@ -212,23 +215,23 @@ type Prog struct {
 	Pc     int64
 	Lineno int32
 	Spadj  int32
-	As     int16
+	As     As // Assembler opcode.
 	Reg    int16
-	RegTo2 int16 // 2nd register output operand
-	Mark   uint16
+	RegTo2 int16  // 2nd register output operand
+	Mark   uint16 // bitmask of arch-specific items
 	Optab  uint16
 	Scond  uint8
 	Back   uint8
 	Ft     uint8
 	Tt     uint8
-	Isize  uint8
+	Isize  uint8 // size of the instruction in bytes (x86 only)
 	Mode   int8
 
 	Info ProgInfo
 }
 
 // From3Type returns From3.Type, or TYPE_NONE when From3 is nil.
-func (p *Prog) From3Type() int16 {
+func (p *Prog) From3Type() AddrType {
 	if p.From3 == nil {
 		return TYPE_NONE
 	}
@@ -254,19 +257,18 @@ type ProgInfo struct {
 	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.
+// An As denotes an assembler opcode.
+// There are some portable opcodes, declared here in package obj,
+// that are common to all architectures.
+// However, the majority of opcodes are arch-specific
+// and are declared in their respective architecture's subpackage.
+type As int16
+
+// These are the portable opcodes.
 const (
-	AXXX = 0 + iota
+	AXXX As = iota
 	ACALL
 	ACHECKNIL
-	ADATA
 	ADUFFCOPY
 	ADUFFZERO
 	AEND
@@ -286,38 +288,71 @@ const (
 	A_ARCHSPECIFIC
 )
 
+// Each architecture is allotted a distinct subspace of opcode values
+// for declaring its arch-specific opcodes.
+// Within this subspace, the first arch-specific opcode should be
+// at offset A_ARCHSPECIFIC.
+//
+// Subspaces are aligned to a power of two so opcodes can be masked
+// with AMask and used as compact array indices.
+const (
+	ABase386 = (1 + iota) << 12
+	ABaseARM
+	ABaseAMD64
+	ABasePPC64
+	ABaseARM64
+	ABaseMIPS64
+	ABaseS390X
+
+	AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
+)
+
 // 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
+	Dupok     bool
+	Cfunc     bool
+	Nosplit   bool
+	Leaf      bool
+	Seenglobl bool
+	Onlist    bool
+
+	// ReflectMethod means the function may call reflect.Type.Method or
+	// reflect.Type.MethodByName. Matching is imprecise (as reflect.Type
+	// can be used through a custom interface), so ReflectMethod may be
+	// set in some cases when the reflect package is not called.
+	//
+	// Used by the linker to determine what methods can be pruned.
+	ReflectMethod bool
+
 	// 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
+	Local bool
+
+	RefIdx int // Index of this symbol in the symbol reference list.
 	Args   int32
 	Locals int32
-	Value  int64
 	Size   int64
-	Next   *LSym
 	Gotype *LSym
 	Autom  *Auto
 	Text   *Prog
-	Etext  *Prog
 	Pcln   *Pcln
 	P      []byte
 	R      []Reloc
 }
 
+// The compiler needs LSym to satisfy fmt.Stringer, because it stores
+// an LSym in ssa.ExternSymbol.
+func (s *LSym) String() string {
+	return s.Name
+}
+
 type Pcln struct {
 	Pcsp        Pcdata
 	Pcfile      Pcdata
@@ -339,6 +374,7 @@ const (
 	STYPE
 	SSTRING
 	SGOSTRING
+	SGOSTRINGHDR
 	SGOFUNC
 	SGCBITS
 	SRODATA
@@ -357,12 +393,14 @@ const (
 	STYPERELRO
 	SSTRINGRELRO
 	SGOSTRINGRELRO
+	SGOSTRINGHDRRELRO
 	SGOFUNCRELRO
 	SGCBITSRELRO
 	SRODATARELRO
 	SFUNCTABRELRO
 
 	STYPELINK
+	SITABLINK
 	SSYMTAB
 	SPCLNTAB
 	SELFROSECT
@@ -388,6 +426,8 @@ const (
 	SCONST
 	SDYNIMPORT
 	SHOSTOBJ
+	SDWARFSECT
+	SDWARFINFO
 	SSUB       = 1 << 8
 	SMASK      = SSUB - 1
 	SHIDDEN    = 1 << 9
@@ -414,9 +454,12 @@ const (
 	// R_ADDRARM64 relocates an adrp, add pair to compute the address of the
 	// referenced symbol.
 	R_ADDRARM64
-	// R_ADDRMIPS (only used on mips64) resolves to a 32-bit external address,
-	// by loading the address into a register with two instructions (lui, ori).
+	// R_ADDRMIPS (only used on mips64) resolves to the low 16 bits of an external
+	// address, by encoding it into the instruction.
 	R_ADDRMIPS
+	// R_ADDROFF resolves to a 32-bit offset from the beginning of the section
+	// holding the data being relocated to the referenced symbol.
+	R_ADDROFF
 	R_SIZE
 	R_CALL
 	R_CALLARM
@@ -444,18 +487,31 @@ const (
 	R_PLT1
 	R_PLT2
 	R_USEFIELD
+	// R_USETYPE resolves to an *rtype, but no relocation is created. The
+	// linker uses this as a signal that the pointed-to type information
+	// should be linked into the final binary, even if there are no other
+	// direct references. (This is used for types reachable by reflection.)
+	R_USETYPE
+	// R_METHODOFF resolves to a 32-bit offset from the beginning of the section
+	// holding the data being relocated to the referenced symbol.
+	// It is a variant of R_ADDROFF used when linking from the uncommonType of a
+	// *rtype, and may be set to zero by the linker if it determines the method
+	// text is unreachable by the linked program.
+	R_METHODOFF
 	R_POWER_TOC
 	R_GOTPCREL
 	// R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address
 	// of a JMP instruction, by encoding the address into the instruction.
 	// The stack nosplit check ignores this since it is not a function call.
 	R_JMPMIPS
+	// R_DWARFREF resolves to the offset of the symbol from its section.
+	R_DWARFREF
 
 	// Platform dependent relocations. Architectures with fixed width instructions
 	// have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be
 	// stuffed into a 32-bit instruction, so an address needs to be spread across
 	// several instructions, and in turn this requires a sequence of relocations, each
-	// updating a part of an instruction.  This leads to relocation codes that are
+	// updating a part of an instruction. This leads to relocation codes that are
 	// inherently processor specific.
 
 	// Arm64.
@@ -521,6 +577,17 @@ const (
 	// R_ADDRPOWER_DS but inserts the offset from the TOC to the address of the the
 	// relocated symbol rather than the symbol's address.
 	R_ADDRPOWER_TOCREL_DS
+
+	// R_PCRELDBL relocates s390x 2-byte aligned PC-relative addresses.
+	// TODO(mundaym): remove once variants can be serialized - see issue 14218.
+	R_PCRELDBL
+
+	// R_ADDRMIPSU (only used on mips64) resolves to the sign-adjusted "upper" 16
+	// bits (bit 16-31) of an external address, by encoding it into the instruction.
+	R_ADDRMIPSU
+	// R_ADDRMIPSTLS (only used on mips64) resolves to the low 16 bits of a TLS
+	// address (offset from thread pointer), by encoding it into the instruction.
+	R_ADDRMIPSTLS
 )
 
 type Auto struct {
@@ -541,19 +608,6 @@ 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 (
@@ -563,60 +617,62 @@ const (
 // 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
-	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
-	Plan9privates      *LSym
-	Curp               *Prog
-	Printp             *Prog
-	Blitrl             *Prog
-	Elitrl             *Prog
-	Rexflag            int
-	Vexflag            int
-	Rep                int
-	Repn               int
-	Lock               int
-	Asmode             int
-	Andptr             []byte
-	And                [100]uint8
-	Instoffset         int64
-	Autosize           int32
-	Armsize            int32
-	Pc                 int64
-	DiagFunc           func(string, ...interface{})
-	Mode               int
-	Cursym             *LSym
-	Version            int
-	Textp              *LSym
-	Etextp             *LSym
-	Errors             int
+	Goarm         int32
+	Headtype      int
+	Arch          *LinkArch
+	Debugasm      int32
+	Debugvlog     int32
+	Debugdivmod   int32
+	Debugpcln     int32
+	Flag_shared   bool
+	Flag_dynlink  bool
+	Flag_optimize bool
+	Bso           *bufio.Writer
+	Pathname      string
+	Goroot        string
+	Goroot_final  string
+	Hash          map[SymVer]*LSym
+	LineHist      LineHist
+	Imports       []string
+	Plist         *Plist
+	Plast         *Plist
+	Sym_div       *LSym
+	Sym_divu      *LSym
+	Sym_mod       *LSym
+	Sym_modu      *LSym
+	Plan9privates *LSym
+	Curp          *Prog
+	Printp        *Prog
+	Blitrl        *Prog
+	Elitrl        *Prog
+	Rexflag       int
+	Vexflag       int
+	Rep           int
+	Repn          int
+	Lock          int
+	Asmode        int
+	AsmBuf        AsmBuf // instruction buffer for x86
+	Instoffset    int64
+	Autosize      int32
+	Armsize       int32
+	Pc            int64
+	DiagFunc      func(string, ...interface{})
+	Mode          int
+	Cursym        *LSym
+	Version       int
+	Textp         *LSym
+	Etextp        *LSym
+	Errors        int
+
+	Framepointer_enabled bool
 
 	// state for writing objects
-	Text  *LSym
-	Data  *LSym
-	Etext *LSym
-	Edata *LSym
+	Text []*LSym
+	Data []*LSym
+
+	// Cache of Progs
+	allocIdx int
+	progs    [10000]Prog
 }
 
 func (ctxt *Link) Diag(format string, args ...interface{}) {
@@ -629,15 +685,15 @@ func (ctxt *Link) Diag(format string, args ...interface{}) {
 // on the stack in the function prologue and so always have a pointer between
 // the hardware stack pointer and the local variable area.
 func (ctxt *Link) FixedFrameSize() int64 {
-	switch ctxt.Arch.Thechar {
-	case '6', '8':
+	switch ctxt.Arch.Family {
+	case sys.AMD64, sys.I386:
 		return 0
-	case '9':
+	case sys.PPC64:
 		// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
 		// just use that much stack always on ppc64x.
-		return int64(4 * ctxt.Arch.Ptrsize)
+		return int64(4 * ctxt.Arch.PtrSize)
 	default:
-		return int64(ctxt.Arch.Ptrsize)
+		return int64(ctxt.Arch.PtrSize)
 	}
 }
 
@@ -648,17 +704,12 @@ type SymVer struct {
 
 // LinkArch is the definition of a single architecture.
 type LinkArch struct {
-	ByteOrder  binary.ByteOrder
-	Name       string
-	Thechar    int
+	*sys.Arch
 	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
+	UnaryDst   map[As]bool // Instruction takes one operand, a destination.
 }
 
 /* executable header types */
@@ -666,7 +717,6 @@ const (
 	Hunknown = 0 + iota
 	Hdarwin
 	Hdragonfly
-	Helf
 	Hfreebsd
 	Hlinux
 	Hnacl
@@ -677,23 +727,95 @@ const (
 	Hwindows
 )
 
-type Plist struct {
-	Name    *LSym
-	Firstpc *Prog
-	Recur   int
-	Link    *Plist
+// AsmBuf is a simple buffer to assemble variable-length x86 instructions into.
+type AsmBuf struct {
+	buf [100]byte
+	off int
 }
 
-/*
- * 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
+// Put1 appends one byte to the end of the buffer.
+func (a *AsmBuf) Put1(x byte) {
+	a.buf[a.off] = x
+	a.off++
+}
+
+// Put2 appends two bytes to the end of the buffer.
+func (a *AsmBuf) Put2(x, y byte) {
+	a.buf[a.off+0] = x
+	a.buf[a.off+1] = y
+	a.off += 2
+}
+
+// Put3 appends three bytes to the end of the buffer.
+func (a *AsmBuf) Put3(x, y, z byte) {
+	a.buf[a.off+0] = x
+	a.buf[a.off+1] = y
+	a.buf[a.off+2] = z
+	a.off += 3
+}
+
+// Put4 appends four bytes to the end of the buffer.
+func (a *AsmBuf) Put4(x, y, z, w byte) {
+	a.buf[a.off+0] = x
+	a.buf[a.off+1] = y
+	a.buf[a.off+2] = z
+	a.buf[a.off+3] = w
+	a.off += 4
+}
+
+// PutInt16 writes v into the buffer using little-endian encoding.
+func (a *AsmBuf) PutInt16(v int16) {
+	a.buf[a.off+0] = byte(v)
+	a.buf[a.off+1] = byte(v >> 8)
+	a.off += 2
+}
+
+// PutInt32 writes v into the buffer using little-endian encoding.
+func (a *AsmBuf) PutInt32(v int32) {
+	a.buf[a.off+0] = byte(v)
+	a.buf[a.off+1] = byte(v >> 8)
+	a.buf[a.off+2] = byte(v >> 16)
+	a.buf[a.off+3] = byte(v >> 24)
+	a.off += 4
+}
+
+// PutInt64 writes v into the buffer using little-endian encoding.
+func (a *AsmBuf) PutInt64(v int64) {
+	a.buf[a.off+0] = byte(v)
+	a.buf[a.off+1] = byte(v >> 8)
+	a.buf[a.off+2] = byte(v >> 16)
+	a.buf[a.off+3] = byte(v >> 24)
+	a.buf[a.off+4] = byte(v >> 32)
+	a.buf[a.off+5] = byte(v >> 40)
+	a.buf[a.off+6] = byte(v >> 48)
+	a.buf[a.off+7] = byte(v >> 56)
+	a.off += 8
+}
+
+// Put copies b into the buffer.
+func (a *AsmBuf) Put(b []byte) {
+	copy(a.buf[a.off:], b)
+	a.off += len(b)
+}
+
+// Insert inserts b at offset i.
+func (a *AsmBuf) Insert(i int, b byte) {
+	a.off++
+	copy(a.buf[i+1:a.off], a.buf[i:a.off-1])
+	a.buf[i] = b
 }
+
+// Last returns the byte at the end of the buffer.
+func (a *AsmBuf) Last() byte { return a.buf[a.off-1] }
+
+// Len returns the length of the buffer.
+func (a *AsmBuf) Len() int { return a.off }
+
+// Bytes returns the contents of the buffer.
+func (a *AsmBuf) Bytes() []byte { return a.buf[:a.off] }
+
+// Reset empties the buffer.
+func (a *AsmBuf) Reset() { a.off = 0 }
+
+// Peek returns the byte at offset i.
+func (a *AsmBuf) Peek(i int) byte { return a.buf[i] }
diff --git a/src/cmd/internal/obj/mips/a.out.go b/src/cmd/internal/obj/mips/a.out.go
index 282cb79..bc6b69d 100644
--- a/src/cmd/internal/obj/mips/a.out.go
+++ b/src/cmd/internal/obj/mips/a.out.go
@@ -7,7 +7,7 @@
 //	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.
+//	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
@@ -187,7 +187,7 @@ const (
 
 	REGZERO  = REG_R0 /* set to zero */
 	REGSP    = REG_R29
-	REGSB    = REG_R30
+	REGSB    = REG_R28
 	REGLINK  = REG_R31
 	REGRET   = REG_R1
 	REGARG   = -1      /* -1 disables passing the first argument in register */
@@ -195,7 +195,7 @@ const (
 	REGRT2   = REG_R2  /* reserved for runtime, duffcopy */
 	REGCTXT  = REG_R22 /* context for closures */
 	REGG     = REG_R30 /* G */
-	REGTMP   = REG_R28 /* used by the linker */
+	REGTMP   = REG_R23 /* used by the linker */
 	FREGRET  = REG_F0
 	FREGZERO = REG_F24 /* both float and double */
 	FREGHALF = REG_F26 /* double */
@@ -243,6 +243,7 @@ const (
 	C_LACON /* $n(REG) where int16 < n <= int32 */
 	C_LECON
 	C_DACON /* $n(REG) where int32 < n */
+	C_STCON /* $tlsvar */
 	C_SBRA
 	C_LBRA
 	C_SAUTO
@@ -254,6 +255,7 @@ const (
 	C_LOREG
 	C_GOK
 	C_ADDR
+	C_TLS
 	C_TEXTSIZE
 
 	C_NCLASS /* must be the last */
@@ -292,6 +294,7 @@ const (
 	ADIVU
 	ADIVW
 	AGOK
+	ALUI
 	AMOVB
 	AMOVBU
 	AMOVD
diff --git a/src/cmd/internal/obj/mips/anames.go b/src/cmd/internal/obj/mips/anames.go
index a943e50..c784809 100644
--- a/src/cmd/internal/obj/mips/anames.go
+++ b/src/cmd/internal/obj/mips/anames.go
@@ -38,6 +38,7 @@ var Anames = []string{
 	"DIVU",
 	"DIVW",
 	"GOK",
+	"LUI",
 	"MOVB",
 	"MOVBU",
 	"MOVD",
diff --git a/src/cmd/internal/obj/mips/anames0.go b/src/cmd/internal/obj/mips/anames0.go
index 7f342e6..c56d34e 100644
--- a/src/cmd/internal/obj/mips/anames0.go
+++ b/src/cmd/internal/obj/mips/anames0.go
@@ -1,3 +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.
+
 package mips
 
 var cnames0 = []string{
@@ -22,6 +26,7 @@ var cnames0 = []string{
 	"LACON",
 	"LECON",
 	"DACON",
+	"STCON",
 	"SBRA",
 	"LBRA",
 	"SAUTO",
@@ -33,6 +38,7 @@ var cnames0 = []string{
 	"LOREG",
 	"GOK",
 	"ADDR",
+	"TLS",
 	"TEXTSIZE",
 	"NCLASS",
 }
diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go
index 63df672..11aa202 100644
--- a/src/cmd/internal/obj/mips/asm0.go
+++ b/src/cmd/internal/obj/mips/asm0.go
@@ -7,7 +7,7 @@
 //	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.
+//	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
@@ -47,7 +47,7 @@ const (
 )
 
 type Optab struct {
-	as    int16
+	as    obj.As
 	a1    uint8
 	a2    uint8
 	a3    uint8
@@ -60,7 +60,7 @@ var optab = []Optab{
 	{obj.ATEXT, C_LEXT, C_NONE, C_TEXTSIZE, 0, 0, 0},
 	{obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0},
 
-	{AMOVW, C_REG, C_NONE, C_REG, 14, 8, 0},
+	{AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0},
 	{AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0},
 	{AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0},
 	{AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0},
@@ -121,60 +121,72 @@ var optab = []Optab{
 	{AMOVBU, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO},
 	{AMOVWL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO},
 
-	{AMOVW, C_REG, C_NONE, C_LEXT, 35, 16, REGSB},
-	{AMOVWU, C_REG, C_NONE, C_LEXT, 35, 16, REGSB},
-	{AMOVV, C_REG, C_NONE, C_LEXT, 35, 16, REGSB},
-	{AMOVB, C_REG, C_NONE, C_LEXT, 35, 16, REGSB},
-	{AMOVBU, C_REG, C_NONE, C_LEXT, 35, 16, REGSB},
-	{AMOVW, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP},
-	{AMOVWU, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP},
-	{AMOVV, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP},
-	{AMOVB, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP},
-	{AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 16, REGSP},
-	{AMOVW, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO},
-	{AMOVWU, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO},
-	{AMOVV, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO},
-	{AMOVB, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO},
-	{AMOVBU, C_REG, C_NONE, C_LOREG, 35, 16, REGZERO},
+	{AMOVW, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
+	{AMOVWU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
+	{AMOVV, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
+	{AMOVB, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
+	{AMOVBU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
+	{AMOVW, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
+	{AMOVWU, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
+	{AMOVV, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
+	{AMOVB, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
+	{AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
+	{AMOVW, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
+	{AMOVWU, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
+	{AMOVV, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
+	{AMOVB, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
+	{AMOVBU, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
 	{AMOVW, C_REG, C_NONE, C_ADDR, 50, 12, 0},
 	{AMOVWU, C_REG, C_NONE, C_ADDR, 50, 12, 0},
 	{AMOVV, C_REG, C_NONE, C_ADDR, 50, 12, 0},
 	{AMOVB, C_REG, C_NONE, C_ADDR, 50, 12, 0},
 	{AMOVBU, C_REG, C_NONE, C_ADDR, 50, 12, 0},
-
-	{AMOVW, C_LEXT, C_NONE, C_REG, 36, 16, REGSB},
-	{AMOVWU, C_LEXT, C_NONE, C_REG, 36, 16, REGSB},
-	{AMOVV, C_LEXT, C_NONE, C_REG, 36, 16, REGSB},
-	{AMOVB, C_LEXT, C_NONE, C_REG, 36, 16, REGSB},
-	{AMOVBU, C_LEXT, C_NONE, C_REG, 36, 16, REGSB},
-	{AMOVW, C_LAUTO, C_NONE, C_REG, 36, 16, REGSP},
-	{AMOVWU, C_LAUTO, C_NONE, C_REG, 36, 16, REGSP},
-	{AMOVV, C_LAUTO, C_NONE, C_REG, 36, 16, REGSP},
-	{AMOVB, C_LAUTO, C_NONE, C_REG, 36, 16, REGSP},
-	{AMOVBU, C_LAUTO, C_NONE, C_REG, 36, 16, REGSP},
-	{AMOVW, C_LOREG, C_NONE, C_REG, 36, 16, REGZERO},
-	{AMOVWU, C_LOREG, C_NONE, C_REG, 36, 16, REGZERO},
-	{AMOVV, C_LOREG, C_NONE, C_REG, 36, 16, REGZERO},
-	{AMOVB, C_LOREG, C_NONE, C_REG, 36, 16, REGZERO},
-	{AMOVBU, C_LOREG, C_NONE, C_REG, 36, 16, REGZERO},
+	{AMOVW, C_REG, C_NONE, C_TLS, 53, 8, 0},
+	{AMOVWU, C_REG, C_NONE, C_TLS, 53, 8, 0},
+	{AMOVV, C_REG, C_NONE, C_TLS, 53, 8, 0},
+	{AMOVB, C_REG, C_NONE, C_TLS, 53, 8, 0},
+	{AMOVBU, C_REG, C_NONE, C_TLS, 53, 8, 0},
+
+	{AMOVW, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
+	{AMOVWU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
+	{AMOVV, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
+	{AMOVB, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
+	{AMOVBU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
+	{AMOVW, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
+	{AMOVWU, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
+	{AMOVV, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
+	{AMOVB, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
+	{AMOVBU, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
+	{AMOVW, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
+	{AMOVWU, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
+	{AMOVV, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
+	{AMOVB, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
+	{AMOVBU, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
 	{AMOVW, C_ADDR, C_NONE, C_REG, 51, 12, 0},
 	{AMOVWU, C_ADDR, C_NONE, C_REG, 51, 12, 0},
 	{AMOVV, C_ADDR, C_NONE, C_REG, 51, 12, 0},
 	{AMOVB, C_ADDR, C_NONE, C_REG, 51, 12, 0},
 	{AMOVBU, C_ADDR, C_NONE, C_REG, 51, 12, 0},
+	{AMOVW, C_TLS, C_NONE, C_REG, 54, 8, 0},
+	{AMOVWU, C_TLS, C_NONE, C_REG, 54, 8, 0},
+	{AMOVV, C_TLS, C_NONE, C_REG, 54, 8, 0},
+	{AMOVB, C_TLS, C_NONE, C_REG, 54, 8, 0},
+	{AMOVBU, C_TLS, C_NONE, C_REG, 54, 8, 0},
 
 	{AMOVW, C_SECON, C_NONE, C_REG, 3, 4, REGSB},
 	{AMOVV, C_SECON, C_NONE, C_REG, 3, 4, REGSB},
 	{AMOVW, C_SACON, C_NONE, C_REG, 3, 4, REGSP},
 	{AMOVV, C_SACON, C_NONE, C_REG, 3, 4, REGSP},
-	{AMOVW, C_LECON, C_NONE, C_REG, 26, 12, REGSB},
-	{AMOVV, C_LECON, C_NONE, C_REG, 26, 12, REGSB},
+	{AMOVW, C_LECON, C_NONE, C_REG, 52, 12, REGSB},
+	{AMOVV, C_LECON, C_NONE, C_REG, 52, 12, REGSB},
 	{AMOVW, C_LACON, C_NONE, C_REG, 26, 12, REGSP},
 	{AMOVV, C_LACON, C_NONE, C_REG, 26, 12, REGSP},
 	{AMOVW, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO},
 	{AMOVV, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO},
 	{AMOVW, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO},
 	{AMOVV, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO},
+	{AMOVW, C_STCON, C_NONE, C_REG, 55, 8, 0},
+	{AMOVV, C_STCON, C_NONE, C_REG, 55, 8, 0},
 
 	{AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0},
 	{AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0},
@@ -238,15 +250,15 @@ var optab = []Optab{
 	{AMOVF, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO},
 	{AMOVD, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO},
 
-	{AMOVW, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB},
-	{AMOVF, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB},
-	{AMOVD, C_LEXT, C_NONE, C_FREG, 27, 16, REGSB},
-	{AMOVW, C_LAUTO, C_NONE, C_FREG, 27, 16, REGSP},
-	{AMOVF, C_LAUTO, C_NONE, C_FREG, 27, 16, REGSP},
-	{AMOVD, C_LAUTO, C_NONE, C_FREG, 27, 16, REGSP},
-	{AMOVW, C_LOREG, C_NONE, C_FREG, 27, 16, REGZERO},
-	{AMOVF, C_LOREG, C_NONE, C_FREG, 27, 16, REGZERO},
-	{AMOVD, C_LOREG, C_NONE, C_FREG, 27, 16, REGZERO},
+	{AMOVW, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB},
+	{AMOVF, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB},
+	{AMOVD, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB},
+	{AMOVW, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP},
+	{AMOVF, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP},
+	{AMOVD, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP},
+	{AMOVW, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO},
+	{AMOVF, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO},
+	{AMOVD, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO},
 	{AMOVF, C_ADDR, C_NONE, C_FREG, 51, 12, 0},
 	{AMOVD, C_ADDR, C_NONE, C_FREG, 51, 12, 0},
 
@@ -260,15 +272,15 @@ var optab = []Optab{
 	{AMOVF, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO},
 	{AMOVD, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO},
 
-	{AMOVW, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB},
-	{AMOVF, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB},
-	{AMOVD, C_FREG, C_NONE, C_LEXT, 28, 16, REGSB},
-	{AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP},
-	{AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP},
-	{AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 16, REGSP},
-	{AMOVW, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO},
-	{AMOVF, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO},
-	{AMOVD, C_FREG, C_NONE, C_LOREG, 28, 16, REGZERO},
+	{AMOVW, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB},
+	{AMOVF, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB},
+	{AMOVD, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB},
+	{AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP},
+	{AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP},
+	{AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP},
+	{AMOVW, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO},
+	{AMOVF, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO},
+	{AMOVD, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO},
 	{AMOVF, C_FREG, C_NONE, C_ADDR, 50, 12, 0},
 	{AMOVD, C_FREG, C_NONE, C_ADDR, 50, 12, 0},
 
@@ -279,8 +291,6 @@ var optab = []Optab{
 
 	{AMOVW, C_ADDCON, C_NONE, C_FREG, 34, 8, 0},
 	{AMOVW, C_ANDCON, C_NONE, C_FREG, 34, 8, 0},
-	{AMOVW, C_UCON, C_NONE, C_FREG, 35, 8, 0},
-	{AMOVW, C_LCON, C_NONE, C_FREG, 36, 12, 0},
 
 	{AMOVW, C_REG, C_NONE, C_MREG, 37, 4, 0},
 	{AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0},
@@ -310,14 +320,9 @@ var optab = []Optab{
 	{obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0},
 }
 
-type Oprang struct {
-	start []Optab
-	stop  []Optab
-}
-
-var oprange [ALAST & obj.AMask]Oprang
+var oprange [ALAST & obj.AMask][]Optab
 
-var xcmp [C_NCLASS][C_NCLASS]uint8
+var xcmp [C_NCLASS][C_NCLASS]bool
 
 func span0(ctxt *obj.Link, cursym *obj.LSym) {
 	p := cursym.Text
@@ -327,7 +332,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) {
 	ctxt.Cursym = cursym
 	ctxt.Autosize = int32(p.To.Offset + 8)
 
-	if oprange[AOR&obj.AMask].start == nil {
+	if oprange[AOR&obj.AMask] == nil {
 		buildop(ctxt)
 	}
 
@@ -420,7 +425,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) {
 	 * lay out the code, emitting code and data relocations.
 	 */
 
-	obj.Symgrow(ctxt, cursym, cursym.Size)
+	cursym.Grow(cursym.Size)
 
 	bp := cursym.P
 	var i int32
@@ -483,6 +488,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			}
 			ctxt.Instoffset = a.Offset
 			if a.Sym != nil { // use relocation
+				if a.Sym.Type == obj.STLSBSS {
+					return C_TLS
+				}
 				return C_ADDR
 			}
 			return C_LEXT
@@ -541,14 +549,15 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 				break
 			}
 			if s.Type == obj.SCONST {
-				ctxt.Instoffset = s.Value + a.Offset
+				ctxt.Instoffset = a.Offset
 				goto consize
 			}
 
-			ctxt.Instoffset = s.Value + a.Offset
-
-			/* not sure why this barfs */
-			return C_LCON
+			ctxt.Instoffset = a.Offset
+			if s.Type == obj.STLSBSS {
+				return C_STCON // address of TLS variable
+			}
+			return C_LECON
 
 		case obj.NAME_AUTO:
 			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
@@ -610,13 +619,13 @@ func prasm(p *obj.Prog) {
 }
 
 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
-	if oprange[AOR&obj.AMask].start == nil {
+	if oprange[AOR&obj.AMask] == nil {
 		buildop(ctxt)
 	}
 
 	a1 := int(p.Optab)
 	if a1 != 0 {
-		return &optab[a1-1:][0]
+		return &optab[a1-1]
 	}
 	a1 = int(p.From.Class)
 	if a1 == 0 {
@@ -638,32 +647,24 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	}
 
 	//print("oplook %P %d %d %d\n", p, a1, a2, a3);
-	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][:]
-	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]
-				}
-			}
+	ops := oprange[p.As&obj.AMask]
+	c1 := &xcmp[a1]
+	c3 := &xcmp[a3]
+	for i := range ops {
+		op := &ops[i]
+		if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] {
+			p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
+			return op
 		}
 	}
 
-	ctxt.Diag("illegal combination %v %v %v %v", obj.Aconv(int(p.As)), DRconv(a1), DRconv(a2), DRconv(a3))
+	ctxt.Diag("illegal combination %v %v %v %v", obj.Aconv(p.As), DRconv(a1), DRconv(a2), DRconv(a3))
 	prasm(p)
-	if o == nil {
-		o = optab
+	if ops == nil {
+		ops = optab
 	}
-	return &o[0]
+	return &ops[0]
 }
 
 func cmp(a int, b int) bool {
@@ -778,7 +779,8 @@ func (x ocmp) Less(i, j int) bool {
 	}
 	return false
 }
-func opset(a, b0 int16) {
+
+func opset(a, b0 obj.As) {
 	oprange[a&obj.AMask] = oprange[b0]
 }
 
@@ -788,7 +790,7 @@ func buildop(ctxt *obj.Link) {
 	for i := 0; i < C_NCLASS; i++ {
 		for n = 0; n < C_NCLASS; n++ {
 			if cmp(n, i) {
-				xcmp[i][n] = 1
+				xcmp[i][n] = true
 			}
 		}
 	}
@@ -798,16 +800,16 @@ func buildop(ctxt *obj.Link) {
 	for i := 0; i < n; i++ {
 		r := optab[i].as
 		r0 := r & obj.AMask
-		oprange[r0].start = optab[i:]
+		start := i
 		for optab[i].as == r {
 			i++
 		}
-		oprange[r0].stop = optab[i:]
+		oprange[r0] = optab[start:i]
 		i--
 
 		switch r {
 		default:
-			ctxt.Diag("unknown op in build: %v", obj.Aconv(int(r)))
+			ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
 			log.Fatalf("bad code")
 
 		case AABSF:
@@ -987,10 +989,6 @@ func OP_JMP(op uint32, i uint32) uint32 {
 	return op | i&0x3FFFFFF
 }
 
-func oclass(a *obj.Addr) int {
-	return int(a.Class) - 1
-}
-
 func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	o1 := uint32(0)
 	o2 := uint32(0)
@@ -1006,7 +1004,11 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		break
 
 	case 1: /* mov r1,r2 ==> OR r1,r0,r2 */
-		o1 = OP_RRR(oprrr(ctxt, AOR), uint32(p.From.Reg), uint32(REGZERO), uint32(p.To.Reg))
+		a := AOR
+		if p.As == AMOVW {
+			a = AADDU // sign-extended to high 32 bits
+		}
+		o1 = OP_RRR(oprrr(ctxt, a), uint32(p.From.Reg), uint32(REGZERO), uint32(p.To.Reg))
 
 	case 2: /* add/sub r1,[r2],r3 */
 		r := int(p.Reg)
@@ -1014,7 +1016,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = OP_RRR(oprrr(ctxt, int(p.As)), uint32(p.From.Reg), uint32(r), uint32(p.To.Reg))
+		o1 = OP_RRR(oprrr(ctxt, p.As), uint32(p.From.Reg), uint32(r), uint32(p.To.Reg))
 
 	case 3: /* mov $soreg, r ==> or/add $i,o,r */
 		v := regoff(ctxt, &p.From)
@@ -1038,10 +1040,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			r = int(p.To.Reg)
 		}
 
-		o1 = OP_IRR(opirr(ctxt, int(p.As)), uint32(v), uint32(r), uint32(p.To.Reg))
+		o1 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(r), uint32(p.To.Reg))
 
 	case 5: /* syscall */
-		o1 = uint32(oprrr(ctxt, int(p.As)))
+		o1 = oprrr(ctxt, p.As)
 
 	case 6: /* beq r1,[r2],sbra */
 		v := int32(0)
@@ -1053,7 +1055,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if (v<<16)>>16 != v {
 			ctxt.Diag("short branch too far\n%v", p)
 		}
-		o1 = OP_IRR(opirr(ctxt, int(p.As)), uint32(v), uint32(p.From.Reg), uint32(p.Reg))
+		o1 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(p.From.Reg), uint32(p.Reg))
 		// for ABFPT and ABFPF only: always fill delay slot with 0
 		// see comments in func preprocess for details.
 		o2 = 0
@@ -1064,7 +1066,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			r = int(o.param)
 		}
 		v := regoff(ctxt, &p.To)
-		o1 = OP_IRR(opirr(ctxt, int(p.As)), uint32(v), uint32(r), uint32(p.From.Reg))
+		o1 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(r), uint32(p.From.Reg))
 
 	case 8: /* mov soreg, r ==> lw o(r) */
 		r := int(p.From.Reg)
@@ -1072,7 +1074,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			r = int(o.param)
 		}
 		v := regoff(ctxt, &p.From)
-		o1 = OP_IRR(opirr(ctxt, int(p.As)+ALAST), uint32(v), uint32(r), uint32(p.To.Reg))
+		o1 = OP_IRR(opirr(ctxt, -p.As), uint32(v), uint32(r), uint32(p.To.Reg))
 
 	case 9: /* sll r1,[r2],r3 */
 		r := int(p.Reg)
@@ -1080,7 +1082,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = OP_RRR(oprrr(ctxt, int(p.As)), uint32(r), uint32(p.From.Reg), uint32(p.To.Reg))
+		o1 = OP_RRR(oprrr(ctxt, p.As), uint32(r), uint32(p.From.Reg), uint32(p.To.Reg))
 
 	case 10: /* add $con,[r1],r2 ==> mov $con, t; add t,[r1],r2 */
 		v := regoff(ctxt, &p.From)
@@ -1093,7 +1095,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o2 = OP_RRR(oprrr(ctxt, int(p.As)), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
+		o2 = OP_RRR(oprrr(ctxt, p.As), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
 
 	case 11: /* jmp lbra */
 		v := int32(0)
@@ -1115,7 +1117,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		} else {
 			v = int32(p.Pcond.Pc) >> 2
 		}
-		o1 = OP_JMP(opirr(ctxt, int(p.As)), uint32(v))
+		o1 = OP_JMP(opirr(ctxt, p.As), uint32(v))
 		if p.To.Sym == nil {
 			p.To.Sym = ctxt.Cursym.Text.From.Sym
 			p.To.Offset = p.Pcond.Pc
@@ -1147,12 +1149,8 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 14: /* movwu r,r */
-		o1 = OP_SRR(opirr(ctxt, ASLLV+ALAST), uint32(0), uint32(p.From.Reg), uint32(p.To.Reg))
-		if p.As == AMOVWU {
-			o2 = OP_SRR(opirr(ctxt, ASRLV+ALAST), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
-		} else {
-			o2 = OP_SRR(opirr(ctxt, ASRAV+ALAST), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
-		}
+		o1 = OP_SRR(opirr(ctxt, -ASLLV), uint32(0), uint32(p.From.Reg), uint32(p.To.Reg))
+		o2 = OP_SRR(opirr(ctxt, -ASRLV), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
 
 	case 16: /* sll $c,[r1],r2 */
 		v := regoff(ctxt, &p.From)
@@ -1163,9 +1161,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 		/* OP_SRR will use only the low 5 bits of the shift value */
 		if v >= 32 && vshift(p.As) {
-			o1 = OP_SRR(opirr(ctxt, int(p.As)+ALAST), uint32(v-32), uint32(r), uint32(p.To.Reg))
+			o1 = OP_SRR(opirr(ctxt, -p.As), uint32(v-32), uint32(r), uint32(p.To.Reg))
 		} else {
-			o1 = OP_SRR(opirr(ctxt, int(p.As)), uint32(v), uint32(r), uint32(p.To.Reg))
+			o1 = OP_SRR(opirr(ctxt, p.As), uint32(v), uint32(r), uint32(p.To.Reg))
 		}
 
 	case 18: /* jmp [r1],0(r2) */
@@ -1173,7 +1171,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = OP_RRR(oprrr(ctxt, int(p.As)), uint32(0), uint32(p.To.Reg), uint32(r))
+		o1 = OP_RRR(oprrr(ctxt, p.As), uint32(0), uint32(p.To.Reg), uint32(r))
 		rel := obj.Addrel(ctxt.Cursym)
 		rel.Off = int32(ctxt.Pc)
 		rel.Siz = 0
@@ -1181,16 +1179,8 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	case 19: /* mov $lcon,r ==> lu+or */
 		v := regoff(ctxt, &p.From)
-		o1 = OP_IRR(opirr(ctxt, ALAST), uint32(v>>16), uint32(REGZERO), uint32(p.To.Reg))
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32(v>>16), uint32(REGZERO), uint32(p.To.Reg))
 		o2 = OP_IRR(opirr(ctxt, AOR), uint32(v), uint32(p.To.Reg), uint32(p.To.Reg))
-		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_ADDRMIPS
-		}
 
 	case 20: /* mov lo/hi,r */
 		a := OP(2, 0) /* mfhi */
@@ -1207,34 +1197,34 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 = OP_RRR(a, uint32(REGZERO), uint32(p.From.Reg), uint32(REGZERO))
 
 	case 22: /* mul r1,r2 */
-		o1 = OP_RRR(oprrr(ctxt, int(p.As)), uint32(p.From.Reg), uint32(p.Reg), uint32(REGZERO))
+		o1 = OP_RRR(oprrr(ctxt, p.As), uint32(p.From.Reg), uint32(p.Reg), uint32(REGZERO))
 
 	case 23: /* add $lcon,r1,r2 ==> lu+or+add */
 		v := regoff(ctxt, &p.From)
-		o1 = OP_IRR(opirr(ctxt, ALAST), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
 		o2 = OP_IRR(opirr(ctxt, AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o3 = OP_RRR(oprrr(ctxt, int(p.As)), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
+		o3 = OP_RRR(oprrr(ctxt, p.As), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
 
 	case 24: /* mov $ucon,r ==> lu r */
 		v := regoff(ctxt, &p.From)
-		o1 = OP_IRR(opirr(ctxt, ALAST), uint32(v>>16), uint32(REGZERO), uint32(p.To.Reg))
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32(v>>16), uint32(REGZERO), uint32(p.To.Reg))
 
 	case 25: /* add/and $ucon,[r1],r2 ==> lu $con,t; add t,[r1],r2 */
 		v := regoff(ctxt, &p.From)
-		o1 = OP_IRR(opirr(ctxt, ALAST), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
 		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o2 = OP_RRR(oprrr(ctxt, int(p.As)), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
+		o2 = OP_RRR(oprrr(ctxt, p.As), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
 
 	case 26: /* mov $lsext/auto/oreg,r ==> lu+or+add */
 		v := regoff(ctxt, &p.From)
-		o1 = OP_IRR(opirr(ctxt, ALAST), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
 		o2 = OP_IRR(opirr(ctxt, AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
 		r := int(p.From.Reg)
 		if r == 0 {
@@ -1248,16 +1238,15 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(o.param)
 		}
-		a := AMOVF + ALAST
+		a := -AMOVF
 		if p.As == AMOVD {
-			a = AMOVD + ALAST
+			a = -AMOVD
 		}
 		switch o.size {
-		case 16:
-			o1 = OP_IRR(opirr(ctxt, ALAST), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
-			o2 = OP_IRR(opirr(ctxt, AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
-			o3 = OP_RRR(opirr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
-			o4 = OP_IRR(opirr(ctxt, a), uint32(0), uint32(r), uint32(p.To.Reg))
+		case 12:
+			o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
+			o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
+			o3 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(REGTMP), uint32(p.To.Reg))
 
 		case 4:
 			o1 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(r), uint32(p.To.Reg))
@@ -1274,11 +1263,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			a = AMOVD
 		}
 		switch o.size {
-		case 16:
-			o1 = OP_IRR(opirr(ctxt, ALAST), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
-			o2 = OP_IRR(opirr(ctxt, AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
-			o3 = OP_RRR(opirr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
-			o4 = OP_IRR(opirr(ctxt, a), uint32(0), uint32(REGTMP), uint32(p.From.Reg))
+		case 12:
+			o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
+			o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
+			o3 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(REGTMP), uint32(p.From.Reg))
 
 		case 4:
 			o1 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(r), uint32(p.From.Reg))
@@ -1297,10 +1285,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = OP_FRRR(oprrr(ctxt, int(p.As)), uint32(p.From.Reg), uint32(r), uint32(p.To.Reg))
+		o1 = OP_FRRR(oprrr(ctxt, p.As), uint32(p.From.Reg), uint32(r), uint32(p.To.Reg))
 
 	case 33: /* fabs fr1, fr3 */
-		o1 = OP_FRRR(oprrr(ctxt, int(p.As)), uint32(0), uint32(p.From.Reg), uint32(p.To.Reg))
+		o1 = OP_FRRR(oprrr(ctxt, p.As), uint32(0), uint32(p.From.Reg), uint32(p.To.Reg))
 
 	case 34: /* mov $con,fr ==> or/add $i,t; mov t,fr */
 		v := regoff(ctxt, &p.From)
@@ -1311,27 +1299,25 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 = OP_IRR(opirr(ctxt, a), uint32(v), uint32(0), uint32(REGTMP))
 		o2 = OP_RRR(SP(2, 1)|(4<<21), uint32(REGTMP), uint32(0), uint32(p.To.Reg)) /* mtc1 */
 
-	case 35: /* mov r,lext/auto/oreg ==> sw o(r) */
+	case 35: /* mov r,lext/auto/oreg ==> sw o(REGTMP) */
 		v := regoff(ctxt, &p.To)
 		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = OP_IRR(opirr(ctxt, ALAST), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
-		o2 = OP_IRR(opirr(ctxt, AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
-		o3 = OP_RRR(oprrr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
-		o4 = OP_IRR(opirr(ctxt, int(p.As)), uint32(0), uint32(REGTMP), uint32(p.From.Reg))
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
+		o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
+		o3 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(REGTMP), uint32(p.From.Reg))
 
-	case 36: /* mov lext/auto/oreg,r ==> lw o(r30) */
+	case 36: /* mov lext/auto/oreg,r ==> lw o(REGTMP) */
 		v := regoff(ctxt, &p.From)
 		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
-		o1 = OP_IRR(opirr(ctxt, ALAST), uint32(v>>16), uint32(REGZERO), uint32(REGTMP))
-		o2 = OP_IRR(opirr(ctxt, AOR), uint32(v), uint32(REGTMP), uint32(REGTMP))
-		o3 = OP_RRR(oprrr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
-		o4 = OP_IRR(opirr(ctxt, int(p.As)+ALAST), uint32(0), uint32(REGTMP), uint32(p.To.Reg))
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
+		o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
+		o3 = OP_IRR(opirr(ctxt, -p.As), uint32(v), uint32(REGTMP), uint32(p.To.Reg))
 
 	case 37: /* movw r,mr */
 		a := SP(2, 0) | (4 << 21) /* mtc0 */
@@ -1366,30 +1352,93 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		o1 = OP_RRR(a, uint32(p.To.Reg), uint32(0), uint32(p.From.Reg))
 
 	case 49: /* undef */
-		o1 = 8 /* JMP (R0) */
+		o1 = 52 /* trap -- teq r0, r0 */
 
 	/* relocation operations */
-	case 50: /* mov r,addr ==> lu + or + sw (REGTMP) */
-		o1 = OP_IRR(opirr(ctxt, ALAST), uint32(0), uint32(REGZERO), uint32(REGTMP))
-		o2 = OP_IRR(opirr(ctxt, AOR), uint32(0), uint32(REGTMP), uint32(REGTMP))
+	case 50: /* mov r,addr ==> lu + add REGSB, REGTMP + sw o(REGTMP) */
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32(0), uint32(REGZERO), uint32(REGTMP))
 		rel := obj.Addrel(ctxt.Cursym)
 		rel.Off = int32(ctxt.Pc)
-		rel.Siz = 8
+		rel.Siz = 4
 		rel.Sym = p.To.Sym
 		rel.Add = p.To.Offset
-		rel.Type = obj.R_ADDRMIPS
-		o3 = OP_IRR(opirr(ctxt, int(p.As)), uint32(0), uint32(REGTMP), uint32(p.From.Reg))
-
-	case 51: /* mov addr,r ==> lu + or + lw (REGTMP) */
-		o1 = OP_IRR(opirr(ctxt, ALAST), uint32(0), uint32(REGZERO), uint32(REGTMP))
-		o2 = OP_IRR(opirr(ctxt, AOR), uint32(0), uint32(REGTMP), uint32(REGTMP))
+		rel.Type = obj.R_ADDRMIPSU
+		o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(REGTMP), uint32(REGTMP))
+		o3 = OP_IRR(opirr(ctxt, p.As), uint32(0), uint32(REGTMP), uint32(p.From.Reg))
+		rel2 := obj.Addrel(ctxt.Cursym)
+		rel2.Off = int32(ctxt.Pc + 8)
+		rel2.Siz = 4
+		rel2.Sym = p.To.Sym
+		rel2.Add = p.To.Offset
+		rel2.Type = obj.R_ADDRMIPS
+
+	case 51: /* mov addr,r ==> lu + add REGSB, REGTMP + lw o(REGTMP) */
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32(0), uint32(REGZERO), uint32(REGTMP))
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc)
+		rel.Siz = 4
+		rel.Sym = p.From.Sym
+		rel.Add = p.From.Offset
+		rel.Type = obj.R_ADDRMIPSU
+		o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(REGTMP), uint32(REGTMP))
+		o3 = OP_IRR(opirr(ctxt, -p.As), uint32(0), uint32(REGTMP), uint32(p.To.Reg))
+		rel2 := obj.Addrel(ctxt.Cursym)
+		rel2.Off = int32(ctxt.Pc + 8)
+		rel2.Siz = 4
+		rel2.Sym = p.From.Sym
+		rel2.Add = p.From.Offset
+		rel2.Type = obj.R_ADDRMIPS
+
+	case 52: /* mov $lext, r ==> lu + add REGSB, r + add */
+		o1 = OP_IRR(opirr(ctxt, ALUI), uint32(0), uint32(REGZERO), uint32(p.To.Reg))
 		rel := obj.Addrel(ctxt.Cursym)
 		rel.Off = int32(ctxt.Pc)
-		rel.Siz = 8
+		rel.Siz = 4
+		rel.Sym = p.From.Sym
+		rel.Add = p.From.Offset
+		rel.Type = obj.R_ADDRMIPSU
+		o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(p.To.Reg), uint32(p.To.Reg))
+		o3 = OP_IRR(opirr(ctxt, AADDVU), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
+		rel2 := obj.Addrel(ctxt.Cursym)
+		rel2.Off = int32(ctxt.Pc + 8)
+		rel2.Siz = 4
+		rel2.Sym = p.From.Sym
+		rel2.Add = p.From.Offset
+		rel2.Type = obj.R_ADDRMIPS
+
+	case 53: /* mov r, tlsvar ==> rdhwr + sw o(r3) */
+		// clobbers R3 !
+		// load thread pointer with RDHWR, R3 is used for fast kernel emulation on Linux
+		o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3
+		o2 = OP_IRR(opirr(ctxt, p.As), uint32(0), uint32(REG_R3), uint32(p.From.Reg))
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc + 4)
+		rel.Siz = 4
+		rel.Sym = p.To.Sym
+		rel.Add = p.To.Offset
+		rel.Type = obj.R_ADDRMIPSTLS
+
+	case 54: /* mov tlsvar, r ==> rdhwr + lw o(r3) */
+		// clobbers R3 !
+		o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3
+		o2 = OP_IRR(opirr(ctxt, -p.As), uint32(0), uint32(REG_R3), uint32(p.To.Reg))
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc + 4)
+		rel.Siz = 4
+		rel.Sym = p.From.Sym
+		rel.Add = p.From.Offset
+		rel.Type = obj.R_ADDRMIPSTLS
+
+	case 55: /* mov $tlsvar, r ==> rdhwr + add */
+		// clobbers R3 !
+		o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3
+		o2 = OP_IRR(opirr(ctxt, AADDVU), uint32(0), uint32(REG_R3), uint32(p.To.Reg))
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc + 4)
+		rel.Siz = 4
 		rel.Sym = p.From.Sym
 		rel.Add = p.From.Offset
-		rel.Type = obj.R_ADDRMIPS
-		o3 = OP_IRR(opirr(ctxt, int(p.As)+ALAST), uint32(0), uint32(REGTMP), uint32(p.To.Reg))
+		rel.Type = obj.R_ADDRMIPSTLS
 	}
 
 	out[0] = o1
@@ -1409,7 +1458,7 @@ func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
 	return int32(vregoff(ctxt, a))
 }
 
-func oprrr(ctxt *obj.Link, a int) uint32 {
+func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AADD:
 		return OP(4, 0)
@@ -1562,15 +1611,15 @@ func oprrr(ctxt *obj.Link, a int) uint32 {
 		return FPD(7, 6)
 	}
 
-	if a >= ALAST {
-		ctxt.Diag("bad rrr opcode %v+ALAST", obj.Aconv(a-ALAST))
+	if a < 0 {
+		ctxt.Diag("bad rrr opcode -%v", obj.Aconv(-a))
 	} else {
 		ctxt.Diag("bad rrr opcode %v", obj.Aconv(a))
 	}
 	return 0
 }
 
-func opirr(ctxt *obj.Link, a int) uint32 {
+func opirr(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AADD:
 		return SP(1, 0)
@@ -1586,8 +1635,8 @@ func opirr(ctxt *obj.Link, a int) uint32 {
 		return SP(1, 5)
 	case AXOR:
 		return SP(1, 6)
-	case ALAST:
-		return SP(1, 7) /* lui */
+	case ALUI:
+		return SP(1, 7)
 	case ASLL:
 		return OP(0, 0)
 	case ASRL:
@@ -1607,43 +1656,43 @@ func opirr(ctxt *obj.Link, a int) uint32 {
 		return SP(0, 3)
 	case ABEQ:
 		return SP(0, 4)
-	case ABEQ + ALAST:
+	case -ABEQ:
 		return SP(2, 4) /* likely */
 	case ABNE:
 		return SP(0, 5)
-	case ABNE + ALAST:
+	case -ABNE:
 		return SP(2, 5) /* likely */
 	case ABGEZ:
 		return SP(0, 1) | BCOND(0, 1)
-	case ABGEZ + ALAST:
+	case -ABGEZ:
 		return SP(0, 1) | BCOND(0, 3) /* likely */
 	case ABGEZAL:
 		return SP(0, 1) | BCOND(2, 1)
-	case ABGEZAL + ALAST:
+	case -ABGEZAL:
 		return SP(0, 1) | BCOND(2, 3) /* likely */
 	case ABGTZ:
 		return SP(0, 7)
-	case ABGTZ + ALAST:
+	case -ABGTZ:
 		return SP(2, 7) /* likely */
 	case ABLEZ:
 		return SP(0, 6)
-	case ABLEZ + ALAST:
+	case -ABLEZ:
 		return SP(2, 6) /* likely */
 	case ABLTZ:
 		return SP(0, 1) | BCOND(0, 0)
-	case ABLTZ + ALAST:
+	case -ABLTZ:
 		return SP(0, 1) | BCOND(0, 2) /* likely */
 	case ABLTZAL:
 		return SP(0, 1) | BCOND(2, 0)
-	case ABLTZAL + ALAST:
+	case -ABLTZAL:
 		return SP(0, 1) | BCOND(2, 2) /* likely */
 	case ABFPT:
 		return SP(2, 1) | (257 << 16)
-	case ABFPT + ALAST:
+	case -ABFPT:
 		return SP(2, 1) | (259 << 16) /* likely */
 	case ABFPF:
 		return SP(2, 1) | (256 << 16)
-	case ABFPF + ALAST:
+	case -ABFPF:
 		return SP(2, 1) | (258 << 16) /* likely */
 
 	case AMOVB,
@@ -1673,31 +1722,31 @@ func opirr(ctxt *obj.Link, a int) uint32 {
 	case ABREAK:
 		return SP(5, 7)
 
-	case AMOVWL + ALAST:
+	case -AMOVWL:
 		return SP(4, 2)
-	case AMOVWR + ALAST:
+	case -AMOVWR:
 		return SP(4, 6)
-	case AMOVVL + ALAST:
+	case -AMOVVL:
 		return SP(3, 2)
-	case AMOVVR + ALAST:
+	case -AMOVVR:
 		return SP(3, 3)
-	case AMOVB + ALAST:
+	case -AMOVB:
 		return SP(4, 0)
-	case AMOVBU + ALAST:
+	case -AMOVBU:
 		return SP(4, 4)
-	case AMOVH + ALAST:
+	case -AMOVH:
 		return SP(4, 1)
-	case AMOVHU + ALAST:
+	case -AMOVHU:
 		return SP(4, 5)
-	case AMOVW + ALAST:
+	case -AMOVW:
 		return SP(4, 3)
-	case AMOVWU + ALAST:
+	case -AMOVWU:
 		return SP(4, 7)
-	case AMOVV + ALAST:
+	case -AMOVV:
 		return SP(6, 7)
-	case AMOVF + ALAST:
+	case -AMOVF:
 		return SP(6, 1)
-	case AMOVD + ALAST:
+	case -AMOVD:
 		return SP(6, 5)
 
 	case ASLLV:
@@ -1706,23 +1755,23 @@ func opirr(ctxt *obj.Link, a int) uint32 {
 		return OP(7, 2)
 	case ASRAV:
 		return OP(7, 3)
-	case ASLLV + ALAST:
+	case -ASLLV:
 		return OP(7, 4)
-	case ASRLV + ALAST:
+	case -ASRLV:
 		return OP(7, 6)
-	case ASRAV + ALAST:
+	case -ASRAV:
 		return OP(7, 7)
 	}
 
-	if a >= ALAST {
-		ctxt.Diag("bad irr opcode %v+ALAST", obj.Aconv(a-ALAST))
+	if a < 0 {
+		ctxt.Diag("bad irr opcode -%v", obj.Aconv(-a))
 	} else {
 		ctxt.Diag("bad irr opcode %v", obj.Aconv(a))
 	}
 	return 0
 }
 
-func vshift(a int16) bool {
+func vshift(a obj.As) bool {
 	switch a {
 	case ASLLV,
 		ASRLV,
diff --git a/src/cmd/internal/obj/mips/list0.go b/src/cmd/internal/obj/mips/list0.go
index 40dc460..28881e8 100644
--- a/src/cmd/internal/obj/mips/list0.go
+++ b/src/cmd/internal/obj/mips/list0.go
@@ -7,7 +7,7 @@
 //	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.
+//	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
@@ -47,6 +47,10 @@ func Rconv(r int) string {
 		// Special case.
 		return "g"
 	}
+	if r == REGSB {
+		// Special case.
+		return "RSB"
+	}
 	if REG_R0 <= r && r <= REG_R31 {
 		return fmt.Sprintf("R%d", r-REG_R0)
 	}
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
index a3ccad2..ade1ee5 100644
--- a/src/cmd/internal/obj/mips/obj0.go
+++ b/src/cmd/internal/obj/mips/obj0.go
@@ -7,7 +7,7 @@
 //	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.
+//	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
@@ -31,7 +31,7 @@ package mips
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"math"
 )
@@ -261,11 +261,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	}
 
 	autosize := int32(0)
-	var o int
 	var p1 *obj.Prog
 	var p2 *obj.Prog
 	for p := cursym.Text; p != nil; p = p.Link {
-		o = int(p.As)
+		o := p.As
 		switch o {
 		case obj.ATEXT:
 			autosize = int32(textstksiz + 8)
@@ -303,7 +302,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 			if cursym.Text.Mark&LEAF != 0 {
-				cursym.Leaf = 1
+				cursym.Leaf = true
 				break
 			}
 
@@ -337,7 +336,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.As = AMOVV
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REGG
-				q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R1
 
@@ -513,7 +512,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	// instruction scheduling
 	q = nil          // p - 1
 	q1 = cursym.Text // top of block
-	o = 0            // count of instructions
+	o := 0           // count of instructions
 	for p = cursym.Text; p != nil; p = p1 {
 		p1 = p.Link
 		o++
@@ -560,9 +559,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	p.As = AMOVV
 	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.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
+	if ctxt.Cursym.Cfunc {
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R1
@@ -691,7 +690,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 
 	p.As = AJAL
 	p.To.Type = obj.TYPE_BRANCH
-	if ctxt.Cursym.Cfunc != 0 {
+	if ctxt.Cursym.Cfunc {
 		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)
@@ -1230,11 +1229,11 @@ func markregused(ctxt *obj.Link, s *Sch) {
 			s.used.ireg |= 1 << uint(c-REG_R0)
 		}
 	}
-	s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 cant be set */
+	s.set.ireg &^= (1 << (REGZERO - REG_R0)) /* R0 can't be set */
 }
 
 /*
- * test to see if 2 instrictions can be
+ * test to see if two instructions can be
  * interchanged without changing semantics
  */
 func depend(ctxt *obj.Link, sa, sb *Sch) bool {
@@ -1342,14 +1341,13 @@ func follow(ctxt *obj.Link, s *obj.LSym) {
 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)
+	a := p.As
 	if a == AJMP {
 		q = p.Pcond
 		if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) {
@@ -1381,7 +1379,7 @@ loop:
 			if q == *last || (q.Mark&NOSCHED != 0) {
 				break
 			}
-			a = int(q.As)
+			a = q.As
 			if a == obj.ANOP {
 				i--
 				continue
@@ -1402,7 +1400,7 @@ loop:
 				r = ctxt.NewProg()
 				*r = *p
 				if r.Mark&FOLL == 0 {
-					fmt.Printf("cant happen 1\n")
+					fmt.Printf("can't happen 1\n")
 				}
 				r.Mark |= FOLL
 				if p != q {
@@ -1427,7 +1425,7 @@ loop:
 					xfol(ctxt, r.Link, last)
 				}
 				if r.Pcond.Mark&FOLL == 0 {
-					fmt.Printf("cant happen 2\n")
+					fmt.Printf("can't happen 2\n")
 				}
 				return
 			}
@@ -1435,7 +1433,7 @@ loop:
 
 		a = AJMP
 		q = ctxt.NewProg()
-		q.As = int16(a)
+		q.As = a
 		q.Lineno = p.Lineno
 		q.To.Type = obj.TYPE_BRANCH
 		q.To.Offset = p.Pc
@@ -1471,27 +1469,17 @@ loop:
 }
 
 var Linkmips64 = obj.LinkArch{
-	ByteOrder:  binary.BigEndian,
-	Name:       "mips64",
-	Thechar:    '0',
+	Arch:       sys.ArchMIPS64,
 	Preprocess: preprocess,
 	Assemble:   span0,
 	Follow:     follow,
 	Progedit:   progedit,
-	Minlc:      4,
-	Ptrsize:    8,
-	Regsize:    8,
 }
 
 var Linkmips64le = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "mips64le",
-	Thechar:    '0',
+	Arch:       sys.ArchMIPS64LE,
 	Preprocess: preprocess,
 	Assemble:   span0,
 	Follow:     follow,
 	Progedit:   progedit,
-	Minlc:      4,
-	Ptrsize:    8,
-	Regsize:    8,
 }
diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go
index 30ab549..3eb37b3 100644
--- a/src/cmd/internal/obj/obj.go
+++ b/src/cmd/internal/obj/obj.go
@@ -25,12 +25,13 @@ import (
 //	  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
+	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
+	PrintFilenameOnly bool        // ignore path when pretty-printing a line; internal use only
+	GOROOT            string      // current GOROOT
+	GOROOT_FINAL      string      // target GOROOT
 }
 
 // A LineStack is an entry in the recorded line history.
@@ -221,20 +222,28 @@ func (h *LineHist) LineString(lineno int) string {
 		return "<unknown line number>"
 	}
 
-	text := fmt.Sprintf("%s:%d", stk.File, stk.fileLineAt(lineno))
+	filename := stk.File
+	if h.PrintFilenameOnly {
+		filename = filepath.Base(filename)
+	}
+	text := fmt.Sprintf("%s:%d", filename, stk.fileLineAt(lineno))
 	if stk.Directive && stk.Parent != nil {
 		stk = stk.Parent
-		text += fmt.Sprintf("[%s:%d]", stk.File, stk.fileLineAt(lineno))
+		filename = stk.File
+		if h.PrintFilenameOnly {
+			filename = filepath.Base(filename)
+		}
+		text += fmt.Sprintf("[%s:%d]", filename, 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))
+			text += fmt.Sprintf(" %s:%d", filename, stk.fileLineAt(lineno))
 			if stk.Directive && stk.Parent != nil {
 				stk = stk.Parent
-				text += fmt.Sprintf("[%s:%d]", stk.File, stk.fileLineAt(lineno))
+				text += fmt.Sprintf("[%s:%d]", filename, stk.fileLineAt(lineno))
 			}
 		}
 	}
@@ -264,20 +273,35 @@ func (h *LineHist) AbsFileLine(lineno int) (file string, line int) {
 // 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) {
+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
+		return Linklookup(ctxt, "??", HistVersion), 0
 	}
 	if stk.Sym == nil {
 		stk.Sym = Linklookup(ctxt, stk.AbsFile, HistVersion)
 	}
-	*f = stk.Sym
-	*l = int32(stk.fileLineAt(int(lineno)))
+	return stk.Sym, int32(stk.fileLineAt(int(lineno)))
 }
 
 func Linkprfile(ctxt *Link, line int) {
 	fmt.Printf("%s ", ctxt.LineHist.LineString(line))
 }
+
+func fieldtrack(ctxt *Link, cursym *LSym) {
+	p := cursym.Text
+	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
+		return
+	}
+	ctxt.Cursym = cursym
+
+	for ; p != nil; p = p.Link {
+		if p.As == AUSEFIELD {
+			r := Addrel(ctxt.Cursym)
+			r.Off = 0
+			r.Siz = 0
+			r.Sym = p.From.Sym
+			r.Type = R_USEFIELD
+		}
+	}
+}
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 8d4a506..a1fdee6 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -15,13 +15,23 @@
 //
 // The file format is:
 //
-//	- magic header: "\x00\x00go13ld"
+//	- magic header: "\x00\x00go17ld"
 //	- byte 1 - version number
 //	- sequence of strings giving dependencies (imported packages)
 //	- empty string (marks end of sequence)
+//	- sequence of symbol references used by the defined symbols
+//	- byte 0xff (marks end of sequence)
+//	- sequence of integer lengths:
+//		- total data length
+//		- total number of relocations
+//		- total number of pcdata
+//		- total number of automatics
+//		- total number of funcdata
+//		- total number of files
+//	- data, the content of the defined symbols
 //	- sequence of defined symbols
 //	- byte 0xff (marks end of sequence)
-//	- magic footer: "\xff\xffgo13ld"
+//	- magic footer: "\xff\xffgo17ld"
 //
 // All integers are stored in a zigzag varint format.
 // See golang.org/s/go12symtab for a definition.
@@ -30,18 +40,21 @@
 // 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.
+//
+// A symbol points to other symbols using an index into the symbol
+// reference sequence. Index 0 corresponds to a nil LSym* pointer.
+// In the symbol layout described below "symref index" stands for this
+// index.
 //
 // Each symbol is laid out as the following fields (taken from LSym*):
 //
 //	- byte 0xfe (sanity check for synchronization)
 //	- type [int]
-//	- name [string]
-//	- version [int]
+//	- name & version [symref index]
 //	- flags [int]
 //		1 dupok
 //	- size [int]
-//	- gotype [symbol reference]
+//	- gotype [symref index]
 //	- p [data block]
 //	- nr [int]
 //	- r [nr relocations, sorted by off]
@@ -52,8 +65,9 @@
 //	- locals [int]
 //	- nosplit [int]
 //	- flags [int]
-//		1 leaf
-//		2 C function
+//		1<<0 leaf
+//		1<<1 C function
+//		1<<2 function may call reflect.Type.Method
 //	- nlocal [int]
 //	- local [nlocal automatics]
 //	- pcln [pcln table]
@@ -64,16 +78,14 @@
 //	- siz [int]
 //	- type [int]
 //	- add [int]
-//	- xadd [int]
-//	- sym [symbol reference]
-//	- xsym [symbol reference]
+//	- sym [symref index]
 //
 // Each local has the encoding:
 //
-//	- asym [symbol reference]
+//	- asym [symref index]
 //	- offset [int]
 //	- type [int]
-//	- gotype [symbol reference]
+//	- gotype [symref index]
 //
 // The pcln table has the encoding:
 //
@@ -83,455 +95,414 @@
 //	- npcdata [int]
 //	- pcdata [npcdata data blocks]
 //	- nfuncdata [int]
-//	- funcdata [nfuncdata symbol references]
+//	- funcdata [nfuncdata symref index]
 //	- funcdatasym [nfuncdata ints]
 //	- nfile [int]
-//	- file [nfile symbol references]
+//	- file [nfile symref index]
 //
 // 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 (
+	"bufio"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"path/filepath"
-	"strings"
+	"sort"
 )
 
 // 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
+// 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) {
+func Writeobjdirect(ctxt *Link, b *bufio.Writer) {
 	Flushplist(ctxt)
-	Writeobjfile(ctxt, b)
+	WriteObjFile(ctxt, b)
 }
 
-func Flushplist(ctxt *Link) {
-	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 assemblers just use one big list.
-	var curtext *LSym
-	var text *LSym
-	var etext *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 ctxt.Data == nil {
-					ctxt.Data = s
-				} else {
-					ctxt.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
-				} else if flag&TLSBSS != 0 {
-					s.Type = STLSBSS
-				}
-				ctxt.Edata = s
-				continue
-			}
+// objWriter writes Go object files.
+type objWriter struct {
+	wr   *bufio.Writer
+	ctxt *Link
+	// Temporary buffer for zigzag int writing.
+	varintbuf [10]uint8
+
+	// Provide the the index of a symbol reference by symbol name.
+	// One map for versioned symbols and one for unversioned symbols.
+	// Used for deduplicating the symbol reference list.
+	refIdx  map[string]int
+	vrefIdx map[string]int
+
+	// Number of objects written of each type.
+	nRefs     int
+	nData     int
+	nReloc    int
+	nPcdata   int
+	nAutom    int
+	nFuncdata int
+	nFile     int
+}
 
-			if p.As == ADATA {
-				savedata(ctxt, p.From.Sym, p, "<input>")
-				continue
-			}
+func (w *objWriter) addLengths(s *LSym) {
+	w.nData += len(s.P)
+	w.nReloc += len(s.R)
 
-			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 s.Type != STEXT {
+		return
+	}
 
-			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))
-				}
-			}
+	pc := s.Pcln
 
-			if curtext == nil {
-				continue
-			}
-			s = curtext
-			s.Etext.Link = p
-			s.Etext = p
-		}
+	data := 0
+	data += len(pc.Pcsp.P)
+	data += len(pc.Pcfile.P)
+	data += len(pc.Pcline.P)
+	for i := 0; i < len(pc.Pcdata); i++ {
+		data += len(pc.Pcdata[i].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
-			}
-		}
+	w.nData += data
+	w.nPcdata += len(pc.Pcdata)
 
-		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))
-		}
+	autom := 0
+	for a := s.Autom; a != nil; a = a.Link {
+		autom++
 	}
+	w.nAutom += autom
+	w.nFuncdata += len(pc.Funcdataoff)
+	w.nFile += len(pc.File)
+}
 
-	// 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)
-	}
+func (w *objWriter) writeLengths() {
+	w.writeInt(int64(w.nData))
+	w.writeInt(int64(w.nReloc))
+	w.writeInt(int64(w.nPcdata))
+	w.writeInt(int64(w.nAutom))
+	w.writeInt(int64(w.nFuncdata))
+	w.writeInt(int64(w.nFile))
+}
 
-	// Add to running list in ctxt.
-	if ctxt.Etext == nil {
-		ctxt.Text = text
-	} else {
-		ctxt.Etext.Next = text
+func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
+	return &objWriter{
+		ctxt:    ctxt,
+		wr:      b,
+		vrefIdx: make(map[string]int),
+		refIdx:  make(map[string]int),
 	}
-	ctxt.Etext = etext
-	ctxt.Plist = nil
 }
 
-func Writeobjfile(ctxt *Link, b *Biobuf) {
-	// Emit header.
-	Bputc(b, 0)
+func WriteObjFile(ctxt *Link, b *bufio.Writer) {
+	w := newObjWriter(ctxt, b)
+
+	// Magic header
+	w.wr.WriteString("\x00\x00go17ld")
 
-	Bputc(b, 0)
-	fmt.Fprintf(b, "go13ld")
-	Bputc(b, 1) // version
+	// Version
+	w.wr.WriteByte(1)
 
-	// Emit autolib.
+	// Autolib
 	for _, pkg := range ctxt.Imports {
-		wrstring(b, pkg)
+		w.writeString(pkg)
+	}
+	w.writeString("")
+
+	// Symbol references
+	for _, s := range ctxt.Text {
+		w.writeRefs(s)
+		w.addLengths(s)
+	}
+	for _, s := range ctxt.Data {
+		w.writeRefs(s)
+		w.addLengths(s)
 	}
-	wrstring(b, "")
+	// End symbol references
+	w.wr.WriteByte(0xff)
 
-	// Emit symbols.
-	for s := ctxt.Text; s != nil; s = s.Next {
-		writesym(ctxt, b, s)
+	// Lengths
+	w.writeLengths()
+
+	// Data block
+	for _, s := range ctxt.Text {
+		w.wr.Write(s.P)
+		pc := s.Pcln
+		w.wr.Write(pc.Pcsp.P)
+		w.wr.Write(pc.Pcfile.P)
+		w.wr.Write(pc.Pcline.P)
+		for i := 0; i < len(pc.Pcdata); i++ {
+			w.wr.Write(pc.Pcdata[i].P)
+		}
 	}
-	for s := ctxt.Data; s != nil; s = s.Next {
-		writesym(ctxt, b, s)
+	for _, s := range ctxt.Data {
+		w.wr.Write(s.P)
 	}
 
-	// Emit footer.
-	Bputc(b, 0xff)
+	// Symbols
+	for _, s := range ctxt.Text {
+		w.writeSym(s)
+	}
+	for _, s := range ctxt.Data {
+		w.writeSym(s)
+	}
 
-	Bputc(b, 0xff)
-	fmt.Fprintf(b, "go13ld")
+	// Magic footer
+	w.wr.WriteString("\xff\xffgo17ld")
 }
 
-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)
+// Symbols are prefixed so their content doesn't get confused with the magic footer.
+const symPrefix = 0xfe
+
+func (w *objWriter) writeRef(s *LSym, isPath bool) {
+	if s == nil || s.RefIdx != 0 {
+		return
+	}
+	var m map[string]int
+	switch s.Version {
+	case 0:
+		m = w.refIdx
+	case 1:
+		m = w.vrefIdx
+	default:
+		log.Fatalf("%s: invalid version number %d", s.Name, s.Version)
+	}
+
+	idx := m[s.Name]
+	if idx != 0 {
+		s.RefIdx = idx
+		return
+	}
+	w.wr.WriteByte(symPrefix)
+	if isPath {
+		w.writeString(filepath.ToSlash(s.Name))
+	} else {
+		w.writeString(s.Name)
+	}
+	w.writeInt(int64(s.Version))
+	w.nRefs++
+	s.RefIdx = w.nRefs
+	m[s.Name] = w.nRefs
+}
+
+func (w *objWriter) writeRefs(s *LSym) {
+	w.writeRef(s, false)
+	w.writeRef(s.Gotype, false)
+	for i := range s.R {
+		w.writeRef(s.R[i].Sym, false)
+	}
+
+	if s.Type == STEXT {
+		for a := s.Autom; a != nil; a = a.Link {
+			w.writeRef(a.Asym, false)
+			w.writeRef(a.Gotype, false)
 		}
-		if s.Type != 0 {
-			fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
+		pc := s.Pcln
+		for _, d := range pc.Funcdata {
+			w.writeRef(d, false)
+		}
+		for _, f := range pc.File {
+			w.writeRef(f, true)
 		}
-		if s.Dupok != 0 {
-			fmt.Fprintf(ctxt.Bso, "dupok ")
+	}
+}
+
+func (w *objWriter) writeSymDebug(s *LSym) {
+	ctxt := w.ctxt
+	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 {
+		fmt.Fprintf(ctxt.Bso, "dupok ")
+	}
+	if s.Cfunc {
+		fmt.Fprintf(ctxt.Bso, "cfunc ")
+	}
+	if s.Nosplit {
+		fmt.Fprintf(ctxt.Bso, "nosplit ")
+	}
+	fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
+	if s.Type == STEXT {
+		fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
+		if s.Leaf {
+			fmt.Fprintf(ctxt.Bso, " leaf")
 		}
-		if s.Cfunc != 0 {
-			fmt.Fprintf(ctxt.Bso, "cfunc ")
+	}
+
+	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])
 		}
-		if s.Nosplit != 0 {
-			fmt.Fprintf(ctxt.Bso, "nosplit ")
+		for ; j < i+16; j++ {
+			fmt.Fprintf(ctxt.Bso, "   ")
 		}
-		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, "  ")
+		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")
-		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, ".")
-				}
-			}
+		i += 16
+	}
 
-			fmt.Fprintf(ctxt.Bso, "\n")
-			i += 16
+	sort.Sort(relocByOff(s.R)) // generate stable output
+	for _, r := range s.R {
+		name := ""
+		if r.Sym != nil {
+			name = r.Sym.Name
+		} else if r.Type == R_TLS_LE {
+			name = "TLS"
 		}
-
-		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))
-			}
+		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
+			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
+		} else {
+			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
 		}
 	}
+}
 
-	Bputc(b, 0xfe)
-	wrint(b, int64(s.Type))
-	wrstring(b, s.Name)
-	wrint(b, int64(s.Version))
-	flags := int64(s.Dupok)
+func (w *objWriter) writeSym(s *LSym) {
+	ctxt := w.ctxt
+	if ctxt.Debugasm != 0 {
+		w.writeSymDebug(s)
+	}
+
+	w.wr.WriteByte(symPrefix)
+	w.writeInt(int64(s.Type))
+	w.writeRefIndex(s)
+	flags := int64(0)
+	if s.Dupok {
+		flags |= 1
+	}
 	if s.Local {
-		flags |= 2
+		flags |= 1 << 1
 	}
-	wrint(b, flags)
-	wrint(b, s.Size)
-	wrsym(b, s.Gotype)
-	wrdata(b, s.P)
+	w.writeInt(flags)
+	w.writeInt(s.Size)
+	w.writeRefIndex(s.Gotype)
+	w.writeInt(int64(len(s.P)))
 
-	wrint(b, int64(len(s.R)))
+	w.writeInt(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
+		w.writeInt(int64(r.Off))
+		w.writeInt(int64(r.Siz))
+		w.writeInt(int64(r.Type))
+		w.writeInt(r.Add)
+		w.writeRefIndex(r.Sym)
 	}
 
-	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)
-		}
+	if s.Type != STEXT {
+		return
+	}
 
-		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])
+	w.writeInt(int64(s.Args))
+	w.writeInt(int64(s.Locals))
+	if s.Nosplit {
+		w.writeInt(1)
+	} else {
+		w.writeInt(0)
+	}
+	flags = int64(0)
+	if s.Leaf {
+		flags |= 1
+	}
+	if s.Cfunc {
+		flags |= 1 << 1
+	}
+	if s.ReflectMethod {
+		flags |= 1 << 2
+	}
+	w.writeInt(flags)
+	n := 0
+	for a := s.Autom; a != nil; a = a.Link {
+		n++
+	}
+	w.writeInt(int64(n))
+	for a := s.Autom; a != nil; a = a.Link {
+		w.writeRefIndex(a.Asym)
+		w.writeInt(int64(a.Aoffset))
+		if a.Name == NAME_AUTO {
+			w.writeInt(A_AUTO)
+		} else if a.Name == NAME_PARAM {
+			w.writeInt(A_PARAM)
+		} else {
+			log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
 		}
+		w.writeRefIndex(a.Gotype)
 	}
-}
 
-// Reusable buffer to avoid allocations.
-// This buffer was responsible for 15% of gc's allocations.
-var varintbuf [10]uint8
+	pc := s.Pcln
+	w.writeInt(int64(len(pc.Pcsp.P)))
+	w.writeInt(int64(len(pc.Pcfile.P)))
+	w.writeInt(int64(len(pc.Pcline.P)))
+	w.writeInt(int64(len(pc.Pcdata)))
+	for i := 0; i < len(pc.Pcdata); i++ {
+		w.writeInt(int64(len(pc.Pcdata[i].P)))
+	}
+	w.writeInt(int64(len(pc.Funcdataoff)))
+	for i := 0; i < len(pc.Funcdataoff); i++ {
+		w.writeRefIndex(pc.Funcdata[i])
+	}
+	for i := 0; i < len(pc.Funcdataoff); i++ {
+		w.writeInt(pc.Funcdataoff[i])
+	}
+	w.writeInt(int64(len(pc.File)))
+	for _, f := range pc.File {
+		w.writeRefIndex(f)
+	}
+}
 
-func wrint(b *Biobuf, sval int64) {
+func (w *objWriter) writeInt(sval int64) {
 	var v uint64
-	uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63))
-	p := varintbuf[:]
+	uv := (uint64(sval) << 1) ^ uint64(sval>>63)
+	p := w.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))
+	w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
 }
 
-func wrdata(b *Biobuf, v []byte) {
-	wrint(b, int64(len(v)))
-	b.Write(v)
+func (w *objWriter) writeString(s string) {
+	w.writeInt(int64(len(s)))
+	w.wr.WriteString(s)
 }
 
-func wrpathsym(ctxt *Link, b *Biobuf, s *LSym) {
+func (w *objWriter) writeRefIndex(s *LSym) {
 	if s == nil {
-		wrint(b, 0)
-		wrint(b, 0)
+		w.writeInt(0)
 		return
 	}
-
-	wrpath(ctxt, b, s.Name)
-	wrint(b, int64(s.Version))
+	if s.RefIdx == 0 {
+		log.Fatalln("writing an unreferenced symbol", s.Name)
+	}
+	w.writeInt(int64(s.RefIdx))
 }
 
-func wrsym(b *Biobuf, s *LSym) {
-	if s == nil {
-		wrint(b, 0)
-		wrint(b, 0)
-		return
-	}
+// relocByOff sorts relocations by their offsets.
+type relocByOff []Reloc
 
-	wrstring(b, s.Name)
-	wrint(b, int64(s.Version))
-}
+func (x relocByOff) Len() int           { return len(x) }
+func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
+func (x relocByOff) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go
index b92dfe2..ffbff74 100644
--- a/src/cmd/internal/obj/pass.go
+++ b/src/cmd/internal/obj/pass.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -202,13 +202,14 @@ func linkpatch(ctxt *Link, sym *LSym) {
 		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 ctxt.Flag_optimize {
+		for p := sym.Text; p != nil; p = p.Link {
 			if p.Pcond != nil {
-				if p.To.Type == TYPE_BRANCH {
-					p.To.Offset = p.Pcond.Pc
+				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
index 91c9293..b1536eb 100644
--- a/src/cmd/internal/obj/pcln.go
+++ b/src/cmd/internal/obj/pcln.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -64,7 +64,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
 		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)
+				fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(p.Pc), "", p)
 			}
 			continue
 		}
@@ -76,7 +76,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
 		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)
+				fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(p.Pc), "", p)
 			}
 			continue
 		}
@@ -96,11 +96,11 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
 		// 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)
+			fmt.Fprintf(ctxt.Bso, "%6x %6d %v\n", uint64(p.Pc), val, p)
 		}
 
 		if started != 0 {
-			addvarint(ctxt, dst, uint32((p.Pc-pc)/int64(ctxt.Arch.Minlc)))
+			addvarint(ctxt, dst, uint32((p.Pc-pc)/int64(ctxt.Arch.MinLC)))
 			pc = p.Pc
 		}
 
@@ -118,9 +118,9 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
 
 	if started != 0 {
 		if ctxt.Debugpcln != 0 {
-			fmt.Fprintf(ctxt.Bso, "%6x done\n", uint64(int64(func_.Text.Pc)+func_.Size))
+			fmt.Fprintf(ctxt.Bso, "%6x done\n", uint64(func_.Text.Pc+func_.Size))
 		}
-		addvarint(ctxt, dst, uint32((func_.Value+func_.Size-pc)/int64(ctxt.Arch.Minlc)))
+		addvarint(ctxt, dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC)))
 		addvarint(ctxt, dst, 0) // terminator
 	}
 
@@ -143,9 +143,7 @@ func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg
 	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)
+	f, l := linkgetline(ctxt, p.Lineno)
 	if f == nil {
 		//	print("getline failed for %s %v\n", ctxt->cursym->name, p);
 		return oldval
@@ -160,19 +158,18 @@ func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg
 		return int32(pcln.Lastindex)
 	}
 
-	var i int32
-	for i = 0; i < int32(len(pcln.File)); i++ {
-		file := pcln.File[i]
+	for i, file := range pcln.File {
 		if file == f {
 			pcln.Lastfile = f
-			pcln.Lastindex = int(i)
+			pcln.Lastindex = i
 			return int32(i)
 		}
 	}
+	i := len(pcln.File)
 	pcln.File = append(pcln.File, f)
 	pcln.Lastfile = f
-	pcln.Lastindex = int(i)
-	return i
+	pcln.Lastindex = i
+	return int32(i)
 }
 
 // pctospadj computes the sp adjustment in effect.
@@ -278,61 +275,3 @@ func linkpcln(ctxt *Link, cursym *LSym) {
 		}
 	}
 }
-
-// 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/plist.go b/src/cmd/internal/obj/plist.go
new file mode 100644
index 0000000..e55dbec
--- /dev/null
+++ b/src/cmd/internal/obj/plist.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.
+
+package obj
+
+import (
+	"fmt"
+	"log"
+	"strings"
+)
+
+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
+}
+
+func Flushplist(ctxt *Link) {
+	flushplist(ctxt, ctxt.Debugasm == 0)
+}
+func FlushplistNoFree(ctxt *Link) {
+	flushplist(ctxt, false)
+}
+func flushplist(ctxt *Link, freeProgs bool) {
+	// Build list of symbols, and assign instructions to lists.
+	// Ignore ctxt->plist boundaries. There are no guarantees there,
+	// and the assemblers just use one big list.
+	var curtext *LSym
+	var etext *Prog
+	var text []*LSym
+
+	for pl := ctxt.Plist; pl != nil; pl = pl.Link {
+		var plink *Prog
+		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
+
+			switch p.As {
+			case AEND:
+				continue
+
+			case 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
+
+			case AGLOBL:
+				s := p.From.Sym
+				if s.Seenglobl {
+					fmt.Printf("duplicate %v\n", p)
+				}
+				s.Seenglobl = true
+				if s.Onlist {
+					log.Fatalf("symbol %s listed multiple times", s.Name)
+				}
+				s.Onlist = true
+				ctxt.Data = append(ctxt.Data, s)
+				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 = true
+				}
+				if flag&RODATA != 0 {
+					s.Type = SRODATA
+				} else if flag&NOPTR != 0 {
+					s.Type = SNOPTRBSS
+				} else if flag&TLSBSS != 0 {
+					s.Type = STLSBSS
+				}
+				continue
+
+			case 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 {
+					log.Fatalf("symbol %s listed multiple times", s.Name)
+				}
+				s.Onlist = true
+				text = append(text, s)
+				flag := int(p.From3Offset())
+				if flag&DUPOK != 0 {
+					s.Dupok = true
+				}
+				if flag&NOSPLIT != 0 {
+					s.Nosplit = true
+				}
+				if flag&REFLECTMETHOD != 0 {
+					s.ReflectMethod = true
+				}
+				s.Type = STEXT
+				s.Text = p
+				etext = p
+				curtext = s
+				continue
+
+			case 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 {
+				etext = nil
+				continue
+			}
+			etext.Link = p
+			etext = p
+		}
+	}
+
+	// Add reference to Go arguments for C or assembly functions without them.
+	for _, s := range text {
+		if !strings.HasPrefix(s.Name, "\"\".") {
+			continue
+		}
+		found := false
+		var p *Prog
+		for p = s.Text; p != nil; p = p.Link {
+			if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps {
+				found = true
+				break
+			}
+		}
+
+		if !found {
+			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 := range text {
+		mkfwd(s)
+		linkpatch(ctxt, s)
+		if ctxt.Flag_optimize {
+			ctxt.Arch.Follow(ctxt, s)
+		}
+		ctxt.Arch.Preprocess(ctxt, s)
+		ctxt.Arch.Assemble(ctxt, s)
+		fieldtrack(ctxt, s)
+		linkpcln(ctxt, s)
+		if freeProgs {
+			s.Text = nil
+		}
+	}
+
+	// Add to running list in ctxt.
+	ctxt.Text = append(ctxt.Text, text...)
+	ctxt.Plist = nil
+	ctxt.Plast = nil
+	ctxt.Curp = nil
+	if freeProgs {
+		ctxt.freeProgs()
+	}
+}
diff --git a/src/cmd/internal/obj/ppc64/a.out.go b/src/cmd/internal/obj/ppc64/a.out.go
index 4f6cdcd..8e58c59 100644
--- a/src/cmd/internal/obj/ppc64/a.out.go
+++ b/src/cmd/internal/obj/ppc64/a.out.go
@@ -7,7 +7,7 @@
 //	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.
+//	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
@@ -342,8 +342,10 @@ const (
 	AFSUBS
 	AFSUBSCC
 	AMOVMW
+	ALBAR
 	ALSW
 	ALWAR
+	ALWSYNC
 	AMOVWBR
 	AMOVB
 	AMOVBU
@@ -401,6 +403,7 @@ const (
 	ASRAW
 	ASRAWCC
 	ASRWCC
+	ASTBCCC
 	ASTSW
 	ASTWCCC
 	ASUB
@@ -480,6 +483,8 @@ const (
 	/* AFCFIW; AFCFIWCC */
 	AFCFID
 	AFCFIDCC
+	AFCFIDU
+	AFCFIDUCC
 	AFCTID
 	AFCTIDCC
 	AFCTIDZ
diff --git a/src/cmd/internal/obj/ppc64/anames.go b/src/cmd/internal/obj/ppc64/anames.go
index 1ae7a52..eb42c9a 100644
--- a/src/cmd/internal/obj/ppc64/anames.go
+++ b/src/cmd/internal/obj/ppc64/anames.go
@@ -118,8 +118,10 @@ var Anames = []string{
 	"FSUBS",
 	"FSUBSCC",
 	"MOVMW",
+	"LBAR",
 	"LSW",
 	"LWAR",
+	"LWSYNC",
 	"MOVWBR",
 	"MOVB",
 	"MOVBU",
@@ -177,6 +179,7 @@ var Anames = []string{
 	"SRAW",
 	"SRAWCC",
 	"SRWCC",
+	"STBCCC",
 	"STSW",
 	"STWCCC",
 	"SUB",
@@ -247,6 +250,8 @@ var Anames = []string{
 	"EXTSWCC",
 	"FCFID",
 	"FCFIDCC",
+	"FCFIDU",
+	"FCFIDUCC",
 	"FCTID",
 	"FCTIDCC",
 	"FCTIDZ",
diff --git a/src/cmd/internal/obj/ppc64/anames9.go b/src/cmd/internal/obj/ppc64/anames9.go
index d7140b1..f7d1d77 100644
--- a/src/cmd/internal/obj/ppc64/anames9.go
+++ b/src/cmd/internal/obj/ppc64/anames9.go
@@ -1,3 +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.
+
 package ppc64
 
 var cnames9 = []string{
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 90224c3..5366809 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -7,7 +7,7 @@
 //	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.
+//	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
@@ -48,7 +48,7 @@ const (
 )
 
 type Optab struct {
-	as    int16
+	as    obj.As
 	a1    uint8
 	a2    uint8
 	a3    uint8
@@ -403,14 +403,9 @@ var optab = []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 oprange [ALAST & obj.AMask][]Optab
 
-var xcmp [C_NCLASS][C_NCLASS]uint8
+var xcmp [C_NCLASS][C_NCLASS]bool
 
 func span9(ctxt *obj.Link, cursym *obj.LSym) {
 	p := cursym.Text
@@ -420,7 +415,7 @@ func span9(ctxt *obj.Link, cursym *obj.LSym) {
 	ctxt.Cursym = cursym
 	ctxt.Autosize = int32(p.To.Offset)
 
-	if oprange[AANDN&obj.AMask].start == nil {
+	if oprange[AANDN&obj.AMask] == nil {
 		buildop(ctxt)
 	}
 
@@ -511,7 +506,7 @@ func span9(ctxt *obj.Link, cursym *obj.LSym) {
 	 * lay out the code, emitting code and data relocations.
 	 */
 
-	obj.Symgrow(ctxt, cursym, cursym.Size)
+	cursym.Grow(cursym.Size)
 
 	bp := cursym.P
 	var i int32
@@ -590,7 +585,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 			ctxt.Instoffset = a.Offset
 			if a.Sym != nil { // use relocation
 				if a.Sym.Type == obj.STLSBSS {
-					if ctxt.Flag_shared != 0 {
+					if ctxt.Flag_shared {
 						return C_TLS_IE
 					} else {
 						return C_TLS_LE
@@ -636,7 +631,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 	case obj.TYPE_CONST,
 		obj.TYPE_ADDR:
 		switch a.Name {
-		case obj.TYPE_NONE:
+		case obj.NAME_NONE:
 			ctxt.Instoffset = a.Offset
 			if a.Reg != 0 {
 				if -BIG <= ctxt.Instoffset && ctxt.Instoffset <= BIG {
@@ -657,11 +652,11 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
 				break
 			}
 			if s.Type == obj.SCONST {
-				ctxt.Instoffset = s.Value + a.Offset
+				ctxt.Instoffset = a.Offset
 				goto consize
 			}
 
-			ctxt.Instoffset = s.Value + a.Offset
+			ctxt.Instoffset = a.Offset
 
 			/* not sure why this barfs */
 			return C_LCON
@@ -731,7 +726,7 @@ func prasm(p *obj.Prog) {
 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	a1 := int(p.Optab)
 	if a1 != 0 {
-		return &optab[a1-1:][0]
+		return &optab[a1-1]
 	}
 	a1 = int(p.From.Class)
 	if a1 == 0 {
@@ -763,35 +758,24 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
 	}
 
 	//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]
-					}
-				}
-			}
+	ops := oprange[p.As&obj.AMask]
+	c1 := &xcmp[a1]
+	c3 := &xcmp[a3]
+	c4 := &xcmp[a4]
+	for i := range ops {
+		op := &ops[i]
+		if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] && c4[op.a4] {
+			p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
+			return op
 		}
 	}
 
-	ctxt.Diag("illegal combination %v %v %v %v %v", obj.Aconv(int(p.As)), DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
+	ctxt.Diag("illegal combination %v %v %v %v %v", obj.Aconv(p.As), DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
 	prasm(p)
-	if o == nil {
-		o = optab
+	if ops == nil {
+		ops = optab
 	}
-	return &o[0]
+	return &ops[0]
 }
 
 func cmp(a int, b int) bool {
@@ -906,7 +890,7 @@ func (x ocmp) Less(i, j int) bool {
 	}
 	return false
 }
-func opset(a, b0 int16) {
+func opset(a, b0 obj.As) {
 	oprange[a&obj.AMask] = oprange[b0]
 }
 
@@ -916,7 +900,7 @@ func buildop(ctxt *obj.Link) {
 	for i := 0; i < C_NCLASS; i++ {
 		for n = 0; n < C_NCLASS; n++ {
 			if cmp(n, i) {
-				xcmp[i][n] = 1
+				xcmp[i][n] = true
 			}
 		}
 	}
@@ -926,16 +910,16 @@ func buildop(ctxt *obj.Link) {
 	for i := 0; i < n; i++ {
 		r := optab[i].as
 		r0 := r & obj.AMask
-		oprange[r0].start = optab[i:]
+		start := i
 		for optab[i].as == r {
 			i++
 		}
-		oprange[r0].stop = optab[i:]
+		oprange[r0] = optab[start:i]
 		i--
 
 		switch r {
 		default:
-			ctxt.Diag("unknown op in build: %v", obj.Aconv(int(r)))
+			ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
 			log.Fatalf("bad code")
 
 		case ADCBF: /* unary indexed: op (b+a); op (b) */
@@ -949,6 +933,7 @@ func buildop(ctxt *obj.Link) {
 
 		case AECOWX: /* indexed store: op s,(b+a); op s,(b) */
 			opset(ASTWCCC, r0)
+			opset(ASTBCCC, r0)
 
 			opset(ASTDCCC, r0)
 
@@ -1121,6 +1106,8 @@ func buildop(ctxt *obj.Link) {
 			opset(AFCTIDZCC, r0)
 			opset(AFCFID, r0)
 			opset(AFCFIDCC, r0)
+			opset(AFCFIDU, r0)
+			opset(AFCFIDUCC, r0)
 			opset(AFRES, r0)
 			opset(AFRESCC, r0)
 			opset(AFRSQRTE, r0)
@@ -1216,6 +1203,7 @@ func buildop(ctxt *obj.Link) {
 
 		case ASYNC:
 			opset(AISYNC, r0)
+			opset(ALWSYNC, r0)
 			opset(APTESYNC, r0)
 			opset(ATLBSYNC, r0)
 
@@ -1242,6 +1230,7 @@ func buildop(ctxt *obj.Link) {
 			opset(AFMOVSU, r0)
 
 		case AECIWX:
+			opset(ALBAR, r0)
 			opset(ALWAR, r0)
 			opset(ALDAR, r0)
 
@@ -1399,8 +1388,8 @@ const (
 // opform returns the form (D_FORM or DS_FORM) of an instruction. Used to decide on
 // which relocation to use with a load or store and only supports the needed
 // instructions.
-func opform(ctxt *obj.Link, insn int32) int {
-	switch uint32(insn) {
+func opform(ctxt *obj.Link, insn uint32) int {
+	switch insn {
 	default:
 		ctxt.Diag("bad insn in loadform: %x", insn)
 	case OPVCC(58, 0, 0, 0), // ld
@@ -1426,22 +1415,22 @@ func opform(ctxt *obj.Link, insn int32) int {
 
 // Encode instructions and create relocation for accessing s+d according to the
 // instruction op with source or destination (as appropriate) register reg.
-func symbolAccess(ctxt *obj.Link, s *obj.LSym, d int64, reg int16, op int32) (o1, o2 uint32) {
+func symbolAccess(ctxt *obj.Link, s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 uint32) {
 	var base uint32
 	form := opform(ctxt, op)
-	if ctxt.Flag_shared != 0 {
+	if ctxt.Flag_shared {
 		base = REG_R2
 	} else {
 		base = REG_R0
 	}
 	o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0)
-	o2 = AOP_IRR(uint32(op), uint32(reg), REGTMP, 0)
+	o2 = AOP_IRR(op, uint32(reg), REGTMP, 0)
 	rel := obj.Addrel(ctxt.Cursym)
 	rel.Off = int32(ctxt.Pc)
 	rel.Siz = 8
 	rel.Sym = s
 	rel.Add = d
-	if ctxt.Flag_shared != 0 {
+	if ctxt.Flag_shared {
 		switch form {
 		case D_FORM:
 			rel.Type = obj.R_ADDRPOWER_TOCREL
@@ -1592,7 +1581,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = AOP_RRR(oprrr(ctxt, 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)
@@ -1638,10 +1627,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = AOP_IRR(opirr(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(v))
 
 	case 5: /* syscall */
-		o1 = uint32(oprrr(ctxt, int(p.As)))
+		o1 = oprrr(ctxt, p.As)
 
 	case 6: /* logical op Rb,[Rs,]Ra; no literal */
 		r := int(p.Reg)
@@ -1649,7 +1638,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = LOP_RRR(oprrr(ctxt, 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)
@@ -1662,7 +1651,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			if v != 0 {
 				ctxt.Diag("illegal indexed instruction\n%v", p)
 			}
-			if ctxt.Flag_shared != 0 && r == REG_R13 {
+			if ctxt.Flag_shared && r == REG_R13 {
 				rel := obj.Addrel(ctxt.Cursym)
 				rel.Off = int32(ctxt.Pc)
 				rel.Siz = 4
@@ -1674,12 +1663,12 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 				rel.Sym = obj.Linklookup(ctxt, "runtime.tls_g", 0)
 				rel.Type = obj.R_POWER_TLS
 			}
-			o1 = AOP_RRR(uint32(opstorex(ctxt, int(p.As))), uint32(p.From.Reg), uint32(p.To.Index), uint32(r))
+			o1 = AOP_RRR(opstorex(ctxt, 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))
+			o1 = AOP_IRR(opstore(ctxt, p.As), uint32(p.From.Reg), uint32(r), uint32(v))
 		}
 
 	case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
@@ -1693,19 +1682,19 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			if v != 0 {
 				ctxt.Diag("illegal indexed instruction\n%v", p)
 			}
-			if ctxt.Flag_shared != 0 && r == REG_R13 {
+			if ctxt.Flag_shared && r == REG_R13 {
 				rel := obj.Addrel(ctxt.Cursym)
 				rel.Off = int32(ctxt.Pc)
 				rel.Siz = 4
 				rel.Sym = obj.Linklookup(ctxt, "runtime.tls_g", 0)
 				rel.Type = obj.R_POWER_TLS
 			}
-			o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
+			o1 = AOP_RRR(oploadx(ctxt, 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))
+			o1 = AOP_IRR(opload(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(v))
 		}
 
 	case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
@@ -1719,9 +1708,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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))
+			o1 = AOP_RRR(oploadx(ctxt, 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))
+			o1 = AOP_IRR(opload(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(v))
 		}
 		o2 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
@@ -1731,7 +1720,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(r))
 
 	case 11: /* br/bl lbra */
 		v := int32(0)
@@ -1748,7 +1737,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			}
 		}
 
-		o1 = OP_BR(uint32(opirr(ctxt, int(p.As))), uint32(v), 0)
+		o1 = OP_BR(opirr(ctxt, p.As), uint32(v), 0)
 		if p.To.Sym != nil {
 			rel := obj.Addrel(ctxt.Cursym)
 			rel.Off = int32(ctxt.Pc)
@@ -1823,7 +1812,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			a = 0
 		}
 
-		o1 = LOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
+		o1 = LOP_RRR(oprrr(ctxt, 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 */
@@ -1852,7 +1841,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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)
+		o1 = OP_BC(opirr(ctxt, p.As), uint32(a), uint32(r), uint32(v), 0)
 
 	case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */
 		var v int32
@@ -1918,11 +1907,11 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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)
+		o1 = AOP_IRR(opirr(ctxt, -p.As), 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)
+			ctxt.Diag("can't synthesize large constant\n%v", p)
 		}
 		d := vregoff(ctxt, &p.From)
 		o1 = loadu32(REGTMP, d)
@@ -1931,7 +1920,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o3 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(r))
+		o3 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), REGTMP, uint32(r))
 		if p.From.Sym != nil {
 			ctxt.Diag("%v is not supported", p)
 		}
@@ -1940,7 +1929,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 
 	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)
+			ctxt.Diag("can't synthesize large constant\n%v", p)
 		}
 		d := vregoff(ctxt, &p.From)
 		o1 = loadu32(REGTMP, d)
@@ -1949,7 +1938,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o3 = LOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(r))
+		o3 = LOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), REGTMP, uint32(r))
 		if p.From.Sym != nil {
 			ctxt.Diag("%v is not supported", p)
 		}
@@ -2015,7 +2004,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = AOP_IRR(opirr(ctxt, 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 {
@@ -2024,7 +2013,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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)
+		o3 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(p.From.Reg), REGTMP)
 		if p.From.Sym != nil {
 			ctxt.Diag("%v is not supported", p)
 		}
@@ -2062,7 +2051,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			a = 0
 		}
 
-		o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
+		o1 = AOP_RRR(opirr(ctxt, p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
 		o1 |= (uint32(a) & 31) << 6
 		if v&0x20 != 0 {
 			o1 |= 1 << 1
@@ -2080,7 +2069,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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 = AOP_RRR(opirr(ctxt, 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
@@ -2117,7 +2106,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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
+		o1 = AOP_RRR(oprrr(ctxt, 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)
@@ -2125,10 +2114,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = AOP_RRR(oprrr(ctxt, 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
+		o1 = AOP_RRR(oprrr(ctxt, 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)
@@ -2138,7 +2127,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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))
+		o2 = AOP_IRR(opstore(ctxt, 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)
@@ -2148,7 +2137,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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))
+		o2 = AOP_IRR(opload(ctxt, 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)
@@ -2158,29 +2147,29 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			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))
+		o2 = AOP_IRR(opload(ctxt, 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
+		o1 = AOP_RRR(opirr(ctxt, 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
+		o1 = AOP_RRR(opirr(ctxt, 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))
+		o1 = AOP_RRR(oprrr(ctxt, 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))
+		o1 = AOP_RRR(opstorex(ctxt, 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))
+		o1 = AOP_RRR(oploadx(ctxt, 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)))
+		o1 = oprrr(ctxt, p.As)
 
 	case 47: /* op Ra, Rd; also op [Ra,] Rd */
 		r := int(p.From.Reg)
@@ -2188,7 +2177,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), 0)
+		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(p.To.Reg), uint32(r), 0)
 
 	case 48: /* op Rs, Ra */
 		r := int(p.From.Reg)
@@ -2196,14 +2185,14 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		o1 = LOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), 0)
+		o1 = LOP_RRR(oprrr(ctxt, 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
+			o1 = AOP_RRR(oprrr(ctxt, 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))
+			o1 = AOP_RRR(oprrr(ctxt, p.As), 0, 0, uint32(p.From.Reg))
 		}
 
 	case 50: /* rem[u] r1[,r2],r3 */
@@ -2212,11 +2201,11 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		v := oprrr(ctxt, int(p.As))
+		v := oprrr(ctxt, p.As)
 		t := v & (1<<10 | 1) /* OE|Rc */
-		o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg))
+		o1 = AOP_RRR(v&^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))
+		o3 = AOP_RRR(OP_SUBF|t, uint32(p.To.Reg), REGTMP, uint32(r))
 		if p.As == AREMU {
 			o4 = o3
 
@@ -2230,16 +2219,16 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		v := oprrr(ctxt, int(p.As))
+		v := oprrr(ctxt, p.As)
 		t := v & (1<<10 | 1) /* OE|Rc */
-		o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg))
+		o1 = AOP_RRR(v&^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))
+		o3 = AOP_RRR(OP_SUBF|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)
+		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(v), 0, 0)
 
 	case 53: /* mffsX ,fr1 */
 		o1 = AOP_RRR(OP_MFFS, uint32(p.To.Reg), 0, 0)
@@ -2256,7 +2245,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 	case 55: /* op Rb, Rd */
-		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), 0, uint32(p.From.Reg))
+		o1 = AOP_RRR(oprrr(ctxt, 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)
@@ -2265,7 +2254,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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)
+		o1 = AOP_RRR(opirr(ctxt, p.As), uint32(r), uint32(p.To.Reg), uint32(v)&31)
 		if (p.As == ASRAD || p.As == ASRADCC) && (v&0x20 != 0) {
 			o1 |= 1 << 1 /* mb[5] */
 		}
@@ -2312,7 +2301,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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))
+		o1 = LOP_IRR(opirr(ctxt, p.As), uint32(p.To.Reg), uint32(r), uint32(v))
 
 	case 59: /* or/and $ucon,,r */
 		v := regoff(ctxt, &p.From)
@@ -2321,32 +2310,32 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		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 */
+		o1 = LOP_IRR(opirr(ctxt, -p.As), 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))
+		o1 = AOP_RRR(oprrr(ctxt, 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))
+		o1 = AOP_IRR(opirr(ctxt, 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 = AOP_RRR(opirr(ctxt, 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 = AOP_RRR(opirr(ctxt, 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} */
@@ -2425,7 +2414,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		} 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))
+		o1 = AOP_RRR(oprrr(ctxt, p.As), uint32(r), uint32(p.From.Reg), uint32(p.To.Reg))
 
 	case 71: /* cmp[l] r,i,cr*/
 		var r int
@@ -2434,10 +2423,10 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		} 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
+		o1 = AOP_RRR(opirr(ctxt, 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))
+		o1 = AOP_RRR(oprrr(ctxt, 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 {
@@ -2458,8 +2447,8 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			o1 = 0x7fe00008 // trap always
 		}
 
-		o2 = uint32(oprrr(ctxt, int(p.As)))
-		o3 = AOP_RRR(uint32(oprrr(ctxt, AXOR)), REGZERO, REGZERO, REGZERO) // XOR R0, R0
+		o2 = oprrr(ctxt, p.As)
+		o3 = AOP_RRR(oprrr(ctxt, AXOR), REGZERO, REGZERO, REGZERO) // XOR R0, R0
 
 	case 78: /* undef */
 		o1 = 0 /* "An instruction consisting entirely of binary 0s is guaranteed
@@ -2468,19 +2457,19 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 	/* relocation operations */
 	case 74:
 		v := vregoff(ctxt, &p.To)
-		o1, o2 = symbolAccess(ctxt, p.To.Sym, v, p.From.Reg, opstore(ctxt, int(p.As)))
+		o1, o2 = symbolAccess(ctxt, p.To.Sym, v, p.From.Reg, opstore(ctxt, p.As))
 
 	//if(dlm) reloc(&p->to, p->pc, 1);
 
 	case 75:
 		v := vregoff(ctxt, &p.From)
-		o1, o2 = symbolAccess(ctxt, p.From.Sym, v, p.To.Reg, opload(ctxt, int(p.As)))
+		o1, o2 = symbolAccess(ctxt, p.From.Sym, v, p.To.Reg, opload(ctxt, p.As))
 
 	//if(dlm) reloc(&p->from, p->pc, 1);
 
 	case 76:
 		v := vregoff(ctxt, &p.From)
-		o1, o2 = symbolAccess(ctxt, p.From.Sym, v, p.To.Reg, opload(ctxt, int(p.As)))
+		o1, o2 = symbolAccess(ctxt, p.From.Sym, v, p.To.Reg, opload(ctxt, p.As))
 		o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
 		//if(dlm) reloc(&p->from, p->pc, 1);
@@ -2501,7 +2490,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 			ctxt.Diag("invalid offset against tls var %v", p)
 		}
 		o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
-		o2 = AOP_IRR(uint32(opload(ctxt, AMOVD)), uint32(p.To.Reg), uint32(p.To.Reg), 0)
+		o2 = AOP_IRR(opload(ctxt, AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0)
 		rel := obj.Addrel(ctxt.Cursym)
 		rel.Off = int32(ctxt.Pc)
 		rel.Siz = 8
@@ -2515,7 +2504,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
 		}
 
 		o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
-		o2 = AOP_IRR(uint32(opload(ctxt, AMOVD)), uint32(p.To.Reg), uint32(p.To.Reg), 0)
+		o2 = AOP_IRR(opload(ctxt, AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0)
 		rel := obj.Addrel(ctxt.Cursym)
 		rel.Off = int32(ctxt.Pc)
 		rel.Siz = 8
@@ -2543,625 +2532,632 @@ func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
 	return int32(vregoff(ctxt, a))
 }
 
-func oprrr(ctxt *obj.Link, a int) int32 {
+func oprrr(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AADD:
-		return int32(OPVCC(31, 266, 0, 0))
+		return OPVCC(31, 266, 0, 0)
 	case AADDCC:
-		return int32(OPVCC(31, 266, 0, 1))
+		return OPVCC(31, 266, 0, 1)
 	case AADDV:
-		return int32(OPVCC(31, 266, 1, 0))
+		return OPVCC(31, 266, 1, 0)
 	case AADDVCC:
-		return int32(OPVCC(31, 266, 1, 1))
+		return OPVCC(31, 266, 1, 1)
 	case AADDC:
-		return int32(OPVCC(31, 10, 0, 0))
+		return OPVCC(31, 10, 0, 0)
 	case AADDCCC:
-		return int32(OPVCC(31, 10, 0, 1))
+		return OPVCC(31, 10, 0, 1)
 	case AADDCV:
-		return int32(OPVCC(31, 10, 1, 0))
+		return OPVCC(31, 10, 1, 0)
 	case AADDCVCC:
-		return int32(OPVCC(31, 10, 1, 1))
+		return OPVCC(31, 10, 1, 1)
 	case AADDE:
-		return int32(OPVCC(31, 138, 0, 0))
+		return OPVCC(31, 138, 0, 0)
 	case AADDECC:
-		return int32(OPVCC(31, 138, 0, 1))
+		return OPVCC(31, 138, 0, 1)
 	case AADDEV:
-		return int32(OPVCC(31, 138, 1, 0))
+		return OPVCC(31, 138, 1, 0)
 	case AADDEVCC:
-		return int32(OPVCC(31, 138, 1, 1))
+		return OPVCC(31, 138, 1, 1)
 	case AADDME:
-		return int32(OPVCC(31, 234, 0, 0))
+		return OPVCC(31, 234, 0, 0)
 	case AADDMECC:
-		return int32(OPVCC(31, 234, 0, 1))
+		return OPVCC(31, 234, 0, 1)
 	case AADDMEV:
-		return int32(OPVCC(31, 234, 1, 0))
+		return OPVCC(31, 234, 1, 0)
 	case AADDMEVCC:
-		return int32(OPVCC(31, 234, 1, 1))
+		return OPVCC(31, 234, 1, 1)
 	case AADDZE:
-		return int32(OPVCC(31, 202, 0, 0))
+		return OPVCC(31, 202, 0, 0)
 	case AADDZECC:
-		return int32(OPVCC(31, 202, 0, 1))
+		return OPVCC(31, 202, 0, 1)
 	case AADDZEV:
-		return int32(OPVCC(31, 202, 1, 0))
+		return OPVCC(31, 202, 1, 0)
 	case AADDZEVCC:
-		return int32(OPVCC(31, 202, 1, 1))
+		return OPVCC(31, 202, 1, 1)
 
 	case AAND:
-		return int32(OPVCC(31, 28, 0, 0))
+		return OPVCC(31, 28, 0, 0)
 	case AANDCC:
-		return int32(OPVCC(31, 28, 0, 1))
+		return OPVCC(31, 28, 0, 1)
 	case AANDN:
-		return int32(OPVCC(31, 60, 0, 0))
+		return OPVCC(31, 60, 0, 0)
 	case AANDNCC:
-		return int32(OPVCC(31, 60, 0, 1))
+		return OPVCC(31, 60, 0, 1)
 
 	case ACMP:
-		return int32(OPVCC(31, 0, 0, 0) | 1<<21) /* L=1 */
+		return OPVCC(31, 0, 0, 0) | 1<<21 /* L=1 */
 	case ACMPU:
-		return int32(OPVCC(31, 32, 0, 0) | 1<<21)
+		return OPVCC(31, 32, 0, 0) | 1<<21
 	case ACMPW:
-		return int32(OPVCC(31, 0, 0, 0)) /* L=0 */
+		return OPVCC(31, 0, 0, 0) /* L=0 */
 	case ACMPWU:
-		return int32(OPVCC(31, 32, 0, 0))
+		return OPVCC(31, 32, 0, 0)
 
 	case ACNTLZW:
-		return int32(OPVCC(31, 26, 0, 0))
+		return OPVCC(31, 26, 0, 0)
 	case ACNTLZWCC:
-		return int32(OPVCC(31, 26, 0, 1))
+		return OPVCC(31, 26, 0, 1)
 	case ACNTLZD:
-		return int32(OPVCC(31, 58, 0, 0))
+		return OPVCC(31, 58, 0, 0)
 	case ACNTLZDCC:
-		return int32(OPVCC(31, 58, 0, 1))
+		return OPVCC(31, 58, 0, 1)
 
 	case ACRAND:
-		return int32(OPVCC(19, 257, 0, 0))
+		return OPVCC(19, 257, 0, 0)
 	case ACRANDN:
-		return int32(OPVCC(19, 129, 0, 0))
+		return OPVCC(19, 129, 0, 0)
 	case ACREQV:
-		return int32(OPVCC(19, 289, 0, 0))
+		return OPVCC(19, 289, 0, 0)
 	case ACRNAND:
-		return int32(OPVCC(19, 225, 0, 0))
+		return OPVCC(19, 225, 0, 0)
 	case ACRNOR:
-		return int32(OPVCC(19, 33, 0, 0))
+		return OPVCC(19, 33, 0, 0)
 	case ACROR:
-		return int32(OPVCC(19, 449, 0, 0))
+		return OPVCC(19, 449, 0, 0)
 	case ACRORN:
-		return int32(OPVCC(19, 417, 0, 0))
+		return OPVCC(19, 417, 0, 0)
 	case ACRXOR:
-		return int32(OPVCC(19, 193, 0, 0))
+		return OPVCC(19, 193, 0, 0)
 
 	case ADCBF:
-		return int32(OPVCC(31, 86, 0, 0))
+		return OPVCC(31, 86, 0, 0)
 	case ADCBI:
-		return int32(OPVCC(31, 470, 0, 0))
+		return OPVCC(31, 470, 0, 0)
 	case ADCBST:
-		return int32(OPVCC(31, 54, 0, 0))
+		return OPVCC(31, 54, 0, 0)
 	case ADCBT:
-		return int32(OPVCC(31, 278, 0, 0))
+		return OPVCC(31, 278, 0, 0)
 	case ADCBTST:
-		return int32(OPVCC(31, 246, 0, 0))
+		return OPVCC(31, 246, 0, 0)
 	case ADCBZ:
-		return int32(OPVCC(31, 1014, 0, 0))
+		return OPVCC(31, 1014, 0, 0)
 
 	case AREM, ADIVW:
-		return int32(OPVCC(31, 491, 0, 0))
+		return OPVCC(31, 491, 0, 0)
 
 	case AREMCC, ADIVWCC:
-		return int32(OPVCC(31, 491, 0, 1))
+		return OPVCC(31, 491, 0, 1)
 
 	case AREMV, ADIVWV:
-		return int32(OPVCC(31, 491, 1, 0))
+		return OPVCC(31, 491, 1, 0)
 
 	case AREMVCC, ADIVWVCC:
-		return int32(OPVCC(31, 491, 1, 1))
+		return OPVCC(31, 491, 1, 1)
 
 	case AREMU, ADIVWU:
-		return int32(OPVCC(31, 459, 0, 0))
+		return OPVCC(31, 459, 0, 0)
 
 	case AREMUCC, ADIVWUCC:
-		return int32(OPVCC(31, 459, 0, 1))
+		return OPVCC(31, 459, 0, 1)
 
 	case AREMUV, ADIVWUV:
-		return int32(OPVCC(31, 459, 1, 0))
+		return OPVCC(31, 459, 1, 0)
 
 	case AREMUVCC, ADIVWUVCC:
-		return int32(OPVCC(31, 459, 1, 1))
+		return OPVCC(31, 459, 1, 1)
 
 	case AREMD, ADIVD:
-		return int32(OPVCC(31, 489, 0, 0))
+		return OPVCC(31, 489, 0, 0)
 
 	case AREMDCC, ADIVDCC:
-		return int32(OPVCC(31, 489, 0, 1))
+		return OPVCC(31, 489, 0, 1)
 
 	case AREMDV, ADIVDV:
-		return int32(OPVCC(31, 489, 1, 0))
+		return OPVCC(31, 489, 1, 0)
 
 	case AREMDVCC, ADIVDVCC:
-		return int32(OPVCC(31, 489, 1, 1))
+		return OPVCC(31, 489, 1, 1)
 
 	case AREMDU, ADIVDU:
-		return int32(OPVCC(31, 457, 0, 0))
+		return OPVCC(31, 457, 0, 0)
 
 	case AREMDUCC, ADIVDUCC:
-		return int32(OPVCC(31, 457, 0, 1))
+		return OPVCC(31, 457, 0, 1)
 
 	case AREMDUV, ADIVDUV:
-		return int32(OPVCC(31, 457, 1, 0))
+		return OPVCC(31, 457, 1, 0)
 
 	case AREMDUVCC, ADIVDUVCC:
-		return int32(OPVCC(31, 457, 1, 1))
+		return OPVCC(31, 457, 1, 1)
 
 	case AEIEIO:
-		return int32(OPVCC(31, 854, 0, 0))
+		return OPVCC(31, 854, 0, 0)
 
 	case AEQV:
-		return int32(OPVCC(31, 284, 0, 0))
+		return OPVCC(31, 284, 0, 0)
 	case AEQVCC:
-		return int32(OPVCC(31, 284, 0, 1))
+		return OPVCC(31, 284, 0, 1)
 
 	case AEXTSB:
-		return int32(OPVCC(31, 954, 0, 0))
+		return OPVCC(31, 954, 0, 0)
 	case AEXTSBCC:
-		return int32(OPVCC(31, 954, 0, 1))
+		return OPVCC(31, 954, 0, 1)
 	case AEXTSH:
-		return int32(OPVCC(31, 922, 0, 0))
+		return OPVCC(31, 922, 0, 0)
 	case AEXTSHCC:
-		return int32(OPVCC(31, 922, 0, 1))
+		return OPVCC(31, 922, 0, 1)
 	case AEXTSW:
-		return int32(OPVCC(31, 986, 0, 0))
+		return OPVCC(31, 986, 0, 0)
 	case AEXTSWCC:
-		return int32(OPVCC(31, 986, 0, 1))
+		return OPVCC(31, 986, 0, 1)
 
 	case AFABS:
-		return int32(OPVCC(63, 264, 0, 0))
+		return OPVCC(63, 264, 0, 0)
 	case AFABSCC:
-		return int32(OPVCC(63, 264, 0, 1))
+		return OPVCC(63, 264, 0, 1)
 	case AFADD:
-		return int32(OPVCC(63, 21, 0, 0))
+		return OPVCC(63, 21, 0, 0)
 	case AFADDCC:
-		return int32(OPVCC(63, 21, 0, 1))
+		return OPVCC(63, 21, 0, 1)
 	case AFADDS:
-		return int32(OPVCC(59, 21, 0, 0))
+		return OPVCC(59, 21, 0, 0)
 	case AFADDSCC:
-		return int32(OPVCC(59, 21, 0, 1))
+		return OPVCC(59, 21, 0, 1)
 	case AFCMPO:
-		return int32(OPVCC(63, 32, 0, 0))
+		return OPVCC(63, 32, 0, 0)
 	case AFCMPU:
-		return int32(OPVCC(63, 0, 0, 0))
+		return OPVCC(63, 0, 0, 0)
 	case AFCFID:
-		return int32(OPVCC(63, 846, 0, 0))
+		return OPVCC(63, 846, 0, 0)
 	case AFCFIDCC:
-		return int32(OPVCC(63, 846, 0, 1))
+		return OPVCC(63, 846, 0, 1)
+	case AFCFIDU:
+		return OPVCC(63, 974, 0, 0)
+	case AFCFIDUCC:
+		return OPVCC(63, 974, 0, 1)
 	case AFCTIW:
-		return int32(OPVCC(63, 14, 0, 0))
+		return OPVCC(63, 14, 0, 0)
 	case AFCTIWCC:
-		return int32(OPVCC(63, 14, 0, 1))
+		return OPVCC(63, 14, 0, 1)
 	case AFCTIWZ:
-		return int32(OPVCC(63, 15, 0, 0))
+		return OPVCC(63, 15, 0, 0)
 	case AFCTIWZCC:
-		return int32(OPVCC(63, 15, 0, 1))
+		return OPVCC(63, 15, 0, 1)
 	case AFCTID:
-		return int32(OPVCC(63, 814, 0, 0))
+		return OPVCC(63, 814, 0, 0)
 	case AFCTIDCC:
-		return int32(OPVCC(63, 814, 0, 1))
+		return OPVCC(63, 814, 0, 1)
 	case AFCTIDZ:
-		return int32(OPVCC(63, 815, 0, 0))
+		return OPVCC(63, 815, 0, 0)
 	case AFCTIDZCC:
-		return int32(OPVCC(63, 815, 0, 1))
+		return OPVCC(63, 815, 0, 1)
 	case AFDIV:
-		return int32(OPVCC(63, 18, 0, 0))
+		return OPVCC(63, 18, 0, 0)
 	case AFDIVCC:
-		return int32(OPVCC(63, 18, 0, 1))
+		return OPVCC(63, 18, 0, 1)
 	case AFDIVS:
-		return int32(OPVCC(59, 18, 0, 0))
+		return OPVCC(59, 18, 0, 0)
 	case AFDIVSCC:
-		return int32(OPVCC(59, 18, 0, 1))
+		return OPVCC(59, 18, 0, 1)
 	case AFMADD:
-		return int32(OPVCC(63, 29, 0, 0))
+		return OPVCC(63, 29, 0, 0)
 	case AFMADDCC:
-		return int32(OPVCC(63, 29, 0, 1))
+		return OPVCC(63, 29, 0, 1)
 	case AFMADDS:
-		return int32(OPVCC(59, 29, 0, 0))
+		return OPVCC(59, 29, 0, 0)
 	case AFMADDSCC:
-		return int32(OPVCC(59, 29, 0, 1))
+		return OPVCC(59, 29, 0, 1)
 
 	case AFMOVS, AFMOVD:
-		return int32(OPVCC(63, 72, 0, 0)) /* load */
+		return OPVCC(63, 72, 0, 0) /* load */
 	case AFMOVDCC:
-		return int32(OPVCC(63, 72, 0, 1))
+		return OPVCC(63, 72, 0, 1)
 	case AFMSUB:
-		return int32(OPVCC(63, 28, 0, 0))
+		return OPVCC(63, 28, 0, 0)
 	case AFMSUBCC:
-		return int32(OPVCC(63, 28, 0, 1))
+		return OPVCC(63, 28, 0, 1)
 	case AFMSUBS:
-		return int32(OPVCC(59, 28, 0, 0))
+		return OPVCC(59, 28, 0, 0)
 	case AFMSUBSCC:
-		return int32(OPVCC(59, 28, 0, 1))
+		return OPVCC(59, 28, 0, 1)
 	case AFMUL:
-		return int32(OPVCC(63, 25, 0, 0))
+		return OPVCC(63, 25, 0, 0)
 	case AFMULCC:
-		return int32(OPVCC(63, 25, 0, 1))
+		return OPVCC(63, 25, 0, 1)
 	case AFMULS:
-		return int32(OPVCC(59, 25, 0, 0))
+		return OPVCC(59, 25, 0, 0)
 	case AFMULSCC:
-		return int32(OPVCC(59, 25, 0, 1))
+		return OPVCC(59, 25, 0, 1)
 	case AFNABS:
-		return int32(OPVCC(63, 136, 0, 0))
+		return OPVCC(63, 136, 0, 0)
 	case AFNABSCC:
-		return int32(OPVCC(63, 136, 0, 1))
+		return OPVCC(63, 136, 0, 1)
 	case AFNEG:
-		return int32(OPVCC(63, 40, 0, 0))
+		return OPVCC(63, 40, 0, 0)
 	case AFNEGCC:
-		return int32(OPVCC(63, 40, 0, 1))
+		return OPVCC(63, 40, 0, 1)
 	case AFNMADD:
-		return int32(OPVCC(63, 31, 0, 0))
+		return OPVCC(63, 31, 0, 0)
 	case AFNMADDCC:
-		return int32(OPVCC(63, 31, 0, 1))
+		return OPVCC(63, 31, 0, 1)
 	case AFNMADDS:
-		return int32(OPVCC(59, 31, 0, 0))
+		return OPVCC(59, 31, 0, 0)
 	case AFNMADDSCC:
-		return int32(OPVCC(59, 31, 0, 1))
+		return OPVCC(59, 31, 0, 1)
 	case AFNMSUB:
-		return int32(OPVCC(63, 30, 0, 0))
+		return OPVCC(63, 30, 0, 0)
 	case AFNMSUBCC:
-		return int32(OPVCC(63, 30, 0, 1))
+		return OPVCC(63, 30, 0, 1)
 	case AFNMSUBS:
-		return int32(OPVCC(59, 30, 0, 0))
+		return OPVCC(59, 30, 0, 0)
 	case AFNMSUBSCC:
-		return int32(OPVCC(59, 30, 0, 1))
+		return OPVCC(59, 30, 0, 1)
 	case AFRES:
-		return int32(OPVCC(59, 24, 0, 0))
+		return OPVCC(59, 24, 0, 0)
 	case AFRESCC:
-		return int32(OPVCC(59, 24, 0, 1))
+		return OPVCC(59, 24, 0, 1)
 	case AFRSP:
-		return int32(OPVCC(63, 12, 0, 0))
+		return OPVCC(63, 12, 0, 0)
 	case AFRSPCC:
-		return int32(OPVCC(63, 12, 0, 1))
+		return OPVCC(63, 12, 0, 1)
 	case AFRSQRTE:
-		return int32(OPVCC(63, 26, 0, 0))
+		return OPVCC(63, 26, 0, 0)
 	case AFRSQRTECC:
-		return int32(OPVCC(63, 26, 0, 1))
+		return OPVCC(63, 26, 0, 1)
 	case AFSEL:
-		return int32(OPVCC(63, 23, 0, 0))
+		return OPVCC(63, 23, 0, 0)
 	case AFSELCC:
-		return int32(OPVCC(63, 23, 0, 1))
+		return OPVCC(63, 23, 0, 1)
 	case AFSQRT:
-		return int32(OPVCC(63, 22, 0, 0))
+		return OPVCC(63, 22, 0, 0)
 	case AFSQRTCC:
-		return int32(OPVCC(63, 22, 0, 1))
+		return OPVCC(63, 22, 0, 1)
 	case AFSQRTS:
-		return int32(OPVCC(59, 22, 0, 0))
+		return OPVCC(59, 22, 0, 0)
 	case AFSQRTSCC:
-		return int32(OPVCC(59, 22, 0, 1))
+		return OPVCC(59, 22, 0, 1)
 	case AFSUB:
-		return int32(OPVCC(63, 20, 0, 0))
+		return OPVCC(63, 20, 0, 0)
 	case AFSUBCC:
-		return int32(OPVCC(63, 20, 0, 1))
+		return OPVCC(63, 20, 0, 1)
 	case AFSUBS:
-		return int32(OPVCC(59, 20, 0, 0))
+		return OPVCC(59, 20, 0, 0)
 	case AFSUBSCC:
-		return int32(OPVCC(59, 20, 0, 1))
+		return OPVCC(59, 20, 0, 1)
 
 	case AICBI:
-		return int32(OPVCC(31, 982, 0, 0))
+		return OPVCC(31, 982, 0, 0)
 	case AISYNC:
-		return int32(OPVCC(19, 150, 0, 0))
+		return OPVCC(19, 150, 0, 0)
 
 	case AMTFSB0:
-		return int32(OPVCC(63, 70, 0, 0))
+		return OPVCC(63, 70, 0, 0)
 	case AMTFSB0CC:
-		return int32(OPVCC(63, 70, 0, 1))
+		return OPVCC(63, 70, 0, 1)
 	case AMTFSB1:
-		return int32(OPVCC(63, 38, 0, 0))
+		return OPVCC(63, 38, 0, 0)
 	case AMTFSB1CC:
-		return int32(OPVCC(63, 38, 0, 1))
+		return OPVCC(63, 38, 0, 1)
 
 	case AMULHW:
-		return int32(OPVCC(31, 75, 0, 0))
+		return OPVCC(31, 75, 0, 0)
 	case AMULHWCC:
-		return int32(OPVCC(31, 75, 0, 1))
+		return OPVCC(31, 75, 0, 1)
 	case AMULHWU:
-		return int32(OPVCC(31, 11, 0, 0))
+		return OPVCC(31, 11, 0, 0)
 	case AMULHWUCC:
-		return int32(OPVCC(31, 11, 0, 1))
+		return OPVCC(31, 11, 0, 1)
 	case AMULLW:
-		return int32(OPVCC(31, 235, 0, 0))
+		return OPVCC(31, 235, 0, 0)
 	case AMULLWCC:
-		return int32(OPVCC(31, 235, 0, 1))
+		return OPVCC(31, 235, 0, 1)
 	case AMULLWV:
-		return int32(OPVCC(31, 235, 1, 0))
+		return OPVCC(31, 235, 1, 0)
 	case AMULLWVCC:
-		return int32(OPVCC(31, 235, 1, 1))
+		return OPVCC(31, 235, 1, 1)
 
 	case AMULHD:
-		return int32(OPVCC(31, 73, 0, 0))
+		return OPVCC(31, 73, 0, 0)
 	case AMULHDCC:
-		return int32(OPVCC(31, 73, 0, 1))
+		return OPVCC(31, 73, 0, 1)
 	case AMULHDU:
-		return int32(OPVCC(31, 9, 0, 0))
+		return OPVCC(31, 9, 0, 0)
 	case AMULHDUCC:
-		return int32(OPVCC(31, 9, 0, 1))
+		return OPVCC(31, 9, 0, 1)
 	case AMULLD:
-		return int32(OPVCC(31, 233, 0, 0))
+		return OPVCC(31, 233, 0, 0)
 	case AMULLDCC:
-		return int32(OPVCC(31, 233, 0, 1))
+		return OPVCC(31, 233, 0, 1)
 	case AMULLDV:
-		return int32(OPVCC(31, 233, 1, 0))
+		return OPVCC(31, 233, 1, 0)
 	case AMULLDVCC:
-		return int32(OPVCC(31, 233, 1, 1))
+		return OPVCC(31, 233, 1, 1)
 
 	case ANAND:
-		return int32(OPVCC(31, 476, 0, 0))
+		return OPVCC(31, 476, 0, 0)
 	case ANANDCC:
-		return int32(OPVCC(31, 476, 0, 1))
+		return OPVCC(31, 476, 0, 1)
 	case ANEG:
-		return int32(OPVCC(31, 104, 0, 0))
+		return OPVCC(31, 104, 0, 0)
 	case ANEGCC:
-		return int32(OPVCC(31, 104, 0, 1))
+		return OPVCC(31, 104, 0, 1)
 	case ANEGV:
-		return int32(OPVCC(31, 104, 1, 0))
+		return OPVCC(31, 104, 1, 0)
 	case ANEGVCC:
-		return int32(OPVCC(31, 104, 1, 1))
+		return OPVCC(31, 104, 1, 1)
 	case ANOR:
-		return int32(OPVCC(31, 124, 0, 0))
+		return OPVCC(31, 124, 0, 0)
 	case ANORCC:
-		return int32(OPVCC(31, 124, 0, 1))
+		return OPVCC(31, 124, 0, 1)
 	case AOR:
-		return int32(OPVCC(31, 444, 0, 0))
+		return OPVCC(31, 444, 0, 0)
 	case AORCC:
-		return int32(OPVCC(31, 444, 0, 1))
+		return OPVCC(31, 444, 0, 1)
 	case AORN:
-		return int32(OPVCC(31, 412, 0, 0))
+		return OPVCC(31, 412, 0, 0)
 	case AORNCC:
-		return int32(OPVCC(31, 412, 0, 1))
+		return OPVCC(31, 412, 0, 1)
 
 	case ARFI:
-		return int32(OPVCC(19, 50, 0, 0))
+		return OPVCC(19, 50, 0, 0)
 	case ARFCI:
-		return int32(OPVCC(19, 51, 0, 0))
+		return OPVCC(19, 51, 0, 0)
 	case ARFID:
-		return int32(OPVCC(19, 18, 0, 0))
+		return OPVCC(19, 18, 0, 0)
 	case AHRFID:
-		return int32(OPVCC(19, 274, 0, 0))
+		return OPVCC(19, 274, 0, 0)
 
 	case ARLWMI:
-		return int32(OPVCC(20, 0, 0, 0))
+		return OPVCC(20, 0, 0, 0)
 	case ARLWMICC:
-		return int32(OPVCC(20, 0, 0, 1))
+		return OPVCC(20, 0, 0, 1)
 	case ARLWNM:
-		return int32(OPVCC(23, 0, 0, 0))
+		return OPVCC(23, 0, 0, 0)
 	case ARLWNMCC:
-		return int32(OPVCC(23, 0, 0, 1))
+		return OPVCC(23, 0, 0, 1)
 
 	case ARLDCL:
-		return int32(OPVCC(30, 8, 0, 0))
+		return OPVCC(30, 8, 0, 0)
 	case ARLDCR:
-		return int32(OPVCC(30, 9, 0, 0))
+		return OPVCC(30, 9, 0, 0)
 
 	case ASYSCALL:
-		return int32(OPVCC(17, 1, 0, 0))
+		return OPVCC(17, 1, 0, 0)
 
 	case ASLW:
-		return int32(OPVCC(31, 24, 0, 0))
+		return OPVCC(31, 24, 0, 0)
 	case ASLWCC:
-		return int32(OPVCC(31, 24, 0, 1))
+		return OPVCC(31, 24, 0, 1)
 	case ASLD:
-		return int32(OPVCC(31, 27, 0, 0))
+		return OPVCC(31, 27, 0, 0)
 	case ASLDCC:
-		return int32(OPVCC(31, 27, 0, 1))
+		return OPVCC(31, 27, 0, 1)
 
 	case ASRAW:
-		return int32(OPVCC(31, 792, 0, 0))
+		return OPVCC(31, 792, 0, 0)
 	case ASRAWCC:
-		return int32(OPVCC(31, 792, 0, 1))
+		return OPVCC(31, 792, 0, 1)
 	case ASRAD:
-		return int32(OPVCC(31, 794, 0, 0))
+		return OPVCC(31, 794, 0, 0)
 	case ASRADCC:
-		return int32(OPVCC(31, 794, 0, 1))
+		return OPVCC(31, 794, 0, 1)
 
 	case ASRW:
-		return int32(OPVCC(31, 536, 0, 0))
+		return OPVCC(31, 536, 0, 0)
 	case ASRWCC:
-		return int32(OPVCC(31, 536, 0, 1))
+		return OPVCC(31, 536, 0, 1)
 	case ASRD:
-		return int32(OPVCC(31, 539, 0, 0))
+		return OPVCC(31, 539, 0, 0)
 	case ASRDCC:
-		return int32(OPVCC(31, 539, 0, 1))
+		return OPVCC(31, 539, 0, 1)
 
 	case ASUB:
-		return int32(OPVCC(31, 40, 0, 0))
+		return OPVCC(31, 40, 0, 0)
 	case ASUBCC:
-		return int32(OPVCC(31, 40, 0, 1))
+		return OPVCC(31, 40, 0, 1)
 	case ASUBV:
-		return int32(OPVCC(31, 40, 1, 0))
+		return OPVCC(31, 40, 1, 0)
 	case ASUBVCC:
-		return int32(OPVCC(31, 40, 1, 1))
+		return OPVCC(31, 40, 1, 1)
 	case ASUBC:
-		return int32(OPVCC(31, 8, 0, 0))
+		return OPVCC(31, 8, 0, 0)
 	case ASUBCCC:
-		return int32(OPVCC(31, 8, 0, 1))
+		return OPVCC(31, 8, 0, 1)
 	case ASUBCV:
-		return int32(OPVCC(31, 8, 1, 0))
+		return OPVCC(31, 8, 1, 0)
 	case ASUBCVCC:
-		return int32(OPVCC(31, 8, 1, 1))
+		return OPVCC(31, 8, 1, 1)
 	case ASUBE:
-		return int32(OPVCC(31, 136, 0, 0))
+		return OPVCC(31, 136, 0, 0)
 	case ASUBECC:
-		return int32(OPVCC(31, 136, 0, 1))
+		return OPVCC(31, 136, 0, 1)
 	case ASUBEV:
-		return int32(OPVCC(31, 136, 1, 0))
+		return OPVCC(31, 136, 1, 0)
 	case ASUBEVCC:
-		return int32(OPVCC(31, 136, 1, 1))
+		return OPVCC(31, 136, 1, 1)
 	case ASUBME:
-		return int32(OPVCC(31, 232, 0, 0))
+		return OPVCC(31, 232, 0, 0)
 	case ASUBMECC:
-		return int32(OPVCC(31, 232, 0, 1))
+		return OPVCC(31, 232, 0, 1)
 	case ASUBMEV:
-		return int32(OPVCC(31, 232, 1, 0))
+		return OPVCC(31, 232, 1, 0)
 	case ASUBMEVCC:
-		return int32(OPVCC(31, 232, 1, 1))
+		return OPVCC(31, 232, 1, 1)
 	case ASUBZE:
-		return int32(OPVCC(31, 200, 0, 0))
+		return OPVCC(31, 200, 0, 0)
 	case ASUBZECC:
-		return int32(OPVCC(31, 200, 0, 1))
+		return OPVCC(31, 200, 0, 1)
 	case ASUBZEV:
-		return int32(OPVCC(31, 200, 1, 0))
+		return OPVCC(31, 200, 1, 0)
 	case ASUBZEVCC:
-		return int32(OPVCC(31, 200, 1, 1))
+		return OPVCC(31, 200, 1, 1)
 
 	case ASYNC:
-		return int32(OPVCC(31, 598, 0, 0))
+		return OPVCC(31, 598, 0, 0)
+	case ALWSYNC:
+		return OPVCC(31, 598, 0, 0) | 1<<21
+
 	case APTESYNC:
-		return int32(OPVCC(31, 598, 0, 0) | 2<<21)
+		return OPVCC(31, 598, 0, 0) | 2<<21
 
 	case ATLBIE:
-		return int32(OPVCC(31, 306, 0, 0))
+		return OPVCC(31, 306, 0, 0)
 	case ATLBIEL:
-		return int32(OPVCC(31, 274, 0, 0))
+		return OPVCC(31, 274, 0, 0)
 	case ATLBSYNC:
-		return int32(OPVCC(31, 566, 0, 0))
+		return OPVCC(31, 566, 0, 0)
 	case ASLBIA:
-		return int32(OPVCC(31, 498, 0, 0))
+		return OPVCC(31, 498, 0, 0)
 	case ASLBIE:
-		return int32(OPVCC(31, 434, 0, 0))
+		return OPVCC(31, 434, 0, 0)
 	case ASLBMFEE:
-		return int32(OPVCC(31, 915, 0, 0))
+		return OPVCC(31, 915, 0, 0)
 	case ASLBMFEV:
-		return int32(OPVCC(31, 851, 0, 0))
+		return OPVCC(31, 851, 0, 0)
 	case ASLBMTE:
-		return int32(OPVCC(31, 402, 0, 0))
+		return OPVCC(31, 402, 0, 0)
 
 	case ATW:
-		return int32(OPVCC(31, 4, 0, 0))
+		return OPVCC(31, 4, 0, 0)
 	case ATD:
-		return int32(OPVCC(31, 68, 0, 0))
+		return OPVCC(31, 68, 0, 0)
 
 	case AXOR:
-		return int32(OPVCC(31, 316, 0, 0))
+		return OPVCC(31, 316, 0, 0)
 	case AXORCC:
-		return int32(OPVCC(31, 316, 0, 1))
+		return 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 {
+func opirr(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AADD:
-		return int32(OPVCC(14, 0, 0, 0))
+		return OPVCC(14, 0, 0, 0)
 	case AADDC:
-		return int32(OPVCC(12, 0, 0, 0))
+		return 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 */
+		return OPVCC(13, 0, 0, 0)
+	case -AADD:
+		return 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. */
+		return OPVCC(28, 0, 0, 0)
+	case -AANDCC:
+		return OPVCC(29, 0, 0, 0) /* ANDIS./ANDIU. */
 
 	case ABR:
-		return int32(OPVCC(18, 0, 0, 0))
+		return OPVCC(18, 0, 0, 0)
 	case ABL:
-		return int32(OPVCC(18, 0, 0, 0) | 1)
+		return OPVCC(18, 0, 0, 0) | 1
 	case obj.ADUFFZERO:
-		return int32(OPVCC(18, 0, 0, 0) | 1)
+		return OPVCC(18, 0, 0, 0) | 1
 	case obj.ADUFFCOPY:
-		return int32(OPVCC(18, 0, 0, 0) | 1)
+		return OPVCC(18, 0, 0, 0) | 1
 	case ABC:
-		return int32(OPVCC(16, 0, 0, 0))
+		return OPVCC(16, 0, 0, 0)
 	case ABCL:
-		return int32(OPVCC(16, 0, 0, 0) | 1)
+		return OPVCC(16, 0, 0, 0) | 1
 
 	case ABEQ:
-		return int32(AOP_RRR(16<<26, 12, 2, 0))
+		return AOP_RRR(16<<26, 12, 2, 0)
 	case ABGE:
-		return int32(AOP_RRR(16<<26, 4, 0, 0))
+		return AOP_RRR(16<<26, 4, 0, 0)
 	case ABGT:
-		return int32(AOP_RRR(16<<26, 12, 1, 0))
+		return AOP_RRR(16<<26, 12, 1, 0)
 	case ABLE:
-		return int32(AOP_RRR(16<<26, 4, 1, 0))
+		return AOP_RRR(16<<26, 4, 1, 0)
 	case ABLT:
-		return int32(AOP_RRR(16<<26, 12, 0, 0))
+		return AOP_RRR(16<<26, 12, 0, 0)
 	case ABNE:
-		return int32(AOP_RRR(16<<26, 4, 2, 0))
+		return AOP_RRR(16<<26, 4, 2, 0)
 	case ABVC:
-		return int32(AOP_RRR(16<<26, 4, 3, 0))
+		return AOP_RRR(16<<26, 4, 3, 0)
 	case ABVS:
-		return int32(AOP_RRR(16<<26, 12, 3, 0))
+		return AOP_RRR(16<<26, 12, 3, 0)
 
 	case ACMP:
-		return int32(OPVCC(11, 0, 0, 0) | 1<<21) /* L=1 */
+		return OPVCC(11, 0, 0, 0) | 1<<21 /* L=1 */
 	case ACMPU:
-		return int32(OPVCC(10, 0, 0, 0) | 1<<21)
+		return OPVCC(10, 0, 0, 0) | 1<<21
 	case ACMPW:
-		return int32(OPVCC(11, 0, 0, 0)) /* L=0 */
+		return OPVCC(11, 0, 0, 0) /* L=0 */
 	case ACMPWU:
-		return int32(OPVCC(10, 0, 0, 0))
+		return OPVCC(10, 0, 0, 0)
 	case ALSW:
-		return int32(OPVCC(31, 597, 0, 0))
+		return OPVCC(31, 597, 0, 0)
 
 	case AMULLW:
-		return int32(OPVCC(7, 0, 0, 0))
+		return 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 */
+		return OPVCC(24, 0, 0, 0)
+	case -AOR:
+		return OPVCC(25, 0, 0, 0) /* ORIS/ORIU */
 
 	case ARLWMI:
-		return int32(OPVCC(20, 0, 0, 0)) /* rlwimi */
+		return OPVCC(20, 0, 0, 0) /* rlwimi */
 	case ARLWMICC:
-		return int32(OPVCC(20, 0, 0, 1))
+		return OPVCC(20, 0, 0, 1)
 	case ARLDMI:
-		return int32(OPVCC(30, 0, 0, 0) | 3<<2) /* rldimi */
+		return OPVCC(30, 0, 0, 0) | 3<<2 /* rldimi */
 	case ARLDMICC:
-		return int32(OPVCC(30, 0, 0, 1) | 3<<2)
+		return OPVCC(30, 0, 0, 1) | 3<<2
 
 	case ARLWNM:
-		return int32(OPVCC(21, 0, 0, 0)) /* rlwinm */
+		return OPVCC(21, 0, 0, 0) /* rlwinm */
 	case ARLWNMCC:
-		return int32(OPVCC(21, 0, 0, 1))
+		return OPVCC(21, 0, 0, 1)
 
 	case ARLDCL:
-		return int32(OPVCC(30, 0, 0, 0)) /* rldicl */
+		return OPVCC(30, 0, 0, 0) /* rldicl */
 	case ARLDCLCC:
-		return int32(OPVCC(30, 0, 0, 1))
+		return OPVCC(30, 0, 0, 1)
 	case ARLDCR:
-		return int32(OPVCC(30, 1, 0, 0)) /* rldicr */
+		return OPVCC(30, 1, 0, 0) /* rldicr */
 	case ARLDCRCC:
-		return int32(OPVCC(30, 1, 0, 1))
+		return OPVCC(30, 1, 0, 1)
 	case ARLDC:
-		return int32(OPVCC(30, 0, 0, 0) | 2<<2)
+		return OPVCC(30, 0, 0, 0) | 2<<2
 	case ARLDCCC:
-		return int32(OPVCC(30, 0, 0, 1) | 2<<2)
+		return OPVCC(30, 0, 0, 1) | 2<<2
 
 	case ASRAW:
-		return int32(OPVCC(31, 824, 0, 0))
+		return OPVCC(31, 824, 0, 0)
 	case ASRAWCC:
-		return int32(OPVCC(31, 824, 0, 1))
+		return OPVCC(31, 824, 0, 1)
 	case ASRAD:
-		return int32(OPVCC(31, (413 << 1), 0, 0))
+		return OPVCC(31, (413 << 1), 0, 0)
 	case ASRADCC:
-		return int32(OPVCC(31, (413 << 1), 0, 1))
+		return OPVCC(31, (413 << 1), 0, 1)
 
 	case ASTSW:
-		return int32(OPVCC(31, 725, 0, 0))
+		return OPVCC(31, 725, 0, 0)
 
 	case ASUBC:
-		return int32(OPVCC(8, 0, 0, 0))
+		return OPVCC(8, 0, 0, 0)
 
 	case ATW:
-		return int32(OPVCC(3, 0, 0, 0))
+		return OPVCC(3, 0, 0, 0)
 	case ATD:
-		return int32(OPVCC(2, 0, 0, 0))
+		return 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 */
+		return OPVCC(26, 0, 0, 0) /* XORIL */
+	case -AXOR:
+		return OPVCC(27, 0, 0, 0) /* XORIU */
 	}
 
 	ctxt.Diag("bad opcode i/r %v", obj.Aconv(a))
@@ -3171,44 +3167,44 @@ func opirr(ctxt *obj.Link, a int) int32 {
 /*
  * load o(a),d
  */
-func opload(ctxt *obj.Link, a int) int32 {
+func opload(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AMOVD:
-		return int32(OPVCC(58, 0, 0, 0)) /* ld */
+		return OPVCC(58, 0, 0, 0) /* ld */
 	case AMOVDU:
-		return int32(OPVCC(58, 0, 0, 1)) /* ldu */
+		return OPVCC(58, 0, 0, 1) /* ldu */
 	case AMOVWZ:
-		return int32(OPVCC(32, 0, 0, 0)) /* lwz */
+		return OPVCC(32, 0, 0, 0) /* lwz */
 	case AMOVWZU:
-		return int32(OPVCC(33, 0, 0, 0)) /* lwzu */
+		return OPVCC(33, 0, 0, 0) /* lwzu */
 	case AMOVW:
-		return int32(OPVCC(58, 0, 0, 0) | 1<<1) /* lwa */
+		return OPVCC(58, 0, 0, 0) | 1<<1 /* lwa */
 
 		/* no AMOVWU */
 	case AMOVB, AMOVBZ:
-		return int32(OPVCC(34, 0, 0, 0))
+		return OPVCC(34, 0, 0, 0)
 		/* load */
 
 	case AMOVBU, AMOVBZU:
-		return int32(OPVCC(35, 0, 0, 0))
+		return OPVCC(35, 0, 0, 0)
 	case AFMOVD:
-		return int32(OPVCC(50, 0, 0, 0))
+		return OPVCC(50, 0, 0, 0)
 	case AFMOVDU:
-		return int32(OPVCC(51, 0, 0, 0))
+		return OPVCC(51, 0, 0, 0)
 	case AFMOVS:
-		return int32(OPVCC(48, 0, 0, 0))
+		return OPVCC(48, 0, 0, 0)
 	case AFMOVSU:
-		return int32(OPVCC(49, 0, 0, 0))
+		return OPVCC(49, 0, 0, 0)
 	case AMOVH:
-		return int32(OPVCC(42, 0, 0, 0))
+		return OPVCC(42, 0, 0, 0)
 	case AMOVHU:
-		return int32(OPVCC(43, 0, 0, 0))
+		return OPVCC(43, 0, 0, 0)
 	case AMOVHZ:
-		return int32(OPVCC(40, 0, 0, 0))
+		return OPVCC(40, 0, 0, 0)
 	case AMOVHZU:
-		return int32(OPVCC(41, 0, 0, 0))
+		return OPVCC(41, 0, 0, 0)
 	case AMOVMW:
-		return int32(OPVCC(46, 0, 0, 0)) /* lmw */
+		return OPVCC(46, 0, 0, 0) /* lmw */
 	}
 
 	ctxt.Diag("bad load opcode %v", obj.Aconv(a))
@@ -3218,54 +3214,56 @@ func opload(ctxt *obj.Link, a int) int32 {
 /*
  * indexed load a(b),d
  */
-func oploadx(ctxt *obj.Link, a int) int32 {
+func oploadx(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AMOVWZ:
-		return int32(OPVCC(31, 23, 0, 0)) /* lwzx */
+		return OPVCC(31, 23, 0, 0) /* lwzx */
 	case AMOVWZU:
-		return int32(OPVCC(31, 55, 0, 0)) /* lwzux */
+		return OPVCC(31, 55, 0, 0) /* lwzux */
 	case AMOVW:
-		return int32(OPVCC(31, 341, 0, 0)) /* lwax */
+		return OPVCC(31, 341, 0, 0) /* lwax */
 	case AMOVWU:
-		return int32(OPVCC(31, 373, 0, 0)) /* lwaux */
+		return OPVCC(31, 373, 0, 0) /* lwaux */
 
 	case AMOVB, AMOVBZ:
-		return int32(OPVCC(31, 87, 0, 0)) /* lbzx */
+		return OPVCC(31, 87, 0, 0) /* lbzx */
 
 	case AMOVBU, AMOVBZU:
-		return int32(OPVCC(31, 119, 0, 0)) /* lbzux */
+		return OPVCC(31, 119, 0, 0) /* lbzux */
 	case AFMOVD:
-		return int32(OPVCC(31, 599, 0, 0)) /* lfdx */
+		return OPVCC(31, 599, 0, 0) /* lfdx */
 	case AFMOVDU:
-		return int32(OPVCC(31, 631, 0, 0)) /*  lfdux */
+		return OPVCC(31, 631, 0, 0) /*  lfdux */
 	case AFMOVS:
-		return int32(OPVCC(31, 535, 0, 0)) /* lfsx */
+		return OPVCC(31, 535, 0, 0) /* lfsx */
 	case AFMOVSU:
-		return int32(OPVCC(31, 567, 0, 0)) /* lfsux */
+		return OPVCC(31, 567, 0, 0) /* lfsux */
 	case AMOVH:
-		return int32(OPVCC(31, 343, 0, 0)) /* lhax */
+		return OPVCC(31, 343, 0, 0) /* lhax */
 	case AMOVHU:
-		return int32(OPVCC(31, 375, 0, 0)) /* lhaux */
+		return OPVCC(31, 375, 0, 0) /* lhaux */
 	case AMOVHBR:
-		return int32(OPVCC(31, 790, 0, 0)) /* lhbrx */
+		return OPVCC(31, 790, 0, 0) /* lhbrx */
 	case AMOVWBR:
-		return int32(OPVCC(31, 534, 0, 0)) /* lwbrx */
+		return OPVCC(31, 534, 0, 0) /* lwbrx */
 	case AMOVHZ:
-		return int32(OPVCC(31, 279, 0, 0)) /* lhzx */
+		return OPVCC(31, 279, 0, 0) /* lhzx */
 	case AMOVHZU:
-		return int32(OPVCC(31, 311, 0, 0)) /* lhzux */
+		return OPVCC(31, 311, 0, 0) /* lhzux */
 	case AECIWX:
-		return int32(OPVCC(31, 310, 0, 0)) /* eciwx */
+		return OPVCC(31, 310, 0, 0) /* eciwx */
+	case ALBAR:
+		return OPVCC(31, 52, 0, 0) /* lbarx */
 	case ALWAR:
-		return int32(OPVCC(31, 20, 0, 0)) /* lwarx */
+		return OPVCC(31, 20, 0, 0) /* lwarx */
 	case ALDAR:
-		return int32(OPVCC(31, 84, 0, 0))
+		return OPVCC(31, 84, 0, 0)
 	case ALSW:
-		return int32(OPVCC(31, 533, 0, 0)) /* lswx */
+		return OPVCC(31, 533, 0, 0) /* lswx */
 	case AMOVD:
-		return int32(OPVCC(31, 21, 0, 0)) /* ldx */
+		return OPVCC(31, 21, 0, 0) /* ldx */
 	case AMOVDU:
-		return int32(OPVCC(31, 53, 0, 0)) /* ldux */
+		return OPVCC(31, 53, 0, 0) /* ldux */
 	}
 
 	ctxt.Diag("bad loadx opcode %v", obj.Aconv(a))
@@ -3275,41 +3273,41 @@ func oploadx(ctxt *obj.Link, a int) int32 {
 /*
  * store s,o(d)
  */
-func opstore(ctxt *obj.Link, a int) int32 {
+func opstore(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AMOVB, AMOVBZ:
-		return int32(OPVCC(38, 0, 0, 0)) /* stb */
+		return OPVCC(38, 0, 0, 0) /* stb */
 
 	case AMOVBU, AMOVBZU:
-		return int32(OPVCC(39, 0, 0, 0)) /* stbu */
+		return OPVCC(39, 0, 0, 0) /* stbu */
 	case AFMOVD:
-		return int32(OPVCC(54, 0, 0, 0)) /* stfd */
+		return OPVCC(54, 0, 0, 0) /* stfd */
 	case AFMOVDU:
-		return int32(OPVCC(55, 0, 0, 0)) /* stfdu */
+		return OPVCC(55, 0, 0, 0) /* stfdu */
 	case AFMOVS:
-		return int32(OPVCC(52, 0, 0, 0)) /* stfs */
+		return OPVCC(52, 0, 0, 0) /* stfs */
 	case AFMOVSU:
-		return int32(OPVCC(53, 0, 0, 0)) /* stfsu */
+		return OPVCC(53, 0, 0, 0) /* stfsu */
 
 	case AMOVHZ, AMOVH:
-		return int32(OPVCC(44, 0, 0, 0)) /* sth */
+		return OPVCC(44, 0, 0, 0) /* sth */
 
 	case AMOVHZU, AMOVHU:
-		return int32(OPVCC(45, 0, 0, 0)) /* sthu */
+		return OPVCC(45, 0, 0, 0) /* sthu */
 	case AMOVMW:
-		return int32(OPVCC(47, 0, 0, 0)) /* stmw */
+		return OPVCC(47, 0, 0, 0) /* stmw */
 	case ASTSW:
-		return int32(OPVCC(31, 725, 0, 0)) /* stswi */
+		return OPVCC(31, 725, 0, 0) /* stswi */
 
 	case AMOVWZ, AMOVW:
-		return int32(OPVCC(36, 0, 0, 0)) /* stw */
+		return OPVCC(36, 0, 0, 0) /* stw */
 
 	case AMOVWZU, AMOVWU:
-		return int32(OPVCC(37, 0, 0, 0)) /* stwu */
+		return OPVCC(37, 0, 0, 0) /* stwu */
 	case AMOVD:
-		return int32(OPVCC(62, 0, 0, 0)) /* std */
+		return OPVCC(62, 0, 0, 0) /* std */
 	case AMOVDU:
-		return int32(OPVCC(62, 0, 0, 1)) /* stdu */
+		return OPVCC(62, 0, 0, 1) /* stdu */
 	}
 
 	ctxt.Diag("unknown store opcode %v", obj.Aconv(a))
@@ -3319,49 +3317,51 @@ func opstore(ctxt *obj.Link, a int) int32 {
 /*
  * indexed store s,a(b)
  */
-func opstorex(ctxt *obj.Link, a int) int32 {
+func opstorex(ctxt *obj.Link, a obj.As) uint32 {
 	switch a {
 	case AMOVB, AMOVBZ:
-		return int32(OPVCC(31, 215, 0, 0)) /* stbx */
+		return OPVCC(31, 215, 0, 0) /* stbx */
 
 	case AMOVBU, AMOVBZU:
-		return int32(OPVCC(31, 247, 0, 0)) /* stbux */
+		return OPVCC(31, 247, 0, 0) /* stbux */
 	case AFMOVD:
-		return int32(OPVCC(31, 727, 0, 0)) /* stfdx */
+		return OPVCC(31, 727, 0, 0) /* stfdx */
 	case AFMOVDU:
-		return int32(OPVCC(31, 759, 0, 0)) /* stfdux */
+		return OPVCC(31, 759, 0, 0) /* stfdux */
 	case AFMOVS:
-		return int32(OPVCC(31, 663, 0, 0)) /* stfsx */
+		return OPVCC(31, 663, 0, 0) /* stfsx */
 	case AFMOVSU:
-		return int32(OPVCC(31, 695, 0, 0)) /* stfsux */
+		return OPVCC(31, 695, 0, 0) /* stfsux */
 
 	case AMOVHZ, AMOVH:
-		return int32(OPVCC(31, 407, 0, 0)) /* sthx */
+		return OPVCC(31, 407, 0, 0) /* sthx */
 	case AMOVHBR:
-		return int32(OPVCC(31, 918, 0, 0)) /* sthbrx */
+		return OPVCC(31, 918, 0, 0) /* sthbrx */
 
 	case AMOVHZU, AMOVHU:
-		return int32(OPVCC(31, 439, 0, 0)) /* sthux */
+		return OPVCC(31, 439, 0, 0) /* sthux */
 
 	case AMOVWZ, AMOVW:
-		return int32(OPVCC(31, 151, 0, 0)) /* stwx */
+		return OPVCC(31, 151, 0, 0) /* stwx */
 
 	case AMOVWZU, AMOVWU:
-		return int32(OPVCC(31, 183, 0, 0)) /* stwux */
+		return OPVCC(31, 183, 0, 0) /* stwux */
 	case ASTSW:
-		return int32(OPVCC(31, 661, 0, 0)) /* stswx */
+		return OPVCC(31, 661, 0, 0) /* stswx */
 	case AMOVWBR:
-		return int32(OPVCC(31, 662, 0, 0)) /* stwbrx */
+		return OPVCC(31, 662, 0, 0) /* stwbrx */
+	case ASTBCCC:
+		return OPVCC(31, 694, 0, 1) /* stbcx. */
 	case ASTWCCC:
-		return int32(OPVCC(31, 150, 0, 1)) /* stwcx. */
+		return OPVCC(31, 150, 0, 1) /* stwcx. */
 	case ASTDCCC:
-		return int32(OPVCC(31, 214, 0, 1)) /* stwdx. */
+		return OPVCC(31, 214, 0, 1) /* stwdx. */
 	case AECOWX:
-		return int32(OPVCC(31, 438, 0, 0)) /* ecowx */
+		return OPVCC(31, 438, 0, 0) /* ecowx */
 	case AMOVD:
-		return int32(OPVCC(31, 149, 0, 0)) /* stdx */
+		return OPVCC(31, 149, 0, 0) /* stdx */
 	case AMOVDU:
-		return int32(OPVCC(31, 181, 0, 0)) /* stdux */
+		return OPVCC(31, 181, 0, 0) /* stdux */
 	}
 
 	ctxt.Diag("unknown storex opcode %v", obj.Aconv(a))
diff --git a/src/cmd/internal/obj/ppc64/list9.go b/src/cmd/internal/obj/ppc64/list9.go
index 4cdcfbc..d46297a 100644
--- a/src/cmd/internal/obj/ppc64/list9.go
+++ b/src/cmd/internal/obj/ppc64/list9.go
@@ -7,7 +7,7 @@
 //	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.
+//	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
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index 11be4d7..5f88307 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -7,7 +7,7 @@
 //	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.
+//	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
@@ -31,7 +31,7 @@ package ppc64
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"math"
 )
@@ -301,6 +301,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 		case ALWAR,
+			ALBAR,
+			ASTBCCC,
 			ASTWCCC,
 			AECIWX,
 			AECOWX,
@@ -323,6 +325,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			ASYNC,
 			ATLBSYNC,
 			APTESYNC,
+			ALWSYNC,
 			ATW,
 			AWORD,
 			ARFI,
@@ -444,12 +447,11 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 	autosize := int32(0)
 	var aoffset int
-	var mov int
-	var o int
+	var mov obj.As
 	var p1 *obj.Prog
 	var p2 *obj.Prog
 	for p := cursym.Text; p != nil; p = p.Link {
-		o = int(p.As)
+		o := p.As
 		switch o {
 		case obj.ATEXT:
 			mov = AMOVD
@@ -471,7 +473,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 
 			q = p
 
-			if ctxt.Flag_shared != 0 && cursym.Name != "runtime.duffzero" && cursym.Name != "runtime.duffcopy" && cursym.Name != "runtime.stackBarrier" {
+			if ctxt.Flag_shared && cursym.Name != "runtime.duffzero" && cursym.Name != "runtime.duffcopy" && cursym.Name != "runtime.stackBarrier" {
 				// When compiling Go into PIC, all functions must start
 				// with instructions to load the TOC pointer into r2:
 				//
@@ -535,7 +537,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			}
 
 			if cursym.Text.Mark&LEAF != 0 {
-				cursym.Leaf = 1
+				cursym.Leaf = true
 				break
 			}
 
@@ -548,7 +550,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 			q.To.Reg = REGTMP
 
 			q = obj.Appendp(ctxt, q)
-			q.As = int16(mov)
+			q.As = mov
 			q.Lineno = p.Lineno
 			q.From.Type = obj.TYPE_REG
 			q.From.Reg = REGTMP
@@ -559,7 +561,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.Spadj = int32(-aoffset)
 			}
 
-			if ctxt.Flag_shared != 0 {
+			if ctxt.Flag_shared {
 				q = obj.Appendp(ctxt, q)
 				q.As = AMOVD
 				q.Lineno = p.Lineno
@@ -593,7 +595,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REGG
-				q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R3
 
@@ -828,9 +830,9 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	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.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
+	if ctxt.Cursym.Cfunc {
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R3
@@ -944,7 +946,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	var morestacksym *obj.LSym
-	if ctxt.Cursym.Cfunc != 0 {
+	if ctxt.Cursym.Cfunc {
 		morestacksym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
 	} else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
 		morestacksym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
@@ -953,7 +955,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
 	}
 
 	if ctxt.Flag_dynlink {
-		// Avoid calling morestack via a PLT when dynamically linking.  The
+		// Avoid calling morestack via a PLT when dynamically linking. The
 		// PLT stubs generated by the system linker on ppc64le when "std r2,
 		// 24(r1)" to save the TOC pointer in their callers stack
 		// frame. Unfortunately (and necessarily) morestack is called before
@@ -1025,7 +1027,7 @@ func follow(ctxt *obj.Link, s *obj.LSym) {
 	s.Text = firstp.Link
 }
 
-func relinv(a int) int {
+func relinv(a obj.As) obj.As {
 	switch a {
 	case ABEQ:
 		return ABNE
@@ -1054,15 +1056,14 @@ func relinv(a int) int {
 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 b obj.As
 	var i int
 
 loop:
 	if p == nil {
 		return
 	}
-	a = int(p.As)
+	a := p.As
 	if a == ABR {
 		q = p.Pcond
 		if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) {
@@ -1095,7 +1096,7 @@ loop:
 				break
 			}
 			b = 0 /* set */
-			a = int(q.As)
+			a = q.As
 			if a == obj.ANOP {
 				i--
 				continue
@@ -1117,7 +1118,7 @@ loop:
 				r = ctxt.NewProg()
 				*r = *p
 				if r.Mark&FOLL == 0 {
-					fmt.Printf("cant happen 1\n")
+					fmt.Printf("can't happen 1\n")
 				}
 				r.Mark |= FOLL
 				if p != q {
@@ -1132,14 +1133,14 @@ loop:
 				if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
 					return
 				}
-				r.As = int16(b)
+				r.As = 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")
+					fmt.Printf("can't happen 2\n")
 				}
 				return
 			}
@@ -1147,7 +1148,7 @@ loop:
 
 		a = ABR
 		q = ctxt.NewProg()
-		q.As = int16(a)
+		q.As = a
 		q.Lineno = p.Lineno
 		q.To.Type = obj.TYPE_BRANCH
 		q.To.Offset = p.Pc
@@ -1183,27 +1184,17 @@ loop:
 }
 
 var Linkppc64 = obj.LinkArch{
-	ByteOrder:  binary.BigEndian,
-	Name:       "ppc64",
-	Thechar:    '9',
+	Arch:       sys.ArchPPC64,
 	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',
+	Arch:       sys.ArchPPC64LE,
 	Preprocess: preprocess,
 	Assemble:   span9,
 	Follow:     follow,
 	Progedit:   progedit,
-	Minlc:      4,
-	Ptrsize:    8,
-	Regsize:    8,
 }
diff --git a/src/cmd/internal/obj/s390x/a.out.go b/src/cmd/internal/obj/s390x/a.out.go
new file mode 100644
index 0000000..490695c
--- /dev/null
+++ b/src/cmd/internal/obj/s390x/a.out.go
@@ -0,0 +1,896 @@
+// Based on cmd/internal/obj/ppc64/a.out.go.
+//
+//	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 s390x
+
+import "cmd/internal/obj"
+
+//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p s390x
+
+const (
+	NSNAME = 8
+	NSYM   = 50
+	NREG   = 16 // number of general purpose registers
+	NFREG  = 16 // number of floating point registers
+)
+
+const (
+	// General purpose registers (GPRs).
+	REG_R0 = obj.RBaseS390X + 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
+
+	// Floating point registers (FPRs).
+	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
+
+	// Vector registers (VRs) - only available when the vector
+	// facility is installed.
+	// V0-V15 are aliases for F0-F15.
+	// We keep them in a separate space to make printing etc. easier
+	// If the code generator ever emits vector instructions it will
+	// need to take into account the aliasing.
+	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
+
+	// Access registers (ARs).
+	// The thread pointer is typically stored in the register pair
+	// AR0 and AR1.
+	REG_AR0
+	REG_AR1
+	REG_AR2
+	REG_AR3
+	REG_AR4
+	REG_AR5
+	REG_AR6
+	REG_AR7
+	REG_AR8
+	REG_AR9
+	REG_AR10
+	REG_AR11
+	REG_AR12
+	REG_AR13
+	REG_AR14
+	REG_AR15
+
+	REG_RESERVED // end of allocated registers
+
+	REGZERO = REG_R0  // set to zero
+	REGARG  = -1      // -1 disables passing the first argument in register
+	REGRT1  = REG_R3  // used during zeroing of the stack - not reserved
+	REGRT2  = REG_R4  // used during zeroing of the stack - not reserved
+	REGTMP  = REG_R10 // scratch register used in the assembler and linker
+	REGTMP2 = REG_R11 // scratch register used in the assembler and linker
+	REGCTXT = REG_R12 // context for closures
+	REGG    = REG_R13 // G
+	REG_LR  = REG_R14 // link register
+	REGSP   = REG_R15 // stack pointer
+)
+
+const (
+	BIG    = 32768 - 8
+	DISP12 = 4096
+	DISP16 = 65536
+	DISP20 = 1048576
+)
+
+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 ( // comments from func aclass in asmz.go
+	C_NONE     = iota
+	C_REG      // general-purpose register (64-bit)
+	C_FREG     // floating-point register (64-bit)
+	C_VREG     // vector register (128-bit)
+	C_AREG     // access register (32-bit)
+	C_ZCON     // constant == 0
+	C_SCON     // 0 <= constant <= 0x7fff (positive int16)
+	C_UCON     // constant & 0xffff == 0 (int16 or uint16)
+	C_ADDCON   // 0 > constant >= -0x8000 (negative int16)
+	C_ANDCON   // constant <= 0xffff
+	C_LCON     // constant (int32 or uint32)
+	C_DCON     // constant (int64 or uint64)
+	C_SACON    // computed address, 16-bit displacement, possibly SP-relative
+	C_LACON    // computed address, 32-bit displacement, possibly SP-relative
+	C_DACON    // computed address, 64-bit displacment?
+	C_SBRA     // short branch
+	C_LBRA     // long branch
+	C_SAUTO    // short auto
+	C_LAUTO    // long auto
+	C_ZOREG    // heap address, register-based, displacement == 0
+	C_SOREG    // heap address, register-based, int16 displacement
+	C_LOREG    // heap address, register-based, int32 displacement
+	C_TLS_LE   // TLS - local exec model (for executables)
+	C_TLS_IE   // TLS - initial exec model (for shared libraries loaded at program startup)
+	C_GOK      // general address
+	C_ADDR     // relocation for extern or static symbols (loads and stores)
+	C_SYMADDR  // relocation for extern or static symbols (address taking)
+	C_GOTADDR  // GOT slot for a symbol in -dynlink mode
+	C_TEXTSIZE // text size
+	C_ANY
+	C_NCLASS // must be the last
+)
+
+const (
+	// integer arithmetic
+	AADD = obj.ABaseS390X + obj.A_ARCHSPECIFIC + iota
+	AADDC
+	AADDME
+	AADDE
+	AADDZE
+	ADIVW
+	ADIVWU
+	ADIVD
+	ADIVDU
+	AMULLW
+	AMULLD
+	AMULHD
+	AMULHDU
+	ASUB
+	ASUBC
+	ASUBME
+	ASUBV
+	ASUBE
+	ASUBZE
+	ANEG
+
+	// integer moves
+	AMOVWBR
+	AMOVB
+	AMOVBZ
+	AMOVH
+	AMOVHBR
+	AMOVHZ
+	AMOVW
+	AMOVWZ
+	AMOVD
+	AMOVDBR
+
+	// integer bitwise
+	AAND
+	AANDN
+	ANAND
+	ANOR
+	AOR
+	AORN
+	AXOR
+	ASLW
+	ASLD
+	ASRW
+	ASRAW
+	ASRD
+	ASRAD
+	ARLL
+	ARLLG
+
+	// floating point
+	AFABS
+	AFADD
+	AFADDS
+	AFCMPO
+	AFCMPU
+	ACEBR
+	AFDIV
+	AFDIVS
+	AFMADD
+	AFMADDS
+	AFMOVD
+	AFMOVS
+	AFMSUB
+	AFMSUBS
+	AFMUL
+	AFMULS
+	AFNABS
+	AFNEG
+	AFNMADD
+	AFNMADDS
+	AFNMSUB
+	AFNMSUBS
+	ALEDBR
+	ALDEBR
+	AFSUB
+	AFSUBS
+	AFSQRT
+	AFSQRTS
+
+	// convert from int32/int64 to float/float64
+	ACEFBRA
+	ACDFBRA
+	ACEGBRA
+	ACDGBRA
+
+	// convert from float/float64 to int32/int64
+	ACFEBRA
+	ACFDBRA
+	ACGEBRA
+	ACGDBRA
+
+	// convert from uint32/uint64 to float/float64
+	ACELFBR
+	ACDLFBR
+	ACELGBR
+	ACDLGBR
+
+	// convert from float/float64 to uint32/uint64
+	ACLFEBR
+	ACLFDBR
+	ACLGEBR
+	ACLGDBR
+
+	// compare
+	ACMP
+	ACMPU
+	ACMPW
+	ACMPWU
+
+	// compare and swap
+	ACS
+	ACSG
+
+	// serialize
+	ASYNC
+
+	// branch
+	ABC
+	ABCL
+	ABEQ
+	ABGE
+	ABGT
+	ABLE
+	ABLT
+	ABNE
+	ABVC
+	ABVS
+	ASYSCALL
+
+	// compare and branch
+	ACMPBEQ
+	ACMPBGE
+	ACMPBGT
+	ACMPBLE
+	ACMPBLT
+	ACMPBNE
+	ACMPUBEQ
+	ACMPUBGE
+	ACMPUBGT
+	ACMPUBLE
+	ACMPUBLT
+	ACMPUBNE
+
+	// storage-and-storage
+	AMVC
+	ACLC
+	AXC
+	AOC
+	ANC
+
+	// load
+	AEXRL
+	ALARL
+	ALA
+	ALAY
+
+	// load/store multiple
+	ALMY
+	ALMG
+	ASTMY
+	ASTMG
+
+	// store clock
+	ASTCK
+	ASTCKC
+	ASTCKE
+	ASTCKF
+
+	// macros
+	ACLEAR
+
+	// vector
+	AVA
+	AVAB
+	AVAH
+	AVAF
+	AVAG
+	AVAQ
+	AVACC
+	AVACCB
+	AVACCH
+	AVACCF
+	AVACCG
+	AVACCQ
+	AVAC
+	AVACQ
+	AVACCC
+	AVACCCQ
+	AVN
+	AVNC
+	AVAVG
+	AVAVGB
+	AVAVGH
+	AVAVGF
+	AVAVGG
+	AVAVGL
+	AVAVGLB
+	AVAVGLH
+	AVAVGLF
+	AVAVGLG
+	AVCKSM
+	AVCEQ
+	AVCEQB
+	AVCEQH
+	AVCEQF
+	AVCEQG
+	AVCEQBS
+	AVCEQHS
+	AVCEQFS
+	AVCEQGS
+	AVCH
+	AVCHB
+	AVCHH
+	AVCHF
+	AVCHG
+	AVCHBS
+	AVCHHS
+	AVCHFS
+	AVCHGS
+	AVCHL
+	AVCHLB
+	AVCHLH
+	AVCHLF
+	AVCHLG
+	AVCHLBS
+	AVCHLHS
+	AVCHLFS
+	AVCHLGS
+	AVCLZ
+	AVCLZB
+	AVCLZH
+	AVCLZF
+	AVCLZG
+	AVCTZ
+	AVCTZB
+	AVCTZH
+	AVCTZF
+	AVCTZG
+	AVEC
+	AVECB
+	AVECH
+	AVECF
+	AVECG
+	AVECL
+	AVECLB
+	AVECLH
+	AVECLF
+	AVECLG
+	AVERIM
+	AVERIMB
+	AVERIMH
+	AVERIMF
+	AVERIMG
+	AVERLL
+	AVERLLB
+	AVERLLH
+	AVERLLF
+	AVERLLG
+	AVERLLV
+	AVERLLVB
+	AVERLLVH
+	AVERLLVF
+	AVERLLVG
+	AVESLV
+	AVESLVB
+	AVESLVH
+	AVESLVF
+	AVESLVG
+	AVESL
+	AVESLB
+	AVESLH
+	AVESLF
+	AVESLG
+	AVESRA
+	AVESRAB
+	AVESRAH
+	AVESRAF
+	AVESRAG
+	AVESRAV
+	AVESRAVB
+	AVESRAVH
+	AVESRAVF
+	AVESRAVG
+	AVESRL
+	AVESRLB
+	AVESRLH
+	AVESRLF
+	AVESRLG
+	AVESRLV
+	AVESRLVB
+	AVESRLVH
+	AVESRLVF
+	AVESRLVG
+	AVX
+	AVFAE
+	AVFAEB
+	AVFAEH
+	AVFAEF
+	AVFAEBS
+	AVFAEHS
+	AVFAEFS
+	AVFAEZB
+	AVFAEZH
+	AVFAEZF
+	AVFAEZBS
+	AVFAEZHS
+	AVFAEZFS
+	AVFEE
+	AVFEEB
+	AVFEEH
+	AVFEEF
+	AVFEEBS
+	AVFEEHS
+	AVFEEFS
+	AVFEEZB
+	AVFEEZH
+	AVFEEZF
+	AVFEEZBS
+	AVFEEZHS
+	AVFEEZFS
+	AVFENE
+	AVFENEB
+	AVFENEH
+	AVFENEF
+	AVFENEBS
+	AVFENEHS
+	AVFENEFS
+	AVFENEZB
+	AVFENEZH
+	AVFENEZF
+	AVFENEZBS
+	AVFENEZHS
+	AVFENEZFS
+	AVFA
+	AVFADB
+	AWFADB
+	AWFK
+	AWFKDB
+	AVFCE
+	AVFCEDB
+	AVFCEDBS
+	AWFCEDB
+	AWFCEDBS
+	AVFCH
+	AVFCHDB
+	AVFCHDBS
+	AWFCHDB
+	AWFCHDBS
+	AVFCHE
+	AVFCHEDB
+	AVFCHEDBS
+	AWFCHEDB
+	AWFCHEDBS
+	AWFC
+	AWFCDB
+	AVCDG
+	AVCDGB
+	AWCDGB
+	AVCDLG
+	AVCDLGB
+	AWCDLGB
+	AVCGD
+	AVCGDB
+	AWCGDB
+	AVCLGD
+	AVCLGDB
+	AWCLGDB
+	AVFD
+	AVFDDB
+	AWFDDB
+	AVLDE
+	AVLDEB
+	AWLDEB
+	AVLED
+	AVLEDB
+	AWLEDB
+	AVFM
+	AVFMDB
+	AWFMDB
+	AVFMA
+	AVFMADB
+	AWFMADB
+	AVFMS
+	AVFMSDB
+	AWFMSDB
+	AVFPSO
+	AVFPSODB
+	AWFPSODB
+	AVFLCDB
+	AWFLCDB
+	AVFLNDB
+	AWFLNDB
+	AVFLPDB
+	AWFLPDB
+	AVFSQ
+	AVFSQDB
+	AWFSQDB
+	AVFS
+	AVFSDB
+	AWFSDB
+	AVFTCI
+	AVFTCIDB
+	AWFTCIDB
+	AVGFM
+	AVGFMB
+	AVGFMH
+	AVGFMF
+	AVGFMG
+	AVGFMA
+	AVGFMAB
+	AVGFMAH
+	AVGFMAF
+	AVGFMAG
+	AVGEF
+	AVGEG
+	AVGBM
+	AVZERO
+	AVONE
+	AVGM
+	AVGMB
+	AVGMH
+	AVGMF
+	AVGMG
+	AVISTR
+	AVISTRB
+	AVISTRH
+	AVISTRF
+	AVISTRBS
+	AVISTRHS
+	AVISTRFS
+	AVL
+	AVLR
+	AVLREP
+	AVLREPB
+	AVLREPH
+	AVLREPF
+	AVLREPG
+	AVLC
+	AVLCB
+	AVLCH
+	AVLCF
+	AVLCG
+	AVLEH
+	AVLEF
+	AVLEG
+	AVLEB
+	AVLEIH
+	AVLEIF
+	AVLEIG
+	AVLEIB
+	AVFI
+	AVFIDB
+	AWFIDB
+	AVLGV
+	AVLGVB
+	AVLGVH
+	AVLGVF
+	AVLGVG
+	AVLLEZ
+	AVLLEZB
+	AVLLEZH
+	AVLLEZF
+	AVLLEZG
+	AVLM
+	AVLP
+	AVLPB
+	AVLPH
+	AVLPF
+	AVLPG
+	AVLBB
+	AVLVG
+	AVLVGB
+	AVLVGH
+	AVLVGF
+	AVLVGG
+	AVLVGP
+	AVLL
+	AVMX
+	AVMXB
+	AVMXH
+	AVMXF
+	AVMXG
+	AVMXL
+	AVMXLB
+	AVMXLH
+	AVMXLF
+	AVMXLG
+	AVMRH
+	AVMRHB
+	AVMRHH
+	AVMRHF
+	AVMRHG
+	AVMRL
+	AVMRLB
+	AVMRLH
+	AVMRLF
+	AVMRLG
+	AVMN
+	AVMNB
+	AVMNH
+	AVMNF
+	AVMNG
+	AVMNL
+	AVMNLB
+	AVMNLH
+	AVMNLF
+	AVMNLG
+	AVMAE
+	AVMAEB
+	AVMAEH
+	AVMAEF
+	AVMAH
+	AVMAHB
+	AVMAHH
+	AVMAHF
+	AVMALE
+	AVMALEB
+	AVMALEH
+	AVMALEF
+	AVMALH
+	AVMALHB
+	AVMALHH
+	AVMALHF
+	AVMALO
+	AVMALOB
+	AVMALOH
+	AVMALOF
+	AVMAL
+	AVMALB
+	AVMALHW
+	AVMALF
+	AVMAO
+	AVMAOB
+	AVMAOH
+	AVMAOF
+	AVME
+	AVMEB
+	AVMEH
+	AVMEF
+	AVMH
+	AVMHB
+	AVMHH
+	AVMHF
+	AVMLE
+	AVMLEB
+	AVMLEH
+	AVMLEF
+	AVMLH
+	AVMLHB
+	AVMLHH
+	AVMLHF
+	AVMLO
+	AVMLOB
+	AVMLOH
+	AVMLOF
+	AVML
+	AVMLB
+	AVMLHW
+	AVMLF
+	AVMO
+	AVMOB
+	AVMOH
+	AVMOF
+	AVNO
+	AVNOT
+	AVO
+	AVPK
+	AVPKH
+	AVPKF
+	AVPKG
+	AVPKLS
+	AVPKLSH
+	AVPKLSF
+	AVPKLSG
+	AVPKLSHS
+	AVPKLSFS
+	AVPKLSGS
+	AVPKS
+	AVPKSH
+	AVPKSF
+	AVPKSG
+	AVPKSHS
+	AVPKSFS
+	AVPKSGS
+	AVPERM
+	AVPDI
+	AVPOPCT
+	AVREP
+	AVREPB
+	AVREPH
+	AVREPF
+	AVREPG
+	AVREPI
+	AVREPIB
+	AVREPIH
+	AVREPIF
+	AVREPIG
+	AVSCEF
+	AVSCEG
+	AVSEL
+	AVSL
+	AVSLB
+	AVSLDB
+	AVSRA
+	AVSRAB
+	AVSRL
+	AVSRLB
+	AVSEG
+	AVSEGB
+	AVSEGH
+	AVSEGF
+	AVST
+	AVSTEH
+	AVSTEF
+	AVSTEG
+	AVSTEB
+	AVSTM
+	AVSTL
+	AVSTRC
+	AVSTRCB
+	AVSTRCH
+	AVSTRCF
+	AVSTRCBS
+	AVSTRCHS
+	AVSTRCFS
+	AVSTRCZB
+	AVSTRCZH
+	AVSTRCZF
+	AVSTRCZBS
+	AVSTRCZHS
+	AVSTRCZFS
+	AVS
+	AVSB
+	AVSH
+	AVSF
+	AVSG
+	AVSQ
+	AVSCBI
+	AVSCBIB
+	AVSCBIH
+	AVSCBIF
+	AVSCBIG
+	AVSCBIQ
+	AVSBCBI
+	AVSBCBIQ
+	AVSBI
+	AVSBIQ
+	AVSUMG
+	AVSUMGH
+	AVSUMGF
+	AVSUMQ
+	AVSUMQF
+	AVSUMQG
+	AVSUM
+	AVSUMB
+	AVSUMH
+	AVTM
+	AVUPH
+	AVUPHB
+	AVUPHH
+	AVUPHF
+	AVUPLH
+	AVUPLHB
+	AVUPLHH
+	AVUPLHF
+	AVUPLL
+	AVUPLLB
+	AVUPLLH
+	AVUPLLF
+	AVUPL
+	AVUPLB
+	AVUPLHW
+	AVUPLF
+
+	// binary
+	ABYTE
+	AWORD
+	ADWORD
+
+	// end marker
+	ALAST
+
+	// aliases
+	ABR = obj.AJMP
+	ABL = obj.ACALL
+)
diff --git a/src/cmd/internal/obj/s390x/anames.go b/src/cmd/internal/obj/s390x/anames.go
new file mode 100644
index 0000000..62dd181
--- /dev/null
+++ b/src/cmd/internal/obj/s390x/anames.go
@@ -0,0 +1,651 @@
+// Generated by stringer -i a.out.go -o anames.go -p s390x
+// Do not edit.
+
+package s390x
+
+import "cmd/internal/obj"
+
+var Anames = []string{
+	obj.A_ARCHSPECIFIC: "ADD",
+	"ADDC",
+	"ADDME",
+	"ADDE",
+	"ADDZE",
+	"DIVW",
+	"DIVWU",
+	"DIVD",
+	"DIVDU",
+	"MULLW",
+	"MULLD",
+	"MULHD",
+	"MULHDU",
+	"SUB",
+	"SUBC",
+	"SUBME",
+	"SUBV",
+	"SUBE",
+	"SUBZE",
+	"NEG",
+	"MOVWBR",
+	"MOVB",
+	"MOVBZ",
+	"MOVH",
+	"MOVHBR",
+	"MOVHZ",
+	"MOVW",
+	"MOVWZ",
+	"MOVD",
+	"MOVDBR",
+	"AND",
+	"ANDN",
+	"NAND",
+	"NOR",
+	"OR",
+	"ORN",
+	"XOR",
+	"SLW",
+	"SLD",
+	"SRW",
+	"SRAW",
+	"SRD",
+	"SRAD",
+	"RLL",
+	"RLLG",
+	"FABS",
+	"FADD",
+	"FADDS",
+	"FCMPO",
+	"FCMPU",
+	"CEBR",
+	"FDIV",
+	"FDIVS",
+	"FMADD",
+	"FMADDS",
+	"FMOVD",
+	"FMOVS",
+	"FMSUB",
+	"FMSUBS",
+	"FMUL",
+	"FMULS",
+	"FNABS",
+	"FNEG",
+	"FNMADD",
+	"FNMADDS",
+	"FNMSUB",
+	"FNMSUBS",
+	"LEDBR",
+	"LDEBR",
+	"FSUB",
+	"FSUBS",
+	"FSQRT",
+	"FSQRTS",
+	"CEFBRA",
+	"CDFBRA",
+	"CEGBRA",
+	"CDGBRA",
+	"CFEBRA",
+	"CFDBRA",
+	"CGEBRA",
+	"CGDBRA",
+	"CELFBR",
+	"CDLFBR",
+	"CELGBR",
+	"CDLGBR",
+	"CLFEBR",
+	"CLFDBR",
+	"CLGEBR",
+	"CLGDBR",
+	"CMP",
+	"CMPU",
+	"CMPW",
+	"CMPWU",
+	"CS",
+	"CSG",
+	"SYNC",
+	"BC",
+	"BCL",
+	"BEQ",
+	"BGE",
+	"BGT",
+	"BLE",
+	"BLT",
+	"BNE",
+	"BVC",
+	"BVS",
+	"SYSCALL",
+	"CMPBEQ",
+	"CMPBGE",
+	"CMPBGT",
+	"CMPBLE",
+	"CMPBLT",
+	"CMPBNE",
+	"CMPUBEQ",
+	"CMPUBGE",
+	"CMPUBGT",
+	"CMPUBLE",
+	"CMPUBLT",
+	"CMPUBNE",
+	"MVC",
+	"CLC",
+	"XC",
+	"OC",
+	"NC",
+	"EXRL",
+	"LARL",
+	"LA",
+	"LAY",
+	"LMY",
+	"LMG",
+	"STMY",
+	"STMG",
+	"STCK",
+	"STCKC",
+	"STCKE",
+	"STCKF",
+	"CLEAR",
+	"VA",
+	"VAB",
+	"VAH",
+	"VAF",
+	"VAG",
+	"VAQ",
+	"VACC",
+	"VACCB",
+	"VACCH",
+	"VACCF",
+	"VACCG",
+	"VACCQ",
+	"VAC",
+	"VACQ",
+	"VACCC",
+	"VACCCQ",
+	"VN",
+	"VNC",
+	"VAVG",
+	"VAVGB",
+	"VAVGH",
+	"VAVGF",
+	"VAVGG",
+	"VAVGL",
+	"VAVGLB",
+	"VAVGLH",
+	"VAVGLF",
+	"VAVGLG",
+	"VCKSM",
+	"VCEQ",
+	"VCEQB",
+	"VCEQH",
+	"VCEQF",
+	"VCEQG",
+	"VCEQBS",
+	"VCEQHS",
+	"VCEQFS",
+	"VCEQGS",
+	"VCH",
+	"VCHB",
+	"VCHH",
+	"VCHF",
+	"VCHG",
+	"VCHBS",
+	"VCHHS",
+	"VCHFS",
+	"VCHGS",
+	"VCHL",
+	"VCHLB",
+	"VCHLH",
+	"VCHLF",
+	"VCHLG",
+	"VCHLBS",
+	"VCHLHS",
+	"VCHLFS",
+	"VCHLGS",
+	"VCLZ",
+	"VCLZB",
+	"VCLZH",
+	"VCLZF",
+	"VCLZG",
+	"VCTZ",
+	"VCTZB",
+	"VCTZH",
+	"VCTZF",
+	"VCTZG",
+	"VEC",
+	"VECB",
+	"VECH",
+	"VECF",
+	"VECG",
+	"VECL",
+	"VECLB",
+	"VECLH",
+	"VECLF",
+	"VECLG",
+	"VERIM",
+	"VERIMB",
+	"VERIMH",
+	"VERIMF",
+	"VERIMG",
+	"VERLL",
+	"VERLLB",
+	"VERLLH",
+	"VERLLF",
+	"VERLLG",
+	"VERLLV",
+	"VERLLVB",
+	"VERLLVH",
+	"VERLLVF",
+	"VERLLVG",
+	"VESLV",
+	"VESLVB",
+	"VESLVH",
+	"VESLVF",
+	"VESLVG",
+	"VESL",
+	"VESLB",
+	"VESLH",
+	"VESLF",
+	"VESLG",
+	"VESRA",
+	"VESRAB",
+	"VESRAH",
+	"VESRAF",
+	"VESRAG",
+	"VESRAV",
+	"VESRAVB",
+	"VESRAVH",
+	"VESRAVF",
+	"VESRAVG",
+	"VESRL",
+	"VESRLB",
+	"VESRLH",
+	"VESRLF",
+	"VESRLG",
+	"VESRLV",
+	"VESRLVB",
+	"VESRLVH",
+	"VESRLVF",
+	"VESRLVG",
+	"VX",
+	"VFAE",
+	"VFAEB",
+	"VFAEH",
+	"VFAEF",
+	"VFAEBS",
+	"VFAEHS",
+	"VFAEFS",
+	"VFAEZB",
+	"VFAEZH",
+	"VFAEZF",
+	"VFAEZBS",
+	"VFAEZHS",
+	"VFAEZFS",
+	"VFEE",
+	"VFEEB",
+	"VFEEH",
+	"VFEEF",
+	"VFEEBS",
+	"VFEEHS",
+	"VFEEFS",
+	"VFEEZB",
+	"VFEEZH",
+	"VFEEZF",
+	"VFEEZBS",
+	"VFEEZHS",
+	"VFEEZFS",
+	"VFENE",
+	"VFENEB",
+	"VFENEH",
+	"VFENEF",
+	"VFENEBS",
+	"VFENEHS",
+	"VFENEFS",
+	"VFENEZB",
+	"VFENEZH",
+	"VFENEZF",
+	"VFENEZBS",
+	"VFENEZHS",
+	"VFENEZFS",
+	"VFA",
+	"VFADB",
+	"WFADB",
+	"WFK",
+	"WFKDB",
+	"VFCE",
+	"VFCEDB",
+	"VFCEDBS",
+	"WFCEDB",
+	"WFCEDBS",
+	"VFCH",
+	"VFCHDB",
+	"VFCHDBS",
+	"WFCHDB",
+	"WFCHDBS",
+	"VFCHE",
+	"VFCHEDB",
+	"VFCHEDBS",
+	"WFCHEDB",
+	"WFCHEDBS",
+	"WFC",
+	"WFCDB",
+	"VCDG",
+	"VCDGB",
+	"WCDGB",
+	"VCDLG",
+	"VCDLGB",
+	"WCDLGB",
+	"VCGD",
+	"VCGDB",
+	"WCGDB",
+	"VCLGD",
+	"VCLGDB",
+	"WCLGDB",
+	"VFD",
+	"VFDDB",
+	"WFDDB",
+	"VLDE",
+	"VLDEB",
+	"WLDEB",
+	"VLED",
+	"VLEDB",
+	"WLEDB",
+	"VFM",
+	"VFMDB",
+	"WFMDB",
+	"VFMA",
+	"VFMADB",
+	"WFMADB",
+	"VFMS",
+	"VFMSDB",
+	"WFMSDB",
+	"VFPSO",
+	"VFPSODB",
+	"WFPSODB",
+	"VFLCDB",
+	"WFLCDB",
+	"VFLNDB",
+	"WFLNDB",
+	"VFLPDB",
+	"WFLPDB",
+	"VFSQ",
+	"VFSQDB",
+	"WFSQDB",
+	"VFS",
+	"VFSDB",
+	"WFSDB",
+	"VFTCI",
+	"VFTCIDB",
+	"WFTCIDB",
+	"VGFM",
+	"VGFMB",
+	"VGFMH",
+	"VGFMF",
+	"VGFMG",
+	"VGFMA",
+	"VGFMAB",
+	"VGFMAH",
+	"VGFMAF",
+	"VGFMAG",
+	"VGEF",
+	"VGEG",
+	"VGBM",
+	"VZERO",
+	"VONE",
+	"VGM",
+	"VGMB",
+	"VGMH",
+	"VGMF",
+	"VGMG",
+	"VISTR",
+	"VISTRB",
+	"VISTRH",
+	"VISTRF",
+	"VISTRBS",
+	"VISTRHS",
+	"VISTRFS",
+	"VL",
+	"VLR",
+	"VLREP",
+	"VLREPB",
+	"VLREPH",
+	"VLREPF",
+	"VLREPG",
+	"VLC",
+	"VLCB",
+	"VLCH",
+	"VLCF",
+	"VLCG",
+	"VLEH",
+	"VLEF",
+	"VLEG",
+	"VLEB",
+	"VLEIH",
+	"VLEIF",
+	"VLEIG",
+	"VLEIB",
+	"VFI",
+	"VFIDB",
+	"WFIDB",
+	"VLGV",
+	"VLGVB",
+	"VLGVH",
+	"VLGVF",
+	"VLGVG",
+	"VLLEZ",
+	"VLLEZB",
+	"VLLEZH",
+	"VLLEZF",
+	"VLLEZG",
+	"VLM",
+	"VLP",
+	"VLPB",
+	"VLPH",
+	"VLPF",
+	"VLPG",
+	"VLBB",
+	"VLVG",
+	"VLVGB",
+	"VLVGH",
+	"VLVGF",
+	"VLVGG",
+	"VLVGP",
+	"VLL",
+	"VMX",
+	"VMXB",
+	"VMXH",
+	"VMXF",
+	"VMXG",
+	"VMXL",
+	"VMXLB",
+	"VMXLH",
+	"VMXLF",
+	"VMXLG",
+	"VMRH",
+	"VMRHB",
+	"VMRHH",
+	"VMRHF",
+	"VMRHG",
+	"VMRL",
+	"VMRLB",
+	"VMRLH",
+	"VMRLF",
+	"VMRLG",
+	"VMN",
+	"VMNB",
+	"VMNH",
+	"VMNF",
+	"VMNG",
+	"VMNL",
+	"VMNLB",
+	"VMNLH",
+	"VMNLF",
+	"VMNLG",
+	"VMAE",
+	"VMAEB",
+	"VMAEH",
+	"VMAEF",
+	"VMAH",
+	"VMAHB",
+	"VMAHH",
+	"VMAHF",
+	"VMALE",
+	"VMALEB",
+	"VMALEH",
+	"VMALEF",
+	"VMALH",
+	"VMALHB",
+	"VMALHH",
+	"VMALHF",
+	"VMALO",
+	"VMALOB",
+	"VMALOH",
+	"VMALOF",
+	"VMAL",
+	"VMALB",
+	"VMALHW",
+	"VMALF",
+	"VMAO",
+	"VMAOB",
+	"VMAOH",
+	"VMAOF",
+	"VME",
+	"VMEB",
+	"VMEH",
+	"VMEF",
+	"VMH",
+	"VMHB",
+	"VMHH",
+	"VMHF",
+	"VMLE",
+	"VMLEB",
+	"VMLEH",
+	"VMLEF",
+	"VMLH",
+	"VMLHB",
+	"VMLHH",
+	"VMLHF",
+	"VMLO",
+	"VMLOB",
+	"VMLOH",
+	"VMLOF",
+	"VML",
+	"VMLB",
+	"VMLHW",
+	"VMLF",
+	"VMO",
+	"VMOB",
+	"VMOH",
+	"VMOF",
+	"VNO",
+	"VNOT",
+	"VO",
+	"VPK",
+	"VPKH",
+	"VPKF",
+	"VPKG",
+	"VPKLS",
+	"VPKLSH",
+	"VPKLSF",
+	"VPKLSG",
+	"VPKLSHS",
+	"VPKLSFS",
+	"VPKLSGS",
+	"VPKS",
+	"VPKSH",
+	"VPKSF",
+	"VPKSG",
+	"VPKSHS",
+	"VPKSFS",
+	"VPKSGS",
+	"VPERM",
+	"VPDI",
+	"VPOPCT",
+	"VREP",
+	"VREPB",
+	"VREPH",
+	"VREPF",
+	"VREPG",
+	"VREPI",
+	"VREPIB",
+	"VREPIH",
+	"VREPIF",
+	"VREPIG",
+	"VSCEF",
+	"VSCEG",
+	"VSEL",
+	"VSL",
+	"VSLB",
+	"VSLDB",
+	"VSRA",
+	"VSRAB",
+	"VSRL",
+	"VSRLB",
+	"VSEG",
+	"VSEGB",
+	"VSEGH",
+	"VSEGF",
+	"VST",
+	"VSTEH",
+	"VSTEF",
+	"VSTEG",
+	"VSTEB",
+	"VSTM",
+	"VSTL",
+	"VSTRC",
+	"VSTRCB",
+	"VSTRCH",
+	"VSTRCF",
+	"VSTRCBS",
+	"VSTRCHS",
+	"VSTRCFS",
+	"VSTRCZB",
+	"VSTRCZH",
+	"VSTRCZF",
+	"VSTRCZBS",
+	"VSTRCZHS",
+	"VSTRCZFS",
+	"VS",
+	"VSB",
+	"VSH",
+	"VSF",
+	"VSG",
+	"VSQ",
+	"VSCBI",
+	"VSCBIB",
+	"VSCBIH",
+	"VSCBIF",
+	"VSCBIG",
+	"VSCBIQ",
+	"VSBCBI",
+	"VSBCBIQ",
+	"VSBI",
+	"VSBIQ",
+	"VSUMG",
+	"VSUMGH",
+	"VSUMGF",
+	"VSUMQ",
+	"VSUMQF",
+	"VSUMQG",
+	"VSUM",
+	"VSUMB",
+	"VSUMH",
+	"VTM",
+	"VUPH",
+	"VUPHB",
+	"VUPHH",
+	"VUPHF",
+	"VUPLH",
+	"VUPLHB",
+	"VUPLHH",
+	"VUPLHF",
+	"VUPLL",
+	"VUPLLB",
+	"VUPLLH",
+	"VUPLLF",
+	"VUPL",
+	"VUPLB",
+	"VUPLHW",
+	"VUPLF",
+	"BYTE",
+	"WORD",
+	"DWORD",
+	"LAST",
+}
diff --git a/src/cmd/internal/obj/s390x/anamesz.go b/src/cmd/internal/obj/s390x/anamesz.go
new file mode 100644
index 0000000..9c9b4d5
--- /dev/null
+++ b/src/cmd/internal/obj/s390x/anamesz.go
@@ -0,0 +1,39 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s390x
+
+var cnamesz = []string{
+	"NONE",
+	"REG",
+	"FREG",
+	"VREG",
+	"AREG",
+	"ZCON",
+	"SCON",
+	"UCON",
+	"ADDCON",
+	"ANDCON",
+	"LCON",
+	"DCON",
+	"SACON",
+	"LACON",
+	"DACON",
+	"SBRA",
+	"LBRA",
+	"SAUTO",
+	"LAUTO",
+	"ZOREG",
+	"SOREG",
+	"LOREG",
+	"TLS_LE",
+	"TLS_IE",
+	"GOK",
+	"ADDR",
+	"SYMADDR",
+	"GOTADDR",
+	"TEXTSIZE",
+	"ANY",
+	"NCLASS",
+}
diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go
new file mode 100644
index 0000000..2a99bbe
--- /dev/null
+++ b/src/cmd/internal/obj/s390x/asmz.go
@@ -0,0 +1,4645 @@
+// Based on cmd/internal/obj/ppc64/asm9.go.
+//
+//    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 s390x
+
+import (
+	"cmd/internal/obj"
+	"log"
+	"math"
+	"sort"
+)
+
+// instruction layout.
+const (
+	FuncAlign = 16
+)
+
+type Optab struct {
+	as    obj.As // opcode
+	a1    uint8  // From
+	a2    uint8  // Reg
+	a3    uint8  // From3
+	a4    uint8  // To
+	type_ int8
+	param int16 // REGSP for auto variables
+}
+
+var optab = []Optab{
+	// instruction,  From,   Reg,    From3,  To, type, param
+	Optab{obj.ATEXT, C_ADDR, C_NONE, C_NONE, C_TEXTSIZE, 0, 0},
+	Optab{obj.ATEXT, C_ADDR, C_NONE, C_LCON, C_TEXTSIZE, 0, 0},
+
+	// move register
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_REG, 1, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_REG, 1, 0},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_REG, 1, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_REG, 1, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_REG, 1, 0},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 1, 0},
+	Optab{AMOVDBR, C_REG, C_NONE, C_NONE, C_REG, 1, 0},
+
+	// load constant
+	Optab{AMOVD, C_LACON, C_NONE, C_NONE, C_REG, 26, REGSP},
+	Optab{AMOVW, C_LACON, C_NONE, C_NONE, C_REG, 26, REGSP},
+	Optab{AMOVWZ, C_LACON, C_NONE, C_NONE, C_REG, 26, REGSP},
+	Optab{AMOVD, C_DCON, C_NONE, C_NONE, C_REG, 3, 0},
+	Optab{AMOVW, C_DCON, C_NONE, C_NONE, C_REG, 3, 0},
+	Optab{AMOVWZ, C_DCON, C_NONE, C_NONE, C_REG, 3, 0},
+	Optab{AMOVB, C_DCON, C_NONE, C_NONE, C_REG, 3, 0},
+	Optab{AMOVBZ, C_DCON, C_NONE, C_NONE, C_REG, 3, 0},
+
+	// store constant
+	Optab{AMOVD, C_SYMADDR, C_NONE, C_NONE, C_ADDR, 73, 0},
+	Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
+	Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
+	Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
+	Optab{AMOVBZ, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
+	Optab{AMOVB, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
+	Optab{AMOVD, C_SYMADDR, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVB, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVBZ, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
+	Optab{AMOVD, C_SYMADDR, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVB, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+	Optab{AMOVBZ, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
+
+	// store
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
+	Optab{AMOVDBR, C_REG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
+	Optab{AMOVHBR, C_REG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 35, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 35, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 0},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 35, 0},
+	Optab{AMOVDBR, C_REG, C_NONE, C_NONE, C_LOREG, 35, 0},
+	Optab{AMOVHBR, C_REG, C_NONE, C_NONE, C_LOREG, 35, 0},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 74, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 74, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 0},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 74, 0},
+
+	// load
+	Optab{AMOVD, C_LAUTO, C_NONE, C_NONE, C_REG, 36, REGSP},
+	Optab{AMOVW, C_LAUTO, C_NONE, C_NONE, C_REG, 36, REGSP},
+	Optab{AMOVWZ, C_LAUTO, C_NONE, C_NONE, C_REG, 36, REGSP},
+	Optab{AMOVBZ, C_LAUTO, C_NONE, C_NONE, C_REG, 36, REGSP},
+	Optab{AMOVB, C_LAUTO, C_NONE, C_NONE, C_REG, 36, REGSP},
+	Optab{AMOVDBR, C_LAUTO, C_NONE, C_NONE, C_REG, 36, REGSP},
+	Optab{AMOVHBR, C_LAUTO, C_NONE, C_NONE, C_REG, 36, REGSP},
+	Optab{AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 36, 0},
+	Optab{AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 36, 0},
+	Optab{AMOVWZ, C_LOREG, C_NONE, C_NONE, C_REG, 36, 0},
+	Optab{AMOVBZ, C_LOREG, C_NONE, C_NONE, C_REG, 36, 0},
+	Optab{AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 36, 0},
+	Optab{AMOVDBR, C_LOREG, C_NONE, C_NONE, C_REG, 36, 0},
+	Optab{AMOVHBR, C_LOREG, C_NONE, C_NONE, C_REG, 36, 0},
+	Optab{AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 75, 0},
+	Optab{AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 75, 0},
+	Optab{AMOVWZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 0},
+	Optab{AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 0},
+	Optab{AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 75, 0},
+
+	// integer arithmetic
+	Optab{AADD, C_REG, C_REG, C_NONE, C_REG, 2, 0},
+	Optab{AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 0},
+	Optab{AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 0},
+	Optab{AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 0},
+	Optab{AMULHD, C_REG, C_NONE, C_NONE, C_REG, 4, 0},
+	Optab{AMULHD, C_REG, C_REG, C_NONE, C_REG, 4, 0},
+	Optab{ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 0},
+	Optab{ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 0},
+	Optab{ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 0},
+	Optab{ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 0},
+	Optab{ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 0},
+	Optab{ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 0},
+	Optab{AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 0},
+	Optab{ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 0},
+	Optab{ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 0},
+
+	// integer logical
+	Optab{AAND, C_REG, C_REG, C_NONE, C_REG, 6, 0},
+	Optab{AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 0},
+	Optab{AAND, C_LCON, C_NONE, C_NONE, C_REG, 23, 0},
+	Optab{AAND, C_LCON, C_REG, C_NONE, C_REG, 23, 0},
+	Optab{AOR, C_REG, C_REG, C_NONE, C_REG, 6, 0},
+	Optab{AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 0},
+	Optab{AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 0},
+	Optab{AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 0},
+	Optab{ASLD, C_REG, C_NONE, C_NONE, C_REG, 7, 0},
+	Optab{ASLD, C_REG, C_REG, C_NONE, C_REG, 7, 0},
+	Optab{ASLD, C_SCON, C_REG, C_NONE, C_REG, 7, 0},
+	Optab{ASLD, C_SCON, C_NONE, C_NONE, C_REG, 7, 0},
+
+	// compare and swap
+	Optab{ACSG, C_REG, C_REG, C_NONE, C_SOREG, 79, 0},
+
+	// floating point
+	Optab{AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 0},
+	Optab{AFADD, C_FREG, C_FREG, C_NONE, C_FREG, 2, 0},
+	Optab{AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 0},
+	Optab{AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 0},
+	Optab{AFMADD, C_FREG, C_FREG, C_FREG, C_FREG, 34, 0},
+	Optab{AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 0},
+	Optab{AFMUL, C_FREG, C_FREG, C_NONE, C_FREG, 32, 0},
+	Optab{AFMOVD, C_LAUTO, C_NONE, C_NONE, C_FREG, 36, REGSP},
+	Optab{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 36, 0},
+	Optab{AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 75, 0},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 35, REGSP},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 35, 0},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 0},
+	Optab{AFMOVD, C_ZCON, C_NONE, C_NONE, C_FREG, 67, 0},
+	Optab{ACEFBRA, C_REG, C_NONE, C_NONE, C_FREG, 82, 0},
+	Optab{ACFEBRA, C_FREG, C_NONE, C_NONE, C_REG, 83, 0},
+
+	// load symbol address (plus offset)
+	Optab{AMOVD, C_SYMADDR, C_NONE, C_NONE, C_REG, 19, 0},
+	Optab{AMOVD, C_GOTADDR, C_NONE, C_NONE, C_REG, 93, 0},
+	Optab{AMOVD, C_TLS_LE, C_NONE, C_NONE, C_REG, 94, 0},
+	Optab{AMOVD, C_TLS_IE, C_NONE, C_NONE, C_REG, 95, 0},
+
+	// system call
+	Optab{ASYSCALL, C_NONE, C_NONE, C_NONE, C_NONE, 5, 0},
+	Optab{ASYSCALL, C_SCON, C_NONE, C_NONE, C_NONE, 77, 0},
+
+	// branch
+	Optab{ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 0},
+	Optab{ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 0},
+	Optab{ABC, C_SCON, C_REG, C_NONE, C_LBRA, 16, 0},
+	Optab{ABR, C_NONE, C_NONE, C_NONE, C_REG, 18, 0},
+	Optab{ABR, C_REG, C_NONE, C_NONE, C_REG, 18, 0},
+	Optab{ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 0},
+	Optab{ABC, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 0},
+	Optab{ACMPBEQ, C_REG, C_REG, C_NONE, C_SBRA, 89, 0},
+	Optab{ACMPBEQ, C_REG, C_NONE, C_ADDCON, C_SBRA, 90, 0},
+	Optab{ACMPBEQ, C_REG, C_NONE, C_SCON, C_SBRA, 90, 0},
+	Optab{ACMPUBEQ, C_REG, C_REG, C_NONE, C_SBRA, 89, 0},
+	Optab{ACMPUBEQ, C_REG, C_NONE, C_ANDCON, C_SBRA, 90, 0},
+
+	// compare
+	Optab{ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 0},
+	Optab{ACMP, C_REG, C_NONE, C_NONE, C_LCON, 71, 0},
+	Optab{ACMPU, C_REG, C_NONE, C_NONE, C_REG, 70, 0},
+	Optab{ACMPU, C_REG, C_NONE, C_NONE, C_LCON, 71, 0},
+	Optab{AFCMPO, C_FREG, C_NONE, C_NONE, C_FREG, 70, 0},
+	Optab{AFCMPO, C_FREG, C_REG, C_NONE, C_FREG, 70, 0},
+
+	// 32-bit access registers
+	Optab{AMOVW, C_AREG, C_NONE, C_NONE, C_REG, 68, 0},
+	Optab{AMOVWZ, C_AREG, C_NONE, C_NONE, C_REG, 68, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_AREG, 69, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_AREG, 69, 0},
+
+	// macros
+	Optab{ACLEAR, C_LCON, C_NONE, C_NONE, C_LOREG, 96, 0},
+	Optab{ACLEAR, C_LCON, C_NONE, C_NONE, C_LAUTO, 96, REGSP},
+
+	// load/store multiple
+	Optab{ASTMG, C_REG, C_REG, C_NONE, C_LOREG, 97, 0},
+	Optab{ASTMG, C_REG, C_REG, C_NONE, C_LAUTO, 97, REGSP},
+	Optab{ALMG, C_LOREG, C_REG, C_NONE, C_REG, 98, 0},
+	Optab{ALMG, C_LAUTO, C_REG, C_NONE, C_REG, 98, REGSP},
+
+	// bytes
+	Optab{ABYTE, C_SCON, C_NONE, C_NONE, C_NONE, 40, 0},
+	Optab{AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 0},
+	Optab{ADWORD, C_LCON, C_NONE, C_NONE, C_NONE, 31, 0},
+	Optab{ADWORD, C_DCON, C_NONE, C_NONE, C_NONE, 31, 0},
+
+	// fast synchronization
+	Optab{ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 81, 0},
+
+	// store clock
+	Optab{ASTCK, C_NONE, C_NONE, C_NONE, C_SAUTO, 88, REGSP},
+	Optab{ASTCK, C_NONE, C_NONE, C_NONE, C_SOREG, 88, 0},
+
+	// storage and storage
+	Optab{AMVC, C_LOREG, C_NONE, C_SCON, C_LOREG, 84, 0},
+	Optab{AMVC, C_LOREG, C_NONE, C_SCON, C_LAUTO, 84, REGSP},
+	Optab{AMVC, C_LAUTO, C_NONE, C_SCON, C_LAUTO, 84, REGSP},
+
+	// address
+	Optab{ALARL, C_LCON, C_NONE, C_NONE, C_REG, 85, 0},
+	Optab{ALARL, C_SYMADDR, C_NONE, C_NONE, C_REG, 85, 0},
+	Optab{ALA, C_SOREG, C_NONE, C_NONE, C_REG, 86, 0},
+	Optab{ALA, C_SAUTO, C_NONE, C_NONE, C_REG, 86, REGSP},
+	Optab{AEXRL, C_SYMADDR, C_NONE, C_NONE, C_REG, 87, 0},
+
+	// misc
+	Optab{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 78, 0},
+	Optab{obj.APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, 0, 0},
+	Optab{obj.AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, 0, 0},
+	Optab{obj.ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0},
+	Optab{obj.ANOP, C_SAUTO, C_NONE, C_NONE, C_NONE, 0, 0},
+
+	// vector instructions
+
+	// VRX store
+	Optab{AVST, C_VREG, C_NONE, C_NONE, C_SOREG, 100, 0},
+	Optab{AVST, C_VREG, C_NONE, C_NONE, C_SAUTO, 100, REGSP},
+	Optab{AVSTEG, C_VREG, C_NONE, C_SCON, C_SOREG, 100, 0},
+	Optab{AVSTEG, C_VREG, C_NONE, C_SCON, C_SAUTO, 100, REGSP},
+
+	// VRX load
+	Optab{AVL, C_SOREG, C_NONE, C_NONE, C_VREG, 101, 0},
+	Optab{AVL, C_SAUTO, C_NONE, C_NONE, C_VREG, 101, REGSP},
+	Optab{AVLEG, C_SOREG, C_NONE, C_SCON, C_VREG, 101, 0},
+	Optab{AVLEG, C_SAUTO, C_NONE, C_SCON, C_VREG, 101, REGSP},
+
+	// VRV scatter
+	Optab{AVSCEG, C_VREG, C_NONE, C_SCON, C_SOREG, 102, 0},
+	Optab{AVSCEG, C_VREG, C_NONE, C_SCON, C_SAUTO, 102, REGSP},
+
+	// VRV gather
+	Optab{AVGEG, C_SOREG, C_NONE, C_SCON, C_VREG, 103, 0},
+	Optab{AVGEG, C_SAUTO, C_NONE, C_SCON, C_VREG, 103, REGSP},
+
+	// VRS element shift/rotate and load gr to/from vr element
+	Optab{AVESLG, C_SCON, C_VREG, C_NONE, C_VREG, 104, 0},
+	Optab{AVESLG, C_REG, C_VREG, C_NONE, C_VREG, 104, 0},
+	Optab{AVESLG, C_SCON, C_NONE, C_NONE, C_VREG, 104, 0},
+	Optab{AVESLG, C_REG, C_NONE, C_NONE, C_VREG, 104, 0},
+	Optab{AVLGVG, C_SCON, C_VREG, C_NONE, C_REG, 104, 0},
+	Optab{AVLGVG, C_REG, C_VREG, C_NONE, C_REG, 104, 0},
+	Optab{AVLVGG, C_SCON, C_REG, C_NONE, C_VREG, 104, 0},
+	Optab{AVLVGG, C_REG, C_REG, C_NONE, C_VREG, 104, 0},
+
+	// VRS store multiple
+	Optab{AVSTM, C_VREG, C_VREG, C_NONE, C_SOREG, 105, 0},
+	Optab{AVSTM, C_VREG, C_VREG, C_NONE, C_SAUTO, 105, REGSP},
+
+	// VRS load multiple
+	Optab{AVLM, C_SOREG, C_VREG, C_NONE, C_VREG, 106, 0},
+	Optab{AVLM, C_SAUTO, C_VREG, C_NONE, C_VREG, 106, REGSP},
+
+	// VRS store with length
+	Optab{AVSTL, C_VREG, C_NONE, C_REG, C_SOREG, 107, 0},
+	Optab{AVSTL, C_VREG, C_NONE, C_REG, C_SAUTO, 107, REGSP},
+
+	// VRS load with length
+	Optab{AVLL, C_SOREG, C_NONE, C_REG, C_VREG, 108, 0},
+	Optab{AVLL, C_SAUTO, C_NONE, C_REG, C_VREG, 108, REGSP},
+
+	// VRI-a
+	Optab{AVGBM, C_ANDCON, C_NONE, C_NONE, C_VREG, 109, 0},
+	Optab{AVZERO, C_NONE, C_NONE, C_NONE, C_VREG, 109, 0},
+	Optab{AVREPIG, C_ADDCON, C_NONE, C_NONE, C_VREG, 109, 0},
+	Optab{AVREPIG, C_SCON, C_NONE, C_NONE, C_VREG, 109, 0},
+	Optab{AVLEIG, C_ADDCON, C_NONE, C_SCON, C_VREG, 109, 0},
+	Optab{AVLEIG, C_SCON, C_NONE, C_SCON, C_VREG, 109, 0},
+
+	// VRI-b generate mask
+	Optab{AVGMG, C_SCON, C_NONE, C_SCON, C_VREG, 110, 0},
+
+	// VRI-c replicate
+	Optab{AVREPG, C_UCON, C_VREG, C_NONE, C_VREG, 111, 0},
+
+	// VRI-d element rotate and insert under mask and
+	// shift left double by byte
+	Optab{AVERIMG, C_VREG, C_VREG, C_SCON, C_VREG, 112, 0},
+	Optab{AVSLDB, C_VREG, C_VREG, C_SCON, C_VREG, 112, 0},
+
+	// VRI-d fp test data class immediate
+	Optab{AVFTCIDB, C_SCON, C_VREG, C_NONE, C_VREG, 113, 0},
+
+	// VRR-a load reg
+	Optab{AVLR, C_VREG, C_NONE, C_NONE, C_VREG, 114, 0},
+
+	// VRR-a compare
+	Optab{AVECG, C_VREG, C_NONE, C_NONE, C_VREG, 115, 0},
+
+	// VRR-b
+	Optab{AVCEQG, C_VREG, C_VREG, C_NONE, C_VREG, 117, 0},
+	Optab{AVFAEF, C_VREG, C_VREG, C_NONE, C_VREG, 117, 0},
+	Optab{AVPKSG, C_VREG, C_VREG, C_NONE, C_VREG, 117, 0},
+
+	// VRR-c
+	Optab{AVAQ, C_VREG, C_VREG, C_NONE, C_VREG, 118, 0},
+	Optab{AVAQ, C_VREG, C_NONE, C_NONE, C_VREG, 118, 0},
+	Optab{AVNOT, C_VREG, C_NONE, C_NONE, C_VREG, 118, 0},
+	Optab{AVPDI, C_VREG, C_VREG, C_SCON, C_VREG, 123, 0},
+
+	// VRR-c shifts
+	Optab{AVERLLVG, C_VREG, C_VREG, C_NONE, C_VREG, 119, 0},
+	Optab{AVERLLVG, C_VREG, C_NONE, C_NONE, C_VREG, 119, 0},
+
+	// VRR-d
+	//             2       3       1       4
+	Optab{AVACQ, C_VREG, C_VREG, C_VREG, C_VREG, 120, 0},
+
+	// VRR-e
+	Optab{AVSEL, C_VREG, C_VREG, C_VREG, C_VREG, 121, 0},
+
+	// VRR-f
+	Optab{AVLVGP, C_REG, C_REG, C_NONE, C_VREG, 122, 0},
+}
+
+var oprange [ALAST & obj.AMask][]Optab
+
+var xcmp [C_NCLASS][C_NCLASS]bool
+
+func spanz(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)
+
+	if oprange[AANDN&obj.AMask] == nil {
+		buildop(ctxt)
+	}
+
+	buffer := make([]byte, 0)
+	changed := true
+	loop := 0
+	for changed {
+		if loop > 10 {
+			ctxt.Diag("stuck in spanz loop")
+			break
+		}
+		changed = false
+		buffer = buffer[:0]
+		ctxt.Cursym.R = make([]obj.Reloc, 0)
+		for p := cursym.Text; p != nil; p = p.Link {
+			pc := int64(len(buffer))
+			if pc != p.Pc {
+				changed = true
+			}
+			p.Pc = pc
+			ctxt.Pc = p.Pc
+			ctxt.Curp = p
+			asmout(ctxt, &buffer)
+			if pc == int64(len(buffer)) {
+				switch p.As {
+				case obj.ANOP, obj.AFUNCDATA, obj.APCDATA, obj.ATEXT:
+					// ok
+				default:
+					ctxt.Diag("zero-width instruction\n%v", p)
+				}
+			}
+		}
+		loop++
+	}
+
+	cursym.Size = int64(len(buffer))
+	if cursym.Size%FuncAlign != 0 {
+		cursym.Size += FuncAlign - (cursym.Size % FuncAlign)
+	}
+	cursym.Grow(cursym.Size)
+	copy(cursym.P, buffer)
+}
+
+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_R15 {
+			return C_REG
+		}
+		if REG_F0 <= a.Reg && a.Reg <= REG_F15 {
+			return C_FREG
+		}
+		if REG_AR0 <= a.Reg && a.Reg <= REG_AR15 {
+			return C_AREG
+		}
+		if REG_V0 <= a.Reg && a.Reg <= REG_V31 {
+			return C_VREG
+		}
+		return C_GOK
+
+	case obj.TYPE_MEM:
+		switch a.Name {
+		case obj.NAME_EXTERN,
+			obj.NAME_STATIC:
+			if a.Sym == nil {
+				// must have a symbol
+				break
+			}
+			ctxt.Instoffset = a.Offset
+			if a.Sym.Type == obj.STLSBSS {
+				if ctxt.Flag_shared {
+					return C_TLS_IE // initial exec model
+				}
+				return C_TLS_LE // local exec model
+			}
+			return C_ADDR
+
+		case obj.NAME_GOTREF:
+			return C_GOTADDR
+
+		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 + ctxt.FixedFrameSize()
+			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_FCONST:
+		if f64, ok := a.Val.(float64); ok && math.Float64bits(f64) == 0 {
+			return C_ZCON
+		}
+		ctxt.Diag("cannot handle the floating point constant %v", a.Val)
+
+	case obj.TYPE_CONST,
+		obj.TYPE_ADDR:
+		switch a.Name {
+		case obj.NAME_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
+			}
+			ctxt.Instoffset = a.Offset
+			if s.Type == obj.SCONST {
+				goto consize
+			}
+
+			return C_SYMADDR
+
+		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 + ctxt.FixedFrameSize()
+			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+				return C_SACON
+			}
+			return C_LACON
+		}
+
+		return C_GOK
+
+	consize:
+		if ctxt.Instoffset == 0 {
+			return C_ZCON
+		}
+		if ctxt.Instoffset >= 0 {
+			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 oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
+	a1 := int(p.Optab)
+	if a1 != 0 {
+		return &optab[a1-1]
+	}
+	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 {
+		if REG_R0 <= p.Reg && p.Reg <= REG_R15 {
+			a2 = C_REG
+		} else if REG_V0 <= p.Reg && p.Reg <= REG_V31 {
+			a2 = C_VREG
+		} else if REG_F0 <= p.Reg && p.Reg <= REG_F15 {
+			a2 = C_FREG
+		} else if REG_AR0 <= p.Reg && p.Reg <= REG_AR15 {
+			a2 = C_AREG
+		}
+	}
+
+	ops := oprange[p.As&obj.AMask]
+	c1 := &xcmp[a1]
+	c2 := &xcmp[a2]
+	c3 := &xcmp[a3]
+	c4 := &xcmp[a4]
+	for i := range ops {
+		op := &ops[i]
+		if (int(op.a2) == a2 || c2[op.a2]) && c4[op.a4] && c1[op.a1] && c3[op.a3] {
+			p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
+			return op
+		}
+	}
+
+	// cannot find a case; abort
+	ctxt.Diag("illegal combination %v %v %v %v %v\n", obj.Aconv(p.As), DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
+	ctxt.Diag("prog: %v\n", p)
+	return nil
+}
+
+func cmp(a int, b int) bool {
+	if a == b {
+		return true
+	}
+	switch a {
+	case C_DCON:
+		if b == C_LCON {
+			return true
+		}
+		fallthrough
+	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_UCON:
+		if b == C_ZCON || b == C_SCON {
+			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_LAUTO:
+		if b == C_SAUTO {
+			return true
+		}
+
+	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, b obj.As) {
+	oprange[a&obj.AMask] = oprange[b&obj.AMask]
+}
+
+func buildop(ctxt *obj.Link) {
+	for i := 0; i < C_NCLASS; i++ {
+		for n := 0; n < C_NCLASS; n++ {
+			if cmp(n, i) {
+				xcmp[i][n] = true
+			}
+		}
+	}
+	sort.Sort(ocmp(optab))
+	for i := 0; i < len(optab); i++ {
+		r := optab[i].as
+		start := i
+		for ; i+1 < len(optab); i++ {
+			if optab[i+1].as != r {
+				break
+			}
+		}
+		oprange[r&obj.AMask] = optab[start : i+1]
+
+		// opset() aliases optab ranges for similar instructions, to reduce the number of optabs in the array.
+		// oprange[] is used by oplook() to find the Optab entry that applies to a given Prog.
+		switch r {
+		case AADD:
+			opset(AADDC, r)
+			opset(AMULLD, r)
+			opset(AMULLW, r)
+		case ADIVW:
+			opset(AADDE, r)
+			opset(ADIVD, r)
+			opset(ADIVDU, r)
+			opset(ADIVWU, r)
+		case AMULHD:
+			opset(AMULHDU, r)
+		case AMOVBZ:
+			opset(AMOVH, r)
+			opset(AMOVHZ, r)
+		case ALA:
+			opset(ALAY, r)
+		case AMVC:
+			opset(ACLC, r)
+			opset(AXC, r)
+			opset(AOC, r)
+			opset(ANC, r)
+		case ASTCK:
+			opset(ASTCKC, r)
+			opset(ASTCKE, r)
+			opset(ASTCKF, r)
+		case ASTMG:
+			opset(ASTMY, r)
+		case ALMG:
+			opset(ALMY, r)
+		case AAND:
+			opset(AANDN, r)
+			opset(ANAND, r)
+			opset(ANOR, r)
+			opset(AORN, r)
+		case AADDME:
+			opset(AADDZE, r)
+			opset(ASUBME, r)
+			opset(ASUBZE, r)
+		case ABEQ:
+			opset(ABGE, r)
+			opset(ABGT, r)
+			opset(ABLE, r)
+			opset(ABLT, r)
+			opset(ABNE, r)
+			opset(ABVC, r)
+			opset(ABVS, r)
+		case ABR:
+			opset(ABL, r)
+		case ABC:
+			opset(ABCL, r)
+		case AFABS:
+			opset(AFNABS, r)
+			opset(AFNEG, r)
+			opset(ALEDBR, r)
+			opset(ALDEBR, r)
+			opset(AFSQRT, r)
+			opset(AFSQRTS, r)
+		case AFADD:
+			opset(AFADDS, r)
+			opset(AFDIV, r)
+			opset(AFDIVS, r)
+			opset(AFSUB, r)
+			opset(AFSUBS, r)
+		case AFMADD:
+			opset(AFMADDS, r)
+			opset(AFMSUB, r)
+			opset(AFMSUBS, r)
+			opset(AFNMADD, r)
+			opset(AFNMADDS, r)
+			opset(AFNMSUB, r)
+			opset(AFNMSUBS, r)
+		case AFMUL:
+			opset(AFMULS, r)
+		case AFCMPO:
+			opset(AFCMPU, r)
+			opset(ACEBR, r)
+		case AOR:
+			opset(AXOR, r)
+		case ASLD:
+			opset(ASRD, r)
+			opset(ASLW, r)
+			opset(ASRW, r)
+			opset(ASRAD, r)
+			opset(ASRAW, r)
+			opset(ARLL, r)
+			opset(ARLLG, r)
+		case ACSG:
+			opset(ACS, r)
+		case ASUB:
+			opset(ASUBC, r)
+			opset(ASUBE, r)
+		case AFMOVD:
+			opset(AFMOVS, r)
+		case AMOVDBR:
+			opset(AMOVWBR, r)
+		case ACMP:
+			opset(ACMPW, r)
+		case ACMPU:
+			opset(ACMPWU, r)
+		case ACEFBRA:
+			opset(ACDFBRA, r)
+			opset(ACEGBRA, r)
+			opset(ACDGBRA, r)
+			opset(ACELFBR, r)
+			opset(ACDLFBR, r)
+			opset(ACELGBR, r)
+			opset(ACDLGBR, r)
+		case ACFEBRA:
+			opset(ACFDBRA, r)
+			opset(ACGEBRA, r)
+			opset(ACGDBRA, r)
+			opset(ACLFEBR, r)
+			opset(ACLFDBR, r)
+			opset(ACLGEBR, r)
+			opset(ACLGDBR, r)
+		case ACMPBEQ:
+			opset(ACMPBGE, r)
+			opset(ACMPBGT, r)
+			opset(ACMPBLE, r)
+			opset(ACMPBLT, r)
+			opset(ACMPBNE, r)
+		case ACMPUBEQ:
+			opset(ACMPUBGE, r)
+			opset(ACMPUBGT, r)
+			opset(ACMPUBLE, r)
+			opset(ACMPUBLT, r)
+			opset(ACMPUBNE, r)
+		case AVL:
+			opset(AVLLEZB, r)
+			opset(AVLLEZH, r)
+			opset(AVLLEZF, r)
+			opset(AVLLEZG, r)
+			opset(AVLREPB, r)
+			opset(AVLREPH, r)
+			opset(AVLREPF, r)
+			opset(AVLREPG, r)
+		case AVLEG:
+			opset(AVLBB, r)
+			opset(AVLEB, r)
+			opset(AVLEH, r)
+			opset(AVLEF, r)
+			opset(AVLEG, r)
+			opset(AVLREP, r)
+		case AVSTEG:
+			opset(AVSTEB, r)
+			opset(AVSTEH, r)
+			opset(AVSTEF, r)
+		case AVSCEG:
+			opset(AVSCEF, r)
+		case AVGEG:
+			opset(AVGEF, r)
+		case AVESLG:
+			opset(AVESLB, r)
+			opset(AVESLH, r)
+			opset(AVESLF, r)
+			opset(AVERLLB, r)
+			opset(AVERLLH, r)
+			opset(AVERLLF, r)
+			opset(AVERLLG, r)
+			opset(AVESRAB, r)
+			opset(AVESRAH, r)
+			opset(AVESRAF, r)
+			opset(AVESRAG, r)
+			opset(AVESRLB, r)
+			opset(AVESRLH, r)
+			opset(AVESRLF, r)
+			opset(AVESRLG, r)
+		case AVLGVG:
+			opset(AVLGVB, r)
+			opset(AVLGVH, r)
+			opset(AVLGVF, r)
+		case AVLVGG:
+			opset(AVLVGB, r)
+			opset(AVLVGH, r)
+			opset(AVLVGF, r)
+		case AVZERO:
+			opset(AVONE, r)
+		case AVREPIG:
+			opset(AVREPIB, r)
+			opset(AVREPIH, r)
+			opset(AVREPIF, r)
+		case AVLEIG:
+			opset(AVLEIB, r)
+			opset(AVLEIH, r)
+			opset(AVLEIF, r)
+		case AVGMG:
+			opset(AVGMB, r)
+			opset(AVGMH, r)
+			opset(AVGMF, r)
+		case AVREPG:
+			opset(AVREPB, r)
+			opset(AVREPH, r)
+			opset(AVREPF, r)
+		case AVERIMG:
+			opset(AVERIMB, r)
+			opset(AVERIMH, r)
+			opset(AVERIMF, r)
+		case AVFTCIDB:
+			opset(AWFTCIDB, r)
+		case AVLR:
+			opset(AVUPHB, r)
+			opset(AVUPHH, r)
+			opset(AVUPHF, r)
+			opset(AVUPLHB, r)
+			opset(AVUPLHH, r)
+			opset(AVUPLHF, r)
+			opset(AVUPLB, r)
+			opset(AVUPLHW, r)
+			opset(AVUPLF, r)
+			opset(AVUPLLB, r)
+			opset(AVUPLLH, r)
+			opset(AVUPLLF, r)
+			opset(AVCLZB, r)
+			opset(AVCLZH, r)
+			opset(AVCLZF, r)
+			opset(AVCLZG, r)
+			opset(AVCTZB, r)
+			opset(AVCTZH, r)
+			opset(AVCTZF, r)
+			opset(AVCTZG, r)
+			opset(AVLDEB, r)
+			opset(AWLDEB, r)
+			opset(AVFLCDB, r)
+			opset(AWFLCDB, r)
+			opset(AVFLNDB, r)
+			opset(AWFLNDB, r)
+			opset(AVFLPDB, r)
+			opset(AWFLPDB, r)
+			opset(AVFSQDB, r)
+			opset(AWFSQDB, r)
+			opset(AVISTRB, r)
+			opset(AVISTRH, r)
+			opset(AVISTRF, r)
+			opset(AVISTRBS, r)
+			opset(AVISTRHS, r)
+			opset(AVISTRFS, r)
+			opset(AVLCB, r)
+			opset(AVLCH, r)
+			opset(AVLCF, r)
+			opset(AVLCG, r)
+			opset(AVLPB, r)
+			opset(AVLPH, r)
+			opset(AVLPF, r)
+			opset(AVLPG, r)
+			opset(AVPOPCT, r)
+			opset(AVSEGB, r)
+			opset(AVSEGH, r)
+			opset(AVSEGF, r)
+		case AVECG:
+			opset(AVECB, r)
+			opset(AVECH, r)
+			opset(AVECF, r)
+			opset(AVECLB, r)
+			opset(AVECLH, r)
+			opset(AVECLF, r)
+			opset(AVECLG, r)
+			opset(AWFCDB, r)
+			opset(AWFKDB, r)
+		case AVCEQG:
+			opset(AVCEQB, r)
+			opset(AVCEQH, r)
+			opset(AVCEQF, r)
+			opset(AVCEQBS, r)
+			opset(AVCEQHS, r)
+			opset(AVCEQFS, r)
+			opset(AVCEQGS, r)
+			opset(AVCHB, r)
+			opset(AVCHH, r)
+			opset(AVCHF, r)
+			opset(AVCHG, r)
+			opset(AVCHBS, r)
+			opset(AVCHHS, r)
+			opset(AVCHFS, r)
+			opset(AVCHGS, r)
+			opset(AVCHLB, r)
+			opset(AVCHLH, r)
+			opset(AVCHLF, r)
+			opset(AVCHLG, r)
+			opset(AVCHLBS, r)
+			opset(AVCHLHS, r)
+			opset(AVCHLFS, r)
+			opset(AVCHLGS, r)
+		case AVFAEF:
+			opset(AVFAEB, r)
+			opset(AVFAEH, r)
+			opset(AVFAEBS, r)
+			opset(AVFAEHS, r)
+			opset(AVFAEFS, r)
+			opset(AVFAEZB, r)
+			opset(AVFAEZH, r)
+			opset(AVFAEZF, r)
+			opset(AVFAEZBS, r)
+			opset(AVFAEZHS, r)
+			opset(AVFAEZFS, r)
+			opset(AVFEEB, r)
+			opset(AVFEEH, r)
+			opset(AVFEEF, r)
+			opset(AVFEEBS, r)
+			opset(AVFEEHS, r)
+			opset(AVFEEFS, r)
+			opset(AVFEEZB, r)
+			opset(AVFEEZH, r)
+			opset(AVFEEZF, r)
+			opset(AVFEEZBS, r)
+			opset(AVFEEZHS, r)
+			opset(AVFEEZFS, r)
+			opset(AVFENEB, r)
+			opset(AVFENEH, r)
+			opset(AVFENEF, r)
+			opset(AVFENEBS, r)
+			opset(AVFENEHS, r)
+			opset(AVFENEFS, r)
+			opset(AVFENEZB, r)
+			opset(AVFENEZH, r)
+			opset(AVFENEZF, r)
+			opset(AVFENEZBS, r)
+			opset(AVFENEZHS, r)
+			opset(AVFENEZFS, r)
+		case AVPKSG:
+			opset(AVPKSH, r)
+			opset(AVPKSF, r)
+			opset(AVPKSHS, r)
+			opset(AVPKSFS, r)
+			opset(AVPKSGS, r)
+			opset(AVPKLSH, r)
+			opset(AVPKLSF, r)
+			opset(AVPKLSG, r)
+			opset(AVPKLSHS, r)
+			opset(AVPKLSFS, r)
+			opset(AVPKLSGS, r)
+		case AVAQ:
+			opset(AVAB, r)
+			opset(AVAH, r)
+			opset(AVAF, r)
+			opset(AVAG, r)
+			opset(AVACCB, r)
+			opset(AVACCH, r)
+			opset(AVACCF, r)
+			opset(AVACCG, r)
+			opset(AVACCQ, r)
+			opset(AVN, r)
+			opset(AVNC, r)
+			opset(AVAVGB, r)
+			opset(AVAVGH, r)
+			opset(AVAVGF, r)
+			opset(AVAVGG, r)
+			opset(AVAVGLB, r)
+			opset(AVAVGLH, r)
+			opset(AVAVGLF, r)
+			opset(AVAVGLG, r)
+			opset(AVCKSM, r)
+			opset(AVX, r)
+			opset(AVFADB, r)
+			opset(AWFADB, r)
+			opset(AVFCEDB, r)
+			opset(AVFCEDBS, r)
+			opset(AWFCEDB, r)
+			opset(AWFCEDBS, r)
+			opset(AVFCHDB, r)
+			opset(AVFCHDBS, r)
+			opset(AWFCHDB, r)
+			opset(AWFCHDBS, r)
+			opset(AVFCHEDB, r)
+			opset(AVFCHEDBS, r)
+			opset(AWFCHEDB, r)
+			opset(AWFCHEDBS, r)
+			opset(AVFMDB, r)
+			opset(AWFMDB, r)
+			opset(AVGFMB, r)
+			opset(AVGFMH, r)
+			opset(AVGFMF, r)
+			opset(AVGFMG, r)
+			opset(AVMXB, r)
+			opset(AVMXH, r)
+			opset(AVMXF, r)
+			opset(AVMXG, r)
+			opset(AVMXLB, r)
+			opset(AVMXLH, r)
+			opset(AVMXLF, r)
+			opset(AVMXLG, r)
+			opset(AVMNB, r)
+			opset(AVMNH, r)
+			opset(AVMNF, r)
+			opset(AVMNG, r)
+			opset(AVMNLB, r)
+			opset(AVMNLH, r)
+			opset(AVMNLF, r)
+			opset(AVMNLG, r)
+			opset(AVMRHB, r)
+			opset(AVMRHH, r)
+			opset(AVMRHF, r)
+			opset(AVMRHG, r)
+			opset(AVMRLB, r)
+			opset(AVMRLH, r)
+			opset(AVMRLF, r)
+			opset(AVMRLG, r)
+			opset(AVMEB, r)
+			opset(AVMEH, r)
+			opset(AVMEF, r)
+			opset(AVMLEB, r)
+			opset(AVMLEH, r)
+			opset(AVMLEF, r)
+			opset(AVMOB, r)
+			opset(AVMOH, r)
+			opset(AVMOF, r)
+			opset(AVMLOB, r)
+			opset(AVMLOH, r)
+			opset(AVMLOF, r)
+			opset(AVMHB, r)
+			opset(AVMHH, r)
+			opset(AVMHF, r)
+			opset(AVMLHB, r)
+			opset(AVMLHH, r)
+			opset(AVMLHF, r)
+			opset(AVMLH, r)
+			opset(AVMLHW, r)
+			opset(AVMLF, r)
+			opset(AVNO, r)
+			opset(AVO, r)
+			opset(AVPKH, r)
+			opset(AVPKF, r)
+			opset(AVPKG, r)
+			opset(AVSUMGH, r)
+			opset(AVSUMGF, r)
+			opset(AVSUMQF, r)
+			opset(AVSUMQG, r)
+			opset(AVSUMB, r)
+			opset(AVSUMH, r)
+		case AVERLLVG:
+			opset(AVERLLVB, r)
+			opset(AVERLLVH, r)
+			opset(AVERLLVF, r)
+			opset(AVESLVB, r)
+			opset(AVESLVH, r)
+			opset(AVESLVF, r)
+			opset(AVESLVG, r)
+			opset(AVESRAVB, r)
+			opset(AVESRAVH, r)
+			opset(AVESRAVF, r)
+			opset(AVESRAVG, r)
+			opset(AVESRLVB, r)
+			opset(AVESRLVH, r)
+			opset(AVESRLVF, r)
+			opset(AVESRLVG, r)
+			opset(AVFDDB, r)
+			opset(AWFDDB, r)
+			opset(AVFSDB, r)
+			opset(AWFSDB, r)
+			opset(AVSL, r)
+			opset(AVSLB, r)
+			opset(AVSRA, r)
+			opset(AVSRAB, r)
+			opset(AVSRL, r)
+			opset(AVSRLB, r)
+			opset(AVSF, r)
+			opset(AVSG, r)
+			opset(AVSQ, r)
+			opset(AVSCBIB, r)
+			opset(AVSCBIH, r)
+			opset(AVSCBIF, r)
+			opset(AVSCBIG, r)
+			opset(AVSCBIQ, r)
+		case AVACQ:
+			opset(AVACCCQ, r)
+			opset(AVGFMAB, r)
+			opset(AVGFMAH, r)
+			opset(AVGFMAF, r)
+			opset(AVGFMAG, r)
+			opset(AVMALB, r)
+			opset(AVMALHW, r)
+			opset(AVMALF, r)
+			opset(AVMAHB, r)
+			opset(AVMAHH, r)
+			opset(AVMAHF, r)
+			opset(AVMALHB, r)
+			opset(AVMALHH, r)
+			opset(AVMALHF, r)
+			opset(AVMAEB, r)
+			opset(AVMAEH, r)
+			opset(AVMAEF, r)
+			opset(AVMALEB, r)
+			opset(AVMALEH, r)
+			opset(AVMALEF, r)
+			opset(AVMAOB, r)
+			opset(AVMAOH, r)
+			opset(AVMAOF, r)
+			opset(AVMALOB, r)
+			opset(AVMALOH, r)
+			opset(AVMALOF, r)
+			opset(AVSTRCB, r)
+			opset(AVSTRCH, r)
+			opset(AVSTRCF, r)
+			opset(AVSTRCBS, r)
+			opset(AVSTRCHS, r)
+			opset(AVSTRCFS, r)
+			opset(AVSTRCZB, r)
+			opset(AVSTRCZH, r)
+			opset(AVSTRCZF, r)
+			opset(AVSTRCZBS, r)
+			opset(AVSTRCZHS, r)
+			opset(AVSTRCZFS, r)
+			opset(AVSBCBIQ, r)
+			opset(AVSBIQ, r)
+		case AVSEL:
+			opset(AVFMADB, r)
+			opset(AWFMADB, r)
+			opset(AVFMSDB, r)
+			opset(AWFMSDB, r)
+			opset(AVPERM, r)
+		}
+	}
+}
+
+const (
+	op_A       uint32 = 0x5A00 // FORMAT_RX1        ADD (32)
+	op_AD      uint32 = 0x6A00 // FORMAT_RX1        ADD NORMALIZED (long HFP)
+	op_ADB     uint32 = 0xED1A // FORMAT_RXE        ADD (long BFP)
+	op_ADBR    uint32 = 0xB31A // FORMAT_RRE        ADD (long BFP)
+	op_ADR     uint32 = 0x2A00 // FORMAT_RR         ADD NORMALIZED (long HFP)
+	op_ADTR    uint32 = 0xB3D2 // FORMAT_RRF1       ADD (long DFP)
+	op_ADTRA   uint32 = 0xB3D2 // FORMAT_RRF1       ADD (long DFP)
+	op_AE      uint32 = 0x7A00 // FORMAT_RX1        ADD NORMALIZED (short HFP)
+	op_AEB     uint32 = 0xED0A // FORMAT_RXE        ADD (short BFP)
+	op_AEBR    uint32 = 0xB30A // FORMAT_RRE        ADD (short BFP)
+	op_AER     uint32 = 0x3A00 // FORMAT_RR         ADD NORMALIZED (short HFP)
+	op_AFI     uint32 = 0xC209 // FORMAT_RIL1       ADD IMMEDIATE (32)
+	op_AG      uint32 = 0xE308 // FORMAT_RXY1       ADD (64)
+	op_AGF     uint32 = 0xE318 // FORMAT_RXY1       ADD (64<-32)
+	op_AGFI    uint32 = 0xC208 // FORMAT_RIL1       ADD IMMEDIATE (64<-32)
+	op_AGFR    uint32 = 0xB918 // FORMAT_RRE        ADD (64<-32)
+	op_AGHI    uint32 = 0xA70B // FORMAT_RI1        ADD HALFWORD IMMEDIATE (64)
+	op_AGHIK   uint32 = 0xECD9 // FORMAT_RIE4       ADD IMMEDIATE (64<-16)
+	op_AGR     uint32 = 0xB908 // FORMAT_RRE        ADD (64)
+	op_AGRK    uint32 = 0xB9E8 // FORMAT_RRF1       ADD (64)
+	op_AGSI    uint32 = 0xEB7A // FORMAT_SIY        ADD IMMEDIATE (64<-8)
+	op_AH      uint32 = 0x4A00 // FORMAT_RX1        ADD HALFWORD
+	op_AHHHR   uint32 = 0xB9C8 // FORMAT_RRF1       ADD HIGH (32)
+	op_AHHLR   uint32 = 0xB9D8 // FORMAT_RRF1       ADD HIGH (32)
+	op_AHI     uint32 = 0xA70A // FORMAT_RI1        ADD HALFWORD IMMEDIATE (32)
+	op_AHIK    uint32 = 0xECD8 // FORMAT_RIE4       ADD IMMEDIATE (32<-16)
+	op_AHY     uint32 = 0xE37A // FORMAT_RXY1       ADD HALFWORD
+	op_AIH     uint32 = 0xCC08 // FORMAT_RIL1       ADD IMMEDIATE HIGH (32)
+	op_AL      uint32 = 0x5E00 // FORMAT_RX1        ADD LOGICAL (32)
+	op_ALC     uint32 = 0xE398 // FORMAT_RXY1       ADD LOGICAL WITH CARRY (32)
+	op_ALCG    uint32 = 0xE388 // FORMAT_RXY1       ADD LOGICAL WITH CARRY (64)
+	op_ALCGR   uint32 = 0xB988 // FORMAT_RRE        ADD LOGICAL WITH CARRY (64)
+	op_ALCR    uint32 = 0xB998 // FORMAT_RRE        ADD LOGICAL WITH CARRY (32)
+	op_ALFI    uint32 = 0xC20B // FORMAT_RIL1       ADD LOGICAL IMMEDIATE (32)
+	op_ALG     uint32 = 0xE30A // FORMAT_RXY1       ADD LOGICAL (64)
+	op_ALGF    uint32 = 0xE31A // FORMAT_RXY1       ADD LOGICAL (64<-32)
+	op_ALGFI   uint32 = 0xC20A // FORMAT_RIL1       ADD LOGICAL IMMEDIATE (64<-32)
+	op_ALGFR   uint32 = 0xB91A // FORMAT_RRE        ADD LOGICAL (64<-32)
+	op_ALGHSIK uint32 = 0xECDB // FORMAT_RIE4       ADD LOGICAL WITH SIGNED IMMEDIATE (64<-16)
+	op_ALGR    uint32 = 0xB90A // FORMAT_RRE        ADD LOGICAL (64)
+	op_ALGRK   uint32 = 0xB9EA // FORMAT_RRF1       ADD LOGICAL (64)
+	op_ALGSI   uint32 = 0xEB7E // FORMAT_SIY        ADD LOGICAL WITH SIGNED IMMEDIATE (64<-8)
+	op_ALHHHR  uint32 = 0xB9CA // FORMAT_RRF1       ADD LOGICAL HIGH (32)
+	op_ALHHLR  uint32 = 0xB9DA // FORMAT_RRF1       ADD LOGICAL HIGH (32)
+	op_ALHSIK  uint32 = 0xECDA // FORMAT_RIE4       ADD LOGICAL WITH SIGNED IMMEDIATE (32<-16)
+	op_ALR     uint32 = 0x1E00 // FORMAT_RR         ADD LOGICAL (32)
+	op_ALRK    uint32 = 0xB9FA // FORMAT_RRF1       ADD LOGICAL (32)
+	op_ALSI    uint32 = 0xEB6E // FORMAT_SIY        ADD LOGICAL WITH SIGNED IMMEDIATE (32<-8)
+	op_ALSIH   uint32 = 0xCC0A // FORMAT_RIL1       ADD LOGICAL WITH SIGNED IMMEDIATE HIGH (32)
+	op_ALSIHN  uint32 = 0xCC0B // FORMAT_RIL1       ADD LOGICAL WITH SIGNED IMMEDIATE HIGH (32)
+	op_ALY     uint32 = 0xE35E // FORMAT_RXY1       ADD LOGICAL (32)
+	op_AP      uint32 = 0xFA00 // FORMAT_SS2        ADD DECIMAL
+	op_AR      uint32 = 0x1A00 // FORMAT_RR         ADD (32)
+	op_ARK     uint32 = 0xB9F8 // FORMAT_RRF1       ADD (32)
+	op_ASI     uint32 = 0xEB6A // FORMAT_SIY        ADD IMMEDIATE (32<-8)
+	op_AU      uint32 = 0x7E00 // FORMAT_RX1        ADD UNNORMALIZED (short HFP)
+	op_AUR     uint32 = 0x3E00 // FORMAT_RR         ADD UNNORMALIZED (short HFP)
+	op_AW      uint32 = 0x6E00 // FORMAT_RX1        ADD UNNORMALIZED (long HFP)
+	op_AWR     uint32 = 0x2E00 // FORMAT_RR         ADD UNNORMALIZED (long HFP)
+	op_AXBR    uint32 = 0xB34A // FORMAT_RRE        ADD (extended BFP)
+	op_AXR     uint32 = 0x3600 // FORMAT_RR         ADD NORMALIZED (extended HFP)
+	op_AXTR    uint32 = 0xB3DA // FORMAT_RRF1       ADD (extended DFP)
+	op_AXTRA   uint32 = 0xB3DA // FORMAT_RRF1       ADD (extended DFP)
+	op_AY      uint32 = 0xE35A // FORMAT_RXY1       ADD (32)
+	op_BAKR    uint32 = 0xB240 // FORMAT_RRE        BRANCH AND STACK
+	op_BAL     uint32 = 0x4500 // FORMAT_RX1        BRANCH AND LINK
+	op_BALR    uint32 = 0x0500 // FORMAT_RR         BRANCH AND LINK
+	op_BAS     uint32 = 0x4D00 // FORMAT_RX1        BRANCH AND SAVE
+	op_BASR    uint32 = 0x0D00 // FORMAT_RR         BRANCH AND SAVE
+	op_BASSM   uint32 = 0x0C00 // FORMAT_RR         BRANCH AND SAVE AND SET MODE
+	op_BC      uint32 = 0x4700 // FORMAT_RX2        BRANCH ON CONDITION
+	op_BCR     uint32 = 0x0700 // FORMAT_RR         BRANCH ON CONDITION
+	op_BCT     uint32 = 0x4600 // FORMAT_RX1        BRANCH ON COUNT (32)
+	op_BCTG    uint32 = 0xE346 // FORMAT_RXY1       BRANCH ON COUNT (64)
+	op_BCTGR   uint32 = 0xB946 // FORMAT_RRE        BRANCH ON COUNT (64)
+	op_BCTR    uint32 = 0x0600 // FORMAT_RR         BRANCH ON COUNT (32)
+	op_BPP     uint32 = 0xC700 // FORMAT_SMI        BRANCH PREDICTION PRELOAD
+	op_BPRP    uint32 = 0xC500 // FORMAT_MII        BRANCH PREDICTION RELATIVE PRELOAD
+	op_BRAS    uint32 = 0xA705 // FORMAT_RI2        BRANCH RELATIVE AND SAVE
+	op_BRASL   uint32 = 0xC005 // FORMAT_RIL2       BRANCH RELATIVE AND SAVE LONG
+	op_BRC     uint32 = 0xA704 // FORMAT_RI3        BRANCH RELATIVE ON CONDITION
+	op_BRCL    uint32 = 0xC004 // FORMAT_RIL3       BRANCH RELATIVE ON CONDITION LONG
+	op_BRCT    uint32 = 0xA706 // FORMAT_RI2        BRANCH RELATIVE ON COUNT (32)
+	op_BRCTG   uint32 = 0xA707 // FORMAT_RI2        BRANCH RELATIVE ON COUNT (64)
+	op_BRCTH   uint32 = 0xCC06 // FORMAT_RIL2       BRANCH RELATIVE ON COUNT HIGH (32)
+	op_BRXH    uint32 = 0x8400 // FORMAT_RSI        BRANCH RELATIVE ON INDEX HIGH (32)
+	op_BRXHG   uint32 = 0xEC44 // FORMAT_RIE5       BRANCH RELATIVE ON INDEX HIGH (64)
+	op_BRXLE   uint32 = 0x8500 // FORMAT_RSI        BRANCH RELATIVE ON INDEX LOW OR EQ. (32)
+	op_BRXLG   uint32 = 0xEC45 // FORMAT_RIE5       BRANCH RELATIVE ON INDEX LOW OR EQ. (64)
+	op_BSA     uint32 = 0xB25A // FORMAT_RRE        BRANCH AND SET AUTHORITY
+	op_BSG     uint32 = 0xB258 // FORMAT_RRE        BRANCH IN SUBSPACE GROUP
+	op_BSM     uint32 = 0x0B00 // FORMAT_RR         BRANCH AND SET MODE
+	op_BXH     uint32 = 0x8600 // FORMAT_RS1        BRANCH ON INDEX HIGH (32)
+	op_BXHG    uint32 = 0xEB44 // FORMAT_RSY1       BRANCH ON INDEX HIGH (64)
+	op_BXLE    uint32 = 0x8700 // FORMAT_RS1        BRANCH ON INDEX LOW OR EQUAL (32)
+	op_BXLEG   uint32 = 0xEB45 // FORMAT_RSY1       BRANCH ON INDEX LOW OR EQUAL (64)
+	op_C       uint32 = 0x5900 // FORMAT_RX1        COMPARE (32)
+	op_CD      uint32 = 0x6900 // FORMAT_RX1        COMPARE (long HFP)
+	op_CDB     uint32 = 0xED19 // FORMAT_RXE        COMPARE (long BFP)
+	op_CDBR    uint32 = 0xB319 // FORMAT_RRE        COMPARE (long BFP)
+	op_CDFBR   uint32 = 0xB395 // FORMAT_RRE        CONVERT FROM FIXED (32 to long BFP)
+	op_CDFBRA  uint32 = 0xB395 // FORMAT_RRF5       CONVERT FROM FIXED (32 to long BFP)
+	op_CDFR    uint32 = 0xB3B5 // FORMAT_RRE        CONVERT FROM FIXED (32 to long HFP)
+	op_CDFTR   uint32 = 0xB951 // FORMAT_RRE        CONVERT FROM FIXED (32 to long DFP)
+	op_CDGBR   uint32 = 0xB3A5 // FORMAT_RRE        CONVERT FROM FIXED (64 to long BFP)
+	op_CDGBRA  uint32 = 0xB3A5 // FORMAT_RRF5       CONVERT FROM FIXED (64 to long BFP)
+	op_CDGR    uint32 = 0xB3C5 // FORMAT_RRE        CONVERT FROM FIXED (64 to long HFP)
+	op_CDGTR   uint32 = 0xB3F1 // FORMAT_RRE        CONVERT FROM FIXED (64 to long DFP)
+	op_CDGTRA  uint32 = 0xB3F1 // FORMAT_RRF5       CONVERT FROM FIXED (64 to long DFP)
+	op_CDLFBR  uint32 = 0xB391 // FORMAT_RRF5       CONVERT FROM LOGICAL (32 to long BFP)
+	op_CDLFTR  uint32 = 0xB953 // FORMAT_RRF5       CONVERT FROM LOGICAL (32 to long DFP)
+	op_CDLGBR  uint32 = 0xB3A1 // FORMAT_RRF5       CONVERT FROM LOGICAL (64 to long BFP)
+	op_CDLGTR  uint32 = 0xB952 // FORMAT_RRF5       CONVERT FROM LOGICAL (64 to long DFP)
+	op_CDR     uint32 = 0x2900 // FORMAT_RR         COMPARE (long HFP)
+	op_CDS     uint32 = 0xBB00 // FORMAT_RS1        COMPARE DOUBLE AND SWAP (32)
+	op_CDSG    uint32 = 0xEB3E // FORMAT_RSY1       COMPARE DOUBLE AND SWAP (64)
+	op_CDSTR   uint32 = 0xB3F3 // FORMAT_RRE        CONVERT FROM SIGNED PACKED (64 to long DFP)
+	op_CDSY    uint32 = 0xEB31 // FORMAT_RSY1       COMPARE DOUBLE AND SWAP (32)
+	op_CDTR    uint32 = 0xB3E4 // FORMAT_RRE        COMPARE (long DFP)
+	op_CDUTR   uint32 = 0xB3F2 // FORMAT_RRE        CONVERT FROM UNSIGNED PACKED (64 to long DFP)
+	op_CDZT    uint32 = 0xEDAA // FORMAT_RSL        CONVERT FROM ZONED (to long DFP)
+	op_CE      uint32 = 0x7900 // FORMAT_RX1        COMPARE (short HFP)
+	op_CEB     uint32 = 0xED09 // FORMAT_RXE        COMPARE (short BFP)
+	op_CEBR    uint32 = 0xB309 // FORMAT_RRE        COMPARE (short BFP)
+	op_CEDTR   uint32 = 0xB3F4 // FORMAT_RRE        COMPARE BIASED EXPONENT (long DFP)
+	op_CEFBR   uint32 = 0xB394 // FORMAT_RRE        CONVERT FROM FIXED (32 to short BFP)
+	op_CEFBRA  uint32 = 0xB394 // FORMAT_RRF5       CONVERT FROM FIXED (32 to short BFP)
+	op_CEFR    uint32 = 0xB3B4 // FORMAT_RRE        CONVERT FROM FIXED (32 to short HFP)
+	op_CEGBR   uint32 = 0xB3A4 // FORMAT_RRE        CONVERT FROM FIXED (64 to short BFP)
+	op_CEGBRA  uint32 = 0xB3A4 // FORMAT_RRF5       CONVERT FROM FIXED (64 to short BFP)
+	op_CEGR    uint32 = 0xB3C4 // FORMAT_RRE        CONVERT FROM FIXED (64 to short HFP)
+	op_CELFBR  uint32 = 0xB390 // FORMAT_RRF5       CONVERT FROM LOGICAL (32 to short BFP)
+	op_CELGBR  uint32 = 0xB3A0 // FORMAT_RRF5       CONVERT FROM LOGICAL (64 to short BFP)
+	op_CER     uint32 = 0x3900 // FORMAT_RR         COMPARE (short HFP)
+	op_CEXTR   uint32 = 0xB3FC // FORMAT_RRE        COMPARE BIASED EXPONENT (extended DFP)
+	op_CFC     uint32 = 0xB21A // FORMAT_S          COMPARE AND FORM CODEWORD
+	op_CFDBR   uint32 = 0xB399 // FORMAT_RRF5       CONVERT TO FIXED (long BFP to 32)
+	op_CFDBRA  uint32 = 0xB399 // FORMAT_RRF5       CONVERT TO FIXED (long BFP to 32)
+	op_CFDR    uint32 = 0xB3B9 // FORMAT_RRF5       CONVERT TO FIXED (long HFP to 32)
+	op_CFDTR   uint32 = 0xB941 // FORMAT_RRF5       CONVERT TO FIXED (long DFP to 32)
+	op_CFEBR   uint32 = 0xB398 // FORMAT_RRF5       CONVERT TO FIXED (short BFP to 32)
+	op_CFEBRA  uint32 = 0xB398 // FORMAT_RRF5       CONVERT TO FIXED (short BFP to 32)
+	op_CFER    uint32 = 0xB3B8 // FORMAT_RRF5       CONVERT TO FIXED (short HFP to 32)
+	op_CFI     uint32 = 0xC20D // FORMAT_RIL1       COMPARE IMMEDIATE (32)
+	op_CFXBR   uint32 = 0xB39A // FORMAT_RRF5       CONVERT TO FIXED (extended BFP to 32)
+	op_CFXBRA  uint32 = 0xB39A // FORMAT_RRF5       CONVERT TO FIXED (extended BFP to 32)
+	op_CFXR    uint32 = 0xB3BA // FORMAT_RRF5       CONVERT TO FIXED (extended HFP to 32)
+	op_CFXTR   uint32 = 0xB949 // FORMAT_RRF5       CONVERT TO FIXED (extended DFP to 32)
+	op_CG      uint32 = 0xE320 // FORMAT_RXY1       COMPARE (64)
+	op_CGDBR   uint32 = 0xB3A9 // FORMAT_RRF5       CONVERT TO FIXED (long BFP to 64)
+	op_CGDBRA  uint32 = 0xB3A9 // FORMAT_RRF5       CONVERT TO FIXED (long BFP to 64)
+	op_CGDR    uint32 = 0xB3C9 // FORMAT_RRF5       CONVERT TO FIXED (long HFP to 64)
+	op_CGDTR   uint32 = 0xB3E1 // FORMAT_RRF5       CONVERT TO FIXED (long DFP to 64)
+	op_CGDTRA  uint32 = 0xB3E1 // FORMAT_RRF5       CONVERT TO FIXED (long DFP to 64)
+	op_CGEBR   uint32 = 0xB3A8 // FORMAT_RRF5       CONVERT TO FIXED (short BFP to 64)
+	op_CGEBRA  uint32 = 0xB3A8 // FORMAT_RRF5       CONVERT TO FIXED (short BFP to 64)
+	op_CGER    uint32 = 0xB3C8 // FORMAT_RRF5       CONVERT TO FIXED (short HFP to 64)
+	op_CGF     uint32 = 0xE330 // FORMAT_RXY1       COMPARE (64<-32)
+	op_CGFI    uint32 = 0xC20C // FORMAT_RIL1       COMPARE IMMEDIATE (64<-32)
+	op_CGFR    uint32 = 0xB930 // FORMAT_RRE        COMPARE (64<-32)
+	op_CGFRL   uint32 = 0xC60C // FORMAT_RIL2       COMPARE RELATIVE LONG (64<-32)
+	op_CGH     uint32 = 0xE334 // FORMAT_RXY1       COMPARE HALFWORD (64<-16)
+	op_CGHI    uint32 = 0xA70F // FORMAT_RI1        COMPARE HALFWORD IMMEDIATE (64<-16)
+	op_CGHRL   uint32 = 0xC604 // FORMAT_RIL2       COMPARE HALFWORD RELATIVE LONG (64<-16)
+	op_CGHSI   uint32 = 0xE558 // FORMAT_SIL        COMPARE HALFWORD IMMEDIATE (64<-16)
+	op_CGIB    uint32 = 0xECFC // FORMAT_RIS        COMPARE IMMEDIATE AND BRANCH (64<-8)
+	op_CGIJ    uint32 = 0xEC7C // FORMAT_RIE3       COMPARE IMMEDIATE AND BRANCH RELATIVE (64<-8)
+	op_CGIT    uint32 = 0xEC70 // FORMAT_RIE1       COMPARE IMMEDIATE AND TRAP (64<-16)
+	op_CGR     uint32 = 0xB920 // FORMAT_RRE        COMPARE (64)
+	op_CGRB    uint32 = 0xECE4 // FORMAT_RRS        COMPARE AND BRANCH (64)
+	op_CGRJ    uint32 = 0xEC64 // FORMAT_RIE2       COMPARE AND BRANCH RELATIVE (64)
+	op_CGRL    uint32 = 0xC608 // FORMAT_RIL2       COMPARE RELATIVE LONG (64)
+	op_CGRT    uint32 = 0xB960 // FORMAT_RRF3       COMPARE AND TRAP (64)
+	op_CGXBR   uint32 = 0xB3AA // FORMAT_RRF5       CONVERT TO FIXED (extended BFP to 64)
+	op_CGXBRA  uint32 = 0xB3AA // FORMAT_RRF5       CONVERT TO FIXED (extended BFP to 64)
+	op_CGXR    uint32 = 0xB3CA // FORMAT_RRF5       CONVERT TO FIXED (extended HFP to 64)
+	op_CGXTR   uint32 = 0xB3E9 // FORMAT_RRF5       CONVERT TO FIXED (extended DFP to 64)
+	op_CGXTRA  uint32 = 0xB3E9 // FORMAT_RRF5       CONVERT TO FIXED (extended DFP to 64)
+	op_CH      uint32 = 0x4900 // FORMAT_RX1        COMPARE HALFWORD (32<-16)
+	op_CHF     uint32 = 0xE3CD // FORMAT_RXY1       COMPARE HIGH (32)
+	op_CHHR    uint32 = 0xB9CD // FORMAT_RRE        COMPARE HIGH (32)
+	op_CHHSI   uint32 = 0xE554 // FORMAT_SIL        COMPARE HALFWORD IMMEDIATE (16)
+	op_CHI     uint32 = 0xA70E // FORMAT_RI1        COMPARE HALFWORD IMMEDIATE (32<-16)
+	op_CHLR    uint32 = 0xB9DD // FORMAT_RRE        COMPARE HIGH (32)
+	op_CHRL    uint32 = 0xC605 // FORMAT_RIL2       COMPARE HALFWORD RELATIVE LONG (32<-16)
+	op_CHSI    uint32 = 0xE55C // FORMAT_SIL        COMPARE HALFWORD IMMEDIATE (32<-16)
+	op_CHY     uint32 = 0xE379 // FORMAT_RXY1       COMPARE HALFWORD (32<-16)
+	op_CIB     uint32 = 0xECFE // FORMAT_RIS        COMPARE IMMEDIATE AND BRANCH (32<-8)
+	op_CIH     uint32 = 0xCC0D // FORMAT_RIL1       COMPARE IMMEDIATE HIGH (32)
+	op_CIJ     uint32 = 0xEC7E // FORMAT_RIE3       COMPARE IMMEDIATE AND BRANCH RELATIVE (32<-8)
+	op_CIT     uint32 = 0xEC72 // FORMAT_RIE1       COMPARE IMMEDIATE AND TRAP (32<-16)
+	op_CKSM    uint32 = 0xB241 // FORMAT_RRE        CHECKSUM
+	op_CL      uint32 = 0x5500 // FORMAT_RX1        COMPARE LOGICAL (32)
+	op_CLC     uint32 = 0xD500 // FORMAT_SS1        COMPARE LOGICAL (character)
+	op_CLCL    uint32 = 0x0F00 // FORMAT_RR         COMPARE LOGICAL LONG
+	op_CLCLE   uint32 = 0xA900 // FORMAT_RS1        COMPARE LOGICAL LONG EXTENDED
+	op_CLCLU   uint32 = 0xEB8F // FORMAT_RSY1       COMPARE LOGICAL LONG UNICODE
+	op_CLFDBR  uint32 = 0xB39D // FORMAT_RRF5       CONVERT TO LOGICAL (long BFP to 32)
+	op_CLFDTR  uint32 = 0xB943 // FORMAT_RRF5       CONVERT TO LOGICAL (long DFP to 32)
+	op_CLFEBR  uint32 = 0xB39C // FORMAT_RRF5       CONVERT TO LOGICAL (short BFP to 32)
+	op_CLFHSI  uint32 = 0xE55D // FORMAT_SIL        COMPARE LOGICAL IMMEDIATE (32<-16)
+	op_CLFI    uint32 = 0xC20F // FORMAT_RIL1       COMPARE LOGICAL IMMEDIATE (32)
+	op_CLFIT   uint32 = 0xEC73 // FORMAT_RIE1       COMPARE LOGICAL IMMEDIATE AND TRAP (32<-16)
+	op_CLFXBR  uint32 = 0xB39E // FORMAT_RRF5       CONVERT TO LOGICAL (extended BFP to 32)
+	op_CLFXTR  uint32 = 0xB94B // FORMAT_RRF5       CONVERT TO LOGICAL (extended DFP to 32)
+	op_CLG     uint32 = 0xE321 // FORMAT_RXY1       COMPARE LOGICAL (64)
+	op_CLGDBR  uint32 = 0xB3AD // FORMAT_RRF5       CONVERT TO LOGICAL (long BFP to 64)
+	op_CLGDTR  uint32 = 0xB942 // FORMAT_RRF5       CONVERT TO LOGICAL (long DFP to 64)
+	op_CLGEBR  uint32 = 0xB3AC // FORMAT_RRF5       CONVERT TO LOGICAL (short BFP to 64)
+	op_CLGF    uint32 = 0xE331 // FORMAT_RXY1       COMPARE LOGICAL (64<-32)
+	op_CLGFI   uint32 = 0xC20E // FORMAT_RIL1       COMPARE LOGICAL IMMEDIATE (64<-32)
+	op_CLGFR   uint32 = 0xB931 // FORMAT_RRE        COMPARE LOGICAL (64<-32)
+	op_CLGFRL  uint32 = 0xC60E // FORMAT_RIL2       COMPARE LOGICAL RELATIVE LONG (64<-32)
+	op_CLGHRL  uint32 = 0xC606 // FORMAT_RIL2       COMPARE LOGICAL RELATIVE LONG (64<-16)
+	op_CLGHSI  uint32 = 0xE559 // FORMAT_SIL        COMPARE LOGICAL IMMEDIATE (64<-16)
+	op_CLGIB   uint32 = 0xECFD // FORMAT_RIS        COMPARE LOGICAL IMMEDIATE AND BRANCH (64<-8)
+	op_CLGIJ   uint32 = 0xEC7D // FORMAT_RIE3       COMPARE LOGICAL IMMEDIATE AND BRANCH RELATIVE (64<-8)
+	op_CLGIT   uint32 = 0xEC71 // FORMAT_RIE1       COMPARE LOGICAL IMMEDIATE AND TRAP (64<-16)
+	op_CLGR    uint32 = 0xB921 // FORMAT_RRE        COMPARE LOGICAL (64)
+	op_CLGRB   uint32 = 0xECE5 // FORMAT_RRS        COMPARE LOGICAL AND BRANCH (64)
+	op_CLGRJ   uint32 = 0xEC65 // FORMAT_RIE2       COMPARE LOGICAL AND BRANCH RELATIVE (64)
+	op_CLGRL   uint32 = 0xC60A // FORMAT_RIL2       COMPARE LOGICAL RELATIVE LONG (64)
+	op_CLGRT   uint32 = 0xB961 // FORMAT_RRF3       COMPARE LOGICAL AND TRAP (64)
+	op_CLGT    uint32 = 0xEB2B // FORMAT_RSY2       COMPARE LOGICAL AND TRAP (64)
+	op_CLGXBR  uint32 = 0xB3AE // FORMAT_RRF5       CONVERT TO LOGICAL (extended BFP to 64)
+	op_CLGXTR  uint32 = 0xB94A // FORMAT_RRF5       CONVERT TO LOGICAL (extended DFP to 64)
+	op_CLHF    uint32 = 0xE3CF // FORMAT_RXY1       COMPARE LOGICAL HIGH (32)
+	op_CLHHR   uint32 = 0xB9CF // FORMAT_RRE        COMPARE LOGICAL HIGH (32)
+	op_CLHHSI  uint32 = 0xE555 // FORMAT_SIL        COMPARE LOGICAL IMMEDIATE (16)
+	op_CLHLR   uint32 = 0xB9DF // FORMAT_RRE        COMPARE LOGICAL HIGH (32)
+	op_CLHRL   uint32 = 0xC607 // FORMAT_RIL2       COMPARE LOGICAL RELATIVE LONG (32<-16)
+	op_CLI     uint32 = 0x9500 // FORMAT_SI         COMPARE LOGICAL (immediate)
+	op_CLIB    uint32 = 0xECFF // FORMAT_RIS        COMPARE LOGICAL IMMEDIATE AND BRANCH (32<-8)
+	op_CLIH    uint32 = 0xCC0F // FORMAT_RIL1       COMPARE LOGICAL IMMEDIATE HIGH (32)
+	op_CLIJ    uint32 = 0xEC7F // FORMAT_RIE3       COMPARE LOGICAL IMMEDIATE AND BRANCH RELATIVE (32<-8)
+	op_CLIY    uint32 = 0xEB55 // FORMAT_SIY        COMPARE LOGICAL (immediate)
+	op_CLM     uint32 = 0xBD00 // FORMAT_RS2        COMPARE LOGICAL CHAR. UNDER MASK (low)
+	op_CLMH    uint32 = 0xEB20 // FORMAT_RSY2       COMPARE LOGICAL CHAR. UNDER MASK (high)
+	op_CLMY    uint32 = 0xEB21 // FORMAT_RSY2       COMPARE LOGICAL CHAR. UNDER MASK (low)
+	op_CLR     uint32 = 0x1500 // FORMAT_RR         COMPARE LOGICAL (32)
+	op_CLRB    uint32 = 0xECF7 // FORMAT_RRS        COMPARE LOGICAL AND BRANCH (32)
+	op_CLRJ    uint32 = 0xEC77 // FORMAT_RIE2       COMPARE LOGICAL AND BRANCH RELATIVE (32)
+	op_CLRL    uint32 = 0xC60F // FORMAT_RIL2       COMPARE LOGICAL RELATIVE LONG (32)
+	op_CLRT    uint32 = 0xB973 // FORMAT_RRF3       COMPARE LOGICAL AND TRAP (32)
+	op_CLST    uint32 = 0xB25D // FORMAT_RRE        COMPARE LOGICAL STRING
+	op_CLT     uint32 = 0xEB23 // FORMAT_RSY2       COMPARE LOGICAL AND TRAP (32)
+	op_CLY     uint32 = 0xE355 // FORMAT_RXY1       COMPARE LOGICAL (32)
+	op_CMPSC   uint32 = 0xB263 // FORMAT_RRE        COMPRESSION CALL
+	op_CP      uint32 = 0xF900 // FORMAT_SS2        COMPARE DECIMAL
+	op_CPSDR   uint32 = 0xB372 // FORMAT_RRF2       COPY SIGN (long)
+	op_CPYA    uint32 = 0xB24D // FORMAT_RRE        COPY ACCESS
+	op_CR      uint32 = 0x1900 // FORMAT_RR         COMPARE (32)
+	op_CRB     uint32 = 0xECF6 // FORMAT_RRS        COMPARE AND BRANCH (32)
+	op_CRDTE   uint32 = 0xB98F // FORMAT_RRF2       COMPARE AND REPLACE DAT TABLE ENTRY
+	op_CRJ     uint32 = 0xEC76 // FORMAT_RIE2       COMPARE AND BRANCH RELATIVE (32)
+	op_CRL     uint32 = 0xC60D // FORMAT_RIL2       COMPARE RELATIVE LONG (32)
+	op_CRT     uint32 = 0xB972 // FORMAT_RRF3       COMPARE AND TRAP (32)
+	op_CS      uint32 = 0xBA00 // FORMAT_RS1        COMPARE AND SWAP (32)
+	op_CSCH    uint32 = 0xB230 // FORMAT_S          CLEAR SUBCHANNEL
+	op_CSDTR   uint32 = 0xB3E3 // FORMAT_RRF4       CONVERT TO SIGNED PACKED (long DFP to 64)
+	op_CSG     uint32 = 0xEB30 // FORMAT_RSY1       COMPARE AND SWAP (64)
+	op_CSP     uint32 = 0xB250 // FORMAT_RRE        COMPARE AND SWAP AND PURGE
+	op_CSPG    uint32 = 0xB98A // FORMAT_RRE        COMPARE AND SWAP AND PURGE
+	op_CSST    uint32 = 0xC802 // FORMAT_SSF        COMPARE AND SWAP AND STORE
+	op_CSXTR   uint32 = 0xB3EB // FORMAT_RRF4       CONVERT TO SIGNED PACKED (extended DFP to 128)
+	op_CSY     uint32 = 0xEB14 // FORMAT_RSY1       COMPARE AND SWAP (32)
+	op_CU12    uint32 = 0xB2A7 // FORMAT_RRF3       CONVERT UTF-8 TO UTF-16
+	op_CU14    uint32 = 0xB9B0 // FORMAT_RRF3       CONVERT UTF-8 TO UTF-32
+	op_CU21    uint32 = 0xB2A6 // FORMAT_RRF3       CONVERT UTF-16 TO UTF-8
+	op_CU24    uint32 = 0xB9B1 // FORMAT_RRF3       CONVERT UTF-16 TO UTF-32
+	op_CU41    uint32 = 0xB9B2 // FORMAT_RRE        CONVERT UTF-32 TO UTF-8
+	op_CU42    uint32 = 0xB9B3 // FORMAT_RRE        CONVERT UTF-32 TO UTF-16
+	op_CUDTR   uint32 = 0xB3E2 // FORMAT_RRE        CONVERT TO UNSIGNED PACKED (long DFP to 64)
+	op_CUSE    uint32 = 0xB257 // FORMAT_RRE        COMPARE UNTIL SUBSTRING EQUAL
+	op_CUTFU   uint32 = 0xB2A7 // FORMAT_RRF3       CONVERT UTF-8 TO UNICODE
+	op_CUUTF   uint32 = 0xB2A6 // FORMAT_RRF3       CONVERT UNICODE TO UTF-8
+	op_CUXTR   uint32 = 0xB3EA // FORMAT_RRE        CONVERT TO UNSIGNED PACKED (extended DFP to 128)
+	op_CVB     uint32 = 0x4F00 // FORMAT_RX1        CONVERT TO BINARY (32)
+	op_CVBG    uint32 = 0xE30E // FORMAT_RXY1       CONVERT TO BINARY (64)
+	op_CVBY    uint32 = 0xE306 // FORMAT_RXY1       CONVERT TO BINARY (32)
+	op_CVD     uint32 = 0x4E00 // FORMAT_RX1        CONVERT TO DECIMAL (32)
+	op_CVDG    uint32 = 0xE32E // FORMAT_RXY1       CONVERT TO DECIMAL (64)
+	op_CVDY    uint32 = 0xE326 // FORMAT_RXY1       CONVERT TO DECIMAL (32)
+	op_CXBR    uint32 = 0xB349 // FORMAT_RRE        COMPARE (extended BFP)
+	op_CXFBR   uint32 = 0xB396 // FORMAT_RRE        CONVERT FROM FIXED (32 to extended BFP)
+	op_CXFBRA  uint32 = 0xB396 // FORMAT_RRF5       CONVERT FROM FIXED (32 to extended BFP)
+	op_CXFR    uint32 = 0xB3B6 // FORMAT_RRE        CONVERT FROM FIXED (32 to extended HFP)
+	op_CXFTR   uint32 = 0xB959 // FORMAT_RRE        CONVERT FROM FIXED (32 to extended DFP)
+	op_CXGBR   uint32 = 0xB3A6 // FORMAT_RRE        CONVERT FROM FIXED (64 to extended BFP)
+	op_CXGBRA  uint32 = 0xB3A6 // FORMAT_RRF5       CONVERT FROM FIXED (64 to extended BFP)
+	op_CXGR    uint32 = 0xB3C6 // FORMAT_RRE        CONVERT FROM FIXED (64 to extended HFP)
+	op_CXGTR   uint32 = 0xB3F9 // FORMAT_RRE        CONVERT FROM FIXED (64 to extended DFP)
+	op_CXGTRA  uint32 = 0xB3F9 // FORMAT_RRF5       CONVERT FROM FIXED (64 to extended DFP)
+	op_CXLFBR  uint32 = 0xB392 // FORMAT_RRF5       CONVERT FROM LOGICAL (32 to extended BFP)
+	op_CXLFTR  uint32 = 0xB95B // FORMAT_RRF5       CONVERT FROM LOGICAL (32 to extended DFP)
+	op_CXLGBR  uint32 = 0xB3A2 // FORMAT_RRF5       CONVERT FROM LOGICAL (64 to extended BFP)
+	op_CXLGTR  uint32 = 0xB95A // FORMAT_RRF5       CONVERT FROM LOGICAL (64 to extended DFP)
+	op_CXR     uint32 = 0xB369 // FORMAT_RRE        COMPARE (extended HFP)
+	op_CXSTR   uint32 = 0xB3FB // FORMAT_RRE        CONVERT FROM SIGNED PACKED (128 to extended DFP)
+	op_CXTR    uint32 = 0xB3EC // FORMAT_RRE        COMPARE (extended DFP)
+	op_CXUTR   uint32 = 0xB3FA // FORMAT_RRE        CONVERT FROM UNSIGNED PACKED (128 to ext. DFP)
+	op_CXZT    uint32 = 0xEDAB // FORMAT_RSL        CONVERT FROM ZONED (to extended DFP)
+	op_CY      uint32 = 0xE359 // FORMAT_RXY1       COMPARE (32)
+	op_CZDT    uint32 = 0xEDA8 // FORMAT_RSL        CONVERT TO ZONED (from long DFP)
+	op_CZXT    uint32 = 0xEDA9 // FORMAT_RSL        CONVERT TO ZONED (from extended DFP)
+	op_D       uint32 = 0x5D00 // FORMAT_RX1        DIVIDE (32<-64)
+	op_DD      uint32 = 0x6D00 // FORMAT_RX1        DIVIDE (long HFP)
+	op_DDB     uint32 = 0xED1D // FORMAT_RXE        DIVIDE (long BFP)
+	op_DDBR    uint32 = 0xB31D // FORMAT_RRE        DIVIDE (long BFP)
+	op_DDR     uint32 = 0x2D00 // FORMAT_RR         DIVIDE (long HFP)
+	op_DDTR    uint32 = 0xB3D1 // FORMAT_RRF1       DIVIDE (long DFP)
+	op_DDTRA   uint32 = 0xB3D1 // FORMAT_RRF1       DIVIDE (long DFP)
+	op_DE      uint32 = 0x7D00 // FORMAT_RX1        DIVIDE (short HFP)
+	op_DEB     uint32 = 0xED0D // FORMAT_RXE        DIVIDE (short BFP)
+	op_DEBR    uint32 = 0xB30D // FORMAT_RRE        DIVIDE (short BFP)
+	op_DER     uint32 = 0x3D00 // FORMAT_RR         DIVIDE (short HFP)
+	op_DIDBR   uint32 = 0xB35B // FORMAT_RRF2       DIVIDE TO INTEGER (long BFP)
+	op_DIEBR   uint32 = 0xB353 // FORMAT_RRF2       DIVIDE TO INTEGER (short BFP)
+	op_DL      uint32 = 0xE397 // FORMAT_RXY1       DIVIDE LOGICAL (32<-64)
+	op_DLG     uint32 = 0xE387 // FORMAT_RXY1       DIVIDE LOGICAL (64<-128)
+	op_DLGR    uint32 = 0xB987 // FORMAT_RRE        DIVIDE LOGICAL (64<-128)
+	op_DLR     uint32 = 0xB997 // FORMAT_RRE        DIVIDE LOGICAL (32<-64)
+	op_DP      uint32 = 0xFD00 // FORMAT_SS2        DIVIDE DECIMAL
+	op_DR      uint32 = 0x1D00 // FORMAT_RR         DIVIDE (32<-64)
+	op_DSG     uint32 = 0xE30D // FORMAT_RXY1       DIVIDE SINGLE (64)
+	op_DSGF    uint32 = 0xE31D // FORMAT_RXY1       DIVIDE SINGLE (64<-32)
+	op_DSGFR   uint32 = 0xB91D // FORMAT_RRE        DIVIDE SINGLE (64<-32)
+	op_DSGR    uint32 = 0xB90D // FORMAT_RRE        DIVIDE SINGLE (64)
+	op_DXBR    uint32 = 0xB34D // FORMAT_RRE        DIVIDE (extended BFP)
+	op_DXR     uint32 = 0xB22D // FORMAT_RRE        DIVIDE (extended HFP)
+	op_DXTR    uint32 = 0xB3D9 // FORMAT_RRF1       DIVIDE (extended DFP)
+	op_DXTRA   uint32 = 0xB3D9 // FORMAT_RRF1       DIVIDE (extended DFP)
+	op_EAR     uint32 = 0xB24F // FORMAT_RRE        EXTRACT ACCESS
+	op_ECAG    uint32 = 0xEB4C // FORMAT_RSY1       EXTRACT CACHE ATTRIBUTE
+	op_ECTG    uint32 = 0xC801 // FORMAT_SSF        EXTRACT CPU TIME
+	op_ED      uint32 = 0xDE00 // FORMAT_SS1        EDIT
+	op_EDMK    uint32 = 0xDF00 // FORMAT_SS1        EDIT AND MARK
+	op_EEDTR   uint32 = 0xB3E5 // FORMAT_RRE        EXTRACT BIASED EXPONENT (long DFP to 64)
+	op_EEXTR   uint32 = 0xB3ED // FORMAT_RRE        EXTRACT BIASED EXPONENT (extended DFP to 64)
+	op_EFPC    uint32 = 0xB38C // FORMAT_RRE        EXTRACT FPC
+	op_EPAIR   uint32 = 0xB99A // FORMAT_RRE        EXTRACT PRIMARY ASN AND INSTANCE
+	op_EPAR    uint32 = 0xB226 // FORMAT_RRE        EXTRACT PRIMARY ASN
+	op_EPSW    uint32 = 0xB98D // FORMAT_RRE        EXTRACT PSW
+	op_EREG    uint32 = 0xB249 // FORMAT_RRE        EXTRACT STACKED REGISTERS (32)
+	op_EREGG   uint32 = 0xB90E // FORMAT_RRE        EXTRACT STACKED REGISTERS (64)
+	op_ESAIR   uint32 = 0xB99B // FORMAT_RRE        EXTRACT SECONDARY ASN AND INSTANCE
+	op_ESAR    uint32 = 0xB227 // FORMAT_RRE        EXTRACT SECONDARY ASN
+	op_ESDTR   uint32 = 0xB3E7 // FORMAT_RRE        EXTRACT SIGNIFICANCE (long DFP)
+	op_ESEA    uint32 = 0xB99D // FORMAT_RRE        EXTRACT AND SET EXTENDED AUTHORITY
+	op_ESTA    uint32 = 0xB24A // FORMAT_RRE        EXTRACT STACKED STATE
+	op_ESXTR   uint32 = 0xB3EF // FORMAT_RRE        EXTRACT SIGNIFICANCE (extended DFP)
+	op_ETND    uint32 = 0xB2EC // FORMAT_RRE        EXTRACT TRANSACTION NESTING DEPTH
+	op_EX      uint32 = 0x4400 // FORMAT_RX1        EXECUTE
+	op_EXRL    uint32 = 0xC600 // FORMAT_RIL2       EXECUTE RELATIVE LONG
+	op_FIDBR   uint32 = 0xB35F // FORMAT_RRF5       LOAD FP INTEGER (long BFP)
+	op_FIDBRA  uint32 = 0xB35F // FORMAT_RRF5       LOAD FP INTEGER (long BFP)
+	op_FIDR    uint32 = 0xB37F // FORMAT_RRE        LOAD FP INTEGER (long HFP)
+	op_FIDTR   uint32 = 0xB3D7 // FORMAT_RRF5       LOAD FP INTEGER (long DFP)
+	op_FIEBR   uint32 = 0xB357 // FORMAT_RRF5       LOAD FP INTEGER (short BFP)
+	op_FIEBRA  uint32 = 0xB357 // FORMAT_RRF5       LOAD FP INTEGER (short BFP)
+	op_FIER    uint32 = 0xB377 // FORMAT_RRE        LOAD FP INTEGER (short HFP)
+	op_FIXBR   uint32 = 0xB347 // FORMAT_RRF5       LOAD FP INTEGER (extended BFP)
+	op_FIXBRA  uint32 = 0xB347 // FORMAT_RRF5       LOAD FP INTEGER (extended BFP)
+	op_FIXR    uint32 = 0xB367 // FORMAT_RRE        LOAD FP INTEGER (extended HFP)
+	op_FIXTR   uint32 = 0xB3DF // FORMAT_RRF5       LOAD FP INTEGER (extended DFP)
+	op_FLOGR   uint32 = 0xB983 // FORMAT_RRE        FIND LEFTMOST ONE
+	op_HDR     uint32 = 0x2400 // FORMAT_RR         HALVE (long HFP)
+	op_HER     uint32 = 0x3400 // FORMAT_RR         HALVE (short HFP)
+	op_HSCH    uint32 = 0xB231 // FORMAT_S          HALT SUBCHANNEL
+	op_IAC     uint32 = 0xB224 // FORMAT_RRE        INSERT ADDRESS SPACE CONTROL
+	op_IC      uint32 = 0x4300 // FORMAT_RX1        INSERT CHARACTER
+	op_ICM     uint32 = 0xBF00 // FORMAT_RS2        INSERT CHARACTERS UNDER MASK (low)
+	op_ICMH    uint32 = 0xEB80 // FORMAT_RSY2       INSERT CHARACTERS UNDER MASK (high)
+	op_ICMY    uint32 = 0xEB81 // FORMAT_RSY2       INSERT CHARACTERS UNDER MASK (low)
+	op_ICY     uint32 = 0xE373 // FORMAT_RXY1       INSERT CHARACTER
+	op_IDTE    uint32 = 0xB98E // FORMAT_RRF2       INVALIDATE DAT TABLE ENTRY
+	op_IEDTR   uint32 = 0xB3F6 // FORMAT_RRF2       INSERT BIASED EXPONENT (64 to long DFP)
+	op_IEXTR   uint32 = 0xB3FE // FORMAT_RRF2       INSERT BIASED EXPONENT (64 to extended DFP)
+	op_IIHF    uint32 = 0xC008 // FORMAT_RIL1       INSERT IMMEDIATE (high)
+	op_IIHH    uint32 = 0xA500 // FORMAT_RI1        INSERT IMMEDIATE (high high)
+	op_IIHL    uint32 = 0xA501 // FORMAT_RI1        INSERT IMMEDIATE (high low)
+	op_IILF    uint32 = 0xC009 // FORMAT_RIL1       INSERT IMMEDIATE (low)
+	op_IILH    uint32 = 0xA502 // FORMAT_RI1        INSERT IMMEDIATE (low high)
+	op_IILL    uint32 = 0xA503 // FORMAT_RI1        INSERT IMMEDIATE (low low)
+	op_IPK     uint32 = 0xB20B // FORMAT_S          INSERT PSW KEY
+	op_IPM     uint32 = 0xB222 // FORMAT_RRE        INSERT PROGRAM MASK
+	op_IPTE    uint32 = 0xB221 // FORMAT_RRF1       INVALIDATE PAGE TABLE ENTRY
+	op_ISKE    uint32 = 0xB229 // FORMAT_RRE        INSERT STORAGE KEY EXTENDED
+	op_IVSK    uint32 = 0xB223 // FORMAT_RRE        INSERT VIRTUAL STORAGE KEY
+	op_KDB     uint32 = 0xED18 // FORMAT_RXE        COMPARE AND SIGNAL (long BFP)
+	op_KDBR    uint32 = 0xB318 // FORMAT_RRE        COMPARE AND SIGNAL (long BFP)
+	op_KDTR    uint32 = 0xB3E0 // FORMAT_RRE        COMPARE AND SIGNAL (long DFP)
+	op_KEB     uint32 = 0xED08 // FORMAT_RXE        COMPARE AND SIGNAL (short BFP)
+	op_KEBR    uint32 = 0xB308 // FORMAT_RRE        COMPARE AND SIGNAL (short BFP)
+	op_KIMD    uint32 = 0xB93E // FORMAT_RRE        COMPUTE INTERMEDIATE MESSAGE DIGEST
+	op_KLMD    uint32 = 0xB93F // FORMAT_RRE        COMPUTE LAST MESSAGE DIGEST
+	op_KM      uint32 = 0xB92E // FORMAT_RRE        CIPHER MESSAGE
+	op_KMAC    uint32 = 0xB91E // FORMAT_RRE        COMPUTE MESSAGE AUTHENTICATION CODE
+	op_KMC     uint32 = 0xB92F // FORMAT_RRE        CIPHER MESSAGE WITH CHAINING
+	op_KMCTR   uint32 = 0xB92D // FORMAT_RRF2       CIPHER MESSAGE WITH COUNTER
+	op_KMF     uint32 = 0xB92A // FORMAT_RRE        CIPHER MESSAGE WITH CFB
+	op_KMO     uint32 = 0xB92B // FORMAT_RRE        CIPHER MESSAGE WITH OFB
+	op_KXBR    uint32 = 0xB348 // FORMAT_RRE        COMPARE AND SIGNAL (extended BFP)
+	op_KXTR    uint32 = 0xB3E8 // FORMAT_RRE        COMPARE AND SIGNAL (extended DFP)
+	op_L       uint32 = 0x5800 // FORMAT_RX1        LOAD (32)
+	op_LA      uint32 = 0x4100 // FORMAT_RX1        LOAD ADDRESS
+	op_LAA     uint32 = 0xEBF8 // FORMAT_RSY1       LOAD AND ADD (32)
+	op_LAAG    uint32 = 0xEBE8 // FORMAT_RSY1       LOAD AND ADD (64)
+	op_LAAL    uint32 = 0xEBFA // FORMAT_RSY1       LOAD AND ADD LOGICAL (32)
+	op_LAALG   uint32 = 0xEBEA // FORMAT_RSY1       LOAD AND ADD LOGICAL (64)
+	op_LAE     uint32 = 0x5100 // FORMAT_RX1        LOAD ADDRESS EXTENDED
+	op_LAEY    uint32 = 0xE375 // FORMAT_RXY1       LOAD ADDRESS EXTENDED
+	op_LAM     uint32 = 0x9A00 // FORMAT_RS1        LOAD ACCESS MULTIPLE
+	op_LAMY    uint32 = 0xEB9A // FORMAT_RSY1       LOAD ACCESS MULTIPLE
+	op_LAN     uint32 = 0xEBF4 // FORMAT_RSY1       LOAD AND AND (32)
+	op_LANG    uint32 = 0xEBE4 // FORMAT_RSY1       LOAD AND AND (64)
+	op_LAO     uint32 = 0xEBF6 // FORMAT_RSY1       LOAD AND OR (32)
+	op_LAOG    uint32 = 0xEBE6 // FORMAT_RSY1       LOAD AND OR (64)
+	op_LARL    uint32 = 0xC000 // FORMAT_RIL2       LOAD ADDRESS RELATIVE LONG
+	op_LASP    uint32 = 0xE500 // FORMAT_SSE        LOAD ADDRESS SPACE PARAMETERS
+	op_LAT     uint32 = 0xE39F // FORMAT_RXY1       LOAD AND TRAP (32L<-32)
+	op_LAX     uint32 = 0xEBF7 // FORMAT_RSY1       LOAD AND EXCLUSIVE OR (32)
+	op_LAXG    uint32 = 0xEBE7 // FORMAT_RSY1       LOAD AND EXCLUSIVE OR (64)
+	op_LAY     uint32 = 0xE371 // FORMAT_RXY1       LOAD ADDRESS
+	op_LB      uint32 = 0xE376 // FORMAT_RXY1       LOAD BYTE (32)
+	op_LBH     uint32 = 0xE3C0 // FORMAT_RXY1       LOAD BYTE HIGH (32<-8)
+	op_LBR     uint32 = 0xB926 // FORMAT_RRE        LOAD BYTE (32)
+	op_LCDBR   uint32 = 0xB313 // FORMAT_RRE        LOAD COMPLEMENT (long BFP)
+	op_LCDFR   uint32 = 0xB373 // FORMAT_RRE        LOAD COMPLEMENT (long)
+	op_LCDR    uint32 = 0x2300 // FORMAT_RR         LOAD COMPLEMENT (long HFP)
+	op_LCEBR   uint32 = 0xB303 // FORMAT_RRE        LOAD COMPLEMENT (short BFP)
+	op_LCER    uint32 = 0x3300 // FORMAT_RR         LOAD COMPLEMENT (short HFP)
+	op_LCGFR   uint32 = 0xB913 // FORMAT_RRE        LOAD COMPLEMENT (64<-32)
+	op_LCGR    uint32 = 0xB903 // FORMAT_RRE        LOAD COMPLEMENT (64)
+	op_LCR     uint32 = 0x1300 // FORMAT_RR         LOAD COMPLEMENT (32)
+	op_LCTL    uint32 = 0xB700 // FORMAT_RS1        LOAD CONTROL (32)
+	op_LCTLG   uint32 = 0xEB2F // FORMAT_RSY1       LOAD CONTROL (64)
+	op_LCXBR   uint32 = 0xB343 // FORMAT_RRE        LOAD COMPLEMENT (extended BFP)
+	op_LCXR    uint32 = 0xB363 // FORMAT_RRE        LOAD COMPLEMENT (extended HFP)
+	op_LD      uint32 = 0x6800 // FORMAT_RX1        LOAD (long)
+	op_LDE     uint32 = 0xED24 // FORMAT_RXE        LOAD LENGTHENED (short to long HFP)
+	op_LDEB    uint32 = 0xED04 // FORMAT_RXE        LOAD LENGTHENED (short to long BFP)
+	op_LDEBR   uint32 = 0xB304 // FORMAT_RRE        LOAD LENGTHENED (short to long BFP)
+	op_LDER    uint32 = 0xB324 // FORMAT_RRE        LOAD LENGTHENED (short to long HFP)
+	op_LDETR   uint32 = 0xB3D4 // FORMAT_RRF4       LOAD LENGTHENED (short to long DFP)
+	op_LDGR    uint32 = 0xB3C1 // FORMAT_RRE        LOAD FPR FROM GR (64 to long)
+	op_LDR     uint32 = 0x2800 // FORMAT_RR         LOAD (long)
+	op_LDXBR   uint32 = 0xB345 // FORMAT_RRE        LOAD ROUNDED (extended to long BFP)
+	op_LDXBRA  uint32 = 0xB345 // FORMAT_RRF5       LOAD ROUNDED (extended to long BFP)
+	op_LDXR    uint32 = 0x2500 // FORMAT_RR         LOAD ROUNDED (extended to long HFP)
+	op_LDXTR   uint32 = 0xB3DD // FORMAT_RRF5       LOAD ROUNDED (extended to long DFP)
+	op_LDY     uint32 = 0xED65 // FORMAT_RXY1       LOAD (long)
+	op_LE      uint32 = 0x7800 // FORMAT_RX1        LOAD (short)
+	op_LEDBR   uint32 = 0xB344 // FORMAT_RRE        LOAD ROUNDED (long to short BFP)
+	op_LEDBRA  uint32 = 0xB344 // FORMAT_RRF5       LOAD ROUNDED (long to short BFP)
+	op_LEDR    uint32 = 0x3500 // FORMAT_RR         LOAD ROUNDED (long to short HFP)
+	op_LEDTR   uint32 = 0xB3D5 // FORMAT_RRF5       LOAD ROUNDED (long to short DFP)
+	op_LER     uint32 = 0x3800 // FORMAT_RR         LOAD (short)
+	op_LEXBR   uint32 = 0xB346 // FORMAT_RRE        LOAD ROUNDED (extended to short BFP)
+	op_LEXBRA  uint32 = 0xB346 // FORMAT_RRF5       LOAD ROUNDED (extended to short BFP)
+	op_LEXR    uint32 = 0xB366 // FORMAT_RRE        LOAD ROUNDED (extended to short HFP)
+	op_LEY     uint32 = 0xED64 // FORMAT_RXY1       LOAD (short)
+	op_LFAS    uint32 = 0xB2BD // FORMAT_S          LOAD FPC AND SIGNAL
+	op_LFH     uint32 = 0xE3CA // FORMAT_RXY1       LOAD HIGH (32)
+	op_LFHAT   uint32 = 0xE3C8 // FORMAT_RXY1       LOAD HIGH AND TRAP (32H<-32)
+	op_LFPC    uint32 = 0xB29D // FORMAT_S          LOAD FPC
+	op_LG      uint32 = 0xE304 // FORMAT_RXY1       LOAD (64)
+	op_LGAT    uint32 = 0xE385 // FORMAT_RXY1       LOAD AND TRAP (64)
+	op_LGB     uint32 = 0xE377 // FORMAT_RXY1       LOAD BYTE (64)
+	op_LGBR    uint32 = 0xB906 // FORMAT_RRE        LOAD BYTE (64)
+	op_LGDR    uint32 = 0xB3CD // FORMAT_RRE        LOAD GR FROM FPR (long to 64)
+	op_LGF     uint32 = 0xE314 // FORMAT_RXY1       LOAD (64<-32)
+	op_LGFI    uint32 = 0xC001 // FORMAT_RIL1       LOAD IMMEDIATE (64<-32)
+	op_LGFR    uint32 = 0xB914 // FORMAT_RRE        LOAD (64<-32)
+	op_LGFRL   uint32 = 0xC40C // FORMAT_RIL2       LOAD RELATIVE LONG (64<-32)
+	op_LGH     uint32 = 0xE315 // FORMAT_RXY1       LOAD HALFWORD (64)
+	op_LGHI    uint32 = 0xA709 // FORMAT_RI1        LOAD HALFWORD IMMEDIATE (64)
+	op_LGHR    uint32 = 0xB907 // FORMAT_RRE        LOAD HALFWORD (64)
+	op_LGHRL   uint32 = 0xC404 // FORMAT_RIL2       LOAD HALFWORD RELATIVE LONG (64<-16)
+	op_LGR     uint32 = 0xB904 // FORMAT_RRE        LOAD (64)
+	op_LGRL    uint32 = 0xC408 // FORMAT_RIL2       LOAD RELATIVE LONG (64)
+	op_LH      uint32 = 0x4800 // FORMAT_RX1        LOAD HALFWORD (32)
+	op_LHH     uint32 = 0xE3C4 // FORMAT_RXY1       LOAD HALFWORD HIGH (32<-16)
+	op_LHI     uint32 = 0xA708 // FORMAT_RI1        LOAD HALFWORD IMMEDIATE (32)
+	op_LHR     uint32 = 0xB927 // FORMAT_RRE        LOAD HALFWORD (32)
+	op_LHRL    uint32 = 0xC405 // FORMAT_RIL2       LOAD HALFWORD RELATIVE LONG (32<-16)
+	op_LHY     uint32 = 0xE378 // FORMAT_RXY1       LOAD HALFWORD (32)
+	op_LLC     uint32 = 0xE394 // FORMAT_RXY1       LOAD LOGICAL CHARACTER (32)
+	op_LLCH    uint32 = 0xE3C2 // FORMAT_RXY1       LOAD LOGICAL CHARACTER HIGH (32<-8)
+	op_LLCR    uint32 = 0xB994 // FORMAT_RRE        LOAD LOGICAL CHARACTER (32)
+	op_LLGC    uint32 = 0xE390 // FORMAT_RXY1       LOAD LOGICAL CHARACTER (64)
+	op_LLGCR   uint32 = 0xB984 // FORMAT_RRE        LOAD LOGICAL CHARACTER (64)
+	op_LLGF    uint32 = 0xE316 // FORMAT_RXY1       LOAD LOGICAL (64<-32)
+	op_LLGFAT  uint32 = 0xE39D // FORMAT_RXY1       LOAD LOGICAL AND TRAP (64<-32)
+	op_LLGFR   uint32 = 0xB916 // FORMAT_RRE        LOAD LOGICAL (64<-32)
+	op_LLGFRL  uint32 = 0xC40E // FORMAT_RIL2       LOAD LOGICAL RELATIVE LONG (64<-32)
+	op_LLGH    uint32 = 0xE391 // FORMAT_RXY1       LOAD LOGICAL HALFWORD (64)
+	op_LLGHR   uint32 = 0xB985 // FORMAT_RRE        LOAD LOGICAL HALFWORD (64)
+	op_LLGHRL  uint32 = 0xC406 // FORMAT_RIL2       LOAD LOGICAL HALFWORD RELATIVE LONG (64<-16)
+	op_LLGT    uint32 = 0xE317 // FORMAT_RXY1       LOAD LOGICAL THIRTY ONE BITS
+	op_LLGTAT  uint32 = 0xE39C // FORMAT_RXY1       LOAD LOGICAL THIRTY ONE BITS AND TRAP (64<-31)
+	op_LLGTR   uint32 = 0xB917 // FORMAT_RRE        LOAD LOGICAL THIRTY ONE BITS
+	op_LLH     uint32 = 0xE395 // FORMAT_RXY1       LOAD LOGICAL HALFWORD (32)
+	op_LLHH    uint32 = 0xE3C6 // FORMAT_RXY1       LOAD LOGICAL HALFWORD HIGH (32<-16)
+	op_LLHR    uint32 = 0xB995 // FORMAT_RRE        LOAD LOGICAL HALFWORD (32)
+	op_LLHRL   uint32 = 0xC402 // FORMAT_RIL2       LOAD LOGICAL HALFWORD RELATIVE LONG (32<-16)
+	op_LLIHF   uint32 = 0xC00E // FORMAT_RIL1       LOAD LOGICAL IMMEDIATE (high)
+	op_LLIHH   uint32 = 0xA50C // FORMAT_RI1        LOAD LOGICAL IMMEDIATE (high high)
+	op_LLIHL   uint32 = 0xA50D // FORMAT_RI1        LOAD LOGICAL IMMEDIATE (high low)
+	op_LLILF   uint32 = 0xC00F // FORMAT_RIL1       LOAD LOGICAL IMMEDIATE (low)
+	op_LLILH   uint32 = 0xA50E // FORMAT_RI1        LOAD LOGICAL IMMEDIATE (low high)
+	op_LLILL   uint32 = 0xA50F // FORMAT_RI1        LOAD LOGICAL IMMEDIATE (low low)
+	op_LM      uint32 = 0x9800 // FORMAT_RS1        LOAD MULTIPLE (32)
+	op_LMD     uint32 = 0xEF00 // FORMAT_SS5        LOAD MULTIPLE DISJOINT
+	op_LMG     uint32 = 0xEB04 // FORMAT_RSY1       LOAD MULTIPLE (64)
+	op_LMH     uint32 = 0xEB96 // FORMAT_RSY1       LOAD MULTIPLE HIGH
+	op_LMY     uint32 = 0xEB98 // FORMAT_RSY1       LOAD MULTIPLE (32)
+	op_LNDBR   uint32 = 0xB311 // FORMAT_RRE        LOAD NEGATIVE (long BFP)
+	op_LNDFR   uint32 = 0xB371 // FORMAT_RRE        LOAD NEGATIVE (long)
+	op_LNDR    uint32 = 0x2100 // FORMAT_RR         LOAD NEGATIVE (long HFP)
+	op_LNEBR   uint32 = 0xB301 // FORMAT_RRE        LOAD NEGATIVE (short BFP)
+	op_LNER    uint32 = 0x3100 // FORMAT_RR         LOAD NEGATIVE (short HFP)
+	op_LNGFR   uint32 = 0xB911 // FORMAT_RRE        LOAD NEGATIVE (64<-32)
+	op_LNGR    uint32 = 0xB901 // FORMAT_RRE        LOAD NEGATIVE (64)
+	op_LNR     uint32 = 0x1100 // FORMAT_RR         LOAD NEGATIVE (32)
+	op_LNXBR   uint32 = 0xB341 // FORMAT_RRE        LOAD NEGATIVE (extended BFP)
+	op_LNXR    uint32 = 0xB361 // FORMAT_RRE        LOAD NEGATIVE (extended HFP)
+	op_LOC     uint32 = 0xEBF2 // FORMAT_RSY2       LOAD ON CONDITION (32)
+	op_LOCG    uint32 = 0xEBE2 // FORMAT_RSY2       LOAD ON CONDITION (64)
+	op_LOCGR   uint32 = 0xB9E2 // FORMAT_RRF3       LOAD ON CONDITION (64)
+	op_LOCR    uint32 = 0xB9F2 // FORMAT_RRF3       LOAD ON CONDITION (32)
+	op_LPD     uint32 = 0xC804 // FORMAT_SSF        LOAD PAIR DISJOINT (32)
+	op_LPDBR   uint32 = 0xB310 // FORMAT_RRE        LOAD POSITIVE (long BFP)
+	op_LPDFR   uint32 = 0xB370 // FORMAT_RRE        LOAD POSITIVE (long)
+	op_LPDG    uint32 = 0xC805 // FORMAT_SSF        LOAD PAIR DISJOINT (64)
+	op_LPDR    uint32 = 0x2000 // FORMAT_RR         LOAD POSITIVE (long HFP)
+	op_LPEBR   uint32 = 0xB300 // FORMAT_RRE        LOAD POSITIVE (short BFP)
+	op_LPER    uint32 = 0x3000 // FORMAT_RR         LOAD POSITIVE (short HFP)
+	op_LPGFR   uint32 = 0xB910 // FORMAT_RRE        LOAD POSITIVE (64<-32)
+	op_LPGR    uint32 = 0xB900 // FORMAT_RRE        LOAD POSITIVE (64)
+	op_LPQ     uint32 = 0xE38F // FORMAT_RXY1       LOAD PAIR FROM QUADWORD
+	op_LPR     uint32 = 0x1000 // FORMAT_RR         LOAD POSITIVE (32)
+	op_LPSW    uint32 = 0x8200 // FORMAT_S          LOAD PSW
+	op_LPSWE   uint32 = 0xB2B2 // FORMAT_S          LOAD PSW EXTENDED
+	op_LPTEA   uint32 = 0xB9AA // FORMAT_RRF2       LOAD PAGE TABLE ENTRY ADDRESS
+	op_LPXBR   uint32 = 0xB340 // FORMAT_RRE        LOAD POSITIVE (extended BFP)
+	op_LPXR    uint32 = 0xB360 // FORMAT_RRE        LOAD POSITIVE (extended HFP)
+	op_LR      uint32 = 0x1800 // FORMAT_RR         LOAD (32)
+	op_LRA     uint32 = 0xB100 // FORMAT_RX1        LOAD REAL ADDRESS (32)
+	op_LRAG    uint32 = 0xE303 // FORMAT_RXY1       LOAD REAL ADDRESS (64)
+	op_LRAY    uint32 = 0xE313 // FORMAT_RXY1       LOAD REAL ADDRESS (32)
+	op_LRDR    uint32 = 0x2500 // FORMAT_RR         LOAD ROUNDED (extended to long HFP)
+	op_LRER    uint32 = 0x3500 // FORMAT_RR         LOAD ROUNDED (long to short HFP)
+	op_LRL     uint32 = 0xC40D // FORMAT_RIL2       LOAD RELATIVE LONG (32)
+	op_LRV     uint32 = 0xE31E // FORMAT_RXY1       LOAD REVERSED (32)
+	op_LRVG    uint32 = 0xE30F // FORMAT_RXY1       LOAD REVERSED (64)
+	op_LRVGR   uint32 = 0xB90F // FORMAT_RRE        LOAD REVERSED (64)
+	op_LRVH    uint32 = 0xE31F // FORMAT_RXY1       LOAD REVERSED (16)
+	op_LRVR    uint32 = 0xB91F // FORMAT_RRE        LOAD REVERSED (32)
+	op_LT      uint32 = 0xE312 // FORMAT_RXY1       LOAD AND TEST (32)
+	op_LTDBR   uint32 = 0xB312 // FORMAT_RRE        LOAD AND TEST (long BFP)
+	op_LTDR    uint32 = 0x2200 // FORMAT_RR         LOAD AND TEST (long HFP)
+	op_LTDTR   uint32 = 0xB3D6 // FORMAT_RRE        LOAD AND TEST (long DFP)
+	op_LTEBR   uint32 = 0xB302 // FORMAT_RRE        LOAD AND TEST (short BFP)
+	op_LTER    uint32 = 0x3200 // FORMAT_RR         LOAD AND TEST (short HFP)
+	op_LTG     uint32 = 0xE302 // FORMAT_RXY1       LOAD AND TEST (64)
+	op_LTGF    uint32 = 0xE332 // FORMAT_RXY1       LOAD AND TEST (64<-32)
+	op_LTGFR   uint32 = 0xB912 // FORMAT_RRE        LOAD AND TEST (64<-32)
+	op_LTGR    uint32 = 0xB902 // FORMAT_RRE        LOAD AND TEST (64)
+	op_LTR     uint32 = 0x1200 // FORMAT_RR         LOAD AND TEST (32)
+	op_LTXBR   uint32 = 0xB342 // FORMAT_RRE        LOAD AND TEST (extended BFP)
+	op_LTXR    uint32 = 0xB362 // FORMAT_RRE        LOAD AND TEST (extended HFP)
+	op_LTXTR   uint32 = 0xB3DE // FORMAT_RRE        LOAD AND TEST (extended DFP)
+	op_LURA    uint32 = 0xB24B // FORMAT_RRE        LOAD USING REAL ADDRESS (32)
+	op_LURAG   uint32 = 0xB905 // FORMAT_RRE        LOAD USING REAL ADDRESS (64)
+	op_LXD     uint32 = 0xED25 // FORMAT_RXE        LOAD LENGTHENED (long to extended HFP)
+	op_LXDB    uint32 = 0xED05 // FORMAT_RXE        LOAD LENGTHENED (long to extended BFP)
+	op_LXDBR   uint32 = 0xB305 // FORMAT_RRE        LOAD LENGTHENED (long to extended BFP)
+	op_LXDR    uint32 = 0xB325 // FORMAT_RRE        LOAD LENGTHENED (long to extended HFP)
+	op_LXDTR   uint32 = 0xB3DC // FORMAT_RRF4       LOAD LENGTHENED (long to extended DFP)
+	op_LXE     uint32 = 0xED26 // FORMAT_RXE        LOAD LENGTHENED (short to extended HFP)
+	op_LXEB    uint32 = 0xED06 // FORMAT_RXE        LOAD LENGTHENED (short to extended BFP)
+	op_LXEBR   uint32 = 0xB306 // FORMAT_RRE        LOAD LENGTHENED (short to extended BFP)
+	op_LXER    uint32 = 0xB326 // FORMAT_RRE        LOAD LENGTHENED (short to extended HFP)
+	op_LXR     uint32 = 0xB365 // FORMAT_RRE        LOAD (extended)
+	op_LY      uint32 = 0xE358 // FORMAT_RXY1       LOAD (32)
+	op_LZDR    uint32 = 0xB375 // FORMAT_RRE        LOAD ZERO (long)
+	op_LZER    uint32 = 0xB374 // FORMAT_RRE        LOAD ZERO (short)
+	op_LZXR    uint32 = 0xB376 // FORMAT_RRE        LOAD ZERO (extended)
+	op_M       uint32 = 0x5C00 // FORMAT_RX1        MULTIPLY (64<-32)
+	op_MAD     uint32 = 0xED3E // FORMAT_RXF        MULTIPLY AND ADD (long HFP)
+	op_MADB    uint32 = 0xED1E // FORMAT_RXF        MULTIPLY AND ADD (long BFP)
+	op_MADBR   uint32 = 0xB31E // FORMAT_RRD        MULTIPLY AND ADD (long BFP)
+	op_MADR    uint32 = 0xB33E // FORMAT_RRD        MULTIPLY AND ADD (long HFP)
+	op_MAE     uint32 = 0xED2E // FORMAT_RXF        MULTIPLY AND ADD (short HFP)
+	op_MAEB    uint32 = 0xED0E // FORMAT_RXF        MULTIPLY AND ADD (short BFP)
+	op_MAEBR   uint32 = 0xB30E // FORMAT_RRD        MULTIPLY AND ADD (short BFP)
+	op_MAER    uint32 = 0xB32E // FORMAT_RRD        MULTIPLY AND ADD (short HFP)
+	op_MAY     uint32 = 0xED3A // FORMAT_RXF        MULTIPLY & ADD UNNORMALIZED (long to ext. HFP)
+	op_MAYH    uint32 = 0xED3C // FORMAT_RXF        MULTIPLY AND ADD UNNRM. (long to ext. high HFP)
+	op_MAYHR   uint32 = 0xB33C // FORMAT_RRD        MULTIPLY AND ADD UNNRM. (long to ext. high HFP)
+	op_MAYL    uint32 = 0xED38 // FORMAT_RXF        MULTIPLY AND ADD UNNRM. (long to ext. low HFP)
+	op_MAYLR   uint32 = 0xB338 // FORMAT_RRD        MULTIPLY AND ADD UNNRM. (long to ext. low HFP)
+	op_MAYR    uint32 = 0xB33A // FORMAT_RRD        MULTIPLY & ADD UNNORMALIZED (long to ext. HFP)
+	op_MC      uint32 = 0xAF00 // FORMAT_SI         MONITOR CALL
+	op_MD      uint32 = 0x6C00 // FORMAT_RX1        MULTIPLY (long HFP)
+	op_MDB     uint32 = 0xED1C // FORMAT_RXE        MULTIPLY (long BFP)
+	op_MDBR    uint32 = 0xB31C // FORMAT_RRE        MULTIPLY (long BFP)
+	op_MDE     uint32 = 0x7C00 // FORMAT_RX1        MULTIPLY (short to long HFP)
+	op_MDEB    uint32 = 0xED0C // FORMAT_RXE        MULTIPLY (short to long BFP)
+	op_MDEBR   uint32 = 0xB30C // FORMAT_RRE        MULTIPLY (short to long BFP)
+	op_MDER    uint32 = 0x3C00 // FORMAT_RR         MULTIPLY (short to long HFP)
+	op_MDR     uint32 = 0x2C00 // FORMAT_RR         MULTIPLY (long HFP)
+	op_MDTR    uint32 = 0xB3D0 // FORMAT_RRF1       MULTIPLY (long DFP)
+	op_MDTRA   uint32 = 0xB3D0 // FORMAT_RRF1       MULTIPLY (long DFP)
+	op_ME      uint32 = 0x7C00 // FORMAT_RX1        MULTIPLY (short to long HFP)
+	op_MEE     uint32 = 0xED37 // FORMAT_RXE        MULTIPLY (short HFP)
+	op_MEEB    uint32 = 0xED17 // FORMAT_RXE        MULTIPLY (short BFP)
+	op_MEEBR   uint32 = 0xB317 // FORMAT_RRE        MULTIPLY (short BFP)
+	op_MEER    uint32 = 0xB337 // FORMAT_RRE        MULTIPLY (short HFP)
+	op_MER     uint32 = 0x3C00 // FORMAT_RR         MULTIPLY (short to long HFP)
+	op_MFY     uint32 = 0xE35C // FORMAT_RXY1       MULTIPLY (64<-32)
+	op_MGHI    uint32 = 0xA70D // FORMAT_RI1        MULTIPLY HALFWORD IMMEDIATE (64)
+	op_MH      uint32 = 0x4C00 // FORMAT_RX1        MULTIPLY HALFWORD (32)
+	op_MHI     uint32 = 0xA70C // FORMAT_RI1        MULTIPLY HALFWORD IMMEDIATE (32)
+	op_MHY     uint32 = 0xE37C // FORMAT_RXY1       MULTIPLY HALFWORD (32)
+	op_ML      uint32 = 0xE396 // FORMAT_RXY1       MULTIPLY LOGICAL (64<-32)
+	op_MLG     uint32 = 0xE386 // FORMAT_RXY1       MULTIPLY LOGICAL (128<-64)
+	op_MLGR    uint32 = 0xB986 // FORMAT_RRE        MULTIPLY LOGICAL (128<-64)
+	op_MLR     uint32 = 0xB996 // FORMAT_RRE        MULTIPLY LOGICAL (64<-32)
+	op_MP      uint32 = 0xFC00 // FORMAT_SS2        MULTIPLY DECIMAL
+	op_MR      uint32 = 0x1C00 // FORMAT_RR         MULTIPLY (64<-32)
+	op_MS      uint32 = 0x7100 // FORMAT_RX1        MULTIPLY SINGLE (32)
+	op_MSCH    uint32 = 0xB232 // FORMAT_S          MODIFY SUBCHANNEL
+	op_MSD     uint32 = 0xED3F // FORMAT_RXF        MULTIPLY AND SUBTRACT (long HFP)
+	op_MSDB    uint32 = 0xED1F // FORMAT_RXF        MULTIPLY AND SUBTRACT (long BFP)
+	op_MSDBR   uint32 = 0xB31F // FORMAT_RRD        MULTIPLY AND SUBTRACT (long BFP)
+	op_MSDR    uint32 = 0xB33F // FORMAT_RRD        MULTIPLY AND SUBTRACT (long HFP)
+	op_MSE     uint32 = 0xED2F // FORMAT_RXF        MULTIPLY AND SUBTRACT (short HFP)
+	op_MSEB    uint32 = 0xED0F // FORMAT_RXF        MULTIPLY AND SUBTRACT (short BFP)
+	op_MSEBR   uint32 = 0xB30F // FORMAT_RRD        MULTIPLY AND SUBTRACT (short BFP)
+	op_MSER    uint32 = 0xB32F // FORMAT_RRD        MULTIPLY AND SUBTRACT (short HFP)
+	op_MSFI    uint32 = 0xC201 // FORMAT_RIL1       MULTIPLY SINGLE IMMEDIATE (32)
+	op_MSG     uint32 = 0xE30C // FORMAT_RXY1       MULTIPLY SINGLE (64)
+	op_MSGF    uint32 = 0xE31C // FORMAT_RXY1       MULTIPLY SINGLE (64<-32)
+	op_MSGFI   uint32 = 0xC200 // FORMAT_RIL1       MULTIPLY SINGLE IMMEDIATE (64<-32)
+	op_MSGFR   uint32 = 0xB91C // FORMAT_RRE        MULTIPLY SINGLE (64<-32)
+	op_MSGR    uint32 = 0xB90C // FORMAT_RRE        MULTIPLY SINGLE (64)
+	op_MSR     uint32 = 0xB252 // FORMAT_RRE        MULTIPLY SINGLE (32)
+	op_MSTA    uint32 = 0xB247 // FORMAT_RRE        MODIFY STACKED STATE
+	op_MSY     uint32 = 0xE351 // FORMAT_RXY1       MULTIPLY SINGLE (32)
+	op_MVC     uint32 = 0xD200 // FORMAT_SS1        MOVE (character)
+	op_MVCDK   uint32 = 0xE50F // FORMAT_SSE        MOVE WITH DESTINATION KEY
+	op_MVCIN   uint32 = 0xE800 // FORMAT_SS1        MOVE INVERSE
+	op_MVCK    uint32 = 0xD900 // FORMAT_SS4        MOVE WITH KEY
+	op_MVCL    uint32 = 0x0E00 // FORMAT_RR         MOVE LONG
+	op_MVCLE   uint32 = 0xA800 // FORMAT_RS1        MOVE LONG EXTENDED
+	op_MVCLU   uint32 = 0xEB8E // FORMAT_RSY1       MOVE LONG UNICODE
+	op_MVCOS   uint32 = 0xC800 // FORMAT_SSF        MOVE WITH OPTIONAL SPECIFICATIONS
+	op_MVCP    uint32 = 0xDA00 // FORMAT_SS4        MOVE TO PRIMARY
+	op_MVCS    uint32 = 0xDB00 // FORMAT_SS4        MOVE TO SECONDARY
+	op_MVCSK   uint32 = 0xE50E // FORMAT_SSE        MOVE WITH SOURCE KEY
+	op_MVGHI   uint32 = 0xE548 // FORMAT_SIL        MOVE (64<-16)
+	op_MVHHI   uint32 = 0xE544 // FORMAT_SIL        MOVE (16<-16)
+	op_MVHI    uint32 = 0xE54C // FORMAT_SIL        MOVE (32<-16)
+	op_MVI     uint32 = 0x9200 // FORMAT_SI         MOVE (immediate)
+	op_MVIY    uint32 = 0xEB52 // FORMAT_SIY        MOVE (immediate)
+	op_MVN     uint32 = 0xD100 // FORMAT_SS1        MOVE NUMERICS
+	op_MVO     uint32 = 0xF100 // FORMAT_SS2        MOVE WITH OFFSET
+	op_MVPG    uint32 = 0xB254 // FORMAT_RRE        MOVE PAGE
+	op_MVST    uint32 = 0xB255 // FORMAT_RRE        MOVE STRING
+	op_MVZ     uint32 = 0xD300 // FORMAT_SS1        MOVE ZONES
+	op_MXBR    uint32 = 0xB34C // FORMAT_RRE        MULTIPLY (extended BFP)
+	op_MXD     uint32 = 0x6700 // FORMAT_RX1        MULTIPLY (long to extended HFP)
+	op_MXDB    uint32 = 0xED07 // FORMAT_RXE        MULTIPLY (long to extended BFP)
+	op_MXDBR   uint32 = 0xB307 // FORMAT_RRE        MULTIPLY (long to extended BFP)
+	op_MXDR    uint32 = 0x2700 // FORMAT_RR         MULTIPLY (long to extended HFP)
+	op_MXR     uint32 = 0x2600 // FORMAT_RR         MULTIPLY (extended HFP)
+	op_MXTR    uint32 = 0xB3D8 // FORMAT_RRF1       MULTIPLY (extended DFP)
+	op_MXTRA   uint32 = 0xB3D8 // FORMAT_RRF1       MULTIPLY (extended DFP)
+	op_MY      uint32 = 0xED3B // FORMAT_RXF        MULTIPLY UNNORMALIZED (long to ext. HFP)
+	op_MYH     uint32 = 0xED3D // FORMAT_RXF        MULTIPLY UNNORM. (long to ext. high HFP)
+	op_MYHR    uint32 = 0xB33D // FORMAT_RRD        MULTIPLY UNNORM. (long to ext. high HFP)
+	op_MYL     uint32 = 0xED39 // FORMAT_RXF        MULTIPLY UNNORM. (long to ext. low HFP)
+	op_MYLR    uint32 = 0xB339 // FORMAT_RRD        MULTIPLY UNNORM. (long to ext. low HFP)
+	op_MYR     uint32 = 0xB33B // FORMAT_RRD        MULTIPLY UNNORMALIZED (long to ext. HFP)
+	op_N       uint32 = 0x5400 // FORMAT_RX1        AND (32)
+	op_NC      uint32 = 0xD400 // FORMAT_SS1        AND (character)
+	op_NG      uint32 = 0xE380 // FORMAT_RXY1       AND (64)
+	op_NGR     uint32 = 0xB980 // FORMAT_RRE        AND (64)
+	op_NGRK    uint32 = 0xB9E4 // FORMAT_RRF1       AND (64)
+	op_NI      uint32 = 0x9400 // FORMAT_SI         AND (immediate)
+	op_NIAI    uint32 = 0xB2FA // FORMAT_IE         NEXT INSTRUCTION ACCESS INTENT
+	op_NIHF    uint32 = 0xC00A // FORMAT_RIL1       AND IMMEDIATE (high)
+	op_NIHH    uint32 = 0xA504 // FORMAT_RI1        AND IMMEDIATE (high high)
+	op_NIHL    uint32 = 0xA505 // FORMAT_RI1        AND IMMEDIATE (high low)
+	op_NILF    uint32 = 0xC00B // FORMAT_RIL1       AND IMMEDIATE (low)
+	op_NILH    uint32 = 0xA506 // FORMAT_RI1        AND IMMEDIATE (low high)
+	op_NILL    uint32 = 0xA507 // FORMAT_RI1        AND IMMEDIATE (low low)
+	op_NIY     uint32 = 0xEB54 // FORMAT_SIY        AND (immediate)
+	op_NR      uint32 = 0x1400 // FORMAT_RR         AND (32)
+	op_NRK     uint32 = 0xB9F4 // FORMAT_RRF1       AND (32)
+	op_NTSTG   uint32 = 0xE325 // FORMAT_RXY1       NONTRANSACTIONAL STORE
+	op_NY      uint32 = 0xE354 // FORMAT_RXY1       AND (32)
+	op_O       uint32 = 0x5600 // FORMAT_RX1        OR (32)
+	op_OC      uint32 = 0xD600 // FORMAT_SS1        OR (character)
+	op_OG      uint32 = 0xE381 // FORMAT_RXY1       OR (64)
+	op_OGR     uint32 = 0xB981 // FORMAT_RRE        OR (64)
+	op_OGRK    uint32 = 0xB9E6 // FORMAT_RRF1       OR (64)
+	op_OI      uint32 = 0x9600 // FORMAT_SI         OR (immediate)
+	op_OIHF    uint32 = 0xC00C // FORMAT_RIL1       OR IMMEDIATE (high)
+	op_OIHH    uint32 = 0xA508 // FORMAT_RI1        OR IMMEDIATE (high high)
+	op_OIHL    uint32 = 0xA509 // FORMAT_RI1        OR IMMEDIATE (high low)
+	op_OILF    uint32 = 0xC00D // FORMAT_RIL1       OR IMMEDIATE (low)
+	op_OILH    uint32 = 0xA50A // FORMAT_RI1        OR IMMEDIATE (low high)
+	op_OILL    uint32 = 0xA50B // FORMAT_RI1        OR IMMEDIATE (low low)
+	op_OIY     uint32 = 0xEB56 // FORMAT_SIY        OR (immediate)
+	op_OR      uint32 = 0x1600 // FORMAT_RR         OR (32)
+	op_ORK     uint32 = 0xB9F6 // FORMAT_RRF1       OR (32)
+	op_OY      uint32 = 0xE356 // FORMAT_RXY1       OR (32)
+	op_PACK    uint32 = 0xF200 // FORMAT_SS2        PACK
+	op_PALB    uint32 = 0xB248 // FORMAT_RRE        PURGE ALB
+	op_PC      uint32 = 0xB218 // FORMAT_S          PROGRAM CALL
+	op_PCC     uint32 = 0xB92C // FORMAT_RRE        PERFORM CRYPTOGRAPHIC COMPUTATION
+	op_PCKMO   uint32 = 0xB928 // FORMAT_RRE        PERFORM CRYPTOGRAPHIC KEY MGMT. OPERATIONS
+	op_PFD     uint32 = 0xE336 // FORMAT_RXY2       PREFETCH DATA
+	op_PFDRL   uint32 = 0xC602 // FORMAT_RIL3       PREFETCH DATA RELATIVE LONG
+	op_PFMF    uint32 = 0xB9AF // FORMAT_RRE        PERFORM FRAME MANAGEMENT FUNCTION
+	op_PFPO    uint32 = 0x010A // FORMAT_E          PERFORM FLOATING-POINT OPERATION
+	op_PGIN    uint32 = 0xB22E // FORMAT_RRE        PAGE IN
+	op_PGOUT   uint32 = 0xB22F // FORMAT_RRE        PAGE OUT
+	op_PKA     uint32 = 0xE900 // FORMAT_SS6        PACK ASCII
+	op_PKU     uint32 = 0xE100 // FORMAT_SS6        PACK UNICODE
+	op_PLO     uint32 = 0xEE00 // FORMAT_SS5        PERFORM LOCKED OPERATION
+	op_POPCNT  uint32 = 0xB9E1 // FORMAT_RRE        POPULATION COUNT
+	op_PPA     uint32 = 0xB2E8 // FORMAT_RRF3       PERFORM PROCESSOR ASSIST
+	op_PR      uint32 = 0x0101 // FORMAT_E          PROGRAM RETURN
+	op_PT      uint32 = 0xB228 // FORMAT_RRE        PROGRAM TRANSFER
+	op_PTF     uint32 = 0xB9A2 // FORMAT_RRE        PERFORM TOPOLOGY FUNCTION
+	op_PTFF    uint32 = 0x0104 // FORMAT_E          PERFORM TIMING FACILITY FUNCTION
+	op_PTI     uint32 = 0xB99E // FORMAT_RRE        PROGRAM TRANSFER WITH INSTANCE
+	op_PTLB    uint32 = 0xB20D // FORMAT_S          PURGE TLB
+	op_QADTR   uint32 = 0xB3F5 // FORMAT_RRF2       QUANTIZE (long DFP)
+	op_QAXTR   uint32 = 0xB3FD // FORMAT_RRF2       QUANTIZE (extended DFP)
+	op_RCHP    uint32 = 0xB23B // FORMAT_S          RESET CHANNEL PATH
+	op_RISBG   uint32 = 0xEC55 // FORMAT_RIE6       ROTATE THEN INSERT SELECTED BITS
+	op_RISBGN  uint32 = 0xEC59 // FORMAT_RIE6       ROTATE THEN INSERT SELECTED BITS
+	op_RISBHG  uint32 = 0xEC5D // FORMAT_RIE6       ROTATE THEN INSERT SELECTED BITS HIGH
+	op_RISBLG  uint32 = 0xEC51 // FORMAT_RIE6       ROTATE THEN INSERT SELECTED BITS LOW
+	op_RLL     uint32 = 0xEB1D // FORMAT_RSY1       ROTATE LEFT SINGLE LOGICAL (32)
+	op_RLLG    uint32 = 0xEB1C // FORMAT_RSY1       ROTATE LEFT SINGLE LOGICAL (64)
+	op_RNSBG   uint32 = 0xEC54 // FORMAT_RIE6       ROTATE THEN AND SELECTED BITS
+	op_ROSBG   uint32 = 0xEC56 // FORMAT_RIE6       ROTATE THEN OR SELECTED BITS
+	op_RP      uint32 = 0xB277 // FORMAT_S          RESUME PROGRAM
+	op_RRBE    uint32 = 0xB22A // FORMAT_RRE        RESET REFERENCE BIT EXTENDED
+	op_RRBM    uint32 = 0xB9AE // FORMAT_RRE        RESET REFERENCE BITS MULTIPLE
+	op_RRDTR   uint32 = 0xB3F7 // FORMAT_RRF2       REROUND (long DFP)
+	op_RRXTR   uint32 = 0xB3FF // FORMAT_RRF2       REROUND (extended DFP)
+	op_RSCH    uint32 = 0xB238 // FORMAT_S          RESUME SUBCHANNEL
+	op_RXSBG   uint32 = 0xEC57 // FORMAT_RIE6       ROTATE THEN EXCLUSIVE OR SELECTED BITS
+	op_S       uint32 = 0x5B00 // FORMAT_RX1        SUBTRACT (32)
+	op_SAC     uint32 = 0xB219 // FORMAT_S          SET ADDRESS SPACE CONTROL
+	op_SACF    uint32 = 0xB279 // FORMAT_S          SET ADDRESS SPACE CONTROL FAST
+	op_SAL     uint32 = 0xB237 // FORMAT_S          SET ADDRESS LIMIT
+	op_SAM24   uint32 = 0x010C // FORMAT_E          SET ADDRESSING MODE (24)
+	op_SAM31   uint32 = 0x010D // FORMAT_E          SET ADDRESSING MODE (31)
+	op_SAM64   uint32 = 0x010E // FORMAT_E          SET ADDRESSING MODE (64)
+	op_SAR     uint32 = 0xB24E // FORMAT_RRE        SET ACCESS
+	op_SCHM    uint32 = 0xB23C // FORMAT_S          SET CHANNEL MONITOR
+	op_SCK     uint32 = 0xB204 // FORMAT_S          SET CLOCK
+	op_SCKC    uint32 = 0xB206 // FORMAT_S          SET CLOCK COMPARATOR
+	op_SCKPF   uint32 = 0x0107 // FORMAT_E          SET CLOCK PROGRAMMABLE FIELD
+	op_SD      uint32 = 0x6B00 // FORMAT_RX1        SUBTRACT NORMALIZED (long HFP)
+	op_SDB     uint32 = 0xED1B // FORMAT_RXE        SUBTRACT (long BFP)
+	op_SDBR    uint32 = 0xB31B // FORMAT_RRE        SUBTRACT (long BFP)
+	op_SDR     uint32 = 0x2B00 // FORMAT_RR         SUBTRACT NORMALIZED (long HFP)
+	op_SDTR    uint32 = 0xB3D3 // FORMAT_RRF1       SUBTRACT (long DFP)
+	op_SDTRA   uint32 = 0xB3D3 // FORMAT_RRF1       SUBTRACT (long DFP)
+	op_SE      uint32 = 0x7B00 // FORMAT_RX1        SUBTRACT NORMALIZED (short HFP)
+	op_SEB     uint32 = 0xED0B // FORMAT_RXE        SUBTRACT (short BFP)
+	op_SEBR    uint32 = 0xB30B // FORMAT_RRE        SUBTRACT (short BFP)
+	op_SER     uint32 = 0x3B00 // FORMAT_RR         SUBTRACT NORMALIZED (short HFP)
+	op_SFASR   uint32 = 0xB385 // FORMAT_RRE        SET FPC AND SIGNAL
+	op_SFPC    uint32 = 0xB384 // FORMAT_RRE        SET FPC
+	op_SG      uint32 = 0xE309 // FORMAT_RXY1       SUBTRACT (64)
+	op_SGF     uint32 = 0xE319 // FORMAT_RXY1       SUBTRACT (64<-32)
+	op_SGFR    uint32 = 0xB919 // FORMAT_RRE        SUBTRACT (64<-32)
+	op_SGR     uint32 = 0xB909 // FORMAT_RRE        SUBTRACT (64)
+	op_SGRK    uint32 = 0xB9E9 // FORMAT_RRF1       SUBTRACT (64)
+	op_SH      uint32 = 0x4B00 // FORMAT_RX1        SUBTRACT HALFWORD
+	op_SHHHR   uint32 = 0xB9C9 // FORMAT_RRF1       SUBTRACT HIGH (32)
+	op_SHHLR   uint32 = 0xB9D9 // FORMAT_RRF1       SUBTRACT HIGH (32)
+	op_SHY     uint32 = 0xE37B // FORMAT_RXY1       SUBTRACT HALFWORD
+	op_SIGP    uint32 = 0xAE00 // FORMAT_RS1        SIGNAL PROCESSOR
+	op_SL      uint32 = 0x5F00 // FORMAT_RX1        SUBTRACT LOGICAL (32)
+	op_SLA     uint32 = 0x8B00 // FORMAT_RS1        SHIFT LEFT SINGLE (32)
+	op_SLAG    uint32 = 0xEB0B // FORMAT_RSY1       SHIFT LEFT SINGLE (64)
+	op_SLAK    uint32 = 0xEBDD // FORMAT_RSY1       SHIFT LEFT SINGLE (32)
+	op_SLB     uint32 = 0xE399 // FORMAT_RXY1       SUBTRACT LOGICAL WITH BORROW (32)
+	op_SLBG    uint32 = 0xE389 // FORMAT_RXY1       SUBTRACT LOGICAL WITH BORROW (64)
+	op_SLBGR   uint32 = 0xB989 // FORMAT_RRE        SUBTRACT LOGICAL WITH BORROW (64)
+	op_SLBR    uint32 = 0xB999 // FORMAT_RRE        SUBTRACT LOGICAL WITH BORROW (32)
+	op_SLDA    uint32 = 0x8F00 // FORMAT_RS1        SHIFT LEFT DOUBLE
+	op_SLDL    uint32 = 0x8D00 // FORMAT_RS1        SHIFT LEFT DOUBLE LOGICAL
+	op_SLDT    uint32 = 0xED40 // FORMAT_RXF        SHIFT SIGNIFICAND LEFT (long DFP)
+	op_SLFI    uint32 = 0xC205 // FORMAT_RIL1       SUBTRACT LOGICAL IMMEDIATE (32)
+	op_SLG     uint32 = 0xE30B // FORMAT_RXY1       SUBTRACT LOGICAL (64)
+	op_SLGF    uint32 = 0xE31B // FORMAT_RXY1       SUBTRACT LOGICAL (64<-32)
+	op_SLGFI   uint32 = 0xC204 // FORMAT_RIL1       SUBTRACT LOGICAL IMMEDIATE (64<-32)
+	op_SLGFR   uint32 = 0xB91B // FORMAT_RRE        SUBTRACT LOGICAL (64<-32)
+	op_SLGR    uint32 = 0xB90B // FORMAT_RRE        SUBTRACT LOGICAL (64)
+	op_SLGRK   uint32 = 0xB9EB // FORMAT_RRF1       SUBTRACT LOGICAL (64)
+	op_SLHHHR  uint32 = 0xB9CB // FORMAT_RRF1       SUBTRACT LOGICAL HIGH (32)
+	op_SLHHLR  uint32 = 0xB9DB // FORMAT_RRF1       SUBTRACT LOGICAL HIGH (32)
+	op_SLL     uint32 = 0x8900 // FORMAT_RS1        SHIFT LEFT SINGLE LOGICAL (32)
+	op_SLLG    uint32 = 0xEB0D // FORMAT_RSY1       SHIFT LEFT SINGLE LOGICAL (64)
+	op_SLLK    uint32 = 0xEBDF // FORMAT_RSY1       SHIFT LEFT SINGLE LOGICAL (32)
+	op_SLR     uint32 = 0x1F00 // FORMAT_RR         SUBTRACT LOGICAL (32)
+	op_SLRK    uint32 = 0xB9FB // FORMAT_RRF1       SUBTRACT LOGICAL (32)
+	op_SLXT    uint32 = 0xED48 // FORMAT_RXF        SHIFT SIGNIFICAND LEFT (extended DFP)
+	op_SLY     uint32 = 0xE35F // FORMAT_RXY1       SUBTRACT LOGICAL (32)
+	op_SP      uint32 = 0xFB00 // FORMAT_SS2        SUBTRACT DECIMAL
+	op_SPKA    uint32 = 0xB20A // FORMAT_S          SET PSW KEY FROM ADDRESS
+	op_SPM     uint32 = 0x0400 // FORMAT_RR         SET PROGRAM MASK
+	op_SPT     uint32 = 0xB208 // FORMAT_S          SET CPU TIMER
+	op_SPX     uint32 = 0xB210 // FORMAT_S          SET PREFIX
+	op_SQD     uint32 = 0xED35 // FORMAT_RXE        SQUARE ROOT (long HFP)
+	op_SQDB    uint32 = 0xED15 // FORMAT_RXE        SQUARE ROOT (long BFP)
+	op_SQDBR   uint32 = 0xB315 // FORMAT_RRE        SQUARE ROOT (long BFP)
+	op_SQDR    uint32 = 0xB244 // FORMAT_RRE        SQUARE ROOT (long HFP)
+	op_SQE     uint32 = 0xED34 // FORMAT_RXE        SQUARE ROOT (short HFP)
+	op_SQEB    uint32 = 0xED14 // FORMAT_RXE        SQUARE ROOT (short BFP)
+	op_SQEBR   uint32 = 0xB314 // FORMAT_RRE        SQUARE ROOT (short BFP)
+	op_SQER    uint32 = 0xB245 // FORMAT_RRE        SQUARE ROOT (short HFP)
+	op_SQXBR   uint32 = 0xB316 // FORMAT_RRE        SQUARE ROOT (extended BFP)
+	op_SQXR    uint32 = 0xB336 // FORMAT_RRE        SQUARE ROOT (extended HFP)
+	op_SR      uint32 = 0x1B00 // FORMAT_RR         SUBTRACT (32)
+	op_SRA     uint32 = 0x8A00 // FORMAT_RS1        SHIFT RIGHT SINGLE (32)
+	op_SRAG    uint32 = 0xEB0A // FORMAT_RSY1       SHIFT RIGHT SINGLE (64)
+	op_SRAK    uint32 = 0xEBDC // FORMAT_RSY1       SHIFT RIGHT SINGLE (32)
+	op_SRDA    uint32 = 0x8E00 // FORMAT_RS1        SHIFT RIGHT DOUBLE
+	op_SRDL    uint32 = 0x8C00 // FORMAT_RS1        SHIFT RIGHT DOUBLE LOGICAL
+	op_SRDT    uint32 = 0xED41 // FORMAT_RXF        SHIFT SIGNIFICAND RIGHT (long DFP)
+	op_SRK     uint32 = 0xB9F9 // FORMAT_RRF1       SUBTRACT (32)
+	op_SRL     uint32 = 0x8800 // FORMAT_RS1        SHIFT RIGHT SINGLE LOGICAL (32)
+	op_SRLG    uint32 = 0xEB0C // FORMAT_RSY1       SHIFT RIGHT SINGLE LOGICAL (64)
+	op_SRLK    uint32 = 0xEBDE // FORMAT_RSY1       SHIFT RIGHT SINGLE LOGICAL (32)
+	op_SRNM    uint32 = 0xB299 // FORMAT_S          SET BFP ROUNDING MODE (2 bit)
+	op_SRNMB   uint32 = 0xB2B8 // FORMAT_S          SET BFP ROUNDING MODE (3 bit)
+	op_SRNMT   uint32 = 0xB2B9 // FORMAT_S          SET DFP ROUNDING MODE
+	op_SRP     uint32 = 0xF000 // FORMAT_SS3        SHIFT AND ROUND DECIMAL
+	op_SRST    uint32 = 0xB25E // FORMAT_RRE        SEARCH STRING
+	op_SRSTU   uint32 = 0xB9BE // FORMAT_RRE        SEARCH STRING UNICODE
+	op_SRXT    uint32 = 0xED49 // FORMAT_RXF        SHIFT SIGNIFICAND RIGHT (extended DFP)
+	op_SSAIR   uint32 = 0xB99F // FORMAT_RRE        SET SECONDARY ASN WITH INSTANCE
+	op_SSAR    uint32 = 0xB225 // FORMAT_RRE        SET SECONDARY ASN
+	op_SSCH    uint32 = 0xB233 // FORMAT_S          START SUBCHANNEL
+	op_SSKE    uint32 = 0xB22B // FORMAT_RRF3       SET STORAGE KEY EXTENDED
+	op_SSM     uint32 = 0x8000 // FORMAT_S          SET SYSTEM MASK
+	op_ST      uint32 = 0x5000 // FORMAT_RX1        STORE (32)
+	op_STAM    uint32 = 0x9B00 // FORMAT_RS1        STORE ACCESS MULTIPLE
+	op_STAMY   uint32 = 0xEB9B // FORMAT_RSY1       STORE ACCESS MULTIPLE
+	op_STAP    uint32 = 0xB212 // FORMAT_S          STORE CPU ADDRESS
+	op_STC     uint32 = 0x4200 // FORMAT_RX1        STORE CHARACTER
+	op_STCH    uint32 = 0xE3C3 // FORMAT_RXY1       STORE CHARACTER HIGH (8)
+	op_STCK    uint32 = 0xB205 // FORMAT_S          STORE CLOCK
+	op_STCKC   uint32 = 0xB207 // FORMAT_S          STORE CLOCK COMPARATOR
+	op_STCKE   uint32 = 0xB278 // FORMAT_S          STORE CLOCK EXTENDED
+	op_STCKF   uint32 = 0xB27C // FORMAT_S          STORE CLOCK FAST
+	op_STCM    uint32 = 0xBE00 // FORMAT_RS2        STORE CHARACTERS UNDER MASK (low)
+	op_STCMH   uint32 = 0xEB2C // FORMAT_RSY2       STORE CHARACTERS UNDER MASK (high)
+	op_STCMY   uint32 = 0xEB2D // FORMAT_RSY2       STORE CHARACTERS UNDER MASK (low)
+	op_STCPS   uint32 = 0xB23A // FORMAT_S          STORE CHANNEL PATH STATUS
+	op_STCRW   uint32 = 0xB239 // FORMAT_S          STORE CHANNEL REPORT WORD
+	op_STCTG   uint32 = 0xEB25 // FORMAT_RSY1       STORE CONTROL (64)
+	op_STCTL   uint32 = 0xB600 // FORMAT_RS1        STORE CONTROL (32)
+	op_STCY    uint32 = 0xE372 // FORMAT_RXY1       STORE CHARACTER
+	op_STD     uint32 = 0x6000 // FORMAT_RX1        STORE (long)
+	op_STDY    uint32 = 0xED67 // FORMAT_RXY1       STORE (long)
+	op_STE     uint32 = 0x7000 // FORMAT_RX1        STORE (short)
+	op_STEY    uint32 = 0xED66 // FORMAT_RXY1       STORE (short)
+	op_STFH    uint32 = 0xE3CB // FORMAT_RXY1       STORE HIGH (32)
+	op_STFL    uint32 = 0xB2B1 // FORMAT_S          STORE FACILITY LIST
+	op_STFLE   uint32 = 0xB2B0 // FORMAT_S          STORE FACILITY LIST EXTENDED
+	op_STFPC   uint32 = 0xB29C // FORMAT_S          STORE FPC
+	op_STG     uint32 = 0xE324 // FORMAT_RXY1       STORE (64)
+	op_STGRL   uint32 = 0xC40B // FORMAT_RIL2       STORE RELATIVE LONG (64)
+	op_STH     uint32 = 0x4000 // FORMAT_RX1        STORE HALFWORD
+	op_STHH    uint32 = 0xE3C7 // FORMAT_RXY1       STORE HALFWORD HIGH (16)
+	op_STHRL   uint32 = 0xC407 // FORMAT_RIL2       STORE HALFWORD RELATIVE LONG
+	op_STHY    uint32 = 0xE370 // FORMAT_RXY1       STORE HALFWORD
+	op_STIDP   uint32 = 0xB202 // FORMAT_S          STORE CPU ID
+	op_STM     uint32 = 0x9000 // FORMAT_RS1        STORE MULTIPLE (32)
+	op_STMG    uint32 = 0xEB24 // FORMAT_RSY1       STORE MULTIPLE (64)
+	op_STMH    uint32 = 0xEB26 // FORMAT_RSY1       STORE MULTIPLE HIGH
+	op_STMY    uint32 = 0xEB90 // FORMAT_RSY1       STORE MULTIPLE (32)
+	op_STNSM   uint32 = 0xAC00 // FORMAT_SI         STORE THEN AND SYSTEM MASK
+	op_STOC    uint32 = 0xEBF3 // FORMAT_RSY2       STORE ON CONDITION (32)
+	op_STOCG   uint32 = 0xEBE3 // FORMAT_RSY2       STORE ON CONDITION (64)
+	op_STOSM   uint32 = 0xAD00 // FORMAT_SI         STORE THEN OR SYSTEM MASK
+	op_STPQ    uint32 = 0xE38E // FORMAT_RXY1       STORE PAIR TO QUADWORD
+	op_STPT    uint32 = 0xB209 // FORMAT_S          STORE CPU TIMER
+	op_STPX    uint32 = 0xB211 // FORMAT_S          STORE PREFIX
+	op_STRAG   uint32 = 0xE502 // FORMAT_SSE        STORE REAL ADDRESS
+	op_STRL    uint32 = 0xC40F // FORMAT_RIL2       STORE RELATIVE LONG (32)
+	op_STRV    uint32 = 0xE33E // FORMAT_RXY1       STORE REVERSED (32)
+	op_STRVG   uint32 = 0xE32F // FORMAT_RXY1       STORE REVERSED (64)
+	op_STRVH   uint32 = 0xE33F // FORMAT_RXY1       STORE REVERSED (16)
+	op_STSCH   uint32 = 0xB234 // FORMAT_S          STORE SUBCHANNEL
+	op_STSI    uint32 = 0xB27D // FORMAT_S          STORE SYSTEM INFORMATION
+	op_STURA   uint32 = 0xB246 // FORMAT_RRE        STORE USING REAL ADDRESS (32)
+	op_STURG   uint32 = 0xB925 // FORMAT_RRE        STORE USING REAL ADDRESS (64)
+	op_STY     uint32 = 0xE350 // FORMAT_RXY1       STORE (32)
+	op_SU      uint32 = 0x7F00 // FORMAT_RX1        SUBTRACT UNNORMALIZED (short HFP)
+	op_SUR     uint32 = 0x3F00 // FORMAT_RR         SUBTRACT UNNORMALIZED (short HFP)
+	op_SVC     uint32 = 0x0A00 // FORMAT_I          SUPERVISOR CALL
+	op_SW      uint32 = 0x6F00 // FORMAT_RX1        SUBTRACT UNNORMALIZED (long HFP)
+	op_SWR     uint32 = 0x2F00 // FORMAT_RR         SUBTRACT UNNORMALIZED (long HFP)
+	op_SXBR    uint32 = 0xB34B // FORMAT_RRE        SUBTRACT (extended BFP)
+	op_SXR     uint32 = 0x3700 // FORMAT_RR         SUBTRACT NORMALIZED (extended HFP)
+	op_SXTR    uint32 = 0xB3DB // FORMAT_RRF1       SUBTRACT (extended DFP)
+	op_SXTRA   uint32 = 0xB3DB // FORMAT_RRF1       SUBTRACT (extended DFP)
+	op_SY      uint32 = 0xE35B // FORMAT_RXY1       SUBTRACT (32)
+	op_TABORT  uint32 = 0xB2FC // FORMAT_S          TRANSACTION ABORT
+	op_TAM     uint32 = 0x010B // FORMAT_E          TEST ADDRESSING MODE
+	op_TAR     uint32 = 0xB24C // FORMAT_RRE        TEST ACCESS
+	op_TB      uint32 = 0xB22C // FORMAT_RRE        TEST BLOCK
+	op_TBDR    uint32 = 0xB351 // FORMAT_RRF5       CONVERT HFP TO BFP (long)
+	op_TBEDR   uint32 = 0xB350 // FORMAT_RRF5       CONVERT HFP TO BFP (long to short)
+	op_TBEGIN  uint32 = 0xE560 // FORMAT_SIL        TRANSACTION BEGIN
+	op_TBEGINC uint32 = 0xE561 // FORMAT_SIL        TRANSACTION BEGIN
+	op_TCDB    uint32 = 0xED11 // FORMAT_RXE        TEST DATA CLASS (long BFP)
+	op_TCEB    uint32 = 0xED10 // FORMAT_RXE        TEST DATA CLASS (short BFP)
+	op_TCXB    uint32 = 0xED12 // FORMAT_RXE        TEST DATA CLASS (extended BFP)
+	op_TDCDT   uint32 = 0xED54 // FORMAT_RXE        TEST DATA CLASS (long DFP)
+	op_TDCET   uint32 = 0xED50 // FORMAT_RXE        TEST DATA CLASS (short DFP)
+	op_TDCXT   uint32 = 0xED58 // FORMAT_RXE        TEST DATA CLASS (extended DFP)
+	op_TDGDT   uint32 = 0xED55 // FORMAT_RXE        TEST DATA GROUP (long DFP)
+	op_TDGET   uint32 = 0xED51 // FORMAT_RXE        TEST DATA GROUP (short DFP)
+	op_TDGXT   uint32 = 0xED59 // FORMAT_RXE        TEST DATA GROUP (extended DFP)
+	op_TEND    uint32 = 0xB2F8 // FORMAT_S          TRANSACTION END
+	op_THDER   uint32 = 0xB358 // FORMAT_RRE        CONVERT BFP TO HFP (short to long)
+	op_THDR    uint32 = 0xB359 // FORMAT_RRE        CONVERT BFP TO HFP (long)
+	op_TM      uint32 = 0x9100 // FORMAT_SI         TEST UNDER MASK
+	op_TMH     uint32 = 0xA700 // FORMAT_RI1        TEST UNDER MASK HIGH
+	op_TMHH    uint32 = 0xA702 // FORMAT_RI1        TEST UNDER MASK (high high)
+	op_TMHL    uint32 = 0xA703 // FORMAT_RI1        TEST UNDER MASK (high low)
+	op_TML     uint32 = 0xA701 // FORMAT_RI1        TEST UNDER MASK LOW
+	op_TMLH    uint32 = 0xA700 // FORMAT_RI1        TEST UNDER MASK (low high)
+	op_TMLL    uint32 = 0xA701 // FORMAT_RI1        TEST UNDER MASK (low low)
+	op_TMY     uint32 = 0xEB51 // FORMAT_SIY        TEST UNDER MASK
+	op_TP      uint32 = 0xEBC0 // FORMAT_RSL        TEST DECIMAL
+	op_TPI     uint32 = 0xB236 // FORMAT_S          TEST PENDING INTERRUPTION
+	op_TPROT   uint32 = 0xE501 // FORMAT_SSE        TEST PROTECTION
+	op_TR      uint32 = 0xDC00 // FORMAT_SS1        TRANSLATE
+	op_TRACE   uint32 = 0x9900 // FORMAT_RS1        TRACE (32)
+	op_TRACG   uint32 = 0xEB0F // FORMAT_RSY1       TRACE (64)
+	op_TRAP2   uint32 = 0x01FF // FORMAT_E          TRAP
+	op_TRAP4   uint32 = 0xB2FF // FORMAT_S          TRAP
+	op_TRE     uint32 = 0xB2A5 // FORMAT_RRE        TRANSLATE EXTENDED
+	op_TROO    uint32 = 0xB993 // FORMAT_RRF3       TRANSLATE ONE TO ONE
+	op_TROT    uint32 = 0xB992 // FORMAT_RRF3       TRANSLATE ONE TO TWO
+	op_TRT     uint32 = 0xDD00 // FORMAT_SS1        TRANSLATE AND TEST
+	op_TRTE    uint32 = 0xB9BF // FORMAT_RRF3       TRANSLATE AND TEST EXTENDED
+	op_TRTO    uint32 = 0xB991 // FORMAT_RRF3       TRANSLATE TWO TO ONE
+	op_TRTR    uint32 = 0xD000 // FORMAT_SS1        TRANSLATE AND TEST REVERSE
+	op_TRTRE   uint32 = 0xB9BD // FORMAT_RRF3       TRANSLATE AND TEST REVERSE EXTENDED
+	op_TRTT    uint32 = 0xB990 // FORMAT_RRF3       TRANSLATE TWO TO TWO
+	op_TS      uint32 = 0x9300 // FORMAT_S          TEST AND SET
+	op_TSCH    uint32 = 0xB235 // FORMAT_S          TEST SUBCHANNEL
+	op_UNPK    uint32 = 0xF300 // FORMAT_SS2        UNPACK
+	op_UNPKA   uint32 = 0xEA00 // FORMAT_SS1        UNPACK ASCII
+	op_UNPKU   uint32 = 0xE200 // FORMAT_SS1        UNPACK UNICODE
+	op_UPT     uint32 = 0x0102 // FORMAT_E          UPDATE TREE
+	op_X       uint32 = 0x5700 // FORMAT_RX1        EXCLUSIVE OR (32)
+	op_XC      uint32 = 0xD700 // FORMAT_SS1        EXCLUSIVE OR (character)
+	op_XG      uint32 = 0xE382 // FORMAT_RXY1       EXCLUSIVE OR (64)
+	op_XGR     uint32 = 0xB982 // FORMAT_RRE        EXCLUSIVE OR (64)
+	op_XGRK    uint32 = 0xB9E7 // FORMAT_RRF1       EXCLUSIVE OR (64)
+	op_XI      uint32 = 0x9700 // FORMAT_SI         EXCLUSIVE OR (immediate)
+	op_XIHF    uint32 = 0xC006 // FORMAT_RIL1       EXCLUSIVE OR IMMEDIATE (high)
+	op_XILF    uint32 = 0xC007 // FORMAT_RIL1       EXCLUSIVE OR IMMEDIATE (low)
+	op_XIY     uint32 = 0xEB57 // FORMAT_SIY        EXCLUSIVE OR (immediate)
+	op_XR      uint32 = 0x1700 // FORMAT_RR         EXCLUSIVE OR (32)
+	op_XRK     uint32 = 0xB9F7 // FORMAT_RRF1       EXCLUSIVE OR (32)
+	op_XSCH    uint32 = 0xB276 // FORMAT_S          CANCEL SUBCHANNEL
+	op_XY      uint32 = 0xE357 // FORMAT_RXY1       EXCLUSIVE OR (32)
+	op_ZAP     uint32 = 0xF800 // FORMAT_SS2        ZERO AND ADD
+
+	// added in z13
+	op_CXPT   uint32 = 0xEDAF // 	RSL-b	CONVERT FROM PACKED (to extended DFP)
+	op_CDPT   uint32 = 0xEDAE // 	RSL-b	CONVERT FROM PACKED (to long DFP)
+	op_CPXT   uint32 = 0xEDAD // 	RSL-b	CONVERT TO PACKED (from extended DFP)
+	op_CPDT   uint32 = 0xEDAC // 	RSL-b	CONVERT TO PACKED (from long DFP)
+	op_LZRF   uint32 = 0xE33B // 	RXY-a	LOAD AND ZERO RIGHTMOST BYTE (32)
+	op_LZRG   uint32 = 0xE32A // 	RXY-a	LOAD AND ZERO RIGHTMOST BYTE (64)
+	op_LCCB   uint32 = 0xE727 // 	RXE	LOAD COUNT TO BLOCK BOUNDARY
+	op_LOCHHI uint32 = 0xEC4E // 	RIE-g	LOAD HALFWORD HIGH IMMEDIATE ON CONDITION (32←16)
+	op_LOCHI  uint32 = 0xEC42 // 	RIE-g	LOAD HALFWORD IMMEDIATE ON CONDITION (32←16)
+	op_LOCGHI uint32 = 0xEC46 // 	RIE-g	LOAD HALFWORD IMMEDIATE ON CONDITION (64←16)
+	op_LOCFH  uint32 = 0xEBE0 // 	RSY-b	LOAD HIGH ON CONDITION (32)
+	op_LOCFHR uint32 = 0xB9E0 // 	RRF-c	LOAD HIGH ON CONDITION (32)
+	op_LLZRGF uint32 = 0xE33A // 	RXY-a	LOAD LOGICAL AND ZERO RIGHTMOST BYTE (64←32)
+	op_STOCFH uint32 = 0xEBE1 // 	RSY-b	STORE HIGH ON CONDITION
+	op_VA     uint32 = 0xE7F3 // 	VRR-c	VECTOR ADD
+	op_VACC   uint32 = 0xE7F1 // 	VRR-c	VECTOR ADD COMPUTE CARRY
+	op_VAC    uint32 = 0xE7BB // 	VRR-d	VECTOR ADD WITH CARRY
+	op_VACCC  uint32 = 0xE7B9 // 	VRR-d	VECTOR ADD WITH CARRY COMPUTE CARRY
+	op_VN     uint32 = 0xE768 // 	VRR-c	VECTOR AND
+	op_VNC    uint32 = 0xE769 // 	VRR-c	VECTOR AND WITH COMPLEMENT
+	op_VAVG   uint32 = 0xE7F2 // 	VRR-c	VECTOR AVERAGE
+	op_VAVGL  uint32 = 0xE7F0 // 	VRR-c	VECTOR AVERAGE LOGICAL
+	op_VCKSM  uint32 = 0xE766 // 	VRR-c	VECTOR CHECKSUM
+	op_VCEQ   uint32 = 0xE7F8 // 	VRR-b	VECTOR COMPARE EQUAL
+	op_VCH    uint32 = 0xE7FB // 	VRR-b	VECTOR COMPARE HIGH
+	op_VCHL   uint32 = 0xE7F9 // 	VRR-b	VECTOR COMPARE HIGH LOGICAL
+	op_VCLZ   uint32 = 0xE753 // 	VRR-a	VECTOR COUNT LEADING ZEROS
+	op_VCTZ   uint32 = 0xE752 // 	VRR-a	VECTOR COUNT TRAILING ZEROS
+	op_VEC    uint32 = 0xE7DB // 	VRR-a	VECTOR ELEMENT COMPARE
+	op_VECL   uint32 = 0xE7D9 // 	VRR-a	VECTOR ELEMENT COMPARE LOGICAL
+	op_VERIM  uint32 = 0xE772 // 	VRI-d	VECTOR ELEMENT ROTATE AND INSERT UNDER MASK
+	op_VERLL  uint32 = 0xE733 // 	VRS-a	VECTOR ELEMENT ROTATE LEFT LOGICAL
+	op_VERLLV uint32 = 0xE773 // 	VRR-c	VECTOR ELEMENT ROTATE LEFT LOGICAL
+	op_VESLV  uint32 = 0xE770 // 	VRR-c	VECTOR ELEMENT SHIFT LEFT
+	op_VESL   uint32 = 0xE730 // 	VRS-a	VECTOR ELEMENT SHIFT LEFT
+	op_VESRA  uint32 = 0xE73A // 	VRS-a	VECTOR ELEMENT SHIFT RIGHT ARITHMETIC
+	op_VESRAV uint32 = 0xE77A // 	VRR-c	VECTOR ELEMENT SHIFT RIGHT ARITHMETIC
+	op_VESRL  uint32 = 0xE738 // 	VRS-a	VECTOR ELEMENT SHIFT RIGHT LOGICAL
+	op_VESRLV uint32 = 0xE778 // 	VRR-c	VECTOR ELEMENT SHIFT RIGHT LOGICAL
+	op_VX     uint32 = 0xE76D // 	VRR-c	VECTOR EXCLUSIVE OR
+	op_VFAE   uint32 = 0xE782 // 	VRR-b	VECTOR FIND ANY ELEMENT EQUAL
+	op_VFEE   uint32 = 0xE780 // 	VRR-b	VECTOR FIND ELEMENT EQUAL
+	op_VFENE  uint32 = 0xE781 // 	VRR-b	VECTOR FIND ELEMENT NOT EQUAL
+	op_VFA    uint32 = 0xE7E3 // 	VRR-c	VECTOR FP ADD
+	op_WFK    uint32 = 0xE7CA // 	VRR-a	VECTOR FP COMPARE AND SIGNAL SCALAR
+	op_VFCE   uint32 = 0xE7E8 // 	VRR-c	VECTOR FP COMPARE EQUAL
+	op_VFCH   uint32 = 0xE7EB // 	VRR-c	VECTOR FP COMPARE HIGH
+	op_VFCHE  uint32 = 0xE7EA // 	VRR-c	VECTOR FP COMPARE HIGH OR EQUAL
+	op_WFC    uint32 = 0xE7CB // 	VRR-a	VECTOR FP COMPARE SCALAR
+	op_VCDG   uint32 = 0xE7C3 // 	VRR-a	VECTOR FP CONVERT FROM FIXED 64-BIT
+	op_VCDLG  uint32 = 0xE7C1 // 	VRR-a	VECTOR FP CONVERT FROM LOGICAL 64-BIT
+	op_VCGD   uint32 = 0xE7C2 // 	VRR-a	VECTOR FP CONVERT TO FIXED 64-BIT
+	op_VCLGD  uint32 = 0xE7C0 // 	VRR-a	VECTOR FP CONVERT TO LOGICAL 64-BIT
+	op_VFD    uint32 = 0xE7E5 // 	VRR-c	VECTOR FP DIVIDE
+	op_VLDE   uint32 = 0xE7C4 // 	VRR-a	VECTOR FP LOAD LENGTHENED
+	op_VLED   uint32 = 0xE7C5 // 	VRR-a	VECTOR FP LOAD ROUNDED
+	op_VFM    uint32 = 0xE7E7 // 	VRR-c	VECTOR FP MULTIPLY
+	op_VFMA   uint32 = 0xE78F // 	VRR-e	VECTOR FP MULTIPLY AND ADD
+	op_VFMS   uint32 = 0xE78E // 	VRR-e	VECTOR FP MULTIPLY AND SUBTRACT
+	op_VFPSO  uint32 = 0xE7CC // 	VRR-a	VECTOR FP PERFORM SIGN OPERATION
+	op_VFSQ   uint32 = 0xE7CE // 	VRR-a	VECTOR FP SQUARE ROOT
+	op_VFS    uint32 = 0xE7E2 // 	VRR-c	VECTOR FP SUBTRACT
+	op_VFTCI  uint32 = 0xE74A // 	VRI-e	VECTOR FP TEST DATA CLASS IMMEDIATE
+	op_VGFM   uint32 = 0xE7B4 // 	VRR-c	VECTOR GALOIS FIELD MULTIPLY SUM
+	op_VGFMA  uint32 = 0xE7BC // 	VRR-d	VECTOR GALOIS FIELD MULTIPLY SUM AND ACCUMULATE
+	op_VGEF   uint32 = 0xE713 // 	VRV	VECTOR GATHER ELEMENT (32)
+	op_VGEG   uint32 = 0xE712 // 	VRV	VECTOR GATHER ELEMENT (64)
+	op_VGBM   uint32 = 0xE744 // 	VRI-a	VECTOR GENERATE BYTE MASK
+	op_VGM    uint32 = 0xE746 // 	VRI-b	VECTOR GENERATE MASK
+	op_VISTR  uint32 = 0xE75C // 	VRR-a	VECTOR ISOLATE STRING
+	op_VL     uint32 = 0xE706 // 	VRX	VECTOR LOAD
+	op_VLR    uint32 = 0xE756 // 	VRR-a	VECTOR LOAD
+	op_VLREP  uint32 = 0xE705 // 	VRX	VECTOR LOAD AND REPLICATE
+	op_VLC    uint32 = 0xE7DE // 	VRR-a	VECTOR LOAD COMPLEMENT
+	op_VLEH   uint32 = 0xE701 // 	VRX	VECTOR LOAD ELEMENT (16)
+	op_VLEF   uint32 = 0xE703 // 	VRX	VECTOR LOAD ELEMENT (32)
+	op_VLEG   uint32 = 0xE702 // 	VRX	VECTOR LOAD ELEMENT (64)
+	op_VLEB   uint32 = 0xE700 // 	VRX	VECTOR LOAD ELEMENT (8)
+	op_VLEIH  uint32 = 0xE741 // 	VRI-a	VECTOR LOAD ELEMENT IMMEDIATE (16)
+	op_VLEIF  uint32 = 0xE743 // 	VRI-a	VECTOR LOAD ELEMENT IMMEDIATE (32)
+	op_VLEIG  uint32 = 0xE742 // 	VRI-a	VECTOR LOAD ELEMENT IMMEDIATE (64)
+	op_VLEIB  uint32 = 0xE740 // 	VRI-a	VECTOR LOAD ELEMENT IMMEDIATE (8)
+	op_VFI    uint32 = 0xE7C7 // 	VRR-a	VECTOR LOAD FP INTEGER
+	op_VLGV   uint32 = 0xE721 // 	VRS-c	VECTOR LOAD GR FROM VR ELEMENT
+	op_VLLEZ  uint32 = 0xE704 // 	VRX	VECTOR LOAD LOGICAL ELEMENT AND ZERO
+	op_VLM    uint32 = 0xE736 // 	VRS-a	VECTOR LOAD MULTIPLE
+	op_VLP    uint32 = 0xE7DF // 	VRR-a	VECTOR LOAD POSITIVE
+	op_VLBB   uint32 = 0xE707 // 	VRX	VECTOR LOAD TO BLOCK BOUNDARY
+	op_VLVG   uint32 = 0xE722 // 	VRS-b	VECTOR LOAD VR ELEMENT FROM GR
+	op_VLVGP  uint32 = 0xE762 // 	VRR-f	VECTOR LOAD VR FROM GRS DISJOINT
+	op_VLL    uint32 = 0xE737 // 	VRS-b	VECTOR LOAD WITH LENGTH
+	op_VMX    uint32 = 0xE7FF // 	VRR-c	VECTOR MAXIMUM
+	op_VMXL   uint32 = 0xE7FD // 	VRR-c	VECTOR MAXIMUM LOGICAL
+	op_VMRH   uint32 = 0xE761 // 	VRR-c	VECTOR MERGE HIGH
+	op_VMRL   uint32 = 0xE760 // 	VRR-c	VECTOR MERGE LOW
+	op_VMN    uint32 = 0xE7FE // 	VRR-c	VECTOR MINIMUM
+	op_VMNL   uint32 = 0xE7FC // 	VRR-c	VECTOR MINIMUM LOGICAL
+	op_VMAE   uint32 = 0xE7AE // 	VRR-d	VECTOR MULTIPLY AND ADD EVEN
+	op_VMAH   uint32 = 0xE7AB // 	VRR-d	VECTOR MULTIPLY AND ADD HIGH
+	op_VMALE  uint32 = 0xE7AC // 	VRR-d	VECTOR MULTIPLY AND ADD LOGICAL EVEN
+	op_VMALH  uint32 = 0xE7A9 // 	VRR-d	VECTOR MULTIPLY AND ADD LOGICAL HIGH
+	op_VMALO  uint32 = 0xE7AD // 	VRR-d	VECTOR MULTIPLY AND ADD LOGICAL ODD
+	op_VMAL   uint32 = 0xE7AA // 	VRR-d	VECTOR MULTIPLY AND ADD LOW
+	op_VMAO   uint32 = 0xE7AF // 	VRR-d	VECTOR MULTIPLY AND ADD ODD
+	op_VME    uint32 = 0xE7A6 // 	VRR-c	VECTOR MULTIPLY EVEN
+	op_VMH    uint32 = 0xE7A3 // 	VRR-c	VECTOR MULTIPLY HIGH
+	op_VMLE   uint32 = 0xE7A4 // 	VRR-c	VECTOR MULTIPLY EVEN LOGICAL
+	op_VMLH   uint32 = 0xE7A1 // 	VRR-c	VECTOR MULTIPLY HIGH LOGICAL
+	op_VMLO   uint32 = 0xE7A5 // 	VRR-c	VECTOR MULTIPLY ODD LOGICAL
+	op_VML    uint32 = 0xE7A2 // 	VRR-c	VECTOR MULTIPLY LOW
+	op_VMO    uint32 = 0xE7A7 // 	VRR-c	VECTOR MULTIPLY ODD
+	op_VNO    uint32 = 0xE76B // 	VRR-c	VECTOR NOR
+	op_VO     uint32 = 0xE76A // 	VRR-c	VECTOR OR
+	op_VPK    uint32 = 0xE794 // 	VRR-c	VECTOR PACK
+	op_VPKLS  uint32 = 0xE795 // 	VRR-b	VECTOR PACK LOGICAL SATURATE
+	op_VPKS   uint32 = 0xE797 // 	VRR-b	VECTOR PACK SATURATE
+	op_VPERM  uint32 = 0xE78C // 	VRR-e	VECTOR PERMUTE
+	op_VPDI   uint32 = 0xE784 // 	VRR-c	VECTOR PERMUTE DOUBLEWORD IMMEDIATE
+	op_VPOPCT uint32 = 0xE750 // 	VRR-a	VECTOR POPULATION COUNT
+	op_VREP   uint32 = 0xE74D // 	VRI-c	VECTOR REPLICATE
+	op_VREPI  uint32 = 0xE745 // 	VRI-a	VECTOR REPLICATE IMMEDIATE
+	op_VSCEF  uint32 = 0xE71B // 	VRV	VECTOR SCATTER ELEMENT (32)
+	op_VSCEG  uint32 = 0xE71A // 	VRV	VECTOR SCATTER ELEMENT (64)
+	op_VSEL   uint32 = 0xE78D // 	VRR-e	VECTOR SELECT
+	op_VSL    uint32 = 0xE774 // 	VRR-c	VECTOR SHIFT LEFT
+	op_VSLB   uint32 = 0xE775 // 	VRR-c	VECTOR SHIFT LEFT BY BYTE
+	op_VSLDB  uint32 = 0xE777 // 	VRI-d	VECTOR SHIFT LEFT DOUBLE BY BYTE
+	op_VSRA   uint32 = 0xE77E // 	VRR-c	VECTOR SHIFT RIGHT ARITHMETIC
+	op_VSRAB  uint32 = 0xE77F // 	VRR-c	VECTOR SHIFT RIGHT ARITHMETIC BY BYTE
+	op_VSRL   uint32 = 0xE77C // 	VRR-c	VECTOR SHIFT RIGHT LOGICAL
+	op_VSRLB  uint32 = 0xE77D // 	VRR-c	VECTOR SHIFT RIGHT LOGICAL BY BYTE
+	op_VSEG   uint32 = 0xE75F // 	VRR-a	VECTOR SIGN EXTEND TO DOUBLEWORD
+	op_VST    uint32 = 0xE70E // 	VRX	VECTOR STORE
+	op_VSTEH  uint32 = 0xE709 // 	VRX	VECTOR STORE ELEMENT (16)
+	op_VSTEF  uint32 = 0xE70B // 	VRX	VECTOR STORE ELEMENT (32)
+	op_VSTEG  uint32 = 0xE70A // 	VRX	VECTOR STORE ELEMENT (64)
+	op_VSTEB  uint32 = 0xE708 // 	VRX	VECTOR STORE ELEMENT (8)
+	op_VSTM   uint32 = 0xE73E // 	VRS-a	VECTOR STORE MULTIPLE
+	op_VSTL   uint32 = 0xE73F // 	VRS-b	VECTOR STORE WITH LENGTH
+	op_VSTRC  uint32 = 0xE78A // 	VRR-d	VECTOR STRING RANGE COMPARE
+	op_VS     uint32 = 0xE7F7 // 	VRR-c	VECTOR SUBTRACT
+	op_VSCBI  uint32 = 0xE7F5 // 	VRR-c	VECTOR SUBTRACT COMPUTE BORROW INDICATION
+	op_VSBCBI uint32 = 0xE7BD // 	VRR-d	VECTOR SUBTRACT WITH BORROW COMPUTE BORROW INDICATION
+	op_VSBI   uint32 = 0xE7BF // 	VRR-d	VECTOR SUBTRACT WITH BORROW INDICATION
+	op_VSUMG  uint32 = 0xE765 // 	VRR-c	VECTOR SUM ACROSS DOUBLEWORD
+	op_VSUMQ  uint32 = 0xE767 // 	VRR-c	VECTOR SUM ACROSS QUADWORD
+	op_VSUM   uint32 = 0xE764 // 	VRR-c	VECTOR SUM ACROSS WORD
+	op_VTM    uint32 = 0xE7D8 // 	VRR-a	VECTOR TEST UNDER MASK
+	op_VUPH   uint32 = 0xE7D7 // 	VRR-a	VECTOR UNPACK HIGH
+	op_VUPLH  uint32 = 0xE7D5 // 	VRR-a	VECTOR UNPACK LOGICAL HIGH
+	op_VUPLL  uint32 = 0xE7D4 // 	VRR-a	VECTOR UNPACK LOGICAL LOW
+	op_VUPL   uint32 = 0xE7D6 // 	VRR-a	VECTOR UNPACK LOW
+)
+
+func oclass(a *obj.Addr) int {
+	return int(a.Class) - 1
+}
+
+// Add a relocation for the immediate in a RIL style instruction.
+// The addend will be adjusted as required.
+func addrilreloc(ctxt *obj.Link, sym *obj.LSym, add int64) *obj.Reloc {
+	if sym == nil {
+		ctxt.Diag("require symbol to apply relocation")
+	}
+	offset := int64(2) // relocation offset from start of instruction
+	rel := obj.Addrel(ctxt.Cursym)
+	rel.Off = int32(ctxt.Pc + offset)
+	rel.Siz = 4
+	rel.Sym = sym
+	rel.Add = add + offset + int64(rel.Siz)
+	rel.Type = obj.R_PCRELDBL
+	return rel
+}
+
+func addrilrelocoffset(ctxt *obj.Link, sym *obj.LSym, add, offset int64) *obj.Reloc {
+	if sym == nil {
+		ctxt.Diag("require symbol to apply relocation")
+	}
+	offset += int64(2) // relocation offset from start of instruction
+	rel := obj.Addrel(ctxt.Cursym)
+	rel.Off = int32(ctxt.Pc + offset)
+	rel.Siz = 4
+	rel.Sym = sym
+	rel.Add = add + offset + int64(rel.Siz)
+	rel.Type = obj.R_PCRELDBL
+	return rel
+}
+
+// Add a CALL relocation for the immediate in a RIL style instruction.
+// The addend will be adjusted as required.
+func addcallreloc(ctxt *obj.Link, sym *obj.LSym, add int64) *obj.Reloc {
+	if sym == nil {
+		ctxt.Diag("require symbol to apply relocation")
+	}
+	offset := int64(2) // relocation offset from start of instruction
+	rel := obj.Addrel(ctxt.Cursym)
+	rel.Off = int32(ctxt.Pc + offset)
+	rel.Siz = 4
+	rel.Sym = sym
+	rel.Add = add + offset + int64(rel.Siz)
+	rel.Type = obj.R_CALL
+	return rel
+}
+
+func branchMask(ctxt *obj.Link, p *obj.Prog) uint32 {
+	switch p.As {
+	case ABEQ, ACMPBEQ, ACMPUBEQ:
+		return 0x8
+	case ABGE, ACMPBGE, ACMPUBGE:
+		return 0xA
+	case ABGT, ACMPBGT, ACMPUBGT:
+		return 0x2
+	case ABLE, ACMPBLE, ACMPUBLE:
+		return 0xC
+	case ABLT, ACMPBLT, ACMPUBLT:
+		return 0x4
+	case ABNE, ACMPBNE, ACMPUBNE:
+		return 0x7
+	case ABVC:
+		return 0x0 //needs extra instruction
+	case ABVS:
+		return 0x1
+	}
+	ctxt.Diag("unknown conditional branch %v", p.As)
+	return 0xF
+}
+
+func asmout(ctxt *obj.Link, asm *[]byte) {
+	p := ctxt.Curp
+	o := oplook(ctxt, p)
+	ctxt.Printp = p
+
+	switch o.type_ {
+	default:
+		ctxt.Diag("unknown type %d", o.type_)
+
+	case 0: // PSEUDO OPS
+		break
+
+	case 1: // mov reg reg
+		switch p.As {
+		default:
+			ctxt.Diag("unhandled operation: %v", p.As)
+		case AMOVD:
+			zRRE(op_LGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		// sign extend
+		case AMOVW:
+			zRRE(op_LGFR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		case AMOVH:
+			zRRE(op_LGHR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		case AMOVB:
+			zRRE(op_LGBR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		// zero extend
+		case AMOVWZ:
+			zRRE(op_LLGFR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		case AMOVHZ:
+			zRRE(op_LLGHR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		case AMOVBZ:
+			zRRE(op_LLGCR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		// reverse bytes
+		case AMOVDBR:
+			zRRE(op_LRVGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		case AMOVWBR:
+			zRRE(op_LRVR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		// floating point
+		case AFMOVD, AFMOVS:
+			zRR(op_LDR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		}
+
+	case 2: // arithmetic op reg [reg] reg
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+
+		var opcode uint32
+
+		switch p.As {
+		default:
+			ctxt.Diag("invalid opcode")
+		case AADD:
+			opcode = op_AGRK
+		case AADDC:
+			opcode = op_ALGRK
+		case AADDE:
+			opcode = op_ALCGR
+		case AMULLW:
+			opcode = op_MSGFR
+		case AMULLD:
+			opcode = op_MSGR
+		case ADIVW:
+			opcode = op_DSGFR
+		case ADIVWU:
+			opcode = op_DLR
+		case ADIVD:
+			opcode = op_DSGR
+		case ADIVDU:
+			opcode = op_DLGR
+		case AFADD:
+			opcode = op_ADBR
+		case AFADDS:
+			opcode = op_AEBR
+		case AFSUB:
+			opcode = op_SDBR
+		case AFSUBS:
+			opcode = op_SEBR
+		case AFDIV:
+			opcode = op_DDBR
+		case AFDIVS:
+			opcode = op_DEBR
+		}
+
+		switch p.As {
+		default:
+
+		case AADD, AADDC:
+			zRRF(opcode, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
+
+		case AADDE, AMULLW, AMULLD:
+			if r == int(p.To.Reg) {
+				zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			} else if p.From.Reg == p.To.Reg {
+				zRRE(opcode, uint32(p.To.Reg), uint32(r), asm)
+			} else {
+				zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
+				zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			}
+
+		case ADIVW, ADIVWU, ADIVD, ADIVDU:
+			if p.As == ADIVWU || p.As == ADIVDU {
+				zRRE(op_LGR, REGTMP, REGZERO, asm)
+			}
+			zRRE(op_LGR, REGTMP2, uint32(r), asm)
+			zRRE(opcode, REGTMP, uint32(p.From.Reg), asm)
+			zRRE(op_LGR, uint32(p.To.Reg), REGTMP2, asm)
+
+		case AFADD, AFADDS:
+			if r == int(p.To.Reg) {
+				zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			} else if p.From.Reg == p.To.Reg {
+				zRRE(opcode, uint32(p.To.Reg), uint32(r), asm)
+			} else {
+				zRR(op_LDR, uint32(p.To.Reg), uint32(r), asm)
+				zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			}
+
+		case AFSUB, AFSUBS, AFDIV, AFDIVS:
+			if r == int(p.To.Reg) {
+				zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			} else if p.From.Reg == p.To.Reg {
+				zRRE(op_LGDR, REGTMP, uint32(r), asm)
+				zRRE(opcode, uint32(r), uint32(p.From.Reg), asm)
+				zRR(op_LDR, uint32(p.To.Reg), uint32(r), asm)
+				zRRE(op_LDGR, uint32(r), REGTMP, asm)
+			} else {
+				zRR(op_LDR, uint32(p.To.Reg), uint32(r), asm)
+				zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			}
+
+		}
+
+	case 3: // mov $constant reg
+		v := vregoff(ctxt, &p.From)
+		switch p.As {
+		case AMOVBZ:
+			v = int64(uint8(v))
+		case AMOVHZ:
+			v = int64(uint16(v))
+		case AMOVWZ:
+			v = int64(uint32(v))
+		case AMOVB:
+			v = int64(int8(v))
+		case AMOVH:
+			v = int64(int16(v))
+		case AMOVW:
+			v = int64(int32(v))
+		}
+		if v&0xffff == v {
+			zRI(op_LLILL, uint32(p.To.Reg), uint32(v), asm)
+		} else if v&0xffff0000 == v {
+			zRI(op_LLILH, uint32(p.To.Reg), uint32(v>>16), asm)
+		} else if v&0xffff00000000 == v {
+			zRI(op_LLIHL, uint32(p.To.Reg), uint32(v>>32), asm)
+		} else if uint64(v)&0xffff000000000000 == uint64(v) {
+			zRI(op_LLIHH, uint32(p.To.Reg), uint32(v>>48), asm)
+		} else if int64(int16(v)) == v {
+			zRI(op_LGHI, uint32(p.To.Reg), uint32(v), asm)
+		} else if int64(int32(v)) == v {
+			zRIL(_a, op_LGFI, uint32(p.To.Reg), uint32(v), asm)
+		} else if int64(uint32(v)) == v {
+			zRIL(_a, op_LLILF, uint32(p.To.Reg), uint32(v), asm)
+		} else if uint64(v)&0xffffffff00000000 == uint64(v) {
+			zRIL(_a, op_LLIHF, uint32(p.To.Reg), uint32(v>>32), asm)
+		} else {
+			zRIL(_a, op_LLILF, uint32(p.To.Reg), uint32(v), asm)
+			zRIL(_a, op_IIHF, uint32(p.To.Reg), uint32(v>>32), asm)
+		}
+
+	case 4: // multiply high (a*b)>>64
+		r := p.Reg
+		if r == 0 {
+			r = p.To.Reg
+		}
+		zRRE(op_LGR, REGTMP2, uint32(r), asm)
+		zRRE(op_MLGR, REGTMP, uint32(p.From.Reg), asm)
+		switch p.As {
+		case AMULHDU:
+			// Unsigned: move result into correct register.
+			zRRE(op_LGR, uint32(p.To.Reg), REGTMP, asm)
+		case AMULHD:
+			// Signed: need to convert result.
+			// See Hacker's Delight 8-3.
+			zRSY(op_SRAG, REGTMP2, uint32(p.From.Reg), 0, 63, asm)
+			zRRE(op_NGR, REGTMP2, uint32(r), asm)
+			zRRE(op_SGR, REGTMP, REGTMP2, asm)
+			zRSY(op_SRAG, REGTMP2, uint32(r), 0, 63, asm)
+			zRRE(op_NGR, REGTMP2, uint32(p.From.Reg), asm)
+			zRRF(op_SGRK, REGTMP2, 0, uint32(p.To.Reg), REGTMP, asm)
+		}
+
+	case 5: // syscall
+		zI(op_SVC, 0, asm)
+
+	case 6: // logical op reg [reg] reg
+		if p.To.Reg == 0 {
+			ctxt.Diag("literal operation on R0\n%v", p)
+		}
+
+		switch p.As {
+		case AAND, AOR, AXOR:
+			var opcode1, opcode2 uint32
+			switch p.As {
+			default:
+			case AAND:
+				opcode1 = op_NGR
+				opcode2 = op_NGRK
+			case AOR:
+				opcode1 = op_OGR
+				opcode2 = op_OGRK
+			case AXOR:
+				opcode1 = op_XGR
+				opcode2 = op_XGRK
+			}
+
+			r := int(p.Reg)
+			if r == 0 {
+				zRRE(opcode1, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			} else {
+				zRRF(opcode2, uint32(r), 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			}
+
+		case AANDN, AORN:
+			var opcode1, opcode2 uint32
+			switch p.As {
+			default:
+			case AANDN:
+				opcode1 = op_NGR
+				opcode2 = op_NGRK
+			case AORN:
+				opcode1 = op_OGR
+				opcode2 = op_OGRK
+			}
+
+			r := int(p.Reg)
+			if r == 0 {
+				zRRE(op_LCGR, uint32(p.To.Reg), uint32(p.To.Reg), asm)
+				zRRE(opcode1, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			} else {
+				zRRE(op_LCGR, REGTMP, uint32(r), asm)
+				zRRF(opcode2, REGTMP, 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			}
+
+		case ANAND, ANOR:
+			var opcode1, opcode2 uint32
+			switch p.As {
+			default:
+			case ANAND:
+				opcode1 = op_NGR
+				opcode2 = op_NGRK
+			case ANOR:
+				opcode1 = op_OGR
+				opcode2 = op_OGRK
+			}
+
+			r := int(p.Reg)
+			if r == 0 {
+				zRRE(opcode1, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			} else {
+				zRRF(opcode2, uint32(r), 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			}
+
+			zRRE(op_LCGR, uint32(p.To.Reg), uint32(p.To.Reg), asm)
+		}
+
+	case 7: // shift/rotate reg [reg] reg
+		d2 := vregoff(ctxt, &p.From)
+		b2 := p.From.Reg
+		r3 := p.Reg
+		if r3 == 0 {
+			r3 = p.To.Reg
+		}
+		r1 := p.To.Reg
+		var opcode uint32
+		switch p.As {
+		default:
+		case ASLD:
+			opcode = op_SLLG
+		case ASRD:
+			opcode = op_SRLG
+		case ASLW:
+			opcode = op_SLLK
+		case ASRW:
+			opcode = op_SRLK
+		case ARLL:
+			opcode = op_RLL
+		case ARLLG:
+			opcode = op_RLLG
+		case ASRAW:
+			opcode = op_SRAK
+		case ASRAD:
+			opcode = op_SRAG
+		}
+		zRSY(opcode, uint32(r1), uint32(r3), uint32(b2), uint32(d2), asm)
+
+	case 10: // subtract reg [reg] reg
+		r := int(p.Reg)
+
+		switch p.As {
+		default:
+		case ASUB:
+			if r == 0 {
+				zRRE(op_SGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			} else {
+				zRRF(op_SGRK, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
+			}
+		case ASUBC:
+			if r == 0 {
+				zRRE(op_SLGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			} else {
+				zRRF(op_SLGRK, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
+			}
+
+		case ASUBE:
+			if r == 0 {
+				r = int(p.To.Reg)
+			}
+			if r == int(p.To.Reg) {
+				zRRE(op_SLBGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			} else if p.From.Reg == p.To.Reg {
+				zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
+				zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
+				zRRE(op_SLBGR, uint32(p.To.Reg), REGTMP, asm)
+			} else {
+				zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
+				zRRE(op_SLBGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+			}
+		}
+
+	case 11: // br/bl
+		v := int32(0)
+
+		if p.Pcond != nil {
+			v = int32((p.Pcond.Pc - p.Pc) >> 1)
+		}
+
+		if p.As == ABR && p.To.Sym == nil && int32(int16(v)) == v {
+			zRI(op_BRC, 0xF, uint32(v), asm)
+		} else {
+			if p.As == ABL {
+				zRIL(_b, op_BRASL, uint32(REG_LR), uint32(v), asm)
+			} else {
+				zRIL(_c, op_BRCL, 0xF, uint32(v), asm)
+			}
+			if p.To.Sym != nil {
+				addcallreloc(ctxt, p.To.Sym, p.To.Offset)
+			}
+		}
+
+	case 15: // br/bl (reg)
+		r := p.To.Reg
+		if p.As == ABCL || p.As == ABL {
+			zRR(op_BASR, uint32(REG_LR), uint32(r), asm)
+		} else {
+			zRR(op_BCR, 0xF, uint32(r), asm)
+		}
+
+	case 16: // conditional branch
+		v := int32(0)
+		if p.Pcond != nil {
+			v = int32((p.Pcond.Pc - p.Pc) >> 1)
+		}
+		mask := branchMask(ctxt, p)
+		if p.To.Sym == nil && int32(int16(v)) == v {
+			zRI(op_BRC, mask, uint32(v), asm)
+		} else {
+			zRIL(_c, op_BRCL, mask, uint32(v), asm)
+		}
+		if p.To.Sym != nil {
+			addrilreloc(ctxt, p.To.Sym, p.To.Offset)
+		}
+
+	case 18: // br/bl reg
+		if p.As == ABL {
+			zRR(op_BASR, uint32(REG_LR), uint32(p.To.Reg), asm)
+		} else {
+			zRR(op_BCR, 0xF, uint32(p.To.Reg), asm)
+		}
+
+	case 19: // mov $sym+n(SB) reg
+		d := vregoff(ctxt, &p.From)
+		zRIL(_b, op_LARL, uint32(p.To.Reg), 0, asm)
+		if d&1 != 0 {
+			zRX(op_LA, uint32(p.To.Reg), uint32(p.To.Reg), 0, 1, asm)
+			d -= 1
+		}
+		addrilreloc(ctxt, p.From.Sym, d)
+
+	case 22: // arithmetic op $constant [reg] reg
+		if p.From.Sym != nil {
+			ctxt.Diag("%v is not supported", p)
+		}
+		v := vregoff(ctxt, &p.From)
+		r := p.Reg
+		if r == 0 {
+			r = p.To.Reg
+		}
+		switch p.As {
+		default:
+		case AADD:
+			if r == p.To.Reg {
+				zRIL(_a, op_AGFI, uint32(p.To.Reg), uint32(v), asm)
+			} else if int64(int16(v)) == v {
+				zRIE(_d, op_AGHIK, uint32(p.To.Reg), uint32(r), uint32(v), 0, 0, 0, 0, asm)
+			} else {
+				zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
+				zRIL(_a, op_AGFI, uint32(p.To.Reg), uint32(v), asm)
+			}
+		case AADDC:
+			if r != p.To.Reg {
+				zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
+			}
+			zRIL(_a, op_ALGFI, uint32(p.To.Reg), uint32(v), asm)
+		case AMULLW, AMULLD:
+			if r != p.To.Reg {
+				zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
+			}
+			if int64(int16(v)) == v {
+				zRI(op_MGHI, uint32(p.To.Reg), uint32(v), asm)
+			} else {
+				zRIL(_a, op_MSGFI, uint32(p.To.Reg), uint32(v), asm)
+			}
+		}
+
+	case 23: // logical op $constant [reg] reg
+		v := vregoff(ctxt, &p.From)
+		var opcode uint32
+		r := p.Reg
+		if r == 0 {
+			r = p.To.Reg
+		}
+		if r == p.To.Reg {
+			switch p.As {
+			default:
+				ctxt.Diag("%v is not supported", p)
+			case AAND:
+				if v >= 0 { // needs zero extend
+					zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
+					zRRE(op_NGR, uint32(p.To.Reg), REGTMP, asm)
+				} else if int64(int16(v)) == v {
+					zRI(op_NILL, uint32(p.To.Reg), uint32(v), asm)
+				} else { //  r.To.Reg & 0xffffffff00000000 & uint32(v)
+					zRIL(_a, op_NILF, uint32(p.To.Reg), uint32(v), asm)
+				}
+			case AOR:
+				if int64(uint32(v)) != v { // needs sign extend
+					zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
+					zRRE(op_OGR, uint32(p.To.Reg), REGTMP, asm)
+				} else if int64(uint16(v)) == v {
+					zRI(op_OILL, uint32(p.To.Reg), uint32(v), asm)
+				} else {
+					zRIL(_a, op_OILF, uint32(p.To.Reg), uint32(v), asm)
+				}
+			case AXOR:
+				if int64(uint32(v)) != v { // needs sign extend
+					zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
+					zRRE(op_XGR, uint32(p.To.Reg), REGTMP, asm)
+				} else {
+					zRIL(_a, op_XILF, uint32(p.To.Reg), uint32(v), asm)
+				}
+			}
+		} else {
+			switch p.As {
+			default:
+				ctxt.Diag("%v is not supported", p)
+			case AAND:
+				opcode = op_NGRK
+			case AOR:
+				opcode = op_OGRK
+			case AXOR:
+				opcode = op_XGRK
+			}
+			zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
+			zRRF(opcode, uint32(r), 0, uint32(p.To.Reg), REGTMP, asm)
+		}
+
+	case 26: // mov $addr/sym reg
+		v := regoff(ctxt, &p.From)
+		r := p.From.Reg
+		if r == 0 {
+			r = o.param
+		}
+		if v >= 0 && v < DISP12 {
+			zRX(op_LA, uint32(p.To.Reg), uint32(r), 0, uint32(v), asm)
+		} else if v >= -DISP20/2 && v < DISP20/2 {
+			zRXY(op_LAY, uint32(p.To.Reg), uint32(r), 0, uint32(v), asm)
+		} else {
+			zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
+			zRX(op_LA, uint32(p.To.Reg), uint32(r), REGTMP, 0, asm)
+		}
+
+	case 31: // dword
+		wd := uint64(vregoff(ctxt, &p.From))
+		*asm = append(*asm,
+			uint8(wd>>56),
+			uint8(wd>>48),
+			uint8(wd>>40),
+			uint8(wd>>32),
+			uint8(wd>>24),
+			uint8(wd>>16),
+			uint8(wd>>8),
+			uint8(wd))
+
+	case 32: // fmul freg [freg] freg
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+
+		var opcode uint32
+
+		switch p.As {
+		default:
+			ctxt.Diag("invalid opcode")
+		case AFMUL:
+			opcode = op_MDBR
+		case AFMULS:
+			opcode = op_MEEBR
+		}
+
+		if r == int(p.To.Reg) {
+			zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		} else if p.From.Reg == p.To.Reg {
+			zRRE(opcode, uint32(p.To.Reg), uint32(r), asm)
+		} else {
+			zRR(op_LDR, uint32(p.To.Reg), uint32(r), asm)
+			zRRE(opcode, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+		}
+
+	case 33: // float op [freg] freg
+		r := p.From.Reg
+		if oclass(&p.From) == C_NONE {
+			r = p.To.Reg
+		}
+		var opcode uint32
+		switch p.As {
+		default:
+		case AFABS:
+			opcode = op_LPDBR
+		case AFNABS:
+			opcode = op_LNDBR
+		case AFNEG:
+			opcode = op_LCDFR
+		case ALEDBR:
+			opcode = op_LEDBR
+		case ALDEBR:
+			opcode = op_LDEBR
+		case AFSQRT:
+			opcode = op_SQDBR
+		case AFSQRTS:
+			opcode = op_SQEBR
+		}
+		zRRE(opcode, uint32(p.To.Reg), uint32(r), asm)
+
+	case 34: // float multiply-add freg freg freg freg
+		var opcode uint32
+
+		switch p.As {
+		default:
+			ctxt.Diag("invalid opcode")
+		case AFMADD:
+			opcode = op_MADBR
+		case AFMADDS:
+			opcode = op_MAEBR
+		case AFMSUB:
+			opcode = op_MSDBR
+		case AFMSUBS:
+			opcode = op_MSEBR
+		case AFNMADD:
+			opcode = op_MADBR
+		case AFNMADDS:
+			opcode = op_MAEBR
+		case AFNMSUB:
+			opcode = op_MSDBR
+		case AFNMSUBS:
+			opcode = op_MSEBR
+		}
+
+		zRR(op_LDR, uint32(p.To.Reg), uint32(p.Reg), asm)
+		zRRD(opcode, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.From3.Reg), asm)
+
+		if p.As == AFNMADD || p.As == AFNMADDS || p.As == AFNMSUB || p.As == AFNMSUBS {
+			zRRE(op_LCDFR, uint32(p.To.Reg), uint32(p.To.Reg), asm)
+		}
+
+	case 35: // mov reg mem (no relocation)
+		d2 := regoff(ctxt, &p.To)
+		b2 := p.To.Reg
+		if b2 == 0 {
+			b2 = o.param
+		}
+		x2 := p.To.Index
+		if d2 < -DISP20/2 || d2 >= DISP20/2 {
+			zRIL(_a, op_LGFI, REGTMP, uint32(d2), asm)
+			if x2 != 0 {
+				zRX(op_LA, REGTMP, REGTMP, uint32(x2), 0, asm)
+			}
+			x2 = REGTMP
+			d2 = 0
+		}
+		zRXY(zopstore(ctxt, p.As), uint32(p.From.Reg), uint32(x2), uint32(b2), uint32(d2), asm)
+
+	case 36: // mov mem reg (no relocation)
+		d2 := regoff(ctxt, &p.From)
+		b2 := p.From.Reg
+		if b2 == 0 {
+			b2 = o.param
+		}
+		x2 := p.From.Index
+		if d2 < -DISP20/2 || d2 >= DISP20/2 {
+			zRIL(_a, op_LGFI, REGTMP, uint32(d2), asm)
+			if x2 != 0 {
+				zRX(op_LA, REGTMP, REGTMP, uint32(x2), 0, asm)
+			}
+			x2 = REGTMP
+			d2 = 0
+		}
+		zRXY(zopload(ctxt, p.As), uint32(p.To.Reg), uint32(x2), uint32(b2), uint32(d2), asm)
+
+	case 40: // word/byte
+		wd := uint32(regoff(ctxt, &p.From))
+		if p.As == AWORD { //WORD
+			*asm = append(*asm, uint8(wd>>24), uint8(wd>>16), uint8(wd>>8), uint8(wd))
+		} else { //BYTE
+			*asm = append(*asm, uint8(wd))
+		}
+
+	case 47: // arithmetic op (carry) reg [reg] reg
+		switch p.As {
+		default:
+
+		case AADDME:
+			r := int(p.From.Reg)
+			if p.To.Reg == p.From.Reg {
+				zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
+				r = REGTMP
+			}
+			zRIL(_a, op_LGFI, uint32(p.To.Reg), 0xffffffff, asm) // p.To.Reg <- -1
+			zRRE(op_ALCGR, uint32(p.To.Reg), uint32(r), asm)
+
+		case AADDZE:
+			r := int(p.From.Reg)
+			if p.To.Reg == p.From.Reg {
+				zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
+				r = REGTMP
+			}
+			zRRE(op_LGR, uint32(p.To.Reg), REGZERO, asm) // p.To.Reg <- 0
+			zRRE(op_ALCGR, uint32(p.To.Reg), uint32(r), asm)
+
+		case ASUBME:
+			r := int(p.From.Reg)
+			if p.To.Reg == p.From.Reg {
+				zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
+				r = REGTMP
+			}
+			zRIL(_a, op_LGFI, uint32(p.To.Reg), 0xffffffff, asm) // p.To.Reg <- -1
+			zRRE(op_SLBGR, uint32(p.To.Reg), uint32(r), asm)
+
+		case ASUBZE:
+			r := int(p.From.Reg)
+			if p.To.Reg == p.From.Reg {
+				zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
+				r = REGTMP
+			}
+			zRRE(op_LGR, uint32(p.To.Reg), REGZERO, asm) // p.To.Reg <- 0
+			zRRE(op_SLBGR, uint32(p.To.Reg), uint32(r), asm)
+
+		case ANEG:
+			r := int(p.From.Reg)
+			if r == 0 {
+				r = int(p.To.Reg)
+			}
+			zRRE(op_LCGR, uint32(p.To.Reg), uint32(r), asm)
+		}
+
+	case 67: // fmov $0 freg
+		var opcode uint32
+		switch p.As {
+		case AFMOVS:
+			opcode = op_LZER
+		case AFMOVD:
+			opcode = op_LZDR
+		}
+		zRRE(opcode, uint32(p.To.Reg), 0, asm)
+
+	case 68: // movw areg reg
+		zRRE(op_EAR, uint32(p.To.Reg), uint32(p.From.Reg-REG_AR0), asm)
+
+	case 69: // movw reg areg
+		zRRE(op_SAR, uint32(p.To.Reg-REG_AR0), uint32(p.From.Reg), asm)
+
+	case 70: // cmp reg reg
+		if p.As == ACMPW || p.As == ACMPWU {
+			zRR(zoprr(ctxt, p.As), uint32(p.From.Reg), uint32(p.To.Reg), asm)
+		} else {
+			zRRE(zoprre(ctxt, p.As), uint32(p.From.Reg), uint32(p.To.Reg), asm)
+		}
+
+	case 71: // cmp reg $constant
+		v := vregoff(ctxt, &p.To)
+		switch p.As {
+		case ACMP, ACMPW:
+			if int64(int32(v)) != v {
+				ctxt.Diag("%v overflows an int32", v)
+			}
+		case ACMPU, ACMPWU:
+			if int64(uint32(v)) != v {
+				ctxt.Diag("%v overflows a uint32", v)
+			}
+		}
+		zRIL(_a, zopril(ctxt, p.As), uint32(p.From.Reg), uint32(regoff(ctxt, &p.To)), asm)
+
+	case 72: // mov $constant/$addr mem
+		v := regoff(ctxt, &p.From)
+		d := regoff(ctxt, &p.To)
+		r := p.To.Reg
+		x := p.To.Index
+		if r == 0 {
+			r = o.param
+		}
+		if p.From.Sym != nil {
+			zRIL(_b, op_LARL, REGTMP, 0, asm)
+			if v&0x1 != 0 {
+				v -= 1
+				zRX(op_LA, REGTMP, REGTMP, 0, 1, asm)
+			}
+			addrilreloc(ctxt, p.From.Sym, int64(v))
+			if d < -DISP20/2 || d >= DISP20/2 {
+				zRIL(_a, op_LGFI, REGTMP2, uint32(d), asm)
+				if x != 0 {
+					zRRE(op_AGR, REGTMP2, uint32(x), asm)
+				}
+				d = 0
+				x = REGTMP2
+			}
+			zRXY(zopstore(ctxt, p.As), REGTMP, uint32(x), uint32(r), uint32(d), asm)
+		} else if int32(int16(v)) == v && x == 0 {
+			if d < 0 || d >= DISP12 {
+				if r == REGTMP || r == REGTMP2 {
+					zRIL(_a, op_AGFI, uint32(r), uint32(d), asm)
+				} else {
+					zRIL(_a, op_LGFI, REGTMP, uint32(d), asm)
+					zRRE(op_AGR, REGTMP, uint32(r), asm)
+					r = REGTMP
+				}
+				d = 0
+			}
+			var opcode uint32
+			switch p.As {
+			case AMOVD:
+				opcode = op_MVGHI
+			case AMOVW, AMOVWZ:
+				opcode = op_MVHI
+			case AMOVH, AMOVHZ:
+				opcode = op_MVHHI
+			case AMOVB, AMOVBZ:
+				opcode = op_MVI
+			}
+			if opcode == op_MVI {
+				zSI(opcode, uint32(v), uint32(r), uint32(d), asm)
+			} else {
+				zSIL(opcode, uint32(r), uint32(d), uint32(v), asm)
+			}
+		} else {
+			zRIL(_a, op_LGFI, REGTMP2, uint32(v), asm)
+			if d < -DISP20/2 || d >= DISP20/2 {
+				if r == REGTMP {
+					zRIL(_a, op_AGFI, REGTMP, uint32(d), asm)
+				} else {
+					zRIL(_a, op_LGFI, REGTMP, uint32(d), asm)
+					if x != 0 {
+						zRRE(op_AGR, REGTMP, uint32(x), asm)
+					}
+					x = REGTMP
+				}
+				d = 0
+			}
+			zRXY(zopstore(ctxt, p.As), REGTMP2, uint32(x), uint32(r), uint32(d), asm)
+		}
+
+	case 73: // mov $constant addr (including relocation)
+		v := regoff(ctxt, &p.From)
+		d := regoff(ctxt, &p.To)
+		a := uint32(0)
+		if d&1 != 0 {
+			d -= 1
+			a = 1
+		}
+		zRIL(_b, op_LARL, REGTMP, uint32(d), asm)
+		addrilreloc(ctxt, p.To.Sym, int64(d))
+		if p.From.Sym != nil {
+			zRIL(_b, op_LARL, REGTMP2, 0, asm)
+			a := uint32(0)
+			if v&0x1 != 0 {
+				v -= 1
+				zRX(op_LA, REGTMP2, REGTMP2, 0, 1, asm)
+			}
+			addrilrelocoffset(ctxt, p.From.Sym, int64(v), sizeRIL)
+			zRXY(zopstore(ctxt, p.As), REGTMP2, 0, REGTMP, a, asm)
+		} else if int32(int16(v)) == v {
+			var opcode uint32
+			switch p.As {
+			case AMOVD:
+				opcode = op_MVGHI
+			case AMOVW, AMOVWZ:
+				opcode = op_MVHI
+			case AMOVH, AMOVHZ:
+				opcode = op_MVHHI
+			case AMOVB, AMOVBZ:
+				opcode = op_MVI
+			}
+			if opcode == op_MVI {
+				zSI(opcode, uint32(v), REGTMP, a, asm)
+			} else {
+				zSIL(opcode, REGTMP, a, uint32(v), asm)
+			}
+		} else {
+			zRIL(_a, op_LGFI, REGTMP2, uint32(v), asm)
+			zRXY(zopstore(ctxt, p.As), REGTMP2, 0, REGTMP, a, asm)
+		}
+
+	case 74: // mov reg addr (including relocation)
+		i2 := regoff(ctxt, &p.To)
+		switch p.As {
+		case AMOVD:
+			zRIL(_b, op_STGRL, uint32(p.From.Reg), 0, asm)
+		case AMOVW, AMOVWZ: // The zero extension doesn't affect store instructions
+			zRIL(_b, op_STRL, uint32(p.From.Reg), 0, asm)
+		case AMOVH, AMOVHZ: // The zero extension doesn't affect store instructions
+			zRIL(_b, op_STHRL, uint32(p.From.Reg), 0, asm)
+		case AMOVB, AMOVBZ: // The zero extension doesn't affect store instructions
+			zRIL(_b, op_LARL, REGTMP, 0, asm)
+			adj := uint32(0) // adjustment needed for odd addresses
+			if i2&1 != 0 {
+				i2 -= 1
+				adj = 1
+			}
+			zRX(op_STC, uint32(p.From.Reg), 0, REGTMP, adj, asm)
+		case AFMOVD:
+			zRIL(_b, op_LARL, REGTMP, 0, asm)
+			zRX(op_STD, uint32(p.From.Reg), 0, REGTMP, 0, asm)
+		case AFMOVS:
+			zRIL(_b, op_LARL, REGTMP, 0, asm)
+			zRX(op_STE, uint32(p.From.Reg), 0, REGTMP, 0, asm)
+		}
+		addrilreloc(ctxt, p.To.Sym, int64(i2))
+
+	case 75: // mov addr reg (including relocation)
+		i2 := regoff(ctxt, &p.From)
+		switch p.As {
+		case AMOVD:
+			if i2&1 != 0 {
+				zRIL(_b, op_LARL, REGTMP, 0, asm)
+				zRXY(op_LG, uint32(p.To.Reg), REGTMP, 0, 1, asm)
+				i2 -= 1
+			} else {
+				zRIL(_b, op_LGRL, uint32(p.To.Reg), 0, asm)
+			}
+		case AMOVW:
+			zRIL(_b, op_LGFRL, uint32(p.To.Reg), 0, asm)
+		case AMOVWZ:
+			zRIL(_b, op_LLGFRL, uint32(p.To.Reg), 0, asm)
+		case AMOVH:
+			zRIL(_b, op_LGHRL, uint32(p.To.Reg), 0, asm)
+		case AMOVHZ:
+			zRIL(_b, op_LLGHRL, uint32(p.To.Reg), 0, asm)
+		case AMOVB, AMOVBZ:
+			zRIL(_b, op_LARL, REGTMP, 0, asm)
+			adj := uint32(0) // adjustment needed for odd addresses
+			if i2&1 != 0 {
+				i2 -= 1
+				adj = 1
+			}
+			switch p.As {
+			case AMOVB:
+				zRXY(op_LGB, uint32(p.To.Reg), 0, REGTMP, adj, asm)
+			case AMOVBZ:
+				zRXY(op_LLGC, uint32(p.To.Reg), 0, REGTMP, adj, asm)
+			}
+		case AFMOVD:
+			zRIL(_a, op_LARL, REGTMP, 0, asm)
+			zRX(op_LD, uint32(p.To.Reg), 0, REGTMP, 0, asm)
+		case AFMOVS:
+			zRIL(_a, op_LARL, REGTMP, 0, asm)
+			zRX(op_LE, uint32(p.To.Reg), 0, REGTMP, 0, asm)
+		}
+		addrilreloc(ctxt, p.From.Sym, int64(i2))
+
+	case 77: // syscall $constant
+		if p.From.Offset > 255 || p.From.Offset < 1 {
+			ctxt.Diag("illegal system call; system call number out of range: %v", p)
+			zE(op_TRAP2, asm) // trap always
+		} else {
+			zI(op_SVC, uint32(p.From.Offset), asm)
+		}
+
+	case 78: // undef
+		// "An instruction consisting entirely of binary 0s is guaranteed
+		// always to be an illegal instruction."
+		*asm = append(*asm, 0, 0, 0, 0)
+
+	case 79: // compare and swap reg reg reg
+		v := regoff(ctxt, &p.To)
+		if v < 0 {
+			v = 0
+		}
+		if p.As == ACS {
+			zRS(op_CS, uint32(p.From.Reg), uint32(p.Reg), uint32(p.To.Reg), uint32(v), asm)
+		} else if p.As == ACSG {
+			zRSY(op_CSG, uint32(p.From.Reg), uint32(p.Reg), uint32(p.To.Reg), uint32(v), asm)
+		}
+
+	case 81: // sync
+		zRR(op_BCR, 0xE, 0, asm)
+
+	case 82: // fixed to float conversion
+		var opcode uint32
+		switch p.As {
+		default:
+			log.Fatalf("unexpected opcode %v", p.As)
+		case ACEFBRA:
+			opcode = op_CEFBRA
+		case ACDFBRA:
+			opcode = op_CDFBRA
+		case ACEGBRA:
+			opcode = op_CEGBRA
+		case ACDGBRA:
+			opcode = op_CDGBRA
+		case ACELFBR:
+			opcode = op_CELFBR
+		case ACDLFBR:
+			opcode = op_CDLFBR
+		case ACELGBR:
+			opcode = op_CELGBR
+		case ACDLGBR:
+			opcode = op_CDLGBR
+		}
+		// set immediate operand M3 to 0 to use the default BFP rounding mode
+		// (usually round to nearest, ties to even)
+		// TODO(mundaym): should this be fixed at round to nearest, ties to even?
+		// M4 is reserved and must be 0
+		zRRF(opcode, 0, 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+
+	case 83: // float to fixed conversion
+		var opcode uint32
+		switch p.As {
+		default:
+			log.Fatalf("unexpected opcode %v", p.As)
+		case ACFEBRA:
+			opcode = op_CFEBRA
+		case ACFDBRA:
+			opcode = op_CFDBRA
+		case ACGEBRA:
+			opcode = op_CGEBRA
+		case ACGDBRA:
+			opcode = op_CGDBRA
+		case ACLFEBR:
+			opcode = op_CLFEBR
+		case ACLFDBR:
+			opcode = op_CLFDBR
+		case ACLGEBR:
+			opcode = op_CLGEBR
+		case ACLGDBR:
+			opcode = op_CLGDBR
+		}
+		// set immediate operand M3 to 5 for rounding toward zero (required by Go spec)
+		// M4 is reserved and must be 0
+		zRRF(opcode, 5, 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+
+	case 84: // storage-and-storage operations $length mem mem (length in From3)
+		l := regoff(ctxt, p.From3)
+		if l < 1 || l > 256 {
+			ctxt.Diag("number of bytes (%v) not in range [1,256]", l)
+		}
+		if p.From.Index != 0 || p.To.Index != 0 {
+			ctxt.Diag("cannot use index reg")
+		}
+		b1 := p.To.Reg
+		b2 := p.From.Reg
+		if b1 == 0 {
+			b1 = o.param
+		}
+		if b2 == 0 {
+			b2 = o.param
+		}
+		d1 := regoff(ctxt, &p.To)
+		d2 := regoff(ctxt, &p.From)
+		if d1 < 0 || d1 >= DISP12 {
+			if b2 == REGTMP {
+				ctxt.Diag("REGTMP conflict")
+			}
+			if b1 != REGTMP {
+				zRRE(op_LGR, REGTMP, uint32(b1), asm)
+			}
+			zRIL(_a, op_AGFI, REGTMP, uint32(d1), asm)
+			if d1 == d2 && b1 == b2 {
+				d2 = 0
+				b2 = REGTMP
+			}
+			d1 = 0
+			b1 = REGTMP
+		}
+		if d2 < 0 || d2 >= DISP12 {
+			if b1 == REGTMP2 {
+				ctxt.Diag("REGTMP2 conflict")
+			}
+			if b2 != REGTMP2 {
+				zRRE(op_LGR, REGTMP2, uint32(b2), asm)
+			}
+			zRIL(_a, op_AGFI, REGTMP2, uint32(d2), asm)
+			d2 = 0
+			b2 = REGTMP2
+		}
+		var opcode uint32
+		switch p.As {
+		default:
+			ctxt.Diag("unexpected opcode %v", p.As)
+		case AMVC:
+			opcode = op_MVC
+		case ACLC:
+			opcode = op_CLC
+			// swap operand order for CLC so that it matches CMP
+			b1, b2 = b2, b1
+			d1, d2 = d2, d1
+		case AXC:
+			opcode = op_XC
+		case AOC:
+			opcode = op_OC
+		case ANC:
+			opcode = op_NC
+		}
+		zSS(_a, opcode, uint32(l-1), 0, uint32(b1), uint32(d1), uint32(b2), uint32(d2), asm)
+
+	case 85: // load address relative long
+		v := regoff(ctxt, &p.From)
+		if p.From.Sym == nil {
+			if (v & 1) != 0 {
+				ctxt.Diag("cannot use LARL with odd offset: %v", v)
+			}
+		} else {
+			addrilreloc(ctxt, p.From.Sym, int64(v))
+			v = 0
+		}
+		zRIL(_b, op_LARL, uint32(p.To.Reg), uint32(v>>1), asm)
+
+	case 86: // load address
+		d := vregoff(ctxt, &p.From)
+		x := p.From.Index
+		b := p.From.Reg
+		if b == 0 {
+			b = o.param
+		}
+		switch p.As {
+		case ALA:
+			zRX(op_LA, uint32(p.To.Reg), uint32(x), uint32(b), uint32(d), asm)
+		case ALAY:
+			zRXY(op_LAY, uint32(p.To.Reg), uint32(x), uint32(b), uint32(d), asm)
+		}
+
+	case 87: // execute relative long
+		v := vregoff(ctxt, &p.From)
+		if p.From.Sym == nil {
+			if v&1 != 0 {
+				ctxt.Diag("cannot use EXRL with odd offset: %v", v)
+			}
+		} else {
+			addrilreloc(ctxt, p.From.Sym, v)
+			v = 0
+		}
+		zRIL(_b, op_EXRL, uint32(p.To.Reg), uint32(v>>1), asm)
+
+	case 88: // store clock
+		var opcode uint32
+		switch p.As {
+		case ASTCK:
+			opcode = op_STCK
+		case ASTCKC:
+			opcode = op_STCKC
+		case ASTCKE:
+			opcode = op_STCKE
+		case ASTCKF:
+			opcode = op_STCKF
+		}
+		v := vregoff(ctxt, &p.To)
+		r := int(p.To.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		zS(opcode, uint32(r), uint32(v), asm)
+
+	case 89: // compare and branch reg reg
+		var v int32
+		if p.Pcond != nil {
+			v = int32((p.Pcond.Pc - p.Pc) >> 1)
+		}
+		var opcode, opcode2 uint32
+		switch p.As {
+		case ACMPBEQ, ACMPBGE, ACMPBGT, ACMPBLE, ACMPBLT, ACMPBNE:
+			opcode = op_CGRJ
+			opcode2 = op_CGR
+		case ACMPUBEQ, ACMPUBGE, ACMPUBGT, ACMPUBLE, ACMPUBLT, ACMPUBNE:
+			opcode = op_CLGRJ
+			opcode2 = op_CLGR
+		}
+		mask := branchMask(ctxt, p)
+		if int32(int16(v)) != v {
+			zRRE(opcode2, uint32(p.From.Reg), uint32(p.Reg), asm)
+			zRIL(_c, op_BRCL, mask, uint32(v-sizeRRE/2), asm)
+		} else {
+			zRIE(_b, opcode, uint32(p.From.Reg), uint32(p.Reg), uint32(v), 0, 0, mask, 0, asm)
+		}
+
+	case 90: // compare and branch reg $constant
+		var v int32
+		if p.Pcond != nil {
+			v = int32((p.Pcond.Pc - p.Pc) >> 1)
+		}
+		var opcode, opcode2 uint32
+		switch p.As {
+		case ACMPBEQ, ACMPBGE, ACMPBGT, ACMPBLE, ACMPBLT, ACMPBNE:
+			opcode = op_CGIJ
+			opcode2 = op_CGFI
+		case ACMPUBEQ, ACMPUBGE, ACMPUBGT, ACMPUBLE, ACMPUBLT, ACMPUBNE:
+			opcode = op_CLGIJ
+			opcode2 = op_CLGFI
+		}
+		mask := branchMask(ctxt, p)
+		if int32(int16(v)) != v {
+			zRIL(_a, opcode2, uint32(p.From.Reg), uint32(regoff(ctxt, p.From3)), asm)
+			zRIL(_c, op_BRCL, mask, uint32(v-sizeRIL/2), asm)
+		} else {
+			zRIE(_c, opcode, uint32(p.From.Reg), mask, uint32(v), 0, 0, 0, uint32(regoff(ctxt, p.From3)), asm)
+		}
+
+	case 93: // GOT lookup
+		v := vregoff(ctxt, &p.To)
+		if v != 0 {
+			ctxt.Diag("invalid offset against GOT slot %v", p)
+		}
+		zRIL(_b, op_LGRL, uint32(p.To.Reg), 0, asm)
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc + 2)
+		rel.Siz = 4
+		rel.Sym = p.From.Sym
+		rel.Type = obj.R_GOTPCREL
+		rel.Add = 2 + int64(rel.Siz)
+
+	case 94: // TLS local exec model
+		zRIL(_b, op_LARL, REGTMP, (sizeRIL+sizeRXY+sizeRI)>>1, asm)
+		zRXY(op_LG, uint32(p.To.Reg), REGTMP, 0, 0, asm)
+		zRI(op_BRC, 0xF, (sizeRI+8)>>1, asm)
+		*asm = append(*asm, 0, 0, 0, 0, 0, 0, 0, 0)
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc + sizeRIL + sizeRXY + sizeRI)
+		rel.Siz = 8
+		rel.Sym = p.From.Sym
+		rel.Type = obj.R_TLS_LE
+		rel.Add = 0
+
+	case 95: // TLS initial exec model
+		// Assembly                   | Relocation symbol    | Done Here?
+		// --------------------------------------------------------------
+		// ear  %r11, %a0             |                      |
+		// sllg %r11, %r11, 32        |                      |
+		// ear  %r11, %a1             |                      |
+		// larl %r10, <var>@indntpoff | R_390_TLS_IEENT      | Y
+		// lg   %r10, 0(%r10)         | R_390_TLS_LOAD (tag) | Y
+		// la   %r10, 0(%r10, %r11)   |                      |
+		// --------------------------------------------------------------
+
+		// R_390_TLS_IEENT
+		zRIL(_b, op_LARL, REGTMP, 0, asm)
+		ieent := obj.Addrel(ctxt.Cursym)
+		ieent.Off = int32(ctxt.Pc + 2)
+		ieent.Siz = 4
+		ieent.Sym = p.From.Sym
+		ieent.Type = obj.R_TLS_IE
+		ieent.Add = 2 + int64(ieent.Siz)
+
+		// R_390_TLS_LOAD
+		zRXY(op_LGF, uint32(p.To.Reg), REGTMP, 0, 0, asm)
+		// TODO(mundaym): add R_390_TLS_LOAD relocation here
+		// not strictly required but might allow the linker to optimize
+
+	case 96: // clear macro
+		length := vregoff(ctxt, &p.From)
+		offset := vregoff(ctxt, &p.To)
+		reg := p.To.Reg
+		if reg == 0 {
+			reg = o.param
+		}
+		if length <= 0 {
+			ctxt.Diag("cannot CLEAR %d bytes, must be greater than 0", length)
+		}
+		for length > 0 {
+			if offset < 0 || offset >= DISP12 {
+				if offset >= -DISP20/2 && offset < DISP20/2 {
+					zRXY(op_LAY, REGTMP, uint32(reg), 0, uint32(offset), asm)
+				} else {
+					if reg != REGTMP {
+						zRRE(op_LGR, REGTMP, uint32(reg), asm)
+					}
+					zRIL(_a, op_AGFI, REGTMP, uint32(offset), asm)
+				}
+				reg = REGTMP
+				offset = 0
+			}
+			size := length
+			if size > 256 {
+				size = 256
+			}
+
+			switch size {
+			case 1:
+				zSI(op_MVI, 0, uint32(reg), uint32(offset), asm)
+			case 2:
+				zSIL(op_MVHHI, uint32(reg), uint32(offset), 0, asm)
+			case 4:
+				zSIL(op_MVHI, uint32(reg), uint32(offset), 0, asm)
+			case 8:
+				zSIL(op_MVGHI, uint32(reg), uint32(offset), 0, asm)
+			default:
+				zSS(_a, op_XC, uint32(size-1), 0, uint32(reg), uint32(offset), uint32(reg), uint32(offset), asm)
+			}
+
+			length -= size
+			offset += size
+		}
+
+	case 97: // store multiple
+		rstart := p.From.Reg
+		rend := p.Reg
+		offset := regoff(ctxt, &p.To)
+		reg := p.To.Reg
+		if reg == 0 {
+			reg = o.param
+		}
+		if offset < -DISP20/2 || offset >= DISP20/2 {
+			if reg != REGTMP {
+				zRRE(op_LGR, REGTMP, uint32(reg), asm)
+			}
+			zRIL(_a, op_AGFI, REGTMP, uint32(offset), asm)
+			reg = REGTMP
+			offset = 0
+		}
+		switch p.As {
+		case ASTMY:
+			if offset >= 0 && offset < DISP12 {
+				zRS(op_STM, uint32(rstart), uint32(rend), uint32(reg), uint32(offset), asm)
+			} else {
+				zRSY(op_STMY, uint32(rstart), uint32(rend), uint32(reg), uint32(offset), asm)
+			}
+		case ASTMG:
+			zRSY(op_STMG, uint32(rstart), uint32(rend), uint32(reg), uint32(offset), asm)
+		}
+
+	case 98: // load multiple
+		rstart := p.Reg
+		rend := p.To.Reg
+		offset := regoff(ctxt, &p.From)
+		reg := p.From.Reg
+		if reg == 0 {
+			reg = o.param
+		}
+		if offset < -DISP20/2 || offset >= DISP20/2 {
+			if reg != REGTMP {
+				zRRE(op_LGR, REGTMP, uint32(reg), asm)
+			}
+			zRIL(_a, op_AGFI, REGTMP, uint32(offset), asm)
+			reg = REGTMP
+			offset = 0
+		}
+		switch p.As {
+		case ALMY:
+			if offset >= 0 && offset < DISP12 {
+				zRS(op_LM, uint32(rstart), uint32(rend), uint32(reg), uint32(offset), asm)
+			} else {
+				zRSY(op_LMY, uint32(rstart), uint32(rend), uint32(reg), uint32(offset), asm)
+			}
+		case ALMG:
+			zRSY(op_LMG, uint32(rstart), uint32(rend), uint32(reg), uint32(offset), asm)
+		}
+
+	case 100: // VRX STORE
+		op, m3, _ := vop(p.As)
+		if p.From3 != nil {
+			m3 = uint32(vregoff(ctxt, p.From3))
+		}
+		b2 := p.To.Reg
+		if b2 == 0 {
+			b2 = o.param
+		}
+		d2 := uint32(vregoff(ctxt, &p.To))
+		zVRX(op, uint32(p.From.Reg), uint32(p.To.Index), uint32(b2), d2, m3, asm)
+
+	case 101: // VRX LOAD
+		op, m3, _ := vop(p.As)
+		if p.From3 != nil {
+			m3 = uint32(vregoff(ctxt, p.From3))
+		}
+		b2 := p.From.Reg
+		if b2 == 0 {
+			b2 = o.param
+		}
+		d2 := uint32(vregoff(ctxt, &p.From))
+		zVRX(op, uint32(p.To.Reg), uint32(p.From.Index), uint32(b2), d2, m3, asm)
+
+	case 102: // VRV SCATTER
+		op, m3, _ := vop(p.As)
+		if p.From3 != nil {
+			m3 = uint32(vregoff(ctxt, p.From3))
+		}
+		b2 := p.To.Reg
+		if b2 == 0 {
+			b2 = o.param
+		}
+		d2 := uint32(vregoff(ctxt, &p.To))
+		zVRV(op, uint32(p.From.Reg), uint32(p.To.Index), uint32(b2), d2, m3, asm)
+
+	case 103: // VRV GATHER
+		op, m3, _ := vop(p.As)
+		if p.From3 != nil {
+			m3 = uint32(vregoff(ctxt, p.From3))
+		}
+		b2 := p.From.Reg
+		if b2 == 0 {
+			b2 = o.param
+		}
+		d2 := uint32(vregoff(ctxt, &p.From))
+		zVRV(op, uint32(p.To.Reg), uint32(p.From.Index), uint32(b2), d2, m3, asm)
+
+	case 104: // VRS SHIFT/ROTATE and LOAD GR FROM VR ELEMENT
+		op, m4, _ := vop(p.As)
+		fr := p.Reg
+		if fr == 0 {
+			fr = p.To.Reg
+		}
+		bits := uint32(vregoff(ctxt, &p.From))
+		zVRS(op, uint32(p.To.Reg), uint32(fr), uint32(p.From.Reg), bits, m4, asm)
+
+	case 105: // VRS STORE MULTIPLE
+		op, _, _ := vop(p.As)
+		offset := uint32(vregoff(ctxt, &p.To))
+		reg := p.To.Reg
+		if reg == 0 {
+			reg = o.param
+		}
+		zVRS(op, uint32(p.From.Reg), uint32(p.Reg), uint32(reg), offset, 0, asm)
+
+	case 106: // VRS LOAD MULTIPLE
+		op, _, _ := vop(p.As)
+		offset := uint32(vregoff(ctxt, &p.From))
+		reg := p.From.Reg
+		if reg == 0 {
+			reg = o.param
+		}
+		zVRS(op, uint32(p.Reg), uint32(p.To.Reg), uint32(reg), offset, 0, asm)
+
+	case 107: // VRS STORE WITH LENGTH
+		op, _, _ := vop(p.As)
+		offset := uint32(vregoff(ctxt, &p.To))
+		reg := p.To.Reg
+		if reg == 0 {
+			reg = o.param
+		}
+		zVRS(op, uint32(p.From.Reg), uint32(p.From3.Reg), uint32(reg), offset, 0, asm)
+
+	case 108: // VRS LOAD WITH LENGTH
+		op, _, _ := vop(p.As)
+		offset := uint32(vregoff(ctxt, &p.From))
+		reg := p.From.Reg
+		if reg == 0 {
+			reg = o.param
+		}
+		zVRS(op, uint32(p.To.Reg), uint32(p.From3.Reg), uint32(reg), offset, 0, asm)
+
+	case 109: // VRI-a
+		op, _, _ := vop(p.As)
+		i2 := uint32(vregoff(ctxt, &p.From))
+		switch p.As {
+		case AVZERO:
+			i2 = 0
+		case AVONE:
+			i2 = 0xffff
+		}
+		m3 := uint32(0)
+		if p.From3 != nil {
+			m3 = uint32(vregoff(ctxt, p.From3))
+		}
+		zVRIa(op, uint32(p.To.Reg), i2, m3, asm)
+
+	case 110:
+		op, m4, _ := vop(p.As)
+		i2 := uint32(vregoff(ctxt, p.From3))
+		i3 := uint32(vregoff(ctxt, &p.From))
+		zVRIb(op, uint32(p.To.Reg), i2, i3, m4, asm)
+
+	case 111:
+		op, m4, _ := vop(p.As)
+		i2 := uint32(vregoff(ctxt, &p.From))
+		zVRIc(op, uint32(p.To.Reg), uint32(p.Reg), i2, m4, asm)
+
+	case 112:
+		op, m5, _ := vop(p.As)
+		i4 := uint32(vregoff(ctxt, p.From3))
+		zVRId(op, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), i4, m5, asm)
+
+	case 113:
+		op, m4, _ := vop(p.As)
+		m5 := singleElementMask(p.As)
+		i3 := uint32(vregoff(ctxt, &p.From))
+		zVRIe(op, uint32(p.To.Reg), uint32(p.Reg), i3, m5, m4, asm)
+
+	case 114: // VRR-a
+		op, m3, m5 := vop(p.As)
+		m4 := singleElementMask(p.As)
+		zVRRa(op, uint32(p.To.Reg), uint32(p.From.Reg), m5, m4, m3, asm)
+
+	case 115: // VRR-a COMPARE
+		op, m3, m5 := vop(p.As)
+		m4 := singleElementMask(p.As)
+		zVRRa(op, uint32(p.From.Reg), uint32(p.To.Reg), m5, m4, m3, asm)
+
+	case 116: // VRR-a
+
+	case 117: // VRR-b
+		op, m4, m5 := vop(p.As)
+		zVRRb(op, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), m5, m4, asm)
+
+	case 118: // VRR-c
+		op, m4, m6 := vop(p.As)
+		m5 := singleElementMask(p.As)
+		v3 := p.Reg
+		if v3 == 0 {
+			v3 = p.To.Reg
+		}
+		zVRRc(op, uint32(p.To.Reg), uint32(p.From.Reg), uint32(v3), m6, m5, m4, asm)
+
+	case 119: // VRR-c SHIFT/ROTATE/DIVIDE/SUB (rhs value on the left, like SLD, DIV etc.)
+		op, m4, m6 := vop(p.As)
+		m5 := singleElementMask(p.As)
+		v2 := p.Reg
+		if v2 == 0 {
+			v2 = p.To.Reg
+		}
+		zVRRc(op, uint32(p.To.Reg), uint32(v2), uint32(p.From.Reg), m6, m5, m4, asm)
+
+	case 120: // VRR-d
+		op, m6, _ := vop(p.As)
+		m5 := singleElementMask(p.As)
+		v1 := uint32(p.To.Reg)
+		v2 := uint32(p.From3.Reg)
+		v3 := uint32(p.From.Reg)
+		v4 := uint32(p.Reg)
+		zVRRd(op, v1, v2, v3, m6, m5, v4, asm)
+
+	case 121: // VRR-e
+		op, m6, _ := vop(p.As)
+		m5 := singleElementMask(p.As)
+		v1 := uint32(p.To.Reg)
+		v2 := uint32(p.From3.Reg)
+		v3 := uint32(p.From.Reg)
+		v4 := uint32(p.Reg)
+		zVRRe(op, v1, v2, v3, m5, m6, v4, asm)
+
+	case 122: // VRR-f LOAD VRS FROM GRS DISJOINT
+		op, _, _ := vop(p.As)
+		zVRRf(op, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), asm)
+
+	case 123: // VPDI $m4, V2, V3, V1
+		op, _, _ := vop(p.As)
+		m4 := regoff(ctxt, p.From3)
+		zVRRc(op, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), 0, 0, uint32(m4), asm)
+	}
+}
+
+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))
+}
+
+// zopload returns the RXY op for the given load
+func zopload(ctxt *obj.Link, a obj.As) uint32 {
+	switch a {
+	// fixed point load
+	case AMOVD:
+		return op_LG
+	case AMOVW:
+		return op_LGF
+	case AMOVWZ:
+		return op_LLGF
+	case AMOVH:
+		return op_LGH
+	case AMOVHZ:
+		return op_LLGH
+	case AMOVB:
+		return op_LGB
+	case AMOVBZ:
+		return op_LLGC
+
+	// floating point load
+	case AFMOVD:
+		return op_LDY
+	case AFMOVS:
+		return op_LEY
+
+	// byte reversed load
+	case AMOVDBR:
+		return op_LRVG
+	case AMOVWBR:
+		return op_LRV
+	case AMOVHBR:
+		return op_LRVH
+	}
+
+	ctxt.Diag("unknown store opcode %v", obj.Aconv(a))
+	return 0
+}
+
+// zopstore returns the RXY op for the given store
+func zopstore(ctxt *obj.Link, a obj.As) uint32 {
+	switch a {
+	// fixed point store
+	case AMOVD:
+		return op_STG
+	case AMOVW, AMOVWZ:
+		return op_STY
+	case AMOVH, AMOVHZ:
+		return op_STHY
+	case AMOVB, AMOVBZ:
+		return op_STCY
+
+	// floating point store
+	case AFMOVD:
+		return op_STDY
+	case AFMOVS:
+		return op_STEY
+
+	// byte reversed store
+	case AMOVDBR:
+		return op_STRVG
+	case AMOVWBR:
+		return op_STRV
+	case AMOVHBR:
+		return op_STRVH
+	}
+
+	ctxt.Diag("unknown store opcode %v", obj.Aconv(a))
+	return 0
+}
+
+// zoprre returns the RRE op for the given a
+func zoprre(ctxt *obj.Link, a obj.As) uint32 {
+	switch a {
+	case ACMP:
+		return op_CGR
+	case ACMPU:
+		return op_CLGR
+	case AFCMPO: //ordered
+		return op_KDBR
+	case AFCMPU: //unordered
+		return op_CDBR
+	case ACEBR:
+		return op_CEBR
+	}
+	ctxt.Diag("unknown rre opcode %v", obj.Aconv(a))
+	return 0
+}
+
+// zoprr returns the RR op for the given a
+func zoprr(ctxt *obj.Link, a obj.As) uint32 {
+	switch a {
+	case ACMPW:
+		return op_CR
+	case ACMPWU:
+		return op_CLR
+	}
+	ctxt.Diag("unknown rr opcode %v", obj.Aconv(a))
+	return 0
+}
+
+// zopril returns the RIL op for the given a
+func zopril(ctxt *obj.Link, a obj.As) uint32 {
+	switch a {
+	case ACMP:
+		return op_CGFI
+	case ACMPU:
+		return op_CLGFI
+	case ACMPW:
+		return op_CFI
+	case ACMPWU:
+		return op_CLFI
+	}
+	ctxt.Diag("unknown ril opcode %v", obj.Aconv(a))
+	return 0
+}
+
+// z instructions sizes
+const (
+	sizeE    = 2
+	sizeI    = 2
+	sizeIE   = 4
+	sizeMII  = 6
+	sizeRI   = 4
+	sizeRI1  = 4
+	sizeRI2  = 4
+	sizeRI3  = 4
+	sizeRIE  = 6
+	sizeRIE1 = 6
+	sizeRIE2 = 6
+	sizeRIE3 = 6
+	sizeRIE4 = 6
+	sizeRIE5 = 6
+	sizeRIE6 = 6
+	sizeRIL  = 6
+	sizeRIL1 = 6
+	sizeRIL2 = 6
+	sizeRIL3 = 6
+	sizeRIS  = 6
+	sizeRR   = 2
+	sizeRRD  = 4
+	sizeRRE  = 4
+	sizeRRF  = 4
+	sizeRRF1 = 4
+	sizeRRF2 = 4
+	sizeRRF3 = 4
+	sizeRRF4 = 4
+	sizeRRF5 = 4
+	sizeRRR  = 2
+	sizeRRS  = 6
+	sizeRS   = 4
+	sizeRS1  = 4
+	sizeRS2  = 4
+	sizeRSI  = 4
+	sizeRSL  = 6
+	sizeRSY  = 6
+	sizeRSY1 = 6
+	sizeRSY2 = 6
+	sizeRX   = 4
+	sizeRX1  = 4
+	sizeRX2  = 4
+	sizeRXE  = 6
+	sizeRXF  = 6
+	sizeRXY  = 6
+	sizeRXY1 = 6
+	sizeRXY2 = 6
+	sizeS    = 4
+	sizeSI   = 4
+	sizeSIL  = 6
+	sizeSIY  = 6
+	sizeSMI  = 6
+	sizeSS   = 6
+	sizeSS1  = 6
+	sizeSS2  = 6
+	sizeSS3  = 6
+	sizeSS4  = 6
+	sizeSS5  = 6
+	sizeSS6  = 6
+	sizeSSE  = 6
+	sizeSSF  = 6
+)
+
+// instruction format variations
+type form int
+
+const (
+	_a form = iota
+	_b
+	_c
+	_d
+	_e
+	_f
+)
+
+func zE(op uint32, asm *[]byte) {
+	*asm = append(*asm, uint8(op>>8), uint8(op))
+}
+
+func zI(op, i1 uint32, asm *[]byte) {
+	*asm = append(*asm, uint8(op>>8), uint8(i1))
+}
+
+func zMII(op, m1, ri2, ri3 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(m1)<<4)|uint8((ri2>>8)&0x0F),
+		uint8(ri2),
+		uint8(ri3>>16),
+		uint8(ri3>>8),
+		uint8(ri3))
+}
+
+func zRI(op, r1_m1, i2_ri2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1_m1)<<4)|(uint8(op)&0x0F),
+		uint8(i2_ri2>>8),
+		uint8(i2_ri2))
+}
+
+// Expected argument values for the instruction formats.
+//
+// Format    a1  a2   a3  a4  a5  a6  a7
+// ------------------------------------
+// a         r1,  0,  i2,  0,  0, m3,  0
+// b         r1, r2, ri4,  0,  0, m3,  0
+// c         r1, m3, ri4,  0,  0,  0, i2
+// d         r1, r3,  i2,  0,  0,  0,  0
+// e         r1, r3, ri2,  0,  0,  0,  0
+// f         r1, r2,   0, i3, i4,  0, i5
+// g         r1, m3,  i2,  0,  0,  0,  0
+func zRIE(f form, op, r1, r2_m3_r3, i2_ri4_ri2, i3, i4, m3, i2_i5 uint32, asm *[]byte) {
+	*asm = append(*asm, uint8(op>>8), uint8(r1)<<4|uint8(r2_m3_r3&0x0F))
+
+	switch f {
+	default:
+		*asm = append(*asm, uint8(i2_ri4_ri2>>8), uint8(i2_ri4_ri2))
+	case _f:
+		*asm = append(*asm, uint8(i3), uint8(i4))
+	}
+
+	switch f {
+	case _a, _b:
+		*asm = append(*asm, uint8(m3)<<4)
+	default:
+		*asm = append(*asm, uint8(i2_i5))
+	}
+
+	*asm = append(*asm, uint8(op))
+}
+
+func zRIL(f form, op, r1_m1, i2_ri2 uint32, asm *[]byte) {
+	if f == _a || f == _b {
+		r1_m1 = r1_m1 - obj.RBaseS390X // this is a register base
+	}
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1_m1)<<4)|(uint8(op)&0x0F),
+		uint8(i2_ri2>>24),
+		uint8(i2_ri2>>16),
+		uint8(i2_ri2>>8),
+		uint8(i2_ri2))
+}
+
+func zRIS(op, r1, m3, b4, d4, i2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1)<<4)|uint8(m3&0x0F),
+		(uint8(b4)<<4)|(uint8(d4>>8)&0x0F),
+		uint8(d4),
+		uint8(i2),
+		uint8(op))
+}
+
+func zRR(op, r1, r2 uint32, asm *[]byte) {
+	*asm = append(*asm, uint8(op>>8), (uint8(r1)<<4)|uint8(r2&0x0F))
+}
+
+func zRRD(op, r1, r3, r2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(op),
+		uint8(r1)<<4,
+		(uint8(r3)<<4)|uint8(r2&0x0F))
+}
+
+func zRRE(op, r1, r2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(op),
+		0,
+		(uint8(r1)<<4)|uint8(r2&0x0F))
+}
+
+func zRRF(op, r3_m3, m4, r1, r2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(op),
+		(uint8(r3_m3)<<4)|uint8(m4&0x0F),
+		(uint8(r1)<<4)|uint8(r2&0x0F))
+}
+
+func zRRS(op, r1, r2, b4, d4, m3 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1)<<4)|uint8(r2&0x0F),
+		(uint8(b4)<<4)|uint8((d4>>8)&0x0F),
+		uint8(d4),
+		uint8(m3)<<4,
+		uint8(op))
+}
+
+func zRS(op, r1, r3_m3, b2, d2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1)<<4)|uint8(r3_m3&0x0F),
+		(uint8(b2)<<4)|uint8((d2>>8)&0x0F),
+		uint8(d2))
+}
+
+func zRSI(op, r1, r3, ri2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1)<<4)|uint8(r3&0x0F),
+		uint8(ri2>>8),
+		uint8(ri2))
+}
+
+func zRSL(op, l1, b2, d2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(l1),
+		(uint8(b2)<<4)|uint8((d2>>8)&0x0F),
+		uint8(d2),
+		uint8(op))
+}
+
+func zRSY(op, r1, r3_m3, b2, d2 uint32, asm *[]byte) {
+	dl2 := uint16(d2) & 0x0FFF
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1)<<4)|uint8(r3_m3&0x0F),
+		(uint8(b2)<<4)|(uint8(dl2>>8)&0x0F),
+		uint8(dl2),
+		uint8(d2>>12),
+		uint8(op))
+}
+
+func zRX(op, r1_m1, x2, b2, d2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1_m1)<<4)|uint8(x2&0x0F),
+		(uint8(b2)<<4)|uint8((d2>>8)&0x0F),
+		uint8(d2))
+}
+
+func zRXE(op, r1, x2, b2, d2, m3 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1)<<4)|uint8(x2&0x0F),
+		(uint8(b2)<<4)|uint8((d2>>8)&0x0F),
+		uint8(d2),
+		uint8(m3)<<4,
+		uint8(op))
+}
+
+func zRXF(op, r3, x2, b2, d2, m1 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r3)<<4)|uint8(x2&0x0F),
+		(uint8(b2)<<4)|uint8((d2>>8)&0x0F),
+		uint8(d2),
+		uint8(m1)<<4,
+		uint8(op))
+}
+
+func zRXY(op, r1_m1, x2, b2, d2 uint32, asm *[]byte) {
+	dl2 := uint16(d2) & 0x0FFF
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r1_m1)<<4)|uint8(x2&0x0F),
+		(uint8(b2)<<4)|(uint8(dl2>>8)&0x0F),
+		uint8(dl2),
+		uint8(d2>>12),
+		uint8(op))
+}
+
+func zS(op, b2, d2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(op),
+		(uint8(b2)<<4)|uint8((d2>>8)&0x0F),
+		uint8(d2))
+}
+
+func zSI(op, i2, b1, d1 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(i2),
+		(uint8(b1)<<4)|uint8((d1>>8)&0x0F),
+		uint8(d1))
+}
+
+func zSIL(op, b1, d1, i2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(op),
+		(uint8(b1)<<4)|uint8((d1>>8)&0x0F),
+		uint8(d1),
+		uint8(i2>>8),
+		uint8(i2))
+}
+
+func zSIY(op, i2, b1, d1 uint32, asm *[]byte) {
+	dl1 := uint16(d1) & 0x0FFF
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(i2),
+		(uint8(b1)<<4)|(uint8(dl1>>8)&0x0F),
+		uint8(dl1),
+		uint8(d1>>12),
+		uint8(op))
+}
+
+func zSMI(op, m1, b3, d3, ri2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(m1)<<4,
+		(uint8(b3)<<4)|uint8((d3>>8)&0x0F),
+		uint8(d3),
+		uint8(ri2>>8),
+		uint8(ri2))
+}
+
+// Expected argument values for the instruction formats.
+//
+// Format    a1  a2  a3  a4  a5  a6
+// -------------------------------
+// a         l1,  0, b1, d1, b2, d2
+// b         l1, l2, b1, d1, b2, d2
+// c         l1, i3, b1, d1, b2, d2
+// d         r1, r3, b1, d1, b2, d2
+// e         r1, r3, b2, d2, b4, d4
+// f          0, l2, b1, d1, b2, d2
+func zSS(f form, op, l1_r1, l2_i3_r3, b1_b2, d1_d2, b2_b4, d2_d4 uint32, asm *[]byte) {
+	*asm = append(*asm, uint8(op>>8))
+
+	switch f {
+	case _a:
+		*asm = append(*asm, uint8(l1_r1))
+	case _b, _c, _d, _e:
+		*asm = append(*asm, (uint8(l1_r1)<<4)|uint8(l2_i3_r3&0x0F))
+	case _f:
+		*asm = append(*asm, uint8(l2_i3_r3))
+	}
+
+	*asm = append(*asm,
+		(uint8(b1_b2)<<4)|uint8((d1_d2>>8)&0x0F),
+		uint8(d1_d2),
+		(uint8(b2_b4)<<4)|uint8((d2_d4>>8)&0x0F),
+		uint8(d2_d4))
+}
+
+func zSSE(op, b1, d1, b2, d2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(op),
+		(uint8(b1)<<4)|uint8((d1>>8)&0x0F),
+		uint8(d1),
+		(uint8(b2)<<4)|uint8((d2>>8)&0x0F),
+		uint8(d2))
+}
+
+func zSSF(op, r3, b1, d1, b2, d2 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(r3)<<4)|(uint8(op)&0x0F),
+		(uint8(b1)<<4)|uint8((d1>>8)&0x0F),
+		uint8(d1),
+		(uint8(b2)<<4)|uint8((d2>>8)&0x0F),
+		uint8(d2))
+}
+
+func rxb(va, vb, vc, vd uint32) uint8 {
+	mask := uint8(0)
+	if va >= REG_V16 && va <= REG_V31 {
+		mask |= 0x8
+	}
+	if vb >= REG_V16 && vb <= REG_V31 {
+		mask |= 0x4
+	}
+	if vc >= REG_V16 && vc <= REG_V31 {
+		mask |= 0x2
+	}
+	if vd >= REG_V16 && vd <= REG_V31 {
+		mask |= 0x1
+	}
+	return mask
+}
+
+func zVRX(op, v1, x2, b2, d2, m3 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(x2)&0xf),
+		(uint8(b2)<<4)|(uint8(d2>>8)&0xf),
+		uint8(d2),
+		(uint8(m3)<<4)|rxb(v1, 0, 0, 0),
+		uint8(op))
+}
+
+func zVRV(op, v1, v2, b2, d2, m3 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v2)&0xf),
+		(uint8(b2)<<4)|(uint8(d2>>8)&0xf),
+		uint8(d2),
+		(uint8(m3)<<4)|rxb(v1, v2, 0, 0),
+		uint8(op))
+}
+
+func zVRS(op, v1, v3_r3, b2, d2, m4 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v3_r3)&0xf),
+		(uint8(b2)<<4)|(uint8(d2>>8)&0xf),
+		uint8(d2),
+		(uint8(m4)<<4)|rxb(v1, v3_r3, 0, 0),
+		uint8(op))
+}
+
+func zVRRa(op, v1, v2, m5, m4, m3 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v2)&0xf),
+		0,
+		(uint8(m5)<<4)|(uint8(m4)&0xf),
+		(uint8(m3)<<4)|rxb(v1, v2, 0, 0),
+		uint8(op))
+}
+
+func zVRRb(op, v1, v2, v3, m5, m4 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v2)&0xf),
+		uint8(v3)<<4,
+		uint8(m5)<<4,
+		(uint8(m4)<<4)|rxb(v1, v2, v3, 0),
+		uint8(op))
+}
+
+func zVRRc(op, v1, v2, v3, m6, m5, m4 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v2)&0xf),
+		uint8(v3)<<4,
+		(uint8(m6)<<4)|(uint8(m5)&0xf),
+		(uint8(m4)<<4)|rxb(v1, v2, v3, 0),
+		uint8(op))
+}
+
+func zVRRd(op, v1, v2, v3, m5, m6, v4 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v2)&0xf),
+		(uint8(v3)<<4)|(uint8(m5)&0xf),
+		uint8(m6)<<4,
+		(uint8(v4)<<4)|rxb(v1, v2, v3, v4),
+		uint8(op))
+}
+
+func zVRRe(op, v1, v2, v3, m6, m5, v4 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v2)&0xf),
+		(uint8(v3)<<4)|(uint8(m6)&0xf),
+		uint8(m5),
+		(uint8(v4)<<4)|rxb(v1, v2, v3, v4),
+		uint8(op))
+}
+
+func zVRRf(op, v1, r2, r3 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(r2)&0xf),
+		uint8(r3)<<4,
+		0,
+		rxb(v1, 0, 0, 0),
+		uint8(op))
+}
+
+func zVRIa(op, v1, i2, m3 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(v1)<<4,
+		uint8(i2>>8),
+		uint8(i2),
+		(uint8(m3)<<4)|rxb(v1, 0, 0, 0),
+		uint8(op))
+}
+
+func zVRIb(op, v1, i2, i3, m4 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		uint8(v1)<<4,
+		uint8(i2),
+		uint8(i3),
+		(uint8(m4)<<4)|rxb(v1, 0, 0, 0),
+		uint8(op))
+}
+
+func zVRIc(op, v1, v3, i2, m4 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v3)&0xf),
+		uint8(i2>>8),
+		uint8(i2),
+		(uint8(m4)<<4)|rxb(v1, v3, 0, 0),
+		uint8(op))
+}
+
+func zVRId(op, v1, v2, v3, i4, m5 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v2)&0xf),
+		uint8(v3)<<4,
+		uint8(i4),
+		(uint8(m5)<<4)|rxb(v1, v2, v3, 0),
+		uint8(op))
+}
+
+func zVRIe(op, v1, v2, i3, m5, m4 uint32, asm *[]byte) {
+	*asm = append(*asm,
+		uint8(op>>8),
+		(uint8(v1)<<4)|(uint8(v2)&0xf),
+		uint8(i3>>4),
+		(uint8(i3)<<4)|(uint8(m5)&0xf),
+		(uint8(m4)<<4)|rxb(v1, v2, 0, 0),
+		uint8(op))
+}
diff --git a/src/cmd/internal/obj/s390x/listz.go b/src/cmd/internal/obj/s390x/listz.go
new file mode 100644
index 0000000..152a45b
--- /dev/null
+++ b/src/cmd/internal/obj/s390x/listz.go
@@ -0,0 +1,73 @@
+// Based on cmd/internal/obj/ppc64/list9.go.
+//
+//	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 s390x
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+)
+
+func init() {
+	obj.RegisterRegister(obj.RBaseS390X, REG_R0+1024, Rconv)
+	obj.RegisterOpcode(obj.ABaseS390X, 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)
+	}
+	if REG_AR0 <= r && r <= REG_AR15 {
+		return fmt.Sprintf("AR%d", r-REG_AR0)
+	}
+	if REG_V0 <= r && r <= REG_V31 {
+		return fmt.Sprintf("V%d", r-REG_V0)
+	}
+	return fmt.Sprintf("Rgok(%d)", r-obj.RBaseS390X)
+}
+
+func DRconv(a int) string {
+	s := "C_??"
+	if a >= C_NONE && a <= C_NCLASS {
+		s = cnamesz[a]
+	}
+	var fp string
+	fp += s
+	return fp
+}
diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go
new file mode 100644
index 0000000..0526a35
--- /dev/null
+++ b/src/cmd/internal/obj/s390x/objz.go
@@ -0,0 +1,1008 @@
+// Based on cmd/internal/obj/ppc64/obj9.go.
+//
+//	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 s390x
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/sys"
+	"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 unless they are +0.
+	switch p.As {
+	case AFMOVS:
+		if p.From.Type == obj.TYPE_FCONST {
+			f32 := float32(p.From.Val.(float64))
+			i32 := math.Float32bits(f32)
+			if i32 == 0 { // +0
+				break
+			}
+			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.Sym.Local = true
+			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))
+			if i64 == 0 { // +0
+				break
+			}
+			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.Sym.Local = true
+			p.From.Name = obj.NAME_EXTERN
+			p.From.Offset = 0
+		}
+
+		// put constants not loadable by LOAD IMMEDIATE into memory
+	case AMOVD:
+		if p.From.Type == obj.TYPE_CONST {
+			val := p.From.Offset
+			if int64(int32(val)) != val &&
+				int64(uint32(val)) != val &&
+				int64(uint64(val)&(0xffffffff<<32)) != val {
+				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.Sym.Local = true
+				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 ASUB:
+		if p.From.Type == obj.TYPE_CONST {
+			p.From.Offset = -p.From.Offset
+			p.As = AADD
+		}
+	}
+
+	if ctxt.Flag_dynlink {
+		rewriteToUseGot(ctxt, p)
+	}
+}
+
+// Rewrite p, if necessary, to access global data via the global offset table.
+func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
+	// At the moment EXRL instructions are not emitted by the compiler and only reference local symbols in
+	// assembly code.
+	if p.As == AEXRL {
+		return
+	}
+
+	// We only care about global data: NAME_EXTERN means a global
+	// symbol in the Go sense, and p.Sym.Local is true for a few
+	// internally defined symbols.
+	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+		// MOVD $sym, Rx becomes MOVD sym at GOT, Rx
+		// MOVD $sym+<off>, Rx becomes MOVD sym at GOT, Rx; ADD <off>, Rx
+		if p.To.Type != obj.TYPE_REG || p.As != AMOVD {
+			ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
+		}
+		p.From.Type = obj.TYPE_MEM
+		p.From.Name = obj.NAME_GOTREF
+		q := p
+		if p.From.Offset != 0 {
+			q = obj.Appendp(ctxt, p)
+			q.As = AADD
+			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
+	// MOVD sym, Ry becomes MOVD sym at GOT, REGTMP; MOVD (REGTMP), Ry
+	// MOVD Ry, sym becomes MOVD sym at GOT, REGTMP; MOVD Ry, (REGTMP)
+	// An addition may be inserted between the two MOVs if there is an offset.
+	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.Sym.Type == obj.STLSBSS {
+		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 = AMOVD
+	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 = REGTMP
+
+	p2.As = p.As
+	p2.From = p.From
+	p2.To = p.To
+	if p.From.Name == obj.NAME_EXTERN {
+		p2.From.Reg = REGTMP
+		p2.From.Name = obj.NAME_NONE
+		p2.From.Sym = nil
+	} else if p.To.Name == obj.NAME_EXTERN {
+		p2.To.Reg = REGTMP
+		p2.To.Name = obj.NAME_NONE
+		p2.To.Sym = nil
+	} else {
+		return
+	}
+	obj.Nopout(p)
+}
+
+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
+	if textstksiz == -8 {
+		// Compatibility hack.
+		p.From3.Offset |= obj.NOFRAME
+		textstksiz = 0
+	}
+	if textstksiz%8 != 0 {
+		ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
+	}
+	if p.From3.Offset&obj.NOFRAME != 0 {
+		if textstksiz != 0 {
+			ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
+		}
+	}
+
+	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 ASYNC,
+			AWORD:
+			q = p
+			p.Mark |= LABEL | SYNC
+			continue
+
+		case AMOVW, AMOVWZ, AMOVD:
+			q = p
+			if p.From.Reg >= REG_RESERVED || p.To.Reg >= REG_RESERVED {
+				p.Mark |= LABEL | SYNC
+			}
+			continue
+
+		case AFABS,
+			AFADD,
+			AFDIV,
+			AFMADD,
+			AFMOVD,
+			AFMOVS,
+			AFMSUB,
+			AFMUL,
+			AFNABS,
+			AFNEG,
+			AFNMADD,
+			AFNMSUB,
+			ALEDBR,
+			ALDEBR,
+			AFSUB:
+			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,
+			ACMPBEQ,
+			ACMPBGE,
+			ACMPBGT,
+			ACMPBLE,
+			ACMPBLT,
+			ACMPBNE,
+			ACMPUBEQ,
+			ACMPUBGE,
+			ACMPUBGT,
+			ACMPUBLE,
+			ACMPUBLT,
+			ACMPUBNE:
+			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 p1 *obj.Prog
+	var p2 *obj.Prog
+	var pLast *obj.Prog
+	var pPre *obj.Prog
+	var pPreempt *obj.Prog
+	wasSplit := false
+	for p := cursym.Text; p != nil; p = p.Link {
+		pLast = p
+		switch p.As {
+		case obj.ATEXT:
+			autosize = int32(textstksiz)
+
+			if p.Mark&LEAF != 0 && autosize == 0 && p.From3.Offset&obj.NOFRAME == 0 {
+				// A leaf function with no locals has no frame.
+				p.From3.Offset |= obj.NOFRAME
+			}
+
+			if p.From3.Offset&obj.NOFRAME == 0 {
+				// If there is a stack frame at all, it includes
+				// space to save the LR.
+				autosize += int32(ctxt.FixedFrameSize())
+			}
+
+			p.To.Offset = int64(autosize)
+
+			q = p
+
+			if p.From3.Offset&obj.NOSPLIT == 0 {
+				p, pPreempt = stacksplitPre(ctxt, p, autosize) // emit pre part of split check
+				pPre = p
+				wasSplit = true //need post part of split
+			}
+
+			if autosize != 0 {
+				q = obj.Appendp(ctxt, p)
+				q.As = AMOVD
+				q.From.Type = obj.TYPE_ADDR
+				q.From.Offset = int64(-autosize)
+				q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REGSP
+				q.Spadj = autosize
+			} else if cursym.Text.Mark&LEAF == 0 {
+				// A very few functions that do not return to their caller
+				// (e.g. gogo) are not identified as leaves but still have
+				// no frame.
+				cursym.Text.Mark |= LEAF
+			}
+
+			if cursym.Text.Mark&LEAF != 0 {
+				cursym.Leaf = true
+				break
+			}
+
+			q = obj.Appendp(ctxt, q)
+			q.As = AMOVD
+			q.From.Type = obj.TYPE_REG
+			q.From.Reg = REG_LR
+			q.To.Type = obj.TYPE_MEM
+			q.To.Reg = REGSP
+			q.To.Offset = 0
+
+			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 s390x 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) + ctxt.FixedFrameSize()
+				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 = ctxt.FixedFrameSize()
+				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
+			}
+
+			retTarget := p.To.Sym
+
+			if cursym.Text.Mark&LEAF != 0 {
+				if autosize == 0 {
+					p.As = ABR
+					p.From = obj.Addr{}
+					if retTarget == nil {
+						p.To.Type = obj.TYPE_REG
+						p.To.Reg = REG_LR
+					} else {
+						p.To.Type = obj.TYPE_BRANCH
+						p.To.Sym = retTarget
+					}
+					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 = obj.Appendp(ctxt, p)
+				q.As = ABR
+				q.From = obj.Addr{}
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_LR
+				q.Mark |= BRANCH
+				q.Spadj = autosize
+				break
+			}
+
+			p.As = AMOVD
+			p.From.Type = obj.TYPE_MEM
+			p.From.Reg = REGSP
+			p.From.Offset = 0
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = REG_LR
+
+			q = p
+
+			if autosize != 0 {
+				q = obj.Appendp(ctxt, q)
+				q.As = AADD
+				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 = obj.Appendp(ctxt, q)
+			q.As = ABR
+			q.From = obj.Addr{}
+			if retTarget == nil {
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_LR
+			} else {
+				q.To.Type = obj.TYPE_BRANCH
+				q.To.Sym = retTarget
+			}
+			q.Mark |= BRANCH
+			q.Spadj = autosize
+
+		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)
+			}
+		}
+	}
+	if wasSplit {
+		pLast = stacksplitPost(ctxt, pLast, pPre, pPreempt) // emit post part of split check
+	}
+}
+
+/*
+// 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 stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) {
+	var q *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 {
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
+	}
+	p.To.Type = obj.TYPE_REG
+	p.To.Reg = REG_R3
+
+	q = nil
+	if framesize <= obj.StackSmall {
+		// small stack: SP < stackguard
+		//	CMP	stackguard, SP
+
+		//p.To.Type = obj.TYPE_REG
+		//p.To.Reg = REGSP
+
+		// q1: BLT	done
+
+		p = obj.Appendp(ctxt, p)
+		//q1 = p
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R3
+		p.Reg = REGSP
+		p.As = ACMPUBGE
+		p.To.Type = obj.TYPE_BRANCH
+		//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
+
+		//p = obj.Appendp(ctxt, p)
+		//p.As = ABGE
+		//p.To.Type = obj.TYPE_BRANCH
+
+	} 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.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R3
+		p.Reg = REG_R4
+		p.As = ACMPUBGE
+		p.To.Type = obj.TYPE_BRANCH
+
+	} 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)), TEMP
+		//	CMPUBGE	TEMP, 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.From.Type = obj.TYPE_REG
+		p.From.Reg = REGTMP
+		p.Reg = REG_R4
+		p.As = ACMPUBGE
+		p.To.Type = obj.TYPE_BRANCH
+	}
+
+	return p, q
+}
+
+func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog) *obj.Prog {
+
+	// MOVD	LR, R5
+	p = obj.Appendp(ctxt, p)
+	pPre.Pcond = 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 pPreempt != nil {
+		pPreempt.Pcond = p
+	}
+
+	// BL	runtime.morestack(SB)
+	p = obj.Appendp(ctxt, p)
+
+	p.As = ABL
+	p.To.Type = obj.TYPE_BRANCH
+	if ctxt.Cursym.Cfunc {
+		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
+	return p
+}
+
+var pc_cnt int64
+
+func follow(ctxt *obj.Link, s *obj.LSym) {
+	ctxt.Cursym = s
+
+	pc_cnt = 0
+	firstp := ctxt.NewProg()
+	lastp := firstp
+	xfol(ctxt, s.Text, &lastp)
+	lastp.Link = nil
+	s.Text = firstp.Link
+}
+
+func relinv(a obj.As) obj.As {
+	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 b obj.As
+
+	for p != nil {
+		a := 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
+				(*last).Pc = pc_cnt
+				pc_cnt += 1
+				p = p.Link
+				xfol(ctxt, p, last)
+				p = q
+				if p != nil && p.Mark&FOLL == 0 {
+					continue
+				}
+				return
+			}
+
+			if q != nil {
+				p.Mark |= FOLL
+				p = q
+				if p.Mark&FOLL == 0 {
+					continue
+				}
+			}
+		}
+
+		if p.Mark&FOLL != 0 {
+			q = p
+			for i := 0; i < 4; i, q = i+1, q.Link {
+				if q == *last || (q.Mark&NOSCHED != 0) {
+					break
+				}
+				b = 0 /* set */
+				a = q.As
+				if a == obj.ANOP {
+					i--
+					continue
+				}
+				if a != ABR && a != obj.ARET {
+					if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
+						continue
+					}
+					b = relinv(a)
+					if b == 0 {
+						continue
+					}
+				}
+
+				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
+						(*last).Pc = pc_cnt
+						pc_cnt += 1
+						continue
+					}
+
+					(*last).Link = r
+					*last = r
+					(*last).Pc = pc_cnt
+					pc_cnt += 1
+					if a == ABR || a == obj.ARET {
+						return
+					}
+					r.As = 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("can't happen 2\n")
+					}
+					return
+				}
+			}
+
+			a = ABR
+			q = ctxt.NewProg()
+			q.As = 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
+		(*last).Pc = pc_cnt
+		pc_cnt += 1
+
+		if a == ABR || a == obj.ARET {
+			if p.Mark&NOSCHED != 0 {
+				p = p.Link
+				continue
+			}
+
+			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
+				}
+				continue
+			}
+		}
+
+		p = p.Link
+	}
+}
+
+var unaryDst = map[obj.As]bool{
+	ASTCK:  true,
+	ASTCKC: true,
+	ASTCKE: true,
+	ASTCKF: true,
+	ANEG:   true,
+	AVONE:  true,
+	AVZERO: true,
+}
+
+var Links390x = obj.LinkArch{
+	Arch:       sys.ArchS390X,
+	Preprocess: preprocess,
+	Assemble:   spanz,
+	Follow:     follow,
+	Progedit:   progedit,
+	UnaryDst:   unaryDst,
+}
diff --git a/src/cmd/internal/obj/s390x/vector.go b/src/cmd/internal/obj/s390x/vector.go
new file mode 100644
index 0000000..d36dfb1
--- /dev/null
+++ b/src/cmd/internal/obj/s390x/vector.go
@@ -0,0 +1,1061 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s390x
+
+import (
+	"cmd/internal/obj"
+)
+
+// This file contains utility functions for use when
+// assembling vector instructions.
+
+// vop returns the opcode, element size and condition
+// setting for the given (possibly extended) mnemonic.
+func vop(as obj.As) (opcode, es, cs uint32) {
+	switch as {
+	default:
+		return 0, 0, 0
+	case AVA:
+		return op_VA, 0, 0
+	case AVAB:
+		return op_VA, 0, 0
+	case AVAH:
+		return op_VA, 1, 0
+	case AVAF:
+		return op_VA, 2, 0
+	case AVAG:
+		return op_VA, 3, 0
+	case AVAQ:
+		return op_VA, 4, 0
+	case AVACC:
+		return op_VACC, 0, 0
+	case AVACCB:
+		return op_VACC, 0, 0
+	case AVACCH:
+		return op_VACC, 1, 0
+	case AVACCF:
+		return op_VACC, 2, 0
+	case AVACCG:
+		return op_VACC, 3, 0
+	case AVACCQ:
+		return op_VACC, 4, 0
+	case AVAC:
+		return op_VAC, 0, 0
+	case AVACQ:
+		return op_VAC, 4, 0
+	case AVACCC:
+		return op_VACCC, 0, 0
+	case AVACCCQ:
+		return op_VACCC, 4, 0
+	case AVN:
+		return op_VN, 0, 0
+	case AVNC:
+		return op_VNC, 0, 0
+	case AVAVG:
+		return op_VAVG, 0, 0
+	case AVAVGB:
+		return op_VAVG, 0, 0
+	case AVAVGH:
+		return op_VAVG, 1, 0
+	case AVAVGF:
+		return op_VAVG, 2, 0
+	case AVAVGG:
+		return op_VAVG, 3, 0
+	case AVAVGL:
+		return op_VAVGL, 0, 0
+	case AVAVGLB:
+		return op_VAVGL, 0, 0
+	case AVAVGLH:
+		return op_VAVGL, 1, 0
+	case AVAVGLF:
+		return op_VAVGL, 2, 0
+	case AVAVGLG:
+		return op_VAVGL, 3, 0
+	case AVCKSM:
+		return op_VCKSM, 0, 0
+	case AVCEQ:
+		return op_VCEQ, 0, 0
+	case AVCEQB:
+		return op_VCEQ, 0, 0
+	case AVCEQH:
+		return op_VCEQ, 1, 0
+	case AVCEQF:
+		return op_VCEQ, 2, 0
+	case AVCEQG:
+		return op_VCEQ, 3, 0
+	case AVCEQBS:
+		return op_VCEQ, 0, 1
+	case AVCEQHS:
+		return op_VCEQ, 1, 1
+	case AVCEQFS:
+		return op_VCEQ, 2, 1
+	case AVCEQGS:
+		return op_VCEQ, 3, 1
+	case AVCH:
+		return op_VCH, 0, 0
+	case AVCHB:
+		return op_VCH, 0, 0
+	case AVCHH:
+		return op_VCH, 1, 0
+	case AVCHF:
+		return op_VCH, 2, 0
+	case AVCHG:
+		return op_VCH, 3, 0
+	case AVCHBS:
+		return op_VCH, 0, 1
+	case AVCHHS:
+		return op_VCH, 1, 1
+	case AVCHFS:
+		return op_VCH, 2, 1
+	case AVCHGS:
+		return op_VCH, 3, 1
+	case AVCHL:
+		return op_VCHL, 0, 0
+	case AVCHLB:
+		return op_VCHL, 0, 0
+	case AVCHLH:
+		return op_VCHL, 1, 0
+	case AVCHLF:
+		return op_VCHL, 2, 0
+	case AVCHLG:
+		return op_VCHL, 3, 0
+	case AVCHLBS:
+		return op_VCHL, 0, 1
+	case AVCHLHS:
+		return op_VCHL, 1, 1
+	case AVCHLFS:
+		return op_VCHL, 2, 1
+	case AVCHLGS:
+		return op_VCHL, 3, 1
+	case AVCLZ:
+		return op_VCLZ, 0, 0
+	case AVCLZB:
+		return op_VCLZ, 0, 0
+	case AVCLZH:
+		return op_VCLZ, 1, 0
+	case AVCLZF:
+		return op_VCLZ, 2, 0
+	case AVCLZG:
+		return op_VCLZ, 3, 0
+	case AVCTZ:
+		return op_VCTZ, 0, 0
+	case AVCTZB:
+		return op_VCTZ, 0, 0
+	case AVCTZH:
+		return op_VCTZ, 1, 0
+	case AVCTZF:
+		return op_VCTZ, 2, 0
+	case AVCTZG:
+		return op_VCTZ, 3, 0
+	case AVEC:
+		return op_VEC, 0, 0
+	case AVECB:
+		return op_VEC, 0, 0
+	case AVECH:
+		return op_VEC, 1, 0
+	case AVECF:
+		return op_VEC, 2, 0
+	case AVECG:
+		return op_VEC, 3, 0
+	case AVECL:
+		return op_VECL, 0, 0
+	case AVECLB:
+		return op_VECL, 0, 0
+	case AVECLH:
+		return op_VECL, 1, 0
+	case AVECLF:
+		return op_VECL, 2, 0
+	case AVECLG:
+		return op_VECL, 3, 0
+	case AVERIM:
+		return op_VERIM, 0, 0
+	case AVERIMB:
+		return op_VERIM, 0, 0
+	case AVERIMH:
+		return op_VERIM, 1, 0
+	case AVERIMF:
+		return op_VERIM, 2, 0
+	case AVERIMG:
+		return op_VERIM, 3, 0
+	case AVERLL:
+		return op_VERLL, 0, 0
+	case AVERLLB:
+		return op_VERLL, 0, 0
+	case AVERLLH:
+		return op_VERLL, 1, 0
+	case AVERLLF:
+		return op_VERLL, 2, 0
+	case AVERLLG:
+		return op_VERLL, 3, 0
+	case AVERLLV:
+		return op_VERLLV, 0, 0
+	case AVERLLVB:
+		return op_VERLLV, 0, 0
+	case AVERLLVH:
+		return op_VERLLV, 1, 0
+	case AVERLLVF:
+		return op_VERLLV, 2, 0
+	case AVERLLVG:
+		return op_VERLLV, 3, 0
+	case AVESLV:
+		return op_VESLV, 0, 0
+	case AVESLVB:
+		return op_VESLV, 0, 0
+	case AVESLVH:
+		return op_VESLV, 1, 0
+	case AVESLVF:
+		return op_VESLV, 2, 0
+	case AVESLVG:
+		return op_VESLV, 3, 0
+	case AVESL:
+		return op_VESL, 0, 0
+	case AVESLB:
+		return op_VESL, 0, 0
+	case AVESLH:
+		return op_VESL, 1, 0
+	case AVESLF:
+		return op_VESL, 2, 0
+	case AVESLG:
+		return op_VESL, 3, 0
+	case AVESRA:
+		return op_VESRA, 0, 0
+	case AVESRAB:
+		return op_VESRA, 0, 0
+	case AVESRAH:
+		return op_VESRA, 1, 0
+	case AVESRAF:
+		return op_VESRA, 2, 0
+	case AVESRAG:
+		return op_VESRA, 3, 0
+	case AVESRAV:
+		return op_VESRAV, 0, 0
+	case AVESRAVB:
+		return op_VESRAV, 0, 0
+	case AVESRAVH:
+		return op_VESRAV, 1, 0
+	case AVESRAVF:
+		return op_VESRAV, 2, 0
+	case AVESRAVG:
+		return op_VESRAV, 3, 0
+	case AVESRL:
+		return op_VESRL, 0, 0
+	case AVESRLB:
+		return op_VESRL, 0, 0
+	case AVESRLH:
+		return op_VESRL, 1, 0
+	case AVESRLF:
+		return op_VESRL, 2, 0
+	case AVESRLG:
+		return op_VESRL, 3, 0
+	case AVESRLV:
+		return op_VESRLV, 0, 0
+	case AVESRLVB:
+		return op_VESRLV, 0, 0
+	case AVESRLVH:
+		return op_VESRLV, 1, 0
+	case AVESRLVF:
+		return op_VESRLV, 2, 0
+	case AVESRLVG:
+		return op_VESRLV, 3, 0
+	case AVX:
+		return op_VX, 0, 0
+	case AVFAE:
+		return op_VFAE, 0, 0
+	case AVFAEB:
+		return op_VFAE, 0, 0
+	case AVFAEH:
+		return op_VFAE, 1, 0
+	case AVFAEF:
+		return op_VFAE, 2, 0
+	case AVFAEBS:
+		return op_VFAE, 0, 1
+	case AVFAEHS:
+		return op_VFAE, 1, 1
+	case AVFAEFS:
+		return op_VFAE, 2, 1
+	case AVFAEZB:
+		return op_VFAE, 0, 2
+	case AVFAEZH:
+		return op_VFAE, 1, 2
+	case AVFAEZF:
+		return op_VFAE, 2, 2
+	case AVFAEZBS:
+		return op_VFAE, 0, 3
+	case AVFAEZHS:
+		return op_VFAE, 1, 3
+	case AVFAEZFS:
+		return op_VFAE, 2, 3
+	case AVFEE:
+		return op_VFEE, 0, 0
+	case AVFEEB:
+		return op_VFEE, 0, 0
+	case AVFEEH:
+		return op_VFEE, 1, 0
+	case AVFEEF:
+		return op_VFEE, 2, 0
+	case AVFEEBS:
+		return op_VFEE, 0, 1
+	case AVFEEHS:
+		return op_VFEE, 1, 1
+	case AVFEEFS:
+		return op_VFEE, 2, 1
+	case AVFEEZB:
+		return op_VFEE, 0, 2
+	case AVFEEZH:
+		return op_VFEE, 1, 2
+	case AVFEEZF:
+		return op_VFEE, 2, 2
+	case AVFEEZBS:
+		return op_VFEE, 0, 3
+	case AVFEEZHS:
+		return op_VFEE, 1, 3
+	case AVFEEZFS:
+		return op_VFEE, 2, 3
+	case AVFENE:
+		return op_VFENE, 0, 0
+	case AVFENEB:
+		return op_VFENE, 0, 0
+	case AVFENEH:
+		return op_VFENE, 1, 0
+	case AVFENEF:
+		return op_VFENE, 2, 0
+	case AVFENEBS:
+		return op_VFENE, 0, 1
+	case AVFENEHS:
+		return op_VFENE, 1, 1
+	case AVFENEFS:
+		return op_VFENE, 2, 1
+	case AVFENEZB:
+		return op_VFENE, 0, 2
+	case AVFENEZH:
+		return op_VFENE, 1, 2
+	case AVFENEZF:
+		return op_VFENE, 2, 2
+	case AVFENEZBS:
+		return op_VFENE, 0, 3
+	case AVFENEZHS:
+		return op_VFENE, 1, 3
+	case AVFENEZFS:
+		return op_VFENE, 2, 3
+	case AVFA:
+		return op_VFA, 0, 0
+	case AVFADB:
+		return op_VFA, 3, 0
+	case AWFADB:
+		return op_VFA, 3, 0
+	case AWFK:
+		return op_WFK, 0, 0
+	case AWFKDB:
+		return op_WFK, 3, 0
+	case AVFCE:
+		return op_VFCE, 0, 0
+	case AVFCEDB:
+		return op_VFCE, 3, 0
+	case AVFCEDBS:
+		return op_VFCE, 3, 1
+	case AWFCEDB:
+		return op_VFCE, 3, 0
+	case AWFCEDBS:
+		return op_VFCE, 3, 1
+	case AVFCH:
+		return op_VFCH, 0, 0
+	case AVFCHDB:
+		return op_VFCH, 3, 0
+	case AVFCHDBS:
+		return op_VFCH, 3, 1
+	case AWFCHDB:
+		return op_VFCH, 3, 0
+	case AWFCHDBS:
+		return op_VFCH, 3, 1
+	case AVFCHE:
+		return op_VFCHE, 0, 0
+	case AVFCHEDB:
+		return op_VFCHE, 3, 0
+	case AVFCHEDBS:
+		return op_VFCHE, 3, 1
+	case AWFCHEDB:
+		return op_VFCHE, 3, 0
+	case AWFCHEDBS:
+		return op_VFCHE, 3, 1
+	case AWFC:
+		return op_WFC, 0, 0
+	case AWFCDB:
+		return op_WFC, 3, 0
+	case AVCDG:
+		return op_VCDG, 0, 0
+	case AVCDGB:
+		return op_VCDG, 3, 0
+	case AWCDGB:
+		return op_VCDG, 3, 0
+	case AVCDLG:
+		return op_VCDLG, 0, 0
+	case AVCDLGB:
+		return op_VCDLG, 3, 0
+	case AWCDLGB:
+		return op_VCDLG, 3, 0
+	case AVCGD:
+		return op_VCGD, 0, 0
+	case AVCGDB:
+		return op_VCGD, 3, 0
+	case AWCGDB:
+		return op_VCGD, 3, 0
+	case AVCLGD:
+		return op_VCLGD, 0, 0
+	case AVCLGDB:
+		return op_VCLGD, 3, 0
+	case AWCLGDB:
+		return op_VCLGD, 3, 0
+	case AVFD:
+		return op_VFD, 0, 0
+	case AVFDDB:
+		return op_VFD, 3, 0
+	case AWFDDB:
+		return op_VFD, 3, 0
+	case AVLDE:
+		return op_VLDE, 0, 0
+	case AVLDEB:
+		return op_VLDE, 2, 0
+	case AWLDEB:
+		return op_VLDE, 2, 0
+	case AVLED:
+		return op_VLED, 0, 0
+	case AVLEDB:
+		return op_VLED, 3, 0
+	case AWLEDB:
+		return op_VLED, 3, 0
+	case AVFM:
+		return op_VFM, 0, 0
+	case AVFMDB:
+		return op_VFM, 3, 0
+	case AWFMDB:
+		return op_VFM, 3, 0
+	case AVFMA:
+		return op_VFMA, 0, 0
+	case AVFMADB:
+		return op_VFMA, 3, 0
+	case AWFMADB:
+		return op_VFMA, 3, 0
+	case AVFMS:
+		return op_VFMS, 0, 0
+	case AVFMSDB:
+		return op_VFMS, 3, 0
+	case AWFMSDB:
+		return op_VFMS, 3, 0
+	case AVFPSO:
+		return op_VFPSO, 0, 0
+	case AVFPSODB:
+		return op_VFPSO, 3, 0
+	case AWFPSODB:
+		return op_VFPSO, 3, 0
+	case AVFLCDB:
+		return op_VFPSO, 3, 0
+	case AWFLCDB:
+		return op_VFPSO, 3, 0
+	case AVFLNDB:
+		return op_VFPSO, 3, 1
+	case AWFLNDB:
+		return op_VFPSO, 3, 1
+	case AVFLPDB:
+		return op_VFPSO, 3, 2
+	case AWFLPDB:
+		return op_VFPSO, 3, 2
+	case AVFSQ:
+		return op_VFSQ, 0, 0
+	case AVFSQDB:
+		return op_VFSQ, 3, 0
+	case AWFSQDB:
+		return op_VFSQ, 3, 0
+	case AVFS:
+		return op_VFS, 0, 0
+	case AVFSDB:
+		return op_VFS, 3, 0
+	case AWFSDB:
+		return op_VFS, 3, 0
+	case AVFTCI:
+		return op_VFTCI, 0, 0
+	case AVFTCIDB:
+		return op_VFTCI, 3, 0
+	case AWFTCIDB:
+		return op_VFTCI, 3, 0
+	case AVGFM:
+		return op_VGFM, 0, 0
+	case AVGFMB:
+		return op_VGFM, 0, 0
+	case AVGFMH:
+		return op_VGFM, 1, 0
+	case AVGFMF:
+		return op_VGFM, 2, 0
+	case AVGFMG:
+		return op_VGFM, 3, 0
+	case AVGFMA:
+		return op_VGFMA, 0, 0
+	case AVGFMAB:
+		return op_VGFMA, 0, 0
+	case AVGFMAH:
+		return op_VGFMA, 1, 0
+	case AVGFMAF:
+		return op_VGFMA, 2, 0
+	case AVGFMAG:
+		return op_VGFMA, 3, 0
+	case AVGEF:
+		return op_VGEF, 0, 0
+	case AVGEG:
+		return op_VGEG, 0, 0
+	case AVGBM:
+		return op_VGBM, 0, 0
+	case AVZERO:
+		return op_VGBM, 0, 0
+	case AVONE:
+		return op_VGBM, 0, 0
+	case AVGM:
+		return op_VGM, 0, 0
+	case AVGMB:
+		return op_VGM, 0, 0
+	case AVGMH:
+		return op_VGM, 1, 0
+	case AVGMF:
+		return op_VGM, 2, 0
+	case AVGMG:
+		return op_VGM, 3, 0
+	case AVISTR:
+		return op_VISTR, 0, 0
+	case AVISTRB:
+		return op_VISTR, 0, 0
+	case AVISTRH:
+		return op_VISTR, 1, 0
+	case AVISTRF:
+		return op_VISTR, 2, 0
+	case AVISTRBS:
+		return op_VISTR, 0, 1
+	case AVISTRHS:
+		return op_VISTR, 1, 1
+	case AVISTRFS:
+		return op_VISTR, 2, 1
+	case AVL:
+		return op_VL, 0, 0
+	case AVLR:
+		return op_VLR, 0, 0
+	case AVLREP:
+		return op_VLREP, 0, 0
+	case AVLREPB:
+		return op_VLREP, 0, 0
+	case AVLREPH:
+		return op_VLREP, 1, 0
+	case AVLREPF:
+		return op_VLREP, 2, 0
+	case AVLREPG:
+		return op_VLREP, 3, 0
+	case AVLC:
+		return op_VLC, 0, 0
+	case AVLCB:
+		return op_VLC, 0, 0
+	case AVLCH:
+		return op_VLC, 1, 0
+	case AVLCF:
+		return op_VLC, 2, 0
+	case AVLCG:
+		return op_VLC, 3, 0
+	case AVLEH:
+		return op_VLEH, 0, 0
+	case AVLEF:
+		return op_VLEF, 0, 0
+	case AVLEG:
+		return op_VLEG, 0, 0
+	case AVLEB:
+		return op_VLEB, 0, 0
+	case AVLEIH:
+		return op_VLEIH, 0, 0
+	case AVLEIF:
+		return op_VLEIF, 0, 0
+	case AVLEIG:
+		return op_VLEIG, 0, 0
+	case AVLEIB:
+		return op_VLEIB, 0, 0
+	case AVFI:
+		return op_VFI, 0, 0
+	case AVFIDB:
+		return op_VFI, 3, 0
+	case AWFIDB:
+		return op_VFI, 3, 0
+	case AVLGV:
+		return op_VLGV, 0, 0
+	case AVLGVB:
+		return op_VLGV, 0, 0
+	case AVLGVH:
+		return op_VLGV, 1, 0
+	case AVLGVF:
+		return op_VLGV, 2, 0
+	case AVLGVG:
+		return op_VLGV, 3, 0
+	case AVLLEZ:
+		return op_VLLEZ, 0, 0
+	case AVLLEZB:
+		return op_VLLEZ, 0, 0
+	case AVLLEZH:
+		return op_VLLEZ, 1, 0
+	case AVLLEZF:
+		return op_VLLEZ, 2, 0
+	case AVLLEZG:
+		return op_VLLEZ, 3, 0
+	case AVLM:
+		return op_VLM, 0, 0
+	case AVLP:
+		return op_VLP, 0, 0
+	case AVLPB:
+		return op_VLP, 0, 0
+	case AVLPH:
+		return op_VLP, 1, 0
+	case AVLPF:
+		return op_VLP, 2, 0
+	case AVLPG:
+		return op_VLP, 3, 0
+	case AVLBB:
+		return op_VLBB, 0, 0
+	case AVLVG:
+		return op_VLVG, 0, 0
+	case AVLVGB:
+		return op_VLVG, 0, 0
+	case AVLVGH:
+		return op_VLVG, 1, 0
+	case AVLVGF:
+		return op_VLVG, 2, 0
+	case AVLVGG:
+		return op_VLVG, 3, 0
+	case AVLVGP:
+		return op_VLVGP, 0, 0
+	case AVLL:
+		return op_VLL, 0, 0
+	case AVMX:
+		return op_VMX, 0, 0
+	case AVMXB:
+		return op_VMX, 0, 0
+	case AVMXH:
+		return op_VMX, 1, 0
+	case AVMXF:
+		return op_VMX, 2, 0
+	case AVMXG:
+		return op_VMX, 3, 0
+	case AVMXL:
+		return op_VMXL, 0, 0
+	case AVMXLB:
+		return op_VMXL, 0, 0
+	case AVMXLH:
+		return op_VMXL, 1, 0
+	case AVMXLF:
+		return op_VMXL, 2, 0
+	case AVMXLG:
+		return op_VMXL, 3, 0
+	case AVMRH:
+		return op_VMRH, 0, 0
+	case AVMRHB:
+		return op_VMRH, 0, 0
+	case AVMRHH:
+		return op_VMRH, 1, 0
+	case AVMRHF:
+		return op_VMRH, 2, 0
+	case AVMRHG:
+		return op_VMRH, 3, 0
+	case AVMRL:
+		return op_VMRL, 0, 0
+	case AVMRLB:
+		return op_VMRL, 0, 0
+	case AVMRLH:
+		return op_VMRL, 1, 0
+	case AVMRLF:
+		return op_VMRL, 2, 0
+	case AVMRLG:
+		return op_VMRL, 3, 0
+	case AVMN:
+		return op_VMN, 0, 0
+	case AVMNB:
+		return op_VMN, 0, 0
+	case AVMNH:
+		return op_VMN, 1, 0
+	case AVMNF:
+		return op_VMN, 2, 0
+	case AVMNG:
+		return op_VMN, 3, 0
+	case AVMNL:
+		return op_VMNL, 0, 0
+	case AVMNLB:
+		return op_VMNL, 0, 0
+	case AVMNLH:
+		return op_VMNL, 1, 0
+	case AVMNLF:
+		return op_VMNL, 2, 0
+	case AVMNLG:
+		return op_VMNL, 3, 0
+	case AVMAE:
+		return op_VMAE, 0, 0
+	case AVMAEB:
+		return op_VMAE, 0, 0
+	case AVMAEH:
+		return op_VMAE, 1, 0
+	case AVMAEF:
+		return op_VMAE, 2, 0
+	case AVMAH:
+		return op_VMAH, 0, 0
+	case AVMAHB:
+		return op_VMAH, 0, 0
+	case AVMAHH:
+		return op_VMAH, 1, 0
+	case AVMAHF:
+		return op_VMAH, 2, 0
+	case AVMALE:
+		return op_VMALE, 0, 0
+	case AVMALEB:
+		return op_VMALE, 0, 0
+	case AVMALEH:
+		return op_VMALE, 1, 0
+	case AVMALEF:
+		return op_VMALE, 2, 0
+	case AVMALH:
+		return op_VMALH, 0, 0
+	case AVMALHB:
+		return op_VMALH, 0, 0
+	case AVMALHH:
+		return op_VMALH, 1, 0
+	case AVMALHF:
+		return op_VMALH, 2, 0
+	case AVMALO:
+		return op_VMALO, 0, 0
+	case AVMALOB:
+		return op_VMALO, 0, 0
+	case AVMALOH:
+		return op_VMALO, 1, 0
+	case AVMALOF:
+		return op_VMALO, 2, 0
+	case AVMAL:
+		return op_VMAL, 0, 0
+	case AVMALB:
+		return op_VMAL, 0, 0
+	case AVMALHW:
+		return op_VMAL, 1, 0
+	case AVMALF:
+		return op_VMAL, 2, 0
+	case AVMAO:
+		return op_VMAO, 0, 0
+	case AVMAOB:
+		return op_VMAO, 0, 0
+	case AVMAOH:
+		return op_VMAO, 1, 0
+	case AVMAOF:
+		return op_VMAO, 2, 0
+	case AVME:
+		return op_VME, 0, 0
+	case AVMEB:
+		return op_VME, 0, 0
+	case AVMEH:
+		return op_VME, 1, 0
+	case AVMEF:
+		return op_VME, 2, 0
+	case AVMH:
+		return op_VMH, 0, 0
+	case AVMHB:
+		return op_VMH, 0, 0
+	case AVMHH:
+		return op_VMH, 1, 0
+	case AVMHF:
+		return op_VMH, 2, 0
+	case AVMLE:
+		return op_VMLE, 0, 0
+	case AVMLEB:
+		return op_VMLE, 0, 0
+	case AVMLEH:
+		return op_VMLE, 1, 0
+	case AVMLEF:
+		return op_VMLE, 2, 0
+	case AVMLH:
+		return op_VMLH, 0, 0
+	case AVMLHB:
+		return op_VMLH, 0, 0
+	case AVMLHH:
+		return op_VMLH, 1, 0
+	case AVMLHF:
+		return op_VMLH, 2, 0
+	case AVMLO:
+		return op_VMLO, 0, 0
+	case AVMLOB:
+		return op_VMLO, 0, 0
+	case AVMLOH:
+		return op_VMLO, 1, 0
+	case AVMLOF:
+		return op_VMLO, 2, 0
+	case AVML:
+		return op_VML, 0, 0
+	case AVMLB:
+		return op_VML, 0, 0
+	case AVMLHW:
+		return op_VML, 1, 0
+	case AVMLF:
+		return op_VML, 2, 0
+	case AVMO:
+		return op_VMO, 0, 0
+	case AVMOB:
+		return op_VMO, 0, 0
+	case AVMOH:
+		return op_VMO, 1, 0
+	case AVMOF:
+		return op_VMO, 2, 0
+	case AVNO:
+		return op_VNO, 0, 0
+	case AVNOT:
+		return op_VNO, 0, 0
+	case AVO:
+		return op_VO, 0, 0
+	case AVPK:
+		return op_VPK, 0, 0
+	case AVPKH:
+		return op_VPK, 1, 0
+	case AVPKF:
+		return op_VPK, 2, 0
+	case AVPKG:
+		return op_VPK, 3, 0
+	case AVPKLS:
+		return op_VPKLS, 0, 0
+	case AVPKLSH:
+		return op_VPKLS, 1, 0
+	case AVPKLSF:
+		return op_VPKLS, 2, 0
+	case AVPKLSG:
+		return op_VPKLS, 3, 0
+	case AVPKLSHS:
+		return op_VPKLS, 1, 1
+	case AVPKLSFS:
+		return op_VPKLS, 2, 1
+	case AVPKLSGS:
+		return op_VPKLS, 3, 1
+	case AVPKS:
+		return op_VPKS, 0, 0
+	case AVPKSH:
+		return op_VPKS, 1, 0
+	case AVPKSF:
+		return op_VPKS, 2, 0
+	case AVPKSG:
+		return op_VPKS, 3, 0
+	case AVPKSHS:
+		return op_VPKS, 1, 1
+	case AVPKSFS:
+		return op_VPKS, 2, 1
+	case AVPKSGS:
+		return op_VPKS, 3, 1
+	case AVPERM:
+		return op_VPERM, 0, 0
+	case AVPDI:
+		return op_VPDI, 0, 0
+	case AVPOPCT:
+		return op_VPOPCT, 0, 0
+	case AVREP:
+		return op_VREP, 0, 0
+	case AVREPB:
+		return op_VREP, 0, 0
+	case AVREPH:
+		return op_VREP, 1, 0
+	case AVREPF:
+		return op_VREP, 2, 0
+	case AVREPG:
+		return op_VREP, 3, 0
+	case AVREPI:
+		return op_VREPI, 0, 0
+	case AVREPIB:
+		return op_VREPI, 0, 0
+	case AVREPIH:
+		return op_VREPI, 1, 0
+	case AVREPIF:
+		return op_VREPI, 2, 0
+	case AVREPIG:
+		return op_VREPI, 3, 0
+	case AVSCEF:
+		return op_VSCEF, 0, 0
+	case AVSCEG:
+		return op_VSCEG, 0, 0
+	case AVSEL:
+		return op_VSEL, 0, 0
+	case AVSL:
+		return op_VSL, 0, 0
+	case AVSLB:
+		return op_VSLB, 0, 0
+	case AVSLDB:
+		return op_VSLDB, 0, 0
+	case AVSRA:
+		return op_VSRA, 0, 0
+	case AVSRAB:
+		return op_VSRAB, 0, 0
+	case AVSRL:
+		return op_VSRL, 0, 0
+	case AVSRLB:
+		return op_VSRLB, 0, 0
+	case AVSEG:
+		return op_VSEG, 0, 0
+	case AVSEGB:
+		return op_VSEG, 0, 0
+	case AVSEGH:
+		return op_VSEG, 1, 0
+	case AVSEGF:
+		return op_VSEG, 2, 0
+	case AVST:
+		return op_VST, 0, 0
+	case AVSTEH:
+		return op_VSTEH, 0, 0
+	case AVSTEF:
+		return op_VSTEF, 0, 0
+	case AVSTEG:
+		return op_VSTEG, 0, 0
+	case AVSTEB:
+		return op_VSTEB, 0, 0
+	case AVSTM:
+		return op_VSTM, 0, 0
+	case AVSTL:
+		return op_VSTL, 0, 0
+	case AVSTRC:
+		return op_VSTRC, 0, 0
+	case AVSTRCB:
+		return op_VSTRC, 0, 0
+	case AVSTRCH:
+		return op_VSTRC, 1, 0
+	case AVSTRCF:
+		return op_VSTRC, 2, 0
+	case AVSTRCBS:
+		return op_VSTRC, 0, 1
+	case AVSTRCHS:
+		return op_VSTRC, 1, 1
+	case AVSTRCFS:
+		return op_VSTRC, 2, 1
+	case AVSTRCZB:
+		return op_VSTRC, 0, 2
+	case AVSTRCZH:
+		return op_VSTRC, 1, 2
+	case AVSTRCZF:
+		return op_VSTRC, 2, 2
+	case AVSTRCZBS:
+		return op_VSTRC, 0, 3
+	case AVSTRCZHS:
+		return op_VSTRC, 1, 3
+	case AVSTRCZFS:
+		return op_VSTRC, 2, 3
+	case AVS:
+		return op_VS, 0, 0
+	case AVSB:
+		return op_VS, 0, 0
+	case AVSH:
+		return op_VS, 1, 0
+	case AVSF:
+		return op_VS, 2, 0
+	case AVSG:
+		return op_VS, 3, 0
+	case AVSQ:
+		return op_VS, 4, 0
+	case AVSCBI:
+		return op_VSCBI, 0, 0
+	case AVSCBIB:
+		return op_VSCBI, 0, 0
+	case AVSCBIH:
+		return op_VSCBI, 1, 0
+	case AVSCBIF:
+		return op_VSCBI, 2, 0
+	case AVSCBIG:
+		return op_VSCBI, 3, 0
+	case AVSCBIQ:
+		return op_VSCBI, 4, 0
+	case AVSBCBI:
+		return op_VSBCBI, 0, 0
+	case AVSBCBIQ:
+		return op_VSBCBI, 4, 0
+	case AVSBI:
+		return op_VSBI, 0, 0
+	case AVSBIQ:
+		return op_VSBI, 4, 0
+	case AVSUMG:
+		return op_VSUMG, 0, 0
+	case AVSUMGH:
+		return op_VSUMG, 1, 0
+	case AVSUMGF:
+		return op_VSUMG, 2, 0
+	case AVSUMQ:
+		return op_VSUMQ, 0, 0
+	case AVSUMQF:
+		return op_VSUMQ, 1, 0
+	case AVSUMQG:
+		return op_VSUMQ, 2, 0
+	case AVSUM:
+		return op_VSUM, 0, 0
+	case AVSUMB:
+		return op_VSUM, 0, 0
+	case AVSUMH:
+		return op_VSUM, 1, 0
+	case AVTM:
+		return op_VTM, 0, 0
+	case AVUPH:
+		return op_VUPH, 0, 0
+	case AVUPHB:
+		return op_VUPH, 0, 0
+	case AVUPHH:
+		return op_VUPH, 1, 0
+	case AVUPHF:
+		return op_VUPH, 2, 0
+	case AVUPLH:
+		return op_VUPLH, 0, 0
+	case AVUPLHB:
+		return op_VUPLH, 0, 0
+	case AVUPLHH:
+		return op_VUPLH, 1, 0
+	case AVUPLHF:
+		return op_VUPLH, 2, 0
+	case AVUPLL:
+		return op_VUPLL, 0, 0
+	case AVUPLLB:
+		return op_VUPLL, 0, 0
+	case AVUPLLH:
+		return op_VUPLL, 1, 0
+	case AVUPLLF:
+		return op_VUPLL, 2, 0
+	case AVUPL:
+		return op_VUPL, 0, 0
+	case AVUPLB:
+		return op_VUPL, 0, 0
+	case AVUPLHW:
+		return op_VUPL, 1, 0
+	case AVUPLF:
+		return op_VUPL, 2, 0
+	}
+}
+
+// singleElementMask returns the single element mask bits required for the
+// given instruction.
+func singleElementMask(as obj.As) uint32 {
+	switch as {
+	case AWFADB,
+		AWFK,
+		AWFKDB,
+		AWFCEDB,
+		AWFCEDBS,
+		AWFCHDB,
+		AWFCHDBS,
+		AWFCHEDB,
+		AWFCHEDBS,
+		AWFC,
+		AWFCDB,
+		AWCDGB,
+		AWCDLGB,
+		AWCGDB,
+		AWCLGDB,
+		AWFDDB,
+		AWLDEB,
+		AWLEDB,
+		AWFMDB,
+		AWFMADB,
+		AWFMSDB,
+		AWFPSODB,
+		AWFLCDB,
+		AWFLNDB,
+		AWFLPDB,
+		AWFSQDB,
+		AWFSDB,
+		AWFTCIDB,
+		AWFIDB:
+		return 8
+	}
+	return 0
+}
diff --git a/src/cmd/internal/obj/sizeof_test.go b/src/cmd/internal/obj/sizeof_test.go
new file mode 100644
index 0000000..f7173d3
--- /dev/null
+++ b/src/cmd/internal/obj/sizeof_test.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go 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
+
+package obj
+
+import (
+	"reflect"
+	"testing"
+	"unsafe"
+)
+
+// Assert that the size of important structures do not change unexpectedly.
+
+func TestSizeof(t *testing.T) {
+	const _64bit = unsafe.Sizeof(uintptr(0)) == 8
+
+	var tests = []struct {
+		val    interface{} // type as a value
+		_32bit uintptr     // size on 32bit platforms
+		_64bit uintptr     // size on 64bit platforms
+	}{
+		{Addr{}, 52, 80},
+		{LSym{}, 80, 136},
+		{Prog{}, 196, 288},
+	}
+
+	for _, tt := range tests {
+		want := tt._32bit
+		if _64bit {
+			want = tt._64bit
+		}
+		got := reflect.TypeOf(tt.val).Size()
+		if want != got {
+			t.Errorf("unsafe.Sizeof(%T) = %d, want %d", tt.val, got, want)
+		}
+	}
+}
diff --git a/src/cmd/internal/obj/stack.go b/src/cmd/internal/obj/stack.go
index 80f6c6c..712a10f 100644
--- a/src/cmd/internal/obj/stack.go
+++ b/src/cmd/internal/obj/stack.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index dd5297e..e974ca8 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -9,7 +9,7 @@
 //	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.
+//	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
@@ -32,10 +32,10 @@
 package obj
 
 import (
+	"cmd/internal/sys"
 	"log"
 	"os"
 	"path/filepath"
-	"runtime"
 	"strconv"
 )
 
@@ -45,7 +45,6 @@ var headers = []struct {
 }{
 	{"darwin", Hdarwin},
 	{"dragonfly", Hdragonfly},
-	{"elf", Helf},
 	{"freebsd", Hfreebsd},
 	{"linux", Hlinux},
 	{"android", Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
@@ -83,10 +82,6 @@ func Linknew(arch *LinkArch) *Link {
 	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()
@@ -106,40 +101,31 @@ func Linknew(arch *LinkArch) *Link {
 	}
 
 	// On arm, record goarm.
-	if ctxt.Arch.Thechar == '5' {
+	if ctxt.Arch.Family == sys.ARM {
 		ctxt.Goarm = Getgoarm()
 	}
 
+	ctxt.Flag_optimize = true
+	ctxt.Framepointer_enabled = Framepointer_enabled(Getgoos(), arch.Name)
 	return ctxt
 }
 
-func _lookup(ctxt *Link, symb string, v int, create bool) *LSym {
-	s := ctxt.Hash[SymVer{symb, v}]
-	if s != nil || !create {
+func Linklookup(ctxt *Link, name string, v int) *LSym {
+	s := ctxt.Hash[SymVer{name, v}]
+	if s != nil {
 		return s
 	}
 
 	s = &LSym{
-		Name:    symb,
+		Name:    name,
 		Type:    0,
 		Version: int16(v),
-		Value:   0,
 		Size:    0,
 	}
-	ctxt.Hash[SymVer{symb, v}] = s
-
+	ctxt.Hash[SymVer{name, 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>"
diff --git a/src/cmd/internal/obj/textflag.go b/src/cmd/internal/obj/textflag.go
index 3d3b3b8..d8a52da 100644
--- a/src/cmd/internal/obj/textflag.go
+++ b/src/cmd/internal/obj/textflag.go
@@ -1,9 +1,9 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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
+// and data objects. The compilers, assemblers, and linker must
 // all agree on these values.
 
 package obj
@@ -14,7 +14,7 @@ const (
 	// Deprecated: Not implemented, do not use.
 	NOPROF = 1
 
-	// It is ok for the linker to get multiple of these symbols.  It will
+	// It is ok for the linker to get multiple of these symbols. It will
 	// pick one of the duplicates to use.
 	DUPOK = 2
 
@@ -44,4 +44,7 @@ const (
 	// Only valid on functions that declare a frame size of 0.
 	// TODO(mwhudson): only implemented for ppc64x at present.
 	NOFRAME = 512
+
+	// Function can call reflect.Type.Method or reflect.Type.MethodByName.
+	REFLECTMETHOD = 1024
 )
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
index 5103299..18813c3 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -1,14 +1,12 @@
-// Copyright 2015 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.
 
 package obj
 
 import (
-	"bufio"
 	"bytes"
 	"fmt"
-	"io"
 	"log"
 	"os"
 	"strings"
@@ -26,165 +24,6 @@ func Cputime() float64 {
 	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 Binitr(r io.Reader) *Biobuf {
-	return &Biobuf{r: bufio.NewReader(r)}
-}
-
-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 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
@@ -287,6 +126,10 @@ func CConv(s uint8) string {
 }
 
 func (p *Prog) String() string {
+	if p == nil {
+		return "<nil Prog>"
+	}
+
 	if p.Ctxt == nil {
 		return "<Prog without ctxt>"
 	}
@@ -295,8 +138,13 @@ func (p *Prog) String() string {
 
 	var buf bytes.Buffer
 
-	fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(int(p.As)), sc)
+	fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(p.As), sc)
 	sep := "\t"
+	quadOpAmd64 := p.RegTo2 == -1
+	if quadOpAmd64 {
+		fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset)
+		sep = ", "
+	}
 	if p.From.Type != TYPE_NONE {
 		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
 		sep = ", "
@@ -307,9 +155,11 @@ func (p *Prog) String() string {
 		sep = ", "
 	}
 	if p.From3Type() != TYPE_NONE {
-		if p.From3.Type == TYPE_CONST && (p.As == ADATA || p.As == ATEXT || p.As == AGLOBL) {
+		if p.From3.Type == TYPE_CONST && (p.As == ATEXT || p.As == AGLOBL) {
 			// Special case - omit $.
 			fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
+		} else if quadOpAmd64 {
+			fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg)))
 		} else {
 			fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
 		}
@@ -318,17 +168,30 @@ func (p *Prog) String() string {
 	if p.To.Type != TYPE_NONE {
 		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
 	}
-	if p.RegTo2 != REG_NONE {
+	if p.RegTo2 != REG_NONE && !quadOpAmd64 {
 		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
+	var p *Prog
+	if i := ctxt.allocIdx; i < len(ctxt.progs) {
+		p = &ctxt.progs[i]
+		ctxt.allocIdx = i + 1
+	} else {
+		p = new(Prog) // should be the only call to this; all others should use ctxt.NewProg
+	}
 	p.Ctxt = ctxt
 	return p
 }
+func (ctxt *Link) freeProgs() {
+	s := ctxt.progs[:ctxt.allocIdx]
+	for i := range s {
+		s[i] = Prog{}
+	}
+	ctxt.allocIdx = 0
+}
 
 func (ctxt *Link) Line(n int) string {
 	return ctxt.LineHist.LineString(n)
@@ -366,7 +229,7 @@ func Dconv(p *Prog, a *Addr) string {
 		}
 
 		str = Rconv(int(a.Reg))
-		if a.Name != TYPE_NONE || a.Sym != nil {
+		if a.Name != NAME_NONE || a.Sym != nil {
 			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
 		}
 
@@ -389,6 +252,9 @@ func Dconv(p *Prog, a *Addr) string {
 		if a.Index != REG_NONE {
 			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
 		}
+		if p != nil && p.As == ATYPE && a.Gotype != nil {
+			str += fmt.Sprintf("%s", a.Gotype.Name)
+		}
 
 	case TYPE_CONST:
 		if a.Reg != 0 {
@@ -420,7 +286,7 @@ func Dconv(p *Prog, a *Addr) string {
 
 	case TYPE_SHIFT:
 		v := int(a.Offset)
-		op := string("<<>>->@>"[((v>>5)&3)<<1:])
+		op := "<<>>->@>"[((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 {
@@ -530,10 +396,11 @@ const (
 	RBasePPC64  = 4 * 1024  // range [4k, 8k)
 	RBaseARM64  = 8 * 1024  // range [8k, 13k)
 	RBaseMIPS64 = 13 * 1024 // range [13k, 14k)
+	RBaseS390X  = 14 * 1024 // range [14k, 15k)
 )
 
 // RegisterRegister binds a pretty-printer (Rconv) for register
-// numbers to a given register number range.  Lo is inclusive,
+// 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})
@@ -575,26 +442,8 @@ func regListConv(list int) string {
 	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
-	ABaseMIPS64
-	AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
-)
-
 type opSet struct {
-	lo    int
+	lo    As
 	names []string
 }
 
@@ -603,17 +452,17 @@ var aSpace []opSet
 
 // RegisterOpcode binds a list of instruction names
 // to a given instruction number range.
-func RegisterOpcode(lo int, Anames []string) {
+func RegisterOpcode(lo As, Anames []string) {
 	aSpace = append(aSpace, opSet{lo, Anames})
 }
 
-func Aconv(a int) string {
-	if 0 <= a && a < len(Anames) {
+func Aconv(a As) string {
+	if 0 <= a && int(a) < len(Anames) {
 		return Anames[a]
 	}
 	for i := range aSpace {
 		as := &aSpace[i]
-		if as.lo <= a && a < as.lo+len(as.names) {
+		if as.lo <= a && int(a-as.lo) < len(as.names) {
 			return as.names[a-as.lo]
 		}
 	}
@@ -624,7 +473,6 @@ var Anames = []string{
 	"XXX",
 	"CALL",
 	"CHECKNIL",
-	"DATA",
 	"DUFFCOPY",
 	"DUFFZERO",
 	"END",
diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go
index 12eaa90..ab1dabc 100644
--- a/src/cmd/internal/obj/x86/a.out.go
+++ b/src/cmd/internal/obj/x86/a.out.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -34,6 +34,12 @@ import "cmd/internal/obj"
 
 //go:generate go run ../stringer.go -i $GOFILE -o anames.go -p x86
 
+const (
+	/* mark flags */
+	DONE          = 1 << iota
+	PRESERVEFLAGS // not allowed to clobber flags
+)
+
 /*
  *	amd64
  */
@@ -114,23 +120,23 @@ const (
 	AINTO
 	AIRETL
 	AIRETW
-	AJCC
-	AJCS
+	AJCC // >= unsigned
+	AJCS // < unsigned
 	AJCXZL
-	AJEQ
-	AJGE
-	AJGT
-	AJHI
-	AJLE
-	AJLS
-	AJLT
-	AJMI
-	AJNE
-	AJOC
-	AJOS
-	AJPC
-	AJPL
-	AJPS
+	AJEQ // == (zero)
+	AJGE // >= signed
+	AJGT // > signed
+	AJHI // > unsigned
+	AJLE // <= signed
+	AJLS // <= unsigned
+	AJLT // < signed
+	AJMI // sign bit set (negative)
+	AJNE // != (nonzero)
+	AJOC // overflow clear
+	AJOS // overflow set
+	AJPC // parity clear
+	AJPL // sign bit clear (positive)
+	AJPS // parity set
 	ALAHF
 	ALARL
 	ALARW
@@ -289,8 +295,6 @@ const (
 	AFMOVX
 	AFMOVXP
 
-	AFCOMB
-	AFCOMBP
 	AFCOMD
 	AFCOMDP
 	AFCOMDPP
@@ -620,14 +624,7 @@ const (
 	APADDUSW
 	APADDW
 	APAND
-	APANDB
-	APANDL
 	APANDN
-	APANDSB
-	APANDSW
-	APANDUSB
-	APANDUSW
-	APANDW
 	APAVGB
 	APAVGW
 	APCMPEQB
@@ -644,23 +641,6 @@ const (
 	APEXTRD
 	APEXTRQ
 	APEXTRW
-	APFACC
-	APFADD
-	APFCMPEQ
-	APFCMPGE
-	APFCMPGT
-	APFMAX
-	APFMIN
-	APFMUL
-	APFNACC
-	APFPNACC
-	APFRCP
-	APFRCPI2T
-	APFRCPIT1
-	APFRSQIT1
-	APFRSQRT
-	APFSUB
-	APFSUBR
 	APHADDD
 	APHADDSW
 	APHADDW
@@ -691,7 +671,6 @@ const (
 	APMOVZXWD
 	APMOVZXWQ
 	APMULDQ
-	APMULHRW
 	APMULHUW
 	APMULHW
 	APMULLD
@@ -722,7 +701,6 @@ const (
 	APSUBUSB
 	APSUBUSW
 	APSUBW
-	APSWAPL
 	APUNPCKHBW
 	APUNPCKHLQ
 	APUNPCKHQDQ
@@ -761,11 +739,8 @@ const (
 	AUNPCKLPS
 	AXORPD
 	AXORPS
+	APCMPESTRI
 
-	APF2IW
-	APF2IL
-	API2FW
-	API2FL
 	ARETFW
 	ARETFL
 	ARETFQ
@@ -810,6 +785,24 @@ const (
 	AVPAND
 	AVPTEST
 	AVPBROADCASTB
+	AVPSHUFB
+	AVPSHUFD
+	AVPERM2F128
+	AVPALIGNR
+	AVPADDQ
+	AVPADDD
+	AVPSRLDQ
+	AVPSLLDQ
+	AVPSRLQ
+	AVPSLLQ
+	AVPSRLD
+	AVPSLLD
+	AVPOR
+	AVPBLENDD
+	AVINSERTI128
+	AVPERM2I128
+	ARORXL
+	ARORXQ
 
 	// from 386
 	AJCXZW
diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go
index 1875eae..3b30154 100644
--- a/src/cmd/internal/obj/x86/anames.go
+++ b/src/cmd/internal/obj/x86/anames.go
@@ -255,8 +255,6 @@ var Anames = []string{
 	"FMOVWP",
 	"FMOVX",
 	"FMOVXP",
-	"FCOMB",
-	"FCOMBP",
 	"FCOMD",
 	"FCOMDP",
 	"FCOMDPP",
@@ -569,14 +567,7 @@ var Anames = []string{
 	"PADDUSW",
 	"PADDW",
 	"PAND",
-	"PANDB",
-	"PANDL",
 	"PANDN",
-	"PANDSB",
-	"PANDSW",
-	"PANDUSB",
-	"PANDUSW",
-	"PANDW",
 	"PAVGB",
 	"PAVGW",
 	"PCMPEQB",
@@ -593,23 +584,6 @@ var Anames = []string{
 	"PEXTRD",
 	"PEXTRQ",
 	"PEXTRW",
-	"PFACC",
-	"PFADD",
-	"PFCMPEQ",
-	"PFCMPGE",
-	"PFCMPGT",
-	"PFMAX",
-	"PFMIN",
-	"PFMUL",
-	"PFNACC",
-	"PFPNACC",
-	"PFRCP",
-	"PFRCPI2T",
-	"PFRCPIT1",
-	"PFRSQIT1",
-	"PFRSQRT",
-	"PFSUB",
-	"PFSUBR",
 	"PHADDD",
 	"PHADDSW",
 	"PHADDW",
@@ -640,7 +614,6 @@ var Anames = []string{
 	"PMOVZXWD",
 	"PMOVZXWQ",
 	"PMULDQ",
-	"PMULHRW",
 	"PMULHUW",
 	"PMULHW",
 	"PMULLD",
@@ -671,7 +644,6 @@ var Anames = []string{
 	"PSUBUSB",
 	"PSUBUSW",
 	"PSUBW",
-	"PSWAPL",
 	"PUNPCKHBW",
 	"PUNPCKHLQ",
 	"PUNPCKHQDQ",
@@ -710,10 +682,7 @@ var Anames = []string{
 	"UNPCKLPS",
 	"XORPD",
 	"XORPS",
-	"PF2IW",
-	"PF2IL",
-	"PI2FW",
-	"PI2FL",
+	"PCMPESTRI",
 	"RETFW",
 	"RETFL",
 	"RETFQ",
@@ -751,6 +720,24 @@ var Anames = []string{
 	"VPAND",
 	"VPTEST",
 	"VPBROADCASTB",
+	"VPSHUFB",
+	"VPSHUFD",
+	"VPERM2F128",
+	"VPALIGNR",
+	"VPADDQ",
+	"VPADDD",
+	"VPSRLDQ",
+	"VPSLLDQ",
+	"VPSRLQ",
+	"VPSLLQ",
+	"VPSRLD",
+	"VPSLLD",
+	"VPOR",
+	"VPBLENDD",
+	"VINSERTI128",
+	"VPERM2I128",
+	"RORXL",
+	"RORXQ",
 	"JCXZW",
 	"FCMOVCC",
 	"FCMOVCS",
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 4ed1d87..676da40 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,6 +32,7 @@ package x86
 
 import (
 	"cmd/internal/obj"
+	"encoding/binary"
 	"fmt"
 	"log"
 	"strings"
@@ -59,7 +60,7 @@ const (
 )
 
 type Optab struct {
-	as     int16
+	as     obj.As
 	ytab   []ytab
 	prefix uint8
 	op     [23]uint8
@@ -74,7 +75,7 @@ type ytab struct {
 }
 
 type Movtab struct {
-	as   int16
+	as   obj.As
 	ft   uint8
 	f3t  uint8
 	tt   uint8
@@ -184,7 +185,6 @@ const (
 	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 */
@@ -208,6 +208,9 @@ const (
 	Zvex_rm_v_r
 	Zvex_r_v_rm
 	Zvex_v_rm_r
+	Zvex_i_rm_r
+	Zvex_i_r_v
+	Zvex_i_rm_v_r
 	Zmax
 )
 
@@ -753,10 +756,6 @@ 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},
@@ -851,6 +850,35 @@ var yvex_xy3 = []ytab{
 	{Yym, Yyr, Yyr, Zvex_rm_v_r, 2},
 }
 
+var yvex_ri3 = []ytab{
+	{Yi8, Ymb, Yrl, Zvex_i_rm_r, 2},
+}
+
+var yvex_xyi3 = []ytab{
+	{Yi8, Yxm, Yxr, Zvex_i_rm_r, 2},
+	{Yi8, Yym, Yyr, Zvex_i_rm_r, 2},
+}
+
+var yvex_yyi4 = []ytab{ //TODO don't hide 4 op, some version have xmm version
+	{Yym, Yyr, Yyr, Zvex_i_rm_v_r, 2},
+}
+
+var yvex_xyi4 = []ytab{
+	{Yxm, Yyr, Yyr, Zvex_i_rm_v_r, 2},
+}
+
+var yvex_shift = []ytab{
+	{Yi8, Yxr, Yxr, Zvex_i_r_v, 3},
+	{Yi8, Yyr, Yyr, Zvex_i_r_v, 3},
+	{Yxm, Yxr, Yxr, Zvex_rm_v_r, 2},
+	{Yxm, Yyr, Yyr, Zvex_rm_v_r, 2},
+}
+
+var yvex_shift_dq = []ytab{
+	{Yi8, Yxr, Yxr, Zvex_i_r_v, 3},
+	{Yi8, Yyr, Yyr, Zvex_i_r_v, 3},
+}
+
 var yvex_r3 = []ytab{
 	{Yml, Yrl, Yrl, Zvex_rm_v_r, 2},
 	{Yml, Yrl, Yrl, Zvex_rm_v_r, 2},
@@ -888,11 +916,6 @@ var yvex_vpbroadcast = []ytab{
 	{Yxm, Ynone, Yyr, Zvex_rm_v_r, 2},
 }
 
-var yvex_xxmyxm = []ytab{
-	{Yxr, Ynone, Yxm, Zvex_r_v_rm, 2},
-	{Yyr, Ynone, Yxm, Zvex_r_v_rm, 2},
-}
-
 var ymmxmm0f38 = []ytab{
 	{Ymm, Ynone, Ymr, Zlitm_r, 3},
 	{Yxm, Ynone, Yxr, Zlitm_r, 5},
@@ -1085,7 +1108,6 @@ var optab =
 	{ACVTPD2PS, yxm, Pe, [23]uint8{0x5a}},
 	{ACVTPS2PL, yxcvm1, Px, [23]uint8{Pe, 0x5b, Pm, 0x2d}},
 	{ACVTPS2PD, yxm, Pm, [23]uint8{0x5a}},
-	{API2FW, ymfp, Px, [23]uint8{0x0c}},
 	{ACVTSD2SL, yxcvfl, Pf2, [23]uint8{0x2d}},
 	{ACVTSD2SQ, yxcvfq, Pw, [23]uint8{Pf2, 0x2d}},
 	{ACVTSD2SS, yxm, Pf2, [23]uint8{0x5a}},
@@ -1106,7 +1128,6 @@ var optab =
 	{ACQO, ynone, Pw, [23]uint8{0x99}},
 	{ADAA, ynone, P32, [23]uint8{0x27}},
 	{ADAS, ynone, P32, [23]uint8{0x2f}},
-	{obj.ADATA, nil, 0, [23]uint8{}},
 	{ADECB, yincb, Pb, [23]uint8{0xfe, 01}},
 	{ADECL, yincl, Px1, [23]uint8{0x48, 0xff, 01}},
 	{ADECQ, yincq, Pw, [23]uint8{0xff, 01}},
@@ -1303,26 +1324,6 @@ var optab =
 	{APEXTRB, yextr, Pq, [23]uint8{0x3a, 0x14, 00}},
 	{APEXTRD, yextr, Pq, [23]uint8{0x3a, 0x16, 00}},
 	{APEXTRQ, yextr, Pq3, [23]uint8{0x3a, 0x16, 00}},
-	{APF2IL, ymfp, Px, [23]uint8{0x1d}},
-	{APF2IW, ymfp, Px, [23]uint8{0x1c}},
-	{API2FL, ymfp, Px, [23]uint8{0x0d}},
-	{APFACC, ymfp, Px, [23]uint8{0xae}},
-	{APFADD, ymfp, Px, [23]uint8{0x9e}},
-	{APFCMPEQ, ymfp, Px, [23]uint8{0xb0}},
-	{APFCMPGE, ymfp, Px, [23]uint8{0x90}},
-	{APFCMPGT, ymfp, Px, [23]uint8{0xa0}},
-	{APFMAX, ymfp, Px, [23]uint8{0xa4}},
-	{APFMIN, ymfp, Px, [23]uint8{0x94}},
-	{APFMUL, ymfp, Px, [23]uint8{0xb4}},
-	{APFNACC, ymfp, Px, [23]uint8{0x8a}},
-	{APFPNACC, ymfp, Px, [23]uint8{0x8e}},
-	{APFRCP, ymfp, Px, [23]uint8{0x96}},
-	{APFRCPIT1, ymfp, Px, [23]uint8{0xa6}},
-	{APFRCPI2T, ymfp, Px, [23]uint8{0xb6}},
-	{APFRSQIT1, ymfp, Px, [23]uint8{0xa7}},
-	{APFRSQRT, ymfp, Px, [23]uint8{0x97}},
-	{APFSUB, ymfp, Px, [23]uint8{0x9a}},
-	{APFSUBR, ymfp, Px, [23]uint8{0xaa}},
 	{APHADDD, ymmxmm0f38, Px, [23]uint8{0x0F, 0x38, 0x02, 0, 0x66, 0x0F, 0x38, 0x02, 0}},
 	{APHADDSW, yxm_q4, Pq4, [23]uint8{0x03}},
 	{APHADDW, yxm_q4, Pq4, [23]uint8{0x01}},
@@ -1353,7 +1354,6 @@ var optab =
 	{APMOVZXWD, yxm_q4, Pq4, [23]uint8{0x33}},
 	{APMOVZXWQ, yxm_q4, Pq4, [23]uint8{0x34}},
 	{APMULDQ, yxm_q4, Pq4, [23]uint8{0x28}},
-	{APMULHRW, ymfp, Px, [23]uint8{0xb7}},
 	{APMULHUW, ymm, Py1, [23]uint8{0xe4, Pe, 0xe4}},
 	{APMULHW, ymm, Py1, [23]uint8{0xe5, Pe, 0xe5}},
 	{APMULLD, yxm_q4, Pq4, [23]uint8{0x40}},
@@ -1395,7 +1395,6 @@ var optab =
 	{APSUBUSB, yxm, Pe, [23]uint8{0xd8}},
 	{APSUBUSW, yxm, Pe, [23]uint8{0xd9}},
 	{APSUBW, yxm, Pe, [23]uint8{0xf9}},
-	{APSWAPL, ymfp, Px, [23]uint8{0xbb}},
 	{APUNPCKHBW, ymm, Py1, [23]uint8{0x68, Pe, 0x68}},
 	{APUNPCKHLQ, ymm, Py1, [23]uint8{0x6a, Pe, 0x6a}},
 	{APUNPCKHQDQ, yxm, Pe, [23]uint8{0x6d}},
@@ -1553,8 +1552,6 @@ var optab =
 	{AFCMOVNE, yfcmv, Px, [23]uint8{0xdb, 01}},
 	{AFCMOVNU, yfcmv, Px, [23]uint8{0xdb, 03}},
 	{AFCMOVUN, yfcmv, Px, [23]uint8{0xda, 03}},
-	{AFCOMB, nil, 0, [23]uint8{}},
-	{AFCOMBP, nil, 0, [23]uint8{}},
 	{AFCOMD, yfadd, Px, [23]uint8{0xdc, 02, 0xd8, 02, 0xdc, 02}},  /* botch */
 	{AFCOMDP, yfadd, Px, [23]uint8{0xdc, 03, 0xd8, 03, 0xdc, 03}}, /* botch */
 	{AFCOMDPP, ycompp, Px, [23]uint8{0xde, 03}},
@@ -1683,6 +1680,7 @@ var optab =
 	{AROUNDSS, yaes2, Pq, [23]uint8{0x3a, 0x0a, 0}},
 	{APSHUFD, yxshuf, Pq, [23]uint8{0x70, 0}},
 	{APCLMULQDQ, yxshuf, Pq, [23]uint8{0x3a, 0x44, 0}},
+	{APCMPESTRI, yxshuf, Pq, [23]uint8{0x3a, 0x61, 0}},
 
 	{AANDNL, yvex_r3, Pvex, [23]uint8{VEX_LZ_0F38_W0, 0xF2}},
 	{AANDNQ, yvex_r3, Pvex, [23]uint8{VEX_LZ_0F38_W1, 0xF2}},
@@ -1713,6 +1711,24 @@ var optab =
 	{AVPAND, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xDB, VEX_256_66_0F_WIG, 0xDB}},
 	{AVPBROADCASTB, yvex_vpbroadcast, Pvex, [23]uint8{VEX_128_66_0F38_W0, 0x78, VEX_256_66_0F38_W0, 0x78}},
 	{AVPTEST, yvex_xy2, Pvex, [23]uint8{VEX_128_66_0F38_WIG, 0x17, VEX_256_66_0F38_WIG, 0x17}},
+	{AVPSHUFB, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F38_WIG, 0x00, VEX_256_66_0F38_WIG, 0x00}},
+	{AVPSHUFD, yvex_xyi3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x70, VEX_256_66_0F_WIG, 0x70}},
+	{AVPOR, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xeb, VEX_256_66_0F_WIG, 0xeb}},
+	{AVPADDQ, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xd4, VEX_256_66_0F_WIG, 0xd4}},
+	{AVPADDD, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xfe, VEX_256_66_0F_WIG, 0xfe}},
+	{AVPSLLD, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x72, 0xf0, VEX_256_66_0F_WIG, 0x72, 0xf0, VEX_128_66_0F_WIG, 0xf2, VEX_256_66_0F_WIG, 0xf2}},
+	{AVPSLLQ, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xf0, VEX_256_66_0F_WIG, 0x73, 0xf0, VEX_128_66_0F_WIG, 0xf3, VEX_256_66_0F_WIG, 0xf3}},
+	{AVPSRLD, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x72, 0xd0, VEX_256_66_0F_WIG, 0x72, 0xd0, VEX_128_66_0F_WIG, 0xd2, VEX_256_66_0F_WIG, 0xd2}},
+	{AVPSRLQ, yvex_shift, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xd0, VEX_256_66_0F_WIG, 0x73, 0xd0, VEX_128_66_0F_WIG, 0xd3, VEX_256_66_0F_WIG, 0xd3}},
+	{AVPSRLDQ, yvex_shift_dq, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xd8, VEX_256_66_0F_WIG, 0x73, 0xd8}},
+	{AVPSLLDQ, yvex_shift_dq, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x73, 0xf8, VEX_256_66_0F_WIG, 0x73, 0xf8}},
+	{AVPERM2F128, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_W0, 0x06}},
+	{AVPALIGNR, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x0f}},
+	{AVPBLENDD, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x02}},
+	{AVINSERTI128, yvex_xyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x38}},
+	{AVPERM2I128, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x46}},
+	{ARORXL, yvex_ri3, Pvex, [23]uint8{VEX_LZ_F2_0F3A_W0, 0xf0}},
+	{ARORXQ, yvex_ri3, Pvex, [23]uint8{VEX_LZ_F2_0F3A_W1, 0xf0}},
 
 	{AXACQUIRE, ynone, Px, [23]uint8{0xf2}},
 	{AXRELEASE, ynone, Px, [23]uint8{0xf3}},
@@ -1778,13 +1794,13 @@ func fillnop(p []byte, n int) {
 }
 
 func naclpad(ctxt *obj.Link, s *obj.LSym, c int32, pad int32) int32 {
-	obj.Symgrow(ctxt, s, int64(c)+int64(pad))
+	s.Grow(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 {
+func spadjop(ctxt *obj.Link, p *obj.Prog, l, q obj.As) obj.As {
+	if p.Mode != 64 || ctxt.Arch.PtrSize == 4 {
 		return l
 	}
 	return q
@@ -1801,7 +1817,6 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 		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 {
@@ -1811,11 +1826,11 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 		if p.As == AADJSP {
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = REG_SP
-			v = int32(-p.From.Offset)
+			v := int32(-p.From.Offset)
 			p.From.Offset = int64(v)
-			p.As = int16(spadjop(ctxt, p, AADDL, AADDQ))
+			p.As = spadjop(ctxt, p, AADDL, AADDQ)
 			if v < 0 {
-				p.As = int16(spadjop(ctxt, p, ASUBL, ASUBQ))
+				p.As = spadjop(ctxt, p, ASUBL, ASUBQ)
 				v = -v
 				p.From.Offset = int64(v)
 			}
@@ -1827,7 +1842,9 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 	}
 
 	var q *obj.Prog
+	var count int64 // rough count of number of instructions
 	for p := s.Text; p != nil; p = p.Link {
+		count++
 		p.Back = 2 // use short branches first time through
 		q = p.Pcond
 		if q != nil && (q.Back&2 != 0) {
@@ -1838,11 +1855,11 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 		if p.As == AADJSP {
 			p.To.Type = obj.TYPE_REG
 			p.To.Reg = REG_SP
-			v = int32(-p.From.Offset)
+			v := int32(-p.From.Offset)
 			p.From.Offset = int64(v)
-			p.As = int16(spadjop(ctxt, p, AADDL, AADDQ))
+			p.As = spadjop(ctxt, p, AADDL, AADDQ)
 			if v < 0 {
-				p.As = int16(spadjop(ctxt, p, ASUBL, ASUBQ))
+				p.As = spadjop(ctxt, p, ASUBL, ASUBQ)
 				v = -v
 				p.From.Offset = int64(v)
 			}
@@ -1852,30 +1869,25 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 			}
 		}
 	}
+	s.GrowCap(count * 5) // preallocate roughly 5 bytes per instruction
 
 	n := 0
-	var bp []byte
 	var c int32
-	var i int
-	var loop int32
-	var m int
-	var p *obj.Prog
 	errors := ctxt.Errors
+	var deferreturn *obj.LSym
+	if ctxt.Headtype == obj.Hnacl {
+		deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0)
+	}
 	for {
-		loop = 0
-		for i = 0; i < len(s.R); i++ {
+		loop := int32(0)
+		for i := range s.R {
 			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 {
+		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 {
@@ -1912,10 +1924,10 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 
 			if (p.Back&4 != 0) && c&(LoopAlign-1) != 0 {
 				// pad with NOPs
-				v = -c & (LoopAlign - 1)
+				v := -c & (LoopAlign - 1)
 
 				if v <= MaxLoopPad {
-					obj.Symgrow(ctxt, s, int64(c)+int64(v))
+					s.Grow(int64(c) + int64(v))
 					fillnop(s.P[c:], int(v))
 					c += v
 				}
@@ -1925,7 +1937,7 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 
 			// process forward jumps to p
 			for q = p.Rel; q != nil; q = q.Forwd {
-				v = int32(p.Pc - (q.Pc + int64(q.Mark)))
+				v := int32(p.Pc - (q.Pc + int64(q.Isize)))
 				if q.Back&2 != 0 { // short
 					if v > 127 {
 						loop++
@@ -1938,14 +1950,7 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 						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)
+					binary.LittleEndian.PutUint32(s.P[q.Pc+int64(q.Isize)-4:], uint32(v))
 				}
 			}
 
@@ -1953,15 +1958,14 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 
 			p.Pc = int64(c)
 			asmins(ctxt, p)
-			m = -cap(ctxt.Andptr) + cap(ctxt.And[:])
+			m := ctxt.AsmBuf.Len()
 			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)
+			s.Grow(p.Pc + int64(m))
+			copy(s.P[p.Pc:], ctxt.AsmBuf.Bytes())
 			c += int32(m)
 		}
 
@@ -1982,16 +1986,6 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 		c = naclpad(ctxt, s, c, -c&31)
 	}
 
-	// Pad functions with trap instruction, to catch invalid jumps
-	if c&(FuncAlign-1) != 0 {
-		v = -c & (FuncAlign - 1)
-		obj.Symgrow(ctxt, s, int64(c)+int64(v))
-		for i := c; i < c+v; i++ {
-			// 0xCC is INT $3 - breakpoint instruction
-			s.P[i] = uint8(0xCC)
-		}
-		c += v
-	}
 	s.Size = int64(c)
 
 	if false { /* debug['a'] > 1 */
@@ -2016,10 +2010,8 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
 }
 
 func instinit() {
-	var c int
-
 	for i := 1; optab[i].as != 0; i++ {
-		c = int(optab[i].as)
+		c := optab[i].as
 		if opindex[c&obj.AMask] != nil {
 			log.Fatalf("phase error in optab: %d (%v)", i, obj.Aconv(c))
 		}
@@ -2214,7 +2206,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 					return 0x64 // FS
 				}
 
-				if ctxt.Flag_shared != 0 {
+				if ctxt.Flag_shared {
 					log.Fatalf("unknown TLS base register for linux with -shared")
 				} else {
 					return 0x64 // FS
@@ -2234,7 +2226,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 	}
 
 	if p.Mode == 32 {
-		if a.Index == REG_TLS && ctxt.Flag_shared != 0 {
+		if a.Index == REG_TLS && ctxt.Flag_shared {
 			// When building for inclusion into a shared library, an instruction of the form
 			//     MOVL 0(CX)(TLS*1), AX
 			// becomes
@@ -2263,7 +2255,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 		return 0x26
 
 	case REG_TLS:
-		if ctxt.Flag_shared != 0 {
+		if ctxt.Flag_shared {
 			// When building for inclusion into a shared library, an instruction of the form
 			//     MOV 0(CX)(TLS*1), AX
 			// becomes
@@ -2302,8 +2294,28 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 		return Yxxx
 
 	case obj.TYPE_MEM:
-		if a.Name != obj.NAME_NONE {
-			if ctxt.Asmode == 64 && (a.Reg != REG_NONE || a.Index != REG_NONE || a.Scale != 0) {
+		if a.Index == REG_SP {
+			// Can't use SP as the index register
+			return Yxxx
+		}
+		if ctxt.Asmode == 64 {
+			switch a.Name {
+			case obj.NAME_EXTERN, obj.NAME_STATIC, obj.NAME_GOTREF:
+				// Global variables can't use index registers and their
+				// base register is %rip (%rip is encoded as REG_NONE).
+				if a.Reg != REG_NONE || a.Index != REG_NONE || a.Scale != 0 {
+					return Yxxx
+				}
+			case obj.NAME_AUTO, obj.NAME_PARAM:
+				// These names must have a base of SP.  The old compiler
+				// uses 0 for the base register. SSA uses REG_SP.
+				if a.Reg != REG_SP && a.Reg != 0 {
+					return Yxxx
+				}
+			case obj.NAME_NONE:
+				// everything is ok
+			default:
+				// unknown name
 				return Yxxx
 			}
 		}
@@ -2317,7 +2329,7 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 
 		case obj.NAME_EXTERN,
 			obj.NAME_STATIC:
-			if a.Sym != nil && isextern(a.Sym) || (p.Mode == 32 && ctxt.Flag_shared == 0) {
+			if a.Sym != nil && isextern(a.Sym) || (p.Mode == 32 && !ctxt.Flag_shared) {
 				return Yi32
 			}
 			return Yiauto // use pc-relative addressing
@@ -2351,6 +2363,10 @@ func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
 			v = int64(int32(v))
 		}
 		if v == 0 {
+			if p.Mark&PRESERVEFLAGS != 0 {
+				// If PRESERVEFLAGS is set, avoid MOV $0, AX turning into XOR AX, AX.
+				return Yu7
+			}
 			return Yi0
 		}
 		if v == 1 {
@@ -2672,25 +2688,15 @@ bas:
 		i |= reg[base]
 	}
 
-	ctxt.Andptr[0] = byte(i)
-	ctxt.Andptr = ctxt.Andptr[1:]
+	ctxt.AsmBuf.Put1(byte(i))
 	return
 
 bad:
 	ctxt.Diag("asmidx: bad address %d/%d/%d", scale, index, base)
-	ctxt.Andptr[0] = 0
-	ctxt.Andptr = ctxt.Andptr[1:]
+	ctxt.AsmBuf.Put1(0)
 	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
 
@@ -2701,22 +2707,10 @@ func relput4(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 		}
 		r := obj.Addrel(ctxt.Cursym)
 		*r = rel
-		r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+		r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 	}
 
-	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:]
+	ctxt.AsmBuf.PutInt32(int32(v))
 }
 
 /*
@@ -2754,7 +2748,7 @@ func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
 		if a.Name == obj.NAME_GOTREF {
 			r.Siz = 4
 			r.Type = obj.R_GOTPCREL
-		} else if isextern(s) || (p.Mode != 64 && ctxt.Flag_shared == 0) {
+		} else if isextern(s) || (p.Mode != 64 && !ctxt.Flag_shared) {
 			r.Siz = 4
 			r.Type = obj.R_ADDR
 		} else {
@@ -2775,7 +2769,7 @@ func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
 			log.Fatalf("reloc")
 		}
 
-		if ctxt.Flag_shared == 0 || isAndroid {
+		if !ctxt.Flag_shared || isAndroid {
 			r.Type = obj.R_TLS_LE
 			r.Siz = 4
 			r.Off = -1 // caller must fill in
@@ -2792,6 +2786,16 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 	var rel obj.Reloc
 
 	rex &= 0x40 | Rxr
+	switch {
+	case int64(int32(a.Offset)) == a.Offset:
+		// Offset fits in sign-extended 32 bits.
+	case int64(uint32(a.Offset)) == a.Offset && ctxt.Rexflag&Rxw == 0:
+		// Offset fits in zero-extended 32 bits in a 32-bit instruction.
+		// This is allowed for assembly that wants to use 32-bit hex
+		// constants, e.g. LEAL 0x99999999(AX), AX.
+	default:
+		ctxt.Diag("offset too large in %s", p)
+	}
 	v := int32(a.Offset)
 	rel.Siz = 0
 
@@ -2812,8 +2816,7 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 		if v != 0 {
 			goto bad
 		}
-		ctxt.Andptr[0] = byte(3<<6 | reg[a.Reg]<<0 | r<<3)
-		ctxt.Andptr = ctxt.Andptr[1:]
+		ctxt.AsmBuf.Put1(byte(3<<6 | reg[a.Reg]<<0 | r<<3))
 		ctxt.Rexflag |= regrex[a.Reg]&(0x40|Rxb) | rex
 		return
 	}
@@ -2831,7 +2834,7 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 			if !isextern(a.Sym) && p.Mode == 64 {
 				goto bad
 			}
-			if p.Mode == 32 && ctxt.Flag_shared != 0 {
+			if p.Mode == 32 && ctxt.Flag_shared {
 				base = REG_CX
 			} else {
 				base = REG_NONE
@@ -2845,30 +2848,25 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 
 		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:]
+			ctxt.AsmBuf.Put1(byte(0<<6 | 4<<0 | r<<3))
 			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:]
+			ctxt.AsmBuf.Put1(byte(0<<6 | 4<<0 | r<<3))
 			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:]
+			ctxt.AsmBuf.Put1(byte(1<<6 | 4<<0 | r<<3))
 			asmidx(ctxt, int(a.Scale), int(a.Index), base)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.AsmBuf.Put1(byte(v))
 			return
 		}
 
-		ctxt.Andptr[0] = byte(2<<6 | 4<<0 | r<<3)
-		ctxt.Andptr = ctxt.Andptr[1:]
+		ctxt.AsmBuf.Put1(byte(2<<6 | 4<<0 | r<<3))
 		asmidx(ctxt, int(a.Scale), int(a.Index), base)
 		goto putrelv
 	}
@@ -2881,7 +2879,7 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 		if a.Sym == nil {
 			ctxt.Diag("bad addr: %v", p)
 		}
-		if p.Mode == 32 && ctxt.Flag_shared != 0 {
+		if p.Mode == 32 && ctxt.Flag_shared {
 			base = REG_CX
 		} else {
 			base = REG_NONE
@@ -2903,44 +2901,39 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 			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:]
+			ctxt.AsmBuf.Put1(byte(0<<6 | 5<<0 | r<<3))
 			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 */
+		// temporary
+		ctxt.AsmBuf.Put2(
+			byte(0<<6|4<<0|r<<3), // sib present
+			0<<6|4<<3|5<<0,       // 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:]
+			ctxt.AsmBuf.Put1(byte(0<<6 | reg[base]<<0 | r<<3))
 			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:]
+			ctxt.AsmBuf.Put1(byte(1<<6 | reg[base]<<0 | r<<3))
 			asmidx(ctxt, int(a.Scale), REG_NONE, base)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.AsmBuf.Put1(byte(v))
 			return
 		}
 
-		ctxt.Andptr[0] = byte(2<<6 | reg[base]<<0 | r<<3)
-		ctxt.Andptr = ctxt.Andptr[1:]
+		ctxt.AsmBuf.Put1(byte(2<<6 | reg[base]<<0 | r<<3))
 		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 {
+		if a.Index == REG_TLS && !ctxt.Flag_shared {
 			rel = obj.Reloc{}
 			rel.Type = obj.R_TLS_LE
 			rel.Siz = 4
@@ -2950,20 +2943,16 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
 		}
 
 		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:]
+			ctxt.AsmBuf.Put1(byte(0<<6 | reg[base]<<0 | r<<3))
 			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:]
+			ctxt.AsmBuf.Put2(byte(1<<6|reg[base]<<0|r<<3), byte(v))
 			return
 		}
 
-		ctxt.Andptr[0] = byte(2<<6 | reg[base]<<0 | r<<3)
-		ctxt.Andptr = ctxt.Andptr[1:]
+		ctxt.AsmBuf.Put1(byte(2<<6 | reg[base]<<0 | r<<3))
 		goto putrelv
 	}
 
@@ -2978,10 +2967,10 @@ putrelv:
 
 		r := obj.Addrel(ctxt.Cursym)
 		*r = rel
-		r.Off = int32(ctxt.Curp.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+		r.Off = int32(ctxt.Curp.Pc + int64(ctxt.AsmBuf.Len()))
 	}
 
-	put4(ctxt, v)
+	ctxt.AsmBuf.PutInt32(v)
 	return
 
 bad:
@@ -3202,11 +3191,9 @@ func mediaop(ctxt *obj.Link, o *Optab, op int, osize int, z int) int {
 	case Pm, Pe, Pf2, Pf3:
 		if osize != 1 {
 			if op != Pm {
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 			}
-			ctxt.Andptr[0] = Pm
-			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.AsmBuf.Put1(Pm)
 			z++
 			op = int(o.op[z])
 			break
@@ -3214,14 +3201,12 @@ func mediaop(ctxt *obj.Link, o *Optab, op int, osize int, z int) int {
 		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:]
+		if ctxt.AsmBuf.Len() == 0 || ctxt.AsmBuf.Last() != Pm {
+			ctxt.AsmBuf.Put1(Pm)
 		}
 	}
 
-	ctxt.Andptr[0] = byte(op)
-	ctxt.Andptr = ctxt.Andptr[1:]
+	ctxt.AsmBuf.Put1(byte(op))
 	return z
 }
 
@@ -3244,9 +3229,16 @@ var bpduff2 = []byte{
 // https://en.wikipedia.org/wiki/VEX_prefix#Technical_description
 func asmvex(ctxt *obj.Link, rm, v, r *obj.Addr, vex, opcode uint8) {
 	ctxt.Vexflag = 1
-	rexR := regrex[r.Reg] & Rxr
-	rexB := regrex[rm.Reg] & Rxb
-	rexX := regrex[rm.Index] & Rxx
+	rexR := 0
+	if r != nil {
+		rexR = regrex[r.Reg] & Rxr
+	}
+	rexB := 0
+	rexX := 0
+	if rm != nil {
+		rexB = regrex[rm.Reg] & Rxb
+		rexX = regrex[rm.Index] & Rxx
+	}
 	vexM := (vex >> 3) & 0xF
 	vexWLP := vex & 0x87
 	vexV := byte(0)
@@ -3256,18 +3248,15 @@ func asmvex(ctxt *obj.Link, rm, v, r *obj.Addr, vex, opcode uint8) {
 	vexV ^= 0xF
 	if vexM == 1 && (rexX|rexB) == 0 && vex&vexW1 == 0 {
 		// Can use 2-byte encoding.
-		ctxt.Andptr[0] = 0xc5
-		ctxt.Andptr[1] = byte(rexR<<5) ^ 0x80 | vexV<<3 | vexWLP
-		ctxt.Andptr = ctxt.Andptr[2:]
+		ctxt.AsmBuf.Put2(0xc5, byte(rexR<<5)^0x80|vexV<<3|vexWLP)
 	} else {
 		// Must use 3-byte encoding.
-		ctxt.Andptr[0] = 0xc4
-		ctxt.Andptr[1] = (byte(rexR|rexX|rexB) << 5) ^ 0xE0 | vexM
-		ctxt.Andptr[2] = vexV<<3 | vexWLP
-		ctxt.Andptr = ctxt.Andptr[3:]
+		ctxt.AsmBuf.Put3(0xc4,
+			(byte(rexR|rexX|rexB)<<5)^0xE0|vexM,
+			vexV<<3|vexWLP,
+		)
 	}
-	ctxt.Andptr[0] = opcode
-	ctxt.Andptr = ctxt.Andptr[1:]
+	ctxt.AsmBuf.Put1(opcode)
 }
 
 func doasm(ctxt *obj.Link, p *obj.Prog) {
@@ -3282,13 +3271,11 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 
 	pre := prefixof(ctxt, p, &p.From)
 	if pre != 0 {
-		ctxt.Andptr[0] = byte(pre)
-		ctxt.Andptr = ctxt.Andptr[1:]
+		ctxt.AsmBuf.Put1(byte(pre))
 	}
 	pre = prefixof(ctxt, p, &p.To)
 	if pre != 0 {
-		ctxt.Andptr[0] = byte(pre)
-		ctxt.Andptr = ctxt.Andptr[1:]
+		ctxt.AsmBuf.Put1(byte(pre))
 	}
 
 	// TODO(rsc): This special case is for SHRQ $3, AX:DX,
@@ -3358,55 +3345,31 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					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:]
+				ctxt.AsmBuf.Put2(Pe, Pm)
 
 			case Pq3: /* 16 bit escape and opcode escape + REX.W */
 				ctxt.Rexflag |= Pw
-				ctxt.Andptr[0] = Pe
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = Pm
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put2(Pe, Pm)
 
 			case Pq4: /*  66 0F 38 */
-				ctxt.Andptr[0] = 0x66
-				ctxt.Andptr[1] = 0x0F
-				ctxt.Andptr[2] = 0x38
-				ctxt.Andptr = ctxt.Andptr[3:]
+				ctxt.AsmBuf.Put3(0x66, 0x0F, 0x38)
 
 			case Pf2, /* xmm opcode escape */
 				Pf3:
-				ctxt.Andptr[0] = byte(o.prefix)
-				ctxt.Andptr = ctxt.Andptr[1:]
-
-				ctxt.Andptr[0] = Pm
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put2(o.prefix, Pm)
 
 			case Pef3:
-				ctxt.Andptr[0] = Pe
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = Pf3
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = Pm
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put3(Pe, Pf3, Pm)
 
 			case Pfw: /* xmm opcode escape + REX.W */
 				ctxt.Rexflag |= Pw
-				ctxt.Andptr[0] = Pf3
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = Pm
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put2(Pf3, Pm)
 
 			case Pm: /* opcode escape */
-				ctxt.Andptr[0] = Pm
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(Pm)
 
 			case Pe: /* 16 bit escape */
-				ctxt.Andptr[0] = Pe
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(Pe)
 
 			case Pw: /* 64-bit escape */
 				if p.Mode != 64 {
@@ -3465,8 +3428,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 			}
 			op = int(o.op[z])
 			if op == 0x0f {
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				z++
 				op = int(o.op[z])
 			}
@@ -3485,8 +3447,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					if op == 0 {
 						break
 					}
-					ctxt.Andptr[0] = byte(op)
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put1(byte(op))
 				}
 
 			case Zlitm_r:
@@ -3495,8 +3456,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					if op == 0 {
 						break
 					}
-					ctxt.Andptr[0] = byte(op)
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put1(byte(op))
 				}
 				asmand(ctxt, p, &p.From, &p.To)
 
@@ -3504,18 +3464,12 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				bytereg(&p.From, &p.Ft)
 				fallthrough
 
-				/* fall through */
 			case Zm_r:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
-
+				ctxt.AsmBuf.Put1(byte(op))
 				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:]
+				ctxt.AsmBuf.Put2(byte(op), o.op[z+1])
 				asmand(ctxt, p, &p.From, &p.To)
 
 			case Zm_r_xm:
@@ -3530,17 +3484,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 			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:]
+				ctxt.AsmBuf.Put1(byte(p.To.Offset))
 
 			case Zibm_r, Zibr_m:
 				for {
@@ -3550,20 +3494,17 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					if op == 0 {
 						break
 					}
-					ctxt.Andptr[0] = byte(op)
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put1(byte(op))
 				}
 				if yt.zcase == Zibr_m {
 					asmand(ctxt, p, &p.To, p.From3)
 				} else {
 					asmand(ctxt, p, p.From3, &p.To)
 				}
-				ctxt.Andptr[0] = byte(p.From.Offset)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(p.From.Offset))
 
 			case Zaut_r:
-				ctxt.Andptr[0] = 0x8d
-				ctxt.Andptr = ctxt.Andptr[1:] /* leal */
+				ctxt.AsmBuf.Put1(0x8d) // leal
 				if p.From.Type != obj.TYPE_ADDR {
 					ctxt.Diag("asmins: Zaut sb type ADDR")
 				}
@@ -3572,19 +3513,38 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				p.From.Type = obj.TYPE_ADDR
 
 			case Zm_o:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				asmando(ctxt, p, &p.From, int(o.op[z+1]))
 
 			case Zr_m:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				asmand(ctxt, p, &p.To, &p.From)
 
 			case Zvex_rm_v_r:
 				asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1])
 				asmand(ctxt, p, &p.From, &p.To)
 
+			case Zvex_i_r_v:
+				asmvex(ctxt, p.From3, &p.To, nil, o.op[z], o.op[z+1])
+				regnum := byte(0x7)
+				if p.From3.Reg >= REG_X0 && p.From3.Reg <= REG_X15 {
+					regnum &= byte(p.From3.Reg - REG_X0)
+				} else {
+					regnum &= byte(p.From3.Reg - REG_Y0)
+				}
+				ctxt.AsmBuf.Put1(byte(o.op[z+2]) | regnum)
+				ctxt.AsmBuf.Put1(byte(p.From.Offset))
+
+			case Zvex_i_rm_v_r:
+				asmvex(ctxt, &p.From, p.From3, &p.To, o.op[z], o.op[z+1])
+				asmand(ctxt, p, &p.From, &p.To)
+				ctxt.AsmBuf.Put1(byte(p.From3.Offset))
+
+			case Zvex_i_rm_r:
+				asmvex(ctxt, p.From3, nil, &p.To, o.op[z], o.op[z+1])
+				asmand(ctxt, p, p.From3, &p.To)
+				ctxt.AsmBuf.Put1(byte(p.From.Offset))
+
 			case Zvex_v_rm_r:
 				asmvex(ctxt, p.From3, &p.From, &p.To, o.op[z], o.op[z+1])
 				asmand(ctxt, p, p.From3, &p.To)
@@ -3603,8 +3563,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				asmand(ctxt, p, &p.To, &p.From)
 
 			case Zo_m:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				asmando(ctxt, p, &p.To, int(o.op[z+1]))
 
 			case Zcallindreg:
@@ -3615,29 +3574,23 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				fallthrough
 
 			case Zo_m64:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				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:]
+				ctxt.AsmBuf.Put1(byte(op))
 				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:]
+				ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, &p.To, nil)))
 
 			case Zibo_m:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				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:]
+				ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, &p.From, nil)))
 
 			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:]
+				ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, &p.From, nil)))
 
 			case Z_ib, Zib_:
 				if yt.zcase == Zib_ {
@@ -3645,45 +3598,31 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				} else {
 					a = &p.To
 				}
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				if p.As == AXABORT {
-					ctxt.Andptr[0] = byte(o.op[z+1])
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put1(o.op[z+1])
 				}
-				ctxt.Andptr[0] = byte(vaddr(ctxt, p, a, nil))
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, a, nil)))
 
 			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:]
+				ctxt.AsmBuf.Put2(byte(op+reg[p.To.Reg]), byte(vaddr(ctxt, p, &p.From, nil)))
 
 			case Zil_rp:
 				ctxt.Rexflag |= regrex[p.To.Reg] & Rxb
-				ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op + reg[p.To.Reg]))
 				if o.prefix == Pe {
 					v = vaddr(ctxt, p, &p.From, nil)
-					ctxt.Andptr[0] = byte(v)
-					ctxt.Andptr = ctxt.Andptr[1:]
-					ctxt.Andptr[0] = byte(v >> 8)
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.PutInt16(int16(v))
 				} else {
 					relput4(ctxt, p, &p.From)
 				}
 
 			case Zo_iw:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				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:]
+					ctxt.AsmBuf.PutInt16(int16(v))
 				}
 
 			case Ziq_rp:
@@ -3695,45 +3634,39 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					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:]
+					ctxt.AsmBuf.Put1(byte(0xb8 + reg[p.To.Reg]))
 					if rel.Type != 0 {
 						r = obj.Addrel(ctxt.Cursym)
 						*r = rel
-						r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+						r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 					}
 
-					put4(ctxt, int32(v))
+					ctxt.AsmBuf.PutInt32(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:]
-
+					ctxt.AsmBuf.Put1(0xc7)
 					asmando(ctxt, p, &p.To, 0)
-					put4(ctxt, int32(v)) /* need all 8 */
+
+					ctxt.AsmBuf.PutInt32(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:]
+					ctxt.AsmBuf.Put1(byte(op + reg[p.To.Reg]))
 					if rel.Type != 0 {
 						r = obj.Addrel(ctxt.Cursym)
 						*r = rel
-						r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+						r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 					}
 
-					put8(ctxt, v)
+					ctxt.AsmBuf.PutInt64(v)
 				}
 
 			case Zib_rr:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				asmand(ctxt, p, &p.To, &p.To)
-				ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, &p.From, nil)))
 
 			case Z_il, Zil_:
 				if yt.zcase == Zil_ {
@@ -3741,21 +3674,16 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				} else {
 					a = &p.To
 				}
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				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:]
+					ctxt.AsmBuf.PutInt16(int16(v))
 				} else {
 					relput4(ctxt, p, a)
 				}
 
 			case Zm_ilo, Zilo_m:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				if yt.zcase == Zilo_m {
 					a = &p.From
 					asmando(ctxt, p, &p.To, int(o.op[z+1]))
@@ -3766,71 +3694,56 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 
 				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:]
+					ctxt.AsmBuf.PutInt16(int16(v))
 				} else {
 					relput4(ctxt, p, a)
 				}
 
 			case Zil_rr:
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				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:]
+					ctxt.AsmBuf.PutInt16(int16(v))
 				} 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:]
+				ctxt.AsmBuf.Put1(byte(op + reg[p.To.Reg]))
 
 			case Zrp_:
 				ctxt.Rexflag |= regrex[p.From.Reg] & (Rxb | 0x40)
-				ctxt.Andptr[0] = byte(op + reg[p.From.Reg])
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op + reg[p.From.Reg]))
 
 			case Zclr:
 				ctxt.Rexflag &^= Pw
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				asmand(ctxt, p, &p.To, &p.To)
 
 			case Zcallcon, Zjmpcon:
 				if yt.zcase == Zcallcon {
-					ctxt.Andptr[0] = byte(op)
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put1(byte(op))
 				} else {
-					ctxt.Andptr[0] = byte(o.op[z+1])
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put1(o.op[z+1])
 				}
 				r = obj.Addrel(ctxt.Cursym)
-				r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+				r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 				r.Type = obj.R_PCREL
 				r.Siz = 4
 				r.Add = p.To.Offset
-				put4(ctxt, 0)
+				ctxt.AsmBuf.PutInt32(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:]
+				ctxt.AsmBuf.Put2(byte(op), o.op[z+1])
 				r = obj.Addrel(ctxt.Cursym)
-				r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+				r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 				r.Type = obj.R_ADDR
 				r.Siz = 4
 				r.Add = p.To.Offset
 				r.Sym = p.To.Sym
-				put4(ctxt, 0)
+				ctxt.AsmBuf.PutInt32(0)
 
 			case Zcall, Zcallduff:
 				if p.To.Sym == nil {
@@ -3842,7 +3755,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					ctxt.Diag("directly calling duff when dynamically linking Go")
 				}
 
-				if obj.Framepointer_enabled != 0 && yt.zcase == Zcallduff && p.Mode == 64 {
+				if ctxt.Framepointer_enabled && 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
@@ -3850,31 +3763,27 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					// 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.AsmBuf.Put(bpduff1)
 				}
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(op))
 				r = obj.Addrel(ctxt.Cursym)
-				r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+				r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 				r.Sym = p.To.Sym
 				r.Add = p.To.Offset
 				r.Type = obj.R_CALL
 				r.Siz = 4
-				put4(ctxt, 0)
+				ctxt.AsmBuf.PutInt32(0)
 
-				if obj.Framepointer_enabled != 0 && yt.zcase == Zcallduff && p.Mode == 64 {
+				if ctxt.Framepointer_enabled && yt.zcase == Zcallduff && p.Mode == 64 {
 					// Pop BP pushed above.
 					// MOVQ 0(BP), BP
-					copy(ctxt.Andptr, bpduff2)
-					ctxt.Andptr = ctxt.Andptr[len(bpduff2):]
+					ctxt.AsmBuf.Put(bpduff2)
 				}
 
 			// TODO: jump across functions needs reloc
 			case Zbr, Zjmp, Zloop:
 				if p.As == AXBEGIN {
-					ctxt.Andptr[0] = byte(op)
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put1(byte(op))
 				}
 				if p.To.Sym != nil {
 					if yt.zcase != Zjmp {
@@ -3882,14 +3791,13 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						log.Fatalf("bad code")
 					}
 
-					ctxt.Andptr[0] = byte(o.op[z+1])
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put1(o.op[z+1])
 					r = obj.Addrel(ctxt.Cursym)
-					r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+					r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 					r.Sym = p.To.Sym
 					r.Type = obj.R_PCREL
 					r.Siz = 4
-					put4(ctxt, 0)
+					ctxt.AsmBuf.PutInt32(0)
 					break
 				}
 
@@ -3908,13 +3816,9 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					v = q.Pc - (p.Pc + 2)
 					if v >= -128 && p.As != AXBEGIN {
 						if p.As == AJCXZL {
-							ctxt.Andptr[0] = 0x67
-							ctxt.Andptr = ctxt.Andptr[1:]
+							ctxt.AsmBuf.Put1(0x67)
 						}
-						ctxt.Andptr[0] = byte(op)
-						ctxt.Andptr = ctxt.Andptr[1:]
-						ctxt.Andptr[0] = byte(v)
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put2(byte(op), byte(v))
 					} else if yt.zcase == Zloop {
 						ctxt.Diag("loop too far: %v", p)
 					} else {
@@ -3923,21 +3827,12 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 							v--
 						}
 						if yt.zcase == Zbr {
-							ctxt.Andptr[0] = 0x0f
-							ctxt.Andptr = ctxt.Andptr[1:]
+							ctxt.AsmBuf.Put1(0x0f)
 							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:]
+						ctxt.AsmBuf.Put1(o.op[z+1])
+						ctxt.AsmBuf.PutInt32(int32(v))
 					}
 
 					break
@@ -3949,30 +3844,17 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 				q.Rel = p
 				if p.Back&2 != 0 && p.As != AXBEGIN { // short
 					if p.As == AJCXZL {
-						ctxt.Andptr[0] = 0x67
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put1(0x67)
 					}
-					ctxt.Andptr[0] = byte(op)
-					ctxt.Andptr = ctxt.Andptr[1:]
-					ctxt.Andptr[0] = 0
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put2(byte(op), 0)
 				} 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.AsmBuf.Put1(0x0f)
 					}
-					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:]
+					ctxt.AsmBuf.Put1(o.op[z+1])
+					ctxt.AsmBuf.PutInt32(0)
 				}
 
 				break
@@ -4002,28 +3884,16 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 					rel.Siz = uint8(op)
 					r = obj.Addrel(ctxt.Cursym)
 					*r = rel
-					r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+					r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 				}
 
-				ctxt.Andptr[0] = byte(v)
-				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.AsmBuf.Put1(byte(v))
 				if op > 1 {
-					ctxt.Andptr[0] = byte(v >> 8)
-					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.AsmBuf.Put1(byte(v >> 8))
 					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:]
+						ctxt.AsmBuf.PutInt16(int16(v >> 16))
 						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:]
+							ctxt.AsmBuf.PutInt32(int32(v >> 32))
 						}
 					}
 				}
@@ -4045,74 +3915,49 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 
 				case 0: /* lit */
 					for z = 0; t[z] != E; z++ {
-						ctxt.Andptr[0] = t[z]
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put1(t[z])
 					}
 
 				case 1: /* r,m */
-					ctxt.Andptr[0] = t[0]
-					ctxt.Andptr = ctxt.Andptr[1:]
-
+					ctxt.AsmBuf.Put1(t[0])
 					asmando(ctxt, p, &p.To, int(t[1]))
 
 				case 2: /* m,r */
-					ctxt.Andptr[0] = t[0]
-					ctxt.Andptr = ctxt.Andptr[1:]
-
+					ctxt.AsmBuf.Put1(t[0])
 					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:]
+					ctxt.AsmBuf.Put2(t[0], t[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:]
+					ctxt.AsmBuf.Put2(t[0], t[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:]
+						ctxt.AsmBuf.Put1(t[0])
 					}
 					switch p.To.Index {
 					default:
 						goto bad
 
 					case REG_DS:
-						ctxt.Andptr[0] = 0xc5
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put1(0xc5)
 
 					case REG_SS:
-						ctxt.Andptr[0] = 0x0f
-						ctxt.Andptr = ctxt.Andptr[1:]
-						ctxt.Andptr[0] = 0xb2
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put2(0x0f, 0xb2)
 
 					case REG_ES:
-						ctxt.Andptr[0] = 0xc4
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put1(0xc4)
 
 					case REG_FS:
-						ctxt.Andptr[0] = 0x0f
-						ctxt.Andptr = ctxt.Andptr[1:]
-						ctxt.Andptr[0] = 0xb4
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put2(0x0f, 0xb4)
 
 					case REG_GS:
-						ctxt.Andptr[0] = 0x0f
-						ctxt.Andptr = ctxt.Andptr[1:]
-						ctxt.Andptr[0] = 0xb5
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put2(0x0f, 0xb5)
 					}
 
 					asmand(ctxt, p, &p.From, &p.To)
@@ -4125,8 +3970,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						ctxt.Rexflag |= Pw
 						t = t[1:]
 					} else if t[0] == Pe {
-						ctxt.Andptr[0] = Pe
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put1(Pe)
 						t = t[1:]
 					}
 
@@ -4135,13 +3979,9 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						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:]
+						ctxt.AsmBuf.Put2(0x0f, t[0])
 						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:]
+						ctxt.AsmBuf.Put1(byte(p.From.Offset))
 
 					case obj.TYPE_REG:
 						switch p.From.Reg {
@@ -4149,10 +3989,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 							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:]
+							ctxt.AsmBuf.Put2(0x0f, t[1])
 							asmandsz(ctxt, p, &p.To, reg[p.From3.Reg], regrex[p.From3.Reg], 0)
 						}
 					}
@@ -4177,7 +4014,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 
 						case obj.Hlinux,
 							obj.Hnacl:
-							if ctxt.Flag_shared != 0 {
+							if ctxt.Flag_shared {
 								// Note that this is not generating the same insns as the other cases.
 								//     MOV TLS, R_to
 								// becomes
@@ -4189,25 +4026,21 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 								// and R_CALL & R_TLS_IE relocs. 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.Andptr[0] = 0xe8
-								ctxt.Andptr = ctxt.Andptr[1:]
+								ctxt.AsmBuf.Put1(0xe8)
 								r = obj.Addrel(ctxt.Cursym)
-								r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+								r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 								r.Type = obj.R_CALL
 								r.Siz = 4
 								r.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk.cx", 0)
-								put4(ctxt, 0)
+								ctxt.AsmBuf.PutInt32(0)
 
-								ctxt.Andptr[0] = 0x8B
-								ctxt.Andptr = ctxt.Andptr[1:]
-								ctxt.Andptr[0] = byte(2<<6 | reg[REG_CX] | (reg[p.To.Reg] << 3))
-								ctxt.Andptr = ctxt.Andptr[1:]
+								ctxt.AsmBuf.Put2(0x8B, byte(2<<6|reg[REG_CX]|(reg[p.To.Reg]<<3)))
 								r = obj.Addrel(ctxt.Cursym)
-								r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+								r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 								r.Type = obj.R_TLS_IE
 								r.Siz = 4
 								r.Add = 2
-								put4(ctxt, 0)
+								ctxt.AsmBuf.PutInt32(0)
 							} else {
 								// ELF TLS base is 0(GS).
 								pp.From = p.From
@@ -4217,10 +4050,8 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 								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:]
+								ctxt.AsmBuf.Put2(0x65, // GS
+									0x8B)
 								asmand(ctxt, p, &pp.From, &p.To)
 							}
 						case obj.Hplan9:
@@ -4233,8 +4064,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 							pp.From.Sym = ctxt.Plan9privates
 							pp.From.Offset = 0
 							pp.From.Index = REG_NONE
-							ctxt.Andptr[0] = 0x8B
-							ctxt.Andptr = ctxt.Andptr[1:]
+							ctxt.AsmBuf.Put1(0x8B)
 							asmand(ctxt, p, &pp.From, &p.To)
 
 						case obj.Hwindows:
@@ -4246,10 +4076,8 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 							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:]
+							ctxt.AsmBuf.Put2(0x64, // FS
+								0x8B)
 							asmand(ctxt, p, &pp.From, &p.To)
 						}
 						break
@@ -4260,7 +4088,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						log.Fatalf("unknown TLS base location for %s", obj.Headstr(ctxt.Headtype))
 
 					case obj.Hlinux:
-						if ctxt.Flag_shared == 0 {
+						if !ctxt.Flag_shared {
 							log.Fatalf("unknown TLS base location for linux without -shared")
 						}
 						// Note that this is not generating the same insn as the other cases.
@@ -4274,16 +4102,13 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						// 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:]
+						ctxt.AsmBuf.Put2(0x8B, byte(0x05|(reg[p.To.Reg]<<3)))
 						r = obj.Addrel(ctxt.Cursym)
-						r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+						r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
 						r.Type = obj.R_TLS_IE
 						r.Siz = 4
 						r.Add = -4
-						put4(ctxt, 0)
+						ctxt.AsmBuf.PutInt32(0)
 
 					case obj.Hplan9:
 						if ctxt.Plan9privates == nil {
@@ -4296,8 +4121,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						pp.From.Offset = 0
 						pp.From.Index = REG_NONE
 						ctxt.Rexflag |= Pw
-						ctxt.Andptr[0] = 0x8B
-						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.AsmBuf.Put1(0x8B)
 						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.
@@ -4311,10 +4135,8 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						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:]
+						ctxt.AsmBuf.Put2(0x64, // FS
+							0x8B)
 						asmand(ctxt, p, &pp.From, &p.To)
 
 					case obj.Hwindows:
@@ -4328,10 +4150,8 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 						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:]
+						ctxt.AsmBuf.Put2(0x65, // GS
+							0x8B)
 						asmand(ctxt, p, &pp.From, &p.To)
 					}
 				}
@@ -4362,21 +4182,17 @@ bad:
 			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 */
+					ctxt.AsmBuf.Put1(0x87) // 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 */
+					ctxt.AsmBuf.Put1(0x87) // 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 */
+					ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // 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 */
+					ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
 				}
 				return
 			}
@@ -4384,21 +4200,17 @@ bad:
 			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 */
+				ctxt.AsmBuf.Put1(0x87) // 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 */
+				ctxt.AsmBuf.Put1(0x87) // 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 */
+				ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // 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 */
+				ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg lsh,ax
 			}
 			return
 		}
@@ -4410,41 +4222,33 @@ bad:
 			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 */
+					ctxt.AsmBuf.Put1(0x87) //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 */
+					ctxt.AsmBuf.Put1(0x87) // 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 */
+					ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // 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 */
+					ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
 				}
 				return
 			}
 
 			if isax(&p.From) {
-				ctxt.Andptr[0] = 0x87
-				ctxt.Andptr = ctxt.Andptr[1:] /* xchg rhs,bx */
+				ctxt.AsmBuf.Put1(0x87) // 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 */
+				ctxt.AsmBuf.Put1(0x87) // 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 */
+				ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // 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 */
+				ctxt.AsmBuf.Put1(byte(0x90 + reg[z])) // xchg rsh,ax
 			}
 			return
 		}
@@ -4581,50 +4385,30 @@ var naclstos = []uint8{
 
 func nacltrunc(ctxt *obj.Link, reg int) {
 	if reg >= REG_R8 {
-		ctxt.Andptr[0] = 0x45
-		ctxt.Andptr = ctxt.Andptr[1:]
+		ctxt.AsmBuf.Put1(0x45)
 	}
 	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:]
+	ctxt.AsmBuf.Put2(0x89, byte(3<<6|reg<<3|reg))
 }
 
 func asmins(ctxt *obj.Link, p *obj.Prog) {
-	ctxt.Andptr = ctxt.And[:]
+	ctxt.AsmBuf.Reset()
 	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):]
+			ctxt.AsmBuf.Put(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:]
+				ctxt.AsmBuf.Put3(0x83, byte(0xe0|(p.To.Reg-REG_AX)), 0xe0)
 			}
 
 		case AINT:
-			ctxt.Andptr[0] = 0xf4
-			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.AsmBuf.Put1(0xf4)
 			return
 		}
 	}
@@ -4646,67 +4430,37 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
 		}
 
 		if p.As != ALEAQ && p.As != ALEAL {
-			if p.From.Index != obj.TYPE_NONE && p.From.Scale > 0 {
+			if p.From.Index != REG_NONE && p.From.Scale > 0 {
 				nacltrunc(ctxt, int(p.From.Index))
 			}
-			if p.To.Index != obj.TYPE_NONE && p.To.Scale > 0 {
+			if p.To.Index != REG_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):]
+			ctxt.AsmBuf.Put(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:]
-
+				ctxt.AsmBuf.Put3(0x83, byte(0xe0|(p.To.Reg-REG_AX)), 0xe0)
 				// 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:]
+				ctxt.AsmBuf.Put3(0x4c, 0x01, byte(0xf8|(p.To.Reg-REG_AX)))
 			}
 
 			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:]
-
+				ctxt.AsmBuf.Put4(0x41, 0x83, byte(0xe0|(p.To.Reg-REG_R8)), 0xe0)
 				// 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:]
+				ctxt.AsmBuf.Put3(0x4d, 0x01, byte(0xf8|(p.To.Reg-REG_R8)))
 			}
 
 		case AINT:
-			ctxt.Andptr[0] = 0xf4
-			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.AsmBuf.Put1(0xf4)
 			return
 
 		case ASCASB,
@@ -4717,36 +4471,31 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
 			ASTOSW,
 			ASTOSL,
 			ASTOSQ:
-			copy(ctxt.Andptr, naclstos)
-			ctxt.Andptr = ctxt.Andptr[len(naclstos):]
+			ctxt.AsmBuf.Put(naclstos)
 
 		case AMOVSB, AMOVSW, AMOVSL, AMOVSQ:
-			copy(ctxt.Andptr, naclmovs)
-			ctxt.Andptr = ctxt.Andptr[len(naclmovs):]
+			ctxt.AsmBuf.Put(naclmovs)
 		}
 
 		if ctxt.Rep != 0 {
-			ctxt.Andptr[0] = 0xf3
-			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.AsmBuf.Put1(0xf3)
 			ctxt.Rep = 0
 		}
 
 		if ctxt.Repn != 0 {
-			ctxt.Andptr[0] = 0xf2
-			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.AsmBuf.Put1(0xf2)
 			ctxt.Repn = 0
 		}
 
 		if ctxt.Lock != 0 {
-			ctxt.Andptr[0] = 0xf0
-			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.AsmBuf.Put1(0xf0)
 			ctxt.Lock = 0
 		}
 	}
 
 	ctxt.Rexflag = 0
 	ctxt.Vexflag = 0
-	and0 := ctxt.Andptr
+	mark := ctxt.AsmBuf.Len()
 	ctxt.Asmode = int(p.Mode)
 	doasm(ctxt, p)
 	if ctxt.Rexflag != 0 && ctxt.Vexflag == 0 {
@@ -4760,25 +4509,20 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
 		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
+		n := ctxt.AsmBuf.Len()
 		var np int
-		for np = 0; np < n; np++ {
-			c = int(and0[np])
+		for np = mark; np < n; np++ {
+			c := ctxt.AsmBuf.Peek(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:]
+		ctxt.AsmBuf.Insert(np, byte(0x40|ctxt.Rexflag))
 	}
 
-	n := -cap(ctxt.Andptr) + cap(ctxt.And[:])
-	var r *obj.Reloc
+	n := ctxt.AsmBuf.Len()
 	for i := len(ctxt.Cursym.R) - 1; i >= 0; i-- {
-		r = &ctxt.Cursym.R[i:][0]
+		r := &ctxt.Cursym.R[i]
 		if int64(r.Off) < p.Pc {
 			break
 		}
@@ -4813,12 +4557,9 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
 	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):]
-
+			ctxt.AsmBuf.Put(naclspfix)
 		case REG_BP:
-			copy(ctxt.Andptr, naclbpfix)
-			ctxt.Andptr = ctxt.Andptr[len(naclbpfix):]
+			ctxt.AsmBuf.Put(naclbpfix)
 		}
 	}
 }
diff --git a/src/cmd/internal/obj/x86/list6.go b/src/cmd/internal/obj/x86/list6.go
index 0284bbf..fa9ddca 100644
--- a/src/cmd/internal/obj/x86/list6.go
+++ b/src/cmd/internal/obj/x86/list6.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 55ddfe1..75638a0 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,13 +32,13 @@ package x86
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"math"
 )
 
-func canuse1insntls(ctxt *obj.Link) bool {
+func CanUse1InsnTLS(ctxt *obj.Link) bool {
 	if isAndroid {
 		// For android, we use a disgusting hack that assumes
 		// the thread-local storage slot for g is allocated
@@ -49,7 +49,7 @@ func canuse1insntls(ctxt *obj.Link) bool {
 		return true
 	}
 
-	if ctxt.Arch.Regsize == 4 {
+	if ctxt.Arch.RegSize == 4 {
 		switch ctxt.Headtype {
 		case obj.Hlinux,
 			obj.Hnacl,
@@ -66,7 +66,7 @@ func canuse1insntls(ctxt *obj.Link) bool {
 		obj.Hwindows:
 		return false
 	case obj.Hlinux:
-		return ctxt.Flag_shared == 0
+		return !ctxt.Flag_shared
 	}
 
 	return true
@@ -75,7 +75,7 @@ func canuse1insntls(ctxt *obj.Link) bool {
 func progedit(ctxt *obj.Link, p *obj.Prog) {
 	// Maintain information about code generation mode.
 	if ctxt.Mode == 0 {
-		ctxt.Mode = ctxt.Arch.Regsize * 8
+		ctxt.Mode = ctxt.Arch.RegSize * 8
 	}
 	p.Mode = int8(ctxt.Mode)
 
@@ -130,7 +130,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	// rewriting the instructions more comprehensively, and it only does because
 	// we only support a single TLS variable (g).
 
-	if canuse1insntls(ctxt) {
+	if CanUse1InsnTLS(ctxt) {
 		// Reduce 2-instruction sequence to 1-instruction sequence.
 		// Sequences like
 		//	MOVQ TLS, BX
@@ -189,7 +189,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		}
 	}
 
-	// Rewrite 0 to $0 in 3rd argment to CMPPS etc.
+	// Rewrite 0 to $0 in 3rd argument to CMPPS etc.
 	// That's what the tables expect.
 	switch p.As {
 	case ACMPPD, ACMPPS, ACMPSD, ACMPSS:
@@ -207,7 +207,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	}
 
 	// 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) {
+	if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Family == sys.AMD64 || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
 		switch p.As {
 		case AMOVL:
 			p.As = ALEAL
@@ -231,7 +231,8 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
 	case AMOVSS:
 		if p.From.Type == obj.TYPE_FCONST {
-			if p.From.Val.(float64) == 0 {
+			//  f == 0 can't be used here due to -0, so use Float64bits
+			if f := p.From.Val.(float64); math.Float64bits(f) == 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
@@ -271,7 +272,8 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 	case AMOVSD:
 		// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
 		if p.From.Type == obj.TYPE_FCONST {
-			if p.From.Val.(float64) == 0 {
+			//  f == 0 can't be used here due to -0, so use Float64bits
+			if f := p.From.Val.(float64); math.Float64bits(f) == 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
@@ -312,14 +314,15 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
 		rewriteToUseGot(ctxt, p)
 	}
 
-	if ctxt.Flag_shared != 0 && p.Mode == 32 {
+	if ctxt.Flag_shared && p.Mode == 32 {
 		rewriteToPcrel(ctxt, p)
 	}
 }
 
 // Rewrite p, if necessary, to access global data via the global offset table.
 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
-	var add, lea, mov, reg int16
+	var add, lea, mov obj.As
+	var reg int16
 	if p.Mode == 64 {
 		add = AADDQ
 		lea = ALEAQ
@@ -375,7 +378,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 	}
 	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
 		// $MOV $sym, Rx becomes $MOV sym at GOT, Rx
-		// $MOV $sym+<off>, Rx becomes $MOV sym at GOT, Rx; $ADD <off>, Rx
+		// $MOV $sym+<off>, Rx becomes $MOV sym at GOT, Rx; $LEA <off>(Rx), Rx
 		// On 386 only, more complicated things like PUSHL $sym become $MOV sym at GOT, CX; PUSHL CX
 		cmplxdest := false
 		pAs := p.As
@@ -397,8 +400,9 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
 		q := p
 		if p.From.Offset != 0 {
 			q = obj.Appendp(ctxt, p)
-			q.As = add
-			q.From.Type = obj.TYPE_CONST
+			q.As = lea
+			q.From.Type = obj.TYPE_MEM
+			q.From.Reg = p.To.Reg
 			q.From.Offset = p.From.Offset
 			q.To = p.To
 			p.From.Offset = 0
@@ -606,12 +610,11 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	}
 
 	var bpsize int
-	if p.Mode == 64 && obj.Framepointer_enabled != 0 && autoffset > 0 {
-		// Make room for to save a base pointer.  If autoffset == 0,
+	if p.Mode == 64 && ctxt.Framepointer_enabled && autoffset > 0 && p.From3.Offset&obj.NOFRAME == 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
-
+		bpsize = ctxt.Arch.PtrSize
 		autoffset += int32(bpsize)
 		p.To.Offset += int64(bpsize)
 	} else {
@@ -652,7 +655,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 	}
 
 	if autoffset != 0 {
-		if autoffset%int32(ctxt.Arch.Regsize) != 0 {
+		if autoffset%int32(ctxt.Arch.RegSize) != 0 {
 			ctxt.Diag("unaligned stack size %d", autoffset)
 		}
 		p = obj.Appendp(ctxt, p)
@@ -667,10 +670,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		p = obj.Appendp(ctxt, p)
 
 		p.As = obj.ANOP
-		p.Spadj = int32(-ctxt.Arch.Ptrsize)
+		p.Spadj = int32(-ctxt.Arch.PtrSize)
 		p = obj.Appendp(ctxt, p)
 		p.As = obj.ANOP
-		p.Spadj = int32(ctxt.Arch.Ptrsize)
+		p.Spadj = int32(ctxt.Arch.PtrSize)
 	}
 
 	deltasp := autoffset
@@ -720,7 +723,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		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.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 {
@@ -753,7 +756,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
 		p.As = ALEAQ
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_SP
-		p.From.Offset = int64(autoffset) + int64(ctxt.Arch.Regsize)
+		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 {
@@ -931,7 +934,7 @@ func indir_cx(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
 // Returns last new instruction.
 func load_g_cx(ctxt *obj.Link, p *obj.Prog) *obj.Prog {
 	p.As = AMOVQ
-	if ctxt.Arch.Ptrsize == 4 {
+	if ctxt.Arch.PtrSize == 4 {
 		p.As = AMOVL
 	}
 	p.From.Type = obj.TYPE_MEM
@@ -976,13 +979,13 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 		//	CMPQ SP, stackguard
 		p = obj.Appendp(ctxt, p)
 
-		p.As = int16(cmp)
+		p.As = 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
+		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
+		if ctxt.Cursym.Cfunc {
+			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 		}
 	} else if framesize <= obj.StackBig {
 		// large stack: SP-framesize <= stackguard-StackSmall
@@ -990,7 +993,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 		//	CMPQ AX, stackguard
 		p = obj.Appendp(ctxt, p)
 
-		p.As = int16(lea)
+		p.As = lea
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_SP
 		p.From.Offset = -(int64(framesize) - obj.StackSmall)
@@ -998,13 +1001,13 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 		p.To.Reg = REG_AX
 
 		p = obj.Appendp(ctxt, p)
-		p.As = int16(cmp)
+		p.As = 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
+		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
+		if ctxt.Cursym.Cfunc {
+			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 		}
 	} else {
 		// Such a large stack we need to protect against wraparound.
@@ -1024,17 +1027,17 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 
 		p = obj.Appendp(ctxt, p)
 
-		p.As = int16(mov)
+		p.As = 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.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
+		if ctxt.Cursym.Cfunc {
+			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.As = cmp
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_SI
 		p.To.Type = obj.TYPE_CONST
@@ -1049,7 +1052,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 		q1 = p
 
 		p = obj.Appendp(ctxt, p)
-		p.As = int16(lea)
+		p.As = lea
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_SP
 		p.From.Offset = obj.StackGuard
@@ -1057,14 +1060,14 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 		p.To.Reg = REG_AX
 
 		p = obj.Appendp(ctxt, p)
-		p.As = int16(sub)
+		p.As = 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.As = cmp
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_AX
 		p.To.Type = obj.TYPE_CONST
@@ -1089,16 +1092,26 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
 	call.Mode = ctxt.Cursym.Text.Mode
 	call.As = obj.ACALL
 	call.To.Type = obj.TYPE_BRANCH
+	call.To.Name = obj.NAME_EXTERN
 	morestack := "runtime.morestack"
 	switch {
-	case ctxt.Cursym.Cfunc != 0:
+	case ctxt.Cursym.Cfunc:
 		morestack = "runtime.morestackc"
 	case ctxt.Cursym.Text.From3Offset()&obj.NEEDCTXT == 0:
 		morestack = "runtime.morestack_noctxt"
 	}
 	call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
+	// When compiling 386 code for dynamic linking, the call needs to be adjusted
+	// to follow PIC rules. This in turn can insert more instructions, so we need
+	// to keep track of the start of the call (where the jump will be to) and the
+	// end (which following instructions are appended to).
+	callend := call
+	progedit(ctxt, callend)
+	for ; callend.Link != nil; callend = callend.Link {
+		progedit(ctxt, callend.Link)
+	}
 
-	jmp := obj.Appendp(ctxt, call)
+	jmp := obj.Appendp(ctxt, callend)
 	jmp.As = obj.AJMP
 	jmp.To.Type = obj.TYPE_BRANCH
 	jmp.Pcond = ctxt.Cursym.Text.Link
@@ -1122,7 +1135,7 @@ func follow(ctxt *obj.Link, s *obj.LSym) {
 	s.Text = firstp.Link
 }
 
-func nofollow(a int) bool {
+func nofollow(a obj.As) bool {
 	switch a {
 	case obj.AJMP,
 		obj.ARET,
@@ -1139,7 +1152,7 @@ func nofollow(a int) bool {
 	return false
 }
 
-func pushpop(a int) bool {
+func pushpop(a obj.As) bool {
 	switch a {
 	case APUSHL,
 		APUSHFL,
@@ -1159,7 +1172,7 @@ func pushpop(a int) bool {
 	return false
 }
 
-func relinv(a int16) int16 {
+func relinv(a obj.As) obj.As {
 	switch a {
 	case AJEQ:
 		return AJNE
@@ -1195,14 +1208,14 @@ func relinv(a int16) int16 {
 		return AJOS
 	}
 
-	log.Fatalf("unknown relation: %s", obj.Aconv(int(a)))
+	log.Fatalf("unknown relation: %s", obj.Aconv(a))
 	return 0
 }
 
 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
 	var q *obj.Prog
 	var i int
-	var a int
+	var a obj.As
 
 loop:
 	if p == nil {
@@ -1212,16 +1225,16 @@ loop:
 		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.Mark |= DONE
 
 			p = q
-			if p.Mark == 0 {
+			if p.Mark&DONE == 0 {
 				goto loop
 			}
 		}
 	}
 
-	if p.Mark != 0 {
+	if p.Mark&DONE != 0 {
 		/*
 		 * p goes here, but already used it elsewhere.
 		 * copy up to 4 instructions or else branch to other copy.
@@ -1235,7 +1248,7 @@ loop:
 			if q == *last {
 				break
 			}
-			a = int(q.As)
+			a = q.As
 			if a == obj.ANOP {
 				i--
 				continue
@@ -1244,7 +1257,7 @@ loop:
 			if nofollow(a) || pushpop(a) {
 				break // NOTE(rsc): arm does goto copy
 			}
-			if q.Pcond == nil || q.Pcond.Mark != 0 {
+			if q.Pcond == nil || q.Pcond.Mark&DONE != 0 {
 				continue
 			}
 			if a == obj.ACALL || a == ALOOP {
@@ -1258,10 +1271,10 @@ loop:
 
 				q = obj.Copyp(ctxt, p)
 				p = p.Link
-				q.Mark = 1
+				q.Mark |= DONE
 				(*last).Link = q
 				*last = q
-				if int(q.As) != a || q.Pcond == nil || q.Pcond.Mark != 0 {
+				if q.As != a || q.Pcond == nil || q.Pcond.Mark&DONE != 0 {
 					continue
 				}
 
@@ -1271,7 +1284,7 @@ loop:
 				q.Link = p
 				xfol(ctxt, q.Link, last)
 				p = q.Link
-				if p.Mark != 0 {
+				if p.Mark&DONE != 0 {
 					return
 				}
 				goto loop
@@ -1288,11 +1301,11 @@ loop:
 	}
 
 	/* emit p */
-	p.Mark = 1
+	p.Mark |= DONE
 
 	(*last).Link = p
 	*last = p
-	a = int(p.As)
+	a = p.As
 
 	/* continue loop with what comes after p */
 	if nofollow(a) {
@@ -1318,7 +1331,7 @@ loop:
 				 * expect conditional jump to be taken.
 				 * rewrite so that's the fall-through case.
 				 */
-				p.As = relinv(int16(a))
+				p.As = relinv(a)
 
 				q = p.Link
 				p.Link = p.Pcond
@@ -1326,9 +1339,9 @@ loop:
 			}
 		} else {
 			q = p.Link
-			if q.Mark != 0 {
+			if q.Mark&DONE != 0 {
 				if a != ALOOP {
-					p.As = relinv(int16(a))
+					p.As = relinv(a)
 					p.Link = p.Pcond
 					p.Pcond = q
 				}
@@ -1336,7 +1349,7 @@ loop:
 		}
 
 		xfol(ctxt, p.Link, last)
-		if p.Pcond.Mark != 0 {
+		if p.Pcond.Mark&DONE != 0 {
 			return
 		}
 		p = p.Pcond
@@ -1347,7 +1360,7 @@ loop:
 	goto loop
 }
 
-var unaryDst = map[int]bool{
+var unaryDst = map[obj.As]bool{
 	ABSWAPL:    true,
 	ABSWAPQ:    true,
 	ACMPXCHG8B: true,
@@ -1398,43 +1411,28 @@ var unaryDst = map[int]bool{
 }
 
 var Linkamd64 = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "amd64",
-	Thechar:    '6',
+	Arch:       sys.ArchAMD64,
 	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',
+	Arch:       sys.ArchAMD64P32,
 	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',
+	Arch:       sys.Arch386,
 	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
index 5fa1d3b..fe1f95c 100644
--- a/src/cmd/internal/obj/x86/obj6_test.go
+++ b/src/cmd/internal/obj/x86/obj6_test.go
@@ -20,9 +20,9 @@ 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
+LEAQ name+10(SB), AX -> MOVQ name at GOT(SB), AX; LEAQ 10(AX), 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+10(SB), AX -> MOVQ name at GOT(SB), AX; LEAQ 10(AX), AX
 
 MOVQ name(SB), AX -> NOP; MOVQ name at GOT(SB), R15; MOVQ (R15), AX
 MOVQ name+10(SB), AX -> NOP; MOVQ name at GOT(SB), R15; MOVQ 10(R15), AX
@@ -76,7 +76,6 @@ func parseTestData(t *testing.T) *ParsedTestData {
 }
 
 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), " ")
diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go
index f038883..25c3301 100644
--- a/src/cmd/internal/objfile/disasm.go
+++ b/src/cmd/internal/objfile/disasm.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -15,8 +15,8 @@ import (
 	"strings"
 	"text/tabwriter"
 
-	"cmd/internal/unvendor/golang.org/x/arch/arm/armasm"
-	"cmd/internal/unvendor/golang.org/x/arch/x86/x86asm"
+	"golang.org/x/arch/arm/armasm"
+	"golang.org/x/arch/x86/x86asm"
 )
 
 // Disasm is a disassembler for a given File.
@@ -245,4 +245,5 @@ var byteOrders = map[string]binary.ByteOrder{
 	"arm":     binary.LittleEndian,
 	"ppc64":   binary.BigEndian,
 	"ppc64le": binary.LittleEndian,
+	"s390x":   binary.BigEndian,
 }
diff --git a/src/cmd/internal/objfile/elf.go b/src/cmd/internal/objfile/elf.go
index 305706d..c811460 100644
--- a/src/cmd/internal/objfile/elf.go
+++ b/src/cmd/internal/objfile/elf.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,6 +7,7 @@
 package objfile
 
 import (
+	"debug/dwarf"
 	"debug/elf"
 	"fmt"
 	"os"
@@ -99,6 +100,21 @@ func (f *elfFile) goarch() string {
 		return "arm"
 	case elf.EM_PPC64:
 		return "ppc64"
+	case elf.EM_S390:
+		return "s390x"
 	}
 	return ""
 }
+
+func (f *elfFile) loadAddress() (uint64, error) {
+	for _, p := range f.elf.Progs {
+		if p.Type == elf.PT_LOAD {
+			return p.Vaddr, nil
+		}
+	}
+	return 0, fmt.Errorf("unknown load address")
+}
+
+func (f *elfFile) dwarf() (*dwarf.Data, error) {
+	return f.elf.DWARF()
+}
diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go
index 6b1607a..43435ef 100644
--- a/src/cmd/internal/objfile/goobj.go
+++ b/src/cmd/internal/objfile/goobj.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,6 +8,8 @@ package objfile
 
 import (
 	"cmd/internal/goobj"
+	"debug/dwarf"
+	"errors"
 	"fmt"
 	"os"
 )
@@ -41,7 +43,7 @@ func (f *goobjFile) symbols() ([]Sym, error) {
 		switch s.Kind {
 		case goobj.STEXT, goobj.SELFRXSECT:
 			sym.Code = 'T'
-		case goobj.STYPE, goobj.SSTRING, goobj.SGOSTRING, goobj.SGOFUNC, goobj.SRODATA, goobj.SFUNCTAB, goobj.STYPELINK, goobj.SSYMTAB, goobj.SPCLNTAB, goobj.SELFROSECT:
+		case goobj.STYPE, goobj.SSTRING, goobj.SGOSTRING, goobj.SGOFUNC, goobj.SRODATA, goobj.SFUNCTAB, goobj.STYPELINK, goobj.SITABLINK, goobj.SSYMTAB, goobj.SPCLNTAB, goobj.SELFROSECT:
 			sym.Code = 'R'
 		case goobj.SMACHOPLT, goobj.SELFSECT, goobj.SMACHO, goobj.SMACHOGOT, goobj.SNOPTRDATA, goobj.SINITARR, goobj.SDATA, goobj.SWINDOWS:
 			sym.Code = 'D'
@@ -91,3 +93,11 @@ func (f *goobjFile) text() (textStart uint64, text []byte, err error) {
 func (f *goobjFile) goarch() string {
 	return "GOARCH unimplemented for debug/goobj files"
 }
+
+func (f *goobjFile) loadAddress() (uint64, error) {
+	return 0, fmt.Errorf("unknown load address")
+}
+
+func (f *goobjFile) dwarf() (*dwarf.Data, error) {
+	return nil, errors.New("no DWARF data in go object file")
+}
diff --git a/src/cmd/internal/objfile/macho.go b/src/cmd/internal/objfile/macho.go
index 7371c0d..1d22a09 100644
--- a/src/cmd/internal/objfile/macho.go
+++ b/src/cmd/internal/objfile/macho.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,6 +7,7 @@
 package objfile
 
 import (
+	"debug/dwarf"
 	"debug/macho"
 	"fmt"
 	"os"
@@ -123,3 +124,11 @@ type uint64s []uint64
 func (x uint64s) Len() int           { return len(x) }
 func (x uint64s) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
 func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }
+
+func (f *machoFile) loadAddress() (uint64, error) {
+	return 0, fmt.Errorf("unknown load address")
+}
+
+func (f *machoFile) dwarf() (*dwarf.Data, error) {
+	return f.macho.DWARF()
+}
diff --git a/src/cmd/internal/objfile/objfile.go b/src/cmd/internal/objfile/objfile.go
index 9227ef3..e5d99f0 100644
--- a/src/cmd/internal/objfile/objfile.go
+++ b/src/cmd/internal/objfile/objfile.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,6 +6,7 @@
 package objfile
 
 import (
+	"debug/dwarf"
 	"debug/gosym"
 	"fmt"
 	"os"
@@ -17,6 +18,8 @@ type rawFile interface {
 	pcln() (textStart uint64, symtab, pclntab []byte, err error)
 	text() (textStart uint64, text []byte, err error)
 	goarch() string
+	loadAddress() (uint64, error)
+	dwarf() (*dwarf.Data, error)
 }
 
 // A File is an opened executable file.
@@ -92,3 +95,16 @@ func (f *File) Text() (uint64, []byte, error) {
 func (f *File) GOARCH() string {
 	return f.raw.goarch()
 }
+
+// LoadAddress returns the expected load address of the file.
+// This differs from the actual load address for a position-independent
+// executable.
+func (f *File) LoadAddress() (uint64, error) {
+	return f.raw.loadAddress()
+}
+
+// DWARF returns DWARF debug data for the file, if any.
+// This is for cmd/pprof to locate cgo functions.
+func (f *File) DWARF() (*dwarf.Data, error) {
+	return f.raw.dwarf()
+}
diff --git a/src/cmd/internal/objfile/pe.go b/src/cmd/internal/objfile/pe.go
index 67e59c2..46b2317 100644
--- a/src/cmd/internal/objfile/pe.go
+++ b/src/cmd/internal/objfile/pe.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,6 +7,7 @@
 package objfile
 
 import (
+	"debug/dwarf"
 	"debug/pe"
 	"fmt"
 	"os"
@@ -68,8 +69,6 @@ func (f *peFile) symbols() ([]Sym, error) {
 				text  = 0x20
 				data  = 0x40
 				bss   = 0x80
-				permX = 0x20000000
-				permR = 0x40000000
 				permW = 0x80000000
 			)
 			ch := sect.Characteristics
@@ -199,3 +198,11 @@ func (f *peFile) goarch() string {
 	}
 	return ""
 }
+
+func (f *peFile) loadAddress() (uint64, error) {
+	return 0, fmt.Errorf("unknown load address")
+}
+
+func (f *peFile) dwarf() (*dwarf.Data, error) {
+	return f.pe.DWARF()
+}
diff --git a/src/cmd/internal/objfile/plan9obj.go b/src/cmd/internal/objfile/plan9obj.go
index eb6cba5..3e34f65 100644
--- a/src/cmd/internal/objfile/plan9obj.go
+++ b/src/cmd/internal/objfile/plan9obj.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,7 +7,9 @@
 package objfile
 
 import (
+	"debug/dwarf"
 	"debug/plan9obj"
+	"errors"
 	"fmt"
 	"os"
 	"sort"
@@ -57,7 +59,7 @@ func (f *plan9File) symbols() ([]Sym, error) {
 		if !validSymType[s.Type] {
 			continue
 		}
-		sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)}
+		sym := Sym{Addr: s.Value, Name: s.Name, Code: s.Type}
 		i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
 		if i < len(addrs) {
 			sym.Size = int64(addrs[i] - s.Value)
@@ -144,3 +146,11 @@ func (f *plan9File) goarch() string {
 	}
 	return ""
 }
+
+func (f *plan9File) loadAddress() (uint64, error) {
+	return 0, fmt.Errorf("unknown load address")
+}
+
+func (f *plan9File) dwarf() (*dwarf.Data, error) {
+	return nil, errors.New("no DWARF data in Plan 9 file")
+}
diff --git a/src/cmd/internal/pprof/commands/commands.go b/src/cmd/internal/pprof/commands/commands.go
new file mode 100644
index 0000000..5dfbbd4
--- /dev/null
+++ b/src/cmd/internal/pprof/commands/commands.go
@@ -0,0 +1,244 @@
+// 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 commands defines and manages the basic pprof commands
+package commands
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"runtime"
+	"strings"
+	"time"
+
+	"cmd/internal/pprof/plugin"
+	"cmd/internal/pprof/report"
+	"cmd/internal/pprof/svg"
+	"cmd/internal/pprof/tempfile"
+)
+
+// Commands describes the commands accepted by pprof.
+type Commands map[string]*Command
+
+// Command describes the actions for a pprof command. Includes a
+// function for command-line completion, the report format to use
+// during report generation, any postprocessing functions, and whether
+// the command expects a regexp parameter (typically a function name).
+type Command struct {
+	Complete    Completer     // autocomplete for interactive mode
+	Format      int           // report format to generate
+	PostProcess PostProcessor // postprocessing to run on report
+	HasParam    bool          // Collect a parameter from the CLI
+	Usage       string        // Help text
+}
+
+// Completer is a function for command-line autocompletion
+type Completer func(prefix string) string
+
+// PostProcessor is a function that applies post-processing to the report output
+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) Commands {
+	return Commands{
+		// Commands that require no post-processing.
+		"tags":   {nil, report.Tags, nil, false, "Outputs all tags in the profile"},
+		"raw":    {c, report.Raw, nil, false, "Outputs a text representation of the raw profile"},
+		"dot":    {c, report.Dot, nil, false, "Outputs a graph in DOT format"},
+		"top":    {c, report.Text, nil, false, "Outputs top entries in text form"},
+		"tree":   {c, report.Tree, nil, false, "Outputs a text rendering of call graph"},
+		"text":   {c, report.Text, nil, false, "Outputs top entries in text form"},
+		"disasm": {c, report.Dis, nil, true, "Output annotated assembly for functions matching regexp or address"},
+		"list":   {c, report.List, nil, true, "Output annotated source for functions matching regexp"},
+		"peek":   {c, report.Tree, nil, true, "Output callers/callees of functions matching regexp"},
+
+		// Save binary formats to a file
+		"callgrind": {c, report.Callgrind, awayFromTTY("callgraph.out"), false, "Outputs a graph in callgrind format"},
+		"proto":     {c, report.Proto, awayFromTTY("pb.gz"), false, "Outputs the profile in compressed protobuf format"},
+
+		// Generate report in DOT format and postprocess with dot
+		"gif": {c, report.Dot, invokeDot("gif"), false, "Outputs a graph image in GIF format"},
+		"pdf": {c, report.Dot, invokeDot("pdf"), false, "Outputs a graph in PDF format"},
+		"png": {c, report.Dot, invokeDot("png"), false, "Outputs a graph image in PNG format"},
+		"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(), 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(), "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"},
+	}
+}
+
+// browsers returns a list of commands to attempt for web visualization
+// on the current platform
+func browsers() []string {
+	var cmds []string
+	if exe := os.Getenv("BROWSER"); exe != "" {
+		cmds = append(cmds, exe)
+	}
+	switch runtime.GOOS {
+	case "darwin":
+		cmds = append(cmds, "/usr/bin/open")
+	case "windows":
+		cmds = append(cmds, "cmd /c start")
+	default:
+		cmds = append(cmds, "xdg-open")
+	}
+	cmds = append(cmds, "chrome", "google-chrome", "firefox")
+	return cmds
+}
+
+// NewCompleter creates an autocompletion function for a set of commands.
+func NewCompleter(cs Commands) Completer {
+	return func(line string) string {
+		switch tokens := strings.Fields(line); len(tokens) {
+		case 0:
+			// Nothing to complete
+		case 1:
+			// Single token -- complete command name
+			found := ""
+			for c := range cs {
+				if strings.HasPrefix(c, tokens[0]) {
+					if found != "" {
+						return line
+					}
+					found = c
+				}
+			}
+			if found != "" {
+				return found
+			}
+		default:
+			// Multiple tokens -- complete using command completer
+			if c, ok := cs[tokens[0]]; ok {
+				if c.Complete != nil {
+					lastTokenIdx := len(tokens) - 1
+					lastToken := tokens[lastTokenIdx]
+					if strings.HasPrefix(lastToken, "-") {
+						lastToken = "-" + c.Complete(lastToken[1:])
+					} else {
+						lastToken = c.Complete(lastToken)
+					}
+					return strings.Join(append(tokens[:lastTokenIdx], lastToken), " ")
+				}
+			}
+		}
+		return line
+	}
+}
+
+// awayFromTTY saves the output in a file if it would otherwise go to
+// the terminal screen. This is used to avoid dumping binary data on
+// the screen.
+func awayFromTTY(format string) PostProcessor {
+	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
+		if output == os.Stdout && ui.IsTerminal() {
+			tempFile, err := tempfile.New("", "profile", "."+format)
+			if err != nil {
+				return err
+			}
+			ui.PrintErr("Generating report in ", tempFile.Name())
+			_, err = fmt.Fprint(tempFile, input)
+			return err
+		}
+		_, err := fmt.Fprint(output, input)
+		return err
+	}
+}
+
+func invokeDot(format string) PostProcessor {
+	divert := awayFromTTY(format)
+	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
+		if _, err := exec.LookPath("dot"); err != nil {
+			ui.PrintErr("Cannot find dot, have you installed Graphviz?")
+			return err
+		}
+		cmd := exec.Command("dot", "-T"+format)
+		var buf bytes.Buffer
+		cmd.Stdin, cmd.Stdout, cmd.Stderr = input, &buf, os.Stderr
+		if err := cmd.Run(); err != nil {
+			return err
+		}
+		return divert(&buf, output, ui)
+	}
+}
+
+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))
+		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
+	}
+	tempfile.DeferDelete(name)
+	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 {
+		if err := makeVizTmpDir(); err != nil {
+			return err
+		}
+		tempFile, err := tempfile.New(vizTmpDir, "pprof", "."+suffix)
+		if err != nil {
+			return err
+		}
+		tempfile.DeferDelete(tempFile.Name())
+		if err = format(input, tempFile, ui); err != nil {
+			return err
+		}
+		tempFile.Close() // on windows, if the file is Open, start cannot access it.
+		// Try visualizers until one is successful
+		for _, v := range visualizers {
+			// Separate command and arguments for exec.Command.
+			args := strings.Split(v, " ")
+			if len(args) == 0 {
+				continue
+			}
+			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
+					return viewer.Wait()
+				}
+				return nil
+			}
+		}
+		return err
+	}
+}
diff --git a/src/cmd/internal/pprof/driver/driver.go b/src/cmd/internal/pprof/driver/driver.go
new file mode 100644
index 0000000..782acfd
--- /dev/null
+++ b/src/cmd/internal/pprof/driver/driver.go
@@ -0,0 +1,1041 @@
+// 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 driver implements the core pprof functionality. It can be
+// parameterized with a flag implementation, fetch and symbolize
+// mechanisms.
+package driver
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"net/url"
+	"os"
+	"path/filepath"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
+
+	"cmd/internal/pprof/commands"
+	"cmd/internal/pprof/plugin"
+	"cmd/internal/pprof/profile"
+	"cmd/internal/pprof/report"
+	"cmd/internal/pprof/tempfile"
+)
+
+// PProf acquires a profile, and symbolizes it using a profile
+// manager. Then it generates a report formatted according to the
+// options selected through the flags package.
+func PProf(flagset plugin.FlagSet, fetch plugin.Fetcher, sym plugin.Symbolizer, obj plugin.ObjTool, ui plugin.UI, overrides commands.Commands) error {
+	// Remove any temporary files created during pprof processing.
+	defer tempfile.Cleanup()
+
+	f, err := getFlags(flagset, overrides, ui)
+	if err != nil {
+		return err
+	}
+
+	obj.SetConfig(*f.flagTools)
+
+	sources := f.profileSource
+	if len(sources) > 1 {
+		source := sources[0]
+		// If the first argument is a supported object file, treat as executable.
+		if file, err := obj.Open(source, 0); err == nil {
+			file.Close()
+			f.profileExecName = source
+			sources = sources[1:]
+		} else if *f.flagBuildID == "" && isBuildID(source) {
+			f.flagBuildID = &source
+			sources = sources[1:]
+		}
+	}
+
+	// errMu protects concurrent accesses to errset and err. errset is set if an
+	// error is encountered by one of the goroutines grabbing a profile.
+	errMu, errset := sync.Mutex{}, false
+
+	// Fetch profiles.
+	wg := sync.WaitGroup{}
+	profs := make([]*profile.Profile, len(sources))
+	for i, source := range sources {
+		wg.Add(1)
+		go func(i int, src string) {
+			defer wg.Done()
+			p, grabErr := grabProfile(src, f.profileExecName, *f.flagBuildID, fetch, sym, obj, ui, f)
+			if grabErr != nil {
+				errMu.Lock()
+				defer errMu.Unlock()
+				errset, err = true, grabErr
+				return
+			}
+			profs[i] = p
+		}(i, source)
+	}
+	wg.Wait()
+	if errset {
+		return err
+	}
+
+	// Merge profiles.
+	prof := profs[0]
+	for _, p := range profs[1:] {
+		if err = prof.Merge(p, 1); err != nil {
+			return err
+		}
+	}
+
+	if *f.flagBase != "" {
+		// Fetch base profile and subtract from current profile.
+		base, err := grabProfile(*f.flagBase, f.profileExecName, *f.flagBuildID, fetch, sym, obj, ui, f)
+		if err != nil {
+			return err
+		}
+
+		if err = prof.Merge(base, -1); err != nil {
+			return err
+		}
+	}
+
+	if err := processFlags(prof, ui, f); err != nil {
+		return err
+	}
+
+	if !*f.flagRuntime {
+		prof.RemoveUninteresting()
+	}
+
+	if *f.flagInteractive {
+		return interactive(prof, obj, ui, f)
+	}
+
+	return generate(false, prof, obj, ui, f)
+}
+
+// isBuildID determines if the profile may contain a build ID, by
+// checking that it is a string of hex digits.
+func isBuildID(id string) bool {
+	return strings.Trim(id, "0123456789abcdefABCDEF") == ""
+}
+
+// adjustURL updates the profile source URL based on heuristics. It
+// will append ?seconds=sec for CPU profiles if not already
+// specified. Returns the hostname if the profile is remote.
+func adjustURL(source string, sec int, ui plugin.UI) (adjusted, host string, duration time.Duration) {
+	// If there is a local file with this name, just use it.
+	if _, err := os.Stat(source); err == nil {
+		return source, "", 0
+	}
+
+	url, err := url.Parse(source)
+
+	// Automatically add http:// to URLs of the form hostname:port/path.
+	// url.Parse treats "hostname" as the Scheme.
+	if err != nil || (url.Host == "" && url.Scheme != "" && url.Scheme != "file") {
+		url, err = url.Parse("http://" + source)
+		if err != nil {
+			return source, "", 0
+		}
+	}
+	if scheme := strings.ToLower(url.Scheme); scheme == "" || scheme == "file" {
+		url.Scheme = ""
+		return url.String(), "", 0
+	}
+
+	values := url.Query()
+	if urlSeconds := values.Get("seconds"); urlSeconds != "" {
+		if us, err := strconv.ParseInt(urlSeconds, 10, 32); err == nil {
+			if sec >= 0 {
+				ui.PrintErr("Overriding -seconds for URL ", source)
+			}
+			sec = int(us)
+		}
+	}
+
+	switch strings.ToLower(url.Path) {
+	case "", "/":
+		// Apply default /profilez.
+		url.Path = "/profilez"
+	case "/protoz":
+		// Rewrite to /profilez?type=proto
+		url.Path = "/profilez"
+		values.Set("type", "proto")
+	}
+
+	if hasDuration(url.Path) {
+		if sec > 0 {
+			duration = time.Duration(sec) * time.Second
+			values.Set("seconds", fmt.Sprintf("%d", sec))
+		} else {
+			// Assume default duration: 30 seconds
+			duration = 30 * time.Second
+		}
+	}
+	url.RawQuery = values.Encode()
+	return url.String(), url.Host, duration
+}
+
+func hasDuration(path string) bool {
+	for _, trigger := range []string{"profilez", "wallz", "/profile"} {
+		if strings.Contains(path, trigger) {
+			return true
+		}
+	}
+	return false
+}
+
+// preprocess does filtering and aggregation of a profile based on the
+// requested options.
+func preprocess(prof *profile.Profile, ui plugin.UI, f *flags) error {
+	if *f.flagFocus != "" || *f.flagIgnore != "" || *f.flagHide != "" {
+		focus, ignore, hide, err := compileFocusIgnore(*f.flagFocus, *f.flagIgnore, *f.flagHide)
+		if err != nil {
+			return err
+		}
+		fm, im, hm := prof.FilterSamplesByName(focus, ignore, hide)
+
+		warnNoMatches(fm, *f.flagFocus, "Focus", ui)
+		warnNoMatches(im, *f.flagIgnore, "Ignore", ui)
+		warnNoMatches(hm, *f.flagHide, "Hide", ui)
+	}
+
+	if *f.flagTagFocus != "" || *f.flagTagIgnore != "" {
+		focus, err := compileTagFilter(*f.flagTagFocus, ui)
+		if err != nil {
+			return err
+		}
+		ignore, err := compileTagFilter(*f.flagTagIgnore, ui)
+		if err != nil {
+			return err
+		}
+		fm, im := prof.FilterSamplesByTag(focus, ignore)
+
+		warnNoMatches(fm, *f.flagTagFocus, "TagFocus", ui)
+		warnNoMatches(im, *f.flagTagIgnore, "TagIgnore", ui)
+	}
+
+	return aggregate(prof, f)
+}
+
+func compileFocusIgnore(focus, ignore, hide string) (f, i, h *regexp.Regexp, err error) {
+	if focus != "" {
+		if f, err = regexp.Compile(focus); err != nil {
+			return nil, nil, nil, fmt.Errorf("parsing focus regexp: %v", err)
+		}
+	}
+
+	if ignore != "" {
+		if i, err = regexp.Compile(ignore); err != nil {
+			return nil, nil, nil, fmt.Errorf("parsing ignore regexp: %v", err)
+		}
+	}
+
+	if hide != "" {
+		if h, err = regexp.Compile(hide); err != nil {
+			return nil, nil, nil, fmt.Errorf("parsing hide regexp: %v", err)
+		}
+	}
+	return
+}
+
+func compileTagFilter(filter string, ui plugin.UI) (f func(string, string, int64) bool, err error) {
+	if filter == "" {
+		return nil, nil
+	}
+	if numFilter := parseTagFilterRange(filter); numFilter != nil {
+		ui.PrintErr("Interpreted '", filter, "' as range, not regexp")
+		return func(key, val string, num int64) bool {
+			if val != "" {
+				return false
+			}
+			return numFilter(num, key)
+		}, nil
+	}
+	fx, err := regexp.Compile(filter)
+	if err != nil {
+		return nil, err
+	}
+
+	return func(key, val string, num int64) bool {
+		if val == "" {
+			return false
+		}
+		return fx.MatchString(key + ":" + val)
+	}, nil
+}
+
+var tagFilterRangeRx = regexp.MustCompile("([[:digit:]]+)([[:alpha:]]+)")
+
+// parseTagFilterRange returns a function to checks if a value is
+// contained on the range described by a string. It can recognize
+// strings of the form:
+// "32kb" -- matches values == 32kb
+// ":64kb" -- matches values <= 64kb
+// "4mb:" -- matches values >= 4mb
+// "12kb:64mb" -- matches values between 12kb and 64mb (both included).
+func parseTagFilterRange(filter string) func(int64, string) bool {
+	ranges := tagFilterRangeRx.FindAllStringSubmatch(filter, 2)
+	if len(ranges) == 0 {
+		return nil // No ranges were identified
+	}
+	v, err := strconv.ParseInt(ranges[0][1], 10, 64)
+	if err != nil {
+		panic(fmt.Errorf("Failed to parse int %s: %v", ranges[0][1], err))
+	}
+	value, unit := report.ScaleValue(v, ranges[0][2], ranges[0][2])
+	if len(ranges) == 1 {
+		switch match := ranges[0][0]; filter {
+		case match:
+			return func(v int64, u string) bool {
+				sv, su := report.ScaleValue(v, u, unit)
+				return su == unit && sv == value
+			}
+		case match + ":":
+			return func(v int64, u string) bool {
+				sv, su := report.ScaleValue(v, u, unit)
+				return su == unit && sv >= value
+			}
+		case ":" + match:
+			return func(v int64, u string) bool {
+				sv, su := report.ScaleValue(v, u, unit)
+				return su == unit && sv <= value
+			}
+		}
+		return nil
+	}
+	if filter != ranges[0][0]+":"+ranges[1][0] {
+		return nil
+	}
+	if v, err = strconv.ParseInt(ranges[1][1], 10, 64); err != nil {
+		panic(fmt.Errorf("Failed to parse int %s: %v", ranges[1][1], err))
+	}
+	value2, unit2 := report.ScaleValue(v, ranges[1][2], unit)
+	if unit != unit2 {
+		return nil
+	}
+	return func(v int64, u string) bool {
+		sv, su := report.ScaleValue(v, u, unit)
+		return su == unit && sv >= value && sv <= value2
+	}
+}
+
+func warnNoMatches(match bool, rx, option string, ui plugin.UI) {
+	if !match && rx != "" && rx != "." {
+		ui.PrintErr(option + " expression matched no samples: " + rx)
+	}
+}
+
+// grabProfile fetches and symbolizes a profile.
+func grabProfile(source, exec, buildid string, fetch plugin.Fetcher, sym plugin.Symbolizer, obj plugin.ObjTool, ui plugin.UI, f *flags) (*profile.Profile, error) {
+	source, host, duration := adjustURL(source, *f.flagSeconds, ui)
+	remote := host != ""
+
+	if remote {
+		ui.Print("Fetching profile from ", source)
+		if duration != 0 {
+			ui.Print("Please wait... (" + duration.String() + ")")
+		}
+	}
+
+	now := time.Now()
+	// Fetch profile from source.
+	// Give 50% slack on the timeout.
+	p, err := fetch(source, duration+duration/2, ui)
+	if err != nil {
+		return nil, err
+	}
+
+	// Update the time/duration if the profile source doesn't include it.
+	// TODO(rsilvera): Remove this when we remove support for legacy profiles.
+	if remote {
+		if p.TimeNanos == 0 {
+			p.TimeNanos = now.UnixNano()
+		}
+		if duration != 0 && p.DurationNanos == 0 {
+			p.DurationNanos = int64(duration)
+		}
+	}
+
+	// Replace executable/buildID with the options provided in the
+	// command line. Assume the executable is the first Mapping entry.
+	if exec != "" || buildid != "" {
+		if len(p.Mapping) == 0 {
+			// Create a fake mapping to hold the user option, and associate
+			// all samples to it.
+			m := &profile.Mapping{
+				ID: 1,
+			}
+			for _, l := range p.Location {
+				l.Mapping = m
+			}
+			p.Mapping = []*profile.Mapping{m}
+		}
+		if exec != "" {
+			p.Mapping[0].File = exec
+		}
+		if buildid != "" {
+			p.Mapping[0].BuildID = buildid
+		}
+	}
+
+	if err := sym(*f.flagSymbolize, source, p, obj, ui); err != nil {
+		return nil, err
+	}
+
+	// Save a copy of any remote profiles, unless the user is explicitly
+	// saving it.
+	if remote && !f.isFormat("proto") {
+		prefix := "pprof."
+		if len(p.Mapping) > 0 && p.Mapping[0].File != "" {
+			prefix = prefix + filepath.Base(p.Mapping[0].File) + "."
+		}
+		if !strings.ContainsRune(host, os.PathSeparator) {
+			prefix = prefix + host + "."
+		}
+		for _, s := range p.SampleType {
+			prefix = prefix + s.Type + "."
+		}
+
+		dir := os.Getenv("PPROF_TMPDIR")
+		tempFile, err := tempfile.New(dir, prefix, ".pb.gz")
+		if err == nil {
+			if err = p.Write(tempFile); err == nil {
+				ui.PrintErr("Saved profile in ", tempFile.Name())
+			}
+		}
+		if err != nil {
+			ui.PrintErr("Could not save profile: ", err)
+		}
+	}
+
+	if err := p.Demangle(obj.Demangle); err != nil {
+		ui.PrintErr("Failed to demangle profile: ", err)
+	}
+
+	if err := p.CheckValid(); err != nil {
+		return nil, fmt.Errorf("Grab %s: %v", source, err)
+	}
+
+	return p, nil
+}
+
+type flags struct {
+	flagInteractive   *bool              // Accept commands interactively
+	flagCommands      map[string]*bool   // pprof commands without parameters
+	flagParamCommands map[string]*string // pprof commands with parameters
+
+	flagOutput *string // Output file name
+
+	flagCum      *bool // Sort by cumulative data
+	flagCallTree *bool // generate a context-sensitive call tree
+
+	flagAddresses *bool // Report at address level
+	flagLines     *bool // Report at source line level
+	flagFiles     *bool // Report at file level
+	flagFunctions *bool // Report at function level [default]
+
+	flagSymbolize *string // Symbolization options (=none to disable)
+	flagBuildID   *string // Override build if for first mapping
+
+	flagNodeCount    *int     // Max number of nodes to show
+	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
+	flagTagFocus     *string  // Restrict to samples tagged with key:value matching regexp
+	flagTagIgnore    *string  // Discard samples tagged with key:value matching regexp
+	flagDropNegative *bool    // Skip negative values
+
+	flagBase *string // Source for base profile to user for comparison
+
+	flagSeconds *int // Length of time for dynamic profiles
+
+	flagTotalDelay  *bool // Display total delay at each region
+	flagContentions *bool // Display number of delays at each region
+	flagMeanDelay   *bool // Display mean delay at each region
+
+	flagInUseSpace   *bool    // Display in-use memory size
+	flagInUseObjects *bool    // Display in-use object counts
+	flagAllocSpace   *bool    // Display allocated memory size
+	flagAllocObjects *bool    // Display allocated object counts
+	flagDisplayUnit  *string  // Measurement unit to use on reports
+	flagDivideBy     *float64 // Ratio to divide sample values
+
+	flagSampleIndex *int  // Sample value to use in reports.
+	flagMean        *bool // Use mean of sample_index over count
+
+	flagTools       *string
+	profileSource   []string
+	profileExecName string
+
+	extraUsage string
+	commands   commands.Commands
+}
+
+func (f *flags) isFormat(format string) bool {
+	if fl := f.flagCommands[format]; fl != nil {
+		return *fl
+	}
+	if fl := f.flagParamCommands[format]; fl != nil {
+		return *fl != ""
+	}
+	return false
+}
+
+// String provides a printable representation for the current set of flags.
+func (f *flags) String(p *profile.Profile) string {
+	var ret string
+
+	if ix := *f.flagSampleIndex; ix != -1 {
+		ret += fmt.Sprintf("  %-25s : %d (%s)\n", "sample_index", ix, p.SampleType[ix].Type)
+	}
+	if ix := *f.flagMean; ix {
+		ret += boolFlagString("mean")
+	}
+	if *f.flagDisplayUnit != "minimum" {
+		ret += stringFlagString("unit", *f.flagDisplayUnit)
+	}
+
+	switch {
+	case *f.flagInteractive:
+		ret += boolFlagString("interactive")
+	}
+	for name, fl := range f.flagCommands {
+		if *fl {
+			ret += boolFlagString(name)
+		}
+	}
+
+	if *f.flagCum {
+		ret += boolFlagString("cum")
+	}
+	if *f.flagCallTree {
+		ret += boolFlagString("call_tree")
+	}
+
+	switch {
+	case *f.flagAddresses:
+		ret += boolFlagString("addresses")
+	case *f.flagLines:
+		ret += boolFlagString("lines")
+	case *f.flagFiles:
+		ret += boolFlagString("files")
+	case *f.flagFunctions:
+		ret += boolFlagString("functions")
+	}
+
+	if *f.flagNodeCount != -1 {
+		ret += intFlagString("nodecount", *f.flagNodeCount)
+	}
+
+	ret += floatFlagString("nodefraction", *f.flagNodeFraction)
+	ret += floatFlagString("edgefraction", *f.flagEdgeFraction)
+
+	if *f.flagFocus != "" {
+		ret += stringFlagString("focus", *f.flagFocus)
+	}
+	if *f.flagIgnore != "" {
+		ret += stringFlagString("ignore", *f.flagIgnore)
+	}
+	if *f.flagHide != "" {
+		ret += stringFlagString("hide", *f.flagHide)
+	}
+
+	if *f.flagTagFocus != "" {
+		ret += stringFlagString("tagfocus", *f.flagTagFocus)
+	}
+	if *f.flagTagIgnore != "" {
+		ret += stringFlagString("tagignore", *f.flagTagIgnore)
+	}
+
+	return ret
+}
+
+func boolFlagString(label string) string {
+	return fmt.Sprintf("  %-25s : true\n", label)
+}
+
+func stringFlagString(label, value string) string {
+	return fmt.Sprintf("  %-25s : %s\n", label, value)
+}
+
+func intFlagString(label string, value int) string {
+	return fmt.Sprintf("  %-25s : %d\n", label, value)
+}
+
+func floatFlagString(label string, value float64) string {
+	return fmt.Sprintf("  %-25s : %f\n", label, value)
+}
+
+// Utility routines to set flag values.
+func newBool(b bool) *bool {
+	return &b
+}
+
+func newString(s string) *string {
+	return &s
+}
+
+func newFloat64(fl float64) *float64 {
+	return &fl
+}
+
+func newInt(i int) *int {
+	return &i
+}
+
+func (f *flags) usage(ui plugin.UI) {
+	var commandMsg []string
+	for name, cmd := range f.commands {
+		if cmd.HasParam {
+			name = name + "=p"
+		}
+		commandMsg = append(commandMsg,
+			fmt.Sprintf("  -%-16s %s", name, cmd.Usage))
+	}
+
+	sort.Strings(commandMsg)
+
+	text := usageMsgHdr + strings.Join(commandMsg, "\n") + "\n" + usageMsg + "\n"
+	if f.extraUsage != "" {
+		text += f.extraUsage + "\n"
+	}
+	text += usageMsgVars
+	ui.Print(text)
+}
+
+func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*flags, error) {
+	f := &flags{
+		flagInteractive:   flag.Bool("interactive", false, "Accepts commands interactively"),
+		flagCommands:      make(map[string]*bool),
+		flagParamCommands: make(map[string]*string),
+
+		// Filename for file-based output formats, stdout by default.
+		flagOutput: flag.String("output", "", "Output filename for file-based outputs "),
+		// Comparisons.
+		flagBase:         flag.String("base", "", "Source for base profile for comparison"),
+		flagDropNegative: flag.Bool("drop_negative", false, "Ignore negative differences"),
+
+		// Data sorting criteria.
+		flagCum: flag.Bool("cum", false, "Sort by cumulative data"),
+		// Graph handling options.
+		flagCallTree: flag.Bool("call_tree", false, "Create a context-sensitive call tree"),
+		// Granularity of output resolution.
+		flagAddresses: flag.Bool("addresses", false, "Report at address level"),
+		flagLines:     flag.Bool("lines", false, "Report at source line level"),
+		flagFiles:     flag.Bool("files", false, "Report at source file level"),
+		flagFunctions: flag.Bool("functions", false, "Report at function level [default]"),
+		// Internal options.
+		flagSymbolize: flag.String("symbolize", "", "Options for profile symbolization"),
+		flagBuildID:   flag.String("buildid", "", "Override build id for first mapping"),
+		// Filtering options
+		flagNodeCount:    flag.Int("nodecount", -1, "Max number of nodes to show"),
+		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"),
+		flagTagFocus:     flag.String("tagfocus", "", "Restrict to samples with tags in range or matched by regexp"),
+		flagTagIgnore:    flag.String("tagignore", "", "Discard samples with tags in range or matched by regexp"),
+		// CPU profile options
+		flagSeconds: flag.Int("seconds", -1, "Length of time for dynamic profiles"),
+		// Heap profile options
+		flagInUseSpace:   flag.Bool("inuse_space", false, "Display in-use memory size"),
+		flagInUseObjects: flag.Bool("inuse_objects", false, "Display in-use object counts"),
+		flagAllocSpace:   flag.Bool("alloc_space", false, "Display allocated memory size"),
+		flagAllocObjects: flag.Bool("alloc_objects", false, "Display allocated object counts"),
+		flagDisplayUnit:  flag.String("unit", "minimum", "Measurement units to display"),
+		flagDivideBy:     flag.Float64("divide_by", 1.0, "Ratio to divide all samples before visualization"),
+		flagSampleIndex:  flag.Int("sample_index", -1, "Index of sample value to report"),
+		flagMean:         flag.Bool("mean", false, "Average sample value over first value (count)"),
+		// Contention profile options
+		flagTotalDelay:  flag.Bool("total_delay", false, "Display total delay at each region"),
+		flagContentions: flag.Bool("contentions", false, "Display number of delays at each region"),
+		flagMeanDelay:   flag.Bool("mean_delay", false, "Display mean delay at each region"),
+		flagTools:       flag.String("tools", os.Getenv("PPROF_TOOLS"), "Path for object tool pathnames"),
+		extraUsage:      flag.ExtraUsage(),
+	}
+
+	// Flags used during command processing
+	interactive := &f.flagInteractive
+	f.commands = commands.PProf(functionCompleter, interactive)
+
+	// Override commands
+	for name, cmd := range overrides {
+		f.commands[name] = cmd
+	}
+
+	for name, cmd := range f.commands {
+		if cmd.HasParam {
+			f.flagParamCommands[name] = flag.String(name, "", "Generate a report in "+name+" format, matching regexp")
+		} else {
+			f.flagCommands[name] = flag.Bool(name, false, "Generate a report in "+name+" format")
+		}
+	}
+
+	args := flag.Parse(func() { f.usage(ui) })
+	if len(args) == 0 {
+		return nil, fmt.Errorf("no profile source specified")
+	}
+
+	f.profileSource = args
+
+	// Instruct legacy heapz parsers to grab historical allocation data,
+	// instead of the default in-use data. Not available with tcmalloc.
+	if *f.flagAllocSpace || *f.flagAllocObjects {
+		profile.LegacyHeapAllocated = true
+	}
+
+	if profileDir := os.Getenv("PPROF_TMPDIR"); profileDir == "" {
+		profileDir = os.Getenv("HOME") + "/pprof"
+		os.Setenv("PPROF_TMPDIR", profileDir)
+		if err := os.MkdirAll(profileDir, 0755); err != nil {
+			return nil, fmt.Errorf("failed to access temp dir %s: %v", profileDir, err)
+		}
+	}
+
+	return f, nil
+}
+
+func processFlags(p *profile.Profile, ui plugin.UI, f *flags) error {
+	flagDis := f.isFormat("disasm")
+	flagPeek := f.isFormat("peek")
+	flagWebList := f.isFormat("weblist")
+	flagList := f.isFormat("list")
+
+	if flagDis || flagWebList {
+		// Collect all samples at address granularity for assembly
+		// listing.
+		f.flagNodeCount = newInt(0)
+		f.flagAddresses = newBool(true)
+		f.flagLines = newBool(false)
+		f.flagFiles = newBool(false)
+		f.flagFunctions = newBool(false)
+	}
+
+	if flagPeek {
+		// Collect all samples at function granularity for peek command
+		f.flagNodeCount = newInt(0)
+		f.flagAddresses = newBool(false)
+		f.flagLines = newBool(false)
+		f.flagFiles = newBool(false)
+		f.flagFunctions = newBool(true)
+	}
+
+	if flagList {
+		// Collect all samples at fileline granularity for source
+		// listing.
+		f.flagNodeCount = newInt(0)
+		f.flagAddresses = newBool(false)
+		f.flagLines = newBool(true)
+		f.flagFiles = newBool(false)
+		f.flagFunctions = newBool(false)
+	}
+
+	if !*f.flagTrim {
+		f.flagNodeCount = newInt(0)
+		f.flagNodeFraction = newFloat64(0)
+		f.flagEdgeFraction = newFloat64(0)
+	}
+
+	if oc := countFlagMap(f.flagCommands, f.flagParamCommands); oc == 0 {
+		f.flagInteractive = newBool(true)
+	} else if oc > 1 {
+		f.usage(ui)
+		return fmt.Errorf("must set at most one output format")
+	}
+
+	// Apply nodecount defaults for non-interactive mode. The
+	// interactive shell will apply defaults for the interactive mode.
+	if *f.flagNodeCount < 0 && !*f.flagInteractive {
+		switch {
+		default:
+			f.flagNodeCount = newInt(80)
+		case f.isFormat("text"):
+			f.flagNodeCount = newInt(0)
+		}
+	}
+
+	// Apply legacy options and diagnose conflicts.
+	if rc := countFlags([]*bool{f.flagAddresses, f.flagLines, f.flagFiles, f.flagFunctions}); rc == 0 {
+		f.flagFunctions = newBool(true)
+	} else if rc > 1 {
+		f.usage(ui)
+		return fmt.Errorf("must set at most one granularity option")
+	}
+
+	var err error
+	si, sm := *f.flagSampleIndex, *f.flagMean || *f.flagMeanDelay
+	si, err = sampleIndex(p, &f.flagTotalDelay, si, 1, "delay", "-total_delay", err)
+	si, err = sampleIndex(p, &f.flagMeanDelay, si, 1, "delay", "-mean_delay", err)
+	si, err = sampleIndex(p, &f.flagContentions, si, 0, "contentions", "-contentions", err)
+
+	si, err = sampleIndex(p, &f.flagInUseSpace, si, 1, "inuse_space", "-inuse_space", err)
+	si, err = sampleIndex(p, &f.flagInUseObjects, si, 0, "inuse_objects", "-inuse_objects", err)
+	si, err = sampleIndex(p, &f.flagAllocSpace, si, 1, "alloc_space", "-alloc_space", err)
+	si, err = sampleIndex(p, &f.flagAllocObjects, si, 0, "alloc_objects", "-alloc_objects", err)
+
+	if si == -1 {
+		// Use last value if none is requested.
+		si = len(p.SampleType) - 1
+	} else if si < 0 || si >= len(p.SampleType) {
+		err = fmt.Errorf("sample_index value %d out of range [0..%d]", si, len(p.SampleType)-1)
+	}
+
+	if err != nil {
+		f.usage(ui)
+		return err
+	}
+	f.flagSampleIndex, f.flagMean = newInt(si), newBool(sm)
+	return nil
+}
+
+func sampleIndex(p *profile.Profile, flag **bool,
+	sampleIndex int,
+	newSampleIndex int,
+	sampleType, option string,
+	err error) (int, error) {
+	if err != nil || !**flag {
+		return sampleIndex, err
+	}
+	*flag = newBool(false)
+	if sampleIndex != -1 {
+		return 0, fmt.Errorf("set at most one sample value selection option")
+	}
+	if newSampleIndex >= len(p.SampleType) ||
+		p.SampleType[newSampleIndex].Type != sampleType {
+		return 0, fmt.Errorf("option %s not valid for this profile", option)
+	}
+	return newSampleIndex, nil
+}
+
+func countFlags(bs []*bool) int {
+	var c int
+	for _, b := range bs {
+		if *b {
+			c++
+		}
+	}
+	return c
+}
+
+func countFlagMap(bms map[string]*bool, bmrxs map[string]*string) int {
+	var c int
+	for _, b := range bms {
+		if *b {
+			c++
+		}
+	}
+	for _, s := range bmrxs {
+		if *s != "" {
+			c++
+		}
+	}
+	return c
+}
+
+var usageMsgHdr = "usage: pprof [options] [binary] <profile source> ...\n" +
+	"Output format (only set one):\n"
+
+var usageMsg = "Output file parameters (for file-based output formats):\n" +
+	"  -output=f         Generate output on file f (stdout by default)\n" +
+	"Output granularity (only set one):\n" +
+	"  -functions        Report at function level [default]\n" +
+	"  -files            Report at source file level\n" +
+	"  -lines            Report at source line level\n" +
+	"  -addresses        Report at address level\n" +
+	"Comparison options:\n" +
+	"  -base <profile>   Show delta from this profile\n" +
+	"  -drop_negative    Ignore negative differences\n" +
+	"Sorting options:\n" +
+	"  -cum              Sort by cumulative data\n\n" +
+	"Dynamic profile options:\n" +
+	"  -seconds=N        Length of time for dynamic profiles\n" +
+	"Profile trimming options:\n" +
+	"  -nodecount=N      Max number of nodes to show\n" +
+	"  -nodefraction=f   Hide nodes below <f>*total\n" +
+	"  -edgefraction=f   Hide edges below <f>*total\n" +
+	"Sample value selection option (by index):\n" +
+	"  -sample_index      Index of sample value to display\n" +
+	"  -mean              Average sample value over first value\n" +
+	"Sample value selection option (for heap profiles):\n" +
+	"  -inuse_space      Display in-use memory size\n" +
+	"  -inuse_objects    Display in-use object counts\n" +
+	"  -alloc_space      Display allocated memory size\n" +
+	"  -alloc_objects    Display allocated object counts\n" +
+	"Sample value selection option (for contention profiles):\n" +
+	"  -total_delay      Display total delay at each region\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" +
+	"                    Restrict to samples with numeric tags in range (eg \"32kb:1mb\")\n" +
+	"  -tagignore=r      Discard samples tagged with key:value matching regexp\n" +
+	"                    Avoid samples with numeric tags in range (eg \"1mb:\")\n" +
+	"Miscellaneous:\n" +
+	"  -call_tree        Generate a context-sensitive call tree\n" +
+	"  -unit=u           Convert all samples to unit u for display\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 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" +
+	"                      finds binaries by $name and $buildid/$name"
+
+func aggregate(prof *profile.Profile, f *flags) error {
+	switch {
+	case f.isFormat("proto"), f.isFormat("raw"):
+		// No aggregation for raw profiles.
+	case f.isFormat("callgrind"):
+		// Aggregate to file/line for callgrind.
+		fallthrough
+	case *f.flagLines:
+		return prof.Aggregate(true, true, true, true, false)
+	case *f.flagFiles:
+		return prof.Aggregate(true, false, true, false, false)
+	case *f.flagFunctions:
+		return prof.Aggregate(true, true, false, false, false)
+	case f.isFormat("weblist"), f.isFormat("disasm"):
+		return prof.Aggregate(false, true, true, true, true)
+	}
+	return nil
+}
+
+// parseOptions parses the options into report.Options
+// Returns a function to postprocess the report after generation.
+func parseOptions(f *flags) (o *report.Options, p commands.PostProcessor, err error) {
+
+	if *f.flagDivideBy == 0 {
+		return nil, nil, fmt.Errorf("zero divisor specified")
+	}
+
+	o = &report.Options{
+		CumSort:        *f.flagCum,
+		CallTree:       *f.flagCallTree,
+		PrintAddresses: *f.flagAddresses,
+		DropNegative:   *f.flagDropNegative,
+		Ratio:          1 / *f.flagDivideBy,
+
+		NodeCount:    *f.flagNodeCount,
+		NodeFraction: *f.flagNodeFraction,
+		EdgeFraction: *f.flagEdgeFraction,
+		OutputUnit:   *f.flagDisplayUnit,
+	}
+
+	for cmd, b := range f.flagCommands {
+		if *b {
+			pcmd := f.commands[cmd]
+			o.OutputFormat = pcmd.Format
+			return o, pcmd.PostProcess, nil
+		}
+	}
+
+	for cmd, rx := range f.flagParamCommands {
+		if *rx != "" {
+			pcmd := f.commands[cmd]
+			if o.Symbol, err = regexp.Compile(*rx); err != nil {
+				return nil, nil, fmt.Errorf("parsing -%s regexp: %v", cmd, err)
+			}
+			o.OutputFormat = pcmd.Format
+			return o, pcmd.PostProcess, nil
+		}
+	}
+
+	return nil, nil, fmt.Errorf("no output format selected")
+}
+
+type sampleValueFunc func(*profile.Sample) int64
+
+// sampleFormat returns a function to extract values out of a profile.Sample,
+// and the type/units of those values.
+func sampleFormat(p *profile.Profile, f *flags) (sampleValueFunc, string, string) {
+	valueIndex := *f.flagSampleIndex
+
+	if *f.flagMean {
+		return meanExtractor(valueIndex), "mean_" + p.SampleType[valueIndex].Type, p.SampleType[valueIndex].Unit
+	}
+
+	return valueExtractor(valueIndex), p.SampleType[valueIndex].Type, p.SampleType[valueIndex].Unit
+}
+
+func valueExtractor(ix int) sampleValueFunc {
+	return func(s *profile.Sample) int64 {
+		return s.Value[ix]
+	}
+}
+
+func meanExtractor(ix int) sampleValueFunc {
+	return func(s *profile.Sample) int64 {
+		if s.Value[0] == 0 {
+			return 0
+		}
+		return s.Value[ix] / s.Value[0]
+	}
+}
+
+func generate(interactive bool, prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, f *flags) error {
+	o, postProcess, err := parseOptions(f)
+	if err != nil {
+		return err
+	}
+
+	var w io.Writer
+	if *f.flagOutput == "" {
+		w = os.Stdout
+	} else {
+		ui.PrintErr("Generating report in ", *f.flagOutput)
+		outputFile, err := os.Create(*f.flagOutput)
+		if err != nil {
+			return err
+		}
+		defer outputFile.Close()
+		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)
+
+	// Do not apply filters if we're just generating a proto, so we
+	// still have all the data.
+	if o.OutputFormat != report.Proto {
+		// Delay applying focus/ignore until after creating the report so
+		// the report reflects the total number of samples.
+		if err := preprocess(prof, ui, f); err != nil {
+			return err
+		}
+	}
+
+	if postProcess == nil {
+		return report.Generate(w, rpt, obj)
+	}
+
+	var dot bytes.Buffer
+	if err = report.Generate(&dot, rpt, obj); err != nil {
+		return err
+	}
+
+	return postProcess(&dot, w, ui)
+}
diff --git a/src/cmd/internal/pprof/driver/interactive.go b/src/cmd/internal/pprof/driver/interactive.go
new file mode 100644
index 0000000..1b08226
--- /dev/null
+++ b/src/cmd/internal/pprof/driver/interactive.go
@@ -0,0 +1,492 @@
+// 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 driver
+
+import (
+	"fmt"
+	"io"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+
+	"cmd/internal/pprof/commands"
+	"cmd/internal/pprof/plugin"
+	"cmd/internal/pprof/profile"
+)
+
+var profileFunctionNames = []string{}
+
+// functionCompleter replaces provided substring with a function
+// name retrieved from a profile if a single match exists. Otherwise,
+// it returns unchanged substring. It defaults to no-op if the profile
+// is not specified.
+func functionCompleter(substring string) string {
+	found := ""
+	for _, fName := range profileFunctionNames {
+		if strings.Contains(fName, substring) {
+			if found != "" {
+				return substring
+			}
+			found = fName
+		}
+	}
+	if found != "" {
+		return found
+	}
+	return substring
+}
+
+// updateAutoComplete enhances autocompletion with information that can be
+// retrieved from the profile
+func updateAutoComplete(p *profile.Profile) {
+	profileFunctionNames = nil // remove function names retrieved previously
+	for _, fn := range p.Function {
+		profileFunctionNames = append(profileFunctionNames, fn.Name)
+	}
+}
+
+// splitCommand splits the command line input into tokens separated by
+// spaces. Takes care to separate commands of the form 'top10' into
+// two tokens: 'top' and '10'
+func splitCommand(input string) []string {
+	fields := strings.Fields(input)
+	if num := strings.IndexAny(fields[0], "0123456789"); num != -1 {
+		inputNumber := fields[0][num:]
+		fields[0] = fields[0][:num]
+		fields = append([]string{fields[0], inputNumber}, fields[1:]...)
+	}
+	return fields
+}
+
+// interactive displays a prompt and reads commands for profile
+// manipulation/visualization.
+func interactive(p *profile.Profile, obj plugin.ObjTool, ui plugin.UI, f *flags) error {
+	updateAutoComplete(p)
+
+	// Enter command processing loop.
+	ui.Print("Entering interactive mode (type \"help\" for commands)")
+	ui.SetAutoComplete(commands.NewCompleter(f.commands))
+
+	for {
+		input, err := readCommand(p, ui, f)
+		if err != nil {
+			if err != io.EOF {
+				return err
+			}
+			if input == "" {
+				return nil
+			}
+		}
+		// Process simple commands.
+		switch input {
+		case "":
+			continue
+		case ":":
+			f.flagFocus = newString("")
+			f.flagIgnore = newString("")
+			f.flagTagFocus = newString("")
+			f.flagTagIgnore = newString("")
+			f.flagHide = newString("")
+			continue
+		}
+
+		fields := splitCommand(input)
+		// Process report generation commands.
+		if _, ok := f.commands[fields[0]]; ok {
+			if err := generateReport(p, fields, obj, ui, f); err != nil {
+				if err == io.EOF {
+					return nil
+				}
+				ui.PrintErr(err)
+			}
+			continue
+		}
+
+		switch cmd := fields[0]; cmd {
+		case "help":
+			commandHelp(fields, ui, f)
+			continue
+		case "exit", "quit":
+			return nil
+		}
+
+		// Process option settings.
+		if of, err := optFlags(p, input, f); err == nil {
+			f = of
+		} else {
+			ui.PrintErr("Error: ", err.Error())
+		}
+	}
+}
+
+func generateReport(p *profile.Profile, cmd []string, obj plugin.ObjTool, ui plugin.UI, f *flags) error {
+	prof := p.Copy()
+
+	cf, err := cmdFlags(prof, cmd, ui, f)
+	if err != nil {
+		return err
+	}
+
+	return generate(true, prof, obj, ui, cf)
+}
+
+// validateRegex checks if a string is a valid regular expression.
+func validateRegex(v string) error {
+	_, err := regexp.Compile(v)
+	return err
+}
+
+// readCommand prompts for and reads the next command.
+func readCommand(p *profile.Profile, ui plugin.UI, f *flags) (string, error) {
+	//ui.Print("Options:\n", f.String(p))
+	s, err := ui.ReadLine()
+	return strings.TrimSpace(s), err
+}
+
+func commandHelp(_ []string, ui plugin.UI, f *flags) error {
+	help := `
+ Commands:
+   cmd [n] [--cum] [focus_regex]* [-ignore_regex]*
+       Produce a text report with the top n entries.
+       Include samples matching focus_regex, and exclude ignore_regex.
+       Add --cum to sort using cumulative data.
+       Available commands:
+`
+	var commands []string
+	for name, cmd := range f.commands {
+		commands = append(commands, fmt.Sprintf("         %-12s %s", name, cmd.Usage))
+	}
+	sort.Strings(commands)
+
+	help = help + strings.Join(commands, "\n") + `
+   peek func_regex
+       Display callers and callees of functions matching func_regex.
+
+   dot [n] [focus_regex]* [-ignore_regex]* [>file]
+       Produce an annotated callgraph with the top n entries.
+       Include samples matching focus_regex, and exclude ignore_regex.
+       For other outputs, replace dot with:
+       - Graphic formats: dot, svg, pdf, ps, gif, png (use > to name output file)
+       - Graph viewer:    gv, web, evince, eog
+
+   callgrind [n] [focus_regex]* [-ignore_regex]* [>file]
+       Produce a file in callgrind-compatible format.
+       Include samples matching focus_regex, and exclude ignore_regex.
+
+   weblist func_regex [-ignore_regex]*
+       Show annotated source with interspersed assembly in a web browser.
+
+   list func_regex [-ignore_regex]*
+       Print source for routines matching func_regex, and exclude ignore_regex.
+
+   disasm func_regex [-ignore_regex]*
+       Disassemble routines matching func_regex, and exclude ignore_regex.
+
+   tags tag_regex [-ignore_regex]*
+       List tags with key:value matching tag_regex and exclude ignore_regex.
+
+   quit/exit/^D
+ 	     Exit pprof.
+
+   option=value
+       The following options can be set individually:
+           cum/flat:           Sort entries based on cumulative or flat data
+           call_tree:          Build context-sensitive call trees
+           nodecount:          Max number of entries to display
+           nodefraction:       Min frequency ratio of nodes to display
+           edgefraction:       Min frequency ratio of edges to display
+           focus/ignore:       Regexp to include/exclude samples by name/file
+           tagfocus/tagignore: Regexp or value range to filter samples by tag
+                               eg "1mb", "1mb:2mb", ":64kb"
+
+           functions:          Level of aggregation for sample data
+           files:
+           lines:
+           addresses:
+
+           unit:               Measurement unit to use on reports
+
+           Sample value selection by index:
+            sample_index:      Index of sample value to display
+            mean:              Average sample value over first value
+
+           Sample value selection by name:
+            alloc_space        for heap profiles
+            alloc_objects
+            inuse_space
+            inuse_objects
+
+            total_delay        for contention profiles
+            mean_delay
+            contentions
+
+   :   Clear focus/ignore/hide/tagfocus/tagignore`
+
+	ui.Print(help)
+	return nil
+}
+
+// cmdFlags parses the options of an interactive command and returns
+// an updated flags object.
+func cmdFlags(prof *profile.Profile, input []string, ui plugin.UI, f *flags) (*flags, error) {
+	cf := *f
+
+	var focus, ignore string
+	output := *cf.flagOutput
+	nodeCount := *cf.flagNodeCount
+	cmd := input[0]
+
+	// Update output flags based on parameters.
+	tokens := input[1:]
+	for p := 0; p < len(tokens); p++ {
+		t := tokens[p]
+		if t == "" {
+			continue
+		}
+		if c, err := strconv.ParseInt(t, 10, 32); err == nil {
+			nodeCount = int(c)
+			continue
+		}
+		switch t[0] {
+		case '>':
+			if len(t) > 1 {
+				output = t[1:]
+				continue
+			}
+			// find next token
+			for p++; p < len(tokens); p++ {
+				if tokens[p] != "" {
+					output = tokens[p]
+					break
+				}
+			}
+		case '-':
+			if t == "--cum" || t == "-cum" {
+				cf.flagCum = newBool(true)
+				continue
+			}
+			ignore = catRegex(ignore, t[1:])
+		default:
+			focus = catRegex(focus, t)
+		}
+	}
+
+	pcmd, ok := f.commands[cmd]
+	if !ok {
+		return nil, fmt.Errorf("Unexpected parse failure: %v", input)
+	}
+	// Reset flags
+	cf.flagCommands = make(map[string]*bool)
+	cf.flagParamCommands = make(map[string]*string)
+
+	if !pcmd.HasParam {
+		cf.flagCommands[cmd] = newBool(true)
+
+		switch cmd {
+		case "tags":
+			cf.flagTagFocus = newString(focus)
+			cf.flagTagIgnore = newString(ignore)
+		default:
+			cf.flagFocus = newString(catRegex(*cf.flagFocus, focus))
+			cf.flagIgnore = newString(catRegex(*cf.flagIgnore, ignore))
+		}
+	} else {
+		if focus == "" {
+			focus = "."
+		}
+		cf.flagParamCommands[cmd] = newString(focus)
+		cf.flagIgnore = newString(catRegex(*cf.flagIgnore, ignore))
+	}
+
+	if nodeCount < 0 {
+		switch cmd {
+		case "text", "top":
+			// Default text/top to 10 nodes on interactive mode
+			nodeCount = 10
+		default:
+			nodeCount = 80
+		}
+	}
+
+	cf.flagNodeCount = newInt(nodeCount)
+	cf.flagOutput = newString(output)
+
+	// Do regular flags processing
+	if err := processFlags(prof, ui, &cf); err != nil {
+		cf.usage(ui)
+		return nil, err
+	}
+
+	return &cf, nil
+}
+
+func catRegex(a, b string) string {
+	if a == "" {
+		return b
+	}
+	if b == "" {
+		return a
+	}
+	return a + "|" + b
+}
+
+// optFlags parses an interactive option setting and returns
+// an updated flags object.
+func optFlags(p *profile.Profile, input string, f *flags) (*flags, error) {
+	inputs := strings.SplitN(input, "=", 2)
+	option := strings.ToLower(strings.TrimSpace(inputs[0]))
+	var value string
+	if len(inputs) == 2 {
+		value = strings.TrimSpace(inputs[1])
+	}
+
+	of := *f
+
+	var err error
+	var bv bool
+	var uv uint64
+	var fv float64
+
+	switch option {
+	case "cum":
+		if bv, err = parseBool(value); err != nil {
+			return nil, err
+		}
+		of.flagCum = newBool(bv)
+	case "flat":
+		if bv, err = parseBool(value); err != nil {
+			return nil, err
+		}
+		of.flagCum = newBool(!bv)
+	case "call_tree":
+		if bv, err = parseBool(value); err != nil {
+			return nil, err
+		}
+		of.flagCallTree = newBool(bv)
+	case "unit":
+		of.flagDisplayUnit = newString(value)
+	case "sample_index":
+		if uv, err = strconv.ParseUint(value, 10, 32); err != nil {
+			return nil, err
+		}
+		if ix := int(uv); ix < 0 || ix >= len(p.SampleType) {
+			return nil, fmt.Errorf("sample_index out of range [0..%d]", len(p.SampleType)-1)
+		}
+		of.flagSampleIndex = newInt(int(uv))
+	case "mean":
+		if bv, err = parseBool(value); err != nil {
+			return nil, err
+		}
+		of.flagMean = newBool(bv)
+	case "nodecount":
+		if uv, err = strconv.ParseUint(value, 10, 32); err != nil {
+			return nil, err
+		}
+		of.flagNodeCount = newInt(int(uv))
+	case "nodefraction":
+		if fv, err = strconv.ParseFloat(value, 64); err != nil {
+			return nil, err
+		}
+		of.flagNodeFraction = newFloat64(fv)
+	case "edgefraction":
+		if fv, err = strconv.ParseFloat(value, 64); err != nil {
+			return nil, err
+		}
+		of.flagEdgeFraction = newFloat64(fv)
+	case "focus":
+		if err = validateRegex(value); err != nil {
+			return nil, err
+		}
+		of.flagFocus = newString(value)
+	case "ignore":
+		if err = validateRegex(value); err != nil {
+			return nil, err
+		}
+		of.flagIgnore = newString(value)
+	case "tagfocus":
+		if err = validateRegex(value); err != nil {
+			return nil, err
+		}
+		of.flagTagFocus = newString(value)
+	case "tagignore":
+		if err = validateRegex(value); err != nil {
+			return nil, err
+		}
+		of.flagTagIgnore = newString(value)
+	case "hide":
+		if err = validateRegex(value); err != nil {
+			return nil, err
+		}
+		of.flagHide = newString(value)
+	case "addresses", "files", "lines", "functions":
+		if bv, err = parseBool(value); err != nil {
+			return nil, err
+		}
+		if !bv {
+			return nil, fmt.Errorf("select one of addresses/files/lines/functions")
+		}
+		setGranularityToggle(option, &of)
+	default:
+		if ix := findSampleIndex(p, "", option); ix >= 0 {
+			of.flagSampleIndex = newInt(ix)
+		} else if ix := findSampleIndex(p, "total_", option); ix >= 0 {
+			of.flagSampleIndex = newInt(ix)
+			of.flagMean = newBool(false)
+		} else if ix := findSampleIndex(p, "mean_", option); ix >= 1 {
+			of.flagSampleIndex = newInt(ix)
+			of.flagMean = newBool(true)
+		} else {
+			return nil, fmt.Errorf("unrecognized command: %s", input)
+		}
+	}
+	return &of, nil
+}
+
+// parseBool parses a string as a boolean value.
+func parseBool(v string) (bool, error) {
+	switch strings.ToLower(v) {
+	case "true", "t", "yes", "y", "1", "":
+		return true, nil
+	case "false", "f", "no", "n", "0":
+		return false, nil
+	}
+	return false, fmt.Errorf(`illegal input "%s" for bool value`, v)
+}
+
+func findSampleIndex(p *profile.Profile, prefix, sampleType string) int {
+	if !strings.HasPrefix(sampleType, prefix) {
+		return -1
+	}
+	sampleType = strings.TrimPrefix(sampleType, prefix)
+	for i, r := range p.SampleType {
+		if r.Type == sampleType {
+			return i
+		}
+	}
+	return -1
+}
+
+// setGranularityToggle manages the set of granularity options. These
+// operate as a toggle; turning one on turns the others off.
+func setGranularityToggle(o string, fl *flags) {
+	t, f := newBool(true), newBool(false)
+	fl.flagFunctions = f
+	fl.flagFiles = f
+	fl.flagLines = f
+	fl.flagAddresses = f
+	switch o {
+	case "functions":
+		fl.flagFunctions = t
+	case "files":
+		fl.flagFiles = t
+	case "lines":
+		fl.flagLines = t
+	case "addresses":
+		fl.flagAddresses = t
+	default:
+		panic(fmt.Errorf("unexpected option %s", o))
+	}
+}
diff --git a/src/cmd/internal/pprof/fetch/fetch.go b/src/cmd/internal/pprof/fetch/fetch.go
new file mode 100644
index 0000000..ffd282e
--- /dev/null
+++ b/src/cmd/internal/pprof/fetch/fetch.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.
+
+// Package fetch provides an extensible mechanism to fetch a profile
+// from a data source.
+package fetch
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"os"
+	"strings"
+	"time"
+
+	"cmd/internal/pprof/plugin"
+	"cmd/internal/pprof/profile"
+)
+
+// FetchProfile reads from a data source (network, file) and generates a
+// profile.
+func FetchProfile(source string, timeout time.Duration) (*profile.Profile, error) {
+	return Fetcher(source, timeout, plugin.StandardUI())
+}
+
+// Fetcher is the plugin.Fetcher version of FetchProfile.
+func Fetcher(source string, timeout time.Duration, ui plugin.UI) (*profile.Profile, error) {
+	var f io.ReadCloser
+	var err error
+
+	url, err := url.Parse(source)
+	if err == nil && url.Host != "" {
+		f, err = FetchURL(source, timeout)
+	} else {
+		f, err = os.Open(source)
+	}
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+	return profile.Parse(f)
+}
+
+// FetchURL fetches a profile from a URL using HTTP.
+func FetchURL(source string, timeout time.Duration) (io.ReadCloser, error) {
+	resp, err := httpGet(source, timeout)
+	if err != nil {
+		return nil, fmt.Errorf("http fetch %s: %v", source, err)
+	}
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("server response: %s", resp.Status)
+	}
+
+	return resp.Body, nil
+}
+
+// PostURL issues a POST to a URL over HTTP.
+func PostURL(source, post string) ([]byte, error) {
+	resp, err := http.Post(source, "application/octet-stream", strings.NewReader(post))
+	if err != nil {
+		return nil, fmt.Errorf("http post %s: %v", source, err)
+	}
+	if resp.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("server response: %s", resp.Status)
+	}
+	defer resp.Body.Close()
+	return ioutil.ReadAll(resp.Body)
+}
+
+// httpGet is a wrapper around http.Get; it is defined as a variable
+// so it can be redefined during for testing.
+var httpGet = func(url string, timeout time.Duration) (*http.Response, error) {
+	client := &http.Client{
+		Transport: &http.Transport{
+			ResponseHeaderTimeout: timeout + 5*time.Second,
+		},
+	}
+	return client.Get(url)
+}
diff --git a/src/cmd/internal/pprof/plugin/plugin.go b/src/cmd/internal/pprof/plugin/plugin.go
new file mode 100644
index 0000000..d5025d5
--- /dev/null
+++ b/src/cmd/internal/pprof/plugin/plugin.go
@@ -0,0 +1,213 @@
+// 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 plugin defines the plugin implementations that the main pprof driver requires.
+package plugin
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"regexp"
+	"strings"
+	"time"
+
+	"cmd/internal/pprof/profile"
+)
+
+// A FlagSet creates and parses command-line flags.
+// It is similar to the standard flag.FlagSet.
+type FlagSet interface {
+	// Bool, Int, Float64, and String define new flags,
+	// like the functions of the same name in package flag.
+	Bool(name string, def bool, usage string) *bool
+	Int(name string, def int, usage string) *int
+	Float64(name string, def float64, usage string) *float64
+	String(name string, def string, usage string) *string
+
+	// ExtraUsage returns any additional text that should be
+	// printed after the standard usage message.
+	// The typical use of ExtraUsage is to show any custom flags
+	// defined by the specific pprof plugins being used.
+	ExtraUsage() string
+
+	// Parse initializes the flags with their values for this run
+	// and returns the non-flag command line arguments.
+	// If an unknown flag is encountered or there are no arguments,
+	// Parse should call usage and return nil.
+	Parse(usage func()) []string
+}
+
+// An ObjTool inspects shared libraries and executable files.
+type ObjTool interface {
+	// Open opens the named object file.
+	// If the object is a shared library, start is the address where
+	// it is mapped into memory in the address space being inspected.
+	Open(file string, start uint64) (ObjFile, error)
+
+	// Demangle translates a batch of symbol names from mangled
+	// form to human-readable form.
+	Demangle(names []string) (map[string]string, error)
+
+	// Disasm disassembles the named object file, starting at
+	// the start address and stopping at (before) the end address.
+	Disasm(file string, start, end uint64) ([]Inst, error)
+
+	// SetConfig configures the tool.
+	// The implementation defines the meaning of the string
+	// and can ignore it entirely.
+	SetConfig(config string)
+}
+
+// NoObjTool returns a trivial implementation of the ObjTool interface.
+// Open returns an error indicating that the requested file does not exist.
+// Demangle returns an empty map and a nil error.
+// Disasm returns an error.
+// SetConfig is a no-op.
+func NoObjTool() ObjTool {
+	return noObjTool{}
+}
+
+type noObjTool struct{}
+
+func (noObjTool) Open(file string, start uint64) (ObjFile, error) {
+	return nil, &os.PathError{Op: "open", Path: file, Err: os.ErrNotExist}
+}
+
+func (noObjTool) Demangle(name []string) (map[string]string, error) {
+	return make(map[string]string), nil
+}
+
+func (noObjTool) Disasm(file string, start, end uint64) ([]Inst, error) {
+	return nil, fmt.Errorf("disassembly not supported")
+}
+
+func (noObjTool) SetConfig(config string) {
+}
+
+// An ObjFile is a single object file: a shared library or executable.
+type ObjFile interface {
+	// Name returns the underlyinf file name, if available
+	Name() string
+
+	// Base returns the base address to use when looking up symbols in the file.
+	Base() uint64
+
+	// BuildID returns the GNU build ID of the file, or an empty string.
+	BuildID() string
+
+	// SourceLine reports the source line information for a given
+	// address in the file. Due to inlining, the source line information
+	// is in general a list of positions representing a call stack,
+	// with the leaf function first.
+	SourceLine(addr uint64) ([]Frame, error)
+
+	// Symbols returns a list of symbols in the object file.
+	// If r is not nil, Symbols restricts the list to symbols
+	// with names matching the regular expression.
+	// If addr is not zero, Symbols restricts the list to symbols
+	// containing that address.
+	Symbols(r *regexp.Regexp, addr uint64) ([]*Sym, error)
+
+	// Close closes the file, releasing associated resources.
+	Close() error
+}
+
+// A Frame describes a single line in a source file.
+type Frame struct {
+	Func string // name of function
+	File string // source file name
+	Line int    // line in file
+}
+
+// A Sym describes a single symbol in an object file.
+type Sym struct {
+	Name  []string // names of symbol (many if symbol was dedup'ed)
+	File  string   // object file containing symbol
+	Start uint64   // start virtual address
+	End   uint64   // virtual address of last byte in sym (Start+size-1)
+}
+
+// An Inst is a single instruction in an assembly listing.
+type Inst struct {
+	Addr uint64 // virtual address of instruction
+	Text string // instruction text
+	File string // source file
+	Line int    // source line
+}
+
+// A UI manages user interactions.
+type UI interface {
+	// Read returns a line of text (a command) read from the user.
+	ReadLine() (string, error)
+
+	// Print shows a message to the user.
+	// It formats the text as fmt.Print would and adds a final \n if not already present.
+	// For line-based UI, Print writes to standard error.
+	// (Standard output is reserved for report data.)
+	Print(...interface{})
+
+	// PrintErr shows an error message to the user.
+	// It formats the text as fmt.Print would and adds a final \n if not already present.
+	// For line-based UI, PrintErr writes to standard error.
+	PrintErr(...interface{})
+
+	// IsTerminal returns whether the UI is known to be tied to an
+	// interactive terminal (as opposed to being redirected to a file).
+	IsTerminal() bool
+
+	// SetAutoComplete instructs the UI to call complete(cmd) to obtain
+	// the auto-completion of cmd, if the UI supports auto-completion at all.
+	SetAutoComplete(complete func(string) string)
+}
+
+// StandardUI returns a UI that reads from standard input,
+// prints messages to standard output,
+// prints errors to standard error, and doesn't use auto-completion.
+func StandardUI() UI {
+	return &stdUI{r: bufio.NewReader(os.Stdin)}
+}
+
+type stdUI struct {
+	r *bufio.Reader
+}
+
+func (ui *stdUI) ReadLine() (string, error) {
+	os.Stdout.WriteString("(pprof) ")
+	return ui.r.ReadString('\n')
+}
+
+func (ui *stdUI) Print(args ...interface{}) {
+	ui.fprint(os.Stderr, args)
+}
+
+func (ui *stdUI) PrintErr(args ...interface{}) {
+	ui.fprint(os.Stderr, args)
+}
+
+func (ui *stdUI) IsTerminal() bool {
+	return false
+}
+
+func (ui *stdUI) SetAutoComplete(func(string) string) {
+}
+
+func (ui *stdUI) fprint(f *os.File, args []interface{}) {
+	text := fmt.Sprint(args...)
+	if !strings.HasSuffix(text, "\n") {
+		text += "\n"
+	}
+	f.WriteString(text)
+}
+
+// A Fetcher reads and returns the profile named by src.
+// It gives up after the given timeout, unless src contains a timeout override
+// (as defined by the implementation).
+// It can print messages to ui.
+type Fetcher func(src string, timeout time.Duration, ui UI) (*profile.Profile, error)
+
+// A Symbolizer annotates a profile with symbol information.
+// The profile was fetch from src.
+// The meaning of mode is defined by the implementation.
+type Symbolizer func(mode, src string, prof *profile.Profile, obj ObjTool, ui UI) error
diff --git a/src/cmd/internal/pprof/profile/encode.go b/src/cmd/internal/pprof/profile/encode.go
new file mode 100644
index 0000000..6b879a8
--- /dev/null
+++ b/src/cmd/internal/pprof/profile/encode.go
@@ -0,0 +1,470 @@
+// 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 profile
+
+import (
+	"errors"
+	"fmt"
+	"sort"
+)
+
+func (p *Profile) decoder() []decoder {
+	return profileDecoder
+}
+
+// preEncode populates the unexported fields to be used by encode
+// (with suffix X) from the corresponding exported fields. The
+// exported fields are cleared up to facilitate testing.
+func (p *Profile) preEncode() {
+	strings := make(map[string]int)
+	addString(strings, "")
+
+	for _, st := range p.SampleType {
+		st.typeX = addString(strings, st.Type)
+		st.unitX = addString(strings, st.Unit)
+	}
+
+	for _, s := range p.Sample {
+		s.labelX = nil
+		var keys []string
+		for k := range s.Label {
+			keys = append(keys, k)
+		}
+		sort.Strings(keys)
+		for _, k := range keys {
+			vs := s.Label[k]
+			for _, v := range vs {
+				s.labelX = append(s.labelX,
+					Label{
+						keyX: addString(strings, k),
+						strX: addString(strings, v),
+					},
+				)
+			}
+		}
+		var numKeys []string
+		for k := range s.NumLabel {
+			numKeys = append(numKeys, k)
+		}
+		sort.Strings(numKeys)
+		for _, k := range numKeys {
+			vs := s.NumLabel[k]
+			for _, v := range vs {
+				s.labelX = append(s.labelX,
+					Label{
+						keyX: addString(strings, k),
+						numX: v,
+					},
+				)
+			}
+		}
+		s.locationIDX = nil
+		for _, l := range s.Location {
+			s.locationIDX = append(s.locationIDX, l.ID)
+		}
+	}
+
+	for _, m := range p.Mapping {
+		m.fileX = addString(strings, m.File)
+		m.buildIDX = addString(strings, m.BuildID)
+	}
+
+	for _, l := range p.Location {
+		for i, ln := range l.Line {
+			if ln.Function != nil {
+				l.Line[i].functionIDX = ln.Function.ID
+			} else {
+				l.Line[i].functionIDX = 0
+			}
+		}
+		if l.Mapping != nil {
+			l.mappingIDX = l.Mapping.ID
+		} else {
+			l.mappingIDX = 0
+		}
+	}
+	for _, f := range p.Function {
+		f.nameX = addString(strings, f.Name)
+		f.systemNameX = addString(strings, f.SystemName)
+		f.filenameX = addString(strings, f.Filename)
+	}
+
+	p.dropFramesX = addString(strings, p.DropFrames)
+	p.keepFramesX = addString(strings, p.KeepFrames)
+
+	if pt := p.PeriodType; pt != nil {
+		pt.typeX = addString(strings, pt.Type)
+		pt.unitX = addString(strings, pt.Unit)
+	}
+
+	p.stringTable = make([]string, len(strings))
+	for s, i := range strings {
+		p.stringTable[i] = s
+	}
+}
+
+func (p *Profile) encode(b *buffer) {
+	for _, x := range p.SampleType {
+		encodeMessage(b, 1, x)
+	}
+	for _, x := range p.Sample {
+		encodeMessage(b, 2, x)
+	}
+	for _, x := range p.Mapping {
+		encodeMessage(b, 3, x)
+	}
+	for _, x := range p.Location {
+		encodeMessage(b, 4, x)
+	}
+	for _, x := range p.Function {
+		encodeMessage(b, 5, x)
+	}
+	encodeStrings(b, 6, p.stringTable)
+	encodeInt64Opt(b, 7, p.dropFramesX)
+	encodeInt64Opt(b, 8, p.keepFramesX)
+	encodeInt64Opt(b, 9, p.TimeNanos)
+	encodeInt64Opt(b, 10, p.DurationNanos)
+	if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
+		encodeMessage(b, 11, p.PeriodType)
+	}
+	encodeInt64Opt(b, 12, p.Period)
+}
+
+var profileDecoder = []decoder{
+	nil, // 0
+	// repeated ValueType sample_type = 1
+	func(b *buffer, m message) error {
+		x := new(ValueType)
+		pp := m.(*Profile)
+		pp.SampleType = append(pp.SampleType, x)
+		return decodeMessage(b, x)
+	},
+	// repeated Sample sample = 2
+	func(b *buffer, m message) error {
+		x := new(Sample)
+		pp := m.(*Profile)
+		pp.Sample = append(pp.Sample, x)
+		return decodeMessage(b, x)
+	},
+	// repeated Mapping mapping = 3
+	func(b *buffer, m message) error {
+		x := new(Mapping)
+		pp := m.(*Profile)
+		pp.Mapping = append(pp.Mapping, x)
+		return decodeMessage(b, x)
+	},
+	// repeated Location location = 4
+	func(b *buffer, m message) error {
+		x := new(Location)
+		pp := m.(*Profile)
+		pp.Location = append(pp.Location, x)
+		return decodeMessage(b, x)
+	},
+	// repeated Function function = 5
+	func(b *buffer, m message) error {
+		x := new(Function)
+		pp := m.(*Profile)
+		pp.Function = append(pp.Function, x)
+		return decodeMessage(b, x)
+	},
+	// repeated string string_table = 6
+	func(b *buffer, m message) error {
+		err := decodeStrings(b, &m.(*Profile).stringTable)
+		if err != nil {
+			return err
+		}
+		if *&m.(*Profile).stringTable[0] != "" {
+			return errors.New("string_table[0] must be ''")
+		}
+		return nil
+	},
+	// repeated int64 drop_frames = 7
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
+	// repeated int64 keep_frames = 8
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
+	// repeated int64 time_nanos = 9
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).TimeNanos) },
+	// repeated int64 duration_nanos = 10
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
+	// optional string period_type = 11
+	func(b *buffer, m message) error {
+		x := new(ValueType)
+		pp := m.(*Profile)
+		pp.PeriodType = x
+		return decodeMessage(b, x)
+	},
+	// repeated int64 period = 12
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
+}
+
+// postDecode takes the unexported fields populated by decode (with
+// suffix X) and populates the corresponding exported fields.
+// The unexported fields are cleared up to facilitate testing.
+func (p *Profile) postDecode() error {
+	var err error
+
+	mappings := make(map[uint64]*Mapping)
+	for _, m := range p.Mapping {
+		m.File, err = getString(p.stringTable, &m.fileX, err)
+		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
+		mappings[m.ID] = m
+	}
+
+	functions := make(map[uint64]*Function)
+	for _, f := range p.Function {
+		f.Name, err = getString(p.stringTable, &f.nameX, err)
+		f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
+		f.Filename, err = getString(p.stringTable, &f.filenameX, err)
+		functions[f.ID] = f
+	}
+
+	locations := make(map[uint64]*Location)
+	for _, l := range p.Location {
+		l.Mapping = mappings[l.mappingIDX]
+		l.mappingIDX = 0
+		for i, ln := range l.Line {
+			if id := ln.functionIDX; id != 0 {
+				l.Line[i].Function = functions[id]
+				if l.Line[i].Function == nil {
+					return fmt.Errorf("Function ID %d not found", id)
+				}
+				l.Line[i].functionIDX = 0
+			}
+		}
+		locations[l.ID] = l
+	}
+
+	for _, st := range p.SampleType {
+		st.Type, err = getString(p.stringTable, &st.typeX, err)
+		st.Unit, err = getString(p.stringTable, &st.unitX, err)
+	}
+
+	for _, s := range p.Sample {
+		labels := make(map[string][]string)
+		numLabels := make(map[string][]int64)
+		for _, l := range s.labelX {
+			var key, value string
+			key, err = getString(p.stringTable, &l.keyX, err)
+			if l.strX != 0 {
+				value, err = getString(p.stringTable, &l.strX, err)
+				labels[key] = append(labels[key], value)
+			} else {
+				numLabels[key] = append(numLabels[key], l.numX)
+			}
+		}
+		if len(labels) > 0 {
+			s.Label = labels
+		}
+		if len(numLabels) > 0 {
+			s.NumLabel = numLabels
+		}
+		s.Location = nil
+		for _, lid := range s.locationIDX {
+			s.Location = append(s.Location, locations[lid])
+		}
+		s.locationIDX = nil
+	}
+
+	p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
+	p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
+
+	if pt := p.PeriodType; pt == nil {
+		p.PeriodType = &ValueType{}
+	}
+
+	if pt := p.PeriodType; pt != nil {
+		pt.Type, err = getString(p.stringTable, &pt.typeX, err)
+		pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
+	}
+	p.stringTable = nil
+	return nil
+}
+
+func (p *ValueType) decoder() []decoder {
+	return valueTypeDecoder
+}
+
+func (p *ValueType) encode(b *buffer) {
+	encodeInt64Opt(b, 1, p.typeX)
+	encodeInt64Opt(b, 2, p.unitX)
+}
+
+var valueTypeDecoder = []decoder{
+	nil, // 0
+	// optional int64 type = 1
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
+	// optional int64 unit = 2
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
+}
+
+func (p *Sample) decoder() []decoder {
+	return sampleDecoder
+}
+
+func (p *Sample) encode(b *buffer) {
+	encodeUint64s(b, 1, p.locationIDX)
+	for _, x := range p.Value {
+		encodeInt64(b, 2, x)
+	}
+	for _, x := range p.labelX {
+		encodeMessage(b, 3, x)
+	}
+}
+
+var sampleDecoder = []decoder{
+	nil, // 0
+	// repeated uint64 location = 1
+	func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
+	// repeated int64 value = 2
+	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
+	// repeated Label label = 3
+	func(b *buffer, m message) error {
+		s := m.(*Sample)
+		n := len(s.labelX)
+		s.labelX = append(s.labelX, Label{})
+		return decodeMessage(b, &s.labelX[n])
+	},
+}
+
+func (p Label) decoder() []decoder {
+	return labelDecoder
+}
+
+func (p Label) encode(b *buffer) {
+	encodeInt64Opt(b, 1, p.keyX)
+	encodeInt64Opt(b, 2, p.strX)
+	encodeInt64Opt(b, 3, p.numX)
+}
+
+var labelDecoder = []decoder{
+	nil, // 0
+	// optional int64 key = 1
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).keyX) },
+	// optional int64 str = 2
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).strX) },
+	// optional int64 num = 3
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).numX) },
+}
+
+func (p *Mapping) decoder() []decoder {
+	return mappingDecoder
+}
+
+func (p *Mapping) encode(b *buffer) {
+	encodeUint64Opt(b, 1, p.ID)
+	encodeUint64Opt(b, 2, p.Start)
+	encodeUint64Opt(b, 3, p.Limit)
+	encodeUint64Opt(b, 4, p.Offset)
+	encodeInt64Opt(b, 5, p.fileX)
+	encodeInt64Opt(b, 6, p.buildIDX)
+	encodeBoolOpt(b, 7, p.HasFunctions)
+	encodeBoolOpt(b, 8, p.HasFilenames)
+	encodeBoolOpt(b, 9, p.HasLineNumbers)
+	encodeBoolOpt(b, 10, p.HasInlineFrames)
+}
+
+var mappingDecoder = []decoder{
+	nil, // 0
+	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
+	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
+	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
+	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
+	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
+	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
+	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
+	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
+}
+
+func (p *Location) decoder() []decoder {
+	return locationDecoder
+}
+
+func (p *Location) encode(b *buffer) {
+	encodeUint64Opt(b, 1, p.ID)
+	encodeUint64Opt(b, 2, p.mappingIDX)
+	encodeUint64Opt(b, 3, p.Address)
+	for i := range p.Line {
+		encodeMessage(b, 4, &p.Line[i])
+	}
+}
+
+var locationDecoder = []decoder{
+	nil, // 0
+	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
+	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
+	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
+	func(b *buffer, m message) error { // repeated Line line = 4
+		pp := m.(*Location)
+		n := len(pp.Line)
+		pp.Line = append(pp.Line, Line{})
+		return decodeMessage(b, &pp.Line[n])
+	},
+}
+
+func (p *Line) decoder() []decoder {
+	return lineDecoder
+}
+
+func (p *Line) encode(b *buffer) {
+	encodeUint64Opt(b, 1, p.functionIDX)
+	encodeInt64Opt(b, 2, p.Line)
+}
+
+var lineDecoder = []decoder{
+	nil, // 0
+	// optional uint64 function_id = 1
+	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
+	// optional int64 line = 2
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
+}
+
+func (p *Function) decoder() []decoder {
+	return functionDecoder
+}
+
+func (p *Function) encode(b *buffer) {
+	encodeUint64Opt(b, 1, p.ID)
+	encodeInt64Opt(b, 2, p.nameX)
+	encodeInt64Opt(b, 3, p.systemNameX)
+	encodeInt64Opt(b, 4, p.filenameX)
+	encodeInt64Opt(b, 5, p.StartLine)
+}
+
+var functionDecoder = []decoder{
+	nil, // 0
+	// optional uint64 id = 1
+	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
+	// optional int64 function_name = 2
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
+	// optional int64 function_system_name = 3
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
+	// repeated int64 filename = 4
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
+	// optional int64 start_line = 5
+	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
+}
+
+func addString(strings map[string]int, s string) int64 {
+	i, ok := strings[s]
+	if !ok {
+		i = len(strings)
+		strings[s] = i
+	}
+	return int64(i)
+}
+
+func getString(strings []string, strng *int64, err error) (string, error) {
+	if err != nil {
+		return "", err
+	}
+	s := int(*strng)
+	if s < 0 || s >= len(strings) {
+		return "", errMalformed
+	}
+	*strng = 0
+	return strings[s], nil
+}
diff --git a/src/cmd/pprof/internal/profile/filter.go b/src/cmd/internal/pprof/profile/filter.go
similarity index 100%
rename from src/cmd/pprof/internal/profile/filter.go
rename to src/cmd/internal/pprof/profile/filter.go
diff --git a/src/cmd/internal/pprof/profile/legacy_profile.go b/src/cmd/internal/pprof/profile/legacy_profile.go
new file mode 100644
index 0000000..8ccfe45
--- /dev/null
+++ b/src/cmd/internal/pprof/profile/legacy_profile.go
@@ -0,0 +1,1236 @@
+// 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 parsers to convert legacy profiles into the
+// profile.proto format.
+
+package profile
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"math"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+var (
+	countStartRE = regexp.MustCompile(`\A(\w+) profile: total \d+\n\z`)
+	countRE      = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\n\z`)
+
+	heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`)
+	heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`)
+
+	contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`)
+
+	hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`)
+
+	growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz`)
+
+	fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz`)
+
+	threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`)
+	threadStartRE  = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`)
+
+	procMapsRE = regexp.MustCompile(`([[:xdigit:]]+)-([[:xdigit:]]+)\s+([-rwxp]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+):([[:xdigit:]]+)\s+([[:digit:]]+)\s*(\S+)?`)
+
+	briefMapsRE = regexp.MustCompile(`\s*([[:xdigit:]]+)-([[:xdigit:]]+):\s*(\S+)(\s.*@)?([[:xdigit:]]+)?`)
+
+	// LegacyHeapAllocated instructs the heapz parsers to use the
+	// allocated memory stats instead of the default in-use memory. Note
+	// that tcmalloc doesn't provide all allocated memory, only in-use
+	// stats.
+	LegacyHeapAllocated bool
+)
+
+func isSpaceOrComment(line string) bool {
+	trimmed := strings.TrimSpace(line)
+	return len(trimmed) == 0 || trimmed[0] == '#'
+}
+
+// parseGoCount parses a Go count profile (e.g., threadcreate or
+// goroutine) and returns a new Profile.
+func parseGoCount(b []byte) (*Profile, error) {
+	r := bytes.NewBuffer(b)
+
+	var line string
+	var err error
+	for {
+		// Skip past comments and empty lines seeking a real header.
+		line, err = r.ReadString('\n')
+		if err != nil {
+			return nil, err
+		}
+		if !isSpaceOrComment(line) {
+			break
+		}
+	}
+
+	m := countStartRE.FindStringSubmatch(line)
+	if m == nil {
+		return nil, errUnrecognized
+	}
+	profileType := m[1]
+	p := &Profile{
+		PeriodType: &ValueType{Type: profileType, Unit: "count"},
+		Period:     1,
+		SampleType: []*ValueType{{Type: profileType, Unit: "count"}},
+	}
+	locations := make(map[uint64]*Location)
+	for {
+		line, err = r.ReadString('\n')
+		if err != nil {
+			if err == io.EOF {
+				break
+			}
+			return nil, err
+		}
+		if isSpaceOrComment(line) {
+			continue
+		}
+		if strings.HasPrefix(line, "---") {
+			break
+		}
+		m := countRE.FindStringSubmatch(line)
+		if m == nil {
+			return nil, errMalformed
+		}
+		n, err := strconv.ParseInt(m[1], 0, 64)
+		if err != nil {
+			return nil, errMalformed
+		}
+		fields := strings.Fields(m[2])
+		locs := make([]*Location, 0, len(fields))
+		for _, stk := range fields {
+			addr, err := strconv.ParseUint(stk, 0, 64)
+			if err != nil {
+				return nil, errMalformed
+			}
+			// Adjust all frames by -1 to land on the call instruction.
+			addr--
+			loc := locations[addr]
+			if loc == nil {
+				loc = &Location{
+					Address: addr,
+				}
+				locations[addr] = loc
+				p.Location = append(p.Location, loc)
+			}
+			locs = append(locs, loc)
+		}
+		p.Sample = append(p.Sample, &Sample{
+			Location: locs,
+			Value:    []int64{n},
+		})
+	}
+
+	if err = parseAdditionalSections(strings.TrimSpace(line), r, p); err != nil {
+		return nil, err
+	}
+	return p, nil
+}
+
+// remapLocationIDs ensures there is a location for each address
+// referenced by a sample, and remaps the samples to point to the new
+// location ids.
+func (p *Profile) remapLocationIDs() {
+	seen := make(map[*Location]bool, len(p.Location))
+	var locs []*Location
+
+	for _, s := range p.Sample {
+		for _, l := range s.Location {
+			if seen[l] {
+				continue
+			}
+			l.ID = uint64(len(locs) + 1)
+			locs = append(locs, l)
+			seen[l] = true
+		}
+	}
+	p.Location = locs
+}
+
+func (p *Profile) remapFunctionIDs() {
+	seen := make(map[*Function]bool, len(p.Function))
+	var fns []*Function
+
+	for _, l := range p.Location {
+		for _, ln := range l.Line {
+			fn := ln.Function
+			if fn == nil || seen[fn] {
+				continue
+			}
+			fn.ID = uint64(len(fns) + 1)
+			fns = append(fns, fn)
+			seen[fn] = true
+		}
+	}
+	p.Function = fns
+}
+
+// remapMappingIDs matches location addresses with existing mappings
+// and updates them appropriately. This is O(N*M), if this ever shows
+// up as a bottleneck, evaluate sorting the mappings and doing a
+// binary search, which would make it O(N*log(M)).
+func (p *Profile) remapMappingIDs() {
+	if len(p.Mapping) == 0 {
+		return
+	}
+
+	// Some profile handlers will incorrectly set regions for the main
+	// executable if its section is remapped. Fix them through heuristics.
+
+	// Remove the initial mapping if named '/anon_hugepage' and has a
+	// consecutive adjacent mapping.
+	if m := p.Mapping[0]; strings.HasPrefix(m.File, "/anon_hugepage") {
+		if len(p.Mapping) > 1 && m.Limit == p.Mapping[1].Start {
+			p.Mapping = p.Mapping[1:]
+		}
+	}
+
+	// Subtract the offset from the start of the main mapping if it
+	// ends up at a recognizable start address.
+	const expectedStart = 0x400000
+	if m := p.Mapping[0]; m.Start-m.Offset == expectedStart {
+		m.Start = expectedStart
+		m.Offset = 0
+	}
+
+	for _, l := range p.Location {
+		if a := l.Address; a != 0 {
+			for _, m := range p.Mapping {
+				if m.Start <= a && a < m.Limit {
+					l.Mapping = m
+					break
+				}
+			}
+		}
+	}
+
+	// Reset all mapping IDs.
+	for i, m := range p.Mapping {
+		m.ID = uint64(i + 1)
+	}
+}
+
+var cpuInts = []func([]byte) (uint64, []byte){
+	get32l,
+	get32b,
+	get64l,
+	get64b,
+}
+
+func get32l(b []byte) (uint64, []byte) {
+	if len(b) < 4 {
+		return 0, nil
+	}
+	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24, b[4:]
+}
+
+func get32b(b []byte) (uint64, []byte) {
+	if len(b) < 4 {
+		return 0, nil
+	}
+	return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24, b[4:]
+}
+
+func get64l(b []byte) (uint64, []byte) {
+	if len(b) < 8 {
+		return 0, nil
+	}
+	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, b[8:]
+}
+
+func get64b(b []byte) (uint64, []byte) {
+	if len(b) < 8 {
+		return 0, nil
+	}
+	return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56, b[8:]
+}
+
+// ParseTracebacks parses a set of tracebacks and returns a newly
+// populated profile. It will accept any text file and generate a
+// Profile out of it with any hex addresses it can identify, including
+// a process map if it can recognize one. Each sample will include a
+// tag "source" with the addresses recognized in string format.
+func ParseTracebacks(b []byte) (*Profile, error) {
+	r := bytes.NewBuffer(b)
+
+	p := &Profile{
+		PeriodType: &ValueType{Type: "trace", Unit: "count"},
+		Period:     1,
+		SampleType: []*ValueType{
+			{Type: "trace", Unit: "count"},
+		},
+	}
+
+	var sources []string
+	var sloc []*Location
+
+	locs := make(map[uint64]*Location)
+	for {
+		l, err := r.ReadString('\n')
+		if err != nil {
+			if err != io.EOF {
+				return nil, err
+			}
+			if l == "" {
+				break
+			}
+		}
+		if sectionTrigger(l) == memoryMapSection {
+			break
+		}
+		if s, addrs := extractHexAddresses(l); len(s) > 0 {
+			for _, addr := range addrs {
+				// Addresses from stack traces point to the next instruction after
+				// each call. Adjust by -1 to land somewhere on the actual call.
+				addr--
+				loc := locs[addr]
+				if locs[addr] == nil {
+					loc = &Location{
+						Address: addr,
+					}
+					p.Location = append(p.Location, loc)
+					locs[addr] = loc
+				}
+				sloc = append(sloc, loc)
+			}
+
+			sources = append(sources, s...)
+		} else {
+			if len(sources) > 0 || len(sloc) > 0 {
+				addTracebackSample(sloc, sources, p)
+				sloc, sources = nil, nil
+			}
+		}
+	}
+
+	// Add final sample to save any leftover data.
+	if len(sources) > 0 || len(sloc) > 0 {
+		addTracebackSample(sloc, sources, p)
+	}
+
+	if err := p.ParseMemoryMap(r); err != nil {
+		return nil, err
+	}
+	return p, nil
+}
+
+func addTracebackSample(l []*Location, s []string, p *Profile) {
+	p.Sample = append(p.Sample,
+		&Sample{
+			Value:    []int64{1},
+			Location: l,
+			Label:    map[string][]string{"source": s},
+		})
+}
+
+// parseCPU parses a profilez legacy profile and returns a newly
+// populated Profile.
+//
+// The general format for profilez samples is a sequence of words in
+// binary format. The first words are a header with the following data:
+//   1st word -- 0
+//   2nd word -- 3
+//   3rd word -- 0 if a c++ application, 1 if a java application.
+//   4th word -- Sampling period (in microseconds).
+//   5th word -- Padding.
+func parseCPU(b []byte) (*Profile, error) {
+	var parse func([]byte) (uint64, []byte)
+	var n1, n2, n3, n4, n5 uint64
+	for _, parse = range cpuInts {
+		var tmp []byte
+		n1, tmp = parse(b)
+		n2, tmp = parse(tmp)
+		n3, tmp = parse(tmp)
+		n4, tmp = parse(tmp)
+		n5, tmp = parse(tmp)
+
+		if tmp != nil && n1 == 0 && n2 == 3 && n3 == 0 && n4 > 0 && n5 == 0 {
+			b = tmp
+			return cpuProfile(b, int64(n4), parse)
+		}
+	}
+	return nil, errUnrecognized
+}
+
+// cpuProfile returns a new Profile from C++ profilez data.
+// b is the profile bytes after the header, period is the profiling
+// period, and parse is a function to parse 8-byte chunks from the
+// profile in its native endianness.
+func cpuProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) {
+	p := &Profile{
+		Period:     period * 1000,
+		PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
+		SampleType: []*ValueType{
+			{Type: "samples", Unit: "count"},
+			{Type: "cpu", Unit: "nanoseconds"},
+		},
+	}
+	var err error
+	if b, _, err = parseCPUSamples(b, parse, true, p); err != nil {
+		return nil, err
+	}
+
+	// If all samples have the same second-to-the-bottom frame, it
+	// strongly suggests that it is an uninteresting artifact of
+	// measurement -- a stack frame pushed by the signal handler. The
+	// bottom frame is always correct as it is picked up from the signal
+	// structure, not the stack. Check if this is the case and if so,
+	// remove.
+	if len(p.Sample) > 1 && len(p.Sample[0].Location) > 1 {
+		allSame := true
+		id1 := p.Sample[0].Location[1].Address
+		for _, s := range p.Sample {
+			if len(s.Location) < 2 || id1 != s.Location[1].Address {
+				allSame = false
+				break
+			}
+		}
+		if allSame {
+			for _, s := range p.Sample {
+				s.Location = append(s.Location[:1], s.Location[2:]...)
+			}
+		}
+	}
+
+	if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil {
+		return nil, err
+	}
+	return p, nil
+}
+
+// parseCPUSamples parses a collection of profilez samples from a
+// profile.
+//
+// profilez samples are a repeated sequence of stack frames of the
+// form:
+//    1st word -- The number of times this stack was encountered.
+//    2nd word -- The size of the stack (StackSize).
+//    3rd word -- The first address on the stack.
+//    ...
+//    StackSize + 2 -- The last address on the stack
+// The last stack trace is of the form:
+//   1st word -- 0
+//   2nd word -- 1
+//   3rd word -- 0
+//
+// Addresses from stack traces may point to the next instruction after
+// each call. Optionally adjust by -1 to land somewhere on the actual
+// call (except for the leaf, which is not a call).
+func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust bool, p *Profile) ([]byte, map[uint64]*Location, error) {
+	locs := make(map[uint64]*Location)
+	for len(b) > 0 {
+		var count, nstk uint64
+		count, b = parse(b)
+		nstk, b = parse(b)
+		if b == nil || nstk > uint64(len(b)/4) {
+			return nil, nil, errUnrecognized
+		}
+		var sloc []*Location
+		addrs := make([]uint64, nstk)
+		for i := 0; i < int(nstk); i++ {
+			addrs[i], b = parse(b)
+		}
+
+		if count == 0 && nstk == 1 && addrs[0] == 0 {
+			// End of data marker
+			break
+		}
+		for i, addr := range addrs {
+			if adjust && i > 0 {
+				addr--
+			}
+			loc := locs[addr]
+			if loc == nil {
+				loc = &Location{
+					Address: addr,
+				}
+				locs[addr] = loc
+				p.Location = append(p.Location, loc)
+			}
+			sloc = append(sloc, loc)
+		}
+		p.Sample = append(p.Sample,
+			&Sample{
+				Value:    []int64{int64(count), int64(count) * p.Period},
+				Location: sloc,
+			})
+	}
+	// Reached the end without finding the EOD marker.
+	return b, locs, nil
+}
+
+// parseHeap parses a heapz legacy or a growthz profile and
+// returns a newly populated Profile.
+func parseHeap(b []byte) (p *Profile, err error) {
+	r := bytes.NewBuffer(b)
+	l, err := r.ReadString('\n')
+	if err != nil {
+		return nil, errUnrecognized
+	}
+
+	sampling := ""
+
+	if header := heapHeaderRE.FindStringSubmatch(l); header != nil {
+		p = &Profile{
+			SampleType: []*ValueType{
+				{Type: "objects", Unit: "count"},
+				{Type: "space", Unit: "bytes"},
+			},
+			PeriodType: &ValueType{Type: "objects", Unit: "bytes"},
+		}
+
+		var period int64
+		if len(header[6]) > 0 {
+			if period, err = strconv.ParseInt(header[6], 10, 64); err != nil {
+				return nil, errUnrecognized
+			}
+		}
+
+		switch header[5] {
+		case "heapz_v2", "heap_v2":
+			sampling, p.Period = "v2", period
+		case "heapprofile":
+			sampling, p.Period = "", 1
+		case "heap":
+			sampling, p.Period = "v2", period/2
+		default:
+			return nil, errUnrecognized
+		}
+	} else if header = growthHeaderRE.FindStringSubmatch(l); header != nil {
+		p = &Profile{
+			SampleType: []*ValueType{
+				{Type: "objects", Unit: "count"},
+				{Type: "space", Unit: "bytes"},
+			},
+			PeriodType: &ValueType{Type: "heapgrowth", Unit: "count"},
+			Period:     1,
+		}
+	} else if header = fragmentationHeaderRE.FindStringSubmatch(l); header != nil {
+		p = &Profile{
+			SampleType: []*ValueType{
+				{Type: "objects", Unit: "count"},
+				{Type: "space", Unit: "bytes"},
+			},
+			PeriodType: &ValueType{Type: "allocations", Unit: "count"},
+			Period:     1,
+		}
+	} else {
+		return nil, errUnrecognized
+	}
+
+	if LegacyHeapAllocated {
+		for _, st := range p.SampleType {
+			st.Type = "alloc_" + st.Type
+		}
+	} else {
+		for _, st := range p.SampleType {
+			st.Type = "inuse_" + st.Type
+		}
+	}
+
+	locs := make(map[uint64]*Location)
+	for {
+		l, err = r.ReadString('\n')
+		if err != nil {
+			if err != io.EOF {
+				return nil, err
+			}
+
+			if l == "" {
+				break
+			}
+		}
+
+		if isSpaceOrComment(l) {
+			continue
+		}
+		l = strings.TrimSpace(l)
+
+		if sectionTrigger(l) != unrecognizedSection {
+			break
+		}
+
+		value, blocksize, addrs, err := parseHeapSample(l, p.Period, sampling)
+		if err != nil {
+			return nil, err
+		}
+		var sloc []*Location
+		for _, addr := range addrs {
+			// Addresses from stack traces point to the next instruction after
+			// each call. Adjust by -1 to land somewhere on the actual call.
+			addr--
+			loc := locs[addr]
+			if locs[addr] == nil {
+				loc = &Location{
+					Address: addr,
+				}
+				p.Location = append(p.Location, loc)
+				locs[addr] = loc
+			}
+			sloc = append(sloc, loc)
+		}
+
+		p.Sample = append(p.Sample, &Sample{
+			Value:    value,
+			Location: sloc,
+			NumLabel: map[string][]int64{"bytes": {blocksize}},
+		})
+	}
+
+	if err = parseAdditionalSections(l, r, p); err != nil {
+		return nil, err
+	}
+	return p, nil
+}
+
+// parseHeapSample parses a single row from a heap profile into a new Sample.
+func parseHeapSample(line string, rate int64, sampling string) (value []int64, blocksize int64, addrs []uint64, err error) {
+	sampleData := heapSampleRE.FindStringSubmatch(line)
+	if len(sampleData) != 6 {
+		return value, blocksize, addrs, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData))
+	}
+
+	// Use first two values by default; tcmalloc sampling generates the
+	// same value for both, only the older heap-profile collect separate
+	// stats for in-use and allocated objects.
+	valueIndex := 1
+	if LegacyHeapAllocated {
+		valueIndex = 3
+	}
+
+	var v1, v2 int64
+	if v1, err = strconv.ParseInt(sampleData[valueIndex], 10, 64); err != nil {
+		return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+	}
+	if v2, err = strconv.ParseInt(sampleData[valueIndex+1], 10, 64); err != nil {
+		return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+	}
+
+	if v1 == 0 {
+		if v2 != 0 {
+			return value, blocksize, addrs, fmt.Errorf("allocation count was 0 but allocation bytes was %d", v2)
+		}
+	} else {
+		blocksize = v2 / v1
+		if sampling == "v2" {
+			v1, v2 = scaleHeapSample(v1, v2, rate)
+		}
+	}
+
+	value = []int64{v1, v2}
+	addrs = parseHexAddresses(sampleData[5])
+
+	return value, blocksize, addrs, nil
+}
+
+// extractHexAddresses extracts hex numbers from a string and returns
+// them, together with their numeric value, in a slice.
+func extractHexAddresses(s string) ([]string, []uint64) {
+	hexStrings := hexNumberRE.FindAllString(s, -1)
+	var ids []uint64
+	for _, s := range hexStrings {
+		if id, err := strconv.ParseUint(s, 0, 64); err == nil {
+			ids = append(ids, id)
+		} else {
+			// Do not expect any parsing failures due to the regexp matching.
+			panic("failed to parse hex value:" + s)
+		}
+	}
+	return hexStrings, ids
+}
+
+// parseHexAddresses parses hex numbers from a string and returns them
+// in a slice.
+func parseHexAddresses(s string) []uint64 {
+	_, ids := extractHexAddresses(s)
+	return ids
+}
+
+// scaleHeapSample adjusts the data from a heapz Sample to
+// account for its probability of appearing in the collected
+// data. heapz profiles are a sampling of the memory allocations
+// requests in a program. We estimate the unsampled value by dividing
+// each collected sample by its probability of appearing in the
+// profile. heapz v2 profiles rely on a poisson process to determine
+// which samples to collect, based on the desired average collection
+// rate R. The probability of a sample of size S to appear in that
+// profile is 1-exp(-S/R).
+func scaleHeapSample(count, size, rate int64) (int64, int64) {
+	if count == 0 || size == 0 {
+		return 0, 0
+	}
+
+	if rate <= 1 {
+		// if rate==1 all samples were collected so no adjustment is needed.
+		// if rate<1 treat as unknown and skip scaling.
+		return count, size
+	}
+
+	avgSize := float64(size) / float64(count)
+	scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
+
+	return int64(float64(count) * scale), int64(float64(size) * scale)
+}
+
+// parseContention parses a contentionz profile and returns a newly
+// populated Profile.
+func parseContention(b []byte) (p *Profile, err error) {
+	r := bytes.NewBuffer(b)
+	l, err := r.ReadString('\n')
+	if err != nil {
+		return nil, errUnrecognized
+	}
+
+	if !strings.HasPrefix(l, "--- contention") {
+		return nil, errUnrecognized
+	}
+
+	p = &Profile{
+		PeriodType: &ValueType{Type: "contentions", Unit: "count"},
+		Period:     1,
+		SampleType: []*ValueType{
+			{Type: "contentions", Unit: "count"},
+			{Type: "delay", Unit: "nanoseconds"},
+		},
+	}
+
+	var cpuHz int64
+	// Parse text of the form "attribute = value" before the samples.
+	const delimiter = "="
+	for {
+		l, err = r.ReadString('\n')
+		if err != nil {
+			if err != io.EOF {
+				return nil, err
+			}
+
+			if l == "" {
+				break
+			}
+		}
+
+		if l = strings.TrimSpace(l); l == "" {
+			continue
+		}
+
+		if strings.HasPrefix(l, "---") {
+			break
+		}
+
+		attr := strings.SplitN(l, delimiter, 2)
+		if len(attr) != 2 {
+			break
+		}
+		key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])
+		var err error
+		switch key {
+		case "cycles/second":
+			if cpuHz, err = strconv.ParseInt(val, 0, 64); err != nil {
+				return nil, errUnrecognized
+			}
+		case "sampling period":
+			if p.Period, err = strconv.ParseInt(val, 0, 64); err != nil {
+				return nil, errUnrecognized
+			}
+		case "ms since reset":
+			ms, err := strconv.ParseInt(val, 0, 64)
+			if err != nil {
+				return nil, errUnrecognized
+			}
+			p.DurationNanos = ms * 1000 * 1000
+		case "format":
+			// CPP contentionz profiles don't have format.
+			return nil, errUnrecognized
+		case "resolution":
+			// CPP contentionz profiles don't have resolution.
+			return nil, errUnrecognized
+		case "discarded samples":
+		default:
+			return nil, errUnrecognized
+		}
+	}
+
+	locs := make(map[uint64]*Location)
+	for {
+		if l = strings.TrimSpace(l); strings.HasPrefix(l, "---") {
+			break
+		}
+		value, addrs, err := parseContentionSample(l, p.Period, cpuHz)
+		if err != nil {
+			return nil, err
+		}
+		var sloc []*Location
+		for _, addr := range addrs {
+			// Addresses from stack traces point to the next instruction after
+			// each call. Adjust by -1 to land somewhere on the actual call.
+			addr--
+			loc := locs[addr]
+			if locs[addr] == nil {
+				loc = &Location{
+					Address: addr,
+				}
+				p.Location = append(p.Location, loc)
+				locs[addr] = loc
+			}
+			sloc = append(sloc, loc)
+		}
+		p.Sample = append(p.Sample, &Sample{
+			Value:    value,
+			Location: sloc,
+		})
+
+		if l, err = r.ReadString('\n'); err != nil {
+			if err != io.EOF {
+				return nil, err
+			}
+			if l == "" {
+				break
+			}
+		}
+	}
+
+	if err = parseAdditionalSections(l, r, p); err != nil {
+		return nil, err
+	}
+
+	return p, nil
+}
+
+// parseContentionSample parses a single row from a contention profile
+// into a new Sample.
+func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) {
+	sampleData := contentionSampleRE.FindStringSubmatch(line)
+	if sampleData == nil {
+		return value, addrs, errUnrecognized
+	}
+
+	v1, err := strconv.ParseInt(sampleData[1], 10, 64)
+	if err != nil {
+		return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+	}
+	v2, err := strconv.ParseInt(sampleData[2], 10, 64)
+	if err != nil {
+		return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+	}
+
+	// Unsample values if period and cpuHz are available.
+	// - Delays are scaled to cycles and then to nanoseconds.
+	// - Contentions are scaled to cycles.
+	if period > 0 {
+		if cpuHz > 0 {
+			cpuGHz := float64(cpuHz) / 1e9
+			v1 = int64(float64(v1) * float64(period) / cpuGHz)
+		}
+		v2 = v2 * period
+	}
+
+	value = []int64{v2, v1}
+	addrs = parseHexAddresses(sampleData[3])
+
+	return value, addrs, nil
+}
+
+// parseThread parses a Threadz profile and returns a new Profile.
+func parseThread(b []byte) (*Profile, error) {
+	r := bytes.NewBuffer(b)
+
+	var line string
+	var err error
+	for {
+		// Skip past comments and empty lines seeking a real header.
+		line, err = r.ReadString('\n')
+		if err != nil {
+			return nil, err
+		}
+		if !isSpaceOrComment(line) {
+			break
+		}
+	}
+
+	if m := threadzStartRE.FindStringSubmatch(line); m != nil {
+		// Advance over initial comments until first stack trace.
+		for {
+			line, err = r.ReadString('\n')
+			if err != nil {
+				if err != io.EOF {
+					return nil, err
+				}
+
+				if line == "" {
+					break
+				}
+			}
+			if sectionTrigger(line) != unrecognizedSection || line[0] == '-' {
+				break
+			}
+		}
+	} else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
+		return nil, errUnrecognized
+	}
+
+	p := &Profile{
+		SampleType: []*ValueType{{Type: "thread", Unit: "count"}},
+		PeriodType: &ValueType{Type: "thread", Unit: "count"},
+		Period:     1,
+	}
+
+	locs := make(map[uint64]*Location)
+	// Recognize each thread and populate profile samples.
+	for sectionTrigger(line) == unrecognizedSection {
+		if strings.HasPrefix(line, "---- no stack trace for") {
+			line = ""
+			break
+		}
+		if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
+			return nil, errUnrecognized
+		}
+
+		var addrs []uint64
+		line, addrs, err = parseThreadSample(r)
+		if err != nil {
+			return nil, errUnrecognized
+		}
+		if len(addrs) == 0 {
+			// We got a --same as previous threads--. Bump counters.
+			if len(p.Sample) > 0 {
+				s := p.Sample[len(p.Sample)-1]
+				s.Value[0]++
+			}
+			continue
+		}
+
+		var sloc []*Location
+		for _, addr := range addrs {
+			// Addresses from stack traces point to the next instruction after
+			// each call. Adjust by -1 to land somewhere on the actual call.
+			addr--
+			loc := locs[addr]
+			if locs[addr] == nil {
+				loc = &Location{
+					Address: addr,
+				}
+				p.Location = append(p.Location, loc)
+				locs[addr] = loc
+			}
+			sloc = append(sloc, loc)
+		}
+
+		p.Sample = append(p.Sample, &Sample{
+			Value:    []int64{1},
+			Location: sloc,
+		})
+	}
+
+	if err = parseAdditionalSections(line, r, p); err != nil {
+		return nil, err
+	}
+
+	return p, nil
+}
+
+// parseThreadSample parses a symbolized or unsymbolized stack trace.
+// Returns the first line after the traceback, the sample (or nil if
+// it hits a 'same-as-previous' marker) and an error.
+func parseThreadSample(b *bytes.Buffer) (nextl string, addrs []uint64, err error) {
+	var l string
+	sameAsPrevious := false
+	for {
+		if l, err = b.ReadString('\n'); err != nil {
+			if err != io.EOF {
+				return "", nil, err
+			}
+			if l == "" {
+				break
+			}
+		}
+		if l = strings.TrimSpace(l); l == "" {
+			continue
+		}
+
+		if strings.HasPrefix(l, "---") {
+			break
+		}
+		if strings.Contains(l, "same as previous thread") {
+			sameAsPrevious = true
+			continue
+		}
+
+		addrs = append(addrs, parseHexAddresses(l)...)
+	}
+
+	if sameAsPrevious {
+		return l, nil, nil
+	}
+	return l, addrs, nil
+}
+
+// parseAdditionalSections parses any additional sections in the
+// profile, ignoring any unrecognized sections.
+func parseAdditionalSections(l string, b *bytes.Buffer, p *Profile) (err error) {
+	for {
+		if sectionTrigger(l) == memoryMapSection {
+			break
+		}
+		// Ignore any unrecognized sections.
+		if l, err := b.ReadString('\n'); err != nil {
+			if err != io.EOF {
+				return err
+			}
+			if l == "" {
+				break
+			}
+		}
+	}
+	return p.ParseMemoryMap(b)
+}
+
+// ParseMemoryMap parses a memory map in the format of
+// /proc/self/maps, and overrides the mappings in the current profile.
+// It renumbers the samples and locations in the profile correspondingly.
+func (p *Profile) ParseMemoryMap(rd io.Reader) error {
+	b := bufio.NewReader(rd)
+
+	var attrs []string
+	var r *strings.Replacer
+	const delimiter = "="
+	for {
+		l, err := b.ReadString('\n')
+		if err != nil {
+			if err != io.EOF {
+				return err
+			}
+			if l == "" {
+				break
+			}
+		}
+		if l = strings.TrimSpace(l); l == "" {
+			continue
+		}
+
+		if r != nil {
+			l = r.Replace(l)
+		}
+		m, err := parseMappingEntry(l)
+		if err != nil {
+			if err == errUnrecognized {
+				// Recognize assignments of the form: attr=value, and replace
+				// $attr with value on subsequent mappings.
+				if attr := strings.SplitN(l, delimiter, 2); len(attr) == 2 {
+					attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
+					r = strings.NewReplacer(attrs...)
+				}
+				// Ignore any unrecognized entries
+				continue
+			}
+			return err
+		}
+		if m == nil || (m.File == "" && len(p.Mapping) != 0) {
+			// In some cases the first entry may include the address range
+			// but not the name of the file. It should be followed by
+			// another entry with the name.
+			continue
+		}
+		if len(p.Mapping) == 1 && p.Mapping[0].File == "" {
+			// Update the name if this is the entry following that empty one.
+			p.Mapping[0].File = m.File
+			continue
+		}
+		p.Mapping = append(p.Mapping, m)
+	}
+	p.remapLocationIDs()
+	p.remapFunctionIDs()
+	p.remapMappingIDs()
+	return nil
+}
+
+func parseMappingEntry(l string) (*Mapping, error) {
+	mapping := &Mapping{}
+	var err error
+	if me := procMapsRE.FindStringSubmatch(l); len(me) == 9 {
+		if !strings.Contains(me[3], "x") {
+			// Skip non-executable entries.
+			return nil, nil
+		}
+		if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
+			return nil, errUnrecognized
+		}
+		if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
+			return nil, errUnrecognized
+		}
+		if me[4] != "" {
+			if mapping.Offset, err = strconv.ParseUint(me[4], 16, 64); err != nil {
+				return nil, errUnrecognized
+			}
+		}
+		mapping.File = me[8]
+		return mapping, nil
+	}
+
+	if me := briefMapsRE.FindStringSubmatch(l); len(me) == 6 {
+		if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
+			return nil, errUnrecognized
+		}
+		if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
+			return nil, errUnrecognized
+		}
+		mapping.File = me[3]
+		if me[5] != "" {
+			if mapping.Offset, err = strconv.ParseUint(me[5], 16, 64); err != nil {
+				return nil, errUnrecognized
+			}
+		}
+		return mapping, nil
+	}
+
+	return nil, errUnrecognized
+}
+
+type sectionType int
+
+const (
+	unrecognizedSection sectionType = iota
+	memoryMapSection
+)
+
+var memoryMapTriggers = []string{
+	"--- Memory map: ---",
+	"MAPPED_LIBRARIES:",
+}
+
+func sectionTrigger(line string) sectionType {
+	for _, trigger := range memoryMapTriggers {
+		if strings.Contains(line, trigger) {
+			return memoryMapSection
+		}
+	}
+	return unrecognizedSection
+}
+
+func (p *Profile) addLegacyFrameInfo() {
+	switch {
+	case isProfileType(p, heapzSampleTypes) ||
+		isProfileType(p, heapzInUseSampleTypes) ||
+		isProfileType(p, heapzAllocSampleTypes):
+		p.DropFrames, p.KeepFrames = allocRxStr, allocSkipRxStr
+	case isProfileType(p, contentionzSampleTypes):
+		p.DropFrames, p.KeepFrames = lockRxStr, ""
+	default:
+		p.DropFrames, p.KeepFrames = cpuProfilerRxStr, ""
+	}
+}
+
+var heapzSampleTypes = []string{"allocations", "size"} // early Go pprof profiles
+var heapzInUseSampleTypes = []string{"inuse_objects", "inuse_space"}
+var heapzAllocSampleTypes = []string{"alloc_objects", "alloc_space"}
+var contentionzSampleTypes = []string{"contentions", "delay"}
+
+func isProfileType(p *Profile, t []string) bool {
+	st := p.SampleType
+	if len(st) != len(t) {
+		return false
+	}
+
+	for i := range st {
+		if st[i].Type != t[i] {
+			return false
+		}
+	}
+	return true
+}
+
+var allocRxStr = strings.Join([]string{
+	// POSIX entry points.
+	`calloc`,
+	`cfree`,
+	`malloc`,
+	`free`,
+	`memalign`,
+	`do_memalign`,
+	`(__)?posix_memalign`,
+	`pvalloc`,
+	`valloc`,
+	`realloc`,
+
+	// TC malloc.
+	`tcmalloc::.*`,
+	`tc_calloc`,
+	`tc_cfree`,
+	`tc_malloc`,
+	`tc_free`,
+	`tc_memalign`,
+	`tc_posix_memalign`,
+	`tc_pvalloc`,
+	`tc_valloc`,
+	`tc_realloc`,
+	`tc_new`,
+	`tc_delete`,
+	`tc_newarray`,
+	`tc_deletearray`,
+	`tc_new_nothrow`,
+	`tc_newarray_nothrow`,
+
+	// Memory-allocation routines on OS X.
+	`malloc_zone_malloc`,
+	`malloc_zone_calloc`,
+	`malloc_zone_valloc`,
+	`malloc_zone_realloc`,
+	`malloc_zone_memalign`,
+	`malloc_zone_free`,
+
+	// Go runtime
+	`runtime\..*`,
+
+	// Other misc. memory allocation routines
+	`BaseArena::.*`,
+	`(::)?do_malloc_no_errno`,
+	`(::)?do_malloc_pages`,
+	`(::)?do_malloc`,
+	`DoSampledAllocation`,
+	`MallocedMemBlock::MallocedMemBlock`,
+	`_M_allocate`,
+	`__builtin_(vec_)?delete`,
+	`__builtin_(vec_)?new`,
+	`__gnu_cxx::new_allocator::allocate`,
+	`__libc_malloc`,
+	`__malloc_alloc_template::allocate`,
+	`allocate`,
+	`cpp_alloc`,
+	`operator new(\[\])?`,
+	`simple_alloc::allocate`,
+}, `|`)
+
+var allocSkipRxStr = strings.Join([]string{
+	// Preserve Go runtime frames that appear in the middle/bottom of
+	// the stack.
+	`runtime\.panic`,
+}, `|`)
+
+var cpuProfilerRxStr = strings.Join([]string{
+	`ProfileData::Add`,
+	`ProfileData::prof_handler`,
+	`CpuProfiler::prof_handler`,
+	`__pthread_sighandler`,
+	`__restore`,
+}, `|`)
+
+var lockRxStr = strings.Join([]string{
+	`RecordLockProfileData`,
+	`(base::)?RecordLockProfileData.*`,
+	`(base::)?SubmitMutexProfileData.*`,
+	`(base::)?SubmitSpinLockProfileData.*`,
+	`(Mutex::)?AwaitCommon.*`,
+	`(Mutex::)?Unlock.*`,
+	`(Mutex::)?UnlockSlow.*`,
+	`(Mutex::)?ReaderUnlock.*`,
+	`(MutexLock::)?~MutexLock.*`,
+	`(SpinLock::)?Unlock.*`,
+	`(SpinLock::)?SlowUnlock.*`,
+	`(SpinLockHolder::)?~SpinLockHolder.*`,
+}, `|`)
diff --git a/src/cmd/internal/pprof/profile/profile.go b/src/cmd/internal/pprof/profile/profile.go
new file mode 100644
index 0000000..28e713d
--- /dev/null
+++ b/src/cmd/internal/pprof/profile/profile.go
@@ -0,0 +1,572 @@
+// 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 profile provides a representation of profile.proto and
+// methods to encode/decode profiles in this format.
+package profile
+
+import (
+	"bytes"
+	"compress/gzip"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"regexp"
+	"strings"
+	"time"
+)
+
+// Profile is an in-memory representation of profile.proto.
+type Profile struct {
+	SampleType []*ValueType
+	Sample     []*Sample
+	Mapping    []*Mapping
+	Location   []*Location
+	Function   []*Function
+
+	DropFrames string
+	KeepFrames string
+
+	TimeNanos     int64
+	DurationNanos int64
+	PeriodType    *ValueType
+	Period        int64
+
+	dropFramesX int64
+	keepFramesX int64
+	stringTable []string
+}
+
+// ValueType corresponds to Profile.ValueType
+type ValueType struct {
+	Type string // cpu, wall, inuse_space, etc
+	Unit string // seconds, nanoseconds, bytes, etc
+
+	typeX int64
+	unitX int64
+}
+
+// Sample corresponds to Profile.Sample
+type Sample struct {
+	Location []*Location
+	Value    []int64
+	Label    map[string][]string
+	NumLabel map[string][]int64
+
+	locationIDX []uint64
+	labelX      []Label
+}
+
+// Label corresponds to Profile.Label
+type Label struct {
+	keyX int64
+	// Exactly one of the two following values must be set
+	strX int64
+	numX int64 // Integer value for this label
+}
+
+// Mapping corresponds to Profile.Mapping
+type Mapping struct {
+	ID              uint64
+	Start           uint64
+	Limit           uint64
+	Offset          uint64
+	File            string
+	BuildID         string
+	HasFunctions    bool
+	HasFilenames    bool
+	HasLineNumbers  bool
+	HasInlineFrames bool
+
+	fileX    int64
+	buildIDX int64
+}
+
+// Location corresponds to Profile.Location
+type Location struct {
+	ID      uint64
+	Mapping *Mapping
+	Address uint64
+	Line    []Line
+
+	mappingIDX uint64
+}
+
+// Line corresponds to Profile.Line
+type Line struct {
+	Function *Function
+	Line     int64
+
+	functionIDX uint64
+}
+
+// Function corresponds to Profile.Function
+type Function struct {
+	ID         uint64
+	Name       string
+	SystemName string
+	Filename   string
+	StartLine  int64
+
+	nameX       int64
+	systemNameX int64
+	filenameX   int64
+}
+
+// Parse parses a profile and checks for its validity. The input
+// may be a gzip-compressed encoded protobuf or one of many legacy
+// profile formats which may be unsupported in the future.
+func Parse(r io.Reader) (*Profile, error) {
+	orig, err := ioutil.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+
+	var p *Profile
+	if len(orig) >= 2 && orig[0] == 0x1f && orig[1] == 0x8b {
+		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)
+		}
+		orig = data
+	}
+	if p, err = parseUncompressed(orig); err != nil {
+		if p, err = parseLegacy(orig); err != nil {
+			return nil, fmt.Errorf("parsing profile: %v", err)
+		}
+	}
+
+	if err := p.CheckValid(); err != nil {
+		return nil, fmt.Errorf("malformed profile: %v", err)
+	}
+	return p, nil
+}
+
+var errUnrecognized = fmt.Errorf("unrecognized profile format")
+var errMalformed = fmt.Errorf("malformed profile format")
+
+func parseLegacy(data []byte) (*Profile, error) {
+	parsers := []func([]byte) (*Profile, error){
+		parseCPU,
+		parseHeap,
+		parseGoCount, // goroutine, threadcreate
+		parseThread,
+		parseContention,
+	}
+
+	for _, parser := range parsers {
+		p, err := parser(data)
+		if err == nil {
+			p.setMain()
+			p.addLegacyFrameInfo()
+			return p, nil
+		}
+		if err != errUnrecognized {
+			return nil, err
+		}
+	}
+	return nil, errUnrecognized
+}
+
+func parseUncompressed(data []byte) (*Profile, error) {
+	p := &Profile{}
+	if err := unmarshal(data, p); err != nil {
+		return nil, err
+	}
+
+	if err := p.postDecode(); err != nil {
+		return nil, err
+	}
+
+	return p, nil
+}
+
+var libRx = regexp.MustCompile(`([.]so$|[.]so[._][0-9]+)`)
+
+// setMain scans Mapping entries and guesses which entry is main
+// because legacy profiles don't obey the convention of putting main
+// first.
+func (p *Profile) setMain() {
+	for i := 0; i < len(p.Mapping); i++ {
+		file := strings.TrimSpace(strings.Replace(p.Mapping[i].File, "(deleted)", "", -1))
+		if len(file) == 0 {
+			continue
+		}
+		if len(libRx.FindStringSubmatch(file)) > 0 {
+			continue
+		}
+		if strings.HasPrefix(file, "[") {
+			continue
+		}
+		// Swap what we guess is main to position 0.
+		tmp := p.Mapping[i]
+		p.Mapping[i] = p.Mapping[0]
+		p.Mapping[0] = tmp
+		break
+	}
+}
+
+// Write writes the profile as a gzip-compressed marshaled protobuf.
+func (p *Profile) Write(w io.Writer) error {
+	p.preEncode()
+	b := marshal(p)
+	zw := gzip.NewWriter(w)
+	defer zw.Close()
+	_, err := zw.Write(b)
+	return err
+}
+
+// CheckValid tests whether the profile is valid. Checks include, but are
+// not limited to:
+//   - len(Profile.Sample[n].value) == len(Profile.value_unit)
+//   - Sample.id has a corresponding Profile.Location
+func (p *Profile) CheckValid() error {
+	// Check that sample values are consistent
+	sampleLen := len(p.SampleType)
+	if sampleLen == 0 && len(p.Sample) != 0 {
+		return fmt.Errorf("missing sample type information")
+	}
+	for _, s := range p.Sample {
+		if len(s.Value) != sampleLen {
+			return fmt.Errorf("mismatch: sample has: %d values vs. %d types", len(s.Value), len(p.SampleType))
+		}
+	}
+
+	// Check that all mappings/locations/functions are in the tables
+	// Check that there are no duplicate ids
+	mappings := make(map[uint64]*Mapping, len(p.Mapping))
+	for _, m := range p.Mapping {
+		if m.ID == 0 {
+			return fmt.Errorf("found mapping with reserved ID=0")
+		}
+		if mappings[m.ID] != nil {
+			return fmt.Errorf("multiple mappings with same id: %d", m.ID)
+		}
+		mappings[m.ID] = m
+	}
+	functions := make(map[uint64]*Function, len(p.Function))
+	for _, f := range p.Function {
+		if f.ID == 0 {
+			return fmt.Errorf("found function with reserved ID=0")
+		}
+		if functions[f.ID] != nil {
+			return fmt.Errorf("multiple functions with same id: %d", f.ID)
+		}
+		functions[f.ID] = f
+	}
+	locations := make(map[uint64]*Location, len(p.Location))
+	for _, l := range p.Location {
+		if l.ID == 0 {
+			return fmt.Errorf("found location with reserved id=0")
+		}
+		if locations[l.ID] != nil {
+			return fmt.Errorf("multiple locations with same id: %d", l.ID)
+		}
+		locations[l.ID] = l
+		if m := l.Mapping; m != nil {
+			if m.ID == 0 || mappings[m.ID] != m {
+				return fmt.Errorf("inconsistent mapping %p: %d", m, m.ID)
+			}
+		}
+		for _, ln := range l.Line {
+			if f := ln.Function; f != nil {
+				if f.ID == 0 || functions[f.ID] != f {
+					return fmt.Errorf("inconsistent function %p: %d", f, f.ID)
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// Aggregate merges the locations in the profile into equivalence
+// classes preserving the request attributes. It also updates the
+// samples to point to the merged locations.
+func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error {
+	for _, m := range p.Mapping {
+		m.HasInlineFrames = m.HasInlineFrames && inlineFrame
+		m.HasFunctions = m.HasFunctions && function
+		m.HasFilenames = m.HasFilenames && filename
+		m.HasLineNumbers = m.HasLineNumbers && linenumber
+	}
+
+	// Aggregate functions
+	if !function || !filename {
+		for _, f := range p.Function {
+			if !function {
+				f.Name = ""
+				f.SystemName = ""
+			}
+			if !filename {
+				f.Filename = ""
+			}
+		}
+	}
+
+	// Aggregate locations
+	if !inlineFrame || !address || !linenumber {
+		for _, l := range p.Location {
+			if !inlineFrame && len(l.Line) > 1 {
+				l.Line = l.Line[len(l.Line)-1:]
+			}
+			if !linenumber {
+				for i := range l.Line {
+					l.Line[i].Line = 0
+				}
+			}
+			if !address {
+				l.Address = 0
+			}
+		}
+	}
+
+	return p.CheckValid()
+}
+
+// Print dumps a text representation of a profile. Intended mainly
+// for debugging purposes.
+func (p *Profile) String() string {
+
+	ss := make([]string, 0, len(p.Sample)+len(p.Mapping)+len(p.Location))
+	if pt := p.PeriodType; pt != nil {
+		ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit))
+	}
+	ss = append(ss, fmt.Sprintf("Period: %d", p.Period))
+	if p.TimeNanos != 0 {
+		ss = append(ss, fmt.Sprintf("Time: %v", time.Unix(0, p.TimeNanos)))
+	}
+	if p.DurationNanos != 0 {
+		ss = append(ss, fmt.Sprintf("Duration: %v", time.Duration(p.DurationNanos)))
+	}
+
+	ss = append(ss, "Samples:")
+	var sh1 string
+	for _, s := range p.SampleType {
+		sh1 = sh1 + fmt.Sprintf("%s/%s ", s.Type, s.Unit)
+	}
+	ss = append(ss, strings.TrimSpace(sh1))
+	for _, s := range p.Sample {
+		var sv string
+		for _, v := range s.Value {
+			sv = fmt.Sprintf("%s %10d", sv, v)
+		}
+		sv = sv + ": "
+		for _, l := range s.Location {
+			sv = sv + fmt.Sprintf("%d ", l.ID)
+		}
+		ss = append(ss, sv)
+		const labelHeader = "                "
+		if len(s.Label) > 0 {
+			ls := labelHeader
+			for k, v := range s.Label {
+				ls = ls + fmt.Sprintf("%s:%v ", k, v)
+			}
+			ss = append(ss, ls)
+		}
+		if len(s.NumLabel) > 0 {
+			ls := labelHeader
+			for k, v := range s.NumLabel {
+				ls = ls + fmt.Sprintf("%s:%v ", k, v)
+			}
+			ss = append(ss, ls)
+		}
+	}
+
+	ss = append(ss, "Locations")
+	for _, l := range p.Location {
+		locStr := fmt.Sprintf("%6d: %#x ", l.ID, l.Address)
+		if m := l.Mapping; m != nil {
+			locStr = locStr + fmt.Sprintf("M=%d ", m.ID)
+		}
+		if len(l.Line) == 0 {
+			ss = append(ss, locStr)
+		}
+		for li := range l.Line {
+			lnStr := "??"
+			if fn := l.Line[li].Function; fn != nil {
+				lnStr = fmt.Sprintf("%s %s:%d s=%d",
+					fn.Name,
+					fn.Filename,
+					l.Line[li].Line,
+					fn.StartLine)
+				if fn.Name != fn.SystemName {
+					lnStr = lnStr + "(" + fn.SystemName + ")"
+				}
+			}
+			ss = append(ss, locStr+lnStr)
+			// Do not print location details past the first line
+			locStr = "             "
+		}
+	}
+
+	ss = append(ss, "Mappings")
+	for _, m := range p.Mapping {
+		bits := ""
+		if m.HasFunctions {
+			bits = bits + "[FN]"
+		}
+		if m.HasFilenames {
+			bits = bits + "[FL]"
+		}
+		if m.HasLineNumbers {
+			bits = bits + "[LN]"
+		}
+		if m.HasInlineFrames {
+			bits = bits + "[IN]"
+		}
+		ss = append(ss, fmt.Sprintf("%d: %#x/%#x/%#x %s %s %s",
+			m.ID,
+			m.Start, m.Limit, m.Offset,
+			m.File,
+			m.BuildID,
+			bits))
+	}
+
+	return strings.Join(ss, "\n") + "\n"
+}
+
+// Merge adds profile p adjusted by ratio r into profile p. Profiles
+// must be compatible (same Type and SampleType).
+// TODO(rsilvera): consider normalizing the profiles based on the
+// total samples collected.
+func (p *Profile) Merge(pb *Profile, r float64) error {
+	if err := p.Compatible(pb); err != nil {
+		return err
+	}
+
+	pb = pb.Copy()
+
+	// Keep the largest of the two periods.
+	if pb.Period > p.Period {
+		p.Period = pb.Period
+	}
+
+	p.DurationNanos += pb.DurationNanos
+
+	p.Mapping = append(p.Mapping, pb.Mapping...)
+	for i, m := range p.Mapping {
+		m.ID = uint64(i + 1)
+	}
+	p.Location = append(p.Location, pb.Location...)
+	for i, l := range p.Location {
+		l.ID = uint64(i + 1)
+	}
+	p.Function = append(p.Function, pb.Function...)
+	for i, f := range p.Function {
+		f.ID = uint64(i + 1)
+	}
+
+	if r != 1.0 {
+		for _, s := range pb.Sample {
+			for i, v := range s.Value {
+				s.Value[i] = int64((float64(v) * r))
+			}
+		}
+	}
+	p.Sample = append(p.Sample, pb.Sample...)
+	return p.CheckValid()
+}
+
+// Compatible determines if two profiles can be compared/merged.
+// returns nil if the profiles are compatible; otherwise an error with
+// details on the incompatibility.
+func (p *Profile) Compatible(pb *Profile) error {
+	if !compatibleValueTypes(p.PeriodType, pb.PeriodType) {
+		return fmt.Errorf("incompatible period types %v and %v", p.PeriodType, pb.PeriodType)
+	}
+
+	if len(p.SampleType) != len(pb.SampleType) {
+		return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
+	}
+
+	for i := range p.SampleType {
+		if !compatibleValueTypes(p.SampleType[i], pb.SampleType[i]) {
+			return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
+		}
+	}
+
+	return nil
+}
+
+// HasFunctions determines if all locations in this profile have
+// symbolized function information.
+func (p *Profile) HasFunctions() bool {
+	for _, l := range p.Location {
+		if l.Mapping == nil || !l.Mapping.HasFunctions {
+			return false
+		}
+	}
+	return true
+}
+
+// HasFileLines determines if all locations in this profile have
+// symbolized file and line number information.
+func (p *Profile) HasFileLines() bool {
+	for _, l := range p.Location {
+		if l.Mapping == nil || (!l.Mapping.HasFilenames || !l.Mapping.HasLineNumbers) {
+			return false
+		}
+	}
+	return true
+}
+
+func compatibleValueTypes(v1, v2 *ValueType) bool {
+	if v1 == nil || v2 == nil {
+		return true // No grounds to disqualify.
+	}
+	return v1.Type == v2.Type && v1.Unit == v2.Unit
+}
+
+// Copy makes a fully independent copy of a profile.
+func (p *Profile) Copy() *Profile {
+	p.preEncode()
+	b := marshal(p)
+
+	pp := &Profile{}
+	if err := unmarshal(b, pp); err != nil {
+		panic(err)
+	}
+	if err := pp.postDecode(); err != nil {
+		panic(err)
+	}
+
+	return pp
+}
+
+// Demangler maps symbol names to a human-readable form. This may
+// include C++ demangling and additional simplification. Names that
+// are not demangled may be missing from the resulting map.
+type Demangler func(name []string) (map[string]string, error)
+
+// Demangle attempts to demangle and optionally simplify any function
+// names referenced in the profile. It works on a best-effort basis:
+// it will silently preserve the original names in case of any errors.
+func (p *Profile) Demangle(d Demangler) error {
+	// Collect names to demangle.
+	var names []string
+	for _, fn := range p.Function {
+		names = append(names, fn.SystemName)
+	}
+
+	// Update profile with demangled names.
+	demangled, err := d(names)
+	if err != nil {
+		return err
+	}
+	for _, fn := range p.Function {
+		if dd, ok := demangled[fn.SystemName]; ok {
+			fn.Name = dd
+		}
+	}
+	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/internal/pprof/profile/profile_test.go
similarity index 100%
rename from src/cmd/pprof/internal/profile/profile_test.go
rename to src/cmd/internal/pprof/profile/profile_test.go
diff --git a/src/cmd/internal/pprof/profile/proto.go b/src/cmd/internal/pprof/profile/proto.go
new file mode 100644
index 0000000..11d7f9f
--- /dev/null
+++ b/src/cmd/internal/pprof/profile/proto.go
@@ -0,0 +1,360 @@
+// 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 is a simple protocol buffer encoder and decoder.
+//
+// A protocol message must implement the message interface:
+//   decoder() []decoder
+//   encode(*buffer)
+//
+// The decode method returns a slice indexed by field number that gives the
+// function to decode that field.
+// The encode method encodes its receiver into the given buffer.
+//
+// The two methods are simple enough to be implemented by hand rather than
+// by using a protocol compiler.
+//
+// See profile.go for examples of messages implementing this interface.
+//
+// There is no support for groups, message sets, or "has" bits.
+
+package profile
+
+import "errors"
+
+type buffer struct {
+	field int
+	typ   int
+	u64   uint64
+	data  []byte
+	tmp   [16]byte
+}
+
+type decoder func(*buffer, message) error
+
+type message interface {
+	decoder() []decoder
+	encode(*buffer)
+}
+
+func marshal(m message) []byte {
+	var b buffer
+	m.encode(&b)
+	return b.data
+}
+
+func encodeVarint(b *buffer, x uint64) {
+	for x >= 128 {
+		b.data = append(b.data, byte(x)|0x80)
+		x >>= 7
+	}
+	b.data = append(b.data, byte(x))
+}
+
+func encodeLength(b *buffer, tag int, len int) {
+	encodeVarint(b, uint64(tag)<<3|2)
+	encodeVarint(b, uint64(len))
+}
+
+func encodeUint64(b *buffer, tag int, x uint64) {
+	// append varint to b.data
+	encodeVarint(b, uint64(tag)<<3|0)
+	encodeVarint(b, x)
+}
+
+func encodeUint64s(b *buffer, tag int, x []uint64) {
+	if len(x) > 2 {
+		// Use packed encoding
+		n1 := len(b.data)
+		for _, u := range x {
+			encodeVarint(b, u)
+		}
+		n2 := len(b.data)
+		encodeLength(b, tag, n2-n1)
+		n3 := len(b.data)
+		copy(b.tmp[:], b.data[n2:n3])
+		copy(b.data[n1+(n3-n2):], b.data[n1:n2])
+		copy(b.data[n1:], b.tmp[:n3-n2])
+		return
+	}
+	for _, u := range x {
+		encodeUint64(b, tag, u)
+	}
+}
+
+func encodeUint64Opt(b *buffer, tag int, x uint64) {
+	if x == 0 {
+		return
+	}
+	encodeUint64(b, tag, x)
+}
+
+func encodeInt64(b *buffer, tag int, x int64) {
+	u := uint64(x)
+	encodeUint64(b, tag, u)
+}
+
+func encodeInt64Opt(b *buffer, tag int, x int64) {
+	if x == 0 {
+		return
+	}
+	encodeInt64(b, tag, x)
+}
+
+func encodeInt64s(b *buffer, tag int, x []int64) {
+	if len(x) > 2 {
+		// Use packed encoding
+		n1 := len(b.data)
+		for _, u := range x {
+			encodeVarint(b, uint64(u))
+		}
+		n2 := len(b.data)
+		encodeLength(b, tag, n2-n1)
+		n3 := len(b.data)
+		copy(b.tmp[:], b.data[n2:n3])
+		copy(b.data[n1+(n3-n2):], b.data[n1:n2])
+		copy(b.data[n1:], b.tmp[:n3-n2])
+		return
+	}
+	for _, u := range x {
+		encodeInt64(b, tag, u)
+	}
+}
+
+func encodeString(b *buffer, tag int, x string) {
+	encodeLength(b, tag, len(x))
+	b.data = append(b.data, x...)
+}
+
+func encodeStrings(b *buffer, tag int, x []string) {
+	for _, s := range x {
+		encodeString(b, tag, s)
+	}
+}
+
+func encodeStringOpt(b *buffer, tag int, x string) {
+	if x == "" {
+		return
+	}
+	encodeString(b, tag, x)
+}
+
+func encodeBool(b *buffer, tag int, x bool) {
+	if x {
+		encodeUint64(b, tag, 1)
+	} else {
+		encodeUint64(b, tag, 0)
+	}
+}
+
+func encodeBoolOpt(b *buffer, tag int, x bool) {
+	if x == false {
+		return
+	}
+	encodeBool(b, tag, x)
+}
+
+func encodeMessage(b *buffer, tag int, m message) {
+	n1 := len(b.data)
+	m.encode(b)
+	n2 := len(b.data)
+	encodeLength(b, tag, n2-n1)
+	n3 := len(b.data)
+	copy(b.tmp[:], b.data[n2:n3])
+	copy(b.data[n1+(n3-n2):], b.data[n1:n2])
+	copy(b.data[n1:], b.tmp[:n3-n2])
+}
+
+func unmarshal(data []byte, m message) (err error) {
+	b := buffer{data: data, typ: 2}
+	return decodeMessage(&b, m)
+}
+
+func le64(p []byte) uint64 {
+	return uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
+}
+
+func le32(p []byte) uint32 {
+	return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+}
+
+func decodeVarint(data []byte) (uint64, []byte, error) {
+	var i int
+	var u uint64
+	for i = 0; ; i++ {
+		if i >= 10 || i >= len(data) {
+			return 0, nil, errors.New("bad varint")
+		}
+		u |= uint64(data[i]&0x7F) << uint(7*i)
+		if data[i]&0x80 == 0 {
+			return u, data[i+1:], nil
+		}
+	}
+}
+
+func decodeField(b *buffer, data []byte) ([]byte, error) {
+	x, data, err := decodeVarint(data)
+	if err != nil {
+		return nil, err
+	}
+	b.field = int(x >> 3)
+	b.typ = int(x & 7)
+	b.data = nil
+	b.u64 = 0
+	switch b.typ {
+	case 0:
+		b.u64, data, err = decodeVarint(data)
+		if err != nil {
+			return nil, err
+		}
+	case 1:
+		if len(data) < 8 {
+			return nil, errors.New("not enough data")
+		}
+		b.u64 = le64(data[:8])
+		data = data[8:]
+	case 2:
+		var n uint64
+		n, data, err = decodeVarint(data)
+		if err != nil {
+			return nil, err
+		}
+		if n > uint64(len(data)) {
+			return nil, errors.New("too much data")
+		}
+		b.data = data[:n]
+		data = data[n:]
+	case 5:
+		if len(data) < 4 {
+			return nil, errors.New("not enough data")
+		}
+		b.u64 = uint64(le32(data[:4]))
+		data = data[4:]
+	default:
+		return nil, errors.New("unknown type: " + string(b.typ))
+	}
+
+	return data, nil
+}
+
+func checkType(b *buffer, typ int) error {
+	if b.typ != typ {
+		return errors.New("type mismatch")
+	}
+	return nil
+}
+
+func decodeMessage(b *buffer, m message) error {
+	if err := checkType(b, 2); err != nil {
+		return err
+	}
+	dec := m.decoder()
+	data := b.data
+	for len(data) > 0 {
+		// pull varint field# + type
+		var err error
+		data, err = decodeField(b, data)
+		if err != nil {
+			return err
+		}
+		if b.field >= len(dec) || dec[b.field] == nil {
+			continue
+		}
+		if err := dec[b.field](b, m); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func decodeInt64(b *buffer, x *int64) error {
+	if err := checkType(b, 0); err != nil {
+		return err
+	}
+	*x = int64(b.u64)
+	return nil
+}
+
+func decodeInt64s(b *buffer, x *[]int64) error {
+	if b.typ == 2 {
+		// Packed encoding
+		data := b.data
+		for len(data) > 0 {
+			var u uint64
+			var err error
+
+			if u, data, err = decodeVarint(data); err != nil {
+				return err
+			}
+			*x = append(*x, int64(u))
+		}
+		return nil
+	}
+	var i int64
+	if err := decodeInt64(b, &i); err != nil {
+		return err
+	}
+	*x = append(*x, i)
+	return nil
+}
+
+func decodeUint64(b *buffer, x *uint64) error {
+	if err := checkType(b, 0); err != nil {
+		return err
+	}
+	*x = b.u64
+	return nil
+}
+
+func decodeUint64s(b *buffer, x *[]uint64) error {
+	if b.typ == 2 {
+		data := b.data
+		// Packed encoding
+		for len(data) > 0 {
+			var u uint64
+			var err error
+
+			if u, data, err = decodeVarint(data); err != nil {
+				return err
+			}
+			*x = append(*x, u)
+		}
+		return nil
+	}
+	var u uint64
+	if err := decodeUint64(b, &u); err != nil {
+		return err
+	}
+	*x = append(*x, u)
+	return nil
+}
+
+func decodeString(b *buffer, x *string) error {
+	if err := checkType(b, 2); err != nil {
+		return err
+	}
+	*x = string(b.data)
+	return nil
+}
+
+func decodeStrings(b *buffer, x *[]string) error {
+	var s string
+	if err := decodeString(b, &s); err != nil {
+		return err
+	}
+	*x = append(*x, s)
+	return nil
+}
+
+func decodeBool(b *buffer, x *bool) error {
+	if err := checkType(b, 0); err != nil {
+		return err
+	}
+	if int64(b.u64) == 0 {
+		*x = false
+	} else {
+		*x = true
+	}
+	return nil
+}
diff --git a/src/cmd/internal/pprof/profile/proto_test.go b/src/cmd/internal/pprof/profile/proto_test.go
new file mode 100644
index 0000000..c2613fc
--- /dev/null
+++ b/src/cmd/internal/pprof/profile/proto_test.go
@@ -0,0 +1,67 @@
+package profile
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestPackedEncoding(t *testing.T) {
+
+	type testcase struct {
+		uint64s []uint64
+		int64s  []int64
+		encoded []byte
+	}
+	for i, tc := range []testcase{
+		{
+			[]uint64{0, 1, 10, 100, 1000, 10000},
+			[]int64{1000, 0, 1000},
+			[]byte{10, 8, 0, 1, 10, 100, 232, 7, 144, 78, 18, 5, 232, 7, 0, 232, 7},
+		},
+		{
+			[]uint64{10000},
+			nil,
+			[]byte{8, 144, 78},
+		},
+		{
+			nil,
+			[]int64{-10000},
+			[]byte{16, 240, 177, 255, 255, 255, 255, 255, 255, 255, 1},
+		},
+	} {
+		source := &packedInts{tc.uint64s, tc.int64s}
+		if got, want := marshal(source), tc.encoded; !reflect.DeepEqual(got, want) {
+			t.Errorf("failed encode %d, got %v, want %v", i, got, want)
+		}
+
+		dest := new(packedInts)
+		if err := unmarshal(tc.encoded, dest); err != nil {
+			t.Errorf("failed decode %d: %v", i, err)
+			continue
+		}
+		if got, want := dest.uint64s, tc.uint64s; !reflect.DeepEqual(got, want) {
+			t.Errorf("failed decode uint64s %d, got %v, want %v", i, got, want)
+		}
+		if got, want := dest.int64s, tc.int64s; !reflect.DeepEqual(got, want) {
+			t.Errorf("failed decode int64s %d, got %v, want %v", i, got, want)
+		}
+	}
+}
+
+type packedInts struct {
+	uint64s []uint64
+	int64s  []int64
+}
+
+func (u *packedInts) decoder() []decoder {
+	return []decoder{
+		nil,
+		func(b *buffer, m message) error { return decodeUint64s(b, &m.(*packedInts).uint64s) },
+		func(b *buffer, m message) error { return decodeInt64s(b, &m.(*packedInts).int64s) },
+	}
+}
+
+func (u *packedInts) encode(b *buffer) {
+	encodeUint64s(b, 1, u.uint64s)
+	encodeInt64s(b, 2, u.int64s)
+}
diff --git a/src/cmd/internal/pprof/profile/prune.go b/src/cmd/internal/pprof/profile/prune.go
new file mode 100644
index 0000000..1924fad
--- /dev/null
+++ b/src/cmd/internal/pprof/profile/prune.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.
+
+// Implements methods to remove frames from profiles.
+
+package profile
+
+import (
+	"fmt"
+	"regexp"
+)
+
+// Prune removes all nodes beneath a node matching dropRx, and not
+// matching keepRx. If the root node of a Sample matches, the sample
+// will have an empty stack.
+func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
+	prune := make(map[uint64]bool)
+	pruneBeneath := make(map[uint64]bool)
+
+	for _, loc := range p.Location {
+		var i int
+		for i = len(loc.Line) - 1; i >= 0; i-- {
+			if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
+				funcName := fn.Name
+				// Account for leading '.' on the PPC ELF v1 ABI.
+				if funcName[0] == '.' {
+					funcName = funcName[1:]
+				}
+				if dropRx.MatchString(funcName) {
+					if keepRx == nil || !keepRx.MatchString(funcName) {
+						break
+					}
+				}
+			}
+		}
+
+		if i >= 0 {
+			// Found matching entry to prune.
+			pruneBeneath[loc.ID] = true
+
+			// Remove the matching location.
+			if i == len(loc.Line)-1 {
+				// Matched the top entry: prune the whole location.
+				prune[loc.ID] = true
+			} else {
+				loc.Line = loc.Line[i+1:]
+			}
+		}
+	}
+
+	// Prune locs from each Sample
+	for _, sample := range p.Sample {
+		// Scan from the root to the leaves to find the prune location.
+		// Do not prune frames before the first user frame, to avoid
+		// pruning everything.
+		foundUser := false
+		for i := len(sample.Location) - 1; i >= 0; i-- {
+			id := sample.Location[i].ID
+			if !prune[id] && !pruneBeneath[id] {
+				foundUser = true
+				continue
+			}
+			if !foundUser {
+				continue
+			}
+			if prune[id] {
+				sample.Location = sample.Location[i+1:]
+				break
+			}
+			if pruneBeneath[id] {
+				sample.Location = sample.Location[i:]
+				break
+			}
+		}
+	}
+}
+
+// RemoveUninteresting prunes and elides profiles using built-in
+// tables of uninteresting function names.
+func (p *Profile) RemoveUninteresting() error {
+	var keep, drop *regexp.Regexp
+	var err error
+
+	if p.DropFrames != "" {
+		if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil {
+			return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err)
+		}
+		if p.KeepFrames != "" {
+			if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil {
+				return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err)
+			}
+		}
+		p.Prune(drop, keep)
+	}
+	return nil
+}
diff --git a/src/cmd/internal/pprof/report/report.go b/src/cmd/internal/pprof/report/report.go
new file mode 100644
index 0000000..b11ad2a
--- /dev/null
+++ b/src/cmd/internal/pprof/report/report.go
@@ -0,0 +1,1684 @@
+// 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 report summarizes a performance profile into a
+// human-readable report.
+package report
+
+import (
+	"fmt"
+	"io"
+	"math"
+	"path/filepath"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+
+	"cmd/internal/pprof/plugin"
+	"cmd/internal/pprof/profile"
+)
+
+// Generate generates a report as directed by the Report.
+func Generate(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
+	o := rpt.options
+
+	switch o.OutputFormat {
+	case Dot:
+		return printDOT(w, rpt)
+	case Tree:
+		return printTree(w, rpt)
+	case Text:
+		return printText(w, rpt)
+	case Raw:
+		fmt.Fprint(w, rpt.prof.String())
+		return nil
+	case Tags:
+		return printTags(w, rpt)
+	case Proto:
+		return rpt.prof.Write(w)
+	case Dis:
+		return printAssembly(w, rpt, obj)
+	case List:
+		return printSource(w, rpt)
+	case WebList:
+		return printWebSource(w, rpt, obj)
+	case Callgrind:
+		return printCallgrind(w, rpt)
+	}
+	return fmt.Errorf("unexpected output format")
+}
+
+// printAssembly prints an annotated assembly listing.
+func printAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
+	g, err := newGraph(rpt)
+	if err != nil {
+		return err
+	}
+
+	o := rpt.options
+	prof := rpt.prof
+
+	// If the regexp source can be parsed as an address, also match
+	// functions that land on that address.
+	var address *uint64
+	if hex, err := strconv.ParseUint(o.Symbol.String(), 0, 64); err == nil {
+		address = &hex
+	}
+
+	fmt.Fprintln(w, "Total:", rpt.formatValue(rpt.total))
+	symbols := symbolsFromBinaries(prof, g, o.Symbol, address, obj)
+	symNodes := nodesPerSymbol(g.ns, symbols)
+	// Sort function names for printing.
+	var syms objSymbols
+	for s := range symNodes {
+		syms = append(syms, s)
+	}
+	sort.Sort(syms)
+
+	// Correlate the symbols from the binary with the profile samples.
+	for _, s := range syms {
+		sns := symNodes[s]
+
+		// Gather samples for this symbol.
+		flatSum, cumSum := sumNodes(sns)
+
+		// Get the function assembly.
+		insns, err := obj.Disasm(s.sym.File, s.sym.Start, s.sym.End)
+		if err != nil {
+			return err
+		}
+
+		ns := annotateAssembly(insns, sns, s.base)
+
+		fmt.Fprintf(w, "ROUTINE ======================== %s\n", s.sym.Name[0])
+		for _, name := range s.sym.Name[1:] {
+			fmt.Fprintf(w, "    AKA ======================== %s\n", name)
+		}
+		fmt.Fprintf(w, "%10s %10s (flat, cum) %s of Total\n",
+			rpt.formatValue(flatSum), rpt.formatValue(cumSum),
+			percentage(cumSum, rpt.total))
+
+		for _, n := range ns {
+			fmt.Fprintf(w, "%10s %10s %10x: %s\n", valueOrDot(n.flat, rpt), valueOrDot(n.cum, rpt), n.info.address, n.info.name)
+		}
+	}
+	return nil
+}
+
+// symbolsFromBinaries examines the binaries listed on the profile
+// that have associated samples, and identifies symbols matching rx.
+func symbolsFromBinaries(prof *profile.Profile, g graph, rx *regexp.Regexp, address *uint64, obj plugin.ObjTool) []*objSymbol {
+	hasSamples := make(map[string]bool)
+	// Only examine mappings that have samples that match the
+	// regexp. This is an optimization to speed up pprof.
+	for _, n := range g.ns {
+		if name := n.info.prettyName(); rx.MatchString(name) && n.info.objfile != "" {
+			hasSamples[n.info.objfile] = true
+		}
+	}
+
+	// Walk all mappings looking for matching functions with samples.
+	var objSyms []*objSymbol
+	for _, m := range prof.Mapping {
+		if !hasSamples[filepath.Base(m.File)] {
+			if address == nil || !(m.Start <= *address && *address <= m.Limit) {
+				continue
+			}
+		}
+
+		f, err := obj.Open(m.File, m.Start)
+		if err != nil {
+			fmt.Printf("%v\n", err)
+			continue
+		}
+
+		// Find symbols in this binary matching the user regexp.
+		var addr uint64
+		if address != nil {
+			addr = *address
+		}
+		msyms, err := f.Symbols(rx, addr)
+		base := f.Base()
+		f.Close()
+		if err != nil {
+			continue
+		}
+		for _, ms := range msyms {
+			objSyms = append(objSyms,
+				&objSymbol{
+					sym:  ms,
+					base: base,
+				},
+			)
+		}
+	}
+
+	return objSyms
+}
+
+// objSym represents a symbol identified from a binary. It includes
+// the SymbolInfo from the disasm package and the base that must be
+// added to correspond to sample addresses
+type objSymbol struct {
+	sym  *plugin.Sym
+	base uint64
+}
+
+// objSymbols is a wrapper type to enable sorting of []*objSymbol.
+type objSymbols []*objSymbol
+
+func (o objSymbols) Len() int {
+	return len(o)
+}
+
+func (o objSymbols) Less(i, j int) bool {
+	if namei, namej := o[i].sym.Name[0], o[j].sym.Name[0]; namei != namej {
+		return namei < namej
+	}
+	return o[i].sym.Start < o[j].sym.Start
+}
+
+func (o objSymbols) Swap(i, j int) {
+	o[i], o[j] = o[j], o[i]
+}
+
+// nodesPerSymbol classifies nodes into a group of symbols.
+func nodesPerSymbol(ns nodes, symbols []*objSymbol) map[*objSymbol]nodes {
+	symNodes := make(map[*objSymbol]nodes)
+	for _, s := range symbols {
+		// Gather samples for this symbol.
+		for _, n := range ns {
+			address := n.info.address - s.base
+			if address >= s.sym.Start && address < s.sym.End {
+				symNodes[s] = append(symNodes[s], n)
+			}
+		}
+	}
+	return symNodes
+}
+
+// annotateAssembly annotates a set of assembly instructions with a
+// set of samples. It returns a set of nodes to display.  base is an
+// offset to adjust the sample addresses.
+func annotateAssembly(insns []plugin.Inst, samples nodes, base uint64) nodes {
+	// Add end marker to simplify printing loop.
+	insns = append(insns, plugin.Inst{
+		Addr: ^uint64(0),
+	})
+
+	// Ensure samples are sorted by address.
+	samples.sort(addressOrder)
+
+	var s int
+	var asm nodes
+	for ix, in := range insns[:len(insns)-1] {
+		n := node{
+			info: nodeInfo{
+				address: in.Addr,
+				name:    in.Text,
+				file:    trimPath(in.File),
+				lineno:  in.Line,
+			},
+		}
+
+		// Sum all the samples until the next instruction (to account
+		// for samples attributed to the middle of an instruction).
+		for next := insns[ix+1].Addr; s < len(samples) && samples[s].info.address-base < next; s++ {
+			n.flat += samples[s].flat
+			n.cum += samples[s].cum
+			if samples[s].info.file != "" {
+				n.info.file = trimPath(samples[s].info.file)
+				n.info.lineno = samples[s].info.lineno
+			}
+		}
+		asm = append(asm, &n)
+	}
+
+	return asm
+}
+
+// valueOrDot formats a value according to a report, intercepting zero
+// values.
+func valueOrDot(value int64, rpt *Report) string {
+	if value == 0 {
+		return "."
+	}
+	return rpt.formatValue(value)
+}
+
+// printTags collects all tags referenced in the profile and prints
+// them in a sorted table.
+func printTags(w io.Writer, rpt *Report) error {
+	p := rpt.prof
+
+	// Hashtable to keep accumulate tags as key,value,count.
+	tagMap := make(map[string]map[string]int64)
+	for _, s := range p.Sample {
+		for key, vals := range s.Label {
+			for _, val := range vals {
+				if valueMap, ok := tagMap[key]; ok {
+					valueMap[val] = valueMap[val] + s.Value[0]
+					continue
+				}
+				valueMap := make(map[string]int64)
+				valueMap[val] = s.Value[0]
+				tagMap[key] = valueMap
+			}
+		}
+		for key, vals := range s.NumLabel {
+			for _, nval := range vals {
+				val := scaledValueLabel(nval, key, "auto")
+				if valueMap, ok := tagMap[key]; ok {
+					valueMap[val] = valueMap[val] + s.Value[0]
+					continue
+				}
+				valueMap := make(map[string]int64)
+				valueMap[val] = s.Value[0]
+				tagMap[key] = valueMap
+			}
+		}
+	}
+
+	tagKeys := make(tags, 0, len(tagMap))
+	for key := range tagMap {
+		tagKeys = append(tagKeys, &tag{name: key})
+	}
+	sort.Sort(tagKeys)
+
+	for _, tagKey := range tagKeys {
+		var total int64
+		key := tagKey.name
+		tags := make(tags, 0, len(tagMap[key]))
+		for t, c := range tagMap[key] {
+			total += c
+			tags = append(tags, &tag{name: t, weight: c})
+		}
+
+		sort.Sort(tags)
+		fmt.Fprintf(w, "%s: Total %d\n", key, total)
+		for _, t := range tags {
+			if total > 0 {
+				fmt.Fprintf(w, "  %8d (%s): %s\n", t.weight,
+					percentage(t.weight, total), t.name)
+			} else {
+				fmt.Fprintf(w, "  %8d: %s\n", t.weight, t.name)
+			}
+		}
+		fmt.Fprintln(w)
+	}
+	return nil
+}
+
+// printText prints a flat text report for a profile.
+func printText(w io.Writer, rpt *Report) error {
+	g, err := newGraph(rpt)
+	if err != nil {
+		return err
+	}
+
+	origCount, droppedNodes, _ := g.preprocess(rpt)
+	fmt.Fprintln(w, strings.Join(legendDetailLabels(rpt, g, origCount, droppedNodes, 0), "\n"))
+
+	fmt.Fprintf(w, "%10s %5s%% %5s%% %10s %5s%%\n",
+		"flat", "flat", "sum", "cum", "cum")
+
+	var flatSum int64
+	for _, n := range g.ns {
+		name, flat, cum := n.info.prettyName(), n.flat, n.cum
+
+		flatSum += flat
+		fmt.Fprintf(w, "%10s %s %s %10s %s  %s\n",
+			rpt.formatValue(flat),
+			percentage(flat, rpt.total),
+			percentage(flatSum, rpt.total),
+			rpt.formatValue(cum),
+			percentage(cum, rpt.total),
+			name)
+	}
+	return nil
+}
+
+// printCallgrind prints a graph for a profile on callgrind format.
+func printCallgrind(w io.Writer, rpt *Report) error {
+	g, err := newGraph(rpt)
+	if err != nil {
+		return err
+	}
+
+	o := rpt.options
+	rpt.options.NodeFraction = 0
+	rpt.options.EdgeFraction = 0
+	rpt.options.NodeCount = 0
+
+	g.preprocess(rpt)
+
+	fmt.Fprintln(w, "events:", o.SampleType+"("+o.OutputUnit+")")
+
+	files := make(map[string]int)
+	names := make(map[string]int)
+	for _, n := range g.ns {
+		fmt.Fprintln(w, "fl="+callgrindName(files, n.info.file))
+		fmt.Fprintln(w, "fn="+callgrindName(names, n.info.name))
+		sv, _ := ScaleValue(n.flat, o.SampleUnit, o.OutputUnit)
+		fmt.Fprintf(w, "%d %d\n", n.info.lineno, int(sv))
+
+		// Print outgoing edges.
+		for _, out := range sortedEdges(n.out) {
+			c, _ := ScaleValue(out.weight, o.SampleUnit, o.OutputUnit)
+			count := fmt.Sprintf("%d", int(c))
+			callee := out.dest
+			fmt.Fprintln(w, "cfl="+callgrindName(files, callee.info.file))
+			fmt.Fprintln(w, "cfn="+callgrindName(names, callee.info.name))
+			fmt.Fprintln(w, "calls="+count, callee.info.lineno)
+			fmt.Fprintln(w, n.info.lineno, count)
+		}
+		fmt.Fprintln(w)
+	}
+
+	return nil
+}
+
+// callgrindName implements the callgrind naming compression scheme.
+// For names not previously seen returns "(N) name", where N is a
+// unique index. For names previously seen returns "(N)" where N is
+// the index returned the first time.
+func callgrindName(names map[string]int, name string) string {
+	if name == "" {
+		return ""
+	}
+	if id, ok := names[name]; ok {
+		return fmt.Sprintf("(%d)", id)
+	}
+	id := len(names) + 1
+	names[name] = id
+	return fmt.Sprintf("(%d) %s", id, name)
+}
+
+// printTree prints a tree-based report in text form.
+func printTree(w io.Writer, rpt *Report) error {
+	const separator = "----------------------------------------------------------+-------------"
+	const legend = "      flat  flat%   sum%        cum   cum%   calls calls% + context 	 	 "
+
+	g, err := newGraph(rpt)
+	if err != nil {
+		return err
+	}
+
+	origCount, droppedNodes, _ := g.preprocess(rpt)
+	fmt.Fprintln(w, strings.Join(legendDetailLabels(rpt, g, origCount, droppedNodes, 0), "\n"))
+
+	fmt.Fprintln(w, separator)
+	fmt.Fprintln(w, legend)
+	var flatSum int64
+
+	rx := rpt.options.Symbol
+	for _, n := range g.ns {
+		name, flat, cum := n.info.prettyName(), n.flat, n.cum
+
+		// Skip any entries that do not match the regexp (for the "peek" command).
+		if rx != nil && !rx.MatchString(name) {
+			continue
+		}
+
+		fmt.Fprintln(w, separator)
+		// Print incoming edges.
+		inEdges := sortedEdges(n.in)
+		inSum := inEdges.sum()
+		for _, in := range inEdges {
+			fmt.Fprintf(w, "%50s %s |   %s\n", rpt.formatValue(in.weight),
+				percentage(in.weight, inSum), in.src.info.prettyName())
+		}
+
+		// Print current node.
+		flatSum += flat
+		fmt.Fprintf(w, "%10s %s %s %10s %s                | %s\n",
+			rpt.formatValue(flat),
+			percentage(flat, rpt.total),
+			percentage(flatSum, rpt.total),
+			rpt.formatValue(cum),
+			percentage(cum, rpt.total),
+			name)
+
+		// Print outgoing edges.
+		outEdges := sortedEdges(n.out)
+		outSum := outEdges.sum()
+		for _, out := range outEdges {
+			fmt.Fprintf(w, "%50s %s |   %s\n", rpt.formatValue(out.weight),
+				percentage(out.weight, outSum), out.dest.info.prettyName())
+		}
+	}
+	if len(g.ns) > 0 {
+		fmt.Fprintln(w, separator)
+	}
+	return nil
+}
+
+// printDOT prints an annotated callgraph in DOT format.
+func printDOT(w io.Writer, rpt *Report) error {
+	g, err := newGraph(rpt)
+	if err != nil {
+		return err
+	}
+
+	origCount, droppedNodes, droppedEdges := g.preprocess(rpt)
+
+	prof := rpt.prof
+	graphname := "unnamed"
+	if len(prof.Mapping) > 0 {
+		graphname = filepath.Base(prof.Mapping[0].File)
+	}
+	fmt.Fprintln(w, `digraph "`+graphname+`" {`)
+	fmt.Fprintln(w, `node [style=filled fillcolor="#f8f8f8"]`)
+	fmt.Fprintln(w, dotLegend(rpt, g, origCount, droppedNodes, droppedEdges))
+
+	if len(g.ns) == 0 {
+		fmt.Fprintln(w, "}")
+		return nil
+	}
+
+	// Make sure nodes have a unique consistent id.
+	nodeIndex := make(map[*node]int)
+	maxFlat := float64(g.ns[0].flat)
+	for i, n := range g.ns {
+		nodeIndex[n] = i + 1
+		if float64(n.flat) > maxFlat {
+			maxFlat = float64(n.flat)
+		}
+	}
+	var edges edgeList
+	for _, n := range g.ns {
+		node := dotNode(rpt, maxFlat, nodeIndex[n], n)
+		fmt.Fprintln(w, node)
+		if nodelets := dotNodelets(rpt, nodeIndex[n], n); nodelets != "" {
+			fmt.Fprint(w, nodelets)
+		}
+
+		// Collect outgoing edges.
+		for _, e := range n.out {
+			edges = append(edges, e)
+		}
+	}
+	// Sort edges by frequency as a hint to the graph layout engine.
+	sort.Sort(edges)
+	for _, e := range edges {
+		fmt.Fprintln(w, dotEdge(rpt, nodeIndex[e.src], nodeIndex[e.dest], e))
+	}
+	fmt.Fprintln(w, "}")
+	return nil
+}
+
+// percentage computes the percentage of total of a value, and encodes
+// it as a string. At least two digits of precision are printed.
+func percentage(value, total int64) string {
+	var ratio float64
+	if total != 0 {
+		ratio = float64(value) / float64(total) * 100
+	}
+	switch {
+	case ratio >= 99.95:
+		return "  100%"
+	case ratio >= 1.0:
+		return fmt.Sprintf("%5.2f%%", ratio)
+	default:
+		return fmt.Sprintf("%5.2g%%", ratio)
+	}
+}
+
+// dotLegend generates the overall graph label for a report in DOT format.
+func dotLegend(rpt *Report, g graph, origCount, droppedNodes, droppedEdges int) string {
+	label := legendLabels(rpt)
+	label = append(label, legendDetailLabels(rpt, g, origCount, droppedNodes, droppedEdges)...)
+	return fmt.Sprintf(`subgraph cluster_L { L [shape=box fontsize=32 label="%s\l"] }`, strings.Join(label, `\l`))
+}
+
+// legendLabels generates labels exclusive to graph visualization.
+func legendLabels(rpt *Report) []string {
+	prof := rpt.prof
+	o := rpt.options
+	var label []string
+	if len(prof.Mapping) > 0 {
+		if prof.Mapping[0].File != "" {
+			label = append(label, "File: "+filepath.Base(prof.Mapping[0].File))
+		}
+		if prof.Mapping[0].BuildID != "" {
+			label = append(label, "Build ID: "+prof.Mapping[0].BuildID)
+		}
+	}
+	if o.SampleType != "" {
+		label = append(label, "Type: "+o.SampleType)
+	}
+	if prof.TimeNanos != 0 {
+		const layout = "Jan 2, 2006 at 3:04pm (MST)"
+		label = append(label, "Time: "+time.Unix(0, prof.TimeNanos).Format(layout))
+	}
+	if prof.DurationNanos != 0 {
+		label = append(label, fmt.Sprintf("Duration: %v", time.Duration(prof.DurationNanos)))
+	}
+	return label
+}
+
+// legendDetailLabels generates labels common to graph and text visualization.
+func legendDetailLabels(rpt *Report, g graph, origCount, droppedNodes, droppedEdges int) []string {
+	nodeFraction := rpt.options.NodeFraction
+	edgeFraction := rpt.options.EdgeFraction
+	nodeCount := rpt.options.NodeCount
+
+	label := []string{}
+
+	var flatSum int64
+	for _, n := range g.ns {
+		flatSum = flatSum + n.flat
+	}
+
+	label = append(label, fmt.Sprintf("%s of %s total (%s)", rpt.formatValue(flatSum), rpt.formatValue(rpt.total), percentage(flatSum, rpt.total)))
+
+	if rpt.total > 0 {
+		if droppedNodes > 0 {
+			label = append(label, genLabel(droppedNodes, "node", "cum",
+				rpt.formatValue(int64(float64(rpt.total)*nodeFraction))))
+		}
+		if droppedEdges > 0 {
+			label = append(label, genLabel(droppedEdges, "edge", "freq",
+				rpt.formatValue(int64(float64(rpt.total)*edgeFraction))))
+		}
+		if nodeCount > 0 && nodeCount < origCount {
+			label = append(label, fmt.Sprintf("Showing top %d nodes out of %d (cum >= %s)",
+				nodeCount, origCount,
+				rpt.formatValue(g.ns[len(g.ns)-1].cum)))
+		}
+	}
+	return label
+}
+
+func genLabel(d int, n, l, f string) string {
+	if d > 1 {
+		n = n + "s"
+	}
+	return fmt.Sprintf("Dropped %d %s (%s <= %s)", d, n, l, f)
+}
+
+// dotNode generates a graph node in DOT format.
+func dotNode(rpt *Report, maxFlat float64, rIndex int, n *node) string {
+	flat, cum := n.flat, n.cum
+
+	labels := strings.Split(n.info.prettyName(), "::")
+	label := strings.Join(labels, `\n`) + `\n`
+
+	flatValue := rpt.formatValue(flat)
+	if flat > 0 {
+		label = label + fmt.Sprintf(`%s(%s)`,
+			flatValue,
+			strings.TrimSpace(percentage(flat, rpt.total)))
+	} else {
+		label = label + "0"
+	}
+	cumValue := flatValue
+	if cum != flat {
+		if flat > 0 {
+			label = label + `\n`
+		} else {
+			label = label + " "
+		}
+		cumValue = rpt.formatValue(cum)
+		label = label + fmt.Sprintf(`of %s(%s)`,
+			cumValue,
+			strings.TrimSpace(percentage(cum, rpt.total)))
+	}
+
+	// Scale font sizes from 8 to 24 based on percentage of flat frequency.
+	// Use non linear growth to emphasize the size difference.
+	baseFontSize, maxFontGrowth := 8, 16.0
+	fontSize := baseFontSize
+	if maxFlat > 0 && flat > 0 && float64(flat) <= maxFlat {
+		fontSize += int(math.Ceil(maxFontGrowth * math.Sqrt(float64(flat)/maxFlat)))
+	}
+	return fmt.Sprintf(`N%d [label="%s" fontsize=%d shape=box tooltip="%s (%s)"]`,
+		rIndex,
+		label,
+		fontSize, n.info.prettyName(), cumValue)
+}
+
+// dotEdge generates a graph edge in DOT format.
+func dotEdge(rpt *Report, from, to int, e *edgeInfo) string {
+	w := rpt.formatValue(e.weight)
+	attr := fmt.Sprintf(`label=" %s"`, w)
+	if rpt.total > 0 {
+		if weight := 1 + int(e.weight*100/rpt.total); weight > 1 {
+			attr = fmt.Sprintf(`%s weight=%d`, attr, weight)
+		}
+		if width := 1 + int(e.weight*5/rpt.total); width > 1 {
+			attr = fmt.Sprintf(`%s penwidth=%d`, attr, width)
+		}
+	}
+	arrow := "->"
+	if e.residual {
+		arrow = "..."
+	}
+	tooltip := fmt.Sprintf(`"%s %s %s (%s)"`,
+		e.src.info.prettyName(), arrow, e.dest.info.prettyName(), w)
+	attr = fmt.Sprintf(`%s tooltip=%s labeltooltip=%s`,
+		attr, tooltip, tooltip)
+
+	if e.residual {
+		attr = attr + ` style="dotted"`
+	}
+
+	if len(e.src.tags) > 0 {
+		// Separate children further if source has tags.
+		attr = attr + " minlen=2"
+	}
+	return fmt.Sprintf("N%d -> N%d [%s]", from, to, attr)
+}
+
+// dotNodelets generates the DOT boxes for the node tags.
+func dotNodelets(rpt *Report, rIndex int, n *node) (dot string) {
+	const maxNodelets = 4    // Number of nodelets for alphanumeric labels
+	const maxNumNodelets = 4 // Number of nodelets for numeric labels
+
+	var ts, nts tags
+	for _, t := range n.tags {
+		if t.unit == "" {
+			ts = append(ts, t)
+		} else {
+			nts = append(nts, t)
+		}
+	}
+
+	// Select the top maxNodelets alphanumeric labels by weight
+	sort.Sort(ts)
+	if len(ts) > maxNodelets {
+		ts = ts[:maxNodelets]
+	}
+	for i, t := range ts {
+		weight := rpt.formatValue(t.weight)
+		dot += fmt.Sprintf(`N%d_%d [label = "%s" fontsize=8 shape=box3d tooltip="%s"]`+"\n", rIndex, i, t.name, weight)
+		dot += fmt.Sprintf(`N%d -> N%d_%d [label=" %s" weight=100 tooltip="\L" labeltooltip="\L"]`+"\n", rIndex, rIndex, i, weight)
+	}
+
+	// Collapse numeric labels into maxNumNodelets buckets, of the form:
+	// 1MB..2MB, 3MB..5MB, ...
+	nts = collapseTags(nts, maxNumNodelets)
+	sort.Sort(nts)
+	for i, t := range nts {
+		weight := rpt.formatValue(t.weight)
+		dot += fmt.Sprintf(`NN%d_%d [label = "%s" fontsize=8 shape=box3d tooltip="%s"]`+"\n", rIndex, i, t.name, weight)
+		dot += fmt.Sprintf(`N%d -> NN%d_%d [label=" %s" weight=100 tooltip="\L" labeltooltip="\L"]`+"\n", rIndex, rIndex, i, weight)
+	}
+
+	return dot
+}
+
+// graph summarizes a performance profile into a format that is
+// suitable for visualization.
+type graph struct {
+	ns nodes
+}
+
+// nodes is an ordered collection of graph nodes.
+type nodes []*node
+
+// tags represent sample annotations
+type tags []*tag
+type tagMap map[string]*tag
+
+type tag struct {
+	name   string
+	unit   string // Describe the value, "" for non-numeric tags
+	value  int64
+	weight int64
+}
+
+func (t tags) Len() int      { return len(t) }
+func (t tags) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
+func (t tags) Less(i, j int) bool {
+	if t[i].weight == t[j].weight {
+		return t[i].name < t[j].name
+	}
+	return t[i].weight > t[j].weight
+}
+
+// node is an entry on a profiling report. It represents a unique
+// program location. It can include multiple names to represent
+// inlined functions.
+type node struct {
+	info nodeInfo // Information associated to this entry.
+
+	// values associated to this node.
+	// flat is exclusive to this node, cum includes all descendents.
+	flat, cum int64
+
+	// in and out contains the nodes immediately reaching or reached by this nodes.
+	in, out edgeMap
+
+	// tags provide additional information about subsets of a sample.
+	tags tagMap
+}
+
+type nodeInfo struct {
+	name              string
+	origName          string
+	address           uint64
+	file              string
+	startLine, lineno int
+	inline            bool
+	lowPriority       bool
+	objfile           string
+	parent            *node // Used only if creating a calltree
+}
+
+func (n *node) addTags(s *profile.Sample, weight int64) {
+	// Add a tag with all string labels
+	var labels []string
+	for key, vals := range s.Label {
+		for _, v := range vals {
+			labels = append(labels, key+":"+v)
+		}
+	}
+	if len(labels) > 0 {
+		sort.Strings(labels)
+		l := n.tags.findOrAddTag(strings.Join(labels, `\n`), "", 0)
+		l.weight += weight
+	}
+
+	for key, nvals := range s.NumLabel {
+		for _, v := range nvals {
+			label := scaledValueLabel(v, key, "auto")
+			l := n.tags.findOrAddTag(label, key, v)
+			l.weight += weight
+		}
+	}
+}
+
+func (m tagMap) findOrAddTag(label, unit string, value int64) *tag {
+	if l := m[label]; l != nil {
+		return l
+	}
+	l := &tag{
+		name:  label,
+		unit:  unit,
+		value: value,
+	}
+	m[label] = l
+	return l
+}
+
+// collapseTags reduces the number of entries in a tagMap by merging
+// adjacent nodes into ranges. It uses a greedy approach to merge
+// starting with the entries with the lowest weight.
+func collapseTags(ts tags, count int) tags {
+	if len(ts) <= count {
+		return ts
+	}
+
+	sort.Sort(ts)
+	tagGroups := make([]tags, count)
+	for i, t := range ts[:count] {
+		tagGroups[i] = tags{t}
+	}
+	for _, t := range ts[count:] {
+		g, d := 0, tagDistance(t, tagGroups[0][0])
+		for i := 1; i < count; i++ {
+			if nd := tagDistance(t, tagGroups[i][0]); nd < d {
+				g, d = i, nd
+			}
+		}
+		tagGroups[g] = append(tagGroups[g], t)
+	}
+
+	var nts tags
+	for _, g := range tagGroups {
+		l, w := tagGroupLabel(g)
+		nts = append(nts, &tag{
+			name:   l,
+			weight: w,
+		})
+	}
+	return nts
+}
+
+func tagDistance(t, u *tag) float64 {
+	v, _ := ScaleValue(u.value, u.unit, t.unit)
+	if v < float64(t.value) {
+		return float64(t.value) - v
+	}
+	return v - float64(t.value)
+}
+
+func tagGroupLabel(g tags) (string, int64) {
+	if len(g) == 1 {
+		t := g[0]
+		return scaledValueLabel(t.value, t.unit, "auto"), t.weight
+	}
+	min := g[0]
+	max := g[0]
+	w := min.weight
+	for _, t := range g[1:] {
+		if v, _ := ScaleValue(t.value, t.unit, min.unit); int64(v) < min.value {
+			min = t
+		}
+		if v, _ := ScaleValue(t.value, t.unit, max.unit); int64(v) > max.value {
+			max = t
+		}
+		w += t.weight
+	}
+	return scaledValueLabel(min.value, min.unit, "auto") + ".." +
+		scaledValueLabel(max.value, max.unit, "auto"), w
+}
+
+// sumNodes adds the flat and sum values on a report.
+func sumNodes(ns nodes) (flat int64, cum int64) {
+	for _, n := range ns {
+		flat += n.flat
+		cum += n.cum
+	}
+	return
+}
+
+type edgeMap map[*node]*edgeInfo
+
+// edgeInfo contains any attributes to be represented about edges in a graph/
+type edgeInfo struct {
+	src, dest *node
+	// The summary weight of the edge
+	weight int64
+	// residual edges connect nodes that were connected through a
+	// separate node, which has been removed from the report.
+	residual bool
+}
+
+// bumpWeight increases the weight of an edge. If there isn't such an
+// edge in the map one is created.
+func bumpWeight(from, to *node, w int64, residual bool) {
+	if from.out[to] != to.in[from] {
+		panic(fmt.Errorf("asymmetric edges %v %v", *from, *to))
+	}
+
+	if n := from.out[to]; n != nil {
+		n.weight += w
+		if n.residual && !residual {
+			n.residual = false
+		}
+		return
+	}
+
+	info := &edgeInfo{src: from, dest: to, weight: w, residual: residual}
+	from.out[to] = info
+	to.in[from] = info
+}
+
+// Output formats.
+const (
+	Proto = iota
+	Dot
+	Tags
+	Tree
+	Text
+	Raw
+	Dis
+	List
+	WebList
+	Callgrind
+)
+
+// Options are the formatting and filtering options used to generate a
+// profile.
+type Options struct {
+	OutputFormat int
+
+	CumSort        bool
+	CallTree       bool
+	PrintAddresses bool
+	DropNegative   bool
+	Ratio          float64
+
+	NodeCount    int
+	NodeFraction float64
+	EdgeFraction float64
+
+	SampleType string
+	SampleUnit string // Unit for the sample data from the profile.
+	OutputUnit string // Units for data formatting in report.
+
+	Symbol *regexp.Regexp // Symbols to include on disassembly report.
+}
+
+// newGraph summarizes performance data from a profile into a graph.
+func newGraph(rpt *Report) (g graph, err error) {
+	prof := rpt.prof
+	o := rpt.options
+
+	// Generate a tree for graphical output if requested.
+	buildTree := o.CallTree && o.OutputFormat == Dot
+
+	locations := make(map[uint64][]nodeInfo)
+	for _, l := range prof.Location {
+		locations[l.ID] = newLocInfo(l)
+	}
+
+	nm := make(nodeMap)
+	for _, sample := range prof.Sample {
+		if sample.Location == nil {
+			continue
+		}
+
+		// Construct list of node names for sample.
+		var stack []nodeInfo
+		for _, loc := range sample.Location {
+			id := loc.ID
+			stack = append(stack, locations[id]...)
+		}
+
+		// Upfront pass to update the parent chains, to prevent the
+		// merging of nodes with different parents.
+		if buildTree {
+			var nn *node
+			for i := len(stack); i > 0; i-- {
+				n := &stack[i-1]
+				n.parent = nn
+				nn = nm.findOrInsertNode(*n)
+			}
+		}
+
+		leaf := nm.findOrInsertNode(stack[0])
+		weight := rpt.sampleValue(sample)
+		leaf.addTags(sample, weight)
+
+		// Aggregate counter data.
+		leaf.flat += weight
+		seen := make(map[*node]bool)
+		var nn *node
+		for _, s := range stack {
+			n := nm.findOrInsertNode(s)
+			if !seen[n] {
+				seen[n] = true
+				n.cum += weight
+
+				if nn != nil {
+					bumpWeight(n, nn, weight, false)
+				}
+			}
+			nn = n
+		}
+	}
+
+	// Collect new nodes into a report.
+	ns := make(nodes, 0, len(nm))
+	for _, n := range nm {
+		if rpt.options.DropNegative && n.flat < 0 {
+			continue
+		}
+		ns = append(ns, n)
+	}
+
+	return graph{ns}, nil
+}
+
+// Create a slice of formatted names for a location.
+func newLocInfo(l *profile.Location) []nodeInfo {
+	var objfile string
+
+	if m := l.Mapping; m != nil {
+		objfile = filepath.Base(m.File)
+	}
+
+	if len(l.Line) == 0 {
+		return []nodeInfo{
+			{
+				address: l.Address,
+				objfile: objfile,
+			},
+		}
+	}
+	var info []nodeInfo
+	numInlineFrames := len(l.Line) - 1
+	for li, line := range l.Line {
+		ni := nodeInfo{
+			address: l.Address,
+			lineno:  int(line.Line),
+			inline:  li < numInlineFrames,
+			objfile: objfile,
+		}
+
+		if line.Function != nil {
+			ni.name = line.Function.Name
+			ni.origName = line.Function.SystemName
+			ni.file = line.Function.Filename
+			ni.startLine = int(line.Function.StartLine)
+		}
+
+		info = append(info, ni)
+	}
+	return info
+}
+
+// nodeMap maps from a node info struct to a node. It is used to merge
+// report entries with the same info.
+type nodeMap map[nodeInfo]*node
+
+func (m nodeMap) findOrInsertNode(info nodeInfo) *node {
+	rr := m[info]
+	if rr == nil {
+		rr = &node{
+			info: info,
+			in:   make(edgeMap),
+			out:  make(edgeMap),
+			tags: make(map[string]*tag),
+		}
+		m[info] = rr
+	}
+	return rr
+}
+
+// preprocess does any required filtering/sorting according to the
+// report options. Returns the mapping from each node to any nodes
+// removed by path compression and statistics on the nodes/edges removed.
+func (g *graph) preprocess(rpt *Report) (origCount, droppedNodes, droppedEdges int) {
+	o := rpt.options
+
+	// Compute total weight of current set of nodes.
+	// This is <= rpt.total because of node filtering.
+	var totalValue int64
+	for _, n := range g.ns {
+		totalValue += n.flat
+	}
+
+	// Remove nodes with value <= total*nodeFraction
+	if nodeFraction := o.NodeFraction; nodeFraction > 0 {
+		var removed nodes
+		minValue := int64(float64(totalValue) * nodeFraction)
+		kept := make(nodes, 0, len(g.ns))
+		for _, n := range g.ns {
+			if n.cum < minValue {
+				removed = append(removed, n)
+			} else {
+				kept = append(kept, n)
+				tagsKept := make(map[string]*tag)
+				for s, t := range n.tags {
+					if t.weight >= minValue {
+						tagsKept[s] = t
+					}
+				}
+				n.tags = tagsKept
+			}
+		}
+		droppedNodes = len(removed)
+		removeNodes(removed, false, false)
+		g.ns = kept
+	}
+
+	// Remove edges below minimum frequency.
+	if edgeFraction := o.EdgeFraction; edgeFraction > 0 {
+		minEdge := int64(float64(totalValue) * edgeFraction)
+		for _, n := range g.ns {
+			for src, e := range n.in {
+				if e.weight < minEdge {
+					delete(n.in, src)
+					delete(src.out, n)
+					droppedEdges++
+				}
+			}
+		}
+	}
+
+	sortOrder := flatName
+	if o.CumSort {
+		// Force cum sorting for graph output, to preserve connectivity.
+		sortOrder = cumName
+	}
+
+	// Nodes that have flat==0 and a single in/out do not provide much
+	// information. Give them first chance to be removed. Do not consider edges
+	// from/to nodes that are expected to be removed.
+	maxNodes := o.NodeCount
+	if o.OutputFormat == Dot {
+		if maxNodes > 0 && maxNodes < len(g.ns) {
+			sortOrder = cumName
+			g.ns.sort(cumName)
+			cumCutoff := g.ns[maxNodes].cum
+			for _, n := range g.ns {
+				if n.flat == 0 {
+					if count := countEdges(n.out, cumCutoff); count > 1 {
+						continue
+					}
+					if count := countEdges(n.in, cumCutoff); count != 1 {
+						continue
+					}
+					n.info.lowPriority = true
+				}
+			}
+		}
+	}
+
+	g.ns.sort(sortOrder)
+	if maxNodes > 0 {
+		origCount = len(g.ns)
+		for index, nodes := 0, 0; index < len(g.ns); index++ {
+			nodes++
+			// For DOT output, count the tags as nodes since we will draw
+			// boxes for them.
+			if o.OutputFormat == Dot {
+				nodes += len(g.ns[index].tags)
+			}
+			if nodes > maxNodes {
+				// Trim to the top n nodes. Create dotted edges to bridge any
+				// broken connections.
+				removeNodes(g.ns[index:], true, true)
+				g.ns = g.ns[:index]
+				break
+			}
+		}
+	}
+	removeRedundantEdges(g.ns)
+
+	// Select best unit for profile output.
+	// Find the appropriate units for the smallest non-zero sample
+	if o.OutputUnit == "minimum" && len(g.ns) > 0 {
+		var maxValue, minValue int64
+
+		for _, n := range g.ns {
+			if n.flat > 0 && (minValue == 0 || n.flat < minValue) {
+				minValue = n.flat
+			}
+			if n.cum > maxValue {
+				maxValue = n.cum
+			}
+		}
+		if r := o.Ratio; r > 0 && r != 1 {
+			minValue = int64(float64(minValue) * r)
+			maxValue = int64(float64(maxValue) * r)
+		}
+
+		_, minUnit := ScaleValue(minValue, o.SampleUnit, "minimum")
+		_, maxUnit := ScaleValue(maxValue, o.SampleUnit, "minimum")
+
+		unit := minUnit
+		if minUnit != maxUnit && minValue*100 < maxValue && o.OutputFormat != Callgrind {
+			// Minimum and maximum values have different units. Scale
+			// minimum by 100 to use larger units, allowing minimum value to
+			// be scaled down to 0.01, except for callgrind reports since
+			// they can only represent integer values.
+			_, unit = ScaleValue(100*minValue, o.SampleUnit, "minimum")
+		}
+
+		if unit != "" {
+			o.OutputUnit = unit
+		} else {
+			o.OutputUnit = o.SampleUnit
+		}
+	}
+	return
+}
+
+// countEdges counts the number of edges below the specified cutoff.
+func countEdges(el edgeMap, cutoff int64) int {
+	count := 0
+	for _, e := range el {
+		if e.weight > cutoff {
+			count++
+		}
+	}
+	return count
+}
+
+// removeNodes removes nodes from a report, optionally bridging
+// connections between in/out edges and spreading out their weights
+// proportionally. residual marks new bridge edges as residual
+// (dotted).
+func removeNodes(toRemove nodes, bridge, residual bool) {
+	for _, n := range toRemove {
+		for ei := range n.in {
+			delete(ei.out, n)
+		}
+		if bridge {
+			for ei, wi := range n.in {
+				for eo, wo := range n.out {
+					var weight int64
+					if n.cum != 0 {
+						weight = int64(float64(wo.weight) * (float64(wi.weight) / float64(n.cum)))
+					}
+					bumpWeight(ei, eo, weight, residual)
+				}
+			}
+		}
+		for eo := range n.out {
+			delete(eo.in, n)
+		}
+	}
+}
+
+// removeRedundantEdges removes residual edges if the destination can
+// be reached through another path. This is done to simplify the graph
+// while preserving connectivity.
+func removeRedundantEdges(ns nodes) {
+	// Walk the nodes and outgoing edges in reverse order to prefer
+	// removing edges with the lowest weight.
+	for i := len(ns); i > 0; i-- {
+		n := ns[i-1]
+		in := sortedEdges(n.in)
+		for j := len(in); j > 0; j-- {
+			if e := in[j-1]; e.residual && isRedundant(e) {
+				delete(e.src.out, e.dest)
+				delete(e.dest.in, e.src)
+			}
+		}
+	}
+}
+
+// isRedundant determines if an edge can be removed without impacting
+// connectivity of the whole graph. This is implemented by checking if the
+// nodes have a common ancestor after removing the edge.
+func isRedundant(e *edgeInfo) bool {
+	destPred := predecessors(e, e.dest)
+	if len(destPred) == 1 {
+		return false
+	}
+	srcPred := predecessors(e, e.src)
+
+	for n := range srcPred {
+		if destPred[n] && n != e.dest {
+			return true
+		}
+	}
+	return false
+}
+
+// predecessors collects all the predecessors to node n, excluding edge e.
+func predecessors(e *edgeInfo, n *node) map[*node]bool {
+	seen := map[*node]bool{n: true}
+	queue := []*node{n}
+	for len(queue) > 0 {
+		n := queue[0]
+		queue = queue[1:]
+		for _, ie := range n.in {
+			if e == ie || seen[ie.src] {
+				continue
+			}
+			seen[ie.src] = true
+			queue = append(queue, ie.src)
+		}
+	}
+	return seen
+}
+
+// nodeSorter is a mechanism used to allow a report to be sorted
+// in different ways.
+type nodeSorter struct {
+	rs   nodes
+	less func(i, j int) bool
+}
+
+func (s nodeSorter) Len() int           { return len(s.rs) }
+func (s nodeSorter) Swap(i, j int)      { s.rs[i], s.rs[j] = s.rs[j], s.rs[i] }
+func (s nodeSorter) Less(i, j int) bool { return s.less(i, j) }
+
+type nodeOrder int
+
+const (
+	flatName nodeOrder = iota
+	flatCumName
+	cumName
+	nameOrder
+	fileOrder
+	addressOrder
+)
+
+// sort reorders the entries in a report based on the specified
+// ordering criteria. The result is sorted in decreasing order for
+// numeric quantities, alphabetically for text, and increasing for
+// addresses.
+func (ns nodes) sort(o nodeOrder) error {
+	var s nodeSorter
+
+	switch o {
+	case flatName:
+		s = nodeSorter{ns,
+			func(i, j int) bool {
+				if iv, jv := ns[i].flat, ns[j].flat; iv != jv {
+					return iv > jv
+				}
+				if ns[i].info.prettyName() != ns[j].info.prettyName() {
+					return ns[i].info.prettyName() < ns[j].info.prettyName()
+				}
+				iv, jv := ns[i].cum, ns[j].cum
+				return iv > jv
+			},
+		}
+	case flatCumName:
+		s = nodeSorter{ns,
+			func(i, j int) bool {
+				if iv, jv := ns[i].flat, ns[j].flat; iv != jv {
+					return iv > jv
+				}
+				if iv, jv := ns[i].cum, ns[j].cum; iv != jv {
+					return iv > jv
+				}
+				return ns[i].info.prettyName() < ns[j].info.prettyName()
+			},
+		}
+	case cumName:
+		s = nodeSorter{ns,
+			func(i, j int) bool {
+				if ns[i].info.lowPriority != ns[j].info.lowPriority {
+					return ns[j].info.lowPriority
+				}
+				if iv, jv := ns[i].cum, ns[j].cum; iv != jv {
+					return iv > jv
+				}
+				if ns[i].info.prettyName() != ns[j].info.prettyName() {
+					return ns[i].info.prettyName() < ns[j].info.prettyName()
+				}
+				iv, jv := ns[i].flat, ns[j].flat
+				return iv > jv
+			},
+		}
+	case nameOrder:
+		s = nodeSorter{ns,
+			func(i, j int) bool {
+				return ns[i].info.name < ns[j].info.name
+			},
+		}
+	case fileOrder:
+		s = nodeSorter{ns,
+			func(i, j int) bool {
+				return ns[i].info.file < ns[j].info.file
+			},
+		}
+	case addressOrder:
+		s = nodeSorter{ns,
+			func(i, j int) bool {
+				return ns[i].info.address < ns[j].info.address
+			},
+		}
+	default:
+		return fmt.Errorf("report: unrecognized sort ordering: %d", o)
+	}
+	sort.Sort(s)
+	return nil
+}
+
+type edgeList []*edgeInfo
+
+// sortedEdges return a slice of the edges in the map, sorted for
+// visualization. The sort order is first based on the edge weight
+// (higher-to-lower) and then by the node names to avoid flakiness.
+func sortedEdges(edges map[*node]*edgeInfo) edgeList {
+	el := make(edgeList, 0, len(edges))
+	for _, w := range edges {
+		el = append(el, w)
+	}
+
+	sort.Sort(el)
+	return el
+}
+
+func (el edgeList) Len() int {
+	return len(el)
+}
+
+func (el edgeList) Less(i, j int) bool {
+	if el[i].weight != el[j].weight {
+		return el[i].weight > el[j].weight
+	}
+
+	from1 := el[i].src.info.prettyName()
+	from2 := el[j].src.info.prettyName()
+	if from1 != from2 {
+		return from1 < from2
+	}
+
+	to1 := el[i].dest.info.prettyName()
+	to2 := el[j].dest.info.prettyName()
+
+	return to1 < to2
+}
+
+func (el edgeList) Swap(i, j int) {
+	el[i], el[j] = el[j], el[i]
+}
+
+func (el edgeList) sum() int64 {
+	var ret int64
+	for _, e := range el {
+		ret += e.weight
+	}
+	return ret
+}
+
+// ScaleValue reformats a value from a unit to a different unit.
+func ScaleValue(value int64, fromUnit, toUnit string) (sv float64, su string) {
+	// Avoid infinite recursion on overflow.
+	if value < 0 && -value > 0 {
+		v, u := ScaleValue(-value, fromUnit, toUnit)
+		return -v, u
+	}
+	if m, u, ok := memoryLabel(value, fromUnit, toUnit); ok {
+		return m, u
+	}
+	if t, u, ok := timeLabel(value, fromUnit, toUnit); ok {
+		return t, u
+	}
+	// Skip non-interesting units.
+	switch toUnit {
+	case "count", "sample", "unit", "minimum":
+		return float64(value), ""
+	default:
+		return float64(value), toUnit
+	}
+}
+
+func scaledValueLabel(value int64, fromUnit, toUnit string) string {
+	v, u := ScaleValue(value, fromUnit, toUnit)
+
+	sv := strings.TrimSuffix(fmt.Sprintf("%.2f", v), ".00")
+	if sv == "0" || sv == "-0" {
+		return "0"
+	}
+	return sv + u
+}
+
+func memoryLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok bool) {
+	fromUnit = strings.TrimSuffix(strings.ToLower(fromUnit), "s")
+	toUnit = strings.TrimSuffix(strings.ToLower(toUnit), "s")
+
+	switch fromUnit {
+	case "byte", "b":
+	case "kilobyte", "kb":
+		value *= 1024
+	case "megabyte", "mb":
+		value *= 1024 * 1024
+	case "gigabyte", "gb":
+		value *= 1024 * 1024 * 1024
+	default:
+		return 0, "", false
+	}
+
+	if toUnit == "minimum" || toUnit == "auto" {
+		switch {
+		case value < 1024:
+			toUnit = "b"
+		case value < 1024*1024:
+			toUnit = "kb"
+		case value < 1024*1024*1024:
+			toUnit = "mb"
+		default:
+			toUnit = "gb"
+		}
+	}
+
+	var output float64
+	switch toUnit {
+	default:
+		output, toUnit = float64(value), "B"
+	case "kb", "kbyte", "kilobyte":
+		output, toUnit = float64(value)/1024, "kB"
+	case "mb", "mbyte", "megabyte":
+		output, toUnit = float64(value)/(1024*1024), "MB"
+	case "gb", "gbyte", "gigabyte":
+		output, toUnit = float64(value)/(1024*1024*1024), "GB"
+	}
+	return output, toUnit, true
+}
+
+func timeLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok bool) {
+	fromUnit = strings.ToLower(fromUnit)
+	if len(fromUnit) > 2 {
+		fromUnit = strings.TrimSuffix(fromUnit, "s")
+	}
+
+	toUnit = strings.ToLower(toUnit)
+	if len(toUnit) > 2 {
+		toUnit = strings.TrimSuffix(toUnit, "s")
+	}
+
+	var d time.Duration
+	switch fromUnit {
+	case "nanosecond", "ns":
+		d = time.Duration(value) * time.Nanosecond
+	case "microsecond":
+		d = time.Duration(value) * time.Microsecond
+	case "millisecond", "ms":
+		d = time.Duration(value) * time.Millisecond
+	case "second", "sec":
+		d = time.Duration(value) * time.Second
+	case "cycle":
+		return float64(value), "", true
+	default:
+		return 0, "", false
+	}
+
+	if toUnit == "minimum" || toUnit == "auto" {
+		switch {
+		case d < 1*time.Microsecond:
+			toUnit = "ns"
+		case d < 1*time.Millisecond:
+			toUnit = "us"
+		case d < 1*time.Second:
+			toUnit = "ms"
+		case d < 1*time.Minute:
+			toUnit = "sec"
+		case d < 1*time.Hour:
+			toUnit = "min"
+		case d < 24*time.Hour:
+			toUnit = "hour"
+		case d < 15*24*time.Hour:
+			toUnit = "day"
+		case d < 120*24*time.Hour:
+			toUnit = "week"
+		default:
+			toUnit = "year"
+		}
+	}
+
+	var output float64
+	dd := float64(d)
+	switch toUnit {
+	case "ns", "nanosecond":
+		output, toUnit = dd/float64(time.Nanosecond), "ns"
+	case "us", "microsecond":
+		output, toUnit = dd/float64(time.Microsecond), "us"
+	case "ms", "millisecond":
+		output, toUnit = dd/float64(time.Millisecond), "ms"
+	case "min", "minute":
+		output, toUnit = dd/float64(time.Minute), "mins"
+	case "hour", "hr":
+		output, toUnit = dd/float64(time.Hour), "hrs"
+	case "day":
+		output, toUnit = dd/float64(24*time.Hour), "days"
+	case "week", "wk":
+		output, toUnit = dd/float64(7*24*time.Hour), "wks"
+	case "year", "yr":
+		output, toUnit = dd/float64(365*7*24*time.Hour), "yrs"
+	default:
+		fallthrough
+	case "sec", "second", "s":
+		output, toUnit = dd/float64(time.Second), "s"
+	}
+	return output, toUnit, true
+}
+
+// prettyName determines the printable name to be used for a node.
+func (info *nodeInfo) prettyName() string {
+	var name string
+	if info.address != 0 {
+		name = fmt.Sprintf("%016x", info.address)
+	}
+
+	if info.name != "" {
+		name = name + " " + info.name
+	}
+
+	if info.file != "" {
+		name += " " + trimPath(info.file)
+		if info.lineno != 0 {
+			name += fmt.Sprintf(":%d", info.lineno)
+		}
+	}
+
+	if info.inline {
+		name = name + " (inline)"
+	}
+
+	if name = strings.TrimSpace(name); name == "" && info.objfile != "" {
+		name = "[" + info.objfile + "]"
+	}
+	return name
+}
+
+// New builds a new report indexing the sample values interpreting the
+// samples with the provided function.
+func New(prof *profile.Profile, options Options, value func(s *profile.Sample) int64, unit string) *Report {
+	o := &options
+	if o.SampleUnit == "" {
+		o.SampleUnit = unit
+	}
+	format := func(v int64) string {
+		if r := o.Ratio; r > 0 && r != 1 {
+			fv := float64(v) * r
+			v = int64(fv)
+		}
+		return scaledValueLabel(v, o.SampleUnit, o.OutputUnit)
+	}
+	return &Report{prof, computeTotal(prof, value), o, value, format}
+}
+
+// NewDefault builds a new report indexing the sample values with the
+// last value available.
+func NewDefault(prof *profile.Profile, options Options) *Report {
+	index := len(prof.SampleType) - 1
+	o := &options
+	if o.SampleUnit == "" {
+		o.SampleUnit = strings.ToLower(prof.SampleType[index].Unit)
+	}
+	value := func(s *profile.Sample) int64 {
+		return s.Value[index]
+	}
+	format := func(v int64) string {
+		if r := o.Ratio; r > 0 && r != 1 {
+			fv := float64(v) * r
+			v = int64(fv)
+		}
+		return scaledValueLabel(v, o.SampleUnit, o.OutputUnit)
+	}
+	return &Report{prof, computeTotal(prof, value), o, value, format}
+}
+
+func computeTotal(prof *profile.Profile, value func(s *profile.Sample) int64) int64 {
+	var ret int64
+	for _, sample := range prof.Sample {
+		ret += value(sample)
+	}
+	return ret
+}
+
+// Report contains the data and associated routines to extract a
+// report from a profile.
+type Report struct {
+	prof        *profile.Profile
+	total       int64
+	options     *Options
+	sampleValue func(*profile.Sample) int64
+	formatValue func(int64) string
+}
diff --git a/src/cmd/internal/pprof/report/source.go b/src/cmd/internal/pprof/report/source.go
new file mode 100644
index 0000000..608e4d5
--- /dev/null
+++ b/src/cmd/internal/pprof/report/source.go
@@ -0,0 +1,454 @@
+// 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 report
+
+// This file contains routines related to the generation of annotated
+// source listings.
+
+import (
+	"bufio"
+	"fmt"
+	"html/template"
+	"io"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+
+	"cmd/internal/pprof/plugin"
+)
+
+// printSource prints an annotated source listing, include all
+// functions with samples that match the regexp rpt.options.symbol.
+// The sources are sorted by function name and then by filename to
+// eliminate potential nondeterminism.
+func printSource(w io.Writer, rpt *Report) error {
+	o := rpt.options
+	g, err := newGraph(rpt)
+	if err != nil {
+		return err
+	}
+
+	// Identify all the functions that match the regexp provided.
+	// Group nodes for each matching function.
+	var functions nodes
+	functionNodes := make(map[string]nodes)
+	for _, n := range g.ns {
+		if !o.Symbol.MatchString(n.info.name) {
+			continue
+		}
+		if functionNodes[n.info.name] == nil {
+			functions = append(functions, n)
+		}
+		functionNodes[n.info.name] = append(functionNodes[n.info.name], n)
+	}
+	functions.sort(nameOrder)
+
+	fmt.Fprintf(w, "Total: %s\n", rpt.formatValue(rpt.total))
+	for _, fn := range functions {
+		name := fn.info.name
+
+		// Identify all the source files associated to this function.
+		// Group nodes for each source file.
+		var sourceFiles nodes
+		fileNodes := make(map[string]nodes)
+		for _, n := range functionNodes[name] {
+			if n.info.file == "" {
+				continue
+			}
+			if fileNodes[n.info.file] == nil {
+				sourceFiles = append(sourceFiles, n)
+			}
+			fileNodes[n.info.file] = append(fileNodes[n.info.file], n)
+		}
+
+		if len(sourceFiles) == 0 {
+			fmt.Printf("No source information for %s\n", name)
+			continue
+		}
+
+		sourceFiles.sort(fileOrder)
+
+		// Print each file associated with this function.
+		for _, fl := range sourceFiles {
+			filename := fl.info.file
+			fns := fileNodes[filename]
+			flatSum, cumSum := sumNodes(fns)
+
+			fnodes, path, err := getFunctionSource(name, filename, fns, 0, 0)
+			fmt.Fprintf(w, "ROUTINE ======================== %s in %s\n", name, path)
+			fmt.Fprintf(w, "%10s %10s (flat, cum) %s of Total\n",
+				rpt.formatValue(flatSum), rpt.formatValue(cumSum),
+				percentage(cumSum, rpt.total))
+
+			if err != nil {
+				fmt.Fprintf(w, " Error: %v\n", err)
+				continue
+			}
+
+			for _, fn := range fnodes {
+				fmt.Fprintf(w, "%10s %10s %6d:%s\n", valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt), fn.info.lineno, fn.info.name)
+			}
+		}
+	}
+	return nil
+}
+
+// printWebSource prints an annotated source listing, include all
+// functions with samples that match the regexp rpt.options.symbol.
+func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
+	o := rpt.options
+	g, err := newGraph(rpt)
+	if err != nil {
+		return err
+	}
+
+	// If the regexp source can be parsed as an address, also match
+	// functions that land on that address.
+	var address *uint64
+	if hex, err := strconv.ParseUint(o.Symbol.String(), 0, 64); err == nil {
+		address = &hex
+	}
+
+	// Extract interesting symbols from binary files in the profile and
+	// classify samples per symbol.
+	symbols := symbolsFromBinaries(rpt.prof, g, o.Symbol, address, obj)
+	symNodes := nodesPerSymbol(g.ns, symbols)
+
+	// Sort symbols for printing.
+	var syms objSymbols
+	for s := range symNodes {
+		syms = append(syms, s)
+	}
+	sort.Sort(syms)
+
+	if len(syms) == 0 {
+		return fmt.Errorf("no samples found on routines matching: %s", o.Symbol.String())
+	}
+
+	printHeader(w, rpt)
+	for _, s := range syms {
+		name := s.sym.Name[0]
+		// Identify sources associated to a symbol by examining
+		// symbol samples. Classify samples per source file.
+		var sourceFiles nodes
+		fileNodes := make(map[string]nodes)
+		for _, n := range symNodes[s] {
+			if n.info.file == "" {
+				continue
+			}
+			if fileNodes[n.info.file] == nil {
+				sourceFiles = append(sourceFiles, n)
+			}
+			fileNodes[n.info.file] = append(fileNodes[n.info.file], n)
+		}
+
+		if len(sourceFiles) == 0 {
+			fmt.Printf("No source information for %s\n", name)
+			continue
+		}
+
+		sourceFiles.sort(fileOrder)
+
+		// Print each file associated with this function.
+		for _, fl := range sourceFiles {
+			filename := fl.info.file
+			fns := fileNodes[filename]
+
+			asm := assemblyPerSourceLine(symbols, fns, filename, obj)
+			start, end := sourceCoordinates(asm)
+
+			fnodes, path, err := getFunctionSource(name, filename, fns, start, end)
+			if err != nil {
+				fnodes, path = getMissingFunctionSource(filename, asm, start, end)
+			}
+
+			flatSum, cumSum := sumNodes(fnodes)
+			printFunctionHeader(w, name, path, flatSum, cumSum, rpt)
+			for _, fn := range fnodes {
+				printFunctionSourceLine(w, fn, asm[fn.info.lineno], rpt)
+			}
+			printFunctionClosing(w)
+		}
+	}
+	printPageClosing(w)
+	return nil
+}
+
+// sourceCoordinates returns the lowest and highest line numbers from
+// a set of assembly statements.
+func sourceCoordinates(asm map[int]nodes) (start, end int) {
+	for l := range asm {
+		if start == 0 || l < start {
+			start = l
+		}
+		if end == 0 || l > end {
+			end = l
+		}
+	}
+	return start, end
+}
+
+// assemblyPerSourceLine disassembles the binary containing a symbol
+// and classifies the assembly instructions according to its
+// corresponding source line, annotating them with a set of samples.
+func assemblyPerSourceLine(objSyms []*objSymbol, rs nodes, src string, obj plugin.ObjTool) map[int]nodes {
+	assembly := make(map[int]nodes)
+	// Identify symbol to use for this collection of samples.
+	o := findMatchingSymbol(objSyms, rs)
+	if o == nil {
+		return assembly
+	}
+
+	// Extract assembly for matched symbol
+	insns, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End)
+	if err != nil {
+		return assembly
+	}
+
+	srcBase := filepath.Base(src)
+	anodes := annotateAssembly(insns, rs, o.base)
+	var lineno = 0
+	for _, an := range anodes {
+		if filepath.Base(an.info.file) == srcBase {
+			lineno = an.info.lineno
+		}
+		if lineno != 0 {
+			assembly[lineno] = append(assembly[lineno], an)
+		}
+	}
+
+	return assembly
+}
+
+// findMatchingSymbol looks for the symbol that corresponds to a set
+// of samples, by comparing their addresses.
+func findMatchingSymbol(objSyms []*objSymbol, ns nodes) *objSymbol {
+	for _, n := range ns {
+		for _, o := range objSyms {
+			if filepath.Base(o.sym.File) == n.info.objfile &&
+				o.sym.Start <= n.info.address-o.base &&
+				n.info.address-o.base <= o.sym.End {
+				return o
+			}
+		}
+	}
+	return nil
+}
+
+// printHeader prints the page header for a weblist report.
+func printHeader(w io.Writer, rpt *Report) {
+	fmt.Fprintln(w, weblistPageHeader)
+
+	var labels []string
+	for _, l := range legendLabels(rpt) {
+		labels = append(labels, template.HTMLEscapeString(l))
+	}
+
+	fmt.Fprintf(w, `<div class="legend">%s<br>Total: %s</div>`,
+		strings.Join(labels, "<br>\n"),
+		rpt.formatValue(rpt.total),
+	)
+}
+
+// printFunctionHeader prints a function header for a weblist report.
+func printFunctionHeader(w io.Writer, name, path string, flatSum, cumSum int64, rpt *Report) {
+	fmt.Fprintf(w, `<h1>%s</h1>%s
+<pre onClick="pprof_toggle_asm(event)">
+  Total:  %10s %10s (flat, cum) %s
+`,
+		template.HTMLEscapeString(name), template.HTMLEscapeString(path),
+		rpt.formatValue(flatSum), rpt.formatValue(cumSum),
+		percentage(cumSum, rpt.total))
+}
+
+// printFunctionSourceLine prints a source line and the corresponding assembly.
+func printFunctionSourceLine(w io.Writer, fn *node, assembly nodes, rpt *Report) {
+	if len(assembly) == 0 {
+		fmt.Fprintf(w,
+			"<span class=line> %6d</span> <span class=nop>  %10s %10s %s </span>\n",
+			fn.info.lineno,
+			valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt),
+			template.HTMLEscapeString(fn.info.name))
+		return
+	}
+
+	fmt.Fprintf(w,
+		"<span class=line> %6d</span> <span class=deadsrc>  %10s %10s %s </span>",
+		fn.info.lineno,
+		valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt),
+		template.HTMLEscapeString(fn.info.name))
+	fmt.Fprint(w, "<span class=asm>")
+	for _, an := range assembly {
+		var fileline string
+		class := "disasmloc"
+		if an.info.file != "" {
+			fileline = fmt.Sprintf("%s:%d", template.HTMLEscapeString(an.info.file), an.info.lineno)
+			if an.info.lineno != fn.info.lineno {
+				class = "unimportant"
+			}
+		}
+		fmt.Fprintf(w, " %8s %10s %10s %8x: %-48s <span class=%s>%s</span>\n", "",
+			valueOrDot(an.flat, rpt), valueOrDot(an.cum, rpt),
+			an.info.address,
+			template.HTMLEscapeString(an.info.name),
+			class,
+			template.HTMLEscapeString(fileline))
+	}
+	fmt.Fprintln(w, "</span>")
+}
+
+// printFunctionClosing prints the end of a function in a weblist report.
+func printFunctionClosing(w io.Writer) {
+	fmt.Fprintln(w, "</pre>")
+}
+
+// printPageClosing prints the end of the page in a weblist report.
+func printPageClosing(w io.Writer) {
+	fmt.Fprintln(w, weblistPageClosing)
+}
+
+// getFunctionSource collects the sources of a function from a source
+// file and annotates it with the samples in fns. Returns the sources
+// as nodes, using the info.name field to hold the source code.
+func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, string, error) {
+	f, file, err := adjustSourcePath(file)
+	if err != nil {
+		return nil, file, err
+	}
+
+	lineNodes := make(map[int]nodes)
+
+	// Collect source coordinates from profile.
+	const margin = 5 // Lines before first/after last sample.
+	if start == 0 {
+		if fns[0].info.startLine != 0 {
+			start = fns[0].info.startLine
+		} else {
+			start = fns[0].info.lineno - margin
+		}
+	} else {
+		start -= margin
+	}
+	if end == 0 {
+		end = fns[0].info.lineno
+	}
+	end += margin
+	for _, n := range fns {
+		lineno := n.info.lineno
+		nodeStart := n.info.startLine
+		if nodeStart == 0 {
+			nodeStart = lineno - margin
+		}
+		nodeEnd := lineno + margin
+		if nodeStart < start {
+			start = nodeStart
+		} else if nodeEnd > end {
+			end = nodeEnd
+		}
+		lineNodes[lineno] = append(lineNodes[lineno], n)
+	}
+
+	var src nodes
+	buf := bufio.NewReader(f)
+	lineno := 1
+	for {
+		line, err := buf.ReadString('\n')
+		if err != nil {
+			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])
+
+			src = append(src, &node{
+				info: nodeInfo{
+					name:   strings.TrimRight(line, "\n"),
+					lineno: lineno,
+				},
+				flat: flat,
+				cum:  cum,
+			})
+		}
+		lineno++
+		if lineno > end {
+			break
+		}
+	}
+	return src, file, nil
+}
+
+// getMissingFunctionSource creates a dummy function body to point to
+// the source file and annotates it with the samples in asm.
+func getMissingFunctionSource(filename string, asm map[int]nodes, start, end int) (nodes, string) {
+	var fnodes nodes
+	for i := start; i <= end; i++ {
+		lrs := asm[i]
+		if len(lrs) == 0 {
+			continue
+		}
+		flat, cum := sumNodes(lrs)
+		fnodes = append(fnodes, &node{
+			info: nodeInfo{
+				name:   "???",
+				lineno: i,
+			},
+			flat: flat,
+			cum:  cum,
+		})
+	}
+	return fnodes, filename
+}
+
+// adjustSourcePath adjusts the path for a source file by trimming
+// known prefixes and searching for the file on all parents of the
+// current working dir.
+func adjustSourcePath(path string) (*os.File, string, error) {
+	path = trimPath(path)
+	f, err := os.Open(path)
+	if err == nil {
+		return f, path, nil
+	}
+
+	if dir, wderr := os.Getwd(); wderr == nil {
+		for {
+			parent := filepath.Dir(dir)
+			if parent == dir {
+				break
+			}
+			if f, err := os.Open(filepath.Join(parent, path)); err == nil {
+				return f, filepath.Join(parent, path), nil
+			}
+
+			dir = parent
+		}
+	}
+
+	return nil, path, err
+}
+
+// trimPath cleans up a path by removing prefixes that are commonly
+// found on profiles.
+func trimPath(path string) string {
+	basePaths := []string{
+		"/proc/self/cwd/./",
+		"/proc/self/cwd/",
+	}
+
+	sPath := filepath.ToSlash(path)
+
+	for _, base := range basePaths {
+		if strings.HasPrefix(sPath, base) {
+			return filepath.FromSlash(sPath[len(base):])
+		}
+	}
+	return path
+}
diff --git a/src/cmd/pprof/internal/report/source_html.go b/src/cmd/internal/pprof/report/source_html.go
similarity index 100%
rename from src/cmd/pprof/internal/report/source_html.go
rename to src/cmd/internal/pprof/report/source_html.go
diff --git a/src/cmd/pprof/internal/svg/svg.go b/src/cmd/internal/pprof/svg/svg.go
similarity index 100%
rename from src/cmd/pprof/internal/svg/svg.go
rename to src/cmd/internal/pprof/svg/svg.go
diff --git a/src/cmd/pprof/internal/svg/svgpan.go b/src/cmd/internal/pprof/svg/svgpan.go
similarity index 100%
rename from src/cmd/pprof/internal/svg/svgpan.go
rename to src/cmd/internal/pprof/svg/svgpan.go
diff --git a/src/cmd/internal/pprof/symbolizer/symbolizer.go b/src/cmd/internal/pprof/symbolizer/symbolizer.go
new file mode 100644
index 0000000..bc22800
--- /dev/null
+++ b/src/cmd/internal/pprof/symbolizer/symbolizer.go
@@ -0,0 +1,195 @@
+// 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 symbolizer provides a routine to populate a profile with
+// symbol, file and line number information. It relies on the
+// addr2liner and demangler packages to do the actual work.
+package symbolizer
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"cmd/internal/pprof/plugin"
+	"cmd/internal/pprof/profile"
+)
+
+// Symbolize adds symbol and line number information to all locations
+// in a profile. mode enables some options to control
+// symbolization. Currently only recognizes "force", which causes it
+// to overwrite any existing data.
+func Symbolize(mode string, prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error {
+	force := false
+	// Disable some mechanisms based on mode string.
+	for _, o := range strings.Split(strings.ToLower(mode), ":") {
+		switch o {
+		case "force":
+			force = true
+		default:
+		}
+	}
+
+	if len(prof.Mapping) == 0 {
+		return fmt.Errorf("no known mappings")
+	}
+
+	mt, err := newMapping(prof, obj, ui, force)
+	if err != nil {
+		return err
+	}
+	defer mt.close()
+
+	functions := make(map[profile.Function]*profile.Function)
+	for _, l := range mt.prof.Location {
+		m := l.Mapping
+		segment := mt.segments[m]
+		if segment == nil {
+			// Nothing to do
+			continue
+		}
+
+		stack, err := segment.SourceLine(l.Address)
+		if err != nil || len(stack) == 0 {
+			// No answers from addr2line
+			continue
+		}
+
+		l.Line = make([]profile.Line, len(stack))
+		for i, frame := range stack {
+			if frame.Func != "" {
+				m.HasFunctions = true
+			}
+			if frame.File != "" {
+				m.HasFilenames = true
+			}
+			if frame.Line != 0 {
+				m.HasLineNumbers = true
+			}
+			f := &profile.Function{
+				Name:       frame.Func,
+				SystemName: frame.Func,
+				Filename:   frame.File,
+			}
+			if fp := functions[*f]; fp != nil {
+				f = fp
+			} else {
+				functions[*f] = f
+				f.ID = uint64(len(mt.prof.Function)) + 1
+				mt.prof.Function = append(mt.prof.Function, f)
+			}
+			l.Line[i] = profile.Line{
+				Function: f,
+				Line:     int64(frame.Line),
+			}
+		}
+
+		if len(stack) > 0 {
+			m.HasInlineFrames = true
+		}
+	}
+	return nil
+}
+
+// newMapping creates a mappingTable for a profile.
+func newMapping(prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, force bool) (*mappingTable, error) {
+	mt := &mappingTable{
+		prof:     prof,
+		segments: make(map[*profile.Mapping]plugin.ObjFile),
+	}
+
+	// Identify used mappings
+	mappings := make(map[*profile.Mapping]bool)
+	for _, l := range prof.Location {
+		mappings[l.Mapping] = true
+	}
+
+	for _, m := range prof.Mapping {
+		if !mappings[m] {
+			continue
+		}
+		// Do not attempt to re-symbolize a mapping that has already been symbolized.
+		if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) {
+			continue
+		}
+
+		f, err := locateFile(obj, m.File, m.BuildID, m.Start)
+		if err != nil {
+			ui.PrintErr("Local symbolization failed for ", filepath.Base(m.File), ": ", err)
+			// Move on to other mappings
+			continue
+		}
+
+		if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
+			// Build ID mismatch - ignore.
+			f.Close()
+			continue
+		}
+
+		mt.segments[m] = f
+	}
+
+	return mt, nil
+}
+
+// locateFile opens a local file for symbolization on the search path
+// at $PPROF_BINARY_PATH. Looks inside these directories for files
+// named $BUILDID/$BASENAME and $BASENAME (if build id is available).
+func locateFile(obj plugin.ObjTool, file, buildID string, start uint64) (plugin.ObjFile, error) {
+	// Construct search path to examine
+	searchPath := os.Getenv("PPROF_BINARY_PATH")
+	if searchPath == "" {
+		// Use $HOME/pprof/binaries as default directory for local symbolization binaries
+		searchPath = filepath.Join(os.Getenv("HOME"), "pprof", "binaries")
+	}
+
+	// Collect names to search: {buildid/basename, basename}
+	var fileNames []string
+	if baseName := filepath.Base(file); buildID != "" {
+		fileNames = []string{filepath.Join(buildID, baseName), baseName}
+	} else {
+		fileNames = []string{baseName}
+	}
+	for _, path := range filepath.SplitList(searchPath) {
+		for nameIndex, name := range fileNames {
+			file := filepath.Join(path, name)
+			if f, err := obj.Open(file, start); err == nil {
+				fileBuildID := f.BuildID()
+				if buildID == "" || buildID == fileBuildID {
+					return f, nil
+				}
+				f.Close()
+				if nameIndex == 0 {
+					// If this is the first name, the path includes the build id. Report inconsistency.
+					return nil, fmt.Errorf("found file %s with inconsistent build id %s", file, fileBuildID)
+				}
+			}
+		}
+	}
+	// Try original file name
+	f, err := obj.Open(file, start)
+	if err == nil && buildID != "" {
+		if fileBuildID := f.BuildID(); fileBuildID != "" && fileBuildID != buildID {
+			// Mismatched build IDs, ignore
+			f.Close()
+			return nil, fmt.Errorf("mismatched build ids %s != %s", fileBuildID, buildID)
+		}
+	}
+	return f, err
+}
+
+// mappingTable contains the mechanisms for symbolization of a
+// profile.
+type mappingTable struct {
+	prof     *profile.Profile
+	segments map[*profile.Mapping]plugin.ObjFile
+}
+
+// Close releases any external processes being used for the mapping.
+func (mt *mappingTable) close() {
+	for _, segment := range mt.segments {
+		segment.Close()
+	}
+}
diff --git a/src/cmd/internal/pprof/symbolz/symbolz.go b/src/cmd/internal/pprof/symbolz/symbolz.go
new file mode 100644
index 0000000..2f2850a
--- /dev/null
+++ b/src/cmd/internal/pprof/symbolz/symbolz.go
@@ -0,0 +1,111 @@
+// 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 symbolz symbolizes a profile using the output from the symbolz
+// service.
+package symbolz
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"net/url"
+	"regexp"
+	"strconv"
+	"strings"
+
+	"cmd/internal/pprof/profile"
+)
+
+var (
+	symbolzRE = regexp.MustCompile(`(0x[[:xdigit:]]+)\s+(.*)`)
+)
+
+// Symbolize symbolizes profile p by parsing data returned by a
+// symbolz handler. syms receives the symbolz query (hex addresses
+// separated by '+') and returns the symbolz output in a string. It
+// symbolizes all locations based on their addresses, regardless of
+// mapping.
+func Symbolize(source string, syms func(string, string) ([]byte, error), p *profile.Profile) error {
+	if source = symbolz(source, p); source == "" {
+		// If the source is not a recognizable URL, do nothing.
+		return nil
+	}
+
+	// Construct query of addresses to symbolize.
+	var a []string
+	for _, l := range p.Location {
+		if l.Address != 0 && len(l.Line) == 0 {
+			a = append(a, fmt.Sprintf("%#x", l.Address))
+		}
+	}
+
+	if len(a) == 0 {
+		// No addresses to symbolize.
+		return nil
+	}
+	lines := make(map[uint64]profile.Line)
+	functions := make(map[string]*profile.Function)
+	if b, err := syms(source, strings.Join(a, "+")); err == nil {
+		buf := bytes.NewBuffer(b)
+		for {
+			l, err := buf.ReadString('\n')
+
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				return err
+			}
+
+			if symbol := symbolzRE.FindStringSubmatch(l); len(symbol) == 3 {
+				addr, err := strconv.ParseUint(symbol[1], 0, 64)
+				if err != nil {
+					return fmt.Errorf("unexpected parse failure %s: %v", symbol[1], err)
+				}
+
+				name := symbol[2]
+				fn := functions[name]
+				if fn == nil {
+					fn = &profile.Function{
+						ID:         uint64(len(p.Function) + 1),
+						Name:       name,
+						SystemName: name,
+					}
+					functions[name] = fn
+					p.Function = append(p.Function, fn)
+				}
+
+				lines[addr] = profile.Line{Function: fn}
+			}
+		}
+	}
+
+	for _, l := range p.Location {
+		if line, ok := lines[l.Address]; ok {
+			l.Line = []profile.Line{line}
+			if l.Mapping != nil {
+				l.Mapping.HasFunctions = true
+			}
+		}
+	}
+
+	return nil
+}
+
+// symbolz returns the corresponding symbolz source for a profile URL.
+func symbolz(source string, p *profile.Profile) string {
+	if url, err := url.Parse(source); err == nil && url.Host != "" {
+		if last := strings.LastIndex(url.Path, "/"); last != -1 {
+			if strings.HasSuffix(url.Path[:last], "pprof") {
+				url.Path = url.Path[:last] + "/symbol"
+			} else {
+				url.Path = url.Path[:last] + "/symbolz"
+			}
+			return url.String()
+		}
+	}
+
+	return ""
+}
diff --git a/src/cmd/internal/pprof/tempfile/tempfile.go b/src/cmd/internal/pprof/tempfile/tempfile.go
new file mode 100644
index 0000000..a570634
--- /dev/null
+++ b/src/cmd/internal/pprof/tempfile/tempfile.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 tempfile provides tools to create and delete temporary files
+package tempfile
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"sync"
+)
+
+// New returns an unused filename for output files.
+func New(dir, prefix, suffix string) (*os.File, error) {
+	for index := 1; index < 10000; index++ {
+		path := filepath.Join(dir, fmt.Sprintf("%s%03d%s", prefix, index, suffix))
+		if _, err := os.Stat(path); err != nil {
+			return os.Create(path)
+		}
+	}
+	// Give up
+	return nil, fmt.Errorf("could not create file of the form %s%03d%s", prefix, 1, suffix)
+}
+
+var tempFiles []string
+var tempFilesMu = sync.Mutex{}
+
+// DeferDelete marks a file or directory to be deleted by next call to Cleanup.
+func DeferDelete(path string) {
+	tempFilesMu.Lock()
+	tempFiles = append(tempFiles, path)
+	tempFilesMu.Unlock()
+}
+
+// Cleanup removes any temporary files or directories selected for deferred cleaning.
+// Similar to defer semantics, the nodes are deleted in LIFO order.
+func Cleanup() {
+	tempFilesMu.Lock()
+	for i := len(tempFiles) - 1; i >= 0; i-- {
+		os.Remove(tempFiles[i])
+	}
+	tempFiles = nil
+	tempFilesMu.Unlock()
+}
diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go
new file mode 100644
index 0000000..18accde
--- /dev/null
+++ b/src/cmd/internal/sys/arch.go
@@ -0,0 +1,148 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+import "encoding/binary"
+
+// ArchFamily represents a family of one or more related architectures.
+// For example, amd64 and amd64p32 are both members of the AMD64 family,
+// and ppc64 and ppc64le are both members of the PPC64 family.
+type ArchFamily byte
+
+const (
+	AMD64 ArchFamily = iota
+	ARM
+	ARM64
+	I386
+	MIPS64
+	PPC64
+	S390X
+)
+
+// Arch represents an individual architecture.
+type Arch struct {
+	Name   string
+	Family ArchFamily
+
+	ByteOrder binary.ByteOrder
+
+	IntSize int
+	PtrSize int
+	RegSize int
+
+	// MinLC is the minimum length of an instruction code.
+	MinLC int
+}
+
+// InFamily reports whether a is a member of any of the specified
+// architecture families.
+func (a *Arch) InFamily(xs ...ArchFamily) bool {
+	for _, x := range xs {
+		if a.Family == x {
+			return true
+		}
+	}
+	return false
+}
+
+var Arch386 = &Arch{
+	Name:      "386",
+	Family:    I386,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   4,
+	PtrSize:   4,
+	RegSize:   4,
+	MinLC:     1,
+}
+
+var ArchAMD64 = &Arch{
+	Name:      "amd64",
+	Family:    AMD64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     1,
+}
+
+var ArchAMD64P32 = &Arch{
+	Name:      "amd64p32",
+	Family:    AMD64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   4,
+	PtrSize:   4,
+	RegSize:   8,
+	MinLC:     1,
+}
+
+var ArchARM = &Arch{
+	Name:      "arm",
+	Family:    ARM,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   4,
+	PtrSize:   4,
+	RegSize:   4,
+	MinLC:     4,
+}
+
+var ArchARM64 = &Arch{
+	Name:      "arm64",
+	Family:    ARM64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchMIPS64 = &Arch{
+	Name:      "mips64",
+	Family:    MIPS64,
+	ByteOrder: binary.BigEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchMIPS64LE = &Arch{
+	Name:      "mips64le",
+	Family:    MIPS64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchPPC64 = &Arch{
+	Name:      "ppc64",
+	Family:    PPC64,
+	ByteOrder: binary.BigEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchPPC64LE = &Arch{
+	Name:      "ppc64le",
+	Family:    PPC64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchS390X = &Arch{
+	Name:      "s390x",
+	Family:    S390X,
+	ByteOrder: binary.BigEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     2,
+}
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go
deleted file mode 100644
index 6b4d738..0000000
--- a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go
+++ /dev/null
@@ -1,567 +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 armasm
-
-import (
-	"encoding/binary"
-	"fmt"
-)
-
-// An instFormat describes the format of an instruction encoding.
-// An instruction with 32-bit value x matches the format if x&mask == value
-// and the condition matches.
-// The condition matches if x>>28 == 0xF && value>>28==0xF
-// or if x>>28 != 0xF and value>>28 == 0.
-// If x matches the format, then the rest of the fields describe how to interpret x.
-// The opBits describe bits that should be extracted from x and added to the opcode.
-// For example opBits = 0x1234 means that the value
-//	(2 bits at offset 1) followed by (4 bits at offset 3)
-// should be added to op.
-// Finally the args describe how to decode the instruction arguments.
-// args is stored as a fixed-size array; if there are fewer than len(args) arguments,
-// args[i] == 0 marks the end of the argument list.
-type instFormat struct {
-	mask     uint32
-	value    uint32
-	priority int8
-	op       Op
-	opBits   uint64
-	args     instArgs
-}
-
-type instArgs [4]instArg
-
-var (
-	errMode    = fmt.Errorf("unsupported execution mode")
-	errShort   = fmt.Errorf("truncated instruction")
-	errUnknown = fmt.Errorf("unknown instruction")
-)
-
-var decoderCover []bool
-
-// Decode decodes the leading bytes in src as a single instruction.
-func Decode(src []byte, mode Mode) (inst Inst, err error) {
-	if mode != ModeARM {
-		return Inst{}, errMode
-	}
-	if len(src) < 4 {
-		return Inst{}, errShort
-	}
-
-	if decoderCover == nil {
-		decoderCover = make([]bool, len(instFormats))
-	}
-
-	x := binary.LittleEndian.Uint32(src)
-
-	// The instFormat table contains both conditional and unconditional instructions.
-	// Considering only the top 4 bits, the conditional instructions use mask=0, value=0,
-	// while the unconditional instructions use mask=f, value=f.
-	// Prepare a version of x with the condition cleared to 0 in conditional instructions
-	// and then assume mask=f during matching.
-	const condMask = 0xf0000000
-	xNoCond := x
-	if x&condMask != condMask {
-		xNoCond &^= condMask
-	}
-	var priority int8
-Search:
-	for i := range instFormats {
-		f := &instFormats[i]
-		if xNoCond&(f.mask|condMask) != f.value || f.priority <= priority {
-			continue
-		}
-		delta := uint32(0)
-		deltaShift := uint(0)
-		for opBits := f.opBits; opBits != 0; opBits >>= 16 {
-			n := uint(opBits & 0xFF)
-			off := uint((opBits >> 8) & 0xFF)
-			delta |= (x >> off) & (1<<n - 1) << deltaShift
-			deltaShift += n
-		}
-		op := f.op + Op(delta)
-
-		// Special case: BKPT encodes with condition but cannot have one.
-		if op&^15 == BKPT_EQ && op != BKPT {
-			continue Search
-		}
-
-		var args Args
-		for j, aop := range f.args {
-			if aop == 0 {
-				break
-			}
-			arg := decodeArg(aop, x)
-			if arg == nil { // cannot decode argument
-				continue Search
-			}
-			args[j] = arg
-		}
-
-		decoderCover[i] = true
-
-		inst = Inst{
-			Op:   op,
-			Args: args,
-			Enc:  x,
-			Len:  4,
-		}
-		priority = f.priority
-		continue Search
-	}
-	if inst.Op != 0 {
-		return inst, nil
-	}
-	return Inst{}, errUnknown
-}
-
-// An instArg describes the encoding of a single argument.
-// In the names used for arguments, _p_ means +, _m_ means -,
-// _pm_ means ± (usually keyed by the U bit).
-// The _W suffix indicates a general addressing mode based on the P and W bits.
-// The _offset and _postindex suffixes force the given addressing mode.
-// The rest should be somewhat self-explanatory, at least given
-// the decodeArg function.
-type instArg uint8
-
-const (
-	_ instArg = iota
-	arg_APSR
-	arg_FPSCR
-	arg_Dn_half
-	arg_R1_0
-	arg_R1_12
-	arg_R2_0
-	arg_R2_12
-	arg_R_0
-	arg_R_12
-	arg_R_12_nzcv
-	arg_R_16
-	arg_R_16_WB
-	arg_R_8
-	arg_R_rotate
-	arg_R_shift_R
-	arg_R_shift_imm
-	arg_SP
-	arg_Sd
-	arg_Sd_Dd
-	arg_Dd_Sd
-	arg_Sm
-	arg_Sm_Dm
-	arg_Sn
-	arg_Sn_Dn
-	arg_const
-	arg_endian
-	arg_fbits
-	arg_fp_0
-	arg_imm24
-	arg_imm5
-	arg_imm5_32
-	arg_imm5_nz
-	arg_imm_12at8_4at0
-	arg_imm_4at16_12at0
-	arg_imm_vfp
-	arg_label24
-	arg_label24H
-	arg_label_m_12
-	arg_label_p_12
-	arg_label_pm_12
-	arg_label_pm_4_4
-	arg_lsb_width
-	arg_mem_R
-	arg_mem_R_pm_R_W
-	arg_mem_R_pm_R_postindex
-	arg_mem_R_pm_R_shift_imm_W
-	arg_mem_R_pm_R_shift_imm_offset
-	arg_mem_R_pm_R_shift_imm_postindex
-	arg_mem_R_pm_imm12_W
-	arg_mem_R_pm_imm12_offset
-	arg_mem_R_pm_imm12_postindex
-	arg_mem_R_pm_imm8_W
-	arg_mem_R_pm_imm8_postindex
-	arg_mem_R_pm_imm8at0_offset
-	arg_option
-	arg_registers
-	arg_registers1
-	arg_registers2
-	arg_satimm4
-	arg_satimm5
-	arg_satimm4m1
-	arg_satimm5m1
-	arg_widthm1
-)
-
-// decodeArg decodes the arg described by aop from the instruction bits x.
-// It returns nil if x cannot be decoded according to aop.
-func decodeArg(aop instArg, x uint32) Arg {
-	switch aop {
-	default:
-		return nil
-
-	case arg_APSR:
-		return APSR
-	case arg_FPSCR:
-		return FPSCR
-
-	case arg_R_0:
-		return Reg(x & (1<<4 - 1))
-	case arg_R_8:
-		return Reg((x >> 8) & (1<<4 - 1))
-	case arg_R_12:
-		return Reg((x >> 12) & (1<<4 - 1))
-	case arg_R_16:
-		return Reg((x >> 16) & (1<<4 - 1))
-
-	case arg_R_12_nzcv:
-		r := Reg((x >> 12) & (1<<4 - 1))
-		if r == R15 {
-			return APSR_nzcv
-		}
-		return r
-
-	case arg_R_16_WB:
-		mode := AddrLDM
-		if (x>>21)&1 != 0 {
-			mode = AddrLDM_WB
-		}
-		return Mem{Base: Reg((x >> 16) & (1<<4 - 1)), Mode: mode}
-
-	case arg_R_rotate:
-		Rm := Reg(x & (1<<4 - 1))
-		typ, count := decodeShift(x)
-		// ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1.
-		if typ == RotateRightExt {
-			return Reg(Rm)
-		}
-		return RegShift{Rm, typ, uint8(count)}
-
-	case arg_R_shift_R:
-		Rm := Reg(x & (1<<4 - 1))
-		Rs := Reg((x >> 8) & (1<<4 - 1))
-		typ := Shift((x >> 5) & (1<<2 - 1))
-		return RegShiftReg{Rm, typ, Rs}
-
-	case arg_R_shift_imm:
-		Rm := Reg(x & (1<<4 - 1))
-		typ, count := decodeShift(x)
-		if typ == ShiftLeft && count == 0 {
-			return Reg(Rm)
-		}
-		return RegShift{Rm, typ, uint8(count)}
-
-	case arg_R1_0:
-		return Reg((x & (1<<4 - 1)))
-	case arg_R1_12:
-		return Reg(((x >> 12) & (1<<4 - 1)))
-	case arg_R2_0:
-		return Reg((x & (1<<4 - 1)) | 1)
-	case arg_R2_12:
-		return Reg(((x >> 12) & (1<<4 - 1)) | 1)
-
-	case arg_SP:
-		return SP
-
-	case arg_Sd_Dd:
-		v := (x >> 12) & (1<<4 - 1)
-		vx := (x >> 22) & 1
-		sz := (x >> 8) & 1
-		if sz != 0 {
-			return D0 + Reg(vx<<4+v)
-		} else {
-			return S0 + Reg(v<<1+vx)
-		}
-
-	case arg_Dd_Sd:
-		return decodeArg(arg_Sd_Dd, x^(1<<8))
-
-	case arg_Sd:
-		v := (x >> 12) & (1<<4 - 1)
-		vx := (x >> 22) & 1
-		return S0 + Reg(v<<1+vx)
-
-	case arg_Sm_Dm:
-		v := (x >> 0) & (1<<4 - 1)
-		vx := (x >> 5) & 1
-		sz := (x >> 8) & 1
-		if sz != 0 {
-			return D0 + Reg(vx<<4+v)
-		} else {
-			return S0 + Reg(v<<1+vx)
-		}
-
-	case arg_Sm:
-		v := (x >> 0) & (1<<4 - 1)
-		vx := (x >> 5) & 1
-		return S0 + Reg(v<<1+vx)
-
-	case arg_Dn_half:
-		v := (x >> 16) & (1<<4 - 1)
-		vx := (x >> 7) & 1
-		return RegX{D0 + Reg(vx<<4+v), int((x >> 21) & 1)}
-
-	case arg_Sn_Dn:
-		v := (x >> 16) & (1<<4 - 1)
-		vx := (x >> 7) & 1
-		sz := (x >> 8) & 1
-		if sz != 0 {
-			return D0 + Reg(vx<<4+v)
-		} else {
-			return S0 + Reg(v<<1+vx)
-		}
-
-	case arg_Sn:
-		v := (x >> 16) & (1<<4 - 1)
-		vx := (x >> 7) & 1
-		return S0 + Reg(v<<1+vx)
-
-	case arg_const:
-		v := x & (1<<8 - 1)
-		rot := (x >> 8) & (1<<4 - 1) * 2
-		if rot > 0 && v&3 == 0 {
-			// could rotate less
-			return ImmAlt{uint8(v), uint8(rot)}
-		}
-		if rot >= 24 && ((v<<(32-rot))&0xFF)>>(32-rot) == v {
-			// could wrap around to rot==0.
-			return ImmAlt{uint8(v), uint8(rot)}
-		}
-		return Imm(v>>rot | v<<(32-rot))
-
-	case arg_endian:
-		return Endian((x >> 9) & 1)
-
-	case arg_fbits:
-		return Imm((16 << ((x >> 7) & 1)) - ((x&(1<<4-1))<<1 | (x>>5)&1))
-
-	case arg_fp_0:
-		return Imm(0)
-
-	case arg_imm24:
-		return Imm(x & (1<<24 - 1))
-
-	case arg_imm5:
-		return Imm((x >> 7) & (1<<5 - 1))
-
-	case arg_imm5_32:
-		x = (x >> 7) & (1<<5 - 1)
-		if x == 0 {
-			x = 32
-		}
-		return Imm(x)
-
-	case arg_imm5_nz:
-		x = (x >> 7) & (1<<5 - 1)
-		if x == 0 {
-			return nil
-		}
-		return Imm(x)
-
-	case arg_imm_4at16_12at0:
-		return Imm((x>>16)&(1<<4-1)<<12 | x&(1<<12-1))
-
-	case arg_imm_12at8_4at0:
-		return Imm((x>>8)&(1<<12-1)<<4 | x&(1<<4-1))
-
-	case arg_imm_vfp:
-		x = (x>>16)&(1<<4-1)<<4 | x&(1<<4-1)
-		return Imm(x)
-
-	case arg_label24:
-		imm := (x & (1<<24 - 1)) << 2
-		return PCRel(int32(imm<<6) >> 6)
-
-	case arg_label24H:
-		h := (x >> 24) & 1
-		imm := (x&(1<<24-1))<<2 | h<<1
-		return PCRel(int32(imm<<6) >> 6)
-
-	case arg_label_m_12:
-		d := int32(x & (1<<12 - 1))
-		return Mem{Base: PC, Mode: AddrOffset, Offset: int16(-d)}
-
-	case arg_label_p_12:
-		d := int32(x & (1<<12 - 1))
-		return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)}
-
-	case arg_label_pm_12:
-		d := int32(x & (1<<12 - 1))
-		u := (x >> 23) & 1
-		if u == 0 {
-			d = -d
-		}
-		return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)}
-
-	case arg_label_pm_4_4:
-		d := int32((x>>8)&(1<<4-1)<<4 | x&(1<<4-1))
-		u := (x >> 23) & 1
-		if u == 0 {
-			d = -d
-		}
-		return PCRel(d)
-
-	case arg_lsb_width:
-		lsb := (x >> 7) & (1<<5 - 1)
-		msb := (x >> 16) & (1<<5 - 1)
-		if msb < lsb || msb >= 32 {
-			return nil
-		}
-		return Imm(msb + 1 - lsb)
-
-	case arg_mem_R:
-		Rn := Reg((x >> 16) & (1<<4 - 1))
-		return Mem{Base: Rn, Mode: AddrOffset}
-
-	case arg_mem_R_pm_R_postindex:
-		// Treat [<Rn>],+/-<Rm> like [<Rn>,+/-<Rm>{,<shift>}]{!}
-		// by forcing shift bits to <<0 and P=0, W=0 (postindex=true).
-		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5|1<<24|1<<21))
-
-	case arg_mem_R_pm_R_W:
-		// Treat [<Rn>,+/-<Rm>]{!} like [<Rn>,+/-<Rm>{,<shift>}]{!}
-		// by forcing shift bits to <<0.
-		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5))
-
-	case arg_mem_R_pm_R_shift_imm_offset:
-		// Treat [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
-		// by forcing P=1, W=0 (index=false, wback=false).
-		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<21)|1<<24)
-
-	case arg_mem_R_pm_R_shift_imm_postindex:
-		// Treat [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
-		// by forcing P=0, W=0 (postindex=true).
-		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<24|1<<21))
-
-	case arg_mem_R_pm_R_shift_imm_W:
-		Rn := Reg((x >> 16) & (1<<4 - 1))
-		Rm := Reg(x & (1<<4 - 1))
-		typ, count := decodeShift(x)
-		u := (x >> 23) & 1
-		w := (x >> 21) & 1
-		p := (x >> 24) & 1
-		if p == 0 && w == 1 {
-			return nil
-		}
-		sign := int8(+1)
-		if u == 0 {
-			sign = -1
-		}
-		mode := AddrMode(uint8(p<<1) | uint8(w^1))
-		return Mem{Base: Rn, Mode: mode, Sign: sign, Index: Rm, Shift: typ, Count: count}
-
-	case arg_mem_R_pm_imm12_offset:
-		// Treat [<Rn>,#+/-<imm12>] like [<Rn>{,#+/-<imm12>}]{!}
-		// by forcing P=1, W=0 (index=false, wback=false).
-		return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<21)|1<<24)
-
-	case arg_mem_R_pm_imm12_postindex:
-		// Treat [<Rn>],#+/-<imm12> like [<Rn>{,#+/-<imm12>}]{!}
-		// by forcing P=0, W=0 (postindex=true).
-		return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<24|1<<21))
-
-	case arg_mem_R_pm_imm12_W:
-		Rn := Reg((x >> 16) & (1<<4 - 1))
-		u := (x >> 23) & 1
-		w := (x >> 21) & 1
-		p := (x >> 24) & 1
-		if p == 0 && w == 1 {
-			return nil
-		}
-		sign := int8(+1)
-		if u == 0 {
-			sign = -1
-		}
-		imm := int16(x & (1<<12 - 1))
-		mode := AddrMode(uint8(p<<1) | uint8(w^1))
-		return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm}
-
-	case arg_mem_R_pm_imm8_postindex:
-		// Treat [<Rn>],#+/-<imm8> like [<Rn>{,#+/-<imm8>}]{!}
-		// by forcing P=0, W=0 (postindex=true).
-		return decodeArg(arg_mem_R_pm_imm8_W, x&^(1<<24|1<<21))
-
-	case arg_mem_R_pm_imm8_W:
-		Rn := Reg((x >> 16) & (1<<4 - 1))
-		u := (x >> 23) & 1
-		w := (x >> 21) & 1
-		p := (x >> 24) & 1
-		if p == 0 && w == 1 {
-			return nil
-		}
-		sign := int8(+1)
-		if u == 0 {
-			sign = -1
-		}
-		imm := int16((x>>8)&(1<<4-1)<<4 | x&(1<<4-1))
-		mode := AddrMode(uint8(p<<1) | uint8(w^1))
-		return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm}
-
-	case arg_mem_R_pm_imm8at0_offset:
-		Rn := Reg((x >> 16) & (1<<4 - 1))
-		u := (x >> 23) & 1
-		sign := int8(+1)
-		if u == 0 {
-			sign = -1
-		}
-		imm := int16(x&(1<<8-1)) << 2
-		return Mem{Base: Rn, Mode: AddrOffset, Offset: int16(sign) * imm}
-
-	case arg_option:
-		return Imm(x & (1<<4 - 1))
-
-	case arg_registers:
-		return RegList(x & (1<<16 - 1))
-
-	case arg_registers2:
-		x &= 1<<16 - 1
-		n := 0
-		for i := 0; i < 16; i++ {
-			if x>>uint(i)&1 != 0 {
-				n++
-			}
-		}
-		if n < 2 {
-			return nil
-		}
-		return RegList(x)
-
-	case arg_registers1:
-		Rt := (x >> 12) & (1<<4 - 1)
-		return RegList(1 << Rt)
-
-	case arg_satimm4:
-		return Imm((x >> 16) & (1<<4 - 1))
-
-	case arg_satimm5:
-		return Imm((x >> 16) & (1<<5 - 1))
-
-	case arg_satimm4m1:
-		return Imm((x>>16)&(1<<4-1) + 1)
-
-	case arg_satimm5m1:
-		return Imm((x>>16)&(1<<5-1) + 1)
-
-	case arg_widthm1:
-		return Imm((x>>16)&(1<<5-1) + 1)
-
-	}
-}
-
-// decodeShift decodes the shift-by-immediate encoded in x.
-func decodeShift(x uint32) (Shift, uint8) {
-	count := (x >> 7) & (1<<5 - 1)
-	typ := Shift((x >> 5) & (1<<2 - 1))
-	switch typ {
-	case ShiftRight, ShiftRightSigned:
-		if count == 0 {
-			count = 32
-		}
-	case RotateRight:
-		if count == 0 {
-			typ = RotateRightExt
-			count = 1
-		}
-	}
-	return typ, uint8(count)
-}
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go
deleted file mode 100644
index e4122c1..0000000
--- a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go
+++ /dev/null
@@ -1,1646 +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.
-
-// Table-driven decoding of x86 instructions.
-
-package x86asm
-
-import (
-	"encoding/binary"
-	"errors"
-	"fmt"
-	"runtime"
-)
-
-// Set trace to true to cause the decoder to print the PC sequence
-// of the executed instruction codes. This is typically only useful
-// when you are running a test of a single input case.
-const trace = false
-
-// A decodeOp is a single instruction in the decoder bytecode program.
-//
-// The decodeOps correspond to consuming and conditionally branching
-// on input bytes, consuming additional fields, and then interpreting
-// consumed data as instruction arguments. The names of the xRead and xArg
-// operations are taken from the Intel manual conventions, for example
-// Volume 2, Section 3.1.1, page 487 of
-// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf
-//
-// The actual decoding program is generated by ../x86map.
-//
-// TODO(rsc): We may be able to merge various of the memory operands
-// since we don't care about, say, the distinction between m80dec and m80bcd.
-// Similarly, mm and mm1 have identical meaning, as do xmm and xmm1.
-
-type decodeOp uint16
-
-const (
-	xFail  decodeOp = iota // invalid instruction (return)
-	xMatch                 // completed match
-	xJump                  // jump to pc
-
-	xCondByte     // switch on instruction byte value
-	xCondSlashR   // read and switch on instruction /r value
-	xCondPrefix   // switch on presence of instruction prefix
-	xCondIs64     // switch on 64-bit processor mode
-	xCondDataSize // switch on operand size
-	xCondAddrSize // switch on address size
-	xCondIsMem    // switch on memory vs register argument
-
-	xSetOp // set instruction opcode
-
-	xReadSlashR // read /r
-	xReadIb     // read ib
-	xReadIw     // read iw
-	xReadId     // read id
-	xReadIo     // read io
-	xReadCb     // read cb
-	xReadCw     // read cw
-	xReadCd     // read cd
-	xReadCp     // read cp
-	xReadCm     // read cm
-
-	xArg1            // arg 1
-	xArg3            // arg 3
-	xArgAL           // arg AL
-	xArgAX           // arg AX
-	xArgCL           // arg CL
-	xArgCR0dashCR7   // arg CR0-CR7
-	xArgCS           // arg CS
-	xArgDR0dashDR7   // arg DR0-DR7
-	xArgDS           // arg DS
-	xArgDX           // arg DX
-	xArgEAX          // arg EAX
-	xArgEDX          // arg EDX
-	xArgES           // arg ES
-	xArgFS           // arg FS
-	xArgGS           // arg GS
-	xArgImm16        // arg imm16
-	xArgImm32        // arg imm32
-	xArgImm64        // arg imm64
-	xArgImm8         // arg imm8
-	xArgImm8u        // arg imm8 but record as unsigned
-	xArgImm16u       // arg imm8 but record as unsigned
-	xArgM            // arg m
-	xArgM128         // arg m128
-	xArgM1428byte    // arg m14/28byte
-	xArgM16          // arg m16
-	xArgM16and16     // arg m16&16
-	xArgM16and32     // arg m16&32
-	xArgM16and64     // arg m16&64
-	xArgM16colon16   // arg m16:16
-	xArgM16colon32   // arg m16:32
-	xArgM16colon64   // arg m16:64
-	xArgM16int       // arg m16int
-	xArgM2byte       // arg m2byte
-	xArgM32          // arg m32
-	xArgM32and32     // arg m32&32
-	xArgM32fp        // arg m32fp
-	xArgM32int       // arg m32int
-	xArgM512byte     // arg m512byte
-	xArgM64          // arg m64
-	xArgM64fp        // arg m64fp
-	xArgM64int       // arg m64int
-	xArgM8           // arg m8
-	xArgM80bcd       // arg m80bcd
-	xArgM80dec       // arg m80dec
-	xArgM80fp        // arg m80fp
-	xArgM94108byte   // arg m94/108byte
-	xArgMm           // arg mm
-	xArgMm1          // arg mm1
-	xArgMm2          // arg mm2
-	xArgMm2M64       // arg mm2/m64
-	xArgMmM32        // arg mm/m32
-	xArgMmM64        // arg mm/m64
-	xArgMem          // arg mem
-	xArgMoffs16      // arg moffs16
-	xArgMoffs32      // arg moffs32
-	xArgMoffs64      // arg moffs64
-	xArgMoffs8       // arg moffs8
-	xArgPtr16colon16 // arg ptr16:16
-	xArgPtr16colon32 // arg ptr16:32
-	xArgR16          // arg r16
-	xArgR16op        // arg r16 with +rw in opcode
-	xArgR32          // arg r32
-	xArgR32M16       // arg r32/m16
-	xArgR32M8        // arg r32/m8
-	xArgR32op        // arg r32 with +rd in opcode
-	xArgR64          // arg r64
-	xArgR64M16       // arg r64/m16
-	xArgR64op        // arg r64 with +rd in opcode
-	xArgR8           // arg r8
-	xArgR8op         // arg r8 with +rb in opcode
-	xArgRAX          // arg RAX
-	xArgRDX          // arg RDX
-	xArgRM           // arg r/m
-	xArgRM16         // arg r/m16
-	xArgRM32         // arg r/m32
-	xArgRM64         // arg r/m64
-	xArgRM8          // arg r/m8
-	xArgReg          // arg reg
-	xArgRegM16       // arg reg/m16
-	xArgRegM32       // arg reg/m32
-	xArgRegM8        // arg reg/m8
-	xArgRel16        // arg rel16
-	xArgRel32        // arg rel32
-	xArgRel8         // arg rel8
-	xArgSS           // arg SS
-	xArgST           // arg ST, aka ST(0)
-	xArgSTi          // arg ST(i) with +i in opcode
-	xArgSreg         // arg Sreg
-	xArgTR0dashTR7   // arg TR0-TR7
-	xArgXmm          // arg xmm
-	xArgXMM0         // arg <XMM0>
-	xArgXmm1         // arg xmm1
-	xArgXmm2         // arg xmm2
-	xArgXmm2M128     // arg xmm2/m128
-	xArgXmm2M16      // arg xmm2/m16
-	xArgXmm2M32      // arg xmm2/m32
-	xArgXmm2M64      // arg xmm2/m64
-	xArgXmmM128      // arg xmm/m128
-	xArgXmmM32       // arg xmm/m32
-	xArgXmmM64       // arg xmm/m64
-	xArgRmf16        // arg r/m16 but force mod=3
-	xArgRmf32        // arg r/m32 but force mod=3
-	xArgRmf64        // arg r/m64 but force mod=3
-)
-
-// instPrefix returns an Inst describing just one prefix byte.
-// It is only used if there is a prefix followed by an unintelligible
-// or invalid instruction byte sequence.
-func instPrefix(b byte, mode int) (Inst, error) {
-	// When tracing it is useful to see what called instPrefix to report an error.
-	if trace {
-		_, file, line, _ := runtime.Caller(1)
-		fmt.Printf("%s:%d\n", file, line)
-	}
-	p := Prefix(b)
-	switch p {
-	case PrefixDataSize:
-		if mode == 16 {
-			p = PrefixData32
-		} else {
-			p = PrefixData16
-		}
-	case PrefixAddrSize:
-		if mode == 32 {
-			p = PrefixAddr16
-		} else {
-			p = PrefixAddr32
-		}
-	}
-	// Note: using composite literal with Prefix key confuses 'bundle' tool.
-	inst := Inst{Len: 1}
-	inst.Prefix = Prefixes{p}
-	return inst, nil
-}
-
-// truncated reports a truncated instruction.
-// For now we use instPrefix but perhaps later we will return
-// a specific error here.
-func truncated(src []byte, mode int) (Inst, error) {
-	//	return Inst{}, len(src), ErrTruncated
-	return instPrefix(src[0], mode) // too long
-}
-
-// These are the errors returned by Decode.
-var (
-	ErrInvalidMode  = errors.New("invalid x86 mode in Decode")
-	ErrTruncated    = errors.New("truncated instruction")
-	ErrUnrecognized = errors.New("unrecognized instruction")
-)
-
-// decoderCover records coverage information for which parts
-// of the byte code have been executed.
-// TODO(rsc): This is for testing. Only use this if a flag is given.
-var decoderCover []bool
-
-// Decode decodes the leading bytes in src as a single instruction.
-// The mode arguments specifies the assumed processor mode:
-// 16, 32, or 64 for 16-, 32-, and 64-bit execution modes.
-func Decode(src []byte, mode int) (inst Inst, err error) {
-	return decode1(src, mode, false)
-}
-
-// decode1 is the implementation of Decode but takes an extra
-// gnuCompat flag to cause it to change its behavior to mimic
-// bugs (or at least unique features) of GNU libopcodes as used
-// by objdump. We don't believe that logic is the right thing to do
-// in general, but when testing against libopcodes it simplifies the
-// comparison if we adjust a few small pieces of logic.
-// The affected logic is in the conditional branch for "mandatory" prefixes,
-// case xCondPrefix.
-func decode1(src []byte, mode int, gnuCompat bool) (Inst, error) {
-	switch mode {
-	case 16, 32, 64:
-		// ok
-		// TODO(rsc): 64-bit mode not tested, probably not working.
-	default:
-		return Inst{}, ErrInvalidMode
-	}
-
-	// Maximum instruction size is 15 bytes.
-	// If we need to read more, return 'truncated instruction.
-	if len(src) > 15 {
-		src = src[:15]
-	}
-
-	var (
-		// prefix decoding information
-		pos           = 0    // position reading src
-		nprefix       = 0    // number of prefixes
-		lockIndex     = -1   // index of LOCK prefix in src and inst.Prefix
-		repIndex      = -1   // index of REP/REPN prefix in src and inst.Prefix
-		segIndex      = -1   // index of Group 2 prefix in src and inst.Prefix
-		dataSizeIndex = -1   // index of Group 3 prefix in src and inst.Prefix
-		addrSizeIndex = -1   // index of Group 4 prefix in src and inst.Prefix
-		rex           Prefix // rex byte if present (or 0)
-		rexUsed       Prefix // bits used in rex byte
-		rexIndex      = -1   // index of rex byte
-
-		addrMode = mode // address mode (width in bits)
-		dataMode = mode // operand mode (width in bits)
-
-		// decoded ModR/M fields
-		haveModrm bool
-		modrm     int
-		mod       int
-		regop     int
-		rm        int
-
-		// if ModR/M is memory reference, Mem form
-		mem     Mem
-		haveMem bool
-
-		// decoded SIB fields
-		haveSIB bool
-		sib     int
-		scale   int
-		index   int
-		base    int
-		displen int
-		dispoff int
-
-		// decoded immediate values
-		imm     int64
-		imm8    int8
-		immc    int64
-		immcpos int
-
-		// output
-		opshift int
-		inst    Inst
-		narg    int // number of arguments written to inst
-	)
-
-	if mode == 64 {
-		dataMode = 32
-	}
-
-	// Prefixes are certainly the most complex and underspecified part of
-	// decoding x86 instructions. Although the manuals say things like
-	// up to four prefixes, one from each group, nearly everyone seems to
-	// agree that in practice as many prefixes as possible, including multiple
-	// from a particular group or repetitions of a given prefix, can be used on
-	// an instruction, provided the total instruction length including prefixes
-	// does not exceed the agreed-upon maximum of 15 bytes.
-	// Everyone also agrees that if one of these prefixes is the LOCK prefix
-	// and the instruction is not one of the instructions that can be used with
-	// the LOCK prefix or if the destination is not a memory operand,
-	// then the instruction is invalid and produces the #UD exception.
-	// However, that is the end of any semblance of agreement.
-	//
-	// What happens if prefixes are given that conflict with other prefixes?
-	// For example, the memory segment overrides CS, DS, ES, FS, GS, SS
-	// conflict with each other: only one segment can be in effect.
-	// Disassemblers seem to agree that later prefixes take priority over
-	// earlier ones. I have not taken the time to write assembly programs
-	// to check to see if the hardware agrees.
-	//
-	// What happens if prefixes are given that have no meaning for the
-	// specific instruction to which they are attached? It depends.
-	// If they really have no meaning, they are ignored. However, a future
-	// processor may assign a different meaning. As a disassembler, we
-	// don't really know whether we're seeing a meaningless prefix or one
-	// whose meaning we simply haven't been told yet.
-	//
-	// Combining the two questions, what happens when conflicting
-	// extension prefixes are given? No one seems to know for sure.
-	// For example, MOVQ is 66 0F D6 /r, MOVDQ2Q is F2 0F D6 /r,
-	// and MOVQ2DQ is F3 0F D6 /r. What is '66 F2 F3 0F D6 /r'?
-	// Which prefix wins? See the xCondPrefix prefix for more.
-	//
-	// Writing assembly test cases to divine which interpretation the
-	// CPU uses might clarify the situation, but more likely it would
-	// make the situation even less clear.
-
-	// Read non-REX prefixes.
-ReadPrefixes:
-	for ; pos < len(src); pos++ {
-		p := Prefix(src[pos])
-		switch p {
-		default:
-			nprefix = pos
-			break ReadPrefixes
-
-		// Group 1 - lock and repeat prefixes
-		// According to Intel, there should only be one from this set,
-		// but according to AMD both can be present.
-		case 0xF0:
-			if lockIndex >= 0 {
-				inst.Prefix[lockIndex] |= PrefixIgnored
-			}
-			lockIndex = pos
-		case 0xF2, 0xF3:
-			if repIndex >= 0 {
-				inst.Prefix[repIndex] |= PrefixIgnored
-			}
-			repIndex = pos
-
-		// Group 2 - segment override / branch hints
-		case 0x26, 0x2E, 0x36, 0x3E:
-			if mode == 64 {
-				p |= PrefixIgnored
-				break
-			}
-			fallthrough
-		case 0x64, 0x65:
-			if segIndex >= 0 {
-				inst.Prefix[segIndex] |= PrefixIgnored
-			}
-			segIndex = pos
-
-		// Group 3 - operand size override
-		case 0x66:
-			if mode == 16 {
-				dataMode = 32
-				p = PrefixData32
-			} else {
-				dataMode = 16
-				p = PrefixData16
-			}
-			if dataSizeIndex >= 0 {
-				inst.Prefix[dataSizeIndex] |= PrefixIgnored
-			}
-			dataSizeIndex = pos
-
-		// Group 4 - address size override
-		case 0x67:
-			if mode == 32 {
-				addrMode = 16
-				p = PrefixAddr16
-			} else {
-				addrMode = 32
-				p = PrefixAddr32
-			}
-			if addrSizeIndex >= 0 {
-				inst.Prefix[addrSizeIndex] |= PrefixIgnored
-			}
-			addrSizeIndex = pos
-		}
-
-		if pos >= len(inst.Prefix) {
-			return instPrefix(src[0], mode) // too long
-		}
-
-		inst.Prefix[pos] = p
-	}
-
-	// Read REX prefix.
-	if pos < len(src) && mode == 64 && Prefix(src[pos]).IsREX() {
-		rex = Prefix(src[pos])
-		rexIndex = pos
-		if pos >= len(inst.Prefix) {
-			return instPrefix(src[0], mode) // too long
-		}
-		inst.Prefix[pos] = rex
-		pos++
-		if rex&PrefixREXW != 0 {
-			dataMode = 64
-			if dataSizeIndex >= 0 {
-				inst.Prefix[dataSizeIndex] |= PrefixIgnored
-			}
-		}
-	}
-
-	// Decode instruction stream, interpreting decoding instructions.
-	// opshift gives the shift to use when saving the next
-	// opcode byte into inst.Opcode.
-	opshift = 24
-	if decoderCover == nil {
-		decoderCover = make([]bool, len(decoder))
-	}
-
-	// Decode loop, executing decoder program.
-	var oldPC, prevPC int
-Decode:
-	for pc := 1; ; { // TODO uint
-		oldPC = prevPC
-		prevPC = pc
-		if trace {
-			println("run", pc)
-		}
-		x := decoder[pc]
-		decoderCover[pc] = true
-		pc++
-
-		// Read and decode ModR/M if needed by opcode.
-		switch decodeOp(x) {
-		case xCondSlashR, xReadSlashR:
-			if haveModrm {
-				return Inst{Len: pos}, errInternal
-			}
-			haveModrm = true
-			if pos >= len(src) {
-				return truncated(src, mode)
-			}
-			modrm = int(src[pos])
-			pos++
-			if opshift >= 0 {
-				inst.Opcode |= uint32(modrm) << uint(opshift)
-				opshift -= 8
-			}
-			mod = modrm >> 6
-			regop = (modrm >> 3) & 07
-			rm = modrm & 07
-			if rex&PrefixREXR != 0 {
-				rexUsed |= PrefixREXR
-				regop |= 8
-			}
-			if addrMode == 16 {
-				// 16-bit modrm form
-				if mod != 3 {
-					haveMem = true
-					mem = addr16[rm]
-					if rm == 6 && mod == 0 {
-						mem.Base = 0
-					}
-
-					// Consume disp16 if present.
-					if mod == 0 && rm == 6 || mod == 2 {
-						if pos+2 > len(src) {
-							return truncated(src, mode)
-						}
-						mem.Disp = int64(binary.LittleEndian.Uint16(src[pos:]))
-						pos += 2
-					}
-
-					// Consume disp8 if present.
-					if mod == 1 {
-						if pos >= len(src) {
-							return truncated(src, mode)
-						}
-						mem.Disp = int64(int8(src[pos]))
-						pos++
-					}
-				}
-			} else {
-				haveMem = mod != 3
-
-				// 32-bit or 64-bit form
-				// Consume SIB encoding if present.
-				if rm == 4 && mod != 3 {
-					haveSIB = true
-					if pos >= len(src) {
-						return truncated(src, mode)
-					}
-					sib = int(src[pos])
-					pos++
-					if opshift >= 0 {
-						inst.Opcode |= uint32(sib) << uint(opshift)
-						opshift -= 8
-					}
-					scale = sib >> 6
-					index = (sib >> 3) & 07
-					base = sib & 07
-					if rex&PrefixREXB != 0 {
-						rexUsed |= PrefixREXB
-						base |= 8
-					}
-					if rex&PrefixREXX != 0 {
-						rexUsed |= PrefixREXX
-						index |= 8
-					}
-
-					mem.Scale = 1 << uint(scale)
-					if index == 4 {
-						// no mem.Index
-					} else {
-						mem.Index = baseRegForBits(addrMode) + Reg(index)
-					}
-					if base&7 == 5 && mod == 0 {
-						// no mem.Base
-					} else {
-						mem.Base = baseRegForBits(addrMode) + Reg(base)
-					}
-				} else {
-					if rex&PrefixREXB != 0 {
-						rexUsed |= PrefixREXB
-						rm |= 8
-					}
-					if mod == 0 && rm&7 == 5 || rm&7 == 4 {
-						// base omitted
-					} else if mod != 3 {
-						mem.Base = baseRegForBits(addrMode) + Reg(rm)
-					}
-				}
-
-				// Consume disp32 if present.
-				if mod == 0 && (rm&7 == 5 || haveSIB && base&7 == 5) || mod == 2 {
-					if pos+4 > len(src) {
-						return truncated(src, mode)
-					}
-					dispoff = pos
-					displen = 4
-					mem.Disp = int64(binary.LittleEndian.Uint32(src[pos:]))
-					pos += 4
-				}
-
-				// Consume disp8 if present.
-				if mod == 1 {
-					if pos >= len(src) {
-						return truncated(src, mode)
-					}
-					dispoff = pos
-					displen = 1
-					mem.Disp = int64(int8(src[pos]))
-					pos++
-				}
-
-				// In 64-bit, mod=0 rm=5 is PC-relative instead of just disp.
-				// See Vol 2A. Table 2-7.
-				if mode == 64 && mod == 0 && rm&7 == 5 {
-					if addrMode == 32 {
-						mem.Base = EIP
-					} else {
-						mem.Base = RIP
-					}
-				}
-			}
-
-			if segIndex >= 0 {
-				mem.Segment = prefixToSegment(inst.Prefix[segIndex])
-			}
-		}
-
-		// Execute single opcode.
-		switch decodeOp(x) {
-		default:
-			println("bad op", x, "at", pc-1, "from", oldPC)
-			return Inst{Len: pos}, errInternal
-
-		case xFail:
-			inst.Op = 0
-			break Decode
-
-		case xMatch:
-			break Decode
-
-		case xJump:
-			pc = int(decoder[pc])
-
-		// Conditional branches.
-
-		case xCondByte:
-			if pos >= len(src) {
-				return truncated(src, mode)
-			}
-			b := src[pos]
-			n := int(decoder[pc])
-			pc++
-			for i := 0; i < n; i++ {
-				xb, xpc := decoder[pc], int(decoder[pc+1])
-				pc += 2
-				if b == byte(xb) {
-					pc = xpc
-					pos++
-					if opshift >= 0 {
-						inst.Opcode |= uint32(b) << uint(opshift)
-						opshift -= 8
-					}
-					continue Decode
-				}
-			}
-			// xCondByte is the only conditional with a fall through,
-			// so that it can be used to pick off special cases before
-			// an xCondSlash. If the fallthrough instruction is xFail,
-			// advance the position so that the decoded instruction
-			// size includes the byte we just compared against.
-			if decodeOp(decoder[pc]) == xJump {
-				pc = int(decoder[pc+1])
-			}
-			if decodeOp(decoder[pc]) == xFail {
-				pos++
-			}
-
-		case xCondIs64:
-			if mode == 64 {
-				pc = int(decoder[pc+1])
-			} else {
-				pc = int(decoder[pc])
-			}
-
-		case xCondIsMem:
-			mem := haveMem
-			if !haveModrm {
-				if pos >= len(src) {
-					return instPrefix(src[0], mode) // too long
-				}
-				mem = src[pos]>>6 != 3
-			}
-			if mem {
-				pc = int(decoder[pc+1])
-			} else {
-				pc = int(decoder[pc])
-			}
-
-		case xCondDataSize:
-			switch dataMode {
-			case 16:
-				if dataSizeIndex >= 0 {
-					inst.Prefix[dataSizeIndex] |= PrefixImplicit
-				}
-				pc = int(decoder[pc])
-			case 32:
-				if dataSizeIndex >= 0 {
-					inst.Prefix[dataSizeIndex] |= PrefixImplicit
-				}
-				pc = int(decoder[pc+1])
-			case 64:
-				rexUsed |= PrefixREXW
-				pc = int(decoder[pc+2])
-			}
-
-		case xCondAddrSize:
-			switch addrMode {
-			case 16:
-				if addrSizeIndex >= 0 {
-					inst.Prefix[addrSizeIndex] |= PrefixImplicit
-				}
-				pc = int(decoder[pc])
-			case 32:
-				if addrSizeIndex >= 0 {
-					inst.Prefix[addrSizeIndex] |= PrefixImplicit
-				}
-				pc = int(decoder[pc+1])
-			case 64:
-				pc = int(decoder[pc+2])
-			}
-
-		case xCondPrefix:
-			// Conditional branch based on presence or absence of prefixes.
-			// The conflict cases here are completely undocumented and
-			// differ significantly between GNU libopcodes and Intel xed.
-			// I have not written assembly code to divine what various CPUs
-			// do, but it wouldn't surprise me if they are not consistent either.
-			//
-			// The basic idea is to switch on the presence of a prefix, so that
-			// for example:
-			//
-			//	xCondPrefix, 4
-			//	0xF3, 123,
-			//	0xF2, 234,
-			//	0x66, 345,
-			//	0, 456
-			//
-			// branch to 123 if the F3 prefix is present, 234 if the F2 prefix
-			// is present, 66 if the 345 prefix is present, and 456 otherwise.
-			// The prefixes are given in descending order so that the 0 will be last.
-			//
-			// It is unclear what should happen if multiple conditions are
-			// satisfied: what if F2 and F3 are both present, or if 66 and F2
-			// are present, or if all three are present? The one chosen becomes
-			// part of the opcode and the others do not. Perhaps the answer
-			// depends on the specific opcodes in question.
-			//
-			// The only clear example is that CRC32 is F2 0F 38 F1 /r, and
-			// it comes in 16-bit and 32-bit forms based on the 66 prefix,
-			// so 66 F2 0F 38 F1 /r should be treated as F2 taking priority,
-			// with the 66 being only an operand size override, and probably
-			// F2 66 0F 38 F1 /r should be treated the same.
-			// Perhaps that rule is specific to the case of CRC32, since no
-			// 66 0F 38 F1 instruction is defined (today) (that we know of).
-			// However, both libopcodes and xed seem to generalize this
-			// example and choose F2/F3 in preference to 66, and we
-			// do the same.
-			//
-			// Next, what if both F2 and F3 are present? Which wins?
-			// The Intel xed rule, and ours, is that the one that occurs last wins.
-			// The GNU libopcodes rule, which we implement only in gnuCompat mode,
-			// is that F3 beats F2 unless F3 has no special meaning, in which
-			// case F3 can be a modified on an F2 special meaning.
-			//
-			// Concretely,
-			//	66 0F D6 /r is MOVQ
-			//	F2 0F D6 /r is MOVDQ2Q
-			//	F3 0F D6 /r is MOVQ2DQ.
-			//
-			//	F2 66 0F D6 /r is 66 + MOVDQ2Q always.
-			//	66 F2 0F D6 /r is 66 + MOVDQ2Q always.
-			//	F3 66 0F D6 /r is 66 + MOVQ2DQ always.
-			//	66 F3 0F D6 /r is 66 + MOVQ2DQ always.
-			//	F2 F3 0F D6 /r is F2 + MOVQ2DQ always.
-			//	F3 F2 0F D6 /r is F3 + MOVQ2DQ in Intel xed, but F2 + MOVQ2DQ in GNU libopcodes.
-			//	Adding 66 anywhere in the prefix section of the
-			//	last two cases does not change the outcome.
-			//
-			// Finally, what if there is a variant in which 66 is a mandatory
-			// prefix rather than an operand size override, but we know of
-			// no corresponding F2/F3 form, and we see both F2/F3 and 66.
-			// Does F2/F3 still take priority, so that the result is an unknown
-			// instruction, or does the 66 take priority, so that the extended
-			// 66 instruction should be interpreted as having a REP/REPN prefix?
-			// Intel xed does the former and GNU libopcodes does the latter.
-			// We side with Intel xed, unless we are trying to match libopcodes
-			// more closely during the comparison-based test suite.
-			//
-			// In 64-bit mode REX.W is another valid prefix to test for, but
-			// there is less ambiguity about that. When present, REX.W is
-			// always the first entry in the table.
-			n := int(decoder[pc])
-			pc++
-			sawF3 := false
-			for j := 0; j < n; j++ {
-				prefix := Prefix(decoder[pc+2*j])
-				if prefix.IsREX() {
-					rexUsed |= prefix
-					if rex&prefix == prefix {
-						pc = int(decoder[pc+2*j+1])
-						continue Decode
-					}
-					continue
-				}
-				ok := false
-				if prefix == 0 {
-					ok = true
-				} else if prefix.IsREX() {
-					rexUsed |= prefix
-					if rex&prefix == prefix {
-						ok = true
-					}
-				} else {
-					if prefix == 0xF3 {
-						sawF3 = true
-					}
-					switch prefix {
-					case PrefixLOCK:
-						if lockIndex >= 0 {
-							inst.Prefix[lockIndex] |= PrefixImplicit
-							ok = true
-						}
-					case PrefixREP, PrefixREPN:
-						if repIndex >= 0 && inst.Prefix[repIndex]&0xFF == prefix {
-							inst.Prefix[repIndex] |= PrefixImplicit
-							ok = true
-						}
-						if gnuCompat && !ok && prefix == 0xF3 && repIndex >= 0 && (j+1 >= n || decoder[pc+2*(j+1)] != 0xF2) {
-							// Check to see if earlier prefix F3 is present.
-							for i := repIndex - 1; i >= 0; i-- {
-								if inst.Prefix[i]&0xFF == prefix {
-									inst.Prefix[i] |= PrefixImplicit
-									ok = true
-								}
-							}
-						}
-						if gnuCompat && !ok && prefix == 0xF2 && repIndex >= 0 && !sawF3 && inst.Prefix[repIndex]&0xFF == 0xF3 {
-							// Check to see if earlier prefix F2 is present.
-							for i := repIndex - 1; i >= 0; i-- {
-								if inst.Prefix[i]&0xFF == prefix {
-									inst.Prefix[i] |= PrefixImplicit
-									ok = true
-								}
-							}
-						}
-					case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
-						if segIndex >= 0 && inst.Prefix[segIndex]&0xFF == prefix {
-							inst.Prefix[segIndex] |= PrefixImplicit
-							ok = true
-						}
-					case PrefixDataSize:
-						// Looking for 66 mandatory prefix.
-						// The F2/F3 mandatory prefixes take priority when both are present.
-						// If we got this far in the xCondPrefix table and an F2/F3 is present,
-						// it means the table didn't have any entry for that prefix. But if 66 has
-						// special meaning, perhaps F2/F3 have special meaning that we don't know.
-						// Intel xed works this way, treating the F2/F3 as inhibiting the 66.
-						// GNU libopcodes allows the 66 to match. We do what Intel xed does
-						// except in gnuCompat mode.
-						if repIndex >= 0 && !gnuCompat {
-							inst.Op = 0
-							break Decode
-						}
-						if dataSizeIndex >= 0 {
-							inst.Prefix[dataSizeIndex] |= PrefixImplicit
-							ok = true
-						}
-					case PrefixAddrSize:
-						if addrSizeIndex >= 0 {
-							inst.Prefix[addrSizeIndex] |= PrefixImplicit
-							ok = true
-						}
-					}
-				}
-				if ok {
-					pc = int(decoder[pc+2*j+1])
-					continue Decode
-				}
-			}
-			inst.Op = 0
-			break Decode
-
-		case xCondSlashR:
-			pc = int(decoder[pc+regop&7])
-
-		// Input.
-
-		case xReadSlashR:
-			// done above
-
-		case xReadIb:
-			if pos >= len(src) {
-				return truncated(src, mode)
-			}
-			imm8 = int8(src[pos])
-			pos++
-
-		case xReadIw:
-			if pos+2 > len(src) {
-				return truncated(src, mode)
-			}
-			imm = int64(binary.LittleEndian.Uint16(src[pos:]))
-			pos += 2
-
-		case xReadId:
-			if pos+4 > len(src) {
-				return truncated(src, mode)
-			}
-			imm = int64(binary.LittleEndian.Uint32(src[pos:]))
-			pos += 4
-
-		case xReadIo:
-			if pos+8 > len(src) {
-				return truncated(src, mode)
-			}
-			imm = int64(binary.LittleEndian.Uint64(src[pos:]))
-			pos += 8
-
-		case xReadCb:
-			if pos >= len(src) {
-				return truncated(src, mode)
-			}
-			immcpos = pos
-			immc = int64(src[pos])
-			pos++
-
-		case xReadCw:
-			if pos+2 > len(src) {
-				return truncated(src, mode)
-			}
-			immcpos = pos
-			immc = int64(binary.LittleEndian.Uint16(src[pos:]))
-			pos += 2
-
-		case xReadCm:
-			immcpos = pos
-			if addrMode == 16 {
-				if pos+2 > len(src) {
-					return truncated(src, mode)
-				}
-				immc = int64(binary.LittleEndian.Uint16(src[pos:]))
-				pos += 2
-			} else if addrMode == 32 {
-				if pos+4 > len(src) {
-					return truncated(src, mode)
-				}
-				immc = int64(binary.LittleEndian.Uint32(src[pos:]))
-				pos += 4
-			} else {
-				if pos+8 > len(src) {
-					return truncated(src, mode)
-				}
-				immc = int64(binary.LittleEndian.Uint64(src[pos:]))
-				pos += 8
-			}
-		case xReadCd:
-			immcpos = pos
-			if pos+4 > len(src) {
-				return truncated(src, mode)
-			}
-			immc = int64(binary.LittleEndian.Uint32(src[pos:]))
-			pos += 4
-
-		case xReadCp:
-			immcpos = pos
-			if pos+6 > len(src) {
-				return truncated(src, mode)
-			}
-			w := binary.LittleEndian.Uint32(src[pos:])
-			w2 := binary.LittleEndian.Uint16(src[pos+4:])
-			immc = int64(w2)<<32 | int64(w)
-			pos += 6
-
-		// Output.
-
-		case xSetOp:
-			inst.Op = Op(decoder[pc])
-			pc++
-
-		case xArg1,
-			xArg3,
-			xArgAL,
-			xArgAX,
-			xArgCL,
-			xArgCS,
-			xArgDS,
-			xArgDX,
-			xArgEAX,
-			xArgEDX,
-			xArgES,
-			xArgFS,
-			xArgGS,
-			xArgRAX,
-			xArgRDX,
-			xArgSS,
-			xArgST,
-			xArgXMM0:
-			inst.Args[narg] = fixedArg[x]
-			narg++
-
-		case xArgImm8:
-			inst.Args[narg] = Imm(imm8)
-			narg++
-
-		case xArgImm8u:
-			inst.Args[narg] = Imm(uint8(imm8))
-			narg++
-
-		case xArgImm16:
-			inst.Args[narg] = Imm(int16(imm))
-			narg++
-
-		case xArgImm16u:
-			inst.Args[narg] = Imm(uint16(imm))
-			narg++
-
-		case xArgImm32:
-			inst.Args[narg] = Imm(int32(imm))
-			narg++
-
-		case xArgImm64:
-			inst.Args[narg] = Imm(imm)
-			narg++
-
-		case xArgM,
-			xArgM128,
-			xArgM1428byte,
-			xArgM16,
-			xArgM16and16,
-			xArgM16and32,
-			xArgM16and64,
-			xArgM16colon16,
-			xArgM16colon32,
-			xArgM16colon64,
-			xArgM16int,
-			xArgM2byte,
-			xArgM32,
-			xArgM32and32,
-			xArgM32fp,
-			xArgM32int,
-			xArgM512byte,
-			xArgM64,
-			xArgM64fp,
-			xArgM64int,
-			xArgM8,
-			xArgM80bcd,
-			xArgM80dec,
-			xArgM80fp,
-			xArgM94108byte,
-			xArgMem:
-			if !haveMem {
-				inst.Op = 0
-				break Decode
-			}
-			inst.Args[narg] = mem
-			inst.MemBytes = int(memBytes[decodeOp(x)])
-			if mem.Base == RIP {
-				inst.PCRel = displen
-				inst.PCRelOff = dispoff
-			}
-			narg++
-
-		case xArgPtr16colon16:
-			inst.Args[narg] = Imm(immc >> 16)
-			inst.Args[narg+1] = Imm(immc & (1<<16 - 1))
-			narg += 2
-
-		case xArgPtr16colon32:
-			inst.Args[narg] = Imm(immc >> 32)
-			inst.Args[narg+1] = Imm(immc & (1<<32 - 1))
-			narg += 2
-
-		case xArgMoffs8, xArgMoffs16, xArgMoffs32, xArgMoffs64:
-			// TODO(rsc): Can address be 64 bits?
-			mem = Mem{Disp: int64(immc)}
-			if segIndex >= 0 {
-				mem.Segment = prefixToSegment(inst.Prefix[segIndex])
-				inst.Prefix[segIndex] |= PrefixImplicit
-			}
-			inst.Args[narg] = mem
-			inst.MemBytes = int(memBytes[decodeOp(x)])
-			if mem.Base == RIP {
-				inst.PCRel = displen
-				inst.PCRelOff = dispoff
-			}
-			narg++
-
-		case xArgR8, xArgR16, xArgR32, xArgR64, xArgXmm, xArgXmm1, xArgDR0dashDR7:
-			base := baseReg[x]
-			index := Reg(regop)
-			if rex != 0 && base == AL && index >= 4 {
-				rexUsed |= PrefixREX
-				index -= 4
-				base = SPB
-			}
-			inst.Args[narg] = base + index
-			narg++
-
-		case xArgMm, xArgMm1, xArgTR0dashTR7:
-			inst.Args[narg] = baseReg[x] + Reg(regop&7)
-			narg++
-
-		case xArgCR0dashCR7:
-			// AMD documents an extension that the LOCK prefix
-			// can be used in place of a REX prefix in order to access
-			// CR8 from 32-bit mode. The LOCK prefix is allowed in
-			// all modes, provided the corresponding CPUID bit is set.
-			if lockIndex >= 0 {
-				inst.Prefix[lockIndex] |= PrefixImplicit
-				regop += 8
-			}
-			inst.Args[narg] = CR0 + Reg(regop)
-			narg++
-
-		case xArgSreg:
-			regop &= 7
-			if regop >= 6 {
-				inst.Op = 0
-				break Decode
-			}
-			inst.Args[narg] = ES + Reg(regop)
-			narg++
-
-		case xArgRmf16, xArgRmf32, xArgRmf64:
-			base := baseReg[x]
-			index := Reg(modrm & 07)
-			if rex&PrefixREXB != 0 {
-				rexUsed |= PrefixREXB
-				index += 8
-			}
-			inst.Args[narg] = base + index
-			narg++
-
-		case xArgR8op, xArgR16op, xArgR32op, xArgR64op, xArgSTi:
-			n := inst.Opcode >> uint(opshift+8) & 07
-			base := baseReg[x]
-			index := Reg(n)
-			if rex&PrefixREXB != 0 && decodeOp(x) != xArgSTi {
-				rexUsed |= PrefixREXB
-				index += 8
-			}
-			if rex != 0 && base == AL && index >= 4 {
-				rexUsed |= PrefixREX
-				index -= 4
-				base = SPB
-			}
-			inst.Args[narg] = base + index
-			narg++
-
-		case xArgRM8, xArgRM16, xArgRM32, xArgRM64, xArgR32M16, xArgR32M8, xArgR64M16,
-			xArgMmM32, xArgMmM64, xArgMm2M64,
-			xArgXmm2M16, xArgXmm2M32, xArgXmm2M64, xArgXmmM64, xArgXmmM128, xArgXmmM32, xArgXmm2M128:
-			if haveMem {
-				inst.Args[narg] = mem
-				inst.MemBytes = int(memBytes[decodeOp(x)])
-				if mem.Base == RIP {
-					inst.PCRel = displen
-					inst.PCRelOff = dispoff
-				}
-			} else {
-				base := baseReg[x]
-				index := Reg(rm)
-				switch decodeOp(x) {
-				case xArgMmM32, xArgMmM64, xArgMm2M64:
-					// There are only 8 MMX registers, so these ignore the REX.X bit.
-					index &= 7
-				case xArgRM8:
-					if rex != 0 && index >= 4 {
-						rexUsed |= PrefixREX
-						index -= 4
-						base = SPB
-					}
-				}
-				inst.Args[narg] = base + index
-			}
-			narg++
-
-		case xArgMm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
-			if haveMem {
-				inst.Op = 0
-				break Decode
-			}
-			inst.Args[narg] = baseReg[x] + Reg(rm&7)
-			narg++
-
-		case xArgXmm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
-			if haveMem {
-				inst.Op = 0
-				break Decode
-			}
-			inst.Args[narg] = baseReg[x] + Reg(rm)
-			narg++
-
-		case xArgRel8:
-			inst.PCRelOff = immcpos
-			inst.PCRel = 1
-			inst.Args[narg] = Rel(int8(immc))
-			narg++
-
-		case xArgRel16:
-			inst.PCRelOff = immcpos
-			inst.PCRel = 2
-			inst.Args[narg] = Rel(int16(immc))
-			narg++
-
-		case xArgRel32:
-			inst.PCRelOff = immcpos
-			inst.PCRel = 4
-			inst.Args[narg] = Rel(int32(immc))
-			narg++
-		}
-	}
-
-	if inst.Op == 0 {
-		// Invalid instruction.
-		if nprefix > 0 {
-			return instPrefix(src[0], mode) // invalid instruction
-		}
-		return Inst{Len: pos}, ErrUnrecognized
-	}
-
-	// Matched! Hooray!
-
-	// 90 decodes as XCHG EAX, EAX but is NOP.
-	// 66 90 decodes as XCHG AX, AX and is NOP too.
-	// 48 90 decodes as XCHG RAX, RAX and is NOP too.
-	// 43 90 decodes as XCHG R8D, EAX and is *not* NOP.
-	// F3 90 decodes as REP XCHG EAX, EAX but is PAUSE.
-	// It's all too special to handle in the decoding tables, at least for now.
-	if inst.Op == XCHG && inst.Opcode>>24 == 0x90 {
-		if inst.Args[0] == RAX || inst.Args[0] == EAX || inst.Args[0] == AX {
-			inst.Op = NOP
-			if dataSizeIndex >= 0 {
-				inst.Prefix[dataSizeIndex] &^= PrefixImplicit
-			}
-			inst.Args[0] = nil
-			inst.Args[1] = nil
-		}
-		if repIndex >= 0 && inst.Prefix[repIndex] == 0xF3 {
-			inst.Prefix[repIndex] |= PrefixImplicit
-			inst.Op = PAUSE
-			inst.Args[0] = nil
-			inst.Args[1] = nil
-		} else if gnuCompat {
-			for i := nprefix - 1; i >= 0; i-- {
-				if inst.Prefix[i]&0xFF == 0xF3 {
-					inst.Prefix[i] |= PrefixImplicit
-					inst.Op = PAUSE
-					inst.Args[0] = nil
-					inst.Args[1] = nil
-					break
-				}
-			}
-		}
-	}
-
-	// defaultSeg returns the default segment for an implicit
-	// memory reference: the final override if present, or else DS.
-	defaultSeg := func() Reg {
-		if segIndex >= 0 {
-			inst.Prefix[segIndex] |= PrefixImplicit
-			return prefixToSegment(inst.Prefix[segIndex])
-		}
-		return DS
-	}
-
-	// Add implicit arguments not present in the tables.
-	// Normally we shy away from making implicit arguments explicit,
-	// following the Intel manuals, but adding the arguments seems
-	// the best way to express the effect of the segment override prefixes.
-	// TODO(rsc): Perhaps add these to the tables and
-	// create bytecode instructions for them.
-	usedAddrSize := false
-	switch inst.Op {
-	case INSB, INSW, INSD:
-		inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
-		inst.Args[1] = DX
-		usedAddrSize = true
-
-	case OUTSB, OUTSW, OUTSD:
-		inst.Args[0] = DX
-		inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
-		usedAddrSize = true
-
-	case MOVSB, MOVSW, MOVSD, MOVSQ:
-		inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
-		inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
-		usedAddrSize = true
-
-	case CMPSB, CMPSW, CMPSD, CMPSQ:
-		inst.Args[0] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
-		inst.Args[1] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
-		usedAddrSize = true
-
-	case LODSB, LODSW, LODSD, LODSQ:
-		switch inst.Op {
-		case LODSB:
-			inst.Args[0] = AL
-		case LODSW:
-			inst.Args[0] = AX
-		case LODSD:
-			inst.Args[0] = EAX
-		case LODSQ:
-			inst.Args[0] = RAX
-		}
-		inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
-		usedAddrSize = true
-
-	case STOSB, STOSW, STOSD, STOSQ:
-		inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
-		switch inst.Op {
-		case STOSB:
-			inst.Args[1] = AL
-		case STOSW:
-			inst.Args[1] = AX
-		case STOSD:
-			inst.Args[1] = EAX
-		case STOSQ:
-			inst.Args[1] = RAX
-		}
-		usedAddrSize = true
-
-	case SCASB, SCASW, SCASD, SCASQ:
-		inst.Args[1] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
-		switch inst.Op {
-		case SCASB:
-			inst.Args[0] = AL
-		case SCASW:
-			inst.Args[0] = AX
-		case SCASD:
-			inst.Args[0] = EAX
-		case SCASQ:
-			inst.Args[0] = RAX
-		}
-		usedAddrSize = true
-
-	case XLATB:
-		inst.Args[0] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + BX - AX}
-		usedAddrSize = true
-	}
-
-	// If we used the address size annotation to construct the
-	// argument list, mark that prefix as implicit: it doesn't need
-	// to be shown when printing the instruction.
-	if haveMem || usedAddrSize {
-		if addrSizeIndex >= 0 {
-			inst.Prefix[addrSizeIndex] |= PrefixImplicit
-		}
-	}
-
-	// Similarly, if there's some memory operand, the segment
-	// will be shown there and doesn't need to be shown as an
-	// explicit prefix.
-	if haveMem {
-		if segIndex >= 0 {
-			inst.Prefix[segIndex] |= PrefixImplicit
-		}
-	}
-
-	// Branch predict prefixes are overloaded segment prefixes,
-	// since segment prefixes don't make sense on conditional jumps.
-	// Rewrite final instance to prediction prefix.
-	// The set of instructions to which the prefixes apply (other then the
-	// Jcc conditional jumps) is not 100% clear from the manuals, but
-	// the disassemblers seem to agree about the LOOP and JCXZ instructions,
-	// so we'll follow along.
-	// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
-	if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
-	PredictLoop:
-		for i := nprefix - 1; i >= 0; i-- {
-			p := inst.Prefix[i]
-			switch p & 0xFF {
-			case PrefixCS:
-				inst.Prefix[i] = PrefixPN
-				break PredictLoop
-			case PrefixDS:
-				inst.Prefix[i] = PrefixPT
-				break PredictLoop
-			}
-		}
-	}
-
-	// The BND prefix is part of the Intel Memory Protection Extensions (MPX).
-	// A REPN applied to certain control transfers is a BND prefix to bound
-	// the range of possible destinations. There's surprisingly little documentation
-	// about this, so we just do what libopcodes and xed agree on.
-	// In particular, it's unclear why a REPN applied to LOOP or JCXZ instructions
-	// does not turn into a BND.
-	// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
-	if isCondJmp[inst.Op] || inst.Op == JMP || inst.Op == CALL || inst.Op == RET {
-		for i := nprefix - 1; i >= 0; i-- {
-			p := inst.Prefix[i]
-			if p&^PrefixIgnored == PrefixREPN {
-				inst.Prefix[i] = PrefixBND
-				break
-			}
-		}
-	}
-
-	// The LOCK prefix only applies to certain instructions, and then only
-	// to instances of the instruction with a memory destination.
-	// Other uses of LOCK are invalid and cause a processor exception,
-	// in contrast to the "just ignore it" spirit applied to all other prefixes.
-	// Mark invalid lock prefixes.
-	hasLock := false
-	if lockIndex >= 0 && inst.Prefix[lockIndex]&PrefixImplicit == 0 {
-		switch inst.Op {
-		// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
-		case ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCHG8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG:
-			if isMem(inst.Args[0]) {
-				hasLock = true
-				break
-			}
-			fallthrough
-		default:
-			inst.Prefix[lockIndex] |= PrefixInvalid
-		}
-	}
-
-	// In certain cases, all of which require a memory destination,
-	// the REPN and REP prefixes are interpreted as XACQUIRE and XRELEASE
-	// from the Intel Transactional Synchroniation Extensions (TSX).
-	//
-	// The specific rules are:
-	// (1) Any instruction with a valid LOCK prefix can have XACQUIRE or XRELEASE.
-	// (2) Any XCHG, which always has an implicit LOCK, can have XACQUIRE or XRELEASE.
-	// (3) Any 0x88-, 0x89-, 0xC6-, or 0xC7-opcode MOV can have XRELEASE.
-	if isMem(inst.Args[0]) {
-		if inst.Op == XCHG {
-			hasLock = true
-		}
-
-		for i := len(inst.Prefix) - 1; i >= 0; i-- {
-			p := inst.Prefix[i] &^ PrefixIgnored
-			switch p {
-			case PrefixREPN:
-				if hasLock {
-					inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXACQUIRE
-				}
-
-			case PrefixREP:
-				if hasLock {
-					inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXRELEASE
-				}
-
-				if inst.Op == MOV {
-					op := (inst.Opcode >> 24) &^ 1
-					if op == 0x88 || op == 0xC6 {
-						inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXRELEASE
-					}
-				}
-			}
-		}
-	}
-
-	// If REP is used on a non-REP-able instruction, mark the prefix as ignored.
-	if repIndex >= 0 {
-		switch inst.Prefix[repIndex] {
-		case PrefixREP, PrefixREPN:
-			switch inst.Op {
-			// According to the manuals, the REP/REPE prefix applies to all of these,
-			// while the REPN applies only to some of them. However, both libopcodes
-			// and xed show both prefixes explicitly for all instructions, so we do the same.
-			// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
-			case INSB, INSW, INSD,
-				MOVSB, MOVSW, MOVSD, MOVSQ,
-				OUTSB, OUTSW, OUTSD,
-				LODSB, LODSW, LODSD, LODSQ,
-				CMPSB, CMPSW, CMPSD, CMPSQ,
-				SCASB, SCASW, SCASD, SCASQ,
-				STOSB, STOSW, STOSD, STOSQ:
-				// ok
-			default:
-				inst.Prefix[repIndex] |= PrefixIgnored
-			}
-		}
-	}
-
-	// If REX was present, mark implicit if all the 1 bits were consumed.
-	if rexIndex >= 0 {
-		if rexUsed != 0 {
-			rexUsed |= PrefixREX
-		}
-		if rex&^rexUsed == 0 {
-			inst.Prefix[rexIndex] |= PrefixImplicit
-		}
-	}
-
-	inst.DataSize = dataMode
-	inst.AddrSize = addrMode
-	inst.Mode = mode
-	inst.Len = pos
-	return inst, nil
-}
-
-var errInternal = errors.New("internal error")
-
-// addr16 records the eight 16-bit addressing modes.
-var addr16 = [8]Mem{
-	{Base: BX, Scale: 1, Index: SI},
-	{Base: BX, Scale: 1, Index: DI},
-	{Base: BP, Scale: 1, Index: SI},
-	{Base: BP, Scale: 1, Index: DI},
-	{Base: SI},
-	{Base: DI},
-	{Base: BP},
-	{Base: BX},
-}
-
-// baseReg returns the base register for a given register size in bits.
-func baseRegForBits(bits int) Reg {
-	switch bits {
-	case 8:
-		return AL
-	case 16:
-		return AX
-	case 32:
-		return EAX
-	case 64:
-		return RAX
-	}
-	return 0
-}
-
-// baseReg records the base register for argument types that specify
-// a range of registers indexed by op, regop, or rm.
-var baseReg = [...]Reg{
-	xArgDR0dashDR7: DR0,
-	xArgMm1:        M0,
-	xArgMm2:        M0,
-	xArgMm2M64:     M0,
-	xArgMm:         M0,
-	xArgMmM32:      M0,
-	xArgMmM64:      M0,
-	xArgR16:        AX,
-	xArgR16op:      AX,
-	xArgR32:        EAX,
-	xArgR32M16:     EAX,
-	xArgR32M8:      EAX,
-	xArgR32op:      EAX,
-	xArgR64:        RAX,
-	xArgR64M16:     RAX,
-	xArgR64op:      RAX,
-	xArgR8:         AL,
-	xArgR8op:       AL,
-	xArgRM16:       AX,
-	xArgRM32:       EAX,
-	xArgRM64:       RAX,
-	xArgRM8:        AL,
-	xArgRmf16:      AX,
-	xArgRmf32:      EAX,
-	xArgRmf64:      RAX,
-	xArgSTi:        F0,
-	xArgTR0dashTR7: TR0,
-	xArgXmm1:       X0,
-	xArgXmm2:       X0,
-	xArgXmm2M128:   X0,
-	xArgXmm2M16:    X0,
-	xArgXmm2M32:    X0,
-	xArgXmm2M64:    X0,
-	xArgXmm:        X0,
-	xArgXmmM128:    X0,
-	xArgXmmM32:     X0,
-	xArgXmmM64:     X0,
-}
-
-// prefixToSegment returns the segment register
-// corresponding to a particular segment prefix.
-func prefixToSegment(p Prefix) Reg {
-	switch p &^ PrefixImplicit {
-	case PrefixCS:
-		return CS
-	case PrefixDS:
-		return DS
-	case PrefixES:
-		return ES
-	case PrefixFS:
-		return FS
-	case PrefixGS:
-		return GS
-	case PrefixSS:
-		return SS
-	}
-	return 0
-}
-
-// fixedArg records the fixed arguments corresponding to the given bytecodes.
-var fixedArg = [...]Arg{
-	xArg1:    Imm(1),
-	xArg3:    Imm(3),
-	xArgAL:   AL,
-	xArgAX:   AX,
-	xArgDX:   DX,
-	xArgEAX:  EAX,
-	xArgEDX:  EDX,
-	xArgRAX:  RAX,
-	xArgRDX:  RDX,
-	xArgCL:   CL,
-	xArgCS:   CS,
-	xArgDS:   DS,
-	xArgES:   ES,
-	xArgFS:   FS,
-	xArgGS:   GS,
-	xArgSS:   SS,
-	xArgST:   F0,
-	xArgXMM0: X0,
-}
-
-// memBytes records the size of the memory pointed at
-// by a memory argument of the given form.
-var memBytes = [...]int8{
-	xArgM128:       128 / 8,
-	xArgM16:        16 / 8,
-	xArgM16and16:   (16 + 16) / 8,
-	xArgM16colon16: (16 + 16) / 8,
-	xArgM16colon32: (16 + 32) / 8,
-	xArgM16int:     16 / 8,
-	xArgM2byte:     2,
-	xArgM32:        32 / 8,
-	xArgM32and32:   (32 + 32) / 8,
-	xArgM32fp:      32 / 8,
-	xArgM32int:     32 / 8,
-	xArgM64:        64 / 8,
-	xArgM64fp:      64 / 8,
-	xArgM64int:     64 / 8,
-	xArgMm2M64:     64 / 8,
-	xArgMmM32:      32 / 8,
-	xArgMmM64:      64 / 8,
-	xArgMoffs16:    16 / 8,
-	xArgMoffs32:    32 / 8,
-	xArgMoffs64:    64 / 8,
-	xArgMoffs8:     8 / 8,
-	xArgR32M16:     16 / 8,
-	xArgR32M8:      8 / 8,
-	xArgR64M16:     16 / 8,
-	xArgRM16:       16 / 8,
-	xArgRM32:       32 / 8,
-	xArgRM64:       64 / 8,
-	xArgRM8:        8 / 8,
-	xArgXmm2M128:   128 / 8,
-	xArgXmm2M16:    16 / 8,
-	xArgXmm2M32:    32 / 8,
-	xArgXmm2M64:    64 / 8,
-	xArgXmm:        128 / 8,
-	xArgXmmM128:    128 / 8,
-	xArgXmmM32:     32 / 8,
-	xArgXmmM64:     64 / 8,
-}
-
-// isCondJmp records the conditional jumps.
-var isCondJmp = [maxOp + 1]bool{
-	JA:  true,
-	JAE: true,
-	JB:  true,
-	JBE: true,
-	JE:  true,
-	JG:  true,
-	JGE: true,
-	JL:  true,
-	JLE: true,
-	JNE: true,
-	JNO: true,
-	JNP: true,
-	JNS: true,
-	JO:  true,
-	JP:  true,
-	JS:  true,
-}
-
-// isLoop records the loop operators.
-var isLoop = [maxOp + 1]bool{
-	LOOP:   true,
-	LOOPE:  true,
-	LOOPNE: true,
-	JECXZ:  true,
-	JRCXZ:  true,
-}
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go
deleted file mode 100644
index afe6a92..0000000
--- a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x.go
+++ /dev/null
@@ -1,346 +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 x86asm
-
-import (
-	"fmt"
-	"strings"
-)
-
-// GoSyntax returns the Go assembler syntax for the instruction.
-// The syntax was originally defined by Plan 9.
-// The pc is the program counter of the instruction, used for expanding
-// PC-relative addresses into absolute ones.
-// The symname function queries the symbol table for the program
-// being disassembled. Given a target address it returns the name and base
-// address of the symbol containing the target, if any; otherwise it returns "", 0.
-func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string {
-	if symname == nil {
-		symname = func(uint64) (string, uint64) { return "", 0 }
-	}
-	var args []string
-	for i := len(inst.Args) - 1; i >= 0; i-- {
-		a := inst.Args[i]
-		if a == nil {
-			continue
-		}
-		args = append(args, plan9Arg(&inst, pc, symname, a))
-	}
-
-	var last Prefix
-	for _, p := range inst.Prefix {
-		if p == 0 || p.IsREX() {
-			break
-		}
-		last = p
-	}
-
-	prefix := ""
-	switch last & 0xFF {
-	case 0, 0x66, 0x67:
-		// ignore
-	case PrefixREPN:
-		prefix += "REPNE "
-	default:
-		prefix += last.String() + " "
-	}
-
-	op := inst.Op.String()
-	if plan9Suffix[inst.Op] {
-		switch inst.DataSize {
-		case 8:
-			op += "B"
-		case 16:
-			op += "W"
-		case 32:
-			op += "L"
-		case 64:
-			op += "Q"
-		}
-	}
-
-	if args != nil {
-		op += " " + strings.Join(args, ", ")
-	}
-
-	return prefix + op
-}
-
-func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
-	switch a := arg.(type) {
-	case Reg:
-		return plan9Reg[a]
-	case Rel:
-		if pc == 0 {
-			break
-		}
-		// If the absolute address is the start of a symbol, use the name.
-		// Otherwise use the raw address, so that things like relative
-		// jumps show up as JMP 0x123 instead of JMP f+10(SB).
-		// It is usually easier to search for 0x123 than to do the mental
-		// arithmetic to find f+10.
-		addr := pc + uint64(inst.Len) + uint64(a)
-		if s, base := symname(addr); s != "" && addr == base {
-			return fmt.Sprintf("%s(SB)", s)
-		}
-		return fmt.Sprintf("%#x", addr)
-
-	case Imm:
-		if s, base := symname(uint64(a)); s != "" {
-			suffix := ""
-			if uint64(a) != base {
-				suffix = fmt.Sprintf("%+d", uint64(a)-base)
-			}
-			return fmt.Sprintf("$%s%s(SB)", s, suffix)
-		}
-		if inst.Mode == 32 {
-			return fmt.Sprintf("$%#x", uint32(a))
-		}
-		if Imm(int32(a)) == a {
-			return fmt.Sprintf("$%#x", int64(a))
-		}
-		return fmt.Sprintf("$%#x", uint64(a))
-	case Mem:
-		if a.Segment == 0 && a.Disp != 0 && a.Base == 0 && (a.Index == 0 || a.Scale == 0) {
-			if s, base := symname(uint64(a.Disp)); s != "" {
-				suffix := ""
-				if uint64(a.Disp) != base {
-					suffix = fmt.Sprintf("%+d", uint64(a.Disp)-base)
-				}
-				return fmt.Sprintf("%s%s(SB)", s, suffix)
-			}
-		}
-		s := ""
-		if a.Segment != 0 {
-			s += fmt.Sprintf("%s:", plan9Reg[a.Segment])
-		}
-		if a.Disp != 0 {
-			s += fmt.Sprintf("%#x", a.Disp)
-		} else {
-			s += "0"
-		}
-		if a.Base != 0 {
-			s += fmt.Sprintf("(%s)", plan9Reg[a.Base])
-		}
-		if a.Index != 0 && a.Scale != 0 {
-			s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale)
-		}
-		return s
-	}
-	return arg.String()
-}
-
-var plan9Suffix = [maxOp + 1]bool{
-	ADC:       true,
-	ADD:       true,
-	AND:       true,
-	BSF:       true,
-	BSR:       true,
-	BT:        true,
-	BTC:       true,
-	BTR:       true,
-	BTS:       true,
-	CMP:       true,
-	CMPXCHG:   true,
-	CVTSI2SD:  true,
-	CVTSI2SS:  true,
-	CVTSD2SI:  true,
-	CVTSS2SI:  true,
-	CVTTSD2SI: true,
-	CVTTSS2SI: true,
-	DEC:       true,
-	DIV:       true,
-	FLDENV:    true,
-	FRSTOR:    true,
-	IDIV:      true,
-	IMUL:      true,
-	IN:        true,
-	INC:       true,
-	LEA:       true,
-	MOV:       true,
-	MOVNTI:    true,
-	MUL:       true,
-	NEG:       true,
-	NOP:       true,
-	NOT:       true,
-	OR:        true,
-	OUT:       true,
-	POP:       true,
-	POPA:      true,
-	PUSH:      true,
-	PUSHA:     true,
-	RCL:       true,
-	RCR:       true,
-	ROL:       true,
-	ROR:       true,
-	SAR:       true,
-	SBB:       true,
-	SHL:       true,
-	SHLD:      true,
-	SHR:       true,
-	SHRD:      true,
-	SUB:       true,
-	TEST:      true,
-	XADD:      true,
-	XCHG:      true,
-	XOR:       true,
-}
-
-var plan9Reg = [...]string{
-	AL:   "AL",
-	CL:   "CL",
-	BL:   "BL",
-	DL:   "DL",
-	AH:   "AH",
-	CH:   "CH",
-	BH:   "BH",
-	DH:   "DH",
-	SPB:  "SP",
-	BPB:  "BP",
-	SIB:  "SI",
-	DIB:  "DI",
-	R8B:  "R8",
-	R9B:  "R9",
-	R10B: "R10",
-	R11B: "R11",
-	R12B: "R12",
-	R13B: "R13",
-	R14B: "R14",
-	R15B: "R15",
-	AX:   "AX",
-	CX:   "CX",
-	BX:   "BX",
-	DX:   "DX",
-	SP:   "SP",
-	BP:   "BP",
-	SI:   "SI",
-	DI:   "DI",
-	R8W:  "R8",
-	R9W:  "R9",
-	R10W: "R10",
-	R11W: "R11",
-	R12W: "R12",
-	R13W: "R13",
-	R14W: "R14",
-	R15W: "R15",
-	EAX:  "AX",
-	ECX:  "CX",
-	EDX:  "DX",
-	EBX:  "BX",
-	ESP:  "SP",
-	EBP:  "BP",
-	ESI:  "SI",
-	EDI:  "DI",
-	R8L:  "R8",
-	R9L:  "R9",
-	R10L: "R10",
-	R11L: "R11",
-	R12L: "R12",
-	R13L: "R13",
-	R14L: "R14",
-	R15L: "R15",
-	RAX:  "AX",
-	RCX:  "CX",
-	RDX:  "DX",
-	RBX:  "BX",
-	RSP:  "SP",
-	RBP:  "BP",
-	RSI:  "SI",
-	RDI:  "DI",
-	R8:   "R8",
-	R9:   "R9",
-	R10:  "R10",
-	R11:  "R11",
-	R12:  "R12",
-	R13:  "R13",
-	R14:  "R14",
-	R15:  "R15",
-	IP:   "IP",
-	EIP:  "IP",
-	RIP:  "IP",
-	F0:   "F0",
-	F1:   "F1",
-	F2:   "F2",
-	F3:   "F3",
-	F4:   "F4",
-	F5:   "F5",
-	F6:   "F6",
-	F7:   "F7",
-	M0:   "M0",
-	M1:   "M1",
-	M2:   "M2",
-	M3:   "M3",
-	M4:   "M4",
-	M5:   "M5",
-	M6:   "M6",
-	M7:   "M7",
-	X0:   "X0",
-	X1:   "X1",
-	X2:   "X2",
-	X3:   "X3",
-	X4:   "X4",
-	X5:   "X5",
-	X6:   "X6",
-	X7:   "X7",
-	X8:   "X8",
-	X9:   "X9",
-	X10:  "X10",
-	X11:  "X11",
-	X12:  "X12",
-	X13:  "X13",
-	X14:  "X14",
-	X15:  "X15",
-	CS:   "CS",
-	SS:   "SS",
-	DS:   "DS",
-	ES:   "ES",
-	FS:   "FS",
-	GS:   "GS",
-	GDTR: "GDTR",
-	IDTR: "IDTR",
-	LDTR: "LDTR",
-	MSW:  "MSW",
-	TASK: "TASK",
-	CR0:  "CR0",
-	CR1:  "CR1",
-	CR2:  "CR2",
-	CR3:  "CR3",
-	CR4:  "CR4",
-	CR5:  "CR5",
-	CR6:  "CR6",
-	CR7:  "CR7",
-	CR8:  "CR8",
-	CR9:  "CR9",
-	CR10: "CR10",
-	CR11: "CR11",
-	CR12: "CR12",
-	CR13: "CR13",
-	CR14: "CR14",
-	CR15: "CR15",
-	DR0:  "DR0",
-	DR1:  "DR1",
-	DR2:  "DR2",
-	DR3:  "DR3",
-	DR4:  "DR4",
-	DR5:  "DR5",
-	DR6:  "DR6",
-	DR7:  "DR7",
-	DR8:  "DR8",
-	DR9:  "DR9",
-	DR10: "DR10",
-	DR11: "DR11",
-	DR12: "DR12",
-	DR13: "DR13",
-	DR14: "DR14",
-	DR15: "DR15",
-	TR0:  "TR0",
-	TR1:  "TR1",
-	TR2:  "TR2",
-	TR3:  "TR3",
-	TR4:  "TR4",
-	TR5:  "TR5",
-	TR6:  "TR6",
-	TR7:  "TR7",
-}
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt
deleted file mode 100644
index a899d75..0000000
--- a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt
+++ /dev/null
@@ -1,6731 +0,0 @@
-000511223344|556677885f5f5f5f5f5f	32	intel	add byte ptr [0x44332211], al
-000511223344|556677885f5f5f5f5f5f	64	gnu	add %al,0x44332211(%rip)
-000511223344|556677885f5f5f5f5f5f	64	intel	add byte ptr [rip+0x44332211], al
-0100|11223344556677885f5f5f5f5f5f	32	intel	add dword ptr [eax], eax
-0100|11223344556677885f5f5f5f5f5f	32	plan9	ADDL AX, 0(AX)
-0100|11223344556677885f5f5f5f5f5f	64	gnu	add %eax,(%rax)
-0100|11223344556677885f5f5f5f5f5f	64	intel	add dword ptr [rax], eax
-0100|11223344556677885f5f5f5f5f5f	64	plan9	ADDL AX, 0(AX)
-0211|223344556677885f5f5f5f5f5f5f	32	intel	add dl, byte ptr [ecx]
-0211|223344556677885f5f5f5f5f5f5f	32	plan9	ADDL 0(CX), DL
-0211|223344556677885f5f5f5f5f5f5f	64	gnu	add (%rcx),%dl
-0211|223344556677885f5f5f5f5f5f5f	64	intel	add dl, byte ptr [rcx]
-0211|223344556677885f5f5f5f5f5f5f	64	plan9	ADDL 0(CX), DL
-0311|223344556677885f5f5f5f5f5f5f	32	intel	add edx, dword ptr [ecx]
-0311|223344556677885f5f5f5f5f5f5f	32	plan9	ADDL 0(CX), DX
-0311|223344556677885f5f5f5f5f5f5f	64	gnu	add (%rcx),%edx
-0311|223344556677885f5f5f5f5f5f5f	64	intel	add edx, dword ptr [rcx]
-0311|223344556677885f5f5f5f5f5f5f	64	plan9	ADDL 0(CX), DX
-0411|223344556677885f5f5f5f5f5f5f	32	intel	add al, 0x11
-0411|223344556677885f5f5f5f5f5f5f	32	plan9	ADDL $0x11, AL
-0411|223344556677885f5f5f5f5f5f5f	64	gnu	add $0x11,%al
-0411|223344556677885f5f5f5f5f5f5f	64	intel	add al, 0x11
-0411|223344556677885f5f5f5f5f5f5f	64	plan9	ADDL $0x11, AL
-0511223344|556677885f5f5f5f5f5f5f	32	intel	add eax, 0x44332211
-0511223344|556677885f5f5f5f5f5f5f	32	plan9	ADDL $0x44332211, AX
-0511223344|556677885f5f5f5f5f5f5f	64	gnu	add $0x44332211,%eax
-0511223344|556677885f5f5f5f5f5f5f	64	intel	add eax, 0x44332211
-0511223344|556677885f5f5f5f5f5f5f	64	plan9	ADDL $0x44332211, AX
-06|11223344556677885f5f5f5f5f5f5f	32	intel	push es
-06|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL ES
-06|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-06|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-06|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-07|11223344556677885f5f5f5f5f5f5f	32	intel	pop es
-07|11223344556677885f5f5f5f5f5f5f	32	plan9	POPL ES
-07|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-07|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-07|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0811|223344556677885f5f5f5f5f5f5f	32	intel	or byte ptr [ecx], dl
-0811|223344556677885f5f5f5f5f5f5f	32	plan9	ORL DL, 0(CX)
-0811|223344556677885f5f5f5f5f5f5f	64	gnu	or %dl,(%rcx)
-0811|223344556677885f5f5f5f5f5f5f	64	intel	or byte ptr [rcx], dl
-0811|223344556677885f5f5f5f5f5f5f	64	plan9	ORL DL, 0(CX)
-0911|223344556677885f5f5f5f5f5f5f	32	intel	or dword ptr [ecx], edx
-0911|223344556677885f5f5f5f5f5f5f	32	plan9	ORL DX, 0(CX)
-0911|223344556677885f5f5f5f5f5f5f	64	gnu	or %edx,(%rcx)
-0911|223344556677885f5f5f5f5f5f5f	64	intel	or dword ptr [rcx], edx
-0911|223344556677885f5f5f5f5f5f5f	64	plan9	ORL DX, 0(CX)
-0a11|223344556677885f5f5f5f5f5f5f	32	intel	or dl, byte ptr [ecx]
-0a11|223344556677885f5f5f5f5f5f5f	32	plan9	ORL 0(CX), DL
-0a11|223344556677885f5f5f5f5f5f5f	64	gnu	or (%rcx),%dl
-0a11|223344556677885f5f5f5f5f5f5f	64	intel	or dl, byte ptr [rcx]
-0a11|223344556677885f5f5f5f5f5f5f	64	plan9	ORL 0(CX), DL
-0b11|223344556677885f5f5f5f5f5f5f	32	intel	or edx, dword ptr [ecx]
-0b11|223344556677885f5f5f5f5f5f5f	32	plan9	ORL 0(CX), DX
-0b11|223344556677885f5f5f5f5f5f5f	64	gnu	or (%rcx),%edx
-0b11|223344556677885f5f5f5f5f5f5f	64	intel	or edx, dword ptr [rcx]
-0b11|223344556677885f5f5f5f5f5f5f	64	plan9	ORL 0(CX), DX
-0c11|223344556677885f5f5f5f5f5f5f	32	intel	or al, 0x11
-0c11|223344556677885f5f5f5f5f5f5f	32	plan9	ORL $0x11, AL
-0c11|223344556677885f5f5f5f5f5f5f	64	gnu	or $0x11,%al
-0c11|223344556677885f5f5f5f5f5f5f	64	intel	or al, 0x11
-0c11|223344556677885f5f5f5f5f5f5f	64	plan9	ORL $0x11, AL
-0d11223344|556677885f5f5f5f5f5f5f	32	intel	or eax, 0x44332211
-0d11223344|556677885f5f5f5f5f5f5f	32	plan9	ORL $0x44332211, AX
-0d11223344|556677885f5f5f5f5f5f5f	64	gnu	or $0x44332211,%eax
-0d11223344|556677885f5f5f5f5f5f5f	64	intel	or eax, 0x44332211
-0d11223344|556677885f5f5f5f5f5f5f	64	plan9	ORL $0x44332211, AX
-0e|11223344556677885f5f5f5f5f5f5f	32	intel	push cs
-0e|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL CS
-0e|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0e|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0e|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f0000|11223344556677885f5f5f5f5f	32	intel	sldt word ptr [eax]
-0f0000|11223344556677885f5f5f5f5f	32	plan9	SLDT 0(AX)
-0f0000|11223344556677885f5f5f5f5f	64	gnu	sldt (%rax)
-0f0000|11223344556677885f5f5f5f5f	64	intel	sldt word ptr [rax]
-0f0000|11223344556677885f5f5f5f5f	64	plan9	SLDT 0(AX)
-0f0008|11223344556677885f5f5f5f5f	32	intel	str word ptr [eax]
-0f0008|11223344556677885f5f5f5f5f	32	plan9	STR 0(AX)
-0f0008|11223344556677885f5f5f5f5f	64	gnu	str (%rax)
-0f0008|11223344556677885f5f5f5f5f	64	intel	str word ptr [rax]
-0f0008|11223344556677885f5f5f5f5f	64	plan9	STR 0(AX)
-0f0011|223344556677885f5f5f5f5f5f	32	intel	lldt word ptr [ecx]
-0f0011|223344556677885f5f5f5f5f5f	32	plan9	LLDT 0(CX)
-0f0011|223344556677885f5f5f5f5f5f	64	gnu	lldt (%rcx)
-0f0011|223344556677885f5f5f5f5f5f	64	intel	lldt word ptr [rcx]
-0f0011|223344556677885f5f5f5f5f5f	64	plan9	LLDT 0(CX)
-0f0018|11223344556677885f5f5f5f5f	32	intel	ltr word ptr [eax]
-0f0018|11223344556677885f5f5f5f5f	32	plan9	LTR 0(AX)
-0f0018|11223344556677885f5f5f5f5f	64	gnu	ltr (%rax)
-0f0018|11223344556677885f5f5f5f5f	64	intel	ltr word ptr [rax]
-0f0018|11223344556677885f5f5f5f5f	64	plan9	LTR 0(AX)
-0f0020|11223344556677885f5f5f5f5f	32	intel	verr word ptr [eax]
-0f0020|11223344556677885f5f5f5f5f	32	plan9	VERR 0(AX)
-0f0020|11223344556677885f5f5f5f5f	64	gnu	verr (%rax)
-0f0020|11223344556677885f5f5f5f5f	64	intel	verr word ptr [rax]
-0f0020|11223344556677885f5f5f5f5f	64	plan9	VERR 0(AX)
-0f0028|11223344556677885f5f5f5f5f	32	intel	verw word ptr [eax]
-0f0028|11223344556677885f5f5f5f5f	32	plan9	VERW 0(AX)
-0f0028|11223344556677885f5f5f5f5f	64	gnu	verw (%rax)
-0f0028|11223344556677885f5f5f5f5f	64	intel	verw word ptr [rax]
-0f0028|11223344556677885f5f5f5f5f	64	plan9	VERW 0(AX)
-0f0030|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f0030|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f0100|11223344556677885f5f5f5f5f	32	intel	sgdt ptr [eax]
-0f0100|11223344556677885f5f5f5f5f	32	plan9	SGDT 0(AX)
-0f0100|11223344556677885f5f5f5f5f	64	gnu	sgdtl (%rax)
-0f0100|11223344556677885f5f5f5f5f	64	intel	sgdt ptr [rax]
-0f0100|11223344556677885f5f5f5f5f	64	plan9	SGDT 0(AX)
-0f0108|11223344556677885f5f5f5f5f	32	intel	sidt ptr [eax]
-0f0108|11223344556677885f5f5f5f5f	32	plan9	SIDT 0(AX)
-0f0108|11223344556677885f5f5f5f5f	64	gnu	sidtl (%rax)
-0f0108|11223344556677885f5f5f5f5f	64	intel	sidt ptr [rax]
-0f0108|11223344556677885f5f5f5f5f	64	plan9	SIDT 0(AX)
-0f0111|223344556677885f5f5f5f5f5f	32	intel	lgdt ptr [ecx]
-0f0111|223344556677885f5f5f5f5f5f	32	plan9	LGDT 0(CX)
-0f0111|223344556677885f5f5f5f5f5f	64	gnu	lgdtl (%rcx)
-0f0111|223344556677885f5f5f5f5f5f	64	intel	lgdt ptr [rcx]
-0f0111|223344556677885f5f5f5f5f5f	64	plan9	LGDT 0(CX)
-0f0118|11223344556677885f5f5f5f5f	32	intel	lidt ptr [eax]
-0f0118|11223344556677885f5f5f5f5f	32	plan9	LIDT 0(AX)
-0f0118|11223344556677885f5f5f5f5f	64	gnu	lidtl (%rax)
-0f0118|11223344556677885f5f5f5f5f	64	intel	lidt ptr [rax]
-0f0118|11223344556677885f5f5f5f5f	64	plan9	LIDT 0(AX)
-0f0120|11223344556677885f5f5f5f5f	32	intel	smsw word ptr [eax]
-0f0120|11223344556677885f5f5f5f5f	32	plan9	SMSW 0(AX)
-0f0120|11223344556677885f5f5f5f5f	64	gnu	smsw (%rax)
-0f0120|11223344556677885f5f5f5f5f	64	intel	smsw word ptr [rax]
-0f0120|11223344556677885f5f5f5f5f	64	plan9	SMSW 0(AX)
-0f0130|11223344556677885f5f5f5f5f	32	intel	lmsw word ptr [eax]
-0f0130|11223344556677885f5f5f5f5f	32	plan9	LMSW 0(AX)
-0f0130|11223344556677885f5f5f5f5f	64	gnu	lmsw (%rax)
-0f0130|11223344556677885f5f5f5f5f	64	intel	lmsw word ptr [rax]
-0f0130|11223344556677885f5f5f5f5f	64	plan9	LMSW 0(AX)
-0f0138|11223344556677885f5f5f5f5f	32	intel	invlpg byte ptr [eax]
-0f0138|11223344556677885f5f5f5f5f	32	plan9	INVLPG 0(AX)
-0f0138|11223344556677885f5f5f5f5f	64	gnu	invlpg (%rax)
-0f0138|11223344556677885f5f5f5f5f	64	intel	invlpg byte ptr [rax]
-0f0138|11223344556677885f5f5f5f5f	64	plan9	INVLPG 0(AX)
-0f01c8|11223344556677885f5f5f5f5f	32	intel	monitor
-0f01c8|11223344556677885f5f5f5f5f	32	plan9	MONITOR
-0f01c8|11223344556677885f5f5f5f5f	64	gnu	monitor %eax,%ecx,%edx
-0f01c8|11223344556677885f5f5f5f5f	64	intel	monitor
-0f01c8|11223344556677885f5f5f5f5f	64	plan9	MONITOR
-0f01c9|11223344556677885f5f5f5f5f	32	intel	mwait
-0f01c9|11223344556677885f5f5f5f5f	32	plan9	MWAIT
-0f01c9|11223344556677885f5f5f5f5f	64	gnu	mwait %rax,%rcx
-0f01c9|11223344556677885f5f5f5f5f	64	intel	mwait
-0f01c9|11223344556677885f5f5f5f5f	64	plan9	MWAIT
-0f01d0|11223344556677885f5f5f5f5f	32	intel	xgetbv
-0f01d0|11223344556677885f5f5f5f5f	32	plan9	XGETBV
-0f01d0|11223344556677885f5f5f5f5f	64	gnu	xgetbv
-0f01d0|11223344556677885f5f5f5f5f	64	intel	xgetbv
-0f01d0|11223344556677885f5f5f5f5f	64	plan9	XGETBV
-0f01d1|11223344556677885f5f5f5f5f	32	intel	xsetbv
-0f01d1|11223344556677885f5f5f5f5f	32	plan9	XSETBV
-0f01d1|11223344556677885f5f5f5f5f	64	gnu	xsetbv
-0f01d1|11223344556677885f5f5f5f5f	64	intel	xsetbv
-0f01d1|11223344556677885f5f5f5f5f	64	plan9	XSETBV
-0f01d5|11223344556677885f5f5f5f5f	32	intel	xend
-0f01d5|11223344556677885f5f5f5f5f	32	plan9	XEND
-0f01d5|11223344556677885f5f5f5f5f	64	gnu	xend
-0f01d5|11223344556677885f5f5f5f5f	64	intel	xend
-0f01d5|11223344556677885f5f5f5f5f	64	plan9	XEND
-0f01d6|11223344556677885f5f5f5f5f	32	intel	xtest
-0f01d6|11223344556677885f5f5f5f5f	32	plan9	XTEST
-0f01d6|11223344556677885f5f5f5f5f	64	gnu	xtest
-0f01d6|11223344556677885f5f5f5f5f	64	intel	xtest
-0f01d6|11223344556677885f5f5f5f5f	64	plan9	XTEST
-0f01f8|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f01f8|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f01f8|11223344556677885f5f5f5f5f	64	gnu	swapgs
-0f01f8|11223344556677885f5f5f5f5f	64	intel	swapgs
-0f01f8|11223344556677885f5f5f5f5f	64	plan9	SWAPGS
-0f01f9|11223344556677885f5f5f5f5f	32	intel	rdtscp
-0f01f9|11223344556677885f5f5f5f5f	32	plan9	RDTSCP
-0f01f9|11223344556677885f5f5f5f5f	64	gnu	rdtscp
-0f01f9|11223344556677885f5f5f5f5f	64	intel	rdtscp
-0f01f9|11223344556677885f5f5f5f5f	64	plan9	RDTSCP
-0f0211|223344556677885f5f5f5f5f5f	32	intel	lar edx, word ptr [ecx]
-0f0211|223344556677885f5f5f5f5f5f	32	plan9	LAR 0(CX), DX
-0f0211|223344556677885f5f5f5f5f5f	64	gnu	lar (%rcx),%edx
-0f0211|223344556677885f5f5f5f5f5f	64	intel	lar edx, word ptr [rcx]
-0f0211|223344556677885f5f5f5f5f5f	64	plan9	LAR 0(CX), DX
-0f0311|223344556677885f5f5f5f5f5f	32	intel	lsl edx, word ptr [ecx]
-0f0311|223344556677885f5f5f5f5f5f	32	plan9	LSL 0(CX), DX
-0f0311|223344556677885f5f5f5f5f5f	64	gnu	lsl (%rcx),%edx
-0f0311|223344556677885f5f5f5f5f5f	64	intel	lsl edx, word ptr [rcx]
-0f0311|223344556677885f5f5f5f5f5f	64	plan9	LSL 0(CX), DX
-0f04|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f04|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f04|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f04|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f04|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f05|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f05|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f05|11223344556677885f5f5f5f5f5f	64	gnu	syscall
-0f05|11223344556677885f5f5f5f5f5f	64	intel	syscall
-0f05|11223344556677885f5f5f5f5f5f	64	plan9	SYSCALL
-0f06|11223344556677885f5f5f5f5f5f	32	intel	clts
-0f06|11223344556677885f5f5f5f5f5f	32	plan9	CLTS
-0f06|11223344556677885f5f5f5f5f5f	64	gnu	clts
-0f06|11223344556677885f5f5f5f5f5f	64	intel	clts
-0f06|11223344556677885f5f5f5f5f5f	64	plan9	CLTS
-0f07|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f07|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f07|11223344556677885f5f5f5f5f5f	64	gnu	sysretq
-0f07|11223344556677885f5f5f5f5f5f	64	intel	sysret
-0f07|11223344556677885f5f5f5f5f5f	64	plan9	SYSRET
-0f08|11223344556677885f5f5f5f5f5f	32	intel	invd
-0f08|11223344556677885f5f5f5f5f5f	32	plan9	INVD
-0f08|11223344556677885f5f5f5f5f5f	64	gnu	invd
-0f08|11223344556677885f5f5f5f5f5f	64	intel	invd
-0f08|11223344556677885f5f5f5f5f5f	64	plan9	INVD
-0f09|11223344556677885f5f5f5f5f5f	32	intel	wbinvd
-0f09|11223344556677885f5f5f5f5f5f	32	plan9	WBINVD
-0f09|11223344556677885f5f5f5f5f5f	64	gnu	wbinvd
-0f09|11223344556677885f5f5f5f5f5f	64	intel	wbinvd
-0f09|11223344556677885f5f5f5f5f5f	64	plan9	WBINVD
-0f0b|11223344556677885f5f5f5f5f5f	32	intel	ud2
-0f0b|11223344556677885f5f5f5f5f5f	32	plan9	UD2
-0f0b|11223344556677885f5f5f5f5f5f	64	gnu	ud2
-0f0b|11223344556677885f5f5f5f5f5f	64	intel	ud2
-0f0b|11223344556677885f5f5f5f5f5f	64	plan9	UD2
-0f0d08|11223344556677885f5f5f5f5f	32	intel	prefetchw zmmword ptr [eax]
-0f0d08|11223344556677885f5f5f5f5f	32	plan9	PREFETCHW 0(AX)
-0f0d08|11223344556677885f5f5f5f5f	64	gnu	prefetchw (%rax)
-0f0d08|11223344556677885f5f5f5f5f	64	intel	prefetchw zmmword ptr [rax]
-0f0d08|11223344556677885f5f5f5f5f	64	plan9	PREFETCHW 0(AX)
-0f1011|223344556677885f5f5f5f5f5f	32	intel	movups xmm2, xmmword ptr [ecx]
-0f1011|223344556677885f5f5f5f5f5f	32	plan9	MOVUPS 0(CX), X2
-0f1011|223344556677885f5f5f5f5f5f	64	gnu	movups (%rcx),%xmm2
-0f1011|223344556677885f5f5f5f5f5f	64	intel	movups xmm2, xmmword ptr [rcx]
-0f1011|223344556677885f5f5f5f5f5f	64	plan9	MOVUPS 0(CX), X2
-0f1122|3344556677885f5f5f5f5f5f5f	32	intel	movups xmmword ptr [edx], xmm4
-0f1122|3344556677885f5f5f5f5f5f5f	32	plan9	MOVUPS X4, 0(DX)
-0f1122|3344556677885f5f5f5f5f5f5f	64	gnu	movups %xmm4,(%rdx)
-0f1122|3344556677885f5f5f5f5f5f5f	64	intel	movups xmmword ptr [rdx], xmm4
-0f1122|3344556677885f5f5f5f5f5f5f	64	plan9	MOVUPS X4, 0(DX)
-0f1211|223344556677885f5f5f5f5f5f	32	intel	movlps xmm2, qword ptr [ecx]
-0f1211|223344556677885f5f5f5f5f5f	32	plan9	MOVLPS 0(CX), X2
-0f1211|223344556677885f5f5f5f5f5f	64	gnu	movlps (%rcx),%xmm2
-0f1211|223344556677885f5f5f5f5f5f	64	intel	movlps xmm2, qword ptr [rcx]
-0f1211|223344556677885f5f5f5f5f5f	64	plan9	MOVLPS 0(CX), X2
-0f12c0|11223344556677885f5f5f5f5f	32	intel	movhlps xmm0, xmm0
-0f12c0|11223344556677885f5f5f5f5f	32	plan9	MOVHLPS X0, X0
-0f12c0|11223344556677885f5f5f5f5f	64	gnu	movhlps %xmm0,%xmm0
-0f12c0|11223344556677885f5f5f5f5f	64	intel	movhlps xmm0, xmm0
-0f12c0|11223344556677885f5f5f5f5f	64	plan9	MOVHLPS X0, X0
-0f1311|223344556677885f5f5f5f5f5f	32	intel	movlps qword ptr [ecx], xmm2
-0f1311|223344556677885f5f5f5f5f5f	32	plan9	MOVLPS X2, 0(CX)
-0f1311|223344556677885f5f5f5f5f5f	64	gnu	movlps %xmm2,(%rcx)
-0f1311|223344556677885f5f5f5f5f5f	64	intel	movlps qword ptr [rcx], xmm2
-0f1311|223344556677885f5f5f5f5f5f	64	plan9	MOVLPS X2, 0(CX)
-0f1411|223344556677885f5f5f5f5f5f	32	intel	unpcklps xmm2, xmmword ptr [ecx]
-0f1411|223344556677885f5f5f5f5f5f	32	plan9	UNPCKLPS 0(CX), X2
-0f1411|223344556677885f5f5f5f5f5f	64	gnu	unpcklps (%rcx),%xmm2
-0f1411|223344556677885f5f5f5f5f5f	64	intel	unpcklps xmm2, xmmword ptr [rcx]
-0f1411|223344556677885f5f5f5f5f5f	64	plan9	UNPCKLPS 0(CX), X2
-0f1511|223344556677885f5f5f5f5f5f	32	intel	unpckhps xmm2, xmmword ptr [ecx]
-0f1511|223344556677885f5f5f5f5f5f	32	plan9	UNPCKHPS 0(CX), X2
-0f1511|223344556677885f5f5f5f5f5f	64	gnu	unpckhps (%rcx),%xmm2
-0f1511|223344556677885f5f5f5f5f5f	64	intel	unpckhps xmm2, xmmword ptr [rcx]
-0f1511|223344556677885f5f5f5f5f5f	64	plan9	UNPCKHPS 0(CX), X2
-0f1611|223344556677885f5f5f5f5f5f	32	intel	movhps xmm2, qword ptr [ecx]
-0f1611|223344556677885f5f5f5f5f5f	32	plan9	MOVHPS 0(CX), X2
-0f1611|223344556677885f5f5f5f5f5f	64	gnu	movhps (%rcx),%xmm2
-0f1611|223344556677885f5f5f5f5f5f	64	intel	movhps xmm2, qword ptr [rcx]
-0f1611|223344556677885f5f5f5f5f5f	64	plan9	MOVHPS 0(CX), X2
-0f16c0|11223344556677885f5f5f5f5f	32	intel	movlhps xmm0, xmm0
-0f16c0|11223344556677885f5f5f5f5f	32	plan9	MOVLHPS X0, X0
-0f16c0|11223344556677885f5f5f5f5f	64	gnu	movlhps %xmm0,%xmm0
-0f16c0|11223344556677885f5f5f5f5f	64	intel	movlhps xmm0, xmm0
-0f16c0|11223344556677885f5f5f5f5f	64	plan9	MOVLHPS X0, X0
-0f1711|223344556677885f5f5f5f5f5f	32	intel	movhps qword ptr [ecx], xmm2
-0f1711|223344556677885f5f5f5f5f5f	32	plan9	MOVHPS X2, 0(CX)
-0f1711|223344556677885f5f5f5f5f5f	64	gnu	movhps %xmm2,(%rcx)
-0f1711|223344556677885f5f5f5f5f5f	64	intel	movhps qword ptr [rcx], xmm2
-0f1711|223344556677885f5f5f5f5f5f	64	plan9	MOVHPS X2, 0(CX)
-0f1800|11223344556677885f5f5f5f5f	32	intel	prefetchnta zmmword ptr [eax]
-0f1800|11223344556677885f5f5f5f5f	32	plan9	PREFETCHNTA 0(AX)
-0f1800|11223344556677885f5f5f5f5f	64	gnu	prefetchnta (%rax)
-0f1800|11223344556677885f5f5f5f5f	64	intel	prefetchnta zmmword ptr [rax]
-0f1800|11223344556677885f5f5f5f5f	64	plan9	PREFETCHNTA 0(AX)
-0f1808|11223344556677885f5f5f5f5f	32	intel	prefetcht0 zmmword ptr [eax]
-0f1808|11223344556677885f5f5f5f5f	32	plan9	PREFETCHT0 0(AX)
-0f1808|11223344556677885f5f5f5f5f	64	gnu	prefetcht0 (%rax)
-0f1808|11223344556677885f5f5f5f5f	64	intel	prefetcht0 zmmword ptr [rax]
-0f1808|11223344556677885f5f5f5f5f	64	plan9	PREFETCHT0 0(AX)
-0f1811|223344556677885f5f5f5f5f5f	32	intel	prefetcht1 zmmword ptr [ecx]
-0f1811|223344556677885f5f5f5f5f5f	32	plan9	PREFETCHT1 0(CX)
-0f1811|223344556677885f5f5f5f5f5f	64	gnu	prefetcht1 (%rcx)
-0f1811|223344556677885f5f5f5f5f5f	64	intel	prefetcht1 zmmword ptr [rcx]
-0f1811|223344556677885f5f5f5f5f5f	64	plan9	PREFETCHT1 0(CX)
-0f1818|11223344556677885f5f5f5f5f	32	intel	prefetcht2 zmmword ptr [eax]
-0f1818|11223344556677885f5f5f5f5f	32	plan9	PREFETCHT2 0(AX)
-0f1818|11223344556677885f5f5f5f5f	64	gnu	prefetcht2 (%rax)
-0f1818|11223344556677885f5f5f5f5f	64	intel	prefetcht2 zmmword ptr [rax]
-0f1818|11223344556677885f5f5f5f5f	64	plan9	PREFETCHT2 0(AX)
-0f1f00|11223344556677885f5f5f5f5f	32	intel	nop dword ptr [eax], eax
-0f1f00|11223344556677885f5f5f5f5f	32	plan9	NOPL 0(AX)
-0f1f00|11223344556677885f5f5f5f5f	64	gnu	nopl (%rax)
-0f1f00|11223344556677885f5f5f5f5f	64	intel	nop dword ptr [rax], eax
-0f1f00|11223344556677885f5f5f5f5f	64	plan9	NOPL 0(AX)
-0f2011|223344556677885f5f5f5f5f5f	32	intel	mov ecx, cr2
-0f2011|223344556677885f5f5f5f5f5f	32	plan9	MOVL CR2, CX
-0f2011|223344556677885f5f5f5f5f5f	64	gnu	mov %cr2,%rcx
-0f2011|223344556677885f5f5f5f5f5f	64	intel	mov rcx, cr2
-0f2011|223344556677885f5f5f5f5f5f	64	plan9	MOVL CR2, CX
-0f2111|223344556677885f5f5f5f5f5f	32	intel	mov ecx, dr2
-0f2111|223344556677885f5f5f5f5f5f	32	plan9	MOVL DR2, CX
-0f2111|223344556677885f5f5f5f5f5f	64	gnu	mov %db2,%rcx
-0f2111|223344556677885f5f5f5f5f5f	64	intel	mov rcx, dr2
-0f2111|223344556677885f5f5f5f5f5f	64	plan9	MOVL DR2, CX
-0f2211|223344556677885f5f5f5f5f5f	32	intel	mov cr2, ecx
-0f2211|223344556677885f5f5f5f5f5f	32	plan9	MOVL CX, CR2
-0f2211|223344556677885f5f5f5f5f5f	64	gnu	mov %rcx,%cr2
-0f2211|223344556677885f5f5f5f5f5f	64	intel	mov cr2, rcx
-0f2211|223344556677885f5f5f5f5f5f	64	plan9	MOVL CX, CR2
-0f2311|223344556677885f5f5f5f5f5f	32	intel	mov dr2, ecx
-0f2311|223344556677885f5f5f5f5f5f	32	plan9	MOVL CX, DR2
-0f2311|223344556677885f5f5f5f5f5f	64	gnu	mov %rcx,%db2
-0f2311|223344556677885f5f5f5f5f5f	64	intel	mov dr2, rcx
-0f2311|223344556677885f5f5f5f5f5f	64	plan9	MOVL CX, DR2
-0f2411|223344556677885f5f5f5f5f5f	32	intel	mov ecx, tr2
-0f2411|223344556677885f5f5f5f5f5f	32	plan9	MOVL TR2, CX
-0f2411|223344556677885f5f5f5f5f5f	64	gnu	mov %tr2,%rcx
-0f2411|223344556677885f5f5f5f5f5f	64	intel	mov rcx, tr2
-0f2411|223344556677885f5f5f5f5f5f	64	plan9	MOVL TR2, CX
-0f2611|223344556677885f5f5f5f5f5f	32	intel	mov tr2, ecx
-0f2611|223344556677885f5f5f5f5f5f	32	plan9	MOVL CX, TR2
-0f2611|223344556677885f5f5f5f5f5f	64	gnu	mov %rcx,%tr2
-0f2611|223344556677885f5f5f5f5f5f	64	intel	mov tr2, rcx
-0f2611|223344556677885f5f5f5f5f5f	64	plan9	MOVL CX, TR2
-0f2811|223344556677885f5f5f5f5f5f	32	intel	movaps xmm2, xmmword ptr [ecx]
-0f2811|223344556677885f5f5f5f5f5f	32	plan9	MOVAPS 0(CX), X2
-0f2811|223344556677885f5f5f5f5f5f	64	gnu	movaps (%rcx),%xmm2
-0f2811|223344556677885f5f5f5f5f5f	64	intel	movaps xmm2, xmmword ptr [rcx]
-0f2811|223344556677885f5f5f5f5f5f	64	plan9	MOVAPS 0(CX), X2
-0f2911|223344556677885f5f5f5f5f5f	32	intel	movaps xmmword ptr [ecx], xmm2
-0f2911|223344556677885f5f5f5f5f5f	32	plan9	MOVAPS X2, 0(CX)
-0f2911|223344556677885f5f5f5f5f5f	64	gnu	movaps %xmm2,(%rcx)
-0f2911|223344556677885f5f5f5f5f5f	64	intel	movaps xmmword ptr [rcx], xmm2
-0f2911|223344556677885f5f5f5f5f5f	64	plan9	MOVAPS X2, 0(CX)
-0f2a11|223344556677885f5f5f5f5f5f	32	intel	cvtpi2ps xmm2, qword ptr [ecx]
-0f2a11|223344556677885f5f5f5f5f5f	32	plan9	CVTPI2PS 0(CX), X2
-0f2a11|223344556677885f5f5f5f5f5f	64	gnu	cvtpi2ps (%rcx),%xmm2
-0f2a11|223344556677885f5f5f5f5f5f	64	intel	cvtpi2ps xmm2, qword ptr [rcx]
-0f2a11|223344556677885f5f5f5f5f5f	64	plan9	CVTPI2PS 0(CX), X2
-0f2b11|223344556677885f5f5f5f5f5f	32	intel	movntps xmmword ptr [ecx], xmm2
-0f2b11|223344556677885f5f5f5f5f5f	32	plan9	MOVNTPS X2, 0(CX)
-0f2b11|223344556677885f5f5f5f5f5f	64	gnu	movntps %xmm2,(%rcx)
-0f2b11|223344556677885f5f5f5f5f5f	64	intel	movntps xmmword ptr [rcx], xmm2
-0f2b11|223344556677885f5f5f5f5f5f	64	plan9	MOVNTPS X2, 0(CX)
-0f2c11|223344556677885f5f5f5f5f5f	32	intel	cvttps2pi mmx2, qword ptr [ecx]
-0f2c11|223344556677885f5f5f5f5f5f	32	plan9	CVTTPS2PI 0(CX), M2
-0f2c11|223344556677885f5f5f5f5f5f	64	gnu	cvttps2pi (%rcx),%mm2
-0f2c11|223344556677885f5f5f5f5f5f	64	intel	cvttps2pi mmx2, qword ptr [rcx]
-0f2c11|223344556677885f5f5f5f5f5f	64	plan9	CVTTPS2PI 0(CX), M2
-0f2d11|223344556677885f5f5f5f5f5f	32	intel	cvtps2pi mmx2, qword ptr [ecx]
-0f2d11|223344556677885f5f5f5f5f5f	32	plan9	CVTPS2PI 0(CX), M2
-0f2d11|223344556677885f5f5f5f5f5f	64	gnu	cvtps2pi (%rcx),%mm2
-0f2d11|223344556677885f5f5f5f5f5f	64	intel	cvtps2pi mmx2, qword ptr [rcx]
-0f2d11|223344556677885f5f5f5f5f5f	64	plan9	CVTPS2PI 0(CX), M2
-0f2e11|223344556677885f5f5f5f5f5f	32	intel	ucomiss xmm2, dword ptr [ecx]
-0f2e11|223344556677885f5f5f5f5f5f	32	plan9	UCOMISS 0(CX), X2
-0f2e11|223344556677885f5f5f5f5f5f	64	gnu	ucomiss (%rcx),%xmm2
-0f2e11|223344556677885f5f5f5f5f5f	64	intel	ucomiss xmm2, dword ptr [rcx]
-0f2e11|223344556677885f5f5f5f5f5f	64	plan9	UCOMISS 0(CX), X2
-0f2f11|223344556677885f5f5f5f5f5f	32	intel	comiss xmm2, dword ptr [ecx]
-0f2f11|223344556677885f5f5f5f5f5f	32	plan9	COMISS 0(CX), X2
-0f2f11|223344556677885f5f5f5f5f5f	64	gnu	comiss (%rcx),%xmm2
-0f2f11|223344556677885f5f5f5f5f5f	64	intel	comiss xmm2, dword ptr [rcx]
-0f2f11|223344556677885f5f5f5f5f5f	64	plan9	COMISS 0(CX), X2
-0f30|11223344556677885f5f5f5f5f5f	32	intel	wrmsr
-0f30|11223344556677885f5f5f5f5f5f	32	plan9	WRMSR
-0f30|11223344556677885f5f5f5f5f5f	64	gnu	wrmsr
-0f30|11223344556677885f5f5f5f5f5f	64	intel	wrmsr
-0f30|11223344556677885f5f5f5f5f5f	64	plan9	WRMSR
-0f31|11223344556677885f5f5f5f5f5f	32	intel	rdtsc
-0f31|11223344556677885f5f5f5f5f5f	32	plan9	RDTSC
-0f31|11223344556677885f5f5f5f5f5f	64	gnu	rdtsc
-0f31|11223344556677885f5f5f5f5f5f	64	intel	rdtsc
-0f31|11223344556677885f5f5f5f5f5f	64	plan9	RDTSC
-0f32|11223344556677885f5f5f5f5f5f	32	intel	rdmsr
-0f32|11223344556677885f5f5f5f5f5f	32	plan9	RDMSR
-0f32|11223344556677885f5f5f5f5f5f	64	gnu	rdmsr
-0f32|11223344556677885f5f5f5f5f5f	64	intel	rdmsr
-0f32|11223344556677885f5f5f5f5f5f	64	plan9	RDMSR
-0f33|11223344556677885f5f5f5f5f5f	32	intel	rdpmc
-0f33|11223344556677885f5f5f5f5f5f	32	plan9	RDPMC
-0f33|11223344556677885f5f5f5f5f5f	64	gnu	rdpmc
-0f33|11223344556677885f5f5f5f5f5f	64	intel	rdpmc
-0f33|11223344556677885f5f5f5f5f5f	64	plan9	RDPMC
-0f34|11223344556677885f5f5f5f5f5f	32	intel	sysenter
-0f34|11223344556677885f5f5f5f5f5f	32	plan9	SYSENTER
-0f34|11223344556677885f5f5f5f5f5f	64	gnu	sysenter
-0f34|11223344556677885f5f5f5f5f5f	64	intel	sysenter
-0f34|11223344556677885f5f5f5f5f5f	64	plan9	SYSENTER
-0f35|11223344556677885f5f5f5f5f5f	32	intel	sysexit
-0f35|11223344556677885f5f5f5f5f5f	32	plan9	SYSEXIT
-0f35|11223344556677885f5f5f5f5f5f	64	gnu	sysexit
-0f35|11223344556677885f5f5f5f5f5f	64	intel	sysexit
-0f35|11223344556677885f5f5f5f5f5f	64	plan9	SYSEXIT
-0f380011|223344556677885f5f5f5f5f	32	intel	pshufb mmx2, qword ptr [ecx]
-0f380011|223344556677885f5f5f5f5f	32	plan9	PSHUFB 0(CX), M2
-0f380011|223344556677885f5f5f5f5f	64	gnu	pshufb (%rcx),%mm2
-0f380011|223344556677885f5f5f5f5f	64	intel	pshufb mmx2, qword ptr [rcx]
-0f380011|223344556677885f5f5f5f5f	64	plan9	PSHUFB 0(CX), M2
-0f380111|223344556677885f5f5f5f5f	32	intel	phaddw mmx2, qword ptr [ecx]
-0f380111|223344556677885f5f5f5f5f	32	plan9	PHADDW 0(CX), M2
-0f380111|223344556677885f5f5f5f5f	64	gnu	phaddw (%rcx),%mm2
-0f380111|223344556677885f5f5f5f5f	64	intel	phaddw mmx2, qword ptr [rcx]
-0f380111|223344556677885f5f5f5f5f	64	plan9	PHADDW 0(CX), M2
-0f380211|223344556677885f5f5f5f5f	32	intel	phaddd mmx2, qword ptr [ecx]
-0f380211|223344556677885f5f5f5f5f	32	plan9	PHADDD 0(CX), M2
-0f380211|223344556677885f5f5f5f5f	64	gnu	phaddd (%rcx),%mm2
-0f380211|223344556677885f5f5f5f5f	64	intel	phaddd mmx2, qword ptr [rcx]
-0f380211|223344556677885f5f5f5f5f	64	plan9	PHADDD 0(CX), M2
-0f380311|223344556677885f5f5f5f5f	32	intel	phaddsw mmx2, qword ptr [ecx]
-0f380311|223344556677885f5f5f5f5f	32	plan9	PHADDSW 0(CX), M2
-0f380311|223344556677885f5f5f5f5f	64	gnu	phaddsw (%rcx),%mm2
-0f380311|223344556677885f5f5f5f5f	64	intel	phaddsw mmx2, qword ptr [rcx]
-0f380311|223344556677885f5f5f5f5f	64	plan9	PHADDSW 0(CX), M2
-0f380411|223344556677885f5f5f5f5f	32	intel	pmaddubsw mmx2, qword ptr [ecx]
-0f380411|223344556677885f5f5f5f5f	32	plan9	PMADDUBSW 0(CX), M2
-0f380411|223344556677885f5f5f5f5f	64	gnu	pmaddubsw (%rcx),%mm2
-0f380411|223344556677885f5f5f5f5f	64	intel	pmaddubsw mmx2, qword ptr [rcx]
-0f380411|223344556677885f5f5f5f5f	64	plan9	PMADDUBSW 0(CX), M2
-0f380511|223344556677885f5f5f5f5f	32	intel	phsubw mmx2, qword ptr [ecx]
-0f380511|223344556677885f5f5f5f5f	32	plan9	PHSUBW 0(CX), M2
-0f380511|223344556677885f5f5f5f5f	64	gnu	phsubw (%rcx),%mm2
-0f380511|223344556677885f5f5f5f5f	64	intel	phsubw mmx2, qword ptr [rcx]
-0f380511|223344556677885f5f5f5f5f	64	plan9	PHSUBW 0(CX), M2
-0f380611|223344556677885f5f5f5f5f	32	intel	phsubd mmx2, qword ptr [ecx]
-0f380611|223344556677885f5f5f5f5f	32	plan9	PHSUBD 0(CX), M2
-0f380611|223344556677885f5f5f5f5f	64	gnu	phsubd (%rcx),%mm2
-0f380611|223344556677885f5f5f5f5f	64	intel	phsubd mmx2, qword ptr [rcx]
-0f380611|223344556677885f5f5f5f5f	64	plan9	PHSUBD 0(CX), M2
-0f380711|223344556677885f5f5f5f5f	32	intel	phsubsw mmx2, qword ptr [ecx]
-0f380711|223344556677885f5f5f5f5f	32	plan9	PHSUBSW 0(CX), M2
-0f380711|223344556677885f5f5f5f5f	64	gnu	phsubsw (%rcx),%mm2
-0f380711|223344556677885f5f5f5f5f	64	intel	phsubsw mmx2, qword ptr [rcx]
-0f380711|223344556677885f5f5f5f5f	64	plan9	PHSUBSW 0(CX), M2
-0f380811|223344556677885f5f5f5f5f	32	intel	psignb mmx2, qword ptr [ecx]
-0f380811|223344556677885f5f5f5f5f	32	plan9	PSIGNB 0(CX), M2
-0f380811|223344556677885f5f5f5f5f	64	gnu	psignb (%rcx),%mm2
-0f380811|223344556677885f5f5f5f5f	64	intel	psignb mmx2, qword ptr [rcx]
-0f380811|223344556677885f5f5f5f5f	64	plan9	PSIGNB 0(CX), M2
-0f380911|223344556677885f5f5f5f5f	32	intel	psignw mmx2, qword ptr [ecx]
-0f380911|223344556677885f5f5f5f5f	32	plan9	PSIGNW 0(CX), M2
-0f380911|223344556677885f5f5f5f5f	64	gnu	psignw (%rcx),%mm2
-0f380911|223344556677885f5f5f5f5f	64	intel	psignw mmx2, qword ptr [rcx]
-0f380911|223344556677885f5f5f5f5f	64	plan9	PSIGNW 0(CX), M2
-0f380a11|223344556677885f5f5f5f5f	32	intel	psignd mmx2, qword ptr [ecx]
-0f380a11|223344556677885f5f5f5f5f	32	plan9	PSIGND 0(CX), M2
-0f380a11|223344556677885f5f5f5f5f	64	gnu	psignd (%rcx),%mm2
-0f380a11|223344556677885f5f5f5f5f	64	intel	psignd mmx2, qword ptr [rcx]
-0f380a11|223344556677885f5f5f5f5f	64	plan9	PSIGND 0(CX), M2
-0f380b11|223344556677885f5f5f5f5f	32	intel	pmulhrsw mmx2, qword ptr [ecx]
-0f380b11|223344556677885f5f5f5f5f	32	plan9	PMULHRSW 0(CX), M2
-0f380b11|223344556677885f5f5f5f5f	64	gnu	pmulhrsw (%rcx),%mm2
-0f380b11|223344556677885f5f5f5f5f	64	intel	pmulhrsw mmx2, qword ptr [rcx]
-0f380b11|223344556677885f5f5f5f5f	64	plan9	PMULHRSW 0(CX), M2
-0f3810|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3810|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3810|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3810|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3810|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3811|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3811|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3811|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3811|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3811|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3814|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3814|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3814|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3814|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3814|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3815|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3815|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3815|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3815|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3815|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3817|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3817|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3817|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3817|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3817|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f381c11|223344556677885f5f5f5f5f	32	intel	pabsb mmx2, qword ptr [ecx]
-0f381c11|223344556677885f5f5f5f5f	32	plan9	PABSB 0(CX), M2
-0f381c11|223344556677885f5f5f5f5f	64	gnu	pabsb (%rcx),%mm2
-0f381c11|223344556677885f5f5f5f5f	64	intel	pabsb mmx2, qword ptr [rcx]
-0f381c11|223344556677885f5f5f5f5f	64	plan9	PABSB 0(CX), M2
-0f381d11|223344556677885f5f5f5f5f	32	intel	pabsw mmx2, qword ptr [ecx]
-0f381d11|223344556677885f5f5f5f5f	32	plan9	PABSW 0(CX), M2
-0f381d11|223344556677885f5f5f5f5f	64	gnu	pabsw (%rcx),%mm2
-0f381d11|223344556677885f5f5f5f5f	64	intel	pabsw mmx2, qword ptr [rcx]
-0f381d11|223344556677885f5f5f5f5f	64	plan9	PABSW 0(CX), M2
-0f381e11|223344556677885f5f5f5f5f	32	intel	pabsd mmx2, qword ptr [ecx]
-0f381e11|223344556677885f5f5f5f5f	32	plan9	PABSD 0(CX), M2
-0f381e11|223344556677885f5f5f5f5f	64	gnu	pabsd (%rcx),%mm2
-0f381e11|223344556677885f5f5f5f5f	64	intel	pabsd mmx2, qword ptr [rcx]
-0f381e11|223344556677885f5f5f5f5f	64	plan9	PABSD 0(CX), M2
-0f3820|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3820|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3820|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3820|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3820|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3821|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3821|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3821|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3821|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3821|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3822|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3822|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3822|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3822|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3822|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3823|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3823|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3823|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3823|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3823|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3824|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3824|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3824|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3824|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3824|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3825|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3825|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3825|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3825|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3825|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3828|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3828|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3828|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3828|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3828|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3829|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3829|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3829|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3829|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3829|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f382a|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f382a|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f382a|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f382a|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f382a|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f382b|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f382b|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f382b|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f382b|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f382b|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3830|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3830|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3830|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3830|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3830|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3831|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3831|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3831|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3831|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3831|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3832|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3832|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3832|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3832|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3832|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3833|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3833|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3833|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3833|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3833|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3834|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3834|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3834|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3834|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3834|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3835|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3835|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3835|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3835|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3835|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3837|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3837|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3837|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3837|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3837|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3838|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3838|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3838|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3838|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3838|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3839|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3839|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3839|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3839|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3839|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f383a|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f383a|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f383a|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f383a|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f383a|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f383b|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f383b|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f383b|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f383b|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f383b|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f383c|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f383c|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f383c|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f383c|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f383c|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f383d|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f383d|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f383d|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f383d|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f383d|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f383e|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f383e|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f383e|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f383e|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f383e|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f383f|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f383f|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f383f|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f383f|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f383f|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3840|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3840|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3840|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3840|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3840|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3841|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3841|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3841|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3841|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3841|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3882|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3882|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3882|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3882|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3882|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f38db|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f38db|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f38db|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f38db|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f38db|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f38dc|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f38dc|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f38dc|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f38dc|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f38dc|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f38dd|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f38dd|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f38dd|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f38dd|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f38dd|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f38de|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f38de|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f38de|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f38de|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f38de|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f38df|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f38df|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f38df|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f38df|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f38df|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f38f011|223344556677885f5f5f5f5f	32	intel	movbe edx, dword ptr [ecx]
-0f38f011|223344556677885f5f5f5f5f	32	plan9	MOVBE 0(CX), DX
-0f38f011|223344556677885f5f5f5f5f	64	gnu	movbe (%rcx),%edx
-0f38f011|223344556677885f5f5f5f5f	64	intel	movbe edx, dword ptr [rcx]
-0f38f011|223344556677885f5f5f5f5f	64	plan9	MOVBE 0(CX), DX
-0f38f111|223344556677885f5f5f5f5f	32	intel	movbe dword ptr [ecx], edx
-0f38f111|223344556677885f5f5f5f5f	32	plan9	MOVBE DX, 0(CX)
-0f38f111|223344556677885f5f5f5f5f	64	gnu	movbe %edx,(%rcx)
-0f38f111|223344556677885f5f5f5f5f	64	intel	movbe dword ptr [rcx], edx
-0f38f111|223344556677885f5f5f5f5f	64	plan9	MOVBE DX, 0(CX)
-0f3a08|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a08|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a08|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a08|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a08|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a09|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a09|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a09|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a09|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a09|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a0a|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a0a|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a0a|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a0a|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a0a|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a0b|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a0b|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a0b|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a0b|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a0b|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a0c|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a0c|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a0c|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a0c|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a0c|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a0d|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a0d|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a0d|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a0d|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a0d|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a0e|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a0e|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a0e|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a0e|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a0e|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a0f1122|3344556677885f5f5f5f5f	32	intel	palignr mmx2, qword ptr [ecx], 0x22
-0f3a0f1122|3344556677885f5f5f5f5f	32	plan9	PALIGNR $0x22, 0(CX), M2
-0f3a0f1122|3344556677885f5f5f5f5f	64	gnu	palignr $0x22,(%rcx),%mm2
-0f3a0f1122|3344556677885f5f5f5f5f	64	intel	palignr mmx2, qword ptr [rcx], 0x22
-0f3a0f1122|3344556677885f5f5f5f5f	64	plan9	PALIGNR $0x22, 0(CX), M2
-0f3a11|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a11|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a11|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a11|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a11|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a14|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a14|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a14|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a14|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a14|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a15|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a15|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a15|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a15|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a15|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a16|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a16|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a16|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a16|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a16|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a17|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a17|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a17|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a17|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a17|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a20|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a20|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a20|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a20|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a20|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a21|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a21|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a21|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a21|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a21|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a22|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a22|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a22|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a22|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a22|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a40|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a40|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a40|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a40|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a40|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a41|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a41|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a41|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a41|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a41|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a42|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a42|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a42|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a42|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a42|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a44|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a44|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a44|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a44|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a44|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a60|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a60|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a60|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a60|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a60|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a61|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a61|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a61|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a61|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a61|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a62|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a62|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a62|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a62|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a62|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3a63|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3a63|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3a63|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3a63|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3a63|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f3adf|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f3adf|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f3adf|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f3adf|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f3adf|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f4011|223344556677885f5f5f5f5f5f	32	intel	cmovo edx, dword ptr [ecx]
-0f4011|223344556677885f5f5f5f5f5f	32	plan9	CMOVO 0(CX), DX
-0f4011|223344556677885f5f5f5f5f5f	64	gnu	cmovo (%rcx),%edx
-0f4011|223344556677885f5f5f5f5f5f	64	intel	cmovo edx, dword ptr [rcx]
-0f4011|223344556677885f5f5f5f5f5f	64	plan9	CMOVO 0(CX), DX
-0f4111|223344556677885f5f5f5f5f5f	32	intel	cmovno edx, dword ptr [ecx]
-0f4111|223344556677885f5f5f5f5f5f	32	plan9	CMOVNO 0(CX), DX
-0f4111|223344556677885f5f5f5f5f5f	64	gnu	cmovno (%rcx),%edx
-0f4111|223344556677885f5f5f5f5f5f	64	intel	cmovno edx, dword ptr [rcx]
-0f4111|223344556677885f5f5f5f5f5f	64	plan9	CMOVNO 0(CX), DX
-0f4211|223344556677885f5f5f5f5f5f	32	intel	cmovb edx, dword ptr [ecx]
-0f4211|223344556677885f5f5f5f5f5f	32	plan9	CMOVB 0(CX), DX
-0f4211|223344556677885f5f5f5f5f5f	64	gnu	cmovb (%rcx),%edx
-0f4211|223344556677885f5f5f5f5f5f	64	intel	cmovb edx, dword ptr [rcx]
-0f4211|223344556677885f5f5f5f5f5f	64	plan9	CMOVB 0(CX), DX
-0f4311|223344556677885f5f5f5f5f5f	32	intel	cmovnb edx, dword ptr [ecx]
-0f4311|223344556677885f5f5f5f5f5f	32	plan9	CMOVAE 0(CX), DX
-0f4311|223344556677885f5f5f5f5f5f	64	gnu	cmovae (%rcx),%edx
-0f4311|223344556677885f5f5f5f5f5f	64	intel	cmovnb edx, dword ptr [rcx]
-0f4311|223344556677885f5f5f5f5f5f	64	plan9	CMOVAE 0(CX), DX
-0f4411|223344556677885f5f5f5f5f5f	32	intel	cmovz edx, dword ptr [ecx]
-0f4411|223344556677885f5f5f5f5f5f	32	plan9	CMOVE 0(CX), DX
-0f4411|223344556677885f5f5f5f5f5f	64	gnu	cmove (%rcx),%edx
-0f4411|223344556677885f5f5f5f5f5f	64	intel	cmovz edx, dword ptr [rcx]
-0f4411|223344556677885f5f5f5f5f5f	64	plan9	CMOVE 0(CX), DX
-0f4511|223344556677885f5f5f5f5f5f	32	intel	cmovnz edx, dword ptr [ecx]
-0f4511|223344556677885f5f5f5f5f5f	32	plan9	CMOVNE 0(CX), DX
-0f4511|223344556677885f5f5f5f5f5f	64	gnu	cmovne (%rcx),%edx
-0f4511|223344556677885f5f5f5f5f5f	64	intel	cmovnz edx, dword ptr [rcx]
-0f4511|223344556677885f5f5f5f5f5f	64	plan9	CMOVNE 0(CX), DX
-0f4611|223344556677885f5f5f5f5f5f	32	intel	cmovbe edx, dword ptr [ecx]
-0f4611|223344556677885f5f5f5f5f5f	32	plan9	CMOVBE 0(CX), DX
-0f4611|223344556677885f5f5f5f5f5f	64	gnu	cmovbe (%rcx),%edx
-0f4611|223344556677885f5f5f5f5f5f	64	intel	cmovbe edx, dword ptr [rcx]
-0f4611|223344556677885f5f5f5f5f5f	64	plan9	CMOVBE 0(CX), DX
-0f4711|223344556677885f5f5f5f5f5f	32	intel	cmovnbe edx, dword ptr [ecx]
-0f4711|223344556677885f5f5f5f5f5f	32	plan9	CMOVA 0(CX), DX
-0f4711|223344556677885f5f5f5f5f5f	64	gnu	cmova (%rcx),%edx
-0f4711|223344556677885f5f5f5f5f5f	64	intel	cmovnbe edx, dword ptr [rcx]
-0f4711|223344556677885f5f5f5f5f5f	64	plan9	CMOVA 0(CX), DX
-0f4811|223344556677885f5f5f5f5f5f	32	intel	cmovs edx, dword ptr [ecx]
-0f4811|223344556677885f5f5f5f5f5f	32	plan9	CMOVS 0(CX), DX
-0f4811|223344556677885f5f5f5f5f5f	64	gnu	cmovs (%rcx),%edx
-0f4811|223344556677885f5f5f5f5f5f	64	intel	cmovs edx, dword ptr [rcx]
-0f4811|223344556677885f5f5f5f5f5f	64	plan9	CMOVS 0(CX), DX
-0f4911|223344556677885f5f5f5f5f5f	32	intel	cmovns edx, dword ptr [ecx]
-0f4911|223344556677885f5f5f5f5f5f	32	plan9	CMOVNS 0(CX), DX
-0f4911|223344556677885f5f5f5f5f5f	64	gnu	cmovns (%rcx),%edx
-0f4911|223344556677885f5f5f5f5f5f	64	intel	cmovns edx, dword ptr [rcx]
-0f4911|223344556677885f5f5f5f5f5f	64	plan9	CMOVNS 0(CX), DX
-0f4a11|223344556677885f5f5f5f5f5f	32	intel	cmovp edx, dword ptr [ecx]
-0f4a11|223344556677885f5f5f5f5f5f	32	plan9	CMOVP 0(CX), DX
-0f4a11|223344556677885f5f5f5f5f5f	64	gnu	cmovp (%rcx),%edx
-0f4a11|223344556677885f5f5f5f5f5f	64	intel	cmovp edx, dword ptr [rcx]
-0f4a11|223344556677885f5f5f5f5f5f	64	plan9	CMOVP 0(CX), DX
-0f4b11|223344556677885f5f5f5f5f5f	32	intel	cmovnp edx, dword ptr [ecx]
-0f4b11|223344556677885f5f5f5f5f5f	32	plan9	CMOVNP 0(CX), DX
-0f4b11|223344556677885f5f5f5f5f5f	64	gnu	cmovnp (%rcx),%edx
-0f4b11|223344556677885f5f5f5f5f5f	64	intel	cmovnp edx, dword ptr [rcx]
-0f4b11|223344556677885f5f5f5f5f5f	64	plan9	CMOVNP 0(CX), DX
-0f4c11|223344556677885f5f5f5f5f5f	32	intel	cmovl edx, dword ptr [ecx]
-0f4c11|223344556677885f5f5f5f5f5f	32	plan9	CMOVL 0(CX), DX
-0f4c11|223344556677885f5f5f5f5f5f	64	gnu	cmovl (%rcx),%edx
-0f4c11|223344556677885f5f5f5f5f5f	64	intel	cmovl edx, dword ptr [rcx]
-0f4c11|223344556677885f5f5f5f5f5f	64	plan9	CMOVL 0(CX), DX
-0f4d11|223344556677885f5f5f5f5f5f	32	intel	cmovnl edx, dword ptr [ecx]
-0f4d11|223344556677885f5f5f5f5f5f	32	plan9	CMOVGE 0(CX), DX
-0f4d11|223344556677885f5f5f5f5f5f	64	gnu	cmovge (%rcx),%edx
-0f4d11|223344556677885f5f5f5f5f5f	64	intel	cmovnl edx, dword ptr [rcx]
-0f4d11|223344556677885f5f5f5f5f5f	64	plan9	CMOVGE 0(CX), DX
-0f4e11|223344556677885f5f5f5f5f5f	32	intel	cmovle edx, dword ptr [ecx]
-0f4e11|223344556677885f5f5f5f5f5f	32	plan9	CMOVLE 0(CX), DX
-0f4e11|223344556677885f5f5f5f5f5f	64	gnu	cmovle (%rcx),%edx
-0f4e11|223344556677885f5f5f5f5f5f	64	intel	cmovle edx, dword ptr [rcx]
-0f4e11|223344556677885f5f5f5f5f5f	64	plan9	CMOVLE 0(CX), DX
-0f4f11|223344556677885f5f5f5f5f5f	32	intel	cmovnle edx, dword ptr [ecx]
-0f4f11|223344556677885f5f5f5f5f5f	32	plan9	CMOVG 0(CX), DX
-0f4f11|223344556677885f5f5f5f5f5f	64	gnu	cmovg (%rcx),%edx
-0f4f11|223344556677885f5f5f5f5f5f	64	intel	cmovnle edx, dword ptr [rcx]
-0f4f11|223344556677885f5f5f5f5f5f	64	plan9	CMOVG 0(CX), DX
-0f5011|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f5011|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f5011|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f5011|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f5011|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f50c0|11223344556677885f5f5f5f5f	32	intel	movmskps eax, xmm0
-0f50c0|11223344556677885f5f5f5f5f	32	plan9	MOVMSKPS X0, AX
-0f50c0|11223344556677885f5f5f5f5f	64	gnu	movmskps %xmm0,%eax
-0f50c0|11223344556677885f5f5f5f5f	64	intel	movmskps eax, xmm0
-0f50c0|11223344556677885f5f5f5f5f	64	plan9	MOVMSKPS X0, AX
-0f5111|223344556677885f5f5f5f5f5f	32	intel	sqrtps xmm2, xmmword ptr [ecx]
-0f5111|223344556677885f5f5f5f5f5f	32	plan9	SQRTPS 0(CX), X2
-0f5111|223344556677885f5f5f5f5f5f	64	gnu	sqrtps (%rcx),%xmm2
-0f5111|223344556677885f5f5f5f5f5f	64	intel	sqrtps xmm2, xmmword ptr [rcx]
-0f5111|223344556677885f5f5f5f5f5f	64	plan9	SQRTPS 0(CX), X2
-0f5211|223344556677885f5f5f5f5f5f	32	intel	rsqrtps xmm2, xmmword ptr [ecx]
-0f5211|223344556677885f5f5f5f5f5f	32	plan9	RSQRTPS 0(CX), X2
-0f5211|223344556677885f5f5f5f5f5f	64	gnu	rsqrtps (%rcx),%xmm2
-0f5211|223344556677885f5f5f5f5f5f	64	intel	rsqrtps xmm2, xmmword ptr [rcx]
-0f5211|223344556677885f5f5f5f5f5f	64	plan9	RSQRTPS 0(CX), X2
-0f5311|223344556677885f5f5f5f5f5f	32	intel	rcpps xmm2, xmmword ptr [ecx]
-0f5311|223344556677885f5f5f5f5f5f	32	plan9	RCPPS 0(CX), X2
-0f5311|223344556677885f5f5f5f5f5f	64	gnu	rcpps (%rcx),%xmm2
-0f5311|223344556677885f5f5f5f5f5f	64	intel	rcpps xmm2, xmmword ptr [rcx]
-0f5311|223344556677885f5f5f5f5f5f	64	plan9	RCPPS 0(CX), X2
-0f5411|223344556677885f5f5f5f5f5f	32	intel	andps xmm2, xmmword ptr [ecx]
-0f5411|223344556677885f5f5f5f5f5f	32	plan9	ANDPS 0(CX), X2
-0f5411|223344556677885f5f5f5f5f5f	64	gnu	andps (%rcx),%xmm2
-0f5411|223344556677885f5f5f5f5f5f	64	intel	andps xmm2, xmmword ptr [rcx]
-0f5411|223344556677885f5f5f5f5f5f	64	plan9	ANDPS 0(CX), X2
-0f5511|223344556677885f5f5f5f5f5f	32	intel	andnps xmm2, xmmword ptr [ecx]
-0f5511|223344556677885f5f5f5f5f5f	32	plan9	ANDNPS 0(CX), X2
-0f5511|223344556677885f5f5f5f5f5f	64	gnu	andnps (%rcx),%xmm2
-0f5511|223344556677885f5f5f5f5f5f	64	intel	andnps xmm2, xmmword ptr [rcx]
-0f5511|223344556677885f5f5f5f5f5f	64	plan9	ANDNPS 0(CX), X2
-0f5611|223344556677885f5f5f5f5f5f	32	intel	orps xmm2, xmmword ptr [ecx]
-0f5611|223344556677885f5f5f5f5f5f	32	plan9	ORPS 0(CX), X2
-0f5611|223344556677885f5f5f5f5f5f	64	gnu	orps (%rcx),%xmm2
-0f5611|223344556677885f5f5f5f5f5f	64	intel	orps xmm2, xmmword ptr [rcx]
-0f5611|223344556677885f5f5f5f5f5f	64	plan9	ORPS 0(CX), X2
-0f5711|223344556677885f5f5f5f5f5f	32	intel	xorps xmm2, xmmword ptr [ecx]
-0f5711|223344556677885f5f5f5f5f5f	32	plan9	XORPS 0(CX), X2
-0f5711|223344556677885f5f5f5f5f5f	64	gnu	xorps (%rcx),%xmm2
-0f5711|223344556677885f5f5f5f5f5f	64	intel	xorps xmm2, xmmword ptr [rcx]
-0f5711|223344556677885f5f5f5f5f5f	64	plan9	XORPS 0(CX), X2
-0f5811|223344556677885f5f5f5f5f5f	32	intel	addps xmm2, xmmword ptr [ecx]
-0f5811|223344556677885f5f5f5f5f5f	32	plan9	ADDPS 0(CX), X2
-0f5811|223344556677885f5f5f5f5f5f	64	gnu	addps (%rcx),%xmm2
-0f5811|223344556677885f5f5f5f5f5f	64	intel	addps xmm2, xmmword ptr [rcx]
-0f5811|223344556677885f5f5f5f5f5f	64	plan9	ADDPS 0(CX), X2
-0f5911|223344556677885f5f5f5f5f5f	32	intel	mulps xmm2, xmmword ptr [ecx]
-0f5911|223344556677885f5f5f5f5f5f	32	plan9	MULPS 0(CX), X2
-0f5911|223344556677885f5f5f5f5f5f	64	gnu	mulps (%rcx),%xmm2
-0f5911|223344556677885f5f5f5f5f5f	64	intel	mulps xmm2, xmmword ptr [rcx]
-0f5911|223344556677885f5f5f5f5f5f	64	plan9	MULPS 0(CX), X2
-0f5a11|223344556677885f5f5f5f5f5f	32	intel	cvtps2pd xmm2, qword ptr [ecx]
-0f5a11|223344556677885f5f5f5f5f5f	32	plan9	CVTPS2PD 0(CX), X2
-0f5a11|223344556677885f5f5f5f5f5f	64	gnu	cvtps2pd (%rcx),%xmm2
-0f5a11|223344556677885f5f5f5f5f5f	64	intel	cvtps2pd xmm2, qword ptr [rcx]
-0f5a11|223344556677885f5f5f5f5f5f	64	plan9	CVTPS2PD 0(CX), X2
-0f5b11|223344556677885f5f5f5f5f5f	32	intel	cvtdq2ps xmm2, xmmword ptr [ecx]
-0f5b11|223344556677885f5f5f5f5f5f	32	plan9	CVTDQ2PS 0(CX), X2
-0f5b11|223344556677885f5f5f5f5f5f	64	gnu	cvtdq2ps (%rcx),%xmm2
-0f5b11|223344556677885f5f5f5f5f5f	64	intel	cvtdq2ps xmm2, xmmword ptr [rcx]
-0f5b11|223344556677885f5f5f5f5f5f	64	plan9	CVTDQ2PS 0(CX), X2
-0f5c11|223344556677885f5f5f5f5f5f	32	intel	subps xmm2, xmmword ptr [ecx]
-0f5c11|223344556677885f5f5f5f5f5f	32	plan9	SUBPS 0(CX), X2
-0f5c11|223344556677885f5f5f5f5f5f	64	gnu	subps (%rcx),%xmm2
-0f5c11|223344556677885f5f5f5f5f5f	64	intel	subps xmm2, xmmword ptr [rcx]
-0f5c11|223344556677885f5f5f5f5f5f	64	plan9	SUBPS 0(CX), X2
-0f5d11|223344556677885f5f5f5f5f5f	32	intel	minps xmm2, xmmword ptr [ecx]
-0f5d11|223344556677885f5f5f5f5f5f	32	plan9	MINPS 0(CX), X2
-0f5d11|223344556677885f5f5f5f5f5f	64	gnu	minps (%rcx),%xmm2
-0f5d11|223344556677885f5f5f5f5f5f	64	intel	minps xmm2, xmmword ptr [rcx]
-0f5d11|223344556677885f5f5f5f5f5f	64	plan9	MINPS 0(CX), X2
-0f5e11|223344556677885f5f5f5f5f5f	32	intel	divps xmm2, xmmword ptr [ecx]
-0f5e11|223344556677885f5f5f5f5f5f	32	plan9	DIVPS 0(CX), X2
-0f5e11|223344556677885f5f5f5f5f5f	64	gnu	divps (%rcx),%xmm2
-0f5e11|223344556677885f5f5f5f5f5f	64	intel	divps xmm2, xmmword ptr [rcx]
-0f5e11|223344556677885f5f5f5f5f5f	64	plan9	DIVPS 0(CX), X2
-0f5f11|223344556677885f5f5f5f5f5f	32	intel	maxps xmm2, xmmword ptr [ecx]
-0f5f11|223344556677885f5f5f5f5f5f	32	plan9	MAXPS 0(CX), X2
-0f5f11|223344556677885f5f5f5f5f5f	64	gnu	maxps (%rcx),%xmm2
-0f5f11|223344556677885f5f5f5f5f5f	64	intel	maxps xmm2, xmmword ptr [rcx]
-0f5f11|223344556677885f5f5f5f5f5f	64	plan9	MAXPS 0(CX), X2
-0f6011|223344556677885f5f5f5f5f5f	32	intel	punpcklbw mmx2, dword ptr [ecx]
-0f6011|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKLBW 0(CX), M2
-0f6011|223344556677885f5f5f5f5f5f	64	gnu	punpcklbw (%rcx),%mm2
-0f6011|223344556677885f5f5f5f5f5f	64	intel	punpcklbw mmx2, dword ptr [rcx]
-0f6011|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKLBW 0(CX), M2
-0f6111|223344556677885f5f5f5f5f5f	32	intel	punpcklwd mmx2, dword ptr [ecx]
-0f6111|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKLWD 0(CX), M2
-0f6111|223344556677885f5f5f5f5f5f	64	gnu	punpcklwd (%rcx),%mm2
-0f6111|223344556677885f5f5f5f5f5f	64	intel	punpcklwd mmx2, dword ptr [rcx]
-0f6111|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKLWD 0(CX), M2
-0f6211|223344556677885f5f5f5f5f5f	32	intel	punpckldq mmx2, dword ptr [ecx]
-0f6211|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKLDQ 0(CX), M2
-0f6211|223344556677885f5f5f5f5f5f	64	gnu	punpckldq (%rcx),%mm2
-0f6211|223344556677885f5f5f5f5f5f	64	intel	punpckldq mmx2, dword ptr [rcx]
-0f6211|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKLDQ 0(CX), M2
-0f6311|223344556677885f5f5f5f5f5f	32	intel	packsswb mmx2, qword ptr [ecx]
-0f6311|223344556677885f5f5f5f5f5f	32	plan9	PACKSSWB 0(CX), M2
-0f6311|223344556677885f5f5f5f5f5f	64	gnu	packsswb (%rcx),%mm2
-0f6311|223344556677885f5f5f5f5f5f	64	intel	packsswb mmx2, qword ptr [rcx]
-0f6311|223344556677885f5f5f5f5f5f	64	plan9	PACKSSWB 0(CX), M2
-0f6411|223344556677885f5f5f5f5f5f	32	intel	pcmpgtb mmx2, qword ptr [ecx]
-0f6411|223344556677885f5f5f5f5f5f	32	plan9	PCMPGTB 0(CX), M2
-0f6411|223344556677885f5f5f5f5f5f	64	gnu	pcmpgtb (%rcx),%mm2
-0f6411|223344556677885f5f5f5f5f5f	64	intel	pcmpgtb mmx2, qword ptr [rcx]
-0f6411|223344556677885f5f5f5f5f5f	64	plan9	PCMPGTB 0(CX), M2
-0f6511|223344556677885f5f5f5f5f5f	32	intel	pcmpgtw mmx2, qword ptr [ecx]
-0f6511|223344556677885f5f5f5f5f5f	32	plan9	PCMPGTW 0(CX), M2
-0f6511|223344556677885f5f5f5f5f5f	64	gnu	pcmpgtw (%rcx),%mm2
-0f6511|223344556677885f5f5f5f5f5f	64	intel	pcmpgtw mmx2, qword ptr [rcx]
-0f6511|223344556677885f5f5f5f5f5f	64	plan9	PCMPGTW 0(CX), M2
-0f6611|223344556677885f5f5f5f5f5f	32	intel	pcmpgtd mmx2, qword ptr [ecx]
-0f6611|223344556677885f5f5f5f5f5f	32	plan9	PCMPGTD 0(CX), M2
-0f6611|223344556677885f5f5f5f5f5f	64	gnu	pcmpgtd (%rcx),%mm2
-0f6611|223344556677885f5f5f5f5f5f	64	intel	pcmpgtd mmx2, qword ptr [rcx]
-0f6611|223344556677885f5f5f5f5f5f	64	plan9	PCMPGTD 0(CX), M2
-0f6711|223344556677885f5f5f5f5f5f	32	intel	packuswb mmx2, qword ptr [ecx]
-0f6711|223344556677885f5f5f5f5f5f	32	plan9	PACKUSWB 0(CX), M2
-0f6711|223344556677885f5f5f5f5f5f	64	gnu	packuswb (%rcx),%mm2
-0f6711|223344556677885f5f5f5f5f5f	64	intel	packuswb mmx2, qword ptr [rcx]
-0f6711|223344556677885f5f5f5f5f5f	64	plan9	PACKUSWB 0(CX), M2
-0f6811|223344556677885f5f5f5f5f5f	32	intel	punpckhbw mmx2, qword ptr [ecx]
-0f6811|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKHBW 0(CX), M2
-0f6811|223344556677885f5f5f5f5f5f	64	gnu	punpckhbw (%rcx),%mm2
-0f6811|223344556677885f5f5f5f5f5f	64	intel	punpckhbw mmx2, qword ptr [rcx]
-0f6811|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKHBW 0(CX), M2
-0f6911|223344556677885f5f5f5f5f5f	32	intel	punpckhwd mmx2, qword ptr [ecx]
-0f6911|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKHWD 0(CX), M2
-0f6911|223344556677885f5f5f5f5f5f	64	gnu	punpckhwd (%rcx),%mm2
-0f6911|223344556677885f5f5f5f5f5f	64	intel	punpckhwd mmx2, qword ptr [rcx]
-0f6911|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKHWD 0(CX), M2
-0f6a11|223344556677885f5f5f5f5f5f	32	intel	punpckhdq mmx2, qword ptr [ecx]
-0f6a11|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKHDQ 0(CX), M2
-0f6a11|223344556677885f5f5f5f5f5f	64	gnu	punpckhdq (%rcx),%mm2
-0f6a11|223344556677885f5f5f5f5f5f	64	intel	punpckhdq mmx2, qword ptr [rcx]
-0f6a11|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKHDQ 0(CX), M2
-0f6b11|223344556677885f5f5f5f5f5f	32	intel	packssdw mmx2, qword ptr [ecx]
-0f6b11|223344556677885f5f5f5f5f5f	32	plan9	PACKSSDW 0(CX), M2
-0f6b11|223344556677885f5f5f5f5f5f	64	gnu	packssdw (%rcx),%mm2
-0f6b11|223344556677885f5f5f5f5f5f	64	intel	packssdw mmx2, qword ptr [rcx]
-0f6b11|223344556677885f5f5f5f5f5f	64	plan9	PACKSSDW 0(CX), M2
-0f6c|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f6c|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f6c|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f6c|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f6c|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f6d|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f6d|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f6d|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f6d|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f6d|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f6e11|223344556677885f5f5f5f5f5f	32	intel	movd mmx2, dword ptr [ecx]
-0f6e11|223344556677885f5f5f5f5f5f	32	plan9	MOVD 0(CX), M2
-0f6e11|223344556677885f5f5f5f5f5f	64	gnu	movd (%rcx),%mm2
-0f6e11|223344556677885f5f5f5f5f5f	64	intel	movd mmx2, dword ptr [rcx]
-0f6e11|223344556677885f5f5f5f5f5f	64	plan9	MOVD 0(CX), M2
-0f6f11|223344556677885f5f5f5f5f5f	32	intel	movq mmx2, qword ptr [ecx]
-0f6f11|223344556677885f5f5f5f5f5f	32	plan9	MOVQ 0(CX), M2
-0f6f11|223344556677885f5f5f5f5f5f	64	gnu	movq (%rcx),%mm2
-0f6f11|223344556677885f5f5f5f5f5f	64	intel	movq mmx2, qword ptr [rcx]
-0f6f11|223344556677885f5f5f5f5f5f	64	plan9	MOVQ 0(CX), M2
-0f701122|3344556677885f5f5f5f5f5f	32	intel	pshufw mmx2, qword ptr [ecx], 0x22
-0f701122|3344556677885f5f5f5f5f5f	32	plan9	PSHUFW $0x22, 0(CX), M2
-0f701122|3344556677885f5f5f5f5f5f	64	gnu	pshufw $0x22,(%rcx),%mm2
-0f701122|3344556677885f5f5f5f5f5f	64	intel	pshufw mmx2, qword ptr [rcx], 0x22
-0f701122|3344556677885f5f5f5f5f5f	64	plan9	PSHUFW $0x22, 0(CX), M2
-0f7100|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f7100|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f7100|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f7100|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f7100|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f711122|3344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f711122|3344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f711122|3344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f711122|3344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f711122|3344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f712011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f712011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f712011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f712011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f712011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f713011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f713011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f713011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f713011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f713011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f71d011|223344556677885f5f5f5f5f	32	intel	psrlw mmx0, 0x11
-0f71d011|223344556677885f5f5f5f5f	32	plan9	PSRLW $0x11, M0
-0f71d011|223344556677885f5f5f5f5f	64	gnu	psrlw $0x11,%mm0
-0f71d011|223344556677885f5f5f5f5f	64	intel	psrlw mmx0, 0x11
-0f71d011|223344556677885f5f5f5f5f	64	plan9	PSRLW $0x11, M0
-0f71e011|223344556677885f5f5f5f5f	32	intel	psraw mmx0, 0x11
-0f71e011|223344556677885f5f5f5f5f	32	plan9	PSRAW $0x11, M0
-0f71e011|223344556677885f5f5f5f5f	64	gnu	psraw $0x11,%mm0
-0f71e011|223344556677885f5f5f5f5f	64	intel	psraw mmx0, 0x11
-0f71e011|223344556677885f5f5f5f5f	64	plan9	PSRAW $0x11, M0
-0f71f011|223344556677885f5f5f5f5f	32	intel	psllw mmx0, 0x11
-0f71f011|223344556677885f5f5f5f5f	32	plan9	PSLLW $0x11, M0
-0f71f011|223344556677885f5f5f5f5f	64	gnu	psllw $0x11,%mm0
-0f71f011|223344556677885f5f5f5f5f	64	intel	psllw mmx0, 0x11
-0f71f011|223344556677885f5f5f5f5f	64	plan9	PSLLW $0x11, M0
-0f7200|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f7200|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f7200|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f7200|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f7200|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f721122|3344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f721122|3344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f721122|3344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f721122|3344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f721122|3344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f722011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f722011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f722011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f722011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f722011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f723011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f723011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f723011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f723011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f723011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f72d011|223344556677885f5f5f5f5f	32	intel	psrld mmx0, 0x11
-0f72d011|223344556677885f5f5f5f5f	32	plan9	PSRLD $0x11, M0
-0f72d011|223344556677885f5f5f5f5f	64	gnu	psrld $0x11,%mm0
-0f72d011|223344556677885f5f5f5f5f	64	intel	psrld mmx0, 0x11
-0f72d011|223344556677885f5f5f5f5f	64	plan9	PSRLD $0x11, M0
-0f72e011|223344556677885f5f5f5f5f	32	intel	psrad mmx0, 0x11
-0f72e011|223344556677885f5f5f5f5f	32	plan9	PSRAD $0x11, M0
-0f72e011|223344556677885f5f5f5f5f	64	gnu	psrad $0x11,%mm0
-0f72e011|223344556677885f5f5f5f5f	64	intel	psrad mmx0, 0x11
-0f72e011|223344556677885f5f5f5f5f	64	plan9	PSRAD $0x11, M0
-0f72f011|223344556677885f5f5f5f5f	32	intel	pslld mmx0, 0x11
-0f72f011|223344556677885f5f5f5f5f	32	plan9	PSLLD $0x11, M0
-0f72f011|223344556677885f5f5f5f5f	64	gnu	pslld $0x11,%mm0
-0f72f011|223344556677885f5f5f5f5f	64	intel	pslld mmx0, 0x11
-0f72f011|223344556677885f5f5f5f5f	64	plan9	PSLLD $0x11, M0
-0f7300|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f7300|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f7300|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f7300|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f7300|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f731122|3344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f731122|3344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f731122|3344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f731122|3344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f731122|3344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f7318|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f7318|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f7318|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f7318|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f7318|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f733011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f733011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f733011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f733011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f733011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f7338|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0f7338|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f7338|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f7338|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0f7338|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f73d011|223344556677885f5f5f5f5f	32	intel	psrlq mmx0, 0x11
-0f73d011|223344556677885f5f5f5f5f	32	plan9	PSRLQ $0x11, M0
-0f73d011|223344556677885f5f5f5f5f	64	gnu	psrlq $0x11,%mm0
-0f73d011|223344556677885f5f5f5f5f	64	intel	psrlq mmx0, 0x11
-0f73d011|223344556677885f5f5f5f5f	64	plan9	PSRLQ $0x11, M0
-0f73f011|223344556677885f5f5f5f5f	32	intel	psllq mmx0, 0x11
-0f73f011|223344556677885f5f5f5f5f	32	plan9	PSLLQ $0x11, M0
-0f73f011|223344556677885f5f5f5f5f	64	gnu	psllq $0x11,%mm0
-0f73f011|223344556677885f5f5f5f5f	64	intel	psllq mmx0, 0x11
-0f73f011|223344556677885f5f5f5f5f	64	plan9	PSLLQ $0x11, M0
-0f7411|223344556677885f5f5f5f5f5f	32	intel	pcmpeqb mmx2, qword ptr [ecx]
-0f7411|223344556677885f5f5f5f5f5f	32	plan9	PCMPEQB 0(CX), M2
-0f7411|223344556677885f5f5f5f5f5f	64	gnu	pcmpeqb (%rcx),%mm2
-0f7411|223344556677885f5f5f5f5f5f	64	intel	pcmpeqb mmx2, qword ptr [rcx]
-0f7411|223344556677885f5f5f5f5f5f	64	plan9	PCMPEQB 0(CX), M2
-0f7511|223344556677885f5f5f5f5f5f	32	intel	pcmpeqw mmx2, qword ptr [ecx]
-0f7511|223344556677885f5f5f5f5f5f	32	plan9	PCMPEQW 0(CX), M2
-0f7511|223344556677885f5f5f5f5f5f	64	gnu	pcmpeqw (%rcx),%mm2
-0f7511|223344556677885f5f5f5f5f5f	64	intel	pcmpeqw mmx2, qword ptr [rcx]
-0f7511|223344556677885f5f5f5f5f5f	64	plan9	PCMPEQW 0(CX), M2
-0f7611|223344556677885f5f5f5f5f5f	32	intel	pcmpeqd mmx2, qword ptr [ecx]
-0f7611|223344556677885f5f5f5f5f5f	32	plan9	PCMPEQD 0(CX), M2
-0f7611|223344556677885f5f5f5f5f5f	64	gnu	pcmpeqd (%rcx),%mm2
-0f7611|223344556677885f5f5f5f5f5f	64	intel	pcmpeqd mmx2, qword ptr [rcx]
-0f7611|223344556677885f5f5f5f5f5f	64	plan9	PCMPEQD 0(CX), M2
-0f77|11223344556677885f5f5f5f5f5f	32	intel	emms
-0f77|11223344556677885f5f5f5f5f5f	32	plan9	EMMS
-0f77|11223344556677885f5f5f5f5f5f	64	gnu	emms
-0f77|11223344556677885f5f5f5f5f5f	64	intel	emms
-0f77|11223344556677885f5f5f5f5f5f	64	plan9	EMMS
-0f7c|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f7c|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f7c|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f7c|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f7c|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f7d|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0f7d|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0f7d|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0f7d|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0f7d|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0f7e11|223344556677885f5f5f5f5f5f	32	intel	movd dword ptr [ecx], mmx2
-0f7e11|223344556677885f5f5f5f5f5f	32	plan9	MOVD M2, 0(CX)
-0f7e11|223344556677885f5f5f5f5f5f	64	gnu	movd %mm2,(%rcx)
-0f7e11|223344556677885f5f5f5f5f5f	64	intel	movd dword ptr [rcx], mmx2
-0f7e11|223344556677885f5f5f5f5f5f	64	plan9	MOVD M2, 0(CX)
-0f7f11|223344556677885f5f5f5f5f5f	32	intel	movq qword ptr [ecx], mmx2
-0f7f11|223344556677885f5f5f5f5f5f	32	plan9	MOVQ M2, 0(CX)
-0f7f11|223344556677885f5f5f5f5f5f	64	gnu	movq %mm2,(%rcx)
-0f7f11|223344556677885f5f5f5f5f5f	64	intel	movq qword ptr [rcx], mmx2
-0f7f11|223344556677885f5f5f5f5f5f	64	plan9	MOVQ M2, 0(CX)
-0f8011223344|556677885f5f5f5f5f5f	32	intel	jo .+0x44332211
-0f8011223344|556677885f5f5f5f5f5f	32	plan9	JO .+1144201745
-0f8011223344|556677885f5f5f5f5f5f	64	gnu	jo .+0x44332211
-0f8011223344|556677885f5f5f5f5f5f	64	intel	jo .+0x44332211
-0f8011223344|556677885f5f5f5f5f5f	64	plan9	JO .+1144201745
-0f8111223344|556677885f5f5f5f5f5f	32	intel	jno .+0x44332211
-0f8111223344|556677885f5f5f5f5f5f	32	plan9	JNO .+1144201745
-0f8111223344|556677885f5f5f5f5f5f	64	gnu	jno .+0x44332211
-0f8111223344|556677885f5f5f5f5f5f	64	intel	jno .+0x44332211
-0f8111223344|556677885f5f5f5f5f5f	64	plan9	JNO .+1144201745
-0f8211223344|556677885f5f5f5f5f5f	32	intel	jb .+0x44332211
-0f8211223344|556677885f5f5f5f5f5f	32	plan9	JB .+1144201745
-0f8211223344|556677885f5f5f5f5f5f	64	gnu	jb .+0x44332211
-0f8211223344|556677885f5f5f5f5f5f	64	intel	jb .+0x44332211
-0f8211223344|556677885f5f5f5f5f5f	64	plan9	JB .+1144201745
-0f8311223344|556677885f5f5f5f5f5f	32	intel	jnb .+0x44332211
-0f8311223344|556677885f5f5f5f5f5f	32	plan9	JAE .+1144201745
-0f8311223344|556677885f5f5f5f5f5f	64	gnu	jae .+0x44332211
-0f8311223344|556677885f5f5f5f5f5f	64	intel	jnb .+0x44332211
-0f8311223344|556677885f5f5f5f5f5f	64	plan9	JAE .+1144201745
-0f8411223344|556677885f5f5f5f5f5f	32	intel	jz .+0x44332211
-0f8411223344|556677885f5f5f5f5f5f	32	plan9	JE .+1144201745
-0f8411223344|556677885f5f5f5f5f5f	64	gnu	je .+0x44332211
-0f8411223344|556677885f5f5f5f5f5f	64	intel	jz .+0x44332211
-0f8411223344|556677885f5f5f5f5f5f	64	plan9	JE .+1144201745
-0f8511223344|556677885f5f5f5f5f5f	32	intel	jnz .+0x44332211
-0f8511223344|556677885f5f5f5f5f5f	32	plan9	JNE .+1144201745
-0f8511223344|556677885f5f5f5f5f5f	64	gnu	jne .+0x44332211
-0f8511223344|556677885f5f5f5f5f5f	64	intel	jnz .+0x44332211
-0f8511223344|556677885f5f5f5f5f5f	64	plan9	JNE .+1144201745
-0f8611223344|556677885f5f5f5f5f5f	32	intel	jbe .+0x44332211
-0f8611223344|556677885f5f5f5f5f5f	32	plan9	JBE .+1144201745
-0f8611223344|556677885f5f5f5f5f5f	64	gnu	jbe .+0x44332211
-0f8611223344|556677885f5f5f5f5f5f	64	intel	jbe .+0x44332211
-0f8611223344|556677885f5f5f5f5f5f	64	plan9	JBE .+1144201745
-0f8711223344|556677885f5f5f5f5f5f	32	intel	jnbe .+0x44332211
-0f8711223344|556677885f5f5f5f5f5f	32	plan9	JA .+1144201745
-0f8711223344|556677885f5f5f5f5f5f	64	gnu	ja .+0x44332211
-0f8711223344|556677885f5f5f5f5f5f	64	intel	jnbe .+0x44332211
-0f8711223344|556677885f5f5f5f5f5f	64	plan9	JA .+1144201745
-0f8811223344|556677885f5f5f5f5f5f	32	intel	js .+0x44332211
-0f8811223344|556677885f5f5f5f5f5f	32	plan9	JS .+1144201745
-0f8811223344|556677885f5f5f5f5f5f	64	gnu	js .+0x44332211
-0f8811223344|556677885f5f5f5f5f5f	64	intel	js .+0x44332211
-0f8811223344|556677885f5f5f5f5f5f	64	plan9	JS .+1144201745
-0f8911223344|556677885f5f5f5f5f5f	32	intel	jns .+0x44332211
-0f8911223344|556677885f5f5f5f5f5f	32	plan9	JNS .+1144201745
-0f8911223344|556677885f5f5f5f5f5f	64	gnu	jns .+0x44332211
-0f8911223344|556677885f5f5f5f5f5f	64	intel	jns .+0x44332211
-0f8911223344|556677885f5f5f5f5f5f	64	plan9	JNS .+1144201745
-0f8a11223344|556677885f5f5f5f5f5f	32	intel	jp .+0x44332211
-0f8a11223344|556677885f5f5f5f5f5f	32	plan9	JP .+1144201745
-0f8a11223344|556677885f5f5f5f5f5f	64	gnu	jp .+0x44332211
-0f8a11223344|556677885f5f5f5f5f5f	64	intel	jp .+0x44332211
-0f8a11223344|556677885f5f5f5f5f5f	64	plan9	JP .+1144201745
-0f8b11223344|556677885f5f5f5f5f5f	32	intel	jnp .+0x44332211
-0f8b11223344|556677885f5f5f5f5f5f	32	plan9	JNP .+1144201745
-0f8b11223344|556677885f5f5f5f5f5f	64	gnu	jnp .+0x44332211
-0f8b11223344|556677885f5f5f5f5f5f	64	intel	jnp .+0x44332211
-0f8b11223344|556677885f5f5f5f5f5f	64	plan9	JNP .+1144201745
-0f8c11223344|556677885f5f5f5f5f5f	32	intel	jl .+0x44332211
-0f8c11223344|556677885f5f5f5f5f5f	32	plan9	JL .+1144201745
-0f8c11223344|556677885f5f5f5f5f5f	64	gnu	jl .+0x44332211
-0f8c11223344|556677885f5f5f5f5f5f	64	intel	jl .+0x44332211
-0f8c11223344|556677885f5f5f5f5f5f	64	plan9	JL .+1144201745
-0f8d11223344|556677885f5f5f5f5f5f	32	intel	jnl .+0x44332211
-0f8d11223344|556677885f5f5f5f5f5f	32	plan9	JGE .+1144201745
-0f8d11223344|556677885f5f5f5f5f5f	64	gnu	jge .+0x44332211
-0f8d11223344|556677885f5f5f5f5f5f	64	intel	jnl .+0x44332211
-0f8d11223344|556677885f5f5f5f5f5f	64	plan9	JGE .+1144201745
-0f8e11223344|556677885f5f5f5f5f5f	32	intel	jle .+0x44332211
-0f8e11223344|556677885f5f5f5f5f5f	32	plan9	JLE .+1144201745
-0f8e11223344|556677885f5f5f5f5f5f	64	gnu	jle .+0x44332211
-0f8e11223344|556677885f5f5f5f5f5f	64	intel	jle .+0x44332211
-0f8e11223344|556677885f5f5f5f5f5f	64	plan9	JLE .+1144201745
-0f8f11223344|556677885f5f5f5f5f5f	32	intel	jnle .+0x44332211
-0f8f11223344|556677885f5f5f5f5f5f	32	plan9	JG .+1144201745
-0f8f11223344|556677885f5f5f5f5f5f	64	gnu	jg .+0x44332211
-0f8f11223344|556677885f5f5f5f5f5f	64	intel	jnle .+0x44332211
-0f8f11223344|556677885f5f5f5f5f5f	64	plan9	JG .+1144201745
-0f9011|223344556677885f5f5f5f5f5f	32	intel	seto byte ptr [ecx]
-0f9011|223344556677885f5f5f5f5f5f	32	plan9	SETO 0(CX)
-0f9011|223344556677885f5f5f5f5f5f	64	gnu	seto (%rcx)
-0f9011|223344556677885f5f5f5f5f5f	64	intel	seto byte ptr [rcx]
-0f9011|223344556677885f5f5f5f5f5f	64	plan9	SETO 0(CX)
-0f9111|223344556677885f5f5f5f5f5f	32	intel	setno byte ptr [ecx]
-0f9111|223344556677885f5f5f5f5f5f	32	plan9	SETNO 0(CX)
-0f9111|223344556677885f5f5f5f5f5f	64	gnu	setno (%rcx)
-0f9111|223344556677885f5f5f5f5f5f	64	intel	setno byte ptr [rcx]
-0f9111|223344556677885f5f5f5f5f5f	64	plan9	SETNO 0(CX)
-0f9211|223344556677885f5f5f5f5f5f	32	intel	setb byte ptr [ecx]
-0f9211|223344556677885f5f5f5f5f5f	32	plan9	SETB 0(CX)
-0f9211|223344556677885f5f5f5f5f5f	64	gnu	setb (%rcx)
-0f9211|223344556677885f5f5f5f5f5f	64	intel	setb byte ptr [rcx]
-0f9211|223344556677885f5f5f5f5f5f	64	plan9	SETB 0(CX)
-0f9311|223344556677885f5f5f5f5f5f	32	intel	setnb byte ptr [ecx]
-0f9311|223344556677885f5f5f5f5f5f	32	plan9	SETAE 0(CX)
-0f9311|223344556677885f5f5f5f5f5f	64	gnu	setae (%rcx)
-0f9311|223344556677885f5f5f5f5f5f	64	intel	setnb byte ptr [rcx]
-0f9311|223344556677885f5f5f5f5f5f	64	plan9	SETAE 0(CX)
-0f9411|223344556677885f5f5f5f5f5f	32	intel	setz byte ptr [ecx]
-0f9411|223344556677885f5f5f5f5f5f	32	plan9	SETE 0(CX)
-0f9411|223344556677885f5f5f5f5f5f	64	gnu	sete (%rcx)
-0f9411|223344556677885f5f5f5f5f5f	64	intel	setz byte ptr [rcx]
-0f9411|223344556677885f5f5f5f5f5f	64	plan9	SETE 0(CX)
-0f9511|223344556677885f5f5f5f5f5f	32	intel	setnz byte ptr [ecx]
-0f9511|223344556677885f5f5f5f5f5f	32	plan9	SETNE 0(CX)
-0f9511|223344556677885f5f5f5f5f5f	64	gnu	setne (%rcx)
-0f9511|223344556677885f5f5f5f5f5f	64	intel	setnz byte ptr [rcx]
-0f9511|223344556677885f5f5f5f5f5f	64	plan9	SETNE 0(CX)
-0f9611|223344556677885f5f5f5f5f5f	32	intel	setbe byte ptr [ecx]
-0f9611|223344556677885f5f5f5f5f5f	32	plan9	SETBE 0(CX)
-0f9611|223344556677885f5f5f5f5f5f	64	gnu	setbe (%rcx)
-0f9611|223344556677885f5f5f5f5f5f	64	intel	setbe byte ptr [rcx]
-0f9611|223344556677885f5f5f5f5f5f	64	plan9	SETBE 0(CX)
-0f9711|223344556677885f5f5f5f5f5f	32	intel	setnbe byte ptr [ecx]
-0f9711|223344556677885f5f5f5f5f5f	32	plan9	SETA 0(CX)
-0f9711|223344556677885f5f5f5f5f5f	64	gnu	seta (%rcx)
-0f9711|223344556677885f5f5f5f5f5f	64	intel	setnbe byte ptr [rcx]
-0f9711|223344556677885f5f5f5f5f5f	64	plan9	SETA 0(CX)
-0f9811|223344556677885f5f5f5f5f5f	32	intel	sets byte ptr [ecx]
-0f9811|223344556677885f5f5f5f5f5f	32	plan9	SETS 0(CX)
-0f9811|223344556677885f5f5f5f5f5f	64	gnu	sets (%rcx)
-0f9811|223344556677885f5f5f5f5f5f	64	intel	sets byte ptr [rcx]
-0f9811|223344556677885f5f5f5f5f5f	64	plan9	SETS 0(CX)
-0f9911|223344556677885f5f5f5f5f5f	32	intel	setns byte ptr [ecx]
-0f9911|223344556677885f5f5f5f5f5f	32	plan9	SETNS 0(CX)
-0f9911|223344556677885f5f5f5f5f5f	64	gnu	setns (%rcx)
-0f9911|223344556677885f5f5f5f5f5f	64	intel	setns byte ptr [rcx]
-0f9911|223344556677885f5f5f5f5f5f	64	plan9	SETNS 0(CX)
-0f9a11|223344556677885f5f5f5f5f5f	32	intel	setp byte ptr [ecx]
-0f9a11|223344556677885f5f5f5f5f5f	32	plan9	SETP 0(CX)
-0f9a11|223344556677885f5f5f5f5f5f	64	gnu	setp (%rcx)
-0f9a11|223344556677885f5f5f5f5f5f	64	intel	setp byte ptr [rcx]
-0f9a11|223344556677885f5f5f5f5f5f	64	plan9	SETP 0(CX)
-0f9b11|223344556677885f5f5f5f5f5f	32	intel	setnp byte ptr [ecx]
-0f9b11|223344556677885f5f5f5f5f5f	32	plan9	SETNP 0(CX)
-0f9b11|223344556677885f5f5f5f5f5f	64	gnu	setnp (%rcx)
-0f9b11|223344556677885f5f5f5f5f5f	64	intel	setnp byte ptr [rcx]
-0f9b11|223344556677885f5f5f5f5f5f	64	plan9	SETNP 0(CX)
-0f9c11|223344556677885f5f5f5f5f5f	32	intel	setl byte ptr [ecx]
-0f9c11|223344556677885f5f5f5f5f5f	32	plan9	SETL 0(CX)
-0f9c11|223344556677885f5f5f5f5f5f	64	gnu	setl (%rcx)
-0f9c11|223344556677885f5f5f5f5f5f	64	intel	setl byte ptr [rcx]
-0f9c11|223344556677885f5f5f5f5f5f	64	plan9	SETL 0(CX)
-0f9d11|223344556677885f5f5f5f5f5f	32	intel	setnl byte ptr [ecx]
-0f9d11|223344556677885f5f5f5f5f5f	32	plan9	SETGE 0(CX)
-0f9d11|223344556677885f5f5f5f5f5f	64	gnu	setge (%rcx)
-0f9d11|223344556677885f5f5f5f5f5f	64	intel	setnl byte ptr [rcx]
-0f9d11|223344556677885f5f5f5f5f5f	64	plan9	SETGE 0(CX)
-0f9e11|223344556677885f5f5f5f5f5f	32	intel	setle byte ptr [ecx]
-0f9e11|223344556677885f5f5f5f5f5f	32	plan9	SETLE 0(CX)
-0f9e11|223344556677885f5f5f5f5f5f	64	gnu	setle (%rcx)
-0f9e11|223344556677885f5f5f5f5f5f	64	intel	setle byte ptr [rcx]
-0f9e11|223344556677885f5f5f5f5f5f	64	plan9	SETLE 0(CX)
-0f9f11|223344556677885f5f5f5f5f5f	32	intel	setnle byte ptr [ecx]
-0f9f11|223344556677885f5f5f5f5f5f	32	plan9	SETG 0(CX)
-0f9f11|223344556677885f5f5f5f5f5f	64	gnu	setg (%rcx)
-0f9f11|223344556677885f5f5f5f5f5f	64	intel	setnle byte ptr [rcx]
-0f9f11|223344556677885f5f5f5f5f5f	64	plan9	SETG 0(CX)
-0fa0|11223344556677885f5f5f5f5f5f	32	intel	push fs
-0fa0|11223344556677885f5f5f5f5f5f	32	plan9	PUSHL FS
-0fa0|11223344556677885f5f5f5f5f5f	64	gnu	pushq %fs
-0fa0|11223344556677885f5f5f5f5f5f	64	intel	push fs
-0fa0|11223344556677885f5f5f5f5f5f	64	plan9	PUSHL FS
-0fa1|11223344556677885f5f5f5f5f5f	32	intel	pop fs
-0fa1|11223344556677885f5f5f5f5f5f	32	plan9	POPL FS
-0fa1|11223344556677885f5f5f5f5f5f	64	gnu	popq %fs
-0fa1|11223344556677885f5f5f5f5f5f	64	intel	pop fs
-0fa1|11223344556677885f5f5f5f5f5f	64	plan9	POPL FS
-0fa2|11223344556677885f5f5f5f5f5f	32	intel	cpuid
-0fa2|11223344556677885f5f5f5f5f5f	32	plan9	CPUID
-0fa2|11223344556677885f5f5f5f5f5f	64	gnu	cpuid
-0fa2|11223344556677885f5f5f5f5f5f	64	intel	cpuid
-0fa2|11223344556677885f5f5f5f5f5f	64	plan9	CPUID
-0fa311|223344556677885f5f5f5f5f5f	32	intel	bt dword ptr [ecx], edx
-0fa311|223344556677885f5f5f5f5f5f	32	plan9	BTL DX, 0(CX)
-0fa311|223344556677885f5f5f5f5f5f	64	gnu	bt %edx,(%rcx)
-0fa311|223344556677885f5f5f5f5f5f	64	intel	bt dword ptr [rcx], edx
-0fa311|223344556677885f5f5f5f5f5f	64	plan9	BTL DX, 0(CX)
-0fa41122|3344556677885f5f5f5f5f5f	32	intel	shld dword ptr [ecx], edx, 0x22
-0fa41122|3344556677885f5f5f5f5f5f	32	plan9	SHLDL $0x22, DX, 0(CX)
-0fa41122|3344556677885f5f5f5f5f5f	64	gnu	shld $0x22,%edx,(%rcx)
-0fa41122|3344556677885f5f5f5f5f5f	64	intel	shld dword ptr [rcx], edx, 0x22
-0fa41122|3344556677885f5f5f5f5f5f	64	plan9	SHLDL $0x22, DX, 0(CX)
-0fa511|223344556677885f5f5f5f5f5f	32	intel	shld dword ptr [ecx], edx, cl
-0fa511|223344556677885f5f5f5f5f5f	32	plan9	SHLDL CL, DX, 0(CX)
-0fa511|223344556677885f5f5f5f5f5f	64	gnu	shld %cl,%edx,(%rcx)
-0fa511|223344556677885f5f5f5f5f5f	64	intel	shld dword ptr [rcx], edx, cl
-0fa511|223344556677885f5f5f5f5f5f	64	plan9	SHLDL CL, DX, 0(CX)
-0fa8|11223344556677885f5f5f5f5f5f	32	intel	push gs
-0fa8|11223344556677885f5f5f5f5f5f	32	plan9	PUSHL GS
-0fa8|11223344556677885f5f5f5f5f5f	64	gnu	pushq %gs
-0fa8|11223344556677885f5f5f5f5f5f	64	intel	push gs
-0fa8|11223344556677885f5f5f5f5f5f	64	plan9	PUSHL GS
-0fa9|11223344556677885f5f5f5f5f5f	32	intel	pop gs
-0fa9|11223344556677885f5f5f5f5f5f	32	plan9	POPL GS
-0fa9|11223344556677885f5f5f5f5f5f	64	gnu	popq %gs
-0fa9|11223344556677885f5f5f5f5f5f	64	intel	pop gs
-0fa9|11223344556677885f5f5f5f5f5f	64	plan9	POPL GS
-0faa|11223344556677885f5f5f5f5f5f	32	intel	rsm
-0faa|11223344556677885f5f5f5f5f5f	32	plan9	RSM
-0faa|11223344556677885f5f5f5f5f5f	64	gnu	rsm
-0faa|11223344556677885f5f5f5f5f5f	64	intel	rsm
-0faa|11223344556677885f5f5f5f5f5f	64	plan9	RSM
-0fab11|223344556677885f5f5f5f5f5f	32	intel	bts dword ptr [ecx], edx
-0fab11|223344556677885f5f5f5f5f5f	32	plan9	BTSL DX, 0(CX)
-0fab11|223344556677885f5f5f5f5f5f	64	gnu	bts %edx,(%rcx)
-0fab11|223344556677885f5f5f5f5f5f	64	intel	bts dword ptr [rcx], edx
-0fab11|223344556677885f5f5f5f5f5f	64	plan9	BTSL DX, 0(CX)
-0fac1122|3344556677885f5f5f5f5f5f	32	intel	shrd dword ptr [ecx], edx, 0x22
-0fac1122|3344556677885f5f5f5f5f5f	32	plan9	SHRDL $0x22, DX, 0(CX)
-0fac1122|3344556677885f5f5f5f5f5f	64	gnu	shrd $0x22,%edx,(%rcx)
-0fac1122|3344556677885f5f5f5f5f5f	64	intel	shrd dword ptr [rcx], edx, 0x22
-0fac1122|3344556677885f5f5f5f5f5f	64	plan9	SHRDL $0x22, DX, 0(CX)
-0fad11|223344556677885f5f5f5f5f5f	32	intel	shrd dword ptr [ecx], edx, cl
-0fad11|223344556677885f5f5f5f5f5f	32	plan9	SHRDL CL, DX, 0(CX)
-0fad11|223344556677885f5f5f5f5f5f	64	gnu	shrd %cl,%edx,(%rcx)
-0fad11|223344556677885f5f5f5f5f5f	64	intel	shrd dword ptr [rcx], edx, cl
-0fad11|223344556677885f5f5f5f5f5f	64	plan9	SHRDL CL, DX, 0(CX)
-0fae00|11223344556677885f5f5f5f5f	32	intel	fxsave ptr [eax]
-0fae00|11223344556677885f5f5f5f5f	32	plan9	FXSAVE 0(AX)
-0fae00|11223344556677885f5f5f5f5f	64	gnu	fxsave (%rax)
-0fae00|11223344556677885f5f5f5f5f	64	intel	fxsave ptr [rax]
-0fae00|11223344556677885f5f5f5f5f	64	plan9	FXSAVE 0(AX)
-0fae08|11223344556677885f5f5f5f5f	32	intel	fxrstor ptr [eax]
-0fae08|11223344556677885f5f5f5f5f	32	plan9	FXRSTOR 0(AX)
-0fae08|11223344556677885f5f5f5f5f	64	gnu	fxrstor (%rax)
-0fae08|11223344556677885f5f5f5f5f	64	intel	fxrstor ptr [rax]
-0fae08|11223344556677885f5f5f5f5f	64	plan9	FXRSTOR 0(AX)
-0fae11|223344556677885f5f5f5f5f5f	32	intel	ldmxcsr dword ptr [ecx]
-0fae11|223344556677885f5f5f5f5f5f	32	plan9	LDMXCSR 0(CX)
-0fae11|223344556677885f5f5f5f5f5f	64	gnu	ldmxcsr (%rcx)
-0fae11|223344556677885f5f5f5f5f5f	64	intel	ldmxcsr dword ptr [rcx]
-0fae11|223344556677885f5f5f5f5f5f	64	plan9	LDMXCSR 0(CX)
-0fae18|11223344556677885f5f5f5f5f	32	intel	stmxcsr dword ptr [eax]
-0fae18|11223344556677885f5f5f5f5f	32	plan9	STMXCSR 0(AX)
-0fae18|11223344556677885f5f5f5f5f	64	gnu	stmxcsr (%rax)
-0fae18|11223344556677885f5f5f5f5f	64	intel	stmxcsr dword ptr [rax]
-0fae18|11223344556677885f5f5f5f5f	64	plan9	STMXCSR 0(AX)
-0fae20|11223344556677885f5f5f5f5f	32	intel	xsave ptr [eax]
-0fae20|11223344556677885f5f5f5f5f	32	plan9	XSAVE 0(AX)
-0fae20|11223344556677885f5f5f5f5f	64	gnu	xsave (%rax)
-0fae20|11223344556677885f5f5f5f5f	64	intel	xsave ptr [rax]
-0fae20|11223344556677885f5f5f5f5f	64	plan9	XSAVE 0(AX)
-0fae28|11223344556677885f5f5f5f5f	32	intel	xrstor ptr [eax]
-0fae28|11223344556677885f5f5f5f5f	32	plan9	XRSTOR 0(AX)
-0fae28|11223344556677885f5f5f5f5f	64	gnu	xrstor (%rax)
-0fae28|11223344556677885f5f5f5f5f	64	intel	xrstor ptr [rax]
-0fae28|11223344556677885f5f5f5f5f	64	plan9	XRSTOR 0(AX)
-0fae30|11223344556677885f5f5f5f5f	32	intel	xsaveopt ptr [eax]
-0fae30|11223344556677885f5f5f5f5f	32	plan9	XSAVEOPT 0(AX)
-0fae30|11223344556677885f5f5f5f5f	64	gnu	xsaveopt (%rax)
-0fae30|11223344556677885f5f5f5f5f	64	intel	xsaveopt ptr [rax]
-0fae30|11223344556677885f5f5f5f5f	64	plan9	XSAVEOPT 0(AX)
-0fae38|11223344556677885f5f5f5f5f	32	intel	clflush zmmword ptr [eax]
-0fae38|11223344556677885f5f5f5f5f	32	plan9	CLFLUSH 0(AX)
-0fae38|11223344556677885f5f5f5f5f	64	gnu	clflush (%rax)
-0fae38|11223344556677885f5f5f5f5f	64	intel	clflush zmmword ptr [rax]
-0fae38|11223344556677885f5f5f5f5f	64	plan9	CLFLUSH 0(AX)
-0faee8|11223344556677885f5f5f5f5f	32	intel	lfence
-0faee8|11223344556677885f5f5f5f5f	32	plan9	LFENCE
-0faee8|11223344556677885f5f5f5f5f	64	gnu	lfence
-0faee8|11223344556677885f5f5f5f5f	64	intel	lfence
-0faee8|11223344556677885f5f5f5f5f	64	plan9	LFENCE
-0faef0|11223344556677885f5f5f5f5f	32	intel	mfence
-0faef0|11223344556677885f5f5f5f5f	32	plan9	MFENCE
-0faef0|11223344556677885f5f5f5f5f	64	gnu	mfence
-0faef0|11223344556677885f5f5f5f5f	64	intel	mfence
-0faef0|11223344556677885f5f5f5f5f	64	plan9	MFENCE
-0faef8|11223344556677885f5f5f5f5f	32	intel	sfence
-0faef8|11223344556677885f5f5f5f5f	32	plan9	SFENCE
-0faef8|11223344556677885f5f5f5f5f	64	gnu	sfence
-0faef8|11223344556677885f5f5f5f5f	64	intel	sfence
-0faef8|11223344556677885f5f5f5f5f	64	plan9	SFENCE
-0faf11|223344556677885f5f5f5f5f5f	32	intel	imul edx, dword ptr [ecx]
-0faf11|223344556677885f5f5f5f5f5f	32	plan9	IMULL 0(CX), DX
-0faf11|223344556677885f5f5f5f5f5f	64	gnu	imul (%rcx),%edx
-0faf11|223344556677885f5f5f5f5f5f	64	intel	imul edx, dword ptr [rcx]
-0faf11|223344556677885f5f5f5f5f5f	64	plan9	IMULL 0(CX), DX
-0fb011|223344556677885f5f5f5f5f5f	32	intel	cmpxchg byte ptr [ecx], dl
-0fb011|223344556677885f5f5f5f5f5f	32	plan9	CMPXCHGL DL, 0(CX)
-0fb011|223344556677885f5f5f5f5f5f	64	gnu	cmpxchg %dl,(%rcx)
-0fb011|223344556677885f5f5f5f5f5f	64	intel	cmpxchg byte ptr [rcx], dl
-0fb011|223344556677885f5f5f5f5f5f	64	plan9	CMPXCHGL DL, 0(CX)
-0fb111|223344556677885f5f5f5f5f5f	32	intel	cmpxchg dword ptr [ecx], edx
-0fb111|223344556677885f5f5f5f5f5f	32	plan9	CMPXCHGL DX, 0(CX)
-0fb111|223344556677885f5f5f5f5f5f	64	gnu	cmpxchg %edx,(%rcx)
-0fb111|223344556677885f5f5f5f5f5f	64	intel	cmpxchg dword ptr [rcx], edx
-0fb111|223344556677885f5f5f5f5f5f	64	plan9	CMPXCHGL DX, 0(CX)
-0fb211|223344556677885f5f5f5f5f5f	32	intel	lss edx, ptr [ecx]
-0fb211|223344556677885f5f5f5f5f5f	32	plan9	LSS 0(CX), DX
-0fb211|223344556677885f5f5f5f5f5f	64	gnu	lss (%rcx),%edx
-0fb211|223344556677885f5f5f5f5f5f	64	intel	lss edx, ptr [rcx]
-0fb211|223344556677885f5f5f5f5f5f	64	plan9	LSS 0(CX), DX
-0fb311|223344556677885f5f5f5f5f5f	32	intel	btr dword ptr [ecx], edx
-0fb311|223344556677885f5f5f5f5f5f	32	plan9	BTRL DX, 0(CX)
-0fb311|223344556677885f5f5f5f5f5f	64	gnu	btr %edx,(%rcx)
-0fb311|223344556677885f5f5f5f5f5f	64	intel	btr dword ptr [rcx], edx
-0fb311|223344556677885f5f5f5f5f5f	64	plan9	BTRL DX, 0(CX)
-0fb411|223344556677885f5f5f5f5f5f	32	intel	lfs edx, ptr [ecx]
-0fb411|223344556677885f5f5f5f5f5f	32	plan9	LFS 0(CX), DX
-0fb411|223344556677885f5f5f5f5f5f	64	gnu	lfs (%rcx),%edx
-0fb411|223344556677885f5f5f5f5f5f	64	intel	lfs edx, ptr [rcx]
-0fb411|223344556677885f5f5f5f5f5f	64	plan9	LFS 0(CX), DX
-0fb511|223344556677885f5f5f5f5f5f	32	intel	lgs edx, ptr [ecx]
-0fb511|223344556677885f5f5f5f5f5f	32	plan9	LGS 0(CX), DX
-0fb511|223344556677885f5f5f5f5f5f	64	gnu	lgs (%rcx),%edx
-0fb511|223344556677885f5f5f5f5f5f	64	intel	lgs edx, ptr [rcx]
-0fb511|223344556677885f5f5f5f5f5f	64	plan9	LGS 0(CX), DX
-0fb611|223344556677885f5f5f5f5f5f	32	intel	movzx edx, byte ptr [ecx]
-0fb611|223344556677885f5f5f5f5f5f	32	plan9	MOVZX 0(CX), DX
-0fb611|223344556677885f5f5f5f5f5f	64	gnu	movzbl (%rcx),%edx
-0fb611|223344556677885f5f5f5f5f5f	64	intel	movzx edx, byte ptr [rcx]
-0fb611|223344556677885f5f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
-0fb711|223344556677885f5f5f5f5f5f	32	intel	movzx edx, word ptr [ecx]
-0fb711|223344556677885f5f5f5f5f5f	32	plan9	MOVZX 0(CX), DX
-0fb711|223344556677885f5f5f5f5f5f	64	gnu	movzwl (%rcx),%edx
-0fb711|223344556677885f5f5f5f5f5f	64	intel	movzx edx, word ptr [rcx]
-0fb711|223344556677885f5f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
-0fb8|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0fb8|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0fb8|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0fb8|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0fb8|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0fb9|11223344556677885f5f5f5f5f5f	32	intel	ud1
-0fb9|11223344556677885f5f5f5f5f5f	32	plan9	UD1
-0fb9|11223344556677885f5f5f5f5f5f	64	gnu	ud1
-0fb9|11223344556677885f5f5f5f5f5f	64	intel	ud1
-0fb9|11223344556677885f5f5f5f5f5f	64	plan9	UD1
-0fba11|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0fba11|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0fba11|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0fba11|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0fba11|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0fba2011|223344556677885f5f5f5f5f	32	intel	bt dword ptr [eax], 0x11
-0fba2011|223344556677885f5f5f5f5f	32	plan9	BTL $0x11, 0(AX)
-0fba2011|223344556677885f5f5f5f5f	64	gnu	btl $0x11,(%rax)
-0fba2011|223344556677885f5f5f5f5f	64	intel	bt dword ptr [rax], 0x11
-0fba2011|223344556677885f5f5f5f5f	64	plan9	BTL $0x11, 0(AX)
-0fba2811|223344556677885f5f5f5f5f	32	intel	bts dword ptr [eax], 0x11
-0fba2811|223344556677885f5f5f5f5f	32	plan9	BTSL $0x11, 0(AX)
-0fba2811|223344556677885f5f5f5f5f	64	gnu	btsl $0x11,(%rax)
-0fba2811|223344556677885f5f5f5f5f	64	intel	bts dword ptr [rax], 0x11
-0fba2811|223344556677885f5f5f5f5f	64	plan9	BTSL $0x11, 0(AX)
-0fba3011|223344556677885f5f5f5f5f	32	intel	btr dword ptr [eax], 0x11
-0fba3011|223344556677885f5f5f5f5f	32	plan9	BTRL $0x11, 0(AX)
-0fba3011|223344556677885f5f5f5f5f	64	gnu	btrl $0x11,(%rax)
-0fba3011|223344556677885f5f5f5f5f	64	intel	btr dword ptr [rax], 0x11
-0fba3011|223344556677885f5f5f5f5f	64	plan9	BTRL $0x11, 0(AX)
-0fba3811|223344556677885f5f5f5f5f	32	intel	btc dword ptr [eax], 0x11
-0fba3811|223344556677885f5f5f5f5f	32	plan9	BTCL $0x11, 0(AX)
-0fba3811|223344556677885f5f5f5f5f	64	gnu	btcl $0x11,(%rax)
-0fba3811|223344556677885f5f5f5f5f	64	intel	btc dword ptr [rax], 0x11
-0fba3811|223344556677885f5f5f5f5f	64	plan9	BTCL $0x11, 0(AX)
-0fbb11|223344556677885f5f5f5f5f5f	32	intel	btc dword ptr [ecx], edx
-0fbb11|223344556677885f5f5f5f5f5f	32	plan9	BTCL DX, 0(CX)
-0fbb11|223344556677885f5f5f5f5f5f	64	gnu	btc %edx,(%rcx)
-0fbb11|223344556677885f5f5f5f5f5f	64	intel	btc dword ptr [rcx], edx
-0fbb11|223344556677885f5f5f5f5f5f	64	plan9	BTCL DX, 0(CX)
-0fbc11|223344556677885f5f5f5f5f5f	32	intel	bsf edx, dword ptr [ecx]
-0fbc11|223344556677885f5f5f5f5f5f	32	plan9	BSFL 0(CX), DX
-0fbc11|223344556677885f5f5f5f5f5f	64	gnu	bsf (%rcx),%edx
-0fbc11|223344556677885f5f5f5f5f5f	64	intel	bsf edx, dword ptr [rcx]
-0fbc11|223344556677885f5f5f5f5f5f	64	plan9	BSFL 0(CX), DX
-0fbd11|223344556677885f5f5f5f5f5f	32	intel	bsr edx, dword ptr [ecx]
-0fbd11|223344556677885f5f5f5f5f5f	32	plan9	BSRL 0(CX), DX
-0fbd11|223344556677885f5f5f5f5f5f	64	gnu	bsr (%rcx),%edx
-0fbd11|223344556677885f5f5f5f5f5f	64	intel	bsr edx, dword ptr [rcx]
-0fbd11|223344556677885f5f5f5f5f5f	64	plan9	BSRL 0(CX), DX
-0fbe11|223344556677885f5f5f5f5f5f	32	intel	movsx edx, byte ptr [ecx]
-0fbe11|223344556677885f5f5f5f5f5f	32	plan9	MOVSX 0(CX), DX
-0fbe11|223344556677885f5f5f5f5f5f	64	gnu	movsbl (%rcx),%edx
-0fbe11|223344556677885f5f5f5f5f5f	64	intel	movsx edx, byte ptr [rcx]
-0fbe11|223344556677885f5f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
-0fbf11|223344556677885f5f5f5f5f5f	32	intel	movsx edx, word ptr [ecx]
-0fbf11|223344556677885f5f5f5f5f5f	32	plan9	MOVSX 0(CX), DX
-0fbf11|223344556677885f5f5f5f5f5f	64	gnu	movswl (%rcx),%edx
-0fbf11|223344556677885f5f5f5f5f5f	64	intel	movsx edx, word ptr [rcx]
-0fbf11|223344556677885f5f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
-0fc011|223344556677885f5f5f5f5f5f	32	intel	xadd byte ptr [ecx], dl
-0fc011|223344556677885f5f5f5f5f5f	32	plan9	XADDL DL, 0(CX)
-0fc011|223344556677885f5f5f5f5f5f	64	gnu	xadd %dl,(%rcx)
-0fc011|223344556677885f5f5f5f5f5f	64	intel	xadd byte ptr [rcx], dl
-0fc011|223344556677885f5f5f5f5f5f	64	plan9	XADDL DL, 0(CX)
-0fc111|223344556677885f5f5f5f5f5f	32	intel	xadd dword ptr [ecx], edx
-0fc111|223344556677885f5f5f5f5f5f	32	plan9	XADDL DX, 0(CX)
-0fc111|223344556677885f5f5f5f5f5f	64	gnu	xadd %edx,(%rcx)
-0fc111|223344556677885f5f5f5f5f5f	64	intel	xadd dword ptr [rcx], edx
-0fc111|223344556677885f5f5f5f5f5f	64	plan9	XADDL DX, 0(CX)
-0fc20000|11223344556677885f5f5f5f	32	intel	cmpps xmm0, xmmword ptr [eax], 0x0
-0fc20000|11223344556677885f5f5f5f	32	plan9	CMPPS $0x0, 0(AX), X0
-0fc20000|11223344556677885f5f5f5f	64	gnu	cmpeqps (%rax),%xmm0
-0fc20000|11223344556677885f5f5f5f	64	intel	cmpps xmm0, xmmword ptr [rax], 0x0
-0fc20000|11223344556677885f5f5f5f	64	plan9	CMPPS $0x0, 0(AX), X0
-0fc311|223344556677885f5f5f5f5f5f	32	intel	movnti dword ptr [ecx], edx
-0fc311|223344556677885f5f5f5f5f5f	32	plan9	MOVNTIL DX, 0(CX)
-0fc311|223344556677885f5f5f5f5f5f	64	gnu	movnti %edx,(%rcx)
-0fc311|223344556677885f5f5f5f5f5f	64	intel	movnti dword ptr [rcx], edx
-0fc311|223344556677885f5f5f5f5f5f	64	plan9	MOVNTIL DX, 0(CX)
-0fc41122|3344556677885f5f5f5f5f5f	32	intel	pinsrw mmx2, word ptr [ecx], 0x22
-0fc41122|3344556677885f5f5f5f5f5f	32	plan9	PINSRW $0x22, 0(CX), M2
-0fc41122|3344556677885f5f5f5f5f5f	64	gnu	pinsrw $0x22,(%rcx),%mm2
-0fc41122|3344556677885f5f5f5f5f5f	64	intel	pinsrw mmx2, word ptr [rcx], 0x22
-0fc41122|3344556677885f5f5f5f5f5f	64	plan9	PINSRW $0x22, 0(CX), M2
-0fc51122|3344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0fc51122|3344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0fc51122|3344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0fc51122|3344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0fc51122|3344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0fc5c011|223344556677885f5f5f5f5f	32	intel	pextrw eax, mmx0, 0x11
-0fc5c011|223344556677885f5f5f5f5f	32	plan9	PEXTRW $0x11, M0, AX
-0fc5c011|223344556677885f5f5f5f5f	64	gnu	pextrw $0x11,%mm0,%eax
-0fc5c011|223344556677885f5f5f5f5f	64	intel	pextrw eax, mmx0, 0x11
-0fc5c011|223344556677885f5f5f5f5f	64	plan9	PEXTRW $0x11, M0, AX
-0fc61122|3344556677885f5f5f5f5f5f	32	intel	shufps xmm2, xmmword ptr [ecx], 0x22
-0fc61122|3344556677885f5f5f5f5f5f	32	plan9	SHUFPS $0x22, 0(CX), X2
-0fc61122|3344556677885f5f5f5f5f5f	64	gnu	shufps $0x22,(%rcx),%xmm2
-0fc61122|3344556677885f5f5f5f5f5f	64	intel	shufps xmm2, xmmword ptr [rcx], 0x22
-0fc61122|3344556677885f5f5f5f5f5f	64	plan9	SHUFPS $0x22, 0(CX), X2
-0fc708|11223344556677885f5f5f5f5f	32	intel	cmpxchg8b qword ptr [eax]
-0fc708|11223344556677885f5f5f5f5f	32	plan9	CMPXCHG8B 0(AX)
-0fc708|11223344556677885f5f5f5f5f	64	gnu	cmpxchg8b (%rax)
-0fc708|11223344556677885f5f5f5f5f	64	intel	cmpxchg8b qword ptr [rax]
-0fc708|11223344556677885f5f5f5f5f	64	plan9	CMPXCHG8B 0(AX)
-0fc718|11223344556677885f5f5f5f5f	32	intel	xrstors ptr [eax]
-0fc718|11223344556677885f5f5f5f5f	32	plan9	XRSTORS 0(AX)
-0fc718|11223344556677885f5f5f5f5f	64	gnu	xrstors (%rax)
-0fc718|11223344556677885f5f5f5f5f	64	intel	xrstors ptr [rax]
-0fc718|11223344556677885f5f5f5f5f	64	plan9	XRSTORS 0(AX)
-0fc720|11223344556677885f5f5f5f5f	32	intel	xsavec ptr [eax]
-0fc720|11223344556677885f5f5f5f5f	32	plan9	XSAVEC 0(AX)
-0fc720|11223344556677885f5f5f5f5f	64	gnu	xsavec (%rax)
-0fc720|11223344556677885f5f5f5f5f	64	intel	xsavec ptr [rax]
-0fc720|11223344556677885f5f5f5f5f	64	plan9	XSAVEC 0(AX)
-0fc728|11223344556677885f5f5f5f5f	32	intel	xsaves ptr [eax]
-0fc728|11223344556677885f5f5f5f5f	32	plan9	XSAVES 0(AX)
-0fc728|11223344556677885f5f5f5f5f	64	gnu	xsaves (%rax)
-0fc728|11223344556677885f5f5f5f5f	64	intel	xsaves ptr [rax]
-0fc728|11223344556677885f5f5f5f5f	64	plan9	XSAVES 0(AX)
-0fc730|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
-0fc730|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
-0fc730|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
-0fc730|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
-0fc730|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
-0fc7f0|11223344556677885f5f5f5f5f	32	intel	rdrand eax
-0fc7f0|11223344556677885f5f5f5f5f	32	plan9	RDRAND AX
-0fc7f0|11223344556677885f5f5f5f5f	64	gnu	rdrand %eax
-0fc7f0|11223344556677885f5f5f5f5f	64	intel	rdrand eax
-0fc7f0|11223344556677885f5f5f5f5f	64	plan9	RDRAND AX
-0fc8|11223344556677885f5f5f5f5f5f	32	intel	bswap eax
-0fc8|11223344556677885f5f5f5f5f5f	32	plan9	BSWAP AX
-0fc8|11223344556677885f5f5f5f5f5f	64	gnu	bswap %eax
-0fc8|11223344556677885f5f5f5f5f5f	64	intel	bswap eax
-0fc8|11223344556677885f5f5f5f5f5f	64	plan9	BSWAP AX
-0fd0|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0fd0|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0fd0|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0fd0|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0fd0|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0fd111|223344556677885f5f5f5f5f5f	32	intel	psrlw mmx2, qword ptr [ecx]
-0fd111|223344556677885f5f5f5f5f5f	32	plan9	PSRLW 0(CX), M2
-0fd111|223344556677885f5f5f5f5f5f	64	gnu	psrlw (%rcx),%mm2
-0fd111|223344556677885f5f5f5f5f5f	64	intel	psrlw mmx2, qword ptr [rcx]
-0fd111|223344556677885f5f5f5f5f5f	64	plan9	PSRLW 0(CX), M2
-0fd211|223344556677885f5f5f5f5f5f	32	intel	psrld mmx2, qword ptr [ecx]
-0fd211|223344556677885f5f5f5f5f5f	32	plan9	PSRLD 0(CX), M2
-0fd211|223344556677885f5f5f5f5f5f	64	gnu	psrld (%rcx),%mm2
-0fd211|223344556677885f5f5f5f5f5f	64	intel	psrld mmx2, qword ptr [rcx]
-0fd211|223344556677885f5f5f5f5f5f	64	plan9	PSRLD 0(CX), M2
-0fd311|223344556677885f5f5f5f5f5f	32	intel	psrlq mmx2, qword ptr [ecx]
-0fd311|223344556677885f5f5f5f5f5f	32	plan9	PSRLQ 0(CX), M2
-0fd311|223344556677885f5f5f5f5f5f	64	gnu	psrlq (%rcx),%mm2
-0fd311|223344556677885f5f5f5f5f5f	64	intel	psrlq mmx2, qword ptr [rcx]
-0fd311|223344556677885f5f5f5f5f5f	64	plan9	PSRLQ 0(CX), M2
-0fd411|223344556677885f5f5f5f5f5f	32	intel	paddq mmx2, qword ptr [ecx]
-0fd411|223344556677885f5f5f5f5f5f	32	plan9	PADDQ 0(CX), M2
-0fd411|223344556677885f5f5f5f5f5f	64	gnu	paddq (%rcx),%mm2
-0fd411|223344556677885f5f5f5f5f5f	64	intel	paddq mmx2, qword ptr [rcx]
-0fd411|223344556677885f5f5f5f5f5f	64	plan9	PADDQ 0(CX), M2
-0fd511|223344556677885f5f5f5f5f5f	32	intel	pmullw mmx2, qword ptr [ecx]
-0fd511|223344556677885f5f5f5f5f5f	32	plan9	PMULLW 0(CX), M2
-0fd511|223344556677885f5f5f5f5f5f	64	gnu	pmullw (%rcx),%mm2
-0fd511|223344556677885f5f5f5f5f5f	64	intel	pmullw mmx2, qword ptr [rcx]
-0fd511|223344556677885f5f5f5f5f5f	64	plan9	PMULLW 0(CX), M2
-0fd6|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0fd6|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0fd6|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0fd6|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0fd6|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0fd711|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0fd711|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0fd711|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0fd711|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0fd711|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0fd7c0|11223344556677885f5f5f5f5f	32	intel	pmovmskb eax, mmx0
-0fd7c0|11223344556677885f5f5f5f5f	32	plan9	PMOVMSKB M0, AX
-0fd7c0|11223344556677885f5f5f5f5f	64	gnu	pmovmskb %mm0,%eax
-0fd7c0|11223344556677885f5f5f5f5f	64	intel	pmovmskb eax, mmx0
-0fd7c0|11223344556677885f5f5f5f5f	64	plan9	PMOVMSKB M0, AX
-0fd811|223344556677885f5f5f5f5f5f	32	intel	psubusb mmx2, qword ptr [ecx]
-0fd811|223344556677885f5f5f5f5f5f	32	plan9	PSUBUSB 0(CX), M2
-0fd811|223344556677885f5f5f5f5f5f	64	gnu	psubusb (%rcx),%mm2
-0fd811|223344556677885f5f5f5f5f5f	64	intel	psubusb mmx2, qword ptr [rcx]
-0fd811|223344556677885f5f5f5f5f5f	64	plan9	PSUBUSB 0(CX), M2
-0fd911|223344556677885f5f5f5f5f5f	32	intel	psubusw mmx2, qword ptr [ecx]
-0fd911|223344556677885f5f5f5f5f5f	32	plan9	PSUBUSW 0(CX), M2
-0fd911|223344556677885f5f5f5f5f5f	64	gnu	psubusw (%rcx),%mm2
-0fd911|223344556677885f5f5f5f5f5f	64	intel	psubusw mmx2, qword ptr [rcx]
-0fd911|223344556677885f5f5f5f5f5f	64	plan9	PSUBUSW 0(CX), M2
-0fda11|223344556677885f5f5f5f5f5f	32	intel	pminub mmx2, qword ptr [ecx]
-0fda11|223344556677885f5f5f5f5f5f	32	plan9	PMINUB 0(CX), M2
-0fda11|223344556677885f5f5f5f5f5f	64	gnu	pminub (%rcx),%mm2
-0fda11|223344556677885f5f5f5f5f5f	64	intel	pminub mmx2, qword ptr [rcx]
-0fda11|223344556677885f5f5f5f5f5f	64	plan9	PMINUB 0(CX), M2
-0fdb11|223344556677885f5f5f5f5f5f	32	intel	pand mmx2, qword ptr [ecx]
-0fdb11|223344556677885f5f5f5f5f5f	32	plan9	PAND 0(CX), M2
-0fdb11|223344556677885f5f5f5f5f5f	64	gnu	pand (%rcx),%mm2
-0fdb11|223344556677885f5f5f5f5f5f	64	intel	pand mmx2, qword ptr [rcx]
-0fdb11|223344556677885f5f5f5f5f5f	64	plan9	PAND 0(CX), M2
-0fdc11|223344556677885f5f5f5f5f5f	32	intel	paddusb mmx2, qword ptr [ecx]
-0fdc11|223344556677885f5f5f5f5f5f	32	plan9	PADDUSB 0(CX), M2
-0fdc11|223344556677885f5f5f5f5f5f	64	gnu	paddusb (%rcx),%mm2
-0fdc11|223344556677885f5f5f5f5f5f	64	intel	paddusb mmx2, qword ptr [rcx]
-0fdc11|223344556677885f5f5f5f5f5f	64	plan9	PADDUSB 0(CX), M2
-0fdd11|223344556677885f5f5f5f5f5f	32	intel	paddusw mmx2, qword ptr [ecx]
-0fdd11|223344556677885f5f5f5f5f5f	32	plan9	PADDUSW 0(CX), M2
-0fdd11|223344556677885f5f5f5f5f5f	64	gnu	paddusw (%rcx),%mm2
-0fdd11|223344556677885f5f5f5f5f5f	64	intel	paddusw mmx2, qword ptr [rcx]
-0fdd11|223344556677885f5f5f5f5f5f	64	plan9	PADDUSW 0(CX), M2
-0fde11|223344556677885f5f5f5f5f5f	32	intel	pmaxub mmx2, qword ptr [ecx]
-0fde11|223344556677885f5f5f5f5f5f	32	plan9	PMAXUB 0(CX), M2
-0fde11|223344556677885f5f5f5f5f5f	64	gnu	pmaxub (%rcx),%mm2
-0fde11|223344556677885f5f5f5f5f5f	64	intel	pmaxub mmx2, qword ptr [rcx]
-0fde11|223344556677885f5f5f5f5f5f	64	plan9	PMAXUB 0(CX), M2
-0fdf11|223344556677885f5f5f5f5f5f	32	intel	pandn mmx2, qword ptr [ecx]
-0fdf11|223344556677885f5f5f5f5f5f	32	plan9	PANDN 0(CX), M2
-0fdf11|223344556677885f5f5f5f5f5f	64	gnu	pandn (%rcx),%mm2
-0fdf11|223344556677885f5f5f5f5f5f	64	intel	pandn mmx2, qword ptr [rcx]
-0fdf11|223344556677885f5f5f5f5f5f	64	plan9	PANDN 0(CX), M2
-0fe011|223344556677885f5f5f5f5f5f	32	intel	pavgb mmx2, qword ptr [ecx]
-0fe011|223344556677885f5f5f5f5f5f	32	plan9	PAVGB 0(CX), M2
-0fe011|223344556677885f5f5f5f5f5f	64	gnu	pavgb (%rcx),%mm2
-0fe011|223344556677885f5f5f5f5f5f	64	intel	pavgb mmx2, qword ptr [rcx]
-0fe011|223344556677885f5f5f5f5f5f	64	plan9	PAVGB 0(CX), M2
-0fe111|223344556677885f5f5f5f5f5f	32	intel	psraw mmx2, qword ptr [ecx]
-0fe111|223344556677885f5f5f5f5f5f	32	plan9	PSRAW 0(CX), M2
-0fe111|223344556677885f5f5f5f5f5f	64	gnu	psraw (%rcx),%mm2
-0fe111|223344556677885f5f5f5f5f5f	64	intel	psraw mmx2, qword ptr [rcx]
-0fe111|223344556677885f5f5f5f5f5f	64	plan9	PSRAW 0(CX), M2
-0fe211|223344556677885f5f5f5f5f5f	32	intel	psrad mmx2, qword ptr [ecx]
-0fe211|223344556677885f5f5f5f5f5f	32	plan9	PSRAD 0(CX), M2
-0fe211|223344556677885f5f5f5f5f5f	64	gnu	psrad (%rcx),%mm2
-0fe211|223344556677885f5f5f5f5f5f	64	intel	psrad mmx2, qword ptr [rcx]
-0fe211|223344556677885f5f5f5f5f5f	64	plan9	PSRAD 0(CX), M2
-0fe311|223344556677885f5f5f5f5f5f	32	intel	pavgw mmx2, qword ptr [ecx]
-0fe311|223344556677885f5f5f5f5f5f	32	plan9	PAVGW 0(CX), M2
-0fe311|223344556677885f5f5f5f5f5f	64	gnu	pavgw (%rcx),%mm2
-0fe311|223344556677885f5f5f5f5f5f	64	intel	pavgw mmx2, qword ptr [rcx]
-0fe311|223344556677885f5f5f5f5f5f	64	plan9	PAVGW 0(CX), M2
-0fe411|223344556677885f5f5f5f5f5f	32	intel	pmulhuw mmx2, qword ptr [ecx]
-0fe411|223344556677885f5f5f5f5f5f	32	plan9	PMULHUW 0(CX), M2
-0fe411|223344556677885f5f5f5f5f5f	64	gnu	pmulhuw (%rcx),%mm2
-0fe411|223344556677885f5f5f5f5f5f	64	intel	pmulhuw mmx2, qword ptr [rcx]
-0fe411|223344556677885f5f5f5f5f5f	64	plan9	PMULHUW 0(CX), M2
-0fe511|223344556677885f5f5f5f5f5f	32	intel	pmulhw mmx2, qword ptr [ecx]
-0fe511|223344556677885f5f5f5f5f5f	32	plan9	PMULHW 0(CX), M2
-0fe511|223344556677885f5f5f5f5f5f	64	gnu	pmulhw (%rcx),%mm2
-0fe511|223344556677885f5f5f5f5f5f	64	intel	pmulhw mmx2, qword ptr [rcx]
-0fe511|223344556677885f5f5f5f5f5f	64	plan9	PMULHW 0(CX), M2
-0fe6|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0fe6|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0fe6|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0fe6|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0fe6|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0fe711|223344556677885f5f5f5f5f5f	32	intel	movntq qword ptr [ecx], mmx2
-0fe711|223344556677885f5f5f5f5f5f	32	plan9	MOVNTQ M2, 0(CX)
-0fe711|223344556677885f5f5f5f5f5f	64	gnu	movntq %mm2,(%rcx)
-0fe711|223344556677885f5f5f5f5f5f	64	intel	movntq qword ptr [rcx], mmx2
-0fe711|223344556677885f5f5f5f5f5f	64	plan9	MOVNTQ M2, 0(CX)
-0fe811|223344556677885f5f5f5f5f5f	32	intel	psubsb mmx2, qword ptr [ecx]
-0fe811|223344556677885f5f5f5f5f5f	32	plan9	PSUBSB 0(CX), M2
-0fe811|223344556677885f5f5f5f5f5f	64	gnu	psubsb (%rcx),%mm2
-0fe811|223344556677885f5f5f5f5f5f	64	intel	psubsb mmx2, qword ptr [rcx]
-0fe811|223344556677885f5f5f5f5f5f	64	plan9	PSUBSB 0(CX), M2
-0fe911|223344556677885f5f5f5f5f5f	32	intel	psubsw mmx2, qword ptr [ecx]
-0fe911|223344556677885f5f5f5f5f5f	32	plan9	PSUBSW 0(CX), M2
-0fe911|223344556677885f5f5f5f5f5f	64	gnu	psubsw (%rcx),%mm2
-0fe911|223344556677885f5f5f5f5f5f	64	intel	psubsw mmx2, qword ptr [rcx]
-0fe911|223344556677885f5f5f5f5f5f	64	plan9	PSUBSW 0(CX), M2
-0fea11|223344556677885f5f5f5f5f5f	32	intel	pminsw mmx2, qword ptr [ecx]
-0fea11|223344556677885f5f5f5f5f5f	32	plan9	PMINSW 0(CX), M2
-0fea11|223344556677885f5f5f5f5f5f	64	gnu	pminsw (%rcx),%mm2
-0fea11|223344556677885f5f5f5f5f5f	64	intel	pminsw mmx2, qword ptr [rcx]
-0fea11|223344556677885f5f5f5f5f5f	64	plan9	PMINSW 0(CX), M2
-0feb11|223344556677885f5f5f5f5f5f	32	intel	por mmx2, qword ptr [ecx]
-0feb11|223344556677885f5f5f5f5f5f	32	plan9	POR 0(CX), M2
-0feb11|223344556677885f5f5f5f5f5f	64	gnu	por (%rcx),%mm2
-0feb11|223344556677885f5f5f5f5f5f	64	intel	por mmx2, qword ptr [rcx]
-0feb11|223344556677885f5f5f5f5f5f	64	plan9	POR 0(CX), M2
-0fec11|223344556677885f5f5f5f5f5f	32	intel	paddsb mmx2, qword ptr [ecx]
-0fec11|223344556677885f5f5f5f5f5f	32	plan9	PADDSB 0(CX), M2
-0fec11|223344556677885f5f5f5f5f5f	64	gnu	paddsb (%rcx),%mm2
-0fec11|223344556677885f5f5f5f5f5f	64	intel	paddsb mmx2, qword ptr [rcx]
-0fec11|223344556677885f5f5f5f5f5f	64	plan9	PADDSB 0(CX), M2
-0fed11|223344556677885f5f5f5f5f5f	32	intel	paddsw mmx2, qword ptr [ecx]
-0fed11|223344556677885f5f5f5f5f5f	32	plan9	PADDSW 0(CX), M2
-0fed11|223344556677885f5f5f5f5f5f	64	gnu	paddsw (%rcx),%mm2
-0fed11|223344556677885f5f5f5f5f5f	64	intel	paddsw mmx2, qword ptr [rcx]
-0fed11|223344556677885f5f5f5f5f5f	64	plan9	PADDSW 0(CX), M2
-0fee11|223344556677885f5f5f5f5f5f	32	intel	pmaxsw mmx2, qword ptr [ecx]
-0fee11|223344556677885f5f5f5f5f5f	32	plan9	PMAXSW 0(CX), M2
-0fee11|223344556677885f5f5f5f5f5f	64	gnu	pmaxsw (%rcx),%mm2
-0fee11|223344556677885f5f5f5f5f5f	64	intel	pmaxsw mmx2, qword ptr [rcx]
-0fee11|223344556677885f5f5f5f5f5f	64	plan9	PMAXSW 0(CX), M2
-0fef11|223344556677885f5f5f5f5f5f	32	intel	pxor mmx2, qword ptr [ecx]
-0fef11|223344556677885f5f5f5f5f5f	32	plan9	PXOR 0(CX), M2
-0fef11|223344556677885f5f5f5f5f5f	64	gnu	pxor (%rcx),%mm2
-0fef11|223344556677885f5f5f5f5f5f	64	intel	pxor mmx2, qword ptr [rcx]
-0fef11|223344556677885f5f5f5f5f5f	64	plan9	PXOR 0(CX), M2
-0ff0|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0ff0|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0ff0|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0ff0|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0ff0|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0ff111|223344556677885f5f5f5f5f5f	32	intel	psllw mmx2, qword ptr [ecx]
-0ff111|223344556677885f5f5f5f5f5f	32	plan9	PSLLW 0(CX), M2
-0ff111|223344556677885f5f5f5f5f5f	64	gnu	psllw (%rcx),%mm2
-0ff111|223344556677885f5f5f5f5f5f	64	intel	psllw mmx2, qword ptr [rcx]
-0ff111|223344556677885f5f5f5f5f5f	64	plan9	PSLLW 0(CX), M2
-0ff211|223344556677885f5f5f5f5f5f	32	intel	pslld mmx2, qword ptr [ecx]
-0ff211|223344556677885f5f5f5f5f5f	32	plan9	PSLLD 0(CX), M2
-0ff211|223344556677885f5f5f5f5f5f	64	gnu	pslld (%rcx),%mm2
-0ff211|223344556677885f5f5f5f5f5f	64	intel	pslld mmx2, qword ptr [rcx]
-0ff211|223344556677885f5f5f5f5f5f	64	plan9	PSLLD 0(CX), M2
-0ff311|223344556677885f5f5f5f5f5f	32	intel	psllq mmx2, qword ptr [ecx]
-0ff311|223344556677885f5f5f5f5f5f	32	plan9	PSLLQ 0(CX), M2
-0ff311|223344556677885f5f5f5f5f5f	64	gnu	psllq (%rcx),%mm2
-0ff311|223344556677885f5f5f5f5f5f	64	intel	psllq mmx2, qword ptr [rcx]
-0ff311|223344556677885f5f5f5f5f5f	64	plan9	PSLLQ 0(CX), M2
-0ff411|223344556677885f5f5f5f5f5f	32	intel	pmuludq mmx2, qword ptr [ecx]
-0ff411|223344556677885f5f5f5f5f5f	32	plan9	PMULUDQ 0(CX), M2
-0ff411|223344556677885f5f5f5f5f5f	64	gnu	pmuludq (%rcx),%mm2
-0ff411|223344556677885f5f5f5f5f5f	64	intel	pmuludq mmx2, qword ptr [rcx]
-0ff411|223344556677885f5f5f5f5f5f	64	plan9	PMULUDQ 0(CX), M2
-0ff511|223344556677885f5f5f5f5f5f	32	intel	pmaddwd mmx2, qword ptr [ecx]
-0ff511|223344556677885f5f5f5f5f5f	32	plan9	PMADDWD 0(CX), M2
-0ff511|223344556677885f5f5f5f5f5f	64	gnu	pmaddwd (%rcx),%mm2
-0ff511|223344556677885f5f5f5f5f5f	64	intel	pmaddwd mmx2, qword ptr [rcx]
-0ff511|223344556677885f5f5f5f5f5f	64	plan9	PMADDWD 0(CX), M2
-0ff611|223344556677885f5f5f5f5f5f	32	intel	psadbw mmx2, qword ptr [ecx]
-0ff611|223344556677885f5f5f5f5f5f	32	plan9	PSADBW 0(CX), M2
-0ff611|223344556677885f5f5f5f5f5f	64	gnu	psadbw (%rcx),%mm2
-0ff611|223344556677885f5f5f5f5f5f	64	intel	psadbw mmx2, qword ptr [rcx]
-0ff611|223344556677885f5f5f5f5f5f	64	plan9	PSADBW 0(CX), M2
-0ff711|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
-0ff711|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
-0ff711|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-0ff711|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-0ff711|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-0ff7c0|11223344556677885f5f5f5f5f	32	intel	maskmovq mmx0, mmx0
-0ff7c0|11223344556677885f5f5f5f5f	32	plan9	MASKMOVQ M0, M0
-0ff7c0|11223344556677885f5f5f5f5f	64	gnu	maskmovq %mm0,%mm0
-0ff7c0|11223344556677885f5f5f5f5f	64	intel	maskmovq mmx0, mmx0
-0ff7c0|11223344556677885f5f5f5f5f	64	plan9	MASKMOVQ M0, M0
-0ff811|223344556677885f5f5f5f5f5f	32	intel	psubb mmx2, qword ptr [ecx]
-0ff811|223344556677885f5f5f5f5f5f	32	plan9	PSUBB 0(CX), M2
-0ff811|223344556677885f5f5f5f5f5f	64	gnu	psubb (%rcx),%mm2
-0ff811|223344556677885f5f5f5f5f5f	64	intel	psubb mmx2, qword ptr [rcx]
-0ff811|223344556677885f5f5f5f5f5f	64	plan9	PSUBB 0(CX), M2
-0ff911|223344556677885f5f5f5f5f5f	32	intel	psubw mmx2, qword ptr [ecx]
-0ff911|223344556677885f5f5f5f5f5f	32	plan9	PSUBW 0(CX), M2
-0ff911|223344556677885f5f5f5f5f5f	64	gnu	psubw (%rcx),%mm2
-0ff911|223344556677885f5f5f5f5f5f	64	intel	psubw mmx2, qword ptr [rcx]
-0ff911|223344556677885f5f5f5f5f5f	64	plan9	PSUBW 0(CX), M2
-0ffa11|223344556677885f5f5f5f5f5f	32	intel	psubd mmx2, qword ptr [ecx]
-0ffa11|223344556677885f5f5f5f5f5f	32	plan9	PSUBD 0(CX), M2
-0ffa11|223344556677885f5f5f5f5f5f	64	gnu	psubd (%rcx),%mm2
-0ffa11|223344556677885f5f5f5f5f5f	64	intel	psubd mmx2, qword ptr [rcx]
-0ffa11|223344556677885f5f5f5f5f5f	64	plan9	PSUBD 0(CX), M2
-0ffb11|223344556677885f5f5f5f5f5f	32	intel	psubq mmx2, qword ptr [ecx]
-0ffb11|223344556677885f5f5f5f5f5f	32	plan9	PSUBQ 0(CX), M2
-0ffb11|223344556677885f5f5f5f5f5f	64	gnu	psubq (%rcx),%mm2
-0ffb11|223344556677885f5f5f5f5f5f	64	intel	psubq mmx2, qword ptr [rcx]
-0ffb11|223344556677885f5f5f5f5f5f	64	plan9	PSUBQ 0(CX), M2
-0ffc11|223344556677885f5f5f5f5f5f	32	intel	paddb mmx2, qword ptr [ecx]
-0ffc11|223344556677885f5f5f5f5f5f	32	plan9	PADDB 0(CX), M2
-0ffc11|223344556677885f5f5f5f5f5f	64	gnu	paddb (%rcx),%mm2
-0ffc11|223344556677885f5f5f5f5f5f	64	intel	paddb mmx2, qword ptr [rcx]
-0ffc11|223344556677885f5f5f5f5f5f	64	plan9	PADDB 0(CX), M2
-0ffd11|223344556677885f5f5f5f5f5f	32	intel	paddw mmx2, qword ptr [ecx]
-0ffd11|223344556677885f5f5f5f5f5f	32	plan9	PADDW 0(CX), M2
-0ffd11|223344556677885f5f5f5f5f5f	64	gnu	paddw (%rcx),%mm2
-0ffd11|223344556677885f5f5f5f5f5f	64	intel	paddw mmx2, qword ptr [rcx]
-0ffd11|223344556677885f5f5f5f5f5f	64	plan9	PADDW 0(CX), M2
-0ffe11|223344556677885f5f5f5f5f5f	32	intel	paddd mmx2, qword ptr [ecx]
-0ffe11|223344556677885f5f5f5f5f5f	32	plan9	PADDD 0(CX), M2
-0ffe11|223344556677885f5f5f5f5f5f	64	gnu	paddd (%rcx),%mm2
-0ffe11|223344556677885f5f5f5f5f5f	64	intel	paddd mmx2, qword ptr [rcx]
-0ffe11|223344556677885f5f5f5f5f5f	64	plan9	PADDD 0(CX), M2
-1011|223344556677885f5f5f5f5f5f5f	32	intel	adc byte ptr [ecx], dl
-1011|223344556677885f5f5f5f5f5f5f	32	plan9	ADCL DL, 0(CX)
-1011|223344556677885f5f5f5f5f5f5f	64	gnu	adc %dl,(%rcx)
-1011|223344556677885f5f5f5f5f5f5f	64	intel	adc byte ptr [rcx], dl
-1011|223344556677885f5f5f5f5f5f5f	64	plan9	ADCL DL, 0(CX)
-1111|223344556677885f5f5f5f5f5f5f	32	intel	adc dword ptr [ecx], edx
-1111|223344556677885f5f5f5f5f5f5f	32	plan9	ADCL DX, 0(CX)
-1111|223344556677885f5f5f5f5f5f5f	64	gnu	adc %edx,(%rcx)
-1111|223344556677885f5f5f5f5f5f5f	64	intel	adc dword ptr [rcx], edx
-1111|223344556677885f5f5f5f5f5f5f	64	plan9	ADCL DX, 0(CX)
-1211|223344556677885f5f5f5f5f5f5f	32	intel	adc dl, byte ptr [ecx]
-1211|223344556677885f5f5f5f5f5f5f	32	plan9	ADCL 0(CX), DL
-1211|223344556677885f5f5f5f5f5f5f	64	gnu	adc (%rcx),%dl
-1211|223344556677885f5f5f5f5f5f5f	64	intel	adc dl, byte ptr [rcx]
-1211|223344556677885f5f5f5f5f5f5f	64	plan9	ADCL 0(CX), DL
-1311|223344556677885f5f5f5f5f5f5f	32	intel	adc edx, dword ptr [ecx]
-1311|223344556677885f5f5f5f5f5f5f	32	plan9	ADCL 0(CX), DX
-1311|223344556677885f5f5f5f5f5f5f	64	gnu	adc (%rcx),%edx
-1311|223344556677885f5f5f5f5f5f5f	64	intel	adc edx, dword ptr [rcx]
-1311|223344556677885f5f5f5f5f5f5f	64	plan9	ADCL 0(CX), DX
-1411|223344556677885f5f5f5f5f5f5f	32	intel	adc al, 0x11
-1411|223344556677885f5f5f5f5f5f5f	32	plan9	ADCL $0x11, AL
-1411|223344556677885f5f5f5f5f5f5f	64	gnu	adc $0x11,%al
-1411|223344556677885f5f5f5f5f5f5f	64	intel	adc al, 0x11
-1411|223344556677885f5f5f5f5f5f5f	64	plan9	ADCL $0x11, AL
-1511223344|556677885f5f5f5f5f5f5f	32	intel	adc eax, 0x44332211
-1511223344|556677885f5f5f5f5f5f5f	32	plan9	ADCL $0x44332211, AX
-1511223344|556677885f5f5f5f5f5f5f	64	gnu	adc $0x44332211,%eax
-1511223344|556677885f5f5f5f5f5f5f	64	intel	adc eax, 0x44332211
-1511223344|556677885f5f5f5f5f5f5f	64	plan9	ADCL $0x44332211, AX
-16|11223344556677885f5f5f5f5f5f5f	32	intel	push ss
-16|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL SS
-16|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-16|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-16|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-17|11223344556677885f5f5f5f5f5f5f	32	intel	pop ss
-17|11223344556677885f5f5f5f5f5f5f	32	plan9	POPL SS
-17|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-17|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-17|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-1811|223344556677885f5f5f5f5f5f5f	32	intel	sbb byte ptr [ecx], dl
-1811|223344556677885f5f5f5f5f5f5f	32	plan9	SBBL DL, 0(CX)
-1811|223344556677885f5f5f5f5f5f5f	64	gnu	sbb %dl,(%rcx)
-1811|223344556677885f5f5f5f5f5f5f	64	intel	sbb byte ptr [rcx], dl
-1811|223344556677885f5f5f5f5f5f5f	64	plan9	SBBL DL, 0(CX)
-1911|223344556677885f5f5f5f5f5f5f	32	intel	sbb dword ptr [ecx], edx
-1911|223344556677885f5f5f5f5f5f5f	32	plan9	SBBL DX, 0(CX)
-1911|223344556677885f5f5f5f5f5f5f	64	gnu	sbb %edx,(%rcx)
-1911|223344556677885f5f5f5f5f5f5f	64	intel	sbb dword ptr [rcx], edx
-1911|223344556677885f5f5f5f5f5f5f	64	plan9	SBBL DX, 0(CX)
-1a11|223344556677885f5f5f5f5f5f5f	32	intel	sbb dl, byte ptr [ecx]
-1a11|223344556677885f5f5f5f5f5f5f	32	plan9	SBBL 0(CX), DL
-1a11|223344556677885f5f5f5f5f5f5f	64	gnu	sbb (%rcx),%dl
-1a11|223344556677885f5f5f5f5f5f5f	64	intel	sbb dl, byte ptr [rcx]
-1a11|223344556677885f5f5f5f5f5f5f	64	plan9	SBBL 0(CX), DL
-1b11|223344556677885f5f5f5f5f5f5f	32	intel	sbb edx, dword ptr [ecx]
-1b11|223344556677885f5f5f5f5f5f5f	32	plan9	SBBL 0(CX), DX
-1b11|223344556677885f5f5f5f5f5f5f	64	gnu	sbb (%rcx),%edx
-1b11|223344556677885f5f5f5f5f5f5f	64	intel	sbb edx, dword ptr [rcx]
-1b11|223344556677885f5f5f5f5f5f5f	64	plan9	SBBL 0(CX), DX
-1c11|223344556677885f5f5f5f5f5f5f	32	intel	sbb al, 0x11
-1c11|223344556677885f5f5f5f5f5f5f	32	plan9	SBBL $0x11, AL
-1c11|223344556677885f5f5f5f5f5f5f	64	gnu	sbb $0x11,%al
-1c11|223344556677885f5f5f5f5f5f5f	64	intel	sbb al, 0x11
-1c11|223344556677885f5f5f5f5f5f5f	64	plan9	SBBL $0x11, AL
-1d11223344|556677885f5f5f5f5f5f5f	32	intel	sbb eax, 0x44332211
-1d11223344|556677885f5f5f5f5f5f5f	32	plan9	SBBL $0x44332211, AX
-1d11223344|556677885f5f5f5f5f5f5f	64	gnu	sbb $0x44332211,%eax
-1d11223344|556677885f5f5f5f5f5f5f	64	intel	sbb eax, 0x44332211
-1d11223344|556677885f5f5f5f5f5f5f	64	plan9	SBBL $0x44332211, AX
-1e|11223344556677885f5f5f5f5f5f5f	32	intel	push ds
-1e|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL DS
-1e|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-1e|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-1e|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-1f|11223344556677885f5f5f5f5f5f5f	32	intel	pop ds
-1f|11223344556677885f5f5f5f5f5f5f	32	plan9	POPL DS
-1f|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-1f|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-1f|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-2011|223344556677885f5f5f5f5f5f5f	32	intel	and byte ptr [ecx], dl
-2011|223344556677885f5f5f5f5f5f5f	32	plan9	ANDL DL, 0(CX)
-2011|223344556677885f5f5f5f5f5f5f	64	gnu	and %dl,(%rcx)
-2011|223344556677885f5f5f5f5f5f5f	64	intel	and byte ptr [rcx], dl
-2011|223344556677885f5f5f5f5f5f5f	64	plan9	ANDL DL, 0(CX)
-2111|223344556677885f5f5f5f5f5f5f	32	intel	and dword ptr [ecx], edx
-2111|223344556677885f5f5f5f5f5f5f	32	plan9	ANDL DX, 0(CX)
-2111|223344556677885f5f5f5f5f5f5f	64	gnu	and %edx,(%rcx)
-2111|223344556677885f5f5f5f5f5f5f	64	intel	and dword ptr [rcx], edx
-2111|223344556677885f5f5f5f5f5f5f	64	plan9	ANDL DX, 0(CX)
-2211|223344556677885f5f5f5f5f5f5f	32	intel	and dl, byte ptr [ecx]
-2211|223344556677885f5f5f5f5f5f5f	32	plan9	ANDL 0(CX), DL
-2211|223344556677885f5f5f5f5f5f5f	64	gnu	and (%rcx),%dl
-2211|223344556677885f5f5f5f5f5f5f	64	intel	and dl, byte ptr [rcx]
-2211|223344556677885f5f5f5f5f5f5f	64	plan9	ANDL 0(CX), DL
-2311|223344556677885f5f5f5f5f5f5f	32	intel	and edx, dword ptr [ecx]
-2311|223344556677885f5f5f5f5f5f5f	32	plan9	ANDL 0(CX), DX
-2311|223344556677885f5f5f5f5f5f5f	64	gnu	and (%rcx),%edx
-2311|223344556677885f5f5f5f5f5f5f	64	intel	and edx, dword ptr [rcx]
-2311|223344556677885f5f5f5f5f5f5f	64	plan9	ANDL 0(CX), DX
-2411|223344556677885f5f5f5f5f5f5f	32	intel	and al, 0x11
-2411|223344556677885f5f5f5f5f5f5f	32	plan9	ANDL $0x11, AL
-2411|223344556677885f5f5f5f5f5f5f	64	gnu	and $0x11,%al
-2411|223344556677885f5f5f5f5f5f5f	64	intel	and al, 0x11
-2411|223344556677885f5f5f5f5f5f5f	64	plan9	ANDL $0x11, AL
-2511223344|556677885f5f5f5f5f5f5f	32	intel	and eax, 0x44332211
-2511223344|556677885f5f5f5f5f5f5f	32	plan9	ANDL $0x44332211, AX
-2511223344|556677885f5f5f5f5f5f5f	64	gnu	and $0x44332211,%eax
-2511223344|556677885f5f5f5f5f5f5f	64	intel	and eax, 0x44332211
-2511223344|556677885f5f5f5f5f5f5f	64	plan9	ANDL $0x44332211, AX
-266e|11223344556677885f5f5f5f5f5f	32	intel	outsb es
-266e|11223344556677885f5f5f5f5f5f	32	plan9	ES OUTSB ES:0(SI), DX
-266e|11223344556677885f5f5f5f5f5f	64	gnu	outsb %ds:%es:(%rsi),(%dx)
-266e|11223344556677885f5f5f5f5f5f	64	intel	outsb
-266e|11223344556677885f5f5f5f5f5f	64	plan9	ES OUTSB DS:0(SI), DX
-267011|223344556677885f5f5f5f5f5f	32	intel	jo .+0x11
-267011|223344556677885f5f5f5f5f5f	32	plan9	ES JO .+17
-267011|223344556677885f5f5f5f5f5f	64	gnu	es jo .+0x11
-267011|223344556677885f5f5f5f5f5f	64	intel	jo .+0x11
-267011|223344556677885f5f5f5f5f5f	64	plan9	ES JO .+17
-26a01122334455667788|5f5f5f5f5f5f	64	gnu	mov %es:-0x778899aabbccddef,%al
-26a01122334455667788|5f5f5f5f5f5f	64	intel	mov al, byte ptr [0x8877665544332211]
-26a01122334455667788|5f5f5f5f5f5f	64	plan9	ES MOVL -0x778899aabbccddef, AL
-26a011223344|556677885f5f5f5f5f5f	32	intel	mov al, byte ptr es:[0x44332211]
-26a011223344|556677885f5f5f5f5f5f	32	plan9	ES MOVL ES:0x44332211, AL
-26|8211223344556677885f5f5f5f5f5f	32	intel	es
-26|8211223344556677885f5f5f5f5f5f	32	plan9	ES Op(0)
-26|8211223344556677885f5f5f5f5f5f	64	gnu	es
-26|8211223344556677885f5f5f5f5f5f	64	intel	es
-26|8211223344556677885f5f5f5f5f5f	64	plan9	ES Op(0)
-27|11223344556677885f5f5f5f5f5f5f	32	intel	daa
-27|11223344556677885f5f5f5f5f5f5f	32	plan9	DAA
-27|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-27|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-27|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-2811|223344556677885f5f5f5f5f5f5f	32	intel	sub byte ptr [ecx], dl
-2811|223344556677885f5f5f5f5f5f5f	32	plan9	SUBL DL, 0(CX)
-2811|223344556677885f5f5f5f5f5f5f	64	gnu	sub %dl,(%rcx)
-2811|223344556677885f5f5f5f5f5f5f	64	intel	sub byte ptr [rcx], dl
-2811|223344556677885f5f5f5f5f5f5f	64	plan9	SUBL DL, 0(CX)
-2911|223344556677885f5f5f5f5f5f5f	32	intel	sub dword ptr [ecx], edx
-2911|223344556677885f5f5f5f5f5f5f	32	plan9	SUBL DX, 0(CX)
-2911|223344556677885f5f5f5f5f5f5f	64	gnu	sub %edx,(%rcx)
-2911|223344556677885f5f5f5f5f5f5f	64	intel	sub dword ptr [rcx], edx
-2911|223344556677885f5f5f5f5f5f5f	64	plan9	SUBL DX, 0(CX)
-2a11|223344556677885f5f5f5f5f5f5f	32	intel	sub dl, byte ptr [ecx]
-2a11|223344556677885f5f5f5f5f5f5f	32	plan9	SUBL 0(CX), DL
-2a11|223344556677885f5f5f5f5f5f5f	64	gnu	sub (%rcx),%dl
-2a11|223344556677885f5f5f5f5f5f5f	64	intel	sub dl, byte ptr [rcx]
-2a11|223344556677885f5f5f5f5f5f5f	64	plan9	SUBL 0(CX), DL
-2b11|223344556677885f5f5f5f5f5f5f	32	intel	sub edx, dword ptr [ecx]
-2b11|223344556677885f5f5f5f5f5f5f	32	plan9	SUBL 0(CX), DX
-2b11|223344556677885f5f5f5f5f5f5f	64	gnu	sub (%rcx),%edx
-2b11|223344556677885f5f5f5f5f5f5f	64	intel	sub edx, dword ptr [rcx]
-2b11|223344556677885f5f5f5f5f5f5f	64	plan9	SUBL 0(CX), DX
-2c11|223344556677885f5f5f5f5f5f5f	32	intel	sub al, 0x11
-2c11|223344556677885f5f5f5f5f5f5f	32	plan9	SUBL $0x11, AL
-2c11|223344556677885f5f5f5f5f5f5f	64	gnu	sub $0x11,%al
-2c11|223344556677885f5f5f5f5f5f5f	64	intel	sub al, 0x11
-2c11|223344556677885f5f5f5f5f5f5f	64	plan9	SUBL $0x11, AL
-2d11223344|556677885f5f5f5f5f5f5f	32	intel	sub eax, 0x44332211
-2d11223344|556677885f5f5f5f5f5f5f	32	plan9	SUBL $0x44332211, AX
-2d11223344|556677885f5f5f5f5f5f5f	64	gnu	sub $0x44332211,%eax
-2d11223344|556677885f5f5f5f5f5f5f	64	intel	sub eax, 0x44332211
-2d11223344|556677885f5f5f5f5f5f5f	64	plan9	SUBL $0x44332211, AX
-2f|11223344556677885f5f5f5f5f5f5f	32	intel	das
-2f|11223344556677885f5f5f5f5f5f5f	32	plan9	DAS
-2f|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-2f|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-2f|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-3011|223344556677885f5f5f5f5f5f5f	32	intel	xor byte ptr [ecx], dl
-3011|223344556677885f5f5f5f5f5f5f	32	plan9	XORL DL, 0(CX)
-3011|223344556677885f5f5f5f5f5f5f	64	gnu	xor %dl,(%rcx)
-3011|223344556677885f5f5f5f5f5f5f	64	intel	xor byte ptr [rcx], dl
-3011|223344556677885f5f5f5f5f5f5f	64	plan9	XORL DL, 0(CX)
-3111|223344556677885f5f5f5f5f5f5f	32	intel	xor dword ptr [ecx], edx
-3111|223344556677885f5f5f5f5f5f5f	32	plan9	XORL DX, 0(CX)
-3111|223344556677885f5f5f5f5f5f5f	64	gnu	xor %edx,(%rcx)
-3111|223344556677885f5f5f5f5f5f5f	64	intel	xor dword ptr [rcx], edx
-3111|223344556677885f5f5f5f5f5f5f	64	plan9	XORL DX, 0(CX)
-3211|223344556677885f5f5f5f5f5f5f	32	intel	xor dl, byte ptr [ecx]
-3211|223344556677885f5f5f5f5f5f5f	32	plan9	XORL 0(CX), DL
-3211|223344556677885f5f5f5f5f5f5f	64	gnu	xor (%rcx),%dl
-3211|223344556677885f5f5f5f5f5f5f	64	intel	xor dl, byte ptr [rcx]
-3211|223344556677885f5f5f5f5f5f5f	64	plan9	XORL 0(CX), DL
-3311|223344556677885f5f5f5f5f5f5f	32	intel	xor edx, dword ptr [ecx]
-3311|223344556677885f5f5f5f5f5f5f	32	plan9	XORL 0(CX), DX
-3311|223344556677885f5f5f5f5f5f5f	64	gnu	xor (%rcx),%edx
-3311|223344556677885f5f5f5f5f5f5f	64	intel	xor edx, dword ptr [rcx]
-3311|223344556677885f5f5f5f5f5f5f	64	plan9	XORL 0(CX), DX
-3411|223344556677885f5f5f5f5f5f5f	32	intel	xor al, 0x11
-3411|223344556677885f5f5f5f5f5f5f	32	plan9	XORL $0x11, AL
-3411|223344556677885f5f5f5f5f5f5f	64	gnu	xor $0x11,%al
-3411|223344556677885f5f5f5f5f5f5f	64	intel	xor al, 0x11
-3411|223344556677885f5f5f5f5f5f5f	64	plan9	XORL $0x11, AL
-3511223344|556677885f5f5f5f5f5f5f	32	intel	xor eax, 0x44332211
-3511223344|556677885f5f5f5f5f5f5f	32	plan9	XORL $0x44332211, AX
-3511223344|556677885f5f5f5f5f5f5f	64	gnu	xor $0x44332211,%eax
-3511223344|556677885f5f5f5f5f5f5f	64	intel	xor eax, 0x44332211
-3511223344|556677885f5f5f5f5f5f5f	64	plan9	XORL $0x44332211, AX
-3667f3660f2ac0|11223344556677885f	32	intel	addr16 cvtsi2ss xmm0, eax
-3667f3660f2ac0|11223344556677885f	32	plan9	CVTSI2SSW AX, X0
-3667f3660f2ac0|11223344556677885f	64	gnu	ss addr32 cvtsi2ss %ax,%xmm0
-3667f3660f2ac0|11223344556677885f	64	intel	addr32 cvtsi2ss xmm0, eax
-3667f3660f2ac0|11223344556677885f	64	plan9	CVTSI2SSW AX, X0
-36|67f3660ff7c011223344556677885f	64	gnu	ss
-36|f0f2f33e66f066f2f33e3666818411	32	intel	ss
-36|f0f2f33e66f066f2f33e3666818411	32	plan9	SS Op(0)
-36|f0f2f33e66f066f2f33e3666818411	64	gnu	ss
-36|f0f2f33e66f066f2f33e3666818411	64	intel	ss
-36|f0f2f33e66f066f2f33e3666818411	64	plan9	SS Op(0)
-36|f2f33ef0f78411223344556677885f	32	intel	ss
-36|f2f33ef0f78411223344556677885f	32	plan9	SS Op(0)
-36|f2f33ef0f78411223344556677885f	64	gnu	ss
-36|f2f33ef0f78411223344556677885f	64	intel	ss
-36|f2f33ef0f78411223344556677885f	64	plan9	SS Op(0)
-37|11223344556677885f5f5f5f5f5f5f	32	intel	aaa
-37|11223344556677885f5f5f5f5f5f5f	32	plan9	AAA
-37|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-37|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-37|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-3811|223344556677885f5f5f5f5f5f5f	32	intel	cmp byte ptr [ecx], dl
-3811|223344556677885f5f5f5f5f5f5f	32	plan9	CMPL DL, 0(CX)
-3811|223344556677885f5f5f5f5f5f5f	64	gnu	cmp %dl,(%rcx)
-3811|223344556677885f5f5f5f5f5f5f	64	intel	cmp byte ptr [rcx], dl
-3811|223344556677885f5f5f5f5f5f5f	64	plan9	CMPL DL, 0(CX)
-3911|223344556677885f5f5f5f5f5f5f	32	intel	cmp dword ptr [ecx], edx
-3911|223344556677885f5f5f5f5f5f5f	32	plan9	CMPL DX, 0(CX)
-3911|223344556677885f5f5f5f5f5f5f	64	gnu	cmp %edx,(%rcx)
-3911|223344556677885f5f5f5f5f5f5f	64	intel	cmp dword ptr [rcx], edx
-3911|223344556677885f5f5f5f5f5f5f	64	plan9	CMPL DX, 0(CX)
-3a11|223344556677885f5f5f5f5f5f5f	32	intel	cmp dl, byte ptr [ecx]
-3a11|223344556677885f5f5f5f5f5f5f	32	plan9	CMPL 0(CX), DL
-3a11|223344556677885f5f5f5f5f5f5f	64	gnu	cmp (%rcx),%dl
-3a11|223344556677885f5f5f5f5f5f5f	64	intel	cmp dl, byte ptr [rcx]
-3a11|223344556677885f5f5f5f5f5f5f	64	plan9	CMPL 0(CX), DL
-3b11|223344556677885f5f5f5f5f5f5f	32	intel	cmp edx, dword ptr [ecx]
-3b11|223344556677885f5f5f5f5f5f5f	32	plan9	CMPL 0(CX), DX
-3b11|223344556677885f5f5f5f5f5f5f	64	gnu	cmp (%rcx),%edx
-3b11|223344556677885f5f5f5f5f5f5f	64	intel	cmp edx, dword ptr [rcx]
-3b11|223344556677885f5f5f5f5f5f5f	64	plan9	CMPL 0(CX), DX
-3c11|223344556677885f5f5f5f5f5f5f	32	intel	cmp al, 0x11
-3c11|223344556677885f5f5f5f5f5f5f	32	plan9	CMPL $0x11, AL
-3c11|223344556677885f5f5f5f5f5f5f	64	gnu	cmp $0x11,%al
-3c11|223344556677885f5f5f5f5f5f5f	64	intel	cmp al, 0x11
-3c11|223344556677885f5f5f5f5f5f5f	64	plan9	CMPL $0x11, AL
-3d11223344|556677885f5f5f5f5f5f5f	32	intel	cmp eax, 0x44332211
-3d11223344|556677885f5f5f5f5f5f5f	32	plan9	CMPL $0x44332211, AX
-3d11223344|556677885f5f5f5f5f5f5f	64	gnu	cmp $0x44332211,%eax
-3d11223344|556677885f5f5f5f5f5f5f	64	intel	cmp eax, 0x44332211
-3d11223344|556677885f5f5f5f5f5f5f	64	plan9	CMPL $0x44332211, AX
-3e67e011|223344556677885f5f5f5f5f	32	intel	addr16 loopne .+0x11
-3e67e011|223344556677885f5f5f5f5f	32	plan9	LOOPNE .+17
-3e67e011|223344556677885f5f5f5f5f	64	gnu	loopne,pt .+0x11
-3e67e011|223344556677885f5f5f5f5f	64	intel	addr32 loopne .+0x11
-3e67e011|223344556677885f5f5f5f5f	64	plan9	LOOPNE .+17
-3ef367660f38f011|223344556677885f	32	intel	movbe dx, word ptr [bx+di*1]
-3ef367660f38f011|223344556677885f	32	plan9	MOVBE DS:0(BX)(DI*1), DX
-3ef367660f38f011|223344556677885f	64	gnu	rep movbe %ds:(%ecx),%dx
-3ef367660f38f011|223344556677885f	64	intel	movbe dx, word ptr [ecx]
-3ef367660f38f011|223344556677885f	64	plan9	MOVBE 0(CX), DX
-3f|11223344556677885f5f5f5f5f5f5f	32	intel	aas
-3f|11223344556677885f5f5f5f5f5f5f	32	plan9	AAS
-3f|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-3f|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-3f|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-4040|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-4040|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-4040|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-4048|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-4048|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
-4048|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-40|11223344556677885f5f5f5f5f5f5f	32	intel	inc eax
-40|11223344556677885f5f5f5f5f5f5f	32	plan9	INCL AX
-480100|11223344556677885f5f5f5f5f	64	gnu	add %rax,(%rax)
-480100|11223344556677885f5f5f5f5f	64	intel	add qword ptr [rax], rax
-480100|11223344556677885f5f5f5f5f	64	plan9	ADDQ AX, 0(AX)
-480311|223344556677885f5f5f5f5f5f	64	gnu	add (%rcx),%rdx
-480311|223344556677885f5f5f5f5f5f	64	intel	add rdx, qword ptr [rcx]
-480311|223344556677885f5f5f5f5f5f	64	plan9	ADDQ 0(CX), DX
-480511223344|556677885f5f5f5f5f5f	64	gnu	add $0x44332211,%rax
-480511223344|556677885f5f5f5f5f5f	64	intel	add rax, 0x44332211
-480511223344|556677885f5f5f5f5f5f	64	plan9	ADDQ $0x44332211, AX
-480911|223344556677885f5f5f5f5f5f	64	gnu	or %rdx,(%rcx)
-480911|223344556677885f5f5f5f5f5f	64	intel	or qword ptr [rcx], rdx
-480911|223344556677885f5f5f5f5f5f	64	plan9	ORQ DX, 0(CX)
-480b11|223344556677885f5f5f5f5f5f	64	gnu	or (%rcx),%rdx
-480b11|223344556677885f5f5f5f5f5f	64	intel	or rdx, qword ptr [rcx]
-480b11|223344556677885f5f5f5f5f5f	64	plan9	ORQ 0(CX), DX
-480d11223344|556677885f5f5f5f5f5f	64	gnu	or $0x44332211,%rax
-480d11223344|556677885f5f5f5f5f5f	64	intel	or rax, 0x44332211
-480d11223344|556677885f5f5f5f5f5f	64	plan9	ORQ $0x44332211, AX
-480f0000|11223344556677885f5f5f5f	64	gnu	sldt (%rax)
-480f0000|11223344556677885f5f5f5f	64	intel	sldt word ptr [rax]
-480f0000|11223344556677885f5f5f5f	64	plan9	SLDT 0(AX)
-480f0008|11223344556677885f5f5f5f	64	gnu	str (%rax)
-480f0008|11223344556677885f5f5f5f	64	intel	str word ptr [rax]
-480f0008|11223344556677885f5f5f5f	64	plan9	STR 0(AX)
-480f0120|11223344556677885f5f5f5f	64	gnu	smsw (%rax)
-480f0120|11223344556677885f5f5f5f	64	intel	smsw word ptr [rax]
-480f0120|11223344556677885f5f5f5f	64	plan9	SMSW 0(AX)
-480f0211|223344556677885f5f5f5f5f	64	gnu	lar (%rcx),%rdx
-480f0211|223344556677885f5f5f5f5f	64	intel	lar rdx, word ptr [rcx]
-480f0211|223344556677885f5f5f5f5f	64	plan9	LAR 0(CX), DX
-480f0311|223344556677885f5f5f5f5f	64	gnu	lsl (%rcx),%rdx
-480f0311|223344556677885f5f5f5f5f	64	intel	lsl rdx, word ptr [rcx]
-480f0311|223344556677885f5f5f5f5f	64	plan9	LSL 0(CX), DX
-480f35|11223344556677885f5f5f5f5f	64	gnu	sysexit
-480f35|11223344556677885f5f5f5f5f	64	intel	sysexit
-480f35|11223344556677885f5f5f5f5f	64	plan9	SYSEXIT
-480f38f011|223344556677885f5f5f5f	64	gnu	movbe (%rcx),%rdx
-480f38f011|223344556677885f5f5f5f	64	intel	movbe rdx, qword ptr [rcx]
-480f38f011|223344556677885f5f5f5f	64	plan9	MOVBE 0(CX), DX
-480f38f111|223344556677885f5f5f5f	64	gnu	movbe %rdx,(%rcx)
-480f38f111|223344556677885f5f5f5f	64	intel	movbe qword ptr [rcx], rdx
-480f38f111|223344556677885f5f5f5f	64	plan9	MOVBE DX, 0(CX)
-480f4011|223344556677885f5f5f5f5f	64	gnu	cmovo (%rcx),%rdx
-480f4011|223344556677885f5f5f5f5f	64	intel	cmovo rdx, qword ptr [rcx]
-480f4011|223344556677885f5f5f5f5f	64	plan9	CMOVO 0(CX), DX
-480f4111|223344556677885f5f5f5f5f	64	gnu	cmovno (%rcx),%rdx
-480f4111|223344556677885f5f5f5f5f	64	intel	cmovno rdx, qword ptr [rcx]
-480f4111|223344556677885f5f5f5f5f	64	plan9	CMOVNO 0(CX), DX
-480f4211|223344556677885f5f5f5f5f	64	gnu	cmovb (%rcx),%rdx
-480f4211|223344556677885f5f5f5f5f	64	intel	cmovb rdx, qword ptr [rcx]
-480f4211|223344556677885f5f5f5f5f	64	plan9	CMOVB 0(CX), DX
-480f4311|223344556677885f5f5f5f5f	64	gnu	cmovae (%rcx),%rdx
-480f4311|223344556677885f5f5f5f5f	64	intel	cmovnb rdx, qword ptr [rcx]
-480f4311|223344556677885f5f5f5f5f	64	plan9	CMOVAE 0(CX), DX
-480f4411|223344556677885f5f5f5f5f	64	gnu	cmove (%rcx),%rdx
-480f4411|223344556677885f5f5f5f5f	64	intel	cmovz rdx, qword ptr [rcx]
-480f4411|223344556677885f5f5f5f5f	64	plan9	CMOVE 0(CX), DX
-480f4511|223344556677885f5f5f5f5f	64	gnu	cmovne (%rcx),%rdx
-480f4511|223344556677885f5f5f5f5f	64	intel	cmovnz rdx, qword ptr [rcx]
-480f4511|223344556677885f5f5f5f5f	64	plan9	CMOVNE 0(CX), DX
-480f4611|223344556677885f5f5f5f5f	64	gnu	cmovbe (%rcx),%rdx
-480f4611|223344556677885f5f5f5f5f	64	intel	cmovbe rdx, qword ptr [rcx]
-480f4611|223344556677885f5f5f5f5f	64	plan9	CMOVBE 0(CX), DX
-480f4711|223344556677885f5f5f5f5f	64	gnu	cmova (%rcx),%rdx
-480f4711|223344556677885f5f5f5f5f	64	intel	cmovnbe rdx, qword ptr [rcx]
-480f4711|223344556677885f5f5f5f5f	64	plan9	CMOVA 0(CX), DX
-480f4811|223344556677885f5f5f5f5f	64	gnu	cmovs (%rcx),%rdx
-480f4811|223344556677885f5f5f5f5f	64	intel	cmovs rdx, qword ptr [rcx]
-480f4811|223344556677885f5f5f5f5f	64	plan9	CMOVS 0(CX), DX
-480f4911|223344556677885f5f5f5f5f	64	gnu	cmovns (%rcx),%rdx
-480f4911|223344556677885f5f5f5f5f	64	intel	cmovns rdx, qword ptr [rcx]
-480f4911|223344556677885f5f5f5f5f	64	plan9	CMOVNS 0(CX), DX
-480f4a11|223344556677885f5f5f5f5f	64	gnu	cmovp (%rcx),%rdx
-480f4a11|223344556677885f5f5f5f5f	64	intel	cmovp rdx, qword ptr [rcx]
-480f4a11|223344556677885f5f5f5f5f	64	plan9	CMOVP 0(CX), DX
-480f4b11|223344556677885f5f5f5f5f	64	gnu	cmovnp (%rcx),%rdx
-480f4b11|223344556677885f5f5f5f5f	64	intel	cmovnp rdx, qword ptr [rcx]
-480f4b11|223344556677885f5f5f5f5f	64	plan9	CMOVNP 0(CX), DX
-480f4c11|223344556677885f5f5f5f5f	64	gnu	cmovl (%rcx),%rdx
-480f4c11|223344556677885f5f5f5f5f	64	intel	cmovl rdx, qword ptr [rcx]
-480f4c11|223344556677885f5f5f5f5f	64	plan9	CMOVL 0(CX), DX
-480f4d11|223344556677885f5f5f5f5f	64	gnu	cmovge (%rcx),%rdx
-480f4d11|223344556677885f5f5f5f5f	64	intel	cmovnl rdx, qword ptr [rcx]
-480f4d11|223344556677885f5f5f5f5f	64	plan9	CMOVGE 0(CX), DX
-480f4e11|223344556677885f5f5f5f5f	64	gnu	cmovle (%rcx),%rdx
-480f4e11|223344556677885f5f5f5f5f	64	intel	cmovle rdx, qword ptr [rcx]
-480f4e11|223344556677885f5f5f5f5f	64	plan9	CMOVLE 0(CX), DX
-480f4f11|223344556677885f5f5f5f5f	64	gnu	cmovg (%rcx),%rdx
-480f4f11|223344556677885f5f5f5f5f	64	intel	cmovnle rdx, qword ptr [rcx]
-480f4f11|223344556677885f5f5f5f5f	64	plan9	CMOVG 0(CX), DX
-480f6e11|223344556677885f5f5f5f5f	64	gnu	movq (%rcx),%mm2
-480f6e11|223344556677885f5f5f5f5f	64	intel	movq mmx2, qword ptr [rcx]
-480f6e11|223344556677885f5f5f5f5f	64	plan9	MOVQ 0(CX), M2
-480f7e11|223344556677885f5f5f5f5f	64	gnu	movq %mm2,(%rcx)
-480f7e11|223344556677885f5f5f5f5f	64	intel	movq qword ptr [rcx], mmx2
-480f7e11|223344556677885f5f5f5f5f	64	plan9	MOVQ M2, 0(CX)
-480f8011223344|556677885f5f5f5f5f	64	gnu	jo .+0x44332211
-480f8011223344|556677885f5f5f5f5f	64	intel	jo .+0x44332211
-480f8011223344|556677885f5f5f5f5f	64	plan9	JO .+1144201745
-480f8111223344|556677885f5f5f5f5f	64	gnu	jno .+0x44332211
-480f8111223344|556677885f5f5f5f5f	64	intel	jno .+0x44332211
-480f8111223344|556677885f5f5f5f5f	64	plan9	JNO .+1144201745
-480f8211223344|556677885f5f5f5f5f	64	gnu	jb .+0x44332211
-480f8211223344|556677885f5f5f5f5f	64	intel	jb .+0x44332211
-480f8211223344|556677885f5f5f5f5f	64	plan9	JB .+1144201745
-480f8311223344|556677885f5f5f5f5f	64	gnu	jae .+0x44332211
-480f8311223344|556677885f5f5f5f5f	64	intel	jnb .+0x44332211
-480f8311223344|556677885f5f5f5f5f	64	plan9	JAE .+1144201745
-480f8411223344|556677885f5f5f5f5f	64	gnu	je .+0x44332211
-480f8411223344|556677885f5f5f5f5f	64	intel	jz .+0x44332211
-480f8411223344|556677885f5f5f5f5f	64	plan9	JE .+1144201745
-480f8511223344|556677885f5f5f5f5f	64	gnu	jne .+0x44332211
-480f8511223344|556677885f5f5f5f5f	64	intel	jnz .+0x44332211
-480f8511223344|556677885f5f5f5f5f	64	plan9	JNE .+1144201745
-480f8611223344|556677885f5f5f5f5f	64	gnu	jbe .+0x44332211
-480f8611223344|556677885f5f5f5f5f	64	intel	jbe .+0x44332211
-480f8611223344|556677885f5f5f5f5f	64	plan9	JBE .+1144201745
-480f8711223344|556677885f5f5f5f5f	64	gnu	ja .+0x44332211
-480f8711223344|556677885f5f5f5f5f	64	intel	jnbe .+0x44332211
-480f8711223344|556677885f5f5f5f5f	64	plan9	JA .+1144201745
-480f8811223344|556677885f5f5f5f5f	64	gnu	js .+0x44332211
-480f8811223344|556677885f5f5f5f5f	64	intel	js .+0x44332211
-480f8811223344|556677885f5f5f5f5f	64	plan9	JS .+1144201745
-480f8911223344|556677885f5f5f5f5f	64	gnu	jns .+0x44332211
-480f8911223344|556677885f5f5f5f5f	64	intel	jns .+0x44332211
-480f8911223344|556677885f5f5f5f5f	64	plan9	JNS .+1144201745
-480f8a11223344|556677885f5f5f5f5f	64	gnu	jp .+0x44332211
-480f8a11223344|556677885f5f5f5f5f	64	intel	jp .+0x44332211
-480f8a11223344|556677885f5f5f5f5f	64	plan9	JP .+1144201745
-480f8b11223344|556677885f5f5f5f5f	64	gnu	jnp .+0x44332211
-480f8b11223344|556677885f5f5f5f5f	64	intel	jnp .+0x44332211
-480f8b11223344|556677885f5f5f5f5f	64	plan9	JNP .+1144201745
-480f8c11223344|556677885f5f5f5f5f	64	gnu	jl .+0x44332211
-480f8c11223344|556677885f5f5f5f5f	64	intel	jl .+0x44332211
-480f8c11223344|556677885f5f5f5f5f	64	plan9	JL .+1144201745
-480f8d11223344|556677885f5f5f5f5f	64	gnu	jge .+0x44332211
-480f8d11223344|556677885f5f5f5f5f	64	intel	jnl .+0x44332211
-480f8d11223344|556677885f5f5f5f5f	64	plan9	JGE .+1144201745
-480f8e11223344|556677885f5f5f5f5f	64	gnu	jle .+0x44332211
-480f8e11223344|556677885f5f5f5f5f	64	intel	jle .+0x44332211
-480f8e11223344|556677885f5f5f5f5f	64	plan9	JLE .+1144201745
-480f8f11223344|556677885f5f5f5f5f	64	gnu	jg .+0x44332211
-480f8f11223344|556677885f5f5f5f5f	64	intel	jnle .+0x44332211
-480f8f11223344|556677885f5f5f5f5f	64	plan9	JG .+1144201745
-480fa1|11223344556677885f5f5f5f5f	64	gnu	popq %fs
-480fa1|11223344556677885f5f5f5f5f	64	intel	pop fs
-480fa1|11223344556677885f5f5f5f5f	64	plan9	POPQ FS
-480fa311|223344556677885f5f5f5f5f	64	gnu	bt %rdx,(%rcx)
-480fa311|223344556677885f5f5f5f5f	64	intel	bt qword ptr [rcx], rdx
-480fa311|223344556677885f5f5f5f5f	64	plan9	BTQ DX, 0(CX)
-480fa41122|3344556677885f5f5f5f5f	64	gnu	shld $0x22,%rdx,(%rcx)
-480fa41122|3344556677885f5f5f5f5f	64	intel	shld qword ptr [rcx], rdx, 0x22
-480fa41122|3344556677885f5f5f5f5f	64	plan9	SHLDQ $0x22, DX, 0(CX)
-480fa511|223344556677885f5f5f5f5f	64	gnu	shld %cl,%rdx,(%rcx)
-480fa511|223344556677885f5f5f5f5f	64	intel	shld qword ptr [rcx], rdx, cl
-480fa511|223344556677885f5f5f5f5f	64	plan9	SHLDQ CL, DX, 0(CX)
-480fa9|11223344556677885f5f5f5f5f	64	gnu	popq %gs
-480fa9|11223344556677885f5f5f5f5f	64	intel	pop gs
-480fa9|11223344556677885f5f5f5f5f	64	plan9	POPQ GS
-480fab11|223344556677885f5f5f5f5f	64	gnu	bts %rdx,(%rcx)
-480fab11|223344556677885f5f5f5f5f	64	intel	bts qword ptr [rcx], rdx
-480fab11|223344556677885f5f5f5f5f	64	plan9	BTSQ DX, 0(CX)
-480fac1122|3344556677885f5f5f5f5f	64	gnu	shrd $0x22,%rdx,(%rcx)
-480fac1122|3344556677885f5f5f5f5f	64	intel	shrd qword ptr [rcx], rdx, 0x22
-480fac1122|3344556677885f5f5f5f5f	64	plan9	SHRDQ $0x22, DX, 0(CX)
-480fad11|223344556677885f5f5f5f5f	64	gnu	shrd %cl,%rdx,(%rcx)
-480fad11|223344556677885f5f5f5f5f	64	intel	shrd qword ptr [rcx], rdx, cl
-480fad11|223344556677885f5f5f5f5f	64	plan9	SHRDQ CL, DX, 0(CX)
-480fae00|11223344556677885f5f5f5f	64	gnu	fxsave64 (%rax)
-480fae00|11223344556677885f5f5f5f	64	intel	fxsave64 ptr [rax]
-480fae00|11223344556677885f5f5f5f	64	plan9	FXSAVE64 0(AX)
-480fae08|11223344556677885f5f5f5f	64	gnu	fxrstor64 (%rax)
-480fae08|11223344556677885f5f5f5f	64	intel	fxrstor64 ptr [rax]
-480fae08|11223344556677885f5f5f5f	64	plan9	FXRSTOR64 0(AX)
-480fae20|11223344556677885f5f5f5f	64	gnu	xsave64 (%rax)
-480fae20|11223344556677885f5f5f5f	64	intel	xsave64 ptr [rax]
-480fae20|11223344556677885f5f5f5f	64	plan9	XSAVE64 0(AX)
-480fae28|11223344556677885f5f5f5f	64	gnu	xrstor64 (%rax)
-480fae28|11223344556677885f5f5f5f	64	intel	xrstor64 ptr [rax]
-480fae28|11223344556677885f5f5f5f	64	plan9	XRSTOR64 0(AX)
-480fae30|11223344556677885f5f5f5f	64	gnu	xsaveopt64 (%rax)
-480fae30|11223344556677885f5f5f5f	64	intel	xsaveopt64 ptr [rax]
-480fae30|11223344556677885f5f5f5f	64	plan9	XSAVEOPT64 0(AX)
-480faf11|223344556677885f5f5f5f5f	64	gnu	imul (%rcx),%rdx
-480faf11|223344556677885f5f5f5f5f	64	intel	imul rdx, qword ptr [rcx]
-480faf11|223344556677885f5f5f5f5f	64	plan9	IMULQ 0(CX), DX
-480fb111|223344556677885f5f5f5f5f	64	gnu	cmpxchg %rdx,(%rcx)
-480fb111|223344556677885f5f5f5f5f	64	intel	cmpxchg qword ptr [rcx], rdx
-480fb111|223344556677885f5f5f5f5f	64	plan9	CMPXCHGQ DX, 0(CX)
-480fb211|223344556677885f5f5f5f5f	64	gnu	lss (%rcx),%rdx
-480fb211|223344556677885f5f5f5f5f	64	intel	lss rdx, ptr [rcx]
-480fb211|223344556677885f5f5f5f5f	64	plan9	LSS 0(CX), DX
-480fb311|223344556677885f5f5f5f5f	64	gnu	btr %rdx,(%rcx)
-480fb311|223344556677885f5f5f5f5f	64	intel	btr qword ptr [rcx], rdx
-480fb311|223344556677885f5f5f5f5f	64	plan9	BTRQ DX, 0(CX)
-480fb411|223344556677885f5f5f5f5f	64	gnu	lfs (%rcx),%rdx
-480fb411|223344556677885f5f5f5f5f	64	intel	lfs rdx, ptr [rcx]
-480fb411|223344556677885f5f5f5f5f	64	plan9	LFS 0(CX), DX
-480fb511|223344556677885f5f5f5f5f	64	gnu	lgs (%rcx),%rdx
-480fb511|223344556677885f5f5f5f5f	64	intel	lgs rdx, ptr [rcx]
-480fb511|223344556677885f5f5f5f5f	64	plan9	LGS 0(CX), DX
-480fb611|223344556677885f5f5f5f5f	64	gnu	movzbq (%rcx),%rdx
-480fb611|223344556677885f5f5f5f5f	64	intel	movzx rdx, byte ptr [rcx]
-480fb611|223344556677885f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
-480fb711|223344556677885f5f5f5f5f	64	gnu	movzwq (%rcx),%rdx
-480fb711|223344556677885f5f5f5f5f	64	intel	movzx rdx, word ptr [rcx]
-480fb711|223344556677885f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
-480fba2011|223344556677885f5f5f5f	64	gnu	btq $0x11,(%rax)
-480fba2011|223344556677885f5f5f5f	64	intel	bt qword ptr [rax], 0x11
-480fba2011|223344556677885f5f5f5f	64	plan9	BTQ $0x11, 0(AX)
-480fba2811|223344556677885f5f5f5f	64	gnu	btsq $0x11,(%rax)
-480fba2811|223344556677885f5f5f5f	64	intel	bts qword ptr [rax], 0x11
-480fba2811|223344556677885f5f5f5f	64	plan9	BTSQ $0x11, 0(AX)
-480fba3011|223344556677885f5f5f5f	64	gnu	btrq $0x11,(%rax)
-480fba3011|223344556677885f5f5f5f	64	intel	btr qword ptr [rax], 0x11
-480fba3011|223344556677885f5f5f5f	64	plan9	BTRQ $0x11, 0(AX)
-480fba3811|223344556677885f5f5f5f	64	gnu	btcq $0x11,(%rax)
-480fba3811|223344556677885f5f5f5f	64	intel	btc qword ptr [rax], 0x11
-480fba3811|223344556677885f5f5f5f	64	plan9	BTCQ $0x11, 0(AX)
-480fbb11|223344556677885f5f5f5f5f	64	gnu	btc %rdx,(%rcx)
-480fbb11|223344556677885f5f5f5f5f	64	intel	btc qword ptr [rcx], rdx
-480fbb11|223344556677885f5f5f5f5f	64	plan9	BTCQ DX, 0(CX)
-480fbc11|223344556677885f5f5f5f5f	64	gnu	bsf (%rcx),%rdx
-480fbc11|223344556677885f5f5f5f5f	64	intel	bsf rdx, qword ptr [rcx]
-480fbc11|223344556677885f5f5f5f5f	64	plan9	BSFQ 0(CX), DX
-480fbd11|223344556677885f5f5f5f5f	64	gnu	bsr (%rcx),%rdx
-480fbd11|223344556677885f5f5f5f5f	64	intel	bsr rdx, qword ptr [rcx]
-480fbd11|223344556677885f5f5f5f5f	64	plan9	BSRQ 0(CX), DX
-480fbe11|223344556677885f5f5f5f5f	64	gnu	movsbq (%rcx),%rdx
-480fbe11|223344556677885f5f5f5f5f	64	intel	movsx rdx, byte ptr [rcx]
-480fbe11|223344556677885f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
-480fbf11|223344556677885f5f5f5f5f	64	gnu	movswq (%rcx),%rdx
-480fbf11|223344556677885f5f5f5f5f	64	intel	movsx rdx, word ptr [rcx]
-480fbf11|223344556677885f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
-480fc111|223344556677885f5f5f5f5f	64	gnu	xadd %rdx,(%rcx)
-480fc111|223344556677885f5f5f5f5f	64	intel	xadd qword ptr [rcx], rdx
-480fc111|223344556677885f5f5f5f5f	64	plan9	XADDQ DX, 0(CX)
-480fc311|223344556677885f5f5f5f5f	64	gnu	movnti %rdx,(%rcx)
-480fc311|223344556677885f5f5f5f5f	64	intel	movnti qword ptr [rcx], rdx
-480fc311|223344556677885f5f5f5f5f	64	plan9	MOVNTIQ DX, 0(CX)
-480fc708|11223344556677885f5f5f5f	64	gnu	cmpxchg16b (%rax)
-480fc708|11223344556677885f5f5f5f	64	intel	cmpxchg16b xmmword ptr [rax]
-480fc708|11223344556677885f5f5f5f	64	plan9	CMPXCHG16B 0(AX)
-480fc718|11223344556677885f5f5f5f	64	gnu	xrstors64 (%rax)
-480fc718|11223344556677885f5f5f5f	64	intel	xrstors64 ptr [rax]
-480fc718|11223344556677885f5f5f5f	64	plan9	XRSTORS64 0(AX)
-480fc720|11223344556677885f5f5f5f	64	gnu	xsavec64 (%rax)
-480fc720|11223344556677885f5f5f5f	64	intel	xsavec64 ptr [rax]
-480fc720|11223344556677885f5f5f5f	64	plan9	XSAVEC64 0(AX)
-480fc728|11223344556677885f5f5f5f	64	gnu	xsaves64 (%rax)
-480fc728|11223344556677885f5f5f5f	64	intel	xsaves64 ptr [rax]
-480fc728|11223344556677885f5f5f5f	64	plan9	XSAVES64 0(AX)
-480fc730|11223344556677885f5f5f5f	64	gnu	rdrand
-480fc730|11223344556677885f5f5f5f	64	intel	rdrand
-480fc730|11223344556677885f5f5f5f	64	plan9	RDRAND
-480fc8|11223344556677885f5f5f5f5f	64	gnu	bswap %rax
-480fc8|11223344556677885f5f5f5f5f	64	intel	bswap rax
-480fc8|11223344556677885f5f5f5f5f	64	plan9	BSWAP AX
-481122|3344556677885f5f5f5f5f5f5f	64	gnu	adc %rsp,(%rdx)
-481122|3344556677885f5f5f5f5f5f5f	64	intel	adc qword ptr [rdx], rsp
-481122|3344556677885f5f5f5f5f5f5f	64	plan9	ADCQ SP, 0(DX)
-481311|223344556677885f5f5f5f5f5f	64	gnu	adc (%rcx),%rdx
-481311|223344556677885f5f5f5f5f5f	64	intel	adc rdx, qword ptr [rcx]
-481311|223344556677885f5f5f5f5f5f	64	plan9	ADCQ 0(CX), DX
-481511223344|556677885f5f5f5f5f5f	64	gnu	adc $0x44332211,%rax
-481511223344|556677885f5f5f5f5f5f	64	intel	adc rax, 0x44332211
-481511223344|556677885f5f5f5f5f5f	64	plan9	ADCQ $0x44332211, AX
-481911|223344556677885f5f5f5f5f5f	64	gnu	sbb %rdx,(%rcx)
-481911|223344556677885f5f5f5f5f5f	64	intel	sbb qword ptr [rcx], rdx
-481911|223344556677885f5f5f5f5f5f	64	plan9	SBBQ DX, 0(CX)
-481b11|223344556677885f5f5f5f5f5f	64	gnu	sbb (%rcx),%rdx
-481b11|223344556677885f5f5f5f5f5f	64	intel	sbb rdx, qword ptr [rcx]
-481b11|223344556677885f5f5f5f5f5f	64	plan9	SBBQ 0(CX), DX
-481d11223344|556677885f5f5f5f5f5f	64	gnu	sbb $0x44332211,%rax
-481d11223344|556677885f5f5f5f5f5f	64	intel	sbb rax, 0x44332211
-481d11223344|556677885f5f5f5f5f5f	64	plan9	SBBQ $0x44332211, AX
-482111|223344556677885f5f5f5f5f5f	64	gnu	and %rdx,(%rcx)
-482111|223344556677885f5f5f5f5f5f	64	intel	and qword ptr [rcx], rdx
-482111|223344556677885f5f5f5f5f5f	64	plan9	ANDQ DX, 0(CX)
-482311|223344556677885f5f5f5f5f5f	64	gnu	and (%rcx),%rdx
-482311|223344556677885f5f5f5f5f5f	64	intel	and rdx, qword ptr [rcx]
-482311|223344556677885f5f5f5f5f5f	64	plan9	ANDQ 0(CX), DX
-482511223344|556677885f5f5f5f5f5f	64	gnu	and $0x44332211,%rax
-482511223344|556677885f5f5f5f5f5f	64	intel	and rax, 0x44332211
-482511223344|556677885f5f5f5f5f5f	64	plan9	ANDQ $0x44332211, AX
-482911|223344556677885f5f5f5f5f5f	64	gnu	sub %rdx,(%rcx)
-482911|223344556677885f5f5f5f5f5f	64	intel	sub qword ptr [rcx], rdx
-482911|223344556677885f5f5f5f5f5f	64	plan9	SUBQ DX, 0(CX)
-482b11|223344556677885f5f5f5f5f5f	64	gnu	sub (%rcx),%rdx
-482b11|223344556677885f5f5f5f5f5f	64	intel	sub rdx, qword ptr [rcx]
-482b11|223344556677885f5f5f5f5f5f	64	plan9	SUBQ 0(CX), DX
-482d11223344|556677885f5f5f5f5f5f	64	gnu	sub $0x44332211,%rax
-482d11223344|556677885f5f5f5f5f5f	64	intel	sub rax, 0x44332211
-482d11223344|556677885f5f5f5f5f5f	64	plan9	SUBQ $0x44332211, AX
-483111|223344556677885f5f5f5f5f5f	64	gnu	xor %rdx,(%rcx)
-483111|223344556677885f5f5f5f5f5f	64	intel	xor qword ptr [rcx], rdx
-483111|223344556677885f5f5f5f5f5f	64	plan9	XORQ DX, 0(CX)
-483311|223344556677885f5f5f5f5f5f	64	gnu	xor (%rcx),%rdx
-483311|223344556677885f5f5f5f5f5f	64	intel	xor rdx, qword ptr [rcx]
-483311|223344556677885f5f5f5f5f5f	64	plan9	XORQ 0(CX), DX
-483511223344|556677885f5f5f5f5f5f	64	gnu	xor $0x44332211,%rax
-483511223344|556677885f5f5f5f5f5f	64	intel	xor rax, 0x44332211
-483511223344|556677885f5f5f5f5f5f	64	plan9	XORQ $0x44332211, AX
-483911|223344556677885f5f5f5f5f5f	64	gnu	cmp %rdx,(%rcx)
-483911|223344556677885f5f5f5f5f5f	64	intel	cmp qword ptr [rcx], rdx
-483911|223344556677885f5f5f5f5f5f	64	plan9	CMPQ DX, 0(CX)
-483b11|223344556677885f5f5f5f5f5f	64	gnu	cmp (%rcx),%rdx
-483b11|223344556677885f5f5f5f5f5f	64	intel	cmp rdx, qword ptr [rcx]
-483b11|223344556677885f5f5f5f5f5f	64	plan9	CMPQ 0(CX), DX
-483d11223344|556677885f5f5f5f5f5f	64	gnu	cmp $0x44332211,%rax
-483d11223344|556677885f5f5f5f5f5f	64	intel	cmp rax, 0x44332211
-483d11223344|556677885f5f5f5f5f5f	64	plan9	CMPQ $0x44332211, AX
-4850|11223344556677885f5f5f5f5f5f	64	gnu	push %rax
-4850|11223344556677885f5f5f5f5f5f	64	intel	push rax
-4850|11223344556677885f5f5f5f5f5f	64	plan9	PUSHQ AX
-4858|11223344556677885f5f5f5f5f5f	64	gnu	pop %rax
-4858|11223344556677885f5f5f5f5f5f	64	intel	pop rax
-4858|11223344556677885f5f5f5f5f5f	64	plan9	POPQ AX
-486311|223344556677885f5f5f5f5f5f	64	gnu	movsxd (%rcx),%rdx
-486311|223344556677885f5f5f5f5f5f	64	intel	movsxd rdx, dword ptr [rcx]
-486311|223344556677885f5f5f5f5f5f	64	plan9	MOVSXD 0(CX), DX
-486811223344|556677885f5f5f5f5f5f	64	gnu	pushq $0x44332211
-486811223344|556677885f5f5f5f5f5f	64	intel	push 0x44332211
-486811223344|556677885f5f5f5f5f5f	64	plan9	PUSHQ $0x44332211
-48691122334455|6677885f5f5f5f5f5f	64	gnu	imul $0x55443322,(%rcx),%rdx
-48691122334455|6677885f5f5f5f5f5f	64	intel	imul rdx, qword ptr [rcx], 0x55443322
-48691122334455|6677885f5f5f5f5f5f	64	plan9	IMULQ $0x55443322, 0(CX), DX
-486b1122|3344556677885f5f5f5f5f5f	64	gnu	imul $0x22,(%rcx),%rdx
-486b1122|3344556677885f5f5f5f5f5f	64	intel	imul rdx, qword ptr [rcx], 0x22
-486b1122|3344556677885f5f5f5f5f5f	64	plan9	IMULQ $0x22, 0(CX), DX
-486d|11223344556677885f5f5f5f5f5f	64	gnu	insl (%dx),%es:(%rdi)
-486d|11223344556677885f5f5f5f5f5f	64	intel	insd
-486d|11223344556677885f5f5f5f5f5f	64	plan9	INSD DX, ES:0(DI)
-486f|11223344556677885f5f5f5f5f5f	64	gnu	outsl %ds:(%rsi),(%dx)
-486f|11223344556677885f5f5f5f5f5f	64	intel	outsd
-486f|11223344556677885f5f5f5f5f5f	64	plan9	OUTSD DS:0(SI), DX
-48810011223344|556677885f5f5f5f5f	64	gnu	addq $0x44332211,(%rax)
-48810011223344|556677885f5f5f5f5f	64	intel	add qword ptr [rax], 0x44332211
-48810011223344|556677885f5f5f5f5f	64	plan9	ADDQ $0x44332211, 0(AX)
-48810811223344|556677885f5f5f5f5f	64	gnu	orq $0x44332211,(%rax)
-48810811223344|556677885f5f5f5f5f	64	intel	or qword ptr [rax], 0x44332211
-48810811223344|556677885f5f5f5f5f	64	plan9	ORQ $0x44332211, 0(AX)
-48811122334455|6677885f5f5f5f5f5f	64	gnu	adcq $0x55443322,(%rcx)
-48811122334455|6677885f5f5f5f5f5f	64	intel	adc qword ptr [rcx], 0x55443322
-48811122334455|6677885f5f5f5f5f5f	64	plan9	ADCQ $0x55443322, 0(CX)
-48811811223344|556677885f5f5f5f5f	64	gnu	sbbq $0x44332211,(%rax)
-48811811223344|556677885f5f5f5f5f	64	intel	sbb qword ptr [rax], 0x44332211
-48811811223344|556677885f5f5f5f5f	64	plan9	SBBQ $0x44332211, 0(AX)
-48812011223344|556677885f5f5f5f5f	64	gnu	andq $0x44332211,(%rax)
-48812011223344|556677885f5f5f5f5f	64	intel	and qword ptr [rax], 0x44332211
-48812011223344|556677885f5f5f5f5f	64	plan9	ANDQ $0x44332211, 0(AX)
-48812811223344|556677885f5f5f5f5f	64	gnu	subq $0x44332211,(%rax)
-48812811223344|556677885f5f5f5f5f	64	intel	sub qword ptr [rax], 0x44332211
-48812811223344|556677885f5f5f5f5f	64	plan9	SUBQ $0x44332211, 0(AX)
-48813011223344|556677885f5f5f5f5f	64	gnu	xorq $0x44332211,(%rax)
-48813011223344|556677885f5f5f5f5f	64	intel	xor qword ptr [rax], 0x44332211
-48813011223344|556677885f5f5f5f5f	64	plan9	XORQ $0x44332211, 0(AX)
-48813811223344|556677885f5f5f5f5f	64	gnu	cmpq $0x44332211,(%rax)
-48813811223344|556677885f5f5f5f5f	64	intel	cmp qword ptr [rax], 0x44332211
-48813811223344|556677885f5f5f5f5f	64	plan9	CMPQ $0x44332211, 0(AX)
-48830011|223344556677885f5f5f5f5f	64	gnu	addq $0x11,(%rax)
-48830011|223344556677885f5f5f5f5f	64	intel	add qword ptr [rax], 0x11
-48830011|223344556677885f5f5f5f5f	64	plan9	ADDQ $0x11, 0(AX)
-48830811|223344556677885f5f5f5f5f	64	gnu	orq $0x11,(%rax)
-48830811|223344556677885f5f5f5f5f	64	intel	or qword ptr [rax], 0x11
-48830811|223344556677885f5f5f5f5f	64	plan9	ORQ $0x11, 0(AX)
-48831122|3344556677885f5f5f5f5f5f	64	gnu	adcq $0x22,(%rcx)
-48831122|3344556677885f5f5f5f5f5f	64	intel	adc qword ptr [rcx], 0x22
-48831122|3344556677885f5f5f5f5f5f	64	plan9	ADCQ $0x22, 0(CX)
-48831811|223344556677885f5f5f5f5f	64	gnu	sbbq $0x11,(%rax)
-48831811|223344556677885f5f5f5f5f	64	intel	sbb qword ptr [rax], 0x11
-48831811|223344556677885f5f5f5f5f	64	plan9	SBBQ $0x11, 0(AX)
-48832011|223344556677885f5f5f5f5f	64	gnu	andq $0x11,(%rax)
-48832011|223344556677885f5f5f5f5f	64	intel	and qword ptr [rax], 0x11
-48832011|223344556677885f5f5f5f5f	64	plan9	ANDQ $0x11, 0(AX)
-48832811|223344556677885f5f5f5f5f	64	gnu	subq $0x11,(%rax)
-48832811|223344556677885f5f5f5f5f	64	intel	sub qword ptr [rax], 0x11
-48832811|223344556677885f5f5f5f5f	64	plan9	SUBQ $0x11, 0(AX)
-48833011|223344556677885f5f5f5f5f	64	gnu	xorq $0x11,(%rax)
-48833011|223344556677885f5f5f5f5f	64	intel	xor qword ptr [rax], 0x11
-48833011|223344556677885f5f5f5f5f	64	plan9	XORQ $0x11, 0(AX)
-48833811|223344556677885f5f5f5f5f	64	gnu	cmpq $0x11,(%rax)
-48833811|223344556677885f5f5f5f5f	64	intel	cmp qword ptr [rax], 0x11
-48833811|223344556677885f5f5f5f5f	64	plan9	CMPQ $0x11, 0(AX)
-488511|223344556677885f5f5f5f5f5f	64	gnu	test %rdx,(%rcx)
-488511|223344556677885f5f5f5f5f5f	64	intel	test qword ptr [rcx], rdx
-488511|223344556677885f5f5f5f5f5f	64	plan9	TESTQ DX, 0(CX)
-488711|223344556677885f5f5f5f5f5f	64	gnu	xchg %rdx,(%rcx)
-488711|223344556677885f5f5f5f5f5f	64	intel	xchg qword ptr [rcx], rdx
-488711|223344556677885f5f5f5f5f5f	64	plan9	XCHGQ DX, 0(CX)
-488911|223344556677885f5f5f5f5f5f	64	gnu	mov %rdx,(%rcx)
-488911|223344556677885f5f5f5f5f5f	64	intel	mov qword ptr [rcx], rdx
-488911|223344556677885f5f5f5f5f5f	64	plan9	MOVQ DX, 0(CX)
-488b11|223344556677885f5f5f5f5f5f	64	gnu	mov (%rcx),%rdx
-488b11|223344556677885f5f5f5f5f5f	64	intel	mov rdx, qword ptr [rcx]
-488b11|223344556677885f5f5f5f5f5f	64	plan9	MOVQ 0(CX), DX
-488c11|223344556677885f5f5f5f5f5f	64	gnu	mov %ss,(%rcx)
-488c11|223344556677885f5f5f5f5f5f	64	intel	mov word ptr [rcx], ss
-488c11|223344556677885f5f5f5f5f5f	64	plan9	MOVQ SS, 0(CX)
-488d11|223344556677885f5f5f5f5f5f	64	gnu	lea (%rcx),%rdx
-488d11|223344556677885f5f5f5f5f5f	64	intel	lea rdx, ptr [rcx]
-488d11|223344556677885f5f5f5f5f5f	64	plan9	LEAQ 0(CX), DX
-488e11|223344556677885f5f5f5f5f5f	64	gnu	mov (%rcx),%ss
-488e11|223344556677885f5f5f5f5f5f	64	intel	mov ss, word ptr [rcx]
-488e11|223344556677885f5f5f5f5f5f	64	plan9	MOVQ 0(CX), SS
-488f00|11223344556677885f5f5f5f5f	64	gnu	popq (%rax)
-488f00|11223344556677885f5f5f5f5f	64	intel	pop qword ptr [rax]
-488f00|11223344556677885f5f5f5f5f	64	plan9	POPQ 0(AX)
-4891|11223344556677885f5f5f5f5f5f	64	gnu	xchg %rax,%rcx
-4891|11223344556677885f5f5f5f5f5f	64	intel	xchg rcx, rax
-4891|11223344556677885f5f5f5f5f5f	64	plan9	XCHGQ AX, CX
-4898|11223344556677885f5f5f5f5f5f	64	gnu	cdqe
-4898|11223344556677885f5f5f5f5f5f	64	intel	cdqe
-4898|11223344556677885f5f5f5f5f5f	64	plan9	CDQE
-4899|11223344556677885f5f5f5f5f5f	64	gnu	cqto
-4899|11223344556677885f5f5f5f5f5f	64	intel	cqo
-4899|11223344556677885f5f5f5f5f5f	64	plan9	CQO
-489c|11223344556677885f5f5f5f5f5f	64	gnu	pushfq
-489c|11223344556677885f5f5f5f5f5f	64	intel	pushfq
-489c|11223344556677885f5f5f5f5f5f	64	plan9	PUSHFQ
-489d|11223344556677885f5f5f5f5f5f	64	gnu	popfq
-489d|11223344556677885f5f5f5f5f5f	64	intel	popfq
-489d|11223344556677885f5f5f5f5f5f	64	plan9	POPFQ
-48a01122334455667788|5f5f5f5f5f5f	64	gnu	mov -0x778899aabbccddef,%al
-48a01122334455667788|5f5f5f5f5f5f	64	intel	mov al, byte ptr [0x8877665544332211]
-48a01122334455667788|5f5f5f5f5f5f	64	plan9	MOVQ -0x778899aabbccddef, AL
-48a11122334455667788|5f5f5f5f5f5f	64	gnu	mov -0x778899aabbccddef,%rax
-48a11122334455667788|5f5f5f5f5f5f	64	intel	mov rax, qword ptr [0x8877665544332211]
-48a11122334455667788|5f5f5f5f5f5f	64	plan9	MOVQ -0x778899aabbccddef, AX
-48a21122334455667788|5f5f5f5f5f5f	64	gnu	mov %al,-0x778899aabbccddef
-48a21122334455667788|5f5f5f5f5f5f	64	intel	mov byte ptr [0x8877665544332211], al
-48a21122334455667788|5f5f5f5f5f5f	64	plan9	MOVQ AL, -0x778899aabbccddef
-48a31122334455667788|5f5f5f5f5f5f	64	gnu	mov %rax,-0x778899aabbccddef
-48a31122334455667788|5f5f5f5f5f5f	64	intel	mov qword ptr [0x8877665544332211], rax
-48a31122334455667788|5f5f5f5f5f5f	64	plan9	MOVQ AX, -0x778899aabbccddef
-48a5|11223344556677885f5f5f5f5f5f	64	gnu	movsq %ds:(%rsi),%es:(%rdi)
-48a5|11223344556677885f5f5f5f5f5f	64	intel	movsq qword ptr [rdi], qword ptr [rsi]
-48a5|11223344556677885f5f5f5f5f5f	64	plan9	MOVSQ DS:0(SI), ES:0(DI)
-48a7|11223344556677885f5f5f5f5f5f	64	gnu	cmpsq %es:(%rdi),%ds:(%rsi)
-48a7|11223344556677885f5f5f5f5f5f	64	intel	cmpsq qword ptr [rsi], qword ptr [rdi]
-48a7|11223344556677885f5f5f5f5f5f	64	plan9	CMPSQ ES:0(DI), DS:0(SI)
-48a911223344|556677885f5f5f5f5f5f	64	gnu	test $0x44332211,%rax
-48a911223344|556677885f5f5f5f5f5f	64	intel	test rax, 0x44332211
-48a911223344|556677885f5f5f5f5f5f	64	plan9	TESTQ $0x44332211, AX
-48ab|11223344556677885f5f5f5f5f5f	64	gnu	stos %rax,%es:(%rdi)
-48ab|11223344556677885f5f5f5f5f5f	64	intel	stosq qword ptr [rdi]
-48ab|11223344556677885f5f5f5f5f5f	64	plan9	STOSQ AX, ES:0(DI)
-48ad|11223344556677885f5f5f5f5f5f	64	gnu	lods %ds:(%rsi),%rax
-48ad|11223344556677885f5f5f5f5f5f	64	intel	lodsq qword ptr [rsi]
-48ad|11223344556677885f5f5f5f5f5f	64	plan9	LODSQ DS:0(SI), AX
-48af|11223344556677885f5f5f5f5f5f	64	gnu	scas %es:(%rdi),%rax
-48af|11223344556677885f5f5f5f5f5f	64	intel	scasq qword ptr [rdi]
-48af|11223344556677885f5f5f5f5f5f	64	plan9	SCASQ ES:0(DI), AX
-48b81122334455667788|5f5f5f5f5f5f	64	gnu	mov $-0x778899aabbccddef,%rax
-48b81122334455667788|5f5f5f5f5f5f	64	intel	mov rax, 0x8877665544332211
-48b81122334455667788|5f5f5f5f5f5f	64	plan9	MOVQ $0x8877665544332211, AX
-48c10011|223344556677885f5f5f5f5f	64	gnu	rolq $0x11,(%rax)
-48c10011|223344556677885f5f5f5f5f	64	intel	rol qword ptr [rax], 0x11
-48c10011|223344556677885f5f5f5f5f	64	plan9	ROLQ $0x11, 0(AX)
-48c10811|223344556677885f5f5f5f5f	64	gnu	rorq $0x11,(%rax)
-48c10811|223344556677885f5f5f5f5f	64	intel	ror qword ptr [rax], 0x11
-48c10811|223344556677885f5f5f5f5f	64	plan9	RORQ $0x11, 0(AX)
-48c11122|3344556677885f5f5f5f5f5f	64	gnu	rclq $0x22,(%rcx)
-48c11122|3344556677885f5f5f5f5f5f	64	intel	rcl qword ptr [rcx], 0x22
-48c11122|3344556677885f5f5f5f5f5f	64	plan9	RCLQ $0x22, 0(CX)
-48c11811|223344556677885f5f5f5f5f	64	gnu	rcrq $0x11,(%rax)
-48c11811|223344556677885f5f5f5f5f	64	intel	rcr qword ptr [rax], 0x11
-48c11811|223344556677885f5f5f5f5f	64	plan9	RCRQ $0x11, 0(AX)
-48c12011|223344556677885f5f5f5f5f	64	gnu	shlq $0x11,(%rax)
-48c12011|223344556677885f5f5f5f5f	64	intel	shl qword ptr [rax], 0x11
-48c12011|223344556677885f5f5f5f5f	64	plan9	SHLQ $0x11, 0(AX)
-48c12811|223344556677885f5f5f5f5f	64	gnu	shrq $0x11,(%rax)
-48c12811|223344556677885f5f5f5f5f	64	intel	shr qword ptr [rax], 0x11
-48c12811|223344556677885f5f5f5f5f	64	plan9	SHRQ $0x11, 0(AX)
-48c13811|223344556677885f5f5f5f5f	64	gnu	sarq $0x11,(%rax)
-48c13811|223344556677885f5f5f5f5f	64	intel	sar qword ptr [rax], 0x11
-48c13811|223344556677885f5f5f5f5f	64	plan9	SARQ $0x11, 0(AX)
-48c70011223344|556677885f5f5f5f5f	64	gnu	movq $0x44332211,(%rax)
-48c70011223344|556677885f5f5f5f5f	64	intel	mov qword ptr [rax], 0x44332211
-48c70011223344|556677885f5f5f5f5f	64	plan9	MOVQ $0x44332211, 0(AX)
-48c7f811223344|556677885f5f5f5f5f	64	gnu	xbeginq .+0x44332211
-48c7f811223344|556677885f5f5f5f5f	64	intel	xbegin .+0x44332211
-48c7f811223344|556677885f5f5f5f5f	64	plan9	XBEGIN .+1144201745
-48c9|11223344556677885f5f5f5f5f5f	64	gnu	leaveq
-48c9|11223344556677885f5f5f5f5f5f	64	intel	leave
-48c9|11223344556677885f5f5f5f5f5f	64	plan9	LEAVE
-48cf|11223344556677885f5f5f5f5f5f	64	gnu	iretq
-48cf|11223344556677885f5f5f5f5f5f	64	intel	iretq
-48cf|11223344556677885f5f5f5f5f5f	64	plan9	IRETQ
-48d100|11223344556677885f5f5f5f5f	64	gnu	rolq (%rax)
-48d100|11223344556677885f5f5f5f5f	64	intel	rol qword ptr [rax], 0x1
-48d100|11223344556677885f5f5f5f5f	64	plan9	ROLQ $0x1, 0(AX)
-48d108|11223344556677885f5f5f5f5f	64	gnu	rorq (%rax)
-48d108|11223344556677885f5f5f5f5f	64	intel	ror qword ptr [rax], 0x1
-48d108|11223344556677885f5f5f5f5f	64	plan9	RORQ $0x1, 0(AX)
-48d111|223344556677885f5f5f5f5f5f	64	gnu	rclq (%rcx)
-48d111|223344556677885f5f5f5f5f5f	64	intel	rcl qword ptr [rcx], 0x1
-48d111|223344556677885f5f5f5f5f5f	64	plan9	RCLQ $0x1, 0(CX)
-48d118|11223344556677885f5f5f5f5f	64	gnu	rcrq (%rax)
-48d118|11223344556677885f5f5f5f5f	64	intel	rcr qword ptr [rax], 0x1
-48d118|11223344556677885f5f5f5f5f	64	plan9	RCRQ $0x1, 0(AX)
-48d120|11223344556677885f5f5f5f5f	64	gnu	shlq (%rax)
-48d120|11223344556677885f5f5f5f5f	64	intel	shl qword ptr [rax], 0x1
-48d120|11223344556677885f5f5f5f5f	64	plan9	SHLQ $0x1, 0(AX)
-48d128|11223344556677885f5f5f5f5f	64	gnu	shrq (%rax)
-48d128|11223344556677885f5f5f5f5f	64	intel	shr qword ptr [rax], 0x1
-48d128|11223344556677885f5f5f5f5f	64	plan9	SHRQ $0x1, 0(AX)
-48d138|11223344556677885f5f5f5f5f	64	gnu	sarq (%rax)
-48d138|11223344556677885f5f5f5f5f	64	intel	sar qword ptr [rax], 0x1
-48d138|11223344556677885f5f5f5f5f	64	plan9	SARQ $0x1, 0(AX)
-48d300|11223344556677885f5f5f5f5f	64	gnu	rolq %cl,(%rax)
-48d300|11223344556677885f5f5f5f5f	64	intel	rol qword ptr [rax], cl
-48d300|11223344556677885f5f5f5f5f	64	plan9	ROLQ CL, 0(AX)
-48d308|11223344556677885f5f5f5f5f	64	gnu	rorq %cl,(%rax)
-48d308|11223344556677885f5f5f5f5f	64	intel	ror qword ptr [rax], cl
-48d308|11223344556677885f5f5f5f5f	64	plan9	RORQ CL, 0(AX)
-48d311|223344556677885f5f5f5f5f5f	64	gnu	rclq %cl,(%rcx)
-48d311|223344556677885f5f5f5f5f5f	64	intel	rcl qword ptr [rcx], cl
-48d311|223344556677885f5f5f5f5f5f	64	plan9	RCLQ CL, 0(CX)
-48d318|11223344556677885f5f5f5f5f	64	gnu	rcrq %cl,(%rax)
-48d318|11223344556677885f5f5f5f5f	64	intel	rcr qword ptr [rax], cl
-48d318|11223344556677885f5f5f5f5f	64	plan9	RCRQ CL, 0(AX)
-48d320|11223344556677885f5f5f5f5f	64	gnu	shlq %cl,(%rax)
-48d320|11223344556677885f5f5f5f5f	64	intel	shl qword ptr [rax], cl
-48d320|11223344556677885f5f5f5f5f	64	plan9	SHLQ CL, 0(AX)
-48d328|11223344556677885f5f5f5f5f	64	gnu	shrq %cl,(%rax)
-48d328|11223344556677885f5f5f5f5f	64	intel	shr qword ptr [rax], cl
-48d328|11223344556677885f5f5f5f5f	64	plan9	SHRQ CL, 0(AX)
-48d338|11223344556677885f5f5f5f5f	64	gnu	sarq %cl,(%rax)
-48d338|11223344556677885f5f5f5f5f	64	intel	sar qword ptr [rax], cl
-48d338|11223344556677885f5f5f5f5f	64	plan9	SARQ CL, 0(AX)
-48d7|11223344556677885f5f5f5f5f5f	64	gnu	xlat %ds:(%rbx)
-48d7|11223344556677885f5f5f5f5f5f	64	intel	xlat
-48d7|11223344556677885f5f5f5f5f5f	64	plan9	XLATB DS:0(BX)
-48e511|223344556677885f5f5f5f5f5f	64	gnu	in $0x11,%eax
-48e511|223344556677885f5f5f5f5f5f	64	intel	in eax, 0x11
-48e511|223344556677885f5f5f5f5f5f	64	plan9	INQ $0x11, AX
-48e711|223344556677885f5f5f5f5f5f	64	gnu	out %eax,$0x11
-48e711|223344556677885f5f5f5f5f5f	64	intel	out 0x11, eax
-48e711|223344556677885f5f5f5f5f5f	64	plan9	OUTQ AX, $0x11
-48e811223344|556677885f5f5f5f5f5f	64	gnu	callq .+0x44332211
-48e811223344|556677885f5f5f5f5f5f	64	intel	call .+0x44332211
-48e811223344|556677885f5f5f5f5f5f	64	plan9	CALL .+1144201745
-48e911223344|556677885f5f5f5f5f5f	64	gnu	jmpq .+0x44332211
-48e911223344|556677885f5f5f5f5f5f	64	intel	jmp .+0x44332211
-48e911223344|556677885f5f5f5f5f5f	64	plan9	JMP .+1144201745
-48ed|11223344556677885f5f5f5f5f5f	64	gnu	in (%dx),%eax
-48ed|11223344556677885f5f5f5f5f5f	64	intel	in eax, dx
-48ed|11223344556677885f5f5f5f5f5f	64	plan9	INQ DX, AX
-48ef|11223344556677885f5f5f5f5f5f	64	gnu	out %eax,(%dx)
-48ef|11223344556677885f5f5f5f5f5f	64	intel	out dx, eax
-48ef|11223344556677885f5f5f5f5f5f	64	plan9	OUTQ AX, DX
-48f70011223344|556677885f5f5f5f5f	64	gnu	testq $0x44332211,(%rax)
-48f70011223344|556677885f5f5f5f5f	64	intel	test qword ptr [rax], 0x44332211
-48f70011223344|556677885f5f5f5f5f	64	plan9	TESTQ $0x44332211, 0(AX)
-48f711|223344556677885f5f5f5f5f5f	64	gnu	notq (%rcx)
-48f711|223344556677885f5f5f5f5f5f	64	intel	not qword ptr [rcx]
-48f711|223344556677885f5f5f5f5f5f	64	plan9	NOTQ 0(CX)
-48f718|11223344556677885f5f5f5f5f	64	gnu	negq (%rax)
-48f718|11223344556677885f5f5f5f5f	64	intel	neg qword ptr [rax]
-48f718|11223344556677885f5f5f5f5f	64	plan9	NEGQ 0(AX)
-48f720|11223344556677885f5f5f5f5f	64	gnu	mulq (%rax)
-48f720|11223344556677885f5f5f5f5f	64	intel	mul qword ptr [rax]
-48f720|11223344556677885f5f5f5f5f	64	plan9	MULQ 0(AX)
-48f728|11223344556677885f5f5f5f5f	64	gnu	imulq (%rax)
-48f728|11223344556677885f5f5f5f5f	64	intel	imul qword ptr [rax]
-48f728|11223344556677885f5f5f5f5f	64	plan9	IMULQ 0(AX)
-48f730|11223344556677885f5f5f5f5f	64	gnu	divq (%rax)
-48f730|11223344556677885f5f5f5f5f	64	intel	div qword ptr [rax]
-48f730|11223344556677885f5f5f5f5f	64	plan9	DIVQ 0(AX)
-48f738|11223344556677885f5f5f5f5f	64	gnu	idivq (%rax)
-48f738|11223344556677885f5f5f5f5f	64	intel	idiv qword ptr [rax]
-48f738|11223344556677885f5f5f5f5f	64	plan9	IDIVQ 0(AX)
-48ff00|11223344556677885f5f5f5f5f	64	gnu	incq (%rax)
-48ff00|11223344556677885f5f5f5f5f	64	intel	inc qword ptr [rax]
-48ff00|11223344556677885f5f5f5f5f	64	plan9	INCQ 0(AX)
-48ff08|11223344556677885f5f5f5f5f	64	gnu	decq (%rax)
-48ff08|11223344556677885f5f5f5f5f	64	intel	dec qword ptr [rax]
-48ff08|11223344556677885f5f5f5f5f	64	plan9	DECQ 0(AX)
-48ff18|11223344556677885f5f5f5f5f	64	gnu	lcallq *(%rax)
-48ff18|11223344556677885f5f5f5f5f	64	intel	call far ptr [rax]
-48ff18|11223344556677885f5f5f5f5f	64	plan9	LCALL 0(AX)
-48ff28|11223344556677885f5f5f5f5f	64	gnu	ljmpq *(%rax)
-48ff28|11223344556677885f5f5f5f5f	64	intel	jmp far ptr [rax]
-48ff28|11223344556677885f5f5f5f5f	64	plan9	LJMP 0(AX)
-48ff30|11223344556677885f5f5f5f5f	64	gnu	pushq (%rax)
-48ff30|11223344556677885f5f5f5f5f	64	intel	push qword ptr [rax]
-48ff30|11223344556677885f5f5f5f5f	64	plan9	PUSHQ 0(AX)
-48|010011223344556677885f5f5f5f5f	32	intel	dec eax
-48|010011223344556677885f5f5f5f5f	32	plan9	DECL AX
-50|11223344556677885f5f5f5f5f5f5f	32	intel	push eax
-50|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL AX
-50|11223344556677885f5f5f5f5f5f5f	64	gnu	push %rax
-50|11223344556677885f5f5f5f5f5f5f	64	intel	push rax
-50|11223344556677885f5f5f5f5f5f5f	64	plan9	PUSHL AX
-58|11223344556677885f5f5f5f5f5f5f	32	intel	pop eax
-58|11223344556677885f5f5f5f5f5f5f	32	plan9	POPL AX
-58|11223344556677885f5f5f5f5f5f5f	64	gnu	pop %rax
-58|11223344556677885f5f5f5f5f5f5f	64	intel	pop rax
-58|11223344556677885f5f5f5f5f5f5f	64	plan9	POPL AX
-60|11223344556677885f5f5f5f5f5f5f	32	intel	pushad
-60|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHAD
-60|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-60|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-60|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-61|11223344556677885f5f5f5f5f5f5f	32	intel	popad
-61|11223344556677885f5f5f5f5f5f5f	32	plan9	POPAD
-61|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-61|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-61|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-6211|223344556677885f5f5f5f5f5f5f	32	intel	bound edx, qword ptr [ecx]
-6211|223344556677885f5f5f5f5f5f5f	32	plan9	BOUND 0(CX), DX
-62|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-62|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-62|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-6311|223344556677885f5f5f5f5f5f5f	32	intel	arpl word ptr [ecx], dx
-6311|223344556677885f5f5f5f5f5f5f	32	plan9	ARPL DX, 0(CX)
-6311|223344556677885f5f5f5f5f5f5f	64	gnu	movsxd (%rcx),%edx
-6311|223344556677885f5f5f5f5f5f5f	64	intel	movsxd edx, dword ptr [rcx]
-6311|223344556677885f5f5f5f5f5f5f	64	plan9	MOVSXD 0(CX), DX
-660111|223344556677885f5f5f5f5f5f	32	intel	add word ptr [ecx], dx
-660111|223344556677885f5f5f5f5f5f	32	plan9	ADDW DX, 0(CX)
-660111|223344556677885f5f5f5f5f5f	64	gnu	add %dx,(%rcx)
-660111|223344556677885f5f5f5f5f5f	64	intel	add word ptr [rcx], dx
-660111|223344556677885f5f5f5f5f5f	64	plan9	ADDW DX, 0(CX)
-660311|223344556677885f5f5f5f5f5f	32	intel	add dx, word ptr [ecx]
-660311|223344556677885f5f5f5f5f5f	32	plan9	ADDW 0(CX), DX
-660311|223344556677885f5f5f5f5f5f	64	gnu	add (%rcx),%dx
-660311|223344556677885f5f5f5f5f5f	64	intel	add dx, word ptr [rcx]
-660311|223344556677885f5f5f5f5f5f	64	plan9	ADDW 0(CX), DX
-66051122|3344556677885f5f5f5f5f5f	32	intel	add ax, 0x2211
-66051122|3344556677885f5f5f5f5f5f	32	plan9	ADDW $0x2211, AX
-66051122|3344556677885f5f5f5f5f5f	64	gnu	add $0x2211,%ax
-66051122|3344556677885f5f5f5f5f5f	64	intel	add ax, 0x2211
-66051122|3344556677885f5f5f5f5f5f	64	plan9	ADDW $0x2211, AX
-660911|223344556677885f5f5f5f5f5f	32	intel	or word ptr [ecx], dx
-660911|223344556677885f5f5f5f5f5f	32	plan9	ORW DX, 0(CX)
-660911|223344556677885f5f5f5f5f5f	64	gnu	or %dx,(%rcx)
-660911|223344556677885f5f5f5f5f5f	64	intel	or word ptr [rcx], dx
-660911|223344556677885f5f5f5f5f5f	64	plan9	ORW DX, 0(CX)
-660b11|223344556677885f5f5f5f5f5f	32	intel	or dx, word ptr [ecx]
-660b11|223344556677885f5f5f5f5f5f	32	plan9	ORW 0(CX), DX
-660b11|223344556677885f5f5f5f5f5f	64	gnu	or (%rcx),%dx
-660b11|223344556677885f5f5f5f5f5f	64	intel	or dx, word ptr [rcx]
-660b11|223344556677885f5f5f5f5f5f	64	plan9	ORW 0(CX), DX
-660d1122|3344556677885f5f5f5f5f5f	32	intel	or ax, 0x2211
-660d1122|3344556677885f5f5f5f5f5f	32	plan9	ORW $0x2211, AX
-660d1122|3344556677885f5f5f5f5f5f	64	gnu	or $0x2211,%ax
-660d1122|3344556677885f5f5f5f5f5f	64	intel	or ax, 0x2211
-660d1122|3344556677885f5f5f5f5f5f	64	plan9	ORW $0x2211, AX
-660f0000|11223344556677885f5f5f5f	32	intel	sldt word ptr [eax]
-660f0000|11223344556677885f5f5f5f	32	plan9	SLDT 0(AX)
-660f0000|11223344556677885f5f5f5f	64	gnu	data16 sldt (%rax)
-660f0000|11223344556677885f5f5f5f	64	intel	sldt word ptr [rax]
-660f0000|11223344556677885f5f5f5f	64	plan9	SLDT 0(AX)
-660f0008|11223344556677885f5f5f5f	32	intel	str word ptr [eax]
-660f0008|11223344556677885f5f5f5f	32	plan9	STR 0(AX)
-660f0008|11223344556677885f5f5f5f	64	gnu	data16 str (%rax)
-660f0008|11223344556677885f5f5f5f	64	intel	str word ptr [rax]
-660f0008|11223344556677885f5f5f5f	64	plan9	STR 0(AX)
-660f01a611223344|556677885f5f5f5f	32	intel	smsw word ptr [esi+0x44332211]
-660f01a611223344|556677885f5f5f5f	32	plan9	SMSW 0x44332211(SI)
-660f01a611223344|556677885f5f5f5f	64	gnu	data16 smsw 0x44332211(%rsi)
-660f01a611223344|556677885f5f5f5f	64	intel	smsw word ptr [rsi+0x44332211]
-660f01a611223344|556677885f5f5f5f	64	plan9	SMSW 0x44332211(SI)
-660f0211|223344556677885f5f5f5f5f	32	intel	lar dx, word ptr [ecx]
-660f0211|223344556677885f5f5f5f5f	32	plan9	LAR 0(CX), DX
-660f0211|223344556677885f5f5f5f5f	64	gnu	lar (%rcx),%dx
-660f0211|223344556677885f5f5f5f5f	64	intel	lar dx, word ptr [rcx]
-660f0211|223344556677885f5f5f5f5f	64	plan9	LAR 0(CX), DX
-660f0311|223344556677885f5f5f5f5f	32	intel	lsl dx, word ptr [ecx]
-660f0311|223344556677885f5f5f5f5f	32	plan9	LSL 0(CX), DX
-660f0311|223344556677885f5f5f5f5f	64	gnu	lsl (%rcx),%dx
-660f0311|223344556677885f5f5f5f5f	64	intel	lsl dx, word ptr [rcx]
-660f0311|223344556677885f5f5f5f5f	64	plan9	LSL 0(CX), DX
-660f1011|223344556677885f5f5f5f5f	32	intel	movupd xmm2, xmmword ptr [ecx]
-660f1011|223344556677885f5f5f5f5f	32	plan9	MOVUPD 0(CX), X2
-660f1011|223344556677885f5f5f5f5f	64	gnu	movupd (%rcx),%xmm2
-660f1011|223344556677885f5f5f5f5f	64	intel	movupd xmm2, xmmword ptr [rcx]
-660f1011|223344556677885f5f5f5f5f	64	plan9	MOVUPD 0(CX), X2
-660f1122|3344556677885f5f5f5f5f5f	32	intel	movupd xmmword ptr [edx], xmm4
-660f1122|3344556677885f5f5f5f5f5f	32	plan9	MOVUPD X4, 0(DX)
-660f1122|3344556677885f5f5f5f5f5f	64	gnu	movupd %xmm4,(%rdx)
-660f1122|3344556677885f5f5f5f5f5f	64	intel	movupd xmmword ptr [rdx], xmm4
-660f1122|3344556677885f5f5f5f5f5f	64	plan9	MOVUPD X4, 0(DX)
-660f1211|223344556677885f5f5f5f5f	32	intel	movlpd xmm2, qword ptr [ecx]
-660f1211|223344556677885f5f5f5f5f	32	plan9	MOVLPD 0(CX), X2
-660f1211|223344556677885f5f5f5f5f	64	gnu	movlpd (%rcx),%xmm2
-660f1211|223344556677885f5f5f5f5f	64	intel	movlpd xmm2, qword ptr [rcx]
-660f1211|223344556677885f5f5f5f5f	64	plan9	MOVLPD 0(CX), X2
-660f1311|223344556677885f5f5f5f5f	32	intel	movlpd qword ptr [ecx], xmm2
-660f1311|223344556677885f5f5f5f5f	32	plan9	MOVLPD X2, 0(CX)
-660f1311|223344556677885f5f5f5f5f	64	gnu	movlpd %xmm2,(%rcx)
-660f1311|223344556677885f5f5f5f5f	64	intel	movlpd qword ptr [rcx], xmm2
-660f1311|223344556677885f5f5f5f5f	64	plan9	MOVLPD X2, 0(CX)
-660f1411|223344556677885f5f5f5f5f	32	intel	unpcklpd xmm2, xmmword ptr [ecx]
-660f1411|223344556677885f5f5f5f5f	32	plan9	UNPCKLPD 0(CX), X2
-660f1411|223344556677885f5f5f5f5f	64	gnu	unpcklpd (%rcx),%xmm2
-660f1411|223344556677885f5f5f5f5f	64	intel	unpcklpd xmm2, xmmword ptr [rcx]
-660f1411|223344556677885f5f5f5f5f	64	plan9	UNPCKLPD 0(CX), X2
-660f1511|223344556677885f5f5f5f5f	32	intel	unpckhpd xmm2, xmmword ptr [ecx]
-660f1511|223344556677885f5f5f5f5f	32	plan9	UNPCKHPD 0(CX), X2
-660f1511|223344556677885f5f5f5f5f	64	gnu	unpckhpd (%rcx),%xmm2
-660f1511|223344556677885f5f5f5f5f	64	intel	unpckhpd xmm2, xmmword ptr [rcx]
-660f1511|223344556677885f5f5f5f5f	64	plan9	UNPCKHPD 0(CX), X2
-660f1611|223344556677885f5f5f5f5f	32	intel	movhpd xmm2, qword ptr [ecx]
-660f1611|223344556677885f5f5f5f5f	32	plan9	MOVHPD 0(CX), X2
-660f1611|223344556677885f5f5f5f5f	64	gnu	movhpd (%rcx),%xmm2
-660f1611|223344556677885f5f5f5f5f	64	intel	movhpd xmm2, qword ptr [rcx]
-660f1611|223344556677885f5f5f5f5f	64	plan9	MOVHPD 0(CX), X2
-660f1711|223344556677885f5f5f5f5f	32	intel	movhpd qword ptr [ecx], xmm2
-660f1711|223344556677885f5f5f5f5f	32	plan9	MOVHPD X2, 0(CX)
-660f1711|223344556677885f5f5f5f5f	64	gnu	movhpd %xmm2,(%rcx)
-660f1711|223344556677885f5f5f5f5f	64	intel	movhpd qword ptr [rcx], xmm2
-660f1711|223344556677885f5f5f5f5f	64	plan9	MOVHPD X2, 0(CX)
-660f1f00|11223344556677885f5f5f5f	32	intel	nop word ptr [eax], ax
-660f1f00|11223344556677885f5f5f5f	32	plan9	NOPW 0(AX)
-660f1f00|11223344556677885f5f5f5f	64	gnu	nopw (%rax)
-660f1f00|11223344556677885f5f5f5f	64	intel	nop word ptr [rax], ax
-660f1f00|11223344556677885f5f5f5f	64	plan9	NOPW 0(AX)
-660f2811|223344556677885f5f5f5f5f	32	intel	movapd xmm2, xmmword ptr [ecx]
-660f2811|223344556677885f5f5f5f5f	32	plan9	MOVAPD 0(CX), X2
-660f2811|223344556677885f5f5f5f5f	64	gnu	movapd (%rcx),%xmm2
-660f2811|223344556677885f5f5f5f5f	64	intel	movapd xmm2, xmmword ptr [rcx]
-660f2811|223344556677885f5f5f5f5f	64	plan9	MOVAPD 0(CX), X2
-660f2911|223344556677885f5f5f5f5f	32	intel	movapd xmmword ptr [ecx], xmm2
-660f2911|223344556677885f5f5f5f5f	32	plan9	MOVAPD X2, 0(CX)
-660f2911|223344556677885f5f5f5f5f	64	gnu	movapd %xmm2,(%rcx)
-660f2911|223344556677885f5f5f5f5f	64	intel	movapd xmmword ptr [rcx], xmm2
-660f2911|223344556677885f5f5f5f5f	64	plan9	MOVAPD X2, 0(CX)
-660f2a11|223344556677885f5f5f5f5f	32	intel	cvtpi2pd xmm2, qword ptr [ecx]
-660f2a11|223344556677885f5f5f5f5f	32	plan9	CVTPI2PD 0(CX), X2
-660f2a11|223344556677885f5f5f5f5f	64	gnu	cvtpi2pd (%rcx),%xmm2
-660f2a11|223344556677885f5f5f5f5f	64	intel	cvtpi2pd xmm2, qword ptr [rcx]
-660f2a11|223344556677885f5f5f5f5f	64	plan9	CVTPI2PD 0(CX), X2
-660f2b11|223344556677885f5f5f5f5f	32	intel	movntpd xmmword ptr [ecx], xmm2
-660f2b11|223344556677885f5f5f5f5f	32	plan9	MOVNTPD X2, 0(CX)
-660f2b11|223344556677885f5f5f5f5f	64	gnu	movntpd %xmm2,(%rcx)
-660f2b11|223344556677885f5f5f5f5f	64	intel	movntpd xmmword ptr [rcx], xmm2
-660f2b11|223344556677885f5f5f5f5f	64	plan9	MOVNTPD X2, 0(CX)
-660f2c11|223344556677885f5f5f5f5f	32	intel	cvttpd2pi mmx2, xmmword ptr [ecx]
-660f2c11|223344556677885f5f5f5f5f	32	plan9	CVTTPD2PI 0(CX), M2
-660f2c11|223344556677885f5f5f5f5f	64	gnu	cvttpd2pi (%rcx),%mm2
-660f2c11|223344556677885f5f5f5f5f	64	intel	cvttpd2pi mmx2, xmmword ptr [rcx]
-660f2c11|223344556677885f5f5f5f5f	64	plan9	CVTTPD2PI 0(CX), M2
-660f2d11|223344556677885f5f5f5f5f	32	intel	cvtpd2pi mmx2, xmmword ptr [ecx]
-660f2d11|223344556677885f5f5f5f5f	32	plan9	CVTPD2PI 0(CX), M2
-660f2d11|223344556677885f5f5f5f5f	64	gnu	cvtpd2pi (%rcx),%mm2
-660f2d11|223344556677885f5f5f5f5f	64	intel	cvtpd2pi mmx2, xmmword ptr [rcx]
-660f2d11|223344556677885f5f5f5f5f	64	plan9	CVTPD2PI 0(CX), M2
-660f2e11|223344556677885f5f5f5f5f	32	intel	ucomisd xmm2, qword ptr [ecx]
-660f2e11|223344556677885f5f5f5f5f	32	plan9	UCOMISD 0(CX), X2
-660f2e11|223344556677885f5f5f5f5f	64	gnu	ucomisd (%rcx),%xmm2
-660f2e11|223344556677885f5f5f5f5f	64	intel	ucomisd xmm2, qword ptr [rcx]
-660f2e11|223344556677885f5f5f5f5f	64	plan9	UCOMISD 0(CX), X2
-660f2f11|223344556677885f5f5f5f5f	32	intel	comisd xmm2, qword ptr [ecx]
-660f2f11|223344556677885f5f5f5f5f	32	plan9	COMISD 0(CX), X2
-660f2f11|223344556677885f5f5f5f5f	64	gnu	comisd (%rcx),%xmm2
-660f2f11|223344556677885f5f5f5f5f	64	intel	comisd xmm2, qword ptr [rcx]
-660f2f11|223344556677885f5f5f5f5f	64	plan9	COMISD 0(CX), X2
-660f380011|223344556677885f5f5f5f	32	intel	pshufb xmm2, xmmword ptr [ecx]
-660f380011|223344556677885f5f5f5f	32	plan9	PSHUFB 0(CX), X2
-660f380011|223344556677885f5f5f5f	64	gnu	pshufb (%rcx),%xmm2
-660f380011|223344556677885f5f5f5f	64	intel	pshufb xmm2, xmmword ptr [rcx]
-660f380011|223344556677885f5f5f5f	64	plan9	PSHUFB 0(CX), X2
-660f380111|223344556677885f5f5f5f	32	intel	phaddw xmm2, xmmword ptr [ecx]
-660f380111|223344556677885f5f5f5f	32	plan9	PHADDW 0(CX), X2
-660f380111|223344556677885f5f5f5f	64	gnu	phaddw (%rcx),%xmm2
-660f380111|223344556677885f5f5f5f	64	intel	phaddw xmm2, xmmword ptr [rcx]
-660f380111|223344556677885f5f5f5f	64	plan9	PHADDW 0(CX), X2
-660f380211|223344556677885f5f5f5f	32	intel	phaddd xmm2, xmmword ptr [ecx]
-660f380211|223344556677885f5f5f5f	32	plan9	PHADDD 0(CX), X2
-660f380211|223344556677885f5f5f5f	64	gnu	phaddd (%rcx),%xmm2
-660f380211|223344556677885f5f5f5f	64	intel	phaddd xmm2, xmmword ptr [rcx]
-660f380211|223344556677885f5f5f5f	64	plan9	PHADDD 0(CX), X2
-660f380311|223344556677885f5f5f5f	32	intel	phaddsw xmm2, xmmword ptr [ecx]
-660f380311|223344556677885f5f5f5f	32	plan9	PHADDSW 0(CX), X2
-660f380311|223344556677885f5f5f5f	64	gnu	phaddsw (%rcx),%xmm2
-660f380311|223344556677885f5f5f5f	64	intel	phaddsw xmm2, xmmword ptr [rcx]
-660f380311|223344556677885f5f5f5f	64	plan9	PHADDSW 0(CX), X2
-660f380411|223344556677885f5f5f5f	32	intel	pmaddubsw xmm2, xmmword ptr [ecx]
-660f380411|223344556677885f5f5f5f	32	plan9	PMADDUBSW 0(CX), X2
-660f380411|223344556677885f5f5f5f	64	gnu	pmaddubsw (%rcx),%xmm2
-660f380411|223344556677885f5f5f5f	64	intel	pmaddubsw xmm2, xmmword ptr [rcx]
-660f380411|223344556677885f5f5f5f	64	plan9	PMADDUBSW 0(CX), X2
-660f380511|223344556677885f5f5f5f	32	intel	phsubw xmm2, xmmword ptr [ecx]
-660f380511|223344556677885f5f5f5f	32	plan9	PHSUBW 0(CX), X2
-660f380511|223344556677885f5f5f5f	64	gnu	phsubw (%rcx),%xmm2
-660f380511|223344556677885f5f5f5f	64	intel	phsubw xmm2, xmmword ptr [rcx]
-660f380511|223344556677885f5f5f5f	64	plan9	PHSUBW 0(CX), X2
-660f380611|223344556677885f5f5f5f	32	intel	phsubd xmm2, xmmword ptr [ecx]
-660f380611|223344556677885f5f5f5f	32	plan9	PHSUBD 0(CX), X2
-660f380611|223344556677885f5f5f5f	64	gnu	phsubd (%rcx),%xmm2
-660f380611|223344556677885f5f5f5f	64	intel	phsubd xmm2, xmmword ptr [rcx]
-660f380611|223344556677885f5f5f5f	64	plan9	PHSUBD 0(CX), X2
-660f380711|223344556677885f5f5f5f	32	intel	phsubsw xmm2, xmmword ptr [ecx]
-660f380711|223344556677885f5f5f5f	32	plan9	PHSUBSW 0(CX), X2
-660f380711|223344556677885f5f5f5f	64	gnu	phsubsw (%rcx),%xmm2
-660f380711|223344556677885f5f5f5f	64	intel	phsubsw xmm2, xmmword ptr [rcx]
-660f380711|223344556677885f5f5f5f	64	plan9	PHSUBSW 0(CX), X2
-660f380811|223344556677885f5f5f5f	32	intel	psignb xmm2, xmmword ptr [ecx]
-660f380811|223344556677885f5f5f5f	32	plan9	PSIGNB 0(CX), X2
-660f380811|223344556677885f5f5f5f	64	gnu	psignb (%rcx),%xmm2
-660f380811|223344556677885f5f5f5f	64	intel	psignb xmm2, xmmword ptr [rcx]
-660f380811|223344556677885f5f5f5f	64	plan9	PSIGNB 0(CX), X2
-660f380911|223344556677885f5f5f5f	32	intel	psignw xmm2, xmmword ptr [ecx]
-660f380911|223344556677885f5f5f5f	32	plan9	PSIGNW 0(CX), X2
-660f380911|223344556677885f5f5f5f	64	gnu	psignw (%rcx),%xmm2
-660f380911|223344556677885f5f5f5f	64	intel	psignw xmm2, xmmword ptr [rcx]
-660f380911|223344556677885f5f5f5f	64	plan9	PSIGNW 0(CX), X2
-660f380a11|223344556677885f5f5f5f	32	intel	psignd xmm2, xmmword ptr [ecx]
-660f380a11|223344556677885f5f5f5f	32	plan9	PSIGND 0(CX), X2
-660f380a11|223344556677885f5f5f5f	64	gnu	psignd (%rcx),%xmm2
-660f380a11|223344556677885f5f5f5f	64	intel	psignd xmm2, xmmword ptr [rcx]
-660f380a11|223344556677885f5f5f5f	64	plan9	PSIGND 0(CX), X2
-660f380b11|223344556677885f5f5f5f	32	intel	pmulhrsw xmm2, xmmword ptr [ecx]
-660f380b11|223344556677885f5f5f5f	32	plan9	PMULHRSW 0(CX), X2
-660f380b11|223344556677885f5f5f5f	64	gnu	pmulhrsw (%rcx),%xmm2
-660f380b11|223344556677885f5f5f5f	64	intel	pmulhrsw xmm2, xmmword ptr [rcx]
-660f380b11|223344556677885f5f5f5f	64	plan9	PMULHRSW 0(CX), X2
-660f381011|223344556677885f5f5f5f	32	intel	pblendvb xmm2, xmmword ptr [ecx]
-660f381011|223344556677885f5f5f5f	32	plan9	PBLENDVB X0, 0(CX), X2
-660f381011|223344556677885f5f5f5f	64	gnu	pblendvb %xmm0,(%rcx),%xmm2
-660f381011|223344556677885f5f5f5f	64	intel	pblendvb xmm2, xmmword ptr [rcx]
-660f381011|223344556677885f5f5f5f	64	plan9	PBLENDVB X0, 0(CX), X2
-660f381411|223344556677885f5f5f5f	32	intel	blendvps xmm2, xmmword ptr [ecx]
-660f381411|223344556677885f5f5f5f	32	plan9	BLENDVPS X0, 0(CX), X2
-660f381411|223344556677885f5f5f5f	64	gnu	blendvps %xmm0,(%rcx),%xmm2
-660f381411|223344556677885f5f5f5f	64	intel	blendvps xmm2, xmmword ptr [rcx]
-660f381411|223344556677885f5f5f5f	64	plan9	BLENDVPS X0, 0(CX), X2
-660f381511|223344556677885f5f5f5f	32	intel	blendvpd xmm2, xmmword ptr [ecx]
-660f381511|223344556677885f5f5f5f	32	plan9	BLENDVPD X0, 0(CX), X2
-660f381511|223344556677885f5f5f5f	64	gnu	blendvpd %xmm0,(%rcx),%xmm2
-660f381511|223344556677885f5f5f5f	64	intel	blendvpd xmm2, xmmword ptr [rcx]
-660f381511|223344556677885f5f5f5f	64	plan9	BLENDVPD X0, 0(CX), X2
-660f381711|223344556677885f5f5f5f	32	intel	ptest xmm2, xmmword ptr [ecx]
-660f381711|223344556677885f5f5f5f	32	plan9	PTEST 0(CX), X2
-660f381711|223344556677885f5f5f5f	64	gnu	ptest (%rcx),%xmm2
-660f381711|223344556677885f5f5f5f	64	intel	ptest xmm2, xmmword ptr [rcx]
-660f381711|223344556677885f5f5f5f	64	plan9	PTEST 0(CX), X2
-660f381c11|223344556677885f5f5f5f	32	intel	pabsb xmm2, xmmword ptr [ecx]
-660f381c11|223344556677885f5f5f5f	32	plan9	PABSB 0(CX), X2
-660f381c11|223344556677885f5f5f5f	64	gnu	pabsb (%rcx),%xmm2
-660f381c11|223344556677885f5f5f5f	64	intel	pabsb xmm2, xmmword ptr [rcx]
-660f381c11|223344556677885f5f5f5f	64	plan9	PABSB 0(CX), X2
-660f381d11|223344556677885f5f5f5f	32	intel	pabsw xmm2, xmmword ptr [ecx]
-660f381d11|223344556677885f5f5f5f	32	plan9	PABSW 0(CX), X2
-660f381d11|223344556677885f5f5f5f	64	gnu	pabsw (%rcx),%xmm2
-660f381d11|223344556677885f5f5f5f	64	intel	pabsw xmm2, xmmword ptr [rcx]
-660f381d11|223344556677885f5f5f5f	64	plan9	PABSW 0(CX), X2
-660f381e11|223344556677885f5f5f5f	32	intel	pabsd xmm2, xmmword ptr [ecx]
-660f381e11|223344556677885f5f5f5f	32	plan9	PABSD 0(CX), X2
-660f381e11|223344556677885f5f5f5f	64	gnu	pabsd (%rcx),%xmm2
-660f381e11|223344556677885f5f5f5f	64	intel	pabsd xmm2, xmmword ptr [rcx]
-660f381e11|223344556677885f5f5f5f	64	plan9	PABSD 0(CX), X2
-660f382011|223344556677885f5f5f5f	32	intel	pmovsxbw xmm2, qword ptr [ecx]
-660f382011|223344556677885f5f5f5f	32	plan9	PMOVSXBW 0(CX), X2
-660f382011|223344556677885f5f5f5f	64	gnu	pmovsxbw (%rcx),%xmm2
-660f382011|223344556677885f5f5f5f	64	intel	pmovsxbw xmm2, qword ptr [rcx]
-660f382011|223344556677885f5f5f5f	64	plan9	PMOVSXBW 0(CX), X2
-660f382111|223344556677885f5f5f5f	32	intel	pmovsxbd xmm2, dword ptr [ecx]
-660f382111|223344556677885f5f5f5f	32	plan9	PMOVSXBD 0(CX), X2
-660f382111|223344556677885f5f5f5f	64	gnu	pmovsxbd (%rcx),%xmm2
-660f382111|223344556677885f5f5f5f	64	intel	pmovsxbd xmm2, dword ptr [rcx]
-660f382111|223344556677885f5f5f5f	64	plan9	PMOVSXBD 0(CX), X2
-660f382211|223344556677885f5f5f5f	32	intel	pmovsxbq xmm2, word ptr [ecx]
-660f382211|223344556677885f5f5f5f	32	plan9	PMOVSXBQ 0(CX), X2
-660f382211|223344556677885f5f5f5f	64	gnu	pmovsxbq (%rcx),%xmm2
-660f382211|223344556677885f5f5f5f	64	intel	pmovsxbq xmm2, word ptr [rcx]
-660f382211|223344556677885f5f5f5f	64	plan9	PMOVSXBQ 0(CX), X2
-660f382311|223344556677885f5f5f5f	32	intel	pmovsxwd xmm2, qword ptr [ecx]
-660f382311|223344556677885f5f5f5f	32	plan9	PMOVSXWD 0(CX), X2
-660f382311|223344556677885f5f5f5f	64	gnu	pmovsxwd (%rcx),%xmm2
-660f382311|223344556677885f5f5f5f	64	intel	pmovsxwd xmm2, qword ptr [rcx]
-660f382311|223344556677885f5f5f5f	64	plan9	PMOVSXWD 0(CX), X2
-660f382411|223344556677885f5f5f5f	32	intel	pmovsxwq xmm2, dword ptr [ecx]
-660f382411|223344556677885f5f5f5f	32	plan9	PMOVSXWQ 0(CX), X2
-660f382411|223344556677885f5f5f5f	64	gnu	pmovsxwq (%rcx),%xmm2
-660f382411|223344556677885f5f5f5f	64	intel	pmovsxwq xmm2, dword ptr [rcx]
-660f382411|223344556677885f5f5f5f	64	plan9	PMOVSXWQ 0(CX), X2
-660f382511|223344556677885f5f5f5f	32	intel	pmovsxdq xmm2, qword ptr [ecx]
-660f382511|223344556677885f5f5f5f	32	plan9	PMOVSXDQ 0(CX), X2
-660f382511|223344556677885f5f5f5f	64	gnu	pmovsxdq (%rcx),%xmm2
-660f382511|223344556677885f5f5f5f	64	intel	pmovsxdq xmm2, qword ptr [rcx]
-660f382511|223344556677885f5f5f5f	64	plan9	PMOVSXDQ 0(CX), X2
-660f382811|223344556677885f5f5f5f	32	intel	pmuldq xmm2, xmmword ptr [ecx]
-660f382811|223344556677885f5f5f5f	32	plan9	PMULDQ 0(CX), X2
-660f382811|223344556677885f5f5f5f	64	gnu	pmuldq (%rcx),%xmm2
-660f382811|223344556677885f5f5f5f	64	intel	pmuldq xmm2, xmmword ptr [rcx]
-660f382811|223344556677885f5f5f5f	64	plan9	PMULDQ 0(CX), X2
-660f382911|223344556677885f5f5f5f	32	intel	pcmpeqq xmm2, xmmword ptr [ecx]
-660f382911|223344556677885f5f5f5f	32	plan9	PCMPEQQ 0(CX), X2
-660f382911|223344556677885f5f5f5f	64	gnu	pcmpeqq (%rcx),%xmm2
-660f382911|223344556677885f5f5f5f	64	intel	pcmpeqq xmm2, xmmword ptr [rcx]
-660f382911|223344556677885f5f5f5f	64	plan9	PCMPEQQ 0(CX), X2
-660f382a11|223344556677885f5f5f5f	32	intel	movntdqa xmm2, xmmword ptr [ecx]
-660f382a11|223344556677885f5f5f5f	32	plan9	MOVNTDQA 0(CX), X2
-660f382a11|223344556677885f5f5f5f	64	gnu	movntdqa (%rcx),%xmm2
-660f382a11|223344556677885f5f5f5f	64	intel	movntdqa xmm2, xmmword ptr [rcx]
-660f382a11|223344556677885f5f5f5f	64	plan9	MOVNTDQA 0(CX), X2
-660f382b11|223344556677885f5f5f5f	32	intel	packusdw xmm2, xmmword ptr [ecx]
-660f382b11|223344556677885f5f5f5f	32	plan9	PACKUSDW 0(CX), X2
-660f382b11|223344556677885f5f5f5f	64	gnu	packusdw (%rcx),%xmm2
-660f382b11|223344556677885f5f5f5f	64	intel	packusdw xmm2, xmmword ptr [rcx]
-660f382b11|223344556677885f5f5f5f	64	plan9	PACKUSDW 0(CX), X2
-660f383011|223344556677885f5f5f5f	32	intel	pmovzxbw xmm2, qword ptr [ecx]
-660f383011|223344556677885f5f5f5f	32	plan9	PMOVZXBW 0(CX), X2
-660f383011|223344556677885f5f5f5f	64	gnu	pmovzxbw (%rcx),%xmm2
-660f383011|223344556677885f5f5f5f	64	intel	pmovzxbw xmm2, qword ptr [rcx]
-660f383011|223344556677885f5f5f5f	64	plan9	PMOVZXBW 0(CX), X2
-660f383111|223344556677885f5f5f5f	32	intel	pmovzxbd xmm2, dword ptr [ecx]
-660f383111|223344556677885f5f5f5f	32	plan9	PMOVZXBD 0(CX), X2
-660f383111|223344556677885f5f5f5f	64	gnu	pmovzxbd (%rcx),%xmm2
-660f383111|223344556677885f5f5f5f	64	intel	pmovzxbd xmm2, dword ptr [rcx]
-660f383111|223344556677885f5f5f5f	64	plan9	PMOVZXBD 0(CX), X2
-660f383211|223344556677885f5f5f5f	32	intel	pmovzxbq xmm2, word ptr [ecx]
-660f383211|223344556677885f5f5f5f	32	plan9	PMOVZXBQ 0(CX), X2
-660f383211|223344556677885f5f5f5f	64	gnu	pmovzxbq (%rcx),%xmm2
-660f383211|223344556677885f5f5f5f	64	intel	pmovzxbq xmm2, word ptr [rcx]
-660f383211|223344556677885f5f5f5f	64	plan9	PMOVZXBQ 0(CX), X2
-660f383311|223344556677885f5f5f5f	32	intel	pmovzxwd xmm2, qword ptr [ecx]
-660f383311|223344556677885f5f5f5f	32	plan9	PMOVZXWD 0(CX), X2
-660f383311|223344556677885f5f5f5f	64	gnu	pmovzxwd (%rcx),%xmm2
-660f383311|223344556677885f5f5f5f	64	intel	pmovzxwd xmm2, qword ptr [rcx]
-660f383311|223344556677885f5f5f5f	64	plan9	PMOVZXWD 0(CX), X2
-660f383411|223344556677885f5f5f5f	32	intel	pmovzxwq xmm2, dword ptr [ecx]
-660f383411|223344556677885f5f5f5f	32	plan9	PMOVZXWQ 0(CX), X2
-660f383411|223344556677885f5f5f5f	64	gnu	pmovzxwq (%rcx),%xmm2
-660f383411|223344556677885f5f5f5f	64	intel	pmovzxwq xmm2, dword ptr [rcx]
-660f383411|223344556677885f5f5f5f	64	plan9	PMOVZXWQ 0(CX), X2
-660f383511|223344556677885f5f5f5f	32	intel	pmovzxdq xmm2, qword ptr [ecx]
-660f383511|223344556677885f5f5f5f	32	plan9	PMOVZXDQ 0(CX), X2
-660f383511|223344556677885f5f5f5f	64	gnu	pmovzxdq (%rcx),%xmm2
-660f383511|223344556677885f5f5f5f	64	intel	pmovzxdq xmm2, qword ptr [rcx]
-660f383511|223344556677885f5f5f5f	64	plan9	PMOVZXDQ 0(CX), X2
-660f383711|223344556677885f5f5f5f	32	intel	pcmpgtq xmm2, xmmword ptr [ecx]
-660f383711|223344556677885f5f5f5f	32	plan9	PCMPGTQ 0(CX), X2
-660f383711|223344556677885f5f5f5f	64	gnu	pcmpgtq (%rcx),%xmm2
-660f383711|223344556677885f5f5f5f	64	intel	pcmpgtq xmm2, xmmword ptr [rcx]
-660f383711|223344556677885f5f5f5f	64	plan9	PCMPGTQ 0(CX), X2
-660f383811|223344556677885f5f5f5f	32	intel	pminsb xmm2, xmmword ptr [ecx]
-660f383811|223344556677885f5f5f5f	32	plan9	PMINSB 0(CX), X2
-660f383811|223344556677885f5f5f5f	64	gnu	pminsb (%rcx),%xmm2
-660f383811|223344556677885f5f5f5f	64	intel	pminsb xmm2, xmmword ptr [rcx]
-660f383811|223344556677885f5f5f5f	64	plan9	PMINSB 0(CX), X2
-660f383911|223344556677885f5f5f5f	32	intel	pminsd xmm2, xmmword ptr [ecx]
-660f383911|223344556677885f5f5f5f	32	plan9	PMINSD 0(CX), X2
-660f383911|223344556677885f5f5f5f	64	gnu	pminsd (%rcx),%xmm2
-660f383911|223344556677885f5f5f5f	64	intel	pminsd xmm2, xmmword ptr [rcx]
-660f383911|223344556677885f5f5f5f	64	plan9	PMINSD 0(CX), X2
-660f383a11|223344556677885f5f5f5f	32	intel	pminuw xmm2, xmmword ptr [ecx]
-660f383a11|223344556677885f5f5f5f	32	plan9	PMINUW 0(CX), X2
-660f383a11|223344556677885f5f5f5f	64	gnu	pminuw (%rcx),%xmm2
-660f383a11|223344556677885f5f5f5f	64	intel	pminuw xmm2, xmmword ptr [rcx]
-660f383a11|223344556677885f5f5f5f	64	plan9	PMINUW 0(CX), X2
-660f383b11|223344556677885f5f5f5f	32	intel	pminud xmm2, xmmword ptr [ecx]
-660f383b11|223344556677885f5f5f5f	32	plan9	PMINUD 0(CX), X2
-660f383b11|223344556677885f5f5f5f	64	gnu	pminud (%rcx),%xmm2
-660f383b11|223344556677885f5f5f5f	64	intel	pminud xmm2, xmmword ptr [rcx]
-660f383b11|223344556677885f5f5f5f	64	plan9	PMINUD 0(CX), X2
-660f383c11|223344556677885f5f5f5f	32	intel	pmaxsb xmm2, xmmword ptr [ecx]
-660f383c11|223344556677885f5f5f5f	32	plan9	PMAXSB 0(CX), X2
-660f383c11|223344556677885f5f5f5f	64	gnu	pmaxsb (%rcx),%xmm2
-660f383c11|223344556677885f5f5f5f	64	intel	pmaxsb xmm2, xmmword ptr [rcx]
-660f383c11|223344556677885f5f5f5f	64	plan9	PMAXSB 0(CX), X2
-660f383d11|223344556677885f5f5f5f	32	intel	pmaxsd xmm2, xmmword ptr [ecx]
-660f383d11|223344556677885f5f5f5f	32	plan9	PMAXSD 0(CX), X2
-660f383d11|223344556677885f5f5f5f	64	gnu	pmaxsd (%rcx),%xmm2
-660f383d11|223344556677885f5f5f5f	64	intel	pmaxsd xmm2, xmmword ptr [rcx]
-660f383d11|223344556677885f5f5f5f	64	plan9	PMAXSD 0(CX), X2
-660f383e11|223344556677885f5f5f5f	32	intel	pmaxuw xmm2, xmmword ptr [ecx]
-660f383e11|223344556677885f5f5f5f	32	plan9	PMAXUW 0(CX), X2
-660f383e11|223344556677885f5f5f5f	64	gnu	pmaxuw (%rcx),%xmm2
-660f383e11|223344556677885f5f5f5f	64	intel	pmaxuw xmm2, xmmword ptr [rcx]
-660f383e11|223344556677885f5f5f5f	64	plan9	PMAXUW 0(CX), X2
-660f383f11|223344556677885f5f5f5f	32	intel	pmaxud xmm2, xmmword ptr [ecx]
-660f383f11|223344556677885f5f5f5f	32	plan9	PMAXUD 0(CX), X2
-660f383f11|223344556677885f5f5f5f	64	gnu	pmaxud (%rcx),%xmm2
-660f383f11|223344556677885f5f5f5f	64	intel	pmaxud xmm2, xmmword ptr [rcx]
-660f383f11|223344556677885f5f5f5f	64	plan9	PMAXUD 0(CX), X2
-660f384011|223344556677885f5f5f5f	32	intel	pmulld xmm2, xmmword ptr [ecx]
-660f384011|223344556677885f5f5f5f	32	plan9	PMULLD 0(CX), X2
-660f384011|223344556677885f5f5f5f	64	gnu	pmulld (%rcx),%xmm2
-660f384011|223344556677885f5f5f5f	64	intel	pmulld xmm2, xmmword ptr [rcx]
-660f384011|223344556677885f5f5f5f	64	plan9	PMULLD 0(CX), X2
-660f384111|223344556677885f5f5f5f	32	intel	phminposuw xmm2, xmmword ptr [ecx]
-660f384111|223344556677885f5f5f5f	32	plan9	PHMINPOSUW 0(CX), X2
-660f384111|223344556677885f5f5f5f	64	gnu	phminposuw (%rcx),%xmm2
-660f384111|223344556677885f5f5f5f	64	intel	phminposuw xmm2, xmmword ptr [rcx]
-660f384111|223344556677885f5f5f5f	64	plan9	PHMINPOSUW 0(CX), X2
-660f388211|223344556677885f5f5f5f	32	intel	invpcid edx, xmmword ptr [ecx]
-660f388211|223344556677885f5f5f5f	32	plan9	INVPCID 0(CX), DX
-660f388211|223344556677885f5f5f5f	64	gnu	invpcid (%rcx),%rdx
-660f388211|223344556677885f5f5f5f	64	intel	invpcid rdx, xmmword ptr [rcx]
-660f388211|223344556677885f5f5f5f	64	plan9	INVPCID 0(CX), DX
-660f38db11|223344556677885f5f5f5f	32	intel	aesimc xmm2, xmmword ptr [ecx]
-660f38db11|223344556677885f5f5f5f	32	plan9	AESIMC 0(CX), X2
-660f38db11|223344556677885f5f5f5f	64	gnu	aesimc (%rcx),%xmm2
-660f38db11|223344556677885f5f5f5f	64	intel	aesimc xmm2, xmmword ptr [rcx]
-660f38db11|223344556677885f5f5f5f	64	plan9	AESIMC 0(CX), X2
-660f38dc11|223344556677885f5f5f5f	32	intel	aesenc xmm2, xmmword ptr [ecx]
-660f38dc11|223344556677885f5f5f5f	32	plan9	AESENC 0(CX), X2
-660f38dc11|223344556677885f5f5f5f	64	gnu	aesenc (%rcx),%xmm2
-660f38dc11|223344556677885f5f5f5f	64	intel	aesenc xmm2, xmmword ptr [rcx]
-660f38dc11|223344556677885f5f5f5f	64	plan9	AESENC 0(CX), X2
-660f38dd11|223344556677885f5f5f5f	32	intel	aesenclast xmm2, xmmword ptr [ecx]
-660f38dd11|223344556677885f5f5f5f	32	plan9	AESENCLAST 0(CX), X2
-660f38dd11|223344556677885f5f5f5f	64	gnu	aesenclast (%rcx),%xmm2
-660f38dd11|223344556677885f5f5f5f	64	intel	aesenclast xmm2, xmmword ptr [rcx]
-660f38dd11|223344556677885f5f5f5f	64	plan9	AESENCLAST 0(CX), X2
-660f38de11|223344556677885f5f5f5f	32	intel	aesdec xmm2, xmmword ptr [ecx]
-660f38de11|223344556677885f5f5f5f	32	plan9	AESDEC 0(CX), X2
-660f38de11|223344556677885f5f5f5f	64	gnu	aesdec (%rcx),%xmm2
-660f38de11|223344556677885f5f5f5f	64	intel	aesdec xmm2, xmmword ptr [rcx]
-660f38de11|223344556677885f5f5f5f	64	plan9	AESDEC 0(CX), X2
-660f38df11|223344556677885f5f5f5f	32	intel	aesdeclast xmm2, xmmword ptr [ecx]
-660f38df11|223344556677885f5f5f5f	32	plan9	AESDECLAST 0(CX), X2
-660f38df11|223344556677885f5f5f5f	64	gnu	aesdeclast (%rcx),%xmm2
-660f38df11|223344556677885f5f5f5f	64	intel	aesdeclast xmm2, xmmword ptr [rcx]
-660f38df11|223344556677885f5f5f5f	64	plan9	AESDECLAST 0(CX), X2
-660f3a081122|3344556677885f5f5f5f	32	intel	roundps xmm2, xmmword ptr [ecx], 0x22
-660f3a081122|3344556677885f5f5f5f	32	plan9	ROUNDPS $0x22, 0(CX), X2
-660f3a081122|3344556677885f5f5f5f	64	gnu	roundps $0x22,(%rcx),%xmm2
-660f3a081122|3344556677885f5f5f5f	64	intel	roundps xmm2, xmmword ptr [rcx], 0x22
-660f3a081122|3344556677885f5f5f5f	64	plan9	ROUNDPS $0x22, 0(CX), X2
-660f3a091122|3344556677885f5f5f5f	32	intel	roundpd xmm2, xmmword ptr [ecx], 0x22
-660f3a091122|3344556677885f5f5f5f	32	plan9	ROUNDPD $0x22, 0(CX), X2
-660f3a091122|3344556677885f5f5f5f	64	gnu	roundpd $0x22,(%rcx),%xmm2
-660f3a091122|3344556677885f5f5f5f	64	intel	roundpd xmm2, xmmword ptr [rcx], 0x22
-660f3a091122|3344556677885f5f5f5f	64	plan9	ROUNDPD $0x22, 0(CX), X2
-660f3a0a1122|3344556677885f5f5f5f	32	intel	roundss xmm2, dword ptr [ecx], 0x22
-660f3a0a1122|3344556677885f5f5f5f	32	plan9	ROUNDSS $0x22, 0(CX), X2
-660f3a0a1122|3344556677885f5f5f5f	64	gnu	roundss $0x22,(%rcx),%xmm2
-660f3a0a1122|3344556677885f5f5f5f	64	intel	roundss xmm2, dword ptr [rcx], 0x22
-660f3a0a1122|3344556677885f5f5f5f	64	plan9	ROUNDSS $0x22, 0(CX), X2
-660f3a0b1122|3344556677885f5f5f5f	32	intel	roundsd xmm2, qword ptr [ecx], 0x22
-660f3a0b1122|3344556677885f5f5f5f	32	plan9	ROUNDSD $0x22, 0(CX), X2
-660f3a0b1122|3344556677885f5f5f5f	64	gnu	roundsd $0x22,(%rcx),%xmm2
-660f3a0b1122|3344556677885f5f5f5f	64	intel	roundsd xmm2, qword ptr [rcx], 0x22
-660f3a0b1122|3344556677885f5f5f5f	64	plan9	ROUNDSD $0x22, 0(CX), X2
-660f3a0c1122|3344556677885f5f5f5f	32	intel	blendps xmm2, xmmword ptr [ecx], 0x22
-660f3a0c1122|3344556677885f5f5f5f	32	plan9	BLENDPS $0x22, 0(CX), X2
-660f3a0c1122|3344556677885f5f5f5f	64	gnu	blendps $0x22,(%rcx),%xmm2
-660f3a0c1122|3344556677885f5f5f5f	64	intel	blendps xmm2, xmmword ptr [rcx], 0x22
-660f3a0c1122|3344556677885f5f5f5f	64	plan9	BLENDPS $0x22, 0(CX), X2
-660f3a0d1122|3344556677885f5f5f5f	32	intel	blendpd xmm2, xmmword ptr [ecx], 0x22
-660f3a0d1122|3344556677885f5f5f5f	32	plan9	BLENDPD $0x22, 0(CX), X2
-660f3a0d1122|3344556677885f5f5f5f	64	gnu	blendpd $0x22,(%rcx),%xmm2
-660f3a0d1122|3344556677885f5f5f5f	64	intel	blendpd xmm2, xmmword ptr [rcx], 0x22
-660f3a0d1122|3344556677885f5f5f5f	64	plan9	BLENDPD $0x22, 0(CX), X2
-660f3a0e1122|3344556677885f5f5f5f	32	intel	pblendw xmm2, xmmword ptr [ecx], 0x22
-660f3a0e1122|3344556677885f5f5f5f	32	plan9	PBLENDW $0x22, 0(CX), X2
-660f3a0e1122|3344556677885f5f5f5f	64	gnu	pblendw $0x22,(%rcx),%xmm2
-660f3a0e1122|3344556677885f5f5f5f	64	intel	pblendw xmm2, xmmword ptr [rcx], 0x22
-660f3a0e1122|3344556677885f5f5f5f	64	plan9	PBLENDW $0x22, 0(CX), X2
-660f3a0f1122|3344556677885f5f5f5f	32	intel	palignr xmm2, xmmword ptr [ecx], 0x22
-660f3a0f1122|3344556677885f5f5f5f	32	plan9	PALIGNR $0x22, 0(CX), X2
-660f3a0f1122|3344556677885f5f5f5f	64	gnu	palignr $0x22,(%rcx),%xmm2
-660f3a0f1122|3344556677885f5f5f5f	64	intel	palignr xmm2, xmmword ptr [rcx], 0x22
-660f3a0f1122|3344556677885f5f5f5f	64	plan9	PALIGNR $0x22, 0(CX), X2
-660f3a141122|3344556677885f5f5f5f	32	intel	pextrb byte ptr [ecx], xmm2, 0x22
-660f3a141122|3344556677885f5f5f5f	32	plan9	PEXTRB $0x22, X2, 0(CX)
-660f3a141122|3344556677885f5f5f5f	64	gnu	pextrb $0x22,%xmm2,(%rcx)
-660f3a141122|3344556677885f5f5f5f	64	intel	pextrb byte ptr [rcx], xmm2, 0x22
-660f3a141122|3344556677885f5f5f5f	64	plan9	PEXTRB $0x22, X2, 0(CX)
-660f3a151122|3344556677885f5f5f5f	32	intel	pextrw word ptr [ecx], xmm2, 0x22
-660f3a151122|3344556677885f5f5f5f	32	plan9	PEXTRW $0x22, X2, 0(CX)
-660f3a151122|3344556677885f5f5f5f	64	gnu	pextrw $0x22,%xmm2,(%rcx)
-660f3a151122|3344556677885f5f5f5f	64	intel	pextrw word ptr [rcx], xmm2, 0x22
-660f3a151122|3344556677885f5f5f5f	64	plan9	PEXTRW $0x22, X2, 0(CX)
-660f3a161122|3344556677885f5f5f5f	32	intel	pextrd dword ptr [ecx], xmm2, 0x22
-660f3a161122|3344556677885f5f5f5f	32	plan9	PEXTRD $0x22, X2, 0(CX)
-660f3a161122|3344556677885f5f5f5f	64	gnu	pextrd $0x22,%xmm2,(%rcx)
-660f3a161122|3344556677885f5f5f5f	64	intel	pextrd dword ptr [rcx], xmm2, 0x22
-660f3a161122|3344556677885f5f5f5f	64	plan9	PEXTRD $0x22, X2, 0(CX)
-660f3a171122|3344556677885f5f5f5f	32	intel	extractps dword ptr [ecx], xmm2, 0x22
-660f3a171122|3344556677885f5f5f5f	32	plan9	EXTRACTPS $0x22, X2, 0(CX)
-660f3a171122|3344556677885f5f5f5f	64	gnu	extractps $0x22,%xmm2,(%rcx)
-660f3a171122|3344556677885f5f5f5f	64	intel	extractps dword ptr [rcx], xmm2, 0x22
-660f3a171122|3344556677885f5f5f5f	64	plan9	EXTRACTPS $0x22, X2, 0(CX)
-660f3a201122|3344556677885f5f5f5f	32	intel	pinsrb xmm2, byte ptr [ecx], 0x22
-660f3a201122|3344556677885f5f5f5f	32	plan9	PINSRB $0x22, 0(CX), X2
-660f3a201122|3344556677885f5f5f5f	64	gnu	pinsrb $0x22,(%rcx),%xmm2
-660f3a201122|3344556677885f5f5f5f	64	intel	pinsrb xmm2, byte ptr [rcx], 0x22
-660f3a201122|3344556677885f5f5f5f	64	plan9	PINSRB $0x22, 0(CX), X2
-660f3a211122|3344556677885f5f5f5f	32	intel	insertps xmm2, dword ptr [ecx], 0x22
-660f3a211122|3344556677885f5f5f5f	32	plan9	INSERTPS $0x22, 0(CX), X2
-660f3a211122|3344556677885f5f5f5f	64	gnu	insertps $0x22,(%rcx),%xmm2
-660f3a211122|3344556677885f5f5f5f	64	intel	insertps xmm2, dword ptr [rcx], 0x22
-660f3a211122|3344556677885f5f5f5f	64	plan9	INSERTPS $0x22, 0(CX), X2
-660f3a221122|3344556677885f5f5f5f	32	intel	pinsrd xmm2, dword ptr [ecx], 0x22
-660f3a221122|3344556677885f5f5f5f	32	plan9	PINSRD $0x22, 0(CX), X2
-660f3a221122|3344556677885f5f5f5f	64	gnu	pinsrd $0x22,(%rcx),%xmm2
-660f3a221122|3344556677885f5f5f5f	64	intel	pinsrd xmm2, dword ptr [rcx], 0x22
-660f3a221122|3344556677885f5f5f5f	64	plan9	PINSRD $0x22, 0(CX), X2
-660f3a401122|3344556677885f5f5f5f	32	intel	dpps xmm2, xmmword ptr [ecx], 0x22
-660f3a401122|3344556677885f5f5f5f	32	plan9	DPPS $0x22, 0(CX), X2
-660f3a401122|3344556677885f5f5f5f	64	gnu	dpps $0x22,(%rcx),%xmm2
-660f3a401122|3344556677885f5f5f5f	64	intel	dpps xmm2, xmmword ptr [rcx], 0x22
-660f3a401122|3344556677885f5f5f5f	64	plan9	DPPS $0x22, 0(CX), X2
-660f3a411122|3344556677885f5f5f5f	32	intel	dppd xmm2, xmmword ptr [ecx], 0x22
-660f3a411122|3344556677885f5f5f5f	32	plan9	DPPD $0x22, 0(CX), X2
-660f3a411122|3344556677885f5f5f5f	64	gnu	dppd $0x22,(%rcx),%xmm2
-660f3a411122|3344556677885f5f5f5f	64	intel	dppd xmm2, xmmword ptr [rcx], 0x22
-660f3a411122|3344556677885f5f5f5f	64	plan9	DPPD $0x22, 0(CX), X2
-660f3a421122|3344556677885f5f5f5f	32	intel	mpsadbw xmm2, xmmword ptr [ecx], 0x22
-660f3a421122|3344556677885f5f5f5f	32	plan9	MPSADBW $0x22, 0(CX), X2
-660f3a421122|3344556677885f5f5f5f	64	gnu	mpsadbw $0x22,(%rcx),%xmm2
-660f3a421122|3344556677885f5f5f5f	64	intel	mpsadbw xmm2, xmmword ptr [rcx], 0x22
-660f3a421122|3344556677885f5f5f5f	64	plan9	MPSADBW $0x22, 0(CX), X2
-660f3a441122|3344556677885f5f5f5f	32	intel	pclmulqdq xmm2, xmmword ptr [ecx], 0x22
-660f3a441122|3344556677885f5f5f5f	32	plan9	PCLMULQDQ $0x22, 0(CX), X2
-660f3a441122|3344556677885f5f5f5f	64	gnu	pclmulqdq $0x22,(%rcx),%xmm2
-660f3a441122|3344556677885f5f5f5f	64	intel	pclmulqdq xmm2, xmmword ptr [rcx], 0x22
-660f3a441122|3344556677885f5f5f5f	64	plan9	PCLMULQDQ $0x22, 0(CX), X2
-660f3a601122|3344556677885f5f5f5f	32	intel	pcmpestrm xmm2, xmmword ptr [ecx], 0x22
-660f3a601122|3344556677885f5f5f5f	32	plan9	PCMPESTRM $0x22, 0(CX), X2
-660f3a601122|3344556677885f5f5f5f	64	gnu	pcmpestrm $0x22,(%rcx),%xmm2
-660f3a601122|3344556677885f5f5f5f	64	intel	pcmpestrm xmm2, xmmword ptr [rcx], 0x22
-660f3a601122|3344556677885f5f5f5f	64	plan9	PCMPESTRM $0x22, 0(CX), X2
-660f3a611122|3344556677885f5f5f5f	32	intel	pcmpestri xmm2, xmmword ptr [ecx], 0x22
-660f3a611122|3344556677885f5f5f5f	32	plan9	PCMPESTRI $0x22, 0(CX), X2
-660f3a611122|3344556677885f5f5f5f	64	gnu	pcmpestri $0x22,(%rcx),%xmm2
-660f3a611122|3344556677885f5f5f5f	64	intel	pcmpestri xmm2, xmmword ptr [rcx], 0x22
-660f3a611122|3344556677885f5f5f5f	64	plan9	PCMPESTRI $0x22, 0(CX), X2
-660f3a621122|3344556677885f5f5f5f	32	intel	pcmpistrm xmm2, xmmword ptr [ecx], 0x22
-660f3a621122|3344556677885f5f5f5f	32	plan9	PCMPISTRM $0x22, 0(CX), X2
-660f3a621122|3344556677885f5f5f5f	64	gnu	pcmpistrm $0x22,(%rcx),%xmm2
-660f3a621122|3344556677885f5f5f5f	64	intel	pcmpistrm xmm2, xmmword ptr [rcx], 0x22
-660f3a621122|3344556677885f5f5f5f	64	plan9	PCMPISTRM $0x22, 0(CX), X2
-660f3a631122|3344556677885f5f5f5f	32	intel	pcmpistri xmm2, xmmword ptr [ecx], 0x22
-660f3a631122|3344556677885f5f5f5f	32	plan9	PCMPISTRI $0x22, 0(CX), X2
-660f3a631122|3344556677885f5f5f5f	64	gnu	pcmpistri $0x22,(%rcx),%xmm2
-660f3a631122|3344556677885f5f5f5f	64	intel	pcmpistri xmm2, xmmword ptr [rcx], 0x22
-660f3a631122|3344556677885f5f5f5f	64	plan9	PCMPISTRI $0x22, 0(CX), X2
-660f3adf1122|3344556677885f5f5f5f	32	intel	aeskeygenassist xmm2, xmmword ptr [ecx], 0x22
-660f3adf1122|3344556677885f5f5f5f	32	plan9	AESKEYGENASSIST $0x22, 0(CX), X2
-660f3adf1122|3344556677885f5f5f5f	64	gnu	aeskeygenassist $0x22,(%rcx),%xmm2
-660f3adf1122|3344556677885f5f5f5f	64	intel	aeskeygenassist xmm2, xmmword ptr [rcx], 0x22
-660f3adf1122|3344556677885f5f5f5f	64	plan9	AESKEYGENASSIST $0x22, 0(CX), X2
-660f4011|223344556677885f5f5f5f5f	32	intel	cmovo dx, word ptr [ecx]
-660f4011|223344556677885f5f5f5f5f	32	plan9	CMOVO 0(CX), DX
-660f4011|223344556677885f5f5f5f5f	64	gnu	cmovo (%rcx),%dx
-660f4011|223344556677885f5f5f5f5f	64	intel	cmovo dx, word ptr [rcx]
-660f4011|223344556677885f5f5f5f5f	64	plan9	CMOVO 0(CX), DX
-660f4111|223344556677885f5f5f5f5f	32	intel	cmovno dx, word ptr [ecx]
-660f4111|223344556677885f5f5f5f5f	32	plan9	CMOVNO 0(CX), DX
-660f4111|223344556677885f5f5f5f5f	64	gnu	cmovno (%rcx),%dx
-660f4111|223344556677885f5f5f5f5f	64	intel	cmovno dx, word ptr [rcx]
-660f4111|223344556677885f5f5f5f5f	64	plan9	CMOVNO 0(CX), DX
-660f4211|223344556677885f5f5f5f5f	32	intel	cmovb dx, word ptr [ecx]
-660f4211|223344556677885f5f5f5f5f	32	plan9	CMOVB 0(CX), DX
-660f4211|223344556677885f5f5f5f5f	64	gnu	cmovb (%rcx),%dx
-660f4211|223344556677885f5f5f5f5f	64	intel	cmovb dx, word ptr [rcx]
-660f4211|223344556677885f5f5f5f5f	64	plan9	CMOVB 0(CX), DX
-660f4311|223344556677885f5f5f5f5f	32	intel	cmovnb dx, word ptr [ecx]
-660f4311|223344556677885f5f5f5f5f	32	plan9	CMOVAE 0(CX), DX
-660f4311|223344556677885f5f5f5f5f	64	gnu	cmovae (%rcx),%dx
-660f4311|223344556677885f5f5f5f5f	64	intel	cmovnb dx, word ptr [rcx]
-660f4311|223344556677885f5f5f5f5f	64	plan9	CMOVAE 0(CX), DX
-660f4411|223344556677885f5f5f5f5f	32	intel	cmovz dx, word ptr [ecx]
-660f4411|223344556677885f5f5f5f5f	32	plan9	CMOVE 0(CX), DX
-660f4411|223344556677885f5f5f5f5f	64	gnu	cmove (%rcx),%dx
-660f4411|223344556677885f5f5f5f5f	64	intel	cmovz dx, word ptr [rcx]
-660f4411|223344556677885f5f5f5f5f	64	plan9	CMOVE 0(CX), DX
-660f4511|223344556677885f5f5f5f5f	32	intel	cmovnz dx, word ptr [ecx]
-660f4511|223344556677885f5f5f5f5f	32	plan9	CMOVNE 0(CX), DX
-660f4511|223344556677885f5f5f5f5f	64	gnu	cmovne (%rcx),%dx
-660f4511|223344556677885f5f5f5f5f	64	intel	cmovnz dx, word ptr [rcx]
-660f4511|223344556677885f5f5f5f5f	64	plan9	CMOVNE 0(CX), DX
-660f4611|223344556677885f5f5f5f5f	32	intel	cmovbe dx, word ptr [ecx]
-660f4611|223344556677885f5f5f5f5f	32	plan9	CMOVBE 0(CX), DX
-660f4611|223344556677885f5f5f5f5f	64	gnu	cmovbe (%rcx),%dx
-660f4611|223344556677885f5f5f5f5f	64	intel	cmovbe dx, word ptr [rcx]
-660f4611|223344556677885f5f5f5f5f	64	plan9	CMOVBE 0(CX), DX
-660f4711|223344556677885f5f5f5f5f	32	intel	cmovnbe dx, word ptr [ecx]
-660f4711|223344556677885f5f5f5f5f	32	plan9	CMOVA 0(CX), DX
-660f4711|223344556677885f5f5f5f5f	64	gnu	cmova (%rcx),%dx
-660f4711|223344556677885f5f5f5f5f	64	intel	cmovnbe dx, word ptr [rcx]
-660f4711|223344556677885f5f5f5f5f	64	plan9	CMOVA 0(CX), DX
-660f4811|223344556677885f5f5f5f5f	32	intel	cmovs dx, word ptr [ecx]
-660f4811|223344556677885f5f5f5f5f	32	plan9	CMOVS 0(CX), DX
-660f4811|223344556677885f5f5f5f5f	64	gnu	cmovs (%rcx),%dx
-660f4811|223344556677885f5f5f5f5f	64	intel	cmovs dx, word ptr [rcx]
-660f4811|223344556677885f5f5f5f5f	64	plan9	CMOVS 0(CX), DX
-660f4911|223344556677885f5f5f5f5f	32	intel	cmovns dx, word ptr [ecx]
-660f4911|223344556677885f5f5f5f5f	32	plan9	CMOVNS 0(CX), DX
-660f4911|223344556677885f5f5f5f5f	64	gnu	cmovns (%rcx),%dx
-660f4911|223344556677885f5f5f5f5f	64	intel	cmovns dx, word ptr [rcx]
-660f4911|223344556677885f5f5f5f5f	64	plan9	CMOVNS 0(CX), DX
-660f4a11|223344556677885f5f5f5f5f	32	intel	cmovp dx, word ptr [ecx]
-660f4a11|223344556677885f5f5f5f5f	32	plan9	CMOVP 0(CX), DX
-660f4a11|223344556677885f5f5f5f5f	64	gnu	cmovp (%rcx),%dx
-660f4a11|223344556677885f5f5f5f5f	64	intel	cmovp dx, word ptr [rcx]
-660f4a11|223344556677885f5f5f5f5f	64	plan9	CMOVP 0(CX), DX
-660f4b11|223344556677885f5f5f5f5f	32	intel	cmovnp dx, word ptr [ecx]
-660f4b11|223344556677885f5f5f5f5f	32	plan9	CMOVNP 0(CX), DX
-660f4b11|223344556677885f5f5f5f5f	64	gnu	cmovnp (%rcx),%dx
-660f4b11|223344556677885f5f5f5f5f	64	intel	cmovnp dx, word ptr [rcx]
-660f4b11|223344556677885f5f5f5f5f	64	plan9	CMOVNP 0(CX), DX
-660f4c11|223344556677885f5f5f5f5f	32	intel	cmovl dx, word ptr [ecx]
-660f4c11|223344556677885f5f5f5f5f	32	plan9	CMOVL 0(CX), DX
-660f4c11|223344556677885f5f5f5f5f	64	gnu	cmovl (%rcx),%dx
-660f4c11|223344556677885f5f5f5f5f	64	intel	cmovl dx, word ptr [rcx]
-660f4c11|223344556677885f5f5f5f5f	64	plan9	CMOVL 0(CX), DX
-660f4d11|223344556677885f5f5f5f5f	32	intel	cmovnl dx, word ptr [ecx]
-660f4d11|223344556677885f5f5f5f5f	32	plan9	CMOVGE 0(CX), DX
-660f4d11|223344556677885f5f5f5f5f	64	gnu	cmovge (%rcx),%dx
-660f4d11|223344556677885f5f5f5f5f	64	intel	cmovnl dx, word ptr [rcx]
-660f4d11|223344556677885f5f5f5f5f	64	plan9	CMOVGE 0(CX), DX
-660f4e11|223344556677885f5f5f5f5f	32	intel	cmovle dx, word ptr [ecx]
-660f4e11|223344556677885f5f5f5f5f	32	plan9	CMOVLE 0(CX), DX
-660f4e11|223344556677885f5f5f5f5f	64	gnu	cmovle (%rcx),%dx
-660f4e11|223344556677885f5f5f5f5f	64	intel	cmovle dx, word ptr [rcx]
-660f4e11|223344556677885f5f5f5f5f	64	plan9	CMOVLE 0(CX), DX
-660f4f11|223344556677885f5f5f5f5f	32	intel	cmovnle dx, word ptr [ecx]
-660f4f11|223344556677885f5f5f5f5f	32	plan9	CMOVG 0(CX), DX
-660f4f11|223344556677885f5f5f5f5f	64	gnu	cmovg (%rcx),%dx
-660f4f11|223344556677885f5f5f5f5f	64	intel	cmovnle dx, word ptr [rcx]
-660f4f11|223344556677885f5f5f5f5f	64	plan9	CMOVG 0(CX), DX
-660f50c0|11223344556677885f5f5f5f	32	intel	movmskpd eax, xmm0
-660f50c0|11223344556677885f5f5f5f	32	plan9	MOVMSKPD X0, AX
-660f50c0|11223344556677885f5f5f5f	64	gnu	movmskpd %xmm0,%eax
-660f50c0|11223344556677885f5f5f5f	64	intel	movmskpd eax, xmm0
-660f50c0|11223344556677885f5f5f5f	64	plan9	MOVMSKPD X0, AX
-660f5111|223344556677885f5f5f5f5f	32	intel	sqrtpd xmm2, xmmword ptr [ecx]
-660f5111|223344556677885f5f5f5f5f	32	plan9	SQRTPD 0(CX), X2
-660f5111|223344556677885f5f5f5f5f	64	gnu	sqrtpd (%rcx),%xmm2
-660f5111|223344556677885f5f5f5f5f	64	intel	sqrtpd xmm2, xmmword ptr [rcx]
-660f5111|223344556677885f5f5f5f5f	64	plan9	SQRTPD 0(CX), X2
-660f5411|223344556677885f5f5f5f5f	32	intel	andpd xmm2, xmmword ptr [ecx]
-660f5411|223344556677885f5f5f5f5f	32	plan9	ANDPD 0(CX), X2
-660f5411|223344556677885f5f5f5f5f	64	gnu	andpd (%rcx),%xmm2
-660f5411|223344556677885f5f5f5f5f	64	intel	andpd xmm2, xmmword ptr [rcx]
-660f5411|223344556677885f5f5f5f5f	64	plan9	ANDPD 0(CX), X2
-660f5511|223344556677885f5f5f5f5f	32	intel	andnpd xmm2, xmmword ptr [ecx]
-660f5511|223344556677885f5f5f5f5f	32	plan9	ANDNPD 0(CX), X2
-660f5511|223344556677885f5f5f5f5f	64	gnu	andnpd (%rcx),%xmm2
-660f5511|223344556677885f5f5f5f5f	64	intel	andnpd xmm2, xmmword ptr [rcx]
-660f5511|223344556677885f5f5f5f5f	64	plan9	ANDNPD 0(CX), X2
-660f5611|223344556677885f5f5f5f5f	32	intel	orpd xmm2, xmmword ptr [ecx]
-660f5611|223344556677885f5f5f5f5f	32	plan9	ORPD 0(CX), X2
-660f5611|223344556677885f5f5f5f5f	64	gnu	orpd (%rcx),%xmm2
-660f5611|223344556677885f5f5f5f5f	64	intel	orpd xmm2, xmmword ptr [rcx]
-660f5611|223344556677885f5f5f5f5f	64	plan9	ORPD 0(CX), X2
-660f5711|223344556677885f5f5f5f5f	32	intel	xorpd xmm2, xmmword ptr [ecx]
-660f5711|223344556677885f5f5f5f5f	32	plan9	XORPD 0(CX), X2
-660f5711|223344556677885f5f5f5f5f	64	gnu	xorpd (%rcx),%xmm2
-660f5711|223344556677885f5f5f5f5f	64	intel	xorpd xmm2, xmmword ptr [rcx]
-660f5711|223344556677885f5f5f5f5f	64	plan9	XORPD 0(CX), X2
-660f5811|223344556677885f5f5f5f5f	32	intel	addpd xmm2, xmmword ptr [ecx]
-660f5811|223344556677885f5f5f5f5f	32	plan9	ADDPD 0(CX), X2
-660f5811|223344556677885f5f5f5f5f	64	gnu	addpd (%rcx),%xmm2
-660f5811|223344556677885f5f5f5f5f	64	intel	addpd xmm2, xmmword ptr [rcx]
-660f5811|223344556677885f5f5f5f5f	64	plan9	ADDPD 0(CX), X2
-660f5911|223344556677885f5f5f5f5f	32	intel	mulpd xmm2, xmmword ptr [ecx]
-660f5911|223344556677885f5f5f5f5f	32	plan9	MULPD 0(CX), X2
-660f5911|223344556677885f5f5f5f5f	64	gnu	mulpd (%rcx),%xmm2
-660f5911|223344556677885f5f5f5f5f	64	intel	mulpd xmm2, xmmword ptr [rcx]
-660f5911|223344556677885f5f5f5f5f	64	plan9	MULPD 0(CX), X2
-660f5a11|223344556677885f5f5f5f5f	32	intel	cvtpd2ps xmm2, xmmword ptr [ecx]
-660f5a11|223344556677885f5f5f5f5f	32	plan9	CVTPD2PS 0(CX), X2
-660f5a11|223344556677885f5f5f5f5f	64	gnu	cvtpd2ps (%rcx),%xmm2
-660f5a11|223344556677885f5f5f5f5f	64	intel	cvtpd2ps xmm2, xmmword ptr [rcx]
-660f5a11|223344556677885f5f5f5f5f	64	plan9	CVTPD2PS 0(CX), X2
-660f5b11|223344556677885f5f5f5f5f	32	intel	cvtps2dq xmm2, xmmword ptr [ecx]
-660f5b11|223344556677885f5f5f5f5f	32	plan9	CVTPS2DQ 0(CX), X2
-660f5b11|223344556677885f5f5f5f5f	64	gnu	cvtps2dq (%rcx),%xmm2
-660f5b11|223344556677885f5f5f5f5f	64	intel	cvtps2dq xmm2, xmmword ptr [rcx]
-660f5b11|223344556677885f5f5f5f5f	64	plan9	CVTPS2DQ 0(CX), X2
-660f5c11|223344556677885f5f5f5f5f	32	intel	subpd xmm2, xmmword ptr [ecx]
-660f5c11|223344556677885f5f5f5f5f	32	plan9	SUBPD 0(CX), X2
-660f5c11|223344556677885f5f5f5f5f	64	gnu	subpd (%rcx),%xmm2
-660f5c11|223344556677885f5f5f5f5f	64	intel	subpd xmm2, xmmword ptr [rcx]
-660f5c11|223344556677885f5f5f5f5f	64	plan9	SUBPD 0(CX), X2
-660f5d11|223344556677885f5f5f5f5f	32	intel	minpd xmm2, xmmword ptr [ecx]
-660f5d11|223344556677885f5f5f5f5f	32	plan9	MINPD 0(CX), X2
-660f5d11|223344556677885f5f5f5f5f	64	gnu	minpd (%rcx),%xmm2
-660f5d11|223344556677885f5f5f5f5f	64	intel	minpd xmm2, xmmword ptr [rcx]
-660f5d11|223344556677885f5f5f5f5f	64	plan9	MINPD 0(CX), X2
-660f5e11|223344556677885f5f5f5f5f	32	intel	divpd xmm2, xmmword ptr [ecx]
-660f5e11|223344556677885f5f5f5f5f	32	plan9	DIVPD 0(CX), X2
-660f5e11|223344556677885f5f5f5f5f	64	gnu	divpd (%rcx),%xmm2
-660f5e11|223344556677885f5f5f5f5f	64	intel	divpd xmm2, xmmword ptr [rcx]
-660f5e11|223344556677885f5f5f5f5f	64	plan9	DIVPD 0(CX), X2
-660f5f11|223344556677885f5f5f5f5f	32	intel	maxpd xmm2, xmmword ptr [ecx]
-660f5f11|223344556677885f5f5f5f5f	32	plan9	MAXPD 0(CX), X2
-660f5f11|223344556677885f5f5f5f5f	64	gnu	maxpd (%rcx),%xmm2
-660f5f11|223344556677885f5f5f5f5f	64	intel	maxpd xmm2, xmmword ptr [rcx]
-660f5f11|223344556677885f5f5f5f5f	64	plan9	MAXPD 0(CX), X2
-660f6011|223344556677885f5f5f5f5f	32	intel	punpcklbw xmm2, xmmword ptr [ecx]
-660f6011|223344556677885f5f5f5f5f	32	plan9	PUNPCKLBW 0(CX), X2
-660f6011|223344556677885f5f5f5f5f	64	gnu	punpcklbw (%rcx),%xmm2
-660f6011|223344556677885f5f5f5f5f	64	intel	punpcklbw xmm2, xmmword ptr [rcx]
-660f6011|223344556677885f5f5f5f5f	64	plan9	PUNPCKLBW 0(CX), X2
-660f6111|223344556677885f5f5f5f5f	32	intel	punpcklwd xmm2, xmmword ptr [ecx]
-660f6111|223344556677885f5f5f5f5f	32	plan9	PUNPCKLWD 0(CX), X2
-660f6111|223344556677885f5f5f5f5f	64	gnu	punpcklwd (%rcx),%xmm2
-660f6111|223344556677885f5f5f5f5f	64	intel	punpcklwd xmm2, xmmword ptr [rcx]
-660f6111|223344556677885f5f5f5f5f	64	plan9	PUNPCKLWD 0(CX), X2
-660f6211|223344556677885f5f5f5f5f	32	intel	punpckldq xmm2, xmmword ptr [ecx]
-660f6211|223344556677885f5f5f5f5f	32	plan9	PUNPCKLDQ 0(CX), X2
-660f6211|223344556677885f5f5f5f5f	64	gnu	punpckldq (%rcx),%xmm2
-660f6211|223344556677885f5f5f5f5f	64	intel	punpckldq xmm2, xmmword ptr [rcx]
-660f6211|223344556677885f5f5f5f5f	64	plan9	PUNPCKLDQ 0(CX), X2
-660f6311|223344556677885f5f5f5f5f	32	intel	packsswb xmm2, xmmword ptr [ecx]
-660f6311|223344556677885f5f5f5f5f	32	plan9	PACKSSWB 0(CX), X2
-660f6311|223344556677885f5f5f5f5f	64	gnu	packsswb (%rcx),%xmm2
-660f6311|223344556677885f5f5f5f5f	64	intel	packsswb xmm2, xmmword ptr [rcx]
-660f6311|223344556677885f5f5f5f5f	64	plan9	PACKSSWB 0(CX), X2
-660f6411|223344556677885f5f5f5f5f	32	intel	pcmpgtb xmm2, xmmword ptr [ecx]
-660f6411|223344556677885f5f5f5f5f	32	plan9	PCMPGTB 0(CX), X2
-660f6411|223344556677885f5f5f5f5f	64	gnu	pcmpgtb (%rcx),%xmm2
-660f6411|223344556677885f5f5f5f5f	64	intel	pcmpgtb xmm2, xmmword ptr [rcx]
-660f6411|223344556677885f5f5f5f5f	64	plan9	PCMPGTB 0(CX), X2
-660f6511|223344556677885f5f5f5f5f	32	intel	pcmpgtw xmm2, xmmword ptr [ecx]
-660f6511|223344556677885f5f5f5f5f	32	plan9	PCMPGTW 0(CX), X2
-660f6511|223344556677885f5f5f5f5f	64	gnu	pcmpgtw (%rcx),%xmm2
-660f6511|223344556677885f5f5f5f5f	64	intel	pcmpgtw xmm2, xmmword ptr [rcx]
-660f6511|223344556677885f5f5f5f5f	64	plan9	PCMPGTW 0(CX), X2
-660f6611|223344556677885f5f5f5f5f	32	intel	pcmpgtd xmm2, xmmword ptr [ecx]
-660f6611|223344556677885f5f5f5f5f	32	plan9	PCMPGTD 0(CX), X2
-660f6611|223344556677885f5f5f5f5f	64	gnu	pcmpgtd (%rcx),%xmm2
-660f6611|223344556677885f5f5f5f5f	64	intel	pcmpgtd xmm2, xmmword ptr [rcx]
-660f6611|223344556677885f5f5f5f5f	64	plan9	PCMPGTD 0(CX), X2
-660f6711|223344556677885f5f5f5f5f	32	intel	packuswb xmm2, xmmword ptr [ecx]
-660f6711|223344556677885f5f5f5f5f	32	plan9	PACKUSWB 0(CX), X2
-660f6711|223344556677885f5f5f5f5f	64	gnu	packuswb (%rcx),%xmm2
-660f6711|223344556677885f5f5f5f5f	64	intel	packuswb xmm2, xmmword ptr [rcx]
-660f6711|223344556677885f5f5f5f5f	64	plan9	PACKUSWB 0(CX), X2
-660f6811|223344556677885f5f5f5f5f	32	intel	punpckhbw xmm2, xmmword ptr [ecx]
-660f6811|223344556677885f5f5f5f5f	32	plan9	PUNPCKHBW 0(CX), X2
-660f6811|223344556677885f5f5f5f5f	64	gnu	punpckhbw (%rcx),%xmm2
-660f6811|223344556677885f5f5f5f5f	64	intel	punpckhbw xmm2, xmmword ptr [rcx]
-660f6811|223344556677885f5f5f5f5f	64	plan9	PUNPCKHBW 0(CX), X2
-660f6911|223344556677885f5f5f5f5f	32	intel	punpckhwd xmm2, xmmword ptr [ecx]
-660f6911|223344556677885f5f5f5f5f	32	plan9	PUNPCKHWD 0(CX), X2
-660f6911|223344556677885f5f5f5f5f	64	gnu	punpckhwd (%rcx),%xmm2
-660f6911|223344556677885f5f5f5f5f	64	intel	punpckhwd xmm2, xmmword ptr [rcx]
-660f6911|223344556677885f5f5f5f5f	64	plan9	PUNPCKHWD 0(CX), X2
-660f6a11|223344556677885f5f5f5f5f	32	intel	punpckhdq xmm2, xmmword ptr [ecx]
-660f6a11|223344556677885f5f5f5f5f	32	plan9	PUNPCKHDQ 0(CX), X2
-660f6a11|223344556677885f5f5f5f5f	64	gnu	punpckhdq (%rcx),%xmm2
-660f6a11|223344556677885f5f5f5f5f	64	intel	punpckhdq xmm2, xmmword ptr [rcx]
-660f6a11|223344556677885f5f5f5f5f	64	plan9	PUNPCKHDQ 0(CX), X2
-660f6b11|223344556677885f5f5f5f5f	32	intel	packssdw xmm2, xmmword ptr [ecx]
-660f6b11|223344556677885f5f5f5f5f	32	plan9	PACKSSDW 0(CX), X2
-660f6b11|223344556677885f5f5f5f5f	64	gnu	packssdw (%rcx),%xmm2
-660f6b11|223344556677885f5f5f5f5f	64	intel	packssdw xmm2, xmmword ptr [rcx]
-660f6b11|223344556677885f5f5f5f5f	64	plan9	PACKSSDW 0(CX), X2
-660f6c11|223344556677885f5f5f5f5f	32	intel	punpcklqdq xmm2, xmmword ptr [ecx]
-660f6c11|223344556677885f5f5f5f5f	32	plan9	PUNPCKLQDQ 0(CX), X2
-660f6c11|223344556677885f5f5f5f5f	64	gnu	punpcklqdq (%rcx),%xmm2
-660f6c11|223344556677885f5f5f5f5f	64	intel	punpcklqdq xmm2, xmmword ptr [rcx]
-660f6c11|223344556677885f5f5f5f5f	64	plan9	PUNPCKLQDQ 0(CX), X2
-660f6d11|223344556677885f5f5f5f5f	32	intel	punpckhqdq xmm2, xmmword ptr [ecx]
-660f6d11|223344556677885f5f5f5f5f	32	plan9	PUNPCKHQDQ 0(CX), X2
-660f6d11|223344556677885f5f5f5f5f	64	gnu	punpckhqdq (%rcx),%xmm2
-660f6d11|223344556677885f5f5f5f5f	64	intel	punpckhqdq xmm2, xmmword ptr [rcx]
-660f6d11|223344556677885f5f5f5f5f	64	plan9	PUNPCKHQDQ 0(CX), X2
-660f6e11|223344556677885f5f5f5f5f	32	intel	movd xmm2, dword ptr [ecx]
-660f6e11|223344556677885f5f5f5f5f	32	plan9	MOVD 0(CX), X2
-660f6e11|223344556677885f5f5f5f5f	64	gnu	movd (%rcx),%xmm2
-660f6e11|223344556677885f5f5f5f5f	64	intel	movd xmm2, dword ptr [rcx]
-660f6e11|223344556677885f5f5f5f5f	64	plan9	MOVD 0(CX), X2
-660f6f11|223344556677885f5f5f5f5f	32	intel	movdqa xmm2, xmmword ptr [ecx]
-660f6f11|223344556677885f5f5f5f5f	32	plan9	MOVDQA 0(CX), X2
-660f6f11|223344556677885f5f5f5f5f	64	gnu	movdqa (%rcx),%xmm2
-660f6f11|223344556677885f5f5f5f5f	64	intel	movdqa xmm2, xmmword ptr [rcx]
-660f6f11|223344556677885f5f5f5f5f	64	plan9	MOVDQA 0(CX), X2
-660f701122|3344556677885f5f5f5f5f	32	intel	pshufd xmm2, xmmword ptr [ecx], 0x22
-660f701122|3344556677885f5f5f5f5f	32	plan9	PSHUFD $0x22, 0(CX), X2
-660f701122|3344556677885f5f5f5f5f	64	gnu	pshufd $0x22,(%rcx),%xmm2
-660f701122|3344556677885f5f5f5f5f	64	intel	pshufd xmm2, xmmword ptr [rcx], 0x22
-660f701122|3344556677885f5f5f5f5f	64	plan9	PSHUFD $0x22, 0(CX), X2
-660f71d011|223344556677885f5f5f5f	32	intel	psrlw xmm0, 0x11
-660f71d011|223344556677885f5f5f5f	32	plan9	PSRLW $0x11, X0
-660f71d011|223344556677885f5f5f5f	64	gnu	psrlw $0x11,%xmm0
-660f71d011|223344556677885f5f5f5f	64	intel	psrlw xmm0, 0x11
-660f71d011|223344556677885f5f5f5f	64	plan9	PSRLW $0x11, X0
-660f71e011|223344556677885f5f5f5f	32	intel	psraw xmm0, 0x11
-660f71e011|223344556677885f5f5f5f	32	plan9	PSRAW $0x11, X0
-660f71e011|223344556677885f5f5f5f	64	gnu	psraw $0x11,%xmm0
-660f71e011|223344556677885f5f5f5f	64	intel	psraw xmm0, 0x11
-660f71e011|223344556677885f5f5f5f	64	plan9	PSRAW $0x11, X0
-660f71f011|223344556677885f5f5f5f	32	intel	psllw xmm0, 0x11
-660f71f011|223344556677885f5f5f5f	32	plan9	PSLLW $0x11, X0
-660f71f011|223344556677885f5f5f5f	64	gnu	psllw $0x11,%xmm0
-660f71f011|223344556677885f5f5f5f	64	intel	psllw xmm0, 0x11
-660f71f011|223344556677885f5f5f5f	64	plan9	PSLLW $0x11, X0
-660f72d011|223344556677885f5f5f5f	32	intel	psrld xmm0, 0x11
-660f72d011|223344556677885f5f5f5f	32	plan9	PSRLD $0x11, X0
-660f72d011|223344556677885f5f5f5f	64	gnu	psrld $0x11,%xmm0
-660f72d011|223344556677885f5f5f5f	64	intel	psrld xmm0, 0x11
-660f72d011|223344556677885f5f5f5f	64	plan9	PSRLD $0x11, X0
-660f72e011|223344556677885f5f5f5f	32	intel	psrad xmm0, 0x11
-660f72e011|223344556677885f5f5f5f	32	plan9	PSRAD $0x11, X0
-660f72e011|223344556677885f5f5f5f	64	gnu	psrad $0x11,%xmm0
-660f72e011|223344556677885f5f5f5f	64	intel	psrad xmm0, 0x11
-660f72e011|223344556677885f5f5f5f	64	plan9	PSRAD $0x11, X0
-660f72f011|223344556677885f5f5f5f	32	intel	pslld xmm0, 0x11
-660f72f011|223344556677885f5f5f5f	32	plan9	PSLLD $0x11, X0
-660f72f011|223344556677885f5f5f5f	64	gnu	pslld $0x11,%xmm0
-660f72f011|223344556677885f5f5f5f	64	intel	pslld xmm0, 0x11
-660f72f011|223344556677885f5f5f5f	64	plan9	PSLLD $0x11, X0
-660f73d011|223344556677885f5f5f5f	32	intel	psrlq xmm0, 0x11
-660f73d011|223344556677885f5f5f5f	32	plan9	PSRLQ $0x11, X0
-660f73d011|223344556677885f5f5f5f	64	gnu	psrlq $0x11,%xmm0
-660f73d011|223344556677885f5f5f5f	64	intel	psrlq xmm0, 0x11
-660f73d011|223344556677885f5f5f5f	64	plan9	PSRLQ $0x11, X0
-660f73d811|223344556677885f5f5f5f	32	intel	psrldq xmm0, 0x11
-660f73d811|223344556677885f5f5f5f	32	plan9	PSRLDQ $0x11, X0
-660f73d811|223344556677885f5f5f5f	64	gnu	psrldq $0x11,%xmm0
-660f73d811|223344556677885f5f5f5f	64	intel	psrldq xmm0, 0x11
-660f73d811|223344556677885f5f5f5f	64	plan9	PSRLDQ $0x11, X0
-660f73f011|223344556677885f5f5f5f	32	intel	psllq xmm0, 0x11
-660f73f011|223344556677885f5f5f5f	32	plan9	PSLLQ $0x11, X0
-660f73f011|223344556677885f5f5f5f	64	gnu	psllq $0x11,%xmm0
-660f73f011|223344556677885f5f5f5f	64	intel	psllq xmm0, 0x11
-660f73f011|223344556677885f5f5f5f	64	plan9	PSLLQ $0x11, X0
-660f73f811|223344556677885f5f5f5f	32	intel	pslldq xmm0, 0x11
-660f73f811|223344556677885f5f5f5f	32	plan9	PSLLDQ $0x11, X0
-660f73f811|223344556677885f5f5f5f	64	gnu	pslldq $0x11,%xmm0
-660f73f811|223344556677885f5f5f5f	64	intel	pslldq xmm0, 0x11
-660f73f811|223344556677885f5f5f5f	64	plan9	PSLLDQ $0x11, X0
-660f7411|223344556677885f5f5f5f5f	32	intel	pcmpeqb xmm2, xmmword ptr [ecx]
-660f7411|223344556677885f5f5f5f5f	32	plan9	PCMPEQB 0(CX), X2
-660f7411|223344556677885f5f5f5f5f	64	gnu	pcmpeqb (%rcx),%xmm2
-660f7411|223344556677885f5f5f5f5f	64	intel	pcmpeqb xmm2, xmmword ptr [rcx]
-660f7411|223344556677885f5f5f5f5f	64	plan9	PCMPEQB 0(CX), X2
-660f7511|223344556677885f5f5f5f5f	32	intel	pcmpeqw xmm2, xmmword ptr [ecx]
-660f7511|223344556677885f5f5f5f5f	32	plan9	PCMPEQW 0(CX), X2
-660f7511|223344556677885f5f5f5f5f	64	gnu	pcmpeqw (%rcx),%xmm2
-660f7511|223344556677885f5f5f5f5f	64	intel	pcmpeqw xmm2, xmmword ptr [rcx]
-660f7511|223344556677885f5f5f5f5f	64	plan9	PCMPEQW 0(CX), X2
-660f7611|223344556677885f5f5f5f5f	32	intel	pcmpeqd xmm2, xmmword ptr [ecx]
-660f7611|223344556677885f5f5f5f5f	32	plan9	PCMPEQD 0(CX), X2
-660f7611|223344556677885f5f5f5f5f	64	gnu	pcmpeqd (%rcx),%xmm2
-660f7611|223344556677885f5f5f5f5f	64	intel	pcmpeqd xmm2, xmmword ptr [rcx]
-660f7611|223344556677885f5f5f5f5f	64	plan9	PCMPEQD 0(CX), X2
-660f7c11|223344556677885f5f5f5f5f	32	intel	haddpd xmm2, xmmword ptr [ecx]
-660f7c11|223344556677885f5f5f5f5f	32	plan9	HADDPD 0(CX), X2
-660f7c11|223344556677885f5f5f5f5f	64	gnu	haddpd (%rcx),%xmm2
-660f7c11|223344556677885f5f5f5f5f	64	intel	haddpd xmm2, xmmword ptr [rcx]
-660f7c11|223344556677885f5f5f5f5f	64	plan9	HADDPD 0(CX), X2
-660f7d11|223344556677885f5f5f5f5f	32	intel	hsubpd xmm2, xmmword ptr [ecx]
-660f7d11|223344556677885f5f5f5f5f	32	plan9	HSUBPD 0(CX), X2
-660f7d11|223344556677885f5f5f5f5f	64	gnu	hsubpd (%rcx),%xmm2
-660f7d11|223344556677885f5f5f5f5f	64	intel	hsubpd xmm2, xmmword ptr [rcx]
-660f7d11|223344556677885f5f5f5f5f	64	plan9	HSUBPD 0(CX), X2
-660f7e11|223344556677885f5f5f5f5f	32	intel	movd dword ptr [ecx], xmm2
-660f7e11|223344556677885f5f5f5f5f	32	plan9	MOVD X2, 0(CX)
-660f7e11|223344556677885f5f5f5f5f	64	gnu	movd %xmm2,(%rcx)
-660f7e11|223344556677885f5f5f5f5f	64	intel	movd dword ptr [rcx], xmm2
-660f7e11|223344556677885f5f5f5f5f	64	plan9	MOVD X2, 0(CX)
-660f7f11|223344556677885f5f5f5f5f	32	intel	movdqa xmmword ptr [ecx], xmm2
-660f7f11|223344556677885f5f5f5f5f	32	plan9	MOVDQA X2, 0(CX)
-660f7f11|223344556677885f5f5f5f5f	64	gnu	movdqa %xmm2,(%rcx)
-660f7f11|223344556677885f5f5f5f5f	64	intel	movdqa xmmword ptr [rcx], xmm2
-660f7f11|223344556677885f5f5f5f5f	64	plan9	MOVDQA X2, 0(CX)
-660f8011223344|556677885f5f5f5f5f	64	gnu	jo .+0x44332211
-660f8011223344|556677885f5f5f5f5f	64	intel	jo .+0x44332211
-660f8011223344|556677885f5f5f5f5f	64	plan9	JO .+1144201745
-660f801122|3344556677885f5f5f5f5f	32	intel	jo .+0x2211
-660f801122|3344556677885f5f5f5f5f	32	plan9	JO .+8721
-660f8111223344|556677885f5f5f5f5f	64	gnu	jno .+0x44332211
-660f8111223344|556677885f5f5f5f5f	64	intel	jno .+0x44332211
-660f8111223344|556677885f5f5f5f5f	64	plan9	JNO .+1144201745
-660f811122|3344556677885f5f5f5f5f	32	intel	jno .+0x2211
-660f811122|3344556677885f5f5f5f5f	32	plan9	JNO .+8721
-660f8211223344|556677885f5f5f5f5f	64	gnu	jb .+0x44332211
-660f8211223344|556677885f5f5f5f5f	64	intel	jb .+0x44332211
-660f8211223344|556677885f5f5f5f5f	64	plan9	JB .+1144201745
-660f821122|3344556677885f5f5f5f5f	32	intel	jb .+0x2211
-660f821122|3344556677885f5f5f5f5f	32	plan9	JB .+8721
-660f8311223344|556677885f5f5f5f5f	64	gnu	jae .+0x44332211
-660f8311223344|556677885f5f5f5f5f	64	intel	jnb .+0x44332211
-660f8311223344|556677885f5f5f5f5f	64	plan9	JAE .+1144201745
-660f831122|3344556677885f5f5f5f5f	32	intel	jnb .+0x2211
-660f831122|3344556677885f5f5f5f5f	32	plan9	JAE .+8721
-660f8411223344|556677885f5f5f5f5f	64	gnu	je .+0x44332211
-660f8411223344|556677885f5f5f5f5f	64	intel	jz .+0x44332211
-660f8411223344|556677885f5f5f5f5f	64	plan9	JE .+1144201745
-660f841122|3344556677885f5f5f5f5f	32	intel	jz .+0x2211
-660f841122|3344556677885f5f5f5f5f	32	plan9	JE .+8721
-660f8511223344|556677885f5f5f5f5f	64	gnu	jne .+0x44332211
-660f8511223344|556677885f5f5f5f5f	64	intel	jnz .+0x44332211
-660f8511223344|556677885f5f5f5f5f	64	plan9	JNE .+1144201745
-660f851122|3344556677885f5f5f5f5f	32	intel	jnz .+0x2211
-660f851122|3344556677885f5f5f5f5f	32	plan9	JNE .+8721
-660f8611223344|556677885f5f5f5f5f	64	gnu	jbe .+0x44332211
-660f8611223344|556677885f5f5f5f5f	64	intel	jbe .+0x44332211
-660f8611223344|556677885f5f5f5f5f	64	plan9	JBE .+1144201745
-660f861122|3344556677885f5f5f5f5f	32	intel	jbe .+0x2211
-660f861122|3344556677885f5f5f5f5f	32	plan9	JBE .+8721
-660f8711223344|556677885f5f5f5f5f	64	gnu	ja .+0x44332211
-660f8711223344|556677885f5f5f5f5f	64	intel	jnbe .+0x44332211
-660f8711223344|556677885f5f5f5f5f	64	plan9	JA .+1144201745
-660f871122|3344556677885f5f5f5f5f	32	intel	jnbe .+0x2211
-660f871122|3344556677885f5f5f5f5f	32	plan9	JA .+8721
-660f8811223344|556677885f5f5f5f5f	64	gnu	js .+0x44332211
-660f8811223344|556677885f5f5f5f5f	64	intel	js .+0x44332211
-660f8811223344|556677885f5f5f5f5f	64	plan9	JS .+1144201745
-660f881122|3344556677885f5f5f5f5f	32	intel	js .+0x2211
-660f881122|3344556677885f5f5f5f5f	32	plan9	JS .+8721
-660f8911223344|556677885f5f5f5f5f	64	gnu	jns .+0x44332211
-660f8911223344|556677885f5f5f5f5f	64	intel	jns .+0x44332211
-660f8911223344|556677885f5f5f5f5f	64	plan9	JNS .+1144201745
-660f891122|3344556677885f5f5f5f5f	32	intel	jns .+0x2211
-660f891122|3344556677885f5f5f5f5f	32	plan9	JNS .+8721
-660f8a11223344|556677885f5f5f5f5f	64	gnu	jp .+0x44332211
-660f8a11223344|556677885f5f5f5f5f	64	intel	jp .+0x44332211
-660f8a11223344|556677885f5f5f5f5f	64	plan9	JP .+1144201745
-660f8a1122|3344556677885f5f5f5f5f	32	intel	jp .+0x2211
-660f8a1122|3344556677885f5f5f5f5f	32	plan9	JP .+8721
-660f8b11223344|556677885f5f5f5f5f	64	gnu	jnp .+0x44332211
-660f8b11223344|556677885f5f5f5f5f	64	intel	jnp .+0x44332211
-660f8b11223344|556677885f5f5f5f5f	64	plan9	JNP .+1144201745
-660f8b1122|3344556677885f5f5f5f5f	32	intel	jnp .+0x2211
-660f8b1122|3344556677885f5f5f5f5f	32	plan9	JNP .+8721
-660f8c11223344|556677885f5f5f5f5f	64	gnu	jl .+0x44332211
-660f8c11223344|556677885f5f5f5f5f	64	intel	jl .+0x44332211
-660f8c11223344|556677885f5f5f5f5f	64	plan9	JL .+1144201745
-660f8c1122|3344556677885f5f5f5f5f	32	intel	jl .+0x2211
-660f8c1122|3344556677885f5f5f5f5f	32	plan9	JL .+8721
-660f8d11223344|556677885f5f5f5f5f	64	gnu	jge .+0x44332211
-660f8d11223344|556677885f5f5f5f5f	64	intel	jnl .+0x44332211
-660f8d11223344|556677885f5f5f5f5f	64	plan9	JGE .+1144201745
-660f8d1122|3344556677885f5f5f5f5f	32	intel	jnl .+0x2211
-660f8d1122|3344556677885f5f5f5f5f	32	plan9	JGE .+8721
-660f8e11223344|556677885f5f5f5f5f	64	gnu	jle .+0x44332211
-660f8e11223344|556677885f5f5f5f5f	64	intel	jle .+0x44332211
-660f8e11223344|556677885f5f5f5f5f	64	plan9	JLE .+1144201745
-660f8e1122|3344556677885f5f5f5f5f	32	intel	jle .+0x2211
-660f8e1122|3344556677885f5f5f5f5f	32	plan9	JLE .+8721
-660f8f11223344|556677885f5f5f5f5f	64	gnu	jg .+0x44332211
-660f8f11223344|556677885f5f5f5f5f	64	intel	jnle .+0x44332211
-660f8f11223344|556677885f5f5f5f5f	64	plan9	JG .+1144201745
-660f8f1122|3344556677885f5f5f5f5f	32	intel	jnle .+0x2211
-660f8f1122|3344556677885f5f5f5f5f	32	plan9	JG .+8721
-660fa1|11223344556677885f5f5f5f5f	32	intel	pop fs
-660fa1|11223344556677885f5f5f5f5f	32	plan9	POPW FS
-660fa1|11223344556677885f5f5f5f5f	64	gnu	popw %fs
-660fa1|11223344556677885f5f5f5f5f	64	intel	pop fs
-660fa1|11223344556677885f5f5f5f5f	64	plan9	POPW FS
-660fa311|223344556677885f5f5f5f5f	32	intel	bt word ptr [ecx], dx
-660fa311|223344556677885f5f5f5f5f	32	plan9	BTW DX, 0(CX)
-660fa311|223344556677885f5f5f5f5f	64	gnu	bt %dx,(%rcx)
-660fa311|223344556677885f5f5f5f5f	64	intel	bt word ptr [rcx], dx
-660fa311|223344556677885f5f5f5f5f	64	plan9	BTW DX, 0(CX)
-660fa41122|3344556677885f5f5f5f5f	32	intel	shld word ptr [ecx], dx, 0x22
-660fa41122|3344556677885f5f5f5f5f	32	plan9	SHLDW $0x22, DX, 0(CX)
-660fa41122|3344556677885f5f5f5f5f	64	gnu	shld $0x22,%dx,(%rcx)
-660fa41122|3344556677885f5f5f5f5f	64	intel	shld word ptr [rcx], dx, 0x22
-660fa41122|3344556677885f5f5f5f5f	64	plan9	SHLDW $0x22, DX, 0(CX)
-660fa511|223344556677885f5f5f5f5f	32	intel	shld word ptr [ecx], dx, cl
-660fa511|223344556677885f5f5f5f5f	32	plan9	SHLDW CL, DX, 0(CX)
-660fa511|223344556677885f5f5f5f5f	64	gnu	shld %cl,%dx,(%rcx)
-660fa511|223344556677885f5f5f5f5f	64	intel	shld word ptr [rcx], dx, cl
-660fa511|223344556677885f5f5f5f5f	64	plan9	SHLDW CL, DX, 0(CX)
-660fa9|11223344556677885f5f5f5f5f	32	intel	pop gs
-660fa9|11223344556677885f5f5f5f5f	32	plan9	POPW GS
-660fa9|11223344556677885f5f5f5f5f	64	gnu	popw %gs
-660fa9|11223344556677885f5f5f5f5f	64	intel	pop gs
-660fa9|11223344556677885f5f5f5f5f	64	plan9	POPW GS
-660fab11|223344556677885f5f5f5f5f	32	intel	bts word ptr [ecx], dx
-660fab11|223344556677885f5f5f5f5f	32	plan9	BTSW DX, 0(CX)
-660fab11|223344556677885f5f5f5f5f	64	gnu	bts %dx,(%rcx)
-660fab11|223344556677885f5f5f5f5f	64	intel	bts word ptr [rcx], dx
-660fab11|223344556677885f5f5f5f5f	64	plan9	BTSW DX, 0(CX)
-660fac1122|3344556677885f5f5f5f5f	32	intel	shrd word ptr [ecx], dx, 0x22
-660fac1122|3344556677885f5f5f5f5f	32	plan9	SHRDW $0x22, DX, 0(CX)
-660fac1122|3344556677885f5f5f5f5f	64	gnu	shrd $0x22,%dx,(%rcx)
-660fac1122|3344556677885f5f5f5f5f	64	intel	shrd word ptr [rcx], dx, 0x22
-660fac1122|3344556677885f5f5f5f5f	64	plan9	SHRDW $0x22, DX, 0(CX)
-660fad11|223344556677885f5f5f5f5f	32	intel	shrd word ptr [ecx], dx, cl
-660fad11|223344556677885f5f5f5f5f	32	plan9	SHRDW CL, DX, 0(CX)
-660fad11|223344556677885f5f5f5f5f	64	gnu	shrd %cl,%dx,(%rcx)
-660fad11|223344556677885f5f5f5f5f	64	intel	shrd word ptr [rcx], dx, cl
-660fad11|223344556677885f5f5f5f5f	64	plan9	SHRDW CL, DX, 0(CX)
-660fae00|11223344556677885f5f5f5f	32	intel	fxsave ptr [eax]
-660fae00|11223344556677885f5f5f5f	32	plan9	FXSAVE 0(AX)
-660fae00|11223344556677885f5f5f5f	64	gnu	fxsave (%rax)
-660fae00|11223344556677885f5f5f5f	64	intel	fxsave ptr [rax]
-660fae00|11223344556677885f5f5f5f	64	plan9	FXSAVE 0(AX)
-660fae08|11223344556677885f5f5f5f	32	intel	fxrstor ptr [eax]
-660fae08|11223344556677885f5f5f5f	32	plan9	FXRSTOR 0(AX)
-660fae08|11223344556677885f5f5f5f	64	gnu	data16 fxrstor (%rax)
-660fae08|11223344556677885f5f5f5f	64	intel	fxrstor ptr [rax]
-660fae08|11223344556677885f5f5f5f	64	plan9	FXRSTOR 0(AX)
-660fae20|11223344556677885f5f5f5f	32	intel	xsave ptr [eax]
-660fae20|11223344556677885f5f5f5f	32	plan9	XSAVE 0(AX)
-660fae20|11223344556677885f5f5f5f	64	gnu	data16 xsave (%rax)
-660fae20|11223344556677885f5f5f5f	64	intel	xsave ptr [rax]
-660fae20|11223344556677885f5f5f5f	64	plan9	XSAVE 0(AX)
-660fae28|11223344556677885f5f5f5f	32	intel	xrstor ptr [eax]
-660fae28|11223344556677885f5f5f5f	32	plan9	XRSTOR 0(AX)
-660fae28|11223344556677885f5f5f5f	64	gnu	data16 xrstor (%rax)
-660fae28|11223344556677885f5f5f5f	64	intel	xrstor ptr [rax]
-660fae28|11223344556677885f5f5f5f	64	plan9	XRSTOR 0(AX)
-660fae30|11223344556677885f5f5f5f	32	intel	xsaveopt ptr [eax]
-660fae30|11223344556677885f5f5f5f	32	plan9	XSAVEOPT 0(AX)
-660fae30|11223344556677885f5f5f5f	64	gnu	data16 xsaveopt (%rax)
-660fae30|11223344556677885f5f5f5f	64	intel	xsaveopt ptr [rax]
-660fae30|11223344556677885f5f5f5f	64	plan9	XSAVEOPT 0(AX)
-660faf11|223344556677885f5f5f5f5f	32	intel	imul dx, word ptr [ecx]
-660faf11|223344556677885f5f5f5f5f	32	plan9	IMULW 0(CX), DX
-660faf11|223344556677885f5f5f5f5f	64	gnu	imul (%rcx),%dx
-660faf11|223344556677885f5f5f5f5f	64	intel	imul dx, word ptr [rcx]
-660faf11|223344556677885f5f5f5f5f	64	plan9	IMULW 0(CX), DX
-660fb111|223344556677885f5f5f5f5f	32	intel	cmpxchg word ptr [ecx], dx
-660fb111|223344556677885f5f5f5f5f	32	plan9	CMPXCHGW DX, 0(CX)
-660fb111|223344556677885f5f5f5f5f	64	gnu	cmpxchg %dx,(%rcx)
-660fb111|223344556677885f5f5f5f5f	64	intel	cmpxchg word ptr [rcx], dx
-660fb111|223344556677885f5f5f5f5f	64	plan9	CMPXCHGW DX, 0(CX)
-660fb211|223344556677885f5f5f5f5f	32	intel	lss dx, dword ptr [ecx]
-660fb211|223344556677885f5f5f5f5f	32	plan9	LSS 0(CX), DX
-660fb211|223344556677885f5f5f5f5f	64	gnu	lss (%rcx),%dx
-660fb211|223344556677885f5f5f5f5f	64	intel	lss dx, dword ptr [rcx]
-660fb211|223344556677885f5f5f5f5f	64	plan9	LSS 0(CX), DX
-660fb311|223344556677885f5f5f5f5f	32	intel	btr word ptr [ecx], dx
-660fb311|223344556677885f5f5f5f5f	32	plan9	BTRW DX, 0(CX)
-660fb311|223344556677885f5f5f5f5f	64	gnu	btr %dx,(%rcx)
-660fb311|223344556677885f5f5f5f5f	64	intel	btr word ptr [rcx], dx
-660fb311|223344556677885f5f5f5f5f	64	plan9	BTRW DX, 0(CX)
-660fb411|223344556677885f5f5f5f5f	32	intel	lfs dx, dword ptr [ecx]
-660fb411|223344556677885f5f5f5f5f	32	plan9	LFS 0(CX), DX
-660fb411|223344556677885f5f5f5f5f	64	gnu	lfs (%rcx),%dx
-660fb411|223344556677885f5f5f5f5f	64	intel	lfs dx, dword ptr [rcx]
-660fb411|223344556677885f5f5f5f5f	64	plan9	LFS 0(CX), DX
-660fb511|223344556677885f5f5f5f5f	32	intel	lgs dx, dword ptr [ecx]
-660fb511|223344556677885f5f5f5f5f	32	plan9	LGS 0(CX), DX
-660fb511|223344556677885f5f5f5f5f	64	gnu	lgs (%rcx),%dx
-660fb511|223344556677885f5f5f5f5f	64	intel	lgs dx, dword ptr [rcx]
-660fb511|223344556677885f5f5f5f5f	64	plan9	LGS 0(CX), DX
-660fb611|223344556677885f5f5f5f5f	32	intel	movzx dx, byte ptr [ecx]
-660fb611|223344556677885f5f5f5f5f	32	plan9	MOVZX 0(CX), DX
-660fb611|223344556677885f5f5f5f5f	64	gnu	movzbw (%rcx),%dx
-660fb611|223344556677885f5f5f5f5f	64	intel	movzx dx, byte ptr [rcx]
-660fb611|223344556677885f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
-660fb711|223344556677885f5f5f5f5f	32	intel	movzx dx, word ptr [ecx]
-660fb711|223344556677885f5f5f5f5f	32	plan9	MOVZX 0(CX), DX
-660fb711|223344556677885f5f5f5f5f	64	gnu	movzww (%rcx),%dx
-660fb711|223344556677885f5f5f5f5f	64	intel	movzx dx, word ptr [rcx]
-660fb711|223344556677885f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
-660fba2011|223344556677885f5f5f5f	32	intel	bt word ptr [eax], 0x11
-660fba2011|223344556677885f5f5f5f	32	plan9	BTW $0x11, 0(AX)
-660fba2011|223344556677885f5f5f5f	64	gnu	btw $0x11,(%rax)
-660fba2011|223344556677885f5f5f5f	64	intel	bt word ptr [rax], 0x11
-660fba2011|223344556677885f5f5f5f	64	plan9	BTW $0x11, 0(AX)
-660fba2811|223344556677885f5f5f5f	32	intel	bts word ptr [eax], 0x11
-660fba2811|223344556677885f5f5f5f	32	plan9	BTSW $0x11, 0(AX)
-660fba2811|223344556677885f5f5f5f	64	gnu	btsw $0x11,(%rax)
-660fba2811|223344556677885f5f5f5f	64	intel	bts word ptr [rax], 0x11
-660fba2811|223344556677885f5f5f5f	64	plan9	BTSW $0x11, 0(AX)
-660fba3011|223344556677885f5f5f5f	32	intel	btr word ptr [eax], 0x11
-660fba3011|223344556677885f5f5f5f	32	plan9	BTRW $0x11, 0(AX)
-660fba3011|223344556677885f5f5f5f	64	gnu	btrw $0x11,(%rax)
-660fba3011|223344556677885f5f5f5f	64	intel	btr word ptr [rax], 0x11
-660fba3011|223344556677885f5f5f5f	64	plan9	BTRW $0x11, 0(AX)
-660fba3811|223344556677885f5f5f5f	32	intel	btc word ptr [eax], 0x11
-660fba3811|223344556677885f5f5f5f	32	plan9	BTCW $0x11, 0(AX)
-660fba3811|223344556677885f5f5f5f	64	gnu	btcw $0x11,(%rax)
-660fba3811|223344556677885f5f5f5f	64	intel	btc word ptr [rax], 0x11
-660fba3811|223344556677885f5f5f5f	64	plan9	BTCW $0x11, 0(AX)
-660fbb11|223344556677885f5f5f5f5f	32	intel	btc word ptr [ecx], dx
-660fbb11|223344556677885f5f5f5f5f	32	plan9	BTCW DX, 0(CX)
-660fbb11|223344556677885f5f5f5f5f	64	gnu	btc %dx,(%rcx)
-660fbb11|223344556677885f5f5f5f5f	64	intel	btc word ptr [rcx], dx
-660fbb11|223344556677885f5f5f5f5f	64	plan9	BTCW DX, 0(CX)
-660fbc11|223344556677885f5f5f5f5f	32	intel	bsf dx, word ptr [ecx]
-660fbc11|223344556677885f5f5f5f5f	32	plan9	BSFW 0(CX), DX
-660fbc11|223344556677885f5f5f5f5f	64	gnu	bsf (%rcx),%dx
-660fbc11|223344556677885f5f5f5f5f	64	intel	bsf dx, word ptr [rcx]
-660fbc11|223344556677885f5f5f5f5f	64	plan9	BSFW 0(CX), DX
-660fbd11|223344556677885f5f5f5f5f	32	intel	bsr dx, word ptr [ecx]
-660fbd11|223344556677885f5f5f5f5f	32	plan9	BSRW 0(CX), DX
-660fbd11|223344556677885f5f5f5f5f	64	gnu	bsr (%rcx),%dx
-660fbd11|223344556677885f5f5f5f5f	64	intel	bsr dx, word ptr [rcx]
-660fbd11|223344556677885f5f5f5f5f	64	plan9	BSRW 0(CX), DX
-660fbe11|223344556677885f5f5f5f5f	32	intel	movsx dx, byte ptr [ecx]
-660fbe11|223344556677885f5f5f5f5f	32	plan9	MOVSX 0(CX), DX
-660fbe11|223344556677885f5f5f5f5f	64	gnu	movsbw (%rcx),%dx
-660fbe11|223344556677885f5f5f5f5f	64	intel	movsx dx, byte ptr [rcx]
-660fbe11|223344556677885f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
-660fbf11|223344556677885f5f5f5f5f	32	intel	movsx dx, word ptr [ecx]
-660fbf11|223344556677885f5f5f5f5f	32	plan9	MOVSX 0(CX), DX
-660fbf11|223344556677885f5f5f5f5f	64	gnu	movsww (%rcx),%dx
-660fbf11|223344556677885f5f5f5f5f	64	intel	movsx dx, word ptr [rcx]
-660fbf11|223344556677885f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
-660fc111|223344556677885f5f5f5f5f	32	intel	xadd word ptr [ecx], dx
-660fc111|223344556677885f5f5f5f5f	32	plan9	XADDW DX, 0(CX)
-660fc111|223344556677885f5f5f5f5f	64	gnu	xadd %dx,(%rcx)
-660fc111|223344556677885f5f5f5f5f	64	intel	xadd word ptr [rcx], dx
-660fc111|223344556677885f5f5f5f5f	64	plan9	XADDW DX, 0(CX)
-660fc21122|3344556677885f5f5f5f5f	32	intel	cmppd xmm2, xmmword ptr [ecx], 0x22
-660fc21122|3344556677885f5f5f5f5f	32	plan9	CMPPD $0x22, 0(CX), X2
-660fc21122|3344556677885f5f5f5f5f	64	gnu	cmppd $0x22,(%rcx),%xmm2
-660fc21122|3344556677885f5f5f5f5f	64	intel	cmppd xmm2, xmmword ptr [rcx], 0x22
-660fc21122|3344556677885f5f5f5f5f	64	plan9	CMPPD $0x22, 0(CX), X2
-660fc311|223344556677885f5f5f5f5f	32	intel	movnti dword ptr [ecx], edx
-660fc311|223344556677885f5f5f5f5f	32	plan9	MOVNTIW DX, 0(CX)
-660fc311|223344556677885f5f5f5f5f	64	gnu	movnti %edx,(%rcx)
-660fc311|223344556677885f5f5f5f5f	64	intel	movnti dword ptr [rcx], edx
-660fc311|223344556677885f5f5f5f5f	64	plan9	MOVNTIW DX, 0(CX)
-660fc41122|3344556677885f5f5f5f5f	32	intel	pinsrw xmm2, word ptr [ecx], 0x22
-660fc41122|3344556677885f5f5f5f5f	32	plan9	PINSRW $0x22, 0(CX), X2
-660fc41122|3344556677885f5f5f5f5f	64	gnu	pinsrw $0x22,(%rcx),%xmm2
-660fc41122|3344556677885f5f5f5f5f	64	intel	pinsrw xmm2, word ptr [rcx], 0x22
-660fc41122|3344556677885f5f5f5f5f	64	plan9	PINSRW $0x22, 0(CX), X2
-660fc5c011|223344556677885f5f5f5f	32	intel	pextrw eax, xmm0, 0x11
-660fc5c011|223344556677885f5f5f5f	32	plan9	PEXTRW $0x11, X0, AX
-660fc5c011|223344556677885f5f5f5f	64	gnu	pextrw $0x11,%xmm0,%eax
-660fc5c011|223344556677885f5f5f5f	64	intel	pextrw eax, xmm0, 0x11
-660fc5c011|223344556677885f5f5f5f	64	plan9	PEXTRW $0x11, X0, AX
-660fc61122|3344556677885f5f5f5f5f	32	intel	shufpd xmm2, xmmword ptr [ecx], 0x22
-660fc61122|3344556677885f5f5f5f5f	32	plan9	SHUFPD $0x22, 0(CX), X2
-660fc61122|3344556677885f5f5f5f5f	64	gnu	shufpd $0x22,(%rcx),%xmm2
-660fc61122|3344556677885f5f5f5f5f	64	intel	shufpd xmm2, xmmword ptr [rcx], 0x22
-660fc61122|3344556677885f5f5f5f5f	64	plan9	SHUFPD $0x22, 0(CX), X2
-660fc708|11223344556677885f5f5f5f	32	intel	cmpxchg8b qword ptr [eax]
-660fc708|11223344556677885f5f5f5f	32	plan9	CMPXCHG8B 0(AX)
-660fc708|11223344556677885f5f5f5f	64	gnu	data16 cmpxchg8b (%rax)
-660fc708|11223344556677885f5f5f5f	64	intel	cmpxchg8b qword ptr [rax]
-660fc708|11223344556677885f5f5f5f	64	plan9	CMPXCHG8B 0(AX)
-660fc718|11223344556677885f5f5f5f	32	intel	xrstors ptr [eax]
-660fc718|11223344556677885f5f5f5f	32	plan9	XRSTORS 0(AX)
-660fc718|11223344556677885f5f5f5f	64	gnu	xrstors (%rax)
-660fc718|11223344556677885f5f5f5f	64	intel	xrstors ptr [rax]
-660fc718|11223344556677885f5f5f5f	64	plan9	XRSTORS 0(AX)
-660fc720|11223344556677885f5f5f5f	32	intel	xsavec ptr [eax]
-660fc720|11223344556677885f5f5f5f	32	plan9	XSAVEC 0(AX)
-660fc720|11223344556677885f5f5f5f	64	gnu	xsavec (%rax)
-660fc720|11223344556677885f5f5f5f	64	intel	xsavec ptr [rax]
-660fc720|11223344556677885f5f5f5f	64	plan9	XSAVEC 0(AX)
-660fc728|11223344556677885f5f5f5f	32	intel	xsaves ptr [eax]
-660fc728|11223344556677885f5f5f5f	32	plan9	XSAVES 0(AX)
-660fc728|11223344556677885f5f5f5f	64	gnu	xsaves (%rax)
-660fc728|11223344556677885f5f5f5f	64	intel	xsaves ptr [rax]
-660fc728|11223344556677885f5f5f5f	64	plan9	XSAVES 0(AX)
-660fc7f2|11223344556677885f5f5f5f	32	intel	rdrand dx
-660fc7f2|11223344556677885f5f5f5f	32	plan9	RDRAND DX
-660fc7f2|11223344556677885f5f5f5f	64	gnu	rdrand %dx
-660fc7f2|11223344556677885f5f5f5f	64	intel	rdrand dx
-660fc7f2|11223344556677885f5f5f5f	64	plan9	RDRAND DX
-660fc8|11223344556677885f5f5f5f5f	32	intel	bswap ax
-660fc8|11223344556677885f5f5f5f5f	32	plan9	BSWAP AX
-660fc8|11223344556677885f5f5f5f5f	64	gnu	bswap %ax
-660fc8|11223344556677885f5f5f5f5f	64	intel	bswap ax
-660fc8|11223344556677885f5f5f5f5f	64	plan9	BSWAP AX
-660fd011|223344556677885f5f5f5f5f	32	intel	addsubpd xmm2, xmmword ptr [ecx]
-660fd011|223344556677885f5f5f5f5f	32	plan9	ADDSUBPD 0(CX), X2
-660fd011|223344556677885f5f5f5f5f	64	gnu	addsubpd (%rcx),%xmm2
-660fd011|223344556677885f5f5f5f5f	64	intel	addsubpd xmm2, xmmword ptr [rcx]
-660fd011|223344556677885f5f5f5f5f	64	plan9	ADDSUBPD 0(CX), X2
-660fd111|223344556677885f5f5f5f5f	32	intel	psrlw xmm2, xmmword ptr [ecx]
-660fd111|223344556677885f5f5f5f5f	32	plan9	PSRLW 0(CX), X2
-660fd111|223344556677885f5f5f5f5f	64	gnu	psrlw (%rcx),%xmm2
-660fd111|223344556677885f5f5f5f5f	64	intel	psrlw xmm2, xmmword ptr [rcx]
-660fd111|223344556677885f5f5f5f5f	64	plan9	PSRLW 0(CX), X2
-660fd211|223344556677885f5f5f5f5f	32	intel	psrld xmm2, xmmword ptr [ecx]
-660fd211|223344556677885f5f5f5f5f	32	plan9	PSRLD 0(CX), X2
-660fd211|223344556677885f5f5f5f5f	64	gnu	psrld (%rcx),%xmm2
-660fd211|223344556677885f5f5f5f5f	64	intel	psrld xmm2, xmmword ptr [rcx]
-660fd211|223344556677885f5f5f5f5f	64	plan9	PSRLD 0(CX), X2
-660fd311|223344556677885f5f5f5f5f	32	intel	psrlq xmm2, xmmword ptr [ecx]
-660fd311|223344556677885f5f5f5f5f	32	plan9	PSRLQ 0(CX), X2
-660fd311|223344556677885f5f5f5f5f	64	gnu	psrlq (%rcx),%xmm2
-660fd311|223344556677885f5f5f5f5f	64	intel	psrlq xmm2, xmmword ptr [rcx]
-660fd311|223344556677885f5f5f5f5f	64	plan9	PSRLQ 0(CX), X2
-660fd411|223344556677885f5f5f5f5f	32	intel	paddq xmm2, xmmword ptr [ecx]
-660fd411|223344556677885f5f5f5f5f	32	plan9	PADDQ 0(CX), X2
-660fd411|223344556677885f5f5f5f5f	64	gnu	paddq (%rcx),%xmm2
-660fd411|223344556677885f5f5f5f5f	64	intel	paddq xmm2, xmmword ptr [rcx]
-660fd411|223344556677885f5f5f5f5f	64	plan9	PADDQ 0(CX), X2
-660fd511|223344556677885f5f5f5f5f	32	intel	pmullw xmm2, xmmword ptr [ecx]
-660fd511|223344556677885f5f5f5f5f	32	plan9	PMULLW 0(CX), X2
-660fd511|223344556677885f5f5f5f5f	64	gnu	pmullw (%rcx),%xmm2
-660fd511|223344556677885f5f5f5f5f	64	intel	pmullw xmm2, xmmword ptr [rcx]
-660fd511|223344556677885f5f5f5f5f	64	plan9	PMULLW 0(CX), X2
-660fd611|223344556677885f5f5f5f5f	32	intel	movq qword ptr [ecx], xmm2
-660fd611|223344556677885f5f5f5f5f	32	plan9	MOVQ X2, 0(CX)
-660fd611|223344556677885f5f5f5f5f	64	gnu	movq %xmm2,(%rcx)
-660fd611|223344556677885f5f5f5f5f	64	intel	movq qword ptr [rcx], xmm2
-660fd611|223344556677885f5f5f5f5f	64	plan9	MOVQ X2, 0(CX)
-660fd7c0|11223344556677885f5f5f5f	32	intel	pmovmskb eax, xmm0
-660fd7c0|11223344556677885f5f5f5f	32	plan9	PMOVMSKB X0, AX
-660fd7c0|11223344556677885f5f5f5f	64	gnu	pmovmskb %xmm0,%eax
-660fd7c0|11223344556677885f5f5f5f	64	intel	pmovmskb eax, xmm0
-660fd7c0|11223344556677885f5f5f5f	64	plan9	PMOVMSKB X0, AX
-660fd811|223344556677885f5f5f5f5f	32	intel	psubusb xmm2, xmmword ptr [ecx]
-660fd811|223344556677885f5f5f5f5f	32	plan9	PSUBUSB 0(CX), X2
-660fd811|223344556677885f5f5f5f5f	64	gnu	psubusb (%rcx),%xmm2
-660fd811|223344556677885f5f5f5f5f	64	intel	psubusb xmm2, xmmword ptr [rcx]
-660fd811|223344556677885f5f5f5f5f	64	plan9	PSUBUSB 0(CX), X2
-660fd911|223344556677885f5f5f5f5f	32	intel	psubusw xmm2, xmmword ptr [ecx]
-660fd911|223344556677885f5f5f5f5f	32	plan9	PSUBUSW 0(CX), X2
-660fd911|223344556677885f5f5f5f5f	64	gnu	psubusw (%rcx),%xmm2
-660fd911|223344556677885f5f5f5f5f	64	intel	psubusw xmm2, xmmword ptr [rcx]
-660fd911|223344556677885f5f5f5f5f	64	plan9	PSUBUSW 0(CX), X2
-660fda11|223344556677885f5f5f5f5f	32	intel	pminub xmm2, xmmword ptr [ecx]
-660fda11|223344556677885f5f5f5f5f	32	plan9	PMINUB 0(CX), X2
-660fda11|223344556677885f5f5f5f5f	64	gnu	pminub (%rcx),%xmm2
-660fda11|223344556677885f5f5f5f5f	64	intel	pminub xmm2, xmmword ptr [rcx]
-660fda11|223344556677885f5f5f5f5f	64	plan9	PMINUB 0(CX), X2
-660fdb11|223344556677885f5f5f5f5f	32	intel	pand xmm2, xmmword ptr [ecx]
-660fdb11|223344556677885f5f5f5f5f	32	plan9	PAND 0(CX), X2
-660fdb11|223344556677885f5f5f5f5f	64	gnu	pand (%rcx),%xmm2
-660fdb11|223344556677885f5f5f5f5f	64	intel	pand xmm2, xmmword ptr [rcx]
-660fdb11|223344556677885f5f5f5f5f	64	plan9	PAND 0(CX), X2
-660fdc11|223344556677885f5f5f5f5f	32	intel	paddusb xmm2, xmmword ptr [ecx]
-660fdc11|223344556677885f5f5f5f5f	32	plan9	PADDUSB 0(CX), X2
-660fdc11|223344556677885f5f5f5f5f	64	gnu	paddusb (%rcx),%xmm2
-660fdc11|223344556677885f5f5f5f5f	64	intel	paddusb xmm2, xmmword ptr [rcx]
-660fdc11|223344556677885f5f5f5f5f	64	plan9	PADDUSB 0(CX), X2
-660fdd11|223344556677885f5f5f5f5f	32	intel	paddusw xmm2, xmmword ptr [ecx]
-660fdd11|223344556677885f5f5f5f5f	32	plan9	PADDUSW 0(CX), X2
-660fdd11|223344556677885f5f5f5f5f	64	gnu	paddusw (%rcx),%xmm2
-660fdd11|223344556677885f5f5f5f5f	64	intel	paddusw xmm2, xmmword ptr [rcx]
-660fdd11|223344556677885f5f5f5f5f	64	plan9	PADDUSW 0(CX), X2
-660fde11|223344556677885f5f5f5f5f	32	intel	pmaxub xmm2, xmmword ptr [ecx]
-660fde11|223344556677885f5f5f5f5f	32	plan9	PMAXUB 0(CX), X2
-660fde11|223344556677885f5f5f5f5f	64	gnu	pmaxub (%rcx),%xmm2
-660fde11|223344556677885f5f5f5f5f	64	intel	pmaxub xmm2, xmmword ptr [rcx]
-660fde11|223344556677885f5f5f5f5f	64	plan9	PMAXUB 0(CX), X2
-660fdf11|223344556677885f5f5f5f5f	32	intel	pandn xmm2, xmmword ptr [ecx]
-660fdf11|223344556677885f5f5f5f5f	32	plan9	PANDN 0(CX), X2
-660fdf11|223344556677885f5f5f5f5f	64	gnu	pandn (%rcx),%xmm2
-660fdf11|223344556677885f5f5f5f5f	64	intel	pandn xmm2, xmmword ptr [rcx]
-660fdf11|223344556677885f5f5f5f5f	64	plan9	PANDN 0(CX), X2
-660fe011|223344556677885f5f5f5f5f	32	intel	pavgb xmm2, xmmword ptr [ecx]
-660fe011|223344556677885f5f5f5f5f	32	plan9	PAVGB 0(CX), X2
-660fe011|223344556677885f5f5f5f5f	64	gnu	pavgb (%rcx),%xmm2
-660fe011|223344556677885f5f5f5f5f	64	intel	pavgb xmm2, xmmword ptr [rcx]
-660fe011|223344556677885f5f5f5f5f	64	plan9	PAVGB 0(CX), X2
-660fe111|223344556677885f5f5f5f5f	32	intel	psraw xmm2, xmmword ptr [ecx]
-660fe111|223344556677885f5f5f5f5f	32	plan9	PSRAW 0(CX), X2
-660fe111|223344556677885f5f5f5f5f	64	gnu	psraw (%rcx),%xmm2
-660fe111|223344556677885f5f5f5f5f	64	intel	psraw xmm2, xmmword ptr [rcx]
-660fe111|223344556677885f5f5f5f5f	64	plan9	PSRAW 0(CX), X2
-660fe211|223344556677885f5f5f5f5f	32	intel	psrad xmm2, xmmword ptr [ecx]
-660fe211|223344556677885f5f5f5f5f	32	plan9	PSRAD 0(CX), X2
-660fe211|223344556677885f5f5f5f5f	64	gnu	psrad (%rcx),%xmm2
-660fe211|223344556677885f5f5f5f5f	64	intel	psrad xmm2, xmmword ptr [rcx]
-660fe211|223344556677885f5f5f5f5f	64	plan9	PSRAD 0(CX), X2
-660fe311|223344556677885f5f5f5f5f	32	intel	pavgw xmm2, xmmword ptr [ecx]
-660fe311|223344556677885f5f5f5f5f	32	plan9	PAVGW 0(CX), X2
-660fe311|223344556677885f5f5f5f5f	64	gnu	pavgw (%rcx),%xmm2
-660fe311|223344556677885f5f5f5f5f	64	intel	pavgw xmm2, xmmword ptr [rcx]
-660fe311|223344556677885f5f5f5f5f	64	plan9	PAVGW 0(CX), X2
-660fe411|223344556677885f5f5f5f5f	32	intel	pmulhuw xmm2, xmmword ptr [ecx]
-660fe411|223344556677885f5f5f5f5f	32	plan9	PMULHUW 0(CX), X2
-660fe411|223344556677885f5f5f5f5f	64	gnu	pmulhuw (%rcx),%xmm2
-660fe411|223344556677885f5f5f5f5f	64	intel	pmulhuw xmm2, xmmword ptr [rcx]
-660fe411|223344556677885f5f5f5f5f	64	plan9	PMULHUW 0(CX), X2
-660fe511|223344556677885f5f5f5f5f	32	intel	pmulhw xmm2, xmmword ptr [ecx]
-660fe511|223344556677885f5f5f5f5f	32	plan9	PMULHW 0(CX), X2
-660fe511|223344556677885f5f5f5f5f	64	gnu	pmulhw (%rcx),%xmm2
-660fe511|223344556677885f5f5f5f5f	64	intel	pmulhw xmm2, xmmword ptr [rcx]
-660fe511|223344556677885f5f5f5f5f	64	plan9	PMULHW 0(CX), X2
-660fe611|223344556677885f5f5f5f5f	32	intel	cvttpd2dq xmm2, xmmword ptr [ecx]
-660fe611|223344556677885f5f5f5f5f	32	plan9	CVTTPD2DQ 0(CX), X2
-660fe611|223344556677885f5f5f5f5f	64	gnu	cvttpd2dq (%rcx),%xmm2
-660fe611|223344556677885f5f5f5f5f	64	intel	cvttpd2dq xmm2, xmmword ptr [rcx]
-660fe611|223344556677885f5f5f5f5f	64	plan9	CVTTPD2DQ 0(CX), X2
-660fe711|223344556677885f5f5f5f5f	32	intel	movntdq xmmword ptr [ecx], xmm2
-660fe711|223344556677885f5f5f5f5f	32	plan9	MOVNTDQ X2, 0(CX)
-660fe711|223344556677885f5f5f5f5f	64	gnu	movntdq %xmm2,(%rcx)
-660fe711|223344556677885f5f5f5f5f	64	intel	movntdq xmmword ptr [rcx], xmm2
-660fe711|223344556677885f5f5f5f5f	64	plan9	MOVNTDQ X2, 0(CX)
-660fe811|223344556677885f5f5f5f5f	32	intel	psubsb xmm2, xmmword ptr [ecx]
-660fe811|223344556677885f5f5f5f5f	32	plan9	PSUBSB 0(CX), X2
-660fe811|223344556677885f5f5f5f5f	64	gnu	psubsb (%rcx),%xmm2
-660fe811|223344556677885f5f5f5f5f	64	intel	psubsb xmm2, xmmword ptr [rcx]
-660fe811|223344556677885f5f5f5f5f	64	plan9	PSUBSB 0(CX), X2
-660fe911|223344556677885f5f5f5f5f	32	intel	psubsw xmm2, xmmword ptr [ecx]
-660fe911|223344556677885f5f5f5f5f	32	plan9	PSUBSW 0(CX), X2
-660fe911|223344556677885f5f5f5f5f	64	gnu	psubsw (%rcx),%xmm2
-660fe911|223344556677885f5f5f5f5f	64	intel	psubsw xmm2, xmmword ptr [rcx]
-660fe911|223344556677885f5f5f5f5f	64	plan9	PSUBSW 0(CX), X2
-660fea11|223344556677885f5f5f5f5f	32	intel	pminsw xmm2, xmmword ptr [ecx]
-660fea11|223344556677885f5f5f5f5f	32	plan9	PMINSW 0(CX), X2
-660fea11|223344556677885f5f5f5f5f	64	gnu	pminsw (%rcx),%xmm2
-660fea11|223344556677885f5f5f5f5f	64	intel	pminsw xmm2, xmmword ptr [rcx]
-660fea11|223344556677885f5f5f5f5f	64	plan9	PMINSW 0(CX), X2
-660feb11|223344556677885f5f5f5f5f	32	intel	por xmm2, xmmword ptr [ecx]
-660feb11|223344556677885f5f5f5f5f	32	plan9	POR 0(CX), X2
-660feb11|223344556677885f5f5f5f5f	64	gnu	por (%rcx),%xmm2
-660feb11|223344556677885f5f5f5f5f	64	intel	por xmm2, xmmword ptr [rcx]
-660feb11|223344556677885f5f5f5f5f	64	plan9	POR 0(CX), X2
-660fec11|223344556677885f5f5f5f5f	32	intel	paddsb xmm2, xmmword ptr [ecx]
-660fec11|223344556677885f5f5f5f5f	32	plan9	PADDSB 0(CX), X2
-660fec11|223344556677885f5f5f5f5f	64	gnu	paddsb (%rcx),%xmm2
-660fec11|223344556677885f5f5f5f5f	64	intel	paddsb xmm2, xmmword ptr [rcx]
-660fec11|223344556677885f5f5f5f5f	64	plan9	PADDSB 0(CX), X2
-660fed11|223344556677885f5f5f5f5f	32	intel	paddsw xmm2, xmmword ptr [ecx]
-660fed11|223344556677885f5f5f5f5f	32	plan9	PADDSW 0(CX), X2
-660fed11|223344556677885f5f5f5f5f	64	gnu	paddsw (%rcx),%xmm2
-660fed11|223344556677885f5f5f5f5f	64	intel	paddsw xmm2, xmmword ptr [rcx]
-660fed11|223344556677885f5f5f5f5f	64	plan9	PADDSW 0(CX), X2
-660fee11|223344556677885f5f5f5f5f	32	intel	pmaxsw xmm2, xmmword ptr [ecx]
-660fee11|223344556677885f5f5f5f5f	32	plan9	PMAXSW 0(CX), X2
-660fee11|223344556677885f5f5f5f5f	64	gnu	pmaxsw (%rcx),%xmm2
-660fee11|223344556677885f5f5f5f5f	64	intel	pmaxsw xmm2, xmmword ptr [rcx]
-660fee11|223344556677885f5f5f5f5f	64	plan9	PMAXSW 0(CX), X2
-660fef11|223344556677885f5f5f5f5f	32	intel	pxor xmm2, xmmword ptr [ecx]
-660fef11|223344556677885f5f5f5f5f	32	plan9	PXOR 0(CX), X2
-660fef11|223344556677885f5f5f5f5f	64	gnu	pxor (%rcx),%xmm2
-660fef11|223344556677885f5f5f5f5f	64	intel	pxor xmm2, xmmword ptr [rcx]
-660fef11|223344556677885f5f5f5f5f	64	plan9	PXOR 0(CX), X2
-660ff111|223344556677885f5f5f5f5f	32	intel	psllw xmm2, xmmword ptr [ecx]
-660ff111|223344556677885f5f5f5f5f	32	plan9	PSLLW 0(CX), X2
-660ff111|223344556677885f5f5f5f5f	64	gnu	psllw (%rcx),%xmm2
-660ff111|223344556677885f5f5f5f5f	64	intel	psllw xmm2, xmmword ptr [rcx]
-660ff111|223344556677885f5f5f5f5f	64	plan9	PSLLW 0(CX), X2
-660ff211|223344556677885f5f5f5f5f	32	intel	pslld xmm2, xmmword ptr [ecx]
-660ff211|223344556677885f5f5f5f5f	32	plan9	PSLLD 0(CX), X2
-660ff211|223344556677885f5f5f5f5f	64	gnu	pslld (%rcx),%xmm2
-660ff211|223344556677885f5f5f5f5f	64	intel	pslld xmm2, xmmword ptr [rcx]
-660ff211|223344556677885f5f5f5f5f	64	plan9	PSLLD 0(CX), X2
-660ff311|223344556677885f5f5f5f5f	32	intel	psllq xmm2, xmmword ptr [ecx]
-660ff311|223344556677885f5f5f5f5f	32	plan9	PSLLQ 0(CX), X2
-660ff311|223344556677885f5f5f5f5f	64	gnu	psllq (%rcx),%xmm2
-660ff311|223344556677885f5f5f5f5f	64	intel	psllq xmm2, xmmword ptr [rcx]
-660ff311|223344556677885f5f5f5f5f	64	plan9	PSLLQ 0(CX), X2
-660ff411|223344556677885f5f5f5f5f	32	intel	pmuludq xmm2, xmmword ptr [ecx]
-660ff411|223344556677885f5f5f5f5f	32	plan9	PMULUDQ 0(CX), X2
-660ff411|223344556677885f5f5f5f5f	64	gnu	pmuludq (%rcx),%xmm2
-660ff411|223344556677885f5f5f5f5f	64	intel	pmuludq xmm2, xmmword ptr [rcx]
-660ff411|223344556677885f5f5f5f5f	64	plan9	PMULUDQ 0(CX), X2
-660ff511|223344556677885f5f5f5f5f	32	intel	pmaddwd xmm2, xmmword ptr [ecx]
-660ff511|223344556677885f5f5f5f5f	32	plan9	PMADDWD 0(CX), X2
-660ff511|223344556677885f5f5f5f5f	64	gnu	pmaddwd (%rcx),%xmm2
-660ff511|223344556677885f5f5f5f5f	64	intel	pmaddwd xmm2, xmmword ptr [rcx]
-660ff511|223344556677885f5f5f5f5f	64	plan9	PMADDWD 0(CX), X2
-660ff611|223344556677885f5f5f5f5f	32	intel	psadbw xmm2, xmmword ptr [ecx]
-660ff611|223344556677885f5f5f5f5f	32	plan9	PSADBW 0(CX), X2
-660ff611|223344556677885f5f5f5f5f	64	gnu	psadbw (%rcx),%xmm2
-660ff611|223344556677885f5f5f5f5f	64	intel	psadbw xmm2, xmmword ptr [rcx]
-660ff611|223344556677885f5f5f5f5f	64	plan9	PSADBW 0(CX), X2
-660ff7c0|11223344556677885f5f5f5f	32	intel	maskmovdqu xmm0, xmm0
-660ff7c0|11223344556677885f5f5f5f	32	plan9	MASKMOVDQU X0, X0
-660ff7c0|11223344556677885f5f5f5f	64	intel	maskmovdqu xmm0, xmm0
-660ff7c0|11223344556677885f5f5f5f	64	plan9	MASKMOVDQU X0, X0
-660ff811|223344556677885f5f5f5f5f	32	intel	psubb xmm2, xmmword ptr [ecx]
-660ff811|223344556677885f5f5f5f5f	32	plan9	PSUBB 0(CX), X2
-660ff811|223344556677885f5f5f5f5f	64	gnu	psubb (%rcx),%xmm2
-660ff811|223344556677885f5f5f5f5f	64	intel	psubb xmm2, xmmword ptr [rcx]
-660ff811|223344556677885f5f5f5f5f	64	plan9	PSUBB 0(CX), X2
-660ff911|223344556677885f5f5f5f5f	32	intel	psubw xmm2, xmmword ptr [ecx]
-660ff911|223344556677885f5f5f5f5f	32	plan9	PSUBW 0(CX), X2
-660ff911|223344556677885f5f5f5f5f	64	gnu	psubw (%rcx),%xmm2
-660ff911|223344556677885f5f5f5f5f	64	intel	psubw xmm2, xmmword ptr [rcx]
-660ff911|223344556677885f5f5f5f5f	64	plan9	PSUBW 0(CX), X2
-660ffa11|223344556677885f5f5f5f5f	32	intel	psubd xmm2, xmmword ptr [ecx]
-660ffa11|223344556677885f5f5f5f5f	32	plan9	PSUBD 0(CX), X2
-660ffa11|223344556677885f5f5f5f5f	64	gnu	psubd (%rcx),%xmm2
-660ffa11|223344556677885f5f5f5f5f	64	intel	psubd xmm2, xmmword ptr [rcx]
-660ffa11|223344556677885f5f5f5f5f	64	plan9	PSUBD 0(CX), X2
-660ffb11|223344556677885f5f5f5f5f	32	intel	psubq xmm2, xmmword ptr [ecx]
-660ffb11|223344556677885f5f5f5f5f	32	plan9	PSUBQ 0(CX), X2
-660ffb11|223344556677885f5f5f5f5f	64	gnu	psubq (%rcx),%xmm2
-660ffb11|223344556677885f5f5f5f5f	64	intel	psubq xmm2, xmmword ptr [rcx]
-660ffb11|223344556677885f5f5f5f5f	64	plan9	PSUBQ 0(CX), X2
-660ffc11|223344556677885f5f5f5f5f	32	intel	paddb xmm2, xmmword ptr [ecx]
-660ffc11|223344556677885f5f5f5f5f	32	plan9	PADDB 0(CX), X2
-660ffc11|223344556677885f5f5f5f5f	64	gnu	paddb (%rcx),%xmm2
-660ffc11|223344556677885f5f5f5f5f	64	intel	paddb xmm2, xmmword ptr [rcx]
-660ffc11|223344556677885f5f5f5f5f	64	plan9	PADDB 0(CX), X2
-660ffd11|223344556677885f5f5f5f5f	32	intel	paddw xmm2, xmmword ptr [ecx]
-660ffd11|223344556677885f5f5f5f5f	32	plan9	PADDW 0(CX), X2
-660ffd11|223344556677885f5f5f5f5f	64	gnu	paddw (%rcx),%xmm2
-660ffd11|223344556677885f5f5f5f5f	64	intel	paddw xmm2, xmmword ptr [rcx]
-660ffd11|223344556677885f5f5f5f5f	64	plan9	PADDW 0(CX), X2
-660ffe11|223344556677885f5f5f5f5f	32	intel	paddd xmm2, xmmword ptr [ecx]
-660ffe11|223344556677885f5f5f5f5f	32	plan9	PADDD 0(CX), X2
-660ffe11|223344556677885f5f5f5f5f	64	gnu	paddd (%rcx),%xmm2
-660ffe11|223344556677885f5f5f5f5f	64	intel	paddd xmm2, xmmword ptr [rcx]
-660ffe11|223344556677885f5f5f5f5f	64	plan9	PADDD 0(CX), X2
-661122|3344556677885f5f5f5f5f5f5f	32	intel	adc word ptr [edx], sp
-661122|3344556677885f5f5f5f5f5f5f	32	plan9	ADCW SP, 0(DX)
-661122|3344556677885f5f5f5f5f5f5f	64	gnu	adc %sp,(%rdx)
-661122|3344556677885f5f5f5f5f5f5f	64	intel	adc word ptr [rdx], sp
-661122|3344556677885f5f5f5f5f5f5f	64	plan9	ADCW SP, 0(DX)
-661311|223344556677885f5f5f5f5f5f	32	intel	adc dx, word ptr [ecx]
-661311|223344556677885f5f5f5f5f5f	32	plan9	ADCW 0(CX), DX
-661311|223344556677885f5f5f5f5f5f	64	gnu	adc (%rcx),%dx
-661311|223344556677885f5f5f5f5f5f	64	intel	adc dx, word ptr [rcx]
-661311|223344556677885f5f5f5f5f5f	64	plan9	ADCW 0(CX), DX
-66151122|3344556677885f5f5f5f5f5f	32	intel	adc ax, 0x2211
-66151122|3344556677885f5f5f5f5f5f	32	plan9	ADCW $0x2211, AX
-66151122|3344556677885f5f5f5f5f5f	64	gnu	adc $0x2211,%ax
-66151122|3344556677885f5f5f5f5f5f	64	intel	adc ax, 0x2211
-66151122|3344556677885f5f5f5f5f5f	64	plan9	ADCW $0x2211, AX
-661911|223344556677885f5f5f5f5f5f	32	intel	sbb word ptr [ecx], dx
-661911|223344556677885f5f5f5f5f5f	32	plan9	SBBW DX, 0(CX)
-661911|223344556677885f5f5f5f5f5f	64	gnu	sbb %dx,(%rcx)
-661911|223344556677885f5f5f5f5f5f	64	intel	sbb word ptr [rcx], dx
-661911|223344556677885f5f5f5f5f5f	64	plan9	SBBW DX, 0(CX)
-661b11|223344556677885f5f5f5f5f5f	32	intel	sbb dx, word ptr [ecx]
-661b11|223344556677885f5f5f5f5f5f	32	plan9	SBBW 0(CX), DX
-661b11|223344556677885f5f5f5f5f5f	64	gnu	sbb (%rcx),%dx
-661b11|223344556677885f5f5f5f5f5f	64	intel	sbb dx, word ptr [rcx]
-661b11|223344556677885f5f5f5f5f5f	64	plan9	SBBW 0(CX), DX
-661d1122|3344556677885f5f5f5f5f5f	32	intel	sbb ax, 0x2211
-661d1122|3344556677885f5f5f5f5f5f	32	plan9	SBBW $0x2211, AX
-661d1122|3344556677885f5f5f5f5f5f	64	gnu	sbb $0x2211,%ax
-661d1122|3344556677885f5f5f5f5f5f	64	intel	sbb ax, 0x2211
-661d1122|3344556677885f5f5f5f5f5f	64	plan9	SBBW $0x2211, AX
-662111|223344556677885f5f5f5f5f5f	32	intel	and word ptr [ecx], dx
-662111|223344556677885f5f5f5f5f5f	32	plan9	ANDW DX, 0(CX)
-662111|223344556677885f5f5f5f5f5f	64	gnu	and %dx,(%rcx)
-662111|223344556677885f5f5f5f5f5f	64	intel	and word ptr [rcx], dx
-662111|223344556677885f5f5f5f5f5f	64	plan9	ANDW DX, 0(CX)
-662311|223344556677885f5f5f5f5f5f	32	intel	and dx, word ptr [ecx]
-662311|223344556677885f5f5f5f5f5f	32	plan9	ANDW 0(CX), DX
-662311|223344556677885f5f5f5f5f5f	64	gnu	and (%rcx),%dx
-662311|223344556677885f5f5f5f5f5f	64	intel	and dx, word ptr [rcx]
-662311|223344556677885f5f5f5f5f5f	64	plan9	ANDW 0(CX), DX
-66251122|3344556677885f5f5f5f5f5f	32	intel	and ax, 0x2211
-66251122|3344556677885f5f5f5f5f5f	32	plan9	ANDW $0x2211, AX
-66251122|3344556677885f5f5f5f5f5f	64	gnu	and $0x2211,%ax
-66251122|3344556677885f5f5f5f5f5f	64	intel	and ax, 0x2211
-66251122|3344556677885f5f5f5f5f5f	64	plan9	ANDW $0x2211, AX
-662911|223344556677885f5f5f5f5f5f	32	intel	sub word ptr [ecx], dx
-662911|223344556677885f5f5f5f5f5f	32	plan9	SUBW DX, 0(CX)
-662911|223344556677885f5f5f5f5f5f	64	gnu	sub %dx,(%rcx)
-662911|223344556677885f5f5f5f5f5f	64	intel	sub word ptr [rcx], dx
-662911|223344556677885f5f5f5f5f5f	64	plan9	SUBW DX, 0(CX)
-662b11|223344556677885f5f5f5f5f5f	32	intel	sub dx, word ptr [ecx]
-662b11|223344556677885f5f5f5f5f5f	32	plan9	SUBW 0(CX), DX
-662b11|223344556677885f5f5f5f5f5f	64	gnu	sub (%rcx),%dx
-662b11|223344556677885f5f5f5f5f5f	64	intel	sub dx, word ptr [rcx]
-662b11|223344556677885f5f5f5f5f5f	64	plan9	SUBW 0(CX), DX
-662d1122|3344556677885f5f5f5f5f5f	32	intel	sub ax, 0x2211
-662d1122|3344556677885f5f5f5f5f5f	32	plan9	SUBW $0x2211, AX
-662d1122|3344556677885f5f5f5f5f5f	64	gnu	sub $0x2211,%ax
-662d1122|3344556677885f5f5f5f5f5f	64	intel	sub ax, 0x2211
-662d1122|3344556677885f5f5f5f5f5f	64	plan9	SUBW $0x2211, AX
-663111|223344556677885f5f5f5f5f5f	32	intel	xor word ptr [ecx], dx
-663111|223344556677885f5f5f5f5f5f	32	plan9	XORW DX, 0(CX)
-663111|223344556677885f5f5f5f5f5f	64	gnu	xor %dx,(%rcx)
-663111|223344556677885f5f5f5f5f5f	64	intel	xor word ptr [rcx], dx
-663111|223344556677885f5f5f5f5f5f	64	plan9	XORW DX, 0(CX)
-663311|223344556677885f5f5f5f5f5f	32	intel	xor dx, word ptr [ecx]
-663311|223344556677885f5f5f5f5f5f	32	plan9	XORW 0(CX), DX
-663311|223344556677885f5f5f5f5f5f	64	gnu	xor (%rcx),%dx
-663311|223344556677885f5f5f5f5f5f	64	intel	xor dx, word ptr [rcx]
-663311|223344556677885f5f5f5f5f5f	64	plan9	XORW 0(CX), DX
-66351122|3344556677885f5f5f5f5f5f	32	intel	xor ax, 0x2211
-66351122|3344556677885f5f5f5f5f5f	32	plan9	XORW $0x2211, AX
-66351122|3344556677885f5f5f5f5f5f	64	gnu	xor $0x2211,%ax
-66351122|3344556677885f5f5f5f5f5f	64	intel	xor ax, 0x2211
-66351122|3344556677885f5f5f5f5f5f	64	plan9	XORW $0x2211, AX
-663911|223344556677885f5f5f5f5f5f	32	intel	cmp word ptr [ecx], dx
-663911|223344556677885f5f5f5f5f5f	32	plan9	CMPW DX, 0(CX)
-663911|223344556677885f5f5f5f5f5f	64	gnu	cmp %dx,(%rcx)
-663911|223344556677885f5f5f5f5f5f	64	intel	cmp word ptr [rcx], dx
-663911|223344556677885f5f5f5f5f5f	64	plan9	CMPW DX, 0(CX)
-663b11|223344556677885f5f5f5f5f5f	32	intel	cmp dx, word ptr [ecx]
-663b11|223344556677885f5f5f5f5f5f	32	plan9	CMPW 0(CX), DX
-663b11|223344556677885f5f5f5f5f5f	64	gnu	cmp (%rcx),%dx
-663b11|223344556677885f5f5f5f5f5f	64	intel	cmp dx, word ptr [rcx]
-663b11|223344556677885f5f5f5f5f5f	64	plan9	CMPW 0(CX), DX
-663d1122|3344556677885f5f5f5f5f5f	32	intel	cmp ax, 0x2211
-663d1122|3344556677885f5f5f5f5f5f	32	plan9	CMPW $0x2211, AX
-663d1122|3344556677885f5f5f5f5f5f	64	gnu	cmp $0x2211,%ax
-663d1122|3344556677885f5f5f5f5f5f	64	intel	cmp ax, 0x2211
-663d1122|3344556677885f5f5f5f5f5f	64	plan9	CMPW $0x2211, AX
-6640|11223344556677885f5f5f5f5f5f	32	intel	inc ax
-6640|11223344556677885f5f5f5f5f5f	32	plan9	INCW AX
-66480f3a161122|3344556677885f5f5f	64	gnu	pextrq $0x22,%xmm2,(%rcx)
-66480f3a161122|3344556677885f5f5f	64	intel	pextrq qword ptr [rcx], xmm2, 0x22
-66480f3a161122|3344556677885f5f5f	64	plan9	PEXTRQ $0x22, X2, 0(CX)
-66480f3a221122|3344556677885f5f5f	64	gnu	pinsrq $0x22,(%rcx),%xmm2
-66480f3a221122|3344556677885f5f5f	64	intel	pinsrq xmm2, qword ptr [rcx], 0x22
-66480f3a221122|3344556677885f5f5f	64	plan9	PINSRQ $0x22, 0(CX), X2
-66480f6e11|223344556677885f5f5f5f	64	gnu	movq (%rcx),%xmm2
-66480f6e11|223344556677885f5f5f5f	64	intel	movq xmm2, qword ptr [rcx]
-66480f6e11|223344556677885f5f5f5f	64	plan9	MOVQ 0(CX), X2
-66480f7e11|223344556677885f5f5f5f	64	gnu	movq %xmm2,(%rcx)
-66480f7e11|223344556677885f5f5f5f	64	intel	movq qword ptr [rcx], xmm2
-66480f7e11|223344556677885f5f5f5f	64	plan9	MOVQ X2, 0(CX)
-6648|0f3a1611223344556677885f5f5f	32	intel	dec ax
-6648|0f3a1611223344556677885f5f5f	32	plan9	DECW AX
-6650|11223344556677885f5f5f5f5f5f	32	intel	push ax
-6650|11223344556677885f5f5f5f5f5f	32	plan9	PUSHW AX
-6650|11223344556677885f5f5f5f5f5f	64	gnu	push %ax
-6650|11223344556677885f5f5f5f5f5f	64	intel	push ax
-6650|11223344556677885f5f5f5f5f5f	64	plan9	PUSHW AX
-6658|11223344556677885f5f5f5f5f5f	32	intel	pop ax
-6658|11223344556677885f5f5f5f5f5f	32	plan9	POPW AX
-6658|11223344556677885f5f5f5f5f5f	64	gnu	pop %ax
-6658|11223344556677885f5f5f5f5f5f	64	intel	pop ax
-6658|11223344556677885f5f5f5f5f5f	64	plan9	POPW AX
-6660|11223344556677885f5f5f5f5f5f	32	intel	data16 pusha
-6660|11223344556677885f5f5f5f5f5f	32	plan9	PUSHAW
-6661|11223344556677885f5f5f5f5f5f	32	intel	data16 popa
-6661|11223344556677885f5f5f5f5f5f	32	plan9	POPAW
-666211|223344556677885f5f5f5f5f5f	32	intel	bound dx, qword ptr [ecx]
-666211|223344556677885f5f5f5f5f5f	32	plan9	BOUND 0(CX), DX
-666311|223344556677885f5f5f5f5f5f	64	gnu	movsxd (%rcx),%dx
-666311|223344556677885f5f5f5f5f5f	64	intel	movsxd dx, dword ptr [rcx]
-666311|223344556677885f5f5f5f5f5f	64	plan9	MOVSXD 0(CX), DX
-66681122|3344556677885f5f5f5f5f5f	32	intel	push 0x2211
-66681122|3344556677885f5f5f5f5f5f	32	plan9	PUSHW $0x2211
-66681122|3344556677885f5f5f5f5f5f	64	gnu	pushw $0x2211
-66681122|3344556677885f5f5f5f5f5f	64	intel	push 0x2211
-66681122|3344556677885f5f5f5f5f5f	64	plan9	PUSHW $0x2211
-6669112233|44556677885f5f5f5f5f5f	32	intel	imul dx, word ptr [ecx], 0x3322
-6669112233|44556677885f5f5f5f5f5f	32	plan9	IMULW $0x3322, 0(CX), DX
-6669112233|44556677885f5f5f5f5f5f	64	gnu	imul $0x3322,(%rcx),%dx
-6669112233|44556677885f5f5f5f5f5f	64	intel	imul dx, word ptr [rcx], 0x3322
-6669112233|44556677885f5f5f5f5f5f	64	plan9	IMULW $0x3322, 0(CX), DX
-666b1122|3344556677885f5f5f5f5f5f	32	intel	imul dx, word ptr [ecx], 0x22
-666b1122|3344556677885f5f5f5f5f5f	32	plan9	IMULW $0x22, 0(CX), DX
-666b1122|3344556677885f5f5f5f5f5f	64	gnu	imul $0x22,(%rcx),%dx
-666b1122|3344556677885f5f5f5f5f5f	64	intel	imul dx, word ptr [rcx], 0x22
-666b1122|3344556677885f5f5f5f5f5f	64	plan9	IMULW $0x22, 0(CX), DX
-666d|11223344556677885f5f5f5f5f5f	32	intel	data16 insw
-666d|11223344556677885f5f5f5f5f5f	32	plan9	INSW DX, ES:0(DI)
-666d|11223344556677885f5f5f5f5f5f	64	gnu	insw (%dx),%es:(%rdi)
-666d|11223344556677885f5f5f5f5f5f	64	intel	data16 insw
-666d|11223344556677885f5f5f5f5f5f	64	plan9	INSW DX, ES:0(DI)
-666f|11223344556677885f5f5f5f5f5f	32	intel	data16 outsw
-666f|11223344556677885f5f5f5f5f5f	32	plan9	OUTSW DS:0(SI), DX
-666f|11223344556677885f5f5f5f5f5f	64	gnu	outsw %ds:(%rsi),(%dx)
-666f|11223344556677885f5f5f5f5f5f	64	intel	data16 outsw
-666f|11223344556677885f5f5f5f5f5f	64	plan9	OUTSW DS:0(SI), DX
-6681001122|3344556677885f5f5f5f5f	32	intel	add word ptr [eax], 0x2211
-6681001122|3344556677885f5f5f5f5f	32	plan9	ADDW $0x2211, 0(AX)
-6681001122|3344556677885f5f5f5f5f	64	gnu	addw $0x2211,(%rax)
-6681001122|3344556677885f5f5f5f5f	64	intel	add word ptr [rax], 0x2211
-6681001122|3344556677885f5f5f5f5f	64	plan9	ADDW $0x2211, 0(AX)
-6681081122|3344556677885f5f5f5f5f	32	intel	or word ptr [eax], 0x2211
-6681081122|3344556677885f5f5f5f5f	32	plan9	ORW $0x2211, 0(AX)
-6681081122|3344556677885f5f5f5f5f	64	gnu	orw $0x2211,(%rax)
-6681081122|3344556677885f5f5f5f5f	64	intel	or word ptr [rax], 0x2211
-6681081122|3344556677885f5f5f5f5f	64	plan9	ORW $0x2211, 0(AX)
-6681112233|44556677885f5f5f5f5f5f	32	intel	adc word ptr [ecx], 0x3322
-6681112233|44556677885f5f5f5f5f5f	32	plan9	ADCW $0x3322, 0(CX)
-6681112233|44556677885f5f5f5f5f5f	64	gnu	adcw $0x3322,(%rcx)
-6681112233|44556677885f5f5f5f5f5f	64	intel	adc word ptr [rcx], 0x3322
-6681112233|44556677885f5f5f5f5f5f	64	plan9	ADCW $0x3322, 0(CX)
-6681181122|3344556677885f5f5f5f5f	32	intel	sbb word ptr [eax], 0x2211
-6681181122|3344556677885f5f5f5f5f	32	plan9	SBBW $0x2211, 0(AX)
-6681181122|3344556677885f5f5f5f5f	64	gnu	sbbw $0x2211,(%rax)
-6681181122|3344556677885f5f5f5f5f	64	intel	sbb word ptr [rax], 0x2211
-6681181122|3344556677885f5f5f5f5f	64	plan9	SBBW $0x2211, 0(AX)
-6681201122|3344556677885f5f5f5f5f	32	intel	and word ptr [eax], 0x2211
-6681201122|3344556677885f5f5f5f5f	32	plan9	ANDW $0x2211, 0(AX)
-6681201122|3344556677885f5f5f5f5f	64	gnu	andw $0x2211,(%rax)
-6681201122|3344556677885f5f5f5f5f	64	intel	and word ptr [rax], 0x2211
-6681201122|3344556677885f5f5f5f5f	64	plan9	ANDW $0x2211, 0(AX)
-6681281122|3344556677885f5f5f5f5f	32	intel	sub word ptr [eax], 0x2211
-6681281122|3344556677885f5f5f5f5f	32	plan9	SUBW $0x2211, 0(AX)
-6681281122|3344556677885f5f5f5f5f	64	gnu	subw $0x2211,(%rax)
-6681281122|3344556677885f5f5f5f5f	64	intel	sub word ptr [rax], 0x2211
-6681281122|3344556677885f5f5f5f5f	64	plan9	SUBW $0x2211, 0(AX)
-6681301122|3344556677885f5f5f5f5f	32	intel	xor word ptr [eax], 0x2211
-6681301122|3344556677885f5f5f5f5f	32	plan9	XORW $0x2211, 0(AX)
-6681301122|3344556677885f5f5f5f5f	64	gnu	xorw $0x2211,(%rax)
-6681301122|3344556677885f5f5f5f5f	64	intel	xor word ptr [rax], 0x2211
-6681301122|3344556677885f5f5f5f5f	64	plan9	XORW $0x2211, 0(AX)
-6681381122|3344556677885f5f5f5f5f	32	intel	cmp word ptr [eax], 0x2211
-6681381122|3344556677885f5f5f5f5f	32	plan9	CMPW $0x2211, 0(AX)
-6681381122|3344556677885f5f5f5f5f	64	gnu	cmpw $0x2211,(%rax)
-6681381122|3344556677885f5f5f5f5f	64	intel	cmp word ptr [rax], 0x2211
-6681381122|3344556677885f5f5f5f5f	64	plan9	CMPW $0x2211, 0(AX)
-66830011|223344556677885f5f5f5f5f	32	intel	add word ptr [eax], 0x11
-66830011|223344556677885f5f5f5f5f	32	plan9	ADDW $0x11, 0(AX)
-66830011|223344556677885f5f5f5f5f	64	gnu	addw $0x11,(%rax)
-66830011|223344556677885f5f5f5f5f	64	intel	add word ptr [rax], 0x11
-66830011|223344556677885f5f5f5f5f	64	plan9	ADDW $0x11, 0(AX)
-66830811|223344556677885f5f5f5f5f	32	intel	or word ptr [eax], 0x11
-66830811|223344556677885f5f5f5f5f	32	plan9	ORW $0x11, 0(AX)
-66830811|223344556677885f5f5f5f5f	64	gnu	orw $0x11,(%rax)
-66830811|223344556677885f5f5f5f5f	64	intel	or word ptr [rax], 0x11
-66830811|223344556677885f5f5f5f5f	64	plan9	ORW $0x11, 0(AX)
-66831122|3344556677885f5f5f5f5f5f	32	intel	adc word ptr [ecx], 0x22
-66831122|3344556677885f5f5f5f5f5f	32	plan9	ADCW $0x22, 0(CX)
-66831122|3344556677885f5f5f5f5f5f	64	gnu	adcw $0x22,(%rcx)
-66831122|3344556677885f5f5f5f5f5f	64	intel	adc word ptr [rcx], 0x22
-66831122|3344556677885f5f5f5f5f5f	64	plan9	ADCW $0x22, 0(CX)
-66831811|223344556677885f5f5f5f5f	32	intel	sbb word ptr [eax], 0x11
-66831811|223344556677885f5f5f5f5f	32	plan9	SBBW $0x11, 0(AX)
-66831811|223344556677885f5f5f5f5f	64	gnu	sbbw $0x11,(%rax)
-66831811|223344556677885f5f5f5f5f	64	intel	sbb word ptr [rax], 0x11
-66831811|223344556677885f5f5f5f5f	64	plan9	SBBW $0x11, 0(AX)
-66832011|223344556677885f5f5f5f5f	32	intel	and word ptr [eax], 0x11
-66832011|223344556677885f5f5f5f5f	32	plan9	ANDW $0x11, 0(AX)
-66832011|223344556677885f5f5f5f5f	64	gnu	andw $0x11,(%rax)
-66832011|223344556677885f5f5f5f5f	64	intel	and word ptr [rax], 0x11
-66832011|223344556677885f5f5f5f5f	64	plan9	ANDW $0x11, 0(AX)
-66832811|223344556677885f5f5f5f5f	32	intel	sub word ptr [eax], 0x11
-66832811|223344556677885f5f5f5f5f	32	plan9	SUBW $0x11, 0(AX)
-66832811|223344556677885f5f5f5f5f	64	gnu	subw $0x11,(%rax)
-66832811|223344556677885f5f5f5f5f	64	intel	sub word ptr [rax], 0x11
-66832811|223344556677885f5f5f5f5f	64	plan9	SUBW $0x11, 0(AX)
-66833011|223344556677885f5f5f5f5f	32	intel	xor word ptr [eax], 0x11
-66833011|223344556677885f5f5f5f5f	32	plan9	XORW $0x11, 0(AX)
-66833011|223344556677885f5f5f5f5f	64	gnu	xorw $0x11,(%rax)
-66833011|223344556677885f5f5f5f5f	64	intel	xor word ptr [rax], 0x11
-66833011|223344556677885f5f5f5f5f	64	plan9	XORW $0x11, 0(AX)
-66833811|223344556677885f5f5f5f5f	32	intel	cmp word ptr [eax], 0x11
-66833811|223344556677885f5f5f5f5f	32	plan9	CMPW $0x11, 0(AX)
-66833811|223344556677885f5f5f5f5f	64	gnu	cmpw $0x11,(%rax)
-66833811|223344556677885f5f5f5f5f	64	intel	cmp word ptr [rax], 0x11
-66833811|223344556677885f5f5f5f5f	64	plan9	CMPW $0x11, 0(AX)
-668511|223344556677885f5f5f5f5f5f	32	intel	test word ptr [ecx], dx
-668511|223344556677885f5f5f5f5f5f	32	plan9	TESTW DX, 0(CX)
-668511|223344556677885f5f5f5f5f5f	64	gnu	test %dx,(%rcx)
-668511|223344556677885f5f5f5f5f5f	64	intel	test word ptr [rcx], dx
-668511|223344556677885f5f5f5f5f5f	64	plan9	TESTW DX, 0(CX)
-668711|223344556677885f5f5f5f5f5f	32	intel	xchg word ptr [ecx], dx
-668711|223344556677885f5f5f5f5f5f	32	plan9	XCHGW DX, 0(CX)
-668711|223344556677885f5f5f5f5f5f	64	gnu	xchg %dx,(%rcx)
-668711|223344556677885f5f5f5f5f5f	64	intel	xchg word ptr [rcx], dx
-668711|223344556677885f5f5f5f5f5f	64	plan9	XCHGW DX, 0(CX)
-668911|223344556677885f5f5f5f5f5f	32	intel	mov word ptr [ecx], dx
-668911|223344556677885f5f5f5f5f5f	32	plan9	MOVW DX, 0(CX)
-668911|223344556677885f5f5f5f5f5f	64	gnu	mov %dx,(%rcx)
-668911|223344556677885f5f5f5f5f5f	64	intel	mov word ptr [rcx], dx
-668911|223344556677885f5f5f5f5f5f	64	plan9	MOVW DX, 0(CX)
-668b11|223344556677885f5f5f5f5f5f	32	intel	mov dx, word ptr [ecx]
-668b11|223344556677885f5f5f5f5f5f	32	plan9	MOVW 0(CX), DX
-668b11|223344556677885f5f5f5f5f5f	64	gnu	mov (%rcx),%dx
-668b11|223344556677885f5f5f5f5f5f	64	intel	mov dx, word ptr [rcx]
-668b11|223344556677885f5f5f5f5f5f	64	plan9	MOVW 0(CX), DX
-668c11|223344556677885f5f5f5f5f5f	32	intel	mov word ptr [ecx], ss
-668c11|223344556677885f5f5f5f5f5f	32	plan9	MOVW SS, 0(CX)
-668c11|223344556677885f5f5f5f5f5f	64	gnu	data16 mov %ss,(%rcx)
-668c11|223344556677885f5f5f5f5f5f	64	intel	mov word ptr [rcx], ss
-668c11|223344556677885f5f5f5f5f5f	64	plan9	MOVW SS, 0(CX)
-668d11|223344556677885f5f5f5f5f5f	32	intel	lea dx, ptr [ecx]
-668d11|223344556677885f5f5f5f5f5f	32	plan9	LEAW 0(CX), DX
-668d11|223344556677885f5f5f5f5f5f	64	gnu	lea (%rcx),%dx
-668d11|223344556677885f5f5f5f5f5f	64	intel	lea dx, ptr [rcx]
-668d11|223344556677885f5f5f5f5f5f	64	plan9	LEAW 0(CX), DX
-668ec0|11223344556677885f5f5f5f5f	32	intel	mov es, ax
-668ec0|11223344556677885f5f5f5f5f	32	plan9	MOVW AX, ES
-668ec0|11223344556677885f5f5f5f5f	64	gnu	mov %ax,%es
-668ec0|11223344556677885f5f5f5f5f	64	intel	mov es, ax
-668ec0|11223344556677885f5f5f5f5f	64	plan9	MOVW AX, ES
-668f00|11223344556677885f5f5f5f5f	32	intel	pop word ptr [eax]
-668f00|11223344556677885f5f5f5f5f	32	plan9	POPW 0(AX)
-668f00|11223344556677885f5f5f5f5f	64	gnu	popw (%rax)
-668f00|11223344556677885f5f5f5f5f	64	intel	pop word ptr [rax]
-668f00|11223344556677885f5f5f5f5f	64	plan9	POPW 0(AX)
-6690|11223344556677885f5f5f5f5f5f	32	plan9	NOPW
-6690|11223344556677885f5f5f5f5f5f	64	gnu	data16 nop
-6690|11223344556677885f5f5f5f5f5f	64	plan9	NOPW
-6698|11223344556677885f5f5f5f5f5f	32	intel	data16 cbw
-6698|11223344556677885f5f5f5f5f5f	32	plan9	CBW
-6698|11223344556677885f5f5f5f5f5f	64	gnu	cbtw
-6698|11223344556677885f5f5f5f5f5f	64	intel	data16 cbw
-6698|11223344556677885f5f5f5f5f5f	64	plan9	CBW
-6699|11223344556677885f5f5f5f5f5f	32	intel	data16 cwd
-6699|11223344556677885f5f5f5f5f5f	32	plan9	CWD
-6699|11223344556677885f5f5f5f5f5f	64	gnu	cwtd
-6699|11223344556677885f5f5f5f5f5f	64	intel	data16 cwd
-6699|11223344556677885f5f5f5f5f5f	64	plan9	CWD
-669a11223344|556677885f5f5f5f5f5f	32	intel	call far 0x2211, 0x4433
-669a11223344|556677885f5f5f5f5f5f	32	plan9	LCALL $0x2211, $0x4433
-669c|11223344556677885f5f5f5f5f5f	32	intel	data16 pushf
-669c|11223344556677885f5f5f5f5f5f	32	plan9	PUSHF
-669c|11223344556677885f5f5f5f5f5f	64	gnu	pushfw
-669c|11223344556677885f5f5f5f5f5f	64	intel	data16 pushf
-669c|11223344556677885f5f5f5f5f5f	64	plan9	PUSHF
-669d|11223344556677885f5f5f5f5f5f	32	intel	data16 popf
-669d|11223344556677885f5f5f5f5f5f	32	plan9	POPF
-669d|11223344556677885f5f5f5f5f5f	64	gnu	popfw
-669d|11223344556677885f5f5f5f5f5f	64	intel	data16 popf
-669d|11223344556677885f5f5f5f5f5f	64	plan9	POPF
-66a11122334455667788|5f5f5f5f5f5f	64	gnu	mov -0x778899aabbccddef,%ax
-66a11122334455667788|5f5f5f5f5f5f	64	intel	mov ax, word ptr [0x8877665544332211]
-66a11122334455667788|5f5f5f5f5f5f	64	plan9	MOVW -0x778899aabbccddef, AX
-66a111223344|556677885f5f5f5f5f5f	32	intel	mov ax, word ptr [0x44332211]
-66a111223344|556677885f5f5f5f5f5f	32	plan9	MOVW 0x44332211, AX
-66a31122334455667788|5f5f5f5f5f5f	64	gnu	mov %ax,-0x778899aabbccddef
-66a31122334455667788|5f5f5f5f5f5f	64	intel	mov word ptr [0x8877665544332211], ax
-66a31122334455667788|5f5f5f5f5f5f	64	plan9	MOVW AX, -0x778899aabbccddef
-66a311223344|556677885f5f5f5f5f5f	32	intel	mov word ptr [0x44332211], ax
-66a311223344|556677885f5f5f5f5f5f	32	plan9	MOVW AX, 0x44332211
-66a5|11223344556677885f5f5f5f5f5f	32	intel	movsw word ptr [edi], word ptr [esi]
-66a5|11223344556677885f5f5f5f5f5f	32	plan9	MOVSW DS:0(SI), ES:0(DI)
-66a5|11223344556677885f5f5f5f5f5f	64	gnu	movsw %ds:(%rsi),%es:(%rdi)
-66a5|11223344556677885f5f5f5f5f5f	64	intel	movsw word ptr [rdi], word ptr [rsi]
-66a5|11223344556677885f5f5f5f5f5f	64	plan9	MOVSW DS:0(SI), ES:0(DI)
-66a7|11223344556677885f5f5f5f5f5f	32	intel	cmpsw word ptr [esi], word ptr [edi]
-66a7|11223344556677885f5f5f5f5f5f	32	plan9	CMPSW ES:0(DI), DS:0(SI)
-66a7|11223344556677885f5f5f5f5f5f	64	gnu	cmpsw %es:(%rdi),%ds:(%rsi)
-66a7|11223344556677885f5f5f5f5f5f	64	intel	cmpsw word ptr [rsi], word ptr [rdi]
-66a7|11223344556677885f5f5f5f5f5f	64	plan9	CMPSW ES:0(DI), DS:0(SI)
-66a91122|3344556677885f5f5f5f5f5f	32	intel	test ax, 0x2211
-66a91122|3344556677885f5f5f5f5f5f	32	plan9	TESTW $0x2211, AX
-66a91122|3344556677885f5f5f5f5f5f	64	gnu	test $0x2211,%ax
-66a91122|3344556677885f5f5f5f5f5f	64	intel	test ax, 0x2211
-66a91122|3344556677885f5f5f5f5f5f	64	plan9	TESTW $0x2211, AX
-66ab|11223344556677885f5f5f5f5f5f	32	intel	stosw word ptr [edi]
-66ab|11223344556677885f5f5f5f5f5f	32	plan9	STOSW AX, ES:0(DI)
-66ab|11223344556677885f5f5f5f5f5f	64	gnu	stos %ax,%es:(%rdi)
-66ab|11223344556677885f5f5f5f5f5f	64	intel	stosw word ptr [rdi]
-66ab|11223344556677885f5f5f5f5f5f	64	plan9	STOSW AX, ES:0(DI)
-66ad|11223344556677885f5f5f5f5f5f	32	intel	lodsw word ptr [esi]
-66ad|11223344556677885f5f5f5f5f5f	32	plan9	LODSW DS:0(SI), AX
-66ad|11223344556677885f5f5f5f5f5f	64	gnu	lods %ds:(%rsi),%ax
-66ad|11223344556677885f5f5f5f5f5f	64	intel	lodsw word ptr [rsi]
-66ad|11223344556677885f5f5f5f5f5f	64	plan9	LODSW DS:0(SI), AX
-66af|11223344556677885f5f5f5f5f5f	32	intel	scasw word ptr [edi]
-66af|11223344556677885f5f5f5f5f5f	32	plan9	SCASW ES:0(DI), AX
-66af|11223344556677885f5f5f5f5f5f	64	gnu	scas %es:(%rdi),%ax
-66af|11223344556677885f5f5f5f5f5f	64	intel	scasw word ptr [rdi]
-66af|11223344556677885f5f5f5f5f5f	64	plan9	SCASW ES:0(DI), AX
-66b81122|3344556677885f5f5f5f5f5f	32	intel	mov ax, 0x2211
-66b81122|3344556677885f5f5f5f5f5f	32	plan9	MOVW $0x2211, AX
-66b81122|3344556677885f5f5f5f5f5f	64	gnu	mov $0x2211,%ax
-66b81122|3344556677885f5f5f5f5f5f	64	intel	mov ax, 0x2211
-66b81122|3344556677885f5f5f5f5f5f	64	plan9	MOVW $0x2211, AX
-66c10011|223344556677885f5f5f5f5f	32	intel	rol word ptr [eax], 0x11
-66c10011|223344556677885f5f5f5f5f	32	plan9	ROLW $0x11, 0(AX)
-66c10011|223344556677885f5f5f5f5f	64	gnu	rolw $0x11,(%rax)
-66c10011|223344556677885f5f5f5f5f	64	intel	rol word ptr [rax], 0x11
-66c10011|223344556677885f5f5f5f5f	64	plan9	ROLW $0x11, 0(AX)
-66c10811|223344556677885f5f5f5f5f	32	intel	ror word ptr [eax], 0x11
-66c10811|223344556677885f5f5f5f5f	32	plan9	RORW $0x11, 0(AX)
-66c10811|223344556677885f5f5f5f5f	64	gnu	rorw $0x11,(%rax)
-66c10811|223344556677885f5f5f5f5f	64	intel	ror word ptr [rax], 0x11
-66c10811|223344556677885f5f5f5f5f	64	plan9	RORW $0x11, 0(AX)
-66c11122|3344556677885f5f5f5f5f5f	32	intel	rcl word ptr [ecx], 0x22
-66c11122|3344556677885f5f5f5f5f5f	32	plan9	RCLW $0x22, 0(CX)
-66c11122|3344556677885f5f5f5f5f5f	64	gnu	rclw $0x22,(%rcx)
-66c11122|3344556677885f5f5f5f5f5f	64	intel	rcl word ptr [rcx], 0x22
-66c11122|3344556677885f5f5f5f5f5f	64	plan9	RCLW $0x22, 0(CX)
-66c11811|223344556677885f5f5f5f5f	32	intel	rcr word ptr [eax], 0x11
-66c11811|223344556677885f5f5f5f5f	32	plan9	RCRW $0x11, 0(AX)
-66c11811|223344556677885f5f5f5f5f	64	gnu	rcrw $0x11,(%rax)
-66c11811|223344556677885f5f5f5f5f	64	intel	rcr word ptr [rax], 0x11
-66c11811|223344556677885f5f5f5f5f	64	plan9	RCRW $0x11, 0(AX)
-66c12011|223344556677885f5f5f5f5f	32	intel	shl word ptr [eax], 0x11
-66c12011|223344556677885f5f5f5f5f	32	plan9	SHLW $0x11, 0(AX)
-66c12011|223344556677885f5f5f5f5f	64	gnu	shlw $0x11,(%rax)
-66c12011|223344556677885f5f5f5f5f	64	intel	shl word ptr [rax], 0x11
-66c12011|223344556677885f5f5f5f5f	64	plan9	SHLW $0x11, 0(AX)
-66c12811|223344556677885f5f5f5f5f	32	intel	shr word ptr [eax], 0x11
-66c12811|223344556677885f5f5f5f5f	32	plan9	SHRW $0x11, 0(AX)
-66c12811|223344556677885f5f5f5f5f	64	gnu	shrw $0x11,(%rax)
-66c12811|223344556677885f5f5f5f5f	64	intel	shr word ptr [rax], 0x11
-66c12811|223344556677885f5f5f5f5f	64	plan9	SHRW $0x11, 0(AX)
-66c13811|223344556677885f5f5f5f5f	32	intel	sar word ptr [eax], 0x11
-66c13811|223344556677885f5f5f5f5f	32	plan9	SARW $0x11, 0(AX)
-66c13811|223344556677885f5f5f5f5f	64	gnu	sarw $0x11,(%rax)
-66c13811|223344556677885f5f5f5f5f	64	intel	sar word ptr [rax], 0x11
-66c13811|223344556677885f5f5f5f5f	64	plan9	SARW $0x11, 0(AX)
-66c21122|3344556677885f5f5f5f5f5f	32	intel	ret 0x2211
-66c21122|3344556677885f5f5f5f5f5f	32	plan9	RET $0x2211
-66c21122|3344556677885f5f5f5f5f5f	64	gnu	retw $0x2211
-66c21122|3344556677885f5f5f5f5f5f	64	intel	ret 0x2211
-66c21122|3344556677885f5f5f5f5f5f	64	plan9	RET $0x2211
-66c411|223344556677885f5f5f5f5f5f	32	intel	les dx, dword ptr [ecx]
-66c411|223344556677885f5f5f5f5f5f	32	plan9	LES 0(CX), DX
-66c511|223344556677885f5f5f5f5f5f	32	intel	lds dx, dword ptr [ecx]
-66c511|223344556677885f5f5f5f5f5f	32	plan9	LDS 0(CX), DX
-66c7001122|3344556677885f5f5f5f5f	32	intel	mov word ptr [eax], 0x2211
-66c7001122|3344556677885f5f5f5f5f	32	plan9	MOVW $0x2211, 0(AX)
-66c7001122|3344556677885f5f5f5f5f	64	gnu	movw $0x2211,(%rax)
-66c7001122|3344556677885f5f5f5f5f	64	intel	mov word ptr [rax], 0x2211
-66c7001122|3344556677885f5f5f5f5f	64	plan9	MOVW $0x2211, 0(AX)
-66c7f81122|3344556677885f5f5f5f5f	32	intel	xbegin .+0x2211
-66c7f81122|3344556677885f5f5f5f5f	32	plan9	XBEGIN .+8721
-66c7f81122|3344556677885f5f5f5f5f	64	gnu	xbeginw .+0x2211
-66c7f81122|3344556677885f5f5f5f5f	64	intel	xbegin .+0x2211
-66c7f81122|3344556677885f5f5f5f5f	64	plan9	XBEGIN .+8721
-66c9|11223344556677885f5f5f5f5f5f	32	intel	data16 leave
-66c9|11223344556677885f5f5f5f5f5f	32	plan9	LEAVE
-66c9|11223344556677885f5f5f5f5f5f	64	gnu	leavew
-66c9|11223344556677885f5f5f5f5f5f	64	intel	data16 leave
-66c9|11223344556677885f5f5f5f5f5f	64	plan9	LEAVE
-66cf|11223344556677885f5f5f5f5f5f	32	intel	data16 iret
-66cf|11223344556677885f5f5f5f5f5f	32	plan9	IRET
-66cf|11223344556677885f5f5f5f5f5f	64	gnu	iretw
-66cf|11223344556677885f5f5f5f5f5f	64	intel	data16 iret
-66cf|11223344556677885f5f5f5f5f5f	64	plan9	IRET
-66d100|11223344556677885f5f5f5f5f	32	intel	rol word ptr [eax], 0x1
-66d100|11223344556677885f5f5f5f5f	32	plan9	ROLW $0x1, 0(AX)
-66d100|11223344556677885f5f5f5f5f	64	gnu	rolw (%rax)
-66d100|11223344556677885f5f5f5f5f	64	intel	rol word ptr [rax], 0x1
-66d100|11223344556677885f5f5f5f5f	64	plan9	ROLW $0x1, 0(AX)
-66d108|11223344556677885f5f5f5f5f	32	intel	ror word ptr [eax], 0x1
-66d108|11223344556677885f5f5f5f5f	32	plan9	RORW $0x1, 0(AX)
-66d108|11223344556677885f5f5f5f5f	64	gnu	rorw (%rax)
-66d108|11223344556677885f5f5f5f5f	64	intel	ror word ptr [rax], 0x1
-66d108|11223344556677885f5f5f5f5f	64	plan9	RORW $0x1, 0(AX)
-66d111|223344556677885f5f5f5f5f5f	32	intel	rcl word ptr [ecx], 0x1
-66d111|223344556677885f5f5f5f5f5f	32	plan9	RCLW $0x1, 0(CX)
-66d111|223344556677885f5f5f5f5f5f	64	gnu	rclw (%rcx)
-66d111|223344556677885f5f5f5f5f5f	64	intel	rcl word ptr [rcx], 0x1
-66d111|223344556677885f5f5f5f5f5f	64	plan9	RCLW $0x1, 0(CX)
-66d118|11223344556677885f5f5f5f5f	32	intel	rcr word ptr [eax], 0x1
-66d118|11223344556677885f5f5f5f5f	32	plan9	RCRW $0x1, 0(AX)
-66d118|11223344556677885f5f5f5f5f	64	gnu	rcrw (%rax)
-66d118|11223344556677885f5f5f5f5f	64	intel	rcr word ptr [rax], 0x1
-66d118|11223344556677885f5f5f5f5f	64	plan9	RCRW $0x1, 0(AX)
-66d120|11223344556677885f5f5f5f5f	32	intel	shl word ptr [eax], 0x1
-66d120|11223344556677885f5f5f5f5f	32	plan9	SHLW $0x1, 0(AX)
-66d120|11223344556677885f5f5f5f5f	64	gnu	shlw (%rax)
-66d120|11223344556677885f5f5f5f5f	64	intel	shl word ptr [rax], 0x1
-66d120|11223344556677885f5f5f5f5f	64	plan9	SHLW $0x1, 0(AX)
-66d128|11223344556677885f5f5f5f5f	32	intel	shr word ptr [eax], 0x1
-66d128|11223344556677885f5f5f5f5f	32	plan9	SHRW $0x1, 0(AX)
-66d128|11223344556677885f5f5f5f5f	64	gnu	shrw (%rax)
-66d128|11223344556677885f5f5f5f5f	64	intel	shr word ptr [rax], 0x1
-66d128|11223344556677885f5f5f5f5f	64	plan9	SHRW $0x1, 0(AX)
-66d138|11223344556677885f5f5f5f5f	32	intel	sar word ptr [eax], 0x1
-66d138|11223344556677885f5f5f5f5f	32	plan9	SARW $0x1, 0(AX)
-66d138|11223344556677885f5f5f5f5f	64	gnu	sarw (%rax)
-66d138|11223344556677885f5f5f5f5f	64	intel	sar word ptr [rax], 0x1
-66d138|11223344556677885f5f5f5f5f	64	plan9	SARW $0x1, 0(AX)
-66d300|11223344556677885f5f5f5f5f	32	intel	rol word ptr [eax], cl
-66d300|11223344556677885f5f5f5f5f	32	plan9	ROLW CL, 0(AX)
-66d300|11223344556677885f5f5f5f5f	64	gnu	rolw %cl,(%rax)
-66d300|11223344556677885f5f5f5f5f	64	intel	rol word ptr [rax], cl
-66d300|11223344556677885f5f5f5f5f	64	plan9	ROLW CL, 0(AX)
-66d308|11223344556677885f5f5f5f5f	32	intel	ror word ptr [eax], cl
-66d308|11223344556677885f5f5f5f5f	32	plan9	RORW CL, 0(AX)
-66d308|11223344556677885f5f5f5f5f	64	gnu	rorw %cl,(%rax)
-66d308|11223344556677885f5f5f5f5f	64	intel	ror word ptr [rax], cl
-66d308|11223344556677885f5f5f5f5f	64	plan9	RORW CL, 0(AX)
-66d311|223344556677885f5f5f5f5f5f	32	intel	rcl word ptr [ecx], cl
-66d311|223344556677885f5f5f5f5f5f	32	plan9	RCLW CL, 0(CX)
-66d311|223344556677885f5f5f5f5f5f	64	gnu	rclw %cl,(%rcx)
-66d311|223344556677885f5f5f5f5f5f	64	intel	rcl word ptr [rcx], cl
-66d311|223344556677885f5f5f5f5f5f	64	plan9	RCLW CL, 0(CX)
-66d318|11223344556677885f5f5f5f5f	32	intel	rcr word ptr [eax], cl
-66d318|11223344556677885f5f5f5f5f	32	plan9	RCRW CL, 0(AX)
-66d318|11223344556677885f5f5f5f5f	64	gnu	rcrw %cl,(%rax)
-66d318|11223344556677885f5f5f5f5f	64	intel	rcr word ptr [rax], cl
-66d318|11223344556677885f5f5f5f5f	64	plan9	RCRW CL, 0(AX)
-66d320|11223344556677885f5f5f5f5f	32	intel	shl word ptr [eax], cl
-66d320|11223344556677885f5f5f5f5f	32	plan9	SHLW CL, 0(AX)
-66d320|11223344556677885f5f5f5f5f	64	gnu	shlw %cl,(%rax)
-66d320|11223344556677885f5f5f5f5f	64	intel	shl word ptr [rax], cl
-66d320|11223344556677885f5f5f5f5f	64	plan9	SHLW CL, 0(AX)
-66d328|11223344556677885f5f5f5f5f	32	intel	shr word ptr [eax], cl
-66d328|11223344556677885f5f5f5f5f	32	plan9	SHRW CL, 0(AX)
-66d328|11223344556677885f5f5f5f5f	64	gnu	shrw %cl,(%rax)
-66d328|11223344556677885f5f5f5f5f	64	intel	shr word ptr [rax], cl
-66d328|11223344556677885f5f5f5f5f	64	plan9	SHRW CL, 0(AX)
-66d338|11223344556677885f5f5f5f5f	32	intel	sar word ptr [eax], cl
-66d338|11223344556677885f5f5f5f5f	32	plan9	SARW CL, 0(AX)
-66d338|11223344556677885f5f5f5f5f	64	gnu	sarw %cl,(%rax)
-66d338|11223344556677885f5f5f5f5f	64	intel	sar word ptr [rax], cl
-66d338|11223344556677885f5f5f5f5f	64	plan9	SARW CL, 0(AX)
-66d411|223344556677885f5f5f5f5f5f	32	intel	aam 0x11
-66d411|223344556677885f5f5f5f5f5f	32	plan9	AAM $0x11
-66d920|11223344556677885f5f5f5f5f	32	intel	fldenv ptr [eax]
-66d920|11223344556677885f5f5f5f5f	32	plan9	FLDENVW 0(AX)
-66d920|11223344556677885f5f5f5f5f	64	gnu	fldenvs (%rax)
-66d920|11223344556677885f5f5f5f5f	64	intel	fldenv ptr [rax]
-66d920|11223344556677885f5f5f5f5f	64	plan9	FLDENVW 0(AX)
-66e511|223344556677885f5f5f5f5f5f	32	intel	in ax, 0x11
-66e511|223344556677885f5f5f5f5f5f	32	plan9	INW $0x11, AX
-66e511|223344556677885f5f5f5f5f5f	64	gnu	in $0x11,%ax
-66e511|223344556677885f5f5f5f5f5f	64	intel	in ax, 0x11
-66e511|223344556677885f5f5f5f5f5f	64	plan9	INW $0x11, AX
-66e711|223344556677885f5f5f5f5f5f	32	intel	out 0x11, ax
-66e711|223344556677885f5f5f5f5f5f	32	plan9	OUTW AX, $0x11
-66e711|223344556677885f5f5f5f5f5f	64	gnu	out %ax,$0x11
-66e711|223344556677885f5f5f5f5f5f	64	intel	out 0x11, ax
-66e711|223344556677885f5f5f5f5f5f	64	plan9	OUTW AX, $0x11
-66e811223344|556677885f5f5f5f5f5f	64	gnu	callw .+0x44332211
-66e811223344|556677885f5f5f5f5f5f	64	intel	call .+0x44332211
-66e811223344|556677885f5f5f5f5f5f	64	plan9	CALL .+1144201745
-66e81122|3344556677885f5f5f5f5f5f	32	intel	call .+0x2211
-66e81122|3344556677885f5f5f5f5f5f	32	plan9	CALL .+8721
-66e911223344|556677885f5f5f5f5f5f	64	gnu	jmpw .+0x44332211
-66e911223344|556677885f5f5f5f5f5f	64	intel	jmp .+0x44332211
-66e911223344|556677885f5f5f5f5f5f	64	plan9	JMP .+1144201745
-66e91122|3344556677885f5f5f5f5f5f	32	intel	jmp .+0x2211
-66e91122|3344556677885f5f5f5f5f5f	32	plan9	JMP .+8721
-66ea11223344|556677885f5f5f5f5f5f	32	intel	jmp far 0x2211, 0x4433
-66ea11223344|556677885f5f5f5f5f5f	32	plan9	LJMP $0x2211, $0x4433
-66ed|11223344556677885f5f5f5f5f5f	32	intel	in ax, dx
-66ed|11223344556677885f5f5f5f5f5f	32	plan9	INW DX, AX
-66ed|11223344556677885f5f5f5f5f5f	64	gnu	in (%dx),%ax
-66ed|11223344556677885f5f5f5f5f5f	64	intel	in ax, dx
-66ed|11223344556677885f5f5f5f5f5f	64	plan9	INW DX, AX
-66ef|11223344556677885f5f5f5f5f5f	32	intel	out dx, ax
-66ef|11223344556677885f5f5f5f5f5f	32	plan9	OUTW AX, DX
-66ef|11223344556677885f5f5f5f5f5f	64	gnu	out %ax,(%dx)
-66ef|11223344556677885f5f5f5f5f5f	64	intel	out dx, ax
-66ef|11223344556677885f5f5f5f5f5f	64	plan9	OUTW AX, DX
-66f20f2a11|223344556677885f5f5f5f	32	intel	cvtsi2sd xmm2, dword ptr [ecx]
-66f20f2a11|223344556677885f5f5f5f	32	plan9	REPNE CVTSI2SDW 0(CX), X2
-66f20f2a11|223344556677885f5f5f5f	64	gnu	cvtsi2sdl (%rcx),%xmm2
-66f20f2a11|223344556677885f5f5f5f	64	intel	cvtsi2sd xmm2, dword ptr [rcx]
-66f20f2a11|223344556677885f5f5f5f	64	plan9	REPNE CVTSI2SDW 0(CX), X2
-66f20f2c11|223344556677885f5f5f5f	32	intel	cvttsd2si edx, qword ptr [ecx]
-66f20f2c11|223344556677885f5f5f5f	32	plan9	REPNE CVTTSD2SIW 0(CX), DX
-66f20f2c11|223344556677885f5f5f5f	64	gnu	cvttsd2si (%rcx),%dx
-66f20f2c11|223344556677885f5f5f5f	64	intel	cvttsd2si edx, qword ptr [rcx]
-66f20f2c11|223344556677885f5f5f5f	64	plan9	REPNE CVTTSD2SIW 0(CX), DX
-66f20f2d11|223344556677885f5f5f5f	32	intel	cvtsd2si edx, qword ptr [ecx]
-66f20f2d11|223344556677885f5f5f5f	32	plan9	REPNE CVTSD2SIW 0(CX), DX
-66f20f2d11|223344556677885f5f5f5f	64	gnu	cvtsd2si (%rcx),%dx
-66f20f2d11|223344556677885f5f5f5f	64	intel	cvtsd2si edx, qword ptr [rcx]
-66f20f2d11|223344556677885f5f5f5f	64	plan9	REPNE CVTSD2SIW 0(CX), DX
-66f20f38f011|223344556677885f5f5f	32	intel	crc32 edx, byte ptr [ecx]
-66f20f38f011|223344556677885f5f5f	32	plan9	REPNE CRC32 0(CX), DX
-66f20f38f011|223344556677885f5f5f	64	gnu	crc32b (%rcx),%edx
-66f20f38f011|223344556677885f5f5f	64	intel	crc32 edx, byte ptr [rcx]
-66f20f38f011|223344556677885f5f5f	64	plan9	REPNE CRC32 0(CX), DX
-66f30f2c11|223344556677885f5f5f5f	32	intel	cvttss2si edx, dword ptr [ecx]
-66f30f2c11|223344556677885f5f5f5f	32	plan9	REP CVTTSS2SIW 0(CX), DX
-66f30f2c11|223344556677885f5f5f5f	64	gnu	cvttss2si (%rcx),%dx
-66f30f2c11|223344556677885f5f5f5f	64	intel	cvttss2si edx, dword ptr [rcx]
-66f30f2c11|223344556677885f5f5f5f	64	plan9	REP CVTTSS2SIW 0(CX), DX
-66f30f2d11|223344556677885f5f5f5f	32	intel	cvtss2si edx, dword ptr [ecx]
-66f30f2d11|223344556677885f5f5f5f	32	plan9	REP CVTSS2SIW 0(CX), DX
-66f30f2d11|223344556677885f5f5f5f	64	gnu	cvtss2si (%rcx),%dx
-66f30f2d11|223344556677885f5f5f5f	64	intel	cvtss2si edx, dword ptr [rcx]
-66f30f2d11|223344556677885f5f5f5f	64	plan9	REP CVTSS2SIW 0(CX), DX
-66f30fae11|223344556677885f5f5f5f	64	gnu	wrfsbasel (%rcx)
-66f30fae11|223344556677885f5f5f5f	64	intel	wrfsbase dword ptr [rcx]
-66f30fae11|223344556677885f5f5f5f	64	plan9	REP WRFSBASE 0(CX)
-66f30fae18|11223344556677885f5f5f	64	gnu	wrgsbasel (%rax)
-66f30fae18|11223344556677885f5f5f	64	intel	wrgsbase dword ptr [rax]
-66f30fae18|11223344556677885f5f5f	64	plan9	REP WRGSBASE 0(AX)
-66f30faec0|11223344556677885f5f5f	64	gnu	rdfsbase %eax
-66f30faec0|11223344556677885f5f5f	64	intel	rdfsbase eax
-66f30faec0|11223344556677885f5f5f	64	plan9	REP RDFSBASE AX
-66f30faec8|11223344556677885f5f5f	64	gnu	rdgsbase %eax
-66f30faec8|11223344556677885f5f5f	64	intel	rdgsbase eax
-66f30faec8|11223344556677885f5f5f	64	plan9	REP RDGSBASE AX
-66f30fd6c5|11223344556677885f5f5f	32	intel	movq2dq xmm0, mmx5
-66f30fd6c5|11223344556677885f5f5f	32	plan9	REP MOVQ2DQ M5, X0
-66f30fd6c5|11223344556677885f5f5f	64	gnu	movq2dq %mm5,%xmm0
-66f30fd6c5|11223344556677885f5f5f	64	intel	movq2dq xmm0, mmx5
-66f30fd6c5|11223344556677885f5f5f	64	plan9	REP MOVQ2DQ M5, X0
-66f7001122|3344556677885f5f5f5f5f	32	intel	test word ptr [eax], 0x2211
-66f7001122|3344556677885f5f5f5f5f	32	plan9	TESTW $0x2211, 0(AX)
-66f7001122|3344556677885f5f5f5f5f	64	gnu	testw $0x2211,(%rax)
-66f7001122|3344556677885f5f5f5f5f	64	intel	test word ptr [rax], 0x2211
-66f7001122|3344556677885f5f5f5f5f	64	plan9	TESTW $0x2211, 0(AX)
-66f711|223344556677885f5f5f5f5f5f	32	intel	not word ptr [ecx]
-66f711|223344556677885f5f5f5f5f5f	32	plan9	NOTW 0(CX)
-66f711|223344556677885f5f5f5f5f5f	64	gnu	notw (%rcx)
-66f711|223344556677885f5f5f5f5f5f	64	intel	not word ptr [rcx]
-66f711|223344556677885f5f5f5f5f5f	64	plan9	NOTW 0(CX)
-66f718|11223344556677885f5f5f5f5f	32	intel	neg word ptr [eax]
-66f718|11223344556677885f5f5f5f5f	32	plan9	NEGW 0(AX)
-66f718|11223344556677885f5f5f5f5f	64	gnu	negw (%rax)
-66f718|11223344556677885f5f5f5f5f	64	intel	neg word ptr [rax]
-66f718|11223344556677885f5f5f5f5f	64	plan9	NEGW 0(AX)
-66f720|11223344556677885f5f5f5f5f	32	intel	mul word ptr [eax]
-66f720|11223344556677885f5f5f5f5f	32	plan9	MULW 0(AX)
-66f720|11223344556677885f5f5f5f5f	64	gnu	mulw (%rax)
-66f720|11223344556677885f5f5f5f5f	64	intel	mul word ptr [rax]
-66f720|11223344556677885f5f5f5f5f	64	plan9	MULW 0(AX)
-66f728|11223344556677885f5f5f5f5f	32	intel	imul word ptr [eax]
-66f728|11223344556677885f5f5f5f5f	32	plan9	IMULW 0(AX)
-66f728|11223344556677885f5f5f5f5f	64	gnu	imulw (%rax)
-66f728|11223344556677885f5f5f5f5f	64	intel	imul word ptr [rax]
-66f728|11223344556677885f5f5f5f5f	64	plan9	IMULW 0(AX)
-66f730|11223344556677885f5f5f5f5f	32	intel	div word ptr [eax]
-66f730|11223344556677885f5f5f5f5f	32	plan9	DIVW 0(AX)
-66f730|11223344556677885f5f5f5f5f	64	gnu	divw (%rax)
-66f730|11223344556677885f5f5f5f5f	64	intel	div word ptr [rax]
-66f730|11223344556677885f5f5f5f5f	64	plan9	DIVW 0(AX)
-66f738|11223344556677885f5f5f5f5f	32	intel	idiv word ptr [eax]
-66f738|11223344556677885f5f5f5f5f	32	plan9	IDIVW 0(AX)
-66f738|11223344556677885f5f5f5f5f	64	gnu	idivw (%rax)
-66f738|11223344556677885f5f5f5f5f	64	intel	idiv word ptr [rax]
-66f738|11223344556677885f5f5f5f5f	64	plan9	IDIVW 0(AX)
-66ff00|11223344556677885f5f5f5f5f	32	intel	inc word ptr [eax]
-66ff00|11223344556677885f5f5f5f5f	32	plan9	INCW 0(AX)
-66ff00|11223344556677885f5f5f5f5f	64	gnu	incw (%rax)
-66ff00|11223344556677885f5f5f5f5f	64	intel	inc word ptr [rax]
-66ff00|11223344556677885f5f5f5f5f	64	plan9	INCW 0(AX)
-66ff08|11223344556677885f5f5f5f5f	32	intel	dec word ptr [eax]
-66ff08|11223344556677885f5f5f5f5f	32	plan9	DECW 0(AX)
-66ff08|11223344556677885f5f5f5f5f	64	gnu	decw (%rax)
-66ff08|11223344556677885f5f5f5f5f	64	intel	dec word ptr [rax]
-66ff08|11223344556677885f5f5f5f5f	64	plan9	DECW 0(AX)
-66ff11|223344556677885f5f5f5f5f5f	32	intel	call word ptr [ecx]
-66ff11|223344556677885f5f5f5f5f5f	32	plan9	CALL 0(CX)
-66ff11|223344556677885f5f5f5f5f5f	64	gnu	callw *(%rcx)
-66ff11|223344556677885f5f5f5f5f5f	64	intel	call qword ptr [rcx]
-66ff11|223344556677885f5f5f5f5f5f	64	plan9	CALL 0(CX)
-66ff18|11223344556677885f5f5f5f5f	32	intel	call far dword ptr [eax]
-66ff18|11223344556677885f5f5f5f5f	32	plan9	LCALL 0(AX)
-66ff18|11223344556677885f5f5f5f5f	64	gnu	lcallw *(%rax)
-66ff18|11223344556677885f5f5f5f5f	64	intel	call far dword ptr [rax]
-66ff18|11223344556677885f5f5f5f5f	64	plan9	LCALL 0(AX)
-66ff20|11223344556677885f5f5f5f5f	32	intel	jmp word ptr [eax]
-66ff20|11223344556677885f5f5f5f5f	32	plan9	JMP 0(AX)
-66ff20|11223344556677885f5f5f5f5f	64	gnu	jmpw *(%rax)
-66ff20|11223344556677885f5f5f5f5f	64	intel	jmp qword ptr [rax]
-66ff20|11223344556677885f5f5f5f5f	64	plan9	JMP 0(AX)
-66ff28|11223344556677885f5f5f5f5f	32	intel	jmp far dword ptr [eax]
-66ff28|11223344556677885f5f5f5f5f	32	plan9	LJMP 0(AX)
-66ff28|11223344556677885f5f5f5f5f	64	gnu	ljmpw *(%rax)
-66ff28|11223344556677885f5f5f5f5f	64	intel	jmp far dword ptr [rax]
-66ff28|11223344556677885f5f5f5f5f	64	plan9	LJMP 0(AX)
-66ff30|11223344556677885f5f5f5f5f	32	intel	push word ptr [eax]
-66ff30|11223344556677885f5f5f5f5f	32	plan9	PUSHW 0(AX)
-66ff30|11223344556677885f5f5f5f5f	64	gnu	pushw (%rax)
-66ff30|11223344556677885f5f5f5f5f	64	intel	push word ptr [rax]
-66ff30|11223344556677885f5f5f5f5f	64	plan9	PUSHW 0(AX)
-66|9a11223344556677885f5f5f5f5f5f	64	gnu	data16
-66|9a11223344556677885f5f5f5f5f5f	64	intel	data16
-66|9a11223344556677885f5f5f5f5f5f	64	plan9	Op(0)
-66|c411223344556677885f5f5f5f5f5f	64	gnu	data16
-66|c411223344556677885f5f5f5f5f5f	64	intel	data16
-66|c411223344556677885f5f5f5f5f5f	64	plan9	Op(0)
-66|c511223344556677885f5f5f5f5f5f	64	gnu	data16
-66|c511223344556677885f5f5f5f5f5f	64	intel	data16
-66|c511223344556677885f5f5f5f5f5f	64	plan9	Op(0)
-66|d411223344556677885f5f5f5f5f5f	64	gnu	data16
-66|d411223344556677885f5f5f5f5f5f	64	intel	data16
-66|d411223344556677885f5f5f5f5f5f	64	plan9	Op(0)
-66|ea11223344556677885f5f5f5f5f5f	64	gnu	data16
-66|ea11223344556677885f5f5f5f5f5f	64	intel	data16
-66|ea11223344556677885f5f5f5f5f5f	64	plan9	Op(0)
-676c|11223344556677885f5f5f5f5f5f	32	intel	addr16 insb
-676c|11223344556677885f5f5f5f5f5f	32	plan9	INSB DX, ES:0(DI)
-676c|11223344556677885f5f5f5f5f5f	64	gnu	insb (%dx),%es:(%edi)
-676c|11223344556677885f5f5f5f5f5f	64	intel	addr32 insb
-676c|11223344556677885f5f5f5f5f5f	64	plan9	INSB DX, ES:0(DI)
-67d7|11223344556677885f5f5f5f5f5f	32	intel	addr16 xlat
-67d7|11223344556677885f5f5f5f5f5f	32	plan9	XLATB DS:0(BX)
-67d7|11223344556677885f5f5f5f5f5f	64	gnu	xlat %ds:(%ebx)
-67d7|11223344556677885f5f5f5f5f5f	64	intel	addr32 xlat
-67d7|11223344556677885f5f5f5f5f5f	64	plan9	XLATB DS:0(BX)
-67e311|223344556677885f5f5f5f5f5f	32	intel	addr16 jcxz .+0x11
-67e311|223344556677885f5f5f5f5f5f	32	plan9	JCXZ .+17
-67e311|223344556677885f5f5f5f5f5f	64	gnu	jecxz .+0x11
-67e311|223344556677885f5f5f5f5f5f	64	intel	addr32 jecxz .+0x11
-67e311|223344556677885f5f5f5f5f5f	64	plan9	JECXZ .+17
-6811223344|556677885f5f5f5f5f5f5f	32	intel	push 0x44332211
-6811223344|556677885f5f5f5f5f5f5f	32	plan9	PUSHL $0x44332211
-6811223344|556677885f5f5f5f5f5f5f	64	gnu	pushq $0x44332211
-6811223344|556677885f5f5f5f5f5f5f	64	intel	push 0x44332211
-6811223344|556677885f5f5f5f5f5f5f	64	plan9	PUSHL $0x44332211
-691122334455|6677885f5f5f5f5f5f5f	32	intel	imul edx, dword ptr [ecx], 0x55443322
-691122334455|6677885f5f5f5f5f5f5f	32	plan9	IMULL $0x55443322, 0(CX), DX
-691122334455|6677885f5f5f5f5f5f5f	64	gnu	imul $0x55443322,(%rcx),%edx
-691122334455|6677885f5f5f5f5f5f5f	64	intel	imul edx, dword ptr [rcx], 0x55443322
-691122334455|6677885f5f5f5f5f5f5f	64	plan9	IMULL $0x55443322, 0(CX), DX
-6a11|223344556677885f5f5f5f5f5f5f	32	intel	push 0x11
-6a11|223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL $0x11
-6a11|223344556677885f5f5f5f5f5f5f	64	gnu	pushq $0x11
-6a11|223344556677885f5f5f5f5f5f5f	64	intel	push 0x11
-6a11|223344556677885f5f5f5f5f5f5f	64	plan9	PUSHL $0x11
-6b1122|3344556677885f5f5f5f5f5f5f	32	intel	imul edx, dword ptr [ecx], 0x22
-6b1122|3344556677885f5f5f5f5f5f5f	32	plan9	IMULL $0x22, 0(CX), DX
-6b1122|3344556677885f5f5f5f5f5f5f	64	gnu	imul $0x22,(%rcx),%edx
-6b1122|3344556677885f5f5f5f5f5f5f	64	intel	imul edx, dword ptr [rcx], 0x22
-6b1122|3344556677885f5f5f5f5f5f5f	64	plan9	IMULL $0x22, 0(CX), DX
-6d|11223344556677885f5f5f5f5f5f5f	32	intel	insd
-6d|11223344556677885f5f5f5f5f5f5f	32	plan9	INSD DX, ES:0(DI)
-6d|11223344556677885f5f5f5f5f5f5f	64	gnu	insl (%dx),%es:(%rdi)
-6d|11223344556677885f5f5f5f5f5f5f	64	intel	insd
-6d|11223344556677885f5f5f5f5f5f5f	64	plan9	INSD DX, ES:0(DI)
-6f|11223344556677885f5f5f5f5f5f5f	32	intel	outsd
-6f|11223344556677885f5f5f5f5f5f5f	32	plan9	OUTSD DS:0(SI), DX
-6f|11223344556677885f5f5f5f5f5f5f	64	gnu	outsl %ds:(%rsi),(%dx)
-6f|11223344556677885f5f5f5f5f5f5f	64	intel	outsd
-6f|11223344556677885f5f5f5f5f5f5f	64	plan9	OUTSD DS:0(SI), DX
-7111|223344556677885f5f5f5f5f5f5f	32	intel	jno .+0x11
-7111|223344556677885f5f5f5f5f5f5f	32	plan9	JNO .+17
-7111|223344556677885f5f5f5f5f5f5f	64	gnu	jno .+0x11
-7111|223344556677885f5f5f5f5f5f5f	64	intel	jno .+0x11
-7111|223344556677885f5f5f5f5f5f5f	64	plan9	JNO .+17
-7211|223344556677885f5f5f5f5f5f5f	32	intel	jb .+0x11
-7211|223344556677885f5f5f5f5f5f5f	32	plan9	JB .+17
-7211|223344556677885f5f5f5f5f5f5f	64	gnu	jb .+0x11
-7211|223344556677885f5f5f5f5f5f5f	64	intel	jb .+0x11
-7211|223344556677885f5f5f5f5f5f5f	64	plan9	JB .+17
-7311|223344556677885f5f5f5f5f5f5f	32	intel	jnb .+0x11
-7311|223344556677885f5f5f5f5f5f5f	32	plan9	JAE .+17
-7311|223344556677885f5f5f5f5f5f5f	64	gnu	jae .+0x11
-7311|223344556677885f5f5f5f5f5f5f	64	intel	jnb .+0x11
-7311|223344556677885f5f5f5f5f5f5f	64	plan9	JAE .+17
-7411|223344556677885f5f5f5f5f5f5f	32	intel	jz .+0x11
-7411|223344556677885f5f5f5f5f5f5f	32	plan9	JE .+17
-7411|223344556677885f5f5f5f5f5f5f	64	gnu	je .+0x11
-7411|223344556677885f5f5f5f5f5f5f	64	intel	jz .+0x11
-7411|223344556677885f5f5f5f5f5f5f	64	plan9	JE .+17
-7511|223344556677885f5f5f5f5f5f5f	32	intel	jnz .+0x11
-7511|223344556677885f5f5f5f5f5f5f	32	plan9	JNE .+17
-7511|223344556677885f5f5f5f5f5f5f	64	gnu	jne .+0x11
-7511|223344556677885f5f5f5f5f5f5f	64	intel	jnz .+0x11
-7511|223344556677885f5f5f5f5f5f5f	64	plan9	JNE .+17
-7611|223344556677885f5f5f5f5f5f5f	32	intel	jbe .+0x11
-7611|223344556677885f5f5f5f5f5f5f	32	plan9	JBE .+17
-7611|223344556677885f5f5f5f5f5f5f	64	gnu	jbe .+0x11
-7611|223344556677885f5f5f5f5f5f5f	64	intel	jbe .+0x11
-7611|223344556677885f5f5f5f5f5f5f	64	plan9	JBE .+17
-7711|223344556677885f5f5f5f5f5f5f	32	intel	jnbe .+0x11
-7711|223344556677885f5f5f5f5f5f5f	32	plan9	JA .+17
-7711|223344556677885f5f5f5f5f5f5f	64	gnu	ja .+0x11
-7711|223344556677885f5f5f5f5f5f5f	64	intel	jnbe .+0x11
-7711|223344556677885f5f5f5f5f5f5f	64	plan9	JA .+17
-7811|223344556677885f5f5f5f5f5f5f	32	intel	js .+0x11
-7811|223344556677885f5f5f5f5f5f5f	32	plan9	JS .+17
-7811|223344556677885f5f5f5f5f5f5f	64	gnu	js .+0x11
-7811|223344556677885f5f5f5f5f5f5f	64	intel	js .+0x11
-7811|223344556677885f5f5f5f5f5f5f	64	plan9	JS .+17
-7911|223344556677885f5f5f5f5f5f5f	32	intel	jns .+0x11
-7911|223344556677885f5f5f5f5f5f5f	32	plan9	JNS .+17
-7911|223344556677885f5f5f5f5f5f5f	64	gnu	jns .+0x11
-7911|223344556677885f5f5f5f5f5f5f	64	intel	jns .+0x11
-7911|223344556677885f5f5f5f5f5f5f	64	plan9	JNS .+17
-7a11|223344556677885f5f5f5f5f5f5f	32	intel	jp .+0x11
-7a11|223344556677885f5f5f5f5f5f5f	32	plan9	JP .+17
-7a11|223344556677885f5f5f5f5f5f5f	64	gnu	jp .+0x11
-7a11|223344556677885f5f5f5f5f5f5f	64	intel	jp .+0x11
-7a11|223344556677885f5f5f5f5f5f5f	64	plan9	JP .+17
-7b11|223344556677885f5f5f5f5f5f5f	32	intel	jnp .+0x11
-7b11|223344556677885f5f5f5f5f5f5f	32	plan9	JNP .+17
-7b11|223344556677885f5f5f5f5f5f5f	64	gnu	jnp .+0x11
-7b11|223344556677885f5f5f5f5f5f5f	64	intel	jnp .+0x11
-7b11|223344556677885f5f5f5f5f5f5f	64	plan9	JNP .+17
-7c11|223344556677885f5f5f5f5f5f5f	32	intel	jl .+0x11
-7c11|223344556677885f5f5f5f5f5f5f	32	plan9	JL .+17
-7c11|223344556677885f5f5f5f5f5f5f	64	gnu	jl .+0x11
-7c11|223344556677885f5f5f5f5f5f5f	64	intel	jl .+0x11
-7c11|223344556677885f5f5f5f5f5f5f	64	plan9	JL .+17
-7d11|223344556677885f5f5f5f5f5f5f	32	intel	jnl .+0x11
-7d11|223344556677885f5f5f5f5f5f5f	32	plan9	JGE .+17
-7d11|223344556677885f5f5f5f5f5f5f	64	gnu	jge .+0x11
-7d11|223344556677885f5f5f5f5f5f5f	64	intel	jnl .+0x11
-7d11|223344556677885f5f5f5f5f5f5f	64	plan9	JGE .+17
-7e11|223344556677885f5f5f5f5f5f5f	32	intel	jle .+0x11
-7e11|223344556677885f5f5f5f5f5f5f	32	plan9	JLE .+17
-7e11|223344556677885f5f5f5f5f5f5f	64	gnu	jle .+0x11
-7e11|223344556677885f5f5f5f5f5f5f	64	intel	jle .+0x11
-7e11|223344556677885f5f5f5f5f5f5f	64	plan9	JLE .+17
-7f11|223344556677885f5f5f5f5f5f5f	32	intel	jnle .+0x11
-7f11|223344556677885f5f5f5f5f5f5f	32	plan9	JG .+17
-7f11|223344556677885f5f5f5f5f5f5f	64	gnu	jg .+0x11
-7f11|223344556677885f5f5f5f5f5f5f	64	intel	jnle .+0x11
-7f11|223344556677885f5f5f5f5f5f5f	64	plan9	JG .+17
-800011|223344556677885f5f5f5f5f5f	32	intel	add byte ptr [eax], 0x11
-800011|223344556677885f5f5f5f5f5f	32	plan9	ADDL $0x11, 0(AX)
-800011|223344556677885f5f5f5f5f5f	64	gnu	addb $0x11,(%rax)
-800011|223344556677885f5f5f5f5f5f	64	intel	add byte ptr [rax], 0x11
-800011|223344556677885f5f5f5f5f5f	64	plan9	ADDL $0x11, 0(AX)
-800811|223344556677885f5f5f5f5f5f	32	intel	or byte ptr [eax], 0x11
-800811|223344556677885f5f5f5f5f5f	32	plan9	ORL $0x11, 0(AX)
-800811|223344556677885f5f5f5f5f5f	64	gnu	orb $0x11,(%rax)
-800811|223344556677885f5f5f5f5f5f	64	intel	or byte ptr [rax], 0x11
-800811|223344556677885f5f5f5f5f5f	64	plan9	ORL $0x11, 0(AX)
-801122|3344556677885f5f5f5f5f5f5f	32	intel	adc byte ptr [ecx], 0x22
-801122|3344556677885f5f5f5f5f5f5f	32	plan9	ADCL $0x22, 0(CX)
-801122|3344556677885f5f5f5f5f5f5f	64	gnu	adcb $0x22,(%rcx)
-801122|3344556677885f5f5f5f5f5f5f	64	intel	adc byte ptr [rcx], 0x22
-801122|3344556677885f5f5f5f5f5f5f	64	plan9	ADCL $0x22, 0(CX)
-801811|223344556677885f5f5f5f5f5f	32	intel	sbb byte ptr [eax], 0x11
-801811|223344556677885f5f5f5f5f5f	32	plan9	SBBL $0x11, 0(AX)
-801811|223344556677885f5f5f5f5f5f	64	gnu	sbbb $0x11,(%rax)
-801811|223344556677885f5f5f5f5f5f	64	intel	sbb byte ptr [rax], 0x11
-801811|223344556677885f5f5f5f5f5f	64	plan9	SBBL $0x11, 0(AX)
-802011|223344556677885f5f5f5f5f5f	32	intel	and byte ptr [eax], 0x11
-802011|223344556677885f5f5f5f5f5f	32	plan9	ANDL $0x11, 0(AX)
-802011|223344556677885f5f5f5f5f5f	64	gnu	andb $0x11,(%rax)
-802011|223344556677885f5f5f5f5f5f	64	intel	and byte ptr [rax], 0x11
-802011|223344556677885f5f5f5f5f5f	64	plan9	ANDL $0x11, 0(AX)
-802811|223344556677885f5f5f5f5f5f	32	intel	sub byte ptr [eax], 0x11
-802811|223344556677885f5f5f5f5f5f	32	plan9	SUBL $0x11, 0(AX)
-802811|223344556677885f5f5f5f5f5f	64	gnu	subb $0x11,(%rax)
-802811|223344556677885f5f5f5f5f5f	64	intel	sub byte ptr [rax], 0x11
-802811|223344556677885f5f5f5f5f5f	64	plan9	SUBL $0x11, 0(AX)
-803011|223344556677885f5f5f5f5f5f	32	intel	xor byte ptr [eax], 0x11
-803011|223344556677885f5f5f5f5f5f	32	plan9	XORL $0x11, 0(AX)
-803011|223344556677885f5f5f5f5f5f	64	gnu	xorb $0x11,(%rax)
-803011|223344556677885f5f5f5f5f5f	64	intel	xor byte ptr [rax], 0x11
-803011|223344556677885f5f5f5f5f5f	64	plan9	XORL $0x11, 0(AX)
-803811|223344556677885f5f5f5f5f5f	32	intel	cmp byte ptr [eax], 0x11
-803811|223344556677885f5f5f5f5f5f	32	plan9	CMPL $0x11, 0(AX)
-803811|223344556677885f5f5f5f5f5f	64	gnu	cmpb $0x11,(%rax)
-803811|223344556677885f5f5f5f5f5f	64	intel	cmp byte ptr [rax], 0x11
-803811|223344556677885f5f5f5f5f5f	64	plan9	CMPL $0x11, 0(AX)
-810011223344|556677885f5f5f5f5f5f	32	intel	add dword ptr [eax], 0x44332211
-810011223344|556677885f5f5f5f5f5f	32	plan9	ADDL $0x44332211, 0(AX)
-810011223344|556677885f5f5f5f5f5f	64	gnu	addl $0x44332211,(%rax)
-810011223344|556677885f5f5f5f5f5f	64	intel	add dword ptr [rax], 0x44332211
-810011223344|556677885f5f5f5f5f5f	64	plan9	ADDL $0x44332211, 0(AX)
-810811223344|556677885f5f5f5f5f5f	32	intel	or dword ptr [eax], 0x44332211
-810811223344|556677885f5f5f5f5f5f	32	plan9	ORL $0x44332211, 0(AX)
-810811223344|556677885f5f5f5f5f5f	64	gnu	orl $0x44332211,(%rax)
-810811223344|556677885f5f5f5f5f5f	64	intel	or dword ptr [rax], 0x44332211
-810811223344|556677885f5f5f5f5f5f	64	plan9	ORL $0x44332211, 0(AX)
-811122334455|6677885f5f5f5f5f5f5f	32	intel	adc dword ptr [ecx], 0x55443322
-811122334455|6677885f5f5f5f5f5f5f	32	plan9	ADCL $0x55443322, 0(CX)
-811122334455|6677885f5f5f5f5f5f5f	64	gnu	adcl $0x55443322,(%rcx)
-811122334455|6677885f5f5f5f5f5f5f	64	intel	adc dword ptr [rcx], 0x55443322
-811122334455|6677885f5f5f5f5f5f5f	64	plan9	ADCL $0x55443322, 0(CX)
-811811223344|556677885f5f5f5f5f5f	32	intel	sbb dword ptr [eax], 0x44332211
-811811223344|556677885f5f5f5f5f5f	32	plan9	SBBL $0x44332211, 0(AX)
-811811223344|556677885f5f5f5f5f5f	64	gnu	sbbl $0x44332211,(%rax)
-811811223344|556677885f5f5f5f5f5f	64	intel	sbb dword ptr [rax], 0x44332211
-811811223344|556677885f5f5f5f5f5f	64	plan9	SBBL $0x44332211, 0(AX)
-812011223344|556677885f5f5f5f5f5f	32	intel	and dword ptr [eax], 0x44332211
-812011223344|556677885f5f5f5f5f5f	32	plan9	ANDL $0x44332211, 0(AX)
-812011223344|556677885f5f5f5f5f5f	64	gnu	andl $0x44332211,(%rax)
-812011223344|556677885f5f5f5f5f5f	64	intel	and dword ptr [rax], 0x44332211
-812011223344|556677885f5f5f5f5f5f	64	plan9	ANDL $0x44332211, 0(AX)
-812811223344|556677885f5f5f5f5f5f	32	intel	sub dword ptr [eax], 0x44332211
-812811223344|556677885f5f5f5f5f5f	32	plan9	SUBL $0x44332211, 0(AX)
-812811223344|556677885f5f5f5f5f5f	64	gnu	subl $0x44332211,(%rax)
-812811223344|556677885f5f5f5f5f5f	64	intel	sub dword ptr [rax], 0x44332211
-812811223344|556677885f5f5f5f5f5f	64	plan9	SUBL $0x44332211, 0(AX)
-813011223344|556677885f5f5f5f5f5f	32	intel	xor dword ptr [eax], 0x44332211
-813011223344|556677885f5f5f5f5f5f	32	plan9	XORL $0x44332211, 0(AX)
-813011223344|556677885f5f5f5f5f5f	64	gnu	xorl $0x44332211,(%rax)
-813011223344|556677885f5f5f5f5f5f	64	intel	xor dword ptr [rax], 0x44332211
-813011223344|556677885f5f5f5f5f5f	64	plan9	XORL $0x44332211, 0(AX)
-813811223344|556677885f5f5f5f5f5f	32	intel	cmp dword ptr [eax], 0x44332211
-813811223344|556677885f5f5f5f5f5f	32	plan9	CMPL $0x44332211, 0(AX)
-813811223344|556677885f5f5f5f5f5f	64	gnu	cmpl $0x44332211,(%rax)
-813811223344|556677885f5f5f5f5f5f	64	intel	cmp dword ptr [rax], 0x44332211
-813811223344|556677885f5f5f5f5f5f	64	plan9	CMPL $0x44332211, 0(AX)
-830011|223344556677885f5f5f5f5f5f	32	intel	add dword ptr [eax], 0x11
-830011|223344556677885f5f5f5f5f5f	32	plan9	ADDL $0x11, 0(AX)
-830011|223344556677885f5f5f5f5f5f	64	gnu	addl $0x11,(%rax)
-830011|223344556677885f5f5f5f5f5f	64	intel	add dword ptr [rax], 0x11
-830011|223344556677885f5f5f5f5f5f	64	plan9	ADDL $0x11, 0(AX)
-830811|223344556677885f5f5f5f5f5f	32	intel	or dword ptr [eax], 0x11
-830811|223344556677885f5f5f5f5f5f	32	plan9	ORL $0x11, 0(AX)
-830811|223344556677885f5f5f5f5f5f	64	gnu	orl $0x11,(%rax)
-830811|223344556677885f5f5f5f5f5f	64	intel	or dword ptr [rax], 0x11
-830811|223344556677885f5f5f5f5f5f	64	plan9	ORL $0x11, 0(AX)
-831122|3344556677885f5f5f5f5f5f5f	32	intel	adc dword ptr [ecx], 0x22
-831122|3344556677885f5f5f5f5f5f5f	32	plan9	ADCL $0x22, 0(CX)
-831122|3344556677885f5f5f5f5f5f5f	64	gnu	adcl $0x22,(%rcx)
-831122|3344556677885f5f5f5f5f5f5f	64	intel	adc dword ptr [rcx], 0x22
-831122|3344556677885f5f5f5f5f5f5f	64	plan9	ADCL $0x22, 0(CX)
-831811|223344556677885f5f5f5f5f5f	32	intel	sbb dword ptr [eax], 0x11
-831811|223344556677885f5f5f5f5f5f	32	plan9	SBBL $0x11, 0(AX)
-831811|223344556677885f5f5f5f5f5f	64	gnu	sbbl $0x11,(%rax)
-831811|223344556677885f5f5f5f5f5f	64	intel	sbb dword ptr [rax], 0x11
-831811|223344556677885f5f5f5f5f5f	64	plan9	SBBL $0x11, 0(AX)
-832011|223344556677885f5f5f5f5f5f	32	intel	and dword ptr [eax], 0x11
-832011|223344556677885f5f5f5f5f5f	32	plan9	ANDL $0x11, 0(AX)
-832011|223344556677885f5f5f5f5f5f	64	gnu	andl $0x11,(%rax)
-832011|223344556677885f5f5f5f5f5f	64	intel	and dword ptr [rax], 0x11
-832011|223344556677885f5f5f5f5f5f	64	plan9	ANDL $0x11, 0(AX)
-832811|223344556677885f5f5f5f5f5f	32	intel	sub dword ptr [eax], 0x11
-832811|223344556677885f5f5f5f5f5f	32	plan9	SUBL $0x11, 0(AX)
-832811|223344556677885f5f5f5f5f5f	64	gnu	subl $0x11,(%rax)
-832811|223344556677885f5f5f5f5f5f	64	intel	sub dword ptr [rax], 0x11
-832811|223344556677885f5f5f5f5f5f	64	plan9	SUBL $0x11, 0(AX)
-833011|223344556677885f5f5f5f5f5f	32	intel	xor dword ptr [eax], 0x11
-833011|223344556677885f5f5f5f5f5f	32	plan9	XORL $0x11, 0(AX)
-833011|223344556677885f5f5f5f5f5f	64	gnu	xorl $0x11,(%rax)
-833011|223344556677885f5f5f5f5f5f	64	intel	xor dword ptr [rax], 0x11
-833011|223344556677885f5f5f5f5f5f	64	plan9	XORL $0x11, 0(AX)
-833811|223344556677885f5f5f5f5f5f	32	intel	cmp dword ptr [eax], 0x11
-833811|223344556677885f5f5f5f5f5f	32	plan9	CMPL $0x11, 0(AX)
-833811|223344556677885f5f5f5f5f5f	64	gnu	cmpl $0x11,(%rax)
-833811|223344556677885f5f5f5f5f5f	64	intel	cmp dword ptr [rax], 0x11
-833811|223344556677885f5f5f5f5f5f	64	plan9	CMPL $0x11, 0(AX)
-8411|223344556677885f5f5f5f5f5f5f	32	intel	test byte ptr [ecx], dl
-8411|223344556677885f5f5f5f5f5f5f	32	plan9	TESTL DL, 0(CX)
-8411|223344556677885f5f5f5f5f5f5f	64	gnu	test %dl,(%rcx)
-8411|223344556677885f5f5f5f5f5f5f	64	intel	test byte ptr [rcx], dl
-8411|223344556677885f5f5f5f5f5f5f	64	plan9	TESTL DL, 0(CX)
-8511|223344556677885f5f5f5f5f5f5f	32	intel	test dword ptr [ecx], edx
-8511|223344556677885f5f5f5f5f5f5f	32	plan9	TESTL DX, 0(CX)
-8511|223344556677885f5f5f5f5f5f5f	64	gnu	test %edx,(%rcx)
-8511|223344556677885f5f5f5f5f5f5f	64	intel	test dword ptr [rcx], edx
-8511|223344556677885f5f5f5f5f5f5f	64	plan9	TESTL DX, 0(CX)
-8611|223344556677885f5f5f5f5f5f5f	32	intel	xchg byte ptr [ecx], dl
-8611|223344556677885f5f5f5f5f5f5f	32	plan9	XCHGL DL, 0(CX)
-8611|223344556677885f5f5f5f5f5f5f	64	gnu	xchg %dl,(%rcx)
-8611|223344556677885f5f5f5f5f5f5f	64	intel	xchg byte ptr [rcx], dl
-8611|223344556677885f5f5f5f5f5f5f	64	plan9	XCHGL DL, 0(CX)
-8711|223344556677885f5f5f5f5f5f5f	32	intel	xchg dword ptr [ecx], edx
-8711|223344556677885f5f5f5f5f5f5f	32	plan9	XCHGL DX, 0(CX)
-8711|223344556677885f5f5f5f5f5f5f	64	gnu	xchg %edx,(%rcx)
-8711|223344556677885f5f5f5f5f5f5f	64	intel	xchg dword ptr [rcx], edx
-8711|223344556677885f5f5f5f5f5f5f	64	plan9	XCHGL DX, 0(CX)
-8811|223344556677885f5f5f5f5f5f5f	32	intel	mov byte ptr [ecx], dl
-8811|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL DL, 0(CX)
-8811|223344556677885f5f5f5f5f5f5f	64	gnu	mov %dl,(%rcx)
-8811|223344556677885f5f5f5f5f5f5f	64	intel	mov byte ptr [rcx], dl
-8811|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL DL, 0(CX)
-8911|223344556677885f5f5f5f5f5f5f	32	intel	mov dword ptr [ecx], edx
-8911|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL DX, 0(CX)
-8911|223344556677885f5f5f5f5f5f5f	64	gnu	mov %edx,(%rcx)
-8911|223344556677885f5f5f5f5f5f5f	64	intel	mov dword ptr [rcx], edx
-8911|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL DX, 0(CX)
-8a11|223344556677885f5f5f5f5f5f5f	32	intel	mov dl, byte ptr [ecx]
-8a11|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL 0(CX), DL
-8a11|223344556677885f5f5f5f5f5f5f	64	gnu	mov (%rcx),%dl
-8a11|223344556677885f5f5f5f5f5f5f	64	intel	mov dl, byte ptr [rcx]
-8a11|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL 0(CX), DL
-8b11|223344556677885f5f5f5f5f5f5f	32	intel	mov edx, dword ptr [ecx]
-8b11|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL 0(CX), DX
-8b11|223344556677885f5f5f5f5f5f5f	64	gnu	mov (%rcx),%edx
-8b11|223344556677885f5f5f5f5f5f5f	64	intel	mov edx, dword ptr [rcx]
-8b11|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL 0(CX), DX
-8c11|223344556677885f5f5f5f5f5f5f	32	intel	mov word ptr [ecx], ss
-8c11|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL SS, 0(CX)
-8c11|223344556677885f5f5f5f5f5f5f	64	gnu	mov %ss,(%rcx)
-8c11|223344556677885f5f5f5f5f5f5f	64	intel	mov word ptr [rcx], ss
-8c11|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL SS, 0(CX)
-8d11|223344556677885f5f5f5f5f5f5f	32	intel	lea edx, ptr [ecx]
-8d11|223344556677885f5f5f5f5f5f5f	32	plan9	LEAL 0(CX), DX
-8d11|223344556677885f5f5f5f5f5f5f	64	gnu	lea (%rcx),%edx
-8d11|223344556677885f5f5f5f5f5f5f	64	intel	lea edx, ptr [rcx]
-8d11|223344556677885f5f5f5f5f5f5f	64	plan9	LEAL 0(CX), DX
-8e11|223344556677885f5f5f5f5f5f5f	32	intel	mov ss, word ptr [ecx]
-8e11|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL 0(CX), SS
-8e11|223344556677885f5f5f5f5f5f5f	64	gnu	mov (%rcx),%ss
-8e11|223344556677885f5f5f5f5f5f5f	64	intel	mov ss, word ptr [rcx]
-8e11|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL 0(CX), SS
-8f00|11223344556677885f5f5f5f5f5f	32	intel	pop dword ptr [eax]
-8f00|11223344556677885f5f5f5f5f5f	32	plan9	POPL 0(AX)
-8f00|11223344556677885f5f5f5f5f5f	64	gnu	popq (%rax)
-8f00|11223344556677885f5f5f5f5f5f	64	intel	pop qword ptr [rax]
-8f00|11223344556677885f5f5f5f5f5f	64	plan9	POPL 0(AX)
-91|11223344556677885f5f5f5f5f5f5f	32	intel	xchg ecx, eax
-91|11223344556677885f5f5f5f5f5f5f	32	plan9	XCHGL AX, CX
-91|11223344556677885f5f5f5f5f5f5f	64	intel	xchg ecx, eax
-91|11223344556677885f5f5f5f5f5f5f	64	plan9	XCHGL AX, CX
-98|11223344556677885f5f5f5f5f5f5f	32	intel	cwde
-98|11223344556677885f5f5f5f5f5f5f	32	plan9	CWDE
-98|11223344556677885f5f5f5f5f5f5f	64	gnu	cwtl
-98|11223344556677885f5f5f5f5f5f5f	64	intel	cwde
-98|11223344556677885f5f5f5f5f5f5f	64	plan9	CWDE
-99|11223344556677885f5f5f5f5f5f5f	32	intel	cdq
-99|11223344556677885f5f5f5f5f5f5f	32	plan9	CDQ
-99|11223344556677885f5f5f5f5f5f5f	64	gnu	cltd
-99|11223344556677885f5f5f5f5f5f5f	64	intel	cdq
-99|11223344556677885f5f5f5f5f5f5f	64	plan9	CDQ
-9a112233445566|77885f5f5f5f5f5f5f	32	intel	call far 0x44332211, 0x6655
-9a112233445566|77885f5f5f5f5f5f5f	32	plan9	LCALL $0x44332211, $0x6655
-9b|11223344556677885f5f5f5f5f5f5f	32	intel	fwait
-9b|11223344556677885f5f5f5f5f5f5f	32	plan9	FWAIT
-9b|11223344556677885f5f5f5f5f5f5f	64	gnu	fwait
-9b|11223344556677885f5f5f5f5f5f5f	64	intel	fwait
-9b|11223344556677885f5f5f5f5f5f5f	64	plan9	FWAIT
-9c|11223344556677885f5f5f5f5f5f5f	32	intel	pushfd
-9c|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHFD
-9c|11223344556677885f5f5f5f5f5f5f	64	gnu	pushfq
-9c|11223344556677885f5f5f5f5f5f5f	64	intel	pushfq
-9c|11223344556677885f5f5f5f5f5f5f	64	plan9	PUSHFQ
-9d|11223344556677885f5f5f5f5f5f5f	32	intel	popfd
-9d|11223344556677885f5f5f5f5f5f5f	32	plan9	POPFD
-9d|11223344556677885f5f5f5f5f5f5f	64	gnu	popfq
-9d|11223344556677885f5f5f5f5f5f5f	64	intel	popfq
-9d|11223344556677885f5f5f5f5f5f5f	64	plan9	POPFQ
-9e|11223344556677885f5f5f5f5f5f5f	32	intel	sahf
-9e|11223344556677885f5f5f5f5f5f5f	32	plan9	SAHF
-9e|11223344556677885f5f5f5f5f5f5f	64	gnu	sahf
-9e|11223344556677885f5f5f5f5f5f5f	64	intel	sahf
-9e|11223344556677885f5f5f5f5f5f5f	64	plan9	SAHF
-9f|11223344556677885f5f5f5f5f5f5f	32	intel	lahf
-9f|11223344556677885f5f5f5f5f5f5f	32	plan9	LAHF
-9f|11223344556677885f5f5f5f5f5f5f	64	gnu	lahf
-9f|11223344556677885f5f5f5f5f5f5f	64	intel	lahf
-9f|11223344556677885f5f5f5f5f5f5f	64	plan9	LAHF
-a11122334455667788|5f5f5f5f5f5f5f	64	gnu	mov -0x778899aabbccddef,%eax
-a11122334455667788|5f5f5f5f5f5f5f	64	intel	mov eax, dword ptr [0x8877665544332211]
-a11122334455667788|5f5f5f5f5f5f5f	64	plan9	MOVL -0x778899aabbccddef, AX
-a111223344|556677885f5f5f5f5f5f5f	32	intel	mov eax, dword ptr [0x44332211]
-a111223344|556677885f5f5f5f5f5f5f	32	plan9	MOVL 0x44332211, AX
-a21122334455667788|5f5f5f5f5f5f5f	64	gnu	mov %al,-0x778899aabbccddef
-a21122334455667788|5f5f5f5f5f5f5f	64	intel	mov byte ptr [0x8877665544332211], al
-a21122334455667788|5f5f5f5f5f5f5f	64	plan9	MOVL AL, -0x778899aabbccddef
-a211223344|556677885f5f5f5f5f5f5f	32	intel	mov byte ptr [0x44332211], al
-a211223344|556677885f5f5f5f5f5f5f	32	plan9	MOVL AL, 0x44332211
-a31122334455667788|5f5f5f5f5f5f5f	64	gnu	mov %eax,-0x778899aabbccddef
-a31122334455667788|5f5f5f5f5f5f5f	64	intel	mov dword ptr [0x8877665544332211], eax
-a31122334455667788|5f5f5f5f5f5f5f	64	plan9	MOVL AX, -0x778899aabbccddef
-a311223344|556677885f5f5f5f5f5f5f	32	intel	mov dword ptr [0x44332211], eax
-a311223344|556677885f5f5f5f5f5f5f	32	plan9	MOVL AX, 0x44332211
-a4|11223344556677885f5f5f5f5f5f5f	32	intel	movsb byte ptr [edi], byte ptr [esi]
-a4|11223344556677885f5f5f5f5f5f5f	32	plan9	MOVSB DS:0(SI), ES:0(DI)
-a4|11223344556677885f5f5f5f5f5f5f	64	gnu	movsb %ds:(%rsi),%es:(%rdi)
-a4|11223344556677885f5f5f5f5f5f5f	64	intel	movsb byte ptr [rdi], byte ptr [rsi]
-a4|11223344556677885f5f5f5f5f5f5f	64	plan9	MOVSB DS:0(SI), ES:0(DI)
-a5|11223344556677885f5f5f5f5f5f5f	32	intel	movsd dword ptr [edi], dword ptr [esi]
-a5|11223344556677885f5f5f5f5f5f5f	32	plan9	MOVSD DS:0(SI), ES:0(DI)
-a5|11223344556677885f5f5f5f5f5f5f	64	gnu	movsl %ds:(%rsi),%es:(%rdi)
-a5|11223344556677885f5f5f5f5f5f5f	64	intel	movsd dword ptr [rdi], dword ptr [rsi]
-a5|11223344556677885f5f5f5f5f5f5f	64	plan9	MOVSD DS:0(SI), ES:0(DI)
-a6|11223344556677885f5f5f5f5f5f5f	32	intel	cmpsb byte ptr [esi], byte ptr [edi]
-a6|11223344556677885f5f5f5f5f5f5f	32	plan9	CMPSB ES:0(DI), DS:0(SI)
-a6|11223344556677885f5f5f5f5f5f5f	64	gnu	cmpsb %es:(%rdi),%ds:(%rsi)
-a6|11223344556677885f5f5f5f5f5f5f	64	intel	cmpsb byte ptr [rsi], byte ptr [rdi]
-a6|11223344556677885f5f5f5f5f5f5f	64	plan9	CMPSB ES:0(DI), DS:0(SI)
-a7|11223344556677885f5f5f5f5f5f5f	32	intel	cmpsd dword ptr [esi], dword ptr [edi]
-a7|11223344556677885f5f5f5f5f5f5f	32	plan9	CMPSD ES:0(DI), DS:0(SI)
-a7|11223344556677885f5f5f5f5f5f5f	64	gnu	cmpsl %es:(%rdi),%ds:(%rsi)
-a7|11223344556677885f5f5f5f5f5f5f	64	intel	cmpsd dword ptr [rsi], dword ptr [rdi]
-a7|11223344556677885f5f5f5f5f5f5f	64	plan9	CMPSD ES:0(DI), DS:0(SI)
-a811|223344556677885f5f5f5f5f5f5f	32	intel	test al, 0x11
-a811|223344556677885f5f5f5f5f5f5f	32	plan9	TESTL $0x11, AL
-a811|223344556677885f5f5f5f5f5f5f	64	gnu	test $0x11,%al
-a811|223344556677885f5f5f5f5f5f5f	64	intel	test al, 0x11
-a811|223344556677885f5f5f5f5f5f5f	64	plan9	TESTL $0x11, AL
-a911223344|556677885f5f5f5f5f5f5f	32	intel	test eax, 0x44332211
-a911223344|556677885f5f5f5f5f5f5f	32	plan9	TESTL $0x44332211, AX
-a911223344|556677885f5f5f5f5f5f5f	64	gnu	test $0x44332211,%eax
-a911223344|556677885f5f5f5f5f5f5f	64	intel	test eax, 0x44332211
-a911223344|556677885f5f5f5f5f5f5f	64	plan9	TESTL $0x44332211, AX
-aa|11223344556677885f5f5f5f5f5f5f	32	intel	stosb byte ptr [edi]
-aa|11223344556677885f5f5f5f5f5f5f	32	plan9	STOSB AL, ES:0(DI)
-aa|11223344556677885f5f5f5f5f5f5f	64	gnu	stos %al,%es:(%rdi)
-aa|11223344556677885f5f5f5f5f5f5f	64	intel	stosb byte ptr [rdi]
-aa|11223344556677885f5f5f5f5f5f5f	64	plan9	STOSB AL, ES:0(DI)
-ab|11223344556677885f5f5f5f5f5f5f	32	intel	stosd dword ptr [edi]
-ab|11223344556677885f5f5f5f5f5f5f	32	plan9	STOSD AX, ES:0(DI)
-ab|11223344556677885f5f5f5f5f5f5f	64	gnu	stos %eax,%es:(%rdi)
-ab|11223344556677885f5f5f5f5f5f5f	64	intel	stosd dword ptr [rdi]
-ab|11223344556677885f5f5f5f5f5f5f	64	plan9	STOSD AX, ES:0(DI)
-ac|11223344556677885f5f5f5f5f5f5f	32	intel	lodsb byte ptr [esi]
-ac|11223344556677885f5f5f5f5f5f5f	32	plan9	LODSB DS:0(SI), AL
-ac|11223344556677885f5f5f5f5f5f5f	64	gnu	lods %ds:(%rsi),%al
-ac|11223344556677885f5f5f5f5f5f5f	64	intel	lodsb byte ptr [rsi]
-ac|11223344556677885f5f5f5f5f5f5f	64	plan9	LODSB DS:0(SI), AL
-ad|11223344556677885f5f5f5f5f5f5f	32	intel	lodsd dword ptr [esi]
-ad|11223344556677885f5f5f5f5f5f5f	32	plan9	LODSD DS:0(SI), AX
-ad|11223344556677885f5f5f5f5f5f5f	64	gnu	lods %ds:(%rsi),%eax
-ad|11223344556677885f5f5f5f5f5f5f	64	intel	lodsd dword ptr [rsi]
-ad|11223344556677885f5f5f5f5f5f5f	64	plan9	LODSD DS:0(SI), AX
-ae|11223344556677885f5f5f5f5f5f5f	32	intel	scasb byte ptr [edi]
-ae|11223344556677885f5f5f5f5f5f5f	32	plan9	SCASB ES:0(DI), AL
-ae|11223344556677885f5f5f5f5f5f5f	64	gnu	scas %es:(%rdi),%al
-ae|11223344556677885f5f5f5f5f5f5f	64	intel	scasb byte ptr [rdi]
-ae|11223344556677885f5f5f5f5f5f5f	64	plan9	SCASB ES:0(DI), AL
-af|11223344556677885f5f5f5f5f5f5f	32	intel	scasd dword ptr [edi]
-af|11223344556677885f5f5f5f5f5f5f	32	plan9	SCASD ES:0(DI), AX
-af|11223344556677885f5f5f5f5f5f5f	64	gnu	scas %es:(%rdi),%eax
-af|11223344556677885f5f5f5f5f5f5f	64	intel	scasd dword ptr [rdi]
-af|11223344556677885f5f5f5f5f5f5f	64	plan9	SCASD ES:0(DI), AX
-b011|223344556677885f5f5f5f5f5f5f	32	intel	mov al, 0x11
-b011|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL $0x11, AL
-b011|223344556677885f5f5f5f5f5f5f	64	gnu	mov $0x11,%al
-b011|223344556677885f5f5f5f5f5f5f	64	intel	mov al, 0x11
-b011|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL $0x11, AL
-b811223344|556677885f5f5f5f5f5f5f	32	intel	mov eax, 0x44332211
-b811223344|556677885f5f5f5f5f5f5f	32	plan9	MOVL $0x44332211, AX
-b811223344|556677885f5f5f5f5f5f5f	64	gnu	mov $0x44332211,%eax
-b811223344|556677885f5f5f5f5f5f5f	64	intel	mov eax, 0x44332211
-b811223344|556677885f5f5f5f5f5f5f	64	plan9	MOVL $0x44332211, AX
-c00011|223344556677885f5f5f5f5f5f	32	intel	rol byte ptr [eax], 0x11
-c00011|223344556677885f5f5f5f5f5f	32	plan9	ROLL $0x11, 0(AX)
-c00011|223344556677885f5f5f5f5f5f	64	gnu	rolb $0x11,(%rax)
-c00011|223344556677885f5f5f5f5f5f	64	intel	rol byte ptr [rax], 0x11
-c00011|223344556677885f5f5f5f5f5f	64	plan9	ROLL $0x11, 0(AX)
-c00811|223344556677885f5f5f5f5f5f	32	intel	ror byte ptr [eax], 0x11
-c00811|223344556677885f5f5f5f5f5f	32	plan9	RORL $0x11, 0(AX)
-c00811|223344556677885f5f5f5f5f5f	64	gnu	rorb $0x11,(%rax)
-c00811|223344556677885f5f5f5f5f5f	64	intel	ror byte ptr [rax], 0x11
-c00811|223344556677885f5f5f5f5f5f	64	plan9	RORL $0x11, 0(AX)
-c01122|3344556677885f5f5f5f5f5f5f	32	intel	rcl byte ptr [ecx], 0x22
-c01122|3344556677885f5f5f5f5f5f5f	32	plan9	RCLL $0x22, 0(CX)
-c01122|3344556677885f5f5f5f5f5f5f	64	gnu	rclb $0x22,(%rcx)
-c01122|3344556677885f5f5f5f5f5f5f	64	intel	rcl byte ptr [rcx], 0x22
-c01122|3344556677885f5f5f5f5f5f5f	64	plan9	RCLL $0x22, 0(CX)
-c01811|223344556677885f5f5f5f5f5f	32	intel	rcr byte ptr [eax], 0x11
-c01811|223344556677885f5f5f5f5f5f	32	plan9	RCRL $0x11, 0(AX)
-c01811|223344556677885f5f5f5f5f5f	64	gnu	rcrb $0x11,(%rax)
-c01811|223344556677885f5f5f5f5f5f	64	intel	rcr byte ptr [rax], 0x11
-c01811|223344556677885f5f5f5f5f5f	64	plan9	RCRL $0x11, 0(AX)
-c02011|223344556677885f5f5f5f5f5f	32	intel	shl byte ptr [eax], 0x11
-c02011|223344556677885f5f5f5f5f5f	32	plan9	SHLL $0x11, 0(AX)
-c02011|223344556677885f5f5f5f5f5f	64	gnu	shlb $0x11,(%rax)
-c02011|223344556677885f5f5f5f5f5f	64	intel	shl byte ptr [rax], 0x11
-c02011|223344556677885f5f5f5f5f5f	64	plan9	SHLL $0x11, 0(AX)
-c02811|223344556677885f5f5f5f5f5f	32	intel	shr byte ptr [eax], 0x11
-c02811|223344556677885f5f5f5f5f5f	32	plan9	SHRL $0x11, 0(AX)
-c02811|223344556677885f5f5f5f5f5f	64	gnu	shrb $0x11,(%rax)
-c02811|223344556677885f5f5f5f5f5f	64	intel	shr byte ptr [rax], 0x11
-c02811|223344556677885f5f5f5f5f5f	64	plan9	SHRL $0x11, 0(AX)
-c03811|223344556677885f5f5f5f5f5f	32	intel	sar byte ptr [eax], 0x11
-c03811|223344556677885f5f5f5f5f5f	32	plan9	SARL $0x11, 0(AX)
-c03811|223344556677885f5f5f5f5f5f	64	gnu	sarb $0x11,(%rax)
-c03811|223344556677885f5f5f5f5f5f	64	intel	sar byte ptr [rax], 0x11
-c03811|223344556677885f5f5f5f5f5f	64	plan9	SARL $0x11, 0(AX)
-c10011|223344556677885f5f5f5f5f5f	32	intel	rol dword ptr [eax], 0x11
-c10011|223344556677885f5f5f5f5f5f	32	plan9	ROLL $0x11, 0(AX)
-c10011|223344556677885f5f5f5f5f5f	64	gnu	roll $0x11,(%rax)
-c10011|223344556677885f5f5f5f5f5f	64	intel	rol dword ptr [rax], 0x11
-c10011|223344556677885f5f5f5f5f5f	64	plan9	ROLL $0x11, 0(AX)
-c10811|223344556677885f5f5f5f5f5f	32	intel	ror dword ptr [eax], 0x11
-c10811|223344556677885f5f5f5f5f5f	32	plan9	RORL $0x11, 0(AX)
-c10811|223344556677885f5f5f5f5f5f	64	gnu	rorl $0x11,(%rax)
-c10811|223344556677885f5f5f5f5f5f	64	intel	ror dword ptr [rax], 0x11
-c10811|223344556677885f5f5f5f5f5f	64	plan9	RORL $0x11, 0(AX)
-c11122|3344556677885f5f5f5f5f5f5f	32	intel	rcl dword ptr [ecx], 0x22
-c11122|3344556677885f5f5f5f5f5f5f	32	plan9	RCLL $0x22, 0(CX)
-c11122|3344556677885f5f5f5f5f5f5f	64	gnu	rcll $0x22,(%rcx)
-c11122|3344556677885f5f5f5f5f5f5f	64	intel	rcl dword ptr [rcx], 0x22
-c11122|3344556677885f5f5f5f5f5f5f	64	plan9	RCLL $0x22, 0(CX)
-c11811|223344556677885f5f5f5f5f5f	32	intel	rcr dword ptr [eax], 0x11
-c11811|223344556677885f5f5f5f5f5f	32	plan9	RCRL $0x11, 0(AX)
-c11811|223344556677885f5f5f5f5f5f	64	gnu	rcrl $0x11,(%rax)
-c11811|223344556677885f5f5f5f5f5f	64	intel	rcr dword ptr [rax], 0x11
-c11811|223344556677885f5f5f5f5f5f	64	plan9	RCRL $0x11, 0(AX)
-c12011|223344556677885f5f5f5f5f5f	32	intel	shl dword ptr [eax], 0x11
-c12011|223344556677885f5f5f5f5f5f	32	plan9	SHLL $0x11, 0(AX)
-c12011|223344556677885f5f5f5f5f5f	64	gnu	shll $0x11,(%rax)
-c12011|223344556677885f5f5f5f5f5f	64	intel	shl dword ptr [rax], 0x11
-c12011|223344556677885f5f5f5f5f5f	64	plan9	SHLL $0x11, 0(AX)
-c12811|223344556677885f5f5f5f5f5f	32	intel	shr dword ptr [eax], 0x11
-c12811|223344556677885f5f5f5f5f5f	32	plan9	SHRL $0x11, 0(AX)
-c12811|223344556677885f5f5f5f5f5f	64	gnu	shrl $0x11,(%rax)
-c12811|223344556677885f5f5f5f5f5f	64	intel	shr dword ptr [rax], 0x11
-c12811|223344556677885f5f5f5f5f5f	64	plan9	SHRL $0x11, 0(AX)
-c13811|223344556677885f5f5f5f5f5f	32	intel	sar dword ptr [eax], 0x11
-c13811|223344556677885f5f5f5f5f5f	32	plan9	SARL $0x11, 0(AX)
-c13811|223344556677885f5f5f5f5f5f	64	gnu	sarl $0x11,(%rax)
-c13811|223344556677885f5f5f5f5f5f	64	intel	sar dword ptr [rax], 0x11
-c13811|223344556677885f5f5f5f5f5f	64	plan9	SARL $0x11, 0(AX)
-c3|11223344556677885f5f5f5f5f5f5f	32	intel	ret
-c3|11223344556677885f5f5f5f5f5f5f	32	plan9	RET
-c3|11223344556677885f5f5f5f5f5f5f	64	gnu	retq
-c3|11223344556677885f5f5f5f5f5f5f	64	intel	ret
-c3|11223344556677885f5f5f5f5f5f5f	64	plan9	RET
-c411|223344556677885f5f5f5f5f5f5f	32	intel	les edx, ptr [ecx]
-c411|223344556677885f5f5f5f5f5f5f	32	plan9	LES 0(CX), DX
-c511|223344556677885f5f5f5f5f5f5f	32	intel	lds edx, ptr [ecx]
-c511|223344556677885f5f5f5f5f5f5f	32	plan9	LDS 0(CX), DX
-c60011|223344556677885f5f5f5f5f5f	32	intel	mov byte ptr [eax], 0x11
-c60011|223344556677885f5f5f5f5f5f	32	plan9	MOVL $0x11, 0(AX)
-c60011|223344556677885f5f5f5f5f5f	64	gnu	movb $0x11,(%rax)
-c60011|223344556677885f5f5f5f5f5f	64	intel	mov byte ptr [rax], 0x11
-c60011|223344556677885f5f5f5f5f5f	64	plan9	MOVL $0x11, 0(AX)
-c6f811|223344556677885f5f5f5f5f5f	32	intel	xabort 0x11
-c6f811|223344556677885f5f5f5f5f5f	32	plan9	XABORT $0x11
-c6f811|223344556677885f5f5f5f5f5f	64	gnu	xabort $0x11
-c6f811|223344556677885f5f5f5f5f5f	64	intel	xabort 0x11
-c6f811|223344556677885f5f5f5f5f5f	64	plan9	XABORT $0x11
-c70011223344|556677885f5f5f5f5f5f	32	intel	mov dword ptr [eax], 0x44332211
-c70011223344|556677885f5f5f5f5f5f	32	plan9	MOVL $0x44332211, 0(AX)
-c70011223344|556677885f5f5f5f5f5f	64	gnu	movl $0x44332211,(%rax)
-c70011223344|556677885f5f5f5f5f5f	64	intel	mov dword ptr [rax], 0x44332211
-c70011223344|556677885f5f5f5f5f5f	64	plan9	MOVL $0x44332211, 0(AX)
-c7f811223344|556677885f5f5f5f5f5f	32	intel	xbegin .+0x44332211
-c7f811223344|556677885f5f5f5f5f5f	32	plan9	XBEGIN .+1144201745
-c7f811223344|556677885f5f5f5f5f5f	64	gnu	xbeginq .+0x44332211
-c7f811223344|556677885f5f5f5f5f5f	64	intel	xbegin .+0x44332211
-c7f811223344|556677885f5f5f5f5f5f	64	plan9	XBEGIN .+1144201745
-c8112233|44556677885f5f5f5f5f5f5f	32	intel	enter 0x2211, 0x33
-c8112233|44556677885f5f5f5f5f5f5f	32	plan9	ENTER $0x33, $0x2211
-c8112233|44556677885f5f5f5f5f5f5f	64	gnu	enterq $0x2211,$0x33
-c8112233|44556677885f5f5f5f5f5f5f	64	intel	enter 0x2211, 0x33
-c8112233|44556677885f5f5f5f5f5f5f	64	plan9	ENTER $0x33, $0x2211
-c9|11223344556677885f5f5f5f5f5f5f	32	intel	leave
-c9|11223344556677885f5f5f5f5f5f5f	32	plan9	LEAVE
-c9|11223344556677885f5f5f5f5f5f5f	64	gnu	leaveq
-c9|11223344556677885f5f5f5f5f5f5f	64	intel	leave
-c9|11223344556677885f5f5f5f5f5f5f	64	plan9	LEAVE
-ca1122|3344556677885f5f5f5f5f5f5f	32	intel	ret far 0x2211
-ca1122|3344556677885f5f5f5f5f5f5f	32	plan9	LRET $0x2211
-ca1122|3344556677885f5f5f5f5f5f5f	64	gnu	lretq $0x2211
-ca1122|3344556677885f5f5f5f5f5f5f	64	intel	ret far 0x2211
-ca1122|3344556677885f5f5f5f5f5f5f	64	plan9	LRET $0x2211
-cb|11223344556677885f5f5f5f5f5f5f	32	intel	ret far
-cb|11223344556677885f5f5f5f5f5f5f	32	plan9	LRET
-cb|11223344556677885f5f5f5f5f5f5f	64	gnu	lretq
-cb|11223344556677885f5f5f5f5f5f5f	64	intel	ret far
-cb|11223344556677885f5f5f5f5f5f5f	64	plan9	LRET
-cc|11223344556677885f5f5f5f5f5f5f	32	intel	int3
-cc|11223344556677885f5f5f5f5f5f5f	32	plan9	INT $0x3
-cc|11223344556677885f5f5f5f5f5f5f	64	gnu	int3
-cc|11223344556677885f5f5f5f5f5f5f	64	intel	int3
-cc|11223344556677885f5f5f5f5f5f5f	64	plan9	INT $0x3
-cd11|223344556677885f5f5f5f5f5f5f	32	intel	int 0x11
-cd11|223344556677885f5f5f5f5f5f5f	32	plan9	INT $0x11
-cd11|223344556677885f5f5f5f5f5f5f	64	gnu	int $0x11
-cd11|223344556677885f5f5f5f5f5f5f	64	intel	int 0x11
-cd11|223344556677885f5f5f5f5f5f5f	64	plan9	INT $0x11
-ce|11223344556677885f5f5f5f5f5f5f	32	intel	into
-ce|11223344556677885f5f5f5f5f5f5f	32	plan9	INTO
-ce|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-ce|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-ce|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-cf|11223344556677885f5f5f5f5f5f5f	32	intel	iretd
-cf|11223344556677885f5f5f5f5f5f5f	32	plan9	IRETD
-cf|11223344556677885f5f5f5f5f5f5f	64	gnu	iret
-cf|11223344556677885f5f5f5f5f5f5f	64	intel	iretd
-cf|11223344556677885f5f5f5f5f5f5f	64	plan9	IRETD
-d000|11223344556677885f5f5f5f5f5f	32	intel	rol byte ptr [eax], 0x1
-d000|11223344556677885f5f5f5f5f5f	32	plan9	ROLL $0x1, 0(AX)
-d000|11223344556677885f5f5f5f5f5f	64	gnu	rolb (%rax)
-d000|11223344556677885f5f5f5f5f5f	64	intel	rol byte ptr [rax], 0x1
-d000|11223344556677885f5f5f5f5f5f	64	plan9	ROLL $0x1, 0(AX)
-d008|11223344556677885f5f5f5f5f5f	32	intel	ror byte ptr [eax], 0x1
-d008|11223344556677885f5f5f5f5f5f	32	plan9	RORL $0x1, 0(AX)
-d008|11223344556677885f5f5f5f5f5f	64	gnu	rorb (%rax)
-d008|11223344556677885f5f5f5f5f5f	64	intel	ror byte ptr [rax], 0x1
-d008|11223344556677885f5f5f5f5f5f	64	plan9	RORL $0x1, 0(AX)
-d011|223344556677885f5f5f5f5f5f5f	32	intel	rcl byte ptr [ecx], 0x1
-d011|223344556677885f5f5f5f5f5f5f	32	plan9	RCLL $0x1, 0(CX)
-d011|223344556677885f5f5f5f5f5f5f	64	gnu	rclb (%rcx)
-d011|223344556677885f5f5f5f5f5f5f	64	intel	rcl byte ptr [rcx], 0x1
-d011|223344556677885f5f5f5f5f5f5f	64	plan9	RCLL $0x1, 0(CX)
-d018|11223344556677885f5f5f5f5f5f	32	intel	rcr byte ptr [eax], 0x1
-d018|11223344556677885f5f5f5f5f5f	32	plan9	RCRL $0x1, 0(AX)
-d018|11223344556677885f5f5f5f5f5f	64	gnu	rcrb (%rax)
-d018|11223344556677885f5f5f5f5f5f	64	intel	rcr byte ptr [rax], 0x1
-d018|11223344556677885f5f5f5f5f5f	64	plan9	RCRL $0x1, 0(AX)
-d020|11223344556677885f5f5f5f5f5f	32	intel	shl byte ptr [eax], 0x1
-d020|11223344556677885f5f5f5f5f5f	32	plan9	SHLL $0x1, 0(AX)
-d020|11223344556677885f5f5f5f5f5f	64	gnu	shlb (%rax)
-d020|11223344556677885f5f5f5f5f5f	64	intel	shl byte ptr [rax], 0x1
-d020|11223344556677885f5f5f5f5f5f	64	plan9	SHLL $0x1, 0(AX)
-d028|11223344556677885f5f5f5f5f5f	32	intel	shr byte ptr [eax], 0x1
-d028|11223344556677885f5f5f5f5f5f	32	plan9	SHRL $0x1, 0(AX)
-d028|11223344556677885f5f5f5f5f5f	64	gnu	shrb (%rax)
-d028|11223344556677885f5f5f5f5f5f	64	intel	shr byte ptr [rax], 0x1
-d028|11223344556677885f5f5f5f5f5f	64	plan9	SHRL $0x1, 0(AX)
-d038|11223344556677885f5f5f5f5f5f	32	intel	sar byte ptr [eax], 0x1
-d038|11223344556677885f5f5f5f5f5f	32	plan9	SARL $0x1, 0(AX)
-d038|11223344556677885f5f5f5f5f5f	64	gnu	sarb (%rax)
-d038|11223344556677885f5f5f5f5f5f	64	intel	sar byte ptr [rax], 0x1
-d038|11223344556677885f5f5f5f5f5f	64	plan9	SARL $0x1, 0(AX)
-d100|11223344556677885f5f5f5f5f5f	32	intel	rol dword ptr [eax], 0x1
-d100|11223344556677885f5f5f5f5f5f	32	plan9	ROLL $0x1, 0(AX)
-d100|11223344556677885f5f5f5f5f5f	64	gnu	roll (%rax)
-d100|11223344556677885f5f5f5f5f5f	64	intel	rol dword ptr [rax], 0x1
-d100|11223344556677885f5f5f5f5f5f	64	plan9	ROLL $0x1, 0(AX)
-d108|11223344556677885f5f5f5f5f5f	32	intel	ror dword ptr [eax], 0x1
-d108|11223344556677885f5f5f5f5f5f	32	plan9	RORL $0x1, 0(AX)
-d108|11223344556677885f5f5f5f5f5f	64	gnu	rorl (%rax)
-d108|11223344556677885f5f5f5f5f5f	64	intel	ror dword ptr [rax], 0x1
-d108|11223344556677885f5f5f5f5f5f	64	plan9	RORL $0x1, 0(AX)
-d111|223344556677885f5f5f5f5f5f5f	32	intel	rcl dword ptr [ecx], 0x1
-d111|223344556677885f5f5f5f5f5f5f	32	plan9	RCLL $0x1, 0(CX)
-d111|223344556677885f5f5f5f5f5f5f	64	gnu	rcll (%rcx)
-d111|223344556677885f5f5f5f5f5f5f	64	intel	rcl dword ptr [rcx], 0x1
-d111|223344556677885f5f5f5f5f5f5f	64	plan9	RCLL $0x1, 0(CX)
-d118|11223344556677885f5f5f5f5f5f	32	intel	rcr dword ptr [eax], 0x1
-d118|11223344556677885f5f5f5f5f5f	32	plan9	RCRL $0x1, 0(AX)
-d118|11223344556677885f5f5f5f5f5f	64	gnu	rcrl (%rax)
-d118|11223344556677885f5f5f5f5f5f	64	intel	rcr dword ptr [rax], 0x1
-d118|11223344556677885f5f5f5f5f5f	64	plan9	RCRL $0x1, 0(AX)
-d120|11223344556677885f5f5f5f5f5f	32	intel	shl dword ptr [eax], 0x1
-d120|11223344556677885f5f5f5f5f5f	32	plan9	SHLL $0x1, 0(AX)
-d120|11223344556677885f5f5f5f5f5f	64	gnu	shll (%rax)
-d120|11223344556677885f5f5f5f5f5f	64	intel	shl dword ptr [rax], 0x1
-d120|11223344556677885f5f5f5f5f5f	64	plan9	SHLL $0x1, 0(AX)
-d128|11223344556677885f5f5f5f5f5f	32	intel	shr dword ptr [eax], 0x1
-d128|11223344556677885f5f5f5f5f5f	32	plan9	SHRL $0x1, 0(AX)
-d128|11223344556677885f5f5f5f5f5f	64	gnu	shrl (%rax)
-d128|11223344556677885f5f5f5f5f5f	64	intel	shr dword ptr [rax], 0x1
-d128|11223344556677885f5f5f5f5f5f	64	plan9	SHRL $0x1, 0(AX)
-d138|11223344556677885f5f5f5f5f5f	32	intel	sar dword ptr [eax], 0x1
-d138|11223344556677885f5f5f5f5f5f	32	plan9	SARL $0x1, 0(AX)
-d138|11223344556677885f5f5f5f5f5f	64	gnu	sarl (%rax)
-d138|11223344556677885f5f5f5f5f5f	64	intel	sar dword ptr [rax], 0x1
-d138|11223344556677885f5f5f5f5f5f	64	plan9	SARL $0x1, 0(AX)
-d200|11223344556677885f5f5f5f5f5f	32	intel	rol byte ptr [eax], cl
-d200|11223344556677885f5f5f5f5f5f	32	plan9	ROLL CL, 0(AX)
-d200|11223344556677885f5f5f5f5f5f	64	gnu	rolb %cl,(%rax)
-d200|11223344556677885f5f5f5f5f5f	64	intel	rol byte ptr [rax], cl
-d200|11223344556677885f5f5f5f5f5f	64	plan9	ROLL CL, 0(AX)
-d208|11223344556677885f5f5f5f5f5f	32	intel	ror byte ptr [eax], cl
-d208|11223344556677885f5f5f5f5f5f	32	plan9	RORL CL, 0(AX)
-d208|11223344556677885f5f5f5f5f5f	64	gnu	rorb %cl,(%rax)
-d208|11223344556677885f5f5f5f5f5f	64	intel	ror byte ptr [rax], cl
-d208|11223344556677885f5f5f5f5f5f	64	plan9	RORL CL, 0(AX)
-d211|223344556677885f5f5f5f5f5f5f	32	intel	rcl byte ptr [ecx], cl
-d211|223344556677885f5f5f5f5f5f5f	32	plan9	RCLL CL, 0(CX)
-d211|223344556677885f5f5f5f5f5f5f	64	gnu	rclb %cl,(%rcx)
-d211|223344556677885f5f5f5f5f5f5f	64	intel	rcl byte ptr [rcx], cl
-d211|223344556677885f5f5f5f5f5f5f	64	plan9	RCLL CL, 0(CX)
-d218|11223344556677885f5f5f5f5f5f	32	intel	rcr byte ptr [eax], cl
-d218|11223344556677885f5f5f5f5f5f	32	plan9	RCRL CL, 0(AX)
-d218|11223344556677885f5f5f5f5f5f	64	gnu	rcrb %cl,(%rax)
-d218|11223344556677885f5f5f5f5f5f	64	intel	rcr byte ptr [rax], cl
-d218|11223344556677885f5f5f5f5f5f	64	plan9	RCRL CL, 0(AX)
-d220|11223344556677885f5f5f5f5f5f	32	intel	shl byte ptr [eax], cl
-d220|11223344556677885f5f5f5f5f5f	32	plan9	SHLL CL, 0(AX)
-d220|11223344556677885f5f5f5f5f5f	64	gnu	shlb %cl,(%rax)
-d220|11223344556677885f5f5f5f5f5f	64	intel	shl byte ptr [rax], cl
-d220|11223344556677885f5f5f5f5f5f	64	plan9	SHLL CL, 0(AX)
-d228|11223344556677885f5f5f5f5f5f	32	intel	shr byte ptr [eax], cl
-d228|11223344556677885f5f5f5f5f5f	32	plan9	SHRL CL, 0(AX)
-d228|11223344556677885f5f5f5f5f5f	64	gnu	shrb %cl,(%rax)
-d228|11223344556677885f5f5f5f5f5f	64	intel	shr byte ptr [rax], cl
-d228|11223344556677885f5f5f5f5f5f	64	plan9	SHRL CL, 0(AX)
-d238|11223344556677885f5f5f5f5f5f	32	intel	sar byte ptr [eax], cl
-d238|11223344556677885f5f5f5f5f5f	32	plan9	SARL CL, 0(AX)
-d238|11223344556677885f5f5f5f5f5f	64	gnu	sarb %cl,(%rax)
-d238|11223344556677885f5f5f5f5f5f	64	intel	sar byte ptr [rax], cl
-d238|11223344556677885f5f5f5f5f5f	64	plan9	SARL CL, 0(AX)
-d300|11223344556677885f5f5f5f5f5f	32	intel	rol dword ptr [eax], cl
-d300|11223344556677885f5f5f5f5f5f	32	plan9	ROLL CL, 0(AX)
-d300|11223344556677885f5f5f5f5f5f	64	gnu	roll %cl,(%rax)
-d300|11223344556677885f5f5f5f5f5f	64	intel	rol dword ptr [rax], cl
-d300|11223344556677885f5f5f5f5f5f	64	plan9	ROLL CL, 0(AX)
-d308|11223344556677885f5f5f5f5f5f	32	intel	ror dword ptr [eax], cl
-d308|11223344556677885f5f5f5f5f5f	32	plan9	RORL CL, 0(AX)
-d308|11223344556677885f5f5f5f5f5f	64	gnu	rorl %cl,(%rax)
-d308|11223344556677885f5f5f5f5f5f	64	intel	ror dword ptr [rax], cl
-d308|11223344556677885f5f5f5f5f5f	64	plan9	RORL CL, 0(AX)
-d311|223344556677885f5f5f5f5f5f5f	32	intel	rcl dword ptr [ecx], cl
-d311|223344556677885f5f5f5f5f5f5f	32	plan9	RCLL CL, 0(CX)
-d311|223344556677885f5f5f5f5f5f5f	64	gnu	rcll %cl,(%rcx)
-d311|223344556677885f5f5f5f5f5f5f	64	intel	rcl dword ptr [rcx], cl
-d311|223344556677885f5f5f5f5f5f5f	64	plan9	RCLL CL, 0(CX)
-d318|11223344556677885f5f5f5f5f5f	32	intel	rcr dword ptr [eax], cl
-d318|11223344556677885f5f5f5f5f5f	32	plan9	RCRL CL, 0(AX)
-d318|11223344556677885f5f5f5f5f5f	64	gnu	rcrl %cl,(%rax)
-d318|11223344556677885f5f5f5f5f5f	64	intel	rcr dword ptr [rax], cl
-d318|11223344556677885f5f5f5f5f5f	64	plan9	RCRL CL, 0(AX)
-d320|11223344556677885f5f5f5f5f5f	32	intel	shl dword ptr [eax], cl
-d320|11223344556677885f5f5f5f5f5f	32	plan9	SHLL CL, 0(AX)
-d320|11223344556677885f5f5f5f5f5f	64	gnu	shll %cl,(%rax)
-d320|11223344556677885f5f5f5f5f5f	64	intel	shl dword ptr [rax], cl
-d320|11223344556677885f5f5f5f5f5f	64	plan9	SHLL CL, 0(AX)
-d328|11223344556677885f5f5f5f5f5f	32	intel	shr dword ptr [eax], cl
-d328|11223344556677885f5f5f5f5f5f	32	plan9	SHRL CL, 0(AX)
-d328|11223344556677885f5f5f5f5f5f	64	gnu	shrl %cl,(%rax)
-d328|11223344556677885f5f5f5f5f5f	64	intel	shr dword ptr [rax], cl
-d328|11223344556677885f5f5f5f5f5f	64	plan9	SHRL CL, 0(AX)
-d338|11223344556677885f5f5f5f5f5f	32	intel	sar dword ptr [eax], cl
-d338|11223344556677885f5f5f5f5f5f	32	plan9	SARL CL, 0(AX)
-d338|11223344556677885f5f5f5f5f5f	64	gnu	sarl %cl,(%rax)
-d338|11223344556677885f5f5f5f5f5f	64	intel	sar dword ptr [rax], cl
-d338|11223344556677885f5f5f5f5f5f	64	plan9	SARL CL, 0(AX)
-d511|223344556677885f5f5f5f5f5f5f	32	intel	aad 0x11
-d511|223344556677885f5f5f5f5f5f5f	32	plan9	AAD $0x11
-d5|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
-d5|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
-d5|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
-d800|11223344556677885f5f5f5f5f5f	32	intel	fadd st0, dword ptr [eax]
-d800|11223344556677885f5f5f5f5f5f	32	plan9	FADD 0(AX)
-d800|11223344556677885f5f5f5f5f5f	64	gnu	fadds (%rax)
-d800|11223344556677885f5f5f5f5f5f	64	intel	fadd st0, dword ptr [rax]
-d800|11223344556677885f5f5f5f5f5f	64	plan9	FADD 0(AX)
-d808|11223344556677885f5f5f5f5f5f	32	intel	fmul st0, dword ptr [eax]
-d808|11223344556677885f5f5f5f5f5f	32	plan9	FMUL 0(AX)
-d808|11223344556677885f5f5f5f5f5f	64	gnu	fmuls (%rax)
-d808|11223344556677885f5f5f5f5f5f	64	intel	fmul st0, dword ptr [rax]
-d808|11223344556677885f5f5f5f5f5f	64	plan9	FMUL 0(AX)
-d811|223344556677885f5f5f5f5f5f5f	32	intel	fcom st0, dword ptr [ecx]
-d811|223344556677885f5f5f5f5f5f5f	32	plan9	FCOM 0(CX)
-d811|223344556677885f5f5f5f5f5f5f	64	gnu	fcoms (%rcx)
-d811|223344556677885f5f5f5f5f5f5f	64	intel	fcom st0, dword ptr [rcx]
-d811|223344556677885f5f5f5f5f5f5f	64	plan9	FCOM 0(CX)
-d818|11223344556677885f5f5f5f5f5f	32	intel	fcomp st0, dword ptr [eax]
-d818|11223344556677885f5f5f5f5f5f	32	plan9	FCOMP 0(AX)
-d818|11223344556677885f5f5f5f5f5f	64	gnu	fcomps (%rax)
-d818|11223344556677885f5f5f5f5f5f	64	intel	fcomp st0, dword ptr [rax]
-d818|11223344556677885f5f5f5f5f5f	64	plan9	FCOMP 0(AX)
-d820|11223344556677885f5f5f5f5f5f	32	intel	fsub st0, dword ptr [eax]
-d820|11223344556677885f5f5f5f5f5f	32	plan9	FSUB 0(AX)
-d820|11223344556677885f5f5f5f5f5f	64	gnu	fsubs (%rax)
-d820|11223344556677885f5f5f5f5f5f	64	intel	fsub st0, dword ptr [rax]
-d820|11223344556677885f5f5f5f5f5f	64	plan9	FSUB 0(AX)
-d828|11223344556677885f5f5f5f5f5f	32	intel	fsubr st0, dword ptr [eax]
-d828|11223344556677885f5f5f5f5f5f	32	plan9	FSUBR 0(AX)
-d828|11223344556677885f5f5f5f5f5f	64	gnu	fsubrs (%rax)
-d828|11223344556677885f5f5f5f5f5f	64	intel	fsubr st0, dword ptr [rax]
-d828|11223344556677885f5f5f5f5f5f	64	plan9	FSUBR 0(AX)
-d830|11223344556677885f5f5f5f5f5f	32	intel	fdiv st0, dword ptr [eax]
-d830|11223344556677885f5f5f5f5f5f	32	plan9	FDIV 0(AX)
-d830|11223344556677885f5f5f5f5f5f	64	gnu	fdivs (%rax)
-d830|11223344556677885f5f5f5f5f5f	64	intel	fdiv st0, dword ptr [rax]
-d830|11223344556677885f5f5f5f5f5f	64	plan9	FDIV 0(AX)
-d838|11223344556677885f5f5f5f5f5f	32	intel	fdivr st0, dword ptr [eax]
-d838|11223344556677885f5f5f5f5f5f	32	plan9	FDIVR 0(AX)
-d838|11223344556677885f5f5f5f5f5f	64	gnu	fdivrs (%rax)
-d838|11223344556677885f5f5f5f5f5f	64	intel	fdivr st0, dword ptr [rax]
-d838|11223344556677885f5f5f5f5f5f	64	plan9	FDIVR 0(AX)
-d8c0|11223344556677885f5f5f5f5f5f	32	intel	fadd st0, st0
-d8c0|11223344556677885f5f5f5f5f5f	32	plan9	FADD F0, F0
-d8c0|11223344556677885f5f5f5f5f5f	64	gnu	fadd %st,%st
-d8c0|11223344556677885f5f5f5f5f5f	64	intel	fadd st0, st0
-d8c0|11223344556677885f5f5f5f5f5f	64	plan9	FADD F0, F0
-d8c8|11223344556677885f5f5f5f5f5f	32	intel	fmul st0, st0
-d8c8|11223344556677885f5f5f5f5f5f	32	plan9	FMUL F0, F0
-d8c8|11223344556677885f5f5f5f5f5f	64	gnu	fmul %st,%st
-d8c8|11223344556677885f5f5f5f5f5f	64	intel	fmul st0, st0
-d8c8|11223344556677885f5f5f5f5f5f	64	plan9	FMUL F0, F0
-d8d0|11223344556677885f5f5f5f5f5f	32	intel	fcom st0, st0
-d8d0|11223344556677885f5f5f5f5f5f	32	plan9	FCOM F0
-d8d0|11223344556677885f5f5f5f5f5f	64	gnu	fcom %st
-d8d0|11223344556677885f5f5f5f5f5f	64	intel	fcom st0, st0
-d8d0|11223344556677885f5f5f5f5f5f	64	plan9	FCOM F0
-d8d8|11223344556677885f5f5f5f5f5f	32	intel	fcomp st0, st0
-d8d8|11223344556677885f5f5f5f5f5f	32	plan9	FCOMP F0
-d8d8|11223344556677885f5f5f5f5f5f	64	gnu	fcomp %st
-d8d8|11223344556677885f5f5f5f5f5f	64	intel	fcomp st0, st0
-d8d8|11223344556677885f5f5f5f5f5f	64	plan9	FCOMP F0
-d8e0|11223344556677885f5f5f5f5f5f	32	intel	fsub st0, st0
-d8e0|11223344556677885f5f5f5f5f5f	32	plan9	FSUB F0, F0
-d8e0|11223344556677885f5f5f5f5f5f	64	gnu	fsub %st,%st
-d8e0|11223344556677885f5f5f5f5f5f	64	intel	fsub st0, st0
-d8e0|11223344556677885f5f5f5f5f5f	64	plan9	FSUB F0, F0
-d8e8|11223344556677885f5f5f5f5f5f	32	intel	fsubr st0, st0
-d8e8|11223344556677885f5f5f5f5f5f	32	plan9	FSUBR F0, F0
-d8e8|11223344556677885f5f5f5f5f5f	64	gnu	fsubr %st,%st
-d8e8|11223344556677885f5f5f5f5f5f	64	intel	fsubr st0, st0
-d8e8|11223344556677885f5f5f5f5f5f	64	plan9	FSUBR F0, F0
-d8f0|11223344556677885f5f5f5f5f5f	32	intel	fdiv st0, st0
-d8f0|11223344556677885f5f5f5f5f5f	32	plan9	FDIV F0, F0
-d8f0|11223344556677885f5f5f5f5f5f	64	gnu	fdiv %st,%st
-d8f0|11223344556677885f5f5f5f5f5f	64	intel	fdiv st0, st0
-d8f0|11223344556677885f5f5f5f5f5f	64	plan9	FDIV F0, F0
-d8f8|11223344556677885f5f5f5f5f5f	32	intel	fdivr st0, st0
-d8f8|11223344556677885f5f5f5f5f5f	32	plan9	FDIVR F0, F0
-d8f8|11223344556677885f5f5f5f5f5f	64	gnu	fdivr %st,%st
-d8f8|11223344556677885f5f5f5f5f5f	64	intel	fdivr st0, st0
-d8f8|11223344556677885f5f5f5f5f5f	64	plan9	FDIVR F0, F0
-d900|11223344556677885f5f5f5f5f5f	32	intel	fld st0, dword ptr [eax]
-d900|11223344556677885f5f5f5f5f5f	32	plan9	FLD 0(AX)
-d900|11223344556677885f5f5f5f5f5f	64	gnu	flds (%rax)
-d900|11223344556677885f5f5f5f5f5f	64	intel	fld st0, dword ptr [rax]
-d900|11223344556677885f5f5f5f5f5f	64	plan9	FLD 0(AX)
-d911|223344556677885f5f5f5f5f5f5f	32	intel	fst dword ptr [ecx], st0
-d911|223344556677885f5f5f5f5f5f5f	32	plan9	FST 0(CX)
-d911|223344556677885f5f5f5f5f5f5f	64	gnu	fsts (%rcx)
-d911|223344556677885f5f5f5f5f5f5f	64	intel	fst dword ptr [rcx], st0
-d911|223344556677885f5f5f5f5f5f5f	64	plan9	FST 0(CX)
-d918|11223344556677885f5f5f5f5f5f	32	intel	fstp dword ptr [eax], st0
-d918|11223344556677885f5f5f5f5f5f	32	plan9	FSTP 0(AX)
-d918|11223344556677885f5f5f5f5f5f	64	gnu	fstps (%rax)
-d918|11223344556677885f5f5f5f5f5f	64	intel	fstp dword ptr [rax], st0
-d918|11223344556677885f5f5f5f5f5f	64	plan9	FSTP 0(AX)
-d928|11223344556677885f5f5f5f5f5f	32	intel	fldcw word ptr [eax]
-d928|11223344556677885f5f5f5f5f5f	32	plan9	FLDCW 0(AX)
-d928|11223344556677885f5f5f5f5f5f	64	gnu	fldcw (%rax)
-d928|11223344556677885f5f5f5f5f5f	64	intel	fldcw word ptr [rax]
-d928|11223344556677885f5f5f5f5f5f	64	plan9	FLDCW 0(AX)
-d930|11223344556677885f5f5f5f5f5f	32	intel	fnstenv ptr [eax]
-d930|11223344556677885f5f5f5f5f5f	32	plan9	FNSTENV 0(AX)
-d930|11223344556677885f5f5f5f5f5f	64	gnu	fnstenv (%rax)
-d930|11223344556677885f5f5f5f5f5f	64	intel	fnstenv ptr [rax]
-d930|11223344556677885f5f5f5f5f5f	64	plan9	FNSTENV 0(AX)
-d938|11223344556677885f5f5f5f5f5f	32	intel	fnstcw word ptr [eax]
-d938|11223344556677885f5f5f5f5f5f	32	plan9	FNSTCW 0(AX)
-d938|11223344556677885f5f5f5f5f5f	64	gnu	fnstcw (%rax)
-d938|11223344556677885f5f5f5f5f5f	64	intel	fnstcw word ptr [rax]
-d938|11223344556677885f5f5f5f5f5f	64	plan9	FNSTCW 0(AX)
-d9c0|11223344556677885f5f5f5f5f5f	32	intel	fld st0, st0
-d9c0|11223344556677885f5f5f5f5f5f	32	plan9	FLD F0
-d9c0|11223344556677885f5f5f5f5f5f	64	gnu	fld %st
-d9c0|11223344556677885f5f5f5f5f5f	64	intel	fld st0, st0
-d9c0|11223344556677885f5f5f5f5f5f	64	plan9	FLD F0
-d9c8|11223344556677885f5f5f5f5f5f	32	intel	fxch st0, st0
-d9c8|11223344556677885f5f5f5f5f5f	32	plan9	FXCH F0
-d9c8|11223344556677885f5f5f5f5f5f	64	gnu	fxch %st
-d9c8|11223344556677885f5f5f5f5f5f	64	intel	fxch st0, st0
-d9c8|11223344556677885f5f5f5f5f5f	64	plan9	FXCH F0
-d9d0|11223344556677885f5f5f5f5f5f	32	intel	fnop
-d9d0|11223344556677885f5f5f5f5f5f	32	plan9	FNOP
-d9d0|11223344556677885f5f5f5f5f5f	64	gnu	fnop
-d9d0|11223344556677885f5f5f5f5f5f	64	intel	fnop
-d9d0|11223344556677885f5f5f5f5f5f	64	plan9	FNOP
-d9e0|11223344556677885f5f5f5f5f5f	32	intel	fchs st0
-d9e0|11223344556677885f5f5f5f5f5f	32	plan9	FCHS
-d9e0|11223344556677885f5f5f5f5f5f	64	gnu	fchs
-d9e0|11223344556677885f5f5f5f5f5f	64	intel	fchs st0
-d9e0|11223344556677885f5f5f5f5f5f	64	plan9	FCHS
-d9e1|11223344556677885f5f5f5f5f5f	32	intel	fabs st0
-d9e1|11223344556677885f5f5f5f5f5f	32	plan9	FABS
-d9e1|11223344556677885f5f5f5f5f5f	64	gnu	fabs
-d9e1|11223344556677885f5f5f5f5f5f	64	intel	fabs st0
-d9e1|11223344556677885f5f5f5f5f5f	64	plan9	FABS
-d9e4|11223344556677885f5f5f5f5f5f	32	intel	ftst st0
-d9e4|11223344556677885f5f5f5f5f5f	32	plan9	FTST
-d9e4|11223344556677885f5f5f5f5f5f	64	gnu	ftst
-d9e4|11223344556677885f5f5f5f5f5f	64	intel	ftst st0
-d9e4|11223344556677885f5f5f5f5f5f	64	plan9	FTST
-d9e5|11223344556677885f5f5f5f5f5f	32	intel	fxam st0
-d9e5|11223344556677885f5f5f5f5f5f	32	plan9	FXAM
-d9e5|11223344556677885f5f5f5f5f5f	64	gnu	fxam
-d9e5|11223344556677885f5f5f5f5f5f	64	intel	fxam st0
-d9e5|11223344556677885f5f5f5f5f5f	64	plan9	FXAM
-d9e8|11223344556677885f5f5f5f5f5f	32	intel	fld1 st0
-d9e8|11223344556677885f5f5f5f5f5f	32	plan9	FLD1
-d9e8|11223344556677885f5f5f5f5f5f	64	gnu	fld1
-d9e8|11223344556677885f5f5f5f5f5f	64	intel	fld1 st0
-d9e8|11223344556677885f5f5f5f5f5f	64	plan9	FLD1
-d9e9|11223344556677885f5f5f5f5f5f	32	intel	fldl2t st0
-d9e9|11223344556677885f5f5f5f5f5f	32	plan9	FLDL2T
-d9e9|11223344556677885f5f5f5f5f5f	64	gnu	fldl2t
-d9e9|11223344556677885f5f5f5f5f5f	64	intel	fldl2t st0
-d9e9|11223344556677885f5f5f5f5f5f	64	plan9	FLDL2T
-d9ea|11223344556677885f5f5f5f5f5f	32	intel	fldl2e st0
-d9ea|11223344556677885f5f5f5f5f5f	32	plan9	FLDL2E
-d9ea|11223344556677885f5f5f5f5f5f	64	gnu	fldl2e
-d9ea|11223344556677885f5f5f5f5f5f	64	intel	fldl2e st0
-d9ea|11223344556677885f5f5f5f5f5f	64	plan9	FLDL2E
-d9eb|11223344556677885f5f5f5f5f5f	32	intel	fldpi st0
-d9eb|11223344556677885f5f5f5f5f5f	32	plan9	FLDPI
-d9eb|11223344556677885f5f5f5f5f5f	64	gnu	fldpi
-d9eb|11223344556677885f5f5f5f5f5f	64	intel	fldpi st0
-d9eb|11223344556677885f5f5f5f5f5f	64	plan9	FLDPI
-d9ec|11223344556677885f5f5f5f5f5f	32	intel	fldlg2 st0
-d9ec|11223344556677885f5f5f5f5f5f	32	plan9	FLDLG2
-d9ec|11223344556677885f5f5f5f5f5f	64	gnu	fldlg2
-d9ec|11223344556677885f5f5f5f5f5f	64	intel	fldlg2 st0
-d9ec|11223344556677885f5f5f5f5f5f	64	plan9	FLDLG2
-d9f0|11223344556677885f5f5f5f5f5f	32	intel	f2xm1 st0
-d9f0|11223344556677885f5f5f5f5f5f	32	plan9	F2XM1
-d9f0|11223344556677885f5f5f5f5f5f	64	gnu	f2xm1
-d9f0|11223344556677885f5f5f5f5f5f	64	intel	f2xm1 st0
-d9f0|11223344556677885f5f5f5f5f5f	64	plan9	F2XM1
-d9f1|11223344556677885f5f5f5f5f5f	32	intel	fyl2x st0, st1
-d9f1|11223344556677885f5f5f5f5f5f	32	plan9	FYL2X
-d9f1|11223344556677885f5f5f5f5f5f	64	gnu	fyl2x
-d9f1|11223344556677885f5f5f5f5f5f	64	intel	fyl2x st0, st1
-d9f1|11223344556677885f5f5f5f5f5f	64	plan9	FYL2X
-d9f2|11223344556677885f5f5f5f5f5f	32	intel	fptan st0, st1
-d9f2|11223344556677885f5f5f5f5f5f	32	plan9	FPTAN
-d9f2|11223344556677885f5f5f5f5f5f	64	gnu	fptan
-d9f2|11223344556677885f5f5f5f5f5f	64	intel	fptan st0, st1
-d9f2|11223344556677885f5f5f5f5f5f	64	plan9	FPTAN
-d9f3|11223344556677885f5f5f5f5f5f	32	intel	fpatan st0, st1
-d9f3|11223344556677885f5f5f5f5f5f	32	plan9	FPATAN
-d9f3|11223344556677885f5f5f5f5f5f	64	gnu	fpatan
-d9f3|11223344556677885f5f5f5f5f5f	64	intel	fpatan st0, st1
-d9f3|11223344556677885f5f5f5f5f5f	64	plan9	FPATAN
-d9f4|11223344556677885f5f5f5f5f5f	32	intel	fxtract st0, st1
-d9f4|11223344556677885f5f5f5f5f5f	32	plan9	FXTRACT
-d9f4|11223344556677885f5f5f5f5f5f	64	gnu	fxtract
-d9f4|11223344556677885f5f5f5f5f5f	64	intel	fxtract st0, st1
-d9f4|11223344556677885f5f5f5f5f5f	64	plan9	FXTRACT
-d9f5|11223344556677885f5f5f5f5f5f	32	intel	fprem1 st0, st1
-d9f5|11223344556677885f5f5f5f5f5f	32	plan9	FPREM1
-d9f5|11223344556677885f5f5f5f5f5f	64	gnu	fprem1
-d9f5|11223344556677885f5f5f5f5f5f	64	intel	fprem1 st0, st1
-d9f5|11223344556677885f5f5f5f5f5f	64	plan9	FPREM1
-d9f6|11223344556677885f5f5f5f5f5f	32	intel	fdecstp
-d9f6|11223344556677885f5f5f5f5f5f	32	plan9	FDECSTP
-d9f6|11223344556677885f5f5f5f5f5f	64	gnu	fdecstp
-d9f6|11223344556677885f5f5f5f5f5f	64	intel	fdecstp
-d9f6|11223344556677885f5f5f5f5f5f	64	plan9	FDECSTP
-d9f7|11223344556677885f5f5f5f5f5f	32	intel	fincstp
-d9f7|11223344556677885f5f5f5f5f5f	32	plan9	FINCSTP
-d9f7|11223344556677885f5f5f5f5f5f	64	gnu	fincstp
-d9f7|11223344556677885f5f5f5f5f5f	64	intel	fincstp
-d9f7|11223344556677885f5f5f5f5f5f	64	plan9	FINCSTP
-d9f8|11223344556677885f5f5f5f5f5f	32	intel	fprem st0, st1
-d9f8|11223344556677885f5f5f5f5f5f	32	plan9	FPREM
-d9f8|11223344556677885f5f5f5f5f5f	64	gnu	fprem
-d9f8|11223344556677885f5f5f5f5f5f	64	intel	fprem st0, st1
-d9f8|11223344556677885f5f5f5f5f5f	64	plan9	FPREM
-d9f9|11223344556677885f5f5f5f5f5f	32	intel	fyl2xp1 st0, st1
-d9f9|11223344556677885f5f5f5f5f5f	32	plan9	FYL2XP1
-d9f9|11223344556677885f5f5f5f5f5f	64	gnu	fyl2xp1
-d9f9|11223344556677885f5f5f5f5f5f	64	intel	fyl2xp1 st0, st1
-d9f9|11223344556677885f5f5f5f5f5f	64	plan9	FYL2XP1
-d9fa|11223344556677885f5f5f5f5f5f	32	intel	fsqrt st0
-d9fa|11223344556677885f5f5f5f5f5f	32	plan9	FSQRT
-d9fa|11223344556677885f5f5f5f5f5f	64	gnu	fsqrt
-d9fa|11223344556677885f5f5f5f5f5f	64	intel	fsqrt st0
-d9fa|11223344556677885f5f5f5f5f5f	64	plan9	FSQRT
-d9fb|11223344556677885f5f5f5f5f5f	32	intel	fsincos st0, st1
-d9fb|11223344556677885f5f5f5f5f5f	32	plan9	FSINCOS
-d9fb|11223344556677885f5f5f5f5f5f	64	gnu	fsincos
-d9fb|11223344556677885f5f5f5f5f5f	64	intel	fsincos st0, st1
-d9fb|11223344556677885f5f5f5f5f5f	64	plan9	FSINCOS
-d9fc|11223344556677885f5f5f5f5f5f	32	intel	frndint st0
-d9fc|11223344556677885f5f5f5f5f5f	32	plan9	FRNDINT
-d9fc|11223344556677885f5f5f5f5f5f	64	gnu	frndint
-d9fc|11223344556677885f5f5f5f5f5f	64	intel	frndint st0
-d9fc|11223344556677885f5f5f5f5f5f	64	plan9	FRNDINT
-d9fd|11223344556677885f5f5f5f5f5f	32	intel	fscale st0, st1
-d9fd|11223344556677885f5f5f5f5f5f	32	plan9	FSCALE
-d9fd|11223344556677885f5f5f5f5f5f	64	gnu	fscale
-d9fd|11223344556677885f5f5f5f5f5f	64	intel	fscale st0, st1
-d9fd|11223344556677885f5f5f5f5f5f	64	plan9	FSCALE
-d9fe|11223344556677885f5f5f5f5f5f	32	intel	fsin st0
-d9fe|11223344556677885f5f5f5f5f5f	32	plan9	FSIN
-d9fe|11223344556677885f5f5f5f5f5f	64	gnu	fsin
-d9fe|11223344556677885f5f5f5f5f5f	64	intel	fsin st0
-d9fe|11223344556677885f5f5f5f5f5f	64	plan9	FSIN
-d9ff|11223344556677885f5f5f5f5f5f	32	intel	fcos st0
-d9ff|11223344556677885f5f5f5f5f5f	32	plan9	FCOS
-d9ff|11223344556677885f5f5f5f5f5f	64	gnu	fcos
-d9ff|11223344556677885f5f5f5f5f5f	64	intel	fcos st0
-d9ff|11223344556677885f5f5f5f5f5f	64	plan9	FCOS
-da00|11223344556677885f5f5f5f5f5f	32	intel	fiadd st0, dword ptr [eax]
-da00|11223344556677885f5f5f5f5f5f	32	plan9	FIADD 0(AX)
-da00|11223344556677885f5f5f5f5f5f	64	gnu	fiaddl (%rax)
-da00|11223344556677885f5f5f5f5f5f	64	intel	fiadd st0, dword ptr [rax]
-da00|11223344556677885f5f5f5f5f5f	64	plan9	FIADD 0(AX)
-da08|11223344556677885f5f5f5f5f5f	32	intel	fimul st0, dword ptr [eax]
-da08|11223344556677885f5f5f5f5f5f	32	plan9	FIMUL 0(AX)
-da08|11223344556677885f5f5f5f5f5f	64	gnu	fimull (%rax)
-da08|11223344556677885f5f5f5f5f5f	64	intel	fimul st0, dword ptr [rax]
-da08|11223344556677885f5f5f5f5f5f	64	plan9	FIMUL 0(AX)
-da11|223344556677885f5f5f5f5f5f5f	32	intel	ficom st0, dword ptr [ecx]
-da11|223344556677885f5f5f5f5f5f5f	32	plan9	FICOM 0(CX)
-da11|223344556677885f5f5f5f5f5f5f	64	gnu	ficoml (%rcx)
-da11|223344556677885f5f5f5f5f5f5f	64	intel	ficom st0, dword ptr [rcx]
-da11|223344556677885f5f5f5f5f5f5f	64	plan9	FICOM 0(CX)
-da18|11223344556677885f5f5f5f5f5f	32	intel	ficomp st0, dword ptr [eax]
-da18|11223344556677885f5f5f5f5f5f	32	plan9	FICOMP 0(AX)
-da18|11223344556677885f5f5f5f5f5f	64	gnu	ficompl (%rax)
-da18|11223344556677885f5f5f5f5f5f	64	intel	ficomp st0, dword ptr [rax]
-da18|11223344556677885f5f5f5f5f5f	64	plan9	FICOMP 0(AX)
-da20|11223344556677885f5f5f5f5f5f	32	intel	fisub st0, dword ptr [eax]
-da20|11223344556677885f5f5f5f5f5f	32	plan9	FISUB 0(AX)
-da20|11223344556677885f5f5f5f5f5f	64	gnu	fisubl (%rax)
-da20|11223344556677885f5f5f5f5f5f	64	intel	fisub st0, dword ptr [rax]
-da20|11223344556677885f5f5f5f5f5f	64	plan9	FISUB 0(AX)
-da28|11223344556677885f5f5f5f5f5f	32	intel	fisubr st0, dword ptr [eax]
-da28|11223344556677885f5f5f5f5f5f	32	plan9	FISUBR 0(AX)
-da28|11223344556677885f5f5f5f5f5f	64	gnu	fisubrl (%rax)
-da28|11223344556677885f5f5f5f5f5f	64	intel	fisubr st0, dword ptr [rax]
-da28|11223344556677885f5f5f5f5f5f	64	plan9	FISUBR 0(AX)
-da30|11223344556677885f5f5f5f5f5f	32	intel	fidiv st0, dword ptr [eax]
-da30|11223344556677885f5f5f5f5f5f	32	plan9	FIDIV 0(AX)
-da30|11223344556677885f5f5f5f5f5f	64	gnu	fidivl (%rax)
-da30|11223344556677885f5f5f5f5f5f	64	intel	fidiv st0, dword ptr [rax]
-da30|11223344556677885f5f5f5f5f5f	64	plan9	FIDIV 0(AX)
-da38|11223344556677885f5f5f5f5f5f	32	intel	fidivr st0, dword ptr [eax]
-da38|11223344556677885f5f5f5f5f5f	32	plan9	FIDIVR 0(AX)
-da38|11223344556677885f5f5f5f5f5f	64	gnu	fidivrl (%rax)
-da38|11223344556677885f5f5f5f5f5f	64	intel	fidivr st0, dword ptr [rax]
-da38|11223344556677885f5f5f5f5f5f	64	plan9	FIDIVR 0(AX)
-dac0|11223344556677885f5f5f5f5f5f	32	intel	fcmovb st0, st0
-dac0|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVB F0, F0
-dac0|11223344556677885f5f5f5f5f5f	64	gnu	fcmovb %st,%st
-dac0|11223344556677885f5f5f5f5f5f	64	intel	fcmovb st0, st0
-dac0|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVB F0, F0
-dac8|11223344556677885f5f5f5f5f5f	32	intel	fcmove st0, st0
-dac8|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVE F0, F0
-dac8|11223344556677885f5f5f5f5f5f	64	gnu	fcmove %st,%st
-dac8|11223344556677885f5f5f5f5f5f	64	intel	fcmove st0, st0
-dac8|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVE F0, F0
-dad0|11223344556677885f5f5f5f5f5f	32	intel	fcmovbe st0, st0
-dad0|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVBE F0, F0
-dad0|11223344556677885f5f5f5f5f5f	64	gnu	fcmovbe %st,%st
-dad0|11223344556677885f5f5f5f5f5f	64	intel	fcmovbe st0, st0
-dad0|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVBE F0, F0
-dad8|11223344556677885f5f5f5f5f5f	32	intel	fcmovu st0, st0
-dad8|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVU F0, F0
-dad8|11223344556677885f5f5f5f5f5f	64	gnu	fcmovu %st,%st
-dad8|11223344556677885f5f5f5f5f5f	64	intel	fcmovu st0, st0
-dad8|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVU F0, F0
-dae9|11223344556677885f5f5f5f5f5f	32	intel	fucompp st0, st1
-dae9|11223344556677885f5f5f5f5f5f	32	plan9	FUCOMPP
-dae9|11223344556677885f5f5f5f5f5f	64	gnu	fucompp
-dae9|11223344556677885f5f5f5f5f5f	64	intel	fucompp st0, st1
-dae9|11223344556677885f5f5f5f5f5f	64	plan9	FUCOMPP
-db00|11223344556677885f5f5f5f5f5f	32	intel	fild st0, dword ptr [eax]
-db00|11223344556677885f5f5f5f5f5f	32	plan9	FILD 0(AX)
-db00|11223344556677885f5f5f5f5f5f	64	gnu	fildl (%rax)
-db00|11223344556677885f5f5f5f5f5f	64	intel	fild st0, dword ptr [rax]
-db00|11223344556677885f5f5f5f5f5f	64	plan9	FILD 0(AX)
-db08|11223344556677885f5f5f5f5f5f	32	intel	fisttp dword ptr [eax], st0
-db08|11223344556677885f5f5f5f5f5f	32	plan9	FISTTP 0(AX)
-db08|11223344556677885f5f5f5f5f5f	64	gnu	fisttpl (%rax)
-db08|11223344556677885f5f5f5f5f5f	64	intel	fisttp dword ptr [rax], st0
-db08|11223344556677885f5f5f5f5f5f	64	plan9	FISTTP 0(AX)
-db11|223344556677885f5f5f5f5f5f5f	32	intel	fist dword ptr [ecx], st0
-db11|223344556677885f5f5f5f5f5f5f	32	plan9	FIST 0(CX)
-db11|223344556677885f5f5f5f5f5f5f	64	gnu	fistl (%rcx)
-db11|223344556677885f5f5f5f5f5f5f	64	intel	fist dword ptr [rcx], st0
-db11|223344556677885f5f5f5f5f5f5f	64	plan9	FIST 0(CX)
-db18|11223344556677885f5f5f5f5f5f	32	intel	fistp dword ptr [eax], st0
-db18|11223344556677885f5f5f5f5f5f	32	plan9	FISTP 0(AX)
-db18|11223344556677885f5f5f5f5f5f	64	gnu	fistpl (%rax)
-db18|11223344556677885f5f5f5f5f5f	64	intel	fistp dword ptr [rax], st0
-db18|11223344556677885f5f5f5f5f5f	64	plan9	FISTP 0(AX)
-db28|11223344556677885f5f5f5f5f5f	32	intel	fld st0, ptr [eax]
-db28|11223344556677885f5f5f5f5f5f	32	plan9	FLD 0(AX)
-db28|11223344556677885f5f5f5f5f5f	64	gnu	fldt (%rax)
-db28|11223344556677885f5f5f5f5f5f	64	intel	fld st0, ptr [rax]
-db28|11223344556677885f5f5f5f5f5f	64	plan9	FLD 0(AX)
-db38|11223344556677885f5f5f5f5f5f	32	intel	fstp ptr [eax], st0
-db38|11223344556677885f5f5f5f5f5f	32	plan9	FSTP 0(AX)
-db38|11223344556677885f5f5f5f5f5f	64	gnu	fstpt (%rax)
-db38|11223344556677885f5f5f5f5f5f	64	intel	fstp ptr [rax], st0
-db38|11223344556677885f5f5f5f5f5f	64	plan9	FSTP 0(AX)
-dbc0|11223344556677885f5f5f5f5f5f	32	intel	fcmovnb st0, st0
-dbc0|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVNB F0, F0
-dbc0|11223344556677885f5f5f5f5f5f	64	gnu	fcmovnb %st,%st
-dbc0|11223344556677885f5f5f5f5f5f	64	intel	fcmovnb st0, st0
-dbc0|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVNB F0, F0
-dbc8|11223344556677885f5f5f5f5f5f	32	intel	fcmovne st0, st0
-dbc8|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVNE F0, F0
-dbc8|11223344556677885f5f5f5f5f5f	64	gnu	fcmovne %st,%st
-dbc8|11223344556677885f5f5f5f5f5f	64	intel	fcmovne st0, st0
-dbc8|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVNE F0, F0
-dbd0|11223344556677885f5f5f5f5f5f	32	intel	fcmovnbe st0, st0
-dbd0|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVNBE F0, F0
-dbd0|11223344556677885f5f5f5f5f5f	64	gnu	fcmovnbe %st,%st
-dbd0|11223344556677885f5f5f5f5f5f	64	intel	fcmovnbe st0, st0
-dbd0|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVNBE F0, F0
-dbd8|11223344556677885f5f5f5f5f5f	32	intel	fcmovnu st0, st0
-dbd8|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVNU F0, F0
-dbd8|11223344556677885f5f5f5f5f5f	64	gnu	fcmovnu %st,%st
-dbd8|11223344556677885f5f5f5f5f5f	64	intel	fcmovnu st0, st0
-dbd8|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVNU F0, F0
-dbe2|11223344556677885f5f5f5f5f5f	32	intel	fnclex
-dbe2|11223344556677885f5f5f5f5f5f	32	plan9	FNCLEX
-dbe2|11223344556677885f5f5f5f5f5f	64	gnu	fnclex
-dbe2|11223344556677885f5f5f5f5f5f	64	intel	fnclex
-dbe2|11223344556677885f5f5f5f5f5f	64	plan9	FNCLEX
-dbe3|11223344556677885f5f5f5f5f5f	32	intel	fninit
-dbe3|11223344556677885f5f5f5f5f5f	32	plan9	FNINIT
-dbe3|11223344556677885f5f5f5f5f5f	64	gnu	fninit
-dbe3|11223344556677885f5f5f5f5f5f	64	intel	fninit
-dbe3|11223344556677885f5f5f5f5f5f	64	plan9	FNINIT
-dbe8|11223344556677885f5f5f5f5f5f	32	intel	fucomi st0, st0
-dbe8|11223344556677885f5f5f5f5f5f	32	plan9	FUCOMI F0, F0
-dbe8|11223344556677885f5f5f5f5f5f	64	gnu	fucomi %st,%st
-dbe8|11223344556677885f5f5f5f5f5f	64	intel	fucomi st0, st0
-dbe8|11223344556677885f5f5f5f5f5f	64	plan9	FUCOMI F0, F0
-dbf0|11223344556677885f5f5f5f5f5f	32	intel	fcomi st0, st0
-dbf0|11223344556677885f5f5f5f5f5f	32	plan9	FCOMI F0, F0
-dbf0|11223344556677885f5f5f5f5f5f	64	gnu	fcomi %st,%st
-dbf0|11223344556677885f5f5f5f5f5f	64	intel	fcomi st0, st0
-dbf0|11223344556677885f5f5f5f5f5f	64	plan9	FCOMI F0, F0
-dc00|11223344556677885f5f5f5f5f5f	32	intel	fadd st0, qword ptr [eax]
-dc00|11223344556677885f5f5f5f5f5f	32	plan9	FADD 0(AX)
-dc00|11223344556677885f5f5f5f5f5f	64	gnu	faddl (%rax)
-dc00|11223344556677885f5f5f5f5f5f	64	intel	fadd st0, qword ptr [rax]
-dc00|11223344556677885f5f5f5f5f5f	64	plan9	FADD 0(AX)
-dc08|11223344556677885f5f5f5f5f5f	32	intel	fmul st0, qword ptr [eax]
-dc08|11223344556677885f5f5f5f5f5f	32	plan9	FMUL 0(AX)
-dc08|11223344556677885f5f5f5f5f5f	64	gnu	fmull (%rax)
-dc08|11223344556677885f5f5f5f5f5f	64	intel	fmul st0, qword ptr [rax]
-dc08|11223344556677885f5f5f5f5f5f	64	plan9	FMUL 0(AX)
-dc11|223344556677885f5f5f5f5f5f5f	32	intel	fcom st0, qword ptr [ecx]
-dc11|223344556677885f5f5f5f5f5f5f	32	plan9	FCOM 0(CX)
-dc11|223344556677885f5f5f5f5f5f5f	64	gnu	fcoml (%rcx)
-dc11|223344556677885f5f5f5f5f5f5f	64	intel	fcom st0, qword ptr [rcx]
-dc11|223344556677885f5f5f5f5f5f5f	64	plan9	FCOM 0(CX)
-dc18|11223344556677885f5f5f5f5f5f	32	intel	fcomp st0, qword ptr [eax]
-dc18|11223344556677885f5f5f5f5f5f	32	plan9	FCOMP 0(AX)
-dc18|11223344556677885f5f5f5f5f5f	64	gnu	fcompl (%rax)
-dc18|11223344556677885f5f5f5f5f5f	64	intel	fcomp st0, qword ptr [rax]
-dc18|11223344556677885f5f5f5f5f5f	64	plan9	FCOMP 0(AX)
-dc20|11223344556677885f5f5f5f5f5f	32	intel	fsub st0, qword ptr [eax]
-dc20|11223344556677885f5f5f5f5f5f	32	plan9	FSUB 0(AX)
-dc20|11223344556677885f5f5f5f5f5f	64	gnu	fsubl (%rax)
-dc20|11223344556677885f5f5f5f5f5f	64	intel	fsub st0, qword ptr [rax]
-dc20|11223344556677885f5f5f5f5f5f	64	plan9	FSUB 0(AX)
-dc28|11223344556677885f5f5f5f5f5f	32	intel	fsubr st0, qword ptr [eax]
-dc28|11223344556677885f5f5f5f5f5f	32	plan9	FSUBR 0(AX)
-dc28|11223344556677885f5f5f5f5f5f	64	gnu	fsubrl (%rax)
-dc28|11223344556677885f5f5f5f5f5f	64	intel	fsubr st0, qword ptr [rax]
-dc28|11223344556677885f5f5f5f5f5f	64	plan9	FSUBR 0(AX)
-dc30|11223344556677885f5f5f5f5f5f	32	intel	fdiv st0, qword ptr [eax]
-dc30|11223344556677885f5f5f5f5f5f	32	plan9	FDIV 0(AX)
-dc30|11223344556677885f5f5f5f5f5f	64	gnu	fdivl (%rax)
-dc30|11223344556677885f5f5f5f5f5f	64	intel	fdiv st0, qword ptr [rax]
-dc30|11223344556677885f5f5f5f5f5f	64	plan9	FDIV 0(AX)
-dc38|11223344556677885f5f5f5f5f5f	32	intel	fdivr st0, qword ptr [eax]
-dc38|11223344556677885f5f5f5f5f5f	32	plan9	FDIVR 0(AX)
-dc38|11223344556677885f5f5f5f5f5f	64	gnu	fdivrl (%rax)
-dc38|11223344556677885f5f5f5f5f5f	64	intel	fdivr st0, qword ptr [rax]
-dc38|11223344556677885f5f5f5f5f5f	64	plan9	FDIVR 0(AX)
-dcc0|11223344556677885f5f5f5f5f5f	32	intel	fadd st0, st0
-dcc0|11223344556677885f5f5f5f5f5f	32	plan9	FADD F0, F0
-dcc0|11223344556677885f5f5f5f5f5f	64	gnu	fadd %st,%st
-dcc0|11223344556677885f5f5f5f5f5f	64	intel	fadd st0, st0
-dcc0|11223344556677885f5f5f5f5f5f	64	plan9	FADD F0, F0
-dcc8|11223344556677885f5f5f5f5f5f	32	intel	fmul st0, st0
-dcc8|11223344556677885f5f5f5f5f5f	32	plan9	FMUL F0, F0
-dcc8|11223344556677885f5f5f5f5f5f	64	gnu	fmul %st,%st
-dcc8|11223344556677885f5f5f5f5f5f	64	intel	fmul st0, st0
-dcc8|11223344556677885f5f5f5f5f5f	64	plan9	FMUL F0, F0
-dce0|11223344556677885f5f5f5f5f5f	32	intel	fsubr st0, st0
-dce0|11223344556677885f5f5f5f5f5f	32	plan9	FSUBR F0, F0
-dce0|11223344556677885f5f5f5f5f5f	64	gnu	fsub %st,%st
-dce0|11223344556677885f5f5f5f5f5f	64	intel	fsubr st0, st0
-dce0|11223344556677885f5f5f5f5f5f	64	plan9	FSUBR F0, F0
-dce8|11223344556677885f5f5f5f5f5f	32	intel	fsub st0, st0
-dce8|11223344556677885f5f5f5f5f5f	32	plan9	FSUB F0, F0
-dce8|11223344556677885f5f5f5f5f5f	64	gnu	fsubr %st,%st
-dce8|11223344556677885f5f5f5f5f5f	64	intel	fsub st0, st0
-dce8|11223344556677885f5f5f5f5f5f	64	plan9	FSUB F0, F0
-dcf0|11223344556677885f5f5f5f5f5f	32	intel	fdivr st0, st0
-dcf0|11223344556677885f5f5f5f5f5f	32	plan9	FDIVR F0, F0
-dcf0|11223344556677885f5f5f5f5f5f	64	gnu	fdiv %st,%st
-dcf0|11223344556677885f5f5f5f5f5f	64	intel	fdivr st0, st0
-dcf0|11223344556677885f5f5f5f5f5f	64	plan9	FDIVR F0, F0
-dcf8|11223344556677885f5f5f5f5f5f	32	intel	fdiv st0, st0
-dcf8|11223344556677885f5f5f5f5f5f	32	plan9	FDIV F0, F0
-dcf8|11223344556677885f5f5f5f5f5f	64	gnu	fdivr %st,%st
-dcf8|11223344556677885f5f5f5f5f5f	64	intel	fdiv st0, st0
-dcf8|11223344556677885f5f5f5f5f5f	64	plan9	FDIV F0, F0
-dd00|11223344556677885f5f5f5f5f5f	32	intel	fld st0, qword ptr [eax]
-dd00|11223344556677885f5f5f5f5f5f	32	plan9	FLD 0(AX)
-dd00|11223344556677885f5f5f5f5f5f	64	gnu	fldl (%rax)
-dd00|11223344556677885f5f5f5f5f5f	64	intel	fld st0, qword ptr [rax]
-dd00|11223344556677885f5f5f5f5f5f	64	plan9	FLD 0(AX)
-dd08|11223344556677885f5f5f5f5f5f	32	intel	fisttp qword ptr [eax], st0
-dd08|11223344556677885f5f5f5f5f5f	32	plan9	FISTTP 0(AX)
-dd08|11223344556677885f5f5f5f5f5f	64	gnu	fisttpll (%rax)
-dd08|11223344556677885f5f5f5f5f5f	64	intel	fisttp qword ptr [rax], st0
-dd08|11223344556677885f5f5f5f5f5f	64	plan9	FISTTP 0(AX)
-dd11|223344556677885f5f5f5f5f5f5f	32	intel	fst qword ptr [ecx], st0
-dd11|223344556677885f5f5f5f5f5f5f	32	plan9	FST 0(CX)
-dd11|223344556677885f5f5f5f5f5f5f	64	gnu	fstl (%rcx)
-dd11|223344556677885f5f5f5f5f5f5f	64	intel	fst qword ptr [rcx], st0
-dd11|223344556677885f5f5f5f5f5f5f	64	plan9	FST 0(CX)
-dd18|11223344556677885f5f5f5f5f5f	32	intel	fstp qword ptr [eax], st0
-dd18|11223344556677885f5f5f5f5f5f	32	plan9	FSTP 0(AX)
-dd18|11223344556677885f5f5f5f5f5f	64	gnu	fstpl (%rax)
-dd18|11223344556677885f5f5f5f5f5f	64	intel	fstp qword ptr [rax], st0
-dd18|11223344556677885f5f5f5f5f5f	64	plan9	FSTP 0(AX)
-dd20|11223344556677885f5f5f5f5f5f	32	intel	frstor ptr [eax]
-dd20|11223344556677885f5f5f5f5f5f	32	plan9	FRSTORL 0(AX)
-dd20|11223344556677885f5f5f5f5f5f	64	gnu	frstor (%rax)
-dd20|11223344556677885f5f5f5f5f5f	64	intel	frstor ptr [rax]
-dd20|11223344556677885f5f5f5f5f5f	64	plan9	FRSTORL 0(AX)
-dd30|11223344556677885f5f5f5f5f5f	32	intel	fnsave ptr [eax]
-dd30|11223344556677885f5f5f5f5f5f	32	plan9	FNSAVE 0(AX)
-dd30|11223344556677885f5f5f5f5f5f	64	gnu	fnsave (%rax)
-dd30|11223344556677885f5f5f5f5f5f	64	intel	fnsave ptr [rax]
-dd30|11223344556677885f5f5f5f5f5f	64	plan9	FNSAVE 0(AX)
-dd38|11223344556677885f5f5f5f5f5f	32	intel	fnstsw word ptr [eax]
-dd38|11223344556677885f5f5f5f5f5f	32	plan9	FNSTSW 0(AX)
-dd38|11223344556677885f5f5f5f5f5f	64	gnu	fnstsw (%rax)
-dd38|11223344556677885f5f5f5f5f5f	64	intel	fnstsw word ptr [rax]
-dd38|11223344556677885f5f5f5f5f5f	64	plan9	FNSTSW 0(AX)
-ddc0|11223344556677885f5f5f5f5f5f	32	intel	ffree st0
-ddc0|11223344556677885f5f5f5f5f5f	32	plan9	FFREE F0
-ddc0|11223344556677885f5f5f5f5f5f	64	gnu	ffree %st
-ddc0|11223344556677885f5f5f5f5f5f	64	intel	ffree st0
-ddc0|11223344556677885f5f5f5f5f5f	64	plan9	FFREE F0
-ddd0|11223344556677885f5f5f5f5f5f	32	intel	fst st0, st0
-ddd0|11223344556677885f5f5f5f5f5f	32	plan9	FST F0
-ddd0|11223344556677885f5f5f5f5f5f	64	gnu	fst %st
-ddd0|11223344556677885f5f5f5f5f5f	64	intel	fst st0, st0
-ddd0|11223344556677885f5f5f5f5f5f	64	plan9	FST F0
-ddd8|11223344556677885f5f5f5f5f5f	32	intel	fstp st0, st0
-ddd8|11223344556677885f5f5f5f5f5f	32	plan9	FSTP F0
-ddd8|11223344556677885f5f5f5f5f5f	64	gnu	fstp %st
-ddd8|11223344556677885f5f5f5f5f5f	64	intel	fstp st0, st0
-ddd8|11223344556677885f5f5f5f5f5f	64	plan9	FSTP F0
-dde0|11223344556677885f5f5f5f5f5f	32	intel	fucom st0, st0
-dde0|11223344556677885f5f5f5f5f5f	32	plan9	FUCOM F0
-dde0|11223344556677885f5f5f5f5f5f	64	gnu	fucom %st
-dde0|11223344556677885f5f5f5f5f5f	64	intel	fucom st0, st0
-dde0|11223344556677885f5f5f5f5f5f	64	plan9	FUCOM F0
-dde8|11223344556677885f5f5f5f5f5f	32	intel	fucomp st0, st0
-dde8|11223344556677885f5f5f5f5f5f	32	plan9	FUCOMP F0
-dde8|11223344556677885f5f5f5f5f5f	64	gnu	fucomp %st
-dde8|11223344556677885f5f5f5f5f5f	64	intel	fucomp st0, st0
-dde8|11223344556677885f5f5f5f5f5f	64	plan9	FUCOMP F0
-de00|11223344556677885f5f5f5f5f5f	32	intel	fiadd st0, word ptr [eax]
-de00|11223344556677885f5f5f5f5f5f	32	plan9	FIADD 0(AX)
-de00|11223344556677885f5f5f5f5f5f	64	gnu	fiadd (%rax)
-de00|11223344556677885f5f5f5f5f5f	64	intel	fiadd st0, word ptr [rax]
-de00|11223344556677885f5f5f5f5f5f	64	plan9	FIADD 0(AX)
-de08|11223344556677885f5f5f5f5f5f	32	intel	fimul st0, word ptr [eax]
-de08|11223344556677885f5f5f5f5f5f	32	plan9	FIMUL 0(AX)
-de08|11223344556677885f5f5f5f5f5f	64	gnu	fimul (%rax)
-de08|11223344556677885f5f5f5f5f5f	64	intel	fimul st0, word ptr [rax]
-de08|11223344556677885f5f5f5f5f5f	64	plan9	FIMUL 0(AX)
-de11|223344556677885f5f5f5f5f5f5f	32	intel	ficom st0, word ptr [ecx]
-de11|223344556677885f5f5f5f5f5f5f	32	plan9	FICOM 0(CX)
-de11|223344556677885f5f5f5f5f5f5f	64	gnu	ficom (%rcx)
-de11|223344556677885f5f5f5f5f5f5f	64	intel	ficom st0, word ptr [rcx]
-de11|223344556677885f5f5f5f5f5f5f	64	plan9	FICOM 0(CX)
-de18|11223344556677885f5f5f5f5f5f	32	intel	ficomp st0, word ptr [eax]
-de18|11223344556677885f5f5f5f5f5f	32	plan9	FICOMP 0(AX)
-de18|11223344556677885f5f5f5f5f5f	64	gnu	ficomp (%rax)
-de18|11223344556677885f5f5f5f5f5f	64	intel	ficomp st0, word ptr [rax]
-de18|11223344556677885f5f5f5f5f5f	64	plan9	FICOMP 0(AX)
-de20|11223344556677885f5f5f5f5f5f	32	intel	fisub st0, word ptr [eax]
-de20|11223344556677885f5f5f5f5f5f	32	plan9	FISUB 0(AX)
-de20|11223344556677885f5f5f5f5f5f	64	gnu	fisub (%rax)
-de20|11223344556677885f5f5f5f5f5f	64	intel	fisub st0, word ptr [rax]
-de20|11223344556677885f5f5f5f5f5f	64	plan9	FISUB 0(AX)
-de28|11223344556677885f5f5f5f5f5f	32	intel	fisubr st0, word ptr [eax]
-de28|11223344556677885f5f5f5f5f5f	32	plan9	FISUBR 0(AX)
-de28|11223344556677885f5f5f5f5f5f	64	gnu	fisubr (%rax)
-de28|11223344556677885f5f5f5f5f5f	64	intel	fisubr st0, word ptr [rax]
-de28|11223344556677885f5f5f5f5f5f	64	plan9	FISUBR 0(AX)
-de30|11223344556677885f5f5f5f5f5f	32	intel	fidiv st0, word ptr [eax]
-de30|11223344556677885f5f5f5f5f5f	32	plan9	FIDIV 0(AX)
-de30|11223344556677885f5f5f5f5f5f	64	gnu	fidiv (%rax)
-de30|11223344556677885f5f5f5f5f5f	64	intel	fidiv st0, word ptr [rax]
-de30|11223344556677885f5f5f5f5f5f	64	plan9	FIDIV 0(AX)
-de38|11223344556677885f5f5f5f5f5f	32	intel	fidivr st0, word ptr [eax]
-de38|11223344556677885f5f5f5f5f5f	32	plan9	FIDIVR 0(AX)
-de38|11223344556677885f5f5f5f5f5f	64	gnu	fidivr (%rax)
-de38|11223344556677885f5f5f5f5f5f	64	intel	fidivr st0, word ptr [rax]
-de38|11223344556677885f5f5f5f5f5f	64	plan9	FIDIVR 0(AX)
-dec0|11223344556677885f5f5f5f5f5f	32	intel	faddp st0, st0
-dec0|11223344556677885f5f5f5f5f5f	32	plan9	FADDP F0, F0
-dec0|11223344556677885f5f5f5f5f5f	64	gnu	faddp %st,%st
-dec0|11223344556677885f5f5f5f5f5f	64	intel	faddp st0, st0
-dec0|11223344556677885f5f5f5f5f5f	64	plan9	FADDP F0, F0
-dec8|11223344556677885f5f5f5f5f5f	32	intel	fmulp st0, st0
-dec8|11223344556677885f5f5f5f5f5f	32	plan9	FMULP F0, F0
-dec8|11223344556677885f5f5f5f5f5f	64	gnu	fmulp %st,%st
-dec8|11223344556677885f5f5f5f5f5f	64	intel	fmulp st0, st0
-dec8|11223344556677885f5f5f5f5f5f	64	plan9	FMULP F0, F0
-ded9|11223344556677885f5f5f5f5f5f	32	intel	fcompp st0, st1
-ded9|11223344556677885f5f5f5f5f5f	32	plan9	FCOMPP
-ded9|11223344556677885f5f5f5f5f5f	64	gnu	fcompp
-ded9|11223344556677885f5f5f5f5f5f	64	intel	fcompp st0, st1
-ded9|11223344556677885f5f5f5f5f5f	64	plan9	FCOMPP
-dee0|11223344556677885f5f5f5f5f5f	32	intel	fsubrp st0, st0
-dee0|11223344556677885f5f5f5f5f5f	32	plan9	FSUBRP F0, F0
-dee0|11223344556677885f5f5f5f5f5f	64	gnu	fsubp %st,%st
-dee0|11223344556677885f5f5f5f5f5f	64	intel	fsubrp st0, st0
-dee0|11223344556677885f5f5f5f5f5f	64	plan9	FSUBRP F0, F0
-dee8|11223344556677885f5f5f5f5f5f	32	intel	fsubp st0, st0
-dee8|11223344556677885f5f5f5f5f5f	32	plan9	FSUBP F0, F0
-dee8|11223344556677885f5f5f5f5f5f	64	gnu	fsubrp %st,%st
-dee8|11223344556677885f5f5f5f5f5f	64	intel	fsubp st0, st0
-dee8|11223344556677885f5f5f5f5f5f	64	plan9	FSUBP F0, F0
-def0|11223344556677885f5f5f5f5f5f	32	intel	fdivrp st0, st0
-def0|11223344556677885f5f5f5f5f5f	32	plan9	FDIVRP F0, F0
-def0|11223344556677885f5f5f5f5f5f	64	gnu	fdivp %st,%st
-def0|11223344556677885f5f5f5f5f5f	64	intel	fdivrp st0, st0
-def0|11223344556677885f5f5f5f5f5f	64	plan9	FDIVRP F0, F0
-def8|11223344556677885f5f5f5f5f5f	32	intel	fdivp st0, st0
-def8|11223344556677885f5f5f5f5f5f	32	plan9	FDIVP F0, F0
-def8|11223344556677885f5f5f5f5f5f	64	gnu	fdivrp %st,%st
-def8|11223344556677885f5f5f5f5f5f	64	intel	fdivp st0, st0
-def8|11223344556677885f5f5f5f5f5f	64	plan9	FDIVP F0, F0
-df00|11223344556677885f5f5f5f5f5f	32	intel	fild st0, word ptr [eax]
-df00|11223344556677885f5f5f5f5f5f	32	plan9	FILD 0(AX)
-df00|11223344556677885f5f5f5f5f5f	64	gnu	fild (%rax)
-df00|11223344556677885f5f5f5f5f5f	64	intel	fild st0, word ptr [rax]
-df00|11223344556677885f5f5f5f5f5f	64	plan9	FILD 0(AX)
-df08|11223344556677885f5f5f5f5f5f	32	intel	fisttp word ptr [eax], st0
-df08|11223344556677885f5f5f5f5f5f	32	plan9	FISTTP 0(AX)
-df08|11223344556677885f5f5f5f5f5f	64	gnu	fisttp (%rax)
-df08|11223344556677885f5f5f5f5f5f	64	intel	fisttp word ptr [rax], st0
-df08|11223344556677885f5f5f5f5f5f	64	plan9	FISTTP 0(AX)
-df11|223344556677885f5f5f5f5f5f5f	32	intel	fist word ptr [ecx], st0
-df11|223344556677885f5f5f5f5f5f5f	32	plan9	FIST 0(CX)
-df11|223344556677885f5f5f5f5f5f5f	64	gnu	fist (%rcx)
-df11|223344556677885f5f5f5f5f5f5f	64	intel	fist word ptr [rcx], st0
-df11|223344556677885f5f5f5f5f5f5f	64	plan9	FIST 0(CX)
-df18|11223344556677885f5f5f5f5f5f	32	intel	fistp word ptr [eax], st0
-df18|11223344556677885f5f5f5f5f5f	32	plan9	FISTP 0(AX)
-df18|11223344556677885f5f5f5f5f5f	64	gnu	fistp (%rax)
-df18|11223344556677885f5f5f5f5f5f	64	intel	fistp word ptr [rax], st0
-df18|11223344556677885f5f5f5f5f5f	64	plan9	FISTP 0(AX)
-df20|11223344556677885f5f5f5f5f5f	32	intel	fbld st0, ptr [eax]
-df20|11223344556677885f5f5f5f5f5f	32	plan9	FBLD 0(AX)
-df20|11223344556677885f5f5f5f5f5f	64	gnu	fbld (%rax)
-df20|11223344556677885f5f5f5f5f5f	64	intel	fbld st0, ptr [rax]
-df20|11223344556677885f5f5f5f5f5f	64	plan9	FBLD 0(AX)
-df28|11223344556677885f5f5f5f5f5f	32	intel	fild st0, qword ptr [eax]
-df28|11223344556677885f5f5f5f5f5f	32	plan9	FILD 0(AX)
-df28|11223344556677885f5f5f5f5f5f	64	gnu	fildll (%rax)
-df28|11223344556677885f5f5f5f5f5f	64	intel	fild st0, qword ptr [rax]
-df28|11223344556677885f5f5f5f5f5f	64	plan9	FILD 0(AX)
-df30|11223344556677885f5f5f5f5f5f	32	intel	fbstp ptr [eax], st0
-df30|11223344556677885f5f5f5f5f5f	32	plan9	FBSTP 0(AX)
-df30|11223344556677885f5f5f5f5f5f	64	gnu	fbstp (%rax)
-df30|11223344556677885f5f5f5f5f5f	64	intel	fbstp ptr [rax], st0
-df30|11223344556677885f5f5f5f5f5f	64	plan9	FBSTP 0(AX)
-df38|11223344556677885f5f5f5f5f5f	32	intel	fistp qword ptr [eax], st0
-df38|11223344556677885f5f5f5f5f5f	32	plan9	FISTP 0(AX)
-df38|11223344556677885f5f5f5f5f5f	64	gnu	fistpll (%rax)
-df38|11223344556677885f5f5f5f5f5f	64	intel	fistp qword ptr [rax], st0
-df38|11223344556677885f5f5f5f5f5f	64	plan9	FISTP 0(AX)
-dfc0|11223344556677885f5f5f5f5f5f	32	intel	ffreep st0
-dfc0|11223344556677885f5f5f5f5f5f	32	plan9	FFREEP F0
-dfc0|11223344556677885f5f5f5f5f5f	64	gnu	ffreep %st
-dfc0|11223344556677885f5f5f5f5f5f	64	intel	ffreep st0
-dfc0|11223344556677885f5f5f5f5f5f	64	plan9	FFREEP F0
-dfe0|11223344556677885f5f5f5f5f5f	32	intel	fnstsw ax
-dfe0|11223344556677885f5f5f5f5f5f	32	plan9	FNSTSW AX
-dfe0|11223344556677885f5f5f5f5f5f	64	gnu	fnstsw %ax
-dfe0|11223344556677885f5f5f5f5f5f	64	intel	fnstsw ax
-dfe0|11223344556677885f5f5f5f5f5f	64	plan9	FNSTSW AX
-dfe8|11223344556677885f5f5f5f5f5f	32	intel	fucomip st0, st0
-dfe8|11223344556677885f5f5f5f5f5f	32	plan9	FUCOMIP F0, F0
-dfe8|11223344556677885f5f5f5f5f5f	64	gnu	fucomip %st,%st
-dfe8|11223344556677885f5f5f5f5f5f	64	intel	fucomip st0, st0
-dfe8|11223344556677885f5f5f5f5f5f	64	plan9	FUCOMIP F0, F0
-dff0|11223344556677885f5f5f5f5f5f	32	intel	fcomip st0, st0
-dff0|11223344556677885f5f5f5f5f5f	32	plan9	FCOMIP F0, F0
-dff0|11223344556677885f5f5f5f5f5f	64	gnu	fcomip %st,%st
-dff0|11223344556677885f5f5f5f5f5f	64	intel	fcomip st0, st0
-dff0|11223344556677885f5f5f5f5f5f	64	plan9	FCOMIP F0, F0
-e111|223344556677885f5f5f5f5f5f5f	32	intel	loope .+0x11
-e111|223344556677885f5f5f5f5f5f5f	32	plan9	LOOPE .+17
-e111|223344556677885f5f5f5f5f5f5f	64	gnu	loope .+0x11
-e111|223344556677885f5f5f5f5f5f5f	64	intel	loope .+0x11
-e111|223344556677885f5f5f5f5f5f5f	64	plan9	LOOPE .+17
-e211|223344556677885f5f5f5f5f5f5f	32	intel	loop .+0x11
-e211|223344556677885f5f5f5f5f5f5f	32	plan9	LOOP .+17
-e211|223344556677885f5f5f5f5f5f5f	64	gnu	loop .+0x11
-e211|223344556677885f5f5f5f5f5f5f	64	intel	loop .+0x11
-e211|223344556677885f5f5f5f5f5f5f	64	plan9	LOOP .+17
-e311|223344556677885f5f5f5f5f5f5f	32	intel	jecxz .+0x11
-e311|223344556677885f5f5f5f5f5f5f	32	plan9	JECXZ .+17
-e311|223344556677885f5f5f5f5f5f5f	64	gnu	jrcxz .+0x11
-e311|223344556677885f5f5f5f5f5f5f	64	intel	jrcxz .+0x11
-e311|223344556677885f5f5f5f5f5f5f	64	plan9	JRCXZ .+17
-e411|223344556677885f5f5f5f5f5f5f	32	intel	in al, 0x11
-e411|223344556677885f5f5f5f5f5f5f	32	plan9	INL $0x11, AL
-e411|223344556677885f5f5f5f5f5f5f	64	gnu	in $0x11,%al
-e411|223344556677885f5f5f5f5f5f5f	64	intel	in al, 0x11
-e411|223344556677885f5f5f5f5f5f5f	64	plan9	INL $0x11, AL
-e511|223344556677885f5f5f5f5f5f5f	32	intel	in eax, 0x11
-e511|223344556677885f5f5f5f5f5f5f	32	plan9	INL $0x11, AX
-e511|223344556677885f5f5f5f5f5f5f	64	gnu	in $0x11,%eax
-e511|223344556677885f5f5f5f5f5f5f	64	intel	in eax, 0x11
-e511|223344556677885f5f5f5f5f5f5f	64	plan9	INL $0x11, AX
-e611|223344556677885f5f5f5f5f5f5f	32	intel	out 0x11, al
-e611|223344556677885f5f5f5f5f5f5f	32	plan9	OUTL AL, $0x11
-e611|223344556677885f5f5f5f5f5f5f	64	gnu	out %al,$0x11
-e611|223344556677885f5f5f5f5f5f5f	64	intel	out 0x11, al
-e611|223344556677885f5f5f5f5f5f5f	64	plan9	OUTL AL, $0x11
-e711|223344556677885f5f5f5f5f5f5f	32	intel	out 0x11, eax
-e711|223344556677885f5f5f5f5f5f5f	32	plan9	OUTL AX, $0x11
-e711|223344556677885f5f5f5f5f5f5f	64	gnu	out %eax,$0x11
-e711|223344556677885f5f5f5f5f5f5f	64	intel	out 0x11, eax
-e711|223344556677885f5f5f5f5f5f5f	64	plan9	OUTL AX, $0x11
-e811223344|556677885f5f5f5f5f5f5f	32	intel	call .+0x44332211
-e811223344|556677885f5f5f5f5f5f5f	32	plan9	CALL .+1144201745
-e811223344|556677885f5f5f5f5f5f5f	64	gnu	callq .+0x44332211
-e811223344|556677885f5f5f5f5f5f5f	64	intel	call .+0x44332211
-e811223344|556677885f5f5f5f5f5f5f	64	plan9	CALL .+1144201745
-e911223344|556677885f5f5f5f5f5f5f	32	intel	jmp .+0x44332211
-e911223344|556677885f5f5f5f5f5f5f	32	plan9	JMP .+1144201745
-e911223344|556677885f5f5f5f5f5f5f	64	gnu	jmpq .+0x44332211
-e911223344|556677885f5f5f5f5f5f5f	64	intel	jmp .+0x44332211
-e911223344|556677885f5f5f5f5f5f5f	64	plan9	JMP .+1144201745
-ea112233445566|77885f5f5f5f5f5f5f	32	intel	jmp far 0x44332211, 0x6655
-ea112233445566|77885f5f5f5f5f5f5f	32	plan9	LJMP $0x44332211, $0x6655
-eb11|223344556677885f5f5f5f5f5f5f	32	intel	jmp .+0x11
-eb11|223344556677885f5f5f5f5f5f5f	32	plan9	JMP .+17
-eb11|223344556677885f5f5f5f5f5f5f	64	gnu	jmp .+0x11
-eb11|223344556677885f5f5f5f5f5f5f	64	intel	jmp .+0x11
-eb11|223344556677885f5f5f5f5f5f5f	64	plan9	JMP .+17
-ec|11223344556677885f5f5f5f5f5f5f	32	intel	in al, dx
-ec|11223344556677885f5f5f5f5f5f5f	32	plan9	INL DX, AL
-ec|11223344556677885f5f5f5f5f5f5f	64	gnu	in (%dx),%al
-ec|11223344556677885f5f5f5f5f5f5f	64	intel	in al, dx
-ec|11223344556677885f5f5f5f5f5f5f	64	plan9	INL DX, AL
-ed|11223344556677885f5f5f5f5f5f5f	32	intel	in eax, dx
-ed|11223344556677885f5f5f5f5f5f5f	32	plan9	INL DX, AX
-ed|11223344556677885f5f5f5f5f5f5f	64	gnu	in (%dx),%eax
-ed|11223344556677885f5f5f5f5f5f5f	64	intel	in eax, dx
-ed|11223344556677885f5f5f5f5f5f5f	64	plan9	INL DX, AX
-ee|11223344556677885f5f5f5f5f5f5f	32	intel	out dx, al
-ee|11223344556677885f5f5f5f5f5f5f	32	plan9	OUTL AL, DX
-ee|11223344556677885f5f5f5f5f5f5f	64	gnu	out %al,(%dx)
-ee|11223344556677885f5f5f5f5f5f5f	64	intel	out dx, al
-ee|11223344556677885f5f5f5f5f5f5f	64	plan9	OUTL AL, DX
-ef|11223344556677885f5f5f5f5f5f5f	32	intel	out dx, eax
-ef|11223344556677885f5f5f5f5f5f5f	32	plan9	OUTL AX, DX
-ef|11223344556677885f5f5f5f5f5f5f	64	gnu	out %eax,(%dx)
-ef|11223344556677885f5f5f5f5f5f5f	64	intel	out dx, eax
-ef|11223344556677885f5f5f5f5f5f5f	64	plan9	OUTL AX, DX
-f1|11223344556677885f5f5f5f5f5f5f	32	intel	int1
-f1|11223344556677885f5f5f5f5f5f5f	32	plan9	ICEBP
-f1|11223344556677885f5f5f5f5f5f5f	64	gnu	icebp
-f1|11223344556677885f5f5f5f5f5f5f	64	intel	int1
-f1|11223344556677885f5f5f5f5f5f5f	64	plan9	ICEBP
-f20f1011|223344556677885f5f5f5f5f	32	intel	movsd xmm2, qword ptr [ecx]
-f20f1011|223344556677885f5f5f5f5f	32	plan9	REPNE MOVSD_XMM 0(CX), X2
-f20f1011|223344556677885f5f5f5f5f	64	gnu	movsd (%rcx),%xmm2
-f20f1011|223344556677885f5f5f5f5f	64	intel	movsd xmm2, qword ptr [rcx]
-f20f1011|223344556677885f5f5f5f5f	64	plan9	REPNE MOVSD_XMM 0(CX), X2
-f20f1122|3344556677885f5f5f5f5f5f	32	intel	movsd qword ptr [edx], xmm4
-f20f1122|3344556677885f5f5f5f5f5f	32	plan9	REPNE MOVSD_XMM X4, 0(DX)
-f20f1122|3344556677885f5f5f5f5f5f	64	gnu	movsd %xmm4,(%rdx)
-f20f1122|3344556677885f5f5f5f5f5f	64	intel	movsd qword ptr [rdx], xmm4
-f20f1122|3344556677885f5f5f5f5f5f	64	plan9	REPNE MOVSD_XMM X4, 0(DX)
-f20f1211|223344556677885f5f5f5f5f	32	intel	movddup xmm2, qword ptr [ecx]
-f20f1211|223344556677885f5f5f5f5f	32	plan9	REPNE MOVDDUP 0(CX), X2
-f20f1211|223344556677885f5f5f5f5f	64	gnu	movddup (%rcx),%xmm2
-f20f1211|223344556677885f5f5f5f5f	64	intel	movddup xmm2, qword ptr [rcx]
-f20f1211|223344556677885f5f5f5f5f	64	plan9	REPNE MOVDDUP 0(CX), X2
-f20f2a11|223344556677885f5f5f5f5f	32	intel	cvtsi2sd xmm2, dword ptr [ecx]
-f20f2a11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTSI2SDL 0(CX), X2
-f20f2a11|223344556677885f5f5f5f5f	64	gnu	cvtsi2sdl (%rcx),%xmm2
-f20f2a11|223344556677885f5f5f5f5f	64	intel	cvtsi2sd xmm2, dword ptr [rcx]
-f20f2a11|223344556677885f5f5f5f5f	64	plan9	REPNE CVTSI2SDL 0(CX), X2
-f20f2c11|223344556677885f5f5f5f5f	32	intel	cvttsd2si edx, qword ptr [ecx]
-f20f2c11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTTSD2SIL 0(CX), DX
-f20f2c11|223344556677885f5f5f5f5f	64	gnu	cvttsd2si (%rcx),%edx
-f20f2c11|223344556677885f5f5f5f5f	64	intel	cvttsd2si edx, qword ptr [rcx]
-f20f2c11|223344556677885f5f5f5f5f	64	plan9	REPNE CVTTSD2SIL 0(CX), DX
-f20f2d11|223344556677885f5f5f5f5f	32	intel	cvtsd2si edx, qword ptr [ecx]
-f20f2d11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTSD2SIL 0(CX), DX
-f20f2d11|223344556677885f5f5f5f5f	64	gnu	cvtsd2si (%rcx),%edx
-f20f2d11|223344556677885f5f5f5f5f	64	intel	cvtsd2si edx, qword ptr [rcx]
-f20f2d11|223344556677885f5f5f5f5f	64	plan9	REPNE CVTSD2SIL 0(CX), DX
-f20f38f011|223344556677885f5f5f5f	32	intel	crc32 edx, byte ptr [ecx]
-f20f38f011|223344556677885f5f5f5f	32	plan9	REPNE CRC32 0(CX), DX
-f20f38f011|223344556677885f5f5f5f	64	gnu	crc32b (%rcx),%edx
-f20f38f011|223344556677885f5f5f5f	64	intel	crc32 edx, byte ptr [rcx]
-f20f38f011|223344556677885f5f5f5f	64	plan9	REPNE CRC32 0(CX), DX
-f20f38f111|223344556677885f5f5f5f	32	intel	crc32 edx, dword ptr [ecx]
-f20f38f111|223344556677885f5f5f5f	32	plan9	REPNE CRC32 0(CX), DX
-f20f38f111|223344556677885f5f5f5f	64	gnu	crc32l (%rcx),%edx
-f20f38f111|223344556677885f5f5f5f	64	intel	crc32 edx, dword ptr [rcx]
-f20f38f111|223344556677885f5f5f5f	64	plan9	REPNE CRC32 0(CX), DX
-f20f5111|223344556677885f5f5f5f5f	32	intel	sqrtsd xmm2, qword ptr [ecx]
-f20f5111|223344556677885f5f5f5f5f	32	plan9	REPNE SQRTSD 0(CX), X2
-f20f5111|223344556677885f5f5f5f5f	64	gnu	sqrtsd (%rcx),%xmm2
-f20f5111|223344556677885f5f5f5f5f	64	intel	sqrtsd xmm2, qword ptr [rcx]
-f20f5111|223344556677885f5f5f5f5f	64	plan9	REPNE SQRTSD 0(CX), X2
-f20f5811|223344556677885f5f5f5f5f	32	intel	addsd xmm2, qword ptr [ecx]
-f20f5811|223344556677885f5f5f5f5f	32	plan9	REPNE ADDSD 0(CX), X2
-f20f5811|223344556677885f5f5f5f5f	64	gnu	addsd (%rcx),%xmm2
-f20f5811|223344556677885f5f5f5f5f	64	intel	addsd xmm2, qword ptr [rcx]
-f20f5811|223344556677885f5f5f5f5f	64	plan9	REPNE ADDSD 0(CX), X2
-f20f5911|223344556677885f5f5f5f5f	32	intel	mulsd xmm2, qword ptr [ecx]
-f20f5911|223344556677885f5f5f5f5f	32	plan9	REPNE MULSD 0(CX), X2
-f20f5911|223344556677885f5f5f5f5f	64	gnu	mulsd (%rcx),%xmm2
-f20f5911|223344556677885f5f5f5f5f	64	intel	mulsd xmm2, qword ptr [rcx]
-f20f5911|223344556677885f5f5f5f5f	64	plan9	REPNE MULSD 0(CX), X2
-f20f5a11|223344556677885f5f5f5f5f	32	intel	cvtsd2ss xmm2, qword ptr [ecx]
-f20f5a11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTSD2SS 0(CX), X2
-f20f5a11|223344556677885f5f5f5f5f	64	gnu	cvtsd2ss (%rcx),%xmm2
-f20f5a11|223344556677885f5f5f5f5f	64	intel	cvtsd2ss xmm2, qword ptr [rcx]
-f20f5a11|223344556677885f5f5f5f5f	64	plan9	REPNE CVTSD2SS 0(CX), X2
-f20f5c11|223344556677885f5f5f5f5f	32	intel	subsd xmm2, qword ptr [ecx]
-f20f5c11|223344556677885f5f5f5f5f	32	plan9	REPNE SUBSD 0(CX), X2
-f20f5c11|223344556677885f5f5f5f5f	64	gnu	subsd (%rcx),%xmm2
-f20f5c11|223344556677885f5f5f5f5f	64	intel	subsd xmm2, qword ptr [rcx]
-f20f5c11|223344556677885f5f5f5f5f	64	plan9	REPNE SUBSD 0(CX), X2
-f20f5d11|223344556677885f5f5f5f5f	32	intel	minsd xmm2, qword ptr [ecx]
-f20f5d11|223344556677885f5f5f5f5f	32	plan9	REPNE MINSD 0(CX), X2
-f20f5d11|223344556677885f5f5f5f5f	64	gnu	minsd (%rcx),%xmm2
-f20f5d11|223344556677885f5f5f5f5f	64	intel	minsd xmm2, qword ptr [rcx]
-f20f5d11|223344556677885f5f5f5f5f	64	plan9	REPNE MINSD 0(CX), X2
-f20f5e11|223344556677885f5f5f5f5f	32	intel	divsd xmm2, qword ptr [ecx]
-f20f5e11|223344556677885f5f5f5f5f	32	plan9	REPNE DIVSD 0(CX), X2
-f20f5e11|223344556677885f5f5f5f5f	64	gnu	divsd (%rcx),%xmm2
-f20f5e11|223344556677885f5f5f5f5f	64	intel	divsd xmm2, qword ptr [rcx]
-f20f5e11|223344556677885f5f5f5f5f	64	plan9	REPNE DIVSD 0(CX), X2
-f20f5f11|223344556677885f5f5f5f5f	32	intel	maxsd xmm2, qword ptr [ecx]
-f20f5f11|223344556677885f5f5f5f5f	32	plan9	REPNE MAXSD 0(CX), X2
-f20f5f11|223344556677885f5f5f5f5f	64	gnu	maxsd (%rcx),%xmm2
-f20f5f11|223344556677885f5f5f5f5f	64	intel	maxsd xmm2, qword ptr [rcx]
-f20f5f11|223344556677885f5f5f5f5f	64	plan9	REPNE MAXSD 0(CX), X2
-f20f701122|3344556677885f5f5f5f5f	32	intel	pshuflw xmm2, xmmword ptr [ecx], 0x22
-f20f701122|3344556677885f5f5f5f5f	32	plan9	REPNE PSHUFLW $0x22, 0(CX), X2
-f20f701122|3344556677885f5f5f5f5f	64	gnu	pshuflw $0x22,(%rcx),%xmm2
-f20f701122|3344556677885f5f5f5f5f	64	intel	pshuflw xmm2, xmmword ptr [rcx], 0x22
-f20f701122|3344556677885f5f5f5f5f	64	plan9	REPNE PSHUFLW $0x22, 0(CX), X2
-f20f7c11|223344556677885f5f5f5f5f	32	intel	haddps xmm2, xmmword ptr [ecx]
-f20f7c11|223344556677885f5f5f5f5f	32	plan9	REPNE HADDPS 0(CX), X2
-f20f7c11|223344556677885f5f5f5f5f	64	gnu	haddps (%rcx),%xmm2
-f20f7c11|223344556677885f5f5f5f5f	64	intel	haddps xmm2, xmmword ptr [rcx]
-f20f7c11|223344556677885f5f5f5f5f	64	plan9	REPNE HADDPS 0(CX), X2
-f20f7d11|223344556677885f5f5f5f5f	32	intel	hsubps xmm2, xmmword ptr [ecx]
-f20f7d11|223344556677885f5f5f5f5f	32	plan9	REPNE HSUBPS 0(CX), X2
-f20f7d11|223344556677885f5f5f5f5f	64	gnu	hsubps (%rcx),%xmm2
-f20f7d11|223344556677885f5f5f5f5f	64	intel	hsubps xmm2, xmmword ptr [rcx]
-f20f7d11|223344556677885f5f5f5f5f	64	plan9	REPNE HSUBPS 0(CX), X2
-f20fc21122|3344556677885f5f5f5f5f	32	intel	cmpsd_xmm xmm2, qword ptr [ecx], 0x22
-f20fc21122|3344556677885f5f5f5f5f	32	plan9	REPNE CMPSD_XMM $0x22, 0(CX), X2
-f20fc21122|3344556677885f5f5f5f5f	64	gnu	cmpsd $0x22,(%rcx),%xmm2
-f20fc21122|3344556677885f5f5f5f5f	64	intel	cmpsd_xmm xmm2, qword ptr [rcx], 0x22
-f20fc21122|3344556677885f5f5f5f5f	64	plan9	REPNE CMPSD_XMM $0x22, 0(CX), X2
-f20fd011|223344556677885f5f5f5f5f	32	intel	addsubps xmm2, xmmword ptr [ecx]
-f20fd011|223344556677885f5f5f5f5f	32	plan9	REPNE ADDSUBPS 0(CX), X2
-f20fd011|223344556677885f5f5f5f5f	64	gnu	addsubps (%rcx),%xmm2
-f20fd011|223344556677885f5f5f5f5f	64	intel	addsubps xmm2, xmmword ptr [rcx]
-f20fd011|223344556677885f5f5f5f5f	64	plan9	REPNE ADDSUBPS 0(CX), X2
-f20fd6c0|11223344556677885f5f5f5f	32	intel	movdq2q mmx0, xmm0
-f20fd6c0|11223344556677885f5f5f5f	32	plan9	REPNE MOVDQ2Q X0, M0
-f20fd6c0|11223344556677885f5f5f5f	64	gnu	movdq2q %xmm0,%mm0
-f20fd6c0|11223344556677885f5f5f5f	64	intel	movdq2q mmx0, xmm0
-f20fd6c0|11223344556677885f5f5f5f	64	plan9	REPNE MOVDQ2Q X0, M0
-f20fe611|223344556677885f5f5f5f5f	32	intel	cvtpd2dq xmm2, xmmword ptr [ecx]
-f20fe611|223344556677885f5f5f5f5f	32	plan9	REPNE CVTPD2DQ 0(CX), X2
-f20fe611|223344556677885f5f5f5f5f	64	gnu	cvtpd2dq (%rcx),%xmm2
-f20fe611|223344556677885f5f5f5f5f	64	intel	cvtpd2dq xmm2, xmmword ptr [rcx]
-f20fe611|223344556677885f5f5f5f5f	64	plan9	REPNE CVTPD2DQ 0(CX), X2
-f20ff011|223344556677885f5f5f5f5f	32	intel	lddqu xmm2, xmmword ptr [ecx]
-f20ff011|223344556677885f5f5f5f5f	32	plan9	REPNE LDDQU 0(CX), X2
-f20ff011|223344556677885f5f5f5f5f	64	gnu	lddqu (%rcx),%xmm2
-f20ff011|223344556677885f5f5f5f5f	64	intel	lddqu xmm2, xmmword ptr [rcx]
-f20ff011|223344556677885f5f5f5f5f	64	plan9	REPNE LDDQU 0(CX), X2
-f2480f2a11|223344556677885f5f5f5f	64	gnu	cvtsi2sdq (%rcx),%xmm2
-f2480f2a11|223344556677885f5f5f5f	64	intel	cvtsi2sd xmm2, qword ptr [rcx]
-f2480f2a11|223344556677885f5f5f5f	64	plan9	REPNE CVTSI2SDQ 0(CX), X2
-f2480f2c11|223344556677885f5f5f5f	64	gnu	cvttsd2si (%rcx),%rdx
-f2480f2c11|223344556677885f5f5f5f	64	intel	cvttsd2si rdx, qword ptr [rcx]
-f2480f2c11|223344556677885f5f5f5f	64	plan9	REPNE CVTTSD2SIQ 0(CX), DX
-f2480f2d11|223344556677885f5f5f5f	64	gnu	cvtsd2si (%rcx),%rdx
-f2480f2d11|223344556677885f5f5f5f	64	intel	cvtsd2si rdx, qword ptr [rcx]
-f2480f2d11|223344556677885f5f5f5f	64	plan9	REPNE CVTSD2SIQ 0(CX), DX
-f2480f38f011|223344556677885f5f5f	64	gnu	crc32b (%rcx),%rdx
-f2480f38f011|223344556677885f5f5f	64	intel	crc32 rdx, byte ptr [rcx]
-f2480f38f011|223344556677885f5f5f	64	plan9	REPNE CRC32 0(CX), DX
-f2480f38f111|223344556677885f5f5f	64	gnu	crc32q (%rcx),%rdx
-f2480f38f111|223344556677885f5f5f	64	intel	crc32 rdx, qword ptr [rcx]
-f2480f38f111|223344556677885f5f5f	64	plan9	REPNE CRC32 0(CX), DX
-f267f0663e360f38f111|223344556677	32	intel	lock crc32 edx, word ptr ss:[bx+di*1]
-f267f0663e360f38f111|223344556677	32	plan9	SS CRC32 SS:0(BX)(DI*1), DX
-f267f0663e360f38f111|223344556677	64	gnu	lock crc32w %ds:%ss:(%ecx),%edx
-f267f0663e360f38f111|223344556677	64	intel	lock crc32 edx, word ptr [ecx]
-f267f0663e360f38f111|223344556677	64	plan9	SS CRC32 0(CX), DX
-f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	intel	movntss dword ptr [ecx], xmm2
-f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	plan9	REP MOVNTSS X2, 0(CX)
-f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	gnu	repn movntss %xmm2,(%rcx)
-f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	intel	movntss dword ptr [rcx], xmm2
-f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	plan9	REP MOVNTSS X2, 0(CX)
-f30f1011|223344556677885f5f5f5f5f	32	intel	movss xmm2, dword ptr [ecx]
-f30f1011|223344556677885f5f5f5f5f	32	plan9	REP MOVSS 0(CX), X2
-f30f1011|223344556677885f5f5f5f5f	64	gnu	movss (%rcx),%xmm2
-f30f1011|223344556677885f5f5f5f5f	64	intel	movss xmm2, dword ptr [rcx]
-f30f1011|223344556677885f5f5f5f5f	64	plan9	REP MOVSS 0(CX), X2
-f30f1122|3344556677885f5f5f5f5f5f	32	intel	movss dword ptr [edx], xmm4
-f30f1122|3344556677885f5f5f5f5f5f	32	plan9	REP MOVSS X4, 0(DX)
-f30f1122|3344556677885f5f5f5f5f5f	64	gnu	movss %xmm4,(%rdx)
-f30f1122|3344556677885f5f5f5f5f5f	64	intel	movss dword ptr [rdx], xmm4
-f30f1122|3344556677885f5f5f5f5f5f	64	plan9	REP MOVSS X4, 0(DX)
-f30f1211|223344556677885f5f5f5f5f	32	intel	movsldup xmm2, xmmword ptr [ecx]
-f30f1211|223344556677885f5f5f5f5f	32	plan9	REP MOVSLDUP 0(CX), X2
-f30f1211|223344556677885f5f5f5f5f	64	gnu	movsldup (%rcx),%xmm2
-f30f1211|223344556677885f5f5f5f5f	64	intel	movsldup xmm2, xmmword ptr [rcx]
-f30f1211|223344556677885f5f5f5f5f	64	plan9	REP MOVSLDUP 0(CX), X2
-f30f1611|223344556677885f5f5f5f5f	32	intel	movshdup xmm2, xmmword ptr [ecx]
-f30f1611|223344556677885f5f5f5f5f	32	plan9	REP MOVSHDUP 0(CX), X2
-f30f1611|223344556677885f5f5f5f5f	64	gnu	movshdup (%rcx),%xmm2
-f30f1611|223344556677885f5f5f5f5f	64	intel	movshdup xmm2, xmmword ptr [rcx]
-f30f1611|223344556677885f5f5f5f5f	64	plan9	REP MOVSHDUP 0(CX), X2
-f30f2a11|223344556677885f5f5f5f5f	32	intel	cvtsi2ss xmm2, dword ptr [ecx]
-f30f2a11|223344556677885f5f5f5f5f	32	plan9	REP CVTSI2SSL 0(CX), X2
-f30f2a11|223344556677885f5f5f5f5f	64	gnu	cvtsi2ssl (%rcx),%xmm2
-f30f2a11|223344556677885f5f5f5f5f	64	intel	cvtsi2ss xmm2, dword ptr [rcx]
-f30f2a11|223344556677885f5f5f5f5f	64	plan9	REP CVTSI2SSL 0(CX), X2
-f30f2c11|223344556677885f5f5f5f5f	32	intel	cvttss2si edx, dword ptr [ecx]
-f30f2c11|223344556677885f5f5f5f5f	32	plan9	REP CVTTSS2SIL 0(CX), DX
-f30f2c11|223344556677885f5f5f5f5f	64	gnu	cvttss2si (%rcx),%edx
-f30f2c11|223344556677885f5f5f5f5f	64	intel	cvttss2si edx, dword ptr [rcx]
-f30f2c11|223344556677885f5f5f5f5f	64	plan9	REP CVTTSS2SIL 0(CX), DX
-f30f2d11|223344556677885f5f5f5f5f	32	intel	cvtss2si edx, dword ptr [ecx]
-f30f2d11|223344556677885f5f5f5f5f	32	plan9	REP CVTSS2SIL 0(CX), DX
-f30f2d11|223344556677885f5f5f5f5f	64	gnu	cvtss2si (%rcx),%edx
-f30f2d11|223344556677885f5f5f5f5f	64	intel	cvtss2si edx, dword ptr [rcx]
-f30f2d11|223344556677885f5f5f5f5f	64	plan9	REP CVTSS2SIL 0(CX), DX
-f30f5111|223344556677885f5f5f5f5f	32	intel	sqrtss xmm2, dword ptr [ecx]
-f30f5111|223344556677885f5f5f5f5f	32	plan9	REP SQRTSS 0(CX), X2
-f30f5111|223344556677885f5f5f5f5f	64	gnu	sqrtss (%rcx),%xmm2
-f30f5111|223344556677885f5f5f5f5f	64	intel	sqrtss xmm2, dword ptr [rcx]
-f30f5111|223344556677885f5f5f5f5f	64	plan9	REP SQRTSS 0(CX), X2
-f30f5211|223344556677885f5f5f5f5f	32	intel	rsqrtss xmm2, dword ptr [ecx]
-f30f5211|223344556677885f5f5f5f5f	32	plan9	REP RSQRTSS 0(CX), X2
-f30f5211|223344556677885f5f5f5f5f	64	gnu	rsqrtss (%rcx),%xmm2
-f30f5211|223344556677885f5f5f5f5f	64	intel	rsqrtss xmm2, dword ptr [rcx]
-f30f5211|223344556677885f5f5f5f5f	64	plan9	REP RSQRTSS 0(CX), X2
-f30f5311|223344556677885f5f5f5f5f	32	intel	rcpss xmm2, dword ptr [ecx]
-f30f5311|223344556677885f5f5f5f5f	32	plan9	REP RCPSS 0(CX), X2
-f30f5311|223344556677885f5f5f5f5f	64	gnu	rcpss (%rcx),%xmm2
-f30f5311|223344556677885f5f5f5f5f	64	intel	rcpss xmm2, dword ptr [rcx]
-f30f5311|223344556677885f5f5f5f5f	64	plan9	REP RCPSS 0(CX), X2
-f30f5811|223344556677885f5f5f5f5f	32	intel	addss xmm2, dword ptr [ecx]
-f30f5811|223344556677885f5f5f5f5f	32	plan9	REP ADDSS 0(CX), X2
-f30f5811|223344556677885f5f5f5f5f	64	gnu	addss (%rcx),%xmm2
-f30f5811|223344556677885f5f5f5f5f	64	intel	addss xmm2, dword ptr [rcx]
-f30f5811|223344556677885f5f5f5f5f	64	plan9	REP ADDSS 0(CX), X2
-f30f5911|223344556677885f5f5f5f5f	32	intel	mulss xmm2, dword ptr [ecx]
-f30f5911|223344556677885f5f5f5f5f	32	plan9	REP MULSS 0(CX), X2
-f30f5911|223344556677885f5f5f5f5f	64	gnu	mulss (%rcx),%xmm2
-f30f5911|223344556677885f5f5f5f5f	64	intel	mulss xmm2, dword ptr [rcx]
-f30f5911|223344556677885f5f5f5f5f	64	plan9	REP MULSS 0(CX), X2
-f30f5a11|223344556677885f5f5f5f5f	32	intel	cvtss2sd xmm2, dword ptr [ecx]
-f30f5a11|223344556677885f5f5f5f5f	32	plan9	REP CVTSS2SD 0(CX), X2
-f30f5a11|223344556677885f5f5f5f5f	64	gnu	cvtss2sd (%rcx),%xmm2
-f30f5a11|223344556677885f5f5f5f5f	64	intel	cvtss2sd xmm2, dword ptr [rcx]
-f30f5a11|223344556677885f5f5f5f5f	64	plan9	REP CVTSS2SD 0(CX), X2
-f30f5b11|223344556677885f5f5f5f5f	32	intel	cvttps2dq xmm2, xmmword ptr [ecx]
-f30f5b11|223344556677885f5f5f5f5f	32	plan9	REP CVTTPS2DQ 0(CX), X2
-f30f5b11|223344556677885f5f5f5f5f	64	gnu	cvttps2dq (%rcx),%xmm2
-f30f5b11|223344556677885f5f5f5f5f	64	intel	cvttps2dq xmm2, xmmword ptr [rcx]
-f30f5b11|223344556677885f5f5f5f5f	64	plan9	REP CVTTPS2DQ 0(CX), X2
-f30f5c11|223344556677885f5f5f5f5f	32	intel	subss xmm2, dword ptr [ecx]
-f30f5c11|223344556677885f5f5f5f5f	32	plan9	REP SUBSS 0(CX), X2
-f30f5c11|223344556677885f5f5f5f5f	64	gnu	subss (%rcx),%xmm2
-f30f5c11|223344556677885f5f5f5f5f	64	intel	subss xmm2, dword ptr [rcx]
-f30f5c11|223344556677885f5f5f5f5f	64	plan9	REP SUBSS 0(CX), X2
-f30f5d11|223344556677885f5f5f5f5f	32	intel	minss xmm2, dword ptr [ecx]
-f30f5d11|223344556677885f5f5f5f5f	32	plan9	REP MINSS 0(CX), X2
-f30f5d11|223344556677885f5f5f5f5f	64	gnu	minss (%rcx),%xmm2
-f30f5d11|223344556677885f5f5f5f5f	64	intel	minss xmm2, dword ptr [rcx]
-f30f5d11|223344556677885f5f5f5f5f	64	plan9	REP MINSS 0(CX), X2
-f30f5e11|223344556677885f5f5f5f5f	32	intel	divss xmm2, dword ptr [ecx]
-f30f5e11|223344556677885f5f5f5f5f	32	plan9	REP DIVSS 0(CX), X2
-f30f5e11|223344556677885f5f5f5f5f	64	gnu	divss (%rcx),%xmm2
-f30f5e11|223344556677885f5f5f5f5f	64	intel	divss xmm2, dword ptr [rcx]
-f30f5e11|223344556677885f5f5f5f5f	64	plan9	REP DIVSS 0(CX), X2
-f30f5f11|223344556677885f5f5f5f5f	32	intel	maxss xmm2, dword ptr [ecx]
-f30f5f11|223344556677885f5f5f5f5f	32	plan9	REP MAXSS 0(CX), X2
-f30f5f11|223344556677885f5f5f5f5f	64	gnu	maxss (%rcx),%xmm2
-f30f5f11|223344556677885f5f5f5f5f	64	intel	maxss xmm2, dword ptr [rcx]
-f30f5f11|223344556677885f5f5f5f5f	64	plan9	REP MAXSS 0(CX), X2
-f30f6f11|223344556677885f5f5f5f5f	32	intel	movdqu xmm2, xmmword ptr [ecx]
-f30f6f11|223344556677885f5f5f5f5f	32	plan9	REP MOVDQU 0(CX), X2
-f30f6f11|223344556677885f5f5f5f5f	64	gnu	movdqu (%rcx),%xmm2
-f30f6f11|223344556677885f5f5f5f5f	64	intel	movdqu xmm2, xmmword ptr [rcx]
-f30f6f11|223344556677885f5f5f5f5f	64	plan9	REP MOVDQU 0(CX), X2
-f30f701122|3344556677885f5f5f5f5f	32	intel	pshufhw xmm2, xmmword ptr [ecx], 0x22
-f30f701122|3344556677885f5f5f5f5f	32	plan9	REP PSHUFHW $0x22, 0(CX), X2
-f30f701122|3344556677885f5f5f5f5f	64	gnu	pshufhw $0x22,(%rcx),%xmm2
-f30f701122|3344556677885f5f5f5f5f	64	intel	pshufhw xmm2, xmmword ptr [rcx], 0x22
-f30f701122|3344556677885f5f5f5f5f	64	plan9	REP PSHUFHW $0x22, 0(CX), X2
-f30f7e11|223344556677885f5f5f5f5f	32	intel	movq xmm2, qword ptr [ecx]
-f30f7e11|223344556677885f5f5f5f5f	32	plan9	REP MOVQ 0(CX), X2
-f30f7e11|223344556677885f5f5f5f5f	64	gnu	movq (%rcx),%xmm2
-f30f7e11|223344556677885f5f5f5f5f	64	intel	movq xmm2, qword ptr [rcx]
-f30f7e11|223344556677885f5f5f5f5f	64	plan9	REP MOVQ 0(CX), X2
-f30f7f11|223344556677885f5f5f5f5f	32	intel	movdqu xmmword ptr [ecx], xmm2
-f30f7f11|223344556677885f5f5f5f5f	32	plan9	REP MOVDQU X2, 0(CX)
-f30f7f11|223344556677885f5f5f5f5f	64	gnu	movdqu %xmm2,(%rcx)
-f30f7f11|223344556677885f5f5f5f5f	64	intel	movdqu xmmword ptr [rcx], xmm2
-f30f7f11|223344556677885f5f5f5f5f	64	plan9	REP MOVDQU X2, 0(CX)
-f30fae11|223344556677885f5f5f5f5f	64	gnu	wrfsbasel (%rcx)
-f30fae11|223344556677885f5f5f5f5f	64	intel	wrfsbase dword ptr [rcx]
-f30fae11|223344556677885f5f5f5f5f	64	plan9	REP WRFSBASE 0(CX)
-f30fae18|11223344556677885f5f5f5f	64	gnu	wrgsbasel (%rax)
-f30fae18|11223344556677885f5f5f5f	64	intel	wrgsbase dword ptr [rax]
-f30fae18|11223344556677885f5f5f5f	64	plan9	REP WRGSBASE 0(AX)
-f30faec0|11223344556677885f5f5f5f	64	gnu	rdfsbase %eax
-f30faec0|11223344556677885f5f5f5f	64	intel	rdfsbase eax
-f30faec0|11223344556677885f5f5f5f	64	plan9	REP RDFSBASE AX
-f30faec8|11223344556677885f5f5f5f	64	gnu	rdgsbase %eax
-f30faec8|11223344556677885f5f5f5f	64	intel	rdgsbase eax
-f30faec8|11223344556677885f5f5f5f	64	plan9	REP RDGSBASE AX
-f30fb811|223344556677885f5f5f5f5f	32	intel	popcnt edx, dword ptr [ecx]
-f30fb811|223344556677885f5f5f5f5f	32	plan9	REP POPCNT 0(CX), DX
-f30fb811|223344556677885f5f5f5f5f	64	gnu	popcnt (%rcx),%edx
-f30fb811|223344556677885f5f5f5f5f	64	intel	popcnt edx, dword ptr [rcx]
-f30fb811|223344556677885f5f5f5f5f	64	plan9	REP POPCNT 0(CX), DX
-f30fbc11|223344556677885f5f5f5f5f	32	intel	tzcnt edx, dword ptr [ecx]
-f30fbc11|223344556677885f5f5f5f5f	32	plan9	REP TZCNT 0(CX), DX
-f30fbc11|223344556677885f5f5f5f5f	64	gnu	tzcnt (%rcx),%edx
-f30fbc11|223344556677885f5f5f5f5f	64	intel	tzcnt edx, dword ptr [rcx]
-f30fbc11|223344556677885f5f5f5f5f	64	plan9	REP TZCNT 0(CX), DX
-f30fbd11|223344556677885f5f5f5f5f	32	intel	lzcnt edx, dword ptr [ecx]
-f30fbd11|223344556677885f5f5f5f5f	32	plan9	REP LZCNT 0(CX), DX
-f30fbd11|223344556677885f5f5f5f5f	64	gnu	lzcnt (%rcx),%edx
-f30fbd11|223344556677885f5f5f5f5f	64	intel	lzcnt edx, dword ptr [rcx]
-f30fbd11|223344556677885f5f5f5f5f	64	plan9	REP LZCNT 0(CX), DX
-f30fc21122|3344556677885f5f5f5f5f	32	intel	cmpss xmm2, dword ptr [ecx], 0x22
-f30fc21122|3344556677885f5f5f5f5f	32	plan9	REP CMPSS $0x22, 0(CX), X2
-f30fc21122|3344556677885f5f5f5f5f	64	gnu	cmpss $0x22,(%rcx),%xmm2
-f30fc21122|3344556677885f5f5f5f5f	64	intel	cmpss xmm2, dword ptr [rcx], 0x22
-f30fc21122|3344556677885f5f5f5f5f	64	plan9	REP CMPSS $0x22, 0(CX), X2
-f30fe611|223344556677885f5f5f5f5f	32	intel	cvtdq2pd xmm2, qword ptr [ecx]
-f30fe611|223344556677885f5f5f5f5f	32	plan9	REP CVTDQ2PD 0(CX), X2
-f30fe611|223344556677885f5f5f5f5f	64	gnu	cvtdq2pd (%rcx),%xmm2
-f30fe611|223344556677885f5f5f5f5f	64	intel	cvtdq2pd xmm2, qword ptr [rcx]
-f30fe611|223344556677885f5f5f5f5f	64	plan9	REP CVTDQ2PD 0(CX), X2
-f3480f2a11|223344556677885f5f5f5f	64	gnu	cvtsi2ssq (%rcx),%xmm2
-f3480f2a11|223344556677885f5f5f5f	64	intel	cvtsi2ss xmm2, qword ptr [rcx]
-f3480f2a11|223344556677885f5f5f5f	64	plan9	REP CVTSI2SSQ 0(CX), X2
-f3480f2c11|223344556677885f5f5f5f	64	gnu	cvttss2si (%rcx),%rdx
-f3480f2c11|223344556677885f5f5f5f	64	intel	cvttss2si rdx, dword ptr [rcx]
-f3480f2c11|223344556677885f5f5f5f	64	plan9	REP CVTTSS2SIQ 0(CX), DX
-f3480f2d11|223344556677885f5f5f5f	64	gnu	cvtss2si (%rcx),%rdx
-f3480f2d11|223344556677885f5f5f5f	64	intel	cvtss2si rdx, dword ptr [rcx]
-f3480f2d11|223344556677885f5f5f5f	64	plan9	REP CVTSS2SIQ 0(CX), DX
-f3480fae11|223344556677885f5f5f5f	64	gnu	wrfsbaseq (%rcx)
-f3480fae11|223344556677885f5f5f5f	64	intel	wrfsbase qword ptr [rcx]
-f3480fae11|223344556677885f5f5f5f	64	plan9	REP WRFSBASE 0(CX)
-f3480fae18|11223344556677885f5f5f	64	gnu	wrgsbaseq (%rax)
-f3480fae18|11223344556677885f5f5f	64	intel	wrgsbase qword ptr [rax]
-f3480fae18|11223344556677885f5f5f	64	plan9	REP WRGSBASE 0(AX)
-f3480faec0|11223344556677885f5f5f	64	gnu	rdfsbase %rax
-f3480faec0|11223344556677885f5f5f	64	intel	rdfsbase rax
-f3480faec0|11223344556677885f5f5f	64	plan9	REP RDFSBASE AX
-f3480faec8|11223344556677885f5f5f	64	gnu	rdgsbase %rax
-f3480faec8|11223344556677885f5f5f	64	intel	rdgsbase rax
-f3480faec8|11223344556677885f5f5f	64	plan9	REP RDGSBASE AX
-f3480fb811|223344556677885f5f5f5f	64	gnu	popcnt (%rcx),%rdx
-f3480fb811|223344556677885f5f5f5f	64	intel	popcnt rdx, qword ptr [rcx]
-f3480fb811|223344556677885f5f5f5f	64	plan9	REP POPCNT 0(CX), DX
-f3480fbc11|223344556677885f5f5f5f	64	gnu	tzcnt (%rcx),%rdx
-f3480fbc11|223344556677885f5f5f5f	64	intel	tzcnt rdx, qword ptr [rcx]
-f3480fbc11|223344556677885f5f5f5f	64	plan9	REP TZCNT 0(CX), DX
-f3480fbd11|223344556677885f5f5f5f	64	gnu	lzcnt (%rcx),%rdx
-f3480fbd11|223344556677885f5f5f5f	64	intel	lzcnt rdx, qword ptr [rcx]
-f3480fbd11|223344556677885f5f5f5f	64	plan9	REP LZCNT 0(CX), DX
-f3660fb811|223344556677885f5f5f5f	32	intel	popcnt dx, word ptr [ecx]
-f3660fb811|223344556677885f5f5f5f	32	plan9	POPCNT 0(CX), DX
-f3660fb811|223344556677885f5f5f5f	64	gnu	popcnt (%rcx),%dx
-f3660fb811|223344556677885f5f5f5f	64	intel	popcnt dx, word ptr [rcx]
-f3660fb811|223344556677885f5f5f5f	64	plan9	POPCNT 0(CX), DX
-f3660fbc11|223344556677885f5f5f5f	32	intel	tzcnt dx, word ptr [ecx]
-f3660fbc11|223344556677885f5f5f5f	32	plan9	TZCNT 0(CX), DX
-f3660fbc11|223344556677885f5f5f5f	64	gnu	tzcnt (%rcx),%dx
-f3660fbc11|223344556677885f5f5f5f	64	intel	tzcnt dx, word ptr [rcx]
-f3660fbc11|223344556677885f5f5f5f	64	plan9	TZCNT 0(CX), DX
-f3660fbd11|223344556677885f5f5f5f	32	intel	lzcnt dx, word ptr [ecx]
-f3660fbd11|223344556677885f5f5f5f	32	plan9	LZCNT 0(CX), DX
-f3660fbd11|223344556677885f5f5f5f	64	gnu	lzcnt (%rcx),%dx
-f3660fbd11|223344556677885f5f5f5f	64	intel	lzcnt dx, word ptr [rcx]
-f3660fbd11|223344556677885f5f5f5f	64	plan9	LZCNT 0(CX), DX
-f3f0673e660f38f111|22334455667788	32	intel	lock movbe word ptr [bx+di*1], dx
-f3f0673e660f38f111|22334455667788	32	plan9	MOVBE DX, DS:0(BX)(DI*1)
-f3f0673e660f38f111|22334455667788	64	gnu	rep lock movbe %dx,%ds:(%ecx)
-f3f0673e660f38f111|22334455667788	64	intel	lock movbe word ptr [ecx], dx
-f3f0673e660f38f111|22334455667788	64	plan9	MOVBE DX, 0(CX)
-f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	intel	movntsd qword ptr [ecx], xmm2
-f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	plan9	REPNE MOVNTSD X2, 0(CX)
-f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	gnu	repn movntss %xmm2,(%rcx)
-f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	intel	movntsd qword ptr [rcx], xmm2
-f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	plan9	REPNE MOVNTSD X2, 0(CX)
-f4|11223344556677885f5f5f5f5f5f5f	32	intel	hlt
-f4|11223344556677885f5f5f5f5f5f5f	32	plan9	HLT
-f4|11223344556677885f5f5f5f5f5f5f	64	gnu	hlt
-f4|11223344556677885f5f5f5f5f5f5f	64	intel	hlt
-f4|11223344556677885f5f5f5f5f5f5f	64	plan9	HLT
-f5|11223344556677885f5f5f5f5f5f5f	32	intel	cmc
-f5|11223344556677885f5f5f5f5f5f5f	32	plan9	CMC
-f5|11223344556677885f5f5f5f5f5f5f	64	gnu	cmc
-f5|11223344556677885f5f5f5f5f5f5f	64	intel	cmc
-f5|11223344556677885f5f5f5f5f5f5f	64	plan9	CMC
-f60011|223344556677885f5f5f5f5f5f	32	intel	test byte ptr [eax], 0x11
-f60011|223344556677885f5f5f5f5f5f	32	plan9	TESTL $0x11, 0(AX)
-f60011|223344556677885f5f5f5f5f5f	64	gnu	testb $0x11,(%rax)
-f60011|223344556677885f5f5f5f5f5f	64	intel	test byte ptr [rax], 0x11
-f60011|223344556677885f5f5f5f5f5f	64	plan9	TESTL $0x11, 0(AX)
-f611|223344556677885f5f5f5f5f5f5f	32	intel	not byte ptr [ecx]
-f611|223344556677885f5f5f5f5f5f5f	32	plan9	NOTL 0(CX)
-f611|223344556677885f5f5f5f5f5f5f	64	gnu	notb (%rcx)
-f611|223344556677885f5f5f5f5f5f5f	64	intel	not byte ptr [rcx]
-f611|223344556677885f5f5f5f5f5f5f	64	plan9	NOTL 0(CX)
-f618|11223344556677885f5f5f5f5f5f	32	intel	neg byte ptr [eax]
-f618|11223344556677885f5f5f5f5f5f	32	plan9	NEGL 0(AX)
-f618|11223344556677885f5f5f5f5f5f	64	gnu	negb (%rax)
-f618|11223344556677885f5f5f5f5f5f	64	intel	neg byte ptr [rax]
-f618|11223344556677885f5f5f5f5f5f	64	plan9	NEGL 0(AX)
-f620|11223344556677885f5f5f5f5f5f	32	intel	mul byte ptr [eax]
-f620|11223344556677885f5f5f5f5f5f	32	plan9	MULL 0(AX)
-f620|11223344556677885f5f5f5f5f5f	64	gnu	mulb (%rax)
-f620|11223344556677885f5f5f5f5f5f	64	intel	mul byte ptr [rax]
-f620|11223344556677885f5f5f5f5f5f	64	plan9	MULL 0(AX)
-f628|11223344556677885f5f5f5f5f5f	32	intel	imul byte ptr [eax]
-f628|11223344556677885f5f5f5f5f5f	32	plan9	IMULL 0(AX)
-f628|11223344556677885f5f5f5f5f5f	64	gnu	imulb (%rax)
-f628|11223344556677885f5f5f5f5f5f	64	intel	imul byte ptr [rax]
-f628|11223344556677885f5f5f5f5f5f	64	plan9	IMULL 0(AX)
-f630|11223344556677885f5f5f5f5f5f	32	intel	div byte ptr [eax]
-f630|11223344556677885f5f5f5f5f5f	32	plan9	DIVL 0(AX)
-f630|11223344556677885f5f5f5f5f5f	64	gnu	divb (%rax)
-f630|11223344556677885f5f5f5f5f5f	64	intel	div byte ptr [rax]
-f630|11223344556677885f5f5f5f5f5f	64	plan9	DIVL 0(AX)
-f638|11223344556677885f5f5f5f5f5f	32	intel	idiv byte ptr [eax]
-f638|11223344556677885f5f5f5f5f5f	32	plan9	IDIVL 0(AX)
-f638|11223344556677885f5f5f5f5f5f	64	gnu	idivb (%rax)
-f638|11223344556677885f5f5f5f5f5f	64	intel	idiv byte ptr [rax]
-f638|11223344556677885f5f5f5f5f5f	64	plan9	IDIVL 0(AX)
-f70011223344|556677885f5f5f5f5f5f	32	intel	test dword ptr [eax], 0x44332211
-f70011223344|556677885f5f5f5f5f5f	32	plan9	TESTL $0x44332211, 0(AX)
-f70011223344|556677885f5f5f5f5f5f	64	gnu	testl $0x44332211,(%rax)
-f70011223344|556677885f5f5f5f5f5f	64	intel	test dword ptr [rax], 0x44332211
-f70011223344|556677885f5f5f5f5f5f	64	plan9	TESTL $0x44332211, 0(AX)
-f711|223344556677885f5f5f5f5f5f5f	32	intel	not dword ptr [ecx]
-f711|223344556677885f5f5f5f5f5f5f	32	plan9	NOTL 0(CX)
-f711|223344556677885f5f5f5f5f5f5f	64	gnu	notl (%rcx)
-f711|223344556677885f5f5f5f5f5f5f	64	intel	not dword ptr [rcx]
-f711|223344556677885f5f5f5f5f5f5f	64	plan9	NOTL 0(CX)
-f718|11223344556677885f5f5f5f5f5f	32	intel	neg dword ptr [eax]
-f718|11223344556677885f5f5f5f5f5f	32	plan9	NEGL 0(AX)
-f718|11223344556677885f5f5f5f5f5f	64	gnu	negl (%rax)
-f718|11223344556677885f5f5f5f5f5f	64	intel	neg dword ptr [rax]
-f718|11223344556677885f5f5f5f5f5f	64	plan9	NEGL 0(AX)
-f720|11223344556677885f5f5f5f5f5f	32	intel	mul dword ptr [eax]
-f720|11223344556677885f5f5f5f5f5f	32	plan9	MULL 0(AX)
-f720|11223344556677885f5f5f5f5f5f	64	gnu	mull (%rax)
-f720|11223344556677885f5f5f5f5f5f	64	intel	mul dword ptr [rax]
-f720|11223344556677885f5f5f5f5f5f	64	plan9	MULL 0(AX)
-f728|11223344556677885f5f5f5f5f5f	32	intel	imul dword ptr [eax]
-f728|11223344556677885f5f5f5f5f5f	32	plan9	IMULL 0(AX)
-f728|11223344556677885f5f5f5f5f5f	64	gnu	imull (%rax)
-f728|11223344556677885f5f5f5f5f5f	64	intel	imul dword ptr [rax]
-f728|11223344556677885f5f5f5f5f5f	64	plan9	IMULL 0(AX)
-f730|11223344556677885f5f5f5f5f5f	32	intel	div dword ptr [eax]
-f730|11223344556677885f5f5f5f5f5f	32	plan9	DIVL 0(AX)
-f730|11223344556677885f5f5f5f5f5f	64	gnu	divl (%rax)
-f730|11223344556677885f5f5f5f5f5f	64	intel	div dword ptr [rax]
-f730|11223344556677885f5f5f5f5f5f	64	plan9	DIVL 0(AX)
-f738|11223344556677885f5f5f5f5f5f	32	intel	idiv dword ptr [eax]
-f738|11223344556677885f5f5f5f5f5f	32	plan9	IDIVL 0(AX)
-f738|11223344556677885f5f5f5f5f5f	64	gnu	idivl (%rax)
-f738|11223344556677885f5f5f5f5f5f	64	intel	idiv dword ptr [rax]
-f738|11223344556677885f5f5f5f5f5f	64	plan9	IDIVL 0(AX)
-f8|11223344556677885f5f5f5f5f5f5f	32	intel	clc
-f8|11223344556677885f5f5f5f5f5f5f	32	plan9	CLC
-f8|11223344556677885f5f5f5f5f5f5f	64	gnu	clc
-f8|11223344556677885f5f5f5f5f5f5f	64	intel	clc
-f8|11223344556677885f5f5f5f5f5f5f	64	plan9	CLC
-f9|11223344556677885f5f5f5f5f5f5f	32	intel	stc
-f9|11223344556677885f5f5f5f5f5f5f	32	plan9	STC
-f9|11223344556677885f5f5f5f5f5f5f	64	gnu	stc
-f9|11223344556677885f5f5f5f5f5f5f	64	intel	stc
-f9|11223344556677885f5f5f5f5f5f5f	64	plan9	STC
-fa|11223344556677885f5f5f5f5f5f5f	32	intel	cli
-fa|11223344556677885f5f5f5f5f5f5f	32	plan9	CLI
-fa|11223344556677885f5f5f5f5f5f5f	64	gnu	cli
-fa|11223344556677885f5f5f5f5f5f5f	64	intel	cli
-fa|11223344556677885f5f5f5f5f5f5f	64	plan9	CLI
-fb|11223344556677885f5f5f5f5f5f5f	32	intel	sti
-fb|11223344556677885f5f5f5f5f5f5f	32	plan9	STI
-fb|11223344556677885f5f5f5f5f5f5f	64	gnu	sti
-fb|11223344556677885f5f5f5f5f5f5f	64	intel	sti
-fb|11223344556677885f5f5f5f5f5f5f	64	plan9	STI
-fc|11223344556677885f5f5f5f5f5f5f	32	intel	cld
-fc|11223344556677885f5f5f5f5f5f5f	32	plan9	CLD
-fc|11223344556677885f5f5f5f5f5f5f	64	gnu	cld
-fc|11223344556677885f5f5f5f5f5f5f	64	intel	cld
-fc|11223344556677885f5f5f5f5f5f5f	64	plan9	CLD
-fd|11223344556677885f5f5f5f5f5f5f	32	intel	std
-fd|11223344556677885f5f5f5f5f5f5f	32	plan9	STD
-fd|11223344556677885f5f5f5f5f5f5f	64	gnu	std
-fd|11223344556677885f5f5f5f5f5f5f	64	intel	std
-fd|11223344556677885f5f5f5f5f5f5f	64	plan9	STD
-fe00|11223344556677885f5f5f5f5f5f	32	intel	inc byte ptr [eax]
-fe00|11223344556677885f5f5f5f5f5f	32	plan9	INCL 0(AX)
-fe00|11223344556677885f5f5f5f5f5f	64	gnu	incb (%rax)
-fe00|11223344556677885f5f5f5f5f5f	64	intel	inc byte ptr [rax]
-fe00|11223344556677885f5f5f5f5f5f	64	plan9	INCL 0(AX)
-fe08|11223344556677885f5f5f5f5f5f	32	intel	dec byte ptr [eax]
-fe08|11223344556677885f5f5f5f5f5f	32	plan9	DECL 0(AX)
-fe08|11223344556677885f5f5f5f5f5f	64	gnu	decb (%rax)
-fe08|11223344556677885f5f5f5f5f5f	64	intel	dec byte ptr [rax]
-fe08|11223344556677885f5f5f5f5f5f	64	plan9	DECL 0(AX)
-ff00|11223344556677885f5f5f5f5f5f	32	intel	inc dword ptr [eax]
-ff00|11223344556677885f5f5f5f5f5f	32	plan9	INCL 0(AX)
-ff00|11223344556677885f5f5f5f5f5f	64	gnu	incl (%rax)
-ff00|11223344556677885f5f5f5f5f5f	64	intel	inc dword ptr [rax]
-ff00|11223344556677885f5f5f5f5f5f	64	plan9	INCL 0(AX)
-ff08|11223344556677885f5f5f5f5f5f	32	intel	dec dword ptr [eax]
-ff08|11223344556677885f5f5f5f5f5f	32	plan9	DECL 0(AX)
-ff08|11223344556677885f5f5f5f5f5f	64	gnu	decl (%rax)
-ff08|11223344556677885f5f5f5f5f5f	64	intel	dec dword ptr [rax]
-ff08|11223344556677885f5f5f5f5f5f	64	plan9	DECL 0(AX)
-ff11|223344556677885f5f5f5f5f5f5f	32	intel	call dword ptr [ecx]
-ff11|223344556677885f5f5f5f5f5f5f	32	plan9	CALL 0(CX)
-ff18|11223344556677885f5f5f5f5f5f	32	intel	call far ptr [eax]
-ff18|11223344556677885f5f5f5f5f5f	32	plan9	LCALL 0(AX)
-ff18|11223344556677885f5f5f5f5f5f	64	gnu	lcallq *(%rax)
-ff18|11223344556677885f5f5f5f5f5f	64	intel	call far ptr [rax]
-ff18|11223344556677885f5f5f5f5f5f	64	plan9	LCALL 0(AX)
-ff20|11223344556677885f5f5f5f5f5f	32	intel	jmp dword ptr [eax]
-ff20|11223344556677885f5f5f5f5f5f	32	plan9	JMP 0(AX)
-ff28|11223344556677885f5f5f5f5f5f	32	intel	jmp far ptr [eax]
-ff28|11223344556677885f5f5f5f5f5f	32	plan9	LJMP 0(AX)
-ff28|11223344556677885f5f5f5f5f5f	64	gnu	ljmpq *(%rax)
-ff28|11223344556677885f5f5f5f5f5f	64	intel	jmp far ptr [rax]
-ff28|11223344556677885f5f5f5f5f5f	64	plan9	LJMP 0(AX)
-ff30|11223344556677885f5f5f5f5f5f	32	intel	push dword ptr [eax]
-ff30|11223344556677885f5f5f5f5f5f	32	plan9	PUSHL 0(AX)
-ff30|11223344556677885f5f5f5f5f5f	64	gnu	pushq (%rax)
-ff30|11223344556677885f5f5f5f5f5f	64	intel	push qword ptr [rax]
-ff30|11223344556677885f5f5f5f5f5f	64	plan9	PUSHL 0(AX)
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index fa785c2..eff9a22 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -43,7 +43,7 @@ func PADDR(x uint32) uint32 {
 }
 
 func Addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) int64 {
-	s.Reachable = true
+	s.Attr |= ld.AttrReachable
 	i := s.Size
 	s.Size += 4
 	ld.Symgrow(ctxt, s, s.Size)
@@ -65,11 +65,11 @@ func gentext() {
 		// an init function
 		return
 	}
-	addmoduledata.Reachable = true
+	addmoduledata.Attr |= ld.AttrReachable
 	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
 	initfunc.Type = obj.STEXT
-	initfunc.Local = true
-	initfunc.Reachable = true
+	initfunc.Attr |= ld.AttrLocal
+	initfunc.Attr |= ld.AttrReachable
 	o := func(op ...uint8) {
 		for _, op1 := range op {
 			ld.Adduint8(ld.Ctxt, initfunc, op1)
@@ -86,25 +86,14 @@ func gentext() {
 	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
+	ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
 	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
-	initarray_entry.Reachable = true
-	initarray_entry.Local = true
+	initarray_entry.Attr |= ld.AttrReachable
+	initarray_entry.Attr |= ld.AttrLocal
 	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
@@ -259,7 +248,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 				return
 			}
 			// The code is asking for the address of an external
-			// function.  We provide it with the address of the
+			// function. We provide it with the address of the
 			// correspondent GOT symbol.
 			addgotsym(targ)
 
@@ -285,14 +274,14 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 			return
 		}
 
-		if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
+		if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.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,
+			// 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.
@@ -564,7 +553,7 @@ func addpltsym(s *ld.LSym) {
 		// 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
+		// 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.
 		//
@@ -611,12 +600,12 @@ func addgotsym(s *ld.LSym) {
 
 func asmb() {
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+		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())
+		fmt.Fprintf(ld.Bso, "%5.2f codeblk\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 
@@ -626,7 +615,8 @@ func asmb() {
 
 	sect := ld.Segtext.Sect
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
-	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+	// 0xCC is INT $3 - breakpoint instruction
+	ld.CodeblkPad(int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
 	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))
@@ -634,7 +624,7 @@ func asmb() {
 
 	if ld.Segrodata.Filelen > 0 {
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+			fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
 		ld.Bso.Flush()
 
@@ -643,26 +633,18 @@ func asmb() {
 	}
 
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+		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))
 
+	ld.Cseek(int64(ld.Segdwarf.Fileoff))
+	ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.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()
 	}
 
@@ -671,8 +653,7 @@ func asmb() {
 		ld.Diag("unknown header type %d", ld.HEADTYPE)
 		fallthrough
 
-	case obj.Hplan9,
-		obj.Helf:
+	case obj.Hplan9:
 		break
 
 	case obj.Hdarwin:
@@ -697,13 +678,12 @@ func asmb() {
 	symo := int64(0)
 	if ld.Debug['s'] == 0 {
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+			fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
 		}
 		ld.Bso.Flush()
 		switch ld.HEADTYPE {
 		default:
-		case obj.Hplan9,
-			obj.Helf:
+		case obj.Hplan9:
 			ld.Debug['s'] = 1
 			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
 
@@ -717,11 +697,11 @@ func asmb() {
 			obj.Hdragonfly,
 			obj.Hsolaris,
 			obj.Hnacl:
-			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+			symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 			symo = ld.Rnd(symo, int64(ld.INITRND))
 
 		case obj.Hwindows:
-			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+			symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 			symo = ld.Rnd(symo, ld.PEFILEALIGN)
 		}
 
@@ -735,11 +715,9 @@ func asmb() {
 				ld.Cwrite(ld.Elfstrdat)
 
 				if ld.Debug['v'] != 0 {
-					fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+					fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 				}
 
-				ld.Dwarfemitdebugsections()
-
 				if ld.Linkmode == ld.LinkExternal {
 					ld.Elfemitreloc()
 				}
@@ -753,7 +731,7 @@ func asmb() {
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
 				for i := 0; int32(i) < ld.Lcsize; i++ {
-					ld.Cput(uint8(sym.P[i]))
+					ld.Cput(sym.P[i])
 				}
 
 				ld.Cflush()
@@ -761,11 +739,9 @@ func asmb() {
 
 		case obj.Hwindows:
 			if ld.Debug['v'] != 0 {
-				fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+				fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 			}
 
-			ld.Dwarfemitdebugsections()
-
 		case obj.Hdarwin:
 			if ld.Linkmode == ld.LinkExternal {
 				ld.Machoemitreloc()
@@ -774,7 +750,7 @@ func asmb() {
 	}
 
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 	ld.Cseek(0)
diff --git a/src/cmd/link/internal/amd64/l.go b/src/cmd/link/internal/amd64/l.go
index 2537419..05f7fa3 100644
--- a/src/cmd/link/internal/amd64/l.go
+++ b/src/cmd/link/internal/amd64/l.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -31,15 +31,11 @@
 package amd64
 
 const (
-	thechar   = '6'
 	MaxAlign  = 32 // max data alignment
+	MinAlign  = 1  // min data alignment
 	FuncAlign = 16
 )
 
-const (
-	MINLC = 1
-)
-
 /* Used by ../internal/ld/dwarf.go */
 const (
 	DWARFREGSP = 7
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index 1aa4422..f62f237 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,6 +32,7 @@ package amd64
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,19 +46,14 @@ func Main() {
 }
 
 func linkarchinit() {
-	ld.Thestring = "amd64"
-	ld.Thelinkarch = &ld.Linkamd64
+	ld.SysArch = sys.ArchAMD64
 	if obj.Getgoarch() == "amd64p32" {
-		ld.Thelinkarch = &ld.Linkamd64p32
+		ld.SysArch = sys.ArchAMD64P32
 	}
 
-	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.Minalign = MinAlign
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
@@ -74,6 +70,9 @@ func linkarchinit() {
 	ld.Thearch.Lput = ld.Lputl
 	ld.Thearch.Wput = ld.Wputl
 	ld.Thearch.Vput = ld.Vputl
+	ld.Thearch.Append16 = ld.Append16l
+	ld.Thearch.Append32 = ld.Append32l
+	ld.Thearch.Append64 = ld.Append64l
 
 	ld.Thearch.Linuxdynld = "/lib64/ld-linux-x86-64.so.2"
 	ld.Thearch.Freebsddynld = "/libexec/ld-elf.so.1"
@@ -132,19 +131,6 @@ func archinit() {
 			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()
 
diff --git a/src/cmd/link/internal/amd64/z.go b/src/cmd/link/internal/amd64/z.go
deleted file mode 100644
index f70035b..0000000
--- a/src/cmd/link/internal/amd64/z.go
+++ /dev/null
@@ -1 +0,0 @@
-package amd64
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index 74c2249..0c3e957 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -68,11 +68,11 @@ func gentext() {
 		// an init function
 		return
 	}
-	addmoduledata.Reachable = true
+	addmoduledata.Attr |= ld.AttrReachable
 	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
 	initfunc.Type = obj.STEXT
-	initfunc.Local = true
-	initfunc.Reachable = true
+	initfunc.Attr |= ld.AttrLocal
+	initfunc.Attr |= ld.AttrReachable
 	o := func(op uint32) {
 		ld.Adduint32(ld.Ctxt, initfunc, op)
 	}
@@ -95,30 +95,20 @@ func gentext() {
 	rel.Type = obj.R_PCREL
 	rel.Add = 4
 
-	if ld.Ctxt.Etextp != nil {
-		ld.Ctxt.Etextp.Next = initfunc
-	} else {
-		ld.Ctxt.Textp = initfunc
-	}
-	ld.Ctxt.Etextp = initfunc
+	ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
 	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
-	initarray_entry.Reachable = true
-	initarray_entry.Local = true
+	initarray_entry.Attr |= ld.AttrReachable
+	initarray_entry.Attr |= ld.AttrLocal
 	initarray_entry.Type = obj.SINITARR
 	ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
 }
 
 // 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
+// of a and b; used to adjust ARM branch instruction'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
@@ -340,6 +330,36 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
 
 	rs := r.Xsym
 
+	if r.Type == obj.R_PCREL {
+		if rs.Type == obj.SHOSTOBJ {
+			ld.Diag("pc-relative relocation of external symbol is not supported")
+			return -1
+		}
+		if r.Siz != 4 {
+			return -1
+		}
+
+		// emit a pair of "scattered" relocations that
+		// resolve to the difference of section addresses of
+		// the symbol and the instruction
+		// this value is added to the field being relocated
+		o1 := uint32(sectoff)
+		o1 |= 1 << 31 // scattered bit
+		o1 |= ld.MACHO_ARM_RELOC_SECTDIFF << 24
+		o1 |= 2 << 28 // size = 4
+
+		o2 := uint32(0)
+		o2 |= 1 << 31 // scattered bit
+		o2 |= ld.MACHO_ARM_RELOC_PAIR << 24
+		o2 |= 2 << 28 // size = 4
+
+		ld.Thearch.Lput(o1)
+		ld.Thearch.Lput(uint32(ld.Symaddr(rs)))
+		ld.Thearch.Lput(o2)
+		ld.Thearch.Lput(uint32(ld.Ctxt.Cursym.Value + int64(r.Off)))
+		return 0
+	}
+
 	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)
@@ -480,7 +500,7 @@ func addpltreloc(ctxt *ld.Link, plt *ld.LSym, got *ld.LSym, sym *ld.LSym, typ in
 	r.Type = int32(typ)
 	r.Add = int64(sym.Got) - 8
 
-	plt.Reachable = true
+	plt.Attr |= ld.AttrReachable
 	plt.Size += 4
 	ld.Symgrow(ctxt, plt, plt.Size)
 
@@ -563,7 +583,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) {
 
 func asmb() {
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 
@@ -581,7 +601,7 @@ func asmb() {
 
 	if ld.Segrodata.Filelen > 0 {
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+			fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
 		ld.Bso.Flush()
 
@@ -590,26 +610,18 @@ func asmb() {
 	}
 
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+		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))
 
+	ld.Cseek(int64(ld.Segdwarf.Fileoff))
+	ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.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())
 	}
 
@@ -621,13 +633,13 @@ func asmb() {
 	if ld.Debug['s'] == 0 {
 		// TODO: rationalize
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+			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.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
 			}
 
@@ -643,17 +655,12 @@ func asmb() {
 		default:
 			if ld.Iself {
 				if ld.Debug['v'] != 0 {
-					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+					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()
 				}
@@ -667,7 +674,7 @@ func asmb() {
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
 				for i := 0; int32(i) < ld.Lcsize; i++ {
-					ld.Cput(uint8(sym.P[i]))
+					ld.Cput(sym.P[i])
 				}
 
 				ld.Cflush()
@@ -682,7 +689,7 @@ func asmb() {
 
 	ld.Ctxt.Cursym = nil
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 	ld.Cseek(0)
diff --git a/src/cmd/link/internal/arm/l.go b/src/cmd/link/internal/arm/l.go
index b6de5a0..63b1165 100644
--- a/src/cmd/link/internal/arm/l.go
+++ b/src/cmd/link/internal/arm/l.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -42,7 +42,7 @@ package arm
 //	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.
+//	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
@@ -63,10 +63,9 @@ package arm
 // THE SOFTWARE.
 
 const (
-	thechar   = '5'
 	MaxAlign  = 8 // max data alignment
+	MinAlign  = 1 // min data alignment
 	FuncAlign = 4 // single-instruction alignment
-	MINLC     = 4
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go
index 10eb723..9ea9771 100644
--- a/src/cmd/link/internal/arm/obj.go
+++ b/src/cmd/link/internal/arm/obj.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,6 +32,7 @@ package arm
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,16 +46,11 @@ func Main() {
 }
 
 func linkarchinit() {
-	ld.Thestring = "arm"
-	ld.Thelinkarch = &ld.Linkarm
+	ld.SysArch = sys.ArchARM
 
-	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.Minalign = MinAlign
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
@@ -70,6 +66,9 @@ func linkarchinit() {
 	ld.Thearch.Lput = ld.Lputl
 	ld.Thearch.Wput = ld.Wputl
 	ld.Thearch.Vput = ld.Vputl
+	ld.Thearch.Append16 = ld.Append16l
+	ld.Thearch.Append32 = ld.Append32l
+	ld.Thearch.Append64 = ld.Append64l
 
 	ld.Thearch.Linuxdynld = "/lib/ld-linux.so.3" // 2 for OABI, 3 for EABI
 	ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
@@ -156,7 +155,7 @@ func archinit() {
 		}
 
 	case obj.Hdarwin: /* apple MACH */
-		ld.Debug['w'] = 1 // disable DWARF generataion
+		ld.Debug['w'] = 1 // disable DWARF generation
 		ld.Machoinit()
 		ld.HEADR = ld.INITIAL_MACHO_HEADR
 		if ld.INITTEXT == -1 {
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 0e5a2d0..7832e91 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -48,11 +48,11 @@ func gentext() {
 		// an init function
 		return
 	}
-	addmoduledata.Reachable = true
+	addmoduledata.Attr |= ld.AttrReachable
 	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
 	initfunc.Type = obj.STEXT
-	initfunc.Local = true
-	initfunc.Reachable = true
+	initfunc.Attr |= ld.AttrLocal
+	initfunc.Attr |= ld.AttrReachable
 	o := func(op uint32) {
 		ld.Adduint32(ld.Ctxt, initfunc, op)
 	}
@@ -78,23 +78,14 @@ func gentext() {
 	rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
 	rel.Type = obj.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference
 
-	if ld.Ctxt.Etextp != nil {
-		ld.Ctxt.Etextp.Next = initfunc
-	} else {
-		ld.Ctxt.Textp = initfunc
-	}
-	ld.Ctxt.Etextp = initfunc
+	ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
 	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
-	initarray_entry.Reachable = true
-	initarray_entry.Local = true
+	initarray_entry.Attr |= ld.AttrReachable
+	initarray_entry.Attr |= ld.AttrLocal
 	initarray_entry.Type = obj.SINITARR
 	ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
 }
 
-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")
 }
@@ -162,7 +153,7 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
 	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
+	// see cmd/internal/ld/data.go for details. The workaround 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 {
@@ -258,7 +249,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
 			// (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So
 			// we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp;
 			// add + R_ADDRARM64.
-			if !(r.Sym.Version != 0 || (r.Sym.Type&obj.SHIDDEN != 0) || r.Sym.Local) && r.Sym.Type == obj.STEXT && ld.DynlinkingGo() {
+			if !(r.Sym.Version != 0 || (r.Sym.Type&obj.SHIDDEN != 0) || r.Sym.Attr.Local()) && r.Sym.Type == obj.STEXT && ld.DynlinkingGo() {
 				if o2&0xffc00000 != 0xf9400000 {
 					ld.Ctxt.Diag("R_ARM64_GOTPCREL against unexpected instruction %x", o2)
 				}
@@ -375,7 +366,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
 		}
 		// The TCB is two pointers. This is not documented anywhere, but is
 		// de facto part of the ABI.
-		v := r.Sym.Value + int64(2*ld.Thearch.Ptrsize)
+		v := r.Sym.Value + int64(2*ld.SysArch.PtrSize)
 		if v < 0 || v >= 32678 {
 			ld.Diag("TLS offset out of range %d", v)
 		}
@@ -401,7 +392,7 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
 
 func asmb() {
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 
@@ -419,7 +410,7 @@ func asmb() {
 
 	if ld.Segrodata.Filelen > 0 {
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+			fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
 		ld.Bso.Flush()
 
@@ -428,26 +419,18 @@ func asmb() {
 	}
 
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+		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))
 
+	ld.Cseek(int64(ld.Segdwarf.Fileoff))
+	ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.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())
 	}
 
@@ -459,13 +442,13 @@ func asmb() {
 	if ld.Debug['s'] == 0 {
 		// TODO: rationalize
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+			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.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
 			}
 
@@ -481,17 +464,12 @@ func asmb() {
 		default:
 			if ld.Iself {
 				if ld.Debug['v'] != 0 {
-					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+					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()
 				}
@@ -505,7 +483,7 @@ func asmb() {
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
 				for i := 0; int32(i) < ld.Lcsize; i++ {
-					ld.Cput(uint8(sym.P[i]))
+					ld.Cput(sym.P[i])
 				}
 
 				ld.Cflush()
@@ -520,7 +498,7 @@ func asmb() {
 
 	ld.Ctxt.Cursym = nil
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 	ld.Cseek(0)
diff --git a/src/cmd/link/internal/arm64/l.go b/src/cmd/link/internal/arm64/l.go
index 62703d2..cbee2a3 100644
--- a/src/cmd/link/internal/arm64/l.go
+++ b/src/cmd/link/internal/arm64/l.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -41,7 +41,7 @@ package arm64
 //	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.
+//	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
@@ -62,10 +62,9 @@ package arm64
 // THE SOFTWARE.
 
 const (
-	thechar   = '7'
 	MaxAlign  = 32 // max data alignment
+	MinAlign  = 1  // min data alignment
 	FuncAlign = 8
-	MINLC     = 4
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index ae121c2..86f9ff7 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,6 +32,7 @@ package arm64
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,16 +46,11 @@ func Main() {
 }
 
 func linkarchinit() {
-	ld.Thestring = obj.Getgoarch()
-	ld.Thelinkarch = &ld.Linkarm64
+	ld.SysArch = sys.ArchARM64
 
-	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.Minalign = MinAlign
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
@@ -70,6 +66,9 @@ func linkarchinit() {
 	ld.Thearch.Lput = ld.Lputl
 	ld.Thearch.Wput = ld.Wputl
 	ld.Thearch.Vput = ld.Vputl
+	ld.Thearch.Append16 = ld.Append16l
+	ld.Thearch.Append32 = ld.Append32l
+	ld.Thearch.Append64 = ld.Append64l
 
 	ld.Thearch.Linuxdynld = "/lib/ld-linux-aarch64.so.1"
 
diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go
index bd14a43..80c33ce 100644
--- a/src/cmd/link/internal/ld/ar.go
+++ b/src/cmd/link/internal/ld/ar.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -31,9 +31,11 @@
 package ld
 
 import (
+	"cmd/internal/bio"
 	"cmd/internal/obj"
 	"encoding/binary"
 	"fmt"
+	"io"
 	"os"
 )
 
@@ -57,31 +59,31 @@ type ArHdr struct {
 }
 
 // hostArchive reads an archive file holding host objects and links in
-// required objects.  The general format is the same as a Go archive
+// required objects. The general format is the same as a Go archive
 // file, but it has an armap listing symbols and the objects that
-// define them.  This is used for the compiler support library
+// define them. This is used for the compiler support library
 // libgcc.a.
 func hostArchive(name string) {
-	f, err := obj.Bopenr(name)
+	f, err := bio.Open(name)
 	if err != nil {
 		if os.IsNotExist(err) {
 			// It's OK if we don't have a libgcc file at all.
 			if Debug['v'] != 0 {
-				fmt.Fprintf(&Bso, "skipping libgcc file: %v\n", err)
+				fmt.Fprintf(Bso, "skipping libgcc file: %v\n", err)
 			}
 			return
 		}
 		Exitf("cannot open file %s: %v", name, err)
 	}
-	defer obj.Bterm(f)
+	defer f.Close()
 
-	magbuf := make([]byte, len(ARMAG))
-	if obj.Bread(f, magbuf) != len(magbuf) {
+	var magbuf [len(ARMAG)]byte
+	if _, err := io.ReadFull(f, magbuf[:]); err != nil {
 		Exitf("file %s too short", name)
 	}
 
 	var arhdr ArHdr
-	l := nextar(f, obj.Boffset(f), &arhdr)
+	l := nextar(f, f.Offset(), &arhdr)
 	if l <= 0 {
 		Exitf("%s missing armap", name)
 	}
@@ -97,7 +99,7 @@ func hostArchive(name string) {
 	any := true
 	for any {
 		var load []uint64
-		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+		for _, s := range Ctxt.Allsym {
 			for _, r := range s.R {
 				if r.Sym != nil && r.Sym.Type&obj.SMASK == obj.SXREF {
 					if off := armap[r.Sym.Name]; off != 0 && !loaded[off] {
@@ -117,7 +119,7 @@ func hostArchive(name string) {
 			l = atolwhex(arhdr.size)
 
 			h := ldobj(f, "libgcc", l, pname, name, ArchiveObj)
-			obj.Bseek(f, h.off, 0)
+			f.Seek(h.off, 0)
 			h.ld(f, h.pkg, h.length, h.pn)
 		}
 
@@ -130,16 +132,15 @@ func hostArchive(name string) {
 type archiveMap map[string]uint64
 
 // readArmap reads the archive symbol map.
-func readArmap(filename string, f *obj.Biobuf, arhdr ArHdr) archiveMap {
+func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap {
 	is64 := arhdr.name == "/SYM64/"
 	wordSize := 4
 	if is64 {
 		wordSize = 8
 	}
 
-	l := atolwhex(arhdr.size)
-	contents := make([]byte, l)
-	if obj.Bread(f, contents) != int(l) {
+	contents := make([]byte, atolwhex(arhdr.size))
+	if _, err := io.ReadFull(f, contents); err != nil {
 		Exitf("short read from %s", filename)
 	}
 
diff --git a/src/cmd/link/internal/ld/arch.go b/src/cmd/link/internal/ld/arch.go
deleted file mode 100644
index 2fcfd63..0000000
--- a/src/cmd/link/internal/ld/arch.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2015 The Go Authors.  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,
-}
-
-var Linkmips64 = LinkArch{
-	ByteOrder: binary.BigEndian,
-	Name:      "mips64",
-	Thechar:   '0',
-	Minlc:     4,
-	Ptrsize:   8,
-	Regsize:   8,
-}
-
-var Linkmips64le = LinkArch{
-	ByteOrder: binary.LittleEndian,
-	Name:      "mips64le",
-	Thechar:   '0',
-	Minlc:     4,
-	Ptrsize:   8,
-	Regsize:   8,
-}
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index ca8eabb..57a0dad 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -9,7 +9,7 @@
 //	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.
+//	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
@@ -34,11 +34,14 @@ package ld
 import (
 	"cmd/internal/gcprog"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"os"
+	"sort"
 	"strconv"
 	"strings"
+	"sync"
 )
 
 func Symgrow(ctxt *Link, s *LSym, siz int64) {
@@ -48,8 +51,9 @@ func Symgrow(ctxt *Link, s *LSym, siz int64) {
 	if int64(len(s.P)) >= siz {
 		return
 	}
-	for cap(s.P) < int(siz) {
-		s.P = append(s.P[:len(s.P)], 0)
+	if cap(s.P) < int(siz) {
+		p := make([]byte, 2*(siz+1))
+		s.P = append(p[:0], s.P...)
 	}
 	s.P = s.P[:siz]
 }
@@ -63,7 +67,7 @@ func setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
 	if s.Type == 0 {
 		s.Type = obj.SDATA
 	}
-	s.Reachable = true
+	s.Attr |= AttrReachable
 	if s.Size < off+wid {
 		s.Size = off + wid
 		Symgrow(ctxt, s, s.Size)
@@ -77,12 +81,23 @@ func setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
 	case 4:
 		ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
 	case 8:
-		ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(v))
+		ctxt.Arch.ByteOrder.PutUint64(s.P[off:], v)
 	}
 
 	return off + wid
 }
 
+func Addbytes(ctxt *Link, s *LSym, bytes []byte) int64 {
+	if s.Type == 0 {
+		s.Type = obj.SDATA
+	}
+	s.Attr |= AttrReachable
+	s.P = append(s.P, bytes...)
+	s.Size = int64(len(s.P))
+
+	return s.Size
+}
+
 func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 {
 	off := s.Size
 	setuintxx(ctxt, s, off, v, int64(wid))
@@ -90,7 +105,15 @@ func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 {
 }
 
 func Adduint8(ctxt *Link, s *LSym, v uint8) int64 {
-	return adduintxx(ctxt, s, uint64(v), 1)
+	off := s.Size
+	if s.Type == 0 {
+		s.Type = obj.SDATA
+	}
+	s.Attr |= AttrReachable
+	s.Size++
+	s.P = append(s.P, v)
+
+	return off
 }
 
 func Adduint16(ctxt *Link, s *LSym, v uint16) int64 {
@@ -106,7 +129,7 @@ func Adduint64(ctxt *Link, s *LSym, v uint64) int64 {
 }
 
 func adduint(ctxt *Link, s *LSym, v uint64) int64 {
-	return adduintxx(ctxt, s, v, Thearch.Intsize)
+	return adduintxx(ctxt, s, v, SysArch.IntSize)
 }
 
 func setuint8(ctxt *Link, s *LSym, r int64, v uint8) int64 {
@@ -121,14 +144,14 @@ func Addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
 	if s.Type == 0 {
 		s.Type = obj.SDATA
 	}
-	s.Reachable = true
+	s.Attr |= AttrReachable
 	i := s.Size
-	s.Size += int64(ctxt.Arch.Ptrsize)
+	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.Siz = uint8(ctxt.Arch.PtrSize)
 	r.Type = obj.R_ADDR
 	r.Add = add
 	return i + int64(r.Siz)
@@ -138,7 +161,7 @@ func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
 	if s.Type == 0 {
 		s.Type = obj.SDATA
 	}
-	s.Reachable = true
+	s.Attr |= AttrReachable
 	i := s.Size
 	s.Size += 4
 	Symgrow(ctxt, s, s.Size)
@@ -148,6 +171,9 @@ func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
 	r.Add = add
 	r.Type = obj.R_PCREL
 	r.Siz = 4
+	if SysArch.Family == sys.S390X {
+		r.Variant = RV_390_DBL
+	}
 	return i + int64(r.Siz)
 }
 
@@ -159,16 +185,16 @@ 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)
+	s.Attr |= AttrReachable
+	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.Siz = uint8(ctxt.Arch.PtrSize)
 	r.Type = obj.R_ADDR
 	r.Add = add
 	return off + int64(r.Siz)
@@ -182,14 +208,14 @@ func addsize(ctxt *Link, s *LSym, t *LSym) int64 {
 	if s.Type == 0 {
 		s.Type = obj.SDATA
 	}
-	s.Reachable = true
+	s.Attr |= AttrReachable
 	i := s.Size
-	s.Size += int64(ctxt.Arch.Ptrsize)
+	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.Siz = uint8(ctxt.Arch.PtrSize)
 	r.Type = obj.R_SIZE
 	return i + int64(r.Siz)
 }
@@ -198,7 +224,7 @@ func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
 	if s.Type == 0 {
 		s.Type = obj.SDATA
 	}
-	s.Reachable = true
+	s.Attr |= AttrReachable
 	i := s.Size
 	s.Size += 4
 	Symgrow(ctxt, s, s.Size)
@@ -216,28 +242,6 @@ func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
  * 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
@@ -356,14 +360,25 @@ func relocsym(s *LSym) {
 		// 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() {
-			if !(Thearch.Thechar == '9' && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") {
+			if !(SysArch.Family == sys.PPC64 && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") {
 				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 {
+		if r.Sym != nil && r.Sym.Type != obj.STLSBSS && !r.Sym.Attr.Reachable() {
 			Diag("unreachable sym in relocation: %s %s", s.Name, r.Sym.Name)
 		}
 
+		// TODO(mundaym): remove this special case - see issue 14218.
+		if SysArch.Family == sys.S390X {
+			switch r.Type {
+			case obj.R_PCRELDBL:
+				r.Type = obj.R_PCREL
+				r.Variant = RV_390_DBL
+			case obj.R_CALL:
+				r.Variant = RV_390_DBL
+			}
+		}
+
 		switch r.Type {
 		default:
 			switch siz {
@@ -383,7 +398,7 @@ func relocsym(s *LSym) {
 			}
 
 		case obj.R_TLS_LE:
-			isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
+			isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
 
 			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
 				r.Done = 0
@@ -393,13 +408,13 @@ func relocsym(s *LSym) {
 				r.Xsym = r.Sym
 				r.Xadd = r.Add
 				o = 0
-				if Thearch.Thechar != '6' {
+				if SysArch.Family != sys.AMD64 {
 					o = r.Add
 				}
 				break
 			}
 
-			if Iself && Thearch.Thechar == '5' {
+			if Iself && SysArch.Family == sys.ARM {
 				// 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).
@@ -417,7 +432,7 @@ func relocsym(s *LSym) {
 			}
 
 		case obj.R_TLS_IE:
-			isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
+			isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
 
 			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
 				r.Done = 0
@@ -427,7 +442,7 @@ func relocsym(s *LSym) {
 				r.Xsym = r.Sym
 				r.Xadd = r.Add
 				o = 0
-				if Thearch.Thechar != '6' {
+				if SysArch.Family != sys.AMD64 {
 					o = r.Add
 				}
 				break
@@ -454,7 +469,7 @@ func relocsym(s *LSym) {
 
 				o = r.Xadd
 				if Iself {
-					if Thearch.Thechar == '6' {
+					if SysArch.Family == sys.AMD64 {
 						o = 0
 					}
 				} else if HEADTYPE == obj.Hdarwin {
@@ -464,10 +479,10 @@ func relocsym(s *LSym) {
 					// 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 {
+						if SysArch.Family == sys.ARM64 && rs.Dynid < 0 {
 							Diag("R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o)
 						}
-						if Thearch.Thechar != '7' {
+						if SysArch.Family != sys.ARM64 {
 							o += Symaddr(rs)
 						}
 					}
@@ -487,11 +502,33 @@ func relocsym(s *LSym) {
 			// 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 {
+			if int32(o) < 0 && SysArch.PtrSize > 4 && siz == 4 {
 				Diag("non-pc-relative relocation address is too big: %#x (%#x + %#x)", uint64(o), Symaddr(r.Sym), r.Add)
 				errorexit()
 			}
 
+		case obj.R_DWARFREF:
+			if r.Sym.Sect == nil {
+				Diag("missing DWARF section: %s from %s", r.Sym.Name, s.Name)
+			}
+			if Linkmode == LinkExternal {
+				r.Done = 0
+				r.Type = obj.R_ADDR
+
+				r.Xsym = Linkrlookup(Ctxt, r.Sym.Sect.Name, 0)
+				r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
+				o = r.Xadd
+				rs = r.Xsym
+				if Iself && SysArch.Family == sys.AMD64 {
+					o = 0
+				}
+				break
+			}
+			o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
+
+		case obj.R_ADDROFF:
+			o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
+
 			// 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) {
@@ -514,7 +551,7 @@ func relocsym(s *LSym) {
 
 				o = r.Xadd
 				if Iself {
-					if Thearch.Thechar == '6' {
+					if SysArch.Family == sys.AMD64 {
 						o = 0
 					}
 				} else if HEADTYPE == obj.Hdarwin {
@@ -523,10 +560,13 @@ func relocsym(s *LSym) {
 							o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr)
 						}
 						o -= int64(r.Off) // relative to section offset, not symbol
+					} else if SysArch.Family == sys.ARM {
+						// see ../arm/asm.go:/machoreloc1
+						o += Symaddr(rs) - int64(Ctxt.Cursym.Value) - int64(r.Off)
 					} else {
 						o += int64(r.Siz)
 					}
-				} else if HEADTYPE == obj.Hwindows && Thearch.Thechar == '6' { // only amd64 needs PCREL
+				} else if HEADTYPE == obj.Hwindows && SysArch.Family == sys.AMD64 { // 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)
@@ -607,14 +647,17 @@ func relocsym(s *LSym) {
 
 func reloc() {
 	if Debug['v'] != 0 {
-		fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
+		fmt.Fprintf(Bso, "%5.2f reloc\n", obj.Cputime())
 	}
 	Bso.Flush()
 
-	for s := Ctxt.Textp; s != nil; s = s.Next {
+	for _, s := range Ctxt.Textp {
 		relocsym(s)
 	}
-	for s := datap; s != nil; s = s.Next {
+	for _, sym := range datap {
+		relocsym(sym)
+	}
+	for s := dwarfp; s != nil; s = s.Next {
 		relocsym(s)
 	}
 }
@@ -625,15 +668,13 @@ func dynrelocsym(s *LSym) {
 		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
+			r := &s.R[ri]
+			targ := r.Sym
 			if targ == nil {
 				continue
 			}
-			if !targ.Reachable {
+			if !targ.Attr.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.
@@ -642,7 +683,7 @@ func dynrelocsym(s *LSym) {
 				r.Add = int64(targ.Plt)
 
 				// jmp *addr
-				if Thearch.Thechar == '8' {
+				if SysArch.Family == sys.I386 {
 					Adduint8(Ctxt, rel, 0xff)
 					Adduint8(Ctxt, rel, 0x25)
 					Addaddr(Ctxt, rel, targ)
@@ -664,11 +705,10 @@ func dynrelocsym(s *LSym) {
 		return
 	}
 
-	var r *Reloc
 	for ri := 0; ri < len(s.R); ri++ {
-		r = &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 {
+			if r.Sym != nil && !r.Sym.Attr.Reachable() {
 				Diag("internal inconsistency: dynamic symbol %s is not reachable.", r.Sym.Name)
 			}
 			Thearch.Adddynrel(s, r)
@@ -676,22 +716,24 @@ func dynrelocsym(s *LSym) {
 	}
 }
 
-func dynreloc() {
+func dynreloc(data *[obj.SXREF][]*LSym) {
 	// -d suppresses dynamic loader format, so we may as well not
 	// compute these sections or mark their symbols as reachable.
 	if Debug['d'] != 0 && HEADTYPE != obj.Hwindows {
 		return
 	}
 	if Debug['v'] != 0 {
-		fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
+		fmt.Fprintf(Bso, "%5.2f reloc\n", obj.Cputime())
 	}
 	Bso.Flush()
 
-	for s := Ctxt.Textp; s != nil; s = s.Next {
+	for _, s := range Ctxt.Textp {
 		dynrelocsym(s)
 	}
-	for s := datap; s != nil; s = s.Next {
-		dynrelocsym(s)
+	for _, syms := range data {
+		for _, sym := range syms {
+			dynrelocsym(sym)
+		}
 	}
 	if Iself {
 		elfdynhash()
@@ -708,8 +750,6 @@ func blk(start *LSym, addr int64, size int64) {
 	}
 
 	eaddr := addr + size
-	var ep []byte
-	var p []byte
 	for ; sym != nil; sym = sym.Next {
 		if sym.Type&obj.SSUB != 0 {
 			continue
@@ -719,25 +759,22 @@ func blk(start *LSym, addr int64, size int64) {
 		}
 		Ctxt.Cursym = sym
 		if sym.Value < addr {
-			Diag("phase error: addr=%#x but sym=%#x type=%d", int64(addr), int64(sym.Value), sym.Type)
+			Diag("phase error: addr=%#x but sym=%#x type=%d", addr, 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:]
+		if addr < sym.Value {
+			strnput("", int(sym.Value-addr))
+			addr = sym.Value
 		}
+		Cwrite(sym.P)
 		addr += int64(len(sym.P))
-		for ; addr < sym.Value+sym.Size; addr++ {
-			Cput(0)
+		if addr < sym.Value+sym.Size {
+			strnput("", int(sym.Value+sym.Size-addr))
+			addr = sym.Value + sym.Size
 		}
 		if addr != sym.Value+sym.Size {
-			Diag("phase error: addr=%#x value+size=%#x", int64(addr), int64(sym.Value)+sym.Size)
+			Diag("phase error: addr=%#x value+size=%#x", addr, sym.Value+sym.Size)
 			errorexit()
 		}
 
@@ -746,38 +783,42 @@ func blk(start *LSym, addr int64, size int64) {
 		}
 	}
 
-	for ; addr < eaddr; addr++ {
-		Cput(0)
+	if addr < eaddr {
+		strnput("", int(eaddr-addr))
 	}
 	Cflush()
 }
 
 func Codeblk(addr int64, size int64) {
+	CodeblkPad(addr, size, zeros[:])
+}
+func CodeblkPad(addr int64, size int64, pad []byte) {
 	if Debug['a'] != 0 {
-		fmt.Fprintf(&Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+		fmt.Fprintf(Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
 	}
 
-	blk(Ctxt.Textp, addr, size)
+	blkSlice(Ctxt.Textp, addr, size, pad)
 
 	/* again for printing */
 	if Debug['a'] == 0 {
 		return
 	}
 
-	var sym *LSym
-	for sym = Ctxt.Textp; sym != nil; sym = sym.Next {
-		if !sym.Reachable {
+	syms := Ctxt.Textp
+	for i, sym := range syms {
+		if !sym.Attr.Reachable() {
 			continue
 		}
 		if sym.Value >= addr {
+			syms = syms[i:]
 			break
 		}
 	}
 
 	eaddr := addr + size
 	var q []byte
-	for ; sym != nil; sym = sym.Next {
-		if !sym.Reachable {
+	for _, sym := range syms {
+		if !sym.Attr.Reachable() {
 			continue
 		}
 		if sym.Value >= eaddr {
@@ -785,129 +826,190 @@ func Codeblk(addr int64, size int64) {
 		}
 
 		if addr < sym.Value {
-			fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr)))
+			fmt.Fprintf(Bso, "%-20s %.8x|", "_", uint64(addr))
 			for ; addr < sym.Value; addr++ {
-				fmt.Fprintf(&Bso, " %.2x", 0)
+				fmt.Fprintf(Bso, " %.2x", 0)
 			}
-			fmt.Fprintf(&Bso, "\n")
+			fmt.Fprintf(Bso, "\n")
 		}
 
-		fmt.Fprintf(&Bso, "%.6x\t%-20s\n", uint64(int64(addr)), sym.Name)
+		fmt.Fprintf(Bso, "%.6x\t%-20s\n", uint64(addr), sym.Name)
 		q = sym.P
 
 		for len(q) >= 16 {
-			fmt.Fprintf(&Bso, "%.6x\t% x\n", uint64(addr), 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)
+			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)))
+		fmt.Fprintf(Bso, "%-20s %.8x|", "_", uint64(addr))
 		for ; addr < eaddr; addr++ {
-			fmt.Fprintf(&Bso, " %.2x", 0)
+			fmt.Fprintf(Bso, " %.2x", 0)
 		}
 	}
 
 	Bso.Flush()
 }
 
+// blkSlice is a variant of blk that processes slices.
+// After text symbols are converted from a linked list to a slice,
+// delete blk and give this function its name.
+func blkSlice(syms []*LSym, addr, size int64, pad []byte) {
+	for i, s := range syms {
+		if s.Type&obj.SSUB == 0 && s.Value >= addr {
+			syms = syms[i:]
+			break
+		}
+	}
+
+	eaddr := addr + size
+	for _, s := range syms {
+		if s.Type&obj.SSUB != 0 {
+			continue
+		}
+		if s.Value >= eaddr {
+			break
+		}
+		Ctxt.Cursym = s
+		if s.Value < addr {
+			Diag("phase error: addr=%#x but sym=%#x type=%d", addr, s.Value, s.Type)
+			errorexit()
+		}
+		if addr < s.Value {
+			strnputPad("", int(s.Value-addr), pad)
+			addr = s.Value
+		}
+		Cwrite(s.P)
+		addr += int64(len(s.P))
+		if addr < s.Value+s.Size {
+			strnputPad("", int(s.Value+s.Size-addr), pad)
+			addr = s.Value + s.Size
+		}
+		if addr != s.Value+s.Size {
+			Diag("phase error: addr=%#x value+size=%#x", addr, s.Value+s.Size)
+			errorexit()
+		}
+		if s.Value+s.Size >= eaddr {
+			break
+		}
+	}
+
+	if addr < eaddr {
+		strnputPad("", int(eaddr-addr), pad)
+	}
+	Cflush()
+}
+
 func Datblk(addr int64, size int64) {
 	if Debug['a'] != 0 {
-		fmt.Fprintf(&Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+		fmt.Fprintf(Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
 	}
 
-	blk(datap, addr, size)
+	blkSlice(datap, addr, size, zeros[:])
 
 	/* again for printing */
 	if Debug['a'] == 0 {
 		return
 	}
 
-	var sym *LSym
-	for sym = datap; sym != nil; sym = sym.Next {
+	syms := datap
+	for i, sym := range syms {
 		if sym.Value >= addr {
+			syms = syms[i:]
 			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 {
+	for _, sym := range syms {
 		if sym.Value >= eaddr {
 			break
 		}
 		if addr < sym.Value {
-			fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint64(addr))
+			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, "%s\n\t%.8x|", sym.Name, uint64(addr))
+		for i, b := range sym.P {
+			if i > 0 && i%16 == 0 {
+				fmt.Fprintf(Bso, "\n\t%.8x|", uint64(addr)+uint64(i))
 			}
-			fmt.Fprintf(&Bso, " %.2x", p[0])
-			p = p[1:]
+			fmt.Fprintf(Bso, " %.2x", b)
 		}
 
 		addr += int64(len(sym.P))
 		for ; addr < sym.Value+sym.Size; addr++ {
-			fmt.Fprintf(&Bso, " %.2x", 0)
+			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, "\n")
 
-				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 Linkmode != LinkExternal {
+			continue
+		}
+		for _, r := range sym.R {
+			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, r.Add, r.Sym.Value+r.Add)
 		}
 	}
 
 	if addr < eaddr {
-		fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint(addr))
+		fmt.Fprintf(Bso, "\t%.8x| 00 ...\n", uint(addr))
 	}
-	fmt.Fprintf(&Bso, "\t%.8x|\n", uint(eaddr))
+	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--
+func Dwarfblk(addr int64, size int64) {
+	if Debug['a'] != 0 {
+		fmt.Fprintf(Bso, "dwarfblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
 	}
 
-	for n > 0 {
-		Cput(0)
-		n--
+	blk(dwarfp, addr, size)
+}
+
+var zeros [512]byte
+
+// strnput writes the first n bytes of s.
+// If n is larger than len(s),
+// it is padded with NUL bytes.
+func strnput(s string, n int) {
+	strnputPad(s, n, zeros[:])
+}
+
+// strnput writes the first n bytes of s.
+// If n is larger than len(s),
+// it is padded with the bytes in pad (repeated as needed).
+func strnputPad(s string, n int, pad []byte) {
+	if len(s) >= n {
+		Cwritestring(s[:n])
+	} else {
+		Cwritestring(s)
+		n -= len(s)
+		for n > len(pad) {
+			Cwrite(pad)
+			n -= len(pad)
+
+		}
+		Cwrite(pad[:n])
 	}
 }
 
@@ -930,19 +1032,19 @@ func addstrdata(name string, value string) {
 
 	s := Linklookup(Ctxt, name, 0)
 	s.Size = 0
-	s.Dupok = 1
-	reachable := s.Reachable
+	s.Attr |= AttrDuplicateOK
+	reachable := s.Attr.Reachable()
 	Addaddr(Ctxt, s, sp)
-	adduintxx(Ctxt, s, uint64(len(value)), Thearch.Ptrsize)
+	adduintxx(Ctxt, s, uint64(len(value)), SysArch.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
+	s.Attr.Set(AttrReachable, reachable)
 
 	strdata = append(strdata, s)
 
-	sp.Reachable = reachable
+	sp.Attr.Set(AttrReachable, reachable)
 }
 
 func checkstrdata() {
@@ -959,17 +1061,15 @@ 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
+	s.Attr |= AttrReachable
+	r := s.Size
 	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)
+	s.P = append(s.P, str...)
+	s.P = append(s.P, 0)
+	s.Size = int64(len(s.P))
+	return r
 }
 
 // addgostring adds str, as a Go string value, to s. symname is the name of the
@@ -979,8 +1079,8 @@ func addgostring(s *LSym, symname, str string) {
 	if sym.Type != obj.Sxxx {
 		Diag("duplicate symname in addgostring: %s", symname)
 	}
-	sym.Reachable = true
-	sym.Local = true
+	sym.Attr |= AttrReachable
+	sym.Attr |= AttrLocal
 	sym.Type = obj.SRODATA
 	sym.Size = int64(len(str))
 	sym.P = []byte(str)
@@ -993,12 +1093,12 @@ func addinitarrdata(s *LSym) {
 	sp := Linklookup(Ctxt, p, 0)
 	sp.Type = obj.SINITARR
 	sp.Size = 0
-	sp.Dupok = 1
+	sp.Attr |= AttrDuplicateOK
 	Addaddr(Ctxt, sp, s)
 }
 
 func dosymtype() {
-	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+	for _, s := range Ctxt.Allsym {
 		if len(s.P) > 0 {
 			if s.Type == obj.SBSS {
 				s.Type = obj.SDATA
@@ -1018,18 +1118,23 @@ func dosymtype() {
 	}
 }
 
+// symalign returns the required alignment for the given symbol s.
 func symalign(s *LSym) int32 {
-	if s.Align != 0 {
+	min := int32(Thearch.Minalign)
+	if s.Align >= min {
 		return s.Align
+	} else if s.Align != 0 {
+		return min
+	}
+	if (strings.HasPrefix(s.Name, "go.string.") && !strings.HasPrefix(s.Name, "go.string.hdr.")) || strings.HasPrefix(s.Name, "type..namedata.") {
+		// String data is just bytes.
+		// If we align it, we waste a lot of space to padding.
+		return min
 	}
-
 	align := int32(Thearch.Maxalign)
-	for int64(align) > s.Size && align > 1 {
+	for int64(align) > s.Size && align > min {
 		align >>= 1
 	}
-	if align < s.Align {
-		align = s.Align
-	}
 	return align
 }
 
@@ -1037,22 +1142,6 @@ 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 {
@@ -1074,7 +1163,7 @@ func (p *GCProg) writeByte(x byte) {
 }
 
 func (p *GCProg) End(size int64) {
-	p.w.ZeroUntil(size / int64(Thearch.Ptrsize))
+	p.w.ZeroUntil(size / int64(SysArch.PtrSize))
 	p.w.End()
 	if debugGCProg {
 		fmt.Fprintf(os.Stderr, "ld: end GCProg\n")
@@ -1090,7 +1179,7 @@ func (p *GCProg) AddSym(s *LSym) {
 		return
 	}
 
-	ptrsize := int64(Thearch.Ptrsize)
+	ptrsize := int64(SysArch.PtrSize)
 	nptr := decodetype_ptrdata(typ) / ptrsize
 
 	if debugGCProg {
@@ -1114,173 +1203,170 @@ func (p *GCProg) AddSym(s *LSym) {
 	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
+// dataSortKey is used to sort a slice of data symbol *LSym pointers.
+// The sort keys are kept inline to improve cache behaviour while sorting.
+type dataSortKey struct {
+	size int64
+	name string
+	lsym *LSym
 }
 
-func dodata() {
-	if Debug['v'] != 0 {
-		fmt.Fprintf(&Bso, "%5.2f dodata\n", obj.Cputime())
+type bySizeAndName []dataSortKey
+
+func (d bySizeAndName) Len() int      { return len(d) }
+func (d bySizeAndName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
+func (d bySizeAndName) Less(i, j int) bool {
+	s1, s2 := d[i], d[j]
+	if s1.size != s2.size {
+		return s1.size < s2.size
 	}
-	Bso.Flush()
+	return s1.name < s2.name
+}
 
-	var last *LSym
-	datap = nil
+const cutoff int64 = 2e9 // 2 GB (or so; looks better in errors than 2^31)
 
-	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
-		}
+func checkdatsize(datsize int64, symn int) {
+	if datsize > cutoff {
+		Diag("too much data in section %v (over %d bytes)", symn, cutoff)
 	}
+}
 
-	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))
-		}
+func list2slice(s *LSym) []*LSym {
+	var syms []*LSym
+	for ; s != nil; s = s.Next {
+		syms = append(syms, s)
 	}
+	return syms
+}
 
-	/*
-	 * 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()
+// datap is a collection of reachable data symbols in address order.
+// Generated by dodata.
+var datap []*LSym
+
+func dodata() {
+	if Debug['v'] != 0 {
+		fmt.Fprintf(Bso, "%5.2f dodata\n", obj.Cputime())
 	}
-	dynreloc()
+	Bso.Flush()
 
-	/* 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
+	// Collect data symbols by type into data.
+	var data [obj.SXREF][]*LSym
+	for _, s := range Ctxt.Allsym {
+		if !s.Attr.Reachable() || s.Attr.Special() {
+			continue
 		}
-
-		if s.Type <= obj.STEXT || obj.SXREF <= s.Type {
-			*l = s.Next
-		} else {
-			l = &s.Next
+		if s.Type <= obj.STEXT || s.Type >= obj.SXREF {
+			continue
 		}
+		data[s.Type] = append(data[s.Type], s)
 	}
 
-	*l = nil
+	// Now that we have the data symbols, 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(&data)
 
 	if UseRelro() {
 		// "read only" data with relocations needs to go in its own section
 		// when building a shared library. We do this by boosting objects of
 		// type SXXX with relocations to type SXXXRELRO.
-		for s := datap; s != nil; s = s.Next {
-			if (s.Type >= obj.STYPE && s.Type <= obj.SFUNCTAB && len(s.R) > 0) || s.Type == obj.SGOSTRING {
-				s.Type += (obj.STYPERELRO - obj.STYPE)
-				if s.Outer != nil {
-					s.Outer.Type = s.Type
+		for symnro := int16(obj.STYPE); symnro < obj.STYPERELRO; symnro++ {
+			symnrelro := symnro + obj.STYPERELRO - obj.STYPE
+
+			ro := []*LSym{}
+			relro := data[symnrelro]
+
+			for _, s := range data[symnro] {
+				isRelro := len(s.R) > 0
+				switch s.Type {
+				case obj.STYPE, obj.SGOSTRINGHDR, obj.STYPERELRO, obj.SGOSTRINGHDRRELRO:
+					// Symbols are not sorted yet, so it is possible
+					// that an Outer symbol has been changed to a
+					// relro Type before it reaches here.
+					isRelro = true
+				}
+				if isRelro {
+					s.Type = symnrelro
+					if s.Outer != nil {
+						s.Outer.Type = s.Type
+					}
+					relro = append(relro, s)
+				} else {
+					ro = append(ro, s)
 				}
 			}
-		}
-		// Check that we haven't made two symbols with the same .Outer into
-		// different types (because references two symbols with non-nil Outer
-		// become references to the outer symbol + offset it's vital that the
-		// symbol and the outer end up in the same section).
-		for s := datap; s != nil; s = s.Next {
-			if s.Outer != nil && s.Outer.Type != s.Type {
-				Diag("inconsistent types for %s and its Outer %s (%d != %d)",
-					s.Name, s.Outer.Name, s.Type, s.Outer.Type)
-			}
-		}
-
-	}
-
-	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
+			// Check that we haven't made two symbols with the same .Outer into
+			// different types (because references two symbols with non-nil Outer
+			// become references to the outer symbol + offset it's vital that the
+			// symbol and the outer end up in the same section).
+			for _, s := range relro {
+				if s.Outer != nil && s.Outer.Type != s.Type {
+					Diag("inconsistent types for %s and its Outer %s (%d != %d)",
+						s.Name, s.Outer.Name, s.Type, s.Outer.Type)
 				}
 			}
+
+			data[symnro] = ro
+			data[symnrelro] = relro
 		}
 	}
 
-	/*
-	 * 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 {
+	// Sort symbols.
+	var dataMaxAlign [obj.SXREF]int32
+	var wg sync.WaitGroup
+	for symn := range data {
+		symn := symn
+		wg.Add(1)
+		go func() {
+			data[symn], dataMaxAlign[symn] = dodataSect(symn, data[symn])
+			wg.Done()
+		}()
 	}
+	wg.Wait()
 
-	/* writable ELF sections */
+	// Allocate sections.
+	// Data is processed before segtext, because we need
+	// to see all symbols in the .data and .bss sections in order
+	// to generate garbage collection information.
 	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
+	// Writable sections.
+	writableSects := []int{
+		obj.SELFSECT,
+		obj.SMACHO,
+		obj.SMACHOGOT,
+		obj.SWINDOWS,
+	}
+	for _, symn := range writableSects {
+		for _, s := range data[symn] {
+			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)
+			datsize += s.Size
+			sect.Length = uint64(datsize) - sect.Vaddr
+		}
+		checkdatsize(datsize, symn)
 	}
 
-	/* .got (and .toc on ppc64) */
-	if s.Type == obj.SELFGOT {
+	// .got (and .toc on ppc64)
+	if len(data[obj.SELFGOT]) > 0 {
 		sect := addsection(&Segdata, ".got", 06)
-		sect.Align = maxalign(s, obj.SELFGOT)
+		sect.Align = dataMaxAlign[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 {
+		for _, s := range data[obj.SELFGOT] {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
 			s.Type = obj.SDATA
@@ -1288,7 +1374,6 @@ func dodata() {
 
 			// Resolve .TOC. symbol for this object file (ppc64)
 			toc = Linkrlookup(Ctxt, ".TOC.", int(s.Version))
-
 			if toc != nil {
 				toc.Sect = sect
 				toc.Outer = s
@@ -1298,28 +1383,27 @@ func dodata() {
 				toc.Value = 0x8000
 			}
 
-			growdatsize(&datsize, s)
+			datsize += s.Size
 		}
-
+		checkdatsize(datsize, obj.SELFGOT)
 		sect.Length = uint64(datsize) - sect.Vaddr
 	}
 
 	/* pointer-free data */
-	sect = addsection(&Segdata, ".noptrdata", 06)
-
-	sect.Align = maxalign(s, obj.SINITARR-1)
+	sect := addsection(&Segdata, ".noptrdata", 06)
+	sect.Align = dataMaxAlign[obj.SNOPTRDATA]
 	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 {
+	for _, s := range data[obj.SNOPTRDATA] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
 		s.Type = obj.SDATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
-		growdatsize(&datsize, s)
+		datsize += s.Size
 	}
-
+	checkdatsize(datsize, obj.SNOPTRDATA)
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	hasinitarr := Linkshared
@@ -1329,116 +1413,102 @@ func dodata() {
 	case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared:
 		hasinitarr = true
 	}
-
 	if hasinitarr {
 		sect := addsection(&Segdata, ".init_array", 06)
-		sect.Align = maxalign(s, obj.SINITARR)
+		sect.Align = dataMaxAlign[obj.SINITARR]
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
-		for ; s != nil && s.Type == obj.SINITARR; s = s.Next {
+		for _, s := range data[obj.SINITARR] {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
 			s.Value = int64(uint64(datsize) - sect.Vaddr)
-			growdatsize(&datsize, s)
+			datsize += s.Size
 		}
-
 		sect.Length = uint64(datsize) - sect.Vaddr
+		checkdatsize(datsize, obj.SINITARR)
 	}
 
 	/* data */
 	sect = addsection(&Segdata, ".data", 06)
-	sect.Align = maxalign(s, obj.SBSS-1)
+	sect.Align = dataMaxAlign[obj.SDATA]
 	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)
-		}
-
+	for _, s := range data[obj.SDATA] {
 		s.Sect = sect
 		s.Type = obj.SDATA
 		datsize = aligndatsize(datsize, s)
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		gc.AddSym(s)
-		growdatsize(&datsize, s)
+		datsize += s.Size
 	}
+	checkdatsize(datsize, obj.SDATA)
 	sect.Length = uint64(datsize) - sect.Vaddr
 	gc.End(int64(sect.Length))
 
 	/* bss */
 	sect = addsection(&Segdata, ".bss", 06)
-	sect.Align = maxalign(s, obj.SNOPTRBSS-1)
+	sect.Align = dataMaxAlign[obj.SBSS]
 	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 {
+	for _, s := range data[obj.SBSS] {
 		s.Sect = sect
 		datsize = aligndatsize(datsize, s)
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
 		gc.AddSym(s)
-		growdatsize(&datsize, s)
+		datsize += s.Size
 	}
+	checkdatsize(datsize, obj.SBSS)
 	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)
+	sect.Align = dataMaxAlign[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 {
+	for _, s := range data[obj.SNOPTRBSS] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
-		growdatsize(&datsize, s)
+		datsize += s.Size
 	}
 
 	sect.Length = uint64(datsize) - sect.Vaddr
 	Linklookup(Ctxt, "runtime.end", 0).Sect = sect
+	checkdatsize(datsize, obj.SNOPTRBSS)
 
-	// 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 s != nil && s.Type == obj.STLSBSS {
+	if len(data[obj.STLSBSS]) > 0 {
+		var sect *Section
 		if Iself && (Linkmode == LinkExternal || Debug['d'] == 0) && HEADTYPE != obj.Hopenbsd {
 			sect = addsection(&Segdata, ".tbss", 06)
-			sect.Align = int32(Thearch.Ptrsize)
+			sect.Align = int32(SysArch.PtrSize)
 			sect.Vaddr = 0
-		} else {
-			sect = nil
 		}
 		datsize = 0
 
-		for ; s != nil && s.Type == obj.STLSBSS; s = s.Next {
+		for _, s := range data[obj.STLSBSS] {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
 			s.Value = datsize
-			growdatsize(&datsize, s)
+			datsize += s.Size
 		}
+		checkdatsize(datsize, obj.STLSBSS)
 
 		if sect != nil {
 			sect.Length = uint64(datsize)
 		}
 	}
 
-	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.
@@ -1456,39 +1526,62 @@ func dodata() {
 		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)
+	if len(data[obj.STEXT]) != 0 {
+		Diag("dodata found an STEXT symbol: %s", data[obj.STEXT][0].Name)
+	}
+	for _, s := range data[obj.SELFRXSECT] {
+		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)
+		datsize += s.Size
 		sect.Length = uint64(datsize) - sect.Vaddr
+		checkdatsize(datsize, obj.SELFRXSECT)
 	}
 
 	/* read-only data */
 	sect = addsection(segro, ".rodata", 04)
 
-	sect.Align = maxalign(s, obj.STYPERELRO-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.STYPERELRO; s = s.Next {
-		datsize = aligndatsize(datsize, s)
-		s.Sect = sect
-		s.Type = obj.SRODATA
-		s.Value = int64(uint64(datsize) - sect.Vaddr)
-		growdatsize(&datsize, s)
+	if !UseRelro() {
+		Linklookup(Ctxt, "runtime.types", 0).Sect = sect
+		Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect
+	}
+	roSects := []int{
+		obj.STYPE,
+		obj.SSTRING,
+		obj.SGOSTRING,
+		obj.SGOSTRINGHDR,
+		obj.SGOFUNC,
+		obj.SGCBITS,
+		obj.SRODATA,
+		obj.SFUNCTAB,
+	}
+	for _, symn := range roSects {
+		align := dataMaxAlign[symn]
+		if sect.Align < align {
+			sect.Align = align
+		}
+	}
+	datsize = Rnd(datsize, int64(sect.Align))
+	for _, symn := range roSects {
+		for _, s := range data[symn] {
+			datsize = aligndatsize(datsize, s)
+			s.Sect = sect
+			s.Type = obj.SRODATA
+			s.Value = int64(uint64(datsize) - sect.Vaddr)
+			datsize += s.Size
+		}
+		checkdatsize(datsize, symn)
 	}
-
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	// There is some data that are conceptually read-only but are written to by
@@ -1510,18 +1603,38 @@ func dodata() {
 		/* data only written by relocations */
 		sect = addsection(segro, ".data.rel.ro", 06)
 
-		sect.Align = maxalign(s, obj.STYPELINK-1)
-		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = 0
-		for ; s != nil && s.Type < obj.STYPELINK; s = s.Next {
-			datsize = aligndatsize(datsize, s)
-			if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
-				Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name)
+		Linklookup(Ctxt, "runtime.types", 0).Sect = sect
+		Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect
+		relroSects := []int{
+			obj.STYPERELRO,
+			obj.SSTRINGRELRO,
+			obj.SGOSTRINGRELRO,
+			obj.SGOSTRINGHDRRELRO,
+			obj.SGOFUNCRELRO,
+			obj.SGCBITSRELRO,
+			obj.SRODATARELRO,
+			obj.SFUNCTABRELRO,
+		}
+		for _, symn := range relroSects {
+			align := dataMaxAlign[symn]
+			if sect.Align < align {
+				sect.Align = align
 			}
-			s.Sect = sect
-			s.Type = obj.SRODATA
-			s.Value = int64(uint64(datsize) - sect.Vaddr)
-			growdatsize(&datsize, s)
+		}
+		datsize = Rnd(datsize, int64(sect.Align))
+		for _, symn := range relroSects {
+			for _, s := range data[symn] {
+				datsize = aligndatsize(datsize, s)
+				if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
+					Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name)
+				}
+				s.Sect = sect
+				s.Type = obj.SRODATA
+				s.Value = int64(uint64(datsize) - sect.Vaddr)
+				datsize += s.Size
+			}
+			checkdatsize(datsize, symn)
 		}
 
 		sect.Length = uint64(datsize) - sect.Vaddr
@@ -1530,60 +1643,87 @@ func dodata() {
 
 	/* typelink */
 	sect = addsection(segro, relro_prefix+".typelink", relro_perms)
-
-	sect.Align = maxalign(s, obj.STYPELINK)
+	sect.Align = dataMaxAlign[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 {
+	for _, s := range data[obj.STYPELINK] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
 		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
-		growdatsize(&datsize, s)
+		datsize += s.Size
 	}
+	checkdatsize(datsize, obj.STYPELINK)
+	sect.Length = uint64(datsize) - sect.Vaddr
 
+	/* itablink */
+	sect = addsection(segro, relro_prefix+".itablink", relro_perms)
+	sect.Align = dataMaxAlign[obj.SITABLINK]
+	datsize = Rnd(datsize, int64(sect.Align))
+	sect.Vaddr = uint64(datsize)
+	Linklookup(Ctxt, "runtime.itablink", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.eitablink", 0).Sect = sect
+	for _, s := range data[obj.SITABLINK] {
+		datsize = aligndatsize(datsize, s)
+		s.Sect = sect
+		s.Type = obj.SRODATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		datsize += s.Size
+	}
+	checkdatsize(datsize, obj.SITABLINK)
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	/* gosymtab */
 	sect = addsection(segro, relro_prefix+".gosymtab", relro_perms)
-
-	sect.Align = maxalign(s, obj.SPCLNTAB-1)
+	sect.Align = dataMaxAlign[obj.SSYMTAB]
 	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 {
+	for _, s := range data[obj.SSYMTAB] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
 		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
-		growdatsize(&datsize, s)
+		datsize += s.Size
 	}
-
+	checkdatsize(datsize, obj.SSYMTAB)
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	/* gopclntab */
 	sect = addsection(segro, relro_prefix+".gopclntab", relro_perms)
-
-	sect.Align = maxalign(s, obj.SELFROSECT-1)
+	sect.Align = dataMaxAlign[obj.SPCLNTAB]
 	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 {
+	for _, s := range data[obj.SPCLNTAB] {
 		datsize = aligndatsize(datsize, s)
 		s.Sect = sect
 		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
-		growdatsize(&datsize, s)
+		datsize += s.Size
 	}
-
+	checkdatsize(datsize, obj.SRODATA)
 	sect.Length = uint64(datsize) - sect.Vaddr
 
 	/* read-only ELF, Mach-O sections */
-	for ; s != nil && s.Type < obj.SELFSECT; s = s.Next {
+	for _, s := range data[obj.SELFROSECT] {
+		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)
+		datsize += s.Size
+		sect.Length = uint64(datsize) - sect.Vaddr
+	}
+	checkdatsize(datsize, obj.SELFROSECT)
+
+	for _, s := range data[obj.SMACHOPLT] {
 		sect = addsection(segro, s.Name, 04)
 		sect.Align = symalign(s)
 		datsize = Rnd(datsize, int64(sect.Align))
@@ -1591,15 +1731,52 @@ func dodata() {
 		s.Sect = sect
 		s.Type = obj.SRODATA
 		s.Value = int64(uint64(datsize) - sect.Vaddr)
-		growdatsize(&datsize, s)
+		datsize += s.Size
 		sect.Length = uint64(datsize) - sect.Vaddr
 	}
+	checkdatsize(datsize, obj.SMACHOPLT)
 
 	// 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")
 	}
 
+	for symn := obj.SELFRXSECT; symn < obj.SXREF; symn++ {
+		datap = append(datap, data[symn]...)
+	}
+
+	dwarfgeneratedebugsyms()
+
+	var s *LSym
+	for s = dwarfp; s != nil && s.Type == obj.SDWARFSECT; s = s.Next {
+		sect = addsection(&Segdwarf, s.Name, 04)
+		sect.Align = 1
+		datsize = Rnd(datsize, int64(sect.Align))
+		sect.Vaddr = uint64(datsize)
+		s.Sect = sect
+		s.Type = obj.SRODATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		datsize += s.Size
+		sect.Length = uint64(datsize) - sect.Vaddr
+	}
+	checkdatsize(datsize, obj.SDWARFSECT)
+
+	if s != nil {
+		sect = addsection(&Segdwarf, ".debug_info", 04)
+		sect.Align = 1
+		datsize = Rnd(datsize, int64(sect.Align))
+		sect.Vaddr = uint64(datsize)
+		for ; s != nil && s.Type == obj.SDWARFINFO; s = s.Next {
+			s.Sect = sect
+			s.Type = obj.SRODATA
+			s.Value = int64(uint64(datsize) - sect.Vaddr)
+			s.Attr |= AttrLocal
+			datsize += s.Size
+		}
+		sect.Length = uint64(datsize) - sect.Vaddr
+		checkdatsize(datsize, obj.SDWARFINFO)
+	}
+
 	/* number the sections */
 	n := int32(1)
 
@@ -1615,6 +1792,97 @@ func dodata() {
 		sect.Extnum = int16(n)
 		n++
 	}
+	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+		sect.Extnum = int16(n)
+		n++
+	}
+}
+
+func dodataSect(symn int, syms []*LSym) (result []*LSym, maxAlign int32) {
+	if HEADTYPE == obj.Hdarwin {
+		// Some symbols may no longer belong in syms
+		// due to movement in machosymorder.
+		newSyms := make([]*LSym, 0, len(syms))
+		for _, s := range syms {
+			if int(s.Type) == symn {
+				newSyms = append(newSyms, s)
+			}
+		}
+		syms = newSyms
+	}
+
+	symsSort := make([]dataSortKey, len(syms))
+	for i, s := range syms {
+		if s.Attr.OnList() {
+			log.Fatalf("symbol %s listed multiple times", s.Name)
+		}
+		s.Attr |= AttrOnList
+		switch {
+		case s.Size < int64(len(s.P)):
+			Diag("%s: initialize bounds (%d < %d)", s.Name, s.Size, len(s.P))
+		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)
+		}
+
+		symsSort[i] = dataSortKey{
+			size: s.Size,
+			name: s.Name,
+			lsym: s,
+		}
+
+		switch s.Type {
+		case obj.SELFGOT:
+			// For ppc64, we want to interleave the .got and .toc sections
+			// from input files. Both are type SELFGOT, so in that case
+			// we skip size comparison and fall through to the name
+			// comparison (conveniently, .got sorts before .toc).
+			symsSort[i].size = 0
+		case obj.STYPELINK:
+			// Sort typelinks by the rtype.string field so the reflect
+			// package can binary search type links.
+			symsSort[i].name = string(decodetype_str(s.R[0].Sym))
+		}
+	}
+
+	sort.Sort(bySizeAndName(symsSort))
+
+	for i, symSort := range symsSort {
+		syms[i] = symSort.lsym
+		align := symalign(symSort.lsym)
+		if maxAlign < align {
+			maxAlign = align
+		}
+	}
+
+	if Iself && symn == obj.SELFROSECT {
+		// Make .rela and .rela.plt contiguous, the ELF ABI requires this
+		// and Solaris actually cares.
+		reli, plti := -1, -1
+		for i, s := range syms {
+			switch s.Name {
+			case ".rel.plt", ".rela.plt":
+				plti = i
+			case ".rel", ".rela":
+				reli = i
+			}
+		}
+		if reli >= 0 && plti >= 0 && plti != reli+1 {
+			var first, second int
+			if plti > reli {
+				first, second = reli, plti
+			} else {
+				first, second = plti, reli
+			}
+			rel, plt := syms[reli], syms[plti]
+			copy(syms[first+2:], syms[first+1:second])
+			syms[first+0] = rel
+			syms[first+1] = plt
+		}
+	}
+
+	return syms, maxAlign
 }
 
 // Add buildid to beginning of text segment, on non-ELF systems.
@@ -1628,7 +1896,7 @@ func textbuildid() {
 	}
 
 	sym := Linklookup(Ctxt, "go.buildid", 0)
-	sym.Reachable = true
+	sym.Attr |= AttrReachable
 	// 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"
@@ -1636,14 +1904,13 @@ func textbuildid() {
 	sym.P = []byte(data)
 	sym.Size = int64(len(sym.P))
 
-	sym.Next = Ctxt.Textp
-	Ctxt.Textp = sym
+	Ctxt.Textp = append(Ctxt.Textp, nil)
+	copy(Ctxt.Textp[1:], Ctxt.Textp)
+	Ctxt.Textp[0] = sym
 }
 
 // assign addresses to text
 func textaddress() {
-	var sub *LSym
-
 	addsection(&Segtext, ".text", 05)
 
 	// Assign PCs in text segment.
@@ -1654,9 +1921,12 @@ func textaddress() {
 	sect.Align = int32(Funcalign)
 	Linklookup(Ctxt, "runtime.text", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.etext", 0).Sect = sect
+	if HEADTYPE == obj.Hwindows {
+		Linklookup(Ctxt, ".text", 0).Sect = sect
+	}
 	va := uint64(INITTEXT)
 	sect.Vaddr = va
-	for sym := Ctxt.Textp; sym != nil; sym = sym.Next {
+	for _, sym := range Ctxt.Textp {
 		sym.Sect = sect
 		if sym.Type&obj.SSUB != 0 {
 			continue
@@ -1667,7 +1937,7 @@ func textaddress() {
 			va = uint64(Rnd(int64(va), int64(Funcalign)))
 		}
 		sym.Value = 0
-		for sub = sym; sub != nil; sub = sub.Sub {
+		for sub := sym; sub != nil; sub = sub.Sub {
 			sub.Value += int64(va)
 		}
 		if sym.Size == 0 && sym.Sub != nil {
@@ -1763,6 +2033,29 @@ func address() {
 
 	Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
 
+	va = uint64(Rnd(int64(va), int64(INITRND)))
+	Segdwarf.Rwx = 06
+	Segdwarf.Vaddr = va
+	Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(INITRND)))
+	Segdwarf.Filelen = 0
+	if HEADTYPE == obj.Hwindows {
+		Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(PEFILEALIGN)))
+	}
+	for s := Segdwarf.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)
+		if HEADTYPE == obj.Hwindows {
+			va = uint64(Rnd(int64(va), PEFILEALIGN))
+		}
+		Segdwarf.Length = va - Segdwarf.Vaddr
+	}
+
+	Segdwarf.Filelen = va - Segdwarf.Vaddr
+
 	text := Segtext.Sect
 	var rodata *Section
 	if Segrodata.Sect != nil {
@@ -1770,22 +2063,34 @@ func address() {
 	} else {
 		rodata = text.Next
 	}
+	var relrodata *Section
 	typelink := rodata.Next
 	if UseRelro() {
 		// There is another section (.data.rel.ro) when building a shared
 		// object on elf systems.
+		relrodata = typelink
 		typelink = typelink.Next
 	}
-	symtab := typelink.Next
+	itablink := typelink.Next
+	symtab := itablink.Next
 	pclntab := symtab.Next
 
-	var sub *LSym
-	for sym := datap; sym != nil; sym = sym.Next {
+	for _, s := range datap {
+		Ctxt.Cursym = s
+		if s.Sect != nil {
+			s.Value += int64(s.Sect.Vaddr)
+		}
+		for sub := s.Sub; sub != nil; sub = sub.Sub {
+			sub.Value += s.Value
+		}
+	}
+
+	for sym := dwarfp; 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 {
+		for sub := sym.Sub; sub != nil; sub = sub.Sub {
 			sub.Value += sym.Value
 		}
 	}
@@ -1797,20 +2102,32 @@ func address() {
 		s.Value = int64(sectSym.Sect.Vaddr + 16)
 	}
 
+	types := relrodata
+	if types == nil {
+		types = rodata
+	}
+
 	xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
 	xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
+	if HEADTYPE == obj.Hwindows {
+		xdefine(".text", obj.STEXT, int64(text.Vaddr))
+	}
 	xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr))
 	xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length))
+	xdefine("runtime.types", obj.SRODATA, int64(types.Vaddr))
+	xdefine("runtime.etypes", obj.SRODATA, int64(types.Vaddr+types.Length))
 	xdefine("runtime.typelink", obj.SRODATA, int64(typelink.Vaddr))
 	xdefine("runtime.etypelink", obj.SRODATA, int64(typelink.Vaddr+typelink.Length))
+	xdefine("runtime.itablink", obj.SRODATA, int64(itablink.Vaddr))
+	xdefine("runtime.eitablink", obj.SRODATA, int64(itablink.Vaddr+itablink.Length))
 
 	sym := Linklookup(Ctxt, "runtime.gcdata", 0)
-	sym.Local = true
+	sym.Attr |= AttrLocal
 	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
+	sym.Attr |= AttrLocal
 	xdefine("runtime.egcbss", obj.SRODATA, Symaddr(sym)+sym.Size)
 	Linklookup(Ctxt, "runtime.egcbss", 0).Sect = sym.Sect
 
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
new file mode 100644
index 0000000..aaed6cd
--- /dev/null
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -0,0 +1,342 @@
+// Copyright 2016 The Go Authors. 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"
+	"cmd/internal/sys"
+	"fmt"
+	"strings"
+	"unicode"
+)
+
+// deadcode marks all reachable symbols.
+//
+// The basis of the dead code elimination is a flood fill of symbols,
+// following their relocations, beginning at INITENTRY.
+//
+// This flood fill is wrapped in logic for pruning unused methods.
+// All methods are mentioned by relocations on their receiver's *rtype.
+// These relocations are specially defined as R_METHODOFF by the compiler
+// so we can detect and manipulated them here.
+//
+// There are three ways a method of a reachable type can be invoked:
+//
+//	1. direct call
+//	2. through a reachable interface type
+//	3. reflect.Value.Call, .Method, or reflect.Method.Func
+//
+// The first case is handled by the flood fill, a directly called method
+// is marked as reachable.
+//
+// The second case is handled by decomposing all reachable interface
+// types into method signatures. Each encountered method is compared
+// against the interface method signatures, if it matches it is marked
+// as reachable. This is extremely conservative, but easy and correct.
+//
+// The third case is handled by looking to see if any of:
+//	- reflect.Value.Call is reachable
+//	- reflect.Value.Method is reachable
+// 	- reflect.Type.Method or MethodByName is called.
+// If any of these happen, all bets are off and all exported methods
+// of reachable types are marked reachable.
+//
+// Any unreached text symbols are removed from ctxt.Textp.
+func deadcode(ctxt *Link) {
+	if Debug['v'] != 0 {
+		fmt.Fprintf(ctxt.Bso, "%5.2f deadcode\n", obj.Cputime())
+	}
+
+	d := &deadcodepass{
+		ctxt:        ctxt,
+		ifaceMethod: make(map[methodsig]bool),
+	}
+
+	// First, flood fill any symbols directly reachable in the call
+	// graph from INITENTRY. Ignore all methods not directly called.
+	d.init()
+	d.flood()
+
+	callSym := Linkrlookup(ctxt, "reflect.Value.Call", 0)
+	methSym := Linkrlookup(ctxt, "reflect.Value.Method", 0)
+	reflectSeen := false
+
+	if DynlinkingGo() {
+		// Exported methods may satisfy interfaces we don't know
+		// about yet when dynamically linking.
+		reflectSeen = true
+	}
+
+	for {
+		if !reflectSeen {
+			if d.reflectMethod || (callSym != nil && callSym.Attr.Reachable()) || (methSym != nil && methSym.Attr.Reachable()) {
+				// Methods might be called via reflection. Give up on
+				// static analysis, mark all exported methods of
+				// all reachable types as reachable.
+				reflectSeen = true
+			}
+		}
+
+		// Mark all methods that could satisfy a discovered
+		// interface as reachable. We recheck old marked interfaces
+		// as new types (with new methods) may have been discovered
+		// in the last pass.
+		var rem []methodref
+		for _, m := range d.markableMethods {
+			if (reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
+				d.markMethod(m)
+			} else {
+				rem = append(rem, m)
+			}
+		}
+		d.markableMethods = rem
+
+		if len(d.markQueue) == 0 {
+			// No new work was discovered. Done.
+			break
+		}
+		d.flood()
+	}
+
+	// Remove all remaining unreached R_METHODOFF relocations.
+	for _, m := range d.markableMethods {
+		for _, r := range m.r {
+			d.cleanupReloc(r)
+		}
+	}
+
+	if Buildmode != BuildmodeShared {
+		// Keep a typelink or itablink if the symbol it points at is being kept.
+		// (When BuildmodeShared, always keep typelinks and itablinks.)
+		for _, s := range ctxt.Allsym {
+			if strings.HasPrefix(s.Name, "go.typelink.") ||
+				strings.HasPrefix(s.Name, "go.itablink.") {
+				s.Attr.Set(AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable())
+			}
+		}
+	}
+
+	// Remove dead text but keep file information (z symbols).
+	textp := make([]*LSym, 0, len(ctxt.Textp))
+	for _, s := range ctxt.Textp {
+		if s.Attr.Reachable() {
+			textp = append(textp, s)
+		}
+	}
+	ctxt.Textp = textp
+}
+
+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",
+}
+
+// methodref holds the relocations from a receiver type symbol to its
+// method. There are three relocations, one for each of the fields in
+// the reflect.method struct: mtyp, ifn, and tfn.
+type methodref struct {
+	m   methodsig
+	src *LSym     // receiver type symbol
+	r   [3]*Reloc // R_METHODOFF relocations to fields of runtime.method
+}
+
+func (m methodref) ifn() *LSym { return m.r[1].Sym }
+
+func (m methodref) isExported() bool {
+	for _, r := range m.m {
+		return unicode.IsUpper(r)
+	}
+	panic("methodref has no signature")
+}
+
+// deadcodepass holds state for the deadcode flood fill.
+type deadcodepass struct {
+	ctxt            *Link
+	markQueue       []*LSym            // symbols to flood fill in next pass
+	ifaceMethod     map[methodsig]bool // methods declared in reached interfaces
+	markableMethods []methodref        // methods of reached types
+	reflectMethod   bool
+}
+
+func (d *deadcodepass) cleanupReloc(r *Reloc) {
+	if r.Sym.Attr.Reachable() {
+		r.Type = obj.R_ADDROFF
+	} else {
+		if Debug['v'] > 1 {
+			fmt.Fprintf(d.ctxt.Bso, "removing method %s\n", r.Sym.Name)
+		}
+		r.Sym = nil
+		r.Siz = 0
+	}
+}
+
+// mark appends a symbol to the mark queue for flood filling.
+func (d *deadcodepass) mark(s, parent *LSym) {
+	if s == nil || s.Attr.Reachable() {
+		return
+	}
+	if s.Attr.ReflectMethod() {
+		d.reflectMethod = true
+	}
+	if flag_dumpdep {
+		p := "_"
+		if parent != nil {
+			p = parent.Name
+		}
+		fmt.Printf("%s -> %s\n", p, s.Name)
+	}
+	s.Attr |= AttrReachable
+	s.Reachparent = parent
+	d.markQueue = append(d.markQueue, s)
+}
+
+// markMethod marks a method as reachable.
+func (d *deadcodepass) markMethod(m methodref) {
+	for _, r := range m.r {
+		d.mark(r.Sym, m.src)
+		r.Type = obj.R_ADDROFF
+	}
+}
+
+// init marks all initial symbols as reachable.
+// In a typical binary, this is INITENTRY.
+func (d *deadcodepass) init() {
+	var names []string
+
+	if SysArch.Family == sys.ARM {
+		// mark some functions that are only referenced after linker code editing
+		if d.ctxt.Goarm == 5 {
+			names = append(names, "_sfloat")
+		}
+		names = append(names, "runtime.read_tls_fallback")
+	}
+
+	if Buildmode == BuildmodeShared {
+		// Mark all symbols defined in this library as reachable when
+		// building a shared library.
+		for _, s := range d.ctxt.Allsym {
+			if s.Type != 0 && s.Type != obj.SDYNIMPORT {
+				d.mark(s, nil)
+			}
+		}
+	} else {
+		// In a normal binary, start at main.main and the init
+		// functions and mark what is reachable from there.
+		names = append(names, INITENTRY)
+		if Linkshared && Buildmode == BuildmodeExe {
+			names = append(names, "main.main", "main.init")
+		}
+		for _, name := range markextra {
+			names = append(names, name)
+		}
+		for _, s := range dynexp {
+			d.mark(s, nil)
+		}
+	}
+
+	for _, name := range names {
+		d.mark(Linkrlookup(d.ctxt, name, 0), nil)
+	}
+}
+
+// flood flood fills symbols reachable from the markQueue symbols.
+// As it goes, it collects methodref and interface method declarations.
+func (d *deadcodepass) flood() {
+	for len(d.markQueue) > 0 {
+		s := d.markQueue[0]
+		d.markQueue = d.markQueue[1:]
+		if s.Type == obj.STEXT {
+			if Debug['v'] > 1 {
+				fmt.Fprintf(d.ctxt.Bso, "marktext %s\n", s.Name)
+			}
+			if s.FuncInfo != nil {
+				for _, a := range s.FuncInfo.Autom {
+					d.mark(a.Gotype, s)
+				}
+			}
+
+		}
+
+		if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' {
+			if decodetype_kind(s)&kindMask == kindInterface {
+				for _, sig := range decodetype_ifacemethods(s) {
+					if Debug['v'] > 1 {
+						fmt.Fprintf(d.ctxt.Bso, "reached iface method: %s\n", sig)
+					}
+					d.ifaceMethod[sig] = true
+				}
+			}
+		}
+
+		mpos := 0 // 0-3, the R_METHODOFF relocs of runtime.uncommontype
+		var methods []methodref
+		for i := 0; i < len(s.R); i++ {
+			r := &s.R[i]
+			if r.Sym == nil {
+				continue
+			}
+			if r.Type != obj.R_METHODOFF {
+				d.mark(r.Sym, s)
+				continue
+			}
+			// Collect rtype pointers to methods for
+			// later processing in deadcode.
+			if mpos == 0 {
+				m := methodref{src: s}
+				m.r[0] = r
+				methods = append(methods, m)
+			} else {
+				methods[len(methods)-1].r[mpos] = r
+			}
+			mpos++
+			if mpos == len(methodref{}.r) {
+				mpos = 0
+			}
+		}
+		if len(methods) > 0 {
+			// Decode runtime type information for type methods
+			// to help work out which methods can be called
+			// dynamically via interfaces.
+			methodsigs := decodetype_methods(s)
+			if len(methods) != len(methodsigs) {
+				panic(fmt.Sprintf("%q has %d method relocations for %d methods", s.Name, len(methods), len(methodsigs)))
+			}
+			for i, m := range methodsigs {
+				name := string(m)
+				name = name[:strings.Index(name, "(")]
+				if !strings.HasSuffix(methods[i].ifn().Name, name) {
+					panic(fmt.Sprintf("%q relocation for %q does not match method %q", s.Name, methods[i].ifn().Name, name))
+				}
+				methods[i].m = m
+			}
+			d.markableMethods = append(d.markableMethods, methods...)
+		}
+
+		if s.FuncInfo != nil {
+			for i := range s.FuncInfo.Funcdata {
+				d.mark(s.FuncInfo.Funcdata[i], s)
+			}
+		}
+		d.mark(s.Gotype, s)
+		d.mark(s.Sub, s)
+		d.mark(s.Outer, s)
+	}
+}
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index 52eb46b..a1eef03 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -5,18 +5,33 @@
 package ld
 
 import (
+	"bytes"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"debug/elf"
+	"fmt"
 )
 
 // 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.
 
+// tflag is documented in reflect/type.go.
+//
+// tflag values must be kept in sync with copies in:
+//	cmd/compile/internal/gc/reflect.go
+//	cmd/link/internal/ld/decodesym.go
+//	reflect/type.go
+//	runtime/type.go
+const (
+	tflagUncommon  = 1 << 0
+	tflagExtraStar = 1 << 1
+)
+
 func decode_reloc(s *LSym, off int32) *Reloc {
-	for i := 0; i < len(s.R); i++ {
+	for i := range s.R {
 		if s.R[i].Off == off {
-			return &s.R[i:][0]
+			return &s.R[i]
 		}
 	}
 	return nil
@@ -44,35 +59,33 @@ func decode_inuxi(p []byte, sz int) uint64 {
 	}
 }
 
-// commonsize returns the size of the common prefix for all type
-// structures (runtime._type).
-func commonsize() int {
-	return 7*Thearch.Ptrsize + 8
-}
+func commonsize() int      { return 4*SysArch.PtrSize + 8 + 8 } // runtime._type
+func structfieldSize() int { return 3 * SysArch.PtrSize }       // runtime.structfield
+func uncommonSize() int    { return 4 + 2 + 2 + 4 + 4 }         // runtime.uncommontype
 
 // 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
+	return s.P[2*SysArch.PtrSize+7] & obj.KindMask //  0x13 / 0x1f
 }
 
 // Type.commonType.kind
 func decodetype_usegcprog(s *LSym) uint8 {
-	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindGCProg) //  0x13 / 0x1f
+	return s.P[2*SysArch.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
+	return int64(decode_inuxi(s.P, SysArch.PtrSize)) // 0x8 / 0x10
 }
 
 // Type.commonType.ptrdata
 func decodetype_ptrdata(s *LSym) int64 {
-	return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10
+	return int64(decode_inuxi(s.P[SysArch.PtrSize:], SysArch.PtrSize)) // 0x8 / 0x10
+}
+
+// Type.commonType.tflag
+func decodetype_hasUncommon(s *LSym) bool {
+	return s.P[2*SysArch.PtrSize+4]&tflagUncommon != 0
 }
 
 // Find the elf.Section of a given shared library that contains a given address.
@@ -106,11 +119,11 @@ func decodetype_gcprog(s *LSym) []byte {
 		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
+	return decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize)).P
 }
 
 func decodetype_gcprog_shlib(s *LSym) uint64 {
-	if Thearch.Thechar == '7' {
+	if SysArch.Family == sys.ARM64 {
 		for _, shlib := range Ctxt.Shlibs {
 			if shlib.Path == s.File {
 				return shlib.gcdata_addresses[s]
@@ -118,7 +131,7 @@ func decodetype_gcprog_shlib(s *LSym) uint64 {
 		}
 		return 0
 	}
-	return decode_inuxi(s.P[2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize)
+	return decode_inuxi(s.P[2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize):], SysArch.PtrSize)
 }
 
 func decodetype_gcmask(s *LSym) []byte {
@@ -127,14 +140,14 @@ func decodetype_gcmask(s *LSym) []byte {
 		ptrdata := decodetype_ptrdata(s)
 		sect := findShlibSection(s.File, addr)
 		if sect != nil {
-			r := make([]byte, ptrdata/int64(Thearch.Ptrsize))
+			r := make([]byte, ptrdata/int64(SysArch.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))
+	mask := decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize))
 	return mask.P
 }
 
@@ -144,7 +157,7 @@ func decodetype_arrayelem(s *LSym) *LSym {
 }
 
 func decodetype_arraylen(s *LSym) int64 {
-	return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Ptrsize))
+	return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.PtrSize))
 }
 
 // Type.PtrType.elem
@@ -158,7 +171,7 @@ func decodetype_mapkey(s *LSym) *LSym {
 }
 
 func decodetype_mapvalue(s *LSym) *LSym {
-	return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)) // 0x20 / 0x38
+	return decode_reloc_sym(s, int32(commonsize())+int32(SysArch.PtrSize)) // 0x20 / 0x38
 }
 
 // Type.ChanType.elem
@@ -167,68 +180,190 @@ func decodetype_chanelem(s *LSym) *LSym {
 }
 
 // Type.FuncType.dotdotdot
-func decodetype_funcdotdotdot(s *LSym) int {
-	return int(s.P[commonsize()])
+func decodetype_funcdotdotdot(s *LSym) bool {
+	return uint16(decode_inuxi(s.P[commonsize()+2:], 2))&(1<<15) != 0
 }
 
-// Type.FuncType.in.length
+// Type.FuncType.inCount
 func decodetype_funcincount(s *LSym) int {
-	return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
+	return int(decode_inuxi(s.P[commonsize():], 2))
 }
 
 func decodetype_funcoutcount(s *LSym) int {
-	return int(decode_inuxi(s.P[commonsize()+3*Thearch.Ptrsize+2*Thearch.Intsize:], Thearch.Intsize))
+	return int(uint16(decode_inuxi(s.P[commonsize()+2:], 2)) & (1<<15 - 1))
 }
 
 func decodetype_funcintype(s *LSym, i int) *LSym {
-	r := decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize))
-	if r == nil {
-		return nil
+	uadd := commonsize() + 4
+	if SysArch.PtrSize == 8 {
+		uadd += 4
+	}
+	if decodetype_hasUncommon(s) {
+		uadd += uncommonSize()
 	}
-	return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
+	return decode_reloc_sym(s, int32(uadd+i*SysArch.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))))
+	return decodetype_funcintype(s, i+decodetype_funcincount(s))
 }
 
 // Type.StructType.fields.Slice::length
 func decodetype_structfieldcount(s *LSym) int {
-	return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
+	return int(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
 }
 
-func structfieldsize() int {
-	return 5 * Thearch.Ptrsize
+func decodetype_structfieldarrayoff(s *LSym, i int) int {
+	off := commonsize() + 2*SysArch.PtrSize + 2*SysArch.IntSize
+	if decodetype_hasUncommon(s) {
+		off += uncommonSize()
+	}
+	off += i * structfieldSize()
+	return off
 }
 
-// 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 ""
+// decodetype_str returns the contents of an rtype's str field (a nameOff).
+func decodetype_str(s *LSym) string {
+	str := decodetype_name(s, 4*SysArch.PtrSize+8)
+	if s.P[2*SysArch.PtrSize+4]&tflagExtraStar != 0 {
+		return str[1:]
 	}
-	r := decode_reloc(s, 0) // s has a pointer to the string data at offset 0
-	if r == nil {           // shouldn't happen.
+	return str
+}
+
+// decodetype_name decodes the name from a reflect.name.
+func decodetype_name(s *LSym, off int) string {
+	r := decode_reloc(s, int32(off))
+	if r == nil {
 		return ""
 	}
-	return cstring(r.Sym.P[r.Add:])
+
+	data := r.Sym.P
+	namelen := int(uint16(data[1])<<8 | uint16(data[2]))
+	return string(data[3 : 3+namelen])
+}
+
+func decodetype_structfieldname(s *LSym, i int) string {
+	off := decodetype_structfieldarrayoff(s, i)
+	return decodetype_name(s, off)
 }
 
 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))
+	off := decodetype_structfieldarrayoff(s, i)
+	return decode_reloc_sym(s, int32(off+SysArch.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))
+	off := decodetype_structfieldarrayoff(s, i)
+	return int64(decode_inuxi(s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
 }
 
 // InterfaceType.methods.length
 func decodetype_ifacemethodcount(s *LSym) int64 {
-	return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
+	return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
+}
+
+// methodsig is a fully qualified typed method signature, like
+// "Visit(type.go/ast.Node) (type.go/ast.Visitor)".
+type methodsig string
+
+// Matches runtime/typekind.go and reflect.Kind.
+const (
+	kindArray     = 17
+	kindChan      = 18
+	kindFunc      = 19
+	kindInterface = 20
+	kindMap       = 21
+	kindPtr       = 22
+	kindSlice     = 23
+	kindStruct    = 25
+	kindMask      = (1 << 5) - 1
+)
+
+// decode_methodsig decodes an array of method signature information.
+// Each element of the array is size bytes. The first 4 bytes is a
+// nameOff for the method name, and the next 4 bytes is a typeOff for
+// the function type.
+//
+// Conveniently this is the layout of both runtime.method and runtime.imethod.
+func decode_methodsig(s *LSym, off, size, count int) []methodsig {
+	var buf bytes.Buffer
+	var methods []methodsig
+	for i := 0; i < count; i++ {
+		buf.WriteString(decodetype_name(s, off))
+		mtypSym := decode_reloc_sym(s, int32(off+4))
+
+		buf.WriteRune('(')
+		inCount := decodetype_funcincount(mtypSym)
+		for i := 0; i < inCount; i++ {
+			if i > 0 {
+				buf.WriteString(", ")
+			}
+			buf.WriteString(decodetype_funcintype(mtypSym, i).Name)
+		}
+		buf.WriteString(") (")
+		outCount := decodetype_funcoutcount(mtypSym)
+		for i := 0; i < outCount; i++ {
+			if i > 0 {
+				buf.WriteString(", ")
+			}
+			buf.WriteString(decodetype_funcouttype(mtypSym, i).Name)
+		}
+		buf.WriteRune(')')
+
+		off += size
+		methods = append(methods, methodsig(buf.String()))
+		buf.Reset()
+	}
+	return methods
+}
+
+func decodetype_ifacemethods(s *LSym) []methodsig {
+	if decodetype_kind(s)&kindMask != kindInterface {
+		panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
+	}
+	r := decode_reloc(s, int32(commonsize()+SysArch.PtrSize))
+	if r == nil {
+		return nil
+	}
+	if r.Sym != s {
+		panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
+	}
+	off := int(r.Add) // array of reflect.imethod values
+	numMethods := int(decodetype_ifacemethodcount(s))
+	sizeofIMethod := 4 + 4
+	return decode_methodsig(s, off, sizeofIMethod, numMethods)
+}
+
+func decodetype_methods(s *LSym) []methodsig {
+	if !decodetype_hasUncommon(s) {
+		panic(fmt.Sprintf("no methods on %q", s.Name))
+	}
+	off := commonsize() // reflect.rtype
+	switch decodetype_kind(s) & kindMask {
+	case kindStruct: // reflect.structType
+		off += 2*SysArch.PtrSize + 2*SysArch.IntSize
+	case kindPtr: // reflect.ptrType
+		off += SysArch.PtrSize
+	case kindFunc: // reflect.funcType
+		off += SysArch.PtrSize // 4 bytes, pointer aligned
+	case kindSlice: // reflect.sliceType
+		off += SysArch.PtrSize
+	case kindArray: // reflect.arrayType
+		off += 3 * SysArch.PtrSize
+	case kindChan: // reflect.chanType
+		off += 2 * SysArch.PtrSize
+	case kindMap: // reflect.mapType
+		off += 4*SysArch.PtrSize + 8
+	case kindInterface: // reflect.interfaceType
+		off += SysArch.PtrSize + 2*SysArch.IntSize
+	default:
+		// just Sizeof(rtype)
+	}
+
+	mcount := int(decode_inuxi(s.P[off+4:], 2))
+	moff := int(decode_inuxi(s.P[off+4+2+2:], 4))
+	off += moff                // offset to array of reflect.method values
+	const sizeofMethod = 4 * 4 // sizeof reflect.method in program
+	return decode_methodsig(s, off, sizeofMethod, mcount)
 }
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index a96b37a..fa7105f 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -17,158 +17,78 @@ package ld
 import (
 	"cmd/internal/obj"
 	"fmt"
+	"log"
 	"os"
 	"strings"
 )
 
+const infoprefix = "go.dwarf.info."
+
 /*
  * 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 infosec *LSym
+var linesec *LSym
 
 var gdbscript string
 
 /*
  *  Basic I/O
  */
-func addrput(addr int64) {
-	switch Thearch.Ptrsize {
+func addrput(s *LSym, addr int64) {
+	switch SysArch.PtrSize {
 	case 4:
-		Thearch.Lput(uint32(addr))
+		Adduint32(Ctxt, s, uint32(addr))
 
 	case 8:
-		Thearch.Vput(uint64(addr))
+		Adduint64(Ctxt, s, uint64(addr))
 	}
 }
 
-func uleb128enc(v uint64, dst []byte) int {
-	var c uint8
-
-	length := uint8(0)
+func appendUleb128(b []byte, v uint64) []byte {
 	for {
-		c = uint8(v & 0x7f)
+		c := uint8(v & 0x7f)
 		v >>= 7
 		if v != 0 {
 			c |= 0x80
 		}
-		if dst != nil {
-			dst[0] = byte(c)
-			dst = dst[1:]
-		}
-		length++
+		b = append(b, c)
 		if c&0x80 == 0 {
 			break
 		}
 	}
-
-	return int(length)
+	return b
 }
 
-func sleb128enc(v int64, dst []byte) int {
-	var c uint8
-	var s uint8
-
-	length := uint8(0)
+func appendSleb128(b []byte, v int64) []byte {
 	for {
-		c = uint8(v & 0x7f)
-		s = uint8(v & 0x40)
+		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++
+		b = append(b, c)
 		if c&0x80 == 0 {
 			break
 		}
 	}
-
-	return int(length)
+	return b
 }
 
 var encbuf [10]byte
 
-func uleb128put(v int64) {
-	n := uleb128enc(uint64(v), encbuf[:])
-	Cwrite(encbuf[:n])
+func uleb128put(s *LSym, v int64) {
+	b := appendUleb128(encbuf[:0], uint64(v))
+	Addbytes(Ctxt, s, b)
 }
 
-func sleb128put(v int64) {
-	n := sleb128enc(v, encbuf[:])
-	Cwrite(encbuf[:n])
+func sleb128put(s *LSym, v int64) {
+	b := appendSleb128(encbuf[:0], v)
+	Addbytes(Ctxt, s, b)
 }
 
 /*
@@ -479,41 +399,34 @@ var abbrevs = [DW_NABRV]DWAbbrev{
 	},
 }
 
-func writeabbrev() {
-	abbrevo = Cpos()
+var dwarfp *LSym
+
+func writeabbrev() *LSym {
+	s := Linklookup(Ctxt, ".debug_abbrev", 0)
+	s.Type = obj.SDWARFSECT
+	abbrevsym = s
+
 	for i := 1; i < DW_NABRV; i++ {
 		// See section 7.5.3
-		uleb128put(int64(i))
+		uleb128put(s, int64(i))
 
-		uleb128put(int64(abbrevs[i].tag))
-		Cput(abbrevs[i].children)
+		uleb128put(s, int64(abbrevs[i].tag))
+		Adduint8(Ctxt, s, abbrevs[i].children)
 		for _, f := range abbrevs[i].attr {
-			uleb128put(int64(f.attr))
-			uleb128put(int64(f.form))
+			uleb128put(s, int64(f.attr))
+			uleb128put(s, int64(f.form))
 		}
-		uleb128put(0)
-		uleb128put(0)
+		uleb128put(s, 0)
+		uleb128put(s, 0)
 	}
 
-	Cput(0)
-	abbrevsize = Cpos() - abbrevo
+	Adduint8(Ctxt, s, 0)
+	return s
 }
 
 /*
  * 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
@@ -533,11 +446,7 @@ type DWDie struct {
 	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
+	sym    *LSym
 }
 
 /*
@@ -586,9 +495,8 @@ func getattr(die *DWDie, attr uint16) *DWAttr {
 }
 
 // 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 {
+// written out if it is listed in the abbrev).
+func newdie(parent *DWDie, abbrev int, name string, version int) *DWDie {
 	die := new(DWDie)
 	die.abbrev = abbrev
 	die.link = parent.child
@@ -596,19 +504,17 @@ func newdie(parent *DWDie, abbrev int, name string) *DWDie {
 
 	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
+	if name != "" && (abbrev <= DW_ABRV_VARIABLE || abbrev >= DW_ABRV_NULLTYPE) {
+		if abbrev != DW_ABRV_VARIABLE || version == 0 {
+			die.sym = Linklookup(Ctxt, infoprefix+name, version)
+			die.sym.Attr |= AttrHidden
+			die.sym.Type = obj.SDWARFINFO
+		}
 	}
 
 	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 {
@@ -622,179 +528,157 @@ func walktypedef(die *DWDie) *DWDie {
 	return die
 }
 
+func walksymtypedef(s *LSym) *LSym {
+	if t := Linkrlookup(Ctxt, s.Name+"..def", int(s.Version)); t != nil {
+		return t
+	}
+	return s
+}
+
 // Find child by AT_name using hashtable if available or linear scan
 // if not.
-func find(die *DWDie, name string) *DWDie {
+func findchild(die *DWDie, name string) *DWDie {
 	var prev *DWDie
 	for ; die != prev; prev, die = die, walktypedef(die) {
-
-		if die.hash == nil {
-			for a := die.child; a != nil; a = a.link {
-				if name == getattr(a, DW_AT_name).data {
-					return a
-				}
-			}
-			continue
-		}
-
-		h := int(dwarfhashstr(name))
-		a := die.hash[h]
-
-		if a == nil {
-			continue
-		}
-
-		if name == getattr(a, DW_AT_name).data {
-			return a
-		}
-
-		// Move found ones to head of the list.
-		for b := a.hlink; b != nil; b = b.hlink {
-			if name == getattr(b, DW_AT_name).data {
-				a.hlink = b.hlink
-				b.hlink = die.hash[h]
-				die.hash[h] = b
-				return b
+		for a := die.child; a != nil; a = a.link {
+			if name == getattr(a, DW_AT_name).data {
+				return a
 			}
-			a = b
 		}
+		continue
 	}
 	return nil
 }
 
-func mustFind(die *DWDie, name string) *DWDie {
-	r := find(die, name)
+// Used to avoid string allocation when looking up dwarf symbols
+var prefixBuf = []byte(infoprefix)
+
+func find(name string) *LSym {
+	n := append(prefixBuf, name...)
+	// The string allocation below is optimized away because it is only used in a map lookup.
+	s := Linkrlookup(Ctxt, string(n), 0)
+	prefixBuf = n[:len(infoprefix)]
+	return s
+}
+
+func mustFind(name string) *LSym {
+	r := find(name)
 	if r == nil {
-		Exitf("dwarf find: %s %p has no %s", getattr(die, DW_AT_name).data, die, name)
+		Exitf("dwarf find: cannot find %s", 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))
-
+func adddwarfref(ctxt *Link, s *LSym, t *LSym, size int) int64 {
+	var result int64
+	switch size {
 	default:
-		Diag("bad size in adddwarfrel")
+		Diag("invalid size %d in adddwarfref\n", size)
+		fallthrough
+	case SysArch.PtrSize:
+		result = Addaddr(ctxt, s, t)
+	case 4:
+		result = addaddrplus4(ctxt, s, t, 0)
 	}
+	r := &s.R[len(s.R)-1]
+	r.Type = obj.R_DWARFREF
+	return result
 }
 
-func newrefattr(die *DWDie, attr uint16, ref *DWDie) *DWAttr {
+func newrefattr(die *DWDie, attr uint16, ref *LSym) *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{}) {
+func putattr(s *LSym, 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)
+			Addaddrplus(Ctxt, s, data.(*LSym), value)
 			break
 		}
 
-		addrput(value)
+		addrput(s, 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)
+			Adduint8(Ctxt, s, uint8(1+SysArch.PtrSize))
+			Adduint8(Ctxt, s, DW_OP_addr)
+			Addaddr(Ctxt, s, data.(*LSym))
 			break
 		}
 
 		value &= 0xff
-		Cput(uint8(value))
+		Adduint8(Ctxt, s, uint8(value))
 		p := data.([]byte)
 		for i := 0; int64(i) < value; i++ {
-			Cput(uint8(p[i]))
+			Adduint8(Ctxt, s, p[i])
 		}
 
 	case DW_FORM_block2: // block
 		value &= 0xffff
 
-		Thearch.Wput(uint16(value))
+		Adduint16(Ctxt, s, uint16(value))
 		p := data.([]byte)
 		for i := 0; int64(i) < value; i++ {
-			Cput(uint8(p[i]))
+			Adduint8(Ctxt, s, p[i])
 		}
 
 	case DW_FORM_block4: // block
 		value &= 0xffffffff
 
-		Thearch.Lput(uint32(value))
+		Adduint32(Ctxt, s, uint32(value))
 		p := data.([]byte)
 		for i := 0; int64(i) < value; i++ {
-			Cput(uint8(p[i]))
+			Adduint8(Ctxt, s, p[i])
 		}
 
 	case DW_FORM_block: // block
-		uleb128put(value)
+		uleb128put(s, value)
 
 		p := data.([]byte)
 		for i := 0; int64(i) < value; i++ {
-			Cput(uint8(p[i]))
+			Adduint8(Ctxt, s, p[i])
 		}
 
 	case DW_FORM_data1: // constant
-		Cput(uint8(value))
+		Adduint8(Ctxt, s, uint8(value))
 
 	case DW_FORM_data2: // constant
-		Thearch.Wput(uint16(value))
+		Adduint16(Ctxt, s, 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)
+			adddwarfref(Ctxt, s, linesec, 4)
 			break
 		}
 
-		Thearch.Lput(uint32(value))
+		Adduint32(Ctxt, s, uint32(value))
 
 	case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
-		Thearch.Vput(uint64(value))
+		Adduint64(Ctxt, s, uint64(value))
 
 	case DW_FORM_sdata: // constant
-		sleb128put(value)
+		sleb128put(s, value)
 
 	case DW_FORM_udata: // constant
-		uleb128put(value)
+		uleb128put(s, value)
 
 	case DW_FORM_string: // string
-		strnput(data.(string), int(value+1))
+		str := data.(string)
+		Addstring(s, str)
+		for i := int64(len(str)); i < value; i++ {
+			Adduint8(Ctxt, s, 0)
+		}
 
 	case DW_FORM_flag: // flag
 		if value != 0 {
-			Cput(1)
+			Adduint8(Ctxt, s, 1)
 		} else {
-			Cput(0)
+			Adduint8(Ctxt, s, 0)
 		}
 
 		// In DWARF 2 (which is what we claim to generate),
@@ -804,22 +688,14 @@ func putattr(abbrev int, form int, cls int, value int64, data interface{}) {
 	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.
+			if SysArch.PtrSize == 8 {
+				Adduint64(Ctxt, s, 0) // invalid dwarf, gdb will complain.
 			} else {
-				Thearch.Lput(0) // invalid dwarf, gdb will complain.
+				Adduint32(Ctxt, s, 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)
+			dsym := data.(*LSym)
+			adddwarfref(Ctxt, s, dsym, SysArch.PtrSize)
 		}
 
 	case DW_FORM_ref1, // reference within the compilation unit
@@ -838,34 +714,45 @@ func putattr(abbrev int, form int, cls int, value int64, data interface{}) {
 
 // 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) {
+func putattrs(s *LSym, 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)
+				putattr(s, abbrev, int(f.form), int(ap.cls), ap.value, ap.data)
 				continue Outer
 			}
 		}
 
-		putattr(abbrev, int(f.form), 0, 0, nil)
+		putattr(s, abbrev, int(f.form), 0, 0, nil)
 	}
 }
 
-func putdies(die *DWDie) {
+func putdies(prev *LSym, die *DWDie) *LSym {
 	for ; die != nil; die = die.link {
-		putdie(die)
+		prev = putdie(prev, die)
 	}
+	Adduint8(Ctxt, prev, 0)
+	return prev
 }
 
-func putdie(die *DWDie) {
-	die.offs = Cpos() - infoo
-	uleb128put(int64(die.abbrev))
-	putattrs(die.abbrev, die.attr)
+func putdie(prev *LSym, die *DWDie) *LSym {
+	s := die.sym
+	if s == nil {
+		s = prev
+	} else {
+		if s.Attr.OnList() {
+			log.Fatalf("symbol %s listed multiple times", s.Name)
+		}
+		s.Attr |= AttrOnList
+		prev.Next = s
+	}
+	uleb128put(s, int64(die.abbrev))
+	putattrs(s, die.abbrev, die.attr)
 	if abbrevs[die.abbrev].children != 0 {
-		putdies(die.child)
-		Cput(0)
+		return putdies(s, die.child)
 	}
+	return s
 }
 
 func reverselist(list **DWDie) {
@@ -892,12 +779,9 @@ func reversetree(list **DWDie) {
 
 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])
+	b := append(block[:0], DW_OP_plus_uconst)
+	b = appendUleb128(b, uint64(offs))
+	newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, int64(len(b)), b)
 }
 
 // GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
@@ -935,44 +819,50 @@ func dotypedef(parent *DWDie, name string, def *DWDie) {
 		Diag("dwarf: bad def in dotypedef")
 	}
 
+	def.sym = Linklookup(Ctxt, def.sym.Name+"..def", 0)
+	def.sym.Attr |= AttrHidden
+	def.sym.Type = obj.SDWARFINFO
+
 	// 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)
+	die := newdie(parent, DW_ABRV_TYPEDECL, name, 0)
 
-	newrefattr(die, DW_AT_type, def)
+	newrefattr(die, DW_AT_type, def.sym)
 }
 
 // Define gotype, for composite ones recurse into constituents.
-func defgotype(gotype *LSym) *DWDie {
+func defgotype(gotype *LSym) *LSym {
 	if gotype == nil {
-		return mustFind(&dwtypes, "<unspecified>")
+		return mustFind("<unspecified>")
 	}
 
 	if !strings.HasPrefix(gotype.Name, "type.") {
-		Diag("dwarf: type name doesn't start with \".type\": %s", gotype.Name)
-		return mustFind(&dwtypes, "<unspecified>")
+		Diag("dwarf: type name doesn't start with \"type.\": %s", gotype.Name)
+		return mustFind("<unspecified>")
 	}
 
 	name := gotype.Name[5:] // could also decode from Type.string
 
-	die := find(&dwtypes, name)
+	sdie := find(name)
 
-	if die != nil {
-		return die
+	if sdie != nil {
+		return sdie
 	}
 
-	if false && Debug['v'] > 2 {
-		fmt.Printf("new type: %v\n", gotype)
-	}
+	return newtype(gotype).sym
+}
 
+func newtype(gotype *LSym) *DWDie {
+	name := gotype.Name[5:] // could also decode from Type.string
 	kind := decodetype_kind(gotype)
 	bytesize := decodetype_size(gotype)
 
+	var die *DWDie
 	switch kind {
 	case obj.KindBool:
-		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
 		newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
 
@@ -981,7 +871,7 @@ func defgotype(gotype *LSym) *DWDie {
 		obj.KindInt16,
 		obj.KindInt32,
 		obj.KindInt64:
-		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
 		newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
 
@@ -991,66 +881,69 @@ func defgotype(gotype *LSym) *DWDie {
 		obj.KindUint32,
 		obj.KindUint64,
 		obj.KindUintptr:
-		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
 		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)
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
 		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)
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
 		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)
+		die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name, 0)
 		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")
+		fld := newdie(die, DW_ABRV_ARRAYRANGE, "range", 0)
 
 		// 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"))
+		newrefattr(fld, DW_AT_type, mustFind("uintptr"))
 
 	case obj.KindChan:
-		die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name, 0)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
 		s := decodetype_chanelem(gotype)
 		newrefattr(die, DW_AT_go_elem, defgotype(s))
+		// Save elem type for synthesizechantypes. We could synthesize here
+		// but that would change the order of DIEs we output.
+		newrefattr(die, DW_AT_type, s)
 
 	case obj.KindFunc:
-		die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name, 0)
 		dotypedef(&dwtypes, name, die)
-		newrefattr(die, DW_AT_type, mustFind(&dwtypes, "void"))
+		newrefattr(die, DW_AT_type, mustFind("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:])
+			fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
 			newrefattr(fld, DW_AT_type, defgotype(s))
 		}
 
-		if decodetype_funcdotdotdot(gotype) != 0 {
-			newdie(die, DW_ABRV_DOTDOTDOT, "...")
+		if decodetype_funcdotdotdot(gotype) {
+			newdie(die, DW_ABRV_DOTDOTDOT, "...", 0)
 		}
 		nfields = decodetype_funcoutcount(gotype)
 		for i := 0; i < nfields; i++ {
 			s = decodetype_funcouttype(gotype, i)
-			fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:])
+			fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
 			newrefattr(fld, DW_AT_type, defptrto(defgotype(s)))
 		}
 
 	case obj.KindInterface:
-		die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name, 0)
 		dotypedef(&dwtypes, name, die)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
 		nfields := int(decodetype_ifacemethodcount(gotype))
@@ -1063,31 +956,35 @@ func defgotype(gotype *LSym) *DWDie {
 		newrefattr(die, DW_AT_type, defgotype(s))
 
 	case obj.KindMap:
-		die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name, 0)
 		s := decodetype_mapkey(gotype)
 		newrefattr(die, DW_AT_go_key, defgotype(s))
 		s = decodetype_mapvalue(gotype)
 		newrefattr(die, DW_AT_go_elem, defgotype(s))
+		// Save gotype for use in synthesizemaptypes. We could synthesize here,
+		// but that would change the order of the DIEs.
+		newrefattr(die, DW_AT_type, gotype)
 
 	case obj.KindPtr:
-		die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name, 0)
 		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)
+		die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name, 0)
 		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))
+		elem := defgotype(s)
+		newrefattr(die, DW_AT_go_elem, elem)
 
 	case obj.KindString:
-		die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name, 0)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
 
 	case obj.KindStruct:
-		die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name)
+		die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name, 0)
 		dotypedef(&dwtypes, name, die)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
 		nfields := decodetype_structfieldcount(gotype)
@@ -1100,46 +997,55 @@ func defgotype(gotype *LSym) *DWDie {
 			if f == "" {
 				f = s.Name[5:] // skip "type."
 			}
-			fld = newdie(die, DW_ABRV_STRUCTFIELD, f)
+			fld = newdie(die, DW_ABRV_STRUCTFIELD, f, 0)
 			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)
+		die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name, 0)
 
 	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>"))
+		die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name, 0)
+		newrefattr(die, DW_AT_type, mustFind("<unspecified>"))
 	}
 
 	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, int64(kind), 0)
 
+	if _, ok := prototypedies[gotype.Name]; ok {
+		prototypedies[gotype.Name] = die
+	}
+
 	return die
 }
 
+func nameFromDIESym(dwtype *LSym) string {
+	return strings.TrimSuffix(dwtype.Name[len(infoprefix):], "..def")
+}
+
 // 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)
+func defptrto(dwtype *LSym) *LSym {
+	ptrname := "*" + nameFromDIESym(dwtype)
+	die := find(ptrname)
 	if die == nil {
-		die = newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname)
-		newrefattr(die, DW_AT_type, dwtype)
+		pdie := newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname, 0)
+		newrefattr(pdie, DW_AT_type, dwtype)
+		return pdie.sym
 	}
 
 	return die
 }
 
 // Copies src's children into dst. Copies attributes by value.
-// DWAttr.data is copied as pointer only.  If except is one of
+// 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) {
 	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))
+		c := newdie(dst, src.abbrev, getattr(src, DW_AT_name).data.(string), 0)
 		for a := src.attr; a != nil; a = a.link {
 			newattr(c, a.atr, int(a.cls), a.value, a.data)
 		}
@@ -1155,9 +1061,11 @@ func copychildren(dst *DWDie, src *DWDie) {
 
 // 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)
+func substitutetype(structdie *DWDie, field string, dwtype *LSym) {
+	child := findchild(structdie, field)
 	if child == nil {
+		Exitf("dwarf substitutetype: %s does not have member %s",
+			getattr(structdie, DW_AT_name).data, field)
 		return
 	}
 
@@ -1169,8 +1077,17 @@ func substitutetype(structdie *DWDie, field string, dwtype *DWDie) {
 	}
 }
 
+func findprotodie(name string) *DWDie {
+	die, ok := prototypedies[name]
+	if ok && die == nil {
+		defgotype(lookup_or_diag(name))
+		die = prototypedies[name]
+	}
+	return die
+}
+
 func synthesizestringtypes(die *DWDie) {
-	prototype := walktypedef(defgotype(lookup_or_diag("type.runtime.stringStructDWARF")))
+	prototype := walktypedef(findprotodie("type.runtime.stringStructDWARF"))
 	if prototype == nil {
 		return
 	}
@@ -1184,7 +1101,7 @@ func synthesizestringtypes(die *DWDie) {
 }
 
 func synthesizeslicetypes(die *DWDie) {
-	prototype := walktypedef(defgotype(lookup_or_diag("type.runtime.slice")))
+	prototype := walktypedef(findprotodie("type.runtime.slice"))
 	if prototype == nil {
 		return
 	}
@@ -1194,7 +1111,7 @@ func synthesizeslicetypes(die *DWDie) {
 			continue
 		}
 		copychildren(die, prototype)
-		elem := getattr(die, DW_AT_go_elem).data.(*DWDie)
+		elem := getattr(die, DW_AT_go_elem).data.(*LSym)
 		substitutetype(die, "array", defptrto(elem))
 	}
 }
@@ -1218,9 +1135,21 @@ const (
 	BucketSize = 8
 )
 
+func mkinternaltype(abbrev int, typename, keyname, valname string, f func(*DWDie)) *LSym {
+	name := mkinternaltypename(typename, keyname, valname)
+	symname := infoprefix + name
+	s := Linkrlookup(Ctxt, symname, 0)
+	if s != nil {
+		return s
+	}
+	die := newdie(&dwtypes, abbrev, name, 0)
+	f(die)
+	return die.sym
+}
+
 func synthesizemaptypes(die *DWDie) {
-	hash := walktypedef(defgotype(lookup_or_diag("type.runtime.hmap")))
-	bucket := walktypedef(defgotype(lookup_or_diag("type.runtime.bmap")))
+	hash := walktypedef(findprotodie("type.runtime.hmap"))
+	bucket := walktypedef(findprotodie("type.runtime.bmap"))
 
 	if hash == nil {
 		return
@@ -1230,97 +1159,92 @@ func synthesizemaptypes(die *DWDie) {
 		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))
+		gotype := getattr(die, DW_AT_type).data.(*LSym)
+		keytype := decodetype_mapkey(gotype)
+		valtype := decodetype_mapvalue(gotype)
+		keysize, valsize := decodetype_size(keytype), decodetype_size(valtype)
+		keytype, valtype = walksymtypedef(defgotype(keytype)), walksymtypedef(defgotype(valtype))
 
 		// compute size info like hashmap.c does.
-		keysize, valsize := Thearch.Ptrsize, Thearch.Ptrsize
-		a := getattr(keytype, DW_AT_byte_size)
-		if a != nil {
-			keysize = int(a.value)
-		}
-		a = getattr(valtype, DW_AT_byte_size)
-		if a != nil {
-			valsize = int(a.value)
-		}
 		indirect_key, indirect_val := false, false
 		if keysize > MaxKeySize {
-			keysize = Thearch.Ptrsize
+			keysize = int64(SysArch.PtrSize)
 			indirect_key = true
 		}
 		if valsize > MaxValSize {
-			valsize = Thearch.Ptrsize
+			valsize = int64(SysArch.PtrSize)
 			indirect_val = true
 		}
 
 		// 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 {
-			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"))
+		keyname := nameFromDIESym(keytype)
+		dwhks := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *DWDie) {
+			newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*keysize, 0)
+			t := keytype
+			if indirect_key {
+				t = defptrto(keytype)
+			}
+			newrefattr(dwhk, DW_AT_type, t)
+			fld := newdie(dwhk, DW_ABRV_ARRAYRANGE, "size", 0)
+			newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
+			newrefattr(fld, DW_AT_type, mustFind("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 {
-			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"))
+		valname := nameFromDIESym(valtype)
+		dwhvs := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *DWDie) {
+			newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*valsize, 0)
+			t := valtype
+			if indirect_val {
+				t = defptrto(valtype)
+			}
+			newrefattr(dwhv, DW_AT_type, t)
+			fld := newdie(dwhv, DW_ABRV_ARRAYRANGE, "size", 0)
+			newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
+			newrefattr(fld, DW_AT_type, mustFind("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))
-		}
+		dwhbs := mkinternaltype(DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *DWDie) {
+			// Copy over all fields except the field "data" from the generic
+			// bucket. "data" will be replaced with keys/values below.
+			copychildrenexcept(dwhb, bucket, findchild(bucket, "data"))
+
+			fld := newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys", 0)
+			newrefattr(fld, DW_AT_type, dwhks)
+			newmemberoffsetattr(fld, BucketSize)
+			fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values", 0)
+			newrefattr(fld, DW_AT_type, dwhvs)
+			newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
+			fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow", 0)
+			newrefattr(fld, DW_AT_type, defptrto(dwhb.sym))
+			newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
+			if SysArch.RegSize > SysArch.PtrSize {
+				fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad", 0)
+				newrefattr(fld, DW_AT_type, mustFind("uintptr"))
+				newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(SysArch.PtrSize))
+			}
 
-		newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*int64(keysize)+BucketSize*int64(valsize)+int64(Thearch.Regsize), 0)
+			newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*valsize+int64(SysArch.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)
+		dwhs := mkinternaltype(DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *DWDie) {
+			copychildren(dwh, hash)
+			substitutetype(dwh, "buckets", defptrto(dwhbs))
+			substitutetype(dwh, "oldbuckets", defptrto(dwhbs))
+			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))
+		newrefattr(die, DW_AT_type, defptrto(dwhs))
 	}
 }
 
 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")))
+	sudog := walktypedef(findprotodie("type.runtime.sudog"))
+	waitq := walktypedef(findprotodie("type.runtime.waitq"))
+	hchan := walktypedef(findprotodie("type.runtime.hchan"))
 	if sudog == nil || waitq == nil || hchan == nil {
 		return
 	}
@@ -1331,42 +1255,41 @@ func synthesizechantypes(die *DWDie) {
 		if die.abbrev != DW_ABRV_CHANTYPE {
 			continue
 		}
-		elemsize := Thearch.Ptrsize
-		elemtype := getattr(die, DW_AT_go_elem).data.(*DWDie)
-		a := getattr(elemtype, DW_AT_byte_size)
-		if a != nil {
-			elemsize = int(a.value)
-		}
+		elemgotype := getattr(die, DW_AT_type).data.(*LSym)
+		elemsize := decodetype_size(elemgotype)
+		elemname := elemgotype.Name[5:]
+		elemtype := walksymtypedef(defgotype(elemgotype))
 
 		// 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)
+		dwss := mkinternaltype(DW_ABRV_STRUCTTYPE, "sudog", elemname, "", func(dws *DWDie) {
+			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)+elemsize, nil)
+		})
 
 		// waitq<T>
-		dww := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("waitq", getattr(elemtype, DW_AT_name).data.(string), ""))
+		dwws := mkinternaltype(DW_ABRV_STRUCTTYPE, "waitq", elemname, "", func(dww *DWDie) {
 
-		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)
+			copychildren(dww, waitq)
+			substitutetype(dww, "first", defptrto(dwss))
+			substitutetype(dww, "last", defptrto(dwss))
+			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)
+		dwhs := mkinternaltype(DW_ABRV_STRUCTTYPE, "hchan", elemname, "", func(dwh *DWDie) {
+			copychildren(dwh, hchan)
+			substitutetype(dwh, "recvq", dwws)
+			substitutetype(dwh, "sendq", dwws)
+			newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hchan, DW_AT_byte_size).value, nil)
+		})
 
-		newrefattr(die, DW_AT_type, defptrto(dwh))
+		newrefattr(die, DW_AT_type, defptrto(dwhs))
 	}
 }
 
@@ -1386,13 +1309,13 @@ func defdwsymb(sym *LSym, s string, t int, v int64, size int64, ver int, gotype
 
 	var dv *DWDie
 
-	var dt *DWDie
+	var dt *LSym
 	switch t {
 	default:
 		return
 
 	case 'd', 'b', 'D', 'B':
-		dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s)
+		dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s, ver)
 		newabslocexprattr(dv, v, sym)
 		if ver == 0 {
 			newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0)
@@ -1422,8 +1345,8 @@ func finddebugruntimepath(s *LSym) {
 		return
 	}
 
-	for i := 0; i < s.Pcln.Nfile; i++ {
-		f := s.Pcln.File[i]
+	for i := range s.FuncInfo.File {
+		f := s.FuncInfo.File[i]
 		if i := strings.Index(f.Name, "runtime/runtime.go"); i >= 0 {
 			gdbscript = f.Name[:i] + "runtime/runtime-gdb.py"
 			break
@@ -1441,41 +1364,36 @@ const (
 	OPCODE_BASE = 10
 )
 
-func putpclcdelta(delta_pc int64, delta_lc int64) {
+func putpclcdelta(s *LSym, 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))
+			Adduint8(Ctxt, s, uint8(opcode))
 			return
 		}
 	}
 
 	if delta_pc != 0 {
-		Cput(DW_LNS_advance_pc)
-		sleb128put(delta_pc)
+		Adduint8(Ctxt, s, DW_LNS_advance_pc)
+		sleb128put(s, delta_pc)
 	}
 
-	Cput(DW_LNS_advance_line)
-	sleb128put(delta_lc)
-	Cput(DW_LNS_copy)
+	Adduint8(Ctxt, s, DW_LNS_advance_line)
+	sleb128put(s, delta_lc)
+	Adduint8(Ctxt, s, DW_LNS_copy)
 }
 
 func newcfaoffsetattr(die *DWDie, offs int32) {
 	var block [20]byte
+	b := append(block[:0], DW_OP_call_frame_cfa)
 
-	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++
+		b = append(b, DW_OP_consts)
+		b = appendSleb128(b, int64(offs))
+		b = append(b, DW_OP_plus)
 	}
 
-	newattr(die, DW_AT_location, DW_CLS_BLOCK, int64(i), block[:i])
+	newattr(die, DW_AT_location, DW_CLS_BLOCK, int64(len(b)), b)
 }
 
 func mkvarname(name string, da int) string {
@@ -1488,26 +1406,6 @@ func mkvarname(name string, da int) string {
  * 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
@@ -1515,28 +1413,30 @@ func getCompilationDir() string {
 	return "/"
 }
 
-func writelines() {
+func writelines(prev *LSym) *LSym {
 	if linesec == nil {
-		linesec = Linklookup(Ctxt, ".dwarfline", 0)
+		linesec = Linklookup(Ctxt, ".debug_line", 0)
 	}
+	linesec.Type = obj.SDWARFSECT
 	linesec.R = linesec.R[:0]
 
+	ls := linesec
+	prev.Next = ls
+
 	unitstart := int64(-1)
+	headerstart := 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
+	s := Ctxt.Textp[0]
 
-	dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go")
+	dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go", 0)
 	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_stmt_list, DW_CLS_PTR, 0, 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()
@@ -1544,61 +1444,62 @@ func writelines() {
 
 	// 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.
+	unit_length_offset := ls.Size
+	Adduint32(Ctxt, ls, 0) // unit_length (*), filled in at end.
+	unitstart = ls.Size
+	Adduint16(Ctxt, ls, 2) // dwarf version (appendix F)
+	header_length_offset := ls.Size
+	Adduint32(Ctxt, ls, 0) // header_length (*), filled in at end.
+	headerstart = ls.Size
 
 	// 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)
+	Adduint8(Ctxt, ls, 1)              // minimum_instruction_length
+	Adduint8(Ctxt, ls, 1)              // default_is_stmt
+	Adduint8(Ctxt, ls, LINE_BASE&0xFF) // line_base
+	Adduint8(Ctxt, ls, LINE_RANGE)     // line_range
+	Adduint8(Ctxt, ls, OPCODE_BASE)    // opcode_base
+	Adduint8(Ctxt, ls, 0)              // standard_opcode_lengths[1]
+	Adduint8(Ctxt, ls, 1)              // standard_opcode_lengths[2]
+	Adduint8(Ctxt, ls, 1)              // standard_opcode_lengths[3]
+	Adduint8(Ctxt, ls, 1)              // standard_opcode_lengths[4]
+	Adduint8(Ctxt, ls, 1)              // standard_opcode_lengths[5]
+	Adduint8(Ctxt, ls, 0)              // standard_opcode_lengths[6]
+	Adduint8(Ctxt, ls, 0)              // standard_opcode_lengths[7]
+	Adduint8(Ctxt, ls, 0)              // standard_opcode_lengths[8]
+	Adduint8(Ctxt, ls, 1)              // standard_opcode_lengths[9]
+	Adduint8(Ctxt, ls, 0)              // include_directories  (empty)
+
+	for _, f := range Ctxt.Filesyms {
+		Addstring(ls, f.Name)
+		Adduint8(Ctxt, ls, 0)
+		Adduint8(Ctxt, ls, 0)
+		Adduint8(Ctxt, ls, 0)
 	}
 
 	// 4 zeros: the string termination + 3 fields.
-	Cput(0)
+	Adduint8(Ctxt, ls, 0)
 	// terminate file_names.
-	headerend = Cpos()
+	headerend = ls.Size
 
-	Cput(0) // start extended opcode
-	uleb128put(1 + int64(Thearch.Ptrsize))
-	Cput(DW_LNE_set_address)
+	Adduint8(Ctxt, ls, 0) // start extended opcode
+	uleb128put(ls, 1+int64(SysArch.PtrSize))
+	Adduint8(Ctxt, ls, DW_LNE_set_address)
 
 	pc := s.Value
 	line := 1
 	file := 1
 	if Linkmode == LinkExternal {
-		adddwarfrel(linesec, s, lineo, Thearch.Ptrsize, 0)
+		Addaddr(Ctxt, ls, s)
 	} else {
-		addrput(pc)
+		addrput(ls, pc)
 	}
 
 	var pcfile Pciter
 	var pcline Pciter
-	for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
-		s = Ctxt.Cursym
+	for _, Ctxt.Cursym = range Ctxt.Textp {
+		s := Ctxt.Cursym
 
-		dwfunc := newdie(dwinfo, DW_ABRV_FUNCTION, s.Name)
+		dwfunc := newdie(dwinfo, DW_ABRV_FUNCTION, s.Name, int(s.Version))
 		newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s)
 		epc = s.Value + s.Size
 		epcs = s
@@ -1607,14 +1508,14 @@ func writelines() {
 			newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0)
 		}
 
-		if s.Pcln == nil {
+		if s.FuncInfo == nil {
 			continue
 		}
 
 		finddebugruntimepath(s)
 
-		pciterinit(Ctxt, &pcfile, &s.Pcln.Pcfile)
-		pciterinit(Ctxt, &pcline, &s.Pcln.Pcline)
+		pciterinit(Ctxt, &pcfile, &s.FuncInfo.Pcfile)
+		pciterinit(Ctxt, &pcline, &s.FuncInfo.Pcline)
 		epc = pc
 		for pcfile.done == 0 && pcline.done == 0 {
 			if epc-s.Value >= int64(pcfile.nextpc) {
@@ -1628,12 +1529,12 @@ func writelines() {
 			}
 
 			if int32(file) != pcfile.value {
-				Cput(DW_LNS_set_file)
-				uleb128put(int64(pcfile.value))
+				Adduint8(Ctxt, ls, DW_LNS_set_file)
+				uleb128put(ls, int64(pcfile.value))
 				file = int(pcfile.value)
 			}
 
-			putpclcdelta(s.Value+int64(pcline.pc)-pc, int64(pcline.value)-int64(line))
+			putpclcdelta(ls, s.Value+int64(pcline.pc)-pc, int64(pcline.value)-int64(line))
 
 			pc = s.Value + int64(pcline.pc)
 			line = int(pcline.value)
@@ -1646,19 +1547,22 @@ func writelines() {
 		}
 
 		var (
-			dt      int
-			offs    int64
-			varhash [HASHSIZE]*DWDie
+			dt, da int
+			offs   int64
 		)
-		da := 0
-		dwfunc.hash = varhash[:] // enable indexing of children by name
-		for a := s.Autom; a != nil; a = a.Link {
+		for _, a := range s.FuncInfo.Autom {
 			switch a.Name {
 			case obj.A_AUTO:
 				dt = DW_ABRV_AUTO
 				offs = int64(a.Aoffset)
 				if !haslinkregister() {
-					offs -= int64(Thearch.Ptrsize)
+					offs -= int64(SysArch.PtrSize)
+				}
+				if obj.Framepointer_enabled(obj.Getgoos(), obj.Getgoarch()) {
+					// The frame pointer is saved
+					// between the CFA and the
+					// autos.
+					offs -= int64(SysArch.PtrSize)
 				}
 
 			case obj.A_PARAM:
@@ -1673,7 +1577,7 @@ func writelines() {
 				continue
 			}
 			var n string
-			if find(dwfunc, a.Asym.Name) != nil {
+			if findchild(dwfunc, a.Asym.Name) != nil {
 				n = mkvarname(a.Asym.Name, da)
 			} else {
 				n = a.Asym.Name
@@ -1684,7 +1588,7 @@ func writelines() {
 				n = n[i+1:]
 			}
 
-			dwvar := newdie(dwfunc, dt, n)
+			dwvar := newdie(dwfunc, dt, n, 0)
 			newcfaoffsetattr(dwvar, int32(offs))
 			newrefattr(dwvar, DW_AT_type, defgotype(a.Gotype))
 
@@ -1703,98 +1607,110 @@ func writelines() {
 
 			da++
 		}
-
-		dwfunc.hash = nil
 	}
 
-	flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10))
-	linesize = Cpos() - lineo
+	Adduint8(Ctxt, ls, 0) // start extended opcode
+	uleb128put(ls, 1)
+	Adduint8(Ctxt, ls, DW_LNE_end_sequence)
+
+	newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, epc+1, epcs)
+
+	setuint32(Ctxt, ls, unit_length_offset, uint32(ls.Size-unitstart))
+	setuint32(Ctxt, ls, header_length_offset, uint32(headerend-headerstart))
+
+	return ls
 }
 
 /*
  *  Emit .debug_frame
  */
 const (
-	CIERESERVE          = 16
-	DATAALIGNMENTFACTOR = -4
+	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))
+// appendPCDeltaCFA appends per-PC CFA deltas to b and returns the final slice.
+func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte {
+	b = append(b, DW_CFA_def_cfa_offset_sf)
+	b = appendSleb128(b, cfa/dataAlignmentFactor)
+
+	switch {
+	case deltapc < 0x40:
+		b = append(b, uint8(DW_CFA_advance_loc+deltapc))
+	case deltapc < 0x100:
+		b = append(b, DW_CFA_advance_loc1)
+		b = append(b, uint8(deltapc))
+	case deltapc < 0x10000:
+		b = append(b, DW_CFA_advance_loc2)
+		b = Thearch.Append16(b, uint16(deltapc))
+	default:
+		b = append(b, DW_CFA_advance_loc4)
+		b = Thearch.Append32(b, uint32(deltapc))
 	}
+	return b
 }
 
-func writeframes() {
+func writeframes(prev *LSym) *LSym {
 	if framesec == nil {
-		framesec = Linklookup(Ctxt, ".dwarfframe", 0)
+		framesec = Linklookup(Ctxt, ".debug_frame", 0)
 	}
+	framesec.Type = obj.SDWARFSECT
 	framesec.R = framesec.R[:0]
-	frameo = Cpos()
+	fs := framesec
+	prev.Next = fs
 
 	// 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
+	cieReserve := uint32(16)
+	if haslinkregister() {
+		cieReserve = 32
+	}
+	Adduint32(Ctxt, fs, cieReserve)           // initial length, must be multiple of pointer size
+	Adduint32(Ctxt, fs, 0xffffffff)           // cid.
+	Adduint8(Ctxt, fs, 3)                     // dwarf version (appendix F)
+	Adduint8(Ctxt, fs, 0)                     // augmentation ""
+	uleb128put(fs, 1)                         // code_alignment_factor
+	sleb128put(fs, dataAlignmentFactor)       // all CFI offset calculations include multiplication with this factor
+	uleb128put(fs, int64(Thearch.Dwarfreglr)) // return_address_register
+
+	Adduint8(Ctxt, fs, DW_CFA_def_cfa)        // Set the current frame address..
+	uleb128put(fs, int64(Thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)...
+	if haslinkregister() {
+		uleb128put(fs, int64(0)) // ...plus a 0 offset.
 
-	Cput(DW_CFA_def_cfa)
+		Adduint8(Ctxt, fs, DW_CFA_same_value) // The platform's link register is unchanged during the prologue.
+		uleb128put(fs, int64(Thearch.Dwarfreglr))
 
-	uleb128put(int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h)
-	if haslinkregister() {
-		uleb128put(int64(0)) // offset
+		Adduint8(Ctxt, fs, DW_CFA_val_offset)     // The previous value...
+		uleb128put(fs, int64(Thearch.Dwarfregsp)) // ...of the platform's SP register...
+		uleb128put(fs, int64(0))                  // ...is CFA+0.
 	} else {
-		uleb128put(int64(Thearch.Ptrsize)) // offset
-	}
+		uleb128put(fs, int64(SysArch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame).
 
-	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
+		Adduint8(Ctxt, fs, DW_CFA_offset_extended)                  // The previous value...
+		uleb128put(fs, int64(Thearch.Dwarfreglr))                   // ...of the return address...
+		uleb128put(fs, int64(-SysArch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)].
 	}
 
 	// 4 is to exclude the length field.
-	pad := CIERESERVE + frameo + 4 - Cpos()
+	pad := int64(cieReserve) + 4 - fs.Size
 
 	if pad < 0 {
-		Exitf("dwarf: CIERESERVE too small by %d bytes.", -pad)
+		Exitf("dwarf: cieReserve too small by %d bytes.", -pad)
 	}
 
-	strnput("", int(pad))
+	Addbytes(Ctxt, fs, zeros[:pad])
 
+	var deltaBuf []byte
 	var pcsp Pciter
-	for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
+	for _, Ctxt.Cursym = range Ctxt.Textp {
 		s := Ctxt.Cursym
-		if s.Pcln == nil {
+		if s.FuncInfo == 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) {
+		// Emit a FDE, Section 6.4.1.
+		// First build the section contents into a byte buffer.
+		deltaBuf = deltaBuf[:0]
+		for pciterinit(Ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
 			nextpc := pcsp.nextpc
 
 			// pciterinit goes up to the end of the function,
@@ -1807,35 +1723,45 @@ func writeframes() {
 			}
 
 			if haslinkregister() {
-				putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(pcsp.value))
+				// TODO(bryanpkc): This is imprecise. In general, the instruction
+				// that stores the return address to the stack frame is not the
+				// same one that allocates the frame.
+				if pcsp.value > 0 {
+					// The return address is preserved at (CFA-frame_size)
+					// after a stack frame has been allocated.
+					deltaBuf = append(deltaBuf, DW_CFA_offset_extended_sf)
+					deltaBuf = appendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr))
+					deltaBuf = appendSleb128(deltaBuf, -int64(pcsp.value)/dataAlignmentFactor)
+				} else {
+					// The return address is restored into the link register
+					// when a stack frame has been de-allocated.
+					deltaBuf = append(deltaBuf, DW_CFA_same_value)
+					deltaBuf = appendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr))
+				}
+				deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(pcsp.value))
 			} else {
-				putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value))
+				deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(SysArch.PtrSize)+int64(pcsp.value))
 			}
 		}
+		pad := int(Rnd(int64(len(deltaBuf)), int64(SysArch.PtrSize))) - len(deltaBuf)
+		deltaBuf = append(deltaBuf, zeros[:pad]...)
 
-		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))
+		// Emit the FDE header, Section 6.4.1.
+		//	4 bytes: length, must be multiple of thearch.ptrsize
+		//	4 bytes: Pointer to the CIE above, at offset 0
+		//	ptrsize: initial location
+		//	ptrsize: address range
+		Adduint32(Ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
 		if Linkmode == LinkExternal {
-			adddwarfrel(framesec, framesym, frameo, 4, 0)
-			adddwarfrel(framesec, s, frameo, Thearch.Ptrsize, 0)
+			adddwarfref(Ctxt, fs, framesec, 4)
 		} else {
-			Thearch.Lput(0)
-			addrput(s.Value)
+			Adduint32(Ctxt, fs, 0) // CIE offset
 		}
-
-		addrput(s.Size)
-		Cseek(fdeo + 4 + fdesize)
+		Addaddr(Ctxt, fs, s)
+		addrput(fs, s.Size) // address range
+		Addbytes(Ctxt, fs, deltaBuf)
 	}
-
-	Cflush()
-	framesize = Cpos() - frameo
+	return fs
 }
 
 /*
@@ -1845,12 +1771,14 @@ const (
 	COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
 )
 
-func writeinfo() {
-	fwdcount = 0
+func writeinfo(prev *LSym) *LSym {
 	if infosec == nil {
-		infosec = Linklookup(Ctxt, ".dwarfinfo", 0)
+		infosec = Linklookup(Ctxt, ".debug_info", 0)
 	}
 	infosec.R = infosec.R[:0]
+	infosec.Type = obj.SDWARFINFO
+	infosec.Attr |= AttrReachable
+	prev.Next, prev = infosec, infosec
 
 	if arangessec == nil {
 		arangessec = Linklookup(Ctxt, ".dwarfaranges", 0)
@@ -1858,32 +1786,30 @@ func writeinfo() {
 	arangessec.R = arangessec.R[:0]
 
 	for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
-		unitstart := Cpos()
+		s := compunit.sym
+		prev.Next, prev = s, s
 
 		// 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)
+		Adduint32(Ctxt, s, 0) // unit_length (*), will be filled in later.
+		Adduint16(Ctxt, s, 2) // dwarf version (appendix F)
 
 		// debug_abbrev_offset (*)
-		if Linkmode == LinkExternal {
-			adddwarfrel(infosec, abbrevsym, infoo, 4, 0)
-		} else {
-			Thearch.Lput(0)
-		}
+		adddwarfref(Ctxt, s, abbrevsym, 4)
 
-		Cput(uint8(Thearch.Ptrsize)) // address_size
+		Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size
 
-		putdie(compunit)
+		prev = putdie(prev, compunit)
+		cusize := s.Size - 4 // exclude the length field.
+		for child := s.Next; child != nil; child = child.Next {
+			cusize += child.Size
+		}
 
-		here := Cpos()
-		Cseek(unitstart)
-		Thearch.Lput(uint32(here - unitstart - 4)) // exclude the length field.
-		Cseek(here)
+		setuint32(Ctxt, s, 0, uint32(cusize))
+		newattr(compunit, DW_AT_byte_size, DW_CLS_CONSTANT, cusize, 0)
 	}
-
-	Cflush()
+	return prev
 }
 
 /*
@@ -1904,51 +1830,52 @@ func ispubtype(die *DWDie) bool {
 	return die.abbrev >= DW_ABRV_NULLTYPE
 }
 
-func writepub(ispub func(*DWDie) bool) int64 {
-	sectionstart := Cpos()
+func writepub(sname string, ispub func(*DWDie) bool, prev *LSym) *LSym {
+	s := Linklookup(Ctxt, sname, 0)
+	s.Type = obj.SDWARFSECT
+	prev.Next = s
 
 	for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
-		unitend := infoo + infosize
-		unitstart := compunit.offs - COMPUNITHEADERSIZE
-		if compunit.link != nil {
-			unitend = compunit.link.offs - COMPUNITHEADERSIZE
-		}
+		sectionstart := s.Size
+		culength := uint32(getattr(compunit, DW_AT_byte_size).value) + 4
 
 		// 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
+		Adduint32(Ctxt, s, 0)                 // unit_length (*), will be filled in later.
+		Adduint16(Ctxt, s, 2)                 // dwarf version (appendix F)
+		adddwarfref(Ctxt, s, compunit.sym, 4) // debug_info_offset (of the Comp unit Header)
+		Adduint32(Ctxt, s, culength)          // 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))
+			name := dwa.data.(string)
+			if die.sym == nil {
+				fmt.Println("Missing sym for ", name)
+			}
+			adddwarfref(Ctxt, s, die.sym, 4)
+			Addstring(s, name)
 		}
 
-		Thearch.Lput(0)
+		Adduint32(Ctxt, s, 0)
 
-		here := Cpos()
-		Cseek(sectionstart)
-		Thearch.Lput(uint32(here - sectionstart - 4)) // exclude the length field.
-		Cseek(here)
+		setuint32(Ctxt, s, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field.
 	}
 
-	return sectionstart
+	return s
 }
 
 /*
  *  emit .debug_aranges.  _info must have been written before,
  *  because we need die->offs of dw_globals.
  */
-func writearanges() int64 {
-	sectionstart := Cpos()
+func writearanges(prev *LSym) *LSym {
+	s := Linklookup(Ctxt, ".debug_aranges", 0)
+	s.Type = obj.SDWARFSECT
 	// The first tuple is aligned to a multiple of the size of a single tuple
 	// (twice the size of an address)
-	headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize*2))) // don't count unit_length field itself
+	headersize := int(Rnd(4+2+4+1+1, int64(SysArch.PtrSize*2))) // don't count unit_length field itself
 
 	for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
 		b := getattr(compunit, DW_AT_low_pc)
@@ -1961,78 +1888,46 @@ func writearanges() int64 {
 		}
 
 		// 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))
-		}
+		unitlength := uint32(headersize) + 4*uint32(SysArch.PtrSize) - 4
+		Adduint32(Ctxt, s, unitlength) // unit_length (*)
+		Adduint16(Ctxt, s, 2)          // dwarf version (appendix F)
 
-		Cput(uint8(Thearch.Ptrsize))        // address_size
-		Cput(0)                             // segment_size
-		strnput("", headersize-(4+2+4+1+1)) // align to thearch.ptrsize
+		adddwarfref(Ctxt, s, compunit.sym, 4)
 
-		if Linkmode == LinkExternal {
-			adddwarfrel(arangessec, b.data.(*LSym), sectionstart, Thearch.Ptrsize, b.value-(b.data.(*LSym)).Value)
-		} else {
-			addrput(b.value)
+		Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size
+		Adduint8(Ctxt, s, 0)                      // segment_size
+		padding := headersize - (4 + 2 + 4 + 1 + 1)
+		for i := 0; i < padding; i++ {
+			Adduint8(Ctxt, s, 0)
 		}
 
-		addrput(e.value - b.value)
-		addrput(0)
-		addrput(0)
+		Addaddrplus(Ctxt, s, b.data.(*LSym), b.value-(b.data.(*LSym)).Value)
+		addrput(s, e.value-b.value)
+		addrput(s, 0)
+		addrput(s, 0)
 	}
-
-	Cflush()
-	return sectionstart
-}
-
-func writegdbscript() int64 {
-	sectionstart := Cpos()
-
-	if gdbscript != "" {
-		Cput(1) // magic 1 byte?
-		strnput(gdbscript, len(gdbscript)+1)
-		Cflush()
+	if s.Size > 0 {
+		prev.Next = s
+		prev = s
 	}
-
-	return sectionstart
+	return prev
 }
 
-func align(size int64) {
-	if HEADTYPE == obj.Hwindows { // Only Windows PE need section align.
-		strnput("", int(Rnd(size, PEFILEALIGN)-size))
-	}
-}
+func writegdbscript(prev *LSym) *LSym {
 
-func writedwarfreloc(s *LSym) int64 {
-	start := Cpos()
-	for ri := 0; ri < len(s.R); ri++ {
-		r := &s.R[ri]
-		i := -1
-		if Iself {
-			i = Thearch.Elfreloc1(r, int64(r.Off))
-		} else if HEADTYPE == obj.Hdarwin {
-			i = Thearch.Machoreloc1(r, int64(r.Off))
-		}
-		if i < 0 {
-			Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
-		}
+	if gdbscript != "" {
+		s := Linklookup(Ctxt, ".debug_gdb_scripts", 0)
+		s.Type = obj.SDWARFSECT
+		prev.Next = s
+		prev = s
+		Adduint8(Ctxt, s, 1) // magic 1 byte?
+		Addstring(s, gdbscript)
 	}
 
-	return start
+	return prev
 }
 
-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
-}
+var prototypedies map[string]*DWDie
 
 /*
  * This is the main entry point for generating dwarf.  After emitting
@@ -2043,58 +1938,52 @@ func addmachodwarfsect(prev *Section, name string) *Section {
  * passes.
  *
  */
-func Dwarfemitdebugsections() {
+func dwarfgeneratedebugsyms() {
 	if Debug['w'] != 0 { // disable dwarf
 		return
 	}
+	if Debug['s'] != 0 && HEADTYPE != obj.Hdarwin {
+		return
+	}
+	if HEADTYPE == obj.Hplan9 {
+		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
-		}
+	if Debug['v'] != 0 {
+		fmt.Fprintf(Bso, "%5.2f dwarf\n", obj.Cputime())
 	}
 
 	// 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, "<unspecified>", 0)
 
-	newdie(&dwtypes, DW_ABRV_NULLTYPE, "void")
-	newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer")
+	newdie(&dwtypes, DW_ABRV_NULLTYPE, "void", 0)
+	newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer", 0)
 
-	die := newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr") // needed for array size
+	die := newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr", 0) // 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_byte_size, DW_CLS_CONSTANT, int64(SysArch.PtrSize), 0)
 	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, obj.KindUintptr, 0)
 
+	// Prototypes needed for type synthesis.
+	prototypedies = map[string]*DWDie{
+		"type.runtime.stringStructDWARF": nil,
+		"type.runtime.slice":             nil,
+		"type.runtime.hmap":              nil,
+		"type.runtime.bmap":              nil,
+		"type.runtime.sudog":             nil,
+		"type.runtime.waitq":             nil,
+		"type.runtime.hchan":             nil,
+	}
+
 	// Needed by the prettyprinter code for interface inspection.
 	defgotype(lookup_or_diag("type.runtime._type"))
 
@@ -2103,12 +1992,10 @@ func Dwarfemitdebugsections() {
 
 	genasmsym(defdwsymb)
 
-	writeabbrev()
-	align(abbrevsize)
-	writelines()
-	align(linesize)
-	writeframes()
-	align(framesize)
+	dwarfp = writeabbrev()
+	last := dwarfp
+	last = writelines(last)
+	last = writeframes(last)
 
 	synthesizestringtypes(dwtypes.child)
 	synthesizeslicetypes(dwtypes.child)
@@ -2122,412 +2009,61 @@ func Dwarfemitdebugsections() {
 	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)
+	// Need to reorder symbols so SDWARFINFO is after all SDWARFSECT
+	// (but we need to generate dies before writepub)
+	writeinfo(last)
+	infosyms := last.Next
 
-	linereloco = writedwarfreloc(linesec)
-	linerelocsize = Cpos() - linereloco
-	align(linerelocsize)
-
-	framereloco = writedwarfreloc(framesec)
-	framerelocsize = Cpos() - framereloco
-	align(framerelocsize)
+	last = writepub(".debug_pubnames", ispubname, last)
+	last = writepub(".debug_pubtypes", ispubtype, last)
+	last = writearanges(last)
+	last = writegdbscript(last)
+	last.Next = infosyms
 }
 
 /*
  *  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")
+	Addstring(shstrtab, ".debug_abbrev")
+	Addstring(shstrtab, ".debug_aranges")
+	Addstring(shstrtab, ".debug_frame")
+	Addstring(shstrtab, ".debug_info")
+	Addstring(shstrtab, ".debug_line")
+	Addstring(shstrtab, ".debug_pubnames")
+	Addstring(shstrtab, ".debug_pubtypes")
+	Addstring(shstrtab, ".debug_gdb_scripts")
 	if Linkmode == LinkExternal {
-		switch Thearch.Thechar {
-		case '0', '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
+		Addstring(shstrtab, elfRelType+".debug_info")
+		Addstring(shstrtab, elfRelType+".debug_aranges")
+		Addstring(shstrtab, elfRelType+".debug_line")
+		Addstring(shstrtab, elfRelType+".debug_frame")
+		Addstring(shstrtab, elfRelType+".debug_pubnames")
+		Addstring(shstrtab, elfRelType+".debug_pubtypes")
 	}
 }
 
 // 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 '0', '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
+		return
 	}
+	sym := Linklookup(Ctxt, ".debug_info", 0)
+	putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
+	sym = Linklookup(Ctxt, ".debug_abbrev", 0)
+	putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
+	sym = Linklookup(Ctxt, ".debug_line", 0)
+	putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
+	sym = Linklookup(Ctxt, ".debug_frame", 0)
+	putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
 }
 
 /*
@@ -2537,13 +2073,12 @@ 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)
+	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+		h := newPEDWARFSection(sect.Name, int64(sect.Length))
+		fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff
+		if uint64(h.PointerToRawData) != fileoff {
+			Diag("%s.PointerToRawData = %#x, want %#x", sect.Name, h.PointerToRawData, fileoff)
+			errorexit()
+		}
+	}
 }
diff --git a/src/cmd/link/internal/ld/dwarf_defs.go b/src/cmd/link/internal/ld/dwarf_defs.go
index 61389d9..c52879c 100644
--- a/src/cmd/link/internal/ld/dwarf_defs.go
+++ b/src/cmd/link/internal/ld/dwarf_defs.go
@@ -116,7 +116,7 @@ const (
 	DW_CHILDREN_yes = 0x01
 )
 
-// Not from the spec, but logicaly belongs here
+// Not from the spec, but logically belongs here
 const (
 	DW_CLS_ADDRESS = 0x01 + iota
 	DW_CLS_BLOCK
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 6d34978..39d3609 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -6,9 +6,10 @@ package ld
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"crypto/sha1"
 	"encoding/binary"
-	"fmt"
+	"encoding/hex"
 	"path/filepath"
 	"sort"
 	"strings"
@@ -28,7 +29,7 @@ import (
  *
  * 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.
+ * 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
@@ -488,6 +489,55 @@ const (
 	R_386_IRELATIVE     = 42
 	R_386_GOT32X        = 43
 
+	R_MIPS_NONE            = 0
+	R_MIPS_16              = 1
+	R_MIPS_32              = 2
+	R_MIPS_REL32           = 3
+	R_MIPS_26              = 4
+	R_MIPS_HI16            = 5
+	R_MIPS_LO16            = 6
+	R_MIPS_GPREL16         = 7
+	R_MIPS_LITERAL         = 8
+	R_MIPS_GOT16           = 9
+	R_MIPS_PC16            = 10
+	R_MIPS_CALL16          = 11
+	R_MIPS_GPREL32         = 12
+	R_MIPS_SHIFT5          = 16
+	R_MIPS_SHIFT6          = 17
+	R_MIPS_64              = 18
+	R_MIPS_GOT_DISP        = 19
+	R_MIPS_GOT_PAGE        = 20
+	R_MIPS_GOT_OFST        = 21
+	R_MIPS_GOT_HI16        = 22
+	R_MIPS_GOT_LO16        = 23
+	R_MIPS_SUB             = 24
+	R_MIPS_INSERT_A        = 25
+	R_MIPS_INSERT_B        = 26
+	R_MIPS_DELETE          = 27
+	R_MIPS_HIGHER          = 28
+	R_MIPS_HIGHEST         = 29
+	R_MIPS_CALL_HI16       = 30
+	R_MIPS_CALL_LO16       = 31
+	R_MIPS_SCN_DISP        = 32
+	R_MIPS_REL16           = 33
+	R_MIPS_ADD_IMMEDIATE   = 34
+	R_MIPS_PJUMP           = 35
+	R_MIPS_RELGOT          = 36
+	R_MIPS_JALR            = 37
+	R_MIPS_TLS_DTPMOD32    = 38
+	R_MIPS_TLS_DTPREL32    = 39
+	R_MIPS_TLS_DTPMOD64    = 40
+	R_MIPS_TLS_DTPREL64    = 41
+	R_MIPS_TLS_GD          = 42
+	R_MIPS_TLS_LDM         = 43
+	R_MIPS_TLS_DTPREL_HI16 = 44
+	R_MIPS_TLS_DTPREL_LO16 = 45
+	R_MIPS_TLS_GOTTPREL    = 46
+	R_MIPS_TLS_TPREL32     = 47
+	R_MIPS_TLS_TPREL64     = 48
+	R_MIPS_TLS_TPREL_HI16  = 49
+	R_MIPS_TLS_TPREL_LO16  = 50
+
 	R_PPC_NONE            = 0
 	R_PPC_ADDR32          = 1
 	R_PPC_ADDR24          = 2
@@ -646,6 +696,68 @@ const (
 	R_SPARC_UA64     = 54
 	R_SPARC_UA16     = 55
 
+	R_390_NONE        = 0
+	R_390_8           = 1
+	R_390_12          = 2
+	R_390_16          = 3
+	R_390_32          = 4
+	R_390_PC32        = 5
+	R_390_GOT12       = 6
+	R_390_GOT32       = 7
+	R_390_PLT32       = 8
+	R_390_COPY        = 9
+	R_390_GLOB_DAT    = 10
+	R_390_JMP_SLOT    = 11
+	R_390_RELATIVE    = 12
+	R_390_GOTOFF      = 13
+	R_390_GOTPC       = 14
+	R_390_GOT16       = 15
+	R_390_PC16        = 16
+	R_390_PC16DBL     = 17
+	R_390_PLT16DBL    = 18
+	R_390_PC32DBL     = 19
+	R_390_PLT32DBL    = 20
+	R_390_GOTPCDBL    = 21
+	R_390_64          = 22
+	R_390_PC64        = 23
+	R_390_GOT64       = 24
+	R_390_PLT64       = 25
+	R_390_GOTENT      = 26
+	R_390_GOTOFF16    = 27
+	R_390_GOTOFF64    = 28
+	R_390_GOTPLT12    = 29
+	R_390_GOTPLT16    = 30
+	R_390_GOTPLT32    = 31
+	R_390_GOTPLT64    = 32
+	R_390_GOTPLTENT   = 33
+	R_390_GOTPLTOFF16 = 34
+	R_390_GOTPLTOFF32 = 35
+	R_390_GOTPLTOFF64 = 36
+	R_390_TLS_LOAD    = 37
+	R_390_TLS_GDCALL  = 38
+	R_390_TLS_LDCALL  = 39
+	R_390_TLS_GD32    = 40
+	R_390_TLS_GD64    = 41
+	R_390_TLS_GOTIE12 = 42
+	R_390_TLS_GOTIE32 = 43
+	R_390_TLS_GOTIE64 = 44
+	R_390_TLS_LDM32   = 45
+	R_390_TLS_LDM64   = 46
+	R_390_TLS_IE32    = 47
+	R_390_TLS_IE64    = 48
+	R_390_TLS_IEENT   = 49
+	R_390_TLS_LE32    = 50
+	R_390_TLS_LE64    = 51
+	R_390_TLS_LDO32   = 52
+	R_390_TLS_LDO64   = 53
+	R_390_TLS_DTPMOD  = 54
+	R_390_TLS_DTPOFF  = 55
+	R_390_TLS_TPOFF   = 56
+	R_390_20          = 57
+	R_390_GOT20       = 58
+	R_390_GOTPLT20    = 59
+	R_390_TLS_GOTIE20 = 60
+
 	ARM_MAGIC_TRAMP_NUMBER = 0x5c000003
 )
 
@@ -769,19 +881,22 @@ const (
 	NSECT = 48
 )
 
-var Iself bool
-
-var Nelfsym int = 1
-
-var elf64 bool
+var (
+	Iself bool
 
-var ehdr ElfEhdr
+	Nelfsym int = 1
 
-var phdr [NSECT]*ElfPhdr
+	elf64 bool
+	// Either ".rel" or ".rela" depending on which type of relocation the
+	// target platform uses.
+	elfRelType string
 
-var shdr [NSECT]*ElfShdr
+	ehdr ElfEhdr
+	phdr [NSECT]*ElfPhdr
+	shdr [NSECT]*ElfShdr
 
-var interp string
+	interp string
+)
 
 type Elfstring struct {
 	s   string
@@ -801,18 +916,23 @@ var buildinfo []byte
 func Elfinit() {
 	Iself = true
 
-	switch Thearch.Thechar {
+	if SysArch.InFamily(sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.S390X) {
+		elfRelType = ".rela"
+	} else {
+		elfRelType = ".rel"
+	}
+
+	switch SysArch.Family {
 	// 64-bit architectures
-	case '9':
+	case sys.PPC64, sys.S390X:
 		if Ctxt.Arch.ByteOrder == binary.BigEndian {
 			ehdr.flags = 1 /* Version 1 ABI */
 		} else {
 			ehdr.flags = 2 /* Version 2 ABI */
 		}
 		fallthrough
-
-	case '0', '6', '7':
-		if Thearch.Thechar == '0' {
+	case sys.AMD64, sys.ARM64, sys.MIPS64:
+		if SysArch.Family == sys.MIPS64 {
 			ehdr.flags = 0x20000000 /* MIPS 3 */
 		}
 		elf64 = true
@@ -825,7 +945,7 @@ func Elfinit() {
 
 	// we use EABI on both linux/arm and freebsd/arm.
 	// 32-bit architectures
-	case '5':
+	case sys.ARM:
 		// we use EABI on both linux/arm and freebsd/arm.
 		if HEADTYPE == obj.Hlinux || HEADTYPE == obj.Hfreebsd {
 			// We set a value here that makes no indication of which
@@ -839,7 +959,6 @@ func Elfinit() {
 			ehdr.flags = 0x5000002 // has entry point, Version5 EABI
 		}
 		fallthrough
-
 	default:
 		ehdr.phoff = ELF32HDRSIZE
 		/* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
@@ -1042,19 +1161,15 @@ func elfwritehdr() uint32 {
 }
 
 /* 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 {
+func elfhash(name string) uint32 {
+	var h uint32
+	for i := 0; i < len(name); i++ {
+		h = (h << 4) + uint32(name[i])
+		if g := h & 0xf0000000; g != 0 {
 			h ^= g >> 24
 		}
 		h &= 0x0fffffff
 	}
-
 	return h
 }
 
@@ -1200,45 +1315,30 @@ func elfwriteopenbsdsig() int {
 }
 
 func addbuildinfo(val string) {
-	var j int
-
-	if val[0] != '0' || val[1] != 'x' {
+	if !strings.HasPrefix(val, "0x") {
 		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 hex.DecodedLen(len(val)) > maxLen {
+		Exitf("-B option too long (max %d digits): %s", maxLen, ov)
+	}
 
-		const maxLen = 32
-		if i >= maxLen {
-			Exitf("-B option too long (max %d digits): %s", maxLen, ov)
+	b, err := hex.DecodeString(val)
+	if err != nil {
+		if err == hex.ErrLength {
+			Exitf("-B argument must have even number of digits: %s", ov)
 		}
-
-		buildinfo = append(buildinfo, uint8(b))
-		i++
+		if inv, ok := err.(hex.InvalidByteError); ok {
+			Exitf("-B argument contains invalid hex digit %c: %s", byte(inv), ov)
+		}
+		Exitf("-B argument contains invalid hex: %s", ov)
 	}
 
-	buildinfo = buildinfo[:i]
+	buildinfo = b
 }
 
 // Build info note
@@ -1346,7 +1446,7 @@ func elfdynhash() {
 	nsym := Nelfsym
 	s := Linklookup(Ctxt, ".hash", 0)
 	s.Type = obj.SELFROSECT
-	s.Reachable = true
+	s.Attr |= AttrReachable
 
 	i := nsym
 	nbucket := 1
@@ -1361,9 +1461,7 @@ func elfdynhash() {
 	buckets := make([]uint32, nbucket)
 
 	var b int
-	var hc uint32
-	var name string
-	for sy := Ctxt.Allsym; sy != nil; sy = sy.Allsym {
+	for _, sy := range Ctxt.Allsym {
 		if sy.Dynid <= 0 {
 			continue
 		}
@@ -1372,21 +1470,33 @@ func elfdynhash() {
 			need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib, sy.Dynimpvers)
 		}
 
-		name = sy.Extname
-		hc = elfhash([]byte(name))
+		name := sy.Extname
+		hc := elfhash(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])
+	// s390x (ELF64) hash table entries are 8 bytes
+	if SysArch.Family == sys.S390X {
+		Adduint64(Ctxt, s, uint64(nbucket))
+		Adduint64(Ctxt, s, uint64(nsym))
+		for i := 0; i < nbucket; i++ {
+			Adduint64(Ctxt, s, uint64(buckets[i]))
+		}
+		for i := 0; i < nsym; i++ {
+			Adduint64(Ctxt, s, uint64(chain[i]))
+		}
+	} else {
+		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
@@ -1420,7 +1530,7 @@ func elfdynhash() {
 			i++
 
 			// aux struct
-			Adduint32(Ctxt, s, elfhash([]byte(x.vers)))           // hash
+			Adduint32(Ctxt, s, elfhash(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
@@ -1453,21 +1563,15 @@ func elfdynhash() {
 		elfwritedynentsym(s, DT_VERSYM, Linklookup(Ctxt, ".gnu.version", 0))
 	}
 
-	switch Thearch.Thechar {
-	case '0', '6', '7', '9':
-		sy := Linklookup(Ctxt, ".rela.plt", 0)
-		if sy.Size > 0 {
+	sy := Linklookup(Ctxt, elfRelType+".plt", 0)
+	if sy.Size > 0 {
+		if elfRelType == ".rela" {
 			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 {
+		} else {
 			Elfwritedynent(s, DT_PLTREL, DT_REL)
-			elfwritedynentsymsize(s, DT_PLTRELSZ, sy)
-			elfwritedynentsym(s, DT_JMPREL, sy)
 		}
+		elfwritedynentsymsize(s, DT_PLTRELSZ, sy)
+		elfwritedynentsym(s, DT_JMPREL, sy)
 	}
 
 	Elfwritedynent(s, DT_NULL, 0)
@@ -1565,6 +1669,9 @@ func elfshbits(sect *Section) *ElfShdr {
 		sh.flags |= SHF_TLS
 		sh.type_ = SHT_NOBITS
 	}
+	if strings.HasPrefix(sect.Name, ".debug") {
+		sh.flags = 0
+	}
 
 	if Linkmode != LinkExternal {
 		sh.addr = sect.Vaddr
@@ -1591,33 +1698,28 @@ func elfshreloc(sect *Section) *ElfShdr {
 		return nil
 	}
 
-	var prefix string
 	var typ int
-	switch Thearch.Thechar {
-	case '0', '6', '7', '9':
-		prefix = ".rela"
+	if elfRelType == ".rela" {
 		typ = SHT_RELA
-	default:
-		prefix = ".rel"
+	} else {
 		typ = SHT_REL
 	}
 
-	buf := fmt.Sprintf("%s%s", prefix, sect.Name)
-	sh := elfshname(buf)
+	sh := elfshname(elfRelType + sect.Name)
 	sh.type_ = uint32(typ)
-	sh.entsize = uint64(Thearch.Regsize) * 2
+	sh.entsize = uint64(SysArch.RegSize) * 2
 	if typ == SHT_RELA {
-		sh.entsize += uint64(Thearch.Regsize)
+		sh.entsize += uint64(SysArch.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)
+	sh.addralign = uint64(SysArch.RegSize)
 	return sh
 }
 
-func elfrelocsect(sect *Section, first *LSym) {
+func elfrelocsect(sect *Section, syms []*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 {
@@ -1628,21 +1730,19 @@ func elfrelocsect(sect *Section, first *LSym) {
 	}
 
 	sect.Reloff = uint64(Cpos())
-	var sym *LSym
-	for sym = first; sym != nil; sym = sym.Next {
-		if !sym.Reachable {
+	for i, s := range syms {
+		if !s.Attr.Reachable() {
 			continue
 		}
-		if uint64(sym.Value) >= sect.Vaddr {
+		if uint64(s.Value) >= sect.Vaddr {
+			syms = syms[i:]
 			break
 		}
 	}
 
 	eaddr := int32(sect.Vaddr + sect.Length)
-	var r *Reloc
-	var ri int
-	for ; sym != nil; sym = sym.Next {
-		if !sym.Reachable {
+	for _, sym := range syms {
+		if !sym.Attr.Reachable() {
 			continue
 		}
 		if sym.Value >= int64(eaddr) {
@@ -1650,8 +1750,8 @@ func elfrelocsect(sect *Section, first *LSym) {
 		}
 		Ctxt.Cursym = sym
 
-		for ri = 0; ri < len(sym.R); ri++ {
-			r = &sym.R[ri]
+		for ri := 0; ri < len(sym.R); ri++ {
+			r := &sym.R[ri]
 			if r.Done != 0 {
 				continue
 			}
@@ -1659,7 +1759,6 @@ func elfrelocsect(sect *Section, first *LSym) {
 				Diag("missing xsym in relocation")
 				continue
 			}
-
 			if r.Xsym.ElfsymForReloc() == 0 {
 				Diag("reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
 			}
@@ -1687,11 +1786,14 @@ func Elfemitreloc() {
 	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		elfrelocsect(sect, datap)
 	}
+	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+		elfrelocsect(sect, list2slice(dwarfp))
+	}
 }
 
 func addgonote(sectionName string, tag uint32, desc []byte) {
 	s := Linklookup(Ctxt, sectionName, 0)
-	s.Reachable = true
+	s.Attr |= AttrReachable
 	s.Type = obj.SELFROSECT
 	// namesz
 	Adduint32(Ctxt, s, uint32(len(ELF_NOTE_GO_NAME)))
@@ -1721,7 +1823,7 @@ func doelf() {
 	shstrtab := Linklookup(Ctxt, ".shstrtab", 0)
 
 	shstrtab.Type = obj.SELFROSECT
-	shstrtab.Reachable = true
+	shstrtab.Attr |= AttrReachable
 
 	Addstring(shstrtab, "")
 	Addstring(shstrtab, ".text")
@@ -1760,36 +1862,23 @@ func doelf() {
 		relro_prefix = ".data.rel.ro"
 	}
 	Addstring(shstrtab, relro_prefix+".typelink")
+	Addstring(shstrtab, relro_prefix+".itablink")
 	Addstring(shstrtab, relro_prefix+".gosymtab")
 	Addstring(shstrtab, relro_prefix+".gopclntab")
 
 	if Linkmode == LinkExternal {
 		Debug['d'] = 1
 
-		switch Thearch.Thechar {
-		case '0', '6', '7', '9':
-			Addstring(shstrtab, ".rela.text")
-			Addstring(shstrtab, ".rela.rodata")
-			Addstring(shstrtab, ".rela"+relro_prefix+".typelink")
-			Addstring(shstrtab, ".rela"+relro_prefix+".gosymtab")
-			Addstring(shstrtab, ".rela"+relro_prefix+".gopclntab")
-			Addstring(shstrtab, ".rela.noptrdata")
-			Addstring(shstrtab, ".rela.data")
-			if UseRelro() {
-				Addstring(shstrtab, ".rela.data.rel.ro")
-			}
-
-		default:
-			Addstring(shstrtab, ".rel.text")
-			Addstring(shstrtab, ".rel.rodata")
-			Addstring(shstrtab, ".rel"+relro_prefix+".typelink")
-			Addstring(shstrtab, ".rel"+relro_prefix+".gosymtab")
-			Addstring(shstrtab, ".rel"+relro_prefix+".gopclntab")
-			Addstring(shstrtab, ".rel.noptrdata")
-			Addstring(shstrtab, ".rel.data")
-			if UseRelro() {
-				Addstring(shstrtab, ".rel.data.rel.ro")
-			}
+		Addstring(shstrtab, elfRelType+".text")
+		Addstring(shstrtab, elfRelType+".rodata")
+		Addstring(shstrtab, elfRelType+relro_prefix+".typelink")
+		Addstring(shstrtab, elfRelType+relro_prefix+".itablink")
+		Addstring(shstrtab, elfRelType+relro_prefix+".gosymtab")
+		Addstring(shstrtab, elfRelType+relro_prefix+".gopclntab")
+		Addstring(shstrtab, elfRelType+".noptrdata")
+		Addstring(shstrtab, elfRelType+".data")
+		if UseRelro() {
+			Addstring(shstrtab, elfRelType+".data.rel.ro")
 		}
 
 		// add a .note.GNU-stack section to mark the stack as non-executable
@@ -1812,12 +1901,7 @@ func doelf() {
 
 	if hasinitarr {
 		Addstring(shstrtab, ".init_array")
-		switch Thearch.Thechar {
-		case '0', '6', '7', '9':
-			Addstring(shstrtab, ".rela.init_array")
-		default:
-			Addstring(shstrtab, ".rel.init_array")
-		}
+		Addstring(shstrtab, elfRelType+".init_array")
 	}
 
 	if Debug['s'] == 0 {
@@ -1832,21 +1916,15 @@ func doelf() {
 		Addstring(shstrtab, ".interp")
 		Addstring(shstrtab, ".hash")
 		Addstring(shstrtab, ".got")
-		if Thearch.Thechar == '9' {
+		if SysArch.Family == sys.PPC64 {
 			Addstring(shstrtab, ".glink")
 		}
 		Addstring(shstrtab, ".got.plt")
 		Addstring(shstrtab, ".dynamic")
 		Addstring(shstrtab, ".dynsym")
 		Addstring(shstrtab, ".dynstr")
-		switch Thearch.Thechar {
-		case '0', '6', '7', '9':
-			Addstring(shstrtab, ".rela")
-			Addstring(shstrtab, ".rela.plt")
-		default:
-			Addstring(shstrtab, ".rel")
-			Addstring(shstrtab, ".rel.plt")
-		}
+		Addstring(shstrtab, elfRelType)
+		Addstring(shstrtab, elfRelType+".plt")
 
 		Addstring(shstrtab, ".plt")
 		Addstring(shstrtab, ".gnu.version")
@@ -1856,11 +1934,10 @@ func doelf() {
 		s := Linklookup(Ctxt, ".dynsym", 0)
 
 		s.Type = obj.SELFROSECT
-		s.Reachable = true
-		switch Thearch.Thechar {
-		case '0', '6', '7', '9':
+		s.Attr |= AttrReachable
+		if elf64 {
 			s.Size += ELF64SYMSIZE
-		default:
+		} else {
 			s.Size += ELF32SYMSIZE
 		}
 
@@ -1868,49 +1945,44 @@ func doelf() {
 		s = Linklookup(Ctxt, ".dynstr", 0)
 
 		s.Type = obj.SELFROSECT
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		if s.Size == 0 {
 			Addstring(s, "")
 		}
 		dynstr := s
 
 		/* relocation table */
-		switch Thearch.Thechar {
-		case '0', '6', '7', '9':
-			s = Linklookup(Ctxt, ".rela", 0)
-		default:
-			s = Linklookup(Ctxt, ".rel", 0)
-		}
-		s.Reachable = true
+		s = Linklookup(Ctxt, elfRelType, 0)
+		s.Attr |= AttrReachable
 		s.Type = obj.SELFROSECT
 
 		/* global offset table */
 		s = Linklookup(Ctxt, ".got", 0)
 
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		s.Type = obj.SELFGOT // writable
 
 		/* ppc64 glink resolver */
-		if Thearch.Thechar == '9' {
+		if SysArch.Family == sys.PPC64 {
 			s := Linklookup(Ctxt, ".glink", 0)
-			s.Reachable = true
+			s.Attr |= AttrReachable
 			s.Type = obj.SELFRXSECT
 		}
 
 		/* hash */
 		s = Linklookup(Ctxt, ".hash", 0)
 
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		s.Type = obj.SELFROSECT
 
 		s = Linklookup(Ctxt, ".got.plt", 0)
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		s.Type = obj.SELFSECT // writable
 
 		s = Linklookup(Ctxt, ".plt", 0)
 
-		s.Reachable = true
-		if Thearch.Thechar == '9' {
+		s.Attr |= AttrReachable
+		if SysArch.Family == sys.PPC64 {
 			// In the ppc64 ABI, .plt is a data section
 			// written by the dynamic linker.
 			s.Type = obj.SELFSECT
@@ -1920,27 +1992,22 @@ func doelf() {
 
 		Thearch.Elfsetupplt()
 
-		switch Thearch.Thechar {
-		case '0', '6', '7', '9':
-			s = Linklookup(Ctxt, ".rela.plt", 0)
-		default:
-			s = Linklookup(Ctxt, ".rel.plt", 0)
-		}
-		s.Reachable = true
+		s = Linklookup(Ctxt, elfRelType+".plt", 0)
+		s.Attr |= AttrReachable
 		s.Type = obj.SELFROSECT
 
 		s = Linklookup(Ctxt, ".gnu.version", 0)
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		s.Type = obj.SELFROSECT
 
 		s = Linklookup(Ctxt, ".gnu.version_r", 0)
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		s.Type = obj.SELFROSECT
 
 		/* define dynamic elf table */
 		s = Linklookup(Ctxt, ".dynamic", 0)
 
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		s.Type = obj.SELFSECT // writable
 
 		/*
@@ -1949,20 +2016,18 @@ func doelf() {
 		elfwritedynentsym(s, DT_HASH, Linklookup(Ctxt, ".hash", 0))
 
 		elfwritedynentsym(s, DT_SYMTAB, Linklookup(Ctxt, ".dynsym", 0))
-		switch Thearch.Thechar {
-		case '0', '6', '7', '9':
+		if elf64 {
 			Elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE)
-		default:
+		} else {
 			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 '0', '6', '7', '9':
+		if elfRelType == ".rela" {
 			elfwritedynentsym(s, DT_RELA, Linklookup(Ctxt, ".rela", 0))
 			elfwritedynentsymsize(s, DT_RELASZ, Linklookup(Ctxt, ".rela", 0))
 			Elfwritedynent(s, DT_RELAENT, ELF64RELASIZE)
-		default:
+		} else {
 			elfwritedynentsym(s, DT_REL, Linklookup(Ctxt, ".rel", 0))
 			elfwritedynentsymsize(s, DT_RELSZ, Linklookup(Ctxt, ".rel", 0))
 			Elfwritedynent(s, DT_RELENT, ELF32RELSIZE)
@@ -1972,13 +2037,15 @@ func doelf() {
 			Elfwritedynent(s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
 		}
 
-		if Thearch.Thechar == '9' {
+		if SysArch.Family == sys.PPC64 {
 			elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".plt", 0))
+		} else if SysArch.Family == sys.S390X {
+			elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got", 0))
 		} else {
 			elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got.plt", 0))
 		}
 
-		if Thearch.Thechar == '9' {
+		if SysArch.Family == sys.PPC64 {
 			Elfwritedynent(s, DT_PPC64_OPT, 0)
 		}
 
@@ -1993,10 +2060,10 @@ func doelf() {
 		// 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.Attr |= AttrLocal
 		s.Type = obj.SRODATA
-		s.Special = 1
-		s.Reachable = true
+		s.Attr |= AttrSpecial
+		s.Attr |= AttrReachable
 		s.Size = int64(sha1.Size)
 
 		sort.Sort(byPkg(Ctxt.Library))
@@ -2005,7 +2072,7 @@ func doelf() {
 			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))
+		addgonote(".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, pkglistfornote)
 		var deplist []string
 		for _, shlib := range Ctxt.Shlibs {
 			deplist = append(deplist, filepath.Base(shlib.Path))
@@ -2050,25 +2117,30 @@ func Asmbelfsetup() {
 	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		elfshalloc(sect)
 	}
+	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+		elfshalloc(sect)
+	}
 }
 
 func Asmbelf(symo int64) {
 	eh := getElfEhdr()
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Exitf("unknown architecture in asmbelf: %v", Thearch.Thechar)
-	case '0':
+		Exitf("unknown architecture in asmbelf: %v", SysArch.Family)
+	case sys.MIPS64:
 		eh.machine = EM_MIPS
-	case '5':
+	case sys.ARM:
 		eh.machine = EM_ARM
-	case '6':
+	case sys.AMD64:
 		eh.machine = EM_X86_64
-	case '7':
+	case sys.ARM64:
 		eh.machine = EM_AARCH64
-	case '8':
+	case sys.I386:
 		eh.machine = EM_386
-	case '9':
+	case sys.PPC64:
 		eh.machine = EM_PPC64
+	case sys.S390X:
+		eh.machine = EM_S390
 	}
 
 	elfreserve := int64(ELFRESERVE)
@@ -2223,7 +2295,7 @@ func Asmbelf(symo int64) {
 		} else {
 			sh.entsize = ELF32SYMSIZE
 		}
-		sh.addralign = uint64(Thearch.Regsize)
+		sh.addralign = uint64(SysArch.RegSize)
 		sh.link = uint32(elfshname(".dynstr").shnum)
 
 		// sh->info = index of first non-local symbol (number of local symbols)
@@ -2247,19 +2319,18 @@ func Asmbelf(symo int64) {
 			sh = elfshname(".gnu.version_r")
 			sh.type_ = SHT_GNU_VERNEED
 			sh.flags = SHF_ALLOC
-			sh.addralign = uint64(Thearch.Regsize)
+			sh.addralign = uint64(SysArch.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:
+		if elfRelType == ".rela" {
 			sh := elfshname(".rela.plt")
 			sh.type_ = SHT_RELA
 			sh.flags = SHF_ALLOC
 			sh.entsize = ELF64RELASIZE
-			sh.addralign = uint64(Thearch.Regsize)
+			sh.addralign = uint64(SysArch.RegSize)
 			sh.link = uint32(elfshname(".dynsym").shnum)
 			sh.info = uint32(elfshname(".plt").shnum)
 			shsym(sh, Linklookup(Ctxt, ".rela.plt", 0))
@@ -2271,8 +2342,7 @@ func Asmbelf(symo int64) {
 			sh.addralign = 8
 			sh.link = uint32(elfshname(".dynsym").shnum)
 			shsym(sh, Linklookup(Ctxt, ".rela", 0))
-
-		default:
+		} else {
 			sh := elfshname(".rel.plt")
 			sh.type_ = SHT_REL
 			sh.flags = SHF_ALLOC
@@ -2303,6 +2373,8 @@ func Asmbelf(symo int64) {
 		sh.flags = SHF_ALLOC + SHF_EXECINSTR
 		if eh.machine == EM_X86_64 {
 			sh.entsize = 16
+		} else if eh.machine == EM_S390 {
+			sh.entsize = 32
 		} else if eh.machine == EM_PPC64 {
 			// On ppc64, this is just a table of addresses
 			// filled by the dynamic linker
@@ -2322,15 +2394,15 @@ func Asmbelf(symo int64) {
 			sh := elfshname(".got")
 			sh.type_ = SHT_PROGBITS
 			sh.flags = SHF_ALLOC + SHF_WRITE
-			sh.entsize = uint64(Thearch.Regsize)
-			sh.addralign = uint64(Thearch.Regsize)
+			sh.entsize = uint64(SysArch.RegSize)
+			sh.addralign = uint64(SysArch.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)
+			sh.entsize = uint64(SysArch.RegSize)
+			sh.addralign = uint64(SysArch.RegSize)
 			shsym(sh, Linklookup(Ctxt, ".got.plt", 0))
 		}
 
@@ -2338,7 +2410,7 @@ func Asmbelf(symo int64) {
 		sh.type_ = SHT_HASH
 		sh.flags = SHF_ALLOC
 		sh.entsize = 4
-		sh.addralign = uint64(Thearch.Regsize)
+		sh.addralign = uint64(SysArch.RegSize)
 		sh.link = uint32(elfshname(".dynsym").shnum)
 		shsym(sh, Linklookup(Ctxt, ".hash", 0))
 
@@ -2347,8 +2419,8 @@ func Asmbelf(symo int64) {
 
 		sh.type_ = SHT_DYNAMIC
 		sh.flags = SHF_ALLOC + SHF_WRITE
-		sh.entsize = 2 * uint64(Thearch.Regsize)
-		sh.addralign = uint64(Thearch.Regsize)
+		sh.entsize = 2 * uint64(SysArch.RegSize)
+		sh.addralign = uint64(SysArch.RegSize)
 		sh.link = uint32(elfshname(".dynstr").shnum)
 		shsym(sh, Linklookup(Ctxt, ".dynamic", 0))
 		ph := newElfPhdr()
@@ -2374,7 +2446,7 @@ func Asmbelf(symo int64) {
 				ph.type_ = PT_TLS
 				ph.flags = PF_R
 				ph.memsz = tlssize
-				ph.align = uint64(Thearch.Regsize)
+				ph.align = uint64(SysArch.RegSize)
 			}
 		}
 	}
@@ -2383,12 +2455,12 @@ func Asmbelf(symo int64) {
 		ph := newElfPhdr()
 		ph.type_ = PT_GNU_STACK
 		ph.flags = PF_W + PF_R
-		ph.align = uint64(Thearch.Regsize)
+		ph.align = uint64(SysArch.RegSize)
 
 		ph = newElfPhdr()
 		ph.type_ = PT_PAX_FLAGS
 		ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
-		ph.align = uint64(Thearch.Regsize)
+		ph.align = uint64(SysArch.RegSize)
 	}
 
 elfobj:
@@ -2413,6 +2485,9 @@ elfobj:
 	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		elfshbits(sect)
 	}
+	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+		elfshbits(sect)
+	}
 
 	if Linkmode == LinkExternal {
 		for sect := Segtext.Sect; sect != nil; sect = sect.Next {
@@ -2424,7 +2499,14 @@ elfobj:
 		for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 			elfshreloc(sect)
 		}
-
+		for s := dwarfp; s != nil; s = s.Next {
+			if len(s.R) > 0 || s.Type == obj.SDWARFINFO {
+				elfshreloc(s.Sect)
+			}
+			if s.Type == obj.SDWARFINFO {
+				break
+			}
+		}
 		// add a .note.GNU-stack section to mark the stack as non-executable
 		sh := elfshname(".note.GNU-stack")
 
@@ -2438,8 +2520,8 @@ elfobj:
 		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.addralign = uint64(SysArch.RegSize)
+		sh.entsize = 8 + 2*uint64(SysArch.RegSize)
 		sh.link = uint32(elfshname(".strtab").shnum)
 		sh.info = uint32(elfglobalsymndx)
 
@@ -2448,8 +2530,6 @@ elfobj:
 		sh.off = uint64(symo) + uint64(Symsize)
 		sh.size = uint64(len(Elfstrdat))
 		sh.addralign = 1
-
-		dwarfaddelfheaders()
 	}
 
 	/* Main header */
@@ -2537,7 +2617,7 @@ func Elfadddynsym(ctxt *Link, s *LSym) {
 		/* type */
 		t := STB_GLOBAL << 4
 
-		if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
+		if s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
 			t |= STT_FUNC
 		} else {
 			t |= STT_OBJECT
@@ -2564,7 +2644,7 @@ func Elfadddynsym(ctxt *Link, s *LSym) {
 		/* size of object */
 		Adduint64(ctxt, d, uint64(s.Size))
 
-		if Thearch.Thechar == '6' && s.Cgoexport&CgoExportDynamic == 0 && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
+		if SysArch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
 			Elfwritedynent(Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
 		}
 	} else {
@@ -2585,16 +2665,16 @@ func Elfadddynsym(ctxt *Link, s *LSym) {
 			Addaddr(ctxt, d, s)
 		}
 
-		/* size */
-		Adduint32(ctxt, d, 0)
+		/* size of object */
+		Adduint32(ctxt, d, uint32(s.Size))
 
 		/* 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 {
+		if SysArch.Family == sys.I386 && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
 			t |= STT_FUNC
-		} else if Thearch.Thechar == '5' && s.Cgoexport&CgoExportDynamic != 0 && s.Type&obj.SMASK == obj.STEXT {
+		} else if SysArch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT {
 			t |= STT_FUNC
 		} else {
 			t |= STT_OBJECT
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index 28f0910..79cdae0 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -8,8 +8,10 @@ package ld
 
 import (
 	"bytes"
+	"cmd/internal/bio"
 	"cmd/internal/obj"
 	"fmt"
+	"io"
 	"os"
 	"strings"
 )
@@ -26,7 +28,7 @@ func expandpkg(t0 string, pkg string) string {
 //	once the dust settles, try to move some code to
 //		libmach, so that other linkers and ar can share.
 
-func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) {
+func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int) {
 	var p0, p1 int
 
 	if Debug['g'] != 0 {
@@ -48,7 +50,7 @@ func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int)
 	}
 
 	bdata := make([]byte, length)
-	if int64(obj.Bread(f, bdata)) != length {
+	if _, err := io.ReadFull(f, bdata); err != nil {
 		fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
 		if Debug['u'] != 0 {
 			errorexit()
@@ -57,71 +59,33 @@ func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int)
 	}
 	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
-	}
-
-	// \n$$B marks the beginning of binary export data - don't skip over the B
-	p0 += 3
-	for p0 < len(data) && data[p0] != '\n' && data[p0] != 'B' {
-		p0++
-	}
-
-	// second marks end of exports / beginning of local data
-	p1 = strings.Index(data[p0:], "\n$$\n")
-	if p1 < 0 && whence == Pkgdef {
-		p1 = len(data) - p0
-	}
-	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] != 'B' && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
-		p0++
-	}
-	// don't check this section if we have binary (B) export data
-	// TODO fix this eventually
-	if p0 < p1 && data[p0] != 'B' {
-		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
+	// process header lines
+	isSafe := false
+	isMain := false
+	for data != "" {
+		var line string
+		if i := strings.Index(data, "\n"); i >= 0 {
+			line, data = data[:i], data[i+1:]
+		} else {
+			line, data = data, ""
 		}
-
-		p0 += 8
-		for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
-			p0++
+		if line == "safe" {
+			isSafe = true
 		}
-		pname := p0
-		for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' {
-			p0++
+		if line == "main" {
+			isMain = true
 		}
-		if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) {
-			Exitf("load of unsafe package %s", filename)
+		if line == "" {
+			break
 		}
+	}
 
-		name := data[pname:p0]
-		for p0 < p1 && data[p0] != '\n' {
-			p0++
+	if whence == Pkgdef || whence == FileObj {
+		if pkg == "main" && !isMain {
+			Exitf("%s: not package main", filename)
 		}
-		if p0 < p1 {
-			p0++
-		}
-
-		if pkg == "main" && name != "main" {
-			Exitf("%s: not package main (package %s)", filename, name)
+		if Debug['u'] != 0 && whence != ArchiveObj && !isSafe {
+			Exitf("load of unsafe package %s", filename)
 		}
 	}
 
@@ -131,7 +95,7 @@ func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int)
 	}
 
 	// look for cgo section
-	p0 = strings.Index(data[p1:], "\n$$  // cgo")
+	p0 = strings.Index(data, "\n$$  // cgo")
 	if p0 >= 0 {
 		p0 += p1
 		i := strings.IndexByte(data[p0+1:], '\n')
@@ -279,7 +243,7 @@ func loadcgo(file string, pkg string, p string) {
 				s.Type = 0
 			}
 
-			if s.Cgoexport == 0 {
+			if !s.Attr.CgoExport() {
 				s.Extname = remote
 				dynexp = append(dynexp, s)
 			} else if s.Extname != remote {
@@ -289,9 +253,9 @@ func loadcgo(file string, pkg string, p string) {
 			}
 
 			if f[0] == "cgo_export_static" {
-				s.Cgoexport |= CgoExportStatic
+				s.Attr |= AttrCgoExportStatic
 			} else {
-				s.Cgoexport |= CgoExportDynamic
+				s.Attr |= AttrCgoExportDynamic
 			}
 			if local != f[1] {
 			}
@@ -367,160 +331,16 @@ func Adddynsym(ctxt *Link, s *LSym) {
 	}
 }
 
-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
-		}
-	}
-
+func fieldtrack(ctxt *Link) {
 	// record field tracking references
 	var buf bytes.Buffer
-	var p *LSym
-	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+	for _, s := range ctxt.Allsym {
 		if strings.HasPrefix(s.Name, "go.track.") {
-			s.Special = 1 // do not lay out in data segment
-			s.Hide = 1
-			if s.Reachable {
+			s.Attr |= AttrSpecial // do not lay out in data segment
+			s.Attr |= AttrHidden
+			if s.Attr.Reachable() {
 				buf.WriteString(s.Name[9:])
-				for p = s.Reachparent; p != nil; p = p.Reachparent {
+				for p := s.Reachparent; p != nil; p = p.Reachparent {
 					buf.WriteString("\t")
 					buf.WriteString(p.Name)
 				}
@@ -535,35 +355,13 @@ func deadcode() {
 	if tracksym == "" {
 		return
 	}
-	s := Linklookup(Ctxt, tracksym, 0)
-	if !s.Reachable {
+	s := Linklookup(ctxt, tracksym, 0)
+	if !s.Attr.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
@@ -584,35 +382,7 @@ type Pkg struct {
 	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)
-}
+var pkgall []*Pkg
 
 func (p *Pkg) cycle() *Pkg {
 	if p.checked {
diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go
index 1068bdd..bbbfd3e 100644
--- a/src/cmd/link/internal/ld/ld.go
+++ b/src/cmd/link/internal/ld/ld.go
@@ -9,7 +9,7 @@
 //	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.
+//	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
diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go
index bea3f2d..af60a5c 100644
--- a/src/cmd/link/internal/ld/ldelf.go
+++ b/src/cmd/link/internal/ld/ldelf.go
@@ -2,7 +2,9 @@ package ld
 
 import (
 	"bytes"
+	"cmd/internal/bio"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
 	"io"
@@ -266,7 +268,7 @@ type ElfSect struct {
 }
 
 type ElfObj struct {
-	f         *obj.Biobuf
+	f         *bio.Reader
 	base      int64 // offset in f where ELF begins
 	length    int64 // length of ELF
 	is64      int
@@ -403,7 +405,7 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) {
 		ehdr.flags = 0x5000202
 	}
 	if data[0] != 'A' {
-		fmt.Fprintf(&Bso, ".ARM.attributes has unexpected format %c\n", data[0])
+		fmt.Fprintf(Bso, ".ARM.attributes has unexpected format %c\n", data[0])
 		return
 	}
 	data = data[1:]
@@ -414,7 +416,7 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) {
 
 		nulIndex := bytes.IndexByte(sectiondata, 0)
 		if nulIndex < 0 {
-			fmt.Fprintf(&Bso, "corrupt .ARM.attributes (section name not NUL-terminated)\n")
+			fmt.Fprintf(Bso, "corrupt .ARM.attributes (section name not NUL-terminated)\n")
 			return
 		}
 		name := string(sectiondata[:nulIndex])
@@ -438,20 +440,20 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) {
 					}
 				}
 				if attrList.err != nil {
-					fmt.Fprintf(&Bso, "could not parse .ARM.attributes\n")
+					fmt.Fprintf(Bso, "could not parse .ARM.attributes\n")
 				}
 			}
 		}
 	}
 }
 
-func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
+func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
 	if Debug['v'] != 0 {
-		fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
+		fmt.Fprintf(Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
 	}
 
-	Ctxt.Version++
-	base := int32(obj.Boffset(f))
+	Ctxt.IncVersion()
+	base := f.Offset()
 
 	var add uint64
 	var e binary.ByteOrder
@@ -474,7 +476,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 	var sect *ElfSect
 	var sym ElfSym
 	var symbols []*LSym
-	if obj.Bread(f, hdrbuf[:]) != len(hdrbuf) {
+	if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
 		goto bad
 	}
 	hdr = new(ElfHdrBytes)
@@ -498,7 +500,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 
 	elfobj.e = e
 	elfobj.f = f
-	elfobj.base = int64(base)
+	elfobj.base = base
 	elfobj.length = length
 	elfobj.name = pn
 
@@ -546,46 +548,52 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 		return
 	}
 
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Diag("%s: elf %s unimplemented", pn, Thestring)
+		Diag("%s: elf %s unimplemented", pn, SysArch.Name)
 		return
 
-	case '0':
+	case sys.MIPS64:
 		if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass64 {
 			Diag("%s: elf object but not mips64", pn)
 			return
 		}
 
-	case '5':
+	case sys.ARM:
 		if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
 			Diag("%s: elf object but not arm", pn)
 			return
 		}
 
-	case '6':
+	case sys.AMD64:
 		if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
 			Diag("%s: elf object but not amd64", pn)
 			return
 		}
 
-	case '7':
+	case sys.ARM64:
 		if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 {
 			Diag("%s: elf object but not arm64", pn)
 			return
 		}
 
-	case '8':
+	case sys.I386:
 		if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
 			Diag("%s: elf object but not 386", pn)
 			return
 		}
 
-	case '9':
+	case sys.PPC64:
 		if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
 			Diag("%s: elf object but not ppc64", pn)
 			return
 		}
+
+	case sys.S390X:
+		if elfobj.machine != ElfMachS390 || hdr.Ident[4] != ElfClass64 {
+			Diag("%s: elf object but not s390x", pn)
+			return
+		}
 	}
 
 	// load section list into memory.
@@ -593,7 +601,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 
 	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 {
+		if f.Seek(int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
 			goto bad
 		}
 		sect = &elfobj.sect[i]
@@ -604,7 +612,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 				goto bad
 			}
 
-			sect.nameoff = uint32(e.Uint32(b.Name[:]))
+			sect.nameoff = e.Uint32(b.Name[:])
 			sect.type_ = e.Uint32(b.Type[:])
 			sect.flags = e.Uint64(b.Flags[:])
 			sect.addr = e.Uint64(b.Addr[:])
@@ -621,7 +629,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 				goto bad
 			}
 
-			sect.nameoff = uint32(e.Uint32(b.Name[:]))
+			sect.nameoff = e.Uint32(b.Name[:])
 			sect.type_ = e.Uint32(b.Type[:])
 			sect.flags = uint64(e.Uint32(b.Flags[:]))
 			sect.addr = uint64(e.Uint32(b.Addr[:]))
@@ -766,7 +774,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 		if sym.sym == nil {
 			continue
 		}
-		sect = &elfobj.sect[sym.shndx:][0]
+		sect = &elfobj.sect[sym.shndx]
 		if sect.sym == nil {
 			if strings.HasPrefix(sym.name, ".Linfo_string") { // clang does this
 				continue
@@ -778,13 +786,16 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 				continue
 			}
 
+			if strings.HasPrefix(sym.name, ".LASF") { // gcc on s390x 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 {
+			if s.Attr.DuplicateOK() {
 				continue
 			}
 			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
@@ -793,17 +804,17 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 		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 {
+		if !s.Attr.CgoExportDynamic() {
 			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 {
+			if s.Attr.External() && !s.Attr.DuplicateOK() {
 				Diag("%s: duplicate definition of %s", pn, s.Name)
 			}
-			s.External = 1
+			s.Attr |= AttrExternal
 		}
 
 		if elfobj.machine == ElfMachPower64 {
@@ -827,23 +838,17 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 			s.Sub = listsort(s.Sub, valuecmp, listsubp)
 		}
 		if s.Type == obj.STEXT {
-			if s.Onlist != 0 {
+			if s.Attr.OnList() {
 				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
+			s.Attr |= AttrOnList
+			Ctxt.Textp = append(Ctxt.Textp, s)
 			for s = s.Sub; s != nil; s = s.Sub {
-				if s.Onlist != 0 {
+				if s.Attr.OnList() {
 					log.Fatalf("symbol %s listed multiple times", s.Name)
 				}
-				s.Onlist = 1
-				Ctxt.Etextp.Next = s
-				Ctxt.Etextp = s
+				s.Attr |= AttrOnList
+				Ctxt.Textp = append(Ctxt.Textp, s)
 			}
 		}
 	}
@@ -917,7 +922,8 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
 				rp.Sym = sym.sym
 			}
 
-			rp.Type = int32(reltype(pn, int(uint32(info)), &rp.Siz))
+			rp.Type = 256 + int32(info)
+			rp.Siz = relSize(pn, uint32(info))
 			if rela != 0 {
 				rp.Add = int64(add)
 			} else {
@@ -974,9 +980,11 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
 	}
 
 	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
+	if elfobj.f.Seek(int64(uint64(elfobj.base)+sect.off), 0) < 0 {
+		return fmt.Errorf("short read: seek not successful")
+	}
+	if _, err := io.ReadFull(elfobj.f, sect.base); err != nil {
+		return fmt.Errorf("short read: %v", err)
 	}
 
 	return nil
@@ -1043,12 +1051,12 @@ func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
 				// comment #5 for details.
 				if s != nil && sym.other == 2 {
 					s.Type |= obj.SHIDDEN
-					s.Dupok = 1
+					s.Attr |= AttrDuplicateOK
 				}
 			}
 
 		case ElfSymBindLocal:
-			if Thearch.Thechar == '5' && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) {
+			if SysArch.Family == sys.ARM && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) {
 				// binutils for arm generate these mapping
 				// symbols, ignore these
 				break
@@ -1066,9 +1074,9 @@ func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
 			}
 
 			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
+				// local names and hidden global names are unique
+				// and should only be referenced by their index, not name, so we
+				// don't bother to add them into the hash table
 				s = linknewsym(Ctxt, sym.name, Ctxt.Version)
 
 				s.Type |= obj.SHIDDEN
@@ -1118,55 +1126,89 @@ func (x rbyoff) Less(i, j int) bool {
 	return false
 }
 
-func reltype(pn string, elftype int, siz *uint8) int {
-	switch uint32(Thearch.Thechar) | uint32(elftype)<<24 {
+func relSize(pn string, elftype uint32) uint8 {
+	// TODO(mdempsky): Replace this with a struct-valued switch statement
+	// once golang.org/issue/15164 is fixed or found to not impair cmd/link
+	// performance.
+
+	const (
+		AMD64 = uint32(sys.AMD64)
+		ARM   = uint32(sys.ARM)
+		I386  = uint32(sys.I386)
+		PPC64 = uint32(sys.PPC64)
+		S390X = uint32(sys.S390X)
+	)
+
+	switch uint32(SysArch.Family) | 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,
-		'6' | R_X86_64_GOTPCRELX<<24,
-		'6' | R_X86_64_REX_GOTPCRELX<<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,
-		'8' | R_386_GOT32X<<24,
-		'9' | R_PPC64_REL24<<24,
-		'9' | R_PPC_REL32<<24:
-		*siz = 4
-
-	case '6' | R_X86_64_64<<24,
-		'9' | R_PPC64_ADDR64<<24:
-		*siz = 8
+	case S390X | R_390_8<<24:
+		return 1
+
+	case PPC64 | R_PPC64_TOC16<<24,
+		PPC64 | R_PPC64_TOC16_LO<<24,
+		PPC64 | R_PPC64_TOC16_HI<<24,
+		PPC64 | R_PPC64_TOC16_HA<<24,
+		PPC64 | R_PPC64_TOC16_DS<<24,
+		PPC64 | R_PPC64_TOC16_LO_DS<<24,
+		PPC64 | R_PPC64_REL16_LO<<24,
+		PPC64 | R_PPC64_REL16_HI<<24,
+		PPC64 | R_PPC64_REL16_HA<<24,
+		S390X | R_390_16<<24,
+		S390X | R_390_GOT16<<24,
+		S390X | R_390_PC16<<24,
+		S390X | R_390_PC16DBL<<24,
+		S390X | R_390_PLT16DBL<<24:
+		return 2
+
+	case ARM | R_ARM_ABS32<<24,
+		ARM | R_ARM_GOT32<<24,
+		ARM | R_ARM_PLT32<<24,
+		ARM | R_ARM_GOTOFF<<24,
+		ARM | R_ARM_GOTPC<<24,
+		ARM | R_ARM_THM_PC22<<24,
+		ARM | R_ARM_REL32<<24,
+		ARM | R_ARM_CALL<<24,
+		ARM | R_ARM_V4BX<<24,
+		ARM | R_ARM_GOT_PREL<<24,
+		ARM | R_ARM_PC24<<24,
+		ARM | R_ARM_JUMP24<<24,
+		AMD64 | R_X86_64_PC32<<24,
+		AMD64 | R_X86_64_PLT32<<24,
+		AMD64 | R_X86_64_GOTPCREL<<24,
+		AMD64 | R_X86_64_GOTPCRELX<<24,
+		AMD64 | R_X86_64_REX_GOTPCRELX<<24,
+		I386 | R_386_32<<24,
+		I386 | R_386_PC32<<24,
+		I386 | R_386_GOT32<<24,
+		I386 | R_386_PLT32<<24,
+		I386 | R_386_GOTOFF<<24,
+		I386 | R_386_GOTPC<<24,
+		I386 | R_386_GOT32X<<24,
+		PPC64 | R_PPC64_REL24<<24,
+		PPC64 | R_PPC_REL32<<24,
+		S390X | R_390_32<<24,
+		S390X | R_390_PC32<<24,
+		S390X | R_390_GOT32<<24,
+		S390X | R_390_PLT32<<24,
+		S390X | R_390_PC32DBL<<24,
+		S390X | R_390_PLT32DBL<<24,
+		S390X | R_390_GOTPCDBL<<24,
+		S390X | R_390_GOTENT<<24:
+		return 4
+
+	case AMD64 | R_X86_64_64<<24,
+		PPC64 | R_PPC64_ADDR64<<24,
+		S390X | R_390_GLOB_DAT<<24,
+		S390X | R_390_RELATIVE<<24,
+		S390X | R_390_GOTOFF<<24,
+		S390X | R_390_GOTPC<<24,
+		S390X | R_390_64<<24,
+		S390X | R_390_PC64<<24,
+		S390X | R_390_GOT64<<24,
+		S390X | R_390_PLT64<<24:
+		return 8
 	}
-
-	return 256 + elftype
 }
diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go
index 2abfa33..a101249 100644
--- a/src/cmd/link/internal/ld/ldmacho.go
+++ b/src/cmd/link/internal/ld/ldmacho.go
@@ -1,9 +1,12 @@
 package ld
 
 import (
+	"cmd/internal/bio"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
+	"io"
 	"log"
 	"sort"
 )
@@ -41,7 +44,7 @@ const (
 )
 
 type LdMachoObj struct {
-	f          *obj.Biobuf
+	f          *bio.Reader
 	base       int64 // off in f where Mach-O begins
 	length     int64 // length of Mach-O
 	is64       bool
@@ -297,7 +300,10 @@ func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
 	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 {
+	if m.f.Seek(m.base+int64(sect.reloff), 0) < 0 {
+		return -1
+	}
+	if _, err := io.ReadFull(m.f, buf); err != nil {
 		return -1
 	}
 	var p []byte
@@ -343,7 +349,10 @@ 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) {
+	if m.f.Seek(m.base+int64(d.indirectsymoff), 0) < 0 {
+		return -1
+	}
+	if _, err := io.ReadFull(m.f, p); err != nil {
 		return -1
 	}
 
@@ -360,7 +369,10 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
 	}
 
 	strbuf := make([]byte, symtab.strsize)
-	if obj.Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || obj.Bread(m.f, strbuf) != len(strbuf) {
+	if m.f.Seek(m.base+int64(symtab.stroff), 0) < 0 {
+		return -1
+	}
+	if _, err := io.ReadFull(m.f, strbuf); err != nil {
 		return -1
 	}
 
@@ -370,7 +382,10 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
 	}
 	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) {
+	if m.f.Seek(m.base+int64(symtab.symoff), 0) < 0 {
+		return -1
+	}
+	if _, err := io.ReadFull(m.f, symbuf); err != nil {
 		return -1
 	}
 	sym := make([]LdMachoSym, symtab.nsym)
@@ -384,8 +399,8 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
 			return -1
 		}
 		s.name = cstring(strbuf[v:])
-		s.type_ = uint8(p[4])
-		s.sectnum = uint8(p[5])
+		s.type_ = p[4]
+		s.sectnum = p[5]
 		s.desc = m.e.Uint16(p[6:])
 		if m.is64 {
 			s.value = m.e.Uint64(p[8:])
@@ -400,7 +415,7 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
 	return 0
 }
 
-func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
+func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
 	var err error
 	var j int
 	var is64 bool
@@ -429,9 +444,9 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 	var rp *Reloc
 	var name string
 
-	Ctxt.Version++
-	base := obj.Boffset(f)
-	if obj.Bread(f, hdr[:]) != len(hdr) {
+	Ctxt.IncVersion()
+	base := f.Offset()
+	if _, err := io.ReadFull(f, hdr[:]); err != nil {
 		goto bad
 	}
 
@@ -445,44 +460,43 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 	}
 
 	is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
-	ncmd = e.Uint32([]byte(hdr[4*4:]))
-	cmdsz = e.Uint32([]byte(hdr[5*4:]))
+	ncmd = e.Uint32(hdr[4*4:])
+	cmdsz = e.Uint32(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
+		f.Seek(4, 1) // 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.cputype = uint(e.Uint32(hdr[1*4:]))
+	m.subcputype = uint(e.Uint32(hdr[2*4:]))
+	m.filetype = e.Uint32(hdr[3*4:])
 	m.ncmd = uint(ncmd)
-	m.flags = e.Uint32([]byte(hdr[6*4:]))
+	m.flags = e.Uint32(hdr[6*4:])
 	m.is64 = is64
 	m.base = base
 	m.length = length
 	m.name = pn
 
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Diag("%s: mach-o %s unimplemented", pn, Thestring)
+		Diag("%s: mach-o %s unimplemented", pn, SysArch.Name)
 		return
 
-	case '6':
+	case sys.AMD64:
 		if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
 			Diag("%s: mach-o object but not amd64", pn)
 			return
 		}
 
-	case '8':
+	case sys.I386:
 		if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
 			Diag("%s: mach-o object but not 386", pn)
 			return
@@ -492,7 +506,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 	m.cmd = make([]LdMachoCmd, ncmd)
 	off = uint32(len(hdr))
 	cmdp = make([]byte, cmdsz)
-	if obj.Bread(f, cmdp) != len(cmdp) {
+	if _, err2 := io.ReadFull(f, cmdp); err2 != nil {
 		err = fmt.Errorf("reading cmds: %v", err)
 		goto bad
 	}
@@ -555,7 +569,11 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 	}
 
 	dat = make([]byte, c.seg.filesz)
-	if obj.Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || obj.Bread(f, dat) != len(dat) {
+	if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 {
+		err = fmt.Errorf("cannot load object data: %v", err)
+		goto bad
+	}
+	if _, err2 := io.ReadFull(f, dat); err2 != nil {
 		err = fmt.Errorf("cannot load object data: %v", err)
 		goto bad
 	}
@@ -620,7 +638,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 		}
 		s = Linklookup(Ctxt, name, v)
 		if sym.type_&N_EXT == 0 {
-			s.Dupok = 1
+			s.Attr |= AttrDuplicateOK
 		}
 		sym.sym = s
 		if sym.sectnum == 0 { // undefined
@@ -639,7 +657,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 		}
 
 		if s.Outer != nil {
-			if s.Dupok != 0 {
+			if s.Attr.DuplicateOK() {
 				continue
 			}
 			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
@@ -650,14 +668,14 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 		outer.Sub = s
 		s.Outer = outer
 		s.Value = int64(sym.value - sect.addr)
-		if s.Cgoexport&CgoExportDynamic == 0 {
+		if !s.Attr.CgoExportDynamic() {
 			s.Dynimplib = "" // satisfy dynimport
 		}
 		if outer.Type == obj.STEXT {
-			if s.External != 0 && s.Dupok == 0 {
+			if s.Attr.External() && !s.Attr.DuplicateOK() {
 				Diag("%s: duplicate definition of %s", pn, s.Name)
 			}
-			s.External = 1
+			s.Attr |= AttrExternal
 		}
 
 		sym.sym = s
@@ -685,23 +703,17 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 		}
 
 		if s.Type == obj.STEXT {
-			if s.Onlist != 0 {
+			if s.Attr.OnList() {
 				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
+			s.Attr |= AttrOnList
+			Ctxt.Textp = append(Ctxt.Textp, s)
 			for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
-				if s1.Onlist != 0 {
+				if s1.Attr.OnList() {
 					log.Fatalf("symbol %s listed multiple times", s1.Name)
 				}
-				s1.Onlist = 1
-				Ctxt.Etextp.Next = s1
-				Ctxt.Etextp = s1
+				s1.Attr |= AttrOnList
+				Ctxt.Textp = append(Ctxt.Textp, s1)
 			}
 		}
 	}
@@ -724,10 +736,9 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 			rp = &r[rpi]
 			rel = &sect.rel[j]
 			if rel.scattered != 0 {
-				if Thearch.Thechar != '8' {
+				if SysArch.Family != sys.I386 {
 					// mach-o only uses scattered relocation on 32-bit platforms
 					Diag("unexpected scattered relocation")
-
 					continue
 				}
 
@@ -821,7 +832,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 			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 {
+			if SysArch.Family == sys.AMD64 && 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
@@ -845,9 +856,9 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 			}
 
 			// For i386 Mach-O PC-relative, the addend is written such that
-			// it *is* the PC being subtracted.  Use that to make
+			// it *is* the PC being subtracted. Use that to make
 			// it match our version of PC-relative.
-			if rel.pcrel != 0 && Thearch.Thechar == '8' {
+			if rel.pcrel != 0 && SysArch.Family == sys.I386 {
 				rp.Add += int64(rp.Off) + int64(rp.Siz)
 			}
 			if rel.extrn == 0 {
@@ -866,7 +877,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
 				// include that information in the addend.
 				// We only care about the delta from the
 				// section base.
-				if Thearch.Thechar == '8' {
+				if SysArch.Family == sys.I386 {
 					rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
 				}
 			} else {
diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go
index 8439c06..7eb26bc 100644
--- a/src/cmd/link/internal/ld/ldpe.go
+++ b/src/cmd/link/internal/ld/ldpe.go
@@ -5,9 +5,12 @@
 package ld
 
 import (
+	"cmd/internal/bio"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
+	"io"
 	"log"
 	"sort"
 	"strconv"
@@ -116,7 +119,7 @@ type PeSect struct {
 }
 
 type PeObj struct {
-	f      *obj.Biobuf
+	f      *bio.Reader
 	name   string
 	base   uint32
 	sect   []PeSect
@@ -127,14 +130,14 @@ type PeObj struct {
 	snames []byte
 }
 
-func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
+func ldpe(f *bio.Reader, pkg string, length int64, pn string) {
 	if Debug['v'] != 0 {
-		fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
+		fmt.Fprintf(Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
 	}
 
 	var sect *PeSect
-	Ctxt.Version++
-	base := int32(obj.Boffset(f))
+	Ctxt.IncVersion()
+	base := f.Offset()
 
 	peobj := new(PeObj)
 	peobj.f = f
@@ -172,15 +175,15 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
 	// 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)
+	f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
 
-	if obj.Bread(f, symbuf[:4]) != 4 {
+	if _, err := io.ReadFull(f, symbuf[:4]); err != nil {
 		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) {
+	f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
+	if _, err := io.ReadFull(f, peobj.snames); err != nil {
 		goto bad
 	}
 
@@ -200,10 +203,10 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
 	peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)
 
 	peobj.npesym = uint(peobj.fh.NumberOfSymbols)
-	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
+	f.Seek(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) {
+		f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
+		if _, err := io.ReadFull(f, symbuf[:]); err != nil {
 			goto bad
 		}
 
@@ -234,7 +237,7 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
 
 		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.
+			// want to ignore. See issues 5106 and 5273.
 			continue
 		}
 
@@ -283,15 +286,15 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
 		}
 		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.
+			// 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)
+		f.Seek(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 {
+			if _, err := io.ReadFull(f, symbuf[:10]); err != nil {
 				goto bad
 			}
 			rva := Le32(symbuf[0:])
@@ -397,7 +400,7 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
 		}
 
 		if s.Outer != nil {
-			if s.Dupok != 0 {
+			if s.Attr.DuplicateOK() {
 				continue
 			}
 			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
@@ -410,10 +413,10 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
 		s.Size = 4
 		s.Outer = sect.sym
 		if sect.sym.Type == obj.STEXT {
-			if s.External != 0 && s.Dupok == 0 {
+			if s.Attr.External() && !s.Attr.DuplicateOK() {
 				Diag("%s: duplicate definition of %s", pn, s.Name)
 			}
-			s.External = 1
+			s.Attr |= AttrExternal
 		}
 	}
 
@@ -428,23 +431,17 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
 			s.Sub = listsort(s.Sub, valuecmp, listsubp)
 		}
 		if s.Type == obj.STEXT {
-			if s.Onlist != 0 {
+			if s.Attr.OnList() {
 				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
+			s.Attr |= AttrOnList
+			Ctxt.Textp = append(Ctxt.Textp, s)
 			for s = s.Sub; s != nil; s = s.Sub {
-				if s.Onlist != 0 {
+				if s.Attr.OnList() {
 					log.Fatalf("symbol %s listed multiple times", s.Name)
 				}
-				s.Onlist = 1
-				Ctxt.Etextp.Next = s
-				Ctxt.Etextp = s
+				s.Attr |= AttrOnList
+				Ctxt.Textp = append(Ctxt.Textp, s)
 			}
 		}
 	}
@@ -464,7 +461,10 @@ func pemap(peobj *PeObj, sect *PeSect) int {
 	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) {
+	if peobj.f.Seek(int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 {
+		return -1
+	}
+	if _, err := io.ReadFull(peobj.f, sect.base); err != nil {
 		return -1
 	}
 
@@ -492,7 +492,7 @@ func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
 		if strings.HasPrefix(name, "__imp_") {
 			name = name[6:] // __imp_Name => Name
 		}
-		if Thearch.Thechar == '8' && name[0] == '_' {
+		if SysArch.Family == sys.I386 && name[0] == '_' {
 			name = name[1:] // _Name => Name
 		}
 	}
@@ -515,7 +515,7 @@ func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
 
 		case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
 			s = Linklookup(Ctxt, name, Ctxt.Version)
-			s.Dupok = 1
+			s.Attr |= AttrDuplicateOK
 
 		default:
 			err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.sclass)
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index bdfa056..14f4fa9 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -33,7 +33,9 @@ package ld
 import (
 	"bufio"
 	"bytes"
+	"cmd/internal/bio"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"crypto/sha1"
 	"debug/elf"
 	"encoding/binary"
@@ -61,7 +63,7 @@ import (
 //	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.
+//	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
@@ -82,13 +84,9 @@ import (
 // THE SOFTWARE.
 
 type Arch struct {
-	Thechar          int
-	Ptrsize          int
-	Intsize          int
-	Regsize          int
 	Funcalign        int
 	Maxalign         int
-	Minlc            int
+	Minalign         int
 	Dwarfregsp       int
 	Dwarfreglr       int
 	Linuxdynld       string
@@ -107,9 +105,12 @@ type Arch struct {
 	Gentext          func()
 	Machoreloc1      func(*Reloc, int64) int
 	PEreloc1         func(*Reloc, int64) bool
-	Lput             func(uint32)
 	Wput             func(uint16)
+	Lput             func(uint32)
 	Vput             func(uint64)
+	Append16         func(b []byte, v uint16) []byte
+	Append32         func(b []byte, v uint32) []byte
+	Append64         func(b []byte, v uint64) []byte
 }
 
 type Rpath struct {
@@ -129,7 +130,6 @@ func (r *Rpath) String() string {
 
 var (
 	Thearch Arch
-	datap   *LSym
 	Debug   [128]int
 	Lcsize  int32
 	rpath   Rpath
@@ -182,13 +182,12 @@ func UseRelro() bool {
 	case BuildmodeCShared, BuildmodeShared, BuildmodePIE:
 		return Iself
 	default:
-		return false
+		return Linkshared
 	}
 }
 
 var (
-	Thestring          string
-	Thelinkarch        *LinkArch
+	SysArch            *sys.Arch
 	outfile            string
 	dynexp             []*LSym
 	dynlib             []string
@@ -197,6 +196,7 @@ var (
 	Funcalign          int
 	iscgo              bool
 	elfglobalsymndx    int
+	flag_dumpdep       bool
 	flag_installsuffix string
 	flag_race          int
 	flag_msan          int
@@ -222,12 +222,6 @@ var (
 	liveness           int64
 )
 
-// for dynexport field of LSym
-const (
-	CgoExportDynamic = 1 << 0
-	CgoExportStatic  = 1 << 1
-)
-
 var (
 	Segtext   Segment
 	Segrodata Segment
@@ -247,18 +241,31 @@ const (
 var (
 	headstring string
 	// buffered output
-	Bso obj.Biobuf
+	Bso *bufio.Writer
 )
 
-var coutbuf struct {
-	*bufio.Writer
-	f *os.File
+// TODO(dfc) outBuf duplicates bio.Writer
+type outBuf struct {
+	w   *bufio.Writer
+	f   *os.File
+	off int64
 }
 
-const (
-	symname = "__.GOSYMDEF"
-	pkgname = "__.PKGDEF"
-)
+func (w *outBuf) Write(p []byte) (n int, err error) {
+	n, err = w.w.Write(p)
+	w.off += int64(n)
+	return n, err
+}
+
+func (w *outBuf) WriteString(s string) (n int, err error) {
+	n, err = coutbuf.w.WriteString(s)
+	w.off += int64(n)
+	return n, err
+}
+
+var coutbuf outBuf
+
+const pkgname = "__.PKGDEF"
 
 var (
 	// Set if we see an object compiled by the host compiler that is not
@@ -314,6 +321,12 @@ func (mode *BuildMode) Set(s string) error {
 	case "c-archive":
 		switch goos {
 		case "darwin", "linux":
+		case "windows":
+			switch goarch {
+			case "amd64", "386":
+			default:
+				return badmode()
+			}
 		default:
 			return badmode()
 		}
@@ -329,7 +342,7 @@ func (mode *BuildMode) Set(s string) error {
 		switch goos {
 		case "linux":
 			switch goarch {
-			case "386", "amd64", "arm", "arm64", "ppc64le":
+			case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
 			default:
 				return badmode()
 			}
@@ -391,7 +404,7 @@ func libinit() {
 		suffix = "msan"
 	}
 
-	Lflag(fmt.Sprintf("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix))
+	Lflag(filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s%s%s", goos, goarch, suffixsep, suffix)))
 
 	mayberemoveoutfile()
 	f, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
@@ -399,7 +412,7 @@ func libinit() {
 		Exitf("cannot create %s: %v", outfile, err)
 	}
 
-	coutbuf.Writer = bufio.NewWriter(f)
+	coutbuf.w = bufio.NewWriter(f)
 	coutbuf.f = f
 
 	if INITENTRY == "" {
@@ -454,9 +467,9 @@ 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)
+			shlibname := filepath.Join(Ctxt.Libdir[i], name+".shlibname")
 			if Debug['v'] != 0 {
-				fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, shlibname)
+				fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, shlibname)
 			}
 			if _, err := os.Stat(shlibname); err == nil {
 				addlibpath(Ctxt, "internal", "internal", "", name, shlibname)
@@ -464,9 +477,9 @@ func loadinternal(name string) {
 				break
 			}
 		}
-		pname := fmt.Sprintf("%s/%s.a", Ctxt.Libdir[i], name)
+		pname := filepath.Join(Ctxt.Libdir[i], name+".a")
 		if Debug['v'] != 0 {
-			fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, pname)
+			fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, pname)
 		}
 		if _, err := os.Stat(pname); err == nil {
 			addlibpath(Ctxt, "internal", "internal", pname, name, "")
@@ -476,7 +489,7 @@ func loadinternal(name string) {
 	}
 
 	if found == 0 {
-		fmt.Fprintf(&Bso, "warning: unable to find %s.a\n", name)
+		fmt.Fprintf(Bso, "warning: unable to find %s.a\n", name)
 	}
 }
 
@@ -484,16 +497,16 @@ func loadlib() {
 	switch Buildmode {
 	case BuildmodeCShared:
 		s := Linklookup(Ctxt, "runtime.islibrary", 0)
-		s.Dupok = 1
+		s.Attr |= AttrDuplicateOK
 		Adduint8(Ctxt, s, 1)
 	case BuildmodeCArchive:
 		s := Linklookup(Ctxt, "runtime.isarchive", 0)
-		s.Dupok = 1
+		s.Attr |= AttrDuplicateOK
 		Adduint8(Ctxt, s, 1)
 	}
 
 	loadinternal("runtime")
-	if Thearch.Thechar == '5' {
+	if SysArch.Family == sys.ARM {
 		loadinternal("math")
 	}
 	if flag_race != 0 {
@@ -508,7 +521,7 @@ func loadlib() {
 		iscgo = iscgo || Ctxt.Library[i].Pkg == "runtime/cgo"
 		if Ctxt.Library[i].Shlib == "" {
 			if Debug['v'] > 1 {
-				fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
+				fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
 			}
 			objfile(Ctxt.Library[i])
 		}
@@ -517,7 +530,7 @@ func loadlib() {
 	for i = 0; i < len(Ctxt.Library); i++ {
 		if Ctxt.Library[i].Shlib != "" {
 			if Debug['v'] > 1 {
-				fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].Shlib, Ctxt.Library[i].Objref)
+				fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].Shlib, Ctxt.Library[i].Objref)
 			}
 			ldshlibsyms(Ctxt.Library[i].Shlib)
 		}
@@ -546,7 +559,7 @@ func loadlib() {
 		// 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 {
+		if SysArch.InFamily(sys.ARM, sys.ARM64) && HEADTYPE == obj.Hdarwin && iscgo {
 			Linkmode = LinkExternal
 		}
 
@@ -558,14 +571,15 @@ func loadlib() {
 
 	// cmd/7l doesn't support cgo internal linking
 	// This is https://golang.org/issue/10373.
-	if iscgo && goarch == "arm64" {
+	// mips64x doesn't support cgo internal linking either (golang.org/issue/14449)
+	if iscgo && (goarch == "arm64" || goarch == "mips64" || goarch == "mips64le") {
 		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
+		// whether to initialize the TLS.  So give it one. This could
 		// be handled differently but it's an unusual case.
 		loadinternal("runtime/cgo")
 
@@ -584,13 +598,13 @@ func loadlib() {
 	if Linkmode == LinkInternal {
 		// Drop all the cgo_import_static declarations.
 		// Turns out we won't be needing them.
-		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+		for _, s := range Ctxt.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 {
+				if s.Extname != "" && s.Dynimplib != "" && !s.Attr.CgoExport() {
 					s.Type = obj.SDYNIMPORT
 				} else {
 					s.Type = 0
@@ -605,11 +619,11 @@ func loadlib() {
 	// a variable to hold g in assembly (currently only intel).
 	if tlsg.Type == 0 {
 		tlsg.Type = obj.STLSBSS
-		tlsg.Size = int64(Thearch.Ptrsize)
+		tlsg.Size = int64(SysArch.PtrSize)
 	} else if tlsg.Type != obj.SDYNIMPORT {
 		Diag("internal error: runtime declared tlsg variable %d", tlsg.Type)
 	}
-	tlsg.Reachable = true
+	tlsg.Attr |= AttrReachable
 	Ctxt.Tlsg = tlsg
 
 	moduledata := Linklookup(Ctxt, "runtime.firstmoduledata", 0)
@@ -623,34 +637,40 @@ func loadlib() {
 
 		// In addition, on ARM, the runtime depends on the linker
 		// recording the value of GOARM.
-		if Thearch.Thechar == '5' {
+		if SysArch.Family == sys.ARM {
 			s := Linklookup(Ctxt, "runtime.goarm", 0)
-
 			s.Type = obj.SRODATA
 			s.Size = 0
 			Adduint8(Ctxt, s, uint8(Ctxt.Goarm))
 		}
+
+		if obj.Framepointer_enabled(obj.Getgoos(), obj.Getgoarch()) {
+			s := Linklookup(Ctxt, "runtime.framepointer_enabled", 0)
+			s.Type = obj.SRODATA
+			s.Size = 0
+			Adduint8(Ctxt, s, 1)
+		}
 	} else {
 		// If OTOH the module does not contain the runtime package,
 		// create a local symbol for the moduledata.
 		moduledata = Linklookup(Ctxt, "local.moduledata", 0)
-		moduledata.Local = true
+		moduledata.Attr |= AttrLocal
 	}
 	// In all cases way we mark the moduledata as noptrdata to hide it from
 	// the GC.
 	moduledata.Type = obj.SNOPTRDATA
-	moduledata.Reachable = true
+	moduledata.Attr |= AttrReachable
 	Ctxt.Moduledata = moduledata
 
 	// Now that we know the link mode, trim the dynexp list.
-	x := CgoExportDynamic
+	x := AttrCgoExportDynamic
 
 	if Linkmode == LinkExternal {
-		x = CgoExportStatic
+		x = AttrCgoExportStatic
 	}
 	w := 0
 	for i := 0; i < len(dynexp); i++ {
-		if int(dynexp[i].Cgoexport)&x != 0 {
+		if dynexp[i].Attr&x != 0 {
 			dynexp[w] = dynexp[i]
 			w++
 		}
@@ -664,7 +684,7 @@ func loadlib() {
 		// If we have any undefined symbols in external
 		// objects, try to read them from the libgcc file.
 		any := false
-		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+		for _, s := range Ctxt.Allsym {
 			for _, r := range s.R {
 				if r.Sym != nil && r.Sym.Type&obj.SMASK == obj.SXREF && r.Sym.Name != ".got" {
 					any = true
@@ -680,13 +700,13 @@ func loadlib() {
 				args := hostlinkArchArgs()
 				args = append(args, "--print-libgcc-file-name")
 				if Debug['v'] != 0 {
-					fmt.Fprintf(&Bso, "%s %v\n", extld, args)
+					fmt.Fprintf(Bso, "%s %v\n", extld, args)
 				}
 				out, err := exec.Command(extld, args...).Output()
 				if err != nil {
 					if Debug['v'] != 0 {
-						fmt.Fprintln(&Bso, "not using a libgcc file because compiler failed")
-						fmt.Fprintf(&Bso, "%v\n%s\n", err, out)
+						fmt.Fprintln(Bso, "not using a libgcc file because compiler failed")
+						fmt.Fprintf(Bso, "%v\n%s\n", err, out)
 					}
 					libgccfile = "none"
 				} else {
@@ -727,17 +747,17 @@ func loadlib() {
  * look for the next file in an archive.
  * adapted from libmach.
  */
-func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 {
+func nextar(bp *bio.Reader, 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
+	bp.Seek(off, 0)
+	var buf [SAR_HDR]byte
+	if n, err := io.ReadFull(bp, buf[:]); err != nil {
+		if n == 0 && err != io.EOF {
+			return -1
 		}
-		return -1
+		return 0
 	}
 
 	a.name = artrim(buf[0:16])
@@ -752,37 +772,38 @@ func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 {
 	if arsize&1 != 0 {
 		arsize++
 	}
-	return int64(arsize) + SAR_HDR
+	return 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)
+		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)
+	f, err := bio.Open(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) {
+	for i := 0; i < len(ARMAG); i++ {
+		if c, err := f.ReadByte(); err == nil && c == ARMAG[i] {
+			continue
+		}
+
 		/* load it as a regular file */
-		l := obj.Bseek(f, 0, 2)
+		l := f.Seek(0, 2)
 
-		obj.Bseek(f, 0, 0)
+		f.Seek(0, 0)
 		ldobj(f, pkg, l, lib.File, lib.File, FileObj)
-		obj.Bterm(f)
+		f.Close()
 
 		return
 	}
 
-	/* skip over optional __.GOSYMDEF and process __.PKGDEF */
-	off := obj.Boffset(f)
+	/* process __.PKGDEF */
+	off := f.Offset()
 
 	var arhdr ArHdr
 	l := nextar(f, off, &arhdr)
@@ -792,27 +813,20 @@ func objfile(lib *Library) {
 		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)
+		before := f.Offset()
 		pkgdefBytes := make([]byte, atolwhex(arhdr.size))
-		obj.Bread(f, pkgdefBytes)
+		if _, err := io.ReadFull(f, pkgdefBytes); err != nil {
+			Diag("%s: short read on archive file symbol header: %v", lib.File, err)
+		}
 		hash := sha1.Sum(pkgdefBytes)
 		lib.hash = hash[:]
-		obj.Bseek(f, before, 0)
+		f.Seek(before, 0)
 	}
 
 	off += l
@@ -829,7 +843,7 @@ func objfile(lib *Library) {
 	 * the individual symbols that are unused.
 	 *
 	 * loading every object will also make it possible to
-	 * load foreign objects not referenced by __.GOSYMDEF.
+	 * load foreign objects not referenced by __.PKGDEF.
 	 */
 	for {
 		l = nextar(f, off, &arhdr)
@@ -848,11 +862,11 @@ func objfile(lib *Library) {
 	}
 
 out:
-	obj.Bterm(f)
+	f.Close()
 }
 
 type Hostobj struct {
-	ld     func(*obj.Biobuf, string, int64, string)
+	ld     func(*bio.Reader, string, int64, string)
 	pkg    string
 	pn     string
 	file   string
@@ -873,7 +887,7 @@ var internalpkg = []string{
 	"runtime/msan",
 }
 
-func ldhostobj(ld func(*obj.Biobuf, string, int64, string), f *obj.Biobuf, pkg string, length int64, pn string, file string) *Hostobj {
+func ldhostobj(ld func(*bio.Reader, string, int64, string), f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
 	isinternal := false
 	for i := 0; i < len(internalpkg); i++ {
 		if pkg == internalpkg[i] {
@@ -904,26 +918,24 @@ func ldhostobj(ld func(*obj.Biobuf, string, int64, string), f *obj.Biobuf, pkg s
 	h.pkg = pkg
 	h.pn = pn
 	h.file = file
-	h.off = obj.Boffset(f)
+	h.off = f.Offset()
 	h.length = length
 	return h
 }
 
 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 {
+		f, err := bio.Open(h.file)
+		if err != nil {
 			Exitf("cannot reopen %s: %v", h.pn, err)
 		}
 
-		obj.Bseek(f, h.off, 0)
+		f.Seek(h.off, 0)
 		h.ld(f, h.pkg, h.length, h.pn)
-		obj.Bterm(f)
+		f.Close()
 	}
 }
 
@@ -958,14 +970,14 @@ func hostlinksetup() {
 	coutbuf.f.Close()
 	mayberemoveoutfile()
 
-	p := fmt.Sprintf("%s/go.o", tmpdir)
+	p := filepath.Join(tmpdir, "go.o")
 	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.w = bufio.NewWriter(f)
 	coutbuf.f = f
 }
 
@@ -976,7 +988,7 @@ func hostobjCopy() (paths []string) {
 	sema := make(chan struct{}, runtime.NumCPU()) // limit open file descriptors
 	for i, h := range hostobj {
 		h := h
-		dst := fmt.Sprintf("%s/%06d.o", tmpdir, i)
+		dst := filepath.Join(tmpdir, fmt.Sprintf("%06d.o", i))
 		paths = append(paths, dst)
 
 		wg.Add(1)
@@ -1021,12 +1033,21 @@ func archive() {
 	}
 
 	mayberemoveoutfile()
+
+	// Force the buffer to flush here so that external
+	// tools will see a complete file.
+	Cflush()
+	if err := coutbuf.f.Close(); err != nil {
+		Exitf("close: %v", err)
+	}
+	coutbuf.f = nil
+
 	argv := []string{extar, "-q", "-c", "-s", outfile}
-	argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
+	argv = append(argv, filepath.Join(tmpdir, "go.o"))
 	argv = append(argv, hostobjCopy()...)
 
 	if Debug['v'] != 0 {
-		fmt.Fprintf(&Bso, "archive: %s\n", strings.Join(argv, " "))
+		fmt.Fprintf(Bso, "archive: %s\n", strings.Join(argv, " "))
 		Bso.Flush()
 	}
 
@@ -1077,6 +1098,9 @@ func hostlink() {
 			argv = append(argv, "-Wl,-pagezero_size,4000000")
 		}
 	case BuildmodePIE:
+		if UseRelro() {
+			argv = append(argv, "-Wl,-z,relro")
+		}
 		argv = append(argv, "-pie")
 	case BuildmodeCShared:
 		if HEADTYPE == obj.Hdarwin {
@@ -1103,6 +1127,33 @@ func hostlink() {
 		// because lazy PLT resolution can use large amounts of stack at
 		// times we cannot allow it to do so.
 		argv = append(argv, "-Wl,-znow")
+
+		// Do not let the host linker generate COPY relocations. These
+		// can move symbols out of sections that rely on stable offsets
+		// from the beginning of the section (like STYPE).
+		argv = append(argv, "-Wl,-znocopyreloc")
+
+		if SysArch.InFamily(sys.ARM, sys.ARM64) {
+			// On ARM, the GNU linker will generate COPY relocations
+			// even with -znocopyreloc set.
+			// https://sourceware.org/bugzilla/show_bug.cgi?id=19962
+			//
+			// On ARM64, the GNU linker will fail instead of
+			// generating COPY relocations.
+			//
+			// In both cases, switch to gold.
+			argv = append(argv, "-fuse-ld=gold")
+
+			// If gold is not installed, gcc will silently switch
+			// back to ld.bfd. So we parse the version information
+			// and provide a useful error if gold is missing.
+			cmd := exec.Command(extld, "-fuse-ld=gold", "-Wl,--version")
+			if out, err := cmd.CombinedOutput(); err == nil {
+				if !bytes.Contains(out, []byte("GNU gold")) {
+					log.Fatalf("ARM external linker must be gold (issue #15696), but is not: %s", out)
+				}
+			}
+		}
 	}
 
 	if Iself && len(buildinfo) > 0 {
@@ -1111,8 +1162,8 @@ func hostlink() {
 
 	// 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
+	// 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
@@ -1135,7 +1186,7 @@ func hostlink() {
 		argv = append(argv, "-Qunused-arguments")
 	}
 
-	argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
+	argv = append(argv, filepath.Join(tmpdir, "go.o"))
 	argv = append(argv, hostobjCopy()...)
 
 	if Linkshared {
@@ -1171,15 +1222,42 @@ func hostlink() {
 		}
 	}
 
+	sanitizers := flag_race != 0
+
+	for _, flag := range ldflag {
+		if strings.HasPrefix(flag, "-fsanitize=") {
+			sanitizers = true
+		}
+	}
+
 	argv = append(argv, ldflag...)
 
+	if sanitizers {
+		// On a system where the toolchain creates position independent
+		// executables by default, tsan/msan/asan/etc initialization can
+		// fail. So we pass -no-pie here, but support for that flag is quite
+		// new and we test for its support first.
+		src := filepath.Join(tmpdir, "trivial.c")
+		if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
+			Ctxt.Diag("WriteFile trivial.c failed: %v", err)
+		}
+		cmd := exec.Command(argv[0], "-c", "-no-pie", "trivial.c")
+		cmd.Dir = tmpdir
+		cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
+		out, err := cmd.CombinedOutput()
+		supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
+		if supported {
+			argv = append(argv, "-no-pie")
+		}
+	}
+
 	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
+		// 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" {
@@ -1195,25 +1273,25 @@ func hostlink() {
 	}
 
 	if Debug['v'] != 0 {
-		fmt.Fprintf(&Bso, "host link:")
+		fmt.Fprintf(Bso, "host link:")
 		for _, v := range argv {
-			fmt.Fprintf(&Bso, " %q", v)
+			fmt.Fprintf(Bso, " %q", v)
 		}
-		fmt.Fprintf(&Bso, "\n")
+		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)
+		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 !SysArch.InFamily(sys.ARM, sys.ARM64) {
+			dsym := filepath.Join(tmpdir, "go.dwarf")
 			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)
@@ -1240,31 +1318,33 @@ func hostlink() {
 // hostlinkArchArgs returns arguments to pass to the external linker
 // based on the architecture.
 func hostlinkArchArgs() []string {
-	switch Thearch.Thechar {
-	case '8':
+	switch SysArch.Family {
+	case sys.I386:
 		return []string{"-m32"}
-	case '6', '9':
+	case sys.AMD64, sys.PPC64, sys.S390X:
 		return []string{"-m64"}
-	case '5':
+	case sys.ARM:
 		return []string{"-marm"}
-	case '7':
+	case sys.ARM64:
 		// nothing needed
+	case sys.MIPS64:
+		return []string{"-mabi=64"}
 	}
 	return nil
 }
 
-// ldobj loads an input object.  If it is a host object (an object
-// compiled by a non-Go compiler) it returns the Hostobj pointer.  If
+// ldobj loads an input object. If it is a host object (an object
+// compiled by a non-Go compiler) it returns the Hostobj pointer. If
 // it is a Go object, it returns nil.
-func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, whence int) *Hostobj {
-	eof := obj.Boffset(f) + length
+func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, whence int) *Hostobj {
+	eof := f.Offset() + 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)
+	start := f.Offset()
+	c1 := bgetc(f)
+	c2 := bgetc(f)
+	c3 := bgetc(f)
+	c4 := bgetc(f)
+	f.Seek(start, 0)
 
 	magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
 	if magic == 0x7f454c46 { // \x7F E L F
@@ -1280,22 +1360,19 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when
 	}
 
 	/* check the header */
-	line := obj.Brdline(f, '\n')
-	if line == "" {
-		if obj.Blinelen(f) > 0 {
-			Diag("%s: not an object file", pn)
-			return nil
-		}
-		Diag("truncated object file: %s", pn)
+	line, err := f.ReadString('\n')
+	if err != nil {
+		Diag("truncated object file: %s: %v", pn, err)
 		return nil
 	}
 
 	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)
+			Exitf("%s: uncompiled .go source file", pn)
+			return nil
 		}
 
-		if line == Thestring {
+		if line == SysArch.Name {
 			// old header format: just $GOOS
 			Diag("%s: stale object file", pn)
 			return nil
@@ -1327,28 +1404,28 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when
 	}
 
 	/* skip over exports and other info -- ends with \n!\n */
-	import0 := obj.Boffset(f)
+	import0 := f.Offset()
 
 	c1 = '\n' // the last line ended in \n
-	c2 = obj.Bgetc(f)
-	c3 = obj.Bgetc(f)
+	c2 = bgetc(f)
+	c3 = bgetc(f)
 	for c1 != '\n' || c2 != '!' || c3 != '\n' {
 		c1 = c2
 		c2 = c3
-		c3 = obj.Bgetc(f)
-		if c3 == obj.Beof {
+		c3 = bgetc(f)
+		if c3 == -1 {
 			Diag("truncated object file: %s", pn)
 			return nil
 		}
 	}
 
-	import1 := obj.Boffset(f)
+	import1 := f.Offset()
 
-	obj.Bseek(f, import0, 0)
+	f.Seek(import0, 0)
 	ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n
-	obj.Bseek(f, import1, 0)
+	f.Seek(import1, 0)
 
-	ldobjfile(Ctxt, f, pkg, eof-obj.Boffset(f), pn)
+	LoadObjFile(Ctxt, f, pkg, eof-f.Offset(), pn)
 	return nil
 }
 
@@ -1471,9 +1548,10 @@ func ldshlibsyms(shlib string) {
 		}
 		lsym := Linklookup(Ctxt, elfsym.Name, 0)
 		// Because loadlib above loads all .a files before loading any shared
-		// libraries, any symbols we find that duplicate symbols already
-		// loaded should be ignored (the symbols from the .a files "win").
-		if lsym.Type != 0 {
+		// libraries, any non-dynimport symbols we find that duplicate symbols
+		// already loaded should be ignored (the symbols from the .a files
+		// "win").
+		if lsym.Type != 0 && lsym.Type != obj.SDYNIMPORT {
 			continue
 		}
 		lsym.Type = obj.SDYNIMPORT
@@ -1486,12 +1564,12 @@ func ldshlibsyms(shlib string) {
 			// the type data.
 			if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
 				lsym.P = readelfsymboldata(f, &elfsym)
-				gcdata_locations[elfsym.Value+2*uint64(Thearch.Ptrsize)+8+1*uint64(Thearch.Ptrsize)] = lsym
+				gcdata_locations[elfsym.Value+2*uint64(SysArch.PtrSize)+8+1*uint64(SysArch.PtrSize)] = lsym
 			}
 		}
 	}
 	gcdata_addresses := make(map[*LSym]uint64)
-	if Thearch.Thechar == '7' {
+	if SysArch.Family == sys.ARM64 {
 		for _, sect := range f.Sections {
 			if sect.Type == elf.SHT_RELA {
 				var rela elf.Rela64
@@ -1518,30 +1596,14 @@ func ldshlibsyms(shlib string) {
 
 	// 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
+	// pcln table entries for these any more so remove them from Textp.
+	textp := make([]*LSym, 0, len(Ctxt.Textp))
+	for _, s := range Ctxt.Textp {
+		if s.Type != obj.SDYNIMPORT {
+			textp = append(textp, s)
 		}
-		last = s
-	}
-
-	if last == nil {
-		Ctxt.Textp = nil
-		Ctxt.Etextp = nil
-	} else {
-		last.Next = nil
-		Ctxt.Etextp = last
 	}
+	Ctxt.Textp = textp
 
 	Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdata_addresses: gcdata_addresses})
 }
@@ -1550,10 +1612,6 @@ 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.
@@ -1594,7 +1652,7 @@ func addsection(seg *Segment, name string, rwx int) *Section {
 	sect.Rwx = uint8(rwx)
 	sect.Name = name
 	sect.Seg = seg
-	sect.Align = int32(Thearch.Ptrsize) // everything is at least pointer-aligned
+	sect.Align = int32(SysArch.PtrSize) // everything is at least pointer-aligned
 	*l = sect
 	return sect
 }
@@ -1638,7 +1696,7 @@ func callsize() int {
 	if haslinkregister() {
 		return 0
 	}
-	return Thearch.Regsize
+	return SysArch.RegSize
 }
 
 func dostkcheck() {
@@ -1659,7 +1717,7 @@ func dostkcheck() {
 
 	// Check every function, but do the nosplit functions in a first pass,
 	// to make the printed failure chains as short as possible.
-	for s := Ctxt.Textp; s != nil; s = s.Next {
+	for _, s := range Ctxt.Textp {
 		// 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.
@@ -1667,15 +1725,15 @@ func dostkcheck() {
 			continue
 		}
 
-		if s.Nosplit != 0 {
+		if s.Attr.NoSplit() {
 			Ctxt.Cursym = s
 			ch.sym = s
 			stkcheck(&ch, 0)
 		}
 	}
 
-	for s := Ctxt.Textp; s != nil; s = s.Next {
-		if s.Nosplit == 0 {
+	for _, s := range Ctxt.Textp {
+		if !s.Attr.NoSplit() {
 			Ctxt.Cursym = s
 			ch.sym = s
 			stkcheck(&ch, 0)
@@ -1691,10 +1749,10 @@ func stkcheck(up *Chain, depth int) int {
 	// function at top of safe zone once.
 	top := limit == obj.StackLimit-callsize()
 	if top {
-		if s.Stkcheck != 0 {
+		if s.Attr.StackCheck() {
 			return 0
 		}
-		s.Stkcheck = 1
+		s.Attr |= AttrStackCheck
 	}
 
 	if depth > 100 {
@@ -1703,7 +1761,7 @@ func stkcheck(up *Chain, depth int) int {
 		return -1
 	}
 
-	if s.External != 0 || s.Pcln == nil {
+	if s.Attr.External() || s.FuncInfo == nil {
 		// external function.
 		// should never be called directly.
 		// only diagnose the direct caller.
@@ -1729,7 +1787,7 @@ func stkcheck(up *Chain, depth int) int {
 	var ch Chain
 	ch.up = up
 
-	if s.Nosplit == 0 {
+	if !s.Attr.NoSplit() {
 		// Ensure we have enough stack to call morestack.
 		ch.limit = limit - callsize()
 		ch.sym = morestack
@@ -1740,7 +1798,11 @@ func stkcheck(up *Chain, depth int) int {
 			return 0
 		}
 		// Raise limit to allow frame.
-		limit = int(obj.StackLimit+s.Locals) + int(Ctxt.FixedFrameSize())
+		locals := int32(0)
+		if s.FuncInfo != nil {
+			locals = s.FuncInfo.Locals
+		}
+		limit = int(obj.StackLimit+locals) + int(Ctxt.FixedFrameSize())
 	}
 
 	// Walk through sp adjustments in function, consuming relocs.
@@ -1750,7 +1812,7 @@ func stkcheck(up *Chain, depth int) int {
 	var ch1 Chain
 	var pcsp Pciter
 	var r *Reloc
-	for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
+	for pciterinit(Ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
 		// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
 
 		// Check stack size in effect for this span.
@@ -1771,7 +1833,7 @@ func stkcheck(up *Chain, depth int) int {
 					return -1
 				}
 
-			// Indirect call.  Assume it is a call to a splitting function,
+			// 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.
@@ -1802,7 +1864,7 @@ func stkprint(ch *Chain, limit int) {
 
 	if ch.sym != nil {
 		name = ch.sym.Name
-		if ch.sym.Nosplit != 0 {
+		if ch.sym.Attr.NoSplit() {
 			name += " (nosplit)"
 		}
 	} else {
@@ -1811,7 +1873,7 @@ func stkprint(ch *Chain, limit int) {
 
 	if ch.up == nil {
 		// top of chain.  ch->sym != nil.
-		if ch.sym.Nosplit != 0 {
+		if ch.sym.Attr.NoSplit() {
 			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)
@@ -1829,24 +1891,28 @@ func stkprint(ch *Chain, limit int) {
 }
 
 func Cflush() {
-	if err := coutbuf.Writer.Flush(); err != nil {
+	if err := coutbuf.w.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())
+	return coutbuf.off
 }
 
 func Cseek(p int64) {
+	if p == coutbuf.off {
+		return
+	}
 	Cflush()
 	if _, err := coutbuf.f.Seek(p, 0); err != nil {
 		Exitf("seeking in output [0, 1]: %v", err)
 	}
+	coutbuf.off = p
+}
+
+func Cwritestring(s string) {
+	coutbuf.WriteString(s)
 }
 
 func Cwrite(p []byte) {
@@ -1854,7 +1920,8 @@ func Cwrite(p []byte) {
 }
 
 func Cput(c uint8) {
-	coutbuf.WriteByte(c)
+	coutbuf.w.WriteByte(c)
+	coutbuf.off++
 }
 
 func usage() {
@@ -1886,7 +1953,6 @@ 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)
 	}
@@ -1895,8 +1961,11 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
 		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 == "" || s.Name[0] == '.') && s.Version == 0 && s.Name != ".rathole" && s.Name != ".TOC.") {
+	for _, s := range Ctxt.Allsym {
+		if s.Attr.Hidden() {
+			continue
+		}
+		if (s.Name == "" || s.Name[0] == '.') && s.Version == 0 && s.Name != ".rathole" && s.Name != ".TOC." {
 			continue
 		}
 		switch s.Type & obj.SMASK {
@@ -1912,27 +1981,30 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
 			obj.STYPE,
 			obj.SSTRING,
 			obj.SGOSTRING,
+			obj.SGOSTRINGHDR,
 			obj.SGOFUNC,
 			obj.SGCBITS,
 			obj.STYPERELRO,
 			obj.SSTRINGRELRO,
 			obj.SGOSTRINGRELRO,
+			obj.SGOSTRINGHDRRELRO,
 			obj.SGOFUNCRELRO,
 			obj.SGCBITSRELRO,
 			obj.SRODATARELRO,
 			obj.STYPELINK,
+			obj.SITABLINK,
 			obj.SWINDOWS:
-			if !s.Reachable {
+			if !s.Attr.Reachable() {
 				continue
 			}
 			put(s, s.Name, 'D', Symaddr(s), s.Size, int(s.Version), s.Gotype)
 
 		case obj.SBSS, obj.SNOPTRBSS:
-			if !s.Reachable {
+			if !s.Attr.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)
+				Diag("%s should not be bss (size=%d type=%d special=%v)", s.Name, len(s.P), s.Type, s.Attr.Special())
 			}
 			put(s, s.Name, 'B', Symaddr(s), s.Size, int(s.Version), s.Gotype)
 
@@ -1945,7 +2017,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
 			}
 
 		case obj.SDYNIMPORT:
-			if !s.Reachable {
+			if !s.Attr.Reachable() {
 				continue
 			}
 			put(s, s.Extname, 'U', 0, 0, int(s.Version), nil)
@@ -1957,15 +2029,21 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
 		}
 	}
 
-	var a *Auto
 	var off int32
-	for s := Ctxt.Textp; s != nil; s = s.Next {
+	for _, s := range Ctxt.Textp {
 		put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype)
 
+		locals := int32(0)
+		if s.FuncInfo != nil {
+			locals = s.FuncInfo.Locals
+		}
 		// 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)
+		put(nil, ".frame", 'm', int64(locals)+int64(SysArch.PtrSize), 0, 0, nil)
 
-		for a = s.Autom; a != nil; a = a.Link {
+		if s.FuncInfo == nil {
+			continue
+		}
+		for _, a := range s.FuncInfo.Autom {
 			// 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 {
@@ -1976,7 +2054,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
 			if a.Name == obj.A_PARAM {
 				off = a.Aoffset
 			} else {
-				off = a.Aoffset - int32(Thearch.Ptrsize)
+				off = a.Aoffset - int32(SysArch.PtrSize)
 			}
 
 			// FP
@@ -1986,8 +2064,8 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
 			}
 
 			// SP
-			if off <= int32(-Thearch.Ptrsize) {
-				put(nil, a.Asym.Name, 'a', -(int64(off) + int64(Thearch.Ptrsize)), 0, 0, a.Gotype)
+			if off <= int32(-SysArch.PtrSize) {
+				put(nil, a.Asym.Name, 'a', -(int64(off) + int64(SysArch.PtrSize)), 0, 0, a.Gotype)
 				continue
 			}
 		}
@@ -1996,13 +2074,13 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
 	// 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))
+		fmt.Fprintf(Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
 	}
 	Bso.Flush()
 }
 
 func Symaddr(s *LSym) int64 {
-	if !s.Reachable {
+	if !s.Attr.Reachable() {
 		Diag("unreachable symbol in symaddr - %s", s.Name)
 	}
 	return s.Value
@@ -2012,9 +2090,9 @@ 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
+	s.Attr |= AttrReachable
+	s.Attr |= AttrSpecial
+	s.Attr |= AttrLocal
 }
 
 func datoff(addr int64) int64 {
@@ -2055,17 +2133,17 @@ func undefsym(s *LSym) {
 		if r.Sym.Type == obj.Sxxx || r.Sym.Type == obj.SXREF {
 			Diag("undefined: %s", r.Sym.Name)
 		}
-		if !r.Sym.Reachable {
+		if !r.Sym.Attr.Reachable() {
 			Diag("use of unreachable symbol: %s", r.Sym.Name)
 		}
 	}
 }
 
 func undef() {
-	for s := Ctxt.Textp; s != nil; s = s.Next {
+	for _, s := range Ctxt.Textp {
 		undefsym(s)
 	}
-	for s := datap; s != nil; s = s.Next {
+	for _, s := range datap {
 		undefsym(s)
 	}
 	if nerrors > 0 {
@@ -2080,14 +2158,14 @@ func callgraph() {
 
 	var i int
 	var r *Reloc
-	for s := Ctxt.Textp; s != nil; s = s.Next {
+	for _, s := range Ctxt.Textp {
 		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.Type == obj.R_CALLMIPS) && r.Sym.Type == obj.STEXT {
-				fmt.Fprintf(&Bso, "%s calls %s\n", s.Name, r.Sym.Name)
+				fmt.Fprintf(Bso, "%s calls %s\n", s.Name, r.Sym.Name)
 			}
 		}
 	}
@@ -2110,63 +2188,6 @@ func Diag(format string, args ...interface{}) {
 	}
 }
 
-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
@@ -2179,3 +2200,14 @@ func Rnd(v int64, r int64) int64 {
 	v -= c
 	return v
 }
+
+func bgetc(r *bio.Reader) int {
+	c, err := r.ReadByte()
+	if err != nil {
+		if err != io.EOF {
+			log.Fatalf("reading input: %v", err)
+		}
+		return -1
+	}
+	return int(c)
+}
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index 73d23c6..9bab68b 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -31,59 +31,43 @@
 package ld
 
 import (
-	"cmd/internal/obj"
+	"bufio"
+	"cmd/internal/sys"
 	"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
+	Name        string
+	Extname     string
+	Type        int16
+	Version     int16
+	Attr        Attribute
+	Localentry  uint8
 	Dynid       int32
 	Plt         int32
 	Got         int32
 	Align       int32
 	Elfsym      int32
 	LocalElfsym int32
-	Args        int32
-	Locals      int32
 	Value       int64
 	Size        int64
-	Allsym      *LSym
+	// 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
 	Next        *LSym
 	Sub         *LSym
 	Outer       *LSym
 	Gotype      *LSym
 	Reachparent *LSym
-	Queue       *LSym
 	File        string
 	Dynimplib   string
 	Dynimpvers  string
 	Sect        *Section
-	Autom       *Auto
-	Pcln        *Pcln
+	FuncInfo    *FuncInfo
 	P           []byte
 	R           []Reloc
-	Local       bool
 }
 
 func (s *LSym) String() string {
@@ -103,6 +87,49 @@ func (s *LSym) ElfsymForReloc() int32 {
 	}
 }
 
+// Attribute is a set of common symbol attributes.
+type Attribute int16
+
+const (
+	AttrDuplicateOK Attribute = 1 << iota
+	AttrExternal
+	AttrNoSplit
+	AttrReachable
+	AttrCgoExportDynamic
+	AttrCgoExportStatic
+	AttrSpecial
+	AttrStackCheck
+	AttrHidden
+	AttrOnList
+	AttrLocal
+	AttrReflectMethod
+)
+
+func (a Attribute) DuplicateOK() bool      { return a&AttrDuplicateOK != 0 }
+func (a Attribute) External() bool         { return a&AttrExternal != 0 }
+func (a Attribute) NoSplit() bool          { return a&AttrNoSplit != 0 }
+func (a Attribute) Reachable() bool        { return a&AttrReachable != 0 }
+func (a Attribute) CgoExportDynamic() bool { return a&AttrCgoExportDynamic != 0 }
+func (a Attribute) CgoExportStatic() bool  { return a&AttrCgoExportStatic != 0 }
+func (a Attribute) Special() bool          { return a&AttrSpecial != 0 }
+func (a Attribute) StackCheck() bool       { return a&AttrStackCheck != 0 }
+func (a Attribute) Hidden() bool           { return a&AttrHidden != 0 }
+func (a Attribute) OnList() bool           { return a&AttrOnList != 0 }
+func (a Attribute) Local() bool            { return a&AttrLocal != 0 }
+func (a Attribute) ReflectMethod() bool    { return a&AttrReflectMethod != 0 }
+
+func (a Attribute) CgoExport() bool {
+	return a.CgoExportDynamic() || a.CgoExportStatic()
+}
+
+func (a *Attribute) Set(flag Attribute, value bool) {
+	if value {
+		*a |= flag
+	} else {
+		*a &^= flag
+	}
+}
+
 type Reloc struct {
 	Off     int32
 	Siz     uint8
@@ -117,10 +144,9 @@ type Reloc struct {
 
 type Auto struct {
 	Asym    *LSym
-	Link    *Auto
+	Gotype  *LSym
 	Aoffset int32
 	Name    int16
-	Gotype  *LSym
 }
 
 type Shlib struct {
@@ -132,19 +158,18 @@ type Shlib struct {
 }
 
 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
+	Goarm     int32
+	Headtype  int
+	Arch      *sys.Arch
+	Debugvlog int32
+	Bso       *bufio.Writer
+	Windows   int32
+	Goroot    string
+
+	// Symbol lookup based on name and indexed by version.
+	Hash []map[string]*LSym
+
+	Allsym     []*LSym
 	Tlsg       *LSym
 	Libdir     []string
 	Library    []*Library
@@ -153,11 +178,10 @@ type Link struct {
 	Diag       func(string, ...interface{})
 	Cursym     *LSym
 	Version    int
-	Textp      *LSym
-	Etextp     *LSym
-	Nhistfile  int32
-	Filesyms   *LSym
+	Textp      []*LSym
+	Filesyms   []*LSym
 	Moduledata *LSym
+	LSymBatch  []LSym
 }
 
 // The smallest possible offset from the hardware stack pointer to a local
@@ -165,25 +189,21 @@ type Link struct {
 // on the stack in the function prologue and so always have a pointer between
 // the hardware stack pointer and the local variable area.
 func (ctxt *Link) FixedFrameSize() int64 {
-	switch ctxt.Arch.Thechar {
-	case '6', '8':
+	switch ctxt.Arch.Family {
+	case sys.AMD64, sys.I386:
 		return 0
-	case '9':
+	case sys.PPC64:
 		// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
 		// just use that much stack always on ppc64x.
-		return int64(4 * ctxt.Arch.Ptrsize)
+		return int64(4 * ctxt.Arch.PtrSize)
 	default:
-		return int64(ctxt.Arch.Ptrsize)
+		return int64(ctxt.Arch.PtrSize)
 	}
 }
 
-type LinkArch struct {
-	ByteOrder binary.ByteOrder
-	Name      string
-	Thechar   int
-	Minlc     int
-	Ptrsize   int
-	Regsize   int
+func (l *Link) IncVersion() {
+	l.Version++
+	l.Hash = append(l.Hash, make(map[string]*LSym))
 }
 
 type Library struct {
@@ -195,20 +215,17 @@ type Library struct {
 	hash   []byte
 }
 
-type Pcln struct {
+type FuncInfo struct {
+	Args        int32
+	Locals      int32
+	Autom       []Auto
 	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 {
@@ -233,6 +250,12 @@ const (
 	RV_POWER_HI
 	RV_POWER_HA
 	RV_POWER_DS
+
+	// RV_390_DBL is a s390x-specific relocation variant that indicates that
+	// the value to be placed into the relocatable field should first be
+	// divided by 2.
+	RV_390_DBL
+
 	RV_CHECK_OVERFLOW = 1 << 8
 	RV_TYPE_MASK      = RV_CHECK_OVERFLOW - 1
 )
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index cf3fba1..53cc962 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -6,6 +6,7 @@ package ld
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"sort"
 	"strings"
 )
@@ -78,6 +79,8 @@ const (
 	MACHO_X86_64_RELOC_SIGNED_2   = 7
 	MACHO_X86_64_RELOC_SIGNED_4   = 8
 	MACHO_ARM_RELOC_VANILLA       = 0
+	MACHO_ARM_RELOC_PAIR          = 1
+	MACHO_ARM_RELOC_SECTDIFF      = 2
 	MACHO_ARM_RELOC_BR24          = 5
 	MACHO_ARM64_RELOC_UNSIGNED    = 0
 	MACHO_ARM64_RELOC_BRANCH26    = 2
@@ -123,23 +126,15 @@ var sortsym []*LSym
 var nsortsym int
 
 // Amount of space left for adding load commands
-// that refer to dynamic libraries.  Because these have
+// 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
+// "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
-	}
+	macho64 = SysArch.RegSize == 8
 }
 
 func getMachoHdr() *MachoHdr {
@@ -308,37 +303,37 @@ func domacho() {
 	s := Linklookup(Ctxt, ".machosymstr", 0)
 
 	s.Type = obj.SMACHOSYMSTR
-	s.Reachable = true
+	s.Attr |= AttrReachable
 	Adduint8(Ctxt, s, ' ')
 	Adduint8(Ctxt, s, '\x00')
 
 	s = Linklookup(Ctxt, ".machosymtab", 0)
 	s.Type = obj.SMACHOSYMTAB
-	s.Reachable = true
+	s.Attr |= AttrReachable
 
 	if Linkmode != LinkExternal {
 		s := Linklookup(Ctxt, ".plt", 0) // will be __symbol_stub
 		s.Type = obj.SMACHOPLT
-		s.Reachable = true
+		s.Attr |= AttrReachable
 
 		s = Linklookup(Ctxt, ".got", 0) // will be __nl_symbol_ptr
 		s.Type = obj.SMACHOGOT
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		s.Align = 4
 
 		s = Linklookup(Ctxt, ".linkedit.plt", 0) // indirect table for .plt
 		s.Type = obj.SMACHOINDIRECTPLT
-		s.Reachable = true
+		s.Attr |= AttrReachable
 
 		s = Linklookup(Ctxt, ".linkedit.got", 0) // indirect table for .got
 		s.Type = obj.SMACHOINDIRECTGOT
-		s.Reachable = true
+		s.Attr |= AttrReachable
 	}
 }
 
 func Machoadddynlib(lib string) {
 	// Will need to store the library name rounded up
-	// and 24 bytes of header metadata.  If not enough
+	// 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
@@ -356,9 +351,10 @@ 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' || // arm64
-		(Thearch.Thechar == '6' && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) { // amd64
-		// Darwin external linker on arm64 and on amd64 in c-shared/c-archive buildmode
+	if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 ||
+		(SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive)) ||
+		(SysArch.Family == sys.ARM && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) {
+		// Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode
 		// complains about absolute relocs in __TEXT, so if the section is not
 		// executable, put it in __DATA segment.
 		msect = newMachoSect(mseg, buf, "__DATA")
@@ -411,6 +407,10 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
 		msect.name = "__mod_init_func"
 		msect.flag = 9 // S_MOD_INIT_FUNC_POINTERS
 	}
+
+	if segname == "__DWARF" {
+		msect.flag |= 0x02000000
+	}
 }
 
 func Asmbmacho() {
@@ -418,23 +418,23 @@ func Asmbmacho() {
 	va := INITTEXT - int64(HEADR)
 
 	mh := getMachoHdr()
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Exitf("unknown macho architecture: %v", Thearch.Thechar)
+		Exitf("unknown macho architecture: %v", SysArch.Family)
 
-	case '5':
+	case sys.ARM:
 		mh.cpu = MACHO_CPU_ARM
 		mh.subcpu = MACHO_SUBCPU_ARMV7
 
-	case '6':
+	case sys.AMD64:
 		mh.cpu = MACHO_CPU_AMD64
 		mh.subcpu = MACHO_SUBCPU_X86
 
-	case '7':
+	case sys.ARM64:
 		mh.cpu = MACHO_CPU_ARM64
 		mh.subcpu = MACHO_SUBCPU_ARM64_ALL
 
-	case '8':
+	case sys.I386:
 		mh.cpu = MACHO_CPU_386
 		mh.subcpu = MACHO_SUBCPU_X86
 	}
@@ -445,7 +445,7 @@ func Asmbmacho() {
 		ms = newMachoSeg("", 40)
 
 		ms.fileoffset = Segtext.Fileoff
-		if Thearch.Thechar == '5' || Buildmode == BuildmodeCArchive {
+		if SysArch.Family == sys.ARM || Buildmode == BuildmodeCArchive {
 			ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
 		} else {
 			ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
@@ -492,32 +492,46 @@ func Asmbmacho() {
 		machoshbits(ms, sect, "__DATA")
 	}
 
+	/* dwarf */
+	if Debug['w'] == 0 {
+		if Linkmode != LinkExternal {
+			ms = newMachoSeg("__DWARF", 20)
+			ms.vaddr = Segdwarf.Vaddr
+			ms.vsize = 0
+			ms.fileoffset = Segdwarf.Fileoff
+			ms.filesize = Segdwarf.Filelen
+		}
+		for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+			machoshbits(ms, sect, "__DWARF")
+		}
+	}
+
 	if Linkmode != LinkExternal {
-		switch Thearch.Thechar {
+		switch SysArch.Family {
 		default:
-			Exitf("unknown macho architecture: %v", Thearch.Thechar)
+			Exitf("unknown macho architecture: %v", SysArch.Family)
 
-		case '5':
+		case sys.ARM:
 			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':
+		case sys.AMD64:
 			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':
+		case sys.ARM64:
 			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':
+		case sys.I386:
 			ml := newMachoLoad(5, 16+2)          /* unix thread */
 			ml.data[0] = 1                       /* thread type */
 			ml.data[1] = 16                      /* word count */
@@ -528,7 +542,6 @@ func Asmbmacho() {
 	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)
@@ -570,27 +583,19 @@ func Asmbmacho() {
 	if Linkmode == LinkInternal {
 		// For lldb, must say LC_VERSION_MIN_MACOSX or else
 		// it won't know that this Mach-O binary is from OS X
-		// (could be iOS or WatchOS intead).
+		// (could be iOS or WatchOS instead).
 		// Go on iOS uses linkmode=external, and linkmode=external
 		// adds this itself. So we only need this code for linkmode=internal
 		// and we can assume OS X.
 		//
 		// See golang.org/issues/12941.
-		const (
-			LC_VERSION_MIN_MACOSX   = 0x24
-			LC_VERSION_MIN_IPHONEOS = 0x25
-			LC_VERSION_MIN_WATCHOS  = 0x30
-		)
+		const LC_VERSION_MIN_MACOSX = 0x24
+
 		ml := newMachoLoad(LC_VERSION_MIN_MACOSX, 2)
 		ml.data[0] = 10<<16 | 7<<8 | 0<<0 // OS X version 10.7.0
 		ml.data[1] = 10<<16 | 7<<8 | 0<<0 // SDK 10.7.0
 	}
 
-	// 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)
@@ -601,7 +606,7 @@ func symkind(s *LSym) int {
 	if s.Type == obj.SDYNIMPORT {
 		return SymKindUndef
 	}
-	if s.Cgoexport != 0 {
+	if s.Attr.CgoExport() {
 		return SymKindExtdef
 	}
 	return SymKindLocal
@@ -653,9 +658,9 @@ func (x machoscmp) Less(i, j int) bool {
 
 func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
 	genasmsym(put)
-	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+	for _, s := range Ctxt.Allsym {
 		if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
-			if s.Reachable {
+			if s.Attr.Reachable() {
 				put(s, "", 'D', 0, 0, 0, nil)
 			}
 		}
@@ -667,7 +672,7 @@ func machosymorder() {
 	// 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
+		dynexp[i].Attr |= AttrReachable
 	}
 	machogenasmsym(addsym)
 	sortsym = make([]*LSym, nsortsym)
@@ -680,15 +685,11 @@ func machosymorder() {
 }
 
 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]
+		s := sortsym[i]
 		Adduint32(Ctxt, symtab, uint32(symstr.Size))
 
 		// Only add _ to C symbols. Go symbols have dot in the name.
@@ -697,33 +698,20 @@ func machosymtab() {
 		}
 
 		// 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')
-		}
+		Addstring(symstr, strings.Replace(s.Extname, "·", ".", -1))
 
 		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
+			adduintxx(Ctxt, symtab, 0, SysArch.PtrSize) // no value
 		} else {
-			if s.Cgoexport != 0 {
+			if s.Attr.CgoExport() {
 				Adduint8(Ctxt, symtab, 0x0f)
 			} else {
 				Adduint8(Ctxt, symtab, 0x0e)
 			}
-			o = s
+			o := s
 			for o.Outer != nil {
 				o = o.Outer
 			}
@@ -734,7 +722,7 @@ func machosymtab() {
 				Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum))
 			}
 			Adduint16(Ctxt, symtab, 0) // desc
-			adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize)
+			adduintxx(Ctxt, symtab, uint64(Symaddr(s)), SysArch.PtrSize)
 		}
 	}
 }
@@ -786,12 +774,12 @@ func Domacholink() int64 {
 	s4 := Linklookup(Ctxt, ".machosymstr", 0)
 
 	// Force the linkedit section to end on a 16-byte
-	// boundary.  This allows pure (non-cgo) Go binaries
+	// 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,
+	// 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
@@ -821,28 +809,26 @@ func Domacholink() int64 {
 	return Rnd(int64(size), int64(INITRND))
 }
 
-func machorelocsect(sect *Section, first *LSym) {
+func machorelocsect(sect *Section, syms []*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 {
+	for i, s := range syms {
+		if !s.Attr.Reachable() {
 			continue
 		}
-		if uint64(sym.Value) >= sect.Vaddr {
+		if uint64(s.Value) >= sect.Vaddr {
+			syms = syms[i:]
 			break
 		}
 	}
 
 	eaddr := int32(sect.Vaddr + sect.Length)
-	var r *Reloc
-	var ri int
-	for ; sym != nil; sym = sym.Next {
-		if !sym.Reachable {
+	for _, sym := range syms {
+		if !sym.Attr.Reachable() {
 			continue
 		}
 		if sym.Value >= int64(eaddr) {
@@ -850,8 +836,8 @@ func machorelocsect(sect *Section, first *LSym) {
 		}
 		Ctxt.Cursym = sym
 
-		for ri = 0; ri < len(sym.R); ri++ {
-			r = &sym.R[ri]
+		for ri := 0; ri < len(sym.R); ri++ {
+			r := &sym.R[ri]
 			if r.Done != 0 {
 				continue
 			}
@@ -876,5 +862,7 @@ func Machoemitreloc() {
 	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		machorelocsect(sect, datap)
 	}
-	dwarfemitreloc()
+	for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
+		machorelocsect(sect, list2slice(dwarfp))
+	}
 }
diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go
index b5a5a8d..dcc371e 100644
--- a/src/cmd/link/internal/ld/macho_combine_dwarf.go
+++ b/src/cmd/link/internal/ld/macho_combine_dwarf.go
@@ -15,11 +15,9 @@ import (
 	"unsafe"
 )
 
-var fakedwarf, realdwarf, linkseg *macho.Segment
+var realdwarf, linkseg *macho.Segment
 var dwarfstart, linkstart int64
 var linkoffset uint32
-var machHeader *macho.FileHeader
-var mappedHeader []byte
 
 const (
 	LC_ID_DYLIB             = 0xd
diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go
index 36a65ba..be9832d 100644
--- a/src/cmd/link/internal/ld/objfile.go
+++ b/src/cmd/link/internal/ld/objfile.go
@@ -1,10 +1,10 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
+// 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
@@ -17,13 +17,23 @@ package ld
 //
 // The file format is:
 //
-//	- magic header: "\x00\x00go13ld"
+//	- magic header: "\x00\x00go17ld"
 //	- byte 1 - version number
 //	- sequence of strings giving dependencies (imported packages)
 //	- empty string (marks end of sequence)
+//	- sequence of symbol references used by the defined symbols
+//	- byte 0xff (marks end of sequence)
+//	- sequence of integer lengths:
+//		- total data length
+//		- total number of relocations
+//		- total number of pcdata
+//		- total number of automatics
+//		- total number of funcdata
+//		- total number of files
+//	- data, the content of the defined symbols
 //	- sequence of defined symbols
 //	- byte 0xff (marks end of sequence)
-//	- magic footer: "\xff\xffgo13ld"
+//	- magic footer: "\xff\xffgo17ld"
 //
 // All integers are stored in a zigzag varint format.
 // See golang.org/s/go12symtab for a definition.
@@ -32,18 +42,21 @@ package ld
 // 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.
+//
+// A symbol points to other symbols using an index into the symbol
+// reference sequence. Index 0 corresponds to a nil LSym* pointer.
+// In the symbol layout described below "symref index" stands for this
+// index.
 //
 // Each symbol is laid out as the following fields (taken from LSym*):
 //
 //	- byte 0xfe (sanity check for synchronization)
 //	- type [int]
-//	- name [string]
-//	- version [int]
+//	- name & version [symref index]
 //	- flags [int]
 //		1 dupok
 //	- size [int]
-//	- gotype [symbol reference]
+//	- gotype [symref index]
 //	- p [data block]
 //	- nr [int]
 //	- r [nr relocations, sorted by off]
@@ -54,8 +67,9 @@ package ld
 //	- locals [int]
 //	- nosplit [int]
 //	- flags [int]
-//		1 leaf
-//		2 C function
+//		1<<0 leaf
+//		1<<1 C function
+//		1<<2 function may call reflect.Type.Method
 //	- nlocal [int]
 //	- local [nlocal automatics]
 //	- pcln [pcln table]
@@ -66,16 +80,14 @@ package ld
 //	- siz [int]
 //	- type [int]
 //	- add [int]
-//	- xadd [int]
-//	- sym [symbol reference]
-//	- xsym [symbol reference]
+//	- sym [symref index]
 //
 // Each local has the encoding:
 //
-//	- asym [symbol reference]
+//	- asym [symref index]
 //	- offset [int]
 //	- type [int]
-//	- gotype [symbol reference]
+//	- gotype [symref index]
 //
 // The pcln table has the encoding:
 //
@@ -85,106 +97,173 @@ package ld
 //	- npcdata [int]
 //	- pcdata [npcdata data blocks]
 //	- nfuncdata [int]
-//	- funcdata [nfuncdata symbol references]
+//	- funcdata [nfuncdata symref index]
 //	- funcdatasym [nfuncdata ints]
 //	- nfile [int]
-//	- file [nfile symbol references]
+//	- file [nfile symref index]
 //
 // 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 (
+	"bufio"
 	"bytes"
+	"cmd/internal/bio"
 	"cmd/internal/obj"
-	"fmt"
+	"crypto/sha1"
+	"encoding/base64"
+	"io"
 	"log"
 	"strconv"
 	"strings"
 )
 
 const (
-	startmagic = "\x00\x00go13ld"
-	endmagic   = "\xff\xffgo13ld"
+	startmagic = "\x00\x00go17ld"
+	endmagic   = "\xff\xffgo17ld"
 )
 
-func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) {
-	start := obj.Boffset(f)
-	ctxt.Version++
+var emptyPkg = []byte(`"".`)
+
+// objReader reads Go object files.
+type objReader struct {
+	rd   *bufio.Reader
+	ctxt *Link
+	pkg  string
+	pn   string
+	// List of symbol references for the file being read.
+	dupSym *LSym
+
+	// rdBuf is used by readString and readSymName as scratch for reading strings.
+	rdBuf []byte
+
+	refs        []*LSym
+	data        []byte
+	reloc       []Reloc
+	pcdata      []Pcdata
+	autom       []Auto
+	funcdata    []*LSym
+	funcdataoff []int64
+	file        []*LSym
+}
+
+func LoadObjFile(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
+	start := f.Offset()
+	r := &objReader{
+		rd:     f.Reader,
+		pkg:    pkg,
+		ctxt:   ctxt,
+		pn:     pn,
+		dupSym: &LSym{Name: ".dup"},
+	}
+	r.loadObjFile()
+	if f.Offset() != start+length {
+		log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length)
+	}
+}
+
+func (r *objReader) loadObjFile() {
+	// Increment context version, versions are used to differentiate static files in different packages
+	r.ctxt.IncVersion()
+
+	// Magic header
 	var buf [8]uint8
-	obj.Bread(f, buf[:])
+	r.readFull(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])
+		log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.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)
+
+	// Version
+	c, err := r.rd.ReadByte()
+	if err != nil || c != 1 {
+		log.Fatalf("%s: invalid file version number %d", r.pn, c)
 	}
 
-	var lib string
+	// Autolib
 	for {
-		lib = rdstring(f)
+		lib := r.readString()
 		if lib == "" {
 			break
 		}
-		addlib(ctxt, pkg, pn, lib)
+		addlib(r.ctxt, r.pkg, r.pn, lib)
 	}
 
+	// Symbol references
+	r.refs = []*LSym{nil} // zeroth ref is nil
 	for {
-		c, err := f.Peek(1)
+		c, err := r.rd.Peek(1)
 		if err != nil {
-			log.Fatalf("%s: peeking: %v", pn, err)
+			log.Fatalf("%s: peeking: %v", r.pn, err)
 		}
 		if c[0] == 0xff {
+			r.rd.ReadByte()
 			break
 		}
-		readsym(ctxt, f, pkg, pn)
+		r.readRef()
 	}
 
+	// Lengths
+	r.readSlices()
+
+	// Data section
+	r.readFull(r.data)
+
+	// Defined symbols
+	for {
+		c, err := r.rd.Peek(1)
+		if err != nil {
+			log.Fatalf("%s: peeking: %v", r.pn, err)
+		}
+		if c[0] == 0xff {
+			break
+		}
+		r.readSym()
+	}
+
+	// Magic footer
 	buf = [8]uint8{}
-	obj.Bread(f, buf[:])
+	r.readFull(buf[:])
 	if string(buf[:]) != endmagic {
-		log.Fatalf("%s: invalid file end", pn)
+		log.Fatalf("%s: invalid file end", r.pn)
 	}
+}
 
-	if obj.Boffset(f) != start+length {
-		log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length))
-	}
+func (r *objReader) readSlices() {
+	n := r.readInt()
+	r.data = make([]byte, n)
+	n = r.readInt()
+	r.reloc = make([]Reloc, n)
+	n = r.readInt()
+	r.pcdata = make([]Pcdata, n)
+	n = r.readInt()
+	r.autom = make([]Auto, n)
+	n = r.readInt()
+	r.funcdata = make([]*LSym, n)
+	r.funcdataoff = make([]int64, n)
+	n = r.readInt()
+	r.file = make([]*LSym, n)
 }
 
-var readsym_ndup int
+// Symbols are prefixed so their content doesn't get confused with the magic footer.
+const symPrefix = 0xfe
 
-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
+func (r *objReader) readSym() {
+	if c, err := r.rd.ReadByte(); c != symPrefix || err != nil {
+		log.Fatalln("readSym out of sync")
 	}
-	size := rdint(f)
-	typ := rdsym(ctxt, f, pkg)
-	data := rddata(f)
-	nreloc := rdint(f)
+	t := r.readInt()
+	s := r.readSymIndex()
+	flags := r.readInt()
+	dupok := flags&1 != 0
+	local := flags&2 != 0
+	size := r.readInt()
+	typ := r.readSymIndex()
+	data := r.readData()
+	nreloc := r.readInt()
+	isdup := false
 
-	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 {
@@ -200,24 +279,26 @@ func readsym(ctxt *Link, f *obj.Biobuf, pkg string, pn string) {
 		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 s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
+			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn)
 		}
 		if len(s.P) > 0 {
 			dup = s
-			s = linknewsym(ctxt, ".dup", readsym_ndup)
-			readsym_ndup++ // scratch
+			s = r.dupSym
+			isdup = true
 		}
 	}
 
 overwrite:
-	s.File = pkg
-	s.Dupok = uint8(dupok)
+	s.File = r.pkg
+	if dupok {
+		s.Attr |= AttrDuplicateOK
+	}
 	if t == obj.SXREF {
 		log.Fatalf("bad sxref")
 	}
 	if t == 0 {
-		log.Fatalf("missing type for %s in %s", name, pn)
+		log.Fatalf("missing type for %s in %s", s.Name, r.pn)
 	}
 	if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
 		t = int(s.Type)
@@ -226,257 +307,284 @@ overwrite:
 	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.Attr.Set(AttrLocal, local)
+	if typ != nil {
 		s.Gotype = typ
 	}
-	if dup != nil && typ != nil {
+	if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def
 		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
+		s.R = r.reloc[:nreloc:nreloc]
+		if !isdup {
+			r.reloc = r.reloc[nreloc:]
 		}
-	}
 
-	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)
+		for i := 0; i < nreloc; i++ {
+			s.R[i] = Reloc{
+				Off:  r.readInt32(),
+				Siz:  r.readUint8(),
+				Type: r.readInt32(),
+				Add:  r.readInt64(),
+				Sym:  r.readSymIndex(),
+			}
 		}
 	}
 
 	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
+		s.FuncInfo = new(FuncInfo)
+		pc := s.FuncInfo
+
+		pc.Args = r.readInt32()
+		pc.Locals = r.readInt32()
+		if r.readUint8() != 0 {
+			s.Attr |= AttrNoSplit
+		}
+		flags := r.readInt()
+		if flags&(1<<2) != 0 {
+			s.Attr |= AttrReflectMethod
+		}
+		n := r.readInt()
+		pc.Autom = r.autom[:n:n]
+		if !isdup {
+			r.autom = r.autom[n:]
+		}
+
 		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
+			pc.Autom[i] = Auto{
+				Asym:    r.readSymIndex(),
+				Aoffset: r.readInt32(),
+				Name:    r.readInt16(),
+				Gotype:  r.readSymIndex(),
+			}
 		}
 
-		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
+		pc.Pcsp.P = r.readData()
+		pc.Pcfile.P = r.readData()
+		pc.Pcline.P = r.readData()
+		n = r.readInt()
+		pc.Pcdata = r.pcdata[:n:n]
+		if !isdup {
+			r.pcdata = r.pcdata[n:]
+		}
 		for i := 0; i < n; i++ {
-			pc.Pcdata[i].P = rddata(f)
+			pc.Pcdata[i].P = r.readData()
+		}
+		n = r.readInt()
+		pc.Funcdata = r.funcdata[:n:n]
+		pc.Funcdataoff = r.funcdataoff[:n:n]
+		if !isdup {
+			r.funcdata = r.funcdata[n:]
+			r.funcdataoff = r.funcdataoff[n:]
 		}
-		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)
+			pc.Funcdata[i] = r.readSymIndex()
 		}
 		for i := 0; i < n; i++ {
-			pc.Funcdataoff[i] = rdint64(f)
+			pc.Funcdataoff[i] = r.readInt64()
+		}
+		n = r.readInt()
+		pc.File = r.file[:n:n]
+		if !isdup {
+			r.file = r.file[n:]
 		}
-		n = rdint(f)
-		pc.File = make([]*LSym, n)
-		pc.Nfile = n
 		for i := 0; i < n; i++ {
-			pc.File[i] = rdsym(ctxt, f, pkg)
+			pc.File[i] = r.readSymIndex()
 		}
 
-		if dup == nil {
-			if s.Onlist != 0 {
+		if !isdup {
+			if s.Attr.OnList() {
 				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
+			s.Attr |= AttrOnList
+			r.ctxt.Textp = append(r.ctxt.Textp, 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, ".")
-				}
-			}
+func (r *objReader) readFull(b []byte) {
+	_, err := io.ReadFull(r.rd, b)
+	if err != nil {
+		log.Fatalf("%s: error reading %s", r.pn, err)
+	}
+}
 
-			fmt.Fprintf(ctxt.Bso, "\n")
-			i += 16
-		}
+func (r *objReader) readRef() {
+	if c, err := r.rd.ReadByte(); c != symPrefix || err != nil {
+		log.Fatalf("readSym out of sync")
+	}
+	name := r.readSymName()
+	v := r.readInt()
+	if v != 0 && v != 1 {
+		log.Fatalf("invalid symbol version %d", v)
+	}
+	if v == 1 {
+		v = r.ctxt.Version
+	}
+	s := Linklookup(r.ctxt, name, v)
+	r.refs = append(r.refs, s)
 
-		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))
+	if s == nil || v != 0 {
+		return
+	}
+	if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
+		x, err := strconv.ParseUint(s.Name[5:], 16, 64)
+		if err != nil {
+			log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
 		}
+		s.Type = obj.SRODATA
+		s.Attr |= AttrLocal
+		switch s.Name[:5] {
+		case "$f32.":
+			if uint64(uint32(x)) != x {
+				log.Panicf("$-symbol %s too large: %d", s.Name, x)
+			}
+			Adduint32(r.ctxt, s, uint32(x))
+		case "$f64.", "$i64.":
+			Adduint64(r.ctxt, s, x)
+		default:
+			log.Panicf("unrecognized $-symbol: %s", s.Name)
+		}
+		s.Attr.Set(AttrReachable, false)
+	}
+	if strings.HasPrefix(s.Name, "runtime.gcbits.") {
+		s.Attr |= AttrLocal
 	}
 }
 
-func rdint64(f *obj.Biobuf) int64 {
-	var c int
-
+func (r *objReader) readInt64() int64 {
 	uv := uint64(0)
-	for shift := 0; ; shift += 7 {
+	for shift := uint(0); ; shift += 7 {
 		if shift >= 64 {
 			log.Fatalf("corrupt input")
 		}
-		c = obj.Bgetc(f)
-		uv |= uint64(c&0x7F) << uint(shift)
+		c, err := r.rd.ReadByte()
+		if err != nil {
+			log.Fatalln("error reading input: ", err)
+		}
+		uv |= uint64(c&0x7F) << shift
 		if c&0x80 == 0 {
 			break
 		}
 	}
 
-	return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
+	return int64(uv>>1) ^ (int64(uv<<63) >> 63)
 }
 
-func rdint(f *obj.Biobuf) int {
-	n := rdint64(f)
+func (r *objReader) readInt() int {
+	n := r.readInt64()
 	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)
+func (r *objReader) readInt32() int32 {
+	n := r.readInt64()
 	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)
+func (r *objReader) readInt16() int16 {
+	n := r.readInt64()
 	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)
+func (r *objReader) readUint8() uint8 {
+	n := r.readInt64()
 	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 (r *objReader) readString() string {
+	n := r.readInt()
+	if cap(r.rdBuf) < n {
+		r.rdBuf = make([]byte, 2*n)
+	}
+	r.readFull(r.rdBuf[:n])
+	return string(r.rdBuf[:n])
 }
 
-func rddata(f *obj.Biobuf) []byte {
-	n := rdint64(f)
-	p := make([]byte, n)
-	obj.Bread(f, p)
+func (r *objReader) readData() []byte {
+	n := r.readInt()
+	p := r.data[:n:n]
+	r.data = r.data[n:]
 	return p
 }
 
-var symbuf []byte
-
-func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym {
-	n := rdint(f)
+// readSymName reads a symbol name, replacing all "". with pkg.
+func (r *objReader) readSymName() string {
+	pkg := r.pkg
+	n := r.readInt()
 	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
-		}
+		r.readInt64()
+		return ""
+	}
+	if cap(r.rdBuf) < n {
+		r.rdBuf = make([]byte, 2*n)
+	}
+	origName, err := r.rd.Peek(n)
+	if err == bufio.ErrBufferFull {
+		// Long symbol names are rare but exist. One source is type
+		// symbols for types with long string forms. See #15104.
+		origName = make([]byte, n)
+		r.readFull(origName)
+	} else if err != nil {
+		log.Fatalf("%s: error reading symbol: %v", r.pn, err)
 	}
-	if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.") {
-		s.Local = true
+	adjName := r.rdBuf[:0]
+	for {
+		i := bytes.Index(origName, emptyPkg)
+		if i == -1 {
+			s := string(append(adjName, origName...))
+			// Read past the peeked origName, now that we're done with it,
+			// using the rfBuf (also no longer used) as the scratch space.
+			// TODO: use bufio.Reader.Discard if available instead?
+			if err == nil {
+				r.readFull(r.rdBuf[:n])
+			}
+			r.rdBuf = adjName[:0] // in case 2*n wasn't enough
+
+			if DynlinkingGo() {
+				// These types are included in the symbol
+				// table when dynamically linking. To keep
+				// binary size down, we replace the names
+				// with SHA-1 prefixes.
+				//
+				// Keep the type.. prefix, which parts of the
+				// linker (like the DWARF generator) know means
+				// the symbol is not decodable.
+				//
+				// Leave type.runtime. symbols alone, because
+				// other parts of the linker manipulates them.
+				if strings.HasPrefix(s, "type.") && !strings.HasPrefix(s, "type.runtime.") {
+					hash := sha1.Sum([]byte(s))
+					prefix := "type."
+					if s[5] == '.' {
+						prefix = "type.."
+					}
+					s = prefix + base64.StdEncoding.EncodeToString(hash[:6])
+				}
+			}
+			return s
+		}
+		adjName = append(adjName, origName[:i]...)
+		adjName = append(adjName, pkg...)
+		adjName = append(adjName, '.')
+		origName = origName[i+len(emptyPkg):]
 	}
-	return s
+}
+
+// Reads the index of a symbol reference and resolves it to a symbol
+func (r *objReader) readSymIndex() *LSym {
+	i := r.readInt()
+	return r.refs[i]
 }
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index d1e3c25..991b9ef 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -93,11 +93,11 @@ func pciterinit(ctxt *Link, it *Pciter, d *Pcdata) {
 	it.value = -1
 	it.start = 1
 	it.done = 0
-	it.pcscale = uint32(ctxt.Arch.Minlc)
+	it.pcscale = uint32(ctxt.Arch.MinLC)
 	pciternext(it)
 }
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -127,8 +127,7 @@ 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)
+		Addbytes(Ctxt, ftab, d.P)
 	}
 	return int32(setuint32(Ctxt, ftab, int64(off), uint32(start)))
 }
@@ -148,27 +147,21 @@ func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
 	for i := 0; i < len(files); i++ {
 		f = files[i]
 		if f.Type != obj.SFILEPATH {
-			ctxt.Nhistfile++
-			f.Value = int64(ctxt.Nhistfile)
+			ctxt.Filesyms = append(ctxt.Filesyms, f)
+			f.Value = int64(len(ctxt.Filesyms))
 			f.Type = obj.SFILEPATH
-			f.Next = ctxt.Filesyms
 			f.Name = expandGoroot(f.Name)
-			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
+		oldval := it.value
 
+		var val int32
 		if oldval == -1 {
 			val = -1
 		} else {
@@ -178,9 +171,9 @@ func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
 			val = int32(files[oldval].Value)
 		}
 
-		dv = val - newval
+		dv := val - newval
 		newval = val
-		v = (uint32(dv) << 1) ^ uint32(int32(dv>>31))
+		v := (uint32(dv) << 1) ^ uint32(dv>>31)
 		addvarint(&out, v)
 
 		// pc delta
@@ -205,7 +198,7 @@ func container(s *LSym) int {
 // pclntab initializes the pclntab symbol with
 // runtime function and file name information.
 
-var pclntab_zpcln Pcln
+var pclntab_zpcln FuncInfo
 
 // These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
 var pclntabNfunc int32
@@ -218,7 +211,7 @@ func pclntab() {
 	funcdata_bytes := int64(0)
 	ftab := Linklookup(Ctxt, "runtime.pclntab", 0)
 	ftab.Type = obj.SPCLNTAB
-	ftab.Reachable = true
+	ftab.Attr |= AttrReachable
 
 	// See golang.org/s/go12symtab for the format. Briefly:
 	//	8-byte header
@@ -229,40 +222,34 @@ func pclntab() {
 	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 _, s := range Ctxt.Textp {
+		if s.Outer != nil {
+			s.Outer.Type |= obj.SCONTAINER
 		}
 	}
 
-	for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
-		if container(Ctxt.Cursym) == 0 {
+	for _, s := range Ctxt.Textp {
+		if container(s) == 0 {
 			nfunc++
 		}
 	}
 
 	pclntabNfunc = nfunc
-	Symgrow(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize)+4)
+	Symgrow(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.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)
+	setuint8(Ctxt, ftab, 6, uint8(SysArch.MinLC))
+	setuint8(Ctxt, ftab, 7, uint8(SysArch.PtrSize))
+	setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(SysArch.PtrSize))
+	pclntabPclntabOffset = int32(8 + SysArch.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 {
+	for _, Ctxt.Cursym = range Ctxt.Textp {
 		last = Ctxt.Cursym
 		if container(Ctxt.Cursym) != 0 {
 			continue
 		}
-		pcln = Ctxt.Cursym.Pcln
+		pcln := Ctxt.Cursym.FuncInfo
 		if pcln == nil {
 			pcln = &pclntab_zpcln
 		}
@@ -271,17 +258,17 @@ func pclntab() {
 			pclntabFirstFunc = Ctxt.Cursym
 		}
 
-		funcstart = int32(len(ftab.P))
-		funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+		funcstart := int32(len(ftab.P))
+		funcstart += int32(-len(ftab.P)) & (int32(SysArch.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))
+		setaddr(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), Ctxt.Cursym)
+		setuintxx(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint64(funcstart), int64(SysArch.PtrSize))
 
 		// fixed size of struct, checked below
-		off = funcstart
+		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 := funcstart + int32(SysArch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(SysArch.PtrSize)
+		if len(pcln.Funcdata) > 0 && (end&int32(SysArch.PtrSize-1) != 0) {
 			end += 4
 		}
 		Symgrow(Ctxt, ftab, int64(end))
@@ -294,7 +281,11 @@ func pclntab() {
 
 		// args int32
 		// TODO: Move into funcinfo.
-		off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Args)))
+		args := uint32(0)
+		if Ctxt.Cursym.FuncInfo != nil {
+			args = uint32(Ctxt.Cursym.FuncInfo.Args)
+		}
+		off = int32(setuint32(Ctxt, ftab, int64(off), args))
 
 		// frame int32
 		// This has been removed (it was never set quite correctly anyway).
@@ -307,9 +298,10 @@ func pclntab() {
 			renumberfiles(Ctxt, pcln.File, &pcln.Pcfile)
 			if false {
 				// Sanity check the new numbering
+				var it Pciter
 				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)
+					if it.value < 1 || it.value > int32(len(Ctxt.Filesyms)) {
+						Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, len(Ctxt.Filesyms))
 						errorexit()
 					}
 				}
@@ -321,34 +313,34 @@ func pclntab() {
 
 		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 = int32(setuint32(Ctxt, ftab, int64(off), uint32(len(pcln.Pcdata))))
+		off = int32(setuint32(Ctxt, ftab, int64(off), uint32(len(pcln.Funcdata))))
+		for i := 0; i < len(pcln.Pcdata); 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 {
+		if len(pcln.Funcdata) > 0 {
+			if off&int32(SysArch.PtrSize-1) != 0 {
 				off += 4
 			}
-			for i = 0; i < int32(pcln.Nfuncdata); i++ {
+			for i := 0; i < len(pcln.Funcdata); i++ {
 				if pcln.Funcdata[i] == nil {
-					setuintxx(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(Thearch.Ptrsize))
+					setuintxx(Ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(SysArch.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])
+					setaddrplus(Ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
 				}
 			}
 
-			off += int32(pcln.Nfuncdata) * int32(Thearch.Ptrsize)
+			off += int32(len(pcln.Funcdata)) * int32(SysArch.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)
+			Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), SysArch.PtrSize)
 			errorexit()
 		}
 
@@ -357,25 +349,26 @@ func pclntab() {
 
 	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)
+	setaddrplus(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), last, last.Size)
 
 	// Start file table.
 	start := int32(len(ftab.P))
 
-	start += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+	start += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1)
 	pclntabFiletabOffset = start
-	setuint32(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint32(start))
+	setuint32(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.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 {
+	Symgrow(Ctxt, ftab, int64(start)+(int64(len(Ctxt.Filesyms))+1)*4)
+	setuint32(Ctxt, ftab, int64(start), uint32(len(Ctxt.Filesyms)))
+	for i := len(Ctxt.Filesyms) - 1; i >= 0; i-- {
+		s := Ctxt.Filesyms[i]
 		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))
+		fmt.Fprintf(Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), ftab.Size, funcdata_bytes)
 	}
 }
 
@@ -399,18 +392,17 @@ const (
 )
 
 // findfunctab generates a lookup table to quickly find the containing
-// function for a pc.  See src/runtime/symtab.go:findfunc for details.
+// 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
+	t.Attr |= AttrReachable
+	t.Attr |= AttrLocal
 
 	// find min and max address
-	min := Ctxt.Textp.Value
-
+	min := Ctxt.Textp[0].Value
 	max := int64(0)
-	for s := Ctxt.Textp; s != nil; s = s.Next {
+	for _, s := range Ctxt.Textp {
 		max = s.Value + s.Size
 	}
 
@@ -423,34 +415,34 @@ func findfunctab() {
 		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 {
+	for i, s := range Ctxt.Textp {
 		if container(s) != 0 {
 			continue
 		}
-		p = s.Value
-		e = s.Next
-		for container(e) != 0 {
-			e = e.Next
+		p := s.Value
+		var e *LSym
+		i++
+		if i < len(Ctxt.Textp) {
+			e = Ctxt.Textp[i]
+		}
+		for container(e) != 0 && i < len(Ctxt.Textp) {
+			e = Ctxt.Textp[i]
+			i++
 		}
+		q := max
 		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)
+			i = int((p - min) / SUBBUCKETSIZE)
 			if indexes[i] > idx {
 				indexes[i] = idx
 			}
 		}
 
-		i = int32((q - 1 - min) / SUBBUCKETSIZE)
+		i = int((q - 1 - min) / SUBBUCKETSIZE)
 		if indexes[i] > idx {
 			indexes[i] = idx
 		}
@@ -463,15 +455,13 @@ func findfunctab() {
 	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]
+		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++ {
+		for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
 			idx = indexes[i*SUBBUCKETS+j]
 			if idx == NOIDX {
 				Diag("hole in findfunctab")
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 00fbb17..839aa6c 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -6,8 +6,10 @@ package ld
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
+	"os"
 	"sort"
 	"strconv"
 	"strings"
@@ -375,18 +377,6 @@ 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")
@@ -430,9 +420,9 @@ func chksectseg(h *IMAGE_SECTION_HEADER, s *Segment) {
 func Peinit() {
 	var l int
 
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	// 64-bit architectures
-	case '6':
+	case sys.AMD64:
 		pe64 = 1
 
 		l = binary.Size(&oh64)
@@ -487,8 +477,8 @@ func initdynimport() *Dll {
 
 	dr = nil
 	var m *Imp
-	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
-		if !s.Reachable || s.Type != obj.SDYNIMPORT {
+	for _, s := range Ctxt.Allsym {
+		if !s.Attr.Reachable() || s.Type != obj.SDYNIMPORT {
 			continue
 		}
 		for d = dr; d != nil; d = d.next {
@@ -517,7 +507,7 @@ func initdynimport() *Dll {
 			if err != nil {
 				Diag("failed to parse stdcall decoration: %v", err)
 			}
-			m.argsize *= Thearch.Ptrsize
+			m.argsize *= SysArch.PtrSize
 			s.Extname = s.Extname[:i]
 		}
 
@@ -531,25 +521,25 @@ func initdynimport() *Dll {
 		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))
+				Symgrow(Ctxt, m.s, int64(SysArch.PtrSize))
 				dynName := m.s.Extname
 				// only windows/386 requires stdcall decoration
-				if Thearch.Thechar == '8' && m.argsize >= 0 {
+				if SysArch.Family == sys.I386 && m.argsize >= 0 {
 					dynName += fmt.Sprintf("@%d", m.argsize)
 				}
 				dynSym := Linklookup(Ctxt, dynName, 0)
-				dynSym.Reachable = true
+				dynSym.Attr |= AttrReachable
 				dynSym.Type = obj.SHOSTOBJ
 				r := Addrel(m.s)
 				r.Sym = dynSym
 				r.Off = 0
-				r.Siz = uint8(Thearch.Ptrsize)
+				r.Siz = uint8(SysArch.PtrSize)
 				r.Type = obj.R_ADDR
 			}
 		}
 	} else {
 		dynamic := Linklookup(Ctxt, ".windynamic", 0)
-		dynamic.Reachable = true
+		dynamic.Attr |= AttrReachable
 		dynamic.Type = obj.SWINDOWS
 		for d := dr; d != nil; d = d.next {
 			for m = d.ms; m != nil; m = m.next {
@@ -557,10 +547,10 @@ func initdynimport() *Dll {
 				m.s.Sub = dynamic.Sub
 				dynamic.Sub = m.s
 				m.s.Value = dynamic.Size
-				dynamic.Size += int64(Thearch.Ptrsize)
+				dynamic.Size += int64(SysArch.PtrSize)
 			}
 
-			dynamic.Size += int64(Thearch.Ptrsize)
+			dynamic.Size += int64(SysArch.PtrSize)
 		}
 	}
 
@@ -692,8 +682,8 @@ func (s byExtname) Less(i, j int) bool { return s[i].Extname < s[j].Extname }
 
 func initdynexport() {
 	nexport = 0
-	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
-		if !s.Reachable || s.Cgoexport&CgoExportDynamic == 0 {
+	for _, s := range Ctxt.Allsym {
+		if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() {
 			continue
 		}
 		if nexport+1 > len(dexport) {
@@ -774,7 +764,7 @@ func addexports() {
 
 // perelocsect relocates symbols from first in section sect, and returns
 // the total number of relocations emitted.
-func perelocsect(sect *Section, first *LSym) int {
+func perelocsect(sect *Section, syms []*LSym) int {
 	// If main section has no bits, nothing to relocate.
 	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
 		return 0
@@ -783,21 +773,19 @@ func perelocsect(sect *Section, first *LSym) int {
 	relocs := 0
 
 	sect.Reloff = uint64(Cpos())
-	var sym *LSym
-	for sym = first; sym != nil; sym = sym.Next {
-		if !sym.Reachable {
+	for i, s := range syms {
+		if !s.Attr.Reachable() {
 			continue
 		}
-		if uint64(sym.Value) >= sect.Vaddr {
+		if uint64(s.Value) >= sect.Vaddr {
+			syms = syms[i:]
 			break
 		}
 	}
 
 	eaddr := int32(sect.Vaddr + sect.Length)
-	var r *Reloc
-	var ri int
-	for ; sym != nil; sym = sym.Next {
-		if !sym.Reachable {
+	for _, sym := range syms {
+		if !sym.Attr.Reachable() {
 			continue
 		}
 		if sym.Value >= int64(eaddr) {
@@ -805,8 +793,8 @@ func perelocsect(sect *Section, first *LSym) int {
 		}
 		Ctxt.Cursym = sym
 
-		for ri = 0; ri < len(sym.R); ri++ {
-			r = &sym.R[ri]
+		for ri := 0; ri < len(sym.R); ri++ {
+			r := &sym.R[ri]
 			if r.Done != 0 {
 				continue
 			}
@@ -832,7 +820,7 @@ func perelocsect(sect *Section, first *LSym) int {
 }
 
 // peemitreloc emits relocation entries for go.o in external linking.
-func peemitreloc(text, data *IMAGE_SECTION_HEADER) {
+func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) {
 	for Cpos()&7 != 0 {
 		Cput(0)
 	}
@@ -882,13 +870,29 @@ func peemitreloc(text, data *IMAGE_SECTION_HEADER) {
 		data.PointerToRelocations += 10 // skip the extend reloc entry
 	}
 	data.NumberOfRelocations = uint16(n - 1)
+
+	dottext := Linklookup(Ctxt, ".text", 0)
+	ctors.NumberOfRelocations = 1
+	ctors.PointerToRelocations = uint32(Cpos())
+	sectoff := ctors.VirtualAddress
+	Lputl(sectoff)
+	Lputl(uint32(dottext.Dynid))
+	switch obj.Getgoarch() {
+	default:
+		fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch())
+		os.Exit(2)
+	case "386":
+		Wputl(IMAGE_REL_I386_DIR32)
+	case "amd64":
+		Wputl(IMAGE_REL_AMD64_ADDR64)
+	}
 }
 
 func dope() {
 	/* relocation table */
 	rel := Linklookup(Ctxt, ".rel", 0)
 
-	rel.Reachable = true
+	rel.Attr |= AttrReachable
 	rel.Type = obj.SELFROSECT
 
 	initdynimport()
@@ -922,120 +926,122 @@ func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER {
 	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
-	}
+// writePESymTableRecords writes all COFF symbol table records.
+// It returns number of records written.
+func writePESymTableRecords() int {
+	var symcnt int
 
-	switch type_ {
-	default:
-		return
-
-	case 'D', 'B', 'T', 'U':
-		break
-	}
+	put := func(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':
+		}
 
-	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 {
+		if SysArch.Family == sys.I386 &&
+			Linkmode == LinkExternal &&
+			(s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) &&
+			s.Name == s.Extname &&
+			s.Name != "_main" {
 			s.Name = "_" + s.Name
 		}
-		cs := &coffsym[ncoffsym]
-		cs.sym = s
-		if len(s.Name) > 8 {
-			cs.strtbloff = strtbladd(s.Name)
-		}
+
+		var typ uint16
+		var sect int
+		var value int64
 		// 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
+			value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
+			sect = bsssect
 		} else if uint64(s.Value) >= Segdata.Vaddr {
-			cs.value = int64(uint64(s.Value) - Segdata.Vaddr)
-			cs.sect = datasect
+			value = int64(uint64(s.Value) - Segdata.Vaddr)
+			sect = datasect
 		} else if uint64(s.Value) >= Segtext.Vaddr {
-			cs.value = int64(uint64(s.Value) - Segtext.Vaddr)
-			cs.sect = textsect
+			value = int64(uint64(s.Value) - Segtext.Vaddr)
+			sect = textsect
 		} else if type_ == 'U' {
-			cs.value = 0
-			cs.typ = IMAGE_SYM_DTYPE_FUNCTION
+			typ = IMAGE_SYM_DTYPE_FUNCTION
 		} else {
-			cs.value = 0
-			cs.sect = 0
 			Diag("addpesym %#x", addr)
 		}
-	}
 
-	s.Dynid = int32(ncoffsym)
-	ncoffsym++
-}
+		// write COFF symbol table record
+		if len(s.Name) > 8 {
+			Lputl(0)
+			Lputl(uint32(strtbladd(s.Name)))
+		} else {
+			strnput(s.Name, 8)
+		}
+		Lputl(uint32(value))
+		Wputl(uint16(sect))
+		if typ != 0 {
+			Wputl(typ)
+		} else if Linkmode == LinkExternal {
+			Wputl(0)
+		} else {
+			Wputl(0x0308) // "array of structs"
+		}
+		Cput(2) // storage class: external
+		Cput(0) // no aux entries
+
+		s.Dynid = int32(symcnt)
+
+		symcnt++
+	}
 
-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)
+				put(s, s.Name, 'U', 0, int64(SysArch.PtrSize), 0, nil)
 			}
 		}
+
+		s := Linklookup(Ctxt, ".text", 0)
+		if s.Type == obj.STEXT {
+			put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
+		}
 	}
+
 	genasmsym(put)
+
+	return symcnt
 }
 
 func addpesymtable() {
+	symtabStartPos := Cpos()
+
+	// write COFF symbol table
+	var symcnt int
 	if Debug['s'] == 0 || Linkmode == LinkExternal {
-		ncoffsym = 0
-		pegenasmsym(addpesym)
-		coffsym = make([]COFFSym, ncoffsym)
-		ncoffsym = 0
-		pegenasmsym(addpesym)
+		symcnt = writePESymTableRecords()
 	}
-	size := len(strtbl) + 4 + 18*ncoffsym
 
+	// update COFF file header and section table
+	size := len(strtbl) + 4 + 18*symcnt
 	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())
+		chksectoff(h, symtabStartPos)
 	}
-	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))
-		}
+	fh.PointerToSymbolTable = uint32(symtabStartPos)
+	fh.NumberOfSymbols = uint32(symcnt)
 
-		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
+	// write COFF string table
 	Lputl(uint32(len(strtbl)) + 4)
-
 	for i := 0; i < len(strtbl); i++ {
-		Cput(uint8(strtbl[i]))
+		Cput(strtbl[i])
 	}
 	if Linkmode != LinkExternal {
 		strnput("", int(h.SizeOfRawData-uint32(size)))
@@ -1085,13 +1091,49 @@ func addpersrc() {
 	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize
 }
 
+func addinitarray() (c *IMAGE_SECTION_HEADER) {
+	// The size below was determined by the specification for array relocations,
+	// and by observing what GCC writes here. If the initarray section grows to
+	// contain more than one constructor entry, the size will need to be 8 * constructor_count.
+	// However, the entire Go runtime is initialized from just one function, so it is unlikely
+	// that this will need to grow in the future.
+	var size int
+	switch obj.Getgoarch() {
+	default:
+		fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch())
+		os.Exit(2)
+	case "386":
+		size = 4
+	case "amd64":
+		size = 8
+	}
+
+	c = addpesection(".ctors", size, size)
+	c.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
+	c.SizeOfRawData = uint32(size)
+
+	Cseek(int64(c.PointerToRawData))
+	chksectoff(c, Cpos())
+	init_entry := Linklookup(Ctxt, INITENTRY, 0)
+	addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr
+
+	switch obj.Getgoarch() {
+	case "386":
+		Lputl(uint32(addr))
+	case "amd64":
+		Vputl(addr)
+	}
+
+	return c
+}
+
 func Asmbpe() {
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Exitf("unknown PE architecture: %v", Thearch.Thechar)
-	case '6':
+		Exitf("unknown PE architecture: %v", SysArch.Family)
+	case sys.AMD64:
 		fh.Machine = IMAGE_FILE_MACHINE_AMD64
-	case '8':
+	case sys.I386:
 		fh.Machine = IMAGE_FILE_MACHINE_I386
 	}
 
@@ -1106,6 +1148,7 @@ func Asmbpe() {
 	textsect = pensect
 
 	var d *IMAGE_SECTION_HEADER
+	var c *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
@@ -1121,6 +1164,8 @@ func Asmbpe() {
 		b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
 		b.PointerToRawData = 0
 		bsssect = pensect
+
+		c = addinitarray()
 	}
 
 	if Debug['s'] == 0 {
@@ -1135,7 +1180,7 @@ func Asmbpe() {
 	addpesymtable()
 	addpersrc()
 	if Linkmode == LinkExternal {
-		peemitreloc(t, d)
+		peemitreloc(t, d, c)
 	}
 
 	fh.NumberOfSections = uint16(pensect)
diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go
index 808d377..7a4555f 100644
--- a/src/cmd/link/internal/ld/pobj.go
+++ b/src/cmd/link/internal/ld/pobj.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -31,7 +31,9 @@
 package ld
 
 import (
+	"bufio"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"flag"
 	"fmt"
 	"os"
@@ -44,13 +46,12 @@ var (
 )
 
 func Ldmain() {
-	Ctxt = linknew(Thelinkarch)
-	Ctxt.Thechar = int32(Thearch.Thechar)
-	Ctxt.Thestring = Thestring
+	Bso = bufio.NewWriter(os.Stdout)
+
+	Ctxt = linknew(SysArch)
 	Ctxt.Diag = Diag
-	Ctxt.Bso = &Bso
+	Ctxt.Bso = Bso
 
-	Bso = *obj.Binitw(os.Stdout)
 	Debug = [128]int{}
 	nerrors = 0
 	outfile = ""
@@ -70,7 +71,7 @@ func Ldmain() {
 		}
 	}
 
-	if Thearch.Thechar == '6' && obj.Getgoos() == "plan9" {
+	if SysArch.Family == sys.AMD64 && 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)
@@ -89,6 +90,7 @@ func Ldmain() {
 	flag.Var(&Buildmode, "buildmode", "set build `mode`")
 	obj.Flagcount("c", "dump call graph", &Debug['c'])
 	obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
+	flag.BoolVar(&flag_dumpdep, "dumpdep", false, "dump symbol dependency graph")
 	obj.Flagstr("extar", "archive program for buildmode=c-archive", &extar)
 	obj.Flagstr("extld", "use `linker` when linking in external mode", &extld)
 	obj.Flagstr("extldflags", "pass `flags` to external linker", &extldflags)
@@ -107,7 +109,7 @@ func Ldmain() {
 	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' {
+	if SysArch.InFamily(sys.ARM, sys.AMD64) {
 		obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &flagShared)
 	}
 	obj.Flagstr("tmpdir", "use `directory` for temporary files", &tmpdir)
@@ -119,37 +121,10 @@ func Ldmain() {
 	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.Bso = Bso
 	Ctxt.Debugvlog = int32(Debug['v'])
 	if flagShared != 0 {
 		if Buildmode == BuildmodeUnset {
@@ -190,7 +165,7 @@ func Ldmain() {
 	}
 
 	if Debug['v'] != 0 {
-		fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
+		fmt.Fprintf(Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
 	}
 	Bso.Flush()
 
@@ -213,17 +188,9 @@ func Ldmain() {
 	}
 	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()
+	deadcode(Ctxt)
+	fieldtrack(Ctxt)
 	callgraph()
 
 	doelf()
@@ -243,16 +210,15 @@ func Ldmain() {
 	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)
+		fmt.Fprintf(Bso, "%5.2f cpu time\n", obj.Cputime())
+		fmt.Fprintf(Bso, "%d symbols\n", len(Ctxt.Allsym))
+		fmt.Fprintf(Bso, "%d liveness data\n", liveness)
 	}
 
 	Bso.Flush()
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index 731f3ed..a44c8de 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -9,7 +9,7 @@
 //	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.
+//	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
@@ -33,9 +33,8 @@ package ld
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"log"
-	"os"
-	"path/filepath"
 	"strconv"
 )
 
@@ -45,7 +44,6 @@ var headers = []struct {
 }{
 	{"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"
@@ -58,25 +56,23 @@ var headers = []struct {
 	{"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()
+func linknew(arch *sys.Arch) *Link {
+	ctxt := &Link{
+		Hash: []map[string]*LSym{
+			// preallocate about 2mb for hash of
+			// non static symbols
+			make(map[string]*LSym, 100000),
+		},
+		Allsym: make([]*LSym, 0, 100000),
+		Arch:   arch,
+		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())
@@ -103,33 +99,33 @@ func linknew(arch *LinkArch) *Link {
 		obj.Hdragonfly,
 		obj.Hsolaris:
 		if obj.Getgoos() == "android" {
-			switch ctxt.Arch.Thechar {
-			case '6':
+			switch ctxt.Arch.Family {
+			case sys.AMD64:
 				// Android/amd64 constant - offset from 0(FS) to our TLS slot.
 				// Explained in src/runtime/cgo/gcc_android_*.c
 				ctxt.Tlsoffset = 0x1d0
-			case '8':
+			case sys.I386:
 				// Android/386 constant - offset from 0(GS) to our TLS slot.
 				ctxt.Tlsoffset = 0xf8
 			default:
-				ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+				ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
 			}
 		} else {
-			ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+			ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
 		}
 
 	case obj.Hnacl:
-		switch ctxt.Arch.Thechar {
+		switch ctxt.Arch.Family {
 		default:
 			log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
 
-		case '5':
+		case sys.ARM:
 			ctxt.Tlsoffset = 0
 
-		case '6':
+		case sys.AMD64:
 			ctxt.Tlsoffset = 0
 
-		case '8':
+		case sys.I386:
 			ctxt.Tlsoffset = -8
 		}
 
@@ -138,79 +134,65 @@ func linknew(arch *LinkArch) *Link {
 		 * Explained in src/runtime/cgo/gcc_darwin_*.c.
 		 */
 	case obj.Hdarwin:
-		switch ctxt.Arch.Thechar {
+		switch ctxt.Arch.Family {
 		default:
 			log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
 
-		case '5':
+		case sys.ARM:
 			ctxt.Tlsoffset = 0 // dummy value, not needed
 
-		case '6':
+		case sys.AMD64:
 			ctxt.Tlsoffset = 0x8a0
 
-		case '7':
+		case sys.ARM64:
 			ctxt.Tlsoffset = 0 // dummy value, not needed
 
-		case '8':
+		case sys.I386:
 			ctxt.Tlsoffset = 0x468
 		}
 	}
 
 	// On arm, record goarm.
-	if ctxt.Arch.Thechar == '5' {
+	if ctxt.Arch.Family == sys.ARM {
 		ctxt.Goarm = obj.Getgoarm()
 	}
 
 	return ctxt
 }
 
-func linknewsym(ctxt *Link, symb string, v int) *LSym {
-	s := new(LSym)
-	*s = LSym{}
+func linknewsym(ctxt *Link, name string, v int) *LSym {
+	batch := ctxt.LSymBatch
+	if len(batch) == 0 {
+		batch = make([]LSym, 1000)
+	}
+	s := &batch[0]
+	ctxt.LSymBatch = batch[1:]
 
 	s.Dynid = -1
 	s.Plt = -1
 	s.Got = -1
-	s.Name = symb
-	s.Type = 0
+	s.Name = name
 	s.Version = int16(v)
-	s.Value = 0
-	s.Size = 0
-	ctxt.Nsymbol++
-
-	s.Allsym = ctxt.Allsym
-	ctxt.Allsym = s
+	ctxt.Allsym = append(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}]
+func Linklookup(ctxt *Link, name string, v int) *LSym {
+	m := ctxt.Hash[v]
+	s := m[name]
 	if s != nil {
 		return s
 	}
-	if creat == 0 {
-		return nil
-	}
-
-	s = linknewsym(ctxt, symb, v)
+	s = linknewsym(ctxt, name, v)
 	s.Extname = s.Name
-	ctxt.Hash[symVer{symb, v}] = s
+	m[name] = 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)
+	return ctxt.Hash[v][name]
 }
 
 func Headstr(v int) string {
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index 3e6169e..06d7792 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,6 +32,7 @@ package ld
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"path/filepath"
 	"strings"
@@ -47,27 +48,20 @@ func putelfstr(s string) int {
 
 	// 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.
+	// 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)
-
+	Elfstrdat = append(Elfstrdat, s...)
+	Elfstrdat = append(Elfstrdat, 0)
 	return off
 }
 
 func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) {
-	switch Thearch.Thechar {
-	case '0', '6', '7', '9':
+	if elf64 {
 		Thearch.Lput(uint32(off))
 		Cput(uint8(info))
 		Cput(uint8(other))
@@ -75,8 +69,7 @@ func putelfsyment(off int, addr int64, size int64, info int, shndx int, other in
 		Thearch.Vput(uint64(addr))
 		Thearch.Vput(uint64(size))
 		Symsize += ELF64SYMSIZE
-
-	default:
+	} else {
 		Thearch.Lput(uint32(off))
 		Thearch.Lput(uint32(addr))
 		Thearch.Lput(uint32(size))
@@ -142,7 +135,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
 	// maybe one day STB_WEAK.
 	bind := STB_GLOBAL
 
-	if ver != 0 || (x.Type&obj.SHIDDEN != 0) || x.Local {
+	if ver != 0 || (x.Type&obj.SHIDDEN != 0) || x.Attr.Local() {
 		bind = STB_LOCAL
 	}
 
@@ -151,7 +144,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
 	// 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 {
+	if !DynlinkingGo() && Linkmode == LinkExternal && !x.Attr.CgoExportStatic() && elfshnum != SHN_UNDEF {
 		bind = STB_LOCAL
 	}
 
@@ -162,7 +155,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
 	if x.Type&obj.SHIDDEN != 0 {
 		other = STV_HIDDEN
 	}
-	if (Buildmode == BuildmodePIE || DynlinkingGo()) && Thearch.Thechar == '9' && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
+	if (Buildmode == BuildmodePIE || DynlinkingGo()) && SysArch.Family == sys.PPC64 && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
 		// On ppc64 the top three bits of the st_other field indicate how
 		// many instructions separate the global and local entry points. In
 		// our case it is two instructions, indicated by the value 3.
@@ -197,24 +190,19 @@ func putelfsectionsym(s *LSym, shndx int) {
 	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()
 
+	// Some linkers will add a FILE sym if one is not present.
+	// Avoid having the working directory inserted into the symbol table.
+	// It is added with a name to avoid problems with external linking
+	// encountered on some versions of Solaris. See issue #14957.
+	putelfsyment(putelfstr("go.go"), 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0)
+	numelfsym++
+
 	elfbind = STB_LOCAL
 	genasmsym(putelfsym)
 
@@ -238,7 +226,7 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_
 		'Z',
 		'm':
 		l := 4
-		if HEADTYPE == obj.Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
+		if HEADTYPE == obj.Hplan9 && SysArch.Family == sys.AMD64 && Debug['8'] == 0 {
 			Lputb(uint32(addr >> 32))
 			l = 8
 		}
@@ -248,10 +236,10 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_
 
 		var i int
 		if t == 'z' || t == 'Z' {
-			Cput(uint8(s[0]))
+			Cput(s[0])
 			for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 {
-				Cput(uint8(s[i]))
-				Cput(uint8(s[i+1]))
+				Cput(s[i])
+				Cput(s[i+1])
 			}
 
 			Cput(0)
@@ -263,7 +251,7 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_
 				s = s[1:]
 			}
 			for i = 0; i < len(s); i++ {
-				Cput(uint8(s[i]))
+				Cput(s[i])
 			}
 			Cput(0)
 		}
@@ -281,38 +269,36 @@ func Asmplan9sym() {
 
 var symt *LSym
 
-func Wputl(w uint16) {
-	Cput(uint8(w))
-	Cput(uint8(w >> 8))
-}
+func Wputb(w uint16) { Cwrite(Append16b(encbuf[:0], w)) }
+func Lputb(l uint32) { Cwrite(Append32b(encbuf[:0], l)) }
+func Vputb(v uint64) { Cwrite(Append64b(encbuf[:0], v)) }
 
-func Wputb(w uint16) {
-	Cput(uint8(w >> 8))
-	Cput(uint8(w))
-}
+func Wputl(w uint16) { Cwrite(Append16l(encbuf[:0], w)) }
+func Lputl(l uint32) { Cwrite(Append32l(encbuf[:0], l)) }
+func Vputl(v uint64) { Cwrite(Append64l(encbuf[:0], v)) }
 
-func Lputb(l uint32) {
-	Cput(uint8(l >> 24))
-	Cput(uint8(l >> 16))
-	Cput(uint8(l >> 8))
-	Cput(uint8(l))
+func Append16b(b []byte, v uint16) []byte {
+	return append(b, uint8(v>>8), uint8(v))
+}
+func Append16l(b []byte, v uint16) []byte {
+	return append(b, uint8(v), uint8(v>>8))
 }
 
-func Lputl(l uint32) {
-	Cput(uint8(l))
-	Cput(uint8(l >> 8))
-	Cput(uint8(l >> 16))
-	Cput(uint8(l >> 24))
+func Append32b(b []byte, v uint32) []byte {
+	return append(b, uint8(v>>24), uint8(v>>16), uint8(v>>8), uint8(v))
+}
+func Append32l(b []byte, v uint32) []byte {
+	return append(b, uint8(v), uint8(v>>8), uint8(v>>16), uint8(v>>24))
 }
 
-func Vputb(v uint64) {
-	Lputb(uint32(v >> 32))
-	Lputb(uint32(v))
+func Append64b(b []byte, v uint64) []byte {
+	return append(b, uint8(v>>56), uint8(v>>48), uint8(v>>40), uint8(v>>32),
+		uint8(v>>24), uint8(v>>16), uint8(v>>8), uint8(v))
 }
 
-func Vputl(v uint64) {
-	Lputl(uint32(v))
-	Lputl(uint32(v >> 32))
+func Append64l(b []byte, v uint64) []byte {
+	return append(b, uint8(v), uint8(v>>8), uint8(v>>16), uint8(v>>24),
+		uint8(v>>32), uint8(v>>40), uint8(v>>48), uint8(v>>56))
 }
 
 type byPkg []*Library
@@ -339,8 +325,12 @@ func symtab() {
 	xdefine("runtime.etext", obj.STEXT, 0)
 	xdefine("runtime.typelink", obj.SRODATA, 0)
 	xdefine("runtime.etypelink", obj.SRODATA, 0)
+	xdefine("runtime.itablink", obj.SRODATA, 0)
+	xdefine("runtime.eitablink", obj.SRODATA, 0)
 	xdefine("runtime.rodata", obj.SRODATA, 0)
 	xdefine("runtime.erodata", obj.SRODATA, 0)
+	xdefine("runtime.types", obj.SRODATA, 0)
+	xdefine("runtime.etypes", obj.SRODATA, 0)
 	xdefine("runtime.noptrdata", obj.SNOPTRDATA, 0)
 	xdefine("runtime.enoptrdata", obj.SNOPTRDATA, 0)
 	xdefine("runtime.data", obj.SDATA, 0)
@@ -358,13 +348,13 @@ func symtab() {
 
 	s.Type = obj.SRODATA
 	s.Size = 0
-	s.Reachable = true
+	s.Attr |= AttrReachable
 	xdefine("runtime.egcdata", obj.SRODATA, 0)
 
 	s = Linklookup(Ctxt, "runtime.gcbss", 0)
 	s.Type = obj.SRODATA
 	s.Size = 0
-	s.Reachable = true
+	s.Attr |= AttrReachable
 	xdefine("runtime.egcbss", obj.SRODATA, 0)
 
 	// pseudo-symbols to mark locations of type, string, and go string data.
@@ -375,105 +365,115 @@ func symtab() {
 
 		s.Type = obj.STYPE
 		s.Size = 0
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		symtype = s
 
 		s = Linklookup(Ctxt, "typerel.*", 0)
 
 		s.Type = obj.STYPERELRO
 		s.Size = 0
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		symtyperel = s
 	} else if !DynlinkingGo() {
 		s = Linklookup(Ctxt, "type.*", 0)
 
 		s.Type = obj.STYPE
 		s.Size = 0
-		s.Reachable = true
+		s.Attr |= AttrReachable
 		symtype = s
 		symtyperel = 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
+	groupSym := func(name string, t int16) *LSym {
+		s := Linklookup(Ctxt, name, 0)
+		s.Type = t
+		s.Size = 0
+		s.Attr |= AttrLocal | AttrReachable
+		return s
+	}
+	var (
+		symgostring    = groupSym("go.string.*", obj.SGOSTRING)
+		symgostringhdr = groupSym("go.string.hdr.*", obj.SGOSTRINGHDR)
+		symgofunc      = groupSym("go.func.*", obj.SGOFUNC)
+		symgcbits      = groupSym("runtime.gcbits.*", obj.SGCBITS)
+	)
 
 	symtypelink := Linklookup(Ctxt, "runtime.typelink", 0)
 	symtypelink.Type = obj.STYPELINK
 
+	symitablink := Linklookup(Ctxt, "runtime.itablink", 0)
+	symitablink.Type = obj.SITABLINK
+
 	symt = Linklookup(Ctxt, "runtime.symtab", 0)
-	symt.Local = true
+	symt.Attr |= AttrLocal
 	symt.Type = obj.SSYMTAB
 	symt.Size = 0
-	symt.Reachable = true
+	symt.Attr |= AttrReachable
 
 	ntypelinks := 0
+	nitablinks := 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 {
+	for _, s := range Ctxt.Allsym {
+		if !s.Attr.Reachable() || s.Attr.Special() || s.Type != obj.SRODATA {
 			continue
 		}
 
-		if strings.HasPrefix(s.Name, "type.") && !DynlinkingGo() {
-			s.Hide = 1
-			if UseRelro() && len(s.R) > 0 {
+		switch {
+		case strings.HasPrefix(s.Name, "type."):
+			if !DynlinkingGo() {
+				s.Attr |= AttrHidden
+			}
+			if UseRelro() {
 				s.Type = obj.STYPERELRO
 				s.Outer = symtyperel
 			} else {
 				s.Type = obj.STYPE
 				s.Outer = symtype
 			}
-		}
 
-		if strings.HasPrefix(s.Name, "go.typelink.") {
+		case strings.HasPrefix(s.Name, "go.importpath.") && UseRelro():
+			// Keep go.importpath symbols in the same section as types and
+			// names, as they can be referred to by a section offset.
+			s.Type = obj.STYPERELRO
+
+		case strings.HasPrefix(s.Name, "go.typelink."):
 			ntypelinks++
 			s.Type = obj.STYPELINK
-			s.Hide = 1
+			s.Attr |= AttrHidden
 			s.Outer = symtypelink
-		}
 
-		if strings.HasPrefix(s.Name, "go.string.") {
+		case strings.HasPrefix(s.Name, "go.itablink."):
+			nitablinks++
+			s.Type = obj.SITABLINK
+			s.Attr |= AttrHidden
+			s.Outer = symitablink
+
+		case strings.HasPrefix(s.Name, "go.string."):
 			s.Type = obj.SGOSTRING
-			s.Hide = 1
+			s.Attr |= AttrHidden
 			s.Outer = symgostring
-		}
+			if strings.HasPrefix(s.Name, "go.string.hdr.") {
+				s.Type = obj.SGOSTRINGHDR
+				s.Outer = symgostringhdr
+			}
 
-		if strings.HasPrefix(s.Name, "runtime.gcbits.") {
+		case strings.HasPrefix(s.Name, "runtime.gcbits."):
 			s.Type = obj.SGCBITS
-			s.Hide = 1
+			s.Attr |= AttrHidden
 			s.Outer = symgcbits
-		}
 
-		if strings.HasPrefix(s.Name, "go.func.") {
+		case strings.HasPrefix(s.Name, "go.func."):
 			s.Type = obj.SGOFUNC
-			s.Hide = 1
+			s.Attr |= AttrHidden
 			s.Outer = symgofunc
-		}
 
-		if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") {
+		case strings.HasPrefix(s.Name, "gcargs."), strings.HasPrefix(s.Name, "gclocals."), strings.HasPrefix(s.Name, "gclocals·"):
 			s.Type = obj.SGOFUNC
-			s.Hide = 1
+			s.Attr |= AttrHidden
 			s.Outer = symgofunc
 			s.Align = 4
 			liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
@@ -482,7 +482,7 @@ func symtab() {
 
 	if Buildmode == BuildmodeShared {
 		abihashgostr := Linklookup(Ctxt, "go.link.abihash."+filepath.Base(outfile), 0)
-		abihashgostr.Reachable = true
+		abihashgostr.Attr |= AttrReachable
 		abihashgostr.Type = obj.SRODATA
 		hashsym := Linklookup(Ctxt, "go.link.abihashbytes", 0)
 		Addaddr(Ctxt, abihashgostr, hashsym)
@@ -504,8 +504,8 @@ func symtab() {
 	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)+1)
-	adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile)+1)
+	adduint(Ctxt, moduledata, uint64(len(Ctxt.Filesyms))+1)
+	adduint(Ctxt, moduledata, uint64(len(Ctxt.Filesyms))+1)
 	// findfunctab
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.findfunctab", 0))
 	// minpc, maxpc
@@ -525,10 +525,16 @@ func symtab() {
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.end", 0))
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcdata", 0))
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.types", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etypes", 0))
 	// The typelinks slice
 	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
 	adduint(Ctxt, moduledata, uint64(ntypelinks))
 	adduint(Ctxt, moduledata, uint64(ntypelinks))
+	// The itablinks slice
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.itablink", 0))
+	adduint(Ctxt, moduledata, uint64(nitablinks))
+	adduint(Ctxt, moduledata, uint64(nitablinks))
 	if len(Ctxt.Shlibs) > 0 {
 		thismodulename := filepath.Base(outfile)
 		switch Buildmode {
@@ -540,8 +546,8 @@ func symtab() {
 		addgostring(moduledata, "go.link.thismodulename", thismodulename)
 
 		modulehashes := Linklookup(Ctxt, "go.link.abihashes", 0)
-		modulehashes.Reachable = true
-		modulehashes.Local = true
+		modulehashes.Attr |= AttrReachable
+		modulehashes.Attr |= AttrLocal
 		modulehashes.Type = obj.SRODATA
 
 		for i, shlib := range Ctxt.Shlibs {
@@ -554,7 +560,7 @@ func symtab() {
 
 			// modulehashes[i].runtimehash
 			abihash := Linklookup(Ctxt, "go.link.abihash."+modulename, 0)
-			abihash.Reachable = true
+			abihash.Attr |= AttrReachable
 			Addaddr(Ctxt, modulehashes, abihash)
 		}
 
@@ -562,6 +568,7 @@ func symtab() {
 		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
diff --git a/src/cmd/link/internal/ld/util.go b/src/cmd/link/internal/ld/util.go
index 2995e7f..19b3688 100644
--- a/src/cmd/link/internal/ld/util.go
+++ b/src/cmd/link/internal/ld/util.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -67,17 +67,6 @@ func tokenize(s string) []string {
 	return f
 }
 
-// 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()) {
diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go
index 8249c54..32d9f23 100644
--- a/src/cmd/link/internal/mips64/asm.go
+++ b/src/cmd/link/internal/mips64/asm.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,24 +32,65 @@ package mips64
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"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 {
-	return -1
+	// mips64 ELF relocation (endian neutral)
+	//		offset	uint64
+	//		sym		uint32
+	//		ssym	uint8
+	//		type3	uint8
+	//		type2	uint8
+	//		type	uint8
+	//		addend	int64
+
+	ld.Thearch.Vput(uint64(sectoff))
+
+	elfsym := r.Xsym.ElfsymForReloc()
+	ld.Thearch.Lput(uint32(elfsym))
+	ld.Cput(0)
+	ld.Cput(0)
+	ld.Cput(0)
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		switch r.Siz {
+		case 4:
+			ld.Cput(ld.R_MIPS_32)
+		case 8:
+			ld.Cput(ld.R_MIPS_64)
+		default:
+			return -1
+		}
+
+	case obj.R_ADDRMIPS:
+		ld.Cput(ld.R_MIPS_LO16)
+
+	case obj.R_ADDRMIPSU:
+		ld.Cput(ld.R_MIPS_HI16)
+
+	case obj.R_ADDRMIPSTLS:
+		ld.Cput(ld.R_MIPS_TLS_TPREL_LO16)
+
+	case obj.R_CALLMIPS,
+		obj.R_JMPMIPS:
+		ld.Cput(ld.R_MIPS_26)
+	}
+	ld.Thearch.Vput(uint64(r.Xadd))
+
+	return 0
 }
 
 func elfsetupplt() {
@@ -62,7 +103,37 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
 
 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
 	if ld.Linkmode == ld.LinkExternal {
-		return -1
+		switch r.Type {
+		default:
+			return -1
+
+		case obj.R_ADDRMIPS,
+			obj.R_ADDRMIPSU:
+			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.Type != obj.SDYNIMPORT && rs.Sect == nil {
+				ld.Diag("missing section for %s", rs.Name)
+			}
+			r.Xsym = rs
+
+			return 0
+
+		case obj.R_ADDRMIPSTLS,
+			obj.R_CALLMIPS,
+			obj.R_JMPMIPS:
+			r.Done = 0
+			r.Xsym = r.Sym
+			r.Xadd = r.Add
+			return 0
+		}
 	}
 
 	switch r.Type {
@@ -74,32 +145,32 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
 		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
 		return 0
 
-	case obj.R_ADDRMIPS:
+	case obj.R_ADDRMIPS,
+		obj.R_ADDRMIPSU:
 		t := ld.Symaddr(r.Sym) + r.Add
-		if t >= 1<<32 || t < -1<<32 {
-			ld.Diag("program too large, address relocation = %v", t)
+		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
+		if r.Type == obj.R_ADDRMIPS {
+			*val = int64(o1&0xffff0000 | uint32(t)&0xffff)
+		} else {
+			*val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff)
 		}
+		return 0
 
-		// the first instruction is always at the lower address, this is endian neutral;
-		// but note that o1 and o2 should still use the target endian.
-		o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:])
-		o2 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4:])
-		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)
+	case obj.R_ADDRMIPSTLS:
+		// thread pointer is at 0x7000 offset from the start of TLS data area
+		t := ld.Symaddr(r.Sym) + r.Add - 0x7000
+		if t < -32768 || t >= 32678 {
+			ld.Diag("TLS offset out of range %d", t)
 		}
+		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
+		*val = int64(o1&0xffff0000 | uint32(t)&0xffff)
 		return 0
 
 	case obj.R_CALLMIPS,
 		obj.R_JMPMIPS:
 		// Low 26 bits = (S + A) >> 2
 		t := ld.Symaddr(r.Sym) + r.Add
-		o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:])
+		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
 		*val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000)
 		return 0
 	}
@@ -113,7 +184,7 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
 
 func asmb() {
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 
@@ -131,7 +202,7 @@ func asmb() {
 
 	if ld.Segrodata.Filelen > 0 {
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+			fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
 		ld.Bso.Flush()
 
@@ -140,13 +211,16 @@ func asmb() {
 	}
 
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+		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))
 
+	ld.Cseek(int64(ld.Segdwarf.Fileoff))
+	ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
 	/* output symbol table */
 	ld.Symsize = 0
 
@@ -155,13 +229,13 @@ func asmb() {
 	if ld.Debug['s'] == 0 {
 		// TODO: rationalize
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+			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.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
 			}
 
@@ -174,17 +248,12 @@ func asmb() {
 		default:
 			if ld.Iself {
 				if ld.Debug['v'] != 0 {
-					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+					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()
 				}
@@ -198,7 +267,7 @@ func asmb() {
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
 				for i := 0; int32(i) < ld.Lcsize; i++ {
-					ld.Cput(uint8(sym.P[i]))
+					ld.Cput(sym.P[i])
 				}
 
 				ld.Cflush()
@@ -208,7 +277,7 @@ func asmb() {
 
 	ld.Ctxt.Cursym = nil
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 	ld.Cseek(0)
@@ -216,10 +285,10 @@ func asmb() {
 	default:
 	case obj.Hplan9: /* plan 9 */
 		magic := uint32(4*18*18 + 7)
-		if ld.Thestring == "mips64le" {
+		if ld.SysArch == sys.ArchMIPS64LE {
 			magic = uint32(4*26*26 + 7)
 		}
-		ld.Thearch.Lput(uint32(magic))              /* magic */
+		ld.Thearch.Lput(magic)                      /* 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))
diff --git a/src/cmd/link/internal/mips64/l.go b/src/cmd/link/internal/mips64/l.go
index 8ea1d84..e3f4fb3 100644
--- a/src/cmd/link/internal/mips64/l.go
+++ b/src/cmd/link/internal/mips64/l.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -41,7 +41,7 @@ package mips64
 //	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.
+//	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
@@ -62,10 +62,9 @@ package mips64
 // THE SOFTWARE.
 
 const (
-	thechar   = '0'
 	MaxAlign  = 32 // max data alignment
+	MinAlign  = 1  // min data alignment
 	FuncAlign = 8
-	MINLC     = 4
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/mips64/obj.go b/src/cmd/link/internal/mips64/obj.go
index ad686e9..ae9a280 100644
--- a/src/cmd/link/internal/mips64/obj.go
+++ b/src/cmd/link/internal/mips64/obj.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,6 +32,7 @@ package mips64
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,20 +46,15 @@ func Main() {
 }
 
 func linkarchinit() {
-	ld.Thestring = obj.Getgoarch()
-	if ld.Thestring == "mips64le" {
-		ld.Thelinkarch = &ld.Linkmips64le
+	if obj.Getgoarch() == "mips64le" {
+		ld.SysArch = sys.ArchMIPS64LE
 	} else {
-		ld.Thelinkarch = &ld.Linkmips64
+		ld.SysArch = sys.ArchMIPS64
 	}
 
-	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.Minalign = MinAlign
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
@@ -71,14 +67,20 @@ func linkarchinit() {
 	ld.Thearch.Elfsetupplt = elfsetupplt
 	ld.Thearch.Gentext = gentext
 	ld.Thearch.Machoreloc1 = machoreloc1
-	if ld.Thelinkarch == &ld.Linkmips64le {
+	if ld.SysArch == sys.ArchMIPS64LE {
 		ld.Thearch.Lput = ld.Lputl
 		ld.Thearch.Wput = ld.Wputl
 		ld.Thearch.Vput = ld.Vputl
+		ld.Thearch.Append16 = ld.Append16l
+		ld.Thearch.Append32 = ld.Append32l
+		ld.Thearch.Append64 = ld.Append64l
 	} else {
 		ld.Thearch.Lput = ld.Lputb
 		ld.Thearch.Wput = ld.Wputb
 		ld.Thearch.Vput = ld.Vputb
+		ld.Thearch.Append16 = ld.Append16b
+		ld.Thearch.Append32 = ld.Append32b
+		ld.Thearch.Append64 = ld.Append64b
 	}
 
 	ld.Thearch.Linuxdynld = "/lib64/ld64.so.1"
@@ -105,6 +107,9 @@ func archinit() {
 		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:
+		break
 	}
 
 	switch ld.HEADTYPE {
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index 169accc..bd2e23f 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -39,16 +39,8 @@ import (
 )
 
 func genplt() {
-	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
+	// 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.
@@ -78,7 +70,7 @@ func genplt() {
 	// 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
+	//    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.
@@ -89,17 +81,15 @@ func genplt() {
 	// 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,
+	// 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]
+	for _, s := range ld.Ctxt.Textp {
+		for i := range s.R {
+			r := &s.R[i]
 			if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != obj.SDYNIMPORT {
 				continue
 			}
@@ -109,35 +99,28 @@ func genplt() {
 			addpltsym(ld.Ctxt, r.Sym)
 
 			// Generate call stub
-			n = fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
+			n := fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
 
-			stub = ld.Linklookup(ld.Ctxt, n, 0)
-			stub.Reachable = stub.Reachable || s.Reachable
+			stub := ld.Linklookup(ld.Ctxt, n, 0)
+			if s.Attr.Reachable() {
+				stub.Attr |= ld.AttrReachable
+			}
 			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
-
+				ld.Ctxt.Textp = append(ld.Ctxt.Textp, stub)
 				gencallstub(1, stub, r.Sym)
 			}
 
 			// Update the relocation to use the call stub
 			r.Sym = stub
 
-			// Restore TOC after bl.  The compiler put a
+			// Restore TOC after bl. The compiler put a
 			// nop here for us to overwrite.
-			o1 = 0xe8410018 // ld r2,24(r1)
+			const o1 = 0xe8410018 // ld r2,24(r1)
 			ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
 		}
 	}
-
 }
 
 func genaddmoduledata() {
@@ -145,11 +128,11 @@ func genaddmoduledata() {
 	if addmoduledata.Type == obj.STEXT {
 		return
 	}
-	addmoduledata.Reachable = true
+	addmoduledata.Attr |= ld.AttrReachable
 	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
 	initfunc.Type = obj.STEXT
-	initfunc.Local = true
-	initfunc.Reachable = true
+	initfunc.Attr |= ld.AttrLocal
+	initfunc.Attr |= ld.AttrReachable
 	o := func(op uint32) {
 		ld.Adduint32(ld.Ctxt, initfunc, op)
 	}
@@ -193,16 +176,10 @@ func genaddmoduledata() {
 	// blr
 	o(0x4e800020)
 
-	if ld.Ctxt.Etextp != nil {
-		ld.Ctxt.Etextp.Next = initfunc
-	} else {
-		ld.Ctxt.Textp = initfunc
-	}
-	ld.Ctxt.Etextp = initfunc
-
+	ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
 	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
-	initarray_entry.Reachable = true
-	initarray_entry.Local = true
+	initarray_entry.Attr |= ld.AttrReachable
+	initarray_entry.Attr |= ld.AttrLocal
 	initarray_entry.Type = obj.SINITARR
 	ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
 }
@@ -263,10 +240,6 @@ func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
 	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
@@ -284,7 +257,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 
 		// 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
+		// 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
@@ -465,7 +438,7 @@ func elfsetupplt() {
 		// 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.
+		// before the PLT array. Reserve space for these.
 		plt.Size = 16
 	}
 }
@@ -832,7 +805,7 @@ func ensureglinkresolver() *ld.LSym {
 
 func asmb() {
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 
@@ -850,7 +823,7 @@ func asmb() {
 
 	if ld.Segrodata.Filelen > 0 {
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+			fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
 		ld.Bso.Flush()
 
@@ -859,13 +832,16 @@ func asmb() {
 	}
 
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+		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))
 
+	ld.Cseek(int64(ld.Segdwarf.Fileoff))
+	ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
 	/* output symbol table */
 	ld.Symsize = 0
 
@@ -874,13 +850,13 @@ func asmb() {
 	if ld.Debug['s'] == 0 {
 		// TODO: rationalize
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+			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.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
 			}
 
@@ -893,17 +869,12 @@ func asmb() {
 		default:
 			if ld.Iself {
 				if ld.Debug['v'] != 0 {
-					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+					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()
 				}
@@ -917,7 +888,7 @@ func asmb() {
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
 				for i := 0; int32(i) < ld.Lcsize; i++ {
-					ld.Cput(uint8(sym.P[i]))
+					ld.Cput(sym.P[i])
 				}
 
 				ld.Cflush()
@@ -927,7 +898,7 @@ func asmb() {
 
 	ld.Ctxt.Cursym = nil
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 	ld.Cseek(0)
diff --git a/src/cmd/link/internal/ppc64/l.go b/src/cmd/link/internal/ppc64/l.go
index 1c4a4a9..2e5c235 100644
--- a/src/cmd/link/internal/ppc64/l.go
+++ b/src/cmd/link/internal/ppc64/l.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -41,7 +41,7 @@ package ppc64
 //	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.
+//	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
@@ -62,10 +62,9 @@ package ppc64
 // THE SOFTWARE.
 
 const (
-	thechar   = '9'
 	MaxAlign  = 32 // max data alignment
+	MinAlign  = 1  // min data alignment
 	FuncAlign = 8
-	MINLC     = 4
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go
index c604d3b..b619eb9 100644
--- a/src/cmd/link/internal/ppc64/obj.go
+++ b/src/cmd/link/internal/ppc64/obj.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,6 +32,7 @@ package ppc64
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,20 +46,15 @@ func Main() {
 }
 
 func linkarchinit() {
-	ld.Thestring = obj.Getgoarch()
-	if ld.Thestring == "ppc64le" {
-		ld.Thelinkarch = &ld.Linkppc64le
+	if obj.Getgoarch() == "ppc64le" {
+		ld.SysArch = sys.ArchPPC64LE
 	} else {
-		ld.Thelinkarch = &ld.Linkppc64
+		ld.SysArch = sys.ArchPPC64
 	}
 
-	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.Minalign = MinAlign
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
@@ -71,14 +67,20 @@ func linkarchinit() {
 	ld.Thearch.Elfsetupplt = elfsetupplt
 	ld.Thearch.Gentext = gentext
 	ld.Thearch.Machoreloc1 = machoreloc1
-	if ld.Thelinkarch == &ld.Linkppc64le {
+	if ld.SysArch == sys.ArchPPC64LE {
 		ld.Thearch.Lput = ld.Lputl
 		ld.Thearch.Wput = ld.Wputl
 		ld.Thearch.Vput = ld.Vputl
+		ld.Thearch.Append16 = ld.Append16l
+		ld.Thearch.Append32 = ld.Append32l
+		ld.Thearch.Append64 = ld.Append64l
 	} else {
 		ld.Thearch.Lput = ld.Lputb
 		ld.Thearch.Wput = ld.Wputb
 		ld.Thearch.Vput = ld.Vputb
+		ld.Thearch.Append16 = ld.Append16b
+		ld.Thearch.Append32 = ld.Append32b
+		ld.Thearch.Append64 = ld.Append64b
 	}
 
 	// TODO(austin): ABI v1 uses /usr/lib/ld.so.1
@@ -143,7 +145,7 @@ func archinit() {
 		}
 
 	case obj.Hlinux: /* ppc64 elf */
-		if ld.Thestring == "ppc64" {
+		if ld.SysArch == sys.ArchPPC64 {
 			ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet
 		}
 		ld.Elfinit()
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
new file mode 100644
index 0000000..9864749
--- /dev/null
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -0,0 +1,595 @@
+// 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 s390x
+
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/ld"
+	"debug/elf"
+	"fmt"
+)
+
+// gentext generates assembly to append the local moduledata to the global
+// moduledata linked list at initialization time. This is only done if the runtime
+// is in a different module.
+//
+// <go.link.addmoduledata>:
+// 	larl  %r2, <local.moduledata>
+// 	jg    <runtime.addmoduledata at plt>
+//	undef
+//
+// The job of appending the moduledata is delegated to runtime.addmoduledata.
+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.Attr |= ld.AttrReachable
+	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+	initfunc.Type = obj.STEXT
+	initfunc.Attr |= ld.AttrLocal
+	initfunc.Attr |= ld.AttrReachable
+
+	// larl %r2, <local.moduledata>
+	ld.Adduint8(ld.Ctxt, initfunc, 0xc0)
+	ld.Adduint8(ld.Ctxt, initfunc, 0x20)
+	lmd := ld.Addrel(initfunc)
+	lmd.Off = int32(initfunc.Size)
+	lmd.Siz = 4
+	lmd.Sym = ld.Ctxt.Moduledata
+	lmd.Type = obj.R_PCREL
+	lmd.Variant = ld.RV_390_DBL
+	lmd.Add = 2 + int64(lmd.Siz)
+	ld.Adduint32(ld.Ctxt, initfunc, 0)
+
+	// jg <runtime.addmoduledata[@plt]>
+	ld.Adduint8(ld.Ctxt, initfunc, 0xc0)
+	ld.Adduint8(ld.Ctxt, initfunc, 0xf4)
+	rel := ld.Addrel(initfunc)
+	rel.Off = int32(initfunc.Size)
+	rel.Siz = 4
+	rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+	rel.Type = obj.R_CALL
+	rel.Variant = ld.RV_390_DBL
+	rel.Add = 2 + int64(rel.Siz)
+	ld.Adduint32(ld.Ctxt, initfunc, 0)
+
+	// undef (for debugging)
+	ld.Adduint32(ld.Ctxt, initfunc, 0)
+
+	ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
+	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
+	initarray_entry.Attr |= ld.AttrLocal
+	initarray_entry.Attr |= ld.AttrReachable
+	initarray_entry.Type = obj.SINITARR
+	ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
+}
+
+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_390_12,
+		256 + ld.R_390_GOT12:
+		ld.Diag("s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type-256)
+		return
+
+	case 256 + ld.R_390_8,
+		256 + ld.R_390_16,
+		256 + ld.R_390_32,
+		256 + ld.R_390_64:
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected R_390_nn relocation for dynamic symbol %s", targ.Name)
+		}
+		r.Type = obj.R_ADDR
+		return
+
+	case 256 + ld.R_390_PC16,
+		256 + ld.R_390_PC32,
+		256 + ld.R_390_PC64:
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected R_390_PCnn 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 += int64(r.Siz)
+		return
+
+	case 256 + ld.R_390_GOT16,
+		256 + ld.R_390_GOT32,
+		256 + ld.R_390_GOT64:
+		ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
+		return
+
+	case 256 + ld.R_390_PLT16DBL,
+		256 + ld.R_390_PLT32DBL:
+		r.Type = obj.R_PCREL
+		r.Variant = ld.RV_390_DBL
+		r.Add += int64(r.Siz)
+		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_390_PLT32,
+		256 + ld.R_390_PLT64:
+		r.Type = obj.R_PCREL
+		r.Add += int64(r.Siz)
+		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_390_COPY:
+		ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
+
+	case 256 + ld.R_390_GLOB_DAT:
+		ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
+
+	case 256 + ld.R_390_JMP_SLOT:
+		ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
+
+	case 256 + ld.R_390_RELATIVE:
+		ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
+
+	case 256 + ld.R_390_GOTOFF:
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
+		}
+		r.Type = obj.R_GOTOFF
+		return
+
+	case 256 + ld.R_390_GOTPC:
+		r.Type = obj.R_PCREL
+		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+		r.Add += int64(r.Siz)
+		return
+
+	case 256 + ld.R_390_PC16DBL,
+		256 + ld.R_390_PC32DBL:
+		r.Type = obj.R_PCREL
+		r.Variant = ld.RV_390_DBL
+		r.Add += int64(r.Siz)
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
+		}
+		return
+
+	case 256 + ld.R_390_GOTPCDBL:
+		r.Type = obj.R_PCREL
+		r.Variant = ld.RV_390_DBL
+		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+		r.Add += int64(r.Siz)
+		return
+
+	case 256 + ld.R_390_GOTENT:
+		addgotsym(targ)
+
+		r.Type = obj.R_PCREL
+		r.Variant = ld.RV_390_DBL
+		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+		r.Add += int64(targ.Got)
+		r.Add += int64(r.Siz)
+		return
+	}
+	// Handle references to ELF symbols from our own object files.
+	if targ.Type != obj.SDYNIMPORT {
+		return
+	}
+
+	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.ElfsymForReloc()
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_TLS_LE:
+		switch r.Siz {
+		default:
+			return -1
+		case 4:
+			// WARNING - silently ignored by linker in ELF64
+			ld.Thearch.Vput(ld.R_390_TLS_LE32 | uint64(elfsym)<<32)
+		case 8:
+			// WARNING - silently ignored by linker in ELF32
+			ld.Thearch.Vput(ld.R_390_TLS_LE64 | uint64(elfsym)<<32)
+		}
+
+	case obj.R_TLS_IE:
+		switch r.Siz {
+		default:
+			return -1
+		case 4:
+			ld.Thearch.Vput(ld.R_390_TLS_IEENT | uint64(elfsym)<<32)
+		}
+
+	case obj.R_ADDR:
+		switch r.Siz {
+		default:
+			return -1
+		case 4:
+			ld.Thearch.Vput(ld.R_390_32 | uint64(elfsym)<<32)
+		case 8:
+			ld.Thearch.Vput(ld.R_390_64 | uint64(elfsym)<<32)
+		}
+
+	case obj.R_GOTPCREL:
+		if r.Siz == 4 {
+			ld.Thearch.Vput(ld.R_390_GOTENT | uint64(elfsym)<<32)
+		} else {
+			return -1
+		}
+
+	case obj.R_PCREL, obj.R_PCRELDBL, obj.R_CALL:
+		elfrel := ld.R_390_NONE
+		isdbl := r.Variant&ld.RV_TYPE_MASK == ld.RV_390_DBL
+		// TODO(mundaym): all DBL style relocations should be
+		// signalled using the variant - see issue 14218.
+		switch r.Type {
+		case obj.R_PCRELDBL, obj.R_CALL:
+			isdbl = true
+		}
+		if r.Xsym.Type == obj.SDYNIMPORT && (r.Xsym.ElfType == elf.STT_FUNC || r.Type == obj.R_CALL) {
+			if isdbl {
+				switch r.Siz {
+				case 2:
+					elfrel = ld.R_390_PLT16DBL
+				case 4:
+					elfrel = ld.R_390_PLT32DBL
+				}
+			} else {
+				switch r.Siz {
+				case 4:
+					elfrel = ld.R_390_PLT32
+				case 8:
+					elfrel = ld.R_390_PLT64
+				}
+			}
+		} else {
+			if isdbl {
+				switch r.Siz {
+				case 2:
+					elfrel = ld.R_390_PC16DBL
+				case 4:
+					elfrel = ld.R_390_PC32DBL
+				}
+			} else {
+				switch r.Siz {
+				case 2:
+					elfrel = ld.R_390_PC16
+				case 4:
+					elfrel = ld.R_390_PC32
+				case 8:
+					elfrel = ld.R_390_PC64
+				}
+			}
+		}
+		if elfrel == ld.R_390_NONE {
+			return -1 // unsupported size/dbl combination
+		}
+		ld.Thearch.Vput(uint64(elfrel) | uint64(elfsym)<<32)
+	}
+
+	ld.Thearch.Vput(uint64(r.Xadd))
+	return 0
+}
+
+func elfsetupplt() {
+	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
+	got := ld.Linklookup(ld.Ctxt, ".got", 0)
+	if plt.Size == 0 {
+		// stg     %r1,56(%r15)
+		ld.Adduint8(ld.Ctxt, plt, 0xe3)
+		ld.Adduint8(ld.Ctxt, plt, 0x10)
+		ld.Adduint8(ld.Ctxt, plt, 0xf0)
+		ld.Adduint8(ld.Ctxt, plt, 0x38)
+		ld.Adduint8(ld.Ctxt, plt, 0x00)
+		ld.Adduint8(ld.Ctxt, plt, 0x24)
+		// larl    %r1,_GLOBAL_OFFSET_TABLE_
+		ld.Adduint8(ld.Ctxt, plt, 0xc0)
+		ld.Adduint8(ld.Ctxt, plt, 0x10)
+		ld.Addpcrelplus(ld.Ctxt, plt, got, 6)
+		// mvc     48(8,%r15),8(%r1)
+		ld.Adduint8(ld.Ctxt, plt, 0xd2)
+		ld.Adduint8(ld.Ctxt, plt, 0x07)
+		ld.Adduint8(ld.Ctxt, plt, 0xf0)
+		ld.Adduint8(ld.Ctxt, plt, 0x30)
+		ld.Adduint8(ld.Ctxt, plt, 0x10)
+		ld.Adduint8(ld.Ctxt, plt, 0x08)
+		// lg      %r1,16(%r1)
+		ld.Adduint8(ld.Ctxt, plt, 0xe3)
+		ld.Adduint8(ld.Ctxt, plt, 0x10)
+		ld.Adduint8(ld.Ctxt, plt, 0x10)
+		ld.Adduint8(ld.Ctxt, plt, 0x10)
+		ld.Adduint8(ld.Ctxt, plt, 0x00)
+		ld.Adduint8(ld.Ctxt, plt, 0x04)
+		// br      %r1
+		ld.Adduint8(ld.Ctxt, plt, 0x07)
+		ld.Adduint8(ld.Ctxt, plt, 0xf1)
+		// nopr    %r0
+		ld.Adduint8(ld.Ctxt, plt, 0x07)
+		ld.Adduint8(ld.Ctxt, plt, 0x00)
+		// nopr    %r0
+		ld.Adduint8(ld.Ctxt, plt, 0x07)
+		ld.Adduint8(ld.Ctxt, plt, 0x00)
+		// nopr    %r0
+		ld.Adduint8(ld.Ctxt, plt, 0x07)
+		ld.Adduint8(ld.Ctxt, plt, 0x00)
+
+		// 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 machoreloc1(r *ld.Reloc, sectoff int64) int {
+	return -1
+}
+
+func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+	if ld.Linkmode == ld.LinkExternal {
+		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 {
+	switch r.Variant & ld.RV_TYPE_MASK {
+	default:
+		ld.Diag("unexpected relocation variant %d", r.Variant)
+		return t
+
+	case ld.RV_NONE:
+		return t
+
+	case ld.RV_390_DBL:
+		if (t & 1) != 0 {
+			ld.Diag("%s+%v is not 2-byte aligned", r.Sym.Name, r.Sym.Value)
+		}
+		return t >> 1
+	}
+}
+
+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", 0)
+		rela := ld.Linklookup(ctxt, ".rela.plt", 0)
+		if plt.Size == 0 {
+			elfsetupplt()
+		}
+		// larl    %r1,_GLOBAL_OFFSET_TABLE_+index
+
+		ld.Adduint8(ctxt, plt, 0xc0)
+		ld.Adduint8(ctxt, plt, 0x10)
+		ld.Addpcrelplus(ctxt, plt, got, got.Size+6) // need variant?
+
+		// add to got: pointer to current pos in plt
+		ld.Addaddrplus(ctxt, got, plt, plt.Size+8) // weird but correct
+		// lg      %r1,0(%r1)
+		ld.Adduint8(ctxt, plt, 0xe3)
+		ld.Adduint8(ctxt, plt, 0x10)
+		ld.Adduint8(ctxt, plt, 0x10)
+		ld.Adduint8(ctxt, plt, 0x00)
+		ld.Adduint8(ctxt, plt, 0x00)
+		ld.Adduint8(ctxt, plt, 0x04)
+		// br      %r1
+		ld.Adduint8(ctxt, plt, 0x07)
+		ld.Adduint8(ctxt, plt, 0xf1)
+		// basr    %r1,%r0
+		ld.Adduint8(ctxt, plt, 0x0d)
+		ld.Adduint8(ctxt, plt, 0x10)
+		// lgf     %r1,12(%r1)
+		ld.Adduint8(ctxt, plt, 0xe3)
+		ld.Adduint8(ctxt, plt, 0x10)
+		ld.Adduint8(ctxt, plt, 0x10)
+		ld.Adduint8(ctxt, plt, 0x0c)
+		ld.Adduint8(ctxt, plt, 0x00)
+		ld.Adduint8(ctxt, plt, 0x14)
+		// jg .plt
+		ld.Adduint8(ctxt, plt, 0xc0)
+		ld.Adduint8(ctxt, plt, 0xf4)
+
+		ld.Adduint32(ctxt, plt, uint32(-((plt.Size - 2) >> 1))) // roll-your-own relocation
+		//.plt index
+		ld.Adduint32(ctxt, plt, uint32(rela.Size)) // rela size before current entry
+
+		// rela
+		ld.Addaddrplus(ctxt, rela, got, got.Size-8)
+
+		ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_390_JMP_SLOT))
+		ld.Adduint64(ctxt, rela, 0)
+
+		s.Plt = int32(plt.Size - 32)
+
+	} 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_390_GLOB_DAT))
+		ld.Adduint64(ld.Ctxt, rela, 0)
+	} 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))
+
+	ld.Cseek(int64(ld.Segdwarf.Fileoff))
+	ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
+	/* output symbol table */
+	ld.Symsize = 0
+
+	ld.Lcsize = 0
+	symo := uint32(0)
+	if ld.Debug['s'] == 0 {
+		if !ld.Iself {
+			ld.Diag("unsupported executable format")
+		}
+		if ld.Debug['v'] != 0 {
+			fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
+		}
+		ld.Bso.Flush()
+		symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
+		symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+
+		ld.Cseek(int64(symo))
+		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())
+		}
+
+		if ld.Linkmode == ld.LinkExternal {
+			ld.Elfemitreloc()
+		}
+	}
+
+	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:
+		ld.Diag("unsupported operating system")
+	case obj.Hlinux:
+		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/s390x/l.go b/src/cmd/link/internal/s390x/l.go
new file mode 100644
index 0000000..7c92bdb
--- /dev/null
+++ b/src/cmd/link/internal/s390x/l.go
@@ -0,0 +1,74 @@
+// 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 s390x
+
+// 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 (
+	MaxAlign  = 32 // max data alignment
+	MinAlign  = 2  // min data alignment
+	FuncAlign = 16
+)
+
+/* Used by ../internal/ld/dwarf.go */
+const (
+	DWARFREGSP = 15
+	DWARFREGLR = 14
+)
diff --git a/src/cmd/link/internal/s390x/obj.go b/src/cmd/link/internal/s390x/obj.go
new file mode 100644
index 0000000..b77f57d
--- /dev/null
+++ b/src/cmd/link/internal/s390x/obj.go
@@ -0,0 +1,114 @@
+// 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 s390x
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/sys"
+	"cmd/link/internal/ld"
+	"fmt"
+)
+
+// Reading object files.
+
+func Main() {
+	linkarchinit()
+	ld.Ldmain()
+}
+
+func linkarchinit() {
+	ld.SysArch = sys.ArchS390X
+
+	ld.Thearch.Funcalign = FuncAlign
+	ld.Thearch.Maxalign = MaxAlign
+	ld.Thearch.Minalign = MinAlign
+	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 // in asm.go
+	ld.Thearch.Elfreloc1 = elfreloc1
+	ld.Thearch.Elfsetupplt = elfsetupplt
+	ld.Thearch.Gentext = gentext
+	ld.Thearch.Machoreloc1 = machoreloc1
+	ld.Thearch.Lput = ld.Lputb
+	ld.Thearch.Wput = ld.Wputb
+	ld.Thearch.Vput = ld.Vputb
+	ld.Thearch.Append16 = ld.Append16b
+	ld.Thearch.Append32 = ld.Append32b
+	ld.Thearch.Append64 = ld.Append64b
+
+	ld.Thearch.Linuxdynld = "/lib64/ld64.so.1"
+
+	// not relevant for s390x
+	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
+	}
+
+	if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
+		ld.Linkmode = ld.LinkExternal
+	}
+
+	switch ld.HEADTYPE {
+	default:
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+
+	case obj.Hlinux: // s390x 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
+		}
+	}
+
+	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
index 830a7e6..cc8f96f 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -39,7 +39,7 @@ import (
 
 // Append 4 bytes to s and create a R_CALL relocation targeting t to fill them in.
 func addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) {
-	s.Reachable = true
+	s.Attr |= ld.AttrReachable
 	i := s.Size
 	s.Size += 4
 	ld.Symgrow(ctxt, s, s.Size)
@@ -57,8 +57,8 @@ func gentext() {
 
 	thunkfunc := ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0)
 	thunkfunc.Type = obj.STEXT
-	thunkfunc.Local = true
-	thunkfunc.Reachable = true
+	thunkfunc.Attr |= ld.AttrLocal
+	thunkfunc.Attr |= ld.AttrReachable
 	o := func(op ...uint8) {
 		for _, op1 := range op {
 			ld.Adduint8(ld.Ctxt, thunkfunc, op1)
@@ -69,12 +69,7 @@ func gentext() {
 	// c3		ret
 	o(0xc3)
 
-	if ld.Ctxt.Etextp != nil {
-		ld.Ctxt.Etextp.Next = thunkfunc
-	} else {
-		ld.Ctxt.Textp = thunkfunc
-	}
-	ld.Ctxt.Etextp = thunkfunc
+	ld.Ctxt.Textp = append(ld.Ctxt.Textp, thunkfunc)
 
 	addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
 	if addmoduledata.Type == obj.STEXT {
@@ -83,12 +78,12 @@ func gentext() {
 		return
 	}
 
-	addmoduledata.Reachable = true
+	addmoduledata.Attr |= ld.AttrReachable
 
 	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
 	initfunc.Type = obj.STEXT
-	initfunc.Local = true
-	initfunc.Reachable = true
+	initfunc.Attr |= ld.AttrLocal
+	initfunc.Attr |= ld.AttrReachable
 	o = func(op ...uint8) {
 		for _, op1 := range op {
 			ld.Adduint8(ld.Ctxt, initfunc, op1)
@@ -130,19 +125,14 @@ func gentext() {
 
 	o(0xc3)
 
-	ld.Ctxt.Etextp.Next = initfunc
-	ld.Ctxt.Etextp = initfunc
+	ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
 	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
-	initarray_entry.Reachable = true
-	initarray_entry.Local = true
+	initarray_entry.Attr |= ld.AttrReachable
+	initarray_entry.Attr |= ld.AttrLocal
 	initarray_entry.Type = obj.SINITARR
 	ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
 }
 
-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
@@ -292,14 +282,14 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 			return
 		}
 
-		if ld.HEADTYPE == obj.Hdarwin && s.Size == PtrSize && r.Off == 0 {
+		if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.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,
+			// 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.
@@ -317,7 +307,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
 			return
 		}
 
-		if ld.HEADTYPE == obj.Hwindows && s.Size == PtrSize {
+		if ld.HEADTYPE == obj.Hwindows && s.Size == int64(ld.SysArch.PtrSize) {
 			// nothing to do, the relocation will be laid out in pereloc1
 			return
 		}
@@ -609,7 +599,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) {
 
 func asmb() {
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 
@@ -619,7 +609,8 @@ func asmb() {
 
 	sect := ld.Segtext.Sect
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
-	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+	// 0xCC is INT $3 - breakpoint instruction
+	ld.CodeblkPad(int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
 	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))
@@ -627,7 +618,7 @@ func asmb() {
 
 	if ld.Segrodata.Filelen > 0 {
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+			fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
 		}
 		ld.Bso.Flush()
 
@@ -636,26 +627,18 @@ func asmb() {
 	}
 
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+		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))
 
+	ld.Cseek(int64(ld.Segdwarf.Fileoff))
+	ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.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())
 	}
 
@@ -666,13 +649,13 @@ func asmb() {
 	if ld.Debug['s'] == 0 {
 		// TODO: rationalize
 		if ld.Debug['v'] != 0 {
-			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+			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.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
 			}
 
@@ -683,7 +666,7 @@ func asmb() {
 			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.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
 			symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
 		}
 
@@ -692,17 +675,12 @@ func asmb() {
 		default:
 			if ld.Iself {
 				if ld.Debug['v'] != 0 {
-					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+					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()
 				}
@@ -716,7 +694,7 @@ func asmb() {
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
 				for i := 0; int32(i) < ld.Lcsize; i++ {
-					ld.Cput(uint8(sym.P[i]))
+					ld.Cput(sym.P[i])
 				}
 
 				ld.Cflush()
@@ -724,9 +702,8 @@ func asmb() {
 
 		case obj.Hwindows:
 			if ld.Debug['v'] != 0 {
-				fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+				fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 			}
-			ld.Dwarfemitdebugsections()
 
 		case obj.Hdarwin:
 			if ld.Linkmode == ld.LinkExternal {
@@ -736,7 +713,7 @@ func asmb() {
 	}
 
 	if ld.Debug['v'] != 0 {
-		fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
+		fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime())
 	}
 	ld.Bso.Flush()
 	ld.Cseek(0)
diff --git a/src/cmd/link/internal/x86/l.go b/src/cmd/link/internal/x86/l.go
index c067425..065508e 100644
--- a/src/cmd/link/internal/x86/l.go
+++ b/src/cmd/link/internal/x86/l.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -31,11 +31,9 @@
 package x86
 
 const (
-	thechar   = '8'
-	PtrSize   = 4
 	MaxAlign  = 32 // max data alignment
+	MinAlign  = 1  // min data alignment
 	FuncAlign = 16
-	MINLC     = 1
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go
index c153555..a4d8f50 100644
--- a/src/cmd/link/internal/x86/obj.go
+++ b/src/cmd/link/internal/x86/obj.go
@@ -8,7 +8,7 @@
 //	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.
+//	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
@@ -32,6 +32,7 @@ package x86
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,16 +46,11 @@ func Main() {
 }
 
 func linkarchinit() {
-	ld.Thestring = "386"
-	ld.Thelinkarch = &ld.Link386
+	ld.SysArch = sys.Arch386
 
-	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.Minalign = MinAlign
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
@@ -71,6 +67,9 @@ func linkarchinit() {
 	ld.Thearch.Lput = ld.Lputl
 	ld.Thearch.Wput = ld.Wputl
 	ld.Thearch.Vput = ld.Vputl
+	ld.Thearch.Append16 = ld.Append16l
+	ld.Thearch.Append32 = ld.Append32l
+	ld.Thearch.Append64 = ld.Append64l
 
 	ld.Thearch.Linuxdynld = "/lib/ld-linux.so.2"
 	ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
@@ -90,7 +89,7 @@ func archinit() {
 		ld.Linkmode = ld.LinkExternal
 		got := ld.Linklookup(ld.Ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
 		got.Type = obj.SDYNIMPORT
-		got.Reachable = true
+		got.Attr |= ld.AttrReachable
 	}
 
 	switch ld.HEADTYPE {
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
new file mode 100644
index 0000000..4ef1845
--- /dev/null
+++ b/src/cmd/link/link_test.go
@@ -0,0 +1,30 @@
+package main
+
+import "testing"
+
+var AuthorPaidByTheColumnInch struct {
+	fog int `
+	London. Michaelmas term lately over, and the Lord Chancellor sitting in Lincoln’s Inn Hall. Implacable November weather. As much mud in the streets as if the waters had but newly retired from the face of the earth, and it would not be wonderful to meet a Megalosaurus, forty feet long or so, waddling like an elephantine lizard up Holborn Hill. Smoke lowering down from chimney-pots, making a soft black drizzle, with flakes of soot in it as big as full-grown snowflakes—gone into mourning,  [...]
+
+	Fog everywhere. Fog up the river, where it flows among green aits and meadows; fog down the river, where it rolls defiled among the tiers of shipping and the waterside pollutions of a great (and dirty) city. Fog on the Essex marshes, fog on the Kentish heights. Fog creeping into the cabooses of collier-brigs; fog lying out on the yards and hovering in the rigging of great ships; fog drooping on the gunwales of barges and small boats. Fog in the eyes and throats of ancient Greenwich pens [...]
+
+	Gas looming through the fog in divers places in the streets, much as the sun may, from the spongey fields, be seen to loom by husbandman and ploughboy. Most of the shops lighted two hours before their time—as the gas seems to know, for it has a haggard and unwilling look.
+
+	The raw afternoon is rawest, and the dense fog is densest, and the muddy streets are muddiest near that leaden-headed old obstruction, appropriate ornament for the threshold of a leaden-headed old corporation, Temple Bar. And hard by Temple Bar, in Lincoln’s Inn Hall, at the very heart of the fog, sits the Lord High Chancellor in his High Court of Chancery.`
+
+	wind int `
+	It was grand to see how the wind awoke, and bent the trees, and drove the rain before it like a cloud of smoke; and to hear the solemn thunder, and to see the lightning; and while thinking with awe of the tremendous powers by which our little lives are encompassed, to consider how beneficent they are, and how upon the smallest flower and leaf there was already a freshness poured from all this seeming rage, which seemed to make creation new again.`
+
+	jarndyce int `
+	Jarndyce and Jarndyce drones on. This scarecrow of a suit has, over the course of time, become so complicated, that no man alive knows what it means. The parties to it understand it least; but it has been observed that no two Chancery lawyers can talk about it for five minutes, without coming to a total disagreement as to all the premises. Innumerable children have been born into the cause; innumerable young people have married into it; innumerable old people have died out of it. Scores [...]
+
+	principle int `
+	The one great principle of the English law is, to make business for itself. There is no other principle distinctly, certainly, and consistently maintained through all its narrow turnings. Viewed by this light it becomes a coherent scheme, and not the monstrous maze the laity are apt to think it. Let them but once clearly perceive that its grand principle is to make business for itself at their expense, and surely they will cease to grumble.`
+}
+
+func TestLargeSymName(t *testing.T) {
+	// The compiler generates a symbol name using the string form of the
+	// type. This tests that the linker can read symbol names larger than
+	// the bufio buffer. Issue #15104.
+	_ = AuthorPaidByTheColumnInch
+}
diff --git a/src/cmd/link/main.go b/src/cmd/link/main.go
index 63df8de..f92e02e 100644
--- a/src/cmd/link/main.go
+++ b/src/cmd/link/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -11,6 +11,7 @@ import (
 	"cmd/link/internal/arm64"
 	"cmd/link/internal/mips64"
 	"cmd/link/internal/ppc64"
+	"cmd/link/internal/s390x"
 	"cmd/link/internal/x86"
 	"fmt"
 	"os"
@@ -33,5 +34,7 @@ func main() {
 		mips64.Main()
 	case "ppc64", "ppc64le":
 		ppc64.Main()
+	case "s390x":
+		s390x.Main()
 	}
 }
diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go
index 3089e48..462c4c5 100644
--- a/src/cmd/nm/nm.go
+++ b/src/cmd/nm/nm.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 8ceaba0..899db06 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -107,6 +107,8 @@ func TestDisasm(t *testing.T) {
 		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
 	case "mips64", "mips64le":
 		t.Skipf("skipping on %s, issue 12559", runtime.GOARCH)
+	case "s390x":
+		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
 	}
 	testDisasm(t)
 }
@@ -123,6 +125,8 @@ func TestDisasmExtld(t *testing.T) {
 		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
 	case "mips64", "mips64le":
 		t.Skipf("skipping on %s, issue 12559 and 12560", runtime.GOARCH)
+	case "s390x":
+		t.Skipf("skipping on %s, issue 15255", runtime.GOARCH)
 	}
 	// TODO(jsing): Reenable once openbsd/arm has external linking support.
 	if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
index f65ae0c..1c168f9 100644
--- a/src/cmd/pack/pack.go
+++ b/src/cmd/pack/pack.go
@@ -40,7 +40,7 @@ For compatibility with old Go build environments the op string grc is
 accepted as a synonym for c.
 
 For more information, run
-	godoc cmd/pack`
+	go doc cmd/pack`
 
 func usage() {
 	fmt.Fprintln(os.Stderr, usageMessage)
@@ -286,7 +286,7 @@ func (ar *Archive) output(entry *Entry, w io.Writer) {
 		log.Fatal("short file")
 	}
 	if entry.size&1 == 1 {
-		_, err := ar.fd.Seek(1, 1)
+		_, err := ar.fd.Seek(1, io.SeekCurrent)
 		if err != nil {
 			log.Fatal(err)
 		}
@@ -299,7 +299,7 @@ func (ar *Archive) skip(entry *Entry) {
 	if size&1 == 1 {
 		size++
 	}
-	_, err := ar.fd.Seek(size, 1)
+	_, err := ar.fd.Seek(size, io.SeekCurrent)
 	if err != nil {
 		log.Fatal(err)
 	}
diff --git a/src/cmd/pprof/doc.go b/src/cmd/pprof/doc.go
index 1e094fe..84de036 100644
--- a/src/cmd/pprof/doc.go
+++ b/src/cmd/pprof/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/cmd/pprof/internal/commands/commands.go b/src/cmd/pprof/internal/commands/commands.go
deleted file mode 100644
index 9aeee57..0000000
--- a/src/cmd/pprof/internal/commands/commands.go
+++ /dev/null
@@ -1,243 +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 commands defines and manages the basic pprof commands
-package commands
-
-import (
-	"bytes"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"os"
-	"os/exec"
-	"runtime"
-	"strings"
-	"time"
-
-	"cmd/pprof/internal/plugin"
-	"cmd/pprof/internal/report"
-	"cmd/pprof/internal/svg"
-	"cmd/pprof/internal/tempfile"
-)
-
-// Commands describes the commands accepted by pprof.
-type Commands map[string]*Command
-
-// Command describes the actions for a pprof command. Includes a
-// function for command-line completion, the report format to use
-// during report generation, any postprocessing functions, and whether
-// the command expects a regexp parameter (typically a function name).
-type Command struct {
-	Complete    Completer     // autocomplete for interactive mode
-	Format      int           // report format to generate
-	PostProcess PostProcessor // postprocessing to run on report
-	HasParam    bool          // Collect a parameter from the CLI
-	Usage       string        // Help text
-}
-
-// Completer is a function for command-line autocompletion
-type Completer func(prefix string) string
-
-// PostProcessor is a function that applies post-processing to the report output
-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) Commands {
-	return Commands{
-		// Commands that require no post-processing.
-		"tags":   {nil, report.Tags, nil, false, "Outputs all tags in the profile"},
-		"raw":    {c, report.Raw, nil, false, "Outputs a text representation of the raw profile"},
-		"dot":    {c, report.Dot, nil, false, "Outputs a graph in DOT format"},
-		"top":    {c, report.Text, nil, false, "Outputs top entries in text form"},
-		"tree":   {c, report.Tree, nil, false, "Outputs a text rendering of call graph"},
-		"text":   {c, report.Text, nil, false, "Outputs top entries in text form"},
-		"disasm": {c, report.Dis, nil, true, "Output annotated assembly for functions matching regexp or address"},
-		"list":   {c, report.List, nil, true, "Output annotated source for functions matching regexp"},
-		"peek":   {c, report.Tree, nil, true, "Output callers/callees of functions matching regexp"},
-
-		// Save binary formats to a file
-		"callgrind": {c, report.Callgrind, awayFromTTY("callgraph.out"), false, "Outputs a graph in callgrind format"},
-		"proto":     {c, report.Proto, awayFromTTY("pb.gz"), false, "Outputs the profile in compressed protobuf format"},
-
-		// Generate report in DOT format and postprocess with dot
-		"gif": {c, report.Dot, invokeDot("gif"), false, "Outputs a graph image in GIF format"},
-		"pdf": {c, report.Dot, invokeDot("pdf"), false, "Outputs a graph in PDF format"},
-		"png": {c, report.Dot, invokeDot("png"), false, "Outputs a graph image in PNG format"},
-		"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(), 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(), "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"},
-	}
-}
-
-// browsers returns a list of commands to attempt for web visualization
-// on the current platform
-func browsers() []string {
-	var cmds []string
-	if exe := os.Getenv("BROWSER"); exe != "" {
-		cmds = append(cmds, exe)
-	}
-	switch runtime.GOOS {
-	case "darwin":
-		cmds = append(cmds, "/usr/bin/open")
-	case "windows":
-		cmds = append(cmds, "cmd /c start")
-	default:
-		cmds = append(cmds, "xdg-open")
-	}
-	cmds = append(cmds, "chrome", "google-chrome", "firefox")
-	return cmds
-}
-
-// NewCompleter creates an autocompletion function for a set of commands.
-func NewCompleter(cs Commands) Completer {
-	return func(line string) string {
-		switch tokens := strings.Fields(line); len(tokens) {
-		case 0:
-			// Nothing to complete
-		case 1:
-			// Single token -- complete command name
-			found := ""
-			for c := range cs {
-				if strings.HasPrefix(c, tokens[0]) {
-					if found != "" {
-						return line
-					}
-					found = c
-				}
-			}
-			if found != "" {
-				return found
-			}
-		default:
-			// Multiple tokens -- complete using command completer
-			if c, ok := cs[tokens[0]]; ok {
-				if c.Complete != nil {
-					lastTokenIdx := len(tokens) - 1
-					lastToken := tokens[lastTokenIdx]
-					if strings.HasPrefix(lastToken, "-") {
-						lastToken = "-" + c.Complete(lastToken[1:])
-					} else {
-						lastToken = c.Complete(lastToken)
-					}
-					return strings.Join(append(tokens[:lastTokenIdx], lastToken), " ")
-				}
-			}
-		}
-		return line
-	}
-}
-
-// awayFromTTY saves the output in a file if it would otherwise go to
-// the terminal screen. This is used to avoid dumping binary data on
-// the screen.
-func awayFromTTY(format string) PostProcessor {
-	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
-		if output == os.Stdout && ui.IsTerminal() {
-			tempFile, err := tempfile.New("", "profile", "."+format)
-			if err != nil {
-				return err
-			}
-			ui.PrintErr("Generating report in ", tempFile.Name())
-			_, err = fmt.Fprint(tempFile, input)
-			return err
-		}
-		_, err := fmt.Fprint(output, input)
-		return err
-	}
-}
-
-func invokeDot(format string) PostProcessor {
-	divert := awayFromTTY(format)
-	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
-		if _, err := exec.LookPath("dot"); err != nil {
-			ui.PrintErr("Cannot find dot, have you installed Graphviz?")
-			return err
-		}
-		cmd := exec.Command("dot", "-T"+format)
-		var buf bytes.Buffer
-		cmd.Stdin, cmd.Stdout, cmd.Stderr = input, &buf, os.Stderr
-		if err := cmd.Run(); err != nil {
-			return err
-		}
-		return divert(&buf, output, ui)
-	}
-}
-
-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))
-		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 {
-		if err := makeVizTmpDir(); err != nil {
-			return err
-		}
-		tempFile, err := tempfile.New(vizTmpDir, "pprof", "."+suffix)
-		if err != nil {
-			return err
-		}
-		tempfile.DeferDelete(tempFile.Name())
-		if err = format(input, tempFile, ui); err != nil {
-			return err
-		}
-		tempFile.Close() // on windows, if the file is Open, start cannot access it.
-		// Try visualizers until one is successful
-		for _, v := range visualizers {
-			// Separate command and arguments for exec.Command.
-			args := strings.Split(v, " ")
-			if len(args) == 0 {
-				continue
-			}
-			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
-					return viewer.Wait()
-				}
-				return nil
-			}
-		}
-		return err
-	}
-}
diff --git a/src/cmd/pprof/internal/driver/driver.go b/src/cmd/pprof/internal/driver/driver.go
deleted file mode 100644
index df6a2d1..0000000
--- a/src/cmd/pprof/internal/driver/driver.go
+++ /dev/null
@@ -1,1041 +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 driver implements the core pprof functionality. It can be
-// parameterized with a flag implementation, fetch and symbolize
-// mechanisms.
-package driver
-
-import (
-	"bytes"
-	"fmt"
-	"io"
-	"net/url"
-	"os"
-	"path/filepath"
-	"regexp"
-	"sort"
-	"strconv"
-	"strings"
-	"sync"
-	"time"
-
-	"cmd/pprof/internal/commands"
-	"cmd/pprof/internal/plugin"
-	"cmd/pprof/internal/profile"
-	"cmd/pprof/internal/report"
-	"cmd/pprof/internal/tempfile"
-)
-
-// PProf acquires a profile, and symbolizes it using a profile
-// manager. Then it generates a report formatted according to the
-// options selected through the flags package.
-func PProf(flagset plugin.FlagSet, fetch plugin.Fetcher, sym plugin.Symbolizer, obj plugin.ObjTool, ui plugin.UI, overrides commands.Commands) error {
-	// Remove any temporary files created during pprof processing.
-	defer tempfile.Cleanup()
-
-	f, err := getFlags(flagset, overrides, ui)
-	if err != nil {
-		return err
-	}
-
-	obj.SetConfig(*f.flagTools)
-
-	sources := f.profileSource
-	if len(sources) > 1 {
-		source := sources[0]
-		// If the first argument is a supported object file, treat as executable.
-		if file, err := obj.Open(source, 0); err == nil {
-			file.Close()
-			f.profileExecName = source
-			sources = sources[1:]
-		} else if *f.flagBuildID == "" && isBuildID(source) {
-			f.flagBuildID = &source
-			sources = sources[1:]
-		}
-	}
-
-	// errMu protects concurrent accesses to errset and err. errset is set if an
-	// error is encountered by one of the goroutines grabbing a profile.
-	errMu, errset := sync.Mutex{}, false
-
-	// Fetch profiles.
-	wg := sync.WaitGroup{}
-	profs := make([]*profile.Profile, len(sources))
-	for i, source := range sources {
-		wg.Add(1)
-		go func(i int, src string) {
-			defer wg.Done()
-			p, grabErr := grabProfile(src, f.profileExecName, *f.flagBuildID, fetch, sym, obj, ui, f)
-			if grabErr != nil {
-				errMu.Lock()
-				defer errMu.Unlock()
-				errset, err = true, grabErr
-				return
-			}
-			profs[i] = p
-		}(i, source)
-	}
-	wg.Wait()
-	if errset {
-		return err
-	}
-
-	// Merge profiles.
-	prof := profs[0]
-	for _, p := range profs[1:] {
-		if err = prof.Merge(p, 1); err != nil {
-			return err
-		}
-	}
-
-	if *f.flagBase != "" {
-		// Fetch base profile and subtract from current profile.
-		base, err := grabProfile(*f.flagBase, f.profileExecName, *f.flagBuildID, fetch, sym, obj, ui, f)
-		if err != nil {
-			return err
-		}
-
-		if err = prof.Merge(base, -1); err != nil {
-			return err
-		}
-	}
-
-	if err := processFlags(prof, ui, f); err != nil {
-		return err
-	}
-
-	if !*f.flagRuntime {
-		prof.RemoveUninteresting()
-	}
-
-	if *f.flagInteractive {
-		return interactive(prof, obj, ui, f)
-	}
-
-	return generate(false, prof, obj, ui, f)
-}
-
-// isBuildID determines if the profile may contain a build ID, by
-// checking that it is a string of hex digits.
-func isBuildID(id string) bool {
-	return strings.Trim(id, "0123456789abcdefABCDEF") == ""
-}
-
-// adjustURL updates the profile source URL based on heuristics. It
-// will append ?seconds=sec for CPU profiles if not already
-// specified. Returns the hostname if the profile is remote.
-func adjustURL(source string, sec int, ui plugin.UI) (adjusted, host string, duration time.Duration) {
-	// If there is a local file with this name, just use it.
-	if _, err := os.Stat(source); err == nil {
-		return source, "", 0
-	}
-
-	url, err := url.Parse(source)
-
-	// Automatically add http:// to URLs of the form hostname:port/path.
-	// url.Parse treats "hostname" as the Scheme.
-	if err != nil || (url.Host == "" && url.Scheme != "" && url.Scheme != "file") {
-		url, err = url.Parse("http://" + source)
-		if err != nil {
-			return source, url.Host, time.Duration(30) * time.Second
-		}
-	}
-	if scheme := strings.ToLower(url.Scheme); scheme == "" || scheme == "file" {
-		url.Scheme = ""
-		return url.String(), "", 0
-	}
-
-	values := url.Query()
-	if urlSeconds := values.Get("seconds"); urlSeconds != "" {
-		if us, err := strconv.ParseInt(urlSeconds, 10, 32); err == nil {
-			if sec >= 0 {
-				ui.PrintErr("Overriding -seconds for URL ", source)
-			}
-			sec = int(us)
-		}
-	}
-
-	switch strings.ToLower(url.Path) {
-	case "", "/":
-		// Apply default /profilez.
-		url.Path = "/profilez"
-	case "/protoz":
-		// Rewrite to /profilez?type=proto
-		url.Path = "/profilez"
-		values.Set("type", "proto")
-	}
-
-	if hasDuration(url.Path) {
-		if sec > 0 {
-			duration = time.Duration(sec) * time.Second
-			values.Set("seconds", fmt.Sprintf("%d", sec))
-		} else {
-			// Assume default duration: 30 seconds
-			duration = 30 * time.Second
-		}
-	}
-	url.RawQuery = values.Encode()
-	return url.String(), url.Host, duration
-}
-
-func hasDuration(path string) bool {
-	for _, trigger := range []string{"profilez", "wallz", "/profile"} {
-		if strings.Contains(path, trigger) {
-			return true
-		}
-	}
-	return false
-}
-
-// preprocess does filtering and aggregation of a profile based on the
-// requested options.
-func preprocess(prof *profile.Profile, ui plugin.UI, f *flags) error {
-	if *f.flagFocus != "" || *f.flagIgnore != "" || *f.flagHide != "" {
-		focus, ignore, hide, err := compileFocusIgnore(*f.flagFocus, *f.flagIgnore, *f.flagHide)
-		if err != nil {
-			return err
-		}
-		fm, im, hm := prof.FilterSamplesByName(focus, ignore, hide)
-
-		warnNoMatches(fm, *f.flagFocus, "Focus", ui)
-		warnNoMatches(im, *f.flagIgnore, "Ignore", ui)
-		warnNoMatches(hm, *f.flagHide, "Hide", ui)
-	}
-
-	if *f.flagTagFocus != "" || *f.flagTagIgnore != "" {
-		focus, err := compileTagFilter(*f.flagTagFocus, ui)
-		if err != nil {
-			return err
-		}
-		ignore, err := compileTagFilter(*f.flagTagIgnore, ui)
-		if err != nil {
-			return err
-		}
-		fm, im := prof.FilterSamplesByTag(focus, ignore)
-
-		warnNoMatches(fm, *f.flagTagFocus, "TagFocus", ui)
-		warnNoMatches(im, *f.flagTagIgnore, "TagIgnore", ui)
-	}
-
-	return aggregate(prof, f)
-}
-
-func compileFocusIgnore(focus, ignore, hide string) (f, i, h *regexp.Regexp, err error) {
-	if focus != "" {
-		if f, err = regexp.Compile(focus); err != nil {
-			return nil, nil, nil, fmt.Errorf("parsing focus regexp: %v", err)
-		}
-	}
-
-	if ignore != "" {
-		if i, err = regexp.Compile(ignore); err != nil {
-			return nil, nil, nil, fmt.Errorf("parsing ignore regexp: %v", err)
-		}
-	}
-
-	if hide != "" {
-		if h, err = regexp.Compile(hide); err != nil {
-			return nil, nil, nil, fmt.Errorf("parsing hide regexp: %v", err)
-		}
-	}
-	return
-}
-
-func compileTagFilter(filter string, ui plugin.UI) (f func(string, string, int64) bool, err error) {
-	if filter == "" {
-		return nil, nil
-	}
-	if numFilter := parseTagFilterRange(filter); numFilter != nil {
-		ui.PrintErr("Interpreted '", filter, "' as range, not regexp")
-		return func(key, val string, num int64) bool {
-			if val != "" {
-				return false
-			}
-			return numFilter(num, key)
-		}, nil
-	}
-	fx, err := regexp.Compile(filter)
-	if err != nil {
-		return nil, err
-	}
-
-	return func(key, val string, num int64) bool {
-		if val == "" {
-			return false
-		}
-		return fx.MatchString(key + ":" + val)
-	}, nil
-}
-
-var tagFilterRangeRx = regexp.MustCompile("([[:digit:]]+)([[:alpha:]]+)")
-
-// parseTagFilterRange returns a function to checks if a value is
-// contained on the range described by a string. It can recognize
-// strings of the form:
-// "32kb" -- matches values == 32kb
-// ":64kb" -- matches values <= 64kb
-// "4mb:" -- matches values >= 4mb
-// "12kb:64mb" -- matches values between 12kb and 64mb (both included).
-func parseTagFilterRange(filter string) func(int64, string) bool {
-	ranges := tagFilterRangeRx.FindAllStringSubmatch(filter, 2)
-	if len(ranges) == 0 {
-		return nil // No ranges were identified
-	}
-	v, err := strconv.ParseInt(ranges[0][1], 10, 64)
-	if err != nil {
-		panic(fmt.Errorf("Failed to parse int %s: %v", ranges[0][1], err))
-	}
-	value, unit := report.ScaleValue(v, ranges[0][2], ranges[0][2])
-	if len(ranges) == 1 {
-		switch match := ranges[0][0]; filter {
-		case match:
-			return func(v int64, u string) bool {
-				sv, su := report.ScaleValue(v, u, unit)
-				return su == unit && sv == value
-			}
-		case match + ":":
-			return func(v int64, u string) bool {
-				sv, su := report.ScaleValue(v, u, unit)
-				return su == unit && sv >= value
-			}
-		case ":" + match:
-			return func(v int64, u string) bool {
-				sv, su := report.ScaleValue(v, u, unit)
-				return su == unit && sv <= value
-			}
-		}
-		return nil
-	}
-	if filter != ranges[0][0]+":"+ranges[1][0] {
-		return nil
-	}
-	if v, err = strconv.ParseInt(ranges[1][1], 10, 64); err != nil {
-		panic(fmt.Errorf("Failed to parse int %s: %v", ranges[1][1], err))
-	}
-	value2, unit2 := report.ScaleValue(v, ranges[1][2], unit)
-	if unit != unit2 {
-		return nil
-	}
-	return func(v int64, u string) bool {
-		sv, su := report.ScaleValue(v, u, unit)
-		return su == unit && sv >= value && sv <= value2
-	}
-}
-
-func warnNoMatches(match bool, rx, option string, ui plugin.UI) {
-	if !match && rx != "" && rx != "." {
-		ui.PrintErr(option + " expression matched no samples: " + rx)
-	}
-}
-
-// grabProfile fetches and symbolizes a profile.
-func grabProfile(source, exec, buildid string, fetch plugin.Fetcher, sym plugin.Symbolizer, obj plugin.ObjTool, ui plugin.UI, f *flags) (*profile.Profile, error) {
-	source, host, duration := adjustURL(source, *f.flagSeconds, ui)
-	remote := host != ""
-
-	if remote {
-		ui.Print("Fetching profile from ", source)
-		if duration != 0 {
-			ui.Print("Please wait... (" + duration.String() + ")")
-		}
-	}
-
-	now := time.Now()
-	// Fetch profile from source.
-	// Give 50% slack on the timeout.
-	p, err := fetch(source, duration+duration/2, ui)
-	if err != nil {
-		return nil, err
-	}
-
-	// Update the time/duration if the profile source doesn't include it.
-	// TODO(rsilvera): Remove this when we remove support for legacy profiles.
-	if remote {
-		if p.TimeNanos == 0 {
-			p.TimeNanos = now.UnixNano()
-		}
-		if duration != 0 && p.DurationNanos == 0 {
-			p.DurationNanos = int64(duration)
-		}
-	}
-
-	// Replace executable/buildID with the options provided in the
-	// command line. Assume the executable is the first Mapping entry.
-	if exec != "" || buildid != "" {
-		if len(p.Mapping) == 0 {
-			// Create a fake mapping to hold the user option, and associate
-			// all samples to it.
-			m := &profile.Mapping{
-				ID: 1,
-			}
-			for _, l := range p.Location {
-				l.Mapping = m
-			}
-			p.Mapping = []*profile.Mapping{m}
-		}
-		if exec != "" {
-			p.Mapping[0].File = exec
-		}
-		if buildid != "" {
-			p.Mapping[0].BuildID = buildid
-		}
-	}
-
-	if err := sym(*f.flagSymbolize, source, p, obj, ui); err != nil {
-		return nil, err
-	}
-
-	// Save a copy of any remote profiles, unless the user is explicitly
-	// saving it.
-	if remote && !f.isFormat("proto") {
-		prefix := "pprof."
-		if len(p.Mapping) > 0 && p.Mapping[0].File != "" {
-			prefix = prefix + filepath.Base(p.Mapping[0].File) + "."
-		}
-		if !strings.ContainsRune(host, os.PathSeparator) {
-			prefix = prefix + host + "."
-		}
-		for _, s := range p.SampleType {
-			prefix = prefix + s.Type + "."
-		}
-
-		dir := os.Getenv("PPROF_TMPDIR")
-		tempFile, err := tempfile.New(dir, prefix, ".pb.gz")
-		if err == nil {
-			if err = p.Write(tempFile); err == nil {
-				ui.PrintErr("Saved profile in ", tempFile.Name())
-			}
-		}
-		if err != nil {
-			ui.PrintErr("Could not save profile: ", err)
-		}
-	}
-
-	if err := p.Demangle(obj.Demangle); err != nil {
-		ui.PrintErr("Failed to demangle profile: ", err)
-	}
-
-	if err := p.CheckValid(); err != nil {
-		return nil, fmt.Errorf("Grab %s: %v", source, err)
-	}
-
-	return p, nil
-}
-
-type flags struct {
-	flagInteractive   *bool              // Accept commands interactively
-	flagCommands      map[string]*bool   // pprof commands without parameters
-	flagParamCommands map[string]*string // pprof commands with parameters
-
-	flagOutput *string // Output file name
-
-	flagCum      *bool // Sort by cumulative data
-	flagCallTree *bool // generate a context-sensitive call tree
-
-	flagAddresses *bool // Report at address level
-	flagLines     *bool // Report at source line level
-	flagFiles     *bool // Report at file level
-	flagFunctions *bool // Report at function level [default]
-
-	flagSymbolize *string // Symbolization options (=none to disable)
-	flagBuildID   *string // Override build if for first mapping
-
-	flagNodeCount    *int     // Max number of nodes to show
-	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
-	flagTagFocus     *string  // Restrict to samples tagged with key:value matching regexp
-	flagTagIgnore    *string  // Discard samples tagged with key:value matching regexp
-	flagDropNegative *bool    // Skip negative values
-
-	flagBase *string // Source for base profile to user for comparison
-
-	flagSeconds *int // Length of time for dynamic profiles
-
-	flagTotalDelay  *bool // Display total delay at each region
-	flagContentions *bool // Display number of delays at each region
-	flagMeanDelay   *bool // Display mean delay at each region
-
-	flagInUseSpace   *bool    // Display in-use memory size
-	flagInUseObjects *bool    // Display in-use object counts
-	flagAllocSpace   *bool    // Display allocated memory size
-	flagAllocObjects *bool    // Display allocated object counts
-	flagDisplayUnit  *string  // Measurement unit to use on reports
-	flagDivideBy     *float64 // Ratio to divide sample values
-
-	flagSampleIndex *int  // Sample value to use in reports.
-	flagMean        *bool // Use mean of sample_index over count
-
-	flagTools       *string
-	profileSource   []string
-	profileExecName string
-
-	extraUsage string
-	commands   commands.Commands
-}
-
-func (f *flags) isFormat(format string) bool {
-	if fl := f.flagCommands[format]; fl != nil {
-		return *fl
-	}
-	if fl := f.flagParamCommands[format]; fl != nil {
-		return *fl != ""
-	}
-	return false
-}
-
-// String provides a printable representation for the current set of flags.
-func (f *flags) String(p *profile.Profile) string {
-	var ret string
-
-	if ix := *f.flagSampleIndex; ix != -1 {
-		ret += fmt.Sprintf("  %-25s : %d (%s)\n", "sample_index", ix, p.SampleType[ix].Type)
-	}
-	if ix := *f.flagMean; ix {
-		ret += boolFlagString("mean")
-	}
-	if *f.flagDisplayUnit != "minimum" {
-		ret += stringFlagString("unit", *f.flagDisplayUnit)
-	}
-
-	switch {
-	case *f.flagInteractive:
-		ret += boolFlagString("interactive")
-	}
-	for name, fl := range f.flagCommands {
-		if *fl {
-			ret += boolFlagString(name)
-		}
-	}
-
-	if *f.flagCum {
-		ret += boolFlagString("cum")
-	}
-	if *f.flagCallTree {
-		ret += boolFlagString("call_tree")
-	}
-
-	switch {
-	case *f.flagAddresses:
-		ret += boolFlagString("addresses")
-	case *f.flagLines:
-		ret += boolFlagString("lines")
-	case *f.flagFiles:
-		ret += boolFlagString("files")
-	case *f.flagFunctions:
-		ret += boolFlagString("functions")
-	}
-
-	if *f.flagNodeCount != -1 {
-		ret += intFlagString("nodecount", *f.flagNodeCount)
-	}
-
-	ret += floatFlagString("nodefraction", *f.flagNodeFraction)
-	ret += floatFlagString("edgefraction", *f.flagEdgeFraction)
-
-	if *f.flagFocus != "" {
-		ret += stringFlagString("focus", *f.flagFocus)
-	}
-	if *f.flagIgnore != "" {
-		ret += stringFlagString("ignore", *f.flagIgnore)
-	}
-	if *f.flagHide != "" {
-		ret += stringFlagString("hide", *f.flagHide)
-	}
-
-	if *f.flagTagFocus != "" {
-		ret += stringFlagString("tagfocus", *f.flagTagFocus)
-	}
-	if *f.flagTagIgnore != "" {
-		ret += stringFlagString("tagignore", *f.flagTagIgnore)
-	}
-
-	return ret
-}
-
-func boolFlagString(label string) string {
-	return fmt.Sprintf("  %-25s : true\n", label)
-}
-
-func stringFlagString(label, value string) string {
-	return fmt.Sprintf("  %-25s : %s\n", label, value)
-}
-
-func intFlagString(label string, value int) string {
-	return fmt.Sprintf("  %-25s : %d\n", label, value)
-}
-
-func floatFlagString(label string, value float64) string {
-	return fmt.Sprintf("  %-25s : %f\n", label, value)
-}
-
-// Utility routines to set flag values.
-func newBool(b bool) *bool {
-	return &b
-}
-
-func newString(s string) *string {
-	return &s
-}
-
-func newFloat64(fl float64) *float64 {
-	return &fl
-}
-
-func newInt(i int) *int {
-	return &i
-}
-
-func (f *flags) usage(ui plugin.UI) {
-	var commandMsg []string
-	for name, cmd := range f.commands {
-		if cmd.HasParam {
-			name = name + "=p"
-		}
-		commandMsg = append(commandMsg,
-			fmt.Sprintf("  -%-16s %s", name, cmd.Usage))
-	}
-
-	sort.Strings(commandMsg)
-
-	text := usageMsgHdr + strings.Join(commandMsg, "\n") + "\n" + usageMsg + "\n"
-	if f.extraUsage != "" {
-		text += f.extraUsage + "\n"
-	}
-	text += usageMsgVars
-	ui.Print(text)
-}
-
-func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*flags, error) {
-	f := &flags{
-		flagInteractive:   flag.Bool("interactive", false, "Accepts commands interactively"),
-		flagCommands:      make(map[string]*bool),
-		flagParamCommands: make(map[string]*string),
-
-		// Filename for file-based output formats, stdout by default.
-		flagOutput: flag.String("output", "", "Output filename for file-based outputs "),
-		// Comparisons.
-		flagBase:         flag.String("base", "", "Source for base profile for comparison"),
-		flagDropNegative: flag.Bool("drop_negative", false, "Ignore negative differences"),
-
-		// Data sorting criteria.
-		flagCum: flag.Bool("cum", false, "Sort by cumulative data"),
-		// Graph handling options.
-		flagCallTree: flag.Bool("call_tree", false, "Create a context-sensitive call tree"),
-		// Granularity of output resolution.
-		flagAddresses: flag.Bool("addresses", false, "Report at address level"),
-		flagLines:     flag.Bool("lines", false, "Report at source line level"),
-		flagFiles:     flag.Bool("files", false, "Report at source file level"),
-		flagFunctions: flag.Bool("functions", false, "Report at function level [default]"),
-		// Internal options.
-		flagSymbolize: flag.String("symbolize", "", "Options for profile symbolization"),
-		flagBuildID:   flag.String("buildid", "", "Override build id for first mapping"),
-		// Filtering options
-		flagNodeCount:    flag.Int("nodecount", -1, "Max number of nodes to show"),
-		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"),
-		flagTagFocus:     flag.String("tagfocus", "", "Restrict to samples with tags in range or matched by regexp"),
-		flagTagIgnore:    flag.String("tagignore", "", "Discard samples with tags in range or matched by regexp"),
-		// CPU profile options
-		flagSeconds: flag.Int("seconds", -1, "Length of time for dynamic profiles"),
-		// Heap profile options
-		flagInUseSpace:   flag.Bool("inuse_space", false, "Display in-use memory size"),
-		flagInUseObjects: flag.Bool("inuse_objects", false, "Display in-use object counts"),
-		flagAllocSpace:   flag.Bool("alloc_space", false, "Display allocated memory size"),
-		flagAllocObjects: flag.Bool("alloc_objects", false, "Display allocated object counts"),
-		flagDisplayUnit:  flag.String("unit", "minimum", "Measurement units to display"),
-		flagDivideBy:     flag.Float64("divide_by", 1.0, "Ratio to divide all samples before visualization"),
-		flagSampleIndex:  flag.Int("sample_index", -1, "Index of sample value to report"),
-		flagMean:         flag.Bool("mean", false, "Average sample value over first value (count)"),
-		// Contention profile options
-		flagTotalDelay:  flag.Bool("total_delay", false, "Display total delay at each region"),
-		flagContentions: flag.Bool("contentions", false, "Display number of delays at each region"),
-		flagMeanDelay:   flag.Bool("mean_delay", false, "Display mean delay at each region"),
-		flagTools:       flag.String("tools", os.Getenv("PPROF_TOOLS"), "Path for object tool pathnames"),
-		extraUsage:      flag.ExtraUsage(),
-	}
-
-	// Flags used during command processing
-	interactive := &f.flagInteractive
-	f.commands = commands.PProf(functionCompleter, interactive)
-
-	// Override commands
-	for name, cmd := range overrides {
-		f.commands[name] = cmd
-	}
-
-	for name, cmd := range f.commands {
-		if cmd.HasParam {
-			f.flagParamCommands[name] = flag.String(name, "", "Generate a report in "+name+" format, matching regexp")
-		} else {
-			f.flagCommands[name] = flag.Bool(name, false, "Generate a report in "+name+" format")
-		}
-	}
-
-	args := flag.Parse(func() { f.usage(ui) })
-	if len(args) == 0 {
-		return nil, fmt.Errorf("no profile source specified")
-	}
-
-	f.profileSource = args
-
-	// Instruct legacy heapz parsers to grab historical allocation data,
-	// instead of the default in-use data. Not available with tcmalloc.
-	if *f.flagAllocSpace || *f.flagAllocObjects {
-		profile.LegacyHeapAllocated = true
-	}
-
-	if profileDir := os.Getenv("PPROF_TMPDIR"); profileDir == "" {
-		profileDir = os.Getenv("HOME") + "/pprof"
-		os.Setenv("PPROF_TMPDIR", profileDir)
-		if err := os.MkdirAll(profileDir, 0755); err != nil {
-			return nil, fmt.Errorf("failed to access temp dir %s: %v", profileDir, err)
-		}
-	}
-
-	return f, nil
-}
-
-func processFlags(p *profile.Profile, ui plugin.UI, f *flags) error {
-	flagDis := f.isFormat("disasm")
-	flagPeek := f.isFormat("peek")
-	flagWebList := f.isFormat("weblist")
-	flagList := f.isFormat("list")
-
-	if flagDis || flagWebList {
-		// Collect all samples at address granularity for assembly
-		// listing.
-		f.flagNodeCount = newInt(0)
-		f.flagAddresses = newBool(true)
-		f.flagLines = newBool(false)
-		f.flagFiles = newBool(false)
-		f.flagFunctions = newBool(false)
-	}
-
-	if flagPeek {
-		// Collect all samples at function granularity for peek command
-		f.flagNodeCount = newInt(0)
-		f.flagAddresses = newBool(false)
-		f.flagLines = newBool(false)
-		f.flagFiles = newBool(false)
-		f.flagFunctions = newBool(true)
-	}
-
-	if flagList {
-		// Collect all samples at fileline granularity for source
-		// listing.
-		f.flagNodeCount = newInt(0)
-		f.flagAddresses = newBool(false)
-		f.flagLines = newBool(true)
-		f.flagFiles = newBool(false)
-		f.flagFunctions = newBool(false)
-	}
-
-	if !*f.flagTrim {
-		f.flagNodeCount = newInt(0)
-		f.flagNodeFraction = newFloat64(0)
-		f.flagEdgeFraction = newFloat64(0)
-	}
-
-	if oc := countFlagMap(f.flagCommands, f.flagParamCommands); oc == 0 {
-		f.flagInteractive = newBool(true)
-	} else if oc > 1 {
-		f.usage(ui)
-		return fmt.Errorf("must set at most one output format")
-	}
-
-	// Apply nodecount defaults for non-interactive mode. The
-	// interactive shell will apply defaults for the interactive mode.
-	if *f.flagNodeCount < 0 && !*f.flagInteractive {
-		switch {
-		default:
-			f.flagNodeCount = newInt(80)
-		case f.isFormat("text"):
-			f.flagNodeCount = newInt(0)
-		}
-	}
-
-	// Apply legacy options and diagnose conflicts.
-	if rc := countFlags([]*bool{f.flagAddresses, f.flagLines, f.flagFiles, f.flagFunctions}); rc == 0 {
-		f.flagFunctions = newBool(true)
-	} else if rc > 1 {
-		f.usage(ui)
-		return fmt.Errorf("must set at most one granularity option")
-	}
-
-	var err error
-	si, sm := *f.flagSampleIndex, *f.flagMean || *f.flagMeanDelay
-	si, err = sampleIndex(p, &f.flagTotalDelay, si, 1, "delay", "-total_delay", err)
-	si, err = sampleIndex(p, &f.flagMeanDelay, si, 1, "delay", "-mean_delay", err)
-	si, err = sampleIndex(p, &f.flagContentions, si, 0, "contentions", "-contentions", err)
-
-	si, err = sampleIndex(p, &f.flagInUseSpace, si, 1, "inuse_space", "-inuse_space", err)
-	si, err = sampleIndex(p, &f.flagInUseObjects, si, 0, "inuse_objects", "-inuse_objects", err)
-	si, err = sampleIndex(p, &f.flagAllocSpace, si, 1, "alloc_space", "-alloc_space", err)
-	si, err = sampleIndex(p, &f.flagAllocObjects, si, 0, "alloc_objects", "-alloc_objects", err)
-
-	if si == -1 {
-		// Use last value if none is requested.
-		si = len(p.SampleType) - 1
-	} else if si < 0 || si >= len(p.SampleType) {
-		err = fmt.Errorf("sample_index value %d out of range [0..%d]", si, len(p.SampleType)-1)
-	}
-
-	if err != nil {
-		f.usage(ui)
-		return err
-	}
-	f.flagSampleIndex, f.flagMean = newInt(si), newBool(sm)
-	return nil
-}
-
-func sampleIndex(p *profile.Profile, flag **bool,
-	sampleIndex int,
-	newSampleIndex int,
-	sampleType, option string,
-	err error) (int, error) {
-	if err != nil || !**flag {
-		return sampleIndex, err
-	}
-	*flag = newBool(false)
-	if sampleIndex != -1 {
-		return 0, fmt.Errorf("set at most one sample value selection option")
-	}
-	if newSampleIndex >= len(p.SampleType) ||
-		p.SampleType[newSampleIndex].Type != sampleType {
-		return 0, fmt.Errorf("option %s not valid for this profile", option)
-	}
-	return newSampleIndex, nil
-}
-
-func countFlags(bs []*bool) int {
-	var c int
-	for _, b := range bs {
-		if *b {
-			c++
-		}
-	}
-	return c
-}
-
-func countFlagMap(bms map[string]*bool, bmrxs map[string]*string) int {
-	var c int
-	for _, b := range bms {
-		if *b {
-			c++
-		}
-	}
-	for _, s := range bmrxs {
-		if *s != "" {
-			c++
-		}
-	}
-	return c
-}
-
-var usageMsgHdr = "usage: pprof [options] [binary] <profile source> ...\n" +
-	"Output format (only set one):\n"
-
-var usageMsg = "Output file parameters (for file-based output formats):\n" +
-	"  -output=f         Generate output on file f (stdout by default)\n" +
-	"Output granularity (only set one):\n" +
-	"  -functions        Report at function level [default]\n" +
-	"  -files            Report at source file level\n" +
-	"  -lines            Report at source line level\n" +
-	"  -addresses        Report at address level\n" +
-	"Comparison options:\n" +
-	"  -base <profile>   Show delta from this profile\n" +
-	"  -drop_negative    Ignore negative differences\n" +
-	"Sorting options:\n" +
-	"  -cum              Sort by cumulative data\n\n" +
-	"Dynamic profile options:\n" +
-	"  -seconds=N        Length of time for dynamic profiles\n" +
-	"Profile trimming options:\n" +
-	"  -nodecount=N      Max number of nodes to show\n" +
-	"  -nodefraction=f   Hide nodes below <f>*total\n" +
-	"  -edgefraction=f   Hide edges below <f>*total\n" +
-	"Sample value selection option (by index):\n" +
-	"  -sample_index      Index of sample value to display\n" +
-	"  -mean              Average sample value over first value\n" +
-	"Sample value selection option (for heap profiles):\n" +
-	"  -inuse_space      Display in-use memory size\n" +
-	"  -inuse_objects    Display in-use object counts\n" +
-	"  -alloc_space      Display allocated memory size\n" +
-	"  -alloc_objects    Display allocated object counts\n" +
-	"Sample value selection option (for contention profiles):\n" +
-	"  -total_delay      Display total delay at each region\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" +
-	"                    Restrict to samples with numeric tags in range (eg \"32kb:1mb\")\n" +
-	"  -tagignore=r      Discard samples tagged with key:value matching regexp\n" +
-	"                    Avoid samples with numeric tags in range (eg \"1mb:\")\n" +
-	"Miscellaneous:\n" +
-	"  -call_tree        Generate a context-sensitive call tree\n" +
-	"  -unit=u           Convert all samples to unit u for display\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 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" +
-	"                      finds binaries by $name and $buildid/$name"
-
-func aggregate(prof *profile.Profile, f *flags) error {
-	switch {
-	case f.isFormat("proto"), f.isFormat("raw"):
-		// No aggregation for raw profiles.
-	case f.isFormat("callgrind"):
-		// Aggregate to file/line for callgrind.
-		fallthrough
-	case *f.flagLines:
-		return prof.Aggregate(true, true, true, true, false)
-	case *f.flagFiles:
-		return prof.Aggregate(true, false, true, false, false)
-	case *f.flagFunctions:
-		return prof.Aggregate(true, true, false, false, false)
-	case f.isFormat("weblist"), f.isFormat("disasm"):
-		return prof.Aggregate(false, true, true, true, true)
-	}
-	return nil
-}
-
-// parseOptions parses the options into report.Options
-// Returns a function to postprocess the report after generation.
-func parseOptions(f *flags) (o *report.Options, p commands.PostProcessor, err error) {
-
-	if *f.flagDivideBy == 0 {
-		return nil, nil, fmt.Errorf("zero divisor specified")
-	}
-
-	o = &report.Options{
-		CumSort:        *f.flagCum,
-		CallTree:       *f.flagCallTree,
-		PrintAddresses: *f.flagAddresses,
-		DropNegative:   *f.flagDropNegative,
-		Ratio:          1 / *f.flagDivideBy,
-
-		NodeCount:    *f.flagNodeCount,
-		NodeFraction: *f.flagNodeFraction,
-		EdgeFraction: *f.flagEdgeFraction,
-		OutputUnit:   *f.flagDisplayUnit,
-	}
-
-	for cmd, b := range f.flagCommands {
-		if *b {
-			pcmd := f.commands[cmd]
-			o.OutputFormat = pcmd.Format
-			return o, pcmd.PostProcess, nil
-		}
-	}
-
-	for cmd, rx := range f.flagParamCommands {
-		if *rx != "" {
-			pcmd := f.commands[cmd]
-			if o.Symbol, err = regexp.Compile(*rx); err != nil {
-				return nil, nil, fmt.Errorf("parsing -%s regexp: %v", cmd, err)
-			}
-			o.OutputFormat = pcmd.Format
-			return o, pcmd.PostProcess, nil
-		}
-	}
-
-	return nil, nil, fmt.Errorf("no output format selected")
-}
-
-type sampleValueFunc func(*profile.Sample) int64
-
-// sampleFormat returns a function to extract values out of a profile.Sample,
-// and the type/units of those values.
-func sampleFormat(p *profile.Profile, f *flags) (sampleValueFunc, string, string) {
-	valueIndex := *f.flagSampleIndex
-
-	if *f.flagMean {
-		return meanExtractor(valueIndex), "mean_" + p.SampleType[valueIndex].Type, p.SampleType[valueIndex].Unit
-	}
-
-	return valueExtractor(valueIndex), p.SampleType[valueIndex].Type, p.SampleType[valueIndex].Unit
-}
-
-func valueExtractor(ix int) sampleValueFunc {
-	return func(s *profile.Sample) int64 {
-		return s.Value[ix]
-	}
-}
-
-func meanExtractor(ix int) sampleValueFunc {
-	return func(s *profile.Sample) int64 {
-		if s.Value[0] == 0 {
-			return 0
-		}
-		return s.Value[ix] / s.Value[0]
-	}
-}
-
-func generate(interactive bool, prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, f *flags) error {
-	o, postProcess, err := parseOptions(f)
-	if err != nil {
-		return err
-	}
-
-	var w io.Writer
-	if *f.flagOutput == "" {
-		w = os.Stdout
-	} else {
-		ui.PrintErr("Generating report in ", *f.flagOutput)
-		outputFile, err := os.Create(*f.flagOutput)
-		if err != nil {
-			return err
-		}
-		defer outputFile.Close()
-		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)
-
-	// Do not apply filters if we're just generating a proto, so we
-	// still have all the data.
-	if o.OutputFormat != report.Proto {
-		// Delay applying focus/ignore until after creating the report so
-		// the report reflects the total number of samples.
-		if err := preprocess(prof, ui, f); err != nil {
-			return err
-		}
-	}
-
-	if postProcess == nil {
-		return report.Generate(w, rpt, obj)
-	}
-
-	var dot bytes.Buffer
-	if err = report.Generate(&dot, rpt, obj); err != nil {
-		return err
-	}
-
-	return postProcess(&dot, w, ui)
-}
diff --git a/src/cmd/pprof/internal/driver/interactive.go b/src/cmd/pprof/internal/driver/interactive.go
deleted file mode 100644
index 13009bf..0000000
--- a/src/cmd/pprof/internal/driver/interactive.go
+++ /dev/null
@@ -1,492 +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 driver
-
-import (
-	"fmt"
-	"io"
-	"regexp"
-	"sort"
-	"strconv"
-	"strings"
-
-	"cmd/pprof/internal/commands"
-	"cmd/pprof/internal/plugin"
-	"cmd/pprof/internal/profile"
-)
-
-var profileFunctionNames = []string{}
-
-// functionCompleter replaces provided substring with a function
-// name retrieved from a profile if a single match exists. Otherwise,
-// it returns unchanged substring. It defaults to no-op if the profile
-// is not specified.
-func functionCompleter(substring string) string {
-	found := ""
-	for _, fName := range profileFunctionNames {
-		if strings.Contains(fName, substring) {
-			if found != "" {
-				return substring
-			}
-			found = fName
-		}
-	}
-	if found != "" {
-		return found
-	}
-	return substring
-}
-
-// updateAutoComplete enhances autocompletion with information that can be
-// retrieved from the profile
-func updateAutoComplete(p *profile.Profile) {
-	profileFunctionNames = nil // remove function names retrieved previously
-	for _, fn := range p.Function {
-		profileFunctionNames = append(profileFunctionNames, fn.Name)
-	}
-}
-
-// splitCommand splits the command line input into tokens separated by
-// spaces. Takes care to separate commands of the form 'top10' into
-// two tokens: 'top' and '10'
-func splitCommand(input string) []string {
-	fields := strings.Fields(input)
-	if num := strings.IndexAny(fields[0], "0123456789"); num != -1 {
-		inputNumber := fields[0][num:]
-		fields[0] = fields[0][:num]
-		fields = append([]string{fields[0], inputNumber}, fields[1:]...)
-	}
-	return fields
-}
-
-// interactive displays a prompt and reads commands for profile
-// manipulation/visualization.
-func interactive(p *profile.Profile, obj plugin.ObjTool, ui plugin.UI, f *flags) error {
-	updateAutoComplete(p)
-
-	// Enter command processing loop.
-	ui.Print("Entering interactive mode (type \"help\" for commands)")
-	ui.SetAutoComplete(commands.NewCompleter(f.commands))
-
-	for {
-		input, err := readCommand(p, ui, f)
-		if err != nil {
-			if err != io.EOF {
-				return err
-			}
-			if input == "" {
-				return nil
-			}
-		}
-		// Process simple commands.
-		switch input {
-		case "":
-			continue
-		case ":":
-			f.flagFocus = newString("")
-			f.flagIgnore = newString("")
-			f.flagTagFocus = newString("")
-			f.flagTagIgnore = newString("")
-			f.flagHide = newString("")
-			continue
-		}
-
-		fields := splitCommand(input)
-		// Process report generation commands.
-		if _, ok := f.commands[fields[0]]; ok {
-			if err := generateReport(p, fields, obj, ui, f); err != nil {
-				if err == io.EOF {
-					return nil
-				}
-				ui.PrintErr(err)
-			}
-			continue
-		}
-
-		switch cmd := fields[0]; cmd {
-		case "help":
-			commandHelp(fields, ui, f)
-			continue
-		case "exit", "quit":
-			return nil
-		}
-
-		// Process option settings.
-		if of, err := optFlags(p, input, f); err == nil {
-			f = of
-		} else {
-			ui.PrintErr("Error: ", err.Error())
-		}
-	}
-}
-
-func generateReport(p *profile.Profile, cmd []string, obj plugin.ObjTool, ui plugin.UI, f *flags) error {
-	prof := p.Copy()
-
-	cf, err := cmdFlags(prof, cmd, ui, f)
-	if err != nil {
-		return err
-	}
-
-	return generate(true, prof, obj, ui, cf)
-}
-
-// validateRegex checks if a string is a valid regular expression.
-func validateRegex(v string) error {
-	_, err := regexp.Compile(v)
-	return err
-}
-
-// readCommand prompts for and reads the next command.
-func readCommand(p *profile.Profile, ui plugin.UI, f *flags) (string, error) {
-	//ui.Print("Options:\n", f.String(p))
-	s, err := ui.ReadLine()
-	return strings.TrimSpace(s), err
-}
-
-func commandHelp(_ []string, ui plugin.UI, f *flags) error {
-	help := `
- Commands:
-   cmd [n] [--cum] [focus_regex]* [-ignore_regex]*
-       Produce a text report with the top n entries.
-       Include samples matching focus_regex, and exclude ignore_regex.
-       Add --cum to sort using cumulative data.
-       Available commands:
-`
-	var commands []string
-	for name, cmd := range f.commands {
-		commands = append(commands, fmt.Sprintf("         %-12s %s", name, cmd.Usage))
-	}
-	sort.Strings(commands)
-
-	help = help + strings.Join(commands, "\n") + `
-   peek func_regex
-       Display callers and callees of functions matching func_regex.
-
-   dot [n] [focus_regex]* [-ignore_regex]* [>file]
-       Produce an annotated callgraph with the top n entries.
-       Include samples matching focus_regex, and exclude ignore_regex.
-       For other outputs, replace dot with:
-       - Graphic formats: dot, svg, pdf, ps, gif, png (use > to name output file)
-       - Graph viewer:    gv, web, evince, eog
-
-   callgrind [n] [focus_regex]* [-ignore_regex]* [>file]
-       Produce a file in callgrind-compatible format.
-       Include samples matching focus_regex, and exclude ignore_regex.
-
-   weblist func_regex [-ignore_regex]*
-       Show annotated source with interspersed assembly in a web browser.
-
-   list func_regex [-ignore_regex]*
-       Print source for routines matching func_regex, and exclude ignore_regex.
-
-   disasm func_regex [-ignore_regex]*
-       Disassemble routines matching func_regex, and exclude ignore_regex.
-
-   tags tag_regex [-ignore_regex]*
-       List tags with key:value matching tag_regex and exclude ignore_regex.
-
-   quit/exit/^D
- 	     Exit pprof.
-
-   option=value
-       The following options can be set individually:
-           cum/flat:           Sort entries based on cumulative or flat data
-           call_tree:          Build context-sensitive call trees
-           nodecount:          Max number of entries to display
-           nodefraction:       Min frequency ratio of nodes to display
-           edgefraction:       Min frequency ratio of edges to display
-           focus/ignore:       Regexp to include/exclude samples by name/file
-           tagfocus/tagignore: Regexp or value range to filter samples by tag
-                               eg "1mb", "1mb:2mb", ":64kb"
-
-           functions:          Level of aggregation for sample data
-           files:
-           lines:
-           addresses:
-
-           unit:               Measurement unit to use on reports
-
-           Sample value selection by index:
-            sample_index:      Index of sample value to display
-            mean:              Average sample value over first value
-
-           Sample value selection by name:
-            alloc_space        for heap profiles
-            alloc_objects
-            inuse_space
-            inuse_objects
-
-            total_delay        for contention profiles
-            mean_delay
-            contentions
-
-   :   Clear focus/ignore/hide/tagfocus/tagignore`
-
-	ui.Print(help)
-	return nil
-}
-
-// cmdFlags parses the options of an interactive command and returns
-// an updated flags object.
-func cmdFlags(prof *profile.Profile, input []string, ui plugin.UI, f *flags) (*flags, error) {
-	cf := *f
-
-	var focus, ignore string
-	output := *cf.flagOutput
-	nodeCount := *cf.flagNodeCount
-	cmd := input[0]
-
-	// Update output flags based on parameters.
-	tokens := input[1:]
-	for p := 0; p < len(tokens); p++ {
-		t := tokens[p]
-		if t == "" {
-			continue
-		}
-		if c, err := strconv.ParseInt(t, 10, 32); err == nil {
-			nodeCount = int(c)
-			continue
-		}
-		switch t[0] {
-		case '>':
-			if len(t) > 1 {
-				output = t[1:]
-				continue
-			}
-			// find next token
-			for p++; p < len(tokens); p++ {
-				if tokens[p] != "" {
-					output = tokens[p]
-					break
-				}
-			}
-		case '-':
-			if t == "--cum" || t == "-cum" {
-				cf.flagCum = newBool(true)
-				continue
-			}
-			ignore = catRegex(ignore, t[1:])
-		default:
-			focus = catRegex(focus, t)
-		}
-	}
-
-	pcmd, ok := f.commands[cmd]
-	if !ok {
-		return nil, fmt.Errorf("Unexpected parse failure: %v", input)
-	}
-	// Reset flags
-	cf.flagCommands = make(map[string]*bool)
-	cf.flagParamCommands = make(map[string]*string)
-
-	if !pcmd.HasParam {
-		cf.flagCommands[cmd] = newBool(true)
-
-		switch cmd {
-		case "tags":
-			cf.flagTagFocus = newString(focus)
-			cf.flagTagIgnore = newString(ignore)
-		default:
-			cf.flagFocus = newString(catRegex(*cf.flagFocus, focus))
-			cf.flagIgnore = newString(catRegex(*cf.flagIgnore, ignore))
-		}
-	} else {
-		if focus == "" {
-			focus = "."
-		}
-		cf.flagParamCommands[cmd] = newString(focus)
-		cf.flagIgnore = newString(catRegex(*cf.flagIgnore, ignore))
-	}
-
-	if nodeCount < 0 {
-		switch cmd {
-		case "text", "top":
-			// Default text/top to 10 nodes on interactive mode
-			nodeCount = 10
-		default:
-			nodeCount = 80
-		}
-	}
-
-	cf.flagNodeCount = newInt(nodeCount)
-	cf.flagOutput = newString(output)
-
-	// Do regular flags processing
-	if err := processFlags(prof, ui, &cf); err != nil {
-		cf.usage(ui)
-		return nil, err
-	}
-
-	return &cf, nil
-}
-
-func catRegex(a, b string) string {
-	if a == "" {
-		return b
-	}
-	if b == "" {
-		return a
-	}
-	return a + "|" + b
-}
-
-// optFlags parses an interactive option setting and returns
-// an updated flags object.
-func optFlags(p *profile.Profile, input string, f *flags) (*flags, error) {
-	inputs := strings.SplitN(input, "=", 2)
-	option := strings.ToLower(strings.TrimSpace(inputs[0]))
-	var value string
-	if len(inputs) == 2 {
-		value = strings.TrimSpace(inputs[1])
-	}
-
-	of := *f
-
-	var err error
-	var bv bool
-	var uv uint64
-	var fv float64
-
-	switch option {
-	case "cum":
-		if bv, err = parseBool(value); err != nil {
-			return nil, err
-		}
-		of.flagCum = newBool(bv)
-	case "flat":
-		if bv, err = parseBool(value); err != nil {
-			return nil, err
-		}
-		of.flagCum = newBool(!bv)
-	case "call_tree":
-		if bv, err = parseBool(value); err != nil {
-			return nil, err
-		}
-		of.flagCallTree = newBool(bv)
-	case "unit":
-		of.flagDisplayUnit = newString(value)
-	case "sample_index":
-		if uv, err = strconv.ParseUint(value, 10, 32); err != nil {
-			return nil, err
-		}
-		if ix := int(uv); ix < 0 || ix >= len(p.SampleType) {
-			return nil, fmt.Errorf("sample_index out of range [0..%d]", len(p.SampleType)-1)
-		}
-		of.flagSampleIndex = newInt(int(uv))
-	case "mean":
-		if bv, err = parseBool(value); err != nil {
-			return nil, err
-		}
-		of.flagMean = newBool(bv)
-	case "nodecount":
-		if uv, err = strconv.ParseUint(value, 10, 32); err != nil {
-			return nil, err
-		}
-		of.flagNodeCount = newInt(int(uv))
-	case "nodefraction":
-		if fv, err = strconv.ParseFloat(value, 64); err != nil {
-			return nil, err
-		}
-		of.flagNodeFraction = newFloat64(fv)
-	case "edgefraction":
-		if fv, err = strconv.ParseFloat(value, 64); err != nil {
-			return nil, err
-		}
-		of.flagEdgeFraction = newFloat64(fv)
-	case "focus":
-		if err = validateRegex(value); err != nil {
-			return nil, err
-		}
-		of.flagFocus = newString(value)
-	case "ignore":
-		if err = validateRegex(value); err != nil {
-			return nil, err
-		}
-		of.flagIgnore = newString(value)
-	case "tagfocus":
-		if err = validateRegex(value); err != nil {
-			return nil, err
-		}
-		of.flagTagFocus = newString(value)
-	case "tagignore":
-		if err = validateRegex(value); err != nil {
-			return nil, err
-		}
-		of.flagTagIgnore = newString(value)
-	case "hide":
-		if err = validateRegex(value); err != nil {
-			return nil, err
-		}
-		of.flagHide = newString(value)
-	case "addresses", "files", "lines", "functions":
-		if bv, err = parseBool(value); err != nil {
-			return nil, err
-		}
-		if !bv {
-			return nil, fmt.Errorf("select one of addresses/files/lines/functions")
-		}
-		setGranularityToggle(option, &of)
-	default:
-		if ix := findSampleIndex(p, "", option); ix >= 0 {
-			of.flagSampleIndex = newInt(ix)
-		} else if ix := findSampleIndex(p, "total_", option); ix >= 0 {
-			of.flagSampleIndex = newInt(ix)
-			of.flagMean = newBool(false)
-		} else if ix := findSampleIndex(p, "mean_", option); ix >= 1 {
-			of.flagSampleIndex = newInt(ix)
-			of.flagMean = newBool(true)
-		} else {
-			return nil, fmt.Errorf("unrecognized command: %s", input)
-		}
-	}
-	return &of, nil
-}
-
-// parseBool parses a string as a boolean value.
-func parseBool(v string) (bool, error) {
-	switch strings.ToLower(v) {
-	case "true", "t", "yes", "y", "1", "":
-		return true, nil
-	case "false", "f", "no", "n", "0":
-		return false, nil
-	}
-	return false, fmt.Errorf(`illegal input "%s" for bool value`, v)
-}
-
-func findSampleIndex(p *profile.Profile, prefix, sampleType string) int {
-	if !strings.HasPrefix(sampleType, prefix) {
-		return -1
-	}
-	sampleType = strings.TrimPrefix(sampleType, prefix)
-	for i, r := range p.SampleType {
-		if r.Type == sampleType {
-			return i
-		}
-	}
-	return -1
-}
-
-// setGranularityToggle manages the set of granularity options. These
-// operate as a toggle; turning one on turns the others off.
-func setGranularityToggle(o string, fl *flags) {
-	t, f := newBool(true), newBool(false)
-	fl.flagFunctions = f
-	fl.flagFiles = f
-	fl.flagLines = f
-	fl.flagAddresses = f
-	switch o {
-	case "functions":
-		fl.flagFunctions = t
-	case "files":
-		fl.flagFiles = t
-	case "lines":
-		fl.flagLines = t
-	case "addresses":
-		fl.flagAddresses = t
-	default:
-		panic(fmt.Errorf("unexpected option %s", o))
-	}
-}
diff --git a/src/cmd/pprof/internal/fetch/fetch.go b/src/cmd/pprof/internal/fetch/fetch.go
deleted file mode 100644
index ec4a638..0000000
--- a/src/cmd/pprof/internal/fetch/fetch.go
+++ /dev/null
@@ -1,82 +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 fetch provides an extensible mechanism to fetch a profile
-// from a data source.
-package fetch
-
-import (
-	"fmt"
-	"io"
-	"io/ioutil"
-	"net/http"
-	"net/url"
-	"os"
-	"strings"
-	"time"
-
-	"cmd/pprof/internal/plugin"
-	"cmd/pprof/internal/profile"
-)
-
-// FetchProfile reads from a data source (network, file) and generates a
-// profile.
-func FetchProfile(source string, timeout time.Duration) (*profile.Profile, error) {
-	return Fetcher(source, timeout, plugin.StandardUI())
-}
-
-// Fetcher is the plugin.Fetcher version of FetchProfile.
-func Fetcher(source string, timeout time.Duration, ui plugin.UI) (*profile.Profile, error) {
-	var f io.ReadCloser
-	var err error
-
-	url, err := url.Parse(source)
-	if err == nil && url.Host != "" {
-		f, err = FetchURL(source, timeout)
-	} else {
-		f, err = os.Open(source)
-	}
-	if err != nil {
-		return nil, err
-	}
-	defer f.Close()
-	return profile.Parse(f)
-}
-
-// FetchURL fetches a profile from a URL using HTTP.
-func FetchURL(source string, timeout time.Duration) (io.ReadCloser, error) {
-	resp, err := httpGet(source, timeout)
-	if err != nil {
-		return nil, fmt.Errorf("http fetch %s: %v", source, err)
-	}
-	if resp.StatusCode != http.StatusOK {
-		return nil, fmt.Errorf("server response: %s", resp.Status)
-	}
-
-	return resp.Body, nil
-}
-
-// PostURL issues a POST to a URL over HTTP.
-func PostURL(source, post string) ([]byte, error) {
-	resp, err := http.Post(source, "application/octet-stream", strings.NewReader(post))
-	if err != nil {
-		return nil, fmt.Errorf("http post %s: %v", source, err)
-	}
-	if resp.StatusCode != http.StatusOK {
-		return nil, fmt.Errorf("server response: %s", resp.Status)
-	}
-	defer resp.Body.Close()
-	return ioutil.ReadAll(resp.Body)
-}
-
-// httpGet is a wrapper around http.Get; it is defined as a variable
-// so it can be redefined during for testing.
-var httpGet = func(url string, timeout time.Duration) (*http.Response, error) {
-	client := &http.Client{
-		Transport: &http.Transport{
-			ResponseHeaderTimeout: timeout + 5*time.Second,
-		},
-	}
-	return client.Get(url)
-}
diff --git a/src/cmd/pprof/internal/plugin/plugin.go b/src/cmd/pprof/internal/plugin/plugin.go
deleted file mode 100644
index a22ec5f..0000000
--- a/src/cmd/pprof/internal/plugin/plugin.go
+++ /dev/null
@@ -1,213 +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 plugin defines the plugin implementations that the main pprof driver requires.
-package plugin
-
-import (
-	"bufio"
-	"fmt"
-	"os"
-	"regexp"
-	"strings"
-	"time"
-
-	"cmd/pprof/internal/profile"
-)
-
-// A FlagSet creates and parses command-line flags.
-// It is similar to the standard flag.FlagSet.
-type FlagSet interface {
-	// Bool, Int, Float64, and String define new flags,
-	// like the functions of the same name in package flag.
-	Bool(name string, def bool, usage string) *bool
-	Int(name string, def int, usage string) *int
-	Float64(name string, def float64, usage string) *float64
-	String(name string, def string, usage string) *string
-
-	// ExtraUsage returns any additional text that should be
-	// printed after the standard usage message.
-	// The typical use of ExtraUsage is to show any custom flags
-	// defined by the specific pprof plugins being used.
-	ExtraUsage() string
-
-	// Parse initializes the flags with their values for this run
-	// and returns the non-flag command line arguments.
-	// If an unknown flag is encountered or there are no arguments,
-	// Parse should call usage and return nil.
-	Parse(usage func()) []string
-}
-
-// An ObjTool inspects shared libraries and executable files.
-type ObjTool interface {
-	// Open opens the named object file.
-	// If the object is a shared library, start is the address where
-	// it is mapped into memory in the address space being inspected.
-	Open(file string, start uint64) (ObjFile, error)
-
-	// Demangle translates a batch of symbol names from mangled
-	// form to human-readable form.
-	Demangle(names []string) (map[string]string, error)
-
-	// Disasm disassembles the named object file, starting at
-	// the start address and stopping at (before) the end address.
-	Disasm(file string, start, end uint64) ([]Inst, error)
-
-	// SetConfig configures the tool.
-	// The implementation defines the meaning of the string
-	// and can ignore it entirely.
-	SetConfig(config string)
-}
-
-// NoObjTool returns a trivial implementation of the ObjTool interface.
-// Open returns an error indicating that the requested file does not exist.
-// Demangle returns an empty map and a nil error.
-// Disasm returns an error.
-// SetConfig is a no-op.
-func NoObjTool() ObjTool {
-	return noObjTool{}
-}
-
-type noObjTool struct{}
-
-func (noObjTool) Open(file string, start uint64) (ObjFile, error) {
-	return nil, &os.PathError{Op: "open", Path: file, Err: os.ErrNotExist}
-}
-
-func (noObjTool) Demangle(name []string) (map[string]string, error) {
-	return make(map[string]string), nil
-}
-
-func (noObjTool) Disasm(file string, start, end uint64) ([]Inst, error) {
-	return nil, fmt.Errorf("disassembly not supported")
-}
-
-func (noObjTool) SetConfig(config string) {
-}
-
-// An ObjFile is a single object file: a shared library or executable.
-type ObjFile interface {
-	// Name returns the underlyinf file name, if available
-	Name() string
-
-	// Base returns the base address to use when looking up symbols in the file.
-	Base() uint64
-
-	// BuildID returns the GNU build ID of the file, or an empty string.
-	BuildID() string
-
-	// SourceLine reports the source line information for a given
-	// address in the file. Due to inlining, the source line information
-	// is in general a list of positions representing a call stack,
-	// with the leaf function first.
-	SourceLine(addr uint64) ([]Frame, error)
-
-	// Symbols returns a list of symbols in the object file.
-	// If r is not nil, Symbols restricts the list to symbols
-	// with names matching the regular expression.
-	// If addr is not zero, Symbols restricts the list to symbols
-	// containing that address.
-	Symbols(r *regexp.Regexp, addr uint64) ([]*Sym, error)
-
-	// Close closes the file, releasing associated resources.
-	Close() error
-}
-
-// A Frame describes a single line in a source file.
-type Frame struct {
-	Func string // name of function
-	File string // source file name
-	Line int    // line in file
-}
-
-// A Sym describes a single symbol in an object file.
-type Sym struct {
-	Name  []string // names of symbol (many if symbol was dedup'ed)
-	File  string   // object file containing symbol
-	Start uint64   // start virtual address
-	End   uint64   // virtual address of last byte in sym (Start+size-1)
-}
-
-// An Inst is a single instruction in an assembly listing.
-type Inst struct {
-	Addr uint64 // virtual address of instruction
-	Text string // instruction text
-	File string // source file
-	Line int    // source line
-}
-
-// A UI manages user interactions.
-type UI interface {
-	// Read returns a line of text (a command) read from the user.
-	ReadLine() (string, error)
-
-	// Print shows a message to the user.
-	// It formats the text as fmt.Print would and adds a final \n if not already present.
-	// For line-based UI, Print writes to standard error.
-	// (Standard output is reserved for report data.)
-	Print(...interface{})
-
-	// PrintErr shows an error message to the user.
-	// It formats the text as fmt.Print would and adds a final \n if not already present.
-	// For line-based UI, PrintErr writes to standard error.
-	PrintErr(...interface{})
-
-	// IsTerminal returns whether the UI is known to be tied to an
-	// interactive terminal (as opposed to being redirected to a file).
-	IsTerminal() bool
-
-	// SetAutoComplete instructs the UI to call complete(cmd) to obtain
-	// the auto-completion of cmd, if the UI supports auto-completion at all.
-	SetAutoComplete(complete func(string) string)
-}
-
-// StandardUI returns a UI that reads from standard input,
-// prints messages to standard output,
-// prints errors to standard error, and doesn't use auto-completion.
-func StandardUI() UI {
-	return &stdUI{r: bufio.NewReader(os.Stdin)}
-}
-
-type stdUI struct {
-	r *bufio.Reader
-}
-
-func (ui *stdUI) ReadLine() (string, error) {
-	os.Stdout.WriteString("(pprof) ")
-	return ui.r.ReadString('\n')
-}
-
-func (ui *stdUI) Print(args ...interface{}) {
-	ui.fprint(os.Stderr, args)
-}
-
-func (ui *stdUI) PrintErr(args ...interface{}) {
-	ui.fprint(os.Stderr, args)
-}
-
-func (ui *stdUI) IsTerminal() bool {
-	return false
-}
-
-func (ui *stdUI) SetAutoComplete(func(string) string) {
-}
-
-func (ui *stdUI) fprint(f *os.File, args []interface{}) {
-	text := fmt.Sprint(args...)
-	if !strings.HasSuffix(text, "\n") {
-		text += "\n"
-	}
-	f.WriteString(text)
-}
-
-// A Fetcher reads and returns the profile named by src.
-// It gives up after the given timeout, unless src contains a timeout override
-// (as defined by the implementation).
-// It can print messages to ui.
-type Fetcher func(src string, timeout time.Duration, ui UI) (*profile.Profile, error)
-
-// A Symbolizer annotates a profile with symbol information.
-// The profile was fetch from src.
-// The meaning of mode is defined by the implementation.
-type Symbolizer func(mode, src string, prof *profile.Profile, obj ObjTool, ui UI) error
diff --git a/src/cmd/pprof/internal/profile/encode.go b/src/cmd/pprof/internal/profile/encode.go
deleted file mode 100644
index 9e66998..0000000
--- a/src/cmd/pprof/internal/profile/encode.go
+++ /dev/null
@@ -1,470 +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 profile
-
-import (
-	"errors"
-	"fmt"
-	"sort"
-)
-
-func (p *Profile) decoder() []decoder {
-	return profileDecoder
-}
-
-// preEncode populates the unexported fields to be used by encode
-// (with suffix X) from the corresponding exported fields.  The
-// exported fields are cleared up to facilitate testing.
-func (p *Profile) preEncode() {
-	strings := make(map[string]int)
-	addString(strings, "")
-
-	for _, st := range p.SampleType {
-		st.typeX = addString(strings, st.Type)
-		st.unitX = addString(strings, st.Unit)
-	}
-
-	for _, s := range p.Sample {
-		s.labelX = nil
-		var keys []string
-		for k := range s.Label {
-			keys = append(keys, k)
-		}
-		sort.Strings(keys)
-		for _, k := range keys {
-			vs := s.Label[k]
-			for _, v := range vs {
-				s.labelX = append(s.labelX,
-					Label{
-						keyX: addString(strings, k),
-						strX: addString(strings, v),
-					},
-				)
-			}
-		}
-		var numKeys []string
-		for k := range s.NumLabel {
-			numKeys = append(numKeys, k)
-		}
-		sort.Strings(numKeys)
-		for _, k := range numKeys {
-			vs := s.NumLabel[k]
-			for _, v := range vs {
-				s.labelX = append(s.labelX,
-					Label{
-						keyX: addString(strings, k),
-						numX: v,
-					},
-				)
-			}
-		}
-		s.locationIDX = nil
-		for _, l := range s.Location {
-			s.locationIDX = append(s.locationIDX, l.ID)
-		}
-	}
-
-	for _, m := range p.Mapping {
-		m.fileX = addString(strings, m.File)
-		m.buildIDX = addString(strings, m.BuildID)
-	}
-
-	for _, l := range p.Location {
-		for i, ln := range l.Line {
-			if ln.Function != nil {
-				l.Line[i].functionIDX = ln.Function.ID
-			} else {
-				l.Line[i].functionIDX = 0
-			}
-		}
-		if l.Mapping != nil {
-			l.mappingIDX = l.Mapping.ID
-		} else {
-			l.mappingIDX = 0
-		}
-	}
-	for _, f := range p.Function {
-		f.nameX = addString(strings, f.Name)
-		f.systemNameX = addString(strings, f.SystemName)
-		f.filenameX = addString(strings, f.Filename)
-	}
-
-	p.dropFramesX = addString(strings, p.DropFrames)
-	p.keepFramesX = addString(strings, p.KeepFrames)
-
-	if pt := p.PeriodType; pt != nil {
-		pt.typeX = addString(strings, pt.Type)
-		pt.unitX = addString(strings, pt.Unit)
-	}
-
-	p.stringTable = make([]string, len(strings))
-	for s, i := range strings {
-		p.stringTable[i] = s
-	}
-}
-
-func (p *Profile) encode(b *buffer) {
-	for _, x := range p.SampleType {
-		encodeMessage(b, 1, x)
-	}
-	for _, x := range p.Sample {
-		encodeMessage(b, 2, x)
-	}
-	for _, x := range p.Mapping {
-		encodeMessage(b, 3, x)
-	}
-	for _, x := range p.Location {
-		encodeMessage(b, 4, x)
-	}
-	for _, x := range p.Function {
-		encodeMessage(b, 5, x)
-	}
-	encodeStrings(b, 6, p.stringTable)
-	encodeInt64Opt(b, 7, p.dropFramesX)
-	encodeInt64Opt(b, 8, p.keepFramesX)
-	encodeInt64Opt(b, 9, p.TimeNanos)
-	encodeInt64Opt(b, 10, p.DurationNanos)
-	if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
-		encodeMessage(b, 11, p.PeriodType)
-	}
-	encodeInt64Opt(b, 12, p.Period)
-}
-
-var profileDecoder = []decoder{
-	nil, // 0
-	// repeated ValueType sample_type = 1
-	func(b *buffer, m message) error {
-		x := new(ValueType)
-		pp := m.(*Profile)
-		pp.SampleType = append(pp.SampleType, x)
-		return decodeMessage(b, x)
-	},
-	// repeated Sample sample = 2
-	func(b *buffer, m message) error {
-		x := new(Sample)
-		pp := m.(*Profile)
-		pp.Sample = append(pp.Sample, x)
-		return decodeMessage(b, x)
-	},
-	// repeated Mapping mapping = 3
-	func(b *buffer, m message) error {
-		x := new(Mapping)
-		pp := m.(*Profile)
-		pp.Mapping = append(pp.Mapping, x)
-		return decodeMessage(b, x)
-	},
-	// repeated Location location = 4
-	func(b *buffer, m message) error {
-		x := new(Location)
-		pp := m.(*Profile)
-		pp.Location = append(pp.Location, x)
-		return decodeMessage(b, x)
-	},
-	// repeated Function function = 5
-	func(b *buffer, m message) error {
-		x := new(Function)
-		pp := m.(*Profile)
-		pp.Function = append(pp.Function, x)
-		return decodeMessage(b, x)
-	},
-	// repeated string string_table = 6
-	func(b *buffer, m message) error {
-		err := decodeStrings(b, &m.(*Profile).stringTable)
-		if err != nil {
-			return err
-		}
-		if *&m.(*Profile).stringTable[0] != "" {
-			return errors.New("string_table[0] must be ''")
-		}
-		return nil
-	},
-	// repeated int64 drop_frames = 7
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
-	// repeated int64 keep_frames = 8
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
-	// repeated int64 time_nanos = 9
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).TimeNanos) },
-	// repeated int64 duration_nanos = 10
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
-	// optional string period_type = 11
-	func(b *buffer, m message) error {
-		x := new(ValueType)
-		pp := m.(*Profile)
-		pp.PeriodType = x
-		return decodeMessage(b, x)
-	},
-	// repeated int64 period = 12
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
-}
-
-// postDecode takes the unexported fields populated by decode (with
-// suffix X) and populates the corresponding exported fields.
-// The unexported fields are cleared up to facilitate testing.
-func (p *Profile) postDecode() error {
-	var err error
-
-	mappings := make(map[uint64]*Mapping)
-	for _, m := range p.Mapping {
-		m.File, err = getString(p.stringTable, &m.fileX, err)
-		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
-		mappings[m.ID] = m
-	}
-
-	functions := make(map[uint64]*Function)
-	for _, f := range p.Function {
-		f.Name, err = getString(p.stringTable, &f.nameX, err)
-		f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
-		f.Filename, err = getString(p.stringTable, &f.filenameX, err)
-		functions[f.ID] = f
-	}
-
-	locations := make(map[uint64]*Location)
-	for _, l := range p.Location {
-		l.Mapping = mappings[l.mappingIDX]
-		l.mappingIDX = 0
-		for i, ln := range l.Line {
-			if id := ln.functionIDX; id != 0 {
-				l.Line[i].Function = functions[id]
-				if l.Line[i].Function == nil {
-					return fmt.Errorf("Function ID %d not found", id)
-				}
-				l.Line[i].functionIDX = 0
-			}
-		}
-		locations[l.ID] = l
-	}
-
-	for _, st := range p.SampleType {
-		st.Type, err = getString(p.stringTable, &st.typeX, err)
-		st.Unit, err = getString(p.stringTable, &st.unitX, err)
-	}
-
-	for _, s := range p.Sample {
-		labels := make(map[string][]string)
-		numLabels := make(map[string][]int64)
-		for _, l := range s.labelX {
-			var key, value string
-			key, err = getString(p.stringTable, &l.keyX, err)
-			if l.strX != 0 {
-				value, err = getString(p.stringTable, &l.strX, err)
-				labels[key] = append(labels[key], value)
-			} else {
-				numLabels[key] = append(numLabels[key], l.numX)
-			}
-		}
-		if len(labels) > 0 {
-			s.Label = labels
-		}
-		if len(numLabels) > 0 {
-			s.NumLabel = numLabels
-		}
-		s.Location = nil
-		for _, lid := range s.locationIDX {
-			s.Location = append(s.Location, locations[lid])
-		}
-		s.locationIDX = nil
-	}
-
-	p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
-	p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
-
-	if pt := p.PeriodType; pt == nil {
-		p.PeriodType = &ValueType{}
-	}
-
-	if pt := p.PeriodType; pt != nil {
-		pt.Type, err = getString(p.stringTable, &pt.typeX, err)
-		pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
-	}
-	p.stringTable = nil
-	return nil
-}
-
-func (p *ValueType) decoder() []decoder {
-	return valueTypeDecoder
-}
-
-func (p *ValueType) encode(b *buffer) {
-	encodeInt64Opt(b, 1, p.typeX)
-	encodeInt64Opt(b, 2, p.unitX)
-}
-
-var valueTypeDecoder = []decoder{
-	nil, // 0
-	// optional int64 type = 1
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
-	// optional int64 unit = 2
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
-}
-
-func (p *Sample) decoder() []decoder {
-	return sampleDecoder
-}
-
-func (p *Sample) encode(b *buffer) {
-	encodeUint64s(b, 1, p.locationIDX)
-	for _, x := range p.Value {
-		encodeInt64(b, 2, x)
-	}
-	for _, x := range p.labelX {
-		encodeMessage(b, 3, x)
-	}
-}
-
-var sampleDecoder = []decoder{
-	nil, // 0
-	// repeated uint64 location = 1
-	func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
-	// repeated int64 value = 2
-	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
-	// repeated Label label = 3
-	func(b *buffer, m message) error {
-		s := m.(*Sample)
-		n := len(s.labelX)
-		s.labelX = append(s.labelX, Label{})
-		return decodeMessage(b, &s.labelX[n])
-	},
-}
-
-func (p Label) decoder() []decoder {
-	return labelDecoder
-}
-
-func (p Label) encode(b *buffer) {
-	encodeInt64Opt(b, 1, p.keyX)
-	encodeInt64Opt(b, 2, p.strX)
-	encodeInt64Opt(b, 3, p.numX)
-}
-
-var labelDecoder = []decoder{
-	nil, // 0
-	// optional int64 key = 1
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).keyX) },
-	// optional int64 str = 2
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).strX) },
-	// optional int64 num = 3
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).numX) },
-}
-
-func (p *Mapping) decoder() []decoder {
-	return mappingDecoder
-}
-
-func (p *Mapping) encode(b *buffer) {
-	encodeUint64Opt(b, 1, p.ID)
-	encodeUint64Opt(b, 2, p.Start)
-	encodeUint64Opt(b, 3, p.Limit)
-	encodeUint64Opt(b, 4, p.Offset)
-	encodeInt64Opt(b, 5, p.fileX)
-	encodeInt64Opt(b, 6, p.buildIDX)
-	encodeBoolOpt(b, 7, p.HasFunctions)
-	encodeBoolOpt(b, 8, p.HasFilenames)
-	encodeBoolOpt(b, 9, p.HasLineNumbers)
-	encodeBoolOpt(b, 10, p.HasInlineFrames)
-}
-
-var mappingDecoder = []decoder{
-	nil, // 0
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
-	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
-	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
-	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
-	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
-}
-
-func (p *Location) decoder() []decoder {
-	return locationDecoder
-}
-
-func (p *Location) encode(b *buffer) {
-	encodeUint64Opt(b, 1, p.ID)
-	encodeUint64Opt(b, 2, p.mappingIDX)
-	encodeUint64Opt(b, 3, p.Address)
-	for i := range p.Line {
-		encodeMessage(b, 4, &p.Line[i])
-	}
-}
-
-var locationDecoder = []decoder{
-	nil, // 0
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
-	func(b *buffer, m message) error { // repeated Line line = 4
-		pp := m.(*Location)
-		n := len(pp.Line)
-		pp.Line = append(pp.Line, Line{})
-		return decodeMessage(b, &pp.Line[n])
-	},
-}
-
-func (p *Line) decoder() []decoder {
-	return lineDecoder
-}
-
-func (p *Line) encode(b *buffer) {
-	encodeUint64Opt(b, 1, p.functionIDX)
-	encodeInt64Opt(b, 2, p.Line)
-}
-
-var lineDecoder = []decoder{
-	nil, // 0
-	// optional uint64 function_id = 1
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
-	// optional int64 line = 2
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
-}
-
-func (p *Function) decoder() []decoder {
-	return functionDecoder
-}
-
-func (p *Function) encode(b *buffer) {
-	encodeUint64Opt(b, 1, p.ID)
-	encodeInt64Opt(b, 2, p.nameX)
-	encodeInt64Opt(b, 3, p.systemNameX)
-	encodeInt64Opt(b, 4, p.filenameX)
-	encodeInt64Opt(b, 5, p.StartLine)
-}
-
-var functionDecoder = []decoder{
-	nil, // 0
-	// optional uint64 id = 1
-	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
-	// optional int64 function_name = 2
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
-	// optional int64 function_system_name = 3
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
-	// repeated int64 filename = 4
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
-	// optional int64 start_line = 5
-	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
-}
-
-func addString(strings map[string]int, s string) int64 {
-	i, ok := strings[s]
-	if !ok {
-		i = len(strings)
-		strings[s] = i
-	}
-	return int64(i)
-}
-
-func getString(strings []string, strng *int64, err error) (string, error) {
-	if err != nil {
-		return "", err
-	}
-	s := int(*strng)
-	if s < 0 || s >= len(strings) {
-		return "", errMalformed
-	}
-	*strng = 0
-	return strings[s], nil
-}
diff --git a/src/cmd/pprof/internal/profile/legacy_profile.go b/src/cmd/pprof/internal/profile/legacy_profile.go
deleted file mode 100644
index c7c047a..0000000
--- a/src/cmd/pprof/internal/profile/legacy_profile.go
+++ /dev/null
@@ -1,1251 +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 implements parsers to convert legacy profiles into the
-// profile.proto format.
-
-package profile
-
-import (
-	"bufio"
-	"bytes"
-	"fmt"
-	"io"
-	"math"
-	"regexp"
-	"strconv"
-	"strings"
-)
-
-var (
-	countStartRE = regexp.MustCompile(`\A(\w+) profile: total \d+\n\z`)
-	countRE      = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\n\z`)
-
-	heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`)
-	heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`)
-
-	contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`)
-
-	hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`)
-
-	growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz`)
-
-	fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz`)
-
-	threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`)
-	threadStartRE  = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`)
-
-	procMapsRE = regexp.MustCompile(`([[:xdigit:]]+)-([[:xdigit:]]+)\s+([-rwxp]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+):([[:xdigit:]]+)\s+([[:digit:]]+)\s*(\S+)?`)
-
-	briefMapsRE = regexp.MustCompile(`\s*([[:xdigit:]]+)-([[:xdigit:]]+):\s*(\S+)(\s.*@)?([[:xdigit:]]+)?`)
-
-	// LegacyHeapAllocated instructs the heapz parsers to use the
-	// allocated memory stats instead of the default in-use memory. Note
-	// that tcmalloc doesn't provide all allocated memory, only in-use
-	// stats.
-	LegacyHeapAllocated bool
-)
-
-func isSpaceOrComment(line string) bool {
-	trimmed := strings.TrimSpace(line)
-	return len(trimmed) == 0 || trimmed[0] == '#'
-}
-
-// parseGoCount parses a Go count profile (e.g., threadcreate or
-// goroutine) and returns a new Profile.
-func parseGoCount(b []byte) (*Profile, error) {
-	r := bytes.NewBuffer(b)
-
-	var line string
-	var err error
-	for {
-		// Skip past comments and empty lines seeking a real header.
-		line, err = r.ReadString('\n')
-		if err != nil {
-			return nil, err
-		}
-		if !isSpaceOrComment(line) {
-			break
-		}
-	}
-
-	m := countStartRE.FindStringSubmatch(line)
-	if m == nil {
-		return nil, errUnrecognized
-	}
-	profileType := string(m[1])
-	p := &Profile{
-		PeriodType: &ValueType{Type: profileType, Unit: "count"},
-		Period:     1,
-		SampleType: []*ValueType{{Type: profileType, Unit: "count"}},
-	}
-	locations := make(map[uint64]*Location)
-	for {
-		line, err = r.ReadString('\n')
-		if err != nil {
-			if err == io.EOF {
-				break
-			}
-			return nil, err
-		}
-		if isSpaceOrComment(line) {
-			continue
-		}
-		if strings.HasPrefix(line, "---") {
-			break
-		}
-		m := countRE.FindStringSubmatch(line)
-		if m == nil {
-			return nil, errMalformed
-		}
-		n, err := strconv.ParseInt(string(m[1]), 0, 64)
-		if err != nil {
-			return nil, errMalformed
-		}
-		fields := strings.Fields(string(m[2]))
-		locs := make([]*Location, 0, len(fields))
-		for _, stk := range fields {
-			addr, err := strconv.ParseUint(stk, 0, 64)
-			if err != nil {
-				return nil, errMalformed
-			}
-			// Adjust all frames by -1 (except the leaf) to land on top of
-			// the call instruction.
-			if len(locs) > 0 {
-				addr--
-			}
-			loc := locations[addr]
-			if loc == nil {
-				loc = &Location{
-					Address: addr,
-				}
-				locations[addr] = loc
-				p.Location = append(p.Location, loc)
-			}
-			locs = append(locs, loc)
-		}
-		p.Sample = append(p.Sample, &Sample{
-			Location: locs,
-			Value:    []int64{n},
-		})
-	}
-
-	if err = parseAdditionalSections(strings.TrimSpace(line), r, p); err != nil {
-		return nil, err
-	}
-	return p, nil
-}
-
-// remapLocationIDs ensures there is a location for each address
-// referenced by a sample, and remaps the samples to point to the new
-// location ids.
-func (p *Profile) remapLocationIDs() {
-	seen := make(map[*Location]bool, len(p.Location))
-	var locs []*Location
-
-	for _, s := range p.Sample {
-		for _, l := range s.Location {
-			if seen[l] {
-				continue
-			}
-			l.ID = uint64(len(locs) + 1)
-			locs = append(locs, l)
-			seen[l] = true
-		}
-	}
-	p.Location = locs
-}
-
-func (p *Profile) remapFunctionIDs() {
-	seen := make(map[*Function]bool, len(p.Function))
-	var fns []*Function
-
-	for _, l := range p.Location {
-		for _, ln := range l.Line {
-			fn := ln.Function
-			if fn == nil || seen[fn] {
-				continue
-			}
-			fn.ID = uint64(len(fns) + 1)
-			fns = append(fns, fn)
-			seen[fn] = true
-		}
-	}
-	p.Function = fns
-}
-
-// remapMappingIDs matches location addresses with existing mappings
-// and updates them appropriately. This is O(N*M), if this ever shows
-// up as a bottleneck, evaluate sorting the mappings and doing a
-// binary search, which would make it O(N*log(M)).
-func (p *Profile) remapMappingIDs() {
-	if len(p.Mapping) == 0 {
-		return
-	}
-
-	// Some profile handlers will incorrectly set regions for the main
-	// executable if its section is remapped. Fix them through heuristics.
-
-	// Remove the initial mapping if named '/anon_hugepage' and has a
-	// consecutive adjacent mapping.
-	if m := p.Mapping[0]; strings.HasPrefix(m.File, "/anon_hugepage") {
-		if len(p.Mapping) > 1 && m.Limit == p.Mapping[1].Start {
-			p.Mapping = p.Mapping[1:]
-		}
-	}
-
-	// Subtract the offset from the start of the main mapping if it
-	// ends up at a recognizable start address.
-	const expectedStart = 0x400000
-	if m := p.Mapping[0]; m.Start-m.Offset == expectedStart {
-		m.Start = expectedStart
-		m.Offset = 0
-	}
-
-	for _, l := range p.Location {
-		if a := l.Address; a != 0 {
-			for _, m := range p.Mapping {
-				if m.Start <= a && a < m.Limit {
-					l.Mapping = m
-					break
-				}
-			}
-		}
-	}
-
-	// Reset all mapping IDs.
-	for i, m := range p.Mapping {
-		m.ID = uint64(i + 1)
-	}
-}
-
-var cpuInts = []func([]byte) (uint64, []byte){
-	get32l,
-	get32b,
-	get64l,
-	get64b,
-}
-
-func get32l(b []byte) (uint64, []byte) {
-	if len(b) < 4 {
-		return 0, nil
-	}
-	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24, b[4:]
-}
-
-func get32b(b []byte) (uint64, []byte) {
-	if len(b) < 4 {
-		return 0, nil
-	}
-	return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24, b[4:]
-}
-
-func get64l(b []byte) (uint64, []byte) {
-	if len(b) < 8 {
-		return 0, nil
-	}
-	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, b[8:]
-}
-
-func get64b(b []byte) (uint64, []byte) {
-	if len(b) < 8 {
-		return 0, nil
-	}
-	return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56, b[8:]
-}
-
-// ParseTracebacks parses a set of tracebacks and returns a newly
-// populated profile. It will accept any text file and generate a
-// Profile out of it with any hex addresses it can identify, including
-// a process map if it can recognize one. Each sample will include a
-// tag "source" with the addresses recognized in string format.
-func ParseTracebacks(b []byte) (*Profile, error) {
-	r := bytes.NewBuffer(b)
-
-	p := &Profile{
-		PeriodType: &ValueType{Type: "trace", Unit: "count"},
-		Period:     1,
-		SampleType: []*ValueType{
-			{Type: "trace", Unit: "count"},
-		},
-	}
-
-	var sources []string
-	var sloc []*Location
-
-	locs := make(map[uint64]*Location)
-	for {
-		l, err := r.ReadString('\n')
-		if err != nil {
-			if err != io.EOF {
-				return nil, err
-			}
-			if l == "" {
-				break
-			}
-		}
-		if sectionTrigger(l) == memoryMapSection {
-			break
-		}
-		if s, addrs := extractHexAddresses(l); len(s) > 0 {
-			for _, addr := range addrs {
-				// Addresses from stack traces point to the next instruction after
-				// each call.  Adjust by -1 to land somewhere on the actual call
-				// (except for the leaf, which is not a call).
-				if len(sloc) > 0 {
-					addr--
-				}
-				loc := locs[addr]
-				if locs[addr] == nil {
-					loc = &Location{
-						Address: addr,
-					}
-					p.Location = append(p.Location, loc)
-					locs[addr] = loc
-				}
-				sloc = append(sloc, loc)
-			}
-
-			sources = append(sources, s...)
-		} else {
-			if len(sources) > 0 || len(sloc) > 0 {
-				addTracebackSample(sloc, sources, p)
-				sloc, sources = nil, nil
-			}
-		}
-	}
-
-	// Add final sample to save any leftover data.
-	if len(sources) > 0 || len(sloc) > 0 {
-		addTracebackSample(sloc, sources, p)
-	}
-
-	if err := p.ParseMemoryMap(r); err != nil {
-		return nil, err
-	}
-	return p, nil
-}
-
-func addTracebackSample(l []*Location, s []string, p *Profile) {
-	p.Sample = append(p.Sample,
-		&Sample{
-			Value:    []int64{1},
-			Location: l,
-			Label:    map[string][]string{"source": s},
-		})
-}
-
-// parseCPU parses a profilez legacy profile and returns a newly
-// populated Profile.
-//
-// The general format for profilez samples is a sequence of words in
-// binary format. The first words are a header with the following data:
-//   1st word -- 0
-//   2nd word -- 3
-//   3rd word -- 0 if a c++ application, 1 if a java application.
-//   4th word -- Sampling period (in microseconds).
-//   5th word -- Padding.
-func parseCPU(b []byte) (*Profile, error) {
-	var parse func([]byte) (uint64, []byte)
-	var n1, n2, n3, n4, n5 uint64
-	for _, parse = range cpuInts {
-		var tmp []byte
-		n1, tmp = parse(b)
-		n2, tmp = parse(tmp)
-		n3, tmp = parse(tmp)
-		n4, tmp = parse(tmp)
-		n5, tmp = parse(tmp)
-
-		if tmp != nil && n1 == 0 && n2 == 3 && n3 == 0 && n4 > 0 && n5 == 0 {
-			b = tmp
-			return cpuProfile(b, int64(n4), parse)
-		}
-	}
-	return nil, errUnrecognized
-}
-
-// cpuProfile returns a new Profile from C++ profilez data.
-// b is the profile bytes after the header, period is the profiling
-// period, and parse is a function to parse 8-byte chunks from the
-// profile in its native endianness.
-func cpuProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) {
-	p := &Profile{
-		Period:     period * 1000,
-		PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
-		SampleType: []*ValueType{
-			{Type: "samples", Unit: "count"},
-			{Type: "cpu", Unit: "nanoseconds"},
-		},
-	}
-	var err error
-	if b, _, err = parseCPUSamples(b, parse, true, p); err != nil {
-		return nil, err
-	}
-
-	// If all samples have the same second-to-the-bottom frame, it
-	// strongly suggests that it is an uninteresting artifact of
-	// measurement -- a stack frame pushed by the signal handler. The
-	// bottom frame is always correct as it is picked up from the signal
-	// structure, not the stack. Check if this is the case and if so,
-	// remove.
-	if len(p.Sample) > 1 && len(p.Sample[0].Location) > 1 {
-		allSame := true
-		id1 := p.Sample[0].Location[1].Address
-		for _, s := range p.Sample {
-			if len(s.Location) < 2 || id1 != s.Location[1].Address {
-				allSame = false
-				break
-			}
-		}
-		if allSame {
-			for _, s := range p.Sample {
-				s.Location = append(s.Location[:1], s.Location[2:]...)
-			}
-		}
-	}
-
-	if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil {
-		return nil, err
-	}
-	return p, nil
-}
-
-// parseCPUSamples parses a collection of profilez samples from a
-// profile.
-//
-// profilez samples are a repeated sequence of stack frames of the
-// form:
-//    1st word -- The number of times this stack was encountered.
-//    2nd word -- The size of the stack (StackSize).
-//    3rd word -- The first address on the stack.
-//    ...
-//    StackSize + 2 -- The last address on the stack
-// The last stack trace is of the form:
-//   1st word -- 0
-//   2nd word -- 1
-//   3rd word -- 0
-//
-// Addresses from stack traces may point to the next instruction after
-// each call.  Optionally adjust by -1 to land somewhere on the actual
-// call (except for the leaf, which is not a call).
-func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust bool, p *Profile) ([]byte, map[uint64]*Location, error) {
-	locs := make(map[uint64]*Location)
-	for len(b) > 0 {
-		var count, nstk uint64
-		count, b = parse(b)
-		nstk, b = parse(b)
-		if b == nil || nstk > uint64(len(b)/4) {
-			return nil, nil, errUnrecognized
-		}
-		var sloc []*Location
-		addrs := make([]uint64, nstk)
-		for i := 0; i < int(nstk); i++ {
-			addrs[i], b = parse(b)
-		}
-
-		if count == 0 && nstk == 1 && addrs[0] == 0 {
-			// End of data marker
-			break
-		}
-		for i, addr := range addrs {
-			if adjust && i > 0 {
-				addr--
-			}
-			loc := locs[addr]
-			if loc == nil {
-				loc = &Location{
-					Address: addr,
-				}
-				locs[addr] = loc
-				p.Location = append(p.Location, loc)
-			}
-			sloc = append(sloc, loc)
-		}
-		p.Sample = append(p.Sample,
-			&Sample{
-				Value:    []int64{int64(count), int64(count) * int64(p.Period)},
-				Location: sloc,
-			})
-	}
-	// Reached the end without finding the EOD marker.
-	return b, locs, nil
-}
-
-// parseHeap parses a heapz legacy or a growthz profile and
-// returns a newly populated Profile.
-func parseHeap(b []byte) (p *Profile, err error) {
-	r := bytes.NewBuffer(b)
-	l, err := r.ReadString('\n')
-	if err != nil {
-		return nil, errUnrecognized
-	}
-
-	sampling := ""
-
-	if header := heapHeaderRE.FindStringSubmatch(l); header != nil {
-		p = &Profile{
-			SampleType: []*ValueType{
-				{Type: "objects", Unit: "count"},
-				{Type: "space", Unit: "bytes"},
-			},
-			PeriodType: &ValueType{Type: "objects", Unit: "bytes"},
-		}
-
-		var period int64
-		if len(header[6]) > 0 {
-			if period, err = strconv.ParseInt(string(header[6]), 10, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		}
-
-		switch header[5] {
-		case "heapz_v2", "heap_v2":
-			sampling, p.Period = "v2", period
-		case "heapprofile":
-			sampling, p.Period = "", 1
-		case "heap":
-			sampling, p.Period = "v2", period/2
-		default:
-			return nil, errUnrecognized
-		}
-	} else if header = growthHeaderRE.FindStringSubmatch(l); header != nil {
-		p = &Profile{
-			SampleType: []*ValueType{
-				{Type: "objects", Unit: "count"},
-				{Type: "space", Unit: "bytes"},
-			},
-			PeriodType: &ValueType{Type: "heapgrowth", Unit: "count"},
-			Period:     1,
-		}
-	} else if header = fragmentationHeaderRE.FindStringSubmatch(l); header != nil {
-		p = &Profile{
-			SampleType: []*ValueType{
-				{Type: "objects", Unit: "count"},
-				{Type: "space", Unit: "bytes"},
-			},
-			PeriodType: &ValueType{Type: "allocations", Unit: "count"},
-			Period:     1,
-		}
-	} else {
-		return nil, errUnrecognized
-	}
-
-	if LegacyHeapAllocated {
-		for _, st := range p.SampleType {
-			st.Type = "alloc_" + st.Type
-		}
-	} else {
-		for _, st := range p.SampleType {
-			st.Type = "inuse_" + st.Type
-		}
-	}
-
-	locs := make(map[uint64]*Location)
-	for {
-		l, err = r.ReadString('\n')
-		if err != nil {
-			if err != io.EOF {
-				return nil, err
-			}
-
-			if l == "" {
-				break
-			}
-		}
-
-		if isSpaceOrComment(l) {
-			continue
-		}
-		l = strings.TrimSpace(l)
-
-		if sectionTrigger(l) != unrecognizedSection {
-			break
-		}
-
-		value, blocksize, addrs, err := parseHeapSample(l, p.Period, sampling)
-		if err != nil {
-			return nil, err
-		}
-		var sloc []*Location
-		for i, addr := range addrs {
-			// Addresses from stack traces point to the next instruction after
-			// each call.  Adjust by -1 to land somewhere on the actual call
-			// (except for the leaf, which is not a call).
-			if i > 0 {
-				addr--
-			}
-			loc := locs[addr]
-			if locs[addr] == nil {
-				loc = &Location{
-					Address: addr,
-				}
-				p.Location = append(p.Location, loc)
-				locs[addr] = loc
-			}
-			sloc = append(sloc, loc)
-		}
-
-		p.Sample = append(p.Sample, &Sample{
-			Value:    value,
-			Location: sloc,
-			NumLabel: map[string][]int64{"bytes": {blocksize}},
-		})
-	}
-
-	if err = parseAdditionalSections(l, r, p); err != nil {
-		return nil, err
-	}
-	return p, nil
-}
-
-// parseHeapSample parses a single row from a heap profile into a new Sample.
-func parseHeapSample(line string, rate int64, sampling string) (value []int64, blocksize int64, addrs []uint64, err error) {
-	sampleData := heapSampleRE.FindStringSubmatch(line)
-	if len(sampleData) != 6 {
-		return value, blocksize, addrs, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData))
-	}
-
-	// Use first two values by default; tcmalloc sampling generates the
-	// same value for both, only the older heap-profile collect separate
-	// stats for in-use and allocated objects.
-	valueIndex := 1
-	if LegacyHeapAllocated {
-		valueIndex = 3
-	}
-
-	var v1, v2 int64
-	if v1, err = strconv.ParseInt(sampleData[valueIndex], 10, 64); err != nil {
-		return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
-	}
-	if v2, err = strconv.ParseInt(sampleData[valueIndex+1], 10, 64); err != nil {
-		return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
-	}
-
-	if v1 == 0 {
-		if v2 != 0 {
-			return value, blocksize, addrs, fmt.Errorf("allocation count was 0 but allocation bytes was %d", v2)
-		}
-	} else {
-		blocksize = v2 / v1
-		if sampling == "v2" {
-			v1, v2 = scaleHeapSample(v1, v2, rate)
-		}
-	}
-
-	value = []int64{v1, v2}
-	addrs = parseHexAddresses(sampleData[5])
-
-	return value, blocksize, addrs, nil
-}
-
-// extractHexAddresses extracts hex numbers from a string and returns
-// them, together with their numeric value, in a slice.
-func extractHexAddresses(s string) ([]string, []uint64) {
-	hexStrings := hexNumberRE.FindAllString(s, -1)
-	var ids []uint64
-	for _, s := range hexStrings {
-		if id, err := strconv.ParseUint(s, 0, 64); err == nil {
-			ids = append(ids, id)
-		} else {
-			// Do not expect any parsing failures due to the regexp matching.
-			panic("failed to parse hex value:" + s)
-		}
-	}
-	return hexStrings, ids
-}
-
-// parseHexAddresses parses hex numbers from a string and returns them
-// in a slice.
-func parseHexAddresses(s string) []uint64 {
-	_, ids := extractHexAddresses(s)
-	return ids
-}
-
-// scaleHeapSample adjusts the data from a heapz Sample to
-// account for its probability of appearing in the collected
-// data. heapz profiles are a sampling of the memory allocations
-// requests in a program. We estimate the unsampled value by dividing
-// each collected sample by its probability of appearing in the
-// profile. heapz v2 profiles rely on a poisson process to determine
-// which samples to collect, based on the desired average collection
-// rate R. The probability of a sample of size S to appear in that
-// profile is 1-exp(-S/R).
-func scaleHeapSample(count, size, rate int64) (int64, int64) {
-	if count == 0 || size == 0 {
-		return 0, 0
-	}
-
-	if rate <= 1 {
-		// if rate==1 all samples were collected so no adjustment is needed.
-		// if rate<1 treat as unknown and skip scaling.
-		return count, size
-	}
-
-	avgSize := float64(size) / float64(count)
-	scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
-
-	return int64(float64(count) * scale), int64(float64(size) * scale)
-}
-
-// parseContention parses a contentionz profile and returns a newly
-// populated Profile.
-func parseContention(b []byte) (p *Profile, err error) {
-	r := bytes.NewBuffer(b)
-	l, err := r.ReadString('\n')
-	if err != nil {
-		return nil, errUnrecognized
-	}
-
-	if !strings.HasPrefix(l, "--- contention") {
-		return nil, errUnrecognized
-	}
-
-	p = &Profile{
-		PeriodType: &ValueType{Type: "contentions", Unit: "count"},
-		Period:     1,
-		SampleType: []*ValueType{
-			{Type: "contentions", Unit: "count"},
-			{Type: "delay", Unit: "nanoseconds"},
-		},
-	}
-
-	var cpuHz int64
-	// Parse text of the form "attribute = value" before the samples.
-	const delimiter = "="
-	for {
-		l, err = r.ReadString('\n')
-		if err != nil {
-			if err != io.EOF {
-				return nil, err
-			}
-
-			if l == "" {
-				break
-			}
-		}
-
-		if l = strings.TrimSpace(l); l == "" {
-			continue
-		}
-
-		if strings.HasPrefix(l, "---") {
-			break
-		}
-
-		attr := strings.SplitN(l, delimiter, 2)
-		if len(attr) != 2 {
-			break
-		}
-		key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])
-		var err error
-		switch key {
-		case "cycles/second":
-			if cpuHz, err = strconv.ParseInt(val, 0, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		case "sampling period":
-			if p.Period, err = strconv.ParseInt(val, 0, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		case "ms since reset":
-			ms, err := strconv.ParseInt(val, 0, 64)
-			if err != nil {
-				return nil, errUnrecognized
-			}
-			p.DurationNanos = ms * 1000 * 1000
-		case "format":
-			// CPP contentionz profiles don't have format.
-			return nil, errUnrecognized
-		case "resolution":
-			// CPP contentionz profiles don't have resolution.
-			return nil, errUnrecognized
-		case "discarded samples":
-		default:
-			return nil, errUnrecognized
-		}
-	}
-
-	locs := make(map[uint64]*Location)
-	for {
-		if l = strings.TrimSpace(l); strings.HasPrefix(l, "---") {
-			break
-		}
-		value, addrs, err := parseContentionSample(l, p.Period, cpuHz)
-		if err != nil {
-			return nil, err
-		}
-		var sloc []*Location
-		for i, addr := range addrs {
-			// Addresses from stack traces point to the next instruction after
-			// each call.  Adjust by -1 to land somewhere on the actual call
-			// (except for the leaf, which is not a call).
-			if i > 0 {
-				addr--
-			}
-			loc := locs[addr]
-			if locs[addr] == nil {
-				loc = &Location{
-					Address: addr,
-				}
-				p.Location = append(p.Location, loc)
-				locs[addr] = loc
-			}
-			sloc = append(sloc, loc)
-		}
-		p.Sample = append(p.Sample, &Sample{
-			Value:    value,
-			Location: sloc,
-		})
-
-		if l, err = r.ReadString('\n'); err != nil {
-			if err != io.EOF {
-				return nil, err
-			}
-			if l == "" {
-				break
-			}
-		}
-	}
-
-	if err = parseAdditionalSections(l, r, p); err != nil {
-		return nil, err
-	}
-
-	return p, nil
-}
-
-// parseContentionSample parses a single row from a contention profile
-// into a new Sample.
-func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) {
-	sampleData := contentionSampleRE.FindStringSubmatch(line)
-	if sampleData == nil {
-		return value, addrs, errUnrecognized
-	}
-
-	v1, err := strconv.ParseInt(sampleData[1], 10, 64)
-	if err != nil {
-		return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
-	}
-	v2, err := strconv.ParseInt(sampleData[2], 10, 64)
-	if err != nil {
-		return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
-	}
-
-	// Unsample values if period and cpuHz are available.
-	// - Delays are scaled to cycles and then to nanoseconds.
-	// - Contentions are scaled to cycles.
-	if period > 0 {
-		if cpuHz > 0 {
-			cpuGHz := float64(cpuHz) / 1e9
-			v1 = int64(float64(v1) * float64(period) / cpuGHz)
-		}
-		v2 = v2 * period
-	}
-
-	value = []int64{v2, v1}
-	addrs = parseHexAddresses(sampleData[3])
-
-	return value, addrs, nil
-}
-
-// parseThread parses a Threadz profile and returns a new Profile.
-func parseThread(b []byte) (*Profile, error) {
-	r := bytes.NewBuffer(b)
-
-	var line string
-	var err error
-	for {
-		// Skip past comments and empty lines seeking a real header.
-		line, err = r.ReadString('\n')
-		if err != nil {
-			return nil, err
-		}
-		if !isSpaceOrComment(line) {
-			break
-		}
-	}
-
-	if m := threadzStartRE.FindStringSubmatch(line); m != nil {
-		// Advance over initial comments until first stack trace.
-		for {
-			line, err = r.ReadString('\n')
-			if err != nil {
-				if err != io.EOF {
-					return nil, err
-				}
-
-				if line == "" {
-					break
-				}
-			}
-			if sectionTrigger(line) != unrecognizedSection || line[0] == '-' {
-				break
-			}
-		}
-	} else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
-		return nil, errUnrecognized
-	}
-
-	p := &Profile{
-		SampleType: []*ValueType{{Type: "thread", Unit: "count"}},
-		PeriodType: &ValueType{Type: "thread", Unit: "count"},
-		Period:     1,
-	}
-
-	locs := make(map[uint64]*Location)
-	// Recognize each thread and populate profile samples.
-	for sectionTrigger(line) == unrecognizedSection {
-		if strings.HasPrefix(line, "---- no stack trace for") {
-			line = ""
-			break
-		}
-		if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
-			return nil, errUnrecognized
-		}
-
-		var addrs []uint64
-		line, addrs, err = parseThreadSample(r)
-		if err != nil {
-			return nil, errUnrecognized
-		}
-		if len(addrs) == 0 {
-			// We got a --same as previous threads--. Bump counters.
-			if len(p.Sample) > 0 {
-				s := p.Sample[len(p.Sample)-1]
-				s.Value[0]++
-			}
-			continue
-		}
-
-		var sloc []*Location
-		for i, addr := range addrs {
-			// Addresses from stack traces point to the next instruction after
-			// each call.  Adjust by -1 to land somewhere on the actual call
-			// (except for the leaf, which is not a call).
-			if i > 0 {
-				addr--
-			}
-			loc := locs[addr]
-			if locs[addr] == nil {
-				loc = &Location{
-					Address: addr,
-				}
-				p.Location = append(p.Location, loc)
-				locs[addr] = loc
-			}
-			sloc = append(sloc, loc)
-		}
-
-		p.Sample = append(p.Sample, &Sample{
-			Value:    []int64{1},
-			Location: sloc,
-		})
-	}
-
-	if err = parseAdditionalSections(line, r, p); err != nil {
-		return nil, err
-	}
-
-	return p, nil
-}
-
-// parseThreadSample parses a symbolized or unsymbolized stack trace.
-// Returns the first line after the traceback, the sample (or nil if
-// it hits a 'same-as-previous' marker) and an error.
-func parseThreadSample(b *bytes.Buffer) (nextl string, addrs []uint64, err error) {
-	var l string
-	sameAsPrevious := false
-	for {
-		if l, err = b.ReadString('\n'); err != nil {
-			if err != io.EOF {
-				return "", nil, err
-			}
-			if l == "" {
-				break
-			}
-		}
-		if l = strings.TrimSpace(l); l == "" {
-			continue
-		}
-
-		if strings.HasPrefix(l, "---") {
-			break
-		}
-		if strings.Contains(l, "same as previous thread") {
-			sameAsPrevious = true
-			continue
-		}
-
-		addrs = append(addrs, parseHexAddresses(l)...)
-	}
-
-	if sameAsPrevious {
-		return l, nil, nil
-	}
-	return l, addrs, nil
-}
-
-// parseAdditionalSections parses any additional sections in the
-// profile, ignoring any unrecognized sections.
-func parseAdditionalSections(l string, b *bytes.Buffer, p *Profile) (err error) {
-	for {
-		if sectionTrigger(l) == memoryMapSection {
-			break
-		}
-		// Ignore any unrecognized sections.
-		if l, err := b.ReadString('\n'); err != nil {
-			if err != io.EOF {
-				return err
-			}
-			if l == "" {
-				break
-			}
-		}
-	}
-	return p.ParseMemoryMap(b)
-}
-
-// ParseMemoryMap parses a memory map in the format of
-// /proc/self/maps, and overrides the mappings in the current profile.
-// It renumbers the samples and locations in the profile correspondingly.
-func (p *Profile) ParseMemoryMap(rd io.Reader) error {
-	b := bufio.NewReader(rd)
-
-	var attrs []string
-	var r *strings.Replacer
-	const delimiter = "="
-	for {
-		l, err := b.ReadString('\n')
-		if err != nil {
-			if err != io.EOF {
-				return err
-			}
-			if l == "" {
-				break
-			}
-		}
-		if l = strings.TrimSpace(l); l == "" {
-			continue
-		}
-
-		if r != nil {
-			l = r.Replace(l)
-		}
-		m, err := parseMappingEntry(l)
-		if err != nil {
-			if err == errUnrecognized {
-				// Recognize assignments of the form: attr=value, and replace
-				// $attr with value on subsequent mappings.
-				if attr := strings.SplitN(l, delimiter, 2); len(attr) == 2 {
-					attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
-					r = strings.NewReplacer(attrs...)
-				}
-				// Ignore any unrecognized entries
-				continue
-			}
-			return err
-		}
-		if m == nil || (m.File == "" && len(p.Mapping) != 0) {
-			// In some cases the first entry may include the address range
-			// but not the name of the file. It should be followed by
-			// another entry with the name.
-			continue
-		}
-		if len(p.Mapping) == 1 && p.Mapping[0].File == "" {
-			// Update the name if this is the entry following that empty one.
-			p.Mapping[0].File = m.File
-			continue
-		}
-		p.Mapping = append(p.Mapping, m)
-	}
-	p.remapLocationIDs()
-	p.remapFunctionIDs()
-	p.remapMappingIDs()
-	return nil
-}
-
-func parseMappingEntry(l string) (*Mapping, error) {
-	mapping := &Mapping{}
-	var err error
-	if me := procMapsRE.FindStringSubmatch(l); len(me) == 9 {
-		if !strings.Contains(me[3], "x") {
-			// Skip non-executable entries.
-			return nil, nil
-		}
-		if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
-			return nil, errUnrecognized
-		}
-		if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
-			return nil, errUnrecognized
-		}
-		if me[4] != "" {
-			if mapping.Offset, err = strconv.ParseUint(me[4], 16, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		}
-		mapping.File = me[8]
-		return mapping, nil
-	}
-
-	if me := briefMapsRE.FindStringSubmatch(l); len(me) == 6 {
-		if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
-			return nil, errUnrecognized
-		}
-		if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
-			return nil, errUnrecognized
-		}
-		mapping.File = me[3]
-		if me[5] != "" {
-			if mapping.Offset, err = strconv.ParseUint(me[5], 16, 64); err != nil {
-				return nil, errUnrecognized
-			}
-		}
-		return mapping, nil
-	}
-
-	return nil, errUnrecognized
-}
-
-type sectionType int
-
-const (
-	unrecognizedSection sectionType = iota
-	memoryMapSection
-)
-
-var memoryMapTriggers = []string{
-	"--- Memory map: ---",
-	"MAPPED_LIBRARIES:",
-}
-
-func sectionTrigger(line string) sectionType {
-	for _, trigger := range memoryMapTriggers {
-		if strings.Contains(line, trigger) {
-			return memoryMapSection
-		}
-	}
-	return unrecognizedSection
-}
-
-func (p *Profile) addLegacyFrameInfo() {
-	switch {
-	case isProfileType(p, heapzSampleTypes) ||
-		isProfileType(p, heapzInUseSampleTypes) ||
-		isProfileType(p, heapzAllocSampleTypes):
-		p.DropFrames, p.KeepFrames = allocRxStr, allocSkipRxStr
-	case isProfileType(p, contentionzSampleTypes):
-		p.DropFrames, p.KeepFrames = lockRxStr, ""
-	default:
-		p.DropFrames, p.KeepFrames = cpuProfilerRxStr, ""
-	}
-}
-
-var heapzSampleTypes = []string{"allocations", "size"} // early Go pprof profiles
-var heapzInUseSampleTypes = []string{"inuse_objects", "inuse_space"}
-var heapzAllocSampleTypes = []string{"alloc_objects", "alloc_space"}
-var contentionzSampleTypes = []string{"contentions", "delay"}
-
-func isProfileType(p *Profile, t []string) bool {
-	st := p.SampleType
-	if len(st) != len(t) {
-		return false
-	}
-
-	for i := range st {
-		if st[i].Type != t[i] {
-			return false
-		}
-	}
-	return true
-}
-
-var allocRxStr = strings.Join([]string{
-	// POSIX entry points.
-	`calloc`,
-	`cfree`,
-	`malloc`,
-	`free`,
-	`memalign`,
-	`do_memalign`,
-	`(__)?posix_memalign`,
-	`pvalloc`,
-	`valloc`,
-	`realloc`,
-
-	// TC malloc.
-	`tcmalloc::.*`,
-	`tc_calloc`,
-	`tc_cfree`,
-	`tc_malloc`,
-	`tc_free`,
-	`tc_memalign`,
-	`tc_posix_memalign`,
-	`tc_pvalloc`,
-	`tc_valloc`,
-	`tc_realloc`,
-	`tc_new`,
-	`tc_delete`,
-	`tc_newarray`,
-	`tc_deletearray`,
-	`tc_new_nothrow`,
-	`tc_newarray_nothrow`,
-
-	// Memory-allocation routines on OS X.
-	`malloc_zone_malloc`,
-	`malloc_zone_calloc`,
-	`malloc_zone_valloc`,
-	`malloc_zone_realloc`,
-	`malloc_zone_memalign`,
-	`malloc_zone_free`,
-
-	// Go runtime
-	`runtime\..*`,
-
-	// Other misc. memory allocation routines
-	`BaseArena::.*`,
-	`(::)?do_malloc_no_errno`,
-	`(::)?do_malloc_pages`,
-	`(::)?do_malloc`,
-	`DoSampledAllocation`,
-	`MallocedMemBlock::MallocedMemBlock`,
-	`_M_allocate`,
-	`__builtin_(vec_)?delete`,
-	`__builtin_(vec_)?new`,
-	`__gnu_cxx::new_allocator::allocate`,
-	`__libc_malloc`,
-	`__malloc_alloc_template::allocate`,
-	`allocate`,
-	`cpp_alloc`,
-	`operator new(\[\])?`,
-	`simple_alloc::allocate`,
-}, `|`)
-
-var allocSkipRxStr = strings.Join([]string{
-	// Preserve Go runtime frames that appear in the middle/bottom of
-	// the stack.
-	`runtime\.panic`,
-}, `|`)
-
-var cpuProfilerRxStr = strings.Join([]string{
-	`ProfileData::Add`,
-	`ProfileData::prof_handler`,
-	`CpuProfiler::prof_handler`,
-	`__pthread_sighandler`,
-	`__restore`,
-}, `|`)
-
-var lockRxStr = strings.Join([]string{
-	`RecordLockProfileData`,
-	`(base::)?RecordLockProfileData.*`,
-	`(base::)?SubmitMutexProfileData.*`,
-	`(base::)?SubmitSpinLockProfileData.*`,
-	`(Mutex::)?AwaitCommon.*`,
-	`(Mutex::)?Unlock.*`,
-	`(Mutex::)?UnlockSlow.*`,
-	`(Mutex::)?ReaderUnlock.*`,
-	`(MutexLock::)?~MutexLock.*`,
-	`(SpinLock::)?Unlock.*`,
-	`(SpinLock::)?SlowUnlock.*`,
-	`(SpinLockHolder::)?~SpinLockHolder.*`,
-}, `|`)
diff --git a/src/cmd/pprof/internal/profile/profile.go b/src/cmd/pprof/internal/profile/profile.go
deleted file mode 100644
index 6d175bf..0000000
--- a/src/cmd/pprof/internal/profile/profile.go
+++ /dev/null
@@ -1,572 +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 profile provides a representation of profile.proto and
-// methods to encode/decode profiles in this format.
-package profile
-
-import (
-	"bytes"
-	"compress/gzip"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"regexp"
-	"strings"
-	"time"
-)
-
-// Profile is an in-memory representation of profile.proto.
-type Profile struct {
-	SampleType []*ValueType
-	Sample     []*Sample
-	Mapping    []*Mapping
-	Location   []*Location
-	Function   []*Function
-
-	DropFrames string
-	KeepFrames string
-
-	TimeNanos     int64
-	DurationNanos int64
-	PeriodType    *ValueType
-	Period        int64
-
-	dropFramesX int64
-	keepFramesX int64
-	stringTable []string
-}
-
-// ValueType corresponds to Profile.ValueType
-type ValueType struct {
-	Type string // cpu, wall, inuse_space, etc
-	Unit string // seconds, nanoseconds, bytes, etc
-
-	typeX int64
-	unitX int64
-}
-
-// Sample corresponds to Profile.Sample
-type Sample struct {
-	Location []*Location
-	Value    []int64
-	Label    map[string][]string
-	NumLabel map[string][]int64
-
-	locationIDX []uint64
-	labelX      []Label
-}
-
-// Label corresponds to Profile.Label
-type Label struct {
-	keyX int64
-	// Exactly one of the two following values must be set
-	strX int64
-	numX int64 // Integer value for this label
-}
-
-// Mapping corresponds to Profile.Mapping
-type Mapping struct {
-	ID              uint64
-	Start           uint64
-	Limit           uint64
-	Offset          uint64
-	File            string
-	BuildID         string
-	HasFunctions    bool
-	HasFilenames    bool
-	HasLineNumbers  bool
-	HasInlineFrames bool
-
-	fileX    int64
-	buildIDX int64
-}
-
-// Location corresponds to Profile.Location
-type Location struct {
-	ID      uint64
-	Mapping *Mapping
-	Address uint64
-	Line    []Line
-
-	mappingIDX uint64
-}
-
-// Line corresponds to Profile.Line
-type Line struct {
-	Function *Function
-	Line     int64
-
-	functionIDX uint64
-}
-
-// Function corresponds to Profile.Function
-type Function struct {
-	ID         uint64
-	Name       string
-	SystemName string
-	Filename   string
-	StartLine  int64
-
-	nameX       int64
-	systemNameX int64
-	filenameX   int64
-}
-
-// Parse parses a profile and checks for its validity.  The input
-// may be a gzip-compressed encoded protobuf or one of many legacy
-// profile formats which may be unsupported in the future.
-func Parse(r io.Reader) (*Profile, error) {
-	orig, err := ioutil.ReadAll(r)
-	if err != nil {
-		return nil, err
-	}
-
-	var p *Profile
-	if len(orig) >= 2 && orig[0] == 0x1f && orig[1] == 0x8b {
-		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)
-		}
-		orig = data
-	}
-	if p, err = parseUncompressed(orig); err != nil {
-		if p, err = parseLegacy(orig); err != nil {
-			return nil, fmt.Errorf("parsing profile: %v", err)
-		}
-	}
-
-	if err := p.CheckValid(); err != nil {
-		return nil, fmt.Errorf("malformed profile: %v", err)
-	}
-	return p, nil
-}
-
-var errUnrecognized = fmt.Errorf("unrecognized profile format")
-var errMalformed = fmt.Errorf("malformed profile format")
-
-func parseLegacy(data []byte) (*Profile, error) {
-	parsers := []func([]byte) (*Profile, error){
-		parseCPU,
-		parseHeap,
-		parseGoCount, // goroutine, threadcreate
-		parseThread,
-		parseContention,
-	}
-
-	for _, parser := range parsers {
-		p, err := parser(data)
-		if err == nil {
-			p.setMain()
-			p.addLegacyFrameInfo()
-			return p, nil
-		}
-		if err != errUnrecognized {
-			return nil, err
-		}
-	}
-	return nil, errUnrecognized
-}
-
-func parseUncompressed(data []byte) (*Profile, error) {
-	p := &Profile{}
-	if err := unmarshal(data, p); err != nil {
-		return nil, err
-	}
-
-	if err := p.postDecode(); err != nil {
-		return nil, err
-	}
-
-	return p, nil
-}
-
-var libRx = regexp.MustCompile(`([.]so$|[.]so[._][0-9]+)`)
-
-// setMain scans Mapping entries and guesses which entry is main
-// because legacy profiles don't obey the convention of putting main
-// first.
-func (p *Profile) setMain() {
-	for i := 0; i < len(p.Mapping); i++ {
-		file := strings.TrimSpace(strings.Replace(p.Mapping[i].File, "(deleted)", "", -1))
-		if len(file) == 0 {
-			continue
-		}
-		if len(libRx.FindStringSubmatch(file)) > 0 {
-			continue
-		}
-		if strings.HasPrefix(file, "[") {
-			continue
-		}
-		// Swap what we guess is main to position 0.
-		tmp := p.Mapping[i]
-		p.Mapping[i] = p.Mapping[0]
-		p.Mapping[0] = tmp
-		break
-	}
-}
-
-// Write writes the profile as a gzip-compressed marshaled protobuf.
-func (p *Profile) Write(w io.Writer) error {
-	p.preEncode()
-	b := marshal(p)
-	zw := gzip.NewWriter(w)
-	defer zw.Close()
-	_, err := zw.Write(b)
-	return err
-}
-
-// CheckValid tests whether the profile is valid.  Checks include, but are
-// not limited to:
-//   - len(Profile.Sample[n].value) == len(Profile.value_unit)
-//   - Sample.id has a corresponding Profile.Location
-func (p *Profile) CheckValid() error {
-	// Check that sample values are consistent
-	sampleLen := len(p.SampleType)
-	if sampleLen == 0 && len(p.Sample) != 0 {
-		return fmt.Errorf("missing sample type information")
-	}
-	for _, s := range p.Sample {
-		if len(s.Value) != sampleLen {
-			return fmt.Errorf("mismatch: sample has: %d values vs. %d types", len(s.Value), len(p.SampleType))
-		}
-	}
-
-	// Check that all mappings/locations/functions are in the tables
-	// Check that there are no duplicate ids
-	mappings := make(map[uint64]*Mapping, len(p.Mapping))
-	for _, m := range p.Mapping {
-		if m.ID == 0 {
-			return fmt.Errorf("found mapping with reserved ID=0")
-		}
-		if mappings[m.ID] != nil {
-			return fmt.Errorf("multiple mappings with same id: %d", m.ID)
-		}
-		mappings[m.ID] = m
-	}
-	functions := make(map[uint64]*Function, len(p.Function))
-	for _, f := range p.Function {
-		if f.ID == 0 {
-			return fmt.Errorf("found function with reserved ID=0")
-		}
-		if functions[f.ID] != nil {
-			return fmt.Errorf("multiple functions with same id: %d", f.ID)
-		}
-		functions[f.ID] = f
-	}
-	locations := make(map[uint64]*Location, len(p.Location))
-	for _, l := range p.Location {
-		if l.ID == 0 {
-			return fmt.Errorf("found location with reserved id=0")
-		}
-		if locations[l.ID] != nil {
-			return fmt.Errorf("multiple locations with same id: %d", l.ID)
-		}
-		locations[l.ID] = l
-		if m := l.Mapping; m != nil {
-			if m.ID == 0 || mappings[m.ID] != m {
-				return fmt.Errorf("inconsistent mapping %p: %d", m, m.ID)
-			}
-		}
-		for _, ln := range l.Line {
-			if f := ln.Function; f != nil {
-				if f.ID == 0 || functions[f.ID] != f {
-					return fmt.Errorf("inconsistent function %p: %d", f, f.ID)
-				}
-			}
-		}
-	}
-	return nil
-}
-
-// Aggregate merges the locations in the profile into equivalence
-// classes preserving the request attributes. It also updates the
-// samples to point to the merged locations.
-func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error {
-	for _, m := range p.Mapping {
-		m.HasInlineFrames = m.HasInlineFrames && inlineFrame
-		m.HasFunctions = m.HasFunctions && function
-		m.HasFilenames = m.HasFilenames && filename
-		m.HasLineNumbers = m.HasLineNumbers && linenumber
-	}
-
-	// Aggregate functions
-	if !function || !filename {
-		for _, f := range p.Function {
-			if !function {
-				f.Name = ""
-				f.SystemName = ""
-			}
-			if !filename {
-				f.Filename = ""
-			}
-		}
-	}
-
-	// Aggregate locations
-	if !inlineFrame || !address || !linenumber {
-		for _, l := range p.Location {
-			if !inlineFrame && len(l.Line) > 1 {
-				l.Line = l.Line[len(l.Line)-1:]
-			}
-			if !linenumber {
-				for i := range l.Line {
-					l.Line[i].Line = 0
-				}
-			}
-			if !address {
-				l.Address = 0
-			}
-		}
-	}
-
-	return p.CheckValid()
-}
-
-// Print dumps a text representation of a profile. Intended mainly
-// for debugging purposes.
-func (p *Profile) String() string {
-
-	ss := make([]string, 0, len(p.Sample)+len(p.Mapping)+len(p.Location))
-	if pt := p.PeriodType; pt != nil {
-		ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit))
-	}
-	ss = append(ss, fmt.Sprintf("Period: %d", p.Period))
-	if p.TimeNanos != 0 {
-		ss = append(ss, fmt.Sprintf("Time: %v", time.Unix(0, p.TimeNanos)))
-	}
-	if p.DurationNanos != 0 {
-		ss = append(ss, fmt.Sprintf("Duration: %v", time.Duration(p.DurationNanos)))
-	}
-
-	ss = append(ss, "Samples:")
-	var sh1 string
-	for _, s := range p.SampleType {
-		sh1 = sh1 + fmt.Sprintf("%s/%s ", s.Type, s.Unit)
-	}
-	ss = append(ss, strings.TrimSpace(sh1))
-	for _, s := range p.Sample {
-		var sv string
-		for _, v := range s.Value {
-			sv = fmt.Sprintf("%s %10d", sv, v)
-		}
-		sv = sv + ": "
-		for _, l := range s.Location {
-			sv = sv + fmt.Sprintf("%d ", l.ID)
-		}
-		ss = append(ss, sv)
-		const labelHeader = "                "
-		if len(s.Label) > 0 {
-			ls := labelHeader
-			for k, v := range s.Label {
-				ls = ls + fmt.Sprintf("%s:%v ", k, v)
-			}
-			ss = append(ss, ls)
-		}
-		if len(s.NumLabel) > 0 {
-			ls := labelHeader
-			for k, v := range s.NumLabel {
-				ls = ls + fmt.Sprintf("%s:%v ", k, v)
-			}
-			ss = append(ss, ls)
-		}
-	}
-
-	ss = append(ss, "Locations")
-	for _, l := range p.Location {
-		locStr := fmt.Sprintf("%6d: %#x ", l.ID, l.Address)
-		if m := l.Mapping; m != nil {
-			locStr = locStr + fmt.Sprintf("M=%d ", m.ID)
-		}
-		if len(l.Line) == 0 {
-			ss = append(ss, locStr)
-		}
-		for li := range l.Line {
-			lnStr := "??"
-			if fn := l.Line[li].Function; fn != nil {
-				lnStr = fmt.Sprintf("%s %s:%d s=%d",
-					fn.Name,
-					fn.Filename,
-					l.Line[li].Line,
-					fn.StartLine)
-				if fn.Name != fn.SystemName {
-					lnStr = lnStr + "(" + fn.SystemName + ")"
-				}
-			}
-			ss = append(ss, locStr+lnStr)
-			// Do not print location details past the first line
-			locStr = "             "
-		}
-	}
-
-	ss = append(ss, "Mappings")
-	for _, m := range p.Mapping {
-		bits := ""
-		if m.HasFunctions {
-			bits = bits + "[FN]"
-		}
-		if m.HasFilenames {
-			bits = bits + "[FL]"
-		}
-		if m.HasLineNumbers {
-			bits = bits + "[LN]"
-		}
-		if m.HasInlineFrames {
-			bits = bits + "[IN]"
-		}
-		ss = append(ss, fmt.Sprintf("%d: %#x/%#x/%#x %s %s %s",
-			m.ID,
-			m.Start, m.Limit, m.Offset,
-			m.File,
-			m.BuildID,
-			bits))
-	}
-
-	return strings.Join(ss, "\n") + "\n"
-}
-
-// Merge adds profile p adjusted by ratio r into profile p. Profiles
-// must be compatible (same Type and SampleType).
-// TODO(rsilvera): consider normalizing the profiles based on the
-// total samples collected.
-func (p *Profile) Merge(pb *Profile, r float64) error {
-	if err := p.Compatible(pb); err != nil {
-		return err
-	}
-
-	pb = pb.Copy()
-
-	// Keep the largest of the two periods.
-	if pb.Period > p.Period {
-		p.Period = pb.Period
-	}
-
-	p.DurationNanos += pb.DurationNanos
-
-	p.Mapping = append(p.Mapping, pb.Mapping...)
-	for i, m := range p.Mapping {
-		m.ID = uint64(i + 1)
-	}
-	p.Location = append(p.Location, pb.Location...)
-	for i, l := range p.Location {
-		l.ID = uint64(i + 1)
-	}
-	p.Function = append(p.Function, pb.Function...)
-	for i, f := range p.Function {
-		f.ID = uint64(i + 1)
-	}
-
-	if r != 1.0 {
-		for _, s := range pb.Sample {
-			for i, v := range s.Value {
-				s.Value[i] = int64((float64(v) * r))
-			}
-		}
-	}
-	p.Sample = append(p.Sample, pb.Sample...)
-	return p.CheckValid()
-}
-
-// Compatible determines if two profiles can be compared/merged.
-// returns nil if the profiles are compatible; otherwise an error with
-// details on the incompatibility.
-func (p *Profile) Compatible(pb *Profile) error {
-	if !compatibleValueTypes(p.PeriodType, pb.PeriodType) {
-		return fmt.Errorf("incompatible period types %v and %v", p.PeriodType, pb.PeriodType)
-	}
-
-	if len(p.SampleType) != len(pb.SampleType) {
-		return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
-	}
-
-	for i := range p.SampleType {
-		if !compatibleValueTypes(p.SampleType[i], pb.SampleType[i]) {
-			return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
-		}
-	}
-
-	return nil
-}
-
-// HasFunctions determines if all locations in this profile have
-// symbolized function information.
-func (p *Profile) HasFunctions() bool {
-	for _, l := range p.Location {
-		if l.Mapping == nil || !l.Mapping.HasFunctions {
-			return false
-		}
-	}
-	return true
-}
-
-// HasFileLines determines if all locations in this profile have
-// symbolized file and line number information.
-func (p *Profile) HasFileLines() bool {
-	for _, l := range p.Location {
-		if l.Mapping == nil || (!l.Mapping.HasFilenames || !l.Mapping.HasLineNumbers) {
-			return false
-		}
-	}
-	return true
-}
-
-func compatibleValueTypes(v1, v2 *ValueType) bool {
-	if v1 == nil || v2 == nil {
-		return true // No grounds to disqualify.
-	}
-	return v1.Type == v2.Type && v1.Unit == v2.Unit
-}
-
-// Copy makes a fully independent copy of a profile.
-func (p *Profile) Copy() *Profile {
-	p.preEncode()
-	b := marshal(p)
-
-	pp := &Profile{}
-	if err := unmarshal(b, pp); err != nil {
-		panic(err)
-	}
-	if err := pp.postDecode(); err != nil {
-		panic(err)
-	}
-
-	return pp
-}
-
-// Demangler maps symbol names to a human-readable form. This may
-// include C++ demangling and additional simplification. Names that
-// are not demangled may be missing from the resulting map.
-type Demangler func(name []string) (map[string]string, error)
-
-// Demangle attempts to demangle and optionally simplify any function
-// names referenced in the profile. It works on a best-effort basis:
-// it will silently preserve the original names in case of any errors.
-func (p *Profile) Demangle(d Demangler) error {
-	// Collect names to demangle.
-	var names []string
-	for _, fn := range p.Function {
-		names = append(names, fn.SystemName)
-	}
-
-	// Update profile with demangled names.
-	demangled, err := d(names)
-	if err != nil {
-		return err
-	}
-	for _, fn := range p.Function {
-		if dd, ok := demangled[fn.SystemName]; ok {
-			fn.Name = dd
-		}
-	}
-	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/proto.go b/src/cmd/pprof/internal/profile/proto.go
deleted file mode 100644
index 475cf56..0000000
--- a/src/cmd/pprof/internal/profile/proto.go
+++ /dev/null
@@ -1,298 +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 is a simple protocol buffer encoder and decoder.
-//
-// A protocol message must implement the message interface:
-//   decoder() []decoder
-//   encode(*buffer)
-//
-// The decode method returns a slice indexed by field number that gives the
-// function to decode that field.
-// The encode method encodes its receiver into the given buffer.
-//
-// The two methods are simple enough to be implemented by hand rather than
-// by using a protocol compiler.
-//
-// See profile.go for examples of messages implementing this interface.
-//
-// There is no support for groups, message sets, or "has" bits.
-
-package profile
-
-import "errors"
-
-type buffer struct {
-	field int
-	typ   int
-	u64   uint64
-	data  []byte
-	tmp   [16]byte
-}
-
-type decoder func(*buffer, message) error
-
-type message interface {
-	decoder() []decoder
-	encode(*buffer)
-}
-
-func marshal(m message) []byte {
-	var b buffer
-	m.encode(&b)
-	return b.data
-}
-
-func encodeVarint(b *buffer, x uint64) {
-	for x >= 128 {
-		b.data = append(b.data, byte(x)|0x80)
-		x >>= 7
-	}
-	b.data = append(b.data, byte(x))
-}
-
-func encodeLength(b *buffer, tag int, len int) {
-	encodeVarint(b, uint64(tag)<<3|2)
-	encodeVarint(b, uint64(len))
-}
-
-func encodeUint64(b *buffer, tag int, x uint64) {
-	// append varint to b.data
-	encodeVarint(b, uint64(tag)<<3|0)
-	encodeVarint(b, x)
-}
-
-func encodeUint64s(b *buffer, tag int, x []uint64) {
-	for _, u := range x {
-		encodeUint64(b, tag, u)
-	}
-}
-
-func encodeUint64Opt(b *buffer, tag int, x uint64) {
-	if x == 0 {
-		return
-	}
-	encodeUint64(b, tag, x)
-}
-
-func encodeInt64(b *buffer, tag int, x int64) {
-	u := uint64(x)
-	encodeUint64(b, tag, u)
-}
-
-func encodeInt64Opt(b *buffer, tag int, x int64) {
-	if x == 0 {
-		return
-	}
-	encodeInt64(b, tag, x)
-}
-
-func encodeString(b *buffer, tag int, x string) {
-	encodeLength(b, tag, len(x))
-	b.data = append(b.data, x...)
-}
-
-func encodeStrings(b *buffer, tag int, x []string) {
-	for _, s := range x {
-		encodeString(b, tag, s)
-	}
-}
-
-func encodeStringOpt(b *buffer, tag int, x string) {
-	if x == "" {
-		return
-	}
-	encodeString(b, tag, x)
-}
-
-func encodeBool(b *buffer, tag int, x bool) {
-	if x {
-		encodeUint64(b, tag, 1)
-	} else {
-		encodeUint64(b, tag, 0)
-	}
-}
-
-func encodeBoolOpt(b *buffer, tag int, x bool) {
-	if x == false {
-		return
-	}
-	encodeBool(b, tag, x)
-}
-
-func encodeMessage(b *buffer, tag int, m message) {
-	n1 := len(b.data)
-	m.encode(b)
-	n2 := len(b.data)
-	encodeLength(b, tag, n2-n1)
-	n3 := len(b.data)
-	copy(b.tmp[:], b.data[n2:n3])
-	copy(b.data[n1+(n3-n2):], b.data[n1:n2])
-	copy(b.data[n1:], b.tmp[:n3-n2])
-}
-
-func unmarshal(data []byte, m message) (err error) {
-	b := buffer{data: data, typ: 2}
-	return decodeMessage(&b, m)
-}
-
-func le64(p []byte) uint64 {
-	return uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
-}
-
-func le32(p []byte) uint32 {
-	return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
-}
-
-func decodeVarint(data []byte) (uint64, []byte, error) {
-	var i int
-	var u uint64
-	for i = 0; ; i++ {
-		if i >= 10 || i >= len(data) {
-			return 0, nil, errors.New("bad varint")
-		}
-		u |= uint64(data[i]&0x7F) << uint(7*i)
-		if data[i]&0x80 == 0 {
-			return u, data[i+1:], nil
-		}
-	}
-}
-
-func decodeField(b *buffer, data []byte) ([]byte, error) {
-	x, data, err := decodeVarint(data)
-	if err != nil {
-		return nil, err
-	}
-	b.field = int(x >> 3)
-	b.typ = int(x & 7)
-	b.data = nil
-	b.u64 = 0
-	switch b.typ {
-	case 0:
-		b.u64, data, err = decodeVarint(data)
-		if err != nil {
-			return nil, err
-		}
-	case 1:
-		if len(data) < 8 {
-			return nil, errors.New("not enough data")
-		}
-		b.u64 = le64(data[:8])
-		data = data[8:]
-	case 2:
-		var n uint64
-		n, data, err = decodeVarint(data)
-		if err != nil {
-			return nil, err
-		}
-		if n > uint64(len(data)) {
-			return nil, errors.New("too much data")
-		}
-		b.data = data[:n]
-		data = data[n:]
-	case 5:
-		if len(data) < 4 {
-			return nil, errors.New("not enough data")
-		}
-		b.u64 = uint64(le32(data[:4]))
-		data = data[4:]
-	default:
-		return nil, errors.New("unknown type: " + string(b.typ))
-	}
-
-	return data, nil
-}
-
-func checkType(b *buffer, typ int) error {
-	if b.typ != typ {
-		return errors.New("type mismatch")
-	}
-	return nil
-}
-
-func decodeMessage(b *buffer, m message) error {
-	if err := checkType(b, 2); err != nil {
-		return err
-	}
-	dec := m.decoder()
-	data := b.data
-	for len(data) > 0 {
-		// pull varint field# + type
-		var err error
-		data, err = decodeField(b, data)
-		if err != nil {
-			return err
-		}
-		if b.field >= len(dec) || dec[b.field] == nil {
-			continue
-		}
-		if err := dec[b.field](b, m); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func decodeInt64(b *buffer, x *int64) error {
-	if err := checkType(b, 0); err != nil {
-		return err
-	}
-	*x = int64(b.u64)
-	return nil
-}
-
-func decodeInt64s(b *buffer, x *[]int64) error {
-	var i int64
-	if err := decodeInt64(b, &i); err != nil {
-		return err
-	}
-	*x = append(*x, i)
-	return nil
-}
-
-func decodeUint64(b *buffer, x *uint64) error {
-	if err := checkType(b, 0); err != nil {
-		return err
-	}
-	*x = b.u64
-	return nil
-}
-
-func decodeUint64s(b *buffer, x *[]uint64) error {
-	var u uint64
-	if err := decodeUint64(b, &u); err != nil {
-		return err
-	}
-	*x = append(*x, u)
-	return nil
-}
-
-func decodeString(b *buffer, x *string) error {
-	if err := checkType(b, 2); err != nil {
-		return err
-	}
-	*x = string(b.data)
-	return nil
-}
-
-func decodeStrings(b *buffer, x *[]string) error {
-	var s string
-	if err := decodeString(b, &s); err != nil {
-		return err
-	}
-	*x = append(*x, s)
-	return nil
-}
-
-func decodeBool(b *buffer, x *bool) error {
-	if err := checkType(b, 0); err != nil {
-		return err
-	}
-	if int64(b.u64) == 0 {
-		*x = false
-	} else {
-		*x = true
-	}
-	return nil
-}
diff --git a/src/cmd/pprof/internal/profile/prune.go b/src/cmd/pprof/internal/profile/prune.go
deleted file mode 100644
index abc898c..0000000
--- a/src/cmd/pprof/internal/profile/prune.go
+++ /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.
-
-// Implements methods to remove frames from profiles.
-
-package profile
-
-import (
-	"fmt"
-	"regexp"
-)
-
-// Prune removes all nodes beneath a node matching dropRx, and not
-// matching keepRx.  If the root node of a Sample matches, the sample
-// will have an empty stack.
-func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
-	prune := make(map[uint64]bool)
-	pruneBeneath := make(map[uint64]bool)
-
-	for _, loc := range p.Location {
-		var i int
-		for i = len(loc.Line) - 1; i >= 0; i-- {
-			if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
-				funcName := fn.Name
-				// Account for leading '.' on the PPC ELF v1 ABI.
-				if funcName[0] == '.' {
-					funcName = funcName[1:]
-				}
-				if dropRx.MatchString(funcName) {
-					if keepRx == nil || !keepRx.MatchString(funcName) {
-						break
-					}
-				}
-			}
-		}
-
-		if i >= 0 {
-			// Found matching entry to prune.
-			pruneBeneath[loc.ID] = true
-
-			// Remove the matching location.
-			if i == len(loc.Line)-1 {
-				// Matched the top entry: prune the whole location.
-				prune[loc.ID] = true
-			} else {
-				loc.Line = loc.Line[i+1:]
-			}
-		}
-	}
-
-	// Prune locs from each Sample
-	for _, sample := range p.Sample {
-		// Scan from the root to the leaves to find the prune location.
-		// Do not prune frames before the first user frame, to avoid
-		// pruning everything.
-		foundUser := false
-		for i := len(sample.Location) - 1; i >= 0; i-- {
-			id := sample.Location[i].ID
-			if !prune[id] && !pruneBeneath[id] {
-				foundUser = true
-				continue
-			}
-			if !foundUser {
-				continue
-			}
-			if prune[id] {
-				sample.Location = sample.Location[i+1:]
-				break
-			}
-			if pruneBeneath[id] {
-				sample.Location = sample.Location[i:]
-				break
-			}
-		}
-	}
-}
-
-// RemoveUninteresting prunes and elides profiles using built-in
-// tables of uninteresting function names.
-func (p *Profile) RemoveUninteresting() error {
-	var keep, drop *regexp.Regexp
-	var err error
-
-	if p.DropFrames != "" {
-		if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil {
-			return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err)
-		}
-		if p.KeepFrames != "" {
-			if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil {
-				return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err)
-			}
-		}
-		p.Prune(drop, keep)
-	}
-	return nil
-}
diff --git a/src/cmd/pprof/internal/report/report.go b/src/cmd/pprof/internal/report/report.go
deleted file mode 100644
index 0265e23..0000000
--- a/src/cmd/pprof/internal/report/report.go
+++ /dev/null
@@ -1,1718 +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 report summarizes a performance profile into a
-// human-readable report.
-package report
-
-import (
-	"fmt"
-	"io"
-	"math"
-	"os"
-	"path/filepath"
-	"regexp"
-	"sort"
-	"strconv"
-	"strings"
-	"time"
-
-	"cmd/pprof/internal/plugin"
-	"cmd/pprof/internal/profile"
-)
-
-// Generate generates a report as directed by the Report.
-func Generate(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
-	o := rpt.options
-
-	switch o.OutputFormat {
-	case Dot:
-		return printDOT(w, rpt)
-	case Tree:
-		return printTree(w, rpt)
-	case Text:
-		return printText(w, rpt)
-	case Raw:
-		fmt.Fprint(w, rpt.prof.String())
-		return nil
-	case Tags:
-		return printTags(w, rpt)
-	case Proto:
-		return rpt.prof.Write(w)
-	case Dis:
-		return printAssembly(w, rpt, obj)
-	case List:
-		return printSource(w, rpt)
-	case WebList:
-		return printWebSource(w, rpt, obj)
-	case Callgrind:
-		return printCallgrind(w, rpt)
-	}
-	return fmt.Errorf("unexpected output format")
-}
-
-// printAssembly prints an annotated assembly listing.
-func printAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
-	g, err := newGraph(rpt)
-	if err != nil {
-		return err
-	}
-
-	o := rpt.options
-	prof := rpt.prof
-
-	// If the regexp source can be parsed as an address, also match
-	// functions that land on that address.
-	var address *uint64
-	if hex, err := strconv.ParseUint(o.Symbol.String(), 0, 64); err == nil {
-		address = &hex
-	}
-
-	fmt.Fprintln(w, "Total:", rpt.formatValue(rpt.total))
-	symbols := symbolsFromBinaries(prof, g, o.Symbol, address, obj)
-	symNodes := nodesPerSymbol(g.ns, symbols)
-	// Sort function names for printing.
-	var syms objSymbols
-	for s := range symNodes {
-		syms = append(syms, s)
-	}
-	sort.Sort(syms)
-
-	// Correlate the symbols from the binary with the profile samples.
-	for _, s := range syms {
-		sns := symNodes[s]
-
-		// Gather samples for this symbol.
-		flatSum, cumSum := sumNodes(sns)
-
-		// Get the function assembly.
-		insns, err := obj.Disasm(s.sym.File, s.sym.Start, s.sym.End)
-		if err != nil {
-			return err
-		}
-
-		ns := annotateAssembly(insns, sns, s.base)
-
-		fmt.Fprintf(w, "ROUTINE ======================== %s\n", s.sym.Name[0])
-		for _, name := range s.sym.Name[1:] {
-			fmt.Fprintf(w, "    AKA ======================== %s\n", name)
-		}
-		fmt.Fprintf(w, "%10s %10s (flat, cum) %s of Total\n",
-			rpt.formatValue(flatSum), rpt.formatValue(cumSum),
-			percentage(cumSum, rpt.total))
-
-		for _, n := range ns {
-			fmt.Fprintf(w, "%10s %10s %10x: %s\n", valueOrDot(n.flat, rpt), valueOrDot(n.cum, rpt), n.info.address, n.info.name)
-		}
-	}
-	return nil
-}
-
-// symbolsFromBinaries examines the binaries listed on the profile
-// that have associated samples, and identifies symbols matching rx.
-func symbolsFromBinaries(prof *profile.Profile, g graph, rx *regexp.Regexp, address *uint64, obj plugin.ObjTool) []*objSymbol {
-	hasSamples := make(map[string]bool)
-	// Only examine mappings that have samples that match the
-	// regexp. This is an optimization to speed up pprof.
-	for _, n := range g.ns {
-		if name := n.info.prettyName(); rx.MatchString(name) && n.info.objfile != "" {
-			hasSamples[n.info.objfile] = true
-		}
-	}
-
-	// Walk all mappings looking for matching functions with samples.
-	var objSyms []*objSymbol
-	for _, m := range prof.Mapping {
-		if !hasSamples[filepath.Base(m.File)] {
-			if address == nil || !(m.Start <= *address && *address <= m.Limit) {
-				continue
-			}
-		}
-
-		f, err := obj.Open(m.File, m.Start)
-		if err != nil {
-			fmt.Printf("%v\n", err)
-			continue
-		}
-
-		// Find symbols in this binary matching the user regexp.
-		var addr uint64
-		if address != nil {
-			addr = *address
-		}
-		msyms, err := f.Symbols(rx, addr)
-		base := f.Base()
-		f.Close()
-		if err != nil {
-			continue
-		}
-		for _, ms := range msyms {
-			objSyms = append(objSyms,
-				&objSymbol{
-					sym:  ms,
-					base: base,
-				},
-			)
-		}
-	}
-
-	return objSyms
-}
-
-// objSym represents a symbol identified from a binary. It includes
-// the SymbolInfo from the disasm package and the base that must be
-// added to correspond to sample addresses
-type objSymbol struct {
-	sym  *plugin.Sym
-	base uint64
-}
-
-// objSymbols is a wrapper type to enable sorting of []*objSymbol.
-type objSymbols []*objSymbol
-
-func (o objSymbols) Len() int {
-	return len(o)
-}
-
-func (o objSymbols) Less(i, j int) bool {
-	if namei, namej := o[i].sym.Name[0], o[j].sym.Name[0]; namei != namej {
-		return namei < namej
-	}
-	return o[i].sym.Start < o[j].sym.Start
-}
-
-func (o objSymbols) Swap(i, j int) {
-	o[i], o[j] = o[j], o[i]
-}
-
-// nodesPerSymbol classifies nodes into a group of symbols.
-func nodesPerSymbol(ns nodes, symbols []*objSymbol) map[*objSymbol]nodes {
-	symNodes := make(map[*objSymbol]nodes)
-	for _, s := range symbols {
-		// Gather samples for this symbol.
-		for _, n := range ns {
-			address := n.info.address - s.base
-			if address >= s.sym.Start && address < s.sym.End {
-				symNodes[s] = append(symNodes[s], n)
-			}
-		}
-	}
-	return symNodes
-}
-
-// annotateAssembly annotates a set of assembly instructions with a
-// set of samples. It returns a set of nodes to display.  base is an
-// offset to adjust the sample addresses.
-func annotateAssembly(insns []plugin.Inst, samples nodes, base uint64) nodes {
-	// Add end marker to simplify printing loop.
-	insns = append(insns, plugin.Inst{^uint64(0), "", "", 0})
-
-	// Ensure samples are sorted by address.
-	samples.sort(addressOrder)
-
-	var s int
-	var asm nodes
-	for ix, in := range insns[:len(insns)-1] {
-		n := node{
-			info: nodeInfo{
-				address: in.Addr,
-				name:    in.Text,
-				file:    trimPath(in.File),
-				lineno:  in.Line,
-			},
-		}
-
-		// Sum all the samples until the next instruction (to account
-		// for samples attributed to the middle of an instruction).
-		for next := insns[ix+1].Addr; s < len(samples) && samples[s].info.address-base < next; s++ {
-			n.flat += samples[s].flat
-			n.cum += samples[s].cum
-			if samples[s].info.file != "" {
-				n.info.file = trimPath(samples[s].info.file)
-				n.info.lineno = samples[s].info.lineno
-			}
-		}
-		asm = append(asm, &n)
-	}
-
-	return asm
-}
-
-// valueOrDot formats a value according to a report, intercepting zero
-// values.
-func valueOrDot(value int64, rpt *Report) string {
-	if value == 0 {
-		return "."
-	}
-	return rpt.formatValue(value)
-}
-
-// canAccessFile determines if the filename can be opened for reading.
-func canAccessFile(path string) bool {
-	if fi, err := os.Stat(path); err == nil {
-		return fi.Mode().Perm()&0400 != 0
-	}
-	return false
-}
-
-// printTags collects all tags referenced in the profile and prints
-// them in a sorted table.
-func printTags(w io.Writer, rpt *Report) error {
-	p := rpt.prof
-
-	// Hashtable to keep accumulate tags as key,value,count.
-	tagMap := make(map[string]map[string]int64)
-	for _, s := range p.Sample {
-		for key, vals := range s.Label {
-			for _, val := range vals {
-				if valueMap, ok := tagMap[key]; ok {
-					valueMap[val] = valueMap[val] + s.Value[0]
-					continue
-				}
-				valueMap := make(map[string]int64)
-				valueMap[val] = s.Value[0]
-				tagMap[key] = valueMap
-			}
-		}
-		for key, vals := range s.NumLabel {
-			for _, nval := range vals {
-				val := scaledValueLabel(nval, key, "auto")
-				if valueMap, ok := tagMap[key]; ok {
-					valueMap[val] = valueMap[val] + s.Value[0]
-					continue
-				}
-				valueMap := make(map[string]int64)
-				valueMap[val] = s.Value[0]
-				tagMap[key] = valueMap
-			}
-		}
-	}
-
-	tagKeys := make(tags, 0, len(tagMap))
-	for key := range tagMap {
-		tagKeys = append(tagKeys, &tag{name: key})
-	}
-	sort.Sort(tagKeys)
-
-	for _, tagKey := range tagKeys {
-		var total int64
-		key := tagKey.name
-		tags := make(tags, 0, len(tagMap[key]))
-		for t, c := range tagMap[key] {
-			total += c
-			tags = append(tags, &tag{name: t, weight: c})
-		}
-
-		sort.Sort(tags)
-		fmt.Fprintf(w, "%s: Total %d\n", key, total)
-		for _, t := range tags {
-			if total > 0 {
-				fmt.Fprintf(w, "  %8d (%s): %s\n", t.weight,
-					percentage(t.weight, total), t.name)
-			} else {
-				fmt.Fprintf(w, "  %8d: %s\n", t.weight, t.name)
-			}
-		}
-		fmt.Fprintln(w)
-	}
-	return nil
-}
-
-// printText prints a flat text report for a profile.
-func printText(w io.Writer, rpt *Report) error {
-	g, err := newGraph(rpt)
-	if err != nil {
-		return err
-	}
-
-	origCount, droppedNodes, _ := g.preprocess(rpt)
-	fmt.Fprintln(w, strings.Join(legendDetailLabels(rpt, g, origCount, droppedNodes, 0), "\n"))
-
-	fmt.Fprintf(w, "%10s %5s%% %5s%% %10s %5s%%\n",
-		"flat", "flat", "sum", "cum", "cum")
-
-	var flatSum int64
-	for _, n := range g.ns {
-		name, flat, cum := n.info.prettyName(), n.flat, n.cum
-
-		flatSum += flat
-		fmt.Fprintf(w, "%10s %s %s %10s %s  %s\n",
-			rpt.formatValue(flat),
-			percentage(flat, rpt.total),
-			percentage(flatSum, rpt.total),
-			rpt.formatValue(cum),
-			percentage(cum, rpt.total),
-			name)
-	}
-	return nil
-}
-
-// printCallgrind prints a graph for a profile on callgrind format.
-func printCallgrind(w io.Writer, rpt *Report) error {
-	g, err := newGraph(rpt)
-	if err != nil {
-		return err
-	}
-
-	o := rpt.options
-	rpt.options.NodeFraction = 0
-	rpt.options.EdgeFraction = 0
-	rpt.options.NodeCount = 0
-
-	g.preprocess(rpt)
-
-	fmt.Fprintln(w, "events:", o.SampleType+"("+o.OutputUnit+")")
-
-	files := make(map[string]int)
-	names := make(map[string]int)
-	for _, n := range g.ns {
-		fmt.Fprintln(w, "fl="+callgrindName(files, n.info.file))
-		fmt.Fprintln(w, "fn="+callgrindName(names, n.info.name))
-		sv, _ := ScaleValue(n.flat, o.SampleUnit, o.OutputUnit)
-		fmt.Fprintf(w, "%d %d\n", n.info.lineno, int(sv))
-
-		// Print outgoing edges.
-		for _, out := range sortedEdges(n.out) {
-			c, _ := ScaleValue(out.weight, o.SampleUnit, o.OutputUnit)
-			count := fmt.Sprintf("%d", int(c))
-			callee := out.dest
-			fmt.Fprintln(w, "cfl="+callgrindName(files, callee.info.file))
-			fmt.Fprintln(w, "cfn="+callgrindName(names, callee.info.name))
-			fmt.Fprintln(w, "calls="+count, callee.info.lineno)
-			fmt.Fprintln(w, n.info.lineno, count)
-		}
-		fmt.Fprintln(w)
-	}
-
-	return nil
-}
-
-// callgrindName implements the callgrind naming compression scheme.
-// For names not previously seen returns "(N) name", where N is a
-// unique index.  For names previously seen returns "(N)" where N is
-// the index returned the first time.
-func callgrindName(names map[string]int, name string) string {
-	if name == "" {
-		return ""
-	}
-	if id, ok := names[name]; ok {
-		return fmt.Sprintf("(%d)", id)
-	}
-	id := len(names) + 1
-	names[name] = id
-	return fmt.Sprintf("(%d) %s", id, name)
-}
-
-// printTree prints a tree-based report in text form.
-func printTree(w io.Writer, rpt *Report) error {
-	const separator = "----------------------------------------------------------+-------------"
-	const legend = "      flat  flat%   sum%        cum   cum%   calls calls% + context 	 	 "
-
-	g, err := newGraph(rpt)
-	if err != nil {
-		return err
-	}
-
-	origCount, droppedNodes, _ := g.preprocess(rpt)
-	fmt.Fprintln(w, strings.Join(legendDetailLabels(rpt, g, origCount, droppedNodes, 0), "\n"))
-
-	fmt.Fprintln(w, separator)
-	fmt.Fprintln(w, legend)
-	var flatSum int64
-
-	rx := rpt.options.Symbol
-	for _, n := range g.ns {
-		name, flat, cum := n.info.prettyName(), n.flat, n.cum
-
-		// Skip any entries that do not match the regexp (for the "peek" command).
-		if rx != nil && !rx.MatchString(name) {
-			continue
-		}
-
-		fmt.Fprintln(w, separator)
-		// Print incoming edges.
-		inEdges := sortedEdges(n.in)
-		inSum := inEdges.sum()
-		for _, in := range inEdges {
-			fmt.Fprintf(w, "%50s %s |   %s\n", rpt.formatValue(in.weight),
-				percentage(in.weight, inSum), in.src.info.prettyName())
-		}
-
-		// Print current node.
-		flatSum += flat
-		fmt.Fprintf(w, "%10s %s %s %10s %s                | %s\n",
-			rpt.formatValue(flat),
-			percentage(flat, rpt.total),
-			percentage(flatSum, rpt.total),
-			rpt.formatValue(cum),
-			percentage(cum, rpt.total),
-			name)
-
-		// Print outgoing edges.
-		outEdges := sortedEdges(n.out)
-		outSum := outEdges.sum()
-		for _, out := range outEdges {
-			fmt.Fprintf(w, "%50s %s |   %s\n", rpt.formatValue(out.weight),
-				percentage(out.weight, outSum), out.dest.info.prettyName())
-		}
-	}
-	if len(g.ns) > 0 {
-		fmt.Fprintln(w, separator)
-	}
-	return nil
-}
-
-// printDOT prints an annotated callgraph in DOT format.
-func printDOT(w io.Writer, rpt *Report) error {
-	g, err := newGraph(rpt)
-	if err != nil {
-		return err
-	}
-
-	origCount, droppedNodes, droppedEdges := g.preprocess(rpt)
-
-	prof := rpt.prof
-	graphname := "unnamed"
-	if len(prof.Mapping) > 0 {
-		graphname = filepath.Base(prof.Mapping[0].File)
-	}
-	fmt.Fprintln(w, `digraph "`+graphname+`" {`)
-	fmt.Fprintln(w, `node [style=filled fillcolor="#f8f8f8"]`)
-	fmt.Fprintln(w, dotLegend(rpt, g, origCount, droppedNodes, droppedEdges))
-
-	if len(g.ns) == 0 {
-		fmt.Fprintln(w, "}")
-		return nil
-	}
-
-	// Make sure nodes have a unique consistent id.
-	nodeIndex := make(map[*node]int)
-	maxFlat := float64(g.ns[0].flat)
-	for i, n := range g.ns {
-		nodeIndex[n] = i + 1
-		if float64(n.flat) > maxFlat {
-			maxFlat = float64(n.flat)
-		}
-	}
-	var edges edgeList
-	for _, n := range g.ns {
-		node := dotNode(rpt, maxFlat, nodeIndex[n], n)
-		fmt.Fprintln(w, node)
-		if nodelets := dotNodelets(rpt, nodeIndex[n], n); nodelets != "" {
-			fmt.Fprint(w, nodelets)
-		}
-
-		// Collect outgoing edges.
-		for _, e := range n.out {
-			edges = append(edges, e)
-		}
-	}
-	// Sort edges by frequency as a hint to the graph layout engine.
-	sort.Sort(edges)
-	for _, e := range edges {
-		fmt.Fprintln(w, dotEdge(rpt, nodeIndex[e.src], nodeIndex[e.dest], e))
-	}
-	fmt.Fprintln(w, "}")
-	return nil
-}
-
-// percentage computes the percentage of total of a value, and encodes
-// it as a string. At least two digits of precision are printed.
-func percentage(value, total int64) string {
-	var ratio float64
-	if total != 0 {
-		ratio = float64(value) / float64(total) * 100
-	}
-	switch {
-	case ratio >= 99.95:
-		return "  100%"
-	case ratio >= 1.0:
-		return fmt.Sprintf("%5.2f%%", ratio)
-	default:
-		return fmt.Sprintf("%5.2g%%", ratio)
-	}
-}
-
-// dotLegend generates the overall graph label for a report in DOT format.
-func dotLegend(rpt *Report, g graph, origCount, droppedNodes, droppedEdges int) string {
-	label := legendLabels(rpt)
-	label = append(label, legendDetailLabels(rpt, g, origCount, droppedNodes, droppedEdges)...)
-	return fmt.Sprintf(`subgraph cluster_L { L [shape=box fontsize=32 label="%s\l"] }`, strings.Join(label, `\l`))
-}
-
-// legendLabels generates labels exclusive to graph visualization.
-func legendLabels(rpt *Report) []string {
-	prof := rpt.prof
-	o := rpt.options
-	var label []string
-	if len(prof.Mapping) > 0 {
-		if prof.Mapping[0].File != "" {
-			label = append(label, "File: "+filepath.Base(prof.Mapping[0].File))
-		}
-		if prof.Mapping[0].BuildID != "" {
-			label = append(label, "Build ID: "+prof.Mapping[0].BuildID)
-		}
-	}
-	if o.SampleType != "" {
-		label = append(label, "Type: "+o.SampleType)
-	}
-	if prof.TimeNanos != 0 {
-		const layout = "Jan 2, 2006 at 3:04pm (MST)"
-		label = append(label, "Time: "+time.Unix(0, prof.TimeNanos).Format(layout))
-	}
-	if prof.DurationNanos != 0 {
-		label = append(label, fmt.Sprintf("Duration: %v", time.Duration(prof.DurationNanos)))
-	}
-	return label
-}
-
-// legendDetailLabels generates labels common to graph and text visualization.
-func legendDetailLabels(rpt *Report, g graph, origCount, droppedNodes, droppedEdges int) []string {
-	nodeFraction := rpt.options.NodeFraction
-	edgeFraction := rpt.options.EdgeFraction
-	nodeCount := rpt.options.NodeCount
-
-	label := []string{}
-
-	var flatSum int64
-	for _, n := range g.ns {
-		flatSum = flatSum + n.flat
-	}
-
-	label = append(label, fmt.Sprintf("%s of %s total (%s)", rpt.formatValue(flatSum), rpt.formatValue(rpt.total), percentage(flatSum, rpt.total)))
-
-	if rpt.total > 0 {
-		if droppedNodes > 0 {
-			label = append(label, genLabel(droppedNodes, "node", "cum",
-				rpt.formatValue(int64(float64(rpt.total)*nodeFraction))))
-		}
-		if droppedEdges > 0 {
-			label = append(label, genLabel(droppedEdges, "edge", "freq",
-				rpt.formatValue(int64(float64(rpt.total)*edgeFraction))))
-		}
-		if nodeCount > 0 && nodeCount < origCount {
-			label = append(label, fmt.Sprintf("Showing top %d nodes out of %d (cum >= %s)",
-				nodeCount, origCount,
-				rpt.formatValue(g.ns[len(g.ns)-1].cum)))
-		}
-	}
-	return label
-}
-
-func genLabel(d int, n, l, f string) string {
-	if d > 1 {
-		n = n + "s"
-	}
-	return fmt.Sprintf("Dropped %d %s (%s <= %s)", d, n, l, f)
-}
-
-// dotNode generates a graph node in DOT format.
-func dotNode(rpt *Report, maxFlat float64, rIndex int, n *node) string {
-	flat, cum := n.flat, n.cum
-
-	labels := strings.Split(n.info.prettyName(), "::")
-	label := strings.Join(labels, `\n`) + `\n`
-
-	flatValue := rpt.formatValue(flat)
-	if flat > 0 {
-		label = label + fmt.Sprintf(`%s(%s)`,
-			flatValue,
-			strings.TrimSpace(percentage(flat, rpt.total)))
-	} else {
-		label = label + "0"
-	}
-	cumValue := flatValue
-	if cum != flat {
-		if flat > 0 {
-			label = label + `\n`
-		} else {
-			label = label + " "
-		}
-		cumValue = rpt.formatValue(cum)
-		label = label + fmt.Sprintf(`of %s(%s)`,
-			cumValue,
-			strings.TrimSpace(percentage(cum, rpt.total)))
-	}
-
-	// Scale font sizes from 8 to 24 based on percentage of flat frequency.
-	// Use non linear growth to emphasize the size difference.
-	baseFontSize, maxFontGrowth := 8, 16.0
-	fontSize := baseFontSize
-	if maxFlat > 0 && flat > 0 && float64(flat) <= maxFlat {
-		fontSize += int(math.Ceil(maxFontGrowth * math.Sqrt(float64(flat)/maxFlat)))
-	}
-	return fmt.Sprintf(`N%d [label="%s" fontsize=%d shape=box tooltip="%s (%s)"]`,
-		rIndex,
-		label,
-		fontSize, n.info.prettyName(), cumValue)
-}
-
-// dotEdge generates a graph edge in DOT format.
-func dotEdge(rpt *Report, from, to int, e *edgeInfo) string {
-	w := rpt.formatValue(e.weight)
-	attr := fmt.Sprintf(`label=" %s"`, w)
-	if rpt.total > 0 {
-		if weight := 1 + int(e.weight*100/rpt.total); weight > 1 {
-			attr = fmt.Sprintf(`%s weight=%d`, attr, weight)
-		}
-		if width := 1 + int(e.weight*5/rpt.total); width > 1 {
-			attr = fmt.Sprintf(`%s penwidth=%d`, attr, width)
-		}
-	}
-	arrow := "->"
-	if e.residual {
-		arrow = "..."
-	}
-	tooltip := fmt.Sprintf(`"%s %s %s (%s)"`,
-		e.src.info.prettyName(), arrow, e.dest.info.prettyName(), w)
-	attr = fmt.Sprintf(`%s tooltip=%s labeltooltip=%s`,
-		attr, tooltip, tooltip)
-
-	if e.residual {
-		attr = attr + ` style="dotted"`
-	}
-
-	if len(e.src.tags) > 0 {
-		// Separate children further if source has tags.
-		attr = attr + " minlen=2"
-	}
-	return fmt.Sprintf("N%d -> N%d [%s]", from, to, attr)
-}
-
-// dotNodelets generates the DOT boxes for the node tags.
-func dotNodelets(rpt *Report, rIndex int, n *node) (dot string) {
-	const maxNodelets = 4    // Number of nodelets for alphanumeric labels
-	const maxNumNodelets = 4 // Number of nodelets for numeric labels
-
-	var ts, nts tags
-	for _, t := range n.tags {
-		if t.unit == "" {
-			ts = append(ts, t)
-		} else {
-			nts = append(nts, t)
-		}
-	}
-
-	// Select the top maxNodelets alphanumeric labels by weight
-	sort.Sort(ts)
-	if len(ts) > maxNodelets {
-		ts = ts[:maxNodelets]
-	}
-	for i, t := range ts {
-		weight := rpt.formatValue(t.weight)
-		dot += fmt.Sprintf(`N%d_%d [label = "%s" fontsize=8 shape=box3d tooltip="%s"]`+"\n", rIndex, i, t.name, weight)
-		dot += fmt.Sprintf(`N%d -> N%d_%d [label=" %s" weight=100 tooltip="\L" labeltooltip="\L"]`+"\n", rIndex, rIndex, i, weight)
-	}
-
-	// Collapse numeric labels into maxNumNodelets buckets, of the form:
-	// 1MB..2MB, 3MB..5MB, ...
-	nts = collapseTags(nts, maxNumNodelets)
-	sort.Sort(nts)
-	for i, t := range nts {
-		weight := rpt.formatValue(t.weight)
-		dot += fmt.Sprintf(`NN%d_%d [label = "%s" fontsize=8 shape=box3d tooltip="%s"]`+"\n", rIndex, i, t.name, weight)
-		dot += fmt.Sprintf(`N%d -> NN%d_%d [label=" %s" weight=100 tooltip="\L" labeltooltip="\L"]`+"\n", rIndex, rIndex, i, weight)
-	}
-
-	return dot
-}
-
-// graph summarizes a performance profile into a format that is
-// suitable for visualization.
-type graph struct {
-	ns nodes
-}
-
-// nodes is an ordered collection of graph nodes.
-type nodes []*node
-
-// tags represent sample annotations
-type tags []*tag
-type tagMap map[string]*tag
-
-type tag struct {
-	name   string
-	unit   string // Describe the value, "" for non-numeric tags
-	value  int64
-	weight int64
-}
-
-func (t tags) Len() int      { return len(t) }
-func (t tags) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
-func (t tags) Less(i, j int) bool {
-	if t[i].weight == t[j].weight {
-		return t[i].name < t[j].name
-	}
-	return t[i].weight > t[j].weight
-}
-
-// node is an entry on a profiling report. It represents a unique
-// program location. It can include multiple names to represent
-// inlined functions.
-type node struct {
-	info nodeInfo // Information associated to this entry.
-
-	// values associated to this node.
-	// flat is exclusive to this node, cum includes all descendents.
-	flat, cum int64
-
-	// in and out contains the nodes immediately reaching or reached by this nodes.
-	in, out edgeMap
-
-	// tags provide additional information about subsets of a sample.
-	tags tagMap
-}
-
-func (ts tags) string() string {
-	var ret string
-	for _, s := range ts {
-		ret = ret + fmt.Sprintf("%s %s %d %d\n", s.name, s.unit, s.value, s.weight)
-	}
-	return ret
-}
-
-type nodeInfo struct {
-	name              string
-	origName          string
-	address           uint64
-	file              string
-	startLine, lineno int
-	inline            bool
-	lowPriority       bool
-	objfile           string
-	parent            *node // Used only if creating a calltree
-}
-
-func (n *node) addTags(s *profile.Sample, weight int64) {
-	// Add a tag with all string labels
-	var labels []string
-	for key, vals := range s.Label {
-		for _, v := range vals {
-			labels = append(labels, key+":"+v)
-		}
-	}
-	if len(labels) > 0 {
-		sort.Strings(labels)
-		l := n.tags.findOrAddTag(strings.Join(labels, `\n`), "", 0)
-		l.weight += weight
-	}
-
-	for key, nvals := range s.NumLabel {
-		for _, v := range nvals {
-			label := scaledValueLabel(v, key, "auto")
-			l := n.tags.findOrAddTag(label, key, v)
-			l.weight += weight
-		}
-	}
-}
-
-func (m tagMap) findOrAddTag(label, unit string, value int64) *tag {
-	if l := m[label]; l != nil {
-		return l
-	}
-	l := &tag{
-		name:  label,
-		unit:  unit,
-		value: value,
-	}
-	m[label] = l
-	return l
-}
-
-// collapseTags reduces the number of entries in a tagMap by merging
-// adjacent nodes into ranges. It uses a greedy approach to merge
-// starting with the entries with the lowest weight.
-func collapseTags(ts tags, count int) tags {
-	if len(ts) <= count {
-		return ts
-	}
-
-	sort.Sort(ts)
-	tagGroups := make([]tags, count)
-	for i, t := range ts[:count] {
-		tagGroups[i] = tags{t}
-	}
-	for _, t := range ts[count:] {
-		g, d := 0, tagDistance(t, tagGroups[0][0])
-		for i := 1; i < count; i++ {
-			if nd := tagDistance(t, tagGroups[i][0]); nd < d {
-				g, d = i, nd
-			}
-		}
-		tagGroups[g] = append(tagGroups[g], t)
-	}
-
-	var nts tags
-	for _, g := range tagGroups {
-		l, w := tagGroupLabel(g)
-		nts = append(nts, &tag{
-			name:   l,
-			weight: w,
-		})
-	}
-	return nts
-}
-
-func tagDistance(t, u *tag) float64 {
-	v, _ := ScaleValue(u.value, u.unit, t.unit)
-	if v < float64(t.value) {
-		return float64(t.value) - v
-	}
-	return v - float64(t.value)
-}
-
-func tagGroupLabel(g tags) (string, int64) {
-	if len(g) == 1 {
-		t := g[0]
-		return scaledValueLabel(t.value, t.unit, "auto"), t.weight
-	}
-	min := g[0]
-	max := g[0]
-	w := min.weight
-	for _, t := range g[1:] {
-		if v, _ := ScaleValue(t.value, t.unit, min.unit); int64(v) < min.value {
-			min = t
-		}
-		if v, _ := ScaleValue(t.value, t.unit, max.unit); int64(v) > max.value {
-			max = t
-		}
-		w += t.weight
-	}
-	return scaledValueLabel(min.value, min.unit, "auto") + ".." +
-		scaledValueLabel(max.value, max.unit, "auto"), w
-}
-
-// sumNodes adds the flat and sum values on a report.
-func sumNodes(ns nodes) (flat int64, cum int64) {
-	for _, n := range ns {
-		flat += n.flat
-		cum += n.cum
-	}
-	return
-}
-
-type edgeMap map[*node]*edgeInfo
-
-// edgeInfo contains any attributes to be represented about edges in a graph/
-type edgeInfo struct {
-	src, dest *node
-	// The summary weight of the edge
-	weight int64
-	// residual edges connect nodes that were connected through a
-	// separate node, which has been removed from the report.
-	residual bool
-}
-
-// bumpWeight increases the weight of an edge. If there isn't such an
-// edge in the map one is created.
-func bumpWeight(from, to *node, w int64, residual bool) {
-	if from.out[to] != to.in[from] {
-		panic(fmt.Errorf("asymmetric edges %v %v", *from, *to))
-	}
-
-	if n := from.out[to]; n != nil {
-		n.weight += w
-		if n.residual && !residual {
-			n.residual = false
-		}
-		return
-	}
-
-	info := &edgeInfo{src: from, dest: to, weight: w, residual: residual}
-	from.out[to] = info
-	to.in[from] = info
-}
-
-// Output formats.
-const (
-	Proto = iota
-	Dot
-	Tags
-	Tree
-	Text
-	Raw
-	Dis
-	List
-	WebList
-	Callgrind
-)
-
-// Options are the formatting and filtering options used to generate a
-// profile.
-type Options struct {
-	OutputFormat int
-
-	CumSort        bool
-	CallTree       bool
-	PrintAddresses bool
-	DropNegative   bool
-	Ratio          float64
-
-	NodeCount    int
-	NodeFraction float64
-	EdgeFraction float64
-
-	SampleType string
-	SampleUnit string // Unit for the sample data from the profile.
-	OutputUnit string // Units for data formatting in report.
-
-	Symbol *regexp.Regexp // Symbols to include on disassembly report.
-}
-
-// newGraph summarizes performance data from a profile into a graph.
-func newGraph(rpt *Report) (g graph, err error) {
-	prof := rpt.prof
-	o := rpt.options
-
-	// Generate a tree for graphical output if requested.
-	buildTree := o.CallTree && o.OutputFormat == Dot
-
-	locations := make(map[uint64][]nodeInfo)
-	for _, l := range prof.Location {
-		locations[l.ID] = newLocInfo(l)
-	}
-
-	nm := make(nodeMap)
-	for _, sample := range prof.Sample {
-		if sample.Location == nil {
-			continue
-		}
-
-		// Construct list of node names for sample.
-		var stack []nodeInfo
-		for _, loc := range sample.Location {
-			id := loc.ID
-			stack = append(stack, locations[id]...)
-		}
-
-		// Upfront pass to update the parent chains, to prevent the
-		// merging of nodes with different parents.
-		if buildTree {
-			var nn *node
-			for i := len(stack); i > 0; i-- {
-				n := &stack[i-1]
-				n.parent = nn
-				nn = nm.findOrInsertNode(*n)
-			}
-		}
-
-		leaf := nm.findOrInsertNode(stack[0])
-		weight := rpt.sampleValue(sample)
-		leaf.addTags(sample, weight)
-
-		// Aggregate counter data.
-		leaf.flat += weight
-		seen := make(map[*node]bool)
-		var nn *node
-		for _, s := range stack {
-			n := nm.findOrInsertNode(s)
-			if !seen[n] {
-				seen[n] = true
-				n.cum += weight
-
-				if nn != nil {
-					bumpWeight(n, nn, weight, false)
-				}
-			}
-			nn = n
-		}
-	}
-
-	// Collect new nodes into a report.
-	ns := make(nodes, 0, len(nm))
-	for _, n := range nm {
-		if rpt.options.DropNegative && n.flat < 0 {
-			continue
-		}
-		ns = append(ns, n)
-	}
-
-	return graph{ns}, nil
-}
-
-// Create a slice of formatted names for a location.
-func newLocInfo(l *profile.Location) []nodeInfo {
-	var objfile string
-
-	if m := l.Mapping; m != nil {
-		objfile = filepath.Base(m.File)
-	}
-
-	if len(l.Line) == 0 {
-		return []nodeInfo{
-			{
-				address: l.Address,
-				objfile: objfile,
-			},
-		}
-	}
-	var info []nodeInfo
-	numInlineFrames := len(l.Line) - 1
-	for li, line := range l.Line {
-		ni := nodeInfo{
-			address: l.Address,
-			lineno:  int(line.Line),
-			inline:  li < numInlineFrames,
-			objfile: objfile,
-		}
-
-		if line.Function != nil {
-			ni.name = line.Function.Name
-			ni.origName = line.Function.SystemName
-			ni.file = line.Function.Filename
-			ni.startLine = int(line.Function.StartLine)
-		}
-
-		info = append(info, ni)
-	}
-	return info
-}
-
-// nodeMap maps from a node info struct to a node. It is used to merge
-// report entries with the same info.
-type nodeMap map[nodeInfo]*node
-
-func (m nodeMap) findOrInsertNode(info nodeInfo) *node {
-	rr := m[info]
-	if rr == nil {
-		rr = &node{
-			info: info,
-			in:   make(edgeMap),
-			out:  make(edgeMap),
-			tags: make(map[string]*tag),
-		}
-		m[info] = rr
-	}
-	return rr
-}
-
-// preprocess does any required filtering/sorting according to the
-// report options. Returns the mapping from each node to any nodes
-// removed by path compression and statistics on the nodes/edges removed.
-func (g *graph) preprocess(rpt *Report) (origCount, droppedNodes, droppedEdges int) {
-	o := rpt.options
-
-	// Compute total weight of current set of nodes.
-	// This is <= rpt.total because of node filtering.
-	var totalValue int64
-	for _, n := range g.ns {
-		totalValue += n.flat
-	}
-
-	// Remove nodes with value <= total*nodeFraction
-	if nodeFraction := o.NodeFraction; nodeFraction > 0 {
-		var removed nodes
-		minValue := int64(float64(totalValue) * nodeFraction)
-		kept := make(nodes, 0, len(g.ns))
-		for _, n := range g.ns {
-			if n.cum < minValue {
-				removed = append(removed, n)
-			} else {
-				kept = append(kept, n)
-				tagsKept := make(map[string]*tag)
-				for s, t := range n.tags {
-					if t.weight >= minValue {
-						tagsKept[s] = t
-					}
-				}
-				n.tags = tagsKept
-			}
-		}
-		droppedNodes = len(removed)
-		removeNodes(removed, false, false)
-		g.ns = kept
-	}
-
-	// Remove edges below minimum frequency.
-	if edgeFraction := o.EdgeFraction; edgeFraction > 0 {
-		minEdge := int64(float64(totalValue) * edgeFraction)
-		for _, n := range g.ns {
-			for src, e := range n.in {
-				if e.weight < minEdge {
-					delete(n.in, src)
-					delete(src.out, n)
-					droppedEdges++
-				}
-			}
-		}
-	}
-
-	sortOrder := flatName
-	if o.CumSort {
-		// Force cum sorting for graph output, to preserve connectivity.
-		sortOrder = cumName
-	}
-
-	// Nodes that have flat==0 and a single in/out do not provide much
-	// information. Give them first chance to be removed. Do not consider edges
-	// from/to nodes that are expected to be removed.
-	maxNodes := o.NodeCount
-	if o.OutputFormat == Dot {
-		if maxNodes > 0 && maxNodes < len(g.ns) {
-			sortOrder = cumName
-			g.ns.sort(cumName)
-			cumCutoff := g.ns[maxNodes].cum
-			for _, n := range g.ns {
-				if n.flat == 0 {
-					if count := countEdges(n.out, cumCutoff); count > 1 {
-						continue
-					}
-					if count := countEdges(n.in, cumCutoff); count != 1 {
-						continue
-					}
-					n.info.lowPriority = true
-				}
-			}
-		}
-	}
-
-	g.ns.sort(sortOrder)
-	if maxNodes > 0 {
-		origCount = len(g.ns)
-		for index, nodes := 0, 0; index < len(g.ns); index++ {
-			nodes++
-			// For DOT output, count the tags as nodes since we will draw
-			// boxes for them.
-			if o.OutputFormat == Dot {
-				nodes += len(g.ns[index].tags)
-			}
-			if nodes > maxNodes {
-				// Trim to the top n nodes. Create dotted edges to bridge any
-				// broken connections.
-				removeNodes(g.ns[index:], true, true)
-				g.ns = g.ns[:index]
-				break
-			}
-		}
-	}
-	removeRedundantEdges(g.ns)
-
-	// Select best unit for profile output.
-	// Find the appropriate units for the smallest non-zero sample
-	if o.OutputUnit == "minimum" && len(g.ns) > 0 {
-		var maxValue, minValue int64
-
-		for _, n := range g.ns {
-			if n.flat > 0 && (minValue == 0 || n.flat < minValue) {
-				minValue = n.flat
-			}
-			if n.cum > maxValue {
-				maxValue = n.cum
-			}
-		}
-		if r := o.Ratio; r > 0 && r != 1 {
-			minValue = int64(float64(minValue) * r)
-			maxValue = int64(float64(maxValue) * r)
-		}
-
-		_, minUnit := ScaleValue(minValue, o.SampleUnit, "minimum")
-		_, maxUnit := ScaleValue(maxValue, o.SampleUnit, "minimum")
-
-		unit := minUnit
-		if minUnit != maxUnit && minValue*100 < maxValue && o.OutputFormat != Callgrind {
-			// Minimum and maximum values have different units. Scale
-			// minimum by 100 to use larger units, allowing minimum value to
-			// be scaled down to 0.01, except for callgrind reports since
-			// they can only represent integer values.
-			_, unit = ScaleValue(100*minValue, o.SampleUnit, "minimum")
-		}
-
-		if unit != "" {
-			o.OutputUnit = unit
-		} else {
-			o.OutputUnit = o.SampleUnit
-		}
-	}
-	return
-}
-
-// countEdges counts the number of edges below the specified cutoff.
-func countEdges(el edgeMap, cutoff int64) int {
-	count := 0
-	for _, e := range el {
-		if e.weight > cutoff {
-			count++
-		}
-	}
-	return count
-}
-
-// removeNodes removes nodes from a report, optionally bridging
-// connections between in/out edges and spreading out their weights
-// proportionally. residual marks new bridge edges as residual
-// (dotted).
-func removeNodes(toRemove nodes, bridge, residual bool) {
-	for _, n := range toRemove {
-		for ei := range n.in {
-			delete(ei.out, n)
-		}
-		if bridge {
-			for ei, wi := range n.in {
-				for eo, wo := range n.out {
-					var weight int64
-					if n.cum != 0 {
-						weight = int64(float64(wo.weight) * (float64(wi.weight) / float64(n.cum)))
-					}
-					bumpWeight(ei, eo, weight, residual)
-				}
-			}
-		}
-		for eo := range n.out {
-			delete(eo.in, n)
-		}
-	}
-}
-
-// removeRedundantEdges removes residual edges if the destination can
-// be reached through another path. This is done to simplify the graph
-// while preserving connectivity.
-func removeRedundantEdges(ns nodes) {
-	// Walk the nodes and outgoing edges in reverse order to prefer
-	// removing edges with the lowest weight.
-	for i := len(ns); i > 0; i-- {
-		n := ns[i-1]
-		in := sortedEdges(n.in)
-		for j := len(in); j > 0; j-- {
-			if e := in[j-1]; e.residual && isRedundant(e) {
-				delete(e.src.out, e.dest)
-				delete(e.dest.in, e.src)
-			}
-		}
-	}
-}
-
-// isRedundant determines if an edge can be removed without impacting
-// connectivity of the whole graph. This is implemented by checking if the
-// nodes have a common ancestor after removing the edge.
-func isRedundant(e *edgeInfo) bool {
-	destPred := predecessors(e, e.dest)
-	if len(destPred) == 1 {
-		return false
-	}
-	srcPred := predecessors(e, e.src)
-
-	for n := range srcPred {
-		if destPred[n] && n != e.dest {
-			return true
-		}
-	}
-	return false
-}
-
-// predecessors collects all the predecessors to node n, excluding edge e.
-func predecessors(e *edgeInfo, n *node) map[*node]bool {
-	seen := map[*node]bool{n: true}
-	queue := []*node{n}
-	for len(queue) > 0 {
-		n := queue[0]
-		queue = queue[1:]
-		for _, ie := range n.in {
-			if e == ie || seen[ie.src] {
-				continue
-			}
-			seen[ie.src] = true
-			queue = append(queue, ie.src)
-		}
-	}
-	return seen
-}
-
-// nodeSorter is a mechanism used to allow a report to be sorted
-// in different ways.
-type nodeSorter struct {
-	rs   nodes
-	less func(i, j int) bool
-}
-
-func (s nodeSorter) Len() int           { return len(s.rs) }
-func (s nodeSorter) Swap(i, j int)      { s.rs[i], s.rs[j] = s.rs[j], s.rs[i] }
-func (s nodeSorter) Less(i, j int) bool { return s.less(i, j) }
-
-type nodeOrder int
-
-const (
-	flatName nodeOrder = iota
-	flatCumName
-	cumName
-	nameOrder
-	fileOrder
-	addressOrder
-)
-
-// sort reoders the entries in a report based on the specified
-// ordering criteria. The result is sorted in decreasing order for
-// numeric quantities, alphabetically for text, and increasing for
-// addresses.
-func (ns nodes) sort(o nodeOrder) error {
-	var s nodeSorter
-
-	switch o {
-	case flatName:
-		s = nodeSorter{ns,
-			func(i, j int) bool {
-				if iv, jv := ns[i].flat, ns[j].flat; iv != jv {
-					return iv > jv
-				}
-				if ns[i].info.prettyName() != ns[j].info.prettyName() {
-					return ns[i].info.prettyName() < ns[j].info.prettyName()
-				}
-				iv, jv := ns[i].cum, ns[j].cum
-				return iv > jv
-			},
-		}
-	case flatCumName:
-		s = nodeSorter{ns,
-			func(i, j int) bool {
-				if iv, jv := ns[i].flat, ns[j].flat; iv != jv {
-					return iv > jv
-				}
-				if iv, jv := ns[i].cum, ns[j].cum; iv != jv {
-					return iv > jv
-				}
-				return ns[i].info.prettyName() < ns[j].info.prettyName()
-			},
-		}
-	case cumName:
-		s = nodeSorter{ns,
-			func(i, j int) bool {
-				if ns[i].info.lowPriority != ns[j].info.lowPriority {
-					return ns[j].info.lowPriority
-				}
-				if iv, jv := ns[i].cum, ns[j].cum; iv != jv {
-					return iv > jv
-				}
-				if ns[i].info.prettyName() != ns[j].info.prettyName() {
-					return ns[i].info.prettyName() < ns[j].info.prettyName()
-				}
-				iv, jv := ns[i].flat, ns[j].flat
-				return iv > jv
-			},
-		}
-	case nameOrder:
-		s = nodeSorter{ns,
-			func(i, j int) bool {
-				return ns[i].info.name < ns[j].info.name
-			},
-		}
-	case fileOrder:
-		s = nodeSorter{ns,
-			func(i, j int) bool {
-				return ns[i].info.file < ns[j].info.file
-			},
-		}
-	case addressOrder:
-		s = nodeSorter{ns,
-			func(i, j int) bool {
-				return ns[i].info.address < ns[j].info.address
-			},
-		}
-	default:
-		return fmt.Errorf("report: unrecognized sort ordering: %d", o)
-	}
-	sort.Sort(s)
-	return nil
-}
-
-type edgeList []*edgeInfo
-
-// sortedEdges return a slice of the edges in the map, sorted for
-// visualization. The sort order is first based on the edge weight
-// (higher-to-lower) and then by the node names to avoid flakiness.
-func sortedEdges(edges map[*node]*edgeInfo) edgeList {
-	el := make(edgeList, 0, len(edges))
-	for _, w := range edges {
-		el = append(el, w)
-	}
-
-	sort.Sort(el)
-	return el
-}
-
-func (el edgeList) Len() int {
-	return len(el)
-}
-
-func (el edgeList) Less(i, j int) bool {
-	if el[i].weight != el[j].weight {
-		return el[i].weight > el[j].weight
-	}
-
-	from1 := el[i].src.info.prettyName()
-	from2 := el[j].src.info.prettyName()
-	if from1 != from2 {
-		return from1 < from2
-	}
-
-	to1 := el[i].dest.info.prettyName()
-	to2 := el[j].dest.info.prettyName()
-
-	return to1 < to2
-}
-
-func (el edgeList) Swap(i, j int) {
-	el[i], el[j] = el[j], el[i]
-}
-
-func (el edgeList) sum() int64 {
-	var ret int64
-	for _, e := range el {
-		ret += e.weight
-	}
-	return ret
-}
-
-// ScaleValue reformats a value from a unit to a different unit.
-func ScaleValue(value int64, fromUnit, toUnit string) (sv float64, su string) {
-	// Avoid infinite recursion on overflow.
-	if value < 0 && -value > 0 {
-		v, u := ScaleValue(-value, fromUnit, toUnit)
-		return -v, u
-	}
-	if m, u, ok := memoryLabel(value, fromUnit, toUnit); ok {
-		return m, u
-	}
-	if t, u, ok := timeLabel(value, fromUnit, toUnit); ok {
-		return t, u
-	}
-	// Skip non-interesting units.
-	switch toUnit {
-	case "count", "sample", "unit", "minimum":
-		return float64(value), ""
-	default:
-		return float64(value), toUnit
-	}
-}
-
-func scaledValueLabel(value int64, fromUnit, toUnit string) string {
-	v, u := ScaleValue(value, fromUnit, toUnit)
-
-	sv := strings.TrimSuffix(fmt.Sprintf("%.2f", v), ".00")
-	if sv == "0" || sv == "-0" {
-		return "0"
-	}
-	return sv + u
-}
-
-func memoryLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok bool) {
-	fromUnit = strings.TrimSuffix(strings.ToLower(fromUnit), "s")
-	toUnit = strings.TrimSuffix(strings.ToLower(toUnit), "s")
-
-	switch fromUnit {
-	case "byte", "b":
-	case "kilobyte", "kb":
-		value *= 1024
-	case "megabyte", "mb":
-		value *= 1024 * 1024
-	case "gigabyte", "gb":
-		value *= 1024 * 1024 * 1024
-	default:
-		return 0, "", false
-	}
-
-	if toUnit == "minimum" || toUnit == "auto" {
-		switch {
-		case value < 1024:
-			toUnit = "b"
-		case value < 1024*1024:
-			toUnit = "kb"
-		case value < 1024*1024*1024:
-			toUnit = "mb"
-		default:
-			toUnit = "gb"
-		}
-	}
-
-	var output float64
-	switch toUnit {
-	default:
-		output, toUnit = float64(value), "B"
-	case "kb", "kbyte", "kilobyte":
-		output, toUnit = float64(value)/1024, "kB"
-	case "mb", "mbyte", "megabyte":
-		output, toUnit = float64(value)/(1024*1024), "MB"
-	case "gb", "gbyte", "gigabyte":
-		output, toUnit = float64(value)/(1024*1024*1024), "GB"
-	}
-	return output, toUnit, true
-}
-
-func timeLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok bool) {
-	fromUnit = strings.ToLower(fromUnit)
-	if len(fromUnit) > 2 {
-		fromUnit = strings.TrimSuffix(fromUnit, "s")
-	}
-
-	toUnit = strings.ToLower(toUnit)
-	if len(toUnit) > 2 {
-		toUnit = strings.TrimSuffix(toUnit, "s")
-	}
-
-	var d time.Duration
-	switch fromUnit {
-	case "nanosecond", "ns":
-		d = time.Duration(value) * time.Nanosecond
-	case "microsecond":
-		d = time.Duration(value) * time.Microsecond
-	case "millisecond", "ms":
-		d = time.Duration(value) * time.Millisecond
-	case "second", "sec":
-		d = time.Duration(value) * time.Second
-	case "cycle":
-		return float64(value), "", true
-	default:
-		return 0, "", false
-	}
-
-	if toUnit == "minimum" || toUnit == "auto" {
-		switch {
-		case d < 1*time.Microsecond:
-			toUnit = "ns"
-		case d < 1*time.Millisecond:
-			toUnit = "us"
-		case d < 1*time.Second:
-			toUnit = "ms"
-		case d < 1*time.Minute:
-			toUnit = "sec"
-		case d < 1*time.Hour:
-			toUnit = "min"
-		case d < 24*time.Hour:
-			toUnit = "hour"
-		case d < 15*24*time.Hour:
-			toUnit = "day"
-		case d < 120*24*time.Hour:
-			toUnit = "week"
-		default:
-			toUnit = "year"
-		}
-	}
-
-	var output float64
-	dd := float64(d)
-	switch toUnit {
-	case "ns", "nanosecond":
-		output, toUnit = dd/float64(time.Nanosecond), "ns"
-	case "us", "microsecond":
-		output, toUnit = dd/float64(time.Microsecond), "us"
-	case "ms", "millisecond":
-		output, toUnit = dd/float64(time.Millisecond), "ms"
-	case "min", "minute":
-		output, toUnit = dd/float64(time.Minute), "mins"
-	case "hour", "hr":
-		output, toUnit = dd/float64(time.Hour), "hrs"
-	case "day":
-		output, toUnit = dd/float64(24*time.Hour), "days"
-	case "week", "wk":
-		output, toUnit = dd/float64(7*24*time.Hour), "wks"
-	case "year", "yr":
-		output, toUnit = dd/float64(365*7*24*time.Hour), "yrs"
-	default:
-		fallthrough
-	case "sec", "second", "s":
-		output, toUnit = dd/float64(time.Second), "s"
-	}
-	return output, toUnit, true
-}
-
-// prettyName determines the printable name to be used for a node.
-func (info *nodeInfo) prettyName() string {
-	var name string
-	if info.address != 0 {
-		name = fmt.Sprintf("%016x", info.address)
-	}
-
-	if info.name != "" {
-		name = name + " " + info.name
-	}
-
-	if info.file != "" {
-		name += " " + trimPath(info.file)
-		if info.lineno != 0 {
-			name += fmt.Sprintf(":%d", info.lineno)
-		}
-	}
-
-	if info.inline {
-		name = name + " (inline)"
-	}
-
-	if name = strings.TrimSpace(name); name == "" && info.objfile != "" {
-		name = "[" + info.objfile + "]"
-	}
-	return name
-}
-
-// New builds a new report indexing the sample values interpreting the
-// samples with the provided function.
-func New(prof *profile.Profile, options Options, value func(s *profile.Sample) int64, unit string) *Report {
-	o := &options
-	if o.SampleUnit == "" {
-		o.SampleUnit = unit
-	}
-	format := func(v int64) string {
-		if r := o.Ratio; r > 0 && r != 1 {
-			fv := float64(v) * r
-			v = int64(fv)
-		}
-		return scaledValueLabel(v, o.SampleUnit, o.OutputUnit)
-	}
-	return &Report{prof, computeTotal(prof, value), o, value, format}
-}
-
-// NewDefault builds a new report indexing the sample values with the
-// last value available.
-func NewDefault(prof *profile.Profile, options Options) *Report {
-	index := len(prof.SampleType) - 1
-	o := &options
-	if o.SampleUnit == "" {
-		o.SampleUnit = strings.ToLower(prof.SampleType[index].Unit)
-	}
-	value := func(s *profile.Sample) int64 {
-		return s.Value[index]
-	}
-	format := func(v int64) string {
-		if r := o.Ratio; r > 0 && r != 1 {
-			fv := float64(v) * r
-			v = int64(fv)
-		}
-		return scaledValueLabel(v, o.SampleUnit, o.OutputUnit)
-	}
-	return &Report{prof, computeTotal(prof, value), o, value, format}
-}
-
-func computeTotal(prof *profile.Profile, value func(s *profile.Sample) int64) int64 {
-	var ret int64
-	for _, sample := range prof.Sample {
-		ret += value(sample)
-	}
-	return ret
-}
-
-// Report contains the data and associated routines to extract a
-// report from a profile.
-type Report struct {
-	prof        *profile.Profile
-	total       int64
-	options     *Options
-	sampleValue func(*profile.Sample) int64
-	formatValue func(int64) string
-}
-
-func (rpt *Report) formatTags(s *profile.Sample) (string, bool) {
-	var labels []string
-	for key, vals := range s.Label {
-		for _, v := range vals {
-			labels = append(labels, key+":"+v)
-		}
-	}
-	for key, nvals := range s.NumLabel {
-		for _, v := range nvals {
-			labels = append(labels, scaledValueLabel(v, key, "auto"))
-		}
-	}
-	if len(labels) == 0 {
-		return "", false
-	}
-	sort.Strings(labels)
-	return strings.Join(labels, `\n`), true
-}
diff --git a/src/cmd/pprof/internal/report/source.go b/src/cmd/pprof/internal/report/source.go
deleted file mode 100644
index 73ae1b4..0000000
--- a/src/cmd/pprof/internal/report/source.go
+++ /dev/null
@@ -1,454 +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 report
-
-// This file contains routines related to the generation of annotated
-// source listings.
-
-import (
-	"bufio"
-	"fmt"
-	"html/template"
-	"io"
-	"os"
-	"path/filepath"
-	"sort"
-	"strconv"
-	"strings"
-
-	"cmd/pprof/internal/plugin"
-)
-
-// printSource prints an annotated source listing, include all
-// functions with samples that match the regexp rpt.options.symbol.
-// The sources are sorted by function name and then by filename to
-// eliminate potential nondeterminism.
-func printSource(w io.Writer, rpt *Report) error {
-	o := rpt.options
-	g, err := newGraph(rpt)
-	if err != nil {
-		return err
-	}
-
-	// Identify all the functions that match the regexp provided.
-	// Group nodes for each matching function.
-	var functions nodes
-	functionNodes := make(map[string]nodes)
-	for _, n := range g.ns {
-		if !o.Symbol.MatchString(n.info.name) {
-			continue
-		}
-		if functionNodes[n.info.name] == nil {
-			functions = append(functions, n)
-		}
-		functionNodes[n.info.name] = append(functionNodes[n.info.name], n)
-	}
-	functions.sort(nameOrder)
-
-	fmt.Fprintf(w, "Total: %s\n", rpt.formatValue(rpt.total))
-	for _, fn := range functions {
-		name := fn.info.name
-
-		// Identify all the source files associated to this function.
-		// Group nodes for each source file.
-		var sourceFiles nodes
-		fileNodes := make(map[string]nodes)
-		for _, n := range functionNodes[name] {
-			if n.info.file == "" {
-				continue
-			}
-			if fileNodes[n.info.file] == nil {
-				sourceFiles = append(sourceFiles, n)
-			}
-			fileNodes[n.info.file] = append(fileNodes[n.info.file], n)
-		}
-
-		if len(sourceFiles) == 0 {
-			fmt.Printf("No source information for %s\n", name)
-			continue
-		}
-
-		sourceFiles.sort(fileOrder)
-
-		// Print each file associated with this function.
-		for _, fl := range sourceFiles {
-			filename := fl.info.file
-			fns := fileNodes[filename]
-			flatSum, cumSum := sumNodes(fns)
-
-			fnodes, path, err := getFunctionSource(name, filename, fns, 0, 0)
-			fmt.Fprintf(w, "ROUTINE ======================== %s in %s\n", name, path)
-			fmt.Fprintf(w, "%10s %10s (flat, cum) %s of Total\n",
-				rpt.formatValue(flatSum), rpt.formatValue(cumSum),
-				percentage(cumSum, rpt.total))
-
-			if err != nil {
-				fmt.Fprintf(w, " Error: %v\n", err)
-				continue
-			}
-
-			for _, fn := range fnodes {
-				fmt.Fprintf(w, "%10s %10s %6d:%s\n", valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt), fn.info.lineno, fn.info.name)
-			}
-		}
-	}
-	return nil
-}
-
-// printWebSource prints an annotated source listing, include all
-// functions with samples that match the regexp rpt.options.symbol.
-func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
-	o := rpt.options
-	g, err := newGraph(rpt)
-	if err != nil {
-		return err
-	}
-
-	// If the regexp source can be parsed as an address, also match
-	// functions that land on that address.
-	var address *uint64
-	if hex, err := strconv.ParseUint(o.Symbol.String(), 0, 64); err == nil {
-		address = &hex
-	}
-
-	// Extract interesting symbols from binary files in the profile and
-	// classify samples per symbol.
-	symbols := symbolsFromBinaries(rpt.prof, g, o.Symbol, address, obj)
-	symNodes := nodesPerSymbol(g.ns, symbols)
-
-	// Sort symbols for printing.
-	var syms objSymbols
-	for s := range symNodes {
-		syms = append(syms, s)
-	}
-	sort.Sort(syms)
-
-	if len(syms) == 0 {
-		return fmt.Errorf("no samples found on routines matching: %s", o.Symbol.String())
-	}
-
-	printHeader(w, rpt)
-	for _, s := range syms {
-		name := s.sym.Name[0]
-		// Identify sources associated to a symbol by examining
-		// symbol samples. Classify samples per source file.
-		var sourceFiles nodes
-		fileNodes := make(map[string]nodes)
-		for _, n := range symNodes[s] {
-			if n.info.file == "" {
-				continue
-			}
-			if fileNodes[n.info.file] == nil {
-				sourceFiles = append(sourceFiles, n)
-			}
-			fileNodes[n.info.file] = append(fileNodes[n.info.file], n)
-		}
-
-		if len(sourceFiles) == 0 {
-			fmt.Printf("No source information for %s\n", name)
-			continue
-		}
-
-		sourceFiles.sort(fileOrder)
-
-		// Print each file associated with this function.
-		for _, fl := range sourceFiles {
-			filename := fl.info.file
-			fns := fileNodes[filename]
-
-			asm := assemblyPerSourceLine(symbols, fns, filename, obj)
-			start, end := sourceCoordinates(asm)
-
-			fnodes, path, err := getFunctionSource(name, filename, fns, start, end)
-			if err != nil {
-				fnodes, path = getMissingFunctionSource(filename, asm, start, end)
-			}
-
-			flatSum, cumSum := sumNodes(fnodes)
-			printFunctionHeader(w, name, path, flatSum, cumSum, rpt)
-			for _, fn := range fnodes {
-				printFunctionSourceLine(w, fn, asm[fn.info.lineno], rpt)
-			}
-			printFunctionClosing(w)
-		}
-	}
-	printPageClosing(w)
-	return nil
-}
-
-// sourceCoordinates returns the lowest and highest line numbers from
-// a set of assembly statements.
-func sourceCoordinates(asm map[int]nodes) (start, end int) {
-	for l := range asm {
-		if start == 0 || l < start {
-			start = l
-		}
-		if end == 0 || l > end {
-			end = l
-		}
-	}
-	return start, end
-}
-
-// assemblyPerSourceLine disassembles the binary containing a symbol
-// and classifies the assembly instructions according to its
-// corresponding source line, annotating them with a set of samples.
-func assemblyPerSourceLine(objSyms []*objSymbol, rs nodes, src string, obj plugin.ObjTool) map[int]nodes {
-	assembly := make(map[int]nodes)
-	// Identify symbol to use for this collection of samples.
-	o := findMatchingSymbol(objSyms, rs)
-	if o == nil {
-		return assembly
-	}
-
-	// Extract assembly for matched symbol
-	insns, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End)
-	if err != nil {
-		return assembly
-	}
-
-	srcBase := filepath.Base(src)
-	anodes := annotateAssembly(insns, rs, o.base)
-	var lineno = 0
-	for _, an := range anodes {
-		if filepath.Base(an.info.file) == srcBase {
-			lineno = an.info.lineno
-		}
-		if lineno != 0 {
-			assembly[lineno] = append(assembly[lineno], an)
-		}
-	}
-
-	return assembly
-}
-
-// findMatchingSymbol looks for the symbol that corresponds to a set
-// of samples, by comparing their addresses.
-func findMatchingSymbol(objSyms []*objSymbol, ns nodes) *objSymbol {
-	for _, n := range ns {
-		for _, o := range objSyms {
-			if filepath.Base(o.sym.File) == n.info.objfile &&
-				o.sym.Start <= n.info.address-o.base &&
-				n.info.address-o.base <= o.sym.End {
-				return o
-			}
-		}
-	}
-	return nil
-}
-
-// printHeader prints the page header for a weblist report.
-func printHeader(w io.Writer, rpt *Report) {
-	fmt.Fprintln(w, weblistPageHeader)
-
-	var labels []string
-	for _, l := range legendLabels(rpt) {
-		labels = append(labels, template.HTMLEscapeString(l))
-	}
-
-	fmt.Fprintf(w, `<div class="legend">%s<br>Total: %s</div>`,
-		strings.Join(labels, "<br>\n"),
-		rpt.formatValue(rpt.total),
-	)
-}
-
-// printFunctionHeader prints a function header for a weblist report.
-func printFunctionHeader(w io.Writer, name, path string, flatSum, cumSum int64, rpt *Report) {
-	fmt.Fprintf(w, `<h1>%s</h1>%s
-<pre onClick="pprof_toggle_asm()">
-  Total:  %10s %10s (flat, cum) %s
-`,
-		template.HTMLEscapeString(name), template.HTMLEscapeString(path),
-		rpt.formatValue(flatSum), rpt.formatValue(cumSum),
-		percentage(cumSum, rpt.total))
-}
-
-// printFunctionSourceLine prints a source line and the corresponding assembly.
-func printFunctionSourceLine(w io.Writer, fn *node, assembly nodes, rpt *Report) {
-	if len(assembly) == 0 {
-		fmt.Fprintf(w,
-			"<span class=line> %6d</span> <span class=nop>  %10s %10s %s </span>\n",
-			fn.info.lineno,
-			valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt),
-			template.HTMLEscapeString(fn.info.name))
-		return
-	}
-
-	fmt.Fprintf(w,
-		"<span class=line> %6d</span> <span class=deadsrc>  %10s %10s %s </span>",
-		fn.info.lineno,
-		valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt),
-		template.HTMLEscapeString(fn.info.name))
-	fmt.Fprint(w, "<span class=asm>")
-	for _, an := range assembly {
-		var fileline string
-		class := "disasmloc"
-		if an.info.file != "" {
-			fileline = fmt.Sprintf("%s:%d", template.HTMLEscapeString(an.info.file), an.info.lineno)
-			if an.info.lineno != fn.info.lineno {
-				class = "unimportant"
-			}
-		}
-		fmt.Fprintf(w, " %8s %10s %10s %8x: %-48s <span class=%s>%s</span>\n", "",
-			valueOrDot(an.flat, rpt), valueOrDot(an.cum, rpt),
-			an.info.address,
-			template.HTMLEscapeString(an.info.name),
-			class,
-			template.HTMLEscapeString(fileline))
-	}
-	fmt.Fprintln(w, "</span>")
-}
-
-// printFunctionClosing prints the end of a function in a weblist report.
-func printFunctionClosing(w io.Writer) {
-	fmt.Fprintln(w, "</pre>")
-}
-
-// printPageClosing prints the end of the page in a weblist report.
-func printPageClosing(w io.Writer) {
-	fmt.Fprintln(w, weblistPageClosing)
-}
-
-// getFunctionSource collects the sources of a function from a source
-// file and annotates it with the samples in fns. Returns the sources
-// as nodes, using the info.name field to hold the source code.
-func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, string, error) {
-	f, file, err := adjustSourcePath(file)
-	if err != nil {
-		return nil, file, err
-	}
-
-	lineNodes := make(map[int]nodes)
-
-	// Collect source coordinates from profile.
-	const margin = 5 // Lines before first/after last sample.
-	if start == 0 {
-		if fns[0].info.startLine != 0 {
-			start = fns[0].info.startLine
-		} else {
-			start = fns[0].info.lineno - margin
-		}
-	} else {
-		start -= margin
-	}
-	if end == 0 {
-		end = fns[0].info.lineno
-	}
-	end += margin
-	for _, n := range fns {
-		lineno := n.info.lineno
-		nodeStart := n.info.startLine
-		if nodeStart == 0 {
-			nodeStart = lineno - margin
-		}
-		nodeEnd := lineno + margin
-		if nodeStart < start {
-			start = nodeStart
-		} else if nodeEnd > end {
-			end = nodeEnd
-		}
-		lineNodes[lineno] = append(lineNodes[lineno], n)
-	}
-
-	var src nodes
-	buf := bufio.NewReader(f)
-	lineno := 1
-	for {
-		line, err := buf.ReadString('\n')
-		if err != nil {
-			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])
-
-			src = append(src, &node{
-				info: nodeInfo{
-					name:   strings.TrimRight(line, "\n"),
-					lineno: lineno,
-				},
-				flat: flat,
-				cum:  cum,
-			})
-		}
-		lineno++
-		if lineno > end {
-			break
-		}
-	}
-	return src, file, nil
-}
-
-// getMissingFunctionSource creates a dummy function body to point to
-// the source file and annotates it with the samples in asm.
-func getMissingFunctionSource(filename string, asm map[int]nodes, start, end int) (nodes, string) {
-	var fnodes nodes
-	for i := start; i <= end; i++ {
-		lrs := asm[i]
-		if len(lrs) == 0 {
-			continue
-		}
-		flat, cum := sumNodes(lrs)
-		fnodes = append(fnodes, &node{
-			info: nodeInfo{
-				name:   "???",
-				lineno: i,
-			},
-			flat: flat,
-			cum:  cum,
-		})
-	}
-	return fnodes, filename
-}
-
-// adjustSourcePath adjusts the pathe for a source file by trimmming
-// known prefixes and searching for the file on all parents of the
-// current working dir.
-func adjustSourcePath(path string) (*os.File, string, error) {
-	path = trimPath(path)
-	f, err := os.Open(path)
-	if err == nil {
-		return f, path, nil
-	}
-
-	if dir, wderr := os.Getwd(); wderr == nil {
-		for {
-			parent := filepath.Dir(dir)
-			if parent == dir {
-				break
-			}
-			if f, err := os.Open(filepath.Join(parent, path)); err == nil {
-				return f, filepath.Join(parent, path), nil
-			}
-
-			dir = parent
-		}
-	}
-
-	return nil, path, err
-}
-
-// trimPath cleans up a path by removing prefixes that are commonly
-// found on profiles.
-func trimPath(path string) string {
-	basePaths := []string{
-		"/proc/self/cwd/./",
-		"/proc/self/cwd/",
-	}
-
-	sPath := filepath.ToSlash(path)
-
-	for _, base := range basePaths {
-		if strings.HasPrefix(sPath, base) {
-			return filepath.FromSlash(sPath[len(base):])
-		}
-	}
-	return path
-}
diff --git a/src/cmd/pprof/internal/symbolizer/symbolizer.go b/src/cmd/pprof/internal/symbolizer/symbolizer.go
deleted file mode 100644
index 86de564..0000000
--- a/src/cmd/pprof/internal/symbolizer/symbolizer.go
+++ /dev/null
@@ -1,195 +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 symbolizer provides a routine to populate a profile with
-// symbol, file and line number information. It relies on the
-// addr2liner and demangler packages to do the actual work.
-package symbolizer
-
-import (
-	"fmt"
-	"os"
-	"path/filepath"
-	"strings"
-
-	"cmd/pprof/internal/plugin"
-	"cmd/pprof/internal/profile"
-)
-
-// Symbolize adds symbol and line number information to all locations
-// in a profile. mode enables some options to control
-// symbolization. Currently only recognizes "force", which causes it
-// to overwrite any existing data.
-func Symbolize(mode string, prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error {
-	force := false
-	// Disable some mechanisms based on mode string.
-	for _, o := range strings.Split(strings.ToLower(mode), ":") {
-		switch o {
-		case "force":
-			force = true
-		default:
-		}
-	}
-
-	if len(prof.Mapping) == 0 {
-		return fmt.Errorf("no known mappings")
-	}
-
-	mt, err := newMapping(prof, obj, ui, force)
-	if err != nil {
-		return err
-	}
-	defer mt.close()
-
-	functions := make(map[profile.Function]*profile.Function)
-	for _, l := range mt.prof.Location {
-		m := l.Mapping
-		segment := mt.segments[m]
-		if segment == nil {
-			// Nothing to do
-			continue
-		}
-
-		stack, err := segment.SourceLine(l.Address)
-		if err != nil || len(stack) == 0 {
-			// No answers from addr2line
-			continue
-		}
-
-		l.Line = make([]profile.Line, len(stack))
-		for i, frame := range stack {
-			if frame.Func != "" {
-				m.HasFunctions = true
-			}
-			if frame.File != "" {
-				m.HasFilenames = true
-			}
-			if frame.Line != 0 {
-				m.HasLineNumbers = true
-			}
-			f := &profile.Function{
-				Name:       frame.Func,
-				SystemName: frame.Func,
-				Filename:   frame.File,
-			}
-			if fp := functions[*f]; fp != nil {
-				f = fp
-			} else {
-				functions[*f] = f
-				f.ID = uint64(len(mt.prof.Function)) + 1
-				mt.prof.Function = append(mt.prof.Function, f)
-			}
-			l.Line[i] = profile.Line{
-				Function: f,
-				Line:     int64(frame.Line),
-			}
-		}
-
-		if len(stack) > 0 {
-			m.HasInlineFrames = true
-		}
-	}
-	return nil
-}
-
-// newMapping creates a mappingTable for a profile.
-func newMapping(prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, force bool) (*mappingTable, error) {
-	mt := &mappingTable{
-		prof:     prof,
-		segments: make(map[*profile.Mapping]plugin.ObjFile),
-	}
-
-	// Identify used mappings
-	mappings := make(map[*profile.Mapping]bool)
-	for _, l := range prof.Location {
-		mappings[l.Mapping] = true
-	}
-
-	for _, m := range prof.Mapping {
-		if !mappings[m] {
-			continue
-		}
-		// Do not attempt to re-symbolize a mapping that has already been symbolized.
-		if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) {
-			continue
-		}
-
-		f, err := locateFile(obj, m.File, m.BuildID, m.Start)
-		if err != nil {
-			ui.PrintErr("Local symbolization failed for ", filepath.Base(m.File), ": ", err)
-			// Move on to other mappings
-			continue
-		}
-
-		if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
-			// Build ID mismatch - ignore.
-			f.Close()
-			continue
-		}
-
-		mt.segments[m] = f
-	}
-
-	return mt, nil
-}
-
-// locateFile opens a local file for symbolization on the search path
-// at $PPROF_BINARY_PATH. Looks inside these directories for files
-// named $BUILDID/$BASENAME and $BASENAME (if build id is available).
-func locateFile(obj plugin.ObjTool, file, buildID string, start uint64) (plugin.ObjFile, error) {
-	// Construct search path to examine
-	searchPath := os.Getenv("PPROF_BINARY_PATH")
-	if searchPath == "" {
-		// Use $HOME/pprof/binaries as default directory for local symbolization binaries
-		searchPath = filepath.Join(os.Getenv("HOME"), "pprof", "binaries")
-	}
-
-	// Collect names to search: {buildid/basename, basename}
-	var fileNames []string
-	if baseName := filepath.Base(file); buildID != "" {
-		fileNames = []string{filepath.Join(buildID, baseName), baseName}
-	} else {
-		fileNames = []string{baseName}
-	}
-	for _, path := range filepath.SplitList(searchPath) {
-		for nameIndex, name := range fileNames {
-			file := filepath.Join(path, name)
-			if f, err := obj.Open(file, start); err == nil {
-				fileBuildID := f.BuildID()
-				if buildID == "" || buildID == fileBuildID {
-					return f, nil
-				}
-				f.Close()
-				if nameIndex == 0 {
-					// If this is the first name, the path includes the build id. Report inconsistency.
-					return nil, fmt.Errorf("found file %s with inconsistent build id %s", file, fileBuildID)
-				}
-			}
-		}
-	}
-	// Try original file name
-	f, err := obj.Open(file, start)
-	if err == nil && buildID != "" {
-		if fileBuildID := f.BuildID(); fileBuildID != "" && fileBuildID != buildID {
-			// Mismatched build IDs, ignore
-			f.Close()
-			return nil, fmt.Errorf("mismatched build ids %s != %s", fileBuildID, buildID)
-		}
-	}
-	return f, err
-}
-
-// mappingTable contains the mechanisms for symbolization of a
-// profile.
-type mappingTable struct {
-	prof     *profile.Profile
-	segments map[*profile.Mapping]plugin.ObjFile
-}
-
-// Close releases any external processes being used for the mapping.
-func (mt *mappingTable) close() {
-	for _, segment := range mt.segments {
-		segment.Close()
-	}
-}
diff --git a/src/cmd/pprof/internal/symbolz/symbolz.go b/src/cmd/pprof/internal/symbolz/symbolz.go
deleted file mode 100644
index c81e522..0000000
--- a/src/cmd/pprof/internal/symbolz/symbolz.go
+++ /dev/null
@@ -1,111 +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 symbolz symbolizes a profile using the output from the symbolz
-// service.
-package symbolz
-
-import (
-	"bytes"
-	"fmt"
-	"io"
-	"net/url"
-	"regexp"
-	"strconv"
-	"strings"
-
-	"cmd/pprof/internal/profile"
-)
-
-var (
-	symbolzRE = regexp.MustCompile(`(0x[[:xdigit:]]+)\s+(.*)`)
-)
-
-// Symbolize symbolizes profile p by parsing data returned by a
-// symbolz handler. syms receives the symbolz query (hex addresses
-// separated by '+') and returns the symbolz output in a string.  It
-// symbolizes all locations based on their addresses, regardless of
-// mapping.
-func Symbolize(source string, syms func(string, string) ([]byte, error), p *profile.Profile) error {
-	if source = symbolz(source, p); source == "" {
-		// If the source is not a recognizable URL, do nothing.
-		return nil
-	}
-
-	// Construct query of addresses to symbolize.
-	var a []string
-	for _, l := range p.Location {
-		if l.Address != 0 && len(l.Line) == 0 {
-			a = append(a, fmt.Sprintf("%#x", l.Address))
-		}
-	}
-
-	if len(a) == 0 {
-		// No addresses to symbolize.
-		return nil
-	}
-	lines := make(map[uint64]profile.Line)
-	functions := make(map[string]*profile.Function)
-	if b, err := syms(source, strings.Join(a, "+")); err == nil {
-		buf := bytes.NewBuffer(b)
-		for {
-			l, err := buf.ReadString('\n')
-
-			if err != nil {
-				if err == io.EOF {
-					break
-				}
-				return err
-			}
-
-			if symbol := symbolzRE.FindStringSubmatch(l); len(symbol) == 3 {
-				addr, err := strconv.ParseUint(symbol[1], 0, 64)
-				if err != nil {
-					return fmt.Errorf("unexpected parse failure %s: %v", symbol[1], err)
-				}
-
-				name := symbol[2]
-				fn := functions[name]
-				if fn == nil {
-					fn = &profile.Function{
-						ID:         uint64(len(p.Function) + 1),
-						Name:       name,
-						SystemName: name,
-					}
-					functions[name] = fn
-					p.Function = append(p.Function, fn)
-				}
-
-				lines[addr] = profile.Line{Function: fn}
-			}
-		}
-	}
-
-	for _, l := range p.Location {
-		if line, ok := lines[l.Address]; ok {
-			l.Line = []profile.Line{line}
-			if l.Mapping != nil {
-				l.Mapping.HasFunctions = true
-			}
-		}
-	}
-
-	return nil
-}
-
-// symbolz returns the corresponding symbolz source for a profile URL.
-func symbolz(source string, p *profile.Profile) string {
-	if url, err := url.Parse(source); err == nil && url.Host != "" {
-		if last := strings.LastIndex(url.Path, "/"); last != -1 {
-			if strings.HasSuffix(url.Path[:last], "pprof") {
-				url.Path = url.Path[:last] + "/symbol"
-			} else {
-				url.Path = url.Path[:last] + "/symbolz"
-			}
-			return url.String()
-		}
-	}
-
-	return ""
-}
diff --git a/src/cmd/pprof/internal/tempfile/tempfile.go b/src/cmd/pprof/internal/tempfile/tempfile.go
deleted file mode 100644
index 31c1176..0000000
--- a/src/cmd/pprof/internal/tempfile/tempfile.go
+++ /dev/null
@@ -1,45 +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 tempfile provides tools to create and delete temporary files
-package tempfile
-
-import (
-	"fmt"
-	"os"
-	"path/filepath"
-	"sync"
-)
-
-// New returns an unused filename for output files.
-func New(dir, prefix, suffix string) (*os.File, error) {
-	for index := 1; index < 10000; index++ {
-		path := filepath.Join(dir, fmt.Sprintf("%s%03d%s", prefix, index, suffix))
-		if _, err := os.Stat(path); err != nil {
-			return os.Create(path)
-		}
-	}
-	// Give up
-	return nil, fmt.Errorf("could not create file of the form %s%03d%s", prefix, 1, suffix)
-}
-
-var tempFiles []string
-var tempFilesMu = sync.Mutex{}
-
-// DeferDelete marks a file to be deleted by next call to Cleanup()
-func DeferDelete(path string) {
-	tempFilesMu.Lock()
-	tempFiles = append(tempFiles, path)
-	tempFilesMu.Unlock()
-}
-
-// Cleanup removes any temporary files selected for deferred cleaning.
-func Cleanup() {
-	tempFilesMu.Lock()
-	for _, f := range tempFiles {
-		os.Remove(f)
-	}
-	tempFiles = nil
-	tempFilesMu.Unlock()
-}
diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go
index 2b20f1d..5ee8a11 100644
--- a/src/cmd/pprof/pprof.go
+++ b/src/cmd/pprof/pprof.go
@@ -5,22 +5,24 @@
 package main
 
 import (
+	"debug/dwarf"
 	"debug/gosym"
 	"flag"
 	"fmt"
+	"net/url"
 	"os"
 	"regexp"
 	"strings"
 	"sync"
 
 	"cmd/internal/objfile"
-	"cmd/pprof/internal/commands"
-	"cmd/pprof/internal/driver"
-	"cmd/pprof/internal/fetch"
-	"cmd/pprof/internal/plugin"
-	"cmd/pprof/internal/profile"
-	"cmd/pprof/internal/symbolizer"
-	"cmd/pprof/internal/symbolz"
+	"cmd/internal/pprof/commands"
+	"cmd/internal/pprof/driver"
+	"cmd/internal/pprof/fetch"
+	"cmd/internal/pprof/plugin"
+	"cmd/internal/pprof/profile"
+	"cmd/internal/pprof/symbolizer"
+	"cmd/internal/pprof/symbolz"
 )
 
 func main() {
@@ -49,7 +51,16 @@ func symbolize(mode, source string, p *profile.Profile, obj plugin.ObjTool, ui p
 			ui.PrintErr("expecting -symbolize=[local|remote|none][:force]")
 			fallthrough
 		case "", "force":
-			// Ignore these options, -force is recognized by symbolizer.Symbolize
+			// -force is recognized by symbolizer.Symbolize.
+			// If the source is remote, and the mapping file
+			// does not exist, don't use local symbolization.
+			if isRemote(source) {
+				if len(p.Mapping) == 0 {
+					local = false
+				} else if _, err := os.Stat(p.Mapping[0].File); err != nil {
+					local = false
+				}
+			}
 		}
 	}
 
@@ -66,6 +77,21 @@ func symbolize(mode, source string, p *profile.Profile, obj plugin.ObjTool, ui p
 	return err
 }
 
+// isRemote returns whether source is a URL for a remote source.
+func isRemote(source string) bool {
+	url, err := url.Parse(source)
+	if err != nil {
+		url, err = url.Parse("http://" + source)
+		if err != nil {
+			return false
+		}
+	}
+	if scheme := strings.ToLower(url.Scheme); scheme == "" || scheme == "file" {
+		return false
+	}
+	return true
+}
+
 // flags implements the driver.FlagPackage interface using the builtin flag package.
 type flags struct {
 }
@@ -116,6 +142,11 @@ func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) {
 		name: name,
 		file: of,
 	}
+	if start != 0 {
+		if load, err := of.LoadAddress(); err == nil {
+			f.offset = start - load
+		}
+	}
 	return f, nil
 }
 
@@ -168,10 +199,14 @@ func (*objTool) SetConfig(config string) {
 // (instead of invoking GNU binutils).
 // A file represents a single executable being analyzed.
 type file struct {
-	name string
-	sym  []objfile.Sym
-	file *objfile.File
-	pcln *gosym.Table
+	name   string
+	offset uint64
+	sym    []objfile.Sym
+	file   *objfile.File
+	pcln   *gosym.Table
+
+	triedDwarf bool
+	dwarf      *dwarf.Data
 }
 
 func (f *file) Name() string {
@@ -196,18 +231,96 @@ func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) {
 		}
 		f.pcln = pcln
 	}
+	addr -= f.offset
 	file, line, fn := f.pcln.PCToLine(addr)
-	if fn == nil {
-		return nil, fmt.Errorf("no line information for PC=%#x", addr)
+	if fn != nil {
+		frame := []plugin.Frame{
+			{
+				Func: fn.Name,
+				File: file,
+				Line: line,
+			},
+		}
+		return frame, nil
+	}
+
+	frames := f.dwarfSourceLine(addr)
+	if frames != nil {
+		return frames, nil
+	}
+
+	return nil, fmt.Errorf("no line information for PC=%#x", addr)
+}
+
+// dwarfSourceLine tries to get file/line information using DWARF.
+// This is for C functions that appear in the profile.
+// Returns nil if there is no information available.
+func (f *file) dwarfSourceLine(addr uint64) []plugin.Frame {
+	if f.dwarf == nil && !f.triedDwarf {
+		// Ignore any error--we don't care exactly why there
+		// is no DWARF info.
+		f.dwarf, _ = f.file.DWARF()
+		f.triedDwarf = true
 	}
-	frame := []plugin.Frame{
+
+	if f.dwarf != nil {
+		r := f.dwarf.Reader()
+		unit, err := r.SeekPC(addr)
+		if err == nil {
+			if frames := f.dwarfSourceLineEntry(r, unit, addr); frames != nil {
+				return frames
+			}
+		}
+	}
+
+	return nil
+}
+
+// dwarfSourceLineEntry tries to get file/line information from a
+// DWARF compilation unit. Returns nil if it doesn't find anything.
+func (f *file) dwarfSourceLineEntry(r *dwarf.Reader, entry *dwarf.Entry, addr uint64) []plugin.Frame {
+	lines, err := f.dwarf.LineReader(entry)
+	if err != nil {
+		return nil
+	}
+	var lentry dwarf.LineEntry
+	if err := lines.SeekPC(addr, &lentry); err != nil {
+		return nil
+	}
+
+	// Try to find the function name.
+	name := ""
+FindName:
+	for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() {
+		if entry.Tag == dwarf.TagSubprogram {
+			ranges, err := f.dwarf.Ranges(entry)
+			if err != nil {
+				return nil
+			}
+			for _, pcs := range ranges {
+				if pcs[0] <= addr && addr < pcs[1] {
+					var ok bool
+					// TODO: AT_linkage_name, AT_MIPS_linkage_name.
+					name, ok = entry.Val(dwarf.AttrName).(string)
+					if ok {
+						break FindName
+					}
+				}
+			}
+		}
+	}
+
+	// TODO: Report inlined functions.
+
+	frames := []plugin.Frame{
 		{
-			Func: fn.Name,
-			File: file,
-			Line: line,
+			Func: name,
+			File: lentry.File.Name,
+			Line: lentry.Line,
 		},
 	}
-	return frame, nil
+
+	return frames
 }
 
 func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
@@ -220,6 +333,11 @@ func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
 	}
 	var out []*plugin.Sym
 	for _, s := range f.sym {
+		// Ignore a symbol with address 0 and size 0.
+		// An ELF STT_FILE symbol will look like that.
+		if s.Addr == 0 && s.Size == 0 {
+			continue
+		}
 		if (r == nil || r.MatchString(s.Name)) && (addr == 0 || s.Addr <= addr && addr < s.Addr+uint64(s.Size)) {
 			out = append(out, &plugin.Sym{
 				Name:  []string{s.Name},
diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go
index e493be9..893719e 100644
--- a/src/cmd/trace/main.go
+++ b/src/cmd/trace/main.go
@@ -14,7 +14,7 @@ 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
+	go tool trace trace.out
 */
 package main
 
@@ -22,7 +22,9 @@ import (
 	"bufio"
 	"flag"
 	"fmt"
+	"html/template"
 	"internal/trace"
+	"log"
 	"net"
 	"net/http"
 	"os"
@@ -37,7 +39,9 @@ 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
+	go tool trace [flags] [pkg.test] trace.out
+[pkg.test] argument is required for traces produced by Go 1.6 and below.
+Go 1.7 does not require the binary argument.
 
 Flags:
 	-http=addr: HTTP service address (e.g., ':6060')
@@ -58,31 +62,52 @@ func main() {
 	}
 	flag.Parse()
 
-	// Usage information when no arguments.
-	if flag.NArg() != 2 {
+	// Go 1.7 traces embed symbol info and does not require the binary.
+	// But we optionally accept binary as first arg for Go 1.5 traces.
+	switch flag.NArg() {
+	case 1:
+		traceFile = flag.Arg(0)
+	case 2:
+		programBinary = flag.Arg(0)
+		traceFile = flag.Arg(1)
+	default:
 		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.
+
+	log.Printf("Parsing trace...")
+	events, err := parseEvents()
+	if err != nil {
+		dief("%v\n", err)
+	}
+
+	log.Printf("Serializing trace...")
+	params := &traceParams{
+		events:  events,
+		endTime: int64(1<<63 - 1),
+	}
+	data := generateTrace(params)
+
+	log.Printf("Splitting trace...")
+	ranges = splitTrace(data)
+
+	log.Printf("Opening browser")
 	if !startBrowser("http://" + ln.Addr().String()) {
 		fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String())
 	}
 
-	// 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 ranges []Range
+
 var loader struct {
 	once   sync.Once
 	events []*trace.Event
@@ -91,7 +116,7 @@ var loader struct {
 
 func parseEvents() ([]*trace.Event, error) {
 	loader.once.Do(func() {
-		tracef, err := os.Open(flag.Arg(1))
+		tracef, err := os.Open(traceFile)
 		if err != nil {
 			loader.err = fmt.Errorf("failed to open trace file: %v", err)
 			return
@@ -99,16 +124,11 @@ func parseEvents() ([]*trace.Event, error) {
 		defer tracef.Close()
 
 		// Parse and symbolize.
-		events, err := trace.Parse(bufio.NewReader(tracef))
+		events, err := trace.Parse(bufio.NewReader(tracef), programBinary)
 		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
@@ -116,13 +136,23 @@ func parseEvents() ([]*trace.Event, error) {
 
 // httpMain serves the starting page.
 func httpMain(w http.ResponseWriter, r *http.Request) {
-	w.Write(templMain)
+	if err := templMain.Execute(w, ranges); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
 }
 
-var templMain = []byte(`
+var templMain = template.Must(template.New("").Parse(`
 <html>
 <body>
-<a href="/trace">View trace</a><br>
+{{if $}}
+	{{range $e := $}}
+		<a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br>
+	{{end}}
+	<br>
+{{else}}
+	<a href="/trace">View trace</a><br>
+{{end}}
 <a href="/goroutines">Goroutine analysis</a><br>
 <a href="/io">Network blocking profile</a><br>
 <a href="/block">Synchronization blocking profile</a><br>
@@ -130,7 +160,7 @@ var templMain = []byte(`
 <a href="/sched">Scheduler latency profile</a><br>
 </body>
 </html>
-`)
+`))
 
 // startBrowser tries to open the URL in a browser
 // and reports whether it succeeds.
diff --git a/src/cmd/trace/pprof.go b/src/cmd/trace/pprof.go
index 154f04d..fdda6d8 100644
--- a/src/cmd/trace/pprof.go
+++ b/src/cmd/trace/pprof.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,6 +8,7 @@ package main
 
 import (
 	"bufio"
+	"cmd/internal/pprof/profile"
 	"fmt"
 	"internal/trace"
 	"io/ioutil"
@@ -133,34 +134,79 @@ func serveSVGProfile(w http.ResponseWriter, r *http.Request, prof map[uint64]Rec
 		http.Error(w, fmt.Sprintf("failed to create temp file: %v", err), http.StatusInternalServerError)
 		return
 	}
-	defer os.Remove(blockf.Name())
+	defer func() {
+		blockf.Close()
+		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")
+	if err := buildProfile(prof).Write(blockb); err != nil {
+		http.Error(w, fmt.Sprintf("failed to write profile: %v", err), http.StatusInternalServerError)
+		return
 	}
-	err = blockb.Flush()
-	if err != nil {
+	if err := blockb.Flush(); err != nil {
 		http.Error(w, fmt.Sprintf("failed to flush temp file: %v", err), http.StatusInternalServerError)
 		return
 	}
-	err = blockf.Close()
-	if err != nil {
+	if err := blockf.Close(); 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)
+	if output, err := exec.Command("go", "tool", "pprof", "-svg", "-output", svgFilename, blockf.Name()).CombinedOutput(); err != nil {
+		http.Error(w, fmt.Sprintf("failed to execute go tool pprof: %v\n%s", err, output), http.StatusInternalServerError)
 		return
 	}
 	defer os.Remove(svgFilename)
 	w.Header().Set("Content-Type", "image/svg+xml")
 	http.ServeFile(w, r, svgFilename)
 }
+
+func buildProfile(prof map[uint64]Record) *profile.Profile {
+	p := &profile.Profile{
+		PeriodType: &profile.ValueType{Type: "trace", Unit: "count"},
+		Period:     1,
+		SampleType: []*profile.ValueType{
+			{Type: "contentions", Unit: "count"},
+			{Type: "delay", Unit: "nanoseconds"},
+		},
+	}
+	locs := make(map[uint64]*profile.Location)
+	funcs := make(map[string]*profile.Function)
+	for _, rec := range prof {
+		var sloc []*profile.Location
+		for _, frame := range rec.stk {
+			loc := locs[frame.PC]
+			if loc == nil {
+				fn := funcs[frame.File+frame.Fn]
+				if fn == nil {
+					fn = &profile.Function{
+						ID:         uint64(len(p.Function) + 1),
+						Name:       frame.Fn,
+						SystemName: frame.Fn,
+						Filename:   frame.File,
+					}
+					p.Function = append(p.Function, fn)
+					funcs[frame.File+frame.Fn] = fn
+				}
+				loc = &profile.Location{
+					ID:      uint64(len(p.Location) + 1),
+					Address: frame.PC,
+					Line: []profile.Line{
+						profile.Line{
+							Function: fn,
+							Line:     int64(frame.Line),
+						},
+					},
+				}
+				p.Location = append(p.Location, loc)
+				locs[frame.PC] = loc
+			}
+			sloc = append(sloc, loc)
+		}
+		p.Sample = append(p.Sample, &profile.Sample{
+			Value:    []int64{int64(rec.n), rec.time},
+			Location: sloc,
+		})
+	}
+	return p
+}
diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go
index e6eb320..2b6a37b 100644
--- a/src/cmd/trace/trace.go
+++ b/src/cmd/trace/trace.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -14,6 +14,7 @@ import (
 	"runtime"
 	"strconv"
 	"strings"
+	"time"
 )
 
 func init() {
@@ -29,34 +30,97 @@ func httpTrace(w http.ResponseWriter, r *http.Request) {
 		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)
+	if err := r.ParseForm(); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
 	}
-	html := strings.Replace(templTrace, "{{PARAMS}}", params, -1)
+	html := strings.Replace(templTrace, "{{PARAMS}}", r.Form.Encode(), -1)
 	w.Write([]byte(html))
 
 }
 
+// See https://github.com/catapult-project/catapult/blob/master/tracing/docs/embedding-trace-viewer.md
+// This is almost verbatim copy of:
+// https://github.com/catapult-project/catapult/blob/master/tracing/bin/index.html
+// on revision 623a005a3ffa9de13c4b92bc72290e7bcd1ca591.
 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>
+<head>
+<link href="/trace_viewer_html" rel="import">
+<script>
+(function() {
+  var viewer;
+  var url;
+  var model;
+
+  function load() {
+    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(event) {
+      if (req.readyState !== 4)
+        return;
+
+      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;
+  }
+
+  function onResult(result) {
+    model = new tr.Model();
+    var i = new tr.importer.Import(model);
+    var p = i.importTracesWithProgressDialog([result]);
+    p.then(onModelLoaded, onImportFail);
+  }
+
+  function onModelLoaded() {
+    viewer.model = model;
+    viewer.viewTitle = "trace";
+  }
+
+  function onImportFail() {
+    var overlay = new tr.ui.b.Overlay();
+    overlay.textContent = tr.b.normalizeException(err).message;
+    overlay.title = 'Import error';
+    overlay.visible = true;
+  }
+
+  document.addEventListener('DOMContentLoaded', function() {
+    var container = document.createElement('track-view-container');
+    container.id = 'track_view_container';
+
+    viewer = document.createElement('tr-ui-timeline-view');
+    viewer.track_view_container = container;
+    viewer.appendChild(container);
+
+    viewer.id = 'trace-viewer';
+    viewer.globalMode = true;
+    document.body.appendChild(viewer);
+
+    url = '/jsontrace?{{PARAMS}}';
+    load();
+  });
+}());
+</script>
+</head>
+<body>
+</body>
 </html>
 `
 
@@ -81,6 +145,7 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
 	}
 
 	if goids := r.FormValue("goid"); goids != "" {
+		// If goid argument is present, we are rendering a trace for this particular goroutine.
 		goid, err := strconv.ParseUint(goids, 10, 64)
 		if err != nil {
 			log.Printf("failed to parse goid parameter '%v': %v", goids, err)
@@ -95,13 +160,81 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
 		params.gs = trace.RelatedGoroutines(events, goid)
 	}
 
-	err = json.NewEncoder(w).Encode(generateTrace(params))
+	data := generateTrace(params)
+
+	if startStr, endStr := r.FormValue("start"), r.FormValue("end"); startStr != "" && endStr != "" {
+		// If start/end arguments are present, we are rendering a range of the trace.
+		start, err := strconv.ParseUint(startStr, 10, 64)
+		if err != nil {
+			log.Printf("failed to parse start parameter '%v': %v", startStr, err)
+			return
+		}
+		end, err := strconv.ParseUint(endStr, 10, 64)
+		if err != nil {
+			log.Printf("failed to parse end parameter '%v': %v", endStr, err)
+			return
+		}
+		if start >= uint64(len(data.Events)) || end <= start || end > uint64(len(data.Events)) {
+			log.Printf("bogus start/end parameters: %v/%v, trace size %v", start, end, len(data.Events))
+			return
+		}
+		data.Events = append(data.Events[start:end], data.Events[data.footer:]...)
+	}
+	err = json.NewEncoder(w).Encode(data)
 	if err != nil {
 		log.Printf("failed to serialize trace: %v", err)
 		return
 	}
 }
 
+type Range struct {
+	Name  string
+	Start int
+	End   int
+}
+
+// splitTrace splits the trace into a number of ranges,
+// each resulting in approx 100MB of json output (trace viewer can hardly handle more).
+func splitTrace(data ViewerData) []Range {
+	const rangeSize = 100 << 20
+	var ranges []Range
+	cw := new(countingWriter)
+	enc := json.NewEncoder(cw)
+	// First calculate size of the mandatory part of the trace.
+	// This includes stack traces and thread names.
+	data1 := data
+	data1.Events = data.Events[data.footer:]
+	enc.Encode(data1)
+	auxSize := cw.size
+	cw.size = 0
+	// Then calculate size of each individual event and group them into ranges.
+	for i, start := 0, 0; i < data.footer; i++ {
+		enc.Encode(data.Events[i])
+		if cw.size+auxSize > rangeSize || i == data.footer-1 {
+			ranges = append(ranges, Range{
+				Name:  fmt.Sprintf("%v-%v", time.Duration(data.Events[start].Time*1000), time.Duration(data.Events[i].Time*1000)),
+				Start: start,
+				End:   i + 1,
+			})
+			start = i + 1
+			cw.size = 0
+		}
+	}
+	if len(ranges) == 1 {
+		ranges = nil
+	}
+	return ranges
+}
+
+type countingWriter struct {
+	size int
+}
+
+func (cw *countingWriter) Write(data []byte) (int, error) {
+	cw.size += len(data)
+	return len(data), nil
+}
+
 type traceParams struct {
 	events    []*trace.Event
 	gtrace    bool
@@ -135,6 +268,9 @@ type ViewerData struct {
 	Events   []*ViewerEvent         `json:"traceEvents"`
 	Frames   map[string]ViewerFrame `json:"stackFrames"`
 	TimeUnit string                 `json:"displayTimeUnit"`
+
+	// This is where mandatory part of the trace starts (e.g. thread names)
+	footer int
 }
 
 type ViewerEvent struct {
@@ -286,6 +422,7 @@ func generateTrace(params *traceParams) ViewerData {
 		}
 	}
 
+	ctx.data.footer = len(ctx.data.Events)
 	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}})
 
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/Makefile b/src/cmd/vendor/golang.org/x/arch/arm/armasm/Makefile
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/Makefile
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/Makefile
diff --git a/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go
new file mode 100644
index 0000000..cc81dc3
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode.go
@@ -0,0 +1,567 @@
+// 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 armasm
+
+import (
+	"encoding/binary"
+	"fmt"
+)
+
+// An instFormat describes the format of an instruction encoding.
+// An instruction with 32-bit value x matches the format if x&mask == value
+// and the condition matches.
+// The condition matches if x>>28 == 0xF && value>>28==0xF
+// or if x>>28 != 0xF and value>>28 == 0.
+// If x matches the format, then the rest of the fields describe how to interpret x.
+// The opBits describe bits that should be extracted from x and added to the opcode.
+// For example opBits = 0x1234 means that the value
+//	(2 bits at offset 1) followed by (4 bits at offset 3)
+// should be added to op.
+// Finally the args describe how to decode the instruction arguments.
+// args is stored as a fixed-size array; if there are fewer than len(args) arguments,
+// args[i] == 0 marks the end of the argument list.
+type instFormat struct {
+	mask     uint32
+	value    uint32
+	priority int8
+	op       Op
+	opBits   uint64
+	args     instArgs
+}
+
+type instArgs [4]instArg
+
+var (
+	errMode    = fmt.Errorf("unsupported execution mode")
+	errShort   = fmt.Errorf("truncated instruction")
+	errUnknown = fmt.Errorf("unknown instruction")
+)
+
+var decoderCover []bool
+
+// Decode decodes the leading bytes in src as a single instruction.
+func Decode(src []byte, mode Mode) (inst Inst, err error) {
+	if mode != ModeARM {
+		return Inst{}, errMode
+	}
+	if len(src) < 4 {
+		return Inst{}, errShort
+	}
+
+	if decoderCover == nil {
+		decoderCover = make([]bool, len(instFormats))
+	}
+
+	x := binary.LittleEndian.Uint32(src)
+
+	// The instFormat table contains both conditional and unconditional instructions.
+	// Considering only the top 4 bits, the conditional instructions use mask=0, value=0,
+	// while the unconditional instructions use mask=f, value=f.
+	// Prepare a version of x with the condition cleared to 0 in conditional instructions
+	// and then assume mask=f during matching.
+	const condMask = 0xf0000000
+	xNoCond := x
+	if x&condMask != condMask {
+		xNoCond &^= condMask
+	}
+	var priority int8
+Search:
+	for i := range instFormats {
+		f := &instFormats[i]
+		if xNoCond&(f.mask|condMask) != f.value || f.priority <= priority {
+			continue
+		}
+		delta := uint32(0)
+		deltaShift := uint(0)
+		for opBits := f.opBits; opBits != 0; opBits >>= 16 {
+			n := uint(opBits & 0xFF)
+			off := uint((opBits >> 8) & 0xFF)
+			delta |= (x >> off) & (1<<n - 1) << deltaShift
+			deltaShift += n
+		}
+		op := f.op + Op(delta)
+
+		// Special case: BKPT encodes with condition but cannot have one.
+		if op&^15 == BKPT_EQ && op != BKPT {
+			continue Search
+		}
+
+		var args Args
+		for j, aop := range f.args {
+			if aop == 0 {
+				break
+			}
+			arg := decodeArg(aop, x)
+			if arg == nil { // cannot decode argument
+				continue Search
+			}
+			args[j] = arg
+		}
+
+		decoderCover[i] = true
+
+		inst = Inst{
+			Op:   op,
+			Args: args,
+			Enc:  x,
+			Len:  4,
+		}
+		priority = f.priority
+		continue Search
+	}
+	if inst.Op != 0 {
+		return inst, nil
+	}
+	return Inst{}, errUnknown
+}
+
+// An instArg describes the encoding of a single argument.
+// In the names used for arguments, _p_ means +, _m_ means -,
+// _pm_ means ± (usually keyed by the U bit).
+// The _W suffix indicates a general addressing mode based on the P and W bits.
+// The _offset and _postindex suffixes force the given addressing mode.
+// The rest should be somewhat self-explanatory, at least given
+// the decodeArg function.
+type instArg uint8
+
+const (
+	_ instArg = iota
+	arg_APSR
+	arg_FPSCR
+	arg_Dn_half
+	arg_R1_0
+	arg_R1_12
+	arg_R2_0
+	arg_R2_12
+	arg_R_0
+	arg_R_12
+	arg_R_12_nzcv
+	arg_R_16
+	arg_R_16_WB
+	arg_R_8
+	arg_R_rotate
+	arg_R_shift_R
+	arg_R_shift_imm
+	arg_SP
+	arg_Sd
+	arg_Sd_Dd
+	arg_Dd_Sd
+	arg_Sm
+	arg_Sm_Dm
+	arg_Sn
+	arg_Sn_Dn
+	arg_const
+	arg_endian
+	arg_fbits
+	arg_fp_0
+	arg_imm24
+	arg_imm5
+	arg_imm5_32
+	arg_imm5_nz
+	arg_imm_12at8_4at0
+	arg_imm_4at16_12at0
+	arg_imm_vfp
+	arg_label24
+	arg_label24H
+	arg_label_m_12
+	arg_label_p_12
+	arg_label_pm_12
+	arg_label_pm_4_4
+	arg_lsb_width
+	arg_mem_R
+	arg_mem_R_pm_R_W
+	arg_mem_R_pm_R_postindex
+	arg_mem_R_pm_R_shift_imm_W
+	arg_mem_R_pm_R_shift_imm_offset
+	arg_mem_R_pm_R_shift_imm_postindex
+	arg_mem_R_pm_imm12_W
+	arg_mem_R_pm_imm12_offset
+	arg_mem_R_pm_imm12_postindex
+	arg_mem_R_pm_imm8_W
+	arg_mem_R_pm_imm8_postindex
+	arg_mem_R_pm_imm8at0_offset
+	arg_option
+	arg_registers
+	arg_registers1
+	arg_registers2
+	arg_satimm4
+	arg_satimm5
+	arg_satimm4m1
+	arg_satimm5m1
+	arg_widthm1
+)
+
+// decodeArg decodes the arg described by aop from the instruction bits x.
+// It returns nil if x cannot be decoded according to aop.
+func decodeArg(aop instArg, x uint32) Arg {
+	switch aop {
+	default:
+		return nil
+
+	case arg_APSR:
+		return APSR
+	case arg_FPSCR:
+		return FPSCR
+
+	case arg_R_0:
+		return Reg(x & (1<<4 - 1))
+	case arg_R_8:
+		return Reg((x >> 8) & (1<<4 - 1))
+	case arg_R_12:
+		return Reg((x >> 12) & (1<<4 - 1))
+	case arg_R_16:
+		return Reg((x >> 16) & (1<<4 - 1))
+
+	case arg_R_12_nzcv:
+		r := Reg((x >> 12) & (1<<4 - 1))
+		if r == R15 {
+			return APSR_nzcv
+		}
+		return r
+
+	case arg_R_16_WB:
+		mode := AddrLDM
+		if (x>>21)&1 != 0 {
+			mode = AddrLDM_WB
+		}
+		return Mem{Base: Reg((x >> 16) & (1<<4 - 1)), Mode: mode}
+
+	case arg_R_rotate:
+		Rm := Reg(x & (1<<4 - 1))
+		typ, count := decodeShift(x)
+		// ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1.
+		if typ == RotateRightExt {
+			return Rm
+		}
+		return RegShift{Rm, typ, count}
+
+	case arg_R_shift_R:
+		Rm := Reg(x & (1<<4 - 1))
+		Rs := Reg((x >> 8) & (1<<4 - 1))
+		typ := Shift((x >> 5) & (1<<2 - 1))
+		return RegShiftReg{Rm, typ, Rs}
+
+	case arg_R_shift_imm:
+		Rm := Reg(x & (1<<4 - 1))
+		typ, count := decodeShift(x)
+		if typ == ShiftLeft && count == 0 {
+			return Rm
+		}
+		return RegShift{Rm, typ, count}
+
+	case arg_R1_0:
+		return Reg((x & (1<<4 - 1)))
+	case arg_R1_12:
+		return Reg(((x >> 12) & (1<<4 - 1)))
+	case arg_R2_0:
+		return Reg((x & (1<<4 - 1)) | 1)
+	case arg_R2_12:
+		return Reg(((x >> 12) & (1<<4 - 1)) | 1)
+
+	case arg_SP:
+		return SP
+
+	case arg_Sd_Dd:
+		v := (x >> 12) & (1<<4 - 1)
+		vx := (x >> 22) & 1
+		sz := (x >> 8) & 1
+		if sz != 0 {
+			return D0 + Reg(vx<<4+v)
+		} else {
+			return S0 + Reg(v<<1+vx)
+		}
+
+	case arg_Dd_Sd:
+		return decodeArg(arg_Sd_Dd, x^(1<<8))
+
+	case arg_Sd:
+		v := (x >> 12) & (1<<4 - 1)
+		vx := (x >> 22) & 1
+		return S0 + Reg(v<<1+vx)
+
+	case arg_Sm_Dm:
+		v := (x >> 0) & (1<<4 - 1)
+		vx := (x >> 5) & 1
+		sz := (x >> 8) & 1
+		if sz != 0 {
+			return D0 + Reg(vx<<4+v)
+		} else {
+			return S0 + Reg(v<<1+vx)
+		}
+
+	case arg_Sm:
+		v := (x >> 0) & (1<<4 - 1)
+		vx := (x >> 5) & 1
+		return S0 + Reg(v<<1+vx)
+
+	case arg_Dn_half:
+		v := (x >> 16) & (1<<4 - 1)
+		vx := (x >> 7) & 1
+		return RegX{D0 + Reg(vx<<4+v), int((x >> 21) & 1)}
+
+	case arg_Sn_Dn:
+		v := (x >> 16) & (1<<4 - 1)
+		vx := (x >> 7) & 1
+		sz := (x >> 8) & 1
+		if sz != 0 {
+			return D0 + Reg(vx<<4+v)
+		} else {
+			return S0 + Reg(v<<1+vx)
+		}
+
+	case arg_Sn:
+		v := (x >> 16) & (1<<4 - 1)
+		vx := (x >> 7) & 1
+		return S0 + Reg(v<<1+vx)
+
+	case arg_const:
+		v := x & (1<<8 - 1)
+		rot := (x >> 8) & (1<<4 - 1) * 2
+		if rot > 0 && v&3 == 0 {
+			// could rotate less
+			return ImmAlt{uint8(v), uint8(rot)}
+		}
+		if rot >= 24 && ((v<<(32-rot))&0xFF)>>(32-rot) == v {
+			// could wrap around to rot==0.
+			return ImmAlt{uint8(v), uint8(rot)}
+		}
+		return Imm(v>>rot | v<<(32-rot))
+
+	case arg_endian:
+		return Endian((x >> 9) & 1)
+
+	case arg_fbits:
+		return Imm((16 << ((x >> 7) & 1)) - ((x&(1<<4-1))<<1 | (x>>5)&1))
+
+	case arg_fp_0:
+		return Imm(0)
+
+	case arg_imm24:
+		return Imm(x & (1<<24 - 1))
+
+	case arg_imm5:
+		return Imm((x >> 7) & (1<<5 - 1))
+
+	case arg_imm5_32:
+		x = (x >> 7) & (1<<5 - 1)
+		if x == 0 {
+			x = 32
+		}
+		return Imm(x)
+
+	case arg_imm5_nz:
+		x = (x >> 7) & (1<<5 - 1)
+		if x == 0 {
+			return nil
+		}
+		return Imm(x)
+
+	case arg_imm_4at16_12at0:
+		return Imm((x>>16)&(1<<4-1)<<12 | x&(1<<12-1))
+
+	case arg_imm_12at8_4at0:
+		return Imm((x>>8)&(1<<12-1)<<4 | x&(1<<4-1))
+
+	case arg_imm_vfp:
+		x = (x>>16)&(1<<4-1)<<4 | x&(1<<4-1)
+		return Imm(x)
+
+	case arg_label24:
+		imm := (x & (1<<24 - 1)) << 2
+		return PCRel(int32(imm<<6) >> 6)
+
+	case arg_label24H:
+		h := (x >> 24) & 1
+		imm := (x&(1<<24-1))<<2 | h<<1
+		return PCRel(int32(imm<<6) >> 6)
+
+	case arg_label_m_12:
+		d := int32(x & (1<<12 - 1))
+		return Mem{Base: PC, Mode: AddrOffset, Offset: int16(-d)}
+
+	case arg_label_p_12:
+		d := int32(x & (1<<12 - 1))
+		return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)}
+
+	case arg_label_pm_12:
+		d := int32(x & (1<<12 - 1))
+		u := (x >> 23) & 1
+		if u == 0 {
+			d = -d
+		}
+		return Mem{Base: PC, Mode: AddrOffset, Offset: int16(d)}
+
+	case arg_label_pm_4_4:
+		d := int32((x>>8)&(1<<4-1)<<4 | x&(1<<4-1))
+		u := (x >> 23) & 1
+		if u == 0 {
+			d = -d
+		}
+		return PCRel(d)
+
+	case arg_lsb_width:
+		lsb := (x >> 7) & (1<<5 - 1)
+		msb := (x >> 16) & (1<<5 - 1)
+		if msb < lsb || msb >= 32 {
+			return nil
+		}
+		return Imm(msb + 1 - lsb)
+
+	case arg_mem_R:
+		Rn := Reg((x >> 16) & (1<<4 - 1))
+		return Mem{Base: Rn, Mode: AddrOffset}
+
+	case arg_mem_R_pm_R_postindex:
+		// Treat [<Rn>],+/-<Rm> like [<Rn>,+/-<Rm>{,<shift>}]{!}
+		// by forcing shift bits to <<0 and P=0, W=0 (postindex=true).
+		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5|1<<24|1<<21))
+
+	case arg_mem_R_pm_R_W:
+		// Treat [<Rn>,+/-<Rm>]{!} like [<Rn>,+/-<Rm>{,<shift>}]{!}
+		// by forcing shift bits to <<0.
+		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^((1<<7-1)<<5))
+
+	case arg_mem_R_pm_R_shift_imm_offset:
+		// Treat [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
+		// by forcing P=1, W=0 (index=false, wback=false).
+		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<21)|1<<24)
+
+	case arg_mem_R_pm_R_shift_imm_postindex:
+		// Treat [<Rn>],+/-<Rm>{,<shift>} like [<Rn>,+/-<Rm>{,<shift>}]{!}
+		// by forcing P=0, W=0 (postindex=true).
+		return decodeArg(arg_mem_R_pm_R_shift_imm_W, x&^(1<<24|1<<21))
+
+	case arg_mem_R_pm_R_shift_imm_W:
+		Rn := Reg((x >> 16) & (1<<4 - 1))
+		Rm := Reg(x & (1<<4 - 1))
+		typ, count := decodeShift(x)
+		u := (x >> 23) & 1
+		w := (x >> 21) & 1
+		p := (x >> 24) & 1
+		if p == 0 && w == 1 {
+			return nil
+		}
+		sign := int8(+1)
+		if u == 0 {
+			sign = -1
+		}
+		mode := AddrMode(uint8(p<<1) | uint8(w^1))
+		return Mem{Base: Rn, Mode: mode, Sign: sign, Index: Rm, Shift: typ, Count: count}
+
+	case arg_mem_R_pm_imm12_offset:
+		// Treat [<Rn>,#+/-<imm12>] like [<Rn>{,#+/-<imm12>}]{!}
+		// by forcing P=1, W=0 (index=false, wback=false).
+		return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<21)|1<<24)
+
+	case arg_mem_R_pm_imm12_postindex:
+		// Treat [<Rn>],#+/-<imm12> like [<Rn>{,#+/-<imm12>}]{!}
+		// by forcing P=0, W=0 (postindex=true).
+		return decodeArg(arg_mem_R_pm_imm12_W, x&^(1<<24|1<<21))
+
+	case arg_mem_R_pm_imm12_W:
+		Rn := Reg((x >> 16) & (1<<4 - 1))
+		u := (x >> 23) & 1
+		w := (x >> 21) & 1
+		p := (x >> 24) & 1
+		if p == 0 && w == 1 {
+			return nil
+		}
+		sign := int8(+1)
+		if u == 0 {
+			sign = -1
+		}
+		imm := int16(x & (1<<12 - 1))
+		mode := AddrMode(uint8(p<<1) | uint8(w^1))
+		return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm}
+
+	case arg_mem_R_pm_imm8_postindex:
+		// Treat [<Rn>],#+/-<imm8> like [<Rn>{,#+/-<imm8>}]{!}
+		// by forcing P=0, W=0 (postindex=true).
+		return decodeArg(arg_mem_R_pm_imm8_W, x&^(1<<24|1<<21))
+
+	case arg_mem_R_pm_imm8_W:
+		Rn := Reg((x >> 16) & (1<<4 - 1))
+		u := (x >> 23) & 1
+		w := (x >> 21) & 1
+		p := (x >> 24) & 1
+		if p == 0 && w == 1 {
+			return nil
+		}
+		sign := int8(+1)
+		if u == 0 {
+			sign = -1
+		}
+		imm := int16((x>>8)&(1<<4-1)<<4 | x&(1<<4-1))
+		mode := AddrMode(uint8(p<<1) | uint8(w^1))
+		return Mem{Base: Rn, Mode: mode, Offset: int16(sign) * imm}
+
+	case arg_mem_R_pm_imm8at0_offset:
+		Rn := Reg((x >> 16) & (1<<4 - 1))
+		u := (x >> 23) & 1
+		sign := int8(+1)
+		if u == 0 {
+			sign = -1
+		}
+		imm := int16(x&(1<<8-1)) << 2
+		return Mem{Base: Rn, Mode: AddrOffset, Offset: int16(sign) * imm}
+
+	case arg_option:
+		return Imm(x & (1<<4 - 1))
+
+	case arg_registers:
+		return RegList(x & (1<<16 - 1))
+
+	case arg_registers2:
+		x &= 1<<16 - 1
+		n := 0
+		for i := 0; i < 16; i++ {
+			if x>>uint(i)&1 != 0 {
+				n++
+			}
+		}
+		if n < 2 {
+			return nil
+		}
+		return RegList(x)
+
+	case arg_registers1:
+		Rt := (x >> 12) & (1<<4 - 1)
+		return RegList(1 << Rt)
+
+	case arg_satimm4:
+		return Imm((x >> 16) & (1<<4 - 1))
+
+	case arg_satimm5:
+		return Imm((x >> 16) & (1<<5 - 1))
+
+	case arg_satimm4m1:
+		return Imm((x>>16)&(1<<4-1) + 1)
+
+	case arg_satimm5m1:
+		return Imm((x>>16)&(1<<5-1) + 1)
+
+	case arg_widthm1:
+		return Imm((x>>16)&(1<<5-1) + 1)
+
+	}
+}
+
+// decodeShift decodes the shift-by-immediate encoded in x.
+func decodeShift(x uint32) (Shift, uint8) {
+	count := (x >> 7) & (1<<5 - 1)
+	typ := Shift((x >> 5) & (1<<2 - 1))
+	switch typ {
+	case ShiftRight, ShiftRightSigned:
+		if count == 0 {
+			count = 32
+		}
+	case RotateRight:
+		if count == 0 {
+			typ = RotateRightExt
+			count = 1
+		}
+	}
+	return typ, uint8(count)
+}
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode_test.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/decode_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode_test.go
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/decode_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/ext_test.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/ext_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/ext_test.go
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/ext_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/gnu.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/gnu.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/gnu.go
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/gnu.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/inst.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/inst.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/inst.go
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/inst.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdump_test.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/objdump_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdump_test.go
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/objdump_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdumpext_test.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/objdumpext_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/objdumpext_test.go
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/objdumpext_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/plan9x.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/plan9x.go
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/tables.go b/src/cmd/vendor/golang.org/x/arch/arm/armasm/tables.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/tables.go
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/tables.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/Makefile b/src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/Makefile
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/Makefile
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/Makefile
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/decode.txt b/src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/decode.txt
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/testdata/decode.txt
rename to src/cmd/vendor/golang.org/x/arch/arm/armasm/testdata/decode.txt
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/Makefile b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/Makefile
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/Makefile
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/Makefile
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go
new file mode 100644
index 0000000..9b35973
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode.go
@@ -0,0 +1,1646 @@
+// 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.
+
+// Table-driven decoding of x86 instructions.
+
+package x86asm
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"runtime"
+)
+
+// Set trace to true to cause the decoder to print the PC sequence
+// of the executed instruction codes. This is typically only useful
+// when you are running a test of a single input case.
+const trace = false
+
+// A decodeOp is a single instruction in the decoder bytecode program.
+//
+// The decodeOps correspond to consuming and conditionally branching
+// on input bytes, consuming additional fields, and then interpreting
+// consumed data as instruction arguments. The names of the xRead and xArg
+// operations are taken from the Intel manual conventions, for example
+// Volume 2, Section 3.1.1, page 487 of
+// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf
+//
+// The actual decoding program is generated by ../x86map.
+//
+// TODO(rsc): We may be able to merge various of the memory operands
+// since we don't care about, say, the distinction between m80dec and m80bcd.
+// Similarly, mm and mm1 have identical meaning, as do xmm and xmm1.
+
+type decodeOp uint16
+
+const (
+	xFail  decodeOp = iota // invalid instruction (return)
+	xMatch                 // completed match
+	xJump                  // jump to pc
+
+	xCondByte     // switch on instruction byte value
+	xCondSlashR   // read and switch on instruction /r value
+	xCondPrefix   // switch on presence of instruction prefix
+	xCondIs64     // switch on 64-bit processor mode
+	xCondDataSize // switch on operand size
+	xCondAddrSize // switch on address size
+	xCondIsMem    // switch on memory vs register argument
+
+	xSetOp // set instruction opcode
+
+	xReadSlashR // read /r
+	xReadIb     // read ib
+	xReadIw     // read iw
+	xReadId     // read id
+	xReadIo     // read io
+	xReadCb     // read cb
+	xReadCw     // read cw
+	xReadCd     // read cd
+	xReadCp     // read cp
+	xReadCm     // read cm
+
+	xArg1            // arg 1
+	xArg3            // arg 3
+	xArgAL           // arg AL
+	xArgAX           // arg AX
+	xArgCL           // arg CL
+	xArgCR0dashCR7   // arg CR0-CR7
+	xArgCS           // arg CS
+	xArgDR0dashDR7   // arg DR0-DR7
+	xArgDS           // arg DS
+	xArgDX           // arg DX
+	xArgEAX          // arg EAX
+	xArgEDX          // arg EDX
+	xArgES           // arg ES
+	xArgFS           // arg FS
+	xArgGS           // arg GS
+	xArgImm16        // arg imm16
+	xArgImm32        // arg imm32
+	xArgImm64        // arg imm64
+	xArgImm8         // arg imm8
+	xArgImm8u        // arg imm8 but record as unsigned
+	xArgImm16u       // arg imm8 but record as unsigned
+	xArgM            // arg m
+	xArgM128         // arg m128
+	xArgM1428byte    // arg m14/28byte
+	xArgM16          // arg m16
+	xArgM16and16     // arg m16&16
+	xArgM16and32     // arg m16&32
+	xArgM16and64     // arg m16&64
+	xArgM16colon16   // arg m16:16
+	xArgM16colon32   // arg m16:32
+	xArgM16colon64   // arg m16:64
+	xArgM16int       // arg m16int
+	xArgM2byte       // arg m2byte
+	xArgM32          // arg m32
+	xArgM32and32     // arg m32&32
+	xArgM32fp        // arg m32fp
+	xArgM32int       // arg m32int
+	xArgM512byte     // arg m512byte
+	xArgM64          // arg m64
+	xArgM64fp        // arg m64fp
+	xArgM64int       // arg m64int
+	xArgM8           // arg m8
+	xArgM80bcd       // arg m80bcd
+	xArgM80dec       // arg m80dec
+	xArgM80fp        // arg m80fp
+	xArgM94108byte   // arg m94/108byte
+	xArgMm           // arg mm
+	xArgMm1          // arg mm1
+	xArgMm2          // arg mm2
+	xArgMm2M64       // arg mm2/m64
+	xArgMmM32        // arg mm/m32
+	xArgMmM64        // arg mm/m64
+	xArgMem          // arg mem
+	xArgMoffs16      // arg moffs16
+	xArgMoffs32      // arg moffs32
+	xArgMoffs64      // arg moffs64
+	xArgMoffs8       // arg moffs8
+	xArgPtr16colon16 // arg ptr16:16
+	xArgPtr16colon32 // arg ptr16:32
+	xArgR16          // arg r16
+	xArgR16op        // arg r16 with +rw in opcode
+	xArgR32          // arg r32
+	xArgR32M16       // arg r32/m16
+	xArgR32M8        // arg r32/m8
+	xArgR32op        // arg r32 with +rd in opcode
+	xArgR64          // arg r64
+	xArgR64M16       // arg r64/m16
+	xArgR64op        // arg r64 with +rd in opcode
+	xArgR8           // arg r8
+	xArgR8op         // arg r8 with +rb in opcode
+	xArgRAX          // arg RAX
+	xArgRDX          // arg RDX
+	xArgRM           // arg r/m
+	xArgRM16         // arg r/m16
+	xArgRM32         // arg r/m32
+	xArgRM64         // arg r/m64
+	xArgRM8          // arg r/m8
+	xArgReg          // arg reg
+	xArgRegM16       // arg reg/m16
+	xArgRegM32       // arg reg/m32
+	xArgRegM8        // arg reg/m8
+	xArgRel16        // arg rel16
+	xArgRel32        // arg rel32
+	xArgRel8         // arg rel8
+	xArgSS           // arg SS
+	xArgST           // arg ST, aka ST(0)
+	xArgSTi          // arg ST(i) with +i in opcode
+	xArgSreg         // arg Sreg
+	xArgTR0dashTR7   // arg TR0-TR7
+	xArgXmm          // arg xmm
+	xArgXMM0         // arg <XMM0>
+	xArgXmm1         // arg xmm1
+	xArgXmm2         // arg xmm2
+	xArgXmm2M128     // arg xmm2/m128
+	xArgXmm2M16      // arg xmm2/m16
+	xArgXmm2M32      // arg xmm2/m32
+	xArgXmm2M64      // arg xmm2/m64
+	xArgXmmM128      // arg xmm/m128
+	xArgXmmM32       // arg xmm/m32
+	xArgXmmM64       // arg xmm/m64
+	xArgRmf16        // arg r/m16 but force mod=3
+	xArgRmf32        // arg r/m32 but force mod=3
+	xArgRmf64        // arg r/m64 but force mod=3
+)
+
+// instPrefix returns an Inst describing just one prefix byte.
+// It is only used if there is a prefix followed by an unintelligible
+// or invalid instruction byte sequence.
+func instPrefix(b byte, mode int) (Inst, error) {
+	// When tracing it is useful to see what called instPrefix to report an error.
+	if trace {
+		_, file, line, _ := runtime.Caller(1)
+		fmt.Printf("%s:%d\n", file, line)
+	}
+	p := Prefix(b)
+	switch p {
+	case PrefixDataSize:
+		if mode == 16 {
+			p = PrefixData32
+		} else {
+			p = PrefixData16
+		}
+	case PrefixAddrSize:
+		if mode == 32 {
+			p = PrefixAddr16
+		} else {
+			p = PrefixAddr32
+		}
+	}
+	// Note: using composite literal with Prefix key confuses 'bundle' tool.
+	inst := Inst{Len: 1}
+	inst.Prefix = Prefixes{p}
+	return inst, nil
+}
+
+// truncated reports a truncated instruction.
+// For now we use instPrefix but perhaps later we will return
+// a specific error here.
+func truncated(src []byte, mode int) (Inst, error) {
+	//	return Inst{}, len(src), ErrTruncated
+	return instPrefix(src[0], mode) // too long
+}
+
+// These are the errors returned by Decode.
+var (
+	ErrInvalidMode  = errors.New("invalid x86 mode in Decode")
+	ErrTruncated    = errors.New("truncated instruction")
+	ErrUnrecognized = errors.New("unrecognized instruction")
+)
+
+// decoderCover records coverage information for which parts
+// of the byte code have been executed.
+// TODO(rsc): This is for testing. Only use this if a flag is given.
+var decoderCover []bool
+
+// Decode decodes the leading bytes in src as a single instruction.
+// The mode arguments specifies the assumed processor mode:
+// 16, 32, or 64 for 16-, 32-, and 64-bit execution modes.
+func Decode(src []byte, mode int) (inst Inst, err error) {
+	return decode1(src, mode, false)
+}
+
+// decode1 is the implementation of Decode but takes an extra
+// gnuCompat flag to cause it to change its behavior to mimic
+// bugs (or at least unique features) of GNU libopcodes as used
+// by objdump. We don't believe that logic is the right thing to do
+// in general, but when testing against libopcodes it simplifies the
+// comparison if we adjust a few small pieces of logic.
+// The affected logic is in the conditional branch for "mandatory" prefixes,
+// case xCondPrefix.
+func decode1(src []byte, mode int, gnuCompat bool) (Inst, error) {
+	switch mode {
+	case 16, 32, 64:
+		// ok
+		// TODO(rsc): 64-bit mode not tested, probably not working.
+	default:
+		return Inst{}, ErrInvalidMode
+	}
+
+	// Maximum instruction size is 15 bytes.
+	// If we need to read more, return 'truncated instruction.
+	if len(src) > 15 {
+		src = src[:15]
+	}
+
+	var (
+		// prefix decoding information
+		pos           = 0    // position reading src
+		nprefix       = 0    // number of prefixes
+		lockIndex     = -1   // index of LOCK prefix in src and inst.Prefix
+		repIndex      = -1   // index of REP/REPN prefix in src and inst.Prefix
+		segIndex      = -1   // index of Group 2 prefix in src and inst.Prefix
+		dataSizeIndex = -1   // index of Group 3 prefix in src and inst.Prefix
+		addrSizeIndex = -1   // index of Group 4 prefix in src and inst.Prefix
+		rex           Prefix // rex byte if present (or 0)
+		rexUsed       Prefix // bits used in rex byte
+		rexIndex      = -1   // index of rex byte
+
+		addrMode = mode // address mode (width in bits)
+		dataMode = mode // operand mode (width in bits)
+
+		// decoded ModR/M fields
+		haveModrm bool
+		modrm     int
+		mod       int
+		regop     int
+		rm        int
+
+		// if ModR/M is memory reference, Mem form
+		mem     Mem
+		haveMem bool
+
+		// decoded SIB fields
+		haveSIB bool
+		sib     int
+		scale   int
+		index   int
+		base    int
+		displen int
+		dispoff int
+
+		// decoded immediate values
+		imm     int64
+		imm8    int8
+		immc    int64
+		immcpos int
+
+		// output
+		opshift int
+		inst    Inst
+		narg    int // number of arguments written to inst
+	)
+
+	if mode == 64 {
+		dataMode = 32
+	}
+
+	// Prefixes are certainly the most complex and underspecified part of
+	// decoding x86 instructions. Although the manuals say things like
+	// up to four prefixes, one from each group, nearly everyone seems to
+	// agree that in practice as many prefixes as possible, including multiple
+	// from a particular group or repetitions of a given prefix, can be used on
+	// an instruction, provided the total instruction length including prefixes
+	// does not exceed the agreed-upon maximum of 15 bytes.
+	// Everyone also agrees that if one of these prefixes is the LOCK prefix
+	// and the instruction is not one of the instructions that can be used with
+	// the LOCK prefix or if the destination is not a memory operand,
+	// then the instruction is invalid and produces the #UD exception.
+	// However, that is the end of any semblance of agreement.
+	//
+	// What happens if prefixes are given that conflict with other prefixes?
+	// For example, the memory segment overrides CS, DS, ES, FS, GS, SS
+	// conflict with each other: only one segment can be in effect.
+	// Disassemblers seem to agree that later prefixes take priority over
+	// earlier ones. I have not taken the time to write assembly programs
+	// to check to see if the hardware agrees.
+	//
+	// What happens if prefixes are given that have no meaning for the
+	// specific instruction to which they are attached? It depends.
+	// If they really have no meaning, they are ignored. However, a future
+	// processor may assign a different meaning. As a disassembler, we
+	// don't really know whether we're seeing a meaningless prefix or one
+	// whose meaning we simply haven't been told yet.
+	//
+	// Combining the two questions, what happens when conflicting
+	// extension prefixes are given? No one seems to know for sure.
+	// For example, MOVQ is 66 0F D6 /r, MOVDQ2Q is F2 0F D6 /r,
+	// and MOVQ2DQ is F3 0F D6 /r. What is '66 F2 F3 0F D6 /r'?
+	// Which prefix wins? See the xCondPrefix prefix for more.
+	//
+	// Writing assembly test cases to divine which interpretation the
+	// CPU uses might clarify the situation, but more likely it would
+	// make the situation even less clear.
+
+	// Read non-REX prefixes.
+ReadPrefixes:
+	for ; pos < len(src); pos++ {
+		p := Prefix(src[pos])
+		switch p {
+		default:
+			nprefix = pos
+			break ReadPrefixes
+
+		// Group 1 - lock and repeat prefixes
+		// According to Intel, there should only be one from this set,
+		// but according to AMD both can be present.
+		case 0xF0:
+			if lockIndex >= 0 {
+				inst.Prefix[lockIndex] |= PrefixIgnored
+			}
+			lockIndex = pos
+		case 0xF2, 0xF3:
+			if repIndex >= 0 {
+				inst.Prefix[repIndex] |= PrefixIgnored
+			}
+			repIndex = pos
+
+		// Group 2 - segment override / branch hints
+		case 0x26, 0x2E, 0x36, 0x3E:
+			if mode == 64 {
+				p |= PrefixIgnored
+				break
+			}
+			fallthrough
+		case 0x64, 0x65:
+			if segIndex >= 0 {
+				inst.Prefix[segIndex] |= PrefixIgnored
+			}
+			segIndex = pos
+
+		// Group 3 - operand size override
+		case 0x66:
+			if mode == 16 {
+				dataMode = 32
+				p = PrefixData32
+			} else {
+				dataMode = 16
+				p = PrefixData16
+			}
+			if dataSizeIndex >= 0 {
+				inst.Prefix[dataSizeIndex] |= PrefixIgnored
+			}
+			dataSizeIndex = pos
+
+		// Group 4 - address size override
+		case 0x67:
+			if mode == 32 {
+				addrMode = 16
+				p = PrefixAddr16
+			} else {
+				addrMode = 32
+				p = PrefixAddr32
+			}
+			if addrSizeIndex >= 0 {
+				inst.Prefix[addrSizeIndex] |= PrefixIgnored
+			}
+			addrSizeIndex = pos
+		}
+
+		if pos >= len(inst.Prefix) {
+			return instPrefix(src[0], mode) // too long
+		}
+
+		inst.Prefix[pos] = p
+	}
+
+	// Read REX prefix.
+	if pos < len(src) && mode == 64 && Prefix(src[pos]).IsREX() {
+		rex = Prefix(src[pos])
+		rexIndex = pos
+		if pos >= len(inst.Prefix) {
+			return instPrefix(src[0], mode) // too long
+		}
+		inst.Prefix[pos] = rex
+		pos++
+		if rex&PrefixREXW != 0 {
+			dataMode = 64
+			if dataSizeIndex >= 0 {
+				inst.Prefix[dataSizeIndex] |= PrefixIgnored
+			}
+		}
+	}
+
+	// Decode instruction stream, interpreting decoding instructions.
+	// opshift gives the shift to use when saving the next
+	// opcode byte into inst.Opcode.
+	opshift = 24
+	if decoderCover == nil {
+		decoderCover = make([]bool, len(decoder))
+	}
+
+	// Decode loop, executing decoder program.
+	var oldPC, prevPC int
+Decode:
+	for pc := 1; ; { // TODO uint
+		oldPC = prevPC
+		prevPC = pc
+		if trace {
+			println("run", pc)
+		}
+		x := decoder[pc]
+		decoderCover[pc] = true
+		pc++
+
+		// Read and decode ModR/M if needed by opcode.
+		switch decodeOp(x) {
+		case xCondSlashR, xReadSlashR:
+			if haveModrm {
+				return Inst{Len: pos}, errInternal
+			}
+			haveModrm = true
+			if pos >= len(src) {
+				return truncated(src, mode)
+			}
+			modrm = int(src[pos])
+			pos++
+			if opshift >= 0 {
+				inst.Opcode |= uint32(modrm) << uint(opshift)
+				opshift -= 8
+			}
+			mod = modrm >> 6
+			regop = (modrm >> 3) & 07
+			rm = modrm & 07
+			if rex&PrefixREXR != 0 {
+				rexUsed |= PrefixREXR
+				regop |= 8
+			}
+			if addrMode == 16 {
+				// 16-bit modrm form
+				if mod != 3 {
+					haveMem = true
+					mem = addr16[rm]
+					if rm == 6 && mod == 0 {
+						mem.Base = 0
+					}
+
+					// Consume disp16 if present.
+					if mod == 0 && rm == 6 || mod == 2 {
+						if pos+2 > len(src) {
+							return truncated(src, mode)
+						}
+						mem.Disp = int64(binary.LittleEndian.Uint16(src[pos:]))
+						pos += 2
+					}
+
+					// Consume disp8 if present.
+					if mod == 1 {
+						if pos >= len(src) {
+							return truncated(src, mode)
+						}
+						mem.Disp = int64(int8(src[pos]))
+						pos++
+					}
+				}
+			} else {
+				haveMem = mod != 3
+
+				// 32-bit or 64-bit form
+				// Consume SIB encoding if present.
+				if rm == 4 && mod != 3 {
+					haveSIB = true
+					if pos >= len(src) {
+						return truncated(src, mode)
+					}
+					sib = int(src[pos])
+					pos++
+					if opshift >= 0 {
+						inst.Opcode |= uint32(sib) << uint(opshift)
+						opshift -= 8
+					}
+					scale = sib >> 6
+					index = (sib >> 3) & 07
+					base = sib & 07
+					if rex&PrefixREXB != 0 {
+						rexUsed |= PrefixREXB
+						base |= 8
+					}
+					if rex&PrefixREXX != 0 {
+						rexUsed |= PrefixREXX
+						index |= 8
+					}
+
+					mem.Scale = 1 << uint(scale)
+					if index == 4 {
+						// no mem.Index
+					} else {
+						mem.Index = baseRegForBits(addrMode) + Reg(index)
+					}
+					if base&7 == 5 && mod == 0 {
+						// no mem.Base
+					} else {
+						mem.Base = baseRegForBits(addrMode) + Reg(base)
+					}
+				} else {
+					if rex&PrefixREXB != 0 {
+						rexUsed |= PrefixREXB
+						rm |= 8
+					}
+					if mod == 0 && rm&7 == 5 || rm&7 == 4 {
+						// base omitted
+					} else if mod != 3 {
+						mem.Base = baseRegForBits(addrMode) + Reg(rm)
+					}
+				}
+
+				// Consume disp32 if present.
+				if mod == 0 && (rm&7 == 5 || haveSIB && base&7 == 5) || mod == 2 {
+					if pos+4 > len(src) {
+						return truncated(src, mode)
+					}
+					dispoff = pos
+					displen = 4
+					mem.Disp = int64(binary.LittleEndian.Uint32(src[pos:]))
+					pos += 4
+				}
+
+				// Consume disp8 if present.
+				if mod == 1 {
+					if pos >= len(src) {
+						return truncated(src, mode)
+					}
+					dispoff = pos
+					displen = 1
+					mem.Disp = int64(int8(src[pos]))
+					pos++
+				}
+
+				// In 64-bit, mod=0 rm=5 is PC-relative instead of just disp.
+				// See Vol 2A. Table 2-7.
+				if mode == 64 && mod == 0 && rm&7 == 5 {
+					if addrMode == 32 {
+						mem.Base = EIP
+					} else {
+						mem.Base = RIP
+					}
+				}
+			}
+
+			if segIndex >= 0 {
+				mem.Segment = prefixToSegment(inst.Prefix[segIndex])
+			}
+		}
+
+		// Execute single opcode.
+		switch decodeOp(x) {
+		default:
+			println("bad op", x, "at", pc-1, "from", oldPC)
+			return Inst{Len: pos}, errInternal
+
+		case xFail:
+			inst.Op = 0
+			break Decode
+
+		case xMatch:
+			break Decode
+
+		case xJump:
+			pc = int(decoder[pc])
+
+		// Conditional branches.
+
+		case xCondByte:
+			if pos >= len(src) {
+				return truncated(src, mode)
+			}
+			b := src[pos]
+			n := int(decoder[pc])
+			pc++
+			for i := 0; i < n; i++ {
+				xb, xpc := decoder[pc], int(decoder[pc+1])
+				pc += 2
+				if b == byte(xb) {
+					pc = xpc
+					pos++
+					if opshift >= 0 {
+						inst.Opcode |= uint32(b) << uint(opshift)
+						opshift -= 8
+					}
+					continue Decode
+				}
+			}
+			// xCondByte is the only conditional with a fall through,
+			// so that it can be used to pick off special cases before
+			// an xCondSlash. If the fallthrough instruction is xFail,
+			// advance the position so that the decoded instruction
+			// size includes the byte we just compared against.
+			if decodeOp(decoder[pc]) == xJump {
+				pc = int(decoder[pc+1])
+			}
+			if decodeOp(decoder[pc]) == xFail {
+				pos++
+			}
+
+		case xCondIs64:
+			if mode == 64 {
+				pc = int(decoder[pc+1])
+			} else {
+				pc = int(decoder[pc])
+			}
+
+		case xCondIsMem:
+			mem := haveMem
+			if !haveModrm {
+				if pos >= len(src) {
+					return instPrefix(src[0], mode) // too long
+				}
+				mem = src[pos]>>6 != 3
+			}
+			if mem {
+				pc = int(decoder[pc+1])
+			} else {
+				pc = int(decoder[pc])
+			}
+
+		case xCondDataSize:
+			switch dataMode {
+			case 16:
+				if dataSizeIndex >= 0 {
+					inst.Prefix[dataSizeIndex] |= PrefixImplicit
+				}
+				pc = int(decoder[pc])
+			case 32:
+				if dataSizeIndex >= 0 {
+					inst.Prefix[dataSizeIndex] |= PrefixImplicit
+				}
+				pc = int(decoder[pc+1])
+			case 64:
+				rexUsed |= PrefixREXW
+				pc = int(decoder[pc+2])
+			}
+
+		case xCondAddrSize:
+			switch addrMode {
+			case 16:
+				if addrSizeIndex >= 0 {
+					inst.Prefix[addrSizeIndex] |= PrefixImplicit
+				}
+				pc = int(decoder[pc])
+			case 32:
+				if addrSizeIndex >= 0 {
+					inst.Prefix[addrSizeIndex] |= PrefixImplicit
+				}
+				pc = int(decoder[pc+1])
+			case 64:
+				pc = int(decoder[pc+2])
+			}
+
+		case xCondPrefix:
+			// Conditional branch based on presence or absence of prefixes.
+			// The conflict cases here are completely undocumented and
+			// differ significantly between GNU libopcodes and Intel xed.
+			// I have not written assembly code to divine what various CPUs
+			// do, but it wouldn't surprise me if they are not consistent either.
+			//
+			// The basic idea is to switch on the presence of a prefix, so that
+			// for example:
+			//
+			//	xCondPrefix, 4
+			//	0xF3, 123,
+			//	0xF2, 234,
+			//	0x66, 345,
+			//	0, 456
+			//
+			// branch to 123 if the F3 prefix is present, 234 if the F2 prefix
+			// is present, 66 if the 345 prefix is present, and 456 otherwise.
+			// The prefixes are given in descending order so that the 0 will be last.
+			//
+			// It is unclear what should happen if multiple conditions are
+			// satisfied: what if F2 and F3 are both present, or if 66 and F2
+			// are present, or if all three are present? The one chosen becomes
+			// part of the opcode and the others do not. Perhaps the answer
+			// depends on the specific opcodes in question.
+			//
+			// The only clear example is that CRC32 is F2 0F 38 F1 /r, and
+			// it comes in 16-bit and 32-bit forms based on the 66 prefix,
+			// so 66 F2 0F 38 F1 /r should be treated as F2 taking priority,
+			// with the 66 being only an operand size override, and probably
+			// F2 66 0F 38 F1 /r should be treated the same.
+			// Perhaps that rule is specific to the case of CRC32, since no
+			// 66 0F 38 F1 instruction is defined (today) (that we know of).
+			// However, both libopcodes and xed seem to generalize this
+			// example and choose F2/F3 in preference to 66, and we
+			// do the same.
+			//
+			// Next, what if both F2 and F3 are present? Which wins?
+			// The Intel xed rule, and ours, is that the one that occurs last wins.
+			// The GNU libopcodes rule, which we implement only in gnuCompat mode,
+			// is that F3 beats F2 unless F3 has no special meaning, in which
+			// case F3 can be a modified on an F2 special meaning.
+			//
+			// Concretely,
+			//	66 0F D6 /r is MOVQ
+			//	F2 0F D6 /r is MOVDQ2Q
+			//	F3 0F D6 /r is MOVQ2DQ.
+			//
+			//	F2 66 0F D6 /r is 66 + MOVDQ2Q always.
+			//	66 F2 0F D6 /r is 66 + MOVDQ2Q always.
+			//	F3 66 0F D6 /r is 66 + MOVQ2DQ always.
+			//	66 F3 0F D6 /r is 66 + MOVQ2DQ always.
+			//	F2 F3 0F D6 /r is F2 + MOVQ2DQ always.
+			//	F3 F2 0F D6 /r is F3 + MOVQ2DQ in Intel xed, but F2 + MOVQ2DQ in GNU libopcodes.
+			//	Adding 66 anywhere in the prefix section of the
+			//	last two cases does not change the outcome.
+			//
+			// Finally, what if there is a variant in which 66 is a mandatory
+			// prefix rather than an operand size override, but we know of
+			// no corresponding F2/F3 form, and we see both F2/F3 and 66.
+			// Does F2/F3 still take priority, so that the result is an unknown
+			// instruction, or does the 66 take priority, so that the extended
+			// 66 instruction should be interpreted as having a REP/REPN prefix?
+			// Intel xed does the former and GNU libopcodes does the latter.
+			// We side with Intel xed, unless we are trying to match libopcodes
+			// more closely during the comparison-based test suite.
+			//
+			// In 64-bit mode REX.W is another valid prefix to test for, but
+			// there is less ambiguity about that. When present, REX.W is
+			// always the first entry in the table.
+			n := int(decoder[pc])
+			pc++
+			sawF3 := false
+			for j := 0; j < n; j++ {
+				prefix := Prefix(decoder[pc+2*j])
+				if prefix.IsREX() {
+					rexUsed |= prefix
+					if rex&prefix == prefix {
+						pc = int(decoder[pc+2*j+1])
+						continue Decode
+					}
+					continue
+				}
+				ok := false
+				if prefix == 0 {
+					ok = true
+				} else if prefix.IsREX() {
+					rexUsed |= prefix
+					if rex&prefix == prefix {
+						ok = true
+					}
+				} else {
+					if prefix == 0xF3 {
+						sawF3 = true
+					}
+					switch prefix {
+					case PrefixLOCK:
+						if lockIndex >= 0 {
+							inst.Prefix[lockIndex] |= PrefixImplicit
+							ok = true
+						}
+					case PrefixREP, PrefixREPN:
+						if repIndex >= 0 && inst.Prefix[repIndex]&0xFF == prefix {
+							inst.Prefix[repIndex] |= PrefixImplicit
+							ok = true
+						}
+						if gnuCompat && !ok && prefix == 0xF3 && repIndex >= 0 && (j+1 >= n || decoder[pc+2*(j+1)] != 0xF2) {
+							// Check to see if earlier prefix F3 is present.
+							for i := repIndex - 1; i >= 0; i-- {
+								if inst.Prefix[i]&0xFF == prefix {
+									inst.Prefix[i] |= PrefixImplicit
+									ok = true
+								}
+							}
+						}
+						if gnuCompat && !ok && prefix == 0xF2 && repIndex >= 0 && !sawF3 && inst.Prefix[repIndex]&0xFF == 0xF3 {
+							// Check to see if earlier prefix F2 is present.
+							for i := repIndex - 1; i >= 0; i-- {
+								if inst.Prefix[i]&0xFF == prefix {
+									inst.Prefix[i] |= PrefixImplicit
+									ok = true
+								}
+							}
+						}
+					case PrefixCS, PrefixDS, PrefixES, PrefixFS, PrefixGS, PrefixSS:
+						if segIndex >= 0 && inst.Prefix[segIndex]&0xFF == prefix {
+							inst.Prefix[segIndex] |= PrefixImplicit
+							ok = true
+						}
+					case PrefixDataSize:
+						// Looking for 66 mandatory prefix.
+						// The F2/F3 mandatory prefixes take priority when both are present.
+						// If we got this far in the xCondPrefix table and an F2/F3 is present,
+						// it means the table didn't have any entry for that prefix. But if 66 has
+						// special meaning, perhaps F2/F3 have special meaning that we don't know.
+						// Intel xed works this way, treating the F2/F3 as inhibiting the 66.
+						// GNU libopcodes allows the 66 to match. We do what Intel xed does
+						// except in gnuCompat mode.
+						if repIndex >= 0 && !gnuCompat {
+							inst.Op = 0
+							break Decode
+						}
+						if dataSizeIndex >= 0 {
+							inst.Prefix[dataSizeIndex] |= PrefixImplicit
+							ok = true
+						}
+					case PrefixAddrSize:
+						if addrSizeIndex >= 0 {
+							inst.Prefix[addrSizeIndex] |= PrefixImplicit
+							ok = true
+						}
+					}
+				}
+				if ok {
+					pc = int(decoder[pc+2*j+1])
+					continue Decode
+				}
+			}
+			inst.Op = 0
+			break Decode
+
+		case xCondSlashR:
+			pc = int(decoder[pc+regop&7])
+
+		// Input.
+
+		case xReadSlashR:
+			// done above
+
+		case xReadIb:
+			if pos >= len(src) {
+				return truncated(src, mode)
+			}
+			imm8 = int8(src[pos])
+			pos++
+
+		case xReadIw:
+			if pos+2 > len(src) {
+				return truncated(src, mode)
+			}
+			imm = int64(binary.LittleEndian.Uint16(src[pos:]))
+			pos += 2
+
+		case xReadId:
+			if pos+4 > len(src) {
+				return truncated(src, mode)
+			}
+			imm = int64(binary.LittleEndian.Uint32(src[pos:]))
+			pos += 4
+
+		case xReadIo:
+			if pos+8 > len(src) {
+				return truncated(src, mode)
+			}
+			imm = int64(binary.LittleEndian.Uint64(src[pos:]))
+			pos += 8
+
+		case xReadCb:
+			if pos >= len(src) {
+				return truncated(src, mode)
+			}
+			immcpos = pos
+			immc = int64(src[pos])
+			pos++
+
+		case xReadCw:
+			if pos+2 > len(src) {
+				return truncated(src, mode)
+			}
+			immcpos = pos
+			immc = int64(binary.LittleEndian.Uint16(src[pos:]))
+			pos += 2
+
+		case xReadCm:
+			immcpos = pos
+			if addrMode == 16 {
+				if pos+2 > len(src) {
+					return truncated(src, mode)
+				}
+				immc = int64(binary.LittleEndian.Uint16(src[pos:]))
+				pos += 2
+			} else if addrMode == 32 {
+				if pos+4 > len(src) {
+					return truncated(src, mode)
+				}
+				immc = int64(binary.LittleEndian.Uint32(src[pos:]))
+				pos += 4
+			} else {
+				if pos+8 > len(src) {
+					return truncated(src, mode)
+				}
+				immc = int64(binary.LittleEndian.Uint64(src[pos:]))
+				pos += 8
+			}
+		case xReadCd:
+			immcpos = pos
+			if pos+4 > len(src) {
+				return truncated(src, mode)
+			}
+			immc = int64(binary.LittleEndian.Uint32(src[pos:]))
+			pos += 4
+
+		case xReadCp:
+			immcpos = pos
+			if pos+6 > len(src) {
+				return truncated(src, mode)
+			}
+			w := binary.LittleEndian.Uint32(src[pos:])
+			w2 := binary.LittleEndian.Uint16(src[pos+4:])
+			immc = int64(w2)<<32 | int64(w)
+			pos += 6
+
+		// Output.
+
+		case xSetOp:
+			inst.Op = Op(decoder[pc])
+			pc++
+
+		case xArg1,
+			xArg3,
+			xArgAL,
+			xArgAX,
+			xArgCL,
+			xArgCS,
+			xArgDS,
+			xArgDX,
+			xArgEAX,
+			xArgEDX,
+			xArgES,
+			xArgFS,
+			xArgGS,
+			xArgRAX,
+			xArgRDX,
+			xArgSS,
+			xArgST,
+			xArgXMM0:
+			inst.Args[narg] = fixedArg[x]
+			narg++
+
+		case xArgImm8:
+			inst.Args[narg] = Imm(imm8)
+			narg++
+
+		case xArgImm8u:
+			inst.Args[narg] = Imm(uint8(imm8))
+			narg++
+
+		case xArgImm16:
+			inst.Args[narg] = Imm(int16(imm))
+			narg++
+
+		case xArgImm16u:
+			inst.Args[narg] = Imm(uint16(imm))
+			narg++
+
+		case xArgImm32:
+			inst.Args[narg] = Imm(int32(imm))
+			narg++
+
+		case xArgImm64:
+			inst.Args[narg] = Imm(imm)
+			narg++
+
+		case xArgM,
+			xArgM128,
+			xArgM1428byte,
+			xArgM16,
+			xArgM16and16,
+			xArgM16and32,
+			xArgM16and64,
+			xArgM16colon16,
+			xArgM16colon32,
+			xArgM16colon64,
+			xArgM16int,
+			xArgM2byte,
+			xArgM32,
+			xArgM32and32,
+			xArgM32fp,
+			xArgM32int,
+			xArgM512byte,
+			xArgM64,
+			xArgM64fp,
+			xArgM64int,
+			xArgM8,
+			xArgM80bcd,
+			xArgM80dec,
+			xArgM80fp,
+			xArgM94108byte,
+			xArgMem:
+			if !haveMem {
+				inst.Op = 0
+				break Decode
+			}
+			inst.Args[narg] = mem
+			inst.MemBytes = int(memBytes[decodeOp(x)])
+			if mem.Base == RIP {
+				inst.PCRel = displen
+				inst.PCRelOff = dispoff
+			}
+			narg++
+
+		case xArgPtr16colon16:
+			inst.Args[narg] = Imm(immc >> 16)
+			inst.Args[narg+1] = Imm(immc & (1<<16 - 1))
+			narg += 2
+
+		case xArgPtr16colon32:
+			inst.Args[narg] = Imm(immc >> 32)
+			inst.Args[narg+1] = Imm(immc & (1<<32 - 1))
+			narg += 2
+
+		case xArgMoffs8, xArgMoffs16, xArgMoffs32, xArgMoffs64:
+			// TODO(rsc): Can address be 64 bits?
+			mem = Mem{Disp: immc}
+			if segIndex >= 0 {
+				mem.Segment = prefixToSegment(inst.Prefix[segIndex])
+				inst.Prefix[segIndex] |= PrefixImplicit
+			}
+			inst.Args[narg] = mem
+			inst.MemBytes = int(memBytes[decodeOp(x)])
+			if mem.Base == RIP {
+				inst.PCRel = displen
+				inst.PCRelOff = dispoff
+			}
+			narg++
+
+		case xArgR8, xArgR16, xArgR32, xArgR64, xArgXmm, xArgXmm1, xArgDR0dashDR7:
+			base := baseReg[x]
+			index := Reg(regop)
+			if rex != 0 && base == AL && index >= 4 {
+				rexUsed |= PrefixREX
+				index -= 4
+				base = SPB
+			}
+			inst.Args[narg] = base + index
+			narg++
+
+		case xArgMm, xArgMm1, xArgTR0dashTR7:
+			inst.Args[narg] = baseReg[x] + Reg(regop&7)
+			narg++
+
+		case xArgCR0dashCR7:
+			// AMD documents an extension that the LOCK prefix
+			// can be used in place of a REX prefix in order to access
+			// CR8 from 32-bit mode. The LOCK prefix is allowed in
+			// all modes, provided the corresponding CPUID bit is set.
+			if lockIndex >= 0 {
+				inst.Prefix[lockIndex] |= PrefixImplicit
+				regop += 8
+			}
+			inst.Args[narg] = CR0 + Reg(regop)
+			narg++
+
+		case xArgSreg:
+			regop &= 7
+			if regop >= 6 {
+				inst.Op = 0
+				break Decode
+			}
+			inst.Args[narg] = ES + Reg(regop)
+			narg++
+
+		case xArgRmf16, xArgRmf32, xArgRmf64:
+			base := baseReg[x]
+			index := Reg(modrm & 07)
+			if rex&PrefixREXB != 0 {
+				rexUsed |= PrefixREXB
+				index += 8
+			}
+			inst.Args[narg] = base + index
+			narg++
+
+		case xArgR8op, xArgR16op, xArgR32op, xArgR64op, xArgSTi:
+			n := inst.Opcode >> uint(opshift+8) & 07
+			base := baseReg[x]
+			index := Reg(n)
+			if rex&PrefixREXB != 0 && decodeOp(x) != xArgSTi {
+				rexUsed |= PrefixREXB
+				index += 8
+			}
+			if rex != 0 && base == AL && index >= 4 {
+				rexUsed |= PrefixREX
+				index -= 4
+				base = SPB
+			}
+			inst.Args[narg] = base + index
+			narg++
+
+		case xArgRM8, xArgRM16, xArgRM32, xArgRM64, xArgR32M16, xArgR32M8, xArgR64M16,
+			xArgMmM32, xArgMmM64, xArgMm2M64,
+			xArgXmm2M16, xArgXmm2M32, xArgXmm2M64, xArgXmmM64, xArgXmmM128, xArgXmmM32, xArgXmm2M128:
+			if haveMem {
+				inst.Args[narg] = mem
+				inst.MemBytes = int(memBytes[decodeOp(x)])
+				if mem.Base == RIP {
+					inst.PCRel = displen
+					inst.PCRelOff = dispoff
+				}
+			} else {
+				base := baseReg[x]
+				index := Reg(rm)
+				switch decodeOp(x) {
+				case xArgMmM32, xArgMmM64, xArgMm2M64:
+					// There are only 8 MMX registers, so these ignore the REX.X bit.
+					index &= 7
+				case xArgRM8:
+					if rex != 0 && index >= 4 {
+						rexUsed |= PrefixREX
+						index -= 4
+						base = SPB
+					}
+				}
+				inst.Args[narg] = base + index
+			}
+			narg++
+
+		case xArgMm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
+			if haveMem {
+				inst.Op = 0
+				break Decode
+			}
+			inst.Args[narg] = baseReg[x] + Reg(rm&7)
+			narg++
+
+		case xArgXmm2: // register only; TODO(rsc): Handle with tag modrm_regonly tag
+			if haveMem {
+				inst.Op = 0
+				break Decode
+			}
+			inst.Args[narg] = baseReg[x] + Reg(rm)
+			narg++
+
+		case xArgRel8:
+			inst.PCRelOff = immcpos
+			inst.PCRel = 1
+			inst.Args[narg] = Rel(int8(immc))
+			narg++
+
+		case xArgRel16:
+			inst.PCRelOff = immcpos
+			inst.PCRel = 2
+			inst.Args[narg] = Rel(int16(immc))
+			narg++
+
+		case xArgRel32:
+			inst.PCRelOff = immcpos
+			inst.PCRel = 4
+			inst.Args[narg] = Rel(int32(immc))
+			narg++
+		}
+	}
+
+	if inst.Op == 0 {
+		// Invalid instruction.
+		if nprefix > 0 {
+			return instPrefix(src[0], mode) // invalid instruction
+		}
+		return Inst{Len: pos}, ErrUnrecognized
+	}
+
+	// Matched! Hooray!
+
+	// 90 decodes as XCHG EAX, EAX but is NOP.
+	// 66 90 decodes as XCHG AX, AX and is NOP too.
+	// 48 90 decodes as XCHG RAX, RAX and is NOP too.
+	// 43 90 decodes as XCHG R8D, EAX and is *not* NOP.
+	// F3 90 decodes as REP XCHG EAX, EAX but is PAUSE.
+	// It's all too special to handle in the decoding tables, at least for now.
+	if inst.Op == XCHG && inst.Opcode>>24 == 0x90 {
+		if inst.Args[0] == RAX || inst.Args[0] == EAX || inst.Args[0] == AX {
+			inst.Op = NOP
+			if dataSizeIndex >= 0 {
+				inst.Prefix[dataSizeIndex] &^= PrefixImplicit
+			}
+			inst.Args[0] = nil
+			inst.Args[1] = nil
+		}
+		if repIndex >= 0 && inst.Prefix[repIndex] == 0xF3 {
+			inst.Prefix[repIndex] |= PrefixImplicit
+			inst.Op = PAUSE
+			inst.Args[0] = nil
+			inst.Args[1] = nil
+		} else if gnuCompat {
+			for i := nprefix - 1; i >= 0; i-- {
+				if inst.Prefix[i]&0xFF == 0xF3 {
+					inst.Prefix[i] |= PrefixImplicit
+					inst.Op = PAUSE
+					inst.Args[0] = nil
+					inst.Args[1] = nil
+					break
+				}
+			}
+		}
+	}
+
+	// defaultSeg returns the default segment for an implicit
+	// memory reference: the final override if present, or else DS.
+	defaultSeg := func() Reg {
+		if segIndex >= 0 {
+			inst.Prefix[segIndex] |= PrefixImplicit
+			return prefixToSegment(inst.Prefix[segIndex])
+		}
+		return DS
+	}
+
+	// Add implicit arguments not present in the tables.
+	// Normally we shy away from making implicit arguments explicit,
+	// following the Intel manuals, but adding the arguments seems
+	// the best way to express the effect of the segment override prefixes.
+	// TODO(rsc): Perhaps add these to the tables and
+	// create bytecode instructions for them.
+	usedAddrSize := false
+	switch inst.Op {
+	case INSB, INSW, INSD:
+		inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
+		inst.Args[1] = DX
+		usedAddrSize = true
+
+	case OUTSB, OUTSW, OUTSD:
+		inst.Args[0] = DX
+		inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
+		usedAddrSize = true
+
+	case MOVSB, MOVSW, MOVSD, MOVSQ:
+		inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
+		inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
+		usedAddrSize = true
+
+	case CMPSB, CMPSW, CMPSD, CMPSQ:
+		inst.Args[0] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
+		inst.Args[1] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
+		usedAddrSize = true
+
+	case LODSB, LODSW, LODSD, LODSQ:
+		switch inst.Op {
+		case LODSB:
+			inst.Args[0] = AL
+		case LODSW:
+			inst.Args[0] = AX
+		case LODSD:
+			inst.Args[0] = EAX
+		case LODSQ:
+			inst.Args[0] = RAX
+		}
+		inst.Args[1] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + SI - AX}
+		usedAddrSize = true
+
+	case STOSB, STOSW, STOSD, STOSQ:
+		inst.Args[0] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
+		switch inst.Op {
+		case STOSB:
+			inst.Args[1] = AL
+		case STOSW:
+			inst.Args[1] = AX
+		case STOSD:
+			inst.Args[1] = EAX
+		case STOSQ:
+			inst.Args[1] = RAX
+		}
+		usedAddrSize = true
+
+	case SCASB, SCASW, SCASD, SCASQ:
+		inst.Args[1] = Mem{Segment: ES, Base: baseRegForBits(addrMode) + DI - AX}
+		switch inst.Op {
+		case SCASB:
+			inst.Args[0] = AL
+		case SCASW:
+			inst.Args[0] = AX
+		case SCASD:
+			inst.Args[0] = EAX
+		case SCASQ:
+			inst.Args[0] = RAX
+		}
+		usedAddrSize = true
+
+	case XLATB:
+		inst.Args[0] = Mem{Segment: defaultSeg(), Base: baseRegForBits(addrMode) + BX - AX}
+		usedAddrSize = true
+	}
+
+	// If we used the address size annotation to construct the
+	// argument list, mark that prefix as implicit: it doesn't need
+	// to be shown when printing the instruction.
+	if haveMem || usedAddrSize {
+		if addrSizeIndex >= 0 {
+			inst.Prefix[addrSizeIndex] |= PrefixImplicit
+		}
+	}
+
+	// Similarly, if there's some memory operand, the segment
+	// will be shown there and doesn't need to be shown as an
+	// explicit prefix.
+	if haveMem {
+		if segIndex >= 0 {
+			inst.Prefix[segIndex] |= PrefixImplicit
+		}
+	}
+
+	// Branch predict prefixes are overloaded segment prefixes,
+	// since segment prefixes don't make sense on conditional jumps.
+	// Rewrite final instance to prediction prefix.
+	// The set of instructions to which the prefixes apply (other then the
+	// Jcc conditional jumps) is not 100% clear from the manuals, but
+	// the disassemblers seem to agree about the LOOP and JCXZ instructions,
+	// so we'll follow along.
+	// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+	if isCondJmp[inst.Op] || isLoop[inst.Op] || inst.Op == JCXZ || inst.Op == JECXZ || inst.Op == JRCXZ {
+	PredictLoop:
+		for i := nprefix - 1; i >= 0; i-- {
+			p := inst.Prefix[i]
+			switch p & 0xFF {
+			case PrefixCS:
+				inst.Prefix[i] = PrefixPN
+				break PredictLoop
+			case PrefixDS:
+				inst.Prefix[i] = PrefixPT
+				break PredictLoop
+			}
+		}
+	}
+
+	// The BND prefix is part of the Intel Memory Protection Extensions (MPX).
+	// A REPN applied to certain control transfers is a BND prefix to bound
+	// the range of possible destinations. There's surprisingly little documentation
+	// about this, so we just do what libopcodes and xed agree on.
+	// In particular, it's unclear why a REPN applied to LOOP or JCXZ instructions
+	// does not turn into a BND.
+	// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+	if isCondJmp[inst.Op] || inst.Op == JMP || inst.Op == CALL || inst.Op == RET {
+		for i := nprefix - 1; i >= 0; i-- {
+			p := inst.Prefix[i]
+			if p&^PrefixIgnored == PrefixREPN {
+				inst.Prefix[i] = PrefixBND
+				break
+			}
+		}
+	}
+
+	// The LOCK prefix only applies to certain instructions, and then only
+	// to instances of the instruction with a memory destination.
+	// Other uses of LOCK are invalid and cause a processor exception,
+	// in contrast to the "just ignore it" spirit applied to all other prefixes.
+	// Mark invalid lock prefixes.
+	hasLock := false
+	if lockIndex >= 0 && inst.Prefix[lockIndex]&PrefixImplicit == 0 {
+		switch inst.Op {
+		// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+		case ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCHG8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, XCHG:
+			if isMem(inst.Args[0]) {
+				hasLock = true
+				break
+			}
+			fallthrough
+		default:
+			inst.Prefix[lockIndex] |= PrefixInvalid
+		}
+	}
+
+	// In certain cases, all of which require a memory destination,
+	// the REPN and REP prefixes are interpreted as XACQUIRE and XRELEASE
+	// from the Intel Transactional Synchroniation Extensions (TSX).
+	//
+	// The specific rules are:
+	// (1) Any instruction with a valid LOCK prefix can have XACQUIRE or XRELEASE.
+	// (2) Any XCHG, which always has an implicit LOCK, can have XACQUIRE or XRELEASE.
+	// (3) Any 0x88-, 0x89-, 0xC6-, or 0xC7-opcode MOV can have XRELEASE.
+	if isMem(inst.Args[0]) {
+		if inst.Op == XCHG {
+			hasLock = true
+		}
+
+		for i := len(inst.Prefix) - 1; i >= 0; i-- {
+			p := inst.Prefix[i] &^ PrefixIgnored
+			switch p {
+			case PrefixREPN:
+				if hasLock {
+					inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXACQUIRE
+				}
+
+			case PrefixREP:
+				if hasLock {
+					inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXRELEASE
+				}
+
+				if inst.Op == MOV {
+					op := (inst.Opcode >> 24) &^ 1
+					if op == 0x88 || op == 0xC6 {
+						inst.Prefix[i] = inst.Prefix[i]&PrefixIgnored | PrefixXRELEASE
+					}
+				}
+			}
+		}
+	}
+
+	// If REP is used on a non-REP-able instruction, mark the prefix as ignored.
+	if repIndex >= 0 {
+		switch inst.Prefix[repIndex] {
+		case PrefixREP, PrefixREPN:
+			switch inst.Op {
+			// According to the manuals, the REP/REPE prefix applies to all of these,
+			// while the REPN applies only to some of them. However, both libopcodes
+			// and xed show both prefixes explicitly for all instructions, so we do the same.
+			// TODO(rsc): Perhaps this instruction class should be derived from the CSV.
+			case INSB, INSW, INSD,
+				MOVSB, MOVSW, MOVSD, MOVSQ,
+				OUTSB, OUTSW, OUTSD,
+				LODSB, LODSW, LODSD, LODSQ,
+				CMPSB, CMPSW, CMPSD, CMPSQ,
+				SCASB, SCASW, SCASD, SCASQ,
+				STOSB, STOSW, STOSD, STOSQ:
+				// ok
+			default:
+				inst.Prefix[repIndex] |= PrefixIgnored
+			}
+		}
+	}
+
+	// If REX was present, mark implicit if all the 1 bits were consumed.
+	if rexIndex >= 0 {
+		if rexUsed != 0 {
+			rexUsed |= PrefixREX
+		}
+		if rex&^rexUsed == 0 {
+			inst.Prefix[rexIndex] |= PrefixImplicit
+		}
+	}
+
+	inst.DataSize = dataMode
+	inst.AddrSize = addrMode
+	inst.Mode = mode
+	inst.Len = pos
+	return inst, nil
+}
+
+var errInternal = errors.New("internal error")
+
+// addr16 records the eight 16-bit addressing modes.
+var addr16 = [8]Mem{
+	{Base: BX, Scale: 1, Index: SI},
+	{Base: BX, Scale: 1, Index: DI},
+	{Base: BP, Scale: 1, Index: SI},
+	{Base: BP, Scale: 1, Index: DI},
+	{Base: SI},
+	{Base: DI},
+	{Base: BP},
+	{Base: BX},
+}
+
+// baseReg returns the base register for a given register size in bits.
+func baseRegForBits(bits int) Reg {
+	switch bits {
+	case 8:
+		return AL
+	case 16:
+		return AX
+	case 32:
+		return EAX
+	case 64:
+		return RAX
+	}
+	return 0
+}
+
+// baseReg records the base register for argument types that specify
+// a range of registers indexed by op, regop, or rm.
+var baseReg = [...]Reg{
+	xArgDR0dashDR7: DR0,
+	xArgMm1:        M0,
+	xArgMm2:        M0,
+	xArgMm2M64:     M0,
+	xArgMm:         M0,
+	xArgMmM32:      M0,
+	xArgMmM64:      M0,
+	xArgR16:        AX,
+	xArgR16op:      AX,
+	xArgR32:        EAX,
+	xArgR32M16:     EAX,
+	xArgR32M8:      EAX,
+	xArgR32op:      EAX,
+	xArgR64:        RAX,
+	xArgR64M16:     RAX,
+	xArgR64op:      RAX,
+	xArgR8:         AL,
+	xArgR8op:       AL,
+	xArgRM16:       AX,
+	xArgRM32:       EAX,
+	xArgRM64:       RAX,
+	xArgRM8:        AL,
+	xArgRmf16:      AX,
+	xArgRmf32:      EAX,
+	xArgRmf64:      RAX,
+	xArgSTi:        F0,
+	xArgTR0dashTR7: TR0,
+	xArgXmm1:       X0,
+	xArgXmm2:       X0,
+	xArgXmm2M128:   X0,
+	xArgXmm2M16:    X0,
+	xArgXmm2M32:    X0,
+	xArgXmm2M64:    X0,
+	xArgXmm:        X0,
+	xArgXmmM128:    X0,
+	xArgXmmM32:     X0,
+	xArgXmmM64:     X0,
+}
+
+// prefixToSegment returns the segment register
+// corresponding to a particular segment prefix.
+func prefixToSegment(p Prefix) Reg {
+	switch p &^ PrefixImplicit {
+	case PrefixCS:
+		return CS
+	case PrefixDS:
+		return DS
+	case PrefixES:
+		return ES
+	case PrefixFS:
+		return FS
+	case PrefixGS:
+		return GS
+	case PrefixSS:
+		return SS
+	}
+	return 0
+}
+
+// fixedArg records the fixed arguments corresponding to the given bytecodes.
+var fixedArg = [...]Arg{
+	xArg1:    Imm(1),
+	xArg3:    Imm(3),
+	xArgAL:   AL,
+	xArgAX:   AX,
+	xArgDX:   DX,
+	xArgEAX:  EAX,
+	xArgEDX:  EDX,
+	xArgRAX:  RAX,
+	xArgRDX:  RDX,
+	xArgCL:   CL,
+	xArgCS:   CS,
+	xArgDS:   DS,
+	xArgES:   ES,
+	xArgFS:   FS,
+	xArgGS:   GS,
+	xArgSS:   SS,
+	xArgST:   F0,
+	xArgXMM0: X0,
+}
+
+// memBytes records the size of the memory pointed at
+// by a memory argument of the given form.
+var memBytes = [...]int8{
+	xArgM128:       128 / 8,
+	xArgM16:        16 / 8,
+	xArgM16and16:   (16 + 16) / 8,
+	xArgM16colon16: (16 + 16) / 8,
+	xArgM16colon32: (16 + 32) / 8,
+	xArgM16int:     16 / 8,
+	xArgM2byte:     2,
+	xArgM32:        32 / 8,
+	xArgM32and32:   (32 + 32) / 8,
+	xArgM32fp:      32 / 8,
+	xArgM32int:     32 / 8,
+	xArgM64:        64 / 8,
+	xArgM64fp:      64 / 8,
+	xArgM64int:     64 / 8,
+	xArgMm2M64:     64 / 8,
+	xArgMmM32:      32 / 8,
+	xArgMmM64:      64 / 8,
+	xArgMoffs16:    16 / 8,
+	xArgMoffs32:    32 / 8,
+	xArgMoffs64:    64 / 8,
+	xArgMoffs8:     8 / 8,
+	xArgR32M16:     16 / 8,
+	xArgR32M8:      8 / 8,
+	xArgR64M16:     16 / 8,
+	xArgRM16:       16 / 8,
+	xArgRM32:       32 / 8,
+	xArgRM64:       64 / 8,
+	xArgRM8:        8 / 8,
+	xArgXmm2M128:   128 / 8,
+	xArgXmm2M16:    16 / 8,
+	xArgXmm2M32:    32 / 8,
+	xArgXmm2M64:    64 / 8,
+	xArgXmm:        128 / 8,
+	xArgXmmM128:    128 / 8,
+	xArgXmmM32:     32 / 8,
+	xArgXmmM64:     64 / 8,
+}
+
+// isCondJmp records the conditional jumps.
+var isCondJmp = [maxOp + 1]bool{
+	JA:  true,
+	JAE: true,
+	JB:  true,
+	JBE: true,
+	JE:  true,
+	JG:  true,
+	JGE: true,
+	JL:  true,
+	JLE: true,
+	JNE: true,
+	JNO: true,
+	JNP: true,
+	JNS: true,
+	JO:  true,
+	JP:  true,
+	JS:  true,
+}
+
+// isLoop records the loop operators.
+var isLoop = [maxOp + 1]bool{
+	LOOP:   true,
+	LOOPE:  true,
+	LOOPNE: true,
+	JECXZ:  true,
+	JRCXZ:  true,
+}
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode_test.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/decode_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/ext_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/ext_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/ext_test.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/ext_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/gnu.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/gnu.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/gnu.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/inst_test.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/inst_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/intel.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/intel.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/intel.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdump_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdump_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdump_test.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdump_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/objdumpext_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9ext_test.go
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go
new file mode 100644
index 0000000..44427d1
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go
@@ -0,0 +1,350 @@
+// 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 x86asm
+
+import (
+	"fmt"
+	"strings"
+)
+
+// GoSyntax returns the Go assembler syntax for the instruction.
+// The syntax was originally defined by Plan 9.
+// The pc is the program counter of the instruction, used for expanding
+// PC-relative addresses into absolute ones.
+// The symname function queries the symbol table for the program
+// being disassembled. Given a target address it returns the name and base
+// address of the symbol containing the target, if any; otherwise it returns "", 0.
+func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string {
+	if symname == nil {
+		symname = func(uint64) (string, uint64) { return "", 0 }
+	}
+	var args []string
+	for i := len(inst.Args) - 1; i >= 0; i-- {
+		a := inst.Args[i]
+		if a == nil {
+			continue
+		}
+		args = append(args, plan9Arg(&inst, pc, symname, a))
+	}
+
+	var last Prefix
+	for _, p := range inst.Prefix {
+		if p == 0 || p.IsREX() {
+			break
+		}
+		last = p
+	}
+
+	prefix := ""
+	switch last & 0xFF {
+	case 0, 0x66, 0x67:
+		// ignore
+	case PrefixREPN:
+		prefix += "REPNE "
+	default:
+		prefix += last.String() + " "
+	}
+
+	op := inst.Op.String()
+	if plan9Suffix[inst.Op] {
+		s := inst.DataSize
+		if inst.MemBytes != 0 {
+			s = inst.MemBytes * 8
+		}
+		switch s {
+		case 8:
+			op += "B"
+		case 16:
+			op += "W"
+		case 32:
+			op += "L"
+		case 64:
+			op += "Q"
+		}
+	}
+
+	if args != nil {
+		op += " " + strings.Join(args, ", ")
+	}
+
+	return prefix + op
+}
+
+func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
+	switch a := arg.(type) {
+	case Reg:
+		return plan9Reg[a]
+	case Rel:
+		if pc == 0 {
+			break
+		}
+		// If the absolute address is the start of a symbol, use the name.
+		// Otherwise use the raw address, so that things like relative
+		// jumps show up as JMP 0x123 instead of JMP f+10(SB).
+		// It is usually easier to search for 0x123 than to do the mental
+		// arithmetic to find f+10.
+		addr := pc + uint64(inst.Len) + uint64(a)
+		if s, base := symname(addr); s != "" && addr == base {
+			return fmt.Sprintf("%s(SB)", s)
+		}
+		return fmt.Sprintf("%#x", addr)
+
+	case Imm:
+		if s, base := symname(uint64(a)); s != "" {
+			suffix := ""
+			if uint64(a) != base {
+				suffix = fmt.Sprintf("%+d", uint64(a)-base)
+			}
+			return fmt.Sprintf("$%s%s(SB)", s, suffix)
+		}
+		if inst.Mode == 32 {
+			return fmt.Sprintf("$%#x", uint32(a))
+		}
+		if Imm(int32(a)) == a {
+			return fmt.Sprintf("$%#x", int64(a))
+		}
+		return fmt.Sprintf("$%#x", uint64(a))
+	case Mem:
+		if a.Segment == 0 && a.Disp != 0 && a.Base == 0 && (a.Index == 0 || a.Scale == 0) {
+			if s, base := symname(uint64(a.Disp)); s != "" {
+				suffix := ""
+				if uint64(a.Disp) != base {
+					suffix = fmt.Sprintf("%+d", uint64(a.Disp)-base)
+				}
+				return fmt.Sprintf("%s%s(SB)", s, suffix)
+			}
+		}
+		s := ""
+		if a.Segment != 0 {
+			s += fmt.Sprintf("%s:", plan9Reg[a.Segment])
+		}
+		if a.Disp != 0 {
+			s += fmt.Sprintf("%#x", a.Disp)
+		} else {
+			s += "0"
+		}
+		if a.Base != 0 {
+			s += fmt.Sprintf("(%s)", plan9Reg[a.Base])
+		}
+		if a.Index != 0 && a.Scale != 0 {
+			s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale)
+		}
+		return s
+	}
+	return arg.String()
+}
+
+var plan9Suffix = [maxOp + 1]bool{
+	ADC:       true,
+	ADD:       true,
+	AND:       true,
+	BSF:       true,
+	BSR:       true,
+	BT:        true,
+	BTC:       true,
+	BTR:       true,
+	BTS:       true,
+	CMP:       true,
+	CMPXCHG:   true,
+	CVTSI2SD:  true,
+	CVTSI2SS:  true,
+	CVTSD2SI:  true,
+	CVTSS2SI:  true,
+	CVTTSD2SI: true,
+	CVTTSS2SI: true,
+	DEC:       true,
+	DIV:       true,
+	FLDENV:    true,
+	FRSTOR:    true,
+	IDIV:      true,
+	IMUL:      true,
+	IN:        true,
+	INC:       true,
+	LEA:       true,
+	MOV:       true,
+	MOVNTI:    true,
+	MUL:       true,
+	NEG:       true,
+	NOP:       true,
+	NOT:       true,
+	OR:        true,
+	OUT:       true,
+	POP:       true,
+	POPA:      true,
+	PUSH:      true,
+	PUSHA:     true,
+	RCL:       true,
+	RCR:       true,
+	ROL:       true,
+	ROR:       true,
+	SAR:       true,
+	SBB:       true,
+	SHL:       true,
+	SHLD:      true,
+	SHR:       true,
+	SHRD:      true,
+	SUB:       true,
+	TEST:      true,
+	XADD:      true,
+	XCHG:      true,
+	XOR:       true,
+}
+
+var plan9Reg = [...]string{
+	AL:   "AL",
+	CL:   "CL",
+	BL:   "BL",
+	DL:   "DL",
+	AH:   "AH",
+	CH:   "CH",
+	BH:   "BH",
+	DH:   "DH",
+	SPB:  "SP",
+	BPB:  "BP",
+	SIB:  "SI",
+	DIB:  "DI",
+	R8B:  "R8",
+	R9B:  "R9",
+	R10B: "R10",
+	R11B: "R11",
+	R12B: "R12",
+	R13B: "R13",
+	R14B: "R14",
+	R15B: "R15",
+	AX:   "AX",
+	CX:   "CX",
+	BX:   "BX",
+	DX:   "DX",
+	SP:   "SP",
+	BP:   "BP",
+	SI:   "SI",
+	DI:   "DI",
+	R8W:  "R8",
+	R9W:  "R9",
+	R10W: "R10",
+	R11W: "R11",
+	R12W: "R12",
+	R13W: "R13",
+	R14W: "R14",
+	R15W: "R15",
+	EAX:  "AX",
+	ECX:  "CX",
+	EDX:  "DX",
+	EBX:  "BX",
+	ESP:  "SP",
+	EBP:  "BP",
+	ESI:  "SI",
+	EDI:  "DI",
+	R8L:  "R8",
+	R9L:  "R9",
+	R10L: "R10",
+	R11L: "R11",
+	R12L: "R12",
+	R13L: "R13",
+	R14L: "R14",
+	R15L: "R15",
+	RAX:  "AX",
+	RCX:  "CX",
+	RDX:  "DX",
+	RBX:  "BX",
+	RSP:  "SP",
+	RBP:  "BP",
+	RSI:  "SI",
+	RDI:  "DI",
+	R8:   "R8",
+	R9:   "R9",
+	R10:  "R10",
+	R11:  "R11",
+	R12:  "R12",
+	R13:  "R13",
+	R14:  "R14",
+	R15:  "R15",
+	IP:   "IP",
+	EIP:  "IP",
+	RIP:  "IP",
+	F0:   "F0",
+	F1:   "F1",
+	F2:   "F2",
+	F3:   "F3",
+	F4:   "F4",
+	F5:   "F5",
+	F6:   "F6",
+	F7:   "F7",
+	M0:   "M0",
+	M1:   "M1",
+	M2:   "M2",
+	M3:   "M3",
+	M4:   "M4",
+	M5:   "M5",
+	M6:   "M6",
+	M7:   "M7",
+	X0:   "X0",
+	X1:   "X1",
+	X2:   "X2",
+	X3:   "X3",
+	X4:   "X4",
+	X5:   "X5",
+	X6:   "X6",
+	X7:   "X7",
+	X8:   "X8",
+	X9:   "X9",
+	X10:  "X10",
+	X11:  "X11",
+	X12:  "X12",
+	X13:  "X13",
+	X14:  "X14",
+	X15:  "X15",
+	CS:   "CS",
+	SS:   "SS",
+	DS:   "DS",
+	ES:   "ES",
+	FS:   "FS",
+	GS:   "GS",
+	GDTR: "GDTR",
+	IDTR: "IDTR",
+	LDTR: "LDTR",
+	MSW:  "MSW",
+	TASK: "TASK",
+	CR0:  "CR0",
+	CR1:  "CR1",
+	CR2:  "CR2",
+	CR3:  "CR3",
+	CR4:  "CR4",
+	CR5:  "CR5",
+	CR6:  "CR6",
+	CR7:  "CR7",
+	CR8:  "CR8",
+	CR9:  "CR9",
+	CR10: "CR10",
+	CR11: "CR11",
+	CR12: "CR12",
+	CR13: "CR13",
+	CR14: "CR14",
+	CR15: "CR15",
+	DR0:  "DR0",
+	DR1:  "DR1",
+	DR2:  "DR2",
+	DR3:  "DR3",
+	DR4:  "DR4",
+	DR5:  "DR5",
+	DR6:  "DR6",
+	DR7:  "DR7",
+	DR8:  "DR8",
+	DR9:  "DR9",
+	DR10: "DR10",
+	DR11: "DR11",
+	DR12: "DR12",
+	DR13: "DR13",
+	DR14: "DR14",
+	DR15: "DR15",
+	TR0:  "TR0",
+	TR1:  "TR1",
+	TR2:  "TR2",
+	TR3:  "TR3",
+	TR4:  "TR4",
+	TR5:  "TR5",
+	TR6:  "TR6",
+	TR7:  "TR7",
+}
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/plan9x_test.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/tables.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/tables.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/tables.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/Makefile b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/Makefile
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/Makefile
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/Makefile
diff --git a/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt
new file mode 100644
index 0000000..745e81f
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt
@@ -0,0 +1,6733 @@
+000511223344|556677885f5f5f5f5f5f	32	intel	add byte ptr [0x44332211], al
+000511223344|556677885f5f5f5f5f5f	64	gnu	add %al,0x44332211(%rip)
+000511223344|556677885f5f5f5f5f5f	64	intel	add byte ptr [rip+0x44332211], al
+0100|11223344556677885f5f5f5f5f5f	32	intel	add dword ptr [eax], eax
+0100|11223344556677885f5f5f5f5f5f	32	plan9	ADDL AX, 0(AX)
+0100|11223344556677885f5f5f5f5f5f	64	gnu	add %eax,(%rax)
+0100|11223344556677885f5f5f5f5f5f	64	intel	add dword ptr [rax], eax
+0100|11223344556677885f5f5f5f5f5f	64	plan9	ADDL AX, 0(AX)
+0211|223344556677885f5f5f5f5f5f5f	32	intel	add dl, byte ptr [ecx]
+0211|223344556677885f5f5f5f5f5f5f	32	plan9	ADDB 0(CX), DL
+0211|223344556677885f5f5f5f5f5f5f	64	gnu	add (%rcx),%dl
+0211|223344556677885f5f5f5f5f5f5f	64	intel	add dl, byte ptr [rcx]
+0211|223344556677885f5f5f5f5f5f5f	64	plan9	ADDB 0(CX), DL
+0311|223344556677885f5f5f5f5f5f5f	32	intel	add edx, dword ptr [ecx]
+0311|223344556677885f5f5f5f5f5f5f	32	plan9	ADDL 0(CX), DX
+0311|223344556677885f5f5f5f5f5f5f	64	gnu	add (%rcx),%edx
+0311|223344556677885f5f5f5f5f5f5f	64	intel	add edx, dword ptr [rcx]
+0311|223344556677885f5f5f5f5f5f5f	64	plan9	ADDL 0(CX), DX
+0411|223344556677885f5f5f5f5f5f5f	32	intel	add al, 0x11
+0411|223344556677885f5f5f5f5f5f5f	32	plan9	ADDL $0x11, AL
+0411|223344556677885f5f5f5f5f5f5f	64	gnu	add $0x11,%al
+0411|223344556677885f5f5f5f5f5f5f	64	intel	add al, 0x11
+0411|223344556677885f5f5f5f5f5f5f	64	plan9	ADDL $0x11, AL
+0511223344|556677885f5f5f5f5f5f5f	32	intel	add eax, 0x44332211
+0511223344|556677885f5f5f5f5f5f5f	32	plan9	ADDL $0x44332211, AX
+0511223344|556677885f5f5f5f5f5f5f	64	gnu	add $0x44332211,%eax
+0511223344|556677885f5f5f5f5f5f5f	64	intel	add eax, 0x44332211
+0511223344|556677885f5f5f5f5f5f5f	64	plan9	ADDL $0x44332211, AX
+06|11223344556677885f5f5f5f5f5f5f	32	intel	push es
+06|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL ES
+06|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+06|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+06|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+07|11223344556677885f5f5f5f5f5f5f	32	intel	pop es
+07|11223344556677885f5f5f5f5f5f5f	32	plan9	POPL ES
+07|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+07|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+07|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0811|223344556677885f5f5f5f5f5f5f	32	intel	or byte ptr [ecx], dl
+0811|223344556677885f5f5f5f5f5f5f	32	plan9	ORB DL, 0(CX)
+0811|223344556677885f5f5f5f5f5f5f	64	gnu	or %dl,(%rcx)
+0811|223344556677885f5f5f5f5f5f5f	64	intel	or byte ptr [rcx], dl
+0811|223344556677885f5f5f5f5f5f5f	64	plan9	ORB DL, 0(CX)
+0911|223344556677885f5f5f5f5f5f5f	32	intel	or dword ptr [ecx], edx
+0911|223344556677885f5f5f5f5f5f5f	32	plan9	ORL DX, 0(CX)
+0911|223344556677885f5f5f5f5f5f5f	64	gnu	or %edx,(%rcx)
+0911|223344556677885f5f5f5f5f5f5f	64	intel	or dword ptr [rcx], edx
+0911|223344556677885f5f5f5f5f5f5f	64	plan9	ORL DX, 0(CX)
+0a11|223344556677885f5f5f5f5f5f5f	32	intel	or dl, byte ptr [ecx]
+0a11|223344556677885f5f5f5f5f5f5f	32	plan9	ORB 0(CX), DL
+0a11|223344556677885f5f5f5f5f5f5f	64	gnu	or (%rcx),%dl
+0a11|223344556677885f5f5f5f5f5f5f	64	intel	or dl, byte ptr [rcx]
+0a11|223344556677885f5f5f5f5f5f5f	64	plan9	ORB 0(CX), DL
+0b11|223344556677885f5f5f5f5f5f5f	32	intel	or edx, dword ptr [ecx]
+0b11|223344556677885f5f5f5f5f5f5f	32	plan9	ORL 0(CX), DX
+0b11|223344556677885f5f5f5f5f5f5f	64	gnu	or (%rcx),%edx
+0b11|223344556677885f5f5f5f5f5f5f	64	intel	or edx, dword ptr [rcx]
+0b11|223344556677885f5f5f5f5f5f5f	64	plan9	ORL 0(CX), DX
+0c11|223344556677885f5f5f5f5f5f5f	32	intel	or al, 0x11
+0c11|223344556677885f5f5f5f5f5f5f	32	plan9	ORL $0x11, AL
+0c11|223344556677885f5f5f5f5f5f5f	64	gnu	or $0x11,%al
+0c11|223344556677885f5f5f5f5f5f5f	64	intel	or al, 0x11
+0c11|223344556677885f5f5f5f5f5f5f	64	plan9	ORL $0x11, AL
+0d11223344|556677885f5f5f5f5f5f5f	32	intel	or eax, 0x44332211
+0d11223344|556677885f5f5f5f5f5f5f	32	plan9	ORL $0x44332211, AX
+0d11223344|556677885f5f5f5f5f5f5f	64	gnu	or $0x44332211,%eax
+0d11223344|556677885f5f5f5f5f5f5f	64	intel	or eax, 0x44332211
+0d11223344|556677885f5f5f5f5f5f5f	64	plan9	ORL $0x44332211, AX
+0e|11223344556677885f5f5f5f5f5f5f	32	intel	push cs
+0e|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL CS
+0e|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0e|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0e|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f0000|11223344556677885f5f5f5f5f	32	intel	sldt word ptr [eax]
+0f0000|11223344556677885f5f5f5f5f	32	plan9	SLDT 0(AX)
+0f0000|11223344556677885f5f5f5f5f	64	gnu	sldt (%rax)
+0f0000|11223344556677885f5f5f5f5f	64	intel	sldt word ptr [rax]
+0f0000|11223344556677885f5f5f5f5f	64	plan9	SLDT 0(AX)
+0f0008|11223344556677885f5f5f5f5f	32	intel	str word ptr [eax]
+0f0008|11223344556677885f5f5f5f5f	32	plan9	STR 0(AX)
+0f0008|11223344556677885f5f5f5f5f	64	gnu	str (%rax)
+0f0008|11223344556677885f5f5f5f5f	64	intel	str word ptr [rax]
+0f0008|11223344556677885f5f5f5f5f	64	plan9	STR 0(AX)
+0f0011|223344556677885f5f5f5f5f5f	32	intel	lldt word ptr [ecx]
+0f0011|223344556677885f5f5f5f5f5f	32	plan9	LLDT 0(CX)
+0f0011|223344556677885f5f5f5f5f5f	64	gnu	lldt (%rcx)
+0f0011|223344556677885f5f5f5f5f5f	64	intel	lldt word ptr [rcx]
+0f0011|223344556677885f5f5f5f5f5f	64	plan9	LLDT 0(CX)
+0f0018|11223344556677885f5f5f5f5f	32	intel	ltr word ptr [eax]
+0f0018|11223344556677885f5f5f5f5f	32	plan9	LTR 0(AX)
+0f0018|11223344556677885f5f5f5f5f	64	gnu	ltr (%rax)
+0f0018|11223344556677885f5f5f5f5f	64	intel	ltr word ptr [rax]
+0f0018|11223344556677885f5f5f5f5f	64	plan9	LTR 0(AX)
+0f0020|11223344556677885f5f5f5f5f	32	intel	verr word ptr [eax]
+0f0020|11223344556677885f5f5f5f5f	32	plan9	VERR 0(AX)
+0f0020|11223344556677885f5f5f5f5f	64	gnu	verr (%rax)
+0f0020|11223344556677885f5f5f5f5f	64	intel	verr word ptr [rax]
+0f0020|11223344556677885f5f5f5f5f	64	plan9	VERR 0(AX)
+0f0028|11223344556677885f5f5f5f5f	32	intel	verw word ptr [eax]
+0f0028|11223344556677885f5f5f5f5f	32	plan9	VERW 0(AX)
+0f0028|11223344556677885f5f5f5f5f	64	gnu	verw (%rax)
+0f0028|11223344556677885f5f5f5f5f	64	intel	verw word ptr [rax]
+0f0028|11223344556677885f5f5f5f5f	64	plan9	VERW 0(AX)
+0f0030|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f0030|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f0100|11223344556677885f5f5f5f5f	32	intel	sgdt ptr [eax]
+0f0100|11223344556677885f5f5f5f5f	32	plan9	SGDT 0(AX)
+0f0100|11223344556677885f5f5f5f5f	64	gnu	sgdtl (%rax)
+0f0100|11223344556677885f5f5f5f5f	64	intel	sgdt ptr [rax]
+0f0100|11223344556677885f5f5f5f5f	64	plan9	SGDT 0(AX)
+0f0108|11223344556677885f5f5f5f5f	32	intel	sidt ptr [eax]
+0f0108|11223344556677885f5f5f5f5f	32	plan9	SIDT 0(AX)
+0f0108|11223344556677885f5f5f5f5f	64	gnu	sidtl (%rax)
+0f0108|11223344556677885f5f5f5f5f	64	intel	sidt ptr [rax]
+0f0108|11223344556677885f5f5f5f5f	64	plan9	SIDT 0(AX)
+0f0111|223344556677885f5f5f5f5f5f	32	intel	lgdt ptr [ecx]
+0f0111|223344556677885f5f5f5f5f5f	32	plan9	LGDT 0(CX)
+0f0111|223344556677885f5f5f5f5f5f	64	gnu	lgdtl (%rcx)
+0f0111|223344556677885f5f5f5f5f5f	64	intel	lgdt ptr [rcx]
+0f0111|223344556677885f5f5f5f5f5f	64	plan9	LGDT 0(CX)
+0f0118|11223344556677885f5f5f5f5f	32	intel	lidt ptr [eax]
+0f0118|11223344556677885f5f5f5f5f	32	plan9	LIDT 0(AX)
+0f0118|11223344556677885f5f5f5f5f	64	gnu	lidtl (%rax)
+0f0118|11223344556677885f5f5f5f5f	64	intel	lidt ptr [rax]
+0f0118|11223344556677885f5f5f5f5f	64	plan9	LIDT 0(AX)
+0f0120|11223344556677885f5f5f5f5f	32	intel	smsw word ptr [eax]
+0f0120|11223344556677885f5f5f5f5f	32	plan9	SMSW 0(AX)
+0f0120|11223344556677885f5f5f5f5f	64	gnu	smsw (%rax)
+0f0120|11223344556677885f5f5f5f5f	64	intel	smsw word ptr [rax]
+0f0120|11223344556677885f5f5f5f5f	64	plan9	SMSW 0(AX)
+0f0130|11223344556677885f5f5f5f5f	32	intel	lmsw word ptr [eax]
+0f0130|11223344556677885f5f5f5f5f	32	plan9	LMSW 0(AX)
+0f0130|11223344556677885f5f5f5f5f	64	gnu	lmsw (%rax)
+0f0130|11223344556677885f5f5f5f5f	64	intel	lmsw word ptr [rax]
+0f0130|11223344556677885f5f5f5f5f	64	plan9	LMSW 0(AX)
+0f0138|11223344556677885f5f5f5f5f	32	intel	invlpg byte ptr [eax]
+0f0138|11223344556677885f5f5f5f5f	32	plan9	INVLPG 0(AX)
+0f0138|11223344556677885f5f5f5f5f	64	gnu	invlpg (%rax)
+0f0138|11223344556677885f5f5f5f5f	64	intel	invlpg byte ptr [rax]
+0f0138|11223344556677885f5f5f5f5f	64	plan9	INVLPG 0(AX)
+0f01c8|11223344556677885f5f5f5f5f	32	intel	monitor
+0f01c8|11223344556677885f5f5f5f5f	32	plan9	MONITOR
+0f01c8|11223344556677885f5f5f5f5f	64	gnu	monitor %eax,%ecx,%edx
+0f01c8|11223344556677885f5f5f5f5f	64	intel	monitor
+0f01c8|11223344556677885f5f5f5f5f	64	plan9	MONITOR
+0f01c9|11223344556677885f5f5f5f5f	32	intel	mwait
+0f01c9|11223344556677885f5f5f5f5f	32	plan9	MWAIT
+0f01c9|11223344556677885f5f5f5f5f	64	gnu	mwait %rax,%rcx
+0f01c9|11223344556677885f5f5f5f5f	64	intel	mwait
+0f01c9|11223344556677885f5f5f5f5f	64	plan9	MWAIT
+0f01d0|11223344556677885f5f5f5f5f	32	intel	xgetbv
+0f01d0|11223344556677885f5f5f5f5f	32	plan9	XGETBV
+0f01d0|11223344556677885f5f5f5f5f	64	gnu	xgetbv
+0f01d0|11223344556677885f5f5f5f5f	64	intel	xgetbv
+0f01d0|11223344556677885f5f5f5f5f	64	plan9	XGETBV
+0f01d1|11223344556677885f5f5f5f5f	32	intel	xsetbv
+0f01d1|11223344556677885f5f5f5f5f	32	plan9	XSETBV
+0f01d1|11223344556677885f5f5f5f5f	64	gnu	xsetbv
+0f01d1|11223344556677885f5f5f5f5f	64	intel	xsetbv
+0f01d1|11223344556677885f5f5f5f5f	64	plan9	XSETBV
+0f01d5|11223344556677885f5f5f5f5f	32	intel	xend
+0f01d5|11223344556677885f5f5f5f5f	32	plan9	XEND
+0f01d5|11223344556677885f5f5f5f5f	64	gnu	xend
+0f01d5|11223344556677885f5f5f5f5f	64	intel	xend
+0f01d5|11223344556677885f5f5f5f5f	64	plan9	XEND
+0f01d6|11223344556677885f5f5f5f5f	32	intel	xtest
+0f01d6|11223344556677885f5f5f5f5f	32	plan9	XTEST
+0f01d6|11223344556677885f5f5f5f5f	64	gnu	xtest
+0f01d6|11223344556677885f5f5f5f5f	64	intel	xtest
+0f01d6|11223344556677885f5f5f5f5f	64	plan9	XTEST
+0f01f8|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f01f8|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f01f8|11223344556677885f5f5f5f5f	64	gnu	swapgs
+0f01f8|11223344556677885f5f5f5f5f	64	intel	swapgs
+0f01f8|11223344556677885f5f5f5f5f	64	plan9	SWAPGS
+0f01f9|11223344556677885f5f5f5f5f	32	intel	rdtscp
+0f01f9|11223344556677885f5f5f5f5f	32	plan9	RDTSCP
+0f01f9|11223344556677885f5f5f5f5f	64	gnu	rdtscp
+0f01f9|11223344556677885f5f5f5f5f	64	intel	rdtscp
+0f01f9|11223344556677885f5f5f5f5f	64	plan9	RDTSCP
+0f0211|223344556677885f5f5f5f5f5f	32	intel	lar edx, word ptr [ecx]
+0f0211|223344556677885f5f5f5f5f5f	32	plan9	LAR 0(CX), DX
+0f0211|223344556677885f5f5f5f5f5f	64	gnu	lar (%rcx),%edx
+0f0211|223344556677885f5f5f5f5f5f	64	intel	lar edx, word ptr [rcx]
+0f0211|223344556677885f5f5f5f5f5f	64	plan9	LAR 0(CX), DX
+0f0311|223344556677885f5f5f5f5f5f	32	intel	lsl edx, word ptr [ecx]
+0f0311|223344556677885f5f5f5f5f5f	32	plan9	LSL 0(CX), DX
+0f0311|223344556677885f5f5f5f5f5f	64	gnu	lsl (%rcx),%edx
+0f0311|223344556677885f5f5f5f5f5f	64	intel	lsl edx, word ptr [rcx]
+0f0311|223344556677885f5f5f5f5f5f	64	plan9	LSL 0(CX), DX
+0f04|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f04|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f04|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f04|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f04|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f05|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f05|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f05|11223344556677885f5f5f5f5f5f	64	gnu	syscall
+0f05|11223344556677885f5f5f5f5f5f	64	intel	syscall
+0f05|11223344556677885f5f5f5f5f5f	64	plan9	SYSCALL
+0f06|11223344556677885f5f5f5f5f5f	32	intel	clts
+0f06|11223344556677885f5f5f5f5f5f	32	plan9	CLTS
+0f06|11223344556677885f5f5f5f5f5f	64	gnu	clts
+0f06|11223344556677885f5f5f5f5f5f	64	intel	clts
+0f06|11223344556677885f5f5f5f5f5f	64	plan9	CLTS
+0f07|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f07|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f07|11223344556677885f5f5f5f5f5f	64	gnu	sysretq
+0f07|11223344556677885f5f5f5f5f5f	64	intel	sysret
+0f07|11223344556677885f5f5f5f5f5f	64	plan9	SYSRET
+0f08|11223344556677885f5f5f5f5f5f	32	intel	invd
+0f08|11223344556677885f5f5f5f5f5f	32	plan9	INVD
+0f08|11223344556677885f5f5f5f5f5f	64	gnu	invd
+0f08|11223344556677885f5f5f5f5f5f	64	intel	invd
+0f08|11223344556677885f5f5f5f5f5f	64	plan9	INVD
+0f09|11223344556677885f5f5f5f5f5f	32	intel	wbinvd
+0f09|11223344556677885f5f5f5f5f5f	32	plan9	WBINVD
+0f09|11223344556677885f5f5f5f5f5f	64	gnu	wbinvd
+0f09|11223344556677885f5f5f5f5f5f	64	intel	wbinvd
+0f09|11223344556677885f5f5f5f5f5f	64	plan9	WBINVD
+0f0b|11223344556677885f5f5f5f5f5f	32	intel	ud2
+0f0b|11223344556677885f5f5f5f5f5f	32	plan9	UD2
+0f0b|11223344556677885f5f5f5f5f5f	64	gnu	ud2
+0f0b|11223344556677885f5f5f5f5f5f	64	intel	ud2
+0f0b|11223344556677885f5f5f5f5f5f	64	plan9	UD2
+0f0d08|11223344556677885f5f5f5f5f	32	intel	prefetchw zmmword ptr [eax]
+0f0d08|11223344556677885f5f5f5f5f	32	plan9	PREFETCHW 0(AX)
+0f0d08|11223344556677885f5f5f5f5f	64	gnu	prefetchw (%rax)
+0f0d08|11223344556677885f5f5f5f5f	64	intel	prefetchw zmmword ptr [rax]
+0f0d08|11223344556677885f5f5f5f5f	64	plan9	PREFETCHW 0(AX)
+0f1011|223344556677885f5f5f5f5f5f	32	intel	movups xmm2, xmmword ptr [ecx]
+0f1011|223344556677885f5f5f5f5f5f	32	plan9	MOVUPS 0(CX), X2
+0f1011|223344556677885f5f5f5f5f5f	64	gnu	movups (%rcx),%xmm2
+0f1011|223344556677885f5f5f5f5f5f	64	intel	movups xmm2, xmmword ptr [rcx]
+0f1011|223344556677885f5f5f5f5f5f	64	plan9	MOVUPS 0(CX), X2
+0f1122|3344556677885f5f5f5f5f5f5f	32	intel	movups xmmword ptr [edx], xmm4
+0f1122|3344556677885f5f5f5f5f5f5f	32	plan9	MOVUPS X4, 0(DX)
+0f1122|3344556677885f5f5f5f5f5f5f	64	gnu	movups %xmm4,(%rdx)
+0f1122|3344556677885f5f5f5f5f5f5f	64	intel	movups xmmword ptr [rdx], xmm4
+0f1122|3344556677885f5f5f5f5f5f5f	64	plan9	MOVUPS X4, 0(DX)
+0f1211|223344556677885f5f5f5f5f5f	32	intel	movlps xmm2, qword ptr [ecx]
+0f1211|223344556677885f5f5f5f5f5f	32	plan9	MOVLPS 0(CX), X2
+0f1211|223344556677885f5f5f5f5f5f	64	gnu	movlps (%rcx),%xmm2
+0f1211|223344556677885f5f5f5f5f5f	64	intel	movlps xmm2, qword ptr [rcx]
+0f1211|223344556677885f5f5f5f5f5f	64	plan9	MOVLPS 0(CX), X2
+0f12c0|11223344556677885f5f5f5f5f	32	intel	movhlps xmm0, xmm0
+0f12c0|11223344556677885f5f5f5f5f	32	plan9	MOVHLPS X0, X0
+0f12c0|11223344556677885f5f5f5f5f	64	gnu	movhlps %xmm0,%xmm0
+0f12c0|11223344556677885f5f5f5f5f	64	intel	movhlps xmm0, xmm0
+0f12c0|11223344556677885f5f5f5f5f	64	plan9	MOVHLPS X0, X0
+0f1311|223344556677885f5f5f5f5f5f	32	intel	movlps qword ptr [ecx], xmm2
+0f1311|223344556677885f5f5f5f5f5f	32	plan9	MOVLPS X2, 0(CX)
+0f1311|223344556677885f5f5f5f5f5f	64	gnu	movlps %xmm2,(%rcx)
+0f1311|223344556677885f5f5f5f5f5f	64	intel	movlps qword ptr [rcx], xmm2
+0f1311|223344556677885f5f5f5f5f5f	64	plan9	MOVLPS X2, 0(CX)
+0f1411|223344556677885f5f5f5f5f5f	32	intel	unpcklps xmm2, xmmword ptr [ecx]
+0f1411|223344556677885f5f5f5f5f5f	32	plan9	UNPCKLPS 0(CX), X2
+0f1411|223344556677885f5f5f5f5f5f	64	gnu	unpcklps (%rcx),%xmm2
+0f1411|223344556677885f5f5f5f5f5f	64	intel	unpcklps xmm2, xmmword ptr [rcx]
+0f1411|223344556677885f5f5f5f5f5f	64	plan9	UNPCKLPS 0(CX), X2
+0f1511|223344556677885f5f5f5f5f5f	32	intel	unpckhps xmm2, xmmword ptr [ecx]
+0f1511|223344556677885f5f5f5f5f5f	32	plan9	UNPCKHPS 0(CX), X2
+0f1511|223344556677885f5f5f5f5f5f	64	gnu	unpckhps (%rcx),%xmm2
+0f1511|223344556677885f5f5f5f5f5f	64	intel	unpckhps xmm2, xmmword ptr [rcx]
+0f1511|223344556677885f5f5f5f5f5f	64	plan9	UNPCKHPS 0(CX), X2
+0f1611|223344556677885f5f5f5f5f5f	32	intel	movhps xmm2, qword ptr [ecx]
+0f1611|223344556677885f5f5f5f5f5f	32	plan9	MOVHPS 0(CX), X2
+0f1611|223344556677885f5f5f5f5f5f	64	gnu	movhps (%rcx),%xmm2
+0f1611|223344556677885f5f5f5f5f5f	64	intel	movhps xmm2, qword ptr [rcx]
+0f1611|223344556677885f5f5f5f5f5f	64	plan9	MOVHPS 0(CX), X2
+0f16c0|11223344556677885f5f5f5f5f	32	intel	movlhps xmm0, xmm0
+0f16c0|11223344556677885f5f5f5f5f	32	plan9	MOVLHPS X0, X0
+0f16c0|11223344556677885f5f5f5f5f	64	gnu	movlhps %xmm0,%xmm0
+0f16c0|11223344556677885f5f5f5f5f	64	intel	movlhps xmm0, xmm0
+0f16c0|11223344556677885f5f5f5f5f	64	plan9	MOVLHPS X0, X0
+0f1711|223344556677885f5f5f5f5f5f	32	intel	movhps qword ptr [ecx], xmm2
+0f1711|223344556677885f5f5f5f5f5f	32	plan9	MOVHPS X2, 0(CX)
+0f1711|223344556677885f5f5f5f5f5f	64	gnu	movhps %xmm2,(%rcx)
+0f1711|223344556677885f5f5f5f5f5f	64	intel	movhps qword ptr [rcx], xmm2
+0f1711|223344556677885f5f5f5f5f5f	64	plan9	MOVHPS X2, 0(CX)
+0f1800|11223344556677885f5f5f5f5f	32	intel	prefetchnta zmmword ptr [eax]
+0f1800|11223344556677885f5f5f5f5f	32	plan9	PREFETCHNTA 0(AX)
+0f1800|11223344556677885f5f5f5f5f	64	gnu	prefetchnta (%rax)
+0f1800|11223344556677885f5f5f5f5f	64	intel	prefetchnta zmmword ptr [rax]
+0f1800|11223344556677885f5f5f5f5f	64	plan9	PREFETCHNTA 0(AX)
+0f1808|11223344556677885f5f5f5f5f	32	intel	prefetcht0 zmmword ptr [eax]
+0f1808|11223344556677885f5f5f5f5f	32	plan9	PREFETCHT0 0(AX)
+0f1808|11223344556677885f5f5f5f5f	64	gnu	prefetcht0 (%rax)
+0f1808|11223344556677885f5f5f5f5f	64	intel	prefetcht0 zmmword ptr [rax]
+0f1808|11223344556677885f5f5f5f5f	64	plan9	PREFETCHT0 0(AX)
+0f1811|223344556677885f5f5f5f5f5f	32	intel	prefetcht1 zmmword ptr [ecx]
+0f1811|223344556677885f5f5f5f5f5f	32	plan9	PREFETCHT1 0(CX)
+0f1811|223344556677885f5f5f5f5f5f	64	gnu	prefetcht1 (%rcx)
+0f1811|223344556677885f5f5f5f5f5f	64	intel	prefetcht1 zmmword ptr [rcx]
+0f1811|223344556677885f5f5f5f5f5f	64	plan9	PREFETCHT1 0(CX)
+0f1818|11223344556677885f5f5f5f5f	32	intel	prefetcht2 zmmword ptr [eax]
+0f1818|11223344556677885f5f5f5f5f	32	plan9	PREFETCHT2 0(AX)
+0f1818|11223344556677885f5f5f5f5f	64	gnu	prefetcht2 (%rax)
+0f1818|11223344556677885f5f5f5f5f	64	intel	prefetcht2 zmmword ptr [rax]
+0f1818|11223344556677885f5f5f5f5f	64	plan9	PREFETCHT2 0(AX)
+0f1f00|11223344556677885f5f5f5f5f	32	intel	nop dword ptr [eax], eax
+0f1f00|11223344556677885f5f5f5f5f	32	plan9	NOPL 0(AX)
+0f1f00|11223344556677885f5f5f5f5f	64	gnu	nopl (%rax)
+0f1f00|11223344556677885f5f5f5f5f	64	intel	nop dword ptr [rax], eax
+0f1f00|11223344556677885f5f5f5f5f	64	plan9	NOPL 0(AX)
+0f2011|223344556677885f5f5f5f5f5f	32	intel	mov ecx, cr2
+0f2011|223344556677885f5f5f5f5f5f	32	plan9	MOVL CR2, CX
+0f2011|223344556677885f5f5f5f5f5f	64	gnu	mov %cr2,%rcx
+0f2011|223344556677885f5f5f5f5f5f	64	intel	mov rcx, cr2
+0f2011|223344556677885f5f5f5f5f5f	64	plan9	MOVL CR2, CX
+0f2111|223344556677885f5f5f5f5f5f	32	intel	mov ecx, dr2
+0f2111|223344556677885f5f5f5f5f5f	32	plan9	MOVL DR2, CX
+0f2111|223344556677885f5f5f5f5f5f	64	gnu	mov %db2,%rcx
+0f2111|223344556677885f5f5f5f5f5f	64	intel	mov rcx, dr2
+0f2111|223344556677885f5f5f5f5f5f	64	plan9	MOVL DR2, CX
+0f2211|223344556677885f5f5f5f5f5f	32	intel	mov cr2, ecx
+0f2211|223344556677885f5f5f5f5f5f	32	plan9	MOVL CX, CR2
+0f2211|223344556677885f5f5f5f5f5f	64	gnu	mov %rcx,%cr2
+0f2211|223344556677885f5f5f5f5f5f	64	intel	mov cr2, rcx
+0f2211|223344556677885f5f5f5f5f5f	64	plan9	MOVL CX, CR2
+0f2311|223344556677885f5f5f5f5f5f	32	intel	mov dr2, ecx
+0f2311|223344556677885f5f5f5f5f5f	32	plan9	MOVL CX, DR2
+0f2311|223344556677885f5f5f5f5f5f	64	gnu	mov %rcx,%db2
+0f2311|223344556677885f5f5f5f5f5f	64	intel	mov dr2, rcx
+0f2311|223344556677885f5f5f5f5f5f	64	plan9	MOVL CX, DR2
+0f2411|223344556677885f5f5f5f5f5f	32	intel	mov ecx, tr2
+0f2411|223344556677885f5f5f5f5f5f	32	plan9	MOVL TR2, CX
+0f2411|223344556677885f5f5f5f5f5f	64	gnu	mov %tr2,%rcx
+0f2411|223344556677885f5f5f5f5f5f	64	intel	mov rcx, tr2
+0f2411|223344556677885f5f5f5f5f5f	64	plan9	MOVL TR2, CX
+0f2611|223344556677885f5f5f5f5f5f	32	intel	mov tr2, ecx
+0f2611|223344556677885f5f5f5f5f5f	32	plan9	MOVL CX, TR2
+0f2611|223344556677885f5f5f5f5f5f	64	gnu	mov %rcx,%tr2
+0f2611|223344556677885f5f5f5f5f5f	64	intel	mov tr2, rcx
+0f2611|223344556677885f5f5f5f5f5f	64	plan9	MOVL CX, TR2
+0f2811|223344556677885f5f5f5f5f5f	32	intel	movaps xmm2, xmmword ptr [ecx]
+0f2811|223344556677885f5f5f5f5f5f	32	plan9	MOVAPS 0(CX), X2
+0f2811|223344556677885f5f5f5f5f5f	64	gnu	movaps (%rcx),%xmm2
+0f2811|223344556677885f5f5f5f5f5f	64	intel	movaps xmm2, xmmword ptr [rcx]
+0f2811|223344556677885f5f5f5f5f5f	64	plan9	MOVAPS 0(CX), X2
+0f2911|223344556677885f5f5f5f5f5f	32	intel	movaps xmmword ptr [ecx], xmm2
+0f2911|223344556677885f5f5f5f5f5f	32	plan9	MOVAPS X2, 0(CX)
+0f2911|223344556677885f5f5f5f5f5f	64	gnu	movaps %xmm2,(%rcx)
+0f2911|223344556677885f5f5f5f5f5f	64	intel	movaps xmmword ptr [rcx], xmm2
+0f2911|223344556677885f5f5f5f5f5f	64	plan9	MOVAPS X2, 0(CX)
+0f2a11|223344556677885f5f5f5f5f5f	32	intel	cvtpi2ps xmm2, qword ptr [ecx]
+0f2a11|223344556677885f5f5f5f5f5f	32	plan9	CVTPI2PS 0(CX), X2
+0f2a11|223344556677885f5f5f5f5f5f	64	gnu	cvtpi2ps (%rcx),%xmm2
+0f2a11|223344556677885f5f5f5f5f5f	64	intel	cvtpi2ps xmm2, qword ptr [rcx]
+0f2a11|223344556677885f5f5f5f5f5f	64	plan9	CVTPI2PS 0(CX), X2
+0f2b11|223344556677885f5f5f5f5f5f	32	intel	movntps xmmword ptr [ecx], xmm2
+0f2b11|223344556677885f5f5f5f5f5f	32	plan9	MOVNTPS X2, 0(CX)
+0f2b11|223344556677885f5f5f5f5f5f	64	gnu	movntps %xmm2,(%rcx)
+0f2b11|223344556677885f5f5f5f5f5f	64	intel	movntps xmmword ptr [rcx], xmm2
+0f2b11|223344556677885f5f5f5f5f5f	64	plan9	MOVNTPS X2, 0(CX)
+0f2c11|223344556677885f5f5f5f5f5f	32	intel	cvttps2pi mmx2, qword ptr [ecx]
+0f2c11|223344556677885f5f5f5f5f5f	32	plan9	CVTTPS2PI 0(CX), M2
+0f2c11|223344556677885f5f5f5f5f5f	64	gnu	cvttps2pi (%rcx),%mm2
+0f2c11|223344556677885f5f5f5f5f5f	64	intel	cvttps2pi mmx2, qword ptr [rcx]
+0f2c11|223344556677885f5f5f5f5f5f	64	plan9	CVTTPS2PI 0(CX), M2
+0f2d11|223344556677885f5f5f5f5f5f	32	intel	cvtps2pi mmx2, qword ptr [ecx]
+0f2d11|223344556677885f5f5f5f5f5f	32	plan9	CVTPS2PI 0(CX), M2
+0f2d11|223344556677885f5f5f5f5f5f	64	gnu	cvtps2pi (%rcx),%mm2
+0f2d11|223344556677885f5f5f5f5f5f	64	intel	cvtps2pi mmx2, qword ptr [rcx]
+0f2d11|223344556677885f5f5f5f5f5f	64	plan9	CVTPS2PI 0(CX), M2
+0f2e11|223344556677885f5f5f5f5f5f	32	intel	ucomiss xmm2, dword ptr [ecx]
+0f2e11|223344556677885f5f5f5f5f5f	32	plan9	UCOMISS 0(CX), X2
+0f2e11|223344556677885f5f5f5f5f5f	64	gnu	ucomiss (%rcx),%xmm2
+0f2e11|223344556677885f5f5f5f5f5f	64	intel	ucomiss xmm2, dword ptr [rcx]
+0f2e11|223344556677885f5f5f5f5f5f	64	plan9	UCOMISS 0(CX), X2
+0f2f11|223344556677885f5f5f5f5f5f	32	intel	comiss xmm2, dword ptr [ecx]
+0f2f11|223344556677885f5f5f5f5f5f	32	plan9	COMISS 0(CX), X2
+0f2f11|223344556677885f5f5f5f5f5f	64	gnu	comiss (%rcx),%xmm2
+0f2f11|223344556677885f5f5f5f5f5f	64	intel	comiss xmm2, dword ptr [rcx]
+0f2f11|223344556677885f5f5f5f5f5f	64	plan9	COMISS 0(CX), X2
+0f30|11223344556677885f5f5f5f5f5f	32	intel	wrmsr
+0f30|11223344556677885f5f5f5f5f5f	32	plan9	WRMSR
+0f30|11223344556677885f5f5f5f5f5f	64	gnu	wrmsr
+0f30|11223344556677885f5f5f5f5f5f	64	intel	wrmsr
+0f30|11223344556677885f5f5f5f5f5f	64	plan9	WRMSR
+0f31|11223344556677885f5f5f5f5f5f	32	intel	rdtsc
+0f31|11223344556677885f5f5f5f5f5f	32	plan9	RDTSC
+0f31|11223344556677885f5f5f5f5f5f	64	gnu	rdtsc
+0f31|11223344556677885f5f5f5f5f5f	64	intel	rdtsc
+0f31|11223344556677885f5f5f5f5f5f	64	plan9	RDTSC
+0f32|11223344556677885f5f5f5f5f5f	32	intel	rdmsr
+0f32|11223344556677885f5f5f5f5f5f	32	plan9	RDMSR
+0f32|11223344556677885f5f5f5f5f5f	64	gnu	rdmsr
+0f32|11223344556677885f5f5f5f5f5f	64	intel	rdmsr
+0f32|11223344556677885f5f5f5f5f5f	64	plan9	RDMSR
+0f33|11223344556677885f5f5f5f5f5f	32	intel	rdpmc
+0f33|11223344556677885f5f5f5f5f5f	32	plan9	RDPMC
+0f33|11223344556677885f5f5f5f5f5f	64	gnu	rdpmc
+0f33|11223344556677885f5f5f5f5f5f	64	intel	rdpmc
+0f33|11223344556677885f5f5f5f5f5f	64	plan9	RDPMC
+0f34|11223344556677885f5f5f5f5f5f	32	intel	sysenter
+0f34|11223344556677885f5f5f5f5f5f	32	plan9	SYSENTER
+0f34|11223344556677885f5f5f5f5f5f	64	gnu	sysenter
+0f34|11223344556677885f5f5f5f5f5f	64	intel	sysenter
+0f34|11223344556677885f5f5f5f5f5f	64	plan9	SYSENTER
+0f35|11223344556677885f5f5f5f5f5f	32	intel	sysexit
+0f35|11223344556677885f5f5f5f5f5f	32	plan9	SYSEXIT
+0f35|11223344556677885f5f5f5f5f5f	64	gnu	sysexit
+0f35|11223344556677885f5f5f5f5f5f	64	intel	sysexit
+0f35|11223344556677885f5f5f5f5f5f	64	plan9	SYSEXIT
+0f380011|223344556677885f5f5f5f5f	32	intel	pshufb mmx2, qword ptr [ecx]
+0f380011|223344556677885f5f5f5f5f	32	plan9	PSHUFB 0(CX), M2
+0f380011|223344556677885f5f5f5f5f	64	gnu	pshufb (%rcx),%mm2
+0f380011|223344556677885f5f5f5f5f	64	intel	pshufb mmx2, qword ptr [rcx]
+0f380011|223344556677885f5f5f5f5f	64	plan9	PSHUFB 0(CX), M2
+0f380111|223344556677885f5f5f5f5f	32	intel	phaddw mmx2, qword ptr [ecx]
+0f380111|223344556677885f5f5f5f5f	32	plan9	PHADDW 0(CX), M2
+0f380111|223344556677885f5f5f5f5f	64	gnu	phaddw (%rcx),%mm2
+0f380111|223344556677885f5f5f5f5f	64	intel	phaddw mmx2, qword ptr [rcx]
+0f380111|223344556677885f5f5f5f5f	64	plan9	PHADDW 0(CX), M2
+0f380211|223344556677885f5f5f5f5f	32	intel	phaddd mmx2, qword ptr [ecx]
+0f380211|223344556677885f5f5f5f5f	32	plan9	PHADDD 0(CX), M2
+0f380211|223344556677885f5f5f5f5f	64	gnu	phaddd (%rcx),%mm2
+0f380211|223344556677885f5f5f5f5f	64	intel	phaddd mmx2, qword ptr [rcx]
+0f380211|223344556677885f5f5f5f5f	64	plan9	PHADDD 0(CX), M2
+0f380311|223344556677885f5f5f5f5f	32	intel	phaddsw mmx2, qword ptr [ecx]
+0f380311|223344556677885f5f5f5f5f	32	plan9	PHADDSW 0(CX), M2
+0f380311|223344556677885f5f5f5f5f	64	gnu	phaddsw (%rcx),%mm2
+0f380311|223344556677885f5f5f5f5f	64	intel	phaddsw mmx2, qword ptr [rcx]
+0f380311|223344556677885f5f5f5f5f	64	plan9	PHADDSW 0(CX), M2
+0f380411|223344556677885f5f5f5f5f	32	intel	pmaddubsw mmx2, qword ptr [ecx]
+0f380411|223344556677885f5f5f5f5f	32	plan9	PMADDUBSW 0(CX), M2
+0f380411|223344556677885f5f5f5f5f	64	gnu	pmaddubsw (%rcx),%mm2
+0f380411|223344556677885f5f5f5f5f	64	intel	pmaddubsw mmx2, qword ptr [rcx]
+0f380411|223344556677885f5f5f5f5f	64	plan9	PMADDUBSW 0(CX), M2
+0f380511|223344556677885f5f5f5f5f	32	intel	phsubw mmx2, qword ptr [ecx]
+0f380511|223344556677885f5f5f5f5f	32	plan9	PHSUBW 0(CX), M2
+0f380511|223344556677885f5f5f5f5f	64	gnu	phsubw (%rcx),%mm2
+0f380511|223344556677885f5f5f5f5f	64	intel	phsubw mmx2, qword ptr [rcx]
+0f380511|223344556677885f5f5f5f5f	64	plan9	PHSUBW 0(CX), M2
+0f380611|223344556677885f5f5f5f5f	32	intel	phsubd mmx2, qword ptr [ecx]
+0f380611|223344556677885f5f5f5f5f	32	plan9	PHSUBD 0(CX), M2
+0f380611|223344556677885f5f5f5f5f	64	gnu	phsubd (%rcx),%mm2
+0f380611|223344556677885f5f5f5f5f	64	intel	phsubd mmx2, qword ptr [rcx]
+0f380611|223344556677885f5f5f5f5f	64	plan9	PHSUBD 0(CX), M2
+0f380711|223344556677885f5f5f5f5f	32	intel	phsubsw mmx2, qword ptr [ecx]
+0f380711|223344556677885f5f5f5f5f	32	plan9	PHSUBSW 0(CX), M2
+0f380711|223344556677885f5f5f5f5f	64	gnu	phsubsw (%rcx),%mm2
+0f380711|223344556677885f5f5f5f5f	64	intel	phsubsw mmx2, qword ptr [rcx]
+0f380711|223344556677885f5f5f5f5f	64	plan9	PHSUBSW 0(CX), M2
+0f380811|223344556677885f5f5f5f5f	32	intel	psignb mmx2, qword ptr [ecx]
+0f380811|223344556677885f5f5f5f5f	32	plan9	PSIGNB 0(CX), M2
+0f380811|223344556677885f5f5f5f5f	64	gnu	psignb (%rcx),%mm2
+0f380811|223344556677885f5f5f5f5f	64	intel	psignb mmx2, qword ptr [rcx]
+0f380811|223344556677885f5f5f5f5f	64	plan9	PSIGNB 0(CX), M2
+0f380911|223344556677885f5f5f5f5f	32	intel	psignw mmx2, qword ptr [ecx]
+0f380911|223344556677885f5f5f5f5f	32	plan9	PSIGNW 0(CX), M2
+0f380911|223344556677885f5f5f5f5f	64	gnu	psignw (%rcx),%mm2
+0f380911|223344556677885f5f5f5f5f	64	intel	psignw mmx2, qword ptr [rcx]
+0f380911|223344556677885f5f5f5f5f	64	plan9	PSIGNW 0(CX), M2
+0f380a11|223344556677885f5f5f5f5f	32	intel	psignd mmx2, qword ptr [ecx]
+0f380a11|223344556677885f5f5f5f5f	32	plan9	PSIGND 0(CX), M2
+0f380a11|223344556677885f5f5f5f5f	64	gnu	psignd (%rcx),%mm2
+0f380a11|223344556677885f5f5f5f5f	64	intel	psignd mmx2, qword ptr [rcx]
+0f380a11|223344556677885f5f5f5f5f	64	plan9	PSIGND 0(CX), M2
+0f380b11|223344556677885f5f5f5f5f	32	intel	pmulhrsw mmx2, qword ptr [ecx]
+0f380b11|223344556677885f5f5f5f5f	32	plan9	PMULHRSW 0(CX), M2
+0f380b11|223344556677885f5f5f5f5f	64	gnu	pmulhrsw (%rcx),%mm2
+0f380b11|223344556677885f5f5f5f5f	64	intel	pmulhrsw mmx2, qword ptr [rcx]
+0f380b11|223344556677885f5f5f5f5f	64	plan9	PMULHRSW 0(CX), M2
+0f3810|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3810|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3810|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3810|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3810|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3811|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3811|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3811|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3811|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3811|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3814|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3814|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3814|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3814|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3814|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3815|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3815|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3815|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3815|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3815|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3817|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3817|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3817|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3817|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3817|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f381c11|223344556677885f5f5f5f5f	32	intel	pabsb mmx2, qword ptr [ecx]
+0f381c11|223344556677885f5f5f5f5f	32	plan9	PABSB 0(CX), M2
+0f381c11|223344556677885f5f5f5f5f	64	gnu	pabsb (%rcx),%mm2
+0f381c11|223344556677885f5f5f5f5f	64	intel	pabsb mmx2, qword ptr [rcx]
+0f381c11|223344556677885f5f5f5f5f	64	plan9	PABSB 0(CX), M2
+0f381d11|223344556677885f5f5f5f5f	32	intel	pabsw mmx2, qword ptr [ecx]
+0f381d11|223344556677885f5f5f5f5f	32	plan9	PABSW 0(CX), M2
+0f381d11|223344556677885f5f5f5f5f	64	gnu	pabsw (%rcx),%mm2
+0f381d11|223344556677885f5f5f5f5f	64	intel	pabsw mmx2, qword ptr [rcx]
+0f381d11|223344556677885f5f5f5f5f	64	plan9	PABSW 0(CX), M2
+0f381e11|223344556677885f5f5f5f5f	32	intel	pabsd mmx2, qword ptr [ecx]
+0f381e11|223344556677885f5f5f5f5f	32	plan9	PABSD 0(CX), M2
+0f381e11|223344556677885f5f5f5f5f	64	gnu	pabsd (%rcx),%mm2
+0f381e11|223344556677885f5f5f5f5f	64	intel	pabsd mmx2, qword ptr [rcx]
+0f381e11|223344556677885f5f5f5f5f	64	plan9	PABSD 0(CX), M2
+0f3820|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3820|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3820|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3820|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3820|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3821|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3821|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3821|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3821|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3821|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3822|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3822|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3822|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3822|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3822|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3823|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3823|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3823|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3823|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3823|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3824|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3824|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3824|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3824|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3824|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3825|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3825|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3825|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3825|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3825|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3828|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3828|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3828|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3828|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3828|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3829|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3829|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3829|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3829|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3829|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f382a|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f382a|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f382a|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f382a|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f382a|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f382b|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f382b|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f382b|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f382b|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f382b|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3830|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3830|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3830|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3830|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3830|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3831|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3831|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3831|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3831|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3831|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3832|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3832|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3832|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3832|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3832|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3833|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3833|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3833|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3833|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3833|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3834|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3834|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3834|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3834|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3834|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3835|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3835|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3835|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3835|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3835|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3837|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3837|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3837|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3837|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3837|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3838|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3838|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3838|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3838|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3838|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3839|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3839|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3839|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3839|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3839|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f383a|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f383a|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f383a|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f383a|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f383a|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f383b|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f383b|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f383b|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f383b|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f383b|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f383c|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f383c|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f383c|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f383c|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f383c|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f383d|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f383d|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f383d|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f383d|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f383d|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f383e|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f383e|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f383e|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f383e|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f383e|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f383f|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f383f|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f383f|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f383f|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f383f|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3840|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3840|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3840|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3840|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3840|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3841|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3841|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3841|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3841|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3841|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3882|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3882|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3882|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3882|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3882|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f38db|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f38db|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f38db|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f38db|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f38db|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f38dc|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f38dc|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f38dc|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f38dc|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f38dc|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f38dd|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f38dd|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f38dd|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f38dd|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f38dd|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f38de|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f38de|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f38de|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f38de|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f38de|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f38df|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f38df|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f38df|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f38df|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f38df|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f38f011|223344556677885f5f5f5f5f	32	intel	movbe edx, dword ptr [ecx]
+0f38f011|223344556677885f5f5f5f5f	32	plan9	MOVBE 0(CX), DX
+0f38f011|223344556677885f5f5f5f5f	64	gnu	movbe (%rcx),%edx
+0f38f011|223344556677885f5f5f5f5f	64	intel	movbe edx, dword ptr [rcx]
+0f38f011|223344556677885f5f5f5f5f	64	plan9	MOVBE 0(CX), DX
+0f38f111|223344556677885f5f5f5f5f	32	intel	movbe dword ptr [ecx], edx
+0f38f111|223344556677885f5f5f5f5f	32	plan9	MOVBE DX, 0(CX)
+0f38f111|223344556677885f5f5f5f5f	64	gnu	movbe %edx,(%rcx)
+0f38f111|223344556677885f5f5f5f5f	64	intel	movbe dword ptr [rcx], edx
+0f38f111|223344556677885f5f5f5f5f	64	plan9	MOVBE DX, 0(CX)
+0f3a08|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a08|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a08|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a08|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a08|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a09|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a09|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a09|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a09|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a09|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a0a|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a0a|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a0a|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a0a|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a0a|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a0b|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a0b|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a0b|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a0b|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a0b|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a0c|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a0c|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a0c|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a0c|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a0c|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a0d|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a0d|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a0d|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a0d|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a0d|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a0e|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a0e|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a0e|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a0e|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a0e|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a0f1122|3344556677885f5f5f5f5f	32	intel	palignr mmx2, qword ptr [ecx], 0x22
+0f3a0f1122|3344556677885f5f5f5f5f	32	plan9	PALIGNR $0x22, 0(CX), M2
+0f3a0f1122|3344556677885f5f5f5f5f	64	gnu	palignr $0x22,(%rcx),%mm2
+0f3a0f1122|3344556677885f5f5f5f5f	64	intel	palignr mmx2, qword ptr [rcx], 0x22
+0f3a0f1122|3344556677885f5f5f5f5f	64	plan9	PALIGNR $0x22, 0(CX), M2
+0f3a11|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a11|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a11|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a11|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a11|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a14|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a14|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a14|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a14|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a14|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a15|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a15|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a15|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a15|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a15|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a16|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a16|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a16|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a16|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a16|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a17|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a17|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a17|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a17|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a17|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a20|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a20|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a20|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a20|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a20|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a21|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a21|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a21|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a21|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a21|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a22|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a22|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a22|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a22|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a22|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a40|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a40|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a40|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a40|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a40|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a41|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a41|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a41|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a41|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a41|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a42|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a42|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a42|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a42|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a42|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a44|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a44|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a44|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a44|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a44|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a60|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a60|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a60|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a60|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a60|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a61|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a61|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a61|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a61|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a61|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a62|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a62|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a62|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a62|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a62|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3a63|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3a63|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3a63|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3a63|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3a63|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f3adf|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f3adf|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f3adf|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f3adf|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f3adf|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f4011|223344556677885f5f5f5f5f5f	32	intel	cmovo edx, dword ptr [ecx]
+0f4011|223344556677885f5f5f5f5f5f	32	plan9	CMOVO 0(CX), DX
+0f4011|223344556677885f5f5f5f5f5f	64	gnu	cmovo (%rcx),%edx
+0f4011|223344556677885f5f5f5f5f5f	64	intel	cmovo edx, dword ptr [rcx]
+0f4011|223344556677885f5f5f5f5f5f	64	plan9	CMOVO 0(CX), DX
+0f4111|223344556677885f5f5f5f5f5f	32	intel	cmovno edx, dword ptr [ecx]
+0f4111|223344556677885f5f5f5f5f5f	32	plan9	CMOVNO 0(CX), DX
+0f4111|223344556677885f5f5f5f5f5f	64	gnu	cmovno (%rcx),%edx
+0f4111|223344556677885f5f5f5f5f5f	64	intel	cmovno edx, dword ptr [rcx]
+0f4111|223344556677885f5f5f5f5f5f	64	plan9	CMOVNO 0(CX), DX
+0f4211|223344556677885f5f5f5f5f5f	32	intel	cmovb edx, dword ptr [ecx]
+0f4211|223344556677885f5f5f5f5f5f	32	plan9	CMOVB 0(CX), DX
+0f4211|223344556677885f5f5f5f5f5f	64	gnu	cmovb (%rcx),%edx
+0f4211|223344556677885f5f5f5f5f5f	64	intel	cmovb edx, dword ptr [rcx]
+0f4211|223344556677885f5f5f5f5f5f	64	plan9	CMOVB 0(CX), DX
+0f4311|223344556677885f5f5f5f5f5f	32	intel	cmovnb edx, dword ptr [ecx]
+0f4311|223344556677885f5f5f5f5f5f	32	plan9	CMOVAE 0(CX), DX
+0f4311|223344556677885f5f5f5f5f5f	64	gnu	cmovae (%rcx),%edx
+0f4311|223344556677885f5f5f5f5f5f	64	intel	cmovnb edx, dword ptr [rcx]
+0f4311|223344556677885f5f5f5f5f5f	64	plan9	CMOVAE 0(CX), DX
+0f4411|223344556677885f5f5f5f5f5f	32	intel	cmovz edx, dword ptr [ecx]
+0f4411|223344556677885f5f5f5f5f5f	32	plan9	CMOVE 0(CX), DX
+0f4411|223344556677885f5f5f5f5f5f	64	gnu	cmove (%rcx),%edx
+0f4411|223344556677885f5f5f5f5f5f	64	intel	cmovz edx, dword ptr [rcx]
+0f4411|223344556677885f5f5f5f5f5f	64	plan9	CMOVE 0(CX), DX
+0f4511|223344556677885f5f5f5f5f5f	32	intel	cmovnz edx, dword ptr [ecx]
+0f4511|223344556677885f5f5f5f5f5f	32	plan9	CMOVNE 0(CX), DX
+0f4511|223344556677885f5f5f5f5f5f	64	gnu	cmovne (%rcx),%edx
+0f4511|223344556677885f5f5f5f5f5f	64	intel	cmovnz edx, dword ptr [rcx]
+0f4511|223344556677885f5f5f5f5f5f	64	plan9	CMOVNE 0(CX), DX
+0f4611|223344556677885f5f5f5f5f5f	32	intel	cmovbe edx, dword ptr [ecx]
+0f4611|223344556677885f5f5f5f5f5f	32	plan9	CMOVBE 0(CX), DX
+0f4611|223344556677885f5f5f5f5f5f	64	gnu	cmovbe (%rcx),%edx
+0f4611|223344556677885f5f5f5f5f5f	64	intel	cmovbe edx, dword ptr [rcx]
+0f4611|223344556677885f5f5f5f5f5f	64	plan9	CMOVBE 0(CX), DX
+0f4711|223344556677885f5f5f5f5f5f	32	intel	cmovnbe edx, dword ptr [ecx]
+0f4711|223344556677885f5f5f5f5f5f	32	plan9	CMOVA 0(CX), DX
+0f4711|223344556677885f5f5f5f5f5f	64	gnu	cmova (%rcx),%edx
+0f4711|223344556677885f5f5f5f5f5f	64	intel	cmovnbe edx, dword ptr [rcx]
+0f4711|223344556677885f5f5f5f5f5f	64	plan9	CMOVA 0(CX), DX
+0f4811|223344556677885f5f5f5f5f5f	32	intel	cmovs edx, dword ptr [ecx]
+0f4811|223344556677885f5f5f5f5f5f	32	plan9	CMOVS 0(CX), DX
+0f4811|223344556677885f5f5f5f5f5f	64	gnu	cmovs (%rcx),%edx
+0f4811|223344556677885f5f5f5f5f5f	64	intel	cmovs edx, dword ptr [rcx]
+0f4811|223344556677885f5f5f5f5f5f	64	plan9	CMOVS 0(CX), DX
+0f4911|223344556677885f5f5f5f5f5f	32	intel	cmovns edx, dword ptr [ecx]
+0f4911|223344556677885f5f5f5f5f5f	32	plan9	CMOVNS 0(CX), DX
+0f4911|223344556677885f5f5f5f5f5f	64	gnu	cmovns (%rcx),%edx
+0f4911|223344556677885f5f5f5f5f5f	64	intel	cmovns edx, dword ptr [rcx]
+0f4911|223344556677885f5f5f5f5f5f	64	plan9	CMOVNS 0(CX), DX
+0f4a11|223344556677885f5f5f5f5f5f	32	intel	cmovp edx, dword ptr [ecx]
+0f4a11|223344556677885f5f5f5f5f5f	32	plan9	CMOVP 0(CX), DX
+0f4a11|223344556677885f5f5f5f5f5f	64	gnu	cmovp (%rcx),%edx
+0f4a11|223344556677885f5f5f5f5f5f	64	intel	cmovp edx, dword ptr [rcx]
+0f4a11|223344556677885f5f5f5f5f5f	64	plan9	CMOVP 0(CX), DX
+0f4b11|223344556677885f5f5f5f5f5f	32	intel	cmovnp edx, dword ptr [ecx]
+0f4b11|223344556677885f5f5f5f5f5f	32	plan9	CMOVNP 0(CX), DX
+0f4b11|223344556677885f5f5f5f5f5f	64	gnu	cmovnp (%rcx),%edx
+0f4b11|223344556677885f5f5f5f5f5f	64	intel	cmovnp edx, dword ptr [rcx]
+0f4b11|223344556677885f5f5f5f5f5f	64	plan9	CMOVNP 0(CX), DX
+0f4c11|223344556677885f5f5f5f5f5f	32	intel	cmovl edx, dword ptr [ecx]
+0f4c11|223344556677885f5f5f5f5f5f	32	plan9	CMOVL 0(CX), DX
+0f4c11|223344556677885f5f5f5f5f5f	64	gnu	cmovl (%rcx),%edx
+0f4c11|223344556677885f5f5f5f5f5f	64	intel	cmovl edx, dword ptr [rcx]
+0f4c11|223344556677885f5f5f5f5f5f	64	plan9	CMOVL 0(CX), DX
+0f4d11|223344556677885f5f5f5f5f5f	32	intel	cmovnl edx, dword ptr [ecx]
+0f4d11|223344556677885f5f5f5f5f5f	32	plan9	CMOVGE 0(CX), DX
+0f4d11|223344556677885f5f5f5f5f5f	64	gnu	cmovge (%rcx),%edx
+0f4d11|223344556677885f5f5f5f5f5f	64	intel	cmovnl edx, dword ptr [rcx]
+0f4d11|223344556677885f5f5f5f5f5f	64	plan9	CMOVGE 0(CX), DX
+0f4e11|223344556677885f5f5f5f5f5f	32	intel	cmovle edx, dword ptr [ecx]
+0f4e11|223344556677885f5f5f5f5f5f	32	plan9	CMOVLE 0(CX), DX
+0f4e11|223344556677885f5f5f5f5f5f	64	gnu	cmovle (%rcx),%edx
+0f4e11|223344556677885f5f5f5f5f5f	64	intel	cmovle edx, dword ptr [rcx]
+0f4e11|223344556677885f5f5f5f5f5f	64	plan9	CMOVLE 0(CX), DX
+0f4f11|223344556677885f5f5f5f5f5f	32	intel	cmovnle edx, dword ptr [ecx]
+0f4f11|223344556677885f5f5f5f5f5f	32	plan9	CMOVG 0(CX), DX
+0f4f11|223344556677885f5f5f5f5f5f	64	gnu	cmovg (%rcx),%edx
+0f4f11|223344556677885f5f5f5f5f5f	64	intel	cmovnle edx, dword ptr [rcx]
+0f4f11|223344556677885f5f5f5f5f5f	64	plan9	CMOVG 0(CX), DX
+0f5011|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f5011|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f5011|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f5011|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f5011|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f50c0|11223344556677885f5f5f5f5f	32	intel	movmskps eax, xmm0
+0f50c0|11223344556677885f5f5f5f5f	32	plan9	MOVMSKPS X0, AX
+0f50c0|11223344556677885f5f5f5f5f	64	gnu	movmskps %xmm0,%eax
+0f50c0|11223344556677885f5f5f5f5f	64	intel	movmskps eax, xmm0
+0f50c0|11223344556677885f5f5f5f5f	64	plan9	MOVMSKPS X0, AX
+0f5111|223344556677885f5f5f5f5f5f	32	intel	sqrtps xmm2, xmmword ptr [ecx]
+0f5111|223344556677885f5f5f5f5f5f	32	plan9	SQRTPS 0(CX), X2
+0f5111|223344556677885f5f5f5f5f5f	64	gnu	sqrtps (%rcx),%xmm2
+0f5111|223344556677885f5f5f5f5f5f	64	intel	sqrtps xmm2, xmmword ptr [rcx]
+0f5111|223344556677885f5f5f5f5f5f	64	plan9	SQRTPS 0(CX), X2
+0f5211|223344556677885f5f5f5f5f5f	32	intel	rsqrtps xmm2, xmmword ptr [ecx]
+0f5211|223344556677885f5f5f5f5f5f	32	plan9	RSQRTPS 0(CX), X2
+0f5211|223344556677885f5f5f5f5f5f	64	gnu	rsqrtps (%rcx),%xmm2
+0f5211|223344556677885f5f5f5f5f5f	64	intel	rsqrtps xmm2, xmmword ptr [rcx]
+0f5211|223344556677885f5f5f5f5f5f	64	plan9	RSQRTPS 0(CX), X2
+0f5311|223344556677885f5f5f5f5f5f	32	intel	rcpps xmm2, xmmword ptr [ecx]
+0f5311|223344556677885f5f5f5f5f5f	32	plan9	RCPPS 0(CX), X2
+0f5311|223344556677885f5f5f5f5f5f	64	gnu	rcpps (%rcx),%xmm2
+0f5311|223344556677885f5f5f5f5f5f	64	intel	rcpps xmm2, xmmword ptr [rcx]
+0f5311|223344556677885f5f5f5f5f5f	64	plan9	RCPPS 0(CX), X2
+0f5411|223344556677885f5f5f5f5f5f	32	intel	andps xmm2, xmmword ptr [ecx]
+0f5411|223344556677885f5f5f5f5f5f	32	plan9	ANDPS 0(CX), X2
+0f5411|223344556677885f5f5f5f5f5f	64	gnu	andps (%rcx),%xmm2
+0f5411|223344556677885f5f5f5f5f5f	64	intel	andps xmm2, xmmword ptr [rcx]
+0f5411|223344556677885f5f5f5f5f5f	64	plan9	ANDPS 0(CX), X2
+0f5511|223344556677885f5f5f5f5f5f	32	intel	andnps xmm2, xmmword ptr [ecx]
+0f5511|223344556677885f5f5f5f5f5f	32	plan9	ANDNPS 0(CX), X2
+0f5511|223344556677885f5f5f5f5f5f	64	gnu	andnps (%rcx),%xmm2
+0f5511|223344556677885f5f5f5f5f5f	64	intel	andnps xmm2, xmmword ptr [rcx]
+0f5511|223344556677885f5f5f5f5f5f	64	plan9	ANDNPS 0(CX), X2
+0f5611|223344556677885f5f5f5f5f5f	32	intel	orps xmm2, xmmword ptr [ecx]
+0f5611|223344556677885f5f5f5f5f5f	32	plan9	ORPS 0(CX), X2
+0f5611|223344556677885f5f5f5f5f5f	64	gnu	orps (%rcx),%xmm2
+0f5611|223344556677885f5f5f5f5f5f	64	intel	orps xmm2, xmmword ptr [rcx]
+0f5611|223344556677885f5f5f5f5f5f	64	plan9	ORPS 0(CX), X2
+0f5711|223344556677885f5f5f5f5f5f	32	intel	xorps xmm2, xmmword ptr [ecx]
+0f5711|223344556677885f5f5f5f5f5f	32	plan9	XORPS 0(CX), X2
+0f5711|223344556677885f5f5f5f5f5f	64	gnu	xorps (%rcx),%xmm2
+0f5711|223344556677885f5f5f5f5f5f	64	intel	xorps xmm2, xmmword ptr [rcx]
+0f5711|223344556677885f5f5f5f5f5f	64	plan9	XORPS 0(CX), X2
+0f5811|223344556677885f5f5f5f5f5f	32	intel	addps xmm2, xmmword ptr [ecx]
+0f5811|223344556677885f5f5f5f5f5f	32	plan9	ADDPS 0(CX), X2
+0f5811|223344556677885f5f5f5f5f5f	64	gnu	addps (%rcx),%xmm2
+0f5811|223344556677885f5f5f5f5f5f	64	intel	addps xmm2, xmmword ptr [rcx]
+0f5811|223344556677885f5f5f5f5f5f	64	plan9	ADDPS 0(CX), X2
+0f5911|223344556677885f5f5f5f5f5f	32	intel	mulps xmm2, xmmword ptr [ecx]
+0f5911|223344556677885f5f5f5f5f5f	32	plan9	MULPS 0(CX), X2
+0f5911|223344556677885f5f5f5f5f5f	64	gnu	mulps (%rcx),%xmm2
+0f5911|223344556677885f5f5f5f5f5f	64	intel	mulps xmm2, xmmword ptr [rcx]
+0f5911|223344556677885f5f5f5f5f5f	64	plan9	MULPS 0(CX), X2
+0f5a11|223344556677885f5f5f5f5f5f	32	intel	cvtps2pd xmm2, qword ptr [ecx]
+0f5a11|223344556677885f5f5f5f5f5f	32	plan9	CVTPS2PD 0(CX), X2
+0f5a11|223344556677885f5f5f5f5f5f	64	gnu	cvtps2pd (%rcx),%xmm2
+0f5a11|223344556677885f5f5f5f5f5f	64	intel	cvtps2pd xmm2, qword ptr [rcx]
+0f5a11|223344556677885f5f5f5f5f5f	64	plan9	CVTPS2PD 0(CX), X2
+0f5b11|223344556677885f5f5f5f5f5f	32	intel	cvtdq2ps xmm2, xmmword ptr [ecx]
+0f5b11|223344556677885f5f5f5f5f5f	32	plan9	CVTDQ2PS 0(CX), X2
+0f5b11|223344556677885f5f5f5f5f5f	64	gnu	cvtdq2ps (%rcx),%xmm2
+0f5b11|223344556677885f5f5f5f5f5f	64	intel	cvtdq2ps xmm2, xmmword ptr [rcx]
+0f5b11|223344556677885f5f5f5f5f5f	64	plan9	CVTDQ2PS 0(CX), X2
+0f5c11|223344556677885f5f5f5f5f5f	32	intel	subps xmm2, xmmword ptr [ecx]
+0f5c11|223344556677885f5f5f5f5f5f	32	plan9	SUBPS 0(CX), X2
+0f5c11|223344556677885f5f5f5f5f5f	64	gnu	subps (%rcx),%xmm2
+0f5c11|223344556677885f5f5f5f5f5f	64	intel	subps xmm2, xmmword ptr [rcx]
+0f5c11|223344556677885f5f5f5f5f5f	64	plan9	SUBPS 0(CX), X2
+0f5d11|223344556677885f5f5f5f5f5f	32	intel	minps xmm2, xmmword ptr [ecx]
+0f5d11|223344556677885f5f5f5f5f5f	32	plan9	MINPS 0(CX), X2
+0f5d11|223344556677885f5f5f5f5f5f	64	gnu	minps (%rcx),%xmm2
+0f5d11|223344556677885f5f5f5f5f5f	64	intel	minps xmm2, xmmword ptr [rcx]
+0f5d11|223344556677885f5f5f5f5f5f	64	plan9	MINPS 0(CX), X2
+0f5e11|223344556677885f5f5f5f5f5f	32	intel	divps xmm2, xmmword ptr [ecx]
+0f5e11|223344556677885f5f5f5f5f5f	32	plan9	DIVPS 0(CX), X2
+0f5e11|223344556677885f5f5f5f5f5f	64	gnu	divps (%rcx),%xmm2
+0f5e11|223344556677885f5f5f5f5f5f	64	intel	divps xmm2, xmmword ptr [rcx]
+0f5e11|223344556677885f5f5f5f5f5f	64	plan9	DIVPS 0(CX), X2
+0f5f11|223344556677885f5f5f5f5f5f	32	intel	maxps xmm2, xmmword ptr [ecx]
+0f5f11|223344556677885f5f5f5f5f5f	32	plan9	MAXPS 0(CX), X2
+0f5f11|223344556677885f5f5f5f5f5f	64	gnu	maxps (%rcx),%xmm2
+0f5f11|223344556677885f5f5f5f5f5f	64	intel	maxps xmm2, xmmword ptr [rcx]
+0f5f11|223344556677885f5f5f5f5f5f	64	plan9	MAXPS 0(CX), X2
+0f6011|223344556677885f5f5f5f5f5f	32	intel	punpcklbw mmx2, dword ptr [ecx]
+0f6011|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKLBW 0(CX), M2
+0f6011|223344556677885f5f5f5f5f5f	64	gnu	punpcklbw (%rcx),%mm2
+0f6011|223344556677885f5f5f5f5f5f	64	intel	punpcklbw mmx2, dword ptr [rcx]
+0f6011|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKLBW 0(CX), M2
+0f6111|223344556677885f5f5f5f5f5f	32	intel	punpcklwd mmx2, dword ptr [ecx]
+0f6111|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKLWD 0(CX), M2
+0f6111|223344556677885f5f5f5f5f5f	64	gnu	punpcklwd (%rcx),%mm2
+0f6111|223344556677885f5f5f5f5f5f	64	intel	punpcklwd mmx2, dword ptr [rcx]
+0f6111|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKLWD 0(CX), M2
+0f6211|223344556677885f5f5f5f5f5f	32	intel	punpckldq mmx2, dword ptr [ecx]
+0f6211|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKLDQ 0(CX), M2
+0f6211|223344556677885f5f5f5f5f5f	64	gnu	punpckldq (%rcx),%mm2
+0f6211|223344556677885f5f5f5f5f5f	64	intel	punpckldq mmx2, dword ptr [rcx]
+0f6211|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKLDQ 0(CX), M2
+0f6311|223344556677885f5f5f5f5f5f	32	intel	packsswb mmx2, qword ptr [ecx]
+0f6311|223344556677885f5f5f5f5f5f	32	plan9	PACKSSWB 0(CX), M2
+0f6311|223344556677885f5f5f5f5f5f	64	gnu	packsswb (%rcx),%mm2
+0f6311|223344556677885f5f5f5f5f5f	64	intel	packsswb mmx2, qword ptr [rcx]
+0f6311|223344556677885f5f5f5f5f5f	64	plan9	PACKSSWB 0(CX), M2
+0f6411|223344556677885f5f5f5f5f5f	32	intel	pcmpgtb mmx2, qword ptr [ecx]
+0f6411|223344556677885f5f5f5f5f5f	32	plan9	PCMPGTB 0(CX), M2
+0f6411|223344556677885f5f5f5f5f5f	64	gnu	pcmpgtb (%rcx),%mm2
+0f6411|223344556677885f5f5f5f5f5f	64	intel	pcmpgtb mmx2, qword ptr [rcx]
+0f6411|223344556677885f5f5f5f5f5f	64	plan9	PCMPGTB 0(CX), M2
+0f6511|223344556677885f5f5f5f5f5f	32	intel	pcmpgtw mmx2, qword ptr [ecx]
+0f6511|223344556677885f5f5f5f5f5f	32	plan9	PCMPGTW 0(CX), M2
+0f6511|223344556677885f5f5f5f5f5f	64	gnu	pcmpgtw (%rcx),%mm2
+0f6511|223344556677885f5f5f5f5f5f	64	intel	pcmpgtw mmx2, qword ptr [rcx]
+0f6511|223344556677885f5f5f5f5f5f	64	plan9	PCMPGTW 0(CX), M2
+0f6611|223344556677885f5f5f5f5f5f	32	intel	pcmpgtd mmx2, qword ptr [ecx]
+0f6611|223344556677885f5f5f5f5f5f	32	plan9	PCMPGTD 0(CX), M2
+0f6611|223344556677885f5f5f5f5f5f	64	gnu	pcmpgtd (%rcx),%mm2
+0f6611|223344556677885f5f5f5f5f5f	64	intel	pcmpgtd mmx2, qword ptr [rcx]
+0f6611|223344556677885f5f5f5f5f5f	64	plan9	PCMPGTD 0(CX), M2
+0f6711|223344556677885f5f5f5f5f5f	32	intel	packuswb mmx2, qword ptr [ecx]
+0f6711|223344556677885f5f5f5f5f5f	32	plan9	PACKUSWB 0(CX), M2
+0f6711|223344556677885f5f5f5f5f5f	64	gnu	packuswb (%rcx),%mm2
+0f6711|223344556677885f5f5f5f5f5f	64	intel	packuswb mmx2, qword ptr [rcx]
+0f6711|223344556677885f5f5f5f5f5f	64	plan9	PACKUSWB 0(CX), M2
+0f6811|223344556677885f5f5f5f5f5f	32	intel	punpckhbw mmx2, qword ptr [ecx]
+0f6811|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKHBW 0(CX), M2
+0f6811|223344556677885f5f5f5f5f5f	64	gnu	punpckhbw (%rcx),%mm2
+0f6811|223344556677885f5f5f5f5f5f	64	intel	punpckhbw mmx2, qword ptr [rcx]
+0f6811|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKHBW 0(CX), M2
+0f6911|223344556677885f5f5f5f5f5f	32	intel	punpckhwd mmx2, qword ptr [ecx]
+0f6911|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKHWD 0(CX), M2
+0f6911|223344556677885f5f5f5f5f5f	64	gnu	punpckhwd (%rcx),%mm2
+0f6911|223344556677885f5f5f5f5f5f	64	intel	punpckhwd mmx2, qword ptr [rcx]
+0f6911|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKHWD 0(CX), M2
+0f6a11|223344556677885f5f5f5f5f5f	32	intel	punpckhdq mmx2, qword ptr [ecx]
+0f6a11|223344556677885f5f5f5f5f5f	32	plan9	PUNPCKHDQ 0(CX), M2
+0f6a11|223344556677885f5f5f5f5f5f	64	gnu	punpckhdq (%rcx),%mm2
+0f6a11|223344556677885f5f5f5f5f5f	64	intel	punpckhdq mmx2, qword ptr [rcx]
+0f6a11|223344556677885f5f5f5f5f5f	64	plan9	PUNPCKHDQ 0(CX), M2
+0f6b11|223344556677885f5f5f5f5f5f	32	intel	packssdw mmx2, qword ptr [ecx]
+0f6b11|223344556677885f5f5f5f5f5f	32	plan9	PACKSSDW 0(CX), M2
+0f6b11|223344556677885f5f5f5f5f5f	64	gnu	packssdw (%rcx),%mm2
+0f6b11|223344556677885f5f5f5f5f5f	64	intel	packssdw mmx2, qword ptr [rcx]
+0f6b11|223344556677885f5f5f5f5f5f	64	plan9	PACKSSDW 0(CX), M2
+0f6c|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f6c|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f6c|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f6c|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f6c|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f6d|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f6d|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f6d|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f6d|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f6d|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f6e11|223344556677885f5f5f5f5f5f	32	intel	movd mmx2, dword ptr [ecx]
+0f6e11|223344556677885f5f5f5f5f5f	32	plan9	MOVD 0(CX), M2
+0f6e11|223344556677885f5f5f5f5f5f	64	gnu	movd (%rcx),%mm2
+0f6e11|223344556677885f5f5f5f5f5f	64	intel	movd mmx2, dword ptr [rcx]
+0f6e11|223344556677885f5f5f5f5f5f	64	plan9	MOVD 0(CX), M2
+0f6f11|223344556677885f5f5f5f5f5f	32	intel	movq mmx2, qword ptr [ecx]
+0f6f11|223344556677885f5f5f5f5f5f	32	plan9	MOVQ 0(CX), M2
+0f6f11|223344556677885f5f5f5f5f5f	64	gnu	movq (%rcx),%mm2
+0f6f11|223344556677885f5f5f5f5f5f	64	intel	movq mmx2, qword ptr [rcx]
+0f6f11|223344556677885f5f5f5f5f5f	64	plan9	MOVQ 0(CX), M2
+0f701122|3344556677885f5f5f5f5f5f	32	intel	pshufw mmx2, qword ptr [ecx], 0x22
+0f701122|3344556677885f5f5f5f5f5f	32	plan9	PSHUFW $0x22, 0(CX), M2
+0f701122|3344556677885f5f5f5f5f5f	64	gnu	pshufw $0x22,(%rcx),%mm2
+0f701122|3344556677885f5f5f5f5f5f	64	intel	pshufw mmx2, qword ptr [rcx], 0x22
+0f701122|3344556677885f5f5f5f5f5f	64	plan9	PSHUFW $0x22, 0(CX), M2
+0f7100|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f7100|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f7100|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f7100|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f7100|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f711122|3344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f711122|3344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f711122|3344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f711122|3344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f711122|3344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f712011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f712011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f712011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f712011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f712011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f713011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f713011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f713011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f713011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f713011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f71d011|223344556677885f5f5f5f5f	32	intel	psrlw mmx0, 0x11
+0f71d011|223344556677885f5f5f5f5f	32	plan9	PSRLW $0x11, M0
+0f71d011|223344556677885f5f5f5f5f	64	gnu	psrlw $0x11,%mm0
+0f71d011|223344556677885f5f5f5f5f	64	intel	psrlw mmx0, 0x11
+0f71d011|223344556677885f5f5f5f5f	64	plan9	PSRLW $0x11, M0
+0f71e011|223344556677885f5f5f5f5f	32	intel	psraw mmx0, 0x11
+0f71e011|223344556677885f5f5f5f5f	32	plan9	PSRAW $0x11, M0
+0f71e011|223344556677885f5f5f5f5f	64	gnu	psraw $0x11,%mm0
+0f71e011|223344556677885f5f5f5f5f	64	intel	psraw mmx0, 0x11
+0f71e011|223344556677885f5f5f5f5f	64	plan9	PSRAW $0x11, M0
+0f71f011|223344556677885f5f5f5f5f	32	intel	psllw mmx0, 0x11
+0f71f011|223344556677885f5f5f5f5f	32	plan9	PSLLW $0x11, M0
+0f71f011|223344556677885f5f5f5f5f	64	gnu	psllw $0x11,%mm0
+0f71f011|223344556677885f5f5f5f5f	64	intel	psllw mmx0, 0x11
+0f71f011|223344556677885f5f5f5f5f	64	plan9	PSLLW $0x11, M0
+0f7200|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f7200|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f7200|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f7200|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f7200|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f721122|3344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f721122|3344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f721122|3344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f721122|3344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f721122|3344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f722011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f722011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f722011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f722011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f722011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f723011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f723011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f723011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f723011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f723011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f72d011|223344556677885f5f5f5f5f	32	intel	psrld mmx0, 0x11
+0f72d011|223344556677885f5f5f5f5f	32	plan9	PSRLD $0x11, M0
+0f72d011|223344556677885f5f5f5f5f	64	gnu	psrld $0x11,%mm0
+0f72d011|223344556677885f5f5f5f5f	64	intel	psrld mmx0, 0x11
+0f72d011|223344556677885f5f5f5f5f	64	plan9	PSRLD $0x11, M0
+0f72e011|223344556677885f5f5f5f5f	32	intel	psrad mmx0, 0x11
+0f72e011|223344556677885f5f5f5f5f	32	plan9	PSRAD $0x11, M0
+0f72e011|223344556677885f5f5f5f5f	64	gnu	psrad $0x11,%mm0
+0f72e011|223344556677885f5f5f5f5f	64	intel	psrad mmx0, 0x11
+0f72e011|223344556677885f5f5f5f5f	64	plan9	PSRAD $0x11, M0
+0f72f011|223344556677885f5f5f5f5f	32	intel	pslld mmx0, 0x11
+0f72f011|223344556677885f5f5f5f5f	32	plan9	PSLLD $0x11, M0
+0f72f011|223344556677885f5f5f5f5f	64	gnu	pslld $0x11,%mm0
+0f72f011|223344556677885f5f5f5f5f	64	intel	pslld mmx0, 0x11
+0f72f011|223344556677885f5f5f5f5f	64	plan9	PSLLD $0x11, M0
+0f7300|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f7300|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f7300|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f7300|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f7300|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f731122|3344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f731122|3344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f731122|3344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f731122|3344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f731122|3344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f7318|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f7318|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f7318|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f7318|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f7318|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f733011|223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f733011|223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f733011|223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f733011|223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f733011|223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f7338|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0f7338|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f7338|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f7338|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0f7338|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f73d011|223344556677885f5f5f5f5f	32	intel	psrlq mmx0, 0x11
+0f73d011|223344556677885f5f5f5f5f	32	plan9	PSRLQ $0x11, M0
+0f73d011|223344556677885f5f5f5f5f	64	gnu	psrlq $0x11,%mm0
+0f73d011|223344556677885f5f5f5f5f	64	intel	psrlq mmx0, 0x11
+0f73d011|223344556677885f5f5f5f5f	64	plan9	PSRLQ $0x11, M0
+0f73f011|223344556677885f5f5f5f5f	32	intel	psllq mmx0, 0x11
+0f73f011|223344556677885f5f5f5f5f	32	plan9	PSLLQ $0x11, M0
+0f73f011|223344556677885f5f5f5f5f	64	gnu	psllq $0x11,%mm0
+0f73f011|223344556677885f5f5f5f5f	64	intel	psllq mmx0, 0x11
+0f73f011|223344556677885f5f5f5f5f	64	plan9	PSLLQ $0x11, M0
+0f7411|223344556677885f5f5f5f5f5f	32	intel	pcmpeqb mmx2, qword ptr [ecx]
+0f7411|223344556677885f5f5f5f5f5f	32	plan9	PCMPEQB 0(CX), M2
+0f7411|223344556677885f5f5f5f5f5f	64	gnu	pcmpeqb (%rcx),%mm2
+0f7411|223344556677885f5f5f5f5f5f	64	intel	pcmpeqb mmx2, qword ptr [rcx]
+0f7411|223344556677885f5f5f5f5f5f	64	plan9	PCMPEQB 0(CX), M2
+0f7511|223344556677885f5f5f5f5f5f	32	intel	pcmpeqw mmx2, qword ptr [ecx]
+0f7511|223344556677885f5f5f5f5f5f	32	plan9	PCMPEQW 0(CX), M2
+0f7511|223344556677885f5f5f5f5f5f	64	gnu	pcmpeqw (%rcx),%mm2
+0f7511|223344556677885f5f5f5f5f5f	64	intel	pcmpeqw mmx2, qword ptr [rcx]
+0f7511|223344556677885f5f5f5f5f5f	64	plan9	PCMPEQW 0(CX), M2
+0f7611|223344556677885f5f5f5f5f5f	32	intel	pcmpeqd mmx2, qword ptr [ecx]
+0f7611|223344556677885f5f5f5f5f5f	32	plan9	PCMPEQD 0(CX), M2
+0f7611|223344556677885f5f5f5f5f5f	64	gnu	pcmpeqd (%rcx),%mm2
+0f7611|223344556677885f5f5f5f5f5f	64	intel	pcmpeqd mmx2, qword ptr [rcx]
+0f7611|223344556677885f5f5f5f5f5f	64	plan9	PCMPEQD 0(CX), M2
+0f77|11223344556677885f5f5f5f5f5f	32	intel	emms
+0f77|11223344556677885f5f5f5f5f5f	32	plan9	EMMS
+0f77|11223344556677885f5f5f5f5f5f	64	gnu	emms
+0f77|11223344556677885f5f5f5f5f5f	64	intel	emms
+0f77|11223344556677885f5f5f5f5f5f	64	plan9	EMMS
+0f7c|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f7c|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f7c|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f7c|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f7c|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f7d|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0f7d|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0f7d|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0f7d|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0f7d|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0f7e11|223344556677885f5f5f5f5f5f	32	intel	movd dword ptr [ecx], mmx2
+0f7e11|223344556677885f5f5f5f5f5f	32	plan9	MOVD M2, 0(CX)
+0f7e11|223344556677885f5f5f5f5f5f	64	gnu	movd %mm2,(%rcx)
+0f7e11|223344556677885f5f5f5f5f5f	64	intel	movd dword ptr [rcx], mmx2
+0f7e11|223344556677885f5f5f5f5f5f	64	plan9	MOVD M2, 0(CX)
+0f7f11|223344556677885f5f5f5f5f5f	32	intel	movq qword ptr [ecx], mmx2
+0f7f11|223344556677885f5f5f5f5f5f	32	plan9	MOVQ M2, 0(CX)
+0f7f11|223344556677885f5f5f5f5f5f	64	gnu	movq %mm2,(%rcx)
+0f7f11|223344556677885f5f5f5f5f5f	64	intel	movq qword ptr [rcx], mmx2
+0f7f11|223344556677885f5f5f5f5f5f	64	plan9	MOVQ M2, 0(CX)
+0f8011223344|556677885f5f5f5f5f5f	32	intel	jo .+0x44332211
+0f8011223344|556677885f5f5f5f5f5f	32	plan9	JO .+1144201745
+0f8011223344|556677885f5f5f5f5f5f	64	gnu	jo .+0x44332211
+0f8011223344|556677885f5f5f5f5f5f	64	intel	jo .+0x44332211
+0f8011223344|556677885f5f5f5f5f5f	64	plan9	JO .+1144201745
+0f8111223344|556677885f5f5f5f5f5f	32	intel	jno .+0x44332211
+0f8111223344|556677885f5f5f5f5f5f	32	plan9	JNO .+1144201745
+0f8111223344|556677885f5f5f5f5f5f	64	gnu	jno .+0x44332211
+0f8111223344|556677885f5f5f5f5f5f	64	intel	jno .+0x44332211
+0f8111223344|556677885f5f5f5f5f5f	64	plan9	JNO .+1144201745
+0f8211223344|556677885f5f5f5f5f5f	32	intel	jb .+0x44332211
+0f8211223344|556677885f5f5f5f5f5f	32	plan9	JB .+1144201745
+0f8211223344|556677885f5f5f5f5f5f	64	gnu	jb .+0x44332211
+0f8211223344|556677885f5f5f5f5f5f	64	intel	jb .+0x44332211
+0f8211223344|556677885f5f5f5f5f5f	64	plan9	JB .+1144201745
+0f8311223344|556677885f5f5f5f5f5f	32	intel	jnb .+0x44332211
+0f8311223344|556677885f5f5f5f5f5f	32	plan9	JAE .+1144201745
+0f8311223344|556677885f5f5f5f5f5f	64	gnu	jae .+0x44332211
+0f8311223344|556677885f5f5f5f5f5f	64	intel	jnb .+0x44332211
+0f8311223344|556677885f5f5f5f5f5f	64	plan9	JAE .+1144201745
+0f8411223344|556677885f5f5f5f5f5f	32	intel	jz .+0x44332211
+0f8411223344|556677885f5f5f5f5f5f	32	plan9	JE .+1144201745
+0f8411223344|556677885f5f5f5f5f5f	64	gnu	je .+0x44332211
+0f8411223344|556677885f5f5f5f5f5f	64	intel	jz .+0x44332211
+0f8411223344|556677885f5f5f5f5f5f	64	plan9	JE .+1144201745
+0f8511223344|556677885f5f5f5f5f5f	32	intel	jnz .+0x44332211
+0f8511223344|556677885f5f5f5f5f5f	32	plan9	JNE .+1144201745
+0f8511223344|556677885f5f5f5f5f5f	64	gnu	jne .+0x44332211
+0f8511223344|556677885f5f5f5f5f5f	64	intel	jnz .+0x44332211
+0f8511223344|556677885f5f5f5f5f5f	64	plan9	JNE .+1144201745
+0f8611223344|556677885f5f5f5f5f5f	32	intel	jbe .+0x44332211
+0f8611223344|556677885f5f5f5f5f5f	32	plan9	JBE .+1144201745
+0f8611223344|556677885f5f5f5f5f5f	64	gnu	jbe .+0x44332211
+0f8611223344|556677885f5f5f5f5f5f	64	intel	jbe .+0x44332211
+0f8611223344|556677885f5f5f5f5f5f	64	plan9	JBE .+1144201745
+0f8711223344|556677885f5f5f5f5f5f	32	intel	jnbe .+0x44332211
+0f8711223344|556677885f5f5f5f5f5f	32	plan9	JA .+1144201745
+0f8711223344|556677885f5f5f5f5f5f	64	gnu	ja .+0x44332211
+0f8711223344|556677885f5f5f5f5f5f	64	intel	jnbe .+0x44332211
+0f8711223344|556677885f5f5f5f5f5f	64	plan9	JA .+1144201745
+0f8811223344|556677885f5f5f5f5f5f	32	intel	js .+0x44332211
+0f8811223344|556677885f5f5f5f5f5f	32	plan9	JS .+1144201745
+0f8811223344|556677885f5f5f5f5f5f	64	gnu	js .+0x44332211
+0f8811223344|556677885f5f5f5f5f5f	64	intel	js .+0x44332211
+0f8811223344|556677885f5f5f5f5f5f	64	plan9	JS .+1144201745
+0f8911223344|556677885f5f5f5f5f5f	32	intel	jns .+0x44332211
+0f8911223344|556677885f5f5f5f5f5f	32	plan9	JNS .+1144201745
+0f8911223344|556677885f5f5f5f5f5f	64	gnu	jns .+0x44332211
+0f8911223344|556677885f5f5f5f5f5f	64	intel	jns .+0x44332211
+0f8911223344|556677885f5f5f5f5f5f	64	plan9	JNS .+1144201745
+0f8a11223344|556677885f5f5f5f5f5f	32	intel	jp .+0x44332211
+0f8a11223344|556677885f5f5f5f5f5f	32	plan9	JP .+1144201745
+0f8a11223344|556677885f5f5f5f5f5f	64	gnu	jp .+0x44332211
+0f8a11223344|556677885f5f5f5f5f5f	64	intel	jp .+0x44332211
+0f8a11223344|556677885f5f5f5f5f5f	64	plan9	JP .+1144201745
+0f8b11223344|556677885f5f5f5f5f5f	32	intel	jnp .+0x44332211
+0f8b11223344|556677885f5f5f5f5f5f	32	plan9	JNP .+1144201745
+0f8b11223344|556677885f5f5f5f5f5f	64	gnu	jnp .+0x44332211
+0f8b11223344|556677885f5f5f5f5f5f	64	intel	jnp .+0x44332211
+0f8b11223344|556677885f5f5f5f5f5f	64	plan9	JNP .+1144201745
+0f8c11223344|556677885f5f5f5f5f5f	32	intel	jl .+0x44332211
+0f8c11223344|556677885f5f5f5f5f5f	32	plan9	JL .+1144201745
+0f8c11223344|556677885f5f5f5f5f5f	64	gnu	jl .+0x44332211
+0f8c11223344|556677885f5f5f5f5f5f	64	intel	jl .+0x44332211
+0f8c11223344|556677885f5f5f5f5f5f	64	plan9	JL .+1144201745
+0f8d11223344|556677885f5f5f5f5f5f	32	intel	jnl .+0x44332211
+0f8d11223344|556677885f5f5f5f5f5f	32	plan9	JGE .+1144201745
+0f8d11223344|556677885f5f5f5f5f5f	64	gnu	jge .+0x44332211
+0f8d11223344|556677885f5f5f5f5f5f	64	intel	jnl .+0x44332211
+0f8d11223344|556677885f5f5f5f5f5f	64	plan9	JGE .+1144201745
+0f8e11223344|556677885f5f5f5f5f5f	32	intel	jle .+0x44332211
+0f8e11223344|556677885f5f5f5f5f5f	32	plan9	JLE .+1144201745
+0f8e11223344|556677885f5f5f5f5f5f	64	gnu	jle .+0x44332211
+0f8e11223344|556677885f5f5f5f5f5f	64	intel	jle .+0x44332211
+0f8e11223344|556677885f5f5f5f5f5f	64	plan9	JLE .+1144201745
+0f8f11223344|556677885f5f5f5f5f5f	32	intel	jnle .+0x44332211
+0f8f11223344|556677885f5f5f5f5f5f	32	plan9	JG .+1144201745
+0f8f11223344|556677885f5f5f5f5f5f	64	gnu	jg .+0x44332211
+0f8f11223344|556677885f5f5f5f5f5f	64	intel	jnle .+0x44332211
+0f8f11223344|556677885f5f5f5f5f5f	64	plan9	JG .+1144201745
+0f9011|223344556677885f5f5f5f5f5f	32	intel	seto byte ptr [ecx]
+0f9011|223344556677885f5f5f5f5f5f	32	plan9	SETO 0(CX)
+0f9011|223344556677885f5f5f5f5f5f	64	gnu	seto (%rcx)
+0f9011|223344556677885f5f5f5f5f5f	64	intel	seto byte ptr [rcx]
+0f9011|223344556677885f5f5f5f5f5f	64	plan9	SETO 0(CX)
+0f9111|223344556677885f5f5f5f5f5f	32	intel	setno byte ptr [ecx]
+0f9111|223344556677885f5f5f5f5f5f	32	plan9	SETNO 0(CX)
+0f9111|223344556677885f5f5f5f5f5f	64	gnu	setno (%rcx)
+0f9111|223344556677885f5f5f5f5f5f	64	intel	setno byte ptr [rcx]
+0f9111|223344556677885f5f5f5f5f5f	64	plan9	SETNO 0(CX)
+0f9211|223344556677885f5f5f5f5f5f	32	intel	setb byte ptr [ecx]
+0f9211|223344556677885f5f5f5f5f5f	32	plan9	SETB 0(CX)
+0f9211|223344556677885f5f5f5f5f5f	64	gnu	setb (%rcx)
+0f9211|223344556677885f5f5f5f5f5f	64	intel	setb byte ptr [rcx]
+0f9211|223344556677885f5f5f5f5f5f	64	plan9	SETB 0(CX)
+0f9311|223344556677885f5f5f5f5f5f	32	intel	setnb byte ptr [ecx]
+0f9311|223344556677885f5f5f5f5f5f	32	plan9	SETAE 0(CX)
+0f9311|223344556677885f5f5f5f5f5f	64	gnu	setae (%rcx)
+0f9311|223344556677885f5f5f5f5f5f	64	intel	setnb byte ptr [rcx]
+0f9311|223344556677885f5f5f5f5f5f	64	plan9	SETAE 0(CX)
+0f9411|223344556677885f5f5f5f5f5f	32	intel	setz byte ptr [ecx]
+0f9411|223344556677885f5f5f5f5f5f	32	plan9	SETE 0(CX)
+0f9411|223344556677885f5f5f5f5f5f	64	gnu	sete (%rcx)
+0f9411|223344556677885f5f5f5f5f5f	64	intel	setz byte ptr [rcx]
+0f9411|223344556677885f5f5f5f5f5f	64	plan9	SETE 0(CX)
+0f9511|223344556677885f5f5f5f5f5f	32	intel	setnz byte ptr [ecx]
+0f9511|223344556677885f5f5f5f5f5f	32	plan9	SETNE 0(CX)
+0f9511|223344556677885f5f5f5f5f5f	64	gnu	setne (%rcx)
+0f9511|223344556677885f5f5f5f5f5f	64	intel	setnz byte ptr [rcx]
+0f9511|223344556677885f5f5f5f5f5f	64	plan9	SETNE 0(CX)
+0f9611|223344556677885f5f5f5f5f5f	32	intel	setbe byte ptr [ecx]
+0f9611|223344556677885f5f5f5f5f5f	32	plan9	SETBE 0(CX)
+0f9611|223344556677885f5f5f5f5f5f	64	gnu	setbe (%rcx)
+0f9611|223344556677885f5f5f5f5f5f	64	intel	setbe byte ptr [rcx]
+0f9611|223344556677885f5f5f5f5f5f	64	plan9	SETBE 0(CX)
+0f9711|223344556677885f5f5f5f5f5f	32	intel	setnbe byte ptr [ecx]
+0f9711|223344556677885f5f5f5f5f5f	32	plan9	SETA 0(CX)
+0f9711|223344556677885f5f5f5f5f5f	64	gnu	seta (%rcx)
+0f9711|223344556677885f5f5f5f5f5f	64	intel	setnbe byte ptr [rcx]
+0f9711|223344556677885f5f5f5f5f5f	64	plan9	SETA 0(CX)
+0f9811|223344556677885f5f5f5f5f5f	32	intel	sets byte ptr [ecx]
+0f9811|223344556677885f5f5f5f5f5f	32	plan9	SETS 0(CX)
+0f9811|223344556677885f5f5f5f5f5f	64	gnu	sets (%rcx)
+0f9811|223344556677885f5f5f5f5f5f	64	intel	sets byte ptr [rcx]
+0f9811|223344556677885f5f5f5f5f5f	64	plan9	SETS 0(CX)
+0f9911|223344556677885f5f5f5f5f5f	32	intel	setns byte ptr [ecx]
+0f9911|223344556677885f5f5f5f5f5f	32	plan9	SETNS 0(CX)
+0f9911|223344556677885f5f5f5f5f5f	64	gnu	setns (%rcx)
+0f9911|223344556677885f5f5f5f5f5f	64	intel	setns byte ptr [rcx]
+0f9911|223344556677885f5f5f5f5f5f	64	plan9	SETNS 0(CX)
+0f9a11|223344556677885f5f5f5f5f5f	32	intel	setp byte ptr [ecx]
+0f9a11|223344556677885f5f5f5f5f5f	32	plan9	SETP 0(CX)
+0f9a11|223344556677885f5f5f5f5f5f	64	gnu	setp (%rcx)
+0f9a11|223344556677885f5f5f5f5f5f	64	intel	setp byte ptr [rcx]
+0f9a11|223344556677885f5f5f5f5f5f	64	plan9	SETP 0(CX)
+0f9b11|223344556677885f5f5f5f5f5f	32	intel	setnp byte ptr [ecx]
+0f9b11|223344556677885f5f5f5f5f5f	32	plan9	SETNP 0(CX)
+0f9b11|223344556677885f5f5f5f5f5f	64	gnu	setnp (%rcx)
+0f9b11|223344556677885f5f5f5f5f5f	64	intel	setnp byte ptr [rcx]
+0f9b11|223344556677885f5f5f5f5f5f	64	plan9	SETNP 0(CX)
+0f9c11|223344556677885f5f5f5f5f5f	32	intel	setl byte ptr [ecx]
+0f9c11|223344556677885f5f5f5f5f5f	32	plan9	SETL 0(CX)
+0f9c11|223344556677885f5f5f5f5f5f	64	gnu	setl (%rcx)
+0f9c11|223344556677885f5f5f5f5f5f	64	intel	setl byte ptr [rcx]
+0f9c11|223344556677885f5f5f5f5f5f	64	plan9	SETL 0(CX)
+0f9d11|223344556677885f5f5f5f5f5f	32	intel	setnl byte ptr [ecx]
+0f9d11|223344556677885f5f5f5f5f5f	32	plan9	SETGE 0(CX)
+0f9d11|223344556677885f5f5f5f5f5f	64	gnu	setge (%rcx)
+0f9d11|223344556677885f5f5f5f5f5f	64	intel	setnl byte ptr [rcx]
+0f9d11|223344556677885f5f5f5f5f5f	64	plan9	SETGE 0(CX)
+0f9e11|223344556677885f5f5f5f5f5f	32	intel	setle byte ptr [ecx]
+0f9e11|223344556677885f5f5f5f5f5f	32	plan9	SETLE 0(CX)
+0f9e11|223344556677885f5f5f5f5f5f	64	gnu	setle (%rcx)
+0f9e11|223344556677885f5f5f5f5f5f	64	intel	setle byte ptr [rcx]
+0f9e11|223344556677885f5f5f5f5f5f	64	plan9	SETLE 0(CX)
+0f9f11|223344556677885f5f5f5f5f5f	32	intel	setnle byte ptr [ecx]
+0f9f11|223344556677885f5f5f5f5f5f	32	plan9	SETG 0(CX)
+0f9f11|223344556677885f5f5f5f5f5f	64	gnu	setg (%rcx)
+0f9f11|223344556677885f5f5f5f5f5f	64	intel	setnle byte ptr [rcx]
+0f9f11|223344556677885f5f5f5f5f5f	64	plan9	SETG 0(CX)
+0fa0|11223344556677885f5f5f5f5f5f	32	intel	push fs
+0fa0|11223344556677885f5f5f5f5f5f	32	plan9	PUSHL FS
+0fa0|11223344556677885f5f5f5f5f5f	64	gnu	pushq %fs
+0fa0|11223344556677885f5f5f5f5f5f	64	intel	push fs
+0fa0|11223344556677885f5f5f5f5f5f	64	plan9	PUSHL FS
+0fa1|11223344556677885f5f5f5f5f5f	32	intel	pop fs
+0fa1|11223344556677885f5f5f5f5f5f	32	plan9	POPL FS
+0fa1|11223344556677885f5f5f5f5f5f	64	gnu	popq %fs
+0fa1|11223344556677885f5f5f5f5f5f	64	intel	pop fs
+0fa1|11223344556677885f5f5f5f5f5f	64	plan9	POPL FS
+0fa2|11223344556677885f5f5f5f5f5f	32	intel	cpuid
+0fa2|11223344556677885f5f5f5f5f5f	32	plan9	CPUID
+0fa2|11223344556677885f5f5f5f5f5f	64	gnu	cpuid
+0fa2|11223344556677885f5f5f5f5f5f	64	intel	cpuid
+0fa2|11223344556677885f5f5f5f5f5f	64	plan9	CPUID
+0fa311|223344556677885f5f5f5f5f5f	32	intel	bt dword ptr [ecx], edx
+0fa311|223344556677885f5f5f5f5f5f	32	plan9	BTL DX, 0(CX)
+0fa311|223344556677885f5f5f5f5f5f	64	gnu	bt %edx,(%rcx)
+0fa311|223344556677885f5f5f5f5f5f	64	intel	bt dword ptr [rcx], edx
+0fa311|223344556677885f5f5f5f5f5f	64	plan9	BTL DX, 0(CX)
+0fa41122|3344556677885f5f5f5f5f5f	32	intel	shld dword ptr [ecx], edx, 0x22
+0fa41122|3344556677885f5f5f5f5f5f	32	plan9	SHLDL $0x22, DX, 0(CX)
+0fa41122|3344556677885f5f5f5f5f5f	64	gnu	shld $0x22,%edx,(%rcx)
+0fa41122|3344556677885f5f5f5f5f5f	64	intel	shld dword ptr [rcx], edx, 0x22
+0fa41122|3344556677885f5f5f5f5f5f	64	plan9	SHLDL $0x22, DX, 0(CX)
+0fa511|223344556677885f5f5f5f5f5f	32	intel	shld dword ptr [ecx], edx, cl
+0fa511|223344556677885f5f5f5f5f5f	32	plan9	SHLDL CL, DX, 0(CX)
+0fa511|223344556677885f5f5f5f5f5f	64	gnu	shld %cl,%edx,(%rcx)
+0fa511|223344556677885f5f5f5f5f5f	64	intel	shld dword ptr [rcx], edx, cl
+0fa511|223344556677885f5f5f5f5f5f	64	plan9	SHLDL CL, DX, 0(CX)
+0fa8|11223344556677885f5f5f5f5f5f	32	intel	push gs
+0fa8|11223344556677885f5f5f5f5f5f	32	plan9	PUSHL GS
+0fa8|11223344556677885f5f5f5f5f5f	64	gnu	pushq %gs
+0fa8|11223344556677885f5f5f5f5f5f	64	intel	push gs
+0fa8|11223344556677885f5f5f5f5f5f	64	plan9	PUSHL GS
+0fa9|11223344556677885f5f5f5f5f5f	32	intel	pop gs
+0fa9|11223344556677885f5f5f5f5f5f	32	plan9	POPL GS
+0fa9|11223344556677885f5f5f5f5f5f	64	gnu	popq %gs
+0fa9|11223344556677885f5f5f5f5f5f	64	intel	pop gs
+0fa9|11223344556677885f5f5f5f5f5f	64	plan9	POPL GS
+0faa|11223344556677885f5f5f5f5f5f	32	intel	rsm
+0faa|11223344556677885f5f5f5f5f5f	32	plan9	RSM
+0faa|11223344556677885f5f5f5f5f5f	64	gnu	rsm
+0faa|11223344556677885f5f5f5f5f5f	64	intel	rsm
+0faa|11223344556677885f5f5f5f5f5f	64	plan9	RSM
+0fab11|223344556677885f5f5f5f5f5f	32	intel	bts dword ptr [ecx], edx
+0fab11|223344556677885f5f5f5f5f5f	32	plan9	BTSL DX, 0(CX)
+0fab11|223344556677885f5f5f5f5f5f	64	gnu	bts %edx,(%rcx)
+0fab11|223344556677885f5f5f5f5f5f	64	intel	bts dword ptr [rcx], edx
+0fab11|223344556677885f5f5f5f5f5f	64	plan9	BTSL DX, 0(CX)
+0fac1122|3344556677885f5f5f5f5f5f	32	intel	shrd dword ptr [ecx], edx, 0x22
+0fac1122|3344556677885f5f5f5f5f5f	32	plan9	SHRDL $0x22, DX, 0(CX)
+0fac1122|3344556677885f5f5f5f5f5f	64	gnu	shrd $0x22,%edx,(%rcx)
+0fac1122|3344556677885f5f5f5f5f5f	64	intel	shrd dword ptr [rcx], edx, 0x22
+0fac1122|3344556677885f5f5f5f5f5f	64	plan9	SHRDL $0x22, DX, 0(CX)
+0fad11|223344556677885f5f5f5f5f5f	32	intel	shrd dword ptr [ecx], edx, cl
+0fad11|223344556677885f5f5f5f5f5f	32	plan9	SHRDL CL, DX, 0(CX)
+0fad11|223344556677885f5f5f5f5f5f	64	gnu	shrd %cl,%edx,(%rcx)
+0fad11|223344556677885f5f5f5f5f5f	64	intel	shrd dword ptr [rcx], edx, cl
+0fad11|223344556677885f5f5f5f5f5f	64	plan9	SHRDL CL, DX, 0(CX)
+0fae00|11223344556677885f5f5f5f5f	32	intel	fxsave ptr [eax]
+0fae00|11223344556677885f5f5f5f5f	32	plan9	FXSAVE 0(AX)
+0fae00|11223344556677885f5f5f5f5f	64	gnu	fxsave (%rax)
+0fae00|11223344556677885f5f5f5f5f	64	intel	fxsave ptr [rax]
+0fae00|11223344556677885f5f5f5f5f	64	plan9	FXSAVE 0(AX)
+0fae08|11223344556677885f5f5f5f5f	32	intel	fxrstor ptr [eax]
+0fae08|11223344556677885f5f5f5f5f	32	plan9	FXRSTOR 0(AX)
+0fae08|11223344556677885f5f5f5f5f	64	gnu	fxrstor (%rax)
+0fae08|11223344556677885f5f5f5f5f	64	intel	fxrstor ptr [rax]
+0fae08|11223344556677885f5f5f5f5f	64	plan9	FXRSTOR 0(AX)
+0fae11|223344556677885f5f5f5f5f5f	32	intel	ldmxcsr dword ptr [ecx]
+0fae11|223344556677885f5f5f5f5f5f	32	plan9	LDMXCSR 0(CX)
+0fae11|223344556677885f5f5f5f5f5f	64	gnu	ldmxcsr (%rcx)
+0fae11|223344556677885f5f5f5f5f5f	64	intel	ldmxcsr dword ptr [rcx]
+0fae11|223344556677885f5f5f5f5f5f	64	plan9	LDMXCSR 0(CX)
+0fae18|11223344556677885f5f5f5f5f	32	intel	stmxcsr dword ptr [eax]
+0fae18|11223344556677885f5f5f5f5f	32	plan9	STMXCSR 0(AX)
+0fae18|11223344556677885f5f5f5f5f	64	gnu	stmxcsr (%rax)
+0fae18|11223344556677885f5f5f5f5f	64	intel	stmxcsr dword ptr [rax]
+0fae18|11223344556677885f5f5f5f5f	64	plan9	STMXCSR 0(AX)
+0fae20|11223344556677885f5f5f5f5f	32	intel	xsave ptr [eax]
+0fae20|11223344556677885f5f5f5f5f	32	plan9	XSAVE 0(AX)
+0fae20|11223344556677885f5f5f5f5f	64	gnu	xsave (%rax)
+0fae20|11223344556677885f5f5f5f5f	64	intel	xsave ptr [rax]
+0fae20|11223344556677885f5f5f5f5f	64	plan9	XSAVE 0(AX)
+0fae28|11223344556677885f5f5f5f5f	32	intel	xrstor ptr [eax]
+0fae28|11223344556677885f5f5f5f5f	32	plan9	XRSTOR 0(AX)
+0fae28|11223344556677885f5f5f5f5f	64	gnu	xrstor (%rax)
+0fae28|11223344556677885f5f5f5f5f	64	intel	xrstor ptr [rax]
+0fae28|11223344556677885f5f5f5f5f	64	plan9	XRSTOR 0(AX)
+0fae30|11223344556677885f5f5f5f5f	32	intel	xsaveopt ptr [eax]
+0fae30|11223344556677885f5f5f5f5f	32	plan9	XSAVEOPT 0(AX)
+0fae30|11223344556677885f5f5f5f5f	64	gnu	xsaveopt (%rax)
+0fae30|11223344556677885f5f5f5f5f	64	intel	xsaveopt ptr [rax]
+0fae30|11223344556677885f5f5f5f5f	64	plan9	XSAVEOPT 0(AX)
+0fae38|11223344556677885f5f5f5f5f	32	intel	clflush zmmword ptr [eax]
+0fae38|11223344556677885f5f5f5f5f	32	plan9	CLFLUSH 0(AX)
+0fae38|11223344556677885f5f5f5f5f	64	gnu	clflush (%rax)
+0fae38|11223344556677885f5f5f5f5f	64	intel	clflush zmmword ptr [rax]
+0fae38|11223344556677885f5f5f5f5f	64	plan9	CLFLUSH 0(AX)
+0faee8|11223344556677885f5f5f5f5f	32	intel	lfence
+0faee8|11223344556677885f5f5f5f5f	32	plan9	LFENCE
+0faee8|11223344556677885f5f5f5f5f	64	gnu	lfence
+0faee8|11223344556677885f5f5f5f5f	64	intel	lfence
+0faee8|11223344556677885f5f5f5f5f	64	plan9	LFENCE
+0faef0|11223344556677885f5f5f5f5f	32	intel	mfence
+0faef0|11223344556677885f5f5f5f5f	32	plan9	MFENCE
+0faef0|11223344556677885f5f5f5f5f	64	gnu	mfence
+0faef0|11223344556677885f5f5f5f5f	64	intel	mfence
+0faef0|11223344556677885f5f5f5f5f	64	plan9	MFENCE
+0faef8|11223344556677885f5f5f5f5f	32	intel	sfence
+0faef8|11223344556677885f5f5f5f5f	32	plan9	SFENCE
+0faef8|11223344556677885f5f5f5f5f	64	gnu	sfence
+0faef8|11223344556677885f5f5f5f5f	64	intel	sfence
+0faef8|11223344556677885f5f5f5f5f	64	plan9	SFENCE
+0faf11|223344556677885f5f5f5f5f5f	32	intel	imul edx, dword ptr [ecx]
+0faf11|223344556677885f5f5f5f5f5f	32	plan9	IMULL 0(CX), DX
+0faf11|223344556677885f5f5f5f5f5f	64	gnu	imul (%rcx),%edx
+0faf11|223344556677885f5f5f5f5f5f	64	intel	imul edx, dword ptr [rcx]
+0faf11|223344556677885f5f5f5f5f5f	64	plan9	IMULL 0(CX), DX
+0fb011|223344556677885f5f5f5f5f5f	32	intel	cmpxchg byte ptr [ecx], dl
+0fb011|223344556677885f5f5f5f5f5f	32	plan9	CMPXCHGB DL, 0(CX)
+0fb011|223344556677885f5f5f5f5f5f	64	gnu	cmpxchg %dl,(%rcx)
+0fb011|223344556677885f5f5f5f5f5f	64	intel	cmpxchg byte ptr [rcx], dl
+0fb011|223344556677885f5f5f5f5f5f	64	plan9	CMPXCHGB DL, 0(CX)
+0fb111|223344556677885f5f5f5f5f5f	32	intel	cmpxchg dword ptr [ecx], edx
+0fb111|223344556677885f5f5f5f5f5f	32	plan9	CMPXCHGL DX, 0(CX)
+0fb111|223344556677885f5f5f5f5f5f	64	gnu	cmpxchg %edx,(%rcx)
+0fb111|223344556677885f5f5f5f5f5f	64	intel	cmpxchg dword ptr [rcx], edx
+0fb111|223344556677885f5f5f5f5f5f	64	plan9	CMPXCHGL DX, 0(CX)
+0fb211|223344556677885f5f5f5f5f5f	32	intel	lss edx, ptr [ecx]
+0fb211|223344556677885f5f5f5f5f5f	32	plan9	LSS 0(CX), DX
+0fb211|223344556677885f5f5f5f5f5f	64	gnu	lss (%rcx),%edx
+0fb211|223344556677885f5f5f5f5f5f	64	intel	lss edx, ptr [rcx]
+0fb211|223344556677885f5f5f5f5f5f	64	plan9	LSS 0(CX), DX
+0fb311|223344556677885f5f5f5f5f5f	32	intel	btr dword ptr [ecx], edx
+0fb311|223344556677885f5f5f5f5f5f	32	plan9	BTRL DX, 0(CX)
+0fb311|223344556677885f5f5f5f5f5f	64	gnu	btr %edx,(%rcx)
+0fb311|223344556677885f5f5f5f5f5f	64	intel	btr dword ptr [rcx], edx
+0fb311|223344556677885f5f5f5f5f5f	64	plan9	BTRL DX, 0(CX)
+0fb411|223344556677885f5f5f5f5f5f	32	intel	lfs edx, ptr [ecx]
+0fb411|223344556677885f5f5f5f5f5f	32	plan9	LFS 0(CX), DX
+0fb411|223344556677885f5f5f5f5f5f	64	gnu	lfs (%rcx),%edx
+0fb411|223344556677885f5f5f5f5f5f	64	intel	lfs edx, ptr [rcx]
+0fb411|223344556677885f5f5f5f5f5f	64	plan9	LFS 0(CX), DX
+0fb511|223344556677885f5f5f5f5f5f	32	intel	lgs edx, ptr [ecx]
+0fb511|223344556677885f5f5f5f5f5f	32	plan9	LGS 0(CX), DX
+0fb511|223344556677885f5f5f5f5f5f	64	gnu	lgs (%rcx),%edx
+0fb511|223344556677885f5f5f5f5f5f	64	intel	lgs edx, ptr [rcx]
+0fb511|223344556677885f5f5f5f5f5f	64	plan9	LGS 0(CX), DX
+0fb611|223344556677885f5f5f5f5f5f	32	intel	movzx edx, byte ptr [ecx]
+0fb611|223344556677885f5f5f5f5f5f	32	plan9	MOVZX 0(CX), DX
+0fb611|223344556677885f5f5f5f5f5f	64	gnu	movzbl (%rcx),%edx
+0fb611|223344556677885f5f5f5f5f5f	64	intel	movzx edx, byte ptr [rcx]
+0fb611|223344556677885f5f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
+0fb711|223344556677885f5f5f5f5f5f	32	intel	movzx edx, word ptr [ecx]
+0fb711|223344556677885f5f5f5f5f5f	32	plan9	MOVZX 0(CX), DX
+0fb711|223344556677885f5f5f5f5f5f	64	gnu	movzwl (%rcx),%edx
+0fb711|223344556677885f5f5f5f5f5f	64	intel	movzx edx, word ptr [rcx]
+0fb711|223344556677885f5f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
+0fb8|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0fb8|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0fb8|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0fb8|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0fb8|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0fb9|11223344556677885f5f5f5f5f5f	32	intel	ud1
+0fb9|11223344556677885f5f5f5f5f5f	32	plan9	UD1
+0fb9|11223344556677885f5f5f5f5f5f	64	gnu	ud1
+0fb9|11223344556677885f5f5f5f5f5f	64	intel	ud1
+0fb9|11223344556677885f5f5f5f5f5f	64	plan9	UD1
+0fba11|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0fba11|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0fba11|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0fba11|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0fba11|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0fba2011|223344556677885f5f5f5f5f	32	intel	bt dword ptr [eax], 0x11
+0fba2011|223344556677885f5f5f5f5f	32	plan9	BTL $0x11, 0(AX)
+0fba2011|223344556677885f5f5f5f5f	64	gnu	btl $0x11,(%rax)
+0fba2011|223344556677885f5f5f5f5f	64	intel	bt dword ptr [rax], 0x11
+0fba2011|223344556677885f5f5f5f5f	64	plan9	BTL $0x11, 0(AX)
+0fba2811|223344556677885f5f5f5f5f	32	intel	bts dword ptr [eax], 0x11
+0fba2811|223344556677885f5f5f5f5f	32	plan9	BTSL $0x11, 0(AX)
+0fba2811|223344556677885f5f5f5f5f	64	gnu	btsl $0x11,(%rax)
+0fba2811|223344556677885f5f5f5f5f	64	intel	bts dword ptr [rax], 0x11
+0fba2811|223344556677885f5f5f5f5f	64	plan9	BTSL $0x11, 0(AX)
+0fba3011|223344556677885f5f5f5f5f	32	intel	btr dword ptr [eax], 0x11
+0fba3011|223344556677885f5f5f5f5f	32	plan9	BTRL $0x11, 0(AX)
+0fba3011|223344556677885f5f5f5f5f	64	gnu	btrl $0x11,(%rax)
+0fba3011|223344556677885f5f5f5f5f	64	intel	btr dword ptr [rax], 0x11
+0fba3011|223344556677885f5f5f5f5f	64	plan9	BTRL $0x11, 0(AX)
+0fba3811|223344556677885f5f5f5f5f	32	intel	btc dword ptr [eax], 0x11
+0fba3811|223344556677885f5f5f5f5f	32	plan9	BTCL $0x11, 0(AX)
+0fba3811|223344556677885f5f5f5f5f	64	gnu	btcl $0x11,(%rax)
+0fba3811|223344556677885f5f5f5f5f	64	intel	btc dword ptr [rax], 0x11
+0fba3811|223344556677885f5f5f5f5f	64	plan9	BTCL $0x11, 0(AX)
+0fbb11|223344556677885f5f5f5f5f5f	32	intel	btc dword ptr [ecx], edx
+0fbb11|223344556677885f5f5f5f5f5f	32	plan9	BTCL DX, 0(CX)
+0fbb11|223344556677885f5f5f5f5f5f	64	gnu	btc %edx,(%rcx)
+0fbb11|223344556677885f5f5f5f5f5f	64	intel	btc dword ptr [rcx], edx
+0fbb11|223344556677885f5f5f5f5f5f	64	plan9	BTCL DX, 0(CX)
+0fbc11|223344556677885f5f5f5f5f5f	32	intel	bsf edx, dword ptr [ecx]
+0fbc11|223344556677885f5f5f5f5f5f	32	plan9	BSFL 0(CX), DX
+0fbc11|223344556677885f5f5f5f5f5f	64	gnu	bsf (%rcx),%edx
+0fbc11|223344556677885f5f5f5f5f5f	64	intel	bsf edx, dword ptr [rcx]
+0fbc11|223344556677885f5f5f5f5f5f	64	plan9	BSFL 0(CX), DX
+0fbd11|223344556677885f5f5f5f5f5f	32	intel	bsr edx, dword ptr [ecx]
+0fbd11|223344556677885f5f5f5f5f5f	32	plan9	BSRL 0(CX), DX
+0fbd11|223344556677885f5f5f5f5f5f	64	gnu	bsr (%rcx),%edx
+0fbd11|223344556677885f5f5f5f5f5f	64	intel	bsr edx, dword ptr [rcx]
+0fbd11|223344556677885f5f5f5f5f5f	64	plan9	BSRL 0(CX), DX
+0fbe11|223344556677885f5f5f5f5f5f	32	intel	movsx edx, byte ptr [ecx]
+0fbe11|223344556677885f5f5f5f5f5f	32	plan9	MOVSX 0(CX), DX
+0fbe11|223344556677885f5f5f5f5f5f	64	gnu	movsbl (%rcx),%edx
+0fbe11|223344556677885f5f5f5f5f5f	64	intel	movsx edx, byte ptr [rcx]
+0fbe11|223344556677885f5f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
+0fbf11|223344556677885f5f5f5f5f5f	32	intel	movsx edx, word ptr [ecx]
+0fbf11|223344556677885f5f5f5f5f5f	32	plan9	MOVSX 0(CX), DX
+0fbf11|223344556677885f5f5f5f5f5f	64	gnu	movswl (%rcx),%edx
+0fbf11|223344556677885f5f5f5f5f5f	64	intel	movsx edx, word ptr [rcx]
+0fbf11|223344556677885f5f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
+0fc011|223344556677885f5f5f5f5f5f	32	intel	xadd byte ptr [ecx], dl
+0fc011|223344556677885f5f5f5f5f5f	32	plan9	XADDB DL, 0(CX)
+0fc011|223344556677885f5f5f5f5f5f	64	gnu	xadd %dl,(%rcx)
+0fc011|223344556677885f5f5f5f5f5f	64	intel	xadd byte ptr [rcx], dl
+0fc011|223344556677885f5f5f5f5f5f	64	plan9	XADDB DL, 0(CX)
+0fc111|223344556677885f5f5f5f5f5f	32	intel	xadd dword ptr [ecx], edx
+0fc111|223344556677885f5f5f5f5f5f	32	plan9	XADDL DX, 0(CX)
+0fc111|223344556677885f5f5f5f5f5f	64	gnu	xadd %edx,(%rcx)
+0fc111|223344556677885f5f5f5f5f5f	64	intel	xadd dword ptr [rcx], edx
+0fc111|223344556677885f5f5f5f5f5f	64	plan9	XADDL DX, 0(CX)
+0fc20000|11223344556677885f5f5f5f	32	intel	cmpps xmm0, xmmword ptr [eax], 0x0
+0fc20000|11223344556677885f5f5f5f	32	plan9	CMPPS $0x0, 0(AX), X0
+0fc20000|11223344556677885f5f5f5f	64	gnu	cmpeqps (%rax),%xmm0
+0fc20000|11223344556677885f5f5f5f	64	intel	cmpps xmm0, xmmword ptr [rax], 0x0
+0fc20000|11223344556677885f5f5f5f	64	plan9	CMPPS $0x0, 0(AX), X0
+0fc311|223344556677885f5f5f5f5f5f	32	intel	movnti dword ptr [ecx], edx
+0fc311|223344556677885f5f5f5f5f5f	32	plan9	MOVNTIL DX, 0(CX)
+0fc311|223344556677885f5f5f5f5f5f	64	gnu	movnti %edx,(%rcx)
+0fc311|223344556677885f5f5f5f5f5f	64	intel	movnti dword ptr [rcx], edx
+0fc311|223344556677885f5f5f5f5f5f	64	plan9	MOVNTIL DX, 0(CX)
+0fc41122|3344556677885f5f5f5f5f5f	32	intel	pinsrw mmx2, word ptr [ecx], 0x22
+0fc41122|3344556677885f5f5f5f5f5f	32	plan9	PINSRW $0x22, 0(CX), M2
+0fc41122|3344556677885f5f5f5f5f5f	64	gnu	pinsrw $0x22,(%rcx),%mm2
+0fc41122|3344556677885f5f5f5f5f5f	64	intel	pinsrw mmx2, word ptr [rcx], 0x22
+0fc41122|3344556677885f5f5f5f5f5f	64	plan9	PINSRW $0x22, 0(CX), M2
+0fc51122|3344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0fc51122|3344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0fc51122|3344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0fc51122|3344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0fc51122|3344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0fc5c011|223344556677885f5f5f5f5f	32	intel	pextrw eax, mmx0, 0x11
+0fc5c011|223344556677885f5f5f5f5f	32	plan9	PEXTRW $0x11, M0, AX
+0fc5c011|223344556677885f5f5f5f5f	64	gnu	pextrw $0x11,%mm0,%eax
+0fc5c011|223344556677885f5f5f5f5f	64	intel	pextrw eax, mmx0, 0x11
+0fc5c011|223344556677885f5f5f5f5f	64	plan9	PEXTRW $0x11, M0, AX
+0fc61122|3344556677885f5f5f5f5f5f	32	intel	shufps xmm2, xmmword ptr [ecx], 0x22
+0fc61122|3344556677885f5f5f5f5f5f	32	plan9	SHUFPS $0x22, 0(CX), X2
+0fc61122|3344556677885f5f5f5f5f5f	64	gnu	shufps $0x22,(%rcx),%xmm2
+0fc61122|3344556677885f5f5f5f5f5f	64	intel	shufps xmm2, xmmword ptr [rcx], 0x22
+0fc61122|3344556677885f5f5f5f5f5f	64	plan9	SHUFPS $0x22, 0(CX), X2
+0fc708|11223344556677885f5f5f5f5f	32	intel	cmpxchg8b qword ptr [eax]
+0fc708|11223344556677885f5f5f5f5f	32	plan9	CMPXCHG8B 0(AX)
+0fc708|11223344556677885f5f5f5f5f	64	gnu	cmpxchg8b (%rax)
+0fc708|11223344556677885f5f5f5f5f	64	intel	cmpxchg8b qword ptr [rax]
+0fc708|11223344556677885f5f5f5f5f	64	plan9	CMPXCHG8B 0(AX)
+0fc718|11223344556677885f5f5f5f5f	32	intel	xrstors ptr [eax]
+0fc718|11223344556677885f5f5f5f5f	32	plan9	XRSTORS 0(AX)
+0fc718|11223344556677885f5f5f5f5f	64	gnu	xrstors (%rax)
+0fc718|11223344556677885f5f5f5f5f	64	intel	xrstors ptr [rax]
+0fc718|11223344556677885f5f5f5f5f	64	plan9	XRSTORS 0(AX)
+0fc720|11223344556677885f5f5f5f5f	32	intel	xsavec ptr [eax]
+0fc720|11223344556677885f5f5f5f5f	32	plan9	XSAVEC 0(AX)
+0fc720|11223344556677885f5f5f5f5f	64	gnu	xsavec (%rax)
+0fc720|11223344556677885f5f5f5f5f	64	intel	xsavec ptr [rax]
+0fc720|11223344556677885f5f5f5f5f	64	plan9	XSAVEC 0(AX)
+0fc728|11223344556677885f5f5f5f5f	32	intel	xsaves ptr [eax]
+0fc728|11223344556677885f5f5f5f5f	32	plan9	XSAVES 0(AX)
+0fc728|11223344556677885f5f5f5f5f	64	gnu	xsaves (%rax)
+0fc728|11223344556677885f5f5f5f5f	64	intel	xsaves ptr [rax]
+0fc728|11223344556677885f5f5f5f5f	64	plan9	XSAVES 0(AX)
+0fc730|11223344556677885f5f5f5f5f	32	intel	error: unrecognized instruction
+0fc730|11223344556677885f5f5f5f5f	32	plan9	error: unrecognized instruction
+0fc730|11223344556677885f5f5f5f5f	64	gnu	error: unrecognized instruction
+0fc730|11223344556677885f5f5f5f5f	64	intel	error: unrecognized instruction
+0fc730|11223344556677885f5f5f5f5f	64	plan9	error: unrecognized instruction
+0fc7f0|11223344556677885f5f5f5f5f	32	intel	rdrand eax
+0fc7f0|11223344556677885f5f5f5f5f	32	plan9	RDRAND AX
+0fc7f0|11223344556677885f5f5f5f5f	64	gnu	rdrand %eax
+0fc7f0|11223344556677885f5f5f5f5f	64	intel	rdrand eax
+0fc7f0|11223344556677885f5f5f5f5f	64	plan9	RDRAND AX
+0fc8|11223344556677885f5f5f5f5f5f	32	intel	bswap eax
+0fc8|11223344556677885f5f5f5f5f5f	32	plan9	BSWAP AX
+0fc8|11223344556677885f5f5f5f5f5f	64	gnu	bswap %eax
+0fc8|11223344556677885f5f5f5f5f5f	64	intel	bswap eax
+0fc8|11223344556677885f5f5f5f5f5f	64	plan9	BSWAP AX
+0fd0|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0fd0|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0fd0|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0fd0|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0fd0|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0fd111|223344556677885f5f5f5f5f5f	32	intel	psrlw mmx2, qword ptr [ecx]
+0fd111|223344556677885f5f5f5f5f5f	32	plan9	PSRLW 0(CX), M2
+0fd111|223344556677885f5f5f5f5f5f	64	gnu	psrlw (%rcx),%mm2
+0fd111|223344556677885f5f5f5f5f5f	64	intel	psrlw mmx2, qword ptr [rcx]
+0fd111|223344556677885f5f5f5f5f5f	64	plan9	PSRLW 0(CX), M2
+0fd211|223344556677885f5f5f5f5f5f	32	intel	psrld mmx2, qword ptr [ecx]
+0fd211|223344556677885f5f5f5f5f5f	32	plan9	PSRLD 0(CX), M2
+0fd211|223344556677885f5f5f5f5f5f	64	gnu	psrld (%rcx),%mm2
+0fd211|223344556677885f5f5f5f5f5f	64	intel	psrld mmx2, qword ptr [rcx]
+0fd211|223344556677885f5f5f5f5f5f	64	plan9	PSRLD 0(CX), M2
+0fd311|223344556677885f5f5f5f5f5f	32	intel	psrlq mmx2, qword ptr [ecx]
+0fd311|223344556677885f5f5f5f5f5f	32	plan9	PSRLQ 0(CX), M2
+0fd311|223344556677885f5f5f5f5f5f	64	gnu	psrlq (%rcx),%mm2
+0fd311|223344556677885f5f5f5f5f5f	64	intel	psrlq mmx2, qword ptr [rcx]
+0fd311|223344556677885f5f5f5f5f5f	64	plan9	PSRLQ 0(CX), M2
+0fd411|223344556677885f5f5f5f5f5f	32	intel	paddq mmx2, qword ptr [ecx]
+0fd411|223344556677885f5f5f5f5f5f	32	plan9	PADDQ 0(CX), M2
+0fd411|223344556677885f5f5f5f5f5f	64	gnu	paddq (%rcx),%mm2
+0fd411|223344556677885f5f5f5f5f5f	64	intel	paddq mmx2, qword ptr [rcx]
+0fd411|223344556677885f5f5f5f5f5f	64	plan9	PADDQ 0(CX), M2
+0fd511|223344556677885f5f5f5f5f5f	32	intel	pmullw mmx2, qword ptr [ecx]
+0fd511|223344556677885f5f5f5f5f5f	32	plan9	PMULLW 0(CX), M2
+0fd511|223344556677885f5f5f5f5f5f	64	gnu	pmullw (%rcx),%mm2
+0fd511|223344556677885f5f5f5f5f5f	64	intel	pmullw mmx2, qword ptr [rcx]
+0fd511|223344556677885f5f5f5f5f5f	64	plan9	PMULLW 0(CX), M2
+0fd6|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0fd6|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0fd6|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0fd6|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0fd6|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0fd711|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0fd711|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0fd711|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0fd711|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0fd711|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0fd7c0|11223344556677885f5f5f5f5f	32	intel	pmovmskb eax, mmx0
+0fd7c0|11223344556677885f5f5f5f5f	32	plan9	PMOVMSKB M0, AX
+0fd7c0|11223344556677885f5f5f5f5f	64	gnu	pmovmskb %mm0,%eax
+0fd7c0|11223344556677885f5f5f5f5f	64	intel	pmovmskb eax, mmx0
+0fd7c0|11223344556677885f5f5f5f5f	64	plan9	PMOVMSKB M0, AX
+0fd811|223344556677885f5f5f5f5f5f	32	intel	psubusb mmx2, qword ptr [ecx]
+0fd811|223344556677885f5f5f5f5f5f	32	plan9	PSUBUSB 0(CX), M2
+0fd811|223344556677885f5f5f5f5f5f	64	gnu	psubusb (%rcx),%mm2
+0fd811|223344556677885f5f5f5f5f5f	64	intel	psubusb mmx2, qword ptr [rcx]
+0fd811|223344556677885f5f5f5f5f5f	64	plan9	PSUBUSB 0(CX), M2
+0fd911|223344556677885f5f5f5f5f5f	32	intel	psubusw mmx2, qword ptr [ecx]
+0fd911|223344556677885f5f5f5f5f5f	32	plan9	PSUBUSW 0(CX), M2
+0fd911|223344556677885f5f5f5f5f5f	64	gnu	psubusw (%rcx),%mm2
+0fd911|223344556677885f5f5f5f5f5f	64	intel	psubusw mmx2, qword ptr [rcx]
+0fd911|223344556677885f5f5f5f5f5f	64	plan9	PSUBUSW 0(CX), M2
+0fda11|223344556677885f5f5f5f5f5f	32	intel	pminub mmx2, qword ptr [ecx]
+0fda11|223344556677885f5f5f5f5f5f	32	plan9	PMINUB 0(CX), M2
+0fda11|223344556677885f5f5f5f5f5f	64	gnu	pminub (%rcx),%mm2
+0fda11|223344556677885f5f5f5f5f5f	64	intel	pminub mmx2, qword ptr [rcx]
+0fda11|223344556677885f5f5f5f5f5f	64	plan9	PMINUB 0(CX), M2
+0fdb11|223344556677885f5f5f5f5f5f	32	intel	pand mmx2, qword ptr [ecx]
+0fdb11|223344556677885f5f5f5f5f5f	32	plan9	PAND 0(CX), M2
+0fdb11|223344556677885f5f5f5f5f5f	64	gnu	pand (%rcx),%mm2
+0fdb11|223344556677885f5f5f5f5f5f	64	intel	pand mmx2, qword ptr [rcx]
+0fdb11|223344556677885f5f5f5f5f5f	64	plan9	PAND 0(CX), M2
+0fdc11|223344556677885f5f5f5f5f5f	32	intel	paddusb mmx2, qword ptr [ecx]
+0fdc11|223344556677885f5f5f5f5f5f	32	plan9	PADDUSB 0(CX), M2
+0fdc11|223344556677885f5f5f5f5f5f	64	gnu	paddusb (%rcx),%mm2
+0fdc11|223344556677885f5f5f5f5f5f	64	intel	paddusb mmx2, qword ptr [rcx]
+0fdc11|223344556677885f5f5f5f5f5f	64	plan9	PADDUSB 0(CX), M2
+0fdd11|223344556677885f5f5f5f5f5f	32	intel	paddusw mmx2, qword ptr [ecx]
+0fdd11|223344556677885f5f5f5f5f5f	32	plan9	PADDUSW 0(CX), M2
+0fdd11|223344556677885f5f5f5f5f5f	64	gnu	paddusw (%rcx),%mm2
+0fdd11|223344556677885f5f5f5f5f5f	64	intel	paddusw mmx2, qword ptr [rcx]
+0fdd11|223344556677885f5f5f5f5f5f	64	plan9	PADDUSW 0(CX), M2
+0fde11|223344556677885f5f5f5f5f5f	32	intel	pmaxub mmx2, qword ptr [ecx]
+0fde11|223344556677885f5f5f5f5f5f	32	plan9	PMAXUB 0(CX), M2
+0fde11|223344556677885f5f5f5f5f5f	64	gnu	pmaxub (%rcx),%mm2
+0fde11|223344556677885f5f5f5f5f5f	64	intel	pmaxub mmx2, qword ptr [rcx]
+0fde11|223344556677885f5f5f5f5f5f	64	plan9	PMAXUB 0(CX), M2
+0fdf11|223344556677885f5f5f5f5f5f	32	intel	pandn mmx2, qword ptr [ecx]
+0fdf11|223344556677885f5f5f5f5f5f	32	plan9	PANDN 0(CX), M2
+0fdf11|223344556677885f5f5f5f5f5f	64	gnu	pandn (%rcx),%mm2
+0fdf11|223344556677885f5f5f5f5f5f	64	intel	pandn mmx2, qword ptr [rcx]
+0fdf11|223344556677885f5f5f5f5f5f	64	plan9	PANDN 0(CX), M2
+0fe011|223344556677885f5f5f5f5f5f	32	intel	pavgb mmx2, qword ptr [ecx]
+0fe011|223344556677885f5f5f5f5f5f	32	plan9	PAVGB 0(CX), M2
+0fe011|223344556677885f5f5f5f5f5f	64	gnu	pavgb (%rcx),%mm2
+0fe011|223344556677885f5f5f5f5f5f	64	intel	pavgb mmx2, qword ptr [rcx]
+0fe011|223344556677885f5f5f5f5f5f	64	plan9	PAVGB 0(CX), M2
+0fe111|223344556677885f5f5f5f5f5f	32	intel	psraw mmx2, qword ptr [ecx]
+0fe111|223344556677885f5f5f5f5f5f	32	plan9	PSRAW 0(CX), M2
+0fe111|223344556677885f5f5f5f5f5f	64	gnu	psraw (%rcx),%mm2
+0fe111|223344556677885f5f5f5f5f5f	64	intel	psraw mmx2, qword ptr [rcx]
+0fe111|223344556677885f5f5f5f5f5f	64	plan9	PSRAW 0(CX), M2
+0fe211|223344556677885f5f5f5f5f5f	32	intel	psrad mmx2, qword ptr [ecx]
+0fe211|223344556677885f5f5f5f5f5f	32	plan9	PSRAD 0(CX), M2
+0fe211|223344556677885f5f5f5f5f5f	64	gnu	psrad (%rcx),%mm2
+0fe211|223344556677885f5f5f5f5f5f	64	intel	psrad mmx2, qword ptr [rcx]
+0fe211|223344556677885f5f5f5f5f5f	64	plan9	PSRAD 0(CX), M2
+0fe311|223344556677885f5f5f5f5f5f	32	intel	pavgw mmx2, qword ptr [ecx]
+0fe311|223344556677885f5f5f5f5f5f	32	plan9	PAVGW 0(CX), M2
+0fe311|223344556677885f5f5f5f5f5f	64	gnu	pavgw (%rcx),%mm2
+0fe311|223344556677885f5f5f5f5f5f	64	intel	pavgw mmx2, qword ptr [rcx]
+0fe311|223344556677885f5f5f5f5f5f	64	plan9	PAVGW 0(CX), M2
+0fe411|223344556677885f5f5f5f5f5f	32	intel	pmulhuw mmx2, qword ptr [ecx]
+0fe411|223344556677885f5f5f5f5f5f	32	plan9	PMULHUW 0(CX), M2
+0fe411|223344556677885f5f5f5f5f5f	64	gnu	pmulhuw (%rcx),%mm2
+0fe411|223344556677885f5f5f5f5f5f	64	intel	pmulhuw mmx2, qword ptr [rcx]
+0fe411|223344556677885f5f5f5f5f5f	64	plan9	PMULHUW 0(CX), M2
+0fe511|223344556677885f5f5f5f5f5f	32	intel	pmulhw mmx2, qword ptr [ecx]
+0fe511|223344556677885f5f5f5f5f5f	32	plan9	PMULHW 0(CX), M2
+0fe511|223344556677885f5f5f5f5f5f	64	gnu	pmulhw (%rcx),%mm2
+0fe511|223344556677885f5f5f5f5f5f	64	intel	pmulhw mmx2, qword ptr [rcx]
+0fe511|223344556677885f5f5f5f5f5f	64	plan9	PMULHW 0(CX), M2
+0fe6|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0fe6|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0fe6|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0fe6|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0fe6|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0fe711|223344556677885f5f5f5f5f5f	32	intel	movntq qword ptr [ecx], mmx2
+0fe711|223344556677885f5f5f5f5f5f	32	plan9	MOVNTQ M2, 0(CX)
+0fe711|223344556677885f5f5f5f5f5f	64	gnu	movntq %mm2,(%rcx)
+0fe711|223344556677885f5f5f5f5f5f	64	intel	movntq qword ptr [rcx], mmx2
+0fe711|223344556677885f5f5f5f5f5f	64	plan9	MOVNTQ M2, 0(CX)
+0fe811|223344556677885f5f5f5f5f5f	32	intel	psubsb mmx2, qword ptr [ecx]
+0fe811|223344556677885f5f5f5f5f5f	32	plan9	PSUBSB 0(CX), M2
+0fe811|223344556677885f5f5f5f5f5f	64	gnu	psubsb (%rcx),%mm2
+0fe811|223344556677885f5f5f5f5f5f	64	intel	psubsb mmx2, qword ptr [rcx]
+0fe811|223344556677885f5f5f5f5f5f	64	plan9	PSUBSB 0(CX), M2
+0fe911|223344556677885f5f5f5f5f5f	32	intel	psubsw mmx2, qword ptr [ecx]
+0fe911|223344556677885f5f5f5f5f5f	32	plan9	PSUBSW 0(CX), M2
+0fe911|223344556677885f5f5f5f5f5f	64	gnu	psubsw (%rcx),%mm2
+0fe911|223344556677885f5f5f5f5f5f	64	intel	psubsw mmx2, qword ptr [rcx]
+0fe911|223344556677885f5f5f5f5f5f	64	plan9	PSUBSW 0(CX), M2
+0fea11|223344556677885f5f5f5f5f5f	32	intel	pminsw mmx2, qword ptr [ecx]
+0fea11|223344556677885f5f5f5f5f5f	32	plan9	PMINSW 0(CX), M2
+0fea11|223344556677885f5f5f5f5f5f	64	gnu	pminsw (%rcx),%mm2
+0fea11|223344556677885f5f5f5f5f5f	64	intel	pminsw mmx2, qword ptr [rcx]
+0fea11|223344556677885f5f5f5f5f5f	64	plan9	PMINSW 0(CX), M2
+0feb11|223344556677885f5f5f5f5f5f	32	intel	por mmx2, qword ptr [ecx]
+0feb11|223344556677885f5f5f5f5f5f	32	plan9	POR 0(CX), M2
+0feb11|223344556677885f5f5f5f5f5f	64	gnu	por (%rcx),%mm2
+0feb11|223344556677885f5f5f5f5f5f	64	intel	por mmx2, qword ptr [rcx]
+0feb11|223344556677885f5f5f5f5f5f	64	plan9	POR 0(CX), M2
+0fec11|223344556677885f5f5f5f5f5f	32	intel	paddsb mmx2, qword ptr [ecx]
+0fec11|223344556677885f5f5f5f5f5f	32	plan9	PADDSB 0(CX), M2
+0fec11|223344556677885f5f5f5f5f5f	64	gnu	paddsb (%rcx),%mm2
+0fec11|223344556677885f5f5f5f5f5f	64	intel	paddsb mmx2, qword ptr [rcx]
+0fec11|223344556677885f5f5f5f5f5f	64	plan9	PADDSB 0(CX), M2
+0fed11|223344556677885f5f5f5f5f5f	32	intel	paddsw mmx2, qword ptr [ecx]
+0fed11|223344556677885f5f5f5f5f5f	32	plan9	PADDSW 0(CX), M2
+0fed11|223344556677885f5f5f5f5f5f	64	gnu	paddsw (%rcx),%mm2
+0fed11|223344556677885f5f5f5f5f5f	64	intel	paddsw mmx2, qword ptr [rcx]
+0fed11|223344556677885f5f5f5f5f5f	64	plan9	PADDSW 0(CX), M2
+0fee11|223344556677885f5f5f5f5f5f	32	intel	pmaxsw mmx2, qword ptr [ecx]
+0fee11|223344556677885f5f5f5f5f5f	32	plan9	PMAXSW 0(CX), M2
+0fee11|223344556677885f5f5f5f5f5f	64	gnu	pmaxsw (%rcx),%mm2
+0fee11|223344556677885f5f5f5f5f5f	64	intel	pmaxsw mmx2, qword ptr [rcx]
+0fee11|223344556677885f5f5f5f5f5f	64	plan9	PMAXSW 0(CX), M2
+0fef11|223344556677885f5f5f5f5f5f	32	intel	pxor mmx2, qword ptr [ecx]
+0fef11|223344556677885f5f5f5f5f5f	32	plan9	PXOR 0(CX), M2
+0fef11|223344556677885f5f5f5f5f5f	64	gnu	pxor (%rcx),%mm2
+0fef11|223344556677885f5f5f5f5f5f	64	intel	pxor mmx2, qword ptr [rcx]
+0fef11|223344556677885f5f5f5f5f5f	64	plan9	PXOR 0(CX), M2
+0ff0|11223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0ff0|11223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0ff0|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0ff0|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0ff0|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0ff111|223344556677885f5f5f5f5f5f	32	intel	psllw mmx2, qword ptr [ecx]
+0ff111|223344556677885f5f5f5f5f5f	32	plan9	PSLLW 0(CX), M2
+0ff111|223344556677885f5f5f5f5f5f	64	gnu	psllw (%rcx),%mm2
+0ff111|223344556677885f5f5f5f5f5f	64	intel	psllw mmx2, qword ptr [rcx]
+0ff111|223344556677885f5f5f5f5f5f	64	plan9	PSLLW 0(CX), M2
+0ff211|223344556677885f5f5f5f5f5f	32	intel	pslld mmx2, qword ptr [ecx]
+0ff211|223344556677885f5f5f5f5f5f	32	plan9	PSLLD 0(CX), M2
+0ff211|223344556677885f5f5f5f5f5f	64	gnu	pslld (%rcx),%mm2
+0ff211|223344556677885f5f5f5f5f5f	64	intel	pslld mmx2, qword ptr [rcx]
+0ff211|223344556677885f5f5f5f5f5f	64	plan9	PSLLD 0(CX), M2
+0ff311|223344556677885f5f5f5f5f5f	32	intel	psllq mmx2, qword ptr [ecx]
+0ff311|223344556677885f5f5f5f5f5f	32	plan9	PSLLQ 0(CX), M2
+0ff311|223344556677885f5f5f5f5f5f	64	gnu	psllq (%rcx),%mm2
+0ff311|223344556677885f5f5f5f5f5f	64	intel	psllq mmx2, qword ptr [rcx]
+0ff311|223344556677885f5f5f5f5f5f	64	plan9	PSLLQ 0(CX), M2
+0ff411|223344556677885f5f5f5f5f5f	32	intel	pmuludq mmx2, qword ptr [ecx]
+0ff411|223344556677885f5f5f5f5f5f	32	plan9	PMULUDQ 0(CX), M2
+0ff411|223344556677885f5f5f5f5f5f	64	gnu	pmuludq (%rcx),%mm2
+0ff411|223344556677885f5f5f5f5f5f	64	intel	pmuludq mmx2, qword ptr [rcx]
+0ff411|223344556677885f5f5f5f5f5f	64	plan9	PMULUDQ 0(CX), M2
+0ff511|223344556677885f5f5f5f5f5f	32	intel	pmaddwd mmx2, qword ptr [ecx]
+0ff511|223344556677885f5f5f5f5f5f	32	plan9	PMADDWD 0(CX), M2
+0ff511|223344556677885f5f5f5f5f5f	64	gnu	pmaddwd (%rcx),%mm2
+0ff511|223344556677885f5f5f5f5f5f	64	intel	pmaddwd mmx2, qword ptr [rcx]
+0ff511|223344556677885f5f5f5f5f5f	64	plan9	PMADDWD 0(CX), M2
+0ff611|223344556677885f5f5f5f5f5f	32	intel	psadbw mmx2, qword ptr [ecx]
+0ff611|223344556677885f5f5f5f5f5f	32	plan9	PSADBW 0(CX), M2
+0ff611|223344556677885f5f5f5f5f5f	64	gnu	psadbw (%rcx),%mm2
+0ff611|223344556677885f5f5f5f5f5f	64	intel	psadbw mmx2, qword ptr [rcx]
+0ff611|223344556677885f5f5f5f5f5f	64	plan9	PSADBW 0(CX), M2
+0ff711|223344556677885f5f5f5f5f5f	32	intel	error: unrecognized instruction
+0ff711|223344556677885f5f5f5f5f5f	32	plan9	error: unrecognized instruction
+0ff711|223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+0ff711|223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+0ff711|223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+0ff7c0|11223344556677885f5f5f5f5f	32	intel	maskmovq mmx0, mmx0
+0ff7c0|11223344556677885f5f5f5f5f	32	plan9	MASKMOVQ M0, M0
+0ff7c0|11223344556677885f5f5f5f5f	64	gnu	maskmovq %mm0,%mm0
+0ff7c0|11223344556677885f5f5f5f5f	64	intel	maskmovq mmx0, mmx0
+0ff7c0|11223344556677885f5f5f5f5f	64	plan9	MASKMOVQ M0, M0
+0ff811|223344556677885f5f5f5f5f5f	32	intel	psubb mmx2, qword ptr [ecx]
+0ff811|223344556677885f5f5f5f5f5f	32	plan9	PSUBB 0(CX), M2
+0ff811|223344556677885f5f5f5f5f5f	64	gnu	psubb (%rcx),%mm2
+0ff811|223344556677885f5f5f5f5f5f	64	intel	psubb mmx2, qword ptr [rcx]
+0ff811|223344556677885f5f5f5f5f5f	64	plan9	PSUBB 0(CX), M2
+0ff911|223344556677885f5f5f5f5f5f	32	intel	psubw mmx2, qword ptr [ecx]
+0ff911|223344556677885f5f5f5f5f5f	32	plan9	PSUBW 0(CX), M2
+0ff911|223344556677885f5f5f5f5f5f	64	gnu	psubw (%rcx),%mm2
+0ff911|223344556677885f5f5f5f5f5f	64	intel	psubw mmx2, qword ptr [rcx]
+0ff911|223344556677885f5f5f5f5f5f	64	plan9	PSUBW 0(CX), M2
+0ffa11|223344556677885f5f5f5f5f5f	32	intel	psubd mmx2, qword ptr [ecx]
+0ffa11|223344556677885f5f5f5f5f5f	32	plan9	PSUBD 0(CX), M2
+0ffa11|223344556677885f5f5f5f5f5f	64	gnu	psubd (%rcx),%mm2
+0ffa11|223344556677885f5f5f5f5f5f	64	intel	psubd mmx2, qword ptr [rcx]
+0ffa11|223344556677885f5f5f5f5f5f	64	plan9	PSUBD 0(CX), M2
+0ffb11|223344556677885f5f5f5f5f5f	32	intel	psubq mmx2, qword ptr [ecx]
+0ffb11|223344556677885f5f5f5f5f5f	32	plan9	PSUBQ 0(CX), M2
+0ffb11|223344556677885f5f5f5f5f5f	64	gnu	psubq (%rcx),%mm2
+0ffb11|223344556677885f5f5f5f5f5f	64	intel	psubq mmx2, qword ptr [rcx]
+0ffb11|223344556677885f5f5f5f5f5f	64	plan9	PSUBQ 0(CX), M2
+0ffc11|223344556677885f5f5f5f5f5f	32	intel	paddb mmx2, qword ptr [ecx]
+0ffc11|223344556677885f5f5f5f5f5f	32	plan9	PADDB 0(CX), M2
+0ffc11|223344556677885f5f5f5f5f5f	64	gnu	paddb (%rcx),%mm2
+0ffc11|223344556677885f5f5f5f5f5f	64	intel	paddb mmx2, qword ptr [rcx]
+0ffc11|223344556677885f5f5f5f5f5f	64	plan9	PADDB 0(CX), M2
+0ffd11|223344556677885f5f5f5f5f5f	32	intel	paddw mmx2, qword ptr [ecx]
+0ffd11|223344556677885f5f5f5f5f5f	32	plan9	PADDW 0(CX), M2
+0ffd11|223344556677885f5f5f5f5f5f	64	gnu	paddw (%rcx),%mm2
+0ffd11|223344556677885f5f5f5f5f5f	64	intel	paddw mmx2, qword ptr [rcx]
+0ffd11|223344556677885f5f5f5f5f5f	64	plan9	PADDW 0(CX), M2
+0ffe11|223344556677885f5f5f5f5f5f	32	intel	paddd mmx2, qword ptr [ecx]
+0ffe11|223344556677885f5f5f5f5f5f	32	plan9	PADDD 0(CX), M2
+0ffe11|223344556677885f5f5f5f5f5f	64	gnu	paddd (%rcx),%mm2
+0ffe11|223344556677885f5f5f5f5f5f	64	intel	paddd mmx2, qword ptr [rcx]
+0ffe11|223344556677885f5f5f5f5f5f	64	plan9	PADDD 0(CX), M2
+1011|223344556677885f5f5f5f5f5f5f	32	intel	adc byte ptr [ecx], dl
+1011|223344556677885f5f5f5f5f5f5f	32	plan9	ADCB DL, 0(CX)
+1011|223344556677885f5f5f5f5f5f5f	64	gnu	adc %dl,(%rcx)
+1011|223344556677885f5f5f5f5f5f5f	64	intel	adc byte ptr [rcx], dl
+1011|223344556677885f5f5f5f5f5f5f	64	plan9	ADCB DL, 0(CX)
+1111|223344556677885f5f5f5f5f5f5f	32	intel	adc dword ptr [ecx], edx
+1111|223344556677885f5f5f5f5f5f5f	32	plan9	ADCL DX, 0(CX)
+1111|223344556677885f5f5f5f5f5f5f	64	gnu	adc %edx,(%rcx)
+1111|223344556677885f5f5f5f5f5f5f	64	intel	adc dword ptr [rcx], edx
+1111|223344556677885f5f5f5f5f5f5f	64	plan9	ADCL DX, 0(CX)
+1211|223344556677885f5f5f5f5f5f5f	32	intel	adc dl, byte ptr [ecx]
+1211|223344556677885f5f5f5f5f5f5f	32	plan9	ADCB 0(CX), DL
+1211|223344556677885f5f5f5f5f5f5f	64	gnu	adc (%rcx),%dl
+1211|223344556677885f5f5f5f5f5f5f	64	intel	adc dl, byte ptr [rcx]
+1211|223344556677885f5f5f5f5f5f5f	64	plan9	ADCB 0(CX), DL
+1311|223344556677885f5f5f5f5f5f5f	32	intel	adc edx, dword ptr [ecx]
+1311|223344556677885f5f5f5f5f5f5f	32	plan9	ADCL 0(CX), DX
+1311|223344556677885f5f5f5f5f5f5f	64	gnu	adc (%rcx),%edx
+1311|223344556677885f5f5f5f5f5f5f	64	intel	adc edx, dword ptr [rcx]
+1311|223344556677885f5f5f5f5f5f5f	64	plan9	ADCL 0(CX), DX
+1411|223344556677885f5f5f5f5f5f5f	32	intel	adc al, 0x11
+1411|223344556677885f5f5f5f5f5f5f	32	plan9	ADCL $0x11, AL
+1411|223344556677885f5f5f5f5f5f5f	64	gnu	adc $0x11,%al
+1411|223344556677885f5f5f5f5f5f5f	64	intel	adc al, 0x11
+1411|223344556677885f5f5f5f5f5f5f	64	plan9	ADCL $0x11, AL
+1511223344|556677885f5f5f5f5f5f5f	32	intel	adc eax, 0x44332211
+1511223344|556677885f5f5f5f5f5f5f	32	plan9	ADCL $0x44332211, AX
+1511223344|556677885f5f5f5f5f5f5f	64	gnu	adc $0x44332211,%eax
+1511223344|556677885f5f5f5f5f5f5f	64	intel	adc eax, 0x44332211
+1511223344|556677885f5f5f5f5f5f5f	64	plan9	ADCL $0x44332211, AX
+16|11223344556677885f5f5f5f5f5f5f	32	intel	push ss
+16|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL SS
+16|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+16|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+16|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+17|11223344556677885f5f5f5f5f5f5f	32	intel	pop ss
+17|11223344556677885f5f5f5f5f5f5f	32	plan9	POPL SS
+17|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+17|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+17|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+1811|223344556677885f5f5f5f5f5f5f	32	intel	sbb byte ptr [ecx], dl
+1811|223344556677885f5f5f5f5f5f5f	32	plan9	SBBB DL, 0(CX)
+1811|223344556677885f5f5f5f5f5f5f	64	gnu	sbb %dl,(%rcx)
+1811|223344556677885f5f5f5f5f5f5f	64	intel	sbb byte ptr [rcx], dl
+1811|223344556677885f5f5f5f5f5f5f	64	plan9	SBBB DL, 0(CX)
+1911|223344556677885f5f5f5f5f5f5f	32	intel	sbb dword ptr [ecx], edx
+1911|223344556677885f5f5f5f5f5f5f	32	plan9	SBBL DX, 0(CX)
+1911|223344556677885f5f5f5f5f5f5f	64	gnu	sbb %edx,(%rcx)
+1911|223344556677885f5f5f5f5f5f5f	64	intel	sbb dword ptr [rcx], edx
+1911|223344556677885f5f5f5f5f5f5f	64	plan9	SBBL DX, 0(CX)
+1a11|223344556677885f5f5f5f5f5f5f	32	intel	sbb dl, byte ptr [ecx]
+1a11|223344556677885f5f5f5f5f5f5f	32	plan9	SBBB 0(CX), DL
+1a11|223344556677885f5f5f5f5f5f5f	64	gnu	sbb (%rcx),%dl
+1a11|223344556677885f5f5f5f5f5f5f	64	intel	sbb dl, byte ptr [rcx]
+1a11|223344556677885f5f5f5f5f5f5f	64	plan9	SBBB 0(CX), DL
+1b11|223344556677885f5f5f5f5f5f5f	32	intel	sbb edx, dword ptr [ecx]
+1b11|223344556677885f5f5f5f5f5f5f	32	plan9	SBBL 0(CX), DX
+1b11|223344556677885f5f5f5f5f5f5f	64	gnu	sbb (%rcx),%edx
+1b11|223344556677885f5f5f5f5f5f5f	64	intel	sbb edx, dword ptr [rcx]
+1b11|223344556677885f5f5f5f5f5f5f	64	plan9	SBBL 0(CX), DX
+1c11|223344556677885f5f5f5f5f5f5f	32	intel	sbb al, 0x11
+1c11|223344556677885f5f5f5f5f5f5f	32	plan9	SBBL $0x11, AL
+1c11|223344556677885f5f5f5f5f5f5f	64	gnu	sbb $0x11,%al
+1c11|223344556677885f5f5f5f5f5f5f	64	intel	sbb al, 0x11
+1c11|223344556677885f5f5f5f5f5f5f	64	plan9	SBBL $0x11, AL
+1d11223344|556677885f5f5f5f5f5f5f	32	intel	sbb eax, 0x44332211
+1d11223344|556677885f5f5f5f5f5f5f	32	plan9	SBBL $0x44332211, AX
+1d11223344|556677885f5f5f5f5f5f5f	64	gnu	sbb $0x44332211,%eax
+1d11223344|556677885f5f5f5f5f5f5f	64	intel	sbb eax, 0x44332211
+1d11223344|556677885f5f5f5f5f5f5f	64	plan9	SBBL $0x44332211, AX
+1e|11223344556677885f5f5f5f5f5f5f	32	intel	push ds
+1e|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL DS
+1e|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+1e|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+1e|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+1f|11223344556677885f5f5f5f5f5f5f	32	intel	pop ds
+1f|11223344556677885f5f5f5f5f5f5f	32	plan9	POPL DS
+1f|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+1f|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+1f|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+2011|223344556677885f5f5f5f5f5f5f	32	intel	and byte ptr [ecx], dl
+2011|223344556677885f5f5f5f5f5f5f	32	plan9	ANDB DL, 0(CX)
+2011|223344556677885f5f5f5f5f5f5f	64	gnu	and %dl,(%rcx)
+2011|223344556677885f5f5f5f5f5f5f	64	intel	and byte ptr [rcx], dl
+2011|223344556677885f5f5f5f5f5f5f	64	plan9	ANDB DL, 0(CX)
+2111|223344556677885f5f5f5f5f5f5f	32	intel	and dword ptr [ecx], edx
+2111|223344556677885f5f5f5f5f5f5f	32	plan9	ANDL DX, 0(CX)
+2111|223344556677885f5f5f5f5f5f5f	64	gnu	and %edx,(%rcx)
+2111|223344556677885f5f5f5f5f5f5f	64	intel	and dword ptr [rcx], edx
+2111|223344556677885f5f5f5f5f5f5f	64	plan9	ANDL DX, 0(CX)
+2211|223344556677885f5f5f5f5f5f5f	32	intel	and dl, byte ptr [ecx]
+2211|223344556677885f5f5f5f5f5f5f	32	plan9	ANDB 0(CX), DL
+2211|223344556677885f5f5f5f5f5f5f	64	gnu	and (%rcx),%dl
+2211|223344556677885f5f5f5f5f5f5f	64	intel	and dl, byte ptr [rcx]
+2211|223344556677885f5f5f5f5f5f5f	64	plan9	ANDB 0(CX), DL
+2311|223344556677885f5f5f5f5f5f5f	32	intel	and edx, dword ptr [ecx]
+2311|223344556677885f5f5f5f5f5f5f	32	plan9	ANDL 0(CX), DX
+2311|223344556677885f5f5f5f5f5f5f	64	gnu	and (%rcx),%edx
+2311|223344556677885f5f5f5f5f5f5f	64	intel	and edx, dword ptr [rcx]
+2311|223344556677885f5f5f5f5f5f5f	64	plan9	ANDL 0(CX), DX
+2411|223344556677885f5f5f5f5f5f5f	32	intel	and al, 0x11
+2411|223344556677885f5f5f5f5f5f5f	32	plan9	ANDL $0x11, AL
+2411|223344556677885f5f5f5f5f5f5f	64	gnu	and $0x11,%al
+2411|223344556677885f5f5f5f5f5f5f	64	intel	and al, 0x11
+2411|223344556677885f5f5f5f5f5f5f	64	plan9	ANDL $0x11, AL
+2511223344|556677885f5f5f5f5f5f5f	32	intel	and eax, 0x44332211
+2511223344|556677885f5f5f5f5f5f5f	32	plan9	ANDL $0x44332211, AX
+2511223344|556677885f5f5f5f5f5f5f	64	gnu	and $0x44332211,%eax
+2511223344|556677885f5f5f5f5f5f5f	64	intel	and eax, 0x44332211
+2511223344|556677885f5f5f5f5f5f5f	64	plan9	ANDL $0x44332211, AX
+266e|11223344556677885f5f5f5f5f5f	32	intel	outsb es
+266e|11223344556677885f5f5f5f5f5f	32	plan9	ES OUTSB ES:0(SI), DX
+266e|11223344556677885f5f5f5f5f5f	64	gnu	outsb %ds:%es:(%rsi),(%dx)
+266e|11223344556677885f5f5f5f5f5f	64	intel	outsb
+266e|11223344556677885f5f5f5f5f5f	64	plan9	ES OUTSB DS:0(SI), DX
+267011|223344556677885f5f5f5f5f5f	32	intel	jo .+0x11
+267011|223344556677885f5f5f5f5f5f	32	plan9	ES JO .+17
+267011|223344556677885f5f5f5f5f5f	64	gnu	es jo .+0x11
+267011|223344556677885f5f5f5f5f5f	64	intel	jo .+0x11
+267011|223344556677885f5f5f5f5f5f	64	plan9	ES JO .+17
+26a01122334455667788|5f5f5f5f5f5f	64	gnu	mov %es:-0x778899aabbccddef,%al
+26a01122334455667788|5f5f5f5f5f5f	64	intel	mov al, byte ptr [0x8877665544332211]
+26a01122334455667788|5f5f5f5f5f5f	64	plan9	ES MOVB -0x778899aabbccddef, AL
+26a011223344|556677885f5f5f5f5f5f	32	intel	mov al, byte ptr es:[0x44332211]
+26a011223344|556677885f5f5f5f5f5f	32	plan9	ES MOVB ES:0x44332211, AL
+26|8211223344556677885f5f5f5f5f5f	32	intel	es
+26|8211223344556677885f5f5f5f5f5f	32	plan9	ES Op(0)
+26|8211223344556677885f5f5f5f5f5f	64	gnu	es
+26|8211223344556677885f5f5f5f5f5f	64	intel	es
+26|8211223344556677885f5f5f5f5f5f	64	plan9	ES Op(0)
+27|11223344556677885f5f5f5f5f5f5f	32	intel	daa
+27|11223344556677885f5f5f5f5f5f5f	32	plan9	DAA
+27|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+27|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+27|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+2811|223344556677885f5f5f5f5f5f5f	32	intel	sub byte ptr [ecx], dl
+2811|223344556677885f5f5f5f5f5f5f	32	plan9	SUBB DL, 0(CX)
+2811|223344556677885f5f5f5f5f5f5f	64	gnu	sub %dl,(%rcx)
+2811|223344556677885f5f5f5f5f5f5f	64	intel	sub byte ptr [rcx], dl
+2811|223344556677885f5f5f5f5f5f5f	64	plan9	SUBB DL, 0(CX)
+2911|223344556677885f5f5f5f5f5f5f	32	intel	sub dword ptr [ecx], edx
+2911|223344556677885f5f5f5f5f5f5f	32	plan9	SUBL DX, 0(CX)
+2911|223344556677885f5f5f5f5f5f5f	64	gnu	sub %edx,(%rcx)
+2911|223344556677885f5f5f5f5f5f5f	64	intel	sub dword ptr [rcx], edx
+2911|223344556677885f5f5f5f5f5f5f	64	plan9	SUBL DX, 0(CX)
+2a11|223344556677885f5f5f5f5f5f5f	32	intel	sub dl, byte ptr [ecx]
+2a11|223344556677885f5f5f5f5f5f5f	32	plan9	SUBB 0(CX), DL
+2a11|223344556677885f5f5f5f5f5f5f	64	gnu	sub (%rcx),%dl
+2a11|223344556677885f5f5f5f5f5f5f	64	intel	sub dl, byte ptr [rcx]
+2a11|223344556677885f5f5f5f5f5f5f	64	plan9	SUBB 0(CX), DL
+2b11|223344556677885f5f5f5f5f5f5f	32	intel	sub edx, dword ptr [ecx]
+2b11|223344556677885f5f5f5f5f5f5f	32	plan9	SUBL 0(CX), DX
+2b11|223344556677885f5f5f5f5f5f5f	64	gnu	sub (%rcx),%edx
+2b11|223344556677885f5f5f5f5f5f5f	64	intel	sub edx, dword ptr [rcx]
+2b11|223344556677885f5f5f5f5f5f5f	64	plan9	SUBL 0(CX), DX
+2c11|223344556677885f5f5f5f5f5f5f	32	intel	sub al, 0x11
+2c11|223344556677885f5f5f5f5f5f5f	32	plan9	SUBL $0x11, AL
+2c11|223344556677885f5f5f5f5f5f5f	64	gnu	sub $0x11,%al
+2c11|223344556677885f5f5f5f5f5f5f	64	intel	sub al, 0x11
+2c11|223344556677885f5f5f5f5f5f5f	64	plan9	SUBL $0x11, AL
+2d11223344|556677885f5f5f5f5f5f5f	32	intel	sub eax, 0x44332211
+2d11223344|556677885f5f5f5f5f5f5f	32	plan9	SUBL $0x44332211, AX
+2d11223344|556677885f5f5f5f5f5f5f	64	gnu	sub $0x44332211,%eax
+2d11223344|556677885f5f5f5f5f5f5f	64	intel	sub eax, 0x44332211
+2d11223344|556677885f5f5f5f5f5f5f	64	plan9	SUBL $0x44332211, AX
+2f|11223344556677885f5f5f5f5f5f5f	32	intel	das
+2f|11223344556677885f5f5f5f5f5f5f	32	plan9	DAS
+2f|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+2f|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+2f|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+3011|223344556677885f5f5f5f5f5f5f	32	intel	xor byte ptr [ecx], dl
+3011|223344556677885f5f5f5f5f5f5f	32	plan9	XORB DL, 0(CX)
+3011|223344556677885f5f5f5f5f5f5f	64	gnu	xor %dl,(%rcx)
+3011|223344556677885f5f5f5f5f5f5f	64	intel	xor byte ptr [rcx], dl
+3011|223344556677885f5f5f5f5f5f5f	64	plan9	XORB DL, 0(CX)
+3111|223344556677885f5f5f5f5f5f5f	32	intel	xor dword ptr [ecx], edx
+3111|223344556677885f5f5f5f5f5f5f	32	plan9	XORL DX, 0(CX)
+3111|223344556677885f5f5f5f5f5f5f	64	gnu	xor %edx,(%rcx)
+3111|223344556677885f5f5f5f5f5f5f	64	intel	xor dword ptr [rcx], edx
+3111|223344556677885f5f5f5f5f5f5f	64	plan9	XORL DX, 0(CX)
+3211|223344556677885f5f5f5f5f5f5f	32	intel	xor dl, byte ptr [ecx]
+3211|223344556677885f5f5f5f5f5f5f	32	plan9	XORB 0(CX), DL
+3211|223344556677885f5f5f5f5f5f5f	64	gnu	xor (%rcx),%dl
+3211|223344556677885f5f5f5f5f5f5f	64	intel	xor dl, byte ptr [rcx]
+3211|223344556677885f5f5f5f5f5f5f	64	plan9	XORB 0(CX), DL
+3311|223344556677885f5f5f5f5f5f5f	32	intel	xor edx, dword ptr [ecx]
+3311|223344556677885f5f5f5f5f5f5f	32	plan9	XORL 0(CX), DX
+3311|223344556677885f5f5f5f5f5f5f	64	gnu	xor (%rcx),%edx
+3311|223344556677885f5f5f5f5f5f5f	64	intel	xor edx, dword ptr [rcx]
+3311|223344556677885f5f5f5f5f5f5f	64	plan9	XORL 0(CX), DX
+3411|223344556677885f5f5f5f5f5f5f	32	intel	xor al, 0x11
+3411|223344556677885f5f5f5f5f5f5f	32	plan9	XORL $0x11, AL
+3411|223344556677885f5f5f5f5f5f5f	64	gnu	xor $0x11,%al
+3411|223344556677885f5f5f5f5f5f5f	64	intel	xor al, 0x11
+3411|223344556677885f5f5f5f5f5f5f	64	plan9	XORL $0x11, AL
+3511223344|556677885f5f5f5f5f5f5f	32	intel	xor eax, 0x44332211
+3511223344|556677885f5f5f5f5f5f5f	32	plan9	XORL $0x44332211, AX
+3511223344|556677885f5f5f5f5f5f5f	64	gnu	xor $0x44332211,%eax
+3511223344|556677885f5f5f5f5f5f5f	64	intel	xor eax, 0x44332211
+3511223344|556677885f5f5f5f5f5f5f	64	plan9	XORL $0x44332211, AX
+3667f3660f2ac0|11223344556677885f	32	intel	addr16 cvtsi2ss xmm0, eax
+3667f3660f2ac0|11223344556677885f	32	plan9	CVTSI2SSW AX, X0
+3667f3660f2ac0|11223344556677885f	64	gnu	ss addr32 cvtsi2ss %ax,%xmm0
+3667f3660f2ac0|11223344556677885f	64	intel	addr32 cvtsi2ss xmm0, eax
+3667f3660f2ac0|11223344556677885f	64	plan9	CVTSI2SSW AX, X0
+36|67f3660ff7c011223344556677885f	64	gnu	ss
+36|f0f2f33e66f066f2f33e3666818411	32	intel	ss
+36|f0f2f33e66f066f2f33e3666818411	32	plan9	SS Op(0)
+36|f0f2f33e66f066f2f33e3666818411	64	gnu	ss
+36|f0f2f33e66f066f2f33e3666818411	64	intel	ss
+36|f0f2f33e66f066f2f33e3666818411	64	plan9	SS Op(0)
+36|f2f33ef0f78411223344556677885f	32	intel	ss
+36|f2f33ef0f78411223344556677885f	32	plan9	SS Op(0)
+36|f2f33ef0f78411223344556677885f	64	gnu	ss
+36|f2f33ef0f78411223344556677885f	64	intel	ss
+36|f2f33ef0f78411223344556677885f	64	plan9	SS Op(0)
+37|11223344556677885f5f5f5f5f5f5f	32	intel	aaa
+37|11223344556677885f5f5f5f5f5f5f	32	plan9	AAA
+37|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+37|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+37|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+3811|223344556677885f5f5f5f5f5f5f	32	intel	cmp byte ptr [ecx], dl
+3811|223344556677885f5f5f5f5f5f5f	32	plan9	CMPB DL, 0(CX)
+3811|223344556677885f5f5f5f5f5f5f	64	gnu	cmp %dl,(%rcx)
+3811|223344556677885f5f5f5f5f5f5f	64	intel	cmp byte ptr [rcx], dl
+3811|223344556677885f5f5f5f5f5f5f	64	plan9	CMPB DL, 0(CX)
+3911|223344556677885f5f5f5f5f5f5f	32	intel	cmp dword ptr [ecx], edx
+3911|223344556677885f5f5f5f5f5f5f	32	plan9	CMPL DX, 0(CX)
+3911|223344556677885f5f5f5f5f5f5f	64	gnu	cmp %edx,(%rcx)
+3911|223344556677885f5f5f5f5f5f5f	64	intel	cmp dword ptr [rcx], edx
+3911|223344556677885f5f5f5f5f5f5f	64	plan9	CMPL DX, 0(CX)
+3a11|223344556677885f5f5f5f5f5f5f	32	intel	cmp dl, byte ptr [ecx]
+3a11|223344556677885f5f5f5f5f5f5f	32	plan9	CMPB 0(CX), DL
+3a11|223344556677885f5f5f5f5f5f5f	64	gnu	cmp (%rcx),%dl
+3a11|223344556677885f5f5f5f5f5f5f	64	intel	cmp dl, byte ptr [rcx]
+3a11|223344556677885f5f5f5f5f5f5f	64	plan9	CMPB 0(CX), DL
+3b11|223344556677885f5f5f5f5f5f5f	32	intel	cmp edx, dword ptr [ecx]
+3b11|223344556677885f5f5f5f5f5f5f	32	plan9	CMPL 0(CX), DX
+3b11|223344556677885f5f5f5f5f5f5f	64	gnu	cmp (%rcx),%edx
+3b11|223344556677885f5f5f5f5f5f5f	64	intel	cmp edx, dword ptr [rcx]
+3b11|223344556677885f5f5f5f5f5f5f	64	plan9	CMPL 0(CX), DX
+3c11|223344556677885f5f5f5f5f5f5f	32	intel	cmp al, 0x11
+3c11|223344556677885f5f5f5f5f5f5f	32	plan9	CMPL $0x11, AL
+3c11|223344556677885f5f5f5f5f5f5f	64	gnu	cmp $0x11,%al
+3c11|223344556677885f5f5f5f5f5f5f	64	intel	cmp al, 0x11
+3c11|223344556677885f5f5f5f5f5f5f	64	plan9	CMPL $0x11, AL
+3d11223344|556677885f5f5f5f5f5f5f	32	intel	cmp eax, 0x44332211
+3d11223344|556677885f5f5f5f5f5f5f	32	plan9	CMPL $0x44332211, AX
+3d11223344|556677885f5f5f5f5f5f5f	64	gnu	cmp $0x44332211,%eax
+3d11223344|556677885f5f5f5f5f5f5f	64	intel	cmp eax, 0x44332211
+3d11223344|556677885f5f5f5f5f5f5f	64	plan9	CMPL $0x44332211, AX
+3e67e011|223344556677885f5f5f5f5f	32	intel	addr16 loopne .+0x11
+3e67e011|223344556677885f5f5f5f5f	32	plan9	LOOPNE .+17
+3e67e011|223344556677885f5f5f5f5f	64	gnu	loopne,pt .+0x11
+3e67e011|223344556677885f5f5f5f5f	64	intel	addr32 loopne .+0x11
+3e67e011|223344556677885f5f5f5f5f	64	plan9	LOOPNE .+17
+3ef367660f38f011|223344556677885f	32	intel	movbe dx, word ptr [bx+di*1]
+3ef367660f38f011|223344556677885f	32	plan9	MOVBE DS:0(BX)(DI*1), DX
+3ef367660f38f011|223344556677885f	64	gnu	rep movbe %ds:(%ecx),%dx
+3ef367660f38f011|223344556677885f	64	intel	movbe dx, word ptr [ecx]
+3ef367660f38f011|223344556677885f	64	plan9	MOVBE 0(CX), DX
+3f|11223344556677885f5f5f5f5f5f5f	32	intel	aas
+3f|11223344556677885f5f5f5f5f5f5f	32	plan9	AAS
+3f|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+3f|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+3f|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+4040|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+4040|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+4040|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+4048|11223344556677885f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+4048|11223344556677885f5f5f5f5f5f	64	intel	error: unrecognized instruction
+4048|11223344556677885f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+40|11223344556677885f5f5f5f5f5f5f	32	intel	inc eax
+40|11223344556677885f5f5f5f5f5f5f	32	plan9	INCL AX
+480100|11223344556677885f5f5f5f5f	64	gnu	add %rax,(%rax)
+480100|11223344556677885f5f5f5f5f	64	intel	add qword ptr [rax], rax
+480100|11223344556677885f5f5f5f5f	64	plan9	ADDQ AX, 0(AX)
+480311|223344556677885f5f5f5f5f5f	64	gnu	add (%rcx),%rdx
+480311|223344556677885f5f5f5f5f5f	64	intel	add rdx, qword ptr [rcx]
+480311|223344556677885f5f5f5f5f5f	64	plan9	ADDQ 0(CX), DX
+480511223344|556677885f5f5f5f5f5f	64	gnu	add $0x44332211,%rax
+480511223344|556677885f5f5f5f5f5f	64	intel	add rax, 0x44332211
+480511223344|556677885f5f5f5f5f5f	64	plan9	ADDQ $0x44332211, AX
+480911|223344556677885f5f5f5f5f5f	64	gnu	or %rdx,(%rcx)
+480911|223344556677885f5f5f5f5f5f	64	intel	or qword ptr [rcx], rdx
+480911|223344556677885f5f5f5f5f5f	64	plan9	ORQ DX, 0(CX)
+480b11|223344556677885f5f5f5f5f5f	64	gnu	or (%rcx),%rdx
+480b11|223344556677885f5f5f5f5f5f	64	intel	or rdx, qword ptr [rcx]
+480b11|223344556677885f5f5f5f5f5f	64	plan9	ORQ 0(CX), DX
+480d11223344|556677885f5f5f5f5f5f	64	gnu	or $0x44332211,%rax
+480d11223344|556677885f5f5f5f5f5f	64	intel	or rax, 0x44332211
+480d11223344|556677885f5f5f5f5f5f	64	plan9	ORQ $0x44332211, AX
+480f0000|11223344556677885f5f5f5f	64	gnu	sldt (%rax)
+480f0000|11223344556677885f5f5f5f	64	intel	sldt word ptr [rax]
+480f0000|11223344556677885f5f5f5f	64	plan9	SLDT 0(AX)
+480f0008|11223344556677885f5f5f5f	64	gnu	str (%rax)
+480f0008|11223344556677885f5f5f5f	64	intel	str word ptr [rax]
+480f0008|11223344556677885f5f5f5f	64	plan9	STR 0(AX)
+480f0120|11223344556677885f5f5f5f	64	gnu	smsw (%rax)
+480f0120|11223344556677885f5f5f5f	64	intel	smsw word ptr [rax]
+480f0120|11223344556677885f5f5f5f	64	plan9	SMSW 0(AX)
+480f0211|223344556677885f5f5f5f5f	64	gnu	lar (%rcx),%rdx
+480f0211|223344556677885f5f5f5f5f	64	intel	lar rdx, word ptr [rcx]
+480f0211|223344556677885f5f5f5f5f	64	plan9	LAR 0(CX), DX
+480f0311|223344556677885f5f5f5f5f	64	gnu	lsl (%rcx),%rdx
+480f0311|223344556677885f5f5f5f5f	64	intel	lsl rdx, word ptr [rcx]
+480f0311|223344556677885f5f5f5f5f	64	plan9	LSL 0(CX), DX
+480f35|11223344556677885f5f5f5f5f	64	gnu	sysexit
+480f35|11223344556677885f5f5f5f5f	64	intel	sysexit
+480f35|11223344556677885f5f5f5f5f	64	plan9	SYSEXIT
+480f38f011|223344556677885f5f5f5f	64	gnu	movbe (%rcx),%rdx
+480f38f011|223344556677885f5f5f5f	64	intel	movbe rdx, qword ptr [rcx]
+480f38f011|223344556677885f5f5f5f	64	plan9	MOVBE 0(CX), DX
+480f38f111|223344556677885f5f5f5f	64	gnu	movbe %rdx,(%rcx)
+480f38f111|223344556677885f5f5f5f	64	intel	movbe qword ptr [rcx], rdx
+480f38f111|223344556677885f5f5f5f	64	plan9	MOVBE DX, 0(CX)
+480f4011|223344556677885f5f5f5f5f	64	gnu	cmovo (%rcx),%rdx
+480f4011|223344556677885f5f5f5f5f	64	intel	cmovo rdx, qword ptr [rcx]
+480f4011|223344556677885f5f5f5f5f	64	plan9	CMOVO 0(CX), DX
+480f4111|223344556677885f5f5f5f5f	64	gnu	cmovno (%rcx),%rdx
+480f4111|223344556677885f5f5f5f5f	64	intel	cmovno rdx, qword ptr [rcx]
+480f4111|223344556677885f5f5f5f5f	64	plan9	CMOVNO 0(CX), DX
+480f4211|223344556677885f5f5f5f5f	64	gnu	cmovb (%rcx),%rdx
+480f4211|223344556677885f5f5f5f5f	64	intel	cmovb rdx, qword ptr [rcx]
+480f4211|223344556677885f5f5f5f5f	64	plan9	CMOVB 0(CX), DX
+480f4311|223344556677885f5f5f5f5f	64	gnu	cmovae (%rcx),%rdx
+480f4311|223344556677885f5f5f5f5f	64	intel	cmovnb rdx, qword ptr [rcx]
+480f4311|223344556677885f5f5f5f5f	64	plan9	CMOVAE 0(CX), DX
+480f4411|223344556677885f5f5f5f5f	64	gnu	cmove (%rcx),%rdx
+480f4411|223344556677885f5f5f5f5f	64	intel	cmovz rdx, qword ptr [rcx]
+480f4411|223344556677885f5f5f5f5f	64	plan9	CMOVE 0(CX), DX
+480f4511|223344556677885f5f5f5f5f	64	gnu	cmovne (%rcx),%rdx
+480f4511|223344556677885f5f5f5f5f	64	intel	cmovnz rdx, qword ptr [rcx]
+480f4511|223344556677885f5f5f5f5f	64	plan9	CMOVNE 0(CX), DX
+480f4611|223344556677885f5f5f5f5f	64	gnu	cmovbe (%rcx),%rdx
+480f4611|223344556677885f5f5f5f5f	64	intel	cmovbe rdx, qword ptr [rcx]
+480f4611|223344556677885f5f5f5f5f	64	plan9	CMOVBE 0(CX), DX
+480f4711|223344556677885f5f5f5f5f	64	gnu	cmova (%rcx),%rdx
+480f4711|223344556677885f5f5f5f5f	64	intel	cmovnbe rdx, qword ptr [rcx]
+480f4711|223344556677885f5f5f5f5f	64	plan9	CMOVA 0(CX), DX
+480f4811|223344556677885f5f5f5f5f	64	gnu	cmovs (%rcx),%rdx
+480f4811|223344556677885f5f5f5f5f	64	intel	cmovs rdx, qword ptr [rcx]
+480f4811|223344556677885f5f5f5f5f	64	plan9	CMOVS 0(CX), DX
+480f4911|223344556677885f5f5f5f5f	64	gnu	cmovns (%rcx),%rdx
+480f4911|223344556677885f5f5f5f5f	64	intel	cmovns rdx, qword ptr [rcx]
+480f4911|223344556677885f5f5f5f5f	64	plan9	CMOVNS 0(CX), DX
+480f4a11|223344556677885f5f5f5f5f	64	gnu	cmovp (%rcx),%rdx
+480f4a11|223344556677885f5f5f5f5f	64	intel	cmovp rdx, qword ptr [rcx]
+480f4a11|223344556677885f5f5f5f5f	64	plan9	CMOVP 0(CX), DX
+480f4b11|223344556677885f5f5f5f5f	64	gnu	cmovnp (%rcx),%rdx
+480f4b11|223344556677885f5f5f5f5f	64	intel	cmovnp rdx, qword ptr [rcx]
+480f4b11|223344556677885f5f5f5f5f	64	plan9	CMOVNP 0(CX), DX
+480f4c11|223344556677885f5f5f5f5f	64	gnu	cmovl (%rcx),%rdx
+480f4c11|223344556677885f5f5f5f5f	64	intel	cmovl rdx, qword ptr [rcx]
+480f4c11|223344556677885f5f5f5f5f	64	plan9	CMOVL 0(CX), DX
+480f4d11|223344556677885f5f5f5f5f	64	gnu	cmovge (%rcx),%rdx
+480f4d11|223344556677885f5f5f5f5f	64	intel	cmovnl rdx, qword ptr [rcx]
+480f4d11|223344556677885f5f5f5f5f	64	plan9	CMOVGE 0(CX), DX
+480f4e11|223344556677885f5f5f5f5f	64	gnu	cmovle (%rcx),%rdx
+480f4e11|223344556677885f5f5f5f5f	64	intel	cmovle rdx, qword ptr [rcx]
+480f4e11|223344556677885f5f5f5f5f	64	plan9	CMOVLE 0(CX), DX
+480f4f11|223344556677885f5f5f5f5f	64	gnu	cmovg (%rcx),%rdx
+480f4f11|223344556677885f5f5f5f5f	64	intel	cmovnle rdx, qword ptr [rcx]
+480f4f11|223344556677885f5f5f5f5f	64	plan9	CMOVG 0(CX), DX
+480f6e11|223344556677885f5f5f5f5f	64	gnu	movq (%rcx),%mm2
+480f6e11|223344556677885f5f5f5f5f	64	intel	movq mmx2, qword ptr [rcx]
+480f6e11|223344556677885f5f5f5f5f	64	plan9	MOVQ 0(CX), M2
+480f7e11|223344556677885f5f5f5f5f	64	gnu	movq %mm2,(%rcx)
+480f7e11|223344556677885f5f5f5f5f	64	intel	movq qword ptr [rcx], mmx2
+480f7e11|223344556677885f5f5f5f5f	64	plan9	MOVQ M2, 0(CX)
+480f8011223344|556677885f5f5f5f5f	64	gnu	jo .+0x44332211
+480f8011223344|556677885f5f5f5f5f	64	intel	jo .+0x44332211
+480f8011223344|556677885f5f5f5f5f	64	plan9	JO .+1144201745
+480f8111223344|556677885f5f5f5f5f	64	gnu	jno .+0x44332211
+480f8111223344|556677885f5f5f5f5f	64	intel	jno .+0x44332211
+480f8111223344|556677885f5f5f5f5f	64	plan9	JNO .+1144201745
+480f8211223344|556677885f5f5f5f5f	64	gnu	jb .+0x44332211
+480f8211223344|556677885f5f5f5f5f	64	intel	jb .+0x44332211
+480f8211223344|556677885f5f5f5f5f	64	plan9	JB .+1144201745
+480f8311223344|556677885f5f5f5f5f	64	gnu	jae .+0x44332211
+480f8311223344|556677885f5f5f5f5f	64	intel	jnb .+0x44332211
+480f8311223344|556677885f5f5f5f5f	64	plan9	JAE .+1144201745
+480f8411223344|556677885f5f5f5f5f	64	gnu	je .+0x44332211
+480f8411223344|556677885f5f5f5f5f	64	intel	jz .+0x44332211
+480f8411223344|556677885f5f5f5f5f	64	plan9	JE .+1144201745
+480f8511223344|556677885f5f5f5f5f	64	gnu	jne .+0x44332211
+480f8511223344|556677885f5f5f5f5f	64	intel	jnz .+0x44332211
+480f8511223344|556677885f5f5f5f5f	64	plan9	JNE .+1144201745
+480f8611223344|556677885f5f5f5f5f	64	gnu	jbe .+0x44332211
+480f8611223344|556677885f5f5f5f5f	64	intel	jbe .+0x44332211
+480f8611223344|556677885f5f5f5f5f	64	plan9	JBE .+1144201745
+480f8711223344|556677885f5f5f5f5f	64	gnu	ja .+0x44332211
+480f8711223344|556677885f5f5f5f5f	64	intel	jnbe .+0x44332211
+480f8711223344|556677885f5f5f5f5f	64	plan9	JA .+1144201745
+480f8811223344|556677885f5f5f5f5f	64	gnu	js .+0x44332211
+480f8811223344|556677885f5f5f5f5f	64	intel	js .+0x44332211
+480f8811223344|556677885f5f5f5f5f	64	plan9	JS .+1144201745
+480f8911223344|556677885f5f5f5f5f	64	gnu	jns .+0x44332211
+480f8911223344|556677885f5f5f5f5f	64	intel	jns .+0x44332211
+480f8911223344|556677885f5f5f5f5f	64	plan9	JNS .+1144201745
+480f8a11223344|556677885f5f5f5f5f	64	gnu	jp .+0x44332211
+480f8a11223344|556677885f5f5f5f5f	64	intel	jp .+0x44332211
+480f8a11223344|556677885f5f5f5f5f	64	plan9	JP .+1144201745
+480f8b11223344|556677885f5f5f5f5f	64	gnu	jnp .+0x44332211
+480f8b11223344|556677885f5f5f5f5f	64	intel	jnp .+0x44332211
+480f8b11223344|556677885f5f5f5f5f	64	plan9	JNP .+1144201745
+480f8c11223344|556677885f5f5f5f5f	64	gnu	jl .+0x44332211
+480f8c11223344|556677885f5f5f5f5f	64	intel	jl .+0x44332211
+480f8c11223344|556677885f5f5f5f5f	64	plan9	JL .+1144201745
+480f8d11223344|556677885f5f5f5f5f	64	gnu	jge .+0x44332211
+480f8d11223344|556677885f5f5f5f5f	64	intel	jnl .+0x44332211
+480f8d11223344|556677885f5f5f5f5f	64	plan9	JGE .+1144201745
+480f8e11223344|556677885f5f5f5f5f	64	gnu	jle .+0x44332211
+480f8e11223344|556677885f5f5f5f5f	64	intel	jle .+0x44332211
+480f8e11223344|556677885f5f5f5f5f	64	plan9	JLE .+1144201745
+480f8f11223344|556677885f5f5f5f5f	64	gnu	jg .+0x44332211
+480f8f11223344|556677885f5f5f5f5f	64	intel	jnle .+0x44332211
+480f8f11223344|556677885f5f5f5f5f	64	plan9	JG .+1144201745
+480fa1|11223344556677885f5f5f5f5f	64	gnu	popq %fs
+480fa1|11223344556677885f5f5f5f5f	64	intel	pop fs
+480fa1|11223344556677885f5f5f5f5f	64	plan9	POPQ FS
+480fa311|223344556677885f5f5f5f5f	64	gnu	bt %rdx,(%rcx)
+480fa311|223344556677885f5f5f5f5f	64	intel	bt qword ptr [rcx], rdx
+480fa311|223344556677885f5f5f5f5f	64	plan9	BTQ DX, 0(CX)
+480fa41122|3344556677885f5f5f5f5f	64	gnu	shld $0x22,%rdx,(%rcx)
+480fa41122|3344556677885f5f5f5f5f	64	intel	shld qword ptr [rcx], rdx, 0x22
+480fa41122|3344556677885f5f5f5f5f	64	plan9	SHLDQ $0x22, DX, 0(CX)
+480fa511|223344556677885f5f5f5f5f	64	gnu	shld %cl,%rdx,(%rcx)
+480fa511|223344556677885f5f5f5f5f	64	intel	shld qword ptr [rcx], rdx, cl
+480fa511|223344556677885f5f5f5f5f	64	plan9	SHLDQ CL, DX, 0(CX)
+480fa9|11223344556677885f5f5f5f5f	64	gnu	popq %gs
+480fa9|11223344556677885f5f5f5f5f	64	intel	pop gs
+480fa9|11223344556677885f5f5f5f5f	64	plan9	POPQ GS
+480fab11|223344556677885f5f5f5f5f	64	gnu	bts %rdx,(%rcx)
+480fab11|223344556677885f5f5f5f5f	64	intel	bts qword ptr [rcx], rdx
+480fab11|223344556677885f5f5f5f5f	64	plan9	BTSQ DX, 0(CX)
+480fac1122|3344556677885f5f5f5f5f	64	gnu	shrd $0x22,%rdx,(%rcx)
+480fac1122|3344556677885f5f5f5f5f	64	intel	shrd qword ptr [rcx], rdx, 0x22
+480fac1122|3344556677885f5f5f5f5f	64	plan9	SHRDQ $0x22, DX, 0(CX)
+480fad11|223344556677885f5f5f5f5f	64	gnu	shrd %cl,%rdx,(%rcx)
+480fad11|223344556677885f5f5f5f5f	64	intel	shrd qword ptr [rcx], rdx, cl
+480fad11|223344556677885f5f5f5f5f	64	plan9	SHRDQ CL, DX, 0(CX)
+480fae00|11223344556677885f5f5f5f	64	gnu	fxsave64 (%rax)
+480fae00|11223344556677885f5f5f5f	64	intel	fxsave64 ptr [rax]
+480fae00|11223344556677885f5f5f5f	64	plan9	FXSAVE64 0(AX)
+480fae08|11223344556677885f5f5f5f	64	gnu	fxrstor64 (%rax)
+480fae08|11223344556677885f5f5f5f	64	intel	fxrstor64 ptr [rax]
+480fae08|11223344556677885f5f5f5f	64	plan9	FXRSTOR64 0(AX)
+480fae20|11223344556677885f5f5f5f	64	gnu	xsave64 (%rax)
+480fae20|11223344556677885f5f5f5f	64	intel	xsave64 ptr [rax]
+480fae20|11223344556677885f5f5f5f	64	plan9	XSAVE64 0(AX)
+480fae28|11223344556677885f5f5f5f	64	gnu	xrstor64 (%rax)
+480fae28|11223344556677885f5f5f5f	64	intel	xrstor64 ptr [rax]
+480fae28|11223344556677885f5f5f5f	64	plan9	XRSTOR64 0(AX)
+480fae30|11223344556677885f5f5f5f	64	gnu	xsaveopt64 (%rax)
+480fae30|11223344556677885f5f5f5f	64	intel	xsaveopt64 ptr [rax]
+480fae30|11223344556677885f5f5f5f	64	plan9	XSAVEOPT64 0(AX)
+480faf11|223344556677885f5f5f5f5f	64	gnu	imul (%rcx),%rdx
+480faf11|223344556677885f5f5f5f5f	64	intel	imul rdx, qword ptr [rcx]
+480faf11|223344556677885f5f5f5f5f	64	plan9	IMULQ 0(CX), DX
+480fb111|223344556677885f5f5f5f5f	64	gnu	cmpxchg %rdx,(%rcx)
+480fb111|223344556677885f5f5f5f5f	64	intel	cmpxchg qword ptr [rcx], rdx
+480fb111|223344556677885f5f5f5f5f	64	plan9	CMPXCHGQ DX, 0(CX)
+480fb211|223344556677885f5f5f5f5f	64	gnu	lss (%rcx),%rdx
+480fb211|223344556677885f5f5f5f5f	64	intel	lss rdx, ptr [rcx]
+480fb211|223344556677885f5f5f5f5f	64	plan9	LSS 0(CX), DX
+480fb311|223344556677885f5f5f5f5f	64	gnu	btr %rdx,(%rcx)
+480fb311|223344556677885f5f5f5f5f	64	intel	btr qword ptr [rcx], rdx
+480fb311|223344556677885f5f5f5f5f	64	plan9	BTRQ DX, 0(CX)
+480fb411|223344556677885f5f5f5f5f	64	gnu	lfs (%rcx),%rdx
+480fb411|223344556677885f5f5f5f5f	64	intel	lfs rdx, ptr [rcx]
+480fb411|223344556677885f5f5f5f5f	64	plan9	LFS 0(CX), DX
+480fb511|223344556677885f5f5f5f5f	64	gnu	lgs (%rcx),%rdx
+480fb511|223344556677885f5f5f5f5f	64	intel	lgs rdx, ptr [rcx]
+480fb511|223344556677885f5f5f5f5f	64	plan9	LGS 0(CX), DX
+480fb611|223344556677885f5f5f5f5f	64	gnu	movzbq (%rcx),%rdx
+480fb611|223344556677885f5f5f5f5f	64	intel	movzx rdx, byte ptr [rcx]
+480fb611|223344556677885f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
+480fb711|223344556677885f5f5f5f5f	64	gnu	movzwq (%rcx),%rdx
+480fb711|223344556677885f5f5f5f5f	64	intel	movzx rdx, word ptr [rcx]
+480fb711|223344556677885f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
+480fba2011|223344556677885f5f5f5f	64	gnu	btq $0x11,(%rax)
+480fba2011|223344556677885f5f5f5f	64	intel	bt qword ptr [rax], 0x11
+480fba2011|223344556677885f5f5f5f	64	plan9	BTQ $0x11, 0(AX)
+480fba2811|223344556677885f5f5f5f	64	gnu	btsq $0x11,(%rax)
+480fba2811|223344556677885f5f5f5f	64	intel	bts qword ptr [rax], 0x11
+480fba2811|223344556677885f5f5f5f	64	plan9	BTSQ $0x11, 0(AX)
+480fba3011|223344556677885f5f5f5f	64	gnu	btrq $0x11,(%rax)
+480fba3011|223344556677885f5f5f5f	64	intel	btr qword ptr [rax], 0x11
+480fba3011|223344556677885f5f5f5f	64	plan9	BTRQ $0x11, 0(AX)
+480fba3811|223344556677885f5f5f5f	64	gnu	btcq $0x11,(%rax)
+480fba3811|223344556677885f5f5f5f	64	intel	btc qword ptr [rax], 0x11
+480fba3811|223344556677885f5f5f5f	64	plan9	BTCQ $0x11, 0(AX)
+480fbb11|223344556677885f5f5f5f5f	64	gnu	btc %rdx,(%rcx)
+480fbb11|223344556677885f5f5f5f5f	64	intel	btc qword ptr [rcx], rdx
+480fbb11|223344556677885f5f5f5f5f	64	plan9	BTCQ DX, 0(CX)
+480fbc11|223344556677885f5f5f5f5f	64	gnu	bsf (%rcx),%rdx
+480fbc11|223344556677885f5f5f5f5f	64	intel	bsf rdx, qword ptr [rcx]
+480fbc11|223344556677885f5f5f5f5f	64	plan9	BSFQ 0(CX), DX
+480fbd11|223344556677885f5f5f5f5f	64	gnu	bsr (%rcx),%rdx
+480fbd11|223344556677885f5f5f5f5f	64	intel	bsr rdx, qword ptr [rcx]
+480fbd11|223344556677885f5f5f5f5f	64	plan9	BSRQ 0(CX), DX
+480fbe11|223344556677885f5f5f5f5f	64	gnu	movsbq (%rcx),%rdx
+480fbe11|223344556677885f5f5f5f5f	64	intel	movsx rdx, byte ptr [rcx]
+480fbe11|223344556677885f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
+480fbf11|223344556677885f5f5f5f5f	64	gnu	movswq (%rcx),%rdx
+480fbf11|223344556677885f5f5f5f5f	64	intel	movsx rdx, word ptr [rcx]
+480fbf11|223344556677885f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
+480fc111|223344556677885f5f5f5f5f	64	gnu	xadd %rdx,(%rcx)
+480fc111|223344556677885f5f5f5f5f	64	intel	xadd qword ptr [rcx], rdx
+480fc111|223344556677885f5f5f5f5f	64	plan9	XADDQ DX, 0(CX)
+480fc311|223344556677885f5f5f5f5f	64	gnu	movnti %rdx,(%rcx)
+480fc311|223344556677885f5f5f5f5f	64	intel	movnti qword ptr [rcx], rdx
+480fc311|223344556677885f5f5f5f5f	64	plan9	MOVNTIQ DX, 0(CX)
+480fc708|11223344556677885f5f5f5f	64	gnu	cmpxchg16b (%rax)
+480fc708|11223344556677885f5f5f5f	64	intel	cmpxchg16b xmmword ptr [rax]
+480fc708|11223344556677885f5f5f5f	64	plan9	CMPXCHG16B 0(AX)
+480fc718|11223344556677885f5f5f5f	64	gnu	xrstors64 (%rax)
+480fc718|11223344556677885f5f5f5f	64	intel	xrstors64 ptr [rax]
+480fc718|11223344556677885f5f5f5f	64	plan9	XRSTORS64 0(AX)
+480fc720|11223344556677885f5f5f5f	64	gnu	xsavec64 (%rax)
+480fc720|11223344556677885f5f5f5f	64	intel	xsavec64 ptr [rax]
+480fc720|11223344556677885f5f5f5f	64	plan9	XSAVEC64 0(AX)
+480fc728|11223344556677885f5f5f5f	64	gnu	xsaves64 (%rax)
+480fc728|11223344556677885f5f5f5f	64	intel	xsaves64 ptr [rax]
+480fc728|11223344556677885f5f5f5f	64	plan9	XSAVES64 0(AX)
+480fc730|11223344556677885f5f5f5f	64	gnu	rdrand
+480fc730|11223344556677885f5f5f5f	64	intel	rdrand
+480fc730|11223344556677885f5f5f5f	64	plan9	RDRAND
+480fc8|11223344556677885f5f5f5f5f	64	gnu	bswap %rax
+480fc8|11223344556677885f5f5f5f5f	64	intel	bswap rax
+480fc8|11223344556677885f5f5f5f5f	64	plan9	BSWAP AX
+481122|3344556677885f5f5f5f5f5f5f	64	gnu	adc %rsp,(%rdx)
+481122|3344556677885f5f5f5f5f5f5f	64	intel	adc qword ptr [rdx], rsp
+481122|3344556677885f5f5f5f5f5f5f	64	plan9	ADCQ SP, 0(DX)
+481311|223344556677885f5f5f5f5f5f	64	gnu	adc (%rcx),%rdx
+481311|223344556677885f5f5f5f5f5f	64	intel	adc rdx, qword ptr [rcx]
+481311|223344556677885f5f5f5f5f5f	64	plan9	ADCQ 0(CX), DX
+481511223344|556677885f5f5f5f5f5f	64	gnu	adc $0x44332211,%rax
+481511223344|556677885f5f5f5f5f5f	64	intel	adc rax, 0x44332211
+481511223344|556677885f5f5f5f5f5f	64	plan9	ADCQ $0x44332211, AX
+481911|223344556677885f5f5f5f5f5f	64	gnu	sbb %rdx,(%rcx)
+481911|223344556677885f5f5f5f5f5f	64	intel	sbb qword ptr [rcx], rdx
+481911|223344556677885f5f5f5f5f5f	64	plan9	SBBQ DX, 0(CX)
+481b11|223344556677885f5f5f5f5f5f	64	gnu	sbb (%rcx),%rdx
+481b11|223344556677885f5f5f5f5f5f	64	intel	sbb rdx, qword ptr [rcx]
+481b11|223344556677885f5f5f5f5f5f	64	plan9	SBBQ 0(CX), DX
+481d11223344|556677885f5f5f5f5f5f	64	gnu	sbb $0x44332211,%rax
+481d11223344|556677885f5f5f5f5f5f	64	intel	sbb rax, 0x44332211
+481d11223344|556677885f5f5f5f5f5f	64	plan9	SBBQ $0x44332211, AX
+482111|223344556677885f5f5f5f5f5f	64	gnu	and %rdx,(%rcx)
+482111|223344556677885f5f5f5f5f5f	64	intel	and qword ptr [rcx], rdx
+482111|223344556677885f5f5f5f5f5f	64	plan9	ANDQ DX, 0(CX)
+482311|223344556677885f5f5f5f5f5f	64	gnu	and (%rcx),%rdx
+482311|223344556677885f5f5f5f5f5f	64	intel	and rdx, qword ptr [rcx]
+482311|223344556677885f5f5f5f5f5f	64	plan9	ANDQ 0(CX), DX
+482511223344|556677885f5f5f5f5f5f	64	gnu	and $0x44332211,%rax
+482511223344|556677885f5f5f5f5f5f	64	intel	and rax, 0x44332211
+482511223344|556677885f5f5f5f5f5f	64	plan9	ANDQ $0x44332211, AX
+482911|223344556677885f5f5f5f5f5f	64	gnu	sub %rdx,(%rcx)
+482911|223344556677885f5f5f5f5f5f	64	intel	sub qword ptr [rcx], rdx
+482911|223344556677885f5f5f5f5f5f	64	plan9	SUBQ DX, 0(CX)
+482b11|223344556677885f5f5f5f5f5f	64	gnu	sub (%rcx),%rdx
+482b11|223344556677885f5f5f5f5f5f	64	intel	sub rdx, qword ptr [rcx]
+482b11|223344556677885f5f5f5f5f5f	64	plan9	SUBQ 0(CX), DX
+482d11223344|556677885f5f5f5f5f5f	64	gnu	sub $0x44332211,%rax
+482d11223344|556677885f5f5f5f5f5f	64	intel	sub rax, 0x44332211
+482d11223344|556677885f5f5f5f5f5f	64	plan9	SUBQ $0x44332211, AX
+483111|223344556677885f5f5f5f5f5f	64	gnu	xor %rdx,(%rcx)
+483111|223344556677885f5f5f5f5f5f	64	intel	xor qword ptr [rcx], rdx
+483111|223344556677885f5f5f5f5f5f	64	plan9	XORQ DX, 0(CX)
+483311|223344556677885f5f5f5f5f5f	64	gnu	xor (%rcx),%rdx
+483311|223344556677885f5f5f5f5f5f	64	intel	xor rdx, qword ptr [rcx]
+483311|223344556677885f5f5f5f5f5f	64	plan9	XORQ 0(CX), DX
+483511223344|556677885f5f5f5f5f5f	64	gnu	xor $0x44332211,%rax
+483511223344|556677885f5f5f5f5f5f	64	intel	xor rax, 0x44332211
+483511223344|556677885f5f5f5f5f5f	64	plan9	XORQ $0x44332211, AX
+483911|223344556677885f5f5f5f5f5f	64	gnu	cmp %rdx,(%rcx)
+483911|223344556677885f5f5f5f5f5f	64	intel	cmp qword ptr [rcx], rdx
+483911|223344556677885f5f5f5f5f5f	64	plan9	CMPQ DX, 0(CX)
+483b11|223344556677885f5f5f5f5f5f	64	gnu	cmp (%rcx),%rdx
+483b11|223344556677885f5f5f5f5f5f	64	intel	cmp rdx, qword ptr [rcx]
+483b11|223344556677885f5f5f5f5f5f	64	plan9	CMPQ 0(CX), DX
+483d11223344|556677885f5f5f5f5f5f	64	gnu	cmp $0x44332211,%rax
+483d11223344|556677885f5f5f5f5f5f	64	intel	cmp rax, 0x44332211
+483d11223344|556677885f5f5f5f5f5f	64	plan9	CMPQ $0x44332211, AX
+4850|11223344556677885f5f5f5f5f5f	64	gnu	push %rax
+4850|11223344556677885f5f5f5f5f5f	64	intel	push rax
+4850|11223344556677885f5f5f5f5f5f	64	plan9	PUSHQ AX
+4858|11223344556677885f5f5f5f5f5f	64	gnu	pop %rax
+4858|11223344556677885f5f5f5f5f5f	64	intel	pop rax
+4858|11223344556677885f5f5f5f5f5f	64	plan9	POPQ AX
+486311|223344556677885f5f5f5f5f5f	64	gnu	movsxd (%rcx),%rdx
+486311|223344556677885f5f5f5f5f5f	64	intel	movsxd rdx, dword ptr [rcx]
+486311|223344556677885f5f5f5f5f5f	64	plan9	MOVSXD 0(CX), DX
+486811223344|556677885f5f5f5f5f5f	64	gnu	pushq $0x44332211
+486811223344|556677885f5f5f5f5f5f	64	intel	push 0x44332211
+486811223344|556677885f5f5f5f5f5f	64	plan9	PUSHQ $0x44332211
+48691122334455|6677885f5f5f5f5f5f	64	gnu	imul $0x55443322,(%rcx),%rdx
+48691122334455|6677885f5f5f5f5f5f	64	intel	imul rdx, qword ptr [rcx], 0x55443322
+48691122334455|6677885f5f5f5f5f5f	64	plan9	IMULQ $0x55443322, 0(CX), DX
+486b1122|3344556677885f5f5f5f5f5f	64	gnu	imul $0x22,(%rcx),%rdx
+486b1122|3344556677885f5f5f5f5f5f	64	intel	imul rdx, qword ptr [rcx], 0x22
+486b1122|3344556677885f5f5f5f5f5f	64	plan9	IMULQ $0x22, 0(CX), DX
+486d|11223344556677885f5f5f5f5f5f	64	gnu	insl (%dx),%es:(%rdi)
+486d|11223344556677885f5f5f5f5f5f	64	intel	insd
+486d|11223344556677885f5f5f5f5f5f	64	plan9	INSD DX, ES:0(DI)
+486f|11223344556677885f5f5f5f5f5f	64	gnu	outsl %ds:(%rsi),(%dx)
+486f|11223344556677885f5f5f5f5f5f	64	intel	outsd
+486f|11223344556677885f5f5f5f5f5f	64	plan9	OUTSD DS:0(SI), DX
+48810011223344|556677885f5f5f5f5f	64	gnu	addq $0x44332211,(%rax)
+48810011223344|556677885f5f5f5f5f	64	intel	add qword ptr [rax], 0x44332211
+48810011223344|556677885f5f5f5f5f	64	plan9	ADDQ $0x44332211, 0(AX)
+48810811223344|556677885f5f5f5f5f	64	gnu	orq $0x44332211,(%rax)
+48810811223344|556677885f5f5f5f5f	64	intel	or qword ptr [rax], 0x44332211
+48810811223344|556677885f5f5f5f5f	64	plan9	ORQ $0x44332211, 0(AX)
+48811122334455|6677885f5f5f5f5f5f	64	gnu	adcq $0x55443322,(%rcx)
+48811122334455|6677885f5f5f5f5f5f	64	intel	adc qword ptr [rcx], 0x55443322
+48811122334455|6677885f5f5f5f5f5f	64	plan9	ADCQ $0x55443322, 0(CX)
+48811811223344|556677885f5f5f5f5f	64	gnu	sbbq $0x44332211,(%rax)
+48811811223344|556677885f5f5f5f5f	64	intel	sbb qword ptr [rax], 0x44332211
+48811811223344|556677885f5f5f5f5f	64	plan9	SBBQ $0x44332211, 0(AX)
+48812011223344|556677885f5f5f5f5f	64	gnu	andq $0x44332211,(%rax)
+48812011223344|556677885f5f5f5f5f	64	intel	and qword ptr [rax], 0x44332211
+48812011223344|556677885f5f5f5f5f	64	plan9	ANDQ $0x44332211, 0(AX)
+48812811223344|556677885f5f5f5f5f	64	gnu	subq $0x44332211,(%rax)
+48812811223344|556677885f5f5f5f5f	64	intel	sub qword ptr [rax], 0x44332211
+48812811223344|556677885f5f5f5f5f	64	plan9	SUBQ $0x44332211, 0(AX)
+48813011223344|556677885f5f5f5f5f	64	gnu	xorq $0x44332211,(%rax)
+48813011223344|556677885f5f5f5f5f	64	intel	xor qword ptr [rax], 0x44332211
+48813011223344|556677885f5f5f5f5f	64	plan9	XORQ $0x44332211, 0(AX)
+48813811223344|556677885f5f5f5f5f	64	gnu	cmpq $0x44332211,(%rax)
+48813811223344|556677885f5f5f5f5f	64	intel	cmp qword ptr [rax], 0x44332211
+48813811223344|556677885f5f5f5f5f	64	plan9	CMPQ $0x44332211, 0(AX)
+48830011|223344556677885f5f5f5f5f	64	gnu	addq $0x11,(%rax)
+48830011|223344556677885f5f5f5f5f	64	intel	add qword ptr [rax], 0x11
+48830011|223344556677885f5f5f5f5f	64	plan9	ADDQ $0x11, 0(AX)
+48830811|223344556677885f5f5f5f5f	64	gnu	orq $0x11,(%rax)
+48830811|223344556677885f5f5f5f5f	64	intel	or qword ptr [rax], 0x11
+48830811|223344556677885f5f5f5f5f	64	plan9	ORQ $0x11, 0(AX)
+48831122|3344556677885f5f5f5f5f5f	64	gnu	adcq $0x22,(%rcx)
+48831122|3344556677885f5f5f5f5f5f	64	intel	adc qword ptr [rcx], 0x22
+48831122|3344556677885f5f5f5f5f5f	64	plan9	ADCQ $0x22, 0(CX)
+48831811|223344556677885f5f5f5f5f	64	gnu	sbbq $0x11,(%rax)
+48831811|223344556677885f5f5f5f5f	64	intel	sbb qword ptr [rax], 0x11
+48831811|223344556677885f5f5f5f5f	64	plan9	SBBQ $0x11, 0(AX)
+48832011|223344556677885f5f5f5f5f	64	gnu	andq $0x11,(%rax)
+48832011|223344556677885f5f5f5f5f	64	intel	and qword ptr [rax], 0x11
+48832011|223344556677885f5f5f5f5f	64	plan9	ANDQ $0x11, 0(AX)
+48832811|223344556677885f5f5f5f5f	64	gnu	subq $0x11,(%rax)
+48832811|223344556677885f5f5f5f5f	64	intel	sub qword ptr [rax], 0x11
+48832811|223344556677885f5f5f5f5f	64	plan9	SUBQ $0x11, 0(AX)
+48833011|223344556677885f5f5f5f5f	64	gnu	xorq $0x11,(%rax)
+48833011|223344556677885f5f5f5f5f	64	intel	xor qword ptr [rax], 0x11
+48833011|223344556677885f5f5f5f5f	64	plan9	XORQ $0x11, 0(AX)
+48833811|223344556677885f5f5f5f5f	64	gnu	cmpq $0x11,(%rax)
+48833811|223344556677885f5f5f5f5f	64	intel	cmp qword ptr [rax], 0x11
+48833811|223344556677885f5f5f5f5f	64	plan9	CMPQ $0x11, 0(AX)
+488511|223344556677885f5f5f5f5f5f	64	gnu	test %rdx,(%rcx)
+488511|223344556677885f5f5f5f5f5f	64	intel	test qword ptr [rcx], rdx
+488511|223344556677885f5f5f5f5f5f	64	plan9	TESTQ DX, 0(CX)
+488711|223344556677885f5f5f5f5f5f	64	gnu	xchg %rdx,(%rcx)
+488711|223344556677885f5f5f5f5f5f	64	intel	xchg qword ptr [rcx], rdx
+488711|223344556677885f5f5f5f5f5f	64	plan9	XCHGQ DX, 0(CX)
+488911|223344556677885f5f5f5f5f5f	64	gnu	mov %rdx,(%rcx)
+488911|223344556677885f5f5f5f5f5f	64	intel	mov qword ptr [rcx], rdx
+488911|223344556677885f5f5f5f5f5f	64	plan9	MOVQ DX, 0(CX)
+488b11|223344556677885f5f5f5f5f5f	64	gnu	mov (%rcx),%rdx
+488b11|223344556677885f5f5f5f5f5f	64	intel	mov rdx, qword ptr [rcx]
+488b11|223344556677885f5f5f5f5f5f	64	plan9	MOVQ 0(CX), DX
+488c11|223344556677885f5f5f5f5f5f	64	gnu	mov %ss,(%rcx)
+488c11|223344556677885f5f5f5f5f5f	64	intel	mov word ptr [rcx], ss
+# MOVQ is probably more correct here (reads 16 bits of segment register, zero extends, writes 64 bits at CX)
+488c11|223344556677885f5f5f5f5f5f	64	plan9	MOVW SS, 0(CX)
+488d11|223344556677885f5f5f5f5f5f	64	gnu	lea (%rcx),%rdx
+488d11|223344556677885f5f5f5f5f5f	64	intel	lea rdx, ptr [rcx]
+488d11|223344556677885f5f5f5f5f5f	64	plan9	LEAQ 0(CX), DX
+488e11|223344556677885f5f5f5f5f5f	64	gnu	mov (%rcx),%ss
+488e11|223344556677885f5f5f5f5f5f	64	intel	mov ss, word ptr [rcx]
+488e11|223344556677885f5f5f5f5f5f	64	plan9	MOVW 0(CX), SS
+488f00|11223344556677885f5f5f5f5f	64	gnu	popq (%rax)
+488f00|11223344556677885f5f5f5f5f	64	intel	pop qword ptr [rax]
+488f00|11223344556677885f5f5f5f5f	64	plan9	POPQ 0(AX)
+4891|11223344556677885f5f5f5f5f5f	64	gnu	xchg %rax,%rcx
+4891|11223344556677885f5f5f5f5f5f	64	intel	xchg rcx, rax
+4891|11223344556677885f5f5f5f5f5f	64	plan9	XCHGQ AX, CX
+4898|11223344556677885f5f5f5f5f5f	64	gnu	cdqe
+4898|11223344556677885f5f5f5f5f5f	64	intel	cdqe
+4898|11223344556677885f5f5f5f5f5f	64	plan9	CDQE
+4899|11223344556677885f5f5f5f5f5f	64	gnu	cqto
+4899|11223344556677885f5f5f5f5f5f	64	intel	cqo
+4899|11223344556677885f5f5f5f5f5f	64	plan9	CQO
+489c|11223344556677885f5f5f5f5f5f	64	gnu	pushfq
+489c|11223344556677885f5f5f5f5f5f	64	intel	pushfq
+489c|11223344556677885f5f5f5f5f5f	64	plan9	PUSHFQ
+489d|11223344556677885f5f5f5f5f5f	64	gnu	popfq
+489d|11223344556677885f5f5f5f5f5f	64	intel	popfq
+489d|11223344556677885f5f5f5f5f5f	64	plan9	POPFQ
+48a01122334455667788|5f5f5f5f5f5f	64	gnu	mov -0x778899aabbccddef,%al
+48a01122334455667788|5f5f5f5f5f5f	64	intel	mov al, byte ptr [0x8877665544332211]
+48a01122334455667788|5f5f5f5f5f5f	64	plan9	MOVB -0x778899aabbccddef, AL
+48a11122334455667788|5f5f5f5f5f5f	64	gnu	mov -0x778899aabbccddef,%rax
+48a11122334455667788|5f5f5f5f5f5f	64	intel	mov rax, qword ptr [0x8877665544332211]
+48a11122334455667788|5f5f5f5f5f5f	64	plan9	MOVQ -0x778899aabbccddef, AX
+48a21122334455667788|5f5f5f5f5f5f	64	gnu	mov %al,-0x778899aabbccddef
+48a21122334455667788|5f5f5f5f5f5f	64	intel	mov byte ptr [0x8877665544332211], al
+48a21122334455667788|5f5f5f5f5f5f	64	plan9	MOVB AL, -0x778899aabbccddef
+48a31122334455667788|5f5f5f5f5f5f	64	gnu	mov %rax,-0x778899aabbccddef
+48a31122334455667788|5f5f5f5f5f5f	64	intel	mov qword ptr [0x8877665544332211], rax
+48a31122334455667788|5f5f5f5f5f5f	64	plan9	MOVQ AX, -0x778899aabbccddef
+48a5|11223344556677885f5f5f5f5f5f	64	gnu	movsq %ds:(%rsi),%es:(%rdi)
+48a5|11223344556677885f5f5f5f5f5f	64	intel	movsq qword ptr [rdi], qword ptr [rsi]
+48a5|11223344556677885f5f5f5f5f5f	64	plan9	MOVSQ DS:0(SI), ES:0(DI)
+48a7|11223344556677885f5f5f5f5f5f	64	gnu	cmpsq %es:(%rdi),%ds:(%rsi)
+48a7|11223344556677885f5f5f5f5f5f	64	intel	cmpsq qword ptr [rsi], qword ptr [rdi]
+48a7|11223344556677885f5f5f5f5f5f	64	plan9	CMPSQ ES:0(DI), DS:0(SI)
+48a911223344|556677885f5f5f5f5f5f	64	gnu	test $0x44332211,%rax
+48a911223344|556677885f5f5f5f5f5f	64	intel	test rax, 0x44332211
+48a911223344|556677885f5f5f5f5f5f	64	plan9	TESTQ $0x44332211, AX
+48ab|11223344556677885f5f5f5f5f5f	64	gnu	stos %rax,%es:(%rdi)
+48ab|11223344556677885f5f5f5f5f5f	64	intel	stosq qword ptr [rdi]
+48ab|11223344556677885f5f5f5f5f5f	64	plan9	STOSQ AX, ES:0(DI)
+48ad|11223344556677885f5f5f5f5f5f	64	gnu	lods %ds:(%rsi),%rax
+48ad|11223344556677885f5f5f5f5f5f	64	intel	lodsq qword ptr [rsi]
+48ad|11223344556677885f5f5f5f5f5f	64	plan9	LODSQ DS:0(SI), AX
+48af|11223344556677885f5f5f5f5f5f	64	gnu	scas %es:(%rdi),%rax
+48af|11223344556677885f5f5f5f5f5f	64	intel	scasq qword ptr [rdi]
+48af|11223344556677885f5f5f5f5f5f	64	plan9	SCASQ ES:0(DI), AX
+48b81122334455667788|5f5f5f5f5f5f	64	gnu	mov $-0x778899aabbccddef,%rax
+48b81122334455667788|5f5f5f5f5f5f	64	intel	mov rax, 0x8877665544332211
+48b81122334455667788|5f5f5f5f5f5f	64	plan9	MOVQ $0x8877665544332211, AX
+48c10011|223344556677885f5f5f5f5f	64	gnu	rolq $0x11,(%rax)
+48c10011|223344556677885f5f5f5f5f	64	intel	rol qword ptr [rax], 0x11
+48c10011|223344556677885f5f5f5f5f	64	plan9	ROLQ $0x11, 0(AX)
+48c10811|223344556677885f5f5f5f5f	64	gnu	rorq $0x11,(%rax)
+48c10811|223344556677885f5f5f5f5f	64	intel	ror qword ptr [rax], 0x11
+48c10811|223344556677885f5f5f5f5f	64	plan9	RORQ $0x11, 0(AX)
+48c11122|3344556677885f5f5f5f5f5f	64	gnu	rclq $0x22,(%rcx)
+48c11122|3344556677885f5f5f5f5f5f	64	intel	rcl qword ptr [rcx], 0x22
+48c11122|3344556677885f5f5f5f5f5f	64	plan9	RCLQ $0x22, 0(CX)
+48c11811|223344556677885f5f5f5f5f	64	gnu	rcrq $0x11,(%rax)
+48c11811|223344556677885f5f5f5f5f	64	intel	rcr qword ptr [rax], 0x11
+48c11811|223344556677885f5f5f5f5f	64	plan9	RCRQ $0x11, 0(AX)
+48c12011|223344556677885f5f5f5f5f	64	gnu	shlq $0x11,(%rax)
+48c12011|223344556677885f5f5f5f5f	64	intel	shl qword ptr [rax], 0x11
+48c12011|223344556677885f5f5f5f5f	64	plan9	SHLQ $0x11, 0(AX)
+48c12811|223344556677885f5f5f5f5f	64	gnu	shrq $0x11,(%rax)
+48c12811|223344556677885f5f5f5f5f	64	intel	shr qword ptr [rax], 0x11
+48c12811|223344556677885f5f5f5f5f	64	plan9	SHRQ $0x11, 0(AX)
+48c13811|223344556677885f5f5f5f5f	64	gnu	sarq $0x11,(%rax)
+48c13811|223344556677885f5f5f5f5f	64	intel	sar qword ptr [rax], 0x11
+48c13811|223344556677885f5f5f5f5f	64	plan9	SARQ $0x11, 0(AX)
+48c70011223344|556677885f5f5f5f5f	64	gnu	movq $0x44332211,(%rax)
+48c70011223344|556677885f5f5f5f5f	64	intel	mov qword ptr [rax], 0x44332211
+48c70011223344|556677885f5f5f5f5f	64	plan9	MOVQ $0x44332211, 0(AX)
+48c7f811223344|556677885f5f5f5f5f	64	gnu	xbeginq .+0x44332211
+48c7f811223344|556677885f5f5f5f5f	64	intel	xbegin .+0x44332211
+48c7f811223344|556677885f5f5f5f5f	64	plan9	XBEGIN .+1144201745
+48c9|11223344556677885f5f5f5f5f5f	64	gnu	leaveq
+48c9|11223344556677885f5f5f5f5f5f	64	intel	leave
+48c9|11223344556677885f5f5f5f5f5f	64	plan9	LEAVE
+48cf|11223344556677885f5f5f5f5f5f	64	gnu	iretq
+48cf|11223344556677885f5f5f5f5f5f	64	intel	iretq
+48cf|11223344556677885f5f5f5f5f5f	64	plan9	IRETQ
+48d100|11223344556677885f5f5f5f5f	64	gnu	rolq (%rax)
+48d100|11223344556677885f5f5f5f5f	64	intel	rol qword ptr [rax], 0x1
+48d100|11223344556677885f5f5f5f5f	64	plan9	ROLQ $0x1, 0(AX)
+48d108|11223344556677885f5f5f5f5f	64	gnu	rorq (%rax)
+48d108|11223344556677885f5f5f5f5f	64	intel	ror qword ptr [rax], 0x1
+48d108|11223344556677885f5f5f5f5f	64	plan9	RORQ $0x1, 0(AX)
+48d111|223344556677885f5f5f5f5f5f	64	gnu	rclq (%rcx)
+48d111|223344556677885f5f5f5f5f5f	64	intel	rcl qword ptr [rcx], 0x1
+48d111|223344556677885f5f5f5f5f5f	64	plan9	RCLQ $0x1, 0(CX)
+48d118|11223344556677885f5f5f5f5f	64	gnu	rcrq (%rax)
+48d118|11223344556677885f5f5f5f5f	64	intel	rcr qword ptr [rax], 0x1
+48d118|11223344556677885f5f5f5f5f	64	plan9	RCRQ $0x1, 0(AX)
+48d120|11223344556677885f5f5f5f5f	64	gnu	shlq (%rax)
+48d120|11223344556677885f5f5f5f5f	64	intel	shl qword ptr [rax], 0x1
+48d120|11223344556677885f5f5f5f5f	64	plan9	SHLQ $0x1, 0(AX)
+48d128|11223344556677885f5f5f5f5f	64	gnu	shrq (%rax)
+48d128|11223344556677885f5f5f5f5f	64	intel	shr qword ptr [rax], 0x1
+48d128|11223344556677885f5f5f5f5f	64	plan9	SHRQ $0x1, 0(AX)
+48d138|11223344556677885f5f5f5f5f	64	gnu	sarq (%rax)
+48d138|11223344556677885f5f5f5f5f	64	intel	sar qword ptr [rax], 0x1
+48d138|11223344556677885f5f5f5f5f	64	plan9	SARQ $0x1, 0(AX)
+48d300|11223344556677885f5f5f5f5f	64	gnu	rolq %cl,(%rax)
+48d300|11223344556677885f5f5f5f5f	64	intel	rol qword ptr [rax], cl
+48d300|11223344556677885f5f5f5f5f	64	plan9	ROLQ CL, 0(AX)
+48d308|11223344556677885f5f5f5f5f	64	gnu	rorq %cl,(%rax)
+48d308|11223344556677885f5f5f5f5f	64	intel	ror qword ptr [rax], cl
+48d308|11223344556677885f5f5f5f5f	64	plan9	RORQ CL, 0(AX)
+48d311|223344556677885f5f5f5f5f5f	64	gnu	rclq %cl,(%rcx)
+48d311|223344556677885f5f5f5f5f5f	64	intel	rcl qword ptr [rcx], cl
+48d311|223344556677885f5f5f5f5f5f	64	plan9	RCLQ CL, 0(CX)
+48d318|11223344556677885f5f5f5f5f	64	gnu	rcrq %cl,(%rax)
+48d318|11223344556677885f5f5f5f5f	64	intel	rcr qword ptr [rax], cl
+48d318|11223344556677885f5f5f5f5f	64	plan9	RCRQ CL, 0(AX)
+48d320|11223344556677885f5f5f5f5f	64	gnu	shlq %cl,(%rax)
+48d320|11223344556677885f5f5f5f5f	64	intel	shl qword ptr [rax], cl
+48d320|11223344556677885f5f5f5f5f	64	plan9	SHLQ CL, 0(AX)
+48d328|11223344556677885f5f5f5f5f	64	gnu	shrq %cl,(%rax)
+48d328|11223344556677885f5f5f5f5f	64	intel	shr qword ptr [rax], cl
+48d328|11223344556677885f5f5f5f5f	64	plan9	SHRQ CL, 0(AX)
+48d338|11223344556677885f5f5f5f5f	64	gnu	sarq %cl,(%rax)
+48d338|11223344556677885f5f5f5f5f	64	intel	sar qword ptr [rax], cl
+48d338|11223344556677885f5f5f5f5f	64	plan9	SARQ CL, 0(AX)
+48d7|11223344556677885f5f5f5f5f5f	64	gnu	xlat %ds:(%rbx)
+48d7|11223344556677885f5f5f5f5f5f	64	intel	xlat
+48d7|11223344556677885f5f5f5f5f5f	64	plan9	XLATB DS:0(BX)
+48e511|223344556677885f5f5f5f5f5f	64	gnu	in $0x11,%eax
+48e511|223344556677885f5f5f5f5f5f	64	intel	in eax, 0x11
+48e511|223344556677885f5f5f5f5f5f	64	plan9	INQ $0x11, AX
+48e711|223344556677885f5f5f5f5f5f	64	gnu	out %eax,$0x11
+48e711|223344556677885f5f5f5f5f5f	64	intel	out 0x11, eax
+48e711|223344556677885f5f5f5f5f5f	64	plan9	OUTQ AX, $0x11
+48e811223344|556677885f5f5f5f5f5f	64	gnu	callq .+0x44332211
+48e811223344|556677885f5f5f5f5f5f	64	intel	call .+0x44332211
+48e811223344|556677885f5f5f5f5f5f	64	plan9	CALL .+1144201745
+48e911223344|556677885f5f5f5f5f5f	64	gnu	jmpq .+0x44332211
+48e911223344|556677885f5f5f5f5f5f	64	intel	jmp .+0x44332211
+48e911223344|556677885f5f5f5f5f5f	64	plan9	JMP .+1144201745
+48ed|11223344556677885f5f5f5f5f5f	64	gnu	in (%dx),%eax
+48ed|11223344556677885f5f5f5f5f5f	64	intel	in eax, dx
+48ed|11223344556677885f5f5f5f5f5f	64	plan9	INQ DX, AX
+48ef|11223344556677885f5f5f5f5f5f	64	gnu	out %eax,(%dx)
+48ef|11223344556677885f5f5f5f5f5f	64	intel	out dx, eax
+48ef|11223344556677885f5f5f5f5f5f	64	plan9	OUTQ AX, DX
+48f70011223344|556677885f5f5f5f5f	64	gnu	testq $0x44332211,(%rax)
+48f70011223344|556677885f5f5f5f5f	64	intel	test qword ptr [rax], 0x44332211
+48f70011223344|556677885f5f5f5f5f	64	plan9	TESTQ $0x44332211, 0(AX)
+48f711|223344556677885f5f5f5f5f5f	64	gnu	notq (%rcx)
+48f711|223344556677885f5f5f5f5f5f	64	intel	not qword ptr [rcx]
+48f711|223344556677885f5f5f5f5f5f	64	plan9	NOTQ 0(CX)
+48f718|11223344556677885f5f5f5f5f	64	gnu	negq (%rax)
+48f718|11223344556677885f5f5f5f5f	64	intel	neg qword ptr [rax]
+48f718|11223344556677885f5f5f5f5f	64	plan9	NEGQ 0(AX)
+48f720|11223344556677885f5f5f5f5f	64	gnu	mulq (%rax)
+48f720|11223344556677885f5f5f5f5f	64	intel	mul qword ptr [rax]
+48f720|11223344556677885f5f5f5f5f	64	plan9	MULQ 0(AX)
+48f728|11223344556677885f5f5f5f5f	64	gnu	imulq (%rax)
+48f728|11223344556677885f5f5f5f5f	64	intel	imul qword ptr [rax]
+48f728|11223344556677885f5f5f5f5f	64	plan9	IMULQ 0(AX)
+48f730|11223344556677885f5f5f5f5f	64	gnu	divq (%rax)
+48f730|11223344556677885f5f5f5f5f	64	intel	div qword ptr [rax]
+48f730|11223344556677885f5f5f5f5f	64	plan9	DIVQ 0(AX)
+48f738|11223344556677885f5f5f5f5f	64	gnu	idivq (%rax)
+48f738|11223344556677885f5f5f5f5f	64	intel	idiv qword ptr [rax]
+48f738|11223344556677885f5f5f5f5f	64	plan9	IDIVQ 0(AX)
+48ff00|11223344556677885f5f5f5f5f	64	gnu	incq (%rax)
+48ff00|11223344556677885f5f5f5f5f	64	intel	inc qword ptr [rax]
+48ff00|11223344556677885f5f5f5f5f	64	plan9	INCQ 0(AX)
+48ff08|11223344556677885f5f5f5f5f	64	gnu	decq (%rax)
+48ff08|11223344556677885f5f5f5f5f	64	intel	dec qword ptr [rax]
+48ff08|11223344556677885f5f5f5f5f	64	plan9	DECQ 0(AX)
+48ff18|11223344556677885f5f5f5f5f	64	gnu	lcallq *(%rax)
+48ff18|11223344556677885f5f5f5f5f	64	intel	call far ptr [rax]
+48ff18|11223344556677885f5f5f5f5f	64	plan9	LCALL 0(AX)
+48ff28|11223344556677885f5f5f5f5f	64	gnu	ljmpq *(%rax)
+48ff28|11223344556677885f5f5f5f5f	64	intel	jmp far ptr [rax]
+48ff28|11223344556677885f5f5f5f5f	64	plan9	LJMP 0(AX)
+48ff30|11223344556677885f5f5f5f5f	64	gnu	pushq (%rax)
+48ff30|11223344556677885f5f5f5f5f	64	intel	push qword ptr [rax]
+48ff30|11223344556677885f5f5f5f5f	64	plan9	PUSHQ 0(AX)
+48|010011223344556677885f5f5f5f5f	32	intel	dec eax
+48|010011223344556677885f5f5f5f5f	32	plan9	DECL AX
+50|11223344556677885f5f5f5f5f5f5f	32	intel	push eax
+50|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL AX
+50|11223344556677885f5f5f5f5f5f5f	64	gnu	push %rax
+50|11223344556677885f5f5f5f5f5f5f	64	intel	push rax
+50|11223344556677885f5f5f5f5f5f5f	64	plan9	PUSHL AX
+58|11223344556677885f5f5f5f5f5f5f	32	intel	pop eax
+58|11223344556677885f5f5f5f5f5f5f	32	plan9	POPL AX
+58|11223344556677885f5f5f5f5f5f5f	64	gnu	pop %rax
+58|11223344556677885f5f5f5f5f5f5f	64	intel	pop rax
+58|11223344556677885f5f5f5f5f5f5f	64	plan9	POPL AX
+60|11223344556677885f5f5f5f5f5f5f	32	intel	pushad
+60|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHAD
+60|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+60|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+60|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+61|11223344556677885f5f5f5f5f5f5f	32	intel	popad
+61|11223344556677885f5f5f5f5f5f5f	32	plan9	POPAD
+61|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+61|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+61|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+6211|223344556677885f5f5f5f5f5f5f	32	intel	bound edx, qword ptr [ecx]
+6211|223344556677885f5f5f5f5f5f5f	32	plan9	BOUND 0(CX), DX
+62|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+62|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+62|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+6311|223344556677885f5f5f5f5f5f5f	32	intel	arpl word ptr [ecx], dx
+6311|223344556677885f5f5f5f5f5f5f	32	plan9	ARPL DX, 0(CX)
+6311|223344556677885f5f5f5f5f5f5f	64	gnu	movsxd (%rcx),%edx
+6311|223344556677885f5f5f5f5f5f5f	64	intel	movsxd edx, dword ptr [rcx]
+6311|223344556677885f5f5f5f5f5f5f	64	plan9	MOVSXD 0(CX), DX
+660111|223344556677885f5f5f5f5f5f	32	intel	add word ptr [ecx], dx
+660111|223344556677885f5f5f5f5f5f	32	plan9	ADDW DX, 0(CX)
+660111|223344556677885f5f5f5f5f5f	64	gnu	add %dx,(%rcx)
+660111|223344556677885f5f5f5f5f5f	64	intel	add word ptr [rcx], dx
+660111|223344556677885f5f5f5f5f5f	64	plan9	ADDW DX, 0(CX)
+660311|223344556677885f5f5f5f5f5f	32	intel	add dx, word ptr [ecx]
+660311|223344556677885f5f5f5f5f5f	32	plan9	ADDW 0(CX), DX
+660311|223344556677885f5f5f5f5f5f	64	gnu	add (%rcx),%dx
+660311|223344556677885f5f5f5f5f5f	64	intel	add dx, word ptr [rcx]
+660311|223344556677885f5f5f5f5f5f	64	plan9	ADDW 0(CX), DX
+66051122|3344556677885f5f5f5f5f5f	32	intel	add ax, 0x2211
+66051122|3344556677885f5f5f5f5f5f	32	plan9	ADDW $0x2211, AX
+66051122|3344556677885f5f5f5f5f5f	64	gnu	add $0x2211,%ax
+66051122|3344556677885f5f5f5f5f5f	64	intel	add ax, 0x2211
+66051122|3344556677885f5f5f5f5f5f	64	plan9	ADDW $0x2211, AX
+660911|223344556677885f5f5f5f5f5f	32	intel	or word ptr [ecx], dx
+660911|223344556677885f5f5f5f5f5f	32	plan9	ORW DX, 0(CX)
+660911|223344556677885f5f5f5f5f5f	64	gnu	or %dx,(%rcx)
+660911|223344556677885f5f5f5f5f5f	64	intel	or word ptr [rcx], dx
+660911|223344556677885f5f5f5f5f5f	64	plan9	ORW DX, 0(CX)
+660b11|223344556677885f5f5f5f5f5f	32	intel	or dx, word ptr [ecx]
+660b11|223344556677885f5f5f5f5f5f	32	plan9	ORW 0(CX), DX
+660b11|223344556677885f5f5f5f5f5f	64	gnu	or (%rcx),%dx
+660b11|223344556677885f5f5f5f5f5f	64	intel	or dx, word ptr [rcx]
+660b11|223344556677885f5f5f5f5f5f	64	plan9	ORW 0(CX), DX
+660d1122|3344556677885f5f5f5f5f5f	32	intel	or ax, 0x2211
+660d1122|3344556677885f5f5f5f5f5f	32	plan9	ORW $0x2211, AX
+660d1122|3344556677885f5f5f5f5f5f	64	gnu	or $0x2211,%ax
+660d1122|3344556677885f5f5f5f5f5f	64	intel	or ax, 0x2211
+660d1122|3344556677885f5f5f5f5f5f	64	plan9	ORW $0x2211, AX
+660f0000|11223344556677885f5f5f5f	32	intel	sldt word ptr [eax]
+660f0000|11223344556677885f5f5f5f	32	plan9	SLDT 0(AX)
+660f0000|11223344556677885f5f5f5f	64	gnu	data16 sldt (%rax)
+660f0000|11223344556677885f5f5f5f	64	intel	sldt word ptr [rax]
+660f0000|11223344556677885f5f5f5f	64	plan9	SLDT 0(AX)
+660f0008|11223344556677885f5f5f5f	32	intel	str word ptr [eax]
+660f0008|11223344556677885f5f5f5f	32	plan9	STR 0(AX)
+660f0008|11223344556677885f5f5f5f	64	gnu	data16 str (%rax)
+660f0008|11223344556677885f5f5f5f	64	intel	str word ptr [rax]
+660f0008|11223344556677885f5f5f5f	64	plan9	STR 0(AX)
+660f01a611223344|556677885f5f5f5f	32	intel	smsw word ptr [esi+0x44332211]
+660f01a611223344|556677885f5f5f5f	32	plan9	SMSW 0x44332211(SI)
+660f01a611223344|556677885f5f5f5f	64	gnu	data16 smsw 0x44332211(%rsi)
+660f01a611223344|556677885f5f5f5f	64	intel	smsw word ptr [rsi+0x44332211]
+660f01a611223344|556677885f5f5f5f	64	plan9	SMSW 0x44332211(SI)
+660f0211|223344556677885f5f5f5f5f	32	intel	lar dx, word ptr [ecx]
+660f0211|223344556677885f5f5f5f5f	32	plan9	LAR 0(CX), DX
+660f0211|223344556677885f5f5f5f5f	64	gnu	lar (%rcx),%dx
+660f0211|223344556677885f5f5f5f5f	64	intel	lar dx, word ptr [rcx]
+660f0211|223344556677885f5f5f5f5f	64	plan9	LAR 0(CX), DX
+660f0311|223344556677885f5f5f5f5f	32	intel	lsl dx, word ptr [ecx]
+660f0311|223344556677885f5f5f5f5f	32	plan9	LSL 0(CX), DX
+660f0311|223344556677885f5f5f5f5f	64	gnu	lsl (%rcx),%dx
+660f0311|223344556677885f5f5f5f5f	64	intel	lsl dx, word ptr [rcx]
+660f0311|223344556677885f5f5f5f5f	64	plan9	LSL 0(CX), DX
+660f1011|223344556677885f5f5f5f5f	32	intel	movupd xmm2, xmmword ptr [ecx]
+660f1011|223344556677885f5f5f5f5f	32	plan9	MOVUPD 0(CX), X2
+660f1011|223344556677885f5f5f5f5f	64	gnu	movupd (%rcx),%xmm2
+660f1011|223344556677885f5f5f5f5f	64	intel	movupd xmm2, xmmword ptr [rcx]
+660f1011|223344556677885f5f5f5f5f	64	plan9	MOVUPD 0(CX), X2
+660f1122|3344556677885f5f5f5f5f5f	32	intel	movupd xmmword ptr [edx], xmm4
+660f1122|3344556677885f5f5f5f5f5f	32	plan9	MOVUPD X4, 0(DX)
+660f1122|3344556677885f5f5f5f5f5f	64	gnu	movupd %xmm4,(%rdx)
+660f1122|3344556677885f5f5f5f5f5f	64	intel	movupd xmmword ptr [rdx], xmm4
+660f1122|3344556677885f5f5f5f5f5f	64	plan9	MOVUPD X4, 0(DX)
+660f1211|223344556677885f5f5f5f5f	32	intel	movlpd xmm2, qword ptr [ecx]
+660f1211|223344556677885f5f5f5f5f	32	plan9	MOVLPD 0(CX), X2
+660f1211|223344556677885f5f5f5f5f	64	gnu	movlpd (%rcx),%xmm2
+660f1211|223344556677885f5f5f5f5f	64	intel	movlpd xmm2, qword ptr [rcx]
+660f1211|223344556677885f5f5f5f5f	64	plan9	MOVLPD 0(CX), X2
+660f1311|223344556677885f5f5f5f5f	32	intel	movlpd qword ptr [ecx], xmm2
+660f1311|223344556677885f5f5f5f5f	32	plan9	MOVLPD X2, 0(CX)
+660f1311|223344556677885f5f5f5f5f	64	gnu	movlpd %xmm2,(%rcx)
+660f1311|223344556677885f5f5f5f5f	64	intel	movlpd qword ptr [rcx], xmm2
+660f1311|223344556677885f5f5f5f5f	64	plan9	MOVLPD X2, 0(CX)
+660f1411|223344556677885f5f5f5f5f	32	intel	unpcklpd xmm2, xmmword ptr [ecx]
+660f1411|223344556677885f5f5f5f5f	32	plan9	UNPCKLPD 0(CX), X2
+660f1411|223344556677885f5f5f5f5f	64	gnu	unpcklpd (%rcx),%xmm2
+660f1411|223344556677885f5f5f5f5f	64	intel	unpcklpd xmm2, xmmword ptr [rcx]
+660f1411|223344556677885f5f5f5f5f	64	plan9	UNPCKLPD 0(CX), X2
+660f1511|223344556677885f5f5f5f5f	32	intel	unpckhpd xmm2, xmmword ptr [ecx]
+660f1511|223344556677885f5f5f5f5f	32	plan9	UNPCKHPD 0(CX), X2
+660f1511|223344556677885f5f5f5f5f	64	gnu	unpckhpd (%rcx),%xmm2
+660f1511|223344556677885f5f5f5f5f	64	intel	unpckhpd xmm2, xmmword ptr [rcx]
+660f1511|223344556677885f5f5f5f5f	64	plan9	UNPCKHPD 0(CX), X2
+660f1611|223344556677885f5f5f5f5f	32	intel	movhpd xmm2, qword ptr [ecx]
+660f1611|223344556677885f5f5f5f5f	32	plan9	MOVHPD 0(CX), X2
+660f1611|223344556677885f5f5f5f5f	64	gnu	movhpd (%rcx),%xmm2
+660f1611|223344556677885f5f5f5f5f	64	intel	movhpd xmm2, qword ptr [rcx]
+660f1611|223344556677885f5f5f5f5f	64	plan9	MOVHPD 0(CX), X2
+660f1711|223344556677885f5f5f5f5f	32	intel	movhpd qword ptr [ecx], xmm2
+660f1711|223344556677885f5f5f5f5f	32	plan9	MOVHPD X2, 0(CX)
+660f1711|223344556677885f5f5f5f5f	64	gnu	movhpd %xmm2,(%rcx)
+660f1711|223344556677885f5f5f5f5f	64	intel	movhpd qword ptr [rcx], xmm2
+660f1711|223344556677885f5f5f5f5f	64	plan9	MOVHPD X2, 0(CX)
+660f1f00|11223344556677885f5f5f5f	32	intel	nop word ptr [eax], ax
+660f1f00|11223344556677885f5f5f5f	32	plan9	NOPW 0(AX)
+660f1f00|11223344556677885f5f5f5f	64	gnu	nopw (%rax)
+660f1f00|11223344556677885f5f5f5f	64	intel	nop word ptr [rax], ax
+660f1f00|11223344556677885f5f5f5f	64	plan9	NOPW 0(AX)
+660f2811|223344556677885f5f5f5f5f	32	intel	movapd xmm2, xmmword ptr [ecx]
+660f2811|223344556677885f5f5f5f5f	32	plan9	MOVAPD 0(CX), X2
+660f2811|223344556677885f5f5f5f5f	64	gnu	movapd (%rcx),%xmm2
+660f2811|223344556677885f5f5f5f5f	64	intel	movapd xmm2, xmmword ptr [rcx]
+660f2811|223344556677885f5f5f5f5f	64	plan9	MOVAPD 0(CX), X2
+660f2911|223344556677885f5f5f5f5f	32	intel	movapd xmmword ptr [ecx], xmm2
+660f2911|223344556677885f5f5f5f5f	32	plan9	MOVAPD X2, 0(CX)
+660f2911|223344556677885f5f5f5f5f	64	gnu	movapd %xmm2,(%rcx)
+660f2911|223344556677885f5f5f5f5f	64	intel	movapd xmmword ptr [rcx], xmm2
+660f2911|223344556677885f5f5f5f5f	64	plan9	MOVAPD X2, 0(CX)
+660f2a11|223344556677885f5f5f5f5f	32	intel	cvtpi2pd xmm2, qword ptr [ecx]
+660f2a11|223344556677885f5f5f5f5f	32	plan9	CVTPI2PD 0(CX), X2
+660f2a11|223344556677885f5f5f5f5f	64	gnu	cvtpi2pd (%rcx),%xmm2
+660f2a11|223344556677885f5f5f5f5f	64	intel	cvtpi2pd xmm2, qword ptr [rcx]
+660f2a11|223344556677885f5f5f5f5f	64	plan9	CVTPI2PD 0(CX), X2
+660f2b11|223344556677885f5f5f5f5f	32	intel	movntpd xmmword ptr [ecx], xmm2
+660f2b11|223344556677885f5f5f5f5f	32	plan9	MOVNTPD X2, 0(CX)
+660f2b11|223344556677885f5f5f5f5f	64	gnu	movntpd %xmm2,(%rcx)
+660f2b11|223344556677885f5f5f5f5f	64	intel	movntpd xmmword ptr [rcx], xmm2
+660f2b11|223344556677885f5f5f5f5f	64	plan9	MOVNTPD X2, 0(CX)
+660f2c11|223344556677885f5f5f5f5f	32	intel	cvttpd2pi mmx2, xmmword ptr [ecx]
+660f2c11|223344556677885f5f5f5f5f	32	plan9	CVTTPD2PI 0(CX), M2
+660f2c11|223344556677885f5f5f5f5f	64	gnu	cvttpd2pi (%rcx),%mm2
+660f2c11|223344556677885f5f5f5f5f	64	intel	cvttpd2pi mmx2, xmmword ptr [rcx]
+660f2c11|223344556677885f5f5f5f5f	64	plan9	CVTTPD2PI 0(CX), M2
+660f2d11|223344556677885f5f5f5f5f	32	intel	cvtpd2pi mmx2, xmmword ptr [ecx]
+660f2d11|223344556677885f5f5f5f5f	32	plan9	CVTPD2PI 0(CX), M2
+660f2d11|223344556677885f5f5f5f5f	64	gnu	cvtpd2pi (%rcx),%mm2
+660f2d11|223344556677885f5f5f5f5f	64	intel	cvtpd2pi mmx2, xmmword ptr [rcx]
+660f2d11|223344556677885f5f5f5f5f	64	plan9	CVTPD2PI 0(CX), M2
+660f2e11|223344556677885f5f5f5f5f	32	intel	ucomisd xmm2, qword ptr [ecx]
+660f2e11|223344556677885f5f5f5f5f	32	plan9	UCOMISD 0(CX), X2
+660f2e11|223344556677885f5f5f5f5f	64	gnu	ucomisd (%rcx),%xmm2
+660f2e11|223344556677885f5f5f5f5f	64	intel	ucomisd xmm2, qword ptr [rcx]
+660f2e11|223344556677885f5f5f5f5f	64	plan9	UCOMISD 0(CX), X2
+660f2f11|223344556677885f5f5f5f5f	32	intel	comisd xmm2, qword ptr [ecx]
+660f2f11|223344556677885f5f5f5f5f	32	plan9	COMISD 0(CX), X2
+660f2f11|223344556677885f5f5f5f5f	64	gnu	comisd (%rcx),%xmm2
+660f2f11|223344556677885f5f5f5f5f	64	intel	comisd xmm2, qword ptr [rcx]
+660f2f11|223344556677885f5f5f5f5f	64	plan9	COMISD 0(CX), X2
+660f380011|223344556677885f5f5f5f	32	intel	pshufb xmm2, xmmword ptr [ecx]
+660f380011|223344556677885f5f5f5f	32	plan9	PSHUFB 0(CX), X2
+660f380011|223344556677885f5f5f5f	64	gnu	pshufb (%rcx),%xmm2
+660f380011|223344556677885f5f5f5f	64	intel	pshufb xmm2, xmmword ptr [rcx]
+660f380011|223344556677885f5f5f5f	64	plan9	PSHUFB 0(CX), X2
+660f380111|223344556677885f5f5f5f	32	intel	phaddw xmm2, xmmword ptr [ecx]
+660f380111|223344556677885f5f5f5f	32	plan9	PHADDW 0(CX), X2
+660f380111|223344556677885f5f5f5f	64	gnu	phaddw (%rcx),%xmm2
+660f380111|223344556677885f5f5f5f	64	intel	phaddw xmm2, xmmword ptr [rcx]
+660f380111|223344556677885f5f5f5f	64	plan9	PHADDW 0(CX), X2
+660f380211|223344556677885f5f5f5f	32	intel	phaddd xmm2, xmmword ptr [ecx]
+660f380211|223344556677885f5f5f5f	32	plan9	PHADDD 0(CX), X2
+660f380211|223344556677885f5f5f5f	64	gnu	phaddd (%rcx),%xmm2
+660f380211|223344556677885f5f5f5f	64	intel	phaddd xmm2, xmmword ptr [rcx]
+660f380211|223344556677885f5f5f5f	64	plan9	PHADDD 0(CX), X2
+660f380311|223344556677885f5f5f5f	32	intel	phaddsw xmm2, xmmword ptr [ecx]
+660f380311|223344556677885f5f5f5f	32	plan9	PHADDSW 0(CX), X2
+660f380311|223344556677885f5f5f5f	64	gnu	phaddsw (%rcx),%xmm2
+660f380311|223344556677885f5f5f5f	64	intel	phaddsw xmm2, xmmword ptr [rcx]
+660f380311|223344556677885f5f5f5f	64	plan9	PHADDSW 0(CX), X2
+660f380411|223344556677885f5f5f5f	32	intel	pmaddubsw xmm2, xmmword ptr [ecx]
+660f380411|223344556677885f5f5f5f	32	plan9	PMADDUBSW 0(CX), X2
+660f380411|223344556677885f5f5f5f	64	gnu	pmaddubsw (%rcx),%xmm2
+660f380411|223344556677885f5f5f5f	64	intel	pmaddubsw xmm2, xmmword ptr [rcx]
+660f380411|223344556677885f5f5f5f	64	plan9	PMADDUBSW 0(CX), X2
+660f380511|223344556677885f5f5f5f	32	intel	phsubw xmm2, xmmword ptr [ecx]
+660f380511|223344556677885f5f5f5f	32	plan9	PHSUBW 0(CX), X2
+660f380511|223344556677885f5f5f5f	64	gnu	phsubw (%rcx),%xmm2
+660f380511|223344556677885f5f5f5f	64	intel	phsubw xmm2, xmmword ptr [rcx]
+660f380511|223344556677885f5f5f5f	64	plan9	PHSUBW 0(CX), X2
+660f380611|223344556677885f5f5f5f	32	intel	phsubd xmm2, xmmword ptr [ecx]
+660f380611|223344556677885f5f5f5f	32	plan9	PHSUBD 0(CX), X2
+660f380611|223344556677885f5f5f5f	64	gnu	phsubd (%rcx),%xmm2
+660f380611|223344556677885f5f5f5f	64	intel	phsubd xmm2, xmmword ptr [rcx]
+660f380611|223344556677885f5f5f5f	64	plan9	PHSUBD 0(CX), X2
+660f380711|223344556677885f5f5f5f	32	intel	phsubsw xmm2, xmmword ptr [ecx]
+660f380711|223344556677885f5f5f5f	32	plan9	PHSUBSW 0(CX), X2
+660f380711|223344556677885f5f5f5f	64	gnu	phsubsw (%rcx),%xmm2
+660f380711|223344556677885f5f5f5f	64	intel	phsubsw xmm2, xmmword ptr [rcx]
+660f380711|223344556677885f5f5f5f	64	plan9	PHSUBSW 0(CX), X2
+660f380811|223344556677885f5f5f5f	32	intel	psignb xmm2, xmmword ptr [ecx]
+660f380811|223344556677885f5f5f5f	32	plan9	PSIGNB 0(CX), X2
+660f380811|223344556677885f5f5f5f	64	gnu	psignb (%rcx),%xmm2
+660f380811|223344556677885f5f5f5f	64	intel	psignb xmm2, xmmword ptr [rcx]
+660f380811|223344556677885f5f5f5f	64	plan9	PSIGNB 0(CX), X2
+660f380911|223344556677885f5f5f5f	32	intel	psignw xmm2, xmmword ptr [ecx]
+660f380911|223344556677885f5f5f5f	32	plan9	PSIGNW 0(CX), X2
+660f380911|223344556677885f5f5f5f	64	gnu	psignw (%rcx),%xmm2
+660f380911|223344556677885f5f5f5f	64	intel	psignw xmm2, xmmword ptr [rcx]
+660f380911|223344556677885f5f5f5f	64	plan9	PSIGNW 0(CX), X2
+660f380a11|223344556677885f5f5f5f	32	intel	psignd xmm2, xmmword ptr [ecx]
+660f380a11|223344556677885f5f5f5f	32	plan9	PSIGND 0(CX), X2
+660f380a11|223344556677885f5f5f5f	64	gnu	psignd (%rcx),%xmm2
+660f380a11|223344556677885f5f5f5f	64	intel	psignd xmm2, xmmword ptr [rcx]
+660f380a11|223344556677885f5f5f5f	64	plan9	PSIGND 0(CX), X2
+660f380b11|223344556677885f5f5f5f	32	intel	pmulhrsw xmm2, xmmword ptr [ecx]
+660f380b11|223344556677885f5f5f5f	32	plan9	PMULHRSW 0(CX), X2
+660f380b11|223344556677885f5f5f5f	64	gnu	pmulhrsw (%rcx),%xmm2
+660f380b11|223344556677885f5f5f5f	64	intel	pmulhrsw xmm2, xmmword ptr [rcx]
+660f380b11|223344556677885f5f5f5f	64	plan9	PMULHRSW 0(CX), X2
+660f381011|223344556677885f5f5f5f	32	intel	pblendvb xmm2, xmmword ptr [ecx]
+660f381011|223344556677885f5f5f5f	32	plan9	PBLENDVB X0, 0(CX), X2
+660f381011|223344556677885f5f5f5f	64	gnu	pblendvb %xmm0,(%rcx),%xmm2
+660f381011|223344556677885f5f5f5f	64	intel	pblendvb xmm2, xmmword ptr [rcx]
+660f381011|223344556677885f5f5f5f	64	plan9	PBLENDVB X0, 0(CX), X2
+660f381411|223344556677885f5f5f5f	32	intel	blendvps xmm2, xmmword ptr [ecx]
+660f381411|223344556677885f5f5f5f	32	plan9	BLENDVPS X0, 0(CX), X2
+660f381411|223344556677885f5f5f5f	64	gnu	blendvps %xmm0,(%rcx),%xmm2
+660f381411|223344556677885f5f5f5f	64	intel	blendvps xmm2, xmmword ptr [rcx]
+660f381411|223344556677885f5f5f5f	64	plan9	BLENDVPS X0, 0(CX), X2
+660f381511|223344556677885f5f5f5f	32	intel	blendvpd xmm2, xmmword ptr [ecx]
+660f381511|223344556677885f5f5f5f	32	plan9	BLENDVPD X0, 0(CX), X2
+660f381511|223344556677885f5f5f5f	64	gnu	blendvpd %xmm0,(%rcx),%xmm2
+660f381511|223344556677885f5f5f5f	64	intel	blendvpd xmm2, xmmword ptr [rcx]
+660f381511|223344556677885f5f5f5f	64	plan9	BLENDVPD X0, 0(CX), X2
+660f381711|223344556677885f5f5f5f	32	intel	ptest xmm2, xmmword ptr [ecx]
+660f381711|223344556677885f5f5f5f	32	plan9	PTEST 0(CX), X2
+660f381711|223344556677885f5f5f5f	64	gnu	ptest (%rcx),%xmm2
+660f381711|223344556677885f5f5f5f	64	intel	ptest xmm2, xmmword ptr [rcx]
+660f381711|223344556677885f5f5f5f	64	plan9	PTEST 0(CX), X2
+660f381c11|223344556677885f5f5f5f	32	intel	pabsb xmm2, xmmword ptr [ecx]
+660f381c11|223344556677885f5f5f5f	32	plan9	PABSB 0(CX), X2
+660f381c11|223344556677885f5f5f5f	64	gnu	pabsb (%rcx),%xmm2
+660f381c11|223344556677885f5f5f5f	64	intel	pabsb xmm2, xmmword ptr [rcx]
+660f381c11|223344556677885f5f5f5f	64	plan9	PABSB 0(CX), X2
+660f381d11|223344556677885f5f5f5f	32	intel	pabsw xmm2, xmmword ptr [ecx]
+660f381d11|223344556677885f5f5f5f	32	plan9	PABSW 0(CX), X2
+660f381d11|223344556677885f5f5f5f	64	gnu	pabsw (%rcx),%xmm2
+660f381d11|223344556677885f5f5f5f	64	intel	pabsw xmm2, xmmword ptr [rcx]
+660f381d11|223344556677885f5f5f5f	64	plan9	PABSW 0(CX), X2
+660f381e11|223344556677885f5f5f5f	32	intel	pabsd xmm2, xmmword ptr [ecx]
+660f381e11|223344556677885f5f5f5f	32	plan9	PABSD 0(CX), X2
+660f381e11|223344556677885f5f5f5f	64	gnu	pabsd (%rcx),%xmm2
+660f381e11|223344556677885f5f5f5f	64	intel	pabsd xmm2, xmmword ptr [rcx]
+660f381e11|223344556677885f5f5f5f	64	plan9	PABSD 0(CX), X2
+660f382011|223344556677885f5f5f5f	32	intel	pmovsxbw xmm2, qword ptr [ecx]
+660f382011|223344556677885f5f5f5f	32	plan9	PMOVSXBW 0(CX), X2
+660f382011|223344556677885f5f5f5f	64	gnu	pmovsxbw (%rcx),%xmm2
+660f382011|223344556677885f5f5f5f	64	intel	pmovsxbw xmm2, qword ptr [rcx]
+660f382011|223344556677885f5f5f5f	64	plan9	PMOVSXBW 0(CX), X2
+660f382111|223344556677885f5f5f5f	32	intel	pmovsxbd xmm2, dword ptr [ecx]
+660f382111|223344556677885f5f5f5f	32	plan9	PMOVSXBD 0(CX), X2
+660f382111|223344556677885f5f5f5f	64	gnu	pmovsxbd (%rcx),%xmm2
+660f382111|223344556677885f5f5f5f	64	intel	pmovsxbd xmm2, dword ptr [rcx]
+660f382111|223344556677885f5f5f5f	64	plan9	PMOVSXBD 0(CX), X2
+660f382211|223344556677885f5f5f5f	32	intel	pmovsxbq xmm2, word ptr [ecx]
+660f382211|223344556677885f5f5f5f	32	plan9	PMOVSXBQ 0(CX), X2
+660f382211|223344556677885f5f5f5f	64	gnu	pmovsxbq (%rcx),%xmm2
+660f382211|223344556677885f5f5f5f	64	intel	pmovsxbq xmm2, word ptr [rcx]
+660f382211|223344556677885f5f5f5f	64	plan9	PMOVSXBQ 0(CX), X2
+660f382311|223344556677885f5f5f5f	32	intel	pmovsxwd xmm2, qword ptr [ecx]
+660f382311|223344556677885f5f5f5f	32	plan9	PMOVSXWD 0(CX), X2
+660f382311|223344556677885f5f5f5f	64	gnu	pmovsxwd (%rcx),%xmm2
+660f382311|223344556677885f5f5f5f	64	intel	pmovsxwd xmm2, qword ptr [rcx]
+660f382311|223344556677885f5f5f5f	64	plan9	PMOVSXWD 0(CX), X2
+660f382411|223344556677885f5f5f5f	32	intel	pmovsxwq xmm2, dword ptr [ecx]
+660f382411|223344556677885f5f5f5f	32	plan9	PMOVSXWQ 0(CX), X2
+660f382411|223344556677885f5f5f5f	64	gnu	pmovsxwq (%rcx),%xmm2
+660f382411|223344556677885f5f5f5f	64	intel	pmovsxwq xmm2, dword ptr [rcx]
+660f382411|223344556677885f5f5f5f	64	plan9	PMOVSXWQ 0(CX), X2
+660f382511|223344556677885f5f5f5f	32	intel	pmovsxdq xmm2, qword ptr [ecx]
+660f382511|223344556677885f5f5f5f	32	plan9	PMOVSXDQ 0(CX), X2
+660f382511|223344556677885f5f5f5f	64	gnu	pmovsxdq (%rcx),%xmm2
+660f382511|223344556677885f5f5f5f	64	intel	pmovsxdq xmm2, qword ptr [rcx]
+660f382511|223344556677885f5f5f5f	64	plan9	PMOVSXDQ 0(CX), X2
+660f382811|223344556677885f5f5f5f	32	intel	pmuldq xmm2, xmmword ptr [ecx]
+660f382811|223344556677885f5f5f5f	32	plan9	PMULDQ 0(CX), X2
+660f382811|223344556677885f5f5f5f	64	gnu	pmuldq (%rcx),%xmm2
+660f382811|223344556677885f5f5f5f	64	intel	pmuldq xmm2, xmmword ptr [rcx]
+660f382811|223344556677885f5f5f5f	64	plan9	PMULDQ 0(CX), X2
+660f382911|223344556677885f5f5f5f	32	intel	pcmpeqq xmm2, xmmword ptr [ecx]
+660f382911|223344556677885f5f5f5f	32	plan9	PCMPEQQ 0(CX), X2
+660f382911|223344556677885f5f5f5f	64	gnu	pcmpeqq (%rcx),%xmm2
+660f382911|223344556677885f5f5f5f	64	intel	pcmpeqq xmm2, xmmword ptr [rcx]
+660f382911|223344556677885f5f5f5f	64	plan9	PCMPEQQ 0(CX), X2
+660f382a11|223344556677885f5f5f5f	32	intel	movntdqa xmm2, xmmword ptr [ecx]
+660f382a11|223344556677885f5f5f5f	32	plan9	MOVNTDQA 0(CX), X2
+660f382a11|223344556677885f5f5f5f	64	gnu	movntdqa (%rcx),%xmm2
+660f382a11|223344556677885f5f5f5f	64	intel	movntdqa xmm2, xmmword ptr [rcx]
+660f382a11|223344556677885f5f5f5f	64	plan9	MOVNTDQA 0(CX), X2
+660f382b11|223344556677885f5f5f5f	32	intel	packusdw xmm2, xmmword ptr [ecx]
+660f382b11|223344556677885f5f5f5f	32	plan9	PACKUSDW 0(CX), X2
+660f382b11|223344556677885f5f5f5f	64	gnu	packusdw (%rcx),%xmm2
+660f382b11|223344556677885f5f5f5f	64	intel	packusdw xmm2, xmmword ptr [rcx]
+660f382b11|223344556677885f5f5f5f	64	plan9	PACKUSDW 0(CX), X2
+660f383011|223344556677885f5f5f5f	32	intel	pmovzxbw xmm2, qword ptr [ecx]
+660f383011|223344556677885f5f5f5f	32	plan9	PMOVZXBW 0(CX), X2
+660f383011|223344556677885f5f5f5f	64	gnu	pmovzxbw (%rcx),%xmm2
+660f383011|223344556677885f5f5f5f	64	intel	pmovzxbw xmm2, qword ptr [rcx]
+660f383011|223344556677885f5f5f5f	64	plan9	PMOVZXBW 0(CX), X2
+660f383111|223344556677885f5f5f5f	32	intel	pmovzxbd xmm2, dword ptr [ecx]
+660f383111|223344556677885f5f5f5f	32	plan9	PMOVZXBD 0(CX), X2
+660f383111|223344556677885f5f5f5f	64	gnu	pmovzxbd (%rcx),%xmm2
+660f383111|223344556677885f5f5f5f	64	intel	pmovzxbd xmm2, dword ptr [rcx]
+660f383111|223344556677885f5f5f5f	64	plan9	PMOVZXBD 0(CX), X2
+660f383211|223344556677885f5f5f5f	32	intel	pmovzxbq xmm2, word ptr [ecx]
+660f383211|223344556677885f5f5f5f	32	plan9	PMOVZXBQ 0(CX), X2
+660f383211|223344556677885f5f5f5f	64	gnu	pmovzxbq (%rcx),%xmm2
+660f383211|223344556677885f5f5f5f	64	intel	pmovzxbq xmm2, word ptr [rcx]
+660f383211|223344556677885f5f5f5f	64	plan9	PMOVZXBQ 0(CX), X2
+660f383311|223344556677885f5f5f5f	32	intel	pmovzxwd xmm2, qword ptr [ecx]
+660f383311|223344556677885f5f5f5f	32	plan9	PMOVZXWD 0(CX), X2
+660f383311|223344556677885f5f5f5f	64	gnu	pmovzxwd (%rcx),%xmm2
+660f383311|223344556677885f5f5f5f	64	intel	pmovzxwd xmm2, qword ptr [rcx]
+660f383311|223344556677885f5f5f5f	64	plan9	PMOVZXWD 0(CX), X2
+660f383411|223344556677885f5f5f5f	32	intel	pmovzxwq xmm2, dword ptr [ecx]
+660f383411|223344556677885f5f5f5f	32	plan9	PMOVZXWQ 0(CX), X2
+660f383411|223344556677885f5f5f5f	64	gnu	pmovzxwq (%rcx),%xmm2
+660f383411|223344556677885f5f5f5f	64	intel	pmovzxwq xmm2, dword ptr [rcx]
+660f383411|223344556677885f5f5f5f	64	plan9	PMOVZXWQ 0(CX), X2
+660f383511|223344556677885f5f5f5f	32	intel	pmovzxdq xmm2, qword ptr [ecx]
+660f383511|223344556677885f5f5f5f	32	plan9	PMOVZXDQ 0(CX), X2
+660f383511|223344556677885f5f5f5f	64	gnu	pmovzxdq (%rcx),%xmm2
+660f383511|223344556677885f5f5f5f	64	intel	pmovzxdq xmm2, qword ptr [rcx]
+660f383511|223344556677885f5f5f5f	64	plan9	PMOVZXDQ 0(CX), X2
+660f383711|223344556677885f5f5f5f	32	intel	pcmpgtq xmm2, xmmword ptr [ecx]
+660f383711|223344556677885f5f5f5f	32	plan9	PCMPGTQ 0(CX), X2
+660f383711|223344556677885f5f5f5f	64	gnu	pcmpgtq (%rcx),%xmm2
+660f383711|223344556677885f5f5f5f	64	intel	pcmpgtq xmm2, xmmword ptr [rcx]
+660f383711|223344556677885f5f5f5f	64	plan9	PCMPGTQ 0(CX), X2
+660f383811|223344556677885f5f5f5f	32	intel	pminsb xmm2, xmmword ptr [ecx]
+660f383811|223344556677885f5f5f5f	32	plan9	PMINSB 0(CX), X2
+660f383811|223344556677885f5f5f5f	64	gnu	pminsb (%rcx),%xmm2
+660f383811|223344556677885f5f5f5f	64	intel	pminsb xmm2, xmmword ptr [rcx]
+660f383811|223344556677885f5f5f5f	64	plan9	PMINSB 0(CX), X2
+660f383911|223344556677885f5f5f5f	32	intel	pminsd xmm2, xmmword ptr [ecx]
+660f383911|223344556677885f5f5f5f	32	plan9	PMINSD 0(CX), X2
+660f383911|223344556677885f5f5f5f	64	gnu	pminsd (%rcx),%xmm2
+660f383911|223344556677885f5f5f5f	64	intel	pminsd xmm2, xmmword ptr [rcx]
+660f383911|223344556677885f5f5f5f	64	plan9	PMINSD 0(CX), X2
+660f383a11|223344556677885f5f5f5f	32	intel	pminuw xmm2, xmmword ptr [ecx]
+660f383a11|223344556677885f5f5f5f	32	plan9	PMINUW 0(CX), X2
+660f383a11|223344556677885f5f5f5f	64	gnu	pminuw (%rcx),%xmm2
+660f383a11|223344556677885f5f5f5f	64	intel	pminuw xmm2, xmmword ptr [rcx]
+660f383a11|223344556677885f5f5f5f	64	plan9	PMINUW 0(CX), X2
+660f383b11|223344556677885f5f5f5f	32	intel	pminud xmm2, xmmword ptr [ecx]
+660f383b11|223344556677885f5f5f5f	32	plan9	PMINUD 0(CX), X2
+660f383b11|223344556677885f5f5f5f	64	gnu	pminud (%rcx),%xmm2
+660f383b11|223344556677885f5f5f5f	64	intel	pminud xmm2, xmmword ptr [rcx]
+660f383b11|223344556677885f5f5f5f	64	plan9	PMINUD 0(CX), X2
+660f383c11|223344556677885f5f5f5f	32	intel	pmaxsb xmm2, xmmword ptr [ecx]
+660f383c11|223344556677885f5f5f5f	32	plan9	PMAXSB 0(CX), X2
+660f383c11|223344556677885f5f5f5f	64	gnu	pmaxsb (%rcx),%xmm2
+660f383c11|223344556677885f5f5f5f	64	intel	pmaxsb xmm2, xmmword ptr [rcx]
+660f383c11|223344556677885f5f5f5f	64	plan9	PMAXSB 0(CX), X2
+660f383d11|223344556677885f5f5f5f	32	intel	pmaxsd xmm2, xmmword ptr [ecx]
+660f383d11|223344556677885f5f5f5f	32	plan9	PMAXSD 0(CX), X2
+660f383d11|223344556677885f5f5f5f	64	gnu	pmaxsd (%rcx),%xmm2
+660f383d11|223344556677885f5f5f5f	64	intel	pmaxsd xmm2, xmmword ptr [rcx]
+660f383d11|223344556677885f5f5f5f	64	plan9	PMAXSD 0(CX), X2
+660f383e11|223344556677885f5f5f5f	32	intel	pmaxuw xmm2, xmmword ptr [ecx]
+660f383e11|223344556677885f5f5f5f	32	plan9	PMAXUW 0(CX), X2
+660f383e11|223344556677885f5f5f5f	64	gnu	pmaxuw (%rcx),%xmm2
+660f383e11|223344556677885f5f5f5f	64	intel	pmaxuw xmm2, xmmword ptr [rcx]
+660f383e11|223344556677885f5f5f5f	64	plan9	PMAXUW 0(CX), X2
+660f383f11|223344556677885f5f5f5f	32	intel	pmaxud xmm2, xmmword ptr [ecx]
+660f383f11|223344556677885f5f5f5f	32	plan9	PMAXUD 0(CX), X2
+660f383f11|223344556677885f5f5f5f	64	gnu	pmaxud (%rcx),%xmm2
+660f383f11|223344556677885f5f5f5f	64	intel	pmaxud xmm2, xmmword ptr [rcx]
+660f383f11|223344556677885f5f5f5f	64	plan9	PMAXUD 0(CX), X2
+660f384011|223344556677885f5f5f5f	32	intel	pmulld xmm2, xmmword ptr [ecx]
+660f384011|223344556677885f5f5f5f	32	plan9	PMULLD 0(CX), X2
+660f384011|223344556677885f5f5f5f	64	gnu	pmulld (%rcx),%xmm2
+660f384011|223344556677885f5f5f5f	64	intel	pmulld xmm2, xmmword ptr [rcx]
+660f384011|223344556677885f5f5f5f	64	plan9	PMULLD 0(CX), X2
+660f384111|223344556677885f5f5f5f	32	intel	phminposuw xmm2, xmmword ptr [ecx]
+660f384111|223344556677885f5f5f5f	32	plan9	PHMINPOSUW 0(CX), X2
+660f384111|223344556677885f5f5f5f	64	gnu	phminposuw (%rcx),%xmm2
+660f384111|223344556677885f5f5f5f	64	intel	phminposuw xmm2, xmmword ptr [rcx]
+660f384111|223344556677885f5f5f5f	64	plan9	PHMINPOSUW 0(CX), X2
+660f388211|223344556677885f5f5f5f	32	intel	invpcid edx, xmmword ptr [ecx]
+660f388211|223344556677885f5f5f5f	32	plan9	INVPCID 0(CX), DX
+660f388211|223344556677885f5f5f5f	64	gnu	invpcid (%rcx),%rdx
+660f388211|223344556677885f5f5f5f	64	intel	invpcid rdx, xmmword ptr [rcx]
+660f388211|223344556677885f5f5f5f	64	plan9	INVPCID 0(CX), DX
+660f38db11|223344556677885f5f5f5f	32	intel	aesimc xmm2, xmmword ptr [ecx]
+660f38db11|223344556677885f5f5f5f	32	plan9	AESIMC 0(CX), X2
+660f38db11|223344556677885f5f5f5f	64	gnu	aesimc (%rcx),%xmm2
+660f38db11|223344556677885f5f5f5f	64	intel	aesimc xmm2, xmmword ptr [rcx]
+660f38db11|223344556677885f5f5f5f	64	plan9	AESIMC 0(CX), X2
+660f38dc11|223344556677885f5f5f5f	32	intel	aesenc xmm2, xmmword ptr [ecx]
+660f38dc11|223344556677885f5f5f5f	32	plan9	AESENC 0(CX), X2
+660f38dc11|223344556677885f5f5f5f	64	gnu	aesenc (%rcx),%xmm2
+660f38dc11|223344556677885f5f5f5f	64	intel	aesenc xmm2, xmmword ptr [rcx]
+660f38dc11|223344556677885f5f5f5f	64	plan9	AESENC 0(CX), X2
+660f38dd11|223344556677885f5f5f5f	32	intel	aesenclast xmm2, xmmword ptr [ecx]
+660f38dd11|223344556677885f5f5f5f	32	plan9	AESENCLAST 0(CX), X2
+660f38dd11|223344556677885f5f5f5f	64	gnu	aesenclast (%rcx),%xmm2
+660f38dd11|223344556677885f5f5f5f	64	intel	aesenclast xmm2, xmmword ptr [rcx]
+660f38dd11|223344556677885f5f5f5f	64	plan9	AESENCLAST 0(CX), X2
+660f38de11|223344556677885f5f5f5f	32	intel	aesdec xmm2, xmmword ptr [ecx]
+660f38de11|223344556677885f5f5f5f	32	plan9	AESDEC 0(CX), X2
+660f38de11|223344556677885f5f5f5f	64	gnu	aesdec (%rcx),%xmm2
+660f38de11|223344556677885f5f5f5f	64	intel	aesdec xmm2, xmmword ptr [rcx]
+660f38de11|223344556677885f5f5f5f	64	plan9	AESDEC 0(CX), X2
+660f38df11|223344556677885f5f5f5f	32	intel	aesdeclast xmm2, xmmword ptr [ecx]
+660f38df11|223344556677885f5f5f5f	32	plan9	AESDECLAST 0(CX), X2
+660f38df11|223344556677885f5f5f5f	64	gnu	aesdeclast (%rcx),%xmm2
+660f38df11|223344556677885f5f5f5f	64	intel	aesdeclast xmm2, xmmword ptr [rcx]
+660f38df11|223344556677885f5f5f5f	64	plan9	AESDECLAST 0(CX), X2
+660f3a081122|3344556677885f5f5f5f	32	intel	roundps xmm2, xmmword ptr [ecx], 0x22
+660f3a081122|3344556677885f5f5f5f	32	plan9	ROUNDPS $0x22, 0(CX), X2
+660f3a081122|3344556677885f5f5f5f	64	gnu	roundps $0x22,(%rcx),%xmm2
+660f3a081122|3344556677885f5f5f5f	64	intel	roundps xmm2, xmmword ptr [rcx], 0x22
+660f3a081122|3344556677885f5f5f5f	64	plan9	ROUNDPS $0x22, 0(CX), X2
+660f3a091122|3344556677885f5f5f5f	32	intel	roundpd xmm2, xmmword ptr [ecx], 0x22
+660f3a091122|3344556677885f5f5f5f	32	plan9	ROUNDPD $0x22, 0(CX), X2
+660f3a091122|3344556677885f5f5f5f	64	gnu	roundpd $0x22,(%rcx),%xmm2
+660f3a091122|3344556677885f5f5f5f	64	intel	roundpd xmm2, xmmword ptr [rcx], 0x22
+660f3a091122|3344556677885f5f5f5f	64	plan9	ROUNDPD $0x22, 0(CX), X2
+660f3a0a1122|3344556677885f5f5f5f	32	intel	roundss xmm2, dword ptr [ecx], 0x22
+660f3a0a1122|3344556677885f5f5f5f	32	plan9	ROUNDSS $0x22, 0(CX), X2
+660f3a0a1122|3344556677885f5f5f5f	64	gnu	roundss $0x22,(%rcx),%xmm2
+660f3a0a1122|3344556677885f5f5f5f	64	intel	roundss xmm2, dword ptr [rcx], 0x22
+660f3a0a1122|3344556677885f5f5f5f	64	plan9	ROUNDSS $0x22, 0(CX), X2
+660f3a0b1122|3344556677885f5f5f5f	32	intel	roundsd xmm2, qword ptr [ecx], 0x22
+660f3a0b1122|3344556677885f5f5f5f	32	plan9	ROUNDSD $0x22, 0(CX), X2
+660f3a0b1122|3344556677885f5f5f5f	64	gnu	roundsd $0x22,(%rcx),%xmm2
+660f3a0b1122|3344556677885f5f5f5f	64	intel	roundsd xmm2, qword ptr [rcx], 0x22
+660f3a0b1122|3344556677885f5f5f5f	64	plan9	ROUNDSD $0x22, 0(CX), X2
+660f3a0c1122|3344556677885f5f5f5f	32	intel	blendps xmm2, xmmword ptr [ecx], 0x22
+660f3a0c1122|3344556677885f5f5f5f	32	plan9	BLENDPS $0x22, 0(CX), X2
+660f3a0c1122|3344556677885f5f5f5f	64	gnu	blendps $0x22,(%rcx),%xmm2
+660f3a0c1122|3344556677885f5f5f5f	64	intel	blendps xmm2, xmmword ptr [rcx], 0x22
+660f3a0c1122|3344556677885f5f5f5f	64	plan9	BLENDPS $0x22, 0(CX), X2
+660f3a0d1122|3344556677885f5f5f5f	32	intel	blendpd xmm2, xmmword ptr [ecx], 0x22
+660f3a0d1122|3344556677885f5f5f5f	32	plan9	BLENDPD $0x22, 0(CX), X2
+660f3a0d1122|3344556677885f5f5f5f	64	gnu	blendpd $0x22,(%rcx),%xmm2
+660f3a0d1122|3344556677885f5f5f5f	64	intel	blendpd xmm2, xmmword ptr [rcx], 0x22
+660f3a0d1122|3344556677885f5f5f5f	64	plan9	BLENDPD $0x22, 0(CX), X2
+660f3a0e1122|3344556677885f5f5f5f	32	intel	pblendw xmm2, xmmword ptr [ecx], 0x22
+660f3a0e1122|3344556677885f5f5f5f	32	plan9	PBLENDW $0x22, 0(CX), X2
+660f3a0e1122|3344556677885f5f5f5f	64	gnu	pblendw $0x22,(%rcx),%xmm2
+660f3a0e1122|3344556677885f5f5f5f	64	intel	pblendw xmm2, xmmword ptr [rcx], 0x22
+660f3a0e1122|3344556677885f5f5f5f	64	plan9	PBLENDW $0x22, 0(CX), X2
+660f3a0f1122|3344556677885f5f5f5f	32	intel	palignr xmm2, xmmword ptr [ecx], 0x22
+660f3a0f1122|3344556677885f5f5f5f	32	plan9	PALIGNR $0x22, 0(CX), X2
+660f3a0f1122|3344556677885f5f5f5f	64	gnu	palignr $0x22,(%rcx),%xmm2
+660f3a0f1122|3344556677885f5f5f5f	64	intel	palignr xmm2, xmmword ptr [rcx], 0x22
+660f3a0f1122|3344556677885f5f5f5f	64	plan9	PALIGNR $0x22, 0(CX), X2
+660f3a141122|3344556677885f5f5f5f	32	intel	pextrb byte ptr [ecx], xmm2, 0x22
+660f3a141122|3344556677885f5f5f5f	32	plan9	PEXTRB $0x22, X2, 0(CX)
+660f3a141122|3344556677885f5f5f5f	64	gnu	pextrb $0x22,%xmm2,(%rcx)
+660f3a141122|3344556677885f5f5f5f	64	intel	pextrb byte ptr [rcx], xmm2, 0x22
+660f3a141122|3344556677885f5f5f5f	64	plan9	PEXTRB $0x22, X2, 0(CX)
+660f3a151122|3344556677885f5f5f5f	32	intel	pextrw word ptr [ecx], xmm2, 0x22
+660f3a151122|3344556677885f5f5f5f	32	plan9	PEXTRW $0x22, X2, 0(CX)
+660f3a151122|3344556677885f5f5f5f	64	gnu	pextrw $0x22,%xmm2,(%rcx)
+660f3a151122|3344556677885f5f5f5f	64	intel	pextrw word ptr [rcx], xmm2, 0x22
+660f3a151122|3344556677885f5f5f5f	64	plan9	PEXTRW $0x22, X2, 0(CX)
+660f3a161122|3344556677885f5f5f5f	32	intel	pextrd dword ptr [ecx], xmm2, 0x22
+660f3a161122|3344556677885f5f5f5f	32	plan9	PEXTRD $0x22, X2, 0(CX)
+660f3a161122|3344556677885f5f5f5f	64	gnu	pextrd $0x22,%xmm2,(%rcx)
+660f3a161122|3344556677885f5f5f5f	64	intel	pextrd dword ptr [rcx], xmm2, 0x22
+660f3a161122|3344556677885f5f5f5f	64	plan9	PEXTRD $0x22, X2, 0(CX)
+660f3a171122|3344556677885f5f5f5f	32	intel	extractps dword ptr [ecx], xmm2, 0x22
+660f3a171122|3344556677885f5f5f5f	32	plan9	EXTRACTPS $0x22, X2, 0(CX)
+660f3a171122|3344556677885f5f5f5f	64	gnu	extractps $0x22,%xmm2,(%rcx)
+660f3a171122|3344556677885f5f5f5f	64	intel	extractps dword ptr [rcx], xmm2, 0x22
+660f3a171122|3344556677885f5f5f5f	64	plan9	EXTRACTPS $0x22, X2, 0(CX)
+660f3a201122|3344556677885f5f5f5f	32	intel	pinsrb xmm2, byte ptr [ecx], 0x22
+660f3a201122|3344556677885f5f5f5f	32	plan9	PINSRB $0x22, 0(CX), X2
+660f3a201122|3344556677885f5f5f5f	64	gnu	pinsrb $0x22,(%rcx),%xmm2
+660f3a201122|3344556677885f5f5f5f	64	intel	pinsrb xmm2, byte ptr [rcx], 0x22
+660f3a201122|3344556677885f5f5f5f	64	plan9	PINSRB $0x22, 0(CX), X2
+660f3a211122|3344556677885f5f5f5f	32	intel	insertps xmm2, dword ptr [ecx], 0x22
+660f3a211122|3344556677885f5f5f5f	32	plan9	INSERTPS $0x22, 0(CX), X2
+660f3a211122|3344556677885f5f5f5f	64	gnu	insertps $0x22,(%rcx),%xmm2
+660f3a211122|3344556677885f5f5f5f	64	intel	insertps xmm2, dword ptr [rcx], 0x22
+660f3a211122|3344556677885f5f5f5f	64	plan9	INSERTPS $0x22, 0(CX), X2
+660f3a221122|3344556677885f5f5f5f	32	intel	pinsrd xmm2, dword ptr [ecx], 0x22
+660f3a221122|3344556677885f5f5f5f	32	plan9	PINSRD $0x22, 0(CX), X2
+660f3a221122|3344556677885f5f5f5f	64	gnu	pinsrd $0x22,(%rcx),%xmm2
+660f3a221122|3344556677885f5f5f5f	64	intel	pinsrd xmm2, dword ptr [rcx], 0x22
+660f3a221122|3344556677885f5f5f5f	64	plan9	PINSRD $0x22, 0(CX), X2
+660f3a401122|3344556677885f5f5f5f	32	intel	dpps xmm2, xmmword ptr [ecx], 0x22
+660f3a401122|3344556677885f5f5f5f	32	plan9	DPPS $0x22, 0(CX), X2
+660f3a401122|3344556677885f5f5f5f	64	gnu	dpps $0x22,(%rcx),%xmm2
+660f3a401122|3344556677885f5f5f5f	64	intel	dpps xmm2, xmmword ptr [rcx], 0x22
+660f3a401122|3344556677885f5f5f5f	64	plan9	DPPS $0x22, 0(CX), X2
+660f3a411122|3344556677885f5f5f5f	32	intel	dppd xmm2, xmmword ptr [ecx], 0x22
+660f3a411122|3344556677885f5f5f5f	32	plan9	DPPD $0x22, 0(CX), X2
+660f3a411122|3344556677885f5f5f5f	64	gnu	dppd $0x22,(%rcx),%xmm2
+660f3a411122|3344556677885f5f5f5f	64	intel	dppd xmm2, xmmword ptr [rcx], 0x22
+660f3a411122|3344556677885f5f5f5f	64	plan9	DPPD $0x22, 0(CX), X2
+660f3a421122|3344556677885f5f5f5f	32	intel	mpsadbw xmm2, xmmword ptr [ecx], 0x22
+660f3a421122|3344556677885f5f5f5f	32	plan9	MPSADBW $0x22, 0(CX), X2
+660f3a421122|3344556677885f5f5f5f	64	gnu	mpsadbw $0x22,(%rcx),%xmm2
+660f3a421122|3344556677885f5f5f5f	64	intel	mpsadbw xmm2, xmmword ptr [rcx], 0x22
+660f3a421122|3344556677885f5f5f5f	64	plan9	MPSADBW $0x22, 0(CX), X2
+660f3a441122|3344556677885f5f5f5f	32	intel	pclmulqdq xmm2, xmmword ptr [ecx], 0x22
+660f3a441122|3344556677885f5f5f5f	32	plan9	PCLMULQDQ $0x22, 0(CX), X2
+660f3a441122|3344556677885f5f5f5f	64	gnu	pclmulqdq $0x22,(%rcx),%xmm2
+660f3a441122|3344556677885f5f5f5f	64	intel	pclmulqdq xmm2, xmmword ptr [rcx], 0x22
+660f3a441122|3344556677885f5f5f5f	64	plan9	PCLMULQDQ $0x22, 0(CX), X2
+660f3a601122|3344556677885f5f5f5f	32	intel	pcmpestrm xmm2, xmmword ptr [ecx], 0x22
+660f3a601122|3344556677885f5f5f5f	32	plan9	PCMPESTRM $0x22, 0(CX), X2
+660f3a601122|3344556677885f5f5f5f	64	gnu	pcmpestrm $0x22,(%rcx),%xmm2
+660f3a601122|3344556677885f5f5f5f	64	intel	pcmpestrm xmm2, xmmword ptr [rcx], 0x22
+660f3a601122|3344556677885f5f5f5f	64	plan9	PCMPESTRM $0x22, 0(CX), X2
+660f3a611122|3344556677885f5f5f5f	32	intel	pcmpestri xmm2, xmmword ptr [ecx], 0x22
+660f3a611122|3344556677885f5f5f5f	32	plan9	PCMPESTRI $0x22, 0(CX), X2
+660f3a611122|3344556677885f5f5f5f	64	gnu	pcmpestri $0x22,(%rcx),%xmm2
+660f3a611122|3344556677885f5f5f5f	64	intel	pcmpestri xmm2, xmmword ptr [rcx], 0x22
+660f3a611122|3344556677885f5f5f5f	64	plan9	PCMPESTRI $0x22, 0(CX), X2
+660f3a621122|3344556677885f5f5f5f	32	intel	pcmpistrm xmm2, xmmword ptr [ecx], 0x22
+660f3a621122|3344556677885f5f5f5f	32	plan9	PCMPISTRM $0x22, 0(CX), X2
+660f3a621122|3344556677885f5f5f5f	64	gnu	pcmpistrm $0x22,(%rcx),%xmm2
+660f3a621122|3344556677885f5f5f5f	64	intel	pcmpistrm xmm2, xmmword ptr [rcx], 0x22
+660f3a621122|3344556677885f5f5f5f	64	plan9	PCMPISTRM $0x22, 0(CX), X2
+660f3a631122|3344556677885f5f5f5f	32	intel	pcmpistri xmm2, xmmword ptr [ecx], 0x22
+660f3a631122|3344556677885f5f5f5f	32	plan9	PCMPISTRI $0x22, 0(CX), X2
+660f3a631122|3344556677885f5f5f5f	64	gnu	pcmpistri $0x22,(%rcx),%xmm2
+660f3a631122|3344556677885f5f5f5f	64	intel	pcmpistri xmm2, xmmword ptr [rcx], 0x22
+660f3a631122|3344556677885f5f5f5f	64	plan9	PCMPISTRI $0x22, 0(CX), X2
+660f3adf1122|3344556677885f5f5f5f	32	intel	aeskeygenassist xmm2, xmmword ptr [ecx], 0x22
+660f3adf1122|3344556677885f5f5f5f	32	plan9	AESKEYGENASSIST $0x22, 0(CX), X2
+660f3adf1122|3344556677885f5f5f5f	64	gnu	aeskeygenassist $0x22,(%rcx),%xmm2
+660f3adf1122|3344556677885f5f5f5f	64	intel	aeskeygenassist xmm2, xmmword ptr [rcx], 0x22
+660f3adf1122|3344556677885f5f5f5f	64	plan9	AESKEYGENASSIST $0x22, 0(CX), X2
+660f4011|223344556677885f5f5f5f5f	32	intel	cmovo dx, word ptr [ecx]
+660f4011|223344556677885f5f5f5f5f	32	plan9	CMOVO 0(CX), DX
+660f4011|223344556677885f5f5f5f5f	64	gnu	cmovo (%rcx),%dx
+660f4011|223344556677885f5f5f5f5f	64	intel	cmovo dx, word ptr [rcx]
+660f4011|223344556677885f5f5f5f5f	64	plan9	CMOVO 0(CX), DX
+660f4111|223344556677885f5f5f5f5f	32	intel	cmovno dx, word ptr [ecx]
+660f4111|223344556677885f5f5f5f5f	32	plan9	CMOVNO 0(CX), DX
+660f4111|223344556677885f5f5f5f5f	64	gnu	cmovno (%rcx),%dx
+660f4111|223344556677885f5f5f5f5f	64	intel	cmovno dx, word ptr [rcx]
+660f4111|223344556677885f5f5f5f5f	64	plan9	CMOVNO 0(CX), DX
+660f4211|223344556677885f5f5f5f5f	32	intel	cmovb dx, word ptr [ecx]
+660f4211|223344556677885f5f5f5f5f	32	plan9	CMOVB 0(CX), DX
+660f4211|223344556677885f5f5f5f5f	64	gnu	cmovb (%rcx),%dx
+660f4211|223344556677885f5f5f5f5f	64	intel	cmovb dx, word ptr [rcx]
+660f4211|223344556677885f5f5f5f5f	64	plan9	CMOVB 0(CX), DX
+660f4311|223344556677885f5f5f5f5f	32	intel	cmovnb dx, word ptr [ecx]
+660f4311|223344556677885f5f5f5f5f	32	plan9	CMOVAE 0(CX), DX
+660f4311|223344556677885f5f5f5f5f	64	gnu	cmovae (%rcx),%dx
+660f4311|223344556677885f5f5f5f5f	64	intel	cmovnb dx, word ptr [rcx]
+660f4311|223344556677885f5f5f5f5f	64	plan9	CMOVAE 0(CX), DX
+660f4411|223344556677885f5f5f5f5f	32	intel	cmovz dx, word ptr [ecx]
+660f4411|223344556677885f5f5f5f5f	32	plan9	CMOVE 0(CX), DX
+660f4411|223344556677885f5f5f5f5f	64	gnu	cmove (%rcx),%dx
+660f4411|223344556677885f5f5f5f5f	64	intel	cmovz dx, word ptr [rcx]
+660f4411|223344556677885f5f5f5f5f	64	plan9	CMOVE 0(CX), DX
+660f4511|223344556677885f5f5f5f5f	32	intel	cmovnz dx, word ptr [ecx]
+660f4511|223344556677885f5f5f5f5f	32	plan9	CMOVNE 0(CX), DX
+660f4511|223344556677885f5f5f5f5f	64	gnu	cmovne (%rcx),%dx
+660f4511|223344556677885f5f5f5f5f	64	intel	cmovnz dx, word ptr [rcx]
+660f4511|223344556677885f5f5f5f5f	64	plan9	CMOVNE 0(CX), DX
+660f4611|223344556677885f5f5f5f5f	32	intel	cmovbe dx, word ptr [ecx]
+660f4611|223344556677885f5f5f5f5f	32	plan9	CMOVBE 0(CX), DX
+660f4611|223344556677885f5f5f5f5f	64	gnu	cmovbe (%rcx),%dx
+660f4611|223344556677885f5f5f5f5f	64	intel	cmovbe dx, word ptr [rcx]
+660f4611|223344556677885f5f5f5f5f	64	plan9	CMOVBE 0(CX), DX
+660f4711|223344556677885f5f5f5f5f	32	intel	cmovnbe dx, word ptr [ecx]
+660f4711|223344556677885f5f5f5f5f	32	plan9	CMOVA 0(CX), DX
+660f4711|223344556677885f5f5f5f5f	64	gnu	cmova (%rcx),%dx
+660f4711|223344556677885f5f5f5f5f	64	intel	cmovnbe dx, word ptr [rcx]
+660f4711|223344556677885f5f5f5f5f	64	plan9	CMOVA 0(CX), DX
+660f4811|223344556677885f5f5f5f5f	32	intel	cmovs dx, word ptr [ecx]
+660f4811|223344556677885f5f5f5f5f	32	plan9	CMOVS 0(CX), DX
+660f4811|223344556677885f5f5f5f5f	64	gnu	cmovs (%rcx),%dx
+660f4811|223344556677885f5f5f5f5f	64	intel	cmovs dx, word ptr [rcx]
+660f4811|223344556677885f5f5f5f5f	64	plan9	CMOVS 0(CX), DX
+660f4911|223344556677885f5f5f5f5f	32	intel	cmovns dx, word ptr [ecx]
+660f4911|223344556677885f5f5f5f5f	32	plan9	CMOVNS 0(CX), DX
+660f4911|223344556677885f5f5f5f5f	64	gnu	cmovns (%rcx),%dx
+660f4911|223344556677885f5f5f5f5f	64	intel	cmovns dx, word ptr [rcx]
+660f4911|223344556677885f5f5f5f5f	64	plan9	CMOVNS 0(CX), DX
+660f4a11|223344556677885f5f5f5f5f	32	intel	cmovp dx, word ptr [ecx]
+660f4a11|223344556677885f5f5f5f5f	32	plan9	CMOVP 0(CX), DX
+660f4a11|223344556677885f5f5f5f5f	64	gnu	cmovp (%rcx),%dx
+660f4a11|223344556677885f5f5f5f5f	64	intel	cmovp dx, word ptr [rcx]
+660f4a11|223344556677885f5f5f5f5f	64	plan9	CMOVP 0(CX), DX
+660f4b11|223344556677885f5f5f5f5f	32	intel	cmovnp dx, word ptr [ecx]
+660f4b11|223344556677885f5f5f5f5f	32	plan9	CMOVNP 0(CX), DX
+660f4b11|223344556677885f5f5f5f5f	64	gnu	cmovnp (%rcx),%dx
+660f4b11|223344556677885f5f5f5f5f	64	intel	cmovnp dx, word ptr [rcx]
+660f4b11|223344556677885f5f5f5f5f	64	plan9	CMOVNP 0(CX), DX
+660f4c11|223344556677885f5f5f5f5f	32	intel	cmovl dx, word ptr [ecx]
+660f4c11|223344556677885f5f5f5f5f	32	plan9	CMOVL 0(CX), DX
+660f4c11|223344556677885f5f5f5f5f	64	gnu	cmovl (%rcx),%dx
+660f4c11|223344556677885f5f5f5f5f	64	intel	cmovl dx, word ptr [rcx]
+660f4c11|223344556677885f5f5f5f5f	64	plan9	CMOVL 0(CX), DX
+660f4d11|223344556677885f5f5f5f5f	32	intel	cmovnl dx, word ptr [ecx]
+660f4d11|223344556677885f5f5f5f5f	32	plan9	CMOVGE 0(CX), DX
+660f4d11|223344556677885f5f5f5f5f	64	gnu	cmovge (%rcx),%dx
+660f4d11|223344556677885f5f5f5f5f	64	intel	cmovnl dx, word ptr [rcx]
+660f4d11|223344556677885f5f5f5f5f	64	plan9	CMOVGE 0(CX), DX
+660f4e11|223344556677885f5f5f5f5f	32	intel	cmovle dx, word ptr [ecx]
+660f4e11|223344556677885f5f5f5f5f	32	plan9	CMOVLE 0(CX), DX
+660f4e11|223344556677885f5f5f5f5f	64	gnu	cmovle (%rcx),%dx
+660f4e11|223344556677885f5f5f5f5f	64	intel	cmovle dx, word ptr [rcx]
+660f4e11|223344556677885f5f5f5f5f	64	plan9	CMOVLE 0(CX), DX
+660f4f11|223344556677885f5f5f5f5f	32	intel	cmovnle dx, word ptr [ecx]
+660f4f11|223344556677885f5f5f5f5f	32	plan9	CMOVG 0(CX), DX
+660f4f11|223344556677885f5f5f5f5f	64	gnu	cmovg (%rcx),%dx
+660f4f11|223344556677885f5f5f5f5f	64	intel	cmovnle dx, word ptr [rcx]
+660f4f11|223344556677885f5f5f5f5f	64	plan9	CMOVG 0(CX), DX
+660f50c0|11223344556677885f5f5f5f	32	intel	movmskpd eax, xmm0
+660f50c0|11223344556677885f5f5f5f	32	plan9	MOVMSKPD X0, AX
+660f50c0|11223344556677885f5f5f5f	64	gnu	movmskpd %xmm0,%eax
+660f50c0|11223344556677885f5f5f5f	64	intel	movmskpd eax, xmm0
+660f50c0|11223344556677885f5f5f5f	64	plan9	MOVMSKPD X0, AX
+660f5111|223344556677885f5f5f5f5f	32	intel	sqrtpd xmm2, xmmword ptr [ecx]
+660f5111|223344556677885f5f5f5f5f	32	plan9	SQRTPD 0(CX), X2
+660f5111|223344556677885f5f5f5f5f	64	gnu	sqrtpd (%rcx),%xmm2
+660f5111|223344556677885f5f5f5f5f	64	intel	sqrtpd xmm2, xmmword ptr [rcx]
+660f5111|223344556677885f5f5f5f5f	64	plan9	SQRTPD 0(CX), X2
+660f5411|223344556677885f5f5f5f5f	32	intel	andpd xmm2, xmmword ptr [ecx]
+660f5411|223344556677885f5f5f5f5f	32	plan9	ANDPD 0(CX), X2
+660f5411|223344556677885f5f5f5f5f	64	gnu	andpd (%rcx),%xmm2
+660f5411|223344556677885f5f5f5f5f	64	intel	andpd xmm2, xmmword ptr [rcx]
+660f5411|223344556677885f5f5f5f5f	64	plan9	ANDPD 0(CX), X2
+660f5511|223344556677885f5f5f5f5f	32	intel	andnpd xmm2, xmmword ptr [ecx]
+660f5511|223344556677885f5f5f5f5f	32	plan9	ANDNPD 0(CX), X2
+660f5511|223344556677885f5f5f5f5f	64	gnu	andnpd (%rcx),%xmm2
+660f5511|223344556677885f5f5f5f5f	64	intel	andnpd xmm2, xmmword ptr [rcx]
+660f5511|223344556677885f5f5f5f5f	64	plan9	ANDNPD 0(CX), X2
+660f5611|223344556677885f5f5f5f5f	32	intel	orpd xmm2, xmmword ptr [ecx]
+660f5611|223344556677885f5f5f5f5f	32	plan9	ORPD 0(CX), X2
+660f5611|223344556677885f5f5f5f5f	64	gnu	orpd (%rcx),%xmm2
+660f5611|223344556677885f5f5f5f5f	64	intel	orpd xmm2, xmmword ptr [rcx]
+660f5611|223344556677885f5f5f5f5f	64	plan9	ORPD 0(CX), X2
+660f5711|223344556677885f5f5f5f5f	32	intel	xorpd xmm2, xmmword ptr [ecx]
+660f5711|223344556677885f5f5f5f5f	32	plan9	XORPD 0(CX), X2
+660f5711|223344556677885f5f5f5f5f	64	gnu	xorpd (%rcx),%xmm2
+660f5711|223344556677885f5f5f5f5f	64	intel	xorpd xmm2, xmmword ptr [rcx]
+660f5711|223344556677885f5f5f5f5f	64	plan9	XORPD 0(CX), X2
+660f5811|223344556677885f5f5f5f5f	32	intel	addpd xmm2, xmmword ptr [ecx]
+660f5811|223344556677885f5f5f5f5f	32	plan9	ADDPD 0(CX), X2
+660f5811|223344556677885f5f5f5f5f	64	gnu	addpd (%rcx),%xmm2
+660f5811|223344556677885f5f5f5f5f	64	intel	addpd xmm2, xmmword ptr [rcx]
+660f5811|223344556677885f5f5f5f5f	64	plan9	ADDPD 0(CX), X2
+660f5911|223344556677885f5f5f5f5f	32	intel	mulpd xmm2, xmmword ptr [ecx]
+660f5911|223344556677885f5f5f5f5f	32	plan9	MULPD 0(CX), X2
+660f5911|223344556677885f5f5f5f5f	64	gnu	mulpd (%rcx),%xmm2
+660f5911|223344556677885f5f5f5f5f	64	intel	mulpd xmm2, xmmword ptr [rcx]
+660f5911|223344556677885f5f5f5f5f	64	plan9	MULPD 0(CX), X2
+660f5a11|223344556677885f5f5f5f5f	32	intel	cvtpd2ps xmm2, xmmword ptr [ecx]
+660f5a11|223344556677885f5f5f5f5f	32	plan9	CVTPD2PS 0(CX), X2
+660f5a11|223344556677885f5f5f5f5f	64	gnu	cvtpd2ps (%rcx),%xmm2
+660f5a11|223344556677885f5f5f5f5f	64	intel	cvtpd2ps xmm2, xmmword ptr [rcx]
+660f5a11|223344556677885f5f5f5f5f	64	plan9	CVTPD2PS 0(CX), X2
+660f5b11|223344556677885f5f5f5f5f	32	intel	cvtps2dq xmm2, xmmword ptr [ecx]
+660f5b11|223344556677885f5f5f5f5f	32	plan9	CVTPS2DQ 0(CX), X2
+660f5b11|223344556677885f5f5f5f5f	64	gnu	cvtps2dq (%rcx),%xmm2
+660f5b11|223344556677885f5f5f5f5f	64	intel	cvtps2dq xmm2, xmmword ptr [rcx]
+660f5b11|223344556677885f5f5f5f5f	64	plan9	CVTPS2DQ 0(CX), X2
+660f5c11|223344556677885f5f5f5f5f	32	intel	subpd xmm2, xmmword ptr [ecx]
+660f5c11|223344556677885f5f5f5f5f	32	plan9	SUBPD 0(CX), X2
+660f5c11|223344556677885f5f5f5f5f	64	gnu	subpd (%rcx),%xmm2
+660f5c11|223344556677885f5f5f5f5f	64	intel	subpd xmm2, xmmword ptr [rcx]
+660f5c11|223344556677885f5f5f5f5f	64	plan9	SUBPD 0(CX), X2
+660f5d11|223344556677885f5f5f5f5f	32	intel	minpd xmm2, xmmword ptr [ecx]
+660f5d11|223344556677885f5f5f5f5f	32	plan9	MINPD 0(CX), X2
+660f5d11|223344556677885f5f5f5f5f	64	gnu	minpd (%rcx),%xmm2
+660f5d11|223344556677885f5f5f5f5f	64	intel	minpd xmm2, xmmword ptr [rcx]
+660f5d11|223344556677885f5f5f5f5f	64	plan9	MINPD 0(CX), X2
+660f5e11|223344556677885f5f5f5f5f	32	intel	divpd xmm2, xmmword ptr [ecx]
+660f5e11|223344556677885f5f5f5f5f	32	plan9	DIVPD 0(CX), X2
+660f5e11|223344556677885f5f5f5f5f	64	gnu	divpd (%rcx),%xmm2
+660f5e11|223344556677885f5f5f5f5f	64	intel	divpd xmm2, xmmword ptr [rcx]
+660f5e11|223344556677885f5f5f5f5f	64	plan9	DIVPD 0(CX), X2
+660f5f11|223344556677885f5f5f5f5f	32	intel	maxpd xmm2, xmmword ptr [ecx]
+660f5f11|223344556677885f5f5f5f5f	32	plan9	MAXPD 0(CX), X2
+660f5f11|223344556677885f5f5f5f5f	64	gnu	maxpd (%rcx),%xmm2
+660f5f11|223344556677885f5f5f5f5f	64	intel	maxpd xmm2, xmmword ptr [rcx]
+660f5f11|223344556677885f5f5f5f5f	64	plan9	MAXPD 0(CX), X2
+660f6011|223344556677885f5f5f5f5f	32	intel	punpcklbw xmm2, xmmword ptr [ecx]
+660f6011|223344556677885f5f5f5f5f	32	plan9	PUNPCKLBW 0(CX), X2
+660f6011|223344556677885f5f5f5f5f	64	gnu	punpcklbw (%rcx),%xmm2
+660f6011|223344556677885f5f5f5f5f	64	intel	punpcklbw xmm2, xmmword ptr [rcx]
+660f6011|223344556677885f5f5f5f5f	64	plan9	PUNPCKLBW 0(CX), X2
+660f6111|223344556677885f5f5f5f5f	32	intel	punpcklwd xmm2, xmmword ptr [ecx]
+660f6111|223344556677885f5f5f5f5f	32	plan9	PUNPCKLWD 0(CX), X2
+660f6111|223344556677885f5f5f5f5f	64	gnu	punpcklwd (%rcx),%xmm2
+660f6111|223344556677885f5f5f5f5f	64	intel	punpcklwd xmm2, xmmword ptr [rcx]
+660f6111|223344556677885f5f5f5f5f	64	plan9	PUNPCKLWD 0(CX), X2
+660f6211|223344556677885f5f5f5f5f	32	intel	punpckldq xmm2, xmmword ptr [ecx]
+660f6211|223344556677885f5f5f5f5f	32	plan9	PUNPCKLDQ 0(CX), X2
+660f6211|223344556677885f5f5f5f5f	64	gnu	punpckldq (%rcx),%xmm2
+660f6211|223344556677885f5f5f5f5f	64	intel	punpckldq xmm2, xmmword ptr [rcx]
+660f6211|223344556677885f5f5f5f5f	64	plan9	PUNPCKLDQ 0(CX), X2
+660f6311|223344556677885f5f5f5f5f	32	intel	packsswb xmm2, xmmword ptr [ecx]
+660f6311|223344556677885f5f5f5f5f	32	plan9	PACKSSWB 0(CX), X2
+660f6311|223344556677885f5f5f5f5f	64	gnu	packsswb (%rcx),%xmm2
+660f6311|223344556677885f5f5f5f5f	64	intel	packsswb xmm2, xmmword ptr [rcx]
+660f6311|223344556677885f5f5f5f5f	64	plan9	PACKSSWB 0(CX), X2
+660f6411|223344556677885f5f5f5f5f	32	intel	pcmpgtb xmm2, xmmword ptr [ecx]
+660f6411|223344556677885f5f5f5f5f	32	plan9	PCMPGTB 0(CX), X2
+660f6411|223344556677885f5f5f5f5f	64	gnu	pcmpgtb (%rcx),%xmm2
+660f6411|223344556677885f5f5f5f5f	64	intel	pcmpgtb xmm2, xmmword ptr [rcx]
+660f6411|223344556677885f5f5f5f5f	64	plan9	PCMPGTB 0(CX), X2
+660f6511|223344556677885f5f5f5f5f	32	intel	pcmpgtw xmm2, xmmword ptr [ecx]
+660f6511|223344556677885f5f5f5f5f	32	plan9	PCMPGTW 0(CX), X2
+660f6511|223344556677885f5f5f5f5f	64	gnu	pcmpgtw (%rcx),%xmm2
+660f6511|223344556677885f5f5f5f5f	64	intel	pcmpgtw xmm2, xmmword ptr [rcx]
+660f6511|223344556677885f5f5f5f5f	64	plan9	PCMPGTW 0(CX), X2
+660f6611|223344556677885f5f5f5f5f	32	intel	pcmpgtd xmm2, xmmword ptr [ecx]
+660f6611|223344556677885f5f5f5f5f	32	plan9	PCMPGTD 0(CX), X2
+660f6611|223344556677885f5f5f5f5f	64	gnu	pcmpgtd (%rcx),%xmm2
+660f6611|223344556677885f5f5f5f5f	64	intel	pcmpgtd xmm2, xmmword ptr [rcx]
+660f6611|223344556677885f5f5f5f5f	64	plan9	PCMPGTD 0(CX), X2
+660f6711|223344556677885f5f5f5f5f	32	intel	packuswb xmm2, xmmword ptr [ecx]
+660f6711|223344556677885f5f5f5f5f	32	plan9	PACKUSWB 0(CX), X2
+660f6711|223344556677885f5f5f5f5f	64	gnu	packuswb (%rcx),%xmm2
+660f6711|223344556677885f5f5f5f5f	64	intel	packuswb xmm2, xmmword ptr [rcx]
+660f6711|223344556677885f5f5f5f5f	64	plan9	PACKUSWB 0(CX), X2
+660f6811|223344556677885f5f5f5f5f	32	intel	punpckhbw xmm2, xmmword ptr [ecx]
+660f6811|223344556677885f5f5f5f5f	32	plan9	PUNPCKHBW 0(CX), X2
+660f6811|223344556677885f5f5f5f5f	64	gnu	punpckhbw (%rcx),%xmm2
+660f6811|223344556677885f5f5f5f5f	64	intel	punpckhbw xmm2, xmmword ptr [rcx]
+660f6811|223344556677885f5f5f5f5f	64	plan9	PUNPCKHBW 0(CX), X2
+660f6911|223344556677885f5f5f5f5f	32	intel	punpckhwd xmm2, xmmword ptr [ecx]
+660f6911|223344556677885f5f5f5f5f	32	plan9	PUNPCKHWD 0(CX), X2
+660f6911|223344556677885f5f5f5f5f	64	gnu	punpckhwd (%rcx),%xmm2
+660f6911|223344556677885f5f5f5f5f	64	intel	punpckhwd xmm2, xmmword ptr [rcx]
+660f6911|223344556677885f5f5f5f5f	64	plan9	PUNPCKHWD 0(CX), X2
+660f6a11|223344556677885f5f5f5f5f	32	intel	punpckhdq xmm2, xmmword ptr [ecx]
+660f6a11|223344556677885f5f5f5f5f	32	plan9	PUNPCKHDQ 0(CX), X2
+660f6a11|223344556677885f5f5f5f5f	64	gnu	punpckhdq (%rcx),%xmm2
+660f6a11|223344556677885f5f5f5f5f	64	intel	punpckhdq xmm2, xmmword ptr [rcx]
+660f6a11|223344556677885f5f5f5f5f	64	plan9	PUNPCKHDQ 0(CX), X2
+660f6b11|223344556677885f5f5f5f5f	32	intel	packssdw xmm2, xmmword ptr [ecx]
+660f6b11|223344556677885f5f5f5f5f	32	plan9	PACKSSDW 0(CX), X2
+660f6b11|223344556677885f5f5f5f5f	64	gnu	packssdw (%rcx),%xmm2
+660f6b11|223344556677885f5f5f5f5f	64	intel	packssdw xmm2, xmmword ptr [rcx]
+660f6b11|223344556677885f5f5f5f5f	64	plan9	PACKSSDW 0(CX), X2
+660f6c11|223344556677885f5f5f5f5f	32	intel	punpcklqdq xmm2, xmmword ptr [ecx]
+660f6c11|223344556677885f5f5f5f5f	32	plan9	PUNPCKLQDQ 0(CX), X2
+660f6c11|223344556677885f5f5f5f5f	64	gnu	punpcklqdq (%rcx),%xmm2
+660f6c11|223344556677885f5f5f5f5f	64	intel	punpcklqdq xmm2, xmmword ptr [rcx]
+660f6c11|223344556677885f5f5f5f5f	64	plan9	PUNPCKLQDQ 0(CX), X2
+660f6d11|223344556677885f5f5f5f5f	32	intel	punpckhqdq xmm2, xmmword ptr [ecx]
+660f6d11|223344556677885f5f5f5f5f	32	plan9	PUNPCKHQDQ 0(CX), X2
+660f6d11|223344556677885f5f5f5f5f	64	gnu	punpckhqdq (%rcx),%xmm2
+660f6d11|223344556677885f5f5f5f5f	64	intel	punpckhqdq xmm2, xmmword ptr [rcx]
+660f6d11|223344556677885f5f5f5f5f	64	plan9	PUNPCKHQDQ 0(CX), X2
+660f6e11|223344556677885f5f5f5f5f	32	intel	movd xmm2, dword ptr [ecx]
+660f6e11|223344556677885f5f5f5f5f	32	plan9	MOVD 0(CX), X2
+660f6e11|223344556677885f5f5f5f5f	64	gnu	movd (%rcx),%xmm2
+660f6e11|223344556677885f5f5f5f5f	64	intel	movd xmm2, dword ptr [rcx]
+660f6e11|223344556677885f5f5f5f5f	64	plan9	MOVD 0(CX), X2
+660f6f11|223344556677885f5f5f5f5f	32	intel	movdqa xmm2, xmmword ptr [ecx]
+660f6f11|223344556677885f5f5f5f5f	32	plan9	MOVDQA 0(CX), X2
+660f6f11|223344556677885f5f5f5f5f	64	gnu	movdqa (%rcx),%xmm2
+660f6f11|223344556677885f5f5f5f5f	64	intel	movdqa xmm2, xmmword ptr [rcx]
+660f6f11|223344556677885f5f5f5f5f	64	plan9	MOVDQA 0(CX), X2
+660f701122|3344556677885f5f5f5f5f	32	intel	pshufd xmm2, xmmword ptr [ecx], 0x22
+660f701122|3344556677885f5f5f5f5f	32	plan9	PSHUFD $0x22, 0(CX), X2
+660f701122|3344556677885f5f5f5f5f	64	gnu	pshufd $0x22,(%rcx),%xmm2
+660f701122|3344556677885f5f5f5f5f	64	intel	pshufd xmm2, xmmword ptr [rcx], 0x22
+660f701122|3344556677885f5f5f5f5f	64	plan9	PSHUFD $0x22, 0(CX), X2
+660f71d011|223344556677885f5f5f5f	32	intel	psrlw xmm0, 0x11
+660f71d011|223344556677885f5f5f5f	32	plan9	PSRLW $0x11, X0
+660f71d011|223344556677885f5f5f5f	64	gnu	psrlw $0x11,%xmm0
+660f71d011|223344556677885f5f5f5f	64	intel	psrlw xmm0, 0x11
+660f71d011|223344556677885f5f5f5f	64	plan9	PSRLW $0x11, X0
+660f71e011|223344556677885f5f5f5f	32	intel	psraw xmm0, 0x11
+660f71e011|223344556677885f5f5f5f	32	plan9	PSRAW $0x11, X0
+660f71e011|223344556677885f5f5f5f	64	gnu	psraw $0x11,%xmm0
+660f71e011|223344556677885f5f5f5f	64	intel	psraw xmm0, 0x11
+660f71e011|223344556677885f5f5f5f	64	plan9	PSRAW $0x11, X0
+660f71f011|223344556677885f5f5f5f	32	intel	psllw xmm0, 0x11
+660f71f011|223344556677885f5f5f5f	32	plan9	PSLLW $0x11, X0
+660f71f011|223344556677885f5f5f5f	64	gnu	psllw $0x11,%xmm0
+660f71f011|223344556677885f5f5f5f	64	intel	psllw xmm0, 0x11
+660f71f011|223344556677885f5f5f5f	64	plan9	PSLLW $0x11, X0
+660f72d011|223344556677885f5f5f5f	32	intel	psrld xmm0, 0x11
+660f72d011|223344556677885f5f5f5f	32	plan9	PSRLD $0x11, X0
+660f72d011|223344556677885f5f5f5f	64	gnu	psrld $0x11,%xmm0
+660f72d011|223344556677885f5f5f5f	64	intel	psrld xmm0, 0x11
+660f72d011|223344556677885f5f5f5f	64	plan9	PSRLD $0x11, X0
+660f72e011|223344556677885f5f5f5f	32	intel	psrad xmm0, 0x11
+660f72e011|223344556677885f5f5f5f	32	plan9	PSRAD $0x11, X0
+660f72e011|223344556677885f5f5f5f	64	gnu	psrad $0x11,%xmm0
+660f72e011|223344556677885f5f5f5f	64	intel	psrad xmm0, 0x11
+660f72e011|223344556677885f5f5f5f	64	plan9	PSRAD $0x11, X0
+660f72f011|223344556677885f5f5f5f	32	intel	pslld xmm0, 0x11
+660f72f011|223344556677885f5f5f5f	32	plan9	PSLLD $0x11, X0
+660f72f011|223344556677885f5f5f5f	64	gnu	pslld $0x11,%xmm0
+660f72f011|223344556677885f5f5f5f	64	intel	pslld xmm0, 0x11
+660f72f011|223344556677885f5f5f5f	64	plan9	PSLLD $0x11, X0
+660f73d011|223344556677885f5f5f5f	32	intel	psrlq xmm0, 0x11
+660f73d011|223344556677885f5f5f5f	32	plan9	PSRLQ $0x11, X0
+660f73d011|223344556677885f5f5f5f	64	gnu	psrlq $0x11,%xmm0
+660f73d011|223344556677885f5f5f5f	64	intel	psrlq xmm0, 0x11
+660f73d011|223344556677885f5f5f5f	64	plan9	PSRLQ $0x11, X0
+660f73d811|223344556677885f5f5f5f	32	intel	psrldq xmm0, 0x11
+660f73d811|223344556677885f5f5f5f	32	plan9	PSRLDQ $0x11, X0
+660f73d811|223344556677885f5f5f5f	64	gnu	psrldq $0x11,%xmm0
+660f73d811|223344556677885f5f5f5f	64	intel	psrldq xmm0, 0x11
+660f73d811|223344556677885f5f5f5f	64	plan9	PSRLDQ $0x11, X0
+660f73f011|223344556677885f5f5f5f	32	intel	psllq xmm0, 0x11
+660f73f011|223344556677885f5f5f5f	32	plan9	PSLLQ $0x11, X0
+660f73f011|223344556677885f5f5f5f	64	gnu	psllq $0x11,%xmm0
+660f73f011|223344556677885f5f5f5f	64	intel	psllq xmm0, 0x11
+660f73f011|223344556677885f5f5f5f	64	plan9	PSLLQ $0x11, X0
+660f73f811|223344556677885f5f5f5f	32	intel	pslldq xmm0, 0x11
+660f73f811|223344556677885f5f5f5f	32	plan9	PSLLDQ $0x11, X0
+660f73f811|223344556677885f5f5f5f	64	gnu	pslldq $0x11,%xmm0
+660f73f811|223344556677885f5f5f5f	64	intel	pslldq xmm0, 0x11
+660f73f811|223344556677885f5f5f5f	64	plan9	PSLLDQ $0x11, X0
+660f7411|223344556677885f5f5f5f5f	32	intel	pcmpeqb xmm2, xmmword ptr [ecx]
+660f7411|223344556677885f5f5f5f5f	32	plan9	PCMPEQB 0(CX), X2
+660f7411|223344556677885f5f5f5f5f	64	gnu	pcmpeqb (%rcx),%xmm2
+660f7411|223344556677885f5f5f5f5f	64	intel	pcmpeqb xmm2, xmmword ptr [rcx]
+660f7411|223344556677885f5f5f5f5f	64	plan9	PCMPEQB 0(CX), X2
+660f7511|223344556677885f5f5f5f5f	32	intel	pcmpeqw xmm2, xmmword ptr [ecx]
+660f7511|223344556677885f5f5f5f5f	32	plan9	PCMPEQW 0(CX), X2
+660f7511|223344556677885f5f5f5f5f	64	gnu	pcmpeqw (%rcx),%xmm2
+660f7511|223344556677885f5f5f5f5f	64	intel	pcmpeqw xmm2, xmmword ptr [rcx]
+660f7511|223344556677885f5f5f5f5f	64	plan9	PCMPEQW 0(CX), X2
+660f7611|223344556677885f5f5f5f5f	32	intel	pcmpeqd xmm2, xmmword ptr [ecx]
+660f7611|223344556677885f5f5f5f5f	32	plan9	PCMPEQD 0(CX), X2
+660f7611|223344556677885f5f5f5f5f	64	gnu	pcmpeqd (%rcx),%xmm2
+660f7611|223344556677885f5f5f5f5f	64	intel	pcmpeqd xmm2, xmmword ptr [rcx]
+660f7611|223344556677885f5f5f5f5f	64	plan9	PCMPEQD 0(CX), X2
+660f7c11|223344556677885f5f5f5f5f	32	intel	haddpd xmm2, xmmword ptr [ecx]
+660f7c11|223344556677885f5f5f5f5f	32	plan9	HADDPD 0(CX), X2
+660f7c11|223344556677885f5f5f5f5f	64	gnu	haddpd (%rcx),%xmm2
+660f7c11|223344556677885f5f5f5f5f	64	intel	haddpd xmm2, xmmword ptr [rcx]
+660f7c11|223344556677885f5f5f5f5f	64	plan9	HADDPD 0(CX), X2
+660f7d11|223344556677885f5f5f5f5f	32	intel	hsubpd xmm2, xmmword ptr [ecx]
+660f7d11|223344556677885f5f5f5f5f	32	plan9	HSUBPD 0(CX), X2
+660f7d11|223344556677885f5f5f5f5f	64	gnu	hsubpd (%rcx),%xmm2
+660f7d11|223344556677885f5f5f5f5f	64	intel	hsubpd xmm2, xmmword ptr [rcx]
+660f7d11|223344556677885f5f5f5f5f	64	plan9	HSUBPD 0(CX), X2
+660f7e11|223344556677885f5f5f5f5f	32	intel	movd dword ptr [ecx], xmm2
+660f7e11|223344556677885f5f5f5f5f	32	plan9	MOVD X2, 0(CX)
+660f7e11|223344556677885f5f5f5f5f	64	gnu	movd %xmm2,(%rcx)
+660f7e11|223344556677885f5f5f5f5f	64	intel	movd dword ptr [rcx], xmm2
+660f7e11|223344556677885f5f5f5f5f	64	plan9	MOVD X2, 0(CX)
+660f7f11|223344556677885f5f5f5f5f	32	intel	movdqa xmmword ptr [ecx], xmm2
+660f7f11|223344556677885f5f5f5f5f	32	plan9	MOVDQA X2, 0(CX)
+660f7f11|223344556677885f5f5f5f5f	64	gnu	movdqa %xmm2,(%rcx)
+660f7f11|223344556677885f5f5f5f5f	64	intel	movdqa xmmword ptr [rcx], xmm2
+660f7f11|223344556677885f5f5f5f5f	64	plan9	MOVDQA X2, 0(CX)
+660f8011223344|556677885f5f5f5f5f	64	gnu	jo .+0x44332211
+660f8011223344|556677885f5f5f5f5f	64	intel	jo .+0x44332211
+660f8011223344|556677885f5f5f5f5f	64	plan9	JO .+1144201745
+660f801122|3344556677885f5f5f5f5f	32	intel	jo .+0x2211
+660f801122|3344556677885f5f5f5f5f	32	plan9	JO .+8721
+660f8111223344|556677885f5f5f5f5f	64	gnu	jno .+0x44332211
+660f8111223344|556677885f5f5f5f5f	64	intel	jno .+0x44332211
+660f8111223344|556677885f5f5f5f5f	64	plan9	JNO .+1144201745
+660f811122|3344556677885f5f5f5f5f	32	intel	jno .+0x2211
+660f811122|3344556677885f5f5f5f5f	32	plan9	JNO .+8721
+660f8211223344|556677885f5f5f5f5f	64	gnu	jb .+0x44332211
+660f8211223344|556677885f5f5f5f5f	64	intel	jb .+0x44332211
+660f8211223344|556677885f5f5f5f5f	64	plan9	JB .+1144201745
+660f821122|3344556677885f5f5f5f5f	32	intel	jb .+0x2211
+660f821122|3344556677885f5f5f5f5f	32	plan9	JB .+8721
+660f8311223344|556677885f5f5f5f5f	64	gnu	jae .+0x44332211
+660f8311223344|556677885f5f5f5f5f	64	intel	jnb .+0x44332211
+660f8311223344|556677885f5f5f5f5f	64	plan9	JAE .+1144201745
+660f831122|3344556677885f5f5f5f5f	32	intel	jnb .+0x2211
+660f831122|3344556677885f5f5f5f5f	32	plan9	JAE .+8721
+660f8411223344|556677885f5f5f5f5f	64	gnu	je .+0x44332211
+660f8411223344|556677885f5f5f5f5f	64	intel	jz .+0x44332211
+660f8411223344|556677885f5f5f5f5f	64	plan9	JE .+1144201745
+660f841122|3344556677885f5f5f5f5f	32	intel	jz .+0x2211
+660f841122|3344556677885f5f5f5f5f	32	plan9	JE .+8721
+660f8511223344|556677885f5f5f5f5f	64	gnu	jne .+0x44332211
+660f8511223344|556677885f5f5f5f5f	64	intel	jnz .+0x44332211
+660f8511223344|556677885f5f5f5f5f	64	plan9	JNE .+1144201745
+660f851122|3344556677885f5f5f5f5f	32	intel	jnz .+0x2211
+660f851122|3344556677885f5f5f5f5f	32	plan9	JNE .+8721
+660f8611223344|556677885f5f5f5f5f	64	gnu	jbe .+0x44332211
+660f8611223344|556677885f5f5f5f5f	64	intel	jbe .+0x44332211
+660f8611223344|556677885f5f5f5f5f	64	plan9	JBE .+1144201745
+660f861122|3344556677885f5f5f5f5f	32	intel	jbe .+0x2211
+660f861122|3344556677885f5f5f5f5f	32	plan9	JBE .+8721
+660f8711223344|556677885f5f5f5f5f	64	gnu	ja .+0x44332211
+660f8711223344|556677885f5f5f5f5f	64	intel	jnbe .+0x44332211
+660f8711223344|556677885f5f5f5f5f	64	plan9	JA .+1144201745
+660f871122|3344556677885f5f5f5f5f	32	intel	jnbe .+0x2211
+660f871122|3344556677885f5f5f5f5f	32	plan9	JA .+8721
+660f8811223344|556677885f5f5f5f5f	64	gnu	js .+0x44332211
+660f8811223344|556677885f5f5f5f5f	64	intel	js .+0x44332211
+660f8811223344|556677885f5f5f5f5f	64	plan9	JS .+1144201745
+660f881122|3344556677885f5f5f5f5f	32	intel	js .+0x2211
+660f881122|3344556677885f5f5f5f5f	32	plan9	JS .+8721
+660f8911223344|556677885f5f5f5f5f	64	gnu	jns .+0x44332211
+660f8911223344|556677885f5f5f5f5f	64	intel	jns .+0x44332211
+660f8911223344|556677885f5f5f5f5f	64	plan9	JNS .+1144201745
+660f891122|3344556677885f5f5f5f5f	32	intel	jns .+0x2211
+660f891122|3344556677885f5f5f5f5f	32	plan9	JNS .+8721
+660f8a11223344|556677885f5f5f5f5f	64	gnu	jp .+0x44332211
+660f8a11223344|556677885f5f5f5f5f	64	intel	jp .+0x44332211
+660f8a11223344|556677885f5f5f5f5f	64	plan9	JP .+1144201745
+660f8a1122|3344556677885f5f5f5f5f	32	intel	jp .+0x2211
+660f8a1122|3344556677885f5f5f5f5f	32	plan9	JP .+8721
+660f8b11223344|556677885f5f5f5f5f	64	gnu	jnp .+0x44332211
+660f8b11223344|556677885f5f5f5f5f	64	intel	jnp .+0x44332211
+660f8b11223344|556677885f5f5f5f5f	64	plan9	JNP .+1144201745
+660f8b1122|3344556677885f5f5f5f5f	32	intel	jnp .+0x2211
+660f8b1122|3344556677885f5f5f5f5f	32	plan9	JNP .+8721
+660f8c11223344|556677885f5f5f5f5f	64	gnu	jl .+0x44332211
+660f8c11223344|556677885f5f5f5f5f	64	intel	jl .+0x44332211
+660f8c11223344|556677885f5f5f5f5f	64	plan9	JL .+1144201745
+660f8c1122|3344556677885f5f5f5f5f	32	intel	jl .+0x2211
+660f8c1122|3344556677885f5f5f5f5f	32	plan9	JL .+8721
+660f8d11223344|556677885f5f5f5f5f	64	gnu	jge .+0x44332211
+660f8d11223344|556677885f5f5f5f5f	64	intel	jnl .+0x44332211
+660f8d11223344|556677885f5f5f5f5f	64	plan9	JGE .+1144201745
+660f8d1122|3344556677885f5f5f5f5f	32	intel	jnl .+0x2211
+660f8d1122|3344556677885f5f5f5f5f	32	plan9	JGE .+8721
+660f8e11223344|556677885f5f5f5f5f	64	gnu	jle .+0x44332211
+660f8e11223344|556677885f5f5f5f5f	64	intel	jle .+0x44332211
+660f8e11223344|556677885f5f5f5f5f	64	plan9	JLE .+1144201745
+660f8e1122|3344556677885f5f5f5f5f	32	intel	jle .+0x2211
+660f8e1122|3344556677885f5f5f5f5f	32	plan9	JLE .+8721
+660f8f11223344|556677885f5f5f5f5f	64	gnu	jg .+0x44332211
+660f8f11223344|556677885f5f5f5f5f	64	intel	jnle .+0x44332211
+660f8f11223344|556677885f5f5f5f5f	64	plan9	JG .+1144201745
+660f8f1122|3344556677885f5f5f5f5f	32	intel	jnle .+0x2211
+660f8f1122|3344556677885f5f5f5f5f	32	plan9	JG .+8721
+660fa1|11223344556677885f5f5f5f5f	32	intel	pop fs
+660fa1|11223344556677885f5f5f5f5f	32	plan9	POPW FS
+660fa1|11223344556677885f5f5f5f5f	64	gnu	popw %fs
+660fa1|11223344556677885f5f5f5f5f	64	intel	pop fs
+660fa1|11223344556677885f5f5f5f5f	64	plan9	POPW FS
+660fa311|223344556677885f5f5f5f5f	32	intel	bt word ptr [ecx], dx
+660fa311|223344556677885f5f5f5f5f	32	plan9	BTW DX, 0(CX)
+660fa311|223344556677885f5f5f5f5f	64	gnu	bt %dx,(%rcx)
+660fa311|223344556677885f5f5f5f5f	64	intel	bt word ptr [rcx], dx
+660fa311|223344556677885f5f5f5f5f	64	plan9	BTW DX, 0(CX)
+660fa41122|3344556677885f5f5f5f5f	32	intel	shld word ptr [ecx], dx, 0x22
+660fa41122|3344556677885f5f5f5f5f	32	plan9	SHLDW $0x22, DX, 0(CX)
+660fa41122|3344556677885f5f5f5f5f	64	gnu	shld $0x22,%dx,(%rcx)
+660fa41122|3344556677885f5f5f5f5f	64	intel	shld word ptr [rcx], dx, 0x22
+660fa41122|3344556677885f5f5f5f5f	64	plan9	SHLDW $0x22, DX, 0(CX)
+660fa511|223344556677885f5f5f5f5f	32	intel	shld word ptr [ecx], dx, cl
+660fa511|223344556677885f5f5f5f5f	32	plan9	SHLDW CL, DX, 0(CX)
+660fa511|223344556677885f5f5f5f5f	64	gnu	shld %cl,%dx,(%rcx)
+660fa511|223344556677885f5f5f5f5f	64	intel	shld word ptr [rcx], dx, cl
+660fa511|223344556677885f5f5f5f5f	64	plan9	SHLDW CL, DX, 0(CX)
+660fa9|11223344556677885f5f5f5f5f	32	intel	pop gs
+660fa9|11223344556677885f5f5f5f5f	32	plan9	POPW GS
+660fa9|11223344556677885f5f5f5f5f	64	gnu	popw %gs
+660fa9|11223344556677885f5f5f5f5f	64	intel	pop gs
+660fa9|11223344556677885f5f5f5f5f	64	plan9	POPW GS
+660fab11|223344556677885f5f5f5f5f	32	intel	bts word ptr [ecx], dx
+660fab11|223344556677885f5f5f5f5f	32	plan9	BTSW DX, 0(CX)
+660fab11|223344556677885f5f5f5f5f	64	gnu	bts %dx,(%rcx)
+660fab11|223344556677885f5f5f5f5f	64	intel	bts word ptr [rcx], dx
+660fab11|223344556677885f5f5f5f5f	64	plan9	BTSW DX, 0(CX)
+660fac1122|3344556677885f5f5f5f5f	32	intel	shrd word ptr [ecx], dx, 0x22
+660fac1122|3344556677885f5f5f5f5f	32	plan9	SHRDW $0x22, DX, 0(CX)
+660fac1122|3344556677885f5f5f5f5f	64	gnu	shrd $0x22,%dx,(%rcx)
+660fac1122|3344556677885f5f5f5f5f	64	intel	shrd word ptr [rcx], dx, 0x22
+660fac1122|3344556677885f5f5f5f5f	64	plan9	SHRDW $0x22, DX, 0(CX)
+660fad11|223344556677885f5f5f5f5f	32	intel	shrd word ptr [ecx], dx, cl
+660fad11|223344556677885f5f5f5f5f	32	plan9	SHRDW CL, DX, 0(CX)
+660fad11|223344556677885f5f5f5f5f	64	gnu	shrd %cl,%dx,(%rcx)
+660fad11|223344556677885f5f5f5f5f	64	intel	shrd word ptr [rcx], dx, cl
+660fad11|223344556677885f5f5f5f5f	64	plan9	SHRDW CL, DX, 0(CX)
+660fae00|11223344556677885f5f5f5f	32	intel	fxsave ptr [eax]
+660fae00|11223344556677885f5f5f5f	32	plan9	FXSAVE 0(AX)
+660fae00|11223344556677885f5f5f5f	64	gnu	fxsave (%rax)
+660fae00|11223344556677885f5f5f5f	64	intel	fxsave ptr [rax]
+660fae00|11223344556677885f5f5f5f	64	plan9	FXSAVE 0(AX)
+660fae08|11223344556677885f5f5f5f	32	intel	fxrstor ptr [eax]
+660fae08|11223344556677885f5f5f5f	32	plan9	FXRSTOR 0(AX)
+660fae08|11223344556677885f5f5f5f	64	gnu	data16 fxrstor (%rax)
+660fae08|11223344556677885f5f5f5f	64	intel	fxrstor ptr [rax]
+660fae08|11223344556677885f5f5f5f	64	plan9	FXRSTOR 0(AX)
+660fae20|11223344556677885f5f5f5f	32	intel	xsave ptr [eax]
+660fae20|11223344556677885f5f5f5f	32	plan9	XSAVE 0(AX)
+660fae20|11223344556677885f5f5f5f	64	gnu	data16 xsave (%rax)
+660fae20|11223344556677885f5f5f5f	64	intel	xsave ptr [rax]
+660fae20|11223344556677885f5f5f5f	64	plan9	XSAVE 0(AX)
+660fae28|11223344556677885f5f5f5f	32	intel	xrstor ptr [eax]
+660fae28|11223344556677885f5f5f5f	32	plan9	XRSTOR 0(AX)
+660fae28|11223344556677885f5f5f5f	64	gnu	data16 xrstor (%rax)
+660fae28|11223344556677885f5f5f5f	64	intel	xrstor ptr [rax]
+660fae28|11223344556677885f5f5f5f	64	plan9	XRSTOR 0(AX)
+660fae30|11223344556677885f5f5f5f	32	intel	xsaveopt ptr [eax]
+660fae30|11223344556677885f5f5f5f	32	plan9	XSAVEOPT 0(AX)
+660fae30|11223344556677885f5f5f5f	64	gnu	data16 xsaveopt (%rax)
+660fae30|11223344556677885f5f5f5f	64	intel	xsaveopt ptr [rax]
+660fae30|11223344556677885f5f5f5f	64	plan9	XSAVEOPT 0(AX)
+660faf11|223344556677885f5f5f5f5f	32	intel	imul dx, word ptr [ecx]
+660faf11|223344556677885f5f5f5f5f	32	plan9	IMULW 0(CX), DX
+660faf11|223344556677885f5f5f5f5f	64	gnu	imul (%rcx),%dx
+660faf11|223344556677885f5f5f5f5f	64	intel	imul dx, word ptr [rcx]
+660faf11|223344556677885f5f5f5f5f	64	plan9	IMULW 0(CX), DX
+660fb111|223344556677885f5f5f5f5f	32	intel	cmpxchg word ptr [ecx], dx
+660fb111|223344556677885f5f5f5f5f	32	plan9	CMPXCHGW DX, 0(CX)
+660fb111|223344556677885f5f5f5f5f	64	gnu	cmpxchg %dx,(%rcx)
+660fb111|223344556677885f5f5f5f5f	64	intel	cmpxchg word ptr [rcx], dx
+660fb111|223344556677885f5f5f5f5f	64	plan9	CMPXCHGW DX, 0(CX)
+660fb211|223344556677885f5f5f5f5f	32	intel	lss dx, dword ptr [ecx]
+660fb211|223344556677885f5f5f5f5f	32	plan9	LSS 0(CX), DX
+660fb211|223344556677885f5f5f5f5f	64	gnu	lss (%rcx),%dx
+660fb211|223344556677885f5f5f5f5f	64	intel	lss dx, dword ptr [rcx]
+660fb211|223344556677885f5f5f5f5f	64	plan9	LSS 0(CX), DX
+660fb311|223344556677885f5f5f5f5f	32	intel	btr word ptr [ecx], dx
+660fb311|223344556677885f5f5f5f5f	32	plan9	BTRW DX, 0(CX)
+660fb311|223344556677885f5f5f5f5f	64	gnu	btr %dx,(%rcx)
+660fb311|223344556677885f5f5f5f5f	64	intel	btr word ptr [rcx], dx
+660fb311|223344556677885f5f5f5f5f	64	plan9	BTRW DX, 0(CX)
+660fb411|223344556677885f5f5f5f5f	32	intel	lfs dx, dword ptr [ecx]
+660fb411|223344556677885f5f5f5f5f	32	plan9	LFS 0(CX), DX
+660fb411|223344556677885f5f5f5f5f	64	gnu	lfs (%rcx),%dx
+660fb411|223344556677885f5f5f5f5f	64	intel	lfs dx, dword ptr [rcx]
+660fb411|223344556677885f5f5f5f5f	64	plan9	LFS 0(CX), DX
+660fb511|223344556677885f5f5f5f5f	32	intel	lgs dx, dword ptr [ecx]
+660fb511|223344556677885f5f5f5f5f	32	plan9	LGS 0(CX), DX
+660fb511|223344556677885f5f5f5f5f	64	gnu	lgs (%rcx),%dx
+660fb511|223344556677885f5f5f5f5f	64	intel	lgs dx, dword ptr [rcx]
+660fb511|223344556677885f5f5f5f5f	64	plan9	LGS 0(CX), DX
+660fb611|223344556677885f5f5f5f5f	32	intel	movzx dx, byte ptr [ecx]
+660fb611|223344556677885f5f5f5f5f	32	plan9	MOVZX 0(CX), DX
+660fb611|223344556677885f5f5f5f5f	64	gnu	movzbw (%rcx),%dx
+660fb611|223344556677885f5f5f5f5f	64	intel	movzx dx, byte ptr [rcx]
+660fb611|223344556677885f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
+660fb711|223344556677885f5f5f5f5f	32	intel	movzx dx, word ptr [ecx]
+660fb711|223344556677885f5f5f5f5f	32	plan9	MOVZX 0(CX), DX
+660fb711|223344556677885f5f5f5f5f	64	gnu	movzww (%rcx),%dx
+660fb711|223344556677885f5f5f5f5f	64	intel	movzx dx, word ptr [rcx]
+660fb711|223344556677885f5f5f5f5f	64	plan9	MOVZX 0(CX), DX
+660fba2011|223344556677885f5f5f5f	32	intel	bt word ptr [eax], 0x11
+660fba2011|223344556677885f5f5f5f	32	plan9	BTW $0x11, 0(AX)
+660fba2011|223344556677885f5f5f5f	64	gnu	btw $0x11,(%rax)
+660fba2011|223344556677885f5f5f5f	64	intel	bt word ptr [rax], 0x11
+660fba2011|223344556677885f5f5f5f	64	plan9	BTW $0x11, 0(AX)
+660fba2811|223344556677885f5f5f5f	32	intel	bts word ptr [eax], 0x11
+660fba2811|223344556677885f5f5f5f	32	plan9	BTSW $0x11, 0(AX)
+660fba2811|223344556677885f5f5f5f	64	gnu	btsw $0x11,(%rax)
+660fba2811|223344556677885f5f5f5f	64	intel	bts word ptr [rax], 0x11
+660fba2811|223344556677885f5f5f5f	64	plan9	BTSW $0x11, 0(AX)
+660fba3011|223344556677885f5f5f5f	32	intel	btr word ptr [eax], 0x11
+660fba3011|223344556677885f5f5f5f	32	plan9	BTRW $0x11, 0(AX)
+660fba3011|223344556677885f5f5f5f	64	gnu	btrw $0x11,(%rax)
+660fba3011|223344556677885f5f5f5f	64	intel	btr word ptr [rax], 0x11
+660fba3011|223344556677885f5f5f5f	64	plan9	BTRW $0x11, 0(AX)
+660fba3811|223344556677885f5f5f5f	32	intel	btc word ptr [eax], 0x11
+660fba3811|223344556677885f5f5f5f	32	plan9	BTCW $0x11, 0(AX)
+660fba3811|223344556677885f5f5f5f	64	gnu	btcw $0x11,(%rax)
+660fba3811|223344556677885f5f5f5f	64	intel	btc word ptr [rax], 0x11
+660fba3811|223344556677885f5f5f5f	64	plan9	BTCW $0x11, 0(AX)
+660fbb11|223344556677885f5f5f5f5f	32	intel	btc word ptr [ecx], dx
+660fbb11|223344556677885f5f5f5f5f	32	plan9	BTCW DX, 0(CX)
+660fbb11|223344556677885f5f5f5f5f	64	gnu	btc %dx,(%rcx)
+660fbb11|223344556677885f5f5f5f5f	64	intel	btc word ptr [rcx], dx
+660fbb11|223344556677885f5f5f5f5f	64	plan9	BTCW DX, 0(CX)
+660fbc11|223344556677885f5f5f5f5f	32	intel	bsf dx, word ptr [ecx]
+660fbc11|223344556677885f5f5f5f5f	32	plan9	BSFW 0(CX), DX
+660fbc11|223344556677885f5f5f5f5f	64	gnu	bsf (%rcx),%dx
+660fbc11|223344556677885f5f5f5f5f	64	intel	bsf dx, word ptr [rcx]
+660fbc11|223344556677885f5f5f5f5f	64	plan9	BSFW 0(CX), DX
+660fbd11|223344556677885f5f5f5f5f	32	intel	bsr dx, word ptr [ecx]
+660fbd11|223344556677885f5f5f5f5f	32	plan9	BSRW 0(CX), DX
+660fbd11|223344556677885f5f5f5f5f	64	gnu	bsr (%rcx),%dx
+660fbd11|223344556677885f5f5f5f5f	64	intel	bsr dx, word ptr [rcx]
+660fbd11|223344556677885f5f5f5f5f	64	plan9	BSRW 0(CX), DX
+660fbe11|223344556677885f5f5f5f5f	32	intel	movsx dx, byte ptr [ecx]
+660fbe11|223344556677885f5f5f5f5f	32	plan9	MOVSX 0(CX), DX
+660fbe11|223344556677885f5f5f5f5f	64	gnu	movsbw (%rcx),%dx
+660fbe11|223344556677885f5f5f5f5f	64	intel	movsx dx, byte ptr [rcx]
+660fbe11|223344556677885f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
+660fbf11|223344556677885f5f5f5f5f	32	intel	movsx dx, word ptr [ecx]
+660fbf11|223344556677885f5f5f5f5f	32	plan9	MOVSX 0(CX), DX
+660fbf11|223344556677885f5f5f5f5f	64	gnu	movsww (%rcx),%dx
+660fbf11|223344556677885f5f5f5f5f	64	intel	movsx dx, word ptr [rcx]
+660fbf11|223344556677885f5f5f5f5f	64	plan9	MOVSX 0(CX), DX
+660fc111|223344556677885f5f5f5f5f	32	intel	xadd word ptr [ecx], dx
+660fc111|223344556677885f5f5f5f5f	32	plan9	XADDW DX, 0(CX)
+660fc111|223344556677885f5f5f5f5f	64	gnu	xadd %dx,(%rcx)
+660fc111|223344556677885f5f5f5f5f	64	intel	xadd word ptr [rcx], dx
+660fc111|223344556677885f5f5f5f5f	64	plan9	XADDW DX, 0(CX)
+660fc21122|3344556677885f5f5f5f5f	32	intel	cmppd xmm2, xmmword ptr [ecx], 0x22
+660fc21122|3344556677885f5f5f5f5f	32	plan9	CMPPD $0x22, 0(CX), X2
+660fc21122|3344556677885f5f5f5f5f	64	gnu	cmppd $0x22,(%rcx),%xmm2
+660fc21122|3344556677885f5f5f5f5f	64	intel	cmppd xmm2, xmmword ptr [rcx], 0x22
+660fc21122|3344556677885f5f5f5f5f	64	plan9	CMPPD $0x22, 0(CX), X2
+660fc311|223344556677885f5f5f5f5f	32	intel	movnti dword ptr [ecx], edx
+660fc311|223344556677885f5f5f5f5f	32	plan9	MOVNTIL DX, 0(CX)
+660fc311|223344556677885f5f5f5f5f	64	gnu	movnti %edx,(%rcx)
+660fc311|223344556677885f5f5f5f5f	64	intel	movnti dword ptr [rcx], edx
+660fc311|223344556677885f5f5f5f5f	64	plan9	MOVNTIL DX, 0(CX)
+660fc41122|3344556677885f5f5f5f5f	32	intel	pinsrw xmm2, word ptr [ecx], 0x22
+660fc41122|3344556677885f5f5f5f5f	32	plan9	PINSRW $0x22, 0(CX), X2
+660fc41122|3344556677885f5f5f5f5f	64	gnu	pinsrw $0x22,(%rcx),%xmm2
+660fc41122|3344556677885f5f5f5f5f	64	intel	pinsrw xmm2, word ptr [rcx], 0x22
+660fc41122|3344556677885f5f5f5f5f	64	plan9	PINSRW $0x22, 0(CX), X2
+660fc5c011|223344556677885f5f5f5f	32	intel	pextrw eax, xmm0, 0x11
+660fc5c011|223344556677885f5f5f5f	32	plan9	PEXTRW $0x11, X0, AX
+660fc5c011|223344556677885f5f5f5f	64	gnu	pextrw $0x11,%xmm0,%eax
+660fc5c011|223344556677885f5f5f5f	64	intel	pextrw eax, xmm0, 0x11
+660fc5c011|223344556677885f5f5f5f	64	plan9	PEXTRW $0x11, X0, AX
+660fc61122|3344556677885f5f5f5f5f	32	intel	shufpd xmm2, xmmword ptr [ecx], 0x22
+660fc61122|3344556677885f5f5f5f5f	32	plan9	SHUFPD $0x22, 0(CX), X2
+660fc61122|3344556677885f5f5f5f5f	64	gnu	shufpd $0x22,(%rcx),%xmm2
+660fc61122|3344556677885f5f5f5f5f	64	intel	shufpd xmm2, xmmword ptr [rcx], 0x22
+660fc61122|3344556677885f5f5f5f5f	64	plan9	SHUFPD $0x22, 0(CX), X2
+660fc708|11223344556677885f5f5f5f	32	intel	cmpxchg8b qword ptr [eax]
+660fc708|11223344556677885f5f5f5f	32	plan9	CMPXCHG8B 0(AX)
+660fc708|11223344556677885f5f5f5f	64	gnu	data16 cmpxchg8b (%rax)
+660fc708|11223344556677885f5f5f5f	64	intel	cmpxchg8b qword ptr [rax]
+660fc708|11223344556677885f5f5f5f	64	plan9	CMPXCHG8B 0(AX)
+660fc718|11223344556677885f5f5f5f	32	intel	xrstors ptr [eax]
+660fc718|11223344556677885f5f5f5f	32	plan9	XRSTORS 0(AX)
+660fc718|11223344556677885f5f5f5f	64	gnu	xrstors (%rax)
+660fc718|11223344556677885f5f5f5f	64	intel	xrstors ptr [rax]
+660fc718|11223344556677885f5f5f5f	64	plan9	XRSTORS 0(AX)
+660fc720|11223344556677885f5f5f5f	32	intel	xsavec ptr [eax]
+660fc720|11223344556677885f5f5f5f	32	plan9	XSAVEC 0(AX)
+660fc720|11223344556677885f5f5f5f	64	gnu	xsavec (%rax)
+660fc720|11223344556677885f5f5f5f	64	intel	xsavec ptr [rax]
+660fc720|11223344556677885f5f5f5f	64	plan9	XSAVEC 0(AX)
+660fc728|11223344556677885f5f5f5f	32	intel	xsaves ptr [eax]
+660fc728|11223344556677885f5f5f5f	32	plan9	XSAVES 0(AX)
+660fc728|11223344556677885f5f5f5f	64	gnu	xsaves (%rax)
+660fc728|11223344556677885f5f5f5f	64	intel	xsaves ptr [rax]
+660fc728|11223344556677885f5f5f5f	64	plan9	XSAVES 0(AX)
+660fc7f2|11223344556677885f5f5f5f	32	intel	rdrand dx
+660fc7f2|11223344556677885f5f5f5f	32	plan9	RDRAND DX
+660fc7f2|11223344556677885f5f5f5f	64	gnu	rdrand %dx
+660fc7f2|11223344556677885f5f5f5f	64	intel	rdrand dx
+660fc7f2|11223344556677885f5f5f5f	64	plan9	RDRAND DX
+660fc8|11223344556677885f5f5f5f5f	32	intel	bswap ax
+660fc8|11223344556677885f5f5f5f5f	32	plan9	BSWAP AX
+660fc8|11223344556677885f5f5f5f5f	64	gnu	bswap %ax
+660fc8|11223344556677885f5f5f5f5f	64	intel	bswap ax
+660fc8|11223344556677885f5f5f5f5f	64	plan9	BSWAP AX
+660fd011|223344556677885f5f5f5f5f	32	intel	addsubpd xmm2, xmmword ptr [ecx]
+660fd011|223344556677885f5f5f5f5f	32	plan9	ADDSUBPD 0(CX), X2
+660fd011|223344556677885f5f5f5f5f	64	gnu	addsubpd (%rcx),%xmm2
+660fd011|223344556677885f5f5f5f5f	64	intel	addsubpd xmm2, xmmword ptr [rcx]
+660fd011|223344556677885f5f5f5f5f	64	plan9	ADDSUBPD 0(CX), X2
+660fd111|223344556677885f5f5f5f5f	32	intel	psrlw xmm2, xmmword ptr [ecx]
+660fd111|223344556677885f5f5f5f5f	32	plan9	PSRLW 0(CX), X2
+660fd111|223344556677885f5f5f5f5f	64	gnu	psrlw (%rcx),%xmm2
+660fd111|223344556677885f5f5f5f5f	64	intel	psrlw xmm2, xmmword ptr [rcx]
+660fd111|223344556677885f5f5f5f5f	64	plan9	PSRLW 0(CX), X2
+660fd211|223344556677885f5f5f5f5f	32	intel	psrld xmm2, xmmword ptr [ecx]
+660fd211|223344556677885f5f5f5f5f	32	plan9	PSRLD 0(CX), X2
+660fd211|223344556677885f5f5f5f5f	64	gnu	psrld (%rcx),%xmm2
+660fd211|223344556677885f5f5f5f5f	64	intel	psrld xmm2, xmmword ptr [rcx]
+660fd211|223344556677885f5f5f5f5f	64	plan9	PSRLD 0(CX), X2
+660fd311|223344556677885f5f5f5f5f	32	intel	psrlq xmm2, xmmword ptr [ecx]
+660fd311|223344556677885f5f5f5f5f	32	plan9	PSRLQ 0(CX), X2
+660fd311|223344556677885f5f5f5f5f	64	gnu	psrlq (%rcx),%xmm2
+660fd311|223344556677885f5f5f5f5f	64	intel	psrlq xmm2, xmmword ptr [rcx]
+660fd311|223344556677885f5f5f5f5f	64	plan9	PSRLQ 0(CX), X2
+660fd411|223344556677885f5f5f5f5f	32	intel	paddq xmm2, xmmword ptr [ecx]
+660fd411|223344556677885f5f5f5f5f	32	plan9	PADDQ 0(CX), X2
+660fd411|223344556677885f5f5f5f5f	64	gnu	paddq (%rcx),%xmm2
+660fd411|223344556677885f5f5f5f5f	64	intel	paddq xmm2, xmmword ptr [rcx]
+660fd411|223344556677885f5f5f5f5f	64	plan9	PADDQ 0(CX), X2
+660fd511|223344556677885f5f5f5f5f	32	intel	pmullw xmm2, xmmword ptr [ecx]
+660fd511|223344556677885f5f5f5f5f	32	plan9	PMULLW 0(CX), X2
+660fd511|223344556677885f5f5f5f5f	64	gnu	pmullw (%rcx),%xmm2
+660fd511|223344556677885f5f5f5f5f	64	intel	pmullw xmm2, xmmword ptr [rcx]
+660fd511|223344556677885f5f5f5f5f	64	plan9	PMULLW 0(CX), X2
+660fd611|223344556677885f5f5f5f5f	32	intel	movq qword ptr [ecx], xmm2
+660fd611|223344556677885f5f5f5f5f	32	plan9	MOVQ X2, 0(CX)
+660fd611|223344556677885f5f5f5f5f	64	gnu	movq %xmm2,(%rcx)
+660fd611|223344556677885f5f5f5f5f	64	intel	movq qword ptr [rcx], xmm2
+660fd611|223344556677885f5f5f5f5f	64	plan9	MOVQ X2, 0(CX)
+660fd7c0|11223344556677885f5f5f5f	32	intel	pmovmskb eax, xmm0
+660fd7c0|11223344556677885f5f5f5f	32	plan9	PMOVMSKB X0, AX
+660fd7c0|11223344556677885f5f5f5f	64	gnu	pmovmskb %xmm0,%eax
+660fd7c0|11223344556677885f5f5f5f	64	intel	pmovmskb eax, xmm0
+660fd7c0|11223344556677885f5f5f5f	64	plan9	PMOVMSKB X0, AX
+660fd811|223344556677885f5f5f5f5f	32	intel	psubusb xmm2, xmmword ptr [ecx]
+660fd811|223344556677885f5f5f5f5f	32	plan9	PSUBUSB 0(CX), X2
+660fd811|223344556677885f5f5f5f5f	64	gnu	psubusb (%rcx),%xmm2
+660fd811|223344556677885f5f5f5f5f	64	intel	psubusb xmm2, xmmword ptr [rcx]
+660fd811|223344556677885f5f5f5f5f	64	plan9	PSUBUSB 0(CX), X2
+660fd911|223344556677885f5f5f5f5f	32	intel	psubusw xmm2, xmmword ptr [ecx]
+660fd911|223344556677885f5f5f5f5f	32	plan9	PSUBUSW 0(CX), X2
+660fd911|223344556677885f5f5f5f5f	64	gnu	psubusw (%rcx),%xmm2
+660fd911|223344556677885f5f5f5f5f	64	intel	psubusw xmm2, xmmword ptr [rcx]
+660fd911|223344556677885f5f5f5f5f	64	plan9	PSUBUSW 0(CX), X2
+660fda11|223344556677885f5f5f5f5f	32	intel	pminub xmm2, xmmword ptr [ecx]
+660fda11|223344556677885f5f5f5f5f	32	plan9	PMINUB 0(CX), X2
+660fda11|223344556677885f5f5f5f5f	64	gnu	pminub (%rcx),%xmm2
+660fda11|223344556677885f5f5f5f5f	64	intel	pminub xmm2, xmmword ptr [rcx]
+660fda11|223344556677885f5f5f5f5f	64	plan9	PMINUB 0(CX), X2
+660fdb11|223344556677885f5f5f5f5f	32	intel	pand xmm2, xmmword ptr [ecx]
+660fdb11|223344556677885f5f5f5f5f	32	plan9	PAND 0(CX), X2
+660fdb11|223344556677885f5f5f5f5f	64	gnu	pand (%rcx),%xmm2
+660fdb11|223344556677885f5f5f5f5f	64	intel	pand xmm2, xmmword ptr [rcx]
+660fdb11|223344556677885f5f5f5f5f	64	plan9	PAND 0(CX), X2
+660fdc11|223344556677885f5f5f5f5f	32	intel	paddusb xmm2, xmmword ptr [ecx]
+660fdc11|223344556677885f5f5f5f5f	32	plan9	PADDUSB 0(CX), X2
+660fdc11|223344556677885f5f5f5f5f	64	gnu	paddusb (%rcx),%xmm2
+660fdc11|223344556677885f5f5f5f5f	64	intel	paddusb xmm2, xmmword ptr [rcx]
+660fdc11|223344556677885f5f5f5f5f	64	plan9	PADDUSB 0(CX), X2
+660fdd11|223344556677885f5f5f5f5f	32	intel	paddusw xmm2, xmmword ptr [ecx]
+660fdd11|223344556677885f5f5f5f5f	32	plan9	PADDUSW 0(CX), X2
+660fdd11|223344556677885f5f5f5f5f	64	gnu	paddusw (%rcx),%xmm2
+660fdd11|223344556677885f5f5f5f5f	64	intel	paddusw xmm2, xmmword ptr [rcx]
+660fdd11|223344556677885f5f5f5f5f	64	plan9	PADDUSW 0(CX), X2
+660fde11|223344556677885f5f5f5f5f	32	intel	pmaxub xmm2, xmmword ptr [ecx]
+660fde11|223344556677885f5f5f5f5f	32	plan9	PMAXUB 0(CX), X2
+660fde11|223344556677885f5f5f5f5f	64	gnu	pmaxub (%rcx),%xmm2
+660fde11|223344556677885f5f5f5f5f	64	intel	pmaxub xmm2, xmmword ptr [rcx]
+660fde11|223344556677885f5f5f5f5f	64	plan9	PMAXUB 0(CX), X2
+660fdf11|223344556677885f5f5f5f5f	32	intel	pandn xmm2, xmmword ptr [ecx]
+660fdf11|223344556677885f5f5f5f5f	32	plan9	PANDN 0(CX), X2
+660fdf11|223344556677885f5f5f5f5f	64	gnu	pandn (%rcx),%xmm2
+660fdf11|223344556677885f5f5f5f5f	64	intel	pandn xmm2, xmmword ptr [rcx]
+660fdf11|223344556677885f5f5f5f5f	64	plan9	PANDN 0(CX), X2
+660fe011|223344556677885f5f5f5f5f	32	intel	pavgb xmm2, xmmword ptr [ecx]
+660fe011|223344556677885f5f5f5f5f	32	plan9	PAVGB 0(CX), X2
+660fe011|223344556677885f5f5f5f5f	64	gnu	pavgb (%rcx),%xmm2
+660fe011|223344556677885f5f5f5f5f	64	intel	pavgb xmm2, xmmword ptr [rcx]
+660fe011|223344556677885f5f5f5f5f	64	plan9	PAVGB 0(CX), X2
+660fe111|223344556677885f5f5f5f5f	32	intel	psraw xmm2, xmmword ptr [ecx]
+660fe111|223344556677885f5f5f5f5f	32	plan9	PSRAW 0(CX), X2
+660fe111|223344556677885f5f5f5f5f	64	gnu	psraw (%rcx),%xmm2
+660fe111|223344556677885f5f5f5f5f	64	intel	psraw xmm2, xmmword ptr [rcx]
+660fe111|223344556677885f5f5f5f5f	64	plan9	PSRAW 0(CX), X2
+660fe211|223344556677885f5f5f5f5f	32	intel	psrad xmm2, xmmword ptr [ecx]
+660fe211|223344556677885f5f5f5f5f	32	plan9	PSRAD 0(CX), X2
+660fe211|223344556677885f5f5f5f5f	64	gnu	psrad (%rcx),%xmm2
+660fe211|223344556677885f5f5f5f5f	64	intel	psrad xmm2, xmmword ptr [rcx]
+660fe211|223344556677885f5f5f5f5f	64	plan9	PSRAD 0(CX), X2
+660fe311|223344556677885f5f5f5f5f	32	intel	pavgw xmm2, xmmword ptr [ecx]
+660fe311|223344556677885f5f5f5f5f	32	plan9	PAVGW 0(CX), X2
+660fe311|223344556677885f5f5f5f5f	64	gnu	pavgw (%rcx),%xmm2
+660fe311|223344556677885f5f5f5f5f	64	intel	pavgw xmm2, xmmword ptr [rcx]
+660fe311|223344556677885f5f5f5f5f	64	plan9	PAVGW 0(CX), X2
+660fe411|223344556677885f5f5f5f5f	32	intel	pmulhuw xmm2, xmmword ptr [ecx]
+660fe411|223344556677885f5f5f5f5f	32	plan9	PMULHUW 0(CX), X2
+660fe411|223344556677885f5f5f5f5f	64	gnu	pmulhuw (%rcx),%xmm2
+660fe411|223344556677885f5f5f5f5f	64	intel	pmulhuw xmm2, xmmword ptr [rcx]
+660fe411|223344556677885f5f5f5f5f	64	plan9	PMULHUW 0(CX), X2
+660fe511|223344556677885f5f5f5f5f	32	intel	pmulhw xmm2, xmmword ptr [ecx]
+660fe511|223344556677885f5f5f5f5f	32	plan9	PMULHW 0(CX), X2
+660fe511|223344556677885f5f5f5f5f	64	gnu	pmulhw (%rcx),%xmm2
+660fe511|223344556677885f5f5f5f5f	64	intel	pmulhw xmm2, xmmword ptr [rcx]
+660fe511|223344556677885f5f5f5f5f	64	plan9	PMULHW 0(CX), X2
+660fe611|223344556677885f5f5f5f5f	32	intel	cvttpd2dq xmm2, xmmword ptr [ecx]
+660fe611|223344556677885f5f5f5f5f	32	plan9	CVTTPD2DQ 0(CX), X2
+660fe611|223344556677885f5f5f5f5f	64	gnu	cvttpd2dq (%rcx),%xmm2
+660fe611|223344556677885f5f5f5f5f	64	intel	cvttpd2dq xmm2, xmmword ptr [rcx]
+660fe611|223344556677885f5f5f5f5f	64	plan9	CVTTPD2DQ 0(CX), X2
+660fe711|223344556677885f5f5f5f5f	32	intel	movntdq xmmword ptr [ecx], xmm2
+660fe711|223344556677885f5f5f5f5f	32	plan9	MOVNTDQ X2, 0(CX)
+660fe711|223344556677885f5f5f5f5f	64	gnu	movntdq %xmm2,(%rcx)
+660fe711|223344556677885f5f5f5f5f	64	intel	movntdq xmmword ptr [rcx], xmm2
+660fe711|223344556677885f5f5f5f5f	64	plan9	MOVNTDQ X2, 0(CX)
+660fe811|223344556677885f5f5f5f5f	32	intel	psubsb xmm2, xmmword ptr [ecx]
+660fe811|223344556677885f5f5f5f5f	32	plan9	PSUBSB 0(CX), X2
+660fe811|223344556677885f5f5f5f5f	64	gnu	psubsb (%rcx),%xmm2
+660fe811|223344556677885f5f5f5f5f	64	intel	psubsb xmm2, xmmword ptr [rcx]
+660fe811|223344556677885f5f5f5f5f	64	plan9	PSUBSB 0(CX), X2
+660fe911|223344556677885f5f5f5f5f	32	intel	psubsw xmm2, xmmword ptr [ecx]
+660fe911|223344556677885f5f5f5f5f	32	plan9	PSUBSW 0(CX), X2
+660fe911|223344556677885f5f5f5f5f	64	gnu	psubsw (%rcx),%xmm2
+660fe911|223344556677885f5f5f5f5f	64	intel	psubsw xmm2, xmmword ptr [rcx]
+660fe911|223344556677885f5f5f5f5f	64	plan9	PSUBSW 0(CX), X2
+660fea11|223344556677885f5f5f5f5f	32	intel	pminsw xmm2, xmmword ptr [ecx]
+660fea11|223344556677885f5f5f5f5f	32	plan9	PMINSW 0(CX), X2
+660fea11|223344556677885f5f5f5f5f	64	gnu	pminsw (%rcx),%xmm2
+660fea11|223344556677885f5f5f5f5f	64	intel	pminsw xmm2, xmmword ptr [rcx]
+660fea11|223344556677885f5f5f5f5f	64	plan9	PMINSW 0(CX), X2
+660feb11|223344556677885f5f5f5f5f	32	intel	por xmm2, xmmword ptr [ecx]
+660feb11|223344556677885f5f5f5f5f	32	plan9	POR 0(CX), X2
+660feb11|223344556677885f5f5f5f5f	64	gnu	por (%rcx),%xmm2
+660feb11|223344556677885f5f5f5f5f	64	intel	por xmm2, xmmword ptr [rcx]
+660feb11|223344556677885f5f5f5f5f	64	plan9	POR 0(CX), X2
+660fec11|223344556677885f5f5f5f5f	32	intel	paddsb xmm2, xmmword ptr [ecx]
+660fec11|223344556677885f5f5f5f5f	32	plan9	PADDSB 0(CX), X2
+660fec11|223344556677885f5f5f5f5f	64	gnu	paddsb (%rcx),%xmm2
+660fec11|223344556677885f5f5f5f5f	64	intel	paddsb xmm2, xmmword ptr [rcx]
+660fec11|223344556677885f5f5f5f5f	64	plan9	PADDSB 0(CX), X2
+660fed11|223344556677885f5f5f5f5f	32	intel	paddsw xmm2, xmmword ptr [ecx]
+660fed11|223344556677885f5f5f5f5f	32	plan9	PADDSW 0(CX), X2
+660fed11|223344556677885f5f5f5f5f	64	gnu	paddsw (%rcx),%xmm2
+660fed11|223344556677885f5f5f5f5f	64	intel	paddsw xmm2, xmmword ptr [rcx]
+660fed11|223344556677885f5f5f5f5f	64	plan9	PADDSW 0(CX), X2
+660fee11|223344556677885f5f5f5f5f	32	intel	pmaxsw xmm2, xmmword ptr [ecx]
+660fee11|223344556677885f5f5f5f5f	32	plan9	PMAXSW 0(CX), X2
+660fee11|223344556677885f5f5f5f5f	64	gnu	pmaxsw (%rcx),%xmm2
+660fee11|223344556677885f5f5f5f5f	64	intel	pmaxsw xmm2, xmmword ptr [rcx]
+660fee11|223344556677885f5f5f5f5f	64	plan9	PMAXSW 0(CX), X2
+660fef11|223344556677885f5f5f5f5f	32	intel	pxor xmm2, xmmword ptr [ecx]
+660fef11|223344556677885f5f5f5f5f	32	plan9	PXOR 0(CX), X2
+660fef11|223344556677885f5f5f5f5f	64	gnu	pxor (%rcx),%xmm2
+660fef11|223344556677885f5f5f5f5f	64	intel	pxor xmm2, xmmword ptr [rcx]
+660fef11|223344556677885f5f5f5f5f	64	plan9	PXOR 0(CX), X2
+660ff111|223344556677885f5f5f5f5f	32	intel	psllw xmm2, xmmword ptr [ecx]
+660ff111|223344556677885f5f5f5f5f	32	plan9	PSLLW 0(CX), X2
+660ff111|223344556677885f5f5f5f5f	64	gnu	psllw (%rcx),%xmm2
+660ff111|223344556677885f5f5f5f5f	64	intel	psllw xmm2, xmmword ptr [rcx]
+660ff111|223344556677885f5f5f5f5f	64	plan9	PSLLW 0(CX), X2
+660ff211|223344556677885f5f5f5f5f	32	intel	pslld xmm2, xmmword ptr [ecx]
+660ff211|223344556677885f5f5f5f5f	32	plan9	PSLLD 0(CX), X2
+660ff211|223344556677885f5f5f5f5f	64	gnu	pslld (%rcx),%xmm2
+660ff211|223344556677885f5f5f5f5f	64	intel	pslld xmm2, xmmword ptr [rcx]
+660ff211|223344556677885f5f5f5f5f	64	plan9	PSLLD 0(CX), X2
+660ff311|223344556677885f5f5f5f5f	32	intel	psllq xmm2, xmmword ptr [ecx]
+660ff311|223344556677885f5f5f5f5f	32	plan9	PSLLQ 0(CX), X2
+660ff311|223344556677885f5f5f5f5f	64	gnu	psllq (%rcx),%xmm2
+660ff311|223344556677885f5f5f5f5f	64	intel	psllq xmm2, xmmword ptr [rcx]
+660ff311|223344556677885f5f5f5f5f	64	plan9	PSLLQ 0(CX), X2
+660ff411|223344556677885f5f5f5f5f	32	intel	pmuludq xmm2, xmmword ptr [ecx]
+660ff411|223344556677885f5f5f5f5f	32	plan9	PMULUDQ 0(CX), X2
+660ff411|223344556677885f5f5f5f5f	64	gnu	pmuludq (%rcx),%xmm2
+660ff411|223344556677885f5f5f5f5f	64	intel	pmuludq xmm2, xmmword ptr [rcx]
+660ff411|223344556677885f5f5f5f5f	64	plan9	PMULUDQ 0(CX), X2
+660ff511|223344556677885f5f5f5f5f	32	intel	pmaddwd xmm2, xmmword ptr [ecx]
+660ff511|223344556677885f5f5f5f5f	32	plan9	PMADDWD 0(CX), X2
+660ff511|223344556677885f5f5f5f5f	64	gnu	pmaddwd (%rcx),%xmm2
+660ff511|223344556677885f5f5f5f5f	64	intel	pmaddwd xmm2, xmmword ptr [rcx]
+660ff511|223344556677885f5f5f5f5f	64	plan9	PMADDWD 0(CX), X2
+660ff611|223344556677885f5f5f5f5f	32	intel	psadbw xmm2, xmmword ptr [ecx]
+660ff611|223344556677885f5f5f5f5f	32	plan9	PSADBW 0(CX), X2
+660ff611|223344556677885f5f5f5f5f	64	gnu	psadbw (%rcx),%xmm2
+660ff611|223344556677885f5f5f5f5f	64	intel	psadbw xmm2, xmmword ptr [rcx]
+660ff611|223344556677885f5f5f5f5f	64	plan9	PSADBW 0(CX), X2
+660ff7c0|11223344556677885f5f5f5f	32	intel	maskmovdqu xmm0, xmm0
+660ff7c0|11223344556677885f5f5f5f	32	plan9	MASKMOVDQU X0, X0
+660ff7c0|11223344556677885f5f5f5f	64	intel	maskmovdqu xmm0, xmm0
+660ff7c0|11223344556677885f5f5f5f	64	plan9	MASKMOVDQU X0, X0
+660ff811|223344556677885f5f5f5f5f	32	intel	psubb xmm2, xmmword ptr [ecx]
+660ff811|223344556677885f5f5f5f5f	32	plan9	PSUBB 0(CX), X2
+660ff811|223344556677885f5f5f5f5f	64	gnu	psubb (%rcx),%xmm2
+660ff811|223344556677885f5f5f5f5f	64	intel	psubb xmm2, xmmword ptr [rcx]
+660ff811|223344556677885f5f5f5f5f	64	plan9	PSUBB 0(CX), X2
+660ff911|223344556677885f5f5f5f5f	32	intel	psubw xmm2, xmmword ptr [ecx]
+660ff911|223344556677885f5f5f5f5f	32	plan9	PSUBW 0(CX), X2
+660ff911|223344556677885f5f5f5f5f	64	gnu	psubw (%rcx),%xmm2
+660ff911|223344556677885f5f5f5f5f	64	intel	psubw xmm2, xmmword ptr [rcx]
+660ff911|223344556677885f5f5f5f5f	64	plan9	PSUBW 0(CX), X2
+660ffa11|223344556677885f5f5f5f5f	32	intel	psubd xmm2, xmmword ptr [ecx]
+660ffa11|223344556677885f5f5f5f5f	32	plan9	PSUBD 0(CX), X2
+660ffa11|223344556677885f5f5f5f5f	64	gnu	psubd (%rcx),%xmm2
+660ffa11|223344556677885f5f5f5f5f	64	intel	psubd xmm2, xmmword ptr [rcx]
+660ffa11|223344556677885f5f5f5f5f	64	plan9	PSUBD 0(CX), X2
+660ffb11|223344556677885f5f5f5f5f	32	intel	psubq xmm2, xmmword ptr [ecx]
+660ffb11|223344556677885f5f5f5f5f	32	plan9	PSUBQ 0(CX), X2
+660ffb11|223344556677885f5f5f5f5f	64	gnu	psubq (%rcx),%xmm2
+660ffb11|223344556677885f5f5f5f5f	64	intel	psubq xmm2, xmmword ptr [rcx]
+660ffb11|223344556677885f5f5f5f5f	64	plan9	PSUBQ 0(CX), X2
+660ffc11|223344556677885f5f5f5f5f	32	intel	paddb xmm2, xmmword ptr [ecx]
+660ffc11|223344556677885f5f5f5f5f	32	plan9	PADDB 0(CX), X2
+660ffc11|223344556677885f5f5f5f5f	64	gnu	paddb (%rcx),%xmm2
+660ffc11|223344556677885f5f5f5f5f	64	intel	paddb xmm2, xmmword ptr [rcx]
+660ffc11|223344556677885f5f5f5f5f	64	plan9	PADDB 0(CX), X2
+660ffd11|223344556677885f5f5f5f5f	32	intel	paddw xmm2, xmmword ptr [ecx]
+660ffd11|223344556677885f5f5f5f5f	32	plan9	PADDW 0(CX), X2
+660ffd11|223344556677885f5f5f5f5f	64	gnu	paddw (%rcx),%xmm2
+660ffd11|223344556677885f5f5f5f5f	64	intel	paddw xmm2, xmmword ptr [rcx]
+660ffd11|223344556677885f5f5f5f5f	64	plan9	PADDW 0(CX), X2
+660ffe11|223344556677885f5f5f5f5f	32	intel	paddd xmm2, xmmword ptr [ecx]
+660ffe11|223344556677885f5f5f5f5f	32	plan9	PADDD 0(CX), X2
+660ffe11|223344556677885f5f5f5f5f	64	gnu	paddd (%rcx),%xmm2
+660ffe11|223344556677885f5f5f5f5f	64	intel	paddd xmm2, xmmword ptr [rcx]
+660ffe11|223344556677885f5f5f5f5f	64	plan9	PADDD 0(CX), X2
+661122|3344556677885f5f5f5f5f5f5f	32	intel	adc word ptr [edx], sp
+661122|3344556677885f5f5f5f5f5f5f	32	plan9	ADCW SP, 0(DX)
+661122|3344556677885f5f5f5f5f5f5f	64	gnu	adc %sp,(%rdx)
+661122|3344556677885f5f5f5f5f5f5f	64	intel	adc word ptr [rdx], sp
+661122|3344556677885f5f5f5f5f5f5f	64	plan9	ADCW SP, 0(DX)
+661311|223344556677885f5f5f5f5f5f	32	intel	adc dx, word ptr [ecx]
+661311|223344556677885f5f5f5f5f5f	32	plan9	ADCW 0(CX), DX
+661311|223344556677885f5f5f5f5f5f	64	gnu	adc (%rcx),%dx
+661311|223344556677885f5f5f5f5f5f	64	intel	adc dx, word ptr [rcx]
+661311|223344556677885f5f5f5f5f5f	64	plan9	ADCW 0(CX), DX
+66151122|3344556677885f5f5f5f5f5f	32	intel	adc ax, 0x2211
+66151122|3344556677885f5f5f5f5f5f	32	plan9	ADCW $0x2211, AX
+66151122|3344556677885f5f5f5f5f5f	64	gnu	adc $0x2211,%ax
+66151122|3344556677885f5f5f5f5f5f	64	intel	adc ax, 0x2211
+66151122|3344556677885f5f5f5f5f5f	64	plan9	ADCW $0x2211, AX
+661911|223344556677885f5f5f5f5f5f	32	intel	sbb word ptr [ecx], dx
+661911|223344556677885f5f5f5f5f5f	32	plan9	SBBW DX, 0(CX)
+661911|223344556677885f5f5f5f5f5f	64	gnu	sbb %dx,(%rcx)
+661911|223344556677885f5f5f5f5f5f	64	intel	sbb word ptr [rcx], dx
+661911|223344556677885f5f5f5f5f5f	64	plan9	SBBW DX, 0(CX)
+661b11|223344556677885f5f5f5f5f5f	32	intel	sbb dx, word ptr [ecx]
+661b11|223344556677885f5f5f5f5f5f	32	plan9	SBBW 0(CX), DX
+661b11|223344556677885f5f5f5f5f5f	64	gnu	sbb (%rcx),%dx
+661b11|223344556677885f5f5f5f5f5f	64	intel	sbb dx, word ptr [rcx]
+661b11|223344556677885f5f5f5f5f5f	64	plan9	SBBW 0(CX), DX
+661d1122|3344556677885f5f5f5f5f5f	32	intel	sbb ax, 0x2211
+661d1122|3344556677885f5f5f5f5f5f	32	plan9	SBBW $0x2211, AX
+661d1122|3344556677885f5f5f5f5f5f	64	gnu	sbb $0x2211,%ax
+661d1122|3344556677885f5f5f5f5f5f	64	intel	sbb ax, 0x2211
+661d1122|3344556677885f5f5f5f5f5f	64	plan9	SBBW $0x2211, AX
+662111|223344556677885f5f5f5f5f5f	32	intel	and word ptr [ecx], dx
+662111|223344556677885f5f5f5f5f5f	32	plan9	ANDW DX, 0(CX)
+662111|223344556677885f5f5f5f5f5f	64	gnu	and %dx,(%rcx)
+662111|223344556677885f5f5f5f5f5f	64	intel	and word ptr [rcx], dx
+662111|223344556677885f5f5f5f5f5f	64	plan9	ANDW DX, 0(CX)
+662311|223344556677885f5f5f5f5f5f	32	intel	and dx, word ptr [ecx]
+662311|223344556677885f5f5f5f5f5f	32	plan9	ANDW 0(CX), DX
+662311|223344556677885f5f5f5f5f5f	64	gnu	and (%rcx),%dx
+662311|223344556677885f5f5f5f5f5f	64	intel	and dx, word ptr [rcx]
+662311|223344556677885f5f5f5f5f5f	64	plan9	ANDW 0(CX), DX
+66251122|3344556677885f5f5f5f5f5f	32	intel	and ax, 0x2211
+66251122|3344556677885f5f5f5f5f5f	32	plan9	ANDW $0x2211, AX
+66251122|3344556677885f5f5f5f5f5f	64	gnu	and $0x2211,%ax
+66251122|3344556677885f5f5f5f5f5f	64	intel	and ax, 0x2211
+66251122|3344556677885f5f5f5f5f5f	64	plan9	ANDW $0x2211, AX
+662911|223344556677885f5f5f5f5f5f	32	intel	sub word ptr [ecx], dx
+662911|223344556677885f5f5f5f5f5f	32	plan9	SUBW DX, 0(CX)
+662911|223344556677885f5f5f5f5f5f	64	gnu	sub %dx,(%rcx)
+662911|223344556677885f5f5f5f5f5f	64	intel	sub word ptr [rcx], dx
+662911|223344556677885f5f5f5f5f5f	64	plan9	SUBW DX, 0(CX)
+662b11|223344556677885f5f5f5f5f5f	32	intel	sub dx, word ptr [ecx]
+662b11|223344556677885f5f5f5f5f5f	32	plan9	SUBW 0(CX), DX
+662b11|223344556677885f5f5f5f5f5f	64	gnu	sub (%rcx),%dx
+662b11|223344556677885f5f5f5f5f5f	64	intel	sub dx, word ptr [rcx]
+662b11|223344556677885f5f5f5f5f5f	64	plan9	SUBW 0(CX), DX
+662d1122|3344556677885f5f5f5f5f5f	32	intel	sub ax, 0x2211
+662d1122|3344556677885f5f5f5f5f5f	32	plan9	SUBW $0x2211, AX
+662d1122|3344556677885f5f5f5f5f5f	64	gnu	sub $0x2211,%ax
+662d1122|3344556677885f5f5f5f5f5f	64	intel	sub ax, 0x2211
+662d1122|3344556677885f5f5f5f5f5f	64	plan9	SUBW $0x2211, AX
+663111|223344556677885f5f5f5f5f5f	32	intel	xor word ptr [ecx], dx
+663111|223344556677885f5f5f5f5f5f	32	plan9	XORW DX, 0(CX)
+663111|223344556677885f5f5f5f5f5f	64	gnu	xor %dx,(%rcx)
+663111|223344556677885f5f5f5f5f5f	64	intel	xor word ptr [rcx], dx
+663111|223344556677885f5f5f5f5f5f	64	plan9	XORW DX, 0(CX)
+663311|223344556677885f5f5f5f5f5f	32	intel	xor dx, word ptr [ecx]
+663311|223344556677885f5f5f5f5f5f	32	plan9	XORW 0(CX), DX
+663311|223344556677885f5f5f5f5f5f	64	gnu	xor (%rcx),%dx
+663311|223344556677885f5f5f5f5f5f	64	intel	xor dx, word ptr [rcx]
+663311|223344556677885f5f5f5f5f5f	64	plan9	XORW 0(CX), DX
+66351122|3344556677885f5f5f5f5f5f	32	intel	xor ax, 0x2211
+66351122|3344556677885f5f5f5f5f5f	32	plan9	XORW $0x2211, AX
+66351122|3344556677885f5f5f5f5f5f	64	gnu	xor $0x2211,%ax
+66351122|3344556677885f5f5f5f5f5f	64	intel	xor ax, 0x2211
+66351122|3344556677885f5f5f5f5f5f	64	plan9	XORW $0x2211, AX
+663911|223344556677885f5f5f5f5f5f	32	intel	cmp word ptr [ecx], dx
+663911|223344556677885f5f5f5f5f5f	32	plan9	CMPW DX, 0(CX)
+663911|223344556677885f5f5f5f5f5f	64	gnu	cmp %dx,(%rcx)
+663911|223344556677885f5f5f5f5f5f	64	intel	cmp word ptr [rcx], dx
+663911|223344556677885f5f5f5f5f5f	64	plan9	CMPW DX, 0(CX)
+663b11|223344556677885f5f5f5f5f5f	32	intel	cmp dx, word ptr [ecx]
+663b11|223344556677885f5f5f5f5f5f	32	plan9	CMPW 0(CX), DX
+663b11|223344556677885f5f5f5f5f5f	64	gnu	cmp (%rcx),%dx
+663b11|223344556677885f5f5f5f5f5f	64	intel	cmp dx, word ptr [rcx]
+663b11|223344556677885f5f5f5f5f5f	64	plan9	CMPW 0(CX), DX
+663d1122|3344556677885f5f5f5f5f5f	32	intel	cmp ax, 0x2211
+663d1122|3344556677885f5f5f5f5f5f	32	plan9	CMPW $0x2211, AX
+663d1122|3344556677885f5f5f5f5f5f	64	gnu	cmp $0x2211,%ax
+663d1122|3344556677885f5f5f5f5f5f	64	intel	cmp ax, 0x2211
+663d1122|3344556677885f5f5f5f5f5f	64	plan9	CMPW $0x2211, AX
+6640|11223344556677885f5f5f5f5f5f	32	intel	inc ax
+6640|11223344556677885f5f5f5f5f5f	32	plan9	INCW AX
+66480f3a161122|3344556677885f5f5f	64	gnu	pextrq $0x22,%xmm2,(%rcx)
+66480f3a161122|3344556677885f5f5f	64	intel	pextrq qword ptr [rcx], xmm2, 0x22
+66480f3a161122|3344556677885f5f5f	64	plan9	PEXTRQ $0x22, X2, 0(CX)
+66480f3a221122|3344556677885f5f5f	64	gnu	pinsrq $0x22,(%rcx),%xmm2
+66480f3a221122|3344556677885f5f5f	64	intel	pinsrq xmm2, qword ptr [rcx], 0x22
+66480f3a221122|3344556677885f5f5f	64	plan9	PINSRQ $0x22, 0(CX), X2
+66480f6e11|223344556677885f5f5f5f	64	gnu	movq (%rcx),%xmm2
+66480f6e11|223344556677885f5f5f5f	64	intel	movq xmm2, qword ptr [rcx]
+66480f6e11|223344556677885f5f5f5f	64	plan9	MOVQ 0(CX), X2
+66480f7e11|223344556677885f5f5f5f	64	gnu	movq %xmm2,(%rcx)
+66480f7e11|223344556677885f5f5f5f	64	intel	movq qword ptr [rcx], xmm2
+66480f7e11|223344556677885f5f5f5f	64	plan9	MOVQ X2, 0(CX)
+6648|0f3a1611223344556677885f5f5f	32	intel	dec ax
+6648|0f3a1611223344556677885f5f5f	32	plan9	DECW AX
+6650|11223344556677885f5f5f5f5f5f	32	intel	push ax
+6650|11223344556677885f5f5f5f5f5f	32	plan9	PUSHW AX
+6650|11223344556677885f5f5f5f5f5f	64	gnu	push %ax
+6650|11223344556677885f5f5f5f5f5f	64	intel	push ax
+6650|11223344556677885f5f5f5f5f5f	64	plan9	PUSHW AX
+6658|11223344556677885f5f5f5f5f5f	32	intel	pop ax
+6658|11223344556677885f5f5f5f5f5f	32	plan9	POPW AX
+6658|11223344556677885f5f5f5f5f5f	64	gnu	pop %ax
+6658|11223344556677885f5f5f5f5f5f	64	intel	pop ax
+6658|11223344556677885f5f5f5f5f5f	64	plan9	POPW AX
+6660|11223344556677885f5f5f5f5f5f	32	intel	data16 pusha
+6660|11223344556677885f5f5f5f5f5f	32	plan9	PUSHAW
+6661|11223344556677885f5f5f5f5f5f	32	intel	data16 popa
+6661|11223344556677885f5f5f5f5f5f	32	plan9	POPAW
+666211|223344556677885f5f5f5f5f5f	32	intel	bound dx, qword ptr [ecx]
+666211|223344556677885f5f5f5f5f5f	32	plan9	BOUND 0(CX), DX
+666311|223344556677885f5f5f5f5f5f	64	gnu	movsxd (%rcx),%dx
+666311|223344556677885f5f5f5f5f5f	64	intel	movsxd dx, dword ptr [rcx]
+666311|223344556677885f5f5f5f5f5f	64	plan9	MOVSXD 0(CX), DX
+66681122|3344556677885f5f5f5f5f5f	32	intel	push 0x2211
+66681122|3344556677885f5f5f5f5f5f	32	plan9	PUSHW $0x2211
+66681122|3344556677885f5f5f5f5f5f	64	gnu	pushw $0x2211
+66681122|3344556677885f5f5f5f5f5f	64	intel	push 0x2211
+66681122|3344556677885f5f5f5f5f5f	64	plan9	PUSHW $0x2211
+6669112233|44556677885f5f5f5f5f5f	32	intel	imul dx, word ptr [ecx], 0x3322
+6669112233|44556677885f5f5f5f5f5f	32	plan9	IMULW $0x3322, 0(CX), DX
+6669112233|44556677885f5f5f5f5f5f	64	gnu	imul $0x3322,(%rcx),%dx
+6669112233|44556677885f5f5f5f5f5f	64	intel	imul dx, word ptr [rcx], 0x3322
+6669112233|44556677885f5f5f5f5f5f	64	plan9	IMULW $0x3322, 0(CX), DX
+666b1122|3344556677885f5f5f5f5f5f	32	intel	imul dx, word ptr [ecx], 0x22
+666b1122|3344556677885f5f5f5f5f5f	32	plan9	IMULW $0x22, 0(CX), DX
+666b1122|3344556677885f5f5f5f5f5f	64	gnu	imul $0x22,(%rcx),%dx
+666b1122|3344556677885f5f5f5f5f5f	64	intel	imul dx, word ptr [rcx], 0x22
+666b1122|3344556677885f5f5f5f5f5f	64	plan9	IMULW $0x22, 0(CX), DX
+666d|11223344556677885f5f5f5f5f5f	32	intel	data16 insw
+666d|11223344556677885f5f5f5f5f5f	32	plan9	INSW DX, ES:0(DI)
+666d|11223344556677885f5f5f5f5f5f	64	gnu	insw (%dx),%es:(%rdi)
+666d|11223344556677885f5f5f5f5f5f	64	intel	data16 insw
+666d|11223344556677885f5f5f5f5f5f	64	plan9	INSW DX, ES:0(DI)
+666f|11223344556677885f5f5f5f5f5f	32	intel	data16 outsw
+666f|11223344556677885f5f5f5f5f5f	32	plan9	OUTSW DS:0(SI), DX
+666f|11223344556677885f5f5f5f5f5f	64	gnu	outsw %ds:(%rsi),(%dx)
+666f|11223344556677885f5f5f5f5f5f	64	intel	data16 outsw
+666f|11223344556677885f5f5f5f5f5f	64	plan9	OUTSW DS:0(SI), DX
+6681001122|3344556677885f5f5f5f5f	32	intel	add word ptr [eax], 0x2211
+6681001122|3344556677885f5f5f5f5f	32	plan9	ADDW $0x2211, 0(AX)
+6681001122|3344556677885f5f5f5f5f	64	gnu	addw $0x2211,(%rax)
+6681001122|3344556677885f5f5f5f5f	64	intel	add word ptr [rax], 0x2211
+6681001122|3344556677885f5f5f5f5f	64	plan9	ADDW $0x2211, 0(AX)
+6681081122|3344556677885f5f5f5f5f	32	intel	or word ptr [eax], 0x2211
+6681081122|3344556677885f5f5f5f5f	32	plan9	ORW $0x2211, 0(AX)
+6681081122|3344556677885f5f5f5f5f	64	gnu	orw $0x2211,(%rax)
+6681081122|3344556677885f5f5f5f5f	64	intel	or word ptr [rax], 0x2211
+6681081122|3344556677885f5f5f5f5f	64	plan9	ORW $0x2211, 0(AX)
+6681112233|44556677885f5f5f5f5f5f	32	intel	adc word ptr [ecx], 0x3322
+6681112233|44556677885f5f5f5f5f5f	32	plan9	ADCW $0x3322, 0(CX)
+6681112233|44556677885f5f5f5f5f5f	64	gnu	adcw $0x3322,(%rcx)
+6681112233|44556677885f5f5f5f5f5f	64	intel	adc word ptr [rcx], 0x3322
+6681112233|44556677885f5f5f5f5f5f	64	plan9	ADCW $0x3322, 0(CX)
+6681181122|3344556677885f5f5f5f5f	32	intel	sbb word ptr [eax], 0x2211
+6681181122|3344556677885f5f5f5f5f	32	plan9	SBBW $0x2211, 0(AX)
+6681181122|3344556677885f5f5f5f5f	64	gnu	sbbw $0x2211,(%rax)
+6681181122|3344556677885f5f5f5f5f	64	intel	sbb word ptr [rax], 0x2211
+6681181122|3344556677885f5f5f5f5f	64	plan9	SBBW $0x2211, 0(AX)
+6681201122|3344556677885f5f5f5f5f	32	intel	and word ptr [eax], 0x2211
+6681201122|3344556677885f5f5f5f5f	32	plan9	ANDW $0x2211, 0(AX)
+6681201122|3344556677885f5f5f5f5f	64	gnu	andw $0x2211,(%rax)
+6681201122|3344556677885f5f5f5f5f	64	intel	and word ptr [rax], 0x2211
+6681201122|3344556677885f5f5f5f5f	64	plan9	ANDW $0x2211, 0(AX)
+6681281122|3344556677885f5f5f5f5f	32	intel	sub word ptr [eax], 0x2211
+6681281122|3344556677885f5f5f5f5f	32	plan9	SUBW $0x2211, 0(AX)
+6681281122|3344556677885f5f5f5f5f	64	gnu	subw $0x2211,(%rax)
+6681281122|3344556677885f5f5f5f5f	64	intel	sub word ptr [rax], 0x2211
+6681281122|3344556677885f5f5f5f5f	64	plan9	SUBW $0x2211, 0(AX)
+6681301122|3344556677885f5f5f5f5f	32	intel	xor word ptr [eax], 0x2211
+6681301122|3344556677885f5f5f5f5f	32	plan9	XORW $0x2211, 0(AX)
+6681301122|3344556677885f5f5f5f5f	64	gnu	xorw $0x2211,(%rax)
+6681301122|3344556677885f5f5f5f5f	64	intel	xor word ptr [rax], 0x2211
+6681301122|3344556677885f5f5f5f5f	64	plan9	XORW $0x2211, 0(AX)
+6681381122|3344556677885f5f5f5f5f	32	intel	cmp word ptr [eax], 0x2211
+6681381122|3344556677885f5f5f5f5f	32	plan9	CMPW $0x2211, 0(AX)
+6681381122|3344556677885f5f5f5f5f	64	gnu	cmpw $0x2211,(%rax)
+6681381122|3344556677885f5f5f5f5f	64	intel	cmp word ptr [rax], 0x2211
+6681381122|3344556677885f5f5f5f5f	64	plan9	CMPW $0x2211, 0(AX)
+66830011|223344556677885f5f5f5f5f	32	intel	add word ptr [eax], 0x11
+66830011|223344556677885f5f5f5f5f	32	plan9	ADDW $0x11, 0(AX)
+66830011|223344556677885f5f5f5f5f	64	gnu	addw $0x11,(%rax)
+66830011|223344556677885f5f5f5f5f	64	intel	add word ptr [rax], 0x11
+66830011|223344556677885f5f5f5f5f	64	plan9	ADDW $0x11, 0(AX)
+66830811|223344556677885f5f5f5f5f	32	intel	or word ptr [eax], 0x11
+66830811|223344556677885f5f5f5f5f	32	plan9	ORW $0x11, 0(AX)
+66830811|223344556677885f5f5f5f5f	64	gnu	orw $0x11,(%rax)
+66830811|223344556677885f5f5f5f5f	64	intel	or word ptr [rax], 0x11
+66830811|223344556677885f5f5f5f5f	64	plan9	ORW $0x11, 0(AX)
+66831122|3344556677885f5f5f5f5f5f	32	intel	adc word ptr [ecx], 0x22
+66831122|3344556677885f5f5f5f5f5f	32	plan9	ADCW $0x22, 0(CX)
+66831122|3344556677885f5f5f5f5f5f	64	gnu	adcw $0x22,(%rcx)
+66831122|3344556677885f5f5f5f5f5f	64	intel	adc word ptr [rcx], 0x22
+66831122|3344556677885f5f5f5f5f5f	64	plan9	ADCW $0x22, 0(CX)
+66831811|223344556677885f5f5f5f5f	32	intel	sbb word ptr [eax], 0x11
+66831811|223344556677885f5f5f5f5f	32	plan9	SBBW $0x11, 0(AX)
+66831811|223344556677885f5f5f5f5f	64	gnu	sbbw $0x11,(%rax)
+66831811|223344556677885f5f5f5f5f	64	intel	sbb word ptr [rax], 0x11
+66831811|223344556677885f5f5f5f5f	64	plan9	SBBW $0x11, 0(AX)
+66832011|223344556677885f5f5f5f5f	32	intel	and word ptr [eax], 0x11
+66832011|223344556677885f5f5f5f5f	32	plan9	ANDW $0x11, 0(AX)
+66832011|223344556677885f5f5f5f5f	64	gnu	andw $0x11,(%rax)
+66832011|223344556677885f5f5f5f5f	64	intel	and word ptr [rax], 0x11
+66832011|223344556677885f5f5f5f5f	64	plan9	ANDW $0x11, 0(AX)
+66832811|223344556677885f5f5f5f5f	32	intel	sub word ptr [eax], 0x11
+66832811|223344556677885f5f5f5f5f	32	plan9	SUBW $0x11, 0(AX)
+66832811|223344556677885f5f5f5f5f	64	gnu	subw $0x11,(%rax)
+66832811|223344556677885f5f5f5f5f	64	intel	sub word ptr [rax], 0x11
+66832811|223344556677885f5f5f5f5f	64	plan9	SUBW $0x11, 0(AX)
+66833011|223344556677885f5f5f5f5f	32	intel	xor word ptr [eax], 0x11
+66833011|223344556677885f5f5f5f5f	32	plan9	XORW $0x11, 0(AX)
+66833011|223344556677885f5f5f5f5f	64	gnu	xorw $0x11,(%rax)
+66833011|223344556677885f5f5f5f5f	64	intel	xor word ptr [rax], 0x11
+66833011|223344556677885f5f5f5f5f	64	plan9	XORW $0x11, 0(AX)
+66833811|223344556677885f5f5f5f5f	32	intel	cmp word ptr [eax], 0x11
+66833811|223344556677885f5f5f5f5f	32	plan9	CMPW $0x11, 0(AX)
+66833811|223344556677885f5f5f5f5f	64	gnu	cmpw $0x11,(%rax)
+66833811|223344556677885f5f5f5f5f	64	intel	cmp word ptr [rax], 0x11
+66833811|223344556677885f5f5f5f5f	64	plan9	CMPW $0x11, 0(AX)
+668511|223344556677885f5f5f5f5f5f	32	intel	test word ptr [ecx], dx
+668511|223344556677885f5f5f5f5f5f	32	plan9	TESTW DX, 0(CX)
+668511|223344556677885f5f5f5f5f5f	64	gnu	test %dx,(%rcx)
+668511|223344556677885f5f5f5f5f5f	64	intel	test word ptr [rcx], dx
+668511|223344556677885f5f5f5f5f5f	64	plan9	TESTW DX, 0(CX)
+668711|223344556677885f5f5f5f5f5f	32	intel	xchg word ptr [ecx], dx
+668711|223344556677885f5f5f5f5f5f	32	plan9	XCHGW DX, 0(CX)
+668711|223344556677885f5f5f5f5f5f	64	gnu	xchg %dx,(%rcx)
+668711|223344556677885f5f5f5f5f5f	64	intel	xchg word ptr [rcx], dx
+668711|223344556677885f5f5f5f5f5f	64	plan9	XCHGW DX, 0(CX)
+668911|223344556677885f5f5f5f5f5f	32	intel	mov word ptr [ecx], dx
+668911|223344556677885f5f5f5f5f5f	32	plan9	MOVW DX, 0(CX)
+668911|223344556677885f5f5f5f5f5f	64	gnu	mov %dx,(%rcx)
+668911|223344556677885f5f5f5f5f5f	64	intel	mov word ptr [rcx], dx
+668911|223344556677885f5f5f5f5f5f	64	plan9	MOVW DX, 0(CX)
+668b11|223344556677885f5f5f5f5f5f	32	intel	mov dx, word ptr [ecx]
+668b11|223344556677885f5f5f5f5f5f	32	plan9	MOVW 0(CX), DX
+668b11|223344556677885f5f5f5f5f5f	64	gnu	mov (%rcx),%dx
+668b11|223344556677885f5f5f5f5f5f	64	intel	mov dx, word ptr [rcx]
+668b11|223344556677885f5f5f5f5f5f	64	plan9	MOVW 0(CX), DX
+668c11|223344556677885f5f5f5f5f5f	32	intel	mov word ptr [ecx], ss
+668c11|223344556677885f5f5f5f5f5f	32	plan9	MOVW SS, 0(CX)
+668c11|223344556677885f5f5f5f5f5f	64	gnu	data16 mov %ss,(%rcx)
+668c11|223344556677885f5f5f5f5f5f	64	intel	mov word ptr [rcx], ss
+668c11|223344556677885f5f5f5f5f5f	64	plan9	MOVW SS, 0(CX)
+668d11|223344556677885f5f5f5f5f5f	32	intel	lea dx, ptr [ecx]
+668d11|223344556677885f5f5f5f5f5f	32	plan9	LEAW 0(CX), DX
+668d11|223344556677885f5f5f5f5f5f	64	gnu	lea (%rcx),%dx
+668d11|223344556677885f5f5f5f5f5f	64	intel	lea dx, ptr [rcx]
+668d11|223344556677885f5f5f5f5f5f	64	plan9	LEAW 0(CX), DX
+668ec0|11223344556677885f5f5f5f5f	32	intel	mov es, ax
+668ec0|11223344556677885f5f5f5f5f	32	plan9	MOVW AX, ES
+668ec0|11223344556677885f5f5f5f5f	64	gnu	mov %ax,%es
+668ec0|11223344556677885f5f5f5f5f	64	intel	mov es, ax
+668ec0|11223344556677885f5f5f5f5f	64	plan9	MOVW AX, ES
+668f00|11223344556677885f5f5f5f5f	32	intel	pop word ptr [eax]
+668f00|11223344556677885f5f5f5f5f	32	plan9	POPW 0(AX)
+668f00|11223344556677885f5f5f5f5f	64	gnu	popw (%rax)
+668f00|11223344556677885f5f5f5f5f	64	intel	pop word ptr [rax]
+668f00|11223344556677885f5f5f5f5f	64	plan9	POPW 0(AX)
+6690|11223344556677885f5f5f5f5f5f	32	plan9	NOPW
+6690|11223344556677885f5f5f5f5f5f	64	gnu	data16 nop
+6690|11223344556677885f5f5f5f5f5f	64	plan9	NOPW
+6698|11223344556677885f5f5f5f5f5f	32	intel	data16 cbw
+6698|11223344556677885f5f5f5f5f5f	32	plan9	CBW
+6698|11223344556677885f5f5f5f5f5f	64	gnu	cbtw
+6698|11223344556677885f5f5f5f5f5f	64	intel	data16 cbw
+6698|11223344556677885f5f5f5f5f5f	64	plan9	CBW
+6699|11223344556677885f5f5f5f5f5f	32	intel	data16 cwd
+6699|11223344556677885f5f5f5f5f5f	32	plan9	CWD
+6699|11223344556677885f5f5f5f5f5f	64	gnu	cwtd
+6699|11223344556677885f5f5f5f5f5f	64	intel	data16 cwd
+6699|11223344556677885f5f5f5f5f5f	64	plan9	CWD
+669a11223344|556677885f5f5f5f5f5f	32	intel	call far 0x2211, 0x4433
+669a11223344|556677885f5f5f5f5f5f	32	plan9	LCALL $0x2211, $0x4433
+669c|11223344556677885f5f5f5f5f5f	32	intel	data16 pushf
+669c|11223344556677885f5f5f5f5f5f	32	plan9	PUSHF
+669c|11223344556677885f5f5f5f5f5f	64	gnu	pushfw
+669c|11223344556677885f5f5f5f5f5f	64	intel	data16 pushf
+669c|11223344556677885f5f5f5f5f5f	64	plan9	PUSHF
+669d|11223344556677885f5f5f5f5f5f	32	intel	data16 popf
+669d|11223344556677885f5f5f5f5f5f	32	plan9	POPF
+669d|11223344556677885f5f5f5f5f5f	64	gnu	popfw
+669d|11223344556677885f5f5f5f5f5f	64	intel	data16 popf
+669d|11223344556677885f5f5f5f5f5f	64	plan9	POPF
+66a11122334455667788|5f5f5f5f5f5f	64	gnu	mov -0x778899aabbccddef,%ax
+66a11122334455667788|5f5f5f5f5f5f	64	intel	mov ax, word ptr [0x8877665544332211]
+66a11122334455667788|5f5f5f5f5f5f	64	plan9	MOVW -0x778899aabbccddef, AX
+66a111223344|556677885f5f5f5f5f5f	32	intel	mov ax, word ptr [0x44332211]
+66a111223344|556677885f5f5f5f5f5f	32	plan9	MOVW 0x44332211, AX
+66a31122334455667788|5f5f5f5f5f5f	64	gnu	mov %ax,-0x778899aabbccddef
+66a31122334455667788|5f5f5f5f5f5f	64	intel	mov word ptr [0x8877665544332211], ax
+66a31122334455667788|5f5f5f5f5f5f	64	plan9	MOVW AX, -0x778899aabbccddef
+66a311223344|556677885f5f5f5f5f5f	32	intel	mov word ptr [0x44332211], ax
+66a311223344|556677885f5f5f5f5f5f	32	plan9	MOVW AX, 0x44332211
+66a5|11223344556677885f5f5f5f5f5f	32	intel	movsw word ptr [edi], word ptr [esi]
+66a5|11223344556677885f5f5f5f5f5f	32	plan9	MOVSW DS:0(SI), ES:0(DI)
+66a5|11223344556677885f5f5f5f5f5f	64	gnu	movsw %ds:(%rsi),%es:(%rdi)
+66a5|11223344556677885f5f5f5f5f5f	64	intel	movsw word ptr [rdi], word ptr [rsi]
+66a5|11223344556677885f5f5f5f5f5f	64	plan9	MOVSW DS:0(SI), ES:0(DI)
+66a7|11223344556677885f5f5f5f5f5f	32	intel	cmpsw word ptr [esi], word ptr [edi]
+66a7|11223344556677885f5f5f5f5f5f	32	plan9	CMPSW ES:0(DI), DS:0(SI)
+66a7|11223344556677885f5f5f5f5f5f	64	gnu	cmpsw %es:(%rdi),%ds:(%rsi)
+66a7|11223344556677885f5f5f5f5f5f	64	intel	cmpsw word ptr [rsi], word ptr [rdi]
+66a7|11223344556677885f5f5f5f5f5f	64	plan9	CMPSW ES:0(DI), DS:0(SI)
+66a91122|3344556677885f5f5f5f5f5f	32	intel	test ax, 0x2211
+66a91122|3344556677885f5f5f5f5f5f	32	plan9	TESTW $0x2211, AX
+66a91122|3344556677885f5f5f5f5f5f	64	gnu	test $0x2211,%ax
+66a91122|3344556677885f5f5f5f5f5f	64	intel	test ax, 0x2211
+66a91122|3344556677885f5f5f5f5f5f	64	plan9	TESTW $0x2211, AX
+66ab|11223344556677885f5f5f5f5f5f	32	intel	stosw word ptr [edi]
+66ab|11223344556677885f5f5f5f5f5f	32	plan9	STOSW AX, ES:0(DI)
+66ab|11223344556677885f5f5f5f5f5f	64	gnu	stos %ax,%es:(%rdi)
+66ab|11223344556677885f5f5f5f5f5f	64	intel	stosw word ptr [rdi]
+66ab|11223344556677885f5f5f5f5f5f	64	plan9	STOSW AX, ES:0(DI)
+66ad|11223344556677885f5f5f5f5f5f	32	intel	lodsw word ptr [esi]
+66ad|11223344556677885f5f5f5f5f5f	32	plan9	LODSW DS:0(SI), AX
+66ad|11223344556677885f5f5f5f5f5f	64	gnu	lods %ds:(%rsi),%ax
+66ad|11223344556677885f5f5f5f5f5f	64	intel	lodsw word ptr [rsi]
+66ad|11223344556677885f5f5f5f5f5f	64	plan9	LODSW DS:0(SI), AX
+66af|11223344556677885f5f5f5f5f5f	32	intel	scasw word ptr [edi]
+66af|11223344556677885f5f5f5f5f5f	32	plan9	SCASW ES:0(DI), AX
+66af|11223344556677885f5f5f5f5f5f	64	gnu	scas %es:(%rdi),%ax
+66af|11223344556677885f5f5f5f5f5f	64	intel	scasw word ptr [rdi]
+66af|11223344556677885f5f5f5f5f5f	64	plan9	SCASW ES:0(DI), AX
+66b81122|3344556677885f5f5f5f5f5f	32	intel	mov ax, 0x2211
+66b81122|3344556677885f5f5f5f5f5f	32	plan9	MOVW $0x2211, AX
+66b81122|3344556677885f5f5f5f5f5f	64	gnu	mov $0x2211,%ax
+66b81122|3344556677885f5f5f5f5f5f	64	intel	mov ax, 0x2211
+66b81122|3344556677885f5f5f5f5f5f	64	plan9	MOVW $0x2211, AX
+66c10011|223344556677885f5f5f5f5f	32	intel	rol word ptr [eax], 0x11
+66c10011|223344556677885f5f5f5f5f	32	plan9	ROLW $0x11, 0(AX)
+66c10011|223344556677885f5f5f5f5f	64	gnu	rolw $0x11,(%rax)
+66c10011|223344556677885f5f5f5f5f	64	intel	rol word ptr [rax], 0x11
+66c10011|223344556677885f5f5f5f5f	64	plan9	ROLW $0x11, 0(AX)
+66c10811|223344556677885f5f5f5f5f	32	intel	ror word ptr [eax], 0x11
+66c10811|223344556677885f5f5f5f5f	32	plan9	RORW $0x11, 0(AX)
+66c10811|223344556677885f5f5f5f5f	64	gnu	rorw $0x11,(%rax)
+66c10811|223344556677885f5f5f5f5f	64	intel	ror word ptr [rax], 0x11
+66c10811|223344556677885f5f5f5f5f	64	plan9	RORW $0x11, 0(AX)
+66c11122|3344556677885f5f5f5f5f5f	32	intel	rcl word ptr [ecx], 0x22
+66c11122|3344556677885f5f5f5f5f5f	32	plan9	RCLW $0x22, 0(CX)
+66c11122|3344556677885f5f5f5f5f5f	64	gnu	rclw $0x22,(%rcx)
+66c11122|3344556677885f5f5f5f5f5f	64	intel	rcl word ptr [rcx], 0x22
+66c11122|3344556677885f5f5f5f5f5f	64	plan9	RCLW $0x22, 0(CX)
+66c11811|223344556677885f5f5f5f5f	32	intel	rcr word ptr [eax], 0x11
+66c11811|223344556677885f5f5f5f5f	32	plan9	RCRW $0x11, 0(AX)
+66c11811|223344556677885f5f5f5f5f	64	gnu	rcrw $0x11,(%rax)
+66c11811|223344556677885f5f5f5f5f	64	intel	rcr word ptr [rax], 0x11
+66c11811|223344556677885f5f5f5f5f	64	plan9	RCRW $0x11, 0(AX)
+66c12011|223344556677885f5f5f5f5f	32	intel	shl word ptr [eax], 0x11
+66c12011|223344556677885f5f5f5f5f	32	plan9	SHLW $0x11, 0(AX)
+66c12011|223344556677885f5f5f5f5f	64	gnu	shlw $0x11,(%rax)
+66c12011|223344556677885f5f5f5f5f	64	intel	shl word ptr [rax], 0x11
+66c12011|223344556677885f5f5f5f5f	64	plan9	SHLW $0x11, 0(AX)
+66c12811|223344556677885f5f5f5f5f	32	intel	shr word ptr [eax], 0x11
+66c12811|223344556677885f5f5f5f5f	32	plan9	SHRW $0x11, 0(AX)
+66c12811|223344556677885f5f5f5f5f	64	gnu	shrw $0x11,(%rax)
+66c12811|223344556677885f5f5f5f5f	64	intel	shr word ptr [rax], 0x11
+66c12811|223344556677885f5f5f5f5f	64	plan9	SHRW $0x11, 0(AX)
+66c13811|223344556677885f5f5f5f5f	32	intel	sar word ptr [eax], 0x11
+66c13811|223344556677885f5f5f5f5f	32	plan9	SARW $0x11, 0(AX)
+66c13811|223344556677885f5f5f5f5f	64	gnu	sarw $0x11,(%rax)
+66c13811|223344556677885f5f5f5f5f	64	intel	sar word ptr [rax], 0x11
+66c13811|223344556677885f5f5f5f5f	64	plan9	SARW $0x11, 0(AX)
+66c21122|3344556677885f5f5f5f5f5f	32	intel	ret 0x2211
+66c21122|3344556677885f5f5f5f5f5f	32	plan9	RET $0x2211
+66c21122|3344556677885f5f5f5f5f5f	64	gnu	retw $0x2211
+66c21122|3344556677885f5f5f5f5f5f	64	intel	ret 0x2211
+66c21122|3344556677885f5f5f5f5f5f	64	plan9	RET $0x2211
+66c411|223344556677885f5f5f5f5f5f	32	intel	les dx, dword ptr [ecx]
+66c411|223344556677885f5f5f5f5f5f	32	plan9	LES 0(CX), DX
+66c511|223344556677885f5f5f5f5f5f	32	intel	lds dx, dword ptr [ecx]
+66c511|223344556677885f5f5f5f5f5f	32	plan9	LDS 0(CX), DX
+66c7001122|3344556677885f5f5f5f5f	32	intel	mov word ptr [eax], 0x2211
+66c7001122|3344556677885f5f5f5f5f	32	plan9	MOVW $0x2211, 0(AX)
+66c7001122|3344556677885f5f5f5f5f	64	gnu	movw $0x2211,(%rax)
+66c7001122|3344556677885f5f5f5f5f	64	intel	mov word ptr [rax], 0x2211
+66c7001122|3344556677885f5f5f5f5f	64	plan9	MOVW $0x2211, 0(AX)
+66c7f81122|3344556677885f5f5f5f5f	32	intel	xbegin .+0x2211
+66c7f81122|3344556677885f5f5f5f5f	32	plan9	XBEGIN .+8721
+66c7f81122|3344556677885f5f5f5f5f	64	gnu	xbeginw .+0x2211
+66c7f81122|3344556677885f5f5f5f5f	64	intel	xbegin .+0x2211
+66c7f81122|3344556677885f5f5f5f5f	64	plan9	XBEGIN .+8721
+66c9|11223344556677885f5f5f5f5f5f	32	intel	data16 leave
+66c9|11223344556677885f5f5f5f5f5f	32	plan9	LEAVE
+66c9|11223344556677885f5f5f5f5f5f	64	gnu	leavew
+66c9|11223344556677885f5f5f5f5f5f	64	intel	data16 leave
+66c9|11223344556677885f5f5f5f5f5f	64	plan9	LEAVE
+66cf|11223344556677885f5f5f5f5f5f	32	intel	data16 iret
+66cf|11223344556677885f5f5f5f5f5f	32	plan9	IRET
+66cf|11223344556677885f5f5f5f5f5f	64	gnu	iretw
+66cf|11223344556677885f5f5f5f5f5f	64	intel	data16 iret
+66cf|11223344556677885f5f5f5f5f5f	64	plan9	IRET
+66d100|11223344556677885f5f5f5f5f	32	intel	rol word ptr [eax], 0x1
+66d100|11223344556677885f5f5f5f5f	32	plan9	ROLW $0x1, 0(AX)
+66d100|11223344556677885f5f5f5f5f	64	gnu	rolw (%rax)
+66d100|11223344556677885f5f5f5f5f	64	intel	rol word ptr [rax], 0x1
+66d100|11223344556677885f5f5f5f5f	64	plan9	ROLW $0x1, 0(AX)
+66d108|11223344556677885f5f5f5f5f	32	intel	ror word ptr [eax], 0x1
+66d108|11223344556677885f5f5f5f5f	32	plan9	RORW $0x1, 0(AX)
+66d108|11223344556677885f5f5f5f5f	64	gnu	rorw (%rax)
+66d108|11223344556677885f5f5f5f5f	64	intel	ror word ptr [rax], 0x1
+66d108|11223344556677885f5f5f5f5f	64	plan9	RORW $0x1, 0(AX)
+66d111|223344556677885f5f5f5f5f5f	32	intel	rcl word ptr [ecx], 0x1
+66d111|223344556677885f5f5f5f5f5f	32	plan9	RCLW $0x1, 0(CX)
+66d111|223344556677885f5f5f5f5f5f	64	gnu	rclw (%rcx)
+66d111|223344556677885f5f5f5f5f5f	64	intel	rcl word ptr [rcx], 0x1
+66d111|223344556677885f5f5f5f5f5f	64	plan9	RCLW $0x1, 0(CX)
+66d118|11223344556677885f5f5f5f5f	32	intel	rcr word ptr [eax], 0x1
+66d118|11223344556677885f5f5f5f5f	32	plan9	RCRW $0x1, 0(AX)
+66d118|11223344556677885f5f5f5f5f	64	gnu	rcrw (%rax)
+66d118|11223344556677885f5f5f5f5f	64	intel	rcr word ptr [rax], 0x1
+66d118|11223344556677885f5f5f5f5f	64	plan9	RCRW $0x1, 0(AX)
+66d120|11223344556677885f5f5f5f5f	32	intel	shl word ptr [eax], 0x1
+66d120|11223344556677885f5f5f5f5f	32	plan9	SHLW $0x1, 0(AX)
+66d120|11223344556677885f5f5f5f5f	64	gnu	shlw (%rax)
+66d120|11223344556677885f5f5f5f5f	64	intel	shl word ptr [rax], 0x1
+66d120|11223344556677885f5f5f5f5f	64	plan9	SHLW $0x1, 0(AX)
+66d128|11223344556677885f5f5f5f5f	32	intel	shr word ptr [eax], 0x1
+66d128|11223344556677885f5f5f5f5f	32	plan9	SHRW $0x1, 0(AX)
+66d128|11223344556677885f5f5f5f5f	64	gnu	shrw (%rax)
+66d128|11223344556677885f5f5f5f5f	64	intel	shr word ptr [rax], 0x1
+66d128|11223344556677885f5f5f5f5f	64	plan9	SHRW $0x1, 0(AX)
+66d138|11223344556677885f5f5f5f5f	32	intel	sar word ptr [eax], 0x1
+66d138|11223344556677885f5f5f5f5f	32	plan9	SARW $0x1, 0(AX)
+66d138|11223344556677885f5f5f5f5f	64	gnu	sarw (%rax)
+66d138|11223344556677885f5f5f5f5f	64	intel	sar word ptr [rax], 0x1
+66d138|11223344556677885f5f5f5f5f	64	plan9	SARW $0x1, 0(AX)
+66d300|11223344556677885f5f5f5f5f	32	intel	rol word ptr [eax], cl
+66d300|11223344556677885f5f5f5f5f	32	plan9	ROLW CL, 0(AX)
+66d300|11223344556677885f5f5f5f5f	64	gnu	rolw %cl,(%rax)
+66d300|11223344556677885f5f5f5f5f	64	intel	rol word ptr [rax], cl
+66d300|11223344556677885f5f5f5f5f	64	plan9	ROLW CL, 0(AX)
+66d308|11223344556677885f5f5f5f5f	32	intel	ror word ptr [eax], cl
+66d308|11223344556677885f5f5f5f5f	32	plan9	RORW CL, 0(AX)
+66d308|11223344556677885f5f5f5f5f	64	gnu	rorw %cl,(%rax)
+66d308|11223344556677885f5f5f5f5f	64	intel	ror word ptr [rax], cl
+66d308|11223344556677885f5f5f5f5f	64	plan9	RORW CL, 0(AX)
+66d311|223344556677885f5f5f5f5f5f	32	intel	rcl word ptr [ecx], cl
+66d311|223344556677885f5f5f5f5f5f	32	plan9	RCLW CL, 0(CX)
+66d311|223344556677885f5f5f5f5f5f	64	gnu	rclw %cl,(%rcx)
+66d311|223344556677885f5f5f5f5f5f	64	intel	rcl word ptr [rcx], cl
+66d311|223344556677885f5f5f5f5f5f	64	plan9	RCLW CL, 0(CX)
+66d318|11223344556677885f5f5f5f5f	32	intel	rcr word ptr [eax], cl
+66d318|11223344556677885f5f5f5f5f	32	plan9	RCRW CL, 0(AX)
+66d318|11223344556677885f5f5f5f5f	64	gnu	rcrw %cl,(%rax)
+66d318|11223344556677885f5f5f5f5f	64	intel	rcr word ptr [rax], cl
+66d318|11223344556677885f5f5f5f5f	64	plan9	RCRW CL, 0(AX)
+66d320|11223344556677885f5f5f5f5f	32	intel	shl word ptr [eax], cl
+66d320|11223344556677885f5f5f5f5f	32	plan9	SHLW CL, 0(AX)
+66d320|11223344556677885f5f5f5f5f	64	gnu	shlw %cl,(%rax)
+66d320|11223344556677885f5f5f5f5f	64	intel	shl word ptr [rax], cl
+66d320|11223344556677885f5f5f5f5f	64	plan9	SHLW CL, 0(AX)
+66d328|11223344556677885f5f5f5f5f	32	intel	shr word ptr [eax], cl
+66d328|11223344556677885f5f5f5f5f	32	plan9	SHRW CL, 0(AX)
+66d328|11223344556677885f5f5f5f5f	64	gnu	shrw %cl,(%rax)
+66d328|11223344556677885f5f5f5f5f	64	intel	shr word ptr [rax], cl
+66d328|11223344556677885f5f5f5f5f	64	plan9	SHRW CL, 0(AX)
+66d338|11223344556677885f5f5f5f5f	32	intel	sar word ptr [eax], cl
+66d338|11223344556677885f5f5f5f5f	32	plan9	SARW CL, 0(AX)
+66d338|11223344556677885f5f5f5f5f	64	gnu	sarw %cl,(%rax)
+66d338|11223344556677885f5f5f5f5f	64	intel	sar word ptr [rax], cl
+66d338|11223344556677885f5f5f5f5f	64	plan9	SARW CL, 0(AX)
+66d411|223344556677885f5f5f5f5f5f	32	intel	aam 0x11
+66d411|223344556677885f5f5f5f5f5f	32	plan9	AAM $0x11
+66d920|11223344556677885f5f5f5f5f	32	intel	fldenv ptr [eax]
+66d920|11223344556677885f5f5f5f5f	32	plan9	FLDENVW 0(AX)
+66d920|11223344556677885f5f5f5f5f	64	gnu	fldenvs (%rax)
+66d920|11223344556677885f5f5f5f5f	64	intel	fldenv ptr [rax]
+66d920|11223344556677885f5f5f5f5f	64	plan9	FLDENVW 0(AX)
+66e511|223344556677885f5f5f5f5f5f	32	intel	in ax, 0x11
+66e511|223344556677885f5f5f5f5f5f	32	plan9	INW $0x11, AX
+66e511|223344556677885f5f5f5f5f5f	64	gnu	in $0x11,%ax
+66e511|223344556677885f5f5f5f5f5f	64	intel	in ax, 0x11
+66e511|223344556677885f5f5f5f5f5f	64	plan9	INW $0x11, AX
+66e711|223344556677885f5f5f5f5f5f	32	intel	out 0x11, ax
+66e711|223344556677885f5f5f5f5f5f	32	plan9	OUTW AX, $0x11
+66e711|223344556677885f5f5f5f5f5f	64	gnu	out %ax,$0x11
+66e711|223344556677885f5f5f5f5f5f	64	intel	out 0x11, ax
+66e711|223344556677885f5f5f5f5f5f	64	plan9	OUTW AX, $0x11
+66e811223344|556677885f5f5f5f5f5f	64	gnu	callw .+0x44332211
+66e811223344|556677885f5f5f5f5f5f	64	intel	call .+0x44332211
+66e811223344|556677885f5f5f5f5f5f	64	plan9	CALL .+1144201745
+66e81122|3344556677885f5f5f5f5f5f	32	intel	call .+0x2211
+66e81122|3344556677885f5f5f5f5f5f	32	plan9	CALL .+8721
+66e911223344|556677885f5f5f5f5f5f	64	gnu	jmpw .+0x44332211
+66e911223344|556677885f5f5f5f5f5f	64	intel	jmp .+0x44332211
+66e911223344|556677885f5f5f5f5f5f	64	plan9	JMP .+1144201745
+66e91122|3344556677885f5f5f5f5f5f	32	intel	jmp .+0x2211
+66e91122|3344556677885f5f5f5f5f5f	32	plan9	JMP .+8721
+66ea11223344|556677885f5f5f5f5f5f	32	intel	jmp far 0x2211, 0x4433
+66ea11223344|556677885f5f5f5f5f5f	32	plan9	LJMP $0x2211, $0x4433
+66ed|11223344556677885f5f5f5f5f5f	32	intel	in ax, dx
+66ed|11223344556677885f5f5f5f5f5f	32	plan9	INW DX, AX
+66ed|11223344556677885f5f5f5f5f5f	64	gnu	in (%dx),%ax
+66ed|11223344556677885f5f5f5f5f5f	64	intel	in ax, dx
+66ed|11223344556677885f5f5f5f5f5f	64	plan9	INW DX, AX
+66ef|11223344556677885f5f5f5f5f5f	32	intel	out dx, ax
+66ef|11223344556677885f5f5f5f5f5f	32	plan9	OUTW AX, DX
+66ef|11223344556677885f5f5f5f5f5f	64	gnu	out %ax,(%dx)
+66ef|11223344556677885f5f5f5f5f5f	64	intel	out dx, ax
+66ef|11223344556677885f5f5f5f5f5f	64	plan9	OUTW AX, DX
+66f20f2a11|223344556677885f5f5f5f	32	intel	cvtsi2sd xmm2, dword ptr [ecx]
+66f20f2a11|223344556677885f5f5f5f	32	plan9	REPNE CVTSI2SDL 0(CX), X2
+66f20f2a11|223344556677885f5f5f5f	64	gnu	cvtsi2sdl (%rcx),%xmm2
+66f20f2a11|223344556677885f5f5f5f	64	intel	cvtsi2sd xmm2, dword ptr [rcx]
+66f20f2a11|223344556677885f5f5f5f	64	plan9	REPNE CVTSI2SDL 0(CX), X2
+# the Q extension is the size of the source float64 in memory. The destination is L.
+66f20f2c11|223344556677885f5f5f5f	32	intel	cvttsd2si edx, qword ptr [ecx]
+66f20f2c11|223344556677885f5f5f5f	32	plan9	REPNE CVTTSD2SIQ 0(CX), DX
+66f20f2c11|223344556677885f5f5f5f	64	gnu	cvttsd2si (%rcx),%dx
+66f20f2c11|223344556677885f5f5f5f	64	intel	cvttsd2si edx, qword ptr [rcx]
+66f20f2c11|223344556677885f5f5f5f	64	plan9	REPNE CVTTSD2SIQ 0(CX), DX
+66f20f2d11|223344556677885f5f5f5f	32	intel	cvtsd2si edx, qword ptr [ecx]
+66f20f2d11|223344556677885f5f5f5f	32	plan9	REPNE CVTSD2SIQ 0(CX), DX
+66f20f2d11|223344556677885f5f5f5f	64	gnu	cvtsd2si (%rcx),%dx
+66f20f2d11|223344556677885f5f5f5f	64	intel	cvtsd2si edx, qword ptr [rcx]
+66f20f2d11|223344556677885f5f5f5f	64	plan9	REPNE CVTSD2SIQ 0(CX), DX
+66f20f38f011|223344556677885f5f5f	32	intel	crc32 edx, byte ptr [ecx]
+66f20f38f011|223344556677885f5f5f	32	plan9	REPNE CRC32 0(CX), DX
+66f20f38f011|223344556677885f5f5f	64	gnu	crc32b (%rcx),%edx
+66f20f38f011|223344556677885f5f5f	64	intel	crc32 edx, byte ptr [rcx]
+66f20f38f011|223344556677885f5f5f	64	plan9	REPNE CRC32 0(CX), DX
+66f30f2c11|223344556677885f5f5f5f	32	intel	cvttss2si edx, dword ptr [ecx]
+66f30f2c11|223344556677885f5f5f5f	32	plan9	REP CVTTSS2SIL 0(CX), DX
+66f30f2c11|223344556677885f5f5f5f	64	gnu	cvttss2si (%rcx),%dx
+66f30f2c11|223344556677885f5f5f5f	64	intel	cvttss2si edx, dword ptr [rcx]
+66f30f2c11|223344556677885f5f5f5f	64	plan9	REP CVTTSS2SIL 0(CX), DX
+66f30f2d11|223344556677885f5f5f5f	32	intel	cvtss2si edx, dword ptr [ecx]
+66f30f2d11|223344556677885f5f5f5f	32	plan9	REP CVTSS2SIL 0(CX), DX
+66f30f2d11|223344556677885f5f5f5f	64	gnu	cvtss2si (%rcx),%dx
+66f30f2d11|223344556677885f5f5f5f	64	intel	cvtss2si edx, dword ptr [rcx]
+66f30f2d11|223344556677885f5f5f5f	64	plan9	REP CVTSS2SIL 0(CX), DX
+66f30fae11|223344556677885f5f5f5f	64	gnu	wrfsbasel (%rcx)
+66f30fae11|223344556677885f5f5f5f	64	intel	wrfsbase dword ptr [rcx]
+66f30fae11|223344556677885f5f5f5f	64	plan9	REP WRFSBASE 0(CX)
+66f30fae18|11223344556677885f5f5f	64	gnu	wrgsbasel (%rax)
+66f30fae18|11223344556677885f5f5f	64	intel	wrgsbase dword ptr [rax]
+66f30fae18|11223344556677885f5f5f	64	plan9	REP WRGSBASE 0(AX)
+66f30faec0|11223344556677885f5f5f	64	gnu	rdfsbase %eax
+66f30faec0|11223344556677885f5f5f	64	intel	rdfsbase eax
+66f30faec0|11223344556677885f5f5f	64	plan9	REP RDFSBASE AX
+66f30faec8|11223344556677885f5f5f	64	gnu	rdgsbase %eax
+66f30faec8|11223344556677885f5f5f	64	intel	rdgsbase eax
+66f30faec8|11223344556677885f5f5f	64	plan9	REP RDGSBASE AX
+66f30fd6c5|11223344556677885f5f5f	32	intel	movq2dq xmm0, mmx5
+66f30fd6c5|11223344556677885f5f5f	32	plan9	REP MOVQ2DQ M5, X0
+66f30fd6c5|11223344556677885f5f5f	64	gnu	movq2dq %mm5,%xmm0
+66f30fd6c5|11223344556677885f5f5f	64	intel	movq2dq xmm0, mmx5
+66f30fd6c5|11223344556677885f5f5f	64	plan9	REP MOVQ2DQ M5, X0
+66f7001122|3344556677885f5f5f5f5f	32	intel	test word ptr [eax], 0x2211
+66f7001122|3344556677885f5f5f5f5f	32	plan9	TESTW $0x2211, 0(AX)
+66f7001122|3344556677885f5f5f5f5f	64	gnu	testw $0x2211,(%rax)
+66f7001122|3344556677885f5f5f5f5f	64	intel	test word ptr [rax], 0x2211
+66f7001122|3344556677885f5f5f5f5f	64	plan9	TESTW $0x2211, 0(AX)
+66f711|223344556677885f5f5f5f5f5f	32	intel	not word ptr [ecx]
+66f711|223344556677885f5f5f5f5f5f	32	plan9	NOTW 0(CX)
+66f711|223344556677885f5f5f5f5f5f	64	gnu	notw (%rcx)
+66f711|223344556677885f5f5f5f5f5f	64	intel	not word ptr [rcx]
+66f711|223344556677885f5f5f5f5f5f	64	plan9	NOTW 0(CX)
+66f718|11223344556677885f5f5f5f5f	32	intel	neg word ptr [eax]
+66f718|11223344556677885f5f5f5f5f	32	plan9	NEGW 0(AX)
+66f718|11223344556677885f5f5f5f5f	64	gnu	negw (%rax)
+66f718|11223344556677885f5f5f5f5f	64	intel	neg word ptr [rax]
+66f718|11223344556677885f5f5f5f5f	64	plan9	NEGW 0(AX)
+66f720|11223344556677885f5f5f5f5f	32	intel	mul word ptr [eax]
+66f720|11223344556677885f5f5f5f5f	32	plan9	MULW 0(AX)
+66f720|11223344556677885f5f5f5f5f	64	gnu	mulw (%rax)
+66f720|11223344556677885f5f5f5f5f	64	intel	mul word ptr [rax]
+66f720|11223344556677885f5f5f5f5f	64	plan9	MULW 0(AX)
+66f728|11223344556677885f5f5f5f5f	32	intel	imul word ptr [eax]
+66f728|11223344556677885f5f5f5f5f	32	plan9	IMULW 0(AX)
+66f728|11223344556677885f5f5f5f5f	64	gnu	imulw (%rax)
+66f728|11223344556677885f5f5f5f5f	64	intel	imul word ptr [rax]
+66f728|11223344556677885f5f5f5f5f	64	plan9	IMULW 0(AX)
+66f730|11223344556677885f5f5f5f5f	32	intel	div word ptr [eax]
+66f730|11223344556677885f5f5f5f5f	32	plan9	DIVW 0(AX)
+66f730|11223344556677885f5f5f5f5f	64	gnu	divw (%rax)
+66f730|11223344556677885f5f5f5f5f	64	intel	div word ptr [rax]
+66f730|11223344556677885f5f5f5f5f	64	plan9	DIVW 0(AX)
+66f738|11223344556677885f5f5f5f5f	32	intel	idiv word ptr [eax]
+66f738|11223344556677885f5f5f5f5f	32	plan9	IDIVW 0(AX)
+66f738|11223344556677885f5f5f5f5f	64	gnu	idivw (%rax)
+66f738|11223344556677885f5f5f5f5f	64	intel	idiv word ptr [rax]
+66f738|11223344556677885f5f5f5f5f	64	plan9	IDIVW 0(AX)
+66ff00|11223344556677885f5f5f5f5f	32	intel	inc word ptr [eax]
+66ff00|11223344556677885f5f5f5f5f	32	plan9	INCW 0(AX)
+66ff00|11223344556677885f5f5f5f5f	64	gnu	incw (%rax)
+66ff00|11223344556677885f5f5f5f5f	64	intel	inc word ptr [rax]
+66ff00|11223344556677885f5f5f5f5f	64	plan9	INCW 0(AX)
+66ff08|11223344556677885f5f5f5f5f	32	intel	dec word ptr [eax]
+66ff08|11223344556677885f5f5f5f5f	32	plan9	DECW 0(AX)
+66ff08|11223344556677885f5f5f5f5f	64	gnu	decw (%rax)
+66ff08|11223344556677885f5f5f5f5f	64	intel	dec word ptr [rax]
+66ff08|11223344556677885f5f5f5f5f	64	plan9	DECW 0(AX)
+66ff11|223344556677885f5f5f5f5f5f	32	intel	call word ptr [ecx]
+66ff11|223344556677885f5f5f5f5f5f	32	plan9	CALL 0(CX)
+66ff11|223344556677885f5f5f5f5f5f	64	gnu	callw *(%rcx)
+66ff11|223344556677885f5f5f5f5f5f	64	intel	call qword ptr [rcx]
+66ff11|223344556677885f5f5f5f5f5f	64	plan9	CALL 0(CX)
+66ff18|11223344556677885f5f5f5f5f	32	intel	call far dword ptr [eax]
+66ff18|11223344556677885f5f5f5f5f	32	plan9	LCALL 0(AX)
+66ff18|11223344556677885f5f5f5f5f	64	gnu	lcallw *(%rax)
+66ff18|11223344556677885f5f5f5f5f	64	intel	call far dword ptr [rax]
+66ff18|11223344556677885f5f5f5f5f	64	plan9	LCALL 0(AX)
+66ff20|11223344556677885f5f5f5f5f	32	intel	jmp word ptr [eax]
+66ff20|11223344556677885f5f5f5f5f	32	plan9	JMP 0(AX)
+66ff20|11223344556677885f5f5f5f5f	64	gnu	jmpw *(%rax)
+66ff20|11223344556677885f5f5f5f5f	64	intel	jmp qword ptr [rax]
+66ff20|11223344556677885f5f5f5f5f	64	plan9	JMP 0(AX)
+66ff28|11223344556677885f5f5f5f5f	32	intel	jmp far dword ptr [eax]
+66ff28|11223344556677885f5f5f5f5f	32	plan9	LJMP 0(AX)
+66ff28|11223344556677885f5f5f5f5f	64	gnu	ljmpw *(%rax)
+66ff28|11223344556677885f5f5f5f5f	64	intel	jmp far dword ptr [rax]
+66ff28|11223344556677885f5f5f5f5f	64	plan9	LJMP 0(AX)
+66ff30|11223344556677885f5f5f5f5f	32	intel	push word ptr [eax]
+66ff30|11223344556677885f5f5f5f5f	32	plan9	PUSHW 0(AX)
+66ff30|11223344556677885f5f5f5f5f	64	gnu	pushw (%rax)
+66ff30|11223344556677885f5f5f5f5f	64	intel	push word ptr [rax]
+66ff30|11223344556677885f5f5f5f5f	64	plan9	PUSHW 0(AX)
+66|9a11223344556677885f5f5f5f5f5f	64	gnu	data16
+66|9a11223344556677885f5f5f5f5f5f	64	intel	data16
+66|9a11223344556677885f5f5f5f5f5f	64	plan9	Op(0)
+66|c411223344556677885f5f5f5f5f5f	64	gnu	data16
+66|c411223344556677885f5f5f5f5f5f	64	intel	data16
+66|c411223344556677885f5f5f5f5f5f	64	plan9	Op(0)
+66|c511223344556677885f5f5f5f5f5f	64	gnu	data16
+66|c511223344556677885f5f5f5f5f5f	64	intel	data16
+66|c511223344556677885f5f5f5f5f5f	64	plan9	Op(0)
+66|d411223344556677885f5f5f5f5f5f	64	gnu	data16
+66|d411223344556677885f5f5f5f5f5f	64	intel	data16
+66|d411223344556677885f5f5f5f5f5f	64	plan9	Op(0)
+66|ea11223344556677885f5f5f5f5f5f	64	gnu	data16
+66|ea11223344556677885f5f5f5f5f5f	64	intel	data16
+66|ea11223344556677885f5f5f5f5f5f	64	plan9	Op(0)
+676c|11223344556677885f5f5f5f5f5f	32	intel	addr16 insb
+676c|11223344556677885f5f5f5f5f5f	32	plan9	INSB DX, ES:0(DI)
+676c|11223344556677885f5f5f5f5f5f	64	gnu	insb (%dx),%es:(%edi)
+676c|11223344556677885f5f5f5f5f5f	64	intel	addr32 insb
+676c|11223344556677885f5f5f5f5f5f	64	plan9	INSB DX, ES:0(DI)
+67d7|11223344556677885f5f5f5f5f5f	32	intel	addr16 xlat
+67d7|11223344556677885f5f5f5f5f5f	32	plan9	XLATB DS:0(BX)
+67d7|11223344556677885f5f5f5f5f5f	64	gnu	xlat %ds:(%ebx)
+67d7|11223344556677885f5f5f5f5f5f	64	intel	addr32 xlat
+67d7|11223344556677885f5f5f5f5f5f	64	plan9	XLATB DS:0(BX)
+67e311|223344556677885f5f5f5f5f5f	32	intel	addr16 jcxz .+0x11
+67e311|223344556677885f5f5f5f5f5f	32	plan9	JCXZ .+17
+67e311|223344556677885f5f5f5f5f5f	64	gnu	jecxz .+0x11
+67e311|223344556677885f5f5f5f5f5f	64	intel	addr32 jecxz .+0x11
+67e311|223344556677885f5f5f5f5f5f	64	plan9	JECXZ .+17
+6811223344|556677885f5f5f5f5f5f5f	32	intel	push 0x44332211
+6811223344|556677885f5f5f5f5f5f5f	32	plan9	PUSHL $0x44332211
+6811223344|556677885f5f5f5f5f5f5f	64	gnu	pushq $0x44332211
+6811223344|556677885f5f5f5f5f5f5f	64	intel	push 0x44332211
+6811223344|556677885f5f5f5f5f5f5f	64	plan9	PUSHL $0x44332211
+691122334455|6677885f5f5f5f5f5f5f	32	intel	imul edx, dword ptr [ecx], 0x55443322
+691122334455|6677885f5f5f5f5f5f5f	32	plan9	IMULL $0x55443322, 0(CX), DX
+691122334455|6677885f5f5f5f5f5f5f	64	gnu	imul $0x55443322,(%rcx),%edx
+691122334455|6677885f5f5f5f5f5f5f	64	intel	imul edx, dword ptr [rcx], 0x55443322
+691122334455|6677885f5f5f5f5f5f5f	64	plan9	IMULL $0x55443322, 0(CX), DX
+6a11|223344556677885f5f5f5f5f5f5f	32	intel	push 0x11
+6a11|223344556677885f5f5f5f5f5f5f	32	plan9	PUSHL $0x11
+6a11|223344556677885f5f5f5f5f5f5f	64	gnu	pushq $0x11
+6a11|223344556677885f5f5f5f5f5f5f	64	intel	push 0x11
+6a11|223344556677885f5f5f5f5f5f5f	64	plan9	PUSHL $0x11
+6b1122|3344556677885f5f5f5f5f5f5f	32	intel	imul edx, dword ptr [ecx], 0x22
+6b1122|3344556677885f5f5f5f5f5f5f	32	plan9	IMULL $0x22, 0(CX), DX
+6b1122|3344556677885f5f5f5f5f5f5f	64	gnu	imul $0x22,(%rcx),%edx
+6b1122|3344556677885f5f5f5f5f5f5f	64	intel	imul edx, dword ptr [rcx], 0x22
+6b1122|3344556677885f5f5f5f5f5f5f	64	plan9	IMULL $0x22, 0(CX), DX
+6d|11223344556677885f5f5f5f5f5f5f	32	intel	insd
+6d|11223344556677885f5f5f5f5f5f5f	32	plan9	INSD DX, ES:0(DI)
+6d|11223344556677885f5f5f5f5f5f5f	64	gnu	insl (%dx),%es:(%rdi)
+6d|11223344556677885f5f5f5f5f5f5f	64	intel	insd
+6d|11223344556677885f5f5f5f5f5f5f	64	plan9	INSD DX, ES:0(DI)
+6f|11223344556677885f5f5f5f5f5f5f	32	intel	outsd
+6f|11223344556677885f5f5f5f5f5f5f	32	plan9	OUTSD DS:0(SI), DX
+6f|11223344556677885f5f5f5f5f5f5f	64	gnu	outsl %ds:(%rsi),(%dx)
+6f|11223344556677885f5f5f5f5f5f5f	64	intel	outsd
+6f|11223344556677885f5f5f5f5f5f5f	64	plan9	OUTSD DS:0(SI), DX
+7111|223344556677885f5f5f5f5f5f5f	32	intel	jno .+0x11
+7111|223344556677885f5f5f5f5f5f5f	32	plan9	JNO .+17
+7111|223344556677885f5f5f5f5f5f5f	64	gnu	jno .+0x11
+7111|223344556677885f5f5f5f5f5f5f	64	intel	jno .+0x11
+7111|223344556677885f5f5f5f5f5f5f	64	plan9	JNO .+17
+7211|223344556677885f5f5f5f5f5f5f	32	intel	jb .+0x11
+7211|223344556677885f5f5f5f5f5f5f	32	plan9	JB .+17
+7211|223344556677885f5f5f5f5f5f5f	64	gnu	jb .+0x11
+7211|223344556677885f5f5f5f5f5f5f	64	intel	jb .+0x11
+7211|223344556677885f5f5f5f5f5f5f	64	plan9	JB .+17
+7311|223344556677885f5f5f5f5f5f5f	32	intel	jnb .+0x11
+7311|223344556677885f5f5f5f5f5f5f	32	plan9	JAE .+17
+7311|223344556677885f5f5f5f5f5f5f	64	gnu	jae .+0x11
+7311|223344556677885f5f5f5f5f5f5f	64	intel	jnb .+0x11
+7311|223344556677885f5f5f5f5f5f5f	64	plan9	JAE .+17
+7411|223344556677885f5f5f5f5f5f5f	32	intel	jz .+0x11
+7411|223344556677885f5f5f5f5f5f5f	32	plan9	JE .+17
+7411|223344556677885f5f5f5f5f5f5f	64	gnu	je .+0x11
+7411|223344556677885f5f5f5f5f5f5f	64	intel	jz .+0x11
+7411|223344556677885f5f5f5f5f5f5f	64	plan9	JE .+17
+7511|223344556677885f5f5f5f5f5f5f	32	intel	jnz .+0x11
+7511|223344556677885f5f5f5f5f5f5f	32	plan9	JNE .+17
+7511|223344556677885f5f5f5f5f5f5f	64	gnu	jne .+0x11
+7511|223344556677885f5f5f5f5f5f5f	64	intel	jnz .+0x11
+7511|223344556677885f5f5f5f5f5f5f	64	plan9	JNE .+17
+7611|223344556677885f5f5f5f5f5f5f	32	intel	jbe .+0x11
+7611|223344556677885f5f5f5f5f5f5f	32	plan9	JBE .+17
+7611|223344556677885f5f5f5f5f5f5f	64	gnu	jbe .+0x11
+7611|223344556677885f5f5f5f5f5f5f	64	intel	jbe .+0x11
+7611|223344556677885f5f5f5f5f5f5f	64	plan9	JBE .+17
+7711|223344556677885f5f5f5f5f5f5f	32	intel	jnbe .+0x11
+7711|223344556677885f5f5f5f5f5f5f	32	plan9	JA .+17
+7711|223344556677885f5f5f5f5f5f5f	64	gnu	ja .+0x11
+7711|223344556677885f5f5f5f5f5f5f	64	intel	jnbe .+0x11
+7711|223344556677885f5f5f5f5f5f5f	64	plan9	JA .+17
+7811|223344556677885f5f5f5f5f5f5f	32	intel	js .+0x11
+7811|223344556677885f5f5f5f5f5f5f	32	plan9	JS .+17
+7811|223344556677885f5f5f5f5f5f5f	64	gnu	js .+0x11
+7811|223344556677885f5f5f5f5f5f5f	64	intel	js .+0x11
+7811|223344556677885f5f5f5f5f5f5f	64	plan9	JS .+17
+7911|223344556677885f5f5f5f5f5f5f	32	intel	jns .+0x11
+7911|223344556677885f5f5f5f5f5f5f	32	plan9	JNS .+17
+7911|223344556677885f5f5f5f5f5f5f	64	gnu	jns .+0x11
+7911|223344556677885f5f5f5f5f5f5f	64	intel	jns .+0x11
+7911|223344556677885f5f5f5f5f5f5f	64	plan9	JNS .+17
+7a11|223344556677885f5f5f5f5f5f5f	32	intel	jp .+0x11
+7a11|223344556677885f5f5f5f5f5f5f	32	plan9	JP .+17
+7a11|223344556677885f5f5f5f5f5f5f	64	gnu	jp .+0x11
+7a11|223344556677885f5f5f5f5f5f5f	64	intel	jp .+0x11
+7a11|223344556677885f5f5f5f5f5f5f	64	plan9	JP .+17
+7b11|223344556677885f5f5f5f5f5f5f	32	intel	jnp .+0x11
+7b11|223344556677885f5f5f5f5f5f5f	32	plan9	JNP .+17
+7b11|223344556677885f5f5f5f5f5f5f	64	gnu	jnp .+0x11
+7b11|223344556677885f5f5f5f5f5f5f	64	intel	jnp .+0x11
+7b11|223344556677885f5f5f5f5f5f5f	64	plan9	JNP .+17
+7c11|223344556677885f5f5f5f5f5f5f	32	intel	jl .+0x11
+7c11|223344556677885f5f5f5f5f5f5f	32	plan9	JL .+17
+7c11|223344556677885f5f5f5f5f5f5f	64	gnu	jl .+0x11
+7c11|223344556677885f5f5f5f5f5f5f	64	intel	jl .+0x11
+7c11|223344556677885f5f5f5f5f5f5f	64	plan9	JL .+17
+7d11|223344556677885f5f5f5f5f5f5f	32	intel	jnl .+0x11
+7d11|223344556677885f5f5f5f5f5f5f	32	plan9	JGE .+17
+7d11|223344556677885f5f5f5f5f5f5f	64	gnu	jge .+0x11
+7d11|223344556677885f5f5f5f5f5f5f	64	intel	jnl .+0x11
+7d11|223344556677885f5f5f5f5f5f5f	64	plan9	JGE .+17
+7e11|223344556677885f5f5f5f5f5f5f	32	intel	jle .+0x11
+7e11|223344556677885f5f5f5f5f5f5f	32	plan9	JLE .+17
+7e11|223344556677885f5f5f5f5f5f5f	64	gnu	jle .+0x11
+7e11|223344556677885f5f5f5f5f5f5f	64	intel	jle .+0x11
+7e11|223344556677885f5f5f5f5f5f5f	64	plan9	JLE .+17
+7f11|223344556677885f5f5f5f5f5f5f	32	intel	jnle .+0x11
+7f11|223344556677885f5f5f5f5f5f5f	32	plan9	JG .+17
+7f11|223344556677885f5f5f5f5f5f5f	64	gnu	jg .+0x11
+7f11|223344556677885f5f5f5f5f5f5f	64	intel	jnle .+0x11
+7f11|223344556677885f5f5f5f5f5f5f	64	plan9	JG .+17
+800011|223344556677885f5f5f5f5f5f	32	intel	add byte ptr [eax], 0x11
+800011|223344556677885f5f5f5f5f5f	32	plan9	ADDB $0x11, 0(AX)
+800011|223344556677885f5f5f5f5f5f	64	gnu	addb $0x11,(%rax)
+800011|223344556677885f5f5f5f5f5f	64	intel	add byte ptr [rax], 0x11
+800011|223344556677885f5f5f5f5f5f	64	plan9	ADDB $0x11, 0(AX)
+800811|223344556677885f5f5f5f5f5f	32	intel	or byte ptr [eax], 0x11
+800811|223344556677885f5f5f5f5f5f	32	plan9	ORB $0x11, 0(AX)
+800811|223344556677885f5f5f5f5f5f	64	gnu	orb $0x11,(%rax)
+800811|223344556677885f5f5f5f5f5f	64	intel	or byte ptr [rax], 0x11
+800811|223344556677885f5f5f5f5f5f	64	plan9	ORB $0x11, 0(AX)
+801122|3344556677885f5f5f5f5f5f5f	32	intel	adc byte ptr [ecx], 0x22
+801122|3344556677885f5f5f5f5f5f5f	32	plan9	ADCB $0x22, 0(CX)
+801122|3344556677885f5f5f5f5f5f5f	64	gnu	adcb $0x22,(%rcx)
+801122|3344556677885f5f5f5f5f5f5f	64	intel	adc byte ptr [rcx], 0x22
+801122|3344556677885f5f5f5f5f5f5f	64	plan9	ADCB $0x22, 0(CX)
+801811|223344556677885f5f5f5f5f5f	32	intel	sbb byte ptr [eax], 0x11
+801811|223344556677885f5f5f5f5f5f	32	plan9	SBBB $0x11, 0(AX)
+801811|223344556677885f5f5f5f5f5f	64	gnu	sbbb $0x11,(%rax)
+801811|223344556677885f5f5f5f5f5f	64	intel	sbb byte ptr [rax], 0x11
+801811|223344556677885f5f5f5f5f5f	64	plan9	SBBB $0x11, 0(AX)
+802011|223344556677885f5f5f5f5f5f	32	intel	and byte ptr [eax], 0x11
+802011|223344556677885f5f5f5f5f5f	32	plan9	ANDB $0x11, 0(AX)
+802011|223344556677885f5f5f5f5f5f	64	gnu	andb $0x11,(%rax)
+802011|223344556677885f5f5f5f5f5f	64	intel	and byte ptr [rax], 0x11
+802011|223344556677885f5f5f5f5f5f	64	plan9	ANDB $0x11, 0(AX)
+802811|223344556677885f5f5f5f5f5f	32	intel	sub byte ptr [eax], 0x11
+802811|223344556677885f5f5f5f5f5f	32	plan9	SUBB $0x11, 0(AX)
+802811|223344556677885f5f5f5f5f5f	64	gnu	subb $0x11,(%rax)
+802811|223344556677885f5f5f5f5f5f	64	intel	sub byte ptr [rax], 0x11
+802811|223344556677885f5f5f5f5f5f	64	plan9	SUBB $0x11, 0(AX)
+803011|223344556677885f5f5f5f5f5f	32	intel	xor byte ptr [eax], 0x11
+803011|223344556677885f5f5f5f5f5f	32	plan9	XORB $0x11, 0(AX)
+803011|223344556677885f5f5f5f5f5f	64	gnu	xorb $0x11,(%rax)
+803011|223344556677885f5f5f5f5f5f	64	intel	xor byte ptr [rax], 0x11
+803011|223344556677885f5f5f5f5f5f	64	plan9	XORB $0x11, 0(AX)
+803811|223344556677885f5f5f5f5f5f	32	intel	cmp byte ptr [eax], 0x11
+803811|223344556677885f5f5f5f5f5f	32	plan9	CMPB $0x11, 0(AX)
+803811|223344556677885f5f5f5f5f5f	64	gnu	cmpb $0x11,(%rax)
+803811|223344556677885f5f5f5f5f5f	64	intel	cmp byte ptr [rax], 0x11
+803811|223344556677885f5f5f5f5f5f	64	plan9	CMPB $0x11, 0(AX)
+810011223344|556677885f5f5f5f5f5f	32	intel	add dword ptr [eax], 0x44332211
+810011223344|556677885f5f5f5f5f5f	32	plan9	ADDL $0x44332211, 0(AX)
+810011223344|556677885f5f5f5f5f5f	64	gnu	addl $0x44332211,(%rax)
+810011223344|556677885f5f5f5f5f5f	64	intel	add dword ptr [rax], 0x44332211
+810011223344|556677885f5f5f5f5f5f	64	plan9	ADDL $0x44332211, 0(AX)
+810811223344|556677885f5f5f5f5f5f	32	intel	or dword ptr [eax], 0x44332211
+810811223344|556677885f5f5f5f5f5f	32	plan9	ORL $0x44332211, 0(AX)
+810811223344|556677885f5f5f5f5f5f	64	gnu	orl $0x44332211,(%rax)
+810811223344|556677885f5f5f5f5f5f	64	intel	or dword ptr [rax], 0x44332211
+810811223344|556677885f5f5f5f5f5f	64	plan9	ORL $0x44332211, 0(AX)
+811122334455|6677885f5f5f5f5f5f5f	32	intel	adc dword ptr [ecx], 0x55443322
+811122334455|6677885f5f5f5f5f5f5f	32	plan9	ADCL $0x55443322, 0(CX)
+811122334455|6677885f5f5f5f5f5f5f	64	gnu	adcl $0x55443322,(%rcx)
+811122334455|6677885f5f5f5f5f5f5f	64	intel	adc dword ptr [rcx], 0x55443322
+811122334455|6677885f5f5f5f5f5f5f	64	plan9	ADCL $0x55443322, 0(CX)
+811811223344|556677885f5f5f5f5f5f	32	intel	sbb dword ptr [eax], 0x44332211
+811811223344|556677885f5f5f5f5f5f	32	plan9	SBBL $0x44332211, 0(AX)
+811811223344|556677885f5f5f5f5f5f	64	gnu	sbbl $0x44332211,(%rax)
+811811223344|556677885f5f5f5f5f5f	64	intel	sbb dword ptr [rax], 0x44332211
+811811223344|556677885f5f5f5f5f5f	64	plan9	SBBL $0x44332211, 0(AX)
+812011223344|556677885f5f5f5f5f5f	32	intel	and dword ptr [eax], 0x44332211
+812011223344|556677885f5f5f5f5f5f	32	plan9	ANDL $0x44332211, 0(AX)
+812011223344|556677885f5f5f5f5f5f	64	gnu	andl $0x44332211,(%rax)
+812011223344|556677885f5f5f5f5f5f	64	intel	and dword ptr [rax], 0x44332211
+812011223344|556677885f5f5f5f5f5f	64	plan9	ANDL $0x44332211, 0(AX)
+812811223344|556677885f5f5f5f5f5f	32	intel	sub dword ptr [eax], 0x44332211
+812811223344|556677885f5f5f5f5f5f	32	plan9	SUBL $0x44332211, 0(AX)
+812811223344|556677885f5f5f5f5f5f	64	gnu	subl $0x44332211,(%rax)
+812811223344|556677885f5f5f5f5f5f	64	intel	sub dword ptr [rax], 0x44332211
+812811223344|556677885f5f5f5f5f5f	64	plan9	SUBL $0x44332211, 0(AX)
+813011223344|556677885f5f5f5f5f5f	32	intel	xor dword ptr [eax], 0x44332211
+813011223344|556677885f5f5f5f5f5f	32	plan9	XORL $0x44332211, 0(AX)
+813011223344|556677885f5f5f5f5f5f	64	gnu	xorl $0x44332211,(%rax)
+813011223344|556677885f5f5f5f5f5f	64	intel	xor dword ptr [rax], 0x44332211
+813011223344|556677885f5f5f5f5f5f	64	plan9	XORL $0x44332211, 0(AX)
+813811223344|556677885f5f5f5f5f5f	32	intel	cmp dword ptr [eax], 0x44332211
+813811223344|556677885f5f5f5f5f5f	32	plan9	CMPL $0x44332211, 0(AX)
+813811223344|556677885f5f5f5f5f5f	64	gnu	cmpl $0x44332211,(%rax)
+813811223344|556677885f5f5f5f5f5f	64	intel	cmp dword ptr [rax], 0x44332211
+813811223344|556677885f5f5f5f5f5f	64	plan9	CMPL $0x44332211, 0(AX)
+830011|223344556677885f5f5f5f5f5f	32	intel	add dword ptr [eax], 0x11
+830011|223344556677885f5f5f5f5f5f	32	plan9	ADDL $0x11, 0(AX)
+830011|223344556677885f5f5f5f5f5f	64	gnu	addl $0x11,(%rax)
+830011|223344556677885f5f5f5f5f5f	64	intel	add dword ptr [rax], 0x11
+830011|223344556677885f5f5f5f5f5f	64	plan9	ADDL $0x11, 0(AX)
+830811|223344556677885f5f5f5f5f5f	32	intel	or dword ptr [eax], 0x11
+830811|223344556677885f5f5f5f5f5f	32	plan9	ORL $0x11, 0(AX)
+830811|223344556677885f5f5f5f5f5f	64	gnu	orl $0x11,(%rax)
+830811|223344556677885f5f5f5f5f5f	64	intel	or dword ptr [rax], 0x11
+830811|223344556677885f5f5f5f5f5f	64	plan9	ORL $0x11, 0(AX)
+831122|3344556677885f5f5f5f5f5f5f	32	intel	adc dword ptr [ecx], 0x22
+831122|3344556677885f5f5f5f5f5f5f	32	plan9	ADCL $0x22, 0(CX)
+831122|3344556677885f5f5f5f5f5f5f	64	gnu	adcl $0x22,(%rcx)
+831122|3344556677885f5f5f5f5f5f5f	64	intel	adc dword ptr [rcx], 0x22
+831122|3344556677885f5f5f5f5f5f5f	64	plan9	ADCL $0x22, 0(CX)
+831811|223344556677885f5f5f5f5f5f	32	intel	sbb dword ptr [eax], 0x11
+831811|223344556677885f5f5f5f5f5f	32	plan9	SBBL $0x11, 0(AX)
+831811|223344556677885f5f5f5f5f5f	64	gnu	sbbl $0x11,(%rax)
+831811|223344556677885f5f5f5f5f5f	64	intel	sbb dword ptr [rax], 0x11
+831811|223344556677885f5f5f5f5f5f	64	plan9	SBBL $0x11, 0(AX)
+832011|223344556677885f5f5f5f5f5f	32	intel	and dword ptr [eax], 0x11
+832011|223344556677885f5f5f5f5f5f	32	plan9	ANDL $0x11, 0(AX)
+832011|223344556677885f5f5f5f5f5f	64	gnu	andl $0x11,(%rax)
+832011|223344556677885f5f5f5f5f5f	64	intel	and dword ptr [rax], 0x11
+832011|223344556677885f5f5f5f5f5f	64	plan9	ANDL $0x11, 0(AX)
+832811|223344556677885f5f5f5f5f5f	32	intel	sub dword ptr [eax], 0x11
+832811|223344556677885f5f5f5f5f5f	32	plan9	SUBL $0x11, 0(AX)
+832811|223344556677885f5f5f5f5f5f	64	gnu	subl $0x11,(%rax)
+832811|223344556677885f5f5f5f5f5f	64	intel	sub dword ptr [rax], 0x11
+832811|223344556677885f5f5f5f5f5f	64	plan9	SUBL $0x11, 0(AX)
+833011|223344556677885f5f5f5f5f5f	32	intel	xor dword ptr [eax], 0x11
+833011|223344556677885f5f5f5f5f5f	32	plan9	XORL $0x11, 0(AX)
+833011|223344556677885f5f5f5f5f5f	64	gnu	xorl $0x11,(%rax)
+833011|223344556677885f5f5f5f5f5f	64	intel	xor dword ptr [rax], 0x11
+833011|223344556677885f5f5f5f5f5f	64	plan9	XORL $0x11, 0(AX)
+833811|223344556677885f5f5f5f5f5f	32	intel	cmp dword ptr [eax], 0x11
+833811|223344556677885f5f5f5f5f5f	32	plan9	CMPL $0x11, 0(AX)
+833811|223344556677885f5f5f5f5f5f	64	gnu	cmpl $0x11,(%rax)
+833811|223344556677885f5f5f5f5f5f	64	intel	cmp dword ptr [rax], 0x11
+833811|223344556677885f5f5f5f5f5f	64	plan9	CMPL $0x11, 0(AX)
+8411|223344556677885f5f5f5f5f5f5f	32	intel	test byte ptr [ecx], dl
+8411|223344556677885f5f5f5f5f5f5f	32	plan9	TESTB DL, 0(CX)
+8411|223344556677885f5f5f5f5f5f5f	64	gnu	test %dl,(%rcx)
+8411|223344556677885f5f5f5f5f5f5f	64	intel	test byte ptr [rcx], dl
+8411|223344556677885f5f5f5f5f5f5f	64	plan9	TESTB DL, 0(CX)
+8511|223344556677885f5f5f5f5f5f5f	32	intel	test dword ptr [ecx], edx
+8511|223344556677885f5f5f5f5f5f5f	32	plan9	TESTL DX, 0(CX)
+8511|223344556677885f5f5f5f5f5f5f	64	gnu	test %edx,(%rcx)
+8511|223344556677885f5f5f5f5f5f5f	64	intel	test dword ptr [rcx], edx
+8511|223344556677885f5f5f5f5f5f5f	64	plan9	TESTL DX, 0(CX)
+8611|223344556677885f5f5f5f5f5f5f	32	intel	xchg byte ptr [ecx], dl
+8611|223344556677885f5f5f5f5f5f5f	32	plan9	XCHGB DL, 0(CX)
+8611|223344556677885f5f5f5f5f5f5f	64	gnu	xchg %dl,(%rcx)
+8611|223344556677885f5f5f5f5f5f5f	64	intel	xchg byte ptr [rcx], dl
+8611|223344556677885f5f5f5f5f5f5f	64	plan9	XCHGB DL, 0(CX)
+8711|223344556677885f5f5f5f5f5f5f	32	intel	xchg dword ptr [ecx], edx
+8711|223344556677885f5f5f5f5f5f5f	32	plan9	XCHGL DX, 0(CX)
+8711|223344556677885f5f5f5f5f5f5f	64	gnu	xchg %edx,(%rcx)
+8711|223344556677885f5f5f5f5f5f5f	64	intel	xchg dword ptr [rcx], edx
+8711|223344556677885f5f5f5f5f5f5f	64	plan9	XCHGL DX, 0(CX)
+8811|223344556677885f5f5f5f5f5f5f	32	intel	mov byte ptr [ecx], dl
+8811|223344556677885f5f5f5f5f5f5f	32	plan9	MOVB DL, 0(CX)
+8811|223344556677885f5f5f5f5f5f5f	64	gnu	mov %dl,(%rcx)
+8811|223344556677885f5f5f5f5f5f5f	64	intel	mov byte ptr [rcx], dl
+8811|223344556677885f5f5f5f5f5f5f	64	plan9	MOVB DL, 0(CX)
+8911|223344556677885f5f5f5f5f5f5f	32	intel	mov dword ptr [ecx], edx
+8911|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL DX, 0(CX)
+8911|223344556677885f5f5f5f5f5f5f	64	gnu	mov %edx,(%rcx)
+8911|223344556677885f5f5f5f5f5f5f	64	intel	mov dword ptr [rcx], edx
+8911|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL DX, 0(CX)
+8a11|223344556677885f5f5f5f5f5f5f	32	intel	mov dl, byte ptr [ecx]
+8a11|223344556677885f5f5f5f5f5f5f	32	plan9	MOVB 0(CX), DL
+8a11|223344556677885f5f5f5f5f5f5f	64	gnu	mov (%rcx),%dl
+8a11|223344556677885f5f5f5f5f5f5f	64	intel	mov dl, byte ptr [rcx]
+8a11|223344556677885f5f5f5f5f5f5f	64	plan9	MOVB 0(CX), DL
+8b11|223344556677885f5f5f5f5f5f5f	32	intel	mov edx, dword ptr [ecx]
+8b11|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL 0(CX), DX
+8b11|223344556677885f5f5f5f5f5f5f	64	gnu	mov (%rcx),%edx
+8b11|223344556677885f5f5f5f5f5f5f	64	intel	mov edx, dword ptr [rcx]
+8b11|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL 0(CX), DX
+8c11|223344556677885f5f5f5f5f5f5f	32	intel	mov word ptr [ecx], ss
+8c11|223344556677885f5f5f5f5f5f5f	32	plan9	MOVW SS, 0(CX)
+8c11|223344556677885f5f5f5f5f5f5f	64	gnu	mov %ss,(%rcx)
+8c11|223344556677885f5f5f5f5f5f5f	64	intel	mov word ptr [rcx], ss
+8c11|223344556677885f5f5f5f5f5f5f	64	plan9	MOVW SS, 0(CX)
+8d11|223344556677885f5f5f5f5f5f5f	32	intel	lea edx, ptr [ecx]
+8d11|223344556677885f5f5f5f5f5f5f	32	plan9	LEAL 0(CX), DX
+8d11|223344556677885f5f5f5f5f5f5f	64	gnu	lea (%rcx),%edx
+8d11|223344556677885f5f5f5f5f5f5f	64	intel	lea edx, ptr [rcx]
+8d11|223344556677885f5f5f5f5f5f5f	64	plan9	LEAL 0(CX), DX
+8e11|223344556677885f5f5f5f5f5f5f	32	intel	mov ss, word ptr [ecx]
+8e11|223344556677885f5f5f5f5f5f5f	32	plan9	MOVW 0(CX), SS
+8e11|223344556677885f5f5f5f5f5f5f	64	gnu	mov (%rcx),%ss
+8e11|223344556677885f5f5f5f5f5f5f	64	intel	mov ss, word ptr [rcx]
+8e11|223344556677885f5f5f5f5f5f5f	64	plan9	MOVW 0(CX), SS
+8f00|11223344556677885f5f5f5f5f5f	32	intel	pop dword ptr [eax]
+8f00|11223344556677885f5f5f5f5f5f	32	plan9	POPL 0(AX)
+8f00|11223344556677885f5f5f5f5f5f	64	gnu	popq (%rax)
+8f00|11223344556677885f5f5f5f5f5f	64	intel	pop qword ptr [rax]
+8f00|11223344556677885f5f5f5f5f5f	64	plan9	POPQ 0(AX)
+91|11223344556677885f5f5f5f5f5f5f	32	intel	xchg ecx, eax
+91|11223344556677885f5f5f5f5f5f5f	32	plan9	XCHGL AX, CX
+91|11223344556677885f5f5f5f5f5f5f	64	intel	xchg ecx, eax
+91|11223344556677885f5f5f5f5f5f5f	64	plan9	XCHGL AX, CX
+98|11223344556677885f5f5f5f5f5f5f	32	intel	cwde
+98|11223344556677885f5f5f5f5f5f5f	32	plan9	CWDE
+98|11223344556677885f5f5f5f5f5f5f	64	gnu	cwtl
+98|11223344556677885f5f5f5f5f5f5f	64	intel	cwde
+98|11223344556677885f5f5f5f5f5f5f	64	plan9	CWDE
+99|11223344556677885f5f5f5f5f5f5f	32	intel	cdq
+99|11223344556677885f5f5f5f5f5f5f	32	plan9	CDQ
+99|11223344556677885f5f5f5f5f5f5f	64	gnu	cltd
+99|11223344556677885f5f5f5f5f5f5f	64	intel	cdq
+99|11223344556677885f5f5f5f5f5f5f	64	plan9	CDQ
+9a112233445566|77885f5f5f5f5f5f5f	32	intel	call far 0x44332211, 0x6655
+9a112233445566|77885f5f5f5f5f5f5f	32	plan9	LCALL $0x44332211, $0x6655
+9b|11223344556677885f5f5f5f5f5f5f	32	intel	fwait
+9b|11223344556677885f5f5f5f5f5f5f	32	plan9	FWAIT
+9b|11223344556677885f5f5f5f5f5f5f	64	gnu	fwait
+9b|11223344556677885f5f5f5f5f5f5f	64	intel	fwait
+9b|11223344556677885f5f5f5f5f5f5f	64	plan9	FWAIT
+9c|11223344556677885f5f5f5f5f5f5f	32	intel	pushfd
+9c|11223344556677885f5f5f5f5f5f5f	32	plan9	PUSHFD
+9c|11223344556677885f5f5f5f5f5f5f	64	gnu	pushfq
+9c|11223344556677885f5f5f5f5f5f5f	64	intel	pushfq
+9c|11223344556677885f5f5f5f5f5f5f	64	plan9	PUSHFQ
+9d|11223344556677885f5f5f5f5f5f5f	32	intel	popfd
+9d|11223344556677885f5f5f5f5f5f5f	32	plan9	POPFD
+9d|11223344556677885f5f5f5f5f5f5f	64	gnu	popfq
+9d|11223344556677885f5f5f5f5f5f5f	64	intel	popfq
+9d|11223344556677885f5f5f5f5f5f5f	64	plan9	POPFQ
+9e|11223344556677885f5f5f5f5f5f5f	32	intel	sahf
+9e|11223344556677885f5f5f5f5f5f5f	32	plan9	SAHF
+9e|11223344556677885f5f5f5f5f5f5f	64	gnu	sahf
+9e|11223344556677885f5f5f5f5f5f5f	64	intel	sahf
+9e|11223344556677885f5f5f5f5f5f5f	64	plan9	SAHF
+9f|11223344556677885f5f5f5f5f5f5f	32	intel	lahf
+9f|11223344556677885f5f5f5f5f5f5f	32	plan9	LAHF
+9f|11223344556677885f5f5f5f5f5f5f	64	gnu	lahf
+9f|11223344556677885f5f5f5f5f5f5f	64	intel	lahf
+9f|11223344556677885f5f5f5f5f5f5f	64	plan9	LAHF
+a11122334455667788|5f5f5f5f5f5f5f	64	gnu	mov -0x778899aabbccddef,%eax
+a11122334455667788|5f5f5f5f5f5f5f	64	intel	mov eax, dword ptr [0x8877665544332211]
+a11122334455667788|5f5f5f5f5f5f5f	64	plan9	MOVL -0x778899aabbccddef, AX
+a111223344|556677885f5f5f5f5f5f5f	32	intel	mov eax, dword ptr [0x44332211]
+a111223344|556677885f5f5f5f5f5f5f	32	plan9	MOVL 0x44332211, AX
+a21122334455667788|5f5f5f5f5f5f5f	64	gnu	mov %al,-0x778899aabbccddef
+a21122334455667788|5f5f5f5f5f5f5f	64	intel	mov byte ptr [0x8877665544332211], al
+a21122334455667788|5f5f5f5f5f5f5f	64	plan9	MOVB AL, -0x778899aabbccddef
+a211223344|556677885f5f5f5f5f5f5f	32	intel	mov byte ptr [0x44332211], al
+a211223344|556677885f5f5f5f5f5f5f	32	plan9	MOVB AL, 0x44332211
+a31122334455667788|5f5f5f5f5f5f5f	64	gnu	mov %eax,-0x778899aabbccddef
+a31122334455667788|5f5f5f5f5f5f5f	64	intel	mov dword ptr [0x8877665544332211], eax
+a31122334455667788|5f5f5f5f5f5f5f	64	plan9	MOVL AX, -0x778899aabbccddef
+a311223344|556677885f5f5f5f5f5f5f	32	intel	mov dword ptr [0x44332211], eax
+a311223344|556677885f5f5f5f5f5f5f	32	plan9	MOVL AX, 0x44332211
+a4|11223344556677885f5f5f5f5f5f5f	32	intel	movsb byte ptr [edi], byte ptr [esi]
+a4|11223344556677885f5f5f5f5f5f5f	32	plan9	MOVSB DS:0(SI), ES:0(DI)
+a4|11223344556677885f5f5f5f5f5f5f	64	gnu	movsb %ds:(%rsi),%es:(%rdi)
+a4|11223344556677885f5f5f5f5f5f5f	64	intel	movsb byte ptr [rdi], byte ptr [rsi]
+a4|11223344556677885f5f5f5f5f5f5f	64	plan9	MOVSB DS:0(SI), ES:0(DI)
+a5|11223344556677885f5f5f5f5f5f5f	32	intel	movsd dword ptr [edi], dword ptr [esi]
+a5|11223344556677885f5f5f5f5f5f5f	32	plan9	MOVSD DS:0(SI), ES:0(DI)
+a5|11223344556677885f5f5f5f5f5f5f	64	gnu	movsl %ds:(%rsi),%es:(%rdi)
+a5|11223344556677885f5f5f5f5f5f5f	64	intel	movsd dword ptr [rdi], dword ptr [rsi]
+a5|11223344556677885f5f5f5f5f5f5f	64	plan9	MOVSD DS:0(SI), ES:0(DI)
+a6|11223344556677885f5f5f5f5f5f5f	32	intel	cmpsb byte ptr [esi], byte ptr [edi]
+a6|11223344556677885f5f5f5f5f5f5f	32	plan9	CMPSB ES:0(DI), DS:0(SI)
+a6|11223344556677885f5f5f5f5f5f5f	64	gnu	cmpsb %es:(%rdi),%ds:(%rsi)
+a6|11223344556677885f5f5f5f5f5f5f	64	intel	cmpsb byte ptr [rsi], byte ptr [rdi]
+a6|11223344556677885f5f5f5f5f5f5f	64	plan9	CMPSB ES:0(DI), DS:0(SI)
+a7|11223344556677885f5f5f5f5f5f5f	32	intel	cmpsd dword ptr [esi], dword ptr [edi]
+a7|11223344556677885f5f5f5f5f5f5f	32	plan9	CMPSD ES:0(DI), DS:0(SI)
+a7|11223344556677885f5f5f5f5f5f5f	64	gnu	cmpsl %es:(%rdi),%ds:(%rsi)
+a7|11223344556677885f5f5f5f5f5f5f	64	intel	cmpsd dword ptr [rsi], dword ptr [rdi]
+a7|11223344556677885f5f5f5f5f5f5f	64	plan9	CMPSD ES:0(DI), DS:0(SI)
+a811|223344556677885f5f5f5f5f5f5f	32	intel	test al, 0x11
+a811|223344556677885f5f5f5f5f5f5f	32	plan9	TESTL $0x11, AL
+a811|223344556677885f5f5f5f5f5f5f	64	gnu	test $0x11,%al
+a811|223344556677885f5f5f5f5f5f5f	64	intel	test al, 0x11
+a811|223344556677885f5f5f5f5f5f5f	64	plan9	TESTL $0x11, AL
+a911223344|556677885f5f5f5f5f5f5f	32	intel	test eax, 0x44332211
+a911223344|556677885f5f5f5f5f5f5f	32	plan9	TESTL $0x44332211, AX
+a911223344|556677885f5f5f5f5f5f5f	64	gnu	test $0x44332211,%eax
+a911223344|556677885f5f5f5f5f5f5f	64	intel	test eax, 0x44332211
+a911223344|556677885f5f5f5f5f5f5f	64	plan9	TESTL $0x44332211, AX
+aa|11223344556677885f5f5f5f5f5f5f	32	intel	stosb byte ptr [edi]
+aa|11223344556677885f5f5f5f5f5f5f	32	plan9	STOSB AL, ES:0(DI)
+aa|11223344556677885f5f5f5f5f5f5f	64	gnu	stos %al,%es:(%rdi)
+aa|11223344556677885f5f5f5f5f5f5f	64	intel	stosb byte ptr [rdi]
+aa|11223344556677885f5f5f5f5f5f5f	64	plan9	STOSB AL, ES:0(DI)
+ab|11223344556677885f5f5f5f5f5f5f	32	intel	stosd dword ptr [edi]
+ab|11223344556677885f5f5f5f5f5f5f	32	plan9	STOSD AX, ES:0(DI)
+ab|11223344556677885f5f5f5f5f5f5f	64	gnu	stos %eax,%es:(%rdi)
+ab|11223344556677885f5f5f5f5f5f5f	64	intel	stosd dword ptr [rdi]
+ab|11223344556677885f5f5f5f5f5f5f	64	plan9	STOSD AX, ES:0(DI)
+ac|11223344556677885f5f5f5f5f5f5f	32	intel	lodsb byte ptr [esi]
+ac|11223344556677885f5f5f5f5f5f5f	32	plan9	LODSB DS:0(SI), AL
+ac|11223344556677885f5f5f5f5f5f5f	64	gnu	lods %ds:(%rsi),%al
+ac|11223344556677885f5f5f5f5f5f5f	64	intel	lodsb byte ptr [rsi]
+ac|11223344556677885f5f5f5f5f5f5f	64	plan9	LODSB DS:0(SI), AL
+ad|11223344556677885f5f5f5f5f5f5f	32	intel	lodsd dword ptr [esi]
+ad|11223344556677885f5f5f5f5f5f5f	32	plan9	LODSD DS:0(SI), AX
+ad|11223344556677885f5f5f5f5f5f5f	64	gnu	lods %ds:(%rsi),%eax
+ad|11223344556677885f5f5f5f5f5f5f	64	intel	lodsd dword ptr [rsi]
+ad|11223344556677885f5f5f5f5f5f5f	64	plan9	LODSD DS:0(SI), AX
+ae|11223344556677885f5f5f5f5f5f5f	32	intel	scasb byte ptr [edi]
+ae|11223344556677885f5f5f5f5f5f5f	32	plan9	SCASB ES:0(DI), AL
+ae|11223344556677885f5f5f5f5f5f5f	64	gnu	scas %es:(%rdi),%al
+ae|11223344556677885f5f5f5f5f5f5f	64	intel	scasb byte ptr [rdi]
+ae|11223344556677885f5f5f5f5f5f5f	64	plan9	SCASB ES:0(DI), AL
+af|11223344556677885f5f5f5f5f5f5f	32	intel	scasd dword ptr [edi]
+af|11223344556677885f5f5f5f5f5f5f	32	plan9	SCASD ES:0(DI), AX
+af|11223344556677885f5f5f5f5f5f5f	64	gnu	scas %es:(%rdi),%eax
+af|11223344556677885f5f5f5f5f5f5f	64	intel	scasd dword ptr [rdi]
+af|11223344556677885f5f5f5f5f5f5f	64	plan9	SCASD ES:0(DI), AX
+b011|223344556677885f5f5f5f5f5f5f	32	intel	mov al, 0x11
+b011|223344556677885f5f5f5f5f5f5f	32	plan9	MOVL $0x11, AL
+b011|223344556677885f5f5f5f5f5f5f	64	gnu	mov $0x11,%al
+b011|223344556677885f5f5f5f5f5f5f	64	intel	mov al, 0x11
+b011|223344556677885f5f5f5f5f5f5f	64	plan9	MOVL $0x11, AL
+b811223344|556677885f5f5f5f5f5f5f	32	intel	mov eax, 0x44332211
+b811223344|556677885f5f5f5f5f5f5f	32	plan9	MOVL $0x44332211, AX
+b811223344|556677885f5f5f5f5f5f5f	64	gnu	mov $0x44332211,%eax
+b811223344|556677885f5f5f5f5f5f5f	64	intel	mov eax, 0x44332211
+b811223344|556677885f5f5f5f5f5f5f	64	plan9	MOVL $0x44332211, AX
+c00011|223344556677885f5f5f5f5f5f	32	intel	rol byte ptr [eax], 0x11
+c00011|223344556677885f5f5f5f5f5f	32	plan9	ROLB $0x11, 0(AX)
+c00011|223344556677885f5f5f5f5f5f	64	gnu	rolb $0x11,(%rax)
+c00011|223344556677885f5f5f5f5f5f	64	intel	rol byte ptr [rax], 0x11
+c00011|223344556677885f5f5f5f5f5f	64	plan9	ROLB $0x11, 0(AX)
+c00811|223344556677885f5f5f5f5f5f	32	intel	ror byte ptr [eax], 0x11
+c00811|223344556677885f5f5f5f5f5f	32	plan9	RORB $0x11, 0(AX)
+c00811|223344556677885f5f5f5f5f5f	64	gnu	rorb $0x11,(%rax)
+c00811|223344556677885f5f5f5f5f5f	64	intel	ror byte ptr [rax], 0x11
+c00811|223344556677885f5f5f5f5f5f	64	plan9	RORB $0x11, 0(AX)
+c01122|3344556677885f5f5f5f5f5f5f	32	intel	rcl byte ptr [ecx], 0x22
+c01122|3344556677885f5f5f5f5f5f5f	32	plan9	RCLB $0x22, 0(CX)
+c01122|3344556677885f5f5f5f5f5f5f	64	gnu	rclb $0x22,(%rcx)
+c01122|3344556677885f5f5f5f5f5f5f	64	intel	rcl byte ptr [rcx], 0x22
+c01122|3344556677885f5f5f5f5f5f5f	64	plan9	RCLB $0x22, 0(CX)
+c01811|223344556677885f5f5f5f5f5f	32	intel	rcr byte ptr [eax], 0x11
+c01811|223344556677885f5f5f5f5f5f	32	plan9	RCRB $0x11, 0(AX)
+c01811|223344556677885f5f5f5f5f5f	64	gnu	rcrb $0x11,(%rax)
+c01811|223344556677885f5f5f5f5f5f	64	intel	rcr byte ptr [rax], 0x11
+c01811|223344556677885f5f5f5f5f5f	64	plan9	RCRB $0x11, 0(AX)
+c02011|223344556677885f5f5f5f5f5f	32	intel	shl byte ptr [eax], 0x11
+c02011|223344556677885f5f5f5f5f5f	32	plan9	SHLB $0x11, 0(AX)
+c02011|223344556677885f5f5f5f5f5f	64	gnu	shlb $0x11,(%rax)
+c02011|223344556677885f5f5f5f5f5f	64	intel	shl byte ptr [rax], 0x11
+c02011|223344556677885f5f5f5f5f5f	64	plan9	SHLB $0x11, 0(AX)
+c02811|223344556677885f5f5f5f5f5f	32	intel	shr byte ptr [eax], 0x11
+c02811|223344556677885f5f5f5f5f5f	32	plan9	SHRB $0x11, 0(AX)
+c02811|223344556677885f5f5f5f5f5f	64	gnu	shrb $0x11,(%rax)
+c02811|223344556677885f5f5f5f5f5f	64	intel	shr byte ptr [rax], 0x11
+c02811|223344556677885f5f5f5f5f5f	64	plan9	SHRB $0x11, 0(AX)
+c03811|223344556677885f5f5f5f5f5f	32	intel	sar byte ptr [eax], 0x11
+c03811|223344556677885f5f5f5f5f5f	32	plan9	SARB $0x11, 0(AX)
+c03811|223344556677885f5f5f5f5f5f	64	gnu	sarb $0x11,(%rax)
+c03811|223344556677885f5f5f5f5f5f	64	intel	sar byte ptr [rax], 0x11
+c03811|223344556677885f5f5f5f5f5f	64	plan9	SARB $0x11, 0(AX)
+c10011|223344556677885f5f5f5f5f5f	32	intel	rol dword ptr [eax], 0x11
+c10011|223344556677885f5f5f5f5f5f	32	plan9	ROLL $0x11, 0(AX)
+c10011|223344556677885f5f5f5f5f5f	64	gnu	roll $0x11,(%rax)
+c10011|223344556677885f5f5f5f5f5f	64	intel	rol dword ptr [rax], 0x11
+c10011|223344556677885f5f5f5f5f5f	64	plan9	ROLL $0x11, 0(AX)
+c10811|223344556677885f5f5f5f5f5f	32	intel	ror dword ptr [eax], 0x11
+c10811|223344556677885f5f5f5f5f5f	32	plan9	RORL $0x11, 0(AX)
+c10811|223344556677885f5f5f5f5f5f	64	gnu	rorl $0x11,(%rax)
+c10811|223344556677885f5f5f5f5f5f	64	intel	ror dword ptr [rax], 0x11
+c10811|223344556677885f5f5f5f5f5f	64	plan9	RORL $0x11, 0(AX)
+c11122|3344556677885f5f5f5f5f5f5f	32	intel	rcl dword ptr [ecx], 0x22
+c11122|3344556677885f5f5f5f5f5f5f	32	plan9	RCLL $0x22, 0(CX)
+c11122|3344556677885f5f5f5f5f5f5f	64	gnu	rcll $0x22,(%rcx)
+c11122|3344556677885f5f5f5f5f5f5f	64	intel	rcl dword ptr [rcx], 0x22
+c11122|3344556677885f5f5f5f5f5f5f	64	plan9	RCLL $0x22, 0(CX)
+c11811|223344556677885f5f5f5f5f5f	32	intel	rcr dword ptr [eax], 0x11
+c11811|223344556677885f5f5f5f5f5f	32	plan9	RCRL $0x11, 0(AX)
+c11811|223344556677885f5f5f5f5f5f	64	gnu	rcrl $0x11,(%rax)
+c11811|223344556677885f5f5f5f5f5f	64	intel	rcr dword ptr [rax], 0x11
+c11811|223344556677885f5f5f5f5f5f	64	plan9	RCRL $0x11, 0(AX)
+c12011|223344556677885f5f5f5f5f5f	32	intel	shl dword ptr [eax], 0x11
+c12011|223344556677885f5f5f5f5f5f	32	plan9	SHLL $0x11, 0(AX)
+c12011|223344556677885f5f5f5f5f5f	64	gnu	shll $0x11,(%rax)
+c12011|223344556677885f5f5f5f5f5f	64	intel	shl dword ptr [rax], 0x11
+c12011|223344556677885f5f5f5f5f5f	64	plan9	SHLL $0x11, 0(AX)
+c12811|223344556677885f5f5f5f5f5f	32	intel	shr dword ptr [eax], 0x11
+c12811|223344556677885f5f5f5f5f5f	32	plan9	SHRL $0x11, 0(AX)
+c12811|223344556677885f5f5f5f5f5f	64	gnu	shrl $0x11,(%rax)
+c12811|223344556677885f5f5f5f5f5f	64	intel	shr dword ptr [rax], 0x11
+c12811|223344556677885f5f5f5f5f5f	64	plan9	SHRL $0x11, 0(AX)
+c13811|223344556677885f5f5f5f5f5f	32	intel	sar dword ptr [eax], 0x11
+c13811|223344556677885f5f5f5f5f5f	32	plan9	SARL $0x11, 0(AX)
+c13811|223344556677885f5f5f5f5f5f	64	gnu	sarl $0x11,(%rax)
+c13811|223344556677885f5f5f5f5f5f	64	intel	sar dword ptr [rax], 0x11
+c13811|223344556677885f5f5f5f5f5f	64	plan9	SARL $0x11, 0(AX)
+c3|11223344556677885f5f5f5f5f5f5f	32	intel	ret
+c3|11223344556677885f5f5f5f5f5f5f	32	plan9	RET
+c3|11223344556677885f5f5f5f5f5f5f	64	gnu	retq
+c3|11223344556677885f5f5f5f5f5f5f	64	intel	ret
+c3|11223344556677885f5f5f5f5f5f5f	64	plan9	RET
+c411|223344556677885f5f5f5f5f5f5f	32	intel	les edx, ptr [ecx]
+c411|223344556677885f5f5f5f5f5f5f	32	plan9	LES 0(CX), DX
+c511|223344556677885f5f5f5f5f5f5f	32	intel	lds edx, ptr [ecx]
+c511|223344556677885f5f5f5f5f5f5f	32	plan9	LDS 0(CX), DX
+c60011|223344556677885f5f5f5f5f5f	32	intel	mov byte ptr [eax], 0x11
+c60011|223344556677885f5f5f5f5f5f	32	plan9	MOVB $0x11, 0(AX)
+c60011|223344556677885f5f5f5f5f5f	64	gnu	movb $0x11,(%rax)
+c60011|223344556677885f5f5f5f5f5f	64	intel	mov byte ptr [rax], 0x11
+c60011|223344556677885f5f5f5f5f5f	64	plan9	MOVB $0x11, 0(AX)
+c6f811|223344556677885f5f5f5f5f5f	32	intel	xabort 0x11
+c6f811|223344556677885f5f5f5f5f5f	32	plan9	XABORT $0x11
+c6f811|223344556677885f5f5f5f5f5f	64	gnu	xabort $0x11
+c6f811|223344556677885f5f5f5f5f5f	64	intel	xabort 0x11
+c6f811|223344556677885f5f5f5f5f5f	64	plan9	XABORT $0x11
+c70011223344|556677885f5f5f5f5f5f	32	intel	mov dword ptr [eax], 0x44332211
+c70011223344|556677885f5f5f5f5f5f	32	plan9	MOVL $0x44332211, 0(AX)
+c70011223344|556677885f5f5f5f5f5f	64	gnu	movl $0x44332211,(%rax)
+c70011223344|556677885f5f5f5f5f5f	64	intel	mov dword ptr [rax], 0x44332211
+c70011223344|556677885f5f5f5f5f5f	64	plan9	MOVL $0x44332211, 0(AX)
+c7f811223344|556677885f5f5f5f5f5f	32	intel	xbegin .+0x44332211
+c7f811223344|556677885f5f5f5f5f5f	32	plan9	XBEGIN .+1144201745
+c7f811223344|556677885f5f5f5f5f5f	64	gnu	xbeginq .+0x44332211
+c7f811223344|556677885f5f5f5f5f5f	64	intel	xbegin .+0x44332211
+c7f811223344|556677885f5f5f5f5f5f	64	plan9	XBEGIN .+1144201745
+c8112233|44556677885f5f5f5f5f5f5f	32	intel	enter 0x2211, 0x33
+c8112233|44556677885f5f5f5f5f5f5f	32	plan9	ENTER $0x33, $0x2211
+c8112233|44556677885f5f5f5f5f5f5f	64	gnu	enterq $0x2211,$0x33
+c8112233|44556677885f5f5f5f5f5f5f	64	intel	enter 0x2211, 0x33
+c8112233|44556677885f5f5f5f5f5f5f	64	plan9	ENTER $0x33, $0x2211
+c9|11223344556677885f5f5f5f5f5f5f	32	intel	leave
+c9|11223344556677885f5f5f5f5f5f5f	32	plan9	LEAVE
+c9|11223344556677885f5f5f5f5f5f5f	64	gnu	leaveq
+c9|11223344556677885f5f5f5f5f5f5f	64	intel	leave
+c9|11223344556677885f5f5f5f5f5f5f	64	plan9	LEAVE
+ca1122|3344556677885f5f5f5f5f5f5f	32	intel	ret far 0x2211
+ca1122|3344556677885f5f5f5f5f5f5f	32	plan9	LRET $0x2211
+ca1122|3344556677885f5f5f5f5f5f5f	64	gnu	lretq $0x2211
+ca1122|3344556677885f5f5f5f5f5f5f	64	intel	ret far 0x2211
+ca1122|3344556677885f5f5f5f5f5f5f	64	plan9	LRET $0x2211
+cb|11223344556677885f5f5f5f5f5f5f	32	intel	ret far
+cb|11223344556677885f5f5f5f5f5f5f	32	plan9	LRET
+cb|11223344556677885f5f5f5f5f5f5f	64	gnu	lretq
+cb|11223344556677885f5f5f5f5f5f5f	64	intel	ret far
+cb|11223344556677885f5f5f5f5f5f5f	64	plan9	LRET
+cc|11223344556677885f5f5f5f5f5f5f	32	intel	int3
+cc|11223344556677885f5f5f5f5f5f5f	32	plan9	INT $0x3
+cc|11223344556677885f5f5f5f5f5f5f	64	gnu	int3
+cc|11223344556677885f5f5f5f5f5f5f	64	intel	int3
+cc|11223344556677885f5f5f5f5f5f5f	64	plan9	INT $0x3
+cd11|223344556677885f5f5f5f5f5f5f	32	intel	int 0x11
+cd11|223344556677885f5f5f5f5f5f5f	32	plan9	INT $0x11
+cd11|223344556677885f5f5f5f5f5f5f	64	gnu	int $0x11
+cd11|223344556677885f5f5f5f5f5f5f	64	intel	int 0x11
+cd11|223344556677885f5f5f5f5f5f5f	64	plan9	INT $0x11
+ce|11223344556677885f5f5f5f5f5f5f	32	intel	into
+ce|11223344556677885f5f5f5f5f5f5f	32	plan9	INTO
+ce|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+ce|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+ce|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+cf|11223344556677885f5f5f5f5f5f5f	32	intel	iretd
+cf|11223344556677885f5f5f5f5f5f5f	32	plan9	IRETD
+cf|11223344556677885f5f5f5f5f5f5f	64	gnu	iret
+cf|11223344556677885f5f5f5f5f5f5f	64	intel	iretd
+cf|11223344556677885f5f5f5f5f5f5f	64	plan9	IRETD
+d000|11223344556677885f5f5f5f5f5f	32	intel	rol byte ptr [eax], 0x1
+d000|11223344556677885f5f5f5f5f5f	32	plan9	ROLB $0x1, 0(AX)
+d000|11223344556677885f5f5f5f5f5f	64	gnu	rolb (%rax)
+d000|11223344556677885f5f5f5f5f5f	64	intel	rol byte ptr [rax], 0x1
+d000|11223344556677885f5f5f5f5f5f	64	plan9	ROLB $0x1, 0(AX)
+d008|11223344556677885f5f5f5f5f5f	32	intel	ror byte ptr [eax], 0x1
+d008|11223344556677885f5f5f5f5f5f	32	plan9	RORB $0x1, 0(AX)
+d008|11223344556677885f5f5f5f5f5f	64	gnu	rorb (%rax)
+d008|11223344556677885f5f5f5f5f5f	64	intel	ror byte ptr [rax], 0x1
+d008|11223344556677885f5f5f5f5f5f	64	plan9	RORB $0x1, 0(AX)
+d011|223344556677885f5f5f5f5f5f5f	32	intel	rcl byte ptr [ecx], 0x1
+d011|223344556677885f5f5f5f5f5f5f	32	plan9	RCLB $0x1, 0(CX)
+d011|223344556677885f5f5f5f5f5f5f	64	gnu	rclb (%rcx)
+d011|223344556677885f5f5f5f5f5f5f	64	intel	rcl byte ptr [rcx], 0x1
+d011|223344556677885f5f5f5f5f5f5f	64	plan9	RCLB $0x1, 0(CX)
+d018|11223344556677885f5f5f5f5f5f	32	intel	rcr byte ptr [eax], 0x1
+d018|11223344556677885f5f5f5f5f5f	32	plan9	RCRB $0x1, 0(AX)
+d018|11223344556677885f5f5f5f5f5f	64	gnu	rcrb (%rax)
+d018|11223344556677885f5f5f5f5f5f	64	intel	rcr byte ptr [rax], 0x1
+d018|11223344556677885f5f5f5f5f5f	64	plan9	RCRB $0x1, 0(AX)
+d020|11223344556677885f5f5f5f5f5f	32	intel	shl byte ptr [eax], 0x1
+d020|11223344556677885f5f5f5f5f5f	32	plan9	SHLB $0x1, 0(AX)
+d020|11223344556677885f5f5f5f5f5f	64	gnu	shlb (%rax)
+d020|11223344556677885f5f5f5f5f5f	64	intel	shl byte ptr [rax], 0x1
+d020|11223344556677885f5f5f5f5f5f	64	plan9	SHLB $0x1, 0(AX)
+d028|11223344556677885f5f5f5f5f5f	32	intel	shr byte ptr [eax], 0x1
+d028|11223344556677885f5f5f5f5f5f	32	plan9	SHRB $0x1, 0(AX)
+d028|11223344556677885f5f5f5f5f5f	64	gnu	shrb (%rax)
+d028|11223344556677885f5f5f5f5f5f	64	intel	shr byte ptr [rax], 0x1
+d028|11223344556677885f5f5f5f5f5f	64	plan9	SHRB $0x1, 0(AX)
+d038|11223344556677885f5f5f5f5f5f	32	intel	sar byte ptr [eax], 0x1
+d038|11223344556677885f5f5f5f5f5f	32	plan9	SARB $0x1, 0(AX)
+d038|11223344556677885f5f5f5f5f5f	64	gnu	sarb (%rax)
+d038|11223344556677885f5f5f5f5f5f	64	intel	sar byte ptr [rax], 0x1
+d038|11223344556677885f5f5f5f5f5f	64	plan9	SARB $0x1, 0(AX)
+d100|11223344556677885f5f5f5f5f5f	32	intel	rol dword ptr [eax], 0x1
+d100|11223344556677885f5f5f5f5f5f	32	plan9	ROLL $0x1, 0(AX)
+d100|11223344556677885f5f5f5f5f5f	64	gnu	roll (%rax)
+d100|11223344556677885f5f5f5f5f5f	64	intel	rol dword ptr [rax], 0x1
+d100|11223344556677885f5f5f5f5f5f	64	plan9	ROLL $0x1, 0(AX)
+d108|11223344556677885f5f5f5f5f5f	32	intel	ror dword ptr [eax], 0x1
+d108|11223344556677885f5f5f5f5f5f	32	plan9	RORL $0x1, 0(AX)
+d108|11223344556677885f5f5f5f5f5f	64	gnu	rorl (%rax)
+d108|11223344556677885f5f5f5f5f5f	64	intel	ror dword ptr [rax], 0x1
+d108|11223344556677885f5f5f5f5f5f	64	plan9	RORL $0x1, 0(AX)
+d111|223344556677885f5f5f5f5f5f5f	32	intel	rcl dword ptr [ecx], 0x1
+d111|223344556677885f5f5f5f5f5f5f	32	plan9	RCLL $0x1, 0(CX)
+d111|223344556677885f5f5f5f5f5f5f	64	gnu	rcll (%rcx)
+d111|223344556677885f5f5f5f5f5f5f	64	intel	rcl dword ptr [rcx], 0x1
+d111|223344556677885f5f5f5f5f5f5f	64	plan9	RCLL $0x1, 0(CX)
+d118|11223344556677885f5f5f5f5f5f	32	intel	rcr dword ptr [eax], 0x1
+d118|11223344556677885f5f5f5f5f5f	32	plan9	RCRL $0x1, 0(AX)
+d118|11223344556677885f5f5f5f5f5f	64	gnu	rcrl (%rax)
+d118|11223344556677885f5f5f5f5f5f	64	intel	rcr dword ptr [rax], 0x1
+d118|11223344556677885f5f5f5f5f5f	64	plan9	RCRL $0x1, 0(AX)
+d120|11223344556677885f5f5f5f5f5f	32	intel	shl dword ptr [eax], 0x1
+d120|11223344556677885f5f5f5f5f5f	32	plan9	SHLL $0x1, 0(AX)
+d120|11223344556677885f5f5f5f5f5f	64	gnu	shll (%rax)
+d120|11223344556677885f5f5f5f5f5f	64	intel	shl dword ptr [rax], 0x1
+d120|11223344556677885f5f5f5f5f5f	64	plan9	SHLL $0x1, 0(AX)
+d128|11223344556677885f5f5f5f5f5f	32	intel	shr dword ptr [eax], 0x1
+d128|11223344556677885f5f5f5f5f5f	32	plan9	SHRL $0x1, 0(AX)
+d128|11223344556677885f5f5f5f5f5f	64	gnu	shrl (%rax)
+d128|11223344556677885f5f5f5f5f5f	64	intel	shr dword ptr [rax], 0x1
+d128|11223344556677885f5f5f5f5f5f	64	plan9	SHRL $0x1, 0(AX)
+d138|11223344556677885f5f5f5f5f5f	32	intel	sar dword ptr [eax], 0x1
+d138|11223344556677885f5f5f5f5f5f	32	plan9	SARL $0x1, 0(AX)
+d138|11223344556677885f5f5f5f5f5f	64	gnu	sarl (%rax)
+d138|11223344556677885f5f5f5f5f5f	64	intel	sar dword ptr [rax], 0x1
+d138|11223344556677885f5f5f5f5f5f	64	plan9	SARL $0x1, 0(AX)
+d200|11223344556677885f5f5f5f5f5f	32	intel	rol byte ptr [eax], cl
+d200|11223344556677885f5f5f5f5f5f	32	plan9	ROLB CL, 0(AX)
+d200|11223344556677885f5f5f5f5f5f	64	gnu	rolb %cl,(%rax)
+d200|11223344556677885f5f5f5f5f5f	64	intel	rol byte ptr [rax], cl
+d200|11223344556677885f5f5f5f5f5f	64	plan9	ROLB CL, 0(AX)
+d208|11223344556677885f5f5f5f5f5f	32	intel	ror byte ptr [eax], cl
+d208|11223344556677885f5f5f5f5f5f	32	plan9	RORB CL, 0(AX)
+d208|11223344556677885f5f5f5f5f5f	64	gnu	rorb %cl,(%rax)
+d208|11223344556677885f5f5f5f5f5f	64	intel	ror byte ptr [rax], cl
+d208|11223344556677885f5f5f5f5f5f	64	plan9	RORB CL, 0(AX)
+d211|223344556677885f5f5f5f5f5f5f	32	intel	rcl byte ptr [ecx], cl
+d211|223344556677885f5f5f5f5f5f5f	32	plan9	RCLB CL, 0(CX)
+d211|223344556677885f5f5f5f5f5f5f	64	gnu	rclb %cl,(%rcx)
+d211|223344556677885f5f5f5f5f5f5f	64	intel	rcl byte ptr [rcx], cl
+d211|223344556677885f5f5f5f5f5f5f	64	plan9	RCLB CL, 0(CX)
+d218|11223344556677885f5f5f5f5f5f	32	intel	rcr byte ptr [eax], cl
+d218|11223344556677885f5f5f5f5f5f	32	plan9	RCRB CL, 0(AX)
+d218|11223344556677885f5f5f5f5f5f	64	gnu	rcrb %cl,(%rax)
+d218|11223344556677885f5f5f5f5f5f	64	intel	rcr byte ptr [rax], cl
+d218|11223344556677885f5f5f5f5f5f	64	plan9	RCRB CL, 0(AX)
+d220|11223344556677885f5f5f5f5f5f	32	intel	shl byte ptr [eax], cl
+d220|11223344556677885f5f5f5f5f5f	32	plan9	SHLB CL, 0(AX)
+d220|11223344556677885f5f5f5f5f5f	64	gnu	shlb %cl,(%rax)
+d220|11223344556677885f5f5f5f5f5f	64	intel	shl byte ptr [rax], cl
+d220|11223344556677885f5f5f5f5f5f	64	plan9	SHLB CL, 0(AX)
+d228|11223344556677885f5f5f5f5f5f	32	intel	shr byte ptr [eax], cl
+d228|11223344556677885f5f5f5f5f5f	32	plan9	SHRB CL, 0(AX)
+d228|11223344556677885f5f5f5f5f5f	64	gnu	shrb %cl,(%rax)
+d228|11223344556677885f5f5f5f5f5f	64	intel	shr byte ptr [rax], cl
+d228|11223344556677885f5f5f5f5f5f	64	plan9	SHRB CL, 0(AX)
+d238|11223344556677885f5f5f5f5f5f	32	intel	sar byte ptr [eax], cl
+d238|11223344556677885f5f5f5f5f5f	32	plan9	SARB CL, 0(AX)
+d238|11223344556677885f5f5f5f5f5f	64	gnu	sarb %cl,(%rax)
+d238|11223344556677885f5f5f5f5f5f	64	intel	sar byte ptr [rax], cl
+d238|11223344556677885f5f5f5f5f5f	64	plan9	SARB CL, 0(AX)
+d300|11223344556677885f5f5f5f5f5f	32	intel	rol dword ptr [eax], cl
+d300|11223344556677885f5f5f5f5f5f	32	plan9	ROLL CL, 0(AX)
+d300|11223344556677885f5f5f5f5f5f	64	gnu	roll %cl,(%rax)
+d300|11223344556677885f5f5f5f5f5f	64	intel	rol dword ptr [rax], cl
+d300|11223344556677885f5f5f5f5f5f	64	plan9	ROLL CL, 0(AX)
+d308|11223344556677885f5f5f5f5f5f	32	intel	ror dword ptr [eax], cl
+d308|11223344556677885f5f5f5f5f5f	32	plan9	RORL CL, 0(AX)
+d308|11223344556677885f5f5f5f5f5f	64	gnu	rorl %cl,(%rax)
+d308|11223344556677885f5f5f5f5f5f	64	intel	ror dword ptr [rax], cl
+d308|11223344556677885f5f5f5f5f5f	64	plan9	RORL CL, 0(AX)
+d311|223344556677885f5f5f5f5f5f5f	32	intel	rcl dword ptr [ecx], cl
+d311|223344556677885f5f5f5f5f5f5f	32	plan9	RCLL CL, 0(CX)
+d311|223344556677885f5f5f5f5f5f5f	64	gnu	rcll %cl,(%rcx)
+d311|223344556677885f5f5f5f5f5f5f	64	intel	rcl dword ptr [rcx], cl
+d311|223344556677885f5f5f5f5f5f5f	64	plan9	RCLL CL, 0(CX)
+d318|11223344556677885f5f5f5f5f5f	32	intel	rcr dword ptr [eax], cl
+d318|11223344556677885f5f5f5f5f5f	32	plan9	RCRL CL, 0(AX)
+d318|11223344556677885f5f5f5f5f5f	64	gnu	rcrl %cl,(%rax)
+d318|11223344556677885f5f5f5f5f5f	64	intel	rcr dword ptr [rax], cl
+d318|11223344556677885f5f5f5f5f5f	64	plan9	RCRL CL, 0(AX)
+d320|11223344556677885f5f5f5f5f5f	32	intel	shl dword ptr [eax], cl
+d320|11223344556677885f5f5f5f5f5f	32	plan9	SHLL CL, 0(AX)
+d320|11223344556677885f5f5f5f5f5f	64	gnu	shll %cl,(%rax)
+d320|11223344556677885f5f5f5f5f5f	64	intel	shl dword ptr [rax], cl
+d320|11223344556677885f5f5f5f5f5f	64	plan9	SHLL CL, 0(AX)
+d328|11223344556677885f5f5f5f5f5f	32	intel	shr dword ptr [eax], cl
+d328|11223344556677885f5f5f5f5f5f	32	plan9	SHRL CL, 0(AX)
+d328|11223344556677885f5f5f5f5f5f	64	gnu	shrl %cl,(%rax)
+d328|11223344556677885f5f5f5f5f5f	64	intel	shr dword ptr [rax], cl
+d328|11223344556677885f5f5f5f5f5f	64	plan9	SHRL CL, 0(AX)
+d338|11223344556677885f5f5f5f5f5f	32	intel	sar dword ptr [eax], cl
+d338|11223344556677885f5f5f5f5f5f	32	plan9	SARL CL, 0(AX)
+d338|11223344556677885f5f5f5f5f5f	64	gnu	sarl %cl,(%rax)
+d338|11223344556677885f5f5f5f5f5f	64	intel	sar dword ptr [rax], cl
+d338|11223344556677885f5f5f5f5f5f	64	plan9	SARL CL, 0(AX)
+d511|223344556677885f5f5f5f5f5f5f	32	intel	aad 0x11
+d511|223344556677885f5f5f5f5f5f5f	32	plan9	AAD $0x11
+d5|11223344556677885f5f5f5f5f5f5f	64	gnu	error: unrecognized instruction
+d5|11223344556677885f5f5f5f5f5f5f	64	intel	error: unrecognized instruction
+d5|11223344556677885f5f5f5f5f5f5f	64	plan9	error: unrecognized instruction
+d800|11223344556677885f5f5f5f5f5f	32	intel	fadd st0, dword ptr [eax]
+d800|11223344556677885f5f5f5f5f5f	32	plan9	FADD 0(AX)
+d800|11223344556677885f5f5f5f5f5f	64	gnu	fadds (%rax)
+d800|11223344556677885f5f5f5f5f5f	64	intel	fadd st0, dword ptr [rax]
+d800|11223344556677885f5f5f5f5f5f	64	plan9	FADD 0(AX)
+d808|11223344556677885f5f5f5f5f5f	32	intel	fmul st0, dword ptr [eax]
+d808|11223344556677885f5f5f5f5f5f	32	plan9	FMUL 0(AX)
+d808|11223344556677885f5f5f5f5f5f	64	gnu	fmuls (%rax)
+d808|11223344556677885f5f5f5f5f5f	64	intel	fmul st0, dword ptr [rax]
+d808|11223344556677885f5f5f5f5f5f	64	plan9	FMUL 0(AX)
+d811|223344556677885f5f5f5f5f5f5f	32	intel	fcom st0, dword ptr [ecx]
+d811|223344556677885f5f5f5f5f5f5f	32	plan9	FCOM 0(CX)
+d811|223344556677885f5f5f5f5f5f5f	64	gnu	fcoms (%rcx)
+d811|223344556677885f5f5f5f5f5f5f	64	intel	fcom st0, dword ptr [rcx]
+d811|223344556677885f5f5f5f5f5f5f	64	plan9	FCOM 0(CX)
+d818|11223344556677885f5f5f5f5f5f	32	intel	fcomp st0, dword ptr [eax]
+d818|11223344556677885f5f5f5f5f5f	32	plan9	FCOMP 0(AX)
+d818|11223344556677885f5f5f5f5f5f	64	gnu	fcomps (%rax)
+d818|11223344556677885f5f5f5f5f5f	64	intel	fcomp st0, dword ptr [rax]
+d818|11223344556677885f5f5f5f5f5f	64	plan9	FCOMP 0(AX)
+d820|11223344556677885f5f5f5f5f5f	32	intel	fsub st0, dword ptr [eax]
+d820|11223344556677885f5f5f5f5f5f	32	plan9	FSUB 0(AX)
+d820|11223344556677885f5f5f5f5f5f	64	gnu	fsubs (%rax)
+d820|11223344556677885f5f5f5f5f5f	64	intel	fsub st0, dword ptr [rax]
+d820|11223344556677885f5f5f5f5f5f	64	plan9	FSUB 0(AX)
+d828|11223344556677885f5f5f5f5f5f	32	intel	fsubr st0, dword ptr [eax]
+d828|11223344556677885f5f5f5f5f5f	32	plan9	FSUBR 0(AX)
+d828|11223344556677885f5f5f5f5f5f	64	gnu	fsubrs (%rax)
+d828|11223344556677885f5f5f5f5f5f	64	intel	fsubr st0, dword ptr [rax]
+d828|11223344556677885f5f5f5f5f5f	64	plan9	FSUBR 0(AX)
+d830|11223344556677885f5f5f5f5f5f	32	intel	fdiv st0, dword ptr [eax]
+d830|11223344556677885f5f5f5f5f5f	32	plan9	FDIV 0(AX)
+d830|11223344556677885f5f5f5f5f5f	64	gnu	fdivs (%rax)
+d830|11223344556677885f5f5f5f5f5f	64	intel	fdiv st0, dword ptr [rax]
+d830|11223344556677885f5f5f5f5f5f	64	plan9	FDIV 0(AX)
+d838|11223344556677885f5f5f5f5f5f	32	intel	fdivr st0, dword ptr [eax]
+d838|11223344556677885f5f5f5f5f5f	32	plan9	FDIVR 0(AX)
+d838|11223344556677885f5f5f5f5f5f	64	gnu	fdivrs (%rax)
+d838|11223344556677885f5f5f5f5f5f	64	intel	fdivr st0, dword ptr [rax]
+d838|11223344556677885f5f5f5f5f5f	64	plan9	FDIVR 0(AX)
+d8c0|11223344556677885f5f5f5f5f5f	32	intel	fadd st0, st0
+d8c0|11223344556677885f5f5f5f5f5f	32	plan9	FADD F0, F0
+d8c0|11223344556677885f5f5f5f5f5f	64	gnu	fadd %st,%st
+d8c0|11223344556677885f5f5f5f5f5f	64	intel	fadd st0, st0
+d8c0|11223344556677885f5f5f5f5f5f	64	plan9	FADD F0, F0
+d8c8|11223344556677885f5f5f5f5f5f	32	intel	fmul st0, st0
+d8c8|11223344556677885f5f5f5f5f5f	32	plan9	FMUL F0, F0
+d8c8|11223344556677885f5f5f5f5f5f	64	gnu	fmul %st,%st
+d8c8|11223344556677885f5f5f5f5f5f	64	intel	fmul st0, st0
+d8c8|11223344556677885f5f5f5f5f5f	64	plan9	FMUL F0, F0
+d8d0|11223344556677885f5f5f5f5f5f	32	intel	fcom st0, st0
+d8d0|11223344556677885f5f5f5f5f5f	32	plan9	FCOM F0
+d8d0|11223344556677885f5f5f5f5f5f	64	gnu	fcom %st
+d8d0|11223344556677885f5f5f5f5f5f	64	intel	fcom st0, st0
+d8d0|11223344556677885f5f5f5f5f5f	64	plan9	FCOM F0
+d8d8|11223344556677885f5f5f5f5f5f	32	intel	fcomp st0, st0
+d8d8|11223344556677885f5f5f5f5f5f	32	plan9	FCOMP F0
+d8d8|11223344556677885f5f5f5f5f5f	64	gnu	fcomp %st
+d8d8|11223344556677885f5f5f5f5f5f	64	intel	fcomp st0, st0
+d8d8|11223344556677885f5f5f5f5f5f	64	plan9	FCOMP F0
+d8e0|11223344556677885f5f5f5f5f5f	32	intel	fsub st0, st0
+d8e0|11223344556677885f5f5f5f5f5f	32	plan9	FSUB F0, F0
+d8e0|11223344556677885f5f5f5f5f5f	64	gnu	fsub %st,%st
+d8e0|11223344556677885f5f5f5f5f5f	64	intel	fsub st0, st0
+d8e0|11223344556677885f5f5f5f5f5f	64	plan9	FSUB F0, F0
+d8e8|11223344556677885f5f5f5f5f5f	32	intel	fsubr st0, st0
+d8e8|11223344556677885f5f5f5f5f5f	32	plan9	FSUBR F0, F0
+d8e8|11223344556677885f5f5f5f5f5f	64	gnu	fsubr %st,%st
+d8e8|11223344556677885f5f5f5f5f5f	64	intel	fsubr st0, st0
+d8e8|11223344556677885f5f5f5f5f5f	64	plan9	FSUBR F0, F0
+d8f0|11223344556677885f5f5f5f5f5f	32	intel	fdiv st0, st0
+d8f0|11223344556677885f5f5f5f5f5f	32	plan9	FDIV F0, F0
+d8f0|11223344556677885f5f5f5f5f5f	64	gnu	fdiv %st,%st
+d8f0|11223344556677885f5f5f5f5f5f	64	intel	fdiv st0, st0
+d8f0|11223344556677885f5f5f5f5f5f	64	plan9	FDIV F0, F0
+d8f8|11223344556677885f5f5f5f5f5f	32	intel	fdivr st0, st0
+d8f8|11223344556677885f5f5f5f5f5f	32	plan9	FDIVR F0, F0
+d8f8|11223344556677885f5f5f5f5f5f	64	gnu	fdivr %st,%st
+d8f8|11223344556677885f5f5f5f5f5f	64	intel	fdivr st0, st0
+d8f8|11223344556677885f5f5f5f5f5f	64	plan9	FDIVR F0, F0
+d900|11223344556677885f5f5f5f5f5f	32	intel	fld st0, dword ptr [eax]
+d900|11223344556677885f5f5f5f5f5f	32	plan9	FLD 0(AX)
+d900|11223344556677885f5f5f5f5f5f	64	gnu	flds (%rax)
+d900|11223344556677885f5f5f5f5f5f	64	intel	fld st0, dword ptr [rax]
+d900|11223344556677885f5f5f5f5f5f	64	plan9	FLD 0(AX)
+d911|223344556677885f5f5f5f5f5f5f	32	intel	fst dword ptr [ecx], st0
+d911|223344556677885f5f5f5f5f5f5f	32	plan9	FST 0(CX)
+d911|223344556677885f5f5f5f5f5f5f	64	gnu	fsts (%rcx)
+d911|223344556677885f5f5f5f5f5f5f	64	intel	fst dword ptr [rcx], st0
+d911|223344556677885f5f5f5f5f5f5f	64	plan9	FST 0(CX)
+d918|11223344556677885f5f5f5f5f5f	32	intel	fstp dword ptr [eax], st0
+d918|11223344556677885f5f5f5f5f5f	32	plan9	FSTP 0(AX)
+d918|11223344556677885f5f5f5f5f5f	64	gnu	fstps (%rax)
+d918|11223344556677885f5f5f5f5f5f	64	intel	fstp dword ptr [rax], st0
+d918|11223344556677885f5f5f5f5f5f	64	plan9	FSTP 0(AX)
+d928|11223344556677885f5f5f5f5f5f	32	intel	fldcw word ptr [eax]
+d928|11223344556677885f5f5f5f5f5f	32	plan9	FLDCW 0(AX)
+d928|11223344556677885f5f5f5f5f5f	64	gnu	fldcw (%rax)
+d928|11223344556677885f5f5f5f5f5f	64	intel	fldcw word ptr [rax]
+d928|11223344556677885f5f5f5f5f5f	64	plan9	FLDCW 0(AX)
+d930|11223344556677885f5f5f5f5f5f	32	intel	fnstenv ptr [eax]
+d930|11223344556677885f5f5f5f5f5f	32	plan9	FNSTENV 0(AX)
+d930|11223344556677885f5f5f5f5f5f	64	gnu	fnstenv (%rax)
+d930|11223344556677885f5f5f5f5f5f	64	intel	fnstenv ptr [rax]
+d930|11223344556677885f5f5f5f5f5f	64	plan9	FNSTENV 0(AX)
+d938|11223344556677885f5f5f5f5f5f	32	intel	fnstcw word ptr [eax]
+d938|11223344556677885f5f5f5f5f5f	32	plan9	FNSTCW 0(AX)
+d938|11223344556677885f5f5f5f5f5f	64	gnu	fnstcw (%rax)
+d938|11223344556677885f5f5f5f5f5f	64	intel	fnstcw word ptr [rax]
+d938|11223344556677885f5f5f5f5f5f	64	plan9	FNSTCW 0(AX)
+d9c0|11223344556677885f5f5f5f5f5f	32	intel	fld st0, st0
+d9c0|11223344556677885f5f5f5f5f5f	32	plan9	FLD F0
+d9c0|11223344556677885f5f5f5f5f5f	64	gnu	fld %st
+d9c0|11223344556677885f5f5f5f5f5f	64	intel	fld st0, st0
+d9c0|11223344556677885f5f5f5f5f5f	64	plan9	FLD F0
+d9c8|11223344556677885f5f5f5f5f5f	32	intel	fxch st0, st0
+d9c8|11223344556677885f5f5f5f5f5f	32	plan9	FXCH F0
+d9c8|11223344556677885f5f5f5f5f5f	64	gnu	fxch %st
+d9c8|11223344556677885f5f5f5f5f5f	64	intel	fxch st0, st0
+d9c8|11223344556677885f5f5f5f5f5f	64	plan9	FXCH F0
+d9d0|11223344556677885f5f5f5f5f5f	32	intel	fnop
+d9d0|11223344556677885f5f5f5f5f5f	32	plan9	FNOP
+d9d0|11223344556677885f5f5f5f5f5f	64	gnu	fnop
+d9d0|11223344556677885f5f5f5f5f5f	64	intel	fnop
+d9d0|11223344556677885f5f5f5f5f5f	64	plan9	FNOP
+d9e0|11223344556677885f5f5f5f5f5f	32	intel	fchs st0
+d9e0|11223344556677885f5f5f5f5f5f	32	plan9	FCHS
+d9e0|11223344556677885f5f5f5f5f5f	64	gnu	fchs
+d9e0|11223344556677885f5f5f5f5f5f	64	intel	fchs st0
+d9e0|11223344556677885f5f5f5f5f5f	64	plan9	FCHS
+d9e1|11223344556677885f5f5f5f5f5f	32	intel	fabs st0
+d9e1|11223344556677885f5f5f5f5f5f	32	plan9	FABS
+d9e1|11223344556677885f5f5f5f5f5f	64	gnu	fabs
+d9e1|11223344556677885f5f5f5f5f5f	64	intel	fabs st0
+d9e1|11223344556677885f5f5f5f5f5f	64	plan9	FABS
+d9e4|11223344556677885f5f5f5f5f5f	32	intel	ftst st0
+d9e4|11223344556677885f5f5f5f5f5f	32	plan9	FTST
+d9e4|11223344556677885f5f5f5f5f5f	64	gnu	ftst
+d9e4|11223344556677885f5f5f5f5f5f	64	intel	ftst st0
+d9e4|11223344556677885f5f5f5f5f5f	64	plan9	FTST
+d9e5|11223344556677885f5f5f5f5f5f	32	intel	fxam st0
+d9e5|11223344556677885f5f5f5f5f5f	32	plan9	FXAM
+d9e5|11223344556677885f5f5f5f5f5f	64	gnu	fxam
+d9e5|11223344556677885f5f5f5f5f5f	64	intel	fxam st0
+d9e5|11223344556677885f5f5f5f5f5f	64	plan9	FXAM
+d9e8|11223344556677885f5f5f5f5f5f	32	intel	fld1 st0
+d9e8|11223344556677885f5f5f5f5f5f	32	plan9	FLD1
+d9e8|11223344556677885f5f5f5f5f5f	64	gnu	fld1
+d9e8|11223344556677885f5f5f5f5f5f	64	intel	fld1 st0
+d9e8|11223344556677885f5f5f5f5f5f	64	plan9	FLD1
+d9e9|11223344556677885f5f5f5f5f5f	32	intel	fldl2t st0
+d9e9|11223344556677885f5f5f5f5f5f	32	plan9	FLDL2T
+d9e9|11223344556677885f5f5f5f5f5f	64	gnu	fldl2t
+d9e9|11223344556677885f5f5f5f5f5f	64	intel	fldl2t st0
+d9e9|11223344556677885f5f5f5f5f5f	64	plan9	FLDL2T
+d9ea|11223344556677885f5f5f5f5f5f	32	intel	fldl2e st0
+d9ea|11223344556677885f5f5f5f5f5f	32	plan9	FLDL2E
+d9ea|11223344556677885f5f5f5f5f5f	64	gnu	fldl2e
+d9ea|11223344556677885f5f5f5f5f5f	64	intel	fldl2e st0
+d9ea|11223344556677885f5f5f5f5f5f	64	plan9	FLDL2E
+d9eb|11223344556677885f5f5f5f5f5f	32	intel	fldpi st0
+d9eb|11223344556677885f5f5f5f5f5f	32	plan9	FLDPI
+d9eb|11223344556677885f5f5f5f5f5f	64	gnu	fldpi
+d9eb|11223344556677885f5f5f5f5f5f	64	intel	fldpi st0
+d9eb|11223344556677885f5f5f5f5f5f	64	plan9	FLDPI
+d9ec|11223344556677885f5f5f5f5f5f	32	intel	fldlg2 st0
+d9ec|11223344556677885f5f5f5f5f5f	32	plan9	FLDLG2
+d9ec|11223344556677885f5f5f5f5f5f	64	gnu	fldlg2
+d9ec|11223344556677885f5f5f5f5f5f	64	intel	fldlg2 st0
+d9ec|11223344556677885f5f5f5f5f5f	64	plan9	FLDLG2
+d9f0|11223344556677885f5f5f5f5f5f	32	intel	f2xm1 st0
+d9f0|11223344556677885f5f5f5f5f5f	32	plan9	F2XM1
+d9f0|11223344556677885f5f5f5f5f5f	64	gnu	f2xm1
+d9f0|11223344556677885f5f5f5f5f5f	64	intel	f2xm1 st0
+d9f0|11223344556677885f5f5f5f5f5f	64	plan9	F2XM1
+d9f1|11223344556677885f5f5f5f5f5f	32	intel	fyl2x st0, st1
+d9f1|11223344556677885f5f5f5f5f5f	32	plan9	FYL2X
+d9f1|11223344556677885f5f5f5f5f5f	64	gnu	fyl2x
+d9f1|11223344556677885f5f5f5f5f5f	64	intel	fyl2x st0, st1
+d9f1|11223344556677885f5f5f5f5f5f	64	plan9	FYL2X
+d9f2|11223344556677885f5f5f5f5f5f	32	intel	fptan st0, st1
+d9f2|11223344556677885f5f5f5f5f5f	32	plan9	FPTAN
+d9f2|11223344556677885f5f5f5f5f5f	64	gnu	fptan
+d9f2|11223344556677885f5f5f5f5f5f	64	intel	fptan st0, st1
+d9f2|11223344556677885f5f5f5f5f5f	64	plan9	FPTAN
+d9f3|11223344556677885f5f5f5f5f5f	32	intel	fpatan st0, st1
+d9f3|11223344556677885f5f5f5f5f5f	32	plan9	FPATAN
+d9f3|11223344556677885f5f5f5f5f5f	64	gnu	fpatan
+d9f3|11223344556677885f5f5f5f5f5f	64	intel	fpatan st0, st1
+d9f3|11223344556677885f5f5f5f5f5f	64	plan9	FPATAN
+d9f4|11223344556677885f5f5f5f5f5f	32	intel	fxtract st0, st1
+d9f4|11223344556677885f5f5f5f5f5f	32	plan9	FXTRACT
+d9f4|11223344556677885f5f5f5f5f5f	64	gnu	fxtract
+d9f4|11223344556677885f5f5f5f5f5f	64	intel	fxtract st0, st1
+d9f4|11223344556677885f5f5f5f5f5f	64	plan9	FXTRACT
+d9f5|11223344556677885f5f5f5f5f5f	32	intel	fprem1 st0, st1
+d9f5|11223344556677885f5f5f5f5f5f	32	plan9	FPREM1
+d9f5|11223344556677885f5f5f5f5f5f	64	gnu	fprem1
+d9f5|11223344556677885f5f5f5f5f5f	64	intel	fprem1 st0, st1
+d9f5|11223344556677885f5f5f5f5f5f	64	plan9	FPREM1
+d9f6|11223344556677885f5f5f5f5f5f	32	intel	fdecstp
+d9f6|11223344556677885f5f5f5f5f5f	32	plan9	FDECSTP
+d9f6|11223344556677885f5f5f5f5f5f	64	gnu	fdecstp
+d9f6|11223344556677885f5f5f5f5f5f	64	intel	fdecstp
+d9f6|11223344556677885f5f5f5f5f5f	64	plan9	FDECSTP
+d9f7|11223344556677885f5f5f5f5f5f	32	intel	fincstp
+d9f7|11223344556677885f5f5f5f5f5f	32	plan9	FINCSTP
+d9f7|11223344556677885f5f5f5f5f5f	64	gnu	fincstp
+d9f7|11223344556677885f5f5f5f5f5f	64	intel	fincstp
+d9f7|11223344556677885f5f5f5f5f5f	64	plan9	FINCSTP
+d9f8|11223344556677885f5f5f5f5f5f	32	intel	fprem st0, st1
+d9f8|11223344556677885f5f5f5f5f5f	32	plan9	FPREM
+d9f8|11223344556677885f5f5f5f5f5f	64	gnu	fprem
+d9f8|11223344556677885f5f5f5f5f5f	64	intel	fprem st0, st1
+d9f8|11223344556677885f5f5f5f5f5f	64	plan9	FPREM
+d9f9|11223344556677885f5f5f5f5f5f	32	intel	fyl2xp1 st0, st1
+d9f9|11223344556677885f5f5f5f5f5f	32	plan9	FYL2XP1
+d9f9|11223344556677885f5f5f5f5f5f	64	gnu	fyl2xp1
+d9f9|11223344556677885f5f5f5f5f5f	64	intel	fyl2xp1 st0, st1
+d9f9|11223344556677885f5f5f5f5f5f	64	plan9	FYL2XP1
+d9fa|11223344556677885f5f5f5f5f5f	32	intel	fsqrt st0
+d9fa|11223344556677885f5f5f5f5f5f	32	plan9	FSQRT
+d9fa|11223344556677885f5f5f5f5f5f	64	gnu	fsqrt
+d9fa|11223344556677885f5f5f5f5f5f	64	intel	fsqrt st0
+d9fa|11223344556677885f5f5f5f5f5f	64	plan9	FSQRT
+d9fb|11223344556677885f5f5f5f5f5f	32	intel	fsincos st0, st1
+d9fb|11223344556677885f5f5f5f5f5f	32	plan9	FSINCOS
+d9fb|11223344556677885f5f5f5f5f5f	64	gnu	fsincos
+d9fb|11223344556677885f5f5f5f5f5f	64	intel	fsincos st0, st1
+d9fb|11223344556677885f5f5f5f5f5f	64	plan9	FSINCOS
+d9fc|11223344556677885f5f5f5f5f5f	32	intel	frndint st0
+d9fc|11223344556677885f5f5f5f5f5f	32	plan9	FRNDINT
+d9fc|11223344556677885f5f5f5f5f5f	64	gnu	frndint
+d9fc|11223344556677885f5f5f5f5f5f	64	intel	frndint st0
+d9fc|11223344556677885f5f5f5f5f5f	64	plan9	FRNDINT
+d9fd|11223344556677885f5f5f5f5f5f	32	intel	fscale st0, st1
+d9fd|11223344556677885f5f5f5f5f5f	32	plan9	FSCALE
+d9fd|11223344556677885f5f5f5f5f5f	64	gnu	fscale
+d9fd|11223344556677885f5f5f5f5f5f	64	intel	fscale st0, st1
+d9fd|11223344556677885f5f5f5f5f5f	64	plan9	FSCALE
+d9fe|11223344556677885f5f5f5f5f5f	32	intel	fsin st0
+d9fe|11223344556677885f5f5f5f5f5f	32	plan9	FSIN
+d9fe|11223344556677885f5f5f5f5f5f	64	gnu	fsin
+d9fe|11223344556677885f5f5f5f5f5f	64	intel	fsin st0
+d9fe|11223344556677885f5f5f5f5f5f	64	plan9	FSIN
+d9ff|11223344556677885f5f5f5f5f5f	32	intel	fcos st0
+d9ff|11223344556677885f5f5f5f5f5f	32	plan9	FCOS
+d9ff|11223344556677885f5f5f5f5f5f	64	gnu	fcos
+d9ff|11223344556677885f5f5f5f5f5f	64	intel	fcos st0
+d9ff|11223344556677885f5f5f5f5f5f	64	plan9	FCOS
+da00|11223344556677885f5f5f5f5f5f	32	intel	fiadd st0, dword ptr [eax]
+da00|11223344556677885f5f5f5f5f5f	32	plan9	FIADD 0(AX)
+da00|11223344556677885f5f5f5f5f5f	64	gnu	fiaddl (%rax)
+da00|11223344556677885f5f5f5f5f5f	64	intel	fiadd st0, dword ptr [rax]
+da00|11223344556677885f5f5f5f5f5f	64	plan9	FIADD 0(AX)
+da08|11223344556677885f5f5f5f5f5f	32	intel	fimul st0, dword ptr [eax]
+da08|11223344556677885f5f5f5f5f5f	32	plan9	FIMUL 0(AX)
+da08|11223344556677885f5f5f5f5f5f	64	gnu	fimull (%rax)
+da08|11223344556677885f5f5f5f5f5f	64	intel	fimul st0, dword ptr [rax]
+da08|11223344556677885f5f5f5f5f5f	64	plan9	FIMUL 0(AX)
+da11|223344556677885f5f5f5f5f5f5f	32	intel	ficom st0, dword ptr [ecx]
+da11|223344556677885f5f5f5f5f5f5f	32	plan9	FICOM 0(CX)
+da11|223344556677885f5f5f5f5f5f5f	64	gnu	ficoml (%rcx)
+da11|223344556677885f5f5f5f5f5f5f	64	intel	ficom st0, dword ptr [rcx]
+da11|223344556677885f5f5f5f5f5f5f	64	plan9	FICOM 0(CX)
+da18|11223344556677885f5f5f5f5f5f	32	intel	ficomp st0, dword ptr [eax]
+da18|11223344556677885f5f5f5f5f5f	32	plan9	FICOMP 0(AX)
+da18|11223344556677885f5f5f5f5f5f	64	gnu	ficompl (%rax)
+da18|11223344556677885f5f5f5f5f5f	64	intel	ficomp st0, dword ptr [rax]
+da18|11223344556677885f5f5f5f5f5f	64	plan9	FICOMP 0(AX)
+da20|11223344556677885f5f5f5f5f5f	32	intel	fisub st0, dword ptr [eax]
+da20|11223344556677885f5f5f5f5f5f	32	plan9	FISUB 0(AX)
+da20|11223344556677885f5f5f5f5f5f	64	gnu	fisubl (%rax)
+da20|11223344556677885f5f5f5f5f5f	64	intel	fisub st0, dword ptr [rax]
+da20|11223344556677885f5f5f5f5f5f	64	plan9	FISUB 0(AX)
+da28|11223344556677885f5f5f5f5f5f	32	intel	fisubr st0, dword ptr [eax]
+da28|11223344556677885f5f5f5f5f5f	32	plan9	FISUBR 0(AX)
+da28|11223344556677885f5f5f5f5f5f	64	gnu	fisubrl (%rax)
+da28|11223344556677885f5f5f5f5f5f	64	intel	fisubr st0, dword ptr [rax]
+da28|11223344556677885f5f5f5f5f5f	64	plan9	FISUBR 0(AX)
+da30|11223344556677885f5f5f5f5f5f	32	intel	fidiv st0, dword ptr [eax]
+da30|11223344556677885f5f5f5f5f5f	32	plan9	FIDIV 0(AX)
+da30|11223344556677885f5f5f5f5f5f	64	gnu	fidivl (%rax)
+da30|11223344556677885f5f5f5f5f5f	64	intel	fidiv st0, dword ptr [rax]
+da30|11223344556677885f5f5f5f5f5f	64	plan9	FIDIV 0(AX)
+da38|11223344556677885f5f5f5f5f5f	32	intel	fidivr st0, dword ptr [eax]
+da38|11223344556677885f5f5f5f5f5f	32	plan9	FIDIVR 0(AX)
+da38|11223344556677885f5f5f5f5f5f	64	gnu	fidivrl (%rax)
+da38|11223344556677885f5f5f5f5f5f	64	intel	fidivr st0, dword ptr [rax]
+da38|11223344556677885f5f5f5f5f5f	64	plan9	FIDIVR 0(AX)
+dac0|11223344556677885f5f5f5f5f5f	32	intel	fcmovb st0, st0
+dac0|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVB F0, F0
+dac0|11223344556677885f5f5f5f5f5f	64	gnu	fcmovb %st,%st
+dac0|11223344556677885f5f5f5f5f5f	64	intel	fcmovb st0, st0
+dac0|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVB F0, F0
+dac8|11223344556677885f5f5f5f5f5f	32	intel	fcmove st0, st0
+dac8|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVE F0, F0
+dac8|11223344556677885f5f5f5f5f5f	64	gnu	fcmove %st,%st
+dac8|11223344556677885f5f5f5f5f5f	64	intel	fcmove st0, st0
+dac8|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVE F0, F0
+dad0|11223344556677885f5f5f5f5f5f	32	intel	fcmovbe st0, st0
+dad0|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVBE F0, F0
+dad0|11223344556677885f5f5f5f5f5f	64	gnu	fcmovbe %st,%st
+dad0|11223344556677885f5f5f5f5f5f	64	intel	fcmovbe st0, st0
+dad0|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVBE F0, F0
+dad8|11223344556677885f5f5f5f5f5f	32	intel	fcmovu st0, st0
+dad8|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVU F0, F0
+dad8|11223344556677885f5f5f5f5f5f	64	gnu	fcmovu %st,%st
+dad8|11223344556677885f5f5f5f5f5f	64	intel	fcmovu st0, st0
+dad8|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVU F0, F0
+dae9|11223344556677885f5f5f5f5f5f	32	intel	fucompp st0, st1
+dae9|11223344556677885f5f5f5f5f5f	32	plan9	FUCOMPP
+dae9|11223344556677885f5f5f5f5f5f	64	gnu	fucompp
+dae9|11223344556677885f5f5f5f5f5f	64	intel	fucompp st0, st1
+dae9|11223344556677885f5f5f5f5f5f	64	plan9	FUCOMPP
+db00|11223344556677885f5f5f5f5f5f	32	intel	fild st0, dword ptr [eax]
+db00|11223344556677885f5f5f5f5f5f	32	plan9	FILD 0(AX)
+db00|11223344556677885f5f5f5f5f5f	64	gnu	fildl (%rax)
+db00|11223344556677885f5f5f5f5f5f	64	intel	fild st0, dword ptr [rax]
+db00|11223344556677885f5f5f5f5f5f	64	plan9	FILD 0(AX)
+db08|11223344556677885f5f5f5f5f5f	32	intel	fisttp dword ptr [eax], st0
+db08|11223344556677885f5f5f5f5f5f	32	plan9	FISTTP 0(AX)
+db08|11223344556677885f5f5f5f5f5f	64	gnu	fisttpl (%rax)
+db08|11223344556677885f5f5f5f5f5f	64	intel	fisttp dword ptr [rax], st0
+db08|11223344556677885f5f5f5f5f5f	64	plan9	FISTTP 0(AX)
+db11|223344556677885f5f5f5f5f5f5f	32	intel	fist dword ptr [ecx], st0
+db11|223344556677885f5f5f5f5f5f5f	32	plan9	FIST 0(CX)
+db11|223344556677885f5f5f5f5f5f5f	64	gnu	fistl (%rcx)
+db11|223344556677885f5f5f5f5f5f5f	64	intel	fist dword ptr [rcx], st0
+db11|223344556677885f5f5f5f5f5f5f	64	plan9	FIST 0(CX)
+db18|11223344556677885f5f5f5f5f5f	32	intel	fistp dword ptr [eax], st0
+db18|11223344556677885f5f5f5f5f5f	32	plan9	FISTP 0(AX)
+db18|11223344556677885f5f5f5f5f5f	64	gnu	fistpl (%rax)
+db18|11223344556677885f5f5f5f5f5f	64	intel	fistp dword ptr [rax], st0
+db18|11223344556677885f5f5f5f5f5f	64	plan9	FISTP 0(AX)
+db28|11223344556677885f5f5f5f5f5f	32	intel	fld st0, ptr [eax]
+db28|11223344556677885f5f5f5f5f5f	32	plan9	FLD 0(AX)
+db28|11223344556677885f5f5f5f5f5f	64	gnu	fldt (%rax)
+db28|11223344556677885f5f5f5f5f5f	64	intel	fld st0, ptr [rax]
+db28|11223344556677885f5f5f5f5f5f	64	plan9	FLD 0(AX)
+db38|11223344556677885f5f5f5f5f5f	32	intel	fstp ptr [eax], st0
+db38|11223344556677885f5f5f5f5f5f	32	plan9	FSTP 0(AX)
+db38|11223344556677885f5f5f5f5f5f	64	gnu	fstpt (%rax)
+db38|11223344556677885f5f5f5f5f5f	64	intel	fstp ptr [rax], st0
+db38|11223344556677885f5f5f5f5f5f	64	plan9	FSTP 0(AX)
+dbc0|11223344556677885f5f5f5f5f5f	32	intel	fcmovnb st0, st0
+dbc0|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVNB F0, F0
+dbc0|11223344556677885f5f5f5f5f5f	64	gnu	fcmovnb %st,%st
+dbc0|11223344556677885f5f5f5f5f5f	64	intel	fcmovnb st0, st0
+dbc0|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVNB F0, F0
+dbc8|11223344556677885f5f5f5f5f5f	32	intel	fcmovne st0, st0
+dbc8|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVNE F0, F0
+dbc8|11223344556677885f5f5f5f5f5f	64	gnu	fcmovne %st,%st
+dbc8|11223344556677885f5f5f5f5f5f	64	intel	fcmovne st0, st0
+dbc8|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVNE F0, F0
+dbd0|11223344556677885f5f5f5f5f5f	32	intel	fcmovnbe st0, st0
+dbd0|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVNBE F0, F0
+dbd0|11223344556677885f5f5f5f5f5f	64	gnu	fcmovnbe %st,%st
+dbd0|11223344556677885f5f5f5f5f5f	64	intel	fcmovnbe st0, st0
+dbd0|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVNBE F0, F0
+dbd8|11223344556677885f5f5f5f5f5f	32	intel	fcmovnu st0, st0
+dbd8|11223344556677885f5f5f5f5f5f	32	plan9	FCMOVNU F0, F0
+dbd8|11223344556677885f5f5f5f5f5f	64	gnu	fcmovnu %st,%st
+dbd8|11223344556677885f5f5f5f5f5f	64	intel	fcmovnu st0, st0
+dbd8|11223344556677885f5f5f5f5f5f	64	plan9	FCMOVNU F0, F0
+dbe2|11223344556677885f5f5f5f5f5f	32	intel	fnclex
+dbe2|11223344556677885f5f5f5f5f5f	32	plan9	FNCLEX
+dbe2|11223344556677885f5f5f5f5f5f	64	gnu	fnclex
+dbe2|11223344556677885f5f5f5f5f5f	64	intel	fnclex
+dbe2|11223344556677885f5f5f5f5f5f	64	plan9	FNCLEX
+dbe3|11223344556677885f5f5f5f5f5f	32	intel	fninit
+dbe3|11223344556677885f5f5f5f5f5f	32	plan9	FNINIT
+dbe3|11223344556677885f5f5f5f5f5f	64	gnu	fninit
+dbe3|11223344556677885f5f5f5f5f5f	64	intel	fninit
+dbe3|11223344556677885f5f5f5f5f5f	64	plan9	FNINIT
+dbe8|11223344556677885f5f5f5f5f5f	32	intel	fucomi st0, st0
+dbe8|11223344556677885f5f5f5f5f5f	32	plan9	FUCOMI F0, F0
+dbe8|11223344556677885f5f5f5f5f5f	64	gnu	fucomi %st,%st
+dbe8|11223344556677885f5f5f5f5f5f	64	intel	fucomi st0, st0
+dbe8|11223344556677885f5f5f5f5f5f	64	plan9	FUCOMI F0, F0
+dbf0|11223344556677885f5f5f5f5f5f	32	intel	fcomi st0, st0
+dbf0|11223344556677885f5f5f5f5f5f	32	plan9	FCOMI F0, F0
+dbf0|11223344556677885f5f5f5f5f5f	64	gnu	fcomi %st,%st
+dbf0|11223344556677885f5f5f5f5f5f	64	intel	fcomi st0, st0
+dbf0|11223344556677885f5f5f5f5f5f	64	plan9	FCOMI F0, F0
+dc00|11223344556677885f5f5f5f5f5f	32	intel	fadd st0, qword ptr [eax]
+dc00|11223344556677885f5f5f5f5f5f	32	plan9	FADD 0(AX)
+dc00|11223344556677885f5f5f5f5f5f	64	gnu	faddl (%rax)
+dc00|11223344556677885f5f5f5f5f5f	64	intel	fadd st0, qword ptr [rax]
+dc00|11223344556677885f5f5f5f5f5f	64	plan9	FADD 0(AX)
+dc08|11223344556677885f5f5f5f5f5f	32	intel	fmul st0, qword ptr [eax]
+dc08|11223344556677885f5f5f5f5f5f	32	plan9	FMUL 0(AX)
+dc08|11223344556677885f5f5f5f5f5f	64	gnu	fmull (%rax)
+dc08|11223344556677885f5f5f5f5f5f	64	intel	fmul st0, qword ptr [rax]
+dc08|11223344556677885f5f5f5f5f5f	64	plan9	FMUL 0(AX)
+dc11|223344556677885f5f5f5f5f5f5f	32	intel	fcom st0, qword ptr [ecx]
+dc11|223344556677885f5f5f5f5f5f5f	32	plan9	FCOM 0(CX)
+dc11|223344556677885f5f5f5f5f5f5f	64	gnu	fcoml (%rcx)
+dc11|223344556677885f5f5f5f5f5f5f	64	intel	fcom st0, qword ptr [rcx]
+dc11|223344556677885f5f5f5f5f5f5f	64	plan9	FCOM 0(CX)
+dc18|11223344556677885f5f5f5f5f5f	32	intel	fcomp st0, qword ptr [eax]
+dc18|11223344556677885f5f5f5f5f5f	32	plan9	FCOMP 0(AX)
+dc18|11223344556677885f5f5f5f5f5f	64	gnu	fcompl (%rax)
+dc18|11223344556677885f5f5f5f5f5f	64	intel	fcomp st0, qword ptr [rax]
+dc18|11223344556677885f5f5f5f5f5f	64	plan9	FCOMP 0(AX)
+dc20|11223344556677885f5f5f5f5f5f	32	intel	fsub st0, qword ptr [eax]
+dc20|11223344556677885f5f5f5f5f5f	32	plan9	FSUB 0(AX)
+dc20|11223344556677885f5f5f5f5f5f	64	gnu	fsubl (%rax)
+dc20|11223344556677885f5f5f5f5f5f	64	intel	fsub st0, qword ptr [rax]
+dc20|11223344556677885f5f5f5f5f5f	64	plan9	FSUB 0(AX)
+dc28|11223344556677885f5f5f5f5f5f	32	intel	fsubr st0, qword ptr [eax]
+dc28|11223344556677885f5f5f5f5f5f	32	plan9	FSUBR 0(AX)
+dc28|11223344556677885f5f5f5f5f5f	64	gnu	fsubrl (%rax)
+dc28|11223344556677885f5f5f5f5f5f	64	intel	fsubr st0, qword ptr [rax]
+dc28|11223344556677885f5f5f5f5f5f	64	plan9	FSUBR 0(AX)
+dc30|11223344556677885f5f5f5f5f5f	32	intel	fdiv st0, qword ptr [eax]
+dc30|11223344556677885f5f5f5f5f5f	32	plan9	FDIV 0(AX)
+dc30|11223344556677885f5f5f5f5f5f	64	gnu	fdivl (%rax)
+dc30|11223344556677885f5f5f5f5f5f	64	intel	fdiv st0, qword ptr [rax]
+dc30|11223344556677885f5f5f5f5f5f	64	plan9	FDIV 0(AX)
+dc38|11223344556677885f5f5f5f5f5f	32	intel	fdivr st0, qword ptr [eax]
+dc38|11223344556677885f5f5f5f5f5f	32	plan9	FDIVR 0(AX)
+dc38|11223344556677885f5f5f5f5f5f	64	gnu	fdivrl (%rax)
+dc38|11223344556677885f5f5f5f5f5f	64	intel	fdivr st0, qword ptr [rax]
+dc38|11223344556677885f5f5f5f5f5f	64	plan9	FDIVR 0(AX)
+dcc0|11223344556677885f5f5f5f5f5f	32	intel	fadd st0, st0
+dcc0|11223344556677885f5f5f5f5f5f	32	plan9	FADD F0, F0
+dcc0|11223344556677885f5f5f5f5f5f	64	gnu	fadd %st,%st
+dcc0|11223344556677885f5f5f5f5f5f	64	intel	fadd st0, st0
+dcc0|11223344556677885f5f5f5f5f5f	64	plan9	FADD F0, F0
+dcc8|11223344556677885f5f5f5f5f5f	32	intel	fmul st0, st0
+dcc8|11223344556677885f5f5f5f5f5f	32	plan9	FMUL F0, F0
+dcc8|11223344556677885f5f5f5f5f5f	64	gnu	fmul %st,%st
+dcc8|11223344556677885f5f5f5f5f5f	64	intel	fmul st0, st0
+dcc8|11223344556677885f5f5f5f5f5f	64	plan9	FMUL F0, F0
+dce0|11223344556677885f5f5f5f5f5f	32	intel	fsubr st0, st0
+dce0|11223344556677885f5f5f5f5f5f	32	plan9	FSUBR F0, F0
+dce0|11223344556677885f5f5f5f5f5f	64	gnu	fsub %st,%st
+dce0|11223344556677885f5f5f5f5f5f	64	intel	fsubr st0, st0
+dce0|11223344556677885f5f5f5f5f5f	64	plan9	FSUBR F0, F0
+dce8|11223344556677885f5f5f5f5f5f	32	intel	fsub st0, st0
+dce8|11223344556677885f5f5f5f5f5f	32	plan9	FSUB F0, F0
+dce8|11223344556677885f5f5f5f5f5f	64	gnu	fsubr %st,%st
+dce8|11223344556677885f5f5f5f5f5f	64	intel	fsub st0, st0
+dce8|11223344556677885f5f5f5f5f5f	64	plan9	FSUB F0, F0
+dcf0|11223344556677885f5f5f5f5f5f	32	intel	fdivr st0, st0
+dcf0|11223344556677885f5f5f5f5f5f	32	plan9	FDIVR F0, F0
+dcf0|11223344556677885f5f5f5f5f5f	64	gnu	fdiv %st,%st
+dcf0|11223344556677885f5f5f5f5f5f	64	intel	fdivr st0, st0
+dcf0|11223344556677885f5f5f5f5f5f	64	plan9	FDIVR F0, F0
+dcf8|11223344556677885f5f5f5f5f5f	32	intel	fdiv st0, st0
+dcf8|11223344556677885f5f5f5f5f5f	32	plan9	FDIV F0, F0
+dcf8|11223344556677885f5f5f5f5f5f	64	gnu	fdivr %st,%st
+dcf8|11223344556677885f5f5f5f5f5f	64	intel	fdiv st0, st0
+dcf8|11223344556677885f5f5f5f5f5f	64	plan9	FDIV F0, F0
+dd00|11223344556677885f5f5f5f5f5f	32	intel	fld st0, qword ptr [eax]
+dd00|11223344556677885f5f5f5f5f5f	32	plan9	FLD 0(AX)
+dd00|11223344556677885f5f5f5f5f5f	64	gnu	fldl (%rax)
+dd00|11223344556677885f5f5f5f5f5f	64	intel	fld st0, qword ptr [rax]
+dd00|11223344556677885f5f5f5f5f5f	64	plan9	FLD 0(AX)
+dd08|11223344556677885f5f5f5f5f5f	32	intel	fisttp qword ptr [eax], st0
+dd08|11223344556677885f5f5f5f5f5f	32	plan9	FISTTP 0(AX)
+dd08|11223344556677885f5f5f5f5f5f	64	gnu	fisttpll (%rax)
+dd08|11223344556677885f5f5f5f5f5f	64	intel	fisttp qword ptr [rax], st0
+dd08|11223344556677885f5f5f5f5f5f	64	plan9	FISTTP 0(AX)
+dd11|223344556677885f5f5f5f5f5f5f	32	intel	fst qword ptr [ecx], st0
+dd11|223344556677885f5f5f5f5f5f5f	32	plan9	FST 0(CX)
+dd11|223344556677885f5f5f5f5f5f5f	64	gnu	fstl (%rcx)
+dd11|223344556677885f5f5f5f5f5f5f	64	intel	fst qword ptr [rcx], st0
+dd11|223344556677885f5f5f5f5f5f5f	64	plan9	FST 0(CX)
+dd18|11223344556677885f5f5f5f5f5f	32	intel	fstp qword ptr [eax], st0
+dd18|11223344556677885f5f5f5f5f5f	32	plan9	FSTP 0(AX)
+dd18|11223344556677885f5f5f5f5f5f	64	gnu	fstpl (%rax)
+dd18|11223344556677885f5f5f5f5f5f	64	intel	fstp qword ptr [rax], st0
+dd18|11223344556677885f5f5f5f5f5f	64	plan9	FSTP 0(AX)
+dd20|11223344556677885f5f5f5f5f5f	32	intel	frstor ptr [eax]
+dd20|11223344556677885f5f5f5f5f5f	32	plan9	FRSTORL 0(AX)
+dd20|11223344556677885f5f5f5f5f5f	64	gnu	frstor (%rax)
+dd20|11223344556677885f5f5f5f5f5f	64	intel	frstor ptr [rax]
+dd20|11223344556677885f5f5f5f5f5f	64	plan9	FRSTORL 0(AX)
+dd30|11223344556677885f5f5f5f5f5f	32	intel	fnsave ptr [eax]
+dd30|11223344556677885f5f5f5f5f5f	32	plan9	FNSAVE 0(AX)
+dd30|11223344556677885f5f5f5f5f5f	64	gnu	fnsave (%rax)
+dd30|11223344556677885f5f5f5f5f5f	64	intel	fnsave ptr [rax]
+dd30|11223344556677885f5f5f5f5f5f	64	plan9	FNSAVE 0(AX)
+dd38|11223344556677885f5f5f5f5f5f	32	intel	fnstsw word ptr [eax]
+dd38|11223344556677885f5f5f5f5f5f	32	plan9	FNSTSW 0(AX)
+dd38|11223344556677885f5f5f5f5f5f	64	gnu	fnstsw (%rax)
+dd38|11223344556677885f5f5f5f5f5f	64	intel	fnstsw word ptr [rax]
+dd38|11223344556677885f5f5f5f5f5f	64	plan9	FNSTSW 0(AX)
+ddc0|11223344556677885f5f5f5f5f5f	32	intel	ffree st0
+ddc0|11223344556677885f5f5f5f5f5f	32	plan9	FFREE F0
+ddc0|11223344556677885f5f5f5f5f5f	64	gnu	ffree %st
+ddc0|11223344556677885f5f5f5f5f5f	64	intel	ffree st0
+ddc0|11223344556677885f5f5f5f5f5f	64	plan9	FFREE F0
+ddd0|11223344556677885f5f5f5f5f5f	32	intel	fst st0, st0
+ddd0|11223344556677885f5f5f5f5f5f	32	plan9	FST F0
+ddd0|11223344556677885f5f5f5f5f5f	64	gnu	fst %st
+ddd0|11223344556677885f5f5f5f5f5f	64	intel	fst st0, st0
+ddd0|11223344556677885f5f5f5f5f5f	64	plan9	FST F0
+ddd8|11223344556677885f5f5f5f5f5f	32	intel	fstp st0, st0
+ddd8|11223344556677885f5f5f5f5f5f	32	plan9	FSTP F0
+ddd8|11223344556677885f5f5f5f5f5f	64	gnu	fstp %st
+ddd8|11223344556677885f5f5f5f5f5f	64	intel	fstp st0, st0
+ddd8|11223344556677885f5f5f5f5f5f	64	plan9	FSTP F0
+dde0|11223344556677885f5f5f5f5f5f	32	intel	fucom st0, st0
+dde0|11223344556677885f5f5f5f5f5f	32	plan9	FUCOM F0
+dde0|11223344556677885f5f5f5f5f5f	64	gnu	fucom %st
+dde0|11223344556677885f5f5f5f5f5f	64	intel	fucom st0, st0
+dde0|11223344556677885f5f5f5f5f5f	64	plan9	FUCOM F0
+dde8|11223344556677885f5f5f5f5f5f	32	intel	fucomp st0, st0
+dde8|11223344556677885f5f5f5f5f5f	32	plan9	FUCOMP F0
+dde8|11223344556677885f5f5f5f5f5f	64	gnu	fucomp %st
+dde8|11223344556677885f5f5f5f5f5f	64	intel	fucomp st0, st0
+dde8|11223344556677885f5f5f5f5f5f	64	plan9	FUCOMP F0
+de00|11223344556677885f5f5f5f5f5f	32	intel	fiadd st0, word ptr [eax]
+de00|11223344556677885f5f5f5f5f5f	32	plan9	FIADD 0(AX)
+de00|11223344556677885f5f5f5f5f5f	64	gnu	fiadd (%rax)
+de00|11223344556677885f5f5f5f5f5f	64	intel	fiadd st0, word ptr [rax]
+de00|11223344556677885f5f5f5f5f5f	64	plan9	FIADD 0(AX)
+de08|11223344556677885f5f5f5f5f5f	32	intel	fimul st0, word ptr [eax]
+de08|11223344556677885f5f5f5f5f5f	32	plan9	FIMUL 0(AX)
+de08|11223344556677885f5f5f5f5f5f	64	gnu	fimul (%rax)
+de08|11223344556677885f5f5f5f5f5f	64	intel	fimul st0, word ptr [rax]
+de08|11223344556677885f5f5f5f5f5f	64	plan9	FIMUL 0(AX)
+de11|223344556677885f5f5f5f5f5f5f	32	intel	ficom st0, word ptr [ecx]
+de11|223344556677885f5f5f5f5f5f5f	32	plan9	FICOM 0(CX)
+de11|223344556677885f5f5f5f5f5f5f	64	gnu	ficom (%rcx)
+de11|223344556677885f5f5f5f5f5f5f	64	intel	ficom st0, word ptr [rcx]
+de11|223344556677885f5f5f5f5f5f5f	64	plan9	FICOM 0(CX)
+de18|11223344556677885f5f5f5f5f5f	32	intel	ficomp st0, word ptr [eax]
+de18|11223344556677885f5f5f5f5f5f	32	plan9	FICOMP 0(AX)
+de18|11223344556677885f5f5f5f5f5f	64	gnu	ficomp (%rax)
+de18|11223344556677885f5f5f5f5f5f	64	intel	ficomp st0, word ptr [rax]
+de18|11223344556677885f5f5f5f5f5f	64	plan9	FICOMP 0(AX)
+de20|11223344556677885f5f5f5f5f5f	32	intel	fisub st0, word ptr [eax]
+de20|11223344556677885f5f5f5f5f5f	32	plan9	FISUB 0(AX)
+de20|11223344556677885f5f5f5f5f5f	64	gnu	fisub (%rax)
+de20|11223344556677885f5f5f5f5f5f	64	intel	fisub st0, word ptr [rax]
+de20|11223344556677885f5f5f5f5f5f	64	plan9	FISUB 0(AX)
+de28|11223344556677885f5f5f5f5f5f	32	intel	fisubr st0, word ptr [eax]
+de28|11223344556677885f5f5f5f5f5f	32	plan9	FISUBR 0(AX)
+de28|11223344556677885f5f5f5f5f5f	64	gnu	fisubr (%rax)
+de28|11223344556677885f5f5f5f5f5f	64	intel	fisubr st0, word ptr [rax]
+de28|11223344556677885f5f5f5f5f5f	64	plan9	FISUBR 0(AX)
+de30|11223344556677885f5f5f5f5f5f	32	intel	fidiv st0, word ptr [eax]
+de30|11223344556677885f5f5f5f5f5f	32	plan9	FIDIV 0(AX)
+de30|11223344556677885f5f5f5f5f5f	64	gnu	fidiv (%rax)
+de30|11223344556677885f5f5f5f5f5f	64	intel	fidiv st0, word ptr [rax]
+de30|11223344556677885f5f5f5f5f5f	64	plan9	FIDIV 0(AX)
+de38|11223344556677885f5f5f5f5f5f	32	intel	fidivr st0, word ptr [eax]
+de38|11223344556677885f5f5f5f5f5f	32	plan9	FIDIVR 0(AX)
+de38|11223344556677885f5f5f5f5f5f	64	gnu	fidivr (%rax)
+de38|11223344556677885f5f5f5f5f5f	64	intel	fidivr st0, word ptr [rax]
+de38|11223344556677885f5f5f5f5f5f	64	plan9	FIDIVR 0(AX)
+dec0|11223344556677885f5f5f5f5f5f	32	intel	faddp st0, st0
+dec0|11223344556677885f5f5f5f5f5f	32	plan9	FADDP F0, F0
+dec0|11223344556677885f5f5f5f5f5f	64	gnu	faddp %st,%st
+dec0|11223344556677885f5f5f5f5f5f	64	intel	faddp st0, st0
+dec0|11223344556677885f5f5f5f5f5f	64	plan9	FADDP F0, F0
+dec8|11223344556677885f5f5f5f5f5f	32	intel	fmulp st0, st0
+dec8|11223344556677885f5f5f5f5f5f	32	plan9	FMULP F0, F0
+dec8|11223344556677885f5f5f5f5f5f	64	gnu	fmulp %st,%st
+dec8|11223344556677885f5f5f5f5f5f	64	intel	fmulp st0, st0
+dec8|11223344556677885f5f5f5f5f5f	64	plan9	FMULP F0, F0
+ded9|11223344556677885f5f5f5f5f5f	32	intel	fcompp st0, st1
+ded9|11223344556677885f5f5f5f5f5f	32	plan9	FCOMPP
+ded9|11223344556677885f5f5f5f5f5f	64	gnu	fcompp
+ded9|11223344556677885f5f5f5f5f5f	64	intel	fcompp st0, st1
+ded9|11223344556677885f5f5f5f5f5f	64	plan9	FCOMPP
+dee0|11223344556677885f5f5f5f5f5f	32	intel	fsubrp st0, st0
+dee0|11223344556677885f5f5f5f5f5f	32	plan9	FSUBRP F0, F0
+dee0|11223344556677885f5f5f5f5f5f	64	gnu	fsubp %st,%st
+dee0|11223344556677885f5f5f5f5f5f	64	intel	fsubrp st0, st0
+dee0|11223344556677885f5f5f5f5f5f	64	plan9	FSUBRP F0, F0
+dee8|11223344556677885f5f5f5f5f5f	32	intel	fsubp st0, st0
+dee8|11223344556677885f5f5f5f5f5f	32	plan9	FSUBP F0, F0
+dee8|11223344556677885f5f5f5f5f5f	64	gnu	fsubrp %st,%st
+dee8|11223344556677885f5f5f5f5f5f	64	intel	fsubp st0, st0
+dee8|11223344556677885f5f5f5f5f5f	64	plan9	FSUBP F0, F0
+def0|11223344556677885f5f5f5f5f5f	32	intel	fdivrp st0, st0
+def0|11223344556677885f5f5f5f5f5f	32	plan9	FDIVRP F0, F0
+def0|11223344556677885f5f5f5f5f5f	64	gnu	fdivp %st,%st
+def0|11223344556677885f5f5f5f5f5f	64	intel	fdivrp st0, st0
+def0|11223344556677885f5f5f5f5f5f	64	plan9	FDIVRP F0, F0
+def8|11223344556677885f5f5f5f5f5f	32	intel	fdivp st0, st0
+def8|11223344556677885f5f5f5f5f5f	32	plan9	FDIVP F0, F0
+def8|11223344556677885f5f5f5f5f5f	64	gnu	fdivrp %st,%st
+def8|11223344556677885f5f5f5f5f5f	64	intel	fdivp st0, st0
+def8|11223344556677885f5f5f5f5f5f	64	plan9	FDIVP F0, F0
+df00|11223344556677885f5f5f5f5f5f	32	intel	fild st0, word ptr [eax]
+df00|11223344556677885f5f5f5f5f5f	32	plan9	FILD 0(AX)
+df00|11223344556677885f5f5f5f5f5f	64	gnu	fild (%rax)
+df00|11223344556677885f5f5f5f5f5f	64	intel	fild st0, word ptr [rax]
+df00|11223344556677885f5f5f5f5f5f	64	plan9	FILD 0(AX)
+df08|11223344556677885f5f5f5f5f5f	32	intel	fisttp word ptr [eax], st0
+df08|11223344556677885f5f5f5f5f5f	32	plan9	FISTTP 0(AX)
+df08|11223344556677885f5f5f5f5f5f	64	gnu	fisttp (%rax)
+df08|11223344556677885f5f5f5f5f5f	64	intel	fisttp word ptr [rax], st0
+df08|11223344556677885f5f5f5f5f5f	64	plan9	FISTTP 0(AX)
+df11|223344556677885f5f5f5f5f5f5f	32	intel	fist word ptr [ecx], st0
+df11|223344556677885f5f5f5f5f5f5f	32	plan9	FIST 0(CX)
+df11|223344556677885f5f5f5f5f5f5f	64	gnu	fist (%rcx)
+df11|223344556677885f5f5f5f5f5f5f	64	intel	fist word ptr [rcx], st0
+df11|223344556677885f5f5f5f5f5f5f	64	plan9	FIST 0(CX)
+df18|11223344556677885f5f5f5f5f5f	32	intel	fistp word ptr [eax], st0
+df18|11223344556677885f5f5f5f5f5f	32	plan9	FISTP 0(AX)
+df18|11223344556677885f5f5f5f5f5f	64	gnu	fistp (%rax)
+df18|11223344556677885f5f5f5f5f5f	64	intel	fistp word ptr [rax], st0
+df18|11223344556677885f5f5f5f5f5f	64	plan9	FISTP 0(AX)
+df20|11223344556677885f5f5f5f5f5f	32	intel	fbld st0, ptr [eax]
+df20|11223344556677885f5f5f5f5f5f	32	plan9	FBLD 0(AX)
+df20|11223344556677885f5f5f5f5f5f	64	gnu	fbld (%rax)
+df20|11223344556677885f5f5f5f5f5f	64	intel	fbld st0, ptr [rax]
+df20|11223344556677885f5f5f5f5f5f	64	plan9	FBLD 0(AX)
+df28|11223344556677885f5f5f5f5f5f	32	intel	fild st0, qword ptr [eax]
+df28|11223344556677885f5f5f5f5f5f	32	plan9	FILD 0(AX)
+df28|11223344556677885f5f5f5f5f5f	64	gnu	fildll (%rax)
+df28|11223344556677885f5f5f5f5f5f	64	intel	fild st0, qword ptr [rax]
+df28|11223344556677885f5f5f5f5f5f	64	plan9	FILD 0(AX)
+df30|11223344556677885f5f5f5f5f5f	32	intel	fbstp ptr [eax], st0
+df30|11223344556677885f5f5f5f5f5f	32	plan9	FBSTP 0(AX)
+df30|11223344556677885f5f5f5f5f5f	64	gnu	fbstp (%rax)
+df30|11223344556677885f5f5f5f5f5f	64	intel	fbstp ptr [rax], st0
+df30|11223344556677885f5f5f5f5f5f	64	plan9	FBSTP 0(AX)
+df38|11223344556677885f5f5f5f5f5f	32	intel	fistp qword ptr [eax], st0
+df38|11223344556677885f5f5f5f5f5f	32	plan9	FISTP 0(AX)
+df38|11223344556677885f5f5f5f5f5f	64	gnu	fistpll (%rax)
+df38|11223344556677885f5f5f5f5f5f	64	intel	fistp qword ptr [rax], st0
+df38|11223344556677885f5f5f5f5f5f	64	plan9	FISTP 0(AX)
+dfc0|11223344556677885f5f5f5f5f5f	32	intel	ffreep st0
+dfc0|11223344556677885f5f5f5f5f5f	32	plan9	FFREEP F0
+dfc0|11223344556677885f5f5f5f5f5f	64	gnu	ffreep %st
+dfc0|11223344556677885f5f5f5f5f5f	64	intel	ffreep st0
+dfc0|11223344556677885f5f5f5f5f5f	64	plan9	FFREEP F0
+dfe0|11223344556677885f5f5f5f5f5f	32	intel	fnstsw ax
+dfe0|11223344556677885f5f5f5f5f5f	32	plan9	FNSTSW AX
+dfe0|11223344556677885f5f5f5f5f5f	64	gnu	fnstsw %ax
+dfe0|11223344556677885f5f5f5f5f5f	64	intel	fnstsw ax
+dfe0|11223344556677885f5f5f5f5f5f	64	plan9	FNSTSW AX
+dfe8|11223344556677885f5f5f5f5f5f	32	intel	fucomip st0, st0
+dfe8|11223344556677885f5f5f5f5f5f	32	plan9	FUCOMIP F0, F0
+dfe8|11223344556677885f5f5f5f5f5f	64	gnu	fucomip %st,%st
+dfe8|11223344556677885f5f5f5f5f5f	64	intel	fucomip st0, st0
+dfe8|11223344556677885f5f5f5f5f5f	64	plan9	FUCOMIP F0, F0
+dff0|11223344556677885f5f5f5f5f5f	32	intel	fcomip st0, st0
+dff0|11223344556677885f5f5f5f5f5f	32	plan9	FCOMIP F0, F0
+dff0|11223344556677885f5f5f5f5f5f	64	gnu	fcomip %st,%st
+dff0|11223344556677885f5f5f5f5f5f	64	intel	fcomip st0, st0
+dff0|11223344556677885f5f5f5f5f5f	64	plan9	FCOMIP F0, F0
+e111|223344556677885f5f5f5f5f5f5f	32	intel	loope .+0x11
+e111|223344556677885f5f5f5f5f5f5f	32	plan9	LOOPE .+17
+e111|223344556677885f5f5f5f5f5f5f	64	gnu	loope .+0x11
+e111|223344556677885f5f5f5f5f5f5f	64	intel	loope .+0x11
+e111|223344556677885f5f5f5f5f5f5f	64	plan9	LOOPE .+17
+e211|223344556677885f5f5f5f5f5f5f	32	intel	loop .+0x11
+e211|223344556677885f5f5f5f5f5f5f	32	plan9	LOOP .+17
+e211|223344556677885f5f5f5f5f5f5f	64	gnu	loop .+0x11
+e211|223344556677885f5f5f5f5f5f5f	64	intel	loop .+0x11
+e211|223344556677885f5f5f5f5f5f5f	64	plan9	LOOP .+17
+e311|223344556677885f5f5f5f5f5f5f	32	intel	jecxz .+0x11
+e311|223344556677885f5f5f5f5f5f5f	32	plan9	JECXZ .+17
+e311|223344556677885f5f5f5f5f5f5f	64	gnu	jrcxz .+0x11
+e311|223344556677885f5f5f5f5f5f5f	64	intel	jrcxz .+0x11
+e311|223344556677885f5f5f5f5f5f5f	64	plan9	JRCXZ .+17
+e411|223344556677885f5f5f5f5f5f5f	32	intel	in al, 0x11
+e411|223344556677885f5f5f5f5f5f5f	32	plan9	INL $0x11, AL
+e411|223344556677885f5f5f5f5f5f5f	64	gnu	in $0x11,%al
+e411|223344556677885f5f5f5f5f5f5f	64	intel	in al, 0x11
+e411|223344556677885f5f5f5f5f5f5f	64	plan9	INL $0x11, AL
+e511|223344556677885f5f5f5f5f5f5f	32	intel	in eax, 0x11
+e511|223344556677885f5f5f5f5f5f5f	32	plan9	INL $0x11, AX
+e511|223344556677885f5f5f5f5f5f5f	64	gnu	in $0x11,%eax
+e511|223344556677885f5f5f5f5f5f5f	64	intel	in eax, 0x11
+e511|223344556677885f5f5f5f5f5f5f	64	plan9	INL $0x11, AX
+e611|223344556677885f5f5f5f5f5f5f	32	intel	out 0x11, al
+e611|223344556677885f5f5f5f5f5f5f	32	plan9	OUTL AL, $0x11
+e611|223344556677885f5f5f5f5f5f5f	64	gnu	out %al,$0x11
+e611|223344556677885f5f5f5f5f5f5f	64	intel	out 0x11, al
+e611|223344556677885f5f5f5f5f5f5f	64	plan9	OUTL AL, $0x11
+e711|223344556677885f5f5f5f5f5f5f	32	intel	out 0x11, eax
+e711|223344556677885f5f5f5f5f5f5f	32	plan9	OUTL AX, $0x11
+e711|223344556677885f5f5f5f5f5f5f	64	gnu	out %eax,$0x11
+e711|223344556677885f5f5f5f5f5f5f	64	intel	out 0x11, eax
+e711|223344556677885f5f5f5f5f5f5f	64	plan9	OUTL AX, $0x11
+e811223344|556677885f5f5f5f5f5f5f	32	intel	call .+0x44332211
+e811223344|556677885f5f5f5f5f5f5f	32	plan9	CALL .+1144201745
+e811223344|556677885f5f5f5f5f5f5f	64	gnu	callq .+0x44332211
+e811223344|556677885f5f5f5f5f5f5f	64	intel	call .+0x44332211
+e811223344|556677885f5f5f5f5f5f5f	64	plan9	CALL .+1144201745
+e911223344|556677885f5f5f5f5f5f5f	32	intel	jmp .+0x44332211
+e911223344|556677885f5f5f5f5f5f5f	32	plan9	JMP .+1144201745
+e911223344|556677885f5f5f5f5f5f5f	64	gnu	jmpq .+0x44332211
+e911223344|556677885f5f5f5f5f5f5f	64	intel	jmp .+0x44332211
+e911223344|556677885f5f5f5f5f5f5f	64	plan9	JMP .+1144201745
+ea112233445566|77885f5f5f5f5f5f5f	32	intel	jmp far 0x44332211, 0x6655
+ea112233445566|77885f5f5f5f5f5f5f	32	plan9	LJMP $0x44332211, $0x6655
+eb11|223344556677885f5f5f5f5f5f5f	32	intel	jmp .+0x11
+eb11|223344556677885f5f5f5f5f5f5f	32	plan9	JMP .+17
+eb11|223344556677885f5f5f5f5f5f5f	64	gnu	jmp .+0x11
+eb11|223344556677885f5f5f5f5f5f5f	64	intel	jmp .+0x11
+eb11|223344556677885f5f5f5f5f5f5f	64	plan9	JMP .+17
+ec|11223344556677885f5f5f5f5f5f5f	32	intel	in al, dx
+ec|11223344556677885f5f5f5f5f5f5f	32	plan9	INL DX, AL
+ec|11223344556677885f5f5f5f5f5f5f	64	gnu	in (%dx),%al
+ec|11223344556677885f5f5f5f5f5f5f	64	intel	in al, dx
+ec|11223344556677885f5f5f5f5f5f5f	64	plan9	INL DX, AL
+ed|11223344556677885f5f5f5f5f5f5f	32	intel	in eax, dx
+ed|11223344556677885f5f5f5f5f5f5f	32	plan9	INL DX, AX
+ed|11223344556677885f5f5f5f5f5f5f	64	gnu	in (%dx),%eax
+ed|11223344556677885f5f5f5f5f5f5f	64	intel	in eax, dx
+ed|11223344556677885f5f5f5f5f5f5f	64	plan9	INL DX, AX
+ee|11223344556677885f5f5f5f5f5f5f	32	intel	out dx, al
+ee|11223344556677885f5f5f5f5f5f5f	32	plan9	OUTL AL, DX
+ee|11223344556677885f5f5f5f5f5f5f	64	gnu	out %al,(%dx)
+ee|11223344556677885f5f5f5f5f5f5f	64	intel	out dx, al
+ee|11223344556677885f5f5f5f5f5f5f	64	plan9	OUTL AL, DX
+ef|11223344556677885f5f5f5f5f5f5f	32	intel	out dx, eax
+ef|11223344556677885f5f5f5f5f5f5f	32	plan9	OUTL AX, DX
+ef|11223344556677885f5f5f5f5f5f5f	64	gnu	out %eax,(%dx)
+ef|11223344556677885f5f5f5f5f5f5f	64	intel	out dx, eax
+ef|11223344556677885f5f5f5f5f5f5f	64	plan9	OUTL AX, DX
+f1|11223344556677885f5f5f5f5f5f5f	32	intel	int1
+f1|11223344556677885f5f5f5f5f5f5f	32	plan9	ICEBP
+f1|11223344556677885f5f5f5f5f5f5f	64	gnu	icebp
+f1|11223344556677885f5f5f5f5f5f5f	64	intel	int1
+f1|11223344556677885f5f5f5f5f5f5f	64	plan9	ICEBP
+f20f1011|223344556677885f5f5f5f5f	32	intel	movsd xmm2, qword ptr [ecx]
+f20f1011|223344556677885f5f5f5f5f	32	plan9	REPNE MOVSD_XMM 0(CX), X2
+f20f1011|223344556677885f5f5f5f5f	64	gnu	movsd (%rcx),%xmm2
+f20f1011|223344556677885f5f5f5f5f	64	intel	movsd xmm2, qword ptr [rcx]
+f20f1011|223344556677885f5f5f5f5f	64	plan9	REPNE MOVSD_XMM 0(CX), X2
+f20f1122|3344556677885f5f5f5f5f5f	32	intel	movsd qword ptr [edx], xmm4
+f20f1122|3344556677885f5f5f5f5f5f	32	plan9	REPNE MOVSD_XMM X4, 0(DX)
+f20f1122|3344556677885f5f5f5f5f5f	64	gnu	movsd %xmm4,(%rdx)
+f20f1122|3344556677885f5f5f5f5f5f	64	intel	movsd qword ptr [rdx], xmm4
+f20f1122|3344556677885f5f5f5f5f5f	64	plan9	REPNE MOVSD_XMM X4, 0(DX)
+f20f1211|223344556677885f5f5f5f5f	32	intel	movddup xmm2, qword ptr [ecx]
+f20f1211|223344556677885f5f5f5f5f	32	plan9	REPNE MOVDDUP 0(CX), X2
+f20f1211|223344556677885f5f5f5f5f	64	gnu	movddup (%rcx),%xmm2
+f20f1211|223344556677885f5f5f5f5f	64	intel	movddup xmm2, qword ptr [rcx]
+f20f1211|223344556677885f5f5f5f5f	64	plan9	REPNE MOVDDUP 0(CX), X2
+f20f2a11|223344556677885f5f5f5f5f	32	intel	cvtsi2sd xmm2, dword ptr [ecx]
+f20f2a11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTSI2SDL 0(CX), X2
+f20f2a11|223344556677885f5f5f5f5f	64	gnu	cvtsi2sdl (%rcx),%xmm2
+f20f2a11|223344556677885f5f5f5f5f	64	intel	cvtsi2sd xmm2, dword ptr [rcx]
+f20f2a11|223344556677885f5f5f5f5f	64	plan9	REPNE CVTSI2SDL 0(CX), X2
+f20f2c11|223344556677885f5f5f5f5f	32	intel	cvttsd2si edx, qword ptr [ecx]
+f20f2c11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTTSD2SIQ 0(CX), DX
+f20f2c11|223344556677885f5f5f5f5f	64	gnu	cvttsd2si (%rcx),%edx
+f20f2c11|223344556677885f5f5f5f5f	64	intel	cvttsd2si edx, qword ptr [rcx]
+f20f2c11|223344556677885f5f5f5f5f	64	plan9	REPNE CVTTSD2SIQ 0(CX), DX
+f20f2d11|223344556677885f5f5f5f5f	32	intel	cvtsd2si edx, qword ptr [ecx]
+f20f2d11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTSD2SIQ 0(CX), DX
+f20f2d11|223344556677885f5f5f5f5f	64	gnu	cvtsd2si (%rcx),%edx
+f20f2d11|223344556677885f5f5f5f5f	64	intel	cvtsd2si edx, qword ptr [rcx]
+f20f2d11|223344556677885f5f5f5f5f	64	plan9	REPNE CVTSD2SIQ 0(CX), DX
+f20f38f011|223344556677885f5f5f5f	32	intel	crc32 edx, byte ptr [ecx]
+f20f38f011|223344556677885f5f5f5f	32	plan9	REPNE CRC32 0(CX), DX
+f20f38f011|223344556677885f5f5f5f	64	gnu	crc32b (%rcx),%edx
+f20f38f011|223344556677885f5f5f5f	64	intel	crc32 edx, byte ptr [rcx]
+f20f38f011|223344556677885f5f5f5f	64	plan9	REPNE CRC32 0(CX), DX
+f20f38f111|223344556677885f5f5f5f	32	intel	crc32 edx, dword ptr [ecx]
+f20f38f111|223344556677885f5f5f5f	32	plan9	REPNE CRC32 0(CX), DX
+f20f38f111|223344556677885f5f5f5f	64	gnu	crc32l (%rcx),%edx
+f20f38f111|223344556677885f5f5f5f	64	intel	crc32 edx, dword ptr [rcx]
+f20f38f111|223344556677885f5f5f5f	64	plan9	REPNE CRC32 0(CX), DX
+f20f5111|223344556677885f5f5f5f5f	32	intel	sqrtsd xmm2, qword ptr [ecx]
+f20f5111|223344556677885f5f5f5f5f	32	plan9	REPNE SQRTSD 0(CX), X2
+f20f5111|223344556677885f5f5f5f5f	64	gnu	sqrtsd (%rcx),%xmm2
+f20f5111|223344556677885f5f5f5f5f	64	intel	sqrtsd xmm2, qword ptr [rcx]
+f20f5111|223344556677885f5f5f5f5f	64	plan9	REPNE SQRTSD 0(CX), X2
+f20f5811|223344556677885f5f5f5f5f	32	intel	addsd xmm2, qword ptr [ecx]
+f20f5811|223344556677885f5f5f5f5f	32	plan9	REPNE ADDSD 0(CX), X2
+f20f5811|223344556677885f5f5f5f5f	64	gnu	addsd (%rcx),%xmm2
+f20f5811|223344556677885f5f5f5f5f	64	intel	addsd xmm2, qword ptr [rcx]
+f20f5811|223344556677885f5f5f5f5f	64	plan9	REPNE ADDSD 0(CX), X2
+f20f5911|223344556677885f5f5f5f5f	32	intel	mulsd xmm2, qword ptr [ecx]
+f20f5911|223344556677885f5f5f5f5f	32	plan9	REPNE MULSD 0(CX), X2
+f20f5911|223344556677885f5f5f5f5f	64	gnu	mulsd (%rcx),%xmm2
+f20f5911|223344556677885f5f5f5f5f	64	intel	mulsd xmm2, qword ptr [rcx]
+f20f5911|223344556677885f5f5f5f5f	64	plan9	REPNE MULSD 0(CX), X2
+f20f5a11|223344556677885f5f5f5f5f	32	intel	cvtsd2ss xmm2, qword ptr [ecx]
+f20f5a11|223344556677885f5f5f5f5f	32	plan9	REPNE CVTSD2SS 0(CX), X2
+f20f5a11|223344556677885f5f5f5f5f	64	gnu	cvtsd2ss (%rcx),%xmm2
+f20f5a11|223344556677885f5f5f5f5f	64	intel	cvtsd2ss xmm2, qword ptr [rcx]
+f20f5a11|223344556677885f5f5f5f5f	64	plan9	REPNE CVTSD2SS 0(CX), X2
+f20f5c11|223344556677885f5f5f5f5f	32	intel	subsd xmm2, qword ptr [ecx]
+f20f5c11|223344556677885f5f5f5f5f	32	plan9	REPNE SUBSD 0(CX), X2
+f20f5c11|223344556677885f5f5f5f5f	64	gnu	subsd (%rcx),%xmm2
+f20f5c11|223344556677885f5f5f5f5f	64	intel	subsd xmm2, qword ptr [rcx]
+f20f5c11|223344556677885f5f5f5f5f	64	plan9	REPNE SUBSD 0(CX), X2
+f20f5d11|223344556677885f5f5f5f5f	32	intel	minsd xmm2, qword ptr [ecx]
+f20f5d11|223344556677885f5f5f5f5f	32	plan9	REPNE MINSD 0(CX), X2
+f20f5d11|223344556677885f5f5f5f5f	64	gnu	minsd (%rcx),%xmm2
+f20f5d11|223344556677885f5f5f5f5f	64	intel	minsd xmm2, qword ptr [rcx]
+f20f5d11|223344556677885f5f5f5f5f	64	plan9	REPNE MINSD 0(CX), X2
+f20f5e11|223344556677885f5f5f5f5f	32	intel	divsd xmm2, qword ptr [ecx]
+f20f5e11|223344556677885f5f5f5f5f	32	plan9	REPNE DIVSD 0(CX), X2
+f20f5e11|223344556677885f5f5f5f5f	64	gnu	divsd (%rcx),%xmm2
+f20f5e11|223344556677885f5f5f5f5f	64	intel	divsd xmm2, qword ptr [rcx]
+f20f5e11|223344556677885f5f5f5f5f	64	plan9	REPNE DIVSD 0(CX), X2
+f20f5f11|223344556677885f5f5f5f5f	32	intel	maxsd xmm2, qword ptr [ecx]
+f20f5f11|223344556677885f5f5f5f5f	32	plan9	REPNE MAXSD 0(CX), X2
+f20f5f11|223344556677885f5f5f5f5f	64	gnu	maxsd (%rcx),%xmm2
+f20f5f11|223344556677885f5f5f5f5f	64	intel	maxsd xmm2, qword ptr [rcx]
+f20f5f11|223344556677885f5f5f5f5f	64	plan9	REPNE MAXSD 0(CX), X2
+f20f701122|3344556677885f5f5f5f5f	32	intel	pshuflw xmm2, xmmword ptr [ecx], 0x22
+f20f701122|3344556677885f5f5f5f5f	32	plan9	REPNE PSHUFLW $0x22, 0(CX), X2
+f20f701122|3344556677885f5f5f5f5f	64	gnu	pshuflw $0x22,(%rcx),%xmm2
+f20f701122|3344556677885f5f5f5f5f	64	intel	pshuflw xmm2, xmmword ptr [rcx], 0x22
+f20f701122|3344556677885f5f5f5f5f	64	plan9	REPNE PSHUFLW $0x22, 0(CX), X2
+f20f7c11|223344556677885f5f5f5f5f	32	intel	haddps xmm2, xmmword ptr [ecx]
+f20f7c11|223344556677885f5f5f5f5f	32	plan9	REPNE HADDPS 0(CX), X2
+f20f7c11|223344556677885f5f5f5f5f	64	gnu	haddps (%rcx),%xmm2
+f20f7c11|223344556677885f5f5f5f5f	64	intel	haddps xmm2, xmmword ptr [rcx]
+f20f7c11|223344556677885f5f5f5f5f	64	plan9	REPNE HADDPS 0(CX), X2
+f20f7d11|223344556677885f5f5f5f5f	32	intel	hsubps xmm2, xmmword ptr [ecx]
+f20f7d11|223344556677885f5f5f5f5f	32	plan9	REPNE HSUBPS 0(CX), X2
+f20f7d11|223344556677885f5f5f5f5f	64	gnu	hsubps (%rcx),%xmm2
+f20f7d11|223344556677885f5f5f5f5f	64	intel	hsubps xmm2, xmmword ptr [rcx]
+f20f7d11|223344556677885f5f5f5f5f	64	plan9	REPNE HSUBPS 0(CX), X2
+f20fc21122|3344556677885f5f5f5f5f	32	intel	cmpsd_xmm xmm2, qword ptr [ecx], 0x22
+f20fc21122|3344556677885f5f5f5f5f	32	plan9	REPNE CMPSD_XMM $0x22, 0(CX), X2
+f20fc21122|3344556677885f5f5f5f5f	64	gnu	cmpsd $0x22,(%rcx),%xmm2
+f20fc21122|3344556677885f5f5f5f5f	64	intel	cmpsd_xmm xmm2, qword ptr [rcx], 0x22
+f20fc21122|3344556677885f5f5f5f5f	64	plan9	REPNE CMPSD_XMM $0x22, 0(CX), X2
+f20fd011|223344556677885f5f5f5f5f	32	intel	addsubps xmm2, xmmword ptr [ecx]
+f20fd011|223344556677885f5f5f5f5f	32	plan9	REPNE ADDSUBPS 0(CX), X2
+f20fd011|223344556677885f5f5f5f5f	64	gnu	addsubps (%rcx),%xmm2
+f20fd011|223344556677885f5f5f5f5f	64	intel	addsubps xmm2, xmmword ptr [rcx]
+f20fd011|223344556677885f5f5f5f5f	64	plan9	REPNE ADDSUBPS 0(CX), X2
+f20fd6c0|11223344556677885f5f5f5f	32	intel	movdq2q mmx0, xmm0
+f20fd6c0|11223344556677885f5f5f5f	32	plan9	REPNE MOVDQ2Q X0, M0
+f20fd6c0|11223344556677885f5f5f5f	64	gnu	movdq2q %xmm0,%mm0
+f20fd6c0|11223344556677885f5f5f5f	64	intel	movdq2q mmx0, xmm0
+f20fd6c0|11223344556677885f5f5f5f	64	plan9	REPNE MOVDQ2Q X0, M0
+f20fe611|223344556677885f5f5f5f5f	32	intel	cvtpd2dq xmm2, xmmword ptr [ecx]
+f20fe611|223344556677885f5f5f5f5f	32	plan9	REPNE CVTPD2DQ 0(CX), X2
+f20fe611|223344556677885f5f5f5f5f	64	gnu	cvtpd2dq (%rcx),%xmm2
+f20fe611|223344556677885f5f5f5f5f	64	intel	cvtpd2dq xmm2, xmmword ptr [rcx]
+f20fe611|223344556677885f5f5f5f5f	64	plan9	REPNE CVTPD2DQ 0(CX), X2
+f20ff011|223344556677885f5f5f5f5f	32	intel	lddqu xmm2, xmmword ptr [ecx]
+f20ff011|223344556677885f5f5f5f5f	32	plan9	REPNE LDDQU 0(CX), X2
+f20ff011|223344556677885f5f5f5f5f	64	gnu	lddqu (%rcx),%xmm2
+f20ff011|223344556677885f5f5f5f5f	64	intel	lddqu xmm2, xmmword ptr [rcx]
+f20ff011|223344556677885f5f5f5f5f	64	plan9	REPNE LDDQU 0(CX), X2
+f2480f2a11|223344556677885f5f5f5f	64	gnu	cvtsi2sdq (%rcx),%xmm2
+f2480f2a11|223344556677885f5f5f5f	64	intel	cvtsi2sd xmm2, qword ptr [rcx]
+f2480f2a11|223344556677885f5f5f5f	64	plan9	REPNE CVTSI2SDQ 0(CX), X2
+f2480f2c11|223344556677885f5f5f5f	64	gnu	cvttsd2si (%rcx),%rdx
+f2480f2c11|223344556677885f5f5f5f	64	intel	cvttsd2si rdx, qword ptr [rcx]
+f2480f2c11|223344556677885f5f5f5f	64	plan9	REPNE CVTTSD2SIQ 0(CX), DX
+f2480f2d11|223344556677885f5f5f5f	64	gnu	cvtsd2si (%rcx),%rdx
+f2480f2d11|223344556677885f5f5f5f	64	intel	cvtsd2si rdx, qword ptr [rcx]
+f2480f2d11|223344556677885f5f5f5f	64	plan9	REPNE CVTSD2SIQ 0(CX), DX
+f2480f38f011|223344556677885f5f5f	64	gnu	crc32b (%rcx),%rdx
+f2480f38f011|223344556677885f5f5f	64	intel	crc32 rdx, byte ptr [rcx]
+f2480f38f011|223344556677885f5f5f	64	plan9	REPNE CRC32 0(CX), DX
+f2480f38f111|223344556677885f5f5f	64	gnu	crc32q (%rcx),%rdx
+f2480f38f111|223344556677885f5f5f	64	intel	crc32 rdx, qword ptr [rcx]
+f2480f38f111|223344556677885f5f5f	64	plan9	REPNE CRC32 0(CX), DX
+f267f0663e360f38f111|223344556677	32	intel	lock crc32 edx, word ptr ss:[bx+di*1]
+f267f0663e360f38f111|223344556677	32	plan9	SS CRC32 SS:0(BX)(DI*1), DX
+f267f0663e360f38f111|223344556677	64	gnu	lock crc32w %ds:%ss:(%ecx),%edx
+f267f0663e360f38f111|223344556677	64	intel	lock crc32 edx, word ptr [ecx]
+f267f0663e360f38f111|223344556677	64	plan9	SS CRC32 0(CX), DX
+f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	intel	movntss dword ptr [ecx], xmm2
+f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	plan9	REP MOVNTSS X2, 0(CX)
+f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	gnu	repn movntss %xmm2,(%rcx)
+f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	intel	movntss dword ptr [rcx], xmm2
+f2f30f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	plan9	REP MOVNTSS X2, 0(CX)
+f30f1011|223344556677885f5f5f5f5f	32	intel	movss xmm2, dword ptr [ecx]
+f30f1011|223344556677885f5f5f5f5f	32	plan9	REP MOVSS 0(CX), X2
+f30f1011|223344556677885f5f5f5f5f	64	gnu	movss (%rcx),%xmm2
+f30f1011|223344556677885f5f5f5f5f	64	intel	movss xmm2, dword ptr [rcx]
+f30f1011|223344556677885f5f5f5f5f	64	plan9	REP MOVSS 0(CX), X2
+f30f1122|3344556677885f5f5f5f5f5f	32	intel	movss dword ptr [edx], xmm4
+f30f1122|3344556677885f5f5f5f5f5f	32	plan9	REP MOVSS X4, 0(DX)
+f30f1122|3344556677885f5f5f5f5f5f	64	gnu	movss %xmm4,(%rdx)
+f30f1122|3344556677885f5f5f5f5f5f	64	intel	movss dword ptr [rdx], xmm4
+f30f1122|3344556677885f5f5f5f5f5f	64	plan9	REP MOVSS X4, 0(DX)
+f30f1211|223344556677885f5f5f5f5f	32	intel	movsldup xmm2, xmmword ptr [ecx]
+f30f1211|223344556677885f5f5f5f5f	32	plan9	REP MOVSLDUP 0(CX), X2
+f30f1211|223344556677885f5f5f5f5f	64	gnu	movsldup (%rcx),%xmm2
+f30f1211|223344556677885f5f5f5f5f	64	intel	movsldup xmm2, xmmword ptr [rcx]
+f30f1211|223344556677885f5f5f5f5f	64	plan9	REP MOVSLDUP 0(CX), X2
+f30f1611|223344556677885f5f5f5f5f	32	intel	movshdup xmm2, xmmword ptr [ecx]
+f30f1611|223344556677885f5f5f5f5f	32	plan9	REP MOVSHDUP 0(CX), X2
+f30f1611|223344556677885f5f5f5f5f	64	gnu	movshdup (%rcx),%xmm2
+f30f1611|223344556677885f5f5f5f5f	64	intel	movshdup xmm2, xmmword ptr [rcx]
+f30f1611|223344556677885f5f5f5f5f	64	plan9	REP MOVSHDUP 0(CX), X2
+f30f2a11|223344556677885f5f5f5f5f	32	intel	cvtsi2ss xmm2, dword ptr [ecx]
+f30f2a11|223344556677885f5f5f5f5f	32	plan9	REP CVTSI2SSL 0(CX), X2
+f30f2a11|223344556677885f5f5f5f5f	64	gnu	cvtsi2ssl (%rcx),%xmm2
+f30f2a11|223344556677885f5f5f5f5f	64	intel	cvtsi2ss xmm2, dword ptr [rcx]
+f30f2a11|223344556677885f5f5f5f5f	64	plan9	REP CVTSI2SSL 0(CX), X2
+f30f2c11|223344556677885f5f5f5f5f	32	intel	cvttss2si edx, dword ptr [ecx]
+f30f2c11|223344556677885f5f5f5f5f	32	plan9	REP CVTTSS2SIL 0(CX), DX
+f30f2c11|223344556677885f5f5f5f5f	64	gnu	cvttss2si (%rcx),%edx
+f30f2c11|223344556677885f5f5f5f5f	64	intel	cvttss2si edx, dword ptr [rcx]
+f30f2c11|223344556677885f5f5f5f5f	64	plan9	REP CVTTSS2SIL 0(CX), DX
+f30f2d11|223344556677885f5f5f5f5f	32	intel	cvtss2si edx, dword ptr [ecx]
+f30f2d11|223344556677885f5f5f5f5f	32	plan9	REP CVTSS2SIL 0(CX), DX
+f30f2d11|223344556677885f5f5f5f5f	64	gnu	cvtss2si (%rcx),%edx
+f30f2d11|223344556677885f5f5f5f5f	64	intel	cvtss2si edx, dword ptr [rcx]
+f30f2d11|223344556677885f5f5f5f5f	64	plan9	REP CVTSS2SIL 0(CX), DX
+f30f5111|223344556677885f5f5f5f5f	32	intel	sqrtss xmm2, dword ptr [ecx]
+f30f5111|223344556677885f5f5f5f5f	32	plan9	REP SQRTSS 0(CX), X2
+f30f5111|223344556677885f5f5f5f5f	64	gnu	sqrtss (%rcx),%xmm2
+f30f5111|223344556677885f5f5f5f5f	64	intel	sqrtss xmm2, dword ptr [rcx]
+f30f5111|223344556677885f5f5f5f5f	64	plan9	REP SQRTSS 0(CX), X2
+f30f5211|223344556677885f5f5f5f5f	32	intel	rsqrtss xmm2, dword ptr [ecx]
+f30f5211|223344556677885f5f5f5f5f	32	plan9	REP RSQRTSS 0(CX), X2
+f30f5211|223344556677885f5f5f5f5f	64	gnu	rsqrtss (%rcx),%xmm2
+f30f5211|223344556677885f5f5f5f5f	64	intel	rsqrtss xmm2, dword ptr [rcx]
+f30f5211|223344556677885f5f5f5f5f	64	plan9	REP RSQRTSS 0(CX), X2
+f30f5311|223344556677885f5f5f5f5f	32	intel	rcpss xmm2, dword ptr [ecx]
+f30f5311|223344556677885f5f5f5f5f	32	plan9	REP RCPSS 0(CX), X2
+f30f5311|223344556677885f5f5f5f5f	64	gnu	rcpss (%rcx),%xmm2
+f30f5311|223344556677885f5f5f5f5f	64	intel	rcpss xmm2, dword ptr [rcx]
+f30f5311|223344556677885f5f5f5f5f	64	plan9	REP RCPSS 0(CX), X2
+f30f5811|223344556677885f5f5f5f5f	32	intel	addss xmm2, dword ptr [ecx]
+f30f5811|223344556677885f5f5f5f5f	32	plan9	REP ADDSS 0(CX), X2
+f30f5811|223344556677885f5f5f5f5f	64	gnu	addss (%rcx),%xmm2
+f30f5811|223344556677885f5f5f5f5f	64	intel	addss xmm2, dword ptr [rcx]
+f30f5811|223344556677885f5f5f5f5f	64	plan9	REP ADDSS 0(CX), X2
+f30f5911|223344556677885f5f5f5f5f	32	intel	mulss xmm2, dword ptr [ecx]
+f30f5911|223344556677885f5f5f5f5f	32	plan9	REP MULSS 0(CX), X2
+f30f5911|223344556677885f5f5f5f5f	64	gnu	mulss (%rcx),%xmm2
+f30f5911|223344556677885f5f5f5f5f	64	intel	mulss xmm2, dword ptr [rcx]
+f30f5911|223344556677885f5f5f5f5f	64	plan9	REP MULSS 0(CX), X2
+f30f5a11|223344556677885f5f5f5f5f	32	intel	cvtss2sd xmm2, dword ptr [ecx]
+f30f5a11|223344556677885f5f5f5f5f	32	plan9	REP CVTSS2SD 0(CX), X2
+f30f5a11|223344556677885f5f5f5f5f	64	gnu	cvtss2sd (%rcx),%xmm2
+f30f5a11|223344556677885f5f5f5f5f	64	intel	cvtss2sd xmm2, dword ptr [rcx]
+f30f5a11|223344556677885f5f5f5f5f	64	plan9	REP CVTSS2SD 0(CX), X2
+f30f5b11|223344556677885f5f5f5f5f	32	intel	cvttps2dq xmm2, xmmword ptr [ecx]
+f30f5b11|223344556677885f5f5f5f5f	32	plan9	REP CVTTPS2DQ 0(CX), X2
+f30f5b11|223344556677885f5f5f5f5f	64	gnu	cvttps2dq (%rcx),%xmm2
+f30f5b11|223344556677885f5f5f5f5f	64	intel	cvttps2dq xmm2, xmmword ptr [rcx]
+f30f5b11|223344556677885f5f5f5f5f	64	plan9	REP CVTTPS2DQ 0(CX), X2
+f30f5c11|223344556677885f5f5f5f5f	32	intel	subss xmm2, dword ptr [ecx]
+f30f5c11|223344556677885f5f5f5f5f	32	plan9	REP SUBSS 0(CX), X2
+f30f5c11|223344556677885f5f5f5f5f	64	gnu	subss (%rcx),%xmm2
+f30f5c11|223344556677885f5f5f5f5f	64	intel	subss xmm2, dword ptr [rcx]
+f30f5c11|223344556677885f5f5f5f5f	64	plan9	REP SUBSS 0(CX), X2
+f30f5d11|223344556677885f5f5f5f5f	32	intel	minss xmm2, dword ptr [ecx]
+f30f5d11|223344556677885f5f5f5f5f	32	plan9	REP MINSS 0(CX), X2
+f30f5d11|223344556677885f5f5f5f5f	64	gnu	minss (%rcx),%xmm2
+f30f5d11|223344556677885f5f5f5f5f	64	intel	minss xmm2, dword ptr [rcx]
+f30f5d11|223344556677885f5f5f5f5f	64	plan9	REP MINSS 0(CX), X2
+f30f5e11|223344556677885f5f5f5f5f	32	intel	divss xmm2, dword ptr [ecx]
+f30f5e11|223344556677885f5f5f5f5f	32	plan9	REP DIVSS 0(CX), X2
+f30f5e11|223344556677885f5f5f5f5f	64	gnu	divss (%rcx),%xmm2
+f30f5e11|223344556677885f5f5f5f5f	64	intel	divss xmm2, dword ptr [rcx]
+f30f5e11|223344556677885f5f5f5f5f	64	plan9	REP DIVSS 0(CX), X2
+f30f5f11|223344556677885f5f5f5f5f	32	intel	maxss xmm2, dword ptr [ecx]
+f30f5f11|223344556677885f5f5f5f5f	32	plan9	REP MAXSS 0(CX), X2
+f30f5f11|223344556677885f5f5f5f5f	64	gnu	maxss (%rcx),%xmm2
+f30f5f11|223344556677885f5f5f5f5f	64	intel	maxss xmm2, dword ptr [rcx]
+f30f5f11|223344556677885f5f5f5f5f	64	plan9	REP MAXSS 0(CX), X2
+f30f6f11|223344556677885f5f5f5f5f	32	intel	movdqu xmm2, xmmword ptr [ecx]
+f30f6f11|223344556677885f5f5f5f5f	32	plan9	REP MOVDQU 0(CX), X2
+f30f6f11|223344556677885f5f5f5f5f	64	gnu	movdqu (%rcx),%xmm2
+f30f6f11|223344556677885f5f5f5f5f	64	intel	movdqu xmm2, xmmword ptr [rcx]
+f30f6f11|223344556677885f5f5f5f5f	64	plan9	REP MOVDQU 0(CX), X2
+f30f701122|3344556677885f5f5f5f5f	32	intel	pshufhw xmm2, xmmword ptr [ecx], 0x22
+f30f701122|3344556677885f5f5f5f5f	32	plan9	REP PSHUFHW $0x22, 0(CX), X2
+f30f701122|3344556677885f5f5f5f5f	64	gnu	pshufhw $0x22,(%rcx),%xmm2
+f30f701122|3344556677885f5f5f5f5f	64	intel	pshufhw xmm2, xmmword ptr [rcx], 0x22
+f30f701122|3344556677885f5f5f5f5f	64	plan9	REP PSHUFHW $0x22, 0(CX), X2
+f30f7e11|223344556677885f5f5f5f5f	32	intel	movq xmm2, qword ptr [ecx]
+f30f7e11|223344556677885f5f5f5f5f	32	plan9	REP MOVQ 0(CX), X2
+f30f7e11|223344556677885f5f5f5f5f	64	gnu	movq (%rcx),%xmm2
+f30f7e11|223344556677885f5f5f5f5f	64	intel	movq xmm2, qword ptr [rcx]
+f30f7e11|223344556677885f5f5f5f5f	64	plan9	REP MOVQ 0(CX), X2
+f30f7f11|223344556677885f5f5f5f5f	32	intel	movdqu xmmword ptr [ecx], xmm2
+f30f7f11|223344556677885f5f5f5f5f	32	plan9	REP MOVDQU X2, 0(CX)
+f30f7f11|223344556677885f5f5f5f5f	64	gnu	movdqu %xmm2,(%rcx)
+f30f7f11|223344556677885f5f5f5f5f	64	intel	movdqu xmmword ptr [rcx], xmm2
+f30f7f11|223344556677885f5f5f5f5f	64	plan9	REP MOVDQU X2, 0(CX)
+f30fae11|223344556677885f5f5f5f5f	64	gnu	wrfsbasel (%rcx)
+f30fae11|223344556677885f5f5f5f5f	64	intel	wrfsbase dword ptr [rcx]
+f30fae11|223344556677885f5f5f5f5f	64	plan9	REP WRFSBASE 0(CX)
+f30fae18|11223344556677885f5f5f5f	64	gnu	wrgsbasel (%rax)
+f30fae18|11223344556677885f5f5f5f	64	intel	wrgsbase dword ptr [rax]
+f30fae18|11223344556677885f5f5f5f	64	plan9	REP WRGSBASE 0(AX)
+f30faec0|11223344556677885f5f5f5f	64	gnu	rdfsbase %eax
+f30faec0|11223344556677885f5f5f5f	64	intel	rdfsbase eax
+f30faec0|11223344556677885f5f5f5f	64	plan9	REP RDFSBASE AX
+f30faec8|11223344556677885f5f5f5f	64	gnu	rdgsbase %eax
+f30faec8|11223344556677885f5f5f5f	64	intel	rdgsbase eax
+f30faec8|11223344556677885f5f5f5f	64	plan9	REP RDGSBASE AX
+f30fb811|223344556677885f5f5f5f5f	32	intel	popcnt edx, dword ptr [ecx]
+f30fb811|223344556677885f5f5f5f5f	32	plan9	REP POPCNT 0(CX), DX
+f30fb811|223344556677885f5f5f5f5f	64	gnu	popcnt (%rcx),%edx
+f30fb811|223344556677885f5f5f5f5f	64	intel	popcnt edx, dword ptr [rcx]
+f30fb811|223344556677885f5f5f5f5f	64	plan9	REP POPCNT 0(CX), DX
+f30fbc11|223344556677885f5f5f5f5f	32	intel	tzcnt edx, dword ptr [ecx]
+f30fbc11|223344556677885f5f5f5f5f	32	plan9	REP TZCNT 0(CX), DX
+f30fbc11|223344556677885f5f5f5f5f	64	gnu	tzcnt (%rcx),%edx
+f30fbc11|223344556677885f5f5f5f5f	64	intel	tzcnt edx, dword ptr [rcx]
+f30fbc11|223344556677885f5f5f5f5f	64	plan9	REP TZCNT 0(CX), DX
+f30fbd11|223344556677885f5f5f5f5f	32	intel	lzcnt edx, dword ptr [ecx]
+f30fbd11|223344556677885f5f5f5f5f	32	plan9	REP LZCNT 0(CX), DX
+f30fbd11|223344556677885f5f5f5f5f	64	gnu	lzcnt (%rcx),%edx
+f30fbd11|223344556677885f5f5f5f5f	64	intel	lzcnt edx, dword ptr [rcx]
+f30fbd11|223344556677885f5f5f5f5f	64	plan9	REP LZCNT 0(CX), DX
+f30fc21122|3344556677885f5f5f5f5f	32	intel	cmpss xmm2, dword ptr [ecx], 0x22
+f30fc21122|3344556677885f5f5f5f5f	32	plan9	REP CMPSS $0x22, 0(CX), X2
+f30fc21122|3344556677885f5f5f5f5f	64	gnu	cmpss $0x22,(%rcx),%xmm2
+f30fc21122|3344556677885f5f5f5f5f	64	intel	cmpss xmm2, dword ptr [rcx], 0x22
+f30fc21122|3344556677885f5f5f5f5f	64	plan9	REP CMPSS $0x22, 0(CX), X2
+f30fe611|223344556677885f5f5f5f5f	32	intel	cvtdq2pd xmm2, qword ptr [ecx]
+f30fe611|223344556677885f5f5f5f5f	32	plan9	REP CVTDQ2PD 0(CX), X2
+f30fe611|223344556677885f5f5f5f5f	64	gnu	cvtdq2pd (%rcx),%xmm2
+f30fe611|223344556677885f5f5f5f5f	64	intel	cvtdq2pd xmm2, qword ptr [rcx]
+f30fe611|223344556677885f5f5f5f5f	64	plan9	REP CVTDQ2PD 0(CX), X2
+f3480f2a11|223344556677885f5f5f5f	64	gnu	cvtsi2ssq (%rcx),%xmm2
+f3480f2a11|223344556677885f5f5f5f	64	intel	cvtsi2ss xmm2, qword ptr [rcx]
+f3480f2a11|223344556677885f5f5f5f	64	plan9	REP CVTSI2SSQ 0(CX), X2
+f3480f2c11|223344556677885f5f5f5f	64	gnu	cvttss2si (%rcx),%rdx
+f3480f2c11|223344556677885f5f5f5f	64	intel	cvttss2si rdx, dword ptr [rcx]
+f3480f2c11|223344556677885f5f5f5f	64	plan9	REP CVTTSS2SIL 0(CX), DX
+f3480f2d11|223344556677885f5f5f5f	64	gnu	cvtss2si (%rcx),%rdx
+f3480f2d11|223344556677885f5f5f5f	64	intel	cvtss2si rdx, dword ptr [rcx]
+f3480f2d11|223344556677885f5f5f5f	64	plan9	REP CVTSS2SIL 0(CX), DX
+f3480fae11|223344556677885f5f5f5f	64	gnu	wrfsbaseq (%rcx)
+f3480fae11|223344556677885f5f5f5f	64	intel	wrfsbase qword ptr [rcx]
+f3480fae11|223344556677885f5f5f5f	64	plan9	REP WRFSBASE 0(CX)
+f3480fae18|11223344556677885f5f5f	64	gnu	wrgsbaseq (%rax)
+f3480fae18|11223344556677885f5f5f	64	intel	wrgsbase qword ptr [rax]
+f3480fae18|11223344556677885f5f5f	64	plan9	REP WRGSBASE 0(AX)
+f3480faec0|11223344556677885f5f5f	64	gnu	rdfsbase %rax
+f3480faec0|11223344556677885f5f5f	64	intel	rdfsbase rax
+f3480faec0|11223344556677885f5f5f	64	plan9	REP RDFSBASE AX
+f3480faec8|11223344556677885f5f5f	64	gnu	rdgsbase %rax
+f3480faec8|11223344556677885f5f5f	64	intel	rdgsbase rax
+f3480faec8|11223344556677885f5f5f	64	plan9	REP RDGSBASE AX
+f3480fb811|223344556677885f5f5f5f	64	gnu	popcnt (%rcx),%rdx
+f3480fb811|223344556677885f5f5f5f	64	intel	popcnt rdx, qword ptr [rcx]
+f3480fb811|223344556677885f5f5f5f	64	plan9	REP POPCNT 0(CX), DX
+f3480fbc11|223344556677885f5f5f5f	64	gnu	tzcnt (%rcx),%rdx
+f3480fbc11|223344556677885f5f5f5f	64	intel	tzcnt rdx, qword ptr [rcx]
+f3480fbc11|223344556677885f5f5f5f	64	plan9	REP TZCNT 0(CX), DX
+f3480fbd11|223344556677885f5f5f5f	64	gnu	lzcnt (%rcx),%rdx
+f3480fbd11|223344556677885f5f5f5f	64	intel	lzcnt rdx, qword ptr [rcx]
+f3480fbd11|223344556677885f5f5f5f	64	plan9	REP LZCNT 0(CX), DX
+f3660fb811|223344556677885f5f5f5f	32	intel	popcnt dx, word ptr [ecx]
+f3660fb811|223344556677885f5f5f5f	32	plan9	POPCNT 0(CX), DX
+f3660fb811|223344556677885f5f5f5f	64	gnu	popcnt (%rcx),%dx
+f3660fb811|223344556677885f5f5f5f	64	intel	popcnt dx, word ptr [rcx]
+f3660fb811|223344556677885f5f5f5f	64	plan9	POPCNT 0(CX), DX
+f3660fbc11|223344556677885f5f5f5f	32	intel	tzcnt dx, word ptr [ecx]
+f3660fbc11|223344556677885f5f5f5f	32	plan9	TZCNT 0(CX), DX
+f3660fbc11|223344556677885f5f5f5f	64	gnu	tzcnt (%rcx),%dx
+f3660fbc11|223344556677885f5f5f5f	64	intel	tzcnt dx, word ptr [rcx]
+f3660fbc11|223344556677885f5f5f5f	64	plan9	TZCNT 0(CX), DX
+f3660fbd11|223344556677885f5f5f5f	32	intel	lzcnt dx, word ptr [ecx]
+f3660fbd11|223344556677885f5f5f5f	32	plan9	LZCNT 0(CX), DX
+f3660fbd11|223344556677885f5f5f5f	64	gnu	lzcnt (%rcx),%dx
+f3660fbd11|223344556677885f5f5f5f	64	intel	lzcnt dx, word ptr [rcx]
+f3660fbd11|223344556677885f5f5f5f	64	plan9	LZCNT 0(CX), DX
+f3f0673e660f38f111|22334455667788	32	intel	lock movbe word ptr [bx+di*1], dx
+f3f0673e660f38f111|22334455667788	32	plan9	MOVBE DX, DS:0(BX)(DI*1)
+f3f0673e660f38f111|22334455667788	64	gnu	rep lock movbe %dx,%ds:(%ecx)
+f3f0673e660f38f111|22334455667788	64	intel	lock movbe word ptr [ecx], dx
+f3f0673e660f38f111|22334455667788	64	plan9	MOVBE DX, 0(CX)
+f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	intel	movntsd qword ptr [ecx], xmm2
+f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	32	plan9	REPNE MOVNTSD X2, 0(CX)
+f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	gnu	repn movntss %xmm2,(%rcx)
+f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	intel	movntsd qword ptr [rcx], xmm2
+f3f20f2b11|5f5f5f5f5f5f5f5f5f5f5f	64	plan9	REPNE MOVNTSD X2, 0(CX)
+f4|11223344556677885f5f5f5f5f5f5f	32	intel	hlt
+f4|11223344556677885f5f5f5f5f5f5f	32	plan9	HLT
+f4|11223344556677885f5f5f5f5f5f5f	64	gnu	hlt
+f4|11223344556677885f5f5f5f5f5f5f	64	intel	hlt
+f4|11223344556677885f5f5f5f5f5f5f	64	plan9	HLT
+f5|11223344556677885f5f5f5f5f5f5f	32	intel	cmc
+f5|11223344556677885f5f5f5f5f5f5f	32	plan9	CMC
+f5|11223344556677885f5f5f5f5f5f5f	64	gnu	cmc
+f5|11223344556677885f5f5f5f5f5f5f	64	intel	cmc
+f5|11223344556677885f5f5f5f5f5f5f	64	plan9	CMC
+f60011|223344556677885f5f5f5f5f5f	32	intel	test byte ptr [eax], 0x11
+f60011|223344556677885f5f5f5f5f5f	32	plan9	TESTB $0x11, 0(AX)
+f60011|223344556677885f5f5f5f5f5f	64	gnu	testb $0x11,(%rax)
+f60011|223344556677885f5f5f5f5f5f	64	intel	test byte ptr [rax], 0x11
+f60011|223344556677885f5f5f5f5f5f	64	plan9	TESTB $0x11, 0(AX)
+f611|223344556677885f5f5f5f5f5f5f	32	intel	not byte ptr [ecx]
+f611|223344556677885f5f5f5f5f5f5f	32	plan9	NOTB 0(CX)
+f611|223344556677885f5f5f5f5f5f5f	64	gnu	notb (%rcx)
+f611|223344556677885f5f5f5f5f5f5f	64	intel	not byte ptr [rcx]
+f611|223344556677885f5f5f5f5f5f5f	64	plan9	NOTB 0(CX)
+f618|11223344556677885f5f5f5f5f5f	32	intel	neg byte ptr [eax]
+f618|11223344556677885f5f5f5f5f5f	32	plan9	NEGB 0(AX)
+f618|11223344556677885f5f5f5f5f5f	64	gnu	negb (%rax)
+f618|11223344556677885f5f5f5f5f5f	64	intel	neg byte ptr [rax]
+f618|11223344556677885f5f5f5f5f5f	64	plan9	NEGB 0(AX)
+f620|11223344556677885f5f5f5f5f5f	32	intel	mul byte ptr [eax]
+f620|11223344556677885f5f5f5f5f5f	32	plan9	MULB 0(AX)
+f620|11223344556677885f5f5f5f5f5f	64	gnu	mulb (%rax)
+f620|11223344556677885f5f5f5f5f5f	64	intel	mul byte ptr [rax]
+f620|11223344556677885f5f5f5f5f5f	64	plan9	MULB 0(AX)
+f628|11223344556677885f5f5f5f5f5f	32	intel	imul byte ptr [eax]
+f628|11223344556677885f5f5f5f5f5f	32	plan9	IMULB 0(AX)
+f628|11223344556677885f5f5f5f5f5f	64	gnu	imulb (%rax)
+f628|11223344556677885f5f5f5f5f5f	64	intel	imul byte ptr [rax]
+f628|11223344556677885f5f5f5f5f5f	64	plan9	IMULB 0(AX)
+f630|11223344556677885f5f5f5f5f5f	32	intel	div byte ptr [eax]
+f630|11223344556677885f5f5f5f5f5f	32	plan9	DIVB 0(AX)
+f630|11223344556677885f5f5f5f5f5f	64	gnu	divb (%rax)
+f630|11223344556677885f5f5f5f5f5f	64	intel	div byte ptr [rax]
+f630|11223344556677885f5f5f5f5f5f	64	plan9	DIVB 0(AX)
+f638|11223344556677885f5f5f5f5f5f	32	intel	idiv byte ptr [eax]
+f638|11223344556677885f5f5f5f5f5f	32	plan9	IDIVB 0(AX)
+f638|11223344556677885f5f5f5f5f5f	64	gnu	idivb (%rax)
+f638|11223344556677885f5f5f5f5f5f	64	intel	idiv byte ptr [rax]
+f638|11223344556677885f5f5f5f5f5f	64	plan9	IDIVB 0(AX)
+f70011223344|556677885f5f5f5f5f5f	32	intel	test dword ptr [eax], 0x44332211
+f70011223344|556677885f5f5f5f5f5f	32	plan9	TESTL $0x44332211, 0(AX)
+f70011223344|556677885f5f5f5f5f5f	64	gnu	testl $0x44332211,(%rax)
+f70011223344|556677885f5f5f5f5f5f	64	intel	test dword ptr [rax], 0x44332211
+f70011223344|556677885f5f5f5f5f5f	64	plan9	TESTL $0x44332211, 0(AX)
+f711|223344556677885f5f5f5f5f5f5f	32	intel	not dword ptr [ecx]
+f711|223344556677885f5f5f5f5f5f5f	32	plan9	NOTL 0(CX)
+f711|223344556677885f5f5f5f5f5f5f	64	gnu	notl (%rcx)
+f711|223344556677885f5f5f5f5f5f5f	64	intel	not dword ptr [rcx]
+f711|223344556677885f5f5f5f5f5f5f	64	plan9	NOTL 0(CX)
+f718|11223344556677885f5f5f5f5f5f	32	intel	neg dword ptr [eax]
+f718|11223344556677885f5f5f5f5f5f	32	plan9	NEGL 0(AX)
+f718|11223344556677885f5f5f5f5f5f	64	gnu	negl (%rax)
+f718|11223344556677885f5f5f5f5f5f	64	intel	neg dword ptr [rax]
+f718|11223344556677885f5f5f5f5f5f	64	plan9	NEGL 0(AX)
+f720|11223344556677885f5f5f5f5f5f	32	intel	mul dword ptr [eax]
+f720|11223344556677885f5f5f5f5f5f	32	plan9	MULL 0(AX)
+f720|11223344556677885f5f5f5f5f5f	64	gnu	mull (%rax)
+f720|11223344556677885f5f5f5f5f5f	64	intel	mul dword ptr [rax]
+f720|11223344556677885f5f5f5f5f5f	64	plan9	MULL 0(AX)
+f728|11223344556677885f5f5f5f5f5f	32	intel	imul dword ptr [eax]
+f728|11223344556677885f5f5f5f5f5f	32	plan9	IMULL 0(AX)
+f728|11223344556677885f5f5f5f5f5f	64	gnu	imull (%rax)
+f728|11223344556677885f5f5f5f5f5f	64	intel	imul dword ptr [rax]
+f728|11223344556677885f5f5f5f5f5f	64	plan9	IMULL 0(AX)
+f730|11223344556677885f5f5f5f5f5f	32	intel	div dword ptr [eax]
+f730|11223344556677885f5f5f5f5f5f	32	plan9	DIVL 0(AX)
+f730|11223344556677885f5f5f5f5f5f	64	gnu	divl (%rax)
+f730|11223344556677885f5f5f5f5f5f	64	intel	div dword ptr [rax]
+f730|11223344556677885f5f5f5f5f5f	64	plan9	DIVL 0(AX)
+f738|11223344556677885f5f5f5f5f5f	32	intel	idiv dword ptr [eax]
+f738|11223344556677885f5f5f5f5f5f	32	plan9	IDIVL 0(AX)
+f738|11223344556677885f5f5f5f5f5f	64	gnu	idivl (%rax)
+f738|11223344556677885f5f5f5f5f5f	64	intel	idiv dword ptr [rax]
+f738|11223344556677885f5f5f5f5f5f	64	plan9	IDIVL 0(AX)
+f8|11223344556677885f5f5f5f5f5f5f	32	intel	clc
+f8|11223344556677885f5f5f5f5f5f5f	32	plan9	CLC
+f8|11223344556677885f5f5f5f5f5f5f	64	gnu	clc
+f8|11223344556677885f5f5f5f5f5f5f	64	intel	clc
+f8|11223344556677885f5f5f5f5f5f5f	64	plan9	CLC
+f9|11223344556677885f5f5f5f5f5f5f	32	intel	stc
+f9|11223344556677885f5f5f5f5f5f5f	32	plan9	STC
+f9|11223344556677885f5f5f5f5f5f5f	64	gnu	stc
+f9|11223344556677885f5f5f5f5f5f5f	64	intel	stc
+f9|11223344556677885f5f5f5f5f5f5f	64	plan9	STC
+fa|11223344556677885f5f5f5f5f5f5f	32	intel	cli
+fa|11223344556677885f5f5f5f5f5f5f	32	plan9	CLI
+fa|11223344556677885f5f5f5f5f5f5f	64	gnu	cli
+fa|11223344556677885f5f5f5f5f5f5f	64	intel	cli
+fa|11223344556677885f5f5f5f5f5f5f	64	plan9	CLI
+fb|11223344556677885f5f5f5f5f5f5f	32	intel	sti
+fb|11223344556677885f5f5f5f5f5f5f	32	plan9	STI
+fb|11223344556677885f5f5f5f5f5f5f	64	gnu	sti
+fb|11223344556677885f5f5f5f5f5f5f	64	intel	sti
+fb|11223344556677885f5f5f5f5f5f5f	64	plan9	STI
+fc|11223344556677885f5f5f5f5f5f5f	32	intel	cld
+fc|11223344556677885f5f5f5f5f5f5f	32	plan9	CLD
+fc|11223344556677885f5f5f5f5f5f5f	64	gnu	cld
+fc|11223344556677885f5f5f5f5f5f5f	64	intel	cld
+fc|11223344556677885f5f5f5f5f5f5f	64	plan9	CLD
+fd|11223344556677885f5f5f5f5f5f5f	32	intel	std
+fd|11223344556677885f5f5f5f5f5f5f	32	plan9	STD
+fd|11223344556677885f5f5f5f5f5f5f	64	gnu	std
+fd|11223344556677885f5f5f5f5f5f5f	64	intel	std
+fd|11223344556677885f5f5f5f5f5f5f	64	plan9	STD
+fe00|11223344556677885f5f5f5f5f5f	32	intel	inc byte ptr [eax]
+fe00|11223344556677885f5f5f5f5f5f	32	plan9	INCB 0(AX)
+fe00|11223344556677885f5f5f5f5f5f	64	gnu	incb (%rax)
+fe00|11223344556677885f5f5f5f5f5f	64	intel	inc byte ptr [rax]
+fe00|11223344556677885f5f5f5f5f5f	64	plan9	INCB 0(AX)
+fe08|11223344556677885f5f5f5f5f5f	32	intel	dec byte ptr [eax]
+fe08|11223344556677885f5f5f5f5f5f	32	plan9	DECB 0(AX)
+fe08|11223344556677885f5f5f5f5f5f	64	gnu	decb (%rax)
+fe08|11223344556677885f5f5f5f5f5f	64	intel	dec byte ptr [rax]
+fe08|11223344556677885f5f5f5f5f5f	64	plan9	DECB 0(AX)
+ff00|11223344556677885f5f5f5f5f5f	32	intel	inc dword ptr [eax]
+ff00|11223344556677885f5f5f5f5f5f	32	plan9	INCL 0(AX)
+ff00|11223344556677885f5f5f5f5f5f	64	gnu	incl (%rax)
+ff00|11223344556677885f5f5f5f5f5f	64	intel	inc dword ptr [rax]
+ff00|11223344556677885f5f5f5f5f5f	64	plan9	INCL 0(AX)
+ff08|11223344556677885f5f5f5f5f5f	32	intel	dec dword ptr [eax]
+ff08|11223344556677885f5f5f5f5f5f	32	plan9	DECL 0(AX)
+ff08|11223344556677885f5f5f5f5f5f	64	gnu	decl (%rax)
+ff08|11223344556677885f5f5f5f5f5f	64	intel	dec dword ptr [rax]
+ff08|11223344556677885f5f5f5f5f5f	64	plan9	DECL 0(AX)
+ff11|223344556677885f5f5f5f5f5f5f	32	intel	call dword ptr [ecx]
+ff11|223344556677885f5f5f5f5f5f5f	32	plan9	CALL 0(CX)
+ff18|11223344556677885f5f5f5f5f5f	32	intel	call far ptr [eax]
+ff18|11223344556677885f5f5f5f5f5f	32	plan9	LCALL 0(AX)
+ff18|11223344556677885f5f5f5f5f5f	64	gnu	lcallq *(%rax)
+ff18|11223344556677885f5f5f5f5f5f	64	intel	call far ptr [rax]
+ff18|11223344556677885f5f5f5f5f5f	64	plan9	LCALL 0(AX)
+ff20|11223344556677885f5f5f5f5f5f	32	intel	jmp dword ptr [eax]
+ff20|11223344556677885f5f5f5f5f5f	32	plan9	JMP 0(AX)
+ff28|11223344556677885f5f5f5f5f5f	32	intel	jmp far ptr [eax]
+ff28|11223344556677885f5f5f5f5f5f	32	plan9	LJMP 0(AX)
+ff28|11223344556677885f5f5f5f5f5f	64	gnu	ljmpq *(%rax)
+ff28|11223344556677885f5f5f5f5f5f	64	intel	jmp far ptr [rax]
+ff28|11223344556677885f5f5f5f5f5f	64	plan9	LJMP 0(AX)
+ff30|11223344556677885f5f5f5f5f5f	32	intel	push dword ptr [eax]
+ff30|11223344556677885f5f5f5f5f5f	32	plan9	PUSHL 0(AX)
+ff30|11223344556677885f5f5f5f5f5f	64	gnu	pushq (%rax)
+ff30|11223344556677885f5f5f5f5f5f	64	intel	push qword ptr [rax]
+ff30|11223344556677885f5f5f5f5f5f	64	plan9	PUSHQ 0(AX)
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/libmach8db.c
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xed_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/xed_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xed_test.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/xed_test.go
diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xedext_test.go b/src/cmd/vendor/golang.org/x/arch/x86/x86asm/xedext_test.go
similarity index 100%
rename from src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/xedext_test.go
rename to src/cmd/vendor/golang.org/x/arch/x86/x86asm/xedext_test.go
diff --git a/src/cmd/internal/unvendor/vendor.json b/src/cmd/vendor/vendor.json
similarity index 100%
rename from src/cmd/internal/unvendor/vendor.json
rename to src/cmd/vendor/vendor.json
diff --git a/src/cmd/vet/README b/src/cmd/vet/README
new file mode 100644
index 0000000..56d4889
--- /dev/null
+++ b/src/cmd/vet/README
@@ -0,0 +1,33 @@
+Vet is a tool that checks correctness of Go programs. It runs a suite of tests,
+each tailored to check for a particular class of errors. Examples include incorrect
+Printf format verbs or malformed build tags.
+
+Over time many checks have been added to vet's suite, but many more have been
+rejected as not appropriate for the tool. The criteria applied when selecting which
+checks to add are:
+
+Correctness:
+
+Vet's tools are about correctness, not style. A vet check must identify real or
+potential bugs that could cause incorrect compilation or execution. A check that
+only identifies stylistic points or alternative correct approaches to a situation
+is not acceptable.
+
+Frequency:
+
+Vet is run every day by many programmers, often as part of every compilation or
+submission. The cost in execution time is considerable, especially in aggregate,
+so checks must be likely enough to find real problems that they are worth the
+overhead of the added check. A new check that finds only a handful of problems
+across all existing programs, even if the problem is significant, is not worth
+adding to the suite everyone runs daily.
+
+Precision:
+
+Most of vet's checks are heuristic and can generate both false positives (flagging
+correct programs) and false negatives (not flagging incorrect ones). The rate of
+both these failures must be very small. A check that is too noisy will be ignored
+by the programmer overwhelmed by the output; a check that misses too many of the
+cases it's looking for will give a false sense of security. Neither is acceptable.
+A vet check must be accurate enough that everything it reports is worth examining,
+and complete enough to encourage real confidence.
diff --git a/src/cmd/vet/asmdecl.go b/src/cmd/vet/asmdecl.go
index e4a9871..d543b2e 100644
--- a/src/cmd/vet/asmdecl.go
+++ b/src/cmd/vet/asmdecl.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -63,6 +63,8 @@ var (
 	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}
+	asmArchMips64   = asmArch{"mips64", 8, 8, 8, true, "R29", true}
+	asmArchMips64LE = asmArch{"mips64", 8, 8, 8, false, "R29", true}
 	asmArchPpc64    = asmArch{"ppc64", 8, 8, 8, true, "R1", true}
 	asmArchPpc64LE  = asmArch{"ppc64le", 8, 8, 8, false, "R1", true}
 
@@ -72,6 +74,8 @@ var (
 		&asmArchArm64,
 		&asmArchAmd64,
 		&asmArchAmd64p32,
+		&asmArchMips64,
+		&asmArchMips64LE,
 		&asmArchPpc64,
 		&asmArchPpc64LE,
 	}
@@ -559,6 +563,11 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
 				src = 8
 				break
 			}
+			if strings.HasPrefix(op, "P") && strings.HasSuffix(op, "RD") {
+				// PINSRD, PEXTRD, etc
+				src = 4
+				break
+			}
 			if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "F") || strings.HasSuffix(op, "FP")) {
 				// FMOVFP, FXCHF, etc
 				src = 4
@@ -604,6 +613,17 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
 					src = 8
 				}
 			}
+		case "mips64", "mips64le":
+			switch op {
+			case "MOVB", "MOVBU":
+				src = 1
+			case "MOVH", "MOVHU":
+				src = 2
+			case "MOVW", "MOVWU", "MOVF":
+				src = 4
+			case "MOVV", "MOVD":
+				src = 8
+			}
 		}
 	}
 	if dst == 0 {
diff --git a/src/cmd/vet/atomic.go b/src/cmd/vet/atomic.go
index c084f13..b2ca2d8 100644
--- a/src/cmd/vet/atomic.go
+++ b/src/cmd/vet/atomic.go
@@ -23,6 +23,9 @@ func checkAtomicAssignment(f *File, node ast.Node) {
 	if len(n.Lhs) != len(n.Rhs) {
 		return
 	}
+	if len(n.Lhs) == 1 && n.Tok == token.DEFINE {
+		return
+	}
 
 	for i, right := range n.Rhs {
 		call, ok := right.(*ast.CallExpr)
diff --git a/src/cmd/vet/buildtag.go b/src/cmd/vet/buildtag.go
index 2d86edf..ccf764e 100644
--- a/src/cmd/vet/buildtag.go
+++ b/src/cmd/vet/buildtag.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/cmd/vet/cgo.go b/src/cmd/vet/cgo.go
index 1985a86..b896862 100644
--- a/src/cmd/vet/cgo.go
+++ b/src/cmd/vet/cgo.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -56,7 +56,7 @@ func checkCgoCall(f *File, node ast.Node) {
 }
 
 // cgoBaseType tries to look through type conversions involving
-// unsafe.Pointer to find the real type.  It converts:
+// unsafe.Pointer to find the real type. It converts:
 //   unsafe.Pointer(x) => x
 //   *(*unsafe.Pointer)(unsafe.Pointer(&x)) => x
 func cgoBaseType(f *File, arg ast.Expr) types.Type {
@@ -106,7 +106,7 @@ func cgoBaseType(f *File, arg ast.Expr) types.Type {
 }
 
 // typeOKForCgoCall returns true if the type of arg is OK to pass to a
-// C function using cgo.  This is not true for Go types with embedded
+// C function using cgo. This is not true for Go types with embedded
 // pointers.
 func typeOKForCgoCall(t types.Type) bool {
 	if t == nil {
diff --git a/src/cmd/vet/composite.go b/src/cmd/vet/composite.go
index 731c793..f704f18 100644
--- a/src/cmd/vet/composite.go
+++ b/src/cmd/vet/composite.go
@@ -10,6 +10,7 @@ import (
 	"cmd/vet/internal/whitelist"
 	"flag"
 	"go/ast"
+	"go/types"
 	"strings"
 )
 
@@ -25,100 +26,57 @@ func init() {
 // 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
-	}
+	cl := node.(*ast.CompositeLit)
 
-	switch typ.(type) {
-	case *ast.ArrayType:
-		return
-	case *ast.MapType:
+	typ := f.pkg.types[cl].Type
+	if typ == nil {
+		// cannot determine composite literals' type, skip it
 		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.)
+	}
+	typeName := typ.String()
+	if *compositeWhiteList && whitelist.UnkeyedLiteral[typeName] {
+		// skip whitelisted types
 		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 {
+	if _, ok := typ.Underlying().(*types.Struct); !ok {
+		// skip non-struct composite literals
 		return
 	}
-
-	if typeString == "" { // isStruct doesn't know
-		typeString = f.gofmt(typ)
+	if isLocalType(f, typeName) {
+		// allow unkeyed locally defined composite literal
+		return
 	}
 
-	// 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.
+	// check if the CompositeLit contains an unkeyed field
 	allKeyValue := true
-	for _, e := range c.Elts {
+	for _, e := range cl.Elts {
 		if _, ok := e.(*ast.KeyValueExpr); !ok {
 			allKeyValue = false
 			break
 		}
 	}
 	if allKeyValue {
+		// all the composite literal fields are keyed
 		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
-	}
+	f.Badf(cl.Pos(), "%s composite literal uses unkeyed fields", typeName)
+}
 
-	// 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
+func isLocalType(f *File, typeName string) bool {
+	if strings.HasPrefix(typeName, "struct{") {
+		// struct literals are local types
+		return true
 	}
 
-	f.Bad(c.Pos(), typeString+" composite literal uses unkeyed fields")
-}
+	pkgname := f.pkg.path
+	if strings.HasPrefix(typeName, pkgname+".") {
+		return true
+	}
 
-// 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
-			}
-		}
+	// treat types as local inside test packages with _test name suffix
+	if strings.HasSuffix(pkgname, "_test") {
+		pkgname = pkgname[:len(pkgname)-len("_test")]
 	}
-	return ""
+	return strings.HasPrefix(typeName, pkgname+".")
 }
diff --git a/src/cmd/vet/copylock.go b/src/cmd/vet/copylock.go
index 8d8399a..6533768 100644
--- a/src/cmd/vet/copylock.go
+++ b/src/cmd/vet/copylock.go
@@ -18,7 +18,7 @@ func init() {
 	register("copylocks",
 		"check that locks are not passed by value",
 		checkCopyLocks,
-		funcDecl, rangeStmt, funcLit, assignStmt)
+		funcDecl, rangeStmt, funcLit, callExpr, assignStmt, genDecl, compositeLit, returnStmt)
 }
 
 // checkCopyLocks checks whether node might
@@ -31,17 +31,75 @@ func checkCopyLocks(f *File, node ast.Node) {
 		checkCopyLocksFunc(f, node.Name.Name, node.Recv, node.Type)
 	case *ast.FuncLit:
 		checkCopyLocksFunc(f, "func", nil, node.Type)
+	case *ast.CallExpr:
+		checkCopyLocksCallExpr(f, node)
 	case *ast.AssignStmt:
 		checkCopyLocksAssign(f, node)
+	case *ast.GenDecl:
+		checkCopyLocksGenDecl(f, node)
+	case *ast.CompositeLit:
+		checkCopyLocksCompositeLit(f, node)
+	case *ast.ReturnStmt:
+		checkCopyLocksReturnStmt(f, node)
 	}
 }
 
 // checkCopyLocksAssign checks whether an assignment
 // copies a lock.
 func checkCopyLocksAssign(f *File, as *ast.AssignStmt) {
-	for _, x := range as.Lhs {
-		if path := lockPath(f.pkg.typesPkg, f.pkg.types[x].Type); path != nil {
-			f.Badf(x.Pos(), "assignment copies lock value to %v: %v", f.gofmt(x), path)
+	for i, x := range as.Rhs {
+		if path := lockPathRhs(f, x); path != nil {
+			f.Badf(x.Pos(), "assignment copies lock value to %v: %v", f.gofmt(as.Lhs[i]), path)
+		}
+	}
+}
+
+// checkCopyLocksGenDecl checks whether lock is copied
+// in variable declaration.
+func checkCopyLocksGenDecl(f *File, gd *ast.GenDecl) {
+	if gd.Tok != token.VAR {
+		return
+	}
+	for _, spec := range gd.Specs {
+		valueSpec := spec.(*ast.ValueSpec)
+		for i, x := range valueSpec.Values {
+			if path := lockPathRhs(f, x); path != nil {
+				f.Badf(x.Pos(), "variable declaration copies lock value to %v: %v", valueSpec.Names[i].Name, path)
+			}
+		}
+	}
+}
+
+// checkCopyLocksCompositeLit detects lock copy inside a composite literal
+func checkCopyLocksCompositeLit(f *File, cl *ast.CompositeLit) {
+	for _, x := range cl.Elts {
+		if node, ok := x.(*ast.KeyValueExpr); ok {
+			x = node.Value
+		}
+		if path := lockPathRhs(f, x); path != nil {
+			f.Badf(x.Pos(), "literal copies lock value from %v: %v", f.gofmt(x), path)
+		}
+	}
+}
+
+// checkCopyLocksReturnStmt detects lock copy in return statement
+func checkCopyLocksReturnStmt(f *File, rs *ast.ReturnStmt) {
+	for _, x := range rs.Results {
+		if path := lockPathRhs(f, x); path != nil {
+			f.Badf(x.Pos(), "return copies lock value: %v", path)
+		}
+	}
+}
+
+// checkCopyLocksCallExpr detects lock copy in the arguments to a function call
+func checkCopyLocksCallExpr(f *File, ce *ast.CallExpr) {
+	if id, ok := ce.Fun.(*ast.Ident); ok && id.Name == "new" && f.pkg.types[id].IsBuiltin() {
+		// Skip 'new(Type)' for built-in 'new'
+		return
+	}
+	for _, x := range ce.Args {
+		if path := lockPathRhs(f, x); path != nil {
+			f.Badf(x.Pos(), "function call copies lock value: %v", path)
 		}
 	}
 }
@@ -67,14 +125,10 @@ func checkCopyLocksFunc(f *File, name string, recv *ast.FieldList, typ *ast.Func
 		}
 	}
 
-	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)
-			}
-		}
-	}
+	// Don't check typ.Results. If T has a Lock field it's OK to write
+	//     return T{}
+	// because that is returning the zero value. Leave result checking
+	// to the return statement.
 }
 
 // checkCopyLocksRange checks whether a range statement
@@ -132,6 +186,23 @@ func (path typePath) String() string {
 	return buf.String()
 }
 
+func lockPathRhs(f *File, x ast.Expr) typePath {
+	if _, ok := x.(*ast.CompositeLit); ok {
+		return nil
+	}
+	if _, ok := x.(*ast.CallExpr); ok {
+		// A call may return a zero value.
+		return nil
+	}
+	if star, ok := x.(*ast.StarExpr); ok {
+		if _, ok := star.X.(*ast.CallExpr); ok {
+			// A call may return a pointer to a zero value.
+			return nil
+		}
+	}
+	return lockPath(f.pkg.typesPkg, f.pkg.types[x].Type)
+}
+
 // 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 {
diff --git a/src/cmd/vet/deadcode.go b/src/cmd/vet/deadcode.go
index 3b306c2..b1077ae 100644
--- a/src/cmd/vet/deadcode.go
+++ b/src/cmd/vet/deadcode.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -29,6 +29,8 @@ type deadState struct {
 }
 
 // checkUnreachable checks a function body for dead code.
+//
+// TODO(adonovan): use the new cfg package, which is more precise.
 func checkUnreachable(f *File, node ast.Node) {
 	var body *ast.BlockStmt
 	switch n := node.(type) {
diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go
index 53db6dd..69d5f9c 100644
--- a/src/cmd/vet/doc.go
+++ b/src/cmd/vet/doc.go
@@ -29,11 +29,10 @@ 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.
+By default the -all flag is set so 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:
 
@@ -85,12 +84,21 @@ Flag: -copylocks
 
 Locks that are erroneously passed by value.
 
-Documentation examples
+Tests, benchmarks and documentation examples
 
-Flag: -example
+Flag: -tests
 
-Mistakes involving example tests, including examples with incorrect names or
-function signatures, or that document identifiers not in the package.
+Mistakes involving tests including functions with incorrect names or signatures
+and example tests that document identifiers not in the package.
+
+Failure to call the cancelation function returned by context.WithCancel.
+
+Flag: -lostcancel
+
+The cancelation function returned by context.WithCancel, WithTimeout,
+and WithDeadline must be called or the new context will remain live
+until its parent context is cancelled.
+(The background context is never cancelled.)
 
 Methods
 
@@ -188,17 +196,10 @@ These flags configure the behavior of vet:
 	-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
+		A comma-separated list of print-like function names
+		to supplement the standard list.
 		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"
+package main
diff --git a/src/cmd/vet/example.go b/src/cmd/vet/example.go
deleted file mode 100644
index 797c3ce..0000000
--- a/src/cmd/vet/example.go
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2015 The Go Authors. 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/types"
-	"strings"
-	"unicode"
-	"unicode/utf8"
-)
-
-func init() {
-	register("example",
-		"check for common mistaken usages of documentation examples",
-		checkExample,
-		funcDecl)
-}
-
-func isExampleSuffix(s string) bool {
-	r, size := utf8.DecodeRuneInString(s)
-	return size > 0 && unicode.IsLower(r)
-}
-
-// checkExample walks the documentation example functions checking for common
-// mistakes of misnamed functions, failure to map functions to existing
-// identifiers, etc.
-func checkExample(f *File, node ast.Node) {
-	if !strings.HasSuffix(f.name, "_test.go") {
-		return
-	}
-	var (
-		pkg     = f.pkg
-		pkgName = pkg.typesPkg.Name()
-		scopes  = []*types.Scope{pkg.typesPkg.Scope()}
-		lookup  = func(name string) types.Object {
-			for _, scope := range scopes {
-				if o := scope.Lookup(name); o != nil {
-					return o
-				}
-			}
-			return nil
-		}
-	)
-	if strings.HasSuffix(pkgName, "_test") {
-		// Treat 'package foo_test' as an alias for 'package foo'.
-		var (
-			basePkg = strings.TrimSuffix(pkgName, "_test")
-			pkg     = f.pkg
-		)
-		for _, p := range pkg.typesPkg.Imports() {
-			if p.Name() == basePkg {
-				scopes = append(scopes, p.Scope())
-				break
-			}
-		}
-	}
-	fn, ok := node.(*ast.FuncDecl)
-	if !ok {
-		// Ignore non-functions.
-		return
-	}
-	var (
-		fnName = fn.Name.Name
-		report = func(format string, args ...interface{}) { f.Badf(node.Pos(), format, args...) }
-	)
-	if fn.Recv != nil || !strings.HasPrefix(fnName, "Example") {
-		// Ignore methods and types not named "Example".
-		return
-	}
-	if params := fn.Type.Params; len(params.List) != 0 {
-		report("%s should be niladic", fnName)
-	}
-	if results := fn.Type.Results; results != nil && len(results.List) != 0 {
-		report("%s should return nothing", fnName)
-	}
-	if fnName == "Example" {
-		// Nothing more to do.
-		return
-	}
-	if filesRun && !includesNonTest {
-		// The coherence checks between a test and the package it tests
-		// will report false positives if no non-test files have
-		// been provided.
-		return
-	}
-	var (
-		exName = strings.TrimPrefix(fnName, "Example")
-		elems  = strings.SplitN(exName, "_", 3)
-		ident  = elems[0]
-		obj    = lookup(ident)
-	)
-	if ident != "" && obj == nil {
-		// Check ExampleFoo and ExampleBadFoo.
-		report("%s refers to unknown identifier: %s", fnName, ident)
-		// Abort since obj is absent and no subsequent checks can be performed.
-		return
-	}
-	if elemCnt := strings.Count(exName, "_"); elemCnt == 0 {
-		// Nothing more to do.
-		return
-	}
-	mmbr := elems[1]
-	if ident == "" {
-		// Check Example_suffix and Example_BadSuffix.
-		if residual := strings.TrimPrefix(exName, "_"); !isExampleSuffix(residual) {
-			report("%s has malformed example suffix: %s", fnName, residual)
-		}
-		return
-	}
-	if !isExampleSuffix(mmbr) {
-		// Check ExampleFoo_Method and ExampleFoo_BadMethod.
-		if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil {
-			report("%s refers to unknown field or method: %s.%s", fnName, ident, mmbr)
-		}
-	}
-	if len(elems) == 3 && !isExampleSuffix(elems[2]) {
-		// Check ExampleFoo_Method_suffix and ExampleFoo_Method_Badsuffix.
-		report("%s has malformed example suffix: %s", fnName, elems[2])
-	}
-	return
-}
diff --git a/src/cmd/vet/internal/cfg/builder.go b/src/cmd/vet/internal/cfg/builder.go
new file mode 100644
index 0000000..da1cc7e
--- /dev/null
+++ b/src/cmd/vet/internal/cfg/builder.go
@@ -0,0 +1,512 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cfg
+
+// This file implements the CFG construction pass.
+
+import (
+	"fmt"
+	"go/ast"
+	"go/token"
+)
+
+type builder struct {
+	cfg       *CFG
+	mayReturn func(*ast.CallExpr) bool
+	current   *Block
+	lblocks   map[*ast.Object]*lblock // labeled blocks
+	targets   *targets                // linked stack of branch targets
+}
+
+func (b *builder) stmt(_s ast.Stmt) {
+	// The label of the current statement.  If non-nil, its _goto
+	// target is always set; its _break and _continue are set only
+	// within the body of switch/typeswitch/select/for/range.
+	// It is effectively an additional default-nil parameter of stmt().
+	var label *lblock
+start:
+	switch s := _s.(type) {
+	case *ast.BadStmt,
+		*ast.SendStmt,
+		*ast.IncDecStmt,
+		*ast.GoStmt,
+		*ast.DeferStmt,
+		*ast.EmptyStmt,
+		*ast.AssignStmt:
+		// No effect on control flow.
+		b.add(s)
+
+	case *ast.ExprStmt:
+		b.add(s)
+		if call, ok := s.X.(*ast.CallExpr); ok && !b.mayReturn(call) {
+			// Calls to panic, os.Exit, etc, never return.
+			b.current = b.newUnreachableBlock("unreachable.call")
+		}
+
+	case *ast.DeclStmt:
+		// Treat each var ValueSpec as a separate statement.
+		d := s.Decl.(*ast.GenDecl)
+		if d.Tok == token.VAR {
+			for _, spec := range d.Specs {
+				if spec, ok := spec.(*ast.ValueSpec); ok {
+					b.add(spec)
+				}
+			}
+		}
+
+	case *ast.LabeledStmt:
+		label = b.labeledBlock(s.Label)
+		b.jump(label._goto)
+		b.current = label._goto
+		_s = s.Stmt
+		goto start // effectively: tailcall stmt(g, s.Stmt, label)
+
+	case *ast.ReturnStmt:
+		b.add(s)
+		b.current = b.newUnreachableBlock("unreachable.return")
+
+	case *ast.BranchStmt:
+		var block *Block
+		switch s.Tok {
+		case token.BREAK:
+			if s.Label != nil {
+				if lb := b.labeledBlock(s.Label); lb != nil {
+					block = lb._break
+				}
+			} else {
+				for t := b.targets; t != nil && block == nil; t = t.tail {
+					block = t._break
+				}
+			}
+
+		case token.CONTINUE:
+			if s.Label != nil {
+				if lb := b.labeledBlock(s.Label); lb != nil {
+					block = lb._continue
+				}
+			} else {
+				for t := b.targets; t != nil && block == nil; t = t.tail {
+					block = t._continue
+				}
+			}
+
+		case token.FALLTHROUGH:
+			for t := b.targets; t != nil; t = t.tail {
+				block = t._fallthrough
+			}
+
+		case token.GOTO:
+			if s.Label != nil {
+				block = b.labeledBlock(s.Label)._goto
+			}
+		}
+		if block == nil {
+			block = b.newBlock("undefined.branch")
+		}
+		b.jump(block)
+		b.current = b.newUnreachableBlock("unreachable.branch")
+
+	case *ast.BlockStmt:
+		b.stmtList(s.List)
+
+	case *ast.IfStmt:
+		if s.Init != nil {
+			b.stmt(s.Init)
+		}
+		then := b.newBlock("if.then")
+		done := b.newBlock("if.done")
+		_else := done
+		if s.Else != nil {
+			_else = b.newBlock("if.else")
+		}
+		b.add(s.Cond)
+		b.ifelse(then, _else)
+		b.current = then
+		b.stmt(s.Body)
+		b.jump(done)
+
+		if s.Else != nil {
+			b.current = _else
+			b.stmt(s.Else)
+			b.jump(done)
+		}
+
+		b.current = done
+
+	case *ast.SwitchStmt:
+		b.switchStmt(s, label)
+
+	case *ast.TypeSwitchStmt:
+		b.typeSwitchStmt(s, label)
+
+	case *ast.SelectStmt:
+		b.selectStmt(s, label)
+
+	case *ast.ForStmt:
+		b.forStmt(s, label)
+
+	case *ast.RangeStmt:
+		b.rangeStmt(s, label)
+
+	default:
+		panic(fmt.Sprintf("unexpected statement kind: %T", s))
+	}
+}
+
+func (b *builder) stmtList(list []ast.Stmt) {
+	for _, s := range list {
+		b.stmt(s)
+	}
+}
+
+func (b *builder) switchStmt(s *ast.SwitchStmt, label *lblock) {
+	if s.Init != nil {
+		b.stmt(s.Init)
+	}
+	if s.Tag != nil {
+		b.add(s.Tag)
+	}
+	done := b.newBlock("switch.done")
+	if label != nil {
+		label._break = done
+	}
+	// We pull the default case (if present) down to the end.
+	// But each fallthrough label must point to the next
+	// body block in source order, so we preallocate a
+	// body block (fallthru) for the next case.
+	// Unfortunately this makes for a confusing block order.
+	var defaultBody *[]ast.Stmt
+	var defaultFallthrough *Block
+	var fallthru, defaultBlock *Block
+	ncases := len(s.Body.List)
+	for i, clause := range s.Body.List {
+		body := fallthru
+		if body == nil {
+			body = b.newBlock("switch.body") // first case only
+		}
+
+		// Preallocate body block for the next case.
+		fallthru = done
+		if i+1 < ncases {
+			fallthru = b.newBlock("switch.body")
+		}
+
+		cc := clause.(*ast.CaseClause)
+		if cc.List == nil {
+			// Default case.
+			defaultBody = &cc.Body
+			defaultFallthrough = fallthru
+			defaultBlock = body
+			continue
+		}
+
+		var nextCond *Block
+		for _, cond := range cc.List {
+			nextCond = b.newBlock("switch.next")
+			b.add(cond) // one half of the tag==cond condition
+			b.ifelse(body, nextCond)
+			b.current = nextCond
+		}
+		b.current = body
+		b.targets = &targets{
+			tail:         b.targets,
+			_break:       done,
+			_fallthrough: fallthru,
+		}
+		b.stmtList(cc.Body)
+		b.targets = b.targets.tail
+		b.jump(done)
+		b.current = nextCond
+	}
+	if defaultBlock != nil {
+		b.jump(defaultBlock)
+		b.current = defaultBlock
+		b.targets = &targets{
+			tail:         b.targets,
+			_break:       done,
+			_fallthrough: defaultFallthrough,
+		}
+		b.stmtList(*defaultBody)
+		b.targets = b.targets.tail
+	}
+	b.jump(done)
+	b.current = done
+}
+
+func (b *builder) typeSwitchStmt(s *ast.TypeSwitchStmt, label *lblock) {
+	if s.Init != nil {
+		b.stmt(s.Init)
+	}
+	if s.Assign != nil {
+		b.add(s.Assign)
+	}
+
+	done := b.newBlock("typeswitch.done")
+	if label != nil {
+		label._break = done
+	}
+	var default_ *ast.CaseClause
+	for _, clause := range s.Body.List {
+		cc := clause.(*ast.CaseClause)
+		if cc.List == nil {
+			default_ = cc
+			continue
+		}
+		body := b.newBlock("typeswitch.body")
+		var next *Block
+		for _, casetype := range cc.List {
+			next = b.newBlock("typeswitch.next")
+			// casetype is a type, so don't call b.add(casetype).
+			// This block logically contains a type assertion,
+			// x.(casetype), but it's unclear how to represent x.
+			_ = casetype
+			b.ifelse(body, next)
+			b.current = next
+		}
+		b.current = body
+		b.typeCaseBody(cc, done)
+		b.current = next
+	}
+	if default_ != nil {
+		b.typeCaseBody(default_, done)
+	} else {
+		b.jump(done)
+	}
+	b.current = done
+}
+
+func (b *builder) typeCaseBody(cc *ast.CaseClause, done *Block) {
+	b.targets = &targets{
+		tail:   b.targets,
+		_break: done,
+	}
+	b.stmtList(cc.Body)
+	b.targets = b.targets.tail
+	b.jump(done)
+}
+
+func (b *builder) selectStmt(s *ast.SelectStmt, label *lblock) {
+	// First evaluate channel expressions.
+	// TODO(adonovan): fix: evaluate only channel exprs here.
+	for _, clause := range s.Body.List {
+		if comm := clause.(*ast.CommClause).Comm; comm != nil {
+			b.stmt(comm)
+		}
+	}
+
+	done := b.newBlock("select.done")
+	if label != nil {
+		label._break = done
+	}
+
+	var defaultBody *[]ast.Stmt
+	for _, cc := range s.Body.List {
+		clause := cc.(*ast.CommClause)
+		if clause.Comm == nil {
+			defaultBody = &clause.Body
+			continue
+		}
+		body := b.newBlock("select.body")
+		next := b.newBlock("select.next")
+		b.ifelse(body, next)
+		b.current = body
+		b.targets = &targets{
+			tail:   b.targets,
+			_break: done,
+		}
+		switch comm := clause.Comm.(type) {
+		case *ast.ExprStmt: // <-ch
+			// nop
+		case *ast.AssignStmt: // x := <-states[state].Chan
+			b.add(comm.Lhs[0])
+		}
+		b.stmtList(clause.Body)
+		b.targets = b.targets.tail
+		b.jump(done)
+		b.current = next
+	}
+	if defaultBody != nil {
+		b.targets = &targets{
+			tail:   b.targets,
+			_break: done,
+		}
+		b.stmtList(*defaultBody)
+		b.targets = b.targets.tail
+		b.jump(done)
+	}
+	b.current = done
+}
+
+func (b *builder) forStmt(s *ast.ForStmt, label *lblock) {
+	//	...init...
+	//      jump loop
+	// loop:
+	//      if cond goto body else done
+	// body:
+	//      ...body...
+	//      jump post
+	// post:				 (target of continue)
+	//      ...post...
+	//      jump loop
+	// done:                                 (target of break)
+	if s.Init != nil {
+		b.stmt(s.Init)
+	}
+	body := b.newBlock("for.body")
+	done := b.newBlock("for.done") // target of 'break'
+	loop := body                   // target of back-edge
+	if s.Cond != nil {
+		loop = b.newBlock("for.loop")
+	}
+	cont := loop // target of 'continue'
+	if s.Post != nil {
+		cont = b.newBlock("for.post")
+	}
+	if label != nil {
+		label._break = done
+		label._continue = cont
+	}
+	b.jump(loop)
+	b.current = loop
+	if loop != body {
+		b.add(s.Cond)
+		b.ifelse(body, done)
+		b.current = body
+	}
+	b.targets = &targets{
+		tail:      b.targets,
+		_break:    done,
+		_continue: cont,
+	}
+	b.stmt(s.Body)
+	b.targets = b.targets.tail
+	b.jump(cont)
+
+	if s.Post != nil {
+		b.current = cont
+		b.stmt(s.Post)
+		b.jump(loop) // back-edge
+	}
+	b.current = done
+}
+
+func (b *builder) rangeStmt(s *ast.RangeStmt, label *lblock) {
+	b.add(s.X)
+
+	if s.Key != nil {
+		b.add(s.Key)
+	}
+	if s.Value != nil {
+		b.add(s.Value)
+	}
+
+	//      ...
+	// loop:                                   (target of continue)
+	// 	if ... goto body else done
+	// body:
+	//      ...
+	// 	jump loop
+	// done:                                   (target of break)
+
+	loop := b.newBlock("range.loop")
+	b.jump(loop)
+	b.current = loop
+
+	body := b.newBlock("range.body")
+	done := b.newBlock("range.done")
+	b.ifelse(body, done)
+	b.current = body
+
+	if label != nil {
+		label._break = done
+		label._continue = loop
+	}
+	b.targets = &targets{
+		tail:      b.targets,
+		_break:    done,
+		_continue: loop,
+	}
+	b.stmt(s.Body)
+	b.targets = b.targets.tail
+	b.jump(loop) // back-edge
+	b.current = done
+}
+
+// -------- helpers --------
+
+// Destinations associated with unlabeled for/switch/select stmts.
+// We push/pop one of these as we enter/leave each construct and for
+// each BranchStmt we scan for the innermost target of the right type.
+//
+type targets struct {
+	tail         *targets // rest of stack
+	_break       *Block
+	_continue    *Block
+	_fallthrough *Block
+}
+
+// Destinations associated with a labeled block.
+// We populate these as labels are encountered in forward gotos or
+// labeled statements.
+//
+type lblock struct {
+	_goto     *Block
+	_break    *Block
+	_continue *Block
+}
+
+// labeledBlock returns the branch target associated with the
+// specified label, creating it if needed.
+//
+func (b *builder) labeledBlock(label *ast.Ident) *lblock {
+	lb := b.lblocks[label.Obj]
+	if lb == nil {
+		lb = &lblock{_goto: b.newBlock(label.Name)}
+		if b.lblocks == nil {
+			b.lblocks = make(map[*ast.Object]*lblock)
+		}
+		b.lblocks[label.Obj] = lb
+	}
+	return lb
+}
+
+// newBlock appends a new unconnected basic block to b.cfg's block
+// slice and returns it.
+// It does not automatically become the current block.
+// comment is an optional string for more readable debugging output.
+func (b *builder) newBlock(comment string) *Block {
+	g := b.cfg
+	block := &Block{
+		index:   int32(len(g.Blocks)),
+		comment: comment,
+	}
+	block.Succs = block.succs2[:0]
+	g.Blocks = append(g.Blocks, block)
+	return block
+}
+
+func (b *builder) newUnreachableBlock(comment string) *Block {
+	block := b.newBlock(comment)
+	block.unreachable = true
+	return block
+}
+
+func (b *builder) add(n ast.Node) {
+	b.current.Nodes = append(b.current.Nodes, n)
+}
+
+// jump adds an edge from the current block to the target block,
+// and sets b.current to nil.
+func (b *builder) jump(target *Block) {
+	b.current.Succs = append(b.current.Succs, target)
+	b.current = nil
+}
+
+// ifelse emits edges from the current block to the t and f blocks,
+// and sets b.current to nil.
+func (b *builder) ifelse(t, f *Block) {
+	b.current.Succs = append(b.current.Succs, t, f)
+	b.current = nil
+}
diff --git a/src/cmd/vet/internal/cfg/cfg.go b/src/cmd/vet/internal/cfg/cfg.go
new file mode 100644
index 0000000..e4d5bfe
--- /dev/null
+++ b/src/cmd/vet/internal/cfg/cfg.go
@@ -0,0 +1,142 @@
+// Copyright 2016 The Go 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 package constructs a simple control-flow graph (CFG) of the
+// statements and expressions within a single function.
+//
+// Use cfg.New to construct the CFG for a function body.
+//
+// The blocks of the CFG contain all the function's non-control
+// statements.  The CFG does not contain control statements such as If,
+// Switch, Select, and Branch, but does contain their subexpressions.
+// For example, this source code:
+//
+//	if x := f(); x != nil {
+//		T()
+//	} else {
+//		F()
+//	}
+//
+// produces this CFG:
+//
+//    1:  x := f()
+//        x != nil
+//        succs: 2, 3
+//    2:  T()
+//        succs: 4
+//    3:  F()
+//        succs: 4
+//    4:
+//
+// The CFG does contain Return statements; even implicit returns are
+// materialized (at the position of the function's closing brace).
+//
+// The CFG does not record conditions associated with conditional branch
+// edges, nor the short-circuit semantics of the && and || operators,
+// nor abnormal control flow caused by panic.  If you need this
+// information, use golang.org/x/tools/go/ssa instead.
+//
+package cfg
+
+// Although the vet tool has type information, it is often extremely
+// fragmentary, so for simplicity this package does not depend on
+// go/types.  Consequently control-flow conditions are ignored even
+// when constant, and "mayReturn" information must be provided by the
+// client.
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/format"
+	"go/token"
+)
+
+// A CFG represents the control-flow graph of a single function.
+//
+// The entry point is Blocks[0]; there may be multiple return blocks.
+type CFG struct {
+	Blocks []*Block // block[0] is entry; order otherwise undefined
+}
+
+// A Block represents a basic block: a list of statements and
+// expressions that are always evaluated sequentially.
+//
+// A block may have 0-2 successors: zero for a return block or a block
+// that calls a function such as panic that never returns; one for a
+// normal (jump) block; and two for a conditional (if) block.
+type Block struct {
+	Nodes []ast.Node // statements, expressions, and ValueSpecs
+	Succs []*Block   // successor nodes in the graph
+
+	comment     string    // for debugging
+	index       int32     // index within CFG.Blocks
+	unreachable bool      // is block of stmts following return/panic/for{}
+	succs2      [2]*Block // underlying array for Succs
+}
+
+// New returns a new control-flow graph for the specified function body,
+// which must be non-nil.
+//
+// The CFG builder calls mayReturn to determine whether a given function
+// call may return.  For example, calls to panic, os.Exit, and log.Fatal
+// do not return, so the builder can remove infeasible graph edges
+// following such calls.  The builder calls mayReturn only for a
+// CallExpr beneath an ExprStmt.
+func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG {
+	b := builder{
+		mayReturn: mayReturn,
+		cfg:       new(CFG),
+	}
+	b.current = b.newBlock("entry")
+	b.stmt(body)
+
+	// Does control fall off the end of the function's body?
+	// Make implicit return explicit.
+	if b.current != nil && !b.current.unreachable {
+		b.add(&ast.ReturnStmt{
+			Return: body.End() - 1,
+		})
+	}
+
+	return b.cfg
+}
+
+func (b *Block) String() string {
+	return fmt.Sprintf("block %d (%s)", b.index, b.comment)
+}
+
+// Return returns the return statement at the end of this block if present, nil otherwise.
+func (b *Block) Return() (ret *ast.ReturnStmt) {
+	if len(b.Nodes) > 0 {
+		ret, _ = b.Nodes[len(b.Nodes)-1].(*ast.ReturnStmt)
+	}
+	return
+}
+
+// Format formats the control-flow graph for ease of debugging.
+func (g *CFG) Format(fset *token.FileSet) string {
+	var buf bytes.Buffer
+	for _, b := range g.Blocks {
+		fmt.Fprintf(&buf, ".%d: # %s\n", b.index, b.comment)
+		for _, n := range b.Nodes {
+			fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
+		}
+		if len(b.Succs) > 0 {
+			fmt.Fprintf(&buf, "\tsuccs:")
+			for _, succ := range b.Succs {
+				fmt.Fprintf(&buf, " %d", succ.index)
+			}
+			buf.WriteByte('\n')
+		}
+		buf.WriteByte('\n')
+	}
+	return buf.String()
+}
+
+func formatNode(fset *token.FileSet, n ast.Node) string {
+	var buf bytes.Buffer
+	format.Node(&buf, fset, n)
+	// Indent secondary lines by a tab.
+	return string(bytes.Replace(buf.Bytes(), []byte("\n"), []byte("\n\t"), -1))
+}
diff --git a/src/cmd/vet/internal/cfg/cfg_test.go b/src/cmd/vet/internal/cfg/cfg_test.go
new file mode 100644
index 0000000..2400fed
--- /dev/null
+++ b/src/cmd/vet/internal/cfg/cfg_test.go
@@ -0,0 +1,190 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cfg
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/token"
+	"testing"
+)
+
+const src = `package main
+
+import "log"
+
+func f1() {
+	live()
+	return
+	dead()
+}
+
+func f2() {
+	for {
+		live()
+	}
+	dead()
+}
+
+func f3() {
+	if true { // even known values are ignored
+		return
+	}
+	for true { // even known values are ignored
+		live()
+	}
+	for {
+		live()
+	}
+	dead()
+}
+
+func f4(x int) {
+	switch x {
+	case 1:
+		live()
+		fallthrough
+	case 2:
+		live()
+		log.Fatal()
+	default:
+		panic("oops")
+	}
+	dead()
+}
+
+func f4(ch chan int) {
+	select {
+	case <-ch:
+		live()
+		return
+	default:
+		live()
+		panic("oops")
+	}
+	dead()
+}
+
+func f5(unknown bool) {
+	for {
+		if unknown {
+			break
+		}
+		continue
+		dead()
+	}
+	live()
+}
+
+func f6(unknown bool) {
+outer:
+	for {
+		for {
+			break outer
+			dead()
+		}
+		dead()
+	}
+	live()
+}
+
+func f7() {
+	for {
+		break nosuchlabel
+		dead()
+	}
+	dead()
+}
+
+func f8() {
+	select{}
+	dead()
+}
+
+func f9(ch chan int) {
+	select {
+	case <-ch:
+		return
+	}
+	dead()
+}
+
+func f10(ch chan int) {
+	select {
+	case <-ch:
+		return
+		dead()
+	default:
+	}
+	live()
+}
+
+func f11() {
+	goto; // mustn't crash
+	dead()
+}
+
+`
+
+func TestDeadCode(t *testing.T) {
+	// We'll use dead code detection to verify the CFG.
+
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, "dummy.go", src, parser.Mode(0))
+	if err != nil {
+		t.Fatal(err)
+	}
+	for _, decl := range f.Decls {
+		if decl, ok := decl.(*ast.FuncDecl); ok {
+			g := New(decl.Body, mayReturn)
+
+			// Mark blocks reachable from entry.
+			live := make(map[*Block]bool)
+			var visit func(*Block)
+			visit = func(b *Block) {
+				if !live[b] {
+					live[b] = true
+					for _, succ := range b.Succs {
+						visit(succ)
+					}
+				}
+			}
+			visit(g.Blocks[0])
+
+			// Print statements in unreachable blocks
+			// (in order determined by builder).
+			var buf bytes.Buffer
+			for _, b := range g.Blocks {
+				if !live[b] {
+					for _, n := range b.Nodes {
+						fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
+					}
+				}
+			}
+
+			// Check that the result contains "dead" at least once but not "live".
+			if !bytes.Contains(buf.Bytes(), []byte("dead")) ||
+				bytes.Contains(buf.Bytes(), []byte("live")) {
+				t.Errorf("unexpected dead statements in function %s:\n%s",
+					decl.Name.Name,
+					&buf)
+				t.Logf("control flow graph:\n%s", g.Format(fset))
+			}
+		}
+	}
+}
+
+// A trivial mayReturn predicate that looks only at syntax, not types.
+func mayReturn(call *ast.CallExpr) bool {
+	switch fun := call.Fun.(type) {
+	case *ast.Ident:
+		return fun.Name != "panic"
+	case *ast.SelectorExpr:
+		return fun.Sel.Name != "Fatal"
+	}
+	return true
+}
diff --git a/src/cmd/vet/internal/whitelist/whitelist.go b/src/cmd/vet/internal/whitelist/whitelist.go
index b6c8585..fdd65d3 100644
--- a/src/cmd/vet/internal/whitelist/whitelist.go
+++ b/src/cmd/vet/internal/whitelist/whitelist.go
@@ -5,37 +5,9 @@
 // Package whitelist defines exceptions for the vet tool.
 package 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.
+// UnkeyedLiteral is a white list of types in the standard packages
+// that are used with unkeyed literals we deem to be acceptable.
 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,
@@ -44,10 +16,13 @@ var UnkeyedLiteral = map[string]bool{
 	"image/color.Gray":    true,
 	"image/color.NRGBA64": true,
 	"image/color.NRGBA":   true,
+	"image/color.NYCbCrA": true,
 	"image/color.RGBA64":  true,
 	"image/color.RGBA":    true,
 	"image/color.YCbCr":   true,
 	"image.Point":         true,
 	"image.Rectangle":     true,
 	"image.Uniform":       true,
+
+	"unicode.Range16": true,
 }
diff --git a/src/cmd/vet/lostcancel.go b/src/cmd/vet/lostcancel.go
new file mode 100644
index 0000000..d049a3e
--- /dev/null
+++ b/src/cmd/vet/lostcancel.go
@@ -0,0 +1,318 @@
+// Copyright 2016 The Go Authors. 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/vet/internal/cfg"
+	"fmt"
+	"go/ast"
+	"go/types"
+	"strconv"
+)
+
+func init() {
+	register("lostcancel",
+		"check for failure to call cancelation function returned by context.WithCancel",
+		checkLostCancel,
+		funcDecl, funcLit)
+}
+
+const debugLostCancel = false
+
+var contextPackage = "context"
+
+// checkLostCancel reports a failure to the call the cancel function
+// returned by context.WithCancel, either because the variable was
+// assigned to the blank identifier, or because there exists a
+// control-flow path from the call to a return statement and that path
+// does not "use" the cancel function.  Any reference to the variable
+// counts as a use, even within a nested function literal.
+//
+// checkLostCancel analyzes a single named or literal function.
+func checkLostCancel(f *File, node ast.Node) {
+	// Fast path: bypass check if file doesn't use context.WithCancel.
+	if !hasImport(f.file, contextPackage) {
+		return
+	}
+
+	// Maps each cancel variable to its defining ValueSpec/AssignStmt.
+	cancelvars := make(map[*types.Var]ast.Node)
+
+	// Find the set of cancel vars to analyze.
+	stack := make([]ast.Node, 0, 32)
+	ast.Inspect(node, func(n ast.Node) bool {
+		switch n.(type) {
+		case *ast.FuncLit:
+			if len(stack) > 0 {
+				return false // don't stray into nested functions
+			}
+		case nil:
+			stack = stack[:len(stack)-1] // pop
+			return true
+		}
+		stack = append(stack, n) // push
+
+		// Look for [{AssignStmt,ValueSpec} CallExpr SelectorExpr]:
+		//
+		//   ctx, cancel    := context.WithCancel(...)
+		//   ctx, cancel     = context.WithCancel(...)
+		//   var ctx, cancel = context.WithCancel(...)
+		//
+		if isContextWithCancel(f, n) && isCall(stack[len(stack)-2]) {
+			var id *ast.Ident // id of cancel var
+			stmt := stack[len(stack)-3]
+			switch stmt := stmt.(type) {
+			case *ast.ValueSpec:
+				if len(stmt.Names) > 1 {
+					id = stmt.Names[1]
+				}
+			case *ast.AssignStmt:
+				if len(stmt.Lhs) > 1 {
+					id, _ = stmt.Lhs[1].(*ast.Ident)
+				}
+			}
+			if id != nil {
+				if id.Name == "_" {
+					f.Badf(id.Pos(), "the cancel function returned by context.%s should be called, not discarded, to avoid a context leak",
+						n.(*ast.SelectorExpr).Sel.Name)
+				} else if v, ok := f.pkg.uses[id].(*types.Var); ok {
+					cancelvars[v] = stmt
+				} else if v, ok := f.pkg.defs[id].(*types.Var); ok {
+					cancelvars[v] = stmt
+				}
+			}
+		}
+
+		return true
+	})
+
+	if len(cancelvars) == 0 {
+		return // no need to build CFG
+	}
+
+	// Tell the CFG builder which functions never return.
+	info := &types.Info{Uses: f.pkg.uses, Selections: f.pkg.selectors}
+	mayReturn := func(call *ast.CallExpr) bool {
+		name := callName(info, call)
+		return !noReturnFuncs[name]
+	}
+
+	// Build the CFG.
+	var g *cfg.CFG
+	var sig *types.Signature
+	switch node := node.(type) {
+	case *ast.FuncDecl:
+		sig, _ = f.pkg.defs[node.Name].Type().(*types.Signature)
+		g = cfg.New(node.Body, mayReturn)
+	case *ast.FuncLit:
+		sig, _ = f.pkg.types[node.Type].Type.(*types.Signature)
+		g = cfg.New(node.Body, mayReturn)
+	}
+
+	// Print CFG.
+	if debugLostCancel {
+		fmt.Println(g.Format(f.fset))
+	}
+
+	// Examine the CFG for each variable in turn.
+	// (It would be more efficient to analyze all cancelvars in a
+	// single pass over the AST, but seldom is there more than one.)
+	for v, stmt := range cancelvars {
+		if ret := lostCancelPath(f, g, v, stmt, sig); ret != nil {
+			lineno := f.fset.Position(stmt.Pos()).Line
+			f.Badf(stmt.Pos(), "the %s function is not used on all paths (possible context leak)", v.Name())
+			f.Badf(ret.Pos(), "this return statement may be reached without using the %s var defined on line %d", v.Name(), lineno)
+		}
+	}
+}
+
+func isCall(n ast.Node) bool { _, ok := n.(*ast.CallExpr); return ok }
+
+func hasImport(f *ast.File, path string) bool {
+	for _, imp := range f.Imports {
+		v, _ := strconv.Unquote(imp.Path.Value)
+		if v == path {
+			return true
+		}
+	}
+	return false
+}
+
+// isContextWithCancel reports whether n is one of the qualified identifiers
+// context.With{Cancel,Timeout,Deadline}.
+func isContextWithCancel(f *File, n ast.Node) bool {
+	if sel, ok := n.(*ast.SelectorExpr); ok {
+		switch sel.Sel.Name {
+		case "WithCancel", "WithTimeout", "WithDeadline":
+			if x, ok := sel.X.(*ast.Ident); ok {
+				if pkgname, ok := f.pkg.uses[x].(*types.PkgName); ok {
+					return pkgname.Imported().Path() == contextPackage
+				}
+				// Import failed, so we can't check package path.
+				// Just check the local package name (heuristic).
+				return x.Name == "context"
+			}
+		}
+	}
+	return false
+}
+
+// lostCancelPath finds a path through the CFG, from stmt (which defines
+// the 'cancel' variable v) to a return statement, that doesn't "use" v.
+// If it finds one, it returns the return statement (which may be synthetic).
+// sig is the function's type, if known.
+func lostCancelPath(f *File, g *cfg.CFG, v *types.Var, stmt ast.Node, sig *types.Signature) *ast.ReturnStmt {
+	vIsNamedResult := sig != nil && tupleContains(sig.Results(), v)
+
+	// uses reports whether stmts contain a "use" of variable v.
+	uses := func(f *File, v *types.Var, stmts []ast.Node) bool {
+		found := false
+		for _, stmt := range stmts {
+			ast.Inspect(stmt, func(n ast.Node) bool {
+				switch n := n.(type) {
+				case *ast.Ident:
+					if f.pkg.uses[n] == v {
+						found = true
+					}
+				case *ast.ReturnStmt:
+					// A naked return statement counts as a use
+					// of the named result variables.
+					if n.Results == nil && vIsNamedResult {
+						found = true
+					}
+				}
+				return !found
+			})
+		}
+		return found
+	}
+
+	// blockUses computes "uses" for each block, caching the result.
+	memo := make(map[*cfg.Block]bool)
+	blockUses := func(f *File, v *types.Var, b *cfg.Block) bool {
+		res, ok := memo[b]
+		if !ok {
+			res = uses(f, v, b.Nodes)
+			memo[b] = res
+		}
+		return res
+	}
+
+	// Find the var's defining block in the CFG,
+	// plus the rest of the statements of that block.
+	var defblock *cfg.Block
+	var rest []ast.Node
+outer:
+	for _, b := range g.Blocks {
+		for i, n := range b.Nodes {
+			if n == stmt {
+				defblock = b
+				rest = b.Nodes[i+1:]
+				break outer
+			}
+		}
+	}
+	if defblock == nil {
+		panic("internal error: can't find defining block for cancel var")
+	}
+
+	// Is v "used" in the remainder of its defining block?
+	if uses(f, v, rest) {
+		return nil
+	}
+
+	// Does the defining block return without using v?
+	if ret := defblock.Return(); ret != nil {
+		return ret
+	}
+
+	// Search the CFG depth-first for a path, from defblock to a
+	// return block, in which v is never "used".
+	seen := make(map[*cfg.Block]bool)
+	var search func(blocks []*cfg.Block) *ast.ReturnStmt
+	search = func(blocks []*cfg.Block) *ast.ReturnStmt {
+		for _, b := range blocks {
+			if !seen[b] {
+				seen[b] = true
+
+				// Prune the search if the block uses v.
+				if blockUses(f, v, b) {
+					continue
+				}
+
+				// Found path to return statement?
+				if ret := b.Return(); ret != nil {
+					if debugLostCancel {
+						fmt.Printf("found path to return in block %s\n", b)
+					}
+					return ret // found
+				}
+
+				// Recur
+				if ret := search(b.Succs); ret != nil {
+					if debugLostCancel {
+						fmt.Printf(" from block %s\n", b)
+					}
+					return ret
+				}
+			}
+		}
+		return nil
+	}
+	return search(defblock.Succs)
+}
+
+func tupleContains(tuple *types.Tuple, v *types.Var) bool {
+	for i := 0; i < tuple.Len(); i++ {
+		if tuple.At(i) == v {
+			return true
+		}
+	}
+	return false
+}
+
+var noReturnFuncs = map[string]bool{
+	"(*testing.common).FailNow": true,
+	"(*testing.common).Fatal":   true,
+	"(*testing.common).Fatalf":  true,
+	"(*testing.common).Skip":    true,
+	"(*testing.common).SkipNow": true,
+	"(*testing.common).Skipf":   true,
+	"log.Fatal":                 true,
+	"log.Fatalf":                true,
+	"log.Fatalln":               true,
+	"os.Exit":                   true,
+	"panic":                     true,
+	"runtime.Goexit":            true,
+}
+
+// callName returns the canonical name of the builtin, method, or
+// function called by call, if known.
+func callName(info *types.Info, call *ast.CallExpr) string {
+	switch fun := call.Fun.(type) {
+	case *ast.Ident:
+		// builtin, e.g. "panic"
+		if obj, ok := info.Uses[fun].(*types.Builtin); ok {
+			return obj.Name()
+		}
+	case *ast.SelectorExpr:
+		if sel, ok := info.Selections[fun]; ok && sel.Kind() == types.MethodVal {
+			// method call, e.g. "(*testing.common).Fatal"
+			meth := sel.Obj()
+			return fmt.Sprintf("(%s).%s",
+				meth.Type().(*types.Signature).Recv().Type(),
+				meth.Name())
+		}
+		if obj, ok := info.Uses[fun.Sel]; ok {
+			// qualified identifier, e.g. "os.Exit"
+			return fmt.Sprintf("%s.%s",
+				obj.Pkg().Path(),
+				obj.Name())
+		}
+	}
+
+	// function with no name, or defined in missing imported package
+	return ""
+}
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
index 23c041b..4f3cca8 100644
--- a/src/cmd/vet/main.go
+++ b/src/cmd/vet/main.go
@@ -24,10 +24,9 @@ import (
 )
 
 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
+	verbose = flag.Bool("v", false, "verbose")
+	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
@@ -101,7 +100,7 @@ func (ts *triState) Set(value string) error {
 func (ts *triState) String() string {
 	switch *ts {
 	case unset:
-		return "unset"
+		return "true" // An unset flag will be set by -all, so defaults to true.
 	case setTrue:
 		return "true"
 	case setFalse:
@@ -116,13 +115,10 @@ func (ts triState) IsBoolFlag() bool {
 
 // 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
+// setExit sets the value for os.Exit when it is called, later. It
 // remembers the highest value.
 func setExit(err int) {
 	if err > exitCode {
@@ -143,6 +139,7 @@ var (
 	genDecl       *ast.GenDecl
 	interfaceType *ast.InterfaceType
 	rangeStmt     *ast.RangeStmt
+	returnStmt    *ast.ReturnStmt
 
 	// checkers is a two-level map.
 	// The outer level is keyed by a nil pointer, one of the AST vars above.
@@ -167,8 +164,9 @@ 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, "By default, -all is set and all non-experimental checks are run.\n")
 	fmt.Fprintf(os.Stderr, "For more information run\n")
-	fmt.Fprintf(os.Stderr, "\tgodoc cmd/vet\n\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc cmd/vet\n\n")
 	fmt.Fprintf(os.Stderr, "Flags:\n")
 	flag.PrintDefaults()
 	os.Exit(2)
@@ -184,6 +182,9 @@ type File struct {
 	file    *ast.File
 	b       bytes.Buffer // for use by methods
 
+	// Parsed package "foo" when checking package "foo_test"
+	basePkg *Package
+
 	// 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
@@ -240,7 +241,7 @@ func main() {
 		}
 		os.Exit(exitCode)
 	}
-	if !doPackage(".", flag.Args()) {
+	if doPackage(".", flag.Args(), nil) == nil {
 		warnf("no files checked")
 	}
 	os.Exit(exitCode)
@@ -280,12 +281,12 @@ func doPackageDir(directory string) {
 	names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
 	names = append(names, pkg.SFiles...)
 	prefixDirectory(directory, names)
-	doPackage(directory, names)
+	basePkg := doPackage(directory, names, nil)
 	// 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)
+		doPackage(directory, names, basePkg)
 	}
 }
 
@@ -301,8 +302,8 @@ type Package struct {
 }
 
 // doPackage analyzes the single package constructed from the named files.
-// It returns whether any files were checked.
-func doPackage(directory string, names []string) bool {
+// It returns the parsed Package or nil if none of the files have been checked.
+func doPackage(directory string, names []string, basePkg *Package) *Package {
 	var files []*File
 	var astFiles []*ast.File
 	fs := token.NewFileSet()
@@ -311,7 +312,7 @@ func doPackage(directory string, names []string) bool {
 		if err != nil {
 			// Warn but continue to next package.
 			warnf("%s: %s", name, err)
-			return false
+			return nil
 		}
 		checkBuildTag(name, data)
 		var parsedFile *ast.File
@@ -319,14 +320,14 @@ func doPackage(directory string, names []string) bool {
 			parsedFile, err = parser.ParseFile(fs, name, data, 0)
 			if err != nil {
 				warnf("%s: %s", name, err)
-				return false
+				return nil
 			}
 			astFiles = append(astFiles, parsedFile)
 		}
 		files = append(files, &File{fset: fs, content: data, name: name, file: parsedFile})
 	}
 	if len(astFiles) == 0 {
-		return false
+		return nil
 	}
 	pkg := new(Package)
 	pkg.path = astFiles[0].Name.Name
@@ -348,13 +349,14 @@ func doPackage(directory string, names []string) bool {
 	}
 	for _, file := range files {
 		file.pkg = pkg
+		file.basePkg = basePkg
 		file.checkers = chk
 		if file.file != nil {
 			file.walkFile(file.name, file.file)
 		}
 	}
 	asmCheck(pkg)
-	return true
+	return pkg
 }
 
 func visit(path string, f os.FileInfo, err error) error {
@@ -435,17 +437,17 @@ func (f *File) loc(pos token.Pos) string {
 	// 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)
+	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...))
+	fmt.Fprintf(os.Stderr, "%s: %s", 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...)
+	fmt.Fprintf(os.Stderr, "%s: %s\n", f.loc(pos), fmt.Sprintf(format, args...))
 }
 
 // walkFile walks the file's tree.
@@ -480,6 +482,8 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
 		key = interfaceType
 	case *ast.RangeStmt:
 		key = rangeStmt
+	case *ast.ReturnStmt:
+		key = returnStmt
 	}
 	for _, fn := range f.checkers[key] {
 		fn(f, node)
diff --git a/src/cmd/vet/method.go b/src/cmd/vet/method.go
index 00949df..8a554e1 100644
--- a/src/cmd/vet/method.go
+++ b/src/cmd/vet/method.go
@@ -26,10 +26,10 @@ type MethodSig struct {
 }
 
 // canonicalMethods lists the input and output types for Go methods
-// that are checked using dynamic interface checks.  Because the
+// 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
+// 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.
@@ -39,7 +39,7 @@ type MethodSig struct {
 // 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
+// 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
diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go
index a16e864..f4b985c 100644
--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -35,48 +35,107 @@ func initPrintFlags() {
 		if len(name) == 0 {
 			flag.Usage()
 		}
-		skip := 0
+
+		// Backwards compatibility: skip optional first argument
+		// index after the colon.
 		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
+			isFormattedPrint[name] = true
 		} else {
-			printList[name] = skip
+			isPrint[name] = true
 		}
 	}
 }
 
-// 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,
+// isFormattedPrint records the formatted-print functions. Names are
+// lower-cased so the lookup is case insensitive.
+var isFormattedPrint = map[string]bool{
+	"errorf":  true,
+	"fatalf":  true,
+	"fprintf": true,
+	"logf":    true,
+	"panicf":  true,
+	"printf":  true,
+	"sprintf": true,
+}
+
+// isPrint records the unformatted-print functions. Names are lower-cased
+// so the lookup is case insensitive.
+var isPrint = map[string]bool{
+	"error":    true,
+	"fatal":    true,
+	"fprint":   true,
+	"fprintln": true,
+	"log":      true,
+	"panic":    true,
+	"panicln":  true,
+	"print":    true,
+	"println":  true,
+	"sprint":   true,
+	"sprintln": true,
+}
+
+// formatString returns the format string argument and its index within
+// the given printf-like call expression.
+//
+// The last parameter before variadic arguments is assumed to be
+// a format string.
+//
+// The first string literal or string constant is assumed to be a format string
+// if the call's signature cannot be determined.
+//
+// If it cannot find any format string parameter, it returns  ("", -1).
+func formatString(f *File, call *ast.CallExpr) (string, int) {
+	typ := f.pkg.types[call.Fun].Type
+	if typ != nil {
+		if sig, ok := typ.(*types.Signature); ok {
+			if !sig.Variadic() {
+				// Skip checking non-variadic functions
+				return "", -1
+			}
+			idx := sig.Params().Len() - 2
+			if idx < 0 {
+				// Skip checking variadic functions without
+				// fixed arguments.
+				return "", -1
+			}
+			s, ok := stringLiteralArg(f, call, idx)
+			if !ok {
+				// The last argument before variadic args isn't a string
+				return "", -1
+			}
+			return s, idx
+		}
+	}
+
+	// Cannot determine call's signature. Fallback to scanning for the first
+	// string argument in the call
+	for idx := range call.Args {
+		if s, ok := stringLiteralArg(f, call, idx); ok {
+			return s, idx
+		}
+	}
+	return "", -1
 }
 
-// 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,
+// stringLiteralArg returns call's string constant argument at the index idx.
+//
+// ("", false) is returned if call's argument at the index idx isn't a string
+// literal.
+func stringLiteralArg(f *File, call *ast.CallExpr, idx int) (string, bool) {
+	if idx >= len(call.Args) {
+		return "", false
+	}
+	arg := call.Args[idx]
+	lit := f.pkg.types[arg].Value
+	if lit != nil && lit.Kind() == constant.String {
+		return constant.StringVal(lit), true
+	}
+	return "", false
 }
 
 // checkCall triggers the print-specific checks if the call invokes a print function.
@@ -109,12 +168,12 @@ func checkFmtPrintfCall(f *File, node ast.Node) {
 	}
 
 	name := strings.ToLower(Name)
-	if skip, ok := printfList[name]; ok {
-		f.checkPrintf(call, Name, skip)
+	if _, ok := isFormattedPrint[name]; ok {
+		f.checkPrintf(call, Name)
 		return
 	}
-	if skip, ok := printList[name]; ok {
-		f.checkPrint(call, Name, skip)
+	if _, ok := isPrint[name]; ok {
+		f.checkPrint(call, Name)
 		return
 	}
 }
@@ -146,25 +205,16 @@ type formatState struct {
 }
 
 // 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 {
+func (f *File) checkPrintf(call *ast.CallExpr, name string) {
+	format, idx := formatString(f, call)
+	if idx < 0 {
 		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.
+
+	firstArg := idx + 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)
@@ -534,25 +584,38 @@ func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, isStar bool, s
 }
 
 // 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
-				}
-			}
+func (f *File) checkPrint(call *ast.CallExpr, name string) {
+	firstArg := 0
+	typ := f.pkg.types[call.Fun].Type
+	if typ == nil {
+		// Skip checking functions with unknown type.
+		return
+	}
+	if sig, ok := typ.(*types.Signature); ok {
+		if !sig.Variadic() {
+			// Skip checking non-variadic functions.
+			return
 		}
+		params := sig.Params()
+		firstArg = params.Len() - 1
+
+		typ := params.At(firstArg).Type()
+		typ = typ.(*types.Slice).Elem()
+		it, ok := typ.(*types.Interface)
+		if !ok || !it.Empty() {
+			// Skip variadic functions accepting non-interface{} args.
+			return
+		}
+	}
+	args := call.Args
+	if len(args) <= firstArg {
+		// Skip calls without variadic args.
+		return
 	}
+	args = args[firstArg:]
+
 	// check for Println(os.Stderr, ...)
-	if firstArg == 0 && !isF && len(args) > 0 {
+	if firstArg == 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") {
@@ -561,31 +624,15 @@ func (f *File) checkPrint(call *ast.CallExpr, name string, firstArg int) {
 			}
 		}
 	}
-	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]
+	arg := args[0]
 	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 {
+	if strings.HasSuffix(name, "ln") {
 		// The last item, if a string, should not have a newline.
-		arg = args[len(call.Args)-1]
+		arg = args[len(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)
diff --git a/src/cmd/vet/rangeloop.go b/src/cmd/vet/rangeloop.go
index 11eef59..e085e21 100644
--- a/src/cmd/vet/rangeloop.go
+++ b/src/cmd/vet/rangeloop.go
@@ -62,6 +62,10 @@ func checkRangeLoop(f *File, node ast.Node) {
 		if !ok || id.Obj == nil {
 			return true
 		}
+		if f.pkg.types[id].Type == nil {
+			// Not referring to a variable
+			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")
 		}
diff --git a/src/cmd/vet/shadow.go b/src/cmd/vet/shadow.go
index 5d0d6b5..29c952f 100644
--- a/src/cmd/vet/shadow.go
+++ b/src/cmd/vet/shadow.go
@@ -232,7 +232,7 @@ func checkShadowing(f *File, ident *ast.Ident) {
 		// the shadowing identifier.
 		span, ok := f.pkg.spans[shadowed]
 		if !ok {
-			f.Badf(ident.Pos(), "internal error: no range for %s", ident.Name)
+			f.Badf(ident.Pos(), "internal error: no range for %q", ident.Name)
 			return
 		}
 		if !span.contains(ident.Pos()) {
@@ -241,6 +241,6 @@ func checkShadowing(f *File, ident *ast.Ident) {
 	}
 	// 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()))
+		f.Badf(ident.Pos(), "declaration of %q shadows declaration at %s", obj.Name(), f.loc(shadowed.Pos()))
 	}
 }
diff --git a/src/cmd/vet/structtag.go b/src/cmd/vet/structtag.go
index e8164a4..abff14f 100644
--- a/src/cmd/vet/structtag.go
+++ b/src/cmd/vet/structtag.go
@@ -111,7 +111,7 @@ func validateStructTag(tag string) error {
 		if i >= len(tag) {
 			return errTagValueSyntax
 		}
-		qvalue := string(tag[:i+1])
+		qvalue := tag[:i+1]
 		tag = tag[i+1:]
 
 		if _, err := strconv.Unquote(qvalue); err != nil {
diff --git a/src/cmd/vet/testdata/asm.go b/src/cmd/vet/testdata/asm.go
index 9a3d531..8194710 100644
--- a/src/cmd/vet/testdata/asm.go
+++ b/src/cmd/vet/testdata/asm.go
@@ -31,3 +31,5 @@ func nosplit(x int)
 func rodata(x int)
 func noptr(x int)
 func wrapper(x int)
+
+func f15271() (x uint32)
diff --git a/src/cmd/vet/testdata/asm1.s b/src/cmd/vet/testdata/asm1.s
index 62f423c..2c6f13b 100644
--- a/src/cmd/vet/testdata/asm1.s
+++ b/src/cmd/vet/testdata/asm1.s
@@ -252,3 +252,14 @@ TEXT ·returnnamed(SB),0,$0-41
 
 TEXT ·returnintmissing(SB),0,$0-8
 	RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
+
+
+// issue 15271
+TEXT ·f15271(SB), NOSPLIT, $0-4
+    // Stick 123 into the low 32 bits of X0.
+    MOVQ $123, AX
+    PINSRD $0, AX, X0
+
+    // Return them.
+    PEXTRD $0, X0, x+0(FP)
+    RET
diff --git a/src/cmd/vet/testdata/asm5.s b/src/cmd/vet/testdata/asm5.s
new file mode 100644
index 0000000..c6176e9
--- /dev/null
+++ b/src/cmd/vet/testdata/asm5.s
@@ -0,0 +1,193 @@
+// Copyright 2016 The Go 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 mips64
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+	MOVB	x+0(FP), R1
+	MOVBU	y+1(FP), R2
+	MOVH	x+0(FP), R1 // ERROR "\[mips64\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
+	MOVHU	y+1(FP), R1 // ERROR "invalid MOVHU of y\+1\(FP\); uint8 is 1-byte value"
+	MOVW	x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+	MOVWU	y+1(FP), R1 // ERROR "invalid MOVWU of y\+1\(FP\); uint8 is 1-byte value"
+	MOVV	x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int8 is 1-byte value"
+	MOVV	y+1(FP), R1 // ERROR "invalid MOVV of y\+1\(FP\); uint8 is 1-byte value"
+	MOVB	x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+	MOVBU	y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+	MOVB	16(R29), R1 // ERROR "16\(R29\) should be x\+0\(FP\)"
+	MOVB	17(R29), R1 // ERROR "17\(R29\) should be y\+1\(FP\)"
+	MOVB	18(R29), R1 // ERROR "use of 18\(R29\) points beyond argument frame"
+	RET
+
+TEXT ·arg2(SB),0,$0-4
+	MOVBU	x+0(FP), R1 // ERROR "arg2: invalid MOVBU of x\+0\(FP\); int16 is 2-byte value"
+	MOVB	y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+	MOVHU	x+0(FP), R1
+	MOVH	y+2(FP), R2
+	MOVWU	x+0(FP), R1 // ERROR "invalid MOVWU of x\+0\(FP\); int16 is 2-byte value"
+	MOVW	y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
+	MOVV	x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int16 is 2-byte value"
+	MOVV	y+2(FP), R1 // ERROR "invalid MOVV of y\+2\(FP\); uint16 is 2-byte value"
+	MOVHU	x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+	MOVH	y+0(FP), R1 // 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), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+	MOVB	y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+	MOVH	x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
+	MOVH	y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
+	MOVW	x+0(FP), R1
+	MOVW	y+4(FP), R1
+	MOVV	x+0(FP), R1 // ERROR "invalid MOVV of x\+0\(FP\); int32 is 4-byte value"
+	MOVV	y+4(FP), R1 // ERROR "invalid MOVV of y\+4\(FP\); uint32 is 4-byte value"
+	MOVW	x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	MOVW	y+2(FP), R1 // 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), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+	MOVB	y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+	MOVH	x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
+	MOVH	y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
+	MOVW	x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+	MOVW	y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+	MOVV	x+0(FP), R1
+	MOVV	y+8(FP), R1
+	MOVV	x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	MOVV	y+2(FP), R1 // 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), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
+	MOVB	y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
+	MOVH	x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value"
+	MOVH	y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value"
+	MOVW	x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
+	MOVW	y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
+	MOVV	x+0(FP), R1
+	MOVV	y+8(FP), R1
+	MOVV	x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	MOVV	y+2(FP), R1 // 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), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
+	MOVB	y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
+	MOVH	x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value"
+	MOVH	y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value"
+	MOVW	x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
+	MOVW	y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
+	MOVV	x+0(FP), R1
+	MOVV	y+8(FP), R1
+	MOVV	x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	MOVV	y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	MOVW	c+16(FP), R1 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value"
+	MOVW	m+24(FP), R1 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value"
+	MOVW	f+32(FP), R1 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value"
+	RET
+
+TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
+	MOVH	x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value"
+	MOVW	x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
+	MOVV	x+0(FP), R1
+	MOVH	x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value"
+	MOVW	x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
+	MOVV	x_base+0(FP), R1
+	MOVH	x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVW	x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVV	x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVH	x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value"
+	MOVW	x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
+	MOVV	x_len+8(FP), R1
+	MOVV	y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
+	MOVV	y_len+8(FP), R1 // 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"
+	MOVH	x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value"
+	MOVW	x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
+	MOVV	x+0(FP), R1
+	MOVH	x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value"
+	MOVW	x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
+	MOVV	x_base+0(FP), R1
+	MOVH	x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVW	x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVV	x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVH	x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value"
+	MOVW	x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
+	MOVV	x_len+8(FP), R1
+	MOVH	x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+	MOVW	x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+	MOVV	x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+	MOVH	x_cap+16(FP), R1 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value"
+	MOVW	x_cap+16(FP), R1 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
+	MOVV	x_cap+16(FP), R1
+	MOVV	y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
+	MOVV	y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
+	MOVV	y_cap+16(FP), R1 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
+	RET
+
+TEXT ·argiface(SB),0,$0-32
+	MOVH	x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value"
+	MOVW	x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
+	MOVV	x+0(FP), R1
+	MOVH	x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value"
+	MOVW	x_type+0(FP), R1 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
+	MOVV	x_type+0(FP), R1
+	MOVV	x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+	MOVV	x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+	MOVH	x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+	MOVW	x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+	MOVV	x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+	MOVH	x_data+8(FP), R1 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value"
+	MOVW	x_data+8(FP), R1 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
+	MOVV	x_data+8(FP), R1
+	MOVH	y+16(FP), R1 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value"
+	MOVW	y+16(FP), R1 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
+	MOVV	y+16(FP), R1
+	MOVH	y_itable+16(FP), R1 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value"
+	MOVW	y_itable+16(FP), R1 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
+	MOVV	y_itable+16(FP), R1
+	MOVV	y_type+16(FP), R1 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
+	MOVH	y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+	MOVW	y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+	MOVV	y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+	MOVH	y_data+24(FP), R1 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value"
+	MOVW	y_data+24(FP), R1 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
+	MOVV	y_data+24(FP), R1
+	RET
+
+TEXT ·returnint(SB),0,$0-8
+	MOVB	R1, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
+	MOVH	R1, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value"
+	MOVW	R1, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
+	MOVV	R1, ret+0(FP)
+	MOVV	R1, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+	MOVV	R1, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+	RET
+
+TEXT ·returnbyte(SB),0,$0-9
+	MOVV	x+0(FP), R1
+	MOVB	R1, ret+8(FP)
+	MOVH	R1, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value"
+	MOVW	R1, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
+	MOVV	R1, ret+8(FP) // ERROR "invalid MOVV of ret\+8\(FP\); byte is 1-byte value"
+	MOVB	R1, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
+	RET
+
+TEXT ·returnnamed(SB),0,$0-41
+	MOVB	x+0(FP), R1
+	MOVV	R1, r1+8(FP)
+	MOVH	R1, r2+16(FP)
+	MOVV	R1, r3+24(FP)
+	MOVV	R1, r3_base+24(FP)
+	MOVV	R1, r3_len+32(FP)
+	MOVB	R1, r4+40(FP)
+	MOVW	R1, r1+8(FP) // ERROR "invalid MOVW 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/atomic.go b/src/cmd/vet/testdata/atomic.go
index 1ba261d..d5a8e61 100644
--- a/src/cmd/vet/testdata/atomic.go
+++ b/src/cmd/vet/testdata/atomic.go
@@ -40,4 +40,13 @@ func AtomicTests() {
 	*ap[1] = atomic.AddUint64(ap[0], 1)
 
 	x = atomic.AddUint64() // Used to make vet crash; now silently ignored.
+
+	{
+		// A variable declaration creates a new variable in the current scope.
+		x := atomic.AddUint64(&x, 1) // ERROR "declaration of .x. shadows declaration at testdata/atomic.go:16"
+
+		// Re-declaration assigns a new value.
+		x, w := atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
+		_ = w
+	}
 }
diff --git a/src/cmd/vet/testdata/buildtag.go b/src/cmd/vet/testdata/buildtag.go
index eb36fd3..f12f895 100644
--- a/src/cmd/vet/testdata/buildtag.go
+++ b/src/cmd/vet/testdata/buildtag.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/cmd/vet/testdata/composite.go b/src/cmd/vet/testdata/composite.go
index 69e7d7c..2e6ce26 100644
--- a/src/cmd/vet/testdata/composite.go
+++ b/src/cmd/vet/testdata/composite.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.
 
-// This file contains tests for the untagged struct literal checker.
-
 // This file contains the test for untagged struct literals.
 
 package testdata
@@ -11,6 +9,10 @@ package testdata
 import (
 	"flag"
 	"go/scanner"
+	"image"
+	"unicode"
+
+	"path/to/unknownpkg"
 )
 
 var Okay1 = []string{
@@ -35,29 +37,67 @@ var Okay3 = struct {
 	"DefValue",
 }
 
+var Okay4 = []struct {
+	A int
+	B int
+}{
+	{1, 2},
+	{3, 4},
+}
+
 type MyStruct struct {
 	X string
 	Y string
 	Z string
 }
 
-var Okay4 = MyStruct{
+var Okay5 = &MyStruct{
 	"Name",
 	"Usage",
 	"DefValue",
 }
 
+var Okay6 = []MyStruct{
+	{"foo", "bar", "baz"},
+	{"aa", "bb", "cc"},
+}
+
 // Testing is awkward because we need to reference things from a separate package
 // to trigger the warnings.
 
-var BadStructLiteralUsedInTests = flag.Flag{ // ERROR "unkeyed fields"
+var goodStructLiteral = flag.Flag{
+	Name:  "Name",
+	Usage: "Usage",
+}
+var badStructLiteral = 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}
+// SpecialCase is a named slice of CaseRange to test issue 9171.
+var goodNamedSliceLiteral = unicode.SpecialCase{
+	{Lo: 1, Hi: 2},
+	unicode.CaseRange{Lo: 1, Hi: 2},
+}
+var badNamedSliceLiteral = unicode.SpecialCase{
+	{1, 2},                  // ERROR "unkeyed fields"
+	unicode.CaseRange{1, 2}, // ERROR "unkeyed fields"
+}
+
+// ErrorList is a named slice, so no warnings should be emitted.
+var goodScannerErrorList = scanner.ErrorList{
+	&scanner.Error{Msg: "foobar"},
+}
+var badScannerErrorList = scanner.ErrorList{
+	&scanner.Error{"foobar"}, // ERROR "unkeyed fields"
+}
+
+// Check whitelisted structs: if vet is run with --compositewhitelist=false,
+// this line triggers an error.
+var whitelistedPoint = image.Point{1, 2}
+
+// Do not check type from unknown package.
+// See issue 15408.
+var unknownPkgVar = unknownpkg.Foobar{"foo", "bar"}
diff --git a/src/cmd/vet/testdata/copylock.go b/src/cmd/vet/testdata/copylock.go
index 03d0c33..d49f468 100644
--- a/src/cmd/vet/testdata/copylock.go
+++ b/src/cmd/vet/testdata/copylock.go
@@ -1,12 +1,36 @@
 package testdata
 
-import "sync"
+import (
+	"sync"
+	"sync/atomic"
+)
 
 func OkFunc() {
 	var x *sync.Mutex
 	p := x
 	var y sync.Mutex
 	p = &y
+
+	var z = sync.Mutex{}
+	w := sync.Mutex{}
+
+	w = sync.Mutex{}
+	q := struct{ L sync.Mutex }{
+		L: sync.Mutex{},
+	}
+
+	yy := []Tlock{
+		Tlock{},
+		Tlock{
+			once: sync.Once{},
+		},
+	}
+
+	nl := new(sync.Mutex)
+	mx := make([]sync.Mutex, 10)
+	xx := struct{ L *sync.Mutex }{
+		L: new(sync.Mutex),
+	}
 }
 
 type Tlock struct {
@@ -25,4 +49,92 @@ func BadFunc() {
 	tp = &t
 	*tp = t // ERROR "assignment copies lock value to \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
 	t = *tp // ERROR "assignment copies lock value to t: testdata.Tlock contains sync.Once contains sync.Mutex"
+
+	y := *x   // ERROR "assignment copies lock value to y: sync.Mutex"
+	var z = t // ERROR "variable declaration copies lock value to z: testdata.Tlock contains sync.Once contains sync.Mutex"
+
+	w := struct{ L sync.Mutex }{
+		L: *x, // ERROR "literal copies lock value from \*x: sync.Mutex"
+	}
+	var q = map[int]Tlock{
+		1: t,   // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex"
+		2: *tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
+	}
+	yy := []Tlock{
+		t,   // ERROR "literal copies lock value from t: testdata.Tlock contains sync.Once contains sync.Mutex"
+		*tp, // ERROR "literal copies lock value from \*tp: testdata.Tlock contains sync.Once contains sync.Mutex"
+	}
+
+	// override 'new' keyword
+	new := func(interface{}) {}
+	new(t) // ERROR "function call copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
+}
+
+// SyncTypesCheck checks copying of sync.* types except sync.Mutex
+func SyncTypesCheck() {
+	// sync.RWMutex copying
+	var rwmuX sync.RWMutex
+	var rwmuXX = sync.RWMutex{}
+	rwmuX1 := new(sync.RWMutex)
+	rwmuY := rwmuX     // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
+	rwmuY = rwmuX      // ERROR "assignment copies lock value to rwmuY: sync.RWMutex"
+	var rwmuYY = rwmuX // ERROR "variable declaration copies lock value to rwmuYY: sync.RWMutex"
+	rwmuP := &rwmuX
+	rwmuZ := &sync.RWMutex{}
+
+	// sync.Cond copying
+	var condX sync.Cond
+	var condXX = sync.Cond{}
+	condX1 := new(sync.Cond)
+	condY := condX     // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
+	condY = condX      // ERROR "assignment copies lock value to condY: sync.Cond contains sync.noCopy"
+	var condYY = condX // ERROR "variable declaration copies lock value to condYY: sync.Cond contains sync.noCopy"
+	condP := &condX
+	condZ := &sync.Cond{
+		L: &sync.Mutex{},
+	}
+	condZ = sync.NewCond(&sync.Mutex{})
+
+	// sync.WaitGroup copying
+	var wgX sync.WaitGroup
+	var wgXX = sync.WaitGroup{}
+	wgX1 := new(sync.WaitGroup)
+	wgY := wgX     // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
+	wgY = wgX      // ERROR "assignment copies lock value to wgY: sync.WaitGroup contains sync.noCopy"
+	var wgYY = wgX // ERROR "variable declaration copies lock value to wgYY: sync.WaitGroup contains sync.noCopy"
+	wgP := &wgX
+	wgZ := &sync.WaitGroup{}
+
+	// sync.Pool copying
+	var poolX sync.Pool
+	var poolXX = sync.Pool{}
+	poolX1 := new(sync.Pool)
+	poolY := poolX     // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
+	poolY = poolX      // ERROR "assignment copies lock value to poolY: sync.Pool contains sync.noCopy"
+	var poolYY = poolX // ERROR "variable declaration copies lock value to poolYY: sync.Pool contains sync.noCopy"
+	poolP := &poolX
+	poolZ := &sync.Pool{}
+
+	// sync.Once copying
+	var onceX sync.Once
+	var onceXX = sync.Once{}
+	onceX1 := new(sync.Once)
+	onceY := onceX     // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
+	onceY = onceX      // ERROR "assignment copies lock value to onceY: sync.Once contains sync.Mutex"
+	var onceYY = onceX // ERROR "variable declaration copies lock value to onceYY: sync.Once contains sync.Mutex"
+	onceP := &onceX
+	onceZ := &sync.Once{}
+}
+
+// AtomicTypesCheck checks copying of sync/atomic types
+func AtomicTypesCheck() {
+	// atomic.Value copying
+	var vX atomic.Value
+	var vXX = atomic.Value{}
+	vX1 := new(atomic.Value)
+	vY := vX     // ERROR "assignment copies lock value to vY: sync/atomic.Value contains sync/atomic.noCopy"
+	vY = vX      // ERROR "assignment copies lock value to vY: sync/atomic.Value contains sync/atomic.noCopy"
+	var vYY = vX // ERROR "variable declaration copies lock value to vYY: sync/atomic.Value contains sync/atomic.noCopy"
+	vP := &vX
+	vZ := &atomic.Value{}
 }
diff --git a/src/cmd/vet/testdata/copylock_func.go b/src/cmd/vet/testdata/copylock_func.go
index 62725d9..bfafa12 100644
--- a/src/cmd/vet/testdata/copylock_func.go
+++ b/src/cmd/vet/testdata/copylock_func.go
@@ -12,7 +12,7 @@ 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"
+func BadRet() sync.Mutex {} // Don't warn about results
 
 var (
 	OkClosure  = func(*sync.Mutex) {}
@@ -28,7 +28,7 @@ func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: test
 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"
+func BadRet() EmbeddedRWMutex    {} // Don't warn about results
 
 type FieldMutex struct {
 	s sync.Mutex
@@ -78,6 +78,43 @@ func (*CustomLock) Unlock() {}
 func Ok(*CustomLock) {}
 func Bad(CustomLock) {} // ERROR "Bad passes lock by value: testdata.CustomLock"
 
+// Passing lock values into interface function arguments
+func FuncCallInterfaceArg(f func(a int, b interface{})) {
+	var m sync.Mutex
+	var t struct{ lock sync.Mutex }
+
+	f(1, "foo")
+	f(2, &t)
+	f(3, &sync.Mutex{})
+	f(4, m) // ERROR "function call copies lock value: sync.Mutex"
+	f(5, t) // ERROR "function call copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
+}
+
+// Returning lock via interface value
+func ReturnViaInterface(x int) (int, interface{}) {
+	var m sync.Mutex
+	var t struct{ lock sync.Mutex }
+
+	switch x % 4 {
+	case 0:
+		return 0, "qwe"
+	case 1:
+		return 1, &sync.Mutex{}
+	case 2:
+		return 2, m // ERROR "return copies lock value: sync.Mutex"
+	default:
+		return 3, t // ERROR "return copies lock value: struct{lock sync.Mutex} contains sync.Mutex"
+	}
+}
+
+// Some cases that we don't warn about.
+
+func AcceptedCases() {
+	x := EmbeddedRwMutex{} // composite literal on RHS is OK (#16227)
+	x = BadRet()           // function call on RHS is OK (#16227)
+	x = *OKRet()           // indirection of function call on RHS is OK (#16227)
+}
+
 // TODO: Unfortunate cases
 
 // Non-ideal error message:
diff --git a/src/cmd/vet/testdata/divergent/buf_test.go b/src/cmd/vet/testdata/divergent/buf_test.go
index 6b9cba3..b75d55e 100644
--- a/src/cmd/vet/testdata/divergent/buf_test.go
+++ b/src/cmd/vet/testdata/divergent/buf_test.go
@@ -4,11 +4,11 @@ package buf_test
 
 func Example() {} // OK because is package-level.
 
-func Example_suffix() // OK because refers to suffix annotation.
+func Example_suffix() {} // OK because refers to suffix annotation.
 
-func Example_BadSuffix() // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
+func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
 
-func ExampleBuf() // OK because refers to known top-level type.
+func ExampleBuf() {} // OK because refers to known top-level type.
 
 func ExampleBuf_Append() {} // OK because refers to known method.
 
@@ -28,8 +28,8 @@ func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
 
 // "Puffer" is German for "Buffer".
 
-func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
+func ExamplePuffer() {} // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
 
-func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
+func ExamplePuffer_Append() {} // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
 
-func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
+func ExamplePuffer_suffix() {} // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
diff --git a/src/cmd/vet/testdata/examples_test.go b/src/cmd/vet/testdata/examples_test.go
deleted file mode 100644
index 9c53672..0000000
--- a/src/cmd/vet/testdata/examples_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Test of examples.
-
-package testdata
-
-// Buf is a ...
-type Buf []byte
-
-// Append ...
-func (*Buf) Append([]byte) {}
-
-func (Buf) Reset() {}
-
-func (Buf) Len() int { return 0 }
-
-// DefaultBuf is a ...
-var DefaultBuf Buf
-
-func Example() {} // OK because is package-level.
-
-func Example_goodSuffix() // OK because refers to suffix annotation.
-
-func Example_BadSuffix() // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
-
-func ExampleBuf() // OK because refers to known top-level type.
-
-func ExampleBuf_Append() {} // OK because refers to known method.
-
-func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear"
-
-func ExampleBuf_suffix() {} // OK because refers to suffix annotation.
-
-func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad"
-
-func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix.
-
-func ExampleDefaultBuf() {} // OK because refers to top-level identifier.
-
-func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing"
-
-func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
-
-// "Puffer" is German for "Buffer".
-
-func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
-
-func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
-
-func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
diff --git a/src/cmd/vet/testdata/lostcancel.go b/src/cmd/vet/testdata/lostcancel.go
new file mode 100644
index 0000000..b7549c0
--- /dev/null
+++ b/src/cmd/vet/testdata/lostcancel.go
@@ -0,0 +1,155 @@
+// Copyright 2016 The Go Authors. 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 (
+	"context"
+	"log"
+	"os"
+	"testing"
+)
+
+// Check the three functions and assignment forms (var, :=, =) we look for.
+// (Do these early: line numbers are fragile.)
+func _() {
+	var ctx, cancel = context.WithCancel() // ERROR "the cancel function is not used on all paths \(possible context leak\)"
+} // ERROR "this return statement may be reached without using the cancel var defined on line 17"
+
+func _() {
+	ctx, cancel2 := context.WithDeadline() // ERROR "the cancel2 function is not used..."
+} // ERROR "may be reached without using the cancel2 var defined on line 21"
+
+func _() {
+	var ctx context.Context
+	var cancel3 func()
+	ctx, cancel3 = context.WithTimeout() // ERROR "function is not used..."
+} // ERROR "this return statement may be reached without using the cancel3 var defined on line 27"
+
+func _() {
+	ctx, _ := context.WithCancel()  // ERROR "the cancel function returned by context.WithCancel should be called, not discarded, to avoid a context leak"
+	ctx, _ = context.WithTimeout()  // ERROR "the cancel function returned by context.WithTimeout should be called, not discarded, to avoid a context leak"
+	ctx, _ = context.WithDeadline() // ERROR "the cancel function returned by context.WithDeadline should be called, not discarded, to avoid a context leak"
+}
+
+func _() {
+	ctx, cancel := context.WithCancel()
+	defer cancel() // ok
+}
+
+func _() {
+	ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
+	if condition {
+		cancel()
+	}
+	return // ERROR "this return statement may be reached without using the cancel var"
+}
+
+func _() {
+	ctx, cancel := context.WithCancel()
+	if condition {
+		cancel()
+	} else {
+		// ok: infinite loop
+		for {
+			print(0)
+		}
+	}
+}
+
+func _() {
+	ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
+	if condition {
+		cancel()
+	} else {
+		for i := 0; i < 10; i++ {
+			print(0)
+		}
+	}
+} // ERROR "this return statement may be reached without using the cancel var"
+
+func _() {
+	ctx, cancel := context.WithCancel()
+	// ok: used on all paths
+	switch someInt {
+	case 0:
+		new(testing.T).FailNow()
+	case 1:
+		log.Fatal()
+	case 2:
+		cancel()
+	case 3:
+		print("hi")
+		fallthrough
+	default:
+		os.Exit(1)
+	}
+}
+
+func _() {
+	ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
+	switch someInt {
+	case 0:
+		new(testing.T).FailNow()
+	case 1:
+		log.Fatal()
+	case 2:
+		cancel()
+	case 3:
+		print("hi") // falls through to implicit return
+	default:
+		os.Exit(1)
+	}
+} // ERROR "this return statement may be reached without using the cancel var"
+
+func _(ch chan int) int {
+	ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
+	select {
+	case <-ch:
+		new(testing.T).FailNow()
+	case y <- ch:
+		print("hi") // falls through to implicit return
+	case ch <- 1:
+		cancel()
+	default:
+		os.Exit(1)
+	}
+} // ERROR "this return statement may be reached without using the cancel var"
+
+func _(ch chan int) int {
+	ctx, cancel := context.WithCancel()
+	// A blocking select must execute one of its cases.
+	select {
+	case <-ch:
+		panic()
+	}
+}
+
+func _() {
+	go func() {
+		ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
+		print(ctx)
+	}() // ERROR "may be reached without using the cancel var"
+}
+
+var condition bool
+var someInt int
+
+// Regression test for Go issue 16143.
+func _() {
+	var x struct{ f func() }
+	x.f()
+}
+
+// Regression test for Go issue 16230.
+func _() (ctx context.Context, cancel func()) {
+	ctx, cancel = context.WithCancel()
+	return // a naked return counts as a load of the named result values
+}
+
+// Same as above, but for literal function.
+var _ = func() (ctx context.Context, cancel func()) {
+	ctx, cancel = context.WithCancel()
+	return
+}
diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go
index c5faa36..ab97256 100644
--- a/src/cmd/vet/testdata/print.go
+++ b/src/cmd/vet/testdata/print.go
@@ -8,9 +8,13 @@ package testdata
 
 import (
 	"fmt"
+	"io"
 	"math"
 	"os"
 	"unsafe" // just for test case printing unsafe.Pointer
+
+	// For testing printf-like functions from external package.
+	"github.com/foobar/externalprintf"
 )
 
 func UnsafePointerPrintfTest() {
@@ -182,11 +186,11 @@ func PrintfTests() {
 	// 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())        // ok
 	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()        // ok
 	et2.Error("hi")    // ok, not an error method.
 	et2.Error("%d", 3) // ERROR "possible formatting directive in Error call"
 	var et3 errorTest3
@@ -211,24 +215,96 @@ func PrintfTests() {
 	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"
-
+	Logf("%d", "hi") // ERROR "arg .hi. for printf verb %d of wrong type: string"
+
+	Errorf(1, "%d", 3)    // OK
+	Errorf(1, "%d", "hi") // ERROR "arg .hi. for printf verb %d of wrong type: string"
+
+	// Multiple string arguments before variadic args
+	errorf("WARNING", "foobar")            // OK
+	errorf("INFO", "s=%s, n=%d", "foo", 1) // OK
+	errorf("ERROR", "%d")                  // ERROR "format reads arg 1, have only 0 args"
+
+	// Printf from external package
+	externalprintf.Printf("%d", 42) // OK
+	externalprintf.Printf("foobar") // OK
+	level := 123
+	externalprintf.Logf(level, "%d", 42)                        // OK
+	externalprintf.Errorf(level, level, "foo %q bar", "foobar") // OK
+	externalprintf.Logf(level, "%d")                            // ERROR "format reads arg 1, have only 0 args"
+
+	// user-defined Println-like functions
+	ss := &someStruct{}
+	ss.Log(someFunction, "foo")          // OK
+	ss.Error(someFunction, someFunction) // OK
+	ss.Println()                         // OK
+	ss.Println(1.234, "foo")             // OK
+	ss.Println(1, someFunction)          // ERROR "arg someFunction in Println call is a function value, not a function call"
+	ss.log(someFunction)                 // OK
+	ss.log(someFunction, "bar", 1.33)    // OK
+	ss.log(someFunction, someFunction)   // ERROR "arg someFunction in log call is a function value, not a function call"
 }
 
+type someStruct struct{}
+
+// Log is non-variadic user-define Println-like function.
+// Calls to this func must be skipped when checking
+// for Println-like arguments.
+func (ss *someStruct) Log(f func(), s string) {}
+
+// Error is variadic user-define Println-like function.
+// Calls to this func mustn't be checked for Println-like arguments,
+// since variadic arguments type isn't interface{}.
+func (ss *someStruct) Error(args ...func()) {}
+
+// Println is variadic user-defined Println-like function.
+// Calls to this func must be checked for Println-like arguments.
+func (ss *someStruct) Println(args ...interface{}) {}
+
+// log is variadic user-defined Println-like function.
+// Calls to this func must be checked for Println-like arguments.
+func (ss *someStruct) log(f func(), args ...interface{}) {}
+
 // A function we use as a function value; it has no other purpose.
-func someFunction() {
-}
+func someFunction() {}
 
 // Printf is used by the test so we must declare it.
 func Printf(format string, args ...interface{}) {
 	panic("don't call - testing only")
 }
 
+// Println is used by the test so we must declare it.
+func Println(args ...interface{}) {
+	panic("don't call - testing only")
+}
+
+// Logf is used by the test so we must declare it.
+func Logf(format string, args ...interface{}) {
+	panic("don't call - testing only")
+}
+
+// Log is used by the test so we must declare it.
+func Log(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")
 }
 
+// Errorf is used by the test for a case in which the first parameter
+// is not a format string.
+func Errorf(i int, format string, args ...interface{}) {
+	panic("don't call - testing only")
+}
+
+// errorf is used by the test for a case in which the function accepts multiple
+// string parameters before variadic arguments
+func errorf(level, 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")
@@ -350,3 +426,10 @@ var recursiveStruct1V = &RecursiveStruct1{}
 func (int) String() {
 	return ""
 }
+
+func (s *unknownStruct) Fprintln(w io.Writer, s string) {}
+
+func UnknownStructFprintln() {
+	s := unknownStruct{}
+	s.Fprintln(os.Stdout, "hello, world!") // OK
+}
diff --git a/src/cmd/vet/testdata/rangeloop.go b/src/cmd/vet/testdata/rangeloop.go
index 37b5940..66223aa 100644
--- a/src/cmd/vet/testdata/rangeloop.go
+++ b/src/cmd/vet/testdata/rangeloop.go
@@ -56,4 +56,13 @@ func RangeLoopTests() {
 			_ = f // ERROR "range variable f captured by func literal"
 		}()
 	}
+	type T struct {
+		v int
+	}
+	for _, v := range s {
+		go func() {
+			_ = T{v: 1}
+			_ = []int{v: 1} // ERROR "range variable v captured by func literal"
+		}()
+	}
 }
diff --git a/src/cmd/vet/testdata/shadow.go b/src/cmd/vet/testdata/shadow.go
index 241109f..3b61137 100644
--- a/src/cmd/vet/testdata/shadow.go
+++ b/src/cmd/vet/testdata/shadow.go
@@ -17,7 +17,7 @@ func ShadowRead(f *os.File, buf []byte) (err error) {
 		_ = err
 	}
 	if f != nil {
-		_, err := f.Read(buf) // ERROR "declaration of err shadows declaration at testdata/shadow.go:13"
+		_, err := f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13"
 		if err != nil {
 			return err
 		}
@@ -25,8 +25,8 @@ func ShadowRead(f *os.File, buf []byte) (err error) {
 		_ = i
 	}
 	if f != nil {
-		x := one()               // ERROR "declaration of x shadows declaration at testdata/shadow.go:14"
-		var _, err = f.Read(buf) // ERROR "declaration of err shadows declaration at testdata/shadow.go:13"
+		x := one()               // ERROR "declaration of .x. shadows declaration at testdata/shadow.go:14"
+		var _, err = f.Read(buf) // ERROR "declaration of .err. shadows declaration at testdata/shadow.go:13"
 		if x == 1 && err != nil {
 			return err
 		}
@@ -46,7 +46,7 @@ func ShadowRead(f *os.File, buf []byte) (err error) {
 	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"
+		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.
diff --git a/src/cmd/vet/testdata/tests_test.go b/src/cmd/vet/testdata/tests_test.go
new file mode 100644
index 0000000..f5bbc39
--- /dev/null
+++ b/src/cmd/vet/testdata/tests_test.go
@@ -0,0 +1,74 @@
+package testdata
+
+import (
+	"testing"
+)
+
+// Buf is a ...
+type Buf []byte
+
+// Append ...
+func (*Buf) Append([]byte) {}
+
+func (Buf) Reset() {}
+
+func (Buf) Len() int { return 0 }
+
+// DefaultBuf is a ...
+var DefaultBuf Buf
+
+func Example() {} // OK because is package-level.
+
+func Example_goodSuffix() // OK because refers to suffix annotation.
+
+func Example_BadSuffix() // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
+
+func ExampleBuf() // OK because refers to known top-level type.
+
+func ExampleBuf_Append() {} // OK because refers to known method.
+
+func ExampleBuf_Clear() {} // ERROR "ExampleBuf_Clear refers to unknown field or method: Buf.Clear"
+
+func ExampleBuf_suffix() {} // OK because refers to suffix annotation.
+
+func ExampleBuf_Append_Bad() {} // ERROR "ExampleBuf_Append_Bad has malformed example suffix: Bad"
+
+func ExampleBuf_Append_suffix() {} // OK because refers to known method with valid suffix.
+
+func ExampleDefaultBuf() {} // OK because refers to top-level identifier.
+
+func ExampleBuf_Reset() bool { return true } // ERROR "ExampleBuf_Reset should return nothing"
+
+func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
+
+// "Puffer" is German for "Buffer".
+
+func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
+
+func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
+
+func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
+
+func nonTest() {} // OK because it doesn't start with "Test".
+
+func (Buf) TesthasReceiver() {} // OK because it has a receiver.
+
+func TestOKSuffix(*testing.T) {} // OK because first char after "Test" is Uppercase.
+
+func TestÜnicodeWorks(*testing.T) {} // OK because the first char after "Test" is Uppercase.
+
+func TestbadSuffix(*testing.T) {} // ERROR "first letter after 'Test' must not be lowercase"
+
+func TestemptyImportBadSuffix(*T) {} // ERROR "first letter after 'Test' must not be lowercase"
+
+func Test(*testing.T) {} // OK "Test" on its own is considered a test.
+
+func Testify() {} // OK because it takes no parameters.
+
+func TesttooManyParams(*testing.T, string) {} // OK because it takes too many parameters.
+
+func TesttooManyNames(a, b *testing.T) {} // OK because it takes too many names.
+
+func TestnoTParam(string) {} // OK because it doesn't take a *testing.T
+
+func BenchmarkbadSuffix(*testing.B) {} // ERROR "first letter after 'Benchmark' must not be lowercase"
diff --git a/src/cmd/vet/testdata/unsafeptr.go b/src/cmd/vet/testdata/unsafeptr.go
index 8f64030..e04856e 100644
--- a/src/cmd/vet/testdata/unsafeptr.go
+++ b/src/cmd/vet/testdata/unsafeptr.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/cmd/vet/tests.go b/src/cmd/vet/tests.go
new file mode 100644
index 0000000..8c051f1
--- /dev/null
+++ b/src/cmd/vet/tests.go
@@ -0,0 +1,187 @@
+// Copyright 2015 The Go Authors. 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/types"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+)
+
+func init() {
+	register("tests",
+		"check for common mistaken usages of tests/documentation examples",
+		checkTestFunctions,
+		funcDecl)
+}
+
+func isExampleSuffix(s string) bool {
+	r, size := utf8.DecodeRuneInString(s)
+	return size > 0 && unicode.IsLower(r)
+}
+
+func isTestSuffix(name string) bool {
+	if len(name) == 0 {
+		// "Test" is ok.
+		return true
+	}
+	r, _ := utf8.DecodeRuneInString(name)
+	return !unicode.IsLower(r)
+}
+
+func isTestParam(typ ast.Expr, wantType string) bool {
+	ptr, ok := typ.(*ast.StarExpr)
+	if !ok {
+		// Not a pointer.
+		return false
+	}
+	// No easy way of making sure it's a *testing.T or *testing.B:
+	// ensure the name of the type matches.
+	if name, ok := ptr.X.(*ast.Ident); ok {
+		return name.Name == wantType
+	}
+	if sel, ok := ptr.X.(*ast.SelectorExpr); ok {
+		return sel.Sel.Name == wantType
+	}
+	return false
+}
+
+func lookup(name string, scopes []*types.Scope) types.Object {
+	for _, scope := range scopes {
+		if o := scope.Lookup(name); o != nil {
+			return o
+		}
+	}
+	return nil
+}
+
+func extendedScope(f *File) []*types.Scope {
+	scopes := []*types.Scope{f.pkg.typesPkg.Scope()}
+	if f.basePkg != nil {
+		scopes = append(scopes, f.basePkg.typesPkg.Scope())
+	} else {
+		// If basePkg is not specified (e.g. when checking a single file) try to
+		// find it among imports.
+		pkgName := f.pkg.typesPkg.Name()
+		if strings.HasSuffix(pkgName, "_test") {
+			basePkgName := strings.TrimSuffix(pkgName, "_test")
+			for _, p := range f.pkg.typesPkg.Imports() {
+				if p.Name() == basePkgName {
+					scopes = append(scopes, p.Scope())
+					break
+				}
+			}
+		}
+	}
+	return scopes
+}
+
+func checkExample(fn *ast.FuncDecl, f *File, report reporter) {
+	fnName := fn.Name.Name
+	if params := fn.Type.Params; len(params.List) != 0 {
+		report("%s should be niladic", fnName)
+	}
+	if results := fn.Type.Results; results != nil && len(results.List) != 0 {
+		report("%s should return nothing", fnName)
+	}
+
+	if filesRun && !includesNonTest {
+		// The coherence checks between a test and the package it tests
+		// will report false positives if no non-test files have
+		// been provided.
+		return
+	}
+
+	if fnName == "Example" {
+		// Nothing more to do.
+		return
+	}
+
+	var (
+		exName = strings.TrimPrefix(fnName, "Example")
+		elems  = strings.SplitN(exName, "_", 3)
+		ident  = elems[0]
+		obj    = lookup(ident, extendedScope(f))
+	)
+	if ident != "" && obj == nil {
+		// Check ExampleFoo and ExampleBadFoo.
+		report("%s refers to unknown identifier: %s", fnName, ident)
+		// Abort since obj is absent and no subsequent checks can be performed.
+		return
+	}
+	if len(elems) < 2 {
+		// Nothing more to do.
+		return
+	}
+
+	if ident == "" {
+		// Check Example_suffix and Example_BadSuffix.
+		if residual := strings.TrimPrefix(exName, "_"); !isExampleSuffix(residual) {
+			report("%s has malformed example suffix: %s", fnName, residual)
+		}
+		return
+	}
+
+	mmbr := elems[1]
+	if !isExampleSuffix(mmbr) {
+		// Check ExampleFoo_Method and ExampleFoo_BadMethod.
+		if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil {
+			report("%s refers to unknown field or method: %s.%s", fnName, ident, mmbr)
+		}
+	}
+	if len(elems) == 3 && !isExampleSuffix(elems[2]) {
+		// Check ExampleFoo_Method_suffix and ExampleFoo_Method_Badsuffix.
+		report("%s has malformed example suffix: %s", fnName, elems[2])
+	}
+}
+
+func checkTest(fn *ast.FuncDecl, prefix string, report reporter) {
+	// Want functions with 0 results and 1 parameter.
+	if fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
+		fn.Type.Params == nil ||
+		len(fn.Type.Params.List) != 1 ||
+		len(fn.Type.Params.List[0].Names) > 1 {
+		return
+	}
+
+	// The param must look like a *testing.T or *testing.B.
+	if !isTestParam(fn.Type.Params.List[0].Type, prefix[:1]) {
+		return
+	}
+
+	if !isTestSuffix(fn.Name.Name[len(prefix):]) {
+		report("%s has malformed name: first letter after '%s' must not be lowercase", fn.Name.Name, prefix)
+	}
+}
+
+type reporter func(format string, args ...interface{})
+
+// checkTestFunctions walks Test, Benchmark and Example functions checking
+// malformed names, wrong signatures and examples documenting inexistent
+// identifiers.
+func checkTestFunctions(f *File, node ast.Node) {
+	if !strings.HasSuffix(f.name, "_test.go") {
+		return
+	}
+
+	fn, ok := node.(*ast.FuncDecl)
+	if !ok || fn.Recv != nil {
+		// Ignore non-functions or functions with receivers.
+		return
+	}
+
+	report := func(format string, args ...interface{}) { f.Badf(node.Pos(), format, args...) }
+
+	switch {
+	case strings.HasPrefix(fn.Name.Name, "Example"):
+		checkExample(fn, f, report)
+	case strings.HasPrefix(fn.Name.Name, "Test"):
+		checkTest(fn, "Test", report)
+	case strings.HasPrefix(fn.Name.Name, "Benchmark"):
+		checkTest(fn, "Benchmark", report)
+	}
+}
diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go
index 692bae6..4d0e615 100644
--- a/src/cmd/vet/types.go
+++ b/src/cmd/vet/types.go
@@ -85,29 +85,6 @@ func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
 	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.
 //
@@ -292,72 +269,6 @@ func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Ex
 	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.
diff --git a/src/cmd/vet/unsafeptr.go b/src/cmd/vet/unsafeptr.go
index 9ca27dc..a143e4d 100644
--- a/src/cmd/vet/unsafeptr.go
+++ b/src/cmd/vet/unsafeptr.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go
index c1026a3..31d4b90 100644
--- a/src/cmd/vet/vet_test.go
+++ b/src/cmd/vet/vet_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -34,6 +34,9 @@ func MustHavePerl(t *testing.T) {
 	case "plan9", "windows":
 		t.Skipf("skipping test: perl not available on %s", runtime.GOOS)
 	}
+	if _, err := exec.LookPath("perl"); err != nil {
+		t.Skipf("skipping test: perl not found in path")
+	}
 }
 
 var (
@@ -42,11 +45,11 @@ var (
 )
 
 func Build(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+	MustHavePerl(t)
 	if built {
 		return
 	}
-	testenv.MustHaveGoBuild(t)
-	MustHavePerl(t)
 	if failed {
 		t.Skip("cannot run on this environment")
 	}
@@ -65,7 +68,8 @@ func Vet(t *testing.T, files []string) {
 	flags := []string{
 		"./" + binary,
 		"-printfuncs=Warn:1,Warnf:1",
-		"-test", // TODO: Delete once -shadow is part of -all.
+		"-all",
+		"-shadow",
 	}
 	cmd := exec.Command(errchk, append(flags, files...)...)
 	if !run(cmd, t) {
@@ -98,7 +102,7 @@ func TestVet(t *testing.T) {
 func TestDivergentPackagesExamples(t *testing.T) {
 	Build(t)
 	// errchk ./testvet
-	Vet(t, []string{"testdata/divergent/buf.go", "testdata/divergent/buf_test.go"})
+	Vet(t, []string{"testdata/divergent"})
 }
 
 func TestIncompleteExamples(t *testing.T) {
diff --git a/src/cmd/yacc/doc.go b/src/cmd/yacc/doc.go
index 328d87b..c9bb573 100644
--- a/src/cmd/yacc/doc.go
+++ b/src/cmd/yacc/doc.go
@@ -15,7 +15,7 @@ It is largely transliterated from the Inferno version written in Limbo
 which in turn was largely transliterated from the Plan 9 version
 written in C and documented at
 
-	http://plan9.bell-labs.com/magic/man2html/1/yacc
+	https://9p.io/magic/man2html/1/yacc
 
 Adepts of the original yacc will have no trouble adapting to this
 form of the tool.
diff --git a/src/cmd/yacc/testdata/expr/expr.y b/src/cmd/yacc/testdata/expr/expr.y
index bb8e9bf..c39f919 100644
--- a/src/cmd/yacc/testdata/expr/expr.y
+++ b/src/cmd/yacc/testdata/expr/expr.y
@@ -95,14 +95,14 @@ expr3:
 // for clarity.
 const eof = 0
 
-// The parser uses the type <prefix>Lex as a lexer.  It must provide
+// The parser uses the type <prefix>Lex as a lexer. It must provide
 // the methods Lex(*<prefix>SymType) int and Error(string).
 type exprLex struct {
 	line []byte
 	peek rune
 }
 
-// The parser calls this method to get each new token.  This
+// The parser calls this method to get each new token. This
 // implementation returns operators and NUM.
 func (x *exprLex) Lex(yylval *exprSymType) int {
 	for {
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
index 4f9d13c..8a5df05 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -17,7 +17,7 @@ file such as NOTICE, LICENCE or COPYING.
 	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.
+	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
@@ -237,7 +237,6 @@ var defact = make([]int, NSTATES)  // default actions of states
 
 // lookahead set information
 
-var lkst []Lkset
 var nolook = 0  // flag to turn off lookahead computations
 var tbitset = 0 // size of lookahead sets
 var clset Lkset // temporary storage for lookahead computations
@@ -684,6 +683,10 @@ outer:
 		levprd[nprod] = 0
 	}
 
+	if TEMPSIZE < ntokens+nnonter+1 {
+		errorf("too many tokens (%d) or non-terminals (%d)", ntokens, nnonter)
+	}
+
 	//
 	// end of all rules
 	// dump out the prefix code
@@ -3185,8 +3188,6 @@ func isword(c rune) bool {
 	return c >= 0xa0 || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
 }
 
-func mktemp(t string) string { return t }
-
 //
 // return 1 if 2 arrays are equal
 // return 0 if not equal
@@ -3204,13 +3205,6 @@ func aryeq(a []int, b []int) int {
 	return 1
 }
 
-func putrune(f *bufio.Writer, c int) {
-	s := string(c)
-	for i := 0; i < len(s); i++ {
-		f.WriteByte(s[i])
-	}
-}
-
 func getrune(f *bufio.Reader) rune {
 	var r rune
 
diff --git a/src/cmp.bash b/src/cmp.bash
new file mode 100644
index 0000000..68086c3
--- /dev/null
+++ b/src/cmp.bash
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+# Copyright 2016 The Go 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 simple script to compare differences between
+# assembly listings for packages built with different
+# compiler flags. It is useful to inspect the impact
+# of a compiler change across all std lib packages.
+#
+# The script builds the std library (make.bash) once
+# with FLAGS1 and once with FLAGS2 and compares the
+# "go build <pkg>" assembly output for each package
+# and lists the packages with differences.
+#
+# It leaves and old.txt and new.txt file in the package
+# directories for the packages with differences.
+
+FLAGS1="-newexport=0"
+FLAGS2="-newexport=1"
+
+echo
+echo
+echo "1a) clean build using $FLAGS1"
+(export GO_GCFLAGS="$FLAGS1"; sh make.bash)
+
+echo
+echo
+echo "1b) save go build output for all packages"
+for pkg in `go list std`; do
+	echo $pkg
+	DIR=$GOROOT/src/$pkg
+	go build -gcflags "$FLAGS1 -S" -o /dev/null $pkg &> $DIR/old.txt
+done
+
+echo
+echo
+echo "2a) clean build using $FLAGS2"
+(export GO_GCFLAGS="$FLAGS2"; sh make.bash)
+
+echo
+echo
+echo "2b) save go build output for all packages"
+for pkg in `go list std`; do
+	echo $pkg
+	DIR=$GOROOT/src/$pkg
+	go build -gcflags "$FLAGS2 -S" -o /dev/null $pkg &> $DIR/new.txt
+done
+
+echo
+echo
+echo "3) compare assembly files"
+for pkg in `go list std`; do
+	DIR=$GOROOT/src/$pkg
+
+	if cmp $DIR/old.txt $DIR/new.txt &> /dev/null
+	then rm $DIR/old.txt $DIR/new.txt
+	else echo "==> $DIR"
+	fi
+done
diff --git a/src/compress/bzip2/bzip2.go b/src/compress/bzip2/bzip2.go
index 6897957..4278844 100644
--- a/src/compress/bzip2/bzip2.go
+++ b/src/compress/bzip2/bzip2.go
@@ -27,9 +27,8 @@ type reader struct {
 	blockCRC     uint32
 	wantBlockCRC uint32
 	setupDone    bool // true if we have parsed the bzip2 header.
-	blockSize    int  // blockSize in bytes, i.e. 900 * 1024.
+	blockSize    int  // blockSize in bytes, i.e. 900 * 1000.
 	eof          bool
-	buf          []byte    // stores Burrows-Wheeler transformed data.
 	c            [256]uint // the `C' array for the inverse BWT.
 	tt           []uint32  // mirrors the `tt' array in the bzip2 source and contains the P array in the upper 24 bits.
 	tPos         uint32    // Index of the next output byte in tt.
@@ -76,7 +75,7 @@ func (bz2 *reader) setup(needMagic bool) error {
 	}
 
 	bz2.fileCRC = 0
-	bz2.blockSize = 100 * 1024 * (int(level) - '0')
+	bz2.blockSize = 100 * 1000 * (level - '0')
 	if bz2.blockSize > len(bz2.tt) {
 		bz2.tt = make([]uint32, bz2.blockSize)
 	}
@@ -294,7 +293,7 @@ func (bz2 *reader) readBlock() (err error) {
 		if c >= numHuffmanTrees {
 			return StructuralError("tree index too large")
 		}
-		treeIndexes[i] = uint8(mtfTreeDecoder.Decode(c))
+		treeIndexes[i] = mtfTreeDecoder.Decode(c)
 	}
 
 	// The list of symbols for the move-to-front transform is taken from
@@ -319,6 +318,9 @@ func (bz2 *reader) readBlock() (err error) {
 		length := br.ReadBits(5)
 		for j := range lengths {
 			for {
+				if length < 1 || length > 20 {
+					return StructuralError("Huffman length out of range")
+				}
 				if !br.ReadBit() {
 					break
 				}
@@ -328,9 +330,6 @@ func (bz2 *reader) readBlock() (err error) {
 					length++
 				}
 			}
-			if length < 0 || length > 20 {
-				return StructuralError("Huffman length out of range")
-			}
 			lengths[j] = uint8(length)
 		}
 		huffmanTrees[i], err = newHuffmanTree(lengths)
@@ -400,7 +399,7 @@ func (bz2 *reader) readBlock() (err error) {
 				return StructuralError("repeats past end of block")
 			}
 			for i := 0; i < repeat; i++ {
-				b := byte(mtf.First())
+				b := mtf.First()
 				bz2.tt[bufIndex] = uint32(b)
 				bz2.c[b]++
 				bufIndex++
@@ -421,7 +420,7 @@ func (bz2 *reader) readBlock() (err error) {
 		// it's always referenced with a run-length of 1. Thus 0
 		// doesn't need to be encoded and we have |v-1| in the next
 		// line.
-		b := byte(mtf.Decode(int(v - 1)))
+		b := mtf.Decode(int(v - 1))
 		if bufIndex >= bz2.blockSize {
 			return StructuralError("data exceeds block size")
 		}
diff --git a/src/compress/bzip2/bzip2_test.go b/src/compress/bzip2/bzip2_test.go
index 7293d4e..a6c3080 100644
--- a/src/compress/bzip2/bzip2_test.go
+++ b/src/compress/bzip2/bzip2_test.go
@@ -6,193 +6,221 @@ package bzip2
 
 import (
 	"bytes"
-	"encoding/base64"
 	"encoding/hex"
+	"fmt"
 	"io"
 	"io/ioutil"
 	"testing"
 )
 
-func TestBitReader(t *testing.T) {
-	buf := bytes.NewReader([]byte{0xaa})
-	br := newBitReader(buf)
-	if n := br.ReadBits(1); n != 1 {
-		t.Errorf("read 1 wrong")
-	}
-	if n := br.ReadBits(1); n != 0 {
-		t.Errorf("read 2 wrong")
-	}
-	if n := br.ReadBits(1); n != 1 {
-		t.Errorf("read 3 wrong")
-	}
-	if n := br.ReadBits(1); n != 0 {
-		t.Errorf("read 4 wrong")
-	}
-}
-
-func TestBitReaderLarge(t *testing.T) {
-	buf := bytes.NewReader([]byte{0x12, 0x34, 0x56, 0x78})
-	br := newBitReader(buf)
-	if n := br.ReadBits(32); n != 0x12345678 {
-		t.Errorf("got: %x want: %x", n, 0x12345678)
-	}
-}
-
-func readerFromHex(s string) io.Reader {
-	data, err := hex.DecodeString(s)
-	if err != nil {
-		panic("readerFromHex: bad input")
-	}
-	return bytes.NewReader(data)
-}
-
-func decompressHex(s string) (out []byte, err error) {
-	r := NewReader(readerFromHex(s))
-	return ioutil.ReadAll(r)
-}
-
-func TestHelloWorldBZ2(t *testing.T) {
-	out, err := decompressHex(helloWorldBZ2Hex)
+func mustDecodeHex(s string) []byte {
+	b, err := hex.DecodeString(s)
 	if err != nil {
-		t.Errorf("error from Read: %s", err)
-		return
-	}
-
-	if !bytes.Equal(helloWorld, out) {
-		t.Errorf("got %x, want %x", out, helloWorld)
+		panic(err)
 	}
+	return b
 }
 
-func TestConcat(t *testing.T) {
-	out, err := decompressHex(helloWorldBZ2Hex + helloWorldBZ2Hex)
+func mustLoadFile(f string) []byte {
+	b, err := ioutil.ReadFile(f)
 	if err != nil {
-		t.Errorf("error from Read: %s", err)
-		return
-	}
-
-	hello2 := bytes.Repeat(helloWorld, 2)
-	if !bytes.Equal(hello2, out) {
-		t.Errorf("got %x, want %x", out, hello2)
-	}
-}
-
-func testZeros(t *testing.T, inHex string, n int) {
-	out, err := decompressHex(inHex)
-	if err != nil {
-		t.Errorf("error from Read: %s", err)
-		return
-	}
-
-	expected := make([]byte, n)
-
-	if !bytes.Equal(expected, out) {
-		allZeros := true
-		for _, b := range out {
-			if b != 0 {
-				allZeros = false
-				break
+		panic(err)
+	}
+	return b
+}
+
+func trim(b []byte) string {
+	const limit = 1024
+	if len(b) < limit {
+		return fmt.Sprintf("%q", b)
+	}
+	return fmt.Sprintf("%q...", b[:limit])
+}
+
+func TestReader(t *testing.T) {
+	var vectors = []struct {
+		desc   string
+		input  []byte
+		output []byte
+		fail   bool
+	}{{
+		desc: "hello world",
+		input: mustDecodeHex("" +
+			"425a68393141592653594eece83600000251800010400006449080200031064c" +
+			"4101a7a9a580bb9431f8bb9229c28482776741b0",
+		),
+		output: []byte("hello world\n"),
+	}, {
+		desc: "concatenated files",
+		input: mustDecodeHex("" +
+			"425a68393141592653594eece83600000251800010400006449080200031064c" +
+			"4101a7a9a580bb9431f8bb9229c28482776741b0425a68393141592653594eec" +
+			"e83600000251800010400006449080200031064c4101a7a9a580bb9431f8bb92" +
+			"29c28482776741b0",
+		),
+		output: []byte("hello world\nhello world\n"),
+	}, {
+		desc: "32B zeros",
+		input: mustDecodeHex("" +
+			"425a6839314159265359b5aa5098000000600040000004200021008283177245" +
+			"385090b5aa5098",
+		),
+		output: make([]byte, 32),
+	}, {
+		desc: "1MiB zeros",
+		input: mustDecodeHex("" +
+			"425a683931415926535938571ce50008084000c0040008200030cc0529a60806" +
+			"c4201e2ee48a70a12070ae39ca",
+		),
+		output: make([]byte, 1<<20),
+	}, {
+		desc:   "random data",
+		input:  mustLoadFile("testdata/pass-random1.bz2"),
+		output: mustLoadFile("testdata/pass-random1.bin"),
+	}, {
+		desc:   "random data - full symbol range",
+		input:  mustLoadFile("testdata/pass-random2.bz2"),
+		output: mustLoadFile("testdata/pass-random2.bin"),
+	}, {
+		desc: "random data - uses RLE1 stage",
+		input: mustDecodeHex("" +
+			"425a6839314159265359d992d0f60000137dfe84020310091c1e280e100e0428" +
+			"01099210094806c0110002e70806402000546034000034000000f28300000320" +
+			"00d3403264049270eb7a9280d308ca06ad28f6981bee1bf8160727c7364510d7" +
+			"3a1e123083421b63f031f63993a0f40051fbf177245385090d992d0f60",
+		),
+		output: mustDecodeHex("" +
+			"92d5652616ac444a4a04af1a8a3964aca0450d43d6cf233bd03233f4ba92f871" +
+			"9e6c2a2bd4f5f88db07ecd0da3a33b263483db9b2c158786ad6363be35d17335" +
+			"ba",
+		),
+	}, {
+		desc:  "1MiB sawtooth",
+		input: mustLoadFile("testdata/pass-sawtooth.bz2"),
+		output: func() []byte {
+			b := make([]byte, 1<<20)
+			for i := range b {
+				b[i] = byte(i)
+			}
+			return b
+		}(),
+	}, {
+		desc:  "RLE2 buffer overrun - issue 5747",
+		input: mustLoadFile("testdata/fail-issue5747.bz2"),
+		fail:  true,
+	}, {
+		desc: "out-of-range selector - issue 8363",
+		input: mustDecodeHex("" +
+			"425a68393141592653594eece83600000251800010400006449080200031064c" +
+			"4101a7a9a580bb943117724538509000000000",
+		),
+		fail: true,
+	}, {
+		desc: "bad block size - issue 13941",
+		input: mustDecodeHex("" +
+			"425a683131415926535936dc55330063ffc0006000200020a40830008b0008b8" +
+			"bb9229c28481b6e2a998",
+		),
+		fail: true,
+	}, {
+		desc: "bad huffman delta",
+		input: mustDecodeHex("" +
+			"425a6836314159265359b1f7404b000000400040002000217d184682ee48a70a" +
+			"12163ee80960",
+		),
+		fail: true,
+	}}
+
+	for i, v := range vectors {
+		rd := NewReader(bytes.NewReader(v.input))
+		buf, err := ioutil.ReadAll(rd)
+
+		if fail := bool(err != nil); fail != v.fail {
+			if fail {
+				t.Errorf("test %d (%s), unexpected failure: %v", i, v.desc, err)
+			} else {
+				t.Errorf("test %d (%s), unexpected success", i, v.desc)
 			}
 		}
-		t.Errorf("incorrect result, got %d bytes (allZeros: %t)", len(out), allZeros)
+		if !v.fail && !bytes.Equal(buf, v.output) {
+			t.Errorf("test %d (%s), output mismatch:\ngot  %s\nwant %s", i, v.desc, trim(buf), trim(v.output))
+		}
 	}
 }
 
-func Test32Zeros(t *testing.T) {
-	testZeros(t, thirtyTwoZerosBZ2Hex, 32)
-}
-
-func Test1MBZeros(t *testing.T) {
-	testZeros(t, oneMBZerosBZ2Hex, 1024*1024)
-}
-
-func testRandomData(t *testing.T, compressedHex, uncompressedHex string) {
-	out, err := decompressHex(compressedHex)
-	if err != nil {
-		t.Errorf("error from Read: %s", err)
-		return
-	}
-
-	expected, _ := hex.DecodeString(uncompressedHex)
-
-	if !bytes.Equal(out, expected) {
-		t.Errorf("incorrect result\ngot:  %x\nwant: %x", out, expected)
+func TestBitReader(t *testing.T) {
+	var vectors = []struct {
+		nbits uint // Number of bits to read
+		value int  // Expected output value (0 for error)
+		fail  bool // Expected operation failure?
+	}{
+		{nbits: 1, value: 1},
+		{nbits: 1, value: 0},
+		{nbits: 1, value: 1},
+		{nbits: 5, value: 11},
+		{nbits: 32, value: 0x12345678},
+		{nbits: 15, value: 14495},
+		{nbits: 3, value: 6},
+		{nbits: 6, value: 13},
+		{nbits: 1, fail: true},
+	}
+
+	rd := bytes.NewReader([]byte{0xab, 0x12, 0x34, 0x56, 0x78, 0x71, 0x3f, 0x8d})
+	br := newBitReader(rd)
+	for i, v := range vectors {
+		val := br.ReadBits(v.nbits)
+		if fail := bool(br.err != nil); fail != v.fail {
+			if fail {
+				t.Errorf("test %d, unexpected failure: ReadBits(%d) = %v", i, v.nbits, br.err)
+			} else {
+				t.Errorf("test %d, unexpected success: ReadBits(%d) = nil", i, v.nbits)
+			}
+		}
+		if !v.fail && val != v.value {
+			t.Errorf("test %d, mismatching value: ReadBits(%d) = %d, want %d", i, v.nbits, val, v.value)
+		}
 	}
 }
 
-func TestRandomData1(t *testing.T) {
-	testRandomData(t, randBZ2Hex, randHex)
-}
-
-func TestRandomData2(t *testing.T) {
-	// This test involves several repeated bytes in the output, but they
-	// should trigger RLE decoding.
-	testRandomData(t, rand2BZ2Hex, rand2Hex)
-}
-
-func TestRandomData3(t *testing.T) {
-	// This test uses the full range of symbols.
-	testRandomData(t, rand3BZ2Hex, rand3Hex)
-}
-
-func Test1MBSawtooth(t *testing.T) {
-	out, err := decompressHex(oneMBSawtoothBZ2Hex)
-	if err != nil {
-		t.Errorf("error from Read: %s", err)
-		return
-	}
-
-	expected := make([]byte, 1024*1024)
-
-	for i := range expected {
-		expected[i] = byte(i)
+func TestMTF(t *testing.T) {
+	var vectors = []struct {
+		idx int   // Input index
+		sym uint8 // Expected output symbol
+	}{
+		{idx: 1, sym: 1}, // [1 0 2 3 4]
+		{idx: 0, sym: 1}, // [1 0 2 3 4]
+		{idx: 1, sym: 0}, // [0 1 2 3 4]
+		{idx: 4, sym: 4}, // [4 0 1 2 3]
+		{idx: 1, sym: 0}, // [0 4 1 2 3]
 	}
 
-	if !bytes.Equal(out, expected) {
-		t.Error("incorrect result")
+	mtf := newMTFDecoderWithRange(5)
+	for i, v := range vectors {
+		sym := mtf.Decode(v.idx)
+		t.Log(mtf)
+		if sym != v.sym {
+			t.Errorf("test %d, symbol mismatch: Decode(%d) = %d, want %d", i, v.idx, sym, v.sym)
+		}
 	}
 }
 
-const helloWorldBZ2Hex = "425a68393141592653594eece83600000251800010400006449080200031064c4101a7a9a580bb9431f8bb9229c28482776741b0"
-
-var helloWorld = []byte("hello world\n")
-
-const thirtyTwoZerosBZ2Hex = "425a6839314159265359b5aa5098000000600040000004200021008283177245385090b5aa5098"
-const oneMBZerosBZ2Hex = "425a683931415926535938571ce50008084000c0040008200030cc0529a60806c4201e2ee48a70a12070ae39ca"
-
-const randBZ2Hex = "425a6839314159265359905d990d0001957fffffffffffafffffffffffffffffbfff6fffdfffffffffffffffffffffffffffffc002b6dd75676ed5b77720098320d11a64626981323d4da47a83131a13d09e8040f534cd4f4d27a464d193008cd09804601347a980026350c9886234d36864193d1351b44c136919e90340d26127a4cd264c32023009898981310c0344c340027a8303427a99a04c00003534c230d034f5006468d268cf54d36a3009a69a62626261311b40026013d34201a6934c9a604c98ca6c8460989fa9346234d30d3469a2604fd4131a7aa6d0046043d4c62098479269e89e835190d0 [...]
-const randHex = "c95138082bdf2b9bfa5b1072b23f729735d42c785eeb94320fb14c265b9c2ca421d01a3db986df1ac2acde5a0e6bf955d6f95e61261540905928e195f1a66644cc7f37281744fff4dc6df35566a494c41a8167151950eb74f5fc45f85ad0e5ed28b49adfe218aa7ec1707e8e1d55825f61f72beda3b4c006b8c9188d7336a5d875329b1b58c27cc4e89ecbae02c7712400c39dd131d2c6de82e2863da51d472bdfb21ecce62cc9cf769ed28aedc7583d755da45a0d90874bda269dd53283a9bdfd05f95fc8e9a304bb338ea1a2111894678c18134f17d31a15d9bfc1237894650f3e715e2548639ecbddb845cfe [...]
-
-const oneMBSawtoothBZ2Hex = "425a683931415926535971931ea00006ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe007de00000000000000024c00130001300000000000000000000000000000000000000000000000000000000126000980009800000000000000000000000000000000000000000000000000000000930004c0004c000000000000000000000000000000000000000000000000000000004980026000260000000000000000000000000000000000000000000000000000000009aaaaa000000000000000000000000000000000000000000000000000000000000 [...]
-
-const rand2BZ2Hex = "425a6839314159265359d992d0f60000137dfe84020310091c1e280e100e042801099210094806c0110002e70806402000546034000034000000f2830000032000d3403264049270eb7a9280d308ca06ad28f6981bee1bf8160727c7364510d73a1e123083421b63f031f63993a0f40051fbf177245385090d992d0f60"
-const rand2Hex = "92d5652616ac444a4a04af1a8a3964aca0450d43d6cf233bd03233f4ba92f8719e6c2a2bd4f5f88db07ecd0da3a33b263483db9b2c158786ad6363be35d17335ba"
-
-const rand3BZ2Hex = "425a68393141592653593be669d00000327ffffffffffffffffffffffffffffffffffff7ffffffffffffffffffffffffffffffc002b3b2b1b6e2bae400004c00132300004c0d268c004c08c0130026001a008683234c0684c34008c230261a04c0260064d07a8d00034000d27a1268c9931a8d327a3427a41faa69ea0da264c1a34219326869b51b49a6469a3268c689fa53269a62794687a9a68f5189994c9e487a8f534fd49a3d34043629e8c93d04da4f4648d30d4f44d3234c4d3023d0840680984d309934c234d3131a000640984f536a6132601300130130c8d00d04d1841ea7a8d31a02609b40023 [...]
-const rand3Hex = "1744b384d68c042371244e13500d4bfb98c6244e3d71a5b700224420b59c593553f33bd786e3d0ce31626f511bc985f59d1a88aa38ba8ad6218d306abee60dd9172540232b95be1af146c69e72e5fde667a090dc3f93bdc5c5af0ab80acdbaa7a505f628c59dc0247b31a439cacf5010a94376d71521df08c178b02fb96fdb1809144ea38c68536187c53201fea8631fb0a880b4451ccdca7cc61f6aafca21cc7449d920599db61789ac3b1e164b3390124f95022aeea39ccca3ec1053f4fa10de2978e2861ea58e477085c2220021a0927aa94c5d0006b5055abba340e4f9eba22e969978dfd18e278a8b89d8 [...]
-
-const (
-	digits = iota
-	twain
-	random
+var (
+	digits = mustLoadFile("testdata/e.txt.bz2")
+	twain  = mustLoadFile("testdata/Mark.Twain-Tom.Sawyer.txt.bz2")
+	random = mustLoadFile("testdata/random.data.bz2")
 )
 
-var testfiles = []string{
-	// Digits is the digits of the irrational number e. Its decimal representation
-	// does not repeat, but there are only 10 possible digits, so it should be
-	// reasonably compressible.
-	digits: "testdata/e.txt.bz2",
-	// Twain is Mark Twain's classic English novel.
-	twain: "testdata/Mark.Twain-Tom.Sawyer.txt.bz2",
-	// 16KB of random data from /dev/urandom
-	random: "testdata/random.data.bz2",
-}
-
-func benchmarkDecode(b *testing.B, testfile int) {
-	compressed, err := ioutil.ReadFile(testfiles[testfile])
+func benchmarkDecode(b *testing.B, compressed []byte) {
+	// Determine the uncompressed size of testfile.
+	uncompressedSize, err := io.Copy(ioutil.Discard, NewReader(bytes.NewReader(compressed)))
 	if err != nil {
 		b.Fatal(err)
 	}
-	b.SetBytes(int64(len(compressed)))
+
+	b.SetBytes(uncompressedSize)
+	b.ReportAllocs()
+	b.ResetTimer()
+
 	for i := 0; i < b.N; i++ {
 		r := bytes.NewReader(compressed)
 		io.Copy(ioutil.Discard, NewReader(r))
@@ -202,222 +230,3 @@ func benchmarkDecode(b *testing.B, testfile int) {
 func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) }
 func BenchmarkDecodeTwain(b *testing.B)  { benchmarkDecode(b, twain) }
 func BenchmarkDecodeRand(b *testing.B)   { benchmarkDecode(b, random) }
-
-func TestBufferOverrun(t *testing.T) {
-	// Tests https://golang.org/issue/5747.
-	buffer := bytes.NewReader([]byte(bufferOverrunBase64))
-	decoder := base64.NewDecoder(base64.StdEncoding, buffer)
-	decompressor := NewReader(decoder)
-	// This shouldn't panic.
-	ioutil.ReadAll(decompressor)
-}
-
-func TestOutOfRangeSelector(t *testing.T) {
-	// Tests https://golang.org/issue/8363.
-	buffer := bytes.NewReader(outOfRangeSelector)
-	decompressor := NewReader(buffer)
-	// This shouldn't panic.
-	ioutil.ReadAll(decompressor)
-}
-
-func TestMTF(t *testing.T) {
-	mtf := newMTFDecoderWithRange(5)
-
-	// 0 1 2 3 4
-	expect := byte(1)
-	x := mtf.Decode(1)
-	if x != expect {
-		t.Errorf("expected %v, got %v", expect, x)
-	}
-
-	// 1 0 2 3 4
-	x = mtf.Decode(0)
-	if x != expect {
-		t.Errorf("expected %v, got %v", expect, x)
-	}
-
-	// 1 0 2 3 4
-	expect = byte(0)
-	x = mtf.Decode(1)
-	if x != expect {
-		t.Errorf("expected %v, got %v", expect, x)
-	}
-
-	// 0 1 2 3 4
-	expect = byte(4)
-	x = mtf.Decode(4)
-	if x != expect {
-		t.Errorf("expected %v, got %v", expect, x)
-	}
-
-	// 4 0 1 2 3
-	expect = byte(0)
-	x = mtf.Decode(1)
-	if x != expect {
-		t.Errorf("expected %v, got %v", expect, x)
-	}
-}
-
-var bufferOverrunBase64 string = `
-QlpoNTFBWSZTWTzyiGcACMP/////////////////////////////////3/7f3///
-////4N/fCZODak2Xo44GIHZgkGzDRbFAuwAAKoFV7T6AO6qwA6APb6s2rOoAkAAD
-oACUoDtndh0iQAPkAAAAaPWihQoCgr5t97Obju21ChQB0NBm3RbA7apXrRoBooAA
-AhA+IAHWl2Us3O7t9yieb3udvd76+4+fd33nd3HO1bVvfcGRne6+3vfPvfc++995
-w7k973eJhasLVec970tzDNXdX28LoPXZ3H3K9z0s5ufWAfes49d5594c3dUYtI+2
-+h1dvtpRa+uvrVEAG9bl893RVEN7cWvroSqWjPMGgAQi7Gq8TJSgKKdjKFBIB9Ae
-LqWxleu715eXe7ml9e5098Z6G1vr7t1QZ6ot76YzPd3j7333t2ql2Chm7XrA9ICQ
-VF77z3rVBWqkSXtlfb099hyezAr6USbGpICTSCFAaqHrKo+tUnm32rpE4Ue+t2mj
-bKUeipEqwc93EdhhTwmQpOhhesC9iqDSPNTWYNSnUtBdm1nsA0nqqNd7OWwDXtFL
-ONmmA6Ubke26I9UblvWIPR5VOWOnctai443URunnDy77uVC59OfRvezlDu33Z7Ly
-3NNuuHW63088xu3t3NHZhkZbG7tXRlj00qOtbaXTJUUdspTbABR9R6EUwQAEAAAA
-EMEwRpoAAAABMmhoAAjBNNAaCMhponpoGpgJpk9TEyp6niGKZkAaAEfqMQ09U80p
-+pMGSCKngIAAAAgAAg0AAJhGgABGCEaaTyTKeNI1PE0wkj01GajMSNPSZGnqbU9T
-anlPUNAHqGQ0DQAMg9TamgAAYRU/IAAICAmjQJgjQBMEwp5DTSaaYmhTeqfplPID
-U1T9TynoU82pT1NPU/VP0j1NHqRpk9TTR7SnqaNNGmmQAaAD1Aeo0PSAAAAaaBiK
-eBAQBGgIABGQA0AmBNNBoaAgaJmpglPEyYap6npiTT0agGjJjUaaDTQAAAAAAM1A
-9QAaAAAADU8iEAQAEyAJk0NNNJgIZTJ5E00YSemiaZNGm1MpGNJ+lPU9qm9U2RDM
-oY0EzJB6h6nqDID1NMBDDRpo1AGNAjCMmhkMgaYSJIgAAAQyAAEyBoATECCNhTT0
-U/IZAmCM1DSTxkzUE8p6NDaGiZGJqntTFHvUyU9qPQp7Kn5GgKNPU9QAGg9QAAA3
-wz0Pk/g/m/m9P9H4vxv2+dH3gCS8nhbbbbbYxtgNsBsG0m2MbG0NNtsbYNsaY0wb
-bBibGmm22mxptNpsaGNDTY02JsG0MY0xg2MaYNNDbGwG0L5vsK/F9DO+EAA447Kq
-p7Wdf6Y+5c20T7DfHyMXIzRKrZexw72uiQI+y55vOe52xpqbCLC2uR20JdER7Zvr
-7ufuKb6zhiBxLuj0eA27v8RpMLucw9Ohwcizi2wrpt+yU1FdpM7ZYPcwS3XTef+A
-Wzjxwhdrgw3aH1LeC1eZW900x8V9Nv4hTPXp4l067P/4ANVZFF/imOe/d5bdueam
-/DFFokQWnFaU+ZqLBCM+d0PialJQWnLqRQZk/KhfbbYc2pCUTgffcSYbrCM1N+8l
-HU6gSz+h2GJXs+tbrNviL83M97X0vcTn/F82P8wen8/3/h3sHY+sf9CSej9ThYTV
-3lQ+FUHpfpGD4kv7dYMV995dpDX/y3xR8FoXx1bjUxBTNxuutwQ/h/Eedn9wpn6w
-E3+ND8YhN1HSriIxRE/6uFyMv6/oC6Elarw3aHMMqHJkGiiz6tejmvnYLQa+Qm6G
-deZ7jXTZV6NlpocgDnRdimS06bTYSkvPAL/xoWNLkX6N6VljU0dfKSBmm2uZE/xu
-sutQ1EdP7GdjhglIq4xlOFUFEQpmX+xx7R8y6c0GSAaqusOjNZwxZRudOvmXm1tZ
-T+YnbeB2ir9eiHNrtJNSLD/J/WDyuQpwBUtLKo0krccY/wIILP7f86teb9Z/9oyz
-OX05qEWbObfhpRw+9+rCvp/35ML8KX3aHaI0n+tudbFRsV5FLW+Oa8ruLN4peyVL
-DWjTHrXNthq/s7zAJYMeFJZkZt5mT9rfpH+5g3nc+piOSZ+J5nHtOnKI7Ff8Xl+j
-0t76XTNucCHQ6whav1OHdF53TY5wuv5OzvrdnxoId8fTyUvERr0ERINu/8XxZZ5f
-B5/kTZ8bBO0wv54Jp+ED/GQI8lZHzIQCP3vfQhwnCTj9TvITic7P4mYLDbH3fyzR
-i+6EajCcpXLWSGf+ZXkOrWspDWDhXtEKas0v3UqWksqgY1rTj45krX4KihN+daXs
-pZl5WPlta5p06CX6Xm2SfzqkMw12/3ix1bpnnZ+kFeBNX7A+E9zzG6OZaN78GOpl
-9Ht/eZn9PqWdav852zr0zqkDK2H5IjdvNah+b1YVGdQGzwR4Nw+f13yEKnV+y66W
-djfq7zWp7m5w+hzfv+Ly8O7oet5Vvd8/wQvO7qzOZ2vjf9X8Tj8PnMb/nc/nKqRR
-+ml4UEhOOwfCeJEEI109CMYSh91iAJqPjMyH6KjrPD7W25llZVcREYNCTg6htbQt
-M38wYoquCWP6tdKYlVIv14xTNUeUf4El/FunCf6csZkmv+9tfWx7t59wuKIa3saU
-tZs9M+3HFOZtz3OLg/Unoaj9BYazYqA78xBU9tZzrtmF/rQL9CGJt90o/oYnSfcS
-SL3haaw351LXWQ1XOsv1SmH3v6ymuxEpPPnEDmBELaTYsvvMIWJsmPZFFww++Kd7
-s/Jo0JFeUU7uNtI+gVosAIpVVuWfI/9tOIycz7I5Z7zjV+NR2OuZbYtW5F08KX4o
-2k/xuJIchcNFPtxPfw9dkDgscRbMckyFMrzuZ3IvrcGzk0J6iI5ytrv37bGpAXMz
-WK9mMMPebepNevmLjjo/QWoM968Sjv7ldlPS5AinHcXwsFv6dmmh8lJt7UOJWoKu
-lMD1cB2ksIGpMdv8iuqR42Rn/kn+17BhhUZcwDBaUXVdX6bKW7fxlUYbq+mlqIcf
-a9v8HF87M9ANbi9bq9onf9TD7nQ6Xf6vZci8TBPX+/GI0He6j31fTVQYW+NsQxvO
-J8xrx+e58CCLQNjxeIyPt+F+qk/QMiXw+LyxGVkV/XcGQT9X03jSDP6beJ5QG1JW
-9Q3qLv/YixWI7gPV9Mrhf2oRYTc/9KLFRhkE3SjKOTKuSSBKQ24fI+hEznamH71D
-66Hwez8/0et7AtTv9zvamv2OD5He6fMV4k+ePl6+qPfO5CdHtK+eCDZL5+4f5yrl
-gTcRFiq8fXbc5IaI5fbbc1KMM/2T0Mr7+Hwaco6FtXm0fmhCgTZRqY4pKiEIfmaz
-QwHNOOCrtMJ2VwsyMumt7xsOolGnizRev6lILH43qPcczQM7Gc5zRin80YvFt1Qm
-h/57Z0auR2h0fuX50MBO4XQ+26y5l6v4j902R66c0j3z2KHstKQ04J/h6LbuNQE4
-D6cu/lyfK69DxxX8wb8XaQkMUcJdo1LzqUGDAb3Kfn/A3P/JYc99MO9qv67+SxWb
-wYTyqKdWTd+1KbR/Rcn0Io5zI/QquX7FA1bxfMytjQ/X+l0fh0Pf+Hx97meH4fQL
-7/T8/sdTm9Tn8nELvedyhydLlPPTScINdXyLIq9wgIJr4fWPbp9ZhFh/56fdSgOG
-HDXg+gkXsN2Rddr4HQ5P3u+RhLzmSjhzoqY5EsPC4QvRlX9JXjB84rPV5USR66qa
-/kjw4156GJnzoXtydKJE53t6PHfZWO+3ujsfI6iAdshc7OFzGXiZB9PtItKodhYq
-nABkTKdcpu4+TOpf9h5piX5slsaBjkeTnj/Ba02ilboQfcDVigxrYn/iTH5ySWUW
-/lHtg78s5UZM8sErwhNe3N3w+6ZOMnU+5i86/xFNtqZfDdXTGy1H3PzGbdtZXYT+
-Ixx2vpwBYzbPVYHxKosM5rPiVmcTllI9nuoSfeh9ib4foFWauOpvdmhBDqpTpKTX
-u8EO2l2Z195G2RIV7TlKSxGWjR5sl/nALu1uzBeLd9zpSujzMTd1uTX9Qk/Q1S+r
-vaW6bm8qqPO4jb6Wx6XIkm321nrIF6Ae25d1+Dpv/P5G4NoLd2j6/EtENC3FeR5z
-oo7bA+tI8yEQRhiF0z1FlJXLD5ZbhNNWQm/j/IbzRfh8JtOFZU7ruShLvHXysW9S
-9V909tr9jn8/E/Hb5N/1NVNHnZu2HIUvJvHJiHd2ucmeI9PWUMnppmE65GQ5E9xV
-ZRlGEH0X85EvmHyEupkMrCC0oMv9RCq+/H8gcfpe00Hs/S+regT5p58cyYomh93v
-qvuw/A06BE/wzJESuYbN9pqYpoXqXFemW1NksHEJ2w+PYMJ27WJyD5FpaXB85VaW
-qMOhDfO8E3QdH8ybyKt/UgI8/tDGpFbyOlaVdIv1FXJhoLp8soAA4Djg6/KZ066N
-ZFYuS8WdjpSZGP4/Lw+1yaXlzNznc/k2uHe2uXP3uFuPcHx+Dm44utxldoO1uBPy
-+jzOs14+MIgOjOHMVNqAbMd8fUedLlhJMCfMtm4uz01enLNKcMrtLlPIR37Yukh1
-YEMXYpm7eU4XU+j+Jj3pDyaXtXs+p1fWfTN/cy9/Oxs4umUXQ4uHh1kObtayDJ56
-/QMxiHobjHNKuKfMxsrYEwN+QVIyVjAwMDYuMjQ1AAA9IwJniiBLRkZDAAAXt0Ja
-aDQxQVkmU1lZtwytAACLf///////////////////+//////v//////////bv78//
-/+AXO133uwO2xB2UxIvbKXrCqCoURUBL2ytFI82AFdcOwMhVTHtk5rD3szEVNYD4
-aIQINCaMRoTaSn7SbSMJiYmEwieTEp+psqbMCp+VNPaFNpqbBNR7UmanlPUeKfqm
-j1PU0/VPU08o9Q9EeKHlPJtKbYqeTCYhN6U9T1NH6mp+lPyoGNTI/Knkyg1MggAg
-CaMEyQnqZoaaRtRtJpppppoDaTR6hpphGh6mmgHpMQBpkGTTEAAaAAAA00AZDag0
-ADIBkGgABqemiRNTI0k8aU0PRGRoAZlP0UAAAGgAAAyAADQaAAAaAAAAAAAAAAAA
-AaAAAAM0kgRBJ5MlPFP1Gj0jTTTUaekxNAbUGjTQMgaZANNAAAAaAADTQAAAAAAA
-ANAA0AAANADQ0QAAAAAAAAAaGgAAAAAAABoA0AAA0AAAAAAAAAAAAANAAAAAkSEI
-aTRpomp5DUxNNDTJPTKaep6T09Kemmo2JG0aTQ9ENogaaGhkABo0NHqaBoDTI0DC
-Gj0gNAMhoDQ9QMQNAGQAaDDwyMPIMlbG1vhRBTFo6JksSupgpAjPbY0ec02IGXjb
-eS+FBsh01+O4ZOaD+srUZCFaT4DRjVDLx7uKIsFtESIDUg1ZkhyCSYov05C00MtR
-BdNNa/AYPGOQZWcs+VegXOPrkushFbZ3mBoRD6WamClkpBaHZrUhUl02bIfRXX4w
-b3/9cW9nHDVxh2qFBxqgRKfmq7/Jc/tdJk05nVrGbckGVy2PnIy30CDhpWmqrSot
-K2bOnX0NbP1iy2cd0Na0ZmbRstm4MzMzbbMySTd35F7f+zPP8DC+NJLYcakkkkRd
-NZlupJt3OMFoDAD2g+N3FAMCydhIpoRHRQAdFI5nNg4ugEXHCYxkMyGCwtaJmial
-y0IMlpSYYM/weXNJAhFqS0GNmvaPEtYGjbvaucMdklOTmBX1vfVAkTYB1uXCSK64
-UNIixOqRKLuRCFtqIQtgwqaFrCkIYbbewErWABa+VGADWsJXJjfx5SJViLuwiGXq
-Ru6vCuwmU5CJiJz3UiBpmLv0r2wskxUhY4tzPVGQ9RMXJl65eLSNwZVwaSyGZ9Cm
-A3jztQUUpFeUryBTskW95iVwRMFrhBCwZBAFJBZvhMEMNoDJJlUoIhQkAkjbExp2
-YZio+ZYeAZUwmH1qUbdQixmxf0+61+aVgJ1hwxsO1yG3hFx4pfjc09ITVht0pG8u
-FtVFhPa1KE0gTRUSVXywkITucqk0Waz5Fs6qJpVHYdNrbYRFxnFsQGY1qmsTLjK6
-4QX5Rddo6krM/Bx9CqIAKq4CzVQYHrmIAd2EBhYmwVYwLvhzKIUrc2EirnGIvyuD
-O4YZDSwsVTA0BpVvUOjDErkCraBoSutcKwUSSLGhVvNYHLz3klgZD++wWsa/swLw
-gvNDY2De+sncOv8X2lq4HD95ZdwPuTIMXCwSbg4RrIqv+L0y6F17pqDecyQYPEj3
-iN/0BBeWZlJAyBMi5U3Q1zAlsK8IlDhaXGmvZrgISq5CfNjmUgxDeMggOKqxu4sI
-OrilS49Lkl1J3u3GjXTuH+rX+4ccyFAQnizCpPClcY77F59j63S6fr5vr+y99tuO
-7Ox7Wg/ljwhdyaK4xMmXczeJbx7x07htJNtC4xcQfAtvzeznLrN6MN/ILIBOI65I
-qIA2D5fHHj1XN4aN6TvOjWDaSbSWqxCSCvXUpzkNJAkWXAuTwF8k5uSJvQj/rVo0
-hAhEMEIYkCRGx9AX+byIuXWlLMbbVeliHNUL5AQYmNwLFu4SkmGD+UWtBMyVHQOQ
-ss0ggoVKSKOBUgnVS6ljt7WE1qXqJJ4QA1pEwYNLEaguEE1LtPNoVr5WzjbSbWPk
-V9OW3y9IneUDLoIV5pAkEFTEFGFVjeTFxtpzBBfGgycBxVCdz8eESBIzsamRchAa
-TQunQH8DHnpfod9QuAuRvc7JBlKUCYmCjMvynLcxIFohxCaYrDvGw4QbXZB7oWQ7
-hpoGlz23ayDfB8NrRRzdilsEQyQniu9ASLQg7RrGZnoTr1ai12IbCEUCGdFq03P5
-nBnRFAGmisQGcyykV9gKtcVMWLhCuVmXg86dndn7slUpRNSSEAU20oaWIm1maFTu
-E0DT4gTbg0nuhjtz3kNOz+i7sBm0bkXjxQWuLqlZEmp60ZTyRZJDUqKSEKg6hqcy
-ERxdU22CSNOO10RYUUiDVpKhPNdKTOIE1thp02sBNoNTFSht8WJtaBQ09qN3jd5r
-dOLX4IA5fevRyCCzDgRXfV4wzik4KROjmxmTMglBySlIMEzcXehnDXCRiZSlvwA2
-0YsIOROcm4UrIRFxJHctJH7OdN5u1aHVHb5UaLHpv48NgmFRE56KTSoaWunqm2st
-S0mrAdOiqcR12PWVbdVRJKcQ0DQuhwlAPcRtpxN3D4kbXJjToSYJIFw406G2CSaK
-jQMIJPZGlQmgyFhoCSzeGS1VSq5SKKQQxs5RqKUcVUNY57YUETb4mXzV84SPngKi
-nsce0mXByZq5BKUA9puHZWLNwQIYuDaJUNgG+E01E3pDYVNLKYQ0hsVesgV5gZY0
-htDsRdGtm0+iGnkN6+Ea9YJtUZNAkx2GgSoix12nTW0avTUfxR3oYcpvZ7IdtABE
-UhBcjG4qZtDZsS1JQHys243vhLaDTSvvTeBiJA2tmokqECTBcSOCAGkAxMKlVAva
-4IsLRaBBqhxDbcGtgdw03mFcLUaFuhtKuuEIEkUleJQwby/zwu9uvvZK4xTV+ECM
-a8lmzxKmqkBggYK1+xPdbmJclm6tSZhE/OSJtCEjs+unJIQkT9hCWgBJqGMS07Eh
-AJNmBiuVEVdTyjkIJkavuZmx2sJF13htgEZUCC23lZFOE6gWbM9WyYNJTM8yCQrb
-0Sx3OQvBML5cRATAQkSQkAJOAhoxpQkNi4ZiEVDbdtJAME0RXNDXGHA3M3Q0mm1o
-IEwbWpaM1DQCSMbGRCAu3iRIQiT6RlBpT1n3tfwvUXz3gIVlx3mEximY/kZW1kNG
-sgEJIrBisaEoGYPJ+1CQUYFBw+eGEHJQBpNHjErXUJY2iWHQ30hXwFBuMSxQ2lB5
-bg+/LX3euG6HsHUB1lFvBvaiaBrITVwkCTa1d0s9CHZCiDZjbWReKyrpPE2oSa7o
-LPrR4BJvys9ttjUpzETSSMxh8vsr9dXTwKBtK+1xCTGDQmNIaE29HmHdS5GSxpya
-MismcAUSEgSxHBrKtgsZzduG7vHZn16l3kFkVITtENIzS2JsiBwFTDlhgexsjBHv
-5HXOYxHBzoSDCcPZ0ctvkY9aS5XpoQuFYkGJgCsqjJZeUMNUEpDSbKcnUc1PifIA
-CbR2UoXawBlspkEBr9HBfvUi/MUakZVOf1WKYrqSaIXce62JOyhJLq3qJBloTA0F
-VbILEtM+heFmNRCFt70GJrExVJri0ArYbCRbADSGDBpBXxxb/6fo+s3C7uaL7RjM
-LV2IQBNrAJrKFeJwTsPnxbAsemirUx2lk1kaxschzdK4TQNJN5wQnolIFg401OZ4
-2na11LnT3lR+1k1TMJhiAjXMk0F1ooHnYlt9LKfJ3ZIOmeY+2l9bUQHWFNGyEyfj
-EAcu3kpGLq0Ez7XOS+EpAASRQTAYMATfVQibHLTT30zG732+pNe9za1JNt8sNJYn
-RjWuJ6jL5ILV0rcd9vT7X9fObvcXitpvJ2XBJE+PhX2HaTkyWeF9pwnlQNrTe9hV
-tzhA+ihZrDrHNmLcQjZbnv/IMubqq8egxY80t5n6vZ6U5TR6U9uZJvai1xtqAyCR
-NWkW52m00rDTEuO6BA4q2RHDWwbETF55rRsWLIgNW9qJCyMHPbTM/dMBmWMQSMxz
-4M2pRzt47SICxA327UqSCEERqMFybmYi3nUxePtLgHYplqRiw4ynMbXd/kiQ0LE0
-PKJSSCXA42ymziCpAxNWflzpzQdJZusahRFr6t6m+4p273/Taj7k+hZyNgBAgXAY
-8F7pTts6orLb8IA6o4TOwkwQYmKvKu9VwMrE7+GUhVIAgY9a8DyQMiDBkEAwh7S1
-KgCBfao8DK1CwSS8Z3WjL5MEgt93z2koUQCD/YxMBppiCMp7SDVSmkkIHptfGpeh
-t+M13Ccv1tavIASFiaQl6rBz3K4N3DSGwNkCibrvEAC0fQirOWnc4NVbcLKpFG1l
-NQXF/eqdT79wq1Mvlap3QSCLhcD2D3fCkKVWid4aSjtp9FOX1Uaf7P9eT93zd9Sv
-mj2yNLRUGzyI/0oONNSzmmkvJ5Cq2X2CdldIWMGZO57RJ8oyATAWTQmRmNkfh0Sx
-uuR/J9oUsomVy1AEntc0dlPivkqBkBqrxU3j5PnWkaI3ZRGc0gg9spCQEISh4xEU
-pMhVrnmDQLfLP8Ouqpx917MAw7hkjQk6BJFTAbXDsz3LSHIxo/gB8qrA1vbvdZZh
-LtR0frJdfdppX8nAQX/TAxOQ8+H6yw8a9i7/zJEfSYIhop59N/fhcWW2F14cj2Xc
-fyHaZ04lTO4uPnly91jwuFPaREuZVp8AxImIhlkxkAN61tWdWG7tEbaCgszh6VIz
-ThFnHo2Vi8SQXPrXCN7J9Tc9ZYiAYqoThV/u6SYsea5aZL8deOvKBQCgZZuIxX1z
-4EnfcqG176vY4VqMBIC4pMJz0WcHJYqN+j7BiwGoMBwExrIdTB7q4XIFLotcIpS0
-1MqyVsesvoQq7WObmGQXdMliMirSLcDuSx8Qy+4pIBgGDIyMp1qbonnGdcHYvU8S
-O0A8s/iua5oFdNZTWvbVI4FUH9sKcLiB3/fIAF+sB4n8q6L+UCfmbPcAo/crQ6b3
-HqhDBMY9J0q/jdz9GNYZ/1fbXdkUqAQKFePhtzJDRBZba27+LPQNMCcrHMq06F1T
-4QmLmkHt7LxB2pAczUO+T2O9bHEw/HWw+dYf2MoRDUw=
-`
-
-var outOfRangeSelector = []byte{
-	0x42, 0x5a, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
-	0x53, 0x59, 0x4e, 0xec, 0xe8, 0x36, 0x00, 0x00,
-	0x02, 0x51, 0x80, 0x00, 0x10, 0x40, 0x00, 0x06,
-	0x44, 0x90, 0x80, 0x20, 0x00, 0x31, 0x06, 0x4c,
-	0x41, 0x01, 0xa7, 0xa9, 0xa5, 0x80, 0xbb, 0x94,
-	0x31, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0x00,
-	0x00, 0x00, 0x00,
-}
diff --git a/src/compress/bzip2/testdata/fail-issue5747.bz2 b/src/compress/bzip2/testdata/fail-issue5747.bz2
new file mode 100644
index 0000000..2bf2b6a
Binary files /dev/null and b/src/compress/bzip2/testdata/fail-issue5747.bz2 differ
diff --git a/src/compress/bzip2/testdata/pass-random1.bin b/src/compress/bzip2/testdata/pass-random1.bin
new file mode 100644
index 0000000..6e17879
Binary files /dev/null and b/src/compress/bzip2/testdata/pass-random1.bin differ
diff --git a/src/compress/bzip2/testdata/pass-random1.bz2 b/src/compress/bzip2/testdata/pass-random1.bz2
new file mode 100644
index 0000000..f6a9dc7
Binary files /dev/null and b/src/compress/bzip2/testdata/pass-random1.bz2 differ
diff --git a/src/compress/bzip2/testdata/pass-random2.bin b/src/compress/bzip2/testdata/pass-random2.bin
new file mode 100644
index 0000000..f152d40
--- /dev/null
+++ b/src/compress/bzip2/testdata/pass-random2.bin
@@ -0,0 +1 @@
+��e&�DJJ��9d��E
C��#;�23��q�l*+�����~�
��;&4�ۛ,���cc�5�s5�
\ No newline at end of file
diff --git a/src/compress/bzip2/testdata/pass-random2.bz2 b/src/compress/bzip2/testdata/pass-random2.bz2
new file mode 100644
index 0000000..91ef775
Binary files /dev/null and b/src/compress/bzip2/testdata/pass-random2.bz2 differ
diff --git a/src/compress/bzip2/testdata/pass-sawtooth.bz2 b/src/compress/bzip2/testdata/pass-sawtooth.bz2
new file mode 100644
index 0000000..579a378
Binary files /dev/null and b/src/compress/bzip2/testdata/pass-sawtooth.bz2 differ
diff --git a/src/compress/flate/copy.go b/src/compress/flate/copy.go
deleted file mode 100644
index a3200a8..0000000
--- a/src/compress/flate/copy.go
+++ /dev/null
@@ -1,32 +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 flate
-
-// forwardCopy is like the built-in copy function except that it always goes
-// forward from the start, even if the dst and src overlap.
-// It is equivalent to:
-//   for i := 0; i < n; i++ {
-//     mem[dst+i] = mem[src+i]
-//   }
-func forwardCopy(mem []byte, dst, src, n int) {
-	if dst <= src {
-		copy(mem[dst:dst+n], mem[src:src+n])
-		return
-	}
-	for {
-		if dst >= src+n {
-			copy(mem[dst:dst+n], mem[src:src+n])
-			return
-		}
-		// There is some forward overlap.  The destination
-		// will be filled with a repeated pattern of mem[src:src+k].
-		// We copy one instance of the pattern here, then repeat.
-		// Each time around this loop k will double.
-		k := dst - src
-		copy(mem[dst:dst+k], mem[src:src+k])
-		n -= k
-		dst += k
-	}
-}
diff --git a/src/compress/flate/copy_test.go b/src/compress/flate/copy_test.go
deleted file mode 100644
index 2011b15..0000000
--- a/src/compress/flate/copy_test.go
+++ /dev/null
@@ -1,54 +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 flate
-
-import (
-	"testing"
-)
-
-func TestForwardCopy(t *testing.T) {
-	testCases := []struct {
-		dst0, dst1 int
-		src0, src1 int
-		want       string
-	}{
-		{0, 9, 0, 9, "012345678"},
-		{0, 5, 4, 9, "45678"},
-		{4, 9, 0, 5, "01230"},
-		{1, 6, 3, 8, "34567"},
-		{3, 8, 1, 6, "12121"},
-		{0, 9, 3, 6, "345"},
-		{3, 6, 0, 9, "012"},
-		{1, 6, 0, 9, "00000"},
-		{0, 4, 7, 8, "7"},
-		{0, 1, 6, 8, "6"},
-		{4, 4, 6, 9, ""},
-		{2, 8, 6, 6, ""},
-		{0, 0, 0, 0, ""},
-	}
-	for _, tc := range testCases {
-		b := []byte("0123456789")
-		n := tc.dst1 - tc.dst0
-		if tc.src1-tc.src0 < n {
-			n = tc.src1 - tc.src0
-		}
-		forwardCopy(b, tc.dst0, tc.src0, n)
-		got := string(b[tc.dst0 : tc.dst0+n])
-		if got != tc.want {
-			t.Errorf("dst=b[%d:%d], src=b[%d:%d]: got %q, want %q",
-				tc.dst0, tc.dst1, tc.src0, tc.src1, got, tc.want)
-		}
-		// Check that the bytes outside of dst[:n] were not modified.
-		for i, x := range b {
-			if i >= tc.dst0 && i < tc.dst0+n {
-				continue
-			}
-			if int(x) != '0'+i {
-				t.Errorf("dst=b[%d:%d], src=b[%d:%d]: copy overrun at b[%d]: got '%c', want '%c'",
-					tc.dst0, tc.dst1, tc.src0, tc.src1, i, x, '0'+i)
-			}
-		}
-	}
-}
diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go
index 169a0c7..8a085ba 100644
--- a/src/compress/flate/deflate.go
+++ b/src/compress/flate/deflate.go
@@ -13,54 +13,65 @@ import (
 const (
 	NoCompression      = 0
 	BestSpeed          = 1
-	fastCompression    = 3
 	BestCompression    = 9
 	DefaultCompression = -1
-	logWindowSize      = 15
-	windowSize         = 1 << logWindowSize
-	windowMask         = windowSize - 1
-	logMaxOffsetSize   = 15  // Standard DEFLATE
-	minMatchLength     = 3   // The smallest match that the compressor looks for
-	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 to
+	HuffmanOnly        = -2 // Disables match search and only does Huffman entropy reduction.
+)
+
+const (
+	logWindowSize = 15
+	windowSize    = 1 << logWindowSize
+	windowMask    = windowSize - 1
+
+	// The LZ77 step produces a sequence of literal tokens and <length, offset>
+	// pair tokens. The offset is also known as distance. The underlying wire
+	// format limits the range of lengths and offsets. For example, there are
+	// 256 legitimate lengths: those in the range [3, 258]. This package's
+	// compressor uses a higher minimum match length, enabling optimizations
+	// such as finding matches via 32-bit loads and compares.
+	baseMatchLength = 3       // The smallest match length per the RFC section 3.2.5
+	minMatchLength  = 4       // The smallest match length that the compressor actually emits
+	maxMatchLength  = 258     // The largest match length
+	baseMatchOffset = 1       // The smallest match offset
+	maxMatchOffset  = 1 << 15 // The largest match offset
+
+	// The maximum number of tokens we put into a single flate block, just to
 	// stop things from getting too large.
 	maxFlateBlockTokens = 1 << 14
 	maxStoreBlockSize   = 65535
-	hashBits            = 17
+	hashBits            = 17 // After 17 performance degrades
 	hashSize            = 1 << hashBits
 	hashMask            = (1 << hashBits) - 1
-	hashShift           = (hashBits + minMatchLength - 1) / minMatchLength
 	maxHashOffset       = 1 << 24
 
 	skipNever = math.MaxInt32
 )
 
 type compressionLevel struct {
-	good, lazy, nice, chain, fastSkipHashing int
+	level, good, lazy, nice, chain, fastSkipHashing int
 }
 
 var levels = []compressionLevel{
-	{}, // 0
-	// For levels 1-3 we don't bother trying with lazy matches
-	{3, 0, 8, 4, 4},
-	{3, 0, 16, 8, 5},
-	{3, 0, 32, 32, 6},
+	{0, 0, 0, 0, 0, 0}, // NoCompression.
+	{1, 0, 0, 0, 0, 0}, // BestSpeed uses a custom algorithm; see deflatefast.go.
+	// For levels 2-3 we don't bother trying with lazy matches.
+	{2, 4, 0, 16, 8, 5},
+	{3, 4, 0, 32, 32, 6},
 	// Levels 4-9 use increasingly more lazy matching
 	// and increasingly stringent conditions for "good enough".
-	{4, 4, 16, 16, skipNever},
-	{8, 16, 32, 32, skipNever},
-	{8, 16, 128, 128, skipNever},
-	{8, 32, 128, 256, skipNever},
-	{32, 128, 258, 1024, skipNever},
-	{32, 258, 258, 4096, skipNever},
+	{4, 4, 4, 16, 16, skipNever},
+	{5, 8, 16, 32, 32, skipNever},
+	{6, 8, 16, 128, 128, skipNever},
+	{7, 8, 32, 128, 256, skipNever},
+	{8, 32, 128, 258, 1024, skipNever},
+	{9, 32, 258, 258, 4096, skipNever},
 }
 
 type compressor struct {
 	compressionLevel
 
-	w *huffmanBitWriter
+	w          *huffmanBitWriter
+	bulkHasher func([]byte, []uint32)
 
 	// compression algorithm
 	fill func(*compressor, []byte) int // copy data to window
@@ -73,8 +84,8 @@ type compressor struct {
 	// hashPrev[hashHead[hashValue] & windowMask] contains the previous index
 	// with the same hash value.
 	chainHead  int
-	hashHead   []int
-	hashPrev   []int
+	hashHead   [hashSize]uint32
+	hashPrev   [windowSize]uint32
 	hashOffset int
 
 	// input window: unprocessed data is window[index:windowEnd]
@@ -90,9 +101,12 @@ type compressor struct {
 	// deflate state
 	length         int
 	offset         int
-	hash           int
+	hash           uint32
 	maxInsertIndex int
 	err            error
+
+	// hashMatch must be able to contain hashes for the maximum match length.
+	hashMatch [maxMatchLength - 1]uint32
 }
 
 func (d *compressor) fillDeflate(b []byte) int {
@@ -112,15 +126,15 @@ func (d *compressor) fillDeflate(b []byte) int {
 			d.hashOffset -= delta
 			d.chainHead -= delta
 			for i, v := range d.hashPrev {
-				if v > delta {
-					d.hashPrev[i] -= delta
+				if int(v) > delta {
+					d.hashPrev[i] = uint32(int(v) - delta)
 				} else {
 					d.hashPrev[i] = 0
 				}
 			}
 			for i, v := range d.hashHead {
-				if v > delta {
-					d.hashHead[i] -= delta
+				if int(v) > delta {
+					d.hashHead[i] = uint32(int(v) - delta)
 				} else {
 					d.hashHead[i] = 0
 				}
@@ -132,19 +146,74 @@ func (d *compressor) fillDeflate(b []byte) int {
 	return n
 }
 
-func (d *compressor) writeBlock(tokens []token, index int, eof bool) error {
-	if index > 0 || eof {
+func (d *compressor) writeBlock(tokens []token, index int) error {
+	if index > 0 {
 		var window []byte
 		if d.blockStart <= index {
 			window = d.window[d.blockStart:index]
 		}
 		d.blockStart = index
-		d.w.writeBlock(tokens, eof, window)
+		d.w.writeBlock(tokens, false, window)
 		return d.w.err
 	}
 	return nil
 }
 
+// fillWindow will fill the current window with the supplied
+// dictionary and calculate all hashes.
+// This is much faster than doing a full encode.
+// Should only be used after a reset.
+func (d *compressor) fillWindow(b []byte) {
+	// Do not fill window if we are in store-only mode.
+	if d.compressionLevel.level < 2 {
+		return
+	}
+	if d.index != 0 || d.windowEnd != 0 {
+		panic("internal error: fillWindow called with stale data")
+	}
+
+	// If we are given too much, cut it.
+	if len(b) > windowSize {
+		b = b[len(b)-windowSize:]
+	}
+	// Add all to window.
+	n := copy(d.window, b)
+
+	// Calculate 256 hashes at the time (more L1 cache hits)
+	loops := (n + 256 - minMatchLength) / 256
+	for j := 0; j < loops; j++ {
+		index := j * 256
+		end := index + 256 + minMatchLength - 1
+		if end > n {
+			end = n
+		}
+		toCheck := d.window[index:end]
+		dstSize := len(toCheck) - minMatchLength + 1
+
+		if dstSize <= 0 {
+			continue
+		}
+
+		dst := d.hashMatch[:dstSize]
+		d.bulkHasher(toCheck, dst)
+		var newH uint32
+		for i, val := range dst {
+			di := i + index
+			newH = val
+			hh := &d.hashHead[newH&hashMask]
+			// Get previous value with the same hash.
+			// Our chain should point to the previous value.
+			d.hashPrev[di&windowMask] = *hh
+			// Set the head of the hash chain to us.
+			*hh = uint32(di + d.hashOffset)
+		}
+		d.hash = newH
+	}
+	// Update window information.
+	d.windowEnd = n
+	d.index = n
+}
+
 // Try to find a match starting at index whose length is greater than prevSize.
 // We only look at chainCount possibilities before giving up.
 func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
@@ -168,20 +237,15 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead
 		tries >>= 2
 	}
 
-	w0 := win[pos]
-	w1 := win[pos+1]
 	wEnd := win[pos+length]
+	wPos := win[pos:]
 	minIndex := pos - windowSize
 
 	for i := prevHead; tries > 0; tries-- {
-		if w0 == win[i] && w1 == win[i+1] && wEnd == win[i+length] {
-			// The hash function ensures that if win[i] and win[i+1] match, win[i+2] matches
+		if wEnd == win[i+length] {
+			n := matchLen(win[i:], wPos, minMatchLook)
 
-			n := 3
-			for pos+n < len(win) && win[i+n] == win[pos+n] {
-				n++
-			}
-			if n > length && (n > 3 || pos-i <= 4096) {
+			if n > length && (n > minMatchLength || pos-i <= 4096) {
 				length = n
 				offset = pos - i
 				ok = true
@@ -196,7 +260,8 @@ func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead
 			// hashPrev[i & windowMask] has already been overwritten, so stop now.
 			break
 		}
-		if i = d.hashPrev[i&windowMask] - d.hashOffset; i < minIndex || i < 0 {
+		i = int(d.hashPrev[i&windowMask]) - d.hashOffset
+		if i < minIndex || i < 0 {
 			break
 		}
 	}
@@ -211,9 +276,84 @@ func (d *compressor) writeStoredBlock(buf []byte) error {
 	return d.w.err
 }
 
+const hashmul = 0x1e35a7bd
+
+// hash4 returns a hash representation of the first 4 bytes
+// of the supplied slice.
+// The caller must ensure that len(b) >= 4.
+func hash4(b []byte) uint32 {
+	return ((uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24) * hashmul) >> (32 - hashBits)
+}
+
+// bulkHash4 will compute hashes using the same
+// algorithm as hash4
+func bulkHash4(b []byte, dst []uint32) {
+	if len(b) < minMatchLength {
+		return
+	}
+	hb := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+	dst[0] = (hb * hashmul) >> (32 - hashBits)
+	end := len(b) - minMatchLength + 1
+	for i := 1; i < end; i++ {
+		hb = (hb << 8) | uint32(b[i+3])
+		dst[i] = (hb * hashmul) >> (32 - hashBits)
+	}
+}
+
+// matchLen returns the number of matching bytes in a and b
+// up to length 'max'. Both slices must be at least 'max'
+// bytes in size.
+func matchLen(a, b []byte, max int) int {
+	a = a[:max]
+	b = b[:len(a)]
+	for i, av := range a {
+		if b[i] != av {
+			return i
+		}
+	}
+	return max
+}
+
+// encSpeed will compress and store the currently added data,
+// if enough has been accumulated or we at the end of the stream.
+// Any error that occurred will be in d.err
+func (d *compressor) encSpeed() {
+	// We only compress if we have maxStoreBlockSize.
+	if d.windowEnd < maxStoreBlockSize {
+		if !d.sync {
+			return
+		}
+
+		// Handle small sizes.
+		if d.windowEnd < 128 {
+			switch {
+			case d.windowEnd == 0:
+				return
+			case d.windowEnd <= 16:
+				d.err = d.writeStoredBlock(d.window[:d.windowEnd])
+			default:
+				d.w.writeBlockHuff(false, d.window[:d.windowEnd])
+				d.err = d.w.err
+			}
+			d.windowEnd = 0
+			return
+		}
+
+	}
+	// Encode the block.
+	d.tokens = encodeBestSpeed(d.tokens[:0], d.window[:d.windowEnd])
+
+	// If we removed less than 1/16th, Huffman compress the block.
+	if len(d.tokens) > d.windowEnd-(d.windowEnd>>4) {
+		d.w.writeBlockHuff(false, d.window[:d.windowEnd])
+	} else {
+		d.w.writeBlockDynamic(d.tokens, false, d.window[:d.windowEnd])
+	}
+	d.err = d.w.err
+	d.windowEnd = 0
+}
+
 func (d *compressor) initDeflate() {
-	d.hashHead = make([]int, hashSize)
-	d.hashPrev = make([]int, windowSize)
 	d.window = make([]byte, 2*windowSize)
 	d.hashOffset = 1
 	d.tokens = make([]token, 0, maxFlateBlockTokens+1)
@@ -223,6 +363,7 @@ func (d *compressor) initDeflate() {
 	d.index = 0
 	d.hash = 0
 	d.chainHead = -1
+	d.bulkHasher = bulkHash4
 }
 
 func (d *compressor) deflate() {
@@ -232,7 +373,7 @@ func (d *compressor) deflate() {
 
 	d.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
 	if d.index < d.maxInsertIndex {
-		d.hash = int(d.window[d.index])<<hashShift + int(d.window[d.index+1])
+		d.hash = hash4(d.window[d.index : d.index+minMatchLength])
 	}
 
 Loop:
@@ -256,7 +397,7 @@ Loop:
 					d.byteAvailable = false
 				}
 				if len(d.tokens) > 0 {
-					if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
+					if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
 						return
 					}
 					d.tokens = d.tokens[:0]
@@ -266,10 +407,11 @@ Loop:
 		}
 		if d.index < d.maxInsertIndex {
 			// Update the hash
-			d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask
-			d.chainHead = d.hashHead[d.hash]
-			d.hashPrev[d.index&windowMask] = d.chainHead
-			d.hashHead[d.hash] = d.index + d.hashOffset
+			d.hash = hash4(d.window[d.index : d.index+minMatchLength])
+			hh := &d.hashHead[d.hash&hashMask]
+			d.chainHead = int(*hh)
+			d.hashPrev[d.index&windowMask] = uint32(d.chainHead)
+			*hh = uint32(d.index + d.hashOffset)
 		}
 		prevLength := d.length
 		prevOffset := d.offset
@@ -293,9 +435,9 @@ Loop:
 			// There was a match at the previous step, and the current match is
 			// not better. Output the previous match.
 			if d.fastSkipHashing != skipNever {
-				d.tokens = append(d.tokens, matchToken(uint32(d.length-minMatchLength), uint32(d.offset-minOffsetSize)))
+				d.tokens = append(d.tokens, matchToken(uint32(d.length-baseMatchLength), uint32(d.offset-baseMatchOffset)))
 			} else {
-				d.tokens = append(d.tokens, matchToken(uint32(prevLength-minMatchLength), uint32(prevOffset-minOffsetSize)))
+				d.tokens = append(d.tokens, matchToken(uint32(prevLength-baseMatchLength), uint32(prevOffset-baseMatchOffset)))
 			}
 			// Insert in the hash table all strings up to the end of the match.
 			// index and index-1 are already inserted. If there is not enough
@@ -310,12 +452,13 @@ Loop:
 				}
 				for d.index++; d.index < newIndex; d.index++ {
 					if d.index < d.maxInsertIndex {
-						d.hash = (d.hash<<hashShift + int(d.window[d.index+2])) & hashMask
+						d.hash = hash4(d.window[d.index : d.index+minMatchLength])
 						// Get previous value with the same hash.
 						// Our chain should point to the previous value.
-						d.hashPrev[d.index&windowMask] = d.hashHead[d.hash]
+						hh := &d.hashHead[d.hash&hashMask]
+						d.hashPrev[d.index&windowMask] = *hh
 						// Set the head of the hash chain to us.
-						d.hashHead[d.hash] = d.index + d.hashOffset
+						*hh = uint32(d.index + d.hashOffset)
 					}
 				}
 				if d.fastSkipHashing == skipNever {
@@ -327,12 +470,12 @@ Loop:
 				// item into the table.
 				d.index += d.length
 				if d.index < d.maxInsertIndex {
-					d.hash = (int(d.window[d.index])<<hashShift + int(d.window[d.index+1]))
+					d.hash = hash4(d.window[d.index : d.index+minMatchLength])
 				}
 			}
 			if len(d.tokens) == maxFlateBlockTokens {
 				// The block includes the current character
-				if d.err = d.writeBlock(d.tokens, d.index, false); d.err != nil {
+				if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
 					return
 				}
 				d.tokens = d.tokens[:0]
@@ -345,7 +488,7 @@ Loop:
 				}
 				d.tokens = append(d.tokens, literalToken(uint32(d.window[i])))
 				if len(d.tokens) == maxFlateBlockTokens {
-					if d.err = d.writeBlock(d.tokens, i+1, false); d.err != nil {
+					if d.err = d.writeBlock(d.tokens, i+1); d.err != nil {
 						return
 					}
 					d.tokens = d.tokens[:0]
@@ -372,17 +515,37 @@ func (d *compressor) store() {
 	d.windowEnd = 0
 }
 
+// storeHuff compresses and stores the currently added data
+// when the d.window is full or we are at the end of the stream.
+// Any error that occurred will be in d.err
+func (d *compressor) storeHuff() {
+	if d.windowEnd < len(d.window) && !d.sync || d.windowEnd == 0 {
+		return
+	}
+	d.w.writeBlockHuff(false, d.window[:d.windowEnd])
+	d.err = d.w.err
+	d.windowEnd = 0
+}
+
 func (d *compressor) write(b []byte) (n int, err error) {
+	if d.err != nil {
+		return 0, d.err
+	}
 	n = len(b)
-	b = b[d.fill(d, b):]
 	for len(b) > 0 {
 		d.step(d)
 		b = b[d.fill(d, b):]
+		if d.err != nil {
+			return 0, d.err
+		}
 	}
-	return n, d.err
+	return n, nil
 }
 
 func (d *compressor) syncFlush() error {
+	if d.err != nil {
+		return d.err
+	}
 	d.sync = true
 	d.step(d)
 	if d.err == nil {
@@ -402,56 +565,51 @@ func (d *compressor) init(w io.Writer, level int) (err error) {
 		d.window = make([]byte, maxStoreBlockSize)
 		d.fill = (*compressor).fillStore
 		d.step = (*compressor).store
+	case level == HuffmanOnly:
+		d.window = make([]byte, maxStoreBlockSize)
+		d.fill = (*compressor).fillStore
+		d.step = (*compressor).storeHuff
+	case level == BestSpeed:
+		d.compressionLevel = levels[level]
+		d.window = make([]byte, maxStoreBlockSize)
+		d.fill = (*compressor).fillStore
+		d.step = (*compressor).encSpeed
+		d.tokens = make([]token, maxStoreBlockSize)
 	case level == DefaultCompression:
 		level = 6
 		fallthrough
-	case 1 <= level && level <= 9:
+	case 2 <= level && level <= 9:
 		d.compressionLevel = levels[level]
 		d.initDeflate()
 		d.fill = (*compressor).fillDeflate
 		d.step = (*compressor).deflate
 	default:
-		return fmt.Errorf("flate: invalid compression level %d: want value in range [-1, 9]", level)
+		return fmt.Errorf("flate: invalid compression level %d: want value in range [-2, 9]", level)
 	}
 	return nil
 }
 
-var zeroes [32]int
-var bzeroes [256]byte
-
 func (d *compressor) reset(w io.Writer) {
 	d.w.reset(w)
 	d.sync = false
 	d.err = nil
-	switch d.compressionLevel.chain {
-	case 0:
-		// level was NoCompression.
-		for i := range d.window {
-			d.window[i] = 0
-		}
+	switch d.compressionLevel.level {
+	case NoCompression:
+		d.windowEnd = 0
+	case BestSpeed:
 		d.windowEnd = 0
+		d.tokens = d.tokens[:0]
 	default:
 		d.chainHead = -1
-		for s := d.hashHead; len(s) > 0; {
-			n := copy(s, zeroes[:])
-			s = s[n:]
+		for i := range d.hashHead {
+			d.hashHead[i] = 0
 		}
-		for s := d.hashPrev; len(s) > 0; s = s[len(zeroes):] {
-			copy(s, zeroes[:])
+		for i := range d.hashPrev {
+			d.hashPrev[i] = 0
 		}
 		d.hashOffset = 1
-
 		d.index, d.windowEnd = 0, 0
-		for s := d.window; len(s) > 0; {
-			n := copy(s, bzeroes[:])
-			s = s[n:]
-		}
 		d.blockStart, d.byteAvailable = 0, false
-
-		d.tokens = d.tokens[:maxFlateBlockTokens+1]
-		for i := 0; i <= maxFlateBlockTokens; i++ {
-			d.tokens[i] = 0
-		}
 		d.tokens = d.tokens[:0]
 		d.length = minMatchLength - 1
 		d.offset = 0
@@ -461,6 +619,9 @@ func (d *compressor) reset(w io.Writer) {
 }
 
 func (d *compressor) close() error {
+	if d.err != nil {
+		return d.err
+	}
 	d.sync = true
 	d.step(d)
 	if d.err != nil {
@@ -477,10 +638,14 @@ func (d *compressor) close() error {
 // Following zlib, levels range from 1 (BestSpeed) to 9 (BestCompression);
 // higher levels typically run slower but compress more. Level 0
 // (NoCompression) does not attempt any compression; it only adds the
-// necessary DEFLATE framing. Level -1 (DefaultCompression) uses the default
-// compression level.
+// necessary DEFLATE framing.
+// Level -1 (DefaultCompression) uses the default compression level.
+// Level -2 (HuffmanOnly) will use Huffman compression only, giving
+// a very fast compression for all types of input, but sacrificing considerable
+// compression efficiency.
 //
-// If level is in the range [-1, 9] then the error returned will be nil.
+//
+// If level is in the range [-2, 9] then the error returned will be nil.
 // Otherwise the error returned will be non-nil.
 func NewWriter(w io.Writer, level int) (*Writer, error) {
 	var dw Writer
@@ -491,34 +656,28 @@ func NewWriter(w io.Writer, level int) (*Writer, error) {
 }
 
 // NewWriterDict is like NewWriter but initializes the new
-// Writer with a preset dictionary.  The returned Writer behaves
+// Writer with a preset dictionary. The returned Writer behaves
 // as if the dictionary had been written to it without producing
-// any compressed output.  The compressed data written to w
+// any compressed output. The compressed data written to w
 // can only be decompressed by a Reader initialized with the
 // same dictionary.
 func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) {
-	dw := &dictWriter{w, false}
+	dw := &dictWriter{w}
 	zw, err := NewWriter(dw, level)
 	if err != nil {
 		return nil, err
 	}
-	zw.Write(dict)
-	zw.Flush()
-	dw.enabled = true
+	zw.d.fillWindow(dict)
 	zw.dict = append(zw.dict, dict...) // duplicate dictionary for Reset method.
 	return zw, err
 }
 
 type dictWriter struct {
-	w       io.Writer
-	enabled bool
+	w io.Writer
 }
 
 func (w *dictWriter) Write(b []byte) (n int, err error) {
-	if w.enabled {
-		return w.w.Write(b)
-	}
-	return len(b), nil
+	return w.w.Write(b)
 }
 
 // A Writer takes data written to it and writes the compressed
@@ -560,10 +719,7 @@ func (w *Writer) Reset(dst io.Writer) {
 		// w was created with NewWriterDict
 		dw.w = dst
 		w.d.reset(dw)
-		dw.enabled = false
-		w.Write(w.dict)
-		w.Flush()
-		dw.enabled = true
+		w.d.fillWindow(w.dict)
 	} else {
 		// w was created with NewWriter
 		w.d.reset(dst)
diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go
index 72bc665..27a3b38 100644
--- a/src/compress/flate/deflate_test.go
+++ b/src/compress/flate/deflate_test.go
@@ -42,10 +42,10 @@ var deflateTests = []*deflateTest{
 	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0,
 		[]byte{0, 8, 0, 247, 255, 17, 17, 17, 17, 17, 17, 17, 17, 1, 0, 0, 255, 255},
 	},
-	{[]byte{}, 1, []byte{1, 0, 0, 255, 255}},
-	{[]byte{0x11}, 1, []byte{18, 4, 4, 0, 0, 255, 255}},
-	{[]byte{0x11, 0x12}, 1, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
-	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 1, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
+	{[]byte{}, 2, []byte{1, 0, 0, 255, 255}},
+	{[]byte{0x11}, 2, []byte{18, 4, 4, 0, 0, 255, 255}},
+	{[]byte{0x11, 0x12}, 2, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
+	{[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 2, []byte{18, 132, 2, 64, 0, 0, 0, 255, 255}},
 	{[]byte{}, 9, []byte{1, 0, 0, 255, 255}},
 	{[]byte{0x11}, 9, []byte{18, 4, 4, 0, 0, 255, 255}},
 	{[]byte{0x11, 0x12}, 9, []byte{18, 20, 2, 4, 0, 0, 255, 255}},
@@ -80,6 +80,32 @@ func largeDataChunk() []byte {
 	return result
 }
 
+func TestBulkHash4(t *testing.T) {
+	for _, x := range deflateTests {
+		y := x.out
+		if len(y) < minMatchLength {
+			continue
+		}
+		y = append(y, y...)
+		for j := 4; j < len(y); j++ {
+			y := y[:j]
+			dst := make([]uint32, len(y)-minMatchLength+1)
+			for i := range dst {
+				dst[i] = uint32(i + 100)
+			}
+			bulkHash4(y, dst)
+			for i, got := range dst {
+				want := hash4(y[i:])
+				if got != want && got == uint32(i)+100 {
+					t.Errorf("Len:%d Index:%d, want 0x%08x but not modified", len(y), i, want)
+				} else if got != want {
+					t.Errorf("Len:%d Index:%d, got 0x%08x want:0x%08x", len(y), i, got, want)
+				}
+			}
+		}
+	}
+}
+
 func TestDeflate(t *testing.T) {
 	for _, h := range deflateTests {
 		var buf bytes.Buffer
@@ -91,7 +117,7 @@ func TestDeflate(t *testing.T) {
 		w.Write(h.in)
 		w.Close()
 		if !bytes.Equal(buf.Bytes(), h.out) {
-			t.Errorf("Deflate(%d, %x) = %x, want %x", h.level, h.in, buf.Bytes(), h.out)
+			t.Errorf("Deflate(%d, %x) = \n%#v, want \n%#v", h.level, h.in, buf.Bytes(), h.out)
 		}
 	}
 }
@@ -247,7 +273,7 @@ func testSync(t *testing.T, level int, input []byte, name string) {
 		// not necessarily the case: the write Flush may emit
 		// some extra framing bits that are not necessary
 		// to process to obtain the first half of the uncompressed
-		// data.  The test ran correctly most of the time, because
+		// data. The test ran correctly most of the time, because
 		// the background goroutine had usually read even
 		// those extra bits by now, but it's not a useful thing to
 		// check.
@@ -289,6 +315,9 @@ func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name str
 		t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit)
 		return
 	}
+	if limit > 0 {
+		t.Logf("level: %d, size:%.2f%%, %d b\n", level, float64(buffer.Len()*100)/float64(limit), buffer.Len())
+	}
 	r := NewReader(&buffer)
 	out, err := ioutil.ReadAll(r)
 	if err != nil {
@@ -303,15 +332,17 @@ func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name str
 	testSync(t, level, input, name)
 }
 
-func testToFromWithLimit(t *testing.T, input []byte, name string, limit [10]int) {
+func testToFromWithLimit(t *testing.T, input []byte, name string, limit [11]int) {
 	for i := 0; i < 10; i++ {
 		testToFromWithLevelAndLimit(t, i, input, name, limit[i])
 	}
+	// Test HuffmanCompression
+	testToFromWithLevelAndLimit(t, -2, input, name, limit[10])
 }
 
 func TestDeflateInflate(t *testing.T) {
 	for i, h := range deflateInflateTests {
-		testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [10]int{})
+		testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [11]int{})
 	}
 }
 
@@ -327,19 +358,19 @@ func TestReverseBits(t *testing.T) {
 type deflateInflateStringTest struct {
 	filename string
 	label    string
-	limit    [10]int
+	limit    [11]int
 }
 
 var deflateInflateStringTests = []deflateInflateStringTest{
 	{
 		"../testdata/e.txt",
 		"2.718281828...",
-		[...]int{100018, 50650, 50960, 51150, 50930, 50790, 50790, 50790, 50790, 50790},
+		[...]int{100018, 50650, 50960, 51150, 50930, 50790, 50790, 50790, 50790, 50790, 43683},
 	},
 	{
 		"../testdata/Mark.Twain-Tom.Sawyer.txt",
 		"Mark.Twain-Tom.Sawyer",
-		[...]int{407330, 187598, 180361, 172974, 169160, 163476, 160936, 160506, 160295, 160295},
+		[...]int{407330, 187598, 180361, 172974, 169160, 163476, 160936, 160506, 160295, 160295, 233460},
 	},
 }
 
@@ -457,6 +488,17 @@ func TestWriterReset(t *testing.T) {
 		// DeepEqual doesn't compare functions.
 		w.d.fill, wref.d.fill = nil, nil
 		w.d.step, wref.d.step = nil, nil
+		w.d.bulkHasher, wref.d.bulkHasher = nil, nil
+		// hashMatch is always overwritten when used.
+		copy(w.d.hashMatch[:], wref.d.hashMatch[:])
+		if len(w.d.tokens) != 0 {
+			t.Errorf("level %d Writer not reset after Reset. %d tokens were present", level, len(w.d.tokens))
+		}
+		// As long as the length is 0, we don't care about the content.
+		w.d.tokens = wref.d.tokens
+
+		// We don't care if there are values in the window, as long as it is at d.index is 0
+		w.d.window = wref.d.window
 		if !reflect.DeepEqual(w, wref) {
 			t.Errorf("level %d Writer not reset after Reset", level)
 		}
@@ -481,7 +523,7 @@ func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error))
 		w.Write(b)
 	}
 	w.Close()
-	out1 := buf.String()
+	out1 := buf.Bytes()
 
 	buf2 := new(bytes.Buffer)
 	w.Reset(buf2)
@@ -489,10 +531,103 @@ func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error))
 		w.Write(b)
 	}
 	w.Close()
-	out2 := buf2.String()
+	out2 := buf2.Bytes()
 
-	if out1 != out2 {
-		t.Errorf("got %q, expected %q", out2, out1)
+	if len(out1) != len(out2) {
+		t.Errorf("got %d, expected %d bytes", len(out2), len(out1))
+		return
+	}
+	if !bytes.Equal(out1, out2) {
+		mm := 0
+		for i, b := range out1[:len(out2)] {
+			if b != out2[i] {
+				t.Errorf("mismatch index %d: %#02x, expected %#02x", i, out2[i], b)
+			}
+			mm++
+			if mm == 10 {
+				t.Fatal("Stopping")
+			}
+		}
 	}
 	t.Logf("got %d bytes", len(out1))
 }
+
+// TestBestSpeed tests that round-tripping through deflate and then inflate
+// recovers the original input. The Write sizes are near the thresholds in the
+// compressor.encSpeed method (0, 16, 128), as well as near maxStoreBlockSize
+// (65535).
+func TestBestSpeed(t *testing.T) {
+	abc := make([]byte, 128)
+	for i := range abc {
+		abc[i] = byte(i)
+	}
+	abcabc := bytes.Repeat(abc, 131072/len(abc))
+	var want []byte
+
+	testCases := [][]int{
+		{65536, 0},
+		{65536, 1},
+		{65536, 1, 256},
+		{65536, 1, 65536},
+		{65536, 14},
+		{65536, 15},
+		{65536, 16},
+		{65536, 16, 256},
+		{65536, 16, 65536},
+		{65536, 127},
+		{65536, 128},
+		{65536, 128, 256},
+		{65536, 128, 65536},
+		{65536, 129},
+		{65536, 65536, 256},
+		{65536, 65536, 65536},
+	}
+
+	for i, tc := range testCases {
+		for _, firstN := range []int{1, 65534, 65535, 65536, 65537, 131072} {
+			tc[0] = firstN
+		outer:
+			for _, flush := range []bool{false, true} {
+				buf := new(bytes.Buffer)
+				want = want[:0]
+
+				w, err := NewWriter(buf, BestSpeed)
+				if err != nil {
+					t.Errorf("i=%d, firstN=%d, flush=%t: NewWriter: %v", i, firstN, flush, err)
+					continue
+				}
+				for _, n := range tc {
+					want = append(want, abcabc[:n]...)
+					if _, err := w.Write(abcabc[:n]); err != nil {
+						t.Errorf("i=%d, firstN=%d, flush=%t: Write: %v", i, firstN, flush, err)
+						continue outer
+					}
+					if !flush {
+						continue
+					}
+					if err := w.Flush(); err != nil {
+						t.Errorf("i=%d, firstN=%d, flush=%t: Flush: %v", i, firstN, flush, err)
+						continue outer
+					}
+				}
+				if err := w.Close(); err != nil {
+					t.Errorf("i=%d, firstN=%d, flush=%t: Close: %v", i, firstN, flush, err)
+					continue
+				}
+
+				r := NewReader(buf)
+				got, err := ioutil.ReadAll(r)
+				if err != nil {
+					t.Errorf("i=%d, firstN=%d, flush=%t: ReadAll: %v", i, firstN, flush, err)
+					continue
+				}
+				r.Close()
+
+				if !bytes.Equal(got, want) {
+					t.Errorf("i=%d, firstN=%d, flush=%t: corruption during deflate-then-inflate", i, firstN, flush)
+					continue
+				}
+			}
+		}
+	}
+}
diff --git a/src/compress/flate/deflatefast.go b/src/compress/flate/deflatefast.go
new file mode 100644
index 0000000..6b881a4
--- /dev/null
+++ b/src/compress/flate/deflatefast.go
@@ -0,0 +1,174 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+// This encoding algorithm, which prioritizes speed over output size, is
+// based on Snappy's LZ77-style encoder: github.com/golang/snappy
+
+const (
+	tableBits  = 14             // Bits used in the table.
+	tableSize  = 1 << tableBits // Size of the table.
+	tableMask  = tableSize - 1  // Mask for table indices. Redundant, but can eliminate bounds checks.
+	tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32.
+)
+
+func load32(b []byte, i int) uint32 {
+	b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line.
+	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func load64(b []byte, i int) uint64 {
+	b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line.
+	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+		uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+func hash(u uint32) uint32 {
+	return (u * 0x1e35a7bd) >> tableShift
+}
+
+// These constants are defined by the Snappy implementation so that its
+// assembly implementation can fast-path some 16-bytes-at-a-time copies. They
+// aren't necessary in the pure Go implementation, as we don't use those same
+// optimizations, but using the same thresholds doesn't really hurt.
+const (
+	inputMargin            = 16 - 1
+	minNonLiteralBlockSize = 1 + 1 + inputMargin
+)
+
+func encodeBestSpeed(dst []token, src []byte) []token {
+	// This check isn't in the Snappy implementation, but there, the caller
+	// instead of the callee handles this case.
+	if len(src) < minNonLiteralBlockSize {
+		return emitLiteral(dst, src)
+	}
+
+	// Initialize the hash table.
+	//
+	// The table element type is uint16, as s < sLimit and sLimit < len(src)
+	// and len(src) <= maxStoreBlockSize and maxStoreBlockSize == 65535.
+	var table [tableSize]uint16
+
+	// sLimit is when to stop looking for offset/length copies. The inputMargin
+	// lets us use a fast path for emitLiteral in the main loop, while we are
+	// looking for copies.
+	sLimit := len(src) - inputMargin
+
+	// nextEmit is where in src the next emitLiteral should start from.
+	nextEmit := 0
+
+	// The encoded form must start with a literal, as there are no previous
+	// bytes to copy, so we start looking for hash matches at s == 1.
+	s := 1
+	nextHash := hash(load32(src, s))
+
+	for {
+		// Copied from the C++ snappy implementation:
+		//
+		// Heuristic match skipping: If 32 bytes are scanned with no matches
+		// found, start looking only at every other byte. If 32 more bytes are
+		// scanned (or skipped), look at every third byte, etc.. When a match
+		// is found, immediately go back to looking at every byte. This is a
+		// small loss (~5% performance, ~0.1% density) for compressible data
+		// due to more bookkeeping, but for non-compressible data (such as
+		// JPEG) it's a huge win since the compressor quickly "realizes" the
+		// data is incompressible and doesn't bother looking for matches
+		// everywhere.
+		//
+		// The "skip" variable keeps track of how many bytes there are since
+		// the last match; dividing it by 32 (ie. right-shifting by five) gives
+		// the number of bytes to move ahead for each iteration.
+		skip := 32
+
+		nextS := s
+		candidate := 0
+		for {
+			s = nextS
+			bytesBetweenHashLookups := skip >> 5
+			nextS = s + bytesBetweenHashLookups
+			skip += bytesBetweenHashLookups
+			if nextS > sLimit {
+				goto emitRemainder
+			}
+			candidate = int(table[nextHash&tableMask])
+			table[nextHash&tableMask] = uint16(s)
+			nextHash = hash(load32(src, nextS))
+			// TODO: < should be <=, and add a test for that.
+			if s-candidate < maxMatchOffset && load32(src, s) == load32(src, candidate) {
+				break
+			}
+		}
+
+		// A 4-byte match has been found. We'll later see if more than 4 bytes
+		// match. But, prior to the match, src[nextEmit:s] are unmatched. Emit
+		// them as literal bytes.
+		dst = emitLiteral(dst, src[nextEmit:s])
+
+		// Call emitCopy, and then see if another emitCopy could be our next
+		// move. Repeat until we find no match for the input immediately after
+		// what was consumed by the last emitCopy call.
+		//
+		// If we exit this loop normally then we need to call emitLiteral next,
+		// though we don't yet know how big the literal will be. We handle that
+		// by proceeding to the next iteration of the main loop. We also can
+		// exit this loop via goto if we get close to exhausting the input.
+		for {
+			// Invariant: we have a 4-byte match at s, and no need to emit any
+			// literal bytes prior to s.
+			base := s
+
+			// Extend the 4-byte match as long as possible.
+			//
+			// This is an inlined version of Snappy's:
+			//	s = extendMatch(src, candidate+4, s+4)
+			s += 4
+			s1 := base + maxMatchLength
+			if s1 > len(src) {
+				s1 = len(src)
+			}
+			for i := candidate + 4; s < s1 && src[i] == src[s]; i, s = i+1, s+1 {
+			}
+
+			// matchToken is flate's equivalent of Snappy's emitCopy.
+			dst = append(dst, matchToken(uint32(s-base-baseMatchLength), uint32(base-candidate-baseMatchOffset)))
+			nextEmit = s
+			if s >= sLimit {
+				goto emitRemainder
+			}
+
+			// We could immediately start working at s now, but to improve
+			// compression we first update the hash table at s-1 and at s. If
+			// another emitCopy is not our next move, also calculate nextHash
+			// at s+1. At least on GOARCH=amd64, these three hash calculations
+			// are faster as one load64 call (with some shifts) instead of
+			// three load32 calls.
+			x := load64(src, s-1)
+			prevHash := hash(uint32(x >> 0))
+			table[prevHash&tableMask] = uint16(s - 1)
+			currHash := hash(uint32(x >> 8))
+			candidate = int(table[currHash&tableMask])
+			table[currHash&tableMask] = uint16(s)
+			// TODO: >= should be >, and add a test for that.
+			if s-candidate >= maxMatchOffset || uint32(x>>8) != load32(src, candidate) {
+				nextHash = hash(uint32(x >> 16))
+				s++
+				break
+			}
+		}
+	}
+
+emitRemainder:
+	if nextEmit < len(src) {
+		dst = emitLiteral(dst, src[nextEmit:])
+	}
+	return dst
+}
+
+func emitLiteral(dst []token, lit []byte) []token {
+	for _, v := range lit {
+		dst = append(dst, token(v))
+	}
+	return dst
+}
diff --git a/src/compress/flate/dict_decoder.go b/src/compress/flate/dict_decoder.go
new file mode 100644
index 0000000..71c75a0
--- /dev/null
+++ b/src/compress/flate/dict_decoder.go
@@ -0,0 +1,184 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+// dictDecoder implements the LZ77 sliding dictionary as used in decompression.
+// LZ77 decompresses data through sequences of two forms of commands:
+//
+//	* Literal insertions: Runs of one or more symbols are inserted into the data
+//	stream as is. This is accomplished through the writeByte method for a
+//	single symbol, or combinations of writeSlice/writeMark for multiple symbols.
+//	Any valid stream must start with a literal insertion if no preset dictionary
+//	is used.
+//
+//	* Backward copies: Runs of one or more symbols are copied from previously
+//	emitted data. Backward copies come as the tuple (dist, length) where dist
+//	determines how far back in the stream to copy from and length determines how
+//	many bytes to copy. Note that it is valid for the length to be greater than
+//	the distance. Since LZ77 uses forward copies, that situation is used to
+//	perform a form of run-length encoding on repeated runs of symbols.
+//	The writeCopy and tryWriteCopy are used to implement this command.
+//
+// For performance reasons, this implementation performs little to no sanity
+// checks about the arguments. As such, the invariants documented for each
+// method call must be respected.
+type dictDecoder struct {
+	hist []byte // Sliding window history
+
+	// Invariant: 0 <= rdPos <= wrPos <= len(hist)
+	wrPos int  // Current output position in buffer
+	rdPos int  // Have emitted hist[:rdPos] already
+	full  bool // Has a full window length been written yet?
+}
+
+// init initializes dictDecoder to have a sliding window dictionary of the given
+// size. If a preset dict is provided, it will initialize the dictionary with
+// the contents of dict.
+func (dd *dictDecoder) init(size int, dict []byte) {
+	*dd = dictDecoder{hist: dd.hist}
+
+	if cap(dd.hist) < size {
+		dd.hist = make([]byte, size)
+	}
+	dd.hist = dd.hist[:size]
+
+	if len(dict) > len(dd.hist) {
+		dict = dict[len(dict)-len(dd.hist):]
+	}
+	dd.wrPos = copy(dd.hist, dict)
+	if dd.wrPos == len(dd.hist) {
+		dd.wrPos = 0
+		dd.full = true
+	}
+	dd.rdPos = dd.wrPos
+}
+
+// histSize reports the total amount of historical data in the dictionary.
+func (dd *dictDecoder) histSize() int {
+	if dd.full {
+		return len(dd.hist)
+	}
+	return dd.wrPos
+}
+
+// availRead reports the number of bytes that can be flushed by readFlush.
+func (dd *dictDecoder) availRead() int {
+	return dd.wrPos - dd.rdPos
+}
+
+// availWrite reports the available amount of output buffer space.
+func (dd *dictDecoder) availWrite() int {
+	return len(dd.hist) - dd.wrPos
+}
+
+// writeSlice returns a slice of the available buffer to write data to.
+//
+// This invariant will be kept: len(s) <= availWrite()
+func (dd *dictDecoder) writeSlice() []byte {
+	return dd.hist[dd.wrPos:]
+}
+
+// writeMark advances the writer pointer by cnt.
+//
+// This invariant must be kept: 0 <= cnt <= availWrite()
+func (dd *dictDecoder) writeMark(cnt int) {
+	dd.wrPos += cnt
+}
+
+// writeByte writes a single byte to the dictionary.
+//
+// This invariant must be kept: 0 < availWrite()
+func (dd *dictDecoder) writeByte(c byte) {
+	dd.hist[dd.wrPos] = c
+	dd.wrPos++
+}
+
+// writeCopy copies a string at a given (dist, length) to the output.
+// This returns the number of bytes copied and may be less than the requested
+// length if the available space in the output buffer is too small.
+//
+// This invariant must be kept: 0 < dist <= histSize()
+func (dd *dictDecoder) writeCopy(dist, length int) int {
+	dstBase := dd.wrPos
+	dstPos := dstBase
+	srcPos := dstPos - dist
+	endPos := dstPos + length
+	if endPos > len(dd.hist) {
+		endPos = len(dd.hist)
+	}
+
+	// Copy non-overlapping section after destination position.
+	//
+	// This section is non-overlapping in that the copy length for this section
+	// is always less than or equal to the backwards distance. This can occur
+	// if a distance refers to data that wraps-around in the buffer.
+	// Thus, a backwards copy is performed here; that is, the exact bytes in
+	// the source prior to the copy is placed in the destination.
+	if srcPos < 0 {
+		srcPos += len(dd.hist)
+		dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:])
+		srcPos = 0
+	}
+
+	// Copy possibly overlapping section before destination position.
+	//
+	// This section can overlap if the copy length for this section is larger
+	// than the backwards distance. This is allowed by LZ77 so that repeated
+	// strings can be succinctly represented using (dist, length) pairs.
+	// Thus, a forwards copy is performed here; that is, the bytes copied is
+	// possibly dependent on the resulting bytes in the destination as the copy
+	// progresses along. This is functionally equivalent to the following:
+	//
+	//	for i := 0; i < endPos-dstPos; i++ {
+	//		dd.hist[dstPos+i] = dd.hist[srcPos+i]
+	//	}
+	//	dstPos = endPos
+	//
+	for dstPos < endPos {
+		dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos])
+	}
+
+	dd.wrPos = dstPos
+	return dstPos - dstBase
+}
+
+// tryWriteCopy tries to copy a string at a given (distance, length) to the
+// output. This specialized version is optimized for short distances.
+//
+// This method is designed to be inlined for performance reasons.
+//
+// This invariant must be kept: 0 < dist <= histSize()
+func (dd *dictDecoder) tryWriteCopy(dist, length int) int {
+	dstPos := dd.wrPos
+	endPos := dstPos + length
+	if dstPos < dist || endPos > len(dd.hist) {
+		return 0
+	}
+	dstBase := dstPos
+	srcPos := dstPos - dist
+
+	// Copy possibly overlapping section before destination position.
+loop:
+	dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos])
+	if dstPos < endPos {
+		goto loop // Avoid for-loop so that this function can be inlined
+	}
+
+	dd.wrPos = dstPos
+	return dstPos - dstBase
+}
+
+// readFlush returns a slice of the historical buffer that is ready to be
+// emitted to the user. The data returned by readFlush must be fully consumed
+// before calling any other dictDecoder methods.
+func (dd *dictDecoder) readFlush() []byte {
+	toRead := dd.hist[dd.rdPos:dd.wrPos]
+	dd.rdPos = dd.wrPos
+	if dd.wrPos == len(dd.hist) {
+		dd.wrPos, dd.rdPos = 0, 0
+		dd.full = true
+	}
+	return toRead
+}
diff --git a/src/compress/flate/dict_decoder_test.go b/src/compress/flate/dict_decoder_test.go
new file mode 100644
index 0000000..9275cff
--- /dev/null
+++ b/src/compress/flate/dict_decoder_test.go
@@ -0,0 +1,139 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+)
+
+func TestDictDecoder(t *testing.T) {
+	const (
+		abc  = "ABC\n"
+		fox  = "The quick brown fox jumped over the lazy dog!\n"
+		poem = "The Road Not Taken\nRobert Frost\n" +
+			"\n" +
+			"Two roads diverged in a yellow wood,\n" +
+			"And sorry I could not travel both\n" +
+			"And be one traveler, long I stood\n" +
+			"And looked down one as far as I could\n" +
+			"To where it bent in the undergrowth;\n" +
+			"\n" +
+			"Then took the other, as just as fair,\n" +
+			"And having perhaps the better claim,\n" +
+			"Because it was grassy and wanted wear;\n" +
+			"Though as for that the passing there\n" +
+			"Had worn them really about the same,\n" +
+			"\n" +
+			"And both that morning equally lay\n" +
+			"In leaves no step had trodden black.\n" +
+			"Oh, I kept the first for another day!\n" +
+			"Yet knowing how way leads on to way,\n" +
+			"I doubted if I should ever come back.\n" +
+			"\n" +
+			"I shall be telling this with a sigh\n" +
+			"Somewhere ages and ages hence:\n" +
+			"Two roads diverged in a wood, and I-\n" +
+			"I took the one less traveled by,\n" +
+			"And that has made all the difference.\n"
+	)
+
+	var poemRefs = []struct {
+		dist   int // Backward distance (0 if this is an insertion)
+		length int // Length of copy or insertion
+	}{
+		{0, 38}, {33, 3}, {0, 48}, {79, 3}, {0, 11}, {34, 5}, {0, 6}, {23, 7},
+		{0, 8}, {50, 3}, {0, 2}, {69, 3}, {34, 5}, {0, 4}, {97, 3}, {0, 4},
+		{43, 5}, {0, 6}, {7, 4}, {88, 7}, {0, 12}, {80, 3}, {0, 2}, {141, 4},
+		{0, 1}, {196, 3}, {0, 3}, {157, 3}, {0, 6}, {181, 3}, {0, 2}, {23, 3},
+		{77, 3}, {28, 5}, {128, 3}, {110, 4}, {70, 3}, {0, 4}, {85, 6}, {0, 2},
+		{182, 6}, {0, 4}, {133, 3}, {0, 7}, {47, 5}, {0, 20}, {112, 5}, {0, 1},
+		{58, 3}, {0, 8}, {59, 3}, {0, 4}, {173, 3}, {0, 5}, {114, 3}, {0, 4},
+		{92, 5}, {0, 2}, {71, 3}, {0, 2}, {76, 5}, {0, 1}, {46, 3}, {96, 4},
+		{130, 4}, {0, 3}, {360, 3}, {0, 3}, {178, 5}, {0, 7}, {75, 3}, {0, 3},
+		{45, 6}, {0, 6}, {299, 6}, {180, 3}, {70, 6}, {0, 1}, {48, 3}, {66, 4},
+		{0, 3}, {47, 5}, {0, 9}, {325, 3}, {0, 1}, {359, 3}, {318, 3}, {0, 2},
+		{199, 3}, {0, 1}, {344, 3}, {0, 3}, {248, 3}, {0, 10}, {310, 3}, {0, 3},
+		{93, 6}, {0, 3}, {252, 3}, {157, 4}, {0, 2}, {273, 5}, {0, 14}, {99, 4},
+		{0, 1}, {464, 4}, {0, 2}, {92, 4}, {495, 3}, {0, 1}, {322, 4}, {16, 4},
+		{0, 3}, {402, 3}, {0, 2}, {237, 4}, {0, 2}, {432, 4}, {0, 1}, {483, 5},
+		{0, 2}, {294, 4}, {0, 2}, {306, 3}, {113, 5}, {0, 1}, {26, 4}, {164, 3},
+		{488, 4}, {0, 1}, {542, 3}, {248, 6}, {0, 5}, {205, 3}, {0, 8}, {48, 3},
+		{449, 6}, {0, 2}, {192, 3}, {328, 4}, {9, 5}, {433, 3}, {0, 3}, {622, 25},
+		{615, 5}, {46, 5}, {0, 2}, {104, 3}, {475, 10}, {549, 3}, {0, 4}, {597, 8},
+		{314, 3}, {0, 1}, {473, 6}, {317, 5}, {0, 1}, {400, 3}, {0, 3}, {109, 3},
+		{151, 3}, {48, 4}, {0, 4}, {125, 3}, {108, 3}, {0, 2},
+	}
+
+	var got, want bytes.Buffer
+	var dd dictDecoder
+	dd.init(1<<11, nil)
+
+	var writeCopy = func(dist, length int) {
+		for length > 0 {
+			cnt := dd.tryWriteCopy(dist, length)
+			if cnt == 0 {
+				cnt = dd.writeCopy(dist, length)
+			}
+
+			length -= cnt
+			if dd.availWrite() == 0 {
+				got.Write(dd.readFlush())
+			}
+		}
+	}
+	var writeString = func(str string) {
+		for len(str) > 0 {
+			cnt := copy(dd.writeSlice(), str)
+			str = str[cnt:]
+			dd.writeMark(cnt)
+			if dd.availWrite() == 0 {
+				got.Write(dd.readFlush())
+			}
+		}
+	}
+
+	writeString(".")
+	want.WriteByte('.')
+
+	str := poem
+	for _, ref := range poemRefs {
+		if ref.dist == 0 {
+			writeString(str[:ref.length])
+		} else {
+			writeCopy(ref.dist, ref.length)
+		}
+		str = str[ref.length:]
+	}
+	want.WriteString(poem)
+
+	writeCopy(dd.histSize(), 33)
+	want.Write(want.Bytes()[:33])
+
+	writeString(abc)
+	writeCopy(len(abc), 59*len(abc))
+	want.WriteString(strings.Repeat(abc, 60))
+
+	writeString(fox)
+	writeCopy(len(fox), 9*len(fox))
+	want.WriteString(strings.Repeat(fox, 10))
+
+	writeString(".")
+	writeCopy(1, 9)
+	want.WriteString(strings.Repeat(".", 10))
+
+	writeString(strings.ToUpper(poem))
+	writeCopy(len(poem), 7*len(poem))
+	want.WriteString(strings.Repeat(strings.ToUpper(poem), 8))
+
+	writeCopy(dd.histSize(), 10)
+	want.Write(want.Bytes()[want.Len()-dd.histSize():][:10])
+
+	got.Write(dd.readFlush())
+	if got.String() != want.String() {
+		t.Errorf("final string mismatch:\ngot  %q\nwant %q", got.String(), want.String())
+	}
+}
diff --git a/src/compress/flate/flate_test.go b/src/compress/flate/flate_test.go
index 341d807..83c2049 100644
--- a/src/compress/flate/flate_test.go
+++ b/src/compress/flate/flate_test.go
@@ -272,3 +272,81 @@ func TestTruncatedStreams(t *testing.T) {
 		}
 	}
 }
+
+// Verify that flate.Reader.Read returns (n, io.EOF) instead
+// of (n, nil) + (0, io.EOF) when possible.
+//
+// This helps net/http.Transport reuse HTTP/1 connections more
+// aggressively.
+//
+// See https://github.com/google/go-github/pull/317 for background.
+func TestReaderEarlyEOF(t *testing.T) {
+	testSizes := []int{
+		1, 2, 3, 4, 5, 6, 7, 8,
+		100, 1000, 10000, 100000,
+		128, 1024, 16384, 131072,
+
+		// Testing multiples of windowSize triggers the case
+		// where Read will fail to return an early io.EOF.
+		windowSize * 1, windowSize * 2, windowSize * 3,
+	}
+
+	var maxSize int
+	for _, n := range testSizes {
+		if maxSize < n {
+			maxSize = n
+		}
+	}
+
+	readBuf := make([]byte, 40)
+	data := make([]byte, maxSize)
+	for i := range data {
+		data[i] = byte(i)
+	}
+
+	for _, sz := range testSizes {
+		if testing.Short() && sz > windowSize {
+			continue
+		}
+		for _, flush := range []bool{true, false} {
+			earlyEOF := true // Do we expect early io.EOF?
+
+			var buf bytes.Buffer
+			w, _ := NewWriter(&buf, 5)
+			w.Write(data[:sz])
+			if flush {
+				// If a Flush occurs after all the actual data, the flushing
+				// semantics dictate that we will observe a (0, io.EOF) since
+				// Read must return data before it knows that the stream ended.
+				w.Flush()
+				earlyEOF = false
+			}
+			w.Close()
+
+			r := NewReader(&buf)
+			for {
+				n, err := r.Read(readBuf)
+				if err == io.EOF {
+					// If the availWrite == windowSize, then that means that the
+					// previous Read returned because the write buffer was full
+					// and it just so happened that the stream had no more data.
+					// This situation is rare, but unavoidable.
+					if r.(*decompressor).dict.availWrite() == windowSize {
+						earlyEOF = false
+					}
+
+					if n == 0 && earlyEOF {
+						t.Errorf("On size:%d flush:%v, Read() = (0, io.EOF), want (n, io.EOF)", sz, flush)
+					}
+					if n != 0 && !earlyEOF {
+						t.Errorf("On size:%d flush:%v, Read() = (%d, io.EOF), want (0, io.EOF)", sz, flush, n)
+					}
+					break
+				}
+				if err != nil {
+					t.Fatal(err)
+				}
+			}
+		}
+	}
+}
diff --git a/src/compress/flate/huffman_bit_writer.go b/src/compress/flate/huffman_bit_writer.go
index 6164404..c4adef9 100644
--- a/src/compress/flate/huffman_bit_writer.go
+++ b/src/compress/flate/huffman_bit_writer.go
@@ -6,7 +6,6 @@ package flate
 
 import (
 	"io"
-	"math"
 )
 
 const (
@@ -22,6 +21,17 @@ const (
 	// The number of codegen codes.
 	codegenCodeCount = 19
 	badCode          = 255
+
+	// bufferFlushSize indicates the buffer size
+	// after which bytes are flushed to the writer.
+	// Should preferably be a multiple of 6, since
+	// we accumulate 6 bytes between writes to the buffer.
+	bufferFlushSize = 240
+
+	// bufferSize is the actual output byte buffer size.
+	// It must have additional headroom for a flush
+	// which can contain up to 8 bytes.
+	bufferSize = bufferFlushSize + 8
 )
 
 // The number of extra bits needed by length code X - LENGTH_CODES_START.
@@ -70,14 +80,14 @@ type huffmanBitWriter struct {
 	w io.Writer
 	// Data waiting to be written is bytes[0:nbytes]
 	// and then the low nbits of bits.
-	bits            uint32
-	nbits           uint32
-	bytes           [64]byte
+	bits            uint64
+	nbits           uint
+	bytes           [bufferSize]byte
+	codegenFreq     [codegenCodeCount]int32
 	nbytes          int
 	literalFreq     []int32
 	offsetFreq      []int32
 	codegen         []uint8
-	codegenFreq     []int32
 	literalEncoding *huffmanEncoder
 	offsetEncoding  *huffmanEncoder
 	codegenEncoding *huffmanEncoder
@@ -90,54 +100,16 @@ func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
 		literalFreq:     make([]int32, maxNumLit),
 		offsetFreq:      make([]int32, offsetCodeCount),
 		codegen:         make([]uint8, maxNumLit+offsetCodeCount+1),
-		codegenFreq:     make([]int32, codegenCodeCount),
 		literalEncoding: newHuffmanEncoder(maxNumLit),
-		offsetEncoding:  newHuffmanEncoder(offsetCodeCount),
 		codegenEncoding: newHuffmanEncoder(codegenCodeCount),
+		offsetEncoding:  newHuffmanEncoder(offsetCodeCount),
 	}
 }
 
 func (w *huffmanBitWriter) reset(writer io.Writer) {
 	w.w = writer
 	w.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil
-	w.bytes = [64]byte{}
-	for i := range w.codegen {
-		w.codegen[i] = 0
-	}
-	for _, s := range [...][]int32{w.literalFreq, w.offsetFreq, w.codegenFreq} {
-		for i := range s {
-			s[i] = 0
-		}
-	}
-	for _, enc := range [...]*huffmanEncoder{
-		w.literalEncoding,
-		w.offsetEncoding,
-		w.codegenEncoding} {
-		for i := range enc.code {
-			enc.code[i] = 0
-		}
-		for i := range enc.codeBits {
-			enc.codeBits[i] = 0
-		}
-	}
-}
-
-func (w *huffmanBitWriter) flushBits() {
-	if w.err != nil {
-		w.nbits = 0
-		return
-	}
-	bits := w.bits
-	w.bits >>= 16
-	w.nbits -= 16
-	n := w.nbytes
-	w.bytes[n] = byte(bits)
-	w.bytes[n+1] = byte(bits >> 8)
-	if n += 2; n >= len(w.bytes) {
-		_, w.err = w.w.Write(w.bytes[0:])
-		n = 0
-	}
-	w.nbytes = n
+	w.bytes = [bufferSize]byte{}
 }
 
 func (w *huffmanBitWriter) flush() {
@@ -146,26 +118,42 @@ func (w *huffmanBitWriter) flush() {
 		return
 	}
 	n := w.nbytes
-	if w.nbits > 8 {
+	for w.nbits != 0 {
 		w.bytes[n] = byte(w.bits)
 		w.bits >>= 8
-		w.nbits -= 8
-		n++
-	}
-	if w.nbits > 0 {
-		w.bytes[n] = byte(w.bits)
-		w.nbits = 0
+		if w.nbits > 8 { // Avoid underflow
+			w.nbits -= 8
+		} else {
+			w.nbits = 0
+		}
 		n++
 	}
 	w.bits = 0
-	_, w.err = w.w.Write(w.bytes[0:n])
+	_, w.err = w.w.Write(w.bytes[:n])
 	w.nbytes = 0
 }
 
-func (w *huffmanBitWriter) writeBits(b, nb int32) {
-	w.bits |= uint32(b) << w.nbits
-	if w.nbits += uint32(nb); w.nbits >= 16 {
-		w.flushBits()
+func (w *huffmanBitWriter) writeBits(b int32, nb uint) {
+	w.bits |= uint64(b) << w.nbits
+	w.nbits += nb
+	if w.nbits >= 48 {
+		bits := w.bits
+		w.bits >>= 48
+		w.nbits -= 48
+		n := w.nbytes
+		bytes := w.bytes[n : n+6]
+		bytes[0] = byte(bits)
+		bytes[1] = byte(bits >> 8)
+		bytes[2] = byte(bits >> 16)
+		bytes[3] = byte(bits >> 24)
+		bytes[4] = byte(bits >> 32)
+		bytes[5] = byte(bits >> 40)
+		n += 6
+		if n >= bufferFlushSize {
+			_, w.err = w.w.Write(w.bytes[:n])
+			n = 0
+		}
+		w.nbytes = n
 	}
 }
 
@@ -174,17 +162,18 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) {
 		return
 	}
 	n := w.nbytes
-	if w.nbits == 8 {
-		w.bytes[n] = byte(w.bits)
-		w.nbits = 0
-		n++
-	}
-	if w.nbits != 0 {
+	if w.nbits&7 != 0 {
 		w.err = InternalError("writeBytes with unfinished bits")
 		return
 	}
+	for w.nbits != 0 {
+		w.bytes[n] = byte(w.bits)
+		w.bits >>= 8
+		w.nbits -= 8
+		n++
+	}
 	if n != 0 {
-		_, w.err = w.w.Write(w.bytes[0:n])
+		_, w.err = w.w.Write(w.bytes[:n])
 		if w.err != nil {
 			return
 		}
@@ -200,11 +189,12 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) {
 // The result is written into the codegen array, and the frequencies
 // of each code is written into the codegenFreq array.
 // Codes 0-15 are single byte codes. Codes 16-18 are followed by additional
-// information.  Code badCode is an end marker
+// information. Code badCode is an end marker
 //
 //  numLiterals      The number of literals in literalEncoding
 //  numOffsets       The number of offsets in offsetEncoding
-func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
+//  litenc, offenc   The literal and offset encoder to use
+func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, litEnc, offEnc *huffmanEncoder) {
 	for i := range w.codegenFreq {
 		w.codegenFreq[i] = 0
 	}
@@ -213,9 +203,16 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
 	// This is fine because the output is always shorter than the input used
 	// so far.
 	codegen := w.codegen // cache
-	// Copy the concatenated code sizes to codegen.  Put a marker at the end.
-	copy(codegen[0:numLiterals], w.literalEncoding.codeBits)
-	copy(codegen[numLiterals:numLiterals+numOffsets], w.offsetEncoding.codeBits)
+	// Copy the concatenated code sizes to codegen. Put a marker at the end.
+	cgnl := codegen[:numLiterals]
+	for i := range cgnl {
+		cgnl[i] = uint8(litEnc.codes[i].len)
+	}
+
+	cgnl = codegen[numLiterals : numLiterals+numOffsets]
+	for i := range cgnl {
+		cgnl[i] = uint8(offEnc.codes[i].len)
+	}
 	codegen[numLiterals+numOffsets] = badCode
 
 	size := codegen[0]
@@ -284,11 +281,71 @@ func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int) {
 	codegen[outIndex] = badCode
 }
 
-func (w *huffmanBitWriter) writeCode(code *huffmanEncoder, literal uint32) {
+// dynamicSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) dynamicSize(litEnc, offEnc *huffmanEncoder, extraBits int) (size, numCodegens int) {
+	numCodegens = len(w.codegenFreq)
+	for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
+		numCodegens--
+	}
+	header := 3 + 5 + 5 + 4 + (3 * numCodegens) +
+		w.codegenEncoding.bitLength(w.codegenFreq[:]) +
+		int(w.codegenFreq[16])*2 +
+		int(w.codegenFreq[17])*3 +
+		int(w.codegenFreq[18])*7
+	size = header +
+		litEnc.bitLength(w.literalFreq) +
+		offEnc.bitLength(w.offsetFreq) +
+		extraBits
+
+	return size, numCodegens
+}
+
+// fixedSize returns the size of dynamically encoded data in bits.
+func (w *huffmanBitWriter) fixedSize(extraBits int) int {
+	return 3 +
+		fixedLiteralEncoding.bitLength(w.literalFreq) +
+		fixedOffsetEncoding.bitLength(w.offsetFreq) +
+		extraBits
+}
+
+// storedSize calculates the stored size, including header.
+// The function returns the size in bits and whether the block
+// fits inside a single block.
+func (w *huffmanBitWriter) storedSize(in []byte) (int, bool) {
+	if in == nil {
+		return 0, false
+	}
+	if len(in) <= maxStoreBlockSize {
+		return (len(in) + 5) * 8, true
+	}
+	return 0, false
+}
+
+func (w *huffmanBitWriter) writeCode(c hcode) {
 	if w.err != nil {
 		return
 	}
-	w.writeBits(int32(code.code[literal]), int32(code.codeBits[literal]))
+	w.bits |= uint64(c.code) << w.nbits
+	w.nbits += uint(c.len)
+	if w.nbits >= 48 {
+		bits := w.bits
+		w.bits >>= 48
+		w.nbits -= 48
+		n := w.nbytes
+		bytes := w.bytes[n : n+6]
+		bytes[0] = byte(bits)
+		bytes[1] = byte(bits >> 8)
+		bytes[2] = byte(bits >> 16)
+		bytes[3] = byte(bits >> 24)
+		bytes[4] = byte(bits >> 32)
+		bytes[5] = byte(bits >> 40)
+		n += 6
+		if n >= bufferFlushSize {
+			_, w.err = w.w.Write(w.bytes[:n])
+			n = 0
+		}
+		w.nbytes = n
+	}
 }
 
 // Write the header of a dynamic Huffman block to the output stream.
@@ -310,7 +367,7 @@ func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, n
 	w.writeBits(int32(numCodegens-4), 4)
 
 	for i := 0; i < numCodegens; i++ {
-		value := w.codegenEncoding.codeBits[codegenOrder[i]]
+		value := uint(w.codegenEncoding.codes[codegenOrder[i]].len)
 		w.writeBits(int32(value), 3)
 	}
 
@@ -321,8 +378,7 @@ func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, n
 		if codeWord == badCode {
 			break
 		}
-		// The low byte contains the actual code to generate.
-		w.writeCode(w.codegenEncoding, uint32(codeWord))
+		w.writeCode(w.codegenEncoding.codes[uint32(codeWord)])
 
 		switch codeWord {
 		case 16:
@@ -367,10 +423,113 @@ func (w *huffmanBitWriter) writeFixedHeader(isEof bool) {
 	w.writeBits(value, 3)
 }
 
+// writeBlock will write a block of tokens with the smallest encoding.
+// The original input can be supplied, and if the huffman encoded data
+// is larger than the original bytes, the data will be written as a
+// stored block.
+// If the input is nil, the tokens will always be Huffman encoded.
 func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
 	if w.err != nil {
 		return
 	}
+
+	tokens = append(tokens, endBlockMarker)
+	numLiterals, numOffsets := w.indexTokens(tokens)
+
+	var extraBits int
+	storedSize, storable := w.storedSize(input)
+	if storable {
+		// We only bother calculating the costs of the extra bits required by
+		// the length of offset fields (which will be the same for both fixed
+		// and dynamic encoding), if we need to compare those two encodings
+		// against stored encoding.
+		for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ {
+			// First eight length codes have extra size = 0.
+			extraBits += int(w.literalFreq[lengthCode]) * int(lengthExtraBits[lengthCode-lengthCodesStart])
+		}
+		for offsetCode := 4; offsetCode < numOffsets; offsetCode++ {
+			// First four offset codes have extra size = 0.
+			extraBits += int(w.offsetFreq[offsetCode]) * int(offsetExtraBits[offsetCode])
+		}
+	}
+
+	// Figure out smallest code.
+	// Fixed Huffman baseline.
+	var literalEncoding = fixedLiteralEncoding
+	var offsetEncoding = fixedOffsetEncoding
+	var size = w.fixedSize(extraBits)
+
+	// Dynamic Huffman?
+	var numCodegens int
+
+	// Generate codegen and codegenFrequencies, which indicates how to encode
+	// the literalEncoding and the offsetEncoding.
+	w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
+	w.codegenEncoding.generate(w.codegenFreq[:], 7)
+	dynamicSize, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, extraBits)
+
+	if dynamicSize < size {
+		size = dynamicSize
+		literalEncoding = w.literalEncoding
+		offsetEncoding = w.offsetEncoding
+	}
+
+	// Stored bytes?
+	if storable && storedSize < size {
+		w.writeStoredHeader(len(input), eof)
+		w.writeBytes(input)
+		return
+	}
+
+	// Huffman.
+	if literalEncoding == fixedLiteralEncoding {
+		w.writeFixedHeader(eof)
+	} else {
+		w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+	}
+
+	// Write the tokens.
+	w.writeTokens(tokens, literalEncoding.codes, offsetEncoding.codes)
+}
+
+// writeBlockDynamic encodes a block using a dynamic Huffman table.
+// This should be used if the symbols used have a disproportionate
+// histogram distribution.
+// If input is supplied and the compression savings are below 1/16th of the
+// input size the block is stored.
+func (w *huffmanBitWriter) writeBlockDynamic(tokens []token, eof bool, input []byte) {
+	if w.err != nil {
+		return
+	}
+
+	tokens = append(tokens, endBlockMarker)
+	numLiterals, numOffsets := w.indexTokens(tokens)
+
+	// Generate codegen and codegenFrequencies, which indicates how to encode
+	// the literalEncoding and the offsetEncoding.
+	w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
+	w.codegenEncoding.generate(w.codegenFreq[:], 7)
+	size, numCodegens := w.dynamicSize(w.literalEncoding, huffOffset, 0)
+
+	// Store bytes, if we don't get a reasonable improvement.
+	if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) {
+		w.writeStoredHeader(len(input), eof)
+		w.writeBytes(input)
+		return
+	}
+
+	// Write Huffman table.
+	w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+
+	// Write the tokens.
+	w.writeTokens(tokens, w.literalEncoding.codes, w.offsetEncoding.codes)
+}
+
+// indexTokens indexes a slice of tokens, and updates
+// literalFreq and offsetFreq, and generates literalEncoding
+// and offsetEncoding.
+// The number of literal and offset tokens is returned.
+func (w *huffmanBitWriter) indexTokens(tokens []token) (numLiterals, numOffsets int) {
 	for i := range w.literalFreq {
 		w.literalFreq[i] = 0
 	}
@@ -378,29 +537,24 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
 		w.offsetFreq[i] = 0
 	}
 
-	n := len(tokens)
-	tokens = tokens[0 : n+1]
-	tokens[n] = endBlockMarker
-
 	for _, t := range tokens {
-		switch t.typ() {
-		case literalType:
+		if t < matchType {
 			w.literalFreq[t.literal()]++
-		case matchType:
-			length := t.length()
-			offset := t.offset()
-			w.literalFreq[lengthCodesStart+lengthCode(length)]++
-			w.offsetFreq[offsetCode(offset)]++
+			continue
 		}
+		length := t.length()
+		offset := t.offset()
+		w.literalFreq[lengthCodesStart+lengthCode(length)]++
+		w.offsetFreq[offsetCode(offset)]++
 	}
 
 	// get the number of literals
-	numLiterals := len(w.literalFreq)
+	numLiterals = len(w.literalFreq)
 	for w.literalFreq[numLiterals-1] == 0 {
 		numLiterals--
 	}
 	// get the number of offsets
-	numOffsets := len(w.offsetFreq)
+	numOffsets = len(w.offsetFreq)
 	for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 {
 		numOffsets--
 	}
@@ -410,108 +564,134 @@ func (w *huffmanBitWriter) writeBlock(tokens []token, eof bool, input []byte) {
 		w.offsetFreq[0] = 1
 		numOffsets = 1
 	}
-
 	w.literalEncoding.generate(w.literalFreq, 15)
 	w.offsetEncoding.generate(w.offsetFreq, 15)
+	return
+}
 
-	storedBytes := 0
-	if input != nil {
-		storedBytes = len(input)
-	}
-	var extraBits int64
-	var storedSize int64 = math.MaxInt64
-	if storedBytes <= maxStoreBlockSize && input != nil {
-		storedSize = int64((storedBytes + 5) * 8)
-		// We only bother calculating the costs of the extra bits required by
-		// the length of offset fields (which will be the same for both fixed
-		// and dynamic encoding), if we need to compare those two encodings
-		// against stored encoding.
-		for lengthCode := lengthCodesStart + 8; lengthCode < numLiterals; lengthCode++ {
-			// First eight length codes have extra size = 0.
-			extraBits += int64(w.literalFreq[lengthCode]) * int64(lengthExtraBits[lengthCode-lengthCodesStart])
+// writeTokens writes a slice of tokens to the output.
+// codes for literal and offset encoding must be supplied.
+func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) {
+	for _, t := range tokens {
+		if t < matchType {
+			w.writeCode(leCodes[t.literal()])
+			continue
 		}
-		for offsetCode := 4; offsetCode < numOffsets; offsetCode++ {
-			// First four offset codes have extra size = 0.
-			extraBits += int64(w.offsetFreq[offsetCode]) * int64(offsetExtraBits[offsetCode])
+		// Write the length
+		length := t.length()
+		lengthCode := lengthCode(length)
+		w.writeCode(leCodes[lengthCode+lengthCodesStart])
+		extraLengthBits := uint(lengthExtraBits[lengthCode])
+		if extraLengthBits > 0 {
+			extraLength := int32(length - lengthBase[lengthCode])
+			w.writeBits(extraLength, extraLengthBits)
+		}
+		// Write the offset
+		offset := t.offset()
+		offsetCode := offsetCode(offset)
+		w.writeCode(oeCodes[offsetCode])
+		extraOffsetBits := uint(offsetExtraBits[offsetCode])
+		if extraOffsetBits > 0 {
+			extraOffset := int32(offset - offsetBase[offsetCode])
+			w.writeBits(extraOffset, extraOffsetBits)
 		}
 	}
+}
 
-	// Figure out smallest code.
-	// Fixed Huffman baseline.
-	var size = int64(3) +
-		fixedLiteralEncoding.bitLength(w.literalFreq) +
-		fixedOffsetEncoding.bitLength(w.offsetFreq) +
-		extraBits
-	var literalEncoding = fixedLiteralEncoding
-	var offsetEncoding = fixedOffsetEncoding
+// huffOffset is a static offset encoder used for huffman only encoding.
+// It can be reused since we will not be encoding offset values.
+var huffOffset *huffmanEncoder
 
-	// Dynamic Huffman?
-	var numCodegens int
+func init() {
+	w := newHuffmanBitWriter(nil)
+	w.offsetFreq[0] = 1
+	huffOffset = newHuffmanEncoder(offsetCodeCount)
+	huffOffset.generate(w.offsetFreq, 15)
+}
 
-	// Generate codegen and codegenFrequencies, which indicates how to encode
-	// the literalEncoding and the offsetEncoding.
-	w.generateCodegen(numLiterals, numOffsets)
-	w.codegenEncoding.generate(w.codegenFreq, 7)
-	numCodegens = len(w.codegenFreq)
-	for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 {
-		numCodegens--
+// writeBlockHuff encodes a block of bytes as either
+// Huffman encoded literals or uncompressed bytes if the
+// results only gains very little from compression.
+func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) {
+	if w.err != nil {
+		return
 	}
-	dynamicHeader := int64(3+5+5+4+(3*numCodegens)) +
-		w.codegenEncoding.bitLength(w.codegenFreq) +
-		int64(extraBits) +
-		int64(w.codegenFreq[16]*2) +
-		int64(w.codegenFreq[17]*3) +
-		int64(w.codegenFreq[18]*7)
-	dynamicSize := dynamicHeader +
-		w.literalEncoding.bitLength(w.literalFreq) +
-		w.offsetEncoding.bitLength(w.offsetFreq)
 
-	if dynamicSize < size {
-		size = dynamicSize
-		literalEncoding = w.literalEncoding
-		offsetEncoding = w.offsetEncoding
+	// Clear histogram
+	for i := range w.literalFreq {
+		w.literalFreq[i] = 0
 	}
 
-	// Stored bytes?
-	if storedSize < size {
-		w.writeStoredHeader(storedBytes, eof)
-		w.writeBytes(input[0:storedBytes])
+	// Add everything as literals
+	histogram(input, w.literalFreq)
+
+	w.literalFreq[endBlockMarker] = 1
+
+	const numLiterals = endBlockMarker + 1
+	const numOffsets = 1
+
+	w.literalEncoding.generate(w.literalFreq, 15)
+
+	// Figure out smallest code.
+	// Always use dynamic Huffman or Store
+	var numCodegens int
+
+	// Generate codegen and codegenFrequencies, which indicates how to encode
+	// the literalEncoding and the offsetEncoding.
+	w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, huffOffset)
+	w.codegenEncoding.generate(w.codegenFreq[:], 7)
+	size, numCodegens := w.dynamicSize(w.literalEncoding, huffOffset, 0)
+
+	// Store bytes, if we don't get a reasonable improvement.
+	if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) {
+		w.writeStoredHeader(len(input), eof)
+		w.writeBytes(input)
 		return
 	}
 
 	// Huffman.
-	if literalEncoding == fixedLiteralEncoding {
-		w.writeFixedHeader(eof)
-	} else {
-		w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
-	}
-	for _, t := range tokens {
-		switch t.typ() {
-		case literalType:
-			w.writeCode(literalEncoding, t.literal())
-			break
-		case matchType:
-			// Write the length
-			length := t.length()
-			lengthCode := lengthCode(length)
-			w.writeCode(literalEncoding, lengthCode+lengthCodesStart)
-			extraLengthBits := int32(lengthExtraBits[lengthCode])
-			if extraLengthBits > 0 {
-				extraLength := int32(length - lengthBase[lengthCode])
-				w.writeBits(extraLength, extraLengthBits)
-			}
-			// Write the offset
-			offset := t.offset()
-			offsetCode := offsetCode(offset)
-			w.writeCode(offsetEncoding, offsetCode)
-			extraOffsetBits := int32(offsetExtraBits[offsetCode])
-			if extraOffsetBits > 0 {
-				extraOffset := int32(offset - offsetBase[offsetCode])
-				w.writeBits(extraOffset, extraOffsetBits)
-			}
-			break
-		default:
-			panic("unknown token type: " + string(t))
+	w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof)
+	encoding := w.literalEncoding.codes[:257]
+	n := w.nbytes
+	for _, t := range input {
+		// Bitwriting inlined, ~30% speedup
+		c := encoding[t]
+		w.bits |= uint64(c.code) << w.nbits
+		w.nbits += uint(c.len)
+		if w.nbits < 48 {
+			continue
 		}
+		// Store 6 bytes
+		bits := w.bits
+		w.bits >>= 48
+		w.nbits -= 48
+		bytes := w.bytes[n : n+6]
+		bytes[0] = byte(bits)
+		bytes[1] = byte(bits >> 8)
+		bytes[2] = byte(bits >> 16)
+		bytes[3] = byte(bits >> 24)
+		bytes[4] = byte(bits >> 32)
+		bytes[5] = byte(bits >> 40)
+		n += 6
+		if n < bufferFlushSize {
+			continue
+		}
+		_, w.err = w.w.Write(w.bytes[:n])
+		if w.err != nil {
+			return
+		}
+		n = 0
+	}
+	w.nbytes = n
+	w.writeCode(encoding[endBlockMarker])
+}
+
+// histogram accumulates a histogram of b in h.
+//
+// len(h) must be >= 256, and h's elements must be all zeroes.
+func histogram(b []byte, h []int32) {
+	h = h[:256]
+	for _, t := range b {
+		h[t]++
 	}
 }
diff --git a/src/compress/flate/huffman_bit_writer_test.go b/src/compress/flate/huffman_bit_writer_test.go
new file mode 100644
index 0000000..882d3ab
--- /dev/null
+++ b/src/compress/flate/huffman_bit_writer_test.go
@@ -0,0 +1,366 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flate
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+)
+
+var update = flag.Bool("update", false, "update reference files")
+
+// TestBlockHuff tests huffman encoding against reference files
+// to detect possible regressions.
+// If encoding/bit allocation changes you can regenerate these files
+// by using the -update flag.
+func TestBlockHuff(t *testing.T) {
+	// determine input files
+	match, err := filepath.Glob("testdata/huffman-*.in")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, in := range match {
+		out := in // for files where input and output are identical
+		if strings.HasSuffix(in, ".in") {
+			out = in[:len(in)-len(".in")] + ".golden"
+		}
+		testBlockHuff(t, in, out)
+	}
+}
+
+func testBlockHuff(t *testing.T, in, out string) {
+	all, err := ioutil.ReadFile(in)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	var buf bytes.Buffer
+	bw := newHuffmanBitWriter(&buf)
+	bw.writeBlockHuff(false, all)
+	bw.flush()
+	got := buf.Bytes()
+
+	want, err := ioutil.ReadFile(out)
+	if err != nil && !*update {
+		t.Error(err)
+		return
+	}
+
+	t.Logf("Testing %q", in)
+	if !bytes.Equal(got, want) {
+		if *update {
+			if in != out {
+				t.Logf("Updating %q", out)
+				if err := ioutil.WriteFile(out, got, 0666); err != nil {
+					t.Error(err)
+				}
+				return
+			}
+			// in == out: don't accidentally destroy input
+			t.Errorf("WARNING: -update did not rewrite input file %s", in)
+		}
+
+		t.Errorf("%q != %q (see %q)", in, out, in+".got")
+		if err := ioutil.WriteFile(in+".got", got, 0666); err != nil {
+			t.Error(err)
+		}
+		return
+	}
+	t.Log("Output ok")
+
+	// Test if the writer produces the same output after reset.
+	buf.Reset()
+	bw.reset(&buf)
+	bw.writeBlockHuff(false, all)
+	bw.flush()
+	got = buf.Bytes()
+	if !bytes.Equal(got, want) {
+		t.Errorf("after reset %q != %q (see %q)", in, out, in+".reset.got")
+		if err := ioutil.WriteFile(in+".reset.got", got, 0666); err != nil {
+			t.Error(err)
+		}
+		return
+	}
+	t.Log("Reset ok")
+	testWriterEOF(t, "huff", huffTest{input: in}, true)
+}
+
+type huffTest struct {
+	tokens      []token
+	input       string // File name of input data matching the tokens.
+	want        string // File name of data with the expected output with input available.
+	wantNoInput string // File name of the expected output when no input is available.
+}
+
+const ml = 0x7fc00000 // Maximum length token. Used to reduce the size of writeBlockTests
+
+var writeBlockTests = []huffTest{
+	{
+		input:       "testdata/huffman-null-max.in",
+		want:        "testdata/huffman-null-max.%s.expect",
+		wantNoInput: "testdata/huffman-null-max.%s.expect-noinput",
+		tokens:      []token{0x0, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,  [...]
+	},
+	{
+		input:       "testdata/huffman-pi.in",
+		want:        "testdata/huffman-pi.%s.expect",
+		wantNoInput: "testdata/huffman-pi.%s.expect-noinput",
+		tokens:      []token{0x33, 0x2e, 0x31, 0x34, 0x31, 0x35, 0x39, 0x32, 0x36, 0x35, 0x33, 0x35, 0x38, 0x39, 0x37, 0x39, 0x33, 0x32, 0x33, 0x38, 0x34, 0x36, 0x32, 0x36, 0x34, 0x33, 0x33, 0x38, 0x33, 0x32, 0x37, 0x39, 0x35, 0x30, 0x32, 0x38, 0x38, 0x34, 0x31, 0x39, 0x37, 0x31, 0x36, 0x39, 0x33, 0x39, 0x39, 0x33, 0x37, 0x35, 0x31, 0x30, 0x35, 0x38, 0x32, 0x30, 0x39, 0x37, 0x34, 0x39, 0x34, 0x34, 0x35, 0x39, 0x32, 0x33, 0x30, 0x37, 0x38, 0x31, 0x36, 0x34, 0x30, 0x36, 0x32, 0x38, 0x36, 0x32, 0 [...]
+	},
+	{
+		input:       "testdata/huffman-rand-1k.in",
+		want:        "testdata/huffman-rand-1k.%s.expect",
+		wantNoInput: "testdata/huffman-rand-1k.%s.expect-noinput",
+		tokens:      []token{0xf8, 0x8b, 0x96, 0x76, 0x48, 0xd, 0x85, 0x94, 0x25, 0x80, 0xaf, 0xc2, 0xfe, 0x8d, 0xe8, 0x20, 0xeb, 0x17, 0x86, 0xc9, 0xb7, 0xc5, 0xde, 0x6, 0xea, 0x7d, 0x18, 0x8b, 0xe7, 0x3e, 0x7, 0xda, 0xdf, 0xff, 0x6c, 0x73, 0xde, 0xcc, 0xe7, 0x6d, 0x8d, 0x4, 0x19, 0x49, 0x7f, 0x47, 0x1f, 0x48, 0x15, 0xb0, 0xe8, 0x9e, 0xf2, 0x31, 0x59, 0xde, 0x34, 0xb4, 0x5b, 0xe5, 0xe0, 0x9, 0x11, 0x30, 0xc2, 0x88, 0x5b, 0x7c, 0x5d, 0x14, 0x13, 0x6f, 0x23, 0xa9, 0xd, 0xbc, 0x2d, 0x23, 0xbe, 0 [...]
+	},
+	{
+		input:       "testdata/huffman-rand-limit.in",
+		want:        "testdata/huffman-rand-limit.%s.expect",
+		wantNoInput: "testdata/huffman-rand-limit.%s.expect-noinput",
+		tokens:      []token{0x61, 0x51c00000, 0xa, 0xf8, 0x8b, 0x96, 0x76, 0x48, 0xa, 0x85, 0x94, 0x25, 0x80, 0xaf, 0xc2, 0xfe, 0x8d, 0xe8, 0x20, 0xeb, 0x17, 0x86, 0xc9, 0xb7, 0xc5, 0xde, 0x6, 0xea, 0x7d, 0x18, 0x8b, 0xe7, 0x3e, 0x7, 0xda, 0xdf, 0xff, 0x6c, 0x73, 0xde, 0xcc, 0xe7, 0x6d, 0x8d, 0x4, 0x19, 0x49, 0x7f, 0x47, 0x1f, 0x48, 0x15, 0xb0, 0xe8, 0x9e, 0xf2, 0x31, 0x59, 0xde, 0x34, 0xb4, 0x5b, 0xe5, 0xe0, 0x9, 0x11, 0x30, 0xc2, 0x88, 0x5b, 0x7c, 0x5d, 0x14, 0x13, 0x6f, 0x23, 0xa9, 0xa, 0x [...]
+	},
+	{
+		input:       "testdata/huffman-shifts.in",
+		want:        "testdata/huffman-shifts.%s.expect",
+		wantNoInput: "testdata/huffman-shifts.%s.expect-noinput",
+		tokens:      []token{0x31, 0x30, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x52400001, 0xd, 0xa, 0x32, 0x33, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7f400001},
+	},
+	{
+		input:       "testdata/huffman-text-shift.in",
+		want:        "testdata/huffman-text-shift.%s.expect",
+		wantNoInput: "testdata/huffman-text-shift.%s.expect-noinput",
+		tokens:      []token{0x2f, 0x2f, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x32, 0x30, 0x30, 0x39, 0x54, 0x68, 0x47, 0x6f, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x2e, 0x41, 0x6c, 0x6c, 0x40800016, 0x72, 0x72, 0x76, 0x64, 0x2e, 0xd, 0xa, 0x2f, 0x2f, 0x55, 0x6f, 0x66, 0x74, 0x68, 0x69, 0x6f, 0x75, 0x72, 0x63, 0x63, 0x6f, 0x64, 0x69, 0x67, 0x6f, 0x76, 0x72, 0x6e, 0x64, 0x62, 0x79, 0x42, 0x53, 0x44, 0x2d, 0x74, 0x79, 0x6c, 0x40400020, 0x6c, 0x69, 0x63, 0x6e, 0x74, 0x68, 0x74, 0x6 [...]
+	},
+	{
+		input:       "testdata/huffman-text.in",
+		want:        "testdata/huffman-text.%s.expect",
+		wantNoInput: "testdata/huffman-text.%s.expect-noinput",
+		tokens:      []token{0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x4080001e, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0xd, 0xa, 0x2f, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x6 [...]
+	},
+	{
+		input:       "testdata/huffman-zero.in",
+		want:        "testdata/huffman-zero.%s.expect",
+		wantNoInput: "testdata/huffman-zero.%s.expect-noinput",
+		tokens:      []token{0x30, ml, 0x4b800000},
+	},
+	{
+		input:       "",
+		want:        "",
+		wantNoInput: "testdata/null-long-match.%s.expect-noinput",
+		tokens:      []token{0x0, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml,  [...]
+	},
+}
+
+// TestWriteBlock tests if the writeBlock encoding has changed.
+// To update the reference files use the "-update" flag on the test.
+func TestWriteBlock(t *testing.T) {
+	for _, test := range writeBlockTests {
+		testBlock(t, test, "wb")
+	}
+}
+
+// TestWriteBlockDynamic tests if the writeBlockDynamic encoding has changed.
+// To update the reference files use the "-update" flag on the test.
+func TestWriteBlockDynamic(t *testing.T) {
+	for _, test := range writeBlockTests {
+		testBlock(t, test, "dyn")
+	}
+}
+
+// testBlock tests a block against its references,
+// or regenerate the references, if "-update" flag is set.
+func testBlock(t *testing.T, test huffTest, ttype string) {
+	if test.want != "" {
+		test.want = fmt.Sprintf(test.want, ttype)
+	}
+	test.wantNoInput = fmt.Sprintf(test.wantNoInput, ttype)
+	if *update {
+		if test.input != "" {
+			t.Logf("Updating %q", test.want)
+			input, err := ioutil.ReadFile(test.input)
+			if err != nil {
+				t.Error(err)
+				return
+			}
+
+			f, err := os.Create(test.want)
+			if err != nil {
+				t.Error(err)
+				return
+			}
+			defer f.Close()
+			bw := newHuffmanBitWriter(f)
+			writeToType(t, ttype, bw, test.tokens, input)
+		}
+
+		t.Logf("Updating %q", test.wantNoInput)
+		f, err := os.Create(test.wantNoInput)
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		defer f.Close()
+		bw := newHuffmanBitWriter(f)
+		writeToType(t, ttype, bw, test.tokens, nil)
+		return
+	}
+
+	if test.input != "" {
+		t.Logf("Testing %q", test.want)
+		input, err := ioutil.ReadFile(test.input)
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		want, err := ioutil.ReadFile(test.want)
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		var buf bytes.Buffer
+		bw := newHuffmanBitWriter(&buf)
+		writeToType(t, ttype, bw, test.tokens, input)
+
+		got := buf.Bytes()
+		if !bytes.Equal(got, want) {
+			t.Errorf("writeBlock did not yield expected result for file %q with input. See %q", test.want, test.want+".got")
+			if err := ioutil.WriteFile(test.want+".got", got, 0666); err != nil {
+				t.Error(err)
+			}
+		}
+		t.Log("Output ok")
+
+		// Test if the writer produces the same output after reset.
+		buf.Reset()
+		bw.reset(&buf)
+		writeToType(t, ttype, bw, test.tokens, input)
+		bw.flush()
+		got = buf.Bytes()
+		if !bytes.Equal(got, want) {
+			t.Errorf("reset: writeBlock did not yield expected result for file %q with input. See %q", test.want, test.want+".reset.got")
+			if err := ioutil.WriteFile(test.want+".reset.got", got, 0666); err != nil {
+				t.Error(err)
+			}
+			return
+		}
+		t.Log("Reset ok")
+		testWriterEOF(t, "wb", test, true)
+	}
+	t.Logf("Testing %q", test.wantNoInput)
+	wantNI, err := ioutil.ReadFile(test.wantNoInput)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	var buf bytes.Buffer
+	bw := newHuffmanBitWriter(&buf)
+	writeToType(t, ttype, bw, test.tokens, nil)
+
+	got := buf.Bytes()
+	if !bytes.Equal(got, wantNI) {
+		t.Errorf("writeBlock did not yield expected result for file %q with input. See %q", test.wantNoInput, test.wantNoInput+".got")
+		if err := ioutil.WriteFile(test.want+".got", got, 0666); err != nil {
+			t.Error(err)
+		}
+	} else if got[0]&1 == 1 {
+		t.Error("got unexpected EOF")
+		return
+	}
+
+	t.Log("Output ok")
+
+	// Test if the writer produces the same output after reset.
+	buf.Reset()
+	bw.reset(&buf)
+	writeToType(t, ttype, bw, test.tokens, nil)
+	bw.flush()
+	got = buf.Bytes()
+	if !bytes.Equal(got, wantNI) {
+		t.Errorf("reset: writeBlock did not yield expected result for file %q without input. See %q", test.want, test.want+".reset.got")
+		if err := ioutil.WriteFile(test.want+".reset.got", got, 0666); err != nil {
+			t.Error(err)
+		}
+		return
+	}
+	t.Log("Reset ok")
+	testWriterEOF(t, "wb", test, false)
+}
+
+func writeToType(t *testing.T, ttype string, bw *huffmanBitWriter, tok []token, input []byte) {
+	switch ttype {
+	case "wb":
+		bw.writeBlock(tok, false, input)
+	case "dyn":
+		bw.writeBlockDynamic(tok, false, input)
+	default:
+		panic("unknown test type")
+	}
+
+	if bw.err != nil {
+		t.Error(bw.err)
+		return
+	}
+
+	bw.flush()
+	if bw.err != nil {
+		t.Error(bw.err)
+		return
+	}
+}
+
+// testWriterEOF tests if the written block contains an EOF marker.
+func testWriterEOF(t *testing.T, ttype string, test huffTest, useInput bool) {
+	if useInput && test.input == "" {
+		return
+	}
+	var input []byte
+	if useInput {
+		var err error
+		input, err = ioutil.ReadFile(test.input)
+		if err != nil {
+			t.Error(err)
+			return
+		}
+	}
+	var buf bytes.Buffer
+	bw := newHuffmanBitWriter(&buf)
+	switch ttype {
+	case "wb":
+		bw.writeBlock(test.tokens, true, input)
+	case "dyn":
+		bw.writeBlockDynamic(test.tokens, true, input)
+	case "huff":
+		bw.writeBlockHuff(true, input)
+	default:
+		panic("unknown test type")
+	}
+	if bw.err != nil {
+		t.Error(bw.err)
+		return
+	}
+
+	bw.flush()
+	if bw.err != nil {
+		t.Error(bw.err)
+		return
+	}
+	b := buf.Bytes()
+	if len(b) == 0 {
+		t.Error("no output received")
+		return
+	}
+	if b[0]&1 != 1 {
+		t.Errorf("block not marked with EOF for input %q", test.input)
+		return
+	}
+	t.Log("EOF ok")
+}
diff --git a/src/compress/flate/huffman_code.go b/src/compress/flate/huffman_code.go
index 50ec79c..bdcbd82 100644
--- a/src/compress/flate/huffman_code.go
+++ b/src/compress/flate/huffman_code.go
@@ -9,9 +9,17 @@ import (
 	"sort"
 )
 
+// hcode is a huffman code with a bit code and bit length.
+type hcode struct {
+	code, len uint16
+}
+
 type huffmanEncoder struct {
-	codeBits []uint8
-	code     []uint16
+	codes     []hcode
+	freqcache []literalNode
+	bitCount  [17]int32
+	lns       byLiteral // stored to avoid repeated allocation in generate
+	lfs       byFreq    // stored to avoid repeated allocation in generate
 }
 
 type literalNode struct {
@@ -39,21 +47,26 @@ type levelInfo struct {
 	needed int32
 }
 
+// set sets the code and length of an hcode.
+func (h *hcode) set(code uint16, length uint16) {
+	h.len = length
+	h.code = code
+}
+
 func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxInt32} }
 
 func newHuffmanEncoder(size int) *huffmanEncoder {
-	return &huffmanEncoder{make([]uint8, size), make([]uint16, size)}
+	return &huffmanEncoder{codes: make([]hcode, size)}
 }
 
 // Generates a HuffmanCode corresponding to the fixed literal table
 func generateFixedLiteralEncoding() *huffmanEncoder {
 	h := newHuffmanEncoder(maxNumLit)
-	codeBits := h.codeBits
-	code := h.code
+	codes := h.codes
 	var ch uint16
 	for ch = 0; ch < maxNumLit; ch++ {
 		var bits uint16
-		var size uint8
+		var size uint16
 		switch {
 		case ch < 144:
 			// size 8, 000110000  .. 10111111
@@ -75,19 +88,16 @@ func generateFixedLiteralEncoding() *huffmanEncoder {
 			bits = ch + 192 - 280
 			size = 8
 		}
-		codeBits[ch] = size
-		code[ch] = reverseBits(bits, size)
+		codes[ch] = hcode{code: reverseBits(bits, byte(size)), len: size}
 	}
 	return h
 }
 
 func generateFixedOffsetEncoding() *huffmanEncoder {
 	h := newHuffmanEncoder(30)
-	codeBits := h.codeBits
-	code := h.code
-	for ch := uint16(0); ch < 30; ch++ {
-		codeBits[ch] = 5
-		code[ch] = reverseBits(ch, 5)
+	codes := h.codes
+	for ch := range codes {
+		codes[ch] = hcode{code: reverseBits(uint16(ch), 5), len: 5}
 	}
 	return h
 }
@@ -95,11 +105,11 @@ func generateFixedOffsetEncoding() *huffmanEncoder {
 var fixedLiteralEncoding *huffmanEncoder = generateFixedLiteralEncoding()
 var fixedOffsetEncoding *huffmanEncoder = generateFixedOffsetEncoding()
 
-func (h *huffmanEncoder) bitLength(freq []int32) int64 {
-	var total int64
+func (h *huffmanEncoder) bitLength(freq []int32) int {
+	var total int
 	for i, f := range freq {
 		if f != 0 {
-			total += int64(f) * int64(h.codeBits[i])
+			total += int(f) * int(h.codes[i].len)
 		}
 	}
 	return total
@@ -113,7 +123,7 @@ const maxBitsLimit = 16
 // The cases of 0, 1, and 2 literals are handled by special case code.
 //
 // list  An array of the literals with non-zero frequencies
-//             and their associated frequencies.  The array is in order of increasing
+//             and their associated frequencies. The array is in order of increasing
 //             frequency, and has as its last element a special element with frequency
 //             MaxInt32
 // maxBits     The maximum number of bits that should be used to encode any literal.
@@ -128,7 +138,7 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
 	list = list[0 : n+1]
 	list[n] = maxNode()
 
-	// The tree can't have greater depth than n - 1, no matter what.  This
+	// The tree can't have greater depth than n - 1, no matter what. This
 	// saves a little bit of work in some small cases
 	if maxBits > n-1 {
 		maxBits = n - 1
@@ -197,7 +207,7 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
 
 		if l.needed--; l.needed == 0 {
 			// We've done everything we need to do for this level.
-			// Continue calculating one level up.  Fill in nextPairFreq
+			// Continue calculating one level up. Fill in nextPairFreq
 			// of that level with the sum of the two nodes we've just calculated on
 			// this level.
 			if l.level == maxBits {
@@ -220,7 +230,7 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
 		panic("leafCounts[maxBits][maxBits] != n")
 	}
 
-	bitCount := make([]int32, maxBits+1)
+	bitCount := h.bitCount[:maxBits+1]
 	bits := 1
 	counts := &leafCounts[maxBits]
 	for level := maxBits; level > 0; level-- {
@@ -246,10 +256,10 @@ func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalN
 		// code, code + 1, ....  The code values are
 		// assigned in literal order (not frequency order).
 		chunk := list[len(list)-int(bits):]
-		sortByLiteral(chunk)
+
+		h.lns.sort(chunk)
 		for _, node := range chunk {
-			h.codeBits[node.literal] = uint8(n)
-			h.code[node.literal] = reverseBits(code, uint8(n))
+			h.codes[node.literal] = hcode{code: reverseBits(code, uint8(n)), len: uint16(n)}
 			code++
 		}
 		list = list[0 : len(list)-int(bits)]
@@ -261,7 +271,13 @@ func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalN
 // freq  An array of frequencies, in which frequency[i] gives the frequency of literal i.
 // maxBits  The maximum number of bits to use for any literal.
 func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
-	list := make([]literalNode, len(freq)+1)
+	if h.freqcache == nil {
+		// Allocate a reusable buffer with the longest possible frequency table.
+		// Possible lengths are codegenCodeCount, offsetCodeCount and maxNumLit.
+		// The largest of these is maxNumLit, so we allocate for that case.
+		h.freqcache = make([]literalNode, maxNumLit+1)
+	}
+	list := h.freqcache[:len(freq)+1]
 	// Number of non-zero literals
 	count := 0
 	// Set list to be the set of all non-zero literals and their frequencies
@@ -270,23 +286,23 @@ func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
 			list[count] = literalNode{uint16(i), f}
 			count++
 		} else {
-			h.codeBits[i] = 0
+			list[count] = literalNode{}
+			h.codes[i].len = 0
 		}
 	}
-	// If freq[] is shorter than codeBits[], fill rest of codeBits[] with zeros
-	h.codeBits = h.codeBits[0:len(freq)]
-	list = list[0:count]
+	list[len(freq)] = literalNode{}
+
+	list = list[:count]
 	if count <= 2 {
-		// Handle the small cases here, because they are awkward for the general case code.  With
+		// Handle the small cases here, because they are awkward for the general case code. With
 		// two or fewer literals, everything has bit length 1.
 		for i, node := range list {
 			// "list" is in order of increasing literal value.
-			h.codeBits[node.literal] = 1
-			h.code[node.literal] = uint16(i)
+			h.codes[node.literal].set(uint16(i), 1)
 		}
 		return
 	}
-	sortByFreq(list)
+	h.lfs.sort(list)
 
 	// Get the number of literals for each bit count
 	bitCount := h.bitCounts(list, maxBits)
@@ -294,30 +310,35 @@ func (h *huffmanEncoder) generate(freq []int32, maxBits int32) {
 	h.assignEncodingAndSize(bitCount, list)
 }
 
-type literalNodeSorter struct {
-	a    []literalNode
-	less func(i, j int) bool
+type byLiteral []literalNode
+
+func (s *byLiteral) sort(a []literalNode) {
+	*s = byLiteral(a)
+	sort.Sort(s)
 }
 
-func (s literalNodeSorter) Len() int { return len(s.a) }
+func (s byLiteral) Len() int { return len(s) }
 
-func (s literalNodeSorter) Less(i, j int) bool {
-	return s.less(i, j)
+func (s byLiteral) Less(i, j int) bool {
+	return s[i].literal < s[j].literal
 }
 
-func (s literalNodeSorter) Swap(i, j int) { s.a[i], s.a[j] = s.a[j], s.a[i] }
+func (s byLiteral) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 
-func sortByFreq(a []literalNode) {
-	s := &literalNodeSorter{a, func(i, j int) bool {
-		if a[i].freq == a[j].freq {
-			return a[i].literal < a[j].literal
-		}
-		return a[i].freq < a[j].freq
-	}}
+type byFreq []literalNode
+
+func (s *byFreq) sort(a []literalNode) {
+	*s = byFreq(a)
 	sort.Sort(s)
 }
 
-func sortByLiteral(a []literalNode) {
-	s := &literalNodeSorter{a, func(i, j int) bool { return a[i].literal < a[j].literal }}
-	sort.Sort(s)
+func (s byFreq) Len() int { return len(s) }
+
+func (s byFreq) Less(i, j int) bool {
+	if s[i].freq == s[j].freq {
+		return s[i].literal < s[j].literal
+	}
+	return s[i].freq < s[j].freq
 }
+
+func (s byFreq) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
diff --git a/src/compress/flate/inflate.go b/src/compress/flate/inflate.go
index 42261e9..68cc232 100644
--- a/src/compress/flate/inflate.go
+++ b/src/compress/flate/inflate.go
@@ -15,8 +15,7 @@ import (
 )
 
 const (
-	maxCodeLen = 16    // max length of Huffman code
-	maxHist    = 32768 // max history required
+	maxCodeLen = 16 // max length of Huffman 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.
@@ -115,7 +114,7 @@ type huffmanDecoder struct {
 // 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
+	// table construction. It's intended to be used during
 	// development to supplement the currently ad-hoc unit tests.
 	const sanity = false
 
@@ -162,7 +161,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
 	// 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
+	// accept degenerate single-code codings. See also
 	// TestDegenerateHuffmanCoding.
 	if code != 1<<uint(max) && !(code == 1 && max == 1) {
 		return false
@@ -200,7 +199,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		if n <= huffmanChunkBits {
 			for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
 				// We should never need to overwrite
-				// an existing chunk.  Also, 0 is
+				// an existing chunk. Also, 0 is
 				// never a valid chunk, because the
 				// lower 4 "count" bits should be
 				// between 1 and 15.
@@ -230,7 +229,7 @@ func (h *huffmanDecoder) init(bits []int) bool {
 
 	if sanity {
 		// Above we've sanity checked that we never overwrote
-		// an existing entry.  Here we additionally check that
+		// an existing entry. Here we additionally check that
 		// we filled the tables completely.
 		for i, chunk := range h.chunks {
 			if chunk == 0 {
@@ -268,7 +267,6 @@ type decompressor struct {
 	// Input source.
 	r       Reader
 	roffset int64
-	woffset int64
 
 	// Input bits, in top of b.
 	b  uint32
@@ -282,34 +280,24 @@ type decompressor struct {
 	codebits *[numCodes]int
 
 	// Output history, buffer.
-	hist  *[maxHist]byte
-	hp    int  // current output position in buffer
-	hw    int  // have written hist[0:hw] already
-	hfull bool // buffer has filled at least once
+	dict dictDecoder
 
 	// Temporary buffer (avoids repeated allocation).
 	buf [4]byte
 
 	// Next step in the decompression,
 	// and decompression state.
-	step     func(*decompressor)
-	final    bool
-	err      error
-	toRead   []byte
-	hl, hd   *huffmanDecoder
-	copyLen  int
-	copyDist int
+	step      func(*decompressor)
+	stepState int
+	final     bool
+	err       error
+	toRead    []byte
+	hl, hd    *huffmanDecoder
+	copyLen   int
+	copyDist  int
 }
 
 func (f *decompressor) nextBlock() {
-	if f.final {
-		if f.hw != f.hp {
-			f.flush((*decompressor).nextBlock)
-			return
-		}
-		f.err = io.EOF
-		return
-	}
 	for f.nb < 1+2 {
 		if f.err = f.moreBits(); f.err != nil {
 			return
@@ -347,6 +335,9 @@ func (f *decompressor) Read(b []byte) (int, error) {
 		if len(f.toRead) > 0 {
 			n := copy(b, f.toRead)
 			f.toRead = f.toRead[n:]
+			if len(f.toRead) == 0 {
+				return n, f.err
+			}
 			return n, nil
 		}
 		if f.err != nil {
@@ -478,10 +469,24 @@ func (f *decompressor) readHuffman() error {
 
 // Decode a single Huffman block from f.
 // hl and hd are the Huffman states for the lit/length values
-// and the distance values, respectively.  If hd == nil, using the
+// and the distance values, respectively. If hd == nil, using the
 // fixed distance encoding associated with fixed Huffman blocks.
 func (f *decompressor) huffmanBlock() {
-	for {
+	const (
+		stateInit = iota // Zero value must be stateInit
+		stateDict
+	)
+
+	switch f.stepState {
+	case stateInit:
+		goto readLiteral
+	case stateDict:
+		goto copyHistory
+	}
+
+readLiteral:
+	// Read literal and/or (length, distance) according to RFC section 3.2.3.
+	{
 		v, err := f.huffSym(f.hl)
 		if err != nil {
 			f.err = err
@@ -491,17 +496,16 @@ func (f *decompressor) huffmanBlock() {
 		var length int
 		switch {
 		case v < 256:
-			f.hist[f.hp] = byte(v)
-			f.hp++
-			if f.hp == len(f.hist) {
-				// After the flush, continue this loop.
-				f.flush((*decompressor).huffmanBlock)
+			f.dict.writeByte(byte(v))
+			if f.dict.availWrite() == 0 {
+				f.toRead = f.dict.readFlush()
+				f.step = (*decompressor).huffmanBlock
+				f.stepState = stateInit
 				return
 			}
-			continue
+			goto readLiteral
 		case v == 256:
-			// Done with huffman block; read next block.
-			f.step = (*decompressor).nextBlock
+			f.finishBlock()
 			return
 		// otherwise, reference to older data
 		case v < 265:
@@ -581,61 +585,33 @@ func (f *decompressor) huffmanBlock() {
 			return
 		}
 
-		// Copy history[-dist:-dist+length] into output.
-		if dist > len(f.hist) {
-			f.err = InternalError("bad history distance")
-			return
-		}
-
 		// No check on length; encoding can be prescient.
-		if !f.hfull && dist > f.hp {
+		if dist > f.dict.histSize() {
 			f.err = CorruptInputError(f.roffset)
 			return
 		}
 
 		f.copyLen, f.copyDist = length, dist
-		if f.copyHist() {
-			return
-		}
+		goto copyHistory
 	}
-}
 
-// copyHist copies f.copyLen bytes from f.hist (f.copyDist bytes ago) to itself.
-// It reports whether the f.hist buffer is full.
-func (f *decompressor) copyHist() bool {
-	p := f.hp - f.copyDist
-	if p < 0 {
-		p += len(f.hist)
-	}
-	for f.copyLen > 0 {
-		n := f.copyLen
-		if x := len(f.hist) - f.hp; n > x {
-			n = x
-		}
-		if x := len(f.hist) - p; n > x {
-			n = x
+copyHistory:
+	// Perform a backwards copy according to RFC section 3.2.3.
+	{
+		cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen)
+		if cnt == 0 {
+			cnt = f.dict.writeCopy(f.copyDist, f.copyLen)
 		}
-		forwardCopy(f.hist[:], f.hp, p, n)
-		p += n
-		f.hp += n
-		f.copyLen -= n
-		if f.hp == len(f.hist) {
-			// After flush continue copying out of history.
-			f.flush((*decompressor).copyHuff)
-			return true
-		}
-		if p == len(f.hist) {
-			p = 0
-		}
-	}
-	return false
-}
+		f.copyLen -= cnt
 
-func (f *decompressor) copyHuff() {
-	if f.copyHist() {
-		return
+		if f.dict.availWrite() == 0 || f.copyLen > 0 {
+			f.toRead = f.dict.readFlush()
+			f.step = (*decompressor).huffmanBlock // We need to continue this work
+			f.stepState = stateDict
+			return
+		}
+		goto readLiteral
 	}
-	f.huffmanBlock()
 }
 
 // Copy a single uncompressed data block from input to output.
@@ -663,8 +639,8 @@ func (f *decompressor) dataBlock() {
 	}
 
 	if n == 0 {
-		// 0-length block means sync
-		f.flush((*decompressor).nextBlock)
+		f.toRead = f.dict.readFlush()
+		f.finishBlock()
 		return
 	}
 
@@ -675,44 +651,39 @@ func (f *decompressor) dataBlock() {
 // copyData copies f.copyLen bytes from the underlying reader into f.hist.
 // It pauses for reads when f.hist is full.
 func (f *decompressor) copyData() {
-	n := f.copyLen
-	for n > 0 {
-		m := len(f.hist) - f.hp
-		if m > n {
-			m = n
-		}
-		m, err := io.ReadFull(f.r, f.hist[f.hp:f.hp+m])
-		f.roffset += int64(m)
-		if err != nil {
-			if err == io.EOF {
-				err = io.ErrUnexpectedEOF
-			}
-			f.err = err
-			return
-		}
-		n -= m
-		f.hp += m
-		if f.hp == len(f.hist) {
-			f.copyLen = n
-			f.flush((*decompressor).copyData)
-			return
+	buf := f.dict.writeSlice()
+	if len(buf) > f.copyLen {
+		buf = buf[:f.copyLen]
+	}
+
+	cnt, err := io.ReadFull(f.r, buf)
+	f.roffset += int64(cnt)
+	f.copyLen -= cnt
+	f.dict.writeMark(cnt)
+	if err != nil {
+		if err == io.EOF {
+			err = io.ErrUnexpectedEOF
 		}
+		f.err = err
+		return
 	}
-	f.step = (*decompressor).nextBlock
-}
 
-func (f *decompressor) setDict(dict []byte) {
-	if len(dict) > len(f.hist) {
-		// Will only remember the tail.
-		dict = dict[len(dict)-len(f.hist):]
+	if f.dict.availWrite() == 0 || f.copyLen > 0 {
+		f.toRead = f.dict.readFlush()
+		f.step = (*decompressor).copyData
+		return
 	}
+	f.finishBlock()
+}
 
-	f.hp = copy(f.hist[:], dict)
-	if f.hp == len(f.hist) {
-		f.hp = 0
-		f.hfull = true
+func (f *decompressor) finishBlock() {
+	if f.final {
+		if f.dict.availRead() > 0 {
+			f.toRead = f.dict.readFlush()
+		}
+		f.err = io.EOF
 	}
-	f.hw = f.hp
+	f.step = (*decompressor).nextBlock
 }
 
 func (f *decompressor) moreBits() error {
@@ -760,19 +731,6 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
 	}
 }
 
-// Flush any buffered output to the underlying writer.
-func (f *decompressor) flush(step func(*decompressor)) {
-	f.toRead = f.hist[f.hw:f.hp]
-	f.woffset += int64(f.hp - f.hw)
-	f.hw = f.hp
-	if f.hp == len(f.hist) {
-		f.hp = 0
-		f.hw = 0
-		f.hfull = true
-	}
-	f.step = step
-}
-
 func makeReader(r io.Reader) Reader {
 	if rr, ok := r.(Reader); ok {
 		return rr
@@ -805,12 +763,10 @@ func (f *decompressor) Reset(r io.Reader, dict []byte) error {
 		r:        makeReader(r),
 		bits:     f.bits,
 		codebits: f.codebits,
-		hist:     f.hist,
+		dict:     f.dict,
 		step:     (*decompressor).nextBlock,
 	}
-	if dict != nil {
-		f.setDict(dict)
-	}
+	f.dict.init(maxMatchOffset, dict)
 	return nil
 }
 
@@ -827,17 +783,17 @@ func NewReader(r io.Reader) io.ReadCloser {
 
 	var f decompressor
 	f.r = makeReader(r)
-	f.hist = new([maxHist]byte)
 	f.bits = new([maxNumLit + maxNumDist]int)
 	f.codebits = new([numCodes]int)
 	f.step = (*decompressor).nextBlock
+	f.dict.init(maxMatchOffset, nil)
 	return &f
 }
 
 // NewReaderDict is like NewReader but initializes the reader
-// with a preset dictionary.  The returned Reader behaves as if
+// with a preset dictionary. The returned Reader behaves as if
 // the uncompressed data stream started with the given dictionary,
-// which has already been read.  NewReaderDict is typically used
+// which has already been read. NewReaderDict is typically used
 // to read data compressed by NewWriterDict.
 //
 // The ReadCloser returned by NewReader also implements Resetter.
@@ -846,10 +802,9 @@ func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
 
 	var f decompressor
 	f.r = makeReader(r)
-	f.hist = new([maxHist]byte)
 	f.bits = new([maxNumLit + maxNumDist]int)
 	f.codebits = new([numCodes]int)
 	f.step = (*decompressor).nextBlock
-	f.setDict(dict)
+	f.dict.init(maxMatchOffset, dict)
 	return &f
 }
diff --git a/src/compress/flate/inflate_test.go b/src/compress/flate/inflate_test.go
index 9f25d30..e0bce71 100644
--- a/src/compress/flate/inflate_test.go
+++ b/src/compress/flate/inflate_test.go
@@ -37,3 +37,33 @@ func TestReset(t *testing.T) {
 		}
 	}
 }
+
+func TestResetDict(t *testing.T) {
+	dict := []byte("the lorem fox")
+	ss := []string{
+		"lorem ipsum izzle fo rizzle",
+		"the quick brown fox jumped over",
+	}
+
+	deflated := make([]bytes.Buffer, len(ss))
+	for i, s := range ss {
+		w, _ := NewWriterDict(&deflated[i], DefaultCompression, dict)
+		w.Write([]byte(s))
+		w.Close()
+	}
+
+	inflated := make([]bytes.Buffer, len(ss))
+
+	f := NewReader(nil)
+	for i := range inflated {
+		f.(Resetter).Reset(&deflated[i], dict)
+		io.Copy(&inflated[i], f)
+	}
+	f.Close()
+
+	for i, s := range ss {
+		if s != inflated[i].String() {
+			t.Errorf("inflated[%d]:\ngot  %q\nwant %q", i, inflated[i], s)
+		}
+	}
+}
diff --git a/src/compress/flate/reader_test.go b/src/compress/flate/reader_test.go
index bd88732..b0a16ce 100644
--- a/src/compress/flate/reader_test.go
+++ b/src/compress/flate/reader_test.go
@@ -22,75 +22,77 @@ func TestNlitOutOfRange(t *testing.T) {
 			"\x75\xc4\xf8\x0f\x12\x11\xb9\xb4\x4b\x09\xa0\xbe\x8b\x91\x4c")))
 }
 
-const (
-	digits = iota
-	twain
-)
-
-var testfiles = []string{
+var suites = []struct{ name, file string }{
 	// Digits is the digits of the irrational number e. Its decimal representation
 	// does not repeat, but there are only 10 possible digits, so it should be
 	// reasonably compressible.
-	digits: "../testdata/e.txt",
+	{"Digits", "../testdata/e.txt"},
 	// Twain is Mark Twain's classic English novel.
-	twain: "../testdata/Mark.Twain-Tom.Sawyer.txt",
+	{"Twain", "../testdata/Mark.Twain-Tom.Sawyer.txt"},
 }
 
-func benchmarkDecode(b *testing.B, testfile, level, n int) {
-	b.ReportAllocs()
-	b.StopTimer()
-	b.SetBytes(int64(n))
-	buf0, err := ioutil.ReadFile(testfiles[testfile])
-	if err != nil {
-		b.Fatal(err)
-	}
-	if len(buf0) == 0 {
-		b.Fatalf("test file %q has no data", testfiles[testfile])
-	}
-	compressed := new(bytes.Buffer)
-	w, err := NewWriter(compressed, level)
-	if err != nil {
-		b.Fatal(err)
-	}
-	for i := 0; i < n; i += len(buf0) {
-		if len(buf0) > n-i {
-			buf0 = buf0[:n-i]
+func BenchmarkDecode(b *testing.B) {
+	doBench(b, func(b *testing.B, buf0 []byte, level, n int) {
+		b.ReportAllocs()
+		b.StopTimer()
+		b.SetBytes(int64(n))
+
+		compressed := new(bytes.Buffer)
+		w, err := NewWriter(compressed, level)
+		if err != nil {
+			b.Fatal(err)
 		}
-		io.Copy(w, bytes.NewReader(buf0))
-	}
-	w.Close()
-	buf1 := compressed.Bytes()
-	buf0, compressed, w = nil, nil, nil
-	runtime.GC()
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
-	}
+		for i := 0; i < n; i += len(buf0) {
+			if len(buf0) > n-i {
+				buf0 = buf0[:n-i]
+			}
+			io.Copy(w, bytes.NewReader(buf0))
+		}
+		w.Close()
+		buf1 := compressed.Bytes()
+		buf0, compressed, w = nil, nil, nil
+		runtime.GC()
+		b.StartTimer()
+		for i := 0; i < b.N; i++ {
+			io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1)))
+		}
+	})
 }
 
-// These short names are so that gofmt doesn't break the BenchmarkXxx function
-// bodies below over multiple lines.
-const (
-	speed    = BestSpeed
-	default_ = DefaultCompression
-	compress = BestCompression
-)
+var levelTests = []struct {
+	name  string
+	level int
+}{
+	{"Huffman", HuffmanOnly},
+	{"Speed", BestSpeed},
+	{"Default", DefaultCompression},
+	{"Compression", BestCompression},
+}
 
-func BenchmarkDecodeDigitsSpeed1e4(b *testing.B)    { benchmarkDecode(b, digits, speed, 1e4) }
-func BenchmarkDecodeDigitsSpeed1e5(b *testing.B)    { benchmarkDecode(b, digits, speed, 1e5) }
-func BenchmarkDecodeDigitsSpeed1e6(b *testing.B)    { benchmarkDecode(b, digits, speed, 1e6) }
-func BenchmarkDecodeDigitsDefault1e4(b *testing.B)  { benchmarkDecode(b, digits, default_, 1e4) }
-func BenchmarkDecodeDigitsDefault1e5(b *testing.B)  { benchmarkDecode(b, digits, default_, 1e5) }
-func BenchmarkDecodeDigitsDefault1e6(b *testing.B)  { benchmarkDecode(b, digits, default_, 1e6) }
-func BenchmarkDecodeDigitsCompress1e4(b *testing.B) { benchmarkDecode(b, digits, compress, 1e4) }
-func BenchmarkDecodeDigitsCompress1e5(b *testing.B) { benchmarkDecode(b, digits, compress, 1e5) }
-func BenchmarkDecodeDigitsCompress1e6(b *testing.B) { benchmarkDecode(b, digits, compress, 1e6) }
-func BenchmarkDecodeTwainSpeed1e4(b *testing.B)     { benchmarkDecode(b, twain, speed, 1e4) }
-func BenchmarkDecodeTwainSpeed1e5(b *testing.B)     { benchmarkDecode(b, twain, speed, 1e5) }
-func BenchmarkDecodeTwainSpeed1e6(b *testing.B)     { benchmarkDecode(b, twain, speed, 1e6) }
-func BenchmarkDecodeTwainDefault1e4(b *testing.B)   { benchmarkDecode(b, twain, default_, 1e4) }
-func BenchmarkDecodeTwainDefault1e5(b *testing.B)   { benchmarkDecode(b, twain, default_, 1e5) }
-func BenchmarkDecodeTwainDefault1e6(b *testing.B)   { benchmarkDecode(b, twain, default_, 1e6) }
-func BenchmarkDecodeTwainCompress1e4(b *testing.B)  { benchmarkDecode(b, twain, compress, 1e4) }
-func BenchmarkDecodeTwainCompress1e5(b *testing.B)  { benchmarkDecode(b, twain, compress, 1e5) }
-func BenchmarkDecodeTwainCompress1e6(b *testing.B)  { benchmarkDecode(b, twain, compress, 1e6) }
+var sizes = []struct {
+	name string
+	n    int
+}{
+	{"1e4", 1e4},
+	{"1e5", 1e5},
+	{"1e6", 1e6},
+}
+
+func doBench(b *testing.B, f func(b *testing.B, buf []byte, level, n int)) {
+	for _, suite := range suites {
+		buf, err := ioutil.ReadFile(suite.file)
+		if err != nil {
+			b.Fatal(err)
+		}
+		if len(buf) == 0 {
+			b.Fatalf("test file %q has no data", suite.file)
+		}
+		for _, l := range levelTests {
+			for _, s := range sizes {
+				b.Run(suite.name+"/"+l.name+"/"+s.name, func(b *testing.B) {
+					f(b, buf, l.level, s.n)
+				})
+			}
+		}
+	}
+}
diff --git a/src/compress/flate/reverse_bits.go b/src/compress/flate/reverse_bits.go
index c1a0272..6b22290 100644
--- a/src/compress/flate/reverse_bits.go
+++ b/src/compress/flate/reverse_bits.go
@@ -44,5 +44,5 @@ func reverseUint16(v uint16) uint16 {
 }
 
 func reverseBits(number uint16, bitLength byte) uint16 {
-	return reverseUint16(number << uint8(16-bitLength))
+	return reverseUint16(number << (16 - bitLength))
 }
diff --git a/src/compress/flate/testdata/huffman-null-max.dyn.expect b/src/compress/flate/testdata/huffman-null-max.dyn.expect
new file mode 100644
index 0000000..c081651
Binary files /dev/null and b/src/compress/flate/testdata/huffman-null-max.dyn.expect differ
diff --git a/src/compress/flate/testdata/huffman-null-max.dyn.expect-noinput b/src/compress/flate/testdata/huffman-null-max.dyn.expect-noinput
new file mode 100644
index 0000000..c081651
Binary files /dev/null and b/src/compress/flate/testdata/huffman-null-max.dyn.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-null-max.golden b/src/compress/flate/testdata/huffman-null-max.golden
new file mode 100644
index 0000000..db422ca
Binary files /dev/null and b/src/compress/flate/testdata/huffman-null-max.golden differ
diff --git a/src/compress/flate/testdata/huffman-null-max.in b/src/compress/flate/testdata/huffman-null-max.in
new file mode 100644
index 0000000..5dfddf0
Binary files /dev/null and b/src/compress/flate/testdata/huffman-null-max.in differ
diff --git a/src/compress/flate/testdata/huffman-null-max.wb.expect b/src/compress/flate/testdata/huffman-null-max.wb.expect
new file mode 100644
index 0000000..c081651
Binary files /dev/null and b/src/compress/flate/testdata/huffman-null-max.wb.expect differ
diff --git a/src/compress/flate/testdata/huffman-null-max.wb.expect-noinput b/src/compress/flate/testdata/huffman-null-max.wb.expect-noinput
new file mode 100644
index 0000000..c081651
Binary files /dev/null and b/src/compress/flate/testdata/huffman-null-max.wb.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-pi.dyn.expect b/src/compress/flate/testdata/huffman-pi.dyn.expect
new file mode 100644
index 0000000..e4396ac
Binary files /dev/null and b/src/compress/flate/testdata/huffman-pi.dyn.expect differ
diff --git a/src/compress/flate/testdata/huffman-pi.dyn.expect-noinput b/src/compress/flate/testdata/huffman-pi.dyn.expect-noinput
new file mode 100644
index 0000000..e4396ac
Binary files /dev/null and b/src/compress/flate/testdata/huffman-pi.dyn.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-pi.golden b/src/compress/flate/testdata/huffman-pi.golden
new file mode 100644
index 0000000..23d8f7f
Binary files /dev/null and b/src/compress/flate/testdata/huffman-pi.golden differ
diff --git a/src/compress/flate/testdata/huffman-pi.in b/src/compress/flate/testdata/huffman-pi.in
new file mode 100644
index 0000000..efaed43
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-pi.in
@@ -0,0 +1 @@
+3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381 [...]
\ No newline at end of file
diff --git a/src/compress/flate/testdata/huffman-pi.wb.expect b/src/compress/flate/testdata/huffman-pi.wb.expect
new file mode 100644
index 0000000..e4396ac
Binary files /dev/null and b/src/compress/flate/testdata/huffman-pi.wb.expect differ
diff --git a/src/compress/flate/testdata/huffman-pi.wb.expect-noinput b/src/compress/flate/testdata/huffman-pi.wb.expect-noinput
new file mode 100644
index 0000000..e4396ac
Binary files /dev/null and b/src/compress/flate/testdata/huffman-pi.wb.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-rand-1k.dyn.expect b/src/compress/flate/testdata/huffman-rand-1k.dyn.expect
new file mode 100644
index 0000000..09dc798
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-1k.dyn.expect differ
diff --git a/src/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput b/src/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput
new file mode 100644
index 0000000..0c24742
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-rand-1k.golden b/src/compress/flate/testdata/huffman-rand-1k.golden
new file mode 100644
index 0000000..09dc798
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-1k.golden differ
diff --git a/src/compress/flate/testdata/huffman-rand-1k.in b/src/compress/flate/testdata/huffman-rand-1k.in
new file mode 100644
index 0000000..ce038eb
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-1k.in differ
diff --git a/src/compress/flate/testdata/huffman-rand-1k.wb.expect b/src/compress/flate/testdata/huffman-rand-1k.wb.expect
new file mode 100644
index 0000000..09dc798
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-1k.wb.expect differ
diff --git a/src/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput b/src/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput
new file mode 100644
index 0000000..0c24742
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-rand-limit.dyn.expect b/src/compress/flate/testdata/huffman-rand-limit.dyn.expect
new file mode 100644
index 0000000..2d65279
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-limit.dyn.expect differ
diff --git a/src/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput b/src/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput
new file mode 100644
index 0000000..2d65279
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-rand-limit.golden b/src/compress/flate/testdata/huffman-rand-limit.golden
new file mode 100644
index 0000000..57e5932
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-limit.golden differ
diff --git a/src/compress/flate/testdata/huffman-rand-limit.in b/src/compress/flate/testdata/huffman-rand-limit.in
new file mode 100644
index 0000000..fb5b1be
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-rand-limit.in
@@ -0,0 +1,4 @@
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+���vH
+��%������ ��ɷ���}��>���ls���m�IGH���1Y�4�[��	0ˆ[|]o#�
+�-#���ul���pf��ٱ�n�Y�ԀY�w�C8ɯ02� F=gn�r�N!O���{����k�*�w(��b� ��kQC9/��lu>�5�C.��u��
diff --git a/src/compress/flate/testdata/huffman-rand-limit.wb.expect b/src/compress/flate/testdata/huffman-rand-limit.wb.expect
new file mode 100644
index 0000000..881e59c
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-limit.wb.expect differ
diff --git a/src/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput b/src/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput
new file mode 100644
index 0000000..881e59c
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-rand-max.golden b/src/compress/flate/testdata/huffman-rand-max.golden
new file mode 100644
index 0000000..47d53c8
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-max.golden differ
diff --git a/src/compress/flate/testdata/huffman-rand-max.in b/src/compress/flate/testdata/huffman-rand-max.in
new file mode 100644
index 0000000..8418633
Binary files /dev/null and b/src/compress/flate/testdata/huffman-rand-max.in differ
diff --git a/src/compress/flate/testdata/huffman-shifts.dyn.expect b/src/compress/flate/testdata/huffman-shifts.dyn.expect
new file mode 100644
index 0000000..7812c1c
Binary files /dev/null and b/src/compress/flate/testdata/huffman-shifts.dyn.expect differ
diff --git a/src/compress/flate/testdata/huffman-shifts.dyn.expect-noinput b/src/compress/flate/testdata/huffman-shifts.dyn.expect-noinput
new file mode 100644
index 0000000..7812c1c
Binary files /dev/null and b/src/compress/flate/testdata/huffman-shifts.dyn.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-shifts.golden b/src/compress/flate/testdata/huffman-shifts.golden
new file mode 100644
index 0000000..f513377
Binary files /dev/null and b/src/compress/flate/testdata/huffman-shifts.golden differ
diff --git a/src/compress/flate/testdata/huffman-shifts.in b/src/compress/flate/testdata/huffman-shifts.in
new file mode 100644
index 0000000..7c7a50d
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-shifts.in
@@ -0,0 +1,2 @@
+101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 [...]
+232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323 [...]
\ No newline at end of file
diff --git a/src/compress/flate/testdata/huffman-shifts.wb.expect b/src/compress/flate/testdata/huffman-shifts.wb.expect
new file mode 100644
index 0000000..7812c1c
Binary files /dev/null and b/src/compress/flate/testdata/huffman-shifts.wb.expect differ
diff --git a/src/compress/flate/testdata/huffman-shifts.wb.expect-noinput b/src/compress/flate/testdata/huffman-shifts.wb.expect-noinput
new file mode 100644
index 0000000..7812c1c
Binary files /dev/null and b/src/compress/flate/testdata/huffman-shifts.wb.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-text-shift.dyn.expect b/src/compress/flate/testdata/huffman-text-shift.dyn.expect
new file mode 100644
index 0000000..71ce3ae
Binary files /dev/null and b/src/compress/flate/testdata/huffman-text-shift.dyn.expect differ
diff --git a/src/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput b/src/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput
new file mode 100644
index 0000000..71ce3ae
Binary files /dev/null and b/src/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-text-shift.golden b/src/compress/flate/testdata/huffman-text-shift.golden
new file mode 100644
index 0000000..ff02311
Binary files /dev/null and b/src/compress/flate/testdata/huffman-text-shift.golden differ
diff --git a/src/compress/flate/testdata/huffman-text-shift.in b/src/compress/flate/testdata/huffman-text-shift.in
new file mode 100644
index 0000000..cc5c3ad
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-text-shift.in
@@ -0,0 +1,14 @@
+//Copyright2009ThGoAuthor.Allrightrrvd.
+//UofthiourccodigovrndbyBSD-tyl
+//licnthtcnbfoundinthLICENSEfil.
+
+pckgmin
+
+import"o"
+
+funcmin(){
+	vrb=mk([]byt,65535)
+	f,_:=o.Crt("huffmn-null-mx.in")
+	f.Writ(b)
+}
+ABCDEFGHIJKLMNOPQRSTUVXxyz!"#¤%&/?"
\ No newline at end of file
diff --git a/src/compress/flate/testdata/huffman-text-shift.wb.expect b/src/compress/flate/testdata/huffman-text-shift.wb.expect
new file mode 100644
index 0000000..71ce3ae
Binary files /dev/null and b/src/compress/flate/testdata/huffman-text-shift.wb.expect differ
diff --git a/src/compress/flate/testdata/huffman-text-shift.wb.expect-noinput b/src/compress/flate/testdata/huffman-text-shift.wb.expect-noinput
new file mode 100644
index 0000000..71ce3ae
Binary files /dev/null and b/src/compress/flate/testdata/huffman-text-shift.wb.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-text.dyn.expect b/src/compress/flate/testdata/huffman-text.dyn.expect
new file mode 100644
index 0000000..d448727
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-text.dyn.expect
@@ -0,0 +1 @@
+
�_K�0
����
��`K��0Aasě)^�H�����Iɟb߻��_>�4
a��=����-^
�1`_�	1	���	�ő:�Y��-�F66!�A��`�a��C;A���Nyr4ߜU�!���GKС��#�����r:B[G�3��.�L��׶�bFRuM]���^⇳�(#Z���
���i�����v��B��
B�H2S]��u/���ֽ��W�T�G��n���r�
\ No newline at end of file
diff --git a/src/compress/flate/testdata/huffman-text.dyn.expect-noinput b/src/compress/flate/testdata/huffman-text.dyn.expect-noinput
new file mode 100644
index 0000000..d448727
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-text.dyn.expect-noinput
@@ -0,0 +1 @@
+
�_K�0
����
��`K��0Aasě)^�H�����Iɟb߻��_>�4
a��=����-^
�1`_�	1	���	�ő:�Y��-�F66!�A��`�a��C;A���Nyr4ߜU�!���GKС��#�����r:B[G�3��.�L��׶�bFRuM]���^⇳�(#Z���
���i�����v��B��
B�H2S]��u/���ֽ��W�T�G��n���r�
\ No newline at end of file
diff --git a/src/compress/flate/testdata/huffman-text.golden b/src/compress/flate/testdata/huffman-text.golden
new file mode 100644
index 0000000..6d34c61
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-text.golden
@@ -0,0 +1,3 @@
+�AK�0��
x��Z���LP�a�!�x��AD��I�&#I�E�����p]�
Lƿ���F�p��	1�88�h��$���5S��-	�F66!�)v�.��0�Y��
�����&��	S���N|d�2:��
+t�|둍���xz9������骺�����Ɏ�3��
+&&=������ô�UD�=Fu���]��q����UL+�����>FQY��LZ��o���fTߵ�EŴ��{�Yʶb�e�
\ No newline at end of file
diff --git a/src/compress/flate/testdata/huffman-text.in b/src/compress/flate/testdata/huffman-text.in
new file mode 100644
index 0000000..73398b9
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-text.in
@@ -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.
+
+package main
+
+import "os"
+
+func main() {
+	var b = make([]byte, 65535)
+	f, _ := os.Create("huffman-null-max.in")
+	f.Write(b)
+}
diff --git a/src/compress/flate/testdata/huffman-text.wb.expect b/src/compress/flate/testdata/huffman-text.wb.expect
new file mode 100644
index 0000000..d448727
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-text.wb.expect
@@ -0,0 +1 @@
+
�_K�0
����
��`K��0Aasě)^�H�����Iɟb߻��_>�4
a��=����-^
�1`_�	1	���	�ő:�Y��-�F66!�A��`�a��C;A���Nyr4ߜU�!���GKС��#�����r:B[G�3��.�L��׶�bFRuM]���^⇳�(#Z���
���i�����v��B��
B�H2S]��u/���ֽ��W�T�G��n���r�
\ No newline at end of file
diff --git a/src/compress/flate/testdata/huffman-text.wb.expect-noinput b/src/compress/flate/testdata/huffman-text.wb.expect-noinput
new file mode 100644
index 0000000..d448727
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-text.wb.expect-noinput
@@ -0,0 +1 @@
+
�_K�0
����
��`K��0Aasě)^�H�����Iɟb߻��_>�4
a��=����-^
�1`_�	1	���	�ő:�Y��-�F66!�A��`�a��C;A���Nyr4ߜU�!���GKС��#�����r:B[G�3��.�L��׶�bFRuM]���^⇳�(#Z���
���i�����v��B��
B�H2S]��u/���ֽ��W�T�G��n���r�
\ No newline at end of file
diff --git a/src/compress/flate/testdata/huffman-zero.dyn.expect b/src/compress/flate/testdata/huffman-zero.dyn.expect
new file mode 100644
index 0000000..830348a
Binary files /dev/null and b/src/compress/flate/testdata/huffman-zero.dyn.expect differ
diff --git a/src/compress/flate/testdata/huffman-zero.dyn.expect-noinput b/src/compress/flate/testdata/huffman-zero.dyn.expect-noinput
new file mode 100644
index 0000000..830348a
Binary files /dev/null and b/src/compress/flate/testdata/huffman-zero.dyn.expect-noinput differ
diff --git a/src/compress/flate/testdata/huffman-zero.golden b/src/compress/flate/testdata/huffman-zero.golden
new file mode 100644
index 0000000..5abdbaf
Binary files /dev/null and b/src/compress/flate/testdata/huffman-zero.golden differ
diff --git a/src/compress/flate/testdata/huffman-zero.in b/src/compress/flate/testdata/huffman-zero.in
new file mode 100644
index 0000000..349be0e
--- /dev/null
+++ b/src/compress/flate/testdata/huffman-zero.in
@@ -0,0 +1 @@
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
\ No newline at end of file
diff --git a/src/compress/flate/testdata/huffman-zero.wb.expect b/src/compress/flate/testdata/huffman-zero.wb.expect
new file mode 100644
index 0000000..dbe401c
Binary files /dev/null and b/src/compress/flate/testdata/huffman-zero.wb.expect differ
diff --git a/src/compress/flate/testdata/huffman-zero.wb.expect-noinput b/src/compress/flate/testdata/huffman-zero.wb.expect-noinput
new file mode 100644
index 0000000..dbe401c
Binary files /dev/null and b/src/compress/flate/testdata/huffman-zero.wb.expect-noinput differ
diff --git a/src/compress/flate/testdata/null-long-match.dyn.expect-noinput b/src/compress/flate/testdata/null-long-match.dyn.expect-noinput
new file mode 100644
index 0000000..8b92d9f
Binary files /dev/null and b/src/compress/flate/testdata/null-long-match.dyn.expect-noinput differ
diff --git a/src/compress/flate/testdata/null-long-match.wb.expect-noinput b/src/compress/flate/testdata/null-long-match.wb.expect-noinput
new file mode 100644
index 0000000..8b92d9f
Binary files /dev/null and b/src/compress/flate/testdata/null-long-match.wb.expect-noinput differ
diff --git a/src/compress/flate/token.go b/src/compress/flate/token.go
index c485939..ae01391 100644
--- a/src/compress/flate/token.go
+++ b/src/compress/flate/token.go
@@ -75,9 +75,6 @@ func matchToken(xlength uint32, xoffset uint32) token {
 	return token(matchType + xlength<<lengthShift + xoffset)
 }
 
-// Returns the type of a token
-func (t token) typ() uint32 { return uint32(t) & typeMask }
-
 // Returns the literal of a literal token
 func (t token) literal() uint32 { return uint32(t - literalType) }
 
diff --git a/src/compress/flate/writer_test.go b/src/compress/flate/writer_test.go
index 5843177..21cd0b2 100644
--- a/src/compress/flate/writer_test.go
+++ b/src/compress/flate/writer_test.go
@@ -5,56 +5,168 @@
 package flate
 
 import (
+	"bytes"
+	"fmt"
+	"io"
 	"io/ioutil"
+	"math/rand"
 	"runtime"
 	"testing"
 )
 
-func benchmarkEncoder(b *testing.B, testfile, level, n int) {
-	b.StopTimer()
-	b.SetBytes(int64(n))
-	buf0, err := ioutil.ReadFile(testfiles[testfile])
-	if err != nil {
-		b.Fatal(err)
-	}
-	if len(buf0) == 0 {
-		b.Fatalf("test file %q has no data", testfiles[testfile])
-	}
-	buf1 := make([]byte, n)
-	for i := 0; i < n; i += len(buf0) {
-		if len(buf0) > n-i {
-			buf0 = buf0[:n-i]
+func BenchmarkEncode(b *testing.B) {
+	doBench(b, func(b *testing.B, buf0 []byte, level, n int) {
+		b.StopTimer()
+		b.SetBytes(int64(n))
+
+		buf1 := make([]byte, n)
+		for i := 0; i < n; i += len(buf0) {
+			if len(buf0) > n-i {
+				buf0 = buf0[:n-i]
+			}
+			copy(buf1[i:], buf0)
 		}
-		copy(buf1[i:], buf0)
-	}
-	buf0 = nil
-	runtime.GC()
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
+		buf0 = nil
 		w, err := NewWriter(ioutil.Discard, level)
 		if err != nil {
 			b.Fatal(err)
 		}
-		w.Write(buf1)
-		w.Close()
+		runtime.GC()
+		b.StartTimer()
+		for i := 0; i < b.N; i++ {
+			w.Reset(ioutil.Discard)
+			w.Write(buf1)
+			w.Close()
+		}
+	})
+}
+
+// errorWriter is a writer that fails after N writes.
+type errorWriter struct {
+	N int
+}
+
+func (e *errorWriter) Write(b []byte) (int, error) {
+	if e.N <= 0 {
+		return 0, io.ErrClosedPipe
 	}
+	e.N--
+	return len(b), nil
 }
 
-func BenchmarkEncodeDigitsSpeed1e4(b *testing.B)    { benchmarkEncoder(b, digits, speed, 1e4) }
-func BenchmarkEncodeDigitsSpeed1e5(b *testing.B)    { benchmarkEncoder(b, digits, speed, 1e5) }
-func BenchmarkEncodeDigitsSpeed1e6(b *testing.B)    { benchmarkEncoder(b, digits, speed, 1e6) }
-func BenchmarkEncodeDigitsDefault1e4(b *testing.B)  { benchmarkEncoder(b, digits, default_, 1e4) }
-func BenchmarkEncodeDigitsDefault1e5(b *testing.B)  { benchmarkEncoder(b, digits, default_, 1e5) }
-func BenchmarkEncodeDigitsDefault1e6(b *testing.B)  { benchmarkEncoder(b, digits, default_, 1e6) }
-func BenchmarkEncodeDigitsCompress1e4(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e4) }
-func BenchmarkEncodeDigitsCompress1e5(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e5) }
-func BenchmarkEncodeDigitsCompress1e6(b *testing.B) { benchmarkEncoder(b, digits, compress, 1e6) }
-func BenchmarkEncodeTwainSpeed1e4(b *testing.B)     { benchmarkEncoder(b, twain, speed, 1e4) }
-func BenchmarkEncodeTwainSpeed1e5(b *testing.B)     { benchmarkEncoder(b, twain, speed, 1e5) }
-func BenchmarkEncodeTwainSpeed1e6(b *testing.B)     { benchmarkEncoder(b, twain, speed, 1e6) }
-func BenchmarkEncodeTwainDefault1e4(b *testing.B)   { benchmarkEncoder(b, twain, default_, 1e4) }
-func BenchmarkEncodeTwainDefault1e5(b *testing.B)   { benchmarkEncoder(b, twain, default_, 1e5) }
-func BenchmarkEncodeTwainDefault1e6(b *testing.B)   { benchmarkEncoder(b, twain, default_, 1e6) }
-func BenchmarkEncodeTwainCompress1e4(b *testing.B)  { benchmarkEncoder(b, twain, compress, 1e4) }
-func BenchmarkEncodeTwainCompress1e5(b *testing.B)  { benchmarkEncoder(b, twain, compress, 1e5) }
-func BenchmarkEncodeTwainCompress1e6(b *testing.B)  { benchmarkEncoder(b, twain, compress, 1e6) }
+// Test if errors from the underlying writer is passed upwards.
+func TestWriteError(t *testing.T) {
+	buf := new(bytes.Buffer)
+	n := 65536
+	if !testing.Short() {
+		n *= 4
+	}
+	for i := 0; i < n; i++ {
+		fmt.Fprintf(buf, "asdasfasf%d%dfghfgujyut%dyutyu\n", i, i, i)
+	}
+	in := buf.Bytes()
+	// We create our own buffer to control number of writes.
+	copyBuffer := make([]byte, 128)
+	for l := 0; l < 10; l++ {
+		for fail := 1; fail <= 256; fail *= 2 {
+			// Fail after 'fail' writes
+			ew := &errorWriter{N: fail}
+			w, err := NewWriter(ew, l)
+			if err != nil {
+				t.Fatalf("NewWriter: level %d: %v", l, err)
+			}
+			n, err := io.CopyBuffer(w, bytes.NewBuffer(in), copyBuffer)
+			if err == nil {
+				t.Fatalf("Level %d: Expected an error, writer was %#v", l, ew)
+			}
+			n2, err := w.Write([]byte{1, 2, 2, 3, 4, 5})
+			if n2 != 0 {
+				t.Fatal("Level", l, "Expected 0 length write, got", n)
+			}
+			if err == nil {
+				t.Fatal("Level", l, "Expected an error")
+			}
+			err = w.Flush()
+			if err == nil {
+				t.Fatal("Level", l, "Expected an error on flush")
+			}
+			err = w.Close()
+			if err == nil {
+				t.Fatal("Level", l, "Expected an error on close")
+			}
+
+			w.Reset(ioutil.Discard)
+			n2, err = w.Write([]byte{1, 2, 3, 4, 5, 6})
+			if err != nil {
+				t.Fatal("Level", l, "Got unexpected error after reset:", err)
+			}
+			if n2 == 0 {
+				t.Fatal("Level", l, "Got 0 length write, expected > 0")
+			}
+			if testing.Short() {
+				return
+			}
+		}
+	}
+}
+
+// Test if two runs produce identical results
+// even when writing different sizes to the Writer.
+func TestDeterministic(t *testing.T) {
+	for i := 0; i <= 9; i++ {
+		t.Run(fmt.Sprint("L", i), func(t *testing.T) { testDeterministic(i, t) })
+	}
+	t.Run("LM2", func(t *testing.T) { testDeterministic(-2, t) })
+}
+
+func testDeterministic(i int, t *testing.T) {
+	// Test so much we cross a good number of block boundaries.
+	var length = maxStoreBlockSize*30 + 500
+	if testing.Short() {
+		length /= 10
+	}
+
+	// Create a random, but compressible stream.
+	rng := rand.New(rand.NewSource(1))
+	t1 := make([]byte, length)
+	for i := range t1 {
+		t1[i] = byte(rng.Int63() & 7)
+	}
+
+	// Do our first encode.
+	var b1 bytes.Buffer
+	br := bytes.NewBuffer(t1)
+	w, err := NewWriter(&b1, i)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// Use a very small prime sized buffer.
+	cbuf := make([]byte, 787)
+	_, err = io.CopyBuffer(w, br, cbuf)
+	if err != nil {
+		t.Fatal(err)
+	}
+	w.Close()
+
+	// We choose a different buffer size,
+	// bigger than a maximum block, and also a prime.
+	var b2 bytes.Buffer
+	cbuf = make([]byte, 81761)
+	br2 := bytes.NewBuffer(t1)
+	w2, err := NewWriter(&b2, i)
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = io.CopyBuffer(w2, br2, cbuf)
+	if err != nil {
+		t.Fatal(err)
+	}
+	w2.Close()
+
+	b1b := b1.Bytes()
+	b2b := b2.Bytes()
+
+	if !bytes.Equal(b1b, b2b) {
+		t.Errorf("level %d did not produce deterministic result, result mismatch, len(a) = %d, len(b) = %d", i, len(b1b), len(b2b))
+	}
+}
diff --git a/src/compress/gzip/gunzip.go b/src/compress/gzip/gunzip.go
index 3d33145..7e64069 100644
--- a/src/compress/gzip/gunzip.go
+++ b/src/compress/gzip/gunzip.go
@@ -9,8 +9,8 @@ package gzip
 import (
 	"bufio"
 	"compress/flate"
+	"encoding/binary"
 	"errors"
-	"hash"
 	"hash/crc32"
 	"io"
 	"time"
@@ -27,13 +27,6 @@ const (
 	flagComment = 1 << 4
 )
 
-func makeReader(r io.Reader) flate.Reader {
-	if rr, ok := r.(flate.Reader); ok {
-		return rr
-	}
-	return bufio.NewReader(r)
-}
-
 var (
 	// ErrChecksum is returned when reading GZIP data that has an invalid checksum.
 	ErrChecksum = errors.New("gzip: invalid checksum")
@@ -41,6 +34,16 @@ var (
 	ErrHeader = errors.New("gzip: invalid header")
 )
 
+var le = binary.LittleEndian
+
+// noEOF converts io.EOF to io.ErrUnexpectedEOF.
+func noEOF(err error) error {
+	if err == io.EOF {
+		return io.ErrUnexpectedEOF
+	}
+	return err
+}
+
 // The gzip file stores a header giving metadata about the compressed file.
 // That header is exposed as the fields of the Writer and Reader structs.
 //
@@ -58,23 +61,22 @@ type Header struct {
 // uncompressed data from a gzip-format compressed file.
 //
 // In general, a gzip file can be a concatenation of gzip files,
-// each with its own header.  Reads from the Reader
+// each with its own header. Reads from the Reader
 // return the concatenation of the uncompressed data of each.
 // Only the first header is recorded in the Reader fields.
 //
 // Gzip files store a length and checksum of the uncompressed data.
 // The Reader will return a ErrChecksum when Read
 // reaches the end of the uncompressed data if it does not
-// have the expected length or checksum.  Clients should treat data
+// have the expected length or checksum. Clients should treat data
 // returned by Read as tentative until they receive the io.EOF
 // marking the end of the data.
 type Reader struct {
 	Header       // valid after NewReader or Reader.Reset
 	r            flate.Reader
 	decompressor io.ReadCloser
-	digest       hash.Hash32
-	size         uint32
-	flg          byte
+	digest       uint32 // CRC-32, IEEE polynomial (section 8)
+	size         uint32 // Uncompressed size (section 2.3.1)
 	buf          [512]byte
 	err          error
 	multistream  bool
@@ -89,10 +91,7 @@ type Reader struct {
 // The Reader.Header fields will be valid in the Reader returned.
 func NewReader(r io.Reader) (*Reader, error) {
 	z := new(Reader)
-	z.r = makeReader(r)
-	z.multistream = true
-	z.digest = crc32.NewIEEE()
-	if err := z.readHeader(true); err != nil {
+	if err := z.Reset(r); err != nil {
 		return nil, err
 	}
 	return z, nil
@@ -102,16 +101,17 @@ func NewReader(r io.Reader) (*Reader, error) {
 // result of its original state from NewReader, but reading from r instead.
 // This permits reusing a Reader rather than allocating a new one.
 func (z *Reader) Reset(r io.Reader) error {
-	z.r = makeReader(r)
-	if z.digest == nil {
-		z.digest = crc32.NewIEEE()
+	*z = Reader{
+		decompressor: z.decompressor,
+		multistream:  true,
+	}
+	if rr, ok := r.(flate.Reader); ok {
+		z.r = rr
 	} else {
-		z.digest.Reset()
+		z.r = bufio.NewReader(r)
 	}
-	z.size = 0
-	z.err = nil
-	z.multistream = true
-	return z.readHeader(true)
+	z.Header, z.err = z.readHeader()
+	return z.err
 }
 
 // Multistream controls whether the reader supports multistream files.
@@ -134,14 +134,13 @@ func (z *Reader) Multistream(ok bool) {
 	z.multistream = ok
 }
 
-// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
-func get4(p []byte) uint32 {
-	return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
-}
-
+// readString reads a NUL-terminated string from z.r.
+// It treats the bytes read as being encoded as ISO 8859-1 (Latin-1) and
+// will output a string encoded using UTF-8.
+// This method always updates z.digest with the data read.
 func (z *Reader) readString() (string, error) {
 	var err error
-	needconv := false
+	needConv := false
 	for i := 0; ; i++ {
 		if i >= len(z.buf) {
 			return "", ErrHeader
@@ -151,159 +150,138 @@ func (z *Reader) readString() (string, error) {
 			return "", err
 		}
 		if z.buf[i] > 0x7f {
-			needconv = true
+			needConv = true
 		}
 		if z.buf[i] == 0 {
-			// GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
-			if needconv {
+			// Digest covers the NUL terminator.
+			z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:i+1])
+
+			// Strings are ISO 8859-1, Latin-1 (RFC 1952, section 2.3.1).
+			if needConv {
 				s := make([]rune, 0, i)
-				for _, v := range z.buf[0:i] {
+				for _, v := range z.buf[:i] {
 					s = append(s, rune(v))
 				}
 				return string(s), nil
 			}
-			return string(z.buf[0:i]), nil
-		}
-	}
-}
-
-func (z *Reader) read2() (uint32, error) {
-	_, err := io.ReadFull(z.r, z.buf[0:2])
-	if err != nil {
-		if err == io.EOF {
-			err = io.ErrUnexpectedEOF
+			return string(z.buf[:i]), nil
 		}
-		return 0, err
 	}
-	return uint32(z.buf[0]) | uint32(z.buf[1])<<8, nil
 }
 
-func (z *Reader) readHeader(save bool) error {
-	_, err := io.ReadFull(z.r, z.buf[0:10])
-	if err != nil {
-		// RFC1952 section 2.2 says the following:
+// readHeader reads the GZIP header according to section 2.3.1.
+// This method does not set z.err.
+func (z *Reader) readHeader() (hdr Header, err error) {
+	if _, err = io.ReadFull(z.r, z.buf[:10]); err != nil {
+		// RFC 1952, section 2.2, says the following:
 		//	A gzip file consists of a series of "members" (compressed data sets).
 		//
 		// Other than this, the specification does not clarify whether a
 		// "series" is defined as "one or more" or "zero or more". To err on the
 		// side of caution, Go interprets this to mean "zero or more".
 		// Thus, it is okay to return io.EOF here.
-		return err
+		return hdr, err
 	}
 	if z.buf[0] != gzipID1 || z.buf[1] != gzipID2 || z.buf[2] != gzipDeflate {
-		return ErrHeader
-	}
-	z.flg = z.buf[3]
-	if save {
-		z.ModTime = time.Unix(int64(get4(z.buf[4:8])), 0)
-		// z.buf[8] is xfl, ignored
-		z.OS = z.buf[9]
+		return hdr, ErrHeader
 	}
-	z.digest.Reset()
-	z.digest.Write(z.buf[0:10])
+	flg := z.buf[3]
+	hdr.ModTime = time.Unix(int64(le.Uint32(z.buf[4:8])), 0)
+	// z.buf[8] is XFL and is currently ignored.
+	hdr.OS = z.buf[9]
+	z.digest = crc32.ChecksumIEEE(z.buf[:10])
 
-	if z.flg&flagExtra != 0 {
-		n, err := z.read2()
-		if err != nil {
-			return err
+	if flg&flagExtra != 0 {
+		if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil {
+			return hdr, noEOF(err)
 		}
-		data := make([]byte, n)
+		z.digest = crc32.Update(z.digest, crc32.IEEETable, z.buf[:2])
+		data := make([]byte, le.Uint16(z.buf[:2]))
 		if _, err = io.ReadFull(z.r, data); err != nil {
-			if err == io.EOF {
-				err = io.ErrUnexpectedEOF
-			}
-			return err
-		}
-		if save {
-			z.Extra = data
+			return hdr, noEOF(err)
 		}
+		z.digest = crc32.Update(z.digest, crc32.IEEETable, data)
+		hdr.Extra = data
 	}
 
 	var s string
-	if z.flg&flagName != 0 {
+	if flg&flagName != 0 {
 		if s, err = z.readString(); err != nil {
-			return err
-		}
-		if save {
-			z.Name = s
+			return hdr, err
 		}
+		hdr.Name = s
 	}
 
-	if z.flg&flagComment != 0 {
+	if flg&flagComment != 0 {
 		if s, err = z.readString(); err != nil {
-			return err
-		}
-		if save {
-			z.Comment = s
+			return hdr, err
 		}
+		hdr.Comment = s
 	}
 
-	if z.flg&flagHdrCrc != 0 {
-		n, err := z.read2()
-		if err != nil {
-			return err
+	if flg&flagHdrCrc != 0 {
+		if _, err = io.ReadFull(z.r, z.buf[:2]); err != nil {
+			return hdr, noEOF(err)
 		}
-		sum := z.digest.Sum32() & 0xFFFF
-		if n != sum {
-			return ErrHeader
+		digest := le.Uint16(z.buf[:2])
+		if digest != uint16(z.digest) {
+			return hdr, ErrHeader
 		}
 	}
 
-	z.digest.Reset()
+	z.digest = 0
 	if z.decompressor == nil {
 		z.decompressor = flate.NewReader(z.r)
 	} else {
 		z.decompressor.(flate.Resetter).Reset(z.r, nil)
 	}
-	return nil
+	return hdr, nil
 }
 
 func (z *Reader) Read(p []byte) (n int, err error) {
 	if z.err != nil {
 		return 0, z.err
 	}
-	if len(p) == 0 {
-		return 0, nil
-	}
 
-	n, err = z.decompressor.Read(p)
-	z.digest.Write(p[0:n])
+	n, z.err = z.decompressor.Read(p)
+	z.digest = crc32.Update(z.digest, crc32.IEEETable, p[:n])
 	z.size += uint32(n)
-	if n != 0 || err != io.EOF {
-		z.err = err
-		return
+	if z.err != io.EOF {
+		// In the normal case we return here.
+		return n, z.err
 	}
 
-	// Finished file; check checksum + size.
-	if _, err := io.ReadFull(z.r, z.buf[0:8]); err != nil {
-		if err == io.EOF {
-			err = io.ErrUnexpectedEOF
-		}
-		z.err = err
-		return 0, err
+	// Finished file; check checksum and size.
+	if _, err := io.ReadFull(z.r, z.buf[:8]); err != nil {
+		z.err = noEOF(err)
+		return n, z.err
 	}
-	crc32, isize := get4(z.buf[0:4]), get4(z.buf[4:8])
-	sum := z.digest.Sum32()
-	if sum != crc32 || isize != z.size {
+	digest := le.Uint32(z.buf[:4])
+	size := le.Uint32(z.buf[4:8])
+	if digest != z.digest || size != z.size {
 		z.err = ErrChecksum
-		return 0, z.err
+		return n, z.err
 	}
+	z.digest, z.size = 0, 0
 
-	// File is ok; is there another?
+	// File is ok; check if there is another.
 	if !z.multistream {
-		return 0, io.EOF
+		return n, io.EOF
 	}
+	z.err = nil // Remove io.EOF
 
-	if err = z.readHeader(false); err != nil {
-		z.err = err
-		return
+	if _, z.err = z.readHeader(); z.err != nil {
+		return n, z.err
 	}
 
-	// Yes.  Reset and read from it.
-	z.digest.Reset()
-	z.size = 0
+	// Read from next file, if necessary.
+	if n > 0 {
+		return n, nil
+	}
 	return z.Read(p)
 }
 
 // Close closes the Reader. It does not close the underlying io.Reader.
+// In order for the GZIP checksum to be verified, the reader must be
+// fully consumed until the io.EOF.
 func (z *Reader) Close() error { return z.decompressor.Close() }
diff --git a/src/compress/gzip/gunzip_test.go b/src/compress/gzip/gunzip_test.go
index 007d958..fdce919 100644
--- a/src/compress/gzip/gunzip_test.go
+++ b/src/compress/gzip/gunzip_test.go
@@ -36,6 +36,17 @@ var gunzipTests = []gunzipTest{
 		},
 		nil,
 	},
+	{
+		"",
+		"empty - with no file name",
+		"",
+		[]byte{
+			0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88,
+			0x00, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		},
+		nil,
+	},
 	{ // has 1 non-empty fixed huffman block
 		"hello.txt",
 		"hello.txt",
@@ -281,49 +292,102 @@ var gunzipTests = []gunzipTest{
 		},
 		ErrChecksum,
 	},
+	{
+		"f1l3n4m3.tXt",
+		"header with all fields used",
+		"",
+		[]byte{
+			0x1f, 0x8b, 0x08, 0x1e, 0x70, 0xf0, 0xf9, 0x4a,
+			0x00, 0xaa, 0x09, 0x00, 0x7a, 0x7a, 0x05, 0x00,
+			0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x31, 0x6c,
+			0x33, 0x6e, 0x34, 0x6d, 0x33, 0x2e, 0x74, 0x58,
+			0x74, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+			0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+			0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+			0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
+			0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
+			0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
+			0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
+			0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+			0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
+			0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
+			0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
+			0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+			0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
+			0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+			0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76,
+			0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e,
+			0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86,
+			0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e,
+			0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+			0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
+			0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
+			0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae,
+			0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+			0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe,
+			0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6,
+			0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce,
+			0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+			0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde,
+			0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
+			0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee,
+			0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
+			0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe,
+			0xff, 0x00, 0x92, 0xfd, 0x01, 0x00, 0x00, 0xff,
+			0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+			0x00,
+		},
+		nil,
+	},
 }
 
 func TestDecompressor(t *testing.T) {
+	// Keep resetting this reader.
+	// It is intended behavior that Reader.Reset can be called on a zero-value
+	// Reader and be the equivalent as if NewReader was used instead.
+	r1 := new(Reader)
+
 	b := new(bytes.Buffer)
 	for _, tt := range gunzipTests {
+		// Test NewReader.
 		in := bytes.NewReader(tt.gzip)
-		gzip, err := NewReader(in)
+		r2, err := NewReader(in)
 		if err != nil {
-			t.Errorf("%s: NewReader: %s", tt.name, err)
+			t.Errorf("%s: NewReader: %s", tt.desc, err)
 			continue
 		}
-		defer gzip.Close()
-		if tt.name != gzip.Name {
-			t.Errorf("%s: got name %s", tt.name, gzip.Name)
+		defer r2.Close()
+		if tt.name != r2.Name {
+			t.Errorf("%s: got name %s", tt.desc, r2.Name)
 		}
 		b.Reset()
-		n, err := io.Copy(b, gzip)
+		n, err := io.Copy(b, r2)
 		if err != tt.err {
-			t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+			t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
 		}
 		s := b.String()
 		if s != tt.raw {
-			t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+			t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
 		}
 
-		// Test Reader Reset.
+		// Test Reader.Reset.
 		in = bytes.NewReader(tt.gzip)
-		err = gzip.Reset(in)
+		err = r1.Reset(in)
 		if err != nil {
-			t.Errorf("%s: Reset: %s", tt.name, err)
+			t.Errorf("%s: Reset: %s", tt.desc, err)
 			continue
 		}
-		if tt.name != gzip.Name {
-			t.Errorf("%s: got name %s", tt.name, gzip.Name)
+		if tt.name != r1.Name {
+			t.Errorf("%s: got name %s", tt.desc, r1.Name)
 		}
 		b.Reset()
-		n, err = io.Copy(b, gzip)
+		n, err = io.Copy(b, r1)
 		if err != tt.err {
-			t.Errorf("%s: io.Copy: %v want %v", tt.name, err, tt.err)
+			t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
 		}
 		s = b.String()
 		if s != tt.raw {
-			t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.name, n, s, len(tt.raw), tt.raw)
+			t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
 		}
 	}
 }
@@ -356,20 +420,6 @@ func TestIssue6550(t *testing.T) {
 	}
 }
 
-func TestInitialReset(t *testing.T) {
-	var r Reader
-	if err := r.Reset(bytes.NewReader(gunzipTests[1].gzip)); err != nil {
-		t.Error(err)
-	}
-	var buf bytes.Buffer
-	if _, err := io.Copy(&buf, &r); err != nil {
-		t.Error(err)
-	}
-	if s := buf.String(); s != gunzipTests[1].raw {
-		t.Errorf("got %q want %q", s, gunzipTests[1].raw)
-	}
-}
-
 func TestMultistreamFalse(t *testing.T) {
 	// Find concatenation test.
 	var tt gunzipTest
@@ -411,7 +461,7 @@ Found:
 }
 
 func TestNilStream(t *testing.T) {
-	// Go liberally interprets RFC1952 section 2.2 to mean that a gzip file
+	// Go liberally interprets RFC 1952 section 2.2 to mean that a gzip file
 	// consist of zero or more members. Thus, we test that a nil stream is okay.
 	_, err := NewReader(bytes.NewReader(nil))
 	if err != io.EOF {
diff --git a/src/compress/gzip/gzip.go b/src/compress/gzip/gzip.go
index 4d945e4..c702c49 100644
--- a/src/compress/gzip/gzip.go
+++ b/src/compress/gzip/gzip.go
@@ -8,7 +8,6 @@ import (
 	"compress/flate"
 	"errors"
 	"fmt"
-	"hash"
 	"hash/crc32"
 	"io"
 )
@@ -30,8 +29,8 @@ type Writer struct {
 	level       int
 	wroteHeader bool
 	compressor  *flate.Writer
-	digest      hash.Hash32
-	size        uint32
+	digest      uint32 // CRC-32, IEEE polynomial (section 8)
+	size        uint32 // Uncompressed size (section 2.3.1)
 	closed      bool
 	buf         [10]byte
 	err         error
@@ -66,12 +65,6 @@ func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
 }
 
 func (z *Writer) init(w io.Writer, level int) {
-	digest := z.digest
-	if digest != nil {
-		digest.Reset()
-	} else {
-		digest = crc32.NewIEEE()
-	}
 	compressor := z.compressor
 	if compressor != nil {
 		compressor.Reset(w)
@@ -82,7 +75,6 @@ func (z *Writer) init(w io.Writer, level int) {
 		},
 		w:          w,
 		level:      level,
-		digest:     digest,
 		compressor: compressor,
 	}
 }
@@ -95,26 +87,13 @@ func (z *Writer) Reset(w io.Writer) {
 	z.init(w, z.level)
 }
 
-// GZIP (RFC 1952) is little-endian, unlike ZLIB (RFC 1950).
-func put2(p []byte, v uint16) {
-	p[0] = uint8(v >> 0)
-	p[1] = uint8(v >> 8)
-}
-
-func put4(p []byte, v uint32) {
-	p[0] = uint8(v >> 0)
-	p[1] = uint8(v >> 8)
-	p[2] = uint8(v >> 16)
-	p[3] = uint8(v >> 24)
-}
-
 // writeBytes writes a length-prefixed byte slice to z.w.
 func (z *Writer) writeBytes(b []byte) error {
 	if len(b) > 0xffff {
 		return errors.New("gzip.Write: Extra data is too large")
 	}
-	put2(z.buf[0:2], uint16(len(b)))
-	_, err := z.w.Write(z.buf[0:2])
+	le.PutUint16(z.buf[:2], uint16(len(b)))
+	_, err := z.w.Write(z.buf[:2])
 	if err != nil {
 		return err
 	}
@@ -149,7 +128,7 @@ func (z *Writer) writeString(s string) (err error) {
 	}
 	// GZIP strings are NUL-terminated.
 	z.buf[0] = 0
-	_, err = z.w.Write(z.buf[0:1])
+	_, err = z.w.Write(z.buf[:1])
 	return err
 }
 
@@ -176,7 +155,7 @@ func (z *Writer) Write(p []byte) (int, error) {
 		if z.Comment != "" {
 			z.buf[3] |= 0x10
 		}
-		put4(z.buf[4:8], uint32(z.ModTime.Unix()))
+		le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix()))
 		if z.level == BestCompression {
 			z.buf[8] = 2
 		} else if z.level == BestSpeed {
@@ -185,7 +164,7 @@ func (z *Writer) Write(p []byte) (int, error) {
 			z.buf[8] = 0
 		}
 		z.buf[9] = z.OS
-		n, z.err = z.w.Write(z.buf[0:10])
+		n, z.err = z.w.Write(z.buf[:10])
 		if z.err != nil {
 			return n, z.err
 		}
@@ -212,7 +191,7 @@ func (z *Writer) Write(p []byte) (int, error) {
 		}
 	}
 	z.size += uint32(len(p))
-	z.digest.Write(p)
+	z.digest = crc32.Update(z.digest, crc32.IEEETable, p)
 	n, z.err = z.compressor.Write(p)
 	return n, z.err
 }
@@ -262,8 +241,8 @@ func (z *Writer) Close() error {
 	if z.err != nil {
 		return z.err
 	}
-	put4(z.buf[0:4], z.digest.Sum32())
-	put4(z.buf[4:8], z.size)
-	_, z.err = z.w.Write(z.buf[0:8])
+	le.PutUint32(z.buf[:4], z.digest)
+	le.PutUint32(z.buf[4:8], z.size)
+	_, z.err = z.w.Write(z.buf[:8])
 	return z.err
 }
diff --git a/src/compress/gzip/issue14937_test.go b/src/compress/gzip/issue14937_test.go
new file mode 100644
index 0000000..432ad16
--- /dev/null
+++ b/src/compress/gzip/issue14937_test.go
@@ -0,0 +1,59 @@
+package gzip
+
+import (
+	"internal/testenv"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+	"time"
+)
+
+// Per golang.org/issue/14937, check that every .gz file
+// in the tree has a zero mtime.
+func TestGZIPFilesHaveZeroMTimes(t *testing.T) {
+	if testing.Short() && testenv.Builder() == "" {
+		t.Skip("skipping in short mode")
+	}
+	var files []string
+	err := filepath.Walk(runtime.GOROOT(), func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		if !info.IsDir() && strings.HasSuffix(path, ".gz") {
+			files = append(files, path)
+		}
+		return nil
+	})
+	if err != nil {
+		if os.IsNotExist(err) {
+			t.Skipf("skipping: GOROOT directory not found: %s", runtime.GOROOT())
+		}
+		t.Fatal("error collecting list of .gz files in GOROOT: ", err)
+	}
+	if len(files) == 0 {
+		t.Fatal("expected to find some .gz files under GOROOT")
+	}
+	for _, path := range files {
+		checkZeroMTime(t, path)
+	}
+}
+
+func checkZeroMTime(t *testing.T, path string) {
+	f, err := os.Open(path)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	defer f.Close()
+	gz, err := NewReader(f)
+	if err != nil {
+		t.Errorf("cannot read gzip file %s: %s", path, err)
+		return
+	}
+	defer gz.Close()
+	if !gz.ModTime.Equal(time.Unix(0, 0)) {
+		t.Errorf("gzip file %s has non-zero mtime (%s)", path, gz.ModTime)
+	}
+}
diff --git a/src/compress/gzip/testdata/issue6550.gz b/src/compress/gzip/testdata/issue6550.gz
index 57972b6..82b4af1 100644
Binary files a/src/compress/gzip/testdata/issue6550.gz and b/src/compress/gzip/testdata/issue6550.gz differ
diff --git a/src/compress/lzw/reader_test.go b/src/compress/lzw/reader_test.go
index c3a5c3a..6b9f9a3 100644
--- a/src/compress/lzw/reader_test.go
+++ b/src/compress/lzw/reader_test.go
@@ -6,8 +6,10 @@ package lzw
 
 import (
 	"bytes"
+	"fmt"
 	"io"
 	"io/ioutil"
+	"math"
 	"runtime"
 	"strconv"
 	"strings"
@@ -118,42 +120,37 @@ func TestReader(t *testing.T) {
 	}
 }
 
-func benchmarkDecoder(b *testing.B, n int) {
-	b.StopTimer()
-	b.SetBytes(int64(n))
-	buf0, err := ioutil.ReadFile("../testdata/e.txt")
+func BenchmarkDecoder(b *testing.B) {
+	buf, err := ioutil.ReadFile("../testdata/e.txt")
 	if err != nil {
 		b.Fatal(err)
 	}
-	if len(buf0) == 0 {
+	if len(buf) == 0 {
 		b.Fatalf("test file has no data")
 	}
-	compressed := new(bytes.Buffer)
-	w := NewWriter(compressed, LSB, 8)
-	for i := 0; i < n; i += len(buf0) {
-		if len(buf0) > n-i {
-			buf0 = buf0[:n-i]
-		}
-		w.Write(buf0)
-	}
-	w.Close()
-	buf1 := compressed.Bytes()
-	buf0, compressed, w = nil, nil, nil
-	runtime.GC()
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
-	}
-}
-
-func BenchmarkDecoder1e4(b *testing.B) {
-	benchmarkDecoder(b, 1e4)
-}
 
-func BenchmarkDecoder1e5(b *testing.B) {
-	benchmarkDecoder(b, 1e5)
-}
-
-func BenchmarkDecoder1e6(b *testing.B) {
-	benchmarkDecoder(b, 1e6)
+	for e := 4; e <= 6; e++ {
+		n := int(math.Pow10(e))
+		b.Run(fmt.Sprint("1e", e), func(b *testing.B) {
+			b.StopTimer()
+			b.SetBytes(int64(n))
+			buf0 := buf
+			compressed := new(bytes.Buffer)
+			w := NewWriter(compressed, LSB, 8)
+			for i := 0; i < n; i += len(buf0) {
+				if len(buf0) > n-i {
+					buf0 = buf0[:n-i]
+				}
+				w.Write(buf0)
+			}
+			w.Close()
+			buf1 := compressed.Bytes()
+			buf0, compressed, w = nil, nil, nil
+			runtime.GC()
+			b.StartTimer()
+			for i := 0; i < b.N; i++ {
+				io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8))
+			}
+		})
+	}
 }
diff --git a/src/compress/lzw/writer.go b/src/compress/lzw/writer.go
index 7367c29..6ddb335 100644
--- a/src/compress/lzw/writer.go
+++ b/src/compress/lzw/writer.go
@@ -119,7 +119,7 @@ func (e *encoder) incHi() error {
 		if err := e.write(e, clear); err != nil {
 			return err
 		}
-		e.width = uint(e.litWidth) + 1
+		e.width = e.litWidth + 1
 		e.hi = clear + 1
 		e.overflow = clear << 1
 		for i := range e.table {
diff --git a/src/compress/lzw/writer_test.go b/src/compress/lzw/writer_test.go
index 66d7617..4979f8b 100644
--- a/src/compress/lzw/writer_test.go
+++ b/src/compress/lzw/writer_test.go
@@ -5,9 +5,11 @@
 package lzw
 
 import (
+	"fmt"
 	"internal/testenv"
 	"io"
 	"io/ioutil"
+	"math"
 	"os"
 	"runtime"
 	"testing"
@@ -122,41 +124,34 @@ func TestSmallLitWidth(t *testing.T) {
 	}
 }
 
-func benchmarkEncoder(b *testing.B, n int) {
-	b.StopTimer()
-	b.SetBytes(int64(n))
-	buf0, err := ioutil.ReadFile("../testdata/e.txt")
+func BenchmarkEncoder(b *testing.B) {
+	buf, err := ioutil.ReadFile("../testdata/e.txt")
 	if err != nil {
 		b.Fatal(err)
 	}
-	if len(buf0) == 0 {
+	if len(buf) == 0 {
 		b.Fatalf("test file has no data")
 	}
-	buf1 := make([]byte, n)
-	for i := 0; i < n; i += len(buf0) {
-		if len(buf0) > n-i {
-			buf0 = buf0[:n-i]
+
+	for e := 4; e <= 6; e++ {
+		n := int(math.Pow10(e))
+		buf0 := buf
+		buf1 := make([]byte, n)
+		for i := 0; i < n; i += len(buf0) {
+			if len(buf0) > n-i {
+				buf0 = buf0[:n-i]
+			}
+			copy(buf1[i:], buf0)
 		}
-		copy(buf1[i:], buf0)
-	}
-	buf0 = nil
-	runtime.GC()
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		w := NewWriter(ioutil.Discard, LSB, 8)
-		w.Write(buf1)
-		w.Close()
+		buf0 = nil
+		runtime.GC()
+		b.Run(fmt.Sprint("1e", e), func(b *testing.B) {
+			b.SetBytes(int64(n))
+			for i := 0; i < b.N; i++ {
+				w := NewWriter(ioutil.Discard, LSB, 8)
+				w.Write(buf1)
+				w.Close()
+			}
+		})
 	}
 }
-
-func BenchmarkEncoder1e4(b *testing.B) {
-	benchmarkEncoder(b, 1e4)
-}
-
-func BenchmarkEncoder1e5(b *testing.B) {
-	benchmarkEncoder(b, 1e5)
-}
-
-func BenchmarkEncoder1e6(b *testing.B) {
-	benchmarkEncoder(b, 1e6)
-}
diff --git a/src/compress/zlib/reader.go b/src/compress/zlib/reader.go
index 78ea704..2efa193 100644
--- a/src/compress/zlib/reader.go
+++ b/src/compress/zlib/reader.go
@@ -62,7 +62,8 @@ type Resetter interface {
 
 // NewReader creates a new ReadCloser.
 // Reads from the returned ReadCloser read and decompress data from r.
-// The implementation buffers input and may read more data than necessary from r.
+// If r does not implement io.ByteReader, the decompressor may read more
+// data than necessary from r.
 // It is the caller's responsibility to call Close on the ReadCloser when done.
 //
 // The ReadCloser returned by NewReader also implements Resetter.
@@ -84,19 +85,17 @@ func NewReaderDict(r io.Reader, dict []byte) (io.ReadCloser, error) {
 	return z, nil
 }
 
-func (z *reader) Read(p []byte) (n int, err error) {
+func (z *reader) Read(p []byte) (int, error) {
 	if z.err != nil {
 		return 0, z.err
 	}
-	if len(p) == 0 {
-		return 0, nil
-	}
 
-	n, err = z.decompressor.Read(p)
+	var n int
+	n, z.err = z.decompressor.Read(p)
 	z.digest.Write(p[0:n])
-	if n != 0 || err != io.EOF {
-		z.err = err
-		return
+	if z.err != io.EOF {
+		// In the normal case we return here.
+		return n, z.err
 	}
 
 	// Finished file; check checksum.
@@ -105,20 +104,22 @@ func (z *reader) Read(p []byte) (n int, err error) {
 			err = io.ErrUnexpectedEOF
 		}
 		z.err = err
-		return 0, err
+		return n, z.err
 	}
 	// ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
 	checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
 	if checksum != z.digest.Sum32() {
 		z.err = ErrChecksum
-		return 0, z.err
+		return n, z.err
 	}
-	return
+	return n, io.EOF
 }
 
 // Calling Close does not close the wrapped io.Reader originally passed to NewReader.
+// In order for the ZLIB checksum to be verified, the reader must be
+// fully consumed until the io.EOF.
 func (z *reader) Close() error {
-	if z.err != nil {
+	if z.err != nil && z.err != io.EOF {
 		return z.err
 	}
 	z.err = z.decompressor.Close()
@@ -126,36 +127,42 @@ func (z *reader) Close() error {
 }
 
 func (z *reader) Reset(r io.Reader, dict []byte) error {
+	*z = reader{decompressor: z.decompressor}
 	if fr, ok := r.(flate.Reader); ok {
 		z.r = fr
 	} else {
 		z.r = bufio.NewReader(r)
 	}
-	_, err := io.ReadFull(z.r, z.scratch[0:2])
-	if err != nil {
-		if err == io.EOF {
-			err = io.ErrUnexpectedEOF
+
+	// Read the header (RFC 1950 section 2.2.).
+	_, z.err = io.ReadFull(z.r, z.scratch[0:2])
+	if z.err != nil {
+		if z.err == io.EOF {
+			z.err = io.ErrUnexpectedEOF
 		}
-		return err
+		return z.err
 	}
 	h := uint(z.scratch[0])<<8 | uint(z.scratch[1])
 	if (z.scratch[0]&0x0f != zlibDeflate) || (h%31 != 0) {
-		return ErrHeader
+		z.err = ErrHeader
+		return z.err
 	}
 	haveDict := z.scratch[1]&0x20 != 0
 	if haveDict {
-		_, err = io.ReadFull(z.r, z.scratch[0:4])
-		if err != nil {
-			if err == io.EOF {
-				err = io.ErrUnexpectedEOF
+		_, z.err = io.ReadFull(z.r, z.scratch[0:4])
+		if z.err != nil {
+			if z.err == io.EOF {
+				z.err = io.ErrUnexpectedEOF
 			}
-			return err
+			return z.err
 		}
 		checksum := uint32(z.scratch[0])<<24 | uint32(z.scratch[1])<<16 | uint32(z.scratch[2])<<8 | uint32(z.scratch[3])
 		if checksum != adler32.Checksum(dict) {
-			return ErrDictionary
+			z.err = ErrDictionary
+			return z.err
 		}
 	}
+
 	if z.decompressor == nil {
 		if haveDict {
 			z.decompressor = flate.NewReaderDict(z.r, dict)
diff --git a/src/compress/zlib/reader_test.go b/src/compress/zlib/reader_test.go
index 449f446..f74bff1 100644
--- a/src/compress/zlib/reader_test.go
+++ b/src/compress/zlib/reader_test.go
@@ -127,16 +127,18 @@ func TestDecompressor(t *testing.T) {
 	b := new(bytes.Buffer)
 	for _, tt := range zlibTests {
 		in := bytes.NewReader(tt.compressed)
-		zlib, err := NewReaderDict(in, tt.dict)
+		zr, err := NewReaderDict(in, tt.dict)
 		if err != nil {
 			if err != tt.err {
 				t.Errorf("%s: NewReader: %s", tt.desc, err)
 			}
 			continue
 		}
-		defer zlib.Close()
+		defer zr.Close()
+
+		// Read and verify correctness of data.
 		b.Reset()
-		n, err := io.Copy(b, zlib)
+		n, err := io.Copy(b, zr)
 		if err != nil {
 			if err != tt.err {
 				t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
@@ -147,5 +149,13 @@ func TestDecompressor(t *testing.T) {
 		if s != tt.raw {
 			t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
 		}
+
+		// Check for sticky errors.
+		if n, err := zr.Read([]byte{0}); n != 0 || err != io.EOF {
+			t.Errorf("%s: Read() = (%d, %v), want (0, io.EOF)", tt.desc, n, err)
+		}
+		if err := zr.Close(); err != nil {
+			t.Errorf("%s: Close() = %v, want nil", tt.desc, err)
+		}
 	}
 }
diff --git a/src/container/heap/heap.go b/src/container/heap/heap.go
index c467a11..5fe23b9 100644
--- a/src/container/heap/heap.go
+++ b/src/container/heap/heap.go
@@ -25,7 +25,7 @@ import "sort"
 //	!h.Less(j, i) for 0 <= i < h.Len() and 2*i+1 <= j <= 2*i+2 and j < h.Len()
 //
 // Note that Push and Pop in this interface are for package heap's
-// implementation to call.  To add and remove things from the heap,
+// implementation to call. To add and remove things from the heap,
 // use heap.Push and heap.Pop.
 type Interface interface {
 	sort.Interface
diff --git a/src/container/heap/heap_test.go b/src/container/heap/heap_test.go
index b3d054c..d411104 100644
--- a/src/container/heap/heap_test.go
+++ b/src/container/heap/heap_test.go
@@ -173,7 +173,7 @@ func TestRemove2(t *testing.T) {
 
 func BenchmarkDup(b *testing.B) {
 	const n = 10000
-	h := make(myHeap, n)
+	h := make(myHeap, 0, n)
 	for i := 0; i < b.N; i++ {
 		for j := 0; j < n; j++ {
 			Push(&h, 0) // all elements are the same
diff --git a/src/container/list/list_test.go b/src/container/list/list_test.go
index 4d8bfc2..e3bfe53 100644
--- a/src/container/list/list_test.go
+++ b/src/container/list/list_test.go
@@ -326,7 +326,7 @@ func TestInsertAfterUnknownMark(t *testing.T) {
 }
 
 // Test that a list l is not modified when calling MoveAfter or MoveBefore with a mark that is not an element of l.
-func TestMoveUnkownMark(t *testing.T) {
+func TestMoveUnknownMark(t *testing.T) {
 	var l1 List
 	e1 := l1.PushBack(1)
 
diff --git a/src/context/context.go b/src/context/context.go
new file mode 100644
index 0000000..f8ce9cc
--- /dev/null
+++ b/src/context/context.go
@@ -0,0 +1,473 @@
+// 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 context defines the Context type, which carries deadlines,
+// cancelation signals, and other request-scoped values across API boundaries
+// and between processes.
+//
+// Incoming requests to a server should create a Context, and outgoing
+// calls to servers should accept a Context. The chain of function
+// calls between them must propagate the Context, optionally replacing
+// it with a derived Context created using WithCancel, WithDeadline,
+// WithTimeout, or WithValue. When a Context is canceled, all
+// Contexts derived from it are also canceled.
+//
+// The WithCancel, WithDeadline, and WithTimeout functions take a
+// Context (the parent) and return a derived Context (the child) and a
+// CancelFunc. Calling the CancelFunc cancels the child and its
+// children, removes the parent's reference to the child, and stops
+// any associated timers. Failing to call the CancelFunc leaks the
+// child and its children until the parent is canceled or the timer
+// fires. The go vet tool checks that CancelFuncs are used on all
+// control-flow paths.
+//
+// Programs that use Contexts should follow these rules to keep interfaces
+// consistent across packages and enable static analysis tools to check context
+// propagation:
+//
+// Do not store Contexts inside a struct type; instead, pass a Context
+// explicitly to each function that needs it. The Context should be the first
+// parameter, typically named ctx:
+//
+// 	func DoSomething(ctx context.Context, arg Arg) error {
+// 		// ... use ctx ...
+// 	}
+//
+// Do not pass a nil Context, even if a function permits it. Pass context.TODO
+// if you are unsure about which Context to use.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+//
+// The same Context may be passed to functions running in different goroutines;
+// Contexts are safe for simultaneous use by multiple goroutines.
+//
+// See https://blog.golang.org/context for example code for a server that uses
+// Contexts.
+package context
+
+import (
+	"errors"
+	"fmt"
+	"reflect"
+	"sync"
+	"time"
+)
+
+// A Context carries a deadline, a cancelation signal, and other values across
+// API boundaries.
+//
+// Context's methods may be called by multiple goroutines simultaneously.
+type Context interface {
+	// Deadline returns the time when work done on behalf of this context
+	// should be canceled. Deadline returns ok==false when no deadline is
+	// set. Successive calls to Deadline return the same results.
+	Deadline() (deadline time.Time, ok bool)
+
+	// Done returns a channel that's closed when work done on behalf of this
+	// context should be canceled. Done may return nil if this context can
+	// never be canceled. Successive calls to Done return the same value.
+	//
+	// WithCancel arranges for Done to be closed when cancel is called;
+	// WithDeadline arranges for Done to be closed when the deadline
+	// expires; WithTimeout arranges for Done to be closed when the timeout
+	// elapses.
+	//
+	// Done is provided for use in select statements:
+	//
+	//  // Stream generates values with DoSomething and sends them to out
+	//  // until DoSomething returns an error or ctx.Done is closed.
+	//  func Stream(ctx context.Context, out chan<- Value) error {
+	//  	for {
+	//  		v, err := DoSomething(ctx)
+	//  		if err != nil {
+	//  			return err
+	//  		}
+	//  		select {
+	//  		case <-ctx.Done():
+	//  			return ctx.Err()
+	//  		case out <- v:
+	//  		}
+	//  	}
+	//  }
+	//
+	// See https://blog.golang.org/pipelines for more examples of how to use
+	// a Done channel for cancelation.
+	Done() <-chan struct{}
+
+	// Err returns a non-nil error value after Done is closed. Err returns
+	// Canceled if the context was canceled or DeadlineExceeded if the
+	// context's deadline passed. No other values for Err are defined.
+	// After Done is closed, successive calls to Err return the same value.
+	Err() error
+
+	// Value returns the value associated with this context for key, or nil
+	// if no value is associated with key. Successive calls to Value with
+	// the same key returns the same result.
+	//
+	// Use context values only for request-scoped data that transits
+	// processes and API boundaries, not for passing optional parameters to
+	// functions.
+	//
+	// A key identifies a specific value in a Context. Functions that wish
+	// to store values in Context typically allocate a key in a global
+	// variable then use that key as the argument to context.WithValue and
+	// Context.Value. A key can be any type that supports equality;
+	// packages should define keys as an unexported type to avoid
+	// collisions.
+	//
+	// Packages that define a Context key should provide type-safe accessors
+	// for the values stored using that key:
+	//
+	// 	// Package user defines a User type that's stored in Contexts.
+	// 	package user
+	//
+	// 	import "context"
+	//
+	// 	// User is the type of value stored in the Contexts.
+	// 	type User struct {...}
+	//
+	// 	// key is an unexported type for keys defined in this package.
+	// 	// This prevents collisions with keys defined in other packages.
+	// 	type key int
+	//
+	// 	// userKey is the key for user.User values in Contexts. It is
+	// 	// unexported; clients use user.NewContext and user.FromContext
+	// 	// instead of using this key directly.
+	// 	var userKey key = 0
+	//
+	// 	// NewContext returns a new Context that carries value u.
+	// 	func NewContext(ctx context.Context, u *User) context.Context {
+	// 		return context.WithValue(ctx, userKey, u)
+	// 	}
+	//
+	// 	// FromContext returns the User value stored in ctx, if any.
+	// 	func FromContext(ctx context.Context) (*User, bool) {
+	// 		u, ok := ctx.Value(userKey).(*User)
+	// 		return u, ok
+	// 	}
+	Value(key interface{}) interface{}
+}
+
+// Canceled is the error returned by Context.Err when the context is canceled.
+var Canceled = errors.New("context canceled")
+
+// DeadlineExceeded is the error returned by Context.Err when the context's
+// deadline passes.
+var DeadlineExceeded error = deadlineExceededError{}
+
+type deadlineExceededError struct{}
+
+func (deadlineExceededError) Error() string { return "context deadline exceeded" }
+
+func (deadlineExceededError) Timeout() bool { return true }
+
+// An emptyCtx is never canceled, has no values, and has no deadline. It is not
+// struct{}, since vars of this type must have distinct addresses.
+type emptyCtx int
+
+func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
+	return
+}
+
+func (*emptyCtx) Done() <-chan struct{} {
+	return nil
+}
+
+func (*emptyCtx) Err() error {
+	return nil
+}
+
+func (*emptyCtx) Value(key interface{}) interface{} {
+	return nil
+}
+
+func (e *emptyCtx) String() string {
+	switch e {
+	case background:
+		return "context.Background"
+	case todo:
+		return "context.TODO"
+	}
+	return "unknown empty Context"
+}
+
+var (
+	background = new(emptyCtx)
+	todo       = new(emptyCtx)
+)
+
+// Background returns a non-nil, empty Context. It is never canceled, has no
+// values, and has no deadline. It is typically used by the main function,
+// initialization, and tests, and as the top-level Context for incoming
+// requests.
+func Background() Context {
+	return background
+}
+
+// TODO returns a non-nil, empty Context. Code should use context.TODO when
+// it's unclear which Context to use or it is not yet available (because the
+// surrounding function has not yet been extended to accept a Context
+// parameter). TODO is recognized by static analysis tools that determine
+// whether Contexts are propagated correctly in a program.
+func TODO() Context {
+	return todo
+}
+
+// A CancelFunc tells an operation to abandon its work.
+// A CancelFunc does not wait for the work to stop.
+// After the first call, subsequent calls to a CancelFunc do nothing.
+type CancelFunc func()
+
+// WithCancel returns a copy of parent with a new Done channel. The returned
+// context's Done channel is closed when the returned cancel function is called
+// or when the parent context's Done channel is closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
+	c := newCancelCtx(parent)
+	propagateCancel(parent, &c)
+	return &c, func() { c.cancel(true, Canceled) }
+}
+
+// newCancelCtx returns an initialized cancelCtx.
+func newCancelCtx(parent Context) cancelCtx {
+	return cancelCtx{
+		Context: parent,
+		done:    make(chan struct{}),
+	}
+}
+
+// propagateCancel arranges for child to be canceled when parent is.
+func propagateCancel(parent Context, child canceler) {
+	if parent.Done() == nil {
+		return // parent is never canceled
+	}
+	if p, ok := parentCancelCtx(parent); ok {
+		p.mu.Lock()
+		if p.err != nil {
+			// parent has already been canceled
+			child.cancel(false, p.err)
+		} else {
+			if p.children == nil {
+				p.children = make(map[canceler]bool)
+			}
+			p.children[child] = true
+		}
+		p.mu.Unlock()
+	} else {
+		go func() {
+			select {
+			case <-parent.Done():
+				child.cancel(false, parent.Err())
+			case <-child.Done():
+			}
+		}()
+	}
+}
+
+// parentCancelCtx follows a chain of parent references until it finds a
+// *cancelCtx. This function understands how each of the concrete types in this
+// package represents its parent.
+func parentCancelCtx(parent Context) (*cancelCtx, bool) {
+	for {
+		switch c := parent.(type) {
+		case *cancelCtx:
+			return c, true
+		case *timerCtx:
+			return &c.cancelCtx, true
+		case *valueCtx:
+			parent = c.Context
+		default:
+			return nil, false
+		}
+	}
+}
+
+// removeChild removes a context from its parent.
+func removeChild(parent Context, child canceler) {
+	p, ok := parentCancelCtx(parent)
+	if !ok {
+		return
+	}
+	p.mu.Lock()
+	if p.children != nil {
+		delete(p.children, child)
+	}
+	p.mu.Unlock()
+}
+
+// A canceler is a context type that can be canceled directly. The
+// implementations are *cancelCtx and *timerCtx.
+type canceler interface {
+	cancel(removeFromParent bool, err error)
+	Done() <-chan struct{}
+}
+
+// A cancelCtx can be canceled. When canceled, it also cancels any children
+// that implement canceler.
+type cancelCtx struct {
+	Context
+
+	done chan struct{} // closed by the first cancel call.
+
+	mu       sync.Mutex
+	children map[canceler]bool // set to nil by the first cancel call
+	err      error             // set to non-nil by the first cancel call
+}
+
+func (c *cancelCtx) Done() <-chan struct{} {
+	return c.done
+}
+
+func (c *cancelCtx) Err() error {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	return c.err
+}
+
+func (c *cancelCtx) String() string {
+	return fmt.Sprintf("%v.WithCancel", c.Context)
+}
+
+// cancel closes c.done, cancels each of c's children, and, if
+// removeFromParent is true, removes c from its parent's children.
+func (c *cancelCtx) cancel(removeFromParent bool, err error) {
+	if err == nil {
+		panic("context: internal error: missing cancel error")
+	}
+	c.mu.Lock()
+	if c.err != nil {
+		c.mu.Unlock()
+		return // already canceled
+	}
+	c.err = err
+	close(c.done)
+	for child := range c.children {
+		// NOTE: acquiring the child's lock while holding parent's lock.
+		child.cancel(false, err)
+	}
+	c.children = nil
+	c.mu.Unlock()
+
+	if removeFromParent {
+		removeChild(c.Context, c)
+	}
+}
+
+// WithDeadline returns a copy of the parent context with the deadline adjusted
+// to be no later than d. If the parent's deadline is already earlier than d,
+// WithDeadline(parent, d) is semantically equivalent to parent. The returned
+// context's Done channel is closed when the deadline expires, when the returned
+// cancel function is called, or when the parent context's Done channel is
+// closed, whichever happens first.
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete.
+func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
+	if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
+		// The current deadline is already sooner than the new one.
+		return WithCancel(parent)
+	}
+	c := &timerCtx{
+		cancelCtx: newCancelCtx(parent),
+		deadline:  deadline,
+	}
+	propagateCancel(parent, c)
+	d := deadline.Sub(time.Now())
+	if d <= 0 {
+		c.cancel(true, DeadlineExceeded) // deadline has already passed
+		return c, func() { c.cancel(true, Canceled) }
+	}
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	if c.err == nil {
+		c.timer = time.AfterFunc(d, func() {
+			c.cancel(true, DeadlineExceeded)
+		})
+	}
+	return c, func() { c.cancel(true, Canceled) }
+}
+
+// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
+// implement Done and Err. It implements cancel by stopping its timer then
+// delegating to cancelCtx.cancel.
+type timerCtx struct {
+	cancelCtx
+	timer *time.Timer // Under cancelCtx.mu.
+
+	deadline time.Time
+}
+
+func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
+	return c.deadline, true
+}
+
+func (c *timerCtx) String() string {
+	return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now()))
+}
+
+func (c *timerCtx) cancel(removeFromParent bool, err error) {
+	c.cancelCtx.cancel(false, err)
+	if removeFromParent {
+		// Remove this timerCtx from its parent cancelCtx's children.
+		removeChild(c.cancelCtx.Context, c)
+	}
+	c.mu.Lock()
+	if c.timer != nil {
+		c.timer.Stop()
+		c.timer = nil
+	}
+	c.mu.Unlock()
+}
+
+// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
+//
+// Canceling this context releases resources associated with it, so code should
+// call cancel as soon as the operations running in this Context complete:
+//
+// 	func slowOperationWithTimeout(ctx context.Context) (Result, error) {
+// 		ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
+// 		defer cancel()  // releases resources if slowOperation completes before timeout elapses
+// 		return slowOperation(ctx)
+// 	}
+func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
+	return WithDeadline(parent, time.Now().Add(timeout))
+}
+
+// WithValue returns a copy of parent in which the value associated with key is
+// val.
+//
+// Use context Values only for request-scoped data that transits processes and
+// APIs, not for passing optional parameters to functions.
+//
+// The provided key must be comparable.
+func WithValue(parent Context, key, val interface{}) Context {
+	if key == nil {
+		panic("nil key")
+	}
+	if !reflect.TypeOf(key).Comparable() {
+		panic("key is not comparable")
+	}
+	return &valueCtx{parent, key, val}
+}
+
+// A valueCtx carries a key-value pair. It implements Value for that key and
+// delegates all other calls to the embedded Context.
+type valueCtx struct {
+	Context
+	key, val interface{}
+}
+
+func (c *valueCtx) String() string {
+	return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
+}
+
+func (c *valueCtx) Value(key interface{}) interface{} {
+	if c.key == key {
+		return c.val
+	}
+	return c.Context.Value(key)
+}
diff --git a/src/context/context_test.go b/src/context/context_test.go
new file mode 100644
index 0000000..90e78e5
--- /dev/null
+++ b/src/context/context_test.go
@@ -0,0 +1,608 @@
+// 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 context
+
+import (
+	"fmt"
+	"math/rand"
+	"runtime"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+)
+
+// otherContext is a Context that's not one of the types defined in context.go.
+// This lets us test code paths that differ based on the underlying type of the
+// Context.
+type otherContext struct {
+	Context
+}
+
+func TestBackground(t *testing.T) {
+	c := Background()
+	if c == nil {
+		t.Fatalf("Background returned nil")
+	}
+	select {
+	case x := <-c.Done():
+		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+	default:
+	}
+	if got, want := fmt.Sprint(c), "context.Background"; got != want {
+		t.Errorf("Background().String() = %q want %q", got, want)
+	}
+}
+
+func TestTODO(t *testing.T) {
+	c := TODO()
+	if c == nil {
+		t.Fatalf("TODO returned nil")
+	}
+	select {
+	case x := <-c.Done():
+		t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+	default:
+	}
+	if got, want := fmt.Sprint(c), "context.TODO"; got != want {
+		t.Errorf("TODO().String() = %q want %q", got, want)
+	}
+}
+
+func TestWithCancel(t *testing.T) {
+	c1, cancel := WithCancel(Background())
+
+	if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
+		t.Errorf("c1.String() = %q want %q", got, want)
+	}
+
+	o := otherContext{c1}
+	c2, _ := WithCancel(o)
+	contexts := []Context{c1, o, c2}
+
+	for i, c := range contexts {
+		if d := c.Done(); d == nil {
+			t.Errorf("c[%d].Done() == %v want non-nil", i, d)
+		}
+		if e := c.Err(); e != nil {
+			t.Errorf("c[%d].Err() == %v want nil", i, e)
+		}
+
+		select {
+		case x := <-c.Done():
+			t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
+		default:
+		}
+	}
+
+	cancel()
+	time.Sleep(100 * time.Millisecond) // let cancelation propagate
+
+	for i, c := range contexts {
+		select {
+		case <-c.Done():
+		default:
+			t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
+		}
+		if e := c.Err(); e != Canceled {
+			t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
+		}
+	}
+}
+
+func TestParentFinishesChild(t *testing.T) {
+	// Context tree:
+	// parent -> cancelChild
+	// parent -> valueChild -> timerChild
+	parent, cancel := WithCancel(Background())
+	cancelChild, stop := WithCancel(parent)
+	defer stop()
+	valueChild := WithValue(parent, "key", "value")
+	timerChild, stop := WithTimeout(valueChild, 10000*time.Hour)
+	defer stop()
+
+	select {
+	case x := <-parent.Done():
+		t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+	case x := <-cancelChild.Done():
+		t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
+	case x := <-timerChild.Done():
+		t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
+	case x := <-valueChild.Done():
+		t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
+	default:
+	}
+
+	// The parent's children should contain the two cancelable children.
+	pc := parent.(*cancelCtx)
+	cc := cancelChild.(*cancelCtx)
+	tc := timerChild.(*timerCtx)
+	pc.mu.Lock()
+	if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] {
+		t.Errorf("bad linkage: pc.children = %v, want %v and %v",
+			pc.children, cc, tc)
+	}
+	pc.mu.Unlock()
+
+	if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
+		t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
+	}
+	if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
+		t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
+	}
+
+	cancel()
+
+	pc.mu.Lock()
+	if len(pc.children) != 0 {
+		t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
+	}
+	pc.mu.Unlock()
+
+	// parent and children should all be finished.
+	check := func(ctx Context, name string) {
+		select {
+		case <-ctx.Done():
+		default:
+			t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
+		}
+		if e := ctx.Err(); e != Canceled {
+			t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
+		}
+	}
+	check(parent, "parent")
+	check(cancelChild, "cancelChild")
+	check(valueChild, "valueChild")
+	check(timerChild, "timerChild")
+
+	// WithCancel should return a canceled context on a canceled parent.
+	precanceledChild := WithValue(parent, "key", "value")
+	select {
+	case <-precanceledChild.Done():
+	default:
+		t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
+	}
+	if e := precanceledChild.Err(); e != Canceled {
+		t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
+	}
+}
+
+func TestChildFinishesFirst(t *testing.T) {
+	cancelable, stop := WithCancel(Background())
+	defer stop()
+	for _, parent := range []Context{Background(), cancelable} {
+		child, cancel := WithCancel(parent)
+
+		select {
+		case x := <-parent.Done():
+			t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+		case x := <-child.Done():
+			t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
+		default:
+		}
+
+		cc := child.(*cancelCtx)
+		pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
+		if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
+			t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
+		}
+
+		if pcok {
+			pc.mu.Lock()
+			if len(pc.children) != 1 || !pc.children[cc] {
+				t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
+			}
+			pc.mu.Unlock()
+		}
+
+		cancel()
+
+		if pcok {
+			pc.mu.Lock()
+			if len(pc.children) != 0 {
+				t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
+			}
+			pc.mu.Unlock()
+		}
+
+		// child should be finished.
+		select {
+		case <-child.Done():
+		default:
+			t.Errorf("<-child.Done() blocked, but shouldn't have")
+		}
+		if e := child.Err(); e != Canceled {
+			t.Errorf("child.Err() == %v want %v", e, Canceled)
+		}
+
+		// parent should not be finished.
+		select {
+		case x := <-parent.Done():
+			t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
+		default:
+		}
+		if e := parent.Err(); e != nil {
+			t.Errorf("parent.Err() == %v want nil", e)
+		}
+	}
+}
+
+func testDeadline(c Context, name string, failAfter time.Duration, t *testing.T) {
+	select {
+	case <-time.After(failAfter):
+		t.Fatalf("%s: context should have timed out", name)
+	case <-c.Done():
+	}
+	if e := c.Err(); e != DeadlineExceeded {
+		t.Errorf("%s: c.Err() == %v; want %v", name, e, DeadlineExceeded)
+	}
+}
+
+func TestDeadline(t *testing.T) {
+	c, _ := WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
+	if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
+		t.Errorf("c.String() = %q want prefix %q", got, prefix)
+	}
+	testDeadline(c, "WithDeadline", time.Second, t)
+
+	c, _ = WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
+	o := otherContext{c}
+	testDeadline(o, "WithDeadline+otherContext", time.Second, t)
+
+	c, _ = WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
+	o = otherContext{c}
+	c, _ = WithDeadline(o, time.Now().Add(4*time.Second))
+	testDeadline(c, "WithDeadline+otherContext+WithDeadline", 2*time.Second, t)
+}
+
+func TestTimeout(t *testing.T) {
+	c, _ := WithTimeout(Background(), 50*time.Millisecond)
+	if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
+		t.Errorf("c.String() = %q want prefix %q", got, prefix)
+	}
+	testDeadline(c, "WithTimeout", time.Second, t)
+
+	c, _ = WithTimeout(Background(), 50*time.Millisecond)
+	o := otherContext{c}
+	testDeadline(o, "WithTimeout+otherContext", time.Second, t)
+
+	c, _ = WithTimeout(Background(), 50*time.Millisecond)
+	o = otherContext{c}
+	c, _ = WithTimeout(o, 3*time.Second)
+	testDeadline(c, "WithTimeout+otherContext+WithTimeout", 2*time.Second, t)
+}
+
+func TestCanceledTimeout(t *testing.T) {
+	c, _ := WithTimeout(Background(), time.Second)
+	o := otherContext{c}
+	c, cancel := WithTimeout(o, 2*time.Second)
+	cancel()
+	time.Sleep(100 * time.Millisecond) // let cancelation propagate
+	select {
+	case <-c.Done():
+	default:
+		t.Errorf("<-c.Done() blocked, but shouldn't have")
+	}
+	if e := c.Err(); e != Canceled {
+		t.Errorf("c.Err() == %v want %v", e, Canceled)
+	}
+}
+
+type key1 int
+type key2 int
+
+var k1 = key1(1)
+var k2 = key2(1) // same int as k1, different type
+var k3 = key2(3) // same type as k2, different int
+
+func TestValues(t *testing.T) {
+	check := func(c Context, nm, v1, v2, v3 string) {
+		if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
+			t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
+		}
+		if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
+			t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
+		}
+		if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
+			t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
+		}
+	}
+
+	c0 := Background()
+	check(c0, "c0", "", "", "")
+
+	c1 := WithValue(Background(), k1, "c1k1")
+	check(c1, "c1", "c1k1", "", "")
+
+	if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want {
+		t.Errorf("c.String() = %q want %q", got, want)
+	}
+
+	c2 := WithValue(c1, k2, "c2k2")
+	check(c2, "c2", "c1k1", "c2k2", "")
+
+	c3 := WithValue(c2, k3, "c3k3")
+	check(c3, "c2", "c1k1", "c2k2", "c3k3")
+
+	c4 := WithValue(c3, k1, nil)
+	check(c4, "c4", "", "c2k2", "c3k3")
+
+	o0 := otherContext{Background()}
+	check(o0, "o0", "", "", "")
+
+	o1 := otherContext{WithValue(Background(), k1, "c1k1")}
+	check(o1, "o1", "c1k1", "", "")
+
+	o2 := WithValue(o1, k2, "o2k2")
+	check(o2, "o2", "c1k1", "o2k2", "")
+
+	o3 := otherContext{c4}
+	check(o3, "o3", "", "c2k2", "c3k3")
+
+	o4 := WithValue(o3, k3, nil)
+	check(o4, "o4", "", "c2k2", "")
+}
+
+func TestAllocs(t *testing.T) {
+	bg := Background()
+	for _, test := range []struct {
+		desc       string
+		f          func()
+		limit      float64
+		gccgoLimit float64
+	}{
+		{
+			desc:       "Background()",
+			f:          func() { Background() },
+			limit:      0,
+			gccgoLimit: 0,
+		},
+		{
+			desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
+			f: func() {
+				c := WithValue(bg, k1, nil)
+				c.Value(k1)
+			},
+			limit:      3,
+			gccgoLimit: 3,
+		},
+		{
+			desc: "WithTimeout(bg, 15*time.Millisecond)",
+			f: func() {
+				c, _ := WithTimeout(bg, 15*time.Millisecond)
+				<-c.Done()
+			},
+			limit:      8,
+			gccgoLimit: 15,
+		},
+		{
+			desc: "WithCancel(bg)",
+			f: func() {
+				c, cancel := WithCancel(bg)
+				cancel()
+				<-c.Done()
+			},
+			limit:      5,
+			gccgoLimit: 8,
+		},
+		{
+			desc: "WithTimeout(bg, 5*time.Millisecond)",
+			f: func() {
+				c, cancel := WithTimeout(bg, 5*time.Millisecond)
+				cancel()
+				<-c.Done()
+			},
+			limit:      8,
+			gccgoLimit: 25,
+		},
+	} {
+		limit := test.limit
+		if runtime.Compiler == "gccgo" {
+			// gccgo does not yet do escape analysis.
+			// TOOD(iant): Remove this when gccgo does do escape analysis.
+			limit = test.gccgoLimit
+		}
+		numRuns := 100
+		if testing.Short() {
+			numRuns = 10
+		}
+		if n := testing.AllocsPerRun(numRuns, test.f); n > limit {
+			t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
+		}
+	}
+}
+
+func TestSimultaneousCancels(t *testing.T) {
+	root, cancel := WithCancel(Background())
+	m := map[Context]CancelFunc{root: cancel}
+	q := []Context{root}
+	// Create a tree of contexts.
+	for len(q) != 0 && len(m) < 100 {
+		parent := q[0]
+		q = q[1:]
+		for i := 0; i < 4; i++ {
+			ctx, cancel := WithCancel(parent)
+			m[ctx] = cancel
+			q = append(q, ctx)
+		}
+	}
+	// Start all the cancels in a random order.
+	var wg sync.WaitGroup
+	wg.Add(len(m))
+	for _, cancel := range m {
+		go func(cancel CancelFunc) {
+			cancel()
+			wg.Done()
+		}(cancel)
+	}
+	// Wait on all the contexts in a random order.
+	for ctx := range m {
+		select {
+		case <-ctx.Done():
+		case <-time.After(1 * time.Second):
+			buf := make([]byte, 10<<10)
+			n := runtime.Stack(buf, true)
+			t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n])
+		}
+	}
+	// Wait for all the cancel functions to return.
+	done := make(chan struct{})
+	go func() {
+		wg.Wait()
+		close(done)
+	}()
+	select {
+	case <-done:
+	case <-time.After(1 * time.Second):
+		buf := make([]byte, 10<<10)
+		n := runtime.Stack(buf, true)
+		t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n])
+	}
+}
+
+func TestInterlockedCancels(t *testing.T) {
+	parent, cancelParent := WithCancel(Background())
+	child, cancelChild := WithCancel(parent)
+	go func() {
+		parent.Done()
+		cancelChild()
+	}()
+	cancelParent()
+	select {
+	case <-child.Done():
+	case <-time.After(1 * time.Second):
+		buf := make([]byte, 10<<10)
+		n := runtime.Stack(buf, true)
+		t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n])
+	}
+}
+
+func TestLayersCancel(t *testing.T) {
+	testLayers(t, time.Now().UnixNano(), false)
+}
+
+func TestLayersTimeout(t *testing.T) {
+	testLayers(t, time.Now().UnixNano(), true)
+}
+
+func testLayers(t *testing.T, seed int64, testTimeout bool) {
+	rand.Seed(seed)
+	errorf := func(format string, a ...interface{}) {
+		t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
+	}
+	const (
+		timeout   = 200 * time.Millisecond
+		minLayers = 30
+	)
+	type value int
+	var (
+		vals      []*value
+		cancels   []CancelFunc
+		numTimers int
+		ctx       = Background()
+	)
+	for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
+		switch rand.Intn(3) {
+		case 0:
+			v := new(value)
+			ctx = WithValue(ctx, v, v)
+			vals = append(vals, v)
+		case 1:
+			var cancel CancelFunc
+			ctx, cancel = WithCancel(ctx)
+			cancels = append(cancels, cancel)
+		case 2:
+			var cancel CancelFunc
+			ctx, cancel = WithTimeout(ctx, timeout)
+			cancels = append(cancels, cancel)
+			numTimers++
+		}
+	}
+	checkValues := func(when string) {
+		for _, key := range vals {
+			if val := ctx.Value(key).(*value); key != val {
+				errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
+			}
+		}
+	}
+	select {
+	case <-ctx.Done():
+		errorf("ctx should not be canceled yet")
+	default:
+	}
+	if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
+		t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
+	}
+	t.Log(ctx)
+	checkValues("before cancel")
+	if testTimeout {
+		select {
+		case <-ctx.Done():
+		case <-time.After(timeout + time.Second):
+			errorf("ctx should have timed out")
+		}
+		checkValues("after timeout")
+	} else {
+		cancel := cancels[rand.Intn(len(cancels))]
+		cancel()
+		select {
+		case <-ctx.Done():
+		default:
+			errorf("ctx should be canceled")
+		}
+		checkValues("after cancel")
+	}
+}
+
+func TestCancelRemoves(t *testing.T) {
+	checkChildren := func(when string, ctx Context, want int) {
+		if got := len(ctx.(*cancelCtx).children); got != want {
+			t.Errorf("%s: context has %d children, want %d", when, got, want)
+		}
+	}
+
+	ctx, _ := WithCancel(Background())
+	checkChildren("after creation", ctx, 0)
+	_, cancel := WithCancel(ctx)
+	checkChildren("with WithCancel child ", ctx, 1)
+	cancel()
+	checkChildren("after cancelling WithCancel child", ctx, 0)
+
+	ctx, _ = WithCancel(Background())
+	checkChildren("after creation", ctx, 0)
+	_, cancel = WithTimeout(ctx, 60*time.Minute)
+	checkChildren("with WithTimeout child ", ctx, 1)
+	cancel()
+	checkChildren("after cancelling WithTimeout child", ctx, 0)
+}
+
+func TestWithValueChecksKey(t *testing.T) {
+	panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
+	if panicVal == nil {
+		t.Error("expected panic")
+	}
+	panicVal = recoveredValue(func() { WithValue(Background(), nil, "bar") })
+	if got, want := fmt.Sprint(panicVal), "nil key"; got != want {
+		t.Errorf("panic = %q; want %q", got, want)
+	}
+}
+
+func recoveredValue(fn func()) (v interface{}) {
+	defer func() { v = recover() }()
+	fn()
+	return
+}
+
+func TestDeadlineExceededSupportsTimeout(t *testing.T) {
+	i, ok := DeadlineExceeded.(interface {
+		Timeout() bool
+	})
+	if !ok {
+		t.Fatal("DeadlineExceeded does not support Timeout interface")
+	}
+	if !i.Timeout() {
+		t.Fatal("wrong value for timeout")
+	}
+}
diff --git a/src/context/withtimeout_test.go b/src/context/withtimeout_test.go
new file mode 100644
index 0000000..a3e8979
--- /dev/null
+++ b/src/context/withtimeout_test.go
@@ -0,0 +1,33 @@
+// 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 context_test
+
+import (
+	"context"
+	"fmt"
+	"time"
+)
+
+func ExampleWithTimeout() {
+	// Pass a context with a timeout to tell a blocking function that it
+	// should abandon its work after the timeout elapses.
+	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
+
+	select {
+	case <-time.After(1 * time.Second):
+		fmt.Println("overslept")
+	case <-ctx.Done():
+		fmt.Println(ctx.Err()) // prints "context deadline exceeded"
+	}
+
+	// Even though ctx should have expired already, it is good
+	// practice to call its cancelation function in any case.
+	// Failure to do so may keep the context and its parent alive
+	// longer than necessary.
+	cancel()
+
+	// Output:
+	// context deadline exceeded
+}
diff --git a/src/crypto/aes/aes_gcm.go b/src/crypto/aes/aes_gcm.go
index 1377578..a894a68 100644
--- a/src/crypto/aes/aes_gcm.go
+++ b/src/crypto/aes/aes_gcm.go
@@ -45,9 +45,12 @@ var errOpen = errors.New("cipher: message authentication failed")
 // will use the optimised implementation in this file when possible. Instances
 // of this type only exist when hasGCMAsm returns true.
 type aesCipherGCM struct {
-	aesCipher
+	aesCipherAsm
 }
 
+// Assert that aesCipherGCM implements the gcmAble interface.
+var _ gcmAble = (*aesCipherGCM)(nil)
+
 // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
 // called by crypto/cipher.NewGCM via the gcmAble interface.
 func (c *aesCipherGCM) NewGCM(nonceSize int) (cipher.AEAD, error) {
diff --git a/src/crypto/aes/aes_test.go b/src/crypto/aes/aes_test.go
index 3631809..2814496 100644
--- a/src/crypto/aes/aes_test.go
+++ b/src/crypto/aes/aes_test.go
@@ -280,42 +280,6 @@ var encryptTests = []CryptTest{
 	},
 }
 
-// Test encryptBlock against FIPS 197 examples.
-func TestEncryptBlock(t *testing.T) {
-	for i, tt := range encryptTests {
-		n := len(tt.key) + 28
-		enc := make([]uint32, n)
-		dec := make([]uint32, n)
-		expandKey(tt.key, enc, dec)
-		out := make([]byte, len(tt.in))
-		encryptBlock(enc, out, tt.in)
-		for j, v := range out {
-			if v != tt.out[j] {
-				t.Errorf("encryptBlock %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
-				break
-			}
-		}
-	}
-}
-
-// Test decryptBlock against FIPS 197 examples.
-func TestDecryptBlock(t *testing.T) {
-	for i, tt := range encryptTests {
-		n := len(tt.key) + 28
-		enc := make([]uint32, n)
-		dec := make([]uint32, n)
-		expandKey(tt.key, enc, dec)
-		plain := make([]byte, len(tt.in))
-		decryptBlock(dec, plain, tt.out)
-		for j, v := range plain {
-			if v != tt.in[j] {
-				t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
-				break
-			}
-		}
-	}
-}
-
 // Test Cipher Encrypt method against FIPS 197 examples.
 func TestCipherEncrypt(t *testing.T) {
 	for i, tt := range encryptTests {
diff --git a/src/crypto/aes/asm_s390x.s b/src/crypto/aes/asm_s390x.s
new file mode 100644
index 0000000..e31415a
--- /dev/null
+++ b/src/crypto/aes/asm_s390x.s
@@ -0,0 +1,93 @@
+// Copyright 2016 The Go 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 hasAsm() bool
+TEXT ·hasAsm(SB),NOSPLIT,$16-1
+	XOR	R0, R0          // set function code to 0 (query)
+	LA	mask-16(SP), R1 // 16-byte stack variable for mask
+	MOVD	$(0x38<<40), R3 // mask for bits 18-20 (big endian)
+
+	// check for KM AES functions
+	WORD	$0xB92E0024 // cipher message (KM)
+	MOVD	mask-16(SP), R2
+	AND	R3, R2
+	CMPBNE	R2, R3, notfound
+
+	// check for KMC AES functions
+	WORD	$0xB92F0024 // cipher message with chaining (KMC)
+	MOVD	mask-16(SP), R2
+	AND	R3, R2
+	CMPBNE	R2, R3, notfound
+
+	MOVB	$1, ret+0(FP)
+	RET
+notfound:
+	MOVB	$0, ret+0(FP)
+	RET
+
+// func cryptBlocks(function code, key, dst, src *byte, length int)
+TEXT ·cryptBlocks(SB),NOSPLIT,$0-40
+	MOVD	key+8(FP), R1
+	MOVD	dst+16(FP), R2
+	MOVD	src+24(FP), R4
+	MOVD	length+32(FP), R5
+	MOVD	function+0(FP), R0
+loop:
+	WORD	$0xB92E0024 // cipher message (KM)
+	BVS	loop        // branch back if interrupted
+	XOR	R0, R0
+	RET
+
+// func cryptBlocksChain(function code, iv, key, dst, src *byte, length int)
+TEXT ·cryptBlocksChain(SB),NOSPLIT,$48-48
+	LA	params-48(SP), R1
+	MOVD	iv+8(FP), R8
+	MOVD	key+16(FP), R9
+	MVC	$16, 0(R8), 0(R1)  // move iv into params
+	MVC	$32, 0(R9), 16(R1) // move key into params
+	MOVD	dst+24(FP), R2
+	MOVD	src+32(FP), R4
+	MOVD	length+40(FP), R5
+	MOVD	function+0(FP), R0
+loop:
+	WORD	$0xB92F0024       // cipher message with chaining (KMC)
+	BVS	loop              // branch back if interrupted
+	XOR	R0, R0
+	MVC	$16, 0(R1), 0(R8) // update iv
+	RET
+
+// func xorBytes(dst, a, b []byte) int
+TEXT ·xorBytes(SB),NOSPLIT,$0-80
+	MOVD	dst_base+0(FP), R1
+	MOVD	a_base+24(FP), R2
+	MOVD	b_base+48(FP), R3
+	MOVD	a_len+32(FP), R4
+	MOVD	b_len+56(FP), R5
+	CMPBLE	R4, R5, skip
+	MOVD	R5, R4
+skip:
+	MOVD	R4, ret+72(FP)
+	MOVD	$0, R5
+	CMPBLT	R4, $8, tail
+loop:
+	MOVD	0(R2)(R5*1), R7
+	MOVD	0(R3)(R5*1), R8
+	XOR	R7, R8
+	MOVD	R8, 0(R1)(R5*1)
+	LAY	8(R5), R5
+	SUB	$8, R4
+	CMPBGE	R4, $8, loop
+tail:
+	CMPBEQ	R4, $0, done
+	MOVB	0(R2)(R5*1), R7
+	MOVB	0(R3)(R5*1), R8
+	XOR	R7, R8
+	MOVB	R8, 0(R1)(R5*1)
+	LAY	1(R5), R5
+	SUB	$1, R4
+	BR	tail
+done:
+	RET
diff --git a/src/crypto/aes/block.go b/src/crypto/aes/block.go
index 57a7e9e..41ea9cf 100644
--- a/src/crypto/aes/block.go
+++ b/src/crypto/aes/block.go
@@ -137,7 +137,7 @@ func subw(w uint32) uint32 {
 // Rotate
 func rotw(w uint32) uint32 { return w<<8 | w>>24 }
 
-// Key expansion algorithm.  See FIPS-197, Figure 11.
+// Key expansion algorithm. See FIPS-197, Figure 11.
 // Their rcon[i] is our powx[i-1] << 24.
 func expandKeyGo(key []byte, enc, dec []uint32) {
 	// Encryption key setup.
diff --git a/src/crypto/aes/cbc_s390x.go b/src/crypto/aes/cbc_s390x.go
new file mode 100644
index 0000000..427b30b
--- /dev/null
+++ b/src/crypto/aes/cbc_s390x.go
@@ -0,0 +1,59 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+	"crypto/cipher"
+)
+
+// Assert that aesCipherAsm implements the cbcEncAble and cbcDecAble interfaces.
+var _ cbcEncAble = (*aesCipherAsm)(nil)
+var _ cbcDecAble = (*aesCipherAsm)(nil)
+
+type cbc struct {
+	b  *aesCipherAsm
+	c  code
+	iv [BlockSize]byte
+}
+
+func (b *aesCipherAsm) NewCBCEncrypter(iv []byte) cipher.BlockMode {
+	var c cbc
+	c.b = b
+	c.c = b.function
+	copy(c.iv[:], iv)
+	return &c
+}
+
+func (b *aesCipherAsm) NewCBCDecrypter(iv []byte) cipher.BlockMode {
+	var c cbc
+	c.b = b
+	c.c = b.function + 128 // decrypt function code is encrypt + 128
+	copy(c.iv[:], iv)
+	return &c
+}
+
+func (x *cbc) BlockSize() int { return BlockSize }
+
+// cryptBlocksChain invokes the cipher message with chaining (KMC) instruction
+// with the given function code. The length must be a multiple of BlockSize (16).
+//go:noescape
+func cryptBlocksChain(c code, iv, key, dst, src *byte, length int)
+
+func (x *cbc) CryptBlocks(dst, src []byte) {
+	if len(src)%BlockSize != 0 {
+		panic("crypto/cipher: input not full blocks")
+	}
+	if len(dst) < len(src) {
+		panic("crypto/cipher: output smaller than input")
+	}
+	cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src))
+}
+
+func (x *cbc) SetIV(iv []byte) {
+	if len(iv) != BlockSize {
+		panic("cipher: incorrect length IV")
+	}
+	copy(x.iv[:], iv)
+}
diff --git a/src/crypto/aes/cipher.go b/src/crypto/aes/cipher.go
index 04d2be1..c5a8e91 100644
--- a/src/crypto/aes/cipher.go
+++ b/src/crypto/aes/cipher.go
@@ -36,15 +36,15 @@ func NewCipher(key []byte) (cipher.Block, error) {
 	case 16, 24, 32:
 		break
 	}
+	return newCipher(key)
+}
 
-	n := k + 28
+// newCipherGeneric creates and returns a new cipher.Block
+// implemented in pure Go.
+func newCipherGeneric(key []byte) (cipher.Block, error) {
+	n := len(key) + 28
 	c := aesCipher{make([]uint32, n), make([]uint32, n)}
-	expandKey(key, c.enc, c.dec)
-
-	if hasGCMAsm() {
-		return &aesCipherGCM{c}, nil
-	}
-
+	expandKeyGo(key, c.enc, c.dec)
 	return &c, nil
 }
 
@@ -57,7 +57,7 @@ func (c *aesCipher) Encrypt(dst, src []byte) {
 	if len(dst) < BlockSize {
 		panic("crypto/aes: output not full block")
 	}
-	encryptBlock(c.enc, dst, src)
+	encryptBlockGo(c.enc, dst, src)
 }
 
 func (c *aesCipher) Decrypt(dst, src []byte) {
@@ -67,5 +67,5 @@ func (c *aesCipher) Decrypt(dst, src []byte) {
 	if len(dst) < BlockSize {
 		panic("crypto/aes: output not full block")
 	}
-	decryptBlock(c.dec, dst, src)
+	decryptBlockGo(c.dec, dst, src)
 }
diff --git a/src/crypto/aes/cipher_amd64.go b/src/crypto/aes/cipher_amd64.go
new file mode 100644
index 0000000..b33c8ff
--- /dev/null
+++ b/src/crypto/aes/cipher_amd64.go
@@ -0,0 +1,83 @@
+// 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 aes
+
+import (
+	"crypto/cipher"
+)
+
+// defined in asm_amd64.s
+func hasAsm() bool
+func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
+
+type aesCipherAsm struct {
+	aesCipher
+}
+
+var useAsm = hasAsm()
+
+func newCipher(key []byte) (cipher.Block, error) {
+	if !useAsm {
+		return newCipherGeneric(key)
+	}
+	n := len(key) + 28
+	c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}}
+	rounds := 10
+	switch len(key) {
+	case 128 / 8:
+		rounds = 10
+	case 192 / 8:
+		rounds = 12
+	case 256 / 8:
+		rounds = 14
+	}
+	expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0])
+	if hasGCMAsm() {
+		return &aesCipherGCM{c}, nil
+	}
+
+	return &c, nil
+}
+
+func (c *aesCipherAsm) BlockSize() int { return BlockSize }
+
+func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+	if len(src) < BlockSize {
+		panic("crypto/aes: input not full block")
+	}
+	if len(dst) < BlockSize {
+		panic("crypto/aes: output not full block")
+	}
+	encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0])
+}
+
+func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+	if len(src) < BlockSize {
+		panic("crypto/aes: input not full block")
+	}
+	if len(dst) < BlockSize {
+		panic("crypto/aes: output not full block")
+	}
+	decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
+}
+
+// expandKey is used by BenchmarkExpand to ensure that the asm implementation
+// of key expansion is used for the benchmark when it is available.
+func expandKey(key []byte, enc, dec []uint32) {
+	if useAsm {
+		rounds := 10 // rounds needed for AES128
+		switch len(key) {
+		case 192 / 8:
+			rounds = 12
+		case 256 / 8:
+			rounds = 14
+		}
+		expandKeyAsm(rounds, &key[0], &enc[0], &dec[0])
+	} else {
+		expandKeyGo(key, enc, dec)
+	}
+}
diff --git a/src/crypto/aes/cipher_asm.go b/src/crypto/aes/cipher_asm.go
deleted file mode 100644
index 964eaaa..0000000
--- a/src/crypto/aes/cipher_asm.go
+++ /dev/null
@@ -1,48 +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 amd64
-
-package aes
-
-// defined in asm_$GOARCH.s
-func hasAsm() bool
-func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
-func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
-func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
-
-var useAsm = hasAsm()
-
-func encryptBlock(xk []uint32, dst, src []byte) {
-	if useAsm {
-		encryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0])
-	} else {
-		encryptBlockGo(xk, dst, src)
-	}
-}
-
-func decryptBlock(xk []uint32, dst, src []byte) {
-	if useAsm {
-		decryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0])
-	} else {
-		decryptBlockGo(xk, dst, src)
-	}
-}
-
-func expandKey(key []byte, enc, dec []uint32) {
-	if useAsm {
-		rounds := 10
-		switch len(key) {
-		case 128 / 8:
-			rounds = 10
-		case 192 / 8:
-			rounds = 12
-		case 256 / 8:
-			rounds = 14
-		}
-		expandKeyAsm(rounds, &key[0], &enc[0], &dec[0])
-	} else {
-		expandKeyGo(key, enc, dec)
-	}
-}
diff --git a/src/crypto/aes/cipher_generic.go b/src/crypto/aes/cipher_generic.go
index 32b2b3c..f807034 100644
--- a/src/crypto/aes/cipher_generic.go
+++ b/src/crypto/aes/cipher_generic.go
@@ -2,26 +2,25 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64
+// +build !amd64,!s390x
 
 package aes
 
-func encryptBlock(xk []uint32, dst, src []byte) {
-	encryptBlockGo(xk, dst, src)
-}
+import (
+	"crypto/cipher"
+)
 
-func decryptBlock(xk []uint32, dst, src []byte) {
-	decryptBlockGo(xk, dst, src)
+// newCipher calls the newCipherGeneric function
+// directly. Platforms with hardware accelerated
+// implementations of AES should implement their
+// own version of newCipher (which may then call
+// newCipherGeneric if needed).
+func newCipher(key []byte) (cipher.Block, error) {
+	return newCipherGeneric(key)
 }
 
+// expandKey is used by BenchmarkExpand and should
+// call an assembly implementation if one is available.
 func expandKey(key []byte, enc, dec []uint32) {
 	expandKeyGo(key, enc, dec)
 }
-
-func hasGCMAsm() bool {
-	return false
-}
-
-type aesCipherGCM struct {
-	aesCipher
-}
diff --git a/src/crypto/aes/cipher_s390x.go b/src/crypto/aes/cipher_s390x.go
new file mode 100644
index 0000000..bec5933
--- /dev/null
+++ b/src/crypto/aes/cipher_s390x.go
@@ -0,0 +1,90 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+	"crypto/cipher"
+)
+
+type code int
+
+// Function codes for the cipher message family of instructions.
+const (
+	aes128 code = 18
+	aes192      = 19
+	aes256      = 20
+)
+
+type aesCipherAsm struct {
+	function code      // code for cipher message instruction
+	key      []byte    // key (128, 192 or 256 bytes)
+	storage  [256]byte // array backing key slice
+}
+
+// hasAsm reports whether the AES-128, AES-192 and AES-256
+// cipher message (KM) function codes are supported.
+// Note: this function call is expensive.
+func hasAsm() bool
+
+// cryptBlocks invokes the cipher message (KM) instruction with
+// the given function code. This is equivalent to AES in ECB
+// mode. The length must be a multiple of BlockSize (16).
+//go:noesape
+func cryptBlocks(c code, key, dst, src *byte, length int)
+
+var useAsm = hasAsm()
+
+func newCipher(key []byte) (cipher.Block, error) {
+	if !useAsm {
+		return newCipherGeneric(key)
+	}
+
+	var function code
+	switch len(key) {
+	case 128 / 8:
+		function = aes128
+	case 192 / 8:
+		function = aes192
+	case 256 / 8:
+		function = aes256
+	default:
+		return nil, KeySizeError(len(key))
+	}
+
+	var c aesCipherAsm
+	c.function = function
+	c.key = c.storage[:len(key)]
+	copy(c.key, key)
+	return &c, nil
+}
+
+func (c *aesCipherAsm) BlockSize() int { return BlockSize }
+
+func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+	if len(src) < BlockSize {
+		panic("crypto/aes: input not full block")
+	}
+	if len(dst) < BlockSize {
+		panic("crypto/aes: output not full block")
+	}
+	cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize)
+}
+
+func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+	if len(src) < BlockSize {
+		panic("crypto/aes: input not full block")
+	}
+	if len(dst) < BlockSize {
+		panic("crypto/aes: output not full block")
+	}
+	// The decrypt function code is equal to the function code + 128.
+	cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize)
+}
+
+// expandKey is used by BenchmarkExpand. cipher message (KM) does not need key
+// expansion so there is no assembly equivalent.
+func expandKey(key []byte, enc, dec []uint32) {
+	expandKeyGo(key, enc, dec)
+}
diff --git a/src/crypto/aes/ctr_s390x.go b/src/crypto/aes/ctr_s390x.go
new file mode 100644
index 0000000..94dea5c
--- /dev/null
+++ b/src/crypto/aes/ctr_s390x.go
@@ -0,0 +1,76 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+	"crypto/cipher"
+	"unsafe"
+)
+
+// Assert that aesCipherAsm implements the ctrAble interface.
+var _ ctrAble = (*aesCipherAsm)(nil)
+
+// xorBytes xors the contents of a and b and places the resulting values into
+// dst. If a and b are not the same length then the number of bytes processed
+// will be equal to the length of shorter of the two. Returns the number
+// of bytes processed.
+//go:noescape
+func xorBytes(dst, a, b []byte) int
+
+// streamBufferSize is the number of bytes of encrypted counter values to cache.
+const streamBufferSize = 32 * BlockSize
+
+type aesctr struct {
+	block   *aesCipherAsm          // block cipher
+	ctr     [2]uint64              // next value of the counter (big endian)
+	buffer  []byte                 // buffer for the encrypted counter values
+	storage [streamBufferSize]byte // array backing buffer slice
+}
+
+// NewCTR returns a Stream which encrypts/decrypts using the AES block
+// cipher in counter mode. The length of iv must be the same as BlockSize.
+func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream {
+	if len(iv) != BlockSize {
+		panic("cipher.NewCTR: IV length must equal block size")
+	}
+	var ac aesctr
+	ac.block = c
+	ac.ctr[0] = *(*uint64)(unsafe.Pointer((&iv[0]))) // high bits
+	ac.ctr[1] = *(*uint64)(unsafe.Pointer((&iv[8]))) // low bits
+	ac.buffer = ac.storage[:0]
+	return &ac
+}
+
+func (c *aesctr) refill() {
+	// Fill up the buffer with an incrementing count.
+	c.buffer = c.storage[:streamBufferSize]
+	c0, c1 := c.ctr[0], c.ctr[1]
+	for i := 0; i < streamBufferSize; i += BlockSize {
+		b0 := (*uint64)(unsafe.Pointer(&c.buffer[i]))
+		b1 := (*uint64)(unsafe.Pointer(&c.buffer[i+BlockSize/2]))
+		*b0, *b1 = c0, c1
+		// Increment in big endian: c0 is high, c1 is low.
+		c1++
+		if c1 == 0 {
+			// add carry
+			c0++
+		}
+	}
+	c.ctr[0], c.ctr[1] = c0, c1
+	// Encrypt the buffer using AES in ECB mode.
+	cryptBlocks(c.block.function, &c.block.key[0], &c.buffer[0], &c.buffer[0], streamBufferSize)
+}
+
+func (c *aesctr) XORKeyStream(dst, src []byte) {
+	for len(src) > 0 {
+		if len(c.buffer) == 0 {
+			c.refill()
+		}
+		n := xorBytes(dst, src, c.buffer)
+		c.buffer = c.buffer[n:]
+		src = src[n:]
+		dst = dst[n:]
+	}
+}
diff --git a/src/crypto/aes/gcm_amd64.s b/src/crypto/aes/gcm_amd64.s
index cabb028..c25badd 100644
--- a/src/crypto/aes/gcm_amd64.s
+++ b/src/crypto/aes/gcm_amd64.s
@@ -89,8 +89,8 @@ TEXT ·hasGCMAsm(SB),NOSPLIT,$0
 TEXT ·aesEncBlock(SB),NOSPLIT,$0
 	MOVQ dst+0(FP), DI
 	MOVQ src+8(FP), SI
-	MOVQ ks+16(FP), DX
-	MOVQ ks+24(FP), CX
+	MOVQ ks_base+16(FP), DX
+	MOVQ ks_len+24(FP), CX
 
 	SHRQ $2, CX
 	DECQ CX
@@ -211,8 +211,8 @@ TEXT ·gcmAesInit(SB),NOSPLIT,$0
 #define NR DX
 
 	MOVQ productTable+0(FP), dst
-	MOVQ ks+8(FP), KS
-	MOVQ ks+16(FP), NR
+	MOVQ ks_base+8(FP), KS
+	MOVQ ks_len+16(FP), NR
 
 	SHRQ $2, NR
 	DECQ NR
@@ -325,8 +325,8 @@ TEXT ·gcmAesData(SB),NOSPLIT,$0
 #define autLen DX
 
 	MOVQ productTable+0(FP), pTbl
-	MOVQ data+8(FP), aut
-	MOVQ data+16(FP), autLen
+	MOVQ data_base+8(FP), aut
+	MOVQ data_len+16(FP), autLen
 	MOVQ T+32(FP), tPtr
 
 	PXOR ACC0, ACC0
@@ -421,7 +421,7 @@ dataBail:
 #undef autLen
 
 // func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
-TEXT ·gcmAesEnc(SB),0,$256-144
+TEXT ·gcmAesEnc(SB),0,$256-96
 #define pTbl DI
 #define ctx DX
 #define ctrPtr CX
@@ -477,12 +477,12 @@ TEXT ·gcmAesEnc(SB),0,$256-144
 
 	MOVQ productTable+0(FP), pTbl
 	MOVQ dst+8(FP), ctx
-	MOVQ src+32(FP), ptx
-	MOVQ src+40(FP), ptxLen
+	MOVQ src_base+32(FP), ptx
+	MOVQ src_len+40(FP), ptxLen
 	MOVQ ctr+56(FP), ctrPtr
 	MOVQ T+64(FP), tPtr
-	MOVQ KS+72(FP), ks
-	MOVQ nr+80(FP), NR
+	MOVQ ks_base+72(FP), ks
+	MOVQ ks_len+80(FP), NR
 
 	SHRQ $2, NR
 	DECQ NR
@@ -932,7 +932,7 @@ gcmAesEncDone:
 #undef increment
 
 // func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
-TEXT ·gcmAesDec(SB),0,$128-144
+TEXT ·gcmAesDec(SB),0,$128-96
 #define increment(i) ADDL $1, aluCTR; MOVL aluCTR, aluTMP; XORL aluK, aluTMP; BSWAPL aluTMP; MOVL aluTMP, (3*4 + i*16)(SP)
 #define combinedDecRound(i) \
 	MOVOU (16*i)(ks), T0;\
@@ -960,12 +960,12 @@ TEXT ·gcmAesDec(SB),0,$128-144
 
 	MOVQ productTable+0(FP), pTbl
 	MOVQ dst+8(FP), ptx
-	MOVQ src+32(FP), ctx
-	MOVQ src+40(FP), ptxLen
+	MOVQ src_base+32(FP), ctx
+	MOVQ src_len+40(FP), ptxLen
 	MOVQ ctr+56(FP), ctrPtr
 	MOVQ T+64(FP), tPtr
-	MOVQ KS+72(FP), ks
-	MOVQ nr+80(FP), NR
+	MOVQ ks_base+72(FP), ks
+	MOVQ ks_len+80(FP), NR
 
 	SHRQ $2, NR
 	DECQ NR
diff --git a/src/crypto/aes/modes.go b/src/crypto/aes/modes.go
new file mode 100644
index 0000000..1623fc1
--- /dev/null
+++ b/src/crypto/aes/modes.go
@@ -0,0 +1,37 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+	"crypto/cipher"
+)
+
+// gcmAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of GCM through the AEAD interface.
+// See crypto/cipher/gcm.go.
+type gcmAble interface {
+	NewGCM(size int) (cipher.AEAD, error)
+}
+
+// cbcEncAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of CBC encryption through the cipher.BlockMode interface.
+// See crypto/cipher/cbc.go.
+type cbcEncAble interface {
+	NewCBCEncrypter(iv []byte) cipher.BlockMode
+}
+
+// cbcDecAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of CBC decryption through the cipher.BlockMode interface.
+// See crypto/cipher/cbc.go.
+type cbcDecAble interface {
+	NewCBCDecrypter(iv []byte) cipher.BlockMode
+}
+
+// ctrAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of CTR through the cipher.Stream interface.
+// See crypto/cipher/ctr.go.
+type ctrAble interface {
+	NewCTR(iv []byte) cipher.Stream
+}
diff --git a/src/crypto/aes/modes_test.go b/src/crypto/aes/modes_test.go
new file mode 100644
index 0000000..8c2e5f0
--- /dev/null
+++ b/src/crypto/aes/modes_test.go
@@ -0,0 +1,112 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+	"crypto/cipher"
+	"testing"
+)
+
+// Check that the optimized implementations of cipher modes will
+// be picked up correctly.
+
+// testInterface can be asserted to check that a type originates
+// from this test group.
+type testInterface interface {
+	InAESPackage() bool
+}
+
+// testBlock implements the cipher.Block interface and any *Able
+// interfaces that need to be tested.
+type testBlock struct{}
+
+func (*testBlock) BlockSize() int      { return 0 }
+func (*testBlock) Encrypt(a, b []byte) {}
+func (*testBlock) Decrypt(a, b []byte) {}
+func (*testBlock) NewGCM(int) (cipher.AEAD, error) {
+	return &testAEAD{}, nil
+}
+func (*testBlock) NewCBCEncrypter([]byte) cipher.BlockMode {
+	return &testBlockMode{}
+}
+func (*testBlock) NewCBCDecrypter([]byte) cipher.BlockMode {
+	return &testBlockMode{}
+}
+func (*testBlock) NewCTR([]byte) cipher.Stream {
+	return &testStream{}
+}
+
+// testAEAD implements the cipher.AEAD interface.
+type testAEAD struct{}
+
+func (*testAEAD) NonceSize() int                         { return 0 }
+func (*testAEAD) Overhead() int                          { return 0 }
+func (*testAEAD) Seal(a, b, c, d []byte) []byte          { return []byte{} }
+func (*testAEAD) Open(a, b, c, d []byte) ([]byte, error) { return []byte{}, nil }
+func (*testAEAD) InAESPackage() bool                     { return true }
+
+// Test the gcmAble interface is detected correctly by the cipher package.
+func TestGCMAble(t *testing.T) {
+	b := cipher.Block(&testBlock{})
+	if _, ok := b.(gcmAble); !ok {
+		t.Fatalf("testBlock does not implement the gcmAble interface")
+	}
+	aead, err := cipher.NewGCM(b)
+	if err != nil {
+		t.Fatalf("%v", err)
+	}
+	if _, ok := aead.(testInterface); !ok {
+		t.Fatalf("cipher.NewGCM did not use gcmAble interface")
+	}
+}
+
+// testBlockMode implements the cipher.BlockMode interface.
+type testBlockMode struct{}
+
+func (*testBlockMode) BlockSize() int          { return 0 }
+func (*testBlockMode) CryptBlocks(a, b []byte) {}
+func (*testBlockMode) InAESPackage() bool      { return true }
+
+// Test the cbcEncAble interface is detected correctly by the cipher package.
+func TestCBCEncAble(t *testing.T) {
+	b := cipher.Block(&testBlock{})
+	if _, ok := b.(cbcEncAble); !ok {
+		t.Fatalf("testBlock does not implement the cbcEncAble interface")
+	}
+	bm := cipher.NewCBCEncrypter(b, []byte{})
+	if _, ok := bm.(testInterface); !ok {
+		t.Fatalf("cipher.NewCBCEncrypter did not use cbcEncAble interface")
+	}
+}
+
+// Test the cbcDecAble interface is detected correctly by the cipher package.
+func TestCBCDecAble(t *testing.T) {
+	b := cipher.Block(&testBlock{})
+	if _, ok := b.(cbcDecAble); !ok {
+		t.Fatalf("testBlock does not implement the cbcDecAble interface")
+	}
+	bm := cipher.NewCBCDecrypter(b, []byte{})
+	if _, ok := bm.(testInterface); !ok {
+		t.Fatalf("cipher.NewCBCDecrypter did not use cbcDecAble interface")
+	}
+}
+
+// testStream implements the cipher.Stream interface.
+type testStream struct{}
+
+func (*testStream) XORKeyStream(a, b []byte) {}
+func (*testStream) InAESPackage() bool       { return true }
+
+// Test the ctrAble interface is detected correctly by the cipher package.
+func TestCTRAble(t *testing.T) {
+	b := cipher.Block(&testBlock{})
+	if _, ok := b.(ctrAble); !ok {
+		t.Fatalf("testBlock does not implement the ctrAble interface")
+	}
+	s := cipher.NewCTR(b, []byte{})
+	if _, ok := s.(testInterface); !ok {
+		t.Fatalf("cipher.NewCTR did not use ctrAble interface")
+	}
+}
diff --git a/src/crypto/cipher/cbc.go b/src/crypto/cipher/cbc.go
index 241e122..0367d59 100644
--- a/src/crypto/cipher/cbc.go
+++ b/src/crypto/cipher/cbc.go
@@ -29,6 +29,14 @@ func newCBC(b Block, iv []byte) *cbc {
 
 type cbcEncrypter cbc
 
+// cbcEncAble is an interface implemented by ciphers that have a specific
+// optimized implementation of CBC encryption, like crypto/aes.
+// NewCBCEncrypter will check for this interface and return the specific
+// BlockMode if found.
+type cbcEncAble interface {
+	NewCBCEncrypter(iv []byte) BlockMode
+}
+
 // NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining
 // mode, using the given Block. The length of iv must be the same as the
 // Block's block size.
@@ -36,6 +44,9 @@ func NewCBCEncrypter(b Block, iv []byte) BlockMode {
 	if len(iv) != b.BlockSize() {
 		panic("cipher.NewCBCEncrypter: IV length must equal block size")
 	}
+	if cbc, ok := b.(cbcEncAble); ok {
+		return cbc.NewCBCEncrypter(iv)
+	}
 	return (*cbcEncrypter)(newCBC(b, iv))
 }
 
@@ -75,6 +86,14 @@ func (x *cbcEncrypter) SetIV(iv []byte) {
 
 type cbcDecrypter cbc
 
+// cbcDecAble is an interface implemented by ciphers that have a specific
+// optimized implementation of CBC decryption, like crypto/aes.
+// NewCBCDecrypter will check for this interface and return the specific
+// BlockMode if found.
+type cbcDecAble interface {
+	NewCBCDecrypter(iv []byte) BlockMode
+}
+
 // NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
 // mode, using the given Block. The length of iv must be the same as the
 // Block's block size and must match the iv used to encrypt the data.
@@ -82,6 +101,9 @@ func NewCBCDecrypter(b Block, iv []byte) BlockMode {
 	if len(iv) != b.BlockSize() {
 		panic("cipher.NewCBCDecrypter: IV length must equal block size")
 	}
+	if cbc, ok := b.(cbcDecAble); ok {
+		return cbc.NewCBCDecrypter(iv)
+	}
 	return (*cbcDecrypter)(newCBC(b, iv))
 }
 
diff --git a/src/crypto/cipher/cipher.go b/src/crypto/cipher/cipher.go
index 7d27fde..531ecad 100644
--- a/src/crypto/cipher/cipher.go
+++ b/src/crypto/cipher/cipher.go
@@ -9,8 +9,8 @@
 package cipher
 
 // A Block represents an implementation of block cipher
-// using a given key.  It provides the capability to encrypt
-// or decrypt individual blocks.  The mode implementations
+// using a given key. It provides the capability to encrypt
+// or decrypt individual blocks. The mode implementations
 // extend that capability to streams of blocks.
 type Block interface {
 	// BlockSize returns the cipher's block size.
diff --git a/src/crypto/cipher/cipher_test.go b/src/crypto/cipher/cipher_test.go
index 8da5bce..1faa7b8 100644
--- a/src/crypto/cipher/cipher_test.go
+++ b/src/crypto/cipher/cipher_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/crypto/cipher/ctr.go b/src/crypto/cipher/ctr.go
index 16baa6d..75f46cf 100644
--- a/src/crypto/cipher/ctr.go
+++ b/src/crypto/cipher/ctr.go
@@ -21,9 +21,19 @@ type ctr struct {
 
 const streamBufferSize = 512
 
+// ctrAble is an interface implemented by ciphers that have a specific optimized
+// implementation of CTR, like crypto/aes. NewCTR will check for this interface
+// and return the specific Stream if found.
+type ctrAble interface {
+	NewCTR(iv []byte) Stream
+}
+
 // NewCTR returns a Stream which encrypts/decrypts using the given Block in
 // counter mode. The length of iv must be the same as the Block's block size.
 func NewCTR(block Block, iv []byte) Stream {
+	if ctr, ok := block.(ctrAble); ok {
+		return ctr.NewCTR(iv)
+	}
 	if len(iv) != block.BlockSize() {
 		panic("cipher.NewCTR: IV length must equal block size")
 	}
diff --git a/src/crypto/cipher/example_test.go b/src/crypto/cipher/example_test.go
index f6cc386..9abe782 100644
--- a/src/crypto/cipher/example_test.go
+++ b/src/crypto/cipher/example_test.go
@@ -44,9 +44,9 @@ func ExampleNewGCMDecrypter() {
 	// The key argument should be the AES key, either 16 or 32 bytes
 	// to select AES-128 or AES-256.
 	key := []byte("AES256Key-32Characters1234567890")
-	ciphertext, _ := hex.DecodeString("f90fbef747e7212ad7410d0eee2d965de7e890471695cddd2a5bc0ef5da1d04ad8147b62141ad6e4914aee8c512f64fba9037603d41de0d50b718bd665f019cdcd")
+	ciphertext, _ := hex.DecodeString("1019aa66cd7c024f9efd0038899dae1973ee69427f5a6579eba292ffe1b5a260")
 
-	nonce, _ := hex.DecodeString("bb8ef84243d2ee95a41c6c57")
+	nonce, _ := hex.DecodeString("37b8e8a308c354048d245f6d")
 
 	block, err := aes.NewCipher(key)
 	if err != nil {
@@ -63,7 +63,8 @@ func ExampleNewGCMDecrypter() {
 		panic(err.Error())
 	}
 
-	fmt.Printf("%s\n", string(plaintext))
+	fmt.Printf("%s\n", plaintext)
+	// Output: exampleplaintext
 }
 
 func ExampleNewCBCDecrypter() {
diff --git a/src/crypto/cipher/xor.go b/src/crypto/cipher/xor.go
index f88dc89..01ca0a9 100644
--- a/src/crypto/cipher/xor.go
+++ b/src/crypto/cipher/xor.go
@@ -10,7 +10,7 @@ import (
 )
 
 const wordSize = int(unsafe.Sizeof(uintptr(0)))
-const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64"
+const supportsUnaligned = runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "s390x"
 
 // fastXORBytes xors in bulk. It only works on architectures that
 // support unaligned read/writes.
diff --git a/src/crypto/cipher/xor_test.go b/src/crypto/cipher/xor_test.go
index cc1c9d7..d9187eb 100644
--- a/src/crypto/cipher/xor_test.go
+++ b/src/crypto/cipher/xor_test.go
@@ -19,7 +19,7 @@ func TestXOR(t *testing.T) {
 				d2 := make([]byte, 1024+alignD)[alignD:]
 				xorBytes(d1, p, q)
 				safeXORBytes(d2, p, q)
-				if bytes.Compare(d1, d2) != 0 {
+				if !bytes.Equal(d1, d2) {
 					t.Error("not equal")
 				}
 			}
diff --git a/src/crypto/des/block.go b/src/crypto/des/block.go
index 26355a2..99338d6 100644
--- a/src/crypto/des/block.go
+++ b/src/crypto/des/block.go
@@ -72,7 +72,7 @@ func init() {
 		for i := 0; i < 4; i++ {
 			for j := 0; j < 16; j++ {
 				f := uint64(sBoxes[s][i][j]) << (4 * (7 - uint(s)))
-				f = permuteBlock(uint64(f), permutationFunction[:])
+				f = permuteBlock(f, permutationFunction[:])
 				feistelBox[s][16*i+j] = uint32(f)
 			}
 		}
diff --git a/src/crypto/dsa/dsa.go b/src/crypto/dsa/dsa.go
index 9f414a4..e9b6a0c 100644
--- a/src/crypto/dsa/dsa.go
+++ b/src/crypto/dsa/dsa.go
@@ -52,7 +52,7 @@ const numMRTests = 64
 
 // GenerateParameters puts a random, valid set of DSA parameters into params.
 // This function can take many seconds, even on fast machines.
-func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) (err error) {
+func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) error {
 	// This function doesn't follow FIPS 186-3 exactly in that it doesn't
 	// use a verification seed to generate the primes. The verification
 	// seed doesn't appear to be exported or used by other code and
@@ -87,9 +87,8 @@ func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes
 
 GeneratePrimes:
 	for {
-		_, err = io.ReadFull(rand, qBytes)
-		if err != nil {
-			return
+		if _, err := io.ReadFull(rand, qBytes); err != nil {
+			return err
 		}
 
 		qBytes[len(qBytes)-1] |= 1
@@ -101,9 +100,8 @@ GeneratePrimes:
 		}
 
 		for i := 0; i < 4*L; i++ {
-			_, err = io.ReadFull(rand, pBytes)
-			if err != nil {
-				return
+			if _, err := io.ReadFull(rand, pBytes); err != nil {
+				return err
 			}
 
 			pBytes[len(pBytes)-1] |= 1
@@ -142,7 +140,7 @@ GeneratePrimes:
 		}
 
 		params.G = g
-		return
+		return nil
 	}
 }
 
diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go
index e54488c..72fb499 100644
--- a/src/crypto/ecdsa/ecdsa.go
+++ b/src/crypto/ecdsa/ecdsa.go
@@ -97,17 +97,17 @@ func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error)
 }
 
 // GenerateKey generates a public and private key pair.
-func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error) {
+func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
 	k, err := randFieldElement(c, rand)
 	if err != nil {
-		return
+		return nil, err
 	}
 
-	priv = new(PrivateKey)
+	priv := new(PrivateKey)
 	priv.PublicKey.Curve = c
 	priv.D = k
 	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
-	return
+	return priv, nil
 }
 
 // hashToInt converts a hash value to an integer. There is some disagreement
@@ -143,10 +143,11 @@ func fermatInverse(k, N *big.Int) *big.Int {
 
 var errZeroParam = errors.New("zero parameter")
 
-// Sign signs an arbitrary length hash (which should be the result of hashing a
-// larger message) using the private key, priv. It returns the signature as a
-// pair of integers. The security of the private key depends on the entropy of
-// rand.
+// Sign signs a hash (which should be the result of hashing a larger message)
+// using the private key, priv. If the hash is longer than the bit-length of the
+// private key's curve order, the hash will be truncated to that length.  It
+// returns the signature as a 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
@@ -228,7 +229,7 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
 	c := pub.Curve
 	N := c.Params().N
 
-	if r.Sign() == 0 || s.Sign() == 0 {
+	if r.Sign() <= 0 || s.Sign() <= 0 {
 		return false
 	}
 	if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
diff --git a/src/crypto/ecdsa/ecdsa_test.go b/src/crypto/ecdsa/ecdsa_test.go
index 62a3fcc..fc25fd7 100644
--- a/src/crypto/ecdsa/ecdsa_test.go
+++ b/src/crypto/ecdsa/ecdsa_test.go
@@ -130,7 +130,7 @@ func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
 	}
 
 	if r0.Cmp(r1) == 0 {
-		t.Errorf("%s: the nonce used for two diferent messages was the same", tag)
+		t.Errorf("%s: the nonce used for two different messages was the same", tag)
 	}
 }
 
@@ -296,3 +296,26 @@ func TestVectors(t *testing.T) {
 		}
 	}
 }
+
+func testNegativeInputs(t *testing.T, curve elliptic.Curve, tag string) {
+	key, err := GenerateKey(curve, rand.Reader)
+	if err != nil {
+		t.Errorf("failed to generate key for %q", tag)
+	}
+
+	var hash [32]byte
+	r := new(big.Int).SetInt64(1)
+	r.Lsh(r, 550 /* larger than any supported curve */)
+	r.Neg(r)
+
+	if Verify(&key.PublicKey, hash[:], r, r) {
+		t.Errorf("bogus signature accepted for %q", tag)
+	}
+}
+
+func TestNegativeInputs(t *testing.T) {
+	testNegativeInputs(t, elliptic.P224(), "p224")
+	testNegativeInputs(t, elliptic.P256(), "p256")
+	testNegativeInputs(t, elliptic.P384(), "p384")
+	testNegativeInputs(t, elliptic.P521(), "p521")
+}
diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go
index 2d3fac7..de266ca 100644
--- a/src/crypto/elliptic/p224.go
+++ b/src/crypto/elliptic/p224.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/crypto/elliptic/p224_test.go b/src/crypto/elliptic/p224_test.go
index 4b26d16..8b4fa04 100644
--- a/src/crypto/elliptic/p224_test.go
+++ b/src/crypto/elliptic/p224_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go
index 5103e86..05a3311 100644
--- a/src/crypto/elliptic/p256.go
+++ b/src/crypto/elliptic/p256.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -1056,7 +1056,7 @@ func p256ScalarBaseMult(xOut, yOut, zOut *[p256Limbs]uint32, scalar *[32]uint8)
 			p256CopyConditional(yOut, &ty, mask)
 			p256CopyConditional(zOut, &tz, mask)
 			// If p was not zero, then n is now non-zero.
-			nIsInfinityMask &= ^pIsNoninfiniteMask
+			nIsInfinityMask &^= pIsNoninfiniteMask
 		}
 	}
 }
@@ -1136,7 +1136,7 @@ func p256ScalarMult(xOut, yOut, zOut, x, y *[p256Limbs]uint32, scalar *[32]uint8
 		p256CopyConditional(xOut, &tx, mask)
 		p256CopyConditional(yOut, &ty, mask)
 		p256CopyConditional(zOut, &tz, mask)
-		nIsInfinityMask &= ^pIsNoninfiniteMask
+		nIsInfinityMask &^= pIsNoninfiniteMask
 	}
 }
 
diff --git a/src/crypto/elliptic/p256_amd64.go b/src/crypto/elliptic/p256_amd64.go
index 586cd10..66b7cf8 100644
--- a/src/crypto/elliptic/p256_amd64.go
+++ b/src/crypto/elliptic/p256_amd64.go
@@ -66,7 +66,7 @@ func p256NegCond(val []uint64, cond int)
 // if cond == 0 res <- b; else res <- a
 func p256MovCond(res, a, b []uint64, cond int)
 
-// Endianess swap
+// Endianness swap
 func p256BigToLittle(res []uint64, in []byte)
 func p256LittleToBig(res []byte, in []uint64)
 
@@ -93,10 +93,14 @@ func p256PointAddAsm(res, in1, in2 []uint64)
 func p256PointDoubleAsm(res, in []uint64)
 
 func (curve p256Curve) Inverse(k *big.Int) *big.Int {
+	if k.Sign() < 0 {
+		// This should never happen.
+		k = new(big.Int).Neg(k)
+	}
+
 	if k.Cmp(p256.N) >= 0 {
 		// This should never happen.
-		reducedK := new(big.Int).Mod(k, p256.N)
-		k = reducedK
+		k = new(big.Int).Mod(k, p256.N)
 	}
 
 	// table will store precomputed powers of x. The four words at index
diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go
index 3b41cde..a748107 100644
--- a/src/crypto/hmac/hmac.go
+++ b/src/crypto/hmac/hmac.go
@@ -37,26 +37,16 @@ import (
 type hmac struct {
 	size         int
 	blocksize    int
-	key, tmp     []byte
+	opad, ipad   []byte
 	outer, inner hash.Hash
 }
 
-func (h *hmac) tmpPad(xor byte) {
-	for i, k := range h.key {
-		h.tmp[i] = xor ^ k
-	}
-	for i := len(h.key); i < h.blocksize; i++ {
-		h.tmp[i] = xor
-	}
-}
-
 func (h *hmac) Sum(in []byte) []byte {
 	origLen := len(in)
 	in = h.inner.Sum(in)
-	h.tmpPad(0x5c)
-	copy(h.tmp[h.blocksize:], in[origLen:])
 	h.outer.Reset()
-	h.outer.Write(h.tmp)
+	h.outer.Write(h.opad)
+	h.outer.Write(in[origLen:])
 	return h.outer.Sum(in[:origLen])
 }
 
@@ -70,8 +60,7 @@ func (h *hmac) BlockSize() int { return h.blocksize }
 
 func (h *hmac) Reset() {
 	h.inner.Reset()
-	h.tmpPad(0x36)
-	h.inner.Write(h.tmp[:h.blocksize])
+	h.inner.Write(h.ipad)
 }
 
 // New returns a new HMAC hash using the given hash.Hash type and key.
@@ -81,15 +70,22 @@ func New(h func() hash.Hash, key []byte) hash.Hash {
 	hm.inner = h()
 	hm.size = hm.inner.Size()
 	hm.blocksize = hm.inner.BlockSize()
-	hm.tmp = make([]byte, hm.blocksize+hm.size)
+	hm.ipad = make([]byte, hm.blocksize)
+	hm.opad = make([]byte, hm.blocksize)
 	if len(key) > hm.blocksize {
 		// If key is too big, hash it.
 		hm.outer.Write(key)
 		key = hm.outer.Sum(nil)
 	}
-	hm.key = make([]byte, len(key))
-	copy(hm.key, key)
-	hm.Reset()
+	copy(hm.ipad, key)
+	copy(hm.opad, key)
+	for i := range hm.ipad {
+		hm.ipad[i] ^= 0x36
+	}
+	for i := range hm.opad {
+		hm.opad[i] ^= 0x5c
+	}
+	hm.inner.Write(hm.ipad)
 	return hm
 }
 
diff --git a/src/crypto/hmac/hmac_test.go b/src/crypto/hmac/hmac_test.go
index e80b7e0..aac9aa9 100644
--- a/src/crypto/hmac/hmac_test.go
+++ b/src/crypto/hmac/hmac_test.go
@@ -568,3 +568,29 @@ func TestEqual(t *testing.T) {
 		t.Error("Equal accepted unequal slices")
 	}
 }
+
+func BenchmarkHMACSHA256_1K(b *testing.B) {
+	key := make([]byte, 32)
+	buf := make([]byte, 1024)
+	h := New(sha256.New, key)
+	b.SetBytes(int64(len(buf)))
+	for i := 0; i < b.N; i++ {
+		h.Write(buf)
+		h.Reset()
+		mac := h.Sum(nil)
+		buf[0] = mac[0]
+	}
+}
+
+func BenchmarkHMACSHA256_32(b *testing.B) {
+	key := make([]byte, 32)
+	buf := make([]byte, 32)
+	h := New(sha256.New, key)
+	b.SetBytes(int64(len(buf)))
+	for i := 0; i < b.N; i++ {
+		h.Write(buf)
+		h.Reset()
+		mac := h.Sum(nil)
+		buf[0] = mac[0]
+	}
+}
diff --git a/src/crypto/md5/gen.go b/src/crypto/md5/gen.go
index 8cd0a63..178fad1 100644
--- a/src/crypto/md5/gen.go
+++ b/src/crypto/md5/gen.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/crypto/md5/md5.go b/src/crypto/md5/md5.go
index a3550cb..ce58d5e 100644
--- a/src/crypto/md5/md5.go
+++ b/src/crypto/md5/md5.go
@@ -89,7 +89,7 @@ func (d0 *digest) Sum(in []byte) []byte {
 }
 
 func (d *digest) checkSum() [Size]byte {
-	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
+	// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
 	len := d.len
 	var tmp [64]byte
 	tmp[0] = 0x80
diff --git a/src/crypto/md5/md5block_arm.s b/src/crypto/md5/md5block_arm.s
index f1f0f67..54d02b7 100644
--- a/src/crypto/md5/md5block_arm.s
+++ b/src/crypto/md5/md5block_arm.s
@@ -46,7 +46,7 @@ loop:
 	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
+	// memmove(to=4(R13), from=8(R13), n=12(R13)) - Corrupts all registers
 	MOVW	$buf, Rtable	// to
 	MOVW	$64, Rc0		// n
 	MOVM.IB	[Rtable,Rdata,Rc0], (R13)
diff --git a/src/crypto/md5/md5block_decl.go b/src/crypto/md5/md5block_decl.go
index d7956a6..1e6f6e6 100644
--- a/src/crypto/md5/md5block_decl.go
+++ b/src/crypto/md5/md5block_decl.go
@@ -1,8 +1,8 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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 arm
+// +build amd64 amd64p32 386 arm ppc64le s390x
 
 package md5
 
diff --git a/src/crypto/md5/md5block_generic.go b/src/crypto/md5/md5block_generic.go
index 263463e..726e09b 100644
--- a/src/crypto/md5/md5block_generic.go
+++ b/src/crypto/md5/md5block_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 !amd64,!amd64p32,!386,!arm
+// +build !amd64,!amd64p32,!386,!arm,!ppc64le,!s390x
 
 package md5
 
diff --git a/src/crypto/md5/md5block_ppc64le.s b/src/crypto/md5/md5block_ppc64le.s
new file mode 100644
index 0000000..3b95da5
--- /dev/null
+++ b/src/crypto/md5/md5block_ppc64le.s
@@ -0,0 +1,192 @@
+// Original source:
+//	http://www.zorinaq.com/papers/md5-amd64.html
+//	http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// MD5 optimized for ppc64le using Go's assembler for
+// ppc64le, based on md5block_amd64.s implementation by
+// the Go authors.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+#include "textflag.h"
+
+// TODO: Could be updated for ppc64 big endian
+// by using the correct byte reverse instruction.
+// Changes required in the Go assembler to make
+// that instruction work.
+
+#define MOVE_LITTLE_ENDIAN MOVWZ
+
+TEXT ·block(SB),NOSPLIT,$0-32
+	MOVD	dig+0(FP), R10
+	MOVD	p+8(FP), R6
+	MOVD	p_len+16(FP), R5
+	SLD	$6, R5
+	SRD	$6, R5
+	ADD	R6, R5, R7
+
+	MOVWZ	0(R10), R22
+	MOVWZ	4(R10), R3
+	MOVWZ	8(R10), R4
+	MOVWZ	12(R10), R5
+	CMP	R6, R7
+	BEQ	end
+
+loop:
+	MOVWZ	R22, R14
+	MOVWZ	R3, R15
+	MOVWZ	R4, R16
+	MOVWZ	R5, R17
+
+	MOVE_LITTLE_ENDIAN	0(R6), R8
+	MOVWZ	R5, R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+	XOR	c, R9; \
+	ADD	$const, a; \
+	ADD	R8, a; \
+	AND	b, R9; \
+	XOR	d, R9; \
+	MOVE_LITTLE_ENDIAN	(index*4)(R6), R8; \
+	ADD	R9, a; \
+	RLWMI	$shift, a, $0xffffffff, a; \
+	MOVWZ	c, R9; \
+	ADD	b, a; \
+	MOVWZ	a, a
+
+	ROUND1(R22,R3,R4,R5, 1,0xd76aa478, 7);
+	ROUND1(R5,R22,R3,R4, 2,0xe8c7b756,12);
+	ROUND1(R4,R5,R22,R3, 3,0x242070db,17);
+	ROUND1(R3,R4,R5,R22, 4,0xc1bdceee,22);
+	ROUND1(R22,R3,R4,R5, 5,0xf57c0faf, 7);
+	ROUND1(R5,R22,R3,R4, 6,0x4787c62a,12);
+	ROUND1(R4,R5,R22,R3, 7,0xa8304613,17);
+	ROUND1(R3,R4,R5,R22, 8,0xfd469501,22);
+	ROUND1(R22,R3,R4,R5, 9,0x698098d8, 7);
+	ROUND1(R5,R22,R3,R4,10,0x8b44f7af,12);
+	ROUND1(R4,R5,R22,R3,11,0xffff5bb1,17);
+	ROUND1(R3,R4,R5,R22,12,0x895cd7be,22);
+	ROUND1(R22,R3,R4,R5,13,0x6b901122, 7);
+	ROUND1(R5,R22,R3,R4,14,0xfd987193,12);
+	ROUND1(R4,R5,R22,R3,15,0xa679438e,17);
+	ROUND1(R3,R4,R5,R22, 0,0x49b40821,22);
+
+	MOVE_LITTLE_ENDIAN	(1*4)(R6), R8
+	MOVWZ	R5, R9
+	MOVWZ	R5, R10
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+	XOR	$0xffffffff, R9; \ // NOTW R9
+	ADD	$const, a; \
+	ADD	R8, a; \
+	AND	b, R10; \
+	AND	c, R9; \
+	MOVE_LITTLE_ENDIAN	(index*4)(R6), R8; \
+	OR	R9, R10; \
+	MOVWZ	c, R9; \
+	ADD	R10, a; \
+	MOVWZ	c, R10; \
+	RLWMI	$shift, a, $0xffffffff, a; \
+	ADD	b, a; \
+	MOVWZ	a, a
+
+	ROUND2(R22,R3,R4,R5, 6,0xf61e2562, 5);
+	ROUND2(R5,R22,R3,R4,11,0xc040b340, 9);
+	ROUND2(R4,R5,R22,R3, 0,0x265e5a51,14);
+	ROUND2(R3,R4,R5,R22, 5,0xe9b6c7aa,20);
+	ROUND2(R22,R3,R4,R5,10,0xd62f105d, 5);
+	ROUND2(R5,R22,R3,R4,15, 0x2441453, 9);
+	ROUND2(R4,R5,R22,R3, 4,0xd8a1e681,14);
+	ROUND2(R3,R4,R5,R22, 9,0xe7d3fbc8,20);
+	ROUND2(R22,R3,R4,R5,14,0x21e1cde6, 5);
+	ROUND2(R5,R22,R3,R4, 3,0xc33707d6, 9);
+	ROUND2(R4,R5,R22,R3, 8,0xf4d50d87,14);
+	ROUND2(R3,R4,R5,R22,13,0x455a14ed,20);
+	ROUND2(R22,R3,R4,R5, 2,0xa9e3e905, 5);
+	ROUND2(R5,R22,R3,R4, 7,0xfcefa3f8, 9);
+	ROUND2(R4,R5,R22,R3,12,0x676f02d9,14);
+	ROUND2(R3,R4,R5,R22, 0,0x8d2a4c8a,20);
+
+	MOVE_LITTLE_ENDIAN	(5*4)(R6), R8
+	MOVWZ	R4, R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+	ADD	$const, a; \
+	ADD	R8, a; \
+	MOVE_LITTLE_ENDIAN	(index*4)(R6), R8; \
+	XOR	d, R9; \
+	XOR	b, R9; \
+	ADD	R9, a; \
+	RLWMI	$shift, a, $0xffffffff, a; \
+	MOVWZ	b, R9; \
+	ADD	b, a; \
+	MOVWZ	a, a
+
+	ROUND3(R22,R3,R4,R5, 8,0xfffa3942, 4);
+	ROUND3(R5,R22,R3,R4,11,0x8771f681,11);
+	ROUND3(R4,R5,R22,R3,14,0x6d9d6122,16);
+	ROUND3(R3,R4,R5,R22, 1,0xfde5380c,23);
+	ROUND3(R22,R3,R4,R5, 4,0xa4beea44, 4);
+	ROUND3(R5,R22,R3,R4, 7,0x4bdecfa9,11);
+	ROUND3(R4,R5,R22,R3,10,0xf6bb4b60,16);
+	ROUND3(R3,R4,R5,R22,13,0xbebfbc70,23);
+	ROUND3(R22,R3,R4,R5, 0,0x289b7ec6, 4);
+	ROUND3(R5,R22,R3,R4, 3,0xeaa127fa,11);
+	ROUND3(R4,R5,R22,R3, 6,0xd4ef3085,16);
+	ROUND3(R3,R4,R5,R22, 9, 0x4881d05,23);
+	ROUND3(R22,R3,R4,R5,12,0xd9d4d039, 4);
+	ROUND3(R5,R22,R3,R4,15,0xe6db99e5,11);
+	ROUND3(R4,R5,R22,R3, 2,0x1fa27cf8,16);
+	ROUND3(R3,R4,R5,R22, 0,0xc4ac5665,23);
+
+	MOVE_LITTLE_ENDIAN	(0*4)(R6), R8
+	MOVWZ	$0xffffffff, R9
+	XOR	R5, R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+	ADD	$const, a; \
+	ADD	R8, a; \
+	OR	b, R9; \
+	XOR	c, R9; \
+	ADD	R9, a; \
+	MOVE_LITTLE_ENDIAN	(index*4)(R6), R8; \
+	MOVWZ	$0xffffffff, R9; \
+	RLWMI	$shift, a, $0xffffffff, a; \
+	XOR	c, R9; \
+	ADD	b, a; \
+	MOVWZ	a, a
+
+	ROUND4(R22,R3,R4,R5, 7,0xf4292244, 6);
+	ROUND4(R5,R22,R3,R4,14,0x432aff97,10);
+	ROUND4(R4,R5,R22,R3, 5,0xab9423a7,15);
+	ROUND4(R3,R4,R5,R22,12,0xfc93a039,21);
+	ROUND4(R22,R3,R4,R5, 3,0x655b59c3, 6);
+	ROUND4(R5,R22,R3,R4,10,0x8f0ccc92,10);
+	ROUND4(R4,R5,R22,R3, 1,0xffeff47d,15);
+	ROUND4(R3,R4,R5,R22, 8,0x85845dd1,21);
+	ROUND4(R22,R3,R4,R5,15,0x6fa87e4f, 6);
+	ROUND4(R5,R22,R3,R4, 6,0xfe2ce6e0,10);
+	ROUND4(R4,R5,R22,R3,13,0xa3014314,15);
+	ROUND4(R3,R4,R5,R22, 4,0x4e0811a1,21);
+	ROUND4(R22,R3,R4,R5,11,0xf7537e82, 6);
+	ROUND4(R5,R22,R3,R4, 2,0xbd3af235,10);
+	ROUND4(R4,R5,R22,R3, 9,0x2ad7d2bb,15);
+	ROUND4(R3,R4,R5,R22, 0,0xeb86d391,21);
+
+	ADD	R14, R22
+	ADD	R15, R3
+	ADD	R16, R4
+	ADD	R17, R5
+	ADD	$64, R6
+	CMP	R6, R7
+	BLT	loop
+
+end:
+	MOVD	dig+0(FP), R10
+	MOVWZ	R22, 0(R10)
+	MOVWZ	R3, 4(R10)
+	MOVWZ	R4, 8(R10)
+	MOVWZ	R5, 12(R10)
+	RET
diff --git a/src/crypto/md5/md5block_s390x.s b/src/crypto/md5/md5block_s390x.s
new file mode 100644
index 0000000..68f501c
--- /dev/null
+++ b/src/crypto/md5/md5block_s390x.s
@@ -0,0 +1,175 @@
+// Original source:
+//	http://www.zorinaq.com/papers/md5-amd64.html
+//	http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// MD5 adapted for s390x using Go's assembler for
+// s390x, based on md5block_amd64.s implementation by
+// the Go authors.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+#include "textflag.h"
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB),NOSPLIT,$16-32
+	MOVD	dig+0(FP), R1
+	MOVD	p+8(FP), R6
+	MOVD	p_len+16(FP), R5
+	AND	$-64, R5
+	LAY	(R6)(R5*1), R7
+
+	LMY	0(R1), R2, R5
+	CMPBEQ	R6, R7, end
+
+loop:
+	STMY	R2, R5, tmp-16(SP)
+
+	MOVWBR	0(R6), R8
+	MOVWZ	R5, R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+	XOR	c, R9; \
+	ADD	$const, a; \
+	ADD	R8, a; \
+	MOVWBR	(index*4)(R6), R8; \
+	AND	b, R9; \
+	XOR	d, R9; \
+	ADD	R9, a; \
+	RLL	$shift, a; \
+	MOVWZ	c, R9; \
+	ADD	b, a
+
+	ROUND1(R2,R3,R4,R5, 1,0xd76aa478, 7);
+	ROUND1(R5,R2,R3,R4, 2,0xe8c7b756,12);
+	ROUND1(R4,R5,R2,R3, 3,0x242070db,17);
+	ROUND1(R3,R4,R5,R2, 4,0xc1bdceee,22);
+	ROUND1(R2,R3,R4,R5, 5,0xf57c0faf, 7);
+	ROUND1(R5,R2,R3,R4, 6,0x4787c62a,12);
+	ROUND1(R4,R5,R2,R3, 7,0xa8304613,17);
+	ROUND1(R3,R4,R5,R2, 8,0xfd469501,22);
+	ROUND1(R2,R3,R4,R5, 9,0x698098d8, 7);
+	ROUND1(R5,R2,R3,R4,10,0x8b44f7af,12);
+	ROUND1(R4,R5,R2,R3,11,0xffff5bb1,17);
+	ROUND1(R3,R4,R5,R2,12,0x895cd7be,22);
+	ROUND1(R2,R3,R4,R5,13,0x6b901122, 7);
+	ROUND1(R5,R2,R3,R4,14,0xfd987193,12);
+	ROUND1(R4,R5,R2,R3,15,0xa679438e,17);
+	ROUND1(R3,R4,R5,R2, 0,0x49b40821,22);
+
+	MOVWBR	(1*4)(R6), R8
+	MOVWZ	R5, R9
+	MOVWZ	R5, R1
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+	XOR	$0xffffffff, R9; \ // NOTW R9
+	ADD	$const, a; \
+	ADD	R8, a; \
+	MOVWBR	(index*4)(R6), R8; \
+	AND	b, R1; \
+	AND	c, R9; \
+	OR	R9, R1; \
+	MOVWZ	c, R9; \
+	ADD	R1, a; \
+	MOVWZ	c, R1; \
+	RLL	$shift,	a; \
+	ADD	b, a
+
+	ROUND2(R2,R3,R4,R5, 6,0xf61e2562, 5);
+	ROUND2(R5,R2,R3,R4,11,0xc040b340, 9);
+	ROUND2(R4,R5,R2,R3, 0,0x265e5a51,14);
+	ROUND2(R3,R4,R5,R2, 5,0xe9b6c7aa,20);
+	ROUND2(R2,R3,R4,R5,10,0xd62f105d, 5);
+	ROUND2(R5,R2,R3,R4,15, 0x2441453, 9);
+	ROUND2(R4,R5,R2,R3, 4,0xd8a1e681,14);
+	ROUND2(R3,R4,R5,R2, 9,0xe7d3fbc8,20);
+	ROUND2(R2,R3,R4,R5,14,0x21e1cde6, 5);
+	ROUND2(R5,R2,R3,R4, 3,0xc33707d6, 9);
+	ROUND2(R4,R5,R2,R3, 8,0xf4d50d87,14);
+	ROUND2(R3,R4,R5,R2,13,0x455a14ed,20);
+	ROUND2(R2,R3,R4,R5, 2,0xa9e3e905, 5);
+	ROUND2(R5,R2,R3,R4, 7,0xfcefa3f8, 9);
+	ROUND2(R4,R5,R2,R3,12,0x676f02d9,14);
+	ROUND2(R3,R4,R5,R2, 0,0x8d2a4c8a,20);
+
+	MOVWBR	(5*4)(R6), R8
+	MOVWZ	R4, R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+	ADD	$const, a; \
+	ADD	R8, a; \
+	MOVWBR	(index*4)(R6), R8; \
+	XOR	d, R9; \
+	XOR	b, R9; \
+	ADD	R9, a; \
+	RLL	$shift, a; \
+	MOVWZ	b, R9; \
+	ADD	b, a
+
+	ROUND3(R2,R3,R4,R5, 8,0xfffa3942, 4);
+	ROUND3(R5,R2,R3,R4,11,0x8771f681,11);
+	ROUND3(R4,R5,R2,R3,14,0x6d9d6122,16);
+	ROUND3(R3,R4,R5,R2, 1,0xfde5380c,23);
+	ROUND3(R2,R3,R4,R5, 4,0xa4beea44, 4);
+	ROUND3(R5,R2,R3,R4, 7,0x4bdecfa9,11);
+	ROUND3(R4,R5,R2,R3,10,0xf6bb4b60,16);
+	ROUND3(R3,R4,R5,R2,13,0xbebfbc70,23);
+	ROUND3(R2,R3,R4,R5, 0,0x289b7ec6, 4);
+	ROUND3(R5,R2,R3,R4, 3,0xeaa127fa,11);
+	ROUND3(R4,R5,R2,R3, 6,0xd4ef3085,16);
+	ROUND3(R3,R4,R5,R2, 9, 0x4881d05,23);
+	ROUND3(R2,R3,R4,R5,12,0xd9d4d039, 4);
+	ROUND3(R5,R2,R3,R4,15,0xe6db99e5,11);
+	ROUND3(R4,R5,R2,R3, 2,0x1fa27cf8,16);
+	ROUND3(R3,R4,R5,R2, 0,0xc4ac5665,23);
+
+	MOVWBR	(0*4)(R6), R8
+	MOVWZ	$0xffffffff, R9
+	XOR	R5, R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+	ADD	$const, a; \
+	ADD	R8, a; \
+	MOVWBR	(index*4)(R6), R8; \
+	OR	b, R9; \
+	XOR	c, R9; \
+	ADD	R9, a; \
+	MOVWZ	$0xffffffff, R9; \
+	RLL	$shift,	a; \
+	XOR	c, R9; \
+	ADD	b, a
+
+	ROUND4(R2,R3,R4,R5, 7,0xf4292244, 6);
+	ROUND4(R5,R2,R3,R4,14,0x432aff97,10);
+	ROUND4(R4,R5,R2,R3, 5,0xab9423a7,15);
+	ROUND4(R3,R4,R5,R2,12,0xfc93a039,21);
+	ROUND4(R2,R3,R4,R5, 3,0x655b59c3, 6);
+	ROUND4(R5,R2,R3,R4,10,0x8f0ccc92,10);
+	ROUND4(R4,R5,R2,R3, 1,0xffeff47d,15);
+	ROUND4(R3,R4,R5,R2, 8,0x85845dd1,21);
+	ROUND4(R2,R3,R4,R5,15,0x6fa87e4f, 6);
+	ROUND4(R5,R2,R3,R4, 6,0xfe2ce6e0,10);
+	ROUND4(R4,R5,R2,R3,13,0xa3014314,15);
+	ROUND4(R3,R4,R5,R2, 4,0x4e0811a1,21);
+	ROUND4(R2,R3,R4,R5,11,0xf7537e82, 6);
+	ROUND4(R5,R2,R3,R4, 2,0xbd3af235,10);
+	ROUND4(R4,R5,R2,R3, 9,0x2ad7d2bb,15);
+	ROUND4(R3,R4,R5,R2, 0,0xeb86d391,21);
+
+	MOVWZ	tmp-16(SP), R1
+	ADD	R1, R2
+	MOVWZ	tmp-12(SP), R1
+	ADD	R1, R3
+	MOVWZ	tmp-8(SP), R1
+	ADD	R1, R4
+	MOVWZ	tmp-4(SP), R1
+	ADD	R1, R5
+
+	LA	64(R6), R6
+	CMPBLT	R6, R7, loop
+
+end:
+	MOVD	dig+0(FP), R1
+	STMY	R2, R5, 0(R1)
+	RET
diff --git a/src/crypto/rand/eagain.go b/src/crypto/rand/eagain.go
index 2c853d0..7ed2f47 100644
--- a/src/crypto/rand/eagain.go
+++ b/src/crypto/rand/eagain.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/crypto/rand/example_test.go b/src/crypto/rand/example_test.go
index 8a27173..ed18647 100644
--- a/src/crypto/rand/example_test.go
+++ b/src/crypto/rand/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/crypto/rand/rand.go b/src/crypto/rand/rand.go
index ee32fa0..6f7523d 100644
--- a/src/crypto/rand/rand.go
+++ b/src/crypto/rand/rand.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -11,8 +11,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 OpenBSD, Reader uses getentropy(2).
+// On other Unix-like systems, Reader reads from /dev/urandom.
 // 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 7d6d9e8..472daa7 100644
--- a/src/crypto/rand/rand_linux.go
+++ b/src/crypto/rand/rand_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/crypto/rand/rand_openbsd.go b/src/crypto/rand/rand_openbsd.go
new file mode 100644
index 0000000..9cc39f7
--- /dev/null
+++ b/src/crypto/rand/rand_openbsd.go
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors. 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
+
+import (
+	"internal/syscall/unix"
+)
+
+func init() {
+	altGetRandom = getRandomOpenBSD
+}
+
+func getRandomOpenBSD(p []byte) (ok bool) {
+	// getentropy(2) returns a maximum of 256 bytes per call
+	for i := 0; i < len(p); i += 256 {
+		end := i + 256
+		if len(p) < end {
+			end = len(p)
+		}
+		err := unix.GetEntropy(p[i:end])
+		if err != nil {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/crypto/rand/rand_test.go b/src/crypto/rand/rand_test.go
index e46e61d..e45f58e 100644
--- a/src/crypto/rand/rand_test.go
+++ b/src/crypto/rand/rand_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go
index 75c36e0..631972b 100644
--- a/src/crypto/rand/rand_unix.go
+++ b/src/crypto/rand/rand_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -84,7 +84,7 @@ func (hr hideAgainReader) Read(p []byte) (n int, err error) {
 // systems without a reliable /dev/urandom.
 
 // newReader returns a new pseudorandom generator that
-// seeds itself by reading from entropy.  If entropy == nil,
+// seeds itself by reading from entropy. If entropy == nil,
 // the generator seeds itself by reading from the system's
 // random number generator, typically /dev/random.
 // The Read method on the returned reader always returns
diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go
index 82b39b6..4d7511a 100644
--- a/src/crypto/rand/rand_windows.go
+++ b/src/crypto/rand/rand_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/crypto/rand/util.go b/src/crypto/rand/util.go
index 5f74407..592c57e 100644
--- a/src/crypto/rand/util.go
+++ b/src/crypto/rand/util.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -70,7 +70,7 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
 
 		p.SetBytes(bytes)
 
-		// Calculate the value mod the product of smallPrimes.  If it's
+		// Calculate the value mod the product of smallPrimes. If it's
 		// a multiple of any of these primes we add two until it isn't.
 		// The probability of overflowing is minimal and can be ignored
 		// because we still perform Miller-Rabin tests on the result.
diff --git a/src/crypto/rand/util_test.go b/src/crypto/rand/util_test.go
index 2f7cba8..7b07689 100644
--- a/src/crypto/rand/util_test.go
+++ b/src/crypto/rand/util_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/crypto/rc4/rc4.go b/src/crypto/rc4/rc4.go
index 9acb681..bd04aee 100644
--- a/src/crypto/rc4/rc4.go
+++ b/src/crypto/rc4/rc4.go
@@ -23,7 +23,7 @@ func (k KeySizeError) Error() string {
 	return "crypto/rc4: invalid key size " + strconv.Itoa(int(k))
 }
 
-// NewCipher creates and returns a new Cipher.  The key argument should be the
+// NewCipher creates and returns a new Cipher. The key argument should be the
 // RC4 key, at least 1 byte and at most 256 bytes.
 func NewCipher(key []byte) (*Cipher, error) {
 	k := len(key)
@@ -52,7 +52,7 @@ func (c *Cipher) Reset() {
 }
 
 // xorKeyStreamGeneric sets dst to the result of XORing src with the
-// key stream.  Dst and src may be the same slice but otherwise should
+// key stream. Dst and src may be the same slice but otherwise should
 // not overlap.
 //
 // This is the pure Go version. rc4_{amd64,386,arm}* contain assembly
diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go
index 5c5f415..3517a8c 100644
--- a/src/crypto/rsa/pkcs1v15.go
+++ b/src/crypto/rsa/pkcs1v15.go
@@ -24,31 +24,32 @@ type PKCS1v15DecryptOptions struct {
 	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.
+// 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.
 //
-// The rand parameter is used as a source of entropy to ensure that encrypting
-// the same message twice doesn't result in the same ciphertext.
+// The rand parameter is used as a source of entropy to ensure that
+// encrypting the same message twice doesn't result in the same
+// ciphertext.
 //
-// WARNING: use of this function to encrypt plaintexts other than session keys
-// is dangerous. Use RSA OAEP in new protocols.
-func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) {
+// WARNING: use of this function to encrypt plaintexts other than
+// session keys is dangerous. Use RSA OAEP in new protocols.
+func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
 	if err := checkPub(pub); err != nil {
 		return nil, err
 	}
 	k := (pub.N.BitLen() + 7) / 8
 	if len(msg) > k-11 {
-		err = ErrMessageTooLong
-		return
+		return nil, ErrMessageTooLong
 	}
 
 	// EM = 0x00 || 0x02 || PS || 0x00 || M
 	em := make([]byte, k)
 	em[1] = 2
 	ps, mm := em[2:len(em)-len(msg)-1], em[len(em)-len(msg):]
-	err = nonZeroRandomBytes(ps, rand)
+	err := nonZeroRandomBytes(ps, rand)
 	if err != nil {
-		return
+		return nil, err
 	}
 	em[len(em)-len(msg)-1] = 0
 	copy(mm, msg)
@@ -57,8 +58,7 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er
 	c := encrypt(new(big.Int), pub, m)
 
 	copyWithLeftPad(em, c.Bytes())
-	out = em
-	return
+	return em, nil
 }
 
 // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
@@ -69,19 +69,18 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er
 // learn whether each instance returned an error then they can decrypt and
 // forge signatures as if they had the private key. See
 // DecryptPKCS1v15SessionKey for a way of solving this problem.
-func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) {
+func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error) {
 	if err := checkPub(&priv.PublicKey); err != nil {
 		return nil, err
 	}
 	valid, out, index, err := decryptPKCS1v15(rand, priv, ciphertext)
 	if err != nil {
-		return
+		return nil, err
 	}
 	if valid == 0 {
 		return nil, ErrDecryption
 	}
-	out = out[index:]
-	return
+	return out[index:], nil
 }
 
 // DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS#1 v1.5.
@@ -103,7 +102,7 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out [
 // a random value was used (because it'll be different for the same ciphertext)
 // and thus whether the padding was correct. This defeats the point of this
 // function. Using at least a 16-byte key will protect against this attack.
-func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) {
+func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) error {
 	if err := checkPub(&priv.PublicKey); err != nil {
 		return err
 	}
@@ -114,7 +113,7 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []by
 
 	valid, em, index, err := decryptPKCS1v15(rand, priv, ciphertext)
 	if err != nil {
-		return
+		return err
 	}
 
 	if len(em) != k {
@@ -125,7 +124,7 @@ func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []by
 
 	valid &= subtle.ConstantTimeEq(int32(len(em)-index), int32(len(key)))
 	subtle.ConstantTimeCopy(valid, key, em[len(em)-len(key):])
-	return
+	return nil
 }
 
 // decryptPKCS1v15 decrypts ciphertext using priv and blinds the operation if
@@ -213,21 +212,23 @@ var hashPrefixes = map[crypto.Hash][]byte{
 	crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},
 }
 
-// SignPKCS1v15 calculates the signature of hashed using RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.
-// Note that hashed must be the result of hashing the input message using the
-// given hash function. If hash is zero, hashed is signed directly. This isn't
+// SignPKCS1v15 calculates the signature of hashed using
+// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5.  Note that hashed must
+// be the result of hashing the input message using the given hash
+// function. If hash is zero, hashed is signed directly. This isn't
 // advisable except for interoperability.
 //
-// If rand is not nil then RSA blinding will be used to avoid timing side-channel attacks.
+// If rand is not nil then RSA blinding will be used to avoid timing
+// side-channel attacks.
 //
-// This function is deterministic. Thus, if the set of possible messages is
-// small, an attacker may be able to build a map from messages to signatures
-// and identify the signed messages. As ever, signatures provide authenticity,
-// not confidentiality.
-func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) {
+// This function is deterministic. Thus, if the set of possible
+// messages is small, an attacker may be able to build a map from
+// messages to signatures and identify the signed messages. As ever,
+// signatures provide authenticity, not confidentiality.
+func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
 	hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
 	if err != nil {
-		return
+		return nil, err
 	}
 
 	tLen := len(prefix) + hashLen
@@ -248,12 +249,11 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
 	m := new(big.Int).SetBytes(em)
 	c, err := decryptAndCheck(rand, priv, m)
 	if err != nil {
-		return
+		return nil, err
 	}
 
 	copyWithLeftPad(em, c.Bytes())
-	s = em
-	return
+	return em, nil
 }
 
 // VerifyPKCS1v15 verifies an RSA PKCS#1 v1.5 signature.
@@ -261,17 +261,16 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b
 // function and sig is the signature. A valid signature is indicated by
 // returning a nil error. If hash is zero then hashed is used directly. This
 // isn't advisable except for interoperability.
-func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) {
+func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error {
 	hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
 	if err != nil {
-		return
+		return err
 	}
 
 	tLen := len(prefix) + hashLen
 	k := (pub.N.BitLen() + 7) / 8
 	if k < tLen+11 {
-		err = ErrVerification
-		return
+		return ErrVerification
 	}
 
 	c := new(big.Int).SetBytes(sig)
diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go
index 8a94589..1ba194a 100644
--- a/src/crypto/rsa/pss.go
+++ b/src/crypto/rsa/pss.go
@@ -64,7 +64,7 @@ func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byt
 	hash.Reset()
 
 	// 7.  Generate an octet string PS consisting of emLen - sLen - hLen - 2
-	//     zero octets.  The length of PS may be 0.
+	//     zero octets. The length of PS may be 0.
 	//
 	// 8.  Let DB = PS || 0x01 || salt; DB is an octet string of length
 	//     emLen - hLen - 1.
@@ -246,7 +246,7 @@ func (opts *PSSOptions) saltLength() int {
 // Note that hashed must be the result of hashing the input message using the
 // given hash function. The opts argument may be nil, in which case sensible
 // defaults are used.
-func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) (s []byte, err error) {
+func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, opts *PSSOptions) ([]byte, error) {
 	saltLength := opts.saltLength()
 	switch saltLength {
 	case PSSSaltLengthAuto:
@@ -260,8 +260,8 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte,
 	}
 
 	salt := make([]byte, saltLength)
-	if _, err = io.ReadFull(rand, salt); err != nil {
-		return
+	if _, err := io.ReadFull(rand, salt); err != nil {
+		return nil, err
 	}
 	return signPSSWithSalt(rand, priv, hash, hashed, salt)
 }
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
index 0f487fe..5943056 100644
--- a/src/crypto/rsa/rsa.go
+++ b/src/crypto/rsa/rsa.go
@@ -14,7 +14,7 @@
 // possible.
 //
 // Two sets of interfaces are included in this package. When a more abstract
-// interface isn't neccessary, there are functions for encrypting/decrypting
+// interface isn't necessary, there are functions for encrypting/decrypting
 // with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract
 // over the public-key primitive, the PrivateKey struct implements the
 // Decrypter and Signer interfaces from the crypto package.
@@ -191,7 +191,7 @@ func (priv *PrivateKey) Validate() error {
 
 // GenerateKey generates an RSA keypair of the given bit size using the
 // random source random (for example, crypto/rand.Reader).
-func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) {
+func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
 	return GenerateMultiPrimeKey(random, 2, bits)
 }
 
@@ -206,8 +206,8 @@ func GenerateKey(random io.Reader, bits int) (priv *PrivateKey, err error) {
 //
 // [1] US patent 4405829 (1972, expired)
 // [2] http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
-func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *PrivateKey, err error) {
-	priv = new(PrivateKey)
+func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) {
+	priv := new(PrivateKey)
 	priv.E = 65537
 
 	if nprimes < 2 {
@@ -234,6 +234,7 @@ NextSetOfPrimes:
 			todo += (nprimes - 2) / 5
 		}
 		for i := 0; i < nprimes; i++ {
+			var err error
 			primes[i], err = rand.Prime(random, todo/(nprimes-i))
 			if err != nil {
 				return nil, err
@@ -283,7 +284,7 @@ NextSetOfPrimes:
 	}
 
 	priv.Precompute()
-	return
+	return priv, nil
 }
 
 // incCounter increments a four byte, big-endian counter.
@@ -348,15 +349,14 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
 //
 // The message must be no longer than the length of the public modulus less
 // twice the hash length plus 2.
-func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) {
+func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
 	if err := checkPub(pub); err != nil {
 		return nil, err
 	}
 	hash.Reset()
 	k := (pub.N.BitLen() + 7) / 8
 	if len(msg) > k-2*hash.Size()-2 {
-		err = ErrMessageTooLong
-		return
+		return nil, ErrMessageTooLong
 	}
 
 	hash.Write(label)
@@ -371,9 +371,9 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
 	db[len(db)-len(msg)-1] = 1
 	copy(db[len(db)-len(msg):], msg)
 
-	_, err = io.ReadFull(random, seed)
+	_, err := io.ReadFull(random, seed)
 	if err != nil {
-		return
+		return nil, err
 	}
 
 	mgf1XOR(db, hash, seed)
@@ -382,7 +382,7 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
 	m := new(big.Int)
 	m.SetBytes(em)
 	c := encrypt(new(big.Int), pub, m)
-	out = c.Bytes()
+	out := c.Bytes()
 
 	if len(out) < k {
 		// If the output is too small, we need to left-pad with zeros.
@@ -391,7 +391,7 @@ func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, l
 		out = t
 	}
 
-	return
+	return out, nil
 }
 
 // ErrDecryption represents a failure to decrypt a message.
@@ -565,22 +565,21 @@ func decryptAndCheck(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int
 //
 // The label parameter must match the value given when encrypting. See
 // EncryptOAEP for details.
-func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) {
+func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) {
 	if err := checkPub(&priv.PublicKey); err != nil {
 		return nil, err
 	}
 	k := (priv.N.BitLen() + 7) / 8
 	if len(ciphertext) > k ||
 		k < hash.Size()*2+2 {
-		err = ErrDecryption
-		return
+		return nil, ErrDecryption
 	}
 
 	c := new(big.Int).SetBytes(ciphertext)
 
 	m, err := decrypt(random, priv, c)
 	if err != nil {
-		return
+		return nil, err
 	}
 
 	hash.Write(label)
@@ -628,12 +627,10 @@ func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext
 	}
 
 	if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 {
-		err = ErrDecryption
-		return
+		return nil, ErrDecryption
 	}
 
-	msg = rest[index+1:]
-	return
+	return rest[index+1:], nil
 }
 
 // leftPad returns a new slice of length size. The contents of input are right
diff --git a/src/crypto/sha1/fallback_test.go b/src/crypto/sha1/fallback_test.go
new file mode 100644
index 0000000..08acd04
--- /dev/null
+++ b/src/crypto/sha1/fallback_test.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go 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 s390x
+
+package sha1
+
+import (
+	"fmt"
+	"io"
+	"testing"
+)
+
+// Tests the fallback code path in case the optimized asm
+// implementation cannot be used.
+// See also TestBlockGeneric.
+func TestGenericPath(t *testing.T) {
+	if useAsm == false {
+		t.Skipf("assembly implementation unavailable")
+	}
+	useAsm = false
+	defer func() { useAsm = true }()
+	c := New()
+	in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜΝΞΟΠϺϘΡΣΤΥΦΧΨΩ"
+	gold := "0f58c2bb130f8182375f325c18342215255387e5"
+	if _, err := io.WriteString(c, in); err != nil {
+		t.Fatalf("could not write to c: %v", err)
+	}
+	out := fmt.Sprintf("%x", c.Sum(nil))
+	if out != gold {
+		t.Fatalf("mismatch: got %s, wanted %s", out, gold)
+	}
+}
diff --git a/src/crypto/sha1/issue15617_test.go b/src/crypto/sha1/issue15617_test.go
new file mode 100644
index 0000000..98038e5
--- /dev/null
+++ b/src/crypto/sha1/issue15617_test.go
@@ -0,0 +1,28 @@
+// +build amd64
+// +build linux darwin
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha1_test
+
+import (
+	"crypto/sha1"
+	"syscall"
+	"testing"
+)
+
+func TestOutOfBoundsRead(t *testing.T) {
+	const pageSize = 4 << 10
+	data, err := syscall.Mmap(0, 0, 2*pageSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+	if err != nil {
+		panic(err)
+	}
+	if err := syscall.Mprotect(data[pageSize:], syscall.PROT_NONE); err != nil {
+		panic(err)
+	}
+	for i := 0; i < pageSize; i++ {
+		sha1.Sum(data[pageSize-i : pageSize])
+	}
+}
diff --git a/src/crypto/sha1/sha1.go b/src/crypto/sha1/sha1.go
index 9f1a96e..ac593b1 100644
--- a/src/crypto/sha1/sha1.go
+++ b/src/crypto/sha1/sha1.go
@@ -90,7 +90,7 @@ func (d0 *digest) Sum(in []byte) []byte {
 
 func (d *digest) checkSum() [Size]byte {
 	len := d.len
-	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
+	// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
 	var tmp [64]byte
 	tmp[0] = 0x80
 	if len%64 < 56 {
diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go
index 4a62951..214afc5 100644
--- a/src/crypto/sha1/sha1_test.go
+++ b/src/crypto/sha1/sha1_test.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.
 
-// SHA1 hash algorithm.  See RFC 3174.
+// SHA1 hash algorithm. See RFC 3174.
 
 package sha1
 
@@ -19,6 +19,7 @@ type sha1Test struct {
 }
 
 var golden = []sha1Test{
+	{"76245dbf96f661bd221046197ab8b9f063f11bad", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"},
 	{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
 	{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"},
 	{"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"},
@@ -91,15 +92,17 @@ func TestBlockSize(t *testing.T) {
 	}
 }
 
-// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
 func TestBlockGeneric(t *testing.T) {
-	gen, asm := New().(*digest), New().(*digest)
-	buf := make([]byte, BlockSize*20) // arbitrary factor
-	rand.Read(buf)
-	blockGeneric(gen, buf)
-	block(asm, buf)
-	if *gen != *asm {
-		t.Error("block and blockGeneric resulted in different states")
+	for i := 1; i < 30; i++ { // arbitrary factor
+		gen, asm := New().(*digest), New().(*digest)
+		buf := make([]byte, BlockSize*i)
+		rand.Read(buf)
+		blockGeneric(gen, buf)
+		block(asm, buf)
+		if *gen != *asm {
+			t.Errorf("For %#v block and blockGeneric resulted in different states", buf)
+		}
 	}
 }
 
@@ -120,6 +123,10 @@ func BenchmarkHash8Bytes(b *testing.B) {
 	benchmarkSize(b, 8)
 }
 
+func BenchmarkHash320Bytes(b *testing.B) {
+	benchmarkSize(b, 320)
+}
+
 func BenchmarkHash1K(b *testing.B) {
 	benchmarkSize(b, 1024)
 }
diff --git a/src/crypto/sha1/sha1block_386.s b/src/crypto/sha1/sha1block_386.s
index a0adabc..46f5d79 100644
--- a/src/crypto/sha1/sha1block_386.s
+++ b/src/crypto/sha1/sha1block_386.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/crypto/sha1/sha1block_amd64.go b/src/crypto/sha1/sha1block_amd64.go
new file mode 100644
index 0000000..fd85a42
--- /dev/null
+++ b/src/crypto/sha1/sha1block_amd64.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha1
+
+//go:noescape
+
+func blockAVX2(dig *digest, p []byte)
+
+//go:noescape
+func blockAMD64(dig *digest, p []byte)
+func checkAVX2() bool
+
+var hasAVX2 = checkAVX2()
+
+func block(dig *digest, p []byte) {
+	if hasAVX2 && len(p) >= 256 {
+		// blockAVX2 calculates sha1 for 2 block per iteration
+		// it also interleaves precalculation for next block.
+		// So it may read up-to 192 bytes past end of p
+		// We may add checks inside blockAVX2, but this will
+		// just turn it into a copy of blockAMD64,
+		// so call it directly, instead.
+		safeLen := len(p) - 128
+		if safeLen%128 != 0 {
+			safeLen -= 64
+		}
+		blockAVX2(dig, p[:safeLen])
+		blockAMD64(dig, p[safeLen:])
+	} else {
+		blockAMD64(dig, p)
+	}
+}
diff --git a/src/crypto/sha1/sha1block_amd64.s b/src/crypto/sha1/sha1block_amd64.s
index 4319df6..0cdb43b 100644
--- a/src/crypto/sha1/sha1block_amd64.s
+++ b/src/crypto/sha1/sha1block_amd64.s
@@ -1,7 +1,16 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
+// AVX2 version by Intel, same algorithm as code in Linux kernel:
+// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha1_avx2_x86_64_asm.S
+// Authors:
+// Ilya Albrekht <ilya.albrekht at intel.com>
+// Maxim Locktyukhin <maxim.locktyukhin at intel.com>
+// Ronen Zohar <ronen.zohar at intel.com>
+// Chandramouli Narayanan <mouli at linux.intel.com>
+
+
 #include "textflag.h"
 
 // SHA1 block routine. See sha1block.go for Go equivalent.
@@ -87,7 +96,7 @@
 	FUNC4(a, b, c, d, e); \
 	MIX(a, b, c, d, e, 0xCA62C1D6)
 
-TEXT ·block(SB),NOSPLIT,$64-32
+TEXT ·blockAMD64(SB),NOSPLIT,$64-32
 	MOVQ	dig+0(FP),	BP
 	MOVQ	p_base+8(FP),	SI
 	MOVQ	p_len+16(FP),	DX
@@ -214,3 +223,1293 @@ end:
 	MOVL	DX, (3*4)(DI)
 	MOVL	BP, (4*4)(DI)
 	RET
+
+
+// This is the implementation using AVX2. It is based on:
+// "SHA-1 implementation with Intel(R) AVX2 instruction set extensions"
+// From http://software.intel.com/en-us/articles
+// (look for improving-the-performance-of-the-secure-hash-algorithm-1)
+// This implementation is 2x unrolled, and interleaves vector instructions,
+// used to precompute W, with scalar computation of current round
+// for optimal scheduling.
+
+// Trivial helper macros.
+#define UPDATE_HASH(A,TB,C,D,E) \
+	ADDL	(R9), A \
+	MOVL	A, (R9) \
+	ADDL	4(R9), TB \
+	MOVL	TB, 4(R9) \
+	ADDL	8(R9), C \
+	MOVL	C, 8(R9) \
+	ADDL	12(R9), D \
+	MOVL	D, 12(R9) \
+	ADDL	16(R9), E \
+	MOVL	E, 16(R9)
+
+
+
+// Helper macros for PRECALC, which does precomputations
+#define PRECALC_0(OFFSET) \
+	VMOVDQU   OFFSET(R10),X0
+
+#define PRECALC_1(OFFSET) \
+	VINSERTI128 $1, OFFSET(R13), Y0, Y0
+
+#define PRECALC_2(YREG) \
+	VPSHUFB Y10, Y0, YREG
+
+#define PRECALC_4(YREG,K_OFFSET) \
+	VPADDD K_OFFSET(R8), YREG, Y0
+
+#define PRECALC_7(OFFSET) \
+	VMOVDQU Y0, (OFFSET*2)(R14)
+
+
+// Message scheduling pre-compute for rounds 0-15
+// R13 is a pointer to even 64-byte block
+// R10 is a pointer to odd 64-byte block
+// R14 is a pointer to temp buffer
+// X0 is used as temp register
+// YREG is clobbered as part of computation
+// OFFSET chooses 16 byte chunk within a block
+// R8 is a pointer to constants block
+// K_OFFSET chooses K constants relevant to this round
+// X10 holds swap mask
+#define PRECALC_00_15(OFFSET,YREG) \
+	PRECALC_0(OFFSET) \
+	PRECALC_1(OFFSET) \
+	PRECALC_2(YREG) \
+	PRECALC_4(YREG,0x0) \
+	PRECALC_7(OFFSET)
+
+
+// Helper macros for PRECALC_16_31
+#define PRECALC_16(REG_SUB_16,REG_SUB_12,REG_SUB_4,REG) \
+	VPALIGNR $8, REG_SUB_16, REG_SUB_12, REG \  // w[i-14]
+	VPSRLDQ $4, REG_SUB_4, Y0 // w[i-3]
+
+#define PRECALC_17(REG_SUB_16,REG_SUB_8,REG) \
+	VPXOR  REG_SUB_8, REG, REG \
+	VPXOR  REG_SUB_16, Y0, Y0
+
+#define PRECALC_18(REG) \
+	VPXOR Y0, REG, REG \
+	VPSLLDQ $12, REG, Y9
+
+#define PRECALC_19(REG) \
+	VPSLLD $1, REG, Y0 \
+	VPSRLD $31, REG, REG
+
+#define PRECALC_20(REG) \
+	VPOR REG, Y0, Y0 \
+	VPSLLD $2, Y9,  REG
+
+#define PRECALC_21(REG) \
+	VPSRLD $30, Y9, Y9 \
+	VPXOR REG, Y0, Y0
+
+#define PRECALC_23(REG,K_OFFSET,OFFSET) \
+	VPXOR Y9, Y0, REG \
+	VPADDD K_OFFSET(R8), REG, Y0 \
+	VMOVDQU Y0, (OFFSET)(R14)
+
+// Message scheduling pre-compute for rounds 16-31
+// calculating last 32 w[i] values in 8 XMM registers
+// pre-calculate K+w[i] values and store to mem
+// for later load by ALU add instruction.
+// "brute force" vectorization for rounds 16-31 only
+// due to w[i]->w[i-3] dependency.
+// clobbers 5 input ymm registers REG_SUB*
+// uses X0 and X9 as temp registers
+// As always, R8 is a pointer to constants block
+// and R14 is a pointer to temp buffer
+#define PRECALC_16_31(REG,REG_SUB_4,REG_SUB_8,REG_SUB_12,REG_SUB_16,K_OFFSET,OFFSET) \
+	PRECALC_16(REG_SUB_16,REG_SUB_12,REG_SUB_4,REG) \
+	PRECALC_17(REG_SUB_16,REG_SUB_8,REG) \
+	PRECALC_18(REG) \
+	PRECALC_19(REG) \
+	PRECALC_20(REG) \
+	PRECALC_21(REG) \
+	PRECALC_23(REG,K_OFFSET,OFFSET)
+
+
+// Helper macros for PRECALC_32_79
+#define PRECALC_32(REG_SUB_8,REG_SUB_4) \
+	VPALIGNR $8, REG_SUB_8, REG_SUB_4, Y0
+
+#define PRECALC_33(REG_SUB_28,REG) \
+	VPXOR REG_SUB_28, REG, REG
+
+#define PRECALC_34(REG_SUB_16) \
+	VPXOR REG_SUB_16, Y0, Y0
+
+#define PRECALC_35(REG) \
+	VPXOR Y0, REG, REG
+
+#define PRECALC_36(REG) \
+	VPSLLD $2, REG, Y0
+
+#define PRECALC_37(REG) \
+	VPSRLD $30, REG, REG \
+	VPOR REG, Y0, REG
+
+#define PRECALC_39(REG,K_OFFSET,OFFSET) \
+	VPADDD K_OFFSET(R8), REG, Y0 \
+	VMOVDQU Y0, (OFFSET)(R14)
+
+// Message scheduling pre-compute for rounds 32-79
+// In SHA-1 specification we have:
+// w[i] = (w[i-3] ^ w[i-8]  ^ w[i-14] ^ w[i-16]) rol 1
+// Which is the same as:
+// w[i] = (w[i-6] ^ w[i-16] ^ w[i-28] ^ w[i-32]) rol 2
+// This allows for more efficient vectorization,
+// since w[i]->w[i-3] dependency is broken
+#define PRECALC_32_79(REG,REG_SUB_4,REG_SUB_8,REG_SUB_16,REG_SUB_28,K_OFFSET,OFFSET) \
+	PRECALC_32(REG_SUB_8,REG_SUB_4) \
+	PRECALC_33(REG_SUB_28,REG) \
+	PRECALC_34(REG_SUB_16) \
+	PRECALC_35(REG) \
+	PRECALC_36(REG) \
+	PRECALC_37(REG) \
+	PRECALC_39(REG,K_OFFSET,OFFSET)
+
+#define PRECALC \
+	PRECALC_00_15(0,Y15) \
+	PRECALC_00_15(0x10,Y14) \
+	PRECALC_00_15(0x20,Y13) \
+	PRECALC_00_15(0x30,Y12) \
+	PRECALC_16_31(Y8,Y12,Y13,Y14,Y15,0,0x80) \
+	PRECALC_16_31(Y7,Y8,Y12,Y13,Y14,0x20,0xa0) \
+	PRECALC_16_31(Y5,Y7,Y8,Y12,Y13,0x20,0xc0) \
+	PRECALC_16_31(Y3,Y5,Y7,Y8,Y12,0x20,0xe0) \
+	PRECALC_32_79(Y15,Y3,Y5,Y8,Y14,0x20,0x100) \
+	PRECALC_32_79(Y14,Y15,Y3,Y7,Y13,0x20,0x120) \
+	PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x40,0x140) \
+	PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x40,0x160) \
+	PRECALC_32_79(Y8,Y12,Y13,Y15,Y7,0x40,0x180) \
+	PRECALC_32_79(Y7,Y8,Y12,Y14,Y5,0x40,0x1a0) \
+	PRECALC_32_79(Y5,Y7,Y8,Y13,Y3,0x40,0x1c0) \
+	PRECALC_32_79(Y3,Y5,Y7,Y12,Y15,0x60,0x1e0) \
+	PRECALC_32_79(Y15,Y3,Y5,Y8,Y14,0x60,0x200) \
+	PRECALC_32_79(Y14,Y15,Y3,Y7,Y13,0x60,0x220) \
+	PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x60,0x240) \
+	PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x60,0x260)
+
+// Macros calculating individual rounds have general forn
+// CALC_ROUND_PRE + PRECALC_ROUND + CALC_ROUND_POST
+// CALC_ROUND_{PRE,POST} macros follow
+
+#define CALC_F1_PRE(OFFSET,REG_A,REG_B,REG_C,REG_E) \
+	ADDL OFFSET(R15),REG_E \
+	ANDNL REG_C,REG_A,BP \
+	LEAL (REG_E)(REG_B*1), REG_E \ // Add F from the previous round
+	RORXL $0x1b, REG_A, R12 \
+	RORXL $2, REG_A, REG_B         // for next round
+
+// Calculate F for the next round
+#define CALC_F1_POST(REG_A,REG_B,REG_E) \
+	ANDL REG_B,REG_A \             // b&c
+	XORL BP, REG_A \               // F1 = (b&c) ^ (~b&d)
+	LEAL (REG_E)(R12*1), REG_E     // E += A >>> 5
+
+
+// Registers are cycleickly rotated DX -> AX -> DI -> SI -> BX -> CX
+#define CALC_0 \
+	MOVL SI, BX \ // Precalculating first round
+	RORXL $2, SI, SI \
+	ANDNL AX, BX, BP \
+	ANDL DI, BX \
+	XORL BP, BX \
+	CALC_F1_PRE(0x0,CX,BX,DI,DX) \
+	PRECALC_0(0x80) \
+	CALC_F1_POST(CX,SI,DX)
+
+#define CALC_1 \
+	CALC_F1_PRE(0x4,DX,CX,SI,AX) \
+	PRECALC_1(0x80) \
+	CALC_F1_POST(DX,BX,AX)
+
+#define CALC_2 \
+	CALC_F1_PRE(0x8,AX,DX,BX,DI) \
+	PRECALC_2(Y15) \
+	CALC_F1_POST(AX,CX,DI)
+
+#define CALC_3 \
+	CALC_F1_PRE(0xc,DI,AX,CX,SI) \
+	CALC_F1_POST(DI,DX,SI)
+
+#define CALC_4 \
+	CALC_F1_PRE(0x20,SI,DI,DX,BX) \
+	PRECALC_4(Y15,0x0) \
+	CALC_F1_POST(SI,AX,BX)
+
+#define CALC_5 \
+	CALC_F1_PRE(0x24,BX,SI,AX,CX) \
+	CALC_F1_POST(BX,DI,CX)
+
+#define CALC_6 \
+	CALC_F1_PRE(0x28,CX,BX,DI,DX) \
+	CALC_F1_POST(CX,SI,DX)
+
+#define CALC_7 \
+	CALC_F1_PRE(0x2c,DX,CX,SI,AX) \
+	PRECALC_7(0x0) \
+	CALC_F1_POST(DX,BX,AX)
+
+#define CALC_8 \
+	CALC_F1_PRE(0x40,AX,DX,BX,DI) \
+	PRECALC_0(0x90) \
+	CALC_F1_POST(AX,CX,DI)
+
+#define CALC_9 \
+	CALC_F1_PRE(0x44,DI,AX,CX,SI) \
+	PRECALC_1(0x90) \
+	CALC_F1_POST(DI,DX,SI)
+
+#define CALC_10 \
+	CALC_F1_PRE(0x48,SI,DI,DX,BX) \
+	PRECALC_2(Y14) \
+	CALC_F1_POST(SI,AX,BX)
+
+#define CALC_11 \
+	CALC_F1_PRE(0x4c,BX,SI,AX,CX) \
+	CALC_F1_POST(BX,DI,CX)
+
+#define CALC_12 \
+	CALC_F1_PRE(0x60,CX,BX,DI,DX) \
+	PRECALC_4(Y14,0x0) \
+	CALC_F1_POST(CX,SI,DX)
+
+#define CALC_13 \
+	CALC_F1_PRE(0x64,DX,CX,SI,AX) \
+	CALC_F1_POST(DX,BX,AX)
+
+#define CALC_14 \
+	CALC_F1_PRE(0x68,AX,DX,BX,DI) \
+	CALC_F1_POST(AX,CX,DI)
+
+#define CALC_15 \
+	CALC_F1_PRE(0x6c,DI,AX,CX,SI) \
+	PRECALC_7(0x10) \
+	CALC_F1_POST(DI,DX,SI)
+
+#define CALC_16 \
+	CALC_F1_PRE(0x80,SI,DI,DX,BX) \
+	PRECALC_0(0xa0) \
+	CALC_F1_POST(SI,AX,BX)
+
+#define CALC_17 \
+	CALC_F1_PRE(0x84,BX,SI,AX,CX) \
+	PRECALC_1(0xa0) \
+	CALC_F1_POST(BX,DI,CX)
+
+#define CALC_18 \
+	CALC_F1_PRE(0x88,CX,BX,DI,DX) \
+	PRECALC_2(Y13) \
+	CALC_F1_POST(CX,SI,DX)
+
+
+#define CALC_F2_PRE(OFFSET,REG_A,REG_B,REG_E) \
+	ADDL OFFSET(R15),REG_E \
+	LEAL (REG_E)(REG_B*1), REG_E \ // Add F from the previous round
+	RORXL $0x1b, REG_A, R12 \
+	RORXL $2, REG_A, REG_B         // for next round
+
+#define CALC_F2_POST(REG_A,REG_B,REG_C,REG_E) \
+	XORL REG_B, REG_A \
+	ADDL R12, REG_E \
+        XORL REG_C, REG_A
+
+#define CALC_19 \
+	CALC_F2_PRE(0x8c,DX,CX,AX) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_20 \
+	CALC_F2_PRE(0xa0,AX,DX,DI) \
+	PRECALC_4(Y13,0x0) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_21 \
+	CALC_F2_PRE(0xa4,DI,AX,SI) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_22 \
+	CALC_F2_PRE(0xa8,SI,DI,BX) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_23 \
+	CALC_F2_PRE(0xac,BX,SI,CX) \
+	PRECALC_7(0x20) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_24 \
+	CALC_F2_PRE(0xc0,CX,BX,DX) \
+	PRECALC_0(0xb0) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_25 \
+	CALC_F2_PRE(0xc4,DX,CX,AX) \
+	PRECALC_1(0xb0) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_26 \
+	CALC_F2_PRE(0xc8,AX,DX,DI) \
+	PRECALC_2(Y12) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_27 \
+	CALC_F2_PRE(0xcc,DI,AX,SI) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_28 \
+	CALC_F2_PRE(0xe0,SI,DI,BX) \
+	PRECALC_4(Y12,0x0) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_29 \
+	CALC_F2_PRE(0xe4,BX,SI,CX) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_30 \
+	CALC_F2_PRE(0xe8,CX,BX,DX) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_31 \
+	CALC_F2_PRE(0xec,DX,CX,AX) \
+	PRECALC_7(0x30) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_32 \
+	CALC_F2_PRE(0x100,AX,DX,DI) \
+	PRECALC_16(Y15,Y14,Y12,Y8) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_33 \
+	CALC_F2_PRE(0x104,DI,AX,SI) \
+	PRECALC_17(Y15,Y13,Y8) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_34 \
+	CALC_F2_PRE(0x108,SI,DI,BX) \
+	PRECALC_18(Y8) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_35 \
+	CALC_F2_PRE(0x10c,BX,SI,CX) \
+	PRECALC_19(Y8) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_36 \
+	CALC_F2_PRE(0x120,CX,BX,DX) \
+	PRECALC_20(Y8) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_37 \
+	CALC_F2_PRE(0x124,DX,CX,AX) \
+	PRECALC_21(Y8) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_38 \
+	CALC_F2_PRE(0x128,AX,DX,DI) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+
+#define CALC_F3_PRE(OFFSET,REG_E) \
+	ADDL OFFSET(R15),REG_E
+
+#define CALC_F3_POST(REG_A,REG_B,REG_C,REG_E,REG_TB) \
+	LEAL (REG_E)(REG_TB*1), REG_E \ // Add F from the previous round
+	MOVL REG_B, BP \
+	ORL  REG_A, BP \
+	RORXL $0x1b, REG_A, R12 \
+	RORXL $2, REG_A, REG_TB \
+	ANDL REG_C, BP \		// Calculate F for the next round
+	ANDL REG_B, REG_A \
+	ORL  BP, REG_A \
+	ADDL R12, REG_E
+
+#define CALC_39 \
+	CALC_F3_PRE(0x12c,SI) \
+	PRECALC_23(Y8,0x0,0x80) \
+	CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_40 \
+	CALC_F3_PRE(0x140,BX) \
+	PRECALC_16(Y14,Y13,Y8,Y7) \
+	CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_41 \
+	CALC_F3_PRE(0x144,CX) \
+	PRECALC_17(Y14,Y12,Y7) \
+	CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_42 \
+	CALC_F3_PRE(0x148,DX) \
+	PRECALC_18(Y7) \
+	CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_43 \
+	CALC_F3_PRE(0x14c,AX) \
+	PRECALC_19(Y7) \
+	CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_44 \
+	CALC_F3_PRE(0x160,DI) \
+	PRECALC_20(Y7) \
+	CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_45 \
+	CALC_F3_PRE(0x164,SI) \
+	PRECALC_21(Y7) \
+	CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_46 \
+	CALC_F3_PRE(0x168,BX) \
+	CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_47 \
+	CALC_F3_PRE(0x16c,CX) \
+	VPXOR Y9, Y0, Y7 \
+	VPADDD 0x20(R8), Y7, Y0 \
+	VMOVDQU Y0, 0xa0(R14) \
+	CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_48 \
+	CALC_F3_PRE(0x180,DX) \
+	PRECALC_16(Y13,Y12,Y7,Y5) \
+	CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_49 \
+	CALC_F3_PRE(0x184,AX) \
+	PRECALC_17(Y13,Y8,Y5) \
+	CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_50 \
+	CALC_F3_PRE(0x188,DI) \
+	PRECALC_18(Y5) \
+	CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_51 \
+	CALC_F3_PRE(0x18c,SI) \
+	PRECALC_19(Y5) \
+	CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_52 \
+	CALC_F3_PRE(0x1a0,BX) \
+	PRECALC_20(Y5) \
+	CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_53 \
+	CALC_F3_PRE(0x1a4,CX) \
+	PRECALC_21(Y5) \
+	CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_54 \
+	CALC_F3_PRE(0x1a8,DX) \
+	CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_55 \
+	CALC_F3_PRE(0x1ac,AX) \
+	PRECALC_23(Y5,0x20,0xc0) \
+	CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_56 \
+	CALC_F3_PRE(0x1c0,DI) \
+	PRECALC_16(Y12,Y8,Y5,Y3) \
+	CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_57 \
+	CALC_F3_PRE(0x1c4,SI) \
+	PRECALC_17(Y12,Y7,Y3) \
+	CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_58 \
+	CALC_F3_PRE(0x1c8,BX) \
+	PRECALC_18(Y3) \
+	CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_59 \
+	CALC_F2_PRE(0x1cc,BX,SI,CX) \
+	PRECALC_19(Y3) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_60 \
+	CALC_F2_PRE(0x1e0,CX,BX,DX) \
+	PRECALC_20(Y3) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_61 \
+	CALC_F2_PRE(0x1e4,DX,CX,AX) \
+	PRECALC_21(Y3) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_62 \
+	CALC_F2_PRE(0x1e8,AX,DX,DI) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_63 \
+	CALC_F2_PRE(0x1ec,DI,AX,SI) \
+	PRECALC_23(Y3,0x20,0xe0) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_64 \
+	CALC_F2_PRE(0x200,SI,DI,BX) \
+	PRECALC_32(Y5,Y3) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_65 \
+	CALC_F2_PRE(0x204,BX,SI,CX) \
+	PRECALC_33(Y14,Y15) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_66 \
+	CALC_F2_PRE(0x208,CX,BX,DX) \
+	PRECALC_34(Y8) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_67 \
+	CALC_F2_PRE(0x20c,DX,CX,AX) \
+	PRECALC_35(Y15) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_68 \
+	CALC_F2_PRE(0x220,AX,DX,DI) \
+	PRECALC_36(Y15) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_69 \
+	CALC_F2_PRE(0x224,DI,AX,SI) \
+	PRECALC_37(Y15) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_70 \
+	CALC_F2_PRE(0x228,SI,DI,BX) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_71 \
+	CALC_F2_PRE(0x22c,BX,SI,CX) \
+	PRECALC_39(Y15,0x20,0x100) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_72 \
+	CALC_F2_PRE(0x240,CX,BX,DX) \
+	PRECALC_32(Y3,Y15) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_73 \
+	CALC_F2_PRE(0x244,DX,CX,AX) \
+	PRECALC_33(Y13,Y14) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_74 \
+	CALC_F2_PRE(0x248,AX,DX,DI) \
+	PRECALC_34(Y7) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_75 \
+	CALC_F2_PRE(0x24c,DI,AX,SI) \
+	PRECALC_35(Y14) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_76 \
+	CALC_F2_PRE(0x260,SI,DI,BX) \
+	PRECALC_36(Y14) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_77 \
+	CALC_F2_PRE(0x264,BX,SI,CX) \
+	PRECALC_37(Y14) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_78 \
+	CALC_F2_PRE(0x268,CX,BX,DX) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_79 \
+	ADDL 0x26c(R15), AX \
+	LEAL (AX)(CX*1), AX \
+	RORXL $0x1b, DX, R12 \
+	PRECALC_39(Y14,0x20,0x120) \
+	ADDL R12, AX
+
+// Similar to CALC_0
+#define CALC_80 \
+	MOVL CX, DX \
+	RORXL $2, CX, CX \
+	ANDNL SI, DX, BP \
+	ANDL BX, DX \
+	XORL BP, DX \
+	CALC_F1_PRE(0x10,AX,DX,BX,DI) \
+	PRECALC_32(Y15,Y14) \
+	CALC_F1_POST(AX,CX,DI)
+
+#define CALC_81 \
+	CALC_F1_PRE(0x14,DI,AX,CX,SI) \
+	PRECALC_33(Y12,Y13) \
+	CALC_F1_POST(DI,DX,SI)
+
+#define CALC_82 \
+	CALC_F1_PRE(0x18,SI,DI,DX,BX) \
+	PRECALC_34(Y5) \
+	CALC_F1_POST(SI,AX,BX)
+
+#define CALC_83 \
+	CALC_F1_PRE(0x1c,BX,SI,AX,CX) \
+	PRECALC_35(Y13) \
+	CALC_F1_POST(BX,DI,CX)
+
+#define CALC_84 \
+	CALC_F1_PRE(0x30,CX,BX,DI,DX) \
+	PRECALC_36(Y13) \
+	CALC_F1_POST(CX,SI,DX)
+
+#define CALC_85 \
+	CALC_F1_PRE(0x34,DX,CX,SI,AX) \
+	PRECALC_37(Y13) \
+	CALC_F1_POST(DX,BX,AX)
+
+#define CALC_86 \
+	CALC_F1_PRE(0x38,AX,DX,BX,DI) \
+	CALC_F1_POST(AX,CX,DI)
+
+#define CALC_87 \
+	CALC_F1_PRE(0x3c,DI,AX,CX,SI) \
+	PRECALC_39(Y13,0x40,0x140) \
+	CALC_F1_POST(DI,DX,SI)
+
+#define CALC_88 \
+	CALC_F1_PRE(0x50,SI,DI,DX,BX) \
+	PRECALC_32(Y14,Y13) \
+	CALC_F1_POST(SI,AX,BX)
+
+#define CALC_89 \
+	CALC_F1_PRE(0x54,BX,SI,AX,CX) \
+	PRECALC_33(Y8,Y12) \
+	CALC_F1_POST(BX,DI,CX)
+
+#define CALC_90 \
+	CALC_F1_PRE(0x58,CX,BX,DI,DX) \
+	PRECALC_34(Y3) \
+	CALC_F1_POST(CX,SI,DX)
+
+#define CALC_91 \
+	CALC_F1_PRE(0x5c,DX,CX,SI,AX) \
+	PRECALC_35(Y12) \
+	CALC_F1_POST(DX,BX,AX)
+
+#define CALC_92 \
+	CALC_F1_PRE(0x70,AX,DX,BX,DI) \
+	PRECALC_36(Y12) \
+	CALC_F1_POST(AX,CX,DI)
+
+#define CALC_93 \
+	CALC_F1_PRE(0x74,DI,AX,CX,SI) \
+	PRECALC_37(Y12) \
+	CALC_F1_POST(DI,DX,SI)
+
+#define CALC_94 \
+	CALC_F1_PRE(0x78,SI,DI,DX,BX) \
+	CALC_F1_POST(SI,AX,BX)
+
+#define CALC_95 \
+	CALC_F1_PRE(0x7c,BX,SI,AX,CX) \
+	PRECALC_39(Y12,0x40,0x160) \
+	CALC_F1_POST(BX,DI,CX)
+
+#define CALC_96 \
+	CALC_F1_PRE(0x90,CX,BX,DI,DX) \
+	PRECALC_32(Y13,Y12) \
+	CALC_F1_POST(CX,SI,DX)
+
+#define CALC_97 \
+	CALC_F1_PRE(0x94,DX,CX,SI,AX) \
+	PRECALC_33(Y7,Y8) \
+	CALC_F1_POST(DX,BX,AX)
+
+#define CALC_98 \
+	CALC_F1_PRE(0x98,AX,DX,BX,DI) \
+	PRECALC_34(Y15) \
+	CALC_F1_POST(AX,CX,DI)
+
+#define CALC_99 \
+	CALC_F2_PRE(0x9c,DI,AX,SI) \
+	PRECALC_35(Y8) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_100 \
+	CALC_F2_PRE(0xb0,SI,DI,BX) \
+	PRECALC_36(Y8) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_101 \
+	CALC_F2_PRE(0xb4,BX,SI,CX) \
+	PRECALC_37(Y8) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_102 \
+	CALC_F2_PRE(0xb8,CX,BX,DX) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_103 \
+	CALC_F2_PRE(0xbc,DX,CX,AX) \
+	PRECALC_39(Y8,0x40,0x180) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_104 \
+	CALC_F2_PRE(0xd0,AX,DX,DI) \
+	PRECALC_32(Y12,Y8) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_105 \
+	CALC_F2_PRE(0xd4,DI,AX,SI) \
+	PRECALC_33(Y5,Y7) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_106 \
+	CALC_F2_PRE(0xd8,SI,DI,BX) \
+	PRECALC_34(Y14) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_107 \
+	CALC_F2_PRE(0xdc,BX,SI,CX) \
+	PRECALC_35(Y7) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_108 \
+	CALC_F2_PRE(0xf0,CX,BX,DX) \
+	PRECALC_36(Y7) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_109 \
+	CALC_F2_PRE(0xf4,DX,CX,AX) \
+	PRECALC_37(Y7) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_110 \
+	CALC_F2_PRE(0xf8,AX,DX,DI) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_111 \
+	CALC_F2_PRE(0xfc,DI,AX,SI) \
+	PRECALC_39(Y7,0x40,0x1a0) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_112 \
+	CALC_F2_PRE(0x110,SI,DI,BX) \
+	PRECALC_32(Y8,Y7) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_113 \
+	CALC_F2_PRE(0x114,BX,SI,CX) \
+	PRECALC_33(Y3,Y5) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_114 \
+	CALC_F2_PRE(0x118,CX,BX,DX) \
+	PRECALC_34(Y13) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_115 \
+	CALC_F2_PRE(0x11c,DX,CX,AX) \
+	PRECALC_35(Y5) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_116 \
+	CALC_F2_PRE(0x130,AX,DX,DI) \
+	PRECALC_36(Y5) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_117 \
+	CALC_F2_PRE(0x134,DI,AX,SI) \
+	PRECALC_37(Y5) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_118 \
+	CALC_F2_PRE(0x138,SI,DI,BX) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_119 \
+	CALC_F3_PRE(0x13c,CX) \
+	PRECALC_39(Y5,0x40,0x1c0) \
+	CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_120 \
+	CALC_F3_PRE(0x150,DX) \
+	PRECALC_32(Y7,Y5) \
+	CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_121 \
+	CALC_F3_PRE(0x154,AX) \
+	PRECALC_33(Y15,Y3) \
+	CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_122 \
+	CALC_F3_PRE(0x158,DI) \
+	PRECALC_34(Y12) \
+	CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_123 \
+	CALC_F3_PRE(0x15c,SI) \
+	PRECALC_35(Y3) \
+	CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_124 \
+	CALC_F3_PRE(0x170,BX) \
+	PRECALC_36(Y3) \
+	CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_125 \
+	CALC_F3_PRE(0x174,CX) \
+	PRECALC_37(Y3) \
+	CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_126 \
+	CALC_F3_PRE(0x178,DX) \
+	CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_127 \
+	CALC_F3_PRE(0x17c,AX) \
+	PRECALC_39(Y3,0x60,0x1e0) \
+	CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_128 \
+	CALC_F3_PRE(0x190,DI) \
+	PRECALC_32(Y5,Y3) \
+	CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_129 \
+	CALC_F3_PRE(0x194,SI) \
+	PRECALC_33(Y14,Y15) \
+	CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_130 \
+	CALC_F3_PRE(0x198,BX) \
+	PRECALC_34(Y8) \
+	CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_131 \
+	CALC_F3_PRE(0x19c,CX) \
+	PRECALC_35(Y15) \
+	CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_132 \
+	CALC_F3_PRE(0x1b0,DX) \
+	PRECALC_36(Y15) \
+	CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_133 \
+	CALC_F3_PRE(0x1b4,AX) \
+	PRECALC_37(Y15) \
+	CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_134 \
+	CALC_F3_PRE(0x1b8,DI) \
+	CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_135 \
+	CALC_F3_PRE(0x1bc,SI) \
+	PRECALC_39(Y15,0x60,0x200) \
+	CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_136 \
+	CALC_F3_PRE(0x1d0,BX) \
+	PRECALC_32(Y3,Y15) \
+	CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_137 \
+	CALC_F3_PRE(0x1d4,CX) \
+	PRECALC_33(Y13,Y14) \
+	CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_138 \
+	CALC_F3_PRE(0x1d8,DX) \
+	PRECALC_34(Y7) \
+	CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_139 \
+	CALC_F2_PRE(0x1dc,DX,CX,AX) \
+	PRECALC_35(Y14) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_140 \
+	CALC_F2_PRE(0x1f0,AX,DX,DI) \
+	PRECALC_36(Y14) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_141 \
+	CALC_F2_PRE(0x1f4,DI,AX,SI) \
+	PRECALC_37(Y14) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_142 \
+	CALC_F2_PRE(0x1f8,SI,DI,BX) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_143 \
+	CALC_F2_PRE(0x1fc,BX,SI,CX) \
+	PRECALC_39(Y14,0x60,0x220) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_144 \
+	CALC_F2_PRE(0x210,CX,BX,DX) \
+	PRECALC_32(Y15,Y14) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_145 \
+	CALC_F2_PRE(0x214,DX,CX,AX) \
+	PRECALC_33(Y12,Y13) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_146 \
+	CALC_F2_PRE(0x218,AX,DX,DI) \
+	PRECALC_34(Y5) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_147 \
+	CALC_F2_PRE(0x21c,DI,AX,SI) \
+	PRECALC_35(Y13) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_148 \
+	CALC_F2_PRE(0x230,SI,DI,BX) \
+	PRECALC_36(Y13) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_149 \
+	CALC_F2_PRE(0x234,BX,SI,CX) \
+	PRECALC_37(Y13) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_150 \
+	CALC_F2_PRE(0x238,CX,BX,DX) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_151 \
+	CALC_F2_PRE(0x23c,DX,CX,AX) \
+	PRECALC_39(Y13,0x60,0x240) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_152 \
+	CALC_F2_PRE(0x250,AX,DX,DI) \
+	PRECALC_32(Y14,Y13) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_153 \
+	CALC_F2_PRE(0x254,DI,AX,SI) \
+	PRECALC_33(Y8,Y12) \
+	CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_154 \
+	CALC_F2_PRE(0x258,SI,DI,BX) \
+	PRECALC_34(Y3) \
+	CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_155 \
+	CALC_F2_PRE(0x25c,BX,SI,CX) \
+	PRECALC_35(Y12) \
+	CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_156 \
+	CALC_F2_PRE(0x270,CX,BX,DX) \
+	PRECALC_36(Y12) \
+	CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_157 \
+	CALC_F2_PRE(0x274,DX,CX,AX) \
+	PRECALC_37(Y12) \
+	CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_158 \
+	CALC_F2_PRE(0x278,AX,DX,DI) \
+	CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_159 \
+	ADDL 0x27c(R15),SI \
+	LEAL (SI)(AX*1), SI \
+	RORXL $0x1b, DI, R12 \
+	PRECALC_39(Y12,0x60,0x260) \
+	ADDL R12, SI
+
+
+
+#define CALC \
+	MOVL	(R9), CX \
+	MOVL	4(R9), SI \
+	MOVL	8(R9), DI \
+	MOVL	12(R9), AX \
+	MOVL	16(R9), DX \
+	MOVQ    SP, R14 \
+	LEAQ    (2*4*80+32)(SP), R15 \
+	PRECALC \ // Precalc WK for first 2 blocks
+	XCHGQ   R15, R14 \
+loop: \  // this loops is unrolled
+	CMPQ    R10, R8 \ // we use R8 value (set below) as a signal of a last block
+	JNE	begin \
+	VZEROUPPER \
+	RET \
+begin: \
+	CALC_0 \
+	CALC_1 \
+	CALC_2 \
+	CALC_3 \
+	CALC_4 \
+	CALC_5 \
+	CALC_6 \
+	CALC_7 \
+	CALC_8 \
+	CALC_9 \
+	CALC_10 \
+	CALC_11 \
+	CALC_12 \
+	CALC_13 \
+	CALC_14 \
+	CALC_15 \
+	CALC_16 \
+	CALC_17 \
+	CALC_18 \
+	CALC_19 \
+	CALC_20 \
+	CALC_21 \
+	CALC_22 \
+	CALC_23 \
+	CALC_24 \
+	CALC_25 \
+	CALC_26 \
+	CALC_27 \
+	CALC_28 \
+	CALC_29 \
+	CALC_30 \
+	CALC_31 \
+	CALC_32 \
+	CALC_33 \
+	CALC_34 \
+	CALC_35 \
+	CALC_36 \
+	CALC_37 \
+	CALC_38 \
+	CALC_39 \
+	CALC_40 \
+	CALC_41 \
+	CALC_42 \
+	CALC_43 \
+	CALC_44 \
+	CALC_45 \
+	CALC_46 \
+	CALC_47 \
+	CALC_48 \
+	CALC_49 \
+	CALC_50 \
+	CALC_51 \
+	CALC_52 \
+	CALC_53 \
+	CALC_54 \
+	CALC_55 \
+	CALC_56 \
+	CALC_57 \
+	CALC_58 \
+	CALC_59 \
+	ADDQ $128, R10 \ // move to next even-64-byte block
+	CMPQ R10, R11 \ // is current block the last one?
+	CMOVQCC R8, R10 \ // signal the last iteration smartly
+	CALC_60 \
+	CALC_61 \
+	CALC_62 \
+	CALC_63 \
+	CALC_64 \
+	CALC_65 \
+	CALC_66 \
+	CALC_67 \
+	CALC_68 \
+	CALC_69 \
+	CALC_70 \
+	CALC_71 \
+	CALC_72 \
+	CALC_73 \
+	CALC_74 \
+	CALC_75 \
+	CALC_76 \
+	CALC_77 \
+	CALC_78 \
+	CALC_79 \
+	UPDATE_HASH(AX,DX,BX,SI,DI) \
+	CMPQ R10, R8 \ // is current block the last one?
+	JE loop\
+	MOVL DX, CX \
+	CALC_80 \
+	CALC_81 \
+	CALC_82 \
+	CALC_83 \
+	CALC_84 \
+	CALC_85 \
+	CALC_86 \
+	CALC_87 \
+	CALC_88 \
+	CALC_89 \
+	CALC_90 \
+	CALC_91 \
+	CALC_92 \
+	CALC_93 \
+	CALC_94 \
+	CALC_95 \
+	CALC_96 \
+	CALC_97 \
+	CALC_98 \
+	CALC_99 \
+	CALC_100 \
+	CALC_101 \
+	CALC_102 \
+	CALC_103 \
+	CALC_104 \
+	CALC_105 \
+	CALC_106 \
+	CALC_107 \
+	CALC_108 \
+	CALC_109 \
+	CALC_110 \
+	CALC_111 \
+	CALC_112 \
+	CALC_113 \
+	CALC_114 \
+	CALC_115 \
+	CALC_116 \
+	CALC_117 \
+	CALC_118 \
+	CALC_119 \
+	CALC_120 \
+	CALC_121 \
+	CALC_122 \
+	CALC_123 \
+	CALC_124 \
+	CALC_125 \
+	CALC_126 \
+	CALC_127 \
+	CALC_128 \
+	CALC_129 \
+	CALC_130 \
+	CALC_131 \
+	CALC_132 \
+	CALC_133 \
+	CALC_134 \
+	CALC_135 \
+	CALC_136 \
+	CALC_137 \
+	CALC_138 \
+	CALC_139 \
+	ADDQ $128, R13 \ //move to next even-64-byte block
+	CMPQ R13, R11 \ //is current block the last one?
+	CMOVQCC R8, R10 \
+	CALC_140 \
+	CALC_141 \
+	CALC_142 \
+	CALC_143 \
+	CALC_144 \
+	CALC_145 \
+	CALC_146 \
+	CALC_147 \
+	CALC_148 \
+	CALC_149 \
+	CALC_150 \
+	CALC_151 \
+	CALC_152 \
+	CALC_153 \
+	CALC_154 \
+	CALC_155 \
+	CALC_156 \
+	CALC_157 \
+	CALC_158 \
+	CALC_159 \
+	UPDATE_HASH(SI,DI,DX,CX,BX) \
+	MOVL	SI, R12 \ //Reset state for  AVX2 reg permutation
+	MOVL	DI, SI \
+	MOVL	DX, DI \
+	MOVL	BX, DX \
+	MOVL	CX, AX \
+	MOVL	R12, CX \
+	XCHGQ   R15, R14 \
+	JMP     loop
+
+
+
+TEXT ·blockAVX2(SB),$1408-32
+
+	MOVQ	dig+0(FP),	DI
+	MOVQ	p_base+8(FP),	SI
+	MOVQ	p_len+16(FP),	DX
+	SHRQ	$6,		DX
+	SHLQ	$6,		DX
+
+	MOVQ	$K_XMM_AR<>(SB), R8
+
+	MOVQ	DI, R9
+	MOVQ	SI, R10
+	LEAQ	64(SI), R13
+
+	ADDQ	SI, DX
+	ADDQ	$64, DX
+	MOVQ	DX, R11
+
+	CMPQ	R13, R11
+	CMOVQCC	R8, R13
+
+	MOVQ    $BSWAP_SHUFB_CTL<>(SB), R8
+	VMOVDQU (R8), Y10
+	MOVQ	$K_XMM_AR<>(SB), R8 //restore R8
+
+	CALC // RET is inside macros
+
+
+// func checkAVX2() bool
+// returns whether AVX2 is supported
+TEXT ·checkAVX2(SB),NOSPLIT,$0
+	CMPB runtime·support_avx2(SB), $1
+	JE   has
+        MOVB    $0, ret+0(FP)
+	RET
+has:
+        MOVB    $1, ret+0(FP)
+	RET
+
+
+DATA K_XMM_AR<>+0x00(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x04(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x08(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x0c(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x10(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x14(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x18(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x1c(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x20(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x24(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x28(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x2c(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x30(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x34(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x38(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x3c(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x40(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x44(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x48(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x4c(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x50(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x54(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x58(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x5c(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x60(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x64(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x68(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x6c(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x70(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x74(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x78(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x7c(SB)/4,$0xca62c1d6
+GLOBL K_XMM_AR<>(SB),RODATA,$128
+
+DATA BSWAP_SHUFB_CTL<>+0x00(SB)/4,$0x00010203
+DATA BSWAP_SHUFB_CTL<>+0x04(SB)/4,$0x04050607
+DATA BSWAP_SHUFB_CTL<>+0x08(SB)/4,$0x08090a0b
+DATA BSWAP_SHUFB_CTL<>+0x0c(SB)/4,$0x0c0d0e0f
+DATA BSWAP_SHUFB_CTL<>+0x10(SB)/4,$0x00010203
+DATA BSWAP_SHUFB_CTL<>+0x14(SB)/4,$0x04050607
+DATA BSWAP_SHUFB_CTL<>+0x18(SB)/4,$0x08090a0b
+DATA BSWAP_SHUFB_CTL<>+0x1c(SB)/4,$0x0c0d0e0f
+GLOBL BSWAP_SHUFB_CTL<>(SB),RODATA,$32
diff --git a/src/crypto/sha1/sha1block_amd64p32.s b/src/crypto/sha1/sha1block_amd64p32.s
index d93fbf1..efebbf0 100644
--- a/src/crypto/sha1/sha1block_amd64p32.s
+++ b/src/crypto/sha1/sha1block_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/crypto/sha1/sha1block_arm.s b/src/crypto/sha1/sha1block_arm.s
index c06d4ba..9c76801 100644
--- a/src/crypto/sha1/sha1block_arm.s
+++ b/src/crypto/sha1/sha1block_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/crypto/sha1/sha1block_decl.go b/src/crypto/sha1/sha1block_decl.go
index 24e521a..6d2d073 100644
--- a/src/crypto/sha1/sha1block_decl.go
+++ b/src/crypto/sha1/sha1block_decl.go
@@ -1,8 +1,8 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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 arm 386
+// +build amd64p32 arm 386 s390x
 
 package sha1
 
diff --git a/src/crypto/sha1/sha1block_generic.go b/src/crypto/sha1/sha1block_generic.go
index 696e26b..f019462 100644
--- a/src/crypto/sha1/sha1block_generic.go
+++ b/src/crypto/sha1/sha1block_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 !amd64,!amd64p32,!386,!arm
+// +build !amd64,!amd64p32,!386,!arm,!s390x
 
 package sha1
 
diff --git a/src/crypto/sha1/sha1block_s390x.go b/src/crypto/sha1/sha1block_s390x.go
new file mode 100644
index 0000000..aac7c11
--- /dev/null
+++ b/src/crypto/sha1/sha1block_s390x.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha1
+
+// featureCheck reports whether the CPU supports the
+// SHA1 compute intermediate message digest (KIMD)
+// function code.
+func featureCheck() bool
+
+var useAsm = featureCheck()
diff --git a/src/crypto/sha1/sha1block_s390x.s b/src/crypto/sha1/sha1block_s390x.s
new file mode 100644
index 0000000..a9c4b08
--- /dev/null
+++ b/src/crypto/sha1/sha1block_s390x.s
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go 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 featureCheck() bool
+TEXT ·featureCheck(SB),NOSPLIT,$16-1
+	LA	tmp-16(SP), R1
+	XOR	R0, R0         // query function code is 0
+	WORD    $0xB93E0006    // KIMD (R6 is ignored)
+	MOVBZ	tmp-16(SP), R4 // get the first byte
+	AND	$0x40, R4      // bit 1 (big endian) for SHA1
+	CMPBEQ	R4, $0, nosha1
+	MOVB	$1, ret+0(FP)
+	RET
+nosha1:
+	MOVB	$0, ret+0(FP)
+	RET
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB),NOSPLIT,$0-32
+	MOVBZ	·useAsm(SB), R4
+	LMG	dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
+	CMPBNE	R4, $1, generic
+	MOVBZ	$1, R0        // SHA1 function code
+loop:
+	WORD	$0xB93E0002   // KIMD R2
+	BVS	loop          // continue if interrupted
+done:
+	XOR	R0, R0        // restore R0
+	RET
+generic:
+	BR	·blockGeneric(SB)
diff --git a/src/crypto/sha256/fallback_test.go b/src/crypto/sha256/fallback_test.go
new file mode 100644
index 0000000..5917a48
--- /dev/null
+++ b/src/crypto/sha256/fallback_test.go
@@ -0,0 +1,35 @@
+// Copyright 2016 The Go 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 s390x
+
+package sha256
+
+import (
+	"fmt"
+	"io"
+	"testing"
+)
+
+// Tests the fallback code path in case the optimized asm
+// implementation cannot be used.
+// See also TestBlockGeneric.
+func TestGenericPath(t *testing.T) {
+	if useAsm == false {
+		t.Skipf("assembly implementation unavailable")
+	}
+	useAsm = false
+	defer func() { useAsm = true }()
+	c := New()
+	in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜΝΞΟΠϺϘΡΣΤΥΦΧΨΩ"
+	gold := "e93d84ec2b22383123be9f713697fb25" +
+		"338c86e2f7d8d1ddc2d89d332dd9d76c"
+	if _, err := io.WriteString(c, in); err != nil {
+		t.Fatalf("could not write to c: %v", err)
+	}
+	out := fmt.Sprintf("%x", c.Sum(nil))
+	if out != gold {
+		t.Fatalf("mismatch: got %s, wanted %s", out, gold)
+	}
+}
diff --git a/src/crypto/sha256/sha256.go b/src/crypto/sha256/sha256.go
index d84cebf..74b05b9 100644
--- a/src/crypto/sha256/sha256.go
+++ b/src/crypto/sha256/sha256.go
@@ -137,7 +137,7 @@ func (d0 *digest) Sum(in []byte) []byte {
 
 func (d *digest) checkSum() [Size]byte {
 	len := d.len
-	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
+	// Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
 	var tmp [64]byte
 	tmp[0] = 0x80
 	if len%64 < 56 {
diff --git a/src/crypto/sha256/sha256_test.go b/src/crypto/sha256/sha256_test.go
index 1d883d3..279cf5a 100644
--- a/src/crypto/sha256/sha256_test.go
+++ b/src/crypto/sha256/sha256_test.go
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// SHA256 hash algorithm.  See FIPS 180-2.
+// SHA256 hash algorithm. See FIPS 180-2.
 
 package sha256
 
 import (
+	"crypto/rand"
 	"fmt"
 	"io"
 	"testing"
@@ -150,6 +151,18 @@ func TestBlockSize(t *testing.T) {
 	}
 }
 
+// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
+func TestBlockGeneric(t *testing.T) {
+	gen, asm := New().(*digest), New().(*digest)
+	buf := make([]byte, BlockSize*20) // arbitrary factor
+	rand.Read(buf)
+	blockGeneric(gen, buf)
+	block(asm, buf)
+	if *gen != *asm {
+		t.Error("block and blockGeneric resulted in different states")
+	}
+}
+
 var bench = New()
 var buf = make([]byte, 8192)
 
diff --git a/src/crypto/sha256/sha256block.go b/src/crypto/sha256/sha256block.go
index ca5efd1..d43bbf0 100644
--- a/src/crypto/sha256/sha256block.go
+++ b/src/crypto/sha256/sha256block.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 !386,!amd64
-
 // SHA256 block step.
 // In its own file so that a faster assembly or C version
 // can be substituted easily.
@@ -77,7 +75,7 @@ var _K = []uint32{
 	0xc67178f2,
 }
 
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
 	var w [64]uint32
 	h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
 	for len(p) >= chunk {
diff --git a/src/crypto/sha256/sha256block_386.s b/src/crypto/sha256/sha256block_386.s
index 73ae2bf..e0353c3 100644
--- a/src/crypto/sha256/sha256block_386.s
+++ b/src/crypto/sha256/sha256block_386.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/crypto/sha256/sha256block_amd64.s b/src/crypto/sha256/sha256block_amd64.s
index 868eaed..6ab3b52 100644
--- a/src/crypto/sha256/sha256block_amd64.s
+++ b/src/crypto/sha256/sha256block_amd64.s
@@ -9,7 +9,18 @@
 // The algorithm is detailed in FIPS 180-4:
 //
 //  http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
-//
+
+// The avx2-version is described in an Intel White-Paper:
+// "Fast SHA-256 Implementations on Intel Architecture Processors"
+// To find it, surf to http://www.intel.com/p/en_US/embedded
+// and search for that title.
+// AVX2 version by Intel, same algorithm as code in Linux kernel:
+// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha256-avx2-asm.S
+// by
+//     James Guilford <james.guilford at intel.com>
+//     Kirk Yap <kirk.s.yap at intel.com>
+//     Tim Chen <tim.c.chen at linux.intel.com>
+
 // Wt = Mt; for 0 <= t <= 15
 // Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
 //
@@ -140,29 +151,439 @@
 	MSGSCHEDULE1(index); \
 	SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
 
-TEXT ·block(SB),0,$264-32
-	MOVQ	p_base+8(FP), SI
-	MOVQ	p_len+16(FP), DX
-	SHRQ	$6, DX
-	SHLQ	$6, DX
-
-	LEAQ	(SI)(DX*1), DI
-	MOVQ	DI, 256(SP)
-	CMPQ	SI, DI
-	JEQ	end
-
-	MOVQ	dig+0(FP), BP
-	MOVL	(0*4)(BP), R8		// a = H0
-	MOVL	(1*4)(BP), R9		// b = H1
-	MOVL	(2*4)(BP), R10		// c = H2
-	MOVL	(3*4)(BP), R11		// d = H3
-	MOVL	(4*4)(BP), R12		// e = H4
-	MOVL	(5*4)(BP), R13		// f = H5
-	MOVL	(6*4)(BP), R14		// g = H6
-	MOVL	(7*4)(BP), R15		// h = H7
+
+// Definitions for AVX2 version
+
+// addm (mem), reg
+// Add reg to mem using reg-mem add and store
+#define addm(P1, P2) \
+	ADDL P2, P1; \
+	MOVL P1, P2
+
+#define XDWORD0 Y4
+#define XDWORD1 Y5
+#define XDWORD2 Y6
+#define XDWORD3 Y7
+
+#define XWORD0 X4
+#define XWORD1 X5
+#define XWORD2 X6
+#define XWORD3 X7
+
+#define XTMP0 Y0
+#define XTMP1 Y1
+#define XTMP2 Y2
+#define XTMP3 Y3
+#define XTMP4 Y8
+#define XTMP5 Y11
+
+#define XFER  Y9
+
+#define BYTE_FLIP_MASK 	Y13 // mask to convert LE -> BE
+#define X_BYTE_FLIP_MASK X13
+
+#define NUM_BYTES DX
+#define INP	DI
+
+#define CTX SI // Beginning of digest in memory (a, b, c, ... , h)
+
+#define a AX
+#define b BX
+#define c CX
+#define d R8
+#define e DX
+#define f R9
+#define g R10
+#define h R11
+
+#define old_h R11
+
+#define TBL BP
+
+#define SRND SI // SRND is same register as CTX
+
+#define T1 R12
+
+#define y0 R13
+#define y1 R14
+#define y2 R15
+#define y3 DI
+
+// Offsets
+#define XFER_SIZE 2*64*4
+#define INP_END_SIZE 8
+#define INP_SIZE 8
+#define TMP_SIZE 4
+
+#define _XFER 0
+#define _INP_END _XFER + XFER_SIZE
+#define _INP _INP_END + INP_END_SIZE
+#define _TMP _INP + INP_SIZE
+#define STACK_SIZE _TMP + TMP_SIZE
+
+#define ROUND_AND_SCHED_N_0(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+	;                                     \ // #############################  RND N + 0 ############################//
+	MOVL     a, y3;                       \ // y3 = a					// MAJA
+	RORXL    $25, e, y0;                  \ // y0 = e >> 25				// S1A
+	RORXL    $11, e, y1;                  \ // y1 = e >> 11				// S1B
+	;                                     \
+	ADDL     (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h        // disp = k + w
+	ORL      c, y3;                       \ // y3 = a|c				// MAJA
+	VPALIGNR $4, XDWORD2, XDWORD3, XTMP0; \ // XTMP0 = W[-7]
+	MOVL     f, y2;                       \ // y2 = f				// CH
+	RORXL    $13, a, T1;                  \ // T1 = a >> 13			// S0B
+	;                                     \
+	XORL     y1, y0;                      \ // y0 = (e>>25) ^ (e>>11)					// S1
+	XORL     g, y2;                       \ // y2 = f^g                              	// CH
+	VPADDD   XDWORD0, XTMP0, XTMP0;       \ // XTMP0 = W[-7] + W[-16]	// y1 = (e >> 6)	// S1
+	RORXL    $6, e, y1;                   \ // y1 = (e >> 6)						// S1
+	;                                     \
+	ANDL     e, y2;                       \ // y2 = (f^g)&e                         // CH
+	XORL     y1, y0;                      \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6)		// S1
+	RORXL    $22, a, y1;                  \ // y1 = a >> 22							// S0A
+	ADDL     h, d;                        \ // d = k + w + h + d                     	// --
+	;                                     \
+	ANDL     b, y3;                       \ // y3 = (a|c)&b							// MAJA
+	VPALIGNR $4, XDWORD0, XDWORD1, XTMP1; \ // XTMP1 = W[-15]
+	XORL     T1, y1;                      \ // y1 = (a>>22) ^ (a>>13)				// S0
+	RORXL    $2, a, T1;                   \ // T1 = (a >> 2)						// S0
+	;                                     \
+	XORL     g, y2;                       \ // y2 = CH = ((f^g)&e)^g				// CH
+	VPSRLD   $7, XTMP1, XTMP2;            \
+	XORL     T1, y1;                      \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2)		// S0
+	MOVL     a, T1;                       \ // T1 = a								// MAJB
+	ANDL     c, T1;                       \ // T1 = a&c								// MAJB
+	;                                     \
+	ADDL     y0, y2;                      \ // y2 = S1 + CH							// --
+	VPSLLD   $(32-7), XTMP1, XTMP3;       \
+	ORL      T1, y3;                      \ // y3 = MAJ = (a|c)&b)|(a&c)			// MAJ
+	ADDL     y1, h;                       \ // h = k + w + h + S0					// --
+	;                                     \
+	ADDL     y2, d;                       \ // d = k + w + h + d + S1 + CH = d + t1  // --
+	VPOR     XTMP2, XTMP3, XTMP3;         \ // XTMP3 = W[-15] ror 7
+	;                                     \
+	VPSRLD   $18, XTMP1, XTMP2;           \
+	ADDL     y2, h;                       \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+	ADDL     y3, h                        // h = t1 + S0 + MAJ                     // --
+
+#define ROUND_AND_SCHED_N_1(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+	;                                    \ // ################################### RND N + 1 ############################
+	;                                    \
+	MOVL    a, y3;                       \ // y3 = a                       // MAJA
+	RORXL   $25, e, y0;                  \ // y0 = e >> 25					// S1A
+	RORXL   $11, e, y1;                  \ // y1 = e >> 11					// S1B
+	ADDL    (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h         		// --
+	ORL     c, y3;                       \ // y3 = a|c						// MAJA
+	;                                    \
+	VPSRLD  $3, XTMP1, XTMP4;            \ // XTMP4 = W[-15] >> 3
+	MOVL    f, y2;                       \ // y2 = f						// CH
+	RORXL   $13, a, T1;                  \ // T1 = a >> 13					// S0B
+	XORL    y1, y0;                      \ // y0 = (e>>25) ^ (e>>11)		// S1
+	XORL    g, y2;                       \ // y2 = f^g						// CH
+	;                                    \
+	RORXL   $6, e, y1;                   \ // y1 = (e >> 6)				// S1
+	XORL    y1, y0;                      \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6)	// S1
+	RORXL   $22, a, y1;                  \ // y1 = a >> 22						// S0A
+	ANDL    e, y2;                       \ // y2 = (f^g)&e						// CH
+	ADDL    h, d;                        \ // d = k + w + h + d				// --
+	;                                    \
+	VPSLLD  $(32-18), XTMP1, XTMP1;      \
+	ANDL    b, y3;                       \ // y3 = (a|c)&b					// MAJA
+	XORL    T1, y1;                      \ // y1 = (a>>22) ^ (a>>13)		// S0
+	;                                    \
+	VPXOR   XTMP1, XTMP3, XTMP3;         \
+	RORXL   $2, a, T1;                   \ // T1 = (a >> 2)				// S0
+	XORL    g, y2;                       \ // y2 = CH = ((f^g)&e)^g		// CH
+	;                                    \
+	VPXOR   XTMP2, XTMP3, XTMP3;         \ // XTMP3 = W[-15] ror 7 ^ W[-15] ror 18
+	XORL    T1, y1;                      \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2)		// S0
+	MOVL    a, T1;                       \ // T1 = a						// MAJB
+	ANDL    c, T1;                       \ // T1 = a&c						// MAJB
+	ADDL    y0, y2;                      \ // y2 = S1 + CH					// --
+	;                                    \
+	VPXOR   XTMP4, XTMP3, XTMP1;         \ // XTMP1 = s0
+	VPSHUFD $-6, XDWORD3, XTMP2;         \ // XTMP2 = W[-2] {BBAA}
+	ORL     T1, y3;                      \ // y3 = MAJ = (a|c)&b)|(a&c)             // MAJ
+	ADDL    y1, h;                       \ // h = k + w + h + S0                    // --
+	;                                    \
+	VPADDD  XTMP1, XTMP0, XTMP0;         \ // XTMP0 = W[-16] + W[-7] + s0
+	ADDL    y2, d;                       \ // d = k + w + h + d + S1 + CH = d + t1  // --
+	ADDL    y2, h;                       \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+	ADDL    y3, h;                       \ // h = t1 + S0 + MAJ                     // --
+	;                                    \
+	VPSRLD  $10, XTMP2, XTMP4            // XTMP4 = W[-2] >> 10 {BBAA}
+
+#define ROUND_AND_SCHED_N_2(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+	;                                    \ // ################################### RND N + 2 ############################
+	;                                    \
+	MOVL    a, y3;                       \ // y3 = a							// MAJA
+	RORXL   $25, e, y0;                  \ // y0 = e >> 25						// S1A
+	ADDL    (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h        			// --
+	;                                    \
+	VPSRLQ  $19, XTMP2, XTMP3;           \ // XTMP3 = W[-2] ror 19 {xBxA}
+	RORXL   $11, e, y1;                  \ // y1 = e >> 11						// S1B
+	ORL     c, y3;                       \ // y3 = a|c                         // MAJA
+	MOVL    f, y2;                       \ // y2 = f                           // CH
+	XORL    g, y2;                       \ // y2 = f^g                         // CH
+	;                                    \
+	RORXL   $13, a, T1;                  \ // T1 = a >> 13						// S0B
+	XORL    y1, y0;                      \ // y0 = (e>>25) ^ (e>>11)			// S1
+	VPSRLQ  $17, XTMP2, XTMP2;           \ // XTMP2 = W[-2] ror 17 {xBxA}
+	ANDL    e, y2;                       \ // y2 = (f^g)&e						// CH
+	;                                    \
+	RORXL   $6, e, y1;                   \ // y1 = (e >> 6)					// S1
+	VPXOR   XTMP3, XTMP2, XTMP2;         \
+	ADDL    h, d;                        \ // d = k + w + h + d				// --
+	ANDL    b, y3;                       \ // y3 = (a|c)&b						// MAJA
+	;                                    \
+	XORL    y1, y0;                      \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6)	// S1
+	RORXL   $22, a, y1;                  \ // y1 = a >> 22						// S0A
+	VPXOR   XTMP2, XTMP4, XTMP4;         \ // XTMP4 = s1 {xBxA}
+	XORL    g, y2;                       \ // y2 = CH = ((f^g)&e)^g			// CH
+	;                                    \
+	MOVL    f, _TMP(SP);                 \
+	MOVQ    $shuff_00BA<>(SB), f;        \ // f is used to keep SHUF_00BA
+	VPSHUFB (f), XTMP4, XTMP4;           \ // XTMP4 = s1 {00BA}
+	MOVL    _TMP(SP), f;                 \ // f is restored
+	;                                    \
+	XORL    T1, y1;                      \ // y1 = (a>>22) ^ (a>>13)		// S0
+	RORXL   $2, a, T1;                   \ // T1 = (a >> 2)				// S0
+	VPADDD  XTMP4, XTMP0, XTMP0;         \ // XTMP0 = {..., ..., W[1], W[0]}
+	;                                    \
+	XORL    T1, y1;                      \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2)	// S0
+	MOVL    a, T1;                       \ // T1 = a                                // MAJB
+	ANDL    c, T1;                       \ // T1 = a&c                              // MAJB
+	ADDL    y0, y2;                      \ // y2 = S1 + CH                          // --
+	VPSHUFD $80, XTMP0, XTMP2;           \ // XTMP2 = W[-2] {DDCC}
+	;                                    \
+	ORL     T1, y3;                      \ // y3 = MAJ = (a|c)&b)|(a&c)             // MAJ
+	ADDL    y1, h;                       \ // h = k + w + h + S0                    // --
+	ADDL    y2, d;                       \ // d = k + w + h + d + S1 + CH = d + t1  // --
+	ADDL    y2, h;                       \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+	;                                    \
+	ADDL    y3, h                        // h = t1 + S0 + MAJ                     // --
+
+#define ROUND_AND_SCHED_N_3(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+	;                                    \ // ################################### RND N + 3 ############################
+	;                                    \
+	MOVL    a, y3;                       \ // y3 = a						// MAJA
+	RORXL   $25, e, y0;                  \ // y0 = e >> 25					// S1A
+	RORXL   $11, e, y1;                  \ // y1 = e >> 11					// S1B
+	ADDL    (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h				// --
+	ORL     c, y3;                       \ // y3 = a|c                     // MAJA
+	;                                    \
+	VPSRLD  $10, XTMP2, XTMP5;           \ // XTMP5 = W[-2] >> 10 {DDCC}
+	MOVL    f, y2;                       \ // y2 = f						// CH
+	RORXL   $13, a, T1;                  \ // T1 = a >> 13					// S0B
+	XORL    y1, y0;                      \ // y0 = (e>>25) ^ (e>>11)		// S1
+	XORL    g, y2;                       \ // y2 = f^g						// CH
+	;                                    \
+	VPSRLQ  $19, XTMP2, XTMP3;           \ // XTMP3 = W[-2] ror 19 {xDxC}
+	RORXL   $6, e, y1;                   \ // y1 = (e >> 6)				// S1
+	ANDL    e, y2;                       \ // y2 = (f^g)&e					// CH
+	ADDL    h, d;                        \ // d = k + w + h + d			// --
+	ANDL    b, y3;                       \ // y3 = (a|c)&b					// MAJA
+	;                                    \
+	VPSRLQ  $17, XTMP2, XTMP2;           \ // XTMP2 = W[-2] ror 17 {xDxC}
+	XORL    y1, y0;                      \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6)	// S1
+	XORL    g, y2;                       \ // y2 = CH = ((f^g)&e)^g			// CH
+	;                                    \
+	VPXOR   XTMP3, XTMP2, XTMP2;         \
+	RORXL   $22, a, y1;                  \ // y1 = a >> 22					// S0A
+	ADDL    y0, y2;                      \ // y2 = S1 + CH					// --
+	;                                    \
+	VPXOR   XTMP2, XTMP5, XTMP5;         \ // XTMP5 = s1 {xDxC}
+	XORL    T1, y1;                      \ // y1 = (a>>22) ^ (a>>13)		// S0
+	ADDL    y2, d;                       \ // d = k + w + h + d + S1 + CH = d + t1  // --
+	;                                    \
+	RORXL   $2, a, T1;                   \ // T1 = (a >> 2)				// S0
+	;                                    \
+	MOVL    f, _TMP(SP);                 \ // Save f
+	MOVQ    $shuff_DC00<>(SB), f;        \ // SHUF_00DC
+	VPSHUFB (f), XTMP5, XTMP5;           \ // XTMP5 = s1 {DC00}
+	MOVL    _TMP(SP), f;                 \ // Restore f
+	;                                    \
+	VPADDD  XTMP0, XTMP5, XDWORD0;       \ // XDWORD0 = {W[3], W[2], W[1], W[0]}
+	XORL    T1, y1;                      \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2)	// S0
+	MOVL    a, T1;                       \ // T1 = a							// MAJB
+	ANDL    c, T1;                       \ // T1 = a&c							// MAJB
+	ORL     T1, y3;                      \ // y3 = MAJ = (a|c)&b)|(a&c)		// MAJ
+	;                                    \
+	ADDL    y1, h;                       \ // h = k + w + h + S0				// --
+	ADDL    y2, h;                       \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+	ADDL    y3, h                        // h = t1 + S0 + MAJ				// --
+
+#define DO_ROUND_N_0(disp, a, b, c, d, e, f, g, h, old_h) \
+	;                                  \ // ################################### RND N + 0 ###########################
+	MOVL  f, y2;                       \ // y2 = f					// CH
+	RORXL $25, e, y0;                  \ // y0 = e >> 25				// S1A
+	RORXL $11, e, y1;                  \ // y1 = e >> 11				// S1B
+	XORL  g, y2;                       \ // y2 = f^g					// CH
+	;                                  \
+	XORL  y1, y0;                      \ // y0 = (e>>25) ^ (e>>11)	// S1
+	RORXL $6, e, y1;                   \ // y1 = (e >> 6)			// S1
+	ANDL  e, y2;                       \ // y2 = (f^g)&e				// CH
+	;                                  \
+	XORL  y1, y0;                      \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6)	// S1
+	RORXL $13, a, T1;                  \ // T1 = a >> 13						// S0B
+	XORL  g, y2;                       \ // y2 = CH = ((f^g)&e)^g			// CH
+	RORXL $22, a, y1;                  \ // y1 = a >> 22						// S0A
+	MOVL  a, y3;                       \ // y3 = a							// MAJA
+	;                                  \
+	XORL  T1, y1;                      \ // y1 = (a>>22) ^ (a>>13)			// S0
+	RORXL $2, a, T1;                   \ // T1 = (a >> 2)					// S0
+	ADDL  (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+	ORL   c, y3;                       \ // y3 = a|c							// MAJA
+	;                                  \
+	XORL  T1, y1;                      \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2)	// S0
+	MOVL  a, T1;                       \ // T1 = a							// MAJB
+	ANDL  b, y3;                       \ // y3 = (a|c)&b						// MAJA
+	ANDL  c, T1;                       \ // T1 = a&c							// MAJB
+	ADDL  y0, y2;                      \ // y2 = S1 + CH						// --
+	;                                  \
+	ADDL  h, d;                        \ // d = k + w + h + d					// --
+	ORL   T1, y3;                      \ // y3 = MAJ = (a|c)&b)|(a&c)			// MAJ
+	ADDL  y1, h;                       \ // h = k + w + h + S0					// --
+	ADDL  y2, d                        // d = k + w + h + d + S1 + CH = d + t1	// --
+
+#define DO_ROUND_N_1(disp, a, b, c, d, e, f, g, h, old_h) \
+	;                                  \ // ################################### RND N + 1 ###########################
+	ADDL  y2, old_h;                   \ // h = k + w + h + S0 + S1 + CH = t1 + S0 // --
+	MOVL  f, y2;                       \ // y2 = f                                // CH
+	RORXL $25, e, y0;                  \ // y0 = e >> 25				// S1A
+	RORXL $11, e, y1;                  \ // y1 = e >> 11				// S1B
+	XORL  g, y2;                       \ // y2 = f^g                             // CH
+	;                                  \
+	XORL  y1, y0;                      \ // y0 = (e>>25) ^ (e>>11)				// S1
+	RORXL $6, e, y1;                   \ // y1 = (e >> 6)						// S1
+	ANDL  e, y2;                       \ // y2 = (f^g)&e                         // CH
+	ADDL  y3, old_h;                   \ // h = t1 + S0 + MAJ                    // --
+	;                                  \
+	XORL  y1, y0;                      \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6)		// S1
+	RORXL $13, a, T1;                  \ // T1 = a >> 13							// S0B
+	XORL  g, y2;                       \ // y2 = CH = ((f^g)&e)^g                // CH
+	RORXL $22, a, y1;                  \ // y1 = a >> 22							// S0A
+	MOVL  a, y3;                       \ // y3 = a                               // MAJA
+	;                                  \
+	XORL  T1, y1;                      \ // y1 = (a>>22) ^ (a>>13)				// S0
+	RORXL $2, a, T1;                   \ // T1 = (a >> 2)						// S0
+	ADDL  (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+	ORL   c, y3;                       \ // y3 = a|c                             // MAJA
+	;                                  \
+	XORL  T1, y1;                      \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2)		// S0
+	MOVL  a, T1;                       \ // T1 = a                               // MAJB
+	ANDL  b, y3;                       \ // y3 = (a|c)&b                         // MAJA
+	ANDL  c, T1;                       \ // T1 = a&c                             // MAJB
+	ADDL  y0, y2;                      \ // y2 = S1 + CH                         // --
+	;                                  \
+	ADDL  h, d;                        \ // d = k + w + h + d                    // --
+	ORL   T1, y3;                      \ // y3 = MAJ = (a|c)&b)|(a&c)            // MAJ
+	ADDL  y1, h;                       \ // h = k + w + h + S0                   // --
+	;                                  \
+	ADDL  y2, d                        // d = k + w + h + d + S1 + CH = d + t1 // --
+
+#define DO_ROUND_N_2(disp, a, b, c, d, e, f, g, h, old_h) \
+	;                                  \ // ################################### RND N + 2 ##############################
+	ADDL  y2, old_h;                   \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+	MOVL  f, y2;                       \ // y2 = f								// CH
+	RORXL $25, e, y0;                  \ // y0 = e >> 25							// S1A
+	RORXL $11, e, y1;                  \ // y1 = e >> 11							// S1B
+	XORL  g, y2;                       \ // y2 = f^g								// CH
+	;                                  \
+	XORL  y1, y0;                      \ // y0 = (e>>25) ^ (e>>11)				// S1
+	RORXL $6, e, y1;                   \ // y1 = (e >> 6)						// S1
+	ANDL  e, y2;                       \ // y2 = (f^g)&e							// CH
+	ADDL  y3, old_h;                   \ // h = t1 + S0 + MAJ					// --
+	;                                  \
+	XORL  y1, y0;                      \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6)		// S1
+	RORXL $13, a, T1;                  \ // T1 = a >> 13							// S0B
+	XORL  g, y2;                       \ // y2 = CH = ((f^g)&e)^g                // CH
+	RORXL $22, a, y1;                  \ // y1 = a >> 22							// S0A
+	MOVL  a, y3;                       \ // y3 = a								// MAJA
+	;                                  \
+	XORL  T1, y1;                      \ // y1 = (a>>22) ^ (a>>13)				// S0
+	RORXL $2, a, T1;                   \ // T1 = (a >> 2)						// S0
+	ADDL  (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h 	// --
+	ORL   c, y3;                       \ // y3 = a|c								// MAJA
+	;                                  \
+	XORL  T1, y1;                      \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2)		// S0
+	MOVL  a, T1;                       \ // T1 = a								// MAJB
+	ANDL  b, y3;                       \ // y3 = (a|c)&b							// MAJA
+	ANDL  c, T1;                       \ // T1 = a&c								// MAJB
+	ADDL  y0, y2;                      \ // y2 = S1 + CH							// --
+	;                                  \
+	ADDL  h, d;                        \ // d = k + w + h + d					// --
+	ORL   T1, y3;                      \ // y3 = MAJ = (a|c)&b)|(a&c)			// MAJ
+	ADDL  y1, h;                       \ // h = k + w + h + S0					// --
+	;                                  \
+	ADDL  y2, d                        // d = k + w + h + d + S1 + CH = d + t1 // --
+
+#define DO_ROUND_N_3(disp, a, b, c, d, e, f, g, h, old_h) \
+	;                                  \ // ################################### RND N + 3 ###########################
+	ADDL  y2, old_h;                   \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+	MOVL  f, y2;                       \ // y2 = f								// CH
+	RORXL $25, e, y0;                  \ // y0 = e >> 25							// S1A
+	RORXL $11, e, y1;                  \ // y1 = e >> 11							// S1B
+	XORL  g, y2;                       \ // y2 = f^g								// CH
+	;                                  \
+	XORL  y1, y0;                      \ // y0 = (e>>25) ^ (e>>11)				// S1
+	RORXL $6, e, y1;                   \ // y1 = (e >> 6)						// S1
+	ANDL  e, y2;                       \ // y2 = (f^g)&e							// CH
+	ADDL  y3, old_h;                   \ // h = t1 + S0 + MAJ					// --
+	;                                  \
+	XORL  y1, y0;                      \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6)		// S1
+	RORXL $13, a, T1;                  \ // T1 = a >> 13							// S0B
+	XORL  g, y2;                       \ // y2 = CH = ((f^g)&e)^g				// CH
+	RORXL $22, a, y1;                  \ // y1 = a >> 22							// S0A
+	MOVL  a, y3;                       \ // y3 = a								// MAJA
+	;                                  \
+	XORL  T1, y1;                      \ // y1 = (a>>22) ^ (a>>13)				// S0
+	RORXL $2, a, T1;                   \ // T1 = (a >> 2)						// S0
+	ADDL  (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h 	// --
+	ORL   c, y3;                       \ // y3 = a|c								// MAJA
+	;                                  \
+	XORL  T1, y1;                      \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2)		// S0
+	MOVL  a, T1;                       \ // T1 = a								// MAJB
+	ANDL  b, y3;                       \ // y3 = (a|c)&b							// MAJA
+	ANDL  c, T1;                       \ // T1 = a&c								// MAJB
+	ADDL  y0, y2;                      \ // y2 = S1 + CH							// --
+	;                                  \
+	ADDL  h, d;                        \ // d = k + w + h + d					// --
+	ORL   T1, y3;                      \ // y3 = MAJ = (a|c)&b)|(a&c)			// MAJ
+	ADDL  y1, h;                       \ // h = k + w + h + S0					// --
+	;                                  \
+	ADDL  y2, d;                       \ // d = k + w + h + d + S1 + CH = d + t1	// --
+	;                                  \
+	ADDL  y2, h;                       \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+	;                                  \
+	ADDL  y3, h                        // h = t1 + S0 + MAJ					// --
+
+TEXT ·block(SB), 0, $536-32
+	CMPB runtime·support_avx2(SB), $1
+	JE   avx2
+
+	MOVQ p_base+8(FP), SI
+	MOVQ p_len+16(FP), DX
+	SHRQ $6, DX
+	SHLQ $6, DX
+
+	LEAQ (SI)(DX*1), DI
+	MOVQ DI, 256(SP)
+	CMPQ SI, DI
+	JEQ  end
+
+	MOVQ dig+0(FP), BP
+	MOVL (0*4)(BP), R8  // a = H0
+	MOVL (1*4)(BP), R9  // b = H1
+	MOVL (2*4)(BP), R10 // c = H2
+	MOVL (3*4)(BP), R11 // d = H3
+	MOVL (4*4)(BP), R12 // e = H4
+	MOVL (5*4)(BP), R13 // f = H5
+	MOVL (6*4)(BP), R14 // g = H6
+	MOVL (7*4)(BP), R15 // h = H7
 
 loop:
-	MOVQ	SP, BP			// message schedule
+	MOVQ SP, BP
 
 	SHA256ROUND0(0, 0x428a2f98, R8, R9, R10, R11, R12, R13, R14, R15)
 	SHA256ROUND0(1, 0x71374491, R15, R8, R9, R10, R11, R12, R13, R14)
@@ -230,27 +651,391 @@ loop:
 	SHA256ROUND1(62, 0xbef9a3f7, R10, R11, R12, R13, R14, R15, R8, R9)
 	SHA256ROUND1(63, 0xc67178f2, R9, R10, R11, R12, R13, R14, R15, R8)
 
-	MOVQ	dig+0(FP), BP
-	ADDL	(0*4)(BP), R8	// H0 = a + H0
-	MOVL	R8, (0*4)(BP)
-	ADDL	(1*4)(BP), R9	// H1 = b + H1
-	MOVL	R9, (1*4)(BP)
-	ADDL	(2*4)(BP), R10	// H2 = c + H2
-	MOVL	R10, (2*4)(BP)
-	ADDL	(3*4)(BP), R11	// H3 = d + H3
-	MOVL	R11, (3*4)(BP)
-	ADDL	(4*4)(BP), R12	// H4 = e + H4
-	MOVL	R12, (4*4)(BP)
-	ADDL	(5*4)(BP), R13	// H5 = f + H5
-	MOVL	R13, (5*4)(BP)
-	ADDL	(6*4)(BP), R14	// H6 = g + H6
-	MOVL	R14, (6*4)(BP)
-	ADDL	(7*4)(BP), R15	// H7 = h + H7
-	MOVL	R15, (7*4)(BP)
-
-	ADDQ	$64, SI
-	CMPQ	SI, 256(SP)
-	JB	loop
+	MOVQ dig+0(FP), BP
+	ADDL (0*4)(BP), R8  // H0 = a + H0
+	MOVL R8, (0*4)(BP)
+	ADDL (1*4)(BP), R9  // H1 = b + H1
+	MOVL R9, (1*4)(BP)
+	ADDL (2*4)(BP), R10 // H2 = c + H2
+	MOVL R10, (2*4)(BP)
+	ADDL (3*4)(BP), R11 // H3 = d + H3
+	MOVL R11, (3*4)(BP)
+	ADDL (4*4)(BP), R12 // H4 = e + H4
+	MOVL R12, (4*4)(BP)
+	ADDL (5*4)(BP), R13 // H5 = f + H5
+	MOVL R13, (5*4)(BP)
+	ADDL (6*4)(BP), R14 // H6 = g + H6
+	MOVL R14, (6*4)(BP)
+	ADDL (7*4)(BP), R15 // H7 = h + H7
+	MOVL R15, (7*4)(BP)
+
+	ADDQ $64, SI
+	CMPQ SI, 256(SP)
+	JB   loop
 
 end:
 	RET
+
+avx2:
+	MOVQ dig+0(FP), CTX          // d.h[8]
+	MOVQ p_base+8(FP), INP
+	MOVQ p_len+16(FP), NUM_BYTES
+
+	LEAQ -64(INP)(NUM_BYTES*1), NUM_BYTES // Pointer to the last block
+	MOVQ NUM_BYTES, _INP_END(SP)
+
+	CMPQ NUM_BYTES, INP
+	JE   avx2_only_one_block
+
+	// Load initial digest
+	MOVL 0(CTX), a  // a = H0
+	MOVL 4(CTX), b  // b = H1
+	MOVL 8(CTX), c  // c = H2
+	MOVL 12(CTX), d // d = H3
+	MOVL 16(CTX), e // e = H4
+	MOVL 20(CTX), f // f = H5
+	MOVL 24(CTX), g // g = H6
+	MOVL 28(CTX), h // h = H7
+
+avx2_loop0: // at each iteration works with one block (512 bit)
+
+	VMOVDQU (0*32)(INP), XTMP0
+	VMOVDQU (1*32)(INP), XTMP1
+	VMOVDQU (2*32)(INP), XTMP2
+	VMOVDQU (3*32)(INP), XTMP3
+
+	MOVQ    $flip_mask<>(SB), BP // BYTE_FLIP_MASK
+	VMOVDQU (BP), BYTE_FLIP_MASK
+
+	// Apply Byte Flip Mask: LE -> BE
+	VPSHUFB BYTE_FLIP_MASK, XTMP0, XTMP0
+	VPSHUFB BYTE_FLIP_MASK, XTMP1, XTMP1
+	VPSHUFB BYTE_FLIP_MASK, XTMP2, XTMP2
+	VPSHUFB BYTE_FLIP_MASK, XTMP3, XTMP3
+
+	// Transpose data into high/low parts
+	VPERM2I128 $0x20, XTMP2, XTMP0, XDWORD0 // w3, w2, w1, w0
+	VPERM2I128 $0x31, XTMP2, XTMP0, XDWORD1 // w7, w6, w5, w4
+	VPERM2I128 $0x20, XTMP3, XTMP1, XDWORD2 // w11, w10, w9, w8
+	VPERM2I128 $0x31, XTMP3, XTMP1, XDWORD3 // w15, w14, w13, w12
+
+	MOVQ $K256<>(SB), TBL // Loading address of table with round-specific constants
+
+avx2_last_block_enter:
+	ADDQ $64, INP
+	MOVQ INP, _INP(SP)
+	XORQ SRND, SRND
+
+avx2_loop1: // for w0 - w47
+	// Do 4 rounds and scheduling
+	VPADDD  0*32(TBL)(SRND*1), XDWORD0, XFER
+	VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1)
+	ROUND_AND_SCHED_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+	ROUND_AND_SCHED_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+	ROUND_AND_SCHED_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+	ROUND_AND_SCHED_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+
+	// Do 4 rounds and scheduling
+	VPADDD  1*32(TBL)(SRND*1), XDWORD1, XFER
+	VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1)
+	ROUND_AND_SCHED_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+	ROUND_AND_SCHED_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+	ROUND_AND_SCHED_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+	ROUND_AND_SCHED_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+
+	// Do 4 rounds and scheduling
+	VPADDD  2*32(TBL)(SRND*1), XDWORD2, XFER
+	VMOVDQU XFER, (_XFER + 2*32)(SP)(SRND*1)
+	ROUND_AND_SCHED_N_0(_XFER + 2*32, a, b, c, d, e, f, g, h, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+	ROUND_AND_SCHED_N_1(_XFER + 2*32, h, a, b, c, d, e, f, g, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+	ROUND_AND_SCHED_N_2(_XFER + 2*32, g, h, a, b, c, d, e, f, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+	ROUND_AND_SCHED_N_3(_XFER + 2*32, f, g, h, a, b, c, d, e, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+
+	// Do 4 rounds and scheduling
+	VPADDD  3*32(TBL)(SRND*1), XDWORD3, XFER
+	VMOVDQU XFER, (_XFER + 3*32)(SP)(SRND*1)
+	ROUND_AND_SCHED_N_0(_XFER + 3*32, e, f, g, h, a, b, c, d, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+	ROUND_AND_SCHED_N_1(_XFER + 3*32, d, e, f, g, h, a, b, c, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+	ROUND_AND_SCHED_N_2(_XFER + 3*32, c, d, e, f, g, h, a, b, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+	ROUND_AND_SCHED_N_3(_XFER + 3*32, b, c, d, e, f, g, h, a, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+
+	ADDQ $4*32, SRND
+	CMPQ SRND, $3*4*32
+	JB   avx2_loop1
+
+avx2_loop2:
+	// w48 - w63 processed with no scheduliung (last 16 rounds)
+	VPADDD  0*32(TBL)(SRND*1), XDWORD0, XFER
+	VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1)
+	DO_ROUND_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, h)
+	DO_ROUND_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, h)
+	DO_ROUND_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, g)
+	DO_ROUND_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, f)
+
+	VPADDD  1*32(TBL)(SRND*1), XDWORD1, XFER
+	VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1)
+	DO_ROUND_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, e)
+	DO_ROUND_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, d)
+	DO_ROUND_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, c)
+	DO_ROUND_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, b)
+
+	ADDQ $2*32, SRND
+
+	VMOVDQU XDWORD2, XDWORD0
+	VMOVDQU XDWORD3, XDWORD1
+
+	CMPQ SRND, $4*4*32
+	JB   avx2_loop2
+
+	MOVQ dig+0(FP), CTX // d.h[8]
+	MOVQ _INP(SP), INP
+
+	addm(  0(CTX), a)
+	addm(  4(CTX), b)
+	addm(  8(CTX), c)
+	addm( 12(CTX), d)
+	addm( 16(CTX), e)
+	addm( 20(CTX), f)
+	addm( 24(CTX), g)
+	addm( 28(CTX), h)
+
+	CMPQ _INP_END(SP), INP
+	JB   done_hash
+
+	XORQ SRND, SRND
+
+avx2_loop3: // Do second block using previously scheduled results
+	DO_ROUND_N_0(_XFER + 0*32 + 16, a, b, c, d, e, f, g, h, a)
+	DO_ROUND_N_1(_XFER + 0*32 + 16, h, a, b, c, d, e, f, g, h)
+	DO_ROUND_N_2(_XFER + 0*32 + 16, g, h, a, b, c, d, e, f, g)
+	DO_ROUND_N_3(_XFER + 0*32 + 16, f, g, h, a, b, c, d, e, f)
+
+	DO_ROUND_N_0(_XFER + 1*32 + 16, e, f, g, h, a, b, c, d, e)
+	DO_ROUND_N_1(_XFER + 1*32 + 16, d, e, f, g, h, a, b, c, d)
+	DO_ROUND_N_2(_XFER + 1*32 + 16, c, d, e, f, g, h, a, b, c)
+	DO_ROUND_N_3(_XFER + 1*32 + 16, b, c, d, e, f, g, h, a, b)
+
+	ADDQ $2*32, SRND
+	CMPQ SRND, $4*4*32
+	JB   avx2_loop3
+
+	MOVQ dig+0(FP), CTX // d.h[8]
+	MOVQ _INP(SP), INP
+	ADDQ $64, INP
+
+	addm(  0(CTX), a)
+	addm(  4(CTX), b)
+	addm(  8(CTX), c)
+	addm( 12(CTX), d)
+	addm( 16(CTX), e)
+	addm( 20(CTX), f)
+	addm( 24(CTX), g)
+	addm( 28(CTX), h)
+
+	CMPQ _INP_END(SP), INP
+	JA   avx2_loop0
+	JB   done_hash
+
+avx2_do_last_block:
+
+	VMOVDQU 0(INP), XWORD0
+	VMOVDQU 16(INP), XWORD1
+	VMOVDQU 32(INP), XWORD2
+	VMOVDQU 48(INP), XWORD3
+
+	MOVQ    $flip_mask<>(SB), BP
+	VMOVDQU (BP), X_BYTE_FLIP_MASK
+
+	VPSHUFB X_BYTE_FLIP_MASK, XWORD0, XWORD0
+	VPSHUFB X_BYTE_FLIP_MASK, XWORD1, XWORD1
+	VPSHUFB X_BYTE_FLIP_MASK, XWORD2, XWORD2
+	VPSHUFB X_BYTE_FLIP_MASK, XWORD3, XWORD3
+
+	MOVQ $K256<>(SB), TBL
+
+	JMP avx2_last_block_enter
+
+avx2_only_one_block:
+	// Load initial digest
+	MOVL 0(CTX), a  // a = H0
+	MOVL 4(CTX), b  // b = H1
+	MOVL 8(CTX), c  // c = H2
+	MOVL 12(CTX), d // d = H3
+	MOVL 16(CTX), e // e = H4
+	MOVL 20(CTX), f // f = H5
+	MOVL 24(CTX), g // g = H6
+	MOVL 28(CTX), h // h = H7
+
+	JMP avx2_do_last_block
+
+done_hash:
+	VZEROUPPER
+	RET
+
+// shuffle byte order from LE to BE
+DATA flip_mask<>+0x00(SB)/8, $0x0405060700010203
+DATA flip_mask<>+0x08(SB)/8, $0x0c0d0e0f08090a0b
+DATA flip_mask<>+0x10(SB)/8, $0x0405060700010203
+DATA flip_mask<>+0x18(SB)/8, $0x0c0d0e0f08090a0b
+GLOBL flip_mask<>(SB), 8, $32
+
+// shuffle xBxA -> 00BA
+DATA shuff_00BA<>+0x00(SB)/8, $0x0b0a090803020100
+DATA shuff_00BA<>+0x08(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA shuff_00BA<>+0x10(SB)/8, $0x0b0a090803020100
+DATA shuff_00BA<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF
+GLOBL shuff_00BA<>(SB), 8, $32
+
+// shuffle xDxC -> DC00
+DATA shuff_DC00<>+0x00(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA shuff_DC00<>+0x08(SB)/8, $0x0b0a090803020100
+DATA shuff_DC00<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA shuff_DC00<>+0x18(SB)/8, $0x0b0a090803020100
+GLOBL shuff_DC00<>(SB), 8, $32
+
+// Round specific constants
+DATA K256<>+0x00(SB)/4, $0x428a2f98 // k1
+DATA K256<>+0x04(SB)/4, $0x71374491 // k2
+DATA K256<>+0x08(SB)/4, $0xb5c0fbcf // k3
+DATA K256<>+0x0c(SB)/4, $0xe9b5dba5 // k4
+DATA K256<>+0x10(SB)/4, $0x428a2f98 // k1
+DATA K256<>+0x14(SB)/4, $0x71374491 // k2
+DATA K256<>+0x18(SB)/4, $0xb5c0fbcf // k3
+DATA K256<>+0x1c(SB)/4, $0xe9b5dba5 // k4
+
+DATA K256<>+0x20(SB)/4, $0x3956c25b // k5 - k8
+DATA K256<>+0x24(SB)/4, $0x59f111f1
+DATA K256<>+0x28(SB)/4, $0x923f82a4
+DATA K256<>+0x2c(SB)/4, $0xab1c5ed5
+DATA K256<>+0x30(SB)/4, $0x3956c25b
+DATA K256<>+0x34(SB)/4, $0x59f111f1
+DATA K256<>+0x38(SB)/4, $0x923f82a4
+DATA K256<>+0x3c(SB)/4, $0xab1c5ed5
+
+DATA K256<>+0x40(SB)/4, $0xd807aa98 // k9 - k12
+DATA K256<>+0x44(SB)/4, $0x12835b01
+DATA K256<>+0x48(SB)/4, $0x243185be
+DATA K256<>+0x4c(SB)/4, $0x550c7dc3
+DATA K256<>+0x50(SB)/4, $0xd807aa98
+DATA K256<>+0x54(SB)/4, $0x12835b01
+DATA K256<>+0x58(SB)/4, $0x243185be
+DATA K256<>+0x5c(SB)/4, $0x550c7dc3
+
+DATA K256<>+0x60(SB)/4, $0x72be5d74 // k13 - k16
+DATA K256<>+0x64(SB)/4, $0x80deb1fe
+DATA K256<>+0x68(SB)/4, $0x9bdc06a7
+DATA K256<>+0x6c(SB)/4, $0xc19bf174
+DATA K256<>+0x70(SB)/4, $0x72be5d74
+DATA K256<>+0x74(SB)/4, $0x80deb1fe
+DATA K256<>+0x78(SB)/4, $0x9bdc06a7
+DATA K256<>+0x7c(SB)/4, $0xc19bf174
+
+DATA K256<>+0x80(SB)/4, $0xe49b69c1 // k17 - k20
+DATA K256<>+0x84(SB)/4, $0xefbe4786
+DATA K256<>+0x88(SB)/4, $0x0fc19dc6
+DATA K256<>+0x8c(SB)/4, $0x240ca1cc
+DATA K256<>+0x90(SB)/4, $0xe49b69c1
+DATA K256<>+0x94(SB)/4, $0xefbe4786
+DATA K256<>+0x98(SB)/4, $0x0fc19dc6
+DATA K256<>+0x9c(SB)/4, $0x240ca1cc
+
+DATA K256<>+0xa0(SB)/4, $0x2de92c6f // k21 - k24
+DATA K256<>+0xa4(SB)/4, $0x4a7484aa
+DATA K256<>+0xa8(SB)/4, $0x5cb0a9dc
+DATA K256<>+0xac(SB)/4, $0x76f988da
+DATA K256<>+0xb0(SB)/4, $0x2de92c6f
+DATA K256<>+0xb4(SB)/4, $0x4a7484aa
+DATA K256<>+0xb8(SB)/4, $0x5cb0a9dc
+DATA K256<>+0xbc(SB)/4, $0x76f988da
+
+DATA K256<>+0xc0(SB)/4, $0x983e5152 // k25 - k28
+DATA K256<>+0xc4(SB)/4, $0xa831c66d
+DATA K256<>+0xc8(SB)/4, $0xb00327c8
+DATA K256<>+0xcc(SB)/4, $0xbf597fc7
+DATA K256<>+0xd0(SB)/4, $0x983e5152
+DATA K256<>+0xd4(SB)/4, $0xa831c66d
+DATA K256<>+0xd8(SB)/4, $0xb00327c8
+DATA K256<>+0xdc(SB)/4, $0xbf597fc7
+
+DATA K256<>+0xe0(SB)/4, $0xc6e00bf3 // k29 - k32
+DATA K256<>+0xe4(SB)/4, $0xd5a79147
+DATA K256<>+0xe8(SB)/4, $0x06ca6351
+DATA K256<>+0xec(SB)/4, $0x14292967
+DATA K256<>+0xf0(SB)/4, $0xc6e00bf3
+DATA K256<>+0xf4(SB)/4, $0xd5a79147
+DATA K256<>+0xf8(SB)/4, $0x06ca6351
+DATA K256<>+0xfc(SB)/4, $0x14292967
+
+DATA K256<>+0x100(SB)/4, $0x27b70a85
+DATA K256<>+0x104(SB)/4, $0x2e1b2138
+DATA K256<>+0x108(SB)/4, $0x4d2c6dfc
+DATA K256<>+0x10c(SB)/4, $0x53380d13
+DATA K256<>+0x110(SB)/4, $0x27b70a85
+DATA K256<>+0x114(SB)/4, $0x2e1b2138
+DATA K256<>+0x118(SB)/4, $0x4d2c6dfc
+DATA K256<>+0x11c(SB)/4, $0x53380d13
+
+DATA K256<>+0x120(SB)/4, $0x650a7354
+DATA K256<>+0x124(SB)/4, $0x766a0abb
+DATA K256<>+0x128(SB)/4, $0x81c2c92e
+DATA K256<>+0x12c(SB)/4, $0x92722c85
+DATA K256<>+0x130(SB)/4, $0x650a7354
+DATA K256<>+0x134(SB)/4, $0x766a0abb
+DATA K256<>+0x138(SB)/4, $0x81c2c92e
+DATA K256<>+0x13c(SB)/4, $0x92722c85
+
+DATA K256<>+0x140(SB)/4, $0xa2bfe8a1
+DATA K256<>+0x144(SB)/4, $0xa81a664b
+DATA K256<>+0x148(SB)/4, $0xc24b8b70
+DATA K256<>+0x14c(SB)/4, $0xc76c51a3
+DATA K256<>+0x150(SB)/4, $0xa2bfe8a1
+DATA K256<>+0x154(SB)/4, $0xa81a664b
+DATA K256<>+0x158(SB)/4, $0xc24b8b70
+DATA K256<>+0x15c(SB)/4, $0xc76c51a3
+
+DATA K256<>+0x160(SB)/4, $0xd192e819
+DATA K256<>+0x164(SB)/4, $0xd6990624
+DATA K256<>+0x168(SB)/4, $0xf40e3585
+DATA K256<>+0x16c(SB)/4, $0x106aa070
+DATA K256<>+0x170(SB)/4, $0xd192e819
+DATA K256<>+0x174(SB)/4, $0xd6990624
+DATA K256<>+0x178(SB)/4, $0xf40e3585
+DATA K256<>+0x17c(SB)/4, $0x106aa070
+
+DATA K256<>+0x180(SB)/4, $0x19a4c116
+DATA K256<>+0x184(SB)/4, $0x1e376c08
+DATA K256<>+0x188(SB)/4, $0x2748774c
+DATA K256<>+0x18c(SB)/4, $0x34b0bcb5
+DATA K256<>+0x190(SB)/4, $0x19a4c116
+DATA K256<>+0x194(SB)/4, $0x1e376c08
+DATA K256<>+0x198(SB)/4, $0x2748774c
+DATA K256<>+0x19c(SB)/4, $0x34b0bcb5
+
+DATA K256<>+0x1a0(SB)/4, $0x391c0cb3
+DATA K256<>+0x1a4(SB)/4, $0x4ed8aa4a
+DATA K256<>+0x1a8(SB)/4, $0x5b9cca4f
+DATA K256<>+0x1ac(SB)/4, $0x682e6ff3
+DATA K256<>+0x1b0(SB)/4, $0x391c0cb3
+DATA K256<>+0x1b4(SB)/4, $0x4ed8aa4a
+DATA K256<>+0x1b8(SB)/4, $0x5b9cca4f
+DATA K256<>+0x1bc(SB)/4, $0x682e6ff3
+
+DATA K256<>+0x1c0(SB)/4, $0x748f82ee
+DATA K256<>+0x1c4(SB)/4, $0x78a5636f
+DATA K256<>+0x1c8(SB)/4, $0x84c87814
+DATA K256<>+0x1cc(SB)/4, $0x8cc70208
+DATA K256<>+0x1d0(SB)/4, $0x748f82ee
+DATA K256<>+0x1d4(SB)/4, $0x78a5636f
+DATA K256<>+0x1d8(SB)/4, $0x84c87814
+DATA K256<>+0x1dc(SB)/4, $0x8cc70208
+
+DATA K256<>+0x1e0(SB)/4, $0x90befffa
+DATA K256<>+0x1e4(SB)/4, $0xa4506ceb
+DATA K256<>+0x1e8(SB)/4, $0xbef9a3f7
+DATA K256<>+0x1ec(SB)/4, $0xc67178f2
+DATA K256<>+0x1f0(SB)/4, $0x90befffa
+DATA K256<>+0x1f4(SB)/4, $0xa4506ceb
+DATA K256<>+0x1f8(SB)/4, $0xbef9a3f7
+DATA K256<>+0x1fc(SB)/4, $0xc67178f2
+
+GLOBL K256<>(SB), (NOPTR + RODATA), $512
diff --git a/src/crypto/sha256/sha256block_decl.go b/src/crypto/sha256/sha256block_decl.go
index a50c978..e6caff9 100644
--- a/src/crypto/sha256/sha256block_decl.go
+++ b/src/crypto/sha256/sha256block_decl.go
@@ -1,8 +1,8 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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 amd64
+// +build 386 amd64 s390x
 
 package sha256
 
diff --git a/src/crypto/sha256/sha256block_generic.go b/src/crypto/sha256/sha256block_generic.go
new file mode 100644
index 0000000..1a01969
--- /dev/null
+++ b/src/crypto/sha256/sha256block_generic.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go 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,!386,!s390x
+
+package sha256
+
+var block = blockGeneric
diff --git a/src/crypto/sha256/sha256block_s390x.go b/src/crypto/sha256/sha256block_s390x.go
new file mode 100644
index 0000000..b7beefe
--- /dev/null
+++ b/src/crypto/sha256/sha256block_s390x.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha256
+
+// featureCheck reports whether the CPU supports the
+// SHA256 compute intermediate message digest (KIMD)
+// function code.
+func featureCheck() bool
+
+var useAsm = featureCheck()
diff --git a/src/crypto/sha256/sha256block_s390x.s b/src/crypto/sha256/sha256block_s390x.s
new file mode 100644
index 0000000..ee35991
--- /dev/null
+++ b/src/crypto/sha256/sha256block_s390x.s
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go 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 featureCheck() bool
+TEXT ·featureCheck(SB),NOSPLIT,$16-1
+	LA	tmp-16(SP), R1
+	XOR	R0, R0         // query function code is 0
+	WORD    $0xB93E0006    // KIMD (R6 is ignored)
+	MOVBZ	tmp-16(SP), R4 // get the first byte
+	AND	$0x20, R4      // bit 2 (big endian) for SHA256
+	CMPBEQ	R4, $0, nosha256
+	MOVB	$1, ret+0(FP)
+	RET
+nosha256:
+	MOVB	$0, ret+0(FP)
+	RET
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB),NOSPLIT,$0-32
+	MOVBZ	·useAsm(SB), R4
+	LMG	dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
+	CMPBNE	R4, $1, generic
+	MOVBZ	$2, R0        // SHA256 function code
+loop:
+	WORD	$0xB93E0002   // KIMD R2
+	BVS	loop          // continue if interrupted
+done:
+	XOR	R0, R0        // restore R0
+	RET
+generic:
+	BR	·blockGeneric(SB)
diff --git a/src/crypto/sha512/fallback_test.go b/src/crypto/sha512/fallback_test.go
new file mode 100644
index 0000000..9024ce6
--- /dev/null
+++ b/src/crypto/sha512/fallback_test.go
@@ -0,0 +1,37 @@
+// Copyright 2016 The Go 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 s390x
+
+package sha512
+
+import (
+	"fmt"
+	"io"
+	"testing"
+)
+
+// Tests the fallback code path in case the optimized asm
+// implementation cannot be used.
+// See also TestBlockGeneric.
+func TestGenericPath(t *testing.T) {
+	if useAsm == false {
+		t.Skipf("assembly implementation unavailable")
+	}
+	useAsm = false
+	defer func() { useAsm = true }()
+	c := New()
+	in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜΝΞΟΠϺϘΡΣΤΥΦΧΨΩ"
+	gold := "6922e319366d677f34c504af31bfcb29" +
+		"e531c125ecd08679362bffbd6b6ebfb9" +
+		"0dcc27dfc1f3d3b16a16c0763cf43b91" +
+		"40bbf9bbb7233724e9a0c6655b185d76"
+	if _, err := io.WriteString(c, in); err != nil {
+		t.Fatalf("could not write to c: %v", err)
+	}
+	out := fmt.Sprintf("%x", c.Sum(nil))
+	if out != gold {
+		t.Fatalf("mismatch: got %s, wanted %s", out, gold)
+	}
+}
diff --git a/src/crypto/sha512/sha512.go b/src/crypto/sha512/sha512.go
index e7781fd..5603c90 100644
--- a/src/crypto/sha512/sha512.go
+++ b/src/crypto/sha512/sha512.go
@@ -208,7 +208,7 @@ func (d0 *digest) Sum(in []byte) []byte {
 }
 
 func (d *digest) checkSum() [Size]byte {
-	// Padding.  Add a 1 bit and 0 bits until 112 bytes mod 128.
+	// Padding. Add a 1 bit and 0 bits until 112 bytes mod 128.
 	len := d.len
 	var tmp [128]byte
 	tmp[0] = 0x80
diff --git a/src/crypto/sha512/sha512_test.go b/src/crypto/sha512/sha512_test.go
index 04b3d4a..a3a136a 100644
--- a/src/crypto/sha512/sha512_test.go
+++ b/src/crypto/sha512/sha512_test.go
@@ -2,11 +2,12 @@
 // 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-4.
+// SHA512 hash algorithm. See FIPS 180-4.
 
 package sha512
 
 import (
+	"crypto/rand"
 	"encoding/hex"
 	"hash"
 	"io"
@@ -304,6 +305,18 @@ func TestBlockSize(t *testing.T) {
 	}
 }
 
+// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
+func TestBlockGeneric(t *testing.T) {
+	gen, asm := New().(*digest), New().(*digest)
+	buf := make([]byte, BlockSize*20) // arbitrary factor
+	rand.Read(buf)
+	blockGeneric(gen, buf)
+	block(asm, buf)
+	if *gen != *asm {
+		t.Error("block and blockGeneric resulted in different states")
+	}
+}
+
 var bench = New()
 var buf = make([]byte, 8192)
 
diff --git a/src/crypto/sha512/sha512block.go b/src/crypto/sha512/sha512block.go
index 648ae8f..42e8d19 100644
--- a/src/crypto/sha512/sha512block.go
+++ b/src/crypto/sha512/sha512block.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 !amd64
-
 // SHA512 block step.
 // In its own file so that a faster assembly or C version
 // can be substituted easily.
@@ -93,7 +91,7 @@ var _K = []uint64{
 	0x6c44198c4a475817,
 }
 
-func block(dig *digest, p []byte) {
+func blockGeneric(dig *digest, p []byte) {
 	var w [80]uint64
 	h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
 	for len(p) >= chunk {
diff --git a/src/crypto/sha512/sha512block_amd64.s b/src/crypto/sha512/sha512block_amd64.s
index 2e10233..87502cd 100644
--- a/src/crypto/sha512/sha512block_amd64.s
+++ b/src/crypto/sha512/sha512block_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/crypto/sha512/sha512block_decl.go b/src/crypto/sha512/sha512block_decl.go
index bef99de..47d656a 100644
--- a/src/crypto/sha512/sha512block_decl.go
+++ b/src/crypto/sha512/sha512block_decl.go
@@ -1,8 +1,8 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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 amd64 s390x
 
 package sha512
 
diff --git a/src/crypto/sha512/sha512block_generic.go b/src/crypto/sha512/sha512block_generic.go
new file mode 100644
index 0000000..2c691ba
--- /dev/null
+++ b/src/crypto/sha512/sha512block_generic.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go 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,!s390x
+
+package sha512
+
+var block = blockGeneric
diff --git a/src/crypto/sha512/sha512block_s390x.go b/src/crypto/sha512/sha512block_s390x.go
new file mode 100644
index 0000000..f05dc18
--- /dev/null
+++ b/src/crypto/sha512/sha512block_s390x.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha512
+
+// featureCheck reports whether the CPU supports the
+// SHA512 compute intermediate message digest (KIMD)
+// function code.
+func featureCheck() bool
+
+var useAsm = featureCheck()
diff --git a/src/crypto/sha512/sha512block_s390x.s b/src/crypto/sha512/sha512block_s390x.s
new file mode 100644
index 0000000..aab81e2
--- /dev/null
+++ b/src/crypto/sha512/sha512block_s390x.s
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go 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 featureCheck() bool
+TEXT ·featureCheck(SB),NOSPLIT,$16-1
+	LA	tmp-16(SP), R1
+	XOR	R0, R0         // query function code is 0
+	WORD    $0xB93E0006    // KIMD (R6 is ignored)
+	MOVBZ	tmp-16(SP), R4 // get the first byte
+	AND	$0x10, R4      // bit 3 (big endian) for SHA512
+	CMPBEQ	R4, $0, nosha512
+	MOVB	$1, ret+0(FP)
+	RET
+nosha512:
+	MOVB	$0, ret+0(FP)
+	RET
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB),NOSPLIT,$0-32
+	MOVBZ	·useAsm(SB), R4
+	LMG	dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
+	CMPBNE	R4, $1, generic
+	MOVBZ	$3, R0        // SHA512 function code
+loop:
+	WORD	$0xB93E0002   // KIMD R2
+	BVS	loop          // continue if interrupted
+done:
+	XOR	R0, R0        // restore R0
+	RET
+generic:
+	BR	·blockGeneric(SB)
diff --git a/src/crypto/subtle/constant_time.go b/src/crypto/subtle/constant_time.go
index 6f80e7c..11312b8 100644
--- a/src/crypto/subtle/constant_time.go
+++ b/src/crypto/subtle/constant_time.go
@@ -6,7 +6,7 @@
 // code but require careful thought to use correctly.
 package subtle
 
-// ConstantTimeCompare returns 1 iff the two slices, x
+// ConstantTimeCompare returns 1 if and only if the two slices, x
 // and y, have equal contents. The time taken is a function of the length of
 // the slices and is independent of the contents.
 func ConstantTimeCompare(x, y []byte) int {
diff --git a/src/crypto/tls/alert.go b/src/crypto/tls/alert.go
index 3de4834..9cf9922 100644
--- a/src/crypto/tls/alert.go
+++ b/src/crypto/tls/alert.go
@@ -69,9 +69,9 @@ var alertText = map[alert]string{
 func (e alert) String() string {
 	s, ok := alertText[e]
 	if ok {
-		return s
+		return "tls: " + s
 	}
-	return "alert(" + strconv.Itoa(int(e)) + ")"
+	return "tls: alert(" + strconv.Itoa(int(e)) + ")"
 }
 
 func (e alert) Error() string {
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index 869ffa5..e69f5f9 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -74,7 +74,7 @@ type cipherSuite struct {
 
 var cipherSuites = []*cipherSuite{
 	// Ciphersuite order is chosen so that ECDHE comes before plain RSA
-	// and RC4 comes before AES (because of the Lucky13 attack).
+	// and RC4 comes before AES-CBC (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_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
@@ -261,8 +261,10 @@ func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
 	return nil
 }
 
-// A list of the possible cipher suite ids. Taken from
-// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+// A list of cipher suite IDs that are, or have been, implemented by this
+// package.
+//
+// Taken from http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
 const (
 	TLS_RSA_WITH_RC4_128_SHA                uint16 = 0x0005
 	TLS_RSA_WITH_3DES_EDE_CBC_SHA           uint16 = 0x000a
@@ -284,6 +286,6 @@ const (
 
 	// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
 	// that the client is doing version fallback. See
-	// https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00.
+	// https://tools.ietf.org/html/rfc7507.
 	TLS_FALLBACK_SCSV uint16 = 0x5600
 )
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index c68ebfe..9fc7420 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -48,6 +48,7 @@ const (
 
 // TLS handshake message types.
 const (
+	typeHelloRequest       uint8 = 0
 	typeClientHello        uint8 = 1
 	typeServerHello        uint8 = 2
 	typeNewSessionTicket   uint8 = 4
@@ -114,7 +115,7 @@ const (
 	certTypeRSAFixedDH = 3 // A certificate containing a static DH key
 	certTypeDSSFixedDH = 4 // A certificate containing a static DH key
 
-	// See RFC4492 sections 3 and 5.5.
+	// See RFC 4492 sections 3 and 5.5.
 	certTypeECDSASign      = 64 // A certificate containing an ECDSA-capable public key, signed with ECDSA.
 	certTypeRSAFixedECDH   = 65 // A certificate containing an ECDH-capable public key, signed with RSA.
 	certTypeECDSAFixedECDH = 66 // A certificate containing an ECDH-capable public key, signed with ECDSA.
@@ -238,6 +239,33 @@ type ClientHelloInfo struct {
 	SupportedPoints []uint8
 }
 
+// RenegotiationSupport enumerates the different levels of support for TLS
+// renegotiation. TLS renegotiation is the act of performing subsequent
+// handshakes on a connection after the first. This significantly complicates
+// the state machine and has been the source of numerous, subtle security
+// issues. Initiating a renegotiation is not supported, but support for
+// accepting renegotiation requests may be enabled.
+//
+// Even when enabled, the server may not change its identity between handshakes
+// (i.e. the leaf certificate must be the same). Additionally, concurrent
+// handshake and application data flow is not permitted so renegotiation can
+// only be used with protocols that synchronise with the renegotiation, such as
+// HTTPS.
+type RenegotiationSupport int
+
+const (
+	// RenegotiateNever disables renegotiation.
+	RenegotiateNever RenegotiationSupport = iota
+
+	// RenegotiateOnceAsClient allows a remote server to request
+	// renegotiation once per connection.
+	RenegotiateOnceAsClient
+
+	// RenegotiateFreelyAsClient allows a remote server to repeatedly
+	// request renegotiation.
+	RenegotiateFreelyAsClient
+)
+
 // A Config structure is used to configure a TLS client or server.
 // After one has been passed to a TLS function it must not be
 // modified. A Config may be reused; the tls package will also not
@@ -349,6 +377,16 @@ type Config struct {
 	// be used.
 	CurvePreferences []CurveID
 
+	// DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
+	// When true, the largest possible TLS record size is always used. When
+	// false, the size of TLS records may be adjusted in an attempt to
+	// improve latency.
+	DynamicRecordSizingDisabled bool
+
+	// Renegotiation controls what types of renegotiation are supported.
+	// The default, none, is correct for the vast majority of applications.
+	Renegotiation RenegotiationSupport
+
 	serverInitOnce sync.Once // guards calling (*Config).serverInit
 
 	// mutex protects sessionTicketKeys
@@ -384,6 +422,33 @@ func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
 	return key
 }
 
+// clone returns a copy of c. Only the exported fields are copied.
+func (c *Config) clone() *Config {
+	return &Config{
+		Rand:                        c.Rand,
+		Time:                        c.Time,
+		Certificates:                c.Certificates,
+		NameToCertificate:           c.NameToCertificate,
+		GetCertificate:              c.GetCertificate,
+		RootCAs:                     c.RootCAs,
+		NextProtos:                  c.NextProtos,
+		ServerName:                  c.ServerName,
+		ClientAuth:                  c.ClientAuth,
+		ClientCAs:                   c.ClientCAs,
+		InsecureSkipVerify:          c.InsecureSkipVerify,
+		CipherSuites:                c.CipherSuites,
+		PreferServerCipherSuites:    c.PreferServerCipherSuites,
+		SessionTicketsDisabled:      c.SessionTicketsDisabled,
+		SessionTicketKey:            c.SessionTicketKey,
+		ClientSessionCache:          c.ClientSessionCache,
+		MinVersion:                  c.MinVersion,
+		MaxVersion:                  c.MaxVersion,
+		CurvePreferences:            c.CurvePreferences,
+		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
+		Renegotiation:               c.Renegotiation,
+	}
+}
+
 func (c *Config) serverInit() {
 	if c.SessionTicketsDisabled {
 		return
@@ -510,7 +575,7 @@ func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, err
 	}
 
 	if len(c.Certificates) == 0 {
-		return nil, errors.New("crypto/tls: no certificates configured")
+		return nil, errors.New("tls: no certificates configured")
 	}
 
 	if len(c.Certificates) == 1 || c.NameToCertificate == nil {
@@ -584,13 +649,6 @@ type Certificate struct {
 	Leaf *x509.Certificate
 }
 
-// A TLS record.
-type record struct {
-	contentType  recordType
-	major, minor uint8
-	payload      []byte
-}
-
 type handshakeMessage interface {
 	marshal() []byte
 	unmarshal([]byte) bool
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index 0377568..87bef23 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -28,34 +28,60 @@ type Conn struct {
 	isClient bool
 
 	// constant after handshake; protected by handshakeMutex
-	handshakeMutex    sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
-	handshakeErr      error      // error resulting from handshake
-	vers              uint16     // TLS version
-	haveVers          bool       // version has been negotiated
-	config            *Config    // configuration passed to constructor
+	handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
+	handshakeErr   error      // error resulting from handshake
+	vers           uint16     // TLS version
+	haveVers       bool       // version has been negotiated
+	config         *Config    // configuration passed to constructor
+	// handshakeComplete is true if the connection is currently transfering
+	// application data (i.e. is not currently processing a handshake).
 	handshakeComplete bool
-	didResume         bool // whether this connection was a session resumption
-	cipherSuite       uint16
-	ocspResponse      []byte   // stapled OCSP response
-	scts              [][]byte // signed certificate timestamps from server
-	peerCertificates  []*x509.Certificate
+	// handshakes counts the number of handshakes performed on the
+	// connection so far. If renegotiation is disabled then this is either
+	// zero or one.
+	handshakes       int
+	didResume        bool // whether this connection was a session resumption
+	cipherSuite      uint16
+	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.
 	verifiedChains [][]*x509.Certificate
 	// serverName contains the server name indicated by the client, if any.
 	serverName string
-	// firstFinished contains the first Finished hash sent during the
-	// handshake. This is the "tls-unique" channel binding value.
-	firstFinished [12]byte
+	// secureRenegotiation is true if the server echoed the secure
+	// renegotiation extension. (This is meaningless as a server because
+	// renegotiation is not supported in that case.)
+	secureRenegotiation bool
+
+	// clientFinishedIsFirst is true if the client sent the first Finished
+	// message during the most recent handshake. This is recorded because
+	// the first transmitted Finished message is the tls-unique
+	// channel-binding value.
+	clientFinishedIsFirst bool
+	// clientFinished and serverFinished contain the Finished message sent
+	// by the client or server in the most recent handshake. This is
+	// retained to support the renegotiation extension and tls-unique
+	// channel-binding.
+	clientFinished [12]byte
+	serverFinished [12]byte
 
 	clientProtocol         string
 	clientProtocolFallback bool
 
 	// input/output
-	in, out  halfConn     // in.Mutex < out.Mutex
-	rawInput *block       // raw input, right off the wire
-	input    *block       // application data waiting to be read
-	hand     bytes.Buffer // handshake data waiting to be read
+	in, out   halfConn     // in.Mutex < out.Mutex
+	rawInput  *block       // raw input, right off the wire
+	input     *block       // application data waiting to be read
+	hand      bytes.Buffer // handshake data waiting to be read
+	buffering bool         // whether records are buffered in sendBuf
+	sendBuf   []byte       // a buffer of records waiting to be sent
+
+	// bytesSent counts the bytes of application data sent.
+	// packetsSent counts packets.
+	bytesSent   int64
+	packetsSent int64
 
 	// activeCall is an atomic int32; the low bit is whether Close has
 	// been called. the rest of the bits are the number of goroutines
@@ -124,13 +150,6 @@ func (hc *halfConn) setErrorLocked(err error) error {
 	return err
 }
 
-func (hc *halfConn) error() error {
-	hc.Lock()
-	err := hc.err
-	hc.Unlock()
-	return err
-}
-
 // prepareCipherSpec sets the encryption and MAC states
 // that a subsequent changeCipherSpec will use.
 func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
@@ -170,13 +189,6 @@ func (hc *halfConn) incSeq() {
 	panic("TLS: sequence number wraparound")
 }
 
-// resetSeq resets the sequence number to zero.
-func (hc *halfConn) resetSeq() {
-	for i := range hc.seq {
-		hc.seq[i] = 0
-	}
-}
-
 // removePadding returns an unpadded slice, in constant time, which is a prefix
 // of the input. It also returns a byte which is equal to 255 if the padding
 // was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
@@ -535,7 +547,7 @@ func (c *Conn) newRecordHeaderError(msg string) (err RecordHeaderError) {
 func (c *Conn) readRecord(want recordType) error {
 	// Caller must be in sync with connection:
 	// handshake data if handshake not yet completed,
-	// else application data.  (We don't support renegotiation.)
+	// else application data.
 	switch want {
 	default:
 		c.sendAlert(alertInternalError)
@@ -543,12 +555,12 @@ func (c *Conn) readRecord(want recordType) error {
 	case recordTypeHandshake, recordTypeChangeCipherSpec:
 		if c.handshakeComplete {
 			c.sendAlert(alertInternalError)
-			return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested after handshake complete"))
+			return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested while not in handshake"))
 		}
 	case recordTypeApplicationData:
 		if !c.handshakeComplete {
 			c.sendAlert(alertInternalError)
-			return c.in.setErrorLocked(errors.New("tls: application data record requested before handshake complete"))
+			return c.in.setErrorLocked(errors.New("tls: application data record requested while in handshake"))
 		}
 	}
 
@@ -672,7 +684,7 @@ Again:
 
 	case recordTypeHandshake:
 		// TODO(rsc): Should at least pick off connection close.
-		if typ != want {
+		if typ != want && !(c.isClient && c.config.Renegotiation != RenegotiateNever) {
 			return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation))
 		}
 		c.hand.Write(data)
@@ -694,12 +706,14 @@ func (c *Conn) sendAlertLocked(err alert) error {
 		c.tmp[0] = alertLevelError
 	}
 	c.tmp[1] = byte(err)
-	c.writeRecord(recordTypeAlert, c.tmp[0:2])
-	// closeNotify is a special case in that it isn't an error:
-	if err != alertCloseNotify {
-		return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+
+	_, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2])
+	if err == alertCloseNotify {
+		// closeNotify is a special case in that it isn't an error.
+		return writeErr
 	}
-	return nil
+
+	return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
 }
 
 // sendAlert sends a TLS alert message.
@@ -710,16 +724,120 @@ func (c *Conn) sendAlert(err alert) error {
 	return c.sendAlertLocked(err)
 }
 
-// writeRecord writes a TLS record with the given type and payload
-// to the connection and updates the record layer state.
+const (
+	// tcpMSSEstimate is a conservative estimate of the TCP maximum segment
+	// size (MSS). A constant is used, rather than querying the kernel for
+	// the actual MSS, to avoid complexity. The value here is the IPv6
+	// minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40
+	// bytes) and a TCP header with timestamps (32 bytes).
+	tcpMSSEstimate = 1208
+
+	// recordSizeBoostThreshold is the number of bytes of application data
+	// sent after which the TLS record size will be increased to the
+	// maximum.
+	recordSizeBoostThreshold = 128 * 1024
+)
+
+// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the
+// next application data record. There is the following trade-off:
+//
+//   - For latency-sensitive applications, such as web browsing, each TLS
+//     record should fit in one TCP segment.
+//   - For throughput-sensitive applications, such as large file transfers,
+//     larger TLS records better amortize framing and encryption overheads.
+//
+// A simple heuristic that works well in practice is to use small records for
+// the first 1MB of data, then use larger records for subsequent data, and
+// reset back to smaller records after the connection becomes idle. See "High
+// Performance Web Networking", Chapter 4, or:
+// https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/
+//
+// In the interests of simplicity and determinism, this code does not attempt
+// to reset the record size once the connection is idle, however.
+//
+// c.out.Mutex <= L.
+func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int {
+	if c.config.DynamicRecordSizingDisabled || typ != recordTypeApplicationData {
+		return maxPlaintext
+	}
+
+	if c.bytesSent >= recordSizeBoostThreshold {
+		return maxPlaintext
+	}
+
+	// Subtract TLS overheads to get the maximum payload size.
+	macSize := 0
+	if c.out.mac != nil {
+		macSize = c.out.mac.Size()
+	}
+
+	payloadBytes := tcpMSSEstimate - recordHeaderLen - explicitIVLen
+	if c.out.cipher != nil {
+		switch ciph := c.out.cipher.(type) {
+		case cipher.Stream:
+			payloadBytes -= macSize
+		case cipher.AEAD:
+			payloadBytes -= ciph.Overhead()
+		case cbcMode:
+			blockSize := ciph.BlockSize()
+			// The payload must fit in a multiple of blockSize, with
+			// room for at least one padding byte.
+			payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1
+			// The MAC is appended before padding so affects the
+			// payload size directly.
+			payloadBytes -= macSize
+		default:
+			panic("unknown cipher type")
+		}
+	}
+
+	// Allow packet growth in arithmetic progression up to max.
+	pkt := c.packetsSent
+	c.packetsSent++
+	if pkt > 1000 {
+		return maxPlaintext // avoid overflow in multiply below
+	}
+
+	n := payloadBytes * int(pkt+1)
+	if n > maxPlaintext {
+		n = maxPlaintext
+	}
+	return n
+}
+
 // c.out.Mutex <= L.
-func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
+func (c *Conn) write(data []byte) (int, error) {
+	if c.buffering {
+		c.sendBuf = append(c.sendBuf, data...)
+		return len(data), nil
+	}
+
+	n, err := c.conn.Write(data)
+	c.bytesSent += int64(n)
+	return n, err
+}
+
+func (c *Conn) flush() (int, error) {
+	if len(c.sendBuf) == 0 {
+		return 0, nil
+	}
+
+	n, err := c.conn.Write(c.sendBuf)
+	c.bytesSent += int64(n)
+	c.sendBuf = nil
+	c.buffering = false
+	return n, err
+}
+
+// writeRecordLocked writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+// c.out.Mutex <= L.
+func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
 	b := c.out.newBlock()
+	defer c.out.freeBlock(b)
+
+	var n int
 	for len(data) > 0 {
-		m := len(data)
-		if m > maxPlaintext {
-			m = maxPlaintext
-		}
 		explicitIVLen := 0
 		explicitIVIsSeq := false
 
@@ -742,6 +860,10 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
 				explicitIVIsSeq = true
 			}
 		}
+		m := len(data)
+		if maxPayload := c.maxPayloadSizeForWrite(typ, explicitIVLen); m > maxPayload {
+			m = maxPayload
+		}
 		b.resize(recordHeaderLen + explicitIVLen + m)
 		b.data[0] = byte(typ)
 		vers := c.vers
@@ -759,34 +881,37 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
 			if explicitIVIsSeq {
 				copy(explicitIV, c.out.seq[:])
 			} else {
-				if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
-					break
+				if _, err := io.ReadFull(c.config.rand(), explicitIV); err != nil {
+					return n, err
 				}
 			}
 		}
 		copy(b.data[recordHeaderLen+explicitIVLen:], data)
 		c.out.encrypt(b, explicitIVLen)
-		_, err = c.conn.Write(b.data)
-		if err != nil {
-			break
+		if _, err := c.write(b.data); err != nil {
+			return n, err
 		}
 		n += m
 		data = data[m:]
 	}
-	c.out.freeBlock(b)
 
 	if typ == recordTypeChangeCipherSpec {
-		err = c.out.changeCipherSpec()
-		if err != nil {
-			// Cannot call sendAlert directly,
-			// because we already hold c.out.Mutex.
-			c.tmp[0] = alertLevelError
-			c.tmp[1] = byte(err.(alert))
-			c.writeRecord(recordTypeAlert, c.tmp[0:2])
-			return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+		if err := c.out.changeCipherSpec(); err != nil {
+			return n, c.sendAlertLocked(err.(alert))
 		}
 	}
-	return
+
+	return n, nil
+}
+
+// writeRecord writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+// L < c.out.Mutex.
+func (c *Conn) writeRecord(typ recordType, data []byte) (int, error) {
+	c.out.Lock()
+	defer c.out.Unlock()
+
+	return c.writeRecordLocked(typ, data)
 }
 
 // readHandshake reads the next handshake message from
@@ -805,7 +930,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
 	data := c.hand.Bytes()
 	n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
 	if n > maxHandshake {
-		return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
+		c.sendAlertLocked(alertInternalError)
+		return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake))
 	}
 	for c.hand.Len() < 4+n {
 		if err := c.in.err; err != nil {
@@ -818,6 +944,8 @@ func (c *Conn) readHandshake() (interface{}, error) {
 	data = c.hand.Next(4 + n)
 	var m handshakeMessage
 	switch data[0] {
+	case typeHelloRequest:
+		m = new(helloRequestMsg)
 	case typeClientHello:
 		m = new(clientHelloMsg)
 	case typeServerHello:
@@ -861,7 +989,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
 	return m, nil
 }
 
-var errClosed = errors.New("crypto/tls: use of closed connection")
+var errClosed = errors.New("tls: use of closed connection")
 
 // Write writes data to the connection.
 func (c *Conn) Write(b []byte) (int, error) {
@@ -904,7 +1032,7 @@ func (c *Conn) Write(b []byte) (int, error) {
 	var m int
 	if len(b) > 1 && c.vers <= VersionTLS10 {
 		if _, ok := c.out.cipher.(cipher.BlockMode); ok {
-			n, err := c.writeRecord(recordTypeApplicationData, b[:1])
+			n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1])
 			if err != nil {
 				return n, c.out.setErrorLocked(err)
 			}
@@ -912,10 +1040,52 @@ func (c *Conn) Write(b []byte) (int, error) {
 		}
 	}
 
-	n, err := c.writeRecord(recordTypeApplicationData, b)
+	n, err := c.writeRecordLocked(recordTypeApplicationData, b)
 	return n + m, c.out.setErrorLocked(err)
 }
 
+// handleRenegotiation processes a HelloRequest handshake message.
+// c.in.Mutex <= L
+func (c *Conn) handleRenegotiation() error {
+	msg, err := c.readHandshake()
+	if err != nil {
+		return err
+	}
+
+	_, ok := msg.(*helloRequestMsg)
+	if !ok {
+		c.sendAlert(alertUnexpectedMessage)
+		return alertUnexpectedMessage
+	}
+
+	if !c.isClient {
+		return c.sendAlert(alertNoRenegotiation)
+	}
+
+	switch c.config.Renegotiation {
+	case RenegotiateNever:
+		return c.sendAlert(alertNoRenegotiation)
+	case RenegotiateOnceAsClient:
+		if c.handshakes > 1 {
+			return c.sendAlert(alertNoRenegotiation)
+		}
+	case RenegotiateFreelyAsClient:
+		// Ok.
+	default:
+		c.sendAlert(alertInternalError)
+		return errors.New("tls: unknown Renegotiation value")
+	}
+
+	c.handshakeMutex.Lock()
+	defer c.handshakeMutex.Unlock()
+
+	c.handshakeComplete = false
+	if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil {
+		c.handshakes++
+	}
+	return c.handshakeErr
+}
+
 // Read can be made to time out and return a net.Error with Timeout() == true
 // after a fixed time limit; see SetDeadline and SetReadDeadline.
 func (c *Conn) Read(b []byte) (n int, err error) {
@@ -940,6 +1110,13 @@ func (c *Conn) Read(b []byte) (n int, err error) {
 				// Soft error, like EAGAIN
 				return 0, err
 			}
+			if c.hand.Len() > 0 {
+				// We received handshake bytes, indicating the
+				// start of a renegotiation.
+				if err := c.handleRenegotiation(); err != nil {
+					return 0, err
+				}
+			}
 		}
 		if err := c.in.err; err != nil {
 			return 0, err
@@ -1020,13 +1197,35 @@ func (c *Conn) Close() error {
 // Most uses of this package need not call Handshake
 // explicitly: the first Read or Write will call it automatically.
 func (c *Conn) Handshake() error {
+	// c.handshakeErr and c.handshakeComplete are protected by
+	// c.handshakeMutex. In order to perform a handshake, we need to lock
+	// c.in also and c.handshakeMutex must be locked after c.in.
+	//
+	// However, if a Read() operation is hanging then it'll be holding the
+	// lock on c.in and so taking it here would cause all operations that
+	// need to check whether a handshake is pending (such as Write) to
+	// block.
+	//
+	// Thus we take c.handshakeMutex first and, if we find that a handshake
+	// is needed, then we unlock, acquire c.in and c.handshakeMutex in the
+	// correct order, and check again.
 	c.handshakeMutex.Lock()
 	defer c.handshakeMutex.Unlock()
-	if err := c.handshakeErr; err != nil {
-		return err
-	}
-	if c.handshakeComplete {
-		return nil
+
+	for i := 0; i < 2; i++ {
+		if i == 1 {
+			c.handshakeMutex.Unlock()
+			c.in.Lock()
+			defer c.in.Unlock()
+			c.handshakeMutex.Lock()
+		}
+
+		if err := c.handshakeErr; err != nil {
+			return err
+		}
+		if c.handshakeComplete {
+			return nil
+		}
 	}
 
 	if c.isClient {
@@ -1034,6 +1233,9 @@ func (c *Conn) Handshake() error {
 	} else {
 		c.handshakeErr = c.serverHandshake()
 	}
+	if c.handshakeErr == nil {
+		c.handshakes++
+	}
 	return c.handshakeErr
 }
 
@@ -1056,7 +1258,11 @@ func (c *Conn) ConnectionState() ConnectionState {
 		state.SignedCertificateTimestamps = c.scts
 		state.OCSPResponse = c.ocspResponse
 		if !c.didResume {
-			state.TLSUnique = c.firstFinished[:]
+			if c.clientFinishedIsFirst {
+				state.TLSUnique = c.clientFinished[:]
+			} else {
+				state.TLSUnique = c.serverFinished[:]
+			}
 		}
 	}
 
@@ -1073,7 +1279,7 @@ func (c *Conn) OCSPResponse() []byte {
 }
 
 // VerifyHostname checks that the peer certificate chain is valid for
-// connecting to host.  If so, it returns nil; if not, it returns an error
+// connecting to host. If so, it returns nil; if not, it returns an error
 // describing the problem.
 func (c *Conn) VerifyHostname(host string) error {
 	c.handshakeMutex.Lock()
diff --git a/src/crypto/tls/conn_test.go b/src/crypto/tls/conn_test.go
index ec802ca..5cff7e7 100644
--- a/src/crypto/tls/conn_test.go
+++ b/src/crypto/tls/conn_test.go
@@ -5,6 +5,9 @@
 package tls
 
 import (
+	"bytes"
+	"io"
+	"net"
 	"testing"
 )
 
@@ -116,3 +119,125 @@ func TestCertificateSelection(t *testing.T) {
 		t.Errorf("foo.bar.baz.example.com returned certificate %d, not 0", n)
 	}
 }
+
+// Run with multiple crypto configs to test the logic for computing TLS record overheads.
+func runDynamicRecordSizingTest(t *testing.T, config *Config) {
+	clientConn, serverConn := net.Pipe()
+
+	serverConfig := config.clone()
+	serverConfig.DynamicRecordSizingDisabled = false
+	tlsConn := Server(serverConn, serverConfig)
+
+	recordSizesChan := make(chan []int, 1)
+	go func() {
+		// This goroutine performs a TLS handshake over clientConn and
+		// then reads TLS records until EOF. It writes a slice that
+		// contains all the record sizes to recordSizesChan.
+		defer close(recordSizesChan)
+		defer clientConn.Close()
+
+		tlsConn := Client(clientConn, config)
+		if err := tlsConn.Handshake(); err != nil {
+			t.Errorf("Error from client handshake: %s", err)
+			return
+		}
+
+		var recordHeader [recordHeaderLen]byte
+		var record []byte
+		var recordSizes []int
+
+		for {
+			n, err := clientConn.Read(recordHeader[:])
+			if err == io.EOF {
+				break
+			}
+			if err != nil || n != len(recordHeader) {
+				t.Errorf("Error from client read: %s", err)
+				return
+			}
+
+			length := int(recordHeader[3])<<8 | int(recordHeader[4])
+			if len(record) < length {
+				record = make([]byte, length)
+			}
+
+			n, err = clientConn.Read(record[:length])
+			if err != nil || n != length {
+				t.Errorf("Error from client read: %s", err)
+				return
+			}
+
+			// The last record will be a close_notify alert, which
+			// we don't wish to record.
+			if recordType(recordHeader[0]) == recordTypeApplicationData {
+				recordSizes = append(recordSizes, recordHeaderLen+length)
+			}
+		}
+
+		recordSizesChan <- recordSizes
+	}()
+
+	if err := tlsConn.Handshake(); err != nil {
+		t.Fatalf("Error from server handshake: %s", err)
+	}
+
+	// The server writes these plaintexts in order.
+	plaintext := bytes.Join([][]byte{
+		bytes.Repeat([]byte("x"), recordSizeBoostThreshold),
+		bytes.Repeat([]byte("y"), maxPlaintext*2),
+		bytes.Repeat([]byte("z"), maxPlaintext),
+	}, nil)
+
+	if _, err := tlsConn.Write(plaintext); err != nil {
+		t.Fatalf("Error from server write: %s", err)
+	}
+	if err := tlsConn.Close(); err != nil {
+		t.Fatalf("Error from server close: %s", err)
+	}
+
+	recordSizes := <-recordSizesChan
+	if recordSizes == nil {
+		t.Fatalf("Client encountered an error")
+	}
+
+	// Drop the size of last record, which is likely to be truncated.
+	recordSizes = recordSizes[:len(recordSizes)-1]
+
+	// recordSizes should contain a series of records smaller than
+	// tcpMSSEstimate followed by some larger than maxPlaintext.
+	seenLargeRecord := false
+	for i, size := range recordSizes {
+		if !seenLargeRecord {
+			if size > (i+1)*tcpMSSEstimate {
+				t.Fatalf("Record #%d has size %d, which is too large too soon", i, size)
+			}
+			if size >= maxPlaintext {
+				seenLargeRecord = true
+			}
+		} else if size <= maxPlaintext {
+			t.Fatalf("Record #%d has size %d but should be full sized", i, size)
+		}
+	}
+
+	if !seenLargeRecord {
+		t.Fatalf("No large records observed")
+	}
+}
+
+func TestDynamicRecordSizingWithStreamCipher(t *testing.T) {
+	config := testConfig.clone()
+	config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
+	runDynamicRecordSizingTest(t, config)
+}
+
+func TestDynamicRecordSizingWithCBC(t *testing.T) {
+	config := testConfig.clone()
+	config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA}
+	runDynamicRecordSizingTest(t, config)
+}
+
+func TestDynamicRecordSizingWithAEAD(t *testing.T) {
+	config := testConfig.clone()
+	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
+	runDynamicRecordSizingTest(t, config)
+}
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 3c996ac..f789e6f 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -16,6 +16,7 @@ import (
 	"io"
 	"net"
 	"strconv"
+	"strings"
 )
 
 type clientHandshakeState struct {
@@ -28,11 +29,16 @@ type clientHandshakeState struct {
 	session      *ClientSessionState
 }
 
+// c.out.Mutex <= L; c.handshakeMutex <= L.
 func (c *Conn) clientHandshake() error {
 	if c.config == nil {
 		c.config = defaultConfig()
 	}
 
+	// This may be a renegotiation handshake, in which case some fields
+	// need to be reset.
+	c.didResume = false
+
 	if len(c.config.ServerName) == 0 && !c.config.InsecureSkipVerify {
 		return errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
 	}
@@ -49,25 +55,22 @@ func (c *Conn) clientHandshake() error {
 		return errors.New("tls: NextProtos values too large")
 	}
 
-	sni := c.config.ServerName
-	// IP address literals are not permitted as SNI values. See
-	// https://tools.ietf.org/html/rfc6066#section-3.
-	if net.ParseIP(sni) != nil {
-		sni = ""
+	hello := &clientHelloMsg{
+		vers:                         c.config.maxVersion(),
+		compressionMethods:           []uint8{compressionNone},
+		random:                       make([]byte, 32),
+		ocspStapling:                 true,
+		scts:                         true,
+		serverName:                   hostnameInSNI(c.config.ServerName),
+		supportedCurves:              c.config.curvePreferences(),
+		supportedPoints:              []uint8{pointFormatUncompressed},
+		nextProtoNeg:                 len(c.config.NextProtos) > 0,
+		secureRenegotiationSupported: true,
+		alpnProtocols:                c.config.NextProtos,
 	}
 
-	hello := &clientHelloMsg{
-		vers:                c.config.maxVersion(),
-		compressionMethods:  []uint8{compressionNone},
-		random:              make([]byte, 32),
-		ocspStapling:        true,
-		scts:                true,
-		serverName:          sni,
-		supportedCurves:     c.config.curvePreferences(),
-		supportedPoints:     []uint8{pointFormatUncompressed},
-		nextProtoNeg:        len(c.config.NextProtos) > 0,
-		secureRenegotiation: true,
-		alpnProtocols:       c.config.NextProtos,
+	if c.handshakes > 0 {
+		hello.secureRenegotiation = c.clientFinished[:]
 	}
 
 	possibleCipherSuites := c.config.cipherSuites()
@@ -108,7 +111,12 @@ NextCipherSuite:
 
 	if sessionCache != nil {
 		hello.ticketSupported = true
+	}
 
+	// Session resumption is not allowed if renegotiating because
+	// renegotiation is primarily used to allow a client to send a client
+	// certificate, which would be skipped if session resumption occured.
+	if sessionCache != nil && c.handshakes == 0 {
 		// Try to resume a previously negotiated TLS session, if
 		// available.
 		cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
@@ -144,7 +152,9 @@ NextCipherSuite:
 		}
 	}
 
-	c.writeRecord(recordTypeHandshake, hello.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hello.marshal()); err != nil {
+		return err
+	}
 
 	msg, err := c.readHandshake()
 	if err != nil {
@@ -196,6 +206,7 @@ NextCipherSuite:
 	hs.finishedHash.Write(hs.hello.marshal())
 	hs.finishedHash.Write(hs.serverHello.marshal())
 
+	c.buffering = true
 	if isResume {
 		if err := hs.establishKeys(); err != nil {
 			return err
@@ -203,10 +214,14 @@ NextCipherSuite:
 		if err := hs.readSessionTicket(); err != nil {
 			return err
 		}
-		if err := hs.readFinished(c.firstFinished[:]); err != nil {
+		if err := hs.readFinished(c.serverFinished[:]); err != nil {
+			return err
+		}
+		c.clientFinishedIsFirst = false
+		if err := hs.sendFinished(c.clientFinished[:]); err != nil {
 			return err
 		}
-		if err := hs.sendFinished(nil); err != nil {
+		if _, err := c.flush(); err != nil {
 			return err
 		}
 	} else {
@@ -216,13 +231,17 @@ NextCipherSuite:
 		if err := hs.establishKeys(); err != nil {
 			return err
 		}
-		if err := hs.sendFinished(c.firstFinished[:]); err != nil {
+		if err := hs.sendFinished(c.clientFinished[:]); err != nil {
 			return err
 		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+		c.clientFinishedIsFirst = true
 		if err := hs.readSessionTicket(); err != nil {
 			return err
 		}
-		if err := hs.readFinished(nil); err != nil {
+		if err := hs.readFinished(c.serverFinished[:]); err != nil {
 			return err
 		}
 	}
@@ -251,47 +270,62 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 	}
 	hs.finishedHash.Write(certMsg.marshal())
 
-	certs := make([]*x509.Certificate, len(certMsg.certificates))
-	for i, asn1Data := range certMsg.certificates {
-		cert, err := x509.ParseCertificate(asn1Data)
-		if err != nil {
-			c.sendAlert(alertBadCertificate)
-			return errors.New("tls: failed to parse certificate from server: " + err.Error())
+	if c.handshakes == 0 {
+		// If this is the first handshake on a connection, process and
+		// (optionally) verify the server's certificates.
+		certs := make([]*x509.Certificate, len(certMsg.certificates))
+		for i, asn1Data := range certMsg.certificates {
+			cert, err := x509.ParseCertificate(asn1Data)
+			if err != nil {
+				c.sendAlert(alertBadCertificate)
+				return errors.New("tls: failed to parse certificate from server: " + err.Error())
+			}
+			certs[i] = cert
 		}
-		certs[i] = cert
-	}
 
-	if !c.config.InsecureSkipVerify {
-		opts := x509.VerifyOptions{
-			Roots:         c.config.RootCAs,
-			CurrentTime:   c.config.time(),
-			DNSName:       c.config.ServerName,
-			Intermediates: x509.NewCertPool(),
-		}
+		if !c.config.InsecureSkipVerify {
+			opts := x509.VerifyOptions{
+				Roots:         c.config.RootCAs,
+				CurrentTime:   c.config.time(),
+				DNSName:       c.config.ServerName,
+				Intermediates: x509.NewCertPool(),
+			}
 
-		for i, cert := range certs {
-			if i == 0 {
-				continue
+			for i, cert := range certs {
+				if i == 0 {
+					continue
+				}
+				opts.Intermediates.AddCert(cert)
+			}
+			c.verifiedChains, err = certs[0].Verify(opts)
+			if err != nil {
+				c.sendAlert(alertBadCertificate)
+				return err
 			}
-			opts.Intermediates.AddCert(cert)
 		}
-		c.verifiedChains, err = certs[0].Verify(opts)
-		if err != nil {
-			c.sendAlert(alertBadCertificate)
-			return err
+
+		switch certs[0].PublicKey.(type) {
+		case *rsa.PublicKey, *ecdsa.PublicKey:
+			break
+		default:
+			c.sendAlert(alertUnsupportedCertificate)
+			return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
 		}
-	}
 
-	switch certs[0].PublicKey.(type) {
-	case *rsa.PublicKey, *ecdsa.PublicKey:
-		break
-	default:
-		c.sendAlert(alertUnsupportedCertificate)
-		return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
+		c.peerCertificates = certs
+	} else {
+		// This is a renegotiation handshake. We require that the
+		// server's identity (i.e. leaf certificate) is unchanged and
+		// thus any previous trust decision is still valid.
+		//
+		// See https://mitls.org/pages/attacks/3SHAKE for the
+		// motivation behind this requirement.
+		if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
+			c.sendAlert(alertBadCertificate)
+			return errors.New("tls: server's identity changed during renegotiation")
+		}
 	}
 
-	c.peerCertificates = certs
-
 	if hs.serverHello.ocspStapling {
 		msg, err = c.readHandshake()
 		if err != nil {
@@ -319,7 +353,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 	skx, ok := msg.(*serverKeyExchangeMsg)
 	if ok {
 		hs.finishedHash.Write(skx.marshal())
-		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx)
+		err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
 		if err != nil {
 			c.sendAlert(alertUnexpectedMessage)
 			return err
@@ -425,17 +459,21 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 			certMsg.certificates = chainToSend.Certificate
 		}
 		hs.finishedHash.Write(certMsg.marshal())
-		c.writeRecord(recordTypeHandshake, certMsg.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+			return err
+		}
 	}
 
-	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0])
+	preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0])
 	if err != nil {
 		c.sendAlert(alertInternalError)
 		return err
 	}
 	if ckx != nil {
 		hs.finishedHash.Write(ckx.marshal())
-		c.writeRecord(recordTypeHandshake, ckx.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, ckx.marshal()); err != nil {
+			return err
+		}
 	}
 
 	if chainToSend != nil {
@@ -477,7 +515,9 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 		}
 
 		hs.finishedHash.Write(certVerify.marshal())
-		c.writeRecord(recordTypeHandshake, certVerify.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certVerify.marshal()); err != nil {
+			return err
+		}
 	}
 
 	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
@@ -524,6 +564,24 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
 		return false, errors.New("tls: server selected unsupported compression format")
 	}
 
+	if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported {
+		c.secureRenegotiation = true
+		if len(hs.serverHello.secureRenegotiation) != 0 {
+			c.sendAlert(alertHandshakeFailure)
+			return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+		}
+	}
+
+	if c.handshakes > 0 && c.secureRenegotiation {
+		var expectedSecureRenegotiation [24]byte
+		copy(expectedSecureRenegotiation[:], c.clientFinished[:])
+		copy(expectedSecureRenegotiation[12:], c.serverFinished[:])
+		if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) {
+			c.sendAlert(alertHandshakeFailure)
+			return false, errors.New("tls: incorrect renegotiation extension contents")
+		}
+	}
+
 	clientDidNPN := hs.hello.nextProtoNeg
 	clientDidALPN := len(hs.hello.alpnProtocols) > 0
 	serverHasNPN := hs.serverHello.nextProtoNeg
@@ -531,17 +589,17 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
 
 	if !clientDidNPN && serverHasNPN {
 		c.sendAlert(alertHandshakeFailure)
-		return false, errors.New("server advertised unrequested NPN extension")
+		return false, errors.New("tls: server advertised unrequested NPN extension")
 	}
 
 	if !clientDidALPN && serverHasALPN {
 		c.sendAlert(alertHandshakeFailure)
-		return false, errors.New("server advertised unrequested ALPN extension")
+		return false, errors.New("tls: server advertised unrequested ALPN extension")
 	}
 
 	if serverHasNPN && serverHasALPN {
 		c.sendAlert(alertHandshakeFailure)
-		return false, errors.New("server advertised both NPN and ALPN extensions")
+		return false, errors.New("tls: server advertised both NPN and ALPN extensions")
 	}
 
 	if serverHasALPN {
@@ -550,22 +608,33 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
 	}
 	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
+	if !hs.serverResumedSession() {
+		return false, nil
+	}
+
+	if hs.session.vers != c.vers {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server resumed a session with a different version")
+	}
+
+	if hs.session.cipherSuite != hs.suite.id {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: server resumed a session with a different cipher suite")
 	}
-	return false, nil
+
+	// 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
 }
 
 func (hs *clientHandshakeState) readFinished(out []byte) error {
 	c := hs.c
 
 	c.readRecord(recordTypeChangeCipherSpec)
-	if err := c.in.error(); err != nil {
-		return err
+	if c.in.err != nil {
+		return c.in.err
 	}
 
 	msg, err := c.readHandshake()
@@ -621,7 +690,9 @@ func (hs *clientHandshakeState) readSessionTicket() error {
 func (hs *clientHandshakeState) sendFinished(out []byte) error {
 	c := hs.c
 
-	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+		return err
+	}
 	if hs.serverHello.nextProtoNeg {
 		nextProto := new(nextProtoMsg)
 		proto, fallback := mutualProtocol(c.config.NextProtos, hs.serverHello.nextProtos)
@@ -630,13 +701,17 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error {
 		c.clientProtocolFallback = fallback
 
 		hs.finishedHash.Write(nextProto.marshal())
-		c.writeRecord(recordTypeHandshake, nextProto.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, nextProto.marshal()); err != nil {
+			return err
+		}
 	}
 
 	finished := new(finishedMsg)
 	finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
 	hs.finishedHash.Write(finished.marshal())
-	c.writeRecord(recordTypeHandshake, finished.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+		return err
+	}
 	copy(out, finished.verifyData)
 	return nil
 }
@@ -665,3 +740,23 @@ func mutualProtocol(protos, preferenceProtos []string) (string, bool) {
 
 	return protos[0], true
 }
+
+// hostnameInSNI converts name into an approriate hostname for SNI.
+// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
+// See https://tools.ietf.org/html/rfc6066#section-3.
+func hostnameInSNI(name string) string {
+	host := name
+	if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+		host = host[1 : len(host)-1]
+	}
+	if i := strings.LastIndex(host, "%"); i > 0 {
+		host = host[:i]
+	}
+	if net.ParseIP(host) != nil {
+		return ""
+	}
+	if len(name) > 0 && name[len(name)-1] == '.' {
+		name = name[:len(name)-1]
+	}
+	return name
+}
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index f78cc46..ce987f1 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -12,6 +12,7 @@ import (
 	"encoding/base64"
 	"encoding/binary"
 	"encoding/pem"
+	"errors"
 	"fmt"
 	"io"
 	"net"
@@ -27,14 +28,80 @@ import (
 // Note: see comment in handshake_test.go for details of how the reference
 // tests work.
 
-// blockingSource is an io.Reader that blocks a Read call until it's closed.
-type blockingSource chan bool
+// opensslInputEvent enumerates possible inputs that can be sent to an `openssl
+// s_client` process.
+type opensslInputEvent int
+
+const (
+	// opensslRenegotiate causes OpenSSL to request a renegotiation of the
+	// connection.
+	opensslRenegotiate opensslInputEvent = iota
+
+	// opensslSendBanner causes OpenSSL to send the contents of
+	// opensslSentinel on the connection.
+	opensslSendSentinel
+)
+
+const opensslSentinel = "SENTINEL\n"
+
+type opensslInput chan opensslInputEvent
+
+func (i opensslInput) Read(buf []byte) (n int, err error) {
+	for event := range i {
+		switch event {
+		case opensslRenegotiate:
+			return copy(buf, []byte("R\n")), nil
+		case opensslSendSentinel:
+			return copy(buf, []byte(opensslSentinel)), nil
+		default:
+			panic("unknown event")
+		}
+	}
 
-func (b blockingSource) Read([]byte) (n int, err error) {
-	<-b
 	return 0, io.EOF
 }
 
+// opensslOutputSink is an io.Writer that receives the stdout and stderr from
+// an `openssl` process and sends a value to handshakeComplete when it sees a
+// log message from a completed server handshake.
+type opensslOutputSink struct {
+	handshakeComplete chan struct{}
+	all               []byte
+	line              []byte
+}
+
+func newOpensslOutputSink() *opensslOutputSink {
+	return &opensslOutputSink{make(chan struct{}), nil, nil}
+}
+
+// opensslEndOfHandshake is a message that the “openssl s_server” tool will
+// print when a handshake completes if run with “-state”.
+const opensslEndOfHandshake = "SSL_accept:SSLv3 write finished A"
+
+func (o *opensslOutputSink) Write(data []byte) (n int, err error) {
+	o.line = append(o.line, data...)
+	o.all = append(o.all, data...)
+
+	for {
+		i := bytes.Index(o.line, []byte{'\n'})
+		if i < 0 {
+			break
+		}
+
+		if bytes.Equal([]byte(opensslEndOfHandshake), o.line[:i]) {
+			o.handshakeComplete <- struct{}{}
+		}
+		o.line = o.line[i+1:]
+	}
+
+	return len(data), nil
+}
+
+func (o *opensslOutputSink) WriteTo(w io.Writer) (int64, error) {
+	n, err := w.Write(o.all)
+	return int64(n), err
+}
+
 // clientTest represents a test of the TLS client handshake against a reference
 // implementation.
 type clientTest struct {
@@ -60,15 +127,25 @@ type clientTest struct {
 	// ConnectionState of the resulting connection. It returns a non-nil
 	// error if the ConnectionState is unacceptable.
 	validate func(ConnectionState) error
+	// numRenegotiations is the number of times that the connection will be
+	// renegotiated.
+	numRenegotiations int
+	// renegotiationExpectedToFail, if not zero, is the number of the
+	// renegotiation attempt that is expected to fail.
+	renegotiationExpectedToFail int
+	// checkRenegotiationError, if not nil, is called with any error
+	// arising from renegotiation. It can map expected errors to nil to
+	// ignore them.
+	checkRenegotiationError func(renegotiationNum int, err error) error
 }
 
 var defaultServerCommand = []string{"openssl", "s_server"}
 
 // connFromCommand starts the reference server process, connects to it and
-// returns a recordingConn for the connection. The stdin return value is a
-// blockingSource for the stdin of the child process. It must be closed before
+// returns a recordingConn for the connection. The stdin return value is an
+// opensslInput for the stdin of the child process. It must be closed before
 // Waiting for child.
-func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin blockingSource, err error) {
+func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin opensslInput, stdout *opensslOutputSink, err error) {
 	cert := testRSACertificate
 	if len(test.cert) > 0 {
 		cert = test.cert
@@ -131,14 +208,28 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
 		command = append(command, "-serverinfo", serverInfoPath)
 	}
 
+	if test.numRenegotiations > 0 {
+		found := false
+		for _, flag := range command[1:] {
+			if flag == "-state" {
+				found = true
+				break
+			}
+		}
+
+		if !found {
+			panic("-state flag missing to OpenSSL. You need this if testing renegotiation")
+		}
+	}
+
 	cmd := exec.Command(command[0], command[1:]...)
-	stdin = blockingSource(make(chan bool))
+	stdin = opensslInput(make(chan opensslInputEvent))
 	cmd.Stdin = stdin
-	var out bytes.Buffer
-	cmd.Stdout = &out
-	cmd.Stderr = &out
+	out := newOpensslOutputSink()
+	cmd.Stdout = out
+	cmd.Stderr = out
 	if err := cmd.Start(); err != nil {
-		return nil, nil, nil, err
+		return nil, nil, nil, nil, err
 	}
 
 	// OpenSSL does print an "ACCEPT" banner, but it does so *before*
@@ -160,14 +251,14 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
 		close(stdin)
 		out.WriteTo(os.Stdout)
 		cmd.Process.Kill()
-		return nil, nil, nil, cmd.Wait()
+		return nil, nil, nil, nil, cmd.Wait()
 	}
 
 	record := &recordingConn{
 		Conn: tcpConn,
 	}
 
-	return record, cmd, stdin, nil
+	return record, cmd, stdin, out, nil
 }
 
 func (test *clientTest) dataPath() string {
@@ -187,11 +278,12 @@ func (test *clientTest) run(t *testing.T, write bool) {
 	var clientConn, serverConn net.Conn
 	var recordingConn *recordingConn
 	var childProcess *exec.Cmd
-	var stdin blockingSource
+	var stdin opensslInput
+	var stdout *opensslOutputSink
 
 	if write {
 		var err error
-		recordingConn, childProcess, stdin, err = test.connFromCommand()
+		recordingConn, childProcess, stdin, stdout, err = test.connFromCommand()
 		if err != nil {
 			t.Fatalf("Failed to start subcommand: %s", err)
 		}
@@ -208,17 +300,77 @@ func (test *clientTest) run(t *testing.T, write bool) {
 
 	doneChan := make(chan bool)
 	go func() {
+		defer func() { doneChan <- true }()
+		defer clientConn.Close()
+		defer client.Close()
+
 		if _, err := client.Write([]byte("hello\n")); err != nil {
 			t.Errorf("Client.Write failed: %s", err)
+			return
 		}
+
+		for i := 1; i <= test.numRenegotiations; i++ {
+			// The initial handshake will generate a
+			// handshakeComplete signal which needs to be quashed.
+			if i == 1 && write {
+				<-stdout.handshakeComplete
+			}
+
+			// OpenSSL will try to interleave application data and
+			// a renegotiation if we send both concurrently.
+			// Therefore: ask OpensSSL to start a renegotiation, run
+			// a goroutine to call client.Read and thus process the
+			// renegotiation request, watch for OpenSSL's stdout to
+			// indicate that the handshake is complete and,
+			// finally, have OpenSSL write something to cause
+			// client.Read to complete.
+			if write {
+				stdin <- opensslRenegotiate
+			}
+
+			signalChan := make(chan struct{})
+
+			go func() {
+				defer func() { signalChan <- struct{}{} }()
+
+				buf := make([]byte, 256)
+				n, err := client.Read(buf)
+
+				if test.checkRenegotiationError != nil {
+					newErr := test.checkRenegotiationError(i, err)
+					if err != nil && newErr == nil {
+						return
+					}
+					err = newErr
+				}
+
+				if err != nil {
+					t.Errorf("Client.Read failed after renegotiation #%d: %s", i, err)
+					return
+				}
+
+				buf = buf[:n]
+				if !bytes.Equal([]byte(opensslSentinel), buf) {
+					t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
+				}
+
+				if expected := i + 1; client.handshakes != expected {
+					t.Errorf("client should have recorded %d handshakes, but believes that %d have occured", expected, client.handshakes)
+				}
+			}()
+
+			if write && test.renegotiationExpectedToFail != i {
+				<-stdout.handshakeComplete
+				stdin <- opensslSendSentinel
+			}
+			<-signalChan
+		}
+
 		if test.validate != nil {
 			if err := test.validate(client.ConnectionState()); err != nil {
 				t.Errorf("validate callback returned error: %s", err)
 			}
 		}
-		client.Close()
-		clientConn.Close()
-		doneChan <- true
 	}()
 
 	if !write {
@@ -357,14 +509,14 @@ func TestHandshakeClientAES256GCMSHA384(t *testing.T) {
 }
 
 func TestHandshakeClientCertRSA(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 	cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
 	config.Certificates = []Certificate{cert}
 
 	test := &clientTest{
 		name:    "ClientCert-RSA-RSA",
 		command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
-		config:  &config,
+		config:  config,
 	}
 
 	runClientTestTLS10(t, test)
@@ -373,7 +525,7 @@ func TestHandshakeClientCertRSA(t *testing.T) {
 	test = &clientTest{
 		name:    "ClientCert-RSA-ECDSA",
 		command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
-		config:  &config,
+		config:  config,
 		cert:    testECDSACertificate,
 		key:     testECDSAPrivateKey,
 	}
@@ -384,7 +536,7 @@ func TestHandshakeClientCertRSA(t *testing.T) {
 	test = &clientTest{
 		name:    "ClientCert-RSA-AES256-GCM-SHA384",
 		command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384", "-verify", "1"},
-		config:  &config,
+		config:  config,
 		cert:    testRSACertificate,
 		key:     testRSAPrivateKey,
 	}
@@ -393,14 +545,14 @@ func TestHandshakeClientCertRSA(t *testing.T) {
 }
 
 func TestHandshakeClientCertECDSA(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 	cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM))
 	config.Certificates = []Certificate{cert}
 
 	test := &clientTest{
 		name:    "ClientCert-ECDSA-RSA",
 		command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
-		config:  &config,
+		config:  config,
 	}
 
 	runClientTestTLS10(t, test)
@@ -409,7 +561,7 @@ func TestHandshakeClientCertECDSA(t *testing.T) {
 	test = &clientTest{
 		name:    "ClientCert-ECDSA-ECDSA",
 		command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
-		config:  &config,
+		config:  config,
 		cert:    testECDSACertificate,
 		key:     testECDSAPrivateKey,
 	}
@@ -448,7 +600,7 @@ func TestClientResumption(t *testing.T) {
 			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)
+			t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifiedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains)
 		}
 	}
 
@@ -539,7 +691,7 @@ func TestLRUClientSessionCache(t *testing.T) {
 }
 
 func TestHandshakeClientALPNMatch(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 	config.NextProtos = []string{"proto2", "proto1"}
 
 	test := &clientTest{
@@ -547,7 +699,7 @@ func TestHandshakeClientALPNMatch(t *testing.T) {
 		// Note that this needs OpenSSL 1.0.2 because that is the first
 		// version that supports the -alpn flag.
 		command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
-		config:  &config,
+		config:  config,
 		validate: func(state ConnectionState) error {
 			// The server's preferences should override the client.
 			if state.NegotiatedProtocol != "proto1" {
@@ -560,7 +712,7 @@ func TestHandshakeClientALPNMatch(t *testing.T) {
 }
 
 func TestHandshakeClientALPNNoMatch(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 	config.NextProtos = []string{"proto3"}
 
 	test := &clientTest{
@@ -568,7 +720,7 @@ func TestHandshakeClientALPNNoMatch(t *testing.T) {
 		// Note that this needs OpenSSL 1.0.2 because that is the first
 		// version that supports the -alpn flag.
 		command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
-		config:  &config,
+		config:  config,
 		validate: func(state ConnectionState) error {
 			// There's no overlap so OpenSSL will not select a protocol.
 			if state.NegotiatedProtocol != "" {
@@ -584,7 +736,7 @@ func TestHandshakeClientALPNNoMatch(t *testing.T) {
 const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBs [...]
 
 func TestHandshakClientSCTs(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 
 	scts, err := base64.StdEncoding.DecodeString(sctsBase64)
 	if err != nil {
@@ -596,7 +748,7 @@ func TestHandshakClientSCTs(t *testing.T) {
 		// 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,
+		config:     config,
 		extensions: [][]byte{scts},
 		validate: func(state ConnectionState) error {
 			expectedSCTs := [][]byte{
@@ -618,14 +770,113 @@ func TestHandshakClientSCTs(t *testing.T) {
 	runClientTestTLS12(t, test)
 }
 
-func TestNoIPAddressesInSNI(t *testing.T) {
-	for _, ipLiteral := range []string{"1.2.3.4", "::1"} {
+func TestRenegotiationRejected(t *testing.T) {
+	config := testConfig.clone()
+	test := &clientTest{
+		name:                        "RenegotiationRejected",
+		command:                     []string{"openssl", "s_server", "-state"},
+		config:                      config,
+		numRenegotiations:           1,
+		renegotiationExpectedToFail: 1,
+		checkRenegotiationError: func(renegotiationNum int, err error) error {
+			if err == nil {
+				return errors.New("expected error from renegotiation but got nil")
+			}
+			if !strings.Contains(err.Error(), "no renegotiation") {
+				return fmt.Errorf("expected renegotiation to be rejected but got %q", err)
+			}
+			return nil
+		},
+	}
+
+	runClientTestTLS12(t, test)
+}
+
+func TestRenegotiateOnce(t *testing.T) {
+	config := testConfig.clone()
+	config.Renegotiation = RenegotiateOnceAsClient
+
+	test := &clientTest{
+		name:              "RenegotiateOnce",
+		command:           []string{"openssl", "s_server", "-state"},
+		config:            config,
+		numRenegotiations: 1,
+	}
+
+	runClientTestTLS12(t, test)
+}
+
+func TestRenegotiateTwice(t *testing.T) {
+	config := testConfig.clone()
+	config.Renegotiation = RenegotiateFreelyAsClient
+
+	test := &clientTest{
+		name:              "RenegotiateTwice",
+		command:           []string{"openssl", "s_server", "-state"},
+		config:            config,
+		numRenegotiations: 2,
+	}
+
+	runClientTestTLS12(t, test)
+}
+
+func TestRenegotiateTwiceRejected(t *testing.T) {
+	config := testConfig.clone()
+	config.Renegotiation = RenegotiateOnceAsClient
+
+	test := &clientTest{
+		name:                        "RenegotiateTwiceRejected",
+		command:                     []string{"openssl", "s_server", "-state"},
+		config:                      config,
+		numRenegotiations:           2,
+		renegotiationExpectedToFail: 2,
+		checkRenegotiationError: func(renegotiationNum int, err error) error {
+			if renegotiationNum == 1 {
+				return err
+			}
+
+			if err == nil {
+				return errors.New("expected error from renegotiation but got nil")
+			}
+			if !strings.Contains(err.Error(), "no renegotiation") {
+				return fmt.Errorf("expected renegotiation to be rejected but got %q", err)
+			}
+			return nil
+		},
+	}
+
+	runClientTestTLS12(t, test)
+}
+
+var hostnameInSNITests = []struct {
+	in, out string
+}{
+	// Opaque string
+	{"", ""},
+	{"localhost", "localhost"},
+	{"foo, bar, baz and qux", "foo, bar, baz and qux"},
+
+	// DNS hostname
+	{"golang.org", "golang.org"},
+	{"golang.org.", "golang.org"},
+
+	// Literal IPv4 address
+	{"1.2.3.4", ""},
+
+	// Literal IPv6 address
+	{"::1", ""},
+	{"::1%lo0", ""}, // with zone identifier
+	{"[::1]", ""},   // as per RFC 5952 we allow the [] style as IPv6 literal
+	{"[::1%lo0]", ""},
+}
+
+func TestHostnameInSNI(t *testing.T) {
+	for _, tt := range hostnameInSNITests {
 		c, s := net.Pipe()
 
-		go func() {
-			client := Client(c, &Config{ServerName: ipLiteral})
-			client.Handshake()
-		}()
+		go func(host string) {
+			Client(c, &Config{ServerName: host, InsecureSkipVerify: true}).Handshake()
+		}(tt.in)
 
 		var header [5]byte
 		if _, err := io.ReadFull(s, header[:]); err != nil {
@@ -637,10 +888,20 @@ func TestNoIPAddressesInSNI(t *testing.T) {
 		if _, err := io.ReadFull(s, record[:]); err != nil {
 			t.Fatal(err)
 		}
+
+		c.Close()
 		s.Close()
 
-		if bytes.Index(record, []byte(ipLiteral)) != -1 {
-			t.Errorf("IP literal %q found in ClientHello: %x", ipLiteral, record)
+		var m clientHelloMsg
+		if !m.unmarshal(record) {
+			t.Errorf("unmarshaling ClientHello for %q failed", tt.in)
+			continue
+		}
+		if tt.in != tt.out && m.serverName == tt.in {
+			t.Errorf("prohibited %q found in ClientHello: %x", tt.in, record)
+		}
+		if m.serverName != tt.out {
+			t.Errorf("expected %q not found in ClientHello: %x", tt.out, record)
 		}
 	}
 }
@@ -694,3 +955,93 @@ func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
 		t.Fatalf("Expected error about unconfigured cipher suite but got %q", err)
 	}
 }
+
+// brokenConn wraps a net.Conn and causes all Writes after a certain number to
+// fail with brokenConnErr.
+type brokenConn struct {
+	net.Conn
+
+	// breakAfter is the number of successful writes that will be allowed
+	// before all subsequent writes fail.
+	breakAfter int
+
+	// numWrites is the number of writes that have been done.
+	numWrites int
+}
+
+// brokenConnErr is the error that brokenConn returns once exhausted.
+var brokenConnErr = errors.New("too many writes to brokenConn")
+
+func (b *brokenConn) Write(data []byte) (int, error) {
+	if b.numWrites >= b.breakAfter {
+		return 0, brokenConnErr
+	}
+
+	b.numWrites++
+	return b.Conn.Write(data)
+}
+
+func TestFailedWrite(t *testing.T) {
+	// Test that a write error during the handshake is returned.
+	for _, breakAfter := range []int{0, 1} {
+		c, s := net.Pipe()
+		done := make(chan bool)
+
+		go func() {
+			Server(s, testConfig).Handshake()
+			s.Close()
+			done <- true
+		}()
+
+		brokenC := &brokenConn{Conn: c, breakAfter: breakAfter}
+		err := Client(brokenC, testConfig).Handshake()
+		if err != brokenConnErr {
+			t.Errorf("#%d: expected error from brokenConn but got %q", breakAfter, err)
+		}
+		brokenC.Close()
+
+		<-done
+	}
+}
+
+// writeCountingConn wraps a net.Conn and counts the number of Write calls.
+type writeCountingConn struct {
+	net.Conn
+
+	// numWrites is the number of writes that have been done.
+	numWrites int
+}
+
+func (wcc *writeCountingConn) Write(data []byte) (int, error) {
+	wcc.numWrites++
+	return wcc.Conn.Write(data)
+}
+
+func TestBuffering(t *testing.T) {
+	c, s := net.Pipe()
+	done := make(chan bool)
+
+	clientWCC := &writeCountingConn{Conn: c}
+	serverWCC := &writeCountingConn{Conn: s}
+
+	go func() {
+		Server(serverWCC, testConfig).Handshake()
+		serverWCC.Close()
+		done <- true
+	}()
+
+	err := Client(clientWCC, testConfig).Handshake()
+	if err != nil {
+		t.Fatal(err)
+	}
+	clientWCC.Close()
+	<-done
+
+	if n := clientWCC.numWrites; n != 2 {
+		t.Errorf("expected client handshake to complete with only two writes, but saw %d", n)
+	}
+
+	if n := serverWCC.numWrites; n != 2 {
+		t.Errorf("expected server handshake to complete with only two writes, but saw %d", n)
+	}
+}
diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go
index 111ce53..ab8e60a 100644
--- a/src/crypto/tls/handshake_messages.go
+++ b/src/crypto/tls/handshake_messages.go
@@ -7,23 +7,24 @@ package tls
 import "bytes"
 
 type clientHelloMsg struct {
-	raw                 []byte
-	vers                uint16
-	random              []byte
-	sessionId           []byte
-	cipherSuites        []uint16
-	compressionMethods  []uint8
-	nextProtoNeg        bool
-	serverName          string
-	ocspStapling        bool
-	scts                bool
-	supportedCurves     []CurveID
-	supportedPoints     []uint8
-	ticketSupported     bool
-	sessionTicket       []uint8
-	signatureAndHashes  []signatureAndHash
-	secureRenegotiation bool
-	alpnProtocols       []string
+	raw                          []byte
+	vers                         uint16
+	random                       []byte
+	sessionId                    []byte
+	cipherSuites                 []uint16
+	compressionMethods           []uint8
+	nextProtoNeg                 bool
+	serverName                   string
+	ocspStapling                 bool
+	scts                         bool
+	supportedCurves              []CurveID
+	supportedPoints              []uint8
+	ticketSupported              bool
+	sessionTicket                []uint8
+	signatureAndHashes           []signatureAndHash
+	secureRenegotiation          []byte
+	secureRenegotiationSupported bool
+	alpnProtocols                []string
 }
 
 func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -47,7 +48,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
 		m.ticketSupported == m1.ticketSupported &&
 		bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
 		eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) &&
-		m.secureRenegotiation == m1.secureRenegotiation &&
+		m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
+		bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
 		eqStrings(m.alpnProtocols, m1.alpnProtocols)
 }
 
@@ -86,8 +88,8 @@ func (m *clientHelloMsg) marshal() []byte {
 		extensionsLength += 2 + 2*len(m.signatureAndHashes)
 		numExtensions++
 	}
-	if m.secureRenegotiation {
-		extensionsLength += 1
+	if m.secureRenegotiationSupported {
+		extensionsLength += 1 + len(m.secureRenegotiation)
 		numExtensions++
 	}
 	if len(m.alpnProtocols) > 0 {
@@ -214,7 +216,7 @@ func (m *clientHelloMsg) marshal() []byte {
 		z[4] = byte(l)
 		z = z[5:]
 		for _, pointFormat := range m.supportedPoints {
-			z[0] = byte(pointFormat)
+			z[0] = pointFormat
 			z = z[1:]
 		}
 	}
@@ -248,12 +250,15 @@ func (m *clientHelloMsg) marshal() []byte {
 			z = z[2:]
 		}
 	}
-	if m.secureRenegotiation {
+	if m.secureRenegotiationSupported {
 		z[0] = byte(extensionRenegotiationInfo >> 8)
 		z[1] = byte(extensionRenegotiationInfo & 0xff)
 		z[2] = 0
-		z[3] = 1
+		z[3] = byte(len(m.secureRenegotiation) + 1)
+		z[4] = byte(len(m.secureRenegotiation))
 		z = z[5:]
+		copy(z, m.secureRenegotiation)
+		z = z[len(m.secureRenegotiation):]
 	}
 	if len(m.alpnProtocols) > 0 {
 		z[0] = byte(extensionALPN >> 8)
@@ -316,7 +321,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 	for i := 0; i < numCipherSuites; i++ {
 		m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i])
 		if m.cipherSuites[i] == scsvRenegotiation {
-			m.secureRenegotiation = true
+			m.secureRenegotiationSupported = true
 		}
 	}
 	data = data[2+cipherSuiteLen:]
@@ -448,10 +453,18 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 				d = d[2:]
 			}
 		case extensionRenegotiationInfo:
-			if length != 1 || data[0] != 0 {
+			if length == 0 {
+				return false
+			}
+			d := data[:length]
+			l := int(d[0])
+			d = d[1:]
+			if l != len(d) {
 				return false
 			}
-			m.secureRenegotiation = true
+
+			m.secureRenegotiation = d
+			m.secureRenegotiationSupported = true
 		case extensionALPN:
 			if length < 2 {
 				return false
@@ -483,19 +496,20 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 }
 
 type serverHelloMsg struct {
-	raw                 []byte
-	vers                uint16
-	random              []byte
-	sessionId           []byte
-	cipherSuite         uint16
-	compressionMethod   uint8
-	nextProtoNeg        bool
-	nextProtos          []string
-	ocspStapling        bool
-	scts                [][]byte
-	ticketSupported     bool
-	secureRenegotiation bool
-	alpnProtocol        string
+	raw                          []byte
+	vers                         uint16
+	random                       []byte
+	sessionId                    []byte
+	cipherSuite                  uint16
+	compressionMethod            uint8
+	nextProtoNeg                 bool
+	nextProtos                   []string
+	ocspStapling                 bool
+	scts                         [][]byte
+	ticketSupported              bool
+	secureRenegotiation          []byte
+	secureRenegotiationSupported bool
+	alpnProtocol                 string
 }
 
 func (m *serverHelloMsg) equal(i interface{}) bool {
@@ -523,7 +537,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
 		eqStrings(m.nextProtos, m1.nextProtos) &&
 		m.ocspStapling == m1.ocspStapling &&
 		m.ticketSupported == m1.ticketSupported &&
-		m.secureRenegotiation == m1.secureRenegotiation &&
+		m.secureRenegotiationSupported == m1.secureRenegotiationSupported &&
+		bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) &&
 		m.alpnProtocol == m1.alpnProtocol
 }
 
@@ -551,8 +566,8 @@ func (m *serverHelloMsg) marshal() []byte {
 	if m.ticketSupported {
 		numExtensions++
 	}
-	if m.secureRenegotiation {
-		extensionsLength += 1
+	if m.secureRenegotiationSupported {
+		extensionsLength += 1 + len(m.secureRenegotiation)
 		numExtensions++
 	}
 	if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
@@ -589,7 +604,7 @@ func (m *serverHelloMsg) marshal() []byte {
 	z := x[39+len(m.sessionId):]
 	z[0] = uint8(m.cipherSuite >> 8)
 	z[1] = uint8(m.cipherSuite)
-	z[2] = uint8(m.compressionMethod)
+	z[2] = m.compressionMethod
 
 	z = z[3:]
 	if numExtensions > 0 {
@@ -624,12 +639,15 @@ func (m *serverHelloMsg) marshal() []byte {
 		z[1] = byte(extensionSessionTicket)
 		z = z[4:]
 	}
-	if m.secureRenegotiation {
+	if m.secureRenegotiationSupported {
 		z[0] = byte(extensionRenegotiationInfo >> 8)
 		z[1] = byte(extensionRenegotiationInfo & 0xff)
 		z[2] = 0
-		z[3] = 1
+		z[3] = byte(len(m.secureRenegotiation) + 1)
+		z[4] = byte(len(m.secureRenegotiation))
 		z = z[5:]
+		copy(z, m.secureRenegotiation)
+		z = z[len(m.secureRenegotiation):]
 	}
 	if alpnLen := len(m.alpnProtocol); alpnLen > 0 {
 		z[0] = byte(extensionALPN >> 8)
@@ -744,10 +762,18 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
 			}
 			m.ticketSupported = true
 		case extensionRenegotiationInfo:
-			if length != 1 || data[0] != 0 {
+			if length == 0 {
+				return false
+			}
+			d := data[:length]
+			l := int(d[0])
+			d = d[1:]
+			if l != len(d) {
 				return false
 			}
-			m.secureRenegotiation = true
+
+			m.secureRenegotiation = d
+			m.secureRenegotiationSupported = true
 		case extensionALPN:
 			d := data[:length]
 			if len(d) < 3 {
@@ -1316,11 +1342,8 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool {
 		m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
 		cas = cas[caLen:]
 	}
-	if len(data) > 0 {
-		return false
-	}
 
-	return true
+	return len(data) == 0
 }
 
 type certificateVerifyMsg struct {
@@ -1466,6 +1489,17 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
 	return true
 }
 
+type helloRequestMsg struct {
+}
+
+func (*helloRequestMsg) marshal() []byte {
+	return []byte{typeHelloRequest, 0, 0, 0}
+}
+
+func (*helloRequestMsg) unmarshal(data []byte) bool {
+	return len(data) == 4
+}
+
 func eqUint16s(x, y []uint16) bool {
 	if len(x) != len(y) {
 		return false
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index e16cddc..1aac729 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -35,6 +35,7 @@ type serverHandshakeState struct {
 }
 
 // serverHandshake performs a TLS handshake as a server.
+// c.out.Mutex <= L; c.handshakeMutex <= L.
 func (c *Conn) serverHandshake() error {
 	config := c.config
 
@@ -51,6 +52,7 @@ func (c *Conn) serverHandshake() error {
 	}
 
 	// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
+	c.buffering = true
 	if isResume {
 		// The client has included a session ticket and so we do an abbreviated handshake.
 		if err := hs.doResumeHandshake(); err != nil {
@@ -67,9 +69,13 @@ func (c *Conn) serverHandshake() error {
 				return err
 			}
 		}
-		if err := hs.sendFinished(c.firstFinished[:]); err != nil {
+		if err := hs.sendFinished(c.serverFinished[:]); err != nil {
 			return err
 		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
+		c.clientFinishedIsFirst = false
 		if err := hs.readFinished(nil); err != nil {
 			return err
 		}
@@ -83,15 +89,20 @@ func (c *Conn) serverHandshake() error {
 		if err := hs.establishKeys(); err != nil {
 			return err
 		}
-		if err := hs.readFinished(c.firstFinished[:]); err != nil {
+		if err := hs.readFinished(c.clientFinished[:]); err != nil {
 			return err
 		}
+		c.clientFinishedIsFirst = true
+		c.buffering = true
 		if err := hs.sendSessionTicket(); err != nil {
 			return err
 		}
 		if err := hs.sendFinished(nil); err != nil {
 			return err
 		}
+		if _, err := c.flush(); err != nil {
+			return err
+		}
 	}
 	c.handshakeComplete = true
 
@@ -165,7 +176,13 @@ Curves:
 		c.sendAlert(alertInternalError)
 		return false, err
 	}
-	hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation
+
+	if len(hs.clientHello.secureRenegotiation) != 0 {
+		c.sendAlert(alertHandshakeFailure)
+		return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+	}
+
+	hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
 	hs.hello.compressionMethod = compressionNone
 	if len(hs.clientHello.serverName) > 0 {
 		c.serverName = hs.clientHello.serverName
@@ -187,12 +204,13 @@ Curves:
 		}
 	}
 
-	if hs.cert, err = config.getCertificate(&ClientHelloInfo{
+	hs.cert, err = config.getCertificate(&ClientHelloInfo{
 		CipherSuites:    hs.clientHello.cipherSuites,
 		ServerName:      hs.clientHello.serverName,
 		SupportedCurves: hs.clientHello.supportedCurves,
 		SupportedPoints: hs.clientHello.supportedPoints,
-	}); err != nil {
+	})
+	if err != nil {
 		c.sendAlert(alertInternalError)
 		return false, err
 	}
@@ -208,7 +226,7 @@ Curves:
 			hs.rsaSignOk = true
 		default:
 			c.sendAlert(alertInternalError)
-			return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public())
+			return false, fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
 		}
 	}
 	if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
@@ -217,7 +235,7 @@ Curves:
 			hs.rsaDecryptOk = true
 		default:
 			c.sendAlert(alertInternalError)
-			return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public())
+			return false, fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
 		}
 	}
 
@@ -245,7 +263,7 @@ Curves:
 		return false, errors.New("tls: no cipher suite supported by both client and server")
 	}
 
-	// See https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00.
+	// See https://tools.ietf.org/html/rfc7507.
 	for _, id := range hs.clientHello.cipherSuites {
 		if id == TLS_FALLBACK_SCSV {
 			// The client is doing a fallback connection.
@@ -274,10 +292,8 @@ func (hs *serverHandshakeState) checkForResumption() bool {
 		return false
 	}
 
-	if hs.sessionState.vers > hs.clientHello.vers {
-		return false
-	}
-	if vers, ok := c.config.mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers {
+	// Never resume a session for a different TLS version.
+	if c.vers != hs.sessionState.vers {
 		return false
 	}
 
@@ -322,7 +338,9 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
 	hs.finishedHash.discardHandshakeBuffer()
 	hs.finishedHash.Write(hs.clientHello.marshal())
 	hs.finishedHash.Write(hs.hello.marshal())
-	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+		return err
+	}
 
 	if len(hs.sessionState.certificates) > 0 {
 		if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil {
@@ -354,19 +372,25 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 	}
 	hs.finishedHash.Write(hs.clientHello.marshal())
 	hs.finishedHash.Write(hs.hello.marshal())
-	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, hs.hello.marshal()); err != nil {
+		return err
+	}
 
 	certMsg := new(certificateMsg)
 	certMsg.certificates = hs.cert.Certificate
 	hs.finishedHash.Write(certMsg.marshal())
-	c.writeRecord(recordTypeHandshake, certMsg.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
+		return err
+	}
 
 	if hs.hello.ocspStapling {
 		certStatus := new(certificateStatusMsg)
 		certStatus.statusType = statusTypeOCSP
 		certStatus.response = hs.cert.OCSPStaple
 		hs.finishedHash.Write(certStatus.marshal())
-		c.writeRecord(recordTypeHandshake, certStatus.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certStatus.marshal()); err != nil {
+			return err
+		}
 	}
 
 	keyAgreement := hs.suite.ka(c.vers)
@@ -377,7 +401,9 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 	}
 	if skx != nil {
 		hs.finishedHash.Write(skx.marshal())
-		c.writeRecord(recordTypeHandshake, skx.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, skx.marshal()); err != nil {
+			return err
+		}
 	}
 
 	if config.ClientAuth >= RequestClientCert {
@@ -401,12 +427,20 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 			certReq.certificateAuthorities = config.ClientCAs.Subjects()
 		}
 		hs.finishedHash.Write(certReq.marshal())
-		c.writeRecord(recordTypeHandshake, certReq.marshal())
+		if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
+			return err
+		}
 	}
 
 	helloDone := new(serverHelloDoneMsg)
 	hs.finishedHash.Write(helloDone.marshal())
-	c.writeRecord(recordTypeHandshake, helloDone.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, helloDone.marshal()); err != nil {
+		return err
+	}
+
+	if _, err := c.flush(); err != nil {
+		return err
+	}
 
 	var pub crypto.PublicKey // public key for client auth, if any
 
@@ -462,7 +496,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 
 	// 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
+	// clientKeyExchangeMsg. This message is a digest of all preceding
 	// handshake-layer messages that is signed using the private key corresponding
 	// to the client's certificate. This allows us to verify that the client is in
 	// possession of the private key of the certificate.
@@ -499,7 +533,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 		switch key := pub.(type) {
 		case *ecdsa.PublicKey:
 			if signatureAndHash.signature != signatureECDSA {
-				err = errors.New("bad signature type for client's ECDSA certificate")
+				err = errors.New("tls: bad signature type for client's ECDSA certificate")
 				break
 			}
 			ecdsaSig := new(ecdsaSignature)
@@ -507,7 +541,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 				break
 			}
 			if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
-				err = errors.New("ECDSA signature contained zero or negative values")
+				err = errors.New("tls: ECDSA signature contained zero or negative values")
 				break
 			}
 			var digest []byte
@@ -515,11 +549,11 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 				break
 			}
 			if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
-				err = errors.New("ECDSA verification failure")
+				err = errors.New("tls: ECDSA verification failure")
 			}
 		case *rsa.PublicKey:
 			if signatureAndHash.signature != signatureRSA {
-				err = errors.New("bad signature type for client's RSA certificate")
+				err = errors.New("tls: bad signature type for client's RSA certificate")
 				break
 			}
 			var digest []byte
@@ -571,8 +605,8 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
 	c := hs.c
 
 	c.readRecord(recordTypeChangeCipherSpec)
-	if err := c.in.error(); err != nil {
-		return err
+	if c.in.err != nil {
+		return c.in.err
 	}
 
 	if hs.hello.nextProtoNeg {
@@ -632,7 +666,9 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
 	}
 
 	hs.finishedHash.Write(m.marshal())
-	c.writeRecord(recordTypeHandshake, m.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil {
+		return err
+	}
 
 	return nil
 }
@@ -640,12 +676,16 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
 func (hs *serverHandshakeState) sendFinished(out []byte) error {
 	c := hs.c
 
-	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
+	if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil {
+		return err
+	}
 
 	finished := new(finishedMsg)
 	finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
 	hs.finishedHash.Write(finished.marshal())
-	c.writeRecord(recordTypeHandshake, finished.marshal())
+	if _, err := c.writeRecord(recordTypeHandshake, finished.marshal()); err != nil {
+		return err
+	}
 
 	c.cipherSuite = hs.suite.id
 	copy(out, finished.verifyData)
@@ -690,20 +730,20 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
 		c.verifiedChains = chains
 	}
 
-	if len(certs) > 0 {
-		var pub crypto.PublicKey
-		switch key := certs[0].PublicKey.(type) {
-		case *ecdsa.PublicKey, *rsa.PublicKey:
-			pub = key
-		default:
-			c.sendAlert(alertUnsupportedCertificate)
-			return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
-		}
-		c.peerCertificates = certs
-		return pub, nil
+	if len(certs) == 0 {
+		return nil, nil
 	}
 
-	return nil, nil
+	var pub crypto.PublicKey
+	switch key := certs[0].PublicKey.(type) {
+	case *ecdsa.PublicKey, *rsa.PublicKey:
+		pub = key
+	default:
+		c.sendAlert(alertUnsupportedCertificate)
+		return nil, fmt.Errorf("tls: client's certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+	}
+	c.peerCertificates = certs
+	return pub, nil
 }
 
 // setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index 438fb31..9ae5d11 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -69,7 +69,7 @@ func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
 
 func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) {
 	// Create in-memory network connection,
-	// send message to server.  Should return
+	// send message to server. Should return
 	// expected error.
 	c, s := net.Pipe()
 	go func() {
@@ -80,7 +80,10 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa
 		cli.writeRecord(recordTypeHandshake, m.marshal())
 		c.Close()
 	}()
-	err := Server(s, serverConfig).Handshake()
+	hs := serverHandshakeState{
+		c: Server(s, serverConfig),
+	}
+	_, err := hs.readClientHello()
 	s.Close()
 	if len(expectedSubStr) == 0 {
 		if err != nil && err != io.EOF {
@@ -105,16 +108,16 @@ func TestRejectBadProtocolVersion(t *testing.T) {
 
 func TestNoSuiteOverlap(t *testing.T) {
 	clientHello := &clientHelloMsg{
-		vers:               0x0301,
+		vers:               VersionTLS10,
 		cipherSuites:       []uint16{0xff00},
-		compressionMethods: []uint8{0},
+		compressionMethods: []uint8{compressionNone},
 	}
 	testClientHelloFailure(t, testConfig, clientHello, "no cipher suite supported by both client and server")
 }
 
 func TestNoCompressionOverlap(t *testing.T) {
 	clientHello := &clientHelloMsg{
-		vers:               0x0301,
+		vers:               VersionTLS10,
 		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
 		compressionMethods: []uint8{0xff},
 	}
@@ -123,56 +126,56 @@ func TestNoCompressionOverlap(t *testing.T) {
 
 func TestNoRC4ByDefault(t *testing.T) {
 	clientHello := &clientHelloMsg{
-		vers:               0x0301,
+		vers:               VersionTLS10,
 		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
-		compressionMethods: []uint8{0},
+		compressionMethods: []uint8{compressionNone},
 	}
-	serverConfig := *testConfig
+	serverConfig := testConfig.clone()
 	// 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")
+	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,
+		vers:               VersionTLS10,
 		cipherSuites:       []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
-		compressionMethods: []uint8{0},
+		compressionMethods: []uint8{compressionNone},
 		supportedCurves:    []CurveID{CurveP256},
 		supportedPoints:    []uint8{pointFormatUncompressed},
 	}
-	serverConfig := *testConfig
+	serverConfig := testConfig.clone()
 	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)
+	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")
+	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,
+		vers:               VersionTLS10,
 		cipherSuites:       []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
-		compressionMethods: []uint8{0},
+		compressionMethods: []uint8{compressionNone},
 		supportedCurves:    []CurveID{CurveP256},
 		supportedPoints:    []uint8{pointFormatUncompressed},
 	}
-	serverConfig := *testConfig
+	serverConfig := testConfig.clone()
 	serverConfig.CipherSuites = clientHello.cipherSuites
 	// First test that it *does* work when the server's key is RSA.
-	testClientHello(t, &serverConfig, clientHello)
+	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).
@@ -180,16 +183,16 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {
 	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")
+	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},
+		vers:               VersionTLS12,
+		compressionMethods: []uint8{compressionNone},
+		random:             make([]byte, 32),
+		secureRenegotiationSupported: true,
+		cipherSuites:                 []uint16{TLS_RSA_WITH_RC4_128_SHA},
 	}
 
 	var buf []byte
@@ -226,7 +229,7 @@ func TestRenegotiationExtension(t *testing.T) {
 		t.Fatalf("Failed to parse ServerHello")
 	}
 
-	if !serverHello.secureRenegotiation {
+	if !serverHello.secureRenegotiationSupported {
 		t.Errorf("Secure renegotiation extension was not echoed.")
 	}
 }
@@ -262,9 +265,9 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
 		reply, clientErr = cli.readHandshake()
 		c.Close()
 	}()
-	config := *testConfig
+	config := testConfig.clone()
 	config.CipherSuites = clientHello.cipherSuites
-	Server(s, &config).Handshake()
+	Server(s, config).Handshake()
 	s.Close()
 	if clientErr != nil {
 		t.Fatal(clientErr)
@@ -396,6 +399,64 @@ func TestSCTHandshake(t *testing.T) {
 	}
 }
 
+func TestCrossVersionResume(t *testing.T) {
+	serverConfig := &Config{
+		CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+		Certificates: testConfig.Certificates,
+	}
+	clientConfig := &Config{
+		CipherSuites:       []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+		InsecureSkipVerify: true,
+		ClientSessionCache: NewLRUClientSessionCache(1),
+		ServerName:         "servername",
+	}
+
+	// Establish a session at TLS 1.1.
+	clientConfig.MaxVersion = VersionTLS11
+	_, _, err := testHandshake(clientConfig, serverConfig)
+	if err != nil {
+		t.Fatalf("handshake failed: %s", err)
+	}
+
+	// The client session cache now contains a TLS 1.1 session.
+	state, _, err := testHandshake(clientConfig, serverConfig)
+	if err != nil {
+		t.Fatalf("handshake failed: %s", err)
+	}
+	if !state.DidResume {
+		t.Fatalf("handshake did not resume at the same version")
+	}
+
+	// Test that the server will decline to resume at a lower version.
+	clientConfig.MaxVersion = VersionTLS10
+	state, _, err = testHandshake(clientConfig, serverConfig)
+	if err != nil {
+		t.Fatalf("handshake failed: %s", err)
+	}
+	if state.DidResume {
+		t.Fatalf("handshake resumed at a lower version")
+	}
+
+	// The client session cache now contains a TLS 1.0 session.
+	state, _, err = testHandshake(clientConfig, serverConfig)
+	if err != nil {
+		t.Fatalf("handshake failed: %s", err)
+	}
+	if !state.DidResume {
+		t.Fatalf("handshake did not resume at the same version")
+	}
+
+	// Test that the server will decline to resume at a higher version.
+	clientConfig.MaxVersion = VersionTLS11
+	state, _, err = testHandshake(clientConfig, serverConfig)
+	if err != nil {
+		t.Fatalf("handshake failed: %s", err)
+	}
+	if state.DidResume {
+		t.Fatalf("handshake resumed at a higher version")
+	}
+}
+
 // Note: see comment in handshake_test.go for details of how the reference
 // tests work.
 
@@ -518,16 +579,17 @@ func (test *serverTest) run(t *testing.T, write bool) {
 	server := Server(serverConn, config)
 	connStateChan := make(chan ConnectionState, 1)
 	go func() {
-		var err error
-		if _, err = server.Write([]byte("hello, world\n")); err != nil {
-			t.Logf("Error from Server.Write: %s", err)
-		}
+		_, err := server.Write([]byte("hello, world\n"))
 		if len(test.expectHandshakeErrorIncluding) > 0 {
 			if err == nil {
 				t.Errorf("Error expected, but no error returned")
 			} else if s := err.Error(); !strings.Contains(s, test.expectHandshakeErrorIncluding) {
 				t.Errorf("Error expected containing '%s' but got '%s'", test.expectHandshakeErrorIncluding, s)
 			}
+		} else {
+			if err != nil {
+				t.Logf("Error from Server.Write: '%s'", err)
+			}
 		}
 		server.Close()
 		serverConn.Close()
@@ -670,7 +732,7 @@ func TestHandshakeServerAES256GCMSHA384(t *testing.T) {
 }
 
 func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 	config.Certificates = make([]Certificate, 1)
 	config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
 	config.Certificates[0].PrivateKey = testECDSAPrivateKey
@@ -679,14 +741,14 @@ func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
 	test := &serverTest{
 		name:    "ECDHE-ECDSA-AES",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA"},
-		config:  &config,
+		config:  config,
 	}
 	runServerTestTLS10(t, test)
 	runServerTestTLS12(t, test)
 }
 
 func TestHandshakeServerALPN(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 	config.NextProtos = []string{"proto1", "proto2"}
 
 	test := &serverTest{
@@ -694,7 +756,7 @@ func TestHandshakeServerALPN(t *testing.T) {
 		// Note that this needs OpenSSL 1.0.2 because that is the first
 		// version that supports the -alpn flag.
 		command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"},
-		config:  &config,
+		config:  config,
 		validate: func(state ConnectionState) error {
 			// The server's preferences should override the client.
 			if state.NegotiatedProtocol != "proto1" {
@@ -707,7 +769,7 @@ func TestHandshakeServerALPN(t *testing.T) {
 }
 
 func TestHandshakeServerALPNNoMatch(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 	config.NextProtos = []string{"proto3"}
 
 	test := &serverTest{
@@ -715,7 +777,7 @@ func TestHandshakeServerALPNNoMatch(t *testing.T) {
 		// Note that this needs OpenSSL 1.0.2 because that is the first
 		// version that supports the -alpn flag.
 		command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"},
-		config:  &config,
+		config:  config,
 		validate: func(state ConnectionState) error {
 			// Rather than reject the connection, Go doesn't select
 			// a protocol when there is no overlap.
@@ -742,7 +804,7 @@ func TestHandshakeServerSNI(t *testing.T) {
 // TestHandshakeServerSNICertForName is similar to TestHandshakeServerSNI, but
 // tests the dynamic GetCertificate method
 func TestHandshakeServerSNIGetCertificate(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 
 	// Replace the NameToCertificate map with a GetCertificate function
 	nameToCert := config.NameToCertificate
@@ -754,7 +816,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
 	test := &serverTest{
 		name:    "SNI-GetCertificate",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
-		config:  &config,
+		config:  config,
 	}
 	runServerTestTLS12(t, test)
 }
@@ -764,7 +826,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
 // GetCertificate method doesn't return a cert, we fall back to what's in
 // the NameToCertificate map.
 func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 
 	config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
 		return nil, nil
@@ -772,7 +834,7 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
 	test := &serverTest{
 		name:    "SNI-GetCertificateNotFound",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
-		config:  &config,
+		config:  config,
 	}
 	runServerTestTLS12(t, test)
 }
@@ -782,18 +844,18 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
 func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
 	const errMsg = "TestHandshakeServerSNIGetCertificateError error"
 
-	serverConfig := *testConfig
+	serverConfig := testConfig.clone()
 	serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
 		return nil, errors.New(errMsg)
 	}
 
 	clientHello := &clientHelloMsg{
-		vers:               0x0301,
+		vers:               VersionTLS10,
 		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
-		compressionMethods: []uint8{0},
+		compressionMethods: []uint8{compressionNone},
 		serverName:         "test",
 	}
-	testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
+	testClientHelloFailure(t, serverConfig, clientHello, errMsg)
 }
 
 // TestHandshakeServerEmptyCertificates tests that GetCertificates is called in
@@ -801,45 +863,45 @@ func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
 func TestHandshakeServerEmptyCertificates(t *testing.T) {
 	const errMsg = "TestHandshakeServerEmptyCertificates error"
 
-	serverConfig := *testConfig
+	serverConfig := testConfig.clone()
 	serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
 		return nil, errors.New(errMsg)
 	}
 	serverConfig.Certificates = nil
 
 	clientHello := &clientHelloMsg{
-		vers:               0x0301,
+		vers:               VersionTLS10,
 		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
-		compressionMethods: []uint8{0},
+		compressionMethods: []uint8{compressionNone},
 	}
-	testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
+	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,
+		vers:               VersionTLS10,
 		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
-		compressionMethods: []uint8{0},
+		compressionMethods: []uint8{compressionNone},
 	}
-	testClientHelloFailure(t, &serverConfig, clientHello, "no certificates")
+	testClientHelloFailure(t, serverConfig, clientHello, "no certificates")
 }
 
 // TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
 // an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
 func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
-	config := *testConfig
+	config := testConfig.clone()
 	config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}
 	config.PreferServerCipherSuites = true
 
 	test := &serverTest{
 		name:   "CipherSuiteCertPreferenceRSA",
-		config: &config,
+		config: config,
 	}
 	runServerTestTLS12(t, test)
 
-	config = *testConfig
+	config = testConfig.clone()
 	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
 	config.Certificates = []Certificate{
 		{
@@ -852,7 +914,7 @@ func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
 
 	test = &serverTest{
 		name:   "CipherSuiteCertPreferenceECDSA",
-		config: &config,
+		config: config,
 	}
 	runServerTestTLS12(t, test)
 }
@@ -878,12 +940,12 @@ func TestResumptionDisabled(t *testing.T) {
 	sessionFilePath := tempFile("")
 	defer os.Remove(sessionFilePath)
 
-	config := *testConfig
+	config := testConfig.clone()
 
 	test := &serverTest{
 		name:    "IssueTicketPreDisable",
 		command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
-		config:  &config,
+		config:  config,
 	}
 	runServerTestTLS12(t, test)
 
@@ -892,7 +954,7 @@ func TestResumptionDisabled(t *testing.T) {
 	test = &serverTest{
 		name:    "ResumeDisabled",
 		command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
-		config:  &config,
+		config:  config,
 	}
 	runServerTestTLS12(t, test)
 
@@ -901,12 +963,12 @@ func TestResumptionDisabled(t *testing.T) {
 }
 
 func TestFallbackSCSV(t *testing.T) {
-	serverConfig := &Config{
+	serverConfig := Config{
 		Certificates: testConfig.Certificates,
 	}
 	test := &serverTest{
 		name:   "FallbackSCSV",
-		config: serverConfig,
+		config: &serverConfig,
 		// OpenSSL 1.0.1j is needed for the -fallback_scsv option.
 		command: []string{"openssl", "s_client", "-fallback_scsv"},
 		expectHandshakeErrorIncluding: "inappropriate protocol fallback",
@@ -991,20 +1053,20 @@ func TestClientAuth(t *testing.T) {
 		defer os.Remove(ecdsaKeyPath)
 	}
 
-	config := *testConfig
+	config := testConfig.clone()
 	config.ClientAuth = RequestClientCert
 
 	test := &serverTest{
 		name:    "ClientAuthRequestedNotGiven",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
-		config:  &config,
+		config:  config,
 	}
 	runServerTestTLS12(t, test)
 
 	test = &serverTest{
 		name:              "ClientAuthRequestedAndGiven",
 		command:           []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", certPath, "-key", keyPath},
-		config:            &config,
+		config:            config,
 		expectedPeerCerts: []string{clientCertificatePEM},
 	}
 	runServerTestTLS12(t, test)
@@ -1012,7 +1074,7 @@ func TestClientAuth(t *testing.T) {
 	test = &serverTest{
 		name:              "ClientAuthRequestedAndECDSAGiven",
 		command:           []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
-		config:            &config,
+		config:            config,
 		expectedPeerCerts: []string{clientECDSACertificatePEM},
 	}
 	runServerTestTLS12(t, test)
diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go
index 0e6a7c2..467efb2 100644
--- a/src/crypto/tls/key_agreement.go
+++ b/src/crypto/tls/key_agreement.go
@@ -51,7 +51,7 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
 	if err != nil {
 		return nil, err
 	}
-	// We don't check the version number in the premaster secret.  For one,
+	// We don't check the version number in the premaster secret. For one,
 	// by checking it, we would leak information about the validity of the
 	// encrypted pre-master secret. Secondly, it provides only a small
 	// benefit against a downgrade attack and some implementations send the
@@ -242,19 +242,19 @@ NextCandidate:
 	case signatureECDSA:
 		_, ok := priv.Public().(*ecdsa.PublicKey)
 		if !ok {
-			return nil, errors.New("ECDHE ECDSA requires an ECDSA server key")
+			return nil, errors.New("tls: ECDHE ECDSA requires an ECDSA server key")
 		}
 	case signatureRSA:
 		_, ok := priv.Public().(*rsa.PublicKey)
 		if !ok {
-			return nil, errors.New("ECDHE RSA requires a RSA server key")
+			return nil, errors.New("tls: ECDHE RSA requires a RSA server key")
 		}
 	default:
-		return nil, errors.New("unknown ECDHE signature algorithm")
+		return nil, errors.New("tls: 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())
+		return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
 	}
 
 	skx := new(serverKeyExchangeMsg)
@@ -354,28 +354,28 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
 	case signatureECDSA:
 		pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
 		if !ok {
-			return errors.New("ECDHE ECDSA requires a ECDSA server public key")
+			return errors.New("tls: ECDHE ECDSA requires a ECDSA server public key")
 		}
 		ecdsaSig := new(ecdsaSignature)
 		if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
 			return err
 		}
 		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
-			return errors.New("ECDSA signature contained zero or negative values")
+			return errors.New("tls: ECDSA signature contained zero or negative values")
 		}
 		if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
-			return errors.New("ECDSA verification failure")
+			return errors.New("tls: ECDSA verification failure")
 		}
 	case signatureRSA:
 		pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
 		if !ok {
-			return errors.New("ECDHE RSA requires a RSA server public key")
+			return errors.New("tls: ECDHE RSA requires a RSA server public key")
 		}
 		if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
 			return err
 		}
 	default:
-		return errors.New("unknown ECDHE signature algorithm")
+		return errors.New("tls: unknown ECDHE signature algorithm")
 	}
 
 	return nil
@@ -383,7 +383,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
 
 func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
 	if ka.curve == nil {
-		return nil, nil, errors.New("missing ServerKeyExchange message")
+		return nil, nil, errors.New("tls: missing ServerKeyExchange message")
 	}
 	priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand())
 	if err != nil {
diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go
index 747b817..5833fc1 100644
--- a/src/crypto/tls/prf.go
+++ b/src/crypto/tls/prf.go
@@ -85,7 +85,7 @@ func prf30(result, secret, label, seed []byte) {
 
 	done := 0
 	i := 0
-	// RFC5246 section 6.3 says that the largest PRF output needed is 128
+	// RFC 5246 section 6.3 says that the largest PRF output needed is 128
 	// bytes. Since no more ciphersuites will be added to SSLv3, this will
 	// remain true. Each iteration gives us 16 bytes so 10 iterations will
 	// be sufficient.
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce
new file mode 100644
index 0000000..00d35f4
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce
@@ -0,0 +1,251 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 85 01 00 00  81 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 22 c0 2f  |............."./|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+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 12  00 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 fa 71 0e 3c 35  |....Y...U...q.<5|
+00000010  33 cc 51 25 19 cf fe c4  ef c8 2d ec 88 75 a9 1c  |3.Q%......-..u..|
+00000020  6a e4 f3 b4 3d fd 74 cc  e1 71 71 20 de 14 e5 21  |j...=.t..qq ...!|
+00000030  84 17 62 62 4f 44 e7 c2  d6 00 07 d2 63 f8 b0 32  |..bbOD......c..2|
+00000040  e0 12 d3 cb 69 1f d8 ed  5d 43 89 86 c0 2f 00 00  |....i...]C.../..|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 71 0b 00 02 6d 00  02 6a 00 02 67 30 82 02  |..q...m..j..g0..|
+00000070  63 30 82 01 cc a0 03 02  01 02 02 09 00 a2 73 00  |c0............s.|
+00000080  0c 81 00 cb f3 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 0b 05 00 30 2b 31 17  30 15 06 03 55 04 0a 13  |....0+1.0...U...|
+000000a0  0e 47 6f 6f 67 6c 65 20  54 45 53 54 49 4e 47 31  |.Google TESTING1|
+000000b0  10 30 0e 06 03 55 04 03  13 07 47 6f 20 52 6f 6f  |.0...U....Go Roo|
+000000c0  74 30 1e 17 0d 31 35 30  31 30 31 30 30 30 30 30  |t0...15010100000|
+000000d0  30 5a 17 0d 32 35 30 31  30 31 30 30 30 30 30 30  |0Z..250101000000|
+000000e0  5a 30 26 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |Z0&1.0...U....Go|
+000000f0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 0b 30 09  |ogle TESTING1.0.|
+00000100  06 03 55 04 03 13 02 47  6f 30 81 9f 30 0d 06 09  |..U....Go0..0...|
+00000110  2a 86 48 86 f7 0d 01 01  01 05 00 03 81 8d 00 30  |*.H............0|
+00000120  81 89 02 81 81 00 af 87  88 f6 20 1b 95 65 6c 14  |.......... ..el.|
+00000130  ab 44 05 af 3b 45 14 e3  b7 6d fd 00 63 4d 95 7f  |.D..;E...m..cM..|
+00000140  fe 6a 62 35 86 c0 4a f9  18 7c f6 aa 25 5e 7a 64  |.jb5..J..|..%^zd|
+00000150  31 66 00 ba f4 8e 92 af  c7 6b d8 76 d4 f3 5f 41  |1f.......k.v.._A|
+00000160  cb 6e 56 15 97 1b 97 c1  3c 12 39 21 66 3d 2b 16  |.nV.....<.9!f=+.|
+00000170  d1 bc db 1c c0 a7 da b7  ca ad ba da cb d5 21 50  |..............!P|
+00000180  ec de 8d ab d1 6b 81 4b  89 02 f3 c4 be c1 6c 89  |.....k.K......l.|
+00000190  b1 44 84 bd 21 d1 04 7d  9d 16 4d f9 82 15 f6 ef  |.D..!..}..M.....|
+000001a0  fa d6 09 47 f2 fb 02 03  01 00 01 a3 81 93 30 81  |...G..........0.|
+000001b0  90 30 0e 06 03 55 1d 0f  01 01 ff 04 04 03 02 05  |.0...U..........|
+000001c0  a0 30 1d 06 03 55 1d 25  04 16 30 14 06 08 2b 06  |.0...U.%..0...+.|
+000001d0  01 05 05 07 03 01 06 08  2b 06 01 05 05 07 03 02  |........+.......|
+000001e0  30 0c 06 03 55 1d 13 01  01 ff 04 02 30 00 30 19  |0...U.......0.0.|
+000001f0  06 03 55 1d 0e 04 12 04  10 12 50 8d 89 6f 1b d1  |..U.......P..o..|
+00000200  dc 54 4d 6e cb 69 5e 06  f4 30 1b 06 03 55 1d 23  |.TMn.i^..0...U.#|
+00000210  04 14 30 12 80 10 bf 3d  b6 a9 66 f2 b8 40 cf ea  |..0....=..f.. at ..|
+00000220  b4 03 78 48 1a 41 30 19  06 03 55 1d 11 04 12 30  |..xH.A0...U....0|
+00000230  10 82 0e 65 78 61 6d 70  6c 65 2e 67 6f 6c 61 6e  |...example.golan|
+00000240  67 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |g0...*.H........|
+00000250  03 81 81 00 92 7c af 91  55 12 18 96 59 31 a6 48  |.....|..U...Y1.H|
+00000260  40 d5 2d d5 ee bb 02 a0  f5 c2 1e 7c 9b b3 30 7d  |@.-........|..0}|
+00000270  3c dc 76 da 4f 3d c0 fa  ae 2d 33 24 6b 03 7b 1b  |<.v.O=...-3$k.{.|
+00000280  67 59 11 21 b5 11 bc 77  b9 d9 e0 6e a8 2d 2e 35  |gY.!...w...n.-.5|
+00000290  fa 64 5f 22 3e 63 10 6b  be ff 14 86 6d 0d f0 15  |.d_">c.k....m...|
+000002a0  31 a8 14 38 1e 3b 84 87  2c cb 98 ed 51 76 b9 b1  |1..8.;..,...Qv..|
+000002b0  4f dd db 9b 84 04 86 40  fa 51 dd ba b4 8d eb e3  |O...... at .Q......|
+000002c0  46 de 46 b9 4f 86 c7 f9  a4 c2 41 34 ac cc f6 ea  |F.F.O.....A4....|
+000002d0  b0 ab 39 18 16 03 03 00  cd 0c 00 00 c9 03 00 17  |..9.............|
+000002e0  41 04 71 a0 a9 f0 31 52  0b a2 5f 44 b1 48 a6 dc  |A.q...1R.._D.H..|
+000002f0  b7 b8 bb a3 59 13 06 46  73 37 b1 9d f6 5a 42 49  |....Y..Fs7...ZBI|
+00000300  a7 e4 3c 26 64 ed 26 41  f9 76 d5 88 ad b5 2f 12  |..<&d.&A.v..../.|
+00000310  ce 02 34 b8 85 36 ee cd  a1 dc d9 d7 4b ed d2 81  |..4..6......K...|
+00000320  82 1e 04 01 00 80 86 91  0e 05 48 de 2b 45 0a 9d  |..........H.+E..|
+00000330  72 33 44 73 98 f3 0e 0f  4c 0b aa c0 6b 02 34 83  |r3Ds....L...k.4.|
+00000340  0c e1 53 04 89 47 21 22  de 09 5e d0 b3 d9 8b 53  |..S..G!"..^....S|
+00000350  62 b0 bf c6 dd fe d3 ed  d6 2e ac a0 64 9d a4 07  |b...........d...|
+00000360  1f a9 d5 89 5f 62 7f e0  b1 9b e2 ef 3e 36 89 70  |...._b......>6.p|
+00000370  3e 7c 0a e7 8c cb c3 a8  e0 91 d9 bd 6e 3d be 0e  |>|..........n=..|
+00000380  a2 8c ab 46 1b 07 24 40  da a5 e3 0b b1 6a 9f 28  |...F..$@.....j.(|
+00000390  c7 4f e8 d0 a3 57 e1 5c  f2 34 07 aa 77 28 91 a0  |.O...W.\.4..w(..|
+000003a0  7e d6 36 2c c3 1a 16 03  03 00 04 0e 00 00 00     |~.6,...........|
+>>> 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 53 c5  |.....(........S.|
+00000060  60 30 29 1d 8a 38 57 f3  6d d1 f4 e1 ec 3e 79 d1  |`0)..8W.m....>y.|
+00000070  79 d3 b8 7f 4e 71 41 d6  72 fa c0 cd 53 92        |y...NqA.r...S.|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 86 be df d2 27  |..........(....'|
+00000010  8b 37 77 eb 0b e4 6e 38  5c 27 56 48 bb b5 f2 be  |.7w...n8\'VH....|
+00000020  43 e5 f7 32 d2 d3 a1 d7  4e 6a 3c 76 17 94 c1 b0  |C..2....Nj<v....|
+00000030  06 af 67                                          |..g|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 17 22 06  |..............".|
+00000010  f7 50 b5 6f 65 e0 dd f9  b6 bc 50 b7 91 c9 54 5c  |.P.oe.....P...T\|
+00000020  4e 2f cc                                          |N/.|
+>>> Flow 6 (server to client)
+00000000  16 03 03 00 1c 86 be df  d2 27 8b 37 78 c8 e7 d6  |.........'.7x...|
+00000010  4b e4 60 9e 4c b0 28 79  d9 7a 78 58 d8 27 76 18  |K.`.L.(y.zxX.'v.|
+00000020  a3                                                |.|
+>>> Flow 7 (client to server)
+00000000  16 03 03 00 a9 00 00 00  00 00 00 00 02 a7 17 56  |...............V|
+00000010  8e ea 2e fc 76 06 40 b2  fa 10 71 62 68 b9 14 e6  |....v. at ...qbh...|
+00000020  09 6d 63 86 d1 6b 87 3a  c4 84 15 77 68 f8 85 ec  |.mc..k.:...wh...|
+00000030  55 49 3c c5 c1 be 24 85  0c 38 4b 66 a8 5f 33 f9  |UI<...$..8Kf._3.|
+00000040  a3 e5 d1 36 fd 25 ba 9d  54 1f 4c df 66 09 a7 08  |...6.%..T.L.f...|
+00000050  8d 7c a4 7e d4 5d c2 11  77 7b 48 7a 32 f7 88 0a  |.|.~.]..w{Hz2...|
+00000060  51 5f 6a 26 e2 11 88 01  5b b6 8e 6a aa 18 79 85  |Q_j&....[..j..y.|
+00000070  6a 0e 31 1f 33 5e 34 fd  e9 1c 84 7c ea 6c 78 5d  |j.1.3^4....|.lx]|
+00000080  0e d2 df c0 8c 92 3d 48  fc 9e 47 18 2a a7 1e e3  |......=H..G.*...|
+00000090  9b 89 6f 30 d0 fd 0a cd  4c b9 d9 89 b6 72 53 54  |..o0....L....rST|
+000000a0  3e 02 c3 d0 68 b0 4e 40  06 86 cd 8e 87 53        |>...h.N at .....S|
+>>> Flow 8 (server to client)
+00000000  16 03 03 00 89 86 be df  d2 27 8b 37 79 29 01 95  |.........'.7y)..|
+00000010  8c 13 0f f0 6e 8b 00 0c  1e 1a 36 73 b6 96 ad e1  |....n.....6s....|
+00000020  40 80 6d 68 f3 41 a9 a1  85 ca 86 81 73 6c fc 49  |@.mh.A......sl.I|
+00000030  b4 61 76 27 0f cd 22 5f  7e a7 c1 e3 13 f6 2e da  |.av'.."_~.......|
+00000040  1a 15 57 1a f1 b0 be 6d  55 44 78 95 62 82 ff 6e  |..W....mUDx.b..n|
+00000050  bb 70 ea 24 2c bf e2 14  48 3a 07 9a 30 3a a8 88  |.p.$,...H:..0:..|
+00000060  8b d6 b4 62 28 cb 30 94  54 f6 9c 15 34 e9 c4 d2  |...b(.0.T...4...|
+00000070  e3 42 cf 79 1f 96 34 f3  4c 9f f2 df 6e 70 4f cd  |.B.y..4.L...npO.|
+00000080  68 ae e2 2c d5 b7 f3 37  86 0a f5 7c af 32 16 03  |h..,...7...|.2..|
+00000090  03 02 89 86 be df d2 27  8b 37 7a 66 a9 20 cf 95  |.......'.7zf. ..|
+000000a0  d1 c9 3c c6 bc 53 16 01  e2 78 7e 2b 4d 45 20 d8  |..<..S...x~+ME .|
+000000b0  be da 93 9f 61 0b 34 25  f8 42 aa 0e b7 c5 a7 7a  |....a.4%.B.....z|
+000000c0  99 23 b5 a5 0b 39 37 48  2d 66 21 8a bd 41 11 e5  |.#...97H-f!..A..|
+000000d0  79 5f 5d c1 9b 4f c2 0c  fc a4 b9 ad 82 7e 7e 5b  |y_]..O.......~~[|
+000000e0  f6 95 46 eb b2 9e 9c 2d  58 7e c7 90 2c c4 7f 1c  |..F....-X~..,...|
+000000f0  cf 32 86 37 ec ab 60 71  ee 82 2b a2 95 61 8f 31  |.2.7..`q..+..a.1|
+00000100  99 2d c7 f4 5f 29 e8 b6  c3 f4 81 4f 2c b6 2c 67  |.-.._).....O,.,g|
+00000110  70 e5 cf d1 00 77 34 28  dc 61 cf e1 78 10 5e 64  |p....w4(.a..x.^d|
+00000120  17 f7 2b 3e 74 2c 8f 42  d5 a8 c2 4e 11 48 0f 0a  |..+>t,.B...N.H..|
+00000130  3f 8a ea 0f 37 f5 da 8f  7f 7c 61 b3 98 d9 69 80  |?...7....|a...i.|
+00000140  b5 1e c6 5c 01 ff e3 8e  45 a1 7a cb ee ea 12 d3  |...\....E.z.....|
+00000150  d7 56 2e 33 8c 55 a5 94  84 f7 a1 a4 fa f3 71 f4  |.V.3.U........q.|
+00000160  a3 15 f0 7e 44 c7 32 65  86 39 93 b7 df ab 6b 94  |...~D.2e.9....k.|
+00000170  df 6d d8 31 72 ba d9 7b  b6 8a 68 b1 c8 da e1 a0  |.m.1r..{..h.....|
+00000180  4f 0f 06 6a 52 78 6e a1  57 2f 2b 6b 10 5b c1 57  |O..jRxn.W/+k.[.W|
+00000190  d0 92 23 bf dc 95 f1 83  66 ce 6f ef c5 22 22 24  |..#.....f.o..""$|
+000001a0  80 bd 2f 38 ff de ec 86  8b ad 81 4e fe 31 65 54  |../8.......N.1eT|
+000001b0  19 94 ce 99 0f 6d 5b 1b  53 ba ad 65 a6 6a f6 27  |.....m[.S..e.j.'|
+000001c0  ba e0 b7 a9 8b 80 18 71  67 f7 6c 35 5f 69 c2 19  |.......qg.l5_i..|
+000001d0  08 27 03 45 5a 58 49 27  cf ec bf 18 e7 60 64 2b  |.'.EZXI'.....`d+|
+000001e0  47 9e 07 1a 49 ef 90 20  c7 f7 69 5c 46 92 ae 65  |G...I.. ..i\F..e|
+000001f0  fa 45 9f 3b a3 4e ed cb  d9 1f d9 26 18 1e bb 58  |.E.;.N.....&...X|
+00000200  16 cd a5 00 df 65 73 39  82 fd 98 29 de 45 8f 70  |.....es9...).E.p|
+00000210  56 e3 c6 0b 18 71 09 92  0e 69 4e b8 e7 23 4f 70  |V....q...iN..#Op|
+00000220  7a 89 06 c7 78 05 04 31  7f 77 5c 68 74 f0 45 76  |z...x..1.w\ht.Ev|
+00000230  e2 56 b2 de 34 e6 79 64  49 9a a8 3a b7 5b 4a d3  |.V..4.ydI..:.[J.|
+00000240  5e 6d 0b f3 fb 6d 0c 2f  61 d0 71 f4 0d ed 60 2f  |^m...m./a.q...`/|
+00000250  61 80 c9 9b b9 e5 89 f2  64 88 52 d6 d3 aa 72 6b  |a.......d.R...rk|
+00000260  66 18 ae e9 df 20 40 15  b5 73 ba ac 50 b1 27 99  |f.... @..s..P.'.|
+00000270  b3 17 97 56 0b 7d 25 8a  64 80 42 5c c8 b8 d5 98  |...V.}%.d.B\....|
+00000280  28 16 2b ce 45 65 3d fc  d8 c6 91 31 c2 d4 09 a3  |(.+.Ee=....1....|
+00000290  cf 92 85 63 36 cb e2 da  a3 66 fb 08 c9 bc 12 23  |...c6....f.....#|
+000002a0  c8 88 7d 46 22 98 40 01  bf fb 58 84 f2 8f ad 83  |..}F". at ...X.....|
+000002b0  ed 79 b4 a8 3d e5 92 b7  b8 e1 d0 50 aa be 22 9c  |.y..=......P..".|
+000002c0  9c cb dc bd 65 59 41 3e  6f 53 89 02 30 b1 88 ca  |....eYA>oS..0...|
+000002d0  06 6d 8e b2 a6 75 6a d8  5a 19 65 de 27 c3 bf 70  |.m...uj.Z.e.'..p|
+000002e0  49 64 13 2d 19 5d 7a ec  91 a7 f6 82 92 7d e3 7e  |Id.-.]z......}.~|
+000002f0  d6 65 5b d4 eb ed 58 d7  cd 41 a2 b9 d3 9e e4 a0  |.e[...X..A......|
+00000300  92 bf 88 4f 0e 59 74 66  86 db 72 11 18 ad 81 24  |...O.Ytf..r....$|
+00000310  6e 43 38 24 23 fb db af  92 d8 1a 2d 16 03 03 00  |nC8$#......-....|
+00000320  e5 86 be df d2 27 8b 37  7b ce 01 b6 78 47 7d 3a  |.....'.7{...xG}:|
+00000330  ad 2e 03 8e 78 03 61 da  55 0e d4 fa 87 9d 20 25  |....x.a.U..... %|
+00000340  73 1f 3b 87 7b 02 c1 a3  af ce d5 b9 9e 29 91 1b  |s.;.{........)..|
+00000350  58 13 c9 bc 96 95 88 f8  67 43 03 25 a3 be 5e a6  |X.......gC.%..^.|
+00000360  1d ee 6e 70 4c b5 66 48  3d 7d 1a 58 8e 10 c0 68  |..npL.fH=}.X...h|
+00000370  6b d8 f1 dd 83 c5 d3 c8  81 c5 6d 72 68 50 41 6f  |k.........mrhPAo|
+00000380  f6 20 13 f8 72 fa 82 9a  25 e4 07 10 df b7 39 90  |. ..r...%.....9.|
+00000390  6a d7 d2 d7 a1 1c 31 4e  b6 7c 00 bc 4d b1 a1 ff  |j.....1N.|..M...|
+000003a0  d0 ae 42 b1 2d 3e 8b c9  43 f4 fa fc d4 71 8f 74  |..B.->..C....q.t|
+000003b0  37 23 1b bb 34 4e b6 e4  fe f1 1b ea da 08 e4 12  |7#..4N..........|
+000003c0  fd 50 23 f9 8a 2d 92 eb  f5 2b fc b4 e1 35 87 74  |.P#..-...+...5.t|
+000003d0  44 79 0b df 6a 14 eb 20  17 ab 5b 12 a7 19 a4 4e  |Dy..j.. ..[....N|
+000003e0  94 70 93 57 2d bd c2 54  88 fb 19 b7 82 28 ab db  |.p.W-..T.....(..|
+000003f0  ca a9 19 5d 36 1b d6 fc  7d 41 2c 5b 76 ec 90 72  |...]6...}A,[v..r|
+00000400  47 5b c4 ae 59 a6 16 03  03 00 46 86 be df d2 27  |G[..Y.....F....'|
+00000410  8b 37 7c ed db 59 c6 0b  4e 52 c9 bc 7a 81 ed 20  |.7|..Y..NR..z.. |
+00000420  00 55 02 76 15 49 9b 0b  f2 81 c2 f7 25 51 61 9d  |.U.v.I......%Qa.|
+00000430  48 e3 d2 6f 08 ea 0c 9b  26 cc 3b 52 58 ef a0 1f  |H..o....&.;RX...|
+00000440  09 c3 ca e8 c2 6c 13 86  b1 94 04 f1 65 e2 de 4c  |.....l......e..L|
+00000450  7c                                                |||
+>>> Flow 9 (client to server)
+00000000  16 03 03 02 89 00 00 00  00 00 00 00 03 3c 0f 09  |.............<..|
+00000010  9e dc 39 b8 be ab ca 53  74 05 93 12 a4 e7 bb 56  |..9....St......V|
+00000020  9f e1 9f 2a 09 7d e1 74  89 ee b3 99 3c 91 c6 38  |...*.}.t....<..8|
+00000030  7e 0c 5e 2d 1f 7d bd cd  1a d1 16 ab af 94 08 c6  |~.^-.}..........|
+00000040  74 e3 16 12 0e 9b bc 91  95 6d 01 fd 10 00 12 c6  |t........m......|
+00000050  03 96 92 08 df 50 89 ba  5c 25 ce 31 d8 b1 84 8a  |.....P..\%.1....|
+00000060  7d 6c cf 7f e6 9a e4 08  17 cc b8 f2 c9 8f e8 4b  |}l.............K|
+00000070  ab 44 4f e9 63 8c 93 71  b1 70 4a f4 29 5f ef 45  |.DO.c..q.pJ.)_.E|
+00000080  68 e1 0e 31 a0 4c 96 8c  65 03 f3 48 24 48 d4 d7  |h..1.L..e..H$H..|
+00000090  93 d1 17 39 8d 97 e8 d8  59 08 4b 46 82 cf a3 99  |...9....Y.KF....|
+000000a0  55 36 65 a9 d8 df db d5  65 78 52 38 c2 2a 1e ec  |U6e.....exR8.*..|
+000000b0  65 6a f5 d5 4c 81 0c f6  e6 77 b2 68 d4 6c 32 05  |ej..L....w.h.l2.|
+000000c0  ef f4 ee 0b e1 83 d0 3a  cf a0 06 f2 cc 61 62 5e  |.......:.....ab^|
+000000d0  fa b4 19 c7 e2 99 c1 cf  02 a1 01 3d 6a e0 be 9f  |...........=j...|
+000000e0  82 cd e5 c8 ac e2 3e 6d  0f 60 a4 e9 9b ca cf c9  |......>m.`......|
+000000f0  c1 fe 2d ef 29 ed f9 c3  11 03 9f 76 66 71 ef 24  |..-.)......vfq.$|
+00000100  5f d3 29 aa 6a e1 0c b1  58 7a f3 df 92 e8 61 e2  |_.).j...Xz....a.|
+00000110  41 43 ad 9d 55 a0 b0 a3  20 8d 2c 8f 34 e6 ab d3  |AC..U... .,.4...|
+00000120  37 80 9e cb 27 91 69 0a  ba 33 05 a1 7f 4d 7f 63  |7...'.i..3...M.c|
+00000130  ed 6a c1 72 43 ec 6a 6c  ac b7 87 bb 81 6e 06 fa  |.j.rC.jl.....n..|
+00000140  68 7a c9 33 28 59 ed 74  87 a1 6a 24 06 02 c0 21  |hz.3(Y.t..j$...!|
+00000150  71 b0 27 f9 6e b3 7e 30  e9 e0 df c2 5d 63 2a dd  |q.'.n.~0....]c*.|
+00000160  9d e9 9c 4f 47 66 68 7e  e4 8c 87 b7 f0 a8 3d b8  |...OGfh~......=.|
+00000170  36 39 3e 4c 9f 55 e7 bb  c7 3e 34 36 54 19 41 33  |69>L.U...>46T.A3|
+00000180  61 e6 9a ae c6 91 1d fa  2d 8c 45 95 5f 95 36 79  |a.......-.E._.6y|
+00000190  e9 59 7e 81 cd 7e 9e 01  fe 85 eb c8 ed 4e 93 c6  |.Y~..~.......N..|
+000001a0  53 76 2d 5c 72 50 22 16  04 15 c2 cf 19 07 e6 73  |Sv-\rP"........s|
+000001b0  74 d0 7b bb 68 c3 29 39  bc ab 1b 4c c9 5a 36 73  |t.{.h.)9...L.Z6s|
+000001c0  55 47 7a c8 4a a7 45 fe  f3 a9 94 6e ea ea cc 7d  |UGz.J.E....n...}|
+000001d0  d1 de f4 82 4c 14 84 f0  58 09 56 25 83 7a 23 71  |....L...X.V%.z#q|
+000001e0  a1 63 e3 4e 13 78 68 41  a1 9a 55 ec 9e 37 ee c2  |.c.N.xhA..U..7..|
+000001f0  7d 3f 8f 91 00 30 f2 ca  7b 13 b7 e7 fe 85 c5 aa  |}?...0..{.......|
+00000200  5e e3 97 2c cb d5 13 1e  83 3d c9 2a b1 21 f1 58  |^..,.....=.*.!.X|
+00000210  7d 09 32 31 d6 fd 89 26  ff 72 3c f7 c4 fe 99 33  |}.21...&.r<....3|
+00000220  41 82 76 05 b9 14 b1 b0  3c 41 02 74 a8 1d dd 80  |A.v.....<A.t....|
+00000230  38 67 25 01 39 f7 36 fa  e4 1c 7d 2f c9 7e 21 0a  |8g%.9.6...}/.~!.|
+00000240  30 77 1e ff fc 8a 31 ac  ee 91 f0 2c b1 9a b7 5e  |0w....1....,...^|
+00000250  26 d0 7a 9d b4 9e 53 6b  dd a6 5e 7b f0 45 99 9b  |&.z...Sk..^{.E..|
+00000260  2b 69 90 d4 dd 1a d0 b5  13 90 11 ac 01 f0 2f 94  |+i............/.|
+00000270  5b 59 7e 7a 40 22 3a b0  d4 24 92 7d 94 bf 34 91  |[Y~z@":..$.}..4.|
+00000280  f6 b9 cc c9 e5 de d3 67  6d 83 97 ee 8f 48 16 03  |.......gm....H..|
+00000290  03 00 5e 00 00 00 00 00  00 00 04 dc 6f 41 98 23  |..^.........oA.#|
+000002a0  d7 70 80 24 74 46 c8 45  e1 2f 43 1d b8 66 4d 0a  |.p.$tF.E./C..fM.|
+000002b0  03 0e d6 01 8b 92 f7 76  c1 2c 32 6c 65 60 da ab  |.......v.,2le`..|
+000002c0  0b 12 6d 30 1c cf de e7  ec a7 12 f9 df 6c b4 42  |..m0.........l.B|
+000002d0  e7 d9 6e 6e f3 1c 10 ee  39 47 7f ec 7c ec 68 68  |..nn....9G..|.hh|
+000002e0  e8 b2 70 a2 67 61 e0 b3  68 b5 91 9f 1a e0 c5 af  |..p.ga..h.......|
+000002f0  e3 16 03 03 00 a0 00 00  00 00 00 00 00 05 6b 56  |..............kV|
+00000300  3d 5e 4e f1 2c 30 e2 91  24 5c b1 5f d3 7d 3e dc  |=^N.,0..$\._.}>.|
+00000310  ba 98 e1 9f 72 98 2b 0e  11 07 d1 ea 14 d5 73 25  |....r.+.......s%|
+00000320  d2 cf 8e bc a5 ea 93 a7  32 ab 94 83 1e ea c5 62  |........2......b|
+00000330  06 79 bb ab 4c a0 cf fb  51 3b 7b f0 11 5e ae 50  |.y..L...Q;{..^.P|
+00000340  23 cb ff 86 03 3d a5 66  b9 c4 35 c2 12 f2 98 85  |#....=.f..5.....|
+00000350  77 ba af 3b d5 dd f2 cd  58 09 29 26 08 cd 4a ed  |w..;....X.)&..J.|
+00000360  ac af 57 ab 27 1a 40 ef  10 57 d1 ad 06 34 be ed  |..W.'. at ..W...4..|
+00000370  fe 88 1d 09 4a 81 8a da  e7 ef fa 27 71 ab 2b 3f  |....J......'q.+?|
+00000380  21 91 5f 1a dc 50 a4 f0  58 bd aa af 75 4e 25 2a  |!._..P..X...uN%*|
+00000390  2c 55 e5 57 c6 ab 14 03  03 00 19 00 00 00 00 00  |,U.W............|
+000003a0  00 00 06 5d 8a 3e 8e 55  e4 9d c0 6a de 91 c6 96  |...].>.U...j....|
+000003b0  6e 17 54 a5 16 03 03 00  28 00 00 00 00 00 00 00  |n.T.....(.......|
+000003c0  00 d5 45 5d 11 af e2 b6  f1 a8 e5 ed 58 80 54 ce  |..E]........X.T.|
+000003d0  b3 db dc 97 b3 86 c0 83  f9 3b 7c b5 ad 21 f8 cf  |.........;|..!..|
+000003e0  9a                                                |.|
+>>> Flow 10 (server to client)
+00000000  14 03 03 00 19 86 be df  d2 27 8b 37 7d 85 70 b7  |.........'.7}.p.|
+00000010  a7 98 89 36 01 b4 a8 6f  cb 14 0f dd ac 08 16 03  |...6...o........|
+00000020  03 00 28 75 41 a9 ef 1c  88 59 4e 84 15 29 a4 75  |..(uA....YN..).u|
+00000030  e6 66 01 3f a1 b7 ff 69  04 b6 08 99 c9 5e 57 60  |.f.?...i.....^W`|
+00000040  ea 76 21 94 06 e4 32 95  e1 4c d7 17 03 03 00 21  |.v!...2..L.....!|
+00000050  75 41 a9 ef 1c 88 59 4f  c8 5d 4e bd 42 52 ec 50  |uA....YO.]N.BR.P|
+00000060  2f 28 4f 87 da bc f0 df  a8 93 14 b7 6f a0 7f a2  |/(O.........o...|
+00000070  c5                                                |.|
+>>> Flow 11 (client to server)
+00000000  15 03 03 00 1a 00 00 00  00 00 00 00 01 92 8a f2  |................|
+00000010  9a d1 c9 1e 68 15 2d 6b  9a a7 f8 21 78 87 89     |....h.-k...!x..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice
new file mode 100644
index 0000000..185dc65
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice
@@ -0,0 +1,409 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 85 01 00 00  81 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 22 c0 2f  |............."./|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+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 12  00 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 bb b7 b5 ee 8b  |....Y...U.......|
+00000010  b7 92 40 96 01 65 93 09  a0 63 77 b3 35 74 0a 73  |.. at ..e...cw.5t.s|
+00000020  db e8 4a 9c d4 95 4b 2a  f9 43 1e 20 d6 5a ed d1  |..J...K*.C. .Z..|
+00000030  05 f0 61 aa 45 ae 0e 92  03 87 1b a6 0a 1a 83 a1  |..a.E...........|
+00000040  bd 4f c3 81 79 e8 56 10  5d 08 7b 6d c0 2f 00 00  |.O..y.V.].{m./..|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 71 0b 00 02 6d 00  02 6a 00 02 67 30 82 02  |..q...m..j..g0..|
+00000070  63 30 82 01 cc a0 03 02  01 02 02 09 00 a2 73 00  |c0............s.|
+00000080  0c 81 00 cb f3 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 0b 05 00 30 2b 31 17  30 15 06 03 55 04 0a 13  |....0+1.0...U...|
+000000a0  0e 47 6f 6f 67 6c 65 20  54 45 53 54 49 4e 47 31  |.Google TESTING1|
+000000b0  10 30 0e 06 03 55 04 03  13 07 47 6f 20 52 6f 6f  |.0...U....Go Roo|
+000000c0  74 30 1e 17 0d 31 35 30  31 30 31 30 30 30 30 30  |t0...15010100000|
+000000d0  30 5a 17 0d 32 35 30 31  30 31 30 30 30 30 30 30  |0Z..250101000000|
+000000e0  5a 30 26 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |Z0&1.0...U....Go|
+000000f0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 0b 30 09  |ogle TESTING1.0.|
+00000100  06 03 55 04 03 13 02 47  6f 30 81 9f 30 0d 06 09  |..U....Go0..0...|
+00000110  2a 86 48 86 f7 0d 01 01  01 05 00 03 81 8d 00 30  |*.H............0|
+00000120  81 89 02 81 81 00 af 87  88 f6 20 1b 95 65 6c 14  |.......... ..el.|
+00000130  ab 44 05 af 3b 45 14 e3  b7 6d fd 00 63 4d 95 7f  |.D..;E...m..cM..|
+00000140  fe 6a 62 35 86 c0 4a f9  18 7c f6 aa 25 5e 7a 64  |.jb5..J..|..%^zd|
+00000150  31 66 00 ba f4 8e 92 af  c7 6b d8 76 d4 f3 5f 41  |1f.......k.v.._A|
+00000160  cb 6e 56 15 97 1b 97 c1  3c 12 39 21 66 3d 2b 16  |.nV.....<.9!f=+.|
+00000170  d1 bc db 1c c0 a7 da b7  ca ad ba da cb d5 21 50  |..............!P|
+00000180  ec de 8d ab d1 6b 81 4b  89 02 f3 c4 be c1 6c 89  |.....k.K......l.|
+00000190  b1 44 84 bd 21 d1 04 7d  9d 16 4d f9 82 15 f6 ef  |.D..!..}..M.....|
+000001a0  fa d6 09 47 f2 fb 02 03  01 00 01 a3 81 93 30 81  |...G..........0.|
+000001b0  90 30 0e 06 03 55 1d 0f  01 01 ff 04 04 03 02 05  |.0...U..........|
+000001c0  a0 30 1d 06 03 55 1d 25  04 16 30 14 06 08 2b 06  |.0...U.%..0...+.|
+000001d0  01 05 05 07 03 01 06 08  2b 06 01 05 05 07 03 02  |........+.......|
+000001e0  30 0c 06 03 55 1d 13 01  01 ff 04 02 30 00 30 19  |0...U.......0.0.|
+000001f0  06 03 55 1d 0e 04 12 04  10 12 50 8d 89 6f 1b d1  |..U.......P..o..|
+00000200  dc 54 4d 6e cb 69 5e 06  f4 30 1b 06 03 55 1d 23  |.TMn.i^..0...U.#|
+00000210  04 14 30 12 80 10 bf 3d  b6 a9 66 f2 b8 40 cf ea  |..0....=..f.. at ..|
+00000220  b4 03 78 48 1a 41 30 19  06 03 55 1d 11 04 12 30  |..xH.A0...U....0|
+00000230  10 82 0e 65 78 61 6d 70  6c 65 2e 67 6f 6c 61 6e  |...example.golan|
+00000240  67 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |g0...*.H........|
+00000250  03 81 81 00 92 7c af 91  55 12 18 96 59 31 a6 48  |.....|..U...Y1.H|
+00000260  40 d5 2d d5 ee bb 02 a0  f5 c2 1e 7c 9b b3 30 7d  |@.-........|..0}|
+00000270  3c dc 76 da 4f 3d c0 fa  ae 2d 33 24 6b 03 7b 1b  |<.v.O=...-3$k.{.|
+00000280  67 59 11 21 b5 11 bc 77  b9 d9 e0 6e a8 2d 2e 35  |gY.!...w...n.-.5|
+00000290  fa 64 5f 22 3e 63 10 6b  be ff 14 86 6d 0d f0 15  |.d_">c.k....m...|
+000002a0  31 a8 14 38 1e 3b 84 87  2c cb 98 ed 51 76 b9 b1  |1..8.;..,...Qv..|
+000002b0  4f dd db 9b 84 04 86 40  fa 51 dd ba b4 8d eb e3  |O...... at .Q......|
+000002c0  46 de 46 b9 4f 86 c7 f9  a4 c2 41 34 ac cc f6 ea  |F.F.O.....A4....|
+000002d0  b0 ab 39 18 16 03 03 00  cd 0c 00 00 c9 03 00 17  |..9.............|
+000002e0  41 04 b5 fe 7d 68 cd 5a  b7 bf 61 10 81 dc 92 23  |A...}h.Z..a....#|
+000002f0  d0 82 13 fb 71 6f 39 48  f9 87 f8 f7 a0 3a cd 18  |....qo9H.....:..|
+00000300  85 d7 4d 66 88 9d 39 8d  6d 53 a1 a3 0d 00 b0 0f  |..Mf..9.mS......|
+00000310  14 64 1b 72 2d 89 5c 93  6f 3c ed c9 82 20 3d 2f  |.d.r-.\.o<... =/|
+00000320  d0 7f 04 01 00 80 42 24  14 6e cf 78 ea 30 90 1e  |......B$.n.x.0..|
+00000330  4e 99 bf ca 98 9c 2f 24  98 c2 a2 b3 f8 34 49 22  |N...../$.....4I"|
+00000340  35 16 11 03 79 3b a8 10  a3 fa d8 5e 17 9d f9 50  |5...y;.....^...P|
+00000350  0a 3b 0b b5 b2 0f 90 18  c1 f5 6f 89 84 04 e2 f0  |.;........o.....|
+00000360  b0 04 2f 3e 78 d3 de 31  9e 6e 3b b8 c7 f5 cc 4f  |../>x..1.n;....O|
+00000370  4e ad fe 76 d2 6d 23 31  94 56 b1 d8 df 0d 9b c5  |N..v.m#1.V......|
+00000380  f7 9e 9c a7 2a 47 e4 c8  20 08 fc 6c d5 29 cd 36  |....*G.. ..l.).6|
+00000390  88 83 c5 59 33 6d 1f 0b  f9 98 65 fa cb f7 89 2d  |...Y3m....e....-|
+000003a0  90 3a 40 8a 31 7e 16 03  03 00 04 0e 00 00 00     |.:@.1~.........|
+>>> 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 fa e7  |.....(..........|
+00000060  ff 47 50 7a 68 0d 20 f6  9f 2a b5 bc f4 21 c1 72  |.GPzh. ..*...!.r|
+00000070  07 4c e5 07 2c 07 e5 1e  d7 fa 07 01 83 68        |.L..,........h|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 b7 93 18 5b 36  |..........(...[6|
+00000010  18 ce 97 17 75 40 15 17  1f 0e 0d 99 fd 66 fa 89  |....u at .......f..|
+00000020  db b7 97 95 a9 45 90 07  6e 82 0e 67 4f 01 58 ec  |.....E..n..gO.X.|
+00000030  94 d7 ad                                          |...|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 21 2b 7b  |.............!+{|
+00000010  62 ac e4 37 d6 77 19 89  77 1c 6a ce 40 c1 9d 71  |b..7.w..w.j. at ..q|
+00000020  5a 23 f0                                          |Z#.|
+>>> Flow 6 (server to client)
+00000000  16 03 03 00 1c b7 93 18  5b 36 18 ce 98 4a 49 69  |........[6...JIi|
+00000010  f4 dd 35 f2 93 3b c6 4e  d5 25 51 34 38 23 ea 74  |..5..;.N.%Q48#.t|
+00000020  84                                                |.|
+>>> Flow 7 (client to server)
+00000000  16 03 03 00 a9 00 00 00  00 00 00 00 02 65 09 7a  |.............e.z|
+00000010  d5 9b 32 0b cd 10 ea 2c  b6 d8 be ce db 3f a4 38  |..2....,.....?.8|
+00000020  a7 37 a3 95 ed 05 a7 c1  28 69 7a 13 50 07 ab 19  |.7......(iz.P...|
+00000030  52 d7 29 fe 49 80 f0 ef  ea 17 ac 20 f9 62 51 72  |R.).I...... .bQr|
+00000040  8d c0 17 62 03 cf bb 80  f8 6f 1b 74 f1 85 45 96  |...b.....o.t..E.|
+00000050  49 55 56 b0 7a dd 9b 5a  f1 3f 1a e7 96 cd 21 ec  |IUV.z..Z.?....!.|
+00000060  85 6f b9 9d 0f e3 f6 55  9b b8 a7 e1 77 ad 53 0b  |.o.....U....w.S.|
+00000070  98 90 ac 5d cf 31 0f 86  69 04 d8 e9 5e fc ea a8  |...].1..i...^...|
+00000080  a8 b7 a2 d8 0f ea 4f e5  ac f2 b2 c0 59 29 ba 53  |......O.....Y).S|
+00000090  af 1e 81 08 be 02 46 a7  b8 6f 2a b4 86 47 5d 8e  |......F..o*..G].|
+000000a0  72 a6 64 84 7e 76 31 9c  31 fb 59 b7 da 15        |r.d.~v1.1.Y...|
+>>> Flow 8 (server to client)
+00000000  16 03 03 00 89 b7 93 18  5b 36 18 ce 99 4a 72 26  |........[6...Jr&|
+00000010  ab cb a4 70 60 0f 7a 02  62 28 f3 10 54 77 a7 33  |...p`.z.b(..Tw.3|
+00000020  32 a6 29 c8 8d 18 48 8f  9d 45 6e 7e 06 07 ca b3  |2.)...H..En~....|
+00000030  b6 45 eb ac f2 41 f1 d9  19 9e 30 1f c0 18 40 1c  |.E...A....0... at .|
+00000040  55 09 4d f2 23 75 2f 2f  c8 b7 46 63 05 d1 73 c0  |U.M.#u//..Fc..s.|
+00000050  02 71 de 5e 4a 84 92 3d  9a b9 68 62 31 91 7d 23  |.q.^J..=..hb1.}#|
+00000060  43 e3 4b 00 98 2e 01 12  f4 1f fa 4c aa 91 a0 ca  |C.K........L....|
+00000070  9c a0 d9 6b 7f 5c b3 f4  8d e2 3a 54 eb e9 82 44  |...k.\....:T...D|
+00000080  21 54 ac 85 86 39 b8 df  23 64 2a 0c 3e 1d 16 03  |!T...9..#d*.>...|
+00000090  03 02 89 b7 93 18 5b 36  18 ce 9a 1c ae 99 12 58  |......[6.......X|
+000000a0  12 fa ef da 77 04 7f b5  42 68 b1 59 64 50 92 2b  |....w...Bh.YdP.+|
+000000b0  a0 21 b7 b3 4c f8 c2 cc  75 5a d0 85 50 95 f4 1b  |.!..L...uZ..P...|
+000000c0  c9 b2 1f 53 94 4c fd 6d  18 ad 1a 0d 24 9f fb 4c  |...S.L.m....$..L|
+000000d0  19 13 5a 74 f2 e2 59 dd  1b d8 67 bc d9 d0 da ab  |..Zt..Y...g.....|
+000000e0  a7 7f 8e ca e0 09 28 59  18 8d a1 8a c9 c3 2e 76  |......(Y.......v|
+000000f0  b9 0d 2f 56 5f c4 77 07  17 ac 62 26 a1 91 50 ee  |../V_.w...b&..P.|
+00000100  60 45 aa a0 8a d9 1a 13  65 68 c8 cf ca 0c 50 3e  |`E......eh....P>|
+00000110  9f 39 62 02 12 ea b4 ed  e2 6c 0e 28 32 d7 fb ec  |.9b......l.(2...|
+00000120  fc 6d e4 0a 14 1d 88 00  a8 c0 57 1e be 78 fd 18  |.m........W..x..|
+00000130  6e 40 70 37 2e f5 3b 52  59 03 02 bf 27 18 c8 00  |n at p7..;RY...'...|
+00000140  58 8f 5e d8 a8 7c 4c 54  83 4a fe f3 dc f8 19 2a  |X.^..|LT.J.....*|
+00000150  00 ed 96 93 0e e4 45 58  8f 41 99 0d 93 f5 6c a4  |......EX.A....l.|
+00000160  4e 62 f2 4b 9a cb 69 30  5a 4b 36 45 f2 d2 c1 62  |Nb.K..i0ZK6E...b|
+00000170  f9 1c c4 c3 b2 94 b3 17  1a ed d8 57 ba b7 79 a1  |...........W..y.|
+00000180  a2 2e 5a 18 79 36 0b 54  ee 2c 2c 3b 62 96 5d e5  |..Z.y6.T.,,;b.].|
+00000190  3c 74 0e be 52 6f 06 7c  93 05 86 0f d6 1d d0 ee  |<t..Ro.|........|
+000001a0  f9 ac 67 50 a6 d3 36 f7  5f 0b 3f 44 3b fc 4b 79  |..gP..6._.?D;.Ky|
+000001b0  b7 29 04 6c 37 18 2a 04  bf f4 3e 1a 53 f3 93 e5  |.).l7.*...>.S...|
+000001c0  f2 b7 b1 4b ed 19 5a 2f  40 d1 f2 91 49 0b 8b f6  |...K..Z/@...I...|
+000001d0  21 0b 20 01 ce 0f a8 f1  44 3f 5e b1 89 1a 15 9f  |!. .....D?^.....|
+000001e0  4c c5 93 6b 68 93 ab 67  b5 1d 10 fa 22 53 e3 0f  |L..kh..g...."S..|
+000001f0  c7 63 d0 32 b7 52 c6 2e  b7 47 a4 1a b4 ab 35 a9  |.c.2.R...G....5.|
+00000200  b0 0e cd f6 8c e7 54 6c  77 7b 5c 6c c2 b3 02 89  |......Tlw{\l....|
+00000210  74 f7 b1 61 91 dc 01 3a  68 d9 81 78 21 95 b1 67  |t..a...:h..x!..g|
+00000220  36 2d 2a d6 c4 96 0d 7b  e0 44 83 cd 52 e4 05 36  |6-*....{.D..R..6|
+00000230  a4 1d 2a 24 e8 cc 76 d7  66 2f 32 ef 8f 70 ef 26  |..*$..v.f/2..p.&|
+00000240  90 73 2e e6 b4 53 91 13  5b 5e 15 51 15 56 e9 43  |.s...S..[^.Q.V.C|
+00000250  22 9a b6 55 3d 94 00 35  73 41 12 fc 8a 0b fd 89  |"..U=..5sA......|
+00000260  7c 00 14 0d b8 f6 76 d0  ac 33 1d e4 73 49 e9 a2  ||.....v..3..sI..|
+00000270  09 69 e1 f1 a7 92 48 ee  2e fc ef 13 09 7c a7 72  |.i....H......|.r|
+00000280  eb 4c 15 39 17 6e cd 71  c0 e9 48 06 43 09 19 39  |.L.9.n.q..H.C..9|
+00000290  72 b0 9c f8 0e 75 af a8  eb 25 96 36 75 68 16 8f  |r....u...%.6uh..|
+000002a0  e8 f6 66 56 66 63 b0 52  47 74 55 af c8 7a 07 dc  |..fVfc.RGtU..z..|
+000002b0  d0 8b bf 51 6e bc 77 fa  8a 03 43 0c 5a 47 fb c7  |...Qn.w...C.ZG..|
+000002c0  be b3 ef b5 ad 24 48 40  6c 4b 03 41 dd 7c 3e 6e  |.....$H at lK.A.|>n|
+000002d0  25 01 4b 45 ce ad d7 23  3a 6c 33 0b f1 7a 44 07  |%.KE...#:l3..zD.|
+000002e0  7e c8 bd 52 a5 a8 30 91  95 3e 4d 42 07 67 57 fb  |~..R..0..>MB.gW.|
+000002f0  c0 4a ed 9f 76 21 8e df  fb f6 a4 0a 08 1e 5b c6  |.J..v!........[.|
+00000300  3e a3 8c 47 a4 4d 41 2b  e6 8f 42 43 cd ef a8 f1  |>..G.MA+..BC....|
+00000310  88 f2 b3 46 eb 8a 24 a3  98 a2 d7 d2 16 03 03 00  |...F..$.........|
+00000320  e5 b7 93 18 5b 36 18 ce  9b 62 57 ae 22 62 34 88  |....[6...bW."b4.|
+00000330  41 e1 7e 2a 4a 07 b4 b8  aa 80 32 f5 93 4c 58 79  |A.~*J.....2..LXy|
+00000340  82 51 d4 b8 c8 5b d2 99  a3 18 43 aa c2 14 bf 65  |.Q...[....C....e|
+00000350  e8 90 8d 46 69 d5 fa 34  e4 1a 47 06 dc 1a ae e9  |...Fi..4..G.....|
+00000360  40 b2 2e 7e 5e 74 f7 72  4d a9 e2 b7 52 b4 bb dc  |@..~^t.rM...R...|
+00000370  06 e6 50 7e ef 42 8f 72  08 63 f9 ec 9e 13 36 0f  |..P~.B.r.c....6.|
+00000380  d4 95 72 2b ff a5 6d 4b  1b db d6 b3 25 50 f0 dd  |..r+..mK....%P..|
+00000390  e3 89 f5 c1 c0 3f aa 6c  f0 a7 30 5d 56 76 77 b6  |.....?.l..0]Vvw.|
+000003a0  24 8f 93 fd 49 8c 73 1e  f7 5c 5c 3a f3 0d 5e 89  |$...I.s..\\:..^.|
+000003b0  a4 bb 48 8a 82 ed 01 a6  2d eb b1 fe d2 6e 4e 88  |..H.....-....nN.|
+000003c0  1d 06 b6 f5 d8 41 86 40  fe 45 3e ef 35 9b 88 df  |.....A. at .E>.5...|
+000003d0  48 af e0 05 33 4e 13 15  8b b6 5a 8e 5c f8 2a 59  |H...3N....Z.\.*Y|
+000003e0  14 6d 4a 79 75 48 e4 9d  16 4f 6f 65 9c c3 40 1e  |.mJyuH...Ooe.. at .|
+000003f0  7c 72 60 ce b9 f8 61 3b  ff 34 81 94 01 aa b3 59  ||r`...a;.4.....Y|
+00000400  72 d2 1e 5f fe 7f 16 03  03 00 46 b7 93 18 5b 36  |r.._......F...[6|
+00000410  18 ce 9c c8 c9 b2 10 f1  39 bb f0 80 a9 0b 68 76  |........9.....hv|
+00000420  2b 60 0b c5 f3 eb 16 72  b5 4c c9 42 96 39 bf c1  |+`.....r.L.B.9..|
+00000430  94 87 f0 47 80 34 11 e2  1c 4c fc 26 d6 4b 00 49  |...G.4...L.&.K.I|
+00000440  ef 73 00 4e ab 61 d6 1f  89 2c 7e f2 5c ea 6b 5c  |.s.N.a...,~.\.k\|
+00000450  50                                                |P|
+>>> Flow 9 (client to server)
+00000000  16 03 03 02 89 00 00 00  00 00 00 00 03 c2 d4 9b  |................|
+00000010  19 c8 b6 76 fb ef e4 b2  f7 97 c7 80 f5 e2 b4 3c  |...v...........<|
+00000020  bd b7 b8 25 da 54 52 a7  f8 38 0d 48 c0 13 19 82  |...%.TR..8.H....|
+00000030  17 3c ff d2 c0 8f bd 76  5d 16 39 db a7 51 3f b1  |.<.....v].9..Q?.|
+00000040  72 b6 59 e4 8c 6c f5 33  de 78 15 8d 64 cf 55 c6  |r.Y..l.3.x..d.U.|
+00000050  47 e3 0b 30 06 e1 6c 2d  e1 e0 7a e1 0a da dd 0d  |G..0..l-..z.....|
+00000060  60 5b 06 28 a8 94 14 a3  cc 91 96 8d 2b 71 af ff  |`[.(........+q..|
+00000070  c2 32 e2 19 77 96 f3 5b  53 3a d3 29 51 c2 54 98  |.2..w..[S:.)Q.T.|
+00000080  f3 00 8e 9a fe ef bb ea  06 27 58 54 3c c8 67 dc  |.........'XT<.g.|
+00000090  f3 41 01 77 de 25 b4 54  53 67 64 41 b3 ae 2b c2  |.A.w.%.TSgdA..+.|
+000000a0  57 cd 74 14 3c 46 a7 70  ec a8 bc 0e 05 46 ce fc  |W.t.<F.p.....F..|
+000000b0  c8 54 4d 23 25 b9 e0 45  fa 1e 1b 2c f1 d0 da 66  |.TM#%..E...,...f|
+000000c0  3c 00 e5 b3 f5 f9 ff 64  75 82 f9 dd c2 3f 42 46  |<......du....?BF|
+000000d0  27 ca 72 a2 f7 6c 4e bf  98 05 e6 99 b5 7b 60 33  |'.r..lN......{`3|
+000000e0  99 e8 7a 7c 91 41 64 cd  96 60 f2 f6 c8 bd 4f 35  |..z|.Ad..`....O5|
+000000f0  5f 6f 43 11 b0 94 3c 98  bc 58 15 7e 52 01 ba cf  |_oC...<..X.~R...|
+00000100  71 f4 0a fb 85 0a 24 13  0c 4a 53 55 77 92 91 cd  |q.....$..JSUw...|
+00000110  ce 39 7e 07 2f 4f ba 47  ca bd 67 5b ce 5a 04 03  |.9~./O.G..g[.Z..|
+00000120  ff 86 0a 82 80 b9 42 b8  4c e3 ce 73 b2 4a 5a 4b  |......B.L..s.JZK|
+00000130  f5 f2 44 d8 e5 01 30 c8  2e ce 4f 62 2d 34 9c d6  |..D...0...Ob-4..|
+00000140  57 20 db 37 20 66 03 b6  4d a7 0f 75 30 d8 ad 2f  |W .7 f..M..u0../|
+00000150  63 f7 4e 24 ec 68 e0 a2  a9 b1 3d 68 e5 c1 8b d8  |c.N$.h....=h....|
+00000160  19 dd 40 33 c6 5c 57 3b  22 5a 9c 24 fe 2f 92 54  |.. at 3.\W;"Z.$./.T|
+00000170  0f e8 85 74 06 72 59 ab  1d b8 5d 31 91 ed 05 51  |...t.rY...]1...Q|
+00000180  61 c6 43 3d 81 f4 47 c3  80 17 4d 1b 08 c4 85 1b  |a.C=..G...M.....|
+00000190  b7 37 b0 cf 5c 73 5f 56  0f 5a b5 21 21 46 e3 df  |.7..\s_V.Z.!!F..|
+000001a0  e6 cb 9d ac ab 16 c0 b1  b8 2a 4a 5b a7 2d 7a 00  |.........*J[.-z.|
+000001b0  9f 9d 76 57 ab 20 ea 80  8a 7a ca 14 45 d7 4e 1b  |..vW. ...z..E.N.|
+000001c0  c8 7c b8 c6 82 fc 40 b2  b4 7d f1 74 7d b5 2a 90  |.|.... at ..}.t}.*.|
+000001d0  01 83 d4 d1 26 63 d7 39  69 b1 33 5f 7e 54 de f7  |....&c.9i.3_~T..|
+000001e0  08 3d 62 3b da 57 0d d4  48 99 9a 3e 99 e5 b0 6b  |.=b;.W..H..>...k|
+000001f0  25 45 38 36 aa 7a bb 81  7d 0b dd 1d 50 c4 17 68  |%E86.z..}...P..h|
+00000200  4b a7 f7 2f d8 cd 97 a6  ea 24 9b 34 69 9e 7d ad  |K../.....$.4i.}.|
+00000210  6a 17 23 d8 36 61 cf 85  74 47 18 5b fd cd 72 ac  |j.#.6a..tG.[..r.|
+00000220  c2 a2 b4 53 e3 5d 25 f7  bb b6 95 99 a0 e5 05 38  |...S.]%........8|
+00000230  0a 52 32 f6 7d a6 30 5c  11 6b 8a 7b af ec a2 9b  |.R2.}.0\.k.{....|
+00000240  b8 f1 85 6d a8 b7 79 61  42 60 4a 35 73 fb d5 2c  |...m..yaB`J5s..,|
+00000250  1f 84 5c d9 c9 23 10 e8  a4 2c 56 fd f4 22 1a 7a  |..\..#...,V..".z|
+00000260  f3 b2 c5 69 8b c9 d1 d5  45 c8 65 59 fc ab d9 d3  |...i....E.eY....|
+00000270  7d ab c3 fe bc da 6d a3  cd 0c 83 32 70 65 c7 7f  |}.....m....2pe..|
+00000280  8c 83 c8 97 3e 7f 89 fc  11 7d 1c a5 fd 99 16 03  |....>....}......|
+00000290  03 00 5e 00 00 00 00 00  00 00 04 64 60 91 c0 fd  |..^........d`...|
+000002a0  3a 96 5a ac 5a 13 a9 9a  41 eb a0 6d 51 98 ee a8  |:.Z.Z...A..mQ...|
+000002b0  4d ee 90 c9 3e a5 15 ac  f3 6a c8 56 f3 20 c3 10  |M...>....j.V. ..|
+000002c0  e3 3a d1 ea b0 7d a7 21  ae 2c b1 fa 5c b8 c1 fa  |.:...}.!.,..\...|
+000002d0  d7 97 6e ea fd 09 53 46  db aa e4 39 31 00 c2 bb  |..n...SF...91...|
+000002e0  ad 36 10 cd e9 cb 46 31  7b 66 ee ce 0c a8 f9 c2  |.6....F1{f......|
+000002f0  0a 16 03 03 00 a0 00 00  00 00 00 00 00 05 6d a0  |..............m.|
+00000300  03 60 12 bb 06 89 0c 03  ad f7 36 f3 5c e4 c1 65  |.`........6.\..e|
+00000310  b2 26 c9 f5 87 85 f9 8f  2d 05 43 35 32 d7 0a a0  |.&......-.C52...|
+00000320  e5 16 7a 94 62 15 ed cc  8e 9f e3 10 8d e7 83 a2  |..z.b...........|
+00000330  ea e4 07 49 c9 df 1d 2b  6f b8 0f 67 31 22 44 9b  |...I...+o..g1"D.|
+00000340  65 77 99 78 f9 3e 14 67  3a 90 e5 5a c2 b5 1b ee  |ew.x.>.g:..Z....|
+00000350  db 20 73 8d 85 22 4d 79  6e e9 17 d0 b1 03 58 f3  |. s.."Myn.....X.|
+00000360  cf 1b f5 03 9a 75 1f 7a  3b 49 ee 67 04 da c4 fc  |.....u.z;I.g....|
+00000370  7a 62 a9 ff 26 4f 71 b2  7e e9 c7 78 96 74 1e 63  |zb..&Oq.~..x.t.c|
+00000380  eb 2b 2f 18 1f 19 cf 1e  89 73 39 9e f6 02 3d 31  |.+/......s9...=1|
+00000390  50 65 1f 80 19 26 14 03  03 00 19 00 00 00 00 00  |Pe...&..........|
+000003a0  00 00 06 82 62 df fd 51  9e be 21 0b 22 b6 c1 6d  |....b..Q..!."..m|
+000003b0  5c 90 ea c5 16 03 03 00  28 00 00 00 00 00 00 00  |\.......(.......|
+000003c0  00 d6 5f a7 05 2b 99 cc  7d fb d7 38 5e e3 31 a7  |.._..+..}..8^.1.|
+000003d0  c9 1c bd 7b c7 89 d0 e5  b5 93 78 d1 63 57 d2 76  |...{......x.cW.v|
+000003e0  38                                                |8|
+>>> Flow 10 (server to client)
+00000000  14 03 03 00 19 b7 93 18  5b 36 18 ce 9d 68 22 e1  |........[6...h".|
+00000010  d0 06 aa e5 87 f8 49 bc  38 d7 b9 38 85 97 16 03  |......I.8..8....|
+00000020  03 00 28 24 71 bf 67 14  d6 5e 29 1b de e6 f4 e0  |..($q.g..^).....|
+00000030  33 76 dc 66 c6 95 c0 3a  15 49 99 09 2f cf 6b 6b  |3v.f...:.I../.kk|
+00000040  a1 8f 1a e4 af 8d 1e 7f  02 b1 87 17 03 03 00 21  |...............!|
+00000050  24 71 bf 67 14 d6 5e 2a  61 7b 98 dd e8 52 b0 1e  |$q.g..^*a{...R..|
+00000060  28 46 28 de e2 22 65 6c  66 85 3a 1d bb 9e 76 a2  |(F(.."elf.:...v.|
+00000070  55 16 03 03 00 1c 24 71  bf 67 14 d6 5e 2b bb 84  |U.....$q.g..^+..|
+00000080  6d f0 1c d0 46 89 bb b2  09 96 dd 95 53 bf ac d7  |m...F.......S...|
+00000090  80 f1                                             |..|
+>>> Flow 11 (client to server)
+00000000  16 03 03 00 a9 00 00 00  00 00 00 00 01 61 12 ee  |.............a..|
+00000010  0a f2 5e e2 3d 3d 36 4c  14 10 20 aa 4d 8a 91 e4  |..^.==6L.. .M...|
+00000020  c2 b0 63 68 9e f5 71 b7  a4 ee 75 27 20 8c 2e 21  |..ch..q...u' ..!|
+00000030  f5 57 3d e9 9a 05 da 7b  a5 af 6a 17 10 8b eb 25  |.W=....{..j....%|
+00000040  8a 79 75 07 dc fe f5 7f  a5 e2 63 31 ee 55 ba c0  |.yu.......c1.U..|
+00000050  e6 3d de 03 36 2b 64 19  b1 1a b8 80 09 25 8c dd  |.=..6+d......%..|
+00000060  dd 59 c7 1d e7 40 20 ae  ca a9 b5 14 a7 57 f0 62  |.Y...@ ......W.b|
+00000070  71 88 a3 2c fc a4 50 dc  8b 85 22 20 38 c5 74 ea  |q..,..P..." 8.t.|
+00000080  ac 33 1d a3 c5 5c cc 10  62 fd c5 70 22 fa e3 73  |.3...\..b..p"..s|
+00000090  f3 bf 24 14 0d cb 7c 25  e4 74 6c fe c0 70 5e a0  |..$...|%.tl..p^.|
+000000a0  63 a7 e5 f2 6e d8 71 bd  7d b9 f0 b6 0b 70        |c...n.q.}....p|
+>>> Flow 12 (server to client)
+00000000  16 03 03 00 89 24 71 bf  67 14 d6 5e 2c 55 62 31  |.....$q.g..^,Ub1|
+00000010  5c a3 53 1a c3 2f 89 47  62 33 7e 24 cd ad a9 5b  |\.S../.Gb3~$...[|
+00000020  51 79 d8 08 08 ff 09 3c  41 c7 80 ed ec 5a 7a e4  |Qy.....<A....Zz.|
+00000030  71 e1 17 91 5e c1 80 58  35 c7 27 ca 62 74 cc d8  |q...^..X5.'.bt..|
+00000040  e8 35 86 97 bf 05 73 b9  3f ae 5b af 9a 14 88 4b  |.5....s.?.[....K|
+00000050  f9 6f a4 de 3d 45 c8 7b  0a b1 7a 81 3e 7c 02 b5  |.o..=E.{..z.>|..|
+00000060  e9 43 a5 64 88 59 f6 55  20 d1 09 39 cd 01 46 0f  |.C.d.Y.U ..9..F.|
+00000070  a2 06 f3 2b 45 14 b2 57  21 2c 2f a0 e5 db 02 99  |...+E..W!,/.....|
+00000080  e4 6b 1e 22 99 c9 ae 93  e4 67 89 d1 c6 6d 16 03  |.k.".....g...m..|
+00000090  03 02 89 24 71 bf 67 14  d6 5e 2d ce 6a 42 6b ce  |...$q.g..^-.jBk.|
+000000a0  07 4e ff 40 39 4b 00 c8  14 4c 76 e0 4d 09 41 c3  |.N. at 9K...Lv.M.A.|
+000000b0  41 3a ca ac 28 06 01 80  e4 b8 73 a2 fc ea 8d 92  |A:..(.....s.....|
+000000c0  44 0e 43 3e d8 cb 8a 0c  a0 c1 5e 88 6d 6d 80 be  |D.C>......^.mm..|
+000000d0  9c 9f cc 20 7c fa 6f e4  1a a1 39 c2 a8 7d 04 85  |... |.o...9..}..|
+000000e0  75 5d c4 d3 6f df d7 3a  9d 83 c3 74 aa 49 df 34  |u]..o..:...t.I.4|
+000000f0  e0 41 ad a3 80 80 c3 29  44 b9 5f a1 7b 67 89 30  |.A.....)D._.{g.0|
+00000100  04 b0 90 78 6b 82 fe ae  0c eb e1 5a 64 e2 6f de  |...xk......Zd.o.|
+00000110  de 12 db 4f 1f eb 1d a9  66 a1 62 11 ab 54 1f 5d  |...O....f.b..T.]|
+00000120  c2 ce 1e a8 b3 8b 29 08  76 13 a0 67 5b e6 1b 2c  |......).v..g[..,|
+00000130  bd 1b 42 80 a5 09 b0 03  28 df 77 6f a7 d5 2f 85  |..B.....(.wo../.|
+00000140  2b b1 69 81 5c a0 16 16  1c eb b4 61 f1 f7 70 55  |+.i.\......a..pU|
+00000150  ee 64 9d 8f 1a 0b af af  18 f5 da e6 32 ab b2 28  |.d..........2..(|
+00000160  0d a0 ea b4 44 3d a9 f7  1a 84 c1 8f 30 09 41 13  |....D=......0.A.|
+00000170  a3 34 79 a7 6f da 76 59  62 9f d6 82 0f 48 21 64  |.4y.o.vYb....H!d|
+00000180  11 49 53 cd 3a 44 5a dc  8b 97 8a 84 d2 f9 12 77  |.IS.:DZ........w|
+00000190  b3 5b b0 37 58 7a a3 5a  47 9d c7 e4 83 f5 0a 32  |.[.7Xz.ZG......2|
+000001a0  10 39 aa d6 7c 8e 44 eb  a9 fd 0f c0 6a 80 82 21  |.9..|.D.....j..!|
+000001b0  30 d1 36 31 73 38 c5 bd  16 99 71 b5 49 8e 7f df  |0.61s8....q.I...|
+000001c0  f9 64 7f ff 16 3b 68 7c  b5 7c 1f 41 19 36 dd ef  |.d...;h|.|.A.6..|
+000001d0  65 11 b9 91 c4 d4 40 eb  37 94 69 8b 3b 10 56 45  |e..... at .7.i.;.VE|
+000001e0  ee 56 a8 a7 3d 94 17 5c  fe f2 88 c7 fb 78 8e 51  |.V..=..\.....x.Q|
+000001f0  53 a8 bc b3 88 ee 75 42  1d 41 b8 c5 34 d5 9e bc  |S.....uB.A..4...|
+00000200  b4 b7 1c 97 8b 83 d6 3d  97 4b 43 7a 40 3d 63 6e  |.......=.KCz@=cn|
+00000210  cf 57 9a d3 71 6d 54 fe  38 ec 6f d7 c3 aa 1c a8  |.W..qmT.8.o.....|
+00000220  2b f6 34 96 cb 16 da 3e  2d 74 dd f6 1c 33 3c 4e  |+.4....>-t...3<N|
+00000230  25 d9 e3 c5 85 52 c3 ea  22 ea 86 16 84 31 05 a4  |%....R.."....1..|
+00000240  7d 41 00 bd 4a b3 79 93  18 1c a1 e4 78 1c 90 49  |}A..J.y.....x..I|
+00000250  b4 9f bc d3 2d d0 f9 46  da 13 7c f6 88 5e e1 b2  |....-..F..|..^..|
+00000260  5c 41 12 bf 2f 1f b4 c3  13 8c 2f a6 83 c5 86 ba  |\A../...../.....|
+00000270  20 42 21 57 e1 78 82 0e  4b 55 32 c1 f2 6e 4c a2  | B!W.x..KU2..nL.|
+00000280  a7 c7 63 b3 b5 30 49 9d  7a 51 5e 67 38 52 89 ee  |..c..0I.zQ^g8R..|
+00000290  51 16 34 5c f6 b1 04 30  7b f4 b0 f8 88 6c 9d bc  |Q.4\...0{....l..|
+000002a0  32 5d 8b 73 b0 df f6 a2  dd e7 62 94 d7 b7 68 92  |2].s......b...h.|
+000002b0  d6 a6 6a b2 53 75 d8 a7  43 1f 1e a2 c0 4e 6a 84  |..j.Su..C....Nj.|
+000002c0  e7 6d ae 81 82 dc 43 bd  8c 44 6a db ec 37 34 70  |.m....C..Dj..74p|
+000002d0  a0 e3 39 a1 17 d2 b7 53  bc 06 0e 33 3f 91 b3 a6  |..9....S...3?...|
+000002e0  0a d1 43 b0 94 54 bc b9  07 52 40 6e 49 99 ab 09  |..C..T...R at nI...|
+000002f0  3f dc 5d 5f c9 33 59 03  3f cf 7b 47 54 2d 05 4b  |?.]_.3Y.?.{GT-.K|
+00000300  c2 e6 81 f5 2f 58 5d 84  ad 9d 72 cc 3b 09 70 50  |..../X]...r.;.pP|
+00000310  75 f8 c8 b7 9a 3f b7 3e  aa 6a 75 5d 16 03 03 00  |u....?.>.ju]....|
+00000320  e5 24 71 bf 67 14 d6 5e  2e 0b f5 20 45 e5 51 07  |.$q.g..^... E.Q.|
+00000330  98 f0 75 3c 5c f3 16 88  ba e7 76 fe 10 18 41 38  |..u<\.....v...A8|
+00000340  d5 df 7f 8b d3 2e 1c 0a  4c 83 57 fc e5 63 35 68  |........L.W..c5h|
+00000350  6e 23 5b c3 0c 9d f9 ab  f8 3c 86 b6 ec 54 ec 52  |n#[......<...T.R|
+00000360  a4 45 cf 7b 31 a7 04 ef  5b 0b b1 11 50 8c 95 25  |.E.{1...[...P..%|
+00000370  9a 17 9b 4d 65 9c 0b d3  bb 0d 98 10 d9 34 52 7a  |...Me........4Rz|
+00000380  f8 1e 9e 78 cb 41 27 47  31 cb 25 42 90 e9 3c 02  |...x.A'G1.%B..<.|
+00000390  49 17 01 5f 06 d2 f4 58  35 75 d5 9d 54 65 15 0d  |I.._...X5u..Te..|
+000003a0  02 7e 94 fd c8 ac b8 c4  97 1c 9a 1c 9a 23 d5 d3  |.~...........#..|
+000003b0  44 c6 9a dd f9 b4 d1 48  e9 3d a0 5b d4 66 b3 d9  |D......H.=.[.f..|
+000003c0  11 0c d5 6d 0e 06 9c 00  90 30 d7 97 06 dc 0e e2  |...m.....0......|
+000003d0  59 51 7f b5 2e b8 f7 eb  be 66 56 fa 9d a4 92 db  |YQ.......fV.....|
+000003e0  82 3a d9 fc bd da c5 23  f6 2c 7b 36 2f a8 57 8e  |.:.....#.,{6/.W.|
+000003f0  c6 0a 48 50 e3 f4 e7 07  95 48 9b 45 a9 ba cb e0  |..HP.....H.E....|
+00000400  3e ee 10 f9 0e cc 16 03  03 00 46 24 71 bf 67 14  |>.........F$q.g.|
+00000410  d6 5e 2f 97 87 ae b8 b4  fb f1 67 2b e7 0f f4 be  |.^/.......g+....|
+00000420  24 0a f8 4a c0 42 4b 40  d3 ea e7 e0 f7 2a 9b 80  |$..J.BK at .....*..|
+00000430  bb 62 c0 2d d5 f8 52 19  49 d4 4c 45 1d c2 28 e7  |.b.-..R.I.LE..(.|
+00000440  8f fd b2 47 0e 22 d1 e1  b1 33 c1 26 6a fd 3f 9f  |...G."...3.&j.?.|
+00000450  d8                                                |.|
+>>> Flow 13 (client to server)
+00000000  16 03 03 02 89 00 00 00  00 00 00 00 02 32 20 c7  |.............2 .|
+00000010  66 2d 3f e5 9b f9 e0 1c  7c 1f 3e 21 d9 51 af 9a  |f-?.....|.>!.Q..|
+00000020  60 65 99 c7 3e 0b 48 f2  a3 8f eb ea 75 da af 60  |`e..>.H.....u..`|
+00000030  2e 5b ac 7f 9f d1 1f 69  86 18 49 3b 18 a2 e5 c5  |.[.....i..I;....|
+00000040  d0 c7 fe 3e c6 15 3d 5d  04 4d aa 7e 28 e3 20 d3  |...>..=].M.~(. .|
+00000050  55 c2 ed 4f 61 5f cc f9  39 5f 7d 3a 0f f2 81 5d  |U..Oa_..9_}:...]|
+00000060  fd 4e 86 92 12 cd 2b b7  e6 46 49 b7 b8 5f 8f e5  |.N....+..FI.._..|
+00000070  b7 5e 64 2f 13 33 65 1c  c8 c4 38 bd 70 94 23 e9  |.^d/.3e...8.p.#.|
+00000080  b6 57 81 c8 23 d1 57 85  91 c5 bc 5b 33 55 eb f5  |.W..#.W....[3U..|
+00000090  2d b3 76 53 44 e2 e8 66  fe 42 de f8 6f 03 37 d4  |-.vSD..f.B..o.7.|
+000000a0  a0 a4 75 7a 03 7f 00 92  eb 45 2f b8 5d 01 d3 4b  |..uz.....E/.]..K|
+000000b0  e7 ca 2f 5b 3b 20 67 dc  32 2a 4c 06 1b 03 97 c1  |../[; g.2*L.....|
+000000c0  38 40 35 79 31 25 b0 fe  d8 f3 b7 ee 6c ad 62 3e  |8 at 5y1%......l.b>|
+000000d0  60 d6 96 6a 10 2b 14 8a  9e 72 f4 c9 63 6a 63 14  |`..j.+...r..cjc.|
+000000e0  d1 b0 e4 1f e9 3d 85 9d  ed 11 3f 85 eb fa ca 46  |.....=....?....F|
+000000f0  17 f8 45 d5 65 28 79 8d  63 8e d7 22 40 9f c7 25  |..E.e(y.c.."@..%|
+00000100  ae e0 72 9f 60 70 95 59  99 25 41 1a e6 e9 45 cb  |..r.`p.Y.%A...E.|
+00000110  3d 5a 2e 2d 4d c2 3c f2  3a 01 61 1f 96 d7 78 1a  |=Z.-M.<.:.a...x.|
+00000120  cd 14 bd 87 75 23 10 7f  67 e4 8e fa 0a 9d 5d e9  |....u#..g.....].|
+00000130  12 f8 c7 35 c1 37 4c a4  91 a1 a5 de 79 9a a7 9c  |...5.7L.....y...|
+00000140  ce d2 c9 72 a8 fa a3 27  24 8d 14 4e d7 11 f3 e9  |...r...'$..N....|
+00000150  07 4d 6d 47 92 4d e2 75  9a 71 d0 1e dd 09 61 0e  |.MmG.M.u.q....a.|
+00000160  16 36 84 3a b1 dd 9b f8  09 dd 73 78 ed f7 29 4e  |.6.:......sx..)N|
+00000170  a6 29 b0 31 54 72 ac 4b  7a 49 13 ba 9b ef b6 8b  |.).1Tr.KzI......|
+00000180  48 dd a1 a7 9d 25 0e b7  37 42 5f 70 27 a7 59 40  |H....%..7B_p'.Y@|
+00000190  fe 72 1a 23 3e 71 b7 56  ef ff 02 c0 c9 07 99 20  |.r.#>q.V....... |
+000001a0  19 d2 9e 65 a5 5e f1 15  d3 ec 6e bb b1 c4 bf c0  |...e.^....n.....|
+000001b0  f8 71 19 bc 77 30 93 72  33 eb 1b c0 62 07 5e ca  |.q..w0.r3...b.^.|
+000001c0  4a bf 89 5d 5d 44 23 fb  58 8e 71 b4 58 41 b9 97  |J..]]D#.X.q.XA..|
+000001d0  8b da b6 a0 b6 40 54 46  01 b9 47 79 21 bc 7c f3  |..... at TF..Gy!.|.|
+000001e0  4c 46 a3 92 ce d6 ec ac  3b 5d 6f 19 65 d1 b0 cd  |LF......;]o.e...|
+000001f0  19 cd 2e 9d 6e 7d d3 57  44 c2 dd c6 56 dd e6 2b  |....n}.WD...V..+|
+00000200  06 c6 f1 46 f1 ba ce e6  d9 c8 1e 03 5d b5 15 37  |...F........]..7|
+00000210  9d 8a d2 01 e7 28 33 30  a2 2b a3 42 d1 05 2f e9  |.....(30.+.B../.|
+00000220  7f 50 bf c8 7f 7b f8 c7  7e 12 3f 97 5e d5 1c 34  |.P...{..~.?.^..4|
+00000230  eb bf 2e c2 f0 6b 36 4e  09 c9 73 0e bb 3a cd f8  |.....k6N..s..:..|
+00000240  5f 2a 13 4d f2 92 b3 ae  4f dd 0e 82 a0 58 a9 be  |_*.M....O....X..|
+00000250  2f c1 20 5c 64 48 11 e3  66 18 22 4d ea aa 76 21  |/. \dH..f."M..v!|
+00000260  07 ac 5a f2 14 38 a7 d8  9a 58 f8 92 62 77 3c 59  |..Z..8...X..bw<Y|
+00000270  1a 31 4e 3f 56 55 2b 9f  87 96 9c 7e c5 f0 10 fa  |.1N?VU+....~....|
+00000280  90 a1 0b 9e e4 66 74 99  80 da 58 85 3d bd 16 03  |.....ft...X.=...|
+00000290  03 00 5e 00 00 00 00 00  00 00 03 42 d9 1d 19 27  |..^........B...'|
+000002a0  98 c0 29 9e bc 35 99 e9  e9 de f5 7c b7 2f ce a1  |..)..5.....|./..|
+000002b0  48 fe a9 79 26 c3 f1 74  63 73 3b 8d b7 4c 47 11  |H..y&..tcs;..LG.|
+000002c0  7c ea 6d 09 4c 1c 10 1d  c9 b4 63 d4 5e c4 f1 34  ||.m.L.....c.^..4|
+000002d0  94 63 1c 04 a1 5f d0 65  7c b6 dd 2b a3 1c 1b 5f  |.c..._.e|..+..._|
+000002e0  5c d6 dc 7f e7 df c4 75  ad df cc ae 71 47 64 cc  |\......u....qGd.|
+000002f0  96 16 03 03 00 a0 00 00  00 00 00 00 00 04 61 37  |..............a7|
+00000300  a3 98 54 d1 7c 5d 14 b9  04 72 6e 02 ab 1a 15 2c  |..T.|]...rn....,|
+00000310  93 07 15 ab 56 b1 ac d5  75 75 2e 25 ae 5e 3f fa  |....V...uu.%.^?.|
+00000320  d0 20 ff 9d e0 ef fd 25  ed 4d 60 56 c7 33 07 d0  |. .....%.M`V.3..|
+00000330  57 09 e4 12 bd aa f0 d2  cc de 0d 45 23 ab b6 67  |W..........E#..g|
+00000340  ea d3 bc e1 4d 3a 75 9f  2d bb 53 b4 70 67 ce 63  |....M:u.-.S.pg.c|
+00000350  83 29 fa 27 2b db ea a3  19 be 79 77 cd 75 fb bf  |.).'+.....yw.u..|
+00000360  c1 27 86 a6 a9 27 06 49  e1 77 13 0d e4 78 0c 07  |.'...'.I.w...x..|
+00000370  d4 1c af 76 f4 7b 05 04  5f 0f ec 66 f9 03 3e 81  |...v.{.._..f..>.|
+00000380  41 be 24 5f 43 2a 99 56  06 a9 d7 be ca 62 46 a2  |A.$_C*.V.....bF.|
+00000390  ba e1 a6 8b 1b 0a 14 03  03 00 19 00 00 00 00 00  |................|
+000003a0  00 00 05 f9 8f d4 80 bf  ed b3 38 3a 12 d9 91 b6  |..........8:....|
+000003b0  cf 87 1a 1b 16 03 03 00  28 00 00 00 00 00 00 00  |........(.......|
+000003c0  00 fb 80 da 9a 59 82 9d  d2 35 57 57 dd 76 a1 b1  |.....Y...5WW.v..|
+000003d0  4a dc a5 cb f6 81 3f e3  4d cc 0e 7f 3a 96 85 f3  |J.....?.M...:...|
+000003e0  ea                                                |.|
+>>> Flow 14 (server to client)
+00000000  14 03 03 00 19 24 71 bf  67 14 d6 5e 30 cc 1c 3f  |.....$q.g..^0..?|
+00000010  3c 20 07 b3 c3 79 d0 6e  fd 59 e6 0d 47 fd 16 03  |< ...y.n.Y..G...|
+00000020  03 00 28 54 db a5 f7 3d  b3 18 49 39 e5 59 93 bb  |..(T...=..I9.Y..|
+00000030  64 93 1c ed 46 d6 f8 89  94 45 ba 4a 9e 73 2e cb  |d...F....E.J.s..|
+00000040  03 18 e4 26 6d 33 e3 34  73 d6 fc 17 03 03 00 21  |...&m3.4s......!|
+00000050  54 db a5 f7 3d b3 18 4a  aa 45 38 3b 50 02 44 37  |T...=..J.E8;P.D7|
+00000060  6a d1 3e f9 d3 3b 33 33  d5 84 2d 52 33 7d 68 84  |j.>..;33..-R3}h.|
+00000070  ef                                                |.|
+>>> Flow 15 (client to server)
+00000000  15 03 03 00 1a 00 00 00  00 00 00 00 01 55 5f 94  |.............U_.|
+00000010  25 d0 89 86 cb 8f 33 6f  b7 b6 35 ec 0f 6a 87     |%.....3o..5..j.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected
new file mode 100644
index 0000000..fe2fa88
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected
@@ -0,0 +1,255 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 85 01 00 00  81 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 22 c0 2f  |............."./|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+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 12  00 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 51 0e b9 8f 73  |....Y...U..Q...s|
+00000010  ec 20 17 90 80 3a 43 7a  bc 19 19 f5 75 c3 76 a6  |. ...:Cz....u.v.|
+00000020  53 53 4b 77 ce dd ca 4b  1b 1e ed 20 8d e5 a7 6f  |SSKw...K... ...o|
+00000030  53 e9 a4 06 4b 01 a6 08  a1 90 e5 da c9 e3 74 b0  |S...K.........t.|
+00000040  87 1f 17 1a 68 d3 f7 ae  39 b8 3e 80 c0 2f 00 00  |....h...9.>../..|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 71 0b 00 02 6d 00  02 6a 00 02 67 30 82 02  |..q...m..j..g0..|
+00000070  63 30 82 01 cc a0 03 02  01 02 02 09 00 a2 73 00  |c0............s.|
+00000080  0c 81 00 cb f3 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 0b 05 00 30 2b 31 17  30 15 06 03 55 04 0a 13  |....0+1.0...U...|
+000000a0  0e 47 6f 6f 67 6c 65 20  54 45 53 54 49 4e 47 31  |.Google TESTING1|
+000000b0  10 30 0e 06 03 55 04 03  13 07 47 6f 20 52 6f 6f  |.0...U....Go Roo|
+000000c0  74 30 1e 17 0d 31 35 30  31 30 31 30 30 30 30 30  |t0...15010100000|
+000000d0  30 5a 17 0d 32 35 30 31  30 31 30 30 30 30 30 30  |0Z..250101000000|
+000000e0  5a 30 26 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |Z0&1.0...U....Go|
+000000f0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 0b 30 09  |ogle TESTING1.0.|
+00000100  06 03 55 04 03 13 02 47  6f 30 81 9f 30 0d 06 09  |..U....Go0..0...|
+00000110  2a 86 48 86 f7 0d 01 01  01 05 00 03 81 8d 00 30  |*.H............0|
+00000120  81 89 02 81 81 00 af 87  88 f6 20 1b 95 65 6c 14  |.......... ..el.|
+00000130  ab 44 05 af 3b 45 14 e3  b7 6d fd 00 63 4d 95 7f  |.D..;E...m..cM..|
+00000140  fe 6a 62 35 86 c0 4a f9  18 7c f6 aa 25 5e 7a 64  |.jb5..J..|..%^zd|
+00000150  31 66 00 ba f4 8e 92 af  c7 6b d8 76 d4 f3 5f 41  |1f.......k.v.._A|
+00000160  cb 6e 56 15 97 1b 97 c1  3c 12 39 21 66 3d 2b 16  |.nV.....<.9!f=+.|
+00000170  d1 bc db 1c c0 a7 da b7  ca ad ba da cb d5 21 50  |..............!P|
+00000180  ec de 8d ab d1 6b 81 4b  89 02 f3 c4 be c1 6c 89  |.....k.K......l.|
+00000190  b1 44 84 bd 21 d1 04 7d  9d 16 4d f9 82 15 f6 ef  |.D..!..}..M.....|
+000001a0  fa d6 09 47 f2 fb 02 03  01 00 01 a3 81 93 30 81  |...G..........0.|
+000001b0  90 30 0e 06 03 55 1d 0f  01 01 ff 04 04 03 02 05  |.0...U..........|
+000001c0  a0 30 1d 06 03 55 1d 25  04 16 30 14 06 08 2b 06  |.0...U.%..0...+.|
+000001d0  01 05 05 07 03 01 06 08  2b 06 01 05 05 07 03 02  |........+.......|
+000001e0  30 0c 06 03 55 1d 13 01  01 ff 04 02 30 00 30 19  |0...U.......0.0.|
+000001f0  06 03 55 1d 0e 04 12 04  10 12 50 8d 89 6f 1b d1  |..U.......P..o..|
+00000200  dc 54 4d 6e cb 69 5e 06  f4 30 1b 06 03 55 1d 23  |.TMn.i^..0...U.#|
+00000210  04 14 30 12 80 10 bf 3d  b6 a9 66 f2 b8 40 cf ea  |..0....=..f.. at ..|
+00000220  b4 03 78 48 1a 41 30 19  06 03 55 1d 11 04 12 30  |..xH.A0...U....0|
+00000230  10 82 0e 65 78 61 6d 70  6c 65 2e 67 6f 6c 61 6e  |...example.golan|
+00000240  67 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |g0...*.H........|
+00000250  03 81 81 00 92 7c af 91  55 12 18 96 59 31 a6 48  |.....|..U...Y1.H|
+00000260  40 d5 2d d5 ee bb 02 a0  f5 c2 1e 7c 9b b3 30 7d  |@.-........|..0}|
+00000270  3c dc 76 da 4f 3d c0 fa  ae 2d 33 24 6b 03 7b 1b  |<.v.O=...-3$k.{.|
+00000280  67 59 11 21 b5 11 bc 77  b9 d9 e0 6e a8 2d 2e 35  |gY.!...w...n.-.5|
+00000290  fa 64 5f 22 3e 63 10 6b  be ff 14 86 6d 0d f0 15  |.d_">c.k....m...|
+000002a0  31 a8 14 38 1e 3b 84 87  2c cb 98 ed 51 76 b9 b1  |1..8.;..,...Qv..|
+000002b0  4f dd db 9b 84 04 86 40  fa 51 dd ba b4 8d eb e3  |O...... at .Q......|
+000002c0  46 de 46 b9 4f 86 c7 f9  a4 c2 41 34 ac cc f6 ea  |F.F.O.....A4....|
+000002d0  b0 ab 39 18 16 03 03 00  cd 0c 00 00 c9 03 00 17  |..9.............|
+000002e0  41 04 5e 2e 43 b7 c2 0f  e8 4a 33 aa b8 d6 04 7f  |A.^.C....J3.....|
+000002f0  2b be a2 e3 6f fa 05 1a  d1 64 a7 d1 ec 45 f9 16  |+...o....d...E..|
+00000300  b7 75 ad f2 52 3e a3 60  67 f8 fb 87 a0 c0 d4 2f  |.u..R>.`g....../|
+00000310  f4 66 c9 dd 38 40 79 5b  16 75 0b 16 6a d8 e5 ad  |.f..8 at y[.u..j...|
+00000320  63 f3 04 01 00 80 5e 89  b3 6b f4 a1 35 b3 27 be  |c.....^..k..5.'.|
+00000330  6a d4 39 42 7c ac e2 d4  9f a0 a0 a3 95 22 b5 09  |j.9B|........"..|
+00000340  70 4a 0c 6f cf 7f 69 f9  7d 27 c4 0d e7 b8 9c 82  |pJ.o..i.}'......|
+00000350  c9 0d 1d bb 5c 23 20 eb  ca 09 ca 02 a0 56 27 10  |....\# ......V'.|
+00000360  c5 d6 13 7d cd 05 64 cc  53 20 5d df ac 00 90 7f  |...}..d.S ].....|
+00000370  d7 cd f2 a1 07 9c 06 c2  e6 d1 94 60 d3 c6 97 a6  |...........`....|
+00000380  3c e5 89 67 e7 cc b7 c1  ba 75 dc 17 2b 47 ce 23  |<..g.....u..+G.#|
+00000390  a3 37 3b 3f 32 39 ae 4a  64 17 d2 64 d1 75 23 8a  |.7;?29.Jd..d.u#.|
+000003a0  e3 b4 fa 75 17 72 16 03  03 00 04 0e 00 00 00     |...u.r.........|
+>>> 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 4f ef  |.....(........O.|
+00000060  08 7c a7 de 53 70 7e 78  fb 08 79 97 1f bd 33 92  |.|..Sp~x..y...3.|
+00000070  c5 46 4d 64 32 bb 94 f0  07 ad 7d 00 86 9e        |.FMd2.....}...|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 59 c3 19 1f ed  |..........(Y....|
+00000010  d1 1b 54 5b 66 81 47 29  9a 77 84 87 a0 bd c5 d4  |..T[f.G).w......|
+00000020  f0 4e e2 11 d3 1d 26 dd  87 7a 55 11 48 37 7f 3a  |.N....&..zU.H7.:|
+00000030  2c fc 62                                          |,.b|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 02 12 57  |...............W|
+00000010  9d 64 c5 47 13 95 13 7b  2b 3e e0 f7 ae 49 0f c7  |.d.G...{+>...I..|
+00000020  0e 3a 67                                          |.:g|
+>>> Flow 6 (server to client)
+00000000  16 03 03 00 1c 59 c3 19  1f ed d1 1b 55 ac 23 dc  |.....Y......U.#.|
+00000010  0c 35 65 1e 7a 65 4f 47  13 46 a0 d0 d0 4d 0a 1f  |.5e.zeOG.F...M..|
+00000020  5c                                                |\|
+>>> Flow 7 (client to server)
+00000000  16 03 03 00 a9 00 00 00  00 00 00 00 02 c0 05 0c  |................|
+00000010  76 0a 46 19 16 17 a6 75  af 11 bb 73 37 74 a4 26  |v.F....u...s7t.&|
+00000020  d9 16 93 b8 19 5e 2f 17  52 d1 12 9e 36 90 4e c9  |.....^/.R...6.N.|
+00000030  7a f9 89 75 3b d9 d4 e1  2e cf a0 5d 03 7d cc f6  |z..u;......].}..|
+00000040  73 aa a9 52 c7 65 78 d0  89 6f b1 15 6e f9 9e 55  |s..R.ex..o..n..U|
+00000050  42 9e 22 09 df 97 00 31  b8 73 57 1b 93 ff 0c e7  |B."....1.sW.....|
+00000060  46 29 40 79 a7 c0 de b9  44 93 7b 4d 35 a0 35 65  |F)@y....D.{M5.5e|
+00000070  6e 58 07 90 2b 11 49 26  10 f7 c7 32 f7 8e 6e a7  |nX..+.I&...2..n.|
+00000080  9b 75 ba cb 4a ce f7 f0  f1 31 ca 04 a6 02 d0 62  |.u..J....1.....b|
+00000090  da 9b 8b 27 8e 04 b8 4a  49 0d d6 31 10 93 30 37  |...'...JI..1..07|
+000000a0  ad ea d7 c4 49 98 90 f3  a1 45 f4 69 2e 59        |....I....E.i.Y|
+>>> Flow 8 (server to client)
+00000000  16 03 03 00 89 59 c3 19  1f ed d1 1b 56 c8 38 86  |.....Y......V.8.|
+00000010  22 b6 5f 55 cb 0c e1 40  e6 12 f2 71 d5 09 bc 47  |"._U... at ...q...G|
+00000020  ea 83 38 3a 58 f4 34 da  ae 7f 64 fb 8c bc 71 64  |..8:X.4...d...qd|
+00000030  1b aa 84 e4 3e c1 cc c4  a9 05 36 13 5a 9b 1e c0  |....>.....6.Z...|
+00000040  44 cc 86 54 f0 75 b7 d0  aa b0 f0 3a b5 c7 f1 cc  |D..T.u.....:....|
+00000050  1f cd 8e 9e 9e bb 24 23  c3 05 0b a5 1d f3 0b 41  |......$#.......A|
+00000060  41 19 89 1e ee 51 fc b3  e8 e2 6e a8 3f c4 8b ab  |A....Q....n.?...|
+00000070  cb af d9 a1 7e 1c db e7  6c f6 23 71 c6 31 db 40  |....~...l.#q.1.@|
+00000080  a8 a7 08 fb 1a ff 8d 94  53 88 9a 11 73 6a 16 03  |........S...sj..|
+00000090  03 02 89 59 c3 19 1f ed  d1 1b 57 17 dd 9c b5 a5  |...Y......W.....|
+000000a0  89 12 3a 14 61 34 e0 1d  0b 35 d6 3a 6c 09 93 2b  |..:.a4...5.:l..+|
+000000b0  6c 69 ee f4 f3 be fb 42  33 99 fd 9a e6 21 38 68  |li.....B3....!8h|
+000000c0  a6 19 37 43 24 81 ba 35  12 fe ab ed 49 0b 03 54  |..7C$..5....I..T|
+000000d0  11 a7 74 4d bb ba e7 b9  f3 ee 6a 4e 1a 84 2f 03  |..tM......jN../.|
+000000e0  0c d1 28 21 49 84 f4 3c  5b 15 92 07 5c 6a 24 89  |..(!I..<[...\j$.|
+000000f0  00 cf 78 31 76 23 0f 9d  45 3b 93 a5 68 ee 9c 73  |..x1v#..E;..h..s|
+00000100  14 3f 08 30 37 40 4e 8b  a4 02 03 3c 4b 52 74 99  |.?.07 at N....<KRt.|
+00000110  0e 9a ec 40 c6 74 16 ef  c5 48 68 33 86 d7 06 57  |... at .t...Hh3...W|
+00000120  bf 8a 6f 3f 41 fe 4d f2  37 0a 1b fd fb 66 55 bd  |..o?A.M.7....fU.|
+00000130  70 4d b0 8c 4f 78 24 eb  1f 8f 22 c7 aa 07 89 04  |pM..Ox$...".....|
+00000140  6a b3 07 15 37 25 21 63  97 39 b1 c1 9b fa 81 5e  |j...7%!c.9.....^|
+00000150  69 c9 c7 4a 9c 5d b3 6a  41 d0 5e b9 f4 d5 5c a1  |i..J.].jA.^...\.|
+00000160  8e 8a ad 58 6e 5c 4f 73  62 38 1c 5f 8d b1 67 63  |...Xn\Osb8._..gc|
+00000170  49 da 4b 4e 83 54 34 8f  8d 12 de 4e 43 4d dc b9  |I.KN.T4....NCM..|
+00000180  02 ab 08 59 db 0b 45 7e  f5 b8 e2 33 f1 04 de 16  |...Y..E~...3....|
+00000190  05 bf b4 2b 07 a1 11 e4  9e 48 f7 52 ab 20 89 04  |...+.....H.R. ..|
+000001a0  a7 44 28 7a 12 6c 19 ab  2f 68 1a d9 26 ec 72 a0  |.D(z.l../h..&.r.|
+000001b0  62 83 48 6f 4b 70 7d 74  3a 43 4f a6 38 37 fe 59  |b.HoKp}t:CO.87.Y|
+000001c0  6e 72 5d 81 7d 2c c7 e1  6b 06 47 41 56 17 2c 25  |nr].},..k.GAV.,%|
+000001d0  06 b1 7f f5 10 0a 31 a3  12 b1 5c 01 2f e0 a6 e4  |......1...\./...|
+000001e0  fa ab d2 0b 02 77 ad ac  f8 54 db 70 20 0a 1f 04  |.....w...T.p ...|
+000001f0  86 a8 32 05 26 ee 7d e0  e9 03 19 cc 8f 67 f5 b6  |..2.&.}......g..|
+00000200  97 fe 06 5e c1 d5 df 25  f5 39 70 64 57 a8 c9 84  |...^...%.9pdW...|
+00000210  8f 0f 25 f8 c8 f9 17 70  e5 00 3c 4a 9f 4b c1 d9  |..%....p..<J.K..|
+00000220  6e b8 1a e4 6d 85 a4 e2  42 44 71 ba 43 9b 03 70  |n...m...BDq.C..p|
+00000230  14 ff 72 5e 5c 69 24 2e  52 0c 73 8b df 50 99 68  |..r^\i$.R.s..P.h|
+00000240  57 81 c1 ed b6 33 fc 74  15 45 fd a2 c4 8c f8 95  |W....3.t.E......|
+00000250  bf 8d 0e 92 91 42 72 77  03 ec c6 f6 9a 02 ca 7d  |.....Brw.......}|
+00000260  3c 87 72 eb 8d 30 3a 5c  b4 03 4a 6d 2e 83 22 c5  |<.r..0:\..Jm..".|
+00000270  e2 4a 95 83 7a 72 72 f2  2a 11 25 4a bd 04 16 ab  |.J..zrr.*.%J....|
+00000280  6a 48 44 2b 99 fb 6f 61  9a 14 4a 42 1e bf d1 82  |jHD+..oa..JB....|
+00000290  db 62 5f ac 1e 6d 1d 1b  0d 4b 9d 8d 3a 84 94 b4  |.b_..m...K..:...|
+000002a0  aa 08 5b 90 7f d2 46 b0  a7 40 f4 55 76 6b 0d 4c  |..[...F.. at .Uvk.L|
+000002b0  8e e3 8c fd ed 33 7d 93  f8 d8 c3 db 26 2d db a1  |.....3}.....&-..|
+000002c0  24 bc b0 fb 26 5f ec 13  5f 97 05 bb 5c 3c cc a3  |$...&_.._...\<..|
+000002d0  c2 57 58 cd 2e 70 0c a7  77 c5 e5 e8 0c 42 f2 e0  |.WX..p..w....B..|
+000002e0  1c 11 0f 62 4b 84 49 c2  b7 10 83 2e 16 1c 38 d4  |...bK.I.......8.|
+000002f0  10 f7 ca 71 7a 87 c5 a3  66 d2 98 1e c8 f2 c0 37  |...qz...f......7|
+00000300  0e 28 31 fe 8e 3e f4 03  74 6e 91 42 22 cb 5d 7f  |.(1..>..tn.B".].|
+00000310  d2 22 da 3c f2 a0 2d 09  a9 a5 2d 14 16 03 03 00  |.".<..-...-.....|
+00000320  e5 59 c3 19 1f ed d1 1b  58 3f 19 93 55 cb 19 f8  |.Y......X?..U...|
+00000330  02 1a 43 b3 b2 6c 4e 3e  ee 99 b3 df fd 45 24 ac  |..C..lN>.....E$.|
+00000340  63 e7 45 cc a4 44 ca cf  3a e1 81 88 01 9a b3 64  |c.E..D..:......d|
+00000350  fe 6b 36 57 9f 81 fc 40  8d ef 21 af 00 be 43 f7  |.k6W... at ..!...C.|
+00000360  a3 3b a3 fa f0 01 f2 b4  ab 8a d1 a8 14 58 1b 6f  |.;...........X.o|
+00000370  75 01 35 92 54 a7 a6 c1  99 1e 92 d8 87 53 7b 42  |u.5.T........S{B|
+00000380  4a 76 96 5e e9 db bb 4e  f1 d9 bb e6 d2 b0 34 10  |Jv.^...N......4.|
+00000390  1b 4c d5 2c ca af 19 0d  3e 77 ee 77 0e 5f ff e2  |.L.,....>w.w._..|
+000003a0  02 c5 4a f2 ec 0b 7d cf  d1 e7 3c 72 d2 17 4d 6c  |..J...}...<r..Ml|
+000003b0  a7 ca 3a 1b 00 2b 69 17  e5 a9 82 69 49 c2 ff 8a  |..:..+i....iI...|
+000003c0  f1 e8 ab 1b c3 8d da f1  31 ba a6 f4 7c 3c 01 6f  |........1...|<.o|
+000003d0  ed a8 6f e2 4f a3 68 77  b7 54 b5 87 1b 5c 5c fb  |..o.O.hw.T...\\.|
+000003e0  83 bf 48 4d 36 43 d6 f7  0a 48 74 f3 44 9d 43 53  |..HM6C...Ht.D.CS|
+000003f0  f8 54 1b 57 97 24 53 5a  93 e2 e9 33 f0 35 5f 0a  |.T.W.$SZ...3.5_.|
+00000400  0d 4c ce 92 4d c9 16 03  03 00 46 59 c3 19 1f ed  |.L..M.....FY....|
+00000410  d1 1b 59 80 50 fc 3a 56  e0 0b 06 b4 58 39 0c d8  |..Y.P.:V....X9..|
+00000420  4b b1 11 7a bd cf 1c 78  41 62 ee 22 74 61 7d 61  |K..z...xAb."ta}a|
+00000430  91 3d 0a 74 a4 b0 cd 25  70 19 a5 de d8 1b df 12  |.=.t...%p.......|
+00000440  4e b8 71 db ac bc 48 ea  89 32 ec 27 69 02 0d 8b  |N.q...H..2.'i...|
+00000450  83                                                |.|
+>>> Flow 9 (client to server)
+00000000  16 03 03 02 89 00 00 00  00 00 00 00 03 be 8d 55  |...............U|
+00000010  8a 5b 24 10 db e3 f2 11  28 0d 26 cc 1b bc 38 fa  |.[$.....(.&...8.|
+00000020  1c 8c f8 c9 64 55 ec 43  16 f7 ca af 12 a8 1c 09  |....dU.C........|
+00000030  0d b0 47 bc 9f 19 02 91  ab 9d 33 b4 bc 45 f7 4d  |..G.......3..E.M|
+00000040  53 85 4a 91 7e d3 2d dc  d6 02 6e 4a 34 51 99 db  |S.J.~.-...nJ4Q..|
+00000050  f2 a1 8d 34 60 6f 15 6a  f9 4d 7a 03 0b dc f7 c1  |...4`o.j.Mz.....|
+00000060  99 c2 2c b8 4c a1 63 ce  a2 fb 33 0d d6 dd d4 0a  |..,.L.c...3.....|
+00000070  88 0c 1d 5c ea 06 00 33  3a 06 6e 3d 63 b4 d5 0c  |...\...3:.n=c...|
+00000080  9b 69 f0 86 72 db 47 52  3d 61 0b 66 57 8d 7b 67  |.i..r.GR=a.fW.{g|
+00000090  1e 42 aa b8 ca e6 d3 07  56 cf f5 09 14 25 a2 1d  |.B......V....%..|
+000000a0  3b 3e dd 0c 41 ac 66 05  3b db 59 85 9d e2 9f 8b  |;>..A.f.;.Y.....|
+000000b0  21 c0 9a 3b 0b 8e 5b 4b  af ac 73 87 d3 b4 34 b7  |!..;..[K..s...4.|
+000000c0  2e 26 b0 5d 10 3a 2e 00  cc ac 40 b5 72 40 69 fa  |.&.].:.... at .r@i.|
+000000d0  11 04 b6 37 38 84 59 76  29 08 f0 0f 0f 79 40 7c  |...78.Yv)....y@||
+000000e0  e4 08 15 b7 58 cd 6c f4  d6 77 d6 f8 cb 1d ca 5c  |....X.l..w.....\|
+000000f0  41 d7 f8 64 63 14 a5 a5  3a 13 ce 55 b4 0a d9 b5  |A..dc...:..U....|
+00000100  34 f9 5e 69 f2 9a 62 88  b9 69 2f 93 08 2c 55 c4  |4.^i..b..i/..,U.|
+00000110  5d 0d cb 92 ac 2c 30 27  83 11 68 9f 74 35 5d 3a  |]....,0'..h.t5]:|
+00000120  96 4c 57 91 95 a8 e7 03  fa b7 ae 8b 94 e3 39 38  |.LW...........98|
+00000130  6d e1 ad b1 f7 26 2c 90  d4 3c eb a5 5e df e4 29  |m....&,..<..^..)|
+00000140  39 ff ba d2 04 f4 b4 9c  fa c2 da 34 bc 04 32 07  |9..........4..2.|
+00000150  db 52 38 fd 92 89 4c e9  50 13 e5 90 e7 f1 88 5e  |.R8...L.P......^|
+00000160  c1 7a 9b fa 6e 1f 99 ce  52 77 0c 03 d8 a6 5d 64  |.z..n...Rw....]d|
+00000170  ab 58 82 93 10 a1 4f 35  ea a3 6d af a9 64 17 3d  |.X....O5..m..d.=|
+00000180  fc a8 d8 9e 7e d7 44 af  2a c1 d6 a8 4d 78 b3 0b  |....~.D.*...Mx..|
+00000190  d1 0b 3d 54 e2 c8 df 84  61 cb 92 1a d8 ce 23 a3  |..=T....a.....#.|
+000001a0  68 f7 af 40 53 09 f0 cc  00 7d 39 83 2c 6d f4 44  |h.. at S....}9.,m.D|
+000001b0  d6 95 59 06 0a ef 9c 74  39 b3 70 cb 0a 0c 13 cd  |..Y....t9.p.....|
+000001c0  ec 1f bf 75 93 01 1a 35  68 75 8b 80 15 80 7d a9  |...u...5hu....}.|
+000001d0  d0 25 9a 52 bc 02 bf 71  eb 60 76 2a 74 90 c8 16  |.%.R...q.`v*t...|
+000001e0  80 03 c2 a8 0c be 94 7c  12 b0 ee 45 3a 38 09 5a  |.......|...E:8.Z|
+000001f0  bf 8b ca 78 f3 9e 79 8a  9f 65 57 84 f8 33 79 2a  |...x..y..eW..3y*|
+00000200  f8 8c e0 c8 4b 9e 12 19  b1 3f ba cf 9d db 48 13  |....K....?....H.|
+00000210  b4 b0 53 0e 7a 6b 1d 21  13 45 37 8d 90 75 88 f9  |..S.zk.!.E7..u..|
+00000220  b5 9d 41 d0 ee 95 5f 6a  e5 96 b6 48 ce 3b 43 20  |..A..._j...H.;C |
+00000230  47 15 db eb ba af 6d bf  38 26 e7 ad 86 ba 1e 91  |G.....m.8&......|
+00000240  be 8b df ba 5c 30 6e 3c  13 6a 96 68 13 24 bf 06  |....\0n<.j.h.$..|
+00000250  f1 d2 b0 05 8f 8e 21 7f  6a 09 5f b8 be 0b c5 5f  |......!.j._...._|
+00000260  67 60 94 ec 78 65 6f 70  94 9b 15 82 07 f4 88 fb  |g`..xeop........|
+00000270  a2 94 68 f7 57 0a 9c ec  ab 3f 8f d5 83 ec 6a 24  |..h.W....?....j$|
+00000280  6f 88 4f 22 7f a1 82 cb  ef ec 4c 33 b9 c1 16 03  |o.O"......L3....|
+00000290  03 00 5e 00 00 00 00 00  00 00 04 34 f9 69 a5 83  |..^........4.i..|
+000002a0  c5 86 34 51 f0 07 5b 44  51 36 c1 0d f7 71 c7 1b  |..4Q..[DQ6...q..|
+000002b0  70 27 aa 35 cd c7 10 76  fd 96 27 dc bc 6f 39 ff  |p'.5...v..'..o9.|
+000002c0  f1 a7 de e3 c5 21 70 e9  70 b1 52 d2 f0 be c0 72  |.....!p.p.R....r|
+000002d0  e5 aa 2b 1a 1d a8 8f 10  37 b5 2f c7 b9 32 c8 3c  |..+.....7./..2.<|
+000002e0  7c c8 11 a5 dc aa 84 12  57 f1 ff 3b f9 04 a4 29  ||.......W..;...)|
+000002f0  24 16 03 03 00 a0 00 00  00 00 00 00 00 05 1a 86  |$...............|
+00000300  c7 35 6f 23 c5 38 85 85  0e 31 df 33 1a 42 6e f8  |.5o#.8...1.3.Bn.|
+00000310  c3 f7 81 29 aa 03 85 8c  5a 8a e1 9b 1c d3 6f 7d  |...)....Z.....o}|
+00000320  36 41 45 30 06 2b dd 19  dc 22 9e 9e d4 bc 0e 51  |6AE0.+...".....Q|
+00000330  65 59 e9 7e 1b a1 d1 54  4b 3c 9a 41 de b9 43 98  |eY.~...TK<.A..C.|
+00000340  a5 ef 7a b8 77 69 f7 a5  80 02 d6 46 73 96 89 46  |..z.wi.....Fs..F|
+00000350  43 3a d7 ae 21 64 db 05  b5 7d fc 83 a3 75 ba ad  |C:..!d...}...u..|
+00000360  0d d2 d6 9b 51 3b cb 37  85 46 92 b5 57 eb 2c dc  |....Q;.7.F..W.,.|
+00000370  b2 8f e2 c0 7f 29 bf 5e  bd f0 26 dd 31 e4 31 af  |.....).^..&.1.1.|
+00000380  09 51 e4 26 09 56 a2 f4  5d fc c5 cb c8 da 51 ee  |.Q.&.V..].....Q.|
+00000390  35 2e bb 3e ee bb 14 03  03 00 19 00 00 00 00 00  |5..>............|
+000003a0  00 00 06 b5 3d 07 af c9  3f ad f0 25 b4 5e b9 0f  |....=...?..%.^..|
+000003b0  fa f0 16 48 16 03 03 00  28 00 00 00 00 00 00 00  |...H....(.......|
+000003c0  00 43 54 67 b4 f1 0e 1d  9d 7f ab f7 4c b6 77 3f  |.CTg........L.w?|
+000003d0  d0 17 da 6a 61 75 a8 c8  42 47 fb 2a f7 22 85 02  |...jau..BG.*."..|
+000003e0  b0                                                |.|
+>>> Flow 10 (server to client)
+00000000  14 03 03 00 19 59 c3 19  1f ed d1 1b 5a 9d 51 67  |.....Y......Z.Qg|
+00000010  ff ed 61 fd 01 85 c2 46  f1 26 e1 08 c3 5b 16 03  |..a....F.&...[..|
+00000020  03 00 28 02 08 83 98 20  78 eb a5 8e f5 d3 31 b6  |..(.... x.....1.|
+00000030  6d 4b 3a 9c cd 76 30 ca  92 4b 6c 17 2c d8 c5 d5  |mK:..v0..Kl.,...|
+00000040  7d 59 76 f8 ff 0c 8f f4  f6 fb 81 17 03 03 00 21  |}Yv............!|
+00000050  02 08 83 98 20 78 eb a6  9b c6 07 33 3b 43 e4 5b  |.... x.....3;C.[|
+00000060  c6 d4 31 6e 2b 5b 4a 65  c2 0a df 27 02 a2 3e 3b  |..1n+[Je...'..>;|
+00000070  04 16 03 03 00 1c 02 08  83 98 20 78 eb a7 43 45  |.......... x..CE|
+00000080  df 9b 74 94 81 17 21 b1  7d d5 c0 7a 2b cc 38 a1  |..t...!.}..z+.8.|
+00000090  30 1d                                             |0.|
+>>> Flow 11 (client to server)
+00000000  15 03 03 00 1a 00 00 00  00 00 00 00 01 d6 2b 5a  |..............+Z|
+00000010  7d c9 ba d3 94 cc 45 26  1c 1e 1e 70 39 6c 4e 15  |}.....E&...p9lN.|
+00000020  03 03 00 1a 00 00 00 00  00 00 00 02 fd 76 21 e8  |.............v!.|
+00000030  b5 16 14 43 36 9f 61 14  6d 40 76 e3 14 11        |...C6.a.m at v...|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected b/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected
new file mode 100644
index 0000000..90adc18
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected
@@ -0,0 +1,97 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 85 01 00 00  81 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 22 c0 2f  |............."./|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 9c 00 9d 00 05  00 2f 00 35 c0 12 00 0a  |........./.5....|
+00000050  01 00 00 36 00 05 00 05  01 00 00 00 00 00 0a 00  |...6............|
+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 12  00 00                    |..........|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 b1 7d c5 82 a4  |....Y...U...}...|
+00000010  f7 1d 3a b9 c0 da 13 7c  2f 75 22 a4 5f 2e 58 2a  |..:....|/u"._.X*|
+00000020  39 eb 18 7c bb 0d 98 ba  51 2e 4a 20 41 40 2f 53  |9..|....Q.J A@/S|
+00000030  bc 16 e0 a4 44 07 f0 5e  8f 43 a3 69 87 0b 94 dd  |....D..^.C.i....|
+00000040  60 a0 20 d0 25 e1 a1 a0  b8 0d d8 00 c0 2f 00 00  |`. .%......../..|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 71 0b 00 02 6d 00  02 6a 00 02 67 30 82 02  |..q...m..j..g0..|
+00000070  63 30 82 01 cc a0 03 02  01 02 02 09 00 a2 73 00  |c0............s.|
+00000080  0c 81 00 cb f3 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 0b 05 00 30 2b 31 17  30 15 06 03 55 04 0a 13  |....0+1.0...U...|
+000000a0  0e 47 6f 6f 67 6c 65 20  54 45 53 54 49 4e 47 31  |.Google TESTING1|
+000000b0  10 30 0e 06 03 55 04 03  13 07 47 6f 20 52 6f 6f  |.0...U....Go Roo|
+000000c0  74 30 1e 17 0d 31 35 30  31 30 31 30 30 30 30 30  |t0...15010100000|
+000000d0  30 5a 17 0d 32 35 30 31  30 31 30 30 30 30 30 30  |0Z..250101000000|
+000000e0  5a 30 26 31 17 30 15 06  03 55 04 0a 13 0e 47 6f  |Z0&1.0...U....Go|
+000000f0  6f 67 6c 65 20 54 45 53  54 49 4e 47 31 0b 30 09  |ogle TESTING1.0.|
+00000100  06 03 55 04 03 13 02 47  6f 30 81 9f 30 0d 06 09  |..U....Go0..0...|
+00000110  2a 86 48 86 f7 0d 01 01  01 05 00 03 81 8d 00 30  |*.H............0|
+00000120  81 89 02 81 81 00 af 87  88 f6 20 1b 95 65 6c 14  |.......... ..el.|
+00000130  ab 44 05 af 3b 45 14 e3  b7 6d fd 00 63 4d 95 7f  |.D..;E...m..cM..|
+00000140  fe 6a 62 35 86 c0 4a f9  18 7c f6 aa 25 5e 7a 64  |.jb5..J..|..%^zd|
+00000150  31 66 00 ba f4 8e 92 af  c7 6b d8 76 d4 f3 5f 41  |1f.......k.v.._A|
+00000160  cb 6e 56 15 97 1b 97 c1  3c 12 39 21 66 3d 2b 16  |.nV.....<.9!f=+.|
+00000170  d1 bc db 1c c0 a7 da b7  ca ad ba da cb d5 21 50  |..............!P|
+00000180  ec de 8d ab d1 6b 81 4b  89 02 f3 c4 be c1 6c 89  |.....k.K......l.|
+00000190  b1 44 84 bd 21 d1 04 7d  9d 16 4d f9 82 15 f6 ef  |.D..!..}..M.....|
+000001a0  fa d6 09 47 f2 fb 02 03  01 00 01 a3 81 93 30 81  |...G..........0.|
+000001b0  90 30 0e 06 03 55 1d 0f  01 01 ff 04 04 03 02 05  |.0...U..........|
+000001c0  a0 30 1d 06 03 55 1d 25  04 16 30 14 06 08 2b 06  |.0...U.%..0...+.|
+000001d0  01 05 05 07 03 01 06 08  2b 06 01 05 05 07 03 02  |........+.......|
+000001e0  30 0c 06 03 55 1d 13 01  01 ff 04 02 30 00 30 19  |0...U.......0.0.|
+000001f0  06 03 55 1d 0e 04 12 04  10 12 50 8d 89 6f 1b d1  |..U.......P..o..|
+00000200  dc 54 4d 6e cb 69 5e 06  f4 30 1b 06 03 55 1d 23  |.TMn.i^..0...U.#|
+00000210  04 14 30 12 80 10 bf 3d  b6 a9 66 f2 b8 40 cf ea  |..0....=..f.. at ..|
+00000220  b4 03 78 48 1a 41 30 19  06 03 55 1d 11 04 12 30  |..xH.A0...U....0|
+00000230  10 82 0e 65 78 61 6d 70  6c 65 2e 67 6f 6c 61 6e  |...example.golan|
+00000240  67 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |g0...*.H........|
+00000250  03 81 81 00 92 7c af 91  55 12 18 96 59 31 a6 48  |.....|..U...Y1.H|
+00000260  40 d5 2d d5 ee bb 02 a0  f5 c2 1e 7c 9b b3 30 7d  |@.-........|..0}|
+00000270  3c dc 76 da 4f 3d c0 fa  ae 2d 33 24 6b 03 7b 1b  |<.v.O=...-3$k.{.|
+00000280  67 59 11 21 b5 11 bc 77  b9 d9 e0 6e a8 2d 2e 35  |gY.!...w...n.-.5|
+00000290  fa 64 5f 22 3e 63 10 6b  be ff 14 86 6d 0d f0 15  |.d_">c.k....m...|
+000002a0  31 a8 14 38 1e 3b 84 87  2c cb 98 ed 51 76 b9 b1  |1..8.;..,...Qv..|
+000002b0  4f dd db 9b 84 04 86 40  fa 51 dd ba b4 8d eb e3  |O...... at .Q......|
+000002c0  46 de 46 b9 4f 86 c7 f9  a4 c2 41 34 ac cc f6 ea  |F.F.O.....A4....|
+000002d0  b0 ab 39 18 16 03 03 00  cd 0c 00 00 c9 03 00 17  |..9.............|
+000002e0  41 04 62 2a a7 2d 1f 7a  8d 7e 8a 9e 84 db df e2  |A.b*.-.z.~......|
+000002f0  7c 35 d8 a1 9f ec 23 ef  c7 c2 9a c5 45 02 6f eb  ||5....#.....E.o.|
+00000300  24 ed 77 e1 ca fe 9a be  06 1e ea 30 5a e7 13 00  |$.w........0Z...|
+00000310  47 52 a4 a2 d8 ee 9d 4e  87 f5 48 83 6f 5d 8e 02  |GR.....N..H.o]..|
+00000320  ff f5 04 01 00 80 19 f6  63 a1 47 d1 cf 4d 28 73  |........c.G..M(s|
+00000330  4e 31 03 78 b5 17 ba 53  64 d0 b8 3f 04 77 9d 6b  |N1.x...Sd..?.w.k|
+00000340  85 d0 d4 1e 02 90 b9 ab  10 dc d7 b1 79 1b 12 80  |............y...|
+00000350  e1 5a 4b 69 80 2d 2a 37  4c fd 72 a9 c3 8e 2a 1f  |.ZKi.-*7L.r...*.|
+00000360  1a 3f 74 49 c6 49 ce 2f  02 58 3f 68 f0 f6 b5 8a  |.?tI.I./.X?h....|
+00000370  16 11 8b 63 15 6a f2 91  f1 74 a8 f0 6d dc 91 0a  |...c.j...t..m...|
+00000380  b4 e2 4e 10 14 1d b9 da  05 29 bf 31 30 ee 7d a5  |..N......).10.}.|
+00000390  75 4e da ff db 43 04 a7  55 4b dd 93 4c 5f 32 be  |uN...C..UK..L_2.|
+000003a0  e9 23 c9 a1 23 86 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 d4 cb  |.....(..........|
+00000060  e2 c0 1e fe cb b0 d6 fe  da 7c 8f 8c b2 2f f7 c1  |.........|.../..|
+00000070  3d e9 52 6e 70 c1 13 13  87 ff 12 85 6c 2c        |=.Rnp.......l,|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 0a 86 ff b2 73  |..........(....s|
+00000010  35 40 a1 89 9f 21 1f 0b  2f 79 50 70 eb 74 e1 2f  |5 at ...!../yPp.t./|
+00000020  4d bc 5c 3c 85 0b 60 cc  73 36 e4 08 01 0a 4c 75  |M.\<..`.s6....Lu|
+00000030  0f a2 9c                                          |...|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 c9 78 b7  |..............x.|
+00000010  07 d1 a9 95 fc b4 aa 57  16 77 86 fb c7 a9 c6 12  |.......W.w......|
+00000020  bc bd 09                                          |...|
+>>> Flow 6 (server to client)
+00000000  16 03 03 00 1c 0a 86 ff  b2 73 35 40 a2 4d b1 9b  |.........s5 at .M..|
+00000010  eb 51 76 71 6b b8 88 fe  21 60 bb 8b 2a cc e3 3e  |.Qvqk...!`..*..>|
+00000020  d5                                                |.|
+>>> Flow 7 (client to server)
+00000000  15 03 03 00 1a 00 00 00  00 00 00 00 02 0e da c6  |................|
+00000010  01 09 cc 0f bb 7d de c9  41 8d 30 b5 d5 b7 f2 15  |.....}..A.0.....|
+00000020  03 03 00 1a 00 00 00 00  00 00 00 03 a7 0e 24 98  |..............$.|
+00000030  32 62 1b a9 98 17 b6 b3  71 af 88 7a a3 6b        |2b......q..z.k|
diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go
index 7be50ce..3e7aa93 100644
--- a/src/crypto/tls/ticket.go
+++ b/src/crypto/tls/ticket.go
@@ -126,11 +126,7 @@ func (s *sessionState) unmarshal(data []byte) bool {
 		data = data[certLen:]
 	}
 
-	if len(data) > 0 {
-		return false
-	}
-
-	return true
+	return len(data) == 0
 }
 
 func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go
index 4bedd76..8eef884 100644
--- a/src/crypto/tls/tls.go
+++ b/src/crypto/tls/tls.go
@@ -47,14 +47,13 @@ type listener struct {
 }
 
 // Accept waits for and returns the next incoming TLS connection.
-// The returned connection c is a *tls.Conn.
-func (l *listener) Accept() (c net.Conn, err error) {
-	c, err = l.Listener.Accept()
+// The returned connection is of type *Conn.
+func (l *listener) Accept() (net.Conn, error) {
+	c, err := l.Listener.Accept()
 	if err != nil {
-		return
+		return nil, err
 	}
-	c = Server(c, l.config)
-	return
+	return Server(c, l.config), nil
 }
 
 // NewListener creates a Listener which accepts connections from an inner
@@ -136,9 +135,9 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*
 	// from the hostname we're connecting to.
 	if config.ServerName == "" {
 		// Make a copy to avoid polluting argument or default.
-		c := *config
+		c := config.clone()
 		c.ServerName = hostname
-		config = &c
+		config = c
 	}
 
 	conn := Client(rawConn, config)
@@ -171,10 +170,11 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
 	return DialWithDialer(new(net.Dialer), network, addr, config)
 }
 
-// LoadX509KeyPair reads and parses a public/private key pair from a pair of
-// files. The files must contain PEM encoded data. On successful return,
-// Certificate.Leaf will be nil because the parsed form of the certificate is
-// not retained.
+// LoadX509KeyPair reads and parses a public/private key pair from a pair
+// of files. The files must contain PEM encoded data. The certificate file
+// may contain intermediate certificates following the leaf certificate to
+// form a certificate chain. On successful return, Certificate.Leaf will
+// be nil because the parsed form of the certificate is not retained.
 func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
 	certPEMBlock, err := ioutil.ReadFile(certFile)
 	if err != nil {
@@ -210,12 +210,12 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
 
 	if len(cert.Certificate) == 0 {
 		if len(skippedBlockTypes) == 0 {
-			return fail(errors.New("crypto/tls: failed to find any PEM data in certificate input"))
-		} else if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
-			return fail(errors.New("crypto/tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
-		} else {
-			return fail(fmt.Errorf("crypto/tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+			return fail(errors.New("tls: failed to find any PEM data in certificate input"))
+		}
+		if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
+			return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
 		}
+		return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
 	}
 
 	skippedBlockTypes = skippedBlockTypes[:0]
@@ -224,12 +224,12 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
 		keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
 		if keyDERBlock == nil {
 			if len(skippedBlockTypes) == 0 {
-				return fail(errors.New("crypto/tls: failed to find any PEM data in key input"))
-			} else if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
-				return fail(errors.New("crypto/tls: found a certificate rather than a key in the PEM for the private key"))
-			} else {
-				return fail(fmt.Errorf("crypto/tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+				return fail(errors.New("tls: failed to find any PEM data in key input"))
 			}
+			if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
+				return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key"))
+			}
+			return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
 		}
 		if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
 			break
@@ -254,22 +254,21 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
 	case *rsa.PublicKey:
 		priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
 		if !ok {
-			return fail(errors.New("crypto/tls: private key type does not match public key type"))
+			return fail(errors.New("tls: private key type does not match public key type"))
 		}
 		if pub.N.Cmp(priv.N) != 0 {
-			return fail(errors.New("crypto/tls: private key does not match public key"))
+			return fail(errors.New("tls: private key does not match public key"))
 		}
 	case *ecdsa.PublicKey:
 		priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
 		if !ok {
-			return fail(errors.New("crypto/tls: private key type does not match public key type"))
-
+			return fail(errors.New("tls: private key type does not match public key type"))
 		}
 		if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
-			return fail(errors.New("crypto/tls: private key does not match public key"))
+			return fail(errors.New("tls: private key does not match public key"))
 		}
 	default:
-		return fail(errors.New("crypto/tls: unknown public key algorithm"))
+		return fail(errors.New("tls: unknown public key algorithm"))
 	}
 
 	return cert, nil
@@ -287,12 +286,12 @@ func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
 		case *rsa.PrivateKey, *ecdsa.PrivateKey:
 			return key, nil
 		default:
-			return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping")
+			return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
 		}
 	}
 	if key, err := x509.ParseECPrivateKey(der); err == nil {
 		return key, nil
 	}
 
-	return nil, errors.New("crypto/tls: failed to parse private key")
+	return nil, errors.New("tls: failed to parse private key")
 }
diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go
index 5cc1427..48b46a0 100644
--- a/src/crypto/tls/tls_test.go
+++ b/src/crypto/tls/tls_test.go
@@ -6,13 +6,19 @@ package tls
 
 import (
 	"bytes"
+	"crypto/x509"
 	"errors"
 	"fmt"
 	"internal/testenv"
 	"io"
+	"math"
+	"math/rand"
 	"net"
+	"os"
+	"reflect"
 	"strings"
 	"testing"
+	"testing/quick"
 	"time"
 )
 
@@ -146,7 +152,7 @@ func TestX509MixedKeyPair(t *testing.T) {
 	}
 }
 
-func newLocalListener(t *testing.T) net.Listener {
+func newLocalListener(t testing.TB) net.Listener {
 	ln, err := net.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		ln, err = net.Listen("tcp6", "[::1]:0")
@@ -188,18 +194,25 @@ func TestDialTimeout(t *testing.T) {
 		t.Fatal("DialWithTimeout completed successfully")
 	}
 
-	if !strings.Contains(err.Error(), "timed out") {
-		t.Errorf("resulting error not a timeout: %s", err)
+	if !isTimeoutError(err) {
+		t.Errorf("resulting error not a timeout: %v\nType %T: %#v", err, err, err)
 	}
 }
 
+func isTimeoutError(err error) bool {
+	if ne, ok := err.(net.Error); ok {
+		return ne.Timeout()
+	}
+	return false
+}
+
 // tests that Conn.Read returns (non-zero, io.EOF) instead of
 // (non-zero, nil) when a Close (alertCloseNotify) is sitting right
 // behind the application data in the buffer.
 func TestConnReadNonzeroAndEOF(t *testing.T) {
 	// This test is racy: it assumes that after a write to a
 	// localhost TCP connection, the peer TCP connection can
-	// immediately read it.  Because it's racy, we skip this test
+	// immediately read it. Because it's racy, we skip this test
 	// in short mode, and then retry it several times with an
 	// increasing sleep in between our final write (via srv.Close
 	// below) and the following read.
@@ -228,8 +241,8 @@ func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
 			srvCh <- nil
 			return
 		}
-		serverConfig := *testConfig
-		srv := Server(sconn, &serverConfig)
+		serverConfig := testConfig.clone()
+		srv := Server(sconn, serverConfig)
 		if err := srv.Handshake(); err != nil {
 			serr = fmt.Errorf("handshake: %v", err)
 			srvCh <- nil
@@ -238,8 +251,8 @@ func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
 		srvCh <- srv
 	}()
 
-	clientConfig := *testConfig
-	conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+	clientConfig := testConfig.clone()
+	conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -282,8 +295,8 @@ func TestTLSUniqueMatches(t *testing.T) {
 			if err != nil {
 				t.Fatal(err)
 			}
-			serverConfig := *testConfig
-			srv := Server(sconn, &serverConfig)
+			serverConfig := testConfig.clone()
+			srv := Server(sconn, serverConfig)
 			if err := srv.Handshake(); err != nil {
 				t.Fatal(err)
 			}
@@ -291,9 +304,9 @@ func TestTLSUniqueMatches(t *testing.T) {
 		}
 	}()
 
-	clientConfig := *testConfig
+	clientConfig := testConfig.clone()
 	clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
-	conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
+	conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -302,7 +315,7 @@ func TestTLSUniqueMatches(t *testing.T) {
 	}
 	conn.Close()
 
-	conn, err = Dial("tcp", ln.Addr().String(), &clientConfig)
+	conn, err = Dial("tcp", ln.Addr().String(), clientConfig)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -381,8 +394,8 @@ func TestConnCloseBreakingWrite(t *testing.T) {
 			srvCh <- nil
 			return
 		}
-		serverConfig := *testConfig
-		srv := Server(sconn, &serverConfig)
+		serverConfig := testConfig.clone()
+		srv := Server(sconn, serverConfig)
 		if err := srv.Handshake(); err != nil {
 			serr = fmt.Errorf("handshake: %v", err)
 			srvCh <- nil
@@ -401,8 +414,8 @@ func TestConnCloseBreakingWrite(t *testing.T) {
 		Conn: cconn,
 	}
 
-	clientConfig := *testConfig
-	tconn := Client(conn, &clientConfig)
+	clientConfig := testConfig.clone()
+	tconn := Client(conn, clientConfig)
 	if err := tconn.Handshake(); err != nil {
 		t.Fatal(err)
 	}
@@ -445,6 +458,58 @@ func TestConnCloseBreakingWrite(t *testing.T) {
 	}
 }
 
+func TestClone(t *testing.T) {
+	var c1 Config
+	v := reflect.ValueOf(&c1).Elem()
+
+	rnd := rand.New(rand.NewSource(time.Now().Unix()))
+	typ := v.Type()
+	for i := 0; i < typ.NumField(); i++ {
+		f := v.Field(i)
+		if !f.CanSet() {
+			// unexported field; not cloned.
+			continue
+		}
+
+		// testing/quick can't handle functions or interfaces.
+		fn := typ.Field(i).Name
+		switch fn {
+		case "Rand":
+			f.Set(reflect.ValueOf(io.Reader(os.Stdin)))
+			continue
+		case "Time", "GetCertificate":
+			// DeepEqual can't compare functions.
+			continue
+		case "Certificates":
+			f.Set(reflect.ValueOf([]Certificate{
+				{Certificate: [][]byte{[]byte{'b'}}},
+			}))
+			continue
+		case "NameToCertificate":
+			f.Set(reflect.ValueOf(map[string]*Certificate{"a": nil}))
+			continue
+		case "RootCAs", "ClientCAs":
+			f.Set(reflect.ValueOf(x509.NewCertPool()))
+			continue
+		case "ClientSessionCache":
+			f.Set(reflect.ValueOf(NewLRUClientSessionCache(10)))
+			continue
+		}
+
+		q, ok := quick.Value(f.Type(), rnd)
+		if !ok {
+			t.Fatalf("quick.Value failed on field %s", fn)
+		}
+		f.Set(q)
+	}
+
+	c2 := c1.clone()
+
+	if !reflect.DeepEqual(&c1, c2) {
+		t.Errorf("clone failed to copy a field")
+	}
+}
+
 // changeImplConn is a net.Conn which can change its Write and Close
 // methods.
 type changeImplConn struct {
@@ -466,3 +531,161 @@ func (w *changeImplConn) Close() error {
 	}
 	return w.Conn.Close()
 }
+
+func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool) {
+	ln := newLocalListener(b)
+	defer ln.Close()
+
+	N := b.N
+
+	// Less than 64KB because Windows appears to use a TCP rwin < 64KB.
+	// See Issue #15899.
+	const bufsize = 32 << 10
+
+	go func() {
+		buf := make([]byte, bufsize)
+		for i := 0; i < N; i++ {
+			sconn, err := ln.Accept()
+			if err != nil {
+				// panic rather than synchronize to avoid benchmark overhead
+				// (cannot call b.Fatal in goroutine)
+				panic(fmt.Errorf("accept: %v", err))
+			}
+			serverConfig := testConfig.clone()
+			serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+			srv := Server(sconn, serverConfig)
+			if err := srv.Handshake(); err != nil {
+				panic(fmt.Errorf("handshake: %v", err))
+			}
+			if _, err := io.CopyBuffer(srv, srv, buf); err != nil {
+				panic(fmt.Errorf("copy buffer: %v", err))
+			}
+		}
+	}()
+
+	b.SetBytes(totalBytes)
+	clientConfig := testConfig.clone()
+	clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+
+	buf := make([]byte, bufsize)
+	chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf))))
+	for i := 0; i < N; i++ {
+		conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+		if err != nil {
+			b.Fatal(err)
+		}
+		for j := 0; j < chunks; j++ {
+			_, err := conn.Write(buf)
+			if err != nil {
+				b.Fatal(err)
+			}
+			_, err = io.ReadFull(conn, buf)
+			if err != nil {
+				b.Fatal(err)
+			}
+		}
+		conn.Close()
+	}
+}
+
+func BenchmarkThroughput(b *testing.B) {
+	for _, mode := range []string{"Max", "Dynamic"} {
+		for size := 1; size <= 64; size <<= 1 {
+			name := fmt.Sprintf("%sPacket/%dMB", mode, size)
+			b.Run(name, func(b *testing.B) {
+				throughput(b, int64(size<<20), mode == "Max")
+			})
+		}
+	}
+}
+
+type slowConn struct {
+	net.Conn
+	bps int
+}
+
+func (c *slowConn) Write(p []byte) (int, error) {
+	if c.bps == 0 {
+		panic("too slow")
+	}
+	t0 := time.Now()
+	wrote := 0
+	for wrote < len(p) {
+		time.Sleep(100 * time.Microsecond)
+		allowed := int(time.Since(t0).Seconds()*float64(c.bps)) / 8
+		if allowed > len(p) {
+			allowed = len(p)
+		}
+		if wrote < allowed {
+			n, err := c.Conn.Write(p[wrote:allowed])
+			wrote += n
+			if err != nil {
+				return wrote, err
+			}
+		}
+	}
+	return len(p), nil
+}
+
+func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) {
+	ln := newLocalListener(b)
+	defer ln.Close()
+
+	N := b.N
+
+	go func() {
+		for i := 0; i < N; i++ {
+			sconn, err := ln.Accept()
+			if err != nil {
+				// panic rather than synchronize to avoid benchmark overhead
+				// (cannot call b.Fatal in goroutine)
+				panic(fmt.Errorf("accept: %v", err))
+			}
+			serverConfig := testConfig.clone()
+			serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+			srv := Server(&slowConn{sconn, bps}, serverConfig)
+			if err := srv.Handshake(); err != nil {
+				panic(fmt.Errorf("handshake: %v", err))
+			}
+			io.Copy(srv, srv)
+		}
+	}()
+
+	clientConfig := testConfig.clone()
+	clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+
+	buf := make([]byte, 16384)
+	peek := make([]byte, 1)
+
+	for i := 0; i < N; i++ {
+		conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+		if err != nil {
+			b.Fatal(err)
+		}
+		// make sure we're connected and previous connection has stopped
+		if _, err := conn.Write(buf[:1]); err != nil {
+			b.Fatal(err)
+		}
+		if _, err := io.ReadFull(conn, peek); err != nil {
+			b.Fatal(err)
+		}
+		if _, err := conn.Write(buf); err != nil {
+			b.Fatal(err)
+		}
+		if _, err = io.ReadFull(conn, peek); err != nil {
+			b.Fatal(err)
+		}
+		conn.Close()
+	}
+}
+
+func BenchmarkLatency(b *testing.B) {
+	for _, mode := range []string{"Max", "Dynamic"} {
+		for _, kbps := range []int{200, 500, 1000, 2000, 5000} {
+			name := fmt.Sprintf("%sPacket/%dkbps", mode, kbps)
+			b.Run(name, func(b *testing.B) {
+				latency(b, kbps*1000, mode == "Max")
+			})
+		}
+	}
+}
diff --git a/src/crypto/x509/cert_pool.go b/src/crypto/x509/cert_pool.go
index 2362e84..59ab887 100644
--- a/src/crypto/x509/cert_pool.go
+++ b/src/crypto/x509/cert_pool.go
@@ -6,6 +6,8 @@ package x509
 
 import (
 	"encoding/pem"
+	"errors"
+	"runtime"
 )
 
 // CertPool is a set of certificates.
@@ -18,12 +20,22 @@ type CertPool struct {
 // NewCertPool returns a new, empty CertPool.
 func NewCertPool() *CertPool {
 	return &CertPool{
-		make(map[string][]int),
-		make(map[string][]int),
-		nil,
+		bySubjectKeyId: make(map[string][]int),
+		byName:         make(map[string][]int),
 	}
 }
 
+// SystemCertPool returns a copy of the system cert pool.
+//
+// Any mutations to the returned pool are not written to disk and do
+// not affect any other pool.
+func SystemCertPool() (*CertPool, error) {
+	if runtime.GOOS == "windows" {
+		return nil, errors.New("crypto/x509: system root pool is not available on Windows")
+	}
+	return loadSystemRoots()
+}
+
 // findVerifiedParents attempts to find certificates in s which have signed the
 // given certificate. If any candidates were rejected then errCert will be set
 // to one of them, arbitrarily, and err will contain the reason that it was
@@ -107,10 +119,10 @@ func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
 
 // Subjects returns a list of the DER-encoded subjects of
 // all of the certificates in the pool.
-func (s *CertPool) Subjects() (res [][]byte) {
-	res = make([][]byte, len(s.certs))
+func (s *CertPool) Subjects() [][]byte {
+	res := make([][]byte, len(s.certs))
 	for i, c := range s.certs {
 		res[i] = c.RawSubject
 	}
-	return
+	return res
 }
diff --git a/src/crypto/x509/example_test.go b/src/crypto/x509/example_test.go
index 29e7c21..97c2ea2 100644
--- a/src/crypto/x509/example_test.go
+++ b/src/crypto/x509/example_test.go
@@ -5,8 +5,12 @@
 package x509_test
 
 import (
+	"crypto/dsa"
+	"crypto/ecdsa"
+	"crypto/rsa"
 	"crypto/x509"
 	"encoding/pem"
+	"fmt"
 )
 
 func ExampleCertificate_Verify() {
@@ -89,3 +93,42 @@ yE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA==
 		panic("failed to verify certificate: " + err.Error())
 	}
 }
+
+func ExampleParsePKIXPublicKey() {
+	const pubPEM = `
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlRuRnThUjU8/prwYxbty
+WPT9pURI3lbsKMiB6Fn/VHOKE13p4D8xgOCADpdRagdT6n4etr9atzDKUSvpMtR3
+CP5noNc97WiNCggBjVWhs7szEe8ugyqF23XwpHQ6uV1LKH50m92MbOWfCtjU9p/x
+qhNpQQ1AZhqNy5Gevap5k8XzRmjSldNAFZMY7Yv3Gi+nyCwGwpVtBUwhuLzgNFK/
+yDtw2WcWmUU7NuC8Q6MWvPebxVtCfVp/iQU6q60yyt6aGOBkhAX0LpKAEhKidixY
+nP9PNVBvxgu3XZ4P36gZV6+ummKdBVnc3NqwBLu5+CcdRdusmHPHd5pHf4/38Z3/
+6qU2a/fPvWzceVTEgZ47QjFMTCTmCwNt29cvi7zZeQzjtwQgn4ipN9NibRH/Ax/q
+TbIzHfrJ1xa2RteWSdFjwtxi9C20HUkjXSeI4YlzQMH0fPX6KCE7aVePTOnB69I/
+a9/q96DiXZajwlpq3wFctrs1oXqBp5DVrCIj8hU2wNgB7LtQ1mCtsYz//heai0K9
+PhE4X6hiE0YmeAZjR0uHl8M/5aW9xCoJ72+12kKpWAa0SFRWLy6FejNYCYpkupVJ
+yecLk/4L1W0l6jQQZnWErXZYe0PNFcmwGXy1Rep83kfBRNKRy5tvocalLlwXLdUk
+AIU+2GKjyT3iMuzZxxFxPFMCAwEAAQ==
+-----END PUBLIC KEY-----`
+
+	block, _ := pem.Decode([]byte(pubPEM))
+	if block == nil {
+		panic("failed to parse PEM block containing the public key")
+	}
+
+	pub, err := x509.ParsePKIXPublicKey(block.Bytes)
+	if err != nil {
+		panic("failed to parse DER encoded public key: " + err.Error())
+	}
+
+	switch pub := pub.(type) {
+	case *rsa.PublicKey:
+		fmt.Println("pub is of type RSA:", pub)
+	case *dsa.PublicKey:
+		fmt.Println("pub is of type DSA:", pub)
+	case *ecdsa.PublicKey:
+		fmt.Println("pub is of type ECDSA:", pub)
+	default:
+		panic("unknown type of public key")
+	}
+}
diff --git a/src/crypto/x509/pem_decrypt.go b/src/crypto/x509/pem_decrypt.go
index 49ceadb..0388d63 100644
--- a/src/crypto/x509/pem_decrypt.go
+++ b/src/crypto/x509/pem_decrypt.go
@@ -42,7 +42,7 @@ type rfc1423Algo struct {
 }
 
 // rfc1423Algos holds a slice of the possible ways to encrypt a PEM
-// block.  The ivSize numbers were taken from the OpenSSL source.
+// block. The ivSize numbers were taken from the OpenSSL source.
 var rfc1423Algos = []rfc1423Algo{{
 	cipher:     PEMCipherDES,
 	name:       "DES-CBC",
diff --git a/src/crypto/x509/pkcs1.go b/src/crypto/x509/pkcs1.go
index acebe35..df20a44 100644
--- a/src/crypto/x509/pkcs1.go
+++ b/src/crypto/x509/pkcs1.go
@@ -36,15 +36,14 @@ type pkcs1AdditionalRSAPrime struct {
 }
 
 // ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form.
-func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
+func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
 	var priv pkcs1PrivateKey
 	rest, err := asn1.Unmarshal(der, &priv)
 	if len(rest) > 0 {
-		err = asn1.SyntaxError{Msg: "trailing data"}
-		return
+		return nil, asn1.SyntaxError{Msg: "trailing data"}
 	}
 	if err != nil {
-		return
+		return nil, err
 	}
 
 	if priv.Version > 1 {
@@ -55,7 +54,7 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
 		return nil, errors.New("x509: private key contains zero or negative value")
 	}
 
-	key = new(rsa.PrivateKey)
+	key := new(rsa.PrivateKey)
 	key.PublicKey = rsa.PublicKey{
 		E: priv.E,
 		N: priv.N,
@@ -80,7 +79,7 @@ func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err error) {
 	}
 	key.Precompute()
 
-	return
+	return key, nil
 }
 
 // MarshalPKCS1PrivateKey converts a private key to ASN.1 DER encoded form.
diff --git a/src/crypto/x509/pkcs8.go b/src/crypto/x509/pkcs8.go
index ba19989..b304a3f 100644
--- a/src/crypto/x509/pkcs8.go
+++ b/src/crypto/x509/pkcs8.go
@@ -13,7 +13,7 @@ import (
 
 // pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See
 // ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
-// and RFC5208.
+// and RFC 5208.
 type pkcs8 struct {
 	Version    int
 	Algo       pkix.AlgorithmIdentifier
@@ -21,8 +21,8 @@ type pkcs8 struct {
 	// optional attributes omitted.
 }
 
-// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. See
-// http://www.rsa.com/rsalabs/node.asp?id=2130 and RFC5208.
+// ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key.
+// See RFC 5208.
 func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
 	var privKey pkcs8
 	if _, err := asn1.Unmarshal(der, &privKey); err != nil {
diff --git a/src/crypto/x509/pkix/pkix.go b/src/crypto/x509/pkix/pkix.go
index 1b3e3c0..faad406 100644
--- a/src/crypto/x509/pkix/pkix.go
+++ b/src/crypto/x509/pkix/pkix.go
@@ -177,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:1"`
+	Version             int `asn1:"optional,default:0"`
 	Signature           AlgorithmIdentifier
 	Issuer              RDNSequence
 	ThisUpdate          time.Time
diff --git a/src/crypto/x509/root.go b/src/crypto/x509/root.go
index 8aae14e..787d955 100644
--- a/src/crypto/x509/root.go
+++ b/src/crypto/x509/root.go
@@ -7,11 +7,16 @@ package x509
 import "sync"
 
 var (
-	once        sync.Once
-	systemRoots *CertPool
+	once           sync.Once
+	systemRoots    *CertPool
+	systemRootsErr error
 )
 
 func systemRootsPool() *CertPool {
 	once.Do(initSystemRoots)
 	return systemRoots
 }
+
+func initSystemRoots() {
+	systemRoots, systemRootsErr = loadSystemRoots()
+}
diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go
index bf4a5cd..0e2fb35 100644
--- a/src/crypto/x509/root_cgo_darwin.go
+++ b/src/crypto/x509/root_cgo_darwin.go
@@ -21,59 +21,91 @@ package x509
 // Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
 // we've consumed its content.
 int FetchPEMRoots(CFDataRef *pemRoots) {
-	if (pemRoots == NULL) {
-		return -1;
-	}
+	// Get certificates from all domains, not just System, this lets
+	// the user add CAs to their "login" keychain, and Admins to add
+	// to the "System" keychain
+	SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem,
+					     kSecTrustSettingsDomainAdmin,
+					     kSecTrustSettingsDomainUser };
 
-	CFArrayRef certs = NULL;
-	OSStatus err = SecTrustCopyAnchorCertificates(&certs);
-	if (err != noErr) {
+	int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain);
+	if (pemRoots == NULL) {
 		return -1;
 	}
 
 	CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
-	int i, ncerts = CFArrayGetCount(certs);
-	for (i = 0; i < ncerts; i++) {
-		CFDataRef data = NULL;
-		SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
-		if (cert == NULL) {
-			continue;
-		}
-
-		// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
-		// Once we support weak imports via cgo we should prefer that, and fall back to this
-		// for older systems.
-		err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+	for (int i = 0; i < numDomains; i++) {
+		CFArrayRef certs = NULL;
+		// Only get certificates from domain that are trusted
+		OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs);
 		if (err != noErr) {
 			continue;
 		}
 
-		if (data != NULL) {
-			CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
-			CFRelease(data);
-		}
-	}
+		int numCerts = CFArrayGetCount(certs);
+		for (int j = 0; j < numCerts; j++) {
+			CFDataRef data = NULL;
+			CFErrorRef errRef = NULL;
+			SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
+			if (cert == NULL) {
+				continue;
+			}
+			// We only want to add Root CAs, so make sure Subject and Issuer Name match
+			CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, &errRef);
+			if (errRef != NULL) {
+				CFRelease(errRef);
+				continue;
+			}
+			CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, &errRef);
+			if (errRef != NULL) {
+				CFRelease(subjectName);
+				CFRelease(errRef);
+				continue;
+			}
+			Boolean equal = CFEqual(subjectName, issuerName);
+			CFRelease(subjectName);
+			CFRelease(issuerName);
+			if (!equal) {
+				continue;
+			}
 
-	CFRelease(certs);
+			// Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+			// Once we support weak imports via cgo we should prefer that, and fall back to this
+			// for older systems.
+			err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+			if (err != noErr) {
+				continue;
+			}
 
+			if (data != NULL) {
+				CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+				CFRelease(data);
+			}
+		}
+		CFRelease(certs);
+	}
 	*pemRoots = combinedData;
 	return 0;
 }
 */
 import "C"
-import "unsafe"
+import (
+	"errors"
+	"unsafe"
+)
 
-func initSystemRoots() {
+func loadSystemRoots() (*CertPool, error) {
 	roots := NewCertPool()
 
 	var data C.CFDataRef = nil
 	err := C.FetchPEMRoots(&data)
 	if err == -1 {
-		return
+		// TODO: better error message
+		return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo")
 	}
 
 	defer C.CFRelease(C.CFTypeRef(data))
 	buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
 	roots.AppendCertsFromPEM(buf)
-	systemRoots = roots
+	return roots, nil
 }
diff --git a/src/crypto/x509/root_darwin_arm_gen.go b/src/crypto/x509/root_darwin_arm_gen.go
index 5817158..fc2488a 100644
--- a/src/crypto/x509/root_darwin_arm_gen.go
+++ b/src/crypto/x509/root_darwin_arm_gen.go
@@ -184,8 +184,9 @@ const header = `
 
 package x509
 
-func initSystemRoots() {
-	systemRoots = NewCertPool()
-	systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM))
+func loadSystemRoots() (*CertPool, error) {
+	p := NewCertPool()
+	p.AppendCertsFromPEM([]byte(systemRootsPEM))
+	return p, nil
 }
 `
diff --git a/src/crypto/x509/root_darwin_armx.go b/src/crypto/x509/root_darwin_armx.go
index 37675b4..ad1c53d 100644
--- a/src/crypto/x509/root_darwin_armx.go
+++ b/src/crypto/x509/root_darwin_armx.go
@@ -10,9 +10,10 @@
 
 package x509
 
-func initSystemRoots() {
-	systemRoots = NewCertPool()
-	systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM))
+func loadSystemRoots() (*CertPool, error) {
+	p := NewCertPool()
+	p.AppendCertsFromPEM([]byte(systemRootsPEM))
+	return p, nil
 }
 
 const systemRootsPEM = `
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index cc6d23c..8b6b151 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -57,6 +57,6 @@ func TestSystemRoots(t *testing.T) {
 	}
 
 	if have < want {
-		t.Errorf("insufficent overlap between cgo and non-cgo roots; want at least %d, have %d", want, have)
+		t.Errorf("insufficient overlap between cgo and non-cgo roots; want at least %d, have %d", want, have)
 	}
 }
diff --git a/src/crypto/x509/root_nocgo_darwin.go b/src/crypto/x509/root_nocgo_darwin.go
index d00e257..2ac4666 100644
--- a/src/crypto/x509/root_nocgo_darwin.go
+++ b/src/crypto/x509/root_nocgo_darwin.go
@@ -6,6 +6,6 @@
 
 package x509
 
-func initSystemRoots() {
-	systemRoots, _ = execSecurityRoots()
+func loadSystemRoots() (*CertPool, error) {
+	return execSecurityRoots()
 }
diff --git a/src/crypto/x509/root_plan9.go b/src/crypto/x509/root_plan9.go
index 9965caa..ebeb7df 100644
--- a/src/crypto/x509/root_plan9.go
+++ b/src/crypto/x509/root_plan9.go
@@ -6,7 +6,10 @@
 
 package x509
 
-import "io/ioutil"
+import (
+	"io/ioutil"
+	"os"
+)
 
 // Possible certificate files; stop after finding one.
 var certFiles = []string{
@@ -17,17 +20,18 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
 	return nil, nil
 }
 
-func initSystemRoots() {
+func loadSystemRoots() (*CertPool, error) {
 	roots := NewCertPool()
+	var bestErr error
 	for _, file := range certFiles {
 		data, err := ioutil.ReadFile(file)
 		if err == nil {
 			roots.AppendCertsFromPEM(data)
-			systemRoots = roots
-			return
+			return roots, nil
+		}
+		if bestErr == nil || (os.IsNotExist(bestErr) && !os.IsNotExist(err)) {
+			bestErr = err
 		}
 	}
-
-	// All of the files failed to load. systemRoots will be nil which will
-	// trigger a specific error at verification time.
+	return nil, bestErr
 }
diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go
index 9f06f9d..7bcb3d6 100644
--- a/src/crypto/x509/root_unix.go
+++ b/src/crypto/x509/root_unix.go
@@ -6,7 +6,10 @@
 
 package x509
 
-import "io/ioutil"
+import (
+	"io/ioutil"
+	"os"
+)
 
 // Possible directories with certificate files; stop after successfully
 // reading at least one file from a directory.
@@ -19,20 +22,26 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
 	return nil, nil
 }
 
-func initSystemRoots() {
+func loadSystemRoots() (*CertPool, error) {
 	roots := NewCertPool()
+	var firstErr error
 	for _, file := range certFiles {
 		data, err := ioutil.ReadFile(file)
 		if err == nil {
 			roots.AppendCertsFromPEM(data)
-			systemRoots = roots
-			return
+			return roots, nil
+		}
+		if firstErr == nil && !os.IsNotExist(err) {
+			firstErr = err
 		}
 	}
 
 	for _, directory := range certDirectories {
 		fis, err := ioutil.ReadDir(directory)
 		if err != nil {
+			if firstErr == nil && !os.IsNotExist(err) {
+				firstErr = err
+			}
 			continue
 		}
 		rootsAdded := false
@@ -43,11 +52,9 @@ func initSystemRoots() {
 			}
 		}
 		if rootsAdded {
-			systemRoots = roots
-			return
+			return roots, nil
 		}
 	}
 
-	// All of the files failed to load. systemRoots will be nil which will
-	// trigger a specific error at verification time.
+	return nil, firstErr
 }
diff --git a/src/crypto/x509/root_windows.go b/src/crypto/x509/root_windows.go
index 81018b7..392c869 100644
--- a/src/crypto/x509/root_windows.go
+++ b/src/crypto/x509/root_windows.go
@@ -179,7 +179,7 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
 	}
 
 	// CertGetCertificateChain will traverse Windows's root stores
-	// in an attempt to build a verified certificate chain.  Once
+	// in an attempt to build a verified certificate chain. Once
 	// it has found a verified chain, it stops. MSDN docs on
 	// CERT_CHAIN_CONTEXT:
 	//
@@ -225,5 +225,4 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
 	return chains, nil
 }
 
-func initSystemRoots() {
-}
+func loadSystemRoots() (*CertPool, error) { return nil, nil }
diff --git a/src/crypto/x509/sec1.go b/src/crypto/x509/sec1.go
index f484b6d..33f376c 100644
--- a/src/crypto/x509/sec1.go
+++ b/src/crypto/x509/sec1.go
@@ -17,9 +17,9 @@ const ecPrivKeyVersion = 1
 
 // ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
 // References:
-//   RFC5915
+//   RFC 5915
 //   SEC1 - http://www.secg.org/sec1-v2.pdf
-// Per RFC5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
+// Per RFC 5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
 // most cases it is not.
 type ecPrivateKey struct {
 	Version       int
@@ -29,7 +29,7 @@ type ecPrivateKey struct {
 }
 
 // ParseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure.
-func ParseECPrivateKey(der []byte) (key *ecdsa.PrivateKey, err error) {
+func ParseECPrivateKey(der []byte) (*ecdsa.PrivateKey, error) {
 	return parseECPrivateKey(nil, der)
 }
 
@@ -41,8 +41,8 @@ func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
 	}
 
 	privateKeyBytes := key.D.Bytes()
-	paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen() + 7) / 8)
-	copy(paddedPrivateKey[len(paddedPrivateKey) - len(privateKeyBytes):], privateKeyBytes)
+	paddedPrivateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8)
+	copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes)
 
 	return asn1.Marshal(ecPrivateKey{
 		Version:       1,
@@ -84,7 +84,7 @@ func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *e
 	priv.Curve = curve
 	priv.D = k
 
-	privateKey := make([]byte, (curveOrder.BitLen() + 7) / 8)
+	privateKey := make([]byte, (curveOrder.BitLen()+7)/8)
 
 	// Some private keys have leading zero padding. This is invalid
 	// according to [SEC1], but this code will ignore it.
@@ -98,7 +98,7 @@ func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *e
 	// Some private keys remove all leading zeros, this is also invalid
 	// according to [SEC1] but since OpenSSL used to do this, we ignore
 	// this too.
-	copy(privateKey[len(privateKey) - len(privKey.PrivateKey):], privKey.PrivateKey)
+	copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey)
 	priv.X, priv.Y = curve.ScalarBaseMult(privateKey)
 
 	return priv, nil
diff --git a/src/crypto/x509/sec1_test.go b/src/crypto/x509/sec1_test.go
index 5e9ded5..55b76d6 100644
--- a/src/crypto/x509/sec1_test.go
+++ b/src/crypto/x509/sec1_test.go
@@ -10,8 +10,8 @@ import (
 	"testing"
 )
 
-var ecKeyTests = []struct{
-	derHex string
+var ecKeyTests = []struct {
+	derHex            string
 	shouldReserialize bool
 }{
 	// Generated using:
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 27e9bbf..85c083f 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -117,10 +117,16 @@ func (e UnknownAuthorityError) Error() string {
 }
 
 // SystemRootsError results when we fail to load the system root certificates.
-type SystemRootsError struct{}
+type SystemRootsError struct {
+	Err error
+}
 
-func (SystemRootsError) Error() string {
-	return "x509: failed to load system roots and no roots provided"
+func (se SystemRootsError) Error() string {
+	msg := "x509: failed to load system roots and no roots provided"
+	if se.Err != nil {
+		return msg + "; " + se.Err.Error()
+	}
+	return msg
 }
 
 // errNotParsed is returned when a certificate without ASN.1 contents is
@@ -179,7 +185,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
 	// being valid for encryption only, but no-one noticed. Another
 	// European CA marked its signature keys as not being valid for
 	// signatures. A different CA marked its own trusted root certificate
-	// as being invalid for certificate signing.  Another national CA
+	// as being invalid for certificate signing. Another national CA
 	// distributed a certificate to be used to encrypt data for the
 	// country’s tax authority that was marked as only being usable for
 	// digital signatures but not for encryption. Yet another CA reversed
@@ -240,7 +246,7 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
 	if opts.Roots == nil {
 		opts.Roots = systemRootsPool()
 		if opts.Roots == nil {
-			return nil, SystemRootsError{}
+			return nil, SystemRootsError{systemRootsErr}
 		}
 	}
 
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 694c140..bacf7de 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -382,7 +382,7 @@ func testVerify(t *testing.T, useSystemRoots bool) {
 					continue
 				}
 				for k, cert := range chain {
-					if strings.Index(nameToKey(&cert.Subject), expectedChain[k]) == -1 {
+					if !strings.Contains(nameToKey(&cert.Subject), expectedChain[k]) {
 						continue TryNextExpected
 					}
 				}
@@ -650,50 +650,6 @@ um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
 NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
 -----END CERTIFICATE-----`
 
-const startComRootSHA256 = `-----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-----`
-
 const smimeLeaf = `-----BEGIN CERTIFICATE-----
 MIIFBjCCA+6gAwIBAgISESFvrjT8XcJTEe6rBlPptILlMA0GCSqGSIb3DQEBBQUA
 MFQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSowKAYD
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index d9288bb..9ad3cf2 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -36,6 +36,12 @@ type pkixPublicKey struct {
 
 // ParsePKIXPublicKey parses a DER encoded public key. These values are
 // typically found in PEM blocks with "BEGIN PUBLIC KEY".
+//
+// Supported key types include RSA, DSA, and ECDSA. Unknown key
+// types result in an error.
+//
+// On success, pub will be of type *rsa.PublicKey, *dsa.PublicKey,
+// or *ecdsa.PublicKey.
 func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
 	var pki publicKeyInfo
 	if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
@@ -120,7 +126,7 @@ type certificate struct {
 
 type tbsCertificate struct {
 	Raw                asn1.RawContent
-	Version            int `asn1:"optional,explicit,default:1,tag:0"`
+	Version            int `asn1:"optional,explicit,default:0,tag:0"`
 	SerialNumber       *big.Int
 	SignatureAlgorithm pkix.AlgorithmIdentifier
 	Issuer             asn1.RawValue
@@ -264,7 +270,7 @@ var (
 	oidSignatureSHA384WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
 	oidSignatureSHA512WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
 	oidSignatureDSAWithSHA1     = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
-	oidSignatureDSAWithSHA256   = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2}
+	oidSignatureDSAWithSHA256   = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
 	oidSignatureECDSAWithSHA1   = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
 	oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
 	oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
@@ -635,7 +641,7 @@ var entrustBrokenSPKI = []byte{
 
 // CheckSignatureFrom verifies that the signature on c is a valid signature
 // from parent.
-func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) {
+func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
 	// RFC 5280, 4.2.1.9:
 	// "If the basic constraints extension is not present in a version 3
 	// certificate, or the extension is present but the cA boolean is not
@@ -663,7 +669,7 @@ 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) {
+func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error {
 	return checkSignature(algo, signed, signature, c.PublicKey)
 }
 
@@ -731,7 +737,7 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
 }
 
 // CheckCRLSignature checks that the signature in crl is from c.
-func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) (err error) {
+func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error {
 	algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm)
 	return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
 }
@@ -1127,7 +1133,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 				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")
+					return nil, errors.New("x509: trailing data after X.509 key-id")
 				}
 				out.SubjectKeyId = keyid
 
@@ -1581,21 +1587,21 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
 		return nil, err
 	}
 
-	if len(parent.SubjectKeyId) > 0 {
-		template.AuthorityKeyId = parent.SubjectKeyId
-	}
-
-	extensions, err := buildExtensions(template)
+	asn1Issuer, err := subjectBytes(parent)
 	if err != nil {
 		return
 	}
 
-	asn1Issuer, err := subjectBytes(parent)
+	asn1Subject, err := subjectBytes(template)
 	if err != nil {
 		return
 	}
 
-	asn1Subject, err := subjectBytes(template)
+	if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 {
+		template.AuthorityKeyId = parent.SubjectKeyId
+	}
+
+	extensions, err := buildExtensions(template)
 	if err != nil {
 		return
 	}
@@ -1648,7 +1654,7 @@ var pemType = "X509 CRL"
 // encoded CRLs will appear where they should be DER encoded, so this function
 // will transparently handle PEM encoding as long as there isn't any leading
 // garbage.
-func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) {
+func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) {
 	if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
 		block, _ := pem.Decode(crlBytes)
 		if block != nil && block.Type == pemType {
@@ -1659,8 +1665,8 @@ 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)
+func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) {
+	certList := new(pkix.CertificateList)
 	if rest, err := asn1.Unmarshal(derBytes, certList); err != nil {
 		return nil, err
 	} else if len(rest) != 0 {
@@ -1790,6 +1796,9 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
 func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
 	var rawAttributes []asn1.RawValue
 	b, err := asn1.Marshal(attributes)
+	if err != nil {
+		return nil, err
+	}
 	rest, err := asn1.Unmarshal(b, &rawAttributes)
 	if err != nil {
 		return nil, err
@@ -1847,8 +1856,8 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error)
 	return ret, nil
 }
 
-// CreateCertificateRequest creates a new certificate based on a template. The
-// following members of template are used: Subject, Attributes,
+// CreateCertificateRequest creates a new certificate request based on a template.
+// The following members of template are used: Subject, Attributes,
 // SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses.
 // The private key is the private key of the signer.
 //
@@ -2065,7 +2074,7 @@ 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) {
+// CheckSignature reports whether the signature on c is valid.
+func (c *CertificateRequest) CheckSignature() 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 d1ef027..c6448d3 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -96,6 +96,17 @@ tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
 -----END RSA PRIVATE KEY-----
 `
 
+var testPrivateKey *rsa.PrivateKey
+
+func init() {
+	block, _ := pem.Decode([]byte(pemPrivateKey))
+
+	var err error
+	if testPrivateKey, err = ParsePKCS1PrivateKey(block.Bytes); err != nil {
+		panic("Failed to parse private key: " + err.Error())
+	}
+}
+
 func bigFromString(s string) *big.Int {
 	ret := new(big.Int)
 	ret.SetString(s, 10)
@@ -314,12 +325,6 @@ var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be13
 func TestCreateSelfSignedCertificate(t *testing.T) {
 	random := rand.Reader
 
-	block, _ := pem.Decode([]byte(pemPrivateKey))
-	rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
-	if err != nil {
-		t.Fatalf("Failed to parse private key: %s", err)
-	}
-
 	ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
 	if err != nil {
 		t.Fatalf("Failed to generate ECDSA key: %s", err)
@@ -331,9 +336,9 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 		checkSig  bool
 		sigAlgo   SignatureAlgorithm
 	}{
-		{"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true, SHA1WithRSA},
-		{"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
-		{"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false, SHA256WithRSA},
+		{"RSA/RSA", &testPrivateKey.PublicKey, testPrivateKey, true, SHA1WithRSA},
+		{"RSA/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
+		{"ECDSA/RSA", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSA},
 		{"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA1},
 	}
 
@@ -488,7 +493,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 			t.Errorf("%s: ExtraExtensions didn't override SubjectKeyId", test.name)
 		}
 
-		if bytes.Index(derBytes, extraExtensionData) == -1 {
+		if !bytes.Contains(derBytes, extraExtensionData) {
 			t.Errorf("%s: didn't find extra extension in DER output", test.name)
 		}
 
@@ -874,12 +879,6 @@ const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RF
 func TestCreateCertificateRequest(t *testing.T) {
 	random := rand.Reader
 
-	block, _ := pem.Decode([]byte(pemPrivateKey))
-	rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
-	if err != nil {
-		t.Fatalf("Failed to parse private key: %s", err)
-	}
-
 	ecdsa256Priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
 	if err != nil {
 		t.Fatalf("Failed to generate ECDSA key: %s", err)
@@ -900,7 +899,7 @@ func TestCreateCertificateRequest(t *testing.T) {
 		priv    interface{}
 		sigAlgo SignatureAlgorithm
 	}{
-		{"RSA", rsaPriv, SHA1WithRSA},
+		{"RSA", testPrivateKey, SHA1WithRSA},
 		{"ECDSA-256", ecdsa256Priv, ECDSAWithSHA1},
 		{"ECDSA-384", ecdsa384Priv, ECDSAWithSHA1},
 		{"ECDSA-521", ecdsa521Priv, ECDSAWithSHA1},
@@ -951,13 +950,7 @@ func TestCreateCertificateRequest(t *testing.T) {
 }
 
 func marshalAndParseCSR(t *testing.T, template *CertificateRequest) *CertificateRequest {
-	block, _ := pem.Decode([]byte(pemPrivateKey))
-	rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	derBytes, err := CreateCertificateRequest(rand.Reader, template, rsaPriv)
+	derBytes, err := CreateCertificateRequest(rand.Reader, template, testPrivateKey)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -1113,13 +1106,25 @@ func TestCriticalFlagInCSRRequestedExtensions(t *testing.T) {
 	}
 }
 
-func TestMaxPathLen(t *testing.T) {
-	block, _ := pem.Decode([]byte(pemPrivateKey))
-	rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)
+// serialiseAndParse generates a self-signed certificate from template and
+// returns a parsed version of it.
+func serialiseAndParse(t *testing.T, template *Certificate) *Certificate {
+	derBytes, err := CreateCertificate(rand.Reader, template, template, &testPrivateKey.PublicKey, testPrivateKey)
 	if err != nil {
-		t.Fatalf("Failed to parse private key: %s", err)
+		t.Fatalf("failed to create certificate: %s", err)
+		return nil
 	}
 
+	cert, err := ParseCertificate(derBytes)
+	if err != nil {
+		t.Fatalf("failed to parse certificate: %s", err)
+		return nil
+	}
+
+	return cert
+}
+
+func TestMaxPathLen(t *testing.T) {
 	template := &Certificate{
 		SerialNumber: big.NewInt(1),
 		Subject: pkix.Name{
@@ -1132,23 +1137,7 @@ func TestMaxPathLen(t *testing.T) {
 		IsCA: true,
 	}
 
-	serialiseAndParse := func(template *Certificate) *Certificate {
-		derBytes, err := CreateCertificate(rand.Reader, template, template, &rsaPriv.PublicKey, rsaPriv)
-		if err != nil {
-			t.Fatalf("failed to create certificate: %s", err)
-			return nil
-		}
-
-		cert, err := ParseCertificate(derBytes)
-		if err != nil {
-			t.Fatalf("failed to parse certificate: %s", err)
-			return nil
-		}
-
-		return cert
-	}
-
-	cert1 := serialiseAndParse(template)
+	cert1 := serialiseAndParse(t, template)
 	if m := cert1.MaxPathLen; m != -1 {
 		t.Errorf("Omitting MaxPathLen didn't turn into -1, got %d", m)
 	}
@@ -1157,7 +1146,7 @@ func TestMaxPathLen(t *testing.T) {
 	}
 
 	template.MaxPathLen = 1
-	cert2 := serialiseAndParse(template)
+	cert2 := serialiseAndParse(t, template)
 	if m := cert2.MaxPathLen; m != 1 {
 		t.Errorf("Setting MaxPathLen didn't work. Got %d but set 1", m)
 	}
@@ -1167,7 +1156,7 @@ func TestMaxPathLen(t *testing.T) {
 
 	template.MaxPathLen = 0
 	template.MaxPathLenZero = true
-	cert3 := serialiseAndParse(template)
+	cert3 := serialiseAndParse(t, template)
 	if m := cert3.MaxPathLen; m != 0 {
 		t.Errorf("Setting MaxPathLenZero didn't work, got %d", m)
 	}
@@ -1176,6 +1165,30 @@ func TestMaxPathLen(t *testing.T) {
 	}
 }
 
+func TestNoAuthorityKeyIdInSelfSignedCert(t *testing.T) {
+	template := &Certificate{
+		SerialNumber: big.NewInt(1),
+		Subject: pkix.Name{
+			CommonName: "Σ Acme Co",
+		},
+		NotBefore: time.Unix(1000, 0),
+		NotAfter:  time.Unix(100000, 0),
+
+		BasicConstraintsValid: true,
+		IsCA:         true,
+		SubjectKeyId: []byte{1, 2, 3, 4},
+	}
+
+	if cert := serialiseAndParse(t, template); len(cert.AuthorityKeyId) != 0 {
+		t.Fatalf("self-signed certificate contained default authority key id")
+	}
+
+	template.AuthorityKeyId = []byte{1, 2, 3, 4}
+	if cert := serialiseAndParse(t, template); len(cert.AuthorityKeyId) == 0 {
+		t.Fatalf("self-signed certificate erased explicit authority key id")
+	}
+}
+
 func TestASN1BitLength(t *testing.T) {
 	tests := []struct {
 		bytes  []byte
diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go
index 740fd9d..99aed23 100644
--- a/src/database/sql/convert.go
+++ b/src/database/sql/convert.go
@@ -44,7 +44,7 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.Value, error) {
 	// Let the Stmt convert its own arguments.
 	for n, arg := range args {
 		// First, see if the value itself knows how to convert
-		// itself to a driver type.  For example, a NullString
+		// itself to a driver type. For example, a NullString
 		// struct changing into a string or nil.
 		if svi, ok := arg.(driver.Valuer); ok {
 			sv, err := svi.Value()
@@ -217,7 +217,12 @@ func convertAssign(dest, src interface{}) error {
 
 	dv := reflect.Indirect(dpv)
 	if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) {
-		dv.Set(sv)
+		switch b := src.(type) {
+		case []byte:
+			dv.Set(reflect.ValueOf(cloneBytes(b)))
+		default:
+			dv.Set(sv)
+		}
 		return nil
 	}
 
diff --git a/src/database/sql/convert_test.go b/src/database/sql/convert_test.go
index 342875e..ab81f2f 100644
--- a/src/database/sql/convert_test.go
+++ b/src/database/sql/convert_test.go
@@ -377,3 +377,15 @@ func TestRawBytesAllocs(t *testing.T) {
 		t.Fatalf("allocs = %v; want max 1", n)
 	}
 }
+
+// https://github.com/golang/go/issues/13905
+func TestUserDefinedBytes(t *testing.T) {
+	type userDefinedBytes []byte
+	var u userDefinedBytes
+	v := []byte("foo")
+
+	convertAssign(&u, v)
+	if &u[0] == &v[0] {
+		t.Fatal("userDefinedBytes got potentially dirty driver memory")
+	}
+}
diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go
index eca25f2..4dba85a 100644
--- a/src/database/sql/driver/driver.go
+++ b/src/database/sql/driver/driver.go
@@ -17,7 +17,7 @@ import "errors"
 //   float64
 //   bool
 //   []byte
-//   string   [*] everywhere except from Rows.Next.
+//   string
 //   time.Time
 type Value interface{}
 
@@ -144,7 +144,7 @@ type Stmt interface {
 // any type to a driver Value.
 type ColumnConverter interface {
 	// ColumnConverter returns a ValueConverter for the provided
-	// column index.  If the type of a specific column isn't known
+	// column index. If the type of a specific column isn't known
 	// or shouldn't be handled specially, DefaultValueConverter
 	// can be returned.
 	ColumnConverter(idx int) ValueConverter
@@ -154,7 +154,7 @@ type ColumnConverter interface {
 type Rows interface {
 	// Columns returns the names of the columns. The number of
 	// columns of the result is inferred from the length of the
-	// slice.  If a particular column name isn't known, an empty
+	// slice. If a particular column name isn't known, an empty
 	// string should be returned for that entry.
 	Columns() []string
 
@@ -165,10 +165,6 @@ type Rows interface {
 	// the provided slice. The provided slice will be the same
 	// size as the Columns() are wide.
 	//
-	// The dest slice may be populated only with
-	// a driver Value type, but excluding string.
-	// All string values must be converted to []byte.
-	//
 	// Next should return io.EOF when there are no more rows.
 	Next(dest []Value) error
 }
diff --git a/src/database/sql/driver/types.go b/src/database/sql/driver/types.go
index bc54784..e480e70 100644
--- a/src/database/sql/driver/types.go
+++ b/src/database/sql/driver/types.go
@@ -15,7 +15,7 @@ import (
 //
 // Various implementations of ValueConverter are provided by the
 // driver package to provide consistent implementations of conversions
-// between drivers.  The ValueConverters have several uses:
+// between drivers. The ValueConverters have several uses:
 //
 //  * converting from the Value types as provided by the sql package
 //    into a database table's specific column type and making sure it
@@ -172,28 +172,21 @@ func (n NotNull) ConvertValue(v interface{}) (Value, error) {
 }
 
 // IsValue reports whether v is a valid Value parameter type.
-// Unlike IsScanValue, IsValue permits the string type.
 func IsValue(v interface{}) bool {
-	if IsScanValue(v) {
+	if v == nil {
 		return true
 	}
-	if _, ok := v.(string); ok {
+	switch v.(type) {
+	case []byte, bool, float64, int64, string, time.Time:
 		return true
 	}
 	return false
 }
 
-// IsScanValue reports whether v is a valid Value scan type.
-// Unlike IsValue, IsScanValue does not permit the string type.
+// IsScanValue is equivalent to IsValue.
+// It exists for compatibility.
 func IsScanValue(v interface{}) bool {
-	if v == nil {
-		return true
-	}
-	switch v.(type) {
-	case int64, float64, []byte, bool, time.Time:
-		return true
-	}
-	return false
+	return IsValue(v)
 }
 
 // DefaultParameterConverter is the default implementation of
diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
index b5ff121..5b238bf 100644
--- a/src/database/sql/fakedb_test.go
+++ b/src/database/sql/fakedb_test.go
@@ -37,7 +37,7 @@ var _ = log.Printf
 // named method on fakeStmt to panic.
 //
 // When opening a fakeDriver's database, it starts empty with no
-// tables.  All tables and data are stored in memory only.
+// tables. All tables and data are stored in memory only.
 type fakeDriver struct {
 	mu         sync.Mutex // guards 3 following fields
 	openCount  int        // conn opens
@@ -51,7 +51,6 @@ type fakeDB struct {
 	name string
 
 	mu      sync.Mutex
-	free    []*fakeConn
 	tables  map[string]*table
 	badConn bool
 }
@@ -76,12 +75,6 @@ type row struct {
 	cols []interface{} // must be same size as its table colname + coltype
 }
 
-func (r *row) clone() *row {
-	nrow := &row{cols: make([]interface{}, len(r.cols))}
-	copy(nrow.cols, r.cols)
-	return nrow
-}
-
 type fakeConn struct {
 	db *fakeDB // where to return ourselves to
 
@@ -705,7 +698,7 @@ func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
 rows:
 	for _, trow := range t.rows {
 		// Process the where clause, skipping non-match rows. This is lazy
-		// and just uses fmt.Sprintf("%v") to test equality.  Good enough
+		// and just uses fmt.Sprintf("%v") to test equality. Good enough
 		// for test code.
 		for widx, wcol := range s.whereCol {
 			idx := t.columnIndex(wcol)
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index d8e7cb7..09de1c3 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -199,7 +199,7 @@ type Scanner interface {
 	//    time.Time
 	//    nil - for NULL values
 	//
-	// An error should be returned if the value can not be stored
+	// An error should be returned if the value cannot be stored
 	// without loss of information.
 	Scan(src interface{}) error
 }
@@ -718,6 +718,9 @@ func (db *DB) maybeOpenNewConnections() {
 	for numRequests > 0 {
 		db.numOpen++ // optimistically
 		numRequests--
+		if db.closed {
+			return
+		}
 		db.openerCh <- struct{}{}
 	}
 }
@@ -797,7 +800,7 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
 		return conn, nil
 	}
 
-	// Out of free connections or we were asked not to use one.  If we're not
+	// 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
@@ -838,11 +841,6 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
 	return dc, nil
 }
 
-var (
-	errConnClosed = errors.New("database/sql: internal sentinel error: conn is closed")
-	errConnBusy   = errors.New("database/sql: internal sentinel error: conn is busy")
-)
-
 // putConnHook is a hook for testing.
 var putConnHook func(*DB, *driverConn)
 
@@ -920,6 +918,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.closed {
+		return false
+	}
 	if db.maxOpen > 0 && db.numOpen > db.maxOpen {
 		return false
 	}
@@ -1207,7 +1208,7 @@ type Tx struct {
 	// ErrTxDone.
 	done bool
 
-	// All Stmts prepared for this transaction.  These will be closed after the
+	// All Stmts prepared for this transaction. These will be closed after the
 	// transaction has been committed or rolled back.
 	stmts struct {
 		sync.Mutex
@@ -1286,7 +1287,7 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
 	// necessary. Or, better: keep a map in DB of query string to
 	// Stmts, and have Stmt.Execute do the right thing and
 	// re-prepare if the Conn in use doesn't have that prepared
-	// statement.  But we'll want to avoid caching the statement
+	// statement. But we'll want to avoid caching the statement
 	// in the case where we only call conn.Prepare implicitly
 	// (such as in db.Exec or tx.Exec), but the caller package
 	// can't be holding a reference to the returned statement.
@@ -1334,7 +1335,7 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
 // 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
+	// each time. This is fine for now to illustrate the API but
 	// we should really cache already-prepared statements
 	// per-Conn. See also the big comment in Tx.Prepare.
 
@@ -1441,9 +1442,9 @@ type Stmt struct {
 	closed bool
 
 	// css is a list of underlying driver statement interfaces
-	// that are valid on particular connections.  This is only
+	// that are valid on particular connections. This is only
 	// used if tx == nil and one is found that has idle
-	// connections.  If tx != nil, txsi is always used.
+	// connections. If tx != nil, txsi is always used.
 	css []connStmt
 
 	// lastNumClosed is copied from db.numClosed when Stmt is created
@@ -1741,9 +1742,9 @@ type Rows struct {
 	closeStmt driver.Stmt // if non-nil, statement to Close on close
 }
 
-// Next prepares the next result row for reading with the Scan method.  It
+// Next prepares the next result row for reading with the Scan method. It
 // returns true on success, or false if there is no next result row or an error
-// happened while preparing it.  Err should be consulted to distinguish between
+// happened while preparing it. Err should be consulted to distinguish between
 // the two cases.
 //
 // Every call to Scan, even the first one, must be preceded by a call to Next.
@@ -1898,8 +1899,8 @@ func (r *Row) Scan(dest ...interface{}) error {
 	// the Rows in our defer, when we return from this function.
 	// the contract with the driver.Next(...) interface is that it
 	// can return slices into read-only temporary memory that's
-	// only valid until the next Scan/Close.  But the TODO is that
-	// for a lot of drivers, this copy will be unnecessary.  We
+	// only valid until the next Scan/Close. But the TODO is that
+	// for a lot of drivers, this copy will be unnecessary. We
 	// should provide an optional interface for drivers to
 	// implement to say, "don't worry, the []bytes that I return
 	// from Next will not be modified again." (for instance, if
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index 8ec70d9..08df0c7 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -144,7 +144,7 @@ func closeDB(t testing.TB, db *DB) {
 	count := db.numOpen
 	db.mu.Unlock()
 	if count != 0 {
-		t.Fatalf("%d connections still open after closing DB", db.numOpen)
+		t.Fatalf("%d connections still open after closing DB", count)
 	}
 }
 
@@ -911,7 +911,7 @@ func nullTestRun(t *testing.T, spec nullTestSpec) {
 	if err == nil {
 		// TODO: this test fails, but it's just because
 		// fakeConn implements the optional Execer interface,
-		// so arguably this is the correct behavior.  But
+		// so arguably this is the correct behavior. But
 		// maybe I should flesh out the fakeConn.Exec
 		// implementation so this properly fails.
 		// t.Errorf("expected error inserting nil name with Exec")
@@ -1239,7 +1239,7 @@ func TestPendingConnsAfterErr(t *testing.T) {
 	time.Sleep(10 * time.Millisecond) // make extra sure all workers are blocked
 	close(unblock)                    // let all workers proceed
 
-	const timeout = 100 * time.Millisecond
+	const timeout = 5 * time.Second
 	to := time.NewTimer(timeout)
 	defer to.Stop()
 
@@ -1591,7 +1591,7 @@ func TestStmtCloseOrder(t *testing.T) {
 
 	_, err := db.Query("SELECT|non_existent|name|")
 	if err == nil {
-		t.Fatal("Quering non-existent table should fail")
+		t.Fatal("Querying non-existent table should fail")
 	}
 }
 
@@ -1615,6 +1615,8 @@ func TestManyErrBadConn(t *testing.T) {
 			}
 		}()
 
+		db.mu.Lock()
+		defer db.mu.Unlock()
 		if db.numOpen != nconn {
 			t.Fatalf("unexpected numOpen %d (was expecting %d)", db.numOpen, nconn)
 		} else if len(db.freeConn) != nconn {
diff --git a/src/debug/dwarf/buf.go b/src/debug/dwarf/buf.go
index 2ade0bd..24d266d 100644
--- a/src/debug/dwarf/buf.go
+++ b/src/debug/dwarf/buf.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -22,16 +22,16 @@ type buf struct {
 	err    error
 }
 
-// Data format, other than byte order.  This affects the handling of
+// Data format, other than byte order. This affects the handling of
 // certain field formats.
 type dataFormat interface {
-	// DWARF version number.  Zero means unknown.
+	// DWARF version number. Zero means unknown.
 	version() int
 
 	// 64-bit DWARF format?
 	dwarf64() (dwarf64 bool, isKnown bool)
 
-	// Size of an address, in bytes.  Zero means unknown.
+	// Size of an address, in bytes. Zero means unknown.
 	addrsize() int
 }
 
@@ -157,7 +157,7 @@ func (b *buf) addr() uint64 {
 	case 4:
 		return uint64(b.uint32())
 	case 8:
-		return uint64(b.uint64())
+		return b.uint64()
 	}
 	b.error("unknown address size")
 	return 0
diff --git a/src/debug/dwarf/const.go b/src/debug/dwarf/const.go
index 2170db1..04d8c50 100644
--- a/src/debug/dwarf/const.go
+++ b/src/debug/dwarf/const.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/debug/dwarf/entry.go b/src/debug/dwarf/entry.go
index 5ca8667..80bf14c 100644
--- a/src/debug/dwarf/entry.go
+++ b/src/debug/dwarf/entry.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -243,7 +243,7 @@ type Field struct {
 	Class Class
 }
 
-// A Class is the DWARF 4 class of an attibute value.
+// A Class is the DWARF 4 class of an attribute 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
@@ -506,7 +506,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
 }
 
 // A Reader allows reading Entry structures from a DWARF ``info'' section.
-// The Entry structures are arranged in a tree.  The Reader's Next function
+// The Entry structures are arranged in a tree. The Reader's Next function
 // return successive entries from a pre-order traversal of the tree.
 // If an entry has children, its Children field will be true, and the children
 // follow, terminated by an Entry with Tag 0.
@@ -598,7 +598,7 @@ func (r *Reader) Next() (*Entry, error) {
 }
 
 // SkipChildren skips over the child entries associated with
-// the last Entry returned by Next.  If that Entry did not have
+// the last Entry returned by Next. If that Entry did not have
 // children or Next has not been called, SkipChildren is a no-op.
 func (r *Reader) SkipChildren() {
 	if r.err != nil || !r.lastChildren {
@@ -625,14 +625,134 @@ func (r *Reader) SkipChildren() {
 	}
 }
 
-// clone returns a copy of the reader.  This is used by the typeReader
+// clone returns a copy of the reader. This is used by the typeReader
 // interface.
 func (r *Reader) clone() typeReader {
 	return r.d.Reader()
 }
 
-// offset returns the current buffer offset.  This is used by the
+// offset returns the current buffer offset. This is used by the
 // typeReader interface.
 func (r *Reader) offset() Offset {
 	return r.b.off
 }
+
+// SeekPC returns the Entry for the compilation unit that includes pc,
+// and positions the reader to read the children of that unit.  If pc
+// is not covered by any unit, SeekPC returns ErrUnknownPC and the
+// position of the reader is undefined.
+//
+// Because compilation units can describe multiple regions of the
+// executable, in the worst case SeekPC must search through all the
+// ranges in all the compilation units. Each call to SeekPC starts the
+// search at the compilation unit of the last call, so in general
+// looking up a series of PCs will be faster if they are sorted. If
+// the caller wishes to do repeated fast PC lookups, it should build
+// an appropriate index using the Ranges method.
+func (r *Reader) SeekPC(pc uint64) (*Entry, error) {
+	unit := r.unit
+	for i := 0; i < len(r.d.unit); i++ {
+		if unit >= len(r.d.unit) {
+			unit = 0
+		}
+		r.err = nil
+		r.lastChildren = false
+		r.unit = unit
+		u := &r.d.unit[unit]
+		r.b = makeBuf(r.d, u, "info", u.off, u.data)
+		e, err := r.Next()
+		if err != nil {
+			return nil, err
+		}
+		ranges, err := r.d.Ranges(e)
+		if err != nil {
+			return nil, err
+		}
+		for _, pcs := range ranges {
+			if pcs[0] <= pc && pc < pcs[1] {
+				return e, nil
+			}
+		}
+		unit++
+	}
+	return nil, ErrUnknownPC
+}
+
+// Ranges returns the PC ranges covered by e, a slice of [low,high) pairs.
+// Only some entry types, such as TagCompileUnit or TagSubprogram, have PC
+// ranges; for others, this will return nil with no error.
+func (d *Data) Ranges(e *Entry) ([][2]uint64, error) {
+	var ret [][2]uint64
+
+	low, lowOK := e.Val(AttrLowpc).(uint64)
+
+	var high uint64
+	var highOK bool
+	highField := e.AttrField(AttrHighpc)
+	if highField != nil {
+		switch highField.Class {
+		case ClassAddress:
+			high, highOK = highField.Val.(uint64)
+		case ClassConstant:
+			off, ok := highField.Val.(int64)
+			if ok {
+				high = low + uint64(off)
+				highOK = true
+			}
+		}
+	}
+
+	if lowOK && highOK {
+		ret = append(ret, [2]uint64{low, high})
+	}
+
+	ranges, rangesOK := e.Val(AttrRanges).(int64)
+	if rangesOK && d.ranges != nil {
+		// The initial base address is the lowpc attribute
+		// of the enclosing compilation unit.
+		// Although DWARF specifies the lowpc attribute,
+		// comments in gdb/dwarf2read.c say that some versions
+		// of GCC use the entrypc attribute, so we check that too.
+		var cu *Entry
+		if e.Tag == TagCompileUnit {
+			cu = e
+		} else {
+			i := d.offsetToUnit(e.Offset)
+			if i == -1 {
+				return nil, errors.New("no unit for entry")
+			}
+			u := &d.unit[i]
+			b := makeBuf(d, u, "info", u.off, u.data)
+			cu = b.entry(u.atable, u.base)
+			if b.err != nil {
+				return nil, b.err
+			}
+		}
+
+		var base uint64
+		if cuEntry, cuEntryOK := cu.Val(AttrEntrypc).(uint64); cuEntryOK {
+			base = cuEntry
+		} else if cuLow, cuLowOK := cu.Val(AttrLowpc).(uint64); cuLowOK {
+			base = cuLow
+		}
+
+		u := &d.unit[d.offsetToUnit(e.Offset)]
+		buf := makeBuf(d, u, "ranges", Offset(ranges), d.ranges[ranges:])
+		for len(buf.data) > 0 {
+			low = buf.addr()
+			high = buf.addr()
+
+			if low == 0 && high == 0 {
+				break
+			}
+
+			if low == ^uint64(0)>>uint((8-u.addrsize())*8) {
+				base = high
+			} else {
+				ret = append(ret, [2]uint64{base + low, base + high})
+			}
+		}
+	}
+
+	return ret, nil
+}
diff --git a/src/debug/dwarf/entry_test.go b/src/debug/dwarf/entry_test.go
index 8bd2d2a..58a5d57 100644
--- a/src/debug/dwarf/entry_test.go
+++ b/src/debug/dwarf/entry_test.go
@@ -6,6 +6,7 @@ package dwarf_test
 
 import (
 	. "debug/dwarf"
+	"reflect"
 	"testing"
 )
 
@@ -34,3 +35,103 @@ func TestSplit(t *testing.T) {
 		t.Fatalf("bad class: have %s, want %s", f.Class, ClassUnknown)
 	}
 }
+
+// wantRange maps from a PC to the ranges of the compilation unit
+// containing that PC.
+type wantRange struct {
+	pc     uint64
+	ranges [][2]uint64
+}
+
+func TestReaderSeek(t *testing.T) {
+	want := []wantRange{
+		{0x40059d, [][2]uint64{{0x40059d, 0x400601}}},
+		{0x400600, [][2]uint64{{0x40059d, 0x400601}}},
+		{0x400601, [][2]uint64{{0x400601, 0x400611}}},
+		{0x4005f0, [][2]uint64{{0x40059d, 0x400601}}}, // loop test
+		{0x10, nil},
+		{0x400611, nil},
+	}
+	testRanges(t, "testdata/line-gcc.elf", want)
+}
+
+func TestRangesSection(t *testing.T) {
+	want := []wantRange{
+		{0x400500, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
+		{0x400400, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
+		{0x400548, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
+		{0x400407, [][2]uint64{{0x400500, 0x400549}, {0x400400, 0x400408}}},
+		{0x400408, nil},
+		{0x400449, nil},
+		{0x4003ff, nil},
+	}
+	testRanges(t, "testdata/ranges.elf", want)
+}
+
+func testRanges(t *testing.T, name string, want []wantRange) {
+	d := elfData(t, name)
+	r := d.Reader()
+	for _, w := range want {
+		entry, err := r.SeekPC(w.pc)
+		if err != nil {
+			if w.ranges != nil {
+				t.Errorf("%s: missing Entry for %#x", name, w.pc)
+			}
+			if err != ErrUnknownPC {
+				t.Errorf("%s: expected ErrUnknownPC for %#x, got %v", name, w.pc, err)
+			}
+			continue
+		}
+
+		ranges, err := d.Ranges(entry)
+		if err != nil {
+			t.Errorf("%s: %v", name, err)
+			continue
+		}
+		if !reflect.DeepEqual(ranges, w.ranges) {
+			t.Errorf("%s: for %#x got %x, expected %x", name, w.pc, ranges, w.ranges)
+		}
+	}
+}
+
+func TestReaderRanges(t *testing.T) {
+	d := elfData(t, "testdata/line-gcc.elf")
+
+	subprograms := []struct {
+		name   string
+		ranges [][2]uint64
+	}{
+		{"f1", [][2]uint64{{0x40059d, 0x4005e7}}},
+		{"main", [][2]uint64{{0x4005e7, 0x400601}}},
+		{"f2", [][2]uint64{{0x400601, 0x400611}}},
+	}
+
+	r := d.Reader()
+	i := 0
+	for entry, err := r.Next(); entry != nil && err == nil; entry, err = r.Next() {
+		if entry.Tag != TagSubprogram {
+			continue
+		}
+
+		if i > len(subprograms) {
+			t.Fatalf("too many subprograms (expected at most %d)", i)
+		}
+
+		if got := entry.Val(AttrName).(string); got != subprograms[i].name {
+			t.Errorf("subprogram %d name is %s, expected %s", i, got, subprograms[i].name)
+		}
+		ranges, err := d.Ranges(entry)
+		if err != nil {
+			t.Errorf("subprogram %d: %v", i, err)
+			continue
+		}
+		if !reflect.DeepEqual(ranges, subprograms[i].ranges) {
+			t.Errorf("subprogram %d ranges are %x, expected %x", i, ranges, subprograms[i].ranges)
+		}
+		i++
+	}
+
+	if i < len(subprograms) {
+		t.Errorf("saw only %d subprograms, expected %d", i, len(subprograms))
+	}
+}
diff --git a/src/debug/dwarf/line.go b/src/debug/dwarf/line.go
index ca64bbd..ed82fee 100644
--- a/src/debug/dwarf/line.go
+++ b/src/debug/dwarf/line.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -361,7 +361,7 @@ func (r *LineReader) step(entry *LineEntry) bool {
 		// 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
+		lineDelta := r.lineBase + adjustedOpcode%r.lineRange
 		r.state.Line += lineDelta
 		goto emit
 	}
diff --git a/src/debug/dwarf/line_test.go b/src/debug/dwarf/line_test.go
index 4104b5d..cc363f5 100644
--- a/src/debug/dwarf/line_test.go
+++ b/src/debug/dwarf/line_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/debug/dwarf/open.go b/src/debug/dwarf/open.go
index c1b3f37..0e9c01c 100644
--- a/src/debug/dwarf/open.go
+++ b/src/debug/dwarf/open.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -78,9 +78,9 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
 	return d, nil
 }
 
-// AddTypes will add one .debug_types section to the DWARF data.  A
+// AddTypes will add one .debug_types section to the DWARF data. A
 // typical object with DWARF version 4 debug info will have multiple
-// .debug_types sections.  The name is used for error reporting only,
+// .debug_types sections. The name is used for error reporting only,
 // and serves to distinguish one .debug_types section from another.
 func (d *Data) AddTypes(name string, types []byte) error {
 	return d.parseTypes(name, types)
diff --git a/src/debug/dwarf/testdata/ranges.c b/src/debug/dwarf/testdata/ranges.c
new file mode 100644
index 0000000..2f208e5
--- /dev/null
+++ b/src/debug/dwarf/testdata/ranges.c
@@ -0,0 +1,25 @@
+// gcc -g -O2 -freorder-blocks-and-partition
+
+const char *arr[10000];
+const char *hot = "hot";
+const char *cold = "cold";
+
+__attribute__((noinline))
+void fn(int path) {
+	int i;
+
+	if (path) {
+		for (i = 0; i < sizeof arr / sizeof arr[0]; i++) {
+			arr[i] = hot;
+		}
+	} else {
+		for (i = 0; i < sizeof arr / sizeof arr[0]; i++) {
+			arr[i] = cold;
+		}
+	}
+}
+
+int main(int argc, char *argv[]) {
+	fn(argc);
+	return 0;
+}
diff --git a/src/debug/dwarf/testdata/ranges.elf b/src/debug/dwarf/testdata/ranges.elf
new file mode 100755
index 0000000..7f54138
Binary files /dev/null and b/src/debug/dwarf/testdata/ranges.elf differ
diff --git a/src/debug/dwarf/testdata/typedef.c b/src/debug/dwarf/testdata/typedef.c
index f05f015..4780a0b 100644
--- a/src/debug/dwarf/testdata/typedef.c
+++ b/src/debug/dwarf/testdata/typedef.c
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/debug/dwarf/type.go b/src/debug/dwarf/type.go
index c76a472..9b39078 100644
--- a/src/debug/dwarf/type.go
+++ b/src/debug/dwarf/type.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -356,7 +356,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
 	}
 
 	// Get Type referred to by Entry's AttrType field.
-	// Set err if error happens.  Not having a type is an error.
+	// Set err if error happens. Not having a type is an error.
 	typeOf := func(e *Entry) Type {
 		tval := e.Val(AttrType)
 		var t Type
@@ -549,7 +549,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
 					bito = f.ByteOffset * 8
 				}
 				if bito == lastFieldBitOffset && t.Kind != "union" {
-					// Last field was zero width.  Fix array length.
+					// Last field was zero width. Fix array length.
 					// (DWARF writes out 0-length arrays as if they were 1-length arrays.)
 					zeroArray(lastFieldType)
 				}
@@ -560,7 +560,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
 		if t.Kind != "union" {
 			b, ok := e.Val(AttrByteSize).(int64)
 			if ok && b*8 == lastFieldBitOffset {
-				// Final field must be zero width.  Fix array length.
+				// Final field must be zero width. Fix array length.
 				zeroArray(lastFieldType)
 			}
 		}
diff --git a/src/debug/dwarf/type_test.go b/src/debug/dwarf/type_test.go
index ad6308d..0283466 100644
--- a/src/debug/dwarf/type_test.go
+++ b/src/debug/dwarf/type_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -34,7 +34,7 @@ var typedefTests = map[string]string{
 }
 
 // As Apple converts gcc to a clang-based front end
-// they keep breaking the DWARF output.  This map lists the
+// they keep breaking the DWARF output. This map lists the
 // conversion from real answer to Apple answer.
 var machoBug = map[string]string{
 	"func(*char, ...) void":                                 "func(*char) void",
diff --git a/src/debug/dwarf/typeunit.go b/src/debug/dwarf/typeunit.go
index 0f4e07e..652e02d 100644
--- a/src/debug/dwarf/typeunit.go
+++ b/src/debug/dwarf/typeunit.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -9,11 +9,11 @@ import (
 	"strconv"
 )
 
-// Parse the type units stored in a DWARF4 .debug_types section.  Each
+// Parse the type units stored in a DWARF4 .debug_types section. Each
 // type unit defines a single primary type and an 8-byte signature.
 // Other sections may then use formRefSig8 to refer to the type.
 
-// The typeUnit format is a single type with a signature.  It holds
+// The typeUnit format is a single type with a signature. It holds
 // the same data as a compilation unit.
 type typeUnit struct {
 	unit
@@ -76,7 +76,7 @@ func (d *Data) parseTypes(name string, types []byte) error {
 				data:   b.bytes(int(n - (b.off - hdroff))),
 				atable: atable,
 				asize:  int(asize),
-				vers:   int(vers),
+				vers:   vers,
 				is64:   dwarf64,
 			},
 			toff: Offset(toff),
@@ -101,7 +101,7 @@ func (d *Data) sigToType(sig uint64) (Type, error) {
 
 	b := makeBuf(d, tu, tu.name, tu.off, tu.data)
 	r := &typeUnitReader{d: d, tu: tu, b: b}
-	t, err := d.readType(tu.name, r, Offset(tu.toff), make(map[Offset]Type), nil)
+	t, err := d.readType(tu.name, r, tu.toff, make(map[Offset]Type), nil)
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/debug/dwarf/unit.go b/src/debug/dwarf/unit.go
index ceb6cdb..e45aed7 100644
--- a/src/debug/dwarf/unit.go
+++ b/src/debug/dwarf/unit.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/debug/elf/elf.go b/src/debug/elf/elf.go
index f53ba00..6e6c801 100644
--- a/src/debug/elf/elf.go
+++ b/src/debug/elf/elf.go
@@ -15,7 +15,7 @@
  *
  * 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.
+ * 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
@@ -1285,7 +1285,7 @@ const (
 	R_MIPS_LITERAL       R_MIPS = 8  /* Reference to literal section  */
 	R_MIPS_GOT16         R_MIPS = 9  /* Reference to global offset table */
 	R_MIPS_PC16          R_MIPS = 10 /* 16 bit PC relative reference */
-	R_MIPS_CALL16        R_MIPS = 11 /* 16 bit call thru glbl offset tbl */
+	R_MIPS_CALL16        R_MIPS = 11 /* 16 bit call through glbl offset tbl */
 	R_MIPS_GPREL32       R_MIPS = 12
 	R_MIPS_SHIFT5        R_MIPS = 16
 	R_MIPS_SHIFT6        R_MIPS = 17
@@ -1725,6 +1725,140 @@ var rppc64Strings = []intName{
 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 s390x processors.
+type R_390 int
+
+const (
+	R_390_NONE        R_390 = 0
+	R_390_8           R_390 = 1
+	R_390_12          R_390 = 2
+	R_390_16          R_390 = 3
+	R_390_32          R_390 = 4
+	R_390_PC32        R_390 = 5
+	R_390_GOT12       R_390 = 6
+	R_390_GOT32       R_390 = 7
+	R_390_PLT32       R_390 = 8
+	R_390_COPY        R_390 = 9
+	R_390_GLOB_DAT    R_390 = 10
+	R_390_JMP_SLOT    R_390 = 11
+	R_390_RELATIVE    R_390 = 12
+	R_390_GOTOFF      R_390 = 13
+	R_390_GOTPC       R_390 = 14
+	R_390_GOT16       R_390 = 15
+	R_390_PC16        R_390 = 16
+	R_390_PC16DBL     R_390 = 17
+	R_390_PLT16DBL    R_390 = 18
+	R_390_PC32DBL     R_390 = 19
+	R_390_PLT32DBL    R_390 = 20
+	R_390_GOTPCDBL    R_390 = 21
+	R_390_64          R_390 = 22
+	R_390_PC64        R_390 = 23
+	R_390_GOT64       R_390 = 24
+	R_390_PLT64       R_390 = 25
+	R_390_GOTENT      R_390 = 26
+	R_390_GOTOFF16    R_390 = 27
+	R_390_GOTOFF64    R_390 = 28
+	R_390_GOTPLT12    R_390 = 29
+	R_390_GOTPLT16    R_390 = 30
+	R_390_GOTPLT32    R_390 = 31
+	R_390_GOTPLT64    R_390 = 32
+	R_390_GOTPLTENT   R_390 = 33
+	R_390_GOTPLTOFF16 R_390 = 34
+	R_390_GOTPLTOFF32 R_390 = 35
+	R_390_GOTPLTOFF64 R_390 = 36
+	R_390_TLS_LOAD    R_390 = 37
+	R_390_TLS_GDCALL  R_390 = 38
+	R_390_TLS_LDCALL  R_390 = 39
+	R_390_TLS_GD32    R_390 = 40
+	R_390_TLS_GD64    R_390 = 41
+	R_390_TLS_GOTIE12 R_390 = 42
+	R_390_TLS_GOTIE32 R_390 = 43
+	R_390_TLS_GOTIE64 R_390 = 44
+	R_390_TLS_LDM32   R_390 = 45
+	R_390_TLS_LDM64   R_390 = 46
+	R_390_TLS_IE32    R_390 = 47
+	R_390_TLS_IE64    R_390 = 48
+	R_390_TLS_IEENT   R_390 = 49
+	R_390_TLS_LE32    R_390 = 50
+	R_390_TLS_LE64    R_390 = 51
+	R_390_TLS_LDO32   R_390 = 52
+	R_390_TLS_LDO64   R_390 = 53
+	R_390_TLS_DTPMOD  R_390 = 54
+	R_390_TLS_DTPOFF  R_390 = 55
+	R_390_TLS_TPOFF   R_390 = 56
+	R_390_20          R_390 = 57
+	R_390_GOT20       R_390 = 58
+	R_390_GOTPLT20    R_390 = 59
+	R_390_TLS_GOTIE20 R_390 = 60
+)
+
+var r390Strings = []intName{
+	{0, "R_390_NONE"},
+	{1, "R_390_8"},
+	{2, "R_390_12"},
+	{3, "R_390_16"},
+	{4, "R_390_32"},
+	{5, "R_390_PC32"},
+	{6, "R_390_GOT12"},
+	{7, "R_390_GOT32"},
+	{8, "R_390_PLT32"},
+	{9, "R_390_COPY"},
+	{10, "R_390_GLOB_DAT"},
+	{11, "R_390_JMP_SLOT"},
+	{12, "R_390_RELATIVE"},
+	{13, "R_390_GOTOFF"},
+	{14, "R_390_GOTPC"},
+	{15, "R_390_GOT16"},
+	{16, "R_390_PC16"},
+	{17, "R_390_PC16DBL"},
+	{18, "R_390_PLT16DBL"},
+	{19, "R_390_PC32DBL"},
+	{20, "R_390_PLT32DBL"},
+	{21, "R_390_GOTPCDBL"},
+	{22, "R_390_64"},
+	{23, "R_390_PC64"},
+	{24, "R_390_GOT64"},
+	{25, "R_390_PLT64"},
+	{26, "R_390_GOTENT"},
+	{27, "R_390_GOTOFF16"},
+	{28, "R_390_GOTOFF64"},
+	{29, "R_390_GOTPLT12"},
+	{30, "R_390_GOTPLT16"},
+	{31, "R_390_GOTPLT32"},
+	{32, "R_390_GOTPLT64"},
+	{33, "R_390_GOTPLTENT"},
+	{34, "R_390_GOTPLTOFF16"},
+	{35, "R_390_GOTPLTOFF32"},
+	{36, "R_390_GOTPLTOFF64"},
+	{37, "R_390_TLS_LOAD"},
+	{38, "R_390_TLS_GDCALL"},
+	{39, "R_390_TLS_LDCALL"},
+	{40, "R_390_TLS_GD32"},
+	{41, "R_390_TLS_GD64"},
+	{42, "R_390_TLS_GOTIE12"},
+	{43, "R_390_TLS_GOTIE32"},
+	{44, "R_390_TLS_GOTIE64"},
+	{45, "R_390_TLS_LDM32"},
+	{46, "R_390_TLS_LDM64"},
+	{47, "R_390_TLS_IE32"},
+	{48, "R_390_TLS_IE64"},
+	{49, "R_390_TLS_IEENT"},
+	{50, "R_390_TLS_LE32"},
+	{51, "R_390_TLS_LE64"},
+	{52, "R_390_TLS_LDO32"},
+	{53, "R_390_TLS_LDO64"},
+	{54, "R_390_TLS_DTPMOD"},
+	{55, "R_390_TLS_DTPOFF"},
+	{56, "R_390_TLS_TPOFF"},
+	{57, "R_390_20"},
+	{58, "R_390_GOT20"},
+	{59, "R_390_GOTPLT20"},
+	{60, "R_390_TLS_GOTIE20"},
+}
+
+func (i R_390) String() string   { return stringName(uint32(i), r390Strings, false) }
+func (i R_390) GoString() string { return stringName(uint32(i), r390Strings, true) }
+
 // Relocation types for SPARC.
 type R_SPARC int
 
@@ -1896,7 +2030,7 @@ type Prog32 struct {
 	Align  uint32 /* Alignment in memory and file. */
 }
 
-// ELF32 Dynamic structure.  The ".dynamic" section contains an array of them.
+// ELF32 Dynamic structure. The ".dynamic" section contains an array of them.
 type Dyn32 struct {
 	Tag int32  /* Entry type. */
 	Val uint32 /* Integer/Address value. */
@@ -1926,8 +2060,8 @@ type Rela32 struct {
 	Addend int32  /* Addend. */
 }
 
-func R_SYM32(info uint32) uint32      { return uint32(info >> 8) }
-func R_TYPE32(info uint32) uint32     { return uint32(info & 0xff) }
+func R_SYM32(info uint32) uint32      { return info >> 8 }
+func R_TYPE32(info uint32) uint32     { return info & 0xff }
 func R_INFO32(sym, typ uint32) uint32 { return sym<<8 | typ }
 
 // ELF32 Symbol.
@@ -1997,7 +2131,7 @@ type Prog64 struct {
 	Align  uint64 /* Alignment in memory and file. */
 }
 
-// ELF64 Dynamic structure.  The ".dynamic" section contains an array of them.
+// ELF64 Dynamic structure. The ".dynamic" section contains an array of them.
 type Dyn64 struct {
 	Tag int64  /* Entry type. */
 	Val uint64 /* Integer/address value */
diff --git a/src/debug/elf/elf_test.go b/src/debug/elf/elf_test.go
index e3c51bb..f8985a8 100644
--- a/src/debug/elf/elf_test.go
+++ b/src/debug/elf/elf_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/debug/elf/file.go b/src/debug/elf/file.go
index 199aa4e..c173ea9 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -269,7 +269,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 	switch f.Class {
 	case ELFCLASS32:
 		hdr := new(Header32)
-		sr.Seek(0, os.SEEK_SET)
+		sr.Seek(0, io.SeekStart)
 		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
 			return nil, err
 		}
@@ -288,13 +288,13 @@ func NewFile(r io.ReaderAt) (*File, error) {
 		shstrndx = int(hdr.Shstrndx)
 	case ELFCLASS64:
 		hdr := new(Header64)
-		sr.Seek(0, os.SEEK_SET)
+		sr.Seek(0, io.SeekStart)
 		if err := binary.Read(sr, f.ByteOrder, hdr); err != nil {
 			return nil, err
 		}
 		f.Type = Type(hdr.Type)
 		f.Machine = Machine(hdr.Machine)
-		f.Entry = uint64(hdr.Entry)
+		f.Entry = hdr.Entry
 		if v := Version(hdr.Version); v != f.Version {
 			return nil, &FormatError{0, "mismatched ELF version", v}
 		}
@@ -315,7 +315,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 	f.Progs = make([]*Prog, phnum)
 	for i := 0; i < phnum; i++ {
 		off := phoff + int64(i)*int64(phentsize)
-		sr.Seek(off, os.SEEK_SET)
+		sr.Seek(off, io.SeekStart)
 		p := new(Prog)
 		switch f.Class {
 		case ELFCLASS32:
@@ -341,12 +341,12 @@ func NewFile(r io.ReaderAt) (*File, error) {
 			p.ProgHeader = ProgHeader{
 				Type:   ProgType(ph.Type),
 				Flags:  ProgFlag(ph.Flags),
-				Off:    uint64(ph.Off),
-				Vaddr:  uint64(ph.Vaddr),
-				Paddr:  uint64(ph.Paddr),
-				Filesz: uint64(ph.Filesz),
-				Memsz:  uint64(ph.Memsz),
-				Align:  uint64(ph.Align),
+				Off:    ph.Off,
+				Vaddr:  ph.Vaddr,
+				Paddr:  ph.Paddr,
+				Filesz: ph.Filesz,
+				Memsz:  ph.Memsz,
+				Align:  ph.Align,
 			}
 		}
 		p.sr = io.NewSectionReader(r, int64(p.Off), int64(p.Filesz))
@@ -359,7 +359,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
 	names := make([]uint32, shnum)
 	for i := 0; i < shnum; i++ {
 		off := shoff + int64(i)*int64(shentsize)
-		sr.Seek(off, os.SEEK_SET)
+		sr.Seek(off, io.SeekStart)
 		s := new(Section)
 		switch f.Class {
 		case ELFCLASS32:
@@ -374,8 +374,8 @@ func NewFile(r io.ReaderAt) (*File, error) {
 				Addr:      uint64(sh.Addr),
 				Offset:    uint64(sh.Off),
 				FileSize:  uint64(sh.Size),
-				Link:      uint32(sh.Link),
-				Info:      uint32(sh.Info),
+				Link:      sh.Link,
+				Info:      sh.Info,
 				Addralign: uint64(sh.Addralign),
 				Entsize:   uint64(sh.Entsize),
 			}
@@ -388,13 +388,13 @@ func NewFile(r io.ReaderAt) (*File, error) {
 			s.SectionHeader = SectionHeader{
 				Type:      SectionType(sh.Type),
 				Flags:     SectionFlag(sh.Flags),
-				Offset:    uint64(sh.Off),
-				FileSize:  uint64(sh.Size),
-				Addr:      uint64(sh.Addr),
-				Link:      uint32(sh.Link),
-				Info:      uint32(sh.Info),
-				Addralign: uint64(sh.Addralign),
-				Entsize:   uint64(sh.Entsize),
+				Offset:    sh.Off,
+				FileSize:  sh.Size,
+				Addr:      sh.Addr,
+				Link:      sh.Link,
+				Info:      sh.Info,
+				Addralign: sh.Addralign,
+				Entsize:   sh.Entsize,
 			}
 		}
 		s.sr = io.NewSectionReader(r, int64(s.Offset), int64(s.FileSize))
@@ -596,6 +596,8 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
 		return f.applyRelocationsPPC64(dst, rels)
 	case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
 		return f.applyRelocationsMIPS64(dst, rels)
+	case f.Class == ELFCLASS64 && f.Machine == EM_S390:
+		return f.applyRelocationss390x(dst, rels)
 	default:
 		return errors.New("applyRelocations: not implemented")
 	}
@@ -911,6 +913,55 @@ func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
 	return nil
 }
 
+func (f *File) applyRelocationss390x(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_390(rela.Info & 0xffff)
+
+		if symNo == 0 || symNo > uint64(len(symbols)) {
+			continue
+		}
+		sym := &symbols[symNo-1]
+		switch SymType(sym.Info & 0xf) {
+		case STT_SECTION, STT_NOTYPE:
+			break
+		default:
+			continue
+		}
+
+		switch t {
+		case R_390_64:
+			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+				continue
+			}
+			val := sym.Value + uint64(rela.Addend)
+			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], val)
+		case R_390_32:
+			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+				continue
+			}
+			val := uint32(sym.Value) + uint32(rela.Addend)
+			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], val)
+		}
+	}
+
+	return nil
+}
+
 func (f *File) DWARF() (*dwarf.Data, error) {
 	// sectionData gets the data for s, checks its size, and
 	// applies any applicable relations.
@@ -958,7 +1009,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 	// 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}
+	var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
 	for i, s := range f.Sections {
 		suffix := ""
 		switch {
@@ -979,7 +1030,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 		dat[suffix] = b
 	}
 
-	d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, nil, dat["str"])
+	d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go
index 5c0df0f..b189219 100644
--- a/src/debug/elf/file_test.go
+++ b/src/debug/elf/file_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -473,6 +473,25 @@ var relocationTests = []relocationTest{
 		},
 	},
 	{
+		"testdata/go-relocation-test-gcc531-s390x.obj",
+		[]relocationTestEntry{
+			{0, &dwarf.Entry{
+				Offset:   0xb,
+				Tag:      dwarf.TagCompileUnit,
+				Children: true,
+				Field: []dwarf.Field{
+					{Attr: dwarf.AttrProducer, Val: "GNU C11 5.3.1 20160316 -march=zEC12 -m64 -mzarch -g -fstack-protector-strong", Class: dwarf.ClassString},
+					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
+					{Attr: dwarf.AttrName, Val: "hello.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: int64(58), Class: dwarf.ClassConstant},
+					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+				},
+			}},
+		},
+	},
+	{
 		"testdata/go-relocation-test-gcc493-mips64le.obj",
 		[]relocationTestEntry{
 			{0, &dwarf.Entry{
@@ -636,7 +655,7 @@ func TestCompressedSection(t *testing.T) {
 	// Test Open method and seeking.
 	buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
 	sf := sec.Open()
-	if got, err := sf.Seek(0, 2); got != int64(len(b)) || err != nil {
+	if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil {
 		t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
 	}
 	if n, err := sf.Read(buf); n != 0 || err != io.EOF {
@@ -649,11 +668,11 @@ func TestCompressedSection(t *testing.T) {
 		target := rand.Int63n(int64(len(buf)))
 		var offset int64
 		switch whence {
-		case 0:
+		case io.SeekStart:
 			offset = target
-		case 1:
+		case io.SeekCurrent:
 			offset = target - pos
-		case 2:
+		case io.SeekEnd:
 			offset = target - int64(len(buf))
 		}
 		pos, err = sf.Seek(offset, whence)
@@ -669,7 +688,7 @@ func TestCompressedSection(t *testing.T) {
 		if end > int64(len(buf)) {
 			end = int64(len(buf))
 		}
-		n, err := sf.Read(buf[pos:end])
+		n, err := io.ReadFull(sf, buf[pos:end])
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/src/debug/elf/reader.go b/src/debug/elf/reader.go
index 17b5716..eab4373 100644
--- a/src/debug/elf/reader.go
+++ b/src/debug/elf/reader.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -63,11 +63,11 @@ func (r *readSeekerFromReader) Read(p []byte) (n int, err error) {
 func (r *readSeekerFromReader) Seek(offset int64, whence int) (int64, error) {
 	var newOffset int64
 	switch whence {
-	case 0:
+	case io.SeekStart:
 		newOffset = offset
-	case 1:
+	case io.SeekCurrent:
 		newOffset = r.offset + offset
-	case 2:
+	case io.SeekEnd:
 		newOffset = r.size + offset
 	default:
 		return 0, os.ErrInvalid
diff --git a/src/debug/elf/testdata/go-relocation-test-gcc531-s390x.obj b/src/debug/elf/testdata/go-relocation-test-gcc531-s390x.obj
new file mode 100644
index 0000000..caacb9b
Binary files /dev/null and b/src/debug/elf/testdata/go-relocation-test-gcc531-s390x.obj differ
diff --git a/src/debug/elf/testdata/hello-world-core.gz b/src/debug/elf/testdata/hello-world-core.gz
index 806af6e..6d76ab0 100644
Binary files a/src/debug/elf/testdata/hello-world-core.gz and b/src/debug/elf/testdata/hello-world-core.gz differ
diff --git a/src/debug/gosym/pclntab.go b/src/debug/gosym/pclntab.go
index 6620aef..e859d5a 100644
--- a/src/debug/gosym/pclntab.go
+++ b/src/debug/gosym/pclntab.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -53,7 +53,7 @@ const oldQuantum = 1
 func (t *LineTable) parse(targetPC uint64, targetLine int) (b []byte, pc uint64, line int) {
 	// The PC/line table can be thought of as a sequence of
 	//  <pc update>* <line update>
-	// batches.  Each update batch results in a (pc, line) pair,
+	// batches. Each update batch results in a (pc, line) pair,
 	// where line applies to every PC from pc up to but not
 	// including the pc of the next pair.
 	//
@@ -167,7 +167,7 @@ func (t *LineTable) go12Init() {
 	// Check header: 4-byte magic, two zeros, pc quantum, pointer size.
 	t.go12 = -1 // not Go 1.2 until proven otherwise
 	if len(t.Data) < 16 || t.Data[4] != 0 || t.Data[5] != 0 ||
-		(t.Data[6] != 1 && t.Data[6] != 4) || // pc quantum
+		(t.Data[6] != 1 && t.Data[6] != 2 && t.Data[6] != 4) || // pc quantum
 		(t.Data[7] != 4 && t.Data[7] != 8) { // pointer size
 		return
 	}
@@ -207,8 +207,8 @@ func (t *LineTable) go12Funcs() []Func {
 	funcs := make([]Func, n)
 	for i := range funcs {
 		f := &funcs[i]
-		f.Entry = uint64(t.uintptr(t.functab[2*i*int(t.ptrsize):]))
-		f.End = uint64(t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):]))
+		f.Entry = t.uintptr(t.functab[2*i*int(t.ptrsize):])
+		f.End = t.uintptr(t.functab[(2*i+2)*int(t.ptrsize):])
 		info := t.Data[t.uintptr(t.functab[(2*i+1)*int(t.ptrsize):]):]
 		f.LineTable = t
 		f.FrameSize = int(t.binary.Uint32(info[t.ptrsize+2*4:]))
diff --git a/src/debug/gosym/pclntab_test.go b/src/debug/gosym/pclntab_test.go
index 8d4aa54..9f82e31 100644
--- a/src/debug/gosym/pclntab_test.go
+++ b/src/debug/gosym/pclntab_test.go
@@ -1,10 +1,11 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 gosym
 
 import (
+	"bytes"
 	"debug/elf"
 	"internal/testenv"
 	"io/ioutil"
@@ -42,7 +43,22 @@ func dotest(t *testing.T) {
 	if err := cmd.Run(); err != nil {
 		t.Fatal(err)
 	}
-	cmd = exec.Command("go", "tool", "link", "-H", "linux", "-E", "main",
+
+	// stamp .o file as being 'package main' so that go tool link will accept it
+	data, err := ioutil.ReadFile(pclinetestBinary + ".o")
+	if err != nil {
+		t.Fatal(err)
+	}
+	i := bytes.IndexByte(data, '\n')
+	if i < 0 {
+		t.Fatal("bad binary")
+	}
+	data = append(append(data[:i:i], "\nmain"...), data[i:]...)
+	if err := ioutil.WriteFile(pclinetestBinary+".o", data, 0666); err != nil {
+		t.Fatal(err)
+	}
+
+	cmd = exec.Command("go", "tool", "link", "-H", "linux",
 		"-o", pclinetestBinary, pclinetestBinary+".o")
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
@@ -111,8 +127,6 @@ func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
 	return f, tab
 }
 
-var goarch = os.Getenv("O")
-
 func TestLineFromAline(t *testing.T) {
 	skipIfNotELF(t)
 
@@ -210,6 +224,7 @@ func TestPCLine(t *testing.T) {
 	defer endtest()
 
 	f, tab := crack(pclinetestBinary, t)
+	defer f.Close()
 	text := f.Section(".text")
 	textdat, err := text.Data()
 	if err != nil {
diff --git a/src/debug/gosym/symtab.go b/src/debug/gosym/symtab.go
index 46f0783..f5f9963 100644
--- a/src/debug/gosym/symtab.go
+++ b/src/debug/gosym/symtab.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,7 +8,7 @@
 package gosym
 
 // The table format is a variant of the format used in Plan 9's a.out
-// format, documented at http://plan9.bell-labs.com/magic/man2html/6/a.out.
+// format, documented at https://9p.io/magic/man2html/6/a.out.
 // The best reference for the differences between the Plan 9 format
 // and the Go format is the runtime source, specifically ../../runtime/symtab.c.
 
@@ -40,8 +40,13 @@ func (s *Sym) Static() bool { return s.Type >= 'a' }
 // PackageName returns the package part of the symbol name,
 // or the empty string if there is none.
 func (s *Sym) PackageName() string {
-	if i := strings.Index(s.Name, "."); i != -1 {
-		return s.Name[0:i]
+	pathend := strings.LastIndex(s.Name, "/")
+	if pathend < 0 {
+		pathend = 0
+	}
+
+	if i := strings.Index(s.Name[pathend:], "."); i != -1 {
+		return s.Name[:pathend+i]
 	}
 	return ""
 }
@@ -49,12 +54,16 @@ func (s *Sym) PackageName() string {
 // ReceiverName returns the receiver type name of this symbol,
 // or the empty string if there is none.
 func (s *Sym) ReceiverName() string {
-	l := strings.Index(s.Name, ".")
-	r := strings.LastIndex(s.Name, ".")
+	pathend := strings.LastIndex(s.Name, "/")
+	if pathend < 0 {
+		pathend = 0
+	}
+	l := strings.Index(s.Name[pathend:], ".")
+	r := strings.LastIndex(s.Name[pathend:], ".")
 	if l == -1 || r == -1 || l == r {
 		return ""
 	}
-	return s.Name[l+1 : r]
+	return s.Name[pathend+l+1 : pathend+r]
 }
 
 // BaseName returns the symbol name without the package or receiver name.
@@ -103,7 +112,7 @@ type Obj struct {
  * Symbol tables
  */
 
-// Table represents a Go symbol table.  It stores all of the
+// Table represents a Go symbol table. It stores all of the
 // symbols decoded from the program and provides methods to translate
 // between symbols, names, and addresses.
 type Table struct {
@@ -294,8 +303,8 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
 		t.Syms = t.Syms[0 : n+1]
 		ts := &t.Syms[n]
 		ts.Type = s.typ
-		ts.Value = uint64(s.value)
-		ts.GoType = uint64(s.gotype)
+		ts.Value = s.value
+		ts.GoType = s.gotype
 		switch s.typ {
 		default:
 			// rewrite name to use . instead of · (c2 b7)
@@ -353,7 +362,7 @@ func NewTable(symtab []byte, pcln *LineTable) (*Table, error) {
 	}
 
 	// Count text symbols and attach frame sizes, parameters, and
-	// locals to them.  Also, find object file boundaries.
+	// locals to them. Also, find object file boundaries.
 	lastf := 0
 	for i := 0; i < len(t.Syms); i++ {
 		sym := &t.Syms[i]
@@ -503,7 +512,7 @@ func (t *Table) PCToLine(pc uint64) (file string, line int, fn *Func) {
 }
 
 // LineToPC looks up the first program counter on the given line in
-// the named file.  It returns UnknownPathError or UnknownLineError if
+// the named file. It returns UnknownPathError or UnknownLineError if
 // there is an error looking up this line.
 func (t *Table) LineToPC(file string, line int) (pc uint64, fn *Func, err error) {
 	obj, ok := t.Files[file]
diff --git a/src/debug/gosym/symtab_test.go b/src/debug/gosym/symtab_test.go
new file mode 100644
index 0000000..08e8633
--- /dev/null
+++ b/src/debug/gosym/symtab_test.go
@@ -0,0 +1,43 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gosym
+
+import (
+	"fmt"
+	"testing"
+)
+
+func assertString(t *testing.T, dsc, out, tgt string) {
+	if out != tgt {
+		t.Fatalf("Expected: %q Actual: %q for %s", tgt, out, dsc)
+	}
+}
+
+func TestStandardLibPackage(t *testing.T) {
+	s1 := Sym{Name: "io.(*LimitedReader).Read"}
+	s2 := Sym{Name: "io.NewSectionReader"}
+	assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "io")
+	assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "io")
+	assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*LimitedReader)")
+	assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
+}
+
+func TestStandardLibPathPackage(t *testing.T) {
+	s1 := Sym{Name: "debug/gosym.(*LineTable).PCToLine"}
+	s2 := Sym{Name: "debug/gosym.NewTable"}
+	assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "debug/gosym")
+	assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "debug/gosym")
+	assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*LineTable)")
+	assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
+}
+
+func TestRemotePackage(t *testing.T) {
+	s1 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.(*FlagSet).PrintDefaults"}
+	s2 := Sym{Name: "github.com/docker/doc.ker/pkg/mflag.PrintDefaults"}
+	assertString(t, fmt.Sprintf("package of %q", s1.Name), s1.PackageName(), "github.com/docker/doc.ker/pkg/mflag")
+	assertString(t, fmt.Sprintf("package of %q", s2.Name), s2.PackageName(), "github.com/docker/doc.ker/pkg/mflag")
+	assertString(t, fmt.Sprintf("receiver of %q", s1.Name), s1.ReceiverName(), "(*FlagSet)")
+	assertString(t, fmt.Sprintf("receiver of %q", s2.Name), s2.ReceiverName(), "")
+}
diff --git a/src/debug/macho/fat.go b/src/debug/macho/fat.go
index 93b8315..6bd730d 100644
--- a/src/debug/macho/fat.go
+++ b/src/debug/macho/fat.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -122,18 +122,18 @@ func NewFatFile(r io.ReaderAt) (*FatFile, error) {
 
 // OpenFat opens the named file using os.Open and prepares it for use as a Mach-O
 // universal binary.
-func OpenFat(name string) (ff *FatFile, err error) {
+func OpenFat(name string) (*FatFile, error) {
 	f, err := os.Open(name)
 	if err != nil {
 		return nil, err
 	}
-	ff, err = NewFatFile(f)
+	ff, err := NewFatFile(f)
 	if err != nil {
 		f.Close()
 		return nil, err
 	}
 	ff.closer = f
-	return
+	return ff, nil
 }
 
 func (ff *FatFile) Close() error {
diff --git a/src/debug/macho/file.go b/src/debug/macho/file.go
index a7599aa..223346f 100644
--- a/src/debug/macho/file.go
+++ b/src/debug/macho/file.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -474,7 +474,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 	// There are many other DWARF sections, but these
 	// are the ones the debug/dwarf package uses.
 	// Don't bother loading others.
-	var names = [...]string{"abbrev", "info", "line", "str"}
+	var names = [...]string{"abbrev", "info", "line", "ranges", "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, line, str := dat[0], dat[1], dat[2], dat[3]
-	return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
+	abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
+	return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
 }
 
 // ImportedSymbols returns the names of all symbols
diff --git a/src/debug/macho/file_test.go b/src/debug/macho/file_test.go
index 4797780..9ff6c5d 100644
--- a/src/debug/macho/file_test.go
+++ b/src/debug/macho/file_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/debug/macho/macho.go b/src/debug/macho/macho.go
index d9678c8..3164753 100644
--- a/src/debug/macho/macho.go
+++ b/src/debug/macho/macho.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -291,26 +291,3 @@ func stringName(i uint32, names []intName, goSyntax bool) string {
 	}
 	return strconv.FormatUint(uint64(i), 10)
 }
-
-func flagName(i uint32, names []intName, goSyntax bool) string {
-	s := ""
-	for _, n := range names {
-		if n.i&i == n.i {
-			if len(s) > 0 {
-				s += "+"
-			}
-			if goSyntax {
-				s += "macho."
-			}
-			s += n.s
-			i -= n.i
-		}
-	}
-	if len(s) == 0 {
-		return "0x" + strconv.FormatUint(uint64(i), 16)
-	}
-	if i != 0 {
-		s += "+0x" + strconv.FormatUint(uint64(i), 16)
-	}
-	return s
-}
diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go
index 3df4ae7..3074ba0 100644
--- a/src/debug/pe/file.go
+++ b/src/debug/pe/file.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,11 +8,9 @@ package pe
 import (
 	"debug/dwarf"
 	"encoding/binary"
-	"errors"
 	"fmt"
 	"io"
 	"os"
-	"strconv"
 )
 
 // A File represents an open PE file.
@@ -20,83 +18,13 @@ type File struct {
 	FileHeader
 	OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
 	Sections       []*Section
-	Symbols        []*Symbol
+	Symbols        []*Symbol    // COFF symbols with auxiliary symbol records removed
+	_COFFSymbols   []COFFSymbol // all COFF symbols (including auxiliary symbol records)
+	_StringTable   _StringTable
 
 	closer io.Closer
 }
 
-type SectionHeader struct {
-	Name                 string
-	VirtualSize          uint32
-	VirtualAddress       uint32
-	Size                 uint32
-	Offset               uint32
-	PointerToRelocations uint32
-	PointerToLineNumbers uint32
-	NumberOfRelocations  uint16
-	NumberOfLineNumbers  uint16
-	Characteristics      uint32
-}
-
-type Section struct {
-	SectionHeader
-
-	// Embed ReaderAt for ReadAt method.
-	// Do not embed SectionReader directly
-	// to avoid having Read and Seek.
-	// If a client wants Read and Seek it must use
-	// Open() to avoid fighting over the seek offset
-	// with other clients.
-	io.ReaderAt
-	sr *io.SectionReader
-}
-
-type Symbol struct {
-	Name          string
-	Value         uint32
-	SectionNumber int16
-	Type          uint16
-	StorageClass  uint8
-}
-
-type ImportDirectory struct {
-	OriginalFirstThunk uint32
-	TimeDateStamp      uint32
-	ForwarderChain     uint32
-	Name               uint32
-	FirstThunk         uint32
-
-	dll string
-}
-
-// Data reads and returns the contents of the PE section.
-func (s *Section) Data() ([]byte, error) {
-	dat := make([]byte, s.sr.Size())
-	n, err := s.sr.ReadAt(dat, 0)
-	if n == len(dat) {
-		err = nil
-	}
-	return dat[0:n], err
-}
-
-// Open returns a new ReadSeeker reading the PE section.
-func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
-
-type FormatError struct {
-	off int64
-	msg string
-	val interface{}
-}
-
-func (e *FormatError) Error() string {
-	msg := e.msg
-	if e.val != nil {
-		msg += fmt.Sprintf(" '%v'", e.val)
-	}
-	msg += fmt.Sprintf(" in record at byte %#x", e.off)
-	return msg
-}
-
 // Open opens the named file using os.Open and prepares it for use as a PE binary.
 func Open(name string) (*File, error) {
 	f, err := os.Open(name)
@@ -129,6 +57,8 @@ var (
 	sizeofOptionalHeader64 = uint16(binary.Size(OptionalHeader64{}))
 )
 
+// TODO(brainman): add Load function, as a replacement for NewFile, that does not call removeAuxSymbols (for performance)
+
 // NewFile creates a new File for accessing a PE binary in an underlying reader.
 func NewFile(r io.ReaderAt) (*File, error) {
 	f := new(File)
@@ -144,66 +74,42 @@ func NewFile(r io.ReaderAt) (*File, error) {
 		var sign [4]byte
 		r.ReadAt(sign[:], signoff)
 		if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
-			return nil, errors.New("Invalid PE File Format.")
+			return nil, fmt.Errorf("Invalid PE COFF file signature of %v.", sign)
 		}
 		base = signoff + 4
 	} else {
 		base = int64(0)
 	}
-	sr.Seek(base, os.SEEK_SET)
+	sr.Seek(base, io.SeekStart)
 	if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
 		return nil, err
 	}
-	if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
-		return nil, errors.New("Invalid PE File Format.")
+	switch f.FileHeader.Machine {
+	case IMAGE_FILE_MACHINE_UNKNOWN, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386:
+	default:
+		return nil, fmt.Errorf("Unrecognised COFF file header machine value of 0x%x.", f.FileHeader.Machine)
 	}
 
-	var ss []byte
-	if f.FileHeader.NumberOfSymbols > 0 {
-		// Get COFF string table, which is located at the end of the COFF symbol table.
-		sr.Seek(int64(f.FileHeader.PointerToSymbolTable+COFFSymbolSize*f.FileHeader.NumberOfSymbols), os.SEEK_SET)
-		var l uint32
-		if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
-			return nil, err
-		}
-		ss = make([]byte, l)
-		if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+COFFSymbolSize*f.FileHeader.NumberOfSymbols)); err != nil {
-			return nil, err
-		}
+	var err error
 
-		// Process COFF symbol table.
-		sr.Seek(int64(f.FileHeader.PointerToSymbolTable), os.SEEK_SET)
-		aux := uint8(0)
-		for i := 0; i < int(f.FileHeader.NumberOfSymbols); i++ {
-			cs := new(COFFSymbol)
-			if err := binary.Read(sr, binary.LittleEndian, cs); err != nil {
-				return nil, err
-			}
-			if aux > 0 {
-				aux--
-				continue
-			}
-			var name string
-			if cs.Name[0] == 0 && cs.Name[1] == 0 && cs.Name[2] == 0 && cs.Name[3] == 0 {
-				si := int(binary.LittleEndian.Uint32(cs.Name[4:]))
-				name, _ = getString(ss, si)
-			} else {
-				name = cstring(cs.Name[:])
-			}
-			aux = cs.NumberOfAuxSymbols
-			s := &Symbol{
-				Name:          name,
-				Value:         cs.Value,
-				SectionNumber: cs.SectionNumber,
-				Type:          cs.Type,
-				StorageClass:  cs.StorageClass,
-			}
-			f.Symbols = append(f.Symbols, s)
-		}
+	// Read string table.
+	f._StringTable, err = readStringTable(&f.FileHeader, sr)
+	if err != nil {
+		return nil, err
+	}
+
+	// Read symbol table.
+	f._COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr)
+	if err != nil {
+		return nil, err
+	}
+	f.Symbols, err = removeAuxSymbols(f._COFFSymbols, f._StringTable)
+	if err != nil {
+		return nil, err
 	}
 
 	// Read optional header.
-	sr.Seek(base, os.SEEK_SET)
+	sr.Seek(base, io.SeekStart)
 	if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
 		return nil, err
 	}
@@ -235,12 +141,9 @@ func NewFile(r io.ReaderAt) (*File, error) {
 		if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
 			return nil, err
 		}
-		var name string
-		if sh.Name[0] == '\x2F' {
-			si, _ := strconv.Atoi(cstring(sh.Name[1:]))
-			name, _ = getString(ss, si)
-		} else {
-			name = cstring(sh.Name[0:])
+		name, err := sh.fullName(f._StringTable)
+		if err != nil {
+			return nil, err
 		}
 		s := new(Section)
 		s.SectionHeader = SectionHeader{
@@ -255,18 +158,34 @@ func NewFile(r io.ReaderAt) (*File, error) {
 			NumberOfLineNumbers:  sh.NumberOfLineNumbers,
 			Characteristics:      sh.Characteristics,
 		}
-		s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
+		r2 := r
+		if sh.PointerToRawData == 0 { // .bss must have all 0s
+			r2 = zeroReaderAt{}
+		}
+		s.sr = io.NewSectionReader(r2, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
 		s.ReaderAt = s.sr
 		f.Sections[i] = s
 	}
+	for i := range f.Sections {
+		var err error
+		f.Sections[i]._Relocs, err = readRelocs(&f.Sections[i].SectionHeader, sr)
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	return f, nil
 }
 
-func cstring(b []byte) string {
-	var i int
-	for i = 0; i < len(b) && b[i] != 0; i++ {
+// zeroReaderAt is ReaderAt that reads 0s.
+type zeroReaderAt struct{}
+
+// ReadAt writes len(p) 0s into p.
+func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
+	for i := range p {
+		p[i] = 0
 	}
-	return string(b[0:i])
+	return len(p), nil
 }
 
 // getString extracts a string from symbol string table.
@@ -298,7 +217,7 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 	// There are many other DWARF sections, but these
 	// are the ones the debug/dwarf package uses.
 	// Don't bother loading others.
-	var names = [...]string{"abbrev", "info", "line", "str"}
+	var names = [...]string{"abbrev", "info", "line", "ranges", "str"}
 	var dat [len(names)][]byte
 	for i, name := range names {
 		name = ".debug_" + name
@@ -316,8 +235,20 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 		dat[i] = b
 	}
 
-	abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
-	return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
+	abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
+	return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+}
+
+// TODO(brainman): document ImportDirectory once we decide what to do with it.
+
+type ImportDirectory struct {
+	OriginalFirstThunk uint32
+	TimeDateStamp      uint32
+	ForwarderChain     uint32
+	Name               uint32
+	FirstThunk         uint32
+
+	dll string
 }
 
 // ImportedSymbols returns the names of all symbols
@@ -347,6 +278,12 @@ func (f *File) ImportedSymbols() ([]string, error) {
 		}
 		ida = append(ida, dt)
 	}
+	// TODO(brainman): this needs to be rewritten
+	//  ds.Data() return contets of .idata section. Why store in variable called "names"?
+	//  Why we are retrieving it second time? We already have it in "d", and it is not modified anywhere.
+	//  getString does not extracts a string from symbol string table (as getString doco says).
+	//  Why ds.Data() called again and again in the loop?
+	//  Needs test before rewrite.
 	names, _ := ds.Data()
 	var all []string
 	for _, dt := range ida {
@@ -395,3 +332,12 @@ func (f *File) ImportedLibraries() ([]string, error) {
 	// cgo -dynimport don't use this for windows PE, so just return.
 	return nil, nil
 }
+
+// FormatError is unused.
+// The type is retained for compatibility.
+type FormatError struct {
+}
+
+func (e *FormatError) Error() string {
+	return "unknown error"
+}
diff --git a/src/debug/pe/file_test.go b/src/debug/pe/file_test.go
index 316a569..964caf5 100644
--- a/src/debug/pe/file_test.go
+++ b/src/debug/pe/file_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,6 +6,7 @@ package pe
 
 import (
 	"debug/dwarf"
+	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -104,6 +105,41 @@ var fileTests = []fileTest{
 		},
 	},
 	{
+		file: "testdata/gcc-386-mingw-no-symbols-exec",
+		hdr:  FileHeader{0x14c, 0x8, 0x69676572, 0x0, 0x0, 0xe0, 0x30f},
+		opthdr: &OptionalHeader32{0x10b, 0x2, 0x18, 0xe00, 0x1e00, 0x200, 0x1280, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x9000, 0x400, 0x5306, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
+			[16]DataDirectory{
+				{0x0, 0x0},
+				{0x6000, 0x378},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x8004, 0x18},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x60b8, 0x7c},
+				{0x0, 0x0},
+				{0x0, 0x0},
+				{0x0, 0x0},
+			},
+		},
+		sections: []*SectionHeader{
+			{".text", 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
+			{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+			{".rdata", 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+			{".eh_fram", 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040},
+			{".bss", 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080},
+			{".idata", 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+			{".CRT", 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+			{".tls", 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
+		},
+		hasNoDwarfInfo: true,
+	},
+	{
 		file: "testdata/gcc-amd64-mingw-obj",
 		hdr:  FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
 		sections: []*SectionHeader{
@@ -307,3 +343,75 @@ func main() {
 	}
 	t.Fatal("main.main not found")
 }
+
+func TestBSSHasZeros(t *testing.T) {
+	testenv.MustHaveExec(t)
+
+	if runtime.GOOS != "windows" {
+		t.Skip("skipping windows only test")
+	}
+	gccpath, err := exec.LookPath("gcc")
+	if err != nil {
+		t.Skip("skipping test: gcc is missing")
+	}
+
+	tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	srcpath := filepath.Join(tmpdir, "a.c")
+	src := `
+#include <stdio.h>
+
+int zero = 0;
+
+int
+main(void)
+{
+	printf("%d\n", zero);
+	return 0;
+}
+`
+	err = ioutil.WriteFile(srcpath, []byte(src), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	objpath := filepath.Join(tmpdir, "a.obj")
+	cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed to build object file: %v - %v", err, string(out))
+	}
+
+	f, err := Open(objpath)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+
+	var bss *Section
+	for _, sect := range f.Sections {
+		if sect.Name == ".bss" {
+			bss = sect
+			break
+		}
+	}
+	if bss == nil {
+		t.Fatal("could not find .bss section")
+	}
+	data, err := bss.Data()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(data) == 0 {
+		t.Fatalf("%s file .bss section cannot be empty", objpath)
+	}
+	for _, b := range data {
+		if b != 0 {
+			t.Fatalf(".bss section has non zero bytes: %v", data)
+		}
+	}
+}
diff --git a/src/debug/pe/pe.go b/src/debug/pe/pe.go
index 8e90b1b..8050d59 100644
--- a/src/debug/pe/pe.go
+++ b/src/debug/pe/pe.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -86,30 +86,6 @@ type OptionalHeader64 struct {
 	DataDirectory               [16]DataDirectory
 }
 
-type SectionHeader32 struct {
-	Name                 [8]uint8
-	VirtualSize          uint32
-	VirtualAddress       uint32
-	SizeOfRawData        uint32
-	PointerToRawData     uint32
-	PointerToRelocations uint32
-	PointerToLineNumbers uint32
-	NumberOfRelocations  uint16
-	NumberOfLineNumbers  uint16
-	Characteristics      uint32
-}
-
-const COFFSymbolSize = 18
-
-type COFFSymbol struct {
-	Name               [8]uint8
-	Value              uint32
-	SectionNumber      int16
-	Type               uint16
-	StorageClass       uint8
-	NumberOfAuxSymbols uint8
-}
-
 const (
 	IMAGE_FILE_MACHINE_UNKNOWN   = 0x0
 	IMAGE_FILE_MACHINE_AM33      = 0x1d3
diff --git a/src/debug/pe/section.go b/src/debug/pe/section.go
new file mode 100644
index 0000000..8e6690f
--- /dev/null
+++ b/src/debug/pe/section.go
@@ -0,0 +1,111 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pe
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+	"strconv"
+)
+
+// SectionHeader32 represents real PE COFF section header.
+type SectionHeader32 struct {
+	Name                 [8]uint8
+	VirtualSize          uint32
+	VirtualAddress       uint32
+	SizeOfRawData        uint32
+	PointerToRawData     uint32
+	PointerToRelocations uint32
+	PointerToLineNumbers uint32
+	NumberOfRelocations  uint16
+	NumberOfLineNumbers  uint16
+	Characteristics      uint32
+}
+
+// fullName finds real name of section sh. Normally name is stored
+// in sh.Name, but if it is longer then 8 characters, it is stored
+// in COFF string table st instead.
+func (sh *SectionHeader32) fullName(st _StringTable) (string, error) {
+	if sh.Name[0] != '/' {
+		return cstring(sh.Name[:]), nil
+	}
+	i, err := strconv.Atoi(cstring(sh.Name[1:]))
+	if err != nil {
+		return "", err
+	}
+	return st.String(uint32(i))
+}
+
+// TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here
+
+// _Reloc represents a PE COFF relocation.
+// Each section contains its own relocation list.
+type _Reloc struct {
+	VirtualAddress   uint32
+	SymbolTableIndex uint32
+	Type             uint16
+}
+
+func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]_Reloc, error) {
+	if sh.NumberOfRelocations <= 0 {
+		return nil, nil
+	}
+	_, err := r.Seek(int64(sh.PointerToRelocations), io.SeekStart)
+	if err != nil {
+		return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err)
+	}
+	relocs := make([]_Reloc, sh.NumberOfRelocations)
+	err = binary.Read(r, binary.LittleEndian, relocs)
+	if err != nil {
+		return nil, fmt.Errorf("fail to read section relocations: %v", err)
+	}
+	return relocs, nil
+}
+
+// SectionHeader is similar to SectionHeader32 with Name
+// field replaced by Go string.
+type SectionHeader struct {
+	Name                 string
+	VirtualSize          uint32
+	VirtualAddress       uint32
+	Size                 uint32
+	Offset               uint32
+	PointerToRelocations uint32
+	PointerToLineNumbers uint32
+	NumberOfRelocations  uint16
+	NumberOfLineNumbers  uint16
+	Characteristics      uint32
+}
+
+// Section provides access to PE COFF section.
+type Section struct {
+	SectionHeader
+	_Relocs []_Reloc
+
+	// Embed ReaderAt for ReadAt method.
+	// Do not embed SectionReader directly
+	// to avoid having Read and Seek.
+	// If a client wants Read and Seek it must use
+	// Open() to avoid fighting over the seek offset
+	// with other clients.
+	io.ReaderAt
+	sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the PE section s.
+func (s *Section) Data() ([]byte, error) {
+	dat := make([]byte, s.sr.Size())
+	n, err := s.sr.ReadAt(dat, 0)
+	if n == len(dat) {
+		err = nil
+	}
+	return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the PE section s.
+func (s *Section) Open() io.ReadSeeker {
+	return io.NewSectionReader(s.sr, 0, 1<<63-1)
+}
diff --git a/src/debug/pe/string.go b/src/debug/pe/string.go
new file mode 100644
index 0000000..69837f6
--- /dev/null
+++ b/src/debug/pe/string.go
@@ -0,0 +1,66 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pe
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+)
+
+// cstring converts ASCII byte sequence b to string.
+// It stops once it finds 0 or reaches end of b.
+func cstring(b []byte) string {
+	var i int
+	for i = 0; i < len(b) && b[i] != 0; i++ {
+	}
+	return string(b[:i])
+}
+
+// _StringTable is a COFF string table.
+type _StringTable []byte
+
+func readStringTable(fh *FileHeader, r io.ReadSeeker) (_StringTable, error) {
+	// COFF string table is located right after COFF symbol table.
+	if fh.PointerToSymbolTable <= 0 {
+		return nil, nil
+	}
+	offset := fh.PointerToSymbolTable + COFFSymbolSize*fh.NumberOfSymbols
+	_, err := r.Seek(int64(offset), io.SeekStart)
+	if err != nil {
+		return nil, fmt.Errorf("fail to seek to string table: %v", err)
+	}
+	var l uint32
+	err = binary.Read(r, binary.LittleEndian, &l)
+	if err != nil {
+		return nil, fmt.Errorf("fail to read string table length: %v", err)
+	}
+	// string table length includes itself
+	if l <= 4 {
+		return nil, nil
+	}
+	l -= 4
+	buf := make([]byte, l)
+	_, err = io.ReadFull(r, buf)
+	if err != nil {
+		return nil, fmt.Errorf("fail to read string table: %v", err)
+	}
+	return _StringTable(buf), nil
+}
+
+// TODO(brainman): decide if start parameter should be int instead of uint32
+
+// String extracts string from COFF string table st at offset start.
+func (st _StringTable) String(start uint32) (string, error) {
+	// start includes 4 bytes of string table length
+	if start < 4 {
+		return "", fmt.Errorf("offset %d is before the start of string table", start)
+	}
+	start -= 4
+	if int(start) > len(st) {
+		return "", fmt.Errorf("offset %d is beyond the end of string table", start)
+	}
+	return cstring(st[start:]), nil
+}
diff --git a/src/debug/pe/symbol.go b/src/debug/pe/symbol.go
new file mode 100644
index 0000000..7b8cbf2
--- /dev/null
+++ b/src/debug/pe/symbol.go
@@ -0,0 +1,95 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pe
+
+import (
+	"encoding/binary"
+	"fmt"
+	"io"
+)
+
+const COFFSymbolSize = 18
+
+// COFFSymbol represents single COFF symbol table record.
+type COFFSymbol struct {
+	Name               [8]uint8
+	Value              uint32
+	SectionNumber      int16
+	Type               uint16
+	StorageClass       uint8
+	NumberOfAuxSymbols uint8
+}
+
+func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
+	if fh.NumberOfSymbols <= 0 {
+		return nil, nil
+	}
+	_, err := r.Seek(int64(fh.PointerToSymbolTable), io.SeekStart)
+	if err != nil {
+		return nil, fmt.Errorf("fail to seek to symbol table: %v", err)
+	}
+	syms := make([]COFFSymbol, fh.NumberOfSymbols)
+	err = binary.Read(r, binary.LittleEndian, syms)
+	if err != nil {
+		return nil, fmt.Errorf("fail to read symbol table: %v", err)
+	}
+	return syms, nil
+}
+
+// isSymNameOffset checks symbol name if it is encoded as offset into string table.
+func isSymNameOffset(name [8]byte) (bool, uint32) {
+	if name[0] == 0 && name[1] == 0 && name[2] == 0 && name[3] == 0 {
+		return true, binary.LittleEndian.Uint32(name[4:])
+	}
+	return false, 0
+}
+
+// _FullName finds real name of symbol sym. Normally name is stored
+// in sym.Name, but if it is longer then 8 characters, it is stored
+// in COFF string table st instead.
+func (sym *COFFSymbol) _FullName(st _StringTable) (string, error) {
+	if ok, offset := isSymNameOffset(sym.Name); ok {
+		return st.String(offset)
+	}
+	return cstring(sym.Name[:]), nil
+}
+
+func removeAuxSymbols(allsyms []COFFSymbol, st _StringTable) ([]*Symbol, error) {
+	if len(allsyms) == 0 {
+		return nil, nil
+	}
+	syms := make([]*Symbol, 0)
+	aux := uint8(0)
+	for _, sym := range allsyms {
+		if aux > 0 {
+			aux--
+			continue
+		}
+		name, err := sym._FullName(st)
+		if err != nil {
+			return nil, err
+		}
+		aux = sym.NumberOfAuxSymbols
+		s := &Symbol{
+			Name:          name,
+			Value:         sym.Value,
+			SectionNumber: sym.SectionNumber,
+			Type:          sym.Type,
+			StorageClass:  sym.StorageClass,
+		}
+		syms = append(syms, s)
+	}
+	return syms, nil
+}
+
+// Symbol is similar to COFFSymbol with Name field replaced
+// by Go string. Symbol also does not have NumberOfAuxSymbols.
+type Symbol struct {
+	Name          string
+	Value         uint32
+	SectionNumber int16
+	Type          uint16
+	StorageClass  uint8
+}
diff --git a/src/debug/pe/testdata/gcc-386-mingw-no-symbols-exec b/src/debug/pe/testdata/gcc-386-mingw-no-symbols-exec
new file mode 100644
index 0000000..329dca6
Binary files /dev/null and b/src/debug/pe/testdata/gcc-386-mingw-no-symbols-exec differ
diff --git a/src/debug/plan9obj/file.go b/src/debug/plan9obj/file.go
index b11ed86..c78e35d 100644
--- a/src/debug/plan9obj/file.go
+++ b/src/debug/plan9obj/file.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/debug/plan9obj/file_test.go b/src/debug/plan9obj/file_test.go
index cfd7a61..7e107bc 100644
--- a/src/debug/plan9obj/file_test.go
+++ b/src/debug/plan9obj/file_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/debug/plan9obj/plan9obj.go b/src/debug/plan9obj/plan9obj.go
index af98585..7a19451 100644
--- a/src/debug/plan9obj/plan9obj.go
+++ b/src/debug/plan9obj/plan9obj.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/encoding/ascii85/ascii85.go b/src/encoding/ascii85/ascii85.go
index 4d71938..d42eb0a 100644
--- a/src/encoding/ascii85/ascii85.go
+++ b/src/encoding/ascii85/ascii85.go
@@ -20,7 +20,7 @@ import (
 //
 // The encoding handles 4-byte chunks, using a special encoding
 // for the last fragment, so Encode is not appropriate for use on
-// individual blocks of a large data stream.  Use NewEncoder() instead.
+// individual blocks of a large data stream. Use NewEncoder() instead.
 //
 // Often, ascii85-encoded data is wrapped in <~ and ~> symbols.
 // Encode does not add these.
@@ -85,7 +85,7 @@ func Encode(dst, src []byte) int {
 // MaxEncodedLen returns the maximum length of an encoding of n source bytes.
 func MaxEncodedLen(n int) int { return (n + 3) / 4 * 5 }
 
-// NewEncoder returns a new ascii85 stream encoder.  Data written to
+// NewEncoder returns a new ascii85 stream encoder. Data written to
 // the returned writer will be encoded and then written to w.
 // Ascii85 encodings operate in 32-bit blocks; when finished
 // writing, the caller must Close the returned encoder to flush any
@@ -294,7 +294,7 @@ func (d *decoder) Read(p []byte) (n int, err error) {
 			}
 		}
 
-		// Out of input, out of decoded output.  Check errors.
+		// Out of input, out of decoded output. Check errors.
 		if d.err != nil {
 			return 0, d.err
 		}
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index 8bafefd..2b5ad08 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -393,7 +393,7 @@ func isPrintable(b byte) bool {
 // byte slice and returns it.
 func parseIA5String(bytes []byte) (ret string, err error) {
 	for _, b := range bytes {
-		if b >= 0x80 {
+		if b >= utf8.RuneSelf {
 			err = SyntaxError{"IA5String contains invalid character"}
 			return
 		}
@@ -461,6 +461,11 @@ func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset i
 		if err != nil {
 			return
 		}
+		// Tags should be encoded in minimal form.
+		if ret.tag < 0x1f {
+			err = SyntaxError{"non-minimal tag"}
+			return
+		}
 	}
 	if offset >= len(bytes) {
 		err = SyntaxError{"truncated tag or length"}
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index e0e8331..f8623fa 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -364,7 +364,7 @@ var tagAndLengthData = []tagAndLengthTest{
 	{[]byte{0xa0, 0x01}, true, tagAndLength{2, 0, 1, true}},
 	{[]byte{0x02, 0x00}, true, tagAndLength{0, 2, 0, false}},
 	{[]byte{0xfe, 0x00}, true, tagAndLength{3, 30, 0, true}},
-	{[]byte{0x1f, 0x01, 0x00}, true, tagAndLength{0, 1, 0, false}},
+	{[]byte{0x1f, 0x1f, 0x00}, true, tagAndLength{0, 31, 0, false}},
 	{[]byte{0x1f, 0x81, 0x00, 0x00}, true, tagAndLength{0, 128, 0, false}},
 	{[]byte{0x1f, 0x81, 0x80, 0x01, 0x00}, true, tagAndLength{0, 0x4001, 0, false}},
 	{[]byte{0x00, 0x81, 0x80}, true, tagAndLength{0, 0, 128, false}},
@@ -382,6 +382,8 @@ var tagAndLengthData = []tagAndLengthTest{
 	{[]byte{0xa0, 0x81, 0x7f}, false, tagAndLength{}},
 	// Tag numbers which would overflow int32 are rejected. (The value below is 2^31.)
 	{[]byte{0x1f, 0x88, 0x80, 0x80, 0x80, 0x00, 0x00}, false, tagAndLength{}},
+	// Long tag number form may not be used for tags that fit in short form.
+	{[]byte{0x1f, 0x1e, 0x00}, false, tagAndLength{}},
 }
 
 func TestParseTagAndLength(t *testing.T) {
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index 6e85858..30797ef 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -17,7 +17,7 @@ import (
 
 // A forkableWriter is an in-memory buffer that can be
 // 'forked' to create new forkableWriters that bracket the
-// original.  After
+// original. After
 //    pre, post := w.fork()
 // the overall sequence of bytes represented is logically w+pre+post.
 type forkableWriter struct {
@@ -315,9 +315,9 @@ func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
 
 	switch {
 	case 1950 <= year && year < 2000:
-		err = marshalTwoDigits(out, int(year-1900))
+		err = marshalTwoDigits(out, year-1900)
 	case 2000 <= year && year < 2050:
-		err = marshalTwoDigits(out, int(year-2000))
+		err = marshalTwoDigits(out, year-2000)
 	default:
 		return StructuralError{"cannot represent time as UTCTime"}
 	}
@@ -435,7 +435,7 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
 			return out.WriteByte(0)
 		}
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return marshalInt64(out, int64(v.Int()))
+		return marshalInt64(out, v.Int())
 	case reflect.Struct:
 		t := v.Type()
 
diff --git a/src/encoding/base32/base32.go b/src/encoding/base32/base32.go
index 5a9e869..c193e65 100644
--- a/src/encoding/base32/base32.go
+++ b/src/encoding/base32/base32.go
@@ -17,7 +17,7 @@ import (
  */
 
 // An Encoding is a radix 32 encoding/decoding scheme, defined by a
-// 32-character alphabet.  The most common is the "base32" encoding
+// 32-character alphabet. The most common is the "base32" encoding
 // introduced for SASL GSSAPI and standardized in RFC 4648.
 // The alternate "base32hex" encoding is used in DNSSEC.
 type Encoding struct {
@@ -66,7 +66,7 @@ var removeNewlinesMapper = func(r rune) rune {
 //
 // The encoding pads the output to a multiple of 8 bytes,
 // so Encode is not appropriate for use on individual blocks
-// of a large data stream.  Use NewEncoder() instead.
+// of a large data stream. Use NewEncoder() instead.
 func (enc *Encoding) Encode(dst, src []byte) {
 	if len(src) == 0 {
 		return
@@ -208,7 +208,7 @@ func (e *encoder) Close() error {
 	return e.err
 }
 
-// NewEncoder returns a new base32 stream encoder.  Data written to
+// NewEncoder returns a new base32 stream encoder. Data written to
 // the returned writer will be encoded using enc and then written to w.
 // Base32 encodings operate in 5-byte blocks; when finished
 // writing, the caller must Close the returned encoder to flush any
@@ -313,9 +313,9 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 	return n, end, nil
 }
 
-// Decode decodes src using the encoding enc.  It writes at most
+// Decode decodes src using the encoding enc. It writes at most
 // DecodedLen(len(src)) bytes to dst and returns the number of bytes
-// written.  If src contains invalid base32 data, it will return the
+// written. If src contains invalid base32 data, it will return the
 // 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) {
diff --git a/src/encoding/base32/base32_test.go b/src/encoding/base32/base32_test.go
index 5a68f06..66a48a3 100644
--- a/src/encoding/base32/base32_test.go
+++ b/src/encoding/base32/base32_test.go
@@ -171,7 +171,7 @@ func TestDecodeCorrupt(t *testing.T) {
 		_, err := StdEncoding.Decode(dbuf, []byte(tc.input))
 		if tc.offset == -1 {
 			if err != nil {
-				t.Error("Decoder wrongly detected coruption in", tc.input)
+				t.Error("Decoder wrongly detected corruption in", tc.input)
 			}
 			continue
 		}
diff --git a/src/encoding/base32/example_test.go b/src/encoding/base32/example_test.go
index f6128d9..2a302d8 100644
--- a/src/encoding/base32/example_test.go
+++ b/src/encoding/base32/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/encoding/base64/base64.go b/src/encoding/base64/base64.go
index 1bda804..c2116d8 100644
--- a/src/encoding/base64/base64.go
+++ b/src/encoding/base64/base64.go
@@ -15,7 +15,7 @@ import (
  */
 
 // An Encoding is a radix 64 encoding/decoding scheme, defined by a
-// 64-character alphabet.  The most common encoding is the "base64"
+// 64-character alphabet. The most common encoding is the "base64"
 // encoding defined in RFC 4648 and used in MIME (RFC 2045) and PEM
 // (RFC 1421).  RFC 4648 also defines an alternate encoding, which is
 // the standard encoding with - and _ substituted for + and /.
@@ -89,7 +89,7 @@ var RawURLEncoding = URLEncoding.WithPadding(NoPadding)
 //
 // The encoding pads the output to a multiple of 4 bytes,
 // so Encode is not appropriate for use on individual blocks
-// of a large data stream.  Use NewEncoder() instead.
+// of a large data stream. Use NewEncoder() instead.
 func (enc *Encoding) Encode(dst, src []byte) {
 	if len(src) == 0 {
 		return
@@ -213,7 +213,7 @@ func (e *encoder) Close() error {
 	return e.err
 }
 
-// NewEncoder returns a new base64 stream encoder.  Data written to
+// NewEncoder returns a new base64 stream encoder. Data written to
 // the returned writer will be encoded using enc and then written to w.
 // Base64 encodings operate in 4-byte blocks; when finished
 // writing, the caller must Close the returned encoder to flush any
@@ -328,9 +328,9 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 	return n, end, err
 }
 
-// Decode decodes src using the encoding enc.  It writes at most
+// Decode decodes src using the encoding enc. It writes at most
 // DecodedLen(len(src)) bytes to dst and returns the number of bytes
-// written.  If src contains invalid base64 data, it will return the
+// written. If src contains invalid base64 data, it will return the
 // 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) {
@@ -459,7 +459,7 @@ func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
 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
+		return n * 6 / 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 fc6a1ea..19ddb92 100644
--- a/src/encoding/base64/base64_test.go
+++ b/src/encoding/base64/base64_test.go
@@ -221,7 +221,7 @@ func TestDecodeCorrupt(t *testing.T) {
 		_, err := StdEncoding.Decode(dbuf, []byte(tc.input))
 		if tc.offset == -1 {
 			if err != nil {
-				t.Error("Decoder wrongly detected coruption in", tc.input)
+				t.Error("Decoder wrongly detected corruption in", tc.input)
 			}
 			continue
 		}
@@ -234,6 +234,51 @@ func TestDecodeCorrupt(t *testing.T) {
 	}
 }
 
+func TestEncodedLen(t *testing.T) {
+	for _, tt := range []struct {
+		enc  *Encoding
+		n    int
+		want int
+	}{
+		{RawStdEncoding, 0, 0},
+		{RawStdEncoding, 1, 2},
+		{RawStdEncoding, 2, 3},
+		{RawStdEncoding, 3, 4},
+		{RawStdEncoding, 7, 10},
+		{StdEncoding, 0, 0},
+		{StdEncoding, 1, 4},
+		{StdEncoding, 2, 4},
+		{StdEncoding, 3, 4},
+		{StdEncoding, 4, 8},
+		{StdEncoding, 7, 12},
+	} {
+		if got := tt.enc.EncodedLen(tt.n); got != tt.want {
+			t.Errorf("EncodedLen(%d): got %d, want %d", tt.n, got, tt.want)
+		}
+	}
+}
+
+func TestDecodedLen(t *testing.T) {
+	for _, tt := range []struct {
+		enc  *Encoding
+		n    int
+		want int
+	}{
+		{RawStdEncoding, 0, 0},
+		{RawStdEncoding, 2, 1},
+		{RawStdEncoding, 3, 2},
+		{RawStdEncoding, 4, 3},
+		{RawStdEncoding, 10, 7},
+		{StdEncoding, 0, 0},
+		{StdEncoding, 4, 3},
+		{StdEncoding, 8, 6},
+	} {
+		if got := tt.enc.DecodedLen(tt.n); got != tt.want {
+			t.Errorf("DecodedLen(%d): got %d, want %d", tt.n, got, tt.want)
+		}
+	}
+}
+
 func TestBig(t *testing.T) {
 	n := 3*1000 + 1
 	raw := make([]byte, n)
diff --git a/src/encoding/base64/example_test.go b/src/encoding/base64/example_test.go
index 8d2c9ce..73f119a 100644
--- a/src/encoding/base64/example_test.go
+++ b/src/encoding/base64/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/encoding/binary/binary.go b/src/encoding/binary/binary.go
index 1c2577b..46c6add 100644
--- a/src/encoding/binary/binary.go
+++ b/src/encoding/binary/binary.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -48,18 +48,24 @@ var BigEndian bigEndian
 
 type littleEndian struct{}
 
-func (littleEndian) Uint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
+func (littleEndian) Uint16(b []byte) uint16 {
+	_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+	return uint16(b[0]) | uint16(b[1])<<8
+}
 
 func (littleEndian) PutUint16(b []byte, v uint16) {
+	_ = b[1] // early bounds check to guarantee safety of writes below
 	b[0] = byte(v)
 	b[1] = byte(v >> 8)
 }
 
 func (littleEndian) Uint32(b []byte) uint32 {
+	_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
 	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
 }
 
 func (littleEndian) PutUint32(b []byte, v uint32) {
+	_ = b[3] // early bounds check to guarantee safety of writes below
 	b[0] = byte(v)
 	b[1] = byte(v >> 8)
 	b[2] = byte(v >> 16)
@@ -67,11 +73,13 @@ func (littleEndian) PutUint32(b []byte, v uint32) {
 }
 
 func (littleEndian) Uint64(b []byte) uint64 {
+	_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
 	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
 		uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
 }
 
 func (littleEndian) PutUint64(b []byte, v uint64) {
+	_ = b[7] // early bounds check to guarantee safety of writes below
 	b[0] = byte(v)
 	b[1] = byte(v >> 8)
 	b[2] = byte(v >> 16)
@@ -88,18 +96,24 @@ func (littleEndian) GoString() string { return "binary.LittleEndian" }
 
 type bigEndian struct{}
 
-func (bigEndian) Uint16(b []byte) uint16 { return uint16(b[1]) | uint16(b[0])<<8 }
+func (bigEndian) Uint16(b []byte) uint16 {
+	_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+	return uint16(b[1]) | uint16(b[0])<<8
+}
 
 func (bigEndian) PutUint16(b []byte, v uint16) {
+	_ = b[1] // early bounds check to guarantee safety of writes below
 	b[0] = byte(v >> 8)
 	b[1] = byte(v)
 }
 
 func (bigEndian) Uint32(b []byte) uint32 {
+	_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
 	return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
 }
 
 func (bigEndian) PutUint32(b []byte, v uint32) {
+	_ = b[3] // early bounds check to guarantee safety of writes below
 	b[0] = byte(v >> 24)
 	b[1] = byte(v >> 16)
 	b[2] = byte(v >> 8)
@@ -107,11 +121,13 @@ func (bigEndian) PutUint32(b []byte, v uint32) {
 }
 
 func (bigEndian) Uint64(b []byte) uint64 {
+	_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
 	return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
 		uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
 }
 
 func (bigEndian) PutUint64(b []byte, v uint64) {
+	_ = b[7] // early bounds check to guarantee safety of writes below
 	b[0] = byte(v >> 56)
 	b[1] = byte(v >> 48)
 	b[2] = byte(v >> 40)
@@ -253,7 +269,7 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
 		case *uint8:
 			b[0] = *v
 		case uint8:
-			b[0] = byte(v)
+			b[0] = v
 		case []uint8:
 			bs = v
 		case *int16:
diff --git a/src/encoding/binary/binary_test.go b/src/encoding/binary/binary_test.go
index 7fd36fa..c0728e9 100644
--- a/src/encoding/binary/binary_test.go
+++ b/src/encoding/binary/binary_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -266,7 +266,7 @@ func TestBlankFields(t *testing.T) {
 }
 
 // An attempt to read into a struct with an unexported field will
-// panic.  This is probably not the best choice, but at this point
+// panic. This is probably not the best choice, but at this point
 // anything else would be an API change.
 
 type Unexported struct {
@@ -339,6 +339,33 @@ func TestReadTruncated(t *testing.T) {
 	}
 }
 
+func testUint64SmallSliceLengthPanics() (panicked bool) {
+	defer func() {
+		panicked = recover() != nil
+	}()
+	b := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
+	LittleEndian.Uint64(b[:4])
+	return false
+}
+
+func testPutUint64SmallSliceLengthPanics() (panicked bool) {
+	defer func() {
+		panicked = recover() != nil
+	}()
+	b := [8]byte{}
+	LittleEndian.PutUint64(b[:4], 0x0102030405060708)
+	return false
+}
+
+func TestEarlyBoundsChecks(t *testing.T) {
+	if testUint64SmallSliceLengthPanics() != true {
+		t.Errorf("binary.LittleEndian.Uint64 expected to panic for small slices, but didn't")
+	}
+	if testPutUint64SmallSliceLengthPanics() != true {
+		t.Errorf("binary.LittleEndian.PutUint64 expected to panic for small slices, but didn't")
+	}
+}
+
 type byteSliceReader struct {
 	remain []byte
 }
@@ -373,8 +400,8 @@ func BenchmarkReadStruct(b *testing.B) {
 		Read(bsr, BigEndian, &t)
 	}
 	b.StopTimer()
-	if !reflect.DeepEqual(s, t) {
-		b.Fatal("no match")
+	if b.N > 0 && !reflect.DeepEqual(s, t) {
+		b.Fatalf("struct doesn't match:\ngot  %v;\nwant %v", t, s)
 	}
 }
 
@@ -405,8 +432,8 @@ func BenchmarkReadInts(b *testing.B) {
 		want.Array[i] = 0
 	}
 	b.StopTimer()
-	if !reflect.DeepEqual(ls, want) {
-		panic("no match")
+	if b.N > 0 && !reflect.DeepEqual(ls, want) {
+		b.Fatalf("struct doesn't match:\ngot  %v;\nwant %v", ls, want)
 	}
 }
 
@@ -427,7 +454,7 @@ func BenchmarkWriteInts(b *testing.B) {
 		Write(w, BigEndian, s.Uint64)
 	}
 	b.StopTimer()
-	if !bytes.Equal(buf.Bytes(), big[:30]) {
+	if b.N > 0 && !bytes.Equal(buf.Bytes(), big[:30]) {
 		b.Fatalf("first half doesn't match: %x %x", buf.Bytes(), big[:30])
 	}
 }
diff --git a/src/encoding/binary/example_test.go b/src/encoding/binary/example_test.go
index 067cf55..c0fec73 100644
--- a/src/encoding/binary/example_test.go
+++ b/src/encoding/binary/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/encoding/binary/varint.go b/src/encoding/binary/varint.go
index 3a2dfa3..d7a75f9 100644
--- a/src/encoding/binary/varint.go
+++ b/src/encoding/binary/varint.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/encoding/csv/reader.go b/src/encoding/csv/reader.go
index a6bb780..a5e03a9 100644
--- a/src/encoding/csv/reader.go
+++ b/src/encoding/csv/reader.go
@@ -3,6 +3,8 @@
 // license that can be found in the LICENSE file.
 
 // Package csv reads and writes comma-separated values (CSV) files.
+// There are many kinds of CSV files; this package supports the format
+// described in RFC 4180.
 //
 // A csv file contains zero or more records of one or more fields per record.
 // Each record is separated by the newline character. The final record may
@@ -14,11 +16,11 @@
 //
 // Carriage returns before newline characters are silently removed.
 //
-// Blank lines are ignored.  A line with only whitespace characters (excluding
+// Blank lines are ignored. A line with only whitespace characters (excluding
 // the ending newline character) is not considered a blank line.
 //
 // Fields which start and stop with the quote character " are called
-// quoted-fields.  The beginning and ending quote are not part of the
+// quoted-fields. The beginning and ending quote are not part of the
 // field.
 //
 // The source:
@@ -84,32 +86,35 @@ var (
 // The exported fields can be changed to customize the details before the
 // first call to Read or ReadAll.
 //
-// Comma is the field delimiter.  It defaults to ','.
 //
-// Comment, if not 0, is the comment character. Lines beginning with the
-// Comment character are ignored.
-//
-// If FieldsPerRecord is positive, Read requires each record to
-// have the given number of fields.  If FieldsPerRecord is 0, Read sets it to
-// the number of fields in the first record, so that future records must
-// have the same field count.  If FieldsPerRecord is negative, no check is
-// made and records may have a variable number of fields.
-//
-// If LazyQuotes is true, a quote may appear in an unquoted field and a
-// non-doubled quote may appear in a quoted field.
-//
-// If TrimLeadingSpace is true, leading white space in a field is ignored.
 type Reader struct {
-	Comma            rune // field delimiter (set to ',' by NewReader)
-	Comment          rune // comment character for start of line
-	FieldsPerRecord  int  // number of expected fields per record
-	LazyQuotes       bool // allow lazy quotes
-	TrailingComma    bool // ignored; here for backwards compatibility
-	TrimLeadingSpace bool // trim leading space
-	line             int
-	column           int
-	r                *bufio.Reader
-	field            bytes.Buffer
+	// Comma is the field delimiter.
+	// It is set to comma (',') by NewReader.
+	Comma rune
+	// Comment, if not 0, is the comment character. Lines beginning with the
+	// Comment character without preceding whitespace are ignored.
+	// With leading whitespace the Comment character becomes part of the
+	// field, even if TrimLeadingSpace is true.
+	Comment rune
+	// FieldsPerRecord is the number of expected fields per record.
+	// If FieldsPerRecord is positive, Read requires each record to
+	// have the given number of fields. If FieldsPerRecord is 0, Read sets it to
+	// the number of fields in the first record, so that future records must
+	// have the same field count. If FieldsPerRecord is negative, no check is
+	// made and records may have a variable number of fields.
+	FieldsPerRecord int
+	// If LazyQuotes is true, a quote may appear in an unquoted field and a
+	// non-doubled quote may appear in a quoted field.
+	LazyQuotes    bool
+	TrailingComma bool // ignored; here for backwards compatibility
+	// If TrimLeadingSpace is true, leading white space in a field is ignored.
+	// This is done even if the field delimiter, Comma, is white space.
+	TrimLeadingSpace bool
+
+	line   int
+	column int
+	r      *bufio.Reader
+	field  bytes.Buffer
 }
 
 // NewReader returns a new Reader that reads from r.
@@ -129,7 +134,7 @@ func (r *Reader) error(err error) error {
 	}
 }
 
-// Read reads one record from r.  The record is a slice of strings with each
+// Read reads one record from r. The record is a slice of strings with each
 // string representing one field.
 func (r *Reader) Read() (record []string, err error) {
 	for {
@@ -177,7 +182,7 @@ func (r *Reader) ReadAll() (records [][]string, err error) {
 func (r *Reader) readRune() (rune, error) {
 	r1, _, err := r.r.ReadRune()
 
-	// Handle \r\n here.  We make the simplifying assumption that
+	// Handle \r\n here. We make the simplifying assumption that
 	// anytime \r is followed by \n that it can be folded to \n.
 	// We will not detect files which contain both \r\n and bare \n.
 	if r1 == '\r' {
@@ -208,13 +213,13 @@ func (r *Reader) skip(delim rune) error {
 
 // parseRecord reads and parses a single csv record from r.
 func (r *Reader) parseRecord() (fields []string, err error) {
-	// Each record starts on a new line.  We increment our line
+	// Each record starts on a new line. We increment our line
 	// number (lines start at 1, not 0) and set column to -1
 	// so as we increment in readRune it points to the character we read.
 	r.line++
 	r.column = -1
 
-	// Peek at the first rune.  If it is an error we are done.
+	// Peek at the first rune. If it is an error we are done.
 	// If we support comments and it is the comment character
 	// then skip to the end of line.
 
@@ -232,7 +237,7 @@ 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
+			// If FieldsPerRecord is greater than 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)
@@ -247,8 +252,8 @@ func (r *Reader) parseRecord() (fields []string, err error) {
 	}
 }
 
-// parseField parses the next field in the record.  The read field is
-// located in r.field.  Delim is the first character not part of the field
+// parseField parses the next field in the record. The read field is
+// located in r.field. Delim is the first character not part of the field
 // (r.Comma or '\n').
 func (r *Reader) parseField() (haveField bool, delim rune, err error) {
 	r.field.Reset()
diff --git a/src/encoding/csv/writer.go b/src/encoding/csv/writer.go
index 353d91f..84b7aa1 100644
--- a/src/encoding/csv/writer.go
+++ b/src/encoding/csv/writer.go
@@ -15,7 +15,7 @@ import (
 // A Writer writes records to a CSV encoded file.
 //
 // As returned by NewWriter, a Writer writes records terminated by a
-// newline and uses ',' as the field delimiter.  The exported fields can be
+// newline and uses ',' as the field delimiter. The exported fields can be
 // changed to customize the details before the first call to Write or WriteAll.
 //
 // Comma is the field delimiter.
@@ -37,27 +37,28 @@ func NewWriter(w io.Writer) *Writer {
 
 // Writer writes a single CSV record to w along with any necessary quoting.
 // A record is a slice of strings with each string being one field.
-func (w *Writer) Write(record []string) (err error) {
+func (w *Writer) Write(record []string) error {
 	for n, field := range record {
 		if n > 0 {
-			if _, err = w.w.WriteRune(w.Comma); err != nil {
-				return
+			if _, err := w.w.WriteRune(w.Comma); err != nil {
+				return err
 			}
 		}
 
 		// If we don't have to have a quoted field then just
 		// write out the field and continue to the next field.
 		if !w.fieldNeedsQuotes(field) {
-			if _, err = w.w.WriteString(field); err != nil {
-				return
+			if _, err := w.w.WriteString(field); err != nil {
+				return err
 			}
 			continue
 		}
-		if err = w.w.WriteByte('"'); err != nil {
-			return
+		if err := w.w.WriteByte('"'); err != nil {
+			return err
 		}
 
 		for _, r1 := range field {
+			var err error
 			switch r1 {
 			case '"':
 				_, err = w.w.WriteString(`""`)
@@ -75,20 +76,21 @@ func (w *Writer) Write(record []string) (err error) {
 				_, err = w.w.WriteRune(r1)
 			}
 			if err != nil {
-				return
+				return err
 			}
 		}
 
-		if err = w.w.WriteByte('"'); err != nil {
-			return
+		if err := w.w.WriteByte('"'); err != nil {
+			return err
 		}
 	}
+	var err error
 	if w.UseCRLF {
 		_, err = w.w.WriteString("\r\n")
 	} else {
 		err = w.w.WriteByte('\n')
 	}
-	return
+	return err
 }
 
 // Flush writes any buffered data to the underlying io.Writer.
@@ -104,9 +106,9 @@ func (w *Writer) Error() error {
 }
 
 // WriteAll writes multiple CSV records to w using Write and then calls Flush.
-func (w *Writer) WriteAll(records [][]string) (err error) {
+func (w *Writer) WriteAll(records [][]string) error {
 	for _, record := range records {
-		err = w.Write(record)
+		err := w.Write(record)
 		if err != nil {
 			return err
 		}
@@ -130,7 +132,7 @@ func (w *Writer) fieldNeedsQuotes(field string) bool {
 	if field == "" {
 		return false
 	}
-	if field == `\.` || strings.IndexRune(field, w.Comma) >= 0 || strings.IndexAny(field, "\"\r\n") >= 0 {
+	if field == `\.` || strings.ContainsRune(field, w.Comma) || strings.ContainsAny(field, "\"\r\n") {
 		return true
 	}
 
diff --git a/src/encoding/encoding.go b/src/encoding/encoding.go
index 6d21807..cc5a536 100644
--- a/src/encoding/encoding.go
+++ b/src/encoding/encoding.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go
index 8efcdc7..d4002cb 100644
--- a/src/encoding/gob/codec_test.go
+++ b/src/encoding/gob/codec_test.go
@@ -970,7 +970,7 @@ func TestBadRecursiveType(t *testing.T) {
 	err := NewEncoder(b).Encode(&rec)
 	if err == nil {
 		t.Error("expected error; got none")
-	} else if strings.Index(err.Error(), "recursive") < 0 {
+	} else if !strings.Contains(err.Error(), "recursive") {
 		t.Error("expected recursive type error; got", err)
 	}
 	// Can't test decode easily because we can't encode one, so we can't pass one to a Decoder.
@@ -1253,7 +1253,7 @@ func TestIgnoreInterface(t *testing.T) {
 	if item2.I != item1.I {
 		t.Error("normal int did not decode correctly")
 	}
-	if item2.F != item2.F {
+	if item2.F != item1.F {
 		t.Error("normal float did not decode correctly")
 	}
 }
@@ -1280,7 +1280,7 @@ func TestUnexportedFields(t *testing.T) {
 	if err != nil {
 		t.Fatal("decode error:", err)
 	}
-	if u0.A != u0.A || u0.B != u1.B || u0.D != u1.D {
+	if u0.A != u1.A || u0.B != u1.B || u0.D != u1.D {
 		t.Errorf("u1->u0: expected %v; got %v", u0, u1)
 	}
 	if u1.c != 1234. {
diff --git a/src/encoding/gob/debug.go b/src/encoding/gob/debug.go
index 536bbdb..d69d36f 100644
--- a/src/encoding/gob/debug.go
+++ b/src/encoding/gob/debug.go
@@ -7,7 +7,7 @@
 
 package gob
 
-// This file is not normally included in the gob package.  Used only for debugging the package itself.
+// This file is not normally included in the gob package. Used only for debugging the package itself.
 // Except for reading uints, it is an implementation of a reader that is independent of
 // the one implemented by Decoder.
 // To enable the Debug function, delete the +build ignore line above and do
@@ -241,7 +241,7 @@ func (deb *debugger) delimitedMessage(indent tab) bool {
 // loadBlock preps us to read a message
 // of the length specified next in the input. It returns
 // the length of the block. The argument tells whether
-// an EOF is acceptable now.  If it is and one is found,
+// an EOF is acceptable now. If it is and one is found,
 // the return value is negative.
 func (deb *debugger) loadBlock(eofOK bool) int {
 	n64, w, err := decodeUintReader(deb.r, deb.tmp) // deb.uint64 will error at EOF
@@ -339,7 +339,7 @@ func (deb *debugger) string() string {
 	return string(b)
 }
 
-// delta returns the field delta at the input point.  The expect argument,
+// delta returns the field delta at the input point. The expect argument,
 // if non-negative, identifies what the value should be.
 func (deb *debugger) delta(expect int) int {
 	delta := int(deb.uint64())
diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go
index 3b0dca8..9645dc5 100644
--- a/src/encoding/gob/decode.go
+++ b/src/encoding/gob/decode.go
@@ -216,10 +216,10 @@ func ignoreTwoUints(i *decInstr, state *decoderState, v reflect.Value) {
 }
 
 // Since the encoder writes no zeros, if we arrive at a decoder we have
-// a value to extract and store.  The field number has already been read
+// a value to extract and store. The field number has already been read
 // (it's how we knew to call this decoder).
 // Each decoder is responsible for handling any indirections associated
-// with the data structure.  If any pointer so reached is nil, allocation must
+// with the data structure. If any pointer so reached is nil, allocation must
 // be done.
 
 // decAlloc takes a value and returns a settable value that can
@@ -308,9 +308,9 @@ func decUint64(i *decInstr, state *decoderState, value reflect.Value) {
 }
 
 // Floating-point numbers are transmitted as uint64s holding the bits
-// of the underlying representation.  They are sent byte-reversed, with
+// of the underlying representation. They are sent byte-reversed, with
 // the exponent end coming out first, so integer floating point numbers
-// (for example) transmit more compactly.  This routine does the
+// (for example) transmit more compactly. This routine does the
 // unswizzling.
 func float64FromBits(u uint64) float64 {
 	var v uint64
@@ -332,7 +332,7 @@ func float32FromBits(u uint64, ovfl error) float64 {
 	if av < 0 {
 		av = -av
 	}
-	// +Inf is OK in both 32- and 64-bit floats.  Underflow is always OK.
+	// +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
 	if math.MaxFloat32 < av && av <= math.MaxFloat64 {
 		error_(ovfl)
 	}
@@ -421,7 +421,7 @@ func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) {
 // Execution engine
 
 // The encoder engine is an array of instructions indexed by field number of the incoming
-// decoder.  It is executed with random access according to field number.
+// decoder. It is executed with random access according to field number.
 type decEngine struct {
 	instr    []decInstr
 	numInstr int // the number of active instructions
@@ -442,7 +442,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, value refl
 }
 
 // decodeStruct decodes a top-level struct and stores it in value.
-// Indir is for the value, not the type.  At the time of the call it may
+// Indir is for the value, not the type. At the time of the call it may
 // differ from ut.indir, which was computed when the engine was built.
 // This state cannot arise for decodeSingle, which is called directly
 // from the user's value, not from the innards of an engine.
@@ -536,7 +536,7 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value,
 }
 
 // decodeArray decodes an array and stores it in value.
-// The length is an unsigned integer preceding the elements.  Even though the length is redundant
+// The length is an unsigned integer preceding the elements. Even though the length is redundant
 // (it's part of the type), it's a useful check and is included in the encoding.
 func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) {
 	if n := state.decodeUint(); n != uint64(length) {
@@ -645,10 +645,10 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
 		errorf("invalid type name length %d: exceeds input size", nr)
 	}
 	n := int(nr)
-	name := string(state.b.Bytes()[:n])
+	name := state.b.Bytes()[:n]
 	state.b.Drop(n)
 	// Allocate the destination interface value.
-	if name == "" {
+	if len(name) == 0 {
 		// Copy the nil interface value to the target.
 		value.Set(reflect.Zero(value.Type()))
 		return
@@ -658,7 +658,7 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
 	}
 	// The concrete type must be registered.
 	registerLock.RLock()
-	typ, ok := nameToConcreteType[name]
+	typ, ok := nameToConcreteType[string(name)]
 	registerLock.RUnlock()
 	if !ok {
 		errorf("name not registered for interface: %q", name)
@@ -1075,7 +1075,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err
 	return
 }
 
-// compileDec compiles the decoder engine for a value.  If the value is not a struct,
+// 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)
diff --git a/src/encoding/gob/decoder.go b/src/encoding/gob/decoder.go
index c453e9b..c182941 100644
--- a/src/encoding/gob/decoder.go
+++ b/src/encoding/gob/decoder.go
@@ -130,9 +130,9 @@ func (dec *Decoder) nextUint() uint64 {
 // decodeTypeSequence parses:
 // TypeSequence
 //	(TypeDefinition DelimitedTypeDefinition*)?
-// and returns the type id of the next value.  It returns -1 at
+// and returns the type id of the next value. It returns -1 at
 // EOF.  Upon return, the remainder of dec.buf is the value to be
-// decoded.  If this is an interface value, it can be ignored by
+// decoded. If this is an interface value, it can be ignored by
 // resetting that buffer.
 func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
 	for dec.err == nil {
@@ -150,7 +150,7 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
 		// Type definition for (-id) follows.
 		dec.recvType(-id)
 		// When decoding an interface, after a type there may be a
-		// DelimitedValue still in the buffer.  Skip its count.
+		// DelimitedValue still in the buffer. Skip its count.
 		// (Alternatively, the buffer is empty and the byte count
 		// will be absorbed by recvMessage.)
 		if dec.buf.Len() > 0 {
@@ -177,7 +177,7 @@ func (dec *Decoder) Decode(e interface{}) error {
 	}
 	value := reflect.ValueOf(e)
 	// If e represents a value as opposed to a pointer, the answer won't
-	// get back to the caller.  Make sure it's a pointer.
+	// get back to the caller. Make sure it's a pointer.
 	if value.Type().Kind() != reflect.Ptr {
 		dec.err = errors.New("gob: attempt to decode into a non-pointer")
 		return dec.err
@@ -187,7 +187,7 @@ func (dec *Decoder) Decode(e interface{}) error {
 
 // DecodeValue reads the next value from the input stream.
 // If v is the zero reflect.Value (v.Kind() == Invalid), DecodeValue discards the value.
-// Otherwise, it stores the value into v.  In that case, v must represent
+// Otherwise, it stores the value into v. In that case, v must represent
 // a non-nil pointer to data or be an assignable reflect.Value (v.CanSet())
 // If the input is at EOF, DecodeValue returns io.EOF and
 // does not modify v.
diff --git a/src/encoding/gob/doc.go b/src/encoding/gob/doc.go
index cf878f4..1536574 100644
--- a/src/encoding/gob/doc.go
+++ b/src/encoding/gob/doc.go
@@ -17,7 +17,8 @@ Basics
 A stream of gobs is self-describing.  Each data item in the stream is preceded by
 a specification of its type, expressed in terms of a small set of predefined
 types.  Pointers are not transmitted, but the things they point to are
-transmitted; that is, the values are flattened.  Recursive types work fine, but
+transmitted; that is, the values are flattened. Nil pointers are not permitted,
+as they have no value. Recursive types work fine, but
 recursive values (data with cycles) are problematic.  This may change.
 
 To use gobs, create an Encoder and present it with a series of data items as
@@ -254,6 +255,12 @@ In summary, a gob stream looks like
 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.
 
+Compatibility: Any future changes to the package will endeavor to maintain
+compatibility with streams encoded using previous versions.  That is, any released
+version of this package should be able to decode data written with any previously
+released version, subject to issues such as security fixes. See the Go compatibility
+document for background: https://golang.org/doc/go1compat
+
 See "Gobs of data" for a design discussion of the gob wire format:
 https://blog.golang.org/gobs-of-data
 */
diff --git a/src/encoding/gob/encode.go b/src/encoding/gob/encode.go
index 96052ef..50cd6ad 100644
--- a/src/encoding/gob/encode.go
+++ b/src/encoding/gob/encode.go
@@ -96,7 +96,7 @@ func (enc *Encoder) freeEncoderState(e *encoderState) {
 	enc.freeList = e
 }
 
-// Unsigned integers have a two-state encoding.  If the number is less
+// Unsigned integers have a two-state encoding. If the number is less
 // than 128 (0 through 0x7F), its value is written directly.
 // Otherwise the value is written in big-endian byte order preceded
 // by the byte length, negated.
@@ -127,7 +127,7 @@ func (state *encoderState) encodeInt(i int64) {
 	} else {
 		x = uint64(i << 1)
 	}
-	state.encodeUint(uint64(x))
+	state.encodeUint(x)
 }
 
 // encOp is the signature of an encoding operator for a given type.
@@ -152,8 +152,8 @@ func (state *encoderState) update(instr *encInstr) {
 
 // Each encoder for a composite is responsible for handling any
 // indirections associated with the elements of the data structure.
-// If any pointer so reached is nil, no bytes are written.  If the
-// data item is zero, no bytes are written.  Single values - ints,
+// If any pointer so reached is nil, no bytes are written. If the
+// data item is zero, no bytes are written. Single values - ints,
 // strings etc. - are indirected before calling their encoders.
 // Otherwise, the output (for a scalar) is the field number, as an
 // encoded integer, followed by the field data in its appropriate
@@ -203,9 +203,9 @@ func encUint(i *encInstr, state *encoderState, v reflect.Value) {
 
 // floatBits returns a uint64 holding the bits of a floating-point number.
 // Floating-point numbers are transmitted as uint64s holding the bits
-// of the underlying representation.  They are sent byte-reversed, with
+// of the underlying representation. They are sent byte-reversed, with
 // the exponent end coming out first, so integer floating point numbers
-// (for example) transmit more compactly.  This routine does the
+// (for example) transmit more compactly. This routine does the
 // swizzling.
 func floatBits(f float64) uint64 {
 	u := math.Float64bits(f)
@@ -272,7 +272,7 @@ func encStructTerminator(i *encInstr, state *encoderState, v reflect.Value) {
 // Execution engine
 
 // encEngine an array of instructions indexed by field number of the encoding
-// data, typically a struct.  It is executed top to bottom, walking the struct.
+// data, typically a struct. It is executed top to bottom, walking the struct.
 type encEngine struct {
 	instr []encInstr
 }
@@ -297,7 +297,7 @@ func (enc *Encoder) encodeSingle(b *encBuffer, engine *encEngine, value reflect.
 	defer enc.freeEncoderState(state)
 	state.fieldnum = singletonField
 	// There is no surrounding struct to frame the transmission, so we must
-	// generate data even if the item is zero.  To do this, set sendZero.
+	// generate data even if the item is zero. To do this, set sendZero.
 	state.sendZero = true
 	instr := &engine.instr[singletonField]
 	if instr.indir > 0 {
@@ -386,7 +386,7 @@ func (enc *Encoder) encodeMap(b *encBuffer, mv reflect.Value, keyOp, elemOp encO
 // encodeInterface encodes the interface value iv.
 // To send an interface, we send a string identifying the concrete type, followed
 // by the type identifier (which might require defining that type right now), followed
-// by the concrete value.  A nil value gets sent as the empty string for the name,
+// by the concrete value. A nil value gets sent as the empty string for the name,
 // followed by no value.
 func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
 	// Gobs can encode nil interface values but not typed interface
@@ -417,7 +417,7 @@ func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
 	enc.sendTypeDescriptor(enc.writer(), state, ut)
 	// Send the type id.
 	enc.sendTypeId(state, ut)
-	// Encode the value into a new buffer.  Any nested type definitions
+	// Encode the value into a new buffer. Any nested type definitions
 	// should be written to b, before the encoded value.
 	enc.pushWriter(b)
 	data := encBufferPool.Get().(*encBuffer)
diff --git a/src/encoding/gob/encoder.go b/src/encoding/gob/encoder.go
index 62d0f42..d6c8fdd 100644
--- a/src/encoding/gob/encoder.go
+++ b/src/encoding/gob/encoder.go
@@ -170,6 +170,7 @@ func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Typ
 
 // Encode transmits the data item represented by the empty interface value,
 // guaranteeing that all necessary type information has been transmitted first.
+// Passing a nil pointer to Encoder will panic, as they cannot be transmitted by gob.
 func (enc *Encoder) Encode(e interface{}) error {
 	return enc.EncodeValue(reflect.ValueOf(e))
 }
@@ -191,7 +192,7 @@ func (enc *Encoder) sendTypeDescriptor(w io.Writer, state *encoderState, ut *use
 			return
 		}
 		// If the type info has still not been transmitted, it means we have
-		// a singleton basic type (int, []byte etc.) at top level.  We don't
+		// a singleton basic type (int, []byte etc.) at top level. We don't
 		// need to send the type info but we do need to update enc.sent.
 		if !sent {
 			info, err := getTypeInfo(ut)
@@ -212,9 +213,8 @@ func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
 
 // EncodeValue transmits the data item represented by the reflection value,
 // guaranteeing that all necessary type information has been transmitted first.
+// Passing a nil pointer to EncodeValue will panic, as they cannot be transmitted by gob.
 func (enc *Encoder) EncodeValue(value reflect.Value) error {
-	// Gobs contain values. They cannot represent nil pointers, which
-	// have no value to encode.
 	if value.Kind() == reflect.Ptr && value.IsNil() {
 		panic("gob: cannot encode nil pointer of type " + value.Type().String())
 	}
diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go
index 570d796..22090a1 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"encoding/hex"
 	"fmt"
+	"io/ioutil"
 	"reflect"
 	"strings"
 	"testing"
@@ -280,7 +281,7 @@ func TestValueError(t *testing.T) {
 	}
 	t4p := &Type4{3}
 	var t4 Type4 // note: not a pointer.
-	if err := encAndDec(t4p, t4); err == nil || strings.Index(err.Error(), "pointer") < 0 {
+	if err := encAndDec(t4p, t4); err == nil || !strings.Contains(err.Error(), "pointer") {
 		t.Error("expected error about pointer; got", err)
 	}
 }
@@ -388,7 +389,7 @@ func TestSingletons(t *testing.T) {
 			t.Errorf("expected error decoding %v: %s", test.in, test.err)
 			continue
 		case err != nil && test.err != "":
-			if strings.Index(err.Error(), test.err) < 0 {
+			if !strings.Contains(err.Error(), test.err) {
 				t.Errorf("wrong error decoding %v: wanted %s, got %v", test.in, test.err, err)
 			}
 			continue
@@ -414,7 +415,7 @@ func TestStructNonStruct(t *testing.T) {
 	var ns NonStruct
 	if err := encAndDec(s, &ns); err == nil {
 		t.Error("should get error for struct/non-struct")
-	} else if strings.Index(err.Error(), "type") < 0 {
+	} else if !strings.Contains(err.Error(), "type") {
 		t.Error("for struct/non-struct expected type error; got", err)
 	}
 	// Now try the other way
@@ -424,7 +425,7 @@ func TestStructNonStruct(t *testing.T) {
 	}
 	if err := encAndDec(ns, &s); err == nil {
 		t.Error("should get error for non-struct/struct")
-	} else if strings.Index(err.Error(), "type") < 0 {
+	} else if !strings.Contains(err.Error(), "type") {
 		t.Error("for non-struct/struct expected type error; got", err)
 	}
 }
@@ -439,8 +440,8 @@ func (this *interfaceIndirectTestT) F() bool {
 	return true
 }
 
-// A version of a bug reported on golang-nuts.  Also tests top-level
-// slice of interfaces.  The issue was registering *T caused T to be
+// A version of a bug reported on golang-nuts. Also tests top-level
+// slice of interfaces. The issue was registering *T caused T to be
 // stored as the concrete type.
 func TestInterfaceIndirect(t *testing.T) {
 	Register(&interfaceIndirectTestT{})
@@ -463,7 +464,7 @@ func TestInterfaceIndirect(t *testing.T) {
 
 // Also, when the ignored object contains an interface value, it may define
 // types. Make sure that skipping the value still defines the types by using
-// the encoder/decoder pair to send a value afterwards.  If an interface
+// the encoder/decoder pair to send a value afterwards. If an interface
 // is sent, its type in the test is always NewType0, so this checks that the
 // encoder and decoder don't skew with respect to type definitions.
 
@@ -603,10 +604,6 @@ type Bug1Elem struct {
 
 type Bug1StructMap map[string]Bug1Elem
 
-func bug1EncDec(in Bug1StructMap, out *Bug1StructMap) error {
-	return nil
-}
-
 func TestMapBug1(t *testing.T) {
 	in := make(Bug1StructMap)
 	in["val1"] = Bug1Elem{"elem1", 1}
@@ -835,30 +832,81 @@ func TestPtrToMapOfMap(t *testing.T) {
 
 // A top-level nil pointer generates a panic with a helpful string-valued message.
 func TestTopLevelNilPointer(t *testing.T) {
-	errMsg := topLevelNilPanic(t)
-	if errMsg == "" {
+	var ip *int
+	encodeErr, panicErr := encodeAndRecover(ip)
+	if encodeErr != nil {
+		t.Fatal("error in encode:", encodeErr)
+	}
+	if panicErr == nil {
 		t.Fatal("top-level nil pointer did not panic")
 	}
+	errMsg := panicErr.Error()
 	if !strings.Contains(errMsg, "nil pointer") {
 		t.Fatal("expected nil pointer error, got:", errMsg)
 	}
 }
 
-func topLevelNilPanic(t *testing.T) (panicErr string) {
+func encodeAndRecover(value interface{}) (encodeErr, panicErr error) {
 	defer func() {
 		e := recover()
-		if err, ok := e.(string); ok {
-			panicErr = err
+		if e != nil {
+			switch err := e.(type) {
+			case error:
+				panicErr = err
+			default:
+				panicErr = fmt.Errorf("%v", err)
+			}
 		}
 	}()
-	var ip *int
-	buf := new(bytes.Buffer)
-	if err := NewEncoder(buf).Encode(ip); err != nil {
-		t.Fatal("error in encode:", err)
-	}
+
+	encodeErr = NewEncoder(ioutil.Discard).Encode(value)
 	return
 }
 
+func TestNilPointerPanics(t *testing.T) {
+	var (
+		nilStringPtr      *string
+		intMap            = make(map[int]int)
+		intMapPtr         = &intMap
+		nilIntMapPtr      *map[int]int
+		zero              int
+		nilBoolChannel    chan bool
+		nilBoolChannelPtr *chan bool
+		nilStringSlice    []string
+		stringSlice       = make([]string, 1)
+		nilStringSlicePtr *[]string
+	)
+
+	testCases := []struct {
+		value     interface{}
+		mustPanic bool
+	}{
+		{nilStringPtr, true},
+		{intMap, false},
+		{intMapPtr, false},
+		{nilIntMapPtr, true},
+		{zero, false},
+		{nilStringSlice, false},
+		{stringSlice, false},
+		{nilStringSlicePtr, true},
+		{nilBoolChannel, false},
+		{nilBoolChannelPtr, true},
+	}
+
+	for _, tt := range testCases {
+		_, panicErr := encodeAndRecover(tt.value)
+		if tt.mustPanic {
+			if panicErr == nil {
+				t.Errorf("expected panic with input %#v, did not panic", tt.value)
+			}
+			continue
+		}
+		if panicErr != nil {
+			t.Fatalf("expected no panic with input %#v, got panic=%v", tt.value, panicErr)
+		}
+	}
+}
+
 func TestNilPointerInsideInterface(t *testing.T) {
 	var ip *int
 	si := struct {
@@ -913,7 +961,7 @@ func TestMutipleEncodingsOfBadType(t *testing.T) {
 // There was an error check comparing the length of the input with the
 // length of the slice being decoded. It was wrong because the next
 // thing in the input might be a type definition, which would lead to
-// an incorrect length check.  This test reproduces the corner case.
+// an incorrect length check. This test reproduces the corner case.
 
 type Z struct {
 }
diff --git a/src/encoding/gob/error.go b/src/encoding/gob/error.go
index 92cc0c6..8b5265c 100644
--- a/src/encoding/gob/error.go
+++ b/src/encoding/gob/error.go
@@ -9,7 +9,7 @@ import "fmt"
 // Errors in decoding and encoding are handled using panic and recover.
 // Panics caused by user error (that is, everything except run-time panics
 // such as "index out of bounds" errors) do not leave the file that caused
-// them, but are instead turned into plain error returns.  Encoding and
+// them, but are instead turned into plain error returns. Encoding and
 // decoding functions and methods that do not return an error either use
 // panic to report an error or are guaranteed error-free.
 
@@ -30,7 +30,7 @@ func error_(err error) {
 }
 
 // catchError is meant to be used as a deferred function to turn a panic(gobError) into a
-// plain error.  It overwrites the error return of the function that deferred its call.
+// plain error. It overwrites the error return of the function that deferred its call.
 func catchError(err *error) {
 	if e := recover(); e != nil {
 		ge, ok := e.(gobError)
diff --git a/src/encoding/gob/example_interface_test.go b/src/encoding/gob/example_interface_test.go
index 4681e63..cf5ba38 100644
--- a/src/encoding/gob/example_interface_test.go
+++ b/src/encoding/gob/example_interface_test.go
@@ -60,7 +60,7 @@ func interfaceEncode(enc *gob.Encoder, p Pythagoras) {
 	// registered. We registered it in the calling function.
 
 	// Pass pointer to interface so Encode sees (and hence sends) a value of
-	// interface type.  If we passed p directly it would see the concrete type instead.
+	// interface type. If we passed p directly it would see the concrete type instead.
 	// See the blog post, "The Laws of Reflection" for background.
 	err := enc.Encode(&p)
 	if err != nil {
diff --git a/src/encoding/gob/example_test.go b/src/encoding/gob/example_test.go
index 020352c..16b7123 100644
--- a/src/encoding/gob/example_test.go
+++ b/src/encoding/gob/example_test.go
@@ -24,7 +24,7 @@ type Q struct {
 // This example shows the basic usage of the package: Create an encoder,
 // transmit some values, receive them with a decoder.
 func Example_basic() {
-	// Initialize the encoder and decoder.  Normally enc and dec would be
+	// Initialize the encoder and decoder. Normally enc and dec would be
 	// bound to network connections and the encoder and decoder would
 	// run in different processes.
 	var network bytes.Buffer        // Stand-in for a network connection
diff --git a/src/encoding/gob/gobencdec_test.go b/src/encoding/gob/gobencdec_test.go
index eb76b48..ecc91ee 100644
--- a/src/encoding/gob/gobencdec_test.go
+++ b/src/encoding/gob/gobencdec_test.go
@@ -376,7 +376,7 @@ func TestGobEncoderIndirectArrayField(t *testing.T) {
 }
 
 // As long as the fields have the same name and implement the
-// interface, we can cross-connect them.  Not sure it's useful
+// interface, we can cross-connect them. Not sure it's useful
 // and may even be bad but it works and it's hard to prevent
 // without exposing the contents of the object, which would
 // defeat the purpose.
@@ -434,7 +434,7 @@ func TestGobEncoderValueEncoder(t *testing.T) {
 }
 
 // Test that we can use a value then a pointer type of a GobEncoder
-// in the same encoded value.  Bug 4647.
+// in the same encoded value. Bug 4647.
 func TestGobEncoderValueThenPointer(t *testing.T) {
 	v := ValueGobber("forty-two")
 	w := ValueGobber("six-by-nine")
@@ -548,7 +548,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
 	if err == nil {
 		t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)")
 	}
-	if strings.Index(err.Error(), "type") < 0 {
+	if !strings.Contains(err.Error(), "type") {
 		t.Fatal("expected type error; got", err)
 	}
 	// Non-encoder to GobDecoder: error
@@ -562,7 +562,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
 	if err == nil {
 		t.Fatal("expected decode error for mismatched fields (non-encoder to decoder)")
 	}
-	if strings.Index(err.Error(), "type") < 0 {
+	if !strings.Contains(err.Error(), "type") {
 		t.Fatal("expected type error; got", err)
 	}
 }
diff --git a/src/encoding/gob/type.go b/src/encoding/gob/type.go
index cf5cec0..c27f7e9 100644
--- a/src/encoding/gob/type.go
+++ b/src/encoding/gob/type.go
@@ -17,7 +17,7 @@ import (
 )
 
 // userTypeInfo stores the information associated with a type the user has handed
-// to the package.  It's computed once and stored in a map keyed by reflection
+// to the package. It's computed once and stored in a map keyed by reflection
 // type.
 type userTypeInfo struct {
 	user        reflect.Type // the type the user handed us
@@ -44,7 +44,7 @@ var (
 )
 
 // validType returns, and saves, the information associated with user-provided type rt.
-// If the user type is not valid, err will be non-nil.  To be used when the error handler
+// If the user type is not valid, err will be non-nil. To be used when the error handler
 // is not set up.
 func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
 	userTypeLock.RLock()
@@ -64,7 +64,7 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err error) {
 	ut.base = rt
 	ut.user = rt
 	// A type that is just a cycle of pointers (such as type T *T) cannot
-	// be represented in gobs, which need some concrete data.  We use a
+	// be represented in gobs, which need some concrete data. We use a
 	// cycle detection algorithm from Knuth, Vol 2, Section 3.1, Ex 6,
 	// pp 539-540.  As we step through indirections, run another type at
 	// half speed. If they meet up, there's a cycle.
@@ -493,7 +493,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err
 		// For arrays, maps, and slices, we set the type id after the elements
 		// are constructed. This is to retain the order of type id allocation after
 		// a fix made to handle recursive types, which changed the order in
-		// which types are built.  Delaying the setting in this way preserves
+		// which types are built. Delaying the setting in this way preserves
 		// type ids while allowing recursive types to be described. Structs,
 		// done below, were already handling recursion correctly so they
 		// assign the top-level id before those of the field.
@@ -597,7 +597,7 @@ func getBaseType(name string, rt reflect.Type) (gobType, error) {
 
 // getType returns the Gob type describing the given reflect.Type.
 // Should be called only when handling GobEncoders/Decoders,
-// which may be pointers.  All other types are handled through the
+// which may be pointers. All other types are handled through the
 // base type, never a pointer.
 // typeLock must be held.
 func getType(name string, ut *userTypeInfo, rt reflect.Type) (gobType, error) {
@@ -642,7 +642,7 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
 // For bootstrapping purposes, we assume that the recipient knows how
 // to decode a wireType; it is exactly the wireType struct here, interpreted
 // using the gob rules for sending a structure, except that we assume the
-// ids for wireType and structType etc. are known.  The relevant pieces
+// ids for wireType and structType etc. are known. The relevant pieces
 // are built in encode.go's init() function.
 // To maintain binary compatibility, if you extend this type, always put
 // the new fields last.
@@ -789,7 +789,7 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo {
 //
 // Note: Since gobs can be stored permanently, it is good design
 // to guarantee the encoding used by a GobEncoder is stable as the
-// software evolves.  For instance, it might make sense for GobEncode
+// software evolves. For instance, it might make sense for GobEncode
 // to include a version number in the encoding.
 type GobEncoder interface {
 	// GobEncode returns a byte slice representing the encoding of the
@@ -838,8 +838,8 @@ func RegisterName(name string, value interface{}) {
 }
 
 // Register records a type, identified by a value for that type, under its
-// internal type name.  That name will identify the concrete type of a value
-// sent or received as an interface variable.  Only types that will be
+// internal type name. That name will identify the concrete type of a value
+// sent or received as an interface variable. Only types that will be
 // transferred as implementations of interface values need to be registered.
 // Expecting to be used only during initialization, it panics if the mapping
 // between types and names is not a bijection.
diff --git a/src/encoding/hex/hex.go b/src/encoding/hex/hex.go
index d1fc702..73a2503 100644
--- a/src/encoding/hex/hex.go
+++ b/src/encoding/hex/hex.go
@@ -18,7 +18,7 @@ const hextable = "0123456789abcdef"
 func EncodedLen(n int) int { return n * 2 }
 
 // Encode encodes src into EncodedLen(len(src))
-// bytes of dst.  As a convenience, it returns the number
+// bytes of dst. As a convenience, it returns the number
 // of bytes written to dst, but this value is always EncodedLen(len(src)).
 // Encode implements hexadecimal encoding.
 func Encode(dst, src []byte) int {
@@ -105,7 +105,7 @@ func Dump(data []byte) string {
 	dumper := Dumper(&buf)
 	dumper.Write(data)
 	dumper.Close()
-	return string(buf.Bytes())
+	return buf.String()
 }
 
 // Dumper returns a WriteCloser that writes a hex dump of all written data to
diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go
index ed89d11..cd7380b 100644
--- a/src/encoding/json/bench_test.go
+++ b/src/encoding/json/bench_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -158,7 +158,7 @@ func BenchmarkCodeUnmarshal(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		var r codeResponse
 		if err := Unmarshal(codeJSON, &r); err != nil {
-			b.Fatal("Unmmarshal:", err)
+			b.Fatal("Unmarshal:", err)
 		}
 	}
 	b.SetBytes(int64(len(codeJSON)))
@@ -173,7 +173,7 @@ func BenchmarkCodeUnmarshalReuse(b *testing.B) {
 	var r codeResponse
 	for i := 0; i < b.N; i++ {
 		if err := Unmarshal(codeJSON, &r); err != nil {
-			b.Fatal("Unmmarshal:", err)
+			b.Fatal("Unmarshal:", err)
 		}
 	}
 }
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index 539d952..2eda875 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -29,9 +29,9 @@ import (
 // with the following additional rules:
 //
 // To unmarshal JSON into a pointer, Unmarshal first handles the case of
-// the JSON being the JSON literal null.  In that case, Unmarshal sets
-// the pointer to nil.  Otherwise, Unmarshal unmarshals the JSON into
-// the value pointed at by the pointer.  If the pointer is nil, Unmarshal
+// the JSON being the JSON literal null. In that case, Unmarshal sets
+// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into
+// the value pointed at by the pointer. If the pointer is nil, Unmarshal
 // allocates a new value for it to point to.
 //
 // To unmarshal JSON into a struct, Unmarshal matches incoming object
@@ -61,10 +61,11 @@ import (
 // If the JSON array is smaller than the Go array,
 // the additional Go array elements are set to zero values.
 //
-// To unmarshal a JSON object into a string-keyed map, Unmarshal first
-// establishes a map to use, If the map is nil, Unmarshal allocates a new map.
-// Otherwise Unmarshal reuses the existing map, keeping existing entries.
-// Unmarshal then stores key-value pairs from the JSON object into the map.
+// To unmarshal a JSON object into a map, Unmarshal first establishes a map to
+// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
+// reuses the existing map, keeping existing entries. Unmarshal then stores key-
+// value pairs from the JSON object into the map. The map's key type must
+// either be a string, an integer, or implement encoding.TextUnmarshaler.
 //
 // If a JSON value is not appropriate for a given target type,
 // or if a JSON number overflows the target type, Unmarshal
@@ -96,7 +97,7 @@ func Unmarshal(data []byte, v interface{}) error {
 	return d.unmarshal(v)
 }
 
-// Unmarshaler is the interface implemented by objects
+// Unmarshaler is the interface implemented by types
 // that can unmarshal a JSON description of themselves.
 // The input can be assumed to be a valid encoding of
 // a JSON value. UnmarshalJSON must copy the JSON data
@@ -534,7 +535,7 @@ func (d *decodeState) array(v reflect.Value) {
 
 	if i < v.Len() {
 		if v.Kind() == reflect.Array {
-			// Array.  Zero the rest.
+			// Array. Zero the rest.
 			z := reflect.Zero(v.Type().Elem())
 			for ; i < v.Len(); i++ {
 				v.Index(i).Set(z)
@@ -549,6 +550,7 @@ func (d *decodeState) array(v reflect.Value) {
 }
 
 var nullLiteral = []byte("null")
+var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
 
 // object consumes an object from d.data[d.off-1:], decoding into the value v.
 // the first byte ('{') of the object has been read already.
@@ -577,16 +579,26 @@ func (d *decodeState) object(v reflect.Value) {
 		return
 	}
 
-	// Check type of target: struct or map[string]T
+	// Check type of target:
+	//   struct or
+	//   map[T1]T2 where T1 is string, an integer type,
+	//             or an encoding.TextUnmarshaler
 	switch v.Kind() {
 	case reflect.Map:
-		// map must have string kind
+		// Map key must either have string kind, have an integer kind,
+		// or be an encoding.TextUnmarshaler.
 		t := v.Type()
-		if t.Key().Kind() != reflect.String {
-			d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
-			d.off--
-			d.next() // skip over { } in input
-			return
+		switch t.Key().Kind() {
+		case reflect.String,
+			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		default:
+			if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
+				d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+				d.off--
+				d.next() // skip over { } in input
+				return
+			}
 		}
 		if v.IsNil() {
 			v.Set(reflect.MakeMap(t))
@@ -687,7 +699,37 @@ func (d *decodeState) object(v reflect.Value) {
 		// Write value back to map;
 		// if using struct, subv points into struct already.
 		if v.Kind() == reflect.Map {
-			kv := reflect.ValueOf(key).Convert(v.Type().Key())
+			kt := v.Type().Key()
+			var kv reflect.Value
+			switch {
+			case kt.Kind() == reflect.String:
+				kv = reflect.ValueOf(key).Convert(kt)
+			case reflect.PtrTo(kt).Implements(textUnmarshalerType):
+				kv = reflect.New(v.Type().Key())
+				d.literalStore(item, kv, true)
+				kv = kv.Elem()
+			default:
+				switch kt.Kind() {
+				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+					s := string(key)
+					n, err := strconv.ParseInt(s, 10, 64)
+					if err != nil || reflect.Zero(kt).OverflowInt(n) {
+						d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)})
+						return
+					}
+					kv = reflect.ValueOf(n).Convert(kt)
+				case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+					s := string(key)
+					n, err := strconv.ParseUint(s, 10, 64)
+					if err != nil || reflect.Zero(kt).OverflowUint(n) {
+						d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)})
+						return
+					}
+					kv = reflect.ValueOf(n).Convert(kt)
+				default:
+					panic("json: Unexpected key type") // should never occur
+				}
+			}
 			v.SetMapIndex(kv, subv)
 		}
 
@@ -902,7 +944,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 }
 
 // The xxxInterface routines build up a value to be stored
-// in an empty interface.  They are not strictly necessary,
+// in an empty interface. They are not strictly necessary,
 // but they avoid the weight of reflection in this common case.
 
 // valueInterface is like value but returns interface{}
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 9546ae4..255ff5c 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -7,10 +7,13 @@ package json
 import (
 	"bytes"
 	"encoding"
+	"errors"
 	"fmt"
 	"image"
+	"math"
 	"net"
 	"reflect"
+	"strconv"
 	"strings"
 	"testing"
 	"time"
@@ -52,6 +55,8 @@ type tx struct {
 	x int
 }
 
+type u8 uint8
+
 // A type that can unmarshal itself.
 
 type unmarshaler struct {
@@ -68,16 +73,20 @@ type ustruct struct {
 }
 
 type unmarshalerText struct {
-	T bool
+	A, B string
 }
 
 // needed for re-marshaling tests
-func (u *unmarshalerText) MarshalText() ([]byte, error) {
-	return []byte(""), nil
+func (u unmarshalerText) MarshalText() ([]byte, error) {
+	return []byte(u.A + ":" + u.B), nil
 }
 
 func (u *unmarshalerText) UnmarshalText(b []byte) error {
-	*u = unmarshalerText{true} // All we need to see that UnmarshalText is called.
+	pos := bytes.Index(b, []byte(":"))
+	if pos == -1 {
+		return errors.New("missing separator")
+	}
+	u.A, u.B = string(b[:pos]), string(b[pos+1:])
 	return nil
 }
 
@@ -87,6 +96,29 @@ type ustructText struct {
 	M unmarshalerText
 }
 
+// u8marshal is an integer type that can marshal/unmarshal itself.
+type u8marshal uint8
+
+func (u8 u8marshal) MarshalText() ([]byte, error) {
+	return []byte(fmt.Sprintf("u%d", u8)), nil
+}
+
+var errMissingU8Prefix = errors.New("missing 'u' prefix")
+
+func (u8 *u8marshal) UnmarshalText(b []byte) error {
+	if !bytes.HasPrefix(b, []byte{'u'}) {
+		return errMissingU8Prefix
+	}
+	n, err := strconv.Atoi(string(b[1:]))
+	if err != nil {
+		return err
+	}
+	*u8 = u8marshal(n)
+	return nil
+}
+
+var _ encoding.TextUnmarshaler = (*u8marshal)(nil)
+
 var (
 	um0, um1 unmarshaler // target2 of unmarshaling
 	ump      = &um1
@@ -95,12 +127,16 @@ var (
 	umslicep = new([]unmarshaler)
 	umstruct = ustruct{unmarshaler{true}}
 
-	um0T, um1T unmarshalerText // target2 of unmarshaling
-	umpT       = &um1T
-	umtrueT    = unmarshalerText{true}
-	umsliceT   = []unmarshalerText{{true}}
-	umslicepT  = new([]unmarshalerText)
-	umstructT  = ustructText{unmarshalerText{true}}
+	um0T, um1T   unmarshalerText // target2 of unmarshaling
+	umpType      = &um1T
+	umtrueXY     = unmarshalerText{"x", "y"}
+	umsliceXY    = []unmarshalerText{{"x", "y"}}
+	umslicepType = new([]unmarshalerText)
+	umstructType = new(ustructText)
+	umstructXY   = ustructText{unmarshalerText{"x", "y"}}
+
+	ummapType = map[unmarshalerText]bool{}
+	ummapXY   = map[unmarshalerText]bool{unmarshalerText{"x", "y"}: true}
 )
 
 // Test data structures for anonymous fields.
@@ -202,14 +238,6 @@ type S13 struct {
 	S8
 }
 
-type unmarshalTest struct {
-	in        string
-	ptr       interface{}
-	out       interface{}
-	err       error
-	useNumber bool
-}
-
 type Ambig struct {
 	// Given "hello", the first match should win.
 	First  int `json:"HELLO"`
@@ -225,6 +253,127 @@ type XYZ struct {
 func sliceAddr(x []int) *[]int                 { return &x }
 func mapAddr(x map[string]int) *map[string]int { return &x }
 
+type byteWithMarshalJSON byte
+
+func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) {
+	return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil
+}
+
+func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error {
+	if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' {
+		return fmt.Errorf("bad quoted string")
+	}
+	i, err := strconv.ParseInt(string(data[2:4]), 16, 8)
+	if err != nil {
+		return fmt.Errorf("bad hex")
+	}
+	*b = byteWithMarshalJSON(i)
+	return nil
+}
+
+type byteWithPtrMarshalJSON byte
+
+func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) {
+	return byteWithMarshalJSON(*b).MarshalJSON()
+}
+
+func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error {
+	return (*byteWithMarshalJSON)(b).UnmarshalJSON(data)
+}
+
+type byteWithMarshalText byte
+
+func (b byteWithMarshalText) MarshalText() ([]byte, error) {
+	return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil
+}
+
+func (b *byteWithMarshalText) UnmarshalText(data []byte) error {
+	if len(data) != 3 || data[0] != 'Z' {
+		return fmt.Errorf("bad quoted string")
+	}
+	i, err := strconv.ParseInt(string(data[1:3]), 16, 8)
+	if err != nil {
+		return fmt.Errorf("bad hex")
+	}
+	*b = byteWithMarshalText(i)
+	return nil
+}
+
+type byteWithPtrMarshalText byte
+
+func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) {
+	return byteWithMarshalText(*b).MarshalText()
+}
+
+func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error {
+	return (*byteWithMarshalText)(b).UnmarshalText(data)
+}
+
+type intWithMarshalJSON int
+
+func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) {
+	return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil
+}
+
+func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error {
+	if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' {
+		return fmt.Errorf("bad quoted string")
+	}
+	i, err := strconv.ParseInt(string(data[2:4]), 16, 8)
+	if err != nil {
+		return fmt.Errorf("bad hex")
+	}
+	*b = intWithMarshalJSON(i)
+	return nil
+}
+
+type intWithPtrMarshalJSON int
+
+func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) {
+	return intWithMarshalJSON(*b).MarshalJSON()
+}
+
+func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error {
+	return (*intWithMarshalJSON)(b).UnmarshalJSON(data)
+}
+
+type intWithMarshalText int
+
+func (b intWithMarshalText) MarshalText() ([]byte, error) {
+	return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil
+}
+
+func (b *intWithMarshalText) UnmarshalText(data []byte) error {
+	if len(data) != 3 || data[0] != 'Z' {
+		return fmt.Errorf("bad quoted string")
+	}
+	i, err := strconv.ParseInt(string(data[1:3]), 16, 8)
+	if err != nil {
+		return fmt.Errorf("bad hex")
+	}
+	*b = intWithMarshalText(i)
+	return nil
+}
+
+type intWithPtrMarshalText int
+
+func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) {
+	return intWithMarshalText(*b).MarshalText()
+}
+
+func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error {
+	return (*intWithMarshalText)(b).UnmarshalText(data)
+}
+
+type unmarshalTest struct {
+	in        string
+	ptr       interface{}
+	out       interface{}
+	err       error
+	useNumber bool
+	golden    bool
+}
+
 var unmarshalTests = []unmarshalTest{
 	// basic types
 	{in: `true`, ptr: new(bool), out: true},
@@ -302,14 +451,81 @@ var unmarshalTests = []unmarshalTest{
 	{in: `{"T":false}`, ptr: &ump, out: &umtrue},
 	{in: `[{"T":false}]`, ptr: &umslice, out: umslice},
 	{in: `[{"T":false}]`, ptr: &umslicep, out: &umslice},
-	{in: `{"M":{"T":false}}`, ptr: &umstruct, out: umstruct},
+	{in: `{"M":{"T":"x:y"}}`, ptr: &umstruct, out: umstruct},
 
 	// UnmarshalText interface test
-	{in: `"X"`, ptr: &um0T, out: umtrueT}, // use "false" so test will fail if custom unmarshaler is not called
-	{in: `"X"`, ptr: &umpT, out: &umtrueT},
-	{in: `["X"]`, ptr: &umsliceT, out: umsliceT},
-	{in: `["X"]`, ptr: &umslicepT, out: &umsliceT},
-	{in: `{"M":"X"}`, ptr: &umstructT, out: umstructT},
+	{in: `"x:y"`, ptr: &um0T, out: umtrueXY},
+	{in: `"x:y"`, ptr: &umpType, out: &umtrueXY},
+	{in: `["x:y"]`, ptr: &umsliceXY, out: umsliceXY},
+	{in: `["x:y"]`, ptr: &umslicepType, out: &umsliceXY},
+	{in: `{"M":"x:y"}`, ptr: umstructType, out: umstructXY},
+
+	// integer-keyed map test
+	{
+		in:  `{"-1":"a","0":"b","1":"c"}`,
+		ptr: new(map[int]string),
+		out: map[int]string{-1: "a", 0: "b", 1: "c"},
+	},
+	{
+		in:  `{"0":"a","10":"c","9":"b"}`,
+		ptr: new(map[u8]string),
+		out: map[u8]string{0: "a", 9: "b", 10: "c"},
+	},
+	{
+		in:  `{"-9223372036854775808":"min","9223372036854775807":"max"}`,
+		ptr: new(map[int64]string),
+		out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"},
+	},
+	{
+		in:  `{"18446744073709551615":"max"}`,
+		ptr: new(map[uint64]string),
+		out: map[uint64]string{math.MaxUint64: "max"},
+	},
+	{
+		in:  `{"0":false,"10":true}`,
+		ptr: new(map[uintptr]bool),
+		out: map[uintptr]bool{0: false, 10: true},
+	},
+
+	// Check that MarshalText and UnmarshalText take precedence
+	// over default integer handling in map keys.
+	{
+		in:  `{"u2":4}`,
+		ptr: new(map[u8marshal]int),
+		out: map[u8marshal]int{2: 4},
+	},
+	{
+		in:  `{"2":4}`,
+		ptr: new(map[u8marshal]int),
+		err: errMissingU8Prefix,
+	},
+
+	// integer-keyed map errors
+	{
+		in:  `{"abc":"abc"}`,
+		ptr: new(map[int]string),
+		err: &UnmarshalTypeError{"number abc", reflect.TypeOf(0), 2},
+	},
+	{
+		in:  `{"256":"abc"}`,
+		ptr: new(map[uint8]string),
+		err: &UnmarshalTypeError{"number 256", reflect.TypeOf(uint8(0)), 2},
+	},
+	{
+		in:  `{"128":"abc"}`,
+		ptr: new(map[int8]string),
+		err: &UnmarshalTypeError{"number 128", reflect.TypeOf(int8(0)), 2},
+	},
+	{
+		in:  `{"-1":"abc"}`,
+		ptr: new(map[uint8]string),
+		err: &UnmarshalTypeError{"number -1", reflect.TypeOf(uint8(0)), 2},
+	},
+
+	// Map keys can be encoding.TextUnmarshalers.
+	{in: `{"x:y":true}`, ptr: &ummapType, out: ummapXY},
+	// If multiple values for the same key exists, only the most recent value is used.
+	{in: `{"x:y":false,"x:y":true}`, ptr: &ummapType, out: ummapXY},
 
 	// Overwriting of data.
 	// This is different from package xml, but it's what we've always done.
@@ -426,11 +642,101 @@ var unmarshalTests = []unmarshalTest{
 		out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld",
 	},
 
-	// issue 8305
+	// Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now.
 	{
 		in:  `{"2009-11-10T23:00:00Z": "hello world"}`,
 		ptr: &map[time.Time]string{},
-		err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{}), 1},
+		out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"},
+	},
+
+	// issue 8305
+	{
+		in:  `{"2009-11-10T23:00:00Z": "hello world"}`,
+		ptr: &map[Point]string{},
+		err: &UnmarshalTypeError{"object", reflect.TypeOf(map[Point]string{}), 1},
+	},
+	{
+		in:  `{"asdf": "hello world"}`,
+		ptr: &map[unmarshaler]string{},
+		err: &UnmarshalTypeError{"object", reflect.TypeOf(map[unmarshaler]string{}), 1},
+	},
+
+	// related to issue 13783.
+	// Go 1.7 changed marshaling a slice of typed byte to use the methods on the byte type,
+	// similar to marshaling a slice of typed int.
+	// These tests check that, assuming the byte type also has valid decoding methods,
+	// either the old base64 string encoding or the new per-element encoding can be
+	// successfully unmarshaled. The custom unmarshalers were accessible in earlier
+	// versions of Go, even though the custom marshaler was not.
+	{
+		in:  `"AQID"`,
+		ptr: new([]byteWithMarshalJSON),
+		out: []byteWithMarshalJSON{1, 2, 3},
+	},
+	{
+		in:     `["Z01","Z02","Z03"]`,
+		ptr:    new([]byteWithMarshalJSON),
+		out:    []byteWithMarshalJSON{1, 2, 3},
+		golden: true,
+	},
+	{
+		in:  `"AQID"`,
+		ptr: new([]byteWithMarshalText),
+		out: []byteWithMarshalText{1, 2, 3},
+	},
+	{
+		in:     `["Z01","Z02","Z03"]`,
+		ptr:    new([]byteWithMarshalText),
+		out:    []byteWithMarshalText{1, 2, 3},
+		golden: true,
+	},
+	{
+		in:  `"AQID"`,
+		ptr: new([]byteWithPtrMarshalJSON),
+		out: []byteWithPtrMarshalJSON{1, 2, 3},
+	},
+	{
+		in:     `["Z01","Z02","Z03"]`,
+		ptr:    new([]byteWithPtrMarshalJSON),
+		out:    []byteWithPtrMarshalJSON{1, 2, 3},
+		golden: true,
+	},
+	{
+		in:  `"AQID"`,
+		ptr: new([]byteWithPtrMarshalText),
+		out: []byteWithPtrMarshalText{1, 2, 3},
+	},
+	{
+		in:     `["Z01","Z02","Z03"]`,
+		ptr:    new([]byteWithPtrMarshalText),
+		out:    []byteWithPtrMarshalText{1, 2, 3},
+		golden: true,
+	},
+
+	// ints work with the marshaler but not the base64 []byte case
+	{
+		in:     `["Z01","Z02","Z03"]`,
+		ptr:    new([]intWithMarshalJSON),
+		out:    []intWithMarshalJSON{1, 2, 3},
+		golden: true,
+	},
+	{
+		in:     `["Z01","Z02","Z03"]`,
+		ptr:    new([]intWithMarshalText),
+		out:    []intWithMarshalText{1, 2, 3},
+		golden: true,
+	},
+	{
+		in:     `["Z01","Z02","Z03"]`,
+		ptr:    new([]intWithPtrMarshalJSON),
+		out:    []intWithPtrMarshalJSON{1, 2, 3},
+		golden: true,
+	},
+	{
+		in:     `["Z01","Z02","Z03"]`,
+		ptr:    new([]intWithPtrMarshalText),
+		out:    []intWithPtrMarshalText{1, 2, 3},
+		golden: true,
 	},
 }
 
@@ -565,13 +871,16 @@ func TestUnmarshal(t *testing.T) {
 			continue
 		}
 
-		// Check round trip.
+		// Check round trip also decodes correctly.
 		if tt.err == nil {
 			enc, err := Marshal(v.Interface())
 			if err != nil {
 				t.Errorf("#%d: error re-marshaling: %v", i, err)
 				continue
 			}
+			if tt.golden && !bytes.Equal(enc, in) {
+				t.Errorf("#%d: remarshal mismatch:\nhave: %s\nwant: %s", i, enc, in)
+			}
 			vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
 			dec = NewDecoder(bytes.NewReader(enc))
 			if tt.useNumber {
@@ -1270,7 +1579,7 @@ func TestSliceOfCustomByte(t *testing.T) {
 		t.Fatal(err)
 	}
 	if !reflect.DeepEqual(a, b) {
-		t.Fatal("expected %v == %v", a, b)
+		t.Fatalf("expected %v == %v", a, b)
 	}
 }
 
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index 69ac7e0..6bb6de8 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -1,9 +1,9 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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 json implements encoding and decoding of JSON objects as defined in
-// RFC 4627. The mapping between JSON objects and Go values is described
+// Package json implements encoding and decoding of JSON as defined in
+// RFC 4627. The mapping between JSON and Go values is described
 // in the documentation for the Marshal and Unmarshal functions.
 //
 // See "JSON and Go" for an introduction to this package:
@@ -22,6 +22,7 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+	"sync/atomic"
 	"unicode"
 	"unicode/utf8"
 )
@@ -49,10 +50,11 @@ import (
 // The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
 // to keep some browsers from misinterpreting JSON output as HTML.
 // Ampersand "&" is also escaped to "\u0026" for the same reason.
+// This escaping can be disabled using an Encoder with DisableHTMLEscaping.
 //
 // Array and slice values encode as JSON arrays, except that
 // []byte encodes as a base64-encoded string, and a nil slice
-// encodes as the null JSON object.
+// encodes as the null JSON value.
 //
 // Struct values encode as JSON objects. Each exported struct field
 // becomes a member of the object unless
@@ -89,8 +91,8 @@ import (
 //    Int64String int64 `json:",string"`
 //
 // The key name will be used if it's a non-empty string consisting of
-// only Unicode letters, digits, dollar signs, percent signs, hyphens,
-// underscores and slashes.
+// only Unicode letters, digits, and ASCII punctuation except quotation
+// marks, backslash, and comma.
 //
 // Anonymous struct fields are usually marshaled as if their inner exported fields
 // were fields in the outer struct, subject to the usual Go visibility rules amended
@@ -116,27 +118,31 @@ import (
 // an anonymous struct field in both current and earlier versions, give the field
 // a JSON tag of "-".
 //
-// Map values encode as JSON objects.
-// 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.
+// Map values encode as JSON objects. The map's key type must either be a
+// string, an integer type, or implement encoding.TextMarshaler. The map keys
+// are sorted and used as JSON object keys by applying the following rules,
+// subject to the UTF-8 coercion described for string values above:
+//   - string keys are used directly
+//   - encoding.TextMarshalers are marshaled
+//   - integer keys are converted to strings
 //
 // Pointer values encode as the value pointed to.
-// A nil pointer encodes as the null JSON object.
+// A nil pointer encodes as the null JSON value.
 //
 // Interface values encode as the value contained in the interface.
-// A nil interface value encodes as the null JSON object.
+// A nil interface value encodes as the null JSON value.
 //
 // Channel, complex, and function values cannot be encoded in JSON.
 // Attempting to encode such a value causes Marshal to return
 // an UnsupportedTypeError.
 //
 // JSON cannot represent cyclic data structures and Marshal does not
-// handle them.  Passing cyclic structures to Marshal will result in
+// handle them. Passing cyclic structures to Marshal will result in
 // an infinite recursion.
 //
 func Marshal(v interface{}) ([]byte, error) {
 	e := &encodeState{}
-	err := e.marshal(v)
+	err := e.marshal(v, encOpts{escapeHTML: true})
 	if err != nil {
 		return nil, err
 	}
@@ -192,7 +198,7 @@ func HTMLEscape(dst *bytes.Buffer, src []byte) {
 	}
 }
 
-// Marshaler is the interface implemented by objects that
+// Marshaler is the interface implemented by types that
 // can marshal themselves into valid JSON.
 type Marshaler interface {
 	MarshalJSON() ([]byte, error)
@@ -259,7 +265,7 @@ func newEncodeState() *encodeState {
 	return new(encodeState)
 }
 
-func (e *encodeState) marshal(v interface{}) (err error) {
+func (e *encodeState) marshal(v interface{}, opts encOpts) (err error) {
 	defer func() {
 		if r := recover(); r != nil {
 			if _, ok := r.(runtime.Error); ok {
@@ -271,7 +277,7 @@ func (e *encodeState) marshal(v interface{}) (err error) {
 			err = r.(error)
 		}
 	}()
-	e.reflectValue(reflect.ValueOf(v))
+	e.reflectValue(reflect.ValueOf(v), opts)
 	return nil
 }
 
@@ -297,11 +303,18 @@ func isEmptyValue(v reflect.Value) bool {
 	return false
 }
 
-func (e *encodeState) reflectValue(v reflect.Value) {
-	valueEncoder(v)(e, v, false)
+func (e *encodeState) reflectValue(v reflect.Value, opts encOpts) {
+	valueEncoder(v)(e, v, opts)
 }
 
-type encoderFunc func(e *encodeState, v reflect.Value, quoted bool)
+type encOpts struct {
+	// quoted causes primitive fields to be encoded inside JSON strings.
+	quoted bool
+	// escapeHTML causes '<', '>', and '&' to be escaped in JSON strings.
+	escapeHTML bool
+}
+
+type encoderFunc func(e *encodeState, v reflect.Value, opts encOpts)
 
 var encoderCache struct {
 	sync.RWMutex
@@ -325,7 +338,7 @@ func typeEncoder(t reflect.Type) encoderFunc {
 
 	// To deal with recursive types, populate the map with an
 	// indirect func before we build it. This type waits on the
-	// real func (f) to be ready and then calls it.  This indirect
+	// real func (f) to be ready and then calls it. This indirect
 	// func is only used for recursive types.
 	encoderCache.Lock()
 	if encoderCache.m == nil {
@@ -333,9 +346,9 @@ func typeEncoder(t reflect.Type) encoderFunc {
 	}
 	var wg sync.WaitGroup
 	wg.Add(1)
-	encoderCache.m[t] = func(e *encodeState, v reflect.Value, quoted bool) {
+	encoderCache.m[t] = func(e *encodeState, v reflect.Value, opts encOpts) {
 		wg.Wait()
-		f(e, v, quoted)
+		f(e, v, opts)
 	}
 	encoderCache.Unlock()
 
@@ -405,11 +418,11 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
 	}
 }
 
-func invalidValueEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func invalidValueEncoder(e *encodeState, v reflect.Value, _ encOpts) {
 	e.WriteString("null")
 }
 
-func marshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
 	if v.Kind() == reflect.Ptr && v.IsNil() {
 		e.WriteString("null")
 		return
@@ -418,14 +431,14 @@ func marshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
 	b, err := m.MarshalJSON()
 	if err == nil {
 		// copy JSON into buffer, checking validity.
-		err = compact(&e.Buffer, b, true)
+		err = compact(&e.Buffer, b, opts.escapeHTML)
 	}
 	if err != nil {
 		e.error(&MarshalerError{v.Type(), err})
 	}
 }
 
-func addrMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func addrMarshalerEncoder(e *encodeState, v reflect.Value, _ encOpts) {
 	va := v.Addr()
 	if va.IsNil() {
 		e.WriteString("null")
@@ -442,7 +455,7 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
 	}
 }
 
-func textMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func textMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
 	if v.Kind() == reflect.Ptr && v.IsNil() {
 		e.WriteString("null")
 		return
@@ -452,10 +465,10 @@ func textMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
 	if err != nil {
 		e.error(&MarshalerError{v.Type(), err})
 	}
-	e.stringBytes(b)
+	e.stringBytes(b, opts.escapeHTML)
 }
 
-func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
 	va := v.Addr()
 	if va.IsNil() {
 		e.WriteString("null")
@@ -466,11 +479,11 @@ func addrTextMarshalerEncoder(e *encodeState, v reflect.Value, quoted bool) {
 	if err != nil {
 		e.error(&MarshalerError{v.Type(), err})
 	}
-	e.stringBytes(b)
+	e.stringBytes(b, opts.escapeHTML)
 }
 
-func boolEncoder(e *encodeState, v reflect.Value, quoted bool) {
-	if quoted {
+func boolEncoder(e *encodeState, v reflect.Value, opts encOpts) {
+	if opts.quoted {
 		e.WriteByte('"')
 	}
 	if v.Bool() {
@@ -478,46 +491,46 @@ func boolEncoder(e *encodeState, v reflect.Value, quoted bool) {
 	} else {
 		e.WriteString("false")
 	}
-	if quoted {
+	if opts.quoted {
 		e.WriteByte('"')
 	}
 }
 
-func intEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func intEncoder(e *encodeState, v reflect.Value, opts encOpts) {
 	b := strconv.AppendInt(e.scratch[:0], v.Int(), 10)
-	if quoted {
+	if opts.quoted {
 		e.WriteByte('"')
 	}
 	e.Write(b)
-	if quoted {
+	if opts.quoted {
 		e.WriteByte('"')
 	}
 }
 
-func uintEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func uintEncoder(e *encodeState, v reflect.Value, opts encOpts) {
 	b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10)
-	if quoted {
+	if opts.quoted {
 		e.WriteByte('"')
 	}
 	e.Write(b)
-	if quoted {
+	if opts.quoted {
 		e.WriteByte('"')
 	}
 }
 
 type floatEncoder int // number of bits
 
-func (bits floatEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
+func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
 	f := v.Float()
 	if math.IsInf(f, 0) || math.IsNaN(f) {
 		e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))})
 	}
 	b := strconv.AppendFloat(e.scratch[:0], f, 'g', -1, int(bits))
-	if quoted {
+	if opts.quoted {
 		e.WriteByte('"')
 	}
 	e.Write(b)
-	if quoted {
+	if opts.quoted {
 		e.WriteByte('"')
 	}
 }
@@ -527,7 +540,7 @@ var (
 	float64Encoder = (floatEncoder(64)).encode
 )
 
-func stringEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) {
 	if v.Type() == numberType {
 		numStr := v.String()
 		// In Go1.5 the empty string encodes to "0", while this is not a valid number literal
@@ -541,26 +554,26 @@ func stringEncoder(e *encodeState, v reflect.Value, quoted bool) {
 		e.WriteString(numStr)
 		return
 	}
-	if quoted {
+	if opts.quoted {
 		sb, err := Marshal(v.String())
 		if err != nil {
 			e.error(err)
 		}
-		e.string(string(sb))
+		e.string(string(sb), opts.escapeHTML)
 	} else {
-		e.string(v.String())
+		e.string(v.String(), opts.escapeHTML)
 	}
 }
 
-func interfaceEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func interfaceEncoder(e *encodeState, v reflect.Value, opts encOpts) {
 	if v.IsNil() {
 		e.WriteString("null")
 		return
 	}
-	e.reflectValue(v.Elem())
+	e.reflectValue(v.Elem(), opts)
 }
 
-func unsupportedTypeEncoder(e *encodeState, v reflect.Value, quoted bool) {
+func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) {
 	e.error(&UnsupportedTypeError{v.Type()})
 }
 
@@ -569,7 +582,7 @@ type structEncoder struct {
 	fieldEncs []encoderFunc
 }
 
-func (se *structEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
+func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
 	e.WriteByte('{')
 	first := true
 	for i, f := range se.fields {
@@ -582,9 +595,10 @@ func (se *structEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
 		} else {
 			e.WriteByte(',')
 		}
-		e.string(f.name)
+		e.string(f.name, opts.escapeHTML)
 		e.WriteByte(':')
-		se.fieldEncs[i](e, fv, f.quoted)
+		opts.quoted = f.quoted
+		se.fieldEncs[i](e, fv, opts)
 	}
 	e.WriteByte('}')
 }
@@ -605,34 +619,50 @@ type mapEncoder struct {
 	elemEnc encoderFunc
 }
 
-func (me *mapEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
+func (me *mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
 	if v.IsNil() {
 		e.WriteString("null")
 		return
 	}
 	e.WriteByte('{')
-	var sv stringValues = v.MapKeys()
-	sort.Sort(sv)
-	for i, k := range sv {
+
+	// Extract and sort the keys.
+	keys := v.MapKeys()
+	sv := make([]reflectWithString, len(keys))
+	for i, v := range keys {
+		sv[i].v = v
+		if err := sv[i].resolve(); err != nil {
+			e.error(&MarshalerError{v.Type(), err})
+		}
+	}
+	sort.Sort(byString(sv))
+
+	for i, kv := range sv {
 		if i > 0 {
 			e.WriteByte(',')
 		}
-		e.string(k.String())
+		e.string(kv.s, opts.escapeHTML)
 		e.WriteByte(':')
-		me.elemEnc(e, v.MapIndex(k), false)
+		me.elemEnc(e, v.MapIndex(kv.v), opts)
 	}
 	e.WriteByte('}')
 }
 
 func newMapEncoder(t reflect.Type) encoderFunc {
-	if t.Key().Kind() != reflect.String {
-		return unsupportedTypeEncoder
+	switch t.Key().Kind() {
+	case reflect.String,
+		reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+	default:
+		if !t.Key().Implements(textMarshalerType) {
+			return unsupportedTypeEncoder
+		}
 	}
 	me := &mapEncoder{typeEncoder(t.Elem())}
 	return me.encode
 }
 
-func encodeByteSlice(e *encodeState, v reflect.Value, _ bool) {
+func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) {
 	if v.IsNil() {
 		e.WriteString("null")
 		return
@@ -659,18 +689,21 @@ type sliceEncoder struct {
 	arrayEnc encoderFunc
 }
 
-func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
+func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
 	if v.IsNil() {
 		e.WriteString("null")
 		return
 	}
-	se.arrayEnc(e, v, false)
+	se.arrayEnc(e, v, opts)
 }
 
 func newSliceEncoder(t reflect.Type) encoderFunc {
 	// Byte slices get special treatment; arrays don't.
 	if t.Elem().Kind() == reflect.Uint8 {
-		return encodeByteSlice
+		p := reflect.PtrTo(t.Elem())
+		if !p.Implements(marshalerType) && !p.Implements(textMarshalerType) {
+			return encodeByteSlice
+		}
 	}
 	enc := &sliceEncoder{newArrayEncoder(t)}
 	return enc.encode
@@ -680,14 +713,14 @@ type arrayEncoder struct {
 	elemEnc encoderFunc
 }
 
-func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, _ bool) {
+func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
 	e.WriteByte('[')
 	n := v.Len()
 	for i := 0; i < n; i++ {
 		if i > 0 {
 			e.WriteByte(',')
 		}
-		ae.elemEnc(e, v.Index(i), false)
+		ae.elemEnc(e, v.Index(i), opts)
 	}
 	e.WriteByte(']')
 }
@@ -701,12 +734,12 @@ type ptrEncoder struct {
 	elemEnc encoderFunc
 }
 
-func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
+func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
 	if v.IsNil() {
 		e.WriteString("null")
 		return
 	}
-	pe.elemEnc(e, v.Elem(), quoted)
+	pe.elemEnc(e, v.Elem(), opts)
 }
 
 func newPtrEncoder(t reflect.Type) encoderFunc {
@@ -718,11 +751,11 @@ type condAddrEncoder struct {
 	canAddrEnc, elseEnc encoderFunc
 }
 
-func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, quoted bool) {
+func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
 	if v.CanAddr() {
-		ce.canAddrEnc(e, v, quoted)
+		ce.canAddrEnc(e, v, opts)
 	} else {
-		ce.elseEnc(e, v, quoted)
+		ce.elseEnc(e, v, opts)
 	}
 }
 
@@ -775,23 +808,50 @@ func typeByIndex(t reflect.Type, index []int) reflect.Type {
 	return t
 }
 
-// stringValues is a slice of reflect.Value holding *reflect.StringValue.
+type reflectWithString struct {
+	v reflect.Value
+	s string
+}
+
+func (w *reflectWithString) resolve() error {
+	if w.v.Kind() == reflect.String {
+		w.s = w.v.String()
+		return nil
+	}
+	if tm, ok := w.v.Interface().(encoding.TextMarshaler); ok {
+		buf, err := tm.MarshalText()
+		w.s = string(buf)
+		return err
+	}
+	switch w.v.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		w.s = strconv.FormatInt(w.v.Int(), 10)
+		return nil
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+		w.s = strconv.FormatUint(w.v.Uint(), 10)
+		return nil
+	}
+	panic("unexpected map key type")
+}
+
+// byString is a slice of reflectWithString where the reflect.Value is either
+// a string or an encoding.TextMarshaler.
 // It implements the methods to sort by string.
-type stringValues []reflect.Value
+type byString []reflectWithString
 
-func (sv stringValues) Len() int           { return len(sv) }
-func (sv stringValues) Swap(i, j int)      { sv[i], sv[j] = sv[j], sv[i] }
-func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
-func (sv stringValues) get(i int) string   { return sv[i].String() }
+func (sv byString) Len() int           { return len(sv) }
+func (sv byString) Swap(i, j int)      { sv[i], sv[j] = sv[j], sv[i] }
+func (sv byString) Less(i, j int) bool { return sv[i].s < sv[j].s }
 
 // NOTE: keep in sync with stringBytes below.
-func (e *encodeState) string(s string) int {
+func (e *encodeState) string(s string, escapeHTML bool) int {
 	len0 := e.Len()
 	e.WriteByte('"')
 	start := 0
 	for i := 0; i < len(s); {
 		if b := s[i]; b < utf8.RuneSelf {
-			if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
+			if 0x20 <= b && b != '\\' && b != '"' &&
+				(!escapeHTML || b != '<' && b != '>' && b != '&') {
 				i++
 				continue
 			}
@@ -812,10 +872,11 @@ func (e *encodeState) string(s string) int {
 				e.WriteByte('\\')
 				e.WriteByte('t')
 			default:
-				// This encodes bytes < 0x20 except for \n and \r,
-				// as well as <, > and &. The latter are escaped because they
-				// can lead to security holes when user-controlled strings
-				// are rendered into JSON and served to some browsers.
+				// This encodes bytes < 0x20 except for \t, \n and \r.
+				// If escapeHTML is set, it also escapes <, >, and &
+				// because they can lead to security holes when
+				// user-controlled strings are rendered into JSON
+				// and served to some browsers.
 				e.WriteString(`\u00`)
 				e.WriteByte(hex[b>>4])
 				e.WriteByte(hex[b&0xF])
@@ -861,13 +922,14 @@ func (e *encodeState) string(s string) int {
 }
 
 // NOTE: keep in sync with string above.
-func (e *encodeState) stringBytes(s []byte) int {
+func (e *encodeState) stringBytes(s []byte, escapeHTML bool) int {
 	len0 := e.Len()
 	e.WriteByte('"')
 	start := 0
 	for i := 0; i < len(s); {
 		if b := s[i]; b < utf8.RuneSelf {
-			if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' && b != '&' {
+			if 0x20 <= b && b != '\\' && b != '"' &&
+				(!escapeHTML || b != '<' && b != '>' && b != '&') {
 				i++
 				continue
 			}
@@ -888,10 +950,11 @@ func (e *encodeState) stringBytes(s []byte) int {
 				e.WriteByte('\\')
 				e.WriteByte('t')
 			default:
-				// This encodes bytes < 0x20 except for \n and \r,
-				// as well as <, >, and &. The latter are escaped because they
-				// can lead to security holes when user-controlled strings
-				// are rendered into JSON and served to some browsers.
+				// This encodes bytes < 0x20 except for \t, \n and \r.
+				// If escapeHTML is set, it also escapes <, >, and &
+				// because they can lead to security holes when
+				// user-controlled strings are rendered into JSON
+				// and served to some browsers.
 				e.WriteString(`\u00`)
 				e.WriteByte(hex[b>>4])
 				e.WriteByte(hex[b&0xF])
@@ -1169,15 +1232,14 @@ func dominantField(fields []field) (field, bool) {
 }
 
 var fieldCache struct {
-	sync.RWMutex
-	m map[reflect.Type][]field
+	value atomic.Value // map[reflect.Type][]field
+	mu    sync.Mutex   // used only by writers
 }
 
 // cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
 func cachedTypeFields(t reflect.Type) []field {
-	fieldCache.RLock()
-	f := fieldCache.m[t]
-	fieldCache.RUnlock()
+	m, _ := fieldCache.value.Load().(map[reflect.Type][]field)
+	f := m[t]
 	if f != nil {
 		return f
 	}
@@ -1189,11 +1251,14 @@ func cachedTypeFields(t reflect.Type) []field {
 		f = []field{}
 	}
 
-	fieldCache.Lock()
-	if fieldCache.m == nil {
-		fieldCache.m = map[reflect.Type][]field{}
+	fieldCache.mu.Lock()
+	m, _ = fieldCache.value.Load().(map[reflect.Type][]field)
+	newM := make(map[reflect.Type][]field, len(m)+1)
+	for k, v := range m {
+		newM[k] = v
 	}
-	fieldCache.m[t] = f
-	fieldCache.Unlock()
+	newM[t] = f
+	fieldCache.value.Store(newM)
+	fieldCache.mu.Unlock()
 	return f
 }
diff --git a/src/encoding/json/encode_test.go b/src/encoding/json/encode_test.go
index c00491e..b484022 100644
--- a/src/encoding/json/encode_test.go
+++ b/src/encoding/json/encode_test.go
@@ -6,6 +6,7 @@ package json
 
 import (
 	"bytes"
+	"fmt"
 	"math"
 	"reflect"
 	"testing"
@@ -375,41 +376,45 @@ func TestDuplicatedFieldDisappears(t *testing.T) {
 
 func TestStringBytes(t *testing.T) {
 	// Test that encodeState.stringBytes and encodeState.string use the same encoding.
-	es := &encodeState{}
 	var r []rune
 	for i := '\u0000'; i <= unicode.MaxRune; i++ {
 		r = append(r, i)
 	}
 	s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too
-	es.string(s)
 
-	esBytes := &encodeState{}
-	esBytes.stringBytes([]byte(s))
+	for _, escapeHTML := range []bool{true, false} {
+		es := &encodeState{}
+		es.string(s, escapeHTML)
 
-	enc := es.Buffer.String()
-	encBytes := esBytes.Buffer.String()
-	if enc != encBytes {
-		i := 0
-		for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
-			i++
-		}
-		enc = enc[i:]
-		encBytes = encBytes[i:]
-		i = 0
-		for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
-			i++
-		}
-		enc = enc[:len(enc)-i]
-		encBytes = encBytes[:len(encBytes)-i]
+		esBytes := &encodeState{}
+		esBytes.stringBytes([]byte(s), escapeHTML)
 
-		if len(enc) > 20 {
-			enc = enc[:20] + "..."
-		}
-		if len(encBytes) > 20 {
-			encBytes = encBytes[:20] + "..."
-		}
+		enc := es.Buffer.String()
+		encBytes := esBytes.Buffer.String()
+		if enc != encBytes {
+			i := 0
+			for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] {
+				i++
+			}
+			enc = enc[i:]
+			encBytes = encBytes[i:]
+			i = 0
+			for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] {
+				i++
+			}
+			enc = enc[:len(enc)-i]
+			encBytes = encBytes[:len(encBytes)-i]
+
+			if len(enc) > 20 {
+				enc = enc[:20] + "..."
+			}
+			if len(encBytes) > 20 {
+				encBytes = encBytes[:20] + "..."
+			}
 
-		t.Errorf("encodings differ at %#q vs %#q", enc, encBytes)
+			t.Errorf("with escapeHTML=%t, encodings differ at %#q vs %#q",
+				escapeHTML, enc, encBytes)
+		}
 	}
 }
 
@@ -536,3 +541,73 @@ func TestEncodeString(t *testing.T) {
 		}
 	}
 }
+
+type jsonbyte byte
+
+func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) }
+
+type textbyte byte
+
+func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) }
+
+type jsonint int
+
+func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) }
+
+type textint int
+
+func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) }
+
+func tenc(format string, a ...interface{}) ([]byte, error) {
+	var buf bytes.Buffer
+	fmt.Fprintf(&buf, format, a...)
+	return buf.Bytes(), nil
+}
+
+// Issue 13783
+func TestEncodeBytekind(t *testing.T) {
+	testdata := []struct {
+		data interface{}
+		want string
+	}{
+		{byte(7), "7"},
+		{jsonbyte(7), `{"JB":7}`},
+		{textbyte(4), `"TB:4"`},
+		{jsonint(5), `{"JI":5}`},
+		{textint(1), `"TI:1"`},
+		{[]byte{0, 1}, `"AAE="`},
+		{[]jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`},
+		{[][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`},
+		{[]textbyte{2, 3}, `["TB:2","TB:3"]`},
+		{[]jsonint{5, 4}, `[{"JI":5},{"JI":4}]`},
+		{[]textint{9, 3}, `["TI:9","TI:3"]`},
+		{[]int{9, 3}, `[9,3]`},
+	}
+	for _, d := range testdata {
+		js, err := Marshal(d.data)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		got, want := string(js), d.want
+		if got != want {
+			t.Errorf("got %s, want %s", got, want)
+		}
+	}
+}
+
+func TestTextMarshalerMapKeysAreSorted(t *testing.T) {
+	b, err := Marshal(map[unmarshalerText]int{
+		{"x", "y"}: 1,
+		{"y", "x"}: 2,
+		{"a", "z"}: 3,
+		{"z", "a"}: 4,
+	})
+	if err != nil {
+		t.Fatalf("Failed to Marshal text.Marshaler: %v", err)
+	}
+	const want = `{"a:z":3,"x:y":1,"y:x":2,"z:a":4}`
+	if string(b) != want {
+		t.Errorf("Marshal map with text.Marshaler keys: got %#q, want %#q", b, want)
+	}
+}
diff --git a/src/encoding/json/example_test.go b/src/encoding/json/example_test.go
index da08e10..555eff9 100644
--- a/src/encoding/json/example_test.go
+++ b/src/encoding/json/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -143,10 +143,9 @@ func ExampleDecoder_Decode_stream() {
 	}
 	fmt.Printf("%T: %v\n", t, t)
 
-	var m Message
 	// while the array contains values
 	for dec.More() {
-
+		var m Message
 		// decode an array value (Message)
 		err := dec.Decode(&m)
 		if err != nil {
diff --git a/src/encoding/json/indent.go b/src/encoding/json/indent.go
index 7cd9f4d..fba1954 100644
--- a/src/encoding/json/indent.go
+++ b/src/encoding/json/indent.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/encoding/json/number_test.go b/src/encoding/json/number_test.go
index 4e63cf9..4b86999 100644
--- a/src/encoding/json/number_test.go
+++ b/src/encoding/json/number_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/encoding/json/scanner.go b/src/encoding/json/scanner.go
index ee6622e..a6d8706 100644
--- a/src/encoding/json/scanner.go
+++ b/src/encoding/json/scanner.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -132,7 +132,7 @@ const (
 
 // These values are stored in the parseState stack.
 // They give the current state of a composite value
-// being scanned.  If the parser is inside a nested value
+// being scanned. If the parser is inside a nested value
 // the parseState describes the nested state, outermost at entry 0.
 const (
 	parseObjectKey   = iota // parsing object key (before colon)
diff --git a/src/encoding/json/scanner_test.go b/src/encoding/json/scanner_test.go
index 66383ef..70a2897 100644
--- a/src/encoding/json/scanner_test.go
+++ b/src/encoding/json/scanner_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/encoding/json/stream.go b/src/encoding/json/stream.go
index 8ddcf4d..87f0e57 100644
--- a/src/encoding/json/stream.go
+++ b/src/encoding/json/stream.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -10,7 +10,7 @@ import (
 	"io"
 )
 
-// A Decoder reads and decodes JSON objects from an input stream.
+// A Decoder reads and decodes JSON values from an input stream.
 type Decoder struct {
 	r     io.Reader
 	buf   []byte
@@ -148,7 +148,7 @@ func (dec *Decoder) refill() error {
 		dec.buf = newBuf
 	}
 
-	// Read.  Delay error for next iteration (after scan).
+	// 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]
 
@@ -164,15 +164,20 @@ func nonSpace(b []byte) bool {
 	return false
 }
 
-// An Encoder writes JSON objects to an output stream.
+// An Encoder writes JSON values to an output stream.
 type Encoder struct {
-	w   io.Writer
-	err error
+	w          io.Writer
+	err        error
+	escapeHTML bool
+
+	indentBuf    *bytes.Buffer
+	indentPrefix string
+	indentValue  string
 }
 
 // NewEncoder returns a new encoder that writes to w.
 func NewEncoder(w io.Writer) *Encoder {
-	return &Encoder{w: w}
+	return &Encoder{w: w, escapeHTML: true}
 }
 
 // Encode writes the JSON encoding of v to the stream,
@@ -185,7 +190,7 @@ func (enc *Encoder) Encode(v interface{}) error {
 		return enc.err
 	}
 	e := newEncodeState()
-	err := e.marshal(v)
+	err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML})
 	if err != nil {
 		return err
 	}
@@ -198,14 +203,45 @@ func (enc *Encoder) Encode(v interface{}) error {
 	// digits coming.
 	e.WriteByte('\n')
 
-	if _, err = enc.w.Write(e.Bytes()); err != nil {
+	b := e.Bytes()
+	if enc.indentPrefix != "" || enc.indentValue != "" {
+		if enc.indentBuf == nil {
+			enc.indentBuf = new(bytes.Buffer)
+		}
+		enc.indentBuf.Reset()
+		err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue)
+		if err != nil {
+			return err
+		}
+		b = enc.indentBuf.Bytes()
+	}
+	if _, err = enc.w.Write(b); err != nil {
 		enc.err = err
 	}
 	encodeStatePool.Put(e)
 	return err
 }
 
-// RawMessage is a raw encoded JSON object.
+// SetIndent instructs the encoder to format each subsequent encoded
+// value as if indented by the package-level function Indent(dst, src, prefix, indent).
+// Calling SetIndent("", "") disables indentation.
+func (enc *Encoder) SetIndent(prefix, indent string) {
+	enc.indentPrefix = prefix
+	enc.indentValue = indent
+}
+
+// SetEscapeHTML specifies whether problematic HTML characters
+// should be escaped inside JSON quoted strings.
+// The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e
+// to avoid certain safety problems that can arise when embedding JSON in HTML.
+//
+// In non-HTML settings where the escaping interferes with the readability
+// of the output, SetEscapeHTML(false) disables this behavior.
+func (enc *Encoder) SetEscapeHTML(on bool) {
+	enc.escapeHTML = on
+}
+
+// RawMessage is a raw encoded JSON value.
 // It implements Marshaler and Unmarshaler and can
 // be used to delay JSON decoding or precompute a JSON encoding.
 type RawMessage []byte
diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go
index c2e3040..84edeb1 100644
--- a/src/encoding/json/stream_test.go
+++ b/src/encoding/json/stream_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -44,6 +44,9 @@ func TestEncoder(t *testing.T) {
 	for i := 0; i <= len(streamTest); i++ {
 		var buf bytes.Buffer
 		enc := NewEncoder(&buf)
+		// Check that enc.SetIndent("", "") turns off indentation.
+		enc.SetIndent(">", ".")
+		enc.SetIndent("", "")
 		for j, v := range streamTest[0:i] {
 			if err := enc.Encode(v); err != nil {
 				t.Fatalf("encode #%d: %v", j, err)
@@ -57,6 +60,69 @@ func TestEncoder(t *testing.T) {
 	}
 }
 
+var streamEncodedIndent = `0.1
+"hello"
+null
+true
+false
+[
+>."a",
+>."b",
+>."c"
+>]
+{
+>."ß": "long s",
+>."K": "Kelvin"
+>}
+3.14
+`
+
+func TestEncoderIndent(t *testing.T) {
+	var buf bytes.Buffer
+	enc := NewEncoder(&buf)
+	enc.SetIndent(">", ".")
+	for _, v := range streamTest {
+		enc.Encode(v)
+	}
+	if have, want := buf.String(), streamEncodedIndent; have != want {
+		t.Error("indented encoding mismatch")
+		diff(t, []byte(have), []byte(want))
+	}
+}
+
+func TestEncoderSetEscapeHTML(t *testing.T) {
+	var c C
+	var ct CText
+	for _, tt := range []struct {
+		name       string
+		v          interface{}
+		wantEscape string
+		want       string
+	}{
+		{"c", c, `"\u003c\u0026\u003e"`, `"<&>"`},
+		{"ct", ct, `"\"\u003c\u0026\u003e\""`, `"\"<&>\""`},
+		{`"<&>"`, "<&>", `"\u003c\u0026\u003e"`, `"<&>"`},
+	} {
+		var buf bytes.Buffer
+		enc := NewEncoder(&buf)
+		if err := enc.Encode(tt.v); err != nil {
+			t.Fatalf("Encode(%s): %s", tt.name, err)
+		}
+		if got := strings.TrimSpace(buf.String()); got != tt.wantEscape {
+			t.Errorf("Encode(%s) = %#q, want %#q", tt.name, got, tt.wantEscape)
+		}
+		buf.Reset()
+		enc.SetEscapeHTML(false)
+		if err := enc.Encode(tt.v); err != nil {
+			t.Fatalf("SetEscapeHTML(false) Encode(%s): %s", tt.name, err)
+		}
+		if got := strings.TrimSpace(buf.String()); got != tt.want {
+			t.Errorf("SetEscapeHTML(false) Encode(%s) = %#q, want %#q",
+				tt.name, got, tt.want)
+		}
+	}
+}
+
 func TestDecoder(t *testing.T) {
 	for i := 0; i <= len(streamTest); i++ {
 		// Use stream without newlines as input,
diff --git a/src/encoding/json/tagkey_test.go b/src/encoding/json/tagkey_test.go
index 85bb4ba..c1739ea 100644
--- a/src/encoding/json/tagkey_test.go
+++ b/src/encoding/json/tagkey_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/encoding/json/tags_test.go b/src/encoding/json/tags_test.go
index 91fb188..8ba8ddd 100644
--- a/src/encoding/json/tags_test.go
+++ b/src/encoding/json/tags_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/encoding/json/testdata/code.json.gz b/src/encoding/json/testdata/code.json.gz
index 0e2895b..1572a92 100644
Binary files a/src/encoding/json/testdata/code.json.gz and b/src/encoding/json/testdata/code.json.gz differ
diff --git a/src/encoding/pem/pem.go b/src/encoding/pem/pem.go
index 506196b..ff2bed1 100644
--- a/src/encoding/pem/pem.go
+++ b/src/encoding/pem/pem.go
@@ -150,7 +150,7 @@ func Decode(data []byte) (p *Block, rest []byte) {
 func decodeError(data, rest []byte) (*Block, []byte) {
 	// If we get here then we have rejected a likely looking, but
 	// ultimately invalid PEM block. We need to start over from a new
-	// position.  We have consumed the preamble line and will have consumed
+	// position. We have consumed the preamble line and will have consumed
 	// any lines which could be header lines. However, a valid preamble
 	// line is not a valid header line, therefore we cannot have consumed
 	// the preamble line for the any subsequent block. Thus, we will always
diff --git a/src/encoding/xml/example_test.go b/src/encoding/xml/example_test.go
index becedd5..21b48de 100644
--- a/src/encoding/xml/example_test.go
+++ b/src/encoding/xml/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index 8ebd693..abb078c 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -26,14 +26,14 @@ const (
 //
 // Marshal handles an array or slice by marshalling each of the elements.
 // Marshal handles a pointer by marshalling the value it points at or, if the
-// pointer is nil, by writing nothing.  Marshal handles an interface value by
+// pointer is nil, by writing nothing. Marshal handles an interface value by
 // marshalling the value it contains or, if the interface value is nil, by
-// writing nothing.  Marshal handles all other data by writing one or more XML
+// writing nothing. Marshal handles all other data by writing one or more XML
 // elements containing the data.
 //
 // The name for the XML elements is taken from, in order of preference:
 //     - the tag on the XMLName field, if the data is a struct
-//     - the value of the XMLName field of type xml.Name
+//     - the value of the XMLName field of type Name
 //     - the tag of the struct field used to obtain the data
 //     - the name of the struct field used to obtain the data
 //     - the name of the marshalled type
@@ -63,7 +63,7 @@ const (
 //       value were part of the outer struct.
 //
 // If a field uses a tag "a>b>c", then the element c will be nested inside
-// parent elements a and b.  Fields that appear next to each other that name
+// parent elements a and b. Fields that appear next to each other that name
 // the same parent will be enclosed in one XML element.
 //
 // See MarshalIndent for an example.
@@ -175,10 +175,9 @@ func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error {
 }
 
 var (
-	begComment   = []byte("<!--")
-	endComment   = []byte("-->")
-	endProcInst  = []byte("?>")
-	endDirective = []byte(">")
+	begComment  = []byte("<!--")
+	endComment  = []byte("-->")
+	endProcInst = []byte("?>")
 )
 
 // EncodeToken writes the given XML token to the stream.
@@ -217,7 +216,7 @@ func (enc *Encoder) EncodeToken(t Token) error {
 		return p.cachedWriteError()
 	case ProcInst:
 		// First token to be encoded which is also a ProcInst with target of xml
-		// is the xml declaration.  The only ProcInst where target of xml is allowed.
+		// is the xml declaration. The only ProcInst where target of xml is allowed.
 		if t.Target == "xml" && p.Buffered() != 0 {
 			return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
 		}
@@ -850,14 +849,14 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
 			switch k {
 			case reflect.String:
 				s := vf.String()
-				dashDash = strings.Index(s, "--") >= 0
+				dashDash = strings.Contains(s, "--")
 				dashLast = s[len(s)-1] == '-'
 				if !dashDash {
 					p.WriteString(s)
 				}
 			case reflect.Slice:
 				b := vf.Bytes()
-				dashDash = bytes.Index(b, ddBytes) >= 0
+				dashDash = bytes.Contains(b, ddBytes)
 				dashLast = b[len(b)-1] == '-'
 				if !dashDash {
 					p.Write(b)
@@ -949,8 +948,8 @@ type parentStack struct {
 }
 
 // trim updates the XML context to match the longest common prefix of the stack
-// and the given parents.  A closing tag will be written for every parent
-// popped.  Passing a zero slice or nil will close all the elements.
+// and the given parents. A closing tag will be written for every parent
+// popped. Passing a zero slice or nil will close all the elements.
 func (s *parentStack) trim(parents []string) error {
 	split := 0
 	for ; split < len(parents) && split < len(s.stack); split++ {
diff --git a/src/encoding/xml/read.go b/src/encoding/xml/read.go
index 77b4c7b..937432e 100644
--- a/src/encoding/xml/read.go
+++ b/src/encoding/xml/read.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -27,7 +27,7 @@ import (
 // discarded.
 //
 // Because Unmarshal uses the reflect package, it can only assign
-// to exported (upper case) fields.  Unmarshal uses a case-sensitive
+// to exported (upper case) fields. Unmarshal uses a case-sensitive
 // comparison to match XML element names to tag values and struct
 // field names.
 //
@@ -37,9 +37,9 @@ import (
 //
 //   * If the struct has a field of type []byte or string with tag
 //      ",innerxml", Unmarshal accumulates the raw XML nested inside the
-//      element in that field.  The rest of the rules still apply.
+//      element in that field. The rest of the rules still apply.
 //
-//   * If the struct has a field named XMLName of type xml.Name,
+//   * If the struct has a field named XMLName of type Name,
 //      Unmarshal records the element name in that field.
 //
 //   * If the XMLName field has an associated tag of the form
@@ -59,7 +59,7 @@ import (
 //
 //   * If the XML element contains comments, they are accumulated in
 //      the first struct field that has tag ",comment".  The struct
-//      field may have type []byte or string.  If there is no such
+//      field may have type []byte or string. If there is no such
 //      field, the comments are discarded.
 //
 //   * If the XML element contains a sub-element whose name matches
@@ -102,11 +102,11 @@ import (
 //
 // Unmarshal maps an XML element or attribute value to an integer or
 // floating-point field by setting the field to the result of
-// interpreting the string value in decimal.  There is no check for
+// interpreting the string value in decimal. There is no check for
 // overflow.
 //
-// Unmarshal maps an XML element to an xml.Name by recording the
-// element name.
+// Unmarshal maps an XML element to a Name by recording the element
+// name.
 //
 // Unmarshal maps an XML element to a pointer by setting the pointer
 // to a freshly allocated value and then mapping the element to that value.
@@ -115,13 +115,13 @@ func Unmarshal(data []byte, v interface{}) error {
 	return NewDecoder(bytes.NewReader(data)).Decode(v)
 }
 
-// Decode works like xml.Unmarshal, except it reads the decoder
+// Decode works like Unmarshal, except it reads the decoder
 // stream to find the start element.
 func (d *Decoder) Decode(v interface{}) error {
 	return d.DecodeElement(v, nil)
 }
 
-// DecodeElement works like xml.Unmarshal except that it takes
+// DecodeElement works like Unmarshal except that it takes
 // a pointer to the start XML element to decode into v.
 // It is useful when a client reads some raw XML tokens itself
 // but also wants to defer to Unmarshal for some elements.
diff --git a/src/encoding/xml/typeinfo.go b/src/encoding/xml/typeinfo.go
index 6483c8d..70da962 100644
--- a/src/encoding/xml/typeinfo.go
+++ b/src/encoding/xml/typeinfo.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/encoding/xml/xml.go b/src/encoding/xml/xml.go
index 45f4157..9a3b792 100644
--- a/src/encoding/xml/xml.go
+++ b/src/encoding/xml/xml.go
@@ -219,7 +219,7 @@ func NewDecoder(r io.Reader) *Decoder {
 //
 // Slices of bytes in the returned token data refer to the
 // parser's internal buffer and remain valid only until the next
-// call to Token.  To acquire a copy of the bytes, call CopyToken
+// call to Token. To acquire a copy of the bytes, call CopyToken
 // or the token's Copy method.
 //
 // Token expands self-closing elements such as <br/>
@@ -237,10 +237,11 @@ func NewDecoder(r io.Reader) *Decoder {
 // set to the URL identifying its name space when known.
 // If Token encounters an unrecognized name space prefix,
 // it uses the prefix as the Space rather than report an error.
-func (d *Decoder) Token() (t Token, err error) {
+func (d *Decoder) Token() (Token, error) {
+	var t Token
+	var err error
 	if d.stk != nil && d.stk.kind == stkEOF {
-		err = io.EOF
-		return
+		return nil, io.EOF
 	}
 	if d.nextToken != nil {
 		t = d.nextToken
@@ -249,7 +250,7 @@ func (d *Decoder) Token() (t Token, err error) {
 		if err == io.EOF && d.stk != nil && d.stk.kind != stkEOF {
 			err = d.syntaxError("unexpected EOF")
 		}
-		return
+		return t, err
 	}
 
 	if !d.Strict {
@@ -292,7 +293,7 @@ func (d *Decoder) Token() (t Token, err error) {
 		}
 		t = t1
 	}
-	return
+	return t, err
 }
 
 const xmlURL = "http://www.w3.org/XML/1998/namespace"
@@ -331,7 +332,7 @@ func (d *Decoder) switchToReader(r io.Reader) {
 }
 
 // Parsing state - stack holds old name space translations
-// and the current set of open elements.  The translations to pop when
+// and the current set of open elements. The translations to pop when
 // ending a given tag are *below* it on the stack, which is
 // more work but forced on us by XML.
 type stack struct {
@@ -1229,7 +1230,7 @@ func isNameString(s string) bool {
 
 // These tables were generated by cut and paste from Appendix B of
 // the XML spec at http://www.xml.com/axml/testaxml.htm
-// and then reformatting.  First corresponds to (Letter | '_' | ':')
+// and then reformatting. First corresponds to (Letter | '_' | ':')
 // and second corresponds to NameChar.
 
 var first = &unicode.RangeTable{
diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go
index 5d5e4bf..dad6ed9 100644
--- a/src/encoding/xml/xml_test.go
+++ b/src/encoding/xml/xml_test.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -184,8 +184,6 @@ const nonStrictInput = `
 <tag>&0a;</tag>
 `
 
-var nonStringEntity = map[string]string{"": "oops!", "0a": "oops!"}
-
 var nonStrictTokens = []Token{
 	CharData("\n"),
 	StartElement{Name{"", "tag"}, []Attr{}},
@@ -652,10 +650,6 @@ func TestDisallowedCharacters(t *testing.T) {
 	}
 }
 
-type procInstEncodingTest struct {
-	expect, got string
-}
-
 var procInstTests = []struct {
 	input  string
 	expect [2]string
diff --git a/src/errors/errors.go b/src/errors/errors.go
index 3085a79..b8a4692 100644
--- a/src/errors/errors.go
+++ b/src/errors/errors.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/errors/errors_test.go b/src/errors/errors_test.go
index 63c05d7..cf4df90 100644
--- a/src/errors/errors_test.go
+++ b/src/errors/errors_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/errors/example_test.go b/src/errors/example_test.go
index 0e86828..5dc8841 100644
--- a/src/errors/example_test.go
+++ b/src/errors/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/expvar/expvar.go b/src/expvar/expvar.go
index 24c2d6b..d5465c5 100644
--- a/src/expvar/expvar.go
+++ b/src/expvar/expvar.go
@@ -15,7 +15,7 @@
 //	memstats  runtime.Memstats
 //
 // The package is sometimes only imported for the side effect of
-// registering its HTTP handler and the above variables.  To use it
+// registering its HTTP handler and the above variables. To use it
 // this way, link this package into your program:
 //	import _ "expvar"
 //
@@ -38,6 +38,9 @@ import (
 
 // Var is an abstract type for all exported variables.
 type Var interface {
+	// String returns a valid JSON value for the variable.
+	// Types with String methods that do not return valid JSON
+	// (such as time.Time) must not be used as a Var.
 	String() string
 }
 
@@ -218,8 +221,10 @@ type String struct {
 
 func (v *String) String() string {
 	v.mu.RLock()
-	defer v.mu.RUnlock()
-	return strconv.Quote(v.s)
+	s := v.s
+	v.mu.RUnlock()
+	b, _ := json.Marshal(s)
+	return string(b)
 }
 
 func (v *String) Set(value string) {
@@ -258,7 +263,8 @@ func Publish(name string, v Var) {
 	sort.Strings(varKeys)
 }
 
-// Get retrieves a named exported variable.
+// Get retrieves a named exported variable. It returns nil if the name has
+// not been registered.
 func Get(name string) Var {
 	mutex.RLock()
 	defer mutex.RUnlock()
diff --git a/src/expvar/expvar_test.go b/src/expvar/expvar_test.go
index 8bc633e..7b1c9df 100644
--- a/src/expvar/expvar_test.go
+++ b/src/expvar/expvar_test.go
@@ -26,6 +26,14 @@ func RemoveAll() {
 	varKeys = nil
 }
 
+func TestNil(t *testing.T) {
+	RemoveAll()
+	val := Get("missing")
+	if val != nil {
+		t.Errorf("got %v, want nil", val)
+	}
+}
+
 func TestInt(t *testing.T) {
 	RemoveAll()
 	reqs := NewInt("requests")
@@ -134,8 +142,14 @@ func TestString(t *testing.T) {
 		t.Errorf("name.s = %q, want \"Mike\"", name.s)
 	}
 
-	if s := name.String(); s != "\"Mike\"" {
-		t.Errorf("reqs.String() = %q, want \"\"Mike\"\"", s)
+	if s, want := name.String(), `"Mike"`; s != want {
+		t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
+	}
+
+	// Make sure we produce safe JSON output.
+	name.Set(`<`)
+	if s, want := name.String(), "\"\\u003c\""; s != want {
+		t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
 	}
 }
 
diff --git a/src/flag/export_test.go b/src/flag/export_test.go
index 56cda58..12d3dc7 100644
--- a/src/flag/export_test.go
+++ b/src/flag/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/flag/flag.go b/src/flag/flag.go
index 3abc80e..fa0f05e 100644
--- a/src/flag/flag.go
+++ b/src/flag/flag.go
@@ -68,6 +68,7 @@ import (
 	"fmt"
 	"io"
 	"os"
+	"reflect"
 	"sort"
 	"strconv"
 	"time"
@@ -261,7 +262,7 @@ const (
 	PanicOnError                         // Call panic with a descriptive error.
 )
 
-// A FlagSet represents a set of defined flags.  The zero value of a FlagSet
+// A FlagSet represents a set of defined flags. The zero value of a FlagSet
 // has no name and has ContinueOnError error handling.
 type FlagSet struct {
 	// Usage is the function called when an error occurs while parsing flags.
@@ -324,7 +325,7 @@ func (f *FlagSet) VisitAll(fn func(*Flag)) {
 }
 
 // VisitAll visits the command-line flags in lexicographical order, calling
-// fn for each.  It visits all flags, even those not set.
+// fn for each. It visits all flags, even those not set.
 func VisitAll(fn func(*Flag)) {
 	CommandLine.VisitAll(fn)
 }
@@ -338,7 +339,7 @@ func (f *FlagSet) Visit(fn func(*Flag)) {
 }
 
 // Visit visits the command-line flags in lexicographical order, calling fn
-// for each.  It visits only those flags that have been set.
+// for each. It visits only those flags that have been set.
 func Visit(fn func(*Flag)) {
 	CommandLine.Visit(fn)
 }
@@ -378,7 +379,21 @@ func Set(name, value string) error {
 
 // 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 {
+func isZeroValue(flag *Flag, value string) bool {
+	// Build a zero value of the flag's Value type, and see if the
+	// result of calling its String method equals the value passed in.
+	// This works unless the Value type is itself an interface type.
+	typ := reflect.TypeOf(flag.Value)
+	var z reflect.Value
+	if typ.Kind() == reflect.Ptr {
+		z = reflect.New(typ.Elem())
+	} else {
+		z = reflect.Zero(typ)
+	}
+	if value == z.Interface().(Value).String() {
+		return true
+	}
+
 	switch value {
 	case "false":
 		return true
@@ -449,7 +464,7 @@ func (f *FlagSet) PrintDefaults() {
 			s += "\n    \t"
 		}
 		s += usage
-		if !isZeroValue(flag.DefValue) {
+		if !isZeroValue(flag, flag.DefValue) {
 			if _, ok := flag.Value.(*stringValue); ok {
 				// put quotes on the value
 				s += fmt.Sprintf(" (default %q)", flag.DefValue)
@@ -514,7 +529,7 @@ func (f *FlagSet) NFlag() int { return len(f.actual) }
 // NFlag returns the number of command-line flags that have been set.
 func NFlag() int { return len(CommandLine.actual) }
 
-// Arg returns the i'th argument.  Arg(0) is the first remaining argument
+// Arg returns the i'th argument. Arg(0) is the first remaining argument
 // after flags have been processed. Arg returns an empty string if the
 // requested element does not exist.
 func (f *FlagSet) Arg(i int) string {
@@ -524,7 +539,7 @@ func (f *FlagSet) Arg(i int) string {
 	return f.args[i]
 }
 
-// Arg returns the i'th command-line argument.  Arg(0) is the first remaining argument
+// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument
 // after flags have been processed. Arg returns an empty string if the
 // requested element does not exist.
 func Arg(i int) string {
@@ -890,7 +905,7 @@ func (f *FlagSet) parseOne() (bool, error) {
 }
 
 // Parse parses flag definitions from the argument list, which should not
-// include the command name.  Must be called after all flags in the FlagSet
+// include the command name. Must be called after all flags in the FlagSet
 // are defined and before flags are accessed by the program.
 // The return value will be ErrHelp if -help or -h were set but not defined.
 func (f *FlagSet) Parse(arguments []string) error {
diff --git a/src/fmt/doc.go b/src/fmt/doc.go
index 4eea48e..c312914 100644
--- a/src/fmt/doc.go
+++ b/src/fmt/doc.go
@@ -62,7 +62,7 @@
 	For compound objects, the elements are printed using these rules, recursively,
 	laid out like this:
 		struct:             {field0 field1 ...}
-		array, slice:       [elem0  elem1 ...]
+		array, slice:       [elem0 elem1 ...]
 		maps:               map[key1:value1 key2:value2]
 		pointer to above:   &{}, &[], &map[]
 
@@ -95,10 +95,10 @@
 
 	For floating-point values, width sets the minimum width of the field and
 	precision sets the number of places after the decimal, if appropriate,
-	except that for %g/%G it sets the total number of digits. For example,
-	given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5.
-	The default precision for %e and %f is 6; for %g it is the smallest
-	number of digits necessary to identify the value uniquely.
+	except that for %g/%G precision sets the total number of significant
+	digits. For example, given 12.345 the format %6.3f prints 12.345 while
+	%.3g prints 12.3. The default precision for %e and %f is 6; for %g it
+	is the smallest number of digits necessary to identify the value uniquely.
 
 	For complex numbers, the width and precision apply to the two
 	components independently and the result is parenthesized, so %f applied
@@ -210,7 +210,7 @@
 		Too many arguments: %!(EXTRA type=value)
 			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
 		Too few arguments: %!verb(MISSING)
-			Printf("hi%d"):            hi %!d(MISSING)
+			Printf("hi%d"):            hi%!d(MISSING)
 		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
 			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
 			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
diff --git a/src/fmt/export_test.go b/src/fmt/export_test.go
index 89d57ee..12d5a11 100644
--- a/src/fmt/export_test.go
+++ b/src/fmt/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index 793f709..5fb2a63 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -48,13 +48,18 @@ func TestFmtInterface(t *testing.T) {
 	}
 }
 
-const b32 uint32 = 1<<32 - 1
-const b64 uint64 = 1<<64 - 1
+var (
+	NaN    = math.NaN()
+	posInf = math.Inf(1)
+	negInf = math.Inf(-1)
 
-var array = [5]int{1, 2, 3, 4, 5}
-var iarray = [4]interface{}{1, "hello", 2.5, nil}
-var slice = array[:]
-var islice = iarray[:]
+	intVar = 0
+
+	array  = [5]int{1, 2, 3, 4, 5}
+	iarray = [4]interface{}{1, "hello", 2.5, nil}
+	slice  = array[:]
+	islice = iarray[:]
+)
 
 type A struct {
 	i int
@@ -112,9 +117,11 @@ var bslice = barray[:]
 
 type byteStringer byte
 
-func (byteStringer) String() string { return "X" }
+func (byteStringer) String() string {
+	return "X"
+}
 
-var byteStringerSlice = []byteStringer{97, 98, 99, 100}
+var byteStringerSlice = []byteStringer{'h', 'e', 'l', 'l', 'o'}
 
 type byteFormatter byte
 
@@ -122,9 +129,7 @@ func (byteFormatter) Format(f State, _ rune) {
 	Fprint(f, "X")
 }
 
-var byteFormatterSlice = []byteFormatter{97, 98, 99, 100}
-
-var b byte
+var byteFormatterSlice = []byteFormatter{'h', 'e', 'l', 'l', 'o'}
 
 var fmtTests = []struct {
 	fmt string
@@ -141,6 +146,10 @@ var fmtTests = []struct {
 	{"%x", "abc", "616263"},
 	{"%x", "\xff\xf0\x0f\xff", "fff00fff"},
 	{"%X", "\xff\xf0\x0f\xff", "FFF00FFF"},
+	{"%x", "", ""},
+	{"% x", "", ""},
+	{"%#x", "", ""},
+	{"%# x", "", ""},
 	{"%x", "xyz", "78797a"},
 	{"%X", "xyz", "78797A"},
 	{"% x", "xyz", "78 79 7a"},
@@ -152,10 +161,16 @@ var fmtTests = []struct {
 
 	// basic bytes
 	{"%s", []byte("abc"), "abc"},
+	{"%s", [3]byte{'a', 'b', 'c'}, "abc"},
+	{"%s", &[3]byte{'a', 'b', 'c'}, "&abc"},
 	{"%q", []byte("abc"), `"abc"`},
 	{"%x", []byte("abc"), "616263"},
 	{"%x", []byte("\xff\xf0\x0f\xff"), "fff00fff"},
 	{"%X", []byte("\xff\xf0\x0f\xff"), "FFF00FFF"},
+	{"%x", []byte(""), ""},
+	{"% x", []byte(""), ""},
+	{"%#x", []byte(""), ""},
+	{"%# x", []byte(""), ""},
 	{"%x", []byte("xyz"), "78797a"},
 	{"%X", []byte("xyz"), "78797A"},
 	{"% x", []byte("xyz"), "78 79 7a"},
@@ -166,29 +181,112 @@ var fmtTests = []struct {
 	{"%# X", []byte("xyz"), "0X78 0X79 0X7A"},
 
 	// escaped strings
-	{"%#q", `abc`, "`abc`"},
-	{"%#q", `"`, "`\"`"},
-	{"1 %#q", `\n`, "1 `\\n`"},
-	{"2 %#q", "\n", `2 "\n"`},
-	{"%q", `"`, `"\""`},
-	{"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+	{"%q", "", `""`},
+	{"%#q", "", "``"},
+	{"%q", "\"", `"\""`},
+	{"%#q", "\"", "`\"`"},
+	{"%q", "`", `"` + "`" + `"`},
+	{"%#q", "`", `"` + "`" + `"`},
+	{"%q", "\n", `"\n"`},
+	{"%#q", "\n", `"\n"`},
+	{"%q", `\n`, `"\\n"`},
+	{"%#q", `\n`, "`\\n`"},
+	{"%q", "abc", `"abc"`},
+	{"%#q", "abc", "`abc`"},
+	{"%q", "日本語", `"日本語"`},
+	{"%+q", "日本語", `"\u65e5\u672c\u8a9e"`},
+	{"%#q", "日本語", "`日本語`"},
+	{"%#+q", "日本語", "`日本語`"},
+	{"%q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+	{"%+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+	{"%#q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+	{"%#+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`},
+	{"%q", "☺", `"☺"`},
+	{"% q", "☺", `"☺"`}, // The space modifier should have no effect.
+	{"%+q", "☺", `"\u263a"`},
+	{"%#q", "☺", "`☺`"},
+	{"%#+q", "☺", "`☺`"},
+	{"%10q", "⌘", `       "⌘"`},
+	{"%+10q", "⌘", `  "\u2318"`},
+	{"%-10q", "⌘", `"⌘"       `},
+	{"%+-10q", "⌘", `"\u2318"  `},
+	{"%010q", "⌘", `0000000"⌘"`},
+	{"%+010q", "⌘", `00"\u2318"`},
+	{"%-010q", "⌘", `"⌘"       `}, // 0 has no effect when - is present.
+	{"%+-010q", "⌘", `"\u2318"  `},
+	{"%#8q", "\n", `    "\n"`},
+	{"%#+8q", "\r", `    "\r"`},
+	{"%#-8q", "\t", "`	`     "},
+	{"%#+-8q", "\b", `"\b"    `},
 	{"%q", "abc\xffdef", `"abc\xffdef"`},
-	{"%q", "\u263a", `"☺"`},
-	{"%+q", "\u263a", `"\u263a"`},
+	{"%+q", "abc\xffdef", `"abc\xffdef"`},
+	{"%#q", "abc\xffdef", `"abc\xffdef"`},
+	{"%#+q", "abc\xffdef", `"abc\xffdef"`},
+	// Runes that are not printable.
 	{"%q", "\U0010ffff", `"\U0010ffff"`},
+	{"%+q", "\U0010ffff", `"\U0010ffff"`},
+	{"%#q", "\U0010ffff", "`􏿿`"},
+	{"%#+q", "\U0010ffff", "`􏿿`"},
+	// Runes that are not valid.
+	{"%q", string(0x110000), `"�"`},
+	{"%+q", string(0x110000), `"\ufffd"`},
+	{"%#q", string(0x110000), "`�`"},
+	{"%#+q", string(0x110000), "`�`"},
+
+	// characters
+	{"%c", uint('x'), "x"},
+	{"%c", 0xe4, "ä"},
+	{"%c", 0x672c, "本"},
+	{"%c", '日', "日"},
+	{"%.0c", '⌘', "⌘"}, // Specifying precision should have no effect.
+	{"%3c", '⌘', "  ⌘"},
+	{"%-3c", '⌘', "⌘  "},
+	// Runes that are not printable.
+	{"%c", '\U00000e00', "\u0e00"},
+	{"%c", '\U0010ffff', "\U0010ffff"},
+	// Runes that are not valid.
+	{"%c", -1, "�"},
+	{"%c", 0xDC80, "�"},
+	{"%c", rune(0x110000), "�"},
+	{"%c", int64(0xFFFFFFFFF), "�"},
+	{"%c", uint64(0xFFFFFFFFF), "�"},
 
 	// escaped characters
-	{"%q", 'x', `'x'`},
-	{"%q", 0, `'\x00'`},
-	{"%q", '\n', `'\n'`},
-	{"%q", '\u0e00', `'\u0e00'`},         // not a printable rune.
-	{"%q", '\U000c2345', `'\U000c2345'`}, // not a printable rune.
-	{"%q", int64(0x7FFFFFFF), `%!q(int64=2147483647)`},
-	{"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
+	{"%q", uint(0), `'\x00'`},
+	{"%+q", uint(0), `'\x00'`},
 	{"%q", '"', `'"'`},
+	{"%+q", '"', `'"'`},
 	{"%q", '\'', `'\''`},
-	{"%q", "\u263a", `"☺"`},
-	{"%+q", "\u263a", `"\u263a"`},
+	{"%+q", '\'', `'\''`},
+	{"%q", '`', "'`'"},
+	{"%+q", '`', "'`'"},
+	{"%q", 'x', `'x'`},
+	{"%+q", 'x', `'x'`},
+	{"%q", 'ÿ', `'ÿ'`},
+	{"%+q", 'ÿ', `'\u00ff'`},
+	{"%q", '\n', `'\n'`},
+	{"%+q", '\n', `'\n'`},
+	{"%q", '☺', `'☺'`},
+	{"%+q", '☺', `'\u263a'`},
+	{"% q", '☺', `'☺'`},  // The space modifier should have no effect.
+	{"%.0q", '☺', `'☺'`}, // Specifying precision should have no effect.
+	{"%10q", '⌘', `       '⌘'`},
+	{"%+10q", '⌘', `  '\u2318'`},
+	{"%-10q", '⌘', `'⌘'       `},
+	{"%+-10q", '⌘', `'\u2318'  `},
+	{"%010q", '⌘', `0000000'⌘'`},
+	{"%+010q", '⌘', `00'\u2318'`},
+	{"%-010q", '⌘', `'⌘'       `}, // 0 has no effect when - is present.
+	{"%+-010q", '⌘', `'\u2318'  `},
+	// Runes that are not printable.
+	{"%q", '\U00000e00', `'\u0e00'`},
+	{"%q", '\U0010ffff', `'\U0010ffff'`},
+	// Runes that are not valid.
+	{"%q", int32(-1), "%!q(int32=-1)"},
+	{"%q", 0xDC80, `'�'`},
+	{"%q", rune(0x110000), "%!q(int32=1114112)"},
+	{"%q", int64(0xFFFFFFFFF), "%!q(int64=68719476735)"},
+	{"%q", uint64(0xFFFFFFFFF), "%!q(uint64=68719476735)"},
 
 	// width
 	{"%5s", "abc", "  abc"},
@@ -199,57 +297,99 @@ var fmtTests = []struct {
 	{"%08q", "abc", `000"abc"`},
 	{"%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"},
 	{"%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"},
+	{"%.0s", "日本語日本語", ""},
 	{"%.5s", "日本語日本語", "日本語日本"},
+	{"%.10s", "日本語日本語", "日本語日本語"},
 	{"%.5s", []byte("日本語日本語"), "日本語日本"},
 	{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
-	{"%.5x", "abcdefghijklmnopqrstuvwxyz", `6162636465`},
+	{"%.5x", "abcdefghijklmnopqrstuvwxyz", "6162636465"},
 	{"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`},
-	{"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), `6162636465`},
+	{"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), "6162636465"},
 	{"%.3q", "日本語日本語", `"日本語"`},
 	{"%.3q", []byte("日本語日本語"), `"日本語"`},
 	{"%.1q", "日本語", `"日"`},
 	{"%.1q", []byte("日本語"), `"日"`},
-	{"%.1x", "日本語", `e6`},
-	{"%.1X", []byte("日本語"), `E6`},
+	{"%.1x", "日本語", "e6"},
+	{"%.1X", []byte("日本語"), "E6"},
 	{"%10.1q", "日本語日本語", `       "日"`},
-	{"%3c", '⌘', "  ⌘"},
-	{"%5q", '\u2026', `  '…'`},
 	{"%10v", nil, "     <nil>"},
 	{"%-10v", nil, "<nil>     "},
 
 	// integers
-	{"%d", 12345, "12345"},
-	{"%d", -12345, "-12345"},
+	{"%d", uint(12345), "12345"},
+	{"%d", int(-12345), "-12345"},
+	{"%d", ^uint8(0), "255"},
+	{"%d", ^uint16(0), "65535"},
+	{"%d", ^uint32(0), "4294967295"},
+	{"%d", ^uint64(0), "18446744073709551615"},
+	{"%d", int8(-1 << 7), "-128"},
+	{"%d", int16(-1 << 15), "-32768"},
+	{"%d", int32(-1 << 31), "-2147483648"},
+	{"%d", int64(-1 << 63), "-9223372036854775808"},
+	{"%.d", 0, ""},
+	{"%.0d", 0, ""},
+	{"%6.0d", 0, "      "},
+	{"%06.0d", 0, "      "},
+	{"% d", 12345, " 12345"},
+	{"%+d", 12345, "+12345"},
+	{"%+d", -12345, "-12345"},
+	{"%b", 7, "111"},
+	{"%b", -6, "-110"},
+	{"%b", ^uint32(0), "11111111111111111111111111111111"},
+	{"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"},
+	{"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
+	{"%o", 01234, "1234"},
+	{"%#o", 01234, "01234"},
+	{"%o", ^uint32(0), "37777777777"},
+	{"%o", ^uint64(0), "1777777777777777777777"},
+	{"%#X", 0, "0X0"},
+	{"%x", 0x12abcdef, "12abcdef"},
+	{"%X", 0x12abcdef, "12ABCDEF"},
+	{"%x", ^uint32(0), "ffffffff"},
+	{"%X", ^uint64(0), "FFFFFFFFFFFFFFFF"},
+	{"%.20b", 7, "00000000000000000111"},
 	{"%10d", 12345, "     12345"},
 	{"%10d", -12345, "    -12345"},
 	{"%+10d", 12345, "    +12345"},
 	{"%010d", 12345, "0000012345"},
 	{"%010d", -12345, "-000012345"},
-	{"%-10d", 12345, "12345     "},
-	{"%010.3d", 1, "       001"},
-	{"%010.3d", -1, "      -001"},
-	{"%+d", 12345, "+12345"},
-	{"%+d", -12345, "-12345"},
-	{"%+d", 0, "+0"},
-	{"% d", 0, " 0"},
-	{"% d", 12345, " 12345"},
-	{"%.0d", 0, ""},
-	{"%.d", 0, ""},
+	{"%20.8d", 1234, "            00001234"},
+	{"%20.8d", -1234, "           -00001234"},
+	{"%020.8d", 1234, "            00001234"},
+	{"%020.8d", -1234, "           -00001234"},
+	{"%-20.8d", 1234, "00001234            "},
+	{"%-20.8d", -1234, "-00001234           "},
+	{"%-#20.8x", 0x1234abc, "0x01234abc          "},
+	{"%-#20.8X", 0x1234abc, "0X01234ABC          "},
+	{"%-#20.8o", 01234, "00001234            "},
+
+	// Test correct f.intbuf overflow checks.
+	{"%068d", 1, zeroFill("", 68, "1")},
+	{"%068d", -1, zeroFill("-", 67, "1")},
+	{"%#.68x", 42, zeroFill("0x", 68, "2a")},
+	{"%.68d", -42, zeroFill("-", 68, "42")},
+	{"%+.68d", 42, zeroFill("+", 68, "42")},
+	{"% .68d", 42, zeroFill(" ", 68, "42")},
+	{"% +.68d", 42, zeroFill("+", 68, "42")},
 
 	// unicode format
-	{"%U", 0x1, "U+0001"},
-	{"%U", uint(0x1), "U+0001"},
-	{"%.8U", 0x2, "U+00000002"},
-	{"%U", 0x1234, "U+1234"},
-	{"%U", 0x12345, "U+12345"},
-	{"%10.6U", 0xABC, "  U+000ABC"},
-	{"%-10.6U", 0xABC, "U+000ABC  "},
+	{"%U", 0, "U+0000"},
+	{"%U", -1, "U+FFFFFFFFFFFFFFFF"},
 	{"%U", '\n', `U+000A`},
 	{"%#U", '\n', `U+000A`},
-	{"%U", 'x', `U+0078`},
-	{"%#U", 'x', `U+0078 'x'`},
+	{"%+U", 'x', `U+0078`},       // Plus flag should have no effect.
+	{"%# U", 'x', `U+0078 'x'`},  // Space flag should have no effect.
+	{"%#.2U", 'x', `U+0078 'x'`}, // Precisions below 4 should print 4 digits.
 	{"%U", '\u263a', `U+263A`},
 	{"%#U", '\u263a', `U+263A '☺'`},
+	{"%U", '\U0001D6C2', `U+1D6C2`},
+	{"%#U", '\U0001D6C2', `U+1D6C2 '𝛂'`},
+	{"%#14.6U", '⌘', "  U+002318 '⌘'"},
+	{"%#-14.6U", '⌘', "U+002318 '⌘'  "},
+	{"%#014.6U", '⌘', "  U+002318 '⌘'"},
+	{"%#-014.6U", '⌘', "U+002318 '⌘'  "},
+	{"%.68U", uint(42), zeroFill("U+", 68, "2A")},
+	{"%#.68U", '日', zeroFill("U+", 68, "65E5") + " '日'"},
 
 	// floats
 	{"%+.3e", 0.0, "+0.000e+00"},
@@ -259,6 +399,12 @@ var fmtTests = []struct {
 	{"%+.3F", float32(-1.0), "-1.000"},
 	{"%+07.2f", 1.0, "+001.00"},
 	{"%+07.2f", -1.0, "-001.00"},
+	{"%-07.2f", 1.0, "1.00   "},
+	{"%-07.2f", -1.0, "-1.00  "},
+	{"%+-07.2f", 1.0, "+1.00  "},
+	{"%+-07.2f", -1.0, "-1.00  "},
+	{"%-+07.2f", 1.0, "+1.00  "},
+	{"%-+07.2f", -1.0, "-1.00  "},
 	{"%+10.2f", +1.0, "     +1.00"},
 	{"%+10.2f", -1.0, "     -1.00"},
 	{"% .3E", -1.0, "-1.000E+00"},
@@ -270,8 +416,36 @@ var fmtTests = []struct {
 	{"% .3g", 1.0, " 1"},
 	{"%b", float32(1.0), "8388608p-23"},
 	{"%b", 1.0, "4503599627370496p-52"},
+	// Precision has no effect for binary float format.
+	{"%.4b", float32(1.0), "8388608p-23"},
+	{"%.4b", -1.0, "-4503599627370496p-52"},
+	// Test correct f.intbuf boundary checks.
+	{"%.68f", 1.0, zeroFill("1.", 68, "")},
+	{"%.68f", -1.0, zeroFill("-1.", 68, "")},
+	// float infinites and NaNs
+	{"%f", posInf, "+Inf"},
+	{"%.1f", negInf, "-Inf"},
+	{"% f", NaN, " NaN"},
+	{"%20f", posInf, "                +Inf"},
+	{"% 20F", posInf, "                 Inf"},
+	{"% 20e", negInf, "                -Inf"},
+	{"%+20E", negInf, "                -Inf"},
+	{"% +20g", negInf, "                -Inf"},
+	{"%+-20G", posInf, "+Inf                "},
+	{"%20e", NaN, "                 NaN"},
+	{"% +20E", NaN, "                +NaN"},
+	{"% -20g", NaN, " NaN                "},
+	{"%+-20G", NaN, "+NaN                "},
+	// Zero padding does not apply to infinities and NaN.
+	{"%+020e", posInf, "                +Inf"},
+	{"%-020f", negInf, "-Inf                "},
+	{"%-020E", NaN, "NaN                 "},
 
 	// complex values
+	{"%.f", 0i, "(0+0i)"},
+	{"% .f", 0i, "( 0+0i)"},
+	{"%+.f", 0i, "(+0+0i)"},
+	{"% +.f", 0i, "(+0+0i)"},
 	{"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
 	{"%+.3f", 0i, "(+0.000+0.000i)"},
 	{"%+.3g", 0i, "(+0+0i)"},
@@ -290,35 +464,33 @@ var fmtTests = []struct {
 	{"%.3f", -1 - 2i, "(-1.000-2.000i)"},
 	{"%.3g", -1 - 2i, "(-1-2i)"},
 	{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
+	{"%+.3g", 1 + 2i, "(+1+2i)"},
 	{"%+.3g", complex64(1 + 2i), "(+1+2i)"},
-	{"%+.3g", complex128(1 + 2i), "(+1+2i)"},
-	{"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
 	{"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
-
-	// erroneous formats
-	{"", 2, "%!(EXTRA int=2)"},
-	{"%d", "hello", "%!d(string=hello)"},
+	{"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
+	// Precision has no effect for binary complex format.
+	{"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
+	{"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
+	// complex infinites and NaNs
+	{"%f", complex(posInf, posInf), "(+Inf+Infi)"},
+	{"%f", complex(negInf, negInf), "(-Inf-Infi)"},
+	{"%f", complex(NaN, NaN), "(NaN+NaNi)"},
+	{"%.1f", complex(posInf, posInf), "(+Inf+Infi)"},
+	{"% f", complex(posInf, posInf), "( Inf+Infi)"},
+	{"% f", complex(negInf, negInf), "(-Inf-Infi)"},
+	{"% f", complex(NaN, NaN), "( NaN+NaNi)"},
+	{"%8e", complex(posInf, posInf), "(    +Inf    +Infi)"},
+	{"% 8E", complex(posInf, posInf), "(     Inf    +Infi)"},
+	{"%+8f", complex(negInf, negInf), "(    -Inf    -Infi)"},
+	{"% +8g", complex(negInf, negInf), "(    -Inf    -Infi)"},
+	{"% -8G", complex(NaN, NaN), "( NaN    +NaN    i)"},
+	{"%+-8b", complex(NaN, NaN), "(+NaN    +NaN    i)"},
+	// Zero padding does not apply to infinities and NaN.
+	{"%08f", complex(posInf, posInf), "(    +Inf    +Infi)"},
+	{"%-08g", complex(negInf, negInf), "(-Inf    -Inf    i)"},
+	{"%-08G", complex(NaN, NaN), "(NaN     +NaN    i)"},
 
 	// old test/fmt_test.go
-	{"%d", 1234, "1234"},
-	{"%d", -1234, "-1234"},
-	{"%d", uint(1234), "1234"},
-	{"%d", uint32(b32), "4294967295"},
-	{"%d", uint64(b64), "18446744073709551615"},
-	{"%o", 01234, "1234"},
-	{"%#o", 01234, "01234"},
-	{"%o", uint32(b32), "37777777777"},
-	{"%o", uint64(b64), "1777777777777777777777"},
-	{"%x", 0x1234abcd, "1234abcd"},
-	{"%#x", 0x1234abcd, "0x1234abcd"},
-	{"%x", b32 - 0x1234567, "fedcba98"},
-	{"%X", 0x1234abcd, "1234ABCD"},
-	{"%X", b32 - 0x1234567, "FEDCBA98"},
-	{"%#X", 0, "0X0"},
-	{"%x", b64, "ffffffffffffffff"},
-	{"%b", 7, "111"},
-	{"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"},
-	{"%b", -6, "-110"},
 	{"%e", 1.0, "1.000000e+00"},
 	{"%e", 1234.5678e3, "1.234568e+06"},
 	{"%e", 1234.5678e-8, "1.234568e-05"},
@@ -345,19 +517,6 @@ var fmtTests = []struct {
 	{"%G", -7.0, "-7"},
 	{"%G", -1e-9, "-1E-09"},
 	{"%G", float32(-1e-9), "-1E-09"},
-	{"%c", 'x', "x"},
-	{"%c", 0xe4, "ä"},
-	{"%c", 0x672c, "本"},
-	{"%c", '日', "日"},
-	{"%20.8d", 1234, "            00001234"},
-	{"%20.8d", -1234, "           -00001234"},
-	{"%20d", 1234, "                1234"},
-	{"%-20.8d", 1234, "00001234            "},
-	{"%-20.8d", -1234, "-00001234           "},
-	{"%-#20.8x", 0x1234abc, "0x01234abc          "},
-	{"%-#20.8X", 0x1234abc, "0X01234ABC          "},
-	{"%-#20.8o", 01234, "00001234            "},
-	{"%.20b", 7, "00000000000000000111"},
 	{"%20.5s", "qwertyuiop", "               qwert"},
 	{"%.5s", "qwertyuiop", "qwert"},
 	{"%-20.5s", "qwertyuiop", "qwert               "},
@@ -377,9 +536,6 @@ var fmtTests = []struct {
 	{"%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                "},
-	{"%20g", math.NaN(), "                 NaN"},
 
 	// arrays
 	{"%v", array, "[1 2 3 4 5]"},
@@ -396,13 +552,44 @@ 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{}, "[]"},
+
+	// byte arrays and slices with %b,%c,%d,%o,%U and %v
+	{"%b", [3]byte{65, 66, 67}, "[1000001 1000010 1000011]"},
+	{"%c", [3]byte{65, 66, 67}, "[A B C]"},
+	{"%d", [3]byte{65, 66, 67}, "[65 66 67]"},
+	{"%o", [3]byte{65, 66, 67}, "[101 102 103]"},
+	{"%U", [3]byte{65, 66, 67}, "[U+0041 U+0042 U+0043]"},
+	{"%v", [3]byte{65, 66, 67}, "[65 66 67]"},
+	{"%v", [1]byte{123}, "[123]"},
+	{"%012v", []byte{}, "[]"},
+	{"%#012v", []byte{}, "[]byte{}"},
+	{"%6v", []byte{1, 11, 111}, "[     1     11    111]"},
+	{"%06v", []byte{1, 11, 111}, "[000001 000011 000111]"},
+	{"%-6v", []byte{1, 11, 111}, "[1      11     111   ]"},
+	{"%-06v", []byte{1, 11, 111}, "[1      11     111   ]"},
+	{"%#v", []byte{1, 11, 111}, "[]byte{0x1, 0xb, 0x6f}"},
+	{"%#6v", []byte{1, 11, 111}, "[]byte{   0x1,    0xb,   0x6f}"},
+	{"%#06v", []byte{1, 11, 111}, "[]byte{0x000001, 0x00000b, 0x00006f}"},
+	{"%#-6v", []byte{1, 11, 111}, "[]byte{0x1   , 0xb   , 0x6f  }"},
+	{"%#-06v", []byte{1, 11, 111}, "[]byte{0x1   , 0xb   , 0x6f  }"},
+	// f.space should and f.plus should not have an effect with %v.
+	{"% v", []byte{1, 11, 111}, "[ 1  11  111]"},
+	{"%+v", [3]byte{1, 11, 111}, "[1 11 111]"},
+	{"%# -6v", []byte{1, 11, 111}, "[]byte{ 0x1  ,  0xb  ,  0x6f }"},
+	{"%#+-6v", [3]byte{1, 11, 111}, "[3]uint8{0x1   , 0xb   , 0x6f  }"},
+	// f.space and f.plus should have an effect with %d.
+	{"% d", []byte{1, 11, 111}, "[ 1  11  111]"},
+	{"%+d", [3]byte{1, 11, 111}, "[+1 +11 +111]"},
+	{"%# -6d", []byte{1, 11, 111}, "[ 1      11     111  ]"},
+	{"%#+-6d", [3]byte{1, 11, 111}, "[+1     +11    +111  ]"},
+
+	// floates with %v
+	{"%v", 1.2345678, "1.2345678"},
+	{"%v", float32(1.2345678), "1.2345678"},
 
 	// complexes with %v
 	{"%v", 1 + 2i, "(1+2i)"},
 	{"%v", complex64(1 + 2i), "(1+2i)"},
-	{"%v", complex128(1 + 2i), "(1+2i)"},
 
 	// structs
 	{"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
@@ -422,7 +609,7 @@ var fmtTests = []struct {
 
 	// go syntax
 	{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
-	{"%#v", &b, "(*uint8)(0xPTR)"},
+	{"%#v", new(byte), "(*uint8)(0xPTR)"},
 	{"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"},
 	{"%#v", make(chan int), "(chan int)(0xPTR)"},
 	{"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
@@ -442,8 +629,20 @@ var fmtTests = []struct {
 	{"%#v", "foo", `"foo"`},
 	{"%#v", barray, `[5]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
 	{"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
-	{"%#v", []byte(nil), "[]byte(nil)"},
 	{"%#v", []int32(nil), "[]int32(nil)"},
+	{"%#v", 1.2345678, "1.2345678"},
+	{"%#v", float32(1.2345678), "1.2345678"},
+	// Only print []byte and []uint8 as type []byte if they appear at the top level.
+	{"%#v", []byte(nil), "[]byte(nil)"},
+	{"%#v", []uint8(nil), "[]byte(nil)"},
+	{"%#v", []byte{}, "[]byte{}"},
+	{"%#v", []uint8{}, "[]byte{}"},
+	{"%#v", reflect.ValueOf([]byte{}), "[]uint8{}"},
+	{"%#v", reflect.ValueOf([]uint8{}), "[]uint8{}"},
+	{"%#v", &[]byte{}, "&[]uint8{}"},
+	{"%#v", &[]byte{}, "&[]uint8{}"},
+	{"%#v", [3]byte{}, "[3]uint8{0x0, 0x0, 0x0}"},
+	{"%#v", [3]uint8{}, "[3]uint8{0x0, 0x0, 0x0}"},
 
 	// slices with other formats
 	{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
@@ -453,30 +652,61 @@ var fmtTests = []struct {
 	{"%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"},
+	{"%2x", []byte{}, "  "},
+	{"%#2x", []byte{}, "  "},
 	{"% 02x", []byte{}, "00"},
-	{"%08x", []byte{0xab}, "000000ab"},
-	{"% 08x", []byte{0xab}, "000000ab"},
-	{"%08x", []byte{0xab, 0xcd}, "0000abcd"},
-	{"% 08x", []byte{0xab, 0xcd}, "000ab cd"},
+	{"%# 02x", []byte{}, "00"},
+	{"%-2x", []byte{}, "  "},
+	{"%-02x", []byte{}, "  "},
 	{"%8x", []byte{0xab}, "      ab"},
 	{"% 8x", []byte{0xab}, "      ab"},
-	{"%8x", []byte{0xab, 0xcd}, "    abcd"},
-	{"% 8x", []byte{0xab, 0xcd}, "   ab cd"},
+	{"%#8x", []byte{0xab}, "    0xab"},
+	{"%# 8x", []byte{0xab}, "    0xab"},
+	{"%08x", []byte{0xab}, "000000ab"},
+	{"% 08x", []byte{0xab}, "000000ab"},
+	{"%#08x", []byte{0xab}, "00000xab"},
+	{"%# 08x", []byte{0xab}, "00000xab"},
+	{"%10x", []byte{0xab, 0xcd}, "      abcd"},
+	{"% 10x", []byte{0xab, 0xcd}, "     ab cd"},
+	{"%#10x", []byte{0xab, 0xcd}, "    0xabcd"},
+	{"%# 10x", []byte{0xab, 0xcd}, " 0xab 0xcd"},
+	{"%010x", []byte{0xab, 0xcd}, "000000abcd"},
+	{"% 010x", []byte{0xab, 0xcd}, "00000ab cd"},
+	{"%#010x", []byte{0xab, 0xcd}, "00000xabcd"},
+	{"%# 010x", []byte{0xab, 0xcd}, "00xab 0xcd"},
+	{"%-10X", []byte{0xab}, "AB        "},
+	{"% -010X", []byte{0xab}, "AB        "},
+	{"%#-10X", []byte{0xab, 0xcd}, "0XABCD    "},
+	{"%# -010X", []byte{0xab, 0xcd}, "0XAB 0XCD "},
 	// Same for strings
-	{"%x", "", ""},
-	{"%02x", "", "00"},
+	{"%2x", "", "  "},
+	{"%#2x", "", "  "},
 	{"% 02x", "", "00"},
-	{"%08x", "\xab", "000000ab"},
-	{"% 08x", "\xab", "000000ab"},
-	{"%08x", "\xab\xcd", "0000abcd"},
-	{"% 08x", "\xab\xcd", "000ab cd"},
+	{"%# 02x", "", "00"},
+	{"%-2x", "", "  "},
+	{"%-02x", "", "  "},
 	{"%8x", "\xab", "      ab"},
 	{"% 8x", "\xab", "      ab"},
-	{"%8x", "\xab\xcd", "    abcd"},
-	{"% 8x", "\xab\xcd", "   ab cd"},
+	{"%#8x", "\xab", "    0xab"},
+	{"%# 8x", "\xab", "    0xab"},
+	{"%08x", "\xab", "000000ab"},
+	{"% 08x", "\xab", "000000ab"},
+	{"%#08x", "\xab", "00000xab"},
+	{"%# 08x", "\xab", "00000xab"},
+	{"%10x", "\xab\xcd", "      abcd"},
+	{"% 10x", "\xab\xcd", "     ab cd"},
+	{"%#10x", "\xab\xcd", "    0xabcd"},
+	{"%# 10x", "\xab\xcd", " 0xab 0xcd"},
+	{"%010x", "\xab\xcd", "000000abcd"},
+	{"% 010x", "\xab\xcd", "00000ab cd"},
+	{"%#010x", "\xab\xcd", "00000xabcd"},
+	{"%# 010x", "\xab\xcd", "00xab 0xcd"},
+	{"%-10X", "\xab", "AB        "},
+	{"% -010X", "\xab", "AB        "},
+	{"%#-10X", "\xab\xcd", "0XABCD    "},
+	{"%# -010X", "\xab\xcd", "0XAB 0XCD "},
 
 	// renamings
 	{"%v", renamedBool(true), "true"},
@@ -495,7 +725,8 @@ var fmtTests = []struct {
 	{"%x", renamedString("thing"), "7468696e67"},
 	{"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`},
 	{"%q", renamedBytes([]byte("hello")), `"hello"`},
-	{"%x", []renamedUint8{'a', 'b', 'c'}, "616263"},
+	{"%x", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656c6c6f"},
+	{"%X", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656C6C6F"},
 	{"%s", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "hello"},
 	{"%q", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, `"hello"`},
 	{"%v", renamedFloat32(22), "22"},
@@ -513,79 +744,72 @@ var fmtTests = []struct {
 	{"%#v", S{F(7), G(8)}, "fmt_test.S{F:<v=F(7)>, G:GoString(8)}"},
 
 	// %T
+	{"%T", byte(0), "uint8"},
+	{"%T", reflect.ValueOf(nil), "reflect.Value"},
 	{"%T", (4 - 3i), "complex128"},
 	{"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
-	{"%T", intVal, "int"},
-	{"%6T", &intVal, "  *int"},
+	{"%T", intVar, "int"},
+	{"%6T", &intVar, "  *int"},
 	{"%10T", nil, "     <nil>"},
 	{"%-10T", nil, "<nil>     "},
 
-	// %p
-	{"p0=%p", new(int), "p0=0xPTR"},
-	{"p1=%s", &pValue, "p1=String(p)"}, // String method...
-	{"p2=%p", &pValue, "p2=0xPTR"},     // ... not called with %p
-	{"p3=%p", (*int)(nil), "p3=0x0"},
-	{"p4=%#p", new(int), "p4=PTR"},
-
+	// %p with pointers
+	{"%p", (*int)(nil), "0x0"},
+	{"%#p", (*int)(nil), "0"},
+	{"%p", &intVar, "0xPTR"},
+	{"%#p", &intVar, "PTR"},
+	{"%p", &array, "0xPTR"},
+	{"%p", &slice, "0xPTR"},
+	{"%8.2p", (*int)(nil), "    0x00"},
+	{"%-20.16p", &intVar, "0xPTR  "},
 	// %p on non-pointers
 	{"%p", make(chan int), "0xPTR"},
 	{"%p", make(map[int]int), "0xPTR"},
-	{"%p", make([]int, 1), "0xPTR"},
-	{"%p", 27, "%!p(int=27)"}, // not a pointer at all
-
-	// %q on pointers
-	{"%q", (*int)(nil), "%!q(*int=<nil>)"},
-	{"%q", new(int), "%!q(*int=0xPTR)"},
-
-	// %v on pointers formats 0 as <nil>
+	{"%p", func() {}, "0xPTR"},
+	{"%p", 27, "%!p(int=27)"},  // not a pointer at all
+	{"%p", nil, "%!p(<nil>)"},  // nil on its own has no type ...
+	{"%#p", nil, "%!p(<nil>)"}, // ... and hence is not a pointer type.
+	// pointers with specified base
+	{"%b", &intVar, "PTR_b"},
+	{"%d", &intVar, "PTR_d"},
+	{"%o", &intVar, "PTR_o"},
+	{"%x", &intVar, "PTR_x"},
+	{"%X", &intVar, "PTR_X"},
+	// %v on pointers
+	{"%v", nil, "<nil>"},
+	{"%#v", nil, "<nil>"},
 	{"%v", (*int)(nil), "<nil>"},
-	{"%v", new(int), "0xPTR"},
-
-	// %d etc. pointers use specified base.
-	{"%d", new(int), "PTR_d"},
-	{"%o", new(int), "PTR_o"},
-	{"%x", new(int), "PTR_x"},
+	{"%#v", (*int)(nil), "(*int)(nil)"},
+	{"%v", &intVar, "0xPTR"},
+	{"%#v", &intVar, "(*int)(0xPTR)"},
+	{"%8.2v", (*int)(nil), "   <nil>"},
+	{"%-20.16v", &intVar, "0xPTR  "},
+	// string method on pointer
+	{"%s", &pValue, "String(p)"}, // String method...
+	{"%p", &pValue, "0xPTR"},     // ... is not called with %p.
 
 	// %d on Stringer should give integer if possible
 	{"%s", time.Time{}.Month(), "January"},
 	{"%d", time.Time{}.Month(), "1"},
 
 	// erroneous things
+	{"", nil, "%!(EXTRA <nil>)"},
+	{"", 2, "%!(EXTRA int=2)"},
+	{"no args", "hello", "no args%!(EXTRA string=hello)"},
 	{"%s %", "hello", "hello %!(NOVERB)"},
 	{"%s %.2", "hello", "hello %!(NOVERB)"},
-	{"%d", "hello", "%!d(string=hello)"},
-	{"no args", "hello", "no args%!(EXTRA string=hello)"},
-	{"%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)"},
+	// Extra argument errors should format without flags set.
+	{"%010.2", "12345", "%!(NOVERB)%!(EXTRA string=12345)"},
 
 	// The "<nil>" show up because maps are printed by
 	// first obtaining a list of keys and then looking up
-	// each key.  Since NaNs can be map keys but cannot
+	// each key. Since NaNs can be map keys but cannot
 	// be fetched directly, the lookup fails and returns a
 	// zero reflect.Value, which formats as <nil>.
 	// This test is just to check that it shows the two NaNs at all.
-	{"%v", map[float64]int{math.NaN(): 1, math.NaN(): 2}, "map[NaN:<nil> NaN:<nil>]"},
-
-	// Used to crash because nByte didn't allow for a sign.
-	{"%b", int64(-1 << 63), zeroFill("-1", 63, "")},
-
-	// Used to panic.
-	{"%0100d", 1, zeroFill("", 100, "1")},
-	{"%0100d", -1, zeroFill("-", 99, "1")},
-	{"%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"},
+	{"%v", map[float64]int{NaN: 1, NaN: 2}, "map[NaN:<nil> NaN:<nil>]"},
 
 	// Comparison of padding rules with C printf.
 	/*
@@ -599,14 +823,16 @@ var fmtTests = []struct {
 			"[%7.2f]",
 			"[% 7.2f]",
 			"[%+7.2f]",
+			"[% +7.2f]",
 			"[%07.2f]",
 			"[% 07.2f]",
 			"[%+07.2f]",
+			"[% +07.2f]"
 		};
 
 		int main(void) {
 			int i;
-			for(i = 0; i < 9; i++) {
+			for(i = 0; i < 11; i++) {
 				printf("%s: ", format[i]);
 				printf(format[i], 1.0);
 				printf(" ");
@@ -622,9 +848,12 @@ var fmtTests = []struct {
 			[%7.2f]: [   1.00] [  -1.00]
 			[% 7.2f]: [   1.00] [  -1.00]
 			[%+7.2f]: [  +1.00] [  -1.00]
+			[% +7.2f]: [  +1.00] [  -1.00]
 			[%07.2f]: [0001.00] [-001.00]
 			[% 07.2f]: [ 001.00] [-001.00]
 			[%+07.2f]: [+001.00] [-001.00]
+			[% +07.2f]: [+001.00] [-001.00]
+
 	*/
 	{"%.2f", 1.0, "1.00"},
 	{"%.2f", -1.0, "-1.00"},
@@ -638,26 +867,35 @@ var fmtTests = []struct {
 	{"% 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"},
+	{"% +07.2f", 1.0, "+001.00"},
+	{"% +07.2f", -1.0, "-001.00"},
 
 	// Complex numbers: exhaustively tested in TestComplexFormatting.
 	{"%7.2f", 1 + 2i, "(   1.00  +2.00i)"},
 	{"%+07.2f", -1 - 2i, "(-001.00-002.00i)"},
-	// 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"},
-	// Make sure we can handle very large widths.
-	{"%0100f", -1.0, zeroFill("-", 99, "1.000000")},
+
+	// Use spaces instead of zero if padding to the right.
+	{"%0-5s", "abc", "abc  "},
+	{"%-05.1f", 1.0, "1.0  "},
+
+	// float and complex formatting should not change the padding width
+	// for other elements. See issue 14642.
+	{"%06v", []interface{}{+10.0, 10}, "[000010 000010]"},
+	{"%06v", []interface{}{-10.0, 10}, "[-00010 000010]"},
+	{"%06v", []interface{}{+10.0 + 10i, 10}, "[(000010+00010i) 000010]"},
+	{"%06v", []interface{}{-10.0 + 10i, 10}, "[(-00010+00010i) 000010]"},
+
+	// integer formatting should not alter padding for other elements.
+	{"%03.6v", []interface{}{1, 2.0, "x"}, "[000001 002 00x]"},
+	{"%03.0v", []interface{}{0, 2.0, "x"}, "[    002 000]"},
 
 	// Complex fmt used to leave the plus flag set for future entries in the array
 	// causing +2+0i and +3+0i instead of 2+0i and 3+0i.
@@ -667,27 +905,6 @@ var fmtTests = []struct {
 	// Incomplete format specification caused crash.
 	{"%.", 3, "%!.(int=3)"},
 
-	// Used to panic with out-of-bounds for very large numeric representations.
-	// nByte is set to handle one bit per uint64 in %b format, with a negative number.
-	// See issue 6777.
-	{"%#064x", 1, zeroFill("0x", 64, "1")},
-	{"%#064x", -1, zeroFill("-0x", 63, "1")},
-	{"%#064b", 1, zeroFill("", 64, "1")},
-	{"%#064b", -1, zeroFill("-", 63, "1")},
-	{"%#064o", 1, zeroFill("", 64, "1")},
-	{"%#064o", -1, zeroFill("-", 63, "1")},
-	{"%#064d", 1, zeroFill("", 64, "1")},
-	{"%#064d", -1, zeroFill("-", 63, "1")},
-	// Test that we handle the crossover above the size of uint64
-	{"%#072x", 1, zeroFill("0x", 72, "1")},
-	{"%#072x", -1, zeroFill("-0x", 71, "1")},
-	{"%#072b", 1, zeroFill("", 72, "1")},
-	{"%#072b", -1, zeroFill("-", 71, "1")},
-	{"%#072o", 1, zeroFill("", 72, "1")},
-	{"%#072o", -1, zeroFill("-", 71, "1")},
-	{"%#072d", 1, zeroFill("", 72, "1")},
-	{"%#072d", -1, zeroFill("-", 71, "1")},
-
 	// Padding for complex numbers. Has been bad, then fixed, then bad again.
 	{"%+10.2f", +104.66 + 440.51i, "(   +104.66   +440.51i)"},
 	{"%+10.2f", -104.66 + 440.51i, "(   -104.66   +440.51i)"},
@@ -699,19 +916,21 @@ var fmtTests = []struct {
 	{"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"},
 
 	// []T where type T is a byte with a Stringer method.
-	{"%v", byteStringerSlice, "[X X X X]"},
-	{"%s", byteStringerSlice, "abcd"},
-	{"%q", byteStringerSlice, "\"abcd\""},
-	{"%x", byteStringerSlice, "61626364"},
-	{"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x61, 0x62, 0x63, 0x64}"},
+	{"%v", byteStringerSlice, "[X X X X X]"},
+	{"%s", byteStringerSlice, "hello"},
+	{"%q", byteStringerSlice, "\"hello\""},
+	{"%x", byteStringerSlice, "68656c6c6f"},
+	{"%X", byteStringerSlice, "68656C6C6F"},
+	{"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x68, 0x65, 0x6c, 0x6c, 0x6f}"},
 
 	// And the same for Formatter.
-	{"%v", byteFormatterSlice, "[X X X X]"},
-	{"%s", byteFormatterSlice, "abcd"},
-	{"%q", byteFormatterSlice, "\"abcd\""},
-	{"%x", byteFormatterSlice, "61626364"},
+	{"%v", byteFormatterSlice, "[X X X X X]"},
+	{"%s", byteFormatterSlice, "hello"},
+	{"%q", byteFormatterSlice, "\"hello\""},
+	{"%x", byteFormatterSlice, "68656c6c6f"},
+	{"%X", byteFormatterSlice, "68656C6C6F"},
 	// This next case seems wrong, but the docs say the Formatter wins here.
-	{"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"},
+	{"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, 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()).
@@ -726,6 +945,32 @@ var fmtTests = []struct {
 
 	// invalid reflect.Value doesn't crash.
 	{"%v", reflect.Value{}, "<invalid reflect.Value>"},
+	{"%v", &reflect.Value{}, "<invalid Value>"},
+	{"%v", SI{reflect.Value{}}, "{<invalid Value>}"},
+
+	// Tests to check that not supported verbs generate an error string.
+	{"%☠", nil, "%!☠(<nil>)"},
+	{"%☠", interface{}(nil), "%!☠(<nil>)"},
+	{"%☠", int(0), "%!☠(int=0)"},
+	{"%☠", uint(0), "%!☠(uint=0)"},
+	{"%☠", []byte{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"},
+	{"%☠", []uint8{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"},
+	{"%☠", [1]byte{0}, "[%!☠(uint8=0)]"},
+	{"%☠", [1]uint8{0}, "[%!☠(uint8=0)]"},
+	{"%☠", "hello", "%!☠(string=hello)"},
+	{"%☠", 1.2345678, "%!☠(float64=1.2345678)"},
+	{"%☠", float32(1.2345678), "%!☠(float32=1.2345678)"},
+	{"%☠", 1.2345678 + 1.2345678i, "%!☠(complex128=(1.2345678+1.2345678i))"},
+	{"%☠", complex64(1.2345678 + 1.2345678i), "%!☠(complex64=(1.2345678+1.2345678i))"},
+	{"%☠", &intVar, "%!☠(*int=0xPTR)"},
+	{"%☠", make(chan int), "%!☠(chan int=0xPTR)"},
+	{"%☠", func() {}, "%!☠(func()=0xPTR)"},
+	{"%☠", reflect.ValueOf(renamedInt(0)), "%!☠(fmt_test.renamedInt=0)"},
+	{"%☠", SI{renamedInt(0)}, "{%!☠(fmt_test.renamedInt=0)}"},
+	{"%☠", &[]interface{}{I(1), G(2)}, "&[%!☠(fmt_test.I=1) %!☠(fmt_test.G=2)]"},
+	{"%☠", SI{&[]interface{}{I(1), G(2)}}, "{%!☠(*[]interface {}=&[1 2])}"},
+	{"%☠", reflect.Value{}, "<invalid reflect.Value>"},
+	{"%☠", map[float64]int{NaN: 1}, "map[%!☠(float64=NaN):%!☠(<nil>)]"},
 }
 
 // zeroFill generates zero-filled strings of the specified width. The length
@@ -737,27 +982,37 @@ func zeroFill(prefix string, width int, suffix string) string {
 func TestSprintf(t *testing.T) {
 	for _, tt := range fmtTests {
 		s := Sprintf(tt.fmt, tt.val)
-		if i := strings.Index(tt.out, "PTR"); i >= 0 {
-			pattern := "PTR"
-			chars := "0123456789abcdefABCDEF"
+		i := strings.Index(tt.out, "PTR")
+		if i >= 0 && i < len(s) {
+			var pattern, chars string
 			switch {
-			case strings.HasPrefix(tt.out[i:], "PTR_d"):
-				pattern = "PTR_d"
-				chars = chars[:10]
+			case strings.HasPrefix(tt.out[i:], "PTR_b"):
+				pattern = "PTR_b"
+				chars = "01"
 			case strings.HasPrefix(tt.out[i:], "PTR_o"):
 				pattern = "PTR_o"
-				chars = chars[:8]
+				chars = "01234567"
+			case strings.HasPrefix(tt.out[i:], "PTR_d"):
+				pattern = "PTR_d"
+				chars = "0123456789"
 			case strings.HasPrefix(tt.out[i:], "PTR_x"):
 				pattern = "PTR_x"
+				chars = "0123456789abcdef"
+			case strings.HasPrefix(tt.out[i:], "PTR_X"):
+				pattern = "PTR_X"
+				chars = "0123456789ABCDEF"
+			default:
+				pattern = "PTR"
+				chars = "0123456789abcdefABCDEF"
 			}
-			j := i
-			for ; j < len(s); j++ {
-				c := s[j]
-				if !strings.ContainsRune(chars, rune(c)) {
+			p := s[:i] + pattern
+			for j := i; j < len(s); j++ {
+				if !strings.ContainsRune(chars, rune(s[j])) {
+					p += s[j:]
 					break
 				}
 			}
-			s = s[0:i] + pattern + s[j:]
+			s = p
 		}
 		if s != tt.out {
 			if _, ok := tt.val.(string); ok {
@@ -775,7 +1030,7 @@ func TestSprintf(t *testing.T) {
 // thing as if done by hand with two singleton prints.
 func TestComplexFormatting(t *testing.T) {
 	var yesNo = []bool{true, false}
-	var values = []float64{1, 0, -1, math.Inf(1), math.Inf(-1), math.NaN()}
+	var values = []float64{1, 0, -1, posInf, negInf, NaN}
 	for _, plus := range yesNo {
 		for _, zero := range yesNo {
 			for _, space := range yesNo {
@@ -869,6 +1124,14 @@ func TestReorder(t *testing.T) {
 	}
 }
 
+func BenchmarkSprintfPadding(b *testing.B) {
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%16f", 1.0)
+		}
+	})
+}
+
 func BenchmarkSprintfEmpty(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
@@ -885,6 +1148,22 @@ func BenchmarkSprintfString(b *testing.B) {
 	})
 }
 
+func BenchmarkSprintfTruncateString(b *testing.B) {
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%.3s", "日本語日本語日本語")
+		}
+	})
+}
+
+func BenchmarkSprintfQuoteString(b *testing.B) {
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%q", "日本語日本語日本語")
+		}
+	})
+}
+
 func BenchmarkSprintfInt(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
@@ -917,6 +1196,66 @@ func BenchmarkSprintfFloat(b *testing.B) {
 	})
 }
 
+func BenchmarkSprintfComplex(b *testing.B) {
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%f", 5.23184+5.23184i)
+		}
+	})
+}
+
+func BenchmarkSprintfBoolean(b *testing.B) {
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%t", true)
+		}
+	})
+}
+
+func BenchmarkSprintfHexString(b *testing.B) {
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("% #x", "0123456789abcdef")
+		}
+	})
+}
+
+func BenchmarkSprintfHexBytes(b *testing.B) {
+	data := []byte("0123456789abcdef")
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("% #x", data)
+		}
+	})
+}
+
+func BenchmarkSprintfBytes(b *testing.B) {
+	data := []byte("0123456789abcdef")
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%v", data)
+		}
+	})
+}
+
+func BenchmarkSprintfStringer(b *testing.B) {
+	stringer := I(12345)
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%v", stringer)
+		}
+	})
+}
+
+func BenchmarkSprintfStructure(b *testing.B) {
+	s := &[]interface{}{SI{12345}, map[int]string{0: "hello"}}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			Sprintf("%#v", s)
+		}
+	})
+}
+
 func BenchmarkManyArgs(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		var buf bytes.Buffer
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 517b18f..0236475 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -5,18 +5,13 @@
 package fmt
 
 import (
-	"math"
 	"strconv"
 	"unicode/utf8"
 )
 
 const (
-	// %b of an int64, plus a sign.
-	// Hex can add 0x and we handle it specially.
-	nByte = 65
-
-	ldigits = "0123456789abcdef"
-	udigits = "0123456789ABCDEF"
+	ldigits = "0123456789abcdefx"
+	udigits = "0123456789ABCDEFX"
 )
 
 const (
@@ -24,16 +19,6 @@ const (
 	unsigned = false
 )
 
-var padZeroBytes = make([]byte, nByte)
-var padSpaceBytes = make([]byte, nByte)
-
-func init() {
-	for i := 0; i < nByte; i++ {
-		padZeroBytes[i] = '0'
-		padSpaceBytes[i] = ' '
-	}
-}
-
 // flags placed in a separate struct for easy clearing.
 type fmtFlags struct {
 	widPresent  bool
@@ -42,8 +27,6 @@ type fmtFlags struct {
 	plus        bool
 	sharp       bool
 	space       bool
-	unicode     bool
-	uniQuote    bool // Use 'x'= prefix for %U if printable.
 	zero        bool
 
 	// For the formats %+v %#v, we set the plusV/sharpV flags
@@ -56,12 +39,16 @@ type fmtFlags struct {
 // A fmt is the raw formatter used by Printf etc.
 // It prints into a buffer that must be set up separately.
 type fmt struct {
-	intbuf [nByte]byte
-	buf    *buffer
-	// width, precision
-	wid  int
-	prec int
+	buf *buffer
+
 	fmtFlags
+
+	wid  int // width
+	prec int // precision
+
+	// intbuf is large enought to store %b of an int64 with a sign and
+	// avoids padding at the end of the struct on 32 bit architectures.
+	intbuf [68]byte
 }
 
 func (f *fmt) clearflags() {
@@ -73,176 +60,213 @@ func (f *fmt) init(buf *buffer) {
 	f.clearflags()
 }
 
-// computePadding computes left and right padding widths (only one will be non-zero).
-func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
-	left := !f.minus
-	w := f.wid
-	if w < 0 {
-		left = false
-		w = -w
-	}
-	w -= width
-	if w > 0 {
-		if left && f.zero {
-			return padZeroBytes, w, 0
-		}
-		if left {
-			return padSpaceBytes, w, 0
-		} else {
-			// can't be zero padding on the right
-			return padSpaceBytes, 0, w
-		}
-	}
-	return
-}
-
 // writePadding generates n bytes of padding.
-func (f *fmt) writePadding(n int, padding []byte) {
-	for n > 0 {
-		m := n
-		if m > nByte {
-			m = nByte
-		}
-		f.buf.Write(padding[0:m])
-		n -= m
+func (f *fmt) writePadding(n int) {
+	if n <= 0 { // No padding bytes needed.
+		return
 	}
+	buf := *f.buf
+	oldLen := len(buf)
+	newLen := oldLen + n
+	// Make enough room for padding.
+	if newLen > cap(buf) {
+		buf = make(buffer, cap(buf)*2+n)
+		copy(buf, *f.buf)
+	}
+	// Decide which byte the padding should be filled with.
+	padByte := byte(' ')
+	if f.zero {
+		padByte = byte('0')
+	}
+	// Fill padding with padByte.
+	padding := buf[oldLen:newLen]
+	for i := range padding {
+		padding[i] = padByte
+	}
+	*f.buf = buf[:newLen]
 }
 
-// pad appends b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
 func (f *fmt) pad(b []byte) {
 	if !f.widPresent || f.wid == 0 {
 		f.buf.Write(b)
 		return
 	}
-	padding, left, right := f.computePadding(utf8.RuneCount(b))
-	if left > 0 {
-		f.writePadding(left, padding)
-	}
-	f.buf.Write(b)
-	if right > 0 {
-		f.writePadding(right, padding)
+	width := f.wid - utf8.RuneCount(b)
+	if !f.minus {
+		// left padding
+		f.writePadding(width)
+		f.buf.Write(b)
+	} else {
+		// right padding
+		f.buf.Write(b)
+		f.writePadding(width)
 	}
 }
 
-// padString appends s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
+// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
 func (f *fmt) padString(s string) {
 	if !f.widPresent || f.wid == 0 {
 		f.buf.WriteString(s)
 		return
 	}
-	padding, left, right := f.computePadding(utf8.RuneCountInString(s))
-	if left > 0 {
-		f.writePadding(left, padding)
-	}
-	f.buf.WriteString(s)
-	if right > 0 {
-		f.writePadding(right, padding)
+	width := f.wid - utf8.RuneCountInString(s)
+	if !f.minus {
+		// left padding
+		f.writePadding(width)
+		f.buf.WriteString(s)
+	} else {
+		// right padding
+		f.buf.WriteString(s)
+		f.writePadding(width)
 	}
 }
 
-var (
-	trueBytes  = []byte("true")
-	falseBytes = []byte("false")
-)
-
 // fmt_boolean formats a boolean.
 func (f *fmt) fmt_boolean(v bool) {
 	if v {
-		f.pad(trueBytes)
+		f.padString("true")
 	} else {
-		f.pad(falseBytes)
+		f.padString("false")
 	}
 }
 
-// integer; interprets prec but not wid.  Once formatted, result is sent to pad()
-// and then flags are cleared.
-func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
-	// precision of 0 and value of 0 means "print nothing"
-	if f.precPresent && f.prec == 0 && a == 0 {
-		return
+// fmt_unicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'".
+func (f *fmt) fmt_unicode(u uint64) {
+	buf := f.intbuf[0:]
+
+	// With default precision set the maximum needed buf length is 18
+	// for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits
+	// into the already allocated intbuf with a capacity of 68 bytes.
+	prec := 4
+	if f.precPresent && f.prec > 4 {
+		prec = f.prec
+		// Compute space needed for "U+" , number, " '", character, "'".
+		width := 2 + prec + 2 + utf8.UTFMax + 1
+		if width > len(buf) {
+			buf = make([]byte, width)
+		}
 	}
 
-	negative := signedness == signed && a < 0
+	// Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left.
+	i := len(buf)
+
+	// For %#U we want to add a space and a quoted character at the end of the buffer.
+	if f.sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) {
+		i--
+		buf[i] = '\''
+		i -= utf8.RuneLen(rune(u))
+		utf8.EncodeRune(buf[i:], rune(u))
+		i--
+		buf[i] = '\''
+		i--
+		buf[i] = ' '
+	}
+	// Format the Unicode code point u as a hexadecimal number.
+	for u >= 16 {
+		i--
+		buf[i] = udigits[u&0xF]
+		prec--
+		u >>= 4
+	}
+	i--
+	buf[i] = udigits[u]
+	prec--
+	// Add zeros in front of the number until requested precision is reached.
+	for prec > 0 {
+		i--
+		buf[i] = '0'
+		prec--
+	}
+	// Add a leading "U+".
+	i--
+	buf[i] = '+'
+	i--
+	buf[i] = 'U'
+
+	oldZero := f.zero
+	f.zero = false
+	f.pad(buf[i:])
+	f.zero = oldZero
+}
+
+// fmt_integer formats signed and unsigned integers.
+func (f *fmt) fmt_integer(u uint64, base int, isSigned bool, digits string) {
+	negative := isSigned && int64(u) < 0
 	if negative {
-		a = -a
+		u = -u
 	}
 
-	var buf []byte = f.intbuf[0:]
-	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 {
+	buf := f.intbuf[0:]
+	// The already allocated f.intbuf with a capacity of 68 bytes
+	// is large enough for integer formatting when no precision or width is set.
+	if f.widPresent || f.precPresent {
+		// Account 3 extra bytes for possible addition of a sign and "0x".
+		width := 3 + f.wid + f.prec // wid and prec are always positive.
+		if width > len(buf) {
 			// We're going to need a bigger boat.
 			buf = make([]byte, width)
 		}
 	}
 
-	// two ways to ask for extra leading zero digits: %.3d or %03d.
-	// apparently the first cancels the second.
+	// Two ways to ask for extra leading zero digits: %.3d or %03d.
+	// If both are specified the f.zero flag is ignored and
+	// padding with spaces is used instead.
 	prec := 0
 	if f.precPresent {
 		prec = f.prec
-		f.zero = false
-	} else if f.zero && f.widPresent && !f.minus && f.wid > 0 {
+		// Precision of 0 and value of 0 means "print nothing" but padding.
+		if prec == 0 && u == 0 {
+			oldZero := f.zero
+			f.zero = false
+			f.writePadding(f.wid)
+			f.zero = oldZero
+			return
+		}
+	} else if f.zero && f.widPresent {
 		prec = f.wid
 		if negative || f.plus || f.space {
 			prec-- // leave room for sign
 		}
 	}
 
-	// format a into buf, ending at buf[i].  (printing is easier right-to-left.)
-	// a is made into unsigned ua.  we could make things
-	// marginally faster by splitting the 32-bit case out into a separate
-	// block but it's not worth the duplication, so ua has 64 bits.
+	// Because printing is easier right-to-left: format u into buf, ending at buf[i].
+	// We could make things marginally faster by splitting the 32-bit case out
+	// into a separate block but it's not worth the duplication, so u has 64 bits.
 	i := len(buf)
-	ua := uint64(a)
-	// use constants for the division and modulo for more efficient code.
-	// switch cases ordered by popularity.
+	// Use constants for the division and modulo for more efficient code.
+	// Switch cases ordered by popularity.
 	switch base {
 	case 10:
-		for ua >= 10 {
+		for u >= 10 {
 			i--
-			next := ua / 10
-			buf[i] = byte('0' + ua - next*10)
-			ua = next
+			next := u / 10
+			buf[i] = byte('0' + u - next*10)
+			u = next
 		}
 	case 16:
-		for ua >= 16 {
+		for u >= 16 {
 			i--
-			buf[i] = digits[ua&0xF]
-			ua >>= 4
+			buf[i] = digits[u&0xF]
+			u >>= 4
 		}
 	case 8:
-		for ua >= 8 {
+		for u >= 8 {
 			i--
-			buf[i] = byte('0' + ua&7)
-			ua >>= 3
+			buf[i] = byte('0' + u&7)
+			u >>= 3
 		}
 	case 2:
-		for ua >= 2 {
+		for u >= 2 {
 			i--
-			buf[i] = byte('0' + ua&1)
-			ua >>= 1
+			buf[i] = byte('0' + u&1)
+			u >>= 1
 		}
 	default:
 		panic("fmt: unknown base; can't happen")
 	}
 	i--
-	buf[i] = digits[ua]
+	buf[i] = digits[u]
 	for i > 0 && prec > len(buf)-i {
 		i--
 		buf[i] = '0'
@@ -257,18 +281,13 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
 				buf[i] = '0'
 			}
 		case 16:
+			// Add a leading 0x or 0X.
 			i--
-			buf[i] = 'x' + digits[10] - 'a'
+			buf[i] = digits[16]
 			i--
 			buf[i] = '0'
 		}
 	}
-	if f.unicode {
-		i--
-		buf[i] = '+'
-		i--
-		buf[i] = 'U'
-	}
 
 	if negative {
 		i--
@@ -281,36 +300,23 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
 		buf[i] = ' '
 	}
 
-	// If we want a quoted char for %#U, move the data up to make room.
-	if f.unicode && f.uniQuote && a >= 0 && a <= utf8.MaxRune && strconv.IsPrint(rune(a)) {
-		runeWidth := utf8.RuneLen(rune(a))
-		width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
-		copy(buf[i-width:], buf[i:])   // guaranteed to have enough room.
-		i -= width
-		// Now put " 'x'" at the end.
-		j := len(buf) - width
-		buf[j] = ' '
-		j++
-		buf[j] = '\''
-		j++
-		utf8.EncodeRune(buf[j:], rune(a))
-		j += runeWidth
-		buf[j] = '\''
-	}
-
+	// Left padding with zeros has already been handled like precision earlier
+	// or the f.zero flag is ignored due to an explicitly set precision.
+	oldZero := f.zero
+	f.zero = false
 	f.pad(buf[i:])
+	f.zero = oldZero
 }
 
 // truncate truncates the string to the specified precision, if present.
 func (f *fmt) truncate(s string) string {
-	if f.precPresent && f.prec < utf8.RuneCountInString(s) {
+	if f.precPresent {
 		n := f.prec
 		for i := range s {
-			if n == 0 {
-				s = s[:i]
-				break
-			}
 			n--
+			if n < 0 {
+				return s[:i]
+			}
 		}
 	}
 	return s
@@ -324,212 +330,169 @@ func (f *fmt) fmt_s(s string) {
 
 // fmt_sbx formats a string or byte slice as a hexadecimal encoding of its bytes.
 func (f *fmt) fmt_sbx(s string, b []byte, digits string) {
-	n := len(b)
+	length := len(b)
 	if b == nil {
-		n = len(s)
+		// No byte slice present. Assume string s should be encoded.
+		length = len(s)
+	}
+	// Set length to not process more bytes than the precision demands.
+	if f.precPresent && f.prec < length {
+		length = f.prec
+	}
+	// Compute width of the encoding taking into account the f.sharp and f.space flag.
+	width := 2 * length
+	if width > 0 {
+		if f.space {
+			// Each element encoded by two hexadecimals will get a leading 0x or 0X.
+			if f.sharp {
+				width *= 2
+			}
+			// Elements will be separated by a space.
+			width += length - 1
+		} else if f.sharp {
+			// Only a leading 0x or 0X will be added for the whole string.
+			width += 2
+		}
+	} else { // The byte slice or string that should be encoded is empty.
+		if f.widPresent {
+			f.writePadding(f.wid)
+		}
+		return
+	}
+	// Handle padding to the left.
+	if f.widPresent && f.wid > width && !f.minus {
+		f.writePadding(f.wid - width)
 	}
-	x := digits[10] - 'a' + 'x'
-	// TODO: Avoid buffer by pre-padding.
-	var buf []byte
-	for i := 0; i < n; i++ {
-		if i > 0 && f.space {
+	// Write the encoding directly into the output buffer.
+	buf := *f.buf
+	if f.sharp {
+		// Add leading 0x or 0X.
+		buf = append(buf, '0', digits[16])
+	}
+	var c byte
+	for i := 0; i < length; i++ {
+		if f.space && i > 0 {
+			// Separate elements with a space.
 			buf = append(buf, ' ')
+			if f.sharp {
+				// Add leading 0x or 0X for each element.
+				buf = append(buf, '0', digits[16])
+			}
 		}
-		if f.sharp && (f.space || i == 0) {
-			buf = append(buf, '0', x)
-		}
-		var c byte
-		if b == nil {
-			c = s[i]
+		if b != nil {
+			c = b[i] // Take a byte from the input byte slice.
 		} else {
-			c = b[i]
+			c = s[i] // Take a byte from the input string.
 		}
+		// Encode each byte as two hexadecimal digits.
 		buf = append(buf, digits[c>>4], digits[c&0xF])
 	}
-	f.pad(buf)
+	*f.buf = buf
+	// Handle padding to the right.
+	if f.widPresent && f.wid > width && f.minus {
+		f.writePadding(f.wid - width)
+	}
 }
 
 // fmt_sx formats a string as a hexadecimal encoding of its bytes.
 func (f *fmt) fmt_sx(s, digits string) {
-	if f.precPresent && f.prec < len(s) {
-		s = s[:f.prec]
-	}
 	f.fmt_sbx(s, nil, digits)
 }
 
 // fmt_bx formats a byte slice as a hexadecimal encoding of its bytes.
 func (f *fmt) fmt_bx(b []byte, digits string) {
-	if f.precPresent && f.prec < len(b) {
-		b = b[:f.prec]
-	}
 	f.fmt_sbx("", b, digits)
 }
 
 // fmt_q formats a string as a double-quoted, escaped Go string constant.
+// If f.sharp is set a raw (backquoted) string may be returned instead
+// if the string does not contain any control characters other than tab.
 func (f *fmt) fmt_q(s string) {
 	s = f.truncate(s)
-	var quoted string
 	if f.sharp && strconv.CanBackquote(s) {
-		quoted = "`" + s + "`"
+		f.padString("`" + s + "`")
+		return
+	}
+	buf := f.intbuf[:0]
+	if f.plus {
+		f.pad(strconv.AppendQuoteToASCII(buf, s))
 	} else {
-		if f.plus {
-			quoted = strconv.QuoteToASCII(s)
-		} else {
-			quoted = strconv.Quote(s)
-		}
+		f.pad(strconv.AppendQuote(buf, s))
 	}
-	f.padString(quoted)
 }
 
-// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
+// fmt_c formats an integer as a Unicode character.
 // If the character is not valid Unicode, it will print '\ufffd'.
-func (f *fmt) fmt_qc(c int64) {
-	var quoted []byte
+func (f *fmt) fmt_c(c uint64) {
+	r := rune(c)
+	if c > utf8.MaxRune {
+		r = utf8.RuneError
+	}
+	buf := f.intbuf[:0]
+	w := utf8.EncodeRune(buf[:utf8.UTFMax], r)
+	f.pad(buf[:w])
+}
+
+// fmt_qc formats an integer as a single-quoted, escaped Go character constant.
+// If the character is not valid Unicode, it will print '\ufffd'.
+func (f *fmt) fmt_qc(c uint64) {
+	r := rune(c)
+	if c > utf8.MaxRune {
+		r = utf8.RuneError
+	}
+	buf := f.intbuf[:0]
 	if f.plus {
-		quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c))
+		f.pad(strconv.AppendQuoteRuneToASCII(buf, r))
 	} else {
-		quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c))
+		f.pad(strconv.AppendQuoteRune(buf, r))
 	}
-	f.pad(quoted)
 }
 
-// floating-point
-
-func doPrec(f *fmt, def int) int {
+// fmt_float formats a float64. It assumes that verb is a valid format specifier
+// for strconv.AppendFloat and therefore fits into a byte.
+func (f *fmt) fmt_float(v float64, size int, verb rune, prec int) {
+	// Explicit precision in format specifier overrules default precision.
 	if f.precPresent {
-		return f.prec
+		prec = f.prec
 	}
-	return def
-}
-
-// formatFloat formats a float64; it is an efficient equivalent to  f.pad(strconv.FormatFloat()...).
-func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
 	// Format number, reserving space for leading + sign if needed.
-	num := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+	num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size)
 	if num[1] == '-' || num[1] == '+' {
 		num = num[1:]
 	} else {
 		num[0] = '+'
 	}
-	// Special handling for infinity, which doesn't look like a number so shouldn't be padded with zeros.
-	if math.IsInf(v, 0) {
-		if f.zero {
-			defer func() { f.zero = true }()
-			f.zero = false
-		}
+	// f.space means to add a leading space instead of a "+" sign unless
+	// the sign is explicitly asked for by f.plus.
+	if f.space && num[0] == '+' && !f.plus {
+		num[0] = ' '
 	}
-	// num is now a signed version of the number.
-	// If we're zero padding, want the sign before the leading zeros.
-	// Achieve this by writing the sign out and then padding the unsigned number.
-	if f.zero && f.widPresent && f.wid > len(num) {
-		if f.space && v >= 0 {
-			f.buf.WriteByte(' ') // This is what C does: even with zero, f.space means space.
-			f.wid--
-		} else if f.plus || v < 0 {
-			f.buf.WriteByte(num[0])
-			f.wid--
+	// Special handling for infinities and NaN,
+	// which don't look like a number so shouldn't be padded with zeros.
+	if num[1] == 'I' || num[1] == 'N' {
+		oldZero := f.zero
+		f.zero = false
+		// Remove sign before NaN if not asked for.
+		if num[1] == 'N' && !f.space && !f.plus {
+			num = num[1:]
 		}
-		f.pad(num[1:])
-		return
-	}
-	// f.space says to replace a leading + with a space.
-	if f.space && num[0] == '+' {
-		num[0] = ' '
 		f.pad(num)
+		f.zero = oldZero
 		return
 	}
-	// Now we know the sign is attached directly to the number, if present at all.
-	// We want a sign if asked for, if it's negative, or if it's infinity (+Inf vs. -Inf).
-	if f.plus || num[0] == '-' || math.IsInf(v, 0) {
+	// We want a sign if asked for and if the sign is not positive.
+	if f.plus || num[0] != '+' {
+		// If we're zero padding to the left we want the sign before the leading zeros.
+		// Achieve this by writing the sign out and then padding the unsigned number.
+		if f.zero && f.widPresent && f.wid > len(num) {
+			f.buf.WriteByte(num[0])
+			f.writePadding(f.wid - len(num))
+			f.buf.Write(num[1:])
+			return
+		}
 		f.pad(num)
 		return
 	}
 	// No sign to show and the number is positive; just print the unsigned number.
 	f.pad(num[1:])
 }
-
-// fmt_e64 formats a float64 in the form -1.23e+12.
-func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
-
-// fmt_E64 formats a float64 in the form -1.23E+12.
-func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
-
-// fmt_f64 formats a float64 in the form -1.23.
-func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
-
-// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
-
-// fmt_G64 formats a float64 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
-
-// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
-
-// float32
-// cannot defer to float64 versions
-// because it will get rounding wrong in corner cases.
-
-// fmt_e32 formats a float32 in the form -1.23e+12.
-func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
-
-// fmt_E32 formats a float32 in the form -1.23E+12.
-func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
-
-// fmt_f32 formats a float32 in the form -1.23.
-func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
-
-// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
-
-// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
-
-// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
-
-// fmt_c64 formats a complex64 according to the verb.
-func (f *fmt) fmt_c64(v complex64, verb rune) {
-	f.fmt_complex(float64(real(v)), float64(imag(v)), 32, verb)
-}
-
-// fmt_c128 formats a complex128 according to the verb.
-func (f *fmt) fmt_c128(v complex128, verb rune) {
-	f.fmt_complex(real(v), imag(v), 64, verb)
-}
-
-// fmt_complex formats a complex number as (r+ji).
-func (f *fmt) fmt_complex(r, j float64, size int, verb rune) {
-	f.buf.WriteByte('(')
-	oldPlus := f.plus
-	oldSpace := f.space
-	oldWid := f.wid
-	for i := 0; ; i++ {
-		switch verb {
-		case 'b':
-			f.formatFloat(r, 'b', 0, size)
-		case 'e':
-			f.formatFloat(r, 'e', doPrec(f, 6), size)
-		case 'E':
-			f.formatFloat(r, 'E', doPrec(f, 6), size)
-		case 'f', 'F':
-			f.formatFloat(r, 'f', doPrec(f, 6), size)
-		case 'g':
-			f.formatFloat(r, 'g', doPrec(f, -1), size)
-		case 'G':
-			f.formatFloat(r, 'G', doPrec(f, -1), size)
-		}
-		if i != 0 {
-			break
-		}
-		// Imaginary part always has a sign.
-		f.plus = true
-		f.space = false
-		f.wid = oldWid
-		r = j
-	}
-	f.space = oldSpace
-	f.plus = oldPlus
-	f.wid = oldWid
-	f.buf.Write(irparenBytes)
-}
diff --git a/src/fmt/print.go b/src/fmt/print.go
index ebfa13e..f8c7316 100644
--- a/src/fmt/print.go
+++ b/src/fmt/print.go
@@ -13,24 +13,23 @@ import (
 	"unicode/utf8"
 )
 
-// Some constants in the form of bytes, to avoid string overhead.
-// Needlessly fastidious, I suppose.
-var (
-	commaSpaceBytes  = []byte(", ")
-	nilAngleBytes    = []byte("<nil>")
-	nilParenBytes    = []byte("(nil)")
-	nilBytes         = []byte("nil")
-	mapBytes         = []byte("map[")
-	percentBangBytes = []byte("%!")
-	missingBytes     = []byte("(MISSING)")
-	badIndexBytes    = []byte("(BADINDEX)")
-	panicBytes       = []byte("(PANIC=")
-	extraBytes       = []byte("%!(EXTRA ")
-	irparenBytes     = []byte("i)")
-	bytesBytes       = []byte("[]byte{")
-	badWidthBytes    = []byte("%!(BADWIDTH)")
-	badPrecBytes     = []byte("%!(BADPREC)")
-	noVerbBytes      = []byte("%!(NOVERB)")
+// Strings for use with buffer.WriteString.
+// This is less overhead than using buffer.Write with byte arrays.
+const (
+	commaSpaceString  = ", "
+	nilAngleString    = "<nil>"
+	nilParenString    = "(nil)"
+	nilString         = "nil"
+	mapString         = "map["
+	percentBangString = "%!"
+	missingString     = "(MISSING)"
+	badIndexString    = "(BADINDEX)"
+	panicString       = "(PANIC="
+	extraString       = "%!(EXTRA "
+	badWidthString    = "%!(BADWIDTH)"
+	badPrecString     = "%!(BADPREC)"
+	noVerbString      = "%!(NOVERB)"
+	invReflectString  = "<invalid reflect.Value>"
 )
 
 // State represents the printer state passed to custom formatters.
@@ -38,7 +37,7 @@ var (
 // the flags and options for the operand's format specifier.
 type State interface {
 	// Write is the function to call to emit formatted output to be printed.
-	Write(b []byte) (ret int, err error)
+	Write(b []byte) (n int, err error)
 	// Width returns the value of the width option and whether it has been set.
 	Width() (wid int, ok bool)
 	// Precision returns the value of the precision option and whether it has been set.
@@ -75,25 +74,22 @@ type GoStringer interface {
 // Use simple []byte instead of bytes.Buffer to avoid large dependency.
 type buffer []byte
 
-func (b *buffer) Write(p []byte) (n int, err error) {
+func (b *buffer) Write(p []byte) {
 	*b = append(*b, p...)
-	return len(p), nil
 }
 
-func (b *buffer) WriteString(s string) (n int, err error) {
+func (b *buffer) WriteString(s string) {
 	*b = append(*b, s...)
-	return len(s), nil
 }
 
-func (b *buffer) WriteByte(c byte) error {
+func (b *buffer) WriteByte(c byte) {
 	*b = append(*b, c)
-	return nil
 }
 
-func (bp *buffer) WriteRune(r rune) error {
+func (bp *buffer) WriteRune(r rune) {
 	if r < utf8.RuneSelf {
 		*bp = append(*bp, byte(r))
-		return nil
+		return
 	}
 
 	b := *bp
@@ -103,25 +99,29 @@ func (bp *buffer) WriteRune(r rune) error {
 	}
 	w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r)
 	*bp = b[:n+w]
-	return nil
 }
 
+// pp is used to store a printer's state and is reused with sync.Pool to avoid allocations.
 type pp struct {
-	n         int
-	panicking bool
-	erroring  bool // printing an error condition
-	buf       buffer
+	buf buffer
+
 	// arg holds the current item, as an interface{}.
 	arg interface{}
-	// value holds the current item, as a reflect.Value, and will be
-	// the zero Value if the item has not been reflected.
+
+	// value is used instead of arg for reflect values.
 	value reflect.Value
+
+	// fmt is used to format basic items such as integers or strings.
+	fmt fmt
+
 	// reordered records whether the format string used argument reordering.
 	reordered bool
 	// goodArgNum records whether the most recent reordering directive was valid.
 	goodArgNum bool
-	runeBuf    [utf8.UTFMax]byte
-	fmt        fmt
+	// panicking is set by catchPanic to avoid infinite panic, recover, panic, ... recursion.
+	panicking bool
+	// erroring is set when printing an error string to guard against calling handleMethods.
+	erroring bool
 }
 
 var ppFree = sync.Pool{
@@ -139,10 +139,6 @@ func newPrinter() *pp {
 
 // free saves used pp structs in ppFree; avoids an allocation per invocation.
 func (p *pp) free() {
-	// Don't hold on to pp structs with large buffers.
-	if cap(p.buf) > 1024 {
-		return
-	}
 	p.buf = p.buf[:0]
 	p.arg = nil
 	p.value = reflect.Value{}
@@ -158,9 +154,9 @@ func (p *pp) Flag(b int) bool {
 	case '-':
 		return p.fmt.minus
 	case '+':
-		return p.fmt.plus
+		return p.fmt.plus || p.fmt.plusV
 	case '#':
-		return p.fmt.sharp
+		return p.fmt.sharp || p.fmt.sharpV
 	case ' ':
 		return p.fmt.space
 	case '0':
@@ -169,14 +165,11 @@ func (p *pp) Flag(b int) bool {
 	return false
 }
 
-func (p *pp) add(c rune) {
-	p.buf.WriteRune(c)
-}
-
 // Implement Write so we can call Fprintf on a pp (through State), for
 // recursive use in custom verbs.
 func (p *pp) Write(b []byte) (ret int, err error) {
-	return p.buf.Write(b)
+	p.buf.Write(b)
+	return len(b), nil
 }
 
 // These routines end in 'f' and take a format string.
@@ -219,7 +212,7 @@ func Errorf(format string, a ...interface{}) error {
 // It returns the number of bytes written and any write error encountered.
 func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
 	p := newPrinter()
-	p.doPrint(a, false, false)
+	p.doPrint(a)
 	n, err = w.Write(p.buf)
 	p.free()
 	return
@@ -236,7 +229,7 @@ func Print(a ...interface{}) (n int, err error) {
 // Spaces are added between operands when neither is a string.
 func Sprint(a ...interface{}) string {
 	p := newPrinter()
-	p.doPrint(a, false, false)
+	p.doPrint(a)
 	s := string(p.buf)
 	p.free()
 	return s
@@ -251,7 +244,7 @@ func Sprint(a ...interface{}) string {
 // It returns the number of bytes written and any write error encountered.
 func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
 	p := newPrinter()
-	p.doPrint(a, true, true)
+	p.doPrintln(a)
 	n, err = w.Write(p.buf)
 	p.free()
 	return
@@ -268,7 +261,7 @@ func Println(a ...interface{}) (n int, err error) {
 // Spaces are always added between operands and a newline is appended.
 func Sprintln(a ...interface{}) string {
 	p := newPrinter()
-	p.doPrint(a, true, true)
+	p.doPrintln(a)
 	s := string(p.buf)
 	p.free()
 	return s
@@ -309,7 +302,7 @@ func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
 
 func (p *pp) unknownType(v reflect.Value) {
 	if !v.IsValid() {
-		p.buf.Write(nilAngleBytes)
+		p.buf.WriteString(nilAngleString)
 		return
 	}
 	p.buf.WriteByte('?')
@@ -319,23 +312,22 @@ func (p *pp) unknownType(v reflect.Value) {
 
 func (p *pp) badVerb(verb rune) {
 	p.erroring = true
-	p.add('%')
-	p.add('!')
-	p.add(verb)
-	p.add('(')
+	p.buf.WriteString(percentBangString)
+	p.buf.WriteRune(verb)
+	p.buf.WriteByte('(')
 	switch {
 	case p.arg != nil:
 		p.buf.WriteString(reflect.TypeOf(p.arg).String())
-		p.add('=')
-		p.printArg(p.arg, 'v', 0)
+		p.buf.WriteByte('=')
+		p.printArg(p.arg, 'v')
 	case p.value.IsValid():
 		p.buf.WriteString(p.value.Type().String())
-		p.add('=')
+		p.buf.WriteByte('=')
 		p.printValue(p.value, 'v', 0)
 	default:
-		p.buf.Write(nilAngleBytes)
+		p.buf.WriteString(nilAngleString)
 	}
-	p.add(')')
+	p.buf.WriteByte(')')
 	p.erroring = false
 }
 
@@ -348,162 +340,82 @@ func (p *pp) fmtBool(v bool, verb rune) {
 	}
 }
 
-// fmtC formats a rune for the 'c' format.
-func (p *pp) fmtC(c int64) {
-	r := rune(c) // Check for overflow.
-	if int64(r) != c {
-		r = utf8.RuneError
-	}
-	w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], r)
-	p.fmt.pad(p.runeBuf[0:w])
-}
-
-func (p *pp) fmtInt64(v int64, verb rune) {
-	switch verb {
-	case 'b':
-		p.fmt.integer(v, 2, signed, ldigits)
-	case 'c':
-		p.fmtC(v)
-	case 'd', 'v':
-		p.fmt.integer(v, 10, signed, ldigits)
-	case 'o':
-		p.fmt.integer(v, 8, signed, ldigits)
-	case 'q':
-		if 0 <= v && v <= utf8.MaxRune {
-			p.fmt.fmt_qc(v)
-		} else {
-			p.badVerb(verb)
-		}
-	case 'x':
-		p.fmt.integer(v, 16, signed, ldigits)
-	case 'U':
-		p.fmtUnicode(v)
-	case 'X':
-		p.fmt.integer(v, 16, signed, udigits)
-	default:
-		p.badVerb(verb)
-	}
-}
-
 // fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
 // not, as requested, by temporarily setting the sharp flag.
 func (p *pp) fmt0x64(v uint64, leading0x bool) {
 	sharp := p.fmt.sharp
 	p.fmt.sharp = leading0x
-	p.fmt.integer(int64(v), 16, unsigned, ldigits)
+	p.fmt.fmt_integer(v, 16, unsigned, ldigits)
 	p.fmt.sharp = sharp
 }
 
-// fmtUnicode formats a uint64 in U+1234 form by
-// temporarily turning on the unicode flag and tweaking the precision.
-func (p *pp) fmtUnicode(v int64) {
-	precPresent := p.fmt.precPresent
-	sharp := p.fmt.sharp
-	p.fmt.sharp = false
-	prec := p.fmt.prec
-	if !precPresent {
-		// If prec is already set, leave it alone; otherwise 4 is minimum.
-		p.fmt.prec = 4
-		p.fmt.precPresent = true
-	}
-	p.fmt.unicode = true // turn on U+
-	p.fmt.uniQuote = sharp
-	p.fmt.integer(int64(v), 16, unsigned, udigits)
-	p.fmt.unicode = false
-	p.fmt.uniQuote = false
-	p.fmt.prec = prec
-	p.fmt.precPresent = precPresent
-	p.fmt.sharp = sharp
-}
-
-func (p *pp) fmtUint64(v uint64, verb rune) {
+// fmtInteger formats a signed or unsigned integer.
+func (p *pp) fmtInteger(v uint64, isSigned bool, verb rune) {
 	switch verb {
-	case 'b':
-		p.fmt.integer(int64(v), 2, unsigned, ldigits)
-	case 'c':
-		p.fmtC(int64(v))
-	case 'd':
-		p.fmt.integer(int64(v), 10, unsigned, ldigits)
 	case 'v':
-		if p.fmt.sharpV {
+		if p.fmt.sharpV && !isSigned {
 			p.fmt0x64(v, true)
 		} else {
-			p.fmt.integer(int64(v), 10, unsigned, ldigits)
+			p.fmt.fmt_integer(v, 10, isSigned, ldigits)
 		}
+	case 'd':
+		p.fmt.fmt_integer(v, 10, isSigned, ldigits)
+	case 'b':
+		p.fmt.fmt_integer(v, 2, isSigned, ldigits)
 	case 'o':
-		p.fmt.integer(int64(v), 8, unsigned, ldigits)
+		p.fmt.fmt_integer(v, 8, isSigned, ldigits)
+	case 'x':
+		p.fmt.fmt_integer(v, 16, isSigned, ldigits)
+	case 'X':
+		p.fmt.fmt_integer(v, 16, isSigned, udigits)
+	case 'c':
+		p.fmt.fmt_c(v)
 	case 'q':
-		if 0 <= v && v <= utf8.MaxRune {
-			p.fmt.fmt_qc(int64(v))
+		if v <= utf8.MaxRune {
+			p.fmt.fmt_qc(v)
 		} else {
 			p.badVerb(verb)
 		}
-	case 'x':
-		p.fmt.integer(int64(v), 16, unsigned, ldigits)
-	case 'X':
-		p.fmt.integer(int64(v), 16, unsigned, udigits)
 	case 'U':
-		p.fmtUnicode(int64(v))
+		p.fmt.fmt_unicode(v)
 	default:
 		p.badVerb(verb)
 	}
 }
 
-func (p *pp) fmtFloat32(v float32, verb rune) {
+// fmtFloat formats a float. The default precision for each verb
+// is specified as last argument in the call to fmt_float.
+func (p *pp) fmtFloat(v float64, size int, verb rune) {
 	switch verb {
-	case 'b':
-		p.fmt.fmt_fb32(v)
-	case 'e':
-		p.fmt.fmt_e32(v)
-	case 'E':
-		p.fmt.fmt_E32(v)
-	case 'f', 'F':
-		p.fmt.fmt_f32(v)
-	case 'g', 'v':
-		p.fmt.fmt_g32(v)
-	case 'G':
-		p.fmt.fmt_G32(v)
-	default:
-		p.badVerb(verb)
-	}
-}
-
-func (p *pp) fmtFloat64(v float64, verb rune) {
-	switch verb {
-	case 'b':
-		p.fmt.fmt_fb64(v)
-	case 'e':
-		p.fmt.fmt_e64(v)
-	case 'E':
-		p.fmt.fmt_E64(v)
-	case 'f', 'F':
-		p.fmt.fmt_f64(v)
-	case 'g', 'v':
-		p.fmt.fmt_g64(v)
-	case 'G':
-		p.fmt.fmt_G64(v)
-	default:
-		p.badVerb(verb)
-	}
-}
-
-func (p *pp) fmtComplex64(v complex64, verb rune) {
-	switch verb {
-	case 'b', 'e', 'E', 'f', 'F', 'g', 'G':
-		p.fmt.fmt_c64(v, verb)
 	case 'v':
-		p.fmt.fmt_c64(v, 'g')
+		p.fmt.fmt_float(v, size, 'g', -1)
+	case 'b', 'g', 'G':
+		p.fmt.fmt_float(v, size, verb, -1)
+	case 'f', 'e', 'E':
+		p.fmt.fmt_float(v, size, verb, 6)
+	case 'F':
+		p.fmt.fmt_float(v, size, 'f', 6)
 	default:
 		p.badVerb(verb)
 	}
 }
 
-func (p *pp) fmtComplex128(v complex128, verb rune) {
+// fmtComplex formats a complex number v with
+// r = real(v) and j = imag(v) as (r+ji) using
+// fmtFloat for r and j formatting.
+func (p *pp) fmtComplex(v complex128, size int, verb rune) {
+	// Make sure any unsupported verbs are found before the
+	// calls to fmtFloat to not generate an incorrect error string.
 	switch verb {
-	case 'b', 'e', 'E', 'f', 'F', 'g', 'G':
-		p.fmt.fmt_c128(v, verb)
-	case 'v':
-		p.fmt.fmt_c128(v, 'g')
+	case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E':
+		oldPlus := p.fmt.plus
+		p.buf.WriteByte('(')
+		p.fmtFloat(real(v), size/2, verb)
+		// Imaginary part always has a sign.
+		p.fmt.plus = true
+		p.fmtFloat(imag(v), size/2, verb)
+		p.buf.WriteString("i)")
+		p.fmt.plus = oldPlus
 	default:
 		p.badVerb(verb)
 	}
@@ -530,45 +442,33 @@ func (p *pp) fmtString(v string, verb rune) {
 	}
 }
 
-func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
-	if verb == 'v' || verb == 'd' {
+func (p *pp) fmtBytes(v []byte, verb rune, typeString string) {
+	switch verb {
+	case 'v', 'd':
 		if p.fmt.sharpV {
+			p.buf.WriteString(typeString)
 			if v == nil {
-				if typ == nil {
-					p.buf.WriteString("[]byte(nil)")
-				} else {
-					p.buf.WriteString(typ.String())
-					p.buf.Write(nilParenBytes)
-				}
+				p.buf.WriteString(nilParenString)
 				return
 			}
-			if typ == nil {
-				p.buf.Write(bytesBytes)
-			} else {
-				p.buf.WriteString(typ.String())
-				p.buf.WriteByte('{')
+			p.buf.WriteByte('{')
+			for i, c := range v {
+				if i > 0 {
+					p.buf.WriteString(commaSpaceString)
+				}
+				p.fmt0x64(uint64(c), true)
 			}
+			p.buf.WriteByte('}')
 		} else {
 			p.buf.WriteByte('[')
-		}
-		for i, c := range v {
-			if i > 0 {
-				if p.fmt.sharpV {
-					p.buf.Write(commaSpaceBytes)
-				} else {
+			for i, c := range v {
+				if i > 0 {
 					p.buf.WriteByte(' ')
 				}
+				p.fmt.fmt_integer(uint64(c), 10, unsigned, ldigits)
 			}
-			p.printArg(c, 'v', depth+1)
-		}
-		if p.fmt.sharpV {
-			p.buf.WriteByte('}')
-		} else {
 			p.buf.WriteByte(']')
 		}
-		return
-	}
-	switch verb {
 	case 's':
 		p.fmt.fmt_s(string(v))
 	case 'x':
@@ -578,23 +478,11 @@ func (p *pp) fmtBytes(v []byte, verb rune, typ reflect.Type, depth int) {
 	case 'q':
 		p.fmt.fmt_q(string(v))
 	default:
-		p.badVerb(verb)
+		p.printValue(reflect.ValueOf(v), verb, 0)
 	}
 }
 
 func (p *pp) fmtPointer(value reflect.Value, verb rune) {
-	use0x64 := true
-	switch verb {
-	case 'p', 'v':
-		// ok
-	case 'b', 'd', 'o', 'x', 'X':
-		use0x64 = false
-		// ok
-	default:
-		p.badVerb(verb)
-		return
-	}
-
 	var u uintptr
 	switch value.Kind() {
 	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
@@ -604,40 +492,41 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune) {
 		return
 	}
 
-	if p.fmt.sharpV {
-		p.add('(')
-		p.buf.WriteString(value.Type().String())
-		p.add(')')
-		p.add('(')
-		if u == 0 {
-			p.buf.Write(nilBytes)
-		} else {
-			p.fmt0x64(uint64(u), true)
-		}
-		p.add(')')
-	} else if verb == 'v' && u == 0 {
-		p.buf.Write(nilAngleBytes)
-	} else {
-		if use0x64 {
-			p.fmt0x64(uint64(u), !p.fmt.sharp)
+	switch verb {
+	case 'v':
+		if p.fmt.sharpV {
+			p.buf.WriteByte('(')
+			p.buf.WriteString(value.Type().String())
+			p.buf.WriteString(")(")
+			if u == 0 {
+				p.buf.WriteString(nilString)
+			} else {
+				p.fmt0x64(uint64(u), true)
+			}
+			p.buf.WriteByte(')')
 		} else {
-			p.fmtUint64(uint64(u), verb)
+			if u == 0 {
+				p.fmt.padString(nilAngleString)
+			} else {
+				p.fmt0x64(uint64(u), !p.fmt.sharp)
+			}
 		}
+	case 'p':
+		p.fmt0x64(uint64(u), !p.fmt.sharp)
+	case 'b', 'o', 'd', 'x', 'X':
+		p.fmtInteger(uint64(u), unsigned, verb)
+	default:
+		p.badVerb(verb)
 	}
 }
 
-var (
-	intBits     = reflect.TypeOf(0).Bits()
-	uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
-)
-
 func (p *pp) catchPanic(arg interface{}, verb rune) {
 	if err := recover(); err != nil {
 		// If it's a nil pointer, just say "<nil>". The likeliest causes are a
 		// Stringer that fails to guard against nil or a nil pointer for a
 		// value receiver, and in either case, "<nil>" is a nice result.
 		if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() {
-			p.buf.Write(nilAngleBytes)
+			p.buf.WriteString(nilAngleString)
 			return
 		}
 		// Otherwise print a concise panic message. Most of the time the panic
@@ -647,52 +536,23 @@ func (p *pp) catchPanic(arg interface{}, verb rune) {
 			panic(err)
 		}
 		p.fmt.clearflags() // We are done, and for this output we want default behavior.
-		p.buf.Write(percentBangBytes)
-		p.add(verb)
-		p.buf.Write(panicBytes)
+		p.buf.WriteString(percentBangString)
+		p.buf.WriteRune(verb)
+		p.buf.WriteString(panicString)
 		p.panicking = true
-		p.printArg(err, 'v', 0)
+		p.printArg(err, 'v')
 		p.panicking = false
 		p.buf.WriteByte(')')
 	}
 }
 
-// clearSpecialFlags pushes %#v back into the regular flags and returns their old state.
-func (p *pp) clearSpecialFlags() (plusV, sharpV bool) {
-	plusV = p.fmt.plusV
-	if plusV {
-		p.fmt.plus = true
-		p.fmt.plusV = false
-	}
-	sharpV = p.fmt.sharpV
-	if sharpV {
-		p.fmt.sharp = true
-		p.fmt.sharpV = false
-	}
-	return
-}
-
-// restoreSpecialFlags, whose argument should be a call to clearSpecialFlags,
-// restores the setting of the plusV and sharpV flags.
-func (p *pp) restoreSpecialFlags(plusV, sharpV bool) {
-	if plusV {
-		p.fmt.plus = false
-		p.fmt.plusV = true
-	}
-	if sharpV {
-		p.fmt.sharp = false
-		p.fmt.sharpV = true
-	}
-}
-
-func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
+func (p *pp) handleMethods(verb rune) (handled bool) {
 	if p.erroring {
 		return
 	}
 	// Is it a Formatter?
 	if formatter, ok := p.arg.(Formatter); ok {
 		handled = true
-		defer p.restoreSpecialFlags(p.clearSpecialFlags())
 		defer p.catchPanic(p.arg, verb)
 		formatter.Format(p, verb)
 		return
@@ -721,13 +581,13 @@ func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
 			case error:
 				handled = true
 				defer p.catchPanic(p.arg, verb)
-				p.printArg(v.Error(), verb, depth)
+				p.fmtString(v.Error(), verb)
 				return
 
 			case Stringer:
 				handled = true
 				defer p.catchPanic(p.arg, verb)
-				p.printArg(v.String(), verb, depth)
+				p.fmtString(v.String(), verb)
 				return
 			}
 		}
@@ -735,28 +595,29 @@ func (p *pp) handleMethods(verb rune, depth int) (handled bool) {
 	return false
 }
 
-func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
+func (p *pp) printArg(arg interface{}, verb rune) {
 	p.arg = arg
 	p.value = reflect.Value{}
 
 	if arg == nil {
-		if verb == 'T' || verb == 'v' {
-			p.fmt.pad(nilAngleBytes)
-		} else {
+		switch verb {
+		case 'T', 'v':
+			p.fmt.padString(nilAngleString)
+		default:
 			p.badVerb(verb)
 		}
-		return false
+		return
 	}
 
 	// Special processing considerations.
 	// %T (the value's type) and %p (its address) are special; we always do them first.
 	switch verb {
 	case 'T':
-		p.printArg(reflect.TypeOf(arg).String(), 's', 0)
-		return false
+		p.fmt.fmt_s(reflect.TypeOf(arg).String())
+		return
 	case 'p':
-		p.fmtPointer(reflect.ValueOf(arg), verb)
-		return false
+		p.fmtPointer(reflect.ValueOf(arg), 'p')
+		return
 	}
 
 	// Some types can be done without reflection.
@@ -764,137 +625,110 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
 	case bool:
 		p.fmtBool(f, verb)
 	case float32:
-		p.fmtFloat32(f, verb)
+		p.fmtFloat(float64(f), 32, verb)
 	case float64:
-		p.fmtFloat64(f, verb)
+		p.fmtFloat(f, 64, verb)
 	case complex64:
-		p.fmtComplex64(f, verb)
+		p.fmtComplex(complex128(f), 64, verb)
 	case complex128:
-		p.fmtComplex128(f, verb)
+		p.fmtComplex(f, 128, verb)
 	case int:
-		p.fmtInt64(int64(f), verb)
+		p.fmtInteger(uint64(f), signed, verb)
 	case int8:
-		p.fmtInt64(int64(f), verb)
+		p.fmtInteger(uint64(f), signed, verb)
 	case int16:
-		p.fmtInt64(int64(f), verb)
+		p.fmtInteger(uint64(f), signed, verb)
 	case int32:
-		p.fmtInt64(int64(f), verb)
+		p.fmtInteger(uint64(f), signed, verb)
 	case int64:
-		p.fmtInt64(f, verb)
+		p.fmtInteger(uint64(f), signed, verb)
 	case uint:
-		p.fmtUint64(uint64(f), verb)
+		p.fmtInteger(uint64(f), unsigned, verb)
 	case uint8:
-		p.fmtUint64(uint64(f), verb)
+		p.fmtInteger(uint64(f), unsigned, verb)
 	case uint16:
-		p.fmtUint64(uint64(f), verb)
+		p.fmtInteger(uint64(f), unsigned, verb)
 	case uint32:
-		p.fmtUint64(uint64(f), verb)
+		p.fmtInteger(uint64(f), unsigned, verb)
 	case uint64:
-		p.fmtUint64(f, verb)
+		p.fmtInteger(f, unsigned, verb)
 	case uintptr:
-		p.fmtUint64(uint64(f), verb)
+		p.fmtInteger(uint64(f), unsigned, verb)
 	case string:
 		p.fmtString(f, verb)
-		wasString = verb == 's' || verb == 'v'
 	case []byte:
-		p.fmtBytes(f, verb, nil, depth)
-		wasString = verb == 's'
+		p.fmtBytes(f, verb, "[]byte")
 	case reflect.Value:
-		return p.printReflectValue(f, verb, depth)
+		p.printValue(f, verb, 0)
 	default:
 		// If the type is not simple, it might have methods.
-		if handled := p.handleMethods(verb, depth); handled {
-			return false
+		if !p.handleMethods(verb) {
+			// Need to use reflection, since the type had no
+			// interface methods that could be used for formatting.
+			p.printValue(reflect.ValueOf(f), verb, 0)
 		}
-		// Need to use reflection
-		return p.printReflectValue(reflect.ValueOf(arg), verb, depth)
 	}
-	p.arg = nil
-	return
 }
 
-// printValue is like printArg but starts with a reflect value, not an interface{} value.
-func (p *pp) printValue(value reflect.Value, verb rune, depth int) (wasString bool) {
-	if !value.IsValid() {
-		if verb == 'T' || verb == 'v' {
-			p.buf.Write(nilAngleBytes)
-		} else {
-			p.badVerb(verb)
-		}
-		return false
-	}
-
-	// Special processing considerations.
-	// %T (the value's type) and %p (its address) are special; we always do them first.
-	switch verb {
-	case 'T':
-		p.printArg(value.Type().String(), 's', 0)
-		return false
-	case 'p':
-		p.fmtPointer(value, verb)
-		return false
-	}
+var byteType = reflect.TypeOf(byte(0))
 
-	// Handle values with special methods.
-	// Call always, even when arg == nil, because handleMethods clears p.fmt.plus for us.
-	p.arg = nil // Make sure it's cleared, for safety.
-	if value.CanInterface() {
+// printValue is similar to printArg but starts with a reflect value, not an interface{} value.
+// It does not handle 'p' and 'T' verbs because these should have been already handled by printArg.
+func (p *pp) printValue(value reflect.Value, verb rune, depth int) {
+	// Handle values with special methods if not already handled by printArg (depth == 0).
+	if depth > 0 && value.IsValid() && value.CanInterface() {
 		p.arg = value.Interface()
+		if p.handleMethods(verb) {
+			return
+		}
 	}
-	if handled := p.handleMethods(verb, depth); handled {
-		return false
-	}
-
-	return p.printReflectValue(value, verb, depth)
-}
-
-var byteType = reflect.TypeOf(byte(0))
-
-// printReflectValue is the fallback for both printArg and printValue.
-// It uses reflect to print the value.
-func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasString bool) {
-	oldValue := p.value
+	p.arg = nil
 	p.value = value
-BigSwitch:
-	switch f := value; f.Kind() {
+
+	switch f := value; value.Kind() {
 	case reflect.Invalid:
-		p.buf.WriteString("<invalid reflect.Value>")
+		if depth == 0 {
+			p.buf.WriteString(invReflectString)
+		} else {
+			switch verb {
+			case 'v':
+				p.buf.WriteString(nilAngleString)
+			default:
+				p.badVerb(verb)
+			}
+		}
 	case reflect.Bool:
 		p.fmtBool(f.Bool(), verb)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		p.fmtInt64(f.Int(), verb)
+		p.fmtInteger(uint64(f.Int()), signed, verb)
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
-		p.fmtUint64(f.Uint(), verb)
-	case reflect.Float32, reflect.Float64:
-		if f.Type().Size() == 4 {
-			p.fmtFloat32(float32(f.Float()), verb)
-		} else {
-			p.fmtFloat64(f.Float(), verb)
-		}
-	case reflect.Complex64, reflect.Complex128:
-		if f.Type().Size() == 8 {
-			p.fmtComplex64(complex64(f.Complex()), verb)
-		} else {
-			p.fmtComplex128(f.Complex(), verb)
-		}
+		p.fmtInteger(f.Uint(), unsigned, verb)
+	case reflect.Float32:
+		p.fmtFloat(f.Float(), 32, verb)
+	case reflect.Float64:
+		p.fmtFloat(f.Float(), 64, verb)
+	case reflect.Complex64:
+		p.fmtComplex(f.Complex(), 64, verb)
+	case reflect.Complex128:
+		p.fmtComplex(f.Complex(), 128, verb)
 	case reflect.String:
 		p.fmtString(f.String(), verb)
 	case reflect.Map:
 		if p.fmt.sharpV {
 			p.buf.WriteString(f.Type().String())
 			if f.IsNil() {
-				p.buf.WriteString("(nil)")
-				break
+				p.buf.WriteString(nilParenString)
+				return
 			}
 			p.buf.WriteByte('{')
 		} else {
-			p.buf.Write(mapBytes)
+			p.buf.WriteString(mapString)
 		}
 		keys := f.MapKeys()
 		for i, key := range keys {
 			if i > 0 {
 				if p.fmt.sharpV {
-					p.buf.Write(commaSpaceBytes)
+					p.buf.WriteString(commaSpaceString)
 				} else {
 					p.buf.WriteByte(' ')
 				}
@@ -910,26 +744,24 @@ BigSwitch:
 		}
 	case reflect.Struct:
 		if p.fmt.sharpV {
-			p.buf.WriteString(value.Type().String())
+			p.buf.WriteString(f.Type().String())
 		}
-		p.add('{')
-		v := f
-		t := v.Type()
-		for i := 0; i < v.NumField(); i++ {
+		p.buf.WriteByte('{')
+		for i := 0; i < f.NumField(); i++ {
 			if i > 0 {
 				if p.fmt.sharpV {
-					p.buf.Write(commaSpaceBytes)
+					p.buf.WriteString(commaSpaceString)
 				} else {
 					p.buf.WriteByte(' ')
 				}
 			}
 			if p.fmt.plusV || p.fmt.sharpV {
-				if f := t.Field(i); f.Name != "" {
-					p.buf.WriteString(f.Name)
+				if name := f.Type().Field(i).Name; name != "" {
+					p.buf.WriteString(name)
 					p.buf.WriteByte(':')
 				}
 			}
-			p.printValue(getField(v, i), verb, depth+1)
+			p.printValue(getField(f, i), verb, depth+1)
 		}
 		p.buf.WriteByte('}')
 	case reflect.Interface:
@@ -937,91 +769,79 @@ BigSwitch:
 		if !value.IsValid() {
 			if p.fmt.sharpV {
 				p.buf.WriteString(f.Type().String())
-				p.buf.Write(nilParenBytes)
+				p.buf.WriteString(nilParenString)
 			} else {
-				p.buf.Write(nilAngleBytes)
+				p.buf.WriteString(nilAngleString)
 			}
 		} else {
-			wasString = p.printValue(value, verb, depth+1)
+			p.printValue(value, verb, depth+1)
 		}
 	case reflect.Array, reflect.Slice:
-		// Byte slices are special:
-		// - Handle []byte (== []uint8) with fmtBytes.
-		// - Handle []T, where T is a named byte type, with fmtBytes only
-		//   for the s, q, an x verbs. For other verbs, T might be a
-		//   Stringer, so we use printValue to print each element.
-		if typ := f.Type(); typ.Elem().Kind() == reflect.Uint8 && (typ.Elem() == byteType || verb == 's' || verb == 'q' || verb == 'x') {
-			var bytes []byte
-			if f.Kind() == reflect.Slice {
-				bytes = f.Bytes()
-			} else if f.CanAddr() {
-				bytes = f.Slice(0, f.Len()).Bytes()
-			} else {
-				// We have an array, but we cannot Slice() a non-addressable array,
-				// so we build a slice by hand. This is a rare case but it would be nice
-				// if reflection could help a little more.
-				bytes = make([]byte, f.Len())
-				for i := range bytes {
-					bytes[i] = byte(f.Index(i).Uint())
+		switch verb {
+		case 's', 'q', 'x', 'X':
+			// Handle byte and uint8 slices and arrays special for the above verbs.
+			t := f.Type()
+			if t.Elem().Kind() == reflect.Uint8 {
+				var bytes []byte
+				if f.Kind() == reflect.Slice {
+					bytes = f.Bytes()
+				} else if f.CanAddr() {
+					bytes = f.Slice(0, f.Len()).Bytes()
+				} else {
+					// We have an array, but we cannot Slice() a non-addressable array,
+					// so we build a slice by hand. This is a rare case but it would be nice
+					// if reflection could help a little more.
+					bytes = make([]byte, f.Len())
+					for i := range bytes {
+						bytes[i] = byte(f.Index(i).Uint())
+					}
 				}
+				p.fmtBytes(bytes, verb, t.String())
+				return
 			}
-			p.fmtBytes(bytes, verb, typ, depth)
-			wasString = verb == 's'
-			break
 		}
 		if p.fmt.sharpV {
-			p.buf.WriteString(value.Type().String())
+			p.buf.WriteString(f.Type().String())
 			if f.Kind() == reflect.Slice && f.IsNil() {
-				p.buf.WriteString("(nil)")
-				break
+				p.buf.WriteString(nilParenString)
+				return
+			} else {
+				p.buf.WriteByte('{')
+				for i := 0; i < f.Len(); i++ {
+					if i > 0 {
+						p.buf.WriteString(commaSpaceString)
+					}
+					p.printValue(f.Index(i), verb, depth+1)
+				}
+				p.buf.WriteByte('}')
 			}
-			p.buf.WriteByte('{')
 		} else {
 			p.buf.WriteByte('[')
-		}
-		for i := 0; i < f.Len(); i++ {
-			if i > 0 {
-				if p.fmt.sharpV {
-					p.buf.Write(commaSpaceBytes)
-				} else {
+			for i := 0; i < f.Len(); i++ {
+				if i > 0 {
 					p.buf.WriteByte(' ')
 				}
+				p.printValue(f.Index(i), verb, depth+1)
 			}
-			p.printValue(f.Index(i), verb, depth+1)
-		}
-		if p.fmt.sharpV {
-			p.buf.WriteByte('}')
-		} else {
 			p.buf.WriteByte(']')
 		}
 	case reflect.Ptr:
-		v := f.Pointer()
 		// pointer to array or slice or struct?  ok at top level
 		// but not embedded (avoid loops)
-		if v != 0 && depth == 0 {
+		if depth == 0 && f.Pointer() != 0 {
 			switch a := f.Elem(); a.Kind() {
-			case reflect.Array, reflect.Slice:
-				p.buf.WriteByte('&')
-				p.printValue(a, verb, depth+1)
-				break BigSwitch
-			case reflect.Struct:
-				p.buf.WriteByte('&')
-				p.printValue(a, verb, depth+1)
-				break BigSwitch
-			case reflect.Map:
+			case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map:
 				p.buf.WriteByte('&')
 				p.printValue(a, verb, depth+1)
-				break BigSwitch
+				return
 			}
 		}
 		fallthrough
 	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
-		p.fmtPointer(value, verb)
+		p.fmtPointer(f, verb)
 	default:
 		p.unknownType(f)
 	}
-	p.value = oldValue
-	return wasString
 }
 
 // intFromArg gets the argNumth element of a. On return, isInt reports whether the argument has integer type.
@@ -1098,11 +918,24 @@ func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum
 	return argNum, i + wid, ok
 }
 
+func (p *pp) badArgNum(verb rune) {
+	p.buf.WriteString(percentBangString)
+	p.buf.WriteRune(verb)
+	p.buf.WriteString(badIndexString)
+}
+
+func (p *pp) missingArg(verb rune) {
+	p.buf.WriteString(percentBangString)
+	p.buf.WriteRune(verb)
+	p.buf.WriteString(missingString)
+}
+
 func (p *pp) doPrintf(format string, a []interface{}) {
 	end := len(format)
 	argNum := 0         // we process one argument per non-trivial format
 	afterIndex := false // previous item in format was an index like [3].
 	p.reordered = false
+formatLoop:
 	for i := 0; i < end; {
 		p.goodArgNum = true
 		lasti := i
@@ -1122,21 +955,40 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 
 		// Do we have flags?
 		p.fmt.clearflags()
-	F:
+	simpleFormat:
 		for ; i < end; i++ {
-			switch format[i] {
+			c := format[i]
+			switch c {
 			case '#':
 				p.fmt.sharp = true
 			case '0':
-				p.fmt.zero = true
+				p.fmt.zero = !p.fmt.minus // Only allow zero padding to the left.
 			case '+':
 				p.fmt.plus = true
 			case '-':
 				p.fmt.minus = true
+				p.fmt.zero = false // Do not pad with zeros to the right.
 			case ' ':
 				p.fmt.space = true
 			default:
-				break F
+				// Fast path for common case of ascii lower case simple verbs
+				// without precision or width or argument indices.
+				if 'a' <= c && c <= 'z' && argNum < len(a) {
+					if c == 'v' {
+						// Go syntax
+						p.fmt.sharpV = p.fmt.sharp
+						p.fmt.sharp = false
+						// Struct-field syntax
+						p.fmt.plusV = p.fmt.plus
+						p.fmt.plus = false
+					}
+					p.printArg(a[argNum], rune(c))
+					argNum++
+					i++
+					continue formatLoop
+				}
+				// Format is more complex than simple flags and a verb or is malformed.
+				break simpleFormat
 			}
 		}
 
@@ -1149,7 +1001,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 			p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
 
 			if !p.fmt.widPresent {
-				p.buf.Write(badWidthBytes)
+				p.buf.WriteString(badWidthString)
 			}
 
 			// We have a negative width, so take its value and ensure
@@ -1157,6 +1009,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 			if p.fmt.wid < 0 {
 				p.fmt.wid = -p.fmt.wid
 				p.fmt.minus = true
+				p.fmt.zero = false // Do not pad with zeros to the right.
 			}
 			afterIndex = false
 		} else {
@@ -1182,7 +1035,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 					p.fmt.precPresent = false
 				}
 				if !p.fmt.precPresent {
-					p.buf.Write(badPrecBytes)
+					p.buf.WriteString(badPrecString)
 				}
 				afterIndex = false
 			} else {
@@ -1199,80 +1052,77 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 		}
 
 		if i >= end {
-			p.buf.Write(noVerbBytes)
-			continue
+			p.buf.WriteString(noVerbString)
+			break
 		}
-		c, w := utf8.DecodeRuneInString(format[i:])
+
+		verb, w := utf8.DecodeRuneInString(format[i:])
 		i += w
-		// percent is special - absorbs no operand
-		if c == '%' {
-			p.buf.WriteByte('%') // We ignore width and prec.
-			continue
-		}
-		if !p.goodArgNum {
-			p.buf.Write(percentBangBytes)
-			p.add(c)
-			p.buf.Write(badIndexBytes)
-			continue
-		} else if argNum >= len(a) { // out of operands
-			p.buf.Write(percentBangBytes)
-			p.add(c)
-			p.buf.Write(missingBytes)
-			continue
-		}
-		arg := a[argNum]
-		argNum++
-
-		if c == 'v' {
-			if p.fmt.sharp {
-				// Go syntax. Set the flag in the fmt and clear the sharp flag.
-				p.fmt.sharp = false
-				p.fmt.sharpV = true
-			}
-			if p.fmt.plus {
-				// Struct-field syntax. Set the flag in the fmt and clear the plus flag.
-				p.fmt.plus = false
-				p.fmt.plusV = true
-			}
+
+		switch {
+		case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
+			p.buf.WriteByte('%')
+		case !p.goodArgNum:
+			p.badArgNum(verb)
+		case argNum >= len(a): // No argument left over to print for the current verb.
+			p.missingArg(verb)
+		case verb == 'v':
+			// Go syntax
+			p.fmt.sharpV = p.fmt.sharp
+			p.fmt.sharp = false
+			// Struct-field syntax
+			p.fmt.plusV = p.fmt.plus
+			p.fmt.plus = false
+			fallthrough
+		default:
+			p.printArg(a[argNum], verb)
+			argNum++
 		}
-		p.printArg(arg, c, 0)
 	}
 
 	// Check for extra arguments unless the call accessed the arguments
 	// out of order, in which case it's too expensive to detect if they've all
 	// been used and arguably OK if they're not.
 	if !p.reordered && argNum < len(a) {
-		p.buf.Write(extraBytes)
-		for ; argNum < len(a); argNum++ {
-			arg := a[argNum]
-			if arg != nil {
+		p.fmt.clearflags()
+		p.buf.WriteString(extraString)
+		for i, arg := range a[argNum:] {
+			if i > 0 {
+				p.buf.WriteString(commaSpaceString)
+			}
+			if arg == nil {
+				p.buf.WriteString(nilAngleString)
+			} else {
 				p.buf.WriteString(reflect.TypeOf(arg).String())
 				p.buf.WriteByte('=')
-			}
-			p.printArg(arg, 'v', 0)
-			if argNum+1 < len(a) {
-				p.buf.Write(commaSpaceBytes)
+				p.printArg(arg, 'v')
 			}
 		}
 		p.buf.WriteByte(')')
 	}
 }
 
-func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
+func (p *pp) doPrint(a []interface{}) {
 	prevString := false
-	for argNum := 0; argNum < len(a); argNum++ {
-		p.fmt.clearflags()
-		// always add spaces if we're doing Println
-		arg := a[argNum]
-		if argNum > 0 {
-			isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
-			if addspace || !isString && !prevString {
-				p.buf.WriteByte(' ')
-			}
+	for argNum, arg := range a {
+		isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
+		// Add a space between two non-string arguments.
+		if argNum > 0 && !isString && !prevString {
+			p.buf.WriteByte(' ')
 		}
-		prevString = p.printArg(arg, 'v', 0)
+		p.printArg(arg, 'v')
+		prevString = isString
 	}
-	if addnewline {
-		p.buf.WriteByte('\n')
+}
+
+// doPrintln is like doPrint but always adds a space between arguments
+// and a newline after the last argument.
+func (p *pp) doPrintln(a []interface{}) {
+	for argNum, arg := range a {
+		if argNum > 0 {
+			p.buf.WriteByte(' ')
+		}
+		p.printArg(arg, 'v')
 	}
+	p.buf.WriteByte('\n')
 }
diff --git a/src/fmt/scan.go b/src/fmt/scan.go
index 4618ed4..08b0bf9 100644
--- a/src/fmt/scan.go
+++ b/src/fmt/scan.go
@@ -15,14 +15,6 @@ import (
 	"unicode/utf8"
 )
 
-// runeUnreader is the interface to something that can unread runes.
-// If the object provided to Scan does not satisfy this interface,
-// a local buffer will be used to back up the input, but its contents
-// will be lost when Scan returns.
-type runeUnreader interface {
-	UnreadRune() error
-}
-
 // ScanState represents the scanner state passed to custom scanners.
 // Scanners may do rune-at-a-time scanning or ask the ScanState
 // to discover the next space-delimited token.
@@ -41,7 +33,7 @@ type ScanState interface {
 	// 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 appropriately for the operation being
+	// 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
@@ -58,15 +50,15 @@ type ScanState interface {
 
 // Scanner is implemented by any value that has a Scan method, which scans
 // the input for the representation of a value and stores the result in the
-// receiver, which must be a pointer to be useful.  The Scan method is called
+// receiver, which must be a pointer to be useful. The Scan method is called
 // for any argument to Scan, Scanf, or Scanln that implements it.
 type Scanner interface {
 	Scan(state ScanState, verb rune) error
 }
 
 // Scan scans text read from standard input, storing successive
-// space-separated values into successive arguments.  Newlines count
-// as space.  It returns the number of items successfully scanned.
+// space-separated values into successive arguments. Newlines count
+// as space. It returns the number of items successfully scanned.
 // If that is less than the number of arguments, err will report why.
 func Scan(a ...interface{}) (n int, err error) {
 	return Fscan(os.Stdin, a...)
@@ -80,7 +72,7 @@ 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.
+// 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
@@ -101,8 +93,8 @@ func (r *stringReader) Read(b []byte) (n int, err error) {
 }
 
 // Sscan scans the argument string, storing successive space-separated
-// values into successive arguments.  Newlines count as space.  It
-// returns the number of items successfully scanned.  If that is less
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
 // than the number of arguments, err will report why.
 func Sscan(str string, a ...interface{}) (n int, err error) {
 	return Fscan((*stringReader)(&str), a...)
@@ -115,7 +107,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
+// 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) {
@@ -123,8 +115,8 @@ func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
 }
 
 // Fscan scans text read from r, storing successive space-separated
-// values into successive arguments.  Newlines count as space.  It
-// returns the number of items successfully scanned.  If that is less
+// values into successive arguments. Newlines count as space. It
+// returns the number of items successfully scanned. If that is less
 // than the number of arguments, err will report why.
 func Fscan(r io.Reader, a ...interface{}) (n int, err error) {
 	s, old := newScanState(r, true, false)
@@ -143,7 +135,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
+// 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) {
@@ -163,12 +155,10 @@ const eof = -1
 
 // ss is the internal implementation of ScanState.
 type ss struct {
-	rr       io.RuneReader // where to read input
-	buf      buffer        // token accumulator
-	peekRune rune          // one-rune lookahead
-	prevRune rune          // last rune returned by ReadRune
-	count    int           // runes consumed so far.
-	atEOF    bool          // already read EOF
+	rs    io.RuneScanner // where to read input
+	buf   buffer         // token accumulator
+	count int            // runes consumed so far.
+	atEOF bool           // already read EOF
 	ssave
 }
 
@@ -191,23 +181,17 @@ func (s *ss) Read(buf []byte) (n int, err error) {
 }
 
 func (s *ss) ReadRune() (r rune, size int, err error) {
-	if s.peekRune >= 0 {
-		s.count++
-		r = s.peekRune
-		size = utf8.RuneLen(r)
-		s.prevRune = r
-		s.peekRune = -1
-		return
-	}
-	if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.argLimit {
+	if s.atEOF || s.count >= s.argLimit {
 		err = io.EOF
 		return
 	}
 
-	r, size, err = s.rr.ReadRune()
+	r, size, err = s.rs.ReadRune()
 	if err == nil {
 		s.count++
-		s.prevRune = r
+		if s.nlIsEnd && r == '\n' {
+			s.atEOF = true
+		}
 	} else if err == io.EOF {
 		s.atEOF = true
 	}
@@ -246,12 +230,8 @@ func (s *ss) mustReadRune() (r rune) {
 }
 
 func (s *ss) UnreadRune() error {
-	if u, ok := s.rr.(runeUnreader); ok {
-		u.UnreadRune()
-	} else {
-		s.peekRune = s.prevRune
-	}
-	s.prevRune = -1
+	s.rs.UnreadRune()
+	s.atEOF = false
 	s.count--
 	return nil
 }
@@ -326,13 +306,14 @@ func (s *ss) SkipSpace() {
 }
 
 // readRune is a structure to enable reading UTF-8 encoded code points
-// from an io.Reader.  It is used if the Reader given to the scanner does
-// not already implement io.RuneReader.
+// from an io.Reader. It is used if the Reader given to the scanner does
+// not already implement io.RuneScanner.
 type readRune struct {
-	reader  io.Reader
-	buf     [utf8.UTFMax]byte // used only inside ReadRune
-	pending int               // number of bytes in pendBuf; only >0 for bad UTF-8
-	pendBuf [utf8.UTFMax]byte // bytes left over
+	reader   io.Reader
+	buf      [utf8.UTFMax]byte // used only inside ReadRune
+	pending  int               // number of bytes in pendBuf; only >0 for bad UTF-8
+	pendBuf  [utf8.UTFMax]byte // bytes left over
+	peekRune rune              // if >=0 next rune; when <0 is ^(previous Rune)
 }
 
 // readByte returns the next byte from the input, which may be
@@ -344,33 +325,35 @@ func (r *readRune) readByte() (b byte, err error) {
 		r.pending--
 		return
 	}
-	n, err := io.ReadFull(r.reader, r.pendBuf[0:1])
-	if n != 1 {
-		return 0, err
+	_, err = r.reader.Read(r.pendBuf[:1])
+	if err != nil {
+		return
 	}
 	return r.pendBuf[0], err
 }
 
-// unread saves the bytes for the next read.
-func (r *readRune) unread(buf []byte) {
-	copy(r.pendBuf[r.pending:], buf)
-	r.pending += len(buf)
-}
-
 // ReadRune returns the next UTF-8 encoded code point from the
 // io.Reader inside r.
 func (r *readRune) ReadRune() (rr rune, size int, err error) {
+	if r.peekRune >= 0 {
+		rr = r.peekRune
+		r.peekRune = ^r.peekRune
+		size = utf8.RuneLen(rr)
+		return
+	}
 	r.buf[0], err = r.readByte()
 	if err != nil {
-		return 0, 0, err
+		return
 	}
 	if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
 		rr = rune(r.buf[0])
 		size = 1 // Known to be 1.
+		// Flip the bits of the rune so it's available to UnreadRune.
+		r.peekRune = ^rr
 		return
 	}
 	var n int
-	for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
+	for n = 1; !utf8.FullRune(r.buf[:n]); n++ {
 		r.buf[n], err = r.readByte()
 		if err != nil {
 			if err == io.EOF {
@@ -380,13 +363,25 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) {
 			return
 		}
 	}
-	rr, size = utf8.DecodeRune(r.buf[0:n])
-	if size < n { // an error
-		r.unread(r.buf[size:n])
+	rr, size = utf8.DecodeRune(r.buf[:n])
+	if size < n { // an error, save the bytes for the next read
+		copy(r.pendBuf[r.pending:], r.buf[size:n])
+		r.pending += n - size
 	}
+	// Flip the bits of the rune so it's available to UnreadRune.
+	r.peekRune = ^rr
 	return
 }
 
+func (r *readRune) UnreadRune() error {
+	if r.peekRune >= 0 {
+		return errors.New("fmt: scanning called UnreadRune with no rune available")
+	}
+	// Reverse bit flip of previously read rune to obtain valid >=0 state.
+	r.peekRune = ^r.peekRune
+	return nil
+}
+
 var ssFree = sync.Pool{
 	New: func() interface{} { return new(ss) },
 }
@@ -394,15 +389,13 @@ 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) {
 	s = ssFree.Get().(*ss)
-	if rr, ok := r.(io.RuneReader); ok {
-		s.rr = rr
+	if rs, ok := r.(io.RuneScanner); ok {
+		s.rs = rs
 	} else {
-		s.rr = &readRune{reader: r}
+		s.rs = &readRune{reader: r, peekRune: -1}
 	}
 	s.nlIsSpace = nlIsSpace
 	s.nlIsEnd = nlIsEnd
-	s.prevRune = -1
-	s.peekRune = -1
 	s.atEOF = false
 	s.limit = hugeWid
 	s.argLimit = hugeWid
@@ -424,7 +417,7 @@ func (s *ss) free(old ssave) {
 		return
 	}
 	s.buf = s.buf[:0]
-	s.rr = nil
+	s.rs = nil
 	ssFree.Put(s)
 }
 
@@ -455,8 +448,8 @@ func (s *ss) skipSpace(stopAtNewline bool) {
 	}
 }
 
-// token returns the next space-delimited string from the input.  It
-// skips white space.  For Scanln, it stops at newlines.  For Scan,
+// token returns the next space-delimited string from the input. It
+// skips white space. For Scanln, it stops at newlines. For Scan,
 // newlines are treated as spaces.
 func (s *ss) token(skipSpace bool, f func(rune) bool) []byte {
 	if skipSpace {
@@ -525,7 +518,7 @@ func (s *ss) notEOF() {
 	s.UnreadRune()
 }
 
-// accept checks the next rune in the input.  If it's a byte (sic) in the string, it puts it in the
+// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
 // buffer and returns true. Otherwise it return false.
 func (s *ss) accept(ok string) bool {
 	return s.consume(ok, true)
@@ -549,7 +542,7 @@ func (s *ss) scanBool(verb rune) bool {
 	if !s.okVerb(verb, "tv", "boolean") {
 		return false
 	}
-	// Syntax-checking a boolean is annoying.  We're not fastidious about case.
+	// Syntax-checking a boolean is annoying. We're not fastidious about case.
 	switch s.getRune() {
 	case '0':
 		return false
@@ -643,7 +636,7 @@ func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
 }
 
 // scanInt returns the value of the integer represented by the next
-// token, checking for overflow.  Any error is stored in s.err.
+// token, checking for overflow. Any error is stored in s.err.
 func (s *ss) scanInt(verb rune, bitSize int) int64 {
 	if verb == 'c' {
 		return s.scanRune(bitSize)
@@ -676,7 +669,7 @@ func (s *ss) scanInt(verb rune, bitSize int) int64 {
 }
 
 // scanUint returns the value of the unsigned integer represented
-// by the next token, checking for overflow.  Any error is stored in s.err.
+// by the next token, checking for overflow. Any error is stored in s.err.
 func (s *ss) scanUint(verb rune, bitSize int) uint64 {
 	if verb == 'c' {
 		return uint64(s.scanRune(bitSize))
@@ -846,7 +839,7 @@ func (s *ss) quotedString() string {
 		return string(s.buf)
 	case '"':
 		// Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
-		s.buf.WriteRune(quote)
+		s.buf.WriteByte('"')
 		for {
 			r := s.mustReadRune()
 			s.buf.WriteRune(r)
@@ -922,9 +915,14 @@ func (s *ss) hexString() string {
 	return string(s.buf)
 }
 
-const floatVerbs = "beEfFgGv"
+const (
+	floatVerbs = "beEfFgGv"
+
+	hugeWid = 1 << 30
 
-const hugeWid = 1 << 30
+	intBits     = 32 << (^uint(0) >> 63)
+	uintptrBits = 32 << (^uintptr(0) >> 63)
+)
 
 // scanOne scans a single value, deriving the scanner from the type of the argument.
 func (s *ss) scanOne(verb rune, arg interface{}) {
@@ -1142,7 +1140,7 @@ func (s *ss) advance(format string) (i int) {
 }
 
 // doScanf does the real work when scanning with a format string.
-//  At the moment, it handles only pointers to basic types.
+// At the moment, it handles only pointers to basic types.
 func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err error) {
 	defer errorHandler(&err)
 	end := len(format) - 1
@@ -1155,7 +1153,7 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
 		}
 		// Either we failed to advance, we have a percent character, or we ran out of input.
 		if format[i] != '%' {
-			// Can't advance format.  Why not?
+			// Can't advance format. Why not?
 			if w < 0 {
 				s.errorString("input does not match format")
 			}
diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go
index 7ac74dc..364d4fb 100644
--- a/src/fmt/scan_test.go
+++ b/src/fmt/scan_test.go
@@ -78,12 +78,6 @@ var (
 	renamedComplex128Val renamedComplex128
 )
 
-type FloatTest struct {
-	text string
-	in   float64
-	out  float64
-}
-
 // Xs accepts any non-empty run of the verb character
 type Xs string
 
@@ -519,7 +513,7 @@ func testScanfMulti(name string, t *testing.T) {
 		if err != nil {
 			if test.err == "" {
 				t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
-			} else if strings.Index(err.Error(), test.err) < 0 {
+			} else if !strings.Contains(err.Error(), test.err) {
 				t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
 			}
 			continue
@@ -613,7 +607,7 @@ func TestScanNotPointer(t *testing.T) {
 	_, err := Fscan(r, a)
 	if err == nil {
 		t.Error("expected error scanning non-pointer")
-	} else if strings.Index(err.Error(), "pointer") < 0 {
+	} else if !strings.Contains(err.Error(), "pointer") {
 		t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
 	}
 }
@@ -623,7 +617,7 @@ func TestScanlnNoNewline(t *testing.T) {
 	_, err := Sscanln("1 x\n", &a)
 	if err == nil {
 		t.Error("expected error scanning string missing newline")
-	} else if strings.Index(err.Error(), "newline") < 0 {
+	} else if !strings.Contains(err.Error(), "newline") {
 		t.Errorf("expected newline error scanning string missing newline, got: %s", err)
 	}
 }
@@ -634,7 +628,7 @@ func TestScanlnWithMiddleNewline(t *testing.T) {
 	_, err := Fscanln(r, &a, &b)
 	if err == nil {
 		t.Error("expected error scanning string with extra newline")
-	} else if strings.Index(err.Error(), "newline") < 0 {
+	} else if !strings.Contains(err.Error(), "newline") {
 		t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
 	}
 }
@@ -767,7 +761,7 @@ func TestUnreadRuneWithBufio(t *testing.T) {
 
 type TwoLines string
 
-// Scan attempts to read two lines into the object.  Scanln should prevent this
+// Scan attempts to read two lines into the object. Scanln should prevent this
 // because it stops at newline; Scan and Scanf should be fine.
 func (t *TwoLines) Scan(state ScanState, verb rune) error {
 	chars := make([]rune, 0, 100)
@@ -1001,6 +995,18 @@ func BenchmarkScanRecursiveInt(b *testing.B) {
 	}
 }
 
+func BenchmarkScanRecursiveIntReaderWrapper(b *testing.B) {
+	b.ResetTimer()
+	ints := makeInts(intCount)
+	var r RecursiveInt
+	for i := b.N - 1; i >= 0; i-- {
+		buf := newReader(string(ints))
+		b.StartTimer()
+		Fscan(buf, &r)
+		b.StopTimer()
+	}
+}
+
 // Issue 9124.
 // %x on bytes couldn't handle non-space bytes terminating the scan.
 func TestHexBytes(t *testing.T) {
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index 5ab4283..d3dcd79 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -99,7 +99,7 @@ func (g *CommentGroup) Text() string {
 	}
 	comments := make([]string, len(g.List))
 	for i, c := range g.List {
-		comments[i] = string(c.Text)
+		comments[i] = c.Text
 	}
 
 	lines := make([]string, 0, 10) // most comments are less than 10 lines
@@ -418,7 +418,7 @@ type (
 )
 
 // Pos and End implementations for expression/type nodes.
-//
+
 func (x *BadExpr) Pos() token.Pos  { return x.From }
 func (x *Ident) Pos() token.Pos    { return x.NamePos }
 func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }
@@ -709,7 +709,7 @@ type (
 )
 
 // Pos and End implementations for statement nodes.
-//
+
 func (s *BadStmt) Pos() token.Pos        { return s.From }
 func (s *DeclStmt) Pos() token.Pos       { return s.Decl.Pos() }
 func (s *EmptyStmt) Pos() token.Pos      { return s.Semicolon }
@@ -854,7 +854,7 @@ type (
 )
 
 // Pos and End implementations for spec nodes.
-//
+
 func (s *ImportSpec) Pos() token.Pos {
 	if s.Name != nil {
 		return s.Name.Pos()
@@ -931,7 +931,7 @@ type (
 )
 
 // Pos and End implementations for declaration nodes.
-//
+
 func (d *BadDecl) Pos() token.Pos  { return d.From }
 func (d *GenDecl) Pos() token.Pos  { return d.TokPos }
 func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() }
diff --git a/src/go/ast/commentmap.go b/src/go/ast/commentmap.go
index ac999d6..2a653a6 100644
--- a/src/go/ast/commentmap.go
+++ b/src/go/ast/commentmap.go
@@ -267,7 +267,7 @@ func (cmap CommentMap) Filter(node Node) CommentMap {
 }
 
 // Comments returns the list of comment groups in the comment map.
-// The result is sorted is source order.
+// The result is sorted in source order.
 //
 func (cmap CommentMap) Comments() []*CommentGroup {
 	list := make([]*CommentGroup, 0, len(cmap))
diff --git a/src/go/ast/import.go b/src/go/ast/import.go
index 5c794c3..6b27fe8 100644
--- a/src/go/ast/import.go
+++ b/src/go/ast/import.go
@@ -31,7 +31,7 @@ func SortImports(fset *token.FileSet, f *File) {
 		specs := d.Specs[:0]
 		for j, s := range d.Specs {
 			if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line {
-				// j begins a new run.  End this one.
+				// j begins a new run. End this one.
 				specs = append(specs, sortSpecs(fset, f, d.Specs[i:j])...)
 				i = j
 			}
diff --git a/src/go/ast/print.go b/src/go/ast/print.go
index f15dc11..d86d9ba 100644
--- a/src/go/ast/print.go
+++ b/src/go/ast/print.go
@@ -36,8 +36,11 @@ func NotNilFilter(_ string, v reflect.Value) bool {
 // struct fields for which f(fieldname, fieldvalue) is true are
 // printed; all others are filtered from the output. Unexported
 // struct fields are never printed.
-//
-func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) {
+func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) error {
+	return fprint(w, fset, x, f)
+}
+
+func fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) {
 	// setup printer
 	p := printer{
 		output: w,
diff --git a/src/go/ast/resolve.go b/src/go/ast/resolve.go
index 0406bfc..c1830b5 100644
--- a/src/go/ast/resolve.go
+++ b/src/go/ast/resolve.go
@@ -56,7 +56,7 @@ func resolve(scope *Scope, ident *Ident) bool {
 // indexed by package id (canonical import path).
 // An Importer must determine the canonical import path and
 // check the map to see if it is already present in the imports map.
-// If so, the Importer can return the map entry.  Otherwise, the
+// If so, the Importer can return the map entry. Otherwise, the
 // Importer should load the package data for the given path into
 // a new *Object (pkg), record pkg in the imports map, and then
 // return pkg.
diff --git a/src/go/build/build.go b/src/go/build/build.go
index c1b70bc..9706b8b 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -55,8 +55,8 @@ type Context struct {
 	InstallSuffix string
 
 	// By default, Import uses the operating system's file system calls
-	// to read directories and files.  To read from other sources,
-	// callers can set the following functions.  They all have default
+	// to read directories and files. To read from other sources,
+	// callers can set the following functions. They all have default
 	// behaviors that use the local file system, so clients need only set
 	// the functions whose behaviors they wish to change.
 
@@ -87,11 +87,11 @@ type Context struct {
 	// ReadDir returns a slice of os.FileInfo, sorted by Name,
 	// describing the content of the named directory.
 	// If ReadDir is nil, Import uses ioutil.ReadDir.
-	ReadDir func(dir string) (fi []os.FileInfo, err error)
+	ReadDir func(dir string) ([]os.FileInfo, error)
 
 	// OpenFile opens a file (not a directory) for reading.
 	// If OpenFile is nil, Import uses os.Open.
-	OpenFile func(path string) (r io.ReadCloser, err error)
+	OpenFile func(path string) (io.ReadCloser, error)
 }
 
 // joinPath calls ctxt.JoinPath (if not nil) or else filepath.Join.
@@ -256,34 +256,6 @@ 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,
-	"darwin/arm":      true,
-	"darwin/arm64":    true,
-	"dragonfly/amd64": true,
-	"freebsd/386":     true,
-	"freebsd/amd64":   true,
-	"freebsd/arm":     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 defaultContext() Context {
 	var c Context
 
@@ -298,7 +270,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".
-	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6"}
+	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7"}
 
 	switch os.Getenv("CGO_ENABLED") {
 	case "1":
@@ -330,12 +302,19 @@ type ImportMode uint
 
 const (
 	// If FindOnly is set, Import stops after locating the directory
-	// that should contain the sources for a package.  It does not
+	// that should contain the sources for a package. It does not
 	// read any files in the directory.
 	FindOnly ImportMode = 1 << iota
 
 	// If AllowBinary is set, Import can be satisfied by a compiled
 	// package object without corresponding sources.
+	//
+	// Deprecated:
+	// The supported way to create a compiled-only package is to
+	// write source code containing a //go:binary-only-package comment at
+	// the top of the file. Such a package will be recognized
+	// regardless of this flag setting (because it has source code)
+	// and will have BinaryOnly set to true in the returned Package.
 	AllowBinary
 
 	// If ImportComment is set, parse import comments on package statements.
@@ -376,6 +355,7 @@ type Package struct {
 	PkgObj        string   // installed .a file
 	AllTags       []string // tags that can influence file selection in this directory
 	ConflictDir   string   // this directory shadows Dir in $GOPATH
+	BinaryOnly    bool     // cannot be rebuilt from source (has //go:binary-only-package comment)
 
 	// Source files
 	GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
@@ -386,6 +366,7 @@ type Package struct {
 	CXXFiles       []string // .cc, .cpp and .cxx source files
 	MFiles         []string // .m (Objective-C) source files
 	HFiles         []string // .h, .hh, .hpp and .hxx source files
+	FFiles         []string // .f, .F, .for and .f90 Fortran source files
 	SFiles         []string // .s source files
 	SwigFiles      []string // .swig files
 	SwigCXXFiles   []string // .swigcxx files
@@ -395,6 +376,7 @@ type Package struct {
 	CgoCFLAGS    []string // Cgo CFLAGS directives
 	CgoCPPFLAGS  []string // Cgo CPPFLAGS directives
 	CgoCXXFLAGS  []string // Cgo CXXFLAGS directives
+	CgoFFLAGS    []string // Cgo FFLAGS directives
 	CgoLDFLAGS   []string // Cgo LDFLAGS directives
 	CgoPkgConfig []string // Cgo pkg-config directives
 
@@ -705,7 +687,7 @@ Found:
 			p.InvalidGoFiles = append(p.InvalidGoFiles, name)
 		}
 
-		match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags)
+		match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags, &p.BinaryOnly)
 		if err != nil {
 			badFile(err)
 			continue
@@ -717,7 +699,7 @@ Found:
 			continue
 		}
 
-		// Going to save the file.  For non-Go files, can stop here.
+		// Going to save the file. For non-Go files, can stop here.
 		switch ext {
 		case ".c":
 			p.CFiles = append(p.CFiles, name)
@@ -731,6 +713,9 @@ Found:
 		case ".h", ".hh", ".hpp", ".hxx":
 			p.HFiles = append(p.HFiles, name)
 			continue
+		case ".f", ".F", ".for", ".f90":
+			p.FFiles = append(p.FFiles, name)
+			continue
 		case ".s":
 			p.SFiles = append(p.SFiles, name)
 			continue
@@ -1016,7 +1001,7 @@ func parseWord(data []byte) (word, rest []byte) {
 // MatchFile considers the name of the file and may use ctxt.OpenFile to
 // read some or all of the file's content.
 func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
-	match, _, _, err = ctxt.matchFile(dir, name, false, nil)
+	match, _, _, err = ctxt.matchFile(dir, name, false, nil, nil)
 	return
 }
 
@@ -1028,7 +1013,7 @@ func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
 // considers text until the first non-comment.
 // If allTags is non-nil, matchFile records any encountered build tag
 // by setting allTags[tag] = true.
-func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map[string]bool) (match bool, data []byte, filename string, err error) {
+func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map[string]bool, binaryOnly *bool) (match bool, data []byte, filename string, err error) {
 	if strings.HasPrefix(name, "_") ||
 		strings.HasPrefix(name, ".") {
 		return
@@ -1045,7 +1030,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
 	}
 
 	switch ext {
-	case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
+	case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".f", ".F", ".f90", ".S", ".swig", ".swigcxx":
 		// tentatively okay - read to make sure
 	case ".syso":
 		// binary, no reading
@@ -1064,7 +1049,11 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
 
 	if strings.HasSuffix(filename, ".go") {
 		data, err = readImports(f, false, nil)
+		if strings.HasSuffix(filename, "_test.go") {
+			binaryOnly = nil // ignore //go:binary-only-package comments in _test.go files
+		}
 	} else {
+		binaryOnly = nil // ignore //go:binary-only-package comments in non-Go sources
 		data, err = readComments(f)
 	}
 	f.Close()
@@ -1074,7 +1063,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
 	}
 
 	// Look for +build comments to accept or reject the file.
-	if !ctxt.shouldBuild(data, allTags) && !ctxt.UseAllFiles {
+	if !ctxt.shouldBuild(data, allTags, binaryOnly) && !ctxt.UseAllFiles {
 		return
 	}
 
@@ -1103,6 +1092,11 @@ func ImportDir(dir string, mode ImportMode) (*Package, error) {
 
 var slashslash = []byte("//")
 
+// Special comment denoting a binary-only package.
+// See https://golang.org/design/2775-binary-only-packages
+// for more about the design of binary-only packages.
+var binaryOnlyComment = []byte("//go:binary-only-package")
+
 // shouldBuild reports whether it is okay to use this file,
 // The rule is that in the file's leading run of // comments
 // and blank lines, which must be followed by a blank line
@@ -1110,13 +1104,19 @@ var slashslash = []byte("//")
 // lines beginning with '// +build' are taken as build directives.
 //
 // The file is accepted only if each such line lists something
-// matching the file.  For example:
+// matching the file. For example:
 //
 //	// +build windows linux
 //
 // marks the file as applicable only on Windows and Linux.
 //
-func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
+// If shouldBuild finds a //go:binary-only-package comment in a file that
+// should be built, it sets *binaryOnly to true. Otherwise it does
+// not change *binaryOnly.
+//
+func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool, binaryOnly *bool) bool {
+	sawBinaryOnly := false
+
 	// Pass 1. Identify leading run of // comments and blank lines,
 	// which must be followed by a blank line.
 	end := 0
@@ -1151,6 +1151,9 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
 		}
 		line = bytes.TrimSpace(line)
 		if bytes.HasPrefix(line, slashslash) {
+			if bytes.Equal(line, binaryOnlyComment) {
+				sawBinaryOnly = true
+			}
 			line = bytes.TrimSpace(line[len(slashslash):])
 			if len(line) > 0 && line[0] == '+' {
 				// Looks like a comment +line.
@@ -1170,6 +1173,10 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
 		}
 	}
 
+	if binaryOnly != nil && sawBinaryOnly {
+		*binaryOnly = true
+	}
+
 	return allok
 }
 
@@ -1236,6 +1243,8 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
 			di.CgoCPPFLAGS = append(di.CgoCPPFLAGS, args...)
 		case "CXXFLAGS":
 			di.CgoCXXFLAGS = append(di.CgoCXXFLAGS, args...)
+		case "FFLAGS":
+			di.CgoFFLAGS = append(di.CgoFFLAGS, args...)
 		case "LDFLAGS":
 			di.CgoLDFLAGS = append(di.CgoLDFLAGS, args...)
 		case "pkg-config":
@@ -1251,7 +1260,7 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
 // the result is safe for the shell.
 func expandSrcDir(str string, srcdir string) (string, bool) {
 	// "\" delimited paths cause safeCgoName to fail
-	// so convert native paths with a different delimeter
+	// so convert native paths with a different delimiter
 	// to "/" before starting (eg: on windows).
 	srcdir = filepath.ToSlash(srcdir)
 
@@ -1287,7 +1296,7 @@ func safeCgoName(s string, spaces bool) bool {
 		safe = safe[len(safeSpaces):]
 	}
 	for i := 0; i < len(s); i++ {
-		if c := s[i]; c < 0x80 && bytes.IndexByte(safe, c) < 0 {
+		if c := s[i]; c < utf8.RuneSelf && bytes.IndexByte(safe, c) < 0 {
 			return false
 		}
 	}
@@ -1300,7 +1309,7 @@ func safeCgoName(s string, spaces bool) bool {
 // Single quotes and double quotes are recognized to prevent splitting within the
 // quoted region, and are removed from the resulting substrings. If a quote in s
 // isn't closed err will be set and r will have the unclosed argument as the
-// last element.  The backslash is used for escaping.
+// last element. The backslash is used for escaping.
 //
 // For example, the following string:
 //
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index 7312af0..c9f906a 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -151,28 +151,28 @@ func TestShouldBuild(t *testing.T) {
 
 	ctx := &Context{BuildTags: []string{"tag1"}}
 	m := map[string]bool{}
-	if !ctx.shouldBuild([]byte(file1), m) {
+	if !ctx.shouldBuild([]byte(file1), m, nil) {
 		t.Errorf("shouldBuild(file1) = false, want true")
 	}
 	if !reflect.DeepEqual(m, want1) {
-		t.Errorf("shoudBuild(file1) tags = %v, want %v", m, want1)
+		t.Errorf("shouldBuild(file1) tags = %v, want %v", m, want1)
 	}
 
 	m = map[string]bool{}
-	if ctx.shouldBuild([]byte(file2), m) {
-		t.Errorf("shouldBuild(file2) = true, want fakse")
+	if ctx.shouldBuild([]byte(file2), m, nil) {
+		t.Errorf("shouldBuild(file2) = true, want false")
 	}
 	if !reflect.DeepEqual(m, want2) {
-		t.Errorf("shoudBuild(file2) tags = %v, want %v", m, want2)
+		t.Errorf("shouldBuild(file2) tags = %v, want %v", m, want2)
 	}
 
 	m = map[string]bool{}
 	ctx = &Context{BuildTags: nil}
-	if !ctx.shouldBuild([]byte(file3), m) {
+	if !ctx.shouldBuild([]byte(file3), m, nil) {
 		t.Errorf("shouldBuild(file3) = false, want true")
 	}
 	if !reflect.DeepEqual(m, want3) {
-		t.Errorf("shoudBuild(file3) tags = %v, want %v", m, want3)
+		t.Errorf("shouldBuild(file3) tags = %v, want %v", m, want3)
 	}
 }
 
@@ -300,7 +300,6 @@ func TestShellSafety(t *testing.T) {
 }
 
 func TestImportVendor(t *testing.T) {
-	t.Skip("skipping; hpack has moved to internal for now; golang.org/issue/14047")
 	testenv.MustHaveGoBuild(t) // really must just have source
 	ctxt := Default
 	ctxt.GOPATH = ""
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 1e6be2f..335e774 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -21,7 +21,7 @@ import (
 )
 
 // pkgDeps defines the expected dependencies between packages in
-// the Go source tree.  It is a statement of policy.
+// the Go source tree. It is a statement of policy.
 // Changes should not be made to this map without prior discussion.
 //
 // The map contains two kinds of entries:
@@ -136,11 +136,23 @@ var pkgDeps = map[string][]string{
 	"internal/syscall/unix":             {"L0", "syscall"},
 	"internal/syscall/windows":          {"L0", "syscall", "internal/syscall/windows/sysdll"},
 	"internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
-	"time":          {"L0", "syscall", "internal/syscall/windows/registry"},
+	"time": {
+		// "L0" without the "io" package:
+		"errors",
+		"runtime",
+		"runtime/internal/atomic",
+		"sync",
+		"sync/atomic",
+		"unsafe",
+		// Other time dependencies:
+		"internal/syscall/windows/registry",
+		"syscall",
+	},
+
 	"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"},
+	"os/exec":       {"L2", "os", "context", "path/filepath", "syscall"},
 	"os/signal":     {"L2", "os", "syscall"},
 
 	// OS enables basic operating system functionality,
@@ -161,14 +173,14 @@ var pkgDeps = map[string][]string{
 	"regexp":         {"L2", "regexp/syntax"},
 	"regexp/syntax":  {"L2"},
 	"runtime/debug":  {"L2", "fmt", "io/ioutil", "os", "time"},
-	"runtime/pprof":  {"L2", "fmt", "text/tabwriter"},
+	"runtime/pprof":  {"L2", "fmt", "os", "text/tabwriter"},
 	"runtime/trace":  {"L0"},
 	"text/tabwriter": {"L2"},
 
 	"testing":          {"L2", "flag", "fmt", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
 	"testing/iotest":   {"L2", "log"},
 	"testing/quick":    {"L2", "flag", "fmt", "reflect"},
-	"internal/testenv": {"L2", "os", "testing"},
+	"internal/testenv": {"L2", "OS", "flag", "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.
@@ -215,6 +227,7 @@ var pkgDeps = map[string][]string{
 	"compress/gzip":            {"L4", "compress/flate"},
 	"compress/lzw":             {"L4"},
 	"compress/zlib":            {"L4", "compress/flate"},
+	"context":                  {"errors", "fmt", "reflect", "sync", "time"},
 	"database/sql":             {"L4", "container/list", "database/sql/driver"},
 	"database/sql/driver":      {"L4", "time"},
 	"debug/dwarf":              {"L4"},
@@ -279,7 +292,13 @@ var pkgDeps = map[string][]string{
 	// Basic networking.
 	// Because net must be used by any package that wants to
 	// do networking portably, it must have a small dependency set: just L0+basic os.
-	"net": {"L0", "CGO", "math/rand", "os", "sort", "syscall", "time", "internal/syscall/windows", "internal/singleflight", "internal/race"},
+	"net": {
+		"L0", "CGO",
+		"context", "math/rand", "os", "sort", "syscall", "time",
+		"internal/nettrace",
+		"internal/syscall/windows", "internal/singleflight", "internal/race",
+		"golang.org/x/net/route",
+	},
 
 	// NET enables use of basic network-related packages.
 	"NET": {
@@ -356,11 +375,16 @@ var pkgDeps = map[string][]string{
 	// HTTP, kingpin of dependencies.
 	"net/http": {
 		"L4", "NET", "OS",
-		"compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
+		"context", "compress/gzip", "container/list", "crypto/tls",
+		"mime/multipart", "runtime/debug",
 		"net/http/internal",
-		"internal/golang.org/x/net/http2/hpack",
+		"golang.org/x/net/http2/hpack",
+		"golang.org/x/net/lex/httplex",
+		"internal/nettrace",
+		"net/http/httptrace",
 	},
-	"net/http/internal": {"L4"},
+	"net/http/internal":  {"L4"},
+	"net/http/httptrace": {"context", "internal/nettrace", "net", "reflect", "time"},
 
 	// HTTP-using packages.
 	"expvar":             {"L4", "OS", "encoding/json", "net/http"},
@@ -402,21 +426,6 @@ func allowed(pkg string) map[string]bool {
 	return m
 }
 
-var bools = []bool{false, true}
-var geese = []string{"android", "darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"}
-var goarches = []string{"386", "amd64", "arm"}
-
-type osPkg struct {
-	goos, pkg string
-}
-
-// allowedErrors are the operating systems and packages known to contain errors
-// (currently just "no Go source files")
-var allowedErrors = map[osPkg]bool{
-	osPkg{"windows", "log/syslog"}: true,
-	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.
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index d436d28..9f7ac8f 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,7 +8,7 @@
 //
 // The Go path is a list of directory trees containing Go source code.
 // It is consulted to resolve imports that cannot be found in the standard
-// Go tree.  The default path is the value of the GOPATH environment
+// Go tree. The default path is the value of the GOPATH environment
 // variable, interpreted as a path list appropriate to the operating system
 // (on Unix, the variable is a colon-separated string;
 // on Windows, a semicolon-separated string;
@@ -16,7 +16,7 @@
 //
 // Each directory listed in the Go path must have a prescribed structure:
 //
-// The src/ directory holds source code.  The path below 'src' determines
+// The src/ directory holds source code. The path below 'src' determines
 // the import path or executable name.
 //
 // The pkg/ directory holds installed package objects.
@@ -31,9 +31,9 @@
 //
 // The bin/ directory holds compiled commands.
 // Each command is named for its source directory, but only
-// using the final element, not the entire path.  That is, the
+// using 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/ is stripped
 // so that you can add DIR/bin to your PATH to get at the
 // installed commands.
 //
@@ -103,6 +103,7 @@
 //	- "go1.4", from Go version 1.4 onward
 //	- "go1.5", from Go version 1.5 onward
 //	- "go1.6", from Go version 1.6 onward
+//	- "go1.7", from Go version 1.7 onward
 //	- any additional words listed in ctxt.BuildTags
 //
 // If a file's name, after stripping the extension and a possible _test suffix,
@@ -138,4 +139,26 @@
 // Using GOOS=android matches build tags and files as for GOOS=linux
 // in addition to android tags and files.
 //
+// Binary-Only Packages
+//
+// It is possible to distribute packages in binary form without including the
+// source code used for compiling the package. To do this, the package must
+// be distributed with a source file not excluded by build constraints and
+// containing a "//go:binary-only-package" comment.
+// Like a build constraint, this comment must appear near the top of the file,
+// preceded only by blank lines and other line comments and with a blank line
+// following the comment, to separate it from the package documentation.
+// Unlike build constraints, this comment is only recognized in non-test
+// Go source files.
+//
+// The minimal source code for a binary-only package is therefore:
+//
+//	//go:binary-only-package
+//
+//	package mypkg
+//
+// The source code may include additional Go code. That code is never compiled
+// but will be processed by tools like godoc and might be useful as end-user
+// documentation.
+//
 package build
diff --git a/src/go/build/read.go b/src/go/build/read.go
index 1049ac5..29b8cdc 100644
--- a/src/go/build/read.go
+++ b/src/go/build/read.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"errors"
 	"io"
+	"unicode/utf8"
 )
 
 type importReader struct {
@@ -20,7 +21,7 @@ type importReader struct {
 }
 
 func isIdent(c byte) bool {
-	return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= 0x80
+	return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
 }
 
 var (
diff --git a/src/go/build/read_test.go b/src/go/build/read_test.go
index 326960b..9cef657 100644
--- a/src/go/build/read_test.go
+++ b/src/go/build/read_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/go/build/syslist.go b/src/go/build/syslist.go
index 7adb0ca..c83622b 100644
--- a/src/go/build/syslist.go
+++ b/src/go/build/syslist.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/go/build/syslist_test.go b/src/go/build/syslist_test.go
index 3be2928..7973ff4 100644
--- a/src/go/build/syslist_test.go
+++ b/src/go/build/syslist_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/go/constant/value.go b/src/go/constant/value.go
index 310814d..ab10ae3 100644
--- a/src/go/constant/value.go
+++ b/src/go/constant/value.go
@@ -276,10 +276,10 @@ func smallRat(x *big.Float) bool {
 // MakeUnknown returns the Unknown value.
 func MakeUnknown() Value { return unknownVal{} }
 
-// MakeBool returns the Bool value for x.
+// MakeBool returns the Bool value for b.
 func MakeBool(b bool) Value { return boolVal(b) }
 
-// MakeString returns the String value for x.
+// MakeString returns the String value for s.
 func MakeString(s string) Value { return stringVal(s) }
 
 // MakeInt64 returns the Int value for x.
@@ -308,8 +308,8 @@ func MakeFloat64(x float64) Value {
 
 // MakeFromLiteral returns the corresponding integer, floating-point,
 // imaginary, character, or string value for a Go literal string. The
-// tok value must be one of token.INT, token.FLOAT, toke.IMAG, token.
-// CHAR, or token.STRING. The final argument must be zero.
+// tok value must be one of token.INT, token.FLOAT, token.IMAG,
+// token.CHAR, or token.STRING. The final argument must be zero.
 // If the literal string syntax is invalid, the result is an Unknown.
 func MakeFromLiteral(lit string, tok token.Token, zero uint) Value {
 	if zero != 0 {
diff --git a/src/go/constant/value_test.go b/src/go/constant/value_test.go
index dbd96c0..8a8a08e 100644
--- a/src/go/constant/value_test.go
+++ b/src/go/constant/value_test.go
@@ -244,6 +244,7 @@ var stringTests = []struct {
 	{"1e9999", "1e+9999", "0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216"},
 	{"1e-9999", "1e-9999", "0x.83b01ba6d8c0425eec1b21e96f7742d63c2653ed0a024cf8a2f9686df578d7b07d7a83d84df6a2ec70a921d1f6cd5574893a7eda4d28ee719e13a5dce2700759p-33215"},
 	{"2.71828182845904523536028747135266249775724709369995957496696763", "2.71828", "271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000"},
+	{"0e9999999999", "0", "0"}, // issue #16176
 
 	// Complex
 	{"0i", "(0 + 0i)", "(0 + 0i)"},
diff --git a/src/go/doc/comment.go b/src/go/doc/comment.go
index f414ca4..ed8eef4 100644
--- a/src/go/doc/comment.go
+++ b/src/go/doc/comment.go
@@ -225,7 +225,7 @@ func heading(line string) string {
 	}
 
 	// exclude lines with illegal characters
-	if strings.IndexAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") >= 0 {
+	if strings.ContainsAny(line, ",.;:!?+*/=()[]{}_^°&§~%#@<\">\\") {
 		return ""
 	}
 
@@ -398,7 +398,7 @@ func blocks(text string) []block {
 
 // ToText prepares comment text for presentation in textual output.
 // It wraps paragraphs of text to width or fewer Unicode code points
-// and then prefixes each line with the indent.  In preformatted sections
+// and then prefixes each line with the indent. In preformatted sections
 // (such as program text), it prefixes each non-blank line with preIndent.
 func ToText(w io.Writer, text string, indent, preIndent string, width int) {
 	l := lineWrapper{
diff --git a/src/go/doc/example.go b/src/go/doc/example.go
index c414e54..bbf8096 100644
--- a/src/go/doc/example.go
+++ b/src/go/doc/example.go
@@ -26,8 +26,9 @@ type Example struct {
 	Play        *ast.File // a whole program version of the example
 	Comments    []*ast.CommentGroup
 	Output      string // expected output
-	EmptyOutput bool   // expect empty output
-	Order       int    // original source code order
+	Unordered   bool
+	EmptyOutput bool // expect empty output
+	Order       int  // original source code order
 }
 
 // Examples returns the examples found in the files, sorted by Name field.
@@ -71,7 +72,7 @@ func Examples(files ...*ast.File) []*Example {
 			if f.Doc != nil {
 				doc = f.Doc.Text()
 			}
-			output, hasOutput := exampleOutput(f.Body, file.Comments)
+			output, unordered, hasOutput := exampleOutput(f.Body, file.Comments)
 			flist = append(flist, &Example{
 				Name:        name[len("Example"):],
 				Doc:         doc,
@@ -79,6 +80,7 @@ func Examples(files ...*ast.File) []*Example {
 				Play:        playExample(file, f.Body),
 				Comments:    file.Comments,
 				Output:      output,
+				Unordered:   unordered,
 				EmptyOutput: output == "" && hasOutput,
 				Order:       len(flist),
 			})
@@ -96,24 +98,27 @@ func Examples(files ...*ast.File) []*Example {
 	return list
 }
 
-var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*output:`)
+var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*(unordered )?output:`)
 
 // Extracts the expected output and whether there was a valid output comment
-func exampleOutput(b *ast.BlockStmt, comments []*ast.CommentGroup) (output string, ok bool) {
+func exampleOutput(b *ast.BlockStmt, comments []*ast.CommentGroup) (output string, unordered, ok bool) {
 	if _, last := lastComment(b, comments); last != nil {
 		// test that it begins with the correct prefix
 		text := last.Text()
-		if loc := outputPrefix.FindStringIndex(text); loc != nil {
+		if loc := outputPrefix.FindStringSubmatchIndex(text); loc != nil {
+			if loc[2] != -1 {
+				unordered = true
+			}
 			text = text[loc[1]:]
 			// Strip zero or more spaces followed by \n or a single space.
 			text = strings.TrimLeft(text, " ")
 			if len(text) > 0 && text[0] == '\n' {
 				text = text[1:]
 			}
-			return text, true
+			return text, unordered, true
 		}
 	}
-	return "", false // no suitable comment found
+	return "", false, false // no suitable comment found
 }
 
 // isTest tells whether name looks like a test, example, or benchmark.
@@ -255,7 +260,8 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
 		}
 	}
 
-	// Strip "Output:" comment and adjust body end position.
+	// Strip the "Output:" or "Unordered output:" comment and adjust body
+	// end position.
 	body, comments = stripOutputComment(body, comments)
 
 	// Synthesize import declaration.
@@ -318,10 +324,10 @@ func playExampleFile(file *ast.File) *ast.File {
 	return &f
 }
 
-// stripOutputComment finds and removes an "Output:" comment from body
-// and comments, and adjusts the body block's end position.
+// stripOutputComment finds and removes the "Output:" or "Unordered output:"
+// comment from body and comments, and adjusts the body block's end position.
 func stripOutputComment(body *ast.BlockStmt, comments []*ast.CommentGroup) (*ast.BlockStmt, []*ast.CommentGroup) {
-	// Do nothing if no "Output:" comment found.
+	// Do nothing if there is no "Output:" or "Unordered output:" comment.
 	i, last := lastComment(body, comments)
 	if last == nil || !outputPrefix.MatchString(last.Text()) {
 		return body, comments
diff --git a/src/go/doc/testdata/benchmark.go b/src/go/doc/testdata/benchmark.go
index 905e496..1d581f0 100644
--- a/src/go/doc/testdata/benchmark.go
+++ b/src/go/doc/testdata/benchmark.go
@@ -33,7 +33,7 @@ type B struct {
 	result    BenchmarkResult
 }
 
-// StartTimer starts timing a test.  This function is called automatically
+// StartTimer starts timing a test. This function is called automatically
 // before a benchmark starts, but it can also used to resume timing after
 // a call to StopTimer.
 func (b *B) StartTimer() {
@@ -43,7 +43,7 @@ func (b *B) StartTimer() {
 	}
 }
 
-// StopTimer stops timing a test.  This can be used to pause the timer
+// StopTimer stops timing a test. This can be used to pause the timer
 // while performing complex initialization that you don't
 // want to measure.
 func (b *B) StopTimer() {
@@ -134,9 +134,9 @@ func (b *B) run() BenchmarkResult {
 	return b.result
 }
 
-// launch launches the benchmark function.  It gradually increases the number
+// launch launches the benchmark function. It gradually increases the number
 // of benchmark iterations until the benchmark runs for a second in order
-// to get a reasonable measurement.  It prints timing information in this form
+// to get a reasonable measurement. It prints timing information in this form
 //		testing.BenchmarkHello	100000		19 ns/op
 // launch is run by the fun function as a separate goroutine.
 func (b *B) launch() {
diff --git a/src/go/doc/testdata/testing.0.golden b/src/go/doc/testdata/testing.0.golden
index f8348f1..83cf37c 100644
--- a/src/go/doc/testdata/testing.0.golden
+++ b/src/go/doc/testdata/testing.0.golden
@@ -78,10 +78,10 @@ TYPES
 	// SetBytes records the number of bytes processed in a single ...
 	func (b *B) SetBytes(n int64)
 
-	// StartTimer starts timing a test.  This function is called ...
+	// StartTimer starts timing a test. This function is called ...
 	func (b *B) StartTimer()
 
-	// StopTimer stops timing a test.  This can be used to pause the ...
+	// StopTimer stops timing a test. This can be used to pause the ...
 	func (b *B) StopTimer()
 
 	// The results of a benchmark run. 
diff --git a/src/go/doc/testdata/testing.1.golden b/src/go/doc/testdata/testing.1.golden
index 282bb10..b9d1451 100644
--- a/src/go/doc/testdata/testing.1.golden
+++ b/src/go/doc/testdata/testing.1.golden
@@ -25,8 +25,8 @@ VARIABLES
 	// 
 	var (
 		// The short flag requests that tests run more quickly, but its functionality
-		// is provided by test writers themselves.  The testing package is just its
-		// home.  The all.bash installation script sets it to make installation more
+		// is provided by test writers themselves. The testing package is just its
+		// home. The all.bash installation script sets it to make installation more
 		// efficient, but by default the flag is off so a plain "go test" will do a
 		// full test of the package.
 		short	= flag.Bool("test.short", false, "run smaller test suite to save time")
@@ -151,13 +151,13 @@ TYPES
 	// SetBytes records the number of bytes processed in a single ...
 	func (b *B) SetBytes(n int64)
 
-	// StartTimer starts timing a test.  This function is called ...
+	// StartTimer starts timing a test. This function is called ...
 	func (b *B) StartTimer()
 
-	// StopTimer stops timing a test.  This can be used to pause the ...
+	// StopTimer stops timing a test. This can be used to pause the ...
 	func (b *B) StopTimer()
 
-	// launch launches the benchmark function.  It gradually increases ...
+	// launch launches the benchmark function. It gradually increases ...
 	func (b *B) launch()
 
 	// log generates the output. It's always at the same stack depth. 
diff --git a/src/go/doc/testdata/testing.2.golden b/src/go/doc/testdata/testing.2.golden
index f8348f1..83cf37c 100644
--- a/src/go/doc/testdata/testing.2.golden
+++ b/src/go/doc/testdata/testing.2.golden
@@ -78,10 +78,10 @@ TYPES
 	// SetBytes records the number of bytes processed in a single ...
 	func (b *B) SetBytes(n int64)
 
-	// StartTimer starts timing a test.  This function is called ...
+	// StartTimer starts timing a test. This function is called ...
 	func (b *B) StartTimer()
 
-	// StopTimer stops timing a test.  This can be used to pause the ...
+	// StopTimer stops timing a test. This can be used to pause the ...
 	func (b *B) StopTimer()
 
 	// The results of a benchmark run. 
diff --git a/src/go/doc/testdata/testing.go b/src/go/doc/testdata/testing.go
index 93ed494..52810f7 100644
--- a/src/go/doc/testdata/testing.go
+++ b/src/go/doc/testdata/testing.go
@@ -22,7 +22,7 @@
 //         }
 //     }
 // The benchmark package will vary b.N until the benchmark function lasts
-// long enough to be timed reliably.  The output
+// long enough to be timed reliably. The output
 //     testing.BenchmarkHello    10000000    282 ns/op
 // means that the loop ran 10000000 times at a speed of 282 ns per loop.
 //
@@ -51,8 +51,8 @@ import (
 
 var (
 	// The short flag requests that tests run more quickly, but its functionality
-	// is provided by test writers themselves.  The testing package is just its
-	// home.  The all.bash installation script sets it to make installation more
+	// is provided by test writers themselves. The testing package is just its
+	// home. The all.bash installation script sets it to make installation more
 	// efficient, but by default the flag is off so a plain "go test" will do a
 	// full test of the package.
 	short = flag.Bool("test.short", false, "run smaller test suite to save time")
@@ -152,9 +152,9 @@ func (c *common) FailNow() {
 	// This previous version duplicated code (those lines are in
 	// tRunner no matter what), but worse the goroutine teardown
 	// implicit in runtime.Goexit was not guaranteed to complete
-	// before the test exited.  If a test deferred an important cleanup
+	// before the test exited. If a test deferred an important cleanup
 	// function (like removing temporary files), there was no guarantee
-	// it would run on a test failure.  Because we send on c.signal during
+	// it would run on a test failure. Because we send on c.signal during
 	// a top-of-stack deferred function now, we know that the send
 	// only happens after any other stacked defers have completed.
 	runtime.Goexit()
diff --git a/src/go/format/internal.go b/src/go/format/internal.go
index 9d04878..b8b470d 100644
--- a/src/go/format/internal.go
+++ b/src/go/format/internal.go
@@ -28,9 +28,9 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
 ) {
 	// 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
+	// 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.
+	// try as a source fragment. Stop and return on any other error.
 	if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
 		return
 	}
@@ -59,7 +59,7 @@ func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
 
 	// 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.
+	// 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 '}'.
diff --git a/src/go/importer/importer.go b/src/go/importer/importer.go
index 560b853..f655bc1 100644
--- a/src/go/importer/importer.go
+++ b/src/go/importer/importer.go
@@ -31,7 +31,7 @@ func For(compiler string, lookup Lookup) types.Importer {
 		return make(gcimports)
 
 	case "gccgo":
-		if lookup == nil {
+		if lookup != nil {
 			panic("gccgo importer for custom import path lookup not yet implemented")
 		}
 
diff --git a/src/go/internal/gccgoimporter/importer.go b/src/go/internal/gccgoimporter/importer.go
index aa0d01a..19b9c73 100644
--- a/src/go/internal/gccgoimporter/importer.go
+++ b/src/go/internal/gccgoimporter/importer.go
@@ -88,12 +88,6 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e
 	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[:]) {
@@ -168,7 +162,7 @@ func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Impo
 		if err != nil {
 			return
 		}
-		_, err = reader.Seek(0, 0)
+		_, err = reader.Seek(0, io.SeekStart)
 		if err != nil {
 			return
 		}
diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go
index 6869042..75c2d91 100644
--- a/src/go/internal/gcimporter/bimport.go
+++ b/src/go/internal/gcimporter/bimport.go
@@ -11,10 +11,34 @@ import (
 	"go/token"
 	"go/types"
 	"sort"
+	"strings"
 	"unicode"
 	"unicode/utf8"
 )
 
+type importer struct {
+	imports map[string]*types.Package
+	data    []byte
+	path    string
+	buf     []byte // for reading strings
+	version string
+
+	// object lists
+	strList       []string         // in order of appearance
+	pkgList       []*types.Package // in order of appearance
+	typList       []types.Type     // in order of appearance
+	trackAllTypes bool
+
+	// position encoding
+	posInfoFormat bool
+	prevFile      string
+	prevLine      int
+
+	// debugging support
+	debugFormat bool
+	read        int // bytes read
+}
+
 // BImportData imports a package from the serialized package data
 // and returns the number of bytes consumed and a reference to the package.
 // If data is obviously malformed, an error is returned but in
@@ -23,11 +47,12 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
 	p := importer{
 		imports: imports,
 		data:    data,
+		path:    path,
+		strList: []string{""}, // empty string is mapped to 0
 	}
-	p.buf = p.bufarray[:]
 
 	// read low-level encoding format
-	switch format := p.byte(); format {
+	switch format := p.rawByte(); format {
 	case 'c':
 		// compact format - nothing to do
 	case 'd':
@@ -36,75 +61,49 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
 		return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
 	}
 
+	p.trackAllTypes = p.rawByte() == 'a'
+
+	p.posInfoFormat = p.int() != 0
+
 	// --- generic export data ---
 
-	if v := p.string(); v != "v0" {
-		return p.read, nil, fmt.Errorf("unknown version: %s", v)
+	p.version = p.string()
+	if p.version != "v0" && p.version != "v1" {
+		return p.read, nil, fmt.Errorf("unknown export data version: %s", p.version)
 	}
 
 	// populate typList with predeclared "known" types
 	p.typList = append(p.typList, predeclared...)
 
 	// read package data
-	// TODO(gri) clean this up
-	i := p.tagOrIndex()
-	if i != packageTag {
-		panic(fmt.Sprintf("package tag expected, got %d", i))
-	}
-	name := p.string()
-	if s := p.string(); s != "" {
-		panic(fmt.Sprintf("empty path expected, got %s", s))
-	}
-	pkg := p.imports[path]
-	if pkg == nil {
-		pkg = types.NewPackage(path, name)
-		p.imports[path] = pkg
-	}
-	p.pkgList = append(p.pkgList, pkg)
-
-	if debug && p.pkgList[0] != pkg {
-		panic("imported packaged not found in pkgList[0]")
-	}
-
-	// read compiler-specific flags
-	p.string() // discard
-
-	// read consts
-	for i := p.int(); i > 0; i-- {
-		name := p.string()
-		typ := p.typ(nil)
-		val := p.value()
-		p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
-	}
-
-	// read vars
-	for i := p.int(); i > 0; i-- {
-		name := p.string()
-		typ := p.typ(nil)
-		p.declare(types.NewVar(token.NoPos, pkg, name, typ))
-	}
-
-	// read funcs
-	for i := p.int(); i > 0; i-- {
-		name := p.string()
-		sig := p.typ(nil).(*types.Signature)
-		p.int() // read and discard index of inlined function body
-		p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
+	pkg := p.pkg()
+
+	// read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go)
+	objcount := 0
+	for {
+		tag := p.tagOrIndex()
+		if tag == endTag {
+			break
+		}
+		p.obj(tag)
+		objcount++
 	}
 
-	// read types
-	for i := p.int(); i > 0; i-- {
-		// name is parsed as part of named type and the
-		// type object is added to scope via respective
-		// named type
-		_ = p.typ(nil).(*types.Named)
+	// self-verification
+	if count := p.int(); count != objcount {
+		panic(fmt.Sprintf("got %d objects; want %d", objcount, count))
 	}
 
 	// ignore compiler-specific import data
 
 	// complete interfaces
 	for _, typ := range p.typList {
-		if it, ok := typ.(*types.Interface); ok {
+		// If we only record named types (!p.trackAllTypes),
+		// we must check the underlying types here. If we
+		// track all types, the Underlying() method call is
+		// not needed.
+		// TODO(gri) Remove if p.trackAllTypes is gone.
+		if it, ok := typ.Underlying().(*types.Interface); ok {
 			it.Complete()
 		}
 	}
@@ -120,25 +119,6 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
 	return p.read, pkg, nil
 }
 
-type importer struct {
-	imports  map[string]*types.Package
-	data     []byte
-	buf      []byte   // for reading strings
-	bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
-	pkgList  []*types.Package
-	typList  []types.Type
-
-	debugFormat bool
-	read        int // bytes read
-}
-
-func (p *importer) declare(obj types.Object) {
-	if alt := p.pkgList[0].Scope().Insert(obj); alt != nil {
-		// This can only happen if we import a package a second time.
-		panic(fmt.Sprintf("%s already declared", alt.Name()))
-	}
-}
-
 func (p *importer) pkg() *types.Package {
 	// if the package was seen before, i is its index (>= 0)
 	i := p.tagOrIndex()
@@ -160,22 +140,100 @@ func (p *importer) pkg() *types.Package {
 		panic("empty package name in import")
 	}
 
-	// we should never see an empty import path
-	if path == "" {
-		panic("empty import path")
+	// an empty path denotes the package we are currently importing;
+	// it must be the first package we see
+	if (path == "") != (len(p.pkgList) == 0) {
+		panic(fmt.Sprintf("package path %q for pkg index %d", path, len(p.pkgList)))
 	}
 
 	// if the package was imported before, use that one; otherwise create a new one
+	if path == "" {
+		path = p.path
+	}
 	pkg := p.imports[path]
 	if pkg == nil {
 		pkg = types.NewPackage(path, name)
 		p.imports[path] = pkg
+	} else if pkg.Name() != name {
+		panic(fmt.Sprintf("conflicting names %s and %s for package %q", pkg.Name(), name, path))
 	}
 	p.pkgList = append(p.pkgList, pkg)
 
 	return pkg
 }
 
+func (p *importer) declare(obj types.Object) {
+	pkg := obj.Pkg()
+	if alt := pkg.Scope().Insert(obj); alt != nil {
+		// This could only trigger if we import a (non-type) object a second time.
+		// This should never happen because 1) we only import a package once; and
+		// b) we ignore compiler-specific export data which may contain functions
+		// whose inlined function bodies refer to other functions that were already
+		// imported.
+		// (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj,
+		// switch case importing functions).
+		panic(fmt.Sprintf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", alt, obj))
+	}
+}
+
+func (p *importer) obj(tag int) {
+	switch tag {
+	case constTag:
+		p.pos()
+		pkg, name := p.qualifiedName()
+		typ := p.typ(nil)
+		val := p.value()
+		p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
+
+	case typeTag:
+		_ = p.typ(nil)
+
+	case varTag:
+		p.pos()
+		pkg, name := p.qualifiedName()
+		typ := p.typ(nil)
+		p.declare(types.NewVar(token.NoPos, pkg, name, typ))
+
+	case funcTag:
+		p.pos()
+		pkg, name := p.qualifiedName()
+		params, isddd := p.paramList()
+		result, _ := p.paramList()
+		sig := types.NewSignature(nil, params, result, isddd)
+		p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
+
+	default:
+		panic(fmt.Sprintf("unexpected object tag %d", tag))
+	}
+}
+
+func (p *importer) pos() {
+	if !p.posInfoFormat {
+		return
+	}
+
+	file := p.prevFile
+	line := p.prevLine
+	if delta := p.int(); delta != 0 {
+		// line changed
+		line += delta
+	} else if n := p.int(); n >= 0 {
+		// file changed
+		file = p.prevFile[:n] + p.string()
+		p.prevFile = file
+		line = p.int()
+	}
+	p.prevLine = line
+
+	// TODO(gri) register new position
+}
+
+func (p *importer) qualifiedName() (pkg *types.Package, name string) {
+	name = p.string()
+	pkg = p.pkg()
+	return
+}
+
 func (p *importer) record(t types.Type) {
 	p.typList = append(p.typList, t)
 }
@@ -205,8 +263,8 @@ func (p *importer) typ(parent *types.Package) types.Type {
 	switch i {
 	case namedTag:
 		// read type object
-		name := p.string()
-		parent = p.pkg()
+		p.pos()
+		parent, name := p.qualifiedName()
 		scope := parent.Scope()
 		obj := scope.Lookup(name)
 
@@ -231,17 +289,27 @@ func (p *importer) typ(parent *types.Package) types.Type {
 		t0.SetUnderlying(p.typ(parent))
 
 		// interfaces don't have associated methods
-		if _, ok := t0.Underlying().(*types.Interface); ok {
+		if types.IsInterface(t0) {
 			return t
 		}
 
 		// read associated methods
 		for i := p.int(); i > 0; i-- {
+			// TODO(gri) replace this with something closer to fieldName
+			p.pos()
 			name := p.string()
+			if !exported(name) {
+				p.pkg()
+			}
+
 			recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver?
 			params, isddd := p.paramList()
 			result, _ := p.paramList()
-			p.int() // read and discard index of inlined function body
+
+			if p.version == "v1" {
+				p.int() // nointerface flag - discarded
+			}
+
 			sig := types.NewSignature(recv.At(0), params, result, isddd)
 			t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig))
 		}
@@ -250,7 +318,9 @@ func (p *importer) typ(parent *types.Package) types.Type {
 
 	case arrayTag:
 		t := new(types.Array)
-		p.record(t)
+		if p.trackAllTypes {
+			p.record(t)
+		}
 
 		n := p.int64()
 		*t = *types.NewArray(p.typ(parent), n)
@@ -258,42 +328,45 @@ func (p *importer) typ(parent *types.Package) types.Type {
 
 	case sliceTag:
 		t := new(types.Slice)
-		p.record(t)
+		if p.trackAllTypes {
+			p.record(t)
+		}
 
 		*t = *types.NewSlice(p.typ(parent))
 		return t
 
 	case dddTag:
 		t := new(dddSlice)
-		p.record(t)
+		if p.trackAllTypes {
+			p.record(t)
+		}
 
 		t.elem = p.typ(parent)
 		return t
 
 	case structTag:
 		t := new(types.Struct)
-		p.record(t)
-
-		n := p.int()
-		fields := make([]*types.Var, n)
-		tags := make([]string, n)
-		for i := range fields {
-			fields[i] = p.field(parent)
-			tags[i] = p.string()
+		if p.trackAllTypes {
+			p.record(t)
 		}
-		*t = *types.NewStruct(fields, tags)
+
+		*t = *types.NewStruct(p.fieldList(parent))
 		return t
 
 	case pointerTag:
 		t := new(types.Pointer)
-		p.record(t)
+		if p.trackAllTypes {
+			p.record(t)
+		}
 
 		*t = *types.NewPointer(p.typ(parent))
 		return t
 
 	case signatureTag:
 		t := new(types.Signature)
-		p.record(t)
+		if p.trackAllTypes {
+			p.record(t)
+		}
 
 		params, isddd := p.paramList()
 		result, _ := p.paramList()
@@ -306,30 +379,26 @@ func (p *importer) typ(parent *types.Package) types.Type {
 		// such cycle must contain a named type which would have been
 		// first defined earlier.
 		n := len(p.typList)
-		p.record(nil)
+		if p.trackAllTypes {
+			p.record(nil)
+		}
 
 		// no embedded interfaces with gc compiler
 		if p.int() != 0 {
 			panic("unexpected embedded interface")
 		}
 
-		// read methods
-		methods := make([]*types.Func, p.int())
-		for i := range methods {
-			pkg, name := p.fieldName(parent)
-			params, isddd := p.paramList()
-			result, _ := p.paramList()
-			sig := types.NewSignature(nil, params, result, isddd)
-			methods[i] = types.NewFunc(token.NoPos, pkg, name, sig)
+		t := types.NewInterface(p.methodList(parent), nil)
+		if p.trackAllTypes {
+			p.typList[n] = t
 		}
-
-		t := types.NewInterface(methods, nil)
-		p.typList[n] = t
 		return t
 
 	case mapTag:
 		t := new(types.Map)
-		p.record(t)
+		if p.trackAllTypes {
+			p.record(t)
+		}
 
 		key := p.typ(parent)
 		val := p.typ(parent)
@@ -338,7 +407,9 @@ func (p *importer) typ(parent *types.Package) types.Type {
 
 	case chanTag:
 		t := new(types.Chan)
-		p.record(t)
+		if p.trackAllTypes {
+			p.record(t)
+		}
 
 		var dir types.ChanDir
 		// tag values must match the constants in cmd/compile/internal/gc/go.go
@@ -361,7 +432,20 @@ func (p *importer) typ(parent *types.Package) types.Type {
 	}
 }
 
+func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags []string) {
+	if n := p.int(); n > 0 {
+		fields = make([]*types.Var, n)
+		tags = make([]string, n)
+		for i := range fields {
+			fields[i] = p.field(parent)
+			tags[i] = p.string()
+		}
+	}
+	return
+}
+
 func (p *importer) field(parent *types.Package) *types.Var {
+	p.pos()
 	pkg, name := p.fieldName(parent)
 	typ := p.typ(parent)
 
@@ -383,6 +467,25 @@ func (p *importer) field(parent *types.Package) *types.Var {
 	return types.NewField(token.NoPos, pkg, name, typ, anonymous)
 }
 
+func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
+	if n := p.int(); n > 0 {
+		methods = make([]*types.Func, n)
+		for i := range methods {
+			methods[i] = p.method(parent)
+		}
+	}
+	return
+}
+
+func (p *importer) method(parent *types.Package) *types.Func {
+	p.pos()
+	pkg, name := p.fieldName(parent)
+	params, isddd := p.paramList()
+	result, _ := p.paramList()
+	sig := types.NewSignature(nil, params, result, isddd)
+	return types.NewFunc(token.NoPos, pkg, name, sig)
+}
+
 func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
 	pkg := parent
 	if pkg == nil {
@@ -430,18 +533,25 @@ func (p *importer) param(named bool) (*types.Var, bool) {
 		t = types.NewSlice(td.elem)
 	}
 
+	var pkg *types.Package
 	var name string
 	if named {
 		name = p.string()
 		if name == "" {
 			panic("expected named parameter")
 		}
+		if name != "_" {
+			pkg = p.pkg()
+		}
+		if i := strings.Index(name, "·"); i > 0 {
+			name = name[:i] // cut off gc-specific parameter numbering
+		}
 	}
 
 	// read and discard compiler-specific info
 	p.string()
 
-	return types.NewVar(token.NoPos, nil, name, t), isddd
+	return types.NewVar(token.NoPos, pkg, name, t), isddd
 }
 
 func exported(name string) bool {
@@ -546,24 +656,28 @@ func (p *importer) string() string {
 	if p.debugFormat {
 		p.marker('s')
 	}
-
-	if n := int(p.rawInt64()); n > 0 {
-		if cap(p.buf) < n {
-			p.buf = make([]byte, n)
-		} else {
-			p.buf = p.buf[:n]
-		}
-		for i := 0; i < n; i++ {
-			p.buf[i] = p.byte()
-		}
-		return string(p.buf)
+	// if the string was seen before, i is its index (>= 0)
+	// (the empty string is at index 0)
+	i := p.rawInt64()
+	if i >= 0 {
+		return p.strList[i]
 	}
-
-	return ""
+	// otherwise, i is the negative string length (< 0)
+	if n := int(-i); n <= cap(p.buf) {
+		p.buf = p.buf[:n]
+	} else {
+		p.buf = make([]byte, n)
+	}
+	for i := range p.buf {
+		p.buf[i] = p.rawByte()
+	}
+	s := string(p.buf)
+	p.strList = append(p.strList, s)
+	return s
 }
 
 func (p *importer) marker(want byte) {
-	if got := p.byte(); got != want {
+	if got := p.rawByte(); got != want {
 		panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read))
 	}
 
@@ -584,12 +698,13 @@ func (p *importer) rawInt64() int64 {
 
 // needed for binary.ReadVarint in rawInt64
 func (p *importer) ReadByte() (byte, error) {
-	return p.byte(), nil
+	return p.rawByte(), nil
 }
 
 // byte is the bottleneck interface for reading p.data.
 // It unescapes '|' 'S' to '$' and '|' '|' to '|'.
-func (p *importer) byte() byte {
+// rawByte should only be used by low-level decoders.
+func (p *importer) rawByte() byte {
 	b := p.data[0]
 	r := 1
 	if b == '|' {
@@ -615,8 +730,13 @@ func (p *importer) byte() byte {
 
 // Tags. Must be < 0.
 const (
-	// Packages
+	// Objects
 	packageTag = -(iota + 1)
+	constTag
+	typeTag
+	varTag
+	funcTag
+	endTag
 
 	// Types
 	namedTag
@@ -638,6 +758,7 @@ const (
 	fractionTag // not used by gc
 	complexTag
 	stringTag
+	unknownTag // not used by gc (only appears in packages with errors)
 )
 
 var predeclared = []types.Type{
@@ -678,4 +799,15 @@ var predeclared = []types.Type{
 
 	// package unsafe
 	types.Typ[types.UnsafePointer],
+
+	// invalid type
+	types.Typ[types.Invalid], // only appears in packages with errors
+
+	// used internally by gc; never used by this package or in .a files
+	anyType{},
 }
+
+type anyType struct{}
+
+func (t anyType) Underlying() types.Type { return t }
+func (t anyType) String() string         { return "any" }
diff --git a/src/go/internal/gcimporter/exportdata.go b/src/go/internal/gcimporter/exportdata.go
index 18bea41..4c0d2fe 100644
--- a/src/go/internal/gcimporter/exportdata.go
+++ b/src/go/internal/gcimporter/exportdata.go
@@ -52,33 +52,11 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
 	if string(line) == "!<arch>\n" {
 		// Archive file. Scan to __.PKGDEF.
 		var name string
-		var size int
-		if name, size, err = readGopackHeader(r); err != nil {
+		if name, _, 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, _, err = readGopackHeader(r); err != nil {
-				return
-			}
-		}
-
-		// First real entry should be __.PKGDEF.
+		// First entry should be __.PKGDEF.
 		if name != "__.PKGDEF" {
 			err = errors.New("go archive is missing __.PKGDEF")
 			return
diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go
index d70ec08..2c6e676 100644
--- a/src/go/internal/gcimporter/gcimporter.go
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -163,7 +163,7 @@ func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types
 		var data []byte
 		data, err = ioutil.ReadAll(buf)
 		if err == nil {
-			_, pkg, err = BImportData(packages, data, path)
+			_, pkg, err = BImportData(packages, data, id)
 			return
 		}
 	default:
@@ -385,7 +385,7 @@ func (p *parser) getPkg(id, name string) *types.Package {
 		if pname := pkg.Name(); pname == "" {
 			pkg.SetName(name)
 		} else if pname != name {
-			p.errorf("%s package name mismatch: %s (given) vs %s (expected)", pname, name)
+			p.errorf("%s package name mismatch: %s (given) vs %s (expected)", id, pname, name)
 		}
 	}
 	return pkg
@@ -451,7 +451,7 @@ func (p *parser) parseMapType(parent *types.Package) types.Type {
 // For qualified names, the returned package is nil (and not created if
 // it doesn't exist yet) unless materializePkg is set (which creates an
 // unnamed package with valid package path). In the latter case, a
-// subequent import clause is expected to provide a name for the package.
+// subsequent import clause is expected to provide a name for the package.
 //
 func (p *parser) parseName(parent *types.Package, materializePkg bool) (pkg *types.Package, name string) {
 	pkg = parent
diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go
index e56720b..d8c5bcf 100644
--- a/src/go/internal/gcimporter/gcimporter_test.go
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -351,9 +351,9 @@ func TestIssue13898(t *testing.T) {
 	}
 
 	// lookup go/types.Object.Pkg method
-	m, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Pkg")
+	m, index, indirect := types.LookupFieldOrMethod(typ, false, nil, "Pkg")
 	if m == nil {
-		t.Fatal("go/types.Object.Pkg not found")
+		t.Fatalf("go/types.Object.Pkg not found (index = %v, indirect = %v)", index, indirect)
 	}
 
 	// the method must belong to go/types
@@ -361,3 +361,67 @@ func TestIssue13898(t *testing.T) {
 		t.Fatalf("found %v; want go/types", m.Pkg())
 	}
 }
+
+func TestIssue15517(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
+	}
+
+	// On windows, we have to set the -D option for the compiler to avoid having a drive
+	// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+	if runtime.GOOS == "windows" {
+		t.Skip("avoid dealing with relative paths/drive letters on windows")
+	}
+
+	if f := compile(t, "testdata", "p.go"); f != "" {
+		defer os.Remove(f)
+	}
+
+	// Multiple imports of p must succeed without redeclaration errors.
+	// We use an import path that's not cleaned up so that the eventual
+	// file path for the package is different from the package path; this
+	// will expose the error if it is present.
+	//
+	// (Issue: Both the textual and the binary importer used the file path
+	// of the package to be imported as key into the shared packages map.
+	// However, the binary importer then used the package path to identify
+	// the imported package to mark it as complete; effectively marking the
+	// wrong package as complete. By using an "unclean" package path, the
+	// file and package path are different, exposing the problem if present.
+	// The same issue occurs with vendoring.)
+	imports := make(map[string]*types.Package)
+	for i := 0; i < 3; i++ {
+		if _, err := Import(imports, "./././testdata/p", "."); err != nil {
+			t.Fatal(err)
+		}
+	}
+}
+
+func TestIssue15920(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
+	}
+
+	// On windows, we have to set the -D option for the compiler to avoid having a drive
+	// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
+	if runtime.GOOS == "windows" {
+		t.Skip("avoid dealing with relative paths/drive letters on windows")
+	}
+
+	if f := compile(t, "testdata", "issue15920.go"); f != "" {
+		defer os.Remove(f)
+	}
+
+	imports := make(map[string]*types.Package)
+	if _, err := Import(imports, "./testdata/issue15920", "."); err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/src/go/internal/gcimporter/testdata/issue15920.go b/src/go/internal/gcimporter/testdata/issue15920.go
new file mode 100644
index 0000000..c70f7d8
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/issue15920.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. 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
+
+// The underlying type of Error is the underlying type of error.
+// Make sure we can import this again without problems.
+type Error error
+
+func F() Error { return nil }
diff --git a/src/go/internal/gcimporter/testdata/p.go b/src/go/internal/gcimporter/testdata/p.go
new file mode 100644
index 0000000..9e2e705
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/p.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Input for TestIssue15517
+
+package p
+
+const C = 0
+
+var V int
+
+func F() {}
diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go
index c6fd932..bff79ca 100644
--- a/src/go/parser/interface.go
+++ b/src/go/parser/interface.go
@@ -73,7 +73,7 @@ const (
 //
 // The mode parameter controls the amount of source text parsed and other
 // optional parser functionality. Position information is recorded in the
-// file set fset.
+// file set fset, which must not be nil.
 //
 // If the source couldn't be read, the returned AST is nil and the error
 // indicates the specific failure. If the source was read but syntax
@@ -82,6 +82,10 @@ const (
 // are returned via a scanner.ErrorList which is sorted by file position.
 //
 func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *ast.File, err error) {
+	if fset == nil {
+		panic("parser.ParseFile: no token.FileSet provided (fset == nil)")
+	}
+
 	// get source
 	text, err := readSource(filename, src)
 	if err != nil {
@@ -125,7 +129,8 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode)
 //
 // If filter != nil, only the files with os.FileInfo entries passing through
 // the filter (and ending in ".go") are considered. The mode bits are passed
-// to ParseFile unchanged. Position information is recorded in fset.
+// to ParseFile unchanged. Position information is recorded in fset, which
+// must not be nil.
 //
 // If the directory couldn't be read, a nil map and the respective error are
 // returned. If a parse error occurred, a non-nil but incomplete map and the
@@ -169,9 +174,14 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
 
 // 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.
+// be a valid Go (type or value) expression. Specifically, fset must not
+// be nil.
 //
 func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (ast.Expr, error) {
+	if fset == nil {
+		panic("parser.ParseExprFrom: no token.FileSet provided (fset == nil)")
+	}
+
 	// get source
 	text, err := readSource(filename, src)
 	if err != nil {
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index f3a2603..d3ef7db 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -1597,23 +1597,19 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
 	}
 
 	x := p.parseUnaryExpr(lhs)
-	for _, prec := p.tokPrec(); prec >= prec1; prec-- {
-		for {
-			op, oprec := p.tokPrec()
-			if oprec != prec {
-				break
-			}
-			pos := p.expect(op)
-			if lhs {
-				p.resolve(x)
-				lhs = false
-			}
-			y := p.parseBinaryExpr(false, prec+1)
-			x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
+	for {
+		op, oprec := p.tokPrec()
+		if oprec < prec1 {
+			return x
+		}
+		pos := p.expect(op)
+		if lhs {
+			p.resolve(x)
+			lhs = false
 		}
+		y := p.parseBinaryExpr(false, oprec+1)
+		x = &ast.BinaryExpr{X: p.checkExpr(x), OpPos: pos, Op: op, Y: p.checkExpr(y)}
 	}
-
-	return x
 }
 
 // If lhs is set and the result is an identifier, it is not resolved.
diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go
index e9476c4..ce660c7 100644
--- a/src/go/scanner/scanner.go
+++ b/src/go/scanner/scanner.go
@@ -26,7 +26,7 @@ import (
 type ErrorHandler func(pos token.Position, msg string)
 
 // A Scanner holds the scanner's internal state while processing
-// a given text.  It can be allocated as part of another data
+// a given text. It can be allocated as part of another data
 // structure but must be initialized via Init before use.
 //
 type Scanner struct {
@@ -64,7 +64,7 @@ func (s *Scanner) next() {
 		switch {
 		case r == 0:
 			s.error(s.offset, "illegal character NUL")
-		case r >= 0x80:
+		case r >= utf8.RuneSelf:
 			// not ASCII
 			r, w = utf8.DecodeRune(s.src[s.rdOffset:])
 			if r == utf8.RuneError && w == 1 {
@@ -255,11 +255,11 @@ func (s *Scanner) findLineEnd() bool {
 }
 
 func isLetter(ch rune) bool {
-	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch)
+	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch)
 }
 
 func isDigit(ch rune) bool {
-	return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch)
+	return '0' <= ch && ch <= '9' || ch >= utf8.RuneSelf && unicode.IsDigit(ch)
 }
 
 func (s *Scanner) scanIdentifier() string {
diff --git a/src/go/token/position.go b/src/go/token/position.go
index 3375177..7306083 100644
--- a/src/go/token/position.go
+++ b/src/go/token/position.go
@@ -164,6 +164,7 @@ func (f *File) MergeLine(line int) {
 // Each line offset must be larger than the offset for the previous line
 // and smaller than the file size; otherwise SetLines fails and returns
 // false.
+// Callers must not mutate the provided slice after SetLines returns.
 //
 func (f *File) SetLines(lines []int) bool {
 	// verify validity of lines table
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
index c2feed3..035ffd6 100644
--- a/src/go/types/api_test.go
+++ b/src/go/types/api_test.go
@@ -572,6 +572,47 @@ func TestInitOrderInfo(t *testing.T) {
 		`, []string{
 			"a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
 		}},
+		// test case for issue 10709
+		// TODO(gri) enable once the issue is fixed
+		// {`package p13
+
+		// var (
+		//     v = t.m()
+		//     t = makeT(0)
+		// )
+
+		// type T struct{}
+
+		// func (T) m() int { return 0 }
+
+		// func makeT(n int) T {
+		//     if n > 0 {
+		//         return makeT(n-1)
+		//     }
+		//     return T{}
+		// }`, []string{
+		// 	"t = makeT(0)", "v = t.m()",
+		// }},
+		// test case for issue 10709: same as test before, but variable decls swapped
+		{`package p14
+
+		var (
+		    t = makeT(0)
+		    v = t.m()
+		)
+
+		type T struct{}
+
+		func (T) m() int { return 0 }
+
+		func makeT(n int) T {
+		    if n > 0 {
+		        return makeT(n-1)
+		    }
+		    return T{}
+		}`, []string{
+			"t = makeT(0)", "v = t.m()",
+		}},
 	}
 
 	for _, test := range tests {
@@ -1042,3 +1083,45 @@ func f() {
 		}
 	}
 }
+
+func TestIdentical_issue15173(t *testing.T) {
+	// Identical should allow nil arguments and be symmetric.
+	for _, test := range []struct {
+		x, y Type
+		want bool
+	}{
+		{Typ[Int], Typ[Int], true},
+		{Typ[Int], nil, false},
+		{nil, Typ[Int], false},
+		{nil, nil, true},
+	} {
+		if got := Identical(test.x, test.y); got != test.want {
+			t.Errorf("Identical(%v, %v) = %t", test.x, test.y, got)
+		}
+	}
+}
+
+func TestIssue15305(t *testing.T) {
+	const src = "package p; func f() int16; var _ = f(undef)"
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, "issue15305.go", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	conf := Config{
+		Error: func(err error) {}, // allow errors
+	}
+	info := &Info{
+		Types: make(map[ast.Expr]TypeAndValue),
+	}
+	conf.Check("p", fset, []*ast.File{f}, info) // ignore result
+	for e, tv := range info.Types {
+		if _, ok := e.(*ast.CallExpr); ok {
+			if tv.Type != Typ[Int16] {
+				t.Errorf("CallExpr has type %v, want int16", tv.Type)
+			}
+			return
+		}
+	}
+	t.Errorf("CallExpr has no type")
+}
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
index 10ab17b..6ebf3b5 100644
--- a/src/go/types/assignments.go
+++ b/src/go/types/assignments.go
@@ -179,6 +179,14 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
 	case variable, mapindex:
 		// ok
 	default:
+		if sel, ok := z.expr.(*ast.SelectorExpr); ok {
+			var op operand
+			check.expr(&op, sel.X)
+			if op.mode == mapindex {
+				check.errorf(z.pos(), "cannot assign to struct field %s in map", ExprString(z.expr))
+				return nil
+			}
+		}
 		check.errorf(z.pos(), "cannot assign to %s", &z)
 		return nil
 	}
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
index 803264f..0082be9 100644
--- a/src/go/types/builtins.go
+++ b/src/go/types/builtins.go
@@ -366,7 +366,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
 			} else {
 				// an untyped non-constant argument may appear if
 				// it contains a (yet untyped non-constant) shift
-				// epression: convert it to complex128 which will
+				// expression: convert it to complex128 which will
 				// result in an error (shift of complex value)
 				check.convertUntyped(x, Typ[Complex128])
 				// x should be invalid now, but be conservative and check
diff --git a/src/go/types/call.go b/src/go/types/call.go
index 8aeb862..45f3e9a 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -62,14 +62,12 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
 		}
 
 		arg, n, _ := unpack(func(x *operand, i int) { check.multiExpr(x, e.Args[i]) }, len(e.Args), false)
-		if arg == nil {
+		if arg != nil {
+			check.arguments(x, e, sig, arg, n)
+		} else {
 			x.mode = invalid
-			x.expr = e
-			return statement
 		}
 
-		check.arguments(x, e, sig, arg, n)
-
 		// determine result
 		switch sig.results.Len() {
 		case 0:
@@ -81,6 +79,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
 			x.mode = value
 			x.typ = sig.results
 		}
+
 		x.expr = e
 		check.hasCallOrRecv = true
 
diff --git a/src/go/types/check.go b/src/go/types/check.go
index bb0b074..0279be0 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -215,7 +215,9 @@ func (check *Checker) handleBailout(err *error) {
 }
 
 // Files checks the provided files as part of the checker's package.
-func (check *Checker) Files(files []*ast.File) (err error) {
+func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) }
+
+func (check *Checker) checkFiles(files []*ast.File) (err error) {
 	defer check.handleBailout(&err)
 
 	check.initFiles(files)
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index f064f68..1ecfb35 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -141,6 +141,14 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
 	// determine type, if any
 	if typ != nil {
 		obj.typ = check.typ(typ)
+		// We cannot spread the type to all lhs variables if there
+		// are more than one since that would mark them as checked
+		// (see Checker.objDecl) and the assignment of init exprs,
+		// if any, would not be checked.
+		//
+		// TODO(gri) If we have no init expr, we should distribute
+		// a given type otherwise we need to re-evalate the type
+		// expr for each lhs variable, leading to duplicate work.
 	}
 
 	// check initialization
@@ -173,6 +181,17 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
 			panic("inconsistent lhs")
 		}
 	}
+
+	// We have multiple variables on the lhs and one init expr.
+	// Make sure all variables have been given the same type if
+	// one was specified, otherwise they assume the type of the
+	// init expression values (was issue #15755).
+	if typ != nil {
+		for _, lhs := range lhs {
+			lhs.typ = obj.typ
+		}
+	}
+
 	check.initVars(lhs, []ast.Expr{init}, token.NoPos)
 }
 
diff --git a/src/go/types/eval.go b/src/go/types/eval.go
index 7b42ff1..831d771 100644
--- a/src/go/types/eval.go
+++ b/src/go/types/eval.go
@@ -34,7 +34,7 @@ import (
 // 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) {
+func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (TypeAndValue, error) {
 	// determine scope
 	var scope *Scope
 	if pkg == nil {
@@ -44,7 +44,7 @@ func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (tv Typ
 		scope = pkg.scope
 	} else {
 		// The package scope extent (position information) may be
-		// incorrect (files spread accross a wide range of fset
+		// incorrect (files spread across a wide range of fset
 		// positions) - ignore it and just consider its children
 		// (file scopes).
 		for _, fscope := range pkg.scope.children {
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index f7c4a17..4430c45 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -660,10 +660,10 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
 				return
 			}
 			// rhs must be within reasonable bounds
-			const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64
+			const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64
 			s, ok := constant.Uint64Val(yval)
-			if !ok || s > stupidShift {
-				check.invalidOp(y.pos(), "stupid shift count %s", y)
+			if !ok || s > shiftBound {
+				check.invalidOp(y.pos(), "invalid shift count %s", y)
 				x.mode = invalid
 				return
 			}
diff --git a/src/go/types/hilbert_test.go b/src/go/types/hilbert_test.go
index cfd51b1..3b56a82 100644
--- a/src/go/types/hilbert_test.go
+++ b/src/go/types/hilbert_test.go
@@ -193,19 +193,6 @@ func (g *gen) printProduct(n int) {
 	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 (
diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go
index 0fd567b..cf9b870 100644
--- a/src/go/types/initorder.go
+++ b/src/go/types/initorder.go
@@ -12,28 +12,43 @@ import (
 // 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.
+	// 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
+	// Compute the transposed 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())
+		fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
+		fmt.Println("Object dependency graph:")
+		for obj, d := range check.objMap {
+			if len(d.deps) > 0 {
+				fmt.Printf("\t%s depends on\n", obj.Name())
+				for dep := range d.deps {
+					fmt.Printf("\t\t%s\n", dep.Name())
+				}
+			} else {
+				fmt.Printf("\t%s has no dependencies\n", obj.Name())
+			}
+		}
+		fmt.Println()
+
+		fmt.Println("Transposed object dependency graph:")
 		for _, n := range pq {
-			for _, o := range n.out {
-				fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
+			fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.in)
+			for _, out := range n.out {
+				fmt.Printf("\t\t%s is dependent\n", out.obj.Name())
 			}
 		}
 		fmt.Println()
-		fmt.Printf("package %s: initialization order\n", check.pkg.Name())
+
+		fmt.Println("Processing nodes:")
 	}
 
-	// determine initialization order by removing the highest priority node
+	// 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
@@ -45,6 +60,11 @@ func (check *Checker) initOrder() {
 		// get the next node
 		n := heap.Pop(&pq).(*objNode)
 
+		if debug {
+			fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
+				n.obj.Name(), n.obj.order(), n.in)
+		}
+
 		// if n still depends on other nodes, we have a cycle
 		if n.in > 0 {
 			mark++ // mark nodes using a different value each time
@@ -86,14 +106,15 @@ func (check *Checker) initOrder() {
 		}
 		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()
+		fmt.Println("Initialization order:")
+		for _, init := range check.Info.InitOrder {
+			fmt.Printf("\t%s\n", init)
+		}
+		fmt.Println()
 	}
 }
 
diff --git a/src/go/types/labels.go b/src/go/types/labels.go
index 7364d4d..3b43b4b 100644
--- a/src/go/types/labels.go
+++ b/src/go/types/labels.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/go/types/object.go b/src/go/types/object.go
index b835c6e..707b806 100644
--- a/src/go/types/object.go
+++ b/src/go/types/object.go
@@ -188,7 +188,7 @@ 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.
+// (interface) method. Its Type() is always a *Signature.
 // An abstract method may belong to many interfaces due to embedding.
 type Func struct {
 	object
diff --git a/src/go/types/package.go b/src/go/types/package.go
index 4a432b5..a588ee7 100644
--- a/src/go/types/package.go
+++ b/src/go/types/package.go
@@ -55,7 +55,7 @@ func (pkg *Package) MarkComplete() { pkg.complete = true }
 // 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
+// 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 }
 
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
index 993c6d2..5509069 100644
--- a/src/go/types/predicates.go
+++ b/src/go/types/predicates.go
@@ -277,6 +277,8 @@ func identical(x, y Type, p *ifacePair) bool {
 			return x.obj == y.obj
 		}
 
+	case nil:
+
 	default:
 		unreachable()
 	}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index 1536df5..cb8e72e 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -32,7 +32,7 @@ func (d *declInfo) hasInitializer() bool {
 	return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
 }
 
-// addDep adds obj as a dependency to d.
+// addDep adds obj to the set of objects d's init expression depends on.
 func (d *declInfo) addDep(obj Object) {
 	m := d.deps
 	if m == nil {
@@ -67,7 +67,7 @@ func (check *Checker) arityMatch(s, init *ast.ValueSpec) {
 			// TODO(gri) avoid declared but not used error here
 		} else {
 			// init exprs "inherited"
-			check.errorf(s.Pos(), "extra init expr at %s", init.Pos())
+			check.errorf(s.Pos(), "extra init expr at %s", check.fset.Position(init.Pos()))
 			// TODO(gri) avoid declared but not used error here
 		}
 	case l > r && (init != nil || r != 1):
diff --git a/src/go/types/return.go b/src/go/types/return.go
index 6628985..0c1447f 100644
--- a/src/go/types/return.go
+++ b/src/go/types/return.go
@@ -83,8 +83,13 @@ func (check *Checker) isTerminating(s ast.Stmt, label string) bool {
 }
 
 func (check *Checker) isTerminatingList(list []ast.Stmt, label string) bool {
-	n := len(list)
-	return n > 0 && check.isTerminating(list[n-1], label)
+	// trailing empty statements are permitted - skip them
+	for i := len(list) - 1; i >= 0; i-- {
+		if _, ok := list[i].(*ast.EmptyStmt); !ok {
+			return check.isTerminating(list[i], label)
+		}
+	}
+	return false // all statements are empty
 }
 
 func (check *Checker) isTerminatingSwitch(body *ast.BlockStmt, label string) bool {
diff --git a/src/go/types/scope.go b/src/go/types/scope.go
index 3502840..b5d34d6 100644
--- a/src/go/types/scope.go
+++ b/src/go/types/scope.go
@@ -31,7 +31,7 @@ type Scope struct {
 }
 
 // NewScope returns a new, empty scope contained in the given parent
-// scope, if any.  The comment is for debugging only.
+// 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!
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
index 09f2585..bd5afaf 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -155,6 +155,7 @@ func TestStdFixed(t *testing.T) {
 		"issue6889.go",  // gc-specific test
 		"issue7746.go",  // large constants - consumes too much memory
 		"issue11362.go", // canonical import path check
+		"issue15002.go", // uses Mmap; testTestDir should consult build tags
 	)
 }
 
@@ -266,13 +267,16 @@ func walkDirs(t *testing.T, dir string) {
 	}
 
 	// typecheck package in directory
-	files, err := pkgFilenames(dir)
-	if err != nil {
-		t.Error(err)
-		return
-	}
-	if files != nil {
-		typecheck(t, dir, files)
+	// but ignore files directly under $GOROOT/src (might be temporary test files).
+	if dir != filepath.Join(runtime.GOROOT(), "src") {
+		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
diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go
index e0129cf..5764430 100644
--- a/src/go/types/stmt.go
+++ b/src/go/types/stmt.go
@@ -83,9 +83,19 @@ func (check *Checker) simpleStmt(s ast.Stmt) {
 	}
 }
 
+func trimTrailingEmptyStmts(list []ast.Stmt) []ast.Stmt {
+	for i := len(list); i > 0; i-- {
+		if _, ok := list[i-1].(*ast.EmptyStmt); !ok {
+			return list[:i]
+		}
+	}
+	return nil
+}
+
 func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
 	ok := ctxt&fallthroughOk != 0
 	inner := ctxt &^ fallthroughOk
+	list = trimTrailingEmptyStmts(list) // trailing empty statements are "invisible" to fallthrough analysis
 	for i, s := range list {
 		inner := inner
 		if ok && i+1 == len(list) {
@@ -113,7 +123,7 @@ func (check *Checker) multipleDefaults(list []ast.Stmt) {
 		}
 		if d != nil {
 			if first != nil {
-				check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos())
+				check.errorf(d.Pos(), "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
 			} else {
 				first = d
 			}
@@ -346,7 +356,17 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
 			check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
 			return
 		}
+
 		var x operand
+		check.expr(&x, s.X)
+		if x.mode == invalid {
+			return
+		}
+		if !isNumeric(x.typ) {
+			check.invalidOp(s.X.Pos(), "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
+			return
+		}
+
 		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 {
diff --git a/src/go/types/testdata/const0.src b/src/go/types/testdata/const0.src
index 716a590..a617178 100644
--- a/src/go/types/testdata/const0.src
+++ b/src/go/types/testdata/const0.src
@@ -239,7 +239,7 @@ const (
 
 type A [iota /* ERROR "cannot use iota" */ ]int
 
-// constant expressions with operands accross different
+// constant expressions with operands across different
 // constant declarations must use the right iota values
 const (
 	_c0 = iota
diff --git a/src/go/types/testdata/gotos.src b/src/go/types/testdata/gotos.src
index 0c7ee44..069a94b 100644
--- a/src/go/types/testdata/gotos.src
+++ b/src/go/types/testdata/gotos.src
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/go/types/testdata/issues.src b/src/go/types/testdata/issues.src
index 4fe0c62..6579aa3 100644
--- a/src/go/types/testdata/issues.src
+++ b/src/go/types/testdata/issues.src
@@ -170,3 +170,19 @@ func issue14229() {
 		_ = b % a
 	)
 }
+
+// Check that in a n:1 variable declaration with type and initialization
+// expression the type is distributed to all variables of the lhs before
+// the initialization expression assignment is checked.
+func issue15755() {
+	// from issue
+	var i interface{}
+	type b bool
+	var x, y b = i.(b)
+	_ = x == y
+
+	// related: we should see an error since the result of f1 is ([]int, int)
+	var u, v []int = f1 /* ERROR cannot use f1 */ ()
+	_ = u
+	_ = v
+}
diff --git a/src/go/types/testdata/labels.src b/src/go/types/testdata/labels.src
index 102ffc7..9f42406 100644
--- a/src/go/types/testdata/labels.src
+++ b/src/go/types/testdata/labels.src
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/go/types/testdata/shifts.src b/src/go/types/testdata/shifts.src
index 64865fc..099c9ec 100644
--- a/src/go/types/testdata/shifts.src
+++ b/src/go/types/testdata/shifts.src
@@ -10,8 +10,8 @@ func shifts0() {
 		s = 10
 		_ = 0<<0
 		_ = 1<<s
-		_ = 1<<- /* ERROR "stupid shift" */ 1
-		_ = 1<<1075 /* ERROR "stupid shift" */
+		_ = 1<<- /* ERROR "invalid shift" */ 1
+		_ = 1<<1075 /* ERROR "invalid shift" */
 		_ = 2.0<<1
 
 		_ int = 2<<s
@@ -338,4 +338,4 @@ func issue11594() {
 	_ = 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
index b7966ed..0c727c3 100644
--- a/src/go/types/testdata/stmt0.src
+++ b/src/go/types/testdata/stmt0.src
@@ -137,7 +137,7 @@ func issue6487() {
 
 	type M map[string]S
 	var m M
-	m /* ERROR "cannot assign" */ ["foo"].x = 0
+	m /* ERROR "cannot assign to struct field" */ ["foo"].x = 0
 	_ = &( /* ERROR "cannot take address" */ m["foo"].x)
 	_ = &m /* ERROR "cannot take address" */ ["foo"].x
 }
@@ -164,7 +164,7 @@ func incdecs() {
 	const c = 3.14
 	c /* ERROR "cannot assign" */ ++
 	s := "foo"
-	s /* ERROR "cannot convert" */ --
+	s /* ERROR "invalid operation" */ --
 	3.14 /* ERROR "cannot assign" */ ++
 	var (
 		x int
@@ -531,16 +531,18 @@ func switches1() {
 	case 1:
 		fallthrough
 	case 2:
-	default:
-		fallthrough
+		fallthrough; ; ; // trailing empty statements are ok
 	case 3:
+	default:
+		fallthrough; ;
+	case 4:
 		fallthrough /* ERROR "fallthrough statement out of place" */
 	}
 
 	var y interface{}
 	switch y.(type) {
 	case int:
-		fallthrough /* ERROR "fallthrough statement out of place" */
+		fallthrough /* ERROR "fallthrough statement out of place" */ ; ; ;
 	default:
 	}
 
@@ -554,7 +556,7 @@ func switches1() {
 	switch x {
 	case 0:
 		goto L1
-		L1: fallthrough
+		L1: fallthrough; ;
 	case 1:
 		goto L2
 		goto L3
@@ -576,9 +578,16 @@ func switches1() {
 
 	switch x {
 	case 0:
+		fallthrough; ;
+	case 1:
 		{
 			fallthrough /* ERROR "fallthrough statement out of place" */
 		}
+	case 2:
+		fallthrough
+	case 3:
+		fallthrough /* ERROR "fallthrough statement out of place" */
+		{ /* empty block is not an empty statement */ }; ;
 	default:
 	}
 }
diff --git a/src/go/types/testdata/stmt1.src b/src/go/types/testdata/stmt1.src
index a2955e6..24ad6eb 100644
--- a/src/go/types/testdata/stmt1.src
+++ b/src/go/types/testdata/stmt1.src
@@ -22,9 +22,23 @@ func _(x, y int) (z int) {
 
 func _(x, y int) (z int) {
 	{
+		return; ; ; // trailing empty statements are ok
+	}
+	; ; ;
+}
+
+func _(x, y int) (z int) {
+	{
 	}
 } /* ERROR "missing return" */
 
+func _(x, y int) (z int) {
+	{
+		; ; ;
+	}
+	; ; ;
+} /* ERROR "missing return" */
+
 // if statements
 func _(x, y int) (z int) {
 	if x < y { return }
@@ -32,6 +46,16 @@ func _(x, y int) (z int) {
 }
 
 func _(x, y int) (z int) {
+	if x < y { return; ; ; ; }
+	return 1
+}
+
+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" */
 
@@ -62,9 +86,16 @@ func _(x, y int) (z int) {
 
 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) {
@@ -75,6 +106,14 @@ func _(x, y int) (z int) {
 }
 
 func _(x, y int) (z int) {
+	for {
+		for { break }
+		return ; ;
+	}
+	;
+}
+
+func _(x, y int) (z int) {
 L:	for {
 		for { break L }
 		return
@@ -91,6 +130,13 @@ func _(x, y int) (z int) {
 
 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" */
@@ -114,6 +160,18 @@ func _(x, y int) (z int) {
 }
 
 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:
@@ -130,6 +188,11 @@ func _(ch chan int) (z int) {
 } // nice!
 
 func _(ch chan int) (z int) {
+	select {}
+	; ;
+}
+
+func _(ch chan int) (z int) {
 	select {
 	default: break
 	}
@@ -154,6 +217,18 @@ func _(ch chan int) (z int) {
 }
 
 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:
@@ -162,4 +237,5 @@ L:	select {
 		}
 		return
 	}
+	; ; ;
 } /* ERROR "missing return" */
diff --git a/src/go/types/type.go b/src/go/types/type.go
index d8415f1..4e00da3 100644
--- a/src/go/types/type.go
+++ b/src/go/types/type.go
@@ -229,7 +229,7 @@ func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
 // function.
 //
 // For an abstract method, Recv returns the enclosing interface either
-// as a *Named or an *Interface.  Due to embedding, an interface may
+// 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 }
 
diff --git a/src/go/types/universe.go b/src/go/types/universe.go
index 40185c1..cc3bd5a 100644
--- a/src/go/types/universe.go
+++ b/src/go/types/universe.go
@@ -196,7 +196,7 @@ func init() {
 //
 func def(obj Object) {
 	name := obj.Name()
-	if strings.Index(name, " ") >= 0 {
+	if strings.Contains(name, " ") {
 		return // nothing to do
 	}
 	// fix Obj link for named types
diff --git a/src/hash/adler32/adler32.go b/src/hash/adler32/adler32.go
index 0c733f7..21d6a2e 100644
--- a/src/hash/adler32/adler32.go
+++ b/src/hash/adler32/adler32.go
@@ -42,7 +42,7 @@ func New() hash.Hash32 {
 
 func (d *digest) Size() int { return Size }
 
-func (d *digest) BlockSize() int { return 1 }
+func (d *digest) BlockSize() int { return 4 }
 
 // Add p to the running checksum d.
 func update(d digest, p []byte) digest {
@@ -52,6 +52,17 @@ func update(d digest, p []byte) digest {
 		if len(p) > nmax {
 			p, q = p[:nmax], p[nmax:]
 		}
+		for len(p) >= 4 {
+			s1 += uint32(p[0])
+			s2 += s1
+			s1 += uint32(p[1])
+			s2 += s1
+			s1 += uint32(p[2])
+			s2 += s1
+			s1 += uint32(p[3])
+			s2 += s1
+			p = p[4:]
+		}
 		for _, x := range p {
 			s1 += uint32(x)
 			s2 += s1
diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go
index dc59948..c3ac7b8 100644
--- a/src/hash/crc32/crc32.go
+++ b/src/hash/crc32/crc32.go
@@ -20,6 +20,9 @@ import (
 // The size of a CRC-32 checksum in bytes.
 const Size = 4
 
+// Use "slice by 8" when payload >= this value.
+const sliceBy8Cutoff = 16
+
 // Predefined polynomials.
 const (
 	// IEEE is by far and away the most common CRC-32 polynomial.
@@ -45,10 +48,12 @@ type Table [256]uint32
 // Castagnoli table so we can compare against it to find when the caller is
 // using this polynomial.
 var castagnoliTable *Table
+var castagnoliTable8 *slicing8Table
 var castagnoliOnce sync.Once
 
 func castagnoliInit() {
 	castagnoliTable = makeTable(Castagnoli)
+	castagnoliTable8 = makeTable8(Castagnoli)
 }
 
 // IEEETable is the table for the IEEE polynomial.
@@ -146,6 +151,9 @@ func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 {
 		p = p[8:]
 	}
 	crc = ^crc
+	if len(p) == 0 {
+		return crc
+	}
 	return update(crc, &tab[0], p)
 }
 
@@ -178,4 +186,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 updateIEEE(0, data) }
diff --git a/src/hash/crc32/crc32_amd64.go b/src/hash/crc32/crc32_amd64.go
index ab4e2b8..a0180a1 100644
--- a/src/hash/crc32/crc32_amd64.go
+++ b/src/hash/crc32/crc32_amd64.go
@@ -30,6 +30,10 @@ func updateCastagnoli(crc uint32, p []byte) uint32 {
 	if sse42 {
 		return castagnoliSSE42(crc, p)
 	}
+	// Use slicing-by-8 on larger inputs.
+	if len(p) >= sliceBy8Cutoff {
+		return updateSlicingBy8(crc, castagnoliTable8, p)
+	}
 	return update(crc, castagnoliTable, p)
 }
 
@@ -44,8 +48,8 @@ func updateIEEE(crc uint32, p []byte) uint32 {
 		return crc
 	}
 
-	// only use slicing-by-8 when input is >= 4KB
-	if len(p) >= 4096 {
+	// Use slicing-by-8 on larger inputs.
+	if len(p) >= sliceBy8Cutoff {
 		ieeeTable8Once.Do(func() {
 			ieeeTable8 = makeTable8(IEEE)
 		})
diff --git a/src/hash/crc32/crc32_amd64p32.go b/src/hash/crc32/crc32_amd64p32.go
index 067fbb1..1f6cd34 100644
--- a/src/hash/crc32/crc32_amd64p32.go
+++ b/src/hash/crc32/crc32_amd64p32.go
@@ -22,12 +22,16 @@ func updateCastagnoli(crc uint32, p []byte) uint32 {
 	if sse42 {
 		return castagnoliSSE42(crc, p)
 	}
+	// Use slicing-by-8 on larger inputs.
+	if len(p) >= sliceBy8Cutoff {
+		return updateSlicingBy8(crc, castagnoliTable8, p)
+	}
 	return update(crc, castagnoliTable, p)
 }
 
 func updateIEEE(crc uint32, p []byte) uint32 {
-	// only use slicing-by-8 when input is >= 4KB
-	if len(p) >= 4096 {
+	// Use slicing-by-8 on larger inputs.
+	if len(p) >= sliceBy8Cutoff {
 		ieeeTable8Once.Do(func() {
 			ieeeTable8 = makeTable8(IEEE)
 		})
diff --git a/src/hash/crc32/crc32_generic.go b/src/hash/crc32/crc32_generic.go
index 8fc11a7..10a6367 100644
--- a/src/hash/crc32/crc32_generic.go
+++ b/src/hash/crc32/crc32_generic.go
@@ -2,20 +2,24 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build 386 arm arm64 mips64 mips64le ppc64 ppc64le
+// +build !amd64,!amd64p32,!s390x
 
 package crc32
 
-// The file contains the generic version of updateCastagnoli which just calls
-// the software implementation.
+// This file contains the generic version of updateCastagnoli which does
+// slicing-by-8, or uses the fallback for very small sizes.
 
 func updateCastagnoli(crc uint32, p []byte) uint32 {
+	// Use slicing-by-8 on larger inputs.
+	if len(p) >= sliceBy8Cutoff {
+		return updateSlicingBy8(crc, castagnoliTable8, p)
+	}
 	return update(crc, castagnoliTable, p)
 }
 
 func updateIEEE(crc uint32, p []byte) uint32 {
-	// only use slicing-by-8 when input is >= 4KB
-	if len(p) >= 4096 {
+	// Use slicing-by-8 on larger inputs.
+	if len(p) >= sliceBy8Cutoff {
 		ieeeTable8Once.Do(func() {
 			ieeeTable8 = makeTable8(IEEE)
 		})
diff --git a/src/hash/crc32/crc32_s390x.go b/src/hash/crc32/crc32_s390x.go
new file mode 100644
index 0000000..2f20690
--- /dev/null
+++ b/src/hash/crc32/crc32_s390x.go
@@ -0,0 +1,101 @@
+// Copyright 2016 The Go Authors. 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
+
+import (
+	"unsafe"
+)
+
+const (
+	vxMinLen    = 64
+	vxAlignment = 16
+	vxAlignMask = vxAlignment - 1
+)
+
+// hasVectorFacility reports whether the machine has the z/Architecture
+// vector facility installed and enabled.
+func hasVectorFacility() bool
+
+var hasVX = hasVectorFacility()
+
+// vectorizedCastagnoli implements CRC32 using vector instructions.
+// It is defined in crc32_s390x.s.
+//go:noescape
+func vectorizedCastagnoli(crc uint32, p []byte) uint32
+
+// vectorizedIEEE implements CRC32 using vector instructions.
+// It is defined in crc32_s390x.s.
+//go:noescape
+func vectorizedIEEE(crc uint32, p []byte) uint32
+
+func genericCastagnoli(crc uint32, p []byte) uint32 {
+	// Use slicing-by-8 on larger inputs.
+	if len(p) >= sliceBy8Cutoff {
+		return updateSlicingBy8(crc, castagnoliTable8, p)
+	}
+	return update(crc, castagnoliTable, p)
+}
+
+func genericIEEE(crc uint32, p []byte) uint32 {
+	// Use slicing-by-8 on larger inputs.
+	if len(p) >= sliceBy8Cutoff {
+		ieeeTable8Once.Do(func() {
+			ieeeTable8 = makeTable8(IEEE)
+		})
+		return updateSlicingBy8(crc, ieeeTable8, p)
+	}
+	return update(crc, IEEETable, p)
+}
+
+// updateCastagnoli calculates the checksum of p using genericCastagnoli to
+// align the data appropriately for vectorCastagnoli. It avoids using
+// vectorCastagnoli entirely if the length of p is less than or equal to
+// vxMinLen.
+func updateCastagnoli(crc uint32, p []byte) uint32 {
+	// Use vectorized function if vector facility is available and
+	// data length is above threshold.
+	if hasVX && len(p) > vxMinLen {
+		pAddr := uintptr(unsafe.Pointer(&p[0]))
+		if pAddr&vxAlignMask != 0 {
+			prealign := vxAlignment - int(pAddr&vxAlignMask)
+			crc = genericCastagnoli(crc, p[:prealign])
+			p = p[prealign:]
+		}
+		aligned := len(p) & ^vxAlignMask
+		crc = vectorizedCastagnoli(crc, p[:aligned])
+		p = p[aligned:]
+		// process remaining data
+		if len(p) > 0 {
+			crc = genericCastagnoli(crc, p)
+		}
+		return crc
+	}
+	return genericCastagnoli(crc, p)
+}
+
+// updateIEEE calculates the checksum of p using genericIEEE to align the data
+// appropriately for vectorIEEE. It avoids using vectorIEEE entirely if the length
+// of p is less than or equal to vxMinLen.
+func updateIEEE(crc uint32, p []byte) uint32 {
+	// Use vectorized function if vector facility is available and
+	// data length is above threshold.
+	if hasVX && len(p) > vxMinLen {
+		pAddr := uintptr(unsafe.Pointer(&p[0]))
+		if pAddr&vxAlignMask != 0 {
+			prealign := vxAlignment - int(pAddr&vxAlignMask)
+			crc = genericIEEE(crc, p[:prealign])
+			p = p[prealign:]
+		}
+		aligned := len(p) & ^vxAlignMask
+		crc = vectorizedIEEE(crc, p[:aligned])
+		p = p[aligned:]
+		// process remaining data
+		if len(p) > 0 {
+			crc = genericIEEE(crc, p)
+		}
+		return crc
+	}
+	return genericIEEE(crc, p)
+}
diff --git a/src/hash/crc32/crc32_s390x.s b/src/hash/crc32/crc32_s390x.s
new file mode 100644
index 0000000..f8d39f3
--- /dev/null
+++ b/src/hash/crc32/crc32_s390x.s
@@ -0,0 +1,245 @@
+// Copyright 2016 The Go 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"
+
+// Vector register range containing CRC-32 constants
+
+#define CONST_PERM_LE2BE        V9
+#define CONST_R2R1              V10
+#define CONST_R4R3              V11
+#define CONST_R5                V12
+#define CONST_RU_POLY           V13
+#define CONST_CRC_POLY          V14
+
+
+// The CRC-32 constant block contains reduction constants to fold and
+// process particular chunks of the input data stream in parallel.
+//
+// Note that the constant definitions below are extended in order to compute
+// intermediate results with a single VECTOR GALOIS FIELD MULTIPLY instruction.
+// The rightmost doubleword can be 0 to prevent contribution to the result or
+// can be multiplied by 1 to perform an XOR without the need for a separate
+// VECTOR EXCLUSIVE OR instruction.
+//
+// The polynomials used are bit-reflected:
+//
+//            IEEE: P'(x) = 0x0edb88320
+//      Castagnoli: P'(x) = 0x082f63b78
+
+
+// IEEE polynomial constants
+DATA    ·crclecons+0(SB)/8,  $0x0F0E0D0C0B0A0908       // LE-to-BE mask
+DATA    ·crclecons+8(SB)/8,  $0x0706050403020100
+DATA    ·crclecons+16(SB)/8, $0x00000001c6e41596       // R2
+DATA    ·crclecons+24(SB)/8, $0x0000000154442bd4       // R1
+DATA    ·crclecons+32(SB)/8, $0x00000000ccaa009e       // R4
+DATA    ·crclecons+40(SB)/8, $0x00000001751997d0       // R3
+DATA    ·crclecons+48(SB)/8, $0x0000000000000000
+DATA    ·crclecons+56(SB)/8, $0x0000000163cd6124       // R5
+DATA    ·crclecons+64(SB)/8, $0x0000000000000000
+DATA    ·crclecons+72(SB)/8, $0x00000001F7011641       // u'
+DATA    ·crclecons+80(SB)/8, $0x0000000000000000
+DATA    ·crclecons+88(SB)/8, $0x00000001DB710641       // P'(x) << 1
+
+GLOBL    ·crclecons(SB),RODATA, $144
+
+// Castagonli Polynomial constants
+DATA    ·crcclecons+0(SB)/8,  $0x0F0E0D0C0B0A0908      // LE-to-BE mask
+DATA    ·crcclecons+8(SB)/8,  $0x0706050403020100
+DATA    ·crcclecons+16(SB)/8, $0x000000009e4addf8      // R2
+DATA    ·crcclecons+24(SB)/8, $0x00000000740eef02      // R1
+DATA    ·crcclecons+32(SB)/8, $0x000000014cd00bd6      // R4
+DATA    ·crcclecons+40(SB)/8, $0x00000000f20c0dfe      // R3
+DATA    ·crcclecons+48(SB)/8, $0x0000000000000000
+DATA    ·crcclecons+56(SB)/8, $0x00000000dd45aab8      // R5
+DATA    ·crcclecons+64(SB)/8, $0x0000000000000000
+DATA    ·crcclecons+72(SB)/8, $0x00000000dea713f1      // u'
+DATA    ·crcclecons+80(SB)/8, $0x0000000000000000
+DATA    ·crcclecons+88(SB)/8, $0x0000000105ec76f0      // P'(x) << 1
+
+GLOBL   ·crcclecons(SB),RODATA, $144
+
+// func hasVectorFacility() bool
+TEXT ·hasVectorFacility(SB),NOSPLIT,$24-1
+	MOVD    $x-24(SP), R1
+	XC      $24, 0(R1), 0(R1) // clear the storage
+	MOVD    $2, R0            // R0 is the number of double words stored -1
+	WORD    $0xB2B01000       // STFLE 0(R1)
+	XOR     R0, R0            // reset the value of R0
+	MOVBZ   z-8(SP), R1
+	AND     $0x40, R1
+	BEQ     novector
+vectorinstalled:
+	// check if the vector instruction has been enabled
+	VLEIB   $0, $0xF, V16
+	VLGVB   $0, V16, R1
+	CMPBNE  R1, $0xF, novector
+	MOVB    $1, ret+0(FP) // have vx
+	RET
+novector:
+	MOVB    $0, ret+0(FP) // no vx
+	RET
+
+
+// The CRC-32 function(s) use these calling conventions:
+//
+// Parameters:
+//
+//      R2:    Initial CRC value, typically ~0; and final CRC (return) value.
+//      R3:    Input buffer pointer, performance might be improved if the
+//             buffer is on a doubleword boundary.
+//      R4:    Length of the buffer, must be 64 bytes or greater.
+//
+// Register usage:
+//
+//      R5:     CRC-32 constant pool base pointer.
+//      V0:     Initial CRC value and intermediate constants and results.
+//      V1..V4: Data for CRC computation.
+//      V5..V8: Next data chunks that are fetched from the input buffer.
+//
+//      V9..V14: CRC-32 constants.
+
+// func vectorizedIEEE(crc uint32, p []byte) uint32
+TEXT ·vectorizedIEEE(SB),NOSPLIT,$0
+	MOVWZ   crc+0(FP), R2     // R2 stores the CRC value
+	MOVD    p+8(FP), R3       // data pointer
+	MOVD    p_len+16(FP), R4  // len(p)
+
+	MOVD    $·crclecons(SB), R5
+	BR      vectorizedBody<>(SB)
+
+// func vectorizedCastagnoli(crc uint32, p []byte) uint32
+TEXT ·vectorizedCastagnoli(SB),NOSPLIT,$0
+	MOVWZ   crc+0(FP), R2     // R2 stores the CRC value
+	MOVD    p+8(FP), R3       // data pointer
+	MOVD    p_len+16(FP), R4  // len(p)
+
+	// R5: crc-32 constant pool base pointer, constant is used to reduce crc
+	MOVD    $·crcclecons(SB), R5
+	BR      vectorizedBody<>(SB)
+
+TEXT vectorizedBody<>(SB),NOSPLIT,$0
+	XOR     $0xffffffff, R2 // NOTW R2
+	VLM     0(R5), CONST_PERM_LE2BE, CONST_CRC_POLY
+
+	// Load the initial CRC value into the rightmost word of V0
+	VZERO   V0
+	VLVGF   $3, R2, V0
+
+	// Load a 64-byte data chunk and XOR with CRC
+	VLM     0(R3), V1, V4    // 64-bytes into V1..V4
+
+	// Reflect the data if the CRC operation is in the bit-reflected domain
+	VPERM   V1, V1, CONST_PERM_LE2BE, V1
+	VPERM   V2, V2, CONST_PERM_LE2BE, V2
+	VPERM   V3, V3, CONST_PERM_LE2BE, V3
+	VPERM   V4, V4, CONST_PERM_LE2BE, V4
+
+	VX      V0, V1, V1     // V1 ^= CRC
+	ADD     $64, R3        // BUF = BUF + 64
+	ADD     $(-64), R4
+
+	// Check remaining buffer size and jump to proper folding method
+	CMP     R4, $64
+	BLT     less_than_64bytes
+
+fold_64bytes_loop:
+	// Load the next 64-byte data chunk into V5 to V8
+	VLM     0(R3), V5, V8
+	VPERM   V5, V5, CONST_PERM_LE2BE, V5
+	VPERM   V6, V6, CONST_PERM_LE2BE, V6
+	VPERM   V7, V7, CONST_PERM_LE2BE, V7
+	VPERM   V8, V8, CONST_PERM_LE2BE, V8
+
+
+	// Perform a GF(2) multiplication of the doublewords in V1 with
+	// the reduction constants in V0.  The intermediate result is
+	// then folded (accumulated) with the next data chunk in V5 and
+	// stored in V1.  Repeat this step for the register contents
+	// in V2, V3, and V4 respectively.
+
+	VGFMAG  CONST_R2R1, V1, V5, V1
+	VGFMAG  CONST_R2R1, V2, V6, V2
+	VGFMAG  CONST_R2R1, V3, V7, V3
+	VGFMAG  CONST_R2R1, V4, V8 ,V4
+
+	// Adjust buffer pointer and length for next loop
+	ADD     $64, R3                  // BUF = BUF + 64
+	ADD     $(-64), R4               // LEN = LEN - 64
+
+	CMP     R4, $64
+	BGE     fold_64bytes_loop
+
+less_than_64bytes:
+	// Fold V1 to V4 into a single 128-bit value in V1
+	VGFMAG  CONST_R4R3, V1, V2, V1
+	VGFMAG  CONST_R4R3, V1, V3, V1
+	VGFMAG  CONST_R4R3, V1, V4, V1
+
+	// Check whether to continue with 64-bit folding
+	CMP R4, $16
+	BLT final_fold
+
+fold_16bytes_loop:
+	VL      0(R3), V2               // Load next data chunk
+	VPERM   V2, V2, CONST_PERM_LE2BE, V2
+
+	VGFMAG  CONST_R4R3, V1, V2, V1  // Fold next data chunk
+
+	// Adjust buffer pointer and size for folding next data chunk
+	ADD     $16, R3
+	ADD     $-16, R4
+
+	// Process remaining data chunks
+	CMP     R4 ,$16
+	BGE     fold_16bytes_loop
+
+final_fold:
+	VLEIB   $7, $0x40, V9
+	VSRLB   V9, CONST_R4R3, V0
+	VLEIG   $0, $1, V0
+
+	VGFMG   V0, V1, V1
+
+	VLEIB   $7, $0x20, V9         // Shift by words
+	VSRLB   V9, V1, V2            // Store remaining bits in V2
+	VUPLLF  V1, V1                // Split rightmost doubleword
+	VGFMAG  CONST_R5, V1, V2, V1  // V1 = (V1 * R5) XOR V2
+
+
+	// The input values to the Barret reduction are the degree-63 polynomial
+	// in V1 (R(x)), degree-32 generator polynomial, and the reduction
+	// constant u.  The Barret reduction result is the CRC value of R(x) mod
+	// P(x).
+	//
+	// The Barret reduction algorithm is defined as:
+	//
+	//    1. T1(x) = floor( R(x) / x^32 ) GF2MUL u
+	//    2. T2(x) = floor( T1(x) / x^32 ) GF2MUL P(x)
+	//    3. C(x)  = R(x) XOR T2(x) mod x^32
+	//
+	// Note: To compensate the division by x^32, use the vector unpack
+	// instruction to move the leftmost word into the leftmost doubleword
+	// of the vector register.  The rightmost doubleword is multiplied
+	// with zero to not contribute to the intermedate results.
+
+
+	// T1(x) = floor( R(x) / x^32 ) GF2MUL u
+	VUPLLF  V1, V2
+	VGFMG   CONST_RU_POLY, V2, V2
+
+
+	// Compute the GF(2) product of the CRC polynomial in VO with T1(x) in
+	// V2 and XOR the intermediate result, T2(x),  with the value in V1.
+	// The final result is in the rightmost word of V2.
+
+	VUPLLF  V2 , V2
+	VGFMAG  CONST_CRC_POLY, V2, V1, V2
+
+done:
+	VLGVF   $2, V2, R2
+	XOR     $0xffffffff, R2 // NOTW R2
+	MOVWZ   R2, ret + 32(FP)
+	RET
diff --git a/src/hash/crc32/crc32_test.go b/src/hash/crc32/crc32_test.go
index 1ca3ac2..e2b3557 100644
--- a/src/hash/crc32/crc32_test.go
+++ b/src/hash/crc32/crc32_test.go
@@ -5,6 +5,7 @@
 package crc32
 
 import (
+	"hash"
 	"io"
 	"testing"
 )
@@ -81,49 +82,51 @@ func TestGolden(t *testing.T) {
 	}
 }
 
-func BenchmarkIEEECrc1KB(b *testing.B) {
-	b.SetBytes(1024)
-	data := make([]byte, 1024)
-	for i := range data {
-		data[i] = byte(i)
-	}
-	h := NewIEEE()
-	in := make([]byte, 0, h.Size())
+func BenchmarkIEEECrc40B(b *testing.B) {
+	benchmark(b, NewIEEE(), 40)
+}
 
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		h.Reset()
-		h.Write(data)
-		h.Sum(in)
-	}
+func BenchmarkIEEECrc1KB(b *testing.B) {
+	benchmark(b, NewIEEE(), 1<<10)
 }
 
 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())
+	benchmark(b, NewIEEE(), 4<<10)
+}
 
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		h.Reset()
-		h.Write(data)
-		h.Sum(in)
-	}
+func BenchmarkIEEECrc32KB(b *testing.B) {
+	benchmark(b, NewIEEE(), 32<<10)
+}
+
+func BenchmarkCastagnoliCrc40B(b *testing.B) {
+	benchmark(b, New(MakeTable(Castagnoli)), 40)
 }
 
 func BenchmarkCastagnoliCrc1KB(b *testing.B) {
-	b.SetBytes(1024)
-	data := make([]byte, 1024)
+	benchmark(b, New(MakeTable(Castagnoli)), 1<<10)
+}
+
+func BenchmarkCastagnoliCrc4KB(b *testing.B) {
+	benchmark(b, New(MakeTable(Castagnoli)), 4<<10)
+}
+
+func BenchmarkCastagnoliCrc32KB(b *testing.B) {
+	benchmark(b, New(MakeTable(Castagnoli)), 32<<10)
+}
+
+func benchmark(b *testing.B, h hash.Hash32, n int64) {
+	b.SetBytes(n)
+	data := make([]byte, n)
 	for i := range data {
 		data[i] = byte(i)
 	}
-	h := New(MakeTable(Castagnoli))
 	in := make([]byte, 0, h.Size())
 
+	// Warm up
+	h.Reset()
+	h.Write(data)
+	h.Sum(in)
+
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 		h.Reset()
diff --git a/src/hash/crc64/crc64.go b/src/hash/crc64/crc64.go
index 54cc560..e939c2a 100644
--- a/src/hash/crc64/crc64.go
+++ b/src/hash/crc64/crc64.go
@@ -24,9 +24,25 @@ const (
 // Table is a 256-word table representing the polynomial for efficient processing.
 type Table [256]uint64
 
+var (
+	slicing8TableISO  = makeSlicingBy8Table(makeTable(ISO))
+	slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA))
+)
+
 // MakeTable returns a Table constructed from the specified polynomial.
 // The contents of this Table must not be modified.
 func MakeTable(poly uint64) *Table {
+	switch poly {
+	case ISO:
+		return &slicing8TableISO[0]
+	case ECMA:
+		return &slicing8TableECMA[0]
+	default:
+		return makeTable(poly)
+	}
+}
+
+func makeTable(poly uint64) *Table {
 	t := new(Table)
 	for i := 0; i < 256; i++ {
 		crc := uint64(i)
@@ -42,6 +58,19 @@ func MakeTable(poly uint64) *Table {
 	return t
 }
 
+func makeSlicingBy8Table(t *Table) *[8]Table {
+	var helperTable [8]Table
+	helperTable[0] = *t
+	for i := 0; i < 256; i++ {
+		crc := t[i]
+		for j := 1; j < 8; j++ {
+			crc = t[crc&0xff] ^ (crc >> 8)
+			helperTable[j][i] = crc
+		}
+	}
+	return &helperTable
+}
+
 // digest represents the partial evaluation of a checksum.
 type digest struct {
 	crc uint64
@@ -61,6 +90,35 @@ func (d *digest) Reset() { d.crc = 0 }
 
 func update(crc uint64, tab *Table, p []byte) uint64 {
 	crc = ^crc
+	// Table comparison is somewhat expensive, so avoid it for small sizes
+	for len(p) >= 64 {
+		var helperTable *[8]Table
+		if *tab == slicing8TableECMA[0] {
+			helperTable = slicing8TableECMA
+		} else if *tab == slicing8TableISO[0] {
+			helperTable = slicing8TableISO
+			// For smaller sizes creating extended table takes too much time
+		} else if len(p) > 16384 {
+			helperTable = makeSlicingBy8Table(tab)
+		} else {
+			break
+		}
+		// Update using slicing-by-8
+		for len(p) > 8 {
+			crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 |
+				uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
+			crc = helperTable[7][crc&0xff] ^
+				helperTable[6][(crc>>8)&0xff] ^
+				helperTable[5][(crc>>16)&0xff] ^
+				helperTable[4][(crc>>24)&0xff] ^
+				helperTable[3][(crc>>32)&0xff] ^
+				helperTable[2][(crc>>40)&0xff] ^
+				helperTable[1][(crc>>48)&0xff] ^
+				helperTable[0][crc>>56]
+			p = p[8:]
+		}
+	}
+	// For reminders or small sizes
 	for _, v := range p {
 		crc = tab[byte(crc)^v] ^ (crc >> 8)
 	}
diff --git a/src/hash/crc64/crc64_test.go b/src/hash/crc64/crc64_test.go
index 81a87b5..480b150 100644
--- a/src/hash/crc64/crc64_test.go
+++ b/src/hash/crc64/crc64_test.go
@@ -10,66 +10,75 @@ import (
 )
 
 type test struct {
-	out uint64
-	in  string
+	outISO  uint64
+	outECMA uint64
+	in      string
 }
 
 var golden = []test{
-	{0x0, ""},
-	{0x3420000000000000, "a"},
-	{0x36c4200000000000, "ab"},
-	{0x3776c42000000000, "abc"},
-	{0x336776c420000000, "abcd"},
-	{0x32d36776c4200000, "abcde"},
-	{0x3002d36776c42000, "abcdef"},
-	{0x31b002d36776c420, "abcdefg"},
-	{0xe21b002d36776c4, "abcdefgh"},
-	{0x8b6e21b002d36776, "abcdefghi"},
-	{0x7f5b6e21b002d367, "abcdefghij"},
-	{0x8ec0e7c835bf9cdf, "Discard medicine more than two years old."},
-	{0xc7db1759e2be5ab4, "He who has a shady past knows that nice guys finish last."},
-	{0xfbf9d9603a6fa020, "I wouldn't marry him with a ten foot pole."},
-	{0xeafc4211a6daa0ef, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
-	{0x3e05b21c7a4dc4da, "The days of the digital watch are numbered.  -Tom Stoppard"},
-	{0x5255866ad6ef28a6, "Nepal premier won't resign."},
-	{0x8a79895be1e9c361, "For every action there is an equal and opposite government program."},
-	{0x8878963a649d4916, "His money is twice tainted: 'taint yours and 'taint mine."},
-	{0xa7b9d53ea87eb82f, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
-	{0xdb6805c0966a2f9c, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
-	{0xf3553c65dacdadd2, "size:  a.out:  bad magic"},
-	{0x9d5e034087a676b9, "The major problem is with sendmail.  -Mark Horton"},
-	{0xa6db2d7f8da96417, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
-	{0x325e00cd2fe819f9, "If the enemy is within range, then so are you."},
-	{0x88c6600ce58ae4c6, "It's well we cannot hear the screams/That we create in others' dreams."},
-	{0x28c4a3f3b769e078, "You remind me of a TV show, but that's all right: I watch it anyway."},
-	{0xa698a34c9d9f1dca, "C is as portable as Stonehedge!!"},
-	{0xf6c1e2a8c26c5cfc, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
-	{0xd402559dfe9b70c, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
-	{0xdb6efff26aa94946, "How can you write a big system without C++?  -Paul Glick"},
+	{0x0, 0x0, ""},
+	{0x3420000000000000, 0x330284772e652b05, "a"},
+	{0x36c4200000000000, 0xbc6573200e84b046, "ab"},
+	{0x3776c42000000000, 0x2cd8094a1a277627, "abc"},
+	{0x336776c420000000, 0x3c9d28596e5960ba, "abcd"},
+	{0x32d36776c4200000, 0x40bdf58fb0895f2, "abcde"},
+	{0x3002d36776c42000, 0xd08e9f8545a700f4, "abcdef"},
+	{0x31b002d36776c420, 0xec20a3a8cc710e66, "abcdefg"},
+	{0xe21b002d36776c4, 0x67b4f30a647a0c59, "abcdefgh"},
+	{0x8b6e21b002d36776, 0x9966f6c89d56ef8e, "abcdefghi"},
+	{0x7f5b6e21b002d367, 0x32093a2ecd5773f4, "abcdefghij"},
+	{0x8ec0e7c835bf9cdf, 0x8a0825223ea6d221, "Discard medicine more than two years old."},
+	{0xc7db1759e2be5ab4, 0x8562c0ac2ab9a00d, "He who has a shady past knows that nice guys finish last."},
+	{0xfbf9d9603a6fa020, 0x3ee2a39c083f38b4, "I wouldn't marry him with a ten foot pole."},
+	{0xeafc4211a6daa0ef, 0x1f603830353e518a, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+	{0x3e05b21c7a4dc4da, 0x2fd681d7b2421fd, "The days of the digital watch are numbered.  -Tom Stoppard"},
+	{0x5255866ad6ef28a6, 0x790ef2b16a745a41, "Nepal premier won't resign."},
+	{0x8a79895be1e9c361, 0x3ef8f06daccdcddf, "For every action there is an equal and opposite government program."},
+	{0x8878963a649d4916, 0x49e41b2660b106d, "His money is twice tainted: 'taint yours and 'taint mine."},
+	{0xa7b9d53ea87eb82f, 0x561cc0cfa235ac68, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+	{0xdb6805c0966a2f9c, 0xd4fe9ef082e69f59, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+	{0xf3553c65dacdadd2, 0xe3b5e46cd8d63a4d, "size:  a.out:  bad magic"},
+	{0x9d5e034087a676b9, 0x865aaf6b94f2a051, "The major problem is with sendmail.  -Mark Horton"},
+	{0xa6db2d7f8da96417, 0x7eca10d2f8136eb4, "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+	{0x325e00cd2fe819f9, 0xd7dd118c98e98727, "If the enemy is within range, then so are you."},
+	{0x88c6600ce58ae4c6, 0x70fb33c119c29318, "It's well we cannot hear the screams/That we create in others' dreams."},
+	{0x28c4a3f3b769e078, 0x57c891e39a97d9b7, "You remind me of a TV show, but that's all right: I watch it anyway."},
+	{0xa698a34c9d9f1dca, 0xa1f46ba20ad06eb7, "C is as portable as Stonehedge!!"},
+	{0xf6c1e2a8c26c5cfc, 0x7ad25fafa1710407, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+	{0xd402559dfe9b70c, 0x73cef1666185c13f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+	{0xdb6efff26aa94946, 0xb41858f73c389602, "How can you write a big system without C++?  -Paul Glick"},
+	{0xe7fcf1006b503b61, 0x27db187fc15bbc72, "This is a test of the emergency broadcast system."},
 }
 
-var tab = MakeTable(ISO)
-
 func TestGolden(t *testing.T) {
+	tabISO := MakeTable(ISO)
+	tabECMA := MakeTable(ECMA)
 	for i := 0; i < len(golden); i++ {
 		g := golden[i]
-		c := New(tab)
+		c := New(tabISO)
 		io.WriteString(c, g.in)
 		s := c.Sum64()
-		if s != g.out {
-			t.Errorf("crc64(%s) = 0x%x want 0x%x", g.in, s, g.out)
+		if s != g.outISO {
+			t.Errorf("ISO crc64(%s) = 0x%x want 0x%x", g.in, s, g.outISO)
+			t.FailNow()
+		}
+		c = New(tabECMA)
+		io.WriteString(c, g.in)
+		s = c.Sum64()
+		if s != g.outECMA {
+			t.Errorf("ECMA crc64(%s) = 0x%x want 0x%x", g.in, s, g.outECMA)
 			t.FailNow()
 		}
 	}
 }
 
-func BenchmarkCrc64KB(b *testing.B) {
-	b.SetBytes(1024)
-	data := make([]byte, 1024)
+func bench(b *testing.B, poly uint64, size int64) {
+	b.SetBytes(size)
+	data := make([]byte, size)
 	for i := range data {
 		data[i] = byte(i)
 	}
-	h := New(tab)
+	h := New(MakeTable(poly))
 	in := make([]byte, 0, h.Size())
 
 	b.ResetTimer()
@@ -79,3 +88,24 @@ func BenchmarkCrc64KB(b *testing.B) {
 		h.Sum(in)
 	}
 }
+
+func BenchmarkCrc64(b *testing.B) {
+	b.Run("ISO64KB", func(b *testing.B) {
+		bench(b, ISO, 64<<10)
+	})
+	b.Run("ISO4KB", func(b *testing.B) {
+		bench(b, ISO, 4<<10)
+	})
+	b.Run("ISO1KB", func(b *testing.B) {
+		bench(b, ISO, 1<<10)
+	})
+	b.Run("ECMA64KB", func(b *testing.B) {
+		bench(b, ECMA, 64<<10)
+	})
+	b.Run("Random64KB", func(b *testing.B) {
+		bench(b, 0x777, 64<<10)
+	})
+	b.Run("Random16KB", func(b *testing.B) {
+		bench(b, 0x777, 16<<10)
+	})
+}
diff --git a/src/html/escape.go b/src/html/escape.go
index ab6fd1c..8dd1f4a 100644
--- a/src/html/escape.go
+++ b/src/html/escape.go
@@ -10,10 +10,6 @@ import (
 	"unicode/utf8"
 )
 
-type writer interface {
-	WriteString(string) (int, error)
-}
-
 // These replacements permit compatibility with old numeric entities that
 // assumed Windows-1252 encoding.
 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
@@ -185,7 +181,7 @@ func EscapeString(s string) string {
 
 // UnescapeString unescapes entities like "<" to become "<". It unescapes a
 // larger range of entities than EscapeString escapes. For example, "á"
-// unescapes to "á", as does "á" and "&xE1;".
+// unescapes to "á", as does "á" and "&#xE1;".
 // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
 // always true.
 func UnescapeString(s string) string {
diff --git a/src/html/template/content.go b/src/html/template/content.go
index 3715ed5..2e14bd1 100644
--- a/src/html/template/content.go
+++ b/src/html/template/content.go
@@ -18,16 +18,28 @@ type (
 	//   4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
 	// See http://www.w3.org/TR/css3-syntax/#parsing and
 	// https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
+	//
+	// Use of this type presents a security risk:
+	// the encapsulated content should come from a trusted source,
+	// as it will be included verbatim in the template output.
 	CSS string
 
 	// HTML encapsulates a known safe HTML document fragment.
 	// It should not be used for HTML from a third-party, or HTML with
 	// unclosed tags or comments. The outputs of a sound HTML sanitizer
 	// and a template escaped by this package are fine for use with HTML.
+	//
+	// Use of this type presents a security risk:
+	// the encapsulated content should come from a trusted source,
+	// as it will be included verbatim in the template output.
 	HTML string
 
 	// HTMLAttr encapsulates an HTML attribute from a trusted source,
 	// for example, ` dir="ltr"`.
+	//
+	// Use of this type presents a security risk:
+	// the encapsulated content should come from a trusted source,
+	// as it will be included verbatim in the template output.
 	HTMLAttr string
 
 	// JS encapsulates a known safe EcmaScript5 Expression, for example,
@@ -37,6 +49,15 @@ type (
 	// statement/expression ambiguity as when passing an expression like
 	// "{ foo: bar() }\n['foo']()", which is both a valid Expression and a
 	// valid Program with a very different meaning.
+	//
+	// Use of this type presents a security risk:
+	// the encapsulated content should come from a trusted source,
+	// as it will be included verbatim in the template output.
+	//
+	// Using JS to include valid but untrusted JSON is not safe.
+	// A safe alternative is to parse the JSON with json.Unmarshal and then
+	// pass the resultant object into the template, where it will be
+	// converted to sanitized JSON when presented in a JavaScript context.
 	JS string
 
 	// JSStr encapsulates a sequence of characters meant to be embedded
@@ -46,6 +67,10 @@ type (
 	//                    | EscapeSequence
 	// Note that LineContinuations are not allowed.
 	// JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.
+	//
+	// Use of this type presents a security risk:
+	// the encapsulated content should come from a trusted source,
+	// as it will be included verbatim in the template output.
 	JSStr string
 
 	// URL encapsulates a known safe URL or URL substring (see RFC 3986).
@@ -53,6 +78,10 @@ type (
 	// from a trusted source should go in the page, but by default dynamic
 	// `javascript:` URLs are filtered out since they are a frequently
 	// exploited injection vector.
+	//
+	// Use of this type presents a security risk:
+	// the encapsulated content should come from a trusted source,
+	// as it will be included verbatim in the template output.
 	URL string
 )
 
diff --git a/src/html/template/css.go b/src/html/template/css.go
index 3184648..9154d86 100644
--- a/src/html/template/css.go
+++ b/src/html/template/css.go
@@ -243,13 +243,13 @@ func cssValueFilter(args ...interface{}) string {
 				return filterFailsafe
 			}
 		default:
-			if c < 0x80 && isCSSNmchar(rune(c)) {
+			if c < utf8.RuneSelf && isCSSNmchar(rune(c)) {
 				id = append(id, c)
 			}
 		}
 	}
 	id = bytes.ToLower(id)
-	if bytes.Index(id, expressionBytes) != -1 || bytes.Index(id, mozBindingBytes) != -1 {
+	if bytes.Contains(id, expressionBytes) || bytes.Contains(id, mozBindingBytes) {
 		return filterFailsafe
 	}
 	return string(b)
diff --git a/src/html/template/doc.go b/src/html/template/doc.go
index 1827403..e1e9cad 100644
--- a/src/html/template/doc.go
+++ b/src/html/template/doc.go
@@ -166,7 +166,7 @@ that would have been produced if {{.}} was a regular string.
 
 Security Model
 
-http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
+https://rawgit.com/mikesamuel/sanitized-jquery-templates/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
 
 This package assumes that template authors are trusted, that Execute's data
 parameter is not, and seeks to preserve the properties below in the face
diff --git a/src/html/template/error.go b/src/html/template/error.go
index 8f99e1b..5637384 100644
--- a/src/html/template/error.go
+++ b/src/html/template/error.go
@@ -164,7 +164,7 @@ const (
 	//   different context than an earlier pass, there is no single context.
 	//   In the example, there is missing a quote, so it is not clear
 	//   whether {{.}} is meant to be inside a JS string or in a JS value
-	//   context.  The second iteration would produce something like
+	//   context. The second iteration would produce something like
 	//
 	//     <script>var x = ['firstValue,'secondValue]</script>
 	ErrRangeLoopReentry
diff --git a/src/html/template/escape.go b/src/html/template/escape.go
index 3c18340..8f2fe46 100644
--- a/src/html/template/escape.go
+++ b/src/html/template/escape.go
@@ -15,8 +15,8 @@ import (
 
 // escapeTemplate rewrites the named template, which must be
 // associated with t, to guarantee that the output of any of the named
-// templates is properly escaped.  If no error is returned, then the named templates have
-// been modified.  Otherwise the named templates have been rendered
+// templates is properly escaped. If no error is returned, then the named templates have
+// been modified. Otherwise the named templates have been rendered
 // unusable.
 func escapeTemplate(tmpl *Template, node parse.Node, name string) error {
 	e := newEscaper(tmpl)
@@ -46,30 +46,30 @@ func escapeTemplate(tmpl *Template, node parse.Node, name string) error {
 
 // funcMap maps command names to functions that render their inputs safe.
 var funcMap = template.FuncMap{
-	"html_template_attrescaper":     attrEscaper,
-	"html_template_commentescaper":  commentEscaper,
-	"html_template_cssescaper":      cssEscaper,
-	"html_template_cssvaluefilter":  cssValueFilter,
-	"html_template_htmlnamefilter":  htmlNameFilter,
-	"html_template_htmlescaper":     htmlEscaper,
-	"html_template_jsregexpescaper": jsRegexpEscaper,
-	"html_template_jsstrescaper":    jsStrEscaper,
-	"html_template_jsvalescaper":    jsValEscaper,
-	"html_template_nospaceescaper":  htmlNospaceEscaper,
-	"html_template_rcdataescaper":   rcdataEscaper,
-	"html_template_urlescaper":      urlEscaper,
-	"html_template_urlfilter":       urlFilter,
-	"html_template_urlnormalizer":   urlNormalizer,
+	"_html_template_attrescaper":     attrEscaper,
+	"_html_template_commentescaper":  commentEscaper,
+	"_html_template_cssescaper":      cssEscaper,
+	"_html_template_cssvaluefilter":  cssValueFilter,
+	"_html_template_htmlnamefilter":  htmlNameFilter,
+	"_html_template_htmlescaper":     htmlEscaper,
+	"_html_template_jsregexpescaper": jsRegexpEscaper,
+	"_html_template_jsstrescaper":    jsStrEscaper,
+	"_html_template_jsvalescaper":    jsValEscaper,
+	"_html_template_nospaceescaper":  htmlNospaceEscaper,
+	"_html_template_rcdataescaper":   rcdataEscaper,
+	"_html_template_urlescaper":      urlEscaper,
+	"_html_template_urlfilter":       urlFilter,
+	"_html_template_urlnormalizer":   urlNormalizer,
 }
 
 // equivEscapers matches contextual escapers to equivalent template builtins.
 var equivEscapers = map[string]string{
-	"html_template_attrescaper":    "html",
-	"html_template_htmlescaper":    "html",
-	"html_template_nospaceescaper": "html",
-	"html_template_rcdataescaper":  "html",
-	"html_template_urlescaper":     "urlquery",
-	"html_template_urlnormalizer":  "urlquery",
+	"_html_template_attrescaper":    "html",
+	"_html_template_htmlescaper":    "html",
+	"_html_template_nospaceescaper": "html",
+	"_html_template_rcdataescaper":  "html",
+	"_html_template_urlescaper":     "urlquery",
+	"_html_template_urlnormalizer":  "urlquery",
 }
 
 // escaper collects type inferences about templates and changes needed to make
@@ -147,17 +147,17 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
 	case stateURL, stateCSSDqStr, stateCSSSqStr, stateCSSDqURL, stateCSSSqURL, stateCSSURL:
 		switch c.urlPart {
 		case urlPartNone:
-			s = append(s, "html_template_urlfilter")
+			s = append(s, "_html_template_urlfilter")
 			fallthrough
 		case urlPartPreQuery:
 			switch c.state {
 			case stateCSSDqStr, stateCSSSqStr:
-				s = append(s, "html_template_cssescaper")
+				s = append(s, "_html_template_cssescaper")
 			default:
-				s = append(s, "html_template_urlnormalizer")
+				s = append(s, "_html_template_urlnormalizer")
 			}
 		case urlPartQueryOrFrag:
-			s = append(s, "html_template_urlescaper")
+			s = append(s, "_html_template_urlescaper")
 		case urlPartUnknown:
 			return context{
 				state: stateError,
@@ -167,27 +167,27 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
 			panic(c.urlPart.String())
 		}
 	case stateJS:
-		s = append(s, "html_template_jsvalescaper")
+		s = append(s, "_html_template_jsvalescaper")
 		// A slash after a value starts a div operator.
 		c.jsCtx = jsCtxDivOp
 	case stateJSDqStr, stateJSSqStr:
-		s = append(s, "html_template_jsstrescaper")
+		s = append(s, "_html_template_jsstrescaper")
 	case stateJSRegexp:
-		s = append(s, "html_template_jsregexpescaper")
+		s = append(s, "_html_template_jsregexpescaper")
 	case stateCSS:
-		s = append(s, "html_template_cssvaluefilter")
+		s = append(s, "_html_template_cssvaluefilter")
 	case stateText:
-		s = append(s, "html_template_htmlescaper")
+		s = append(s, "_html_template_htmlescaper")
 	case stateRCDATA:
-		s = append(s, "html_template_rcdataescaper")
+		s = append(s, "_html_template_rcdataescaper")
 	case stateAttr:
 		// Handled below in delim check.
 	case stateAttrName, stateTag:
 		c.state = stateAttrName
-		s = append(s, "html_template_htmlnamefilter")
+		s = append(s, "_html_template_htmlnamefilter")
 	default:
 		if isComment(c.state) {
-			s = append(s, "html_template_commentescaper")
+			s = append(s, "_html_template_commentescaper")
 		} else {
 			panic("unexpected state " + c.state.String())
 		}
@@ -196,9 +196,9 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
 	case delimNone:
 		// No extra-escaping needed for raw text content.
 	case delimSpaceOrTagEnd:
-		s = append(s, "html_template_nospaceescaper")
+		s = append(s, "_html_template_nospaceescaper")
 	default:
-		s = append(s, "html_template_attrescaper")
+		s = append(s, "_html_template_attrescaper")
 	}
 	e.editActionNode(n, s)
 	return c
@@ -276,22 +276,22 @@ func ensurePipelineContains(p *parse.PipeNode, s []string) {
 // redundantFuncs[a][b] implies that funcMap[b](funcMap[a](x)) == funcMap[a](x)
 // for all x.
 var redundantFuncs = map[string]map[string]bool{
-	"html_template_commentescaper": {
-		"html_template_attrescaper":    true,
-		"html_template_nospaceescaper": true,
-		"html_template_htmlescaper":    true,
+	"_html_template_commentescaper": {
+		"_html_template_attrescaper":    true,
+		"_html_template_nospaceescaper": true,
+		"_html_template_htmlescaper":    true,
 	},
-	"html_template_cssescaper": {
-		"html_template_attrescaper": true,
+	"_html_template_cssescaper": {
+		"_html_template_attrescaper": true,
 	},
-	"html_template_jsregexpescaper": {
-		"html_template_attrescaper": true,
+	"_html_template_jsregexpescaper": {
+		"_html_template_attrescaper": true,
 	},
-	"html_template_jsstrescaper": {
-		"html_template_attrescaper": true,
+	"_html_template_jsstrescaper": {
+		"_html_template_attrescaper": true,
 	},
-	"html_template_urlescaper": {
-		"html_template_urlnormalizer": true,
+	"_html_template_urlescaper": {
+		"_html_template_urlnormalizer": true,
 	},
 }
 
diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
index 707394e..023ee57 100644
--- a/src/html/template/escape_test.go
+++ b/src/html/template/escape_test.go
@@ -990,7 +990,7 @@ func TestErrors(t *testing.T) {
 			}
 			continue
 		}
-		if strings.Index(got, test.err) == -1 {
+		if !strings.Contains(got, test.err) {
 			t.Errorf("input=%q: error\n\t%q\ndoes not contain expected string\n\t%q", test.input, got, test.err)
 			continue
 		}
diff --git a/src/html/template/examplefiles_test.go b/src/html/template/examplefiles_test.go
new file mode 100644
index 0000000..60518ae
--- /dev/null
+++ b/src/html/template/examplefiles_test.go
@@ -0,0 +1,226 @@
+// Copyright 2016 The Go Authors. 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 (
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"text/template"
+)
+
+// templateFile defines the contents of a template to be stored in a file, for testing.
+type templateFile struct {
+	name     string
+	contents string
+}
+
+func createTestDir(files []templateFile) string {
+	dir, err := ioutil.TempDir("", "template")
+	if err != nil {
+		log.Fatal(err)
+	}
+	for _, file := range files {
+		f, err := os.Create(filepath.Join(dir, file.name))
+		if err != nil {
+			log.Fatal(err)
+		}
+		defer f.Close()
+		_, err = io.WriteString(f, file.contents)
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+	return dir
+}
+
+// The following example is duplicated in text/template; keep them in sync.
+
+// Here we demonstrate loading a set of templates from a directory.
+func ExampleTemplate_glob() {
+	// Here we create a temporary directory and populate it with our sample
+	// template definition files; usually the template files would already
+	// exist in some location known to the program.
+	dir := createTestDir([]templateFile{
+		// T0.tmpl is a plain template file that just invokes T1.
+		{"T0.tmpl", `T0 invokes T1: ({{template "T1"}})`},
+		// T1.tmpl defines a template, T1 that invokes T2.
+		{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
+		// T2.tmpl defines a template T2.
+		{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
+	})
+	// Clean up after the test; another quirk of running as an example.
+	defer os.RemoveAll(dir)
+
+	// pattern is the glob pattern used to find all the template files.
+	pattern := filepath.Join(dir, "*.tmpl")
+
+	// Here starts the example proper.
+	// T0.tmpl is the first name matched, so it becomes the starting template,
+	// the value returned by ParseGlob.
+	tmpl := template.Must(template.ParseGlob(pattern))
+
+	err := tmpl.Execute(os.Stdout, nil)
+	if err != nil {
+		log.Fatalf("template execution: %s", err)
+	}
+	// Output:
+	// T0 invokes T1: (T1 invokes T2: (This is T2))
+}
+
+// Here we demonstrate loading a set of templates from files in different directories
+func ExampleTemplate_parsefiles() {
+	// Here we create different temporary directories and populate them with our sample
+	// template definition files; usually the template files would already
+	// exist in some location known to the program.
+	dir1 := createTestDir([]templateFile{
+		// T1.tmpl is a plain template file that just invokes T2.
+		{"T1.tmpl", `T1 invokes T2: ({{template "T2"}})`},
+	})
+
+	dir2 := createTestDir([]templateFile{
+		// T2.tmpl defines a template T2.
+		{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
+	})
+
+	// Clean up after the test; another quirk of running as an example.
+	defer func(dirs ...string) {
+		for _, dir := range dirs {
+			os.RemoveAll(dir)
+		}
+	}(dir1, dir2)
+
+	// Here starts the example proper.
+	// Let's just parse only dir1/T0 and dir2/T2
+	paths := []string{
+		filepath.Join(dir1, "T1.tmpl"),
+		filepath.Join(dir2, "T2.tmpl"),
+	}
+	tmpl := template.Must(template.ParseFiles(paths...))
+
+	err := tmpl.Execute(os.Stdout, nil)
+	if err != nil {
+		log.Fatalf("template execution: %s", err)
+	}
+	// Output:
+	// T1 invokes T2: (This is T2)
+}
+
+// The following example is duplicated in text/template; keep them in sync.
+
+// This example demonstrates one way to share some templates
+// and use them in different contexts. In this variant we add multiple driver
+// templates by hand to an existing bundle of templates.
+func ExampleTemplate_helpers() {
+	// Here we create a temporary directory and populate it with our sample
+	// template definition files; usually the template files would already
+	// exist in some location known to the program.
+	dir := createTestDir([]templateFile{
+		// T1.tmpl defines a template, T1 that invokes T2.
+		{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
+		// T2.tmpl defines a template T2.
+		{"T2.tmpl", `{{define "T2"}}This is T2{{end}}`},
+	})
+	// Clean up after the test; another quirk of running as an example.
+	defer os.RemoveAll(dir)
+
+	// pattern is the glob pattern used to find all the template files.
+	pattern := filepath.Join(dir, "*.tmpl")
+
+	// Here starts the example proper.
+	// Load the helpers.
+	templates := template.Must(template.ParseGlob(pattern))
+	// Add one driver template to the bunch; we do this with an explicit template definition.
+	_, err := templates.Parse("{{define `driver1`}}Driver 1 calls T1: ({{template `T1`}})\n{{end}}")
+	if err != nil {
+		log.Fatal("parsing driver1: ", err)
+	}
+	// Add another driver template.
+	_, err = templates.Parse("{{define `driver2`}}Driver 2 calls T2: ({{template `T2`}})\n{{end}}")
+	if err != nil {
+		log.Fatal("parsing driver2: ", err)
+	}
+	// We load all the templates before execution. This package does not require
+	// that behavior but html/template's escaping does, so it's a good habit.
+	err = templates.ExecuteTemplate(os.Stdout, "driver1", nil)
+	if err != nil {
+		log.Fatalf("driver1 execution: %s", err)
+	}
+	err = templates.ExecuteTemplate(os.Stdout, "driver2", nil)
+	if err != nil {
+		log.Fatalf("driver2 execution: %s", err)
+	}
+	// Output:
+	// Driver 1 calls T1: (T1 invokes T2: (This is T2))
+	// Driver 2 calls T2: (This is T2)
+}
+
+// The following example is duplicated in text/template; keep them in sync.
+
+// This example demonstrates how to use one group of driver
+// templates with distinct sets of helper templates.
+func ExampleTemplate_share() {
+	// Here we create a temporary directory and populate it with our sample
+	// template definition files; usually the template files would already
+	// exist in some location known to the program.
+	dir := createTestDir([]templateFile{
+		// T0.tmpl is a plain template file that just invokes T1.
+		{"T0.tmpl", "T0 ({{.}} version) invokes T1: ({{template `T1`}})\n"},
+		// T1.tmpl defines a template, T1 that invokes T2. Note T2 is not defined
+		{"T1.tmpl", `{{define "T1"}}T1 invokes T2: ({{template "T2"}}){{end}}`},
+	})
+	// Clean up after the test; another quirk of running as an example.
+	defer os.RemoveAll(dir)
+
+	// pattern is the glob pattern used to find all the template files.
+	pattern := filepath.Join(dir, "*.tmpl")
+
+	// Here starts the example proper.
+	// Load the drivers.
+	drivers := template.Must(template.ParseGlob(pattern))
+
+	// We must define an implementation of the T2 template. First we clone
+	// the drivers, then add a definition of T2 to the template name space.
+
+	// 1. Clone the helper set to create a new name space from which to run them.
+	first, err := drivers.Clone()
+	if err != nil {
+		log.Fatal("cloning helpers: ", err)
+	}
+	// 2. Define T2, version A, and parse it.
+	_, err = first.Parse("{{define `T2`}}T2, version A{{end}}")
+	if err != nil {
+		log.Fatal("parsing T2: ", err)
+	}
+
+	// Now repeat the whole thing, using a different version of T2.
+	// 1. Clone the drivers.
+	second, err := drivers.Clone()
+	if err != nil {
+		log.Fatal("cloning drivers: ", err)
+	}
+	// 2. Define T2, version B, and parse it.
+	_, err = second.Parse("{{define `T2`}}T2, version B{{end}}")
+	if err != nil {
+		log.Fatal("parsing T2: ", err)
+	}
+
+	// Execute the templates in the reverse order to verify the
+	// first is unaffected by the second.
+	err = second.ExecuteTemplate(os.Stdout, "T0.tmpl", "second")
+	if err != nil {
+		log.Fatalf("second execution: %s", err)
+	}
+	err = first.ExecuteTemplate(os.Stdout, "T0.tmpl", "first")
+	if err != nil {
+		log.Fatalf("first: execution: %s", err)
+	}
+
+	// Output:
+	// T0 (second version) invokes T1: (T1 invokes T2: (T2, version B))
+	// T0 (first version) invokes T1: (T1 invokes T2: (T2, version A))
+}
diff --git a/src/html/template/template.go b/src/html/template/template.go
index 96ab268..063e46d 100644
--- a/src/html/template/template.go
+++ b/src/html/template/template.go
@@ -346,6 +346,11 @@ func Must(t *Template, err error) *Template {
 // 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.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
+// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
+// named "foo", while "a/foo" is unavailable.
 func ParseFiles(filenames ...string) (*Template, error) {
 	return parseFiles(nil, filenames...)
 }
@@ -353,6 +358,9 @@ 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.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
 func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
 	return parseFiles(t, filenames...)
 }
@@ -399,6 +407,9 @@ func parseFiles(t *Template, filenames ...string) (*Template, error) {
 // returned template will have the (base) name and (parsed) contents of the
 // first file matched by the pattern. ParseGlob is equivalent to calling
 // ParseFiles with the list of files matched by the pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
 func ParseGlob(pattern string) (*Template, error) {
 	return parseGlob(nil, pattern)
 }
@@ -408,6 +419,9 @@ func ParseGlob(pattern string) (*Template, error) {
 // processed by filepath.Glob and must match at least one file. ParseGlob is
 // equivalent to calling t.ParseFiles with the list of files matched by the
 // pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
 func (t *Template) ParseGlob(pattern string) (*Template, error) {
 	return parseGlob(t, pattern)
 }
diff --git a/src/html/template/template_test.go b/src/html/template/template_test.go
index 6f70d67..46df1f8 100644
--- a/src/html/template/template_test.go
+++ b/src/html/template/template_test.go
@@ -13,7 +13,7 @@ func TestTemplateClone(t *testing.T) {
 		t.Fatal(err)
 	}
 	if len(clone.Templates()) != len(orig.Templates()) {
-		t.Fatalf("Invalid lenth of t.Clone().Templates()")
+		t.Fatalf("Invalid length of t.Clone().Templates()")
 	}
 
 	const want = "stuff"
diff --git a/src/html/template/url.go b/src/html/template/url.go
index 2ca76bf..246bfd3 100644
--- a/src/html/template/url.go
+++ b/src/html/template/url.go
@@ -17,7 +17,7 @@ func urlFilter(args ...interface{}) string {
 	if t == contentTypeURL {
 		return s
 	}
-	if i := strings.IndexRune(s, ':'); i >= 0 && strings.IndexRune(s[:i], '/') < 0 {
+	if i := strings.IndexRune(s, ':'); i >= 0 && !strings.ContainsRune(s[:i], '/') {
 		protocol := strings.ToLower(s[:i])
 		if protocol != "http" && protocol != "https" && protocol != "mailto" {
 			return "#" + filterFailsafe
diff --git a/src/image/color/color.go b/src/image/color/color.go
index cae059b..1044339 100644
--- a/src/image/color/color.go
+++ b/src/image/color/color.go
@@ -147,7 +147,7 @@ type Model interface {
 func ModelFunc(f func(Color) Color) Model {
 	// Note: using *modelFunc as the implementation
 	// means that callers can still use comparisons
-	// like m == RGBAModel.  This is not possible if
+	// like m == RGBAModel. This is not possible if
 	// we use the func value directly, because funcs
 	// are no longer comparable.
 	return &modelFunc{f}
diff --git a/src/image/color/palette/gen.go b/src/image/color/palette/gen.go
index 2b5fdaa..57718e6 100644
--- a/src/image/color/palette/gen.go
+++ b/src/image/color/palette/gen.go
@@ -89,7 +89,7 @@ func printPlan9(w io.Writer) {
 	fmt.Fprintln(w, "// of continuous tones.")
 	fmt.Fprintln(w, "//")
 	fmt.Fprintln(w, "// This palette was used in the Plan 9 Operating System, described at")
-	fmt.Fprintln(w, "// http://plan9.bell-labs.com/magic/man2html/6/color")
+	fmt.Fprintln(w, "// https://9p.io/magic/man2html/6/color")
 	fmt.Fprintln(w, "var Plan9 = []color.Color{")
 	for _, line := range lines {
 		fmt.Fprintln(w, line)
diff --git a/src/image/color/palette/palette.go b/src/image/color/palette/palette.go
index 0bf2c8e..b695414 100644
--- a/src/image/color/palette/palette.go
+++ b/src/image/color/palette/palette.go
@@ -19,7 +19,7 @@ import "image/color"
 // of continuous tones.
 //
 // This palette was used in the Plan 9 Operating System, described at
-// http://plan9.bell-labs.com/magic/man2html/6/color
+// https://9p.io/magic/man2html/6/color
 var Plan9 = []color.Color{
 	color.RGBA{0x00, 0x00, 0x00, 0xff},
 	color.RGBA{0x00, 0x00, 0x44, 0xff},
diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go
index 904434f..3df5d36 100644
--- a/src/image/color/ycbcr.go
+++ b/src/image/color/ycbcr.go
@@ -15,24 +15,37 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
 	r1 := int32(r)
 	g1 := int32(g)
 	b1 := int32(b)
+
+	// yy is in range [0,0xff].
 	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 > 0xff {
-		yy = 0xff
-	}
-	if cb < 0 {
-		cb = 0
-	} else if cb > 0xff {
-		cb = 0xff
+
+	// The bit twiddling below is equivalent to
+	//
+	// cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
+	// if cb < 0 {
+	//     cb = 0
+	// } else if cb > 0xff {
+	//     cb = ^int32(0)
+	// }
+	//
+	// but uses fewer branches and is faster.
+	// Note that the uint8 type conversion in the return
+	// statement will convert ^int32(0) to 0xff.
+	// The code below to compute cr uses a similar pattern.
+	cb := -11056*r1 - 21712*g1 + 32768*b1 + 257<<15
+	if uint32(cb)&0xff000000 == 0 {
+		cb >>= 16
+	} else {
+		cb = ^(cb >> 31)
 	}
-	if cr < 0 {
-		cr = 0
-	} else if cr > 0xff {
-		cr = 0xff
+
+	cr := 32768*r1 - 27440*g1 - 5328*b1 + 257<<15
+	if uint32(cr)&0xff000000 == 0 {
+		cr >>= 16
+	} else {
+		cr = ^(cr >> 31)
 	}
+
 	return uint8(yy), uint8(cb), uint8(cr)
 }
 
@@ -44,27 +57,44 @@ func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
 	//	B = Y' + 1.77200*(Cb-128)
 	// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
 
-	yy1 := int32(y) * 0x10100 // Convert 0x12 to 0x121200.
+	yy1 := int32(y) * 0x010100 // 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 > 0xff {
-		r = 0xff
+
+	// The bit twiddling below is equivalent to
+	//
+	// r := (yy1 + 91881*cr1) >> 16
+	// if r < 0 {
+	//     r = 0
+	// } else if r > 0xff {
+	//     r = ^int32(0)
+	// }
+	//
+	// but uses fewer branches and is faster.
+	// Note that the uint8 type conversion in the return
+	// statement will convert ^int32(0) to 0xff.
+	// The code below to compute g and b uses a similar pattern.
+	r := yy1 + 91881*cr1
+	if uint32(r)&0xff000000 == 0 {
+		r >>= 16
+	} else {
+		r = ^(r >> 31)
 	}
-	if g < 0 {
-		g = 0
-	} else if g > 0xff {
-		g = 0xff
+
+	g := yy1 - 22554*cb1 - 46802*cr1
+	if uint32(g)&0xff000000 == 0 {
+		g >>= 16
+	} else {
+		g = ^(g >> 31)
 	}
-	if b < 0 {
-		b = 0
-	} else if b > 0xff {
-		b = 0xff
+
+	b := yy1 + 116130*cb1
+	if uint32(b)&0xff000000 == 0 {
+		b >>= 16
+	} else {
+		b = ^(b >> 31)
 	}
+
 	return uint8(r), uint8(g), uint8(b)
 }
 
@@ -220,10 +250,10 @@ func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
 
 // 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
+	w := 0xffff - uint32(k)*0x101
+	r := (0xffff - uint32(c)*0x101) * w / 0xffff
+	g := (0xffff - uint32(m)*0x101) * w / 0xffff
+	b := (0xffff - uint32(y)*0x101) * w / 0xffff
 	return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
 }
 
@@ -239,11 +269,11 @@ 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
+	w := 0xffff - uint32(c.K)*0x101
+	r := (0xffff - uint32(c.C)*0x101) * w / 0xffff
+	g := (0xffff - uint32(c.M)*0x101) * w / 0xffff
+	b := (0xffff - uint32(c.Y)*0x101) * w / 0xffff
+	return r, g, b, 0xffff
 }
 
 // CMYKModel is the Model for CMYK colors.
diff --git a/src/image/color/ycbcr_test.go b/src/image/color/ycbcr_test.go
index f5e7cbf..561699f 100644
--- a/src/image/color/ycbcr_test.go
+++ b/src/image/color/ycbcr_test.go
@@ -171,3 +171,47 @@ func TestPalette(t *testing.T) {
 		t.Errorf("got %v, want %v", got, want)
 	}
 }
+
+var sink uint8
+
+func BenchmarkYCbCrToRGB(b *testing.B) {
+	// YCbCrToRGB does saturating arithmetic.
+	// Low, middle, and high values can take
+	// different paths through the generated code.
+	b.Run("0", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			sink, sink, sink = YCbCrToRGB(0, 0, 0)
+		}
+	})
+	b.Run("128", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			sink, sink, sink = YCbCrToRGB(128, 128, 128)
+		}
+	})
+	b.Run("255", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			sink, sink, sink = YCbCrToRGB(255, 255, 255)
+		}
+	})
+}
+
+func BenchmarkRGBToYCbCr(b *testing.B) {
+	// RGBToYCbCr does saturating arithmetic.
+	// Different values can take different paths
+	// through the generated code.
+	b.Run("0", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			sink, sink, sink = RGBToYCbCr(0, 0, 0)
+		}
+	})
+	b.Run("Cb", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			sink, sink, sink = RGBToYCbCr(0, 0, 255)
+		}
+	})
+	b.Run("Cr", func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			sink, sink, sink = RGBToYCbCr(255, 0, 0)
+		}
+	})
+}
diff --git a/src/image/decode_test.go b/src/image/decode_test.go
index d16ef8a..85e235e 100644
--- a/src/image/decode_test.go
+++ b/src/image/decode_test.go
@@ -36,6 +36,7 @@ var imageTests = []imageTest{
 	{"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},
+	{"testdata/video-001.progressive.truncated.png", "testdata/video-001.progressive.truncated.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},
diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go
index e47c48d..6a16cd3 100644
--- a/src/image/draw/draw.go
+++ b/src/image/draw/draw.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -634,10 +634,10 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 				if !floydSteinberg {
 					continue
 				}
-				er -= int32(palette[bestIndex][0])
-				eg -= int32(palette[bestIndex][1])
-				eb -= int32(palette[bestIndex][2])
-				ea -= int32(palette[bestIndex][3])
+				er -= palette[bestIndex][0]
+				eg -= palette[bestIndex][1]
+				eb -= palette[bestIndex][2]
+				ea -= palette[bestIndex][3]
 
 			} else {
 				out.R = uint16(er)
diff --git a/src/image/gif/reader.go b/src/image/gif/reader.go
index 6a13312..6181a94 100644
--- a/src/image/gif/reader.go
+++ b/src/image/gif/reader.go
@@ -96,7 +96,7 @@ type decoder struct {
 // blockReader parses the block structure of GIF image data, which
 // comprises (n, (n bytes)) blocks, with 1 <= n <= 255.  It is the
 // reader given to the LZW decoder, which is thus immune to the
-// blocking.  After the LZW decoder completes, there will be a 0-byte
+// blocking. After the LZW decoder completes, there will be a 0-byte
 // block remaining (0, ()), which is consumed when checking that the
 // blockReader is exhausted.
 type blockReader struct {
@@ -178,12 +178,25 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 				}
 				m.Palette = d.globalColorTable
 			}
-			if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
+			if d.hasTransparentIndex {
 				if !useLocalColorTable {
 					// Clone the global color table.
 					m.Palette = append(color.Palette(nil), d.globalColorTable...)
 				}
-				m.Palette[d.transparentIndex] = color.RGBA{}
+				if ti := int(d.transparentIndex); ti < len(m.Palette) {
+					m.Palette[ti] = color.RGBA{}
+				} else {
+					// The transparentIndex is out of range, which is an error
+					// according to the spec, but Firefox and Google Chrome
+					// seem OK with this, so we enlarge the palette with
+					// transparent colors. See golang.org/issue/15059.
+					p := make(color.Palette, ti+1)
+					copy(p, m.Palette)
+					for i := len(m.Palette); i < len(p); i++ {
+						p[i] = color.RGBA{}
+					}
+					m.Palette = p
+				}
 			}
 			litWidth, err := d.r.ReadByte()
 			if err != nil {
@@ -210,7 +223,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 			// 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
+			// before the LZW decoder saw an explicit 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) {
@@ -349,6 +362,9 @@ func (d *decoder) readGraphicControl() error {
 	if _, err := io.ReadFull(d.r, d.tmp[:6]); err != nil {
 		return fmt.Errorf("gif: can't read graphic control: %s", err)
 	}
+	if d.tmp[0] != 4 {
+		return fmt.Errorf("gif: invalid graphic control extension block size: %d", d.tmp[0])
+	}
 	flags := d.tmp[1]
 	d.disposalMethod = (flags & gcDisposalMethodMask) >> 2
 	d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
@@ -356,6 +372,9 @@ func (d *decoder) readGraphicControl() error {
 		d.transparentIndex = d.tmp[4]
 		d.hasTransparentIndex = true
 	}
+	if d.tmp[5] != 0 {
+		return fmt.Errorf("gif: invalid graphic control extension block terminator: %d", d.tmp[5])
+	}
 	return nil
 }
 
diff --git a/src/image/gif/reader_test.go b/src/image/gif/reader_test.go
index c294195..90c8149 100644
--- a/src/image/gif/reader_test.go
+++ b/src/image/gif/reader_test.go
@@ -22,12 +22,16 @@ const (
 	trailerStr = "\x3b"
 )
 
-// lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
-func lzwEncode(n int) []byte {
+// lzwEncode returns an LZW encoding (with 2-bit literals) of in.
+func lzwEncode(in []byte) []byte {
 	b := &bytes.Buffer{}
 	w := lzw.NewWriter(b, lzw.LSB, 2)
-	w.Write(make([]byte, n))
-	w.Close()
+	if _, err := w.Write(in); err != nil {
+		panic(err)
+	}
+	if err := w.Close(); err != nil {
+		panic(err)
+	}
 	return b.Bytes()
 }
 
@@ -53,7 +57,7 @@ func TestDecode(t *testing.T) {
 		// byte, and 2-bit LZW literals.
 		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
 		if tc.nPix > 0 {
-			enc := lzwEncode(tc.nPix)
+			enc := lzwEncode(make([]byte, tc.nPix))
 			if len(enc) > 0xff {
 				t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
 				continue
@@ -97,13 +101,13 @@ func TestTransparentIndex(t *testing.T) {
 	for transparentIndex := 0; transparentIndex < 3; transparentIndex++ {
 		if transparentIndex < 2 {
 			// Write the graphic control for the transparent index.
-			b.WriteString("\x21\xf9\x00\x01\x00\x00")
+			b.WriteString("\x21\xf9\x04\x01\x00\x00")
 			b.WriteByte(byte(transparentIndex))
 			b.WriteByte(0)
 		}
 		// Write an image with bounds 2x1, as per TestDecode.
 		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
-		enc := lzwEncode(2)
+		enc := lzwEncode([]byte{0x00, 0x00})
 		if len(enc) > 0xff {
 			t.Fatalf("compressed length %d is too large", len(enc))
 		}
@@ -196,21 +200,13 @@ func TestNoPalette(t *testing.T) {
 	b.WriteString(headerStr[:len(headerStr)-3])
 	b.WriteString("\x00\x00\x00") // No global palette.
 
-	// Image descriptor: 2x1, no local palette.
+	// Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
 	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, 3}
-	enc := &bytes.Buffer{}
-	w := lzw.NewWriter(enc, lzw.LSB, 2)
-	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())
+	enc := lzwEncode([]byte{0x00, 0x03})
+	b.WriteByte(byte(len(enc)))
+	b.Write(enc)
 	b.WriteByte(0x00) // An empty block signifies the end of the image data.
 
 	b.WriteString(trailerStr)
@@ -226,21 +222,13 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
 		b.WriteString(headerStr)
 		b.WriteString(paletteStr)
 
-		// Image descriptor: 2x1, no local palette.
+		// Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
 		b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
 
 		// Encode the pixels; some pvals trigger the expected error.
-		pix := []byte{pval, pval}
-		enc := &bytes.Buffer{}
-		w := lzw.NewWriter(enc, lzw.LSB, 2)
-		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())
+		enc := lzwEncode([]byte{pval, pval})
+		b.WriteByte(byte(len(enc)))
+		b.Write(enc)
 		b.WriteByte(0x00) // An empty block signifies the end of the image data.
 
 		b.WriteString(trailerStr)
@@ -254,6 +242,36 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
 	}
 }
 
+func TestTransparentPixelOutsidePaletteRange(t *testing.T) {
+	b := &bytes.Buffer{}
+
+	// Manufacture a GIF with a 2 color palette.
+	b.WriteString(headerStr)
+	b.WriteString(paletteStr)
+
+	// Graphic Control Extension: transparency, transparent color index = 3.
+	//
+	// This index, 3, is out of range of the global palette and there is no
+	// local palette in the subsequent image descriptor. This is an error
+	// according to the spec, but Firefox and Google Chrome seem OK with this.
+	//
+	// See golang.org/issue/15059.
+	b.WriteString("\x21\xf9\x04\x01\x00\x00\x03\x00")
+
+	// Image descriptor: 2x1, no local palette, and 2-bit LZW literals.
+	b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
+
+	// Encode the pixels.
+	enc := lzwEncode([]byte{0x03, 0x03})
+	b.WriteByte(byte(len(enc)))
+	b.Write(enc)
+	b.WriteByte(0x00) // An empty block signifies the end of the image data.
+
+	b.WriteString(trailerStr)
+
+	try(t, b.Bytes(), "")
+}
+
 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;")
diff --git a/src/image/internal/imageutil/gen.go b/src/image/internal/imageutil/gen.go
index fc1e707..6792b28 100644
--- a/src/image/internal/imageutil/gen.go
+++ b/src/image/internal/imageutil/gen.go
@@ -95,32 +95,51 @@ const sratioCase = `
 			%s
 
 				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
-				yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+				yy1 := int32(src.Y[yi]) * 0x010100 // 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
+
+				// The bit twiddling below is equivalent to
+				//
+				// r := (yy1 + 91881*cr1) >> 16
+				// if r < 0 {
+				//     r = 0
+				// } else if r > 0xff {
+				//     r = ^int32(0)
+				// }
+				//
+				// but uses fewer branches and is faster.
+				// Note that the uint8 type conversion in the return
+				// statement will convert ^int32(0) to 0xff.
+				// The code below to compute g and b uses a similar pattern.
+				r := yy1 + 91881*cr1
+				if uint32(r)&0xff000000 == 0 {
+					r >>= 16
+				} else {
+					r = ^(r >> 31)
 				}
-				if g < 0 {
-					g = 0
-				} else if g > 255 {
-					g = 255
+
+				g := yy1 - 22554*cb1 - 46802*cr1
+				if uint32(g)&0xff000000 == 0 {
+					g >>= 16
+				} else {
+					g = ^(g >> 31)
 				}
-				if b < 0 {
-					b = 0
-				} else if b > 255 {
-					b = 255
+
+				b := yy1 + 116130*cb1
+				if uint32(b)&0xff000000 == 0 {
+					b >>= 16
+				} else {
+					b = ^(b >> 31)
 				}
 
-				dpix[x+0] = uint8(r)
-				dpix[x+1] = uint8(g)
-				dpix[x+2] = uint8(b)
-				dpix[x+3] = 255
+
+				// use a temp slice to hint to the compiler that a single bounds check suffices
+				rgba := dpix[x : x+4 : len(dpix)]
+				rgba[0] = uint8(r)
+				rgba[1] = uint8(g)
+				rgba[2] = uint8(b)
+				rgba[3] = 255
 			}
 		}
 `
diff --git a/src/image/internal/imageutil/impl.go b/src/image/internal/imageutil/impl.go
index fd7826d..3696b08 100644
--- a/src/image/internal/imageutil/impl.go
+++ b/src/image/internal/imageutil/impl.go
@@ -44,32 +44,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
 			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.
+				yy1 := int32(src.Y[yi]) * 0x010100 // 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
+
+				// The bit twiddling below is equivalent to
+				//
+				// r := (yy1 + 91881*cr1) >> 16
+				// if r < 0 {
+				//     r = 0
+				// } else if r > 0xff {
+				//     r = ^int32(0)
+				// }
+				//
+				// but uses fewer branches and is faster.
+				// Note that the uint8 type conversion in the return
+				// statement will convert ^int32(0) to 0xff.
+				// The code below to compute g and b uses a similar pattern.
+				r := yy1 + 91881*cr1
+				if uint32(r)&0xff000000 == 0 {
+					r >>= 16
+				} else {
+					r = ^(r >> 31)
 				}
-				if g < 0 {
-					g = 0
-				} else if g > 255 {
-					g = 255
+
+				g := yy1 - 22554*cb1 - 46802*cr1
+				if uint32(g)&0xff000000 == 0 {
+					g >>= 16
+				} else {
+					g = ^(g >> 31)
 				}
-				if b < 0 {
-					b = 0
-				} else if b > 255 {
-					b = 255
+
+				b := yy1 + 116130*cb1
+				if uint32(b)&0xff000000 == 0 {
+					b >>= 16
+				} else {
+					b = ^(b >> 31)
 				}
 
-				dpix[x+0] = uint8(r)
-				dpix[x+1] = uint8(g)
-				dpix[x+2] = uint8(b)
-				dpix[x+3] = 255
+				// use a temp slice to hint to the compiler that a single bounds check suffices
+				rgba := dpix[x : x+4 : len(dpix)]
+				rgba[0] = uint8(r)
+				rgba[1] = uint8(g)
+				rgba[2] = uint8(b)
+				rgba[3] = 255
 			}
 		}
 
@@ -83,32 +101,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
 				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.
+				yy1 := int32(src.Y[yi]) * 0x010100 // 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
+
+				// The bit twiddling below is equivalent to
+				//
+				// r := (yy1 + 91881*cr1) >> 16
+				// if r < 0 {
+				//     r = 0
+				// } else if r > 0xff {
+				//     r = ^int32(0)
+				// }
+				//
+				// but uses fewer branches and is faster.
+				// Note that the uint8 type conversion in the return
+				// statement will convert ^int32(0) to 0xff.
+				// The code below to compute g and b uses a similar pattern.
+				r := yy1 + 91881*cr1
+				if uint32(r)&0xff000000 == 0 {
+					r >>= 16
+				} else {
+					r = ^(r >> 31)
 				}
-				if g < 0 {
-					g = 0
-				} else if g > 255 {
-					g = 255
+
+				g := yy1 - 22554*cb1 - 46802*cr1
+				if uint32(g)&0xff000000 == 0 {
+					g >>= 16
+				} else {
+					g = ^(g >> 31)
 				}
-				if b < 0 {
-					b = 0
-				} else if b > 255 {
-					b = 255
+
+				b := yy1 + 116130*cb1
+				if uint32(b)&0xff000000 == 0 {
+					b >>= 16
+				} else {
+					b = ^(b >> 31)
 				}
 
-				dpix[x+0] = uint8(r)
-				dpix[x+1] = uint8(g)
-				dpix[x+2] = uint8(b)
-				dpix[x+3] = 255
+				// use a temp slice to hint to the compiler that a single bounds check suffices
+				rgba := dpix[x : x+4 : len(dpix)]
+				rgba[0] = uint8(r)
+				rgba[1] = uint8(g)
+				rgba[2] = uint8(b)
+				rgba[3] = 255
 			}
 		}
 
@@ -122,32 +158,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
 				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.
+				yy1 := int32(src.Y[yi]) * 0x010100 // 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
+
+				// The bit twiddling below is equivalent to
+				//
+				// r := (yy1 + 91881*cr1) >> 16
+				// if r < 0 {
+				//     r = 0
+				// } else if r > 0xff {
+				//     r = ^int32(0)
+				// }
+				//
+				// but uses fewer branches and is faster.
+				// Note that the uint8 type conversion in the return
+				// statement will convert ^int32(0) to 0xff.
+				// The code below to compute g and b uses a similar pattern.
+				r := yy1 + 91881*cr1
+				if uint32(r)&0xff000000 == 0 {
+					r >>= 16
+				} else {
+					r = ^(r >> 31)
 				}
-				if g < 0 {
-					g = 0
-				} else if g > 255 {
-					g = 255
+
+				g := yy1 - 22554*cb1 - 46802*cr1
+				if uint32(g)&0xff000000 == 0 {
+					g >>= 16
+				} else {
+					g = ^(g >> 31)
 				}
-				if b < 0 {
-					b = 0
-				} else if b > 255 {
-					b = 255
+
+				b := yy1 + 116130*cb1
+				if uint32(b)&0xff000000 == 0 {
+					b >>= 16
+				} else {
+					b = ^(b >> 31)
 				}
 
-				dpix[x+0] = uint8(r)
-				dpix[x+1] = uint8(g)
-				dpix[x+2] = uint8(b)
-				dpix[x+3] = 255
+				// use a temp slice to hint to the compiler that a single bounds check suffices
+				rgba := dpix[x : x+4 : len(dpix)]
+				rgba[0] = uint8(r)
+				rgba[1] = uint8(g)
+				rgba[2] = uint8(b)
+				rgba[3] = 255
 			}
 		}
 
@@ -160,32 +214,50 @@ func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
 			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.
+				yy1 := int32(src.Y[yi]) * 0x010100 // 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
+
+				// The bit twiddling below is equivalent to
+				//
+				// r := (yy1 + 91881*cr1) >> 16
+				// if r < 0 {
+				//     r = 0
+				// } else if r > 0xff {
+				//     r = ^int32(0)
+				// }
+				//
+				// but uses fewer branches and is faster.
+				// Note that the uint8 type conversion in the return
+				// statement will convert ^int32(0) to 0xff.
+				// The code below to compute g and b uses a similar pattern.
+				r := yy1 + 91881*cr1
+				if uint32(r)&0xff000000 == 0 {
+					r >>= 16
+				} else {
+					r = ^(r >> 31)
 				}
-				if g < 0 {
-					g = 0
-				} else if g > 255 {
-					g = 255
+
+				g := yy1 - 22554*cb1 - 46802*cr1
+				if uint32(g)&0xff000000 == 0 {
+					g >>= 16
+				} else {
+					g = ^(g >> 31)
 				}
-				if b < 0 {
-					b = 0
-				} else if b > 255 {
-					b = 255
+
+				b := yy1 + 116130*cb1
+				if uint32(b)&0xff000000 == 0 {
+					b >>= 16
+				} else {
+					b = ^(b >> 31)
 				}
 
-				dpix[x+0] = uint8(r)
-				dpix[x+1] = uint8(g)
-				dpix[x+2] = uint8(b)
-				dpix[x+3] = 255
+				// use a temp slice to hint to the compiler that a single bounds check suffices
+				rgba := dpix[x : x+4 : len(dpix)]
+				rgba[0] = uint8(r)
+				rgba[1] = uint8(g)
+				rgba[2] = uint8(b)
+				rgba[3] = 255
 			}
 		}
 
diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go
index adf97ab..c583421 100644
--- a/src/image/jpeg/reader.go
+++ b/src/image/jpeg/reader.go
@@ -641,6 +641,12 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
 			return nil, err
 		}
 	}
+
+	if d.progressive {
+		if err := d.reconstructProgressiveImage(); err != nil {
+			return nil, err
+		}
+	}
 	if d.img1 != nil {
 		return d.img1, nil
 	}
diff --git a/src/image/jpeg/scan.go b/src/image/jpeg/scan.go
index 99734c0..e1104d2 100644
--- a/src/image/jpeg/scan.go
+++ b/src/image/jpeg/scan.go
@@ -173,7 +173,6 @@ func (d *decoder) processSOS(n int) error {
 				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 < 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.
@@ -286,55 +285,19 @@ 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*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,
-							// the jpeg.Decode function does not return until the entire image is decoded,
-							// so we "continue" here to avoid wasted computation.
-							continue
-						}
-					}
-
-					// Dequantize, perform the inverse DCT and store the block to the image.
-					for zig := 0; zig < blockSize; zig++ {
-						b[unzig[zig]] *= qt[zig]
+						// Save the coefficients.
+						d.progCoeffs[compIndex][by*mxx*hi+bx] = b
+						// At this point, we could call reconstructBlock 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, the jpeg.Decode
+						// function does not return until the entire image is decoded, so we "continue"
+						// here to avoid wasted computation. Instead, reconstructBlock is called on each
+						// accumulated block by the reconstructProgressiveImage method after all of the
+						// SOS markers are processed.
+						continue
 					}
-					idct(&b)
-					dst, stride := []byte(nil), 0
-					if d.nComp == 1 {
-						dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
-					} else {
-						switch compIndex {
-						case 0:
-							dst, stride = d.img3.Y[8*(by*d.img3.YStride+bx):], d.img3.YStride
-						case 1:
-							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")
-						}
-					}
-					// Level shift by +128, clip to [0, 255], and write to dst.
-					for y := 0; y < 8; y++ {
-						y8 := y * 8
-						yStride := y * stride
-						for x := 0; x < 8; x++ {
-							c := b[y8+x]
-							if c < -128 {
-								c = 0
-							} else if c > 127 {
-								c = 255
-							} else {
-								c += 128
-							}
-							dst[yStride+x] = uint8(c)
-						}
+					if err := d.reconstructBlock(&b, bx, by, int(compIndex)); err != nil {
+						return err
 					}
 				} // for j
 			} // for i
@@ -470,3 +433,70 @@ func (d *decoder) refineNonZeroes(b *block, zig, zigEnd, nz, delta int32) (int32
 	}
 	return zig, nil
 }
+
+func (d *decoder) reconstructProgressiveImage() error {
+	// The h0, mxx, by and bx variables have the same meaning as in the
+	// processSOS method.
+	h0 := d.comp[0].h
+	mxx := (d.width + 8*h0 - 1) / (8 * h0)
+	for i := 0; i < d.nComp; i++ {
+		if d.progCoeffs[i] == nil {
+			continue
+		}
+		v := 8 * d.comp[0].v / d.comp[i].v
+		h := 8 * d.comp[0].h / d.comp[i].h
+		stride := mxx * d.comp[i].h
+		for by := 0; by*v < d.height; by++ {
+			for bx := 0; bx*h < d.width; bx++ {
+				if err := d.reconstructBlock(&d.progCoeffs[i][by*stride+bx], bx, by, i); err != nil {
+					return err
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// reconstructBlock dequantizes, performs the inverse DCT and stores the block
+// to the image.
+func (d *decoder) reconstructBlock(b *block, bx, by, compIndex int) error {
+	qt := &d.quant[d.comp[compIndex].tq]
+	for zig := 0; zig < blockSize; zig++ {
+		b[unzig[zig]] *= qt[zig]
+	}
+	idct(b)
+	dst, stride := []byte(nil), 0
+	if d.nComp == 1 {
+		dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
+	} else {
+		switch compIndex {
+		case 0:
+			dst, stride = d.img3.Y[8*(by*d.img3.YStride+bx):], d.img3.YStride
+		case 1:
+			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")
+		}
+	}
+	// Level shift by +128, clip to [0, 255], and write to dst.
+	for y := 0; y < 8; y++ {
+		y8 := y * 8
+		yStride := y * stride
+		for x := 0; x < 8; x++ {
+			c := b[y8+x]
+			if c < -128 {
+				c = 0
+			} else if c > 127 {
+				c = 255
+			} else {
+				c += 128
+			}
+			dst[yStride+x] = uint8(c)
+		}
+	}
+	return nil
+}
diff --git a/src/image/png/reader.go b/src/image/png/reader.go
index 9e6f985..2dd5ed8 100644
--- a/src/image/png/reader.go
+++ b/src/image/png/reader.go
@@ -717,6 +717,13 @@ func (d *decoder) parseChunk() error {
 	case "IDAT":
 		if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.stage == dsSeenIHDR && cbPaletted(d.cb)) {
 			return chunkOrderError
+		} else if d.stage == dsSeenIDAT {
+			// Ignore trailing zero-length or garbage IDAT chunks.
+			//
+			// This does not affect valid PNG images that contain multiple IDAT
+			// chunks, since the first call to parseIDAT below will consume all
+			// consecutive IDAT chunks required for decoding the image.
+			break
 		}
 		d.stage = dsSeenIDAT
 		return d.parseIDAT(length)
diff --git a/src/image/png/reader_test.go b/src/image/png/reader_test.go
index f058f6b..0bc4203 100644
--- a/src/image/png/reader_test.go
+++ b/src/image/png/reader_test.go
@@ -350,6 +350,33 @@ func TestIncompleteIDATOnRowBoundary(t *testing.T) {
 	}
 }
 
+func TestTrailingIDATChunks(t *testing.T) {
+	// The following is a valid 1x1 PNG image containing color.Gray{255} and
+	// a trailing zero-length IDAT chunk (see PNG specification section 12.9):
+	const (
+		ihdr      = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x00\x00\x00\x00\x3a\x7e\x9b\x55"
+		idatWhite = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\xfa\x0f\x08\x00\x00\xff\xff\x01\x05\x01\x02\x5a\xdd\x39\xcd"
+		idatZero  = "\x00\x00\x00\x00IDAT\x35\xaf\x06\x1e"
+		iend      = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
+	)
+	_, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatZero + iend))
+	if err != nil {
+		t.Fatalf("decoding valid image: %v", err)
+	}
+
+	// Non-zero-length trailing IDAT chunks should be ignored (recoverable error).
+	// The following chunk contains a single pixel with color.Gray{0}.
+	const idatBlack = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
+
+	img, err := Decode(strings.NewReader(pngHeader + ihdr + idatWhite + idatBlack + iend))
+	if err != nil {
+		t.Fatalf("trailing IDAT not ignored: %v", err)
+	}
+	if img.At(0, 0) == (color.Gray{0}) {
+		t.Fatal("decoded image from trailing IDAT chunk")
+	}
+}
+
 func TestMultipletRNSChunks(t *testing.T) {
 	/*
 		The following is a valid 1x1 paletted PNG image with a 1-element palette
diff --git a/src/image/testdata/video-001.progressive.truncated.jpeg b/src/image/testdata/video-001.progressive.truncated.jpeg
new file mode 100644
index 0000000..b5be8bc
Binary files /dev/null and b/src/image/testdata/video-001.progressive.truncated.jpeg differ
diff --git a/src/image/testdata/video-001.progressive.truncated.png b/src/image/testdata/video-001.progressive.truncated.png
new file mode 100644
index 0000000..baf1981
Binary files /dev/null and b/src/image/testdata/video-001.progressive.truncated.png differ
diff --git a/src/internal/golang.org/x/net/http2/hpack/encode.go b/src/internal/golang.org/x/net/http2/hpack/encode.go
deleted file mode 100644
index 80d621c..0000000
--- a/src/internal/golang.org/x/net/http2/hpack/encode.go
+++ /dev/null
@@ -1,251 +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 hpack
-
-import (
-	"io"
-)
-
-const (
-	uint32Max              = ^uint32(0)
-	initialHeaderTableSize = 4096
-)
-
-type Encoder struct {
-	dynTab dynamicTable
-	// minSize is the minimum table size set by
-	// SetMaxDynamicTableSize after the previous Header Table Size
-	// Update.
-	minSize uint32
-	// maxSizeLimit is the maximum table size this encoder
-	// supports. This will protect the encoder from too large
-	// size.
-	maxSizeLimit uint32
-	// tableSizeUpdate indicates whether "Header Table Size
-	// Update" is required.
-	tableSizeUpdate bool
-	w               io.Writer
-	buf             []byte
-}
-
-// NewEncoder returns a new Encoder which performs HPACK encoding. An
-// encoded data is written to w.
-func NewEncoder(w io.Writer) *Encoder {
-	e := &Encoder{
-		minSize:         uint32Max,
-		maxSizeLimit:    initialHeaderTableSize,
-		tableSizeUpdate: false,
-		w:               w,
-	}
-	e.dynTab.setMaxSize(initialHeaderTableSize)
-	return e
-}
-
-// WriteField encodes f into a single Write to e's underlying Writer.
-// This function may also produce bytes for "Header Table Size Update"
-// if necessary.  If produced, it is done before encoding f.
-func (e *Encoder) WriteField(f HeaderField) error {
-	e.buf = e.buf[:0]
-
-	if e.tableSizeUpdate {
-		e.tableSizeUpdate = false
-		if e.minSize < e.dynTab.maxSize {
-			e.buf = appendTableSize(e.buf, e.minSize)
-		}
-		e.minSize = uint32Max
-		e.buf = appendTableSize(e.buf, e.dynTab.maxSize)
-	}
-
-	idx, nameValueMatch := e.searchTable(f)
-	if nameValueMatch {
-		e.buf = appendIndexed(e.buf, idx)
-	} else {
-		indexing := e.shouldIndex(f)
-		if indexing {
-			e.dynTab.add(f)
-		}
-
-		if idx == 0 {
-			e.buf = appendNewName(e.buf, f, indexing)
-		} else {
-			e.buf = appendIndexedName(e.buf, f, idx, indexing)
-		}
-	}
-	n, err := e.w.Write(e.buf)
-	if err == nil && n != len(e.buf) {
-		err = io.ErrShortWrite
-	}
-	return err
-}
-
-// searchTable searches f in both stable and dynamic header tables.
-// The static header table is searched first. Only when there is no
-// exact match for both name and value, the dynamic header table is
-// then searched. If there is no match, i is 0. If both name and value
-// match, i is the matched index and nameValueMatch becomes true. If
-// only name matches, i points to that index and nameValueMatch
-// becomes false.
-func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) {
-	for idx, hf := range staticTable {
-		if !constantTimeStringCompare(hf.Name, f.Name) {
-			continue
-		}
-		if i == 0 {
-			i = uint64(idx + 1)
-		}
-		if f.Sensitive {
-			continue
-		}
-		if !constantTimeStringCompare(hf.Value, f.Value) {
-			continue
-		}
-		i = uint64(idx + 1)
-		nameValueMatch = true
-		return
-	}
-
-	j, nameValueMatch := e.dynTab.search(f)
-	if nameValueMatch || (i == 0 && j != 0) {
-		i = j + uint64(len(staticTable))
-	}
-	return
-}
-
-// SetMaxDynamicTableSize changes the dynamic header table size to v.
-// The actual size is bounded by the value passed to
-// SetMaxDynamicTableSizeLimit.
-func (e *Encoder) SetMaxDynamicTableSize(v uint32) {
-	if v > e.maxSizeLimit {
-		v = e.maxSizeLimit
-	}
-	if v < e.minSize {
-		e.minSize = v
-	}
-	e.tableSizeUpdate = true
-	e.dynTab.setMaxSize(v)
-}
-
-// SetMaxDynamicTableSizeLimit changes the maximum value that can be
-// specified in SetMaxDynamicTableSize to v. By default, it is set to
-// 4096, which is the same size of the default dynamic header table
-// size described in HPACK specification. If the current maximum
-// dynamic header table size is strictly greater than v, "Header Table
-// Size Update" will be done in the next WriteField call and the
-// maximum dynamic header table size is truncated to v.
-func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
-	e.maxSizeLimit = v
-	if e.dynTab.maxSize > v {
-		e.tableSizeUpdate = true
-		e.dynTab.setMaxSize(v)
-	}
-}
-
-// shouldIndex reports whether f should be indexed.
-func (e *Encoder) shouldIndex(f HeaderField) bool {
-	return !f.Sensitive && f.size() <= e.dynTab.maxSize
-}
-
-// appendIndexed appends index i, as encoded in "Indexed Header Field"
-// representation, to dst and returns the extended buffer.
-func appendIndexed(dst []byte, i uint64) []byte {
-	first := len(dst)
-	dst = appendVarInt(dst, 7, i)
-	dst[first] |= 0x80
-	return dst
-}
-
-// appendNewName appends f, as encoded in one of "Literal Header field
-// - New Name" representation variants, to dst and returns the
-// extended buffer.
-//
-// If f.Sensitive is true, "Never Indexed" representation is used. If
-// f.Sensitive is false and indexing is true, "Inremental Indexing"
-// representation is used.
-func appendNewName(dst []byte, f HeaderField, indexing bool) []byte {
-	dst = append(dst, encodeTypeByte(indexing, f.Sensitive))
-	dst = appendHpackString(dst, f.Name)
-	return appendHpackString(dst, f.Value)
-}
-
-// appendIndexedName appends f and index i referring indexed name
-// entry, as encoded in one of "Literal Header field - Indexed Name"
-// representation variants, to dst and returns the extended buffer.
-//
-// If f.Sensitive is true, "Never Indexed" representation is used. If
-// f.Sensitive is false and indexing is true, "Incremental Indexing"
-// representation is used.
-func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byte {
-	first := len(dst)
-	var n byte
-	if indexing {
-		n = 6
-	} else {
-		n = 4
-	}
-	dst = appendVarInt(dst, n, i)
-	dst[first] |= encodeTypeByte(indexing, f.Sensitive)
-	return appendHpackString(dst, f.Value)
-}
-
-// appendTableSize appends v, as encoded in "Header Table Size Update"
-// representation, to dst and returns the extended buffer.
-func appendTableSize(dst []byte, v uint32) []byte {
-	first := len(dst)
-	dst = appendVarInt(dst, 5, uint64(v))
-	dst[first] |= 0x20
-	return dst
-}
-
-// appendVarInt appends i, as encoded in variable integer form using n
-// bit prefix, to dst and returns the extended buffer.
-//
-// See
-// http://http2.github.io/http2-spec/compression.html#integer.representation
-func appendVarInt(dst []byte, n byte, i uint64) []byte {
-	k := uint64((1 << n) - 1)
-	if i < k {
-		return append(dst, byte(i))
-	}
-	dst = append(dst, byte(k))
-	i -= k
-	for ; i >= 128; i >>= 7 {
-		dst = append(dst, byte(0x80|(i&0x7f)))
-	}
-	return append(dst, byte(i))
-}
-
-// appendHpackString appends s, as encoded in "String Literal"
-// representation, to dst and returns the the extended buffer.
-//
-// s will be encoded in Huffman codes only when it produces strictly
-// shorter byte string.
-func appendHpackString(dst []byte, s string) []byte {
-	huffmanLength := HuffmanEncodeLength(s)
-	if huffmanLength < uint64(len(s)) {
-		first := len(dst)
-		dst = appendVarInt(dst, 7, huffmanLength)
-		dst = AppendHuffmanString(dst, s)
-		dst[first] |= 0x80
-	} else {
-		dst = appendVarInt(dst, 7, uint64(len(s)))
-		dst = append(dst, s...)
-	}
-	return dst
-}
-
-// encodeTypeByte returns type byte. If sensitive is true, type byte
-// for "Never Indexed" representation is returned. If sensitive is
-// false and indexing is true, type byte for "Incremental Indexing"
-// representation is returned. Otherwise, type byte for "Without
-// Indexing" is returned.
-func encodeTypeByte(indexing, sensitive bool) byte {
-	if sensitive {
-		return 0x10
-	}
-	if indexing {
-		return 0x40
-	}
-	return 0
-}
diff --git a/src/internal/golang.org/x/net/http2/hpack/hpack.go b/src/internal/golang.org/x/net/http2/hpack/hpack.go
deleted file mode 100644
index 2ea4949..0000000
--- a/src/internal/golang.org/x/net/http2/hpack/hpack.go
+++ /dev/null
@@ -1,533 +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 hpack implements HPACK, a compression format for
-// efficiently representing HTTP header fields in the context of HTTP/2.
-//
-// See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09
-package hpack
-
-import (
-	"bytes"
-	"errors"
-	"fmt"
-)
-
-// A DecodingError is something the spec defines as a decoding error.
-type DecodingError struct {
-	Err error
-}
-
-func (de DecodingError) Error() string {
-	return fmt.Sprintf("decoding error: %v", de.Err)
-}
-
-// An InvalidIndexError is returned when an encoder references a table
-// entry before the static table or after the end of the dynamic table.
-type InvalidIndexError int
-
-func (e InvalidIndexError) Error() string {
-	return fmt.Sprintf("invalid indexed representation index %d", int(e))
-}
-
-// A HeaderField is a name-value pair. Both the name and value are
-// treated as opaque sequences of octets.
-type HeaderField struct {
-	Name, Value string
-
-	// Sensitive means that this header field should never be
-	// indexed.
-	Sensitive bool
-}
-
-func (hf HeaderField) String() string {
-	var suffix string
-	if hf.Sensitive {
-		suffix = " (sensitive)"
-	}
-	return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
-}
-
-func (hf *HeaderField) size() uint32 {
-	// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
-	// "The size of the dynamic table is the sum of the size of
-	// its entries.  The size of an entry is the sum of its name's
-	// length in octets (as defined in Section 5.2), its value's
-	// length in octets (see Section 5.2), plus 32.  The size of
-	// an entry is calculated using the length of the name and
-	// value without any Huffman encoding applied."
-
-	// This can overflow if somebody makes a large HeaderField
-	// Name and/or Value by hand, but we don't care, because that
-	// won't happen on the wire because the encoding doesn't allow
-	// it.
-	return uint32(len(hf.Name) + len(hf.Value) + 32)
-}
-
-// A Decoder is the decoding context for incremental processing of
-// header blocks.
-type Decoder struct {
-	dynTab dynamicTable
-	emit   func(f HeaderField)
-
-	emitEnabled bool // whether calls to emit are enabled
-	maxStrLen   int  // 0 means unlimited
-
-	// buf is the unparsed buffer. It's only written to
-	// saveBuf if it was truncated in the middle of a header
-	// block. Because it's usually not owned, we can only
-	// process it under Write.
-	buf []byte // not owned; only valid during Write
-
-	// saveBuf is previous data passed to Write which we weren't able
-	// to fully parse before. Unlike buf, we own this data.
-	saveBuf bytes.Buffer
-}
-
-// NewDecoder returns a new decoder with the provided maximum dynamic
-// table size. The emitFunc will be called for each valid field
-// parsed, in the same goroutine as calls to Write, before Write returns.
-func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder {
-	d := &Decoder{
-		emit:        emitFunc,
-		emitEnabled: true,
-	}
-	d.dynTab.allowedMaxSize = maxDynamicTableSize
-	d.dynTab.setMaxSize(maxDynamicTableSize)
-	return d
-}
-
-// ErrStringLength is returned by Decoder.Write when the max string length
-// (as configured by Decoder.SetMaxStringLength) would be violated.
-var ErrStringLength = errors.New("hpack: string too long")
-
-// SetMaxStringLength sets the maximum size of a HeaderField name or
-// value string. If a string exceeds this length (even after any
-// decompression), Write will return ErrStringLength.
-// A value of 0 means unlimited and is the default from NewDecoder.
-func (d *Decoder) SetMaxStringLength(n int) {
-	d.maxStrLen = n
-}
-
-// SetEmitFunc changes the callback used when new header fields
-// are decoded.
-// It must be non-nil. It does not affect EmitEnabled.
-func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField)) {
-	d.emit = emitFunc
-}
-
-// SetEmitEnabled controls whether the emitFunc provided to NewDecoder
-// should be called. The default is true.
-//
-// This facility exists to let servers enforce MAX_HEADER_LIST_SIZE
-// while still decoding and keeping in-sync with decoder state, but
-// without doing unnecessary decompression or generating unnecessary
-// garbage for header fields past the limit.
-func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v }
-
-// EmitEnabled reports whether calls to the emitFunc provided to NewDecoder
-// are currently enabled. The default is true.
-func (d *Decoder) EmitEnabled() bool { return d.emitEnabled }
-
-// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their
-// underlying buffers for garbage reasons.
-
-func (d *Decoder) SetMaxDynamicTableSize(v uint32) {
-	d.dynTab.setMaxSize(v)
-}
-
-// SetAllowedMaxDynamicTableSize sets the upper bound that the encoded
-// stream (via dynamic table size updates) may set the maximum size
-// to.
-func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
-	d.dynTab.allowedMaxSize = v
-}
-
-type dynamicTable struct {
-	// ents is the FIFO described at
-	// http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2
-	// The newest (low index) is append at the end, and items are
-	// evicted from the front.
-	ents           []HeaderField
-	size           uint32
-	maxSize        uint32 // current maxSize
-	allowedMaxSize uint32 // maxSize may go up to this, inclusive
-}
-
-func (dt *dynamicTable) setMaxSize(v uint32) {
-	dt.maxSize = v
-	dt.evict()
-}
-
-// TODO: change dynamicTable to be a struct with a slice and a size int field,
-// per http://http2.github.io/http2-spec/compression.html#rfc.section.4.1:
-//
-//
-// Then make add increment the size. maybe the max size should move from Decoder to
-// dynamicTable and add should return an ok bool if there was enough space.
-//
-// Later we'll need a remove operation on dynamicTable.
-
-func (dt *dynamicTable) add(f HeaderField) {
-	dt.ents = append(dt.ents, f)
-	dt.size += f.size()
-	dt.evict()
-}
-
-// If we're too big, evict old stuff (front of the slice)
-func (dt *dynamicTable) evict() {
-	base := dt.ents // keep base pointer of slice
-	for dt.size > dt.maxSize {
-		dt.size -= dt.ents[0].size()
-		dt.ents = dt.ents[1:]
-	}
-
-	// Shift slice contents down if we evicted things.
-	if len(dt.ents) != len(base) {
-		copy(base, dt.ents)
-		dt.ents = base[:len(dt.ents)]
-	}
-}
-
-// constantTimeStringCompare compares string a and b in a constant
-// time manner.
-func constantTimeStringCompare(a, b string) bool {
-	if len(a) != len(b) {
-		return false
-	}
-
-	c := byte(0)
-
-	for i := 0; i < len(a); i++ {
-		c |= a[i] ^ b[i]
-	}
-
-	return c == 0
-}
-
-// Search searches f in the table. The return value i is 0 if there is
-// no name match. If there is name match or name/value match, i is the
-// index of that entry (1-based). If both name and value match,
-// nameValueMatch becomes true.
-func (dt *dynamicTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
-	l := len(dt.ents)
-	for j := l - 1; j >= 0; j-- {
-		ent := dt.ents[j]
-		if !constantTimeStringCompare(ent.Name, f.Name) {
-			continue
-		}
-		if i == 0 {
-			i = uint64(l - j)
-		}
-		if f.Sensitive {
-			continue
-		}
-		if !constantTimeStringCompare(ent.Value, f.Value) {
-			continue
-		}
-		i = uint64(l - j)
-		nameValueMatch = true
-		return
-	}
-	return
-}
-
-func (d *Decoder) maxTableIndex() int {
-	return len(d.dynTab.ents) + len(staticTable)
-}
-
-func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
-	if i < 1 {
-		return
-	}
-	if i > uint64(d.maxTableIndex()) {
-		return
-	}
-	if i <= uint64(len(staticTable)) {
-		return staticTable[i-1], true
-	}
-	dents := d.dynTab.ents
-	return dents[len(dents)-(int(i)-len(staticTable))], true
-}
-
-// Decode decodes an entire block.
-//
-// TODO: remove this method and make it incremental later? This is
-// easier for debugging now.
-func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
-	var hf []HeaderField
-	saveFunc := d.emit
-	defer func() { d.emit = saveFunc }()
-	d.emit = func(f HeaderField) { hf = append(hf, f) }
-	if _, err := d.Write(p); err != nil {
-		return nil, err
-	}
-	if err := d.Close(); err != nil {
-		return nil, err
-	}
-	return hf, nil
-}
-
-func (d *Decoder) Close() error {
-	if d.saveBuf.Len() > 0 {
-		d.saveBuf.Reset()
-		return DecodingError{errors.New("truncated headers")}
-	}
-	return nil
-}
-
-func (d *Decoder) Write(p []byte) (n int, err error) {
-	if len(p) == 0 {
-		// Prevent state machine CPU attacks (making us redo
-		// work up to the point of finding out we don't have
-		// enough data)
-		return
-	}
-	// Only copy the data if we have to. Optimistically assume
-	// that p will contain a complete header block.
-	if d.saveBuf.Len() == 0 {
-		d.buf = p
-	} else {
-		d.saveBuf.Write(p)
-		d.buf = d.saveBuf.Bytes()
-		d.saveBuf.Reset()
-	}
-
-	for len(d.buf) > 0 {
-		err = d.parseHeaderFieldRepr()
-		if err == errNeedMore {
-			// Extra paranoia, making sure saveBuf won't
-			// get too large.  All the varint and string
-			// reading code earlier should already catch
-			// overlong things and return ErrStringLength,
-			// but keep this as a last resort.
-			const varIntOverhead = 8 // conservative
-			if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
-				return 0, ErrStringLength
-			}
-			d.saveBuf.Write(d.buf)
-			return len(p), nil
-		}
-		if err != nil {
-			break
-		}
-	}
-	return len(p), err
-}
-
-// errNeedMore is an internal sentinel error value that means the
-// buffer is truncated and we need to read more data before we can
-// continue parsing.
-var errNeedMore = errors.New("need more data")
-
-type indexType int
-
-const (
-	indexedTrue indexType = iota
-	indexedFalse
-	indexedNever
-)
-
-func (v indexType) indexed() bool   { return v == indexedTrue }
-func (v indexType) sensitive() bool { return v == indexedNever }
-
-// returns errNeedMore if there isn't enough data available.
-// any other error is fatal.
-// consumes d.buf iff it returns nil.
-// precondition: must be called with len(d.buf) > 0
-func (d *Decoder) parseHeaderFieldRepr() error {
-	b := d.buf[0]
-	switch {
-	case b&128 != 0:
-		// Indexed representation.
-		// High bit set?
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.1
-		return d.parseFieldIndexed()
-	case b&192 == 64:
-		// 6.2.1 Literal Header Field with Incremental Indexing
-		// 0b10xxxxxx: top two bits are 10
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.1
-		return d.parseFieldLiteral(6, indexedTrue)
-	case b&240 == 0:
-		// 6.2.2 Literal Header Field without Indexing
-		// 0b0000xxxx: top four bits are 0000
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2
-		return d.parseFieldLiteral(4, indexedFalse)
-	case b&240 == 16:
-		// 6.2.3 Literal Header Field never Indexed
-		// 0b0001xxxx: top four bits are 0001
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.3
-		return d.parseFieldLiteral(4, indexedNever)
-	case b&224 == 32:
-		// 6.3 Dynamic Table Size Update
-		// Top three bits are '001'.
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.3
-		return d.parseDynamicTableSizeUpdate()
-	}
-
-	return DecodingError{errors.New("invalid encoding")}
-}
-
-// (same invariants and behavior as parseHeaderFieldRepr)
-func (d *Decoder) parseFieldIndexed() error {
-	buf := d.buf
-	idx, buf, err := readVarInt(7, buf)
-	if err != nil {
-		return err
-	}
-	hf, ok := d.at(idx)
-	if !ok {
-		return DecodingError{InvalidIndexError(idx)}
-	}
-	d.buf = buf
-	return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value})
-}
-
-// (same invariants and behavior as parseHeaderFieldRepr)
-func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
-	buf := d.buf
-	nameIdx, buf, err := readVarInt(n, buf)
-	if err != nil {
-		return err
-	}
-
-	var hf HeaderField
-	wantStr := d.emitEnabled || it.indexed()
-	if nameIdx > 0 {
-		ihf, ok := d.at(nameIdx)
-		if !ok {
-			return DecodingError{InvalidIndexError(nameIdx)}
-		}
-		hf.Name = ihf.Name
-	} else {
-		hf.Name, buf, err = d.readString(buf, wantStr)
-		if err != nil {
-			return err
-		}
-	}
-	hf.Value, buf, err = d.readString(buf, wantStr)
-	if err != nil {
-		return err
-	}
-	d.buf = buf
-	if it.indexed() {
-		d.dynTab.add(hf)
-	}
-	hf.Sensitive = it.sensitive()
-	return d.callEmit(hf)
-}
-
-func (d *Decoder) callEmit(hf HeaderField) error {
-	if d.maxStrLen != 0 {
-		if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen {
-			return ErrStringLength
-		}
-	}
-	if d.emitEnabled {
-		d.emit(hf)
-	}
-	return nil
-}
-
-// (same invariants and behavior as parseHeaderFieldRepr)
-func (d *Decoder) parseDynamicTableSizeUpdate() error {
-	buf := d.buf
-	size, buf, err := readVarInt(5, buf)
-	if err != nil {
-		return err
-	}
-	if size > uint64(d.dynTab.allowedMaxSize) {
-		return DecodingError{errors.New("dynamic table size update too large")}
-	}
-	d.dynTab.setMaxSize(uint32(size))
-	d.buf = buf
-	return nil
-}
-
-var errVarintOverflow = DecodingError{errors.New("varint integer overflow")}
-
-// readVarInt reads an unsigned variable length integer off the
-// beginning of p. n is the parameter as described in
-// http://http2.github.io/http2-spec/compression.html#rfc.section.5.1.
-//
-// n must always be between 1 and 8.
-//
-// The returned remain buffer is either a smaller suffix of p, or err != nil.
-// The error is errNeedMore if p doesn't contain a complete integer.
-func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
-	if n < 1 || n > 8 {
-		panic("bad n")
-	}
-	if len(p) == 0 {
-		return 0, p, errNeedMore
-	}
-	i = uint64(p[0])
-	if n < 8 {
-		i &= (1 << uint64(n)) - 1
-	}
-	if i < (1<<uint64(n))-1 {
-		return i, p[1:], nil
-	}
-
-	origP := p
-	p = p[1:]
-	var m uint64
-	for len(p) > 0 {
-		b := p[0]
-		p = p[1:]
-		i += uint64(b&127) << m
-		if b&128 == 0 {
-			return i, p, nil
-		}
-		m += 7
-		if m >= 63 { // TODO: proper overflow check. making this up.
-			return 0, origP, errVarintOverflow
-		}
-	}
-	return 0, origP, errNeedMore
-}
-
-// readString decodes an hpack string from p.
-//
-// wantStr is whether s will be used. If false, decompression and
-// []byte->string garbage are skipped if s will be ignored
-// anyway. This does mean that huffman decoding errors for non-indexed
-// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
-// is returning an error anyway, and because they're not indexed, the error
-// won't affect the decoding state.
-func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
-	if len(p) == 0 {
-		return "", p, errNeedMore
-	}
-	isHuff := p[0]&128 != 0
-	strLen, p, err := readVarInt(7, p)
-	if err != nil {
-		return "", p, err
-	}
-	if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
-		return "", nil, ErrStringLength
-	}
-	if uint64(len(p)) < strLen {
-		return "", p, errNeedMore
-	}
-	if !isHuff {
-		if wantStr {
-			s = string(p[:strLen])
-		}
-		return s, p[strLen:], nil
-	}
-
-	if wantStr {
-		buf := bufPool.Get().(*bytes.Buffer)
-		buf.Reset() // don't trust others
-		defer bufPool.Put(buf)
-		if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
-			buf.Reset()
-			return "", nil, err
-		}
-		s = buf.String()
-		buf.Reset() // be nice to GC
-	}
-	return s, p[strLen:], nil
-}
diff --git a/src/internal/golang.org/x/net/http2/hpack/hpack_test.go b/src/internal/golang.org/x/net/http2/hpack/hpack_test.go
deleted file mode 100644
index 6dc69f9..0000000
--- a/src/internal/golang.org/x/net/http2/hpack/hpack_test.go
+++ /dev/null
@@ -1,813 +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 hpack
-
-import (
-	"bufio"
-	"bytes"
-	"encoding/hex"
-	"fmt"
-	"math/rand"
-	"reflect"
-	"regexp"
-	"strconv"
-	"strings"
-	"testing"
-	"time"
-)
-
-func TestStaticTable(t *testing.T) {
-	fromSpec := `
-          +-------+-----------------------------+---------------+
-          | 1     | :authority                  |               |
-          | 2     | :method                     | GET           |
-          | 3     | :method                     | POST          |
-          | 4     | :path                       | /             |
-          | 5     | :path                       | /index.html   |
-          | 6     | :scheme                     | http          |
-          | 7     | :scheme                     | https         |
-          | 8     | :status                     | 200           |
-          | 9     | :status                     | 204           |
-          | 10    | :status                     | 206           |
-          | 11    | :status                     | 304           |
-          | 12    | :status                     | 400           |
-          | 13    | :status                     | 404           |
-          | 14    | :status                     | 500           |
-          | 15    | accept-charset              |               |
-          | 16    | accept-encoding             | gzip, deflate |
-          | 17    | accept-language             |               |
-          | 18    | accept-ranges               |               |
-          | 19    | accept                      |               |
-          | 20    | access-control-allow-origin |               |
-          | 21    | age                         |               |
-          | 22    | allow                       |               |
-          | 23    | authorization               |               |
-          | 24    | cache-control               |               |
-          | 25    | content-disposition         |               |
-          | 26    | content-encoding            |               |
-          | 27    | content-language            |               |
-          | 28    | content-length              |               |
-          | 29    | content-location            |               |
-          | 30    | content-range               |               |
-          | 31    | content-type                |               |
-          | 32    | cookie                      |               |
-          | 33    | date                        |               |
-          | 34    | etag                        |               |
-          | 35    | expect                      |               |
-          | 36    | expires                     |               |
-          | 37    | from                        |               |
-          | 38    | host                        |               |
-          | 39    | if-match                    |               |
-          | 40    | if-modified-since           |               |
-          | 41    | if-none-match               |               |
-          | 42    | if-range                    |               |
-          | 43    | if-unmodified-since         |               |
-          | 44    | last-modified               |               |
-          | 45    | link                        |               |
-          | 46    | location                    |               |
-          | 47    | max-forwards                |               |
-          | 48    | proxy-authenticate          |               |
-          | 49    | proxy-authorization         |               |
-          | 50    | range                       |               |
-          | 51    | referer                     |               |
-          | 52    | refresh                     |               |
-          | 53    | retry-after                 |               |
-          | 54    | server                      |               |
-          | 55    | set-cookie                  |               |
-          | 56    | strict-transport-security   |               |
-          | 57    | transfer-encoding           |               |
-          | 58    | user-agent                  |               |
-          | 59    | vary                        |               |
-          | 60    | via                         |               |
-          | 61    | www-authenticate            |               |
-          +-------+-----------------------------+---------------+
-`
-	bs := bufio.NewScanner(strings.NewReader(fromSpec))
-	re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
-	for bs.Scan() {
-		l := bs.Text()
-		if !strings.Contains(l, "|") {
-			continue
-		}
-		m := re.FindStringSubmatch(l)
-		if m == nil {
-			continue
-		}
-		i, err := strconv.Atoi(m[1])
-		if err != nil {
-			t.Errorf("Bogus integer on line %q", l)
-			continue
-		}
-		if i < 1 || i > len(staticTable) {
-			t.Errorf("Bogus index %d on line %q", i, l)
-			continue
-		}
-		if got, want := staticTable[i-1].Name, m[2]; got != want {
-			t.Errorf("header index %d name = %q; want %q", i, got, want)
-		}
-		if got, want := staticTable[i-1].Value, m[3]; got != want {
-			t.Errorf("header index %d value = %q; want %q", i, got, want)
-		}
-	}
-	if err := bs.Err(); err != nil {
-		t.Error(err)
-	}
-}
-
-func (d *Decoder) mustAt(idx int) HeaderField {
-	if hf, ok := d.at(uint64(idx)); !ok {
-		panic(fmt.Sprintf("bogus index %d", idx))
-	} else {
-		return hf
-	}
-}
-
-func TestDynamicTableAt(t *testing.T) {
-	d := NewDecoder(4096, nil)
-	at := d.mustAt
-	if got, want := at(2), (pair(":method", "GET")); got != want {
-		t.Errorf("at(2) = %v; want %v", got, want)
-	}
-	d.dynTab.add(pair("foo", "bar"))
-	d.dynTab.add(pair("blake", "miz"))
-	if got, want := at(len(staticTable)+1), (pair("blake", "miz")); got != want {
-		t.Errorf("at(dyn 1) = %v; want %v", got, want)
-	}
-	if got, want := at(len(staticTable)+2), (pair("foo", "bar")); got != want {
-		t.Errorf("at(dyn 2) = %v; want %v", got, want)
-	}
-	if got, want := at(3), (pair(":method", "POST")); got != want {
-		t.Errorf("at(3) = %v; want %v", got, want)
-	}
-}
-
-func TestDynamicTableSearch(t *testing.T) {
-	dt := dynamicTable{}
-	dt.setMaxSize(4096)
-
-	dt.add(pair("foo", "bar"))
-	dt.add(pair("blake", "miz"))
-	dt.add(pair(":method", "GET"))
-
-	tests := []struct {
-		hf        HeaderField
-		wantI     uint64
-		wantMatch bool
-	}{
-		// Name and Value match
-		{pair("foo", "bar"), 3, true},
-		{pair(":method", "GET"), 1, true},
-
-		// Only name match because of Sensitive == true
-		{HeaderField{"blake", "miz", true}, 2, false},
-
-		// Only Name matches
-		{pair("foo", "..."), 3, false},
-		{pair("blake", "..."), 2, false},
-		{pair(":method", "..."), 1, false},
-
-		// None match
-		{pair("foo-", "bar"), 0, false},
-	}
-	for _, tt := range tests {
-		if gotI, gotMatch := dt.search(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
-			t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
-		}
-	}
-}
-
-func TestDynamicTableSizeEvict(t *testing.T) {
-	d := NewDecoder(4096, nil)
-	if want := uint32(0); d.dynTab.size != want {
-		t.Fatalf("size = %d; want %d", d.dynTab.size, want)
-	}
-	add := d.dynTab.add
-	add(pair("blake", "eats pizza"))
-	if want := uint32(15 + 32); d.dynTab.size != want {
-		t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want)
-	}
-	add(pair("foo", "bar"))
-	if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want {
-		t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want)
-	}
-	d.dynTab.setMaxSize(15 + 32 + 1 /* slop */)
-	if want := uint32(6 + 32); d.dynTab.size != want {
-		t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want)
-	}
-	if got, want := d.mustAt(len(staticTable)+1), (pair("foo", "bar")); got != want {
-		t.Errorf("at(dyn 1) = %v; want %v", got, want)
-	}
-	add(pair("long", strings.Repeat("x", 500)))
-	if want := uint32(0); d.dynTab.size != want {
-		t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want)
-	}
-}
-
-func TestDecoderDecode(t *testing.T) {
-	tests := []struct {
-		name       string
-		in         []byte
-		want       []HeaderField
-		wantDynTab []HeaderField // newest entry first
-	}{
-		// C.2.1 Literal Header Field with Indexing
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.1
-		{"C.2.1", dehex("400a 6375 7374 6f6d 2d6b 6579 0d63 7573 746f 6d2d 6865 6164 6572"),
-			[]HeaderField{pair("custom-key", "custom-header")},
-			[]HeaderField{pair("custom-key", "custom-header")},
-		},
-
-		// C.2.2 Literal Header Field without Indexing
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.2
-		{"C.2.2", dehex("040c 2f73 616d 706c 652f 7061 7468"),
-			[]HeaderField{pair(":path", "/sample/path")},
-			[]HeaderField{}},
-
-		// C.2.3 Literal Header Field never Indexed
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.3
-		{"C.2.3", dehex("1008 7061 7373 776f 7264 0673 6563 7265 74"),
-			[]HeaderField{{"password", "secret", true}},
-			[]HeaderField{}},
-
-		// C.2.4 Indexed Header Field
-		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4
-		{"C.2.4", []byte("\x82"),
-			[]HeaderField{pair(":method", "GET")},
-			[]HeaderField{}},
-	}
-	for _, tt := range tests {
-		d := NewDecoder(4096, nil)
-		hf, err := d.DecodeFull(tt.in)
-		if err != nil {
-			t.Errorf("%s: %v", tt.name, err)
-			continue
-		}
-		if !reflect.DeepEqual(hf, tt.want) {
-			t.Errorf("%s: Got %v; want %v", tt.name, hf, tt.want)
-		}
-		gotDynTab := d.dynTab.reverseCopy()
-		if !reflect.DeepEqual(gotDynTab, tt.wantDynTab) {
-			t.Errorf("%s: dynamic table after = %v; want %v", tt.name, gotDynTab, tt.wantDynTab)
-		}
-	}
-}
-
-func (dt *dynamicTable) reverseCopy() (hf []HeaderField) {
-	hf = make([]HeaderField, len(dt.ents))
-	for i := range hf {
-		hf[i] = dt.ents[len(dt.ents)-1-i]
-	}
-	return
-}
-
-type encAndWant struct {
-	enc         []byte
-	want        []HeaderField
-	wantDynTab  []HeaderField
-	wantDynSize uint32
-}
-
-// C.3 Request Examples without Huffman Coding
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.3
-func TestDecodeC3_NoHuffman(t *testing.T) {
-	testDecodeSeries(t, 4096, []encAndWant{
-		{dehex("8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "http"),
-				pair(":path", "/"),
-				pair(":authority", "www.example.com"),
-			},
-			[]HeaderField{
-				pair(":authority", "www.example.com"),
-			},
-			57,
-		},
-		{dehex("8286 84be 5808 6e6f 2d63 6163 6865"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "http"),
-				pair(":path", "/"),
-				pair(":authority", "www.example.com"),
-				pair("cache-control", "no-cache"),
-			},
-			[]HeaderField{
-				pair("cache-control", "no-cache"),
-				pair(":authority", "www.example.com"),
-			},
-			110,
-		},
-		{dehex("8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "https"),
-				pair(":path", "/index.html"),
-				pair(":authority", "www.example.com"),
-				pair("custom-key", "custom-value"),
-			},
-			[]HeaderField{
-				pair("custom-key", "custom-value"),
-				pair("cache-control", "no-cache"),
-				pair(":authority", "www.example.com"),
-			},
-			164,
-		},
-	})
-}
-
-// C.4 Request Examples with Huffman Coding
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.4
-func TestDecodeC4_Huffman(t *testing.T) {
-	testDecodeSeries(t, 4096, []encAndWant{
-		{dehex("8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "http"),
-				pair(":path", "/"),
-				pair(":authority", "www.example.com"),
-			},
-			[]HeaderField{
-				pair(":authority", "www.example.com"),
-			},
-			57,
-		},
-		{dehex("8286 84be 5886 a8eb 1064 9cbf"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "http"),
-				pair(":path", "/"),
-				pair(":authority", "www.example.com"),
-				pair("cache-control", "no-cache"),
-			},
-			[]HeaderField{
-				pair("cache-control", "no-cache"),
-				pair(":authority", "www.example.com"),
-			},
-			110,
-		},
-		{dehex("8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf"),
-			[]HeaderField{
-				pair(":method", "GET"),
-				pair(":scheme", "https"),
-				pair(":path", "/index.html"),
-				pair(":authority", "www.example.com"),
-				pair("custom-key", "custom-value"),
-			},
-			[]HeaderField{
-				pair("custom-key", "custom-value"),
-				pair("cache-control", "no-cache"),
-				pair(":authority", "www.example.com"),
-			},
-			164,
-		},
-	})
-}
-
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.5
-// "This section shows several consecutive header lists, corresponding
-// to HTTP responses, on the same connection. The HTTP/2 setting
-// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
-// octets, causing some evictions to occur."
-func TestDecodeC5_ResponsesNoHuff(t *testing.T) {
-	testDecodeSeries(t, 256, []encAndWant{
-		{dehex(`
-4803 3330 3258 0770 7269 7661 7465 611d
-4d6f 6e2c 2032 3120 4f63 7420 3230 3133
-2032 303a 3133 3a32 3120 474d 546e 1768
-7474 7073 3a2f 2f77 7777 2e65 7861 6d70
-6c65 2e63 6f6d
-`),
-			[]HeaderField{
-				pair(":status", "302"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("location", "https://www.example.com"),
-			},
-			[]HeaderField{
-				pair("location", "https://www.example.com"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("cache-control", "private"),
-				pair(":status", "302"),
-			},
-			222,
-		},
-		{dehex("4803 3330 37c1 c0bf"),
-			[]HeaderField{
-				pair(":status", "307"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("location", "https://www.example.com"),
-			},
-			[]HeaderField{
-				pair(":status", "307"),
-				pair("location", "https://www.example.com"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("cache-control", "private"),
-			},
-			222,
-		},
-		{dehex(`
-88c1 611d 4d6f 6e2c 2032 3120 4f63 7420
-3230 3133 2032 303a 3133 3a32 3220 474d
-54c0 5a04 677a 6970 7738 666f 6f3d 4153
-444a 4b48 514b 425a 584f 5157 454f 5049
-5541 5851 5745 4f49 553b 206d 6178 2d61
-6765 3d33 3630 303b 2076 6572 7369 6f6e
-3d31
-`),
-			[]HeaderField{
-				pair(":status", "200"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
-				pair("location", "https://www.example.com"),
-				pair("content-encoding", "gzip"),
-				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
-			},
-			[]HeaderField{
-				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
-				pair("content-encoding", "gzip"),
-				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
-			},
-			215,
-		},
-	})
-}
-
-// http://http2.github.io/http2-spec/compression.html#rfc.section.C.6
-// "This section shows the same examples as the previous section, but
-// using Huffman encoding for the literal values. The HTTP/2 setting
-// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
-// octets, causing some evictions to occur. The eviction mechanism
-// uses the length of the decoded literal values, so the same
-// evictions occurs as in the previous section."
-func TestDecodeC6_ResponsesHuffman(t *testing.T) {
-	testDecodeSeries(t, 256, []encAndWant{
-		{dehex(`
-4882 6402 5885 aec3 771a 4b61 96d0 7abe
-9410 54d4 44a8 2005 9504 0b81 66e0 82a6
-2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8
-e9ae 82ae 43d3
-`),
-			[]HeaderField{
-				pair(":status", "302"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("location", "https://www.example.com"),
-			},
-			[]HeaderField{
-				pair("location", "https://www.example.com"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("cache-control", "private"),
-				pair(":status", "302"),
-			},
-			222,
-		},
-		{dehex("4883 640e ffc1 c0bf"),
-			[]HeaderField{
-				pair(":status", "307"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("location", "https://www.example.com"),
-			},
-			[]HeaderField{
-				pair(":status", "307"),
-				pair("location", "https://www.example.com"),
-				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
-				pair("cache-control", "private"),
-			},
-			222,
-		},
-		{dehex(`
-88c1 6196 d07a be94 1054 d444 a820 0595
-040b 8166 e084 a62d 1bff c05a 839b d9ab
-77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b
-3960 d5af 2708 7f36 72c1 ab27 0fb5 291f
-9587 3160 65c0 03ed 4ee5 b106 3d50 07
-`),
-			[]HeaderField{
-				pair(":status", "200"),
-				pair("cache-control", "private"),
-				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
-				pair("location", "https://www.example.com"),
-				pair("content-encoding", "gzip"),
-				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
-			},
-			[]HeaderField{
-				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
-				pair("content-encoding", "gzip"),
-				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
-			},
-			215,
-		},
-	})
-}
-
-func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) {
-	d := NewDecoder(size, nil)
-	for i, step := range steps {
-		hf, err := d.DecodeFull(step.enc)
-		if err != nil {
-			t.Fatalf("Error at step index %d: %v", i, err)
-		}
-		if !reflect.DeepEqual(hf, step.want) {
-			t.Fatalf("At step index %d: Got headers %v; want %v", i, hf, step.want)
-		}
-		gotDynTab := d.dynTab.reverseCopy()
-		if !reflect.DeepEqual(gotDynTab, step.wantDynTab) {
-			t.Errorf("After step index %d, dynamic table = %v; want %v", i, gotDynTab, step.wantDynTab)
-		}
-		if d.dynTab.size != step.wantDynSize {
-			t.Errorf("After step index %d, dynamic table size = %v; want %v", i, d.dynTab.size, step.wantDynSize)
-		}
-	}
-}
-
-func TestHuffmanDecode(t *testing.T) {
-	tests := []struct {
-		inHex, want string
-	}{
-		{"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"},
-		{"a8eb 1064 9cbf", "no-cache"},
-		{"25a8 49e9 5ba9 7d7f", "custom-key"},
-		{"25a8 49e9 5bb8 e8b4 bf", "custom-value"},
-		{"6402", "302"},
-		{"aec3 771a 4b", "private"},
-		{"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
-		{"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"},
-		{"9bd9 ab", "gzip"},
-		{"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
-			"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
-	}
-	for i, tt := range tests {
-		var buf bytes.Buffer
-		in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1))
-		if err != nil {
-			t.Errorf("%d. hex input error: %v", i, err)
-			continue
-		}
-		if _, err := HuffmanDecode(&buf, in); err != nil {
-			t.Errorf("%d. decode error: %v", i, err)
-			continue
-		}
-		if got := buf.String(); tt.want != got {
-			t.Errorf("%d. decode = %q; want %q", i, got, tt.want)
-		}
-	}
-}
-
-func TestAppendHuffmanString(t *testing.T) {
-	tests := []struct {
-		in, want string
-	}{
-		{"www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
-		{"no-cache", "a8eb 1064 9cbf"},
-		{"custom-key", "25a8 49e9 5ba9 7d7f"},
-		{"custom-value", "25a8 49e9 5bb8 e8b4 bf"},
-		{"302", "6402"},
-		{"private", "aec3 771a 4b"},
-		{"Mon, 21 Oct 2013 20:13:21 GMT", "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"},
-		{"https://www.example.com", "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"},
-		{"gzip", "9bd9 ab"},
-		{"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
-			"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07"},
-	}
-	for i, tt := range tests {
-		buf := []byte{}
-		want := strings.Replace(tt.want, " ", "", -1)
-		buf = AppendHuffmanString(buf, tt.in)
-		if got := hex.EncodeToString(buf); want != got {
-			t.Errorf("%d. encode = %q; want %q", i, got, want)
-		}
-	}
-}
-
-func TestHuffmanMaxStrLen(t *testing.T) {
-	const msg = "Some string"
-	huff := AppendHuffmanString(nil, msg)
-
-	testGood := func(max int) {
-		var out bytes.Buffer
-		if err := huffmanDecode(&out, max, huff); err != nil {
-			t.Errorf("For maxLen=%d, unexpected error: %v", max, err)
-		}
-		if out.String() != msg {
-			t.Errorf("For maxLen=%d, out = %q; want %q", max, out.String(), msg)
-		}
-	}
-	testGood(0)
-	testGood(len(msg))
-	testGood(len(msg) + 1)
-
-	var out bytes.Buffer
-	if err := huffmanDecode(&out, len(msg)-1, huff); err != ErrStringLength {
-		t.Errorf("err = %v; want ErrStringLength", err)
-	}
-}
-
-func TestHuffmanRoundtripStress(t *testing.T) {
-	const Len = 50 // of uncompressed string
-	input := make([]byte, Len)
-	var output bytes.Buffer
-	var huff []byte
-
-	n := 5000
-	if testing.Short() {
-		n = 100
-	}
-	seed := time.Now().UnixNano()
-	t.Logf("Seed = %v", seed)
-	src := rand.New(rand.NewSource(seed))
-	var encSize int64
-	for i := 0; i < n; i++ {
-		for l := range input {
-			input[l] = byte(src.Intn(256))
-		}
-		huff = AppendHuffmanString(huff[:0], string(input))
-		encSize += int64(len(huff))
-		output.Reset()
-		if err := huffmanDecode(&output, 0, huff); err != nil {
-			t.Errorf("Failed to decode %q -> %q -> error %v", input, huff, err)
-			continue
-		}
-		if !bytes.Equal(output.Bytes(), input) {
-			t.Errorf("Roundtrip failure on %q -> %q -> %q", input, huff, output.Bytes())
-		}
-	}
-	t.Logf("Compressed size of original: %0.02f%% (%v -> %v)", 100*(float64(encSize)/(Len*float64(n))), Len*n, encSize)
-}
-
-func TestHuffmanDecodeFuzz(t *testing.T) {
-	const Len = 50 // of compressed
-	var buf, zbuf bytes.Buffer
-
-	n := 5000
-	if testing.Short() {
-		n = 100
-	}
-	seed := time.Now().UnixNano()
-	t.Logf("Seed = %v", seed)
-	src := rand.New(rand.NewSource(seed))
-	numFail := 0
-	for i := 0; i < n; i++ {
-		zbuf.Reset()
-		if i == 0 {
-			// Start with at least one invalid one.
-			zbuf.WriteString("00\x91\xff\xff\xff\xff\xc8")
-		} else {
-			for l := 0; l < Len; l++ {
-				zbuf.WriteByte(byte(src.Intn(256)))
-			}
-		}
-
-		buf.Reset()
-		if err := huffmanDecode(&buf, 0, zbuf.Bytes()); err != nil {
-			if err == ErrInvalidHuffman {
-				numFail++
-				continue
-			}
-			t.Errorf("Failed to decode %q: %v", zbuf.Bytes(), err)
-			continue
-		}
-	}
-	t.Logf("%0.02f%% are invalid (%d / %d)", 100*float64(numFail)/float64(n), numFail, n)
-	if numFail < 1 {
-		t.Error("expected at least one invalid huffman encoding (test starts with one)")
-	}
-}
-
-func TestReadVarInt(t *testing.T) {
-	type res struct {
-		i        uint64
-		consumed int
-		err      error
-	}
-	tests := []struct {
-		n    byte
-		p    []byte
-		want res
-	}{
-		// Fits in a byte:
-		{1, []byte{0}, res{0, 1, nil}},
-		{2, []byte{2}, res{2, 1, nil}},
-		{3, []byte{6}, res{6, 1, nil}},
-		{4, []byte{14}, res{14, 1, nil}},
-		{5, []byte{30}, res{30, 1, nil}},
-		{6, []byte{62}, res{62, 1, nil}},
-		{7, []byte{126}, res{126, 1, nil}},
-		{8, []byte{254}, res{254, 1, nil}},
-
-		// Doesn't fit in a byte:
-		{1, []byte{1}, res{0, 0, errNeedMore}},
-		{2, []byte{3}, res{0, 0, errNeedMore}},
-		{3, []byte{7}, res{0, 0, errNeedMore}},
-		{4, []byte{15}, res{0, 0, errNeedMore}},
-		{5, []byte{31}, res{0, 0, errNeedMore}},
-		{6, []byte{63}, res{0, 0, errNeedMore}},
-		{7, []byte{127}, res{0, 0, errNeedMore}},
-		{8, []byte{255}, res{0, 0, errNeedMore}},
-
-		// Ignoring top bits:
-		{5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111
-		{5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100
-		{5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101
-
-		// Extra byte:
-		{5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte
-
-		// Short a byte:
-		{5, []byte{191, 154}, res{0, 0, errNeedMore}},
-
-		// integer overflow:
-		{1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}},
-	}
-	for _, tt := range tests {
-		i, remain, err := readVarInt(tt.n, tt.p)
-		consumed := len(tt.p) - len(remain)
-		got := res{i, consumed, err}
-		if got != tt.want {
-			t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want)
-		}
-	}
-}
-
-// Fuzz crash, originally reported at https://github.com/bradfitz/http2/issues/56
-func TestHuffmanFuzzCrash(t *testing.T) {
-	got, err := HuffmanDecodeToString([]byte("00\x91\xff\xff\xff\xff\xc8"))
-	if got != "" {
-		t.Errorf("Got %q; want empty string", got)
-	}
-	if err != ErrInvalidHuffman {
-		t.Errorf("Err = %v; want ErrInvalidHuffman", err)
-	}
-}
-
-func dehex(s string) []byte {
-	s = strings.Replace(s, " ", "", -1)
-	s = strings.Replace(s, "\n", "", -1)
-	b, err := hex.DecodeString(s)
-	if err != nil {
-		panic(err)
-	}
-	return b
-}
-
-func TestEmitEnabled(t *testing.T) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
-	enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
-	enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
-
-	numCallback := 0
-	var dec *Decoder
-	dec = NewDecoder(8<<20, func(HeaderField) {
-		numCallback++
-		dec.SetEmitEnabled(false)
-	})
-	if !dec.EmitEnabled() {
-		t.Errorf("initial emit enabled = false; want true")
-	}
-	if _, err := dec.Write(buf.Bytes()); err != nil {
-		t.Error(err)
-	}
-	if numCallback != 1 {
-		t.Errorf("num callbacks = %d; want 1", numCallback)
-	}
-	if dec.EmitEnabled() {
-		t.Errorf("emit enabled = true; want false")
-	}
-}
-
-func TestSaveBufLimit(t *testing.T) {
-	const maxStr = 1 << 10
-	var got []HeaderField
-	dec := NewDecoder(initialHeaderTableSize, func(hf HeaderField) {
-		got = append(got, hf)
-	})
-	dec.SetMaxStringLength(maxStr)
-	var frag []byte
-	frag = append(frag[:0], encodeTypeByte(false, false))
-	frag = appendVarInt(frag, 7, 3)
-	frag = append(frag, "foo"...)
-	frag = appendVarInt(frag, 7, 3)
-	frag = append(frag, "bar"...)
-
-	if _, err := dec.Write(frag); err != nil {
-		t.Fatal(err)
-	}
-
-	want := []HeaderField{{Name: "foo", Value: "bar"}}
-	if !reflect.DeepEqual(got, want) {
-		t.Errorf("After small writes, got %v; want %v", got, want)
-	}
-
-	frag = append(frag[:0], encodeTypeByte(false, false))
-	frag = appendVarInt(frag, 7, maxStr*3)
-	frag = append(frag, make([]byte, maxStr*3)...)
-
-	_, err := dec.Write(frag)
-	if err != ErrStringLength {
-		t.Fatalf("Write error = %v; want ErrStringLength", err)
-	}
-}
diff --git a/src/internal/golang.org/x/net/http2/hpack/huffman.go b/src/internal/golang.org/x/net/http2/hpack/huffman.go
deleted file mode 100644
index eb4b1f0..0000000
--- a/src/internal/golang.org/x/net/http2/hpack/huffman.go
+++ /dev/null
@@ -1,190 +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 hpack
-
-import (
-	"bytes"
-	"errors"
-	"io"
-	"sync"
-)
-
-var bufPool = sync.Pool{
-	New: func() interface{} { return new(bytes.Buffer) },
-}
-
-// HuffmanDecode decodes the string in v and writes the expanded
-// result to w, returning the number of bytes written to w and the
-// Write call's return value. At most one Write call is made.
-func HuffmanDecode(w io.Writer, v []byte) (int, error) {
-	buf := bufPool.Get().(*bytes.Buffer)
-	buf.Reset()
-	defer bufPool.Put(buf)
-	if err := huffmanDecode(buf, 0, v); err != nil {
-		return 0, err
-	}
-	return w.Write(buf.Bytes())
-}
-
-// HuffmanDecodeToString decodes the string in v.
-func HuffmanDecodeToString(v []byte) (string, error) {
-	buf := bufPool.Get().(*bytes.Buffer)
-	buf.Reset()
-	defer bufPool.Put(buf)
-	if err := huffmanDecode(buf, 0, v); err != nil {
-		return "", err
-	}
-	return buf.String(), nil
-}
-
-// ErrInvalidHuffman is returned for errors found decoding
-// Huffman-encoded strings.
-var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
-
-// huffmanDecode decodes v to buf.
-// If maxLen is greater than 0, attempts to write more to buf than
-// maxLen bytes will return ErrStringLength.
-func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
-	n := rootHuffmanNode
-	cur, nbits := uint(0), uint8(0)
-	for _, b := range v {
-		cur = cur<<8 | uint(b)
-		nbits += 8
-		for nbits >= 8 {
-			idx := byte(cur >> (nbits - 8))
-			n = n.children[idx]
-			if n == nil {
-				return ErrInvalidHuffman
-			}
-			if n.children == nil {
-				if maxLen != 0 && buf.Len() == maxLen {
-					return ErrStringLength
-				}
-				buf.WriteByte(n.sym)
-				nbits -= n.codeLen
-				n = rootHuffmanNode
-			} else {
-				nbits -= 8
-			}
-		}
-	}
-	for nbits > 0 {
-		n = n.children[byte(cur<<(8-nbits))]
-		if n.children != nil || n.codeLen > nbits {
-			break
-		}
-		buf.WriteByte(n.sym)
-		nbits -= n.codeLen
-		n = rootHuffmanNode
-	}
-	return nil
-}
-
-type node struct {
-	// children is non-nil for internal nodes
-	children []*node
-
-	// The following are only valid if children is nil:
-	codeLen uint8 // number of bits that led to the output of sym
-	sym     byte  // output symbol
-}
-
-func newInternalNode() *node {
-	return &node{children: make([]*node, 256)}
-}
-
-var rootHuffmanNode = newInternalNode()
-
-func init() {
-	if len(huffmanCodes) != 256 {
-		panic("unexpected size")
-	}
-	for i, code := range huffmanCodes {
-		addDecoderNode(byte(i), code, huffmanCodeLen[i])
-	}
-}
-
-func addDecoderNode(sym byte, code uint32, codeLen uint8) {
-	cur := rootHuffmanNode
-	for codeLen > 8 {
-		codeLen -= 8
-		i := uint8(code >> codeLen)
-		if cur.children[i] == nil {
-			cur.children[i] = newInternalNode()
-		}
-		cur = cur.children[i]
-	}
-	shift := 8 - codeLen
-	start, end := int(uint8(code<<shift)), int(1<<shift)
-	for i := start; i < start+end; i++ {
-		cur.children[i] = &node{sym: sym, codeLen: codeLen}
-	}
-}
-
-// AppendHuffmanString appends s, as encoded in Huffman codes, to dst
-// and returns the extended buffer.
-func AppendHuffmanString(dst []byte, s string) []byte {
-	rembits := uint8(8)
-
-	for i := 0; i < len(s); i++ {
-		if rembits == 8 {
-			dst = append(dst, 0)
-		}
-		dst, rembits = appendByteToHuffmanCode(dst, rembits, s[i])
-	}
-
-	if rembits < 8 {
-		// special EOS symbol
-		code := uint32(0x3fffffff)
-		nbits := uint8(30)
-
-		t := uint8(code >> (nbits - rembits))
-		dst[len(dst)-1] |= t
-	}
-
-	return dst
-}
-
-// HuffmanEncodeLength returns the number of bytes required to encode
-// s in Huffman codes. The result is round up to byte boundary.
-func HuffmanEncodeLength(s string) uint64 {
-	n := uint64(0)
-	for i := 0; i < len(s); i++ {
-		n += uint64(huffmanCodeLen[s[i]])
-	}
-	return (n + 7) / 8
-}
-
-// appendByteToHuffmanCode appends Huffman code for c to dst and
-// returns the extended buffer and the remaining bits in the last
-// element. The appending is not byte aligned and the remaining bits
-// in the last element of dst is given in rembits.
-func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) {
-	code := huffmanCodes[c]
-	nbits := huffmanCodeLen[c]
-
-	for {
-		if rembits > nbits {
-			t := uint8(code << (rembits - nbits))
-			dst[len(dst)-1] |= t
-			rembits -= nbits
-			break
-		}
-
-		t := uint8(code >> (nbits - rembits))
-		dst[len(dst)-1] |= t
-
-		nbits -= rembits
-		rembits = 8
-
-		if nbits == 0 {
-			break
-		}
-
-		dst = append(dst, 0)
-	}
-
-	return dst, rembits
-}
diff --git a/src/internal/nettrace/nettrace.go b/src/internal/nettrace/nettrace.go
new file mode 100644
index 0000000..de3254d
--- /dev/null
+++ b/src/internal/nettrace/nettrace.go
@@ -0,0 +1,45 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package nettrace contains internal hooks for tracing activity in
+// the net package. This package is purely internal for use by the
+// net/http/httptrace package and has no stable API exposed to end
+// users.
+package nettrace
+
+// TraceKey is a context.Context Value key. Its associated value should
+// be a *Trace struct.
+type TraceKey struct{}
+
+// LookupIPAltResolverKey is a context.Context Value key used by tests to
+// specify an alternate resolver func.
+// It is not exposed to outsider users. (But see issue 12503)
+// The value should be the same type as lookupIP:
+//     func lookupIP(ctx context.Context, host string) ([]IPAddr, error)
+type LookupIPAltResolverKey struct{}
+
+// Trace contains a set of hooks for tracing events within
+// the net package. Any specific hook may be nil.
+type Trace struct {
+	// DNSStart is called with the hostname of a DNS lookup
+	// before it begins.
+	DNSStart func(name string)
+
+	// DNSDone is called after a DNS lookup completes (or fails).
+	// The coalesced parameter is whether singleflight de-dupped
+	// the call. The addrs are of type net.IPAddr but can't
+	// actually be for circular dependency reasons.
+	DNSDone func(netIPs []interface{}, coalesced bool, err error)
+
+	// ConnectStart is called before a Dial, excluding Dials made
+	// during DNS lookups. In the case of DualStack (Happy Eyeballs)
+	// dialing, this may be called multiple times, from multiple
+	// goroutines.
+	ConnectStart func(network, addr string)
+
+	// ConnectStart is called after a Dial with the results, excluding
+	// Dials made during DNS lookups. It may also be called multiple
+	// times, like ConnectStart.
+	ConnectDone func(network, addr string, err error)
+}
diff --git a/src/internal/race/doc.go b/src/internal/race/doc.go
index d6a2243..8fa44ce 100644
--- a/src/internal/race/doc.go
+++ b/src/internal/race/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/internal/race/norace.go b/src/internal/race/norace.go
index d9049eb..7ef5912 100644
--- a/src/internal/race/norace.go
+++ b/src/internal/race/norace.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/internal/race/race.go b/src/internal/race/race.go
index cb0e773..6c721f6 100644
--- a/src/internal/race/race.go
+++ b/src/internal/race/race.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/internal/singleflight/singleflight.go b/src/internal/singleflight/singleflight.go
index f4cb2d6..de81ac8 100644
--- a/src/internal/singleflight/singleflight.go
+++ b/src/internal/singleflight/singleflight.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/internal/singleflight/singleflight_test.go b/src/internal/singleflight/singleflight_test.go
index c0ec024..5e6f1b3 100644
--- a/src/internal/singleflight/singleflight_test.go
+++ b/src/internal/singleflight/singleflight_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/internal/syscall/unix/getentropy_openbsd.go b/src/internal/syscall/unix/getentropy_openbsd.go
new file mode 100644
index 0000000..d5caa80
--- /dev/null
+++ b/src/internal/syscall/unix/getentropy_openbsd.go
@@ -0,0 +1,25 @@
+// Copyright 2016 The Go Authors. 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 (
+	"syscall"
+	"unsafe"
+)
+
+// getentropy(2)'s syscall number, from /usr/src/sys/kern/syscalls.master
+const entropyTrap uintptr = 7
+
+// GetEntropy calls the OpenBSD getentropy system call.
+func GetEntropy(p []byte) error {
+	_, _, errno := syscall.Syscall(entropyTrap,
+		uintptr(unsafe.Pointer(&p[0])),
+		uintptr(len(p)),
+		0)
+	if errno != 0 {
+		return errno
+	}
+	return nil
+}
diff --git a/src/internal/syscall/unix/getrandom_linux.go b/src/internal/syscall/unix/getrandom_linux.go
index e07557a..0d0d4f1 100644
--- a/src/internal/syscall/unix/getrandom_linux.go
+++ b/src/internal/syscall/unix/getrandom_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/internal/syscall/unix/getrandom_linux_386.go b/src/internal/syscall/unix/getrandom_linux_386.go
index 48c69b4..a583896 100644
--- a/src/internal/syscall/unix/getrandom_linux_386.go
+++ b/src/internal/syscall/unix/getrandom_linux_386.go
@@ -1,7 +1,9 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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
 
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
 const randomTrap uintptr = 355
diff --git a/src/internal/syscall/unix/getrandom_linux_amd64.go b/src/internal/syscall/unix/getrandom_linux_amd64.go
index 7175e36..cff0eb6 100644
--- a/src/internal/syscall/unix/getrandom_linux_amd64.go
+++ b/src/internal/syscall/unix/getrandom_linux_amd64.go
@@ -1,7 +1,9 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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
 
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
 const randomTrap uintptr = 318
diff --git a/src/internal/syscall/unix/getrandom_linux_arm.go b/src/internal/syscall/unix/getrandom_linux_arm.go
index c4d6f43..92e2492 100644
--- a/src/internal/syscall/unix/getrandom_linux_arm.go
+++ b/src/internal/syscall/unix/getrandom_linux_arm.go
@@ -1,7 +1,9 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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
 
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
 const randomTrap uintptr = 384
diff --git a/src/internal/syscall/unix/getrandom_linux_generic.go b/src/internal/syscall/unix/getrandom_linux_generic.go
index 0e632dc..8425800 100644
--- a/src/internal/syscall/unix/getrandom_linux_generic.go
+++ b/src/internal/syscall/unix/getrandom_linux_generic.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,4 +6,11 @@
 
 package unix
 
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+//
+// This file is named "generic" because at a certain point Linux
+// started standardizing on system call numbers across
+// architectures. So far this means only arm64 uses the standard
+// numbers.
 const randomTrap uintptr = 278
diff --git a/src/internal/syscall/unix/getrandom_linux_mips64x.go b/src/internal/syscall/unix/getrandom_linux_mips64x.go
index 8531db6..b328b8f 100644
--- a/src/internal/syscall/unix/getrandom_linux_mips64x.go
+++ b/src/internal/syscall/unix/getrandom_linux_mips64x.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -6,4 +6,6 @@
 
 package unix
 
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
 const randomTrap uintptr = 5313
diff --git a/src/internal/syscall/unix/getrandom_linux_ppc64x.go b/src/internal/syscall/unix/getrandom_linux_ppc64x.go
index 6edaba2..9b6e972 100644
--- a/src/internal/syscall/unix/getrandom_linux_ppc64x.go
+++ b/src/internal/syscall/unix/getrandom_linux_ppc64x.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,4 +6,6 @@
 
 package unix
 
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
 const randomTrap uintptr = 359
diff --git a/src/internal/syscall/unix/getrandom_linux_s390x.go b/src/internal/syscall/unix/getrandom_linux_s390x.go
new file mode 100644
index 0000000..e3bc4ee
--- /dev/null
+++ b/src/internal/syscall/unix/getrandom_linux_s390x.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. 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
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 349
diff --git a/src/internal/syscall/windows/registry/registry_test.go b/src/internal/syscall/windows/registry/registry_test.go
index a63c420..56069d7 100644
--- a/src/internal/syscall/windows/registry/registry_test.go
+++ b/src/internal/syscall/windows/registry/registry_test.go
@@ -213,7 +213,7 @@ func enumerateValues(t *testing.T, k registry.Key) {
 		}
 	}
 	for n, v := range haveNames {
-		t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v)
+		t.Errorf("value %s (%v) is found while enumerating, but has not been created", n, v)
 	}
 }
 
@@ -335,7 +335,7 @@ func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) {
 	// 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)
+		t.Errorf("GetValue(%s, [%d]byte) should fail, but succeeded", test.Name, size-1)
 		return
 	}
 	if err != registry.ErrShortBuffer {
diff --git a/src/internal/syscall/windows/registry/syscall.go b/src/internal/syscall/windows/registry/syscall.go
index 02d985c..5426cae 100644
--- a/src/internal/syscall/windows/registry/syscall.go
+++ b/src/internal/syscall/windows/registry/syscall.go
@@ -8,7 +8,7 @@ package registry
 
 import "syscall"
 
-//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall.go
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
 
 const (
 	_REG_OPTION_NON_VOLATILE = 0
diff --git a/src/internal/syscall/windows/registry/zsyscall_windows.go b/src/internal/syscall/windows/registry/zsyscall_windows.go
index 7e473d4..62affc0 100644
--- a/src/internal/syscall/windows/registry/zsyscall_windows.go
+++ b/src/internal/syscall/windows/registry/zsyscall_windows.go
@@ -2,9 +2,11 @@
 
 package registry
 
-import "unsafe"
-import "syscall"
-import "internal/syscall/windows/sysdll"
+import (
+	"internal/syscall/windows/sysdll"
+	"syscall"
+	"unsafe"
+)
 
 var _ unsafe.Pointer
 
diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go
index e6a3f23..7b2bc79 100644
--- a/src/internal/syscall/windows/syscall_windows.go
+++ b/src/internal/syscall/windows/syscall_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,7 +6,7 @@ package windows
 
 import "syscall"
 
-//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go -systemdll syscall_windows.go
+//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
 
 const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
 
diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
index d599258..6929acf 100644
--- a/src/internal/syscall/windows/zsyscall_windows.go
+++ b/src/internal/syscall/windows/zsyscall_windows.go
@@ -2,9 +2,11 @@
 
 package windows
 
-import "unsafe"
-import "syscall"
-import "internal/syscall/windows/sysdll"
+import (
+	"internal/syscall/windows/sysdll"
+	"syscall"
+	"unsafe"
+)
 
 var _ unsafe.Pointer
 
diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go
index 110af3d..f134f6b 100644
--- a/src/internal/testenv/testenv.go
+++ b/src/internal/testenv/testenv.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -11,8 +11,12 @@
 package testenv
 
 import (
+	"flag"
 	"os"
+	"os/exec"
+	"path/filepath"
 	"runtime"
+	"strconv"
 	"strings"
 	"testing"
 )
@@ -62,6 +66,29 @@ func MustHaveGoRun(t *testing.T) {
 	}
 }
 
+// GoToolPath reports the path to the Go tool.
+// If the tool is unavailable GoToolPath calls t.Skip.
+// If the tool should be available and isn't, GoToolPath calls t.Fatal.
+func GoToolPath(t *testing.T) string {
+	MustHaveGoBuild(t)
+
+	var exeSuffix string
+	if runtime.GOOS == "windows" {
+		exeSuffix = ".exe"
+	}
+
+	path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
+	if _, err := os.Stat(path); err == nil {
+		return path
+	}
+
+	goBin, err := exec.LookPath("go" + exeSuffix)
+	if err != nil {
+		t.Fatalf("cannot find go tool: %v", err)
+	}
+	return goBin
+}
+
 // HasExec reports whether the current system can start new processes
 // using os.StartProcess or (more commonly) exec.Command.
 func HasExec() bool {
@@ -99,3 +126,17 @@ func MustHaveExternalNetwork(t *testing.T) {
 		t.Skipf("skipping test: no external network in -short mode")
 	}
 }
+
+var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
+
+func SkipFlaky(t *testing.T, issue int) {
+	if !*flaky {
+		t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue)
+	}
+}
+
+func SkipFlakyNet(t *testing.T) {
+	if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v {
+		t.Skip("skipping test on builder known to have frequent network failures")
+	}
+}
diff --git a/src/internal/trace/order.go b/src/internal/trace/order.go
new file mode 100644
index 0000000..8ca2da5
--- /dev/null
+++ b/src/internal/trace/order.go
@@ -0,0 +1,278 @@
+// Copyright 2016 The Go Authors. 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 (
+	"fmt"
+	"sort"
+)
+
+type eventBatch struct {
+	events   []*Event
+	selected bool
+}
+
+type orderEvent struct {
+	ev    *Event
+	batch int
+	g     uint64
+	init  gState
+	next  gState
+}
+
+type gStatus int
+
+type gState struct {
+	seq    uint64
+	status gStatus
+}
+
+const (
+	gDead gStatus = iota
+	gRunnable
+	gRunning
+	gWaiting
+
+	unordered = ^uint64(0)
+	garbage   = ^uint64(0) - 1
+	noseq     = ^uint64(0)
+	seqinc    = ^uint64(0) - 1
+)
+
+// order1007 merges a set of per-P event batches into a single, consistent stream.
+// The high level idea is as follows. Events within an individual batch are in
+// correct order, because they are emitted by a single P. So we need to produce
+// a correct interleaving of the batches. To do this we take first unmerged event
+// from each batch (frontier). Then choose subset that is "ready" to be merged,
+// that is, events for which all dependencies are already merged. Then we choose
+// event with the lowest timestamp from the subset, merge it and repeat.
+// This approach ensures that we form a consistent stream even if timestamps are
+// incorrect (condition observed on some machines).
+func order1007(m map[int][]*Event) (events []*Event, err error) {
+	pending := 0
+	var batches []*eventBatch
+	for _, v := range m {
+		pending += len(v)
+		batches = append(batches, &eventBatch{v, false})
+	}
+	gs := make(map[uint64]gState)
+	var frontier []orderEvent
+	for ; pending != 0; pending-- {
+		for i, b := range batches {
+			if b.selected || len(b.events) == 0 {
+				continue
+			}
+			ev := b.events[0]
+			g, init, next := stateTransition(ev)
+			if !transitionReady(g, gs[g], init) {
+				continue
+			}
+			frontier = append(frontier, orderEvent{ev, i, g, init, next})
+			b.events = b.events[1:]
+			b.selected = true
+			// Get rid of "Local" events, they are intended merely for ordering.
+			switch ev.Type {
+			case EvGoStartLocal:
+				ev.Type = EvGoStart
+			case EvGoUnblockLocal:
+				ev.Type = EvGoUnblock
+			case EvGoSysExitLocal:
+				ev.Type = EvGoSysExit
+			}
+		}
+		if len(frontier) == 0 {
+			return nil, fmt.Errorf("no consistent ordering of events possible")
+		}
+		sort.Sort(orderEventList(frontier))
+		f := frontier[0]
+		frontier[0] = frontier[len(frontier)-1]
+		frontier = frontier[:len(frontier)-1]
+		events = append(events, f.ev)
+		transition(gs, f.g, f.init, f.next)
+		if !batches[f.batch].selected {
+			panic("frontier batch is not selected")
+		}
+		batches[f.batch].selected = false
+	}
+
+	// At this point we have a consistent stream of events.
+	// Make sure time stamps respect the ordering.
+	// The tests will skip (not fail) the test case if they see this error.
+	if !sort.IsSorted(eventList(events)) {
+		return nil, ErrTimeOrder
+	}
+
+	// The last part is giving correct timestamps to EvGoSysExit events.
+	// The problem with EvGoSysExit is that actual syscall exit timestamp (ev.Args[2])
+	// is potentially acquired long before event emission. So far we've used
+	// timestamp of event emission (ev.Ts).
+	// We could not set ev.Ts = ev.Args[2] earlier, because it would produce
+	// seemingly broken timestamps (misplaced event).
+	// We also can't simply update the timestamp and resort events, because
+	// if timestamps are broken we will misplace the event and later report
+	// logically broken trace (instead of reporting broken timestamps).
+	lastSysBlock := make(map[uint64]int64)
+	for _, ev := range events {
+		switch ev.Type {
+		case EvGoSysBlock, EvGoInSyscall:
+			lastSysBlock[ev.G] = ev.Ts
+		case EvGoSysExit:
+			ts := int64(ev.Args[2])
+			if ts == 0 {
+				continue
+			}
+			block := lastSysBlock[ev.G]
+			if block == 0 {
+				return nil, fmt.Errorf("stray syscall exit")
+			}
+			if ts < block {
+				return nil, ErrTimeOrder
+			}
+			ev.Ts = ts
+		}
+	}
+	sort.Stable(eventList(events))
+
+	return
+}
+
+// stateTransition returns goroutine state (sequence and status) when the event
+// becomes ready for merging (init) and the goroutine state after the event (next).
+func stateTransition(ev *Event) (g uint64, init, next gState) {
+	switch ev.Type {
+	case EvGoCreate:
+		g = ev.Args[0]
+		init = gState{0, gDead}
+		next = gState{1, gRunnable}
+	case EvGoWaiting, EvGoInSyscall:
+		g = ev.G
+		init = gState{1, gRunnable}
+		next = gState{2, gWaiting}
+	case EvGoStart:
+		g = ev.G
+		init = gState{ev.Args[1], gRunnable}
+		next = gState{ev.Args[1] + 1, gRunning}
+	case EvGoStartLocal:
+		// noseq means that this event is ready for merging as soon as
+		// frontier reaches it (EvGoStartLocal is emitted on the same P
+		// as the corresponding EvGoCreate/EvGoUnblock, and thus the latter
+		// is already merged).
+		// seqinc is a stub for cases when event increments g sequence,
+		// but since we don't know current seq we also don't know next seq.
+		g = ev.G
+		init = gState{noseq, gRunnable}
+		next = gState{seqinc, gRunning}
+	case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
+		EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoSleep, EvGoSysBlock:
+		g = ev.G
+		init = gState{noseq, gRunning}
+		next = gState{noseq, gWaiting}
+	case EvGoSched, EvGoPreempt:
+		g = ev.G
+		init = gState{noseq, gRunning}
+		next = gState{noseq, gRunnable}
+	case EvGoUnblock, EvGoSysExit:
+		g = ev.Args[0]
+		init = gState{ev.Args[1], gWaiting}
+		next = gState{ev.Args[1] + 1, gRunnable}
+	case EvGoUnblockLocal, EvGoSysExitLocal:
+		g = ev.Args[0]
+		init = gState{noseq, gWaiting}
+		next = gState{seqinc, gRunnable}
+	case EvGCStart:
+		g = garbage
+		init = gState{ev.Args[0], gDead}
+		next = gState{ev.Args[0] + 1, gDead}
+	default:
+		// no ordering requirements
+		g = unordered
+	}
+	return
+}
+
+func transitionReady(g uint64, curr, init gState) bool {
+	return g == unordered || (init.seq == noseq || init.seq == curr.seq) && init.status == curr.status
+}
+
+func transition(gs map[uint64]gState, g uint64, init, next gState) {
+	if g == unordered {
+		return
+	}
+	curr := gs[g]
+	if !transitionReady(g, curr, init) {
+		panic("event sequences are broken")
+	}
+	switch next.seq {
+	case noseq:
+		next.seq = curr.seq
+	case seqinc:
+		next.seq = curr.seq + 1
+	}
+	gs[g] = next
+}
+
+// order1005 merges a set of per-P event batches into a single, consistent stream.
+func order1005(m map[int][]*Event) (events []*Event, err error) {
+	for _, batch := range m {
+		events = append(events, batch...)
+	}
+	for _, ev := range events {
+		if ev.Type == EvGoSysExit {
+			// EvGoSysExit emission is delayed until the thread has a P.
+			// Give it the real sequence number and time stamp.
+			ev.seq = int64(ev.Args[1])
+			if ev.Args[2] != 0 {
+				ev.Ts = int64(ev.Args[2])
+			}
+		}
+	}
+	sort.Sort(eventSeqList(events))
+	if !sort.IsSorted(eventList(events)) {
+		return nil, ErrTimeOrder
+	}
+	return
+}
+
+type orderEventList []orderEvent
+
+func (l orderEventList) Len() int {
+	return len(l)
+}
+
+func (l orderEventList) Less(i, j int) bool {
+	return l[i].ev.Ts < l[j].ev.Ts
+}
+
+func (l orderEventList) Swap(i, j int) {
+	l[i], l[j] = l[j], l[i]
+}
+
+type eventList []*Event
+
+func (l eventList) Len() int {
+	return len(l)
+}
+
+func (l eventList) Less(i, j int) bool {
+	return l[i].Ts < l[j].Ts
+}
+
+func (l eventList) Swap(i, j int) {
+	l[i], l[j] = l[j], l[i]
+}
+
+type eventSeqList []*Event
+
+func (l eventSeqList) Len() int {
+	return len(l)
+}
+
+func (l eventSeqList) Less(i, j int) bool {
+	return l[i].seq < l[j].seq
+}
+
+func (l eventSeqList) Swap(i, j int) {
+	l[i], l[j] = l[j], l[i]
+}
diff --git a/src/internal/trace/parser.go b/src/internal/trace/parser.go
index 11f9aba..c31517f 100644
--- a/src/internal/trace/parser.go
+++ b/src/internal/trace/parser.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -9,18 +9,19 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"math/rand"
 	"os"
 	"os/exec"
-	"sort"
 	"strconv"
 	"strings"
+	_ "unsafe"
 )
 
 // 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
+	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
@@ -58,24 +59,48 @@ const (
 )
 
 // Parse parses, post-processes and verifies the trace.
-func Parse(r io.Reader) ([]*Event, error) {
-	rawEvents, err := readTrace(r)
+func Parse(r io.Reader, bin string) ([]*Event, error) {
+	ver, events, err := parse(r, bin)
 	if err != nil {
 		return nil, err
 	}
-	events, err := parseEvents(rawEvents)
+	if ver < 1007 && bin == "" {
+		return nil, fmt.Errorf("for traces produced by go 1.6 or below, the binary argument must be provided")
+	}
+	return events, nil
+}
+
+// parse parses, post-processes and verifies the trace. It returns the
+// trace version and the list of events.
+func parse(r io.Reader, bin string) (int, []*Event, error) {
+	ver, rawEvents, strings, err := readTrace(r)
 	if err != nil {
-		return nil, err
+		return 0, nil, err
+	}
+	events, stacks, err := parseEvents(ver, rawEvents, strings)
+	if err != nil {
+		return 0, nil, err
 	}
 	events, err = removeFutile(events)
 	if err != nil {
-		return nil, err
+		return 0, nil, err
 	}
-	err = postProcessTrace(events)
+	err = postProcessTrace(ver, events)
 	if err != nil {
-		return nil, err
+		return 0, nil, err
 	}
-	return events, nil
+	// Attach stack traces.
+	for _, ev := range events {
+		if ev.StkID != 0 {
+			ev.Stk = stacks[ev.StkID]
+		}
+	}
+	if ver < 1007 && bin != "" {
+		if err := symbolize(events, bin); err != nil {
+			return 0, nil, err
+		}
+	}
+	return ver, events, nil
 }
 
 // rawEvent is a helper type used during parsing.
@@ -87,107 +112,187 @@ type rawEvent struct {
 
 // 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) {
+func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]string, err 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)
+	off, err := io.ReadFull(r, buf[:])
+	if err != nil {
+		err = fmt.Errorf("failed to read header: read %v, err %v", off, err)
+		return
+	}
+	ver, err = parseHeader(buf[:])
+	if err != nil {
+		return
 	}
-	if bytes.Compare(buf[:], []byte("go 1.5 trace\x00\x00\x00\x00")) != 0 {
-		return nil, fmt.Errorf("not a trace file")
+	switch ver {
+	case 1005, 1007:
+		break
+	default:
+		err = fmt.Errorf("unsupported trace file version %v.%v (update Go toolchain) %v", ver/1000, ver%1000, ver)
+		return
 	}
 
 	// Read events.
-	var events []rawEvent
+	strings = make(map[uint64]string)
 	for {
 		// Read event type and number of arguments (1 byte).
 		off0 := off
-		n, err := r.Read(buf[:1])
+		var n int
+		n, err = r.Read(buf[:1])
 		if err == io.EOF {
+			err = nil
 			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)
+			err = fmt.Errorf("failed to read trace at offset 0x%x: n=%v err=%v", off0, n, err)
+			return
 		}
 		off += n
 		typ := buf[0] << 2 >> 2
-		narg := buf[0] >> 6
+		narg := buf[0]>>6 + 1
+		inlineArgs := byte(4)
+		if ver < 1007 {
+			narg++
+			inlineArgs++
+		}
+		if typ == EvNone || typ >= EvCount || EventDescriptions[typ].minVersion > ver {
+			err = fmt.Errorf("unknown event type %v at offset 0x%x", typ, off0)
+			return
+		}
+		if typ == EvString {
+			// String dictionary entry [ID, length, string].
+			var id uint64
+			id, off, err = readVal(r, off)
+			if err != nil {
+				return
+			}
+			if id == 0 {
+				err = fmt.Errorf("string at offset %d has invalid id 0", off)
+				return
+			}
+			if strings[id] != "" {
+				err = fmt.Errorf("string at offset %d has duplicate id %v", off, id)
+				return
+			}
+			var ln uint64
+			ln, off, err = readVal(r, off)
+			if err != nil {
+				return
+			}
+			if ln == 0 {
+				err = fmt.Errorf("string at offset %d has invalid length 0", off)
+				return
+			}
+			if ln > 1e6 {
+				err = fmt.Errorf("string at offset %d has too large length %v", off, ln)
+				return
+			}
+			buf := make([]byte, ln)
+			var n int
+			n, err = io.ReadFull(r, buf)
+			if err != nil {
+				err = fmt.Errorf("failed to read trace at offset %d: read %v, want %v, error %v", off, n, ln, err)
+				return
+			}
+			off += n
+			strings[id] = string(buf)
+			continue
+		}
 		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
+		if narg < inlineArgs {
+			for i := 0; i < int(narg); i++ {
 				var v uint64
 				v, off, err = readVal(r, off)
 				if err != nil {
-					return nil, err
+					err = fmt.Errorf("failed to read event %v argument at offset %v (%v)", typ, off, err)
+					return
 				}
 				ev.args = append(ev.args, v)
 			}
 		} else {
-			// If narg == 3, the first value is length of the event in bytes.
+			// More than inlineArgs args, 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
+				err = fmt.Errorf("failed to read event %v argument at offset %v (%v)", typ, off, err)
+				return
 			}
 			evLen := v
 			off1 := off
 			for evLen > uint64(off-off1) {
 				v, off, err = readVal(r, off)
 				if err != nil {
-					return nil, err
+					err = fmt.Errorf("failed to read event %v argument at offset %v (%v)", typ, off, err)
+					return
 				}
 				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)
+				err = fmt.Errorf("event has wrong length at offset 0x%x: want %v, got %v", off0, evLen, off-off1)
+				return
 			}
 		}
 		events = append(events, ev)
 	}
-	return events, nil
+	return
+}
+
+// parseHeader parses trace header of the form "go 1.7 trace\x00\x00\x00\x00"
+// and returns parsed version as 1007.
+func parseHeader(buf []byte) (int, error) {
+	if len(buf) != 16 {
+		return 0, fmt.Errorf("bad header length")
+	}
+	if buf[0] != 'g' || buf[1] != 'o' || buf[2] != ' ' ||
+		buf[3] < '1' || buf[3] > '9' ||
+		buf[4] != '.' ||
+		buf[5] < '1' || buf[5] > '9' {
+		return 0, fmt.Errorf("not a trace file")
+	}
+	ver := int(buf[5] - '0')
+	i := 0
+	for ; buf[6+i] >= '0' && buf[6+i] <= '9' && i < 2; i++ {
+		ver = ver*10 + int(buf[6+i]-'0')
+	}
+	ver += int(buf[3]-'0') * 1000
+	if !bytes.Equal(buf[6+i:], []byte(" trace\x00\x00\x00\x00")[:10-i]) {
+		return 0, fmt.Errorf("not a trace file")
+	}
+	return ver, 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) {
+func parseEvents(ver int, rawEvents []rawEvent, strings map[uint64]string) (events []*Event, stacks map[uint64][]*Frame, 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)
+	stacks = make(map[uint64][]*Frame)
+	batches := make(map[int][]*Event) // events by P
 	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
-			}
+		narg := argNum(raw, ver)
+		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])
+			if ver < 1007 {
+				lastSeq = int64(raw.args[1])
+				lastTs = int64(raw.args[2])
+			} else {
+				lastTs = int64(raw.args[1])
+			}
 		case EvFrequency:
 			ticksPerSec = int64(raw.args[0])
 			if ticksPerSec <= 0 {
@@ -211,33 +316,53 @@ func parseEvents(rawEvents []rawEvent) (events []*Event, err error) {
 					raw.off, size)
 				return
 			}
-			if uint64(len(raw.args)) != size+2 {
+			want := 2 + 4*size
+			if ver < 1007 {
+				want = 2 + size
+			}
+			if uint64(len(raw.args)) != want {
 				err = fmt.Errorf("EvStack has wrong number of arguments at offset 0x%x: want %v, got %v",
-					raw.off, size+2, len(raw.args))
+					raw.off, want, 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]}
+					if ver < 1007 {
+						stk[i] = &Frame{PC: raw.args[2+i]}
+					} else {
+						pc := raw.args[2+i*4+0]
+						fn := raw.args[2+i*4+1]
+						file := raw.args[2+i*4+2]
+						line := raw.args[2+i*4+3]
+						stk[i] = &Frame{PC: pc, Fn: strings[fn], File: strings[file], Line: int(line)}
+					}
 				}
 				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]
+			var argOffset int
+			if ver < 1007 {
+				e.seq = lastSeq + int64(raw.args[0])
+				e.Ts = lastTs + int64(raw.args[1])
+				lastSeq = e.seq
+				argOffset = 2
+			} else {
+				e.Ts = lastTs + int64(raw.args[0])
+				argOffset = 1
 			}
-			if desc.Stack {
-				e.StkID = raw.args[len(desc.Args)+2]
+			lastTs = e.Ts
+			for i := argOffset; i < narg; i++ {
+				if i == narg-1 && desc.Stack {
+					e.StkID = raw.args[i]
+				} else {
+					e.Args[i-argOffset] = raw.args[i]
+				}
 			}
 			switch raw.typ {
-			case EvGoStart:
+			case EvGoStart, EvGoStartLocal:
 				lastG = e.Args[0]
 				e.G = lastG
 			case EvGCStart, EvGCDone, EvGCScanStart, EvGCScanDone:
@@ -247,45 +372,51 @@ func parseEvents(rawEvents []rawEvent) (events []*Event, err error) {
 				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])
-				}
+			case EvGoSysExit, EvGoWaiting, EvGoInSyscall:
+				e.G = e.Args[0]
 			}
-			events = append(events, e)
+			batches[lastP] = append(batches[lastP], e)
 		}
 	}
-	if len(events) == 0 {
+	if len(batches) == 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
 	}
+	if BreakTimestampsForTesting {
+		var batchArr [][]*Event
+		for _, batch := range batches {
+			batchArr = append(batchArr, batch)
+		}
+		for i := 0; i < 5; i++ {
+			batch := batchArr[rand.Intn(len(batchArr))]
+			batch[rand.Intn(len(batch))].Ts += int64(rand.Intn(2000) - 1000)
+		}
+	}
+	if ver < 1007 {
+		events, err = order1005(batches)
+	} else {
+		events, err = order1007(batches)
+	}
+	if err != nil {
+		return
+	}
+
+	// Translate cpu ticks to real time.
 	minTs := events[0].Ts
+	// Use floating point to avoid integer overflows.
+	freq := 1e9 / float64(ticksPerSec)
 	for _, ev := range events {
-		ev.Ts = (ev.Ts - minTs) * 1e9 / ticksPerSec
+		ev.Ts = int64(float64(ev.Ts-minTs) * freq)
 		// 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]
 		}
 	}
 
@@ -355,7 +486,7 @@ var ErrTimeOrder = fmt.Errorf("time stamps out of order")
 // 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 {
+func postProcessTrace(ver int, events []*Event) error {
 	const (
 		gDead = iota
 		gRunnable
@@ -446,19 +577,15 @@ func postProcessTrace(events []*Event) error {
 			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)
+			if g.state != gRunnable {
+				return fmt.Errorf("g %v is not runnable before EvGoWaiting (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
 			}
-			g1.state = gWaiting
-			gs[ev.Args[0]] = g1
+			g.state = gWaiting
 		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)
+			if g.state != gRunnable {
+				return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
 			}
-			g1.state = gWaiting
-			gs[ev.Args[0]] = g1
+			g.state = gWaiting
 		case EvGoCreate:
 			if err := checkRunning(p, g, ev, true); err != nil {
 				return err
@@ -478,8 +605,12 @@ func postProcessTrace(events []*Event) error {
 			g.evStart = ev
 			p.g = ev.G
 			if g.evCreate != nil {
-				// +1 because symbolizer expects return pc.
-				ev.Stk = []*Frame{{PC: g.evCreate.Args[1] + 1}}
+				if ver < 1007 {
+					// +1 because symbolizer expects return pc.
+					ev.Stk = []*Frame{{PC: g.evCreate.Args[1] + 1}}
+				} else {
+					ev.StkID = g.evCreate.Args[1]
+				}
 				g.evCreate = nil
 			}
 
@@ -565,23 +696,11 @@ func postProcessTrace(events []*Event) error {
 	// 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 {
+// symbolize 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 {
@@ -672,57 +791,81 @@ func readVal(r io.Reader, off0 int) (v uint64, off int, err error) {
 	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
+// Print dumps events to stdout. For debugging.
+func Print(events []*Event) {
+	for _, ev := range events {
+		PrintEvent(ev)
+	}
 }
 
-func (l eventList) Swap(i, j int) {
-	l[i], l[j] = l[j], l[i]
+// PrintEvent dumps the event to stdout. For debugging.
+func PrintEvent(ev *Event) {
+	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")
 }
 
-// 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])
+// argNum returns total number of args for the event accounting for timestamps,
+// sequence numbers and differences between trace format versions.
+func argNum(raw rawEvent, ver int) int {
+	desc := EventDescriptions[raw.typ]
+	if raw.typ == EvStack {
+		return len(raw.args)
+	}
+	narg := len(desc.Args)
+	if desc.Stack {
+		narg++
+	}
+	switch raw.typ {
+	case EvBatch, EvFrequency, EvTimerGoroutine:
+		if ver < 1007 {
+			narg++ // there was an unused arg before 1.7
+		}
+	case EvGCStart, EvGoStart, EvGoUnblock:
+		if ver < 1007 {
+			narg-- // 1.7 added an additional seq arg
+		}
+		fallthrough
+	default:
+		narg++ // timestamp
+		if ver < 1007 {
+			narg++ // sequence
 		}
-		fmt.Printf("\n")
 	}
+	return narg
 }
 
+// BreakTimestampsForTesting causes the parser to randomly alter timestamps (for testing of broken cputicks).
+var BreakTimestampsForTesting bool
+
 // 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]
+	EvStack          = 3  // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}]
 	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]
+	EvGCStart        = 7  // GC start [timestamp, seq, 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]
+	EvGoCreate       = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id]
+	EvGoStart        = 14 // goroutine starts running [timestamp, goroutine id, seq]
 	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]
+	EvGoUnblock      = 21 // goroutine is unblocked [timestamp, goroutine id, seq, 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]
@@ -730,57 +873,66 @@ const (
 	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]
+	EvGoSysExit      = 29 // syscall exit [timestamp, goroutine id, seq, 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]
+	EvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id]
+	EvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id]
+	EvHeapAlloc      = 33 // memstats.heap_live 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
+	EvString         = 37 // string dictionary entry [ID, length, string]
+	EvGoStartLocal   = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id]
+	EvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack]
+	EvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp]
+	EvCount          = 41
 )
 
 var EventDescriptions = [EvCount]struct {
-	Name  string
-	Stack bool
-	Args  []string
+	Name       string
+	minVersion int
+	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{}},
+	EvNone:           {"None", 1005, false, []string{}},
+	EvBatch:          {"Batch", 1005, false, []string{"p", "ticks"}}, // in 1.5 format it was {"p", "seq", "ticks"}
+	EvFrequency:      {"Frequency", 1005, false, []string{"freq"}},   // in 1.5 format it was {"freq", "unused"}
+	EvStack:          {"Stack", 1005, false, []string{"id", "siz"}},
+	EvGomaxprocs:     {"Gomaxprocs", 1005, true, []string{"procs"}},
+	EvProcStart:      {"ProcStart", 1005, false, []string{"thread"}},
+	EvProcStop:       {"ProcStop", 1005, false, []string{}},
+	EvGCStart:        {"GCStart", 1005, true, []string{"seq"}}, // in 1.5 format it was {}
+	EvGCDone:         {"GCDone", 1005, false, []string{}},
+	EvGCScanStart:    {"GCScanStart", 1005, false, []string{}},
+	EvGCScanDone:     {"GCScanDone", 1005, false, []string{}},
+	EvGCSweepStart:   {"GCSweepStart", 1005, true, []string{}},
+	EvGCSweepDone:    {"GCSweepDone", 1005, false, []string{}},
+	EvGoCreate:       {"GoCreate", 1005, true, []string{"g", "stack"}},
+	EvGoStart:        {"GoStart", 1005, false, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
+	EvGoEnd:          {"GoEnd", 1005, false, []string{}},
+	EvGoStop:         {"GoStop", 1005, true, []string{}},
+	EvGoSched:        {"GoSched", 1005, true, []string{}},
+	EvGoPreempt:      {"GoPreempt", 1005, true, []string{}},
+	EvGoSleep:        {"GoSleep", 1005, true, []string{}},
+	EvGoBlock:        {"GoBlock", 1005, true, []string{}},
+	EvGoUnblock:      {"GoUnblock", 1005, true, []string{"g", "seq"}}, // in 1.5 format it was {"g"}
+	EvGoBlockSend:    {"GoBlockSend", 1005, true, []string{}},
+	EvGoBlockRecv:    {"GoBlockRecv", 1005, true, []string{}},
+	EvGoBlockSelect:  {"GoBlockSelect", 1005, true, []string{}},
+	EvGoBlockSync:    {"GoBlockSync", 1005, true, []string{}},
+	EvGoBlockCond:    {"GoBlockCond", 1005, true, []string{}},
+	EvGoBlockNet:     {"GoBlockNet", 1005, true, []string{}},
+	EvGoSysCall:      {"GoSysCall", 1005, true, []string{}},
+	EvGoSysExit:      {"GoSysExit", 1005, false, []string{"g", "seq", "ts"}},
+	EvGoSysBlock:     {"GoSysBlock", 1005, false, []string{}},
+	EvGoWaiting:      {"GoWaiting", 1005, false, []string{"g"}},
+	EvGoInSyscall:    {"GoInSyscall", 1005, false, []string{"g"}},
+	EvHeapAlloc:      {"HeapAlloc", 1005, false, []string{"mem"}},
+	EvNextGC:         {"NextGC", 1005, false, []string{"mem"}},
+	EvTimerGoroutine: {"TimerGoroutine", 1005, false, []string{"g"}}, // in 1.5 format it was {"g", "unused"}
+	EvFutileWakeup:   {"FutileWakeup", 1005, false, []string{}},
+	EvString:         {"String", 1007, false, []string{}},
+	EvGoStartLocal:   {"GoStartLocal", 1007, false, []string{"g"}},
+	EvGoUnblockLocal: {"GoUnblockLocal", 1007, true, []string{"g"}},
+	EvGoSysExitLocal: {"GoSysExitLocal", 1007, false, []string{"g", "ts"}},
 }
diff --git a/src/internal/trace/parser_test.go b/src/internal/trace/parser_test.go
index fecefc4..daad3e3 100644
--- a/src/internal/trace/parser_test.go
+++ b/src/internal/trace/parser_test.go
@@ -5,6 +5,9 @@
 package trace
 
 import (
+	"bytes"
+	"io/ioutil"
+	"path/filepath"
 	"strings"
 	"testing"
 )
@@ -22,9 +25,117 @@ func TestCorruptedInputs(t *testing.T) {
 		"go 1.5 trace\x00\x00\x00\x00\xc3\x0200",
 	}
 	for _, data := range tests {
-		events, err := Parse(strings.NewReader(data))
+		events, err := Parse(strings.NewReader(data), "")
 		if err == nil || events != nil {
-			t.Fatalf("no error on input: %q\n", data)
+			t.Fatalf("no error on input: %q", data)
 		}
 	}
 }
+
+func TestParseCanned(t *testing.T) {
+	files, err := ioutil.ReadDir("./testdata")
+	if err != nil {
+		t.Fatalf("failed to read ./testdata: %v", err)
+	}
+	for _, f := range files {
+		data, err := ioutil.ReadFile(filepath.Join("./testdata", f.Name()))
+		if err != nil {
+			t.Fatalf("failed to read input file: %v", err)
+		}
+		// Instead of Parse that requires a proper binary name for old traces,
+		// we use 'parse' that omits symbol lookup if an empty string is given.
+		_, _, err = parse(bytes.NewReader(data), "")
+		switch {
+		case strings.HasSuffix(f.Name(), "_good"):
+			if err != nil {
+				t.Errorf("failed to parse good trace %v: %v", f.Name(), err)
+			}
+		case strings.HasSuffix(f.Name(), "_unordered"):
+			if err != ErrTimeOrder {
+				t.Errorf("unordered trace is not detected %v: %v", f.Name(), err)
+			}
+		default:
+			t.Errorf("unknown input file suffix: %v", f.Name())
+		}
+	}
+}
+
+func TestParseVersion(t *testing.T) {
+	tests := map[string]int{
+		"go 1.5 trace\x00\x00\x00\x00": 1005,
+		"go 1.7 trace\x00\x00\x00\x00": 1007,
+		"go 1.10 trace\x00\x00\x00":    1010,
+		"go 1.25 trace\x00\x00\x00":    1025,
+		"go 1.234 trace\x00\x00":       1234,
+		"go 1.2345 trace\x00":          -1,
+		"go 0.0 trace\x00\x00\x00\x00": -1,
+		"go a.b trace\x00\x00\x00\x00": -1,
+	}
+	for header, ver := range tests {
+		ver1, err := parseHeader([]byte(header))
+		if ver == -1 {
+			if err == nil {
+				t.Fatalf("no error on input: %q, version %v", header, ver1)
+			}
+		} else {
+			if err != nil {
+				t.Fatalf("failed to parse: %q (%v)", header, err)
+			}
+			if ver != ver1 {
+				t.Fatalf("wrong version: %v, want %v, input: %q", ver1, ver, header)
+			}
+		}
+	}
+}
+
+func TestTimestampOverflow(t *testing.T) {
+	// Test that parser correctly handles large timestamps (long tracing).
+	w := newWriter()
+	w.emit(EvBatch, 0, 0)
+	w.emit(EvFrequency, 1e9)
+	for ts := uint64(1); ts < 1e16; ts *= 2 {
+		w.emit(EvGoCreate, ts, ts, 0, 0)
+	}
+	if _, err := Parse(w, ""); err != nil {
+		t.Fatalf("failed to parse: %v", err)
+	}
+}
+
+type writer struct {
+	bytes.Buffer
+}
+
+func newWriter() *writer {
+	w := new(writer)
+	w.Write([]byte("go 1.7 trace\x00\x00\x00\x00"))
+	return w
+}
+
+func (w *writer) emit(typ byte, args ...uint64) {
+	nargs := byte(len(args)) - 1
+	if nargs > 3 {
+		nargs = 3
+	}
+	buf := []byte{typ | nargs<<6}
+	if nargs == 3 {
+		buf = append(buf, 0)
+	}
+	for _, a := range args {
+		buf = appendVarint(buf, a)
+	}
+	if nargs == 3 {
+		buf[1] = byte(len(buf) - 2)
+	}
+	n, err := w.Write(buf)
+	if n != len(buf) || err != nil {
+		panic("failed to write")
+	}
+}
+
+func appendVarint(buf []byte, v uint64) []byte {
+	for ; v >= 0x80; v >>= 7 {
+		buf = append(buf, 0x80|byte(v))
+	}
+	buf = append(buf, byte(v))
+	return buf
+}
diff --git a/src/internal/trace/testdata/http_1_5_good b/src/internal/trace/testdata/http_1_5_good
new file mode 100644
index 0000000..0736cae
Binary files /dev/null and b/src/internal/trace/testdata/http_1_5_good differ
diff --git a/src/internal/trace/testdata/stress_1_5_good b/src/internal/trace/testdata/stress_1_5_good
new file mode 100644
index 0000000..c5055eb
Binary files /dev/null and b/src/internal/trace/testdata/stress_1_5_good differ
diff --git a/src/internal/trace/testdata/stress_1_5_unordered b/src/internal/trace/testdata/stress_1_5_unordered
new file mode 100644
index 0000000..11f7d74
Binary files /dev/null and b/src/internal/trace/testdata/stress_1_5_unordered differ
diff --git a/src/internal/trace/testdata/stress_start_stop_1_5_good b/src/internal/trace/testdata/stress_start_stop_1_5_good
new file mode 100644
index 0000000..72a887b
Binary files /dev/null and b/src/internal/trace/testdata/stress_start_stop_1_5_good differ
diff --git a/src/io/example_test.go b/src/io/example_test.go
index 412dfb3..bf16de8 100644
--- a/src/io/example_test.go
+++ b/src/io/example_test.go
@@ -189,7 +189,7 @@ func ExampleSectionReader_Seek() {
 	r := strings.NewReader("some io.Reader stream to be read\n")
 	s := io.NewSectionReader(r, 5, 16)
 
-	if _, err := s.Seek(10, 0); err != nil {
+	if _, err := s.Seek(10, io.SeekStart); err != nil {
 		log.Fatal(err)
 	}
 
diff --git a/src/io/io.go b/src/io/io.go
index 8e7855c..19d0ae5 100644
--- a/src/io/io.go
+++ b/src/io/io.go
@@ -16,6 +16,13 @@ import (
 	"errors"
 )
 
+// Seek whence values.
+const (
+	SeekStart   = 0 // seek relative to the origin of the file
+	SeekCurrent = 1 // seek relative to the current offset
+	SeekEnd     = 2 // seek relative to the end
+)
+
 // ErrShortWrite means that a write accepted fewer bytes than requested
 // but failed to return an explicit error.
 var ErrShortWrite = errors.New("short write")
@@ -41,23 +48,23 @@ var ErrNoProgress = errors.New("multiple Read calls return no data or error")
 
 // Reader is the interface that wraps the basic Read method.
 //
-// Read reads up to len(p) bytes into p.  It returns the number of bytes
-// read (0 <= n <= len(p)) and any error encountered.  Even if Read
+// Read reads up to len(p) bytes into p. It returns the number of bytes
+// read (0 <= n <= len(p)) and any error encountered. Even if Read
 // returns n < len(p), it may use all of p as scratch space during the call.
 // If some data is available but not len(p) bytes, Read conventionally
 // returns what is available instead of waiting for more.
 //
 // When Read encounters an error or end-of-file condition after
 // successfully reading n > 0 bytes, it returns the number of
-// bytes read.  It may return the (non-nil) error from the same call
+// bytes read. It may return the (non-nil) error from the same call
 // or return the error (and n == 0) from a subsequent call.
 // 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 either err == EOF or err == nil. The next Read should
 // return 0, EOF.
 //
 // Callers should always process the n > 0 bytes returned before
-// considering the error err.  Doing so correctly handles I/O errors
+// considering the error err. Doing so correctly handles I/O errors
 // that happen after reading some bytes and also both of the
 // allowed EOF behaviors.
 //
@@ -95,10 +102,12 @@ type Closer interface {
 // Seeker is the interface that wraps the basic Seek method.
 //
 // Seek sets the offset for the next Read or Write to offset,
-// interpreted according to whence: 0 means relative to the start of
-// the file, 1 means relative to the current offset, and 2 means
-// relative to the end. Seek returns the new offset relative to the
-// start of the file and an error, if any.
+// interpreted according to whence:
+// SeekStart means relative to the start of the file,
+// SeekCurrent means relative to the current offset, and
+// SeekEnd means relative to the end.
+// Seek returns the new offset relative to the start of the
+// file and an error, if any.
 //
 // Seeking to an offset before the start of the file is an error.
 // Seeking to any positive offset is legal, but the behavior of subsequent
@@ -176,15 +185,15 @@ type WriterTo interface {
 // ReaderAt is the interface that wraps the basic ReadAt method.
 //
 // ReadAt reads len(p) bytes into p starting at offset off in the
-// underlying input source.  It returns the number of bytes
+// underlying input source. It returns the number of bytes
 // read (0 <= n <= len(p)) and any error encountered.
 //
 // When ReadAt returns n < len(p), it returns a non-nil error
-// explaining why more bytes were not returned.  In this respect,
+// explaining why more bytes were not returned. In this respect,
 // ReadAt is stricter than Read.
 //
 // Even if ReadAt returns n < len(p), it may use all of p as scratch
-// space during the call.  If some data is available but not len(p) bytes,
+// space during the call. If some data is available but not len(p) bytes,
 // ReadAt blocks until either all the data is available or an error occurs.
 // In this respect ReadAt is different from Read.
 //
@@ -206,7 +215,7 @@ type ReaderAt interface {
 // WriterAt is the interface that wraps the basic WriteAt method.
 //
 // WriteAt writes len(p) bytes from p to the underlying data stream
-// at offset off.  It returns the number of bytes written from p (0 <= n <= len(p))
+// at offset off. It returns the number of bytes written from p (0 <= n <= len(p))
 // and any error encountered that caused the write to stop early.
 // WriteAt must return a non-nil error if it returns n < len(p).
 //
@@ -226,7 +235,7 @@ type WriterAt interface {
 //
 // ReadByte reads and returns the next byte from the input.
 type ByteReader interface {
-	ReadByte() (c byte, err error)
+	ReadByte() (byte, error)
 }
 
 // ByteScanner is the interface that adds the UnreadByte method to the
@@ -274,6 +283,7 @@ type stringWriter interface {
 
 // 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.
+// Otherwise, w.Write is called exactly once.
 func WriteString(w Writer, s string) (n int, err error) {
 	if sw, ok := w.(stringWriter); ok {
 		return sw.WriteString(s)
@@ -335,7 +345,7 @@ func CopyN(dst Writer, src Reader, n int64) (written int64, err error) {
 }
 
 // Copy copies from src to dst until either EOF is reached
-// on src or an error occurs.  It returns the number of bytes
+// on src or an error occurs. It returns the number of bytes
 // copied and the first error encountered while copying, if any.
 //
 // A successful Copy returns err == nil, not err == EOF.
@@ -462,11 +472,11 @@ func (s *SectionReader) Seek(offset int64, whence int) (int64, error) {
 	switch whence {
 	default:
 		return 0, errWhence
-	case 0:
+	case SeekStart:
 		offset += s.base
-	case 1:
+	case SeekCurrent:
 		offset += s.off
-	case 2:
+	case SeekEnd:
 		offset += s.limit
 	}
 	if offset < s.base {
@@ -497,7 +507,7 @@ func (s *SectionReader) Size() int64 { return s.limit - s.base }
 
 // TeeReader returns a Reader that writes to w what it reads from r.
 // All reads from r performed through it are matched with
-// corresponding writes to w.  There is no internal buffering -
+// corresponding writes to w. There is no internal buffering -
 // the write must complete before the read completes.
 // Any error encountered while writing is reported as a read error.
 func TeeReader(r Reader, w Writer) Reader {
diff --git a/src/io/io_test.go b/src/io/io_test.go
index e892574..877e839 100644
--- a/src/io/io_test.go
+++ b/src/io/io_test.go
@@ -347,7 +347,7 @@ func TestSectionReader_Seek(t *testing.T) {
 	br := bytes.NewReader([]byte("foo"))
 	sr := NewSectionReader(br, 0, int64(len("foo")))
 
-	for whence := 0; whence <= 2; whence++ {
+	for _, whence := range []int{SeekStart, SeekCurrent, SeekEnd} {
 		for offset := int64(-3); offset <= 4; offset++ {
 			brOff, brErr := br.Seek(offset, whence)
 			srOff, srErr := sr.Seek(offset, whence)
@@ -359,7 +359,7 @@ func TestSectionReader_Seek(t *testing.T) {
 	}
 
 	// And verify we can just seek past the end and get an EOF
-	got, err := sr.Seek(100, 0)
+	got, err := sr.Seek(100, SeekStart)
 	if err != nil || got != 100 {
 		t.Errorf("Seek = %v, %v; want 100, nil", got, err)
 	}
diff --git a/src/io/ioutil/ioutil.go b/src/io/ioutil/ioutil.go
index e90a33f..8ecbb2d 100644
--- a/src/io/ioutil/ioutil.go
+++ b/src/io/ioutil/ioutil.go
@@ -63,8 +63,8 @@ func ReadFile(filename string) ([]byte, error) {
 		}
 	}
 	// As initial capacity for readAll, use n + a little extra in case Size is zero,
-	// and to avoid another allocation after Read has filled the buffer.  The readAll
-	// call will read into its allocated internal buffer cheaply.  If the size was
+	// and to avoid another allocation after Read has filled the buffer. The readAll
+	// call will read into its allocated internal buffer cheaply. If the size was
 	// wrong, we'll either waste some space off the end or reallocate as needed, but
 	// in the overwhelmingly common case we'll get it just right.
 	return readAll(f, n+bytes.MinRead)
diff --git a/src/io/ioutil/tempfile.go b/src/io/ioutil/tempfile.go
index 61d4a7a..42718cc 100644
--- a/src/io/ioutil/tempfile.go
+++ b/src/io/ioutil/tempfile.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -41,8 +41,8 @@ func nextSuffix() string {
 // If dir is the empty string, TempFile uses the default directory
 // for temporary files (see os.TempDir).
 // Multiple programs calling TempFile simultaneously
-// will not choose the same file.  The caller can use f.Name()
-// to find the pathname of the file.  It is the caller's responsibility
+// will not choose the same file. The caller can use f.Name()
+// to find the pathname of the file. It is the caller's responsibility
 // to remove the file when no longer needed.
 func TempFile(dir, prefix string) (f *os.File, err error) {
 	if dir == "" {
@@ -68,10 +68,10 @@ func TempFile(dir, prefix string) (f *os.File, err error) {
 
 // TempDir creates a new temporary directory in the directory dir
 // with a name beginning with prefix and returns the path of the
-// new directory.  If dir is the empty string, TempDir uses the
+// new directory. If dir is the empty string, TempDir uses the
 // default directory for temporary files (see os.TempDir).
 // Multiple programs calling TempDir simultaneously
-// will not choose the same directory.  It is the caller's responsibility
+// will not choose the same directory. It is the caller's responsibility
 // to remove the directory when no longer needed.
 func TempDir(dir, prefix string) (name string, err error) {
 	if dir == "" {
diff --git a/src/io/multi.go b/src/io/multi.go
index 16860aa..ed05cac 100644
--- a/src/io/multi.go
+++ b/src/io/multi.go
@@ -10,6 +10,13 @@ type multiReader struct {
 
 func (mr *multiReader) Read(p []byte) (n int, err error) {
 	for len(mr.readers) > 0 {
+		// Optimization to flatten nested multiReaders (Issue 13558)
+		if len(mr.readers) == 1 {
+			if r, ok := mr.readers[0].(*multiReader); ok {
+				mr.readers = r.readers
+				continue
+			}
+		}
 		n, err = mr.readers[0].Read(p)
 		if n > 0 || err != EOF {
 			if err == EOF {
@@ -25,7 +32,7 @@ func (mr *multiReader) Read(p []byte) (n int, err error) {
 }
 
 // MultiReader returns a Reader that's the logical concatenation of
-// the provided input readers.  They're read sequentially.  Once all
+// the provided input readers. They're read sequentially. Once all
 // inputs have returned EOF, Read will return EOF.  If any of the readers
 // return a non-nil, non-EOF error, Read will return that error.
 func MultiReader(readers ...Reader) Reader {
diff --git a/src/io/multi_test.go b/src/io/multi_test.go
index e80592e..2dce369 100644
--- a/src/io/multi_test.go
+++ b/src/io/multi_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,9 +7,11 @@ package io_test
 import (
 	"bytes"
 	"crypto/sha1"
+	"errors"
 	"fmt"
 	. "io"
 	"io/ioutil"
+	"runtime"
 	"strings"
 	"testing"
 )
@@ -164,3 +166,33 @@ func TestMultiWriterCopy(t *testing.T) {
 		t.Errorf("buf.String() = %q, want %q", buf.String(), "hello world")
 	}
 }
+
+// readerFunc is an io.Reader implemented by the underlying func.
+type readerFunc func(p []byte) (int, error)
+
+func (f readerFunc) Read(p []byte) (int, error) {
+	return f(p)
+}
+
+// Test that MultiReader properly flattens chained multiReaders when Read is called
+func TestMultiReaderFlatten(t *testing.T) {
+	pc := make([]uintptr, 1000) // 1000 should fit the full stack
+	var myDepth = runtime.Callers(0, pc)
+	var readDepth int // will contain the depth from which fakeReader.Read was called
+	var r Reader = MultiReader(readerFunc(func(p []byte) (int, error) {
+		readDepth = runtime.Callers(1, pc)
+		return 0, errors.New("irrelevant")
+	}))
+
+	// chain a bunch of multiReaders
+	for i := 0; i < 100; i++ {
+		r = MultiReader(r)
+	}
+
+	r.Read(nil) // don't care about errors, just want to check the call-depth for Read
+
+	if readDepth != myDepth+2 { // 2 should be multiReader.Read and fakeReader.Read
+		t.Errorf("multiReader did not flatten chained multiReaders: expected readDepth %d, got %d",
+			myDepth+2, readDepth)
+	}
+}
diff --git a/src/io/pipe.go b/src/io/pipe.go
index 179515e..7e98cd2 100644
--- a/src/io/pipe.go
+++ b/src/io/pipe.go
@@ -15,11 +15,6 @@ import (
 // ErrClosedPipe is the error used for read or write operations on a closed pipe.
 var ErrClosedPipe = errors.New("io: read/write on closed pipe")
 
-type pipeResult struct {
-	n   int
-	err error
-}
-
 // A pipe is the shared pipe structure underlying PipeReader and PipeWriter.
 type pipe struct {
 	rl    sync.Mutex // gates readers one at a time
diff --git a/src/log/log.go b/src/log/log.go
index 4cfe550..26cdb53 100644
--- a/src/log/log.go
+++ b/src/log/log.go
@@ -42,8 +42,8 @@ const (
 )
 
 // A Logger represents an active logging object that generates lines of
-// output to an io.Writer.  Each logging operation makes a single call to
-// the Writer's Write method.  A Logger can be used simultaneously from
+// output to an io.Writer. Each logging operation makes a single call to
+// the Writer's Write method. A Logger can be used simultaneously from
 // multiple goroutines; it guarantees to serialize access to the Writer.
 type Logger struct {
 	mu     sync.Mutex // ensures atomic writes; protects the following fields
@@ -53,7 +53,7 @@ type Logger struct {
 	buf    []byte     // for accumulating text to write
 }
 
-// New creates a new Logger.   The out variable sets the
+// New creates a new Logger. The out variable sets the
 // destination to which log data will be written.
 // The prefix appears at the beginning of each generated log line.
 // The flag argument defines the logging properties.
@@ -134,10 +134,10 @@ func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
 	}
 }
 
-// Output writes the output for a logging event.  The string s contains
+// 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 used to recover the PC and is
+// Logger. A newline is appended if the last character of s is not
+// already a newline. Calldepth is used to recover the PC and is
 // provided for generality, although at the moment on all pre-defined
 // paths it will be 2.
 func (l *Logger) Output(calldepth int, s string) error {
@@ -334,10 +334,10 @@ func Panicln(v ...interface{}) {
 	panic(s)
 }
 
-// Output writes the output for a logging event.  The string s contains
+// 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
+// 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.
diff --git a/src/log/syslog/syslog.go b/src/log/syslog/syslog.go
index 4bf4476..9e888dd 100644
--- a/src/log/syslog/syslog.go
+++ b/src/log/syslog/syslog.go
@@ -85,8 +85,8 @@ type Writer struct {
 }
 
 // This interface and the separate syslog_unix.go file exist for
-// Solaris support as implemented by gccgo.  On Solaris you can not
-// simply open a TCP connection to the syslog daemon.  The gccgo
+// Solaris support as implemented by gccgo. On Solaris you cannot
+// simply open a TCP connection to the syslog daemon. The gccgo
 // sources have a syslog_solaris.go file that implements unixSyslog to
 // return a type that satisfies this interface and simply calls the C
 // library syslog function.
@@ -100,15 +100,15 @@ type netConn struct {
 	conn  net.Conn
 }
 
-// New establishes a new connection to the system log daemon.  Each
+// New establishes a new connection to the system log daemon. Each
 // write to the returned writer sends a log message with the given
 // priority and prefix.
-func New(priority Priority, tag string) (w *Writer, err error) {
+func New(priority Priority, tag string) (*Writer, error) {
 	return Dial("", "", priority, tag)
 }
 
 // Dial establishes a connection to a log daemon by connecting to
-// address raddr on the specified network.  Each write to the returned
+// address raddr on the specified network. Each write to the returned
 // writer sends a log message with the given facility, severity and
 // tag.
 // If network is empty, Dial will connect to the local syslog server.
@@ -187,57 +187,57 @@ func (w *Writer) Close() error {
 
 // Emerg logs a message with severity LOG_EMERG, ignoring the severity
 // passed to New.
-func (w *Writer) Emerg(m string) (err error) {
-	_, err = w.writeAndRetry(LOG_EMERG, m)
+func (w *Writer) Emerg(m string) error {
+	_, err := w.writeAndRetry(LOG_EMERG, m)
 	return err
 }
 
 // Alert logs a message with severity LOG_ALERT, ignoring the severity
 // passed to New.
-func (w *Writer) Alert(m string) (err error) {
-	_, err = w.writeAndRetry(LOG_ALERT, m)
+func (w *Writer) Alert(m string) error {
+	_, err := w.writeAndRetry(LOG_ALERT, m)
 	return err
 }
 
 // Crit logs a message with severity LOG_CRIT, ignoring the severity
 // passed to New.
-func (w *Writer) Crit(m string) (err error) {
-	_, err = w.writeAndRetry(LOG_CRIT, m)
+func (w *Writer) Crit(m string) error {
+	_, err := w.writeAndRetry(LOG_CRIT, m)
 	return err
 }
 
 // Err logs a message with severity LOG_ERR, ignoring the severity
 // passed to New.
-func (w *Writer) Err(m string) (err error) {
-	_, err = w.writeAndRetry(LOG_ERR, m)
+func (w *Writer) Err(m string) error {
+	_, err := w.writeAndRetry(LOG_ERR, m)
 	return err
 }
 
 // Warning logs a message with severity LOG_WARNING, ignoring the
 // severity passed to New.
-func (w *Writer) Warning(m string) (err error) {
-	_, err = w.writeAndRetry(LOG_WARNING, m)
+func (w *Writer) Warning(m string) error {
+	_, err := w.writeAndRetry(LOG_WARNING, m)
 	return err
 }
 
 // Notice logs a message with severity LOG_NOTICE, ignoring the
 // severity passed to New.
-func (w *Writer) Notice(m string) (err error) {
-	_, err = w.writeAndRetry(LOG_NOTICE, m)
+func (w *Writer) Notice(m string) error {
+	_, err := w.writeAndRetry(LOG_NOTICE, m)
 	return err
 }
 
 // Info logs a message with severity LOG_INFO, ignoring the severity
 // passed to New.
-func (w *Writer) Info(m string) (err error) {
-	_, err = w.writeAndRetry(LOG_INFO, m)
+func (w *Writer) Info(m string) error {
+	_, err := w.writeAndRetry(LOG_INFO, m)
 	return err
 }
 
 // Debug logs a message with severity LOG_DEBUG, ignoring the severity
 // passed to New.
-func (w *Writer) Debug(m string) (err error) {
-	_, err = w.writeAndRetry(LOG_DEBUG, m)
+func (w *Writer) Debug(m string) error {
+	_, err := w.writeAndRetry(LOG_DEBUG, m)
 	return err
 }
 
diff --git a/src/make.bash b/src/make.bash
index 2531ca4..1a1412a 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -44,9 +44,15 @@
 # This is used by cgo. Default is CXX, or, if that is not set, 
 # "g++" or "clang++".
 #
+# FC: Command line to run to compile Fortran code for GOARCH.
+# This is used by cgo. Default is "gfortran".
+#
 # GO_DISTFLAGS: extra flags to provide to "dist bootstrap".
 
 set -e
+
+unset GOBIN # Issue 14340
+
 if [ ! -f run.bash ]; then
 	echo 'make.bash must be run from $GOROOT/src' 1>&2
 	exit 1
@@ -149,6 +155,7 @@ if [ "$1" = "--no-clean" ]; then
 	shift
 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
 echo
diff --git a/src/make.bat b/src/make.bat
index 0efdcc5..bf25b95 100644
--- a/src/make.bat
+++ b/src/make.bat
@@ -31,6 +31,9 @@
 ::
 :: CC_FOR_TARGET: Command line to run compile C code for GOARCH.
 :: This is used by cgo. Default is CC.
+::
+:: FC: Command line to run to compile Fortran code.
+:: This is used by cgo. Default is "gfortran".
 
 @echo off
 
@@ -65,6 +68,7 @@ setlocal
 set GOROOT=%GOROOT_BOOTSTRAP%
 set GOOS=
 set GOARCH=
+set GOBIN=
 "%GOROOT_BOOTSTRAP%\bin\go" build -o cmd\dist\dist.exe .\cmd\dist
 endlocal
 if errorlevel 1 goto fail
diff --git a/src/make.rc b/src/make.rc
index 6016204..243f83c 100755
--- a/src/make.rc
+++ b/src/make.rc
@@ -80,7 +80,7 @@ if(~ $sysname vx32)
 
 if(! ~ $GOHOSTARCH $GOARCH || ! ~ $GOHOSTOS $GOOS){
 	echo '##### Building packages and commands for host,' $GOHOSTOS/$GOHOSTARCH^.
-	GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
+	GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH GOBIN= \
 		$GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std cmd
 	echo
 }
diff --git a/src/math/acosh.go b/src/math/acosh.go
index e394008..dce21b2 100644
--- a/src/math/acosh.go
+++ b/src/math/acosh.go
@@ -6,7 +6,7 @@ package math
 
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/e_acosh.c
-// and came with this notice.  The go code is a simplified
+// and came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/all_test.go b/src/math/all_test.go
index 968a7b1..d9ea1fd 100644
--- a/src/math/all_test.go
+++ b/src/math/all_test.go
@@ -1225,12 +1225,6 @@ var hypotSC = []float64{
 	NaN(),
 }
 
-var vfilogbSC = []float64{
-	Inf(-1),
-	0,
-	Inf(1),
-	NaN(),
-}
 var ilogbSC = []int{
 	MaxInt32,
 	MinInt32,
@@ -1756,7 +1750,6 @@ func tolerance(a, b, e float64) bool {
 	}
 	return d < e
 }
-func kindaclose(a, b float64) bool { return tolerance(a, b, 1e-8) }
 func close(a, b float64) bool      { return tolerance(a, b, 1e-14) }
 func veryclose(a, b float64) bool  { return tolerance(a, b, 4e-16) }
 func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
diff --git a/src/math/asin_386.s b/src/math/asin_386.s
index 4f34e12..7dab390 100644
--- a/src/math/asin_386.s
+++ b/src/math/asin_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/asin_amd64.s b/src/math/asin_amd64.s
index 1a43d48..ad71be0 100644
--- a/src/math/asin_amd64.s
+++ b/src/math/asin_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/asin_amd64p32.s b/src/math/asin_amd64p32.s
index 2751c47..7cbdd41 100644
--- a/src/math/asin_amd64p32.s
+++ b/src/math/asin_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/asin_arm.s b/src/math/asin_arm.s
index 8fe03b6..21a8d07 100644
--- a/src/math/asin_arm.s
+++ b/src/math/asin_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/asinh.go b/src/math/asinh.go
index ff2de02..3b793b0 100644
--- a/src/math/asinh.go
+++ b/src/math/asinh.go
@@ -6,7 +6,7 @@ package math
 
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/s_asinh.c
-// and came with this notice.  The go code is a simplified
+// and came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/atan2_386.s b/src/math/atan2_386.s
index 31a74e7..90d211b 100644
--- a/src/math/atan2_386.s
+++ b/src/math/atan2_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/atan2_amd64.s b/src/math/atan2_amd64.s
index fc471f7..256e98c 100644
--- a/src/math/atan2_amd64.s
+++ b/src/math/atan2_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/atan2_amd64p32.s b/src/math/atan2_amd64p32.s
index 3fdc03c..3d1711a 100644
--- a/src/math/atan2_amd64p32.s
+++ b/src/math/atan2_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/atan2_arm.s b/src/math/atan2_arm.s
index 06c12ec..755131f 100644
--- a/src/math/atan2_arm.s
+++ b/src/math/atan2_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/atan_386.s b/src/math/atan_386.s
index f3976b1..43e79b9 100644
--- a/src/math/atan_386.s
+++ b/src/math/atan_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/atan_amd64.s b/src/math/atan_amd64.s
index b801ae9..0458625 100644
--- a/src/math/atan_amd64.s
+++ b/src/math/atan_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/atan_amd64p32.s b/src/math/atan_amd64p32.s
index 1c1f6ce..166f5b9 100644
--- a/src/math/atan_amd64p32.s
+++ b/src/math/atan_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/atan_arm.s b/src/math/atan_arm.s
index d190a8b..29b5de2 100644
--- a/src/math/atan_arm.s
+++ b/src/math/atan_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/atanh.go b/src/math/atanh.go
index 113d5c1..d59a847 100644
--- a/src/math/atanh.go
+++ b/src/math/atanh.go
@@ -6,7 +6,7 @@ package math
 
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/e_atanh.c
-// and came with this notice.  The go code is a simplified
+// and came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/big/arith_amd64p32.s b/src/math/big/arith_amd64p32.s
index 8610e90..6006646 100644
--- a/src/math/big/arith_amd64p32.s
+++ b/src/math/big/arith_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/big/arith_decl.go b/src/math/big/arith_decl.go
index 1707aa4..5433b6d 100644
--- a/src/math/big/arith_decl.go
+++ b/src/math/big/arith_decl.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/big/arith_decl_pure.go b/src/math/big/arith_decl_pure.go
index e760a38..21775dd 100644
--- a/src/math/big/arith_decl_pure.go
+++ b/src/math/big/arith_decl_pure.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/math/big/arith_s390x.s b/src/math/big/arith_s390x.s
new file mode 100644
index 0000000..a691970
--- /dev/null
+++ b/src/math/big/arith_s390x.s
@@ -0,0 +1,565 @@
+// Copyright 2016 The Go 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,s390x
+
+#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
+	MOVD x+0(FP), R3
+	MOVD y+8(FP), R4
+	MULHDU R3, R4
+	MOVD R10, z1+16(FP)
+	MOVD R11, z0+24(FP)
+	RET
+
+// func divWW(x1, x0, y Word) (q, r Word)
+TEXT ·divWW(SB),NOSPLIT,$0
+	MOVD  x1+0(FP), R10
+	MOVD  x0+8(FP), R11
+	MOVD  y+16(FP), R5
+	WORD  $0xb98700a5 // dlgr r10,r5
+	MOVD  R11, q+24(FP)
+	MOVD  R10, r+32(FP)
+	RET
+
+// DI = R3, CX = R4, SI = r10, r8 = r8, r9=r9, r10 = r2 , r11 = r5, r12 = r6, r13 = r7, r14 = r1 (R0 set to 0) + use R11
+// func addVV(z, x, y []Word) (c Word)
+TEXT ·addVV(SB),NOSPLIT,$0
+	MOVD z_len+8(FP), R3
+	MOVD x+24(FP), R8
+	MOVD y+48(FP), R9
+	MOVD z+0(FP), R2
+
+	MOVD $0, R4		// c = 0
+	MOVD $0, R0		// make sure it's zero
+	MOVD $0, R10		// i = 0
+
+	// s/JL/JMP/ below to disable the unrolled loop
+	SUB  $4, R3		// n -= 4
+	BLT v1			// if n < 0 goto v1
+
+U1:	// n >= 0
+	// regular loop body unrolled 4x
+	MOVD 0(R8)(R10*1), R5
+	MOVD 8(R8)(R10*1), R6
+	MOVD 16(R8)(R10*1), R7
+	MOVD 24(R8)(R10*1), R1
+	ADDC R4, R4		// restore CF
+	MOVD 0(R9)(R10*1), R11
+	ADDE R11, R5
+	MOVD 8(R9)(R10*1), R11
+	ADDE R11, R6
+	MOVD 16(R9)(R10*1), R11
+	ADDE R11, R7
+	MOVD 24(R9)(R10*1), R11
+	ADDE R11, R1
+	MOVD R0, R4
+	ADDE R4, R4		// save CF
+	NEG  R4, R4
+	MOVD R5, 0(R2)(R10*1)
+	MOVD R6, 8(R2)(R10*1)
+	MOVD R7, 16(R2)(R10*1)
+	MOVD R1, 24(R2)(R10*1)
+
+
+	ADD  $32, R10		// i += 4
+	SUB  $4,  R3		// n -= 4
+	BGE  U1			// if n >= 0 goto U1
+
+v1:	ADD  $4, R3		// n += 4
+	BLE E1			// if n <= 0 goto E1
+
+L1:	// n > 0
+	ADDC R4, R4		// restore CF
+	MOVD 0(R8)(R10*1), R5
+	MOVD 0(R9)(R10*1), R11
+	ADDE R11, R5
+	MOVD R5, 0(R2)(R10*1)
+	MOVD R0, R4
+	ADDE R4, R4		// save CF
+	NEG  R4, R4
+
+	ADD  $8, R10		// i++
+	SUB  $1, R3		// n--
+	BGT L1			// if n > 0 goto L1
+
+E1:	NEG  R4, R4
+	MOVD R4, c+72(FP)	// return c
+	RET
+
+// DI = R3, CX = R4, SI = r10, r8 = r8, r9=r9, r10 = r2 , r11 = r5, r12 = r6, r13 = r7, r14 = r1 (R0 set to 0) + use R11
+// func subVV(z, x, y []Word) (c Word)
+// (same as addVV except for SUBC/SUBE instead of ADDC/ADDE and label names)
+TEXT ·subVV(SB),NOSPLIT,$0
+	MOVD z_len+8(FP), R3
+	MOVD x+24(FP), R8
+	MOVD y+48(FP), R9
+	MOVD z+0(FP), R2
+
+	MOVD $0, R4		// c = 0
+	MOVD $0, R0		// make sure it's zero
+	MOVD $0, R10		// i = 0
+
+	// s/JL/JMP/ below to disable the unrolled loop
+	SUB  $4, R3		// n -= 4
+	BLT v1			// if n < 0 goto v1
+
+U1:	// n >= 0
+	// regular loop body unrolled 4x
+	MOVD 0(R8)(R10*1), R5
+	MOVD 8(R8)(R10*1), R6
+	MOVD 16(R8)(R10*1), R7
+	MOVD 24(R8)(R10*1), R1
+	MOVD R0, R11
+	SUBC R4, R11		// restore CF
+	MOVD 0(R9)(R10*1), R11
+	SUBE R11, R5
+	MOVD 8(R9)(R10*1), R11
+	SUBE R11, R6
+	MOVD 16(R9)(R10*1), R11
+	SUBE R11, R7
+	MOVD 24(R9)(R10*1), R11
+	SUBE R11, R1
+	MOVD R0, R4
+	SUBE R4, R4		// save CF
+	MOVD R5, 0(R2)(R10*1)
+	MOVD R6, 8(R2)(R10*1)
+	MOVD R7, 16(R2)(R10*1)
+	MOVD R1, 24(R2)(R10*1)
+
+
+	ADD  $32, R10		// i += 4
+	SUB  $4,  R3		// n -= 4
+	BGE  U1			// if n >= 0 goto U1
+
+v1:	ADD  $4, R3		// n += 4
+	BLE E1			// if n <= 0 goto E1
+
+L1:	// n > 0
+	MOVD R0, R11
+	SUBC R4, R11		// restore CF
+	MOVD 0(R8)(R10*1), R5
+	MOVD 0(R9)(R10*1), R11
+	SUBE R11, R5
+	MOVD R5, 0(R2)(R10*1)
+	MOVD R0, R4
+	SUBE R4, R4		// save CF
+
+	ADD  $8, R10		// i++
+	SUB  $1, R3		// n--
+	BGT L1			// if n > 0 goto L1
+
+E1:	NEG  R4, R4
+	MOVD R4, c+72(FP)	// return c
+	RET
+
+
+// func addVW(z, x []Word, y Word) (c Word)
+TEXT ·addVW(SB),NOSPLIT,$0
+//DI = R3, CX = R4, SI = r10, r8 = r8, r10 = r2 , r11 = r5, r12 = r6, r13 = r7, r14 = r1 (R0 set to 0)
+	MOVD z_len+8(FP), R3
+	MOVD x+24(FP), R8
+	MOVD y+48(FP), R4	// c = y
+	MOVD z+0(FP), R2
+	MOVD $0, R0		// make sure it's 0
+	MOVD $0, R10		// i = 0
+
+	// s/JL/JMP/ below to disable the unrolled loop
+	SUB $4, R3		// n -= 4
+	BLT v4			// if n < 4 goto v4
+
+U4:	// n >= 0
+	// regular loop body unrolled 4x
+	MOVD 0(R8)(R10*1), R5
+	MOVD 8(R8)(R10*1), R6
+	MOVD 16(R8)(R10*1), R7
+	MOVD 24(R8)(R10*1), R1
+	ADDC R4, R5
+	ADDE R0, R6
+	ADDE R0, R7
+	ADDE R0, R1
+	ADDE R0, R0
+	MOVD R0, R4		// save CF
+	SUB  R0, R0
+	MOVD R5, 0(R2)(R10*1)
+	MOVD R6, 8(R2)(R10*1)
+	MOVD R7, 16(R2)(R10*1)
+	MOVD R1, 24(R2)(R10*1)
+
+	ADD $32, R10		// i += 4 -> i +=32
+	SUB $4, R3		// n -= 4
+	BGE U4			// if n >= 0 goto U4
+
+v4:	ADD $4, R3		// n += 4
+	BLE E4			// if n <= 0 goto E4
+
+L4:	// n > 0
+	MOVD 0(R8)(R10*1), R5
+	ADDC R4, R5
+	ADDE R0, R0
+	MOVD R0, R4		// save CF
+	SUB  R0, R0
+	MOVD R5, 0(R2)(R10*1)
+
+	ADD  $8, R10		// i++
+	SUB  $1, R3		// n--
+	BGT L4			// if n > 0 goto L4
+
+E4:	MOVD R4, c+56(FP)	// return c
+
+	RET
+
+//DI = R3, CX = R4, SI = r10, r8 = r8, r10 = r2 , r11 = r5, r12 = r6, r13 = r7, r14 = r1 (R0 set to 0)
+// func subVW(z, x []Word, y Word) (c Word)
+// (same as addVW except for SUBC/SUBE instead of ADDC/ADDE and label names)
+TEXT ·subVW(SB),NOSPLIT,$0
+	MOVD z_len+8(FP), R3
+	MOVD x+24(FP), R8
+	MOVD y+48(FP), R4	// c = y
+	MOVD z+0(FP), R2
+	MOVD $0, R0		// make sure it's 0
+	MOVD $0, R10		// i = 0
+
+	// s/JL/JMP/ below to disable the unrolled loop
+	SUB $4, R3		// n -= 4
+	BLT v4			// if n < 4 goto v4
+
+U4:	// n >= 0
+	// regular loop body unrolled 4x
+	MOVD 0(R8)(R10*1), R5
+	MOVD 8(R8)(R10*1), R6
+	MOVD 16(R8)(R10*1), R7
+	MOVD 24(R8)(R10*1), R1
+	SUBC R4, R5 //SLGR  -> SUBC
+	SUBE R0, R6 //SLBGR -> SUBE
+	SUBE R0, R7
+	SUBE R0, R1
+	SUBE R4, R4		// save CF
+	NEG  R4, R4
+	MOVD R5, 0(R2)(R10*1)
+	MOVD R6, 8(R2)(R10*1)
+	MOVD R7, 16(R2)(R10*1)
+	MOVD R1, 24(R2)(R10*1)
+
+	ADD $32, R10		// i += 4 -> i +=32
+	SUB $4, R3		// n -= 4
+	BGE U4			// if n >= 0 goto U4
+
+v4:	ADD $4, R3		// n += 4
+	BLE E4			// if n <= 0 goto E4
+
+L4:	// n > 0
+	MOVD 0(R8)(R10*1), R5
+	SUBC R4, R5
+	SUBE R4, R4		// save CF
+	NEG  R4, R4
+	MOVD R5, 0(R2)(R10*1)
+
+	ADD  $8, R10		// i++
+	SUB  $1, R3		// n--
+	BGT L4			// if n > 0 goto L4
+
+E4:	MOVD R4, c+56(FP)	// return c
+
+	RET
+
+// func shlVU(z, x []Word, s uint) (c Word)
+TEXT ·shlVU(SB),NOSPLIT,$0
+	MOVD z_len+8(FP), R5
+	SUB  $1, R5             // n--
+	BLT  X8b                // n < 0        (n <= 0)
+
+	// n > 0
+	MOVD s+48(FP), R4
+	CMPBEQ	R0, R4, Z80	       //handle 0 case beq
+	MOVD $64, R6
+	CMPBEQ  R6, R4, Z864	       //handle 64 case beq
+	MOVD z+0(FP), R2
+	MOVD x+24(FP), R8
+	SLD  $3, R5             // n = n*8
+	SUB  R4, R6, R7
+	MOVD (R8)(R5*1), R10    // w1 = x[i-1]
+	SRD  R7, R10, R3
+	MOVD R3, c+56(FP)
+
+	MOVD $0, R1             // i = 0
+	BR   E8
+
+	// i < n-1
+L8:	MOVD R10, R3             // w = w1
+	MOVD -8(R8)(R5*1), R10   // w1 = x[i+1]
+
+	SLD  R4,  R3             // w<<s | w1>>ŝ
+	SRD  R7, R10, R6
+	OR   R6, R3
+	MOVD R3, (R2)(R5*1)      // z[i] = w<<s | w1>>ŝ
+	SUB  $8, R5              // i--
+
+E8:	CMPBGT R5, R0, L8        // i < n-1
+
+	// i >= n-1
+X8a:	SLD  R4, R10             // w1<<s
+	MOVD R10, (R2)           // z[0] = w1<<s
+	RET
+
+X8b:	MOVD R0, c+56(FP)
+	RET
+
+Z80:	MOVD z+0(FP), R2
+	MOVD x+24(FP), R8
+	SLD  $3, R5             // n = n*8
+
+	MOVD (R8), R10
+	MOVD $0, R3
+	MOVD R3, c+56(FP)
+
+	MOVD $0, R1             // i = 0
+	BR   E8Z
+
+	// i < n-1
+L8Z:	MOVD R10, R3
+	MOVD 8(R8)(R1*1), R10
+
+	MOVD R3, (R2)(R1*1)
+	ADD  $8, R1
+
+E8Z:	CMPBLT R1, R5, L8Z
+
+	// i >= n-1
+	MOVD R10, (R2)(R5*1)
+	RET
+
+Z864:	MOVD z+0(FP), R2
+	MOVD x+24(FP), R8
+	SLD  $3, R5             // n = n*8
+	MOVD (R8)(R5*1), R3     // w1 = x[n-1]
+	MOVD R3, c+56(FP)       // z[i] = x[n-1]
+
+	BR   E864
+
+	// i < n-1
+L864:	MOVD -8(R8)(R5*1), R3
+
+	MOVD R3, (R2)(R5*1)     // z[i] = x[n-1]
+	SUB  $8, R5             // i--
+
+E864:	CMPBGT R5, R0, L864     // i < n-1
+
+	MOVD R0, (R2)           // z[n-1] = 0
+	RET
+
+
+// CX = R4, r8 = r8, r10 = r2 , r11 = r5, DX = r3, AX = r10 , BX = R1 , 64-count = r7 (R0 set to 0) temp = R6
+// func shrVU(z, x []Word, s uint) (c Word)
+TEXT ·shrVU(SB),NOSPLIT,$0
+	MOVD z_len+8(FP), R5
+	SUB  $1, R5             // n--
+	BLT  X9b                // n < 0        (n <= 0)
+
+	// n > 0
+	MOVD s+48(FP), R4
+	CMPBEQ	R0, R4, ZB0	       //handle 0 case beq
+	MOVD $64, R6
+	CMPBEQ  R6, R4, ZB64	       //handle 64 case beq
+	MOVD z+0(FP), R2
+	MOVD x+24(FP), R8
+	SLD  $3, R5             // n = n*8
+	SUB  R4, R6, R7
+	MOVD (R8), R10          // w1 = x[0]
+	SLD  R7, R10, R3
+	MOVD R3, c+56(FP)
+
+	MOVD $0, R1            // i = 0
+	BR   E9
+
+	// i < n-1
+L9:	MOVD R10, R3            // w = w1
+	MOVD 8(R8)(R1*1), R10   // w1 = x[i+1]
+
+	SRD  R4,  R3            // w>>s | w1<<s
+	SLD  R7, R10, R6
+	OR   R6, R3
+	MOVD R3, (R2)(R1*1)     // z[i] = w>>s | w1<<s
+	ADD  $8, R1             // i++
+
+E9:	CMPBLT R1, R5, L9       // i < n-1
+
+	// i >= n-1
+X9a:	SRD  R4, R10            // w1>>s
+	MOVD R10, (R2)(R5*1)    // z[n-1] = w1>>s
+	RET
+
+X9b:	MOVD R0, c+56(FP)
+	RET
+
+ZB0:	MOVD z+0(FP), R2
+	MOVD x+24(FP), R8
+	SLD  $3, R5             // n = n*8
+
+	MOVD (R8), R10          // w1 = x[0]
+	MOVD $0, R3             // R10 << 64
+	MOVD R3, c+56(FP)
+
+	MOVD $0, R1             // i = 0
+	BR   E9Z
+
+	// i < n-1
+L9Z:	MOVD R10, R3            // w = w1
+	MOVD 8(R8)(R1*1), R10   // w1 = x[i+1]
+
+	MOVD R3, (R2)(R1*1)     // z[i] = w>>s | w1<<s
+	ADD  $8, R1             // i++
+
+E9Z:	CMPBLT R1, R5, L9Z      // i < n-1
+
+	// i >= n-1
+	MOVD R10, (R2)(R5*1)    // z[n-1] = w1>>s
+	RET
+
+ZB64:	MOVD z+0(FP), R2
+	MOVD x+24(FP), R8
+	SLD  $3, R5             // n = n*8
+	MOVD (R8), R3          // w1 = x[0]
+	MOVD R3, c+56(FP)
+
+	MOVD $0, R1            // i = 0
+	BR   E964
+
+	// i < n-1
+L964:	MOVD 8(R8)(R1*1), R3   // w1 = x[i+1]
+
+	MOVD R3, (R2)(R1*1)     // z[i] = w>>s | w1<<s
+	ADD  $8, R1             // i++
+
+E964:	CMPBLT R1, R5, L964     // i < n-1
+
+	// i >= n-1
+	MOVD  $0, R10            // w1>>s
+	MOVD R10, (R2)(R5*1)    // z[n-1] = w1>>s
+	RET
+
+// CX = R4, r8 = r8, r9=r9, r10 = r2 , r11 = r5, DX = r3, AX = r6 , BX = R1 , (R0 set to 0) + use R11 + use R7 for i
+// func mulAddVWW(z, x []Word, y, r Word) (c Word)
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+	MOVD z+0(FP), R2
+	MOVD x+24(FP), R8
+	MOVD y+48(FP), R9
+	MOVD r+56(FP), R4	// c = r
+	MOVD z_len+8(FP), R5
+	MOVD $0, R1		// i = 0
+	MOVD $0, R7		// i*8 = 0
+	MOVD $0, R0		// make sure it's zero
+	BR E5
+
+L5:	MOVD (R8)(R1*1), R6
+	MULHDU R9, R6
+	ADDC R4, R11 		//add to low order bits
+	ADDE R0, R6
+	MOVD R11, (R2)(R1*1)
+	MOVD R6, R4
+	ADD  $8, R1		// i*8 + 8
+	ADD  $1, R7		// i++
+
+E5:	CMPBLT R7, R5, L5	// i < n
+
+	MOVD R4, c+64(FP)
+	RET
+
+// func addMulVVW(z, x []Word, y Word) (c Word)
+// CX = R4, r8 = r8, r9=r9, r10 = r2 , r11 = r5, AX = r11, DX = R6, r12=r12, BX = R1 , (R0 set to 0) + use R11 + use R7 for i
+TEXT ·addMulVVW(SB),NOSPLIT,$0
+	MOVD z+0(FP), R2
+	MOVD x+24(FP), R8
+	MOVD y+48(FP), R9
+	MOVD z_len+8(FP), R5
+
+	MOVD $0, R1		// i*8 = 0
+	MOVD $0, R7		// i = 0
+	MOVD $0, R0		// make sure it's zero
+	MOVD $0, R4		// c = 0
+
+	MOVD R5, R12
+	AND  $-2, R12
+	CMPBGE R5, $2, A6
+	BR   E6
+
+A6:	MOVD (R8)(R1*1), R6
+	MULHDU R9, R6
+	MOVD (R2)(R1*1), R10
+	ADDC R10, R11	//add to low order bits
+	ADDE R0, R6
+	ADDC R4, R11
+	ADDE R0, R6
+	MOVD R6, R4
+	MOVD R11, (R2)(R1*1)
+
+	MOVD (8)(R8)(R1*1), R6
+	MULHDU R9, R6
+	MOVD (8)(R2)(R1*1), R10
+	ADDC R10, R11	//add to low order bits
+	ADDE R0, R6
+	ADDC R4, R11
+	ADDE R0, R6
+	MOVD R6, R4
+	MOVD R11, (8)(R2)(R1*1)
+
+	ADD  $16, R1		// i*8 + 8
+	ADD  $2, R7		// i++
+
+	CMPBLT R7, R12, A6
+	BR E6
+
+L6:	MOVD (R8)(R1*1), R6
+	MULHDU R9, R6
+	MOVD (R2)(R1*1), R10
+	ADDC R10, R11	//add to low order bits
+	ADDE R0, R6
+	ADDC R4, R11
+	ADDE R0, R6
+	MOVD R6, R4
+	MOVD R11, (R2)(R1*1)
+
+	ADD  $8, R1		// i*8 + 8
+	ADD  $1, R7		// i++
+
+E6:	CMPBLT R7, R5, L6	// i < n
+
+	MOVD R4, c+56(FP)
+	RET
+
+// func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
+// CX = R4, r8 = r8, r9=r9, r10 = r2 , r11 = r5, AX = r11, DX = R6, r12=r12, BX = R1(*8) , (R0 set to 0) + use R11 + use R7 for i
+TEXT ·divWVW(SB),NOSPLIT,$0
+	MOVD z+0(FP), R2
+	MOVD xn+24(FP), R10	// r = xn
+	MOVD x+32(FP), R8
+	MOVD y+56(FP), R9
+	MOVD z_len+8(FP), R7	// i = z
+	SLD  $3, R7, R1		// i*8
+	MOVD $0, R0		// make sure it's zero
+	BR E7
+
+L7:	MOVD (R8)(R1*1), R11
+	WORD $0xB98700A9  //DLGR R10,R9
+	MOVD R11, (R2)(R1*1)
+
+E7:	SUB  $1, R7		// i--
+	SUB  $8, R1
+	BGE L7			// i >= 0
+
+	MOVD R10, r+64(FP)
+	RET
+
+// func bitLen(x Word) (n int)
+TEXT ·bitLen(SB),NOSPLIT,$0
+	MOVD x+0(FP), R2
+	WORD $0xb9830022 // FLOGR R2,R2
+	MOVD $64, R3
+	SUB  R2, R3
+	MOVD R3, n+8(FP)
+	RET
diff --git a/src/math/big/arith_test.go b/src/math/big/arith_test.go
index f46a494..75862b4 100644
--- a/src/math/big/arith_test.go
+++ b/src/math/big/arith_test.go
@@ -5,6 +5,7 @@
 package big
 
 import (
+	"fmt"
 	"math/rand"
 	"testing"
 )
@@ -118,28 +119,22 @@ func rndV(n int) []Word {
 	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)
+var benchSizes = []int{1, 2, 3, 4, 5, 1e1, 1e2, 1e3, 1e4, 1e5}
+
+func BenchmarkAddVV(b *testing.B) {
+	for _, n := range benchSizes {
+		x := rndV(n)
+		y := rndV(n)
+		z := make([]Word, n)
+		b.Run(fmt.Sprint(n), func(b *testing.B) {
+			b.SetBytes(int64(n * _W))
+			for i := 0; i < b.N; i++ {
+				addVV(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
@@ -158,21 +153,6 @@ var sumVW = []argVW{
 	{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},
@@ -251,28 +231,20 @@ func TestFunVW(t *testing.T) {
 	}
 }
 
-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(b *testing.B) {
+	for _, n := range benchSizes {
+		x := rndV(n)
+		y := rndW()
+		z := make([]Word, n)
+		b.Run(fmt.Sprint(n), func(b *testing.B) {
+			b.SetBytes(int64(n * _S))
+			for i := 0; i < b.N; i++ {
+				addVW(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
@@ -397,28 +369,20 @@ func TestMulAddWWW(t *testing.T) {
 	}
 }
 
-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(b *testing.B) {
+	for _, n := range benchSizes {
+		x := rndV(n)
+		y := rndW()
+		z := make([]Word, n)
+		b.Run(fmt.Sprint(n), func(b *testing.B) {
+			b.SetBytes(int64(n * _W))
+			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
@@ -435,23 +399,15 @@ func TestWordBitLen(t *testing.T) {
 }
 
 // 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)
+func BenchmarkBitLen(b *testing.B) {
+	// Individual bitLen tests. Numbers chosen to examine both sides
+	// of powers-of-two boundaries.
+	for _, nbits := range []uint{0, 1, 2, 3, 4, 5, 8, 9, 16, 17, 31} {
+		testword := Word((uint64(1) << nbits) - 1)
+		b.Run(fmt.Sprint(nbits), func(b *testing.B) {
+			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/math/big/float.go b/src/math/big/float.go
index b1c748c..7a9c2b3 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -392,15 +392,13 @@ func (z *Float) round(sbit uint) {
 	// 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
+	bits := m * _W           // present mantissa bits; bits > 0
 	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
@@ -415,111 +413,77 @@ func (z *Float) round(sbit uint) {
 
 	// 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
+	rbit := z.mant.bit(r) & 1    // rounding bit; be safe and ensure it's a single bit
 	if sbit == 0 {
+		// TODO(gri) if rbit != 0 we don't need to compute sbit for some rounding modes (optimization)
 		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
-		}
-	}
+	sbit &= 1 // be safe and ensure it's a single bit
 
 	// cut off extra words
+	n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision
 	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
+	// determine number of trailing zero bits (ntz) and compute lsb mask of mantissa's least-significant word
+	ntz := n*_W - z.prec // 0 <= ntz < _W
+	lsb := Word(1) << ntz
+
+	// round if result is inexact
+	if rbit|sbit != 0 {
+		// Make rounding decision: The result mantissa is truncated ("rounded down")
+		// by default. Decide if we need to increment, or "round up", the (unsigned)
+		// mantissa.
+		inc := false
+		switch z.mode {
+		case ToNegativeInf:
+			inc = z.neg
+		case ToZero:
+			// nothing to do
+		case ToNearestEven:
+			inc = rbit != 0 && (sbit != 0 || z.mant[0]&lsb != 0)
+		case ToNearestAway:
+			inc = rbit != 0
+		case AwayFromZero:
+			inc = true
+		case ToPositiveInf:
+			inc = !z.neg
+		default:
+			panic("unreachable")
 		}
 
-	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 {
+		// A positive result (!z.neg) is Above the exact result if we increment,
+		// and it's Below if we truncate (Exact results require no rounding).
+		// For a negative result (z.neg) it is exactly the opposite.
+		z.acc = makeAcc(inc != z.neg)
+
+		if inc {
+			// add 1 to mantissa
+			if addVW(z.mant, z.mant, lsb) != 0 {
+				// mantissa overflow => adjust exponent
+				if z.exp >= MaxExp {
+					// exponent overflow
+					z.form = inf
+					return
+				}
 				z.exp++
-			} else {
-				// exponent overflow
-				z.acc = makeAcc(!z.neg)
-				z.form = inf
-				return
+				// adjust mantissa: divide by 2 to compensate for exponent adjustment
+				shrVU(z.mant, z.mant, 1)
+				// set msb == carry == 1 from the mantissa overflow above
+				const msb = 1 << (_W - 1)
+				z.mant[n-1] |= msb
 			}
 		}
-		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 {
@@ -874,21 +838,43 @@ func (x *Float) Float32() (float32, Accuracy) {
 			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
+		// Float mantissa m is 0.5 <= m < 1.0; compute exponent e for float32 mantissa.
+		e := x.exp - 1 // exponent for normal mantissa m with 1.0 <= m < 2.0
 
-		// If the exponent is too small, we may have a denormal number
-		// in which case we have fewer mantissa bits available: reduce
-		// precision accordingly.
+		// Compute precision p for float32 mantissa.
+		// If the exponent is too small, we have a denormal number before
+		// rounding and fewer than p mantissa bits of precision available
+		// (the exponent remains fixed but the mantissa gets shifted right).
+		p := mbits + 1 // precision of normal float
 		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
+			// recompute precision
+			p = mbits + 1 - emin + int(e)
+			// If p == 0, the mantissa of x is shifted so much to the right
+			// that its msb falls immediately to the right of the float32
+			// mantissa space. In other words, if the smallest denormal is
+			// considered "1.0", for p == 0, the mantissa value m is >= 0.5.
+			// If m > 0.5, it is rounded up to 1.0; i.e., the smallest denormal.
+			// If m == 0.5, it is rounded down to even, i.e., 0.0.
+			// If p < 0, the mantissa value m is <= "0.25" which is never rounded up.
+			if p < 0 /* m <= 0.25 */ || p == 0 && x.mant.sticky(uint(len(x.mant))*_W-1) == 0 /* m == 0.5 */ {
+				// underflow to ±0
+				if x.neg {
+					var z float32
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// otherwise, round up
+			// We handle p == 0 explicitly because it's easy and because
+			// Float.round doesn't support rounding to 0 bits of precision.
+			if p == 0 {
+				if x.neg {
+					return -math.SmallestNonzeroFloat32, Below
+				}
+				return math.SmallestNonzeroFloat32, Above
 			}
 		}
+		// p > 0
 
 		// round
 		var r Float
@@ -898,12 +884,8 @@ func (x *Float) Float32() (float32, Accuracy) {
 
 		// 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 {
+		// If the exponent is too large, also overflow to ±Inf.
+		if r.form == inf || e > emax {
 			// overflow
 			if x.neg {
 				return float32(math.Inf(-1)), Below
@@ -921,17 +903,12 @@ func (x *Float) Float32() (float32, Accuracy) {
 		// 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)
+			// denormal number: recompute precision
+			// Since rounding may have at best increased precision
+			// and we have eliminated p <= 0 early, we know p > 0.
+			// bexp == 0 for denormals
+			p = mbits + 1 - emin + int(e)
+			mant = msb32(r.mant) >> uint(fbits-p)
 		} else {
 			// normal number: emin <= e <= emax
 			bexp = uint32(e+bias) << mbits
@@ -981,21 +958,43 @@ func (x *Float) Float64() (float64, Accuracy) {
 			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
+		// Float mantissa m is 0.5 <= m < 1.0; compute exponent e for float64 mantissa.
+		e := x.exp - 1 // exponent for normal mantissa m with 1.0 <= m < 2.0
 
-		// If the exponent is too small, we may have a denormal number
-		// in which case we have fewer mantissa bits available: reduce
-		// precision accordingly.
+		// Compute precision p for float64 mantissa.
+		// If the exponent is too small, we have a denormal number before
+		// rounding and fewer than p mantissa bits of precision available
+		// (the exponent remains fixed but the mantissa gets shifted right).
+		p := mbits + 1 // precision of normal float
 		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
+			// recompute precision
+			p = mbits + 1 - emin + int(e)
+			// If p == 0, the mantissa of x is shifted so much to the right
+			// that its msb falls immediately to the right of the float64
+			// mantissa space. In other words, if the smallest denormal is
+			// considered "1.0", for p == 0, the mantissa value m is >= 0.5.
+			// If m > 0.5, it is rounded up to 1.0; i.e., the smallest denormal.
+			// If m == 0.5, it is rounded down to even, i.e., 0.0.
+			// If p < 0, the mantissa value m is <= "0.25" which is never rounded up.
+			if p < 0 /* m <= 0.25 */ || p == 0 && x.mant.sticky(uint(len(x.mant))*_W-1) == 0 /* m == 0.5 */ {
+				// underflow to ±0
+				if x.neg {
+					var z float64
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// otherwise, round up
+			// We handle p == 0 explicitly because it's easy and because
+			// Float.round doesn't support rounding to 0 bits of precision.
+			if p == 0 {
+				if x.neg {
+					return -math.SmallestNonzeroFloat64, Below
+				}
+				return math.SmallestNonzeroFloat64, Above
 			}
 		}
+		// p > 0
 
 		// round
 		var r Float
@@ -1005,12 +1004,8 @@ func (x *Float) Float64() (float64, Accuracy) {
 
 		// 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 {
+		// If the exponent is too large, also overflow to ±Inf.
+		if r.form == inf || e > emax {
 			// overflow
 			if x.neg {
 				return math.Inf(-1), Below
@@ -1028,17 +1023,12 @@ func (x *Float) Float64() (float64, Accuracy) {
 		// 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)
+			// denormal number: recompute precision
+			// Since rounding may have at best increased precision
+			// and we have eliminated p <= 0 early, we know p > 0.
+			// bexp == 0 for denormals
+			p = mbits + 1 - emin + int(e)
+			mant = msb64(r.mant) >> uint(fbits-p)
 		} else {
 			// normal number: emin <= e <= emax
 			bexp = uint64(e+bias) << mbits
@@ -1427,7 +1417,7 @@ func (z *Float) Add(x, y *Float) *Float {
 	}
 
 	if x.form == finite && y.form == finite {
-		// x + y (commom case)
+		// x + y (common case)
 		z.neg = x.neg
 		if x.neg == y.neg {
 			// x + y == x + y
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
index d3b214b..464619b 100644
--- a/src/math/big/float_test.go
+++ b/src/math/big/float_test.go
@@ -829,7 +829,7 @@ func TestFloatFloat32(t *testing.T) {
 	}{
 		{"0", 0, Exact},
 
-		// underflow
+		// underflow to zero
 		{"1e-1000", 0, Below},
 		{"0x0.000002p-127", 0, Below},
 		{"0x.0000010p-126", 0, Below},
@@ -843,6 +843,46 @@ func TestFloatFloat32(t *testing.T) {
 		{"1p-149", math.SmallestNonzeroFloat32, Exact},
 		{"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal
 
+		// special denormal cases (see issues 14553, 14651)
+		{"0x0.0000001p-126", math.Float32frombits(0x00000000), Below}, // underflow to zero
+		{"0x0.0000008p-126", math.Float32frombits(0x00000000), Below}, // underflow to zero
+		{"0x0.0000010p-126", math.Float32frombits(0x00000000), Below}, // rounded down to even
+		{"0x0.0000011p-126", math.Float32frombits(0x00000001), Above}, // rounded up to smallest denormal
+		{"0x0.0000018p-126", math.Float32frombits(0x00000001), Above}, // rounded up to smallest denormal
+
+		{"0x1.0000000p-149", math.Float32frombits(0x00000001), Exact}, // smallest denormal
+		{"0x0.0000020p-126", math.Float32frombits(0x00000001), Exact}, // smallest denormal
+		{"0x0.fffffe0p-126", math.Float32frombits(0x007fffff), Exact}, // largest denormal
+		{"0x1.0000000p-126", math.Float32frombits(0x00800000), Exact}, // smallest normal
+
+		{"0x0.8p-149", math.Float32frombits(0x000000000), Below}, // rounded down to even
+		{"0x0.9p-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+		{"0x0.ap-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+		{"0x0.bp-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+		{"0x0.cp-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
+
+		{"0x1.0p-149", math.Float32frombits(0x000000001), Exact}, // smallest denormal
+		{"0x1.7p-149", math.Float32frombits(0x000000001), Below},
+		{"0x1.8p-149", math.Float32frombits(0x000000002), Above},
+		{"0x1.9p-149", math.Float32frombits(0x000000002), Above},
+
+		{"0x2.0p-149", math.Float32frombits(0x000000002), Exact},
+		{"0x2.8p-149", math.Float32frombits(0x000000002), Below}, // rounded down to even
+		{"0x2.9p-149", math.Float32frombits(0x000000003), Above},
+
+		{"0x3.0p-149", math.Float32frombits(0x000000003), Exact},
+		{"0x3.7p-149", math.Float32frombits(0x000000003), Below},
+		{"0x3.8p-149", math.Float32frombits(0x000000004), Above}, // rounded up to even
+
+		{"0x4.0p-149", math.Float32frombits(0x000000004), Exact},
+		{"0x4.8p-149", math.Float32frombits(0x000000004), Below}, // rounded down to even
+		{"0x4.9p-149", math.Float32frombits(0x000000005), Above},
+
+		// specific case from issue 14553
+		{"0x7.7p-149", math.Float32frombits(0x000000007), Below},
+		{"0x7.8p-149", math.Float32frombits(0x000000008), Above},
+		{"0x7.9p-149", math.Float32frombits(0x000000008), Above},
+
 		// normals
 		{"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal
 		{"1p-126", math.Float32frombits(0x00800000), Exact},         // smallest normal
@@ -881,7 +921,7 @@ func TestFloatFloat32(t *testing.T) {
 			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)
+				t.Errorf("%s: got %g (%#08x, %s); want %g (%#08x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
 			}
 
 			// test that x.SetFloat64(float64(f)).Float32() == f
@@ -903,18 +943,48 @@ func TestFloatFloat64(t *testing.T) {
 	}{
 		{"0", 0, Exact},
 
-		// underflow
+		// underflow to zero
 		{"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
+		{"0x0.00000000000010p-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
 
+		// special denormal cases (see issues 14553, 14651)
+		{"0x0.00000000000001p-1022", math.Float64frombits(0x00000000000000000), Below}, // underflow to zero
+		{"0x0.00000000000004p-1022", math.Float64frombits(0x00000000000000000), Below}, // underflow to zero
+		{"0x0.00000000000008p-1022", math.Float64frombits(0x00000000000000000), Below}, // rounded down to even
+		{"0x0.00000000000009p-1022", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+		{"0x0.0000000000000ap-1022", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+
+		{"0x0.8p-1074", math.Float64frombits(0x00000000000000000), Below}, // rounded down to even
+		{"0x0.9p-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+		{"0x0.ap-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+		{"0x0.bp-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+		{"0x0.cp-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
+
+		{"0x1.0p-1074", math.Float64frombits(0x00000000000000001), Exact},
+		{"0x1.7p-1074", math.Float64frombits(0x00000000000000001), Below},
+		{"0x1.8p-1074", math.Float64frombits(0x00000000000000002), Above},
+		{"0x1.9p-1074", math.Float64frombits(0x00000000000000002), Above},
+
+		{"0x2.0p-1074", math.Float64frombits(0x00000000000000002), Exact},
+		{"0x2.8p-1074", math.Float64frombits(0x00000000000000002), Below}, // rounded down to even
+		{"0x2.9p-1074", math.Float64frombits(0x00000000000000003), Above},
+
+		{"0x3.0p-1074", math.Float64frombits(0x00000000000000003), Exact},
+		{"0x3.7p-1074", math.Float64frombits(0x00000000000000003), Below},
+		{"0x3.8p-1074", math.Float64frombits(0x00000000000000004), Above}, // rounded up to even
+
+		{"0x4.0p-1074", math.Float64frombits(0x00000000000000004), Exact},
+		{"0x4.8p-1074", math.Float64frombits(0x00000000000000004), Below}, // rounded down to even
+		{"0x4.9p-1074", math.Float64frombits(0x00000000000000005), Above},
+
 		// normals
 		{"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal
 		{"1p-1022", math.Float64frombits(0x0010000000000000), Exact},                 // smallest normal
@@ -958,7 +1028,7 @@ func TestFloatFloat64(t *testing.T) {
 			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)
+				t.Errorf("%s: got %g (%#016x, %s); want %g (%#016x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
 			}
 
 			// test that x.SetFloat64(f).Float64() == f
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
index 37d5c06..a884df6 100644
--- a/src/math/big/floatconv.go
+++ b/src/math/big/floatconv.go
@@ -85,7 +85,7 @@ func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
 	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.
+		// Adjust relevant exponent accordingly.
 		d := int64(fcount)
 		switch b {
 		case 10:
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
index b6f9993..b2a1ab0 100644
--- a/src/math/big/floatconv_test.go
+++ b/src/math/big/floatconv_test.go
@@ -290,6 +290,11 @@ func TestFloat64Text(t *testing.T) {
 		// Issue 2625.
 		{383260575764816448, 'f', 0, "383260575764816448"},
 		{383260575764816448, 'g', -1, "3.8326057576481645e+17"},
+
+		// Issue 15918.
+		{1, 'f', -10, "1"},
+		{1, 'f', -11, "1"},
+		{1, 'f', -12, "1"},
 	} {
 		// The test cases are from the strconv package which tests float64 values.
 		// When formatting values with prec = -1 (shortest representation),
diff --git a/src/math/big/floatmarsh.go b/src/math/big/floatmarsh.go
index 44987ee..3725d4b 100644
--- a/src/math/big/floatmarsh.go
+++ b/src/math/big/floatmarsh.go
@@ -6,7 +6,94 @@
 
 package big
 
-import "fmt"
+import (
+	"encoding/binary"
+	"fmt"
+)
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const floatGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+// The Float value and all its attributes (precision,
+// rounding mode, accuracy) are marshalled.
+func (x *Float) GobEncode() ([]byte, error) {
+	if x == nil {
+		return nil, nil
+	}
+
+	// determine max. space (bytes) required for encoding
+	sz := 1 + 1 + 4 // version + mode|acc|form|neg (3+2+2+1bit) + prec
+	n := 0          // number of mantissa words
+	if x.form == finite {
+		// add space for mantissa and exponent
+		n = int((x.prec + (_W - 1)) / _W) // required mantissa length in words for given precision
+		// actual mantissa slice could be shorter (trailing 0's) or longer (unused bits):
+		// - if shorter, only encode the words present
+		// - if longer, cut off unused words when encoding in bytes
+		//   (in practice, this should never happen since rounding
+		//   takes care of it, but be safe and do it always)
+		if len(x.mant) < n {
+			n = len(x.mant)
+		}
+		// len(x.mant) >= n
+		sz += 4 + n*_S // exp + mant
+	}
+	buf := make([]byte, sz)
+
+	buf[0] = floatGobVersion
+	b := byte(x.mode&7)<<5 | byte((x.acc+1)&3)<<3 | byte(x.form&3)<<1
+	if x.neg {
+		b |= 1
+	}
+	buf[1] = b
+	binary.BigEndian.PutUint32(buf[2:], x.prec)
+
+	if x.form == finite {
+		binary.BigEndian.PutUint32(buf[6:], uint32(x.exp))
+		x.mant[len(x.mant)-n:].bytes(buf[10:]) // cut off unused trailing words
+	}
+
+	return buf, nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+// The result is rounded per the precision and rounding mode of
+// z unless z's precision is 0, in which case z is set exactly
+// to the decoded value.
+func (z *Float) GobDecode(buf []byte) error {
+	if len(buf) == 0 {
+		// Other side sent a nil or default value.
+		*z = Float{}
+		return nil
+	}
+
+	if buf[0] != floatGobVersion {
+		return fmt.Errorf("Float.GobDecode: encoding version %d not supported", buf[0])
+	}
+
+	oldPrec := z.prec
+	oldMode := z.mode
+
+	b := buf[1]
+	z.mode = RoundingMode((b >> 5) & 7)
+	z.acc = Accuracy((b>>3)&3) - 1
+	z.form = form((b >> 1) & 3)
+	z.neg = b&1 != 0
+	z.prec = binary.BigEndian.Uint32(buf[2:])
+
+	if z.form == finite {
+		z.exp = int32(binary.BigEndian.Uint32(buf[6:]))
+		z.mant = z.mant.setBytes(buf[10:])
+	}
+
+	if oldPrec != 0 {
+		z.mode = oldMode
+		z.SetPrec(uint(oldPrec))
+	}
+
+	return nil
+}
 
 // MarshalText implements the encoding.TextMarshaler interface.
 // Only the Float value is marshaled (in full precision), other
diff --git a/src/math/big/floatmarsh_test.go b/src/math/big/floatmarsh_test.go
index d7ef2fc..5bd906d 100644
--- a/src/math/big/floatmarsh_test.go
+++ b/src/math/big/floatmarsh_test.go
@@ -5,7 +5,10 @@
 package big
 
 import (
+	"bytes"
+	"encoding/gob"
 	"encoding/json"
+	"io"
 	"testing"
 )
 
@@ -23,6 +26,85 @@ var floatVals = []string{
 	"Inf",
 }
 
+func TestFloatGobEncoding(t *testing.T) {
+	var medium bytes.Buffer
+	enc := gob.NewEncoder(&medium)
+	dec := gob.NewDecoder(&medium)
+	for _, test := range floatVals {
+		for _, sign := range []string{"", "+", "-"} {
+			for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} {
+				for _, mode := range []RoundingMode{ToNearestEven, ToNearestAway, ToZero, AwayFromZero, ToNegativeInf, ToPositiveInf} {
+					medium.Reset() // empty buffer for each test case (in case of failures)
+					x := sign + test
+
+					var tx Float
+					_, _, err := tx.SetPrec(prec).SetMode(mode).Parse(x, 0)
+					if err != nil {
+						t.Errorf("parsing of %s (%dbits, %v) failed (invalid test case): %v", x, prec, mode, err)
+						continue
+					}
+
+					// If tx was set to prec == 0, tx.Parse(x, 0) assumes precision 64. Correct it.
+					if prec == 0 {
+						tx.SetPrec(0)
+					}
+
+					if err := enc.Encode(&tx); err != nil {
+						t.Errorf("encoding of %v (%dbits, %v) failed: %v", &tx, prec, mode, err)
+						continue
+					}
+
+					var rx Float
+					if err := dec.Decode(&rx); err != nil {
+						t.Errorf("decoding of %v (%dbits, %v) failed: %v", &tx, prec, mode, err)
+						continue
+					}
+
+					if rx.Cmp(&tx) != 0 {
+						t.Errorf("transmission of %s failed: got %s want %s", x, rx.String(), tx.String())
+						continue
+					}
+
+					if rx.Prec() != prec {
+						t.Errorf("transmission of %s's prec failed: got %d want %d", x, rx.Prec(), prec)
+					}
+
+					if rx.Mode() != mode {
+						t.Errorf("transmission of %s's mode failed: got %s want %s", x, rx.Mode(), mode)
+					}
+
+					if rx.Acc() != tx.Acc() {
+						t.Errorf("transmission of %s's accuracy failed: got %s want %s", x, rx.Acc(), tx.Acc())
+					}
+				}
+			}
+		}
+	}
+}
+
+func TestFloatCorruptGob(t *testing.T) {
+	var buf bytes.Buffer
+	tx := NewFloat(4 / 3).SetPrec(1000).SetMode(ToPositiveInf)
+	if err := gob.NewEncoder(&buf).Encode(tx); err != nil {
+		t.Fatal(err)
+	}
+	b := buf.Bytes()
+
+	var rx Float
+	if err := gob.NewDecoder(bytes.NewReader(b)).Decode(&rx); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := gob.NewDecoder(bytes.NewReader(b[:10])).Decode(&rx); err != io.ErrUnexpectedEOF {
+		t.Errorf("got %v want EOF", err)
+	}
+
+	b[1] = 0
+	if err := gob.NewDecoder(bytes.NewReader(b)).Decode(&rx); err == nil {
+		t.Fatal("got nil want version error")
+	}
+}
+
 func TestFloatJSONEncoding(t *testing.T) {
 	for _, test := range floatVals {
 		for _, sign := range []string{"", "+", "-"} {
diff --git a/src/math/big/ftoa.go b/src/math/big/ftoa.go
index c5cdb5e..57b16e1 100644
--- a/src/math/big/ftoa.go
+++ b/src/math/big/ftoa.go
@@ -41,8 +41,11 @@ import (
 // x.Prec() mantissa bits.
 // The prec value is ignored for the 'b' or 'p' format.
 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))
+	cap := 10 // TODO(gri) determine a good/better value here
+	if prec > 0 {
+		cap += prec
+	}
+	return string(x.Append(make([]byte, 0, cap), format, prec))
 }
 
 // String formats x like x.Text('g', 10).
@@ -333,9 +336,9 @@ func (x *Float) fmtB(buf []byte) []byte {
 	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.
+// 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,
+// and 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 {
@@ -374,12 +377,11 @@ func min(x, y int) int {
 }
 
 // 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'.
+// formats for floating-point numbers ('b', 'e', 'E', 'f', 'F',
+// 'g', 'G') as well as 'p' and 'v'. See (*Float).Text for the
+// interpretation of '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
+// in digits, the output field width, as well as the format flags
 // '+' and ' ' for sign control, '0' for space or zero padding,
 // and '-' for left or right justification. See the fmt package
 // for details.
diff --git a/src/math/big/gcd_test.go b/src/math/big/gcd_test.go
index c0b9f58..a929bf5 100644
--- a/src/math/big/gcd_test.go
+++ b/src/math/big/gcd_test.go
@@ -20,13 +20,27 @@ func randInt(r *rand.Rand, size uint) *Int {
 }
 
 func runGCD(b *testing.B, aSize, bSize uint) {
+	b.Run("WithoutXY", func(b *testing.B) {
+		runGCDExt(b, aSize, bSize, false)
+	})
+	b.Run("WithXY", func(b *testing.B) {
+		runGCDExt(b, aSize, bSize, true)
+	})
+}
+
+func runGCDExt(b *testing.B, aSize, bSize uint, calcXY bool) {
 	b.StopTimer()
 	var r = rand.New(rand.NewSource(1234))
 	aa := randInt(r, aSize)
 	bb := randInt(r, bSize)
+	var x, y *Int
+	if calcXY {
+		x = new(Int)
+		y = new(Int)
+	}
 	b.StartTimer()
 	for i := 0; i < b.N; i++ {
-		new(Int).GCD(nil, nil, aa, bb)
+		new(Int).GCD(x, y, aa, bb)
 	}
 }
 
diff --git a/src/math/big/int.go b/src/math/big/int.go
index 67ab704..f2a75d1 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -459,11 +459,11 @@ func (z *Int) GCD(x, y, a, b *Int) *Int {
 	q := new(Int)
 	temp := new(Int)
 
+	r := new(Int)
 	for len(B.abs) > 0 {
-		r := new(Int)
 		q, r = q.QuoRem(A, B, r)
 
-		A, B = B, r
+		A, B, r = B, r, A
 
 		temp.Set(X)
 		X.Mul(X, q)
diff --git a/src/math/big/intconv.go b/src/math/big/intconv.go
index 56a75f8..daf674a 100644
--- a/src/math/big/intconv.go
+++ b/src/math/big/intconv.go
@@ -52,16 +52,16 @@ func writeMultiple(s fmt.State, text string, count int) {
 	}
 }
 
-// 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).
+// Format implements 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.
+// flags 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 '-' for left or right
+// justification.
 //
 func (x *Int) Format(s fmt.State, ch rune) {
 	// determine base
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index 79cf6e0..2e65d2a 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -8,7 +8,10 @@
 
 package big
 
-import "math/rand"
+import (
+	"math/rand"
+	"sync"
+)
 
 // An unsigned integer x of the form
 //
@@ -539,6 +542,21 @@ func (z nat) div(z2, u, v nat) (q, r nat) {
 	return
 }
 
+// getNat returns a nat of len n. The contents may not be zero.
+func getNat(n int) nat {
+	var z nat
+	if v := natPool.Get(); v != nil {
+		z = v.(nat)
+	}
+	return z.make(n)
+}
+
+func putNat(x nat) {
+	natPool.Put(x)
+}
+
+var natPool sync.Pool
+
 // 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.
@@ -557,7 +575,7 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
 	}
 	q = z.make(m + 1)
 
-	qhatv := make(nat, n+1)
+	qhatv := getNat(n + 1)
 	if alias(u, uIn) || alias(u, v) {
 		u = nil // u is an alias for uIn or v - cannot reuse
 	}
@@ -565,10 +583,11 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
 	u.clear() // TODO(gri) no need to clear if we allocated a new u
 
 	// D1.
+	var v1 nat
 	shift := nlz(v[n-1])
 	if shift > 0 {
 		// do not modify v, it may be used by another goroutine simultaneously
-		v1 := make(nat, n)
+		v1 = getNat(n)
 		shlVU(v1, v, shift)
 		v = v1
 	}
@@ -609,6 +628,10 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
 
 		q[j] = qhat
 	}
+	if v1 != nil {
+		putNat(v1)
+	}
+	putNat(qhatv)
 
 	q = q.norm()
 	shrVU(u, u, shift)
@@ -647,7 +670,7 @@ 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
+	// 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
@@ -1018,7 +1041,7 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
 		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
+				// gain. Use go test -bench=".*" in crypto/rsa
 				// to check performance before making changes.
 				zz = zz.mul(z, z)
 				zz, z = z, zz
diff --git a/src/math/big/nat_test.go b/src/math/big/nat_test.go
index 563ccb3..ebb2985 100644
--- a/src/math/big/nat_test.go
+++ b/src/math/big/nat_test.go
@@ -5,6 +5,7 @@
 package big
 
 import (
+	"fmt"
 	"runtime"
 	"strings"
 	"testing"
@@ -509,24 +510,20 @@ func TestExpNN(t *testing.T) {
 	}
 }
 
-func ExpHelper(b *testing.B, x, y Word) {
-	var z nat
-	for i := 0; i < b.N; i++ {
-		z.expWW(x, y)
+func BenchmarkExp3Power(b *testing.B) {
+	const x = 3
+	for _, y := range []Word{
+		0x10, 0x40, 0x100, 0x400, 0x1000, 0x4000, 0x10000, 0x40000, 0x100000, 0x400000,
+	} {
+		b.Run(fmt.Sprintf("%#x", y), func(b *testing.B) {
+			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:
diff --git a/src/math/big/natconv.go b/src/math/big/natconv.go
index d2ce667..4454784 100644
--- a/src/math/big/natconv.go
+++ b/src/math/big/natconv.go
@@ -302,7 +302,7 @@ func (x nat) itoa(neg bool, base int) []byte {
 		}
 
 	} else {
-		bb, ndigits := maxPow(Word(b))
+		bb, ndigits := maxPow(b)
 
 		// construct table of successive squares of bb*leafSize to use in subdivisions
 		// result (table != nil) <=> (len(x) > leafSize > 0)
@@ -391,7 +391,7 @@ func (q nat) convertWords(s []byte, b Word, ndigits int, bb Word, table []diviso
 				// this appears to be faster for BenchmarkString10000Base10
 				// and smaller strings (but a bit slower for larger ones)
 				t := r / 10
-				s[i] = '0' + byte(r-t<<3-t-t) // TODO(gri) replace w/ t*10 once compiler produces better code
+				s[i] = '0' + byte(r-t*10)
 				r = t
 			}
 		}
diff --git a/src/math/big/natconv_test.go b/src/math/big/natconv_test.go
index 028e5a8..79901d1 100644
--- a/src/math/big/natconv_test.go
+++ b/src/math/big/natconv_test.go
@@ -6,6 +6,7 @@ package big
 
 import (
 	"bytes"
+	"fmt"
 	"io"
 	"strings"
 	"testing"
@@ -273,102 +274,58 @@ func BenchmarkStringPiParallel(b *testing.B) {
 	})
 }
 
-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)
-
-	s := z.utoa(base)
-	if t := itoa(z, base); !bytes.Equal(s, t) {
-		b.Fatalf("scanning: got %s; want %s", s, t)
+func BenchmarkScan(b *testing.B) {
+	const x = 10
+	for _, base := range []int{2, 8, 10, 16} {
+		for _, y := range []Word{10, 100, 1000, 10000, 100000} {
+			b.Run(fmt.Sprintf("%d/Base%d", y, base), func(b *testing.B) {
+				b.StopTimer()
+				var z nat
+				z = z.expWW(x, y)
+
+				s := z.utoa(base)
+				if t := itoa(z, base); !bytes.Equal(s, t) {
+					b.Fatalf("scanning: got %s; want %s", s, t)
+				}
+				b.StartTimer()
+
+				for i := 0; i < b.N; i++ {
+					z.scan(bytes.NewReader(s), base, false)
+				}
+			})
+		}
 	}
-	b.StartTimer()
+}
 
-	for i := 0; i < b.N; i++ {
-		z.scan(bytes.NewReader(s), base, false)
+func BenchmarkString(b *testing.B) {
+	const x = 10
+	for _, base := range []int{2, 8, 10, 16} {
+		for _, y := range []Word{10, 100, 1000, 10000, 100000} {
+			b.Run(fmt.Sprintf("%d/Base%d", y, base), func(b *testing.B) {
+				b.StopTimer()
+				var z nat
+				z = z.expWW(x, y)
+				z.utoa(base) // warm divisor cache
+				b.StartTimer()
+
+				for i := 0; i < b.N; i++ {
+					_ = z.utoa(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.utoa(base) // warm divisor cache
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		_ = z.utoa(base)
+func BenchmarkLeafSize(b *testing.B) {
+	for n := 0; n <= 16; n++ {
+		b.Run(fmt.Sprint(n), func(b *testing.B) { LeafSizeHelper(b, 10, n) })
+	}
+	// Try some large lengths
+	for _, n := range []int{32, 64} {
+		b.Run(fmt.Sprint(n), func(b *testing.B) { LeafSizeHelper(b, 10, n) })
 	}
 }
 
-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, size int) {
 	b.StopTimer()
 	originalLeafSize := leafSize
diff --git a/src/math/big/rat.go b/src/math/big/rat.go
index 2cd9ed0..56ce33d 100644
--- a/src/math/big/rat.go
+++ b/src/math/big/rat.go
@@ -63,7 +63,7 @@ func (z *Rat) SetFloat64(f float64) *Rat {
 
 // 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.
+// 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 (
@@ -161,7 +161,7 @@ func quotToFloat32(a, b nat) (f float32, exact bool) {
 
 // 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.
+// 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 (
diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go
index 4566ff4..ef2b675 100644
--- a/src/math/big/ratconv.go
+++ b/src/math/big/ratconv.go
@@ -15,7 +15,7 @@ import (
 )
 
 func ratTok(ch rune) bool {
-	return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+	return strings.ContainsRune("+-/0123456789.eE", ch)
 }
 
 // Scan is a support routine for fmt.Scanner. It accepts the formats
@@ -25,7 +25,7 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
 	if err != nil {
 		return err
 	}
-	if strings.IndexRune("efgEFGv", ch) < 0 {
+	if !strings.ContainsRune("efgEFGv", ch) {
 		return errors.New("Rat.Scan: invalid verb")
 	}
 	if _, ok := z.SetString(string(tok)); !ok {
@@ -88,6 +88,12 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
 		return nil, false
 	}
 
+	// special-case 0 (see also issue #16176)
+	if len(z.a.abs) == 0 {
+		return z, true
+	}
+	// len(z.a.abs) > 0
+
 	// correct exponent
 	if ecorr < 0 {
 		exp += int64(ecorr)
@@ -178,7 +184,7 @@ func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err err
 			}
 			break // i > 0
 		}
-		digits = append(digits, byte(ch))
+		digits = append(digits, ch)
 	}
 	// i > 0 => we have at least one digit
 
diff --git a/src/math/big/ratconv_test.go b/src/math/big/ratconv_test.go
index da2fdab..35ad6cc 100644
--- a/src/math/big/ratconv_test.go
+++ b/src/math/big/ratconv_test.go
@@ -48,6 +48,7 @@ var setStringTests = []StringTest{
 	{"53/70893980658822810696", "53/70893980658822810696", true},
 	{"106/141787961317645621392", "53/70893980658822810696", true},
 	{"204211327800791583.81095", "4084226556015831676219/20000", true},
+	{"0e9999999999", "0", true}, // issue #16176
 	{in: "1/0"},
 }
 
@@ -137,7 +138,7 @@ func TestFloatString(t *testing.T) {
 	}
 }
 
-// Test inputs to Rat.SetString.  The prefix "long:" causes the test
+// 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.
diff --git a/src/math/cmplx/cmath_test.go b/src/math/cmplx/cmath_test.go
index 18d9be8..d904be8 100644
--- a/src/math/cmplx/cmath_test.go
+++ b/src/math/cmplx/cmath_test.go
@@ -9,6 +9,9 @@ import (
 	"testing"
 )
 
+// The higher-precision values in vc26 were used to derive the
+// input arguments vc (see also comment below). For reference
+// only (do not delete).
 var vc26 = []complex128{
 	(4.97901192488367350108546816 + 7.73887247457810456552351752i),
 	(7.73887247457810456552351752 - 0.27688005719200159404635997i),
@@ -21,6 +24,7 @@ var vc26 = []complex128{
 	(1.82530809168085506044576505 - 8.68592476857560136238589621i),
 	(-8.68592476857560136238589621 + 4.97901192488367350108546816i),
 }
+
 var vc = []complex128{
 	(4.9790119248836735e+00 + 7.7388724745781045e+00i),
 	(7.7388724745781045e+00 - 2.7688005719200159e-01i),
@@ -448,8 +452,7 @@ func tolerance(a, b, e float64) bool {
 	}
 	return d < e
 }
-func soclose(a, b, e float64) bool { return tolerance(a, b, e) }
-func veryclose(a, b float64) bool  { return tolerance(a, b, 4e-16) }
+func veryclose(a, b float64) bool { return tolerance(a, b, 4e-16) }
 func alike(a, b float64) bool {
 	switch {
 	case a != a && b != b: // math.IsNaN(a) && math.IsNaN(b):
diff --git a/src/math/cmplx/sqrt.go b/src/math/cmplx/sqrt.go
index 276be07..72f81e9 100644
--- a/src/math/cmplx/sqrt.go
+++ b/src/math/cmplx/sqrt.go
@@ -43,7 +43,7 @@ import "math"
 // Cancelation error in r-x or r+x is avoided by using the
 // identity  2 Re w Im w  =  y.
 //
-// Note that -w is also a square root of z.  The root chosen
+// Note that -w is also a square root of z. The root chosen
 // is always in the right half plane and Im w has the same sign as y.
 //
 // ACCURACY:
diff --git a/src/math/dim_386.s b/src/math/dim_386.s
index c8194fe..22b8abb 100644
--- a/src/math/dim_386.s
+++ b/src/math/dim_386.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/dim_amd64.s b/src/math/dim_amd64.s
index 8e6aaad..249f1b1 100644
--- a/src/math/dim_amd64.s
+++ b/src/math/dim_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/dim_amd64p32.s b/src/math/dim_amd64p32.s
index e5e3447..2740aa9 100644
--- a/src/math/dim_amd64p32.s
+++ b/src/math/dim_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/dim_arm.s b/src/math/dim_arm.s
index be66950..642e485 100644
--- a/src/math/dim_arm.s
+++ b/src/math/dim_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/dim_s390x.s b/src/math/dim_s390x.s
new file mode 100644
index 0000000..503d261
--- /dev/null
+++ b/src/math/dim_s390x.s
@@ -0,0 +1,132 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on dim_amd64.s
+
+#include "textflag.h"
+
+#define PosInf 0x7FF0000000000000
+#define NaN    0x7FF8000000000001
+#define NegInf 0xFFF0000000000000
+
+// func Dim(x, y float64) float64
+TEXT ·Dim(SB),NOSPLIT,$0
+	// (+Inf, +Inf) special case
+	MOVD    x+0(FP), R2
+	MOVD    y+8(FP), R3
+	MOVD    $PosInf, R4
+	CMPUBNE R4, R2, dim2
+	CMPUBEQ R4, R3, bothInf
+dim2:	// (-Inf, -Inf) special case
+	MOVD    $NegInf, R4
+	CMPUBNE R4, R2, dim3
+	CMPUBEQ R4, R3, bothInf
+dim3:	// (NaN, x) or (x, NaN)
+	MOVD    $~(1<<63), R5
+	MOVD    $PosInf, R4
+	AND     R5, R2 // x = |x|
+	CMPUBLT R4, R2, isDimNaN
+	AND     R5, R3 // y = |y|
+	CMPUBLT R4, R3, isDimNaN
+
+	FMOVD   x+0(FP), F1
+	FMOVD   y+8(FP), F2
+	FSUB    F2, F1
+	FMOVD   $(0.0), F2
+	FCMPU   F2, F1
+	BGE     +3(PC)
+	FMOVD   F1, ret+16(FP)
+	RET
+	FMOVD   F2, ret+16(FP)
+	RET
+bothInf: // Dim(-Inf, -Inf) or Dim(+Inf, +Inf)
+isDimNaN:
+	MOVD    $NaN, R4
+	MOVD    R4, ret+16(FP)
+	RET
+
+// func ·Max(x, y float64) float64
+TEXT ·Max(SB),NOSPLIT,$0
+	// +Inf special cases
+	MOVD    $PosInf, R4
+	MOVD    x+0(FP), R8
+	CMPUBEQ R4, R8, isPosInf
+	MOVD    y+8(FP), R9
+	CMPUBEQ R4, R9, isPosInf
+	// NaN special cases
+	MOVD    $~(1<<63), R5 // bit mask
+	MOVD    $PosInf, R4
+	MOVD    R8, R2
+	AND     R5, R2 // x = |x|
+	CMPUBLT R4, R2, isMaxNaN
+	MOVD    R9, R3
+	AND     R5, R3 // y = |y|
+	CMPUBLT R4, R3, isMaxNaN
+	// ±0 special cases
+	OR      R3, R2
+	BEQ     isMaxZero
+
+	FMOVD   x+0(FP), F1
+	FMOVD   y+8(FP), F2
+	FCMPU   F2, F1
+	BGT     +3(PC)
+	FMOVD   F1, ret+16(FP)
+	RET
+	FMOVD   F2, ret+16(FP)
+	RET
+isMaxNaN: // return NaN
+	MOVD	$NaN, R4
+isPosInf: // return +Inf
+	MOVD    R4, ret+16(FP)
+	RET
+isMaxZero:
+	MOVD    $(1<<63), R4 // -0.0
+	CMPUBEQ R4, R8, +3(PC)
+	MOVD    R8, ret+16(FP) // return 0
+	RET
+	MOVD    R9, ret+16(FP) // return other 0
+	RET
+
+// func Min(x, y float64) float64
+TEXT ·Min(SB),NOSPLIT,$0
+	// -Inf special cases
+	MOVD    $NegInf, R4
+	MOVD    x+0(FP), R8
+	CMPUBEQ R4, R8, isNegInf
+	MOVD    y+8(FP), R9
+	CMPUBEQ R4, R9, isNegInf
+	// NaN special cases
+	MOVD    $~(1<<63), R5
+	MOVD    $PosInf, R4
+	MOVD    R8, R2
+	AND     R5, R2 // x = |x|
+	CMPUBLT R4, R2, isMinNaN
+	MOVD    R9, R3
+	AND     R5, R3 // y = |y|
+	CMPUBLT R4, R3, isMinNaN
+	// ±0 special cases
+	OR      R3, R2
+	BEQ     isMinZero
+
+	FMOVD   x+0(FP), F1
+	FMOVD   y+8(FP), F2
+	FCMPU   F2, F1
+	BLT     +3(PC)
+	FMOVD   F1, ret+16(FP)
+	RET
+	FMOVD   F2, ret+16(FP)
+	RET
+isMinNaN: // return NaN
+	MOVD	$NaN, R4
+isNegInf: // return -Inf
+	MOVD    R4, ret+16(FP)
+	RET
+isMinZero:
+	MOVD    $(1<<63), R4 // -0.0
+	CMPUBEQ R4, R8, +3(PC)
+	MOVD    R9, ret+16(FP) // return other 0
+	RET
+	MOVD    R8, ret+16(FP) // return -0
+	RET
+
diff --git a/src/math/erf.go b/src/math/erf.go
index 4cd80f8..8ddd5f9 100644
--- a/src/math/erf.go
+++ b/src/math/erf.go
@@ -10,7 +10,7 @@ package math
 
 // The original C code and the long comment below are
 // from FreeBSD's /usr/src/lib/msun/src/s_erf.c and
-// came with this notice.  The go code is a simplified
+// came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/exp.go b/src/math/exp.go
index f31585f..3268c98 100644
--- a/src/math/exp.go
+++ b/src/math/exp.go
@@ -15,7 +15,7 @@ func Exp(x float64) float64
 
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c
-// and came with this notice.  The go code is a simplified
+// and came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/exp2_386.s b/src/math/exp2_386.s
index 7d11920..d04cad6 100644
--- a/src/math/exp2_386.s
+++ b/src/math/exp2_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/exp2_amd64.s b/src/math/exp2_amd64.s
index 903c835..e7e1f86 100644
--- a/src/math/exp2_amd64.s
+++ b/src/math/exp2_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/exp2_amd64p32.s b/src/math/exp2_amd64p32.s
index 4d38309..067d3bf 100644
--- a/src/math/exp2_amd64p32.s
+++ b/src/math/exp2_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/exp2_arm.s b/src/math/exp2_arm.s
index 58283cd..9b996fb 100644
--- a/src/math/exp2_arm.s
+++ b/src/math/exp2_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/exp_386.s b/src/math/exp_386.s
index 6a478a5..18a92ef 100644
--- a/src/math/exp_386.s
+++ b/src/math/exp_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/exp_amd64.s b/src/math/exp_amd64.s
index d9cf8fd..f63efec 100644
--- a/src/math/exp_amd64.s
+++ b/src/math/exp_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/exp_amd64p32.s b/src/math/exp_amd64p32.s
index 98ac2e9..d1f8312 100644
--- a/src/math/exp_amd64p32.s
+++ b/src/math/exp_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/exp_arm.s b/src/math/exp_arm.s
index ce36d03..493677a 100644
--- a/src/math/exp_arm.s
+++ b/src/math/exp_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/expm1.go b/src/math/expm1.go
index 670b96d..8ce67e5 100644
--- a/src/math/expm1.go
+++ b/src/math/expm1.go
@@ -6,7 +6,7 @@ package math
 
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/s_expm1.c
-// and came with this notice.  The go code is a simplified
+// and came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/expm1_386.s b/src/math/expm1_386.s
index a48ca8a..c1392cd 100644
--- a/src/math/expm1_386.s
+++ b/src/math/expm1_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/expm1_amd64.s b/src/math/expm1_amd64.s
index b7d5a3b..bdb78b3 100644
--- a/src/math/expm1_amd64.s
+++ b/src/math/expm1_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/expm1_amd64p32.s b/src/math/expm1_amd64p32.s
index 709ebef..2d27ef5 100644
--- a/src/math/expm1_amd64p32.s
+++ b/src/math/expm1_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/expm1_arm.s b/src/math/expm1_arm.s
index 5f80d87..b7b3b48 100644
--- a/src/math/expm1_arm.s
+++ b/src/math/expm1_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/export_test.go b/src/math/export_test.go
index 02992d7..368308e 100644
--- a/src/math/export_test.go
+++ b/src/math/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/floor_386.s b/src/math/floor_386.s
index 31c9b17..0960eec 100644
--- a/src/math/floor_386.s
+++ b/src/math/floor_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/floor_amd64.s b/src/math/floor_amd64.s
index 7f512e7..aa10ee8 100644
--- a/src/math/floor_amd64.s
+++ b/src/math/floor_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/math/floor_amd64p32.s b/src/math/floor_amd64p32.s
index 5b87d7a..13be9a6 100644
--- a/src/math/floor_amd64p32.s
+++ b/src/math/floor_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/floor_arm.s b/src/math/floor_arm.s
index 5909176..3123be3 100644
--- a/src/math/floor_arm.s
+++ b/src/math/floor_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/frexp_386.s b/src/math/frexp_386.s
index 5bff7e2..832b435 100644
--- a/src/math/frexp_386.s
+++ b/src/math/frexp_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/frexp_amd64.s b/src/math/frexp_amd64.s
index 93a3210..41a6c61 100644
--- a/src/math/frexp_amd64.s
+++ b/src/math/frexp_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/frexp_amd64p32.s b/src/math/frexp_amd64p32.s
index fbb5645..2a9da73 100644
--- a/src/math/frexp_amd64p32.s
+++ b/src/math/frexp_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/frexp_arm.s b/src/math/frexp_arm.s
index 7842eca..fda0068 100644
--- a/src/math/frexp_arm.s
+++ b/src/math/frexp_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/gamma.go b/src/math/gamma.go
index 164f54f..841ec11 100644
--- a/src/math/gamma.go
+++ b/src/math/gamma.go
@@ -21,7 +21,7 @@ package math
 //
 // DESCRIPTION:
 //
-// Returns gamma function of the argument.  The result is
+// Returns gamma function of the argument. The result is
 // correctly signed, and the sign (+1 or -1) is also
 // returned in a global (extern) variable named signgam.
 // This variable is also filled in by the logarithmic gamma
diff --git a/src/math/hypot_386.s b/src/math/hypot_386.s
index d321f46..a89cdf7 100644
--- a/src/math/hypot_386.s
+++ b/src/math/hypot_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/hypot_amd64.s b/src/math/hypot_amd64.s
index a68eebc..d7983a7 100644
--- a/src/math/hypot_amd64.s
+++ b/src/math/hypot_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/hypot_amd64p32.s b/src/math/hypot_amd64p32.s
index b84542a..3f86bb7 100644
--- a/src/math/hypot_amd64p32.s
+++ b/src/math/hypot_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/hypot_arm.s b/src/math/hypot_arm.s
index 9c8abca..a78653a 100644
--- a/src/math/hypot_arm.s
+++ b/src/math/hypot_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/j0.go b/src/math/j0.go
index de77388..cbef7aa 100644
--- a/src/math/j0.go
+++ b/src/math/j0.go
@@ -10,7 +10,7 @@ package math
 
 // The original C code and the long comment below are
 // from FreeBSD's /usr/src/lib/msun/src/e_j0.c and
-// came with this notice.  The go code is a simplified
+// came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/j1.go b/src/math/j1.go
index c537a72..d359d90 100644
--- a/src/math/j1.go
+++ b/src/math/j1.go
@@ -10,7 +10,7 @@ package math
 
 // The original C code and the long comment below are
 // from FreeBSD's /usr/src/lib/msun/src/e_j1.c and
-// came with this notice.  The go code is a simplified
+// came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/jn.go b/src/math/jn.go
index ffb8a00..721112f 100644
--- a/src/math/jn.go
+++ b/src/math/jn.go
@@ -10,7 +10,7 @@ package math
 
 // The original C code and the long comment below are
 // from FreeBSD's /usr/src/lib/msun/src/e_jn.c and
-// came with this notice.  The go code is a simplified
+// came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/ldexp_386.s b/src/math/ldexp_386.s
index ac8e8ba..6f67ae1 100644
--- a/src/math/ldexp_386.s
+++ b/src/math/ldexp_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/ldexp_amd64.s b/src/math/ldexp_amd64.s
index 6063a64..a8fb7c7 100644
--- a/src/math/ldexp_amd64.s
+++ b/src/math/ldexp_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/ldexp_amd64p32.s b/src/math/ldexp_amd64p32.s
index 9aa9d9d..a629e9b 100644
--- a/src/math/ldexp_amd64p32.s
+++ b/src/math/ldexp_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/ldexp_arm.s b/src/math/ldexp_arm.s
index fcffa2e..b571c0a 100644
--- a/src/math/ldexp_arm.s
+++ b/src/math/ldexp_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/lgamma.go b/src/math/lgamma.go
index 6a02c41..19ac3ff 100644
--- a/src/math/lgamma.go
+++ b/src/math/lgamma.go
@@ -10,7 +10,7 @@ package math
 
 // The original C code and the long comment below are
 // from FreeBSD's /usr/src/lib/msun/src/e_lgamma_r.c and
-// came with this notice.  The go code is a simplified
+// came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/log.go b/src/math/log.go
index 818f00a..e328348 100644
--- a/src/math/log.go
+++ b/src/math/log.go
@@ -10,7 +10,7 @@ package math
 
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/e_log.c
-// and came with this notice.  The go code is a simpler
+// and came with this notice. The go code is a simpler
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/log10_386.s b/src/math/log10_386.s
index 2897f3c..10eecd9 100644
--- a/src/math/log10_386.s
+++ b/src/math/log10_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/log10_amd64.s b/src/math/log10_amd64.s
index 8382ba7..4a4d587 100644
--- a/src/math/log10_amd64.s
+++ b/src/math/log10_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/log10_amd64p32.s b/src/math/log10_amd64p32.s
index bf43841..c356226 100644
--- a/src/math/log10_amd64p32.s
+++ b/src/math/log10_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/log10_arm.s b/src/math/log10_arm.s
index dbcb835..271473d 100644
--- a/src/math/log10_arm.s
+++ b/src/math/log10_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/log1p.go b/src/math/log1p.go
index 12b9868..d1bddfb 100644
--- a/src/math/log1p.go
+++ b/src/math/log1p.go
@@ -6,7 +6,7 @@ package math
 
 // The original C code, the long comment, and the constants
 // below are from FreeBSD's /usr/src/lib/msun/src/s_log1p.c
-// and came with this notice.  The go code is a simplified
+// and came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/math/log1p_386.s b/src/math/log1p_386.s
index 1c2d683..63b7e62 100644
--- a/src/math/log1p_386.s
+++ b/src/math/log1p_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/log1p_amd64.s b/src/math/log1p_amd64.s
index 1e58fb1..5d10f29 100644
--- a/src/math/log1p_amd64.s
+++ b/src/math/log1p_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/log1p_amd64p32.s b/src/math/log1p_amd64p32.s
index a14b5e3..10b286b 100644
--- a/src/math/log1p_amd64p32.s
+++ b/src/math/log1p_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/log1p_arm.s b/src/math/log1p_arm.s
index 95d5496..6919b56 100644
--- a/src/math/log1p_arm.s
+++ b/src/math/log1p_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/log_386.s b/src/math/log_386.s
index ff998af..0b64b50 100644
--- a/src/math/log_386.s
+++ b/src/math/log_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/log_amd64.s b/src/math/log_amd64.s
index 84c60ab..bd2d063 100644
--- a/src/math/log_amd64.s
+++ b/src/math/log_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/log_amd64p32.s b/src/math/log_amd64p32.s
index 5058d60..80434c6 100644
--- a/src/math/log_amd64p32.s
+++ b/src/math/log_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/log_arm.s b/src/math/log_arm.s
index e21d036..ecc2a35 100644
--- a/src/math/log_arm.s
+++ b/src/math/log_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/mod_amd64.s b/src/math/mod_amd64.s
index f99dbe2..3a0c980 100644
--- a/src/math/mod_amd64.s
+++ b/src/math/mod_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/mod_amd64p32.s b/src/math/mod_amd64p32.s
index c1b2311..fa85420 100644
--- a/src/math/mod_amd64p32.s
+++ b/src/math/mod_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/mod_arm.s b/src/math/mod_arm.s
index 5afb359..6e98912 100644
--- a/src/math/mod_arm.s
+++ b/src/math/mod_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/modf.go b/src/math/modf.go
index 81cb8b5..c5bb894 100644
--- a/src/math/modf.go
+++ b/src/math/modf.go
@@ -5,7 +5,7 @@
 package math
 
 // Modf returns integer and fractional floating-point numbers
-// that sum to f.  Both values have the same sign as f.
+// that sum to f. Both values have the same sign as f.
 //
 // Special cases are:
 //	Modf(±Inf) = ±Inf, NaN
diff --git a/src/math/modf_386.s b/src/math/modf_386.s
index d549f1d..d9b1eeb 100644
--- a/src/math/modf_386.s
+++ b/src/math/modf_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/modf_amd64.s b/src/math/modf_amd64.s
index 701cf72..5292dd5 100644
--- a/src/math/modf_amd64.s
+++ b/src/math/modf_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/modf_amd64p32.s b/src/math/modf_amd64p32.s
index 5508c25..e9cf32d 100644
--- a/src/math/modf_amd64p32.s
+++ b/src/math/modf_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/modf_arm.s b/src/math/modf_arm.s
index ea3c8dc..7abd6d3 100644
--- a/src/math/modf_arm.s
+++ b/src/math/modf_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/rand/example_test.go b/src/math/rand/example_test.go
index e6cd4f7..614eeae 100644
--- a/src/math/rand/example_test.go
+++ b/src/math/rand/example_test.go
@@ -95,3 +95,13 @@ func Example_rand() {
 	// Int63n(10)  7                   6                   3
 	// Perm        [1 4 2 3 0]         [4 2 1 3 0]         [1 2 4 0 3]
 }
+
+func ExamplePerm() {
+	for _, value := range rand.Perm(3) {
+		fmt.Println(value)
+	}
+
+	// Unordered output: 1
+	// 2
+	// 0
+}
diff --git a/src/math/rand/rand.go b/src/math/rand/rand.go
index d693bfb..8f31b0e 100644
--- a/src/math/rand/rand.go
+++ b/src/math/rand/rand.go
@@ -33,14 +33,26 @@ func NewSource(seed int64) Source {
 // A Rand is a source of random numbers.
 type Rand struct {
 	src Source
+
+	// readVal contains remainder of 63-bit integer used for bytes
+	// generation during most recent Read call.
+	// It is saved so next Read call can start where the previous
+	// one finished.
+	readVal int64
+	// readPos indicates the number of low-order bytes of readVal
+	// that are still valid.
+	readPos int8
 }
 
 // New returns a new Rand that uses random values from src
 // to generate other random values.
-func New(src Source) *Rand { return &Rand{src} }
+func New(src Source) *Rand { return &Rand{src: src} }
 
 // Seed uses the provided seed value to initialize the generator to a deterministic state.
-func (r *Rand) Seed(seed int64) { r.src.Seed(seed) }
+func (r *Rand) Seed(seed int64) {
+	r.src.Seed(seed)
+	r.readPos = 0
+}
 
 // Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
 func (r *Rand) Int63() int64 { return r.src.Int63() }
@@ -161,14 +173,20 @@ func (r *Rand) Perm(n int) []int {
 // Read generates len(p) random bytes and writes them into p. It
 // always returns len(p) and a nil error.
 func (r *Rand) Read(p []byte) (n int, err error) {
-	for i := 0; i < len(p); i += 7 {
-		val := r.src.Int63()
-		for j := 0; i+j < len(p) && j < 7; j++ {
-			p[i+j] = byte(val)
-			val >>= 8
+	pos := r.readPos
+	val := r.readVal
+	for n = 0; n < len(p); n++ {
+		if pos == 0 {
+			val = r.Int63()
+			pos = 7
 		}
+		p[n] = byte(val)
+		val >>= 8
+		pos--
 	}
-	return len(p), nil
+	r.readPos = pos
+	r.readVal = val
+	return
 }
 
 /*
@@ -179,7 +197,8 @@ var globalRand = New(&lockedSource{src: NewSource(1)})
 
 // Seed uses the provided seed value to initialize the default Source to a
 // deterministic state. If Seed is not called, the generator behaves as
-// if seeded by Seed(1).
+// if seeded by Seed(1). Seed values that have the same remainder when
+// divided by 2^31-1 generate the same pseudo-random sequence.
 func Seed(seed int64) { globalRand.Seed(seed) }
 
 // Int63 returns a non-negative pseudo-random 63-bit integer as an int64
diff --git a/src/math/rand/rand_test.go b/src/math/rand/rand_test.go
index 8d68335..6f31279 100644
--- a/src/math/rand/rand_test.go
+++ b/src/math/rand/rand_test.go
@@ -5,13 +5,16 @@
 package rand
 
 import (
+	"bytes"
 	"errors"
 	"fmt"
 	"internal/testenv"
+	"io"
 	"math"
 	"os"
 	"runtime"
 	"testing"
+	"testing/iotest"
 )
 
 const (
@@ -373,7 +376,7 @@ func testReadUniformity(t *testing.T, n int, seed int64) {
 	checkSampleDistribution(t, samples, expected)
 }
 
-func TestRead(t *testing.T) {
+func TestReadUniformity(t *testing.T) {
 	testBufferSizes := []int{
 		2, 4, 7, 64, 1024, 1 << 16, 1 << 20,
 	}
@@ -394,7 +397,42 @@ func TestReadEmpty(t *testing.T) {
 	if n != 0 {
 		t.Errorf("Read into empty buffer returned unexpected n of %d", n)
 	}
+}
+
+func TestReadByOneByte(t *testing.T) {
+	r := New(NewSource(1))
+	b1 := make([]byte, 100)
+	_, err := io.ReadFull(iotest.OneByteReader(r), b1)
+	if err != nil {
+		t.Errorf("read by one byte: %v", err)
+	}
+	r = New(NewSource(1))
+	b2 := make([]byte, 100)
+	_, err = r.Read(b2)
+	if err != nil {
+		t.Errorf("read: %v", err)
+	}
+	if !bytes.Equal(b1, b2) {
+		t.Errorf("read by one byte vs single read:\n%x\n%x", b1, b2)
+	}
+}
 
+func TestReadSeedReset(t *testing.T) {
+	r := New(NewSource(42))
+	b1 := make([]byte, 128)
+	_, err := r.Read(b1)
+	if err != nil {
+		t.Errorf("read: %v", err)
+	}
+	r.Seed(42)
+	b2 := make([]byte, 128)
+	_, err = r.Read(b2)
+	if err != nil {
+		t.Errorf("read: %v", err)
+	}
+	if !bytes.Equal(b1, b2) {
+		t.Errorf("mismatch after re-seed:\n%x\n%x", b1, b2)
+	}
 }
 
 // Benchmarks
diff --git a/src/math/rand/regress_test.go b/src/math/rand/regress_test.go
index 9ae5357..4dd965c 100644
--- a/src/math/rand/regress_test.go
+++ b/src/math/rand/regress_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -342,25 +342,25 @@ var regressGolden = []interface{}{
 	[]int{8, 7, 5, 3, 4, 6, 0, 1, 2},    // Perm(9)
 	[]int{1, 0, 2, 5, 7, 6, 9, 8, 3, 4}, // Perm(10)
 	[]byte{0x1},                         // Read([0])
-	[]byte{0xc0, 0x41, 0xd3, 0xff, 0x12, 0x4, 0x5b},                   // Read([0 0 0 0 0 0 0])
-	[]byte{0x73, 0xc8, 0x6e, 0x4f, 0xf9, 0x5f, 0xf6, 0x62},            // Read([0 0 0 0 0 0 0 0])
-	[]byte{0x4a, 0x2d, 0xb, 0x75, 0xfb, 0x18, 0xd, 0xaf, 0x48},        // Read([0 0 0 0 0 0 0 0 0])
-	[]byte{0x39, 0x46, 0x51, 0x85, 0xf, 0xd4, 0xa1, 0x78, 0x89, 0x2e}, // Read([0 0 0 0 0 0 0 0 0 0])
-	[]byte{0x51}, // Read([0])
-	[]byte{0x4e, 0xe2, 0xd3, 0xd0, 0xd0, 0xde, 0x6b},                   // Read([0 0 0 0 0 0 0])
-	[]byte{0xf8, 0xf9, 0xb4, 0x4c, 0xe8, 0x5f, 0xf0, 0x44},             // Read([0 0 0 0 0 0 0 0])
-	[]byte{0x3b, 0xbf, 0x85, 0x7a, 0xab, 0x99, 0xc5, 0xb2, 0x52},       // Read([0 0 0 0 0 0 0 0 0])
-	[]byte{0xa8, 0xae, 0xb7, 0x9e, 0xf8, 0x56, 0xf6, 0x59, 0xc1, 0x8f}, // Read([0 0 0 0 0 0 0 0 0 0])
-	[]byte{0xc7}, // Read([0])
-	[]byte{0x5f, 0x67, 0xcf, 0xe2, 0x42, 0xcf, 0x3c},                   // Read([0 0 0 0 0 0 0])
-	[]byte{0xc3, 0x54, 0xf3, 0xed, 0xe2, 0xd6, 0xbe, 0xcc},             // Read([0 0 0 0 0 0 0 0])
-	[]byte{0x6a, 0x9f, 0x4a, 0x57, 0x8b, 0xcb, 0x9e, 0xf2, 0xd4},       // Read([0 0 0 0 0 0 0 0 0])
-	[]byte{0x6d, 0x29, 0x97, 0x61, 0xea, 0x9e, 0x4f, 0x5a, 0xa6, 0xae}, // Read([0 0 0 0 0 0 0 0 0 0])
-	[]byte{0xaa}, // Read([0])
-	[]byte{0x20, 0xef, 0xcd, 0x6c, 0xea, 0x84, 0xb6},                   // Read([0 0 0 0 0 0 0])
-	[]byte{0x92, 0x5e, 0x60, 0x7b, 0xe0, 0x63, 0x71, 0x6f},             // Read([0 0 0 0 0 0 0 0])
-	[]byte{0x4, 0x5c, 0x3f, 0x0, 0xf, 0x8a, 0x79, 0x6b, 0xce},          // Read([0 0 0 0 0 0 0 0 0])
-	[]byte{0xaa, 0xca, 0xee, 0xdf, 0xad, 0x5b, 0x50, 0x66, 0x64, 0xe8}, // Read([0 0 0 0 0 0 0 0 0 0])
+	[]byte{0x94, 0xfd, 0xc2, 0xfa, 0x2f, 0xfc, 0xc0},                 // Read([0 0 0 0 0 0 0])
+	[]byte{0x41, 0xd3, 0xff, 0x12, 0x4, 0x5b, 0x73, 0xc8},            // Read([0 0 0 0 0 0 0 0])
+	[]byte{0x6e, 0x4f, 0xf9, 0x5f, 0xf6, 0x62, 0xa5, 0xee, 0xe8},     // Read([0 0 0 0 0 0 0 0 0])
+	[]byte{0x2a, 0xbd, 0xf4, 0x4a, 0x2d, 0xb, 0x75, 0xfb, 0x18, 0xd}, // Read([0 0 0 0 0 0 0 0 0 0])
+	[]byte{0xaf},                                                      // Read([0])
+	[]byte{0x48, 0xa7, 0x9e, 0xe0, 0xb1, 0xd, 0x39},                   // Read([0 0 0 0 0 0 0])
+	[]byte{0x46, 0x51, 0x85, 0xf, 0xd4, 0xa1, 0x78, 0x89},             // Read([0 0 0 0 0 0 0 0])
+	[]byte{0x2e, 0xe2, 0x85, 0xec, 0xe1, 0x51, 0x14, 0x55, 0x78},      // Read([0 0 0 0 0 0 0 0 0])
+	[]byte{0x8, 0x75, 0xd6, 0x4e, 0xe2, 0xd3, 0xd0, 0xd0, 0xde, 0x6b}, // Read([0 0 0 0 0 0 0 0 0 0])
+	[]byte{0xf8}, // Read([0])
+	[]byte{0xf9, 0xb4, 0x4c, 0xe8, 0x5f, 0xf0, 0x44},                   // Read([0 0 0 0 0 0 0])
+	[]byte{0xc6, 0xb1, 0xf8, 0x3b, 0x8e, 0x88, 0x3b, 0xbf},             // Read([0 0 0 0 0 0 0 0])
+	[]byte{0x85, 0x7a, 0xab, 0x99, 0xc5, 0xb2, 0x52, 0xc7, 0x42},       // Read([0 0 0 0 0 0 0 0 0])
+	[]byte{0x9c, 0x32, 0xf3, 0xa8, 0xae, 0xb7, 0x9e, 0xf8, 0x56, 0xf6}, // Read([0 0 0 0 0 0 0 0 0 0])
+	[]byte{0x59},                                                       // Read([0])
+	[]byte{0xc1, 0x8f, 0xd, 0xce, 0xcc, 0x77, 0xc7},                    // Read([0 0 0 0 0 0 0])
+	[]byte{0x5e, 0x7a, 0x81, 0xbf, 0xde, 0x27, 0x5f, 0x67},             // Read([0 0 0 0 0 0 0 0])
+	[]byte{0xcf, 0xe2, 0x42, 0xcf, 0x3c, 0xc3, 0x54, 0xf3, 0xed},       // Read([0 0 0 0 0 0 0 0 0])
+	[]byte{0xe2, 0xd6, 0xbe, 0xcc, 0x4e, 0xa3, 0xae, 0x5e, 0x88, 0x52}, // Read([0 0 0 0 0 0 0 0 0 0])
 	uint32(4059586549),                                                 // Uint32()
 	uint32(1052117029),                                                 // Uint32()
 	uint32(2817310706),                                                 // Uint32()
diff --git a/src/math/remainder.go b/src/math/remainder.go
index 9a4e415..504fdda 100644
--- a/src/math/remainder.go
+++ b/src/math/remainder.go
@@ -6,7 +6,7 @@ package math
 
 // The original C code and the comment below are from
 // FreeBSD's /usr/src/lib/msun/src/e_remainder.c and came
-// with this notice.  The go code is a simplified version of
+// with this notice. The go code is a simplified version of
 // the original C.
 //
 // ====================================================
diff --git a/src/math/remainder_amd64.s b/src/math/remainder_amd64.s
index f7fda99..71b981a 100644
--- a/src/math/remainder_amd64.s
+++ b/src/math/remainder_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/remainder_amd64p32.s b/src/math/remainder_amd64p32.s
index cd5cf55..fdca642 100644
--- a/src/math/remainder_amd64p32.s
+++ b/src/math/remainder_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/remainder_arm.s b/src/math/remainder_arm.s
index 1ae597a..523a59c 100644
--- a/src/math/remainder_arm.s
+++ b/src/math/remainder_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/sin_386.s b/src/math/sin_386.s
index ccc8e64..9d605a1 100644
--- a/src/math/sin_386.s
+++ b/src/math/sin_386.s
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/math/sin_amd64.s b/src/math/sin_amd64.s
index 0c33cec..a3d5f10 100644
--- a/src/math/sin_amd64.s
+++ b/src/math/sin_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/sin_amd64p32.s b/src/math/sin_amd64p32.s
index 9f93eba..4d9b000 100644
--- a/src/math/sin_amd64p32.s
+++ b/src/math/sin_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/sin_arm.s b/src/math/sin_arm.s
index 467af3d..c8142a9 100644
--- a/src/math/sin_arm.s
+++ b/src/math/sin_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/sincos_386.s b/src/math/sincos_386.s
index 83af501..f700a4f 100644
--- a/src/math/sincos_386.s
+++ b/src/math/sincos_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/sincos_amd64.s b/src/math/sincos_amd64.s
index 59bf55f..b9ef88c 100644
--- a/src/math/sincos_amd64.s
+++ b/src/math/sincos_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/sincos_amd64p32.s b/src/math/sincos_amd64p32.s
index 360e94d..db86029 100644
--- a/src/math/sincos_amd64p32.s
+++ b/src/math/sincos_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/sincos_arm.s b/src/math/sincos_arm.s
index 9fe0482..d8d833c 100644
--- a/src/math/sincos_arm.s
+++ b/src/math/sincos_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/sqrt.go b/src/math/sqrt.go
index 96af6e2..7e95f23 100644
--- a/src/math/sqrt.go
+++ b/src/math/sqrt.go
@@ -6,7 +6,7 @@ package math
 
 // 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
+// came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
@@ -79,7 +79,7 @@ package math
 //      equal to huge for some floating point number "huge" and "tiny".
 //
 //
-// Notes:  Rounding mode detection omitted.  The constants "mask", "shift",
+// Notes:  Rounding mode detection omitted. The constants "mask", "shift",
 // and "bias" are found in src/math/bits.go
 
 // Sqrt returns the square root of x.
@@ -142,7 +142,3 @@ func sqrt(x float64) float64 {
 	ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
 	return Float64frombits(ix)
 }
-
-func sqrtC(f float64, r *float64) {
-	*r = sqrt(f)
-}
diff --git a/src/math/sqrt_386.s b/src/math/sqrt_386.s
index 5234a1e..402d152 100644
--- a/src/math/sqrt_386.s
+++ b/src/math/sqrt_386.s
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/math/sqrt_amd64.s b/src/math/sqrt_amd64.s
index 443d83f..f8d825d 100644
--- a/src/math/sqrt_amd64.s
+++ b/src/math/sqrt_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/math/sqrt_amd64p32.s b/src/math/sqrt_amd64p32.s
index d83a286..181114c 100644
--- a/src/math/sqrt_amd64p32.s
+++ b/src/math/sqrt_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/sqrt_arm.s b/src/math/sqrt_arm.s
index 4f9dc2e..a920b08 100644
--- a/src/math/sqrt_arm.s
+++ b/src/math/sqrt_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/sqrt_arm64.s b/src/math/sqrt_arm64.s
index 9861446..3041d25 100644
--- a/src/math/sqrt_arm64.s
+++ b/src/math/sqrt_arm64.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/math/sqrt_ppc64x.s b/src/math/sqrt_ppc64x.s
new file mode 100644
index 0000000..0469f4d
--- /dev/null
+++ b/src/math/sqrt_ppc64x.s
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go 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"
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),NOSPLIT,$0
+	FMOVD	x+0(FP), F0
+	FSQRT	F0, F0
+	FMOVD	F0, ret+8(FP)
+	RET
diff --git a/src/math/sqrt_s390x.s b/src/math/sqrt_s390x.s
new file mode 100644
index 0000000..37ca0be
--- /dev/null
+++ b/src/math/sqrt_s390x.s
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go 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), F1
+	FSQRT F1, F1
+	FMOVD F1, ret+8(FP)
+	RET
diff --git a/src/math/stubs_arm64.s b/src/math/stubs_arm64.s
index eea81e9..04de911 100644
--- a/src/math/stubs_arm64.s
+++ b/src/math/stubs_arm64.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/math/stubs_mips64x.s b/src/math/stubs_mips64x.s
index 63be6ea..97e6e4c 100644
--- a/src/math/stubs_mips64x.s
+++ b/src/math/stubs_mips64x.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/math/stubs_ppc64x.s b/src/math/stubs_ppc64x.s
index 9369c5c..a57357e 100644
--- a/src/math/stubs_ppc64x.s
+++ b/src/math/stubs_ppc64x.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -84,8 +84,5 @@ TEXT ·Sin(SB),NOSPLIT,$0
 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/math/stubs_s390x.s b/src/math/stubs_s390x.s
new file mode 100644
index 0000000..7686844
--- /dev/null
+++ b/src/math/stubs_s390x.s
@@ -0,0 +1,77 @@
+// Copyright 2016 The Go 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/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 ·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 ·Tan(SB),NOSPLIT,$0
+	BR ·tan(SB)
diff --git a/src/math/tan_386.s b/src/math/tan_386.s
index f1bdae1..cb65a3f 100644
--- a/src/math/tan_386.s
+++ b/src/math/tan_386.s
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/math/tan_amd64.s b/src/math/tan_amd64.s
index 39aa080..385ca05 100644
--- a/src/math/tan_amd64.s
+++ b/src/math/tan_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/math/tan_amd64p32.s b/src/math/tan_amd64p32.s
index 9b3f70d..b5e789d 100644
--- a/src/math/tan_amd64p32.s
+++ b/src/math/tan_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/math/tan_arm.s b/src/math/tan_arm.s
index 36c7c12..5f2cdd1 100644
--- a/src/math/tan_arm.s
+++ b/src/math/tan_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/mime/encodedword.go b/src/mime/encodedword.go
index db4b5f4..c3ca4ba 100644
--- a/src/mime/encodedword.go
+++ b/src/mime/encodedword.go
@@ -16,7 +16,7 @@ import (
 	"unicode/utf8"
 )
 
-// A WordEncoder is a RFC 2047 encoded-word encoder.
+// A WordEncoder is an RFC 2047 encoded-word encoder.
 type WordEncoder byte
 
 const (
@@ -71,7 +71,7 @@ const (
 	maxEncodedWordLen = 75
 	// maxContentLen is how much content can be encoded, ignoring the header and
 	// 2-byte footer.
-	maxContentLen = maxEncodedWordLen - len("=?UTF-8?") - len("?=")
+	maxContentLen = maxEncodedWordLen - len("=?UTF-8?q?") - len("?=")
 )
 
 var maxBase64Len = base64.StdEncoding.DecodedLen(maxContentLen)
@@ -89,7 +89,7 @@ func (e WordEncoder) bEncode(buf *bytes.Buffer, charset, s string) {
 
 	var currentLen, last, runeLen int
 	for i := 0; i < len(s); i += runeLen {
-		// Multi-byte characters must not be split accross encoded-words.
+		// Multi-byte characters must not be split across encoded-words.
 		// See RFC 2047, section 5.3.
 		_, runeLen = utf8.DecodeRuneInString(s[i:])
 
@@ -119,7 +119,7 @@ func (e WordEncoder) qEncode(buf *bytes.Buffer, charset, s string) {
 	var currentLen, runeLen int
 	for i := 0; i < len(s); i += runeLen {
 		b := s[i]
-		// Multi-byte characters must not be split accross encoded-words.
+		// Multi-byte characters must not be split across encoded-words.
 		// See RFC 2047, section 5.3.
 		var encLen int
 		if b >= ' ' && b <= '~' && b != '=' && b != '?' && b != '_' {
diff --git a/src/mime/encodedword_test.go b/src/mime/encodedword_test.go
index 5fcd7a0..b7ca4d0 100644
--- a/src/mime/encodedword_test.go
+++ b/src/mime/encodedword_test.go
@@ -31,10 +31,8 @@ func TestEncodeWord(t *testing.T) {
 		{QEncoding, utf8, strings.Repeat("é", 11), "=?utf-8?q?" + strings.Repeat("=C3=A9", 10) + "?= =?utf-8?q?=C3=A9?="},
 		{QEncoding, iso88591, strings.Repeat("\xe9", 22), "=?iso-8859-1?q?" + strings.Repeat("=E9", 22) + "?="},
 		{QEncoding, utf8, strings.Repeat("\x80", 22), "=?utf-8?q?" + strings.Repeat("=80", 21) + "?= =?utf-8?q?=80?="},
-		{BEncoding, utf8, strings.Repeat("é", 24), "=?utf-8?b?" + strings.Repeat("w6nDqcOp", 8) + "?="},
-		{BEncoding, utf8, strings.Repeat("é", 27), "=?utf-8?b?" + strings.Repeat("w6nDqcOp", 8) + "?= =?utf-8?b?w6nDqcOp?="},
 		{BEncoding, iso88591, strings.Repeat("\xe9", 45), "=?iso-8859-1?b?" + strings.Repeat("6enp", 15) + "?="},
-		{BEncoding, utf8, strings.Repeat("\x80", 51), "=?utf-8?b?" + strings.Repeat("gICA", 16) + "?= =?utf-8?b?gICA?="},
+		{BEncoding, utf8, strings.Repeat("\x80", 48), "=?utf-8?b?" + strings.Repeat("gICA", 15) + "?= =?utf-8?b?gICA?="},
 	}
 
 	for _, test := range tests {
@@ -44,6 +42,37 @@ func TestEncodeWord(t *testing.T) {
 	}
 }
 
+func TestEncodedWordLength(t *testing.T) {
+	tests := []struct {
+		enc WordEncoder
+		src string
+	}{
+		{QEncoding, strings.Repeat("à", 30)},
+		{QEncoding, strings.Repeat("é", 60)},
+		{BEncoding, strings.Repeat("ï", 25)},
+		{BEncoding, strings.Repeat("ô", 37)},
+		{BEncoding, strings.Repeat("\x80", 50)},
+		{QEncoding, "{$firstname} Bienvendio a Apostolica, aquà inicia el camino de tu"},
+	}
+
+	for _, test := range tests {
+		s := test.enc.Encode("utf-8", test.src)
+		wordLen := 0
+		for i := 0; i < len(s); i++ {
+			if s[i] == ' ' {
+				wordLen = 0
+				continue
+			}
+
+			wordLen++
+			if wordLen > maxEncodedWordLen {
+				t.Errorf("Encode(%q) has more than %d characters: %q",
+					test.src, maxEncodedWordLen, s)
+			}
+		}
+	}
+}
+
 func TestDecodeWord(t *testing.T) {
 	tests := []struct {
 		src, exp string
@@ -203,6 +232,6 @@ 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!?=")
+		dec.DecodeHeader("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
 	}
 }
diff --git a/src/mime/grammar.go b/src/mime/grammar.go
index 31b66e8..6a6f71d 100644
--- a/src/mime/grammar.go
+++ b/src/mime/grammar.go
@@ -11,7 +11,7 @@ import (
 // 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
+	return strings.ContainsRune(`()<>@,;:\"/[]?=`, r)
 }
 
 // isTokenChar reports whether rune is in 'token' as defined by RFC
diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go
index efee65b..1845401 100644
--- a/src/mime/mediatype.go
+++ b/src/mime/mediatype.go
@@ -221,7 +221,7 @@ func isNotTokenChar(r rune) bool {
 
 // consumeToken consumes a token from the beginning of provided
 // string, per RFC 2045 section 5.1 (referenced from 2183), and return
-// the token consumed and the rest of the string.  Returns ("", v) on
+// the token consumed and the rest of the string. Returns ("", v) on
 // failure to consume at least one character.
 func consumeToken(v string) (token, rest string) {
 	notPos := strings.IndexFunc(v, isNotTokenChar)
@@ -237,7 +237,7 @@ func consumeToken(v string) (token, rest string) {
 // consumeValue consumes a "value" per RFC 2045, where a value is
 // either a 'token' or a 'quoted-string'.  On success, consumeValue
 // returns the value consumed (and de-quoted/escaped, if a
-// quoted-string) and the rest of the string.  On failure, returns
+// quoted-string) and the rest of the string. On failure, returns
 // ("", v).
 func consumeValue(v string) (value, rest string) {
 	if v == "" {
diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go
index eee53fc..8085bd3 100644
--- a/src/mime/multipart/formdata.go
+++ b/src/mime/multipart/formdata.go
@@ -20,7 +20,11 @@ import (
 // a Content-Disposition of "form-data".
 // It stores up to maxMemory bytes of the file parts in memory
 // and the remainder on disk in temporary files.
-func (r *Reader) ReadForm(maxMemory int64) (f *Form, err error) {
+func (r *Reader) ReadForm(maxMemory int64) (*Form, error) {
+	return r.readForm(maxMemory)
+}
+
+func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
 	form := &Form{make(map[string][]string), make(map[string][]*FileHeader)}
 	defer func() {
 		if err != nil {
diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go
index c21c3fc..205348c 100644
--- a/src/mime/multipart/multipart.go
+++ b/src/mime/multipart/multipart.go
@@ -168,13 +168,13 @@ func (pr partReader) Read(d []byte) (n int, err error) {
 	}()
 	if p.buffer.Len() >= len(d) {
 		// Internal buffer of unconsumed data is large enough for
-		// the read request.  No need to parse more at the moment.
+		// the read request. No need to parse more at the moment.
 		return p.buffer.Read(d)
 	}
 	peek, err := p.mr.bufReader.Peek(peekBufferSize) // TODO(bradfitz): add buffer size accessor
 
 	// Look for an immediate empty part without a leading \r\n
-	// before the boundary separator.  Some MIME code makes empty
+	// before the boundary separator. Some MIME code makes empty
 	// parts like this. Most browsers, however, write the \r\n
 	// before the subsequent boundary even for empty parts and
 	// won't hit this path.
@@ -228,7 +228,7 @@ func (p *Part) Close() error {
 }
 
 // Reader is an iterator over parts in a MIME multipart body.
-// Reader's underlying parser consumes its input as needed.  Seeking
+// Reader's underlying parser consumes its input as needed. Seeking
 // isn't supported.
 type Reader struct {
 	bufReader *bufio.Reader
@@ -328,7 +328,7 @@ func (mr *Reader) isBoundaryDelimiterLine(line []byte) (ret bool) {
 	rest = skipLWSPChar(rest)
 
 	// On the first part, see our lines are ending in \n instead of \r\n
-	// and switch into that mode if so.  This is a violation of the spec,
+	// and switch into that mode if so. This is a violation of the spec,
 	// but occurs in practice.
 	if mr.partsRead == 0 && len(rest) == 1 && rest[0] == '\n' {
 		mr.nl = mr.nl[1:]
diff --git a/src/mime/multipart/multipart_test.go b/src/mime/multipart/multipart_test.go
index d06bb41..82a7f86 100644
--- a/src/mime/multipart/multipart_test.go
+++ b/src/mime/multipart/multipart_test.go
@@ -446,8 +446,8 @@ type parseTest struct {
 var parseTests = []parseTest{
 	// Actual body from App Engine on a blob upload. The final part (the
 	// Content-Type: message/external-body) is what App Engine replaces
-	// the uploaded file with.  The other form fields (prefixed with
-	// "other" in their form-data name) are unchanged.  A bug was
+	// the uploaded file with. The other form fields (prefixed with
+	// "other" in their form-data name) are unchanged. A bug was
 	// reported with blob uploads failing when the other fields were
 	// empty. This was the MIME POST body that previously failed.
 	{
diff --git a/src/mime/multipart/writer.go b/src/mime/multipart/writer.go
index 8096093..f82756d 100644
--- a/src/mime/multipart/writer.go
+++ b/src/mime/multipart/writer.go
@@ -11,6 +11,7 @@ import (
 	"fmt"
 	"io"
 	"net/textproto"
+	"sort"
 	"strings"
 )
 
@@ -94,10 +95,14 @@ func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) {
 	} else {
 		fmt.Fprintf(&b, "--%s\r\n", w.boundary)
 	}
-	// TODO(bradfitz): move this to textproto.MimeHeader.Write(w), have it sort
-	// and clean, like http.Header.Write(w) does.
-	for k, vv := range header {
-		for _, v := range vv {
+
+	keys := make([]string, 0, len(header))
+	for k := range header {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	for _, k := range keys {
+		for _, v := range header[k] {
 			fmt.Fprintf(&b, "%s: %s\r\n", k, v)
 		}
 	}
diff --git a/src/mime/multipart/writer_test.go b/src/mime/multipart/writer_test.go
index ba00c97..9670c66 100644
--- a/src/mime/multipart/writer_test.go
+++ b/src/mime/multipart/writer_test.go
@@ -7,6 +7,7 @@ package multipart
 import (
 	"bytes"
 	"io/ioutil"
+	"net/textproto"
 	"strings"
 	"testing"
 )
@@ -126,3 +127,32 @@ func TestWriterBoundaryGoroutines(t *testing.T) {
 	w.Boundary()
 	<-done
 }
+
+func TestSortedHeader(t *testing.T) {
+	var buf bytes.Buffer
+	w := NewWriter(&buf)
+	if err := w.SetBoundary("MIMEBOUNDARY"); err != nil {
+		t.Fatalf("Error setting mime boundary: %v", err)
+	}
+
+	header := textproto.MIMEHeader{
+		"A": {"2"},
+		"B": {"5", "7", "6"},
+		"C": {"4"},
+		"M": {"3"},
+		"Z": {"1"},
+	}
+
+	part, err := w.CreatePart(header)
+	if err != nil {
+		t.Fatalf("Unable to create part: %v", err)
+	}
+	part.Write([]byte("foo"))
+
+	w.Close()
+
+	want := "--MIMEBOUNDARY\r\nA: 2\r\nB: 5\r\nB: 7\r\nB: 6\r\nC: 4\r\nM: 3\r\nZ: 1\r\n\r\nfoo\r\n--MIMEBOUNDARY--\r\n"
+	if want != buf.String() {
+		t.Fatalf("\n got: %q\nwant: %q\n", buf.String(), want)
+	}
+}
diff --git a/src/mime/type_plan9.go b/src/mime/type_plan9.go
index c3ba186..14ff973 100644
--- a/src/mime/type_plan9.go
+++ b/src/mime/type_plan9.go
@@ -21,7 +21,7 @@ func initMimePlan9() {
 }
 
 var typeFiles = []string{
-	"/sys/lib/mimetypes",
+	"/sys/lib/mimetype",
 }
 
 func initMimeForTests() map[string]string {
diff --git a/src/naclmake.bash b/src/naclmake.bash
new file mode 100755
index 0000000..046f50a
--- /dev/null
+++ b/src/naclmake.bash
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Copyright 2016 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# naclmake.bash builds runs make.bash for nacl, but not does run any
+# tests. This is used by the continuous build.
+
+# Assumes that sel_ldr binaries and go_nacl_$GOARCH_exec scripts are in $PATH;
+# see ../misc/nacl/README.
+
+set -e
+ulimit -c 0
+
+# guess GOARCH if not set
+naclGOARCH=$GOARCH
+if [ -z "$naclGOARCH" ]; then
+	case "$(uname -m)" in
+	x86_64)
+		naclGOARCH=amd64p32
+		;;
+	armv7l) # NativeClient on ARM only supports ARMv7A.
+		naclGOARCH=arm
+		;;
+	i?86)
+		naclGOARCH=386
+		;;
+	esac
+fi
+
+unset GOOS GOARCH
+if [ ! -f make.bash ]; then
+	echo 'nacltest.bash must be run from $GOROOT/src' 1>&2
+	exit 1
+fi
+
+# the builder might have set GOROOT_FINAL.
+export GOROOT=$(pwd)/..
+
+# Build zip file embedded in package syscall.
+echo "##### Building fake file system zip for nacl"
+rm -f 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.
+GOOS=nacl GOARCH=$naclGOARCH ./make.bash
diff --git a/src/nacltest.bash b/src/nacltest.bash
index 049aad2..7bbd660 100755
--- a/src/nacltest.bash
+++ b/src/nacltest.bash
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2014 The Go Authors.  All rights reserved.
+# 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.
 
@@ -13,21 +13,7 @@
 set -e
 ulimit -c 0
 
-# guess GOARCH if not set
-naclGOARCH=$GOARCH
-if [ -z "$naclGOARCH" ]; then
-	case "$(uname -m)" in
-	x86_64)
-		naclGOARCH=amd64p32
-		;;
-	armv7l) # NativeClient on ARM only supports ARMv7A.
-		naclGOARCH=arm
-		;;
-	i?86)
-		naclGOARCH=386
-		;;
-	esac
-fi
+. ./naclmake.bash
 
 # Check GOARCH.
 case "$naclGOARCH" in
@@ -59,24 +45,8 @@ if ! which go_nacl_${naclGOARCH}_exec >/dev/null; then
 	exit 1
 fi
 
-unset GOOS GOARCH
-if [ ! -f make.bash ]; then
-	echo 'nacltest.bash must be run from $GOROOT/src' 1>&2
-	exit 1
-fi
-
-# the builder might have set GOROOT_FINAL.
-export GOROOT=$(pwd)/..
-
-# Build zip file embedded in package syscall.
-echo "##### Building fake file system zip for nacl"
-rm -f 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
+export PATH=$(pwd)/../bin:$(pwd)/../misc/nacl:$PATH
+GOROOT=$(../bin/go env GOROOT)
+GOOS=nacl GOARCH=$naclGOARCH go tool dist test --no-rebuild
 
 rm -f syscall/fstest_nacl.go
diff --git a/src/net/addrselect.go b/src/net/addrselect.go
index 58ab7d7..0b9d160 100644
--- a/src/net/addrselect.go
+++ b/src/net/addrselect.go
@@ -203,7 +203,7 @@ func (s *byRFC6724) Less(i, j int) bool {
 		// (e.g., https://golang.org/issue/13283).  Glibc instead only
 		// uses CommonPrefixLen for IPv4 when the source and destination
 		// addresses are on the same subnet, but that requires extra
-		// work to find the netmask for our source addresses.  As a
+		// work to find the netmask for our source addresses. As a
 		// simpler heuristic, we limit its use to when the source and
 		// destination belong to the same special purpose block.
 		if da4 {
diff --git a/src/net/cgo_android.go b/src/net/cgo_android.go
index fe9925b..ab0368d 100644
--- a/src/net/cgo_android.go
+++ b/src/net/cgo_android.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/net/cgo_bsd.go b/src/net/cgo_bsd.go
index c5ec9dd..a923c55 100644
--- a/src/net/cgo_bsd.go
+++ b/src/net/cgo_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/cgo_linux.go b/src/net/cgo_linux.go
index 9a5f898..86d8f4d 100644
--- a/src/net/cgo_linux.go
+++ b/src/net/cgo_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/cgo_netbsd.go b/src/net/cgo_netbsd.go
index 1830913..4610246 100644
--- a/src/net/cgo_netbsd.go
+++ b/src/net/cgo_netbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/cgo_openbsd.go b/src/net/cgo_openbsd.go
index 1830913..4610246 100644
--- a/src/net/cgo_openbsd.go
+++ b/src/net/cgo_openbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/cgo_solaris.go b/src/net/cgo_solaris.go
index dd936dd..25c0721 100644
--- a/src/net/cgo_solaris.go
+++ b/src/net/cgo_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go
index b86ff7d..5125972 100644
--- a/src/net/cgo_stub.go
+++ b/src/net/cgo_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,6 +6,8 @@
 
 package net
 
+import "context"
+
 func init() { netGo = true }
 
 type addrinfoErrno int
@@ -14,22 +16,22 @@ 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) {
+func cgoLookupHost(ctx context.Context, name string) (addrs []string, err error, completed bool) {
 	return nil, nil, false
 }
 
-func cgoLookupPort(network, service string) (port int, err error, completed bool) {
+func cgoLookupPort(ctx context.Context, network, service string) (port int, err error, completed bool) {
 	return 0, nil, false
 }
 
-func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) {
+func cgoLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error, completed bool) {
 	return nil, nil, false
 }
 
-func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
+func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) {
 	return "", nil, false
 }
 
-func cgoLookupPTR(addr string) (ptrs []string, err error, completed bool) {
+func cgoLookupPTR(ctx context.Context, 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 c14f085..5a1eed8 100644
--- a/src/net/cgo_unix.go
+++ b/src/net/cgo_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -19,6 +19,7 @@ package net
 import "C"
 
 import (
+	"context"
 	"syscall"
 	"unsafe"
 )
@@ -32,18 +33,31 @@ func (eai addrinfoErrno) Error() string   { return C.GoString(C.gai_strerror(C.i
 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)
+type portLookupResult struct {
+	port int
+	err  error
+}
+
+type ipLookupResult struct {
+	addrs []IPAddr
+	cname string
+	err   error
+}
+
+type reverseLookupResult struct {
+	names []string
+	err   error
+}
+
+func cgoLookupHost(ctx context.Context, name string) (hosts []string, err error, completed bool) {
+	addrs, err, completed := cgoLookupIP(ctx, name)
 	for _, addr := range addrs {
 		hosts = append(hosts, addr.String())
 	}
 	return
 }
 
-func cgoLookupPort(network, service string) (port int, err error, completed bool) {
-	acquireThread()
-	defer releaseThread()
-
+func cgoLookupPort(ctx context.Context, network, service string) (port int, err error, completed bool) {
 	var hints C.struct_addrinfo
 	switch network {
 	case "": // no hints
@@ -64,11 +78,27 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
 			hints.ai_family = C.AF_INET6
 		}
 	}
+	if ctx.Done() == nil {
+		port, err := cgoLookupServicePort(&hints, network, service)
+		return port, err, true
+	}
+	result := make(chan portLookupResult, 1)
+	go cgoPortLookup(result, &hints, network, service)
+	select {
+	case r := <-result:
+		return r.port, r.err, true
+	case <-ctx.Done():
+		// Since there isn't a portable way to cancel the lookup,
+		// we just let it finish and write to the buffered channel.
+		return 0, mapErr(ctx.Err()), false
+	}
+}
 
+func cgoLookupServicePort(hints *C.struct_addrinfo, network, service string) (port int, err error) {
 	s := C.CString(service)
 	var res *C.struct_addrinfo
 	defer C.free(unsafe.Pointer(s))
-	gerrno, err := C.getaddrinfo(nil, s, &hints, &res)
+	gerrno, err := C.getaddrinfo(nil, s, hints, &res)
 	if gerrno != 0 {
 		switch gerrno {
 		case C.EAI_SYSTEM:
@@ -78,7 +108,7 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
 		default:
 			err = addrinfoErrno(gerrno)
 		}
-		return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}, true
+		return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}
 	}
 	defer C.freeaddrinfo(res)
 
@@ -87,17 +117,22 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
 		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
+			return int(p[0])<<8 | int(p[1]), nil
 		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 int(p[0])<<8 | int(p[1]), nil
 		}
 	}
-	return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}, true
+	return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}
 }
 
-func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) {
+func cgoPortLookup(result chan<- portLookupResult, hints *C.struct_addrinfo, network, service string) {
+	port, err := cgoLookupServicePort(hints, network, service)
+	result <- portLookupResult{port, err}
+}
+
+func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error) {
 	acquireThread()
 	defer releaseThread()
 
@@ -127,7 +162,7 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com
 		default:
 			err = addrinfoErrno(gerrno)
 		}
-		return nil, "", &DNSError{Err: err.Error(), Name: name}, true
+		return nil, "", &DNSError{Err: err.Error(), Name: name}
 	}
 	defer C.freeaddrinfo(res)
 
@@ -156,17 +191,42 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com
 			addrs = append(addrs, addr)
 		}
 	}
-	return addrs, cname, nil, true
+	return addrs, cname, nil
 }
 
-func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) {
-	addrs, _, err, completed = cgoLookupIPCNAME(name)
-	return
+func cgoIPLookup(result chan<- ipLookupResult, name string) {
+	addrs, cname, err := cgoLookupIPCNAME(name)
+	result <- ipLookupResult{addrs, cname, err}
 }
 
-func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
-	_, cname, err, completed = cgoLookupIPCNAME(name)
-	return
+func cgoLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error, completed bool) {
+	if ctx.Done() == nil {
+		addrs, _, err = cgoLookupIPCNAME(name)
+		return addrs, err, true
+	}
+	result := make(chan ipLookupResult, 1)
+	go cgoIPLookup(result, name)
+	select {
+	case r := <-result:
+		return r.addrs, r.err, true
+	case <-ctx.Done():
+		return nil, mapErr(ctx.Err()), false
+	}
+}
+
+func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, completed bool) {
+	if ctx.Done() == nil {
+		_, cname, err = cgoLookupIPCNAME(name)
+		return cname, err, true
+	}
+	result := make(chan ipLookupResult, 1)
+	go cgoIPLookup(result, name)
+	select {
+	case r := <-result:
+		return r.cname, r.err, true
+	case <-ctx.Done():
+		return "", mapErr(ctx.Err()), false
+	}
 }
 
 // These are roughly enough for the following:
@@ -182,10 +242,7 @@ const (
 	maxNameinfoLen = 4096
 )
 
-func cgoLookupPTR(addr string) ([]string, error, bool) {
-	acquireThread()
-	defer releaseThread()
-
+func cgoLookupPTR(ctx context.Context, addr string) (names []string, err error, completed bool) {
 	var zone string
 	ip := parseIPv4(addr)
 	if ip == nil {
@@ -198,9 +255,26 @@ func cgoLookupPTR(addr string) ([]string, error, bool) {
 	if sa == nil {
 		return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true
 	}
-	var err error
-	var b []byte
+	if ctx.Done() == nil {
+		names, err := cgoLookupAddrPTR(addr, sa, salen)
+		return names, err, true
+	}
+	result := make(chan reverseLookupResult, 1)
+	go cgoReverseLookup(result, addr, sa, salen)
+	select {
+	case r := <-result:
+		return r.names, r.err, true
+	case <-ctx.Done():
+		return nil, mapErr(ctx.Err()), false
+	}
+}
+
+func cgoLookupAddrPTR(addr string, sa *C.struct_sockaddr, salen C.socklen_t) (names []string, err error) {
+	acquireThread()
+	defer releaseThread()
+
 	var gerrno int
+	var b []byte
 	for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 {
 		b = make([]byte, l)
 		gerrno, err = cgoNameinfoPTR(b, sa, salen)
@@ -217,16 +291,20 @@ func cgoLookupPTR(addr string) ([]string, error, bool) {
 		default:
 			err = addrinfoErrno(gerrno)
 		}
-		return nil, &DNSError{Err: err.Error(), Name: addr}, true
+		return nil, &DNSError{Err: err.Error(), Name: addr}
 	}
-
 	for i := 0; i < len(b); i++ {
 		if b[i] == 0 {
 			b = b[:i]
 			break
 		}
 	}
-	return []string{absDomainName(b)}, nil, true
+	return []string{absDomainName(b)}, nil
+}
+
+func cgoReverseLookup(result chan<- reverseLookupResult, addr string, sa *C.struct_sockaddr, salen C.socklen_t) {
+	names, err := cgoLookupAddrPTR(addr, sa, salen)
+	result <- reverseLookupResult{names, err}
 }
 
 func cgoSockaddr(ip IP, zone string) (*C.struct_sockaddr, C.socklen_t) {
diff --git a/src/net/cgo_unix_test.go b/src/net/cgo_unix_test.go
index 4d5ab23..e861c7a 100644
--- a/src/net/cgo_unix_test.go
+++ b/src/net/cgo_unix_test.go
@@ -7,18 +7,76 @@
 
 package net
 
-import "testing"
+import (
+	"context"
+	"testing"
+)
 
 func TestCgoLookupIP(t *testing.T) {
-	host := "localhost"
-	_, err, ok := cgoLookupIP(host)
+	ctx := context.Background()
+	_, err, ok := cgoLookupIP(ctx, "localhost")
 	if !ok {
 		t.Errorf("cgoLookupIP must not be a placeholder")
 	}
 	if err != nil {
 		t.Error(err)
 	}
-	if _, err := goLookupIP(host); err != nil {
+}
+
+func TestCgoLookupIPWithCancel(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	_, err, ok := cgoLookupIP(ctx, "localhost")
+	if !ok {
+		t.Errorf("cgoLookupIP must not be a placeholder")
+	}
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func TestCgoLookupPort(t *testing.T) {
+	ctx := context.Background()
+	_, err, ok := cgoLookupPort(ctx, "tcp", "smtp")
+	if !ok {
+		t.Errorf("cgoLookupPort must not be a placeholder")
+	}
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func TestCgoLookupPortWithCancel(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	_, err, ok := cgoLookupPort(ctx, "tcp", "smtp")
+	if !ok {
+		t.Errorf("cgoLookupPort must not be a placeholder")
+	}
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func TestCgoLookupPTR(t *testing.T) {
+	ctx := context.Background()
+	_, err, ok := cgoLookupPTR(ctx, "127.0.0.1")
+	if !ok {
+		t.Errorf("cgoLookupPTR must not be a placeholder")
+	}
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func TestCgoLookupPTRWithCancel(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	_, err, ok := cgoLookupPTR(ctx, "127.0.0.1")
+	if !ok {
+		t.Errorf("cgoLookupPTR must not be a placeholder")
+	}
+	if err != nil {
 		t.Error(err)
 	}
 }
diff --git a/src/net/conf.go b/src/net/conf.go
index ddaa978..eb72916 100644
--- a/src/net/conf.go
+++ b/src/net/conf.go
@@ -124,16 +124,17 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
 			print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n")
 		}()
 	}
+	fallbackOrder := hostLookupCgo
 	if c.netGo {
-		return hostLookupFilesDNS
+		fallbackOrder = hostLookupFilesDNS
 	}
 	if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" {
-		return hostLookupCgo
+		return fallbackOrder
 	}
 	if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 {
 		// Don't deal with special form hostnames with backslashes
 		// or '%'.
-		return hostLookupCgo
+		return fallbackOrder
 	}
 
 	// OpenBSD is unique and doesn't use nsswitch.conf.
@@ -154,7 +155,7 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
 			return hostLookupDNSFiles
 		}
 		if len(lookup) < 1 || len(lookup) > 2 {
-			return hostLookupCgo
+			return fallbackOrder
 		}
 		switch lookup[0] {
 		case "bind":
@@ -162,7 +163,7 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
 				if lookup[1] == "file" {
 					return hostLookupDNSFiles
 				}
-				return hostLookupCgo
+				return fallbackOrder
 			}
 			return hostLookupDNS
 		case "file":
@@ -170,11 +171,11 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
 				if lookup[1] == "bind" {
 					return hostLookupFilesDNS
 				}
-				return hostLookupCgo
+				return fallbackOrder
 			}
 			return hostLookupFiles
 		default:
-			return hostLookupCgo
+			return fallbackOrder
 		}
 	}
 
@@ -185,11 +186,11 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
 		hostname = hostname[:len(hostname)-1]
 	}
 	if stringsHasSuffixFold(hostname, ".local") {
-		// Per RFC 6762, the ".local" TLD is special.  And
+		// 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
+		return fallbackOrder
 	}
 
 	nss := c.nss
@@ -199,7 +200,7 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
 	if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) {
 		if c.goos == "solaris" {
 			// illumos defaults to "nis [NOTFOUND=return] files"
-			return hostLookupCgo
+			return fallbackOrder
 		}
 		if c.goos == "linux" {
 			// glibc says the default is "dns [!UNAVAIL=return] files"
@@ -212,21 +213,21 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
 		// We failed to parse or open nsswitch.conf, so
 		// conservatively assume we should use cgo if it's
 		// available.
-		return hostLookupCgo
+		return fallbackOrder
 	}
 
 	var mdnsSource, filesSource, dnsSource bool
 	var first string
 	for _, src := range srcs {
 		if src.source == "myhostname" {
-			if hasDot {
+			if hostname == "" || hasDot {
 				continue
 			}
-			return hostLookupCgo
+			return fallbackOrder
 		}
 		if src.source == "files" || src.source == "dns" {
 			if !src.standardCriteria() {
-				return hostLookupCgo // non-standard; let libc deal with it.
+				return fallbackOrder // non-standard; let libc deal with it.
 			}
 			if src.source == "files" {
 				filesSource = true
@@ -246,14 +247,14 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
 			continue
 		}
 		// Some source we don't know how to deal with.
-		return hostLookupCgo
+		return fallbackOrder
 	}
 
 	// 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
+		return fallbackOrder
 	}
 
 	// Cases where Go can handle it without cgo and C thread
@@ -272,7 +273,7 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
 	}
 
 	// Something weird. Let libc deal with it.
-	return hostLookupCgo
+	return fallbackOrder
 }
 
 // goDebugNetDNS parses the value of the GODEBUG "netdns" value.
diff --git a/src/net/conf_netcgo.go b/src/net/conf_netcgo.go
index 678361f..db4c703 100644
--- a/src/net/conf_netcgo.go
+++ b/src/net/conf_netcgo.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/net/conf_test.go b/src/net/conf_test.go
index 86904bf..ec8814b 100644
--- a/src/net/conf_test.go
+++ b/src/net/conf_test.go
@@ -32,7 +32,6 @@ func TestConfHostLookupOrder(t *testing.T) {
 	tests := []struct {
 		name      string
 		c         *conf
-		goos      string
 		hostTests []nssHostTest
 	}{
 		{
@@ -48,6 +47,28 @@ func TestConfHostLookupOrder(t *testing.T) {
 			},
 		},
 		{
+			name: "netgo_dns_before_files",
+			c: &conf{
+				netGo:  true,
+				nss:    nssStr("hosts: dns files"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupDNSFiles},
+			},
+		},
+		{
+			name: "netgo_fallback_on_cgo",
+			c: &conf{
+				netGo:  true,
+				nss:    nssStr("hosts: dns files something_custom"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupFilesDNS},
+			},
+		},
+		{
 			name: "ubuntu_trusty_avahi",
 			c: &conf{
 				nss:    nssStr("hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4"),
@@ -236,6 +257,7 @@ func TestConfHostLookupOrder(t *testing.T) {
 			hostTests: []nssHostTest{
 				{"x.com", hostLookupFilesDNS},
 				{"somehostname", hostLookupCgo},
+				{"", hostLookupFilesDNS}, // Issue 13623
 			},
 		},
 		{
diff --git a/src/net/conn_test.go b/src/net/conn_test.go
index 6995c11..16cf69e 100644
--- a/src/net/conn_test.go
+++ b/src/net/conn_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -43,7 +43,7 @@ func TestConnAndListener(t *testing.T) {
 			t.Fatal(err)
 		}
 		defer c.Close()
-		if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+		if c.LocalAddr().Network() != network || c.RemoteAddr().Network() != network {
 			t.Fatalf("got %s->%s; want %s->%s", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
 		}
 		c.SetDeadline(time.Now().Add(someTimeout))
diff --git a/src/net/dial.go b/src/net/dial.go
index 193776f..55edb43 100644
--- a/src/net/dial.go
+++ b/src/net/dial.go
@@ -1,11 +1,12 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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 net
 
 import (
-	"errors"
+	"context"
+	"internal/nettrace"
 	"time"
 )
 
@@ -61,21 +62,34 @@ type Dialer struct {
 	// Cancel is an optional channel whose closure indicates that
 	// the dial should be canceled. Not all types of dials support
 	// cancelation.
+	//
+	// Deprecated: Use DialContext instead.
 	Cancel <-chan struct{}
 }
 
-// Return either now+Timeout or Deadline, whichever comes first.
-// Or zero, if neither is set.
-func (d *Dialer) deadline(now time.Time) time.Time {
-	if d.Timeout == 0 {
-		return d.Deadline
+func minNonzeroTime(a, b time.Time) time.Time {
+	if a.IsZero() {
+		return b
 	}
-	timeoutDeadline := now.Add(d.Timeout)
-	if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) {
-		return timeoutDeadline
-	} else {
-		return d.Deadline
+	if b.IsZero() || a.Before(b) {
+		return a
+	}
+	return b
+}
+
+// deadline returns the earliest of:
+//   - now+Timeout
+//   - d.Deadline
+//   - the context's deadline
+// Or zero, if none of Timeout, Deadline, or context's deadline is set.
+func (d *Dialer) deadline(ctx context.Context, now time.Time) (earliest time.Time) {
+	if d.Timeout != 0 { // including negative, for historical reasons
+		earliest = now.Add(d.Timeout)
+	}
+	if d, ok := ctx.Deadline(); ok {
+		earliest = minNonzeroTime(earliest, d)
 	}
+	return minNonzeroTime(earliest, d.Deadline)
 }
 
 // partialDeadline returns the deadline to use for a single address,
@@ -110,7 +124,7 @@ func (d *Dialer) fallbackDelay() time.Duration {
 	}
 }
 
-func parseNetwork(net string) (afnet string, proto int, err error) {
+func parseNetwork(ctx context.Context, net string) (afnet string, proto int, err error) {
 	i := last(net, ':')
 	if i < 0 { // no colon
 		switch net {
@@ -129,7 +143,7 @@ func parseNetwork(net string) (afnet string, proto int, err error) {
 		protostr := net[i+1:]
 		proto, i, ok := dtoi(protostr, 0)
 		if !ok || i != len(protostr) {
-			proto, err = lookupProtocol(protostr)
+			proto, err = lookupProtocol(ctx, protostr)
 			if err != nil {
 				return "", 0, err
 			}
@@ -139,8 +153,11 @@ func parseNetwork(net string) (afnet string, proto int, err error) {
 	return "", 0, UnknownNetworkError(net)
 }
 
-func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error) {
-	afnet, _, err := parseNetwork(net)
+// resolverAddrList resolves addr using hint and returns a list of
+// addresses. The result contains at least one address when error is
+// nil.
+func resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) {
+	afnet, _, err := parseNetwork(ctx, network)
 	if err != nil {
 		return nil, err
 	}
@@ -149,13 +166,64 @@ func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error)
 	}
 	switch afnet {
 	case "unix", "unixgram", "unixpacket":
+		// TODO(bradfitz): push down context
 		addr, err := ResolveUnixAddr(afnet, addr)
 		if err != nil {
 			return nil, err
 		}
+		if op == "dial" && hint != nil && addr.Network() != hint.Network() {
+			return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()}
+		}
 		return addrList{addr}, nil
 	}
-	return internetAddrList(afnet, addr, deadline)
+	addrs, err := internetAddrList(ctx, afnet, addr)
+	if err != nil || op != "dial" || hint == nil {
+		return addrs, err
+	}
+	var (
+		tcp      *TCPAddr
+		udp      *UDPAddr
+		ip       *IPAddr
+		wildcard bool
+	)
+	switch hint := hint.(type) {
+	case *TCPAddr:
+		tcp = hint
+		wildcard = tcp.isWildcard()
+	case *UDPAddr:
+		udp = hint
+		wildcard = udp.isWildcard()
+	case *IPAddr:
+		ip = hint
+		wildcard = ip.isWildcard()
+	}
+	naddrs := addrs[:0]
+	for _, addr := range addrs {
+		if addr.Network() != hint.Network() {
+			return nil, &AddrError{Err: "mismatched local address type", Addr: hint.String()}
+		}
+		switch addr := addr.(type) {
+		case *TCPAddr:
+			if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(tcp.IP) {
+				continue
+			}
+			naddrs = append(naddrs, addr)
+		case *UDPAddr:
+			if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(udp.IP) {
+				continue
+			}
+			naddrs = append(naddrs, addr)
+		case *IPAddr:
+			if !wildcard && !addr.isWildcard() && !addr.IP.matchAddrFamily(ip.IP) {
+				continue
+			}
+			naddrs = append(naddrs, addr)
+		}
+	}
+	if len(naddrs) == 0 {
+		return nil, errNoSuitableAddress
+	}
+	return naddrs, nil
 }
 
 // Dial connects to the address on the named network.
@@ -173,8 +241,8 @@ func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error)
 // If the host is empty, as in ":80", the local system is assumed.
 //
 // Examples:
-//	Dial("tcp", "12.34.56.78:80")
-//	Dial("tcp", "google.com:http")
+//	Dial("tcp", "192.0.2.1:80")
+//	Dial("tcp", "golang.org:http")
 //	Dial("tcp", "[2001:db8::1]:http")
 //	Dial("tcp", "[fe80::1%lo0]:80")
 //	Dial("tcp", ":80")
@@ -184,8 +252,8 @@ func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error)
 // literal IP address.
 //
 // Examples:
-//	Dial("ip4:1", "127.0.0.1")
-//	Dial("ip6:ospf", "::1")
+//	Dial("ip4:1", "192.0.2.1")
+//	Dial("ip6:ipv6-icmp", "2001:db8::1")
 //
 // For Unix networks, the address must be a file system path.
 func Dial(network, address string) (Conn, error) {
@@ -200,11 +268,10 @@ 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 {
+// dialParam contains a Dial's parameters and configuration.
+type dialParam struct {
 	Dialer
 	network, address string
-	finalDeadline    time.Time
 }
 
 // Dial connects to the address on the named network.
@@ -212,17 +279,62 @@ type dialContext struct {
 // See func Dial for a description of the network and address
 // parameters.
 func (d *Dialer) Dial(network, address string) (Conn, error) {
-	finalDeadline := d.deadline(time.Now())
-	addrs, err := resolveAddrList("dial", network, address, finalDeadline)
+	return d.DialContext(context.Background(), network, address)
+}
+
+// DialContext connects to the address on the named network using
+// the provided context.
+//
+// The provided Context must be non-nil. If the context expires before
+// the connection is complete, an error is returned. Once successfully
+// connected, any expiration of the context will not affect the
+// connection.
+//
+// See func Dial for a description of the network and address
+// parameters.
+func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn, error) {
+	if ctx == nil {
+		panic("nil context")
+	}
+	deadline := d.deadline(ctx, time.Now())
+	if !deadline.IsZero() {
+		if d, ok := ctx.Deadline(); !ok || deadline.Before(d) {
+			subCtx, cancel := context.WithDeadline(ctx, deadline)
+			defer cancel()
+			ctx = subCtx
+		}
+	}
+	if oldCancel := d.Cancel; oldCancel != nil {
+		subCtx, cancel := context.WithCancel(ctx)
+		defer cancel()
+		go func() {
+			select {
+			case <-oldCancel:
+				cancel()
+			case <-subCtx.Done():
+			}
+		}()
+		ctx = subCtx
+	}
+
+	// Shadow the nettrace (if any) during resolve so Connect events don't fire for DNS lookups.
+	resolveCtx := ctx
+	if trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace); trace != nil {
+		shadow := *trace
+		shadow.ConnectStart = nil
+		shadow.ConnectDone = nil
+		resolveCtx = context.WithValue(resolveCtx, nettrace.TraceKey{}, &shadow)
+	}
+
+	addrs, err := resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr)
 	if err != nil {
 		return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
 	}
 
-	ctx := &dialContext{
-		Dialer:        *d,
-		network:       network,
-		address:       address,
-		finalDeadline: finalDeadline,
+	dp := &dialParam{
+		Dialer:  *d,
+		network: network,
+		address: address,
 	}
 
 	var primaries, fallbacks addrList
@@ -233,116 +345,128 @@ func (d *Dialer) Dial(network, address string) (Conn, error) {
 	}
 
 	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)
+	if len(fallbacks) > 0 {
+		c, err = dialParallel(ctx, dp, primaries, fallbacks)
 	} else {
-		c, err = dialParallel(ctx, primaries, fallbacks)
+		c, err = dialSerial(ctx, dp, primaries)
+	}
+	if err != nil {
+		return nil, err
 	}
 
-	if d.KeepAlive > 0 && err == nil {
-		if tc, ok := c.(*TCPConn); ok {
-			setKeepAlive(tc.fd, true)
-			setKeepAlivePeriod(tc.fd, d.KeepAlive)
-			testHookSetKeepAlive()
-		}
+	if tc, ok := c.(*TCPConn); ok && d.KeepAlive > 0 {
+		setKeepAlive(tc.fd, true)
+		setKeepAlivePeriod(tc.fd, d.KeepAlive)
+		testHookSetKeepAlive()
 	}
-	return c, err
+	return c, nil
 }
 
 // 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)
-
-	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
-		}
+func dialParallel(ctx context.Context, dp *dialParam, primaries, fallbacks addrList) (Conn, error) {
+	if len(fallbacks) == 0 {
+		return dialSerial(ctx, dp, primaries)
 	}
-	return nil, primaryErr
-}
 
-type dialResult struct {
-	Conn
-	error
-	primary bool
-}
+	returned := make(chan struct{})
+	defer close(returned)
+
+	type dialResult struct {
+		Conn
+		error
+		primary bool
+		done    bool
+	}
+	results := make(chan dialResult) // unbuffered
 
-// 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.
+	startRacer := func(ctx context.Context, primary bool) {
+		ras := primaries
+		if !primary {
+			ras = fallbacks
+		}
+		c, err := dialSerial(ctx, dp, ras)
 		select {
-		case <-timer.C:
-		case <-cancel:
-			return
+		case results <- dialResult{Conn: c, error: err, primary: primary, done: true}:
+		case <-returned:
+			if c != nil {
+				c.Close()
+			}
 		}
 	}
-	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()
+
+	var primary, fallback dialResult
+
+	// Start the main racer.
+	primaryCtx, primaryCancel := context.WithCancel(ctx)
+	defer primaryCancel()
+	go startRacer(primaryCtx, true)
+
+	// Start the timer for the fallback racer.
+	fallbackTimer := time.NewTimer(dp.fallbackDelay())
+	defer fallbackTimer.Stop()
+
+	for {
+		select {
+		case <-fallbackTimer.C:
+			fallbackCtx, fallbackCancel := context.WithCancel(ctx)
+			defer fallbackCancel()
+			go startRacer(fallbackCtx, false)
+
+		case res := <-results:
+			if res.error == nil {
+				return res.Conn, nil
+			}
+			if res.primary {
+				primary = res
+			} else {
+				fallback = res
+			}
+			if primary.done && fallback.done {
+				return nil, primary.error
+			}
+			if res.primary && fallbackTimer.Stop() {
+				// If we were able to stop the timer, that means it
+				// was running (hadn't yet started the fallback), but
+				// we just got an error on the primary path, so start
+				// the fallback immediately (in 0 nanoseconds).
+				fallbackTimer.Reset(0)
+			}
 		}
 	}
 }
 
 // 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) {
+func dialSerial(ctx context.Context, dp *dialParam, ras addrList) (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}
+		case <-ctx.Done():
+			return nil, &OpError{Op: "dial", Net: dp.network, Source: dp.LocalAddr, Addr: ra, Err: mapErr(ctx.Err())}
 		default:
 		}
 
-		partialDeadline, err := partialDeadline(time.Now(), ctx.finalDeadline, len(ras)-i)
+		deadline, _ := ctx.Deadline()
+		partialDeadline, err := partialDeadline(time.Now(), deadline, 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}
+				firstErr = &OpError{Op: "dial", Net: dp.network, Source: dp.LocalAddr, Addr: ra, Err: err}
 			}
 			break
 		}
-
-		// 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)
+		dialCtx := ctx
+		if partialDeadline.Before(deadline) {
+			var cancel context.CancelFunc
+			dialCtx, cancel = context.WithDeadline(ctx, partialDeadline)
+			defer cancel()
 		}
-		c, err := dial(ctx.network, ra, dialer, partialDeadline)
+
+		c, err := dialSingle(dialCtx, dp, ra)
 		if err == nil {
 			return c, nil
 		}
@@ -352,37 +476,43 @@ func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, e
 	}
 
 	if firstErr == nil {
-		firstErr = &OpError{Op: "dial", Net: ctx.network, Source: nil, Addr: nil, Err: errMissingAddress}
+		firstErr = &OpError{Op: "dial", Net: dp.network, Source: nil, Addr: nil, Err: errMissingAddress}
 	}
 	return nil, firstErr
 }
 
 // dialSingle attempts to establish and returns a single connection to
-// 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: ctx.network, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
+// the destination address.
+func dialSingle(ctx context.Context, dp *dialParam, ra Addr) (c Conn, err error) {
+	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
+	if trace != nil {
+		raStr := ra.String()
+		if trace.ConnectStart != nil {
+			trace.ConnectStart(dp.network, raStr)
+		}
+		if trace.ConnectDone != nil {
+			defer func() { trace.ConnectDone(dp.network, raStr, err) }()
+		}
 	}
+	la := dp.LocalAddr
 	switch ra := ra.(type) {
 	case *TCPAddr:
 		la, _ := la.(*TCPAddr)
-		c, err = testHookDialTCP(ctx.network, la, ra, deadline, ctx.Cancel)
+		c, err = dialTCP(ctx, dp.network, la, ra)
 	case *UDPAddr:
 		la, _ := la.(*UDPAddr)
-		c, err = dialUDP(ctx.network, la, ra, deadline)
+		c, err = dialUDP(ctx, dp.network, la, ra)
 	case *IPAddr:
 		la, _ := la.(*IPAddr)
-		c, err = dialIP(ctx.network, la, ra, deadline)
+		c, err = dialIP(ctx, dp.network, la, ra)
 	case *UnixAddr:
 		la, _ := la.(*UnixAddr)
-		c, err = dialUnix(ctx.network, la, ra, deadline)
+		c, err = dialUnix(ctx, dp.network, la, ra)
 	default:
-		return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: ctx.address}}
+		return nil, &OpError{Op: "dial", Net: dp.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: dp.address}}
 	}
 	if err != nil {
-		return nil, err // c is non-nil interface containing nil pointer
+		return nil, &OpError{Op: "dial", Net: dp.network, Source: la, Addr: ra, Err: err} // c is non-nil interface containing nil pointer
 	}
 	return c, nil
 }
@@ -395,7 +525,7 @@ func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err erro
 // instead of just the interface with the given host address.
 // See Dial for more details about address syntax.
 func Listen(net, laddr string) (Listener, error) {
-	addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
+	addrs, err := resolveAddrList(context.Background(), "listen", net, laddr, nil)
 	if err != nil {
 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
 	}
@@ -422,7 +552,7 @@ func Listen(net, laddr string) (Listener, error) {
 // instead of just the interface with the given host address.
 // See Dial for the syntax of laddr.
 func ListenPacket(net, laddr string) (PacketConn, error) {
-	addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
+	addrs, err := resolveAddrList(context.Background(), "listen", net, laddr, nil)
 	if err != nil {
 		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
 	}
diff --git a/src/net/dial_gen.go b/src/net/dial_gen.go
deleted file mode 100644
index a628f71..0000000
--- a/src/net/dial_gen.go
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build windows plan9
-
-package net
-
-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) {
-	if deadline.IsZero() {
-		return dialer(noDeadline)
-	}
-	timeout := deadline.Sub(time.Now())
-	if timeout <= 0 {
-		return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
-	}
-	t := time.NewTimer(timeout)
-	defer t.Stop()
-	type racer struct {
-		Conn
-		error
-	}
-	ch := make(chan racer, 1)
-	go func() {
-		testHookDialChannel()
-		c, err := dialer(noDeadline)
-		ch <- racer{c, err}
-	}()
-	select {
-	case <-t.C:
-		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_test.go b/src/net/dial_test.go
index 2311b10..9fe507e 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -5,6 +5,8 @@
 package net
 
 import (
+	"bufio"
+	"context"
 	"internal/testenv"
 	"io"
 	"net/internal/socktest"
@@ -23,13 +25,12 @@ var prohibitionaryDialArgTests = []struct {
 }
 
 func TestProhibitionaryDialArg(t *testing.T) {
+	testenv.MustHaveExternalNetwork(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")
 	}
@@ -54,56 +55,12 @@ func TestProhibitionaryDialArg(t *testing.T) {
 	}
 }
 
-func TestSelfConnect(t *testing.T) {
-	if runtime.GOOS == "windows" {
-		// TODO(brainman): do not know why it hangs.
-		t.Skip("known-broken test on windows")
-	}
-
-	// Test that Dial does not honor self-connects.
-	// See the comment in DialTCP.
-
-	// Find a port that would be used as a local address.
-	l, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	c, err := Dial("tcp", l.Addr().String())
-	if err != nil {
-		t.Fatal(err)
-	}
-	addr := c.LocalAddr().String()
-	c.Close()
-	l.Close()
-
-	// Try to connect to that address repeatedly.
-	n := 100000
-	if testing.Short() {
-		n = 1000
-	}
-	switch runtime.GOOS {
-	case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
-		// Non-Linux systems take a long time to figure
-		// out that there is nothing listening on localhost.
-		n = 100
-	}
-	for i := 0; i < n; i++ {
-		c, err := DialTimeout("tcp", addr, time.Millisecond)
-		if err == nil {
-			if c.LocalAddr().String() == addr {
-				t.Errorf("#%d: Dial %q self-connect", i, addr)
-			} else {
-				t.Logf("#%d: Dial %q succeeded - possibly racing with other listener", i, addr)
-			}
-			c.Close()
-		}
-	}
-}
-
 func TestDialTimeoutFDLeak(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	case "openbsd":
+		testenv.SkipFlaky(t, 15157)
 	}
 
 	const T = 100 * time.Millisecond
@@ -130,17 +87,14 @@ func TestDialTimeoutFDLeak(t *testing.T) {
 	// 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()
-	}()
+	defer func() { sw.Set(socktest.FilterClose, nil) }()
 	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
+		return nil, nil
 	})
 
 	const N = 100
@@ -176,6 +130,12 @@ func TestDialerDualStackFDLeak(t *testing.T) {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
 
+	closedPortDelay, expectClosedPortDelay := dialClosedPort()
+	if closedPortDelay > expectClosedPortDelay {
+		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
+	}
+
+	before := sw.Sockets()
 	origTestHookLookupIP := testHookLookupIP
 	defer func() { testHookLookupIP = origTestHookLookupIP }()
 	testHookLookupIP = lookupLocalhost
@@ -188,24 +148,19 @@ func TestDialerDualStackFDLeak(t *testing.T) {
 			c.Close()
 		}
 	}
-	dss, err := newDualStackServer([]streamListener{
-		{network: "tcp4", address: "127.0.0.1"},
-		{network: "tcp6", address: "::1"},
-	})
+	dss, err := newDualStackServer()
 	if err != nil {
 		t.Fatal(err)
 	}
-	defer dss.teardown()
 	if err := dss.buildup(handler); err != nil {
+		dss.teardown()
 		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}
+	d := &Dialer{DualStack: true, Timeout: 100*time.Millisecond + closedPortDelay}
 	for i := 0; i < N; i++ {
 		go func() {
 			defer wg.Done()
@@ -218,7 +173,7 @@ func TestDialerDualStackFDLeak(t *testing.T) {
 		}()
 	}
 	wg.Wait()
-	time.Sleep(2 * T) // wait for the dial racers to stop
+	dss.teardown()
 	after := sw.Sockets()
 	if len(after) != len(before) {
 		t.Errorf("got %d; want %d", len(after), len(before))
@@ -229,18 +184,18 @@ func TestDialerDualStackFDLeak(t *testing.T) {
 // 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
+	slowDst4 = "198.18.0.254"
+	slowDst6 = "2001:2::254"
 )
 
 // 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, cancel <-chan struct{}) (*TCPConn, error) {
-	c, err := dialTCP(net, laddr, raddr, deadline, cancel)
+func slowDialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+	c, err := doDialTCP(ctx, net, laddr, raddr)
 	if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
-		time.Sleep(deadline.Sub(time.Now()))
+		// Wait for the deadline, or indefinitely if none exists.
+		<-ctx.Done()
 	}
 	return c, err
 }
@@ -278,9 +233,8 @@ func dialClosedPort() (actual, expected time.Duration) {
 }
 
 func TestDialParallel(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
+
 	if !supportsIPv4 || !supportsIPv6 {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
@@ -294,7 +248,7 @@ func TestDialParallel(t *testing.T) {
 	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
+	// or trigger the fallbackDelay on Windows. This value holds the
 	// lesser of the two delays.
 	var closedPortOrFallbackDelay time.Duration
 	if closedPortDelay < fallbackDelay {
@@ -369,10 +323,7 @@ func TestDialParallel(t *testing.T) {
 	}
 
 	for i, tt := range testCases {
-		dss, err := newDualStackServer([]streamListener{
-			{network: "tcp4", address: "127.0.0.1"},
-			{network: "tcp6", address: "::1"},
-		})
+		dss, err := newDualStackServer()
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -389,17 +340,15 @@ func TestDialParallel(t *testing.T) {
 		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)
+		dp := &dialParam{
+			Dialer:  d,
+			network: "tcp",
+			address: "?",
+		}
+		c, err := dialParallel(context.Background(), dp, primaries, fallbacks)
+		elapsed := time.Since(startTime)
 
 		if c != nil {
 			c.Close()
@@ -418,12 +367,30 @@ func TestDialParallel(t *testing.T) {
 		} else if !(elapsed <= expectElapsedMax) {
 			t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
 		}
+
+		// Repeat each case, ensuring that it can be canceled quickly.
+		ctx, cancel := context.WithCancel(context.Background())
+		var wg sync.WaitGroup
+		wg.Add(1)
+		go func() {
+			time.Sleep(5 * time.Millisecond)
+			cancel()
+			wg.Done()
+		}()
+		startTime = time.Now()
+		c, err = dialParallel(ctx, dp, primaries, fallbacks)
+		if c != nil {
+			c.Close()
+		}
+		elapsed = time.Now().Sub(startTime)
+		if elapsed > 100*time.Millisecond {
+			t.Errorf("#%d (cancel): got %v; want <= 100ms", i, elapsed)
+		}
+		wg.Wait()
 	}
-	// Wait for any slowDst4/slowDst6 connections to timeout.
-	time.Sleep(slowTimeout * 3 / 2)
 }
 
-func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+func lookupSlowFast(ctx context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
 	switch host {
 	case "slow6loopback4":
 		// Returns a slow IPv6 address, and a local IPv4 address.
@@ -432,14 +399,13 @@ func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, e
 			{IP: ParseIP("127.0.0.1")},
 		}, nil
 	default:
-		return fn(host)
+		return fn(ctx, host)
 	}
 }
 
 func TestDialerFallbackDelay(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
+
 	if !supportsIPv4 || !supportsIPv6 {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
@@ -463,8 +429,6 @@ func TestDialerFallbackDelay(t *testing.T) {
 		{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},
 	}
 
 	handler := func(dss *dualStackServer, ln Listener) {
@@ -476,9 +440,7 @@ func TestDialerFallbackDelay(t *testing.T) {
 			c.Close()
 		}
 	}
-	dss, err := newDualStackServer([]streamListener{
-		{network: "tcp", address: "127.0.0.1"},
-	})
+	dss, err := newDualStackServer()
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -488,7 +450,7 @@ func TestDialerFallbackDelay(t *testing.T) {
 	}
 
 	for i, tt := range testCases {
-		d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout}
+		d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay}
 
 		startTime := time.Now()
 		c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
@@ -509,46 +471,78 @@ func TestDialerFallbackDelay(t *testing.T) {
 	}
 }
 
-func TestDialSerialAsyncSpuriousConnection(t *testing.T) {
-	if runtime.GOOS == "plan9" {
-		t.Skip("skipping on plan9; no deadline support, golang.org/issue/11932")
+func TestDialParallelSpuriousConnection(t *testing.T) {
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
 	}
-	ln, err := newLocalListener("tcp")
+
+	var wg sync.WaitGroup
+	wg.Add(2)
+	handler := func(dss *dualStackServer, ln Listener) {
+		// Accept one connection per address.
+		c, err := ln.Accept()
+		if err != nil {
+			t.Fatal(err)
+		}
+		// The client 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)
+		}
+		c.Close()
+		wg.Done()
+	}
+	dss, err := newDualStackServer()
 	if err != nil {
 		t.Fatal(err)
 	}
-	defer ln.Close()
+	defer dss.teardown()
+	if err := dss.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	const fallbackDelay = 100 * time.Millisecond
+
+	origTestHookDialTCP := testHookDialTCP
+	defer func() { testHookDialTCP = origTestHookDialTCP }()
+	testHookDialTCP = func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+		// Sleep long enough for Happy Eyeballs to kick in, and inhibit cancelation.
+		// This forces dialParallel to juggle two successful connections.
+		time.Sleep(fallbackDelay * 2)
 
-	d := Dialer{}
-	ctx := &dialContext{
-		Dialer:        d,
-		network:       "tcp",
-		address:       "?",
-		finalDeadline: d.deadline(time.Now()),
+		// Now ignore the provided context (which will be canceled) and use a
+		// different one to make sure this completes with a valid connection,
+		// which we hope to be closed below:
+		return doDialTCP(context.Background(), net, laddr, raddr)
 	}
 
-	results := make(chan dialResult)
-	cancel := make(chan struct{})
+	d := Dialer{
+		FallbackDelay: fallbackDelay,
+	}
+	dp := &dialParam{
+		Dialer:  d,
+		network: "tcp",
+		address: "?",
+	}
 
-	// Spawn a connection in the background.
-	go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results)
+	makeAddr := func(ip string) addrList {
+		addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, dss.port))
+		if err != nil {
+			t.Fatal(err)
+		}
+		return addrList{addr}
+	}
 
-	// Receive it at the server.
-	c, err := ln.Accept()
+	// dialParallel returns one connection (and closes the other.)
+	c, err := dialParallel(context.Background(), dp, makeAddr("127.0.0.1"), makeAddr("::1"))
 	if err != nil {
 		t.Fatal(err)
 	}
-	defer c.Close()
-
-	// Tell dialSerialAsync that someone else won the race.
-	close(cancel)
+	c.Close()
 
-	// 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)
-	}
+	// The server should've seen both connections.
+	wg.Wait()
 }
 
 func TestDialerPartialDeadline(t *testing.T) {
@@ -587,40 +581,116 @@ func TestDialerPartialDeadline(t *testing.T) {
 }
 
 func TestDialerLocalAddr(t *testing.T) {
-	ch := make(chan error, 1)
-	handler := func(ls *localServer, ln Listener) {
-		c, err := ln.Accept()
-		if err != nil {
-			ch <- err
-			return
-		}
-		defer c.Close()
-		ch <- nil
-	}
-	ls, err := newLocalServer("tcp")
-	if err != nil {
-		t.Fatal(err)
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
 	}
-	defer ls.teardown()
-	if err := ls.buildup(handler); err != nil {
-		t.Fatal(err)
+
+	type test struct {
+		network, raddr string
+		laddr          Addr
+		error
+	}
+	var tests = []test{
+		{"tcp4", "127.0.0.1", nil, nil},
+		{"tcp4", "127.0.0.1", &TCPAddr{}, nil},
+		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
+		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
+		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"}},
+		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
+		{"tcp4", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
+		{"tcp4", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
+		{"tcp4", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
+		{"tcp4", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
+
+		{"tcp6", "::1", nil, nil},
+		{"tcp6", "::1", &TCPAddr{}, nil},
+		{"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
+		{"tcp6", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
+		{"tcp6", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
+		{"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
+		{"tcp6", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
+		{"tcp6", "::1", &TCPAddr{IP: IPv6loopback}, nil},
+		{"tcp6", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
+		{"tcp6", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
+
+		{"tcp", "127.0.0.1", nil, nil},
+		{"tcp", "127.0.0.1", &TCPAddr{}, nil},
+		{"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
+		{"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
+		{"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, nil},
+		{"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, nil},
+		{"tcp", "127.0.0.1", &TCPAddr{IP: IPv6loopback}, errNoSuitableAddress},
+		{"tcp", "127.0.0.1", &UDPAddr{}, &AddrError{Err: "some error"}},
+		{"tcp", "127.0.0.1", &UnixAddr{}, &AddrError{Err: "some error"}},
+
+		{"tcp", "::1", nil, nil},
+		{"tcp", "::1", &TCPAddr{}, nil},
+		{"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0")}, nil},
+		{"tcp", "::1", &TCPAddr{IP: ParseIP("0.0.0.0").To4()}, nil},
+		{"tcp", "::1", &TCPAddr{IP: ParseIP("::")}, nil},
+		{"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To4()}, errNoSuitableAddress},
+		{"tcp", "::1", &TCPAddr{IP: ParseIP("127.0.0.1").To16()}, errNoSuitableAddress},
+		{"tcp", "::1", &TCPAddr{IP: IPv6loopback}, nil},
+		{"tcp", "::1", &UDPAddr{}, &AddrError{Err: "some error"}},
+		{"tcp", "::1", &UnixAddr{}, &AddrError{Err: "some error"}},
+	}
+
+	if supportsIPv4map {
+		tests = append(tests, test{
+			"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, nil,
+		})
+	} else {
+		tests = append(tests, test{
+			"tcp", "127.0.0.1", &TCPAddr{IP: ParseIP("::")}, &AddrError{Err: "some error"},
+		})
 	}
 
-	laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
-	if err != nil {
-		t.Fatal(err)
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+	handler := func(ls *localServer, ln Listener) {
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				return
+			}
+			c.Close()
+		}
 	}
-	laddr.Port = 0
-	d := &Dialer{LocalAddr: laddr}
-	c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String())
-	if err != nil {
-		t.Fatal(err)
+	var err error
+	var lss [2]*localServer
+	for i, network := range []string{"tcp4", "tcp6"} {
+		lss[i], err = newLocalServer(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer lss[i].teardown()
+		if err := lss[i].buildup(handler); err != nil {
+			t.Fatal(err)
+		}
 	}
-	defer c.Close()
-	c.Read(make([]byte, 1))
-	err = <-ch
-	if err != nil {
-		t.Error(err)
+
+	for _, tt := range tests {
+		d := &Dialer{LocalAddr: tt.laddr}
+		var addr string
+		ip := ParseIP(tt.raddr)
+		if ip.To4() != nil {
+			addr = lss[0].Listener.Addr().String()
+		}
+		if ip.To16() != nil && ip.To4() == nil {
+			addr = lss[1].Listener.Addr().String()
+		}
+		c, err := d.Dial(tt.network, addr)
+		if err == nil && tt.error != nil || err != nil && tt.error == nil {
+			t.Errorf("%s %v->%s: got %v; want %v", tt.network, tt.laddr, tt.raddr, err, tt.error)
+		}
+		if err != nil {
+			if perr := parseDialError(err); perr != nil {
+				t.Error(perr)
+			}
+			continue
+		}
+		c.Close()
 	}
 }
 
@@ -649,10 +719,7 @@ func TestDialerDualStack(t *testing.T) {
 
 	var timeout = 150*time.Millisecond + closedPortDelay
 	for _, dualstack := range []bool{false, true} {
-		dss, err := newDualStackServer([]streamListener{
-			{network: "tcp4", address: "127.0.0.1"},
-			{network: "tcp6", address: "::1"},
-		})
+		dss, err := newDualStackServer()
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -677,7 +744,6 @@ func TestDialerDualStack(t *testing.T) {
 			c.Close()
 		}
 	}
-	time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop
 }
 
 func TestDialerKeepAlive(t *testing.T) {
@@ -719,14 +785,16 @@ func TestDialerKeepAlive(t *testing.T) {
 }
 
 func TestDialCancel(t *testing.T) {
-	if runtime.GOOS == "plan9" || runtime.GOOS == "nacl" {
-		// plan9 is not implemented and nacl doesn't have
-		// external network access.
-		t.Skipf("skipping on %s", runtime.GOOS)
+	switch testenv.Builder() {
+	case "linux-arm64-buildlet":
+		t.Skip("skipping on linux-arm64-buildlet; incompatible network config? issue 15191")
+	case "":
+		testenv.MustHaveExternalNetwork(t)
 	}
-	onGoBuildFarm := testenv.Builder() != ""
-	if testing.Short() && !onGoBuildFarm {
-		t.Skip("skipping in short mode")
+
+	if runtime.GOOS == "nacl" {
+		// nacl doesn't have external network access.
+		t.Skipf("skipping on %s", runtime.GOOS)
 	}
 
 	blackholeIPPort := JoinHostPort(slowDst4, "1234")
@@ -781,3 +849,84 @@ func TestDialCancel(t *testing.T) {
 		}
 	}
 }
+
+func TestCancelAfterDial(t *testing.T) {
+	if testing.Short() {
+		t.Skip("avoiding time.Sleep")
+	}
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var wg sync.WaitGroup
+	wg.Add(1)
+	defer func() {
+		ln.Close()
+		wg.Wait()
+	}()
+
+	// Echo back the first line of each incoming connection.
+	go func() {
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				break
+			}
+			rb := bufio.NewReader(c)
+			line, err := rb.ReadString('\n')
+			if err != nil {
+				t.Error(err)
+				c.Close()
+				continue
+			}
+			if _, err := c.Write([]byte(line)); err != nil {
+				t.Error(err)
+			}
+			c.Close()
+		}
+		wg.Done()
+	}()
+
+	try := func() {
+		cancel := make(chan struct{})
+		d := &Dialer{Cancel: cancel}
+		c, err := d.Dial("tcp", ln.Addr().String())
+
+		// Immediately after dialing, request cancelation and sleep.
+		// Before Issue 15078 was fixed, this would cause subsequent operations
+		// to fail with an i/o timeout roughly 50% of the time.
+		close(cancel)
+		time.Sleep(10 * time.Millisecond)
+
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer c.Close()
+
+		// Send some data to confirm that the connection is still alive.
+		const message = "echo!\n"
+		if _, err := c.Write([]byte(message)); err != nil {
+			t.Fatal(err)
+		}
+
+		// The server should echo the line, and close the connection.
+		rb := bufio.NewReader(c)
+		line, err := rb.ReadString('\n')
+		if err != nil {
+			t.Fatal(err)
+		}
+		if line != message {
+			t.Errorf("got %q; want %q", line, message)
+		}
+		if _, err := rb.ReadByte(); err != io.EOF {
+			t.Errorf("got %v; want %v", err, io.EOF)
+		}
+	}
+
+	// This bug manifested about 50% of the time, so try it a few times.
+	for i := 0; i < 10; i++ {
+		try()
+	}
+}
diff --git a/src/net/dnsclient.go b/src/net/dnsclient.go
index 5dc2a03..f1835b8 100644
--- a/src/net/dnsclient.go
+++ b/src/net/dnsclient.go
@@ -45,7 +45,7 @@ func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs
 	}
 	if dns.rcode != dnsRcodeSuccess {
 		// None of the error codes make sense
-		// for the query we sent.  If we didn't get
+		// for the query we sent. If we didn't get
 		// a name error and we didn't get success,
 		// the server is behaving incorrectly or
 		// having temporary trouble.
@@ -161,7 +161,7 @@ func isDomainName(s string) bool {
 	return ok
 }
 
-// absDomainName returns an absoulte domain name which ends with a
+// absDomainName returns an absolute domain name which ends with a
 // trailing dot to match pure Go reverse resolver and all other lookup
 // routines.
 // See golang.org/issue/12189.
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 17188f0..8f2dff4 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -16,6 +16,7 @@
 package net
 
 import (
+	"context"
 	"errors"
 	"io"
 	"math/rand"
@@ -26,10 +27,10 @@ import (
 
 // A dnsDialer provides dialing suitable for DNS queries.
 type dnsDialer interface {
-	dialDNS(string, string) (dnsConn, error)
+	dialDNS(ctx context.Context, network, addr string) (dnsConn, error)
 }
 
-var testHookDNSDialer = func(d time.Duration) dnsDialer { return &Dialer{Timeout: d} }
+var testHookDNSDialer = func() dnsDialer { return &Dialer{} }
 
 // A dnsConn represents a DNS transport endpoint.
 type dnsConn interface {
@@ -37,46 +38,67 @@ type dnsConn interface {
 
 	SetDeadline(time.Time) error
 
-	// readDNSResponse reads a DNS response message from the DNS
-	// transport endpoint and returns the received DNS response
-	// message.
-	readDNSResponse() (*dnsMsg, error)
+	// dnsRoundTrip executes a single DNS transaction, returning a
+	// DNS response message for the provided DNS query message.
+	dnsRoundTrip(query *dnsMsg) (*dnsMsg, error)
+}
 
-	// writeDNSQuery writes a DNS query message to the DNS
-	// connection endpoint.
-	writeDNSQuery(*dnsMsg) error
+func (c *UDPConn) dnsRoundTrip(query *dnsMsg) (*dnsMsg, error) {
+	return dnsRoundTripUDP(c, query)
 }
 
-func (c *UDPConn) readDNSResponse() (*dnsMsg, error) {
-	b := make([]byte, 512) // see RFC 1035
-	n, err := c.Read(b)
-	if err != nil {
+// dnsRoundTripUDP implements the dnsRoundTrip interface for RFC 1035's
+// "UDP usage" transport mechanism. c should be a packet-oriented connection,
+// such as a *UDPConn.
+func dnsRoundTripUDP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) {
+	b, ok := query.Pack()
+	if !ok {
+		return nil, errors.New("cannot marshal DNS message")
+	}
+	if _, err := c.Write(b); err != nil {
 		return nil, err
 	}
-	msg := &dnsMsg{}
-	if !msg.Unpack(b[:n]) {
-		return nil, errors.New("cannot unmarshal DNS message")
+
+	b = make([]byte, 512) // see RFC 1035
+	for {
+		n, err := c.Read(b)
+		if err != nil {
+			return nil, err
+		}
+		resp := &dnsMsg{}
+		if !resp.Unpack(b[:n]) || !resp.IsResponseTo(query) {
+			// Ignore invalid responses as they may be malicious
+			// forgery attempts. Instead continue waiting until
+			// timeout. See golang.org/issue/13281.
+			continue
+		}
+		return resp, nil
 	}
-	return msg, nil
 }
 
-func (c *UDPConn) writeDNSQuery(msg *dnsMsg) error {
-	b, ok := msg.Pack()
+func (c *TCPConn) dnsRoundTrip(out *dnsMsg) (*dnsMsg, error) {
+	return dnsRoundTripTCP(c, out)
+}
+
+// dnsRoundTripTCP implements the dnsRoundTrip interface for RFC 1035's
+// "TCP usage" transport mechanism. c should be a stream-oriented connection,
+// such as a *TCPConn.
+func dnsRoundTripTCP(c io.ReadWriter, query *dnsMsg) (*dnsMsg, error) {
+	b, ok := query.Pack()
 	if !ok {
-		return errors.New("cannot marshal DNS message")
+		return nil, errors.New("cannot marshal DNS message")
 	}
+	l := len(b)
+	b = append([]byte{byte(l >> 8), byte(l)}, b...)
 	if _, err := c.Write(b); err != nil {
-		return err
+		return nil, err
 	}
-	return nil
-}
 
-func (c *TCPConn) readDNSResponse() (*dnsMsg, error) {
-	b := make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
+	b = make([]byte, 1280) // 1280 is a reasonable initial size for IP over Ethernet, see RFC 4035
 	if _, err := io.ReadFull(c, b[:2]); err != nil {
 		return nil, err
 	}
-	l := int(b[0])<<8 | int(b[1])
+	l = int(b[0])<<8 | int(b[1])
 	if l > len(b) {
 		b = make([]byte, l)
 	}
@@ -84,27 +106,17 @@ func (c *TCPConn) readDNSResponse() (*dnsMsg, error) {
 	if err != nil {
 		return nil, err
 	}
-	msg := &dnsMsg{}
-	if !msg.Unpack(b[:n]) {
+	resp := &dnsMsg{}
+	if !resp.Unpack(b[:n]) {
 		return nil, errors.New("cannot unmarshal DNS message")
 	}
-	return msg, nil
-}
-
-func (c *TCPConn) writeDNSQuery(msg *dnsMsg) error {
-	b, ok := msg.Pack()
-	if !ok {
-		return errors.New("cannot marshal DNS message")
+	if !resp.IsResponseTo(query) {
+		return nil, errors.New("invalid DNS response")
 	}
-	l := uint16(len(b))
-	b = append([]byte{byte(l >> 8), byte(l)}, b...)
-	if _, err := c.Write(b); err != nil {
-		return err
-	}
-	return nil
+	return resp, nil
 }
 
-func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
+func (d *Dialer) dialDNS(ctx context.Context, network, server string) (dnsConn, error) {
 	switch network {
 	case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
 	default:
@@ -115,9 +127,9 @@ func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
 	// call back here to translate it. The DNS config parser has
 	// already checked that all the cfg.servers[i] are IP
 	// addresses, which Dial will use without a DNS lookup.
-	c, err := d.Dial(network, server)
+	c, err := d.DialContext(ctx, network, server)
 	if err != nil {
-		return nil, err
+		return nil, mapErr(err)
 	}
 	switch network {
 	case "tcp", "tcp4", "tcp6":
@@ -129,8 +141,8 @@ func (d *Dialer) dialDNS(network, server string) (dnsConn, error) {
 }
 
 // exchange sends a query on the connection and hopes for a response.
-func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
-	d := testHookDNSDialer(timeout)
+func exchange(ctx context.Context, server, name string, qtype uint16) (*dnsMsg, error) {
+	d := testHookDNSDialer()
 	out := dnsMsg{
 		dnsMsgHdr: dnsMsgHdr{
 			recursion_desired: true,
@@ -140,24 +152,18 @@ func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg
 		},
 	}
 	for _, network := range []string{"udp", "tcp"} {
-		c, err := d.dialDNS(network, server)
+		c, err := d.dialDNS(ctx, network, server)
 		if err != nil {
 			return nil, err
 		}
 		defer c.Close()
-		if timeout > 0 {
-			c.SetDeadline(time.Now().Add(timeout))
+		if d, ok := ctx.Deadline(); ok && !d.IsZero() {
+			c.SetDeadline(d)
 		}
 		out.id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano())
-		if err := c.writeDNSQuery(&out); err != nil {
-			return nil, err
-		}
-		in, err := c.readDNSResponse()
+		in, err := c.dnsRoundTrip(&out)
 		if err != nil {
-			return nil, err
-		}
-		if in.id != out.id {
-			return nil, errors.New("DNS message ID mismatch")
+			return nil, mapErr(err)
 		}
 		if in.truncated { // see RFC 5966
 			continue
@@ -169,16 +175,22 @@ func exchange(server, name string, qtype uint16, timeout time.Duration) (*dnsMsg
 
 // Do a lookup for a single name, which must be rooted
 // (otherwise answer will not find the answers).
-func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
+func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, error) {
 	if len(cfg.servers) == 0 {
 		return "", nil, &DNSError{Err: "no DNS servers", Name: name}
 	}
-	timeout := time.Duration(cfg.timeout) * time.Second
+
+	deadline := time.Now().Add(cfg.timeout)
+	if old, ok := ctx.Deadline(); !ok || deadline.Before(old) {
+		var cancel context.CancelFunc
+		ctx, cancel = context.WithDeadline(ctx, deadline)
+		defer cancel()
+	}
+
 	var lastErr error
 	for i := 0; i < cfg.attempts; i++ {
 		for _, server := range cfg.servers {
-			server = JoinHostPort(server, "53")
-			msg, err := exchange(server, name, qtype, timeout)
+			msg, err := exchange(ctx, server, name, qtype)
 			if err != nil {
 				lastErr = &DNSError{
 					Err:    err.Error(),
@@ -190,6 +202,12 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
 				}
 				continue
 			}
+			// libresolv continues to the next server when it receives
+			// an invalid referral response. See golang.org/issue/15434.
+			if msg.rcode == dnsRcodeSuccess && !msg.authoritative && !msg.recursion_available && len(msg.answer) == 0 && len(msg.extra) == 0 {
+				lastErr = &DNSError{Err: "lame referral", Name: name, Server: server}
+				continue
+			}
 			cname, rrs, err := answer(name, server, msg, qtype)
 			// If answer errored for rcodes dnsRcodeSuccess or dnsRcodeNameError,
 			// it means the response in msg was not useful and trying another
@@ -229,7 +247,6 @@ type resolverConfig struct {
 	// 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
 
 	mu        sync.RWMutex // protects dnsConfig
 	dnsConfig *dnsConfig   // parsed resolv.conf structure used in lookups
@@ -239,16 +256,12 @@ var resolvConf resolverConfig
 
 // init initializes conf and is only called via conf.initOnce.
 func (conf *resolverConfig) init() {
-	// Set dnsConfig, modTime, and lastChecked so we don't parse
+	// Set dnsConfig 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")
 	}
-
-	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
@@ -274,17 +287,12 @@ func (conf *resolverConfig) tryUpdate(name string) {
 	}
 	conf.lastChecked = now
 
+	var mtime time.Time
 	if fi, err := os.Stat(name); err == nil {
-		if fi.ModTime().Equal(conf.modTime) {
-			return
-		}
-		conf.modTime = fi.ModTime()
-	} else {
-		// If modTime wasn't set prior, assume nothing has changed.
-		if conf.modTime.IsZero() {
-			return
-		}
-		conf.modTime = time.Time{}
+		mtime = fi.ModTime()
+	}
+	if mtime.Equal(conf.dnsConfig.mtime) {
+		return
 	}
 
 	dnsConf := dnsReadConfig(name)
@@ -306,7 +314,7 @@ func (conf *resolverConfig) releaseSema() {
 	<-conf.ch
 }
 
-func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
+func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
 	if !isDomainName(name) {
 		return "", nil, &DNSError{Err: "invalid domain name", Name: name}
 	}
@@ -315,7 +323,7 @@ func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
 	conf := resolvConf.dnsConfig
 	resolvConf.mu.RUnlock()
 	for _, fqdn := range conf.nameList(name) {
-		cname, rrs, err = tryOneName(conf, fqdn, qtype)
+		cname, rrs, err = tryOneName(ctx, conf, fqdn, qtype)
 		if err == nil {
 			break
 		}
@@ -329,30 +337,47 @@ func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
 	return
 }
 
+// avoidDNS reports whether this is a hostname for which we should not
+// use DNS. Currently this includes only .onion and .local names,
+// per RFC 7686 and RFC 6762, respectively. See golang.org/issue/13705.
+func avoidDNS(name string) bool {
+	if name == "" {
+		return true
+	}
+	if name[len(name)-1] == '.' {
+		name = name[:len(name)-1]
+	}
+	return stringsHasSuffixFold(name, ".onion") || stringsHasSuffixFold(name, ".local")
+}
+
 // nameList returns a list of names for sequential DNS queries.
 func (conf *dnsConfig) nameList(name string) []string {
+	if avoidDNS(name) {
+		return nil
+	}
+
 	// If name is rooted (trailing dot), try only that name.
 	rooted := len(name) > 0 && name[len(name)-1] == '.'
 	if rooted {
 		return []string{name}
 	}
+
+	hasNdots := count(name, '.') >= conf.ndots
+	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+".")
+	if hasNdots {
+		names = append(names, name)
 	}
 	// Try suffixes.
 	for _, suffix := range conf.search {
-		suffixed := name + "." + suffix
-		if suffixed[len(suffixed)-1] != '.' {
-			suffixed += "."
-		}
-		names = append(names, suffixed)
+		names = append(names, name+suffix)
 	}
 	// Try unsuffixed, if not tried first above.
-	if count(name, '.') < conf.ndots {
-		names = append(names, name+".")
+	if !hasNdots {
+		names = append(names, name)
 	}
 	return names
 }
@@ -392,11 +417,11 @@ func (o hostLookupOrder) String() string {
 // 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 goLookupHost(name string) (addrs []string, err error) {
-	return goLookupHostOrder(name, hostLookupFilesDNS)
+func goLookupHost(ctx context.Context, name string) (addrs []string, err error) {
+	return goLookupHostOrder(ctx, name, hostLookupFilesDNS)
 }
 
-func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err error) {
+func goLookupHostOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []string, err error) {
 	if order == hostLookupFilesDNS || order == hostLookupFiles {
 		// Use entries from /etc/hosts if they match.
 		addrs = lookupStaticHost(name)
@@ -404,7 +429,7 @@ func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err
 			return
 		}
 	}
-	ips, err := goLookupIPOrder(name, order)
+	ips, err := goLookupIPOrder(ctx, name, order)
 	if err != nil {
 		return
 	}
@@ -430,11 +455,11 @@ func goLookupIPFiles(name string) (addrs []IPAddr) {
 
 // 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 goLookupIP(ctx context.Context, name string) (addrs []IPAddr, err error) {
+	return goLookupIPOrder(ctx, name, hostLookupFilesDNS)
 }
 
-func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err error) {
+func goLookupIPOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, err error) {
 	if order == hostLookupFilesDNS || order == hostLookupFiles {
 		addrs = goLookupIPFiles(name)
 		if len(addrs) > 0 || order == hostLookupFiles {
@@ -459,7 +484,7 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er
 	for _, fqdn := range conf.nameList(name) {
 		for _, qtype := range qtypes {
 			go func(qtype uint16) {
-				_, rrs, err := tryOneName(conf, fqdn, qtype)
+				_, rrs, err := tryOneName(ctx, conf, fqdn, qtype)
 				lane <- racer{fqdn, rrs, err}
 			}(qtype)
 		}
@@ -502,8 +527,8 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er
 // 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 goLookupCNAME(name string) (cname string, err error) {
-	_, rrs, err := lookup(name, dnsTypeCNAME)
+func goLookupCNAME(ctx context.Context, name string) (cname string, err error) {
+	_, rrs, err := lookup(ctx, name, dnsTypeCNAME)
 	if err != nil {
 		return
 	}
@@ -516,7 +541,7 @@ func goLookupCNAME(name string) (cname string, err error) {
 // 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) {
+func goLookupPTR(ctx context.Context, addr string) ([]string, error) {
 	names := lookupStaticAddr(addr)
 	if len(names) > 0 {
 		return names, nil
@@ -525,7 +550,7 @@ func goLookupPTR(addr string) ([]string, error) {
 	if err != nil {
 		return nil, err
 	}
-	_, rrs, err := lookup(arpa, dnsTypePTR)
+	_, rrs, err := lookup(ctx, arpa, dnsTypePTR)
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 934f25b..09bbd48 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -7,7 +7,9 @@
 package net
 
 import (
+	"context"
 	"fmt"
+	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"path"
@@ -18,6 +20,9 @@ import (
 	"time"
 )
 
+// Test address from 192.0.2.0/24 block, reserved by RFC 5737 for documentation.
+const TestAddr uint32 = 0xc0000201
+
 var dnsTransportFallbackTests = []struct {
 	server  string
 	name    string
@@ -32,13 +37,12 @@ var dnsTransportFallbackTests = []struct {
 }
 
 func TestDNSTransportFallback(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
 
 	for _, tt := range dnsTransportFallbackTests {
-		timeout := time.Duration(tt.timeout) * time.Second
-		msg, err := exchange(tt.server, tt.name, tt.qtype, timeout)
+		ctx, cancel := context.WithTimeout(context.Background(), time.Duration(tt.timeout)*time.Second)
+		defer cancel()
+		msg, err := exchange(ctx, tt.server, tt.name, tt.qtype)
 		if err != nil {
 			t.Error(err)
 			continue
@@ -67,20 +71,20 @@ var specialDomainNameTests = []struct {
 
 	// 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
+	// Though, we test those names here for verifying negative
 	// answers at DNS query-response interaction level.
 	{"localhost.", dnsTypeALL, dnsRcodeNameError},
 	{"invalid.", dnsTypeALL, dnsRcodeNameError},
 }
 
 func TestSpecialDomainName(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
 
 	server := "8.8.8.8:53"
 	for _, tt := range specialDomainNameTests {
-		msg, err := exchange(server, tt.name, tt.qtype, 3*time.Second)
+		ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
+		defer cancel()
+		msg, err := exchange(ctx, server, tt.name, tt.qtype)
 		if err != nil {
 			t.Error(err)
 			continue
@@ -94,6 +98,57 @@ func TestSpecialDomainName(t *testing.T) {
 	}
 }
 
+// Issue 13705: don't try to resolve onion addresses, etc
+func TestAvoidDNSName(t *testing.T) {
+	tests := []struct {
+		name  string
+		avoid bool
+	}{
+		{"foo.com", false},
+		{"foo.com.", false},
+
+		{"foo.onion.", true},
+		{"foo.onion", true},
+		{"foo.ONION", true},
+		{"foo.ONION.", true},
+
+		{"foo.local.", true},
+		{"foo.local", true},
+		{"foo.LOCAL", true},
+		{"foo.LOCAL.", true},
+
+		{"", true}, // will be rejected earlier too
+
+		// Without stuff before onion/local, they're fine to
+		// use DNS. With a search path,
+		// "onion.vegegtables.com" can use DNS. Without a
+		// search path (or with a trailing dot), the queries
+		// are just kinda useless, but don't reveal anything
+		// private.
+		{"local", false},
+		{"onion", false},
+		{"local.", false},
+		{"onion.", false},
+	}
+	for _, tt := range tests {
+		got := avoidDNS(tt.name)
+		if got != tt.avoid {
+			t.Errorf("avoidDNS(%q) = %v; want %v", tt.name, got, tt.avoid)
+		}
+	}
+}
+
+// Issue 13705: don't try to resolve onion addresses, etc
+func TestLookupTorOnion(t *testing.T) {
+	addrs, err := goLookupIP(context.Background(), "foo.onion")
+	if len(addrs) > 0 {
+		t.Errorf("unexpected addresses: %v", addrs)
+	}
+	if err != nil {
+		t.Fatalf("lookup = %v; want nil", err)
+	}
+}
+
 type resolvConfTest struct {
 	dir  string
 	path string
@@ -124,20 +179,20 @@ func (conf *resolvConfTest) writeAndUpdate(lines []string) error {
 		return err
 	}
 	f.Close()
-	if err := conf.forceUpdate(conf.path); err != nil {
+	if err := conf.forceUpdate(conf.path, time.Now().Add(time.Hour)); err != nil {
 		return err
 	}
 	return nil
 }
 
-func (conf *resolvConfTest) forceUpdate(name string) error {
+func (conf *resolvConfTest) forceUpdate(name string, lastChecked time.Time) 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.lastChecked = lastChecked
 			conf.releaseSema()
 			return nil
 		}
@@ -153,7 +208,7 @@ func (conf *resolvConfTest) servers() []string {
 }
 
 func (conf *resolvConfTest) teardown() error {
-	err := conf.forceUpdate("/etc/resolv.conf")
+	err := conf.forceUpdate("/etc/resolv.conf", time.Time{})
 	os.RemoveAll(conf.dir)
 	return err
 }
@@ -166,7 +221,7 @@ var updateResolvConfTests = []struct {
 	{
 		name:    "golang.org",
 		lines:   []string{"nameserver 8.8.8.8"},
-		servers: []string{"8.8.8.8"},
+		servers: []string{"8.8.8.8:53"},
 	},
 	{
 		name:    "",
@@ -176,14 +231,12 @@ var updateResolvConfTests = []struct {
 	{
 		name:    "www.example.com",
 		lines:   []string{"nameserver 8.8.4.4"},
-		servers: []string{"8.8.4.4"},
+		servers: []string{"8.8.4.4:53"},
 	},
 }
 
 func TestUpdateResolvConf(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
 
 	conf, err := newResolvConfTest()
 	if err != nil {
@@ -203,7 +256,7 @@ func TestUpdateResolvConf(t *testing.T) {
 			for j := 0; j < N; j++ {
 				go func(name string) {
 					defer wg.Done()
-					ips, err := goLookupIP(name)
+					ips, err := goLookupIP(context.Background(), name)
 					if err != nil {
 						t.Error(err)
 						return
@@ -338,9 +391,7 @@ var goLookupIPWithResolverConfigTests = []struct {
 }
 
 func TestGoLookupIPWithResolverConfig(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
 
 	conf, err := newResolvConfTest()
 	if err != nil {
@@ -353,10 +404,15 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) {
 			t.Error(err)
 			continue
 		}
-		conf.tryUpdate(conf.path)
-		addrs, err := goLookupIP(tt.name)
+		addrs, err := goLookupIP(context.Background(), 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) {
+			// This test uses external network connectivity.
+			// We need to take care with errors on both
+			// DNS message exchange layer and DNS
+			// transport layer because goLookupIP may fail
+			// when the IP connectivty on node under test
+			// gets lost during its run.
+			if err, ok := err.(*DNSError); !ok || tt.error != nil && (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
@@ -380,9 +436,7 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) {
 
 // Test that goLookupIPOrder falls back to the host file when no DNS servers are available.
 func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
 
 	// Add a config that simulates no dns servers being available.
 	conf, err := newResolvConfTest()
@@ -392,7 +446,6 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
 	if err := conf.writeAndUpdate([]string{}); err != nil {
 		t.Fatal(err)
 	}
-	conf.tryUpdate(conf.path)
 	// Redirect host file lookups.
 	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
 	testHookHostsPath = "testdata/hosts"
@@ -400,15 +453,15 @@ func TestGoLookupIPOrderFallbackToFile(t *testing.T) {
 	for _, order := range []hostLookupOrder{hostLookupFilesDNS, hostLookupDNSFiles} {
 		name := fmt.Sprintf("order %v", order)
 
-		// First ensure that we get an error when contacting a non-existant host.
-		_, err := goLookupIPOrder("notarealhost", order)
+		// First ensure that we get an error when contacting a non-existent host.
+		_, err := goLookupIPOrder(context.Background(), "notarealhost", order)
 		if err == nil {
 			t.Errorf("%s: expected error while looking up name not in hosts file", name)
 			continue
 		}
 
 		// Now check that we get an address when the name appears in the hosts file.
-		addrs, err := goLookupIPOrder("thor", order) // entry is in "testdata/hosts"
+		addrs, err := goLookupIPOrder(context.Background(), "thor", order) // entry is in "testdata/hosts"
 		if err != nil {
 			t.Errorf("%s: expected to successfully lookup host entry", name)
 			continue
@@ -444,10 +497,10 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	d := &fakeDNSConn{}
-	testHookDNSDialer = func(time.Duration) dnsDialer { return d }
+	d := &fakeDNSDialer{}
+	testHookDNSDialer = func() dnsDialer { return d }
 
-	d.rh = func(q *dnsMsg) (*dnsMsg, error) {
+	d.rh = func(s string, q *dnsMsg) (*dnsMsg, error) {
 		r := &dnsMsg{
 			dnsMsgHdr: dnsMsgHdr{
 				id: q.id,
@@ -464,7 +517,7 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
 		return r, nil
 	}
 
-	_, err = goLookupIP(fqdn)
+	_, err = goLookupIP(context.Background(), fqdn)
 	if err == nil {
 		t.Fatal("expected an error")
 	}
@@ -475,19 +528,83 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
 	}
 }
 
+// Issue 15434. If a name server gives a lame referral, continue to the next.
+func TestIgnoreLameReferrals(t *testing.T) {
+	origTestHookDNSDialer := testHookDNSDialer
+	defer func() { testHookDNSDialer = origTestHookDNSDialer }()
+
+	conf, err := newResolvConfTest()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer conf.teardown()
+
+	if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", "nameserver 192.0.2.2"}); err != nil {
+		t.Fatal(err)
+	}
+
+	d := &fakeDNSDialer{}
+	testHookDNSDialer = func() dnsDialer { return d }
+
+	d.rh = func(s string, q *dnsMsg) (*dnsMsg, error) {
+		t.Log(s, q)
+		r := &dnsMsg{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       q.id,
+				response: true,
+			},
+			question: q.question,
+		}
+
+		if s == "192.0.2.2:53" {
+			r.recursion_available = true
+			if q.question[0].Qtype == dnsTypeA {
+				r.answer = []dnsRR{
+					&dnsRR_A{
+						Hdr: dnsRR_Header{
+							Name:     q.question[0].Name,
+							Rrtype:   dnsTypeA,
+							Class:    dnsClassINET,
+							Rdlength: 4,
+						},
+						A: TestAddr,
+					},
+				}
+			}
+		}
+
+		return r, nil
+	}
+
+	addrs, err := goLookupIP(context.Background(), "www.golang.org")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if got := len(addrs); got != 1 {
+		t.Fatalf("got %d addresses, want 1", got)
+	}
+
+	if got, want := addrs[0].String(), "192.0.2.1"; got != want {
+		t.Fatalf("got address %v, want %v", got, want)
+	}
+}
+
 func BenchmarkGoLookupIP(b *testing.B) {
 	testHookUninstaller.Do(uninstallTestHooks)
+	ctx := context.Background()
 
 	for i := 0; i < b.N; i++ {
-		goLookupIP("www.example.com")
+		goLookupIP(ctx, "www.example.com")
 	}
 }
 
 func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
 	testHookUninstaller.Do(uninstallTestHooks)
+	ctx := context.Background()
 
 	for i := 0; i < b.N; i++ {
-		goLookupIP("some.nonexistent")
+		goLookupIP(ctx, "some.nonexistent")
 	}
 }
 
@@ -507,22 +624,25 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
 	if err := conf.writeAndUpdate(lines); err != nil {
 		b.Fatal(err)
 	}
+	ctx := context.Background()
 
 	for i := 0; i < b.N; i++ {
-		goLookupIP("www.example.com")
+		goLookupIP(ctx, "www.example.com")
 	}
 }
 
-type fakeDNSConn struct {
-	// last query
-	qmu sync.Mutex // guards q
-	q   *dnsMsg
+type fakeDNSDialer struct {
 	// reply handler
-	rh func(*dnsMsg) (*dnsMsg, error)
+	rh func(s string, q *dnsMsg) (*dnsMsg, error)
 }
 
-func (f *fakeDNSConn) dialDNS(n, s string) (dnsConn, error) {
-	return f, nil
+func (f *fakeDNSDialer) dialDNS(_ context.Context, n, s string) (dnsConn, error) {
+	return &fakeDNSConn{f.rh, s}, nil
+}
+
+type fakeDNSConn struct {
+	rh func(s string, q *dnsMsg) (*dnsMsg, error)
+	s  string
 }
 
 func (f *fakeDNSConn) Close() error {
@@ -533,16 +653,74 @@ func (f *fakeDNSConn) SetDeadline(time.Time) error {
 	return nil
 }
 
-func (f *fakeDNSConn) writeDNSQuery(q *dnsMsg) error {
-	f.qmu.Lock()
-	defer f.qmu.Unlock()
-	f.q = q
-	return nil
+func (f *fakeDNSConn) dnsRoundTrip(q *dnsMsg) (*dnsMsg, error) {
+	return f.rh(f.s, q)
 }
 
-func (f *fakeDNSConn) readDNSResponse() (*dnsMsg, error) {
-	f.qmu.Lock()
-	q := f.q
-	f.qmu.Unlock()
-	return f.rh(q)
+// UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281).
+func TestIgnoreDNSForgeries(t *testing.T) {
+	c, s := Pipe()
+	go func() {
+		b := make([]byte, 512)
+		n, err := s.Read(b)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		msg := &dnsMsg{}
+		if !msg.Unpack(b[:n]) {
+			t.Fatal("invalid DNS query")
+		}
+
+		s.Write([]byte("garbage DNS response packet"))
+
+		msg.response = true
+		msg.id++ // make invalid ID
+		b, ok := msg.Pack()
+		if !ok {
+			t.Fatal("failed to pack DNS response")
+		}
+		s.Write(b)
+
+		msg.id-- // restore original ID
+		msg.answer = []dnsRR{
+			&dnsRR_A{
+				Hdr: dnsRR_Header{
+					Name:     "www.example.com.",
+					Rrtype:   dnsTypeA,
+					Class:    dnsClassINET,
+					Rdlength: 4,
+				},
+				A: TestAddr,
+			},
+		}
+
+		b, ok = msg.Pack()
+		if !ok {
+			t.Fatal("failed to pack DNS response")
+		}
+		s.Write(b)
+	}()
+
+	msg := &dnsMsg{
+		dnsMsgHdr: dnsMsgHdr{
+			id: 42,
+		},
+		question: []dnsQuestion{
+			{
+				Name:   "www.example.com.",
+				Qtype:  dnsTypeA,
+				Qclass: dnsClassINET,
+			},
+		},
+	}
+
+	resp, err := dnsRoundTripUDP(c, msg)
+	if err != nil {
+		t.Fatalf("dnsRoundTripUDP failed: %v", err)
+	}
+
+	if got := resp.answer[0].(*dnsRR_A).A; got != TestAddr {
+		t.Errorf("got address %v, want %v", got, TestAddr)
+	}
 }
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index 6073fdb..aec575e 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -8,36 +8,52 @@
 
 package net
 
-var defaultNS = []string{"127.0.0.1", "::1"}
+import (
+	"os"
+	"time"
+)
+
+var (
+	defaultNS   = []string{"127.0.0.1:53", "[::1]:53"}
+	getHostname = os.Hostname // variable for testing
+)
 
 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
-	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
+	servers    []string      // server addresses (in host:port form) to use
+	search     []string      // rooted suffixes to append to local name
+	ndots      int           // number of dots in name to trigger absolute lookup
+	timeout    time.Duration // wait before giving up on a query, including retries
+	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
+	mtime      time.Time     // time of resolv.conf modification
 }
 
 // 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 {
 	conf := &dnsConfig{
 		ndots:    1,
-		timeout:  5,
+		timeout:  5 * time.Second,
 		attempts: 2,
 	}
 	file, err := open(filename)
 	if err != nil {
 		conf.servers = defaultNS
+		conf.search = dnsDefaultSearch()
 		conf.err = err
 		return conf
 	}
 	defer file.close()
+	if fi, err := file.file.Stat(); err == nil {
+		conf.mtime = fi.ModTime()
+	} else {
+		conf.servers = defaultNS
+		conf.search = dnsDefaultSearch()
+		conf.err = err
+		return conf
+	}
 	for line, ok := file.readLine(); ok; line, ok = file.readLine() {
 		if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
 			// comment.
@@ -51,24 +67,24 @@ func dnsReadConfig(filename string) *dnsConfig {
 		case "nameserver": // add one name server
 			if len(f) > 1 && len(conf.servers) < 3 { // small, but the standard limit
 				// One more check: make sure server name is
-				// just an IP address.  Otherwise we need DNS
+				// just an IP address. Otherwise we need DNS
 				// to look it up.
 				if parseIPv4(f[1]) != nil {
-					conf.servers = append(conf.servers, f[1])
+					conf.servers = append(conf.servers, JoinHostPort(f[1], "53"))
 				} else if ip, _ := parseIPv6(f[1], true); ip != nil {
-					conf.servers = append(conf.servers, f[1])
+					conf.servers = append(conf.servers, JoinHostPort(f[1], "53"))
 				}
 			}
 
 		case "domain": // set search path to just this domain
 			if len(f) > 1 {
-				conf.search = []string{f[1]}
+				conf.search = []string{ensureRooted(f[1])}
 			}
 
 		case "search": // set search path to given servers
 			conf.search = make([]string, len(f)-1)
 			for i := 0; i < len(conf.search); i++ {
-				conf.search[i] = f[i+1]
+				conf.search[i] = ensureRooted(f[i+1])
 			}
 
 		case "options": // magic options
@@ -85,7 +101,7 @@ func dnsReadConfig(filename string) *dnsConfig {
 					if n < 1 {
 						n = 1
 					}
-					conf.timeout = n
+					conf.timeout = time.Duration(n) * time.Second
 				case hasPrefix(s, "attempts:"):
 					n, _, _ := dtoi(s, 9)
 					if n < 1 {
@@ -112,9 +128,31 @@ func dnsReadConfig(filename string) *dnsConfig {
 	if len(conf.servers) == 0 {
 		conf.servers = defaultNS
 	}
+	if len(conf.search) == 0 {
+		conf.search = dnsDefaultSearch()
+	}
 	return conf
 }
 
+func dnsDefaultSearch() []string {
+	hn, err := getHostname()
+	if err != nil {
+		// best effort
+		return nil
+	}
+	if i := byteIndex(hn, '.'); i >= 0 && i < len(hn)-1 {
+		return []string{ensureRooted(hn[i+1:])}
+	}
+	return nil
+}
+
 func hasPrefix(s, prefix string) bool {
 	return len(s) >= len(prefix) && s[:len(prefix)] == prefix
 }
+
+func ensureRooted(s string) string {
+	if len(s) > 0 && s[len(s)-1] == '.' {
+		return s
+	}
+	return s + "."
+}
diff --git a/src/net/dnsconfig_unix_test.go b/src/net/dnsconfig_unix_test.go
index c8eed61..9fd6dbf 100644
--- a/src/net/dnsconfig_unix_test.go
+++ b/src/net/dnsconfig_unix_test.go
@@ -7,9 +7,11 @@
 package net
 
 import (
+	"errors"
 	"os"
 	"reflect"
 	"testing"
+	"time"
 )
 
 var dnsReadConfigTests = []struct {
@@ -19,10 +21,10 @@ var dnsReadConfigTests = []struct {
 	{
 		name: "testdata/resolv.conf",
 		want: &dnsConfig{
-			servers:    []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"},
-			search:     []string{"localdomain"},
+			servers:    []string{"8.8.8.8:53", "[2001:4860:4860::8888]:53", "[fe80::1%lo0]:53"},
+			search:     []string{"localdomain."},
 			ndots:      5,
-			timeout:    10,
+			timeout:    10 * time.Second,
 			attempts:   3,
 			rotate:     true,
 			unknownOpt: true, // the "options attempts 3" line
@@ -31,20 +33,20 @@ var dnsReadConfigTests = []struct {
 	{
 		name: "testdata/domain-resolv.conf",
 		want: &dnsConfig{
-			servers:  []string{"8.8.8.8"},
-			search:   []string{"localdomain"},
+			servers:  []string{"8.8.8.8:53"},
+			search:   []string{"localdomain."},
 			ndots:    1,
-			timeout:  5,
+			timeout:  5 * time.Second,
 			attempts: 2,
 		},
 	},
 	{
 		name: "testdata/search-resolv.conf",
 		want: &dnsConfig{
-			servers:  []string{"8.8.8.8"},
-			search:   []string{"test", "invalid"},
+			servers:  []string{"8.8.8.8:53"},
+			search:   []string{"test.", "invalid."},
 			ndots:    1,
-			timeout:  5,
+			timeout:  5 * time.Second,
 			attempts: 2,
 		},
 	},
@@ -53,29 +55,35 @@ var dnsReadConfigTests = []struct {
 		want: &dnsConfig{
 			servers:  defaultNS,
 			ndots:    1,
-			timeout:  5,
+			timeout:  5 * time.Second,
 			attempts: 2,
+			search:   []string{"domain.local."},
 		},
 	},
 	{
 		name: "testdata/openbsd-resolv.conf",
 		want: &dnsConfig{
 			ndots:    1,
-			timeout:  5,
+			timeout:  5 * time.Second,
 			attempts: 2,
 			lookup:   []string{"file", "bind"},
-			servers:  []string{"169.254.169.254", "10.240.0.1"},
+			servers:  []string{"169.254.169.254:53", "10.240.0.1:53"},
 			search:   []string{"c.symbolic-datum-552.internal."},
 		},
 	},
 }
 
 func TestDNSReadConfig(t *testing.T) {
+	origGetHostname := getHostname
+	defer func() { getHostname = origGetHostname }()
+	getHostname = func() (string, error) { return "host.domain.local", nil }
+
 	for _, tt := range dnsReadConfigTests {
 		conf := dnsReadConfig(tt.name)
 		if conf.err != nil {
 			t.Fatal(conf.err)
 		}
+		conf.mtime = time.Time{}
 		if !reflect.DeepEqual(conf, tt.want) {
 			t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want)
 		}
@@ -83,6 +91,10 @@ func TestDNSReadConfig(t *testing.T) {
 }
 
 func TestDNSReadMissingFile(t *testing.T) {
+	origGetHostname := getHostname
+	defer func() { getHostname = origGetHostname }()
+	getHostname = func() (string, error) { return "host.domain.local", nil }
+
 	conf := dnsReadConfig("a-nonexistent-file")
 	if !os.IsNotExist(conf.err) {
 		t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, os.ErrNotExist)
@@ -91,10 +103,54 @@ func TestDNSReadMissingFile(t *testing.T) {
 	want := &dnsConfig{
 		servers:  defaultNS,
 		ndots:    1,
-		timeout:  5,
+		timeout:  5 * time.Second,
 		attempts: 2,
+		search:   []string{"domain.local."},
 	}
 	if !reflect.DeepEqual(conf, want) {
 		t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want)
 	}
 }
+
+var dnsDefaultSearchTests = []struct {
+	name string
+	err  error
+	want []string
+}{
+	{
+		name: "host.long.domain.local",
+		want: []string{"long.domain.local."},
+	},
+	{
+		name: "host.local",
+		want: []string{"local."},
+	},
+	{
+		name: "host",
+		want: nil,
+	},
+	{
+		name: "host.domain.local",
+		err:  errors.New("errored"),
+		want: nil,
+	},
+	{
+		// ensures we don't return []string{""}
+		// which causes duplicate lookups
+		name: "foo.",
+		want: nil,
+	},
+}
+
+func TestDNSDefaultSearch(t *testing.T) {
+	origGetHostname := getHostname
+	defer func() { getHostname = origGetHostname }()
+
+	for _, tt := range dnsDefaultSearchTests {
+		getHostname = func() (string, error) { return tt.name, tt.err }
+		got := dnsDefaultSearch()
+		if !reflect.DeepEqual(got, tt.want) {
+			t.Errorf("dnsDefaultSearch with hostname %q and error %+v = %q, wanted %q", tt.name, tt.err, got, tt.want)
+		}
+	}
+}
diff --git a/src/net/dnsmsg.go b/src/net/dnsmsg.go
index 93078fe..afdb44c 100644
--- a/src/net/dnsmsg.go
+++ b/src/net/dnsmsg.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.
 
-// DNS packet assembly.  See RFC 1035.
+// DNS packet assembly. See RFC 1035.
 //
 // This is intended to support name resolution during Dial.
 // It doesn't have to be blazing fast.
@@ -18,7 +18,7 @@
 // generic pack/unpack routines.
 //
 // TODO(rsc):  There are enough names defined in this file that they're all
-// prefixed with dns.  Perhaps put this in its own package later.
+// prefixed with dns. Perhaps put this in its own package later.
 
 package net
 
@@ -109,7 +109,7 @@ const (
 
 // DNS queries.
 type dnsQuestion struct {
-	Name   string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below
+	Name   string
 	Qtype  uint16
 	Qclass uint16
 }
@@ -124,7 +124,7 @@ func (q *dnsQuestion) Walk(f func(v interface{}, name, tag string) bool) bool {
 // There are many types of messages,
 // but they all share the same header.
 type dnsRR_Header struct {
-	Name     string `net:"domain-name"`
+	Name     string
 	Rrtype   uint16
 	Class    uint16
 	Ttl      uint32
@@ -152,7 +152,7 @@ type dnsRR interface {
 
 type dnsRR_CNAME struct {
 	Hdr   dnsRR_Header
-	Cname string `net:"domain-name"`
+	Cname string
 }
 
 func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
@@ -163,77 +163,10 @@ func (rr *dnsRR_CNAME) Walk(f func(v interface{}, name, tag string) bool) bool {
 	return rr.Hdr.Walk(f) && f(&rr.Cname, "Cname", "domain")
 }
 
-type dnsRR_HINFO struct {
-	Hdr dnsRR_Header
-	Cpu string
-	Os  string
-}
-
-func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
-	return &rr.Hdr
-}
-
-func (rr *dnsRR_HINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
-	return rr.Hdr.Walk(f) && f(&rr.Cpu, "Cpu", "") && f(&rr.Os, "Os", "")
-}
-
-type dnsRR_MB struct {
-	Hdr dnsRR_Header
-	Mb  string `net:"domain-name"`
-}
-
-func (rr *dnsRR_MB) Header() *dnsRR_Header {
-	return &rr.Hdr
-}
-
-func (rr *dnsRR_MB) Walk(f func(v interface{}, name, tag string) bool) bool {
-	return rr.Hdr.Walk(f) && f(&rr.Mb, "Mb", "domain")
-}
-
-type dnsRR_MG struct {
-	Hdr dnsRR_Header
-	Mg  string `net:"domain-name"`
-}
-
-func (rr *dnsRR_MG) Header() *dnsRR_Header {
-	return &rr.Hdr
-}
-
-func (rr *dnsRR_MG) Walk(f func(v interface{}, name, tag string) bool) bool {
-	return rr.Hdr.Walk(f) && f(&rr.Mg, "Mg", "domain")
-}
-
-type dnsRR_MINFO struct {
-	Hdr   dnsRR_Header
-	Rmail string `net:"domain-name"`
-	Email string `net:"domain-name"`
-}
-
-func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
-	return &rr.Hdr
-}
-
-func (rr *dnsRR_MINFO) Walk(f func(v interface{}, name, tag string) bool) bool {
-	return rr.Hdr.Walk(f) && f(&rr.Rmail, "Rmail", "domain") && f(&rr.Email, "Email", "domain")
-}
-
-type dnsRR_MR struct {
-	Hdr dnsRR_Header
-	Mr  string `net:"domain-name"`
-}
-
-func (rr *dnsRR_MR) Header() *dnsRR_Header {
-	return &rr.Hdr
-}
-
-func (rr *dnsRR_MR) Walk(f func(v interface{}, name, tag string) bool) bool {
-	return rr.Hdr.Walk(f) && f(&rr.Mr, "Mr", "domain")
-}
-
 type dnsRR_MX struct {
 	Hdr  dnsRR_Header
 	Pref uint16
-	Mx   string `net:"domain-name"`
+	Mx   string
 }
 
 func (rr *dnsRR_MX) Header() *dnsRR_Header {
@@ -246,7 +179,7 @@ func (rr *dnsRR_MX) Walk(f func(v interface{}, name, tag string) bool) bool {
 
 type dnsRR_NS struct {
 	Hdr dnsRR_Header
-	Ns  string `net:"domain-name"`
+	Ns  string
 }
 
 func (rr *dnsRR_NS) Header() *dnsRR_Header {
@@ -259,7 +192,7 @@ func (rr *dnsRR_NS) Walk(f func(v interface{}, name, tag string) bool) bool {
 
 type dnsRR_PTR struct {
 	Hdr dnsRR_Header
-	Ptr string `net:"domain-name"`
+	Ptr string
 }
 
 func (rr *dnsRR_PTR) Header() *dnsRR_Header {
@@ -272,8 +205,8 @@ func (rr *dnsRR_PTR) Walk(f func(v interface{}, name, tag string) bool) bool {
 
 type dnsRR_SOA struct {
 	Hdr     dnsRR_Header
-	Ns      string `net:"domain-name"`
-	Mbox    string `net:"domain-name"`
+	Ns      string
+	Mbox    string
 	Serial  uint32
 	Refresh uint32
 	Retry   uint32
@@ -315,7 +248,7 @@ func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
 		if !f(&txt, "Txt", "") {
 			return false
 		}
-		// more bytes than rr.Hdr.Rdlength said there woudld be
+		// more bytes than rr.Hdr.Rdlength said there would be
 		if rr.Hdr.Rdlength-n < uint16(len(txt))+1 {
 			return false
 		}
@@ -330,7 +263,7 @@ type dnsRR_SRV struct {
 	Priority uint16
 	Weight   uint16
 	Port     uint16
-	Target   string `net:"domain-name"`
+	Target   string
 }
 
 func (rr *dnsRR_SRV) Header() *dnsRR_Header {
@@ -347,7 +280,7 @@ func (rr *dnsRR_SRV) Walk(f func(v interface{}, name, tag string) bool) bool {
 
 type dnsRR_A struct {
 	Hdr dnsRR_Header
-	A   uint32 `net:"ipv4"`
+	A   uint32
 }
 
 func (rr *dnsRR_A) Header() *dnsRR_Header {
@@ -360,7 +293,7 @@ func (rr *dnsRR_A) Walk(f func(v interface{}, name, tag string) bool) bool {
 
 type dnsRR_AAAA struct {
 	Hdr  dnsRR_Header
-	AAAA [16]byte `net:"ipv6"`
+	AAAA [16]byte
 }
 
 func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
@@ -376,17 +309,12 @@ func (rr *dnsRR_AAAA) Walk(f func(v interface{}, name, tag string) bool) bool {
 // All the packers and unpackers take a (msg []byte, off int)
 // and return (off1 int, ok bool).  If they return ok==false, they
 // also return off1==len(msg), so that the next unpacker will
-// also fail.  This lets us avoid checks of ok until the end of a
+// also fail. This lets us avoid checks of ok until the end of a
 // packing sequence.
 
 // Map of constructors for each RR wire type.
 var rr_mk = map[int]func() dnsRR{
 	dnsTypeCNAME: func() dnsRR { return new(dnsRR_CNAME) },
-	dnsTypeHINFO: func() dnsRR { return new(dnsRR_HINFO) },
-	dnsTypeMB:    func() dnsRR { return new(dnsRR_MB) },
-	dnsTypeMG:    func() dnsRR { return new(dnsRR_MG) },
-	dnsTypeMINFO: func() dnsRR { return new(dnsRR_MINFO) },
-	dnsTypeMR:    func() dnsRR { return new(dnsRR_MR) },
 	dnsTypeMX:    func() dnsRR { return new(dnsRR_MX) },
 	dnsTypeNS:    func() dnsRR { return new(dnsRR_NS) },
 	dnsTypePTR:   func() dnsRR { return new(dnsRR_PTR) },
@@ -399,13 +327,20 @@ var rr_mk = map[int]func() dnsRR{
 
 // Pack a domain name s into msg[off:].
 // Domain names are a sequence of counted strings
-// split at the dots.  They end with a zero-length string.
+// split at the dots. They end with a zero-length string.
 func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
 	// Add trailing dot to canonicalize name.
 	if n := len(s); n == 0 || s[n-1] != '.' {
 		s += "."
 	}
 
+	// Allow root domain.
+	if s == "." {
+		msg[off] = 0
+		off++
+		return off, true
+	}
+
 	// Each dot ends a segment of the name.
 	// We trade each dot byte for a length byte.
 	// There is also a trailing zero.
@@ -422,8 +357,13 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
 			if i-begin >= 1<<6 { // top two bits of length must be clear
 				return len(msg), false
 			}
+			if i-begin == 0 {
+				return len(msg), false
+			}
+
 			msg[off] = byte(i - begin)
 			off++
+
 			for j := begin; j < i; j++ {
 				msg[off] = s[j]
 				off++
@@ -440,8 +380,8 @@ func packDomainName(s string, msg []byte, off int) (off1 int, ok bool) {
 // In addition to the simple sequences of counted strings above,
 // domain names are allowed to refer to strings elsewhere in the
 // packet, to avoid repeating common suffixes when returning
-// many entries in a single domain.  The pointers are marked
-// by a length byte with the top two bits set.  Ignoring those
+// many entries in a single domain. The pointers are marked
+// by a length byte with the top two bits set. Ignoring those
 // two bits, that byte and the next give a 14 bit offset from msg[0]
 // where we should pick up the trail.
 // Note that if we jump elsewhere in the packet,
@@ -494,6 +434,9 @@ Loop:
 			return "", len(msg), false
 		}
 	}
+	if len(s) == 0 {
+		s = "."
+	}
 	if ptr == 0 {
 		off1 = off
 	}
@@ -803,20 +746,32 @@ func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
 	// Pack it in: header and then the pieces.
 	off := 0
 	off, ok = packStruct(&dh, msg, off)
+	if !ok {
+		return nil, false
+	}
 	for i := 0; i < len(question); i++ {
 		off, ok = packStruct(&question[i], msg, off)
+		if !ok {
+			return nil, false
+		}
 	}
 	for i := 0; i < len(answer); i++ {
 		off, ok = packRR(answer[i], msg, off)
+		if !ok {
+			return nil, false
+		}
 	}
 	for i := 0; i < len(ns); i++ {
 		off, ok = packRR(ns[i], msg, off)
+		if !ok {
+			return nil, false
+		}
 	}
 	for i := 0; i < len(extra); i++ {
 		off, ok = packRR(extra[i], msg, off)
-	}
-	if !ok {
-		return nil, false
+		if !ok {
+			return nil, false
+		}
 	}
 	return msg[0:off], true
 }
@@ -848,6 +803,9 @@ func (dns *dnsMsg) Unpack(msg []byte) bool {
 
 	for i := 0; i < len(dns.question); i++ {
 		off, ok = unpackStruct(&dns.question[i], msg, off)
+		if !ok {
+			return false
+		}
 	}
 	for i := 0; i < int(dh.Ancount); i++ {
 		rec, off, ok = unpackRR(msg, off)
@@ -904,3 +862,23 @@ func (dns *dnsMsg) String() string {
 	}
 	return s
 }
+
+// IsResponseTo reports whether m is an acceptable response to query.
+func (m *dnsMsg) IsResponseTo(query *dnsMsg) bool {
+	if !m.response {
+		return false
+	}
+	if m.id != query.id {
+		return false
+	}
+	if len(m.question) != len(query.question) {
+		return false
+	}
+	for i, q := range m.question {
+		q2 := query.question[i]
+		if !equalASCIILabel(q.Name, q2.Name) || q.Qtype != q2.Qtype || q.Qclass != q2.Qclass {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/net/dnsmsg_test.go b/src/net/dnsmsg_test.go
index 1078d77..25bd98c 100644
--- a/src/net/dnsmsg_test.go
+++ b/src/net/dnsmsg_test.go
@@ -10,6 +10,103 @@ import (
 	"testing"
 )
 
+func TestStructPackUnpack(t *testing.T) {
+	want := dnsQuestion{
+		Name:   ".",
+		Qtype:  dnsTypeA,
+		Qclass: dnsClassINET,
+	}
+	buf := make([]byte, 50)
+	n, ok := packStruct(&want, buf, 0)
+	if !ok {
+		t.Fatal("packing failed")
+	}
+	buf = buf[:n]
+	got := dnsQuestion{}
+	n, ok = unpackStruct(&got, buf, 0)
+	if !ok {
+		t.Fatal("unpacking failed")
+	}
+	if n != len(buf) {
+		t.Errorf("unpacked different amount than packed: got n = %d, want = %d", n, len(buf))
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("got = %+v, want = %+v", got, want)
+	}
+}
+
+func TestDomainNamePackUnpack(t *testing.T) {
+	tests := []struct {
+		in   string
+		want string
+		ok   bool
+	}{
+		{"", ".", true},
+		{".", ".", true},
+		{"google..com", "", false},
+		{"google.com", "google.com.", true},
+		{"google..com.", "", false},
+		{"google.com.", "google.com.", true},
+		{".google.com.", "", false},
+		{"www..google.com.", "", false},
+		{"www.google.com.", "www.google.com.", true},
+	}
+
+	for _, test := range tests {
+		buf := make([]byte, 30)
+		n, ok := packDomainName(test.in, buf, 0)
+		if ok != test.ok {
+			t.Errorf("packing of %s: got ok = %t, want = %t", test.in, ok, test.ok)
+			continue
+		}
+		if !test.ok {
+			continue
+		}
+		buf = buf[:n]
+		got, n, ok := unpackDomainName(buf, 0)
+		if !ok {
+			t.Errorf("unpacking for %s failed", test.in)
+			continue
+		}
+		if n != len(buf) {
+			t.Errorf(
+				"unpacked different amount than packed for %s: got n = %d, want = %d",
+				test.in,
+				n,
+				len(buf),
+			)
+		}
+		if got != test.want {
+			t.Errorf("unpacking packing of %s: got = %s, want = %s", test.in, got, test.want)
+		}
+	}
+}
+
+func TestDNSPackUnpack(t *testing.T) {
+	want := dnsMsg{
+		question: []dnsQuestion{{
+			Name:   ".",
+			Qtype:  dnsTypeAAAA,
+			Qclass: dnsClassINET,
+		}},
+		answer: []dnsRR{},
+		ns:     []dnsRR{},
+		extra:  []dnsRR{},
+	}
+	b, ok := want.Pack()
+	if !ok {
+		t.Fatal("packing failed")
+	}
+	var got dnsMsg
+	ok = got.Unpack(b)
+	if !ok {
+		t.Fatal("unpacking failed")
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("got = %+v, want = %+v", got, want)
+	}
+}
+
 func TestDNSParseSRVReply(t *testing.T) {
 	data, err := hex.DecodeString(dnsSRVReply)
 	if err != nil {
@@ -183,6 +280,124 @@ func TestDNSParseTXTCorruptTXTLengthReply(t *testing.T) {
 	}
 }
 
+func TestIsResponseTo(t *testing.T) {
+	// Sample DNS query.
+	query := dnsMsg{
+		dnsMsgHdr: dnsMsgHdr{
+			id: 42,
+		},
+		question: []dnsQuestion{
+			{
+				Name:   "www.example.com.",
+				Qtype:  dnsTypeA,
+				Qclass: dnsClassINET,
+			},
+		},
+	}
+
+	resp := query
+	resp.response = true
+	if !resp.IsResponseTo(&query) {
+		t.Error("got false, want true")
+	}
+
+	badResponses := []dnsMsg{
+		// Different ID.
+		{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       43,
+				response: true,
+			},
+			question: []dnsQuestion{
+				{
+					Name:   "www.example.com.",
+					Qtype:  dnsTypeA,
+					Qclass: dnsClassINET,
+				},
+			},
+		},
+
+		// Different query name.
+		{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       42,
+				response: true,
+			},
+			question: []dnsQuestion{
+				{
+					Name:   "www.google.com.",
+					Qtype:  dnsTypeA,
+					Qclass: dnsClassINET,
+				},
+			},
+		},
+
+		// Different query type.
+		{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       42,
+				response: true,
+			},
+			question: []dnsQuestion{
+				{
+					Name:   "www.example.com.",
+					Qtype:  dnsTypeAAAA,
+					Qclass: dnsClassINET,
+				},
+			},
+		},
+
+		// Different query class.
+		{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       42,
+				response: true,
+			},
+			question: []dnsQuestion{
+				{
+					Name:   "www.example.com.",
+					Qtype:  dnsTypeA,
+					Qclass: dnsClassCSNET,
+				},
+			},
+		},
+
+		// No questions.
+		{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       42,
+				response: true,
+			},
+		},
+
+		// Extra questions.
+		{
+			dnsMsgHdr: dnsMsgHdr{
+				id:       42,
+				response: true,
+			},
+			question: []dnsQuestion{
+				{
+					Name:   "www.example.com.",
+					Qtype:  dnsTypeA,
+					Qclass: dnsClassINET,
+				},
+				{
+					Name:   "www.golang.org.",
+					Qtype:  dnsTypeAAAA,
+					Qclass: dnsClassINET,
+				},
+			},
+		},
+	}
+
+	for i := range badResponses {
+		if badResponses[i].IsResponseTo(&query) {
+			t.Error("%v: got true, want false", i)
+		}
+	}
+}
+
 // Valid DNS SRV reply
 const dnsSRVReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" +
 	"6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" +
diff --git a/src/net/dnsname_test.go b/src/net/dnsname_test.go
index be07dc6..bc777b8 100644
--- a/src/net/dnsname_test.go
+++ b/src/net/dnsname_test.go
@@ -15,7 +15,7 @@ type dnsNameTest struct {
 }
 
 var dnsNameTests = []dnsNameTest{
-	// RFC2181, section 11.
+	// RFC 2181, section 11.
 	{"_xmpp-server._tcp.google.com", true},
 	{"foo.com", true},
 	{"1foo.com", true},
diff --git a/src/net/error_plan9_test.go b/src/net/error_plan9_test.go
index 495ea96..d7c7f14 100644
--- a/src/net/error_plan9_test.go
+++ b/src/net/error_plan9_test.go
@@ -9,6 +9,8 @@ import "syscall"
 var (
 	errTimedout       = syscall.ETIMEDOUT
 	errOpNotSupported = syscall.EPLAN9
+
+	abortedConnRequestErrors []error
 )
 
 func isPlatformError(err error) bool {
diff --git a/src/net/error_posix_test.go b/src/net/error_posix_test.go
index 981cc83..b411a37 100644
--- a/src/net/error_posix_test.go
+++ b/src/net/error_posix_test.go
@@ -12,16 +12,6 @@ import (
 	"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
diff --git a/src/net/error_test.go b/src/net/error_test.go
index 1aab14c..d6de5a3 100644
--- a/src/net/error_test.go
+++ b/src/net/error_test.go
@@ -5,6 +5,7 @@
 package net
 
 import (
+	"context"
 	"fmt"
 	"io"
 	"io/ioutil"
@@ -91,9 +92,12 @@ second:
 	case *os.SyscallError:
 		nestedErr = err.Err
 		goto third
+	case *os.PathError: // for Plan 9
+		nestedErr = err.Err
+		goto third
 	}
 	switch nestedErr {
-	case errCanceled, errClosing, errMissingAddress:
+	case errCanceled, errClosing, errMissingAddress, errNoSuitableAddress:
 		return nil
 	}
 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -135,7 +139,7 @@ func TestDialError(t *testing.T) {
 
 	origTestHookLookupIP := testHookLookupIP
 	defer func() { testHookLookupIP = origTestHookLookupIP }()
-	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+	testHookLookupIP = func(ctx context.Context, fn func(context.Context, 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) {
@@ -203,6 +207,58 @@ func TestProtocolDialError(t *testing.T) {
 	}
 }
 
+func TestDialAddrError(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
+
+	for _, tt := range []struct {
+		network string
+		lit     string
+		addr    *TCPAddr
+	}{
+		{"tcp4", "::1", nil},
+		{"tcp4", "", &TCPAddr{IP: IPv6loopback}},
+		// We don't test the {"tcp6", "byte sequence", nil}
+		// case for now because there is no easy way to
+		// control name resolution.
+		{"tcp6", "", &TCPAddr{IP: IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}}},
+	} {
+		var err error
+		var c Conn
+		if tt.lit != "" {
+			c, err = Dial(tt.network, JoinHostPort(tt.lit, "0"))
+		} else {
+			c, err = DialTCP(tt.network, nil, tt.addr)
+		}
+		if err == nil {
+			c.Close()
+			t.Errorf("%s %q/%v: should fail", tt.network, tt.lit, tt.addr)
+			continue
+		}
+		if perr := parseDialError(err); perr != nil {
+			t.Error(perr)
+			continue
+		}
+		aerr, ok := err.(*OpError).Err.(*AddrError)
+		if !ok {
+			t.Errorf("%s %q/%v: should be AddrError: %v", tt.network, tt.lit, tt.addr, err)
+			continue
+		}
+		want := tt.lit
+		if tt.lit == "" {
+			want = tt.addr.IP.String()
+		}
+		if aerr.Addr != want {
+			t.Fatalf("%s: got %q; want %q", tt.network, aerr.Addr, want)
+		}
+	}
+}
+
 var listenErrorTests = []struct {
 	network, address string
 }{
@@ -228,7 +284,7 @@ func TestListenError(t *testing.T) {
 
 	origTestHookLookupIP := testHookLookupIP
 	defer func() { testHookLookupIP = origTestHookLookupIP }()
-	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+	testHookLookupIP = func(_ context.Context, fn func(context.Context, 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) {
@@ -288,7 +344,7 @@ func TestListenPacketError(t *testing.T) {
 
 	origTestHookLookupIP := testHookLookupIP
 	defer func() { testHookLookupIP = origTestHookLookupIP }()
-	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+	testHookLookupIP = func(_ context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
 		return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
 	}
 
@@ -413,7 +469,7 @@ second:
 		goto third
 	}
 	switch nestedErr {
-	case errCanceled, errClosing, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
+	case errCanceled, errClosing, errMissingAddress, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
 		return nil
 	}
 	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -543,6 +599,9 @@ second:
 	case *os.SyscallError:
 		nestedErr = err.Err
 		goto third
+	case *os.PathError: // for Plan 9
+		nestedErr = err.Err
+		goto third
 	}
 	switch nestedErr {
 	case errClosing, errTimeout:
@@ -703,3 +762,17 @@ func TestFileError(t *testing.T) {
 		ln.Close()
 	}
 }
+
+func parseLookupPortError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch nestedErr.(type) {
+	case *AddrError, *DNSError:
+		return nil
+	case *os.PathError: // for Plan 9
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+}
diff --git a/src/net/error_unix_test.go b/src/net/error_unix_test.go
new file mode 100644
index 0000000..9ce9e12
--- /dev/null
+++ b/src/net/error_unix_test.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.
+
+// +build !plan9,!windows
+
+package net
+
+import (
+	"os"
+	"syscall"
+)
+
+var (
+	errTimedout       = syscall.ETIMEDOUT
+	errOpNotSupported = syscall.EOPNOTSUPP
+
+	abortedConnRequestErrors = []error{syscall.ECONNABORTED} // see accept in fd_unix.go
+)
+
+func isPlatformError(err error) bool {
+	_, ok := err.(syscall.Errno)
+	return ok
+}
+
+func samePlatformError(err, want error) bool {
+	if op, ok := err.(*OpError); ok {
+		err = op.Err
+	}
+	if sys, ok := err.(*os.SyscallError); ok {
+		err = sys.Err
+	}
+	return err == want
+}
diff --git a/src/net/error_windows_test.go b/src/net/error_windows_test.go
new file mode 100644
index 0000000..834a9de
--- /dev/null
+++ b/src/net/error_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 net
+
+import "syscall"
+
+var (
+	errTimedout       = syscall.ETIMEDOUT
+	errOpNotSupported = syscall.EOPNOTSUPP
+
+	abortedConnRequestErrors = []error{syscall.ERROR_NETNAME_DELETED, syscall.WSAECONNRESET} // see accept in fd_windows.go
+)
+
+func isPlatformError(err error) bool {
+	_, ok := err.(syscall.Errno)
+	return ok
+}
diff --git a/src/net/external_test.go b/src/net/external_test.go
index d5ff2be..e18b547 100644
--- a/src/net/external_test.go
+++ b/src/net/external_test.go
@@ -6,15 +6,15 @@ package net
 
 import (
 	"fmt"
+	"internal/testenv"
 	"io"
 	"strings"
 	"testing"
 )
 
 func TestResolveGoogle(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
+
 	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
@@ -60,9 +60,8 @@ var dialGoogleTests = []struct {
 }
 
 func TestDialGoogle(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
+
 	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
diff --git a/src/net/fd_mutex.go b/src/net/fd_mutex.go
index 6d5509d..4591fd1 100644
--- a/src/net/fd_mutex.go
+++ b/src/net/fd_mutex.go
@@ -6,9 +6,9 @@ package net
 
 import "sync/atomic"
 
-// fdMutex is a specialized synchronization primitive
-// that manages lifetime of an fd and serializes access
-// to Read and Write methods on netFD.
+// fdMutex is a specialized synchronization primitive that manages
+// lifetime of an fd and serializes access to Read, Write and Close
+// methods on netFD.
 type fdMutex struct {
 	state uint64
 	rsema uint32
@@ -34,18 +34,21 @@ const (
 	mutexWMask   = (1<<20 - 1) << 43
 )
 
-// Read operations must do RWLock(true)/RWUnlock(true).
-// Write operations must do RWLock(false)/RWUnlock(false).
-// Misc operations must do Incref/Decref. Misc operations include functions like
-// setsockopt and setDeadline. They need to use Incref/Decref to ensure that
-// they operate on the correct fd in presence of a concurrent Close call
-// (otherwise fd can be closed under their feet).
-// Close operation must do IncrefAndClose/Decref.
+// Read operations must do rwlock(true)/rwunlock(true).
+//
+// Write operations must do rwlock(false)/rwunlock(false).
+//
+// Misc operations must do incref/decref.
+// Misc operations include functions like setsockopt and setDeadline.
+// They need to use incref/decref to ensure that they operate on the
+// correct fd in presence of a concurrent close call (otherwise fd can
+// be closed under their feet).
+//
+// Close operations must do increfAndClose/decref.
 
-// RWLock/Incref return whether fd is open.
-// RWUnlock/Decref return whether fd is closed and there are no remaining references.
-
-func (mu *fdMutex) Incref() bool {
+// incref adds a reference to mu.
+// It reports whether mu is available for reading or writing.
+func (mu *fdMutex) incref() bool {
 	for {
 		old := atomic.LoadUint64(&mu.state)
 		if old&mutexClosed != 0 {
@@ -61,7 +64,9 @@ func (mu *fdMutex) Incref() bool {
 	}
 }
 
-func (mu *fdMutex) IncrefAndClose() bool {
+// increfAndClose sets the state of mu to closed.
+// It reports whether there is no remaining reference.
+func (mu *fdMutex) increfAndClose() bool {
 	for {
 		old := atomic.LoadUint64(&mu.state)
 		if old&mutexClosed != 0 {
@@ -90,7 +95,9 @@ func (mu *fdMutex) IncrefAndClose() bool {
 	}
 }
 
-func (mu *fdMutex) Decref() bool {
+// decref removes a reference from mu.
+// It reports whether there is no remaining reference.
+func (mu *fdMutex) decref() bool {
 	for {
 		old := atomic.LoadUint64(&mu.state)
 		if old&mutexRefMask == 0 {
@@ -103,7 +110,9 @@ func (mu *fdMutex) Decref() bool {
 	}
 }
 
-func (mu *fdMutex) RWLock(read bool) bool {
+// lock adds a reference to mu and locks mu.
+// It reports whether mu is available for reading or writing.
+func (mu *fdMutex) rwlock(read bool) bool {
 	var mutexBit, mutexWait, mutexMask uint64
 	var mutexSema *uint32
 	if read {
@@ -146,7 +155,9 @@ func (mu *fdMutex) RWLock(read bool) bool {
 	}
 }
 
-func (mu *fdMutex) RWUnlock(read bool) bool {
+// unlock removes a reference from mu and unlocks mu.
+// It reports whether there is no remaining reference.
+func (mu *fdMutex) rwunlock(read bool) bool {
 	var mutexBit, mutexWait, mutexMask uint64
 	var mutexSema *uint32
 	if read {
@@ -182,3 +193,57 @@ func (mu *fdMutex) RWUnlock(read bool) bool {
 // Implemented in runtime package.
 func runtime_Semacquire(sema *uint32)
 func runtime_Semrelease(sema *uint32)
+
+// incref adds a reference to fd.
+// It returns an error when fd cannot be used.
+func (fd *netFD) incref() error {
+	if !fd.fdmu.incref() {
+		return errClosing
+	}
+	return nil
+}
+
+// decref removes a reference from fd.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *netFD) decref() {
+	if fd.fdmu.decref() {
+		fd.destroy()
+	}
+}
+
+// readLock adds a reference to fd and locks fd for reading.
+// It returns an error when fd cannot be used for reading.
+func (fd *netFD) readLock() error {
+	if !fd.fdmu.rwlock(true) {
+		return errClosing
+	}
+	return nil
+}
+
+// readUnlock removes a reference from fd and unlocks fd for reading.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *netFD) readUnlock() {
+	if fd.fdmu.rwunlock(true) {
+		fd.destroy()
+	}
+}
+
+// writeLock adds a reference to fd and locks fd for writing.
+// It returns an error when fd cannot be used for writing.
+func (fd *netFD) writeLock() error {
+	if !fd.fdmu.rwlock(false) {
+		return errClosing
+	}
+	return nil
+}
+
+// writeUnlock removes a reference from fd and unlocks fd for writing.
+// It also closes fd when the state of fd is set to closed and there
+// is no remaining reference.
+func (fd *netFD) writeUnlock() {
+	if fd.fdmu.rwunlock(false) {
+		fd.destroy()
+	}
+}
diff --git a/src/net/fd_mutex_test.go b/src/net/fd_mutex_test.go
index c34ec59..3542c70 100644
--- a/src/net/fd_mutex_test.go
+++ b/src/net/fd_mutex_test.go
@@ -14,44 +14,44 @@ import (
 func TestMutexLock(t *testing.T) {
 	var mu fdMutex
 
-	if !mu.Incref() {
+	if !mu.incref() {
 		t.Fatal("broken")
 	}
-	if mu.Decref() {
+	if mu.decref() {
 		t.Fatal("broken")
 	}
 
-	if !mu.RWLock(true) {
+	if !mu.rwlock(true) {
 		t.Fatal("broken")
 	}
-	if mu.RWUnlock(true) {
+	if mu.rwunlock(true) {
 		t.Fatal("broken")
 	}
 
-	if !mu.RWLock(false) {
+	if !mu.rwlock(false) {
 		t.Fatal("broken")
 	}
-	if mu.RWUnlock(false) {
+	if mu.rwunlock(false) {
 		t.Fatal("broken")
 	}
 }
 
 func TestMutexClose(t *testing.T) {
 	var mu fdMutex
-	if !mu.IncrefAndClose() {
+	if !mu.increfAndClose() {
 		t.Fatal("broken")
 	}
 
-	if mu.Incref() {
+	if mu.incref() {
 		t.Fatal("broken")
 	}
-	if mu.RWLock(true) {
+	if mu.rwlock(true) {
 		t.Fatal("broken")
 	}
-	if mu.RWLock(false) {
+	if mu.rwlock(false) {
 		t.Fatal("broken")
 	}
-	if mu.IncrefAndClose() {
+	if mu.increfAndClose() {
 		t.Fatal("broken")
 	}
 }
@@ -59,10 +59,10 @@ func TestMutexClose(t *testing.T) {
 func TestMutexCloseUnblock(t *testing.T) {
 	c := make(chan bool)
 	var mu fdMutex
-	mu.RWLock(true)
+	mu.rwlock(true)
 	for i := 0; i < 4; i++ {
 		go func() {
-			if mu.RWLock(true) {
+			if mu.rwlock(true) {
 				t.Error("broken")
 				return
 			}
@@ -76,7 +76,7 @@ func TestMutexCloseUnblock(t *testing.T) {
 		t.Fatal("broken")
 	default:
 	}
-	mu.IncrefAndClose() // Must unblock the readers.
+	mu.increfAndClose() // Must unblock the readers.
 	for i := 0; i < 4; i++ {
 		select {
 		case <-c:
@@ -84,10 +84,10 @@ func TestMutexCloseUnblock(t *testing.T) {
 			t.Fatal("broken")
 		}
 	}
-	if mu.Decref() {
+	if mu.decref() {
 		t.Fatal("broken")
 	}
-	if !mu.RWUnlock(true) {
+	if !mu.rwunlock(true) {
 		t.Fatal("broken")
 	}
 }
@@ -103,21 +103,21 @@ func TestMutexPanic(t *testing.T) {
 	}
 
 	var mu fdMutex
-	ensurePanics(func() { mu.Decref() })
-	ensurePanics(func() { mu.RWUnlock(true) })
-	ensurePanics(func() { mu.RWUnlock(false) })
+	ensurePanics(func() { mu.decref() })
+	ensurePanics(func() { mu.rwunlock(true) })
+	ensurePanics(func() { mu.rwunlock(false) })
 
-	ensurePanics(func() { mu.Incref(); mu.Decref(); mu.Decref() })
-	ensurePanics(func() { mu.RWLock(true); mu.RWUnlock(true); mu.RWUnlock(true) })
-	ensurePanics(func() { mu.RWLock(false); mu.RWUnlock(false); mu.RWUnlock(false) })
+	ensurePanics(func() { mu.incref(); mu.decref(); mu.decref() })
+	ensurePanics(func() { mu.rwlock(true); mu.rwunlock(true); mu.rwunlock(true) })
+	ensurePanics(func() { mu.rwlock(false); mu.rwunlock(false); mu.rwunlock(false) })
 
 	// ensure that it's still not broken
-	mu.Incref()
-	mu.Decref()
-	mu.RWLock(true)
-	mu.RWUnlock(true)
-	mu.RWLock(false)
-	mu.RWUnlock(false)
+	mu.incref()
+	mu.decref()
+	mu.rwlock(true)
+	mu.rwunlock(true)
+	mu.rwlock(false)
+	mu.rwunlock(false)
 }
 
 func TestMutexStress(t *testing.T) {
@@ -138,16 +138,16 @@ func TestMutexStress(t *testing.T) {
 			for i := 0; i < N; i++ {
 				switch r.Intn(3) {
 				case 0:
-					if !mu.Incref() {
+					if !mu.incref() {
 						t.Error("broken")
 						return
 					}
-					if mu.Decref() {
+					if mu.decref() {
 						t.Error("broken")
 						return
 					}
 				case 1:
-					if !mu.RWLock(true) {
+					if !mu.rwlock(true) {
 						t.Error("broken")
 						return
 					}
@@ -158,12 +158,12 @@ func TestMutexStress(t *testing.T) {
 					}
 					readState[0]++
 					readState[1]++
-					if mu.RWUnlock(true) {
+					if mu.rwunlock(true) {
 						t.Error("broken")
 						return
 					}
 				case 2:
-					if !mu.RWLock(false) {
+					if !mu.rwlock(false) {
 						t.Error("broken")
 						return
 					}
@@ -174,7 +174,7 @@ func TestMutexStress(t *testing.T) {
 					}
 					writeState[0]++
 					writeState[1]++
-					if mu.RWUnlock(false) {
+					if mu.rwunlock(false) {
 						t.Error("broken")
 						return
 					}
@@ -186,10 +186,10 @@ func TestMutexStress(t *testing.T) {
 	for p := 0; p < P; p++ {
 		<-done
 	}
-	if !mu.IncrefAndClose() {
+	if !mu.increfAndClose() {
 		t.Fatal("broken")
 	}
-	if !mu.Decref() {
+	if !mu.decref() {
 		t.Fatal("broken")
 	}
 }
diff --git a/src/net/fd_plan9.go b/src/net/fd_plan9.go
index cec8860..7533232 100644
--- a/src/net/fd_plan9.go
+++ b/src/net/fd_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -32,12 +32,6 @@ func sysInit() {
 	netdir = "/net"
 }
 
-func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
-	// On plan9, use the relatively inefficient
-	// goroutine-racing implementation.
-	return dialChannel(net, ra, dialer, deadline)
-}
-
 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
 }
@@ -74,55 +68,6 @@ func (fd *netFD) destroy() {
 	fd.data = nil
 }
 
-// Add a reference to this fd.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) incref() error {
-	if !fd.fdmu.Incref() {
-		return errClosing
-	}
-	return nil
-}
-
-// Remove a reference to this FD and close if we've been asked to do so
-// (and there are no references left).
-func (fd *netFD) decref() {
-	if fd.fdmu.Decref() {
-		fd.destroy()
-	}
-}
-
-// Add a reference to this fd and lock for reading.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) readLock() error {
-	if !fd.fdmu.RWLock(true) {
-		return errClosing
-	}
-	return nil
-}
-
-// Unlock for reading and remove a reference to this FD.
-func (fd *netFD) readUnlock() {
-	if fd.fdmu.RWUnlock(true) {
-		fd.destroy()
-	}
-}
-
-// Add a reference to this fd and lock for writing.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) writeLock() error {
-	if !fd.fdmu.RWLock(false) {
-		return errClosing
-	}
-	return nil
-}
-
-// Unlock for writing and remove a reference to this FD.
-func (fd *netFD) writeUnlock() {
-	if fd.fdmu.RWUnlock(false) {
-		fd.destroy()
-	}
-}
-
 func (fd *netFD) Read(b []byte) (n int, err error) {
 	if !fd.ok() || fd.data == nil {
 		return 0, syscall.EINVAL
@@ -131,7 +76,13 @@ func (fd *netFD) Read(b []byte) (n int, err error) {
 		return 0, err
 	}
 	defer fd.readUnlock()
+	if len(b) == 0 {
+		return 0, nil
+	}
 	n, err = fd.data.Read(b)
+	if isHangup(err) {
+		err = io.EOF
+	}
 	if fd.net == "udp" && err == io.EOF {
 		n = 0
 		err = nil
@@ -165,7 +116,7 @@ func (fd *netFD) closeWrite() error {
 }
 
 func (fd *netFD) Close() error {
-	if !fd.fdmu.IncrefAndClose() {
+	if !fd.fdmu.increfAndClose() {
 		return errClosing
 	}
 	if !fd.ok() {
@@ -206,9 +157,7 @@ func (l *TCPListener) dup() (*os.File, error) {
 }
 
 func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
-	syscall.ForkLock.RLock()
 	dfd, err := syscall.Dup(int(f.Fd()), -1)
-	syscall.ForkLock.RUnlock()
 	if err != nil {
 		return nil, os.NewSyscallError("dup", err)
 	}
@@ -234,3 +183,7 @@ func setReadBuffer(fd *netFD, bytes int) error {
 func setWriteBuffer(fd *netFD, bytes int) error {
 	return syscall.EPLAN9
 }
+
+func isHangup(err error) bool {
+	return err != nil && stringsHasSuffix(err.Error(), "Hangup")
+}
diff --git a/src/net/fd_poll_nacl.go b/src/net/fd_poll_nacl.go
index cdf14e3..cda8b82 100644
--- a/src/net/fd_poll_nacl.go
+++ b/src/net/fd_poll_nacl.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -14,44 +14,44 @@ type pollDesc struct {
 	closing bool
 }
 
-func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil }
+func (pd *pollDesc) init(fd *netFD) error { pd.fd = fd; return nil }
 
-func (pd *pollDesc) Close() {}
+func (pd *pollDesc) close() {}
 
-func (pd *pollDesc) Evict() {
+func (pd *pollDesc) evict() {
 	pd.closing = true
 	if pd.fd != nil {
 		syscall.StopIO(pd.fd.sysfd)
 	}
 }
 
-func (pd *pollDesc) Prepare(mode int) error {
+func (pd *pollDesc) prepare(mode int) error {
 	if pd.closing {
 		return errClosing
 	}
 	return nil
 }
 
-func (pd *pollDesc) PrepareRead() error { return pd.Prepare('r') }
+func (pd *pollDesc) prepareRead() error { return pd.prepare('r') }
 
-func (pd *pollDesc) PrepareWrite() error { return pd.Prepare('w') }
+func (pd *pollDesc) prepareWrite() error { return pd.prepare('w') }
 
-func (pd *pollDesc) Wait(mode int) error {
+func (pd *pollDesc) wait(mode int) error {
 	if pd.closing {
 		return errClosing
 	}
 	return errTimeout
 }
 
-func (pd *pollDesc) WaitRead() error { return pd.Wait('r') }
+func (pd *pollDesc) waitRead() error { return pd.wait('r') }
 
-func (pd *pollDesc) WaitWrite() error { return pd.Wait('w') }
+func (pd *pollDesc) waitWrite() error { return pd.wait('w') }
 
-func (pd *pollDesc) WaitCanceled(mode int) {}
+func (pd *pollDesc) waitCanceled(mode int) {}
 
-func (pd *pollDesc) WaitCanceledRead() {}
+func (pd *pollDesc) waitCanceledRead() {}
 
-func (pd *pollDesc) WaitCanceledWrite() {}
+func (pd *pollDesc) waitCanceledWrite() {}
 
 func (fd *netFD) setDeadline(t time.Time) error {
 	return setDeadlineImpl(fd, t, 'r'+'w')
diff --git a/src/net/fd_poll_runtime.go b/src/net/fd_poll_runtime.go
index 8522cce..6c1d095 100644
--- a/src/net/fd_poll_runtime.go
+++ b/src/net/fd_poll_runtime.go
@@ -30,7 +30,7 @@ type pollDesc struct {
 
 var serverInit sync.Once
 
-func (pd *pollDesc) Init(fd *netFD) error {
+func (pd *pollDesc) init(fd *netFD) error {
 	serverInit.Do(runtime_pollServerInit)
 	ctx, errno := runtime_pollOpen(uintptr(fd.sysfd))
 	if errno != 0 {
@@ -40,7 +40,7 @@ func (pd *pollDesc) Init(fd *netFD) error {
 	return nil
 }
 
-func (pd *pollDesc) Close() {
+func (pd *pollDesc) close() {
 	if pd.runtimeCtx == 0 {
 		return
 	}
@@ -49,49 +49,49 @@ func (pd *pollDesc) Close() {
 }
 
 // Evict evicts fd from the pending list, unblocking any I/O running on fd.
-func (pd *pollDesc) Evict() {
+func (pd *pollDesc) evict() {
 	if pd.runtimeCtx == 0 {
 		return
 	}
 	runtime_pollUnblock(pd.runtimeCtx)
 }
 
-func (pd *pollDesc) Prepare(mode int) error {
+func (pd *pollDesc) prepare(mode int) error {
 	res := runtime_pollReset(pd.runtimeCtx, mode)
 	return convertErr(res)
 }
 
-func (pd *pollDesc) PrepareRead() error {
-	return pd.Prepare('r')
+func (pd *pollDesc) prepareRead() error {
+	return pd.prepare('r')
 }
 
-func (pd *pollDesc) PrepareWrite() error {
-	return pd.Prepare('w')
+func (pd *pollDesc) prepareWrite() error {
+	return pd.prepare('w')
 }
 
-func (pd *pollDesc) Wait(mode int) error {
+func (pd *pollDesc) wait(mode int) error {
 	res := runtime_pollWait(pd.runtimeCtx, mode)
 	return convertErr(res)
 }
 
-func (pd *pollDesc) WaitRead() error {
-	return pd.Wait('r')
+func (pd *pollDesc) waitRead() error {
+	return pd.wait('r')
 }
 
-func (pd *pollDesc) WaitWrite() error {
-	return pd.Wait('w')
+func (pd *pollDesc) waitWrite() error {
+	return pd.wait('w')
 }
 
-func (pd *pollDesc) WaitCanceled(mode int) {
+func (pd *pollDesc) waitCanceled(mode int) {
 	runtime_pollWaitCanceled(pd.runtimeCtx, mode)
 }
 
-func (pd *pollDesc) WaitCanceledRead() {
-	pd.WaitCanceled('r')
+func (pd *pollDesc) waitCanceledRead() {
+	pd.waitCanceled('r')
 }
 
-func (pd *pollDesc) WaitCanceledWrite() {
-	pd.WaitCanceled('w')
+func (pd *pollDesc) waitCanceledWrite() {
+	pd.waitCanceled('w')
 }
 
 func convertErr(res int) error {
@@ -120,7 +120,13 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
 }
 
 func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
-	d := runtimeNano() + int64(t.Sub(time.Now()))
+	diff := int64(t.Sub(time.Now()))
+	d := runtimeNano() + diff
+	if d <= 0 && diff > 0 {
+		// If the user has a deadline in the future, but the delay calculation
+		// overflows, then set the deadline to the maximum possible value.
+		d = 1<<63 - 1
+	}
 	if t.IsZero() {
 		d = 0
 	}
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 2639eab..0f80bc7 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -7,12 +7,12 @@
 package net
 
 import (
+	"context"
 	"io"
 	"os"
 	"runtime"
 	"sync/atomic"
 	"syscall"
-	"time"
 )
 
 // Network file descriptor.
@@ -36,16 +36,12 @@ type netFD struct {
 func sysInit() {
 }
 
-func dial(network string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
-	return dialer(deadline)
-}
-
 func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
 	return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil
 }
 
 func (fd *netFD) init() error {
-	if err := fd.pd.Init(fd); err != nil {
+	if err := fd.pd.init(fd); err != nil {
 		return err
 	}
 	return nil
@@ -68,15 +64,17 @@ func (fd *netFD) name() string {
 	return fd.net + ":" + ls + "->" + rs
 }
 
-func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-chan struct{}) error {
+func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) 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 := connectFunc(fd.sysfd, ra); err {
 	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
 	case nil, syscall.EISCONN:
-		if !deadline.IsZero() && deadline.Before(time.Now()) {
-			return errTimeout
+		select {
+		case <-ctx.Done():
+			return mapErr(ctx.Err())
+		default:
 		}
 		if err := fd.init(); err != nil {
 			return err
@@ -98,23 +96,27 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
 	if err := fd.init(); err != nil {
 		return err
 	}
-	if !deadline.IsZero() {
+	if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
 		fd.setWriteDeadline(deadline)
 		defer fd.setWriteDeadline(noDeadline)
 	}
-	if cancel != nil {
-		done := make(chan bool)
-		defer close(done)
-		go func() {
-			select {
-			case <-cancel:
-				// Force the runtime's poller to immediately give
-				// up waiting for writability.
-				fd.setWriteDeadline(aLongTimeAgo)
-			case <-done:
-			}
-		}()
-	}
+
+	// Wait for the goroutine converting context.Done into a write timeout
+	// to exist, otherwise our caller might cancel the context and
+	// cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial.
+	done := make(chan bool) // must be unbuffered
+	defer func() { done <- true }()
+	go func() {
+		select {
+		case <-ctx.Done():
+			// Force the runtime's poller to immediately give
+			// up waiting for writability.
+			fd.setWriteDeadline(aLongTimeAgo)
+			<-done
+		case <-done:
+		}
+	}()
+
 	for {
 		// Performing multiple connect system calls on a
 		// non-blocking socket under Unix variants does not
@@ -124,10 +126,10 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
 		// SO_ERROR socket option to see if the connection
 		// succeeded or failed. See issue 7474 for further
 		// details.
-		if err := fd.pd.WaitWrite(); err != nil {
+		if err := fd.pd.waitWrite(); err != nil {
 			select {
-			case <-cancel:
-				return errCanceled
+			case <-ctx.Done():
+				return mapErr(ctx.Err())
 			default:
 			}
 			return err
@@ -139,7 +141,16 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
 		switch err := syscall.Errno(nerr); err {
 		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
 		case syscall.Errno(0), syscall.EISCONN:
-			return nil
+			if runtime.GOOS != "darwin" {
+				return nil
+			}
+			// See golang.org/issue/14548.
+			// On Darwin, multiple connect system calls on
+			// a non-blocking socket never harm SO_ERROR.
+			switch err := connectFunc(fd.sysfd, ra); err {
+			case nil, syscall.EISCONN:
+				return nil
+			}
 		default:
 			return os.NewSyscallError("getsockopt", err)
 		}
@@ -149,71 +160,22 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
 func (fd *netFD) destroy() {
 	// Poller may want to unregister fd in readiness notification mechanism,
 	// so this must be executed before closeFunc.
-	fd.pd.Close()
+	fd.pd.close()
 	closeFunc(fd.sysfd)
 	fd.sysfd = -1
 	runtime.SetFinalizer(fd, nil)
 }
 
-// Add a reference to this fd.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) incref() error {
-	if !fd.fdmu.Incref() {
-		return errClosing
-	}
-	return nil
-}
-
-// Remove a reference to this FD and close if we've been asked to do so
-// (and there are no references left).
-func (fd *netFD) decref() {
-	if fd.fdmu.Decref() {
-		fd.destroy()
-	}
-}
-
-// Add a reference to this fd and lock for reading.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) readLock() error {
-	if !fd.fdmu.RWLock(true) {
-		return errClosing
-	}
-	return nil
-}
-
-// Unlock for reading and remove a reference to this FD.
-func (fd *netFD) readUnlock() {
-	if fd.fdmu.RWUnlock(true) {
-		fd.destroy()
-	}
-}
-
-// Add a reference to this fd and lock for writing.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) writeLock() error {
-	if !fd.fdmu.RWLock(false) {
-		return errClosing
-	}
-	return nil
-}
-
-// Unlock for writing and remove a reference to this FD.
-func (fd *netFD) writeUnlock() {
-	if fd.fdmu.RWUnlock(false) {
-		fd.destroy()
-	}
-}
-
 func (fd *netFD) Close() error {
-	if !fd.fdmu.IncrefAndClose() {
+	if !fd.fdmu.increfAndClose() {
 		return errClosing
 	}
 	// Unblock any I/O.  Once it all unblocks and returns,
 	// so that it cannot be referring to fd.sysfd anymore,
-	// the final decref will close fd.sysfd.  This should happen
+	// 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.
-	fd.pd.Evict()
+	fd.pd.evict()
 	fd.decref()
 	return nil
 }
@@ -239,7 +201,15 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
 		return 0, err
 	}
 	defer fd.readUnlock()
-	if err := fd.pd.PrepareRead(); err != nil {
+	if len(p) == 0 {
+		// If the caller wanted a zero byte read, return immediately
+		// without trying. (But after acquiring the readLock.) Otherwise
+		// syscall.Read returns 0, nil and eofError turns that into
+		// io.EOF.
+		// TODO(bradfitz): make it wait for readability? (Issue 15735)
+		return 0, nil
+	}
+	if err := fd.pd.prepareRead(); err != nil {
 		return 0, err
 	}
 	for {
@@ -247,7 +217,7 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
 		if err != nil {
 			n = 0
 			if err == syscall.EAGAIN {
-				if err = fd.pd.WaitRead(); err == nil {
+				if err = fd.pd.waitRead(); err == nil {
 					continue
 				}
 			}
@@ -266,7 +236,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
 		return 0, nil, err
 	}
 	defer fd.readUnlock()
-	if err := fd.pd.PrepareRead(); err != nil {
+	if err := fd.pd.prepareRead(); err != nil {
 		return 0, nil, err
 	}
 	for {
@@ -274,7 +244,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
 		if err != nil {
 			n = 0
 			if err == syscall.EAGAIN {
-				if err = fd.pd.WaitRead(); err == nil {
+				if err = fd.pd.waitRead(); err == nil {
 					continue
 				}
 			}
@@ -293,7 +263,7 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
 		return 0, 0, 0, nil, err
 	}
 	defer fd.readUnlock()
-	if err := fd.pd.PrepareRead(); err != nil {
+	if err := fd.pd.prepareRead(); err != nil {
 		return 0, 0, 0, nil, err
 	}
 	for {
@@ -301,7 +271,7 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
 		if err != nil {
 			// TODO(dfc) should n and oobn be set to 0
 			if err == syscall.EAGAIN {
-				if err = fd.pd.WaitRead(); err == nil {
+				if err = fd.pd.waitRead(); err == nil {
 					continue
 				}
 			}
@@ -320,7 +290,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
 		return 0, err
 	}
 	defer fd.writeUnlock()
-	if err := fd.pd.PrepareWrite(); err != nil {
+	if err := fd.pd.prepareWrite(); err != nil {
 		return 0, err
 	}
 	for {
@@ -333,7 +303,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
 			break
 		}
 		if err == syscall.EAGAIN {
-			if err = fd.pd.WaitWrite(); err == nil {
+			if err = fd.pd.waitWrite(); err == nil {
 				continue
 			}
 		}
@@ -356,13 +326,13 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
 		return 0, err
 	}
 	defer fd.writeUnlock()
-	if err := fd.pd.PrepareWrite(); err != nil {
+	if err := fd.pd.prepareWrite(); err != nil {
 		return 0, err
 	}
 	for {
 		err = syscall.Sendto(fd.sysfd, p, 0, sa)
 		if err == syscall.EAGAIN {
-			if err = fd.pd.WaitWrite(); err == nil {
+			if err = fd.pd.waitWrite(); err == nil {
 				continue
 			}
 		}
@@ -382,13 +352,13 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
 		return 0, 0, err
 	}
 	defer fd.writeUnlock()
-	if err := fd.pd.PrepareWrite(); err != nil {
+	if err := fd.pd.prepareWrite(); err != nil {
 		return 0, 0, err
 	}
 	for {
 		n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0)
 		if err == syscall.EAGAIN {
-			if err = fd.pd.WaitWrite(); err == nil {
+			if err = fd.pd.waitWrite(); err == nil {
 				continue
 			}
 		}
@@ -411,7 +381,7 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
 
 	var s int
 	var rsa syscall.Sockaddr
-	if err = fd.pd.PrepareRead(); err != nil {
+	if err = fd.pd.prepareRead(); err != nil {
 		return nil, err
 	}
 	for {
@@ -423,7 +393,7 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
 			}
 			switch nerr.Err {
 			case syscall.EAGAIN:
-				if err = fd.pd.WaitRead(); err == nil {
+				if err = fd.pd.waitRead(); err == nil {
 					continue
 				}
 			case syscall.ECONNABORTED:
@@ -464,7 +434,7 @@ func dupCloseOnExec(fd int) (newfd int, err error) {
 			// and fcntl there falls back (undocumented)
 			// to doing an ioctl instead, returning EBADF
 			// in this case because fd is not of the
-			// expected device fd type.  Treat it as
+			// expected device fd type. Treat it as
 			// EINVAL instead, so we fall back to the
 			// normal dup path.
 			// TODO: only do this on 10.6 if we can detect 10.6
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index fd50d77..b0b6769 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -5,12 +5,12 @@
 package net
 
 import (
+	"context"
 	"internal/race"
 	"os"
 	"runtime"
 	"sync"
 	"syscall"
-	"time"
 	"unsafe"
 )
 
@@ -42,11 +42,6 @@ func sysInit() {
 		initErr = os.NewSyscallError("wsastartup", e)
 	}
 	canCancelIO = syscall.LoadCancelIoEx() == nil
-	if syscall.LoadGetAddrInfo() == nil {
-		lookupPort = newLookupPort
-		lookupIP = newLookupIP
-	}
-
 	hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil
 	if hasLoadSetFileCompletionNotificationModes {
 		// It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed:
@@ -69,22 +64,15 @@ func sysInit() {
 	}
 }
 
+// canUseConnectEx reports whether we can use the ConnectEx Windows API call
+// for the given network type.
 func canUseConnectEx(net string) bool {
 	switch net {
-	case "udp", "udp4", "udp6", "ip", "ip4", "ip6":
-		// ConnectEx windows API does not support connectionless sockets.
-		return false
-	}
-	return syscall.LoadConnectEx() == nil
-}
-
-func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
-	if !canUseConnectEx(net) {
-		// Use the relatively inefficient goroutine-racing
-		// implementation of DialTimeout.
-		return dialChannel(net, ra, dialer, deadline)
+	case "tcp", "tcp4", "tcp6":
+		return true
 	}
-	return dialer(deadline)
+	// ConnectEx windows API does not support connectionless sockets.
+	return false
 }
 
 // operation contains superset of data necessary to perform all async IO.
@@ -152,7 +140,7 @@ func (s *ioSrv) ProcessRemoteIO() {
 func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) error) (int, error) {
 	fd := o.fd
 	// Notify runtime netpoll about starting IO.
-	err := fd.pd.Prepare(int(o.mode))
+	err := fd.pd.prepare(int(o.mode))
 	if err != nil {
 		return 0, err
 	}
@@ -180,7 +168,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 		return 0, err
 	}
 	// Wait for our request to complete.
-	err = fd.pd.Wait(int(o.mode))
+	err = fd.pd.wait(int(o.mode))
 	if err == nil {
 		// All is good. Extract our IO results and return.
 		if o.errno != 0 {
@@ -210,7 +198,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 		<-o.errc
 	}
 	// Wait for cancelation to complete.
-	fd.pd.WaitCanceled(int(o.mode))
+	fd.pd.waitCanceled(int(o.mode))
 	if o.errno != 0 {
 		err = syscall.Errno(o.errno)
 		if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
@@ -273,7 +261,7 @@ func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error)
 }
 
 func (fd *netFD) init() error {
-	if err := fd.pd.Init(fd); err != nil {
+	if err := fd.pd.init(fd); err != nil {
 		return err
 	}
 	if hasLoadSetFileCompletionNotificationModes {
@@ -320,19 +308,20 @@ func (fd *netFD) setAddr(laddr, raddr Addr) {
 	runtime.SetFinalizer(fd, (*netFD).Close)
 }
 
-func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-chan struct{}) error {
+func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) error {
 	// Do not need to call fd.writeLock here,
 	// because fd is not yet accessible to user,
 	// so no concurrent operations are possible.
 	if err := fd.init(); err != nil {
 		return err
 	}
-	if !deadline.IsZero() {
+	if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
 		fd.setWriteDeadline(deadline)
 		defer fd.setWriteDeadline(noDeadline)
 	}
 	if !canUseConnectEx(fd.net) {
-		return os.NewSyscallError("connect", connectFunc(fd.sysfd, ra))
+		err := connectFunc(fd.sysfd, ra)
+		return os.NewSyscallError("connect", err)
 	}
 	// ConnectEx windows API requires an unconnected, previously bound socket.
 	if la == nil {
@@ -351,26 +340,30 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time, cancel <-c
 	// Call ConnectEx API.
 	o := &fd.wop
 	o.sa = ra
-	if cancel != nil {
-		done := make(chan struct{})
-		defer close(done)
-		go func() {
-			select {
-			case <-cancel:
-				// Force the runtime's poller to immediately give
-				// up waiting for writability.
-				fd.setWriteDeadline(aLongTimeAgo)
-			case <-done:
-			}
-		}()
-	}
+
+	// Wait for the goroutine converting context.Done into a write timeout
+	// to exist, otherwise our caller might cancel the context and
+	// cause fd.setWriteDeadline(aLongTimeAgo) to cancel a successful dial.
+	done := make(chan bool) // must be unbuffered
+	defer func() { done <- true }()
+	go func() {
+		select {
+		case <-ctx.Done():
+			// Force the runtime's poller to immediately give
+			// up waiting for writability.
+			fd.setWriteDeadline(aLongTimeAgo)
+			<-done
+		case <-done:
+		}
+	}()
+
 	_, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error {
 		return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
 	})
 	if err != nil {
 		select {
-		case <-cancel:
-			return errCanceled
+		case <-ctx.Done():
+			return mapErr(ctx.Err())
 		default:
 			if _, ok := err.(syscall.Errno); ok {
 				err = os.NewSyscallError("connectex", err)
@@ -388,68 +381,19 @@ func (fd *netFD) destroy() {
 	}
 	// Poller may want to unregister fd in readiness notification mechanism,
 	// so this must be executed before closeFunc.
-	fd.pd.Close()
+	fd.pd.close()
 	closeFunc(fd.sysfd)
 	fd.sysfd = syscall.InvalidHandle
 	// no need for a finalizer anymore
 	runtime.SetFinalizer(fd, nil)
 }
 
-// Add a reference to this fd.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) incref() error {
-	if !fd.fdmu.Incref() {
-		return errClosing
-	}
-	return nil
-}
-
-// Remove a reference to this FD and close if we've been asked to do so
-// (and there are no references left).
-func (fd *netFD) decref() {
-	if fd.fdmu.Decref() {
-		fd.destroy()
-	}
-}
-
-// Add a reference to this fd and lock for reading.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) readLock() error {
-	if !fd.fdmu.RWLock(true) {
-		return errClosing
-	}
-	return nil
-}
-
-// Unlock for reading and remove a reference to this FD.
-func (fd *netFD) readUnlock() {
-	if fd.fdmu.RWUnlock(true) {
-		fd.destroy()
-	}
-}
-
-// Add a reference to this fd and lock for writing.
-// Returns an error if the fd cannot be used.
-func (fd *netFD) writeLock() error {
-	if !fd.fdmu.RWLock(false) {
-		return errClosing
-	}
-	return nil
-}
-
-// Unlock for writing and remove a reference to this FD.
-func (fd *netFD) writeUnlock() {
-	if fd.fdmu.RWUnlock(false) {
-		fd.destroy()
-	}
-}
-
 func (fd *netFD) Close() error {
-	if !fd.fdmu.IncrefAndClose() {
+	if !fd.fdmu.increfAndClose() {
 		return errClosing
 	}
 	// unblock pending reader and writer
-	fd.pd.Evict()
+	fd.pd.evict()
 	fd.decref()
 	return nil
 }
@@ -483,7 +427,9 @@ func (fd *netFD) Read(buf []byte) (int, error) {
 	if race.Enabled {
 		race.Acquire(unsafe.Pointer(&ioSync))
 	}
-	err = fd.eofError(n, err)
+	if len(buf) != 0 {
+		err = fd.eofError(n, err)
+	}
 	if _, ok := err.(syscall.Errno); ok {
 		err = os.NewSyscallError("wsarecv", err)
 	}
@@ -579,7 +525,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
 	o.handle = s
 	o.rsan = int32(unsafe.Sizeof(rawsa[0]))
 	_, err = rsrv.ExecIO(o, "AcceptEx", func(o *operation) error {
-		return syscall.AcceptEx(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o)
+		return acceptFunc(o.fd.sysfd, o.handle, (*byte)(unsafe.Pointer(&rawsa[0])), 0, uint32(o.rsan), uint32(o.rsan), &o.qty, &o.o)
 	})
 	if err != nil {
 		netfd.Close()
diff --git a/src/net/file_plan9.go b/src/net/file_plan9.go
index 892775a..2939c09 100644
--- a/src/net/file_plan9.go
+++ b/src/net/file_plan9.go
@@ -50,9 +50,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
 	name := comp[2]
 	switch file := comp[n-1]; file {
 	case "ctl", "clone":
-		syscall.ForkLock.RLock()
 		fd, err := syscall.Dup(int(f.Fd()), -1)
-		syscall.ForkLock.RUnlock()
 		if err != nil {
 			return nil, os.NewSyscallError("dup", err)
 		}
@@ -60,7 +58,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
 
 		dir := netdir + "/" + comp[n-2]
 		ctl = os.NewFile(uintptr(fd), dir+"/"+file)
-		ctl.Seek(0, 0)
+		ctl.Seek(0, io.SeekStart)
 		var buf [16]byte
 		n, err := ctl.Read(buf[:])
 		if err != nil {
diff --git a/src/net/hook.go b/src/net/hook.go
index 9ab34c0..d7316ea 100644
--- a/src/net/hook.go
+++ b/src/net/hook.go
@@ -4,9 +4,19 @@
 
 package net
 
+import "context"
+
 var (
-	testHookDialTCP      = dialTCP
-	testHookHostsPath    = "/etc/hosts"
-	testHookLookupIP     = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { return fn(host) }
+	// if non-nil, overrides dialTCP.
+	testHookDialTCP func(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error)
+
+	testHookHostsPath = "/etc/hosts"
+	testHookLookupIP  = func(
+		ctx context.Context,
+		fn func(context.Context, string) ([]IPAddr, error),
+		host string,
+	) ([]IPAddr, error) {
+		return fn(ctx, host)
+	}
 	testHookSetKeepAlive = func() {}
 )
diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go
index 126b0eb..63ea35a 100644
--- a/src/net/hook_windows.go
+++ b/src/net/hook_windows.go
@@ -13,9 +13,10 @@ 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
+	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
+	acceptFunc    func(syscall.Handle, syscall.Handle, *byte, uint32, uint32, uint32, *uint32, *syscall.Overlapped) error = syscall.AcceptEx
 )
diff --git a/src/net/hosts.go b/src/net/hosts.go
index c4de1b6..9c101c6 100644
--- a/src/net/hosts.go
+++ b/src/net/hosts.go
@@ -110,7 +110,9 @@ func lookupStaticHost(host string) []string {
 		lowerHost := []byte(host)
 		lowerASCIIBytes(lowerHost)
 		if ips, ok := hosts.byName[absDomainName(lowerHost)]; ok {
-			return ips
+			ipsCp := make([]string, len(ips))
+			copy(ipsCp, ips)
+			return ipsCp
 		}
 	}
 	return nil
@@ -127,7 +129,9 @@ func lookupStaticAddr(addr string) []string {
 	}
 	if len(hosts.byAddr) != 0 {
 		if hosts, ok := hosts.byAddr[addr]; ok {
-			return hosts
+			hostsCp := make([]string, len(hosts))
+			copy(hostsCp, hosts)
+			return hostsCp
 		}
 	}
 	return nil
diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go
index 4c67bfa..5d6c9cf 100644
--- a/src/net/hosts_test.go
+++ b/src/net/hosts_test.go
@@ -64,13 +64,17 @@ func TestLookupStaticHost(t *testing.T) {
 	for _, tt := range lookupStaticHostTests {
 		testHookHostsPath = tt.name
 		for _, ent := range tt.ents {
-			ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
-			for _, in := range ins {
-				addrs := lookupStaticHost(in)
-				if !reflect.DeepEqual(addrs, ent.out) {
-					t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, in, addrs, ent.out)
-				}
-			}
+			testStaticHost(t, tt.name, ent)
+		}
+	}
+}
+
+func testStaticHost(t *testing.T, hostsPath string, ent staticHostEntry) {
+	ins := []string{ent.in, absDomainName([]byte(ent.in)), strings.ToLower(ent.in), strings.ToUpper(ent.in)}
+	for _, in := range ins {
+		addrs := lookupStaticHost(in)
+		if !reflect.DeepEqual(addrs, ent.out) {
+			t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", hostsPath, in, addrs, ent.out)
 		}
 	}
 }
@@ -129,13 +133,43 @@ func TestLookupStaticAddr(t *testing.T) {
 	for _, tt := range lookupStaticAddrTests {
 		testHookHostsPath = tt.name
 		for _, ent := range tt.ents {
-			hosts := lookupStaticAddr(ent.in)
-			for i := range ent.out {
-				ent.out[i] = absDomainName([]byte(ent.out[i]))
-			}
-			if !reflect.DeepEqual(hosts, ent.out) {
-				t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", tt.name, ent.in, hosts, ent.out)
-			}
+			testStaticAddr(t, tt.name, ent)
 		}
 	}
 }
+
+func testStaticAddr(t *testing.T, hostsPath string, ent staticHostEntry) {
+	hosts := lookupStaticAddr(ent.in)
+	for i := range ent.out {
+		ent.out[i] = absDomainName([]byte(ent.out[i]))
+	}
+	if !reflect.DeepEqual(hosts, ent.out) {
+		t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", hostsPath, ent.in, hosts, ent.out)
+	}
+}
+
+func TestHostCacheModification(t *testing.T) {
+	// Ensure that programs can't modify the internals of the host cache.
+	// See https://github.com/golang/go/issues/14212.
+	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+
+	testHookHostsPath = "testdata/ipv4-hosts"
+	ent := staticHostEntry{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}
+	testStaticHost(t, testHookHostsPath, ent)
+	// Modify the addresses return by lookupStaticHost.
+	addrs := lookupStaticHost(ent.in)
+	for i := range addrs {
+		addrs[i] += "junk"
+	}
+	testStaticHost(t, testHookHostsPath, ent)
+
+	testHookHostsPath = "testdata/ipv6-hosts"
+	ent = staticHostEntry{"::1", []string{"localhost"}}
+	testStaticAddr(t, testHookHostsPath, ent)
+	// Modify the hosts return by lookupStaticAddr.
+	hosts := lookupStaticAddr(ent.in)
+	for i := range hosts {
+		hosts[i] += "junk"
+	}
+	testStaticAddr(t, testHookHostsPath, ent)
+}
diff --git a/src/net/http/cgi/host.go b/src/net/http/cgi/host.go
index 9b4d875..2eea643 100644
--- a/src/net/http/cgi/host.go
+++ b/src/net/http/cgi/host.go
@@ -10,7 +10,7 @@
 //
 // Note that using CGI means starting a new process to handle each
 // request, which is typically less efficient than using a
-// long-running server.  This package is intended primarily for
+// long-running server. This package is intended primarily for
 // compatibility with existing systems.
 package cgi
 
@@ -58,6 +58,7 @@ type Handler struct {
 	InheritEnv []string    // environment variables to inherit from host, as "key"
 	Logger     *log.Logger // optional log for errors or nil to use log.Print
 	Args       []string    // optional arguments to pass to child process
+	Stderr     io.Writer   // optional stderr for the child process; nil means os.Stderr
 
 	// PathLocationHandler specifies the root http Handler that
 	// should handle internal redirects when the CGI process
@@ -70,6 +71,13 @@ type Handler struct {
 	PathLocationHandler http.Handler
 }
 
+func (h *Handler) stderr() io.Writer {
+	if h.Stderr != nil {
+		return h.Stderr
+	}
+	return os.Stderr
+}
+
 // removeLeadingDuplicates remove leading duplicate in environments.
 // It's possible to override environment like following.
 //    cgi.Handler{
@@ -204,7 +212,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		Args:   append([]string{h.Path}, h.Args...),
 		Dir:    cwd,
 		Env:    env,
-		Stderr: os.Stderr, // for now
+		Stderr: h.stderr(),
 	}
 	if req.ContentLength != 0 {
 		cmd.Stdin = req.Body
diff --git a/src/net/http/cgi/host_test.go b/src/net/http/cgi/host_test.go
index 3327764..70c5aff 100644
--- a/src/net/http/cgi/host_test.go
+++ b/src/net/http/cgi/host_test.go
@@ -8,6 +8,7 @@ package cgi
 
 import (
 	"bufio"
+	"bytes"
 	"fmt"
 	"io"
 	"net"
@@ -500,6 +501,23 @@ func TestEnvOverride(t *testing.T) {
 	runCgiTest(t, h, "GET /test.cgi HTTP/1.0\nHost: example.com\n\n", expectedMap)
 }
 
+func TestHandlerStderr(t *testing.T) {
+	check(t)
+	var stderr bytes.Buffer
+	h := &Handler{
+		Path:   "testdata/test.cgi",
+		Root:   "/test.cgi",
+		Stderr: &stderr,
+	}
+
+	rw := httptest.NewRecorder()
+	req := newRequest("GET /test.cgi?writestderr=1 HTTP/1.0\nHost: example.com\n\n")
+	h.ServeHTTP(rw, req)
+	if got, want := stderr.String(), "Hello, stderr!\n"; got != want {
+		t.Errorf("Stderr = %q; want %q", got, want)
+	}
+}
+
 func TestRemoveLeadingDuplicates(t *testing.T) {
 	tests := []struct {
 		env  []string
diff --git a/src/net/http/cgi/testdata/test.cgi b/src/net/http/cgi/testdata/test.cgi
index ec7ee6f..667fce2 100755
--- a/src/net/http/cgi/testdata/test.cgi
+++ b/src/net/http/cgi/testdata/test.cgi
@@ -23,6 +23,10 @@ print "X-CGI-Pid: $$\r\n";
 print "X-Test-Header: X-Test-Value\r\n";
 print "\r\n";
 
+if ($params->{"writestderr"}) {
+    print STDERR "Hello, stderr!\n";
+}
+
 if ($params->{"bigresponse"}) {
     # 17 MB, for OS X: golang.org/issue/4958
     for (1..(17 * 1024)) {
diff --git a/src/net/http/client.go b/src/net/http/client.go
index 3106d22..993c247 100644
--- a/src/net/http/client.go
+++ b/src/net/http/client.go
@@ -44,9 +44,12 @@ type Client struct {
 	// following an HTTP redirect. The arguments req and via are
 	// the upcoming request and the requests made already, oldest
 	// first. If CheckRedirect returns an error, the Client's Get
-	// method returns both the previous Response and
-	// CheckRedirect's error (wrapped in a url.Error) instead of
-	// issuing the Request req.
+	// method returns both the previous Response (with its Body
+	// closed) and CheckRedirect's error (wrapped in a url.Error)
+	// instead of issuing the Request req.
+	// As a special case, if CheckRedirect returns ErrUseLastResponse,
+	// then the most recent response is returned with its body
+	// unclosed, along with a nil error.
 	//
 	// If CheckRedirect is nil, the Client uses its default policy,
 	// which is to stop after 10 consecutive requests.
@@ -110,10 +113,6 @@ type RoundTripper interface {
 	RoundTrip(*Request) (*Response, error)
 }
 
-// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
-// return true if the string includes a port.
-func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
-
 // refererForURL returns a referer without any authentication info or
 // an empty string if lastReq scheme is https and newReq scheme is http.
 func refererForURL(lastReq, newReq *url.URL) string {
@@ -138,14 +137,6 @@ func refererForURL(lastReq, newReq *url.URL) string {
 	return referer
 }
 
-// Used in Send to implement io.ReadCloser by bundling together the
-// bufio.Reader through which we read the response, and the underlying
-// network connection.
-type readClose struct {
-	io.Reader
-	io.Closer
-}
-
 func (c *Client) send(req *Request, deadline time.Time) (*Response, error) {
 	if c.Jar != nil {
 		for _, cookie := range c.Jar.Cookies(req.URL) {
@@ -161,28 +152,33 @@ func (c *Client) send(req *Request, deadline time.Time) (*Response, error) {
 			c.Jar.SetCookies(req.URL, rc)
 		}
 	}
-	return resp, err
+	return resp, nil
 }
 
 // Do sends an HTTP request and returns an HTTP response, following
-// policy (e.g. redirects, cookies, auth) as configured on the client.
+// policy (such as redirects, cookies, auth) as configured on the
+// client.
 //
 // An error is returned if caused by client policy (such as
-// CheckRedirect), or if there was an HTTP protocol error.
-// A non-2xx response doesn't cause an error.
-//
-// When err is nil, resp always contains a non-nil resp.Body.
+// CheckRedirect), or failure to speak HTTP (such as a network
+// connectivity problem). A non-2xx status code doesn't cause an
+// error.
 //
-// Callers should close resp.Body when done reading from it. If
-// resp.Body is not closed, the Client's underlying RoundTripper
-// (typically Transport) may not be able to re-use a persistent TCP
-// connection to the server for a subsequent "keep-alive" request.
+// If the returned error is nil, the Response will contain a non-nil
+// Body which the user is expected to close. If the Body is not
+// closed, the Client's underlying RoundTripper (typically Transport)
+// may not be able to re-use a persistent TCP connection to the server
+// for a subsequent "keep-alive" request.
 //
 // The request Body, if non-nil, will be closed by the underlying
 // Transport, even on errors.
 //
+// On error, any Response can be ignored. A non-nil Response with a
+// non-nil error only occurs when CheckRedirect fails, and even then
+// the returned Response.Body is already closed.
+//
 // Generally Get, Post, or PostForm will be used instead of Do.
-func (c *Client) Do(req *Request) (resp *Response, err error) {
+func (c *Client) Do(req *Request) (*Response, error) {
 	method := valueOrDefault(req.Method, "GET")
 	if method == "GET" || method == "HEAD" {
 		return c.doFollowingRedirects(req, shouldRedirectGet)
@@ -237,7 +233,7 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
 	}
 
 	// Most the callers of send (Get, Post, et al) don't need
-	// Headers, leaving it uninitialized.  We guarantee to the
+	// Headers, leaving it uninitialized. We guarantee to the
 	// Transport that this has been initialized, though.
 	if req.Header == nil {
 		forkReq()
@@ -424,101 +420,125 @@ func (c *Client) Get(url string) (resp *Response, err error) {
 
 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
-	if redirectChecker == nil {
-		redirectChecker = defaultCheckRedirect
+// ErrUseLastResponse can be returned by Client.CheckRedirect hooks to
+// control how redirects are processed. If returned, the next request
+// is not sent and the most recent response is returned with its body
+// unclosed.
+var ErrUseLastResponse = errors.New("net/http: use last response")
+
+// checkRedirect calls either the user's configured CheckRedirect
+// function, or the default.
+func (c *Client) checkRedirect(req *Request, via []*Request) error {
+	fn := c.CheckRedirect
+	if fn == nil {
+		fn = defaultCheckRedirect
 	}
-	var via []*Request
+	return fn(req, via)
+}
 
-	if ireq.URL == nil {
-		ireq.closeBody()
+func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) bool) (*Response, error) {
+	if req.URL == nil {
+		req.closeBody()
 		return nil, errors.New("http: nil Request.URL")
 	}
 
-	req := ireq
-	deadline := c.deadline()
-
-	urlStr := "" // next relative or absolute URL to fetch (after first request)
-	redirectFailed := false
-	for redirect := 0; ; redirect++ {
-		if redirect != 0 {
-			nreq := new(Request)
-			nreq.Cancel = ireq.Cancel
-			nreq.Method = ireq.Method
-			if ireq.Method == "POST" || ireq.Method == "PUT" {
-				nreq.Method = "GET"
+	var (
+		deadline = c.deadline()
+		reqs     []*Request
+		resp     *Response
+	)
+	uerr := func(err error) error {
+		req.closeBody()
+		method := valueOrDefault(reqs[0].Method, "GET")
+		var urlStr string
+		if resp != nil && resp.Request != nil {
+			urlStr = resp.Request.URL.String()
+		} else {
+			urlStr = req.URL.String()
+		}
+		return &url.Error{
+			Op:  method[:1] + strings.ToLower(method[1:]),
+			URL: urlStr,
+			Err: err,
+		}
+	}
+	for {
+		// For all but the first request, create the next
+		// request hop and replace req.
+		if len(reqs) > 0 {
+			loc := resp.Header.Get("Location")
+			if loc == "" {
+				return nil, uerr(fmt.Errorf("%d response missing Location header", resp.StatusCode))
 			}
-			nreq.Header = make(Header)
-			nreq.URL, err = base.Parse(urlStr)
+			u, err := req.URL.Parse(loc)
 			if err != nil {
-				break
+				return nil, uerr(fmt.Errorf("failed to parse Location header %q: %v", loc, err))
 			}
-			if len(via) > 0 {
-				// Add the Referer header.
-				lastReq := via[len(via)-1]
-				if ref := refererForURL(lastReq.URL, nreq.URL); ref != "" {
-					nreq.Header.Set("Referer", ref)
-				}
-
-				err = redirectChecker(nreq, via)
-				if err != nil {
-					redirectFailed = true
-					break
-				}
+			ireq := reqs[0]
+			req = &Request{
+				Method:   ireq.Method,
+				Response: resp,
+				URL:      u,
+				Header:   make(Header),
+				Cancel:   ireq.Cancel,
+				ctx:      ireq.ctx,
 			}
-			req = nreq
-		}
+			if ireq.Method == "POST" || ireq.Method == "PUT" {
+				req.Method = "GET"
+			}
+			// Add the Referer header from the most recent
+			// request URL to the new one, if it's not https->http:
+			if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL); ref != "" {
+				req.Header.Set("Referer", ref)
+			}
+			err = c.checkRedirect(req, reqs)
 
-		urlStr = req.URL.String()
-		if resp, err = c.send(req, deadline); err != nil {
-			if !deadline.IsZero() && !time.Now().Before(deadline) {
-				err = &httpError{
-					err:     err.Error() + " (Client.Timeout exceeded while awaiting headers)",
-					timeout: true,
-				}
+			// Sentinel error to let users select the
+			// previous response, without closing its
+			// body. See Issue 10069.
+			if err == ErrUseLastResponse {
+				return resp, nil
 			}
-			break
-		}
 
-		if shouldRedirect(resp.StatusCode) {
-			// Read the body if small so underlying TCP connection will be re-used.
-			// No need to check for errors: if it fails, Transport won't reuse it anyway.
+			// Close the previous response's body. But
+			// read at least some of the body so if it's
+			// small the underlying TCP connection will be
+			// re-used. No need to check for errors: if it
+			// fails, the Transport won't reuse it anyway.
 			const maxBodySlurpSize = 2 << 10
 			if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
 				io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize)
 			}
 			resp.Body.Close()
-			if urlStr = resp.Header.Get("Location"); urlStr == "" {
-				err = fmt.Errorf("%d response missing Location header", resp.StatusCode)
-				break
+
+			if err != nil {
+				// Special case for Go 1 compatibility: return both the response
+				// and an error if the CheckRedirect function failed.
+				// See https://golang.org/issue/3795
+				// The resp.Body has already been closed.
+				ue := uerr(err)
+				ue.(*url.Error).URL = loc
+				return resp, ue
 			}
-			base = req.URL
-			via = append(via, req)
-			continue
 		}
-		return resp, nil
-	}
 
-	method := valueOrDefault(ireq.Method, "GET")
-	urlErr := &url.Error{
-		Op:  method[:1] + strings.ToLower(method[1:]),
-		URL: urlStr,
-		Err: err,
-	}
+		reqs = append(reqs, req)
 
-	if redirectFailed {
-		// Special case for Go 1 compatibility: return both the response
-		// and an error if the CheckRedirect function failed.
-		// See https://golang.org/issue/3795
-		return resp, urlErr
-	}
+		var err error
+		if resp, err = c.send(req, deadline); err != nil {
+			if !deadline.IsZero() && !time.Now().Before(deadline) {
+				err = &httpError{
+					err:     err.Error() + " (Client.Timeout exceeded while awaiting headers)",
+					timeout: true,
+				}
+			}
+			return nil, uerr(err)
+		}
 
-	if resp != nil {
-		resp.Body.Close()
+		if !shouldRedirect(resp.StatusCode) {
+			return resp, nil
+		}
 	}
-	return nil, urlErr
 }
 
 func defaultCheckRedirect(req *Request, via []*Request) error {
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index 8939dc8..a9b1948 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -8,6 +8,7 @@ package http_test
 
 import (
 	"bytes"
+	"context"
 	"crypto/tls"
 	"crypto/x509"
 	"encoding/base64"
@@ -273,7 +274,7 @@ func TestClientRedirects(t *testing.T) {
 		t.Fatal("didn't see redirect")
 	}
 	if lastReq.Cancel != cancel {
-		t.Errorf("expected lastReq to have the cancel channel set on the inital req")
+		t.Errorf("expected lastReq to have the cancel channel set on the initial req")
 	}
 
 	checkErr = errors.New("no redirects allowed")
@@ -290,6 +291,33 @@ func TestClientRedirects(t *testing.T) {
 	}
 }
 
+func TestClientRedirectContext(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		Redirect(w, r, "/", StatusFound)
+	}))
+	defer ts.Close()
+
+	ctx, cancel := context.WithCancel(context.Background())
+	c := &Client{CheckRedirect: func(req *Request, via []*Request) error {
+		cancel()
+		if len(via) > 2 {
+			return errors.New("too many redirects")
+		}
+		return nil
+	}}
+	req, _ := NewRequest("GET", ts.URL, nil)
+	req = req.WithContext(ctx)
+	_, err := c.Do(req)
+	ue, ok := err.(*url.Error)
+	if !ok {
+		t.Fatalf("got error %T; want *url.Error", err)
+	}
+	if ue.Err != ExportErrRequestCanceled && ue.Err != ExportErrRequestCanceledConn {
+		t.Errorf("url.Error.Err = %v; want errRequestCanceled or errRequestCanceledConn", ue.Err)
+	}
+}
+
 func TestPostRedirects(t *testing.T) {
 	defer afterTest(t)
 	var log struct {
@@ -338,6 +366,44 @@ func TestPostRedirects(t *testing.T) {
 	}
 }
 
+func TestClientRedirectUseResponse(t *testing.T) {
+	defer afterTest(t)
+	const body = "Hello, world."
+	var ts *httptest.Server
+	ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		if strings.Contains(r.URL.Path, "/other") {
+			io.WriteString(w, "wrong body")
+		} else {
+			w.Header().Set("Location", ts.URL+"/other")
+			w.WriteHeader(StatusFound)
+			io.WriteString(w, body)
+		}
+	}))
+	defer ts.Close()
+
+	c := &Client{CheckRedirect: func(req *Request, via []*Request) error {
+		if req.Response == nil {
+			t.Error("expected non-nil Request.Response")
+		}
+		return ErrUseLastResponse
+	}}
+	res, err := c.Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if res.StatusCode != StatusFound {
+		t.Errorf("status = %d; want %d", res.StatusCode, StatusFound)
+	}
+	defer res.Body.Close()
+	slurp, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(slurp) != body {
+		t.Errorf("body = %q; want %q", slurp, body)
+	}
+}
+
 var expectedCookies = []*Cookie{
 	{Name: "ChocolateChip", Value: "tasty"},
 	{Name: "First", Value: "Hit"},
@@ -1140,3 +1206,26 @@ func TestReferer(t *testing.T) {
 		}
 	}
 }
+
+// issue15577Tripper returns a Response with a redirect response
+// header and doesn't populate its Response.Request field.
+type issue15577Tripper struct{}
+
+func (issue15577Tripper) RoundTrip(*Request) (*Response, error) {
+	resp := &Response{
+		StatusCode: 303,
+		Header:     map[string][]string{"Location": {"http://www.example.com/"}},
+		Body:       ioutil.NopCloser(strings.NewReader("")),
+	}
+	return resp, nil
+}
+
+// Issue 15577: don't assume the roundtripper's response populates its Request field.
+func TestClientRedirectResponseWithoutRequest(t *testing.T) {
+	c := &Client{
+		CheckRedirect: func(*Request, []*Request) error { return fmt.Errorf("no redirects!") },
+		Transport:     issue15577Tripper{},
+	}
+	// Check that this doesn't crash:
+	c.Get("http://dummy.tld")
+}
diff --git a/src/net/http/clientserver_test.go b/src/net/http/clientserver_test.go
index fbaa805..e12ea0c 100644
--- a/src/net/http/clientserver_test.go
+++ b/src/net/http/clientserver_test.go
@@ -17,6 +17,7 @@ import (
 	"net"
 	. "net/http"
 	"net/http/httptest"
+	"net/http/httputil"
 	"net/url"
 	"os"
 	"reflect"
@@ -43,6 +44,13 @@ func (t *clientServerTest) close() {
 	t.ts.Close()
 }
 
+func (t *clientServerTest) scheme() string {
+	if t.h2 {
+		return "https"
+	}
+	return "http"
+}
+
 const (
 	h1Mode = false
 	h2Mode = true
@@ -147,10 +155,11 @@ type reqFunc func(c *Client, url string) (*Response, error)
 // h12Compare is a test that compares HTTP/1 and HTTP/2 behavior
 // against each other.
 type h12Compare struct {
-	Handler       func(ResponseWriter, *Request)    // required
-	ReqFunc       reqFunc                           // optional
-	CheckResponse func(proto string, res *Response) // optional
-	Opts          []interface{}
+	Handler            func(ResponseWriter, *Request)    // required
+	ReqFunc            reqFunc                           // optional
+	CheckResponse      func(proto string, res *Response) // optional
+	EarlyCheckResponse func(proto string, res *Response) // optional; pre-normalize
+	Opts               []interface{}
 }
 
 func (tt h12Compare) reqFunc() reqFunc {
@@ -176,6 +185,12 @@ func (tt h12Compare) run(t *testing.T) {
 		t.Errorf("HTTP/2 request: %v", err)
 		return
 	}
+
+	if fn := tt.EarlyCheckResponse; fn != nil {
+		fn("HTTP/1.1", res1)
+		fn("HTTP/2.0", res2)
+	}
+
 	tt.normalizeRes(t, res1, "HTTP/1.1")
 	tt.normalizeRes(t, res2, "HTTP/2.0")
 	res1body, res2body := res1.Body, res2.Body
@@ -220,6 +235,7 @@ func (tt h12Compare) normalizeRes(t *testing.T, res *Response, wantProto string)
 		t.Errorf("got %q response; want %q", res.Proto, wantProto)
 	}
 	slurp, err := ioutil.ReadAll(res.Body)
+
 	res.Body.Close()
 	res.Body = slurpResult{
 		ReadCloser: ioutil.NopCloser(bytes.NewReader(slurp)),
@@ -356,7 +372,7 @@ func TestH12_HandlerWritesTooLittle(t *testing.T) {
 }
 
 // Tests that the HTTP/1 and HTTP/2 servers prevent handlers from
-// writing more than they declared.  This test does not test whether
+// writing more than they declared. This test does not test whether
 // the transport deals with too much data, though, since the server
 // doesn't make it possible to send bogus data. For those tests, see
 // transport_test.go (for HTTP/1) or x/net/http2/transport_test.go
@@ -1045,6 +1061,170 @@ func testTransportGCRequest(t *testing.T, h2, body bool) {
 	}
 }
 
+func TestTransportRejectsInvalidHeaders_h1(t *testing.T) {
+	testTransportRejectsInvalidHeaders(t, h1Mode)
+}
+func TestTransportRejectsInvalidHeaders_h2(t *testing.T) {
+	testTransportRejectsInvalidHeaders(t, h2Mode)
+}
+func testTransportRejectsInvalidHeaders(t *testing.T, h2 bool) {
+	defer afterTest(t)
+	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+		fmt.Fprintf(w, "Handler saw headers: %q", r.Header)
+	}))
+	defer cst.close()
+	cst.tr.DisableKeepAlives = true
+
+	tests := []struct {
+		key, val string
+		ok       bool
+	}{
+		{"Foo", "capital-key", true}, // verify h2 allows capital keys
+		{"Foo", "foo\x00bar", false}, // \x00 byte in value not allowed
+		{"Foo", "two\nlines", false}, // \n byte in value not allowed
+		{"bogus\nkey", "v", false},   // \n byte also not allowed in key
+		{"A space", "v", false},      // spaces in keys not allowed
+		{"имя", "v", false},          // key must be ascii
+		{"name", "валю", true},       // value may be non-ascii
+		{"", "v", false},             // key must be non-empty
+		{"k", "", true},              // value may be empty
+	}
+	for _, tt := range tests {
+		dialedc := make(chan bool, 1)
+		cst.tr.Dial = func(netw, addr string) (net.Conn, error) {
+			dialedc <- true
+			return net.Dial(netw, addr)
+		}
+		req, _ := NewRequest("GET", cst.ts.URL, nil)
+		req.Header[tt.key] = []string{tt.val}
+		res, err := cst.c.Do(req)
+		var body []byte
+		if err == nil {
+			body, _ = ioutil.ReadAll(res.Body)
+			res.Body.Close()
+		}
+		var dialed bool
+		select {
+		case <-dialedc:
+			dialed = true
+		default:
+		}
+
+		if !tt.ok && dialed {
+			t.Errorf("For key %q, value %q, transport dialed. Expected local failure. Response was: (%v, %v)\nServer replied with: %s", tt.key, tt.val, res, err, body)
+		} else if (err == nil) != tt.ok {
+			t.Errorf("For key %q, value %q; got err = %v; want ok=%v", tt.key, tt.val, err, tt.ok)
+		}
+	}
+}
+
+// Tests that we support bogus under-100 HTTP statuses, because we historically
+// have. This might change at some point, but not yet in Go 1.6.
+func TestBogusStatusWorks_h1(t *testing.T) { testBogusStatusWorks(t, h1Mode) }
+func TestBogusStatusWorks_h2(t *testing.T) { testBogusStatusWorks(t, h2Mode) }
+func testBogusStatusWorks(t *testing.T, h2 bool) {
+	defer afterTest(t)
+	const code = 7
+	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.WriteHeader(code)
+	}))
+	defer cst.close()
+
+	res, err := cst.c.Get(cst.ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if res.StatusCode != code {
+		t.Errorf("StatusCode = %d; want %d", res.StatusCode, code)
+	}
+}
+
+func TestInterruptWithPanic_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode) }
+func TestInterruptWithPanic_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode) }
+func testInterruptWithPanic(t *testing.T, h2 bool) {
+	log.SetOutput(ioutil.Discard) // is noisy otherwise
+	defer log.SetOutput(os.Stderr)
+
+	const msg = "hello"
+	defer afterTest(t)
+	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+		io.WriteString(w, msg)
+		w.(Flusher).Flush()
+		panic("no more")
+	}))
+	defer cst.close()
+	res, err := cst.c.Get(cst.ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+	slurp, err := ioutil.ReadAll(res.Body)
+	if string(slurp) != msg {
+		t.Errorf("client read %q; want %q", slurp, msg)
+	}
+	if err == nil {
+		t.Errorf("client read all successfully; want some error")
+	}
+}
+
+// Issue 15366
+func TestH12_AutoGzipWithDumpResponse(t *testing.T) {
+	h12Compare{
+		Handler: func(w ResponseWriter, r *Request) {
+			h := w.Header()
+			h.Set("Content-Encoding", "gzip")
+			h.Set("Content-Length", "23")
+			h.Set("Connection", "keep-alive")
+			io.WriteString(w, "\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00")
+		},
+		EarlyCheckResponse: func(proto string, res *Response) {
+			if !res.Uncompressed {
+				t.Errorf("%s: expected Uncompressed to be set", proto)
+			}
+			dump, err := httputil.DumpResponse(res, true)
+			if err != nil {
+				t.Errorf("%s: DumpResponse: %v", proto, err)
+				return
+			}
+			if strings.Contains(string(dump), "Connection: close") {
+				t.Errorf("%s: should not see \"Connection: close\" in dump; got:\n%s", proto, dump)
+			}
+			if !strings.Contains(string(dump), "FOO") {
+				t.Errorf("%s: should see \"FOO\" in response; got:\n%s", proto, dump)
+			}
+		},
+	}.run(t)
+}
+
+// Issue 14607
+func TestCloseIdleConnections_h1(t *testing.T) { testCloseIdleConnections(t, h1Mode) }
+func TestCloseIdleConnections_h2(t *testing.T) { testCloseIdleConnections(t, h2Mode) }
+func testCloseIdleConnections(t *testing.T, h2 bool) {
+	defer afterTest(t)
+	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("X-Addr", r.RemoteAddr)
+	}))
+	defer cst.close()
+	get := func() string {
+		res, err := cst.c.Get(cst.ts.URL)
+		if err != nil {
+			t.Fatal(err)
+		}
+		res.Body.Close()
+		v := res.Header.Get("X-Addr")
+		if v == "" {
+			t.Fatal("didn't get X-Addr")
+		}
+		return v
+	}
+	a1 := get()
+	cst.tr.CloseIdleConnections()
+	a2 := get()
+	if a1 == a2 {
+		t.Errorf("didn't close connection")
+	}
+}
+
 type noteCloseConn struct {
 	net.Conn
 	closeFunc func()
diff --git a/src/net/http/cookie.go b/src/net/http/cookie.go
index 648709d..1ea0e93 100644
--- a/src/net/http/cookie.go
+++ b/src/net/http/cookie.go
@@ -223,7 +223,7 @@ func readCookies(h Header, filter string) []*Cookie {
 	return cookies
 }
 
-// validCookieDomain returns wheter v is a valid cookie domain-value.
+// validCookieDomain returns whether v is a valid cookie domain-value.
 func validCookieDomain(v string) bool {
 	if isCookieDomainName(v) {
 		return true
diff --git a/src/net/http/cookie_test.go b/src/net/http/cookie_test.go
index d474f31..95e6147 100644
--- a/src/net/http/cookie_test.go
+++ b/src/net/http/cookie_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/net/http/cookiejar/punycode.go b/src/net/http/cookiejar/punycode.go
index ea7ceb5..a9cc666 100644
--- a/src/net/http/cookiejar/punycode.go
+++ b/src/net/http/cookiejar/punycode.go
@@ -37,7 +37,7 @@ func encode(prefix, s string) (string, error) {
 	delta, n, bias := int32(0), initialN, initialBias
 	b, remaining := int32(0), int32(0)
 	for _, r := range s {
-		if r < 0x80 {
+		if r < utf8.RuneSelf {
 			b++
 			output = append(output, byte(r))
 		} else {
diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go
index 7952e00..9c5ba08 100644
--- a/src/net/http/export_test.go
+++ b/src/net/http/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -9,22 +9,22 @@ package http
 
 import (
 	"net"
+	"sort"
 	"sync"
 	"time"
 )
 
 var (
-	DefaultUserAgent              = defaultUserAgent
-	NewLoggingConn                = newLoggingConn
-	ExportAppendTime              = appendTime
-	ExportRefererForURL           = refererForURL
-	ExportServerNewConn           = (*Server).newConn
-	ExportCloseWriteAndWait       = (*conn).closeWriteAndWait
-	ExportErrRequestCanceled      = errRequestCanceled
-	ExportErrRequestCanceledConn  = errRequestCanceledConn
-	ExportServeFile               = serveFile
-	ExportHttp2ConfigureTransport = http2ConfigureTransport
-	ExportHttp2ConfigureServer    = http2ConfigureServer
+	DefaultUserAgent             = defaultUserAgent
+	NewLoggingConn               = newLoggingConn
+	ExportAppendTime             = appendTime
+	ExportRefererForURL          = refererForURL
+	ExportServerNewConn          = (*Server).newConn
+	ExportCloseWriteAndWait      = (*conn).closeWriteAndWait
+	ExportErrRequestCanceled     = errRequestCanceled
+	ExportErrRequestCanceledConn = errRequestCanceledConn
+	ExportServeFile              = serveFile
+	ExportHttp2ConfigureServer   = http2ConfigureServer
 )
 
 func init() {
@@ -35,9 +35,8 @@ func init() {
 }
 
 var (
-	SetEnterRoundTripHook  = hookSetter(&testHookEnterRoundTrip)
-	SetTestHookWaitResLoop = hookSetter(&testHookWaitResLoop)
-	SetRoundTripRetried    = hookSetter(&testHookRoundTripRetried)
+	SetEnterRoundTripHook = hookSetter(&testHookEnterRoundTrip)
+	SetRoundTripRetried   = hookSetter(&testHookRoundTripRetried)
 )
 
 func SetReadLoopBeforeNextReadHook(f func()) {
@@ -81,21 +80,29 @@ func (t *Transport) IdleConnKeysForTesting() (keys []string) {
 	keys = make([]string, 0)
 	t.idleMu.Lock()
 	defer t.idleMu.Unlock()
-	if t.idleConn == nil {
-		return
-	}
 	for key := range t.idleConn {
 		keys = append(keys, key.String())
 	}
+	sort.Strings(keys)
 	return
 }
 
-func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
+func (t *Transport) IdleConnStrsForTesting() []string {
+	var ret []string
 	t.idleMu.Lock()
 	defer t.idleMu.Unlock()
-	if t.idleConn == nil {
-		return 0
+	for _, conns := range t.idleConn {
+		for _, pc := range conns {
+			ret = append(ret, pc.conn.LocalAddr().String()+"/"+pc.conn.RemoteAddr().String())
+		}
 	}
+	sort.Strings(ret)
+	return ret
+}
+
+func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
+	t.idleMu.Lock()
+	defer t.idleMu.Unlock()
 	for k, conns := range t.idleConn {
 		if k.String() == cacheKey {
 			return len(conns)
@@ -144,3 +151,12 @@ func hookSetter(dst *func()) func(func()) {
 		*dst = fn
 	}
 }
+
+func ExportHttp2ConfigureTransport(t *Transport) error {
+	t2, err := http2configureTransport(t)
+	if err != nil {
+		return err
+	}
+	t.h2transport = t2
+	return nil
+}
diff --git a/src/net/http/fcgi/fcgi.go b/src/net/http/fcgi/fcgi.go
index 06bba04..3374841 100644
--- a/src/net/http/fcgi/fcgi.go
+++ b/src/net/http/fcgi/fcgi.go
@@ -58,8 +58,6 @@ const (
 	statusUnknownRole
 )
 
-const headerLen = 8
-
 type header struct {
 	Version       uint8
 	Type          recType
@@ -158,11 +156,6 @@ func (c *conn) writeRecord(recType recType, reqId uint16, b []byte) error {
 	return err
 }
 
-func (c *conn) writeBeginRequest(reqId uint16, role uint16, flags uint8) error {
-	b := [8]byte{byte(role >> 8), byte(role), flags}
-	return c.writeRecord(typeBeginRequest, reqId, b[:])
-}
-
 func (c *conn) writeEndRequest(reqId uint16, appStatus int, protocolStatus uint8) error {
 	b := make([]byte, 8)
 	binary.BigEndian.PutUint32(b, uint32(appStatus))
diff --git a/src/net/http/filetransport.go b/src/net/http/filetransport.go
index 821787e..32126d7 100644
--- a/src/net/http/filetransport.go
+++ b/src/net/http/filetransport.go
@@ -33,7 +33,7 @@ func NewFileTransport(fs FileSystem) RoundTripper {
 
 func (t fileTransport) RoundTrip(req *Request) (resp *Response, err error) {
 	// We start ServeHTTP in a goroutine, which may take a long
-	// time if the file is large.  The newPopulateResponseWriter
+	// time if the file is large. The newPopulateResponseWriter
 	// call returns a channel which either ServeHTTP or finish()
 	// sends our *Response on, once the *Response itself has been
 	// populated (even if the body itself is still being
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index f61c138..c7a58a6 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -34,7 +34,7 @@ import (
 type Dir string
 
 func (d Dir) Open(name string) (File, error) {
-	if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
+	if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) ||
 		strings.Contains(name, "\x00") {
 		return nil, errors.New("http: invalid character in file path")
 	}
@@ -96,7 +96,7 @@ func dirList(w ResponseWriter, f File) {
 }
 
 // ServeContent replies to the request using the content in the
-// provided ReadSeeker.  The main benefit of ServeContent over io.Copy
+// provided ReadSeeker. The main benefit of ServeContent over io.Copy
 // is that it handles Range requests properly, sets the MIME type, and
 // handles If-Modified-Since requests.
 //
@@ -108,7 +108,7 @@ func dirList(w ResponseWriter, f File) {
 // never sent in the response.
 //
 // If modtime is not the zero time or Unix epoch, ServeContent
-// includes it in a Last-Modified header in the response.  If the
+// 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.
 //
@@ -121,11 +121,11 @@ func dirList(w ResponseWriter, f File) {
 // Note that *os.File implements the io.ReadSeeker interface.
 func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker) {
 	sizeFunc := func() (int64, error) {
-		size, err := content.Seek(0, os.SEEK_END)
+		size, err := content.Seek(0, io.SeekEnd)
 		if err != nil {
 			return 0, errSeeker
 		}
-		_, err = content.Seek(0, os.SEEK_SET)
+		_, err = content.Seek(0, io.SeekStart)
 		if err != nil {
 			return 0, errSeeker
 		}
@@ -166,7 +166,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
 			var buf [sniffLen]byte
 			n, _ := io.ReadFull(content, buf[:])
 			ctype = DetectContentType(buf[:n])
-			_, err := content.Seek(0, os.SEEK_SET) // rewind to output whole file
+			_, err := content.Seek(0, io.SeekStart) // rewind to output whole file
 			if err != nil {
 				Error(w, "seeker can't seek", StatusInternalServerError)
 				return
@@ -196,7 +196,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
 			// The total number of bytes in all the ranges
 			// is larger than the size of the file by
 			// itself, so this is probably an attack, or a
-			// dumb client.  Ignore the range request.
+			// dumb client. Ignore the range request.
 			ranges = nil
 		}
 		switch {
@@ -213,7 +213,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
 			// A response to a request for a single range MUST NOT
 			// be sent using the multipart/byteranges media type."
 			ra := ranges[0]
-			if _, err := content.Seek(ra.start, os.SEEK_SET); err != nil {
+			if _, err := content.Seek(ra.start, io.SeekStart); err != nil {
 				Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
 				return
 			}
@@ -236,7 +236,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
 						pw.CloseWithError(err)
 						return
 					}
-					if _, err := content.Seek(ra.start, os.SEEK_SET); err != nil {
+					if _, err := content.Seek(ra.start, io.SeekStart); err != nil {
 						pw.CloseWithError(err)
 						return
 					}
@@ -291,7 +291,7 @@ func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool {
 // checkETag implements If-None-Match and If-Range checks.
 //
 // The ETag or modtime must have been previously set in the
-// ResponseWriter's headers.  The modtime is only compared at second
+// ResponseWriter's headers. The modtime is only compared at second
 // granularity and may be the zero value to mean unknown.
 //
 // The return value is the effective request "Range" header to use and
@@ -336,7 +336,7 @@ func checkETag(w ResponseWriter, r *Request, modtime time.Time) (rangeReq string
 		}
 
 		// TODO(bradfitz): deal with comma-separated or multiple-valued
-		// list of If-None-match values.  For now just handle the common
+		// list of If-None-match values. For now just handle the common
 		// case of a single item.
 		if inm == etag || inm == "*" {
 			h := w.Header()
@@ -393,6 +393,15 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 		}
 	}
 
+	// redirect if the directory name doesn't end in a slash
+	if d.IsDir() {
+		url := r.URL.Path
+		if url[len(url)-1] != '/' {
+			localRedirect(w, r, path.Base(url)+"/")
+			return
+		}
+	}
+
 	// use contents of index.html for directory, if present
 	if d.IsDir() {
 		index := strings.TrimSuffix(name, "/") + indexPage
@@ -451,7 +460,7 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) {
 // ServeFile replies to the request with the contents of the named
 // file or directory.
 //
-// If the provided file or direcory name is a relative path, it is
+// If the provided file or directory name is a relative path, it is
 // interpreted relative to the current directory and may ascend to parent
 // directories. If the provided name is constructed from user input, it
 // should be sanitized before calling ServeFile. As a precaution, ServeFile
diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go
index 69d7806..c811891 100644
--- a/src/net/http/fs_test.go
+++ b/src/net/http/fs_test.go
@@ -24,7 +24,6 @@ import (
 	"reflect"
 	"regexp"
 	"runtime"
-	"strconv"
 	"strings"
 	"testing"
 	"time"
@@ -39,8 +38,6 @@ type wantRange struct {
 	start, end int64 // range [start,end)
 }
 
-var itoa = strconv.Itoa
-
 var ServeFileRangeTests = []struct {
 	r      string
 	code   int
@@ -508,6 +505,24 @@ func TestServeFileFromCWD(t *testing.T) {
 	}
 }
 
+// Issue 13996
+func TestServeDirWithoutTrailingSlash(t *testing.T) {
+	e := "/testdata/"
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		ServeFile(w, r, ".")
+	}))
+	defer ts.Close()
+	r, err := Get(ts.URL + "/testdata")
+	if err != nil {
+		t.Fatal(err)
+	}
+	r.Body.Close()
+	if g := r.Request.URL.Path; g != e {
+		t.Errorf("got %s, want %s", g, e)
+	}
+}
+
 // Tests that ServeFile doesn't add a Content-Length if a Content-Encoding is
 // specified.
 func TestServeFileWithContentEncoding_h1(t *testing.T) { testServeFileWithContentEncoding(t, h1Mode) }
@@ -963,9 +978,9 @@ func TestLinuxSendfile(t *testing.T) {
 
 	syscalls := "sendfile,sendfile64"
 	switch runtime.GOARCH {
-	case "mips64", "mips64le":
-		// mips64 strace doesn't support sendfile64 and will error out
-		// if we specify that with `-e trace='.
+	case "mips64", "mips64le", "s390x":
+		// strace on the above platforms doesn't support sendfile64
+		// and will error out if we specify that with `-e trace='.
 		syscalls = "sendfile"
 	}
 
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index 4e19b3e..352a41d 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -1,5 +1,5 @@
 // Code generated by golang.org/x/tools/cmd/bundle.
-//go:generate bundle -o h2_bundle.go -prefix http2 -import golang.org/x/net/http2/hpack=internal/golang.org/x/net/http2/hpack golang.org/x/net/http2
+//go:generate bundle -o h2_bundle.go -prefix http2 golang.org/x/net/http2
 
 // Package http2 implements the HTTP/2 protocol.
 //
@@ -20,15 +20,16 @@ import (
 	"bufio"
 	"bytes"
 	"compress/gzip"
+	"context"
 	"crypto/tls"
 	"encoding/binary"
 	"errors"
 	"fmt"
-	"internal/golang.org/x/net/http2/hpack"
 	"io"
 	"io/ioutil"
 	"log"
 	"net"
+	"net/http/httptrace"
 	"net/textproto"
 	"net/url"
 	"os"
@@ -39,6 +40,9 @@ import (
 	"strings"
 	"sync"
 	"time"
+
+	"golang.org/x/net/http2/hpack"
+	"golang.org/x/net/lex/httplex"
 )
 
 // ClientConnPool manages a pool of HTTP/2 client connections.
@@ -47,6 +51,18 @@ type http2ClientConnPool interface {
 	MarkDead(*http2ClientConn)
 }
 
+// clientConnPoolIdleCloser is the interface implemented by ClientConnPool
+// implementations which can close their idle connections.
+type http2clientConnPoolIdleCloser interface {
+	http2ClientConnPool
+	closeIdleConnections()
+}
+
+var (
+	_ http2clientConnPoolIdleCloser = (*http2clientConnPool)(nil)
+	_ http2clientConnPoolIdleCloser = http2noDialClientConnPool{}
+)
+
 // TODO: use singleflight for dialing and addConnCalls?
 type http2clientConnPool struct {
 	t *http2Transport
@@ -247,6 +263,15 @@ func http2filterOutClientConn(in []*http2ClientConn, exclude *http2ClientConn) [
 	return out
 }
 
+// noDialClientConnPool is an implementation of http2.ClientConnPool
+// which never dials.  We let the HTTP/1.1 client dial and use its TLS
+// connection instead.
+type http2noDialClientConnPool struct{ *http2clientConnPool }
+
+func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) {
+	return p.getClientConn(req, addr, http2noDialOnMiss)
+}
+
 func http2configureTransport(t1 *Transport) (*http2Transport, error) {
 	connPool := new(http2clientConnPool)
 	t2 := &http2Transport{
@@ -267,7 +292,7 @@ func http2configureTransport(t1 *Transport) (*http2Transport, error) {
 		t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
 	}
 	upgradeFn := func(authority string, c *tls.Conn) RoundTripper {
-		addr := http2authorityAddr(authority)
+		addr := http2authorityAddr("https", authority)
 		if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
 			go c.Close()
 			return http2erringRoundTripper{err}
@@ -299,15 +324,6 @@ func http2registerHTTPSProtocol(t *Transport, rt RoundTripper) (err error) {
 	return nil
 }
 
-// noDialClientConnPool is an implementation of http2.ClientConnPool
-// which never dials.  We let the HTTP/1.1 client dial and use its TLS
-// connection instead.
-type http2noDialClientConnPool struct{ *http2clientConnPool }
-
-func (p http2noDialClientConnPool) GetClientConn(req *Request, addr string) (*http2ClientConn, error) {
-	return p.getClientConn(req, addr, http2noDialOnMiss)
-}
-
 // noDialH2RoundTripper is a RoundTripper which only tries to complete the request
 // if there's already has a cached connection to the host.
 type http2noDialH2RoundTripper struct{ t *http2Transport }
@@ -403,6 +419,35 @@ func (e http2connError) Error() string {
 	return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
 }
 
+type http2pseudoHeaderError string
+
+func (e http2pseudoHeaderError) Error() string {
+	return fmt.Sprintf("invalid pseudo-header %q", string(e))
+}
+
+type http2duplicatePseudoHeaderError string
+
+func (e http2duplicatePseudoHeaderError) Error() string {
+	return fmt.Sprintf("duplicate pseudo-header %q", string(e))
+}
+
+type http2headerFieldNameError string
+
+func (e http2headerFieldNameError) Error() string {
+	return fmt.Sprintf("invalid header field name %q", string(e))
+}
+
+type http2headerFieldValueError string
+
+func (e http2headerFieldValueError) Error() string {
+	return fmt.Sprintf("invalid header field value %q", string(e))
+}
+
+var (
+	http2errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
+	http2errPseudoAfterRegular   = errors.New("pseudo header field after regular")
+)
+
 // fixedBuffer is an io.ReadWriter backed by a fixed size buffer.
 // It never allocates, but moves old data as new data is written.
 type http2fixedBuffer struct {
@@ -743,7 +788,7 @@ type http2Frame interface {
 type http2Framer struct {
 	r         io.Reader
 	lastFrame http2Frame
-	errReason string
+	errDetail error
 
 	// lastHeaderStream is non-zero if the last frame was an
 	// unfinished HEADERS/CONTINUATION.
@@ -775,14 +820,33 @@ type http2Framer struct {
 	// to return non-compliant frames or frame orders.
 	// This is for testing and permits using the Framer to test
 	// other HTTP/2 implementations' conformance to the spec.
+	// It is not compatible with ReadMetaHeaders.
 	AllowIllegalReads bool
 
+	// ReadMetaHeaders if non-nil causes ReadFrame to merge
+	// HEADERS and CONTINUATION frames together and return
+	// MetaHeadersFrame instead.
+	ReadMetaHeaders *hpack.Decoder
+
+	// MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE.
+	// It's used only if ReadMetaHeaders is set; 0 means a sane default
+	// (currently 16MB)
+	// If the limit is hit, MetaHeadersFrame.Truncated is set true.
+	MaxHeaderListSize uint32
+
 	logReads bool
 
 	debugFramer    *http2Framer // only use for logging written writes
 	debugFramerBuf *bytes.Buffer
 }
 
+func (fr *http2Framer) maxHeaderListSize() uint32 {
+	if fr.MaxHeaderListSize == 0 {
+		return 16 << 20
+	}
+	return fr.MaxHeaderListSize
+}
+
 func (f *http2Framer) startWrite(ftype http2FrameType, flags http2Flags, streamID uint32) {
 
 	f.wbuf = append(f.wbuf[:0],
@@ -879,6 +943,17 @@ func (fr *http2Framer) SetMaxReadFrameSize(v uint32) {
 	fr.maxReadSize = v
 }
 
+// ErrorDetail returns a more detailed error of the last error
+// returned by Framer.ReadFrame. For instance, if ReadFrame
+// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
+// will say exactly what was invalid. ErrorDetail is not guaranteed
+// to return a non-nil value and like the rest of the http2 package,
+// its return value is not protected by an API compatibility promise.
+// ErrorDetail is reset after the next call to ReadFrame.
+func (fr *http2Framer) ErrorDetail() error {
+	return fr.errDetail
+}
+
 // ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
 // sends a frame that is larger than declared with SetMaxReadFrameSize.
 var http2ErrFrameTooLarge = errors.New("http2: frame too large")
@@ -897,9 +972,10 @@ func http2terminalReadFrameError(err error) bool {
 //
 // If the frame is larger than previously set with SetMaxReadFrameSize, the
 // returned error is ErrFrameTooLarge. Other errors may be of type
-// ConnectionError, StreamError, or anything else from from the underlying
+// ConnectionError, StreamError, or anything else from the underlying
 // reader.
 func (fr *http2Framer) ReadFrame() (http2Frame, error) {
+	fr.errDetail = nil
 	if fr.lastFrame != nil {
 		fr.lastFrame.invalidate()
 	}
@@ -927,6 +1003,9 @@ func (fr *http2Framer) ReadFrame() (http2Frame, error) {
 	if fr.logReads {
 		log.Printf("http2: Framer %p: read %v", fr, http2summarizeFrame(f))
 	}
+	if fh.Type == http2FrameHeaders && fr.ReadMetaHeaders != nil {
+		return fr.readMetaFrame(f.(*http2HeadersFrame))
+	}
 	return f, nil
 }
 
@@ -935,7 +1014,7 @@ func (fr *http2Framer) ReadFrame() (http2Frame, error) {
 // to the peer before hanging up on them. This might help others debug
 // their implementations.
 func (fr *http2Framer) connError(code http2ErrCode, reason string) error {
-	fr.errReason = reason
+	fr.errDetail = errors.New(reason)
 	return http2ConnectionError(code)
 }
 
@@ -1023,7 +1102,14 @@ func http2parseDataFrame(fh http2FrameHeader, payload []byte) (http2Frame, error
 	return f, nil
 }
 
-var http2errStreamID = errors.New("invalid streamid")
+var (
+	http2errStreamID    = errors.New("invalid stream ID")
+	http2errDepStreamID = errors.New("invalid dependent stream ID")
+)
+
+func http2validStreamIDOrZero(streamID uint32) bool {
+	return streamID&(1<<31) == 0
+}
 
 func http2validStreamID(streamID uint32) bool {
 	return streamID != 0 && streamID&(1<<31) == 0
@@ -1389,8 +1475,8 @@ func (f *http2Framer) WriteHeaders(p http2HeadersFrameParam) error {
 	}
 	if !p.Priority.IsZero() {
 		v := p.Priority.StreamDep
-		if !http2validStreamID(v) && !f.AllowIllegalWrites {
-			return errors.New("invalid dependent stream id")
+		if !http2validStreamIDOrZero(v) && !f.AllowIllegalWrites {
+			return http2errDepStreamID
 		}
 		if p.Priority.Exclusive {
 			v |= 1 << 31
@@ -1458,6 +1544,9 @@ func (f *http2Framer) WritePriority(streamID uint32, p http2PriorityParam) error
 	if !http2validStreamID(streamID) && !f.AllowIllegalWrites {
 		return http2errStreamID
 	}
+	if !http2validStreamIDOrZero(p.StreamDep) {
+		return http2errDepStreamID
+	}
 	f.startWrite(http2FramePriority, 0, streamID)
 	v := p.StreamDep
 	if p.Exclusive {
@@ -1669,6 +1758,193 @@ type http2headersEnder interface {
 	HeadersEnded() bool
 }
 
+type http2headersOrContinuation interface {
+	http2headersEnder
+	HeaderBlockFragment() []byte
+}
+
+// A MetaHeadersFrame is the representation of one HEADERS frame and
+// zero or more contiguous CONTINUATION frames and the decoding of
+// their HPACK-encoded contents.
+//
+// This type of frame does not appear on the wire and is only returned
+// by the Framer when Framer.ReadMetaHeaders is set.
+type http2MetaHeadersFrame struct {
+	*http2HeadersFrame
+
+	// Fields are the fields contained in the HEADERS and
+	// CONTINUATION frames. The underlying slice is owned by the
+	// Framer and must not be retained after the next call to
+	// ReadFrame.
+	//
+	// Fields are guaranteed to be in the correct http2 order and
+	// not have unknown pseudo header fields or invalid header
+	// field names or values. Required pseudo header fields may be
+	// missing, however. Use the MetaHeadersFrame.Pseudo accessor
+	// method access pseudo headers.
+	Fields []hpack.HeaderField
+
+	// Truncated is whether the max header list size limit was hit
+	// and Fields is incomplete. The hpack decoder state is still
+	// valid, however.
+	Truncated bool
+}
+
+// PseudoValue returns the given pseudo header field's value.
+// The provided pseudo field should not contain the leading colon.
+func (mh *http2MetaHeadersFrame) PseudoValue(pseudo string) string {
+	for _, hf := range mh.Fields {
+		if !hf.IsPseudo() {
+			return ""
+		}
+		if hf.Name[1:] == pseudo {
+			return hf.Value
+		}
+	}
+	return ""
+}
+
+// RegularFields returns the regular (non-pseudo) header fields of mh.
+// The caller does not own the returned slice.
+func (mh *http2MetaHeadersFrame) RegularFields() []hpack.HeaderField {
+	for i, hf := range mh.Fields {
+		if !hf.IsPseudo() {
+			return mh.Fields[i:]
+		}
+	}
+	return nil
+}
+
+// PseudoFields returns the pseudo header fields of mh.
+// The caller does not own the returned slice.
+func (mh *http2MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
+	for i, hf := range mh.Fields {
+		if !hf.IsPseudo() {
+			return mh.Fields[:i]
+		}
+	}
+	return mh.Fields
+}
+
+func (mh *http2MetaHeadersFrame) checkPseudos() error {
+	var isRequest, isResponse bool
+	pf := mh.PseudoFields()
+	for i, hf := range pf {
+		switch hf.Name {
+		case ":method", ":path", ":scheme", ":authority":
+			isRequest = true
+		case ":status":
+			isResponse = true
+		default:
+			return http2pseudoHeaderError(hf.Name)
+		}
+
+		for _, hf2 := range pf[:i] {
+			if hf.Name == hf2.Name {
+				return http2duplicatePseudoHeaderError(hf.Name)
+			}
+		}
+	}
+	if isRequest && isResponse {
+		return http2errMixPseudoHeaderTypes
+	}
+	return nil
+}
+
+func (fr *http2Framer) maxHeaderStringLen() int {
+	v := fr.maxHeaderListSize()
+	if uint32(int(v)) == v {
+		return int(v)
+	}
+
+	return 0
+}
+
+// readMetaFrame returns 0 or more CONTINUATION frames from fr and
+// merge them into into the provided hf and returns a MetaHeadersFrame
+// with the decoded hpack values.
+func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFrame, error) {
+	if fr.AllowIllegalReads {
+		return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
+	}
+	mh := &http2MetaHeadersFrame{
+		http2HeadersFrame: hf,
+	}
+	var remainSize = fr.maxHeaderListSize()
+	var sawRegular bool
+
+	var invalid error // pseudo header field errors
+	hdec := fr.ReadMetaHeaders
+	hdec.SetEmitEnabled(true)
+	hdec.SetMaxStringLength(fr.maxHeaderStringLen())
+	hdec.SetEmitFunc(func(hf hpack.HeaderField) {
+		if !httplex.ValidHeaderFieldValue(hf.Value) {
+			invalid = http2headerFieldValueError(hf.Value)
+		}
+		isPseudo := strings.HasPrefix(hf.Name, ":")
+		if isPseudo {
+			if sawRegular {
+				invalid = http2errPseudoAfterRegular
+			}
+		} else {
+			sawRegular = true
+			if !http2validWireHeaderFieldName(hf.Name) {
+				invalid = http2headerFieldNameError(hf.Name)
+			}
+		}
+
+		if invalid != nil {
+			hdec.SetEmitEnabled(false)
+			return
+		}
+
+		size := hf.Size()
+		if size > remainSize {
+			hdec.SetEmitEnabled(false)
+			mh.Truncated = true
+			return
+		}
+		remainSize -= size
+
+		mh.Fields = append(mh.Fields, hf)
+	})
+
+	defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
+
+	var hc http2headersOrContinuation = hf
+	for {
+		frag := hc.HeaderBlockFragment()
+		if _, err := hdec.Write(frag); err != nil {
+			return nil, http2ConnectionError(http2ErrCodeCompression)
+		}
+
+		if hc.HeadersEnded() {
+			break
+		}
+		if f, err := fr.ReadFrame(); err != nil {
+			return nil, err
+		} else {
+			hc = f.(*http2ContinuationFrame)
+		}
+	}
+
+	mh.http2HeadersFrame.headerFragBuf = nil
+	mh.http2HeadersFrame.invalidate()
+
+	if err := hdec.Close(); err != nil {
+		return nil, http2ConnectionError(http2ErrCodeCompression)
+	}
+	if invalid != nil {
+		fr.errDetail = invalid
+		return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol}
+	}
+	if err := mh.checkPseudos(); err != nil {
+		fr.errDetail = err
+		return nil, http2StreamError{mh.StreamID, http2ErrCodeProtocol}
+	}
+	return mh, nil
+}
+
 func http2summarizeFrame(f http2Frame) string {
 	var buf bytes.Buffer
 	f.Header().writeDebug(&buf)
@@ -1712,7 +1988,111 @@ func http2summarizeFrame(f http2Frame) string {
 	return buf.String()
 }
 
-func http2requestCancel(req *Request) <-chan struct{} { return req.Cancel }
+func http2transportExpectContinueTimeout(t1 *Transport) time.Duration {
+	return t1.ExpectContinueTimeout
+}
+
+// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
+func http2isBadCipher(cipher uint16) bool {
+	switch cipher {
+	case tls.TLS_RSA_WITH_RC4_128_SHA,
+		tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+		tls.TLS_RSA_WITH_AES_128_CBC_SHA,
+		tls.TLS_RSA_WITH_AES_256_CBC_SHA,
+		tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
+		tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
+		tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+		tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+		tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+		tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+		tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+		tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+
+		return true
+	default:
+		return false
+	}
+}
+
+type http2contextContext interface {
+	context.Context
+}
+
+func http2serverConnBaseContext(c net.Conn, opts *http2ServeConnOpts) (ctx http2contextContext, cancel func()) {
+	ctx, cancel = context.WithCancel(context.Background())
+	ctx = context.WithValue(ctx, LocalAddrContextKey, c.LocalAddr())
+	if hs := opts.baseConfig(); hs != nil {
+		ctx = context.WithValue(ctx, ServerContextKey, hs)
+	}
+	return
+}
+
+func http2contextWithCancel(ctx http2contextContext) (_ http2contextContext, cancel func()) {
+	return context.WithCancel(ctx)
+}
+
+func http2requestWithContext(req *Request, ctx http2contextContext) *Request {
+	return req.WithContext(ctx)
+}
+
+type http2clientTrace httptrace.ClientTrace
+
+func http2reqContext(r *Request) context.Context { return r.Context() }
+
+func http2setResponseUncompressed(res *Response) { res.Uncompressed = true }
+
+func http2traceGotConn(req *Request, cc *http2ClientConn) {
+	trace := httptrace.ContextClientTrace(req.Context())
+	if trace == nil || trace.GotConn == nil {
+		return
+	}
+	ci := httptrace.GotConnInfo{Conn: cc.tconn}
+	cc.mu.Lock()
+	ci.Reused = cc.nextStreamID > 1
+	ci.WasIdle = len(cc.streams) == 0 && ci.Reused
+	if ci.WasIdle && !cc.lastActive.IsZero() {
+		ci.IdleTime = time.Now().Sub(cc.lastActive)
+	}
+	cc.mu.Unlock()
+
+	trace.GotConn(ci)
+}
+
+func http2traceWroteHeaders(trace *http2clientTrace) {
+	if trace != nil && trace.WroteHeaders != nil {
+		trace.WroteHeaders()
+	}
+}
+
+func http2traceGot100Continue(trace *http2clientTrace) {
+	if trace != nil && trace.Got100Continue != nil {
+		trace.Got100Continue()
+	}
+}
+
+func http2traceWait100Continue(trace *http2clientTrace) {
+	if trace != nil && trace.Wait100Continue != nil {
+		trace.Wait100Continue()
+	}
+}
+
+func http2traceWroteRequest(trace *http2clientTrace, err error) {
+	if trace != nil && trace.WroteRequest != nil {
+		trace.WroteRequest(httptrace.WroteRequestInfo{Err: err})
+	}
+}
+
+func http2traceFirstResponseByte(trace *http2clientTrace) {
+	if trace != nil && trace.GotFirstResponseByte != nil {
+		trace.GotFirstResponseByte()
+	}
+}
+
+func http2requestTrace(req *Request) *http2clientTrace {
+	trace := httptrace.ContextClientTrace(req.Context())
+	return (*http2clientTrace)(trace)
+}
 
 var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
 
@@ -2070,57 +2450,23 @@ var (
 	http2errInvalidHeaderFieldValue = errors.New("http2: invalid header field value")
 )
 
-// validHeaderFieldName reports whether v is a valid header field name (key).
-//  RFC 7230 says:
-//   header-field   = field-name ":" OWS field-value OWS
-//   field-name     = token
-//   tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
-//           "^" / "_" / "
+// validWireHeaderFieldName reports whether v is a valid header field
+// name (key). See httplex.ValidHeaderName for the base rules.
+//
 // Further, http2 says:
 //   "Just as in HTTP/1.x, header field names are strings of ASCII
 //   characters that are compared in a case-insensitive
 //   fashion. However, header field names MUST be converted to
 //   lowercase prior to their encoding in HTTP/2. "
-func http2validHeaderFieldName(v string) bool {
+func http2validWireHeaderFieldName(v string) bool {
 	if len(v) == 0 {
 		return false
 	}
 	for _, r := range v {
-		if int(r) >= len(http2isTokenTable) || ('A' <= r && r <= 'Z') {
+		if !httplex.IsTokenRune(r) {
 			return false
 		}
-		if !http2isTokenTable[byte(r)] {
-			return false
-		}
-	}
-	return true
-}
-
-// validHeaderFieldValue reports whether v is a valid header field value.
-//
-// RFC 7230 says:
-//  field-value    = *( field-content / obs-fold )
-//  obj-fold       =  N/A to http2, and deprecated
-//  field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
-//  field-vchar    = VCHAR / obs-text
-//  obs-text       = %x80-FF
-//  VCHAR          = "any visible [USASCII] character"
-//
-// http2 further says: "Similarly, HTTP/2 allows header field values
-// that are not valid. While most of the values that can be encoded
-// will not alter header field parsing, carriage return (CR, ASCII
-// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
-// 0x0) might be exploited by an attacker if they are translated
-// verbatim. Any request or response that contains a character not
-// permitted in a header field value MUST be treated as malformed
-// (Section 8.1.2.6). Valid characters are defined by the
-// field-content ABNF rule in Section 3.2 of [RFC7230]."
-//
-// This function does not (yet?) properly handle the rejection of
-// strings that begin or end with SP or HTAB.
-func http2validHeaderFieldValue(v string) bool {
-	for i := 0; i < len(v); i++ {
-		if b := v[i]; b < ' ' && b != '\t' || b == 0x7f {
+		if 'A' <= r && r <= 'Z' {
 			return false
 		}
 	}
@@ -2225,7 +2571,7 @@ func http2mustUint31(v int32) uint32 {
 }
 
 // bodyAllowedForStatus reports whether a given response status code
-// permits a body. See RFC2616, section 4.4.
+// permits a body. See RFC 2616, section 4.4.
 func http2bodyAllowedForStatus(status int) bool {
 	switch {
 	case status >= 100 && status <= 199:
@@ -2251,90 +2597,44 @@ func (e *http2httpError) Temporary() bool { return true }
 
 var http2errTimeout error = &http2httpError{msg: "http2: timeout awaiting response headers", timeout: true}
 
-var http2isTokenTable = [127]bool{
-	'!':  true,
-	'#':  true,
-	'$':  true,
-	'%':  true,
-	'&':  true,
-	'\'': true,
-	'*':  true,
-	'+':  true,
-	'-':  true,
-	'.':  true,
-	'0':  true,
-	'1':  true,
-	'2':  true,
-	'3':  true,
-	'4':  true,
-	'5':  true,
-	'6':  true,
-	'7':  true,
-	'8':  true,
-	'9':  true,
-	'A':  true,
-	'B':  true,
-	'C':  true,
-	'D':  true,
-	'E':  true,
-	'F':  true,
-	'G':  true,
-	'H':  true,
-	'I':  true,
-	'J':  true,
-	'K':  true,
-	'L':  true,
-	'M':  true,
-	'N':  true,
-	'O':  true,
-	'P':  true,
-	'Q':  true,
-	'R':  true,
-	'S':  true,
-	'T':  true,
-	'U':  true,
-	'W':  true,
-	'V':  true,
-	'X':  true,
-	'Y':  true,
-	'Z':  true,
-	'^':  true,
-	'_':  true,
-	'`':  true,
-	'a':  true,
-	'b':  true,
-	'c':  true,
-	'd':  true,
-	'e':  true,
-	'f':  true,
-	'g':  true,
-	'h':  true,
-	'i':  true,
-	'j':  true,
-	'k':  true,
-	'l':  true,
-	'm':  true,
-	'n':  true,
-	'o':  true,
-	'p':  true,
-	'q':  true,
-	'r':  true,
-	's':  true,
-	't':  true,
-	'u':  true,
-	'v':  true,
-	'w':  true,
-	'x':  true,
-	'y':  true,
-	'z':  true,
-	'|':  true,
-	'~':  true,
-}
-
 type http2connectionStater interface {
 	ConnectionState() tls.ConnectionState
 }
 
+var http2sorterPool = sync.Pool{New: func() interface{} { return new(http2sorter) }}
+
+type http2sorter struct {
+	v []string // owned by sorter
+}
+
+func (s *http2sorter) Len() int { return len(s.v) }
+
+func (s *http2sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] }
+
+func (s *http2sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
+
+// Keys returns the sorted keys of h.
+//
+// The returned slice is only valid until s used again or returned to
+// its pool.
+func (s *http2sorter) Keys(h Header) []string {
+	keys := s.v[:0]
+	for k := range h {
+		keys = append(keys, k)
+	}
+	s.v = keys
+	sort.Sort(s)
+	return keys
+}
+
+func (s *http2sorter) SortStrings(ss []string) {
+
+	save := s.v
+	s.v = ss
+	sort.Sort(s)
+	s.v = save
+}
+
 // pipe is a goroutine-safe io.Reader/io.Writer pair.  It's like
 // io.Pipe except there are no PipeReader/PipeWriter halves, and the
 // underlying buffer is an interface. (io.Pipe is always unbuffered)
@@ -2354,6 +2654,12 @@ type http2pipeBuffer interface {
 	io.Reader
 }
 
+func (p *http2pipe) Len() int {
+	p.mu.Lock()
+	defer p.mu.Unlock()
+	return p.b.Len()
+}
+
 // Read waits until data is available and copies bytes
 // from the buffer into p.
 func (p *http2pipe) Read(d []byte) (n int, err error) {
@@ -2653,10 +2959,14 @@ func (o *http2ServeConnOpts) handler() Handler {
 //
 // The opts parameter is optional. If nil, default values are used.
 func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
+	baseCtx, cancel := http2serverConnBaseContext(c, opts)
+	defer cancel()
+
 	sc := &http2serverConn{
 		srv:              s,
 		hs:               opts.baseConfig(),
 		conn:             c,
+		baseCtx:          baseCtx,
 		remoteAddrStr:    c.RemoteAddr().String(),
 		bw:               http2newBufferedWriter(c),
 		handler:          opts.handler(),
@@ -2675,13 +2985,14 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
 		serveG:            http2newGoroutineLock(),
 		pushEnabled:       true,
 	}
+
 	sc.flow.add(http2initialWindowSize)
 	sc.inflow.add(http2initialWindowSize)
 	sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
-	sc.hpackDecoder = hpack.NewDecoder(http2initialHeaderTableSize, nil)
-	sc.hpackDecoder.SetMaxStringLength(sc.maxHeaderStringLen())
 
 	fr := http2NewFramer(sc.bw, c)
+	fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
+	fr.MaxHeaderListSize = sc.maxHeaderListSize()
 	fr.SetMaxReadFrameSize(s.maxReadFrameSize())
 	sc.framer = fr
 
@@ -2711,27 +3022,6 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
 	sc.serve()
 }
 
-// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
-func http2isBadCipher(cipher uint16) bool {
-	switch cipher {
-	case tls.TLS_RSA_WITH_RC4_128_SHA,
-		tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
-		tls.TLS_RSA_WITH_AES_128_CBC_SHA,
-		tls.TLS_RSA_WITH_AES_256_CBC_SHA,
-		tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
-		tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
-		tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
-		tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
-		tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
-		tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
-		tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
-
-		return true
-	default:
-		return false
-	}
-}
-
 func (sc *http2serverConn) rejectConn(err http2ErrCode, debug string) {
 	sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
 
@@ -2747,8 +3037,8 @@ type http2serverConn struct {
 	conn             net.Conn
 	bw               *http2bufferedWriter // writing to conn
 	handler          Handler
+	baseCtx          http2contextContext
 	framer           *http2Framer
-	hpackDecoder     *hpack.Decoder
 	doneServing      chan struct{}              // closed when serverConn.serve ends
 	readFrameCh      chan http2readFrameResult  // written by serverConn.readFrames
 	wantWriteFrameCh chan http2frameWriteMsg    // from handlers -> serve
@@ -2775,7 +3065,6 @@ type http2serverConn struct {
 	headerTableSize       uint32
 	peerMaxHeaderListSize uint32            // zero means unknown (default)
 	canonHeader           map[string]string // http2-lower-case -> Go-Canonical-Case
-	req                   http2requestParam // non-zero while reading request headers
 	writingFrame          bool              // started write goroutine but haven't heard back on wroteFrameCh
 	needsFrameFlush       bool              // last frame write wasn't a flush
 	writeSched            http2writeScheduler
@@ -2784,21 +3073,13 @@ type http2serverConn struct {
 	goAwayCode            http2ErrCode
 	shutdownTimerCh       <-chan time.Time // nil until used
 	shutdownTimer         *time.Timer      // nil until used
+	freeRequestBodyBuf    []byte           // if non-nil, a free initialWindowSize buffer for getRequestBodyBuf
 
 	// Owned by the writeFrameAsync goroutine:
 	headerWriteBuf bytes.Buffer
 	hpackEncoder   *hpack.Encoder
 }
 
-func (sc *http2serverConn) maxHeaderStringLen() int {
-	v := sc.maxHeaderListSize()
-	if uint32(int(v)) == v {
-		return int(v)
-	}
-
-	return 0
-}
-
 func (sc *http2serverConn) maxHeaderListSize() uint32 {
 	n := sc.hs.MaxHeaderBytes
 	if n <= 0 {
@@ -2811,21 +3092,6 @@ func (sc *http2serverConn) maxHeaderListSize() uint32 {
 	return uint32(n + typicalHeaders*perFieldOverhead)
 }
 
-// requestParam is the state of the next request, initialized over
-// potentially several frames HEADERS + zero or more CONTINUATION
-// frames.
-type http2requestParam struct {
-	// stream is non-nil if we're reading (HEADER or CONTINUATION)
-	// frames for a request (but not DATA).
-	stream            *http2stream
-	header            Header
-	method, path      string
-	scheme, authority string
-	sawRegularHeader  bool  // saw a non-pseudo header already
-	invalidHeader     bool  // an invalid header was seen
-	headerListSize    int64 // actually uint32, but easier math this way
-}
-
 // stream represents a stream. This is the minimal metadata needed by
 // the serve goroutine. Most of the actual stream state is owned by
 // the http.Handler's goroutine in the responseWriter. Because the
@@ -2835,10 +3101,12 @@ type http2requestParam struct {
 // responseWriter's state field.
 type http2stream struct {
 	// immutable:
-	sc   *http2serverConn
-	id   uint32
-	body *http2pipe       // non-nil if expecting DATA frames
-	cw   http2closeWaiter // closed wait stream transitions to closed state
+	sc        *http2serverConn
+	id        uint32
+	body      *http2pipe       // non-nil if expecting DATA frames
+	cw        http2closeWaiter // closed wait stream transitions to closed state
+	ctx       http2contextContext
+	cancelCtx func()
 
 	// owned by serverConn's serve loop:
 	bodyBytes        int64        // body bytes seen so far
@@ -2852,6 +3120,8 @@ type http2stream struct {
 	sentReset        bool // only true once detached from streams map
 	gotReset         bool // only true once detacted from streams map
 	gotTrailerHeader bool // HEADER frame for trailers was seen
+	wroteHeaders     bool // whether we wrote headers (not status 100)
+	reqBuf           []byte
 
 	trailer    Header // accumulated trailers
 	reqTrailer Header // handler's Request.Trailer
@@ -2952,88 +3222,11 @@ func (sc *http2serverConn) condlogf(err error, format string, args ...interface{
 	}
 }
 
-func (sc *http2serverConn) onNewHeaderField(f hpack.HeaderField) {
+func (sc *http2serverConn) canonicalHeader(v string) string {
 	sc.serveG.check()
-	if http2VerboseLogs {
-		sc.vlogf("http2: server decoded %v", f)
-	}
-	switch {
-	case !http2validHeaderFieldValue(f.Value):
-		sc.req.invalidHeader = true
-	case strings.HasPrefix(f.Name, ":"):
-		if sc.req.sawRegularHeader {
-			sc.logf("pseudo-header after regular header")
-			sc.req.invalidHeader = true
-			return
-		}
-		var dst *string
-		switch f.Name {
-		case ":method":
-			dst = &sc.req.method
-		case ":path":
-			dst = &sc.req.path
-		case ":scheme":
-			dst = &sc.req.scheme
-		case ":authority":
-			dst = &sc.req.authority
-		default:
-
-			sc.logf("invalid pseudo-header %q", f.Name)
-			sc.req.invalidHeader = true
-			return
-		}
-		if *dst != "" {
-			sc.logf("duplicate pseudo-header %q sent", f.Name)
-			sc.req.invalidHeader = true
-			return
-		}
-		*dst = f.Value
-	case !http2validHeaderFieldName(f.Name):
-		sc.req.invalidHeader = true
-	default:
-		sc.req.sawRegularHeader = true
-		sc.req.header.Add(sc.canonicalHeader(f.Name), f.Value)
-		const headerFieldOverhead = 32 // per spec
-		sc.req.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead
-		if sc.req.headerListSize > int64(sc.maxHeaderListSize()) {
-			sc.hpackDecoder.SetEmitEnabled(false)
-		}
-	}
-}
-
-func (st *http2stream) onNewTrailerField(f hpack.HeaderField) {
-	sc := st.sc
-	sc.serveG.check()
-	if http2VerboseLogs {
-		sc.vlogf("http2: server decoded trailer %v", f)
-	}
-	switch {
-	case strings.HasPrefix(f.Name, ":"):
-		sc.req.invalidHeader = true
-		return
-	case !http2validHeaderFieldName(f.Name) || !http2validHeaderFieldValue(f.Value):
-		sc.req.invalidHeader = true
-		return
-	default:
-		key := sc.canonicalHeader(f.Name)
-		if st.trailer != nil {
-			vv := append(st.trailer[key], f.Value)
-			st.trailer[key] = vv
-
-			// arbitrary; TODO: read spec about header list size limits wrt trailers
-			const tooBig = 1000
-			if len(vv) >= tooBig {
-				sc.hpackDecoder.SetEmitEnabled(false)
-			}
-		}
-	}
-}
-
-func (sc *http2serverConn) canonicalHeader(v string) string {
-	sc.serveG.check()
-	cv, ok := http2commonCanonHeader[v]
-	if ok {
-		return cv
+	cv, ok := http2commonCanonHeader[v]
+	if ok {
+		return cv
 	}
 	cv, ok = sc.canonHeader[v]
 	if ok {
@@ -3063,10 +3256,11 @@ type http2readFrameResult struct {
 // It's run on its own goroutine.
 func (sc *http2serverConn) readFrames() {
 	gate := make(http2gate)
+	gateDone := gate.Done
 	for {
 		f, err := sc.framer.ReadFrame()
 		select {
-		case sc.readFrameCh <- http2readFrameResult{f, err, gate.Done}:
+		case sc.readFrameCh <- http2readFrameResult{f, err, gateDone}:
 		case <-sc.doneServing:
 			return
 		}
@@ -3290,7 +3484,21 @@ func (sc *http2serverConn) writeFrameFromHandler(wm http2frameWriteMsg) error {
 // If you're not on the serve goroutine, use writeFrameFromHandler instead.
 func (sc *http2serverConn) writeFrame(wm http2frameWriteMsg) {
 	sc.serveG.check()
-	sc.writeSched.add(wm)
+
+	var ignoreWrite bool
+
+	switch wm.write.(type) {
+	case *http2writeResHeaders:
+		wm.stream.wroteHeaders = true
+	case http2write100ContinueHeadersFrame:
+		if wm.stream.wroteHeaders {
+			ignoreWrite = true
+		}
+	}
+
+	if !ignoreWrite {
+		sc.writeSched.add(wm)
+	}
 	sc.scheduleFrameWrite()
 }
 
@@ -3511,10 +3719,8 @@ func (sc *http2serverConn) processFrame(f http2Frame) error {
 	switch f := f.(type) {
 	case *http2SettingsFrame:
 		return sc.processSettings(f)
-	case *http2HeadersFrame:
+	case *http2MetaHeadersFrame:
 		return sc.processHeaders(f)
-	case *http2ContinuationFrame:
-		return sc.processContinuation(f)
 	case *http2WindowUpdateFrame:
 		return sc.processWindowUpdate(f)
 	case *http2PingFrame:
@@ -3579,6 +3785,7 @@ func (sc *http2serverConn) processResetStream(f *http2RSTStreamFrame) error {
 	}
 	if st != nil {
 		st.gotReset = true
+		st.cancelCtx()
 		sc.closeStream(st, http2StreamError{f.StreamID, f.ErrCode})
 	}
 	return nil
@@ -3600,6 +3807,10 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
 	}
 	st.cw.Close()
 	sc.writeSched.forgetStream(st.id)
+	if st.reqBuf != nil {
+
+		sc.freeRequestBodyBuf = st.reqBuf
+	}
 }
 
 func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
@@ -3732,7 +3943,7 @@ func (st *http2stream) copyTrailersToHandlerRequest() {
 	}
 }
 
-func (sc *http2serverConn) processHeaders(f *http2HeadersFrame) error {
+func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
 	sc.serveG.check()
 	id := f.Header().StreamID
 	if sc.inGoAway {
@@ -3749,17 +3960,18 @@ func (sc *http2serverConn) processHeaders(f *http2HeadersFrame) error {
 		return st.processTrailerHeaders(f)
 	}
 
-	if id <= sc.maxStreamID || sc.req.stream != nil {
+	if id <= sc.maxStreamID {
 		return http2ConnectionError(http2ErrCodeProtocol)
 	}
+	sc.maxStreamID = id
 
-	if id > sc.maxStreamID {
-		sc.maxStreamID = id
-	}
+	ctx, cancelCtx := http2contextWithCancel(sc.baseCtx)
 	st = &http2stream{
-		sc:    sc,
-		id:    id,
-		state: http2stateOpen,
+		sc:        sc,
+		id:        id,
+		state:     http2stateOpen,
+		ctx:       ctx,
+		cancelCtx: cancelCtx,
 	}
 	if f.StreamEnded() {
 		st.state = http2stateHalfClosedRemote
@@ -3779,50 +3991,6 @@ func (sc *http2serverConn) processHeaders(f *http2HeadersFrame) error {
 	if sc.curOpenStreams == 1 {
 		sc.setConnState(StateActive)
 	}
-	sc.req = http2requestParam{
-		stream: st,
-		header: make(Header),
-	}
-	sc.hpackDecoder.SetEmitFunc(sc.onNewHeaderField)
-	sc.hpackDecoder.SetEmitEnabled(true)
-	return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded())
-}
-
-func (st *http2stream) processTrailerHeaders(f *http2HeadersFrame) error {
-	sc := st.sc
-	sc.serveG.check()
-	if st.gotTrailerHeader {
-		return http2ConnectionError(http2ErrCodeProtocol)
-	}
-	st.gotTrailerHeader = true
-	if !f.StreamEnded() {
-		return http2StreamError{st.id, http2ErrCodeProtocol}
-	}
-	sc.resetPendingRequest()
-	return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded())
-}
-
-func (sc *http2serverConn) processContinuation(f *http2ContinuationFrame) error {
-	sc.serveG.check()
-	st := sc.streams[f.Header().StreamID]
-	if st.gotTrailerHeader {
-		return st.processTrailerHeaderBlockFragment(f.HeaderBlockFragment(), f.HeadersEnded())
-	}
-	return sc.processHeaderBlockFragment(st, f.HeaderBlockFragment(), f.HeadersEnded())
-}
-
-func (sc *http2serverConn) processHeaderBlockFragment(st *http2stream, frag []byte, end bool) error {
-	sc.serveG.check()
-	if _, err := sc.hpackDecoder.Write(frag); err != nil {
-		return http2ConnectionError(http2ErrCodeCompression)
-	}
-	if !end {
-		return nil
-	}
-	if err := sc.hpackDecoder.Close(); err != nil {
-		return http2ConnectionError(http2ErrCodeCompression)
-	}
-	defer sc.resetPendingRequest()
 	if sc.curOpenStreams > sc.advMaxStreams {
 
 		if sc.unackedSettings == 0 {
@@ -3833,7 +4001,7 @@ func (sc *http2serverConn) processHeaderBlockFragment(st *http2stream, frag []by
 		return http2StreamError{st.id, http2ErrCodeRefusedStream}
 	}
 
-	rw, req, err := sc.newWriterAndRequest()
+	rw, req, err := sc.newWriterAndRequest(st, f)
 	if err != nil {
 		return err
 	}
@@ -3845,36 +4013,42 @@ func (sc *http2serverConn) processHeaderBlockFragment(st *http2stream, frag []by
 	st.declBodyBytes = req.ContentLength
 
 	handler := sc.handler.ServeHTTP
-	if !sc.hpackDecoder.EmitEnabled() {
+	if f.Truncated {
 
 		handler = http2handleHeaderListTooLong
+	} else if err := http2checkValidHTTP2Request(req); err != nil {
+		handler = http2new400Handler(err)
 	}
 
 	go sc.runHandler(rw, req, handler)
 	return nil
 }
 
-func (st *http2stream) processTrailerHeaderBlockFragment(frag []byte, end bool) error {
+func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
 	sc := st.sc
 	sc.serveG.check()
-	sc.hpackDecoder.SetEmitFunc(st.onNewTrailerField)
-	if _, err := sc.hpackDecoder.Write(frag); err != nil {
-		return http2ConnectionError(http2ErrCodeCompression)
+	if st.gotTrailerHeader {
+		return http2ConnectionError(http2ErrCodeProtocol)
 	}
-	if !end {
-		return nil
+	st.gotTrailerHeader = true
+	if !f.StreamEnded() {
+		return http2StreamError{st.id, http2ErrCodeProtocol}
 	}
 
-	rp := &sc.req
-	if rp.invalidHeader {
-		return http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+	if len(f.PseudoFields()) > 0 {
+		return http2StreamError{st.id, http2ErrCodeProtocol}
 	}
+	if st.trailer != nil {
+		for _, hf := range f.RegularFields() {
+			key := sc.canonicalHeader(hf.Name)
+			if !http2ValidTrailerHeader(key) {
 
-	err := sc.hpackDecoder.Close()
-	st.endStream()
-	if err != nil {
-		return http2ConnectionError(http2ErrCodeCompression)
+				return http2StreamError{st.id, http2ErrCodeProtocol}
+			}
+			st.trailer[key] = append(st.trailer[key], hf.Value)
+		}
 	}
+	st.endStream()
 	return nil
 }
 
@@ -3912,59 +4086,56 @@ func http2adjustStreamPriority(streams map[uint32]*http2stream, streamID uint32,
 	}
 }
 
-// resetPendingRequest zeros out all state related to a HEADERS frame
-// and its zero or more CONTINUATION frames sent to start a new
-// request.
-func (sc *http2serverConn) resetPendingRequest() {
+func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHeadersFrame) (*http2responseWriter, *Request, error) {
 	sc.serveG.check()
-	sc.req = http2requestParam{}
-}
 
-func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request, error) {
-	sc.serveG.check()
-	rp := &sc.req
+	method := f.PseudoValue("method")
+	path := f.PseudoValue("path")
+	scheme := f.PseudoValue("scheme")
+	authority := f.PseudoValue("authority")
 
-	if rp.invalidHeader {
-		return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
-	}
-
-	isConnect := rp.method == "CONNECT"
+	isConnect := method == "CONNECT"
 	if isConnect {
-		if rp.path != "" || rp.scheme != "" || rp.authority == "" {
-			return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+		if path != "" || scheme != "" || authority == "" {
+			return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol}
 		}
-	} else if rp.method == "" || rp.path == "" ||
-		(rp.scheme != "https" && rp.scheme != "http") {
+	} else if method == "" || path == "" ||
+		(scheme != "https" && scheme != "http") {
 
-		return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+		return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol}
 	}
 
-	bodyOpen := rp.stream.state == http2stateOpen
-	if rp.method == "HEAD" && bodyOpen {
+	bodyOpen := !f.StreamEnded()
+	if method == "HEAD" && bodyOpen {
 
-		return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+		return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol}
 	}
 	var tlsState *tls.ConnectionState // nil if not scheme https
 
-	if rp.scheme == "https" {
+	if scheme == "https" {
 		tlsState = sc.tlsState
 	}
-	authority := rp.authority
+
+	header := make(Header)
+	for _, hf := range f.RegularFields() {
+		header.Add(sc.canonicalHeader(hf.Name), hf.Value)
+	}
+
 	if authority == "" {
-		authority = rp.header.Get("Host")
+		authority = header.Get("Host")
 	}
-	needsContinue := rp.header.Get("Expect") == "100-continue"
+	needsContinue := header.Get("Expect") == "100-continue"
 	if needsContinue {
-		rp.header.Del("Expect")
+		header.Del("Expect")
 	}
 
-	if cookies := rp.header["Cookie"]; len(cookies) > 1 {
-		rp.header.Set("Cookie", strings.Join(cookies, "; "))
+	if cookies := header["Cookie"]; len(cookies) > 1 {
+		header.Set("Cookie", strings.Join(cookies, "; "))
 	}
 
 	// Setup Trailers
 	var trailer Header
-	for _, v := range rp.header["Trailer"] {
+	for _, v := range header["Trailer"] {
 		for _, key := range strings.Split(v, ",") {
 			key = CanonicalHeaderKey(strings.TrimSpace(key))
 			switch key {
@@ -3978,31 +4149,31 @@ func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request
 			}
 		}
 	}
-	delete(rp.header, "Trailer")
+	delete(header, "Trailer")
 
 	body := &http2requestBody{
 		conn:          sc,
-		stream:        rp.stream,
+		stream:        st,
 		needsContinue: needsContinue,
 	}
 	var url_ *url.URL
 	var requestURI string
 	if isConnect {
-		url_ = &url.URL{Host: rp.authority}
-		requestURI = rp.authority
+		url_ = &url.URL{Host: authority}
+		requestURI = authority
 	} else {
 		var err error
-		url_, err = url.ParseRequestURI(rp.path)
+		url_, err = url.ParseRequestURI(path)
 		if err != nil {
-			return nil, nil, http2StreamError{rp.stream.id, http2ErrCodeProtocol}
+			return nil, nil, http2StreamError{f.StreamID, http2ErrCodeProtocol}
 		}
-		requestURI = rp.path
+		requestURI = path
 	}
 	req := &Request{
-		Method:     rp.method,
+		Method:     method,
 		URL:        url_,
 		RemoteAddr: sc.remoteAddrStr,
-		Header:     rp.header,
+		Header:     header,
 		RequestURI: requestURI,
 		Proto:      "HTTP/2.0",
 		ProtoMajor: 2,
@@ -4012,12 +4183,16 @@ func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request
 		Body:       body,
 		Trailer:    trailer,
 	}
+	req = http2requestWithContext(req, st.ctx)
 	if bodyOpen {
+
+		buf := make([]byte, http2initialWindowSize)
+
 		body.pipe = &http2pipe{
-			b: &http2fixedBuffer{buf: make([]byte, http2initialWindowSize)},
+			b: &http2fixedBuffer{buf: buf},
 		}
 
-		if vv, ok := rp.header["Content-Length"]; ok {
+		if vv, ok := header["Content-Length"]; ok {
 			req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
 		} else {
 			req.ContentLength = -1
@@ -4030,7 +4205,7 @@ func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request
 	rws.conn = sc
 	rws.bw = bwSave
 	rws.bw.Reset(http2chunkWriter{rws})
-	rws.stream = rp.stream
+	rws.stream = st
 	rws.req = req
 	rws.body = body
 
@@ -4038,10 +4213,20 @@ func (sc *http2serverConn) newWriterAndRequest() (*http2responseWriter, *Request
 	return rw, req, nil
 }
 
+func (sc *http2serverConn) getRequestBodyBuf() []byte {
+	sc.serveG.check()
+	if buf := sc.freeRequestBodyBuf; buf != nil {
+		sc.freeRequestBodyBuf = nil
+		return buf
+	}
+	return make([]byte, http2initialWindowSize)
+}
+
 // Run on its own goroutine.
 func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) {
 	didPanic := true
 	defer func() {
+		rw.rws.stream.cancelCtx()
 		if didPanic {
 			e := recover()
 			// Same as net/http:
@@ -4190,7 +4375,7 @@ type http2requestBody struct {
 
 func (b *http2requestBody) Close() error {
 	if b.pipe != nil {
-		b.pipe.CloseWithError(http2errClosedBody)
+		b.pipe.BreakWithError(http2errClosedBody)
 	}
 	b.closed = true
 	return nil
@@ -4265,9 +4450,9 @@ func (rws *http2responseWriterState) hasTrailers() bool { return len(rws.trailer
 // written in the trailers at the end of the response.
 func (rws *http2responseWriterState) declareTrailer(k string) {
 	k = CanonicalHeaderKey(k)
-	switch k {
-	case "Transfer-Encoding", "Content-Length", "Trailer":
+	if !http2ValidTrailerHeader(k) {
 
+		rws.conn.logf("ignoring invalid trailer %q", k)
 		return
 	}
 	if !http2strSliceContains(rws.trailers, k) {
@@ -4408,7 +4593,12 @@ func (rws *http2responseWriterState) promoteUndeclaredTrailers() {
 		rws.declareTrailer(trailerKey)
 		rws.handlerHeader[CanonicalHeaderKey(trailerKey)] = vv
 	}
-	sort.Strings(rws.trailers)
+
+	if len(rws.trailers) > 1 {
+		sorter := http2sorterPool.Get().(*http2sorter)
+		sorter.SortStrings(rws.trailers)
+		http2sorterPool.Put(sorter)
+	}
 }
 
 func (w *http2responseWriter) Flush() {
@@ -4552,6 +4742,72 @@ func http2foreachHeaderElement(v string, fn func(string)) {
 	}
 }
 
+// From http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.2
+var http2connHeaders = []string{
+	"Connection",
+	"Keep-Alive",
+	"Proxy-Connection",
+	"Transfer-Encoding",
+	"Upgrade",
+}
+
+// checkValidHTTP2Request checks whether req is a valid HTTP/2 request,
+// per RFC 7540 Section 8.1.2.2.
+// The returned error is reported to users.
+func http2checkValidHTTP2Request(req *Request) error {
+	for _, h := range http2connHeaders {
+		if _, ok := req.Header[h]; ok {
+			return fmt.Errorf("request header %q is not valid in HTTP/2", h)
+		}
+	}
+	te := req.Header["Te"]
+	if len(te) > 0 && (len(te) > 1 || (te[0] != "trailers" && te[0] != "")) {
+		return errors.New(`request header "TE" may only be "trailers" in HTTP/2`)
+	}
+	return nil
+}
+
+func http2new400Handler(err error) HandlerFunc {
+	return func(w ResponseWriter, r *Request) {
+		Error(w, err.Error(), StatusBadRequest)
+	}
+}
+
+// ValidTrailerHeader reports whether name is a valid header field name to appear
+// in trailers.
+// See: http://tools.ietf.org/html/rfc7230#section-4.1.2
+func http2ValidTrailerHeader(name string) bool {
+	name = CanonicalHeaderKey(name)
+	if strings.HasPrefix(name, "If-") || http2badTrailer[name] {
+		return false
+	}
+	return true
+}
+
+var http2badTrailer = map[string]bool{
+	"Authorization":       true,
+	"Cache-Control":       true,
+	"Connection":          true,
+	"Content-Encoding":    true,
+	"Content-Length":      true,
+	"Content-Range":       true,
+	"Content-Type":        true,
+	"Expect":              true,
+	"Host":                true,
+	"Keep-Alive":          true,
+	"Max-Forwards":        true,
+	"Pragma":              true,
+	"Proxy-Authenticate":  true,
+	"Proxy-Authorization": true,
+	"Proxy-Connection":    true,
+	"Range":               true,
+	"Realm":               true,
+	"Te":                  true,
+	"Trailer":             true,
+	"Transfer-Encoding":   true,
+	"Www-Authenticate":    true,
+}
+
 const (
 	// transportDefaultConnFlow is how many connection-level flow control
 	// tokens we give the server at start-up, past the default 64k.
@@ -4601,6 +4857,10 @@ type http2Transport struct {
 	// uncompressed.
 	DisableCompression bool
 
+	// AllowHTTP, if true, permits HTTP/2 requests using the insecure,
+	// plain-text "http" scheme. Note that this does not enable h2c support.
+	AllowHTTP bool
+
 	// MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
 	// send in the initial settings frame. It is how many bytes
 	// of response headers are allow. Unlike the http2 spec, zero here
@@ -4673,11 +4933,14 @@ type http2ClientConn struct {
 	inflow       http2flow  // peer's conn-level flow control
 	closed       bool
 	goAway       *http2GoAwayFrame             // if non-nil, the GoAwayFrame we received
+	goAwayDebug  string                        // goAway frame's debug data, retained as a string
 	streams      map[uint32]*http2clientStream // client-initiated
 	nextStreamID uint32
 	bw           *bufio.Writer
 	br           *bufio.Reader
 	fr           *http2Framer
+	lastActive   time.Time
+
 	// Settings from peer:
 	maxFrameSize         uint32
 	maxConcurrentStreams uint32
@@ -4695,10 +4958,12 @@ type http2ClientConn struct {
 type http2clientStream struct {
 	cc            *http2ClientConn
 	req           *Request
+	trace         *http2clientTrace // or nil
 	ID            uint32
 	resc          chan http2resAndError
 	bufPipe       http2pipe // buffered pipe with the flow-controlled response payload
 	requestedGzip bool
+	on100         func() // optional code to run if get a 100 continue response
 
 	flow        http2flow // guarded by cc.mu
 	inflow      http2flow // guarded by cc.mu
@@ -4712,36 +4977,43 @@ type http2clientStream struct {
 	done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu
 
 	// owned by clientConnReadLoop:
-	pastHeaders  bool // got HEADERS w/ END_HEADERS
-	pastTrailers bool // got second HEADERS frame w/ END_HEADERS
+	firstByte    bool // got the first response byte
+	pastHeaders  bool // got first MetaHeadersFrame (actual headers)
+	pastTrailers bool // got optional second MetaHeadersFrame (trailers)
 
 	trailer    Header  // accumulated trailers
 	resTrailer *Header // client's Response.Trailer
 }
 
 // awaitRequestCancel runs in its own goroutine and waits for the user
-// to either cancel a RoundTrip request (using the provided
-// Request.Cancel channel), or for the request to be done (any way it
-// might be removed from the cc.streams map: peer reset, successful
-// completion, TCP connection breakage, etc)
-func (cs *http2clientStream) awaitRequestCancel(cancel <-chan struct{}) {
-	if cancel == nil {
+// to cancel a RoundTrip request, its context to expire, or for the
+// request to be done (any way it might be removed from the cc.streams
+// map: peer reset, successful completion, TCP connection breakage,
+// etc)
+func (cs *http2clientStream) awaitRequestCancel(req *Request) {
+	ctx := http2reqContext(req)
+	if req.Cancel == nil && ctx.Done() == nil {
 		return
 	}
 	select {
-	case <-cancel:
+	case <-req.Cancel:
 		cs.bufPipe.CloseWithError(http2errRequestCanceled)
 		cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+	case <-ctx.Done():
+		cs.bufPipe.CloseWithError(ctx.Err())
+		cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
 	case <-cs.done:
 	}
 }
 
-// checkReset reports any error sent in a RST_STREAM frame by the
-// server.
-func (cs *http2clientStream) checkReset() error {
+// checkResetOrDone reports any error sent in a RST_STREAM frame by the
+// server, or errStreamClosed if the stream is complete.
+func (cs *http2clientStream) checkResetOrDone() error {
 	select {
 	case <-cs.peerReset:
 		return cs.resetErr
+	case <-cs.done:
+		return http2errStreamClosed
 	default:
 		return nil
 	}
@@ -4789,26 +5061,31 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) {
 
 // authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
 // and returns a host:port. The port 443 is added if needed.
-func http2authorityAddr(authority string) (addr string) {
+func http2authorityAddr(scheme string, authority string) (addr string) {
 	if _, _, err := net.SplitHostPort(authority); err == nil {
 		return authority
 	}
-	return net.JoinHostPort(authority, "443")
+	port := "443"
+	if scheme == "http" {
+		port = "80"
+	}
+	return net.JoinHostPort(authority, port)
 }
 
 // RoundTripOpt is like RoundTrip, but takes options.
 func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) {
-	if req.URL.Scheme != "https" {
+	if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
 		return nil, errors.New("http2: unsupported scheme")
 	}
 
-	addr := http2authorityAddr(req.URL.Host)
+	addr := http2authorityAddr(req.URL.Scheme, req.URL.Host)
 	for {
 		cc, err := t.connPool().GetClientConn(req, addr)
 		if err != nil {
 			t.vlogf("http2: Transport failed to get client conn for %s: %v", addr, err)
 			return nil, err
 		}
+		http2traceGotConn(req, cc)
 		res, err := cc.RoundTrip(req)
 		if http2shouldRetryRequest(req, err) {
 			continue
@@ -4825,7 +5102,7 @@ func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Res
 // connected from previous requests but are now sitting idle.
 // It does not interrupt any connections currently in use.
 func (t *http2Transport) CloseIdleConnections() {
-	if cp, ok := t.connPool().(*http2clientConnPool); ok {
+	if cp, ok := t.connPool().(http2clientConnPoolIdleCloser); ok {
 		cp.closeIdleConnections()
 	}
 }
@@ -4857,8 +5134,12 @@ func (t *http2Transport) newTLSConfig(host string) *tls.Config {
 	if t.TLSClientConfig != nil {
 		*cfg = *t.TLSClientConfig
 	}
-	cfg.NextProtos = []string{http2NextProtoTLS}
-	cfg.ServerName = host
+	if !http2strSliceContains(cfg.NextProtos, http2NextProtoTLS) {
+		cfg.NextProtos = append([]string{http2NextProtoTLS}, cfg.NextProtos...)
+	}
+	if cfg.ServerName == "" {
+		cfg.ServerName = host
+	}
 	return cfg
 }
 
@@ -4898,6 +5179,13 @@ func (t *http2Transport) disableKeepAlives() bool {
 	return t.t1 != nil && t.t1.DisableKeepAlives
 }
 
+func (t *http2Transport) expectContinueTimeout() time.Duration {
+	if t.t1 == nil {
+		return 0
+	}
+	return http2transportExpectContinueTimeout(t.t1)
+}
+
 func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
 	if http2VerboseLogs {
 		t.vlogf("http2: Transport creating client conn to %v", c.RemoteAddr())
@@ -4923,6 +5211,8 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
 	cc.bw = bufio.NewWriter(http2stickyErrWriter{c, &cc.werr})
 	cc.br = bufio.NewReader(c)
 	cc.fr = http2NewFramer(cc.bw, cc.br)
+	cc.fr.ReadMetaHeaders = hpack.NewDecoder(http2initialHeaderTableSize, nil)
+	cc.fr.MaxHeaderListSize = t.maxHeaderListSize()
 
 	cc.henc = hpack.NewEncoder(&cc.hbuf)
 
@@ -4932,8 +5222,8 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
 	}
 
 	initialSettings := []http2Setting{
-		http2Setting{ID: http2SettingEnablePush, Val: 0},
-		http2Setting{ID: http2SettingInitialWindowSize, Val: http2transportDefaultStreamFlow},
+		{ID: http2SettingEnablePush, Val: 0},
+		{ID: http2SettingInitialWindowSize, Val: http2transportDefaultStreamFlow},
 	}
 	if max := t.maxHeaderListSize(); max != 0 {
 		initialSettings = append(initialSettings, http2Setting{ID: http2SettingMaxHeaderListSize, Val: max})
@@ -4979,7 +5269,16 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
 func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) {
 	cc.mu.Lock()
 	defer cc.mu.Unlock()
+
+	old := cc.goAway
 	cc.goAway = f
+
+	if cc.goAwayDebug == "" {
+		cc.goAwayDebug = string(f.DebugData())
+	}
+	if old != nil && old.ErrCode != http2ErrCodeNo {
+		cc.goAway.ErrCode = old.ErrCode
+	}
 }
 
 func (cc *http2ClientConn) CanTakeNewRequest() bool {
@@ -5093,6 +5392,30 @@ func http2checkConnHeaders(req *Request) error {
 	return nil
 }
 
+func http2bodyAndLength(req *Request) (body io.Reader, contentLen int64) {
+	body = req.Body
+	if body == nil {
+		return nil, 0
+	}
+	if req.ContentLength != 0 {
+		return req.Body, req.ContentLength
+	}
+
+	// We have a body but a zero content length. Test to see if
+	// it's actually zero or just unset.
+	var buf [1]byte
+	n, rerr := io.ReadFull(body, buf[:])
+	if rerr != nil && rerr != io.EOF {
+		return http2errorReader{rerr}, -1
+	}
+	if n == 1 {
+
+		return io.MultiReader(bytes.NewReader(buf[:]), body), -1
+	}
+
+	return nil, 0
+}
+
 func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 	if err := http2checkConnHeaders(req); err != nil {
 		return nil, err
@@ -5104,67 +5427,62 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 	}
 	hasTrailers := trailers != ""
 
-	var body io.Reader = req.Body
-	contentLen := req.ContentLength
-	if req.Body != nil && contentLen == 0 {
-		// Test to see if it's actually zero or just unset.
-		var buf [1]byte
-		n, rerr := io.ReadFull(body, buf[:])
-		if rerr != nil && rerr != io.EOF {
-			contentLen = -1
-			body = http2errorReader{rerr}
-		} else if n == 1 {
-
-			contentLen = -1
-			body = io.MultiReader(bytes.NewReader(buf[:]), body)
-		} else {
-
-			body = nil
-		}
-	}
+	body, contentLen := http2bodyAndLength(req)
+	hasBody := body != nil
 
 	cc.mu.Lock()
+	cc.lastActive = time.Now()
 	if cc.closed || !cc.canTakeNewRequestLocked() {
 		cc.mu.Unlock()
 		return nil, http2errClientConnUnusable
 	}
 
-	cs := cc.newStream()
-	cs.req = req
-	hasBody := body != nil
-
+	// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
+	var requestedGzip bool
 	if !cc.t.disableCompression() &&
 		req.Header.Get("Accept-Encoding") == "" &&
 		req.Header.Get("Range") == "" &&
 		req.Method != "HEAD" {
 
-		cs.requestedGzip = true
+		requestedGzip = true
+	}
+
+	hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen)
+	if err != nil {
+		cc.mu.Unlock()
+		return nil, err
 	}
 
-	hdrs := cc.encodeHeaders(req, cs.requestedGzip, trailers, contentLen)
+	cs := cc.newStream()
+	cs.req = req
+	cs.trace = http2requestTrace(req)
+	cs.requestedGzip = requestedGzip
+	bodyWriter := cc.t.getBodyWriterState(cs, body)
+	cs.on100 = bodyWriter.on100
+
 	cc.wmu.Lock()
 	endStream := !hasBody && !hasTrailers
 	werr := cc.writeHeaders(cs.ID, endStream, hdrs)
 	cc.wmu.Unlock()
+	http2traceWroteHeaders(cs.trace)
 	cc.mu.Unlock()
 
 	if werr != nil {
 		if hasBody {
 			req.Body.Close()
+			bodyWriter.cancel()
 		}
 		cc.forgetStreamID(cs.ID)
 
+		http2traceWroteRequest(cs.trace, werr)
 		return nil, werr
 	}
 
 	var respHeaderTimer <-chan time.Time
-	var bodyCopyErrc chan error // result of body copy
 	if hasBody {
-		bodyCopyErrc = make(chan error, 1)
-		go func() {
-			bodyCopyErrc <- cs.writeRequestBody(body, req.Body)
-		}()
+		bodyWriter.scheduleBodyWrite()
 	} else {
+		http2traceWroteRequest(cs.trace, nil)
 		if d := cc.responseHeaderTimeout(); d != 0 {
 			timer := time.NewTimer(d)
 			defer timer.Stop()
@@ -5173,8 +5491,8 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 	}
 
 	readLoopResCh := cs.resc
-	requestCanceledCh := http2requestCancel(req)
 	bodyWritten := false
+	ctx := http2reqContext(req)
 
 	for {
 		select {
@@ -5182,6 +5500,7 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 			res := re.res
 			if re.err != nil || res.StatusCode > 299 {
 
+				bodyWriter.cancel()
 				cs.abortRequestBodyWrite(http2errStopReqBodyWrite)
 			}
 			if re.err != nil {
@@ -5196,21 +5515,32 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
 			if !hasBody || bodyWritten {
 				cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
 			} else {
+				bodyWriter.cancel()
 				cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
 			}
 			return nil, http2errTimeout
-		case <-requestCanceledCh:
+		case <-ctx.Done():
 			cc.forgetStreamID(cs.ID)
 			if !hasBody || bodyWritten {
 				cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
 			} else {
+				bodyWriter.cancel()
+				cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
+			}
+			return nil, ctx.Err()
+		case <-req.Cancel:
+			cc.forgetStreamID(cs.ID)
+			if !hasBody || bodyWritten {
+				cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+			} else {
+				bodyWriter.cancel()
 				cs.abortRequestBodyWrite(http2errStopReqBodyWriteAndCancel)
 			}
 			return nil, http2errRequestCanceled
 		case <-cs.peerReset:
 
 			return nil, cs.resetErr
-		case err := <-bodyCopyErrc:
+		case err := <-bodyWriter.resc:
 			if err != nil {
 				return nil, err
 			}
@@ -5268,6 +5598,7 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
 	defer cc.putFrameScratchBuffer(buf)
 
 	defer func() {
+		http2traceWroteRequest(cs.trace, err)
 
 		cerr := bodyCloser.Close()
 		if err == nil {
@@ -5355,7 +5686,7 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err er
 		if cs.stopReqBody != nil {
 			return 0, cs.stopReqBody
 		}
-		if err := cs.checkReset(); err != nil {
+		if err := cs.checkResetOrDone(); err != nil {
 			return 0, err
 		}
 		if a := cs.flow.available(); a > 0 {
@@ -5382,7 +5713,7 @@ type http2badStringError struct {
 func (e *http2badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) }
 
 // requires cc.mu be held.
-func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) []byte {
+func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) {
 	cc.hbuf.Reset()
 
 	host := req.Host
@@ -5390,6 +5721,17 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
 		host = req.URL.Host
 	}
 
+	for k, vv := range req.Header {
+		if !httplex.ValidHeaderFieldName(k) {
+			return nil, fmt.Errorf("invalid HTTP header name %q", k)
+		}
+		for _, v := range vv {
+			if !httplex.ValidHeaderFieldValue(v) {
+				return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
+			}
+		}
+	}
+
 	cc.writeHeader(":authority", host)
 	cc.writeHeader(":method", req.Method)
 	if req.Method != "CONNECT" {
@@ -5407,7 +5749,7 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
 		case "host", "content-length":
 
 			continue
-		case "connection", "proxy-connection", "transfer-encoding", "upgrade":
+		case "connection", "proxy-connection", "transfer-encoding", "upgrade", "keep-alive":
 
 			continue
 		case "user-agent":
@@ -5434,7 +5776,7 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
 	if !didUA {
 		cc.writeHeader("user-agent", http2defaultUserAgent)
 	}
-	return cc.hbuf.Bytes()
+	return cc.hbuf.Bytes(), nil
 }
 
 // shouldSendReqContentLength reports whether the http2.Transport should send
@@ -5510,8 +5852,10 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr
 	defer cc.mu.Unlock()
 	cs := cc.streams[id]
 	if andRemove && cs != nil && !cc.closed {
+		cc.lastActive = time.Now()
 		delete(cc.streams, id)
 		close(cs.done)
+		cc.cond.Broadcast()
 	}
 	return cs
 }
@@ -5521,15 +5865,6 @@ type http2clientConnReadLoop struct {
 	cc            *http2ClientConn
 	activeRes     map[uint32]*http2clientStream // keyed by streamID
 	closeWhenIdle bool
-
-	hdec *hpack.Decoder
-
-	// Fields reset on each HEADERS:
-	nextRes              *Response
-	sawRegHeader         bool  // saw non-pseudo header
-	reqMalformed         error // non-nil once known to be malformed
-	lastHeaderEndsStream bool
-	headerListSize       int64 // actually uint32, but easier math this way
 }
 
 // readLoop runs in its own goroutine and reads and dispatches frames.
@@ -5538,7 +5873,6 @@ func (cc *http2ClientConn) readLoop() {
 		cc:        cc,
 		activeRes: make(map[uint32]*http2clientStream),
 	}
-	rl.hdec = hpack.NewDecoder(http2initialHeaderTableSize, rl.onNewHeaderField)
 
 	defer rl.cleanup()
 	cc.readerErr = rl.run()
@@ -5549,6 +5883,19 @@ func (cc *http2ClientConn) readLoop() {
 	}
 }
 
+// GoAwayError is returned by the Transport when the server closes the
+// TCP connection after sending a GOAWAY frame.
+type http2GoAwayError struct {
+	LastStreamID uint32
+	ErrCode      http2ErrCode
+	DebugData    string
+}
+
+func (e http2GoAwayError) Error() string {
+	return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",
+		e.LastStreamID, e.ErrCode, e.DebugData)
+}
+
 func (rl *http2clientConnReadLoop) cleanup() {
 	cc := rl.cc
 	defer cc.tconn.Close()
@@ -5556,10 +5903,18 @@ func (rl *http2clientConnReadLoop) cleanup() {
 	defer close(cc.readerDone)
 
 	err := cc.readerErr
+	cc.mu.Lock()
 	if err == io.EOF {
-		err = io.ErrUnexpectedEOF
+		if cc.goAway != nil {
+			err = http2GoAwayError{
+				LastStreamID: cc.goAway.LastStreamID,
+				ErrCode:      cc.goAway.ErrCode,
+				DebugData:    cc.goAwayDebug,
+			}
+		} else {
+			err = io.ErrUnexpectedEOF
+		}
 	}
-	cc.mu.Lock()
 	for _, cs := range rl.activeRes {
 		cs.bufPipe.CloseWithError(err)
 	}
@@ -5585,8 +5940,10 @@ func (rl *http2clientConnReadLoop) run() error {
 			cc.vlogf("Transport readFrame error: (%T) %v", err, err)
 		}
 		if se, ok := err.(http2StreamError); ok {
-
-			return se
+			if cs := cc.streamByID(se.StreamID, true); cs != nil {
+				rl.endStreamError(cs, cc.fr.errDetail)
+			}
+			continue
 		} else if err != nil {
 			return err
 		}
@@ -5596,13 +5953,10 @@ func (rl *http2clientConnReadLoop) run() error {
 		maybeIdle := false
 
 		switch f := f.(type) {
-		case *http2HeadersFrame:
+		case *http2MetaHeadersFrame:
 			err = rl.processHeaders(f)
 			maybeIdle = true
 			gotReply = true
-		case *http2ContinuationFrame:
-			err = rl.processContinuation(f)
-			maybeIdle = true
 		case *http2DataFrame:
 			err = rl.processData(f)
 			maybeIdle = true
@@ -5632,83 +5986,105 @@ func (rl *http2clientConnReadLoop) run() error {
 	}
 }
 
-func (rl *http2clientConnReadLoop) processHeaders(f *http2HeadersFrame) error {
-	rl.sawRegHeader = false
-	rl.reqMalformed = nil
-	rl.lastHeaderEndsStream = f.StreamEnded()
-	rl.headerListSize = 0
-	rl.nextRes = &Response{
-		Proto:      "HTTP/2.0",
-		ProtoMajor: 2,
-		Header:     make(Header),
-	}
-	rl.hdec.SetEmitEnabled(true)
-	return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded())
-}
-
-func (rl *http2clientConnReadLoop) processContinuation(f *http2ContinuationFrame) error {
-	return rl.processHeaderBlockFragment(f.HeaderBlockFragment(), f.StreamID, f.HeadersEnded())
-}
-
-func (rl *http2clientConnReadLoop) processHeaderBlockFragment(frag []byte, streamID uint32, finalFrag bool) error {
+func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) error {
 	cc := rl.cc
-	streamEnded := rl.lastHeaderEndsStream
-	cs := cc.streamByID(streamID, streamEnded && finalFrag)
+	cs := cc.streamByID(f.StreamID, f.StreamEnded())
 	if cs == nil {
 
 		return nil
 	}
-	if cs.pastHeaders {
-		rl.hdec.SetEmitFunc(func(f hpack.HeaderField) { rl.onNewTrailerField(cs, f) })
-	} else {
-		rl.hdec.SetEmitFunc(rl.onNewHeaderField)
-	}
-	_, err := rl.hdec.Write(frag)
-	if err != nil {
-		return http2ConnectionError(http2ErrCodeCompression)
-	}
-	if finalFrag {
-		if err := rl.hdec.Close(); err != nil {
-			return http2ConnectionError(http2ErrCodeCompression)
-		}
-	}
+	if !cs.firstByte {
+		if cs.trace != nil {
 
-	if !finalFrag {
-		return nil
+			http2traceFirstResponseByte(cs.trace)
+		}
+		cs.firstByte = true
 	}
-
 	if !cs.pastHeaders {
 		cs.pastHeaders = true
 	} else {
+		return rl.processTrailers(cs, f)
+	}
 
-		if cs.pastTrailers {
-
-			return http2ConnectionError(http2ErrCodeProtocol)
+	res, err := rl.handleResponse(cs, f)
+	if err != nil {
+		if _, ok := err.(http2ConnectionError); ok {
+			return err
 		}
-		cs.pastTrailers = true
-		if !streamEnded {
 
-			return http2ConnectionError(http2ErrCodeProtocol)
-		}
-		rl.endStream(cs)
+		cs.cc.writeStreamReset(f.StreamID, http2ErrCodeProtocol, err)
+		cs.resc <- http2resAndError{err: err}
 		return nil
 	}
+	if res == nil {
 
-	if rl.reqMalformed != nil {
-		cs.resc <- http2resAndError{err: rl.reqMalformed}
-		rl.cc.writeStreamReset(cs.ID, http2ErrCodeProtocol, rl.reqMalformed)
 		return nil
 	}
+	if res.Body != http2noBody {
+		rl.activeRes[cs.ID] = cs
+	}
+	cs.resTrailer = &res.Trailer
+	cs.resc <- http2resAndError{res: res}
+	return nil
+}
 
-	res := rl.nextRes
+// may return error types nil, or ConnectionError. Any other error value
+// is a StreamError of type ErrCodeProtocol. The returned error in that case
+// is the detail.
+//
+// As a special case, handleResponse may return (nil, nil) to skip the
+// frame (currently only used for 100 expect continue). This special
+// case is going away after Issue 13851 is fixed.
+func (rl *http2clientConnReadLoop) handleResponse(cs *http2clientStream, f *http2MetaHeadersFrame) (*Response, error) {
+	if f.Truncated {
+		return nil, http2errResponseHeaderListSize
+	}
 
-	if res.StatusCode == 100 {
+	status := f.PseudoValue("status")
+	if status == "" {
+		return nil, errors.New("missing status pseudo header")
+	}
+	statusCode, err := strconv.Atoi(status)
+	if err != nil {
+		return nil, errors.New("malformed non-numeric status pseudo header")
+	}
 
+	if statusCode == 100 {
+		http2traceGot100Continue(cs.trace)
+		if cs.on100 != nil {
+			cs.on100()
+		}
 		cs.pastHeaders = false
-		return nil
+		return nil, nil
 	}
 
-	if !streamEnded || cs.req.Method == "HEAD" {
+	header := make(Header)
+	res := &Response{
+		Proto:      "HTTP/2.0",
+		ProtoMajor: 2,
+		Header:     header,
+		StatusCode: statusCode,
+		Status:     status + " " + StatusText(statusCode),
+	}
+	for _, hf := range f.RegularFields() {
+		key := CanonicalHeaderKey(hf.Name)
+		if key == "Trailer" {
+			t := res.Trailer
+			if t == nil {
+				t = make(Header)
+				res.Trailer = t
+			}
+			http2foreachHeaderElement(hf.Value, func(v string) {
+				t[CanonicalHeaderKey(v)] = nil
+			})
+		} else {
+			header[key] = append(header[key], hf.Value)
+		}
+	}
+
+	streamEnded := f.StreamEnded()
+	isHead := cs.req.Method == "HEAD"
+	if !streamEnded || isHead {
 		res.ContentLength = -1
 		if clens := res.Header["Content-Length"]; len(clens) == 1 {
 			if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil {
@@ -5721,27 +6097,50 @@ func (rl *http2clientConnReadLoop) processHeaderBlockFragment(frag []byte, strea
 		}
 	}
 
-	if streamEnded {
+	if streamEnded || isHead {
 		res.Body = http2noBody
-	} else {
-		buf := new(bytes.Buffer)
-		cs.bufPipe = http2pipe{b: buf}
-		cs.bytesRemain = res.ContentLength
-		res.Body = http2transportResponseBody{cs}
-		go cs.awaitRequestCancel(http2requestCancel(cs.req))
-
-		if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" {
-			res.Header.Del("Content-Encoding")
-			res.Header.Del("Content-Length")
-			res.ContentLength = -1
-			res.Body = &http2gzipReader{body: res.Body}
-		}
-		rl.activeRes[cs.ID] = cs
+		return res, nil
 	}
 
-	cs.resTrailer = &res.Trailer
-	cs.resc <- http2resAndError{res: res}
-	rl.nextRes = nil
+	buf := new(bytes.Buffer)
+	cs.bufPipe = http2pipe{b: buf}
+	cs.bytesRemain = res.ContentLength
+	res.Body = http2transportResponseBody{cs}
+	go cs.awaitRequestCancel(cs.req)
+
+	if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" {
+		res.Header.Del("Content-Encoding")
+		res.Header.Del("Content-Length")
+		res.ContentLength = -1
+		res.Body = &http2gzipReader{body: res.Body}
+		http2setResponseUncompressed(res)
+	}
+	return res, nil
+}
+
+func (rl *http2clientConnReadLoop) processTrailers(cs *http2clientStream, f *http2MetaHeadersFrame) error {
+	if cs.pastTrailers {
+
+		return http2ConnectionError(http2ErrCodeProtocol)
+	}
+	cs.pastTrailers = true
+	if !f.StreamEnded() {
+
+		return http2ConnectionError(http2ErrCodeProtocol)
+	}
+	if len(f.PseudoFields()) > 0 {
+
+		return http2ConnectionError(http2ErrCodeProtocol)
+	}
+
+	trailer := make(Header)
+	for _, hf := range f.RegularFields() {
+		key := CanonicalHeaderKey(hf.Name)
+		trailer[key] = append(trailer[key], hf.Value)
+	}
+	cs.trailer = trailer
+
+	rl.endStream(cs)
 	return nil
 }
 
@@ -5792,8 +6191,10 @@ func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
 		cc.inflow.add(connAdd)
 	}
 	if err == nil {
-		if v := cs.inflow.available(); v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
-			streamAdd = http2transportDefaultStreamFlow - v
+
+		v := int(cs.inflow.available()) + cs.bufPipe.Len()
+		if v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
+			streamAdd = int32(http2transportDefaultStreamFlow - v)
 			cs.inflow.add(streamAdd)
 		}
 	}
@@ -5855,6 +6256,7 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
 		cc.mu.Unlock()
 
 		if _, err := cs.bufPipe.Write(data); err != nil {
+			rl.endStreamError(cs, err)
 			return err
 		}
 	}
@@ -5869,11 +6271,14 @@ var http2errInvalidTrailers = errors.New("http2: invalid trailers")
 
 func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) {
 
-	err := io.EOF
-	code := cs.copyTrailers
-	if rl.reqMalformed != nil {
-		err = rl.reqMalformed
-		code = nil
+	rl.endStreamError(cs, nil)
+}
+
+func (rl *http2clientConnReadLoop) endStreamError(cs *http2clientStream, err error) {
+	var code func()
+	if err == nil {
+		err = io.EOF
+		code = cs.copyTrailers
 	}
 	cs.bufPipe.closeWithErrorAndCode(err, code)
 	delete(rl.activeRes, cs.ID)
@@ -5997,113 +6402,6 @@ var (
 	http2errPseudoTrailers         = errors.New("http2: invalid pseudo header in trailers")
 )
 
-func (rl *http2clientConnReadLoop) checkHeaderField(f hpack.HeaderField) bool {
-	if rl.reqMalformed != nil {
-		return false
-	}
-
-	const headerFieldOverhead = 32 // per spec
-	rl.headerListSize += int64(len(f.Name)) + int64(len(f.Value)) + headerFieldOverhead
-	if max := rl.cc.t.maxHeaderListSize(); max != 0 && rl.headerListSize > int64(max) {
-		rl.hdec.SetEmitEnabled(false)
-		rl.reqMalformed = http2errResponseHeaderListSize
-		return false
-	}
-
-	if !http2validHeaderFieldValue(f.Value) {
-		rl.reqMalformed = http2errInvalidHeaderFieldValue
-		return false
-	}
-
-	isPseudo := strings.HasPrefix(f.Name, ":")
-	if isPseudo {
-		if rl.sawRegHeader {
-			rl.reqMalformed = errors.New("http2: invalid pseudo header after regular header")
-			return false
-		}
-	} else {
-		if !http2validHeaderFieldName(f.Name) {
-			rl.reqMalformed = http2errInvalidHeaderFieldName
-			return false
-		}
-		rl.sawRegHeader = true
-	}
-
-	return true
-}
-
-// onNewHeaderField runs on the readLoop goroutine whenever a new
-// hpack header field is decoded.
-func (rl *http2clientConnReadLoop) onNewHeaderField(f hpack.HeaderField) {
-	cc := rl.cc
-	if http2VerboseLogs {
-		cc.logf("http2: Transport decoded %v", f)
-	}
-
-	if !rl.checkHeaderField(f) {
-		return
-	}
-
-	isPseudo := strings.HasPrefix(f.Name, ":")
-	if isPseudo {
-		switch f.Name {
-		case ":status":
-			code, err := strconv.Atoi(f.Value)
-			if err != nil {
-				rl.reqMalformed = errors.New("http2: invalid :status")
-				return
-			}
-			rl.nextRes.Status = f.Value + " " + StatusText(code)
-			rl.nextRes.StatusCode = code
-		default:
-
-			rl.reqMalformed = fmt.Errorf("http2: unknown response pseudo header %q", f.Name)
-		}
-		return
-	}
-
-	key := CanonicalHeaderKey(f.Name)
-	if key == "Trailer" {
-		t := rl.nextRes.Trailer
-		if t == nil {
-			t = make(Header)
-			rl.nextRes.Trailer = t
-		}
-		http2foreachHeaderElement(f.Value, func(v string) {
-			t[CanonicalHeaderKey(v)] = nil
-		})
-	} else {
-		rl.nextRes.Header.Add(key, f.Value)
-	}
-}
-
-func (rl *http2clientConnReadLoop) onNewTrailerField(cs *http2clientStream, f hpack.HeaderField) {
-	if http2VerboseLogs {
-		rl.cc.logf("http2: Transport decoded trailer %v", f)
-	}
-	if !rl.checkHeaderField(f) {
-		return
-	}
-	if strings.HasPrefix(f.Name, ":") {
-
-		rl.reqMalformed = http2errPseudoTrailers
-		return
-	}
-
-	key := CanonicalHeaderKey(f.Name)
-
-	// The spec says one must predeclare their trailers but in practice
-	// popular users (which is to say the only user we found) do not so we
-	// violate the spec and accept all of them.
-	const acceptAllTrailers = true
-	if _, ok := (*cs.resTrailer)[key]; ok || acceptAllTrailers {
-		if cs.trailer == nil {
-			cs.trailer = make(Header)
-		}
-		cs.trailer[key] = append(cs.trailer[key], f.Value)
-	}
-}
-
 func (cc *http2ClientConn) logf(format string, args ...interface{}) {
 	cc.t.logf(format, args...)
 }
@@ -6167,6 +6465,79 @@ type http2errorReader struct{ err error }
 
 func (r http2errorReader) Read(p []byte) (int, error) { return 0, r.err }
 
+// bodyWriterState encapsulates various state around the Transport's writing
+// of the request body, particularly regarding doing delayed writes of the body
+// when the request contains "Expect: 100-continue".
+type http2bodyWriterState struct {
+	cs     *http2clientStream
+	timer  *time.Timer   // if non-nil, we're doing a delayed write
+	fnonce *sync.Once    // to call fn with
+	fn     func()        // the code to run in the goroutine, writing the body
+	resc   chan error    // result of fn's execution
+	delay  time.Duration // how long we should delay a delayed write for
+}
+
+func (t *http2Transport) getBodyWriterState(cs *http2clientStream, body io.Reader) (s http2bodyWriterState) {
+	s.cs = cs
+	if body == nil {
+		return
+	}
+	resc := make(chan error, 1)
+	s.resc = resc
+	s.fn = func() {
+		resc <- cs.writeRequestBody(body, cs.req.Body)
+	}
+	s.delay = t.expectContinueTimeout()
+	if s.delay == 0 ||
+		!httplex.HeaderValuesContainsToken(
+			cs.req.Header["Expect"],
+			"100-continue") {
+		return
+	}
+	s.fnonce = new(sync.Once)
+
+	// Arm the timer with a very large duration, which we'll
+	// intentionally lower later. It has to be large now because
+	// we need a handle to it before writing the headers, but the
+	// s.delay value is defined to not start until after the
+	// request headers were written.
+	const hugeDuration = 365 * 24 * time.Hour
+	s.timer = time.AfterFunc(hugeDuration, func() {
+		s.fnonce.Do(s.fn)
+	})
+	return
+}
+
+func (s http2bodyWriterState) cancel() {
+	if s.timer != nil {
+		s.timer.Stop()
+	}
+}
+
+func (s http2bodyWriterState) on100() {
+	if s.timer == nil {
+
+		return
+	}
+	s.timer.Stop()
+	go func() { s.fnonce.Do(s.fn) }()
+}
+
+// scheduleBodyWrite starts writing the body, either immediately (in
+// the common case) or after the delay timeout. It should not be
+// called until after the headers have been written.
+func (s http2bodyWriterState) scheduleBodyWrite() {
+	if s.timer == nil {
+
+		go s.fn()
+		return
+	}
+	http2traceWait100Continue(s.cs.trace)
+	if s.timer.Stop() {
+		s.timer.Reset(s.delay)
+	}
+}
+
 // writeFramer is implemented by any type that is used to write frames.
 type http2writeFramer interface {
 	writeFrame(http2writeContext) error
@@ -6380,24 +6751,22 @@ func (wu http2writeWindowUpdate) writeFrame(ctx http2writeContext) error {
 }
 
 func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
-
 	if keys == nil {
-		keys = make([]string, 0, len(h))
-		for k := range h {
-			keys = append(keys, k)
-		}
-		sort.Strings(keys)
+		sorter := http2sorterPool.Get().(*http2sorter)
+
+		defer http2sorterPool.Put(sorter)
+		keys = sorter.Keys(h)
 	}
 	for _, k := range keys {
 		vv := h[k]
 		k = http2lowerHeader(k)
-		if !http2validHeaderFieldName(k) {
+		if !http2validWireHeaderFieldName(k) {
 
 			continue
 		}
 		isTE := k == "transfer-encoding"
 		for _, v := range vv {
-			if !http2validHeaderFieldValue(v) {
+			if !httplex.ValidHeaderFieldValue(v) {
 
 				continue
 			}
diff --git a/src/net/http/header.go b/src/net/http/header.go
index 049f32f..6343165 100644
--- a/src/net/http/header.go
+++ b/src/net/http/header.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -25,7 +25,7 @@ func (h Header) Add(key, value string) {
 }
 
 // Set sets the header entries associated with key to
-// the single element value.  It replaces any existing
+// the single element value. It replaces any existing
 // values associated with key.
 func (h Header) Set(key, value string) {
 	textproto.MIMEHeader(h).Set(key, value)
@@ -164,9 +164,9 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
 }
 
 // CanonicalHeaderKey returns the canonical format of the
-// header key s.  The canonicalization converts the first
+// header key s. The canonicalization converts the first
 // letter and any letter following a hyphen to upper case;
-// the rest are converted to lowercase.  For example, the
+// the rest are converted to lowercase. For example, the
 // canonical key for "accept-encoding" is "Accept-Encoding".
 // If s contains a space or invalid header field bytes, it is
 // returned without modifications.
@@ -186,7 +186,7 @@ func hasToken(v, token string) bool {
 	for sp := 0; sp <= len(v)-len(token); sp++ {
 		// Check that first character is good.
 		// The token is ASCII, so checking only a single byte
-		// is sufficient.  We skip this potential starting
+		// is sufficient. We skip this potential starting
 		// position if both the first byte and its potential
 		// ASCII uppercase equivalent (b|0x20) don't match.
 		// False positives ('^' => '~') are caught by EqualFold.
diff --git a/src/net/http/header_test.go b/src/net/http/header_test.go
index 9dcd591..bbd35c4 100644
--- a/src/net/http/header_test.go
+++ b/src/net/http/header_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/http/http.go b/src/net/http/http.go
new file mode 100644
index 0000000..4d088a5
--- /dev/null
+++ b/src/net/http/http.go
@@ -0,0 +1,43 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+	"strings"
+
+	"golang.org/x/net/lex/httplex"
+)
+
+// maxInt64 is the effective "infinite" value for the Server and
+// Transport's byte-limiting readers.
+const maxInt64 = 1<<63 - 1
+
+// TODO(bradfitz): move common stuff here. The other files have accumulated
+// generic http stuff in random places.
+
+// contextKey is a value for use with context.WithValue. It's used as
+// a pointer so it fits in an interface{} without allocation.
+type contextKey struct {
+	name string
+}
+
+func (k *contextKey) String() string { return "net/http context value " + k.name }
+
+// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
+// return true if the string includes a port.
+func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
+
+// removeEmptyPort strips the empty port in ":port" to ""
+// as mandated by RFC 3986 Section 6.2.3.
+func removeEmptyPort(host string) string {
+	if hasPort(host) {
+		return strings.TrimSuffix(host, ":")
+	}
+	return host
+}
+
+func isNotToken(r rune) bool {
+	return !httplex.IsTokenRune(r)
+}
diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go
index dead3b0..34da4bb 100644
--- a/src/net/http/http_test.go
+++ b/src/net/http/http_test.go
@@ -2,11 +2,14 @@
 // 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.
+// Tests of internal functions and things with no better homes.
 
 package http
 
 import (
+	"bytes"
+	"internal/testenv"
+	"os/exec"
 	"reflect"
 	"testing"
 )
@@ -56,3 +59,35 @@ func TestCleanHost(t *testing.T) {
 		}
 	}
 }
+
+// Test that cmd/go doesn't link in the HTTP server.
+//
+// This catches accidental dependencies between the HTTP transport and
+// server code.
+func TestCmdGoNoHTTPServer(t *testing.T) {
+	goBin := testenv.GoToolPath(t)
+	out, err := exec.Command("go", "tool", "nm", goBin).CombinedOutput()
+	if err != nil {
+		t.Fatalf("go tool nm: %v: %s", err, out)
+	}
+	wantSym := map[string]bool{
+		// Verify these exist: (sanity checking this test)
+		"net/http.(*Client).Get":          true,
+		"net/http.(*Transport).RoundTrip": true,
+
+		// Verify these don't exist:
+		"net/http.http2Server":           false,
+		"net/http.(*Server).Serve":       false,
+		"net/http.(*ServeMux).ServeHTTP": false,
+		"net/http.DefaultServeMux":       false,
+	}
+	for sym, want := range wantSym {
+		got := bytes.Contains(out, []byte(sym))
+		if !want && got {
+			t.Errorf("cmd/go unexpectedly links in HTTP server code; found symbol %q in cmd/go", sym)
+		}
+		if want && !got {
+			t.Errorf("expected to find symbol %q in cmd/go; not found", sym)
+		}
+	}
+}
diff --git a/src/net/http/httptest/example_test.go b/src/net/http/httptest/example_test.go
index 42a0ec9..124ce75 100644
--- a/src/net/http/httptest/example_test.go
+++ b/src/net/http/httptest/example_test.go
@@ -17,11 +17,7 @@ func ExampleResponseRecorder() {
 		http.Error(w, "something failed", http.StatusInternalServerError)
 	}
 
-	req, err := http.NewRequest("GET", "http://example.com/foo", nil)
-	if err != nil {
-		log.Fatal(err)
-	}
-
+	req := httptest.NewRequest("GET", "http://example.com/foo", nil)
 	w := httptest.NewRecorder()
 	handler(w, req)
 
diff --git a/src/net/http/httptest/httptest.go b/src/net/http/httptest/httptest.go
new file mode 100644
index 0000000..e2148a6
--- /dev/null
+++ b/src/net/http/httptest/httptest.go
@@ -0,0 +1,88 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package httptest provides utilities for HTTP testing.
+package httptest
+
+import (
+	"bufio"
+	"bytes"
+	"crypto/tls"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"strings"
+)
+
+// NewRequest returns a new incoming server Request, suitable
+// for passing to an http.Handler for testing.
+//
+// The target is the RFC 7230 "request-target": it may be either a
+// path or an absolute URL. If target is an absolute URL, the host name
+// from the URL is used. Otherwise, "example.com" is used.
+//
+// The TLS field is set to a non-nil dummy value if target has scheme
+// "https".
+//
+// The Request.Proto is always HTTP/1.1.
+//
+// An empty method means "GET".
+//
+// The provided body may be nil. If the body is of type *bytes.Reader,
+// *strings.Reader, or *bytes.Buffer, the Request.ContentLength is
+// set.
+//
+// NewRequest panics on error for ease of use in testing, where a
+// panic is acceptable.
+func NewRequest(method, target string, body io.Reader) *http.Request {
+	if method == "" {
+		method = "GET"
+	}
+	req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(method + " " + target + " HTTP/1.0\r\n\r\n")))
+	if err != nil {
+		panic("invalid NewRequest arguments; " + err.Error())
+	}
+
+	// HTTP/1.0 was used above to avoid needing a Host field. Change it to 1.1 here.
+	req.Proto = "HTTP/1.1"
+	req.ProtoMinor = 1
+	req.Close = false
+
+	if body != nil {
+		switch v := body.(type) {
+		case *bytes.Buffer:
+			req.ContentLength = int64(v.Len())
+		case *bytes.Reader:
+			req.ContentLength = int64(v.Len())
+		case *strings.Reader:
+			req.ContentLength = int64(v.Len())
+		default:
+			req.ContentLength = -1
+		}
+		if rc, ok := body.(io.ReadCloser); ok {
+			req.Body = rc
+		} else {
+			req.Body = ioutil.NopCloser(body)
+		}
+	}
+
+	// 192.0.2.0/24 is "TEST-NET" in RFC 5737 for use solely in
+	// documentation and example source code and should not be
+	// used publicly.
+	req.RemoteAddr = "192.0.2.1:1234"
+
+	if req.Host == "" {
+		req.Host = "example.com"
+	}
+
+	if strings.HasPrefix(target, "https://") {
+		req.TLS = &tls.ConnectionState{
+			Version:           tls.VersionTLS12,
+			HandshakeComplete: true,
+			ServerName:        req.Host,
+		}
+	}
+
+	return req
+}
diff --git a/src/net/http/httptest/httptest_test.go b/src/net/http/httptest/httptest_test.go
new file mode 100644
index 0000000..4f9ecbd
--- /dev/null
+++ b/src/net/http/httptest/httptest_test.go
@@ -0,0 +1,177 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package httptest
+
+import (
+	"crypto/tls"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func TestNewRequest(t *testing.T) {
+	tests := [...]struct {
+		method, uri string
+		body        io.Reader
+
+		want     *http.Request
+		wantBody string
+	}{
+		// Empty method means GET:
+		0: {
+			method: "",
+			uri:    "/",
+			body:   nil,
+			want: &http.Request{
+				Method:     "GET",
+				Host:       "example.com",
+				URL:        &url.URL{Path: "/"},
+				Header:     http.Header{},
+				Proto:      "HTTP/1.1",
+				ProtoMajor: 1,
+				ProtoMinor: 1,
+				RemoteAddr: "192.0.2.1:1234",
+				RequestURI: "/",
+			},
+			wantBody: "",
+		},
+
+		// GET with full URL:
+		1: {
+			method: "GET",
+			uri:    "http://foo.com/path/%2f/bar/",
+			body:   nil,
+			want: &http.Request{
+				Method: "GET",
+				Host:   "foo.com",
+				URL: &url.URL{
+					Scheme:  "http",
+					Path:    "/path///bar/",
+					RawPath: "/path/%2f/bar/",
+					Host:    "foo.com",
+				},
+				Header:     http.Header{},
+				Proto:      "HTTP/1.1",
+				ProtoMajor: 1,
+				ProtoMinor: 1,
+				RemoteAddr: "192.0.2.1:1234",
+				RequestURI: "http://foo.com/path/%2f/bar/",
+			},
+			wantBody: "",
+		},
+
+		// GET with full https URL:
+		2: {
+			method: "GET",
+			uri:    "https://foo.com/path/",
+			body:   nil,
+			want: &http.Request{
+				Method: "GET",
+				Host:   "foo.com",
+				URL: &url.URL{
+					Scheme: "https",
+					Path:   "/path/",
+					Host:   "foo.com",
+				},
+				Header:     http.Header{},
+				Proto:      "HTTP/1.1",
+				ProtoMajor: 1,
+				ProtoMinor: 1,
+				RemoteAddr: "192.0.2.1:1234",
+				RequestURI: "https://foo.com/path/",
+				TLS: &tls.ConnectionState{
+					Version:           tls.VersionTLS12,
+					HandshakeComplete: true,
+					ServerName:        "foo.com",
+				},
+			},
+			wantBody: "",
+		},
+
+		// Post with known length
+		3: {
+			method: "POST",
+			uri:    "/",
+			body:   strings.NewReader("foo"),
+			want: &http.Request{
+				Method:        "POST",
+				Host:          "example.com",
+				URL:           &url.URL{Path: "/"},
+				Header:        http.Header{},
+				Proto:         "HTTP/1.1",
+				ContentLength: 3,
+				ProtoMajor:    1,
+				ProtoMinor:    1,
+				RemoteAddr:    "192.0.2.1:1234",
+				RequestURI:    "/",
+			},
+			wantBody: "foo",
+		},
+
+		// Post with unknown length
+		4: {
+			method: "POST",
+			uri:    "/",
+			body:   struct{ io.Reader }{strings.NewReader("foo")},
+			want: &http.Request{
+				Method:        "POST",
+				Host:          "example.com",
+				URL:           &url.URL{Path: "/"},
+				Header:        http.Header{},
+				Proto:         "HTTP/1.1",
+				ContentLength: -1,
+				ProtoMajor:    1,
+				ProtoMinor:    1,
+				RemoteAddr:    "192.0.2.1:1234",
+				RequestURI:    "/",
+			},
+			wantBody: "foo",
+		},
+
+		// OPTIONS *
+		5: {
+			method: "OPTIONS",
+			uri:    "*",
+			want: &http.Request{
+				Method:     "OPTIONS",
+				Host:       "example.com",
+				URL:        &url.URL{Path: "*"},
+				Header:     http.Header{},
+				Proto:      "HTTP/1.1",
+				ProtoMajor: 1,
+				ProtoMinor: 1,
+				RemoteAddr: "192.0.2.1:1234",
+				RequestURI: "*",
+			},
+		},
+	}
+	for i, tt := range tests {
+		got := NewRequest(tt.method, tt.uri, tt.body)
+		slurp, err := ioutil.ReadAll(got.Body)
+		if err != nil {
+			t.Errorf("%d. ReadAll: %v", i, err)
+		}
+		if string(slurp) != tt.wantBody {
+			t.Errorf("%d. Body = %q; want %q", i, slurp, tt.wantBody)
+		}
+		got.Body = nil // before DeepEqual
+		if !reflect.DeepEqual(got.URL, tt.want.URL) {
+			t.Errorf("%d. Request.URL mismatch:\n got: %#v\nwant: %#v", i, got.URL, tt.want.URL)
+		}
+		if !reflect.DeepEqual(got.Header, tt.want.Header) {
+			t.Errorf("%d. Request.Header mismatch:\n got: %#v\nwant: %#v", i, got.Header, tt.want.Header)
+		}
+		if !reflect.DeepEqual(got.TLS, tt.want.TLS) {
+			t.Errorf("%d. Request.TLS mismatch:\n got: %#v\nwant: %#v", i, got.TLS, tt.want.TLS)
+		}
+		if !reflect.DeepEqual(got, tt.want) {
+			t.Errorf("%d. Request mismatch:\n got: %#v\nwant: %#v", i, got, tt.want)
+		}
+	}
+}
diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go
index 7c51af1..0ad26a3 100644
--- a/src/net/http/httptest/recorder.go
+++ b/src/net/http/httptest/recorder.go
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package httptest provides utilities for HTTP testing.
 package httptest
 
 import (
 	"bytes"
+	"io/ioutil"
 	"net/http"
 )
 
@@ -18,6 +18,8 @@ type ResponseRecorder struct {
 	Body      *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
 	Flushed   bool
 
+	result      *http.Response // cache of Result's return value
+	snapHeader  http.Header    // snapshot of HeaderMap at first Write
 	wroteHeader bool
 }
 
@@ -59,16 +61,15 @@ func (rw *ResponseRecorder) writeHeader(b []byte, str string) {
 		str = str[:512]
 	}
 
-	_, hasType := rw.HeaderMap["Content-Type"]
-	hasTE := rw.HeaderMap.Get("Transfer-Encoding") != ""
+	m := rw.Header()
+
+	_, hasType := m["Content-Type"]
+	hasTE := m.Get("Transfer-Encoding") != ""
 	if !hasType && !hasTE {
 		if b == nil {
 			b = []byte(str)
 		}
-		if rw.HeaderMap == nil {
-			rw.HeaderMap = make(http.Header)
-		}
-		rw.HeaderMap.Set("Content-Type", http.DetectContentType(b))
+		m.Set("Content-Type", http.DetectContentType(b))
 	}
 
 	rw.WriteHeader(200)
@@ -92,12 +93,28 @@ func (rw *ResponseRecorder) WriteString(str string) (int, error) {
 	return len(str), nil
 }
 
-// WriteHeader sets rw.Code.
+// WriteHeader sets rw.Code. After it is called, changing rw.Header
+// will not affect rw.HeaderMap.
 func (rw *ResponseRecorder) WriteHeader(code int) {
-	if !rw.wroteHeader {
-		rw.Code = code
-		rw.wroteHeader = true
+	if rw.wroteHeader {
+		return
+	}
+	rw.Code = code
+	rw.wroteHeader = true
+	if rw.HeaderMap == nil {
+		rw.HeaderMap = make(http.Header)
 	}
+	rw.snapHeader = cloneHeader(rw.HeaderMap)
+}
+
+func cloneHeader(h http.Header) http.Header {
+	h2 := make(http.Header, len(h))
+	for k, vv := range h {
+		vv2 := make([]string, len(vv))
+		copy(vv2, vv)
+		h2[k] = vv2
+	}
+	return h2
 }
 
 // Flush sets rw.Flushed to true.
@@ -107,3 +124,62 @@ func (rw *ResponseRecorder) Flush() {
 	}
 	rw.Flushed = true
 }
+
+// Result returns the response generated by the handler.
+//
+// The returned Response will have at least its StatusCode,
+// Header, Body, and optionally Trailer populated.
+// More fields may be populated in the future, so callers should
+// not DeepEqual the result in tests.
+//
+// The Response.Header is a snapshot of the headers at the time of the
+// first write call, or at the time of this call, if the handler never
+// did a write.
+//
+// Result must only be called after the handler has finished running.
+func (rw *ResponseRecorder) Result() *http.Response {
+	if rw.result != nil {
+		return rw.result
+	}
+	if rw.snapHeader == nil {
+		rw.snapHeader = cloneHeader(rw.HeaderMap)
+	}
+	res := &http.Response{
+		Proto:      "HTTP/1.1",
+		ProtoMajor: 1,
+		ProtoMinor: 1,
+		StatusCode: rw.Code,
+		Header:     rw.snapHeader,
+	}
+	rw.result = res
+	if res.StatusCode == 0 {
+		res.StatusCode = 200
+	}
+	res.Status = http.StatusText(res.StatusCode)
+	if rw.Body != nil {
+		res.Body = ioutil.NopCloser(bytes.NewReader(rw.Body.Bytes()))
+	}
+
+	if trailers, ok := rw.snapHeader["Trailer"]; ok {
+		res.Trailer = make(http.Header, len(trailers))
+		for _, k := range trailers {
+			// TODO: use http2.ValidTrailerHeader, but we can't
+			// get at it easily because it's bundled into net/http
+			// unexported. This is good enough for now:
+			switch k {
+			case "Transfer-Encoding", "Content-Length", "Trailer":
+				// Ignore since forbidden by RFC 2616 14.40.
+				continue
+			}
+			k = http.CanonicalHeaderKey(k)
+			vv, ok := rw.HeaderMap[k]
+			if !ok {
+				continue
+			}
+			vv2 := make([]string, len(vv))
+			copy(vv2, vv)
+			res.Trailer[k] = vv2
+		}
+	}
+	return res
+}
diff --git a/src/net/http/httptest/recorder_test.go b/src/net/http/httptest/recorder_test.go
index c29b6d4..d4e7137 100644
--- a/src/net/http/httptest/recorder_test.go
+++ b/src/net/http/httptest/recorder_test.go
@@ -23,6 +23,14 @@ func TestRecorder(t *testing.T) {
 			return nil
 		}
 	}
+	hasResultStatus := func(wantCode int) checkFunc {
+		return func(rec *ResponseRecorder) error {
+			if rec.Result().StatusCode != wantCode {
+				return fmt.Errorf("Result().StatusCode = %d; want %d", rec.Result().StatusCode, wantCode)
+			}
+			return nil
+		}
+	}
 	hasContents := func(want string) checkFunc {
 		return func(rec *ResponseRecorder) error {
 			if rec.Body.String() != want {
@@ -39,10 +47,49 @@ func TestRecorder(t *testing.T) {
 			return nil
 		}
 	}
-	hasHeader := func(key, want string) checkFunc {
+	hasOldHeader := func(key, want string) checkFunc {
 		return func(rec *ResponseRecorder) error {
 			if got := rec.HeaderMap.Get(key); got != want {
-				return fmt.Errorf("header %s = %q; want %q", key, got, want)
+				return fmt.Errorf("HeaderMap header %s = %q; want %q", key, got, want)
+			}
+			return nil
+		}
+	}
+	hasHeader := func(key, want string) checkFunc {
+		return func(rec *ResponseRecorder) error {
+			if got := rec.Result().Header.Get(key); got != want {
+				return fmt.Errorf("final header %s = %q; want %q", key, got, want)
+			}
+			return nil
+		}
+	}
+	hasNotHeaders := func(keys ...string) checkFunc {
+		return func(rec *ResponseRecorder) error {
+			for _, k := range keys {
+				v, ok := rec.Result().Header[http.CanonicalHeaderKey(k)]
+				if ok {
+					return fmt.Errorf("unexpected header %s with value %q", k, v)
+				}
+			}
+			return nil
+		}
+	}
+	hasTrailer := func(key, want string) checkFunc {
+		return func(rec *ResponseRecorder) error {
+			if got := rec.Result().Trailer.Get(key); got != want {
+				return fmt.Errorf("trailer %s = %q; want %q", key, got, want)
+			}
+			return nil
+		}
+	}
+	hasNotTrailers := func(keys ...string) checkFunc {
+		return func(rec *ResponseRecorder) error {
+			trailers := rec.Result().Trailer
+			for _, k := range keys {
+				_, ok := trailers[http.CanonicalHeaderKey(k)]
+				if ok {
+					return fmt.Errorf("unexpected trailer %s", k)
+				}
 			}
 			return nil
 		}
@@ -130,6 +177,73 @@ func TestRecorder(t *testing.T) {
 			},
 			check(hasHeader("Content-Type", "text/html; charset=utf-8")),
 		},
+		{
+			"Header is not changed after write",
+			func(w http.ResponseWriter, r *http.Request) {
+				hdr := w.Header()
+				hdr.Set("Key", "correct")
+				w.WriteHeader(200)
+				hdr.Set("Key", "incorrect")
+			},
+			check(hasHeader("Key", "correct")),
+		},
+		{
+			"Trailer headers are correctly recorded",
+			func(w http.ResponseWriter, r *http.Request) {
+				w.Header().Set("Non-Trailer", "correct")
+				w.Header().Set("Trailer", "Trailer-A")
+				w.Header().Add("Trailer", "Trailer-B")
+				w.Header().Add("Trailer", "Trailer-C")
+				io.WriteString(w, "<html>")
+				w.Header().Set("Non-Trailer", "incorrect")
+				w.Header().Set("Trailer-A", "valuea")
+				w.Header().Set("Trailer-C", "valuec")
+				w.Header().Set("Trailer-NotDeclared", "should be omitted")
+			},
+			check(
+				hasStatus(200),
+				hasHeader("Content-Type", "text/html; charset=utf-8"),
+				hasHeader("Non-Trailer", "correct"),
+				hasNotHeaders("Trailer-A", "Trailer-B", "Trailer-C", "Trailer-NotDeclared"),
+				hasTrailer("Trailer-A", "valuea"),
+				hasTrailer("Trailer-C", "valuec"),
+				hasNotTrailers("Non-Trailer", "Trailer-B", "Trailer-NotDeclared"),
+			),
+		},
+		{
+			"Header set without any write", // Issue 15560
+			func(w http.ResponseWriter, r *http.Request) {
+				w.Header().Set("X-Foo", "1")
+
+				// Simulate somebody using
+				// new(ResponseRecorder) instead of
+				// using the constructor which sets
+				// this to 200
+				w.(*ResponseRecorder).Code = 0
+			},
+			check(
+				hasOldHeader("X-Foo", "1"),
+				hasStatus(0),
+				hasHeader("X-Foo", "1"),
+				hasResultStatus(200),
+			),
+		},
+		{
+			"HeaderMap vs FinalHeaders", // more for Issue 15560
+			func(w http.ResponseWriter, r *http.Request) {
+				h := w.Header()
+				h.Set("X-Foo", "1")
+				w.Write([]byte("hi"))
+				h.Set("X-Foo", "2")
+				h.Set("X-Bar", "2")
+			},
+			check(
+				hasOldHeader("X-Foo", "2"),
+				hasOldHeader("X-Bar", "2"),
+				hasHeader("X-Foo", "1"),
+				hasNotHeaders("X-Bar"),
+			),
+		},
 	}
 	r, _ := http.NewRequest("GET", "http://foo.com/", nil)
 	for _, tt := range tests {
diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go
index a2573df..8608077 100644
--- a/src/net/http/httptest/server.go
+++ b/src/net/http/httptest/server.go
@@ -158,7 +158,7 @@ func (s *Server) Close() {
 			// previously-flaky tests) in the case of
 			// socket-late-binding races from the http Client
 			// dialing this server and then getting an idle
-			// connection before the dial completed.  There is thus
+			// connection before the dial completed. There is thus
 			// a connected connection in StateNew with no
 			// associated Request. We only close StateIdle and
 			// StateNew because they're not doing anything. It's
@@ -167,7 +167,7 @@ func (s *Server) Close() {
 			// few milliseconds wasn't liked (early versions of
 			// https://golang.org/cl/15151) so now we just
 			// forcefully close StateNew. The docs for Server.Close say
-			// we wait for "oustanding requests", so we don't close things
+			// we wait for "outstanding requests", so we don't close things
 			// in StateActive.
 			if st == http.StateIdle || st == http.StateNew {
 				s.closeConn(c)
@@ -202,12 +202,10 @@ func (s *Server) logCloseHangDebugInfo() {
 
 // CloseClientConnections closes any open HTTP connections to the test Server.
 func (s *Server) CloseClientConnections() {
-	var conns int
-	ch := make(chan bool)
-
 	s.mu.Lock()
+	nconn := len(s.conns)
+	ch := make(chan struct{}, nconn)
 	for c := range s.conns {
-		conns++
 		s.closeConnChan(c, ch)
 	}
 	s.mu.Unlock()
@@ -220,7 +218,7 @@ func (s *Server) CloseClientConnections() {
 	// in tests.
 	timer := time.NewTimer(5 * time.Second)
 	defer timer.Stop()
-	for i := 0; i < conns; i++ {
+	for i := 0; i < nconn; i++ {
 		select {
 		case <-ch:
 		case <-timer.C:
@@ -294,30 +292,20 @@ func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) }
 
 // closeConnChan is like closeConn, but takes an optional channel to receive a value
 // when the goroutine closing c is done.
-func (s *Server) closeConnChan(c net.Conn, done chan<- bool) {
+func (s *Server) closeConnChan(c net.Conn, done chan<- struct{}) {
 	if runtime.GOOS == "plan9" {
 		// Go's Plan 9 net package isn't great at unblocking reads when
-		// their underlying TCP connections are closed.  Don't trust
+		// their underlying TCP connections are closed. Don't trust
 		// that that the ConnState state machine will get to
 		// StateClosed. Instead, just go there directly. Plan 9 may leak
 		// resources if the syscall doesn't end up returning. Oh well.
 		s.forgetConn(c)
 	}
 
-	// Somewhere in the chaos of https://golang.org/cl/15151 we found that
-	// some types of conns were blocking in Close too long (or deadlocking?)
-	// and we had to call Close in a goroutine. I (bradfitz) forget what
-	// that was at this point, but I suspect it was *tls.Conns, which
-	// were later fixed in https://golang.org/cl/18572, so this goroutine
-	// is _probably_ unnecessary now. But it's too late in Go 1.6 too remove
-	// it with confidence.
-	// TODO(bradfitz): try to remove it for Go 1.7. (golang.org/issue/14291)
-	go func() {
-		c.Close()
-		if done != nil {
-			done <- true
-		}
-	}()
+	c.Close()
+	if done != nil {
+		done <- struct{}{}
+	}
 }
 
 // forgetConn removes c from the set of tracked conns and decrements it from the
diff --git a/src/net/http/httptest/server_test.go b/src/net/http/httptest/server_test.go
index c9606f2..d032c59 100644
--- a/src/net/http/httptest/server_test.go
+++ b/src/net/http/httptest/server_test.go
@@ -53,7 +53,7 @@ func TestGetAfterClose(t *testing.T) {
 	res, err = http.Get(ts.URL)
 	if err == nil {
 		body, _ := ioutil.ReadAll(res.Body)
-		t.Fatalf("Unexected response after close: %v, %v, %s", res.Status, res.Header, body)
+		t.Fatalf("Unexpected response after close: %v, %v, %s", res.Status, res.Header, body)
 	}
 }
 
@@ -95,6 +95,6 @@ func TestServerCloseClientConnections(t *testing.T) {
 	res, err := http.Get(s.URL)
 	if err == nil {
 		res.Body.Close()
-		t.Fatal("Unexpected response: %#v", res)
+		t.Fatalf("Unexpected response: %#v", res)
 	}
 }
diff --git a/src/net/http/httptrace/trace.go b/src/net/http/httptrace/trace.go
new file mode 100644
index 0000000..6f187a7
--- /dev/null
+++ b/src/net/http/httptrace/trace.go
@@ -0,0 +1,226 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.h
+
+// Package httptrace provides mechanisms to trace the events within
+// HTTP client requests.
+package httptrace
+
+import (
+	"context"
+	"internal/nettrace"
+	"net"
+	"reflect"
+	"time"
+)
+
+// unique type to prevent assignment.
+type clientEventContextKey struct{}
+
+// ContextClientTrace returns the ClientTrace associated with the
+// provided context. If none, it returns nil.
+func ContextClientTrace(ctx context.Context) *ClientTrace {
+	trace, _ := ctx.Value(clientEventContextKey{}).(*ClientTrace)
+	return trace
+}
+
+// WithClientTrace returns a new context based on the provided parent
+// ctx. HTTP client requests made with the returned context will use
+// the provided trace hooks, in addition to any previous hooks
+// registered with ctx. Any hooks defined in the provided trace will
+// be called first.
+func WithClientTrace(ctx context.Context, trace *ClientTrace) context.Context {
+	if trace == nil {
+		panic("nil trace")
+	}
+	old := ContextClientTrace(ctx)
+	trace.compose(old)
+
+	ctx = context.WithValue(ctx, clientEventContextKey{}, trace)
+	if trace.hasNetHooks() {
+		nt := &nettrace.Trace{
+			ConnectStart: trace.ConnectStart,
+			ConnectDone:  trace.ConnectDone,
+		}
+		if trace.DNSStart != nil {
+			nt.DNSStart = func(name string) {
+				trace.DNSStart(DNSStartInfo{Host: name})
+			}
+		}
+		if trace.DNSDone != nil {
+			nt.DNSDone = func(netIPs []interface{}, coalesced bool, err error) {
+				addrs := make([]net.IPAddr, len(netIPs))
+				for i, ip := range netIPs {
+					addrs[i] = ip.(net.IPAddr)
+				}
+				trace.DNSDone(DNSDoneInfo{
+					Addrs:     addrs,
+					Coalesced: coalesced,
+					Err:       err,
+				})
+			}
+		}
+		ctx = context.WithValue(ctx, nettrace.TraceKey{}, nt)
+	}
+	return ctx
+}
+
+// ClientTrace is a set of hooks to run at various stages of an HTTP
+// client request. Any particular hook may be nil. Functions may be
+// called concurrently from different goroutines, starting after the
+// call to Transport.RoundTrip and ending either when RoundTrip
+// returns an error, or when the Response.Body is closed.
+type ClientTrace struct {
+	// GetConn is called before a connection is created or
+	// retrieved from an idle pool. The hostPort is the
+	// "host:port" of the target or proxy. GetConn is called even
+	// if there's already an idle cached connection available.
+	GetConn func(hostPort string)
+
+	// GotConn is called after a successful connection is
+	// obtained. There is no hook for failure to obtain a
+	// connection; instead, use the error from
+	// Transport.RoundTrip.
+	GotConn func(GotConnInfo)
+
+	// PutIdleConn is called when the connection is returned to
+	// the idle pool. If err is nil, the connection was
+	// successfully returned to the idle pool. If err is non-nil,
+	// it describes why not. PutIdleConn is not called if
+	// connection reuse is disabled via Transport.DisableKeepAlives.
+	// PutIdleConn is called before the caller's Response.Body.Close
+	// call returns.
+	// For HTTP/2, this hook is not currently used.
+	PutIdleConn func(err error)
+
+	// GotFirstResponseByte is called when the first byte of the response
+	// headers is available.
+	GotFirstResponseByte func()
+
+	// Got100Continue is called if the server replies with a "100
+	// Continue" response.
+	Got100Continue func()
+
+	// DNSStart is called when a DNS lookup begins.
+	DNSStart func(DNSStartInfo)
+
+	// DNSDone is called when a DNS lookup ends.
+	DNSDone func(DNSDoneInfo)
+
+	// ConnectStart is called when a new connection's Dial begins.
+	// If net.Dialer.DualStack (IPv6 "Happy Eyeballs") support is
+	// enabled, this may be called multiple times.
+	ConnectStart func(network, addr string)
+
+	// ConnectDone is called when a new connection's Dial
+	// completes. The provided err indicates whether the
+	// connection completedly successfully.
+	// If net.Dialer.DualStack ("Happy Eyeballs") support is
+	// enabled, this may be called multiple times.
+	ConnectDone func(network, addr string, err error)
+
+	// WroteHeaders is called after the Transport has written
+	// the request headers.
+	WroteHeaders func()
+
+	// Wait100Continue is called if the Request specified
+	// "Expected: 100-continue" and the Transport has written the
+	// request headers but is waiting for "100 Continue" from the
+	// server before writing the request body.
+	Wait100Continue func()
+
+	// WroteRequest is called with the result of writing the
+	// request and any body.
+	WroteRequest func(WroteRequestInfo)
+}
+
+// WroteRequestInfo contains information provided to the WroteRequest
+// hook.
+type WroteRequestInfo struct {
+	// Err is any error encountered while writing the Request.
+	Err error
+}
+
+// compose modifies t such that it respects the previously-registered hooks in old,
+// subject to the composition policy requested in t.Compose.
+func (t *ClientTrace) compose(old *ClientTrace) {
+	if old == nil {
+		return
+	}
+	tv := reflect.ValueOf(t).Elem()
+	ov := reflect.ValueOf(old).Elem()
+	structType := tv.Type()
+	for i := 0; i < structType.NumField(); i++ {
+		tf := tv.Field(i)
+		hookType := tf.Type()
+		if hookType.Kind() != reflect.Func {
+			continue
+		}
+		of := ov.Field(i)
+		if of.IsNil() {
+			continue
+		}
+		if tf.IsNil() {
+			tf.Set(of)
+			continue
+		}
+
+		// Make a copy of tf for tf to call. (Otherwise it
+		// creates a recursive call cycle and stack overflows)
+		tfCopy := reflect.ValueOf(tf.Interface())
+
+		// We need to call both tf and of in some order.
+		newFunc := reflect.MakeFunc(hookType, func(args []reflect.Value) []reflect.Value {
+			tfCopy.Call(args)
+			return of.Call(args)
+		})
+		tv.Field(i).Set(newFunc)
+	}
+}
+
+// DNSStartInfo contains information about a DNS request.
+type DNSStartInfo struct {
+	Host string
+}
+
+// DNSDoneInfo contains information about the results of a DNS lookup.
+type DNSDoneInfo struct {
+	// Addrs are the IPv4 and/or IPv6 addresses found in the DNS
+	// lookup. The contents of the slice should not be mutated.
+	Addrs []net.IPAddr
+
+	// Err is any error that occurred during the DNS lookup.
+	Err error
+
+	// Coalesced is whether the Addrs were shared with another
+	// caller who was doing the same DNS lookup concurrently.
+	Coalesced bool
+}
+
+func (t *ClientTrace) hasNetHooks() bool {
+	if t == nil {
+		return false
+	}
+	return t.DNSStart != nil || t.DNSDone != nil || t.ConnectStart != nil || t.ConnectDone != nil
+}
+
+// GotConnInfo is the argument to the ClientTrace.GotConn function and
+// contains information about the obtained connection.
+type GotConnInfo struct {
+	// Conn is the connection that was obtained. It is owned by
+	// the http.Transport and should not be read, written or
+	// closed by users of ClientTrace.
+	Conn net.Conn
+
+	// Reused is whether this connection has been previously
+	// used for another HTTP request.
+	Reused bool
+
+	// WasIdle is whether this connection was obtained from an
+	// idle pool.
+	WasIdle bool
+
+	// IdleTime reports how long the connection was previously
+	// idle, if WasIdle is true.
+	IdleTime time.Duration
+}
diff --git a/src/net/http/httptrace/trace_test.go b/src/net/http/httptrace/trace_test.go
new file mode 100644
index 0000000..c7eaed8
--- /dev/null
+++ b/src/net/http/httptrace/trace_test.go
@@ -0,0 +1,62 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.h
+
+package httptrace
+
+import (
+	"bytes"
+	"testing"
+)
+
+func TestCompose(t *testing.T) {
+	var buf bytes.Buffer
+	var testNum int
+
+	connectStart := func(b byte) func(network, addr string) {
+		return func(network, addr string) {
+			if addr != "addr" {
+				t.Errorf(`%d. args for %q case = %q, %q; want addr of "addr"`, testNum, b, network, addr)
+			}
+			buf.WriteByte(b)
+		}
+	}
+
+	tests := [...]struct {
+		trace, old *ClientTrace
+		want       string
+	}{
+		0: {
+			want: "T",
+			trace: &ClientTrace{
+				ConnectStart: connectStart('T'),
+			},
+		},
+		1: {
+			want: "TO",
+			trace: &ClientTrace{
+				ConnectStart: connectStart('T'),
+			},
+			old: &ClientTrace{ConnectStart: connectStart('O')},
+		},
+		2: {
+			want:  "O",
+			trace: &ClientTrace{},
+			old:   &ClientTrace{ConnectStart: connectStart('O')},
+		},
+	}
+	for i, tt := range tests {
+		testNum = i
+		buf.Reset()
+
+		tr := *tt.trace
+		tr.compose(tt.old)
+		if tr.ConnectStart != nil {
+			tr.ConnectStart("net", "addr")
+		}
+		if got := buf.String(); got != tt.want {
+			t.Errorf("%d. got = %q; want %q", i, got, tt.want)
+		}
+	}
+
+}
diff --git a/src/net/http/httputil/dump.go b/src/net/http/httputil/dump.go
index e22cc66..1511681 100644
--- a/src/net/http/httputil/dump.go
+++ b/src/net/http/httputil/dump.go
@@ -128,7 +128,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
 
 	// If we used a dummy body above, remove it now.
 	// TODO: if the req.ContentLength is large, we allocate memory
-	// unnecessarily just to slice it off here.  But this is just
+	// unnecessarily just to slice it off here. But this is just
 	// a debug function, so this is acceptable for now. We could
 	// discard the body earlier if this matters.
 	if dummyBody {
@@ -163,18 +163,10 @@ func valueOrDefault(value, def string) string {
 
 var reqWriteExcludeHeaderDump = map[string]bool{
 	"Host":              true, // not in Header map anyway
-	"Content-Length":    true,
 	"Transfer-Encoding": true,
 	"Trailer":           true,
 }
 
-// dumpAsReceived writes req to w in the form as it was received, or
-// at least as accurately as possible from the information retained in
-// the request.
-func dumpAsReceived(req *http.Request, w io.Writer) error {
-	return nil
-}
-
 // DumpRequest returns the given request in its HTTP/1.x wire
 // representation. It should only be used by servers to debug client
 // requests. The returned representation is an approximation only;
@@ -191,7 +183,8 @@ func dumpAsReceived(req *http.Request, w io.Writer) error {
 //
 // The documentation for http.Request.Write details which fields
 // of req are included in the dump.
-func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
+func DumpRequest(req *http.Request, body bool) ([]byte, error) {
+	var err error
 	save := req.Body
 	if !body || req.Body == nil {
 		req.Body = nil
@@ -239,7 +232,7 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
 
 	err = req.Header.WriteSubset(&b, reqWriteExcludeHeaderDump)
 	if err != nil {
-		return
+		return nil, err
 	}
 
 	io.WriteString(&b, "\r\n")
@@ -258,35 +251,42 @@ func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
 
 	req.Body = save
 	if err != nil {
-		return
+		return nil, err
 	}
-	dump = b.Bytes()
-	return
+	return b.Bytes(), nil
 }
 
-// errNoBody is a sentinel error value used by failureToReadBody so we can detect
-// that the lack of body was intentional.
+// errNoBody is a sentinel error value used by failureToReadBody so we
+// can detect that the lack of body was intentional.
 var errNoBody = errors.New("sentinel error value")
 
 // failureToReadBody is a io.ReadCloser that just returns errNoBody on
-// Read.  It's swapped in when we don't actually want to consume the
-// body, but need a non-nil one, and want to distinguish the error
-// from reading the dummy body.
+// Read. It's swapped in when we don't actually want to consume
+// the body, but need a non-nil one, and want to distinguish the
+// error from reading the dummy body.
 type failureToReadBody struct{}
 
 func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody }
 func (failureToReadBody) Close() error             { return nil }
 
+// emptyBody is an instance of empty reader.
 var emptyBody = ioutil.NopCloser(strings.NewReader(""))
 
 // DumpResponse is like DumpRequest but dumps a response.
-func DumpResponse(resp *http.Response, body bool) (dump []byte, err error) {
+func DumpResponse(resp *http.Response, body bool) ([]byte, error) {
 	var b bytes.Buffer
+	var err error
 	save := resp.Body
 	savecl := resp.ContentLength
 
 	if !body {
-		resp.Body = failureToReadBody{}
+		// For content length of zero. Make sure the body is an empty
+		// reader, instead of returning error through failureToReadBody{}.
+		if resp.ContentLength == 0 {
+			resp.Body = emptyBody
+		} else {
+			resp.Body = failureToReadBody{}
+		}
 	} else if resp.Body == nil {
 		resp.Body = emptyBody
 	} else {
diff --git a/src/net/http/httputil/dump_test.go b/src/net/http/httputil/dump_test.go
index 46bf521..2e980d3 100644
--- a/src/net/http/httputil/dump_test.go
+++ b/src/net/http/httputil/dump_test.go
@@ -122,6 +122,10 @@ var dumpTests = []dumpTest{
 				Host:   "post.tld",
 				Path:   "/",
 			},
+			Header: http.Header{
+				"Content-Length": []string{"8193"},
+			},
+
 			ContentLength: 8193,
 			ProtoMajor:    1,
 			ProtoMinor:    1,
@@ -135,6 +139,10 @@ var dumpTests = []dumpTest{
 			"Content-Length: 8193\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n" +
 			strings.Repeat("a", 8193),
+		WantDump: "POST / HTTP/1.1\r\n" +
+			"Host: post.tld\r\n" +
+			"Content-Length: 8193\r\n\r\n" +
+			strings.Repeat("a", 8193),
 	},
 
 	{
@@ -144,6 +152,38 @@ var dumpTests = []dumpTest{
 		WantDump: "GET http://foo.com/ HTTP/1.1\r\n" +
 			"User-Agent: blah\r\n\r\n",
 	},
+
+	// Issue #7215. DumpRequest should return the "Content-Length" when set
+	{
+		Req: *mustReadRequest("POST /v2/api/?login HTTP/1.1\r\n" +
+			"Host: passport.myhost.com\r\n" +
+			"Content-Length: 3\r\n" +
+			"\r\nkey1=name1&key2=name2"),
+		WantDump: "POST /v2/api/?login HTTP/1.1\r\n" +
+			"Host: passport.myhost.com\r\n" +
+			"Content-Length: 3\r\n" +
+			"\r\nkey",
+	},
+
+	// Issue #7215. DumpRequest should return the "Content-Length" in ReadRequest
+	{
+		Req: *mustReadRequest("POST /v2/api/?login HTTP/1.1\r\n" +
+			"Host: passport.myhost.com\r\n" +
+			"Content-Length: 0\r\n" +
+			"\r\nkey1=name1&key2=name2"),
+		WantDump: "POST /v2/api/?login HTTP/1.1\r\n" +
+			"Host: passport.myhost.com\r\n" +
+			"Content-Length: 0\r\n\r\n",
+	},
+
+	// Issue #7215. DumpRequest should not return the "Content-Length" if unset
+	{
+		Req: *mustReadRequest("POST /v2/api/?login HTTP/1.1\r\n" +
+			"Host: passport.myhost.com\r\n" +
+			"\r\nkey1=name1&key2=name2"),
+		WantDump: "POST /v2/api/?login HTTP/1.1\r\n" +
+			"Host: passport.myhost.com\r\n\r\n",
+	},
 }
 
 func TestDumpRequest(t *testing.T) {
@@ -288,6 +328,27 @@ Transfer-Encoding: chunked
 foo
 0`,
 	},
+	{
+		res: &http.Response{
+			Status:        "200 OK",
+			StatusCode:    200,
+			Proto:         "HTTP/1.1",
+			ProtoMajor:    1,
+			ProtoMinor:    1,
+			ContentLength: 0,
+			Header: http.Header{
+				// To verify if headers are not filtered out.
+				"Foo1": []string{"Bar1"},
+				"Foo2": []string{"Bar2"},
+			},
+			Body: nil,
+		},
+		body: false, // to verify we see 0, not empty.
+		want: `HTTP/1.1 200 OK
+Foo1: Bar1
+Foo2: Bar2
+Content-Length: 0`,
+	},
 }
 
 func TestDumpResponse(t *testing.T) {
diff --git a/src/net/http/httputil/example_test.go b/src/net/http/httputil/example_test.go
index f856135..6191603 100644
--- a/src/net/http/httputil/example_test.go
+++ b/src/net/http/httputil/example_test.go
@@ -47,7 +47,7 @@ func ExampleDumpRequest() {
 	fmt.Printf("%s", b)
 
 	// Output:
-	// "POST / HTTP/1.1\r\nHost: www.example.org\r\nAccept-Encoding: gzip\r\nUser-Agent: Go-http-client/1.1\r\n\r\nGo is a general-purpose language designed with systems programming in mind."
+	// "POST / HTTP/1.1\r\nHost: www.example.org\r\nAccept-Encoding: gzip\r\nContent-Length: 75\r\nUser-Agent: Go-http-client/1.1\r\n\r\nGo is a general-purpose language designed with systems programming in mind."
 }
 
 func ExampleDumpRequestOut() {
diff --git a/src/net/http/httputil/persist.go b/src/net/http/httputil/persist.go
index 987bcc9..87ddd52 100644
--- a/src/net/http/httputil/persist.go
+++ b/src/net/http/httputil/persist.go
@@ -24,17 +24,13 @@ var (
 // ErrPersistEOF (above) reports that the remote side is closed.
 var errClosed = errors.New("i/o operation on closed connection")
 
-// A ServerConn reads requests and sends responses over an underlying
-// connection, until the HTTP keepalive logic commands an end. ServerConn
-// also allows hijacking the underlying connection by calling Hijack
-// to regain control over the connection. ServerConn supports pipe-lining,
-// i.e. requests can be read out of sync (but in the same order) while the
-// respective responses are sent.
+// ServerConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
 //
-// ServerConn is low-level and old. Applications should instead use Server
-// in the net/http package.
+// Deprecated: Use the Server in package net/http instead.
 type ServerConn struct {
-	lk              sync.Mutex // read-write protects the following fields
+	mu              sync.Mutex // read-write protects the following fields
 	c               net.Conn
 	r               *bufio.Reader
 	re, we          error // read/write errors
@@ -45,11 +41,11 @@ type ServerConn struct {
 	pipe textproto.Pipeline
 }
 
-// NewServerConn returns a new ServerConn reading and writing c. If r is not
-// nil, it is the buffer to use when reading c.
+// NewServerConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
 //
-// ServerConn is low-level and old. Applications should instead use Server
-// in the net/http package.
+// Deprecated: Use the Server in package net/http instead.
 func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
 	if r == nil {
 		r = bufio.NewReader(c)
@@ -61,17 +57,17 @@ func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn {
 // as the read-side bufio which may have some left over data. Hijack may be
 // called before Read has signaled the end of the keep-alive logic. The user
 // should not call Hijack while Read or Write is in progress.
-func (sc *ServerConn) Hijack() (c net.Conn, r *bufio.Reader) {
-	sc.lk.Lock()
-	defer sc.lk.Unlock()
-	c = sc.c
-	r = sc.r
+func (sc *ServerConn) Hijack() (net.Conn, *bufio.Reader) {
+	sc.mu.Lock()
+	defer sc.mu.Unlock()
+	c := sc.c
+	r := sc.r
 	sc.c = nil
 	sc.r = nil
-	return
+	return c, r
 }
 
-// Close calls Hijack and then also closes the underlying connection
+// Close calls Hijack and then also closes the underlying connection.
 func (sc *ServerConn) Close() error {
 	c, _ := sc.Hijack()
 	if c != nil {
@@ -84,7 +80,9 @@ func (sc *ServerConn) Close() error {
 // it is gracefully determined that there are no more requests (e.g. after the
 // first request on an HTTP/1.0 connection, or after a Connection:close on a
 // HTTP/1.1 connection).
-func (sc *ServerConn) Read() (req *http.Request, err error) {
+func (sc *ServerConn) Read() (*http.Request, error) {
+	var req *http.Request
+	var err error
 
 	// Ensure ordered execution of Reads and Writes
 	id := sc.pipe.Next()
@@ -96,29 +94,29 @@ func (sc *ServerConn) Read() (req *http.Request, err error) {
 			sc.pipe.EndResponse(id)
 		} else {
 			// Remember the pipeline id of this request
-			sc.lk.Lock()
+			sc.mu.Lock()
 			sc.pipereq[req] = id
-			sc.lk.Unlock()
+			sc.mu.Unlock()
 		}
 	}()
 
-	sc.lk.Lock()
+	sc.mu.Lock()
 	if sc.we != nil { // no point receiving if write-side broken or closed
-		defer sc.lk.Unlock()
+		defer sc.mu.Unlock()
 		return nil, sc.we
 	}
 	if sc.re != nil {
-		defer sc.lk.Unlock()
+		defer sc.mu.Unlock()
 		return nil, sc.re
 	}
 	if sc.r == nil { // connection closed by user in the meantime
-		defer sc.lk.Unlock()
+		defer sc.mu.Unlock()
 		return nil, errClosed
 	}
 	r := sc.r
 	lastbody := sc.lastbody
 	sc.lastbody = nil
-	sc.lk.Unlock()
+	sc.mu.Unlock()
 
 	// Make sure body is fully consumed, even if user does not call body.Close
 	if lastbody != nil {
@@ -127,16 +125,16 @@ func (sc *ServerConn) Read() (req *http.Request, err error) {
 		// returned.
 		err = lastbody.Close()
 		if err != nil {
-			sc.lk.Lock()
-			defer sc.lk.Unlock()
+			sc.mu.Lock()
+			defer sc.mu.Unlock()
 			sc.re = err
 			return nil, err
 		}
 	}
 
 	req, err = http.ReadRequest(r)
-	sc.lk.Lock()
-	defer sc.lk.Unlock()
+	sc.mu.Lock()
+	defer sc.mu.Unlock()
 	if err != nil {
 		if err == io.ErrUnexpectedEOF {
 			// A close from the opposing client is treated as a
@@ -161,8 +159,8 @@ func (sc *ServerConn) Read() (req *http.Request, err error) {
 // Pending returns the number of unanswered requests
 // that have been received on the connection.
 func (sc *ServerConn) Pending() int {
-	sc.lk.Lock()
-	defer sc.lk.Unlock()
+	sc.mu.Lock()
+	defer sc.mu.Unlock()
 	return sc.nread - sc.nwritten
 }
 
@@ -172,31 +170,31 @@ func (sc *ServerConn) Pending() int {
 func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
 
 	// Retrieve the pipeline ID of this request/response pair
-	sc.lk.Lock()
+	sc.mu.Lock()
 	id, ok := sc.pipereq[req]
 	delete(sc.pipereq, req)
 	if !ok {
-		sc.lk.Unlock()
+		sc.mu.Unlock()
 		return ErrPipeline
 	}
-	sc.lk.Unlock()
+	sc.mu.Unlock()
 
 	// Ensure pipeline order
 	sc.pipe.StartResponse(id)
 	defer sc.pipe.EndResponse(id)
 
-	sc.lk.Lock()
+	sc.mu.Lock()
 	if sc.we != nil {
-		defer sc.lk.Unlock()
+		defer sc.mu.Unlock()
 		return sc.we
 	}
 	if sc.c == nil { // connection closed by user in the meantime
-		defer sc.lk.Unlock()
+		defer sc.mu.Unlock()
 		return ErrClosed
 	}
 	c := sc.c
 	if sc.nread <= sc.nwritten {
-		defer sc.lk.Unlock()
+		defer sc.mu.Unlock()
 		return errors.New("persist server pipe count")
 	}
 	if resp.Close {
@@ -205,11 +203,11 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
 		// before signaling.
 		sc.re = ErrPersistEOF
 	}
-	sc.lk.Unlock()
+	sc.mu.Unlock()
 
 	err := resp.Write(c)
-	sc.lk.Lock()
-	defer sc.lk.Unlock()
+	sc.mu.Lock()
+	defer sc.mu.Unlock()
 	if err != nil {
 		sc.we = err
 		return err
@@ -219,15 +217,13 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
 	return nil
 }
 
-// A ClientConn sends request and receives headers over an underlying
-// connection, while respecting the HTTP keepalive logic. ClientConn
-// supports hijacking the connection calling Hijack to
-// regain control of the underlying net.Conn and deal with it as desired.
+// ClientConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
 //
-// ClientConn is low-level and old. Applications should instead use
-// Client or Transport in the net/http package.
+// Deprecated: Use Client or Transport in package net/http instead.
 type ClientConn struct {
-	lk              sync.Mutex // read-write protects the following fields
+	mu              sync.Mutex // read-write protects the following fields
 	c               net.Conn
 	r               *bufio.Reader
 	re, we          error // read/write errors
@@ -239,11 +235,11 @@ type ClientConn struct {
 	writeReq func(*http.Request, io.Writer) error
 }
 
-// NewClientConn returns a new ClientConn reading and writing c.  If r is not
-// nil, it is the buffer to use when reading c.
+// NewClientConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
 //
-// ClientConn is low-level and old. Applications should use Client or
-// Transport in the net/http package.
+// Deprecated: Use the Client or Transport in package net/http instead.
 func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
 	if r == nil {
 		r = bufio.NewReader(c)
@@ -256,11 +252,11 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
 	}
 }
 
-// NewProxyClientConn works like NewClientConn but writes Requests
-// using Request's WriteProxy method.
+// NewProxyClientConn is an artifact of Go's early HTTP implementation.
+// It is low-level, old, and unused by Go's current HTTP stack.
+// We should have deleted it before Go 1.
 //
-// New code should not use NewProxyClientConn. See Client or
-// Transport in the net/http package instead.
+// Deprecated: Use the Client or Transport in package net/http instead.
 func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
 	cc := NewClientConn(c, r)
 	cc.writeReq = (*http.Request).WriteProxy
@@ -272,8 +268,8 @@ func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
 // called before the user or Read have signaled the end of the keep-alive
 // logic. The user should not call Hijack while Read or Write is in progress.
 func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
-	cc.lk.Lock()
-	defer cc.lk.Unlock()
+	cc.mu.Lock()
+	defer cc.mu.Unlock()
 	c = cc.c
 	r = cc.r
 	cc.c = nil
@@ -281,7 +277,7 @@ func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader) {
 	return
 }
 
-// Close calls Hijack and then also closes the underlying connection
+// Close calls Hijack and then also closes the underlying connection.
 func (cc *ClientConn) Close() error {
 	c, _ := cc.Hijack()
 	if c != nil {
@@ -295,7 +291,8 @@ func (cc *ClientConn) Close() error {
 // keepalive connection is logically closed after this request and the opposing
 // server is informed. An ErrUnexpectedEOF indicates the remote closed the
 // underlying TCP connection, which is usually considered as graceful close.
-func (cc *ClientConn) Write(req *http.Request) (err error) {
+func (cc *ClientConn) Write(req *http.Request) error {
+	var err error
 
 	// Ensure ordered execution of Writes
 	id := cc.pipe.Next()
@@ -307,23 +304,23 @@ func (cc *ClientConn) Write(req *http.Request) (err error) {
 			cc.pipe.EndResponse(id)
 		} else {
 			// Remember the pipeline id of this request
-			cc.lk.Lock()
+			cc.mu.Lock()
 			cc.pipereq[req] = id
-			cc.lk.Unlock()
+			cc.mu.Unlock()
 		}
 	}()
 
-	cc.lk.Lock()
+	cc.mu.Lock()
 	if cc.re != nil { // no point sending if read-side closed or broken
-		defer cc.lk.Unlock()
+		defer cc.mu.Unlock()
 		return cc.re
 	}
 	if cc.we != nil {
-		defer cc.lk.Unlock()
+		defer cc.mu.Unlock()
 		return cc.we
 	}
 	if cc.c == nil { // connection closed by user in the meantime
-		defer cc.lk.Unlock()
+		defer cc.mu.Unlock()
 		return errClosed
 	}
 	c := cc.c
@@ -332,11 +329,11 @@ func (cc *ClientConn) Write(req *http.Request) (err error) {
 		// still might be some pipelined reads
 		cc.we = ErrPersistEOF
 	}
-	cc.lk.Unlock()
+	cc.mu.Unlock()
 
 	err = cc.writeReq(req, c)
-	cc.lk.Lock()
-	defer cc.lk.Unlock()
+	cc.mu.Lock()
+	defer cc.mu.Unlock()
 	if err != nil {
 		cc.we = err
 		return err
@@ -349,8 +346,8 @@ func (cc *ClientConn) Write(req *http.Request) (err error) {
 // Pending returns the number of unanswered requests
 // that have been sent on the connection.
 func (cc *ClientConn) Pending() int {
-	cc.lk.Lock()
-	defer cc.lk.Unlock()
+	cc.mu.Lock()
+	defer cc.mu.Unlock()
 	return cc.nwritten - cc.nread
 }
 
@@ -360,32 +357,32 @@ func (cc *ClientConn) Pending() int {
 // concurrently with Write, but not with another Read.
 func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
 	// Retrieve the pipeline ID of this request/response pair
-	cc.lk.Lock()
+	cc.mu.Lock()
 	id, ok := cc.pipereq[req]
 	delete(cc.pipereq, req)
 	if !ok {
-		cc.lk.Unlock()
+		cc.mu.Unlock()
 		return nil, ErrPipeline
 	}
-	cc.lk.Unlock()
+	cc.mu.Unlock()
 
 	// Ensure pipeline order
 	cc.pipe.StartResponse(id)
 	defer cc.pipe.EndResponse(id)
 
-	cc.lk.Lock()
+	cc.mu.Lock()
 	if cc.re != nil {
-		defer cc.lk.Unlock()
+		defer cc.mu.Unlock()
 		return nil, cc.re
 	}
 	if cc.r == nil { // connection closed by user in the meantime
-		defer cc.lk.Unlock()
+		defer cc.mu.Unlock()
 		return nil, errClosed
 	}
 	r := cc.r
 	lastbody := cc.lastbody
 	cc.lastbody = nil
-	cc.lk.Unlock()
+	cc.mu.Unlock()
 
 	// Make sure body is fully consumed, even if user does not call body.Close
 	if lastbody != nil {
@@ -394,16 +391,16 @@ func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
 		// returned.
 		err = lastbody.Close()
 		if err != nil {
-			cc.lk.Lock()
-			defer cc.lk.Unlock()
+			cc.mu.Lock()
+			defer cc.mu.Unlock()
 			cc.re = err
 			return nil, err
 		}
 	}
 
 	resp, err = http.ReadResponse(r, req)
-	cc.lk.Lock()
-	defer cc.lk.Unlock()
+	cc.mu.Lock()
+	defer cc.mu.Unlock()
 	if err != nil {
 		cc.re = err
 		return resp, err
@@ -420,10 +417,10 @@ func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) {
 }
 
 // Do is convenience method that writes a request and reads a response.
-func (cc *ClientConn) Do(req *http.Request) (resp *http.Response, err error) {
-	err = cc.Write(req)
+func (cc *ClientConn) Do(req *http.Request) (*http.Response, error) {
+	err := cc.Write(req)
 	if err != nil {
-		return
+		return nil, err
 	}
 	return cc.Read(req)
 }
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index 54411ca..49c120a 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -90,6 +90,10 @@ func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
 		} else {
 			req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
 		}
+		if _, ok := req.Header["User-Agent"]; !ok {
+			// explicitly disable User-Agent so it's not set to default value
+			req.Header.Set("User-Agent", "")
+		}
 	}
 	return &ReverseProxy{Director: director}
 }
@@ -180,9 +184,9 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	outreq.ProtoMinor = 1
 	outreq.Close = false
 
-	// Remove hop-by-hop headers to the backend.  Especially
+	// Remove hop-by-hop headers to the backend. Especially
 	// important is "Connection" because we want a persistent
-	// connection, regardless of what the client sent to us.  This
+	// connection, regardless of what the client sent to us. This
 	// is modifying the same underlying map from req (shallow
 	// copied above) so we only copy it if necessary.
 	copiedHeaders := false
@@ -210,7 +214,7 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	res, err := transport.RoundTrip(outreq)
 	if err != nil {
 		p.logf("http: proxy error: %v", err)
-		rw.WriteHeader(http.StatusInternalServerError)
+		rw.WriteHeader(http.StatusBadGateway)
 		return
 	}
 
@@ -285,13 +289,13 @@ type maxLatencyWriter struct {
 	dst     writeFlusher
 	latency time.Duration
 
-	lk   sync.Mutex // protects Write + Flush
+	mu   sync.Mutex // protects Write + Flush
 	done chan bool
 }
 
 func (m *maxLatencyWriter) Write(p []byte) (int, error) {
-	m.lk.Lock()
-	defer m.lk.Unlock()
+	m.mu.Lock()
+	defer m.mu.Unlock()
 	return m.dst.Write(p)
 }
 
@@ -306,9 +310,9 @@ func (m *maxLatencyWriter) flushLoop() {
 			}
 			return
 		case <-t.C:
-			m.lk.Lock()
+			m.mu.Lock()
 			m.dst.Flush()
-			m.lk.Unlock()
+			m.mu.Unlock()
 		}
 	}
 }
diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go
index 0849427..fe7cdb8 100644
--- a/src/net/http/httputil/reverseproxy_test.go
+++ b/src/net/http/httputil/reverseproxy_test.go
@@ -33,6 +33,11 @@ func TestReverseProxy(t *testing.T) {
 	const backendResponse = "I am the backend"
 	const backendStatus = 404
 	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.Method == "GET" && r.FormValue("mode") == "hangup" {
+			c, _, _ := w.(http.Hijacker).Hijack()
+			c.Close()
+			return
+		}
 		if len(r.TransferEncoding) > 0 {
 			t.Errorf("backend got unexpected TransferEncoding: %v", r.TransferEncoding)
 		}
@@ -69,6 +74,7 @@ func TestReverseProxy(t *testing.T) {
 		t.Fatal(err)
 	}
 	proxyHandler := NewSingleHostReverseProxy(backendURL)
+	proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
 	frontend := httptest.NewServer(proxyHandler)
 	defer frontend.Close()
 
@@ -113,6 +119,20 @@ func TestReverseProxy(t *testing.T) {
 	if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; g != e {
 		t.Errorf("Trailer(X-Trailer) = %q ; want %q", g, e)
 	}
+
+	// Test that a backend failing to be reached or one which doesn't return
+	// a response results in a StatusBadGateway.
+	getReq, _ = http.NewRequest("GET", frontend.URL+"/?mode=hangup", nil)
+	getReq.Close = true
+	res, err = http.DefaultClient.Do(getReq)
+	if err != nil {
+		t.Fatal(err)
+	}
+	res.Body.Close()
+	if res.StatusCode != http.StatusBadGateway {
+		t.Errorf("request to bad proxy = %v; want 502 StatusBadGateway", res.Status)
+	}
+
 }
 
 func TestXForwardedFor(t *testing.T) {
@@ -328,6 +348,49 @@ func TestNilBody(t *testing.T) {
 	}
 }
 
+// Issue 15524
+func TestUserAgentHeader(t *testing.T) {
+	const explicitUA = "explicit UA"
+	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if r.URL.Path == "/noua" {
+			if c := r.Header.Get("User-Agent"); c != "" {
+				t.Errorf("handler got non-empty User-Agent header %q", c)
+			}
+			return
+		}
+		if c := r.Header.Get("User-Agent"); c != explicitUA {
+			t.Errorf("handler got unexpected User-Agent header %q", c)
+		}
+	}))
+	defer backend.Close()
+	backendURL, err := url.Parse(backend.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	proxyHandler := NewSingleHostReverseProxy(backendURL)
+	proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
+	frontend := httptest.NewServer(proxyHandler)
+	defer frontend.Close()
+
+	getReq, _ := http.NewRequest("GET", frontend.URL, nil)
+	getReq.Header.Set("User-Agent", explicitUA)
+	getReq.Close = true
+	res, err := http.DefaultClient.Do(getReq)
+	if err != nil {
+		t.Fatalf("Get: %v", err)
+	}
+	res.Body.Close()
+
+	getReq, _ = http.NewRequest("GET", frontend.URL+"/noua", nil)
+	getReq.Header.Set("User-Agent", "")
+	getReq.Close = true
+	res, err = http.DefaultClient.Do(getReq)
+	if err != nil {
+		t.Fatalf("Get: %v", err)
+	}
+	res.Body.Close()
+}
+
 type bufferPool struct {
 	get func() []byte
 	put func([]byte)
diff --git a/src/net/http/internal/chunked_test.go b/src/net/http/internal/chunked_test.go
index a136dc9..9abe1ab 100644
--- a/src/net/http/internal/chunked_test.go
+++ b/src/net/http/internal/chunked_test.go
@@ -122,7 +122,7 @@ func TestChunkReaderAllocs(t *testing.T) {
 	byter := bytes.NewReader(buf.Bytes())
 	bufr := bufio.NewReader(byter)
 	mallocs := testing.AllocsPerRun(100, func() {
-		byter.Seek(0, 0)
+		byter.Seek(0, io.SeekStart)
 		bufr.Reset(byter)
 		r := NewChunkedReader(bufr)
 		n, err := io.ReadFull(r, readBuf)
diff --git a/src/net/http/lex.go b/src/net/http/lex.go
deleted file mode 100644
index 52b6481..0000000
--- a/src/net/http/lex.go
+++ /dev/null
@@ -1,183 +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 http
-
-import (
-	"strings"
-	"unicode/utf8"
-)
-
-// This file deals with lexical matters of HTTP
-
-var isTokenTable = [127]bool{
-	'!':  true,
-	'#':  true,
-	'$':  true,
-	'%':  true,
-	'&':  true,
-	'\'': true,
-	'*':  true,
-	'+':  true,
-	'-':  true,
-	'.':  true,
-	'0':  true,
-	'1':  true,
-	'2':  true,
-	'3':  true,
-	'4':  true,
-	'5':  true,
-	'6':  true,
-	'7':  true,
-	'8':  true,
-	'9':  true,
-	'A':  true,
-	'B':  true,
-	'C':  true,
-	'D':  true,
-	'E':  true,
-	'F':  true,
-	'G':  true,
-	'H':  true,
-	'I':  true,
-	'J':  true,
-	'K':  true,
-	'L':  true,
-	'M':  true,
-	'N':  true,
-	'O':  true,
-	'P':  true,
-	'Q':  true,
-	'R':  true,
-	'S':  true,
-	'T':  true,
-	'U':  true,
-	'W':  true,
-	'V':  true,
-	'X':  true,
-	'Y':  true,
-	'Z':  true,
-	'^':  true,
-	'_':  true,
-	'`':  true,
-	'a':  true,
-	'b':  true,
-	'c':  true,
-	'd':  true,
-	'e':  true,
-	'f':  true,
-	'g':  true,
-	'h':  true,
-	'i':  true,
-	'j':  true,
-	'k':  true,
-	'l':  true,
-	'm':  true,
-	'n':  true,
-	'o':  true,
-	'p':  true,
-	'q':  true,
-	'r':  true,
-	's':  true,
-	't':  true,
-	'u':  true,
-	'v':  true,
-	'w':  true,
-	'x':  true,
-	'y':  true,
-	'z':  true,
-	'|':  true,
-	'~':  true,
-}
-
-func isToken(r rune) bool {
-	i := int(r)
-	return i < len(isTokenTable) && isTokenTable[i]
-}
-
-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
-}
-
-// isLWS reports whether b is linear white space, according
-// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
-//      LWS            = [CRLF] 1*( SP | HT )
-func isLWS(b byte) bool { return b == ' ' || b == '\t' }
-
-// isCTL reports whether b is a control byte, according
-// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
-//      CTL            = <any US-ASCII control character
-//                       (octets 0 - 31) and DEL (127)>
-func isCTL(b byte) bool {
-	const del = 0x7f // a CTL
-	return b < ' ' || b == del
-}
diff --git a/src/net/http/lex_test.go b/src/net/http/lex_test.go
deleted file mode 100644
index 986fda1..0000000
--- a/src/net/http/lex_test.go
+++ /dev/null
@@ -1,101 +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 http
-
-import (
-	"testing"
-)
-
-func isChar(c rune) bool { return c <= 127 }
-
-func isCtl(c rune) bool { return c <= 31 || c == 127 }
-
-func isSeparator(c rune) bool {
-	switch c {
-	case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t':
-		return true
-	}
-	return false
-}
-
-func TestIsToken(t *testing.T) {
-	for i := 0; i <= 130; i++ {
-		r := rune(i)
-		expected := isChar(r) && !isCtl(r) && !isSeparator(r)
-		if isToken(r) != expected {
-			t.Errorf("isToken(0x%x) = %v", r, !expected)
-		}
-	}
-}
-
-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 299cd7b..aea6e12 100644
--- a/src/net/http/main_test.go
+++ b/src/net/http/main_test.go
@@ -5,7 +5,6 @@
 package http_test
 
 import (
-	"flag"
 	"fmt"
 	"net/http"
 	"os"
@@ -16,8 +15,6 @@ import (
 	"time"
 )
 
-var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
-
 func TestMain(m *testing.M) {
 	v := m.Run()
 	if v == 0 && goroutineLeaked() {
@@ -91,12 +88,6 @@ func setParallel(t *testing.T) {
 	}
 }
 
-func setFlaky(t *testing.T, issue int) {
-	if !*flaky {
-		t.Skipf("skipping known flaky test; see golang.org/issue/%d", issue)
-	}
-}
-
 func afterTest(t testing.TB) {
 	http.DefaultTransport.(*http.Transport).CloseIdleConnections()
 	if testing.Short() {
@@ -129,3 +120,17 @@ func afterTest(t testing.TB) {
 	}
 	t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks)
 }
+
+// waitCondition reports whether fn eventually returned true,
+// checking immediately and then every checkEvery amount,
+// until waitFor has elapsed, at which point it returns false.
+func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
+	deadline := time.Now().Add(waitFor)
+	for time.Now().Before(deadline) {
+		if fn() {
+			return true
+		}
+		time.Sleep(checkEvery)
+	}
+	return false
+}
diff --git a/src/net/http/method.go b/src/net/http/method.go
index b74f960..6f46155 100644
--- a/src/net/http/method.go
+++ b/src/net/http/method.go
@@ -12,7 +12,7 @@ const (
 	MethodHead    = "HEAD"
 	MethodPost    = "POST"
 	MethodPut     = "PUT"
-	MethodPatch   = "PATCH" // RFC 5741
+	MethodPatch   = "PATCH" // RFC 5789
 	MethodDelete  = "DELETE"
 	MethodConnect = "CONNECT"
 	MethodOptions = "OPTIONS"
diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go
index 63ff221..126e9ea 100644
--- a/src/net/http/pprof/pprof.go
+++ b/src/net/http/pprof/pprof.go
@@ -1,11 +1,9 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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 pprof serves via its HTTP server runtime profiling data
 // in the format expected by the pprof visualization tool.
-// For more information about pprof, see
-// http://code.google.com/p/google-perftools/.
 //
 // The package is typically only imported for the side effect of
 // registering its HTTP handlers.
@@ -15,7 +13,7 @@
 //	import _ "net/http/pprof"
 //
 // If your application is not already running an http server, you
-// need to start one.  Add "net/http" and "log" to your imports and
+// need to start one. Add "net/http" and "log" to your imports and
 // the following code to your main function:
 //
 // 	go func() {
@@ -30,7 +28,8 @@
 //
 //	go tool pprof http://localhost:6060/debug/pprof/profile
 //
-// Or to look at the goroutine blocking profile:
+// Or to look at the goroutine blocking profile, after calling
+// runtime.SetBlockProfileRate in your program:
 //
 //	go tool pprof http://localhost:6060/debug/pprof/block
 //
@@ -119,8 +118,8 @@ func Profile(w http.ResponseWriter, r *http.Request) {
 // 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, err := strconv.ParseFloat(r.FormValue("seconds"), 64)
+	if sec <= 0 || err != nil {
 		sec = 1
 	}
 
@@ -135,7 +134,7 @@ func Trace(w http.ResponseWriter, r *http.Request) {
 		fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
 		return
 	}
-	sleep(w, time.Duration(sec)*time.Second)
+	sleep(w, time.Duration(sec*float64(time.Second)))
 	trace.Stop()
 }
 
@@ -146,11 +145,11 @@ func Symbol(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 
 	// We have to read the whole POST body before
-	// writing any output.  Buffer the output here.
+	// writing any output. Buffer the output here.
 	var buf bytes.Buffer
 
 	// We don't know how many symbols we have, but we
-	// do have symbol information.  Pprof only cares whether
+	// do have symbol information. Pprof only cares whether
 	// this number is 0 (no symbols available) or > 0.
 	fmt.Fprintf(&buf, "num_symbols: 1\n")
 
diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go
index 60e2be4..4bf646b 100644
--- a/src/net/http/readrequest_test.go
+++ b/src/net/http/readrequest_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -380,6 +380,27 @@ var reqTests = []reqTest{
 		noTrailer,
 		noError,
 	},
+
+	// http2 client preface:
+	{
+		"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n",
+		&Request{
+			Method: "PRI",
+			URL: &url.URL{
+				Path: "*",
+			},
+			Header:        Header{},
+			Proto:         "HTTP/2.0",
+			ProtoMajor:    2,
+			ProtoMinor:    0,
+			RequestURI:    "*",
+			ContentLength: -1,
+			Close:         true,
+		},
+		noBody,
+		noTrailer,
+		noError,
+	},
 }
 
 func TestReadRequest(t *testing.T) {
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 8cdab02..dc55592 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -9,6 +9,7 @@ package http
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"crypto/tls"
 	"encoding/base64"
 	"errors"
@@ -17,6 +18,7 @@ import (
 	"io/ioutil"
 	"mime"
 	"mime/multipart"
+	"net/http/httptrace"
 	"net/textproto"
 	"net/url"
 	"strconv"
@@ -247,7 +249,52 @@ type Request struct {
 	// RoundTripper may support Cancel.
 	//
 	// For server requests, this field is not applicable.
+	//
+	// Deprecated: Use the Context and WithContext methods
+	// instead. If a Request's Cancel field and context are both
+	// set, it is undefined whether Cancel is respected.
 	Cancel <-chan struct{}
+
+	// Response is the redirect response which caused this request
+	// to be created. This field is only populated during client
+	// redirects.
+	Response *Response
+
+	// ctx is either the client or server context. It should only
+	// be modified via copying the whole Request using WithContext.
+	// It is unexported to prevent people from using Context wrong
+	// and mutating the contexts held by callers of the same request.
+	ctx context.Context
+}
+
+// Context returns the request's context. To change the context, use
+// WithContext.
+//
+// The returned context is always non-nil; it defaults to the
+// background context.
+//
+// For outgoing client requests, the context controls cancelation.
+//
+// For incoming server requests, the context is canceled when the
+// ServeHTTP method returns. For its associated values, see
+// ServerContextKey and LocalAddrContextKey.
+func (r *Request) Context() context.Context {
+	if r.ctx != nil {
+		return r.ctx
+	}
+	return context.Background()
+}
+
+// WithContext returns a shallow copy of r with its context changed
+// to ctx. The provided ctx must be non-nil.
+func (r *Request) WithContext(ctx context.Context) *Request {
+	if ctx == nil {
+		panic("nil context")
+	}
+	r2 := new(Request)
+	*r2 = *r
+	r2.ctx = ctx
+	return r2
 }
 
 // ProtoAtLeast reports whether the HTTP protocol used
@@ -279,8 +326,8 @@ func (r *Request) Cookie(name string) (*Cookie, error) {
 	return nil, ErrNoCookie
 }
 
-// AddCookie adds a cookie to the request.  Per RFC 6265 section 5.4,
-// AddCookie does not attach more than one Cookie header field.  That
+// AddCookie adds a cookie to the request. Per RFC 6265 section 5.4,
+// AddCookie does not attach more than one Cookie header field. That
 // means all cookies, if any, are written into the same line,
 // separated by semicolon.
 func (r *Request) AddCookie(c *Cookie) {
@@ -343,6 +390,12 @@ func (r *Request) multipartReader() (*multipart.Reader, error) {
 	return multipart.NewReader(r.Body, boundary), nil
 }
 
+// isH2Upgrade reports whether r represents the http2 "client preface"
+// magic string.
+func (r *Request) isH2Upgrade() bool {
+	return r.Method == "PRI" && len(r.Header) == 0 && r.URL.Path == "*" && r.Proto == "HTTP/2.0"
+}
+
 // Return value if nonempty, def otherwise.
 func valueOrDefault(value, def string) string {
 	if value != "" {
@@ -375,7 +428,7 @@ func (r *Request) Write(w io.Writer) error {
 }
 
 // WriteProxy is like Write but writes the request in the form
-// expected by an HTTP proxy.  In particular, WriteProxy writes the
+// expected by an HTTP proxy. In particular, WriteProxy writes the
 // initial Request-URI line of the request with an absolute URI, per
 // section 5.1.2 of RFC 2616, including the scheme and host.
 // In either case, WriteProxy also writes a Host header, using
@@ -390,7 +443,16 @@ var errMissingHost = errors.New("http: Request.Write on Request with no Host or
 
 // extraHeaders may be nil
 // waitForContinue may be nil
-func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitForContinue func() bool) error {
+func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitForContinue func() bool) (err error) {
+	trace := httptrace.ContextClientTrace(req.Context())
+	if trace != nil && trace.WroteRequest != nil {
+		defer func() {
+			trace.WroteRequest(httptrace.WroteRequestInfo{
+				Err: err,
+			})
+		}()
+	}
+
 	// Find the target host. Prefer the Host: header, but if that
 	// is not given, use the host from the request URL.
 	//
@@ -427,7 +489,7 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
 		w = bw
 	}
 
-	_, err := fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
+	_, err = fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri)
 	if err != nil {
 		return err
 	}
@@ -478,6 +540,10 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
 		return err
 	}
 
+	if trace != nil && trace.WroteHeaders != nil {
+		trace.WroteHeaders()
+	}
+
 	// Flush and wait for 100-continue if expected.
 	if waitForContinue != nil {
 		if bw, ok := w.(*bufio.Writer); ok {
@@ -486,7 +552,9 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
 				return err
 			}
 		}
-
+		if trace != nil && trace.Wait100Continue != nil {
+			trace.Wait100Continue()
+		}
 		if !waitForContinue() {
 			req.closeBody()
 			return nil
@@ -521,7 +589,7 @@ func cleanHost(in string) string {
 	return in
 }
 
-// removeZone removes IPv6 zone identifer from host.
+// removeZone removes IPv6 zone identifier from host.
 // E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
 func removeZone(host string) string {
 	if !strings.HasPrefix(host, "[") {
@@ -613,6 +681,8 @@ func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
 	if !ok && body != nil {
 		rc = ioutil.NopCloser(body)
 	}
+	// The host's colon:port should be normalized. See Issue 14836.
+	u.Host = removeEmptyPort(u.Host)
 	req := &Request{
 		Method:     method,
 		URL:        u,
@@ -704,7 +774,9 @@ func putTextprotoReader(r *textproto.Reader) {
 }
 
 // ReadRequest reads and parses an incoming request from b.
-func ReadRequest(b *bufio.Reader) (req *Request, err error) { return readRequest(b, deleteHostHeader) }
+func ReadRequest(b *bufio.Reader) (*Request, error) {
+	return readRequest(b, deleteHostHeader)
+}
 
 // Constants for readRequest's deleteHostHeader parameter.
 const (
@@ -768,13 +840,13 @@ func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err erro
 	}
 	req.Header = Header(mimeHeader)
 
-	// RFC2616: Must treat
+	// RFC 2616: Must treat
 	//	GET /index.html HTTP/1.1
 	//	Host: www.google.com
 	// and
 	//	GET http://www.google.com/index.html HTTP/1.1
 	//	Host: doesntmatter
-	// the same.  In the second case, any Host line is ignored.
+	// the same. In the second case, any Host line is ignored.
 	req.Host = req.URL.Host
 	if req.Host == "" {
 		req.Host = req.Header.get("Host")
@@ -792,6 +864,16 @@ func readRequest(b *bufio.Reader, deleteHostHeader bool) (req *Request, err erro
 		return nil, err
 	}
 
+	if req.isH2Upgrade() {
+		// Because it's neither chunked, nor declared:
+		req.ContentLength = -1
+
+		// We want to give handlers a chance to hijack the
+		// connection, but we need to prevent the Server from
+		// dealing with the connection further if it's not
+		// hijacked. Set Close to ensure that:
+		req.Close = true
+	}
 	return req, nil
 }
 
@@ -808,57 +890,56 @@ func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser {
 }
 
 type maxBytesReader struct {
-	w       ResponseWriter
-	r       io.ReadCloser // underlying reader
-	n       int64         // max bytes remaining
-	stopped bool
-	sawEOF  bool
+	w   ResponseWriter
+	r   io.ReadCloser // underlying reader
+	n   int64         // max bytes remaining
+	err error         // sticky error
 }
 
 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")
+	l.err = errors.New("http: request body too large")
+	return 0, l.err
 }
 
 func (l *maxBytesReader) Read(p []byte) (n int, err error) {
-	toRead := l.n
-	if l.n == 0 {
-		if l.sawEOF {
-			return l.tooLarge()
-		}
-		// 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 l.err != nil {
+		return 0, l.err
 	}
-	if int64(len(p)) > toRead {
-		p = p[:toRead]
+	if len(p) == 0 {
+		return 0, nil
+	}
+	// If they asked for a 32KB byte read but only 5 bytes are
+	// remaining, no need to read 32KB. 6 bytes will answer the
+	// question of the whether we hit the limit or go past it.
+	if int64(len(p)) > l.n+1 {
+		p = p[:l.n+1]
 	}
 	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
+
+	if int64(n) <= l.n {
+		l.n -= int64(n)
+		l.err = err
+		return n, err
 	}
-	l.n -= int64(n)
-	if l.n < 0 {
-		l.n = 0
+
+	n = int(l.n)
+	l.n = 0
+
+	// The server code and client code both use
+	// maxBytesReader. This "requestTooLarge" check is
+	// only used by the server code. To prevent binaries
+	// which only using the HTTP Client code (such as
+	// cmd/go) from also linking in the HTTP server, don't
+	// use a static type assertion to the server
+	// "*response" type. Check this interface instead:
+	type requestTooLarger interface {
+		requestTooLarge()
 	}
-	return
+	if res, ok := l.w.(requestTooLarger); ok {
+		res.requestTooLarge()
+	}
+	l.err = errors.New("http: request body too large")
+	return n, l.err
 }
 
 func (l *maxBytesReader) Close() error {
@@ -995,9 +1076,16 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
 	if err != nil {
 		return err
 	}
+
+	if r.PostForm == nil {
+		r.PostForm = make(url.Values)
+	}
 	for k, v := range f.Value {
 		r.Form[k] = append(r.Form[k], v...)
+		// r.PostForm should also be populated. See Issue 9305.
+		r.PostForm[k] = append(r.PostForm[k], v...)
 	}
+
 	r.MultipartForm = f
 
 	return nil
@@ -1086,92 +1174,3 @@ func (r *Request) isReplayable() bool {
 	}
 	return false
 }
-
-func validHostHeader(h string) bool {
-	// The latests spec is actually this:
-	//
-	// http://tools.ietf.org/html/rfc7230#section-5.4
-	//     Host = uri-host [ ":" port ]
-	//
-	// Where uri-host is:
-	//     http://tools.ietf.org/html/rfc3986#section-3.2.2
-	//
-	// But we're going to be much more lenient for now and just
-	// search for any byte that's not a valid byte in any of those
-	// expressions.
-	for i := 0; i < len(h); i++ {
-		if !validHostByte[h[i]] {
-			return false
-		}
-	}
-	return true
-}
-
-// See the validHostHeader comment.
-var validHostByte = [256]bool{
-	'0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
-	'8': true, '9': true,
-
-	'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
-	'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
-	'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
-	'y': true, 'z': true,
-
-	'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
-	'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
-	'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
-	'Y': true, 'Z': true,
-
-	'!':  true, // sub-delims
-	'$':  true, // sub-delims
-	'%':  true, // pct-encoded (and used in IPv6 zones)
-	'&':  true, // sub-delims
-	'(':  true, // sub-delims
-	')':  true, // sub-delims
-	'*':  true, // sub-delims
-	'+':  true, // sub-delims
-	',':  true, // sub-delims
-	'-':  true, // unreserved
-	'.':  true, // unreserved
-	':':  true, // IPv6address + Host expression's optional port
-	';':  true, // sub-delims
-	'=':  true, // sub-delims
-	'[':  true,
-	'\'': true, // sub-delims
-	']':  true,
-	'_':  true, // unreserved
-	'~':  true, // unreserved
-}
-
-func validHeaderName(v string) bool {
-	if len(v) == 0 {
-		return false
-	}
-	return strings.IndexFunc(v, isNotToken) == -1
-}
-
-// validHeaderValue reports whether v is a valid "field-value" according to
-// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
-//
-//        message-header = field-name ":" [ field-value ]
-//        field-value    = *( field-content | LWS )
-//        field-content  = <the OCTETs making up the field-value
-//                         and consisting of either *TEXT or combinations
-//                         of token, separators, and quoted-string>
-//
-// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
-//
-//        TEXT           = <any OCTET except CTLs,
-//                          but including LWS>
-//        LWS            = [CRLF] 1*( SP | HT )
-//        CTL            = <any US-ASCII control character
-//                         (octets 0 - 31) and DEL (127)>
-func validHeaderValue(v string) bool {
-	for i := 0; i < len(v); i++ {
-		b := v[i]
-		if isCTL(b) && !isLWS(b) {
-			return false
-		}
-	}
-	return true
-}
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index 0ecdf85..a4c88c0 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -99,7 +99,7 @@ type parseContentTypeTest struct {
 
 var parseContentTypeTests = []parseContentTypeTest{
 	{false, stringMap{"Content-Type": {"text/plain"}}},
-	// Empty content type is legal - shoult be treated as
+	// Empty content type is legal - should be treated as
 	// application/octet-stream (RFC 2616, section 7.2.1)
 	{false, stringMap{}},
 	{true, stringMap{"Content-Type": {"text/plain; boundary="}}},
@@ -158,6 +158,68 @@ func TestMultipartReader(t *testing.T) {
 	}
 }
 
+// Issue 9305: ParseMultipartForm should populate PostForm too
+func TestParseMultipartFormPopulatesPostForm(t *testing.T) {
+	postData :=
+		`--xxx
+Content-Disposition: form-data; name="field1"
+
+value1
+--xxx
+Content-Disposition: form-data; name="field2"
+
+value2
+--xxx
+Content-Disposition: form-data; name="file"; filename="file"
+Content-Type: application/octet-stream
+Content-Transfer-Encoding: binary
+
+binary data
+--xxx--
+`
+	req := &Request{
+		Method: "POST",
+		Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}},
+		Body:   ioutil.NopCloser(strings.NewReader(postData)),
+	}
+
+	initialFormItems := map[string]string{
+		"language": "Go",
+		"name":     "gopher",
+		"skill":    "go-ing",
+		"field2":   "initial-value2",
+	}
+
+	req.Form = make(url.Values)
+	for k, v := range initialFormItems {
+		req.Form.Add(k, v)
+	}
+
+	err := req.ParseMultipartForm(10000)
+	if err != nil {
+		t.Fatalf("unexpected multipart error %v", err)
+	}
+
+	wantForm := url.Values{
+		"language": []string{"Go"},
+		"name":     []string{"gopher"},
+		"skill":    []string{"go-ing"},
+		"field1":   []string{"value1"},
+		"field2":   []string{"initial-value2", "value2"},
+	}
+	if !reflect.DeepEqual(req.Form, wantForm) {
+		t.Fatalf("req.Form = %v, want %v", req.Form, wantForm)
+	}
+
+	wantPostForm := url.Values{
+		"field1": []string{"value1"},
+		"field2": []string{"value2"},
+	}
+	if !reflect.DeepEqual(req.PostForm, wantPostForm) {
+		t.Fatalf("req.PostForm = %v, want %v", req.PostForm, wantPostForm)
+	}
+}
+
 func TestParseMultipartForm(t *testing.T) {
 	req := &Request{
 		Method: "POST",
@@ -336,11 +398,13 @@ var newRequestHostTests = []struct {
 
 	{"http://192.168.0.1/", "192.168.0.1"},
 	{"http://192.168.0.1:8080/", "192.168.0.1:8080"},
+	{"http://192.168.0.1:/", "192.168.0.1"},
 
 	{"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"},
+	{"http://[fe80::1%25en0]:/", "[fe80::1%en0]"},
 }
 
 func TestNewRequestHost(t *testing.T) {
@@ -615,6 +679,46 @@ func TestIssue10884_MaxBytesEOF(t *testing.T) {
 	}
 }
 
+// Issue 14981: MaxBytesReader's return error wasn't sticky. It
+// doesn't technically need to be, but people expected it to be.
+func TestMaxBytesReaderStickyError(t *testing.T) {
+	isSticky := func(r io.Reader) error {
+		var log bytes.Buffer
+		buf := make([]byte, 1000)
+		var firstErr error
+		for {
+			n, err := r.Read(buf)
+			fmt.Fprintf(&log, "Read(%d) = %d, %v\n", len(buf), n, err)
+			if err == nil {
+				continue
+			}
+			if firstErr == nil {
+				firstErr = err
+				continue
+			}
+			if !reflect.DeepEqual(err, firstErr) {
+				return fmt.Errorf("non-sticky error. got log:\n%s", log.Bytes())
+			}
+			t.Logf("Got log: %s", log.Bytes())
+			return nil
+		}
+	}
+	tests := [...]struct {
+		readable int
+		limit    int64
+	}{
+		0: {99, 100},
+		1: {100, 100},
+		2: {101, 100},
+	}
+	for i, tt := range tests {
+		rc := MaxBytesReader(nil, ioutil.NopCloser(bytes.NewReader(make([]byte, tt.readable))), tt.limit)
+		if err := isSticky(rc); err != nil {
+			t.Errorf("%d. error: %v", i, 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 cfb95b0..2545f6f 100644
--- a/src/net/http/requestwrite_test.go
+++ b/src/net/http/requestwrite_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -573,7 +573,7 @@ func TestRequestWriteClosesBody(t *testing.T) {
 		"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
-		// read from our MultiReader where we stiched the Body back together
+		// read from our MultiReader where we stitched the Body back together
 		// after sniffing whether the Body was 0 bytes or not.
 		chunk("m") +
 		chunk("y body") +
@@ -604,7 +604,7 @@ func TestRequestWriteError(t *testing.T) {
 	failAfter, writeCount := 0, 0
 	errFail := errors.New("fake write failure")
 
-	// w is the buffered io.Writer to write the request to.  It
+	// w is the buffered io.Writer to write the request to. It
 	// fails exactly once on its Nth Write call, as controlled by
 	// failAfter. It also tracks the number of calls in
 	// writeCount.
diff --git a/src/net/http/response.go b/src/net/http/response.go
index c424f61..5450d50 100644
--- a/src/net/http/response.go
+++ b/src/net/http/response.go
@@ -11,6 +11,7 @@ import (
 	"bytes"
 	"crypto/tls"
 	"errors"
+	"fmt"
 	"io"
 	"net/textproto"
 	"net/url"
@@ -33,7 +34,7 @@ type Response struct {
 	ProtoMajor int    // e.g. 1
 	ProtoMinor int    // e.g. 0
 
-	// Header maps header keys to values.  If the response had multiple
+	// Header maps header keys to values. If the response had multiple
 	// headers with the same key, they may be concatenated, with comma
 	// delimiters.  (Section 4.2 of RFC 2616 requires that multiple headers
 	// be semantically equivalent to a comma-delimited sequence.) Values
@@ -57,8 +58,8 @@ type Response struct {
 	// with a "chunked" Transfer-Encoding.
 	Body io.ReadCloser
 
-	// ContentLength records the length of the associated content.  The
-	// value -1 indicates that the length is unknown.  Unless Request.Method
+	// ContentLength records the length of the associated content. The
+	// value -1 indicates that the length is unknown. Unless Request.Method
 	// is "HEAD", values >= 0 indicate that the given number of bytes may
 	// be read from Body.
 	ContentLength int64
@@ -68,10 +69,19 @@ type Response struct {
 	TransferEncoding []string
 
 	// Close records whether the header directed that the connection be
-	// closed after reading Body.  The value is advice for clients: neither
+	// closed after reading Body. The value is advice for clients: neither
 	// ReadResponse nor Response.Write ever closes a connection.
 	Close bool
 
+	// Uncompressed reports whether the response was sent compressed but
+	// was decompressed by the http package. When true, reading from
+	// Body yields the uncompressed content instead of the compressed
+	// content actually set from the server, ContentLength is set to -1,
+	// and the "Content-Length" and "Content-Encoding" fields are deleted
+	// from the responseHeader. To get the original response from
+	// the server, set Transport.DisableCompression to true.
+	Uncompressed bool
+
 	// Trailer maps trailer keys to values in the same
 	// format as Header.
 	//
@@ -86,7 +96,7 @@ type Response struct {
 	// any trailer values sent by the server.
 	Trailer Header
 
-	// The Request that was sent to obtain this Response.
+	// Request is the request that was sent to obtain this Response.
 	// Request's Body is nil (having already been consumed).
 	// This is only populated for Client requests.
 	Request *Request
@@ -108,8 +118,8 @@ func (r *Response) Cookies() []*Cookie {
 var ErrNoLocation = errors.New("http: no Location header in response")
 
 // Location returns the URL of the response's "Location" header,
-// if present.  Relative redirects are resolved relative to
-// the Response's Request.  ErrNoLocation is returned if no
+// if present. Relative redirects are resolved relative to
+// the Response's Request. ErrNoLocation is returned if no
 // Location header is present.
 func (r *Response) Location() (*url.URL, error) {
 	lv := r.Header.Get("Location")
@@ -184,7 +194,7 @@ func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
 	return resp, nil
 }
 
-// RFC2616: Should treat
+// RFC 2616: Should treat
 //	Pragma: no-cache
 // like
 //	Cache-Control: no-cache
@@ -203,7 +213,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
 		r.ProtoMajor == major && r.ProtoMinor >= minor
 }
 
-// Write writes r to w in the HTTP/1.n server response format,
+// Write writes r to w in the HTTP/1.x server response format,
 // including the status line, headers, body, and optional trailer.
 //
 // This method consults the following fields of the response r:
@@ -228,11 +238,13 @@ func (r *Response) Write(w io.Writer) error {
 		if !ok {
 			text = "status code " + strconv.Itoa(r.StatusCode)
 		}
+	} else {
+		// Just to reduce stutter, if user set r.Status to "200 OK" and StatusCode to 200.
+		// Not important.
+		text = strings.TrimPrefix(text, strconv.Itoa(r.StatusCode)+" ")
 	}
-	protoMajor, protoMinor := strconv.Itoa(r.ProtoMajor), strconv.Itoa(r.ProtoMinor)
-	statusCode := strconv.Itoa(r.StatusCode) + " "
-	text = strings.TrimPrefix(text, statusCode)
-	if _, err := io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n"); err != nil {
+
+	if _, err := fmt.Fprintf(w, "HTTP/%d.%d %03d %s\r\n", r.ProtoMajor, r.ProtoMinor, r.StatusCode, text); err != nil {
 		return err
 	}
 
@@ -265,7 +277,7 @@ func (r *Response) Write(w io.Writer) error {
 	// content-length, the only way to do that is the old HTTP/1.0
 	// way, by noting the EOF with a connection close, so we need
 	// to set Close.
-	if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) {
+	if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) && !r1.Uncompressed {
 		r1.Close = true
 	}
 
diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go
index d8a5340..126da92 100644
--- a/src/net/http/response_test.go
+++ b/src/net/http/response_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -10,6 +10,7 @@ import (
 	"compress/gzip"
 	"crypto/rand"
 	"fmt"
+	"go/ast"
 	"io"
 	"io/ioutil"
 	"net/http/internal"
@@ -505,6 +506,32 @@ some body`,
 
 		"Body here\n",
 	},
+
+	{
+		"HTTP/1.1 200 OK\r\n" +
+			"Content-Encoding: gzip\r\n" +
+			"Content-Length: 23\r\n" +
+			"Connection: keep-alive\r\n" +
+			"Keep-Alive: timeout=7200\r\n\r\n" +
+			"\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00",
+		Response{
+			Status:     "200 OK",
+			StatusCode: 200,
+			Proto:      "HTTP/1.1",
+			ProtoMajor: 1,
+			ProtoMinor: 1,
+			Request:    dummyReq("GET"),
+			Header: Header{
+				"Content-Length":   {"23"},
+				"Content-Encoding": {"gzip"},
+				"Connection":       {"keep-alive"},
+				"Keep-Alive":       {"timeout=7200"},
+			},
+			Close:         false,
+			ContentLength: 23,
+		},
+		"\x1f\x8b\b\x00\x00\x00\x00\x00\x00\x00s\xf3\xf7\a\x00\xab'\xd4\x1a\x03\x00\x00\x00",
+	},
 }
 
 // tests successful calls to ReadResponse, and inspects the returned Response.
@@ -656,10 +683,14 @@ func diff(t *testing.T, prefix string, have, want interface{}) {
 		t.Errorf("%s: type mismatch %v want %v", prefix, hv.Type(), wv.Type())
 	}
 	for i := 0; i < hv.NumField(); i++ {
+		name := hv.Type().Field(i).Name
+		if !ast.IsExported(name) {
+			continue
+		}
 		hf := hv.Field(i).Interface()
 		wf := wv.Field(i).Interface()
 		if !reflect.DeepEqual(hf, wf) {
-			t.Errorf("%s: %s = %v want %v", prefix, hv.Type().Field(i).Name, hf, wf)
+			t.Errorf("%s: %s = %v want %v", prefix, name, hf, wf)
 		}
 	}
 }
diff --git a/src/net/http/responsewrite_test.go b/src/net/http/responsewrite_test.go
index 5b8d47a..90f6767 100644
--- a/src/net/http/responsewrite_test.go
+++ b/src/net/http/responsewrite_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -222,6 +222,39 @@ func TestResponseWrite(t *testing.T) {
 			},
 			"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nabcdef",
 		},
+
+		// Status code under 100 should be zero-padded to
+		// three digits.  Still bogus, but less bogus. (be
+		// consistent with generating three digits, since the
+		// Transport requires it)
+		{
+			Response{
+				StatusCode: 7,
+				Status:     "license to violate specs",
+				ProtoMajor: 1,
+				ProtoMinor: 0,
+				Request:    dummyReq("GET"),
+				Header:     Header{},
+				Body:       nil,
+			},
+
+			"HTTP/1.0 007 license to violate specs\r\nContent-Length: 0\r\n\r\n",
+		},
+
+		// No stutter.
+		{
+			Response{
+				StatusCode: 123,
+				Status:     "123 Sesame Street",
+				ProtoMajor: 1,
+				ProtoMinor: 0,
+				Request:    dummyReq("GET"),
+				Header:     Header{},
+				Body:       nil,
+			},
+
+			"HTTP/1.0 123 Sesame Street\r\nContent-Length: 0\r\n\r\n",
+		},
 	}
 
 	for i := range respWriteTests {
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index f79c045..139ce3e 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -9,7 +9,10 @@ package http_test
 import (
 	"bufio"
 	"bytes"
+	"compress/gzip"
+	"context"
 	"crypto/tls"
+	"encoding/json"
 	"errors"
 	"fmt"
 	"internal/testenv"
@@ -617,7 +620,7 @@ func TestIdentityResponse(t *testing.T) {
 	defer ts.Close()
 
 	// Note: this relies on the assumption (which is true) that
-	// Get sends HTTP/1.1 or greater requests.  Otherwise the
+	// Get sends HTTP/1.1 or greater requests. Otherwise the
 	// server wouldn't have the choice to send back chunked
 	// responses.
 	for _, te := range []string{"", "identity"} {
@@ -713,6 +716,31 @@ func testTCPConnectionCloses(t *testing.T, req string, h Handler) {
 	}
 }
 
+func testTCPConnectionStaysOpen(t *testing.T, req string, handler Handler) {
+	defer afterTest(t)
+	ts := httptest.NewServer(handler)
+	defer ts.Close()
+	conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer conn.Close()
+	br := bufio.NewReader(conn)
+	for i := 0; i < 2; i++ {
+		if _, err := io.WriteString(conn, req); err != nil {
+			t.Fatal(err)
+		}
+		res, err := ReadResponse(br, nil)
+		if err != nil {
+			t.Fatalf("res %d: %v", i+1, err)
+		}
+		if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+			t.Fatalf("res %d body copy: %v", i+1, err)
+		}
+		res.Body.Close()
+	}
+}
+
 // TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive.
 func TestServeHTTP10Close(t *testing.T) {
 	testTCPConnectionCloses(t, "GET / HTTP/1.0\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -741,6 +769,61 @@ func TestHandlersCanSetConnectionClose10(t *testing.T) {
 	}))
 }
 
+func TestHTTP2UpgradeClosesConnection(t *testing.T) {
+	testTCPConnectionCloses(t, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+		// Nothing. (if not hijacked, the server should close the connection
+		// afterwards)
+	}))
+}
+
+func send204(w ResponseWriter, r *Request) { w.WriteHeader(204) }
+func send304(w ResponseWriter, r *Request) { w.WriteHeader(304) }
+
+// Issue 15647: 204 responses can't have bodies, so HTTP/1.0 keep-alive conns should stay open.
+func TestHTTP10KeepAlive204Response(t *testing.T) {
+	testTCPConnectionStaysOpen(t, "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n", HandlerFunc(send204))
+}
+
+func TestHTTP11KeepAlive204Response(t *testing.T) {
+	testTCPConnectionStaysOpen(t, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n", HandlerFunc(send204))
+}
+
+func TestHTTP10KeepAlive304Response(t *testing.T) {
+	testTCPConnectionStaysOpen(t,
+		"GET / HTTP/1.0\r\nConnection: keep-alive\r\nIf-Modified-Since: Mon, 02 Jan 2006 15:04:05 GMT\r\n\r\n",
+		HandlerFunc(send304))
+}
+
+// Issue 15703
+func TestKeepAliveFinalChunkWithEOF(t *testing.T) {
+	defer afterTest(t)
+	cst := newClientServerTest(t, false /* h1 */, HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.(Flusher).Flush() // force chunked encoding
+		w.Write([]byte("{\"Addr\": \"" + r.RemoteAddr + "\"}"))
+	}))
+	defer cst.close()
+	type data struct {
+		Addr string
+	}
+	var addrs [2]data
+	for i := range addrs {
+		res, err := cst.c.Get(cst.ts.URL)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := json.NewDecoder(res.Body).Decode(&addrs[i]); err != nil {
+			t.Fatal(err)
+		}
+		if addrs[i].Addr == "" {
+			t.Fatal("no address")
+		}
+		res.Body.Close()
+	}
+	if addrs[0] != addrs[1] {
+		t.Fatalf("connection not reused")
+	}
+}
+
 func TestSetsRemoteAddr_h1(t *testing.T) { testSetsRemoteAddr(t, h1Mode) }
 func TestSetsRemoteAddr_h2(t *testing.T) { testSetsRemoteAddr(t, h2Mode) }
 
@@ -984,7 +1067,7 @@ func TestTLSServer(t *testing.T) {
 	defer ts.Close()
 
 	// Connect an idle TCP connection to this server before we run
-	// our real tests.  This idle connection used to block forever
+	// our real tests. This idle connection used to block forever
 	// in the TLS handshake, preventing future connections from
 	// being accepted. It may prevent future accidental blocking
 	// in newConn.
@@ -1024,11 +1107,44 @@ func TestTLSServer(t *testing.T) {
 	})
 }
 
-func TestAutomaticHTTP2_Serve(t *testing.T) {
+// Issue 15908
+func TestAutomaticHTTP2_Serve_NoTLSConfig(t *testing.T) {
+	testAutomaticHTTP2_Serve(t, nil, true)
+}
+
+func TestAutomaticHTTP2_Serve_NonH2TLSConfig(t *testing.T) {
+	testAutomaticHTTP2_Serve(t, &tls.Config{}, false)
+}
+
+func TestAutomaticHTTP2_Serve_H2TLSConfig(t *testing.T) {
+	testAutomaticHTTP2_Serve(t, &tls.Config{NextProtos: []string{"h2"}}, true)
+}
+
+func testAutomaticHTTP2_Serve(t *testing.T, tlsConf *tls.Config, wantH2 bool) {
 	defer afterTest(t)
 	ln := newLocalListener(t)
 	ln.Close() // immediately (not a defer!)
 	var s Server
+	s.TLSConfig = tlsConf
+	if err := s.Serve(ln); err == nil {
+		t.Fatal("expected an error")
+	}
+	gotH2 := s.TLSNextProto["h2"] != nil
+	if gotH2 != wantH2 {
+		t.Errorf("http2 configured = %v; want %v", gotH2, wantH2)
+	}
+}
+
+func TestAutomaticHTTP2_Serve_WithTLSConfig(t *testing.T) {
+	defer afterTest(t)
+	ln := newLocalListener(t)
+	ln.Close() // immediately (not a defer!)
+	var s Server
+	// Set the TLSConfig. In reality, this would be the
+	// *tls.Config given to tls.NewListener.
+	s.TLSConfig = &tls.Config{
+		NextProtos: []string{"h2"},
+	}
 	if err := s.Serve(ln); err == nil {
 		t.Fatal("expected an error")
 	}
@@ -1914,6 +2030,26 @@ func TestTimeoutHandlerStartTimerWhenServing(t *testing.T) {
 	}
 }
 
+// https://golang.org/issue/15948
+func TestTimeoutHandlerEmptyResponse(t *testing.T) {
+	defer afterTest(t)
+	var handler HandlerFunc = func(w ResponseWriter, _ *Request) {
+		// No response.
+	}
+	timeout := 300 * time.Millisecond
+	ts := httptest.NewServer(TimeoutHandler(handler, timeout, ""))
+	defer ts.Close()
+
+	res, err := Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+	if res.StatusCode != StatusOK {
+		t.Errorf("got res.StatusCode %d, want %v", res.StatusCode, StatusOK)
+	}
+}
+
 // Verifies we don't path.Clean() on the wrong parts in redirects.
 func TestRedirectMunging(t *testing.T) {
 	req, _ := NewRequest("GET", "http://example.com/", nil)
@@ -2053,7 +2189,7 @@ func TestHandlerPanicWithHijack(t *testing.T) {
 func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{}) {
 	defer afterTest(t)
 	// Unlike the other tests that set the log output to ioutil.Discard
-	// to quiet the output, this test uses a pipe.  The pipe serves three
+	// to quiet the output, this test uses a pipe. The pipe serves three
 	// purposes:
 	//
 	//   1) The log.Print from the http server (generated by the caught
@@ -2086,7 +2222,7 @@ func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{})
 	defer cst.close()
 
 	// Do a blocking read on the log output pipe so its logging
-	// doesn't bleed into the next test.  But wait only 5 seconds
+	// doesn't bleed into the next test. But wait only 5 seconds
 	// for it.
 	done := make(chan bool, 1)
 	go func() {
@@ -2231,10 +2367,10 @@ func testRequestBodyLimit(t *testing.T, h2 bool) {
 	nWritten := new(int64)
 	req, _ := NewRequest("POST", cst.ts.URL, io.LimitReader(countReader{neverEnding('a'), nWritten}, limit*200))
 
-	// Send the POST, but don't care it succeeds or not.  The
+	// Send the POST, but don't care it succeeds or not. The
 	// remote side is going to reply and then close the TCP
 	// connection, and HTTP doesn't really define if that's
-	// allowed or not.  Some HTTP clients will get the response
+	// allowed or not. Some HTTP clients will get the response
 	// and some (like ours, currently) will complain that the
 	// request write failed, without reading the response.
 	//
@@ -2676,7 +2812,7 @@ func TestOptions(t *testing.T) {
 }
 
 // Tests regarding the ordering of Write, WriteHeader, Header, and
-// Flush calls.  In Go 1.0, rw.WriteHeader immediately flushed the
+// Flush calls. In Go 1.0, rw.WriteHeader immediately flushed the
 // (*response).header to the wire. In Go 1.1, the actual wire flush is
 // delayed, so we could maybe tack on a Content-Length and better
 // Content-Type after we see more (or all) of the output. To preserve
@@ -3133,7 +3269,7 @@ func testTransportAndServerSharedBodyRace(t *testing.T, h2 bool) {
 
 	const bodySize = 1 << 20
 
-	// errorf is like t.Errorf, but also writes to println.  When
+	// errorf is like t.Errorf, but also writes to println. When
 	// this test fails, it hangs. This helps debugging and I've
 	// added this enough times "temporarily".  It now gets added
 	// full time.
@@ -3855,6 +3991,8 @@ func TestServerValidatesHostHeader(t *testing.T) {
 		host  string
 		want  int
 	}{
+		{"HTTP/0.9", "", 400},
+
 		{"HTTP/1.1", "", 400},
 		{"HTTP/1.1", "Host: \r\n", 200},
 		{"HTTP/1.1", "Host: 1.2.3.4\r\n", 200},
@@ -3877,10 +4015,22 @@ func TestServerValidatesHostHeader(t *testing.T) {
 		{"HTTP/1.0", "", 200},
 		{"HTTP/1.0", "Host: first\r\nHost: second\r\n", 400},
 		{"HTTP/1.0", "Host: \xff\r\n", 400},
+
+		// Make an exception for HTTP upgrade requests:
+		{"PRI * HTTP/2.0", "", 200},
+
+		// But not other HTTP/2 stuff:
+		{"PRI / HTTP/2.0", "", 400},
+		{"GET / HTTP/2.0", "", 400},
+		{"GET / HTTP/3.0", "", 400},
 	}
 	for _, tt := range tests {
 		conn := &testConn{closec: make(chan bool, 1)}
-		io.WriteString(&conn.readBuf, "GET / "+tt.proto+"\r\n"+tt.host+"\r\n")
+		methodTarget := "GET / "
+		if !strings.HasPrefix(tt.proto, "HTTP/") {
+			methodTarget = ""
+		}
+		io.WriteString(&conn.readBuf, methodTarget+tt.proto+"\r\n"+tt.host+"\r\n")
 
 		ln := &oneConnListener{conn}
 		go Serve(ln, HandlerFunc(func(ResponseWriter, *Request) {}))
@@ -3896,6 +4046,45 @@ func TestServerValidatesHostHeader(t *testing.T) {
 	}
 }
 
+func TestServerHandlersCanHandleH2PRI(t *testing.T) {
+	const upgradeResponse = "upgrade here"
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		conn, br, err := w.(Hijacker).Hijack()
+		defer conn.Close()
+		if r.Method != "PRI" || r.RequestURI != "*" {
+			t.Errorf("Got method/target %q %q; want PRI *", r.Method, r.RequestURI)
+			return
+		}
+		if !r.Close {
+			t.Errorf("Request.Close = true; want false")
+		}
+		const want = "SM\r\n\r\n"
+		buf := make([]byte, len(want))
+		n, err := io.ReadFull(br, buf)
+		if err != nil || string(buf[:n]) != want {
+			t.Errorf("Read = %v, %v (%q), want %q", n, err, buf[:n], want)
+			return
+		}
+		io.WriteString(conn, upgradeResponse)
+	}))
+	defer ts.Close()
+
+	c, err := net.Dial("tcp", ts.Listener.Addr().String())
+	if err != nil {
+		t.Fatalf("Dial: %v", err)
+	}
+	defer c.Close()
+	io.WriteString(c, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
+	slurp, err := ioutil.ReadAll(c)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(slurp) != upgradeResponse {
+		t.Errorf("Handler response = %q; want %q", slurp, upgradeResponse)
+	}
+}
+
 // Test that we validate the valid bytes in HTTP/1 headers.
 // Issue 11207.
 func TestServerValidatesHeaders(t *testing.T) {
@@ -3936,6 +4125,140 @@ func TestServerValidatesHeaders(t *testing.T) {
 	}
 }
 
+func TestServerRequestContextCancel_ServeHTTPDone_h1(t *testing.T) {
+	testServerRequestContextCancel_ServeHTTPDone(t, h1Mode)
+}
+func TestServerRequestContextCancel_ServeHTTPDone_h2(t *testing.T) {
+	testServerRequestContextCancel_ServeHTTPDone(t, h2Mode)
+}
+func testServerRequestContextCancel_ServeHTTPDone(t *testing.T, h2 bool) {
+	defer afterTest(t)
+	ctxc := make(chan context.Context, 1)
+	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+		ctx := r.Context()
+		select {
+		case <-ctx.Done():
+			t.Error("should not be Done in ServeHTTP")
+		default:
+		}
+		ctxc <- ctx
+	}))
+	defer cst.close()
+	res, err := cst.c.Get(cst.ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	res.Body.Close()
+	ctx := <-ctxc
+	select {
+	case <-ctx.Done():
+	default:
+		t.Error("context should be done after ServeHTTP completes")
+	}
+}
+
+func TestServerRequestContextCancel_ConnClose(t *testing.T) {
+	// Currently the context is not canceled when the connection
+	// is closed because we're not reading from the connection
+	// until after ServeHTTP for the previous handler is done.
+	// Until the server code is modified to always be in a read
+	// (Issue 15224), this test doesn't work yet.
+	t.Skip("TODO(bradfitz): this test doesn't yet work; golang.org/issue/15224")
+	defer afterTest(t)
+	inHandler := make(chan struct{})
+	handlerDone := make(chan struct{})
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		close(inHandler)
+		select {
+		case <-r.Context().Done():
+		case <-time.After(3 * time.Second):
+			t.Errorf("timeout waiting for context to be done")
+		}
+		close(handlerDone)
+	}))
+	defer ts.Close()
+	c, err := net.Dial("tcp", ts.Listener.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+	io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
+	select {
+	case <-inHandler:
+	case <-time.After(3 * time.Second):
+		t.Fatalf("timeout waiting to see ServeHTTP get called")
+	}
+	c.Close() // this should trigger the context being done
+
+	select {
+	case <-handlerDone:
+	case <-time.After(3 * time.Second):
+		t.Fatalf("timeout waiting to see ServeHTTP exit")
+	}
+}
+
+func TestServerContext_ServerContextKey_h1(t *testing.T) {
+	testServerContext_ServerContextKey(t, h1Mode)
+}
+func TestServerContext_ServerContextKey_h2(t *testing.T) {
+	testServerContext_ServerContextKey(t, h2Mode)
+}
+func testServerContext_ServerContextKey(t *testing.T, h2 bool) {
+	defer afterTest(t)
+	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+		ctx := r.Context()
+		got := ctx.Value(ServerContextKey)
+		if _, ok := got.(*Server); !ok {
+			t.Errorf("context value = %T; want *http.Server", got)
+		}
+
+		got = ctx.Value(LocalAddrContextKey)
+		if addr, ok := got.(net.Addr); !ok {
+			t.Errorf("local addr value = %T; want net.Addr", got)
+		} else if fmt.Sprint(addr) != r.Host {
+			t.Errorf("local addr = %v; want %v", addr, r.Host)
+		}
+	}))
+	defer cst.close()
+	res, err := cst.c.Get(cst.ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	res.Body.Close()
+}
+
+// https://golang.org/issue/15960
+func TestHandlerSetTransferEncodingChunked(t *testing.T) {
+	defer afterTest(t)
+	ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("Transfer-Encoding", "chunked")
+		w.Write([]byte("hello"))
+	}))
+	resp := ht.rawResponse("GET / HTTP/1.1\nHost: foo")
+	const hdr = "Transfer-Encoding: chunked"
+	if n := strings.Count(resp, hdr); n != 1 {
+		t.Errorf("want 1 occurrence of %q in response, got %v\nresponse: %v", hdr, n, resp)
+	}
+}
+
+// https://golang.org/issue/16063
+func TestHandlerSetTransferEncodingGzip(t *testing.T) {
+	defer afterTest(t)
+	ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("Transfer-Encoding", "gzip")
+		gz := gzip.NewWriter(w)
+		gz.Write([]byte("hello"))
+		gz.Close()
+	}))
+	resp := ht.rawResponse("GET / HTTP/1.1\nHost: foo")
+	for _, v := range []string{"gzip", "chunked"} {
+		hdr := "Transfer-Encoding: " + v
+		if n := strings.Count(resp, hdr); n != 1 {
+			t.Errorf("want 1 occurrence of %q in response, got %v\nresponse: %v", hdr, n, resp)
+		}
+	}
+}
+
 func BenchmarkClientServer(b *testing.B) {
 	b.ReportAllocs()
 	b.StopTimer()
@@ -4126,7 +4449,7 @@ func BenchmarkClient(b *testing.B) {
 	// Wait for the server process to respond.
 	url := "http://localhost:" + port + "/"
 	for i := 0; i < 100; i++ {
-		time.Sleep(50 * time.Millisecond)
+		time.Sleep(100 * time.Millisecond)
 		if _, err := getNoBody(url); err == nil {
 			break
 		}
@@ -4147,7 +4470,7 @@ func BenchmarkClient(b *testing.B) {
 		if err != nil {
 			b.Fatalf("ReadAll: %v", err)
 		}
-		if bytes.Compare(body, data) != 0 {
+		if !bytes.Equal(body, data) {
 			b.Fatalf("Got body: %q", body)
 		}
 	}
diff --git a/src/net/http/server.go b/src/net/http/server.go
index f23ef73..7c3237c 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -2,13 +2,14 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// HTTP server.  See RFC 2616.
+// HTTP server. See RFC 2616.
 
 package http
 
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"crypto/tls"
 	"errors"
 	"fmt"
@@ -26,14 +27,30 @@ import (
 	"sync"
 	"sync/atomic"
 	"time"
+
+	"golang.org/x/net/lex/httplex"
 )
 
-// Errors introduced by the HTTP server.
+// Errors used by the HTTP server.
 var (
-	ErrWriteAfterFlush = errors.New("Conn.Write called after Flush")
-	ErrBodyNotAllowed  = errors.New("http: request method or response status code does not allow body")
-	ErrHijacked        = errors.New("Conn has been hijacked")
-	ErrContentLength   = errors.New("Conn.Write wrote more than the declared Content-Length")
+	// ErrBodyNotAllowed is returned by ResponseWriter.Write calls
+	// when the HTTP method or response code does not permit a
+	// body.
+	ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body")
+
+	// ErrHijacked is returned by ResponseWriter.Write calls when
+	// the underlying connection has been hijacked using the
+	// Hijacker interfaced.
+	ErrHijacked = errors.New("http: connection has been hijacked")
+
+	// ErrContentLength is returned by ResponseWriter.Write calls
+	// when a Handler set a Content-Length response header with a
+	// declared size and then attempted to write more bytes than
+	// declared.
+	ErrContentLength = errors.New("http: wrote more than the declared Content-Length")
+
+	// Deprecated: ErrWriteAfterFlush is no longer used.
+	ErrWriteAfterFlush = errors.New("unused")
 )
 
 // A Handler responds to an HTTP request.
@@ -50,6 +67,9 @@ var (
 // ResponseWriter. Cautious handlers should read the Request.Body
 // first, and then reply.
 //
+// Except for reading the body, handlers should not modify the
+// provided Request.
+//
 // If ServeHTTP panics, the server (the caller of ServeHTTP) assumes
 // that the effect of the panic was isolated to the active request.
 // It recovers the panic, logs a stack trace to the server error log,
@@ -73,10 +93,24 @@ type ResponseWriter interface {
 	Header() Header
 
 	// Write writes the data to the connection as part of an HTTP reply.
-	// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
-	// before writing the data.  If the Header does not contain a
-	// Content-Type line, Write adds a Content-Type set to the result of passing
-	// the initial 512 bytes of written data to DetectContentType.
+	//
+	// If WriteHeader has not yet been called, Write calls
+	// WriteHeader(http.StatusOK) before writing the data. If the Header
+	// does not contain a Content-Type line, Write adds a Content-Type set
+	// to the result of passing the initial 512 bytes of written data to
+	// DetectContentType.
+	//
+	// Depending on the HTTP protocol version and the client, calling
+	// Write or WriteHeader may prevent future reads on the
+	// Request.Body. For HTTP/1.x requests, handlers should read any
+	// needed request body data before writing the response. Once the
+	// headers have been flushed (due to either an explicit Flusher.Flush
+	// call or writing enough data to trigger a flush), the request body
+	// may be unavailable. For HTTP/2 requests, the Go HTTP server permits
+	// handlers to continue to read the request body while concurrently
+	// writing the response. However, such behavior may not be supported
+	// by all HTTP/2 clients. Handlers should read before writing if
+	// possible to maximize compatibility.
 	Write([]byte) (int, error)
 
 	// WriteHeader sends an HTTP response header with status code.
@@ -90,6 +124,10 @@ type ResponseWriter interface {
 // The Flusher interface is implemented by ResponseWriters that allow
 // an HTTP handler to flush buffered data to the client.
 //
+// The default HTTP/1.x and HTTP/2 ResponseWriter implementations
+// support Flusher, but ResponseWriter wrappers may not. Handlers
+// should always test for this ability at runtime.
+//
 // Note that even for ResponseWriters that support Flush,
 // if the client is connected through an HTTP proxy,
 // the buffered data may not reach the client until the response
@@ -101,6 +139,11 @@ type Flusher interface {
 
 // The Hijacker interface is implemented by ResponseWriters that allow
 // an HTTP handler to take over the connection.
+//
+// The default ResponseWriter for HTTP/1.x connections supports
+// Hijacker, but HTTP/2 connections intentionally do not.
+// ResponseWriter wrappers may also not support Hijacker. Handlers
+// should always test for this ability at runtime.
 type Hijacker interface {
 	// Hijack lets the caller take over the connection.
 	// After a call to Hijack(), the HTTP server library
@@ -143,6 +186,20 @@ type CloseNotifier interface {
 	CloseNotify() <-chan bool
 }
 
+var (
+	// ServerContextKey is a context key. It can be used in HTTP
+	// handlers with context.WithValue to access the server that
+	// started the handler. The associated value will be of
+	// type *Server.
+	ServerContextKey = &contextKey{"http-server"}
+
+	// LocalAddrContextKey is a context key. It can be used in
+	// HTTP handlers with context.WithValue to access the address
+	// the local address the connection arrived on.
+	// The associated value will be of type net.Addr.
+	LocalAddrContextKey = &contextKey{"local-addr"}
+)
+
 // A conn represents the server side of an HTTP connection.
 type conn struct {
 	// server is the server on which the connection arrived.
@@ -306,11 +363,14 @@ func (cw *chunkWriter) close() {
 
 // A response represents the server side of an HTTP response.
 type response struct {
-	conn          *conn
-	req           *Request // request for this response
-	reqBody       io.ReadCloser
-	wroteHeader   bool // reply header has been (logically) written
-	wroteContinue bool // 100 Continue response was written
+	conn             *conn
+	req              *Request // request for this response
+	reqBody          io.ReadCloser
+	cancelCtx        context.CancelFunc // when ServeHTTP exits
+	wroteHeader      bool               // reply header has been (logically) written
+	wroteContinue    bool               // 100 Continue response was written
+	wants10KeepAlive bool               // HTTP/1.0 w/ Connection "keep-alive"
+	wantsClose       bool               // HTTP request has Connection "close"
 
 	w  *bufio.Writer // buffers output in chunks to chunkWriter
 	cw chunkWriter
@@ -342,7 +402,7 @@ type response struct {
 	requestBodyLimitHit bool
 
 	// trailers are the headers to be sent after the handler
-	// finishes writing the body.  This field is initialized from
+	// finishes writing the body. This field is initialized from
 	// the Trailer response header when the response header is
 	// written.
 	trailers []string
@@ -497,7 +557,7 @@ type connReader struct {
 }
 
 func (cr *connReader) setReadLimit(remain int64) { cr.remain = remain }
-func (cr *connReader) setInfiniteReadLimit()     { cr.remain = 1<<63 - 1 }
+func (cr *connReader) setInfiniteReadLimit()     { cr.remain = maxInt64 }
 func (cr *connReader) hitReadLimit() bool        { return cr.remain <= 0 }
 
 func (cr *connReader) Read(p []byte) (n int, err error) {
@@ -681,7 +741,7 @@ func appendTime(b []byte, t time.Time) []byte {
 var errTooLarge = errors.New("http: request too large")
 
 // Read next request from connection.
-func (c *conn) readRequest() (w *response, err error) {
+func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
 	if c.hijacked() {
 		return nil, ErrHijacked
 	}
@@ -710,25 +770,34 @@ func (c *conn) readRequest() (w *response, err error) {
 		}
 		return nil, err
 	}
+
+	if !http1ServerSupportsRequest(req) {
+		return nil, badRequestError("unsupported protocol version")
+	}
+
+	ctx, cancelCtx := context.WithCancel(ctx)
+	req.ctx = ctx
+
 	c.lastMethod = req.Method
 	c.r.setInfiniteReadLimit()
 
 	hosts, haveHost := req.Header["Host"]
-	if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) {
+	isH2Upgrade := req.isH2Upgrade()
+	if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade {
 		return nil, badRequestError("missing required Host header")
 	}
 	if len(hosts) > 1 {
 		return nil, badRequestError("too many Host headers")
 	}
-	if len(hosts) == 1 && !validHostHeader(hosts[0]) {
+	if len(hosts) == 1 && !httplex.ValidHostHeader(hosts[0]) {
 		return nil, badRequestError("malformed Host header")
 	}
 	for k, vv := range req.Header {
-		if !validHeaderName(k) {
+		if !httplex.ValidHeaderFieldName(k) {
 			return nil, badRequestError("invalid header name")
 		}
 		for _, v := range vv {
-			if !validHeaderValue(v) {
+			if !httplex.ValidHeaderFieldValue(v) {
 				return nil, badRequestError("invalid header value")
 			}
 		}
@@ -743,16 +812,43 @@ func (c *conn) readRequest() (w *response, err error) {
 
 	w = &response{
 		conn:          c,
+		cancelCtx:     cancelCtx,
 		req:           req,
 		reqBody:       req.Body,
 		handlerHeader: make(Header),
 		contentLength: -1,
+
+		// We populate these ahead of time so we're not
+		// reading from req.Header after their Handler starts
+		// and maybe mutates it (Issue 14940)
+		wants10KeepAlive: req.wantsHttp10KeepAlive(),
+		wantsClose:       req.wantsClose(),
+	}
+	if isH2Upgrade {
+		w.closeAfterReply = true
 	}
 	w.cw.res = w
 	w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize)
 	return w, nil
 }
 
+// http1ServerSupportsRequest reports whether Go's HTTP/1.x server
+// supports the given request.
+func http1ServerSupportsRequest(req *Request) bool {
+	if req.ProtoMajor == 1 {
+		return true
+	}
+	// Accept "PRI * HTTP/2.0" upgrade requests, so Handlers can
+	// wire up their own HTTP/2 upgrades.
+	if req.ProtoMajor == 2 && req.ProtoMinor == 0 &&
+		req.Method == "PRI" && req.RequestURI == "*" {
+		return true
+	}
+	// Reject HTTP/0.x, and all other HTTP/2+ requests (which
+	// aren't encoded in ASCII anyway).
+	return false
+}
+
 func (w *response) Header() Header {
 	if w.cw.header == nil && w.wroteHeader && !w.cw.wroteHeader {
 		// Accessing the header between logically writing it
@@ -766,7 +862,7 @@ func (w *response) Header() Header {
 
 // maxPostHandlerReadBytes is the max number of Request.Body bytes not
 // consumed by a handler that the server will read from the client
-// in order to keep a connection alive.  If there are more bytes than
+// in order to keep a connection alive. If there are more bytes than
 // this then the server to be paranoid instead sends a "Connection:
 // close" response.
 //
@@ -855,8 +951,8 @@ func (h extraHeader) Write(w *bufio.Writer) {
 // to cw.res.conn.bufw.
 //
 // p is not written by writeHeader, but is the first chunk of the body
-// that will be written.  It is sniffed for a Content-Type if none is
-// set explicitly.  It's also used to set the Content-Length, if the
+// that will be written. It is sniffed for a Content-Type if none is
+// set explicitly. It's also used to set the Content-Length, if the
 // total body size was small and the handler has already finished
 // running.
 func (cw *chunkWriter) writeHeader(p []byte) {
@@ -911,9 +1007,9 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	// Exceptions: 304/204/1xx responses never get Content-Length, and if
 	// it was a HEAD request, we don't know the difference between
 	// 0 actual bytes and 0 bytes because the handler noticed it
-	// was a HEAD request and chose not to write anything.  So for
+	// was a HEAD request and chose not to write anything. So for
 	// HEAD, the handler should either write the Content-Length or
-	// write non-zero bytes.  If it's actually 0 bytes and the
+	// 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.
 	// Further, we don't send an automatic Content-Length if they
@@ -925,7 +1021,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 
 	// If this was an HTTP/1.0 request with keep-alive and we sent a
 	// Content-Length back, we can make this a keep-alive response ...
-	if w.req.wantsHttp10KeepAlive() && keepAlivesEnabled {
+	if w.wants10KeepAlive && keepAlivesEnabled {
 		sentLength := header.get("Content-Length") != ""
 		if sentLength && header.get("Connection") == "keep-alive" {
 			w.closeAfterReply = false
@@ -935,12 +1031,12 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	// Check for a explicit (and valid) Content-Length header.
 	hasCL := w.contentLength != -1
 
-	if w.req.wantsHttp10KeepAlive() && (isHEAD || hasCL) {
+	if w.wants10KeepAlive && (isHEAD || hasCL || !bodyAllowedForStatus(w.status)) {
 		_, connectionHeaderSet := header["Connection"]
 		if !connectionHeaderSet {
 			setHeader.connection = "keep-alive"
 		}
-	} else if !w.req.ProtoAtLeast(1, 1) || w.req.wantsClose() {
+	} else if !w.req.ProtoAtLeast(1, 1) || w.wantsClose {
 		w.closeAfterReply = true
 	}
 
@@ -965,9 +1061,12 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	}
 
 	// Per RFC 2616, we should consume the request body before
-	// replying, if the handler hasn't already done so.  But we
+	// 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.
+	// TODO(bradfitz): where does RFC 2616 say that? See Issue 15527
+	// about HTTP/1.x Handlers concurrently reading and writing, like
+	// HTTP/2 handlers can do. Maybe this code should be relaxed?
 	if w.req.ContentLength != 0 && !w.closeAfterReply {
 		var discard, tooBig bool
 
@@ -1009,7 +1108,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 					w.closeAfterReply = true
 				}
 			default:
-				// Some other kind of error occured, like a read timeout, or
+				// Some other kind of error occurred, 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
@@ -1069,6 +1168,10 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 			// to avoid closing the connection at EOF.
 			cw.chunking = true
 			setHeader.transferEncoding = "chunked"
+			if hasTE && te == "chunked" {
+				// We will send the chunked Transfer-Encoding header later.
+				delHeader("Transfer-Encoding")
+			}
 		}
 	} else {
 		// HTTP version < 1.1: cannot do chunked transfer
@@ -1148,7 +1251,7 @@ func statusLine(req *Request, code int) string {
 	if proto11 {
 		proto = "HTTP/1.1"
 	}
-	codestring := strconv.Itoa(code)
+	codestring := fmt.Sprintf("%03d", code)
 	text, ok := statusText[code]
 	if !ok {
 		text = "status code " + codestring
@@ -1174,7 +1277,7 @@ func (w *response) bodyAllowed() bool {
 // The Life Of A Write is like this:
 //
 // Handler starts. No header has been sent. The handler can either
-// write a header, or just start writing.  Writing before sending a header
+// write a header, or just start writing. Writing before sending a header
 // sends an implicitly empty 200 OK header.
 //
 // If the handler didn't declare a Content-Length up front, we either
@@ -1200,7 +1303,7 @@ func (w *response) bodyAllowed() bool {
 // initial header contains both a Content-Type and Content-Length.
 // Also short-circuit in (1) when the header's been sent and not in
 // chunking mode, writing directly to (4) instead, if (2) has no
-// buffered data.  More generally, we could short-circuit from (1) to
+// buffered data. More generally, we could short-circuit from (1) to
 // (3) even in chunking mode if the write size from (1) is over some
 // threshold and nothing is in (2).  The answer might be mostly making
 // bufferBeforeChunkingSize smaller and having bufio's fast-paths deal
@@ -1341,7 +1444,7 @@ type closeWriter interface {
 var _ closeWriter = (*net.TCPConn)(nil)
 
 // closeWrite flushes any outstanding data and sends a FIN packet (if
-// client is connected via TCP), signalling that we're done.  We then
+// client is connected via TCP), signalling that we're done. We then
 // pause for a bit, hoping the client processes it before any
 // subsequent RST.
 //
@@ -1355,7 +1458,7 @@ func (c *conn) closeWriteAndWait() {
 }
 
 // validNPN reports whether the proto is not a blacklisted Next
-// Protocol Negotiation protocol.  Empty and built-in protocol types
+// Protocol Negotiation protocol. Empty and built-in protocol types
 // are blacklisted and can't be overridden with alternate
 // implementations.
 func validNPN(proto string) bool {
@@ -1374,13 +1477,13 @@ func (c *conn) setState(nc net.Conn, state ConnState) {
 
 // badRequestError is a literal string (used by in the server in HTML,
 // unescaped) to tell the user why their request was bad. It should
-// be plain text without user info or other embeddded errors.
+// be plain text without user info or other embedded errors.
 type badRequestError string
 
 func (e badRequestError) Error() string { return "Bad Request: " + string(e) }
 
 // Serve a new connection.
-func (c *conn) serve() {
+func (c *conn) serve(ctx context.Context) {
 	c.remoteAddr = c.rwc.RemoteAddr().String()
 	defer func() {
 		if err := recover(); err != nil {
@@ -1417,12 +1520,17 @@ func (c *conn) serve() {
 		}
 	}
 
+	// HTTP/1.x from here on.
+
 	c.r = &connReader{r: c.rwc}
 	c.bufr = newBufioReader(c.r)
 	c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
 
+	ctx, cancelCtx := context.WithCancel(ctx)
+	defer cancelCtx()
+
 	for {
-		w, err := c.readRequest()
+		w, err := c.readRequest(ctx)
 		if c.r.remain != c.server.initialReadLimitSize() {
 			// If we read any bytes off the wire, we're active.
 			c.setState(c.rwc, StateActive)
@@ -1433,7 +1541,7 @@ func (c *conn) serve() {
 				// able to read this if we're
 				// responding to them and hanging up
 				// while they're still writing their
-				// request.  Undefined behavior.
+				// request. Undefined behavior.
 				io.WriteString(c.rwc, "HTTP/1.1 431 Request Header Fields Too Large\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n431 Request Header Fields Too Large")
 				c.closeWriteAndWait()
 				return
@@ -1467,9 +1575,10 @@ func (c *conn) serve() {
 		// HTTP cannot have multiple simultaneous active requests.[*]
 		// Until the server replies to this request, it can't read another,
 		// so we might as well run the handler in this goroutine.
-		// [*] Not strictly true: HTTP pipelining.  We could let them all process
+		// [*] Not strictly true: HTTP pipelining. We could let them all process
 		// in parallel even if their responses need to be serialized.
 		serverHandler{c.server}.ServeHTTP(w, w.req)
+		w.cancelCtx()
 		if c.hijacked() {
 			return
 		}
@@ -1488,7 +1597,7 @@ func (w *response) sendExpectationFailed() {
 	// TODO(bradfitz): let ServeHTTP handlers handle
 	// requests with non-standard expectation[s]? Seems
 	// theoretical at best, and doesn't fit into the
-	// current ServeHTTP model anyway.  We'd need to
+	// current ServeHTTP model anyway. We'd need to
 	// make the ResponseWriter an optional
 	// "ExpectReplier" interface or something.
 	//
@@ -1608,7 +1717,7 @@ func requestBodyRemains(rc io.ReadCloser) bool {
 }
 
 // The HandlerFunc type is an adapter to allow the use of
-// ordinary functions as HTTP handlers.  If f is a function
+// ordinary functions as HTTP handlers. If f is a function
 // with the appropriate signature, HandlerFunc(f) is a
 // Handler that calls f.
 type HandlerFunc func(ResponseWriter, *Request)
@@ -1621,6 +1730,8 @@ func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
 // Helper handlers
 
 // Error replies to the request with the specified error message and HTTP code.
+// It does not otherwise end the request; the caller should ensure no further
+// writes are done to w.
 // 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")
@@ -1709,7 +1820,7 @@ func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
 	w.Header().Set("Location", urlStr)
 	w.WriteHeader(code)
 
-	// RFC2616 recommends that a short note "SHOULD" be included in the
+	// RFC 2616 recommends that a short note "SHOULD" be included in the
 	// response because older user agents may not understand 301/307.
 	// Shouldn't send the response for POST or HEAD; that leaves GET.
 	if r.Method == "GET" {
@@ -1779,7 +1890,7 @@ func RedirectHandler(url string, code int) Handler {
 // been registered separately.
 //
 // Patterns may optionally begin with a host name, restricting matches to
-// URLs on that host only.  Host-specific patterns take precedence over
+// URLs on that host only. Host-specific patterns take precedence over
 // general patterns, so that a handler might register for the two patterns
 // "/codesearch" and "codesearch.google.com/" without also taking over
 // requests for "http://www.google.com/".
@@ -1800,10 +1911,12 @@ type muxEntry struct {
 }
 
 // NewServeMux allocates and returns a new ServeMux.
-func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }
+func NewServeMux() *ServeMux { return new(ServeMux) }
 
 // DefaultServeMux is the default ServeMux used by Serve.
-var DefaultServeMux = NewServeMux()
+var DefaultServeMux = &defaultServeMux
+
+var defaultServeMux ServeMux
 
 // Does path match pattern?
 func pathMatch(pattern, path string) bool {
@@ -1926,6 +2039,9 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
 		panic("http: multiple registrations for " + pattern)
 	}
 
+	if mux.m == nil {
+		mux.m = make(map[string]muxEntry)
+	}
 	mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern}
 
 	if pattern[0] != '/' {
@@ -1968,7 +2084,7 @@ func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
 }
 
 // Serve accepts incoming HTTP connections on the listener l,
-// creating a new service goroutine for each.  The service goroutines
+// creating a new service goroutine for each. The service goroutines
 // read requests and then call handler to reply to them.
 // Handler is typically nil, in which case the DefaultServeMux is used.
 func Serve(l net.Listener, handler Handler) error {
@@ -1979,19 +2095,25 @@ func Serve(l net.Listener, handler Handler) error {
 // A Server defines parameters for running an HTTP server.
 // The zero value for Server is a valid configuration.
 type Server struct {
-	Addr           string        // TCP address to listen on, ":http" if empty
-	Handler        Handler       // handler to invoke, http.DefaultServeMux if nil
-	ReadTimeout    time.Duration // maximum duration before timing out read of the request
-	WriteTimeout   time.Duration // maximum duration before timing out write of the response
-	MaxHeaderBytes int           // maximum size of request headers, DefaultMaxHeaderBytes if 0
-	TLSConfig      *tls.Config   // optional TLS config, used by ListenAndServeTLS
+	Addr         string        // TCP address to listen on, ":http" if empty
+	Handler      Handler       // handler to invoke, http.DefaultServeMux if nil
+	ReadTimeout  time.Duration // maximum duration before timing out read of the request
+	WriteTimeout time.Duration // maximum duration before timing out write of the response
+	TLSConfig    *tls.Config   // optional TLS config, used by ListenAndServeTLS
+
+	// MaxHeaderBytes controls the maximum number of bytes the
+	// server will read parsing the request header's keys and
+	// values, including the request line. It does not limit the
+	// size of the request body.
+	// If zero, DefaultMaxHeaderBytes is used.
+	MaxHeaderBytes int
 
 	// TLSNextProto optionally specifies a function to take over
-	// ownership of the provided TLS connection when an NPN
-	// protocol upgrade has occurred.  The map key is the protocol
+	// ownership of the provided TLS connection when an NPN/ALPN
+	// protocol upgrade has occurred. The map key is the protocol
 	// name negotiated. The Handler argument should be used to
 	// handle HTTP requests and will initialize the Request's TLS
-	// and RemoteAddr if not already set.  The connection is
+	// and RemoteAddr if not already set. The connection is
 	// automatically closed when the function returns.
 	// If TLSNextProto is nil, HTTP/2 support is enabled automatically.
 	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
@@ -2032,7 +2154,7 @@ const (
 	// For HTTP/2, StateActive fires on the transition from zero
 	// to one active request, and only transitions away once all
 	// active requests are complete. That means that ConnState
-	// can not be used to do per-request work; ConnState only notes
+	// cannot be used to do per-request work; ConnState only notes
 	// the overall state of the connection.
 	StateActive
 
@@ -2100,9 +2222,37 @@ func (srv *Server) ListenAndServe() error {
 
 var testHookServerServe func(*Server, net.Listener) // used if non-nil
 
+// shouldDoServeHTTP2 reports whether Server.Serve should configure
+// automatic HTTP/2. (which sets up the srv.TLSNextProto map)
+func (srv *Server) shouldConfigureHTTP2ForServe() bool {
+	if srv.TLSConfig == nil {
+		// Compatibility with Go 1.6:
+		// If there's no TLSConfig, it's possible that the user just
+		// didn't set it on the http.Server, but did pass it to
+		// tls.NewListener and passed that listener to Serve.
+		// So we should configure HTTP/2 (to set up srv.TLSNextProto)
+		// in case the listener returns an "h2" *tls.Conn.
+		return true
+	}
+	// The user specified a TLSConfig on their http.Server.
+	// In this, case, only configure HTTP/2 if their tls.Config
+	// explicitly mentions "h2". Otherwise http2.ConfigureServer
+	// would modify the tls.Config to add it, but they probably already
+	// passed this tls.Config to tls.NewListener. And if they did,
+	// it's too late anyway to fix it. It would only be potentially racy.
+	// See Issue 15908.
+	return strSliceContains(srv.TLSConfig.NextProtos, http2NextProtoTLS)
+}
+
 // Serve accepts incoming connections on the Listener l, creating a
 // new service goroutine for each. The service goroutines read requests and
 // then call srv.Handler to reply to them.
+//
+// For HTTP/2 support, srv.TLSConfig should be initialized to the
+// provided listener's TLS Config before calling Serve. If
+// srv.TLSConfig is non-nil and doesn't include the string "h2" in
+// Config.NextProtos, HTTP/2 support is not enabled.
+//
 // Serve always returns a non-nil error.
 func (srv *Server) Serve(l net.Listener) error {
 	defer l.Close()
@@ -2110,9 +2260,18 @@ func (srv *Server) Serve(l net.Listener) error {
 		fn(srv, l)
 	}
 	var tempDelay time.Duration // how long to sleep on accept failure
-	if err := srv.setupHTTP2(); err != nil {
-		return err
+
+	if srv.shouldConfigureHTTP2ForServe() {
+		if err := srv.setupHTTP2(); err != nil {
+			return err
+		}
 	}
+
+	// TODO: allow changing base context? can't imagine concrete
+	// use cases yet.
+	baseCtx := context.Background()
+	ctx := context.WithValue(baseCtx, ServerContextKey, srv)
+	ctx = context.WithValue(ctx, LocalAddrContextKey, l.Addr())
 	for {
 		rw, e := l.Accept()
 		if e != nil {
@@ -2134,7 +2293,7 @@ func (srv *Server) Serve(l net.Listener) error {
 		tempDelay = 0
 		c := srv.newConn(rw)
 		c.setState(c.rwc, StateNew) // before Serve can return
-		go c.serve()
+		go c.serve(ctx)
 	}
 }
 
@@ -2361,6 +2520,9 @@ func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) {
 		for k, vv := range tw.h {
 			dst[k] = vv
 		}
+		if !tw.wroteHeader {
+			tw.code = StatusOK
+		}
 		w.WriteHeader(tw.code)
 		w.Write(tw.wbuf.Bytes())
 		if t != nil {
diff --git a/src/net/http/sniff.go b/src/net/http/sniff.go
index 18810ba..0d21b44 100644
--- a/src/net/http/sniff.go
+++ b/src/net/http/sniff.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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,8 +14,8 @@ const sniffLen = 512
 
 // DetectContentType implements the algorithm described
 // at http://mimesniff.spec.whatwg.org/ to determine the
-// Content-Type of the given data.  It considers at most the
-// first 512 bytes of data.  DetectContentType always returns
+// Content-Type of the given data. It considers at most the
+// first 512 bytes of data. DetectContentType always returns
 // a valid MIME type: if it cannot determine a more specific one, it
 // returns "application/octet-stream".
 func DetectContentType(data []byte) string {
@@ -91,12 +91,41 @@ var sniffSignatures = []sniffSig{
 		ct:   "image/webp",
 	},
 	&exactSig{[]byte("\x00\x00\x01\x00"), "image/vnd.microsoft.icon"},
-	&exactSig{[]byte("\x4F\x67\x67\x53\x00"), "application/ogg"},
 	&maskedSig{
 		mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"),
 		pat:  []byte("RIFF\x00\x00\x00\x00WAVE"),
 		ct:   "audio/wave",
 	},
+	&maskedSig{
+		mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"),
+		pat:  []byte("FORM\x00\x00\x00\x00AIFF"),
+		ct:   "audio/aiff",
+	},
+	&maskedSig{
+		mask: []byte("\xFF\xFF\xFF\xFF"),
+		pat:  []byte(".snd"),
+		ct:   "audio/basic",
+	},
+	&maskedSig{
+		mask: []byte("OggS\x00"),
+		pat:  []byte("\x4F\x67\x67\x53\x00"),
+		ct:   "application/ogg",
+	},
+	&maskedSig{
+		mask: []byte("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"),
+		pat:  []byte("MThd\x00\x00\x00\x06"),
+		ct:   "audio/midi",
+	},
+	&maskedSig{
+		mask: []byte("\xFF\xFF\xFF"),
+		pat:  []byte("ID3"),
+		ct:   "audio/mpeg",
+	},
+	&maskedSig{
+		mask: []byte("\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF"),
+		pat:  []byte("RIFF\x00\x00\x00\x00AVI "),
+		ct:   "video/avi",
+	},
 	&exactSig{[]byte("\x1A\x45\xDF\xA3"), "video/webm"},
 	&exactSig{[]byte("\x52\x61\x72\x20\x1A\x07\x00"), "application/x-rar-compressed"},
 	&exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"},
@@ -126,9 +155,15 @@ type maskedSig struct {
 }
 
 func (m *maskedSig) match(data []byte, firstNonWS int) string {
+	// pattern matching algorithm section 6
+	// https://mimesniff.spec.whatwg.org/#pattern-matching-algorithm
+
 	if m.skipWS {
 		data = data[firstNonWS:]
 	}
+	if len(m.pat) != len(m.mask) {
+		return ""
+	}
 	if len(data) < len(m.mask) {
 		return ""
 	}
diff --git a/src/net/http/sniff_test.go b/src/net/http/sniff_test.go
index e008551..ac404bf 100644
--- a/src/net/http/sniff_test.go
+++ b/src/net/http/sniff_test.go
@@ -39,7 +39,18 @@ var sniffTests = []struct {
 	{"GIF 87a", []byte(`GIF87a`), "image/gif"},
 	{"GIF 89a", []byte(`GIF89a...`), "image/gif"},
 
+	// Audio types.
+	{"MIDI audio", []byte("MThd\x00\x00\x00\x06\x00\x01"), "audio/midi"},
+	{"MP3 audio/MPEG audio", []byte("ID3\x03\x00\x00\x00\x00\x0f"), "audio/mpeg"},
+	{"WAV audio #1", []byte("RIFFb\xb8\x00\x00WAVEfmt \x12\x00\x00\x00\x06"), "audio/wave"},
+	{"WAV audio #2", []byte("RIFF,\x00\x00\x00WAVEfmt \x12\x00\x00\x00\x06"), "audio/wave"},
+	{"AIFF audio #1", []byte("FORM\x00\x00\x00\x00AIFFCOMM\x00\x00\x00\x12\x00\x01\x00\x00\x57\x55\x00\x10\x40\x0d\xf3\x34"), "audio/aiff"},
+	{"OGG audio", []byte("OggS\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x7e\x46\x00\x00\x00\x00\x00\x00\x1f\xf6\xb4\xfc\x01\x1e\x01\x76\x6f\x72"), "application/ogg"},
+
+	// Video types.
 	{"MP4 video", []byte("\x00\x00\x00\x18ftypmp42\x00\x00\x00\x00mp42isom<\x06t\xbfmdat"), "video/mp4"},
+	{"AVI video #1", []byte("RIFF,O\n\x00AVI LISTÀ"), "video/avi"},
+	{"AVI video #2", []byte("RIFF,\n\x00\x00AVI LISTÀ"), "video/avi"},
 }
 
 func TestDetectContentType(t *testing.T) {
diff --git a/src/net/http/status.go b/src/net/http/status.go
index f3dacab..98645b7 100644
--- a/src/net/http/status.go
+++ b/src/net/http/status.go
@@ -4,63 +4,79 @@
 
 package http
 
-// HTTP status codes, defined in RFC 2616.
+// HTTP status codes as registered with IANA.
+// See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
 const (
-	StatusContinue           = 100
-	StatusSwitchingProtocols = 101
+	StatusContinue           = 100 // RFC 7231, 6.2.1
+	StatusSwitchingProtocols = 101 // RFC 7231, 6.2.2
+	StatusProcessing         = 102 // RFC 2518, 10.1
 
-	StatusOK                   = 200
-	StatusCreated              = 201
-	StatusAccepted             = 202
-	StatusNonAuthoritativeInfo = 203
-	StatusNoContent            = 204
-	StatusResetContent         = 205
-	StatusPartialContent       = 206
+	StatusOK                   = 200 // RFC 7231, 6.3.1
+	StatusCreated              = 201 // RFC 7231, 6.3.2
+	StatusAccepted             = 202 // RFC 7231, 6.3.3
+	StatusNonAuthoritativeInfo = 203 // RFC 7231, 6.3.4
+	StatusNoContent            = 204 // RFC 7231, 6.3.5
+	StatusResetContent         = 205 // RFC 7231, 6.3.6
+	StatusPartialContent       = 206 // RFC 7233, 4.1
+	StatusMultiStatus          = 207 // RFC 4918, 11.1
+	StatusAlreadyReported      = 208 // RFC 5842, 7.1
+	StatusIMUsed               = 226 // RFC 3229, 10.4.1
 
-	StatusMultipleChoices   = 300
-	StatusMovedPermanently  = 301
-	StatusFound             = 302
-	StatusSeeOther          = 303
-	StatusNotModified       = 304
-	StatusUseProxy          = 305
-	StatusTemporaryRedirect = 307
+	StatusMultipleChoices   = 300 // RFC 7231, 6.4.1
+	StatusMovedPermanently  = 301 // RFC 7231, 6.4.2
+	StatusFound             = 302 // RFC 7231, 6.4.3
+	StatusSeeOther          = 303 // RFC 7231, 6.4.4
+	StatusNotModified       = 304 // RFC 7232, 4.1
+	StatusUseProxy          = 305 // RFC 7231, 6.4.5
+	_                       = 306 // RFC 7231, 6.4.6 (Unused)
+	StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
+	StatusPermanentRedirect = 308 // RFC 7538, 3
 
-	StatusBadRequest                   = 400
-	StatusUnauthorized                 = 401
-	StatusPaymentRequired              = 402
-	StatusForbidden                    = 403
-	StatusNotFound                     = 404
-	StatusMethodNotAllowed             = 405
-	StatusNotAcceptable                = 406
-	StatusProxyAuthRequired            = 407
-	StatusRequestTimeout               = 408
-	StatusConflict                     = 409
-	StatusGone                         = 410
-	StatusLengthRequired               = 411
-	StatusPreconditionFailed           = 412
-	StatusRequestEntityTooLarge        = 413
-	StatusRequestURITooLong            = 414
-	StatusUnsupportedMediaType         = 415
-	StatusRequestedRangeNotSatisfiable = 416
-	StatusExpectationFailed            = 417
-	StatusTeapot                       = 418
-	StatusPreconditionRequired         = 428
-	StatusTooManyRequests              = 429
-	StatusRequestHeaderFieldsTooLarge  = 431
-	StatusUnavailableForLegalReasons   = 451
+	StatusBadRequest                   = 400 // RFC 7231, 6.5.1
+	StatusUnauthorized                 = 401 // RFC 7235, 3.1
+	StatusPaymentRequired              = 402 // RFC 7231, 6.5.2
+	StatusForbidden                    = 403 // RFC 7231, 6.5.3
+	StatusNotFound                     = 404 // RFC 7231, 6.5.4
+	StatusMethodNotAllowed             = 405 // RFC 7231, 6.5.5
+	StatusNotAcceptable                = 406 // RFC 7231, 6.5.6
+	StatusProxyAuthRequired            = 407 // RFC 7235, 3.2
+	StatusRequestTimeout               = 408 // RFC 7231, 6.5.7
+	StatusConflict                     = 409 // RFC 7231, 6.5.8
+	StatusGone                         = 410 // RFC 7231, 6.5.9
+	StatusLengthRequired               = 411 // RFC 7231, 6.5.10
+	StatusPreconditionFailed           = 412 // RFC 7232, 4.2
+	StatusRequestEntityTooLarge        = 413 // RFC 7231, 6.5.11
+	StatusRequestURITooLong            = 414 // RFC 7231, 6.5.12
+	StatusUnsupportedMediaType         = 415 // RFC 7231, 6.5.13
+	StatusRequestedRangeNotSatisfiable = 416 // RFC 7233, 4.4
+	StatusExpectationFailed            = 417 // RFC 7231, 6.5.14
+	StatusTeapot                       = 418 // RFC 7168, 2.3.3
+	StatusUnprocessableEntity          = 422 // RFC 4918, 11.2
+	StatusLocked                       = 423 // RFC 4918, 11.3
+	StatusFailedDependency             = 424 // RFC 4918, 11.4
+	StatusUpgradeRequired              = 426 // RFC 7231, 6.5.15
+	StatusPreconditionRequired         = 428 // RFC 6585, 3
+	StatusTooManyRequests              = 429 // RFC 6585, 4
+	StatusRequestHeaderFieldsTooLarge  = 431 // RFC 6585, 5
+	StatusUnavailableForLegalReasons   = 451 // RFC 7725, 3
 
-	StatusInternalServerError           = 500
-	StatusNotImplemented                = 501
-	StatusBadGateway                    = 502
-	StatusServiceUnavailable            = 503
-	StatusGatewayTimeout                = 504
-	StatusHTTPVersionNotSupported       = 505
-	StatusNetworkAuthenticationRequired = 511
+	StatusInternalServerError           = 500 // RFC 7231, 6.6.1
+	StatusNotImplemented                = 501 // RFC 7231, 6.6.2
+	StatusBadGateway                    = 502 // RFC 7231, 6.6.3
+	StatusServiceUnavailable            = 503 // RFC 7231, 6.6.4
+	StatusGatewayTimeout                = 504 // RFC 7231, 6.6.5
+	StatusHTTPVersionNotSupported       = 505 // RFC 7231, 6.6.6
+	StatusVariantAlsoNegotiates         = 506 // RFC 2295, 8.1
+	StatusInsufficientStorage           = 507 // RFC 4918, 11.5
+	StatusLoopDetected                  = 508 // RFC 5842, 7.2
+	StatusNotExtended                   = 510 // RFC 2774, 7
+	StatusNetworkAuthenticationRequired = 511 // RFC 6585, 6
 )
 
 var statusText = map[int]string{
 	StatusContinue:           "Continue",
 	StatusSwitchingProtocols: "Switching Protocols",
+	StatusProcessing:         "Processing",
 
 	StatusOK:                   "OK",
 	StatusCreated:              "Created",
@@ -69,6 +85,9 @@ var statusText = map[int]string{
 	StatusNoContent:            "No Content",
 	StatusResetContent:         "Reset Content",
 	StatusPartialContent:       "Partial Content",
+	StatusMultiStatus:          "Multi-Status",
+	StatusAlreadyReported:      "Already Reported",
+	StatusIMUsed:               "IM Used",
 
 	StatusMultipleChoices:   "Multiple Choices",
 	StatusMovedPermanently:  "Moved Permanently",
@@ -77,6 +96,7 @@ var statusText = map[int]string{
 	StatusNotModified:       "Not Modified",
 	StatusUseProxy:          "Use Proxy",
 	StatusTemporaryRedirect: "Temporary Redirect",
+	StatusPermanentRedirect: "Permanent Redirect",
 
 	StatusBadRequest:                   "Bad Request",
 	StatusUnauthorized:                 "Unauthorized",
@@ -97,6 +117,10 @@ var statusText = map[int]string{
 	StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable",
 	StatusExpectationFailed:            "Expectation Failed",
 	StatusTeapot:                       "I'm a teapot",
+	StatusUnprocessableEntity:          "Unprocessable Entity",
+	StatusLocked:                       "Locked",
+	StatusFailedDependency:             "Failed Dependency",
+	StatusUpgradeRequired:              "Upgrade Required",
 	StatusPreconditionRequired:         "Precondition Required",
 	StatusTooManyRequests:              "Too Many Requests",
 	StatusRequestHeaderFieldsTooLarge:  "Request Header Fields Too Large",
@@ -108,6 +132,10 @@ var statusText = map[int]string{
 	StatusServiceUnavailable:            "Service Unavailable",
 	StatusGatewayTimeout:                "Gateway Timeout",
 	StatusHTTPVersionNotSupported:       "HTTP Version Not Supported",
+	StatusVariantAlsoNegotiates:         "Variant Also Negotiates",
+	StatusInsufficientStorage:           "Insufficient Storage",
+	StatusLoopDetected:                  "Loop Detected",
+	StatusNotExtended:                   "Not Extended",
 	StatusNetworkAuthenticationRequired: "Network Authentication Required",
 }
 
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index 6e59af8..b27ace6 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -17,6 +17,8 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+
+	"golang.org/x/net/lex/httplex"
 )
 
 // ErrLineTooLong is returned when reading request or response bodies
@@ -276,7 +278,7 @@ func (t *transferReader) protoAtLeast(m, n int) bool {
 }
 
 // bodyAllowedForStatus reports whether a given response status code
-// permits a body.  See RFC2616, section 4.4.
+// permits a body. See RFC 2616, section 4.4.
 func bodyAllowedForStatus(status int) bool {
 	switch {
 	case status >= 100 && status <= 199:
@@ -368,7 +370,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
 
 	// If there is no Content-Length or chunked Transfer-Encoding on a *Response
 	// and the status is not 1xx, 204 or 304, then the body is unbounded.
-	// See RFC2616, section 4.4.
+	// See RFC 2616, section 4.4.
 	switch msg.(type) {
 	case *Response:
 		if realLength == -1 &&
@@ -379,7 +381,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
 		}
 	}
 
-	// Prepare body reader.  ContentLength < 0 means chunked encoding
+	// Prepare body reader. ContentLength < 0 means chunked encoding
 	// or close connection when finished, since multipart is not supported yet
 	switch {
 	case chunked(t.TransferEncoding):
@@ -558,21 +560,19 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
 func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool {
 	if major < 1 {
 		return true
-	} else if major == 1 && minor == 0 {
-		vv := header["Connection"]
-		if headerValuesContainsToken(vv, "close") || !headerValuesContainsToken(vv, "keep-alive") {
-			return true
-		}
-		return false
-	} else {
-		if headerValuesContainsToken(header["Connection"], "close") {
-			if removeCloseHeader {
-				header.Del("Connection")
-			}
-			return true
-		}
 	}
-	return false
+
+	conv := header["Connection"]
+	hasClose := httplex.HeaderValuesContainsToken(conv, "close")
+	if major == 1 && minor == 0 {
+		return hasClose || !httplex.HeaderValuesContainsToken(conv, "keep-alive")
+	}
+
+	if hasClose && removeCloseHeader {
+		header.Del("Connection")
+	}
+
+	return hasClose
 }
 
 // Parse the trailer header
@@ -729,11 +729,11 @@ func (b *body) readTrailer() error {
 	}
 
 	// Make sure there's a header terminator coming up, to prevent
-	// a DoS with an unbounded size Trailer.  It's not easy to
+	// a DoS with an unbounded size Trailer. It's not easy to
 	// slip in a LimitReader here, as textproto.NewReader requires
-	// a concrete *bufio.Reader.  Also, we can't get all the way
+	// a concrete *bufio.Reader. Also, we can't get all the way
 	// back up to our conn's LimitedReader that *might* be backing
-	// this bufio.Reader.  Instead, a hack: we iteratively Peek up
+	// this bufio.Reader. Instead, a hack: we iteratively Peek up
 	// to the bufio.Reader's max size, looking for a double CRLF.
 	// This limits the trailer to the underlying buffer size, typically 4kB.
 	if !seeUpcomingDoubleCRLF(b.r) {
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 1e3ea11..f7904b4 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -12,17 +12,22 @@ package http
 import (
 	"bufio"
 	"compress/gzip"
+	"container/list"
+	"context"
 	"crypto/tls"
 	"errors"
 	"fmt"
 	"io"
 	"log"
 	"net"
+	"net/http/httptrace"
 	"net/url"
 	"os"
 	"strings"
 	"sync"
 	"time"
+
+	"golang.org/x/net/lex/httplex"
 )
 
 // DefaultTransport is the default implementation of Transport and is
@@ -32,10 +37,12 @@ import (
 // $no_proxy) environment variables.
 var DefaultTransport RoundTripper = &Transport{
 	Proxy: ProxyFromEnvironment,
-	Dial: (&net.Dialer{
+	DialContext: (&net.Dialer{
 		Timeout:   30 * time.Second,
 		KeepAlive: 30 * time.Second,
-	}).Dial,
+	}).DialContext,
+	MaxIdleConns:          100,
+	IdleConnTimeout:       90 * time.Second,
 	TLSHandshakeTimeout:   10 * time.Second,
 	ExpectContinueTimeout: 1 * time.Second,
 }
@@ -63,9 +70,10 @@ const DefaultMaxIdleConnsPerHost = 2
 // See the package docs for more about HTTP/2.
 type Transport struct {
 	idleMu     sync.Mutex
-	wantIdle   bool // user has requested to close all idle conns
-	idleConn   map[connectMethodKey][]*persistConn
+	wantIdle   bool                                // user has requested to close all idle conns
+	idleConn   map[connectMethodKey][]*persistConn // most recently used at end
 	idleConnCh map[connectMethodKey]chan *persistConn
+	idleLRU    connLRU
 
 	reqMu       sync.Mutex
 	reqCanceler map[*Request]func()
@@ -79,9 +87,16 @@ type Transport struct {
 	// If Proxy is nil or returns a nil *URL, no proxy is used.
 	Proxy func(*Request) (*url.URL, error)
 
-	// Dial specifies the dial function for creating unencrypted
-	// TCP connections.
-	// If Dial is nil, net.Dial is used.
+	// DialContext specifies the dial function for creating unencrypted TCP connections.
+	// If DialContext is nil (and the deprecated Dial below is also nil),
+	// then the transport dials using package net.
+	DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
+
+	// Dial specifies the dial function for creating unencrypted TCP connections.
+	//
+	// Deprecated: Use DialContext instead, which allows the transport
+	// to cancel dials as soon as they are no longer needed.
+	// If both are set, DialContext takes priority.
 	Dial func(network, addr string) (net.Conn, error)
 
 	// DialTLS specifies an optional dial function for creating
@@ -117,11 +132,21 @@ type Transport struct {
 	// uncompressed.
 	DisableCompression bool
 
+	// MaxIdleConns controls the maximum number of idle (keep-alive)
+	// connections across all hosts. Zero means no limit.
+	MaxIdleConns int
+
 	// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
-	// (keep-alive) to keep per-host.  If zero,
+	// (keep-alive) connections to keep per-host. If zero,
 	// DefaultMaxIdleConnsPerHost is used.
 	MaxIdleConnsPerHost int
 
+	// IdleConnTimeout is the maximum amount of time an idle
+	// (keep-alive) connection will remain idle before closing
+	// itself.
+	// Zero means no limit.
+	IdleConnTimeout time.Duration
+
 	// ResponseHeaderTimeout, if non-zero, specifies the amount of
 	// time to wait for a server's response headers after fully
 	// writing the request (including its body, if any). This
@@ -137,7 +162,7 @@ type Transport struct {
 
 	// TLSNextProto specifies how the Transport switches to an
 	// alternate protocol (such as HTTP/2) after a TLS NPN/ALPN
-	// protocol negotiation.  If Transport dials an TLS connection
+	// protocol negotiation. If Transport dials an TLS connection
 	// with a non-empty protocol name and TLSNextProto contains a
 	// map entry for that key (such as "h2"), then the func is
 	// called with the request's authority (such as "example.com"
@@ -146,13 +171,18 @@ type Transport struct {
 	// If TLSNextProto is nil, HTTP/2 support is enabled automatically.
 	TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper
 
+	// MaxResponseHeaderBytes specifies a limit on how many
+	// response bytes are allowed in the server's response
+	// header.
+	//
+	// Zero means to use a default limit.
+	MaxResponseHeaderBytes int64
+
 	// nextProtoOnce guards initialization of TLSNextProto and
 	// h2transport (via onceSetNextProtoDefaults)
 	nextProtoOnce sync.Once
 	h2transport   *http2Transport // non-nil if http2 wired up
 
-	// TODO: tunable on global max cached connections
-	// TODO: tunable on timeout on cached connections
 	// TODO: tunable on max per-host TCP dials in flight (Issue 13957)
 }
 
@@ -167,29 +197,34 @@ func (t *Transport) onceSetNextProtoDefaults() {
 		// Transport.
 		return
 	}
-	if t.TLSClientConfig != nil {
-		// Be conservative for now (for Go 1.6) at least and
-		// don't automatically enable http2 if they've
-		// specified a custom TLS config. Let them opt-in
-		// themselves via http2.ConfigureTransport so we don't
-		// surprise them by modifying their tls.Config.
-		// Issue 14275.
-		return
-	}
-	if t.ExpectContinueTimeout != 0 && t != DefaultTransport {
-		// ExpectContinueTimeout is unsupported in http2, so
-		// if they explicitly asked for it (as opposed to just
-		// using the DefaultTransport, which sets it), then
-		// disable http2 for now.
-		//
-		// Issue 13851. (and changed in Issue 14391)
+	if t.TLSClientConfig != nil || t.Dial != nil || t.DialTLS != nil {
+		// Be conservative and don't automatically enable
+		// http2 if they've specified a custom TLS config or
+		// custom dialers. Let them opt-in themselves via
+		// http2.ConfigureTransport so we don't surprise them
+		// by modifying their tls.Config. Issue 14275.
 		return
 	}
 	t2, err := http2configureTransport(t)
 	if err != nil {
 		log.Printf("Error enabling Transport HTTP/2 support: %v", err)
-	} else {
-		t.h2transport = t2
+		return
+	}
+	t.h2transport = t2
+
+	// Auto-configure the http2.Transport's MaxHeaderListSize from
+	// the http.Transport's MaxResponseHeaderBytes. They don't
+	// exactly mean the same thing, but they're close.
+	//
+	// TODO: also add this to x/net/http2.Configure Transport, behind
+	// a +build go1.7 build tag:
+	if limit1 := t.MaxResponseHeaderBytes; limit1 != 0 && t2.MaxHeaderListSize == 0 {
+		const h2max = 1<<32 - 1
+		if limit1 >= h2max {
+			t2.MaxHeaderListSize = h2max
+		} else {
+			t2.MaxHeaderListSize = uint32(limit1)
+		}
 	}
 }
 
@@ -249,8 +284,9 @@ func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
 // transportRequest is a wrapper around a *Request that adds
 // optional extra headers to write.
 type transportRequest struct {
-	*Request        // original request, not to be mutated
-	extra    Header // extra headers to write, or nil
+	*Request                        // original request, not to be mutated
+	extra    Header                 // extra headers to write, or nil
+	trace    *httptrace.ClientTrace // optional
 }
 
 func (tr *transportRequest) extraHeaders() Header {
@@ -266,6 +302,9 @@ func (tr *transportRequest) extraHeaders() Header {
 // and redirects), see Get, Post, and the Client type.
 func (t *Transport) RoundTrip(req *Request) (*Response, error) {
 	t.nextProtoOnce.Do(t.onceSetNextProtoDefaults)
+	ctx := req.Context()
+	trace := httptrace.ContextClientTrace(ctx)
+
 	if req.URL == nil {
 		req.closeBody()
 		return nil, errors.New("http: nil Request.URL")
@@ -274,18 +313,32 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
 		req.closeBody()
 		return nil, errors.New("http: nil Request.Header")
 	}
+	scheme := req.URL.Scheme
+	isHTTP := scheme == "http" || scheme == "https"
+	if isHTTP {
+		for k, vv := range req.Header {
+			if !httplex.ValidHeaderFieldName(k) {
+				return nil, fmt.Errorf("net/http: invalid header field name %q", k)
+			}
+			for _, v := range vv {
+				if !httplex.ValidHeaderFieldValue(v) {
+					return nil, fmt.Errorf("net/http: invalid header field value %q for key %v", v, k)
+				}
+			}
+		}
+	}
 	// TODO(bradfitz): switch to atomic.Value for this map instead of RWMutex
 	t.altMu.RLock()
-	altRT := t.altProto[req.URL.Scheme]
+	altRT := t.altProto[scheme]
 	t.altMu.RUnlock()
 	if altRT != nil {
 		if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol {
 			return resp, err
 		}
 	}
-	if s := req.URL.Scheme; s != "http" && s != "https" {
+	if !isHTTP {
 		req.closeBody()
-		return nil, &badStringError{"unsupported protocol scheme", s}
+		return nil, &badStringError{"unsupported protocol scheme", scheme}
 	}
 	if req.Method != "" && !validMethod(req.Method) {
 		return nil, fmt.Errorf("net/http: invalid method %q", req.Method)
@@ -297,7 +350,7 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
 
 	for {
 		// treq gets modified by roundTrip, so we need to recreate for each retry.
-		treq := &transportRequest{Request: req}
+		treq := &transportRequest{Request: req, trace: trace}
 		cm, err := t.connectMethodForRequest(treq)
 		if err != nil {
 			req.closeBody()
@@ -306,9 +359,9 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
 
 		// Get the cached or newly-created connection to either the
 		// host (for http or https), the http proxy, or the http proxy
-		// pre-CONNECTed to https server.  In any case, we'll be ready
+		// pre-CONNECTed to https server. In any case, we'll be ready
 		// to send it requests.
-		pconn, err := t.getConn(req, cm)
+		pconn, err := t.getConn(treq, cm)
 		if err != nil {
 			t.setReqCanceler(req, nil)
 			req.closeBody()
@@ -326,46 +379,47 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
 		if err == nil {
 			return resp, nil
 		}
-		if err := checkTransportResend(err, req, pconn); err != nil {
+		if !pconn.shouldRetryRequest(req, err) {
 			return nil, err
 		}
 		testHookRoundTripRetried()
 	}
 }
 
-// checkTransportResend checks whether a failed HTTP request can be
-// resent on a new connection. The non-nil input error is the error from
-// roundTrip, which might be wrapped in a beforeRespHeaderError error.
-//
-// The return value is err or the unwrapped error inside a
-// beforeRespHeaderError.
-func checkTransportResend(err error, req *Request, pconn *persistConn) error {
-	brhErr, ok := err.(beforeRespHeaderError)
-	if !ok {
-		return err
+// shouldRetryRequest reports whether we should retry sending a failed
+// HTTP request on a new connection. The non-nil input error is the
+// error from roundTrip.
+func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool {
+	if err == errMissingHost {
+		// User error.
+		return false
 	}
-	err = brhErr.error // unwrap the custom error in case we return it
-	if err != errMissingHost && pconn.isReused() && req.isReplayable() {
-		// If we try to reuse a connection that the server is in the process of
-		// closing, we may end up successfully writing out our request (or a
-		// portion of our request) only to find a connection error when we try to
-		// read from (or finish writing to) the socket.
-
-		// There can be a race between the socket pool checking whether a socket
-		// is still connected, receiving the FIN, and sending/reading data on a
-		// reused socket. If we receive the FIN between the connectedness check
-		// and writing/reading from the socket, we may first learn the socket is
-		// disconnected when we get a ERR_SOCKET_NOT_CONNECTED. This will most
-		// likely happen when trying to retrieve its IP address. See
-		// http://crbug.com/105824 for more details.
-
-		// We resend a request only if we reused a keep-alive connection and did
-		// not yet receive any header data. This automatically prevents an
-		// infinite resend loop because we'll run out of the cached keep-alive
-		// connections eventually.
-		return nil
+	if !pc.isReused() {
+		// This was a fresh connection. There's no reason the server
+		// should've hung up on us.
+		//
+		// Also, if we retried now, we could loop forever
+		// creating new connections and retrying if the server
+		// is just hanging up on us because it doesn't like
+		// our request (as opposed to sending an error).
+		return false
 	}
-	return err
+	if !req.isReplayable() {
+		// Don't retry non-idempotent requests.
+
+		// TODO: swap the nothingWrittenError and isReplayable checks,
+		// putting the "if nothingWrittenError => return true" case
+		// first, per golang.org/issue/15723
+		return false
+	}
+	if _, ok := err.(nothingWrittenError); ok {
+		// We never wrote anything, so it's safe to retry.
+		return true
+	}
+	if err == errServerClosedIdle || err == errServerClosedConn {
+		return true
+	}
+	return false // conservatively
 }
 
 // ErrSkipAltProtocol is a sentinel error value defined by Transport.RegisterProtocol.
@@ -404,6 +458,7 @@ func (t *Transport) CloseIdleConnections() {
 	t.idleConn = nil
 	t.idleConnCh = nil
 	t.wantIdle = true
+	t.idleLRU = connLRU{}
 	t.idleMu.Unlock()
 	for _, conns := range m {
 		for _, pconn := range conns {
@@ -418,7 +473,7 @@ func (t *Transport) CloseIdleConnections() {
 // CancelRequest cancels an in-flight request by closing its connection.
 // CancelRequest should only be called after RoundTrip has returned.
 //
-// Deprecated: Use Request.Cancel instead. CancelRequest can not cancel
+// Deprecated: Use Request.Cancel instead. CancelRequest cannot cancel
 // HTTP/2 requests.
 func (t *Transport) CancelRequest(req *Request) {
 	t.reqMu.Lock()
@@ -504,9 +559,12 @@ var (
 	errConnBroken         = errors.New("http: putIdleConn: connection is in bad state")
 	errWantIdle           = errors.New("http: putIdleConn: CloseIdleConnections was called")
 	errTooManyIdle        = errors.New("http: putIdleConn: too many idle connections")
+	errTooManyIdleHost    = errors.New("http: putIdleConn: too many idle connections for host")
 	errCloseIdleConns     = errors.New("http: CloseIdleConnections called")
 	errReadLoopExiting    = errors.New("http: persistConn.readLoop exiting")
-	errServerClosedIdle   = errors.New("http: server closed idle conn")
+	errServerClosedIdle   = errors.New("http: server closed idle connection")
+	errServerClosedConn   = errors.New("http: server closed connection")
+	errIdleConnTimeout    = errors.New("http: idle connection timeout")
 )
 
 func (t *Transport) putOrCloseIdleConn(pconn *persistConn) {
@@ -515,6 +573,13 @@ func (t *Transport) putOrCloseIdleConn(pconn *persistConn) {
 	}
 }
 
+func (t *Transport) maxIdleConnsPerHost() int {
+	if v := t.MaxIdleConnsPerHost; v != 0 {
+		return v
+	}
+	return DefaultMaxIdleConnsPerHost
+}
+
 // tryPutIdleConn adds pconn to the list of idle persistent connections awaiting
 // a new request.
 // If pconn is no longer needed or not in a good state, tryPutIdleConn returns
@@ -527,13 +592,11 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
 	if pconn.isBroken() {
 		return errConnBroken
 	}
-	key := pconn.cacheKey
-	max := t.MaxIdleConnsPerHost
-	if max == 0 {
-		max = DefaultMaxIdleConnsPerHost
-	}
 	pconn.markReused()
+	key := pconn.cacheKey
+
 	t.idleMu.Lock()
+	defer t.idleMu.Unlock()
 
 	waitingDialer := t.idleConnCh[key]
 	select {
@@ -541,9 +604,8 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
 		// We're done with this pconn and somebody else is
 		// currently waiting for a conn of this type (they're
 		// actively dialing, but this conn is ready
-		// first). Chrome calls this socket late binding.  See
+		// first). Chrome calls this socket late binding. See
 		// https://insouciant.org/tech/connection-management-in-chromium/
-		t.idleMu.Unlock()
 		return nil
 	default:
 		if waitingDialer != nil {
@@ -553,23 +615,35 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
 		}
 	}
 	if t.wantIdle {
-		t.idleMu.Unlock()
 		return errWantIdle
 	}
 	if t.idleConn == nil {
 		t.idleConn = make(map[connectMethodKey][]*persistConn)
 	}
-	if len(t.idleConn[key]) >= max {
-		t.idleMu.Unlock()
-		return errTooManyIdle
+	idles := t.idleConn[key]
+	if len(idles) >= t.maxIdleConnsPerHost() {
+		return errTooManyIdleHost
 	}
-	for _, exist := range t.idleConn[key] {
+	for _, exist := range idles {
 		if exist == pconn {
 			log.Fatalf("dup idle pconn %p in freelist", pconn)
 		}
 	}
-	t.idleConn[key] = append(t.idleConn[key], pconn)
-	t.idleMu.Unlock()
+	t.idleConn[key] = append(idles, pconn)
+	t.idleLRU.add(pconn)
+	if t.MaxIdleConns != 0 && t.idleLRU.len() > t.MaxIdleConns {
+		oldest := t.idleLRU.removeOldest()
+		oldest.close(errTooManyIdle)
+		t.removeIdleConnLocked(oldest)
+	}
+	if t.IdleConnTimeout > 0 {
+		if pconn.idleTimer != nil {
+			pconn.idleTimer.Reset(t.IdleConnTimeout)
+		} else {
+			pconn.idleTimer = time.AfterFunc(t.IdleConnTimeout, pconn.closeConnIfStillIdle)
+		}
+	}
+	pconn.idleAt = time.Now()
 	return nil
 }
 
@@ -595,29 +669,75 @@ func (t *Transport) getIdleConnCh(cm connectMethod) chan *persistConn {
 	return ch
 }
 
-func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn) {
+func (t *Transport) getIdleConn(cm connectMethod) (pconn *persistConn, idleSince time.Time) {
 	key := cm.key()
 	t.idleMu.Lock()
 	defer t.idleMu.Unlock()
-	if t.idleConn == nil {
-		return nil
-	}
 	for {
 		pconns, ok := t.idleConn[key]
 		if !ok {
-			return nil
+			return nil, time.Time{}
 		}
 		if len(pconns) == 1 {
 			pconn = pconns[0]
 			delete(t.idleConn, key)
 		} else {
-			// 2 or more cached connections; pop last
-			// TODO: queue?
+			// 2 or more cached connections; use the most
+			// recently used one at the end.
 			pconn = pconns[len(pconns)-1]
 			t.idleConn[key] = pconns[:len(pconns)-1]
 		}
-		if !pconn.isBroken() {
-			return
+		t.idleLRU.remove(pconn)
+		if pconn.isBroken() {
+			// There is a tiny window where this is
+			// possible, between the connecting dying and
+			// the persistConn readLoop calling
+			// Transport.removeIdleConn. Just skip it and
+			// carry on.
+			continue
+		}
+		if pconn.idleTimer != nil && !pconn.idleTimer.Stop() {
+			// We picked this conn at the ~same time it
+			// was expiring and it's trying to close
+			// itself in another goroutine. Don't use it.
+			continue
+		}
+		return pconn, pconn.idleAt
+	}
+}
+
+// removeIdleConn marks pconn as dead.
+func (t *Transport) removeIdleConn(pconn *persistConn) {
+	t.idleMu.Lock()
+	defer t.idleMu.Unlock()
+	t.removeIdleConnLocked(pconn)
+}
+
+// t.idleMu must be held.
+func (t *Transport) removeIdleConnLocked(pconn *persistConn) {
+	if pconn.idleTimer != nil {
+		pconn.idleTimer.Stop()
+	}
+	t.idleLRU.remove(pconn)
+	key := pconn.cacheKey
+	pconns, _ := t.idleConn[key]
+	switch len(pconns) {
+	case 0:
+		// Nothing
+	case 1:
+		if pconns[0] == pconn {
+			delete(t.idleConn, key)
+		}
+	default:
+		for i, v := range pconns {
+			if v != pconn {
+				continue
+			}
+			// Slide down, keeping most recently-used
+			// conns at the end.
+			copy(pconns[i:], pconns[i+1:])
+			t.idleConn[key] = pconns[:len(pconns)-1]
+			break
 		}
 	}
 }
@@ -654,7 +774,12 @@ func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool {
 	return true
 }
 
-func (t *Transport) dial(network, addr string) (net.Conn, error) {
+var zeroDialer net.Dialer
+
+func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, error) {
+	if t.DialContext != nil {
+		return t.DialContext(ctx, network, addr)
+	}
 	if t.Dial != nil {
 		c, err := t.Dial(network, addr)
 		if c == nil && err == nil {
@@ -662,15 +787,24 @@ func (t *Transport) dial(network, addr string) (net.Conn, error) {
 		}
 		return c, err
 	}
-	return net.Dial(network, addr)
+	return zeroDialer.DialContext(ctx, network, addr)
 }
 
 // getConn dials and creates a new persistConn to the target as
-// specified in the connectMethod.  This includes doing a proxy CONNECT
+// specified in the connectMethod. This includes doing a proxy CONNECT
 // and/or setting up TLS.  If this doesn't return an error, the persistConn
 // is ready to write requests to.
-func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) {
-	if pc := t.getIdleConn(cm); pc != nil {
+func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistConn, error) {
+	req := treq.Request
+	trace := treq.trace
+	ctx := req.Context()
+	if trace != nil && trace.GetConn != nil {
+		trace.GetConn(cm.addr())
+	}
+	if pc, idleSince := t.getIdleConn(cm); pc != nil {
+		if trace != nil && trace.GotConn != nil {
+			trace.GotConn(pc.gotIdleConnTrace(idleSince))
+		}
 		// set request canceler to some non-nil function so we
 		// can detect whether it was cleared between now and when
 		// we enter roundTrip
@@ -703,7 +837,7 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
 	t.setReqCanceler(req, func() { close(cancelc) })
 
 	go func() {
-		pc, err := t.dialConn(cm)
+		pc, err := t.dialConn(ctx, cm)
 		dialc <- dialRes{pc, err}
 	}()
 
@@ -711,7 +845,26 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
 	select {
 	case v := <-dialc:
 		// Our dial finished.
-		return v.pc, v.err
+		if v.pc != nil {
+			if trace != nil && trace.GotConn != nil && v.pc.alt == nil {
+				trace.GotConn(httptrace.GotConnInfo{Conn: v.pc.conn})
+			}
+			return v.pc, nil
+		}
+		// Our dial failed. See why to return a nicer error
+		// value.
+		select {
+		case <-req.Cancel:
+		case <-req.Context().Done():
+		case <-cancelc:
+		default:
+			// It wasn't an error due to cancelation, so
+			// return the original error message:
+			return nil, v.err
+		}
+		// It was an error due to cancelation, so prioritize that
+		// error value. (Issue 16049)
+		return nil, errRequestCanceledConn
 	case pc := <-idleConnCh:
 		// Another request finished first and its net.Conn
 		// became available before our dial. Or somebody
@@ -719,24 +872,31 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
 		// But our dial is still going, so give it away
 		// when it finishes:
 		handlePendingDial()
+		if trace != nil && trace.GotConn != nil {
+			trace.GotConn(httptrace.GotConnInfo{Conn: pc.conn, Reused: pc.isReused()})
+		}
 		return pc, nil
 	case <-req.Cancel:
 		handlePendingDial()
 		return nil, errRequestCanceledConn
+	case <-req.Context().Done():
+		handlePendingDial()
+		return nil, errRequestCanceledConn
 	case <-cancelc:
 		handlePendingDial()
 		return nil, errRequestCanceledConn
 	}
 }
 
-func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
+func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistConn, error) {
 	pconn := &persistConn{
-		t:          t,
-		cacheKey:   cm.key(),
-		reqch:      make(chan requestAndChan, 1),
-		writech:    make(chan writeRequest, 1),
-		closech:    make(chan struct{}),
-		writeErrCh: make(chan error, 1),
+		t:             t,
+		cacheKey:      cm.key(),
+		reqch:         make(chan requestAndChan, 1),
+		writech:       make(chan writeRequest, 1),
+		closech:       make(chan struct{}),
+		writeErrCh:    make(chan error, 1),
+		writeLoopDone: make(chan struct{}),
 	}
 	tlsDial := t.DialTLS != nil && cm.targetScheme == "https" && cm.proxyURL == nil
 	if tlsDial {
@@ -759,7 +919,7 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
 			pconn.tlsState = &cs
 		}
 	} else {
-		conn, err := t.dial("tcp", cm.addr())
+		conn, err := t.dial(ctx, "tcp", cm.addr())
 		if err != nil {
 			if cm.proxyURL != nil {
 				err = fmt.Errorf("http: error connecting to proxy %s: %v", cm.proxyURL, err)
@@ -852,13 +1012,29 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
 		}
 	}
 
-	pconn.br = bufio.NewReader(noteEOFReader{pconn.conn, &pconn.sawEOF})
-	pconn.bw = bufio.NewWriter(pconn.conn)
+	pconn.br = bufio.NewReader(pconn)
+	pconn.bw = bufio.NewWriter(persistConnWriter{pconn})
 	go pconn.readLoop()
 	go pconn.writeLoop()
 	return pconn, nil
 }
 
+// persistConnWriter is the io.Writer written to by pc.bw.
+// It accumulates the number of bytes written to the underlying conn,
+// so the retry logic can determine whether any bytes made it across
+// the wire.
+// This is exactly 1 pointer field wide so it can go into an interface
+// without allocation.
+type persistConnWriter struct {
+	pc *persistConn
+}
+
+func (w persistConnWriter) Write(p []byte) (n int, err error) {
+	n, err = w.pc.conn.Write(p)
+	w.pc.nwrite += int64(n)
+	return
+}
+
 // 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.
@@ -982,28 +1158,36 @@ func (k connectMethodKey) String() string {
 // (but may be used for non-keep-alive requests as well)
 type persistConn struct {
 	// alt optionally specifies the TLS NextProto RoundTripper.
-	// This is used for HTTP/2 today and future protocol laters.
+	// This is used for HTTP/2 today and future protocols later.
 	// If it's non-nil, the rest of the fields are unused.
 	alt RoundTripper
 
-	t        *Transport
-	cacheKey connectMethodKey
-	conn     net.Conn
-	tlsState *tls.ConnectionState
-	br       *bufio.Reader       // from conn
-	sawEOF   bool                // whether we've seen EOF from conn; owned by readLoop
-	bw       *bufio.Writer       // to conn
-	reqch    chan requestAndChan // written by roundTrip; read by readLoop
-	writech  chan writeRequest   // written by roundTrip; read by writeLoop
-	closech  chan struct{}       // closed when conn closed
-	isProxy  bool
+	t         *Transport
+	cacheKey  connectMethodKey
+	conn      net.Conn
+	tlsState  *tls.ConnectionState
+	br        *bufio.Reader       // from conn
+	bw        *bufio.Writer       // to conn
+	nwrite    int64               // bytes written
+	reqch     chan requestAndChan // written by roundTrip; read by readLoop
+	writech   chan writeRequest   // written by roundTrip; read by writeLoop
+	closech   chan struct{}       // closed when conn closed
+	isProxy   bool
+	sawEOF    bool  // whether we've seen EOF from conn; owned by readLoop
+	readLimit int64 // bytes allowed to be read; owned by readLoop
 	// writeErrCh passes the request write error (usually nil)
 	// from the writeLoop goroutine to the readLoop which passes
 	// it off to the res.Body reader, which then uses it to decide
 	// whether or not a connection can be reused. Issue 7569.
 	writeErrCh chan error
 
-	lk                   sync.Mutex // guards following fields
+	writeLoopDone chan struct{} // closed when write loop ends
+
+	// Both guarded by Transport.idleMu:
+	idleAt    time.Time   // time it last become idle
+	idleTimer *time.Timer // holding an AfterFunc to close it
+
+	mu                   sync.Mutex // guards following fields
 	numExpectedResponses int
 	closed               error // set non-nil when conn is closed, before closech is closed
 	broken               bool  // an error has happened on this connection; marked broken so it's not reused.
@@ -1015,45 +1199,153 @@ type persistConn struct {
 	mutateHeaderFunc func(Header)
 }
 
+func (pc *persistConn) maxHeaderResponseSize() int64 {
+	if v := pc.t.MaxResponseHeaderBytes; v != 0 {
+		return v
+	}
+	return 10 << 20 // conservative default; same as http2
+}
+
+func (pc *persistConn) Read(p []byte) (n int, err error) {
+	if pc.readLimit <= 0 {
+		return 0, fmt.Errorf("read limit of %d bytes exhausted", pc.maxHeaderResponseSize())
+	}
+	if int64(len(p)) > pc.readLimit {
+		p = p[:pc.readLimit]
+	}
+	n, err = pc.conn.Read(p)
+	if err == io.EOF {
+		pc.sawEOF = true
+	}
+	pc.readLimit -= int64(n)
+	return
+}
+
 // isBroken reports whether this connection is in a known broken state.
 func (pc *persistConn) isBroken() bool {
-	pc.lk.Lock()
-	b := pc.broken
-	pc.lk.Unlock()
+	pc.mu.Lock()
+	b := pc.closed != nil
+	pc.mu.Unlock()
 	return b
 }
 
 // isCanceled reports whether this connection was closed due to CancelRequest.
 func (pc *persistConn) isCanceled() bool {
-	pc.lk.Lock()
-	defer pc.lk.Unlock()
+	pc.mu.Lock()
+	defer pc.mu.Unlock()
 	return pc.canceled
 }
 
 // isReused reports whether this connection is in a known broken state.
 func (pc *persistConn) isReused() bool {
-	pc.lk.Lock()
+	pc.mu.Lock()
 	r := pc.reused
-	pc.lk.Unlock()
+	pc.mu.Unlock()
 	return r
 }
 
+func (pc *persistConn) gotIdleConnTrace(idleAt time.Time) (t httptrace.GotConnInfo) {
+	pc.mu.Lock()
+	defer pc.mu.Unlock()
+	t.Reused = pc.reused
+	t.Conn = pc.conn
+	t.WasIdle = true
+	if !idleAt.IsZero() {
+		t.IdleTime = time.Since(idleAt)
+	}
+	return
+}
+
 func (pc *persistConn) cancelRequest() {
-	pc.lk.Lock()
-	defer pc.lk.Unlock()
+	pc.mu.Lock()
+	defer pc.mu.Unlock()
 	pc.canceled = true
 	pc.closeLocked(errRequestCanceled)
 }
 
+// closeConnIfStillIdle closes the connection if it's still sitting idle.
+// This is what's called by the persistConn's idleTimer, and is run in its
+// own goroutine.
+func (pc *persistConn) closeConnIfStillIdle() {
+	t := pc.t
+	t.idleMu.Lock()
+	defer t.idleMu.Unlock()
+	if _, ok := t.idleLRU.m[pc]; !ok {
+		// Not idle.
+		return
+	}
+	t.removeIdleConnLocked(pc)
+	pc.close(errIdleConnTimeout)
+}
+
+// mapRoundTripErrorFromReadLoop maps the provided readLoop error into
+// the error value that should be returned from persistConn.roundTrip.
+//
+// The startBytesWritten value should be the value of pc.nwrite before the roundTrip
+// started writing the request.
+func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, err error) (out error) {
+	if err == nil {
+		return nil
+	}
+	if pc.isCanceled() {
+		return errRequestCanceled
+	}
+	if err == errServerClosedIdle || err == errServerClosedConn {
+		return err
+	}
+	if pc.isBroken() {
+		<-pc.writeLoopDone
+		if pc.nwrite == startBytesWritten {
+			return nothingWrittenError{err}
+		}
+	}
+	return err
+}
+
+// mapRoundTripErrorAfterClosed returns the error value to be propagated
+// up to Transport.RoundTrip method when persistConn.roundTrip sees
+// its pc.closech channel close, indicating the persistConn is dead.
+// (after closech is closed, pc.closed is valid).
+func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) error {
+	if pc.isCanceled() {
+		return errRequestCanceled
+	}
+	err := pc.closed
+	if err == errServerClosedIdle || err == errServerClosedConn {
+		// Don't decorate
+		return err
+	}
+
+	// Wait for the writeLoop goroutine to terminated, and then
+	// see if we actually managed to write anything. If not, we
+	// can retry the request.
+	<-pc.writeLoopDone
+	if pc.nwrite == startBytesWritten {
+		return nothingWrittenError{err}
+	}
+
+	return fmt.Errorf("net/http: HTTP/1.x transport connection broken: %v", err)
+
+}
+
 func (pc *persistConn) readLoop() {
 	closeErr := errReadLoopExiting // default value, if not changed below
-	defer func() { pc.close(closeErr) }()
+	defer func() {
+		pc.close(closeErr)
+		pc.t.removeIdleConn(pc)
+	}()
 
-	tryPutIdleConn := func() bool {
+	tryPutIdleConn := func(trace *httptrace.ClientTrace) bool {
 		if err := pc.t.tryPutIdleConn(pc); err != nil {
 			closeErr = err
+			if trace != nil && trace.PutIdleConn != nil && err != errKeepAlivesDisabled {
+				trace.PutIdleConn(err)
+			}
 			return false
 		}
+		if trace != nil && trace.PutIdleConn != nil {
+			trace.PutIdleConn(nil)
+		}
 		return true
 	}
 
@@ -1070,27 +1362,33 @@ func (pc *persistConn) readLoop() {
 
 	alive := true
 	for alive {
+		pc.readLimit = pc.maxHeaderResponseSize()
 		_, err := pc.br.Peek(1)
-		if err != nil {
-			err = beforeRespHeaderError{err}
-		}
 
-		pc.lk.Lock()
+		pc.mu.Lock()
 		if pc.numExpectedResponses == 0 {
 			pc.readLoopPeekFailLocked(err)
-			pc.lk.Unlock()
+			pc.mu.Unlock()
 			return
 		}
-		pc.lk.Unlock()
+		pc.mu.Unlock()
 
 		rc := <-pc.reqch
+		trace := httptrace.ContextClientTrace(rc.req.Context())
 
 		var resp *Response
 		if err == nil {
-			resp, err = pc.readResponse(rc)
+			resp, err = pc.readResponse(rc, trace)
+		} else {
+			err = errServerClosedConn
+			closeErr = err
 		}
 
 		if err != nil {
+			if pc.readLimit <= 0 {
+				err = fmt.Errorf("net/http: server response headers exceeded %d bytes; aborted", pc.maxHeaderResponseSize())
+			}
+
 			// If we won't be able to retry this request later (from the
 			// roundTrip goroutine), mark it as done now.
 			// BEFORE the send on rc.ch, as the client might re-use the
@@ -1098,7 +1396,7 @@ func (pc *persistConn) readLoop() {
 			// t.setReqCanceler from this persistConn while the Transport
 			// potentially spins up a different persistConn for the
 			// caller's subsequent request.
-			if checkTransportResend(err, rc.req, pc) != nil {
+			if !pc.shouldRetryRequest(rc.req, err) {
 				pc.t.setReqCanceler(rc.req, nil)
 			}
 			select {
@@ -1108,10 +1406,11 @@ func (pc *persistConn) readLoop() {
 			}
 			return
 		}
+		pc.readLimit = maxInt64 // effictively no limit for response bodies
 
-		pc.lk.Lock()
+		pc.mu.Lock()
 		pc.numExpectedResponses--
-		pc.lk.Unlock()
+		pc.mu.Unlock()
 
 		hasBody := rc.req.Method != "HEAD" && resp.ContentLength != 0
 
@@ -1134,7 +1433,7 @@ func (pc *persistConn) readLoop() {
 			alive = alive &&
 				!pc.sawEOF &&
 				pc.wroteRequest() &&
-				tryPutIdleConn()
+				tryPutIdleConn(trace)
 
 			select {
 			case rc.ch <- responseAndError{res: resp}:
@@ -1149,25 +1448,33 @@ func (pc *persistConn) readLoop() {
 			continue
 		}
 
-		if rc.addedGzip {
-			maybeUngzipResponse(resp)
+		waitForBodyRead := make(chan bool, 2)
+		body := &bodyEOFSignal{
+			body: resp.Body,
+			earlyCloseFn: func() error {
+				waitForBodyRead <- false
+				return nil
+
+			},
+			fn: func(err error) error {
+				isEOF := err == io.EOF
+				waitForBodyRead <- isEOF
+				if isEOF {
+					<-eofc // see comment above eofc declaration
+				} else if err != nil && pc.isCanceled() {
+					return errRequestCanceled
+				}
+				return err
+			},
 		}
-		resp.Body = &bodyEOFSignal{body: resp.Body}
 
-		waitForBodyRead := make(chan bool, 2)
-		resp.Body.(*bodyEOFSignal).earlyCloseFn = func() error {
-			waitForBodyRead <- false
-			return nil
-		}
-		resp.Body.(*bodyEOFSignal).fn = func(err error) error {
-			isEOF := err == io.EOF
-			waitForBodyRead <- isEOF
-			if isEOF {
-				<-eofc // see comment above eofc declaration
-			} else if err != nil && pc.isCanceled() {
-				return errRequestCanceled
-			}
-			return err
+		resp.Body = body
+		if rc.addedGzip && resp.Header.Get("Content-Encoding") == "gzip" {
+			resp.Body = &gzipReader{body: body}
+			resp.Header.Del("Content-Encoding")
+			resp.Header.Del("Content-Length")
+			resp.ContentLength = -1
+			resp.Uncompressed = true
 		}
 
 		select {
@@ -1186,13 +1493,16 @@ func (pc *persistConn) readLoop() {
 				bodyEOF &&
 				!pc.sawEOF &&
 				pc.wroteRequest() &&
-				tryPutIdleConn()
+				tryPutIdleConn(trace)
 			if bodyEOF {
 				eofc <- struct{}{}
 			}
 		case <-rc.req.Cancel:
 			alive = false
 			pc.t.CancelRequest(rc.req)
+		case <-rc.req.Context().Done():
+			alive = false
+			pc.t.CancelRequest(rc.req)
 		case <-pc.closech:
 			alive = false
 		}
@@ -1201,15 +1511,6 @@ func (pc *persistConn) readLoop() {
 	}
 }
 
-func maybeUngzipResponse(resp *Response) {
-	if resp.Header.Get("Content-Encoding") == "gzip" {
-		resp.Header.Del("Content-Encoding")
-		resp.Header.Del("Content-Length")
-		resp.ContentLength = -1
-		resp.Body = &gzipReader{body: resp.Body}
-	}
-}
-
 func (pc *persistConn) readLoopPeekFailLocked(peekErr error) {
 	if pc.closed != nil {
 		return
@@ -1228,19 +1529,29 @@ func (pc *persistConn) readLoopPeekFailLocked(peekErr error) {
 
 // readResponse reads an HTTP response (or two, in the case of "Expect:
 // 100-continue") from the server. It returns the final non-100 one.
-func (pc *persistConn) readResponse(rc requestAndChan) (resp *Response, err error) {
+// trace is optional.
+func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTrace) (resp *Response, err error) {
+	if trace != nil && trace.GotFirstResponseByte != nil {
+		if peek, err := pc.br.Peek(1); err == nil && len(peek) == 1 {
+			trace.GotFirstResponseByte()
+		}
+	}
 	resp, err = ReadResponse(pc.br, rc.req)
 	if err != nil {
 		return
 	}
 	if rc.continueCh != nil {
 		if resp.StatusCode == 100 {
+			if trace != nil && trace.Got100Continue != nil {
+				trace.Got100Continue()
+			}
 			rc.continueCh <- struct{}{}
 		} else {
 			close(rc.continueCh)
 		}
 	}
 	if resp.StatusCode == 100 {
+		pc.readLimit = pc.maxHeaderResponseSize() // reset the limit
 		resp, err = ReadResponse(pc.br, rc.req)
 		if err != nil {
 			return
@@ -1272,24 +1583,33 @@ func (pc *persistConn) waitForContinue(continueCh <-chan struct{}) func() bool {
 	}
 }
 
+// nothingWrittenError wraps a write errors which ended up writing zero bytes.
+type nothingWrittenError struct {
+	error
+}
+
 func (pc *persistConn) writeLoop() {
+	defer close(pc.writeLoopDone)
 	for {
 		select {
 		case wr := <-pc.writech:
-			if pc.isBroken() {
-				wr.ch <- errors.New("http: can't write HTTP request on broken connection")
-				continue
-			}
+			startBytesWritten := pc.nwrite
 			err := wr.req.Request.write(pc.bw, pc.isProxy, wr.req.extra, pc.waitForContinue(wr.continueCh))
 			if err == nil {
 				err = pc.bw.Flush()
 			}
 			if err != nil {
-				pc.markBroken()
 				wr.req.Request.closeBody()
+				if pc.nwrite == startBytesWritten {
+					err = nothingWrittenError{err}
+				}
 			}
 			pc.writeErrCh <- err // to the body reader, which might recycle us
 			wr.ch <- err         // to the roundTrip function
+			if err != nil {
+				pc.close(err)
+				return
+			}
 		case <-pc.closech:
 			return
 		}
@@ -1335,9 +1655,9 @@ type requestAndChan struct {
 	req *Request
 	ch  chan responseAndError // unbuffered; always send in select on callerGone
 
-	// did the Transport (as opposed to the client code) add an
-	// Accept-Encoding gzip header? only if it we set it do
-	// we transparently decode the gzip.
+	// whether the Transport (as opposed to the user client code)
+	// added the Accept-Encoding gzip header. If the Transport
+	// set it, only then do we transparently decode the gzip.
 	addedGzip bool
 
 	// Optional blocking chan for Expect: 100-continue (for send).
@@ -1357,7 +1677,7 @@ type writeRequest struct {
 	req *transportRequest
 	ch  chan<- error
 
-	// Optional blocking chan for Expect: 100-continue (for recieve).
+	// Optional blocking chan for Expect: 100-continue (for receive).
 	// If not nil, writeLoop blocks sending request body until
 	// it receives from this chan.
 	continueCh <-chan struct{}
@@ -1373,7 +1693,6 @@ func (e *httpError) Timeout() bool   { return e.timeout }
 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: server closed connection before response was received"}
 var errRequestCanceled = errors.New("net/http: request canceled")
 var errRequestCanceledConn = errors.New("net/http: request canceled while waiting for connection") // TODO: unify?
 
@@ -1391,22 +1710,16 @@ var (
 	testHookReadLoopBeforeNextRead             = nop
 )
 
-// beforeRespHeaderError is used to indicate when an IO error has occurred before
-// any header data was received.
-type beforeRespHeaderError struct {
-	error
-}
-
 func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
 	testHookEnterRoundTrip()
 	if !pc.t.replaceReqCanceler(req.Request, pc.cancelRequest) {
 		pc.t.putOrCloseIdleConn(pc)
 		return nil, errRequestCanceled
 	}
-	pc.lk.Lock()
+	pc.mu.Lock()
 	pc.numExpectedResponses++
 	headerFn := pc.mutateHeaderFunc
-	pc.lk.Unlock()
+	pc.mu.Unlock()
 
 	if headerFn != nil {
 		headerFn(req.extraHeaders())
@@ -1452,6 +1765,7 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
 	// Write the request concurrently with waiting for a response,
 	// in case the server decides to reply before reading our full
 	// request body.
+	startBytesWritten := pc.nwrite
 	writeErrCh := make(chan error, 1)
 	pc.writech <- writeRequest{req, writeErrCh, continueCh}
 
@@ -1476,7 +1790,7 @@ WaitResponse:
 				if pc.isCanceled() {
 					err = errRequestCanceled
 				}
-				re = responseAndError{err: beforeRespHeaderError{err}}
+				re = responseAndError{err: err}
 				pc.close(fmt.Errorf("write error: %v", err))
 				break WaitResponse
 			}
@@ -1486,26 +1800,21 @@ WaitResponse:
 				respHeaderTimer = timer.C
 			}
 		case <-pc.closech:
-			var err error
-			if pc.isCanceled() {
-				err = errRequestCanceled
-			} else {
-				err = beforeRespHeaderError{fmt.Errorf("net/http: HTTP/1 transport connection broken: %v", pc.closed)}
-			}
-			re = responseAndError{err: err}
+			re = responseAndError{err: pc.mapRoundTripErrorAfterClosed(startBytesWritten)}
 			break WaitResponse
 		case <-respHeaderTimer:
 			pc.close(errTimeout)
 			re = responseAndError{err: errTimeout}
 			break WaitResponse
 		case re = <-resc:
-			if re.err != nil && pc.isCanceled() {
-				re.err = errRequestCanceled
-			}
+			re.err = pc.mapRoundTripErrorFromReadLoop(startBytesWritten, re.err)
 			break WaitResponse
 		case <-cancelChan:
 			pc.t.CancelRequest(req.Request)
 			cancelChan = nil
+		case <-req.Context().Done():
+			pc.t.CancelRequest(req.Request)
+			cancelChan = nil
 		}
 	}
 
@@ -1518,21 +1827,12 @@ WaitResponse:
 	return re.res, re.err
 }
 
-// markBroken marks a connection as broken (so it's not reused).
-// It differs from close in that it doesn't close the underlying
-// connection for use when it's still being read.
-func (pc *persistConn) markBroken() {
-	pc.lk.Lock()
-	defer pc.lk.Unlock()
-	pc.broken = true
-}
-
 // markReused marks this connection as having been successfully used for a
 // request and response.
 func (pc *persistConn) markReused() {
-	pc.lk.Lock()
+	pc.mu.Lock()
 	pc.reused = true
-	pc.lk.Unlock()
+	pc.mu.Unlock()
 }
 
 // close closes the underlying TCP connection and closes
@@ -1541,8 +1841,8 @@ func (pc *persistConn) markReused() {
 // The provided err is only for testing and debugging; in normal
 // circumstances it should never be seen by users.
 func (pc *persistConn) close(err error) {
-	pc.lk.Lock()
-	defer pc.lk.Unlock()
+	pc.mu.Lock()
+	defer pc.mu.Unlock()
 	pc.closeLocked(err)
 }
 
@@ -1558,7 +1858,7 @@ func (pc *persistConn) closeLocked(err error) {
 			// handlePendingDial's putOrCloseIdleConn when
 			// it turns out the abandoned connection in
 			// flight ended up negotiating an alternate
-			// protocol.  We don't use the connection
+			// protocol. We don't use the connection
 			// freelist for http2. That's done by the
 			// alternate protocol's RoundTripper.
 		} else {
@@ -1583,7 +1883,11 @@ func canonicalAddr(url *url.URL) string {
 	return addr
 }
 
-// bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
+// bodyEOFSignal is used by the HTTP/1 transport when reading response
+// bodies to make sure we see the end of a response body before
+// proceeding and reading on the connection again.
+//
+// It wraps a ReadCloser but runs fn (if non-nil) at most
 // once, right before its final (error-producing) Read or Close call
 // returns. fn should return the new error to return from Read or Close.
 //
@@ -1599,12 +1903,14 @@ type bodyEOFSignal struct {
 	earlyCloseFn func() error      // optional alt Close func used if io.EOF not seen
 }
 
+var errReadOnClosedResBody = errors.New("http: read on closed response body")
+
 func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
 	es.mu.Lock()
 	closed, rerr := es.closed, es.rerr
 	es.mu.Unlock()
 	if closed {
-		return 0, errors.New("http: read on closed response body")
+		return 0, errReadOnClosedResBody
 	}
 	if rerr != nil {
 		return 0, rerr
@@ -1649,16 +1955,29 @@ func (es *bodyEOFSignal) condfn(err error) error {
 // gzipReader wraps a response body so it can lazily
 // call gzip.NewReader on the first call to Read
 type gzipReader struct {
-	body io.ReadCloser // underlying Response.Body
-	zr   io.Reader     // lazily-initialized gzip reader
+	body *bodyEOFSignal // underlying HTTP/1 response body framing
+	zr   *gzip.Reader   // lazily-initialized gzip reader
+	zerr error          // any error from gzip.NewReader; sticky
 }
 
 func (gz *gzipReader) Read(p []byte) (n int, err error) {
 	if gz.zr == nil {
-		gz.zr, err = gzip.NewReader(gz.body)
-		if err != nil {
-			return 0, err
+		if gz.zerr == nil {
+			gz.zr, gz.zerr = gzip.NewReader(gz.body)
 		}
+		if gz.zerr != nil {
+			return 0, gz.zerr
+		}
+	}
+
+	gz.body.mu.Lock()
+	if gz.body.closed {
+		err = errReadOnClosedResBody
+	}
+	gz.body.mu.Unlock()
+
+	if err != nil {
+		return 0, err
 	}
 	return gz.zr.Read(p)
 }
@@ -1678,19 +1997,6 @@ func (tlsHandshakeTimeoutError) Timeout() bool   { return true }
 func (tlsHandshakeTimeoutError) Temporary() bool { return true }
 func (tlsHandshakeTimeoutError) Error() string   { return "net/http: TLS handshake timeout" }
 
-type noteEOFReader struct {
-	r      io.Reader
-	sawEOF *bool
-}
-
-func (nr noteEOFReader) Read(p []byte) (n int, err error) {
-	n, err = nr.r.Read(p)
-	if err == io.EOF {
-		*nr.sawEOF = true
-	}
-	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.
@@ -1699,17 +2005,6 @@ 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.
@@ -1726,25 +2021,27 @@ func cloneTLSConfig(cfg *tls.Config) *tls.Config {
 		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,
+		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,
+		DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled,
+		Renegotiation:               cfg.Renegotiation,
 	}
 }
 
@@ -1757,22 +2054,63 @@ func cloneTLSClientConfig(cfg *tls.Config) *tls.Config {
 		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,
+		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,
+		DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled,
+		Renegotiation:               cfg.Renegotiation,
 	}
 }
+
+type connLRU struct {
+	ll *list.List // list.Element.Value type is of *persistConn
+	m  map[*persistConn]*list.Element
+}
+
+// add adds pc to the head of the linked list.
+func (cl *connLRU) add(pc *persistConn) {
+	if cl.ll == nil {
+		cl.ll = list.New()
+		cl.m = make(map[*persistConn]*list.Element)
+	}
+	ele := cl.ll.PushFront(pc)
+	if _, ok := cl.m[pc]; ok {
+		panic("persistConn was already in LRU")
+	}
+	cl.m[pc] = ele
+}
+
+func (cl *connLRU) removeOldest() *persistConn {
+	ele := cl.ll.Back()
+	pc := ele.Value.(*persistConn)
+	cl.ll.Remove(ele)
+	delete(cl.m, pc)
+	return pc
+}
+
+// remove removes pc from cl.
+func (cl *connLRU) remove(pc *persistConn) {
+	if ele, ok := cl.m[pc]; ok {
+		cl.ll.Remove(ele)
+		delete(cl.m, pc)
+	}
+}
+
+// len returns the number of items in the cache.
+func (cl *connLRU) len() int {
+	return len(cl.m)
+}
diff --git a/src/net/http/transport_internal_test.go b/src/net/http/transport_internal_test.go
new file mode 100644
index 0000000..a157d90
--- /dev/null
+++ b/src/net/http/transport_internal_test.go
@@ -0,0 +1,69 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// White-box tests for transport.go (in package http instead of http_test).
+
+package http
+
+import (
+	"errors"
+	"net"
+	"testing"
+)
+
+// Issue 15446: incorrect wrapping of errors when server closes an idle connection.
+func TestTransportPersistConnReadLoopEOF(t *testing.T) {
+	ln := newLocalListener(t)
+	defer ln.Close()
+
+	connc := make(chan net.Conn, 1)
+	go func() {
+		defer close(connc)
+		c, err := ln.Accept()
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		connc <- c
+	}()
+
+	tr := new(Transport)
+	req, _ := NewRequest("GET", "http://"+ln.Addr().String(), nil)
+	treq := &transportRequest{Request: req}
+	cm := connectMethod{targetScheme: "http", targetAddr: ln.Addr().String()}
+	pc, err := tr.getConn(treq, cm)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer pc.close(errors.New("test over"))
+
+	conn := <-connc
+	if conn == nil {
+		// Already called t.Error in the accept goroutine.
+		return
+	}
+	conn.Close() // simulate the server hanging up on the client
+
+	_, err = pc.roundTrip(treq)
+	if err != errServerClosedConn && err != errServerClosedIdle {
+		t.Fatalf("roundTrip = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
+	}
+
+	<-pc.closech
+	err = pc.closed
+	if err != errServerClosedConn && err != errServerClosedIdle {
+		t.Fatalf("pc.closed = %#v, %v; want errServerClosedConn or errServerClosedIdle", err, err)
+	}
+}
+
+func newLocalListener(t *testing.T) net.Listener {
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		ln, err = net.Listen("tcp6", "[::1]:0")
+	}
+	if err != nil {
+		t.Fatal(err)
+	}
+	return ln
+}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index d9da078..d653a5a 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -13,16 +13,20 @@ import (
 	"bufio"
 	"bytes"
 	"compress/gzip"
+	"context"
 	"crypto/rand"
 	"crypto/tls"
 	"errors"
 	"fmt"
+	"internal/nettrace"
+	"internal/testenv"
 	"io"
 	"io/ioutil"
 	"log"
 	"net"
 	. "net/http"
 	"net/http/httptest"
+	"net/http/httptrace"
 	"net/http/httputil"
 	"net/http/internal"
 	"net/url"
@@ -379,8 +383,8 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
 		}
 	}))
 	defer ts.Close()
-	maxIdleConns := 2
-	tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConns}
+	maxIdleConnsPerHost := 2
+	tr := &Transport{DisableKeepAlives: false, MaxIdleConnsPerHost: maxIdleConnsPerHost}
 	c := &Client{Transport: tr}
 
 	// Start 3 outstanding requests and wait for the server to get them.
@@ -425,14 +429,65 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
 
 	resch <- "res2"
 	<-donech
-	if e, g := 2, tr.IdleConnCountForTesting(cacheKey); e != g {
-		t.Errorf("after second response, expected %d idle conns; got %d", e, g)
+	if g, w := tr.IdleConnCountForTesting(cacheKey), 2; g != w {
+		t.Errorf("after second response, idle conns = %d; want %d", g, w)
 	}
 
 	resch <- "res3"
 	<-donech
-	if e, g := maxIdleConns, tr.IdleConnCountForTesting(cacheKey); e != g {
-		t.Errorf("after third response, still expected %d idle conns; got %d", e, g)
+	if g, w := tr.IdleConnCountForTesting(cacheKey), maxIdleConnsPerHost; g != w {
+		t.Errorf("after third response, idle conns = %d; want %d", g, w)
+	}
+}
+
+func TestTransportRemovesDeadIdleConnections(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see https://golang.org/issue/15464")
+	}
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		io.WriteString(w, r.RemoteAddr)
+	}))
+	defer ts.Close()
+
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+
+	doReq := func(name string) string {
+		// Do a POST instead of a GET to prevent the Transport's
+		// idempotent request retry logic from kicking in...
+		res, err := c.Post(ts.URL, "", nil)
+		if err != nil {
+			t.Fatalf("%s: %v", name, err)
+		}
+		if res.StatusCode != 200 {
+			t.Fatalf("%s: %v", name, res.Status)
+		}
+		defer res.Body.Close()
+		slurp, err := ioutil.ReadAll(res.Body)
+		if err != nil {
+			t.Fatalf("%s: %v", name, err)
+		}
+		return string(slurp)
+	}
+
+	first := doReq("first")
+	keys1 := tr.IdleConnKeysForTesting()
+
+	ts.CloseClientConnections()
+
+	var keys2 []string
+	if !waitCondition(3*time.Second, 50*time.Millisecond, func() bool {
+		keys2 = tr.IdleConnKeysForTesting()
+		return len(keys2) == 0
+	}) {
+		t.Fatalf("Transport didn't notice idle connection's death.\nbefore: %q\n after: %q\n", keys1, keys2)
+	}
+
+	second := doReq("second")
+	if first == second {
+		t.Errorf("expected a different connection between requests. got %q both times", first)
 	}
 }
 
@@ -478,7 +533,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
 
 	// This test has an expected race. Sleeping for 25 ms prevents
 	// it on most fast machines, causing the next fetch() call to
-	// succeed quickly.  But if we do get errors, fetch() will retry 5
+	// succeed quickly. But if we do get errors, fetch() will retry 5
 	// times with some delays between.
 	time.Sleep(25 * time.Millisecond)
 
@@ -518,7 +573,7 @@ func TestStressSurpriseServerCloses(t *testing.T) {
 	// 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
+	// not what we want to test. TODO(bradfitz): use an io.Pipe
 	// dialer for this test instead?
 	const (
 		numClients    = 20
@@ -853,7 +908,7 @@ func TestTransportExpect100Continue(t *testing.T) {
 		{path: "/100", body: []byte("hello"), sent: 5, status: 200},       // Got 100 followed by 200, entire body is sent.
 		{path: "/200", body: []byte("hello"), sent: 0, status: 200},       // Got 200 without 100. body isn't sent.
 		{path: "/500", body: []byte("hello"), sent: 0, status: 500},       // Got 500 without 100. body isn't sent.
-		{path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Althogh without Connection:close, body isn't sent.
+		{path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Although without Connection:close, body isn't sent.
 		{path: "/timeout", body: []byte("hello"), sent: 5, status: 200},   // Timeout exceeded and entire body is sent.
 	}
 
@@ -923,7 +978,9 @@ func TestTransportGzipRecursive(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	c := &Client{Transport: &Transport{}}
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
 	res, err := c.Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
@@ -968,6 +1025,17 @@ func TestTransportGzipShort(t *testing.T) {
 	}
 }
 
+// Wait until number of goroutines is no greater than nmax, or time out.
+func waitNumGoroutine(nmax int) int {
+	nfinal := runtime.NumGoroutine()
+	for ntries := 10; ntries > 0 && nfinal > nmax; ntries-- {
+		time.Sleep(50 * time.Millisecond)
+		runtime.GC()
+		nfinal = runtime.NumGoroutine()
+	}
+	return nfinal
+}
+
 // tests that persistent goroutine connections shut down when no longer desired.
 func TestTransportPersistConnLeak(t *testing.T) {
 	setParallel(t)
@@ -1019,14 +1087,11 @@ func TestTransportPersistConnLeak(t *testing.T) {
 	}
 
 	tr.CloseIdleConnections()
-	time.Sleep(100 * time.Millisecond)
-	runtime.GC()
-	runtime.GC() // even more.
-	nfinal := runtime.NumGoroutine()
+	nfinal := waitNumGoroutine(n0 + 5)
 
 	growth := nfinal - n0
 
-	// We expect 0 or 1 extra goroutine, empirically.  Allow up to 5.
+	// We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
 	// Previously we were leaking one per numReq.
 	if int(growth) > 5 {
 		t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
@@ -1061,13 +1126,11 @@ func TestTransportPersistConnLeakShortBody(t *testing.T) {
 	}
 	nhigh := runtime.NumGoroutine()
 	tr.CloseIdleConnections()
-	time.Sleep(400 * time.Millisecond)
-	runtime.GC()
-	nfinal := runtime.NumGoroutine()
+	nfinal := waitNumGoroutine(n0 + 5)
 
 	growth := nfinal - n0
 
-	// We expect 0 or 1 extra goroutine, empirically.  Allow up to 5.
+	// We expect 0 or 1 extra goroutine, empirically. Allow up to 5.
 	// Previously we were leaking one per numReq.
 	t.Logf("goroutine growth: %d -> %d -> %d (delta: %d)", n0, nhigh, nfinal, growth)
 	if int(growth) > 5 {
@@ -1103,8 +1166,8 @@ func TestTransportIdleConnCrash(t *testing.T) {
 }
 
 // Test that the transport doesn't close the TCP connection early,
-// before the response body has been read.  This was a regression
-// which sadly lacked a triggering test.  The large response body made
+// before the response body has been read. This was a regression
+// which sadly lacked a triggering test. The large response body made
 // the old race easier to trigger.
 func TestIssue3644(t *testing.T) {
 	defer afterTest(t)
@@ -1199,7 +1262,7 @@ func TestTransportConcurrency(t *testing.T) {
 
 	// Due to the Transport's "socket late binding" (see
 	// idleConnCh in transport.go), the numReqs HTTP requests
-	// below can finish with a dial still outstanding.  To keep
+	// below can finish with a dial still outstanding. To keep
 	// the leak checker happy, keep track of pending dials and
 	// wait for them to finish (and be closed or returned to the
 	// idle pool) before we close idle connections.
@@ -1617,7 +1680,13 @@ func TestCancelRequestWithChannel(t *testing.T) {
 	}
 }
 
-func TestCancelRequestWithChannelBeforeDo(t *testing.T) {
+func TestCancelRequestWithChannelBeforeDo_Cancel(t *testing.T) {
+	testCancelRequestWithChannelBeforeDo(t, false)
+}
+func TestCancelRequestWithChannelBeforeDo_Context(t *testing.T) {
+	testCancelRequestWithChannelBeforeDo(t, true)
+}
+func testCancelRequestWithChannelBeforeDo(t *testing.T, withCtx bool) {
 	setParallel(t)
 	defer afterTest(t)
 	unblockc := make(chan bool)
@@ -1638,9 +1707,15 @@ func TestCancelRequestWithChannelBeforeDo(t *testing.T) {
 	c := &Client{Transport: tr}
 
 	req, _ := NewRequest("GET", ts.URL, nil)
-	ch := make(chan struct{})
-	req.Cancel = ch
-	close(ch)
+	if withCtx {
+		ctx, cancel := context.WithCancel(context.Background())
+		cancel()
+		req = req.WithContext(ctx)
+	} else {
+		ch := make(chan struct{})
+		req.Cancel = ch
+		close(ch)
+	}
 
 	_, err := c.Do(req)
 	if err == nil || !strings.Contains(err.Error(), "canceled") {
@@ -2208,7 +2283,7 @@ func TestTransportTLSHandshakeTimeout(t *testing.T) {
 // Trying to repro golang.org/issue/3514
 func TestTLSServerClosesConnection(t *testing.T) {
 	defer afterTest(t)
-	setFlaky(t, 7634)
+	testenv.SkipFlaky(t, 7634)
 
 	closedc := make(chan bool, 1)
 	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -2273,7 +2348,7 @@ func TestTLSServerClosesConnection(t *testing.T) {
 }
 
 // byteFromChanReader is an io.Reader that reads a single byte at a
-// time from the channel.  When the channel is closed, the reader
+// time from the channel. When the channel is closed, the reader
 // returns io.EOF.
 type byteFromChanReader chan byte
 
@@ -2405,7 +2480,7 @@ func (plan9SleepReader) Read(p []byte) (int, error) {
 		// After the fix to unblock TCP Reads in
 		// https://golang.org/cl/15941, this sleep is required
 		// on plan9 to make sure TCP Writes before an
-		// immediate TCP close go out on the wire.  On Plan 9,
+		// immediate TCP close go out on the wire. On Plan 9,
 		// it seems that a hangup of a TCP connection with
 		// queued data doesn't send the queued data first.
 		// https://golang.org/issue/9554
@@ -2424,7 +2499,7 @@ func (f closerFunc) Close() error { return f() }
 // from (or finish writing to) the socket.
 //
 // NOTE: we resend a request only if the request is idempotent, we reused a
-// keep-alive connection, and we haven't yet received any header data.  This
+// keep-alive connection, and we haven't yet received any header data. This
 // automatically prevents an infinite resend loop because we'll run out of the
 // cached keep-alive connections eventually.
 func TestRetryIdempotentRequestsOnError(t *testing.T) {
@@ -2908,6 +2983,21 @@ func TestTransportAutomaticHTTP2_TLSConfig(t *testing.T) {
 func TestTransportAutomaticHTTP2_ExpectContinueTimeout(t *testing.T) {
 	testTransportAutoHTTP(t, &Transport{
 		ExpectContinueTimeout: 1 * time.Second,
+	}, true)
+}
+
+func TestTransportAutomaticHTTP2_Dial(t *testing.T) {
+	var d net.Dialer
+	testTransportAutoHTTP(t, &Transport{
+		Dial: d.Dial,
+	}, false)
+}
+
+func TestTransportAutomaticHTTP2_DialTLS(t *testing.T) {
+	testTransportAutoHTTP(t, &Transport{
+		DialTLS: func(network, addr string) (net.Conn, error) {
+			panic("unused")
+		},
 	}, false)
 }
 
@@ -3038,6 +3128,377 @@ func TestNoCrashReturningTransportAltConn(t *testing.T) {
 	<-handledPendingDial
 }
 
+func TestTransportReuseConnection_Gzip_Chunked(t *testing.T) {
+	testTransportReuseConnection_Gzip(t, true)
+}
+
+func TestTransportReuseConnection_Gzip_ContentLength(t *testing.T) {
+	testTransportReuseConnection_Gzip(t, false)
+}
+
+// Make sure we re-use underlying TCP connection for gzipped responses too.
+func testTransportReuseConnection_Gzip(t *testing.T, chunked bool) {
+	defer afterTest(t)
+	addr := make(chan string, 2)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		addr <- r.RemoteAddr
+		w.Header().Set("Content-Encoding", "gzip")
+		if chunked {
+			w.(Flusher).Flush()
+		}
+		w.Write(rgz) // arbitrary gzip response
+	}))
+	defer ts.Close()
+
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+	for i := 0; i < 2; i++ {
+		res, err := c.Get(ts.URL)
+		if err != nil {
+			t.Fatal(err)
+		}
+		buf := make([]byte, len(rgz))
+		if n, err := io.ReadFull(res.Body, buf); err != nil {
+			t.Errorf("%d. ReadFull = %v, %v", i, n, err)
+		}
+		// Note: no res.Body.Close call. It should work without it,
+		// since the flate.Reader's internal buffering will hit EOF
+		// and that should be sufficient.
+	}
+	a1, a2 := <-addr, <-addr
+	if a1 != a2 {
+		t.Fatalf("didn't reuse connection")
+	}
+}
+
+func TestTransportResponseHeaderLength(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		if r.URL.Path == "/long" {
+			w.Header().Set("Long", strings.Repeat("a", 1<<20))
+		}
+	}))
+	defer ts.Close()
+
+	tr := &Transport{
+		MaxResponseHeaderBytes: 512 << 10,
+	}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+	if res, err := c.Get(ts.URL); err != nil {
+		t.Fatal(err)
+	} else {
+		res.Body.Close()
+	}
+
+	res, err := c.Get(ts.URL + "/long")
+	if err == nil {
+		defer res.Body.Close()
+		var n int64
+		for k, vv := range res.Header {
+			for _, v := range vv {
+				n += int64(len(k)) + int64(len(v))
+			}
+		}
+		t.Fatalf("Unexpected success. Got %v and %d bytes of response headers", res.Status, n)
+	}
+	if want := "server response headers exceeded 524288 bytes"; !strings.Contains(err.Error(), want) {
+		t.Errorf("got error: %v; want %q", err, want)
+	}
+}
+
+func TestTransportEventTrace(t *testing.T)    { testTransportEventTrace(t, h1Mode, false) }
+func TestTransportEventTrace_h2(t *testing.T) { testTransportEventTrace(t, h2Mode, false) }
+
+// test a non-nil httptrace.ClientTrace but with all hooks set to zero.
+func TestTransportEventTrace_NoHooks(t *testing.T)    { testTransportEventTrace(t, h1Mode, true) }
+func TestTransportEventTrace_NoHooks_h2(t *testing.T) { testTransportEventTrace(t, h2Mode, true) }
+
+func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
+	defer afterTest(t)
+	const resBody = "some body"
+	gotWroteReqEvent := make(chan struct{})
+	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+		if _, err := ioutil.ReadAll(r.Body); err != nil {
+			t.Error(err)
+		}
+		if !noHooks {
+			select {
+			case <-gotWroteReqEvent:
+			case <-time.After(5 * time.Second):
+				t.Error("timeout waiting for WroteRequest event")
+			}
+		}
+		io.WriteString(w, resBody)
+	}))
+	defer cst.close()
+
+	cst.tr.ExpectContinueTimeout = 1 * time.Second
+
+	var mu sync.Mutex
+	var buf bytes.Buffer
+	logf := func(format string, args ...interface{}) {
+		mu.Lock()
+		defer mu.Unlock()
+		fmt.Fprintf(&buf, format, args...)
+		buf.WriteByte('\n')
+	}
+
+	addrStr := cst.ts.Listener.Addr().String()
+	ip, port, err := net.SplitHostPort(addrStr)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Install a fake DNS server.
+	ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, host string) ([]net.IPAddr, error) {
+		if host != "dns-is-faked.golang" {
+			t.Errorf("unexpected DNS host lookup for %q", host)
+			return nil, nil
+		}
+		return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
+	})
+
+	req, _ := NewRequest("POST", cst.scheme()+"://dns-is-faked.golang:"+port, strings.NewReader("some body"))
+	trace := &httptrace.ClientTrace{
+		GetConn:              func(hostPort string) { logf("Getting conn for %v ...", hostPort) },
+		GotConn:              func(ci httptrace.GotConnInfo) { logf("got conn: %+v", ci) },
+		GotFirstResponseByte: func() { logf("first response byte") },
+		PutIdleConn:          func(err error) { logf("PutIdleConn = %v", err) },
+		DNSStart:             func(e httptrace.DNSStartInfo) { logf("DNS start: %+v", e) },
+		DNSDone:              func(e httptrace.DNSDoneInfo) { logf("DNS done: %+v", e) },
+		ConnectStart:         func(network, addr string) { logf("ConnectStart: Connecting to %s %s ...", network, addr) },
+		ConnectDone: func(network, addr string, err error) {
+			if err != nil {
+				t.Errorf("ConnectDone: %v", err)
+			}
+			logf("ConnectDone: connected to %s %s = %v", network, addr, err)
+		},
+		Wait100Continue: func() { logf("Wait100Continue") },
+		Got100Continue:  func() { logf("Got100Continue") },
+		WroteRequest: func(e httptrace.WroteRequestInfo) {
+			close(gotWroteReqEvent)
+			logf("WroteRequest: %+v", e)
+		},
+	}
+	if noHooks {
+		// zero out all func pointers, trying to get some path to crash
+		*trace = httptrace.ClientTrace{}
+	}
+	req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
+
+	req.Header.Set("Expect", "100-continue")
+	res, err := cst.c.Do(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+	logf("got roundtrip.response")
+	slurp, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	logf("consumed body")
+	if string(slurp) != resBody || res.StatusCode != 200 {
+		t.Fatalf("Got %q, %v; want %q, 200 OK", slurp, res.Status, resBody)
+	}
+	res.Body.Close()
+
+	if noHooks {
+		// Done at this point. Just testing a full HTTP
+		// requests can happen with a trace pointing to a zero
+		// ClientTrace, full of nil func pointers.
+		return
+	}
+
+	got := buf.String()
+	wantOnce := func(sub string) {
+		if strings.Count(got, sub) != 1 {
+			t.Errorf("expected substring %q exactly once in output.", sub)
+		}
+	}
+	wantOnceOrMore := func(sub string) {
+		if strings.Count(got, sub) == 0 {
+			t.Errorf("expected substring %q at least once in output.", sub)
+		}
+	}
+	wantOnce("Getting conn for dns-is-faked.golang:" + port)
+	wantOnce("DNS start: {Host:dns-is-faked.golang}")
+	wantOnce("DNS done: {Addrs:[{IP:" + ip + " Zone:}] Err:<nil> Coalesced:false}")
+	wantOnce("got conn: {")
+	wantOnceOrMore("Connecting to tcp " + addrStr)
+	wantOnceOrMore("connected to tcp " + addrStr + " = <nil>")
+	wantOnce("Reused:false WasIdle:false IdleTime:0s")
+	wantOnce("first response byte")
+	if !h2 {
+		wantOnce("PutIdleConn = <nil>")
+	}
+	wantOnce("Wait100Continue")
+	wantOnce("Got100Continue")
+	wantOnce("WroteRequest: {Err:<nil>}")
+	if strings.Contains(got, " to udp ") {
+		t.Errorf("should not see UDP (DNS) connections")
+	}
+	if t.Failed() {
+		t.Errorf("Output:\n%s", got)
+	}
+}
+
+func TestTransportEventTraceRealDNS(t *testing.T) {
+	defer afterTest(t)
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+
+	var mu sync.Mutex
+	var buf bytes.Buffer
+	logf := func(format string, args ...interface{}) {
+		mu.Lock()
+		defer mu.Unlock()
+		fmt.Fprintf(&buf, format, args...)
+		buf.WriteByte('\n')
+	}
+
+	req, _ := NewRequest("GET", "http://dns-should-not-resolve.golang:80", nil)
+	trace := &httptrace.ClientTrace{
+		DNSStart:     func(e httptrace.DNSStartInfo) { logf("DNSStart: %+v", e) },
+		DNSDone:      func(e httptrace.DNSDoneInfo) { logf("DNSDone: %+v", e) },
+		ConnectStart: func(network, addr string) { logf("ConnectStart: %s %s", network, addr) },
+		ConnectDone:  func(network, addr string, err error) { logf("ConnectDone: %s %s %v", network, addr, err) },
+	}
+	req = req.WithContext(httptrace.WithClientTrace(context.Background(), trace))
+
+	resp, err := c.Do(req)
+	if err == nil {
+		resp.Body.Close()
+		t.Fatal("expected error during DNS lookup")
+	}
+
+	got := buf.String()
+	wantSub := func(sub string) {
+		if !strings.Contains(got, sub) {
+			t.Errorf("expected substring %q in output.", sub)
+		}
+	}
+	wantSub("DNSStart: {Host:dns-should-not-resolve.golang}")
+	wantSub("DNSDone: {Addrs:[] Err:")
+	if strings.Contains(got, "ConnectStart") || strings.Contains(got, "ConnectDone") {
+		t.Errorf("should not see Connect events")
+	}
+	if t.Failed() {
+		t.Errorf("Output:\n%s", got)
+	}
+}
+
+func TestTransportMaxIdleConns(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		// No body for convenience.
+	}))
+	defer ts.Close()
+	tr := &Transport{
+		MaxIdleConns: 4,
+	}
+	defer tr.CloseIdleConnections()
+
+	ip, port, err := net.SplitHostPort(ts.Listener.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	c := &Client{Transport: tr}
+	ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, host string) ([]net.IPAddr, error) {
+		return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
+	})
+
+	hitHost := func(n int) {
+		req, _ := NewRequest("GET", fmt.Sprintf("http://host-%d.dns-is-faked.golang:"+port, n), nil)
+		req = req.WithContext(ctx)
+		res, err := c.Do(req)
+		if err != nil {
+			t.Fatal(err)
+		}
+		res.Body.Close()
+	}
+	for i := 0; i < 4; i++ {
+		hitHost(i)
+	}
+	want := []string{
+		"|http|host-0.dns-is-faked.golang:" + port,
+		"|http|host-1.dns-is-faked.golang:" + port,
+		"|http|host-2.dns-is-faked.golang:" + port,
+		"|http|host-3.dns-is-faked.golang:" + port,
+	}
+	if got := tr.IdleConnKeysForTesting(); !reflect.DeepEqual(got, want) {
+		t.Fatalf("idle conn keys mismatch.\n got: %q\nwant: %q\n", got, want)
+	}
+
+	// Now hitting the 5th host should kick out the first host:
+	hitHost(4)
+	want = []string{
+		"|http|host-1.dns-is-faked.golang:" + port,
+		"|http|host-2.dns-is-faked.golang:" + port,
+		"|http|host-3.dns-is-faked.golang:" + port,
+		"|http|host-4.dns-is-faked.golang:" + port,
+	}
+	if got := tr.IdleConnKeysForTesting(); !reflect.DeepEqual(got, want) {
+		t.Fatalf("idle conn keys mismatch after 5th host.\n got: %q\nwant: %q\n", got, want)
+	}
+}
+
+func TestTransportIdleConnTimeout(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	defer afterTest(t)
+
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		// No body for convenience.
+	}))
+	defer ts.Close()
+
+	const timeout = 1 * time.Second
+	tr := &Transport{
+		IdleConnTimeout: timeout,
+	}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+
+	var conn string
+	doReq := func(n int) {
+		req, _ := NewRequest("GET", ts.URL, nil)
+		req = req.WithContext(httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
+			PutIdleConn: func(err error) {
+				if err != nil {
+					t.Errorf("failed to keep idle conn: %v", err)
+				}
+			},
+		}))
+		res, err := c.Do(req)
+		if err != nil {
+			t.Fatal(err)
+		}
+		res.Body.Close()
+		conns := tr.IdleConnStrsForTesting()
+		if len(conns) != 1 {
+			t.Fatalf("req %v: unexpected number of idle conns: %q", n, conns)
+		}
+		if conn == "" {
+			conn = conns[0]
+		}
+		if conn != conns[0] {
+			t.Fatalf("req %v: cached connection changed; expected the same one throughout the test", n)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		doReq(i)
+		time.Sleep(timeout / 2)
+	}
+	time.Sleep(timeout * 3 / 2)
+	if got := tr.IdleConnStrsForTesting(); len(got) != 0 {
+		t.Errorf("idle conns = %q; want none", got)
+	}
+}
+
 var errFakeRoundTrip = errors.New("fake roundtrip")
 
 type funcRoundTripper func()
diff --git a/src/net/interface.go b/src/net/interface.go
index 9c7b5da..52b857c 100644
--- a/src/net/interface.go
+++ b/src/net/interface.go
@@ -1,10 +1,14 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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 "errors"
+import (
+	"errors"
+	"sync"
+	"time"
+)
 
 var (
 	errInvalidInterface         = errors.New("invalid network interface")
@@ -15,7 +19,7 @@ var (
 )
 
 // Interface represents a mapping between network interface name
-// and index.  It also represents network interface facility
+// and index. It also represents network interface facility
 // information.
 type Interface struct {
 	Index        int          // positive integer that starts at one, zero is never used
@@ -88,9 +92,12 @@ func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
 func Interfaces() ([]Interface, error) {
 	ift, err := interfaceTable(0)
 	if err != nil {
-		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
 	}
-	return ift, err
+	if len(ift) != 0 {
+		zoneCache.update(ift)
+	}
+	return ift, nil
 }
 
 // InterfaceAddrs returns a list of the system's network interface
@@ -137,6 +144,9 @@ func InterfaceByName(name string) (*Interface, error) {
 	if err != nil {
 		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
 	}
+	if len(ift) != 0 {
+		zoneCache.update(ift)
+	}
 	for _, ifi := range ift {
 		if name == ifi.Name {
 			return &ifi, nil
@@ -144,3 +154,68 @@ func InterfaceByName(name string) (*Interface, error) {
 	}
 	return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
 }
+
+// An ipv6ZoneCache represents a cache holding partial network
+// interface information. It is used for reducing the cost of IPv6
+// addressing scope zone resolution.
+type ipv6ZoneCache struct {
+	sync.RWMutex                // guard the following
+	lastFetched  time.Time      // last time routing information was fetched
+	toIndex      map[string]int // interface name to its index
+	toName       map[int]string // interface index to its name
+}
+
+var zoneCache = ipv6ZoneCache{
+	toIndex: make(map[string]int),
+	toName:  make(map[int]string),
+}
+
+func (zc *ipv6ZoneCache) update(ift []Interface) {
+	zc.Lock()
+	defer zc.Unlock()
+	now := time.Now()
+	if zc.lastFetched.After(now.Add(-60 * time.Second)) {
+		return
+	}
+	zc.lastFetched = now
+	if len(ift) == 0 {
+		var err error
+		if ift, err = interfaceTable(0); err != nil {
+			return
+		}
+	}
+	zc.toIndex = make(map[string]int, len(ift))
+	zc.toName = make(map[int]string, len(ift))
+	for _, ifi := range ift {
+		zc.toIndex[ifi.Name] = ifi.Index
+		zc.toName[ifi.Index] = ifi.Name
+	}
+}
+
+func zoneToString(zone int) string {
+	if zone == 0 {
+		return ""
+	}
+	zoneCache.update(nil)
+	zoneCache.RLock()
+	defer zoneCache.RUnlock()
+	name, ok := zoneCache.toName[zone]
+	if !ok {
+		name = uitoa(uint(zone))
+	}
+	return name
+}
+
+func zoneToInt(zone string) int {
+	if zone == "" {
+		return 0
+	}
+	zoneCache.update(nil)
+	zoneCache.RLock()
+	defer zoneCache.RUnlock()
+	index, ok := zoneCache.toIndex[zone]
+	if !ok {
+		index, _, _ = dtoi(zone, 0)
+	}
+	return index
+}
diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go
index 208f37f..d791cb3 100644
--- a/src/net/interface_bsd.go
+++ b/src/net/interface_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,74 +7,54 @@
 package net
 
 import (
-	"os"
 	"syscall"
-	"unsafe"
+
+	"golang.org/x/net/route"
 )
 
 // If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces.  Otherwise it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
+	msgs, err := interfaceMessages(ifindex)
 	if err != nil {
-		return nil, os.NewSyscallError("routerib", err)
+		return nil, err
 	}
-	msgs, err := syscall.ParseRoutingMessage(tab)
-	if err != nil {
-		return nil, os.NewSyscallError("parseroutingmessage", err)
+	n := len(msgs)
+	if ifindex != 0 {
+		n = 1
 	}
-	return parseInterfaceTable(ifindex, msgs)
-}
-
-func parseInterfaceTable(ifindex int, msgs []syscall.RoutingMessage) ([]Interface, error) {
-	var ift []Interface
-loop:
+	ift := make([]Interface, n)
+	n = 0
 	for _, m := range msgs {
 		switch m := m.(type) {
-		case *syscall.InterfaceMessage:
-			if ifindex == 0 || ifindex == int(m.Header.Index) {
-				ifi, err := newLink(m)
-				if err != nil {
-					return nil, err
-				}
-				ift = append(ift, *ifi)
-				if ifindex == int(m.Header.Index) {
-					break loop
+		case *route.InterfaceMessage:
+			if ifindex != 0 && ifindex != m.Index {
+				continue
+			}
+			ift[n].Index = m.Index
+			ift[n].Name = m.Name
+			ift[n].Flags = linkFlags(m.Flags)
+			if sa, ok := m.Addrs[syscall.RTAX_IFP].(*route.LinkAddr); ok && len(sa.Addr) > 0 {
+				ift[n].HardwareAddr = make([]byte, len(sa.Addr))
+				copy(ift[n].HardwareAddr, sa.Addr)
+			}
+			for _, sys := range m.Sys() {
+				if imx, ok := sys.(*route.InterfaceMetrics); ok {
+					ift[n].MTU = imx.MTU
+					break
 				}
 			}
+			n++
+			if ifindex == m.Index {
+				return ift[:n], nil
+			}
 		}
 	}
-	return ift, nil
-}
-
-func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
-	sas, err := syscall.ParseRoutingSockaddr(m)
-	if err != nil {
-		return nil, os.NewSyscallError("parseroutingsockaddr", err)
-	}
-	ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
-	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
+	return ift[:n], nil
 }
 
-func linkFlags(rawFlags int32) Flags {
+func linkFlags(rawFlags int) Flags {
 	var f Flags
 	if rawFlags&syscall.IFF_UP != 0 {
 		f |= FlagUp
@@ -95,81 +75,44 @@ func linkFlags(rawFlags int32) Flags {
 }
 
 // If the ifi is nil, interfaceAddrTable returns addresses for all
-// network interfaces.  Otherwise it returns addresses for a specific
+// network interfaces. Otherwise it returns addresses for a specific
 // interface.
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	index := 0
 	if ifi != nil {
 		index = ifi.Index
 	}
-	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
-	if err != nil {
-		return nil, os.NewSyscallError("routerib", err)
-	}
-	msgs, err := syscall.ParseRoutingMessage(tab)
+	msgs, err := interfaceMessages(index)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingmessage", err)
+		return nil, err
 	}
-	var ift []Interface
-	if index == 0 {
-		ift, err = parseInterfaceTable(index, msgs)
-		if err != nil {
-			return nil, err
-		}
-	}
-	var ifat []Addr
+	ifat := make([]Addr, 0, len(msgs))
 	for _, m := range msgs {
 		switch m := m.(type) {
-		case *syscall.InterfaceAddrMessage:
-			if index == 0 || index == int(m.Header.Index) {
-				if index == 0 {
-					var err error
-					ifi, err = interfaceByIndex(ift, int(m.Header.Index))
-					if err != nil {
-						return nil, err
-					}
-				}
-				ifa, err := newAddr(ifi, m)
-				if err != nil {
-					return nil, err
-				}
-				if ifa != nil {
-					ifat = append(ifat, ifa)
-				}
+		case *route.InterfaceAddrMessage:
+			if index != 0 && index != m.Index {
+				continue
+			}
+			var mask IPMask
+			switch sa := m.Addrs[syscall.RTAX_NETMASK].(type) {
+			case *route.Inet4Addr:
+				mask = IPv4Mask(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
+			case *route.Inet6Addr:
+				mask = make(IPMask, IPv6len)
+				copy(mask, sa.IP[:])
+			}
+			var ip IP
+			switch sa := m.Addrs[syscall.RTAX_IFA].(type) {
+			case *route.Inet4Addr:
+				ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
+			case *route.Inet6Addr:
+				ip = make(IP, IPv6len)
+				copy(ip, sa.IP[:])
+			}
+			if ip != nil && mask != nil { // NetBSD may contain route.LinkAddr
+				ifat = append(ifat, &IPNet{IP: ip, Mask: mask})
 			}
 		}
 	}
 	return ifat, nil
 }
-
-func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
-	sas, err := syscall.ParseRoutingSockaddr(m)
-	if err != nil {
-		return nil, os.NewSyscallError("parseroutingsockaddr", err)
-	}
-	ifa := &IPNet{}
-	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 43ccc89..69b0fbc 100644
--- a/src/net/interface_bsd_test.go
+++ b/src/net/interface_bsd_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -9,10 +9,15 @@ package net
 import (
 	"fmt"
 	"os/exec"
+	"runtime"
 )
 
-func (ti *testInterface) setBroadcast(suffix int) error {
-	ti.name = fmt.Sprintf("vlan%d", suffix)
+func (ti *testInterface) setBroadcast(vid int) error {
+	if runtime.GOOS == "openbsd" {
+		ti.name = fmt.Sprintf("vether%d", vid)
+	} else {
+		ti.name = fmt.Sprintf("vlan%d", vid)
+	}
 	xname, err := exec.LookPath("ifconfig")
 	if err != nil {
 		return err
diff --git a/src/net/interface_bsdvar.go b/src/net/interface_bsdvar.go
new file mode 100644
index 0000000..a809b5f
--- /dev/null
+++ b/src/net/interface_bsdvar.go
@@ -0,0 +1,28 @@
+// 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 dragonfly netbsd openbsd
+
+package net
+
+import (
+	"syscall"
+
+	"golang.org/x/net/route"
+)
+
+func interfaceMessages(ifindex int) ([]route.Message, error) {
+	rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex)
+	if err != nil {
+		return nil, err
+	}
+	return route.ParseRIB(syscall.NET_RT_IFLIST, rib)
+}
+
+// interfaceMulticastAddrTable returns addresses for a specific
+// interface.
+func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
+	// TODO(mikio): Implement this like other platforms.
+	return nil, nil
+}
diff --git a/src/net/interface_darwin.go b/src/net/interface_darwin.go
index b7a3338..bb4fd73 100644
--- a/src/net/interface_darwin.go
+++ b/src/net/interface_darwin.go
@@ -1,62 +1,53 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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 (
-	"os"
 	"syscall"
+
+	"golang.org/x/net/route"
 )
 
+func interfaceMessages(ifindex int) ([]route.Message, error) {
+	rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST, ifindex)
+	if err != nil {
+		return nil, err
+	}
+	return route.ParseRIB(syscall.NET_RT_IFLIST, rib)
+}
+
 // interfaceMulticastAddrTable returns addresses for a specific
 // interface.
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
-	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index)
+	rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFLIST2, ifi.Index)
 	if err != nil {
-		return nil, os.NewSyscallError("routerib", err)
+		return nil, err
 	}
-	msgs, err := syscall.ParseRoutingMessage(tab)
+	msgs, err := route.ParseRIB(syscall.NET_RT_IFLIST2, rib)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingmessage", err)
+		return nil, err
 	}
-	var ifmat []Addr
+	ifmat := make([]Addr, 0, len(msgs))
 	for _, m := range msgs {
 		switch m := m.(type) {
-		case *syscall.InterfaceMulticastAddrMessage:
-			if ifi.Index == int(m.Header.Index) {
-				ifma, err := newMulticastAddr(ifi, m)
-				if err != nil {
-					return nil, err
-				}
-				if ifma != nil {
-					ifmat = append(ifmat, ifma)
-				}
+		case *route.InterfaceMulticastAddrMessage:
+			if ifi.Index != m.Index {
+				continue
+			}
+			var ip IP
+			switch sa := m.Addrs[syscall.RTAX_IFA].(type) {
+			case *route.Inet4Addr:
+				ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
+			case *route.Inet6Addr:
+				ip = make(IP, IPv6len)
+				copy(ip, sa.IP[:])
+			}
+			if ip != nil {
+				ifmat = append(ifmat, &IPAddr{IP: ip})
 			}
 		}
 	}
 	return ifmat, nil
 }
-
-func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
-	sas, err := syscall.ParseRoutingSockaddr(m)
-	if err != nil {
-		return nil, os.NewSyscallError("parseroutingsockaddr", err)
-	}
-	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
-	}
-}
diff --git a/src/net/interface_dragonfly.go b/src/net/interface_dragonfly.go
deleted file mode 100644
index c9ce5a7..0000000
--- a/src/net/interface_dragonfly.go
+++ /dev/null
@@ -1,12 +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
-
-// interfaceMulticastAddrTable returns addresses for a specific
-// interface.
-func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
-	// TODO(mikio): Implement this like other platforms.
-	return nil, nil
-}
diff --git a/src/net/interface_freebsd.go b/src/net/interface_freebsd.go
index c42d90b..45badd6 100644
--- a/src/net/interface_freebsd.go
+++ b/src/net/interface_freebsd.go
@@ -1,62 +1,58 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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 (
-	"os"
 	"syscall"
+
+	"golang.org/x/net/route"
 )
 
+func interfaceMessages(ifindex int) ([]route.Message, error) {
+	typ := route.RIBType(syscall.NET_RT_IFLISTL)
+	rib, err := route.FetchRIB(syscall.AF_UNSPEC, typ, ifindex)
+	if err != nil {
+		typ = route.RIBType(syscall.NET_RT_IFLIST)
+		rib, err = route.FetchRIB(syscall.AF_UNSPEC, typ, ifindex)
+	}
+	if err != nil {
+		return nil, err
+	}
+	return route.ParseRIB(typ, rib)
+}
+
 // interfaceMulticastAddrTable returns addresses for a specific
 // interface.
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
-	tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifi.Index)
+	rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_IFMALIST, ifi.Index)
 	if err != nil {
-		return nil, os.NewSyscallError("routerib", err)
+		return nil, err
 	}
-	msgs, err := syscall.ParseRoutingMessage(tab)
+	msgs, err := route.ParseRIB(syscall.NET_RT_IFMALIST, rib)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingmessage", err)
+		return nil, err
 	}
-	var ifmat []Addr
+	ifmat := make([]Addr, 0, len(msgs))
 	for _, m := range msgs {
 		switch m := m.(type) {
-		case *syscall.InterfaceMulticastAddrMessage:
-			if ifi.Index == int(m.Header.Index) {
-				ifma, err := newMulticastAddr(ifi, m)
-				if err != nil {
-					return nil, err
-				}
-				if ifma != nil {
-					ifmat = append(ifmat, ifma)
-				}
+		case *route.InterfaceMulticastAddrMessage:
+			if ifi.Index != m.Index {
+				continue
+			}
+			var ip IP
+			switch sa := m.Addrs[syscall.RTAX_IFA].(type) {
+			case *route.Inet4Addr:
+				ip = IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
+			case *route.Inet6Addr:
+				ip = make(IP, IPv6len)
+				copy(ip, sa.IP[:])
+			}
+			if ip != nil {
+				ifmat = append(ifmat, &IPAddr{IP: ip})
 			}
 		}
 	}
 	return ifmat, nil
 }
-
-func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
-	sas, err := syscall.ParseRoutingSockaddr(m)
-	if err != nil {
-		return nil, os.NewSyscallError("parseroutingsockaddr", err)
-	}
-	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
-	}
-}
diff --git a/src/net/interface_linux.go b/src/net/interface_linux.go
index ef20429..5e391b2 100644
--- a/src/net/interface_linux.go
+++ b/src/net/interface_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -11,7 +11,7 @@ import (
 )
 
 // If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces.  Otherwise it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
 	tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
@@ -115,7 +115,7 @@ func linkFlags(rawFlags uint32) Flags {
 }
 
 // If the ifi is nil, interfaceAddrTable returns addresses for all
-// network interfaces.  Otherwise it returns addresses for a specific
+// network interfaces. Otherwise it returns addresses for a specific
 // interface.
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
diff --git a/src/net/interface_linux_test.go b/src/net/interface_linux_test.go
index 6251b26..6959ddb 100644
--- a/src/net/interface_linux_test.go
+++ b/src/net/interface_linux_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/net/interface_netbsd.go b/src/net/interface_netbsd.go
deleted file mode 100644
index c9ce5a7..0000000
--- a/src/net/interface_netbsd.go
+++ /dev/null
@@ -1,12 +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
-
-// interfaceMulticastAddrTable returns addresses for a specific
-// interface.
-func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
-	// TODO(mikio): Implement this like other platforms.
-	return nil, nil
-}
diff --git a/src/net/interface_openbsd.go b/src/net/interface_openbsd.go
deleted file mode 100644
index c9ce5a7..0000000
--- a/src/net/interface_openbsd.go
+++ /dev/null
@@ -1,12 +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
-
-// interfaceMulticastAddrTable returns addresses for a specific
-// interface.
-func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
-	// TODO(mikio): Implement this like other platforms.
-	return nil, nil
-}
diff --git a/src/net/interface_stub.go b/src/net/interface_stub.go
index c38fb7f..f64174c 100644
--- a/src/net/interface_stub.go
+++ b/src/net/interface_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,14 +7,14 @@
 package net
 
 // If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces.  Otherwise it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
 	return nil, nil
 }
 
 // If the ifi is nil, interfaceAddrTable returns addresses for all
-// network interfaces.  Otherwise it returns addresses for a specific
+// network interfaces. Otherwise it returns addresses for a specific
 // interface.
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	return nil, nil
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index 7bdd924..4c695b9 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -1,17 +1,18 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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"
 	"reflect"
 	"runtime"
 	"testing"
 )
 
 // loopbackInterface returns an available logical network interface
-// for loopback tests.  It returns nil if no suitable interface is
+// for loopback tests. It returns nil if no suitable interface is
 // found.
 func loopbackInterface() *Interface {
 	ift, err := Interfaces()
@@ -47,20 +48,11 @@ 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.Fatal(err)
 	}
-	var stats routeStats
 	for _, ifi := range ift {
 		ifxi, err := InterfaceByIndex(ifi.Index)
 		if err != nil {
@@ -76,56 +68,7 @@ func TestInterfaces(t *testing.T) {
 		if !reflect.DeepEqual(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("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)
-		}
+		t.Logf("%s: flags=%v index=%d mtu=%d hwaddr=%v", ifi.Name, ifi.Flags, ifi.Index, ifi.MTU, ifi.HardwareAddr)
 	}
 }
 
@@ -134,132 +77,217 @@ func TestInterfaceAddrs(t *testing.T) {
 	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++
-			}
-		}
-	}
+	ifStats := interfaceStats(ift)
 	ifat, err := InterfaceAddrs()
 	if err != nil {
 		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)
+	uniStats, err := validateInterfaceUnicastAddrs(ifat)
+	if err != nil {
+		t.Fatal(err)
 	}
-	// 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)
+	if err := checkUnicastStats(ifStats, uniStats); err != nil {
+		t.Fatal(err)
 	}
 }
 
-func testInterfaceAddrs(t *testing.T, ifi *Interface) (naf4, naf6 int) {
-	ifat, err := ifi.Addrs()
+func TestInterfaceUnicastAddrs(t *testing.T) {
+	ift, err := Interfaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+	ifStats := interfaceStats(ift)
 	if err != nil {
 		t.Fatal(err)
 	}
-	return testAddrs(t, ifat)
+	var uniStats routeStats
+	for _, ifi := range ift {
+		ifat, err := ifi.Addrs()
+		if err != nil {
+			t.Fatal(ifi, err)
+		}
+		stats, err := validateInterfaceUnicastAddrs(ifat)
+		if err != nil {
+			t.Fatal(ifi, err)
+		}
+		uniStats.ipv4 += stats.ipv4
+		uniStats.ipv6 += stats.ipv6
+	}
+	if err := checkUnicastStats(ifStats, &uniStats); err != nil {
+		t.Fatal(err)
+	}
 }
 
-func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) (nmaf4, nmaf6 int) {
-	ifmat, err := ifi.MulticastAddrs()
+func TestInterfaceMulticastAddrs(t *testing.T) {
+	ift, err := Interfaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+	ifStats := interfaceStats(ift)
+	ifat, err := InterfaceAddrs()
+	if err != nil {
+		t.Fatal(err)
+	}
+	uniStats, err := validateInterfaceUnicastAddrs(ifat)
 	if err != nil {
 		t.Fatal(err)
 	}
-	return testMulticastAddrs(t, ifmat)
+	var multiStats routeStats
+	for _, ifi := range ift {
+		ifmat, err := ifi.MulticastAddrs()
+		if err != nil {
+			t.Fatal(ifi, err)
+		}
+		stats, err := validateInterfaceMulticastAddrs(ifmat)
+		if err != nil {
+			t.Fatal(ifi, err)
+		}
+		multiStats.ipv4 += stats.ipv4
+		multiStats.ipv6 += stats.ipv6
+	}
+	if err := checkMulticastStats(ifStats, uniStats, &multiStats); err != nil {
+		t.Fatal(err)
+	}
 }
 
-func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
+type ifStats struct {
+	loop  int // # of active loopback interfaces
+	other int // # of active other interfaces
+}
+
+func interfaceStats(ift []Interface) *ifStats {
+	var stats ifStats
+	for _, ifi := range ift {
+		if ifi.Flags&FlagUp != 0 {
+			if ifi.Flags&FlagLoopback != 0 {
+				stats.loop++
+			} else {
+				stats.other++
+			}
+		}
+	}
+	return &stats
+}
+
+type routeStats struct {
+	ipv4, ipv6 int // # of active connected unicast, anycast or multicast routes
+}
+
+func validateInterfaceUnicastAddrs(ifat []Addr) (*routeStats, error) {
+	// Note: BSD variants allow assigning any IPv4/IPv6 address
+	// prefix to IP interface. For example,
+	//   - 0.0.0.0/0 through 255.255.255.255/32
+	//   - ::/0 through ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128
+	// In other words, there is no tightly-coupled combination of
+	// interface address prefixes and connected routes.
+	stats := new(routeStats)
 	for _, ifa := range ifat {
 		switch ifa := ifa.(type) {
 		case *IPNet:
-			if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() || ifa.Mask == nil {
-				t.Errorf("unexpected value: %#v", ifa)
-				continue
+			if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() || ifa.Mask == nil {
+				return nil, fmt.Errorf("unexpected value: %#v", ifa)
 			}
 			if len(ifa.IP) != IPv6len {
-				t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa)
-				continue
+				return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
 			}
 			prefixLen, maxPrefixLen := ifa.Mask.Size()
 			if ifa.IP.To4() != nil {
 				if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
-					t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen)
-					continue
+					return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
 				}
 				if ifa.IP.IsLoopback() && (prefixLen != 8 && prefixLen != 8*IPv4len) { // see RFC 1122
-					t.Errorf("unexpected prefix length for IPv4 loopback: %d/%d", prefixLen, maxPrefixLen)
-					continue
+					return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
 				}
-				naf4++
+				stats.ipv4++
 			}
 			if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
 				if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
-					t.Errorf("unexpected prefix length: %d/%d", prefixLen, maxPrefixLen)
-					continue
+					return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
 				}
 				if ifa.IP.IsLoopback() && prefixLen != 8*IPv6len { // see RFC 4291
-					t.Errorf("unexpected prefix length for IPv6 loopback: %d/%d", prefixLen, maxPrefixLen)
-					continue
+					return nil, fmt.Errorf("unexpected prefix length: %d/%d for %#v", prefixLen, maxPrefixLen, ifa)
 				}
-				naf6++
+				stats.ipv6++
 			}
-			t.Logf("interface address %q", ifa.String())
 		case *IPAddr:
-			if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() {
-				t.Errorf("unexpected value: %#v", ifa)
-				continue
+			if ifa == nil || ifa.IP == nil || ifa.IP.IsMulticast() {
+				return nil, fmt.Errorf("unexpected value: %#v", ifa)
 			}
 			if len(ifa.IP) != IPv6len {
-				t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifa)
-				continue
+				return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
 			}
 			if ifa.IP.To4() != nil {
-				naf4++
+				stats.ipv4++
 			}
 			if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
-				naf6++
+				stats.ipv6++
 			}
-			t.Logf("interface address %s", ifa.String())
 		default:
-			t.Errorf("unexpected type: %T", ifa)
+			return nil, fmt.Errorf("unexpected type: %T", ifa)
 		}
 	}
-	return
+	return stats, nil
 }
 
-func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
-	for _, ifma := range ifmat {
-		switch ifma := ifma.(type) {
+func validateInterfaceMulticastAddrs(ifat []Addr) (*routeStats, error) {
+	stats := new(routeStats)
+	for _, ifa := range ifat {
+		switch ifa := ifa.(type) {
 		case *IPAddr:
-			if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() {
-				t.Errorf("unexpected value: %+v", ifma)
-				continue
+			if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || !ifa.IP.IsMulticast() {
+				return nil, fmt.Errorf("unexpected value: %#v", ifa)
 			}
-			if len(ifma.IP) != IPv6len {
-				t.Errorf("should be internal representation either IPv6 or IPv6 IPv4-mapped address: %#v", ifma)
-				continue
+			if len(ifa.IP) != IPv6len {
+				return nil, fmt.Errorf("should be internal representation either IPv6 or IPv4-mapped IPv6 address: %#v", ifa)
 			}
-			if ifma.IP.To4() != nil {
-				nmaf4++
+			if ifa.IP.To4() != nil {
+				stats.ipv4++
 			}
-			if ifma.IP.To16() != nil && ifma.IP.To4() == nil {
-				nmaf6++
+			if ifa.IP.To16() != nil && ifa.IP.To4() == nil {
+				stats.ipv6++
 			}
-			t.Logf("joined group address %q", ifma.String())
 		default:
-			t.Errorf("unexpected type: %T", ifma)
+			return nil, fmt.Errorf("unexpected type: %T", ifa)
+		}
+	}
+	return stats, nil
+}
+
+func checkUnicastStats(ifStats *ifStats, uniStats *routeStats) error {
+	// Test the existence of connected unicast routes for IPv4.
+	if supportsIPv4 && ifStats.loop+ifStats.other > 0 && uniStats.ipv4 == 0 {
+		return fmt.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
+	}
+	// Test the existence of connected unicast routes for IPv6.
+	// We can assume the existence of ::1/128 when at least one
+	// loopback interface is installed.
+	if supportsIPv6 && ifStats.loop > 0 && uniStats.ipv6 == 0 {
+		return fmt.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v, %+v", ifStats, uniStats)
+	}
+	return nil
+}
+
+func checkMulticastStats(ifStats *ifStats, uniStats, multiStats *routeStats) error {
+	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 IPv4
+		// multicast validation is ignored and we only check
+		// IPv6 below.
+		//
+		// 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 && ifStats.loop > 0 && uniStats.ipv6 > 1 && multiStats.ipv6 == 0 {
+			return fmt.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v, %+v, %+v", ifStats, uniStats, multiStats)
 		}
 	}
-	return
+	return nil
 }
 
 func BenchmarkInterfaces(b *testing.B) {
diff --git a/src/net/interface_unix_test.go b/src/net/interface_unix_test.go
index 93b3b79..36510eb 100644
--- a/src/net/interface_unix_test.go
+++ b/src/net/interface_unix_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,6 +7,7 @@
 package net
 
 import (
+	"fmt"
 	"os"
 	"os/exec"
 	"runtime"
@@ -24,8 +25,8 @@ type testInterface struct {
 
 func (ti *testInterface) setup() error {
 	for _, cmd := range ti.setupCmds {
-		if err := cmd.Run(); err != nil {
-			return err
+		if out, err := cmd.CombinedOutput(); err != nil {
+			return fmt.Errorf("args=%v out=%q err=%v", cmd.Args, string(out), err)
 		}
 	}
 	return nil
@@ -33,8 +34,8 @@ func (ti *testInterface) setup() error {
 
 func (ti *testInterface) teardown() error {
 	for _, cmd := range ti.teardownCmds {
-		if err := cmd.Run(); err != nil {
-			return err
+		if out, err := cmd.CombinedOutput(); err != nil {
+			return fmt.Errorf("args=%v out=%q err=%v ", cmd.Args, string(out), err)
 		}
 	}
 	return nil
@@ -51,12 +52,14 @@ func TestPointToPointInterface(t *testing.T) {
 		t.Skip("must be root")
 	}
 
+	// We suppose that using IPv4 link-local addresses doesn't
+	// harm anyone.
 	local, remote := "169.254.0.1", "169.254.0.254"
 	ip := ParseIP(remote)
 	for i := 0; i < 3; i++ {
 		ti := &testInterface{local: local, remote: remote}
 		if err := ti.setPointToPoint(5963 + i); err != nil {
-			t.Skipf("test requries external command: %v", err)
+			t.Skipf("test requires external command: %v", err)
 		}
 		if err := ti.setup(); err != nil {
 			t.Fatal(err)
@@ -100,15 +103,17 @@ func TestInterfaceArrivalAndDeparture(t *testing.T) {
 		t.Skip("must be root")
 	}
 
+	// We suppose that using IPv4 link-local addresses and the
+	// dot1Q ID for Token Ring and FDDI doesn't harm anyone.
 	local, remote := "169.254.0.1", "169.254.0.254"
 	ip := ParseIP(remote)
-	for i := 0; i < 3; i++ {
+	for _, vid := range []int{1002, 1003, 1004, 1005} {
 		ift1, err := Interfaces()
 		if err != nil {
 			t.Fatal(err)
 		}
 		ti := &testInterface{local: local, remote: remote}
-		if err := ti.setBroadcast(5682 + i); err != nil {
+		if err := ti.setBroadcast(vid); err != nil {
 			t.Skipf("test requires external command: %v", err)
 		}
 		if err := ti.setup(); err != nil {
diff --git a/src/net/interface_windows.go b/src/net/interface_windows.go
index 4d6bcdf..8b976e5 100644
--- a/src/net/interface_windows.go
+++ b/src/net/interface_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -61,7 +61,7 @@ func adapterAddresses() ([]*windows.IpAdapterAddresses, error) {
 }
 
 // If the ifindex is zero, interfaceTable returns mappings of all
-// network interfaces.  Otherwise it returns a mapping of a specific
+// network interfaces. Otherwise it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
 	aas, err := adapterAddresses()
@@ -116,7 +116,7 @@ func interfaceTable(ifindex int) ([]Interface, error) {
 }
 
 // If the ifi is nil, interfaceAddrTable returns addresses for all
-// network interfaces.  Otherwise it returns addresses for a specific
+// network interfaces. Otherwise it returns addresses for a specific
 // interface.
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	aas, err := adapterAddresses()
diff --git a/src/net/internal/socktest/switch.go b/src/net/internal/socktest/switch.go
index 8bef06b..3c37b6f 100644
--- a/src/net/internal/socktest/switch.go
+++ b/src/net/internal/socktest/switch.go
@@ -121,7 +121,7 @@ const (
 	FilterSocket        FilterType = iota // for Socket
 	FilterConnect                         // for Connect or ConnectEx
 	FilterListen                          // for Listen
-	FilterAccept                          // for Accept or Accept4
+	FilterAccept                          // for Accept, Accept4 or AcceptEx
 	FilterGetsockoptInt                   // for GetsockoptInt
 	FilterClose                           // for Close or Closesocket
 )
diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go
index e61bf2b..2e3d2bc 100644
--- a/src/net/internal/socktest/sys_windows.go
+++ b/src/net/internal/socktest/sys_windows.go
@@ -154,3 +154,33 @@ func (sw *Switch) Listen(s syscall.Handle, backlog int) (err error) {
 	sw.stats.getLocked(so.Cookie).Listened++
 	return nil
 }
+
+// AcceptEx wraps syscall.AcceptEx.
+func (sw *Switch) AcceptEx(ls syscall.Handle, as syscall.Handle, b *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, rcvd *uint32, overlapped *syscall.Overlapped) error {
+	so := sw.sockso(ls)
+	if so == nil {
+		return syscall.AcceptEx(ls, as, b, rxdatalen, laddrlen, raddrlen, rcvd, overlapped)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterAccept]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.AcceptEx(ls, as, b, rxdatalen, laddrlen, raddrlen, rcvd, overlapped)
+	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).AcceptFailed++
+		return so.Err
+	}
+	nso := sw.addLocked(as, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
+	sw.stats.getLocked(nso.Cookie).Accepted++
+	return nil
+}
diff --git a/src/net/ip.go b/src/net/ip.go
index cc004d6..d0c8263 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -252,9 +252,11 @@ func (ip IP) Mask(mask IPMask) IP {
 }
 
 // String returns the string form of the IP address ip.
-// If the address is an IPv4 address, the string representation
-// is dotted decimal ("74.125.19.99").  Otherwise the representation
-// is IPv6 ("2001:4860:0:2001::68").
+// It returns one of 4 forms:
+//   - "<nil>", if ip has length 0
+//   - dotted decimal ("192.0.2.1"), if ip is an IPv4 or IP4-mapped IPv6 address
+//   - IPv6 ("2001:db8::1"), if ip is a valid IPv6 address
+//   - the hexadecimal form of ip, without punctuation, if no other cases apply
 func (ip IP) String() string {
 	p := ip
 
@@ -270,7 +272,7 @@ func (ip IP) String() string {
 			uitoa(uint(p4[3]))
 	}
 	if len(p) != IPv6len {
-		return "?"
+		return "?" + hexString(ip)
 	}
 
 	// Find longest run of zeros.
@@ -312,6 +314,14 @@ func (ip IP) String() string {
 	return string(b)
 }
 
+func hexString(b []byte) string {
+	s := make([]byte, len(b)*2)
+	for i, tn := range b {
+		s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf]
+	}
+	return string(s)
+}
+
 // ipEmptyString is like ip.String except that it returns
 // an empty string when ip is unset.
 func ipEmptyString(ip IP) string {
@@ -328,7 +338,7 @@ func (ip IP) MarshalText() ([]byte, error) {
 		return []byte(""), nil
 	}
 	if len(ip) != IPv4len && len(ip) != IPv6len {
-		return nil, &AddrError{Err: "invalid IP address", Addr: ip.String()}
+		return nil, &AddrError{Err: "invalid IP address", Addr: hexString(ip)}
 	}
 	return []byte(ip.String()), nil
 }
@@ -377,6 +387,10 @@ func bytesEqual(x, y []byte) bool {
 	return true
 }
 
+func (ip IP) matchAddrFamily(x IP) bool {
+	return ip.To4() != nil && x.To4() != nil || ip.To16() != nil && ip.To4() == nil && x.To16() != nil && x.To4() == nil
+}
+
 // If mask is a sequence of 1 bits followed by 0 bits,
 // return the number of 1 bits.
 func simpleMaskLength(mask IPMask) int {
@@ -422,11 +436,7 @@ func (m IPMask) String() string {
 	if len(m) == 0 {
 		return "<nil>"
 	}
-	buf := make([]byte, len(m)*2)
-	for i, b := range m {
-		buf[i*2], buf[i*2+1] = hexDigit[b>>4], hexDigit[b&0xf]
-	}
-	return string(buf)
+	return hexString(m)
 }
 
 func networkNumberAndMask(n *IPNet) (ip IP, m IPMask) {
@@ -473,12 +483,12 @@ func (n *IPNet) Contains(ip IP) bool {
 // Network returns the address's network name, "ip+net".
 func (n *IPNet) Network() string { return "ip+net" }
 
-// String returns the CIDR notation of n like "192.168.100.1/24"
-// or "2001:DB8::/48" as defined in RFC 4632 and RFC 4291.
+// String returns the CIDR notation of n like "192.0.2.1/24"
+// or "2001:db8::/48" as defined in RFC 4632 and RFC 4291.
 // If the mask is not in the canonical form, it returns the
 // string which consists of an IP address, followed by a slash
 // character and a mask expressed as hexadecimal form with no
-// punctuation like "192.168.100.1/c000ff00".
+// punctuation like "198.51.100.1/c000ff00".
 func (n *IPNet) String() string {
 	nn, m := networkNumberAndMask(n)
 	if nn == nil || m == nil {
@@ -631,8 +641,8 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
 }
 
 // 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.
+// The string s can be in dotted decimal ("192.0.2.1")
+// or IPv6 ("2001:db8::68") form.
 // If s is not a valid textual representation of an IP address,
 // ParseIP returns nil.
 func ParseIP(s string) IP {
@@ -649,12 +659,12 @@ func ParseIP(s string) IP {
 }
 
 // ParseCIDR parses s as a CIDR notation IP address and mask,
-// like "192.168.100.1/24" or "2001:DB8::/48", as defined in
+// like "192.0.2.0/24" or "2001:db8::/32", as defined in
 // RFC 4632 and RFC 4291.
 //
 // It returns the IP address and the network implied by the IP
-// and mask.  For example, ParseCIDR("192.168.100.1/16") returns
-// the IP address 192.168.100.1 and the network 192.168.0.0/16.
+// and mask. For example, ParseCIDR("198.51.100.1/24") returns
+// the IP address 198.51.100.1 and the network 198.51.100.0/24.
 func ParseCIDR(s string) (IP, *IPNet, error) {
 	i := byteIndex(s, '/')
 	if i < 0 {
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index 3d95a73..b6ac26d 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -5,6 +5,7 @@
 package net
 
 import (
+	"bytes"
 	"reflect"
 	"runtime"
 	"testing"
@@ -124,30 +125,119 @@ func TestMarshalEmptyIP(t *testing.T) {
 }
 
 var ipStringTests = []struct {
-	in  IP
-	out string // see RFC 5952
+	in  IP     // see RFC 791 and RFC 4291
+	str string // see RFC 791, RFC 4291 and RFC 5952
+	byt []byte
+	error
 }{
-	{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, "2001:db8::123:12:1"},
-	{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1"},
-	{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1}, "2001:db8:0:1:0:1:0:1"},
-	{IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0}, "2001:db8:1:0:1:0:1:0"},
-	{IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001::1:0:0:1"},
-	{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0}, "2001:db8:0:0:1::"},
-	{IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1}, "2001:db8::1:0:0:1"},
-	{IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD}, "2001:db8::a:b:c:d"},
-	{IPv4(192, 168, 0, 1), "192.168.0.1"},
-	{nil, ""},
+	// IPv4 address
+	{
+		IP{192, 0, 2, 1},
+		"192.0.2.1",
+		[]byte("192.0.2.1"),
+		nil,
+	},
+	{
+		IP{0, 0, 0, 0},
+		"0.0.0.0",
+		[]byte("0.0.0.0"),
+		nil,
+	},
+
+	// IPv4-mapped IPv6 address
+	{
+		IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 192, 0, 2, 1},
+		"192.0.2.1",
+		[]byte("192.0.2.1"),
+		nil,
+	},
+	{
+		IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0},
+		"0.0.0.0",
+		[]byte("0.0.0.0"),
+		nil,
+	},
+
+	// IPv6 address
+	{
+		IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
+		"2001:db8::123:12:1",
+		[]byte("2001:db8::123:12:1"),
+		nil,
+	},
+	{
+		IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1},
+		"2001:db8::1",
+		[]byte("2001:db8::1"),
+		nil,
+	},
+	{
+		IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1},
+		"2001:db8:0:1:0:1:0:1",
+		[]byte("2001:db8:0:1:0:1:0:1"),
+		nil,
+	},
+	{
+		IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0},
+		"2001:db8:1:0:1:0:1:0",
+		[]byte("2001:db8:1:0:1:0:1:0"),
+		nil,
+	},
+	{
+		IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+		"2001::1:0:0:1",
+		[]byte("2001::1:0:0:1"),
+		nil,
+	},
+	{
+		IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0},
+		"2001:db8:0:0:1::",
+		[]byte("2001:db8:0:0:1::"),
+		nil,
+	},
+	{
+		IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+		"2001:db8::1:0:0:1",
+		[]byte("2001:db8::1:0:0:1"),
+		nil,
+	},
+	{
+		IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0xa, 0, 0xb, 0, 0xc, 0, 0xd},
+		"2001:db8::a:b:c:d",
+		[]byte("2001:db8::a:b:c:d"),
+		nil,
+	},
+	{
+		IPv6unspecified,
+		"::",
+		[]byte("::"),
+		nil,
+	},
+
+	// IP wildcard equivalent address in Dial/Listen API
+	{
+		nil,
+		"<nil>",
+		nil,
+		nil,
+	},
+
+	// Opaque byte sequence
+	{
+		IP{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+		"?0123456789abcdef",
+		nil,
+		&AddrError{Err: "invalid IP address", Addr: "0123456789abcdef"},
+	},
 }
 
 func TestIPString(t *testing.T) {
 	for _, tt := range ipStringTests {
-		if tt.in != nil {
-			if out := tt.in.String(); out != tt.out {
-				t.Errorf("IP.String(%v) = %q, want %q", tt.in, out, tt.out)
-			}
+		if out := tt.in.String(); out != tt.str {
+			t.Errorf("IP.String(%v) = %q, want %q", tt.in, out, tt.str)
 		}
-		if out, err := tt.in.MarshalText(); string(out) != tt.out || err != nil {
-			t.Errorf("IP.MarshalText(%v) = %q, %v, want %q, nil", tt.in, out, err, tt.out)
+		if out, err := tt.in.MarshalText(); !bytes.Equal(out, tt.byt) || !reflect.DeepEqual(err, tt.error) {
+			t.Errorf("IP.MarshalText(%v) = %v, %v, want %v, %v", tt.in, out, err, tt.byt, tt.error)
 		}
 	}
 }
@@ -379,8 +469,8 @@ var splitJoinTests = []struct {
 	{"", "0", ":0"},
 
 	{"google.com", "https%foo", "google.com:https%foo"}, // Go 1.0 behavior
-	{"127.0.0.1", "", "127.0.0.1:"},                     // Go 1.0 behaviour
-	{"www.google.com", "", "www.google.com:"},           // Go 1.0 behaviour
+	{"127.0.0.1", "", "127.0.0.1:"},                     // Go 1.0 behavior
+	{"www.google.com", "", "www.google.com:"},           // Go 1.0 behavior
 }
 
 var splitFailureTests = []struct {
@@ -421,13 +511,16 @@ func TestSplitHostPort(t *testing.T) {
 		}
 	}
 	for _, tt := range splitFailureTests {
-		if _, _, err := SplitHostPort(tt.hostPort); err == nil {
+		if host, port, err := SplitHostPort(tt.hostPort); err == nil {
 			t.Errorf("SplitHostPort(%q) should have failed", tt.hostPort)
 		} else {
 			e := err.(*AddrError)
 			if e.Err != tt.err {
 				t.Errorf("SplitHostPort(%q) = _, _, %q; want %q", tt.hostPort, e.Err, tt.err)
 			}
+			if host != "" || port != "" {
+				t.Errorf("SplitHostPort(%q) = %q, %q, err; want %q, %q, err on failure", tt.hostPort, host, port, "", "")
+			}
 		}
 	}
 }
diff --git a/src/net/ipraw_test.go b/src/net/ipraw_test.go
deleted file mode 100644
index 5d86a9d..0000000
--- a/src/net/ipraw_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 (
-	"reflect"
-	"testing"
-)
-
-// 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 {
-	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},
-
-	{"ip", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
-	{"ip6", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
-	{"ip6:ipv6-icmp", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
-	{"ip6:IPv6-ICMP", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
-
-	{"ip", "::1%en0", &IPAddr{IP: ParseIP("::1"), Zone: "en0"}, nil},
-	{"ip6", "::1%911", &IPAddr{IP: ParseIP("::1"), Zone: "911"}, nil},
-
-	{"", "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 TestResolveIPAddr(t *testing.T) {
-	if !testableNetwork("ip+nopriv") {
-		t.Skip("ip+nopriv test")
-	}
-
-	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.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 := ResolveIPAddr(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)
-		}
-	}
-}
-
-var ipConnLocalNameTests = []struct {
-	net   string
-	laddr *IPAddr
-}{
-	{"ip4:icmp", &IPAddr{IP: IPv4(127, 0, 0, 1)}},
-	{"ip4:icmp", &IPAddr{}},
-	{"ip4:icmp", nil},
-}
-
-func TestIPConnLocalName(t *testing.T) {
-	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.Fatal(err)
-		}
-		defer c.Close()
-		if la := c.LocalAddr(); la == nil {
-			t.Fatal("should not fail")
-		}
-	}
-}
-
-func TestIPConnRemoteName(t *testing.T) {
-	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.Fatal(err)
-	}
-	defer c.Close()
-	if !reflect.DeepEqual(raddr, c.RemoteAddr()) {
-		t.Fatalf("got %#v; want %#v", c.RemoteAddr(), raddr)
-	}
-}
diff --git a/src/net/iprawsock.go b/src/net/iprawsock.go
index f02df7f..173b3cb 100644
--- a/src/net/iprawsock.go
+++ b/src/net/iprawsock.go
@@ -1,9 +1,14 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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 net
 
+import (
+	"context"
+	"syscall"
+)
+
 // IPAddr represents the address of an IP end point.
 type IPAddr struct {
 	IP   IP
@@ -45,7 +50,7 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) {
 	if net == "" { // a hint wildcard for Go 1.0 undocumented behavior
 		net = "ip"
 	}
-	afnet, _, err := parseNetwork(net)
+	afnet, _, err := parseNetwork(context.Background(), net)
 	if err != nil {
 		return nil, err
 	}
@@ -54,9 +59,136 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	addrs, err := internetAddrList(afnet, addr, noDeadline)
+	addrs, err := internetAddrList(context.Background(), afnet, addr)
 	if err != nil {
 		return nil, err
 	}
 	return addrs.first(isIPv4).(*IPAddr), nil
 }
+
+// IPConn is the implementation of the Conn and PacketConn interfaces
+// for IP network connections.
+type IPConn struct {
+	conn
+}
+
+// ReadFromIP reads an IP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromIP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetReadDeadline.
+func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
+	if !c.ok() {
+		return 0, nil, syscall.EINVAL
+	}
+	n, addr, err := c.readFrom(b)
+	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.
+func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
+	if !c.ok() {
+		return 0, nil, syscall.EINVAL
+	}
+	n, addr, err := c.readFrom(b)
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: 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
+// associated out-of-band data into oob. It returns the number of
+// 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) {
+	if !c.ok() {
+		return 0, 0, 0, nil, syscall.EINVAL
+	}
+	n, oobn, flags, addr, err = c.readMsg(b, oob)
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return
+}
+
+// WriteToIP writes an IP packet to addr via c, copying the payload
+// from b.
+//
+// WriteToIP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetWriteDeadline. On packet-oriented connections, write timeouts
+// are rare.
+func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	n, err := c.writeTo(b, addr)
+	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.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	a, ok := addr.(*IPAddr)
+	if !ok {
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+	}
+	n, err := c.writeTo(b, a)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
+	}
+	return n, err
+}
+
+// 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) {
+	if !c.ok() {
+		return 0, 0, syscall.EINVAL
+	}
+	n, oobn, err = c.writeMsg(b, oob, addr)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	return
+}
+
+func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
+
+// DialIP connects to the remote address raddr on the network protocol
+// netProto, which must be "ip", "ip4", or "ip6" followed by a colon
+// and a protocol number or name.
+func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
+	c, err := dialIP(context.Background(), netProto, laddr, raddr)
+	if err != nil {
+		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+	}
+	return c, nil
+}
+
+// ListenIP listens for incoming IP packets addressed to the local
+// address laddr. The returned connection's ReadFrom and WriteTo
+// methods can be used to receive and send IP packets with per-packet
+// addressing.
+func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
+	c, err := listenIP(context.Background(), netProto, laddr)
+	if err != nil {
+		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
+	}
+	return c, nil
+}
diff --git a/src/net/iprawsock_plan9.go b/src/net/iprawsock_plan9.go
index b027adc..6aebea1 100644
--- a/src/net/iprawsock_plan9.go
+++ b/src/net/iprawsock_plan9.go
@@ -1,82 +1,34 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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 net
 
 import (
+	"context"
 	"syscall"
-	"time"
 )
 
-// IPConn is the implementation of the Conn and PacketConn interfaces
-// for IP network connections.
-type IPConn struct {
-	conn
+func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
+	return 0, nil, syscall.EPLAN9
 }
 
-// ReadFromIP reads an IP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// ReadFromIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetReadDeadline.
-func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
-	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
+	return 0, 0, 0, nil, syscall.EPLAN9
 }
 
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
-	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) {
+	return 0, syscall.EPLAN9
 }
 
-// ReadMsgIP reads a packet from c, copying the payload into b and the
-// associated out-of-band data into oob.  It returns the number of
-// 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, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
+	return 0, 0, syscall.EPLAN9
 }
 
-// WriteToIP writes an IP packet to addr via c, copying the payload
-// from b.
-//
-// WriteToIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline.  On packet-oriented connections, write timeouts
-// are rare.
-func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
-	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+func dialIP(ctx context.Context, netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
+	return nil, syscall.EPLAN9
 }
 
-// WriteTo implements the PacketConn WriteTo method.
-func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
-	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, &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
-// netProto, which must be "ip", "ip4", or "ip6" followed by a colon
-// and a protocol number or name.
-func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
-	return dialIP(netProto, laddr, raddr, noDeadline)
-}
-
-func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
-	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
-// address laddr.  The returned connection's ReadFrom and WriteTo
-// methods can be used to receive and send IP packets with per-packet
-// addressing.
-func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
-	return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
+func listenIP(ctx context.Context, netProto string, laddr *IPAddr) (*IPConn, error) {
+	return nil, syscall.EPLAN9
 }
diff --git a/src/net/iprawsock_posix.go b/src/net/iprawsock_posix.go
index 93fee3e..3e0b060 100644
--- a/src/net/iprawsock_posix.go
+++ b/src/net/iprawsock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,8 +7,8 @@
 package net
 
 import (
+	"context"
 	"syscall"
-	"time"
 )
 
 // BUG(mikio): On every POSIX platform, reads from the "ip4" network
@@ -50,25 +50,7 @@ func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	return ipToSockaddr(family, a.IP, 0, a.Zone)
 }
 
-// IPConn is the implementation of the Conn and PacketConn interfaces
-// for IP network connections.
-type IPConn struct {
-	conn
-}
-
-func newIPConn(fd *netFD) *IPConn { return &IPConn{conn{fd}} }
-
-// ReadFromIP reads an IP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// ReadFromIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetReadDeadline.
-func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
-	if !c.ok() {
-		return 0, nil, syscall.EINVAL
-	}
+func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
 	// TODO(cw,rsc): consider using readv if we know the family
 	// type to avoid the header trim/copy
 	var addr *IPAddr
@@ -80,9 +62,6 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
 	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
 }
 
@@ -101,26 +80,7 @@ func stripIPv4Header(n int, b []byte) int {
 	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)
-	if addr == nil {
-		return n, nil, err
-	}
-	return n, addr, err
-}
-
-// ReadMsgIP reads a packet from c, copying the payload into b and the
-// associated out-of-band data into oob.  It returns the number of
-// 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) {
-	if !c.ok() {
-		return 0, 0, 0, nil, syscall.EINVAL
-	}
+func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
 	var sa syscall.Sockaddr
 	n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
 	switch sa := sa.(type) {
@@ -129,121 +89,70 @@ 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
 }
 
-// WriteToIP writes an IP packet to addr via c, copying the payload
-// from b.
-//
-// WriteToIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline.  On packet-oriented connections, write timeouts
-// are rare.
-func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
+func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) {
 	if c.fd.isConnected {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		return 0, ErrWriteToConnected
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+		return 0, errMissingAddress
 	}
 	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		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 n, err
-}
-
-// WriteTo implements the PacketConn WriteTo method.
-func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	a, ok := addr.(*IPAddr)
-	if !ok {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+		return 0, err
 	}
-	return c.WriteToIP(b, a)
+	return c.fd.writeTo(b, sa)
 }
 
-// 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) {
-	if !c.ok() {
-		return 0, 0, syscall.EINVAL
-	}
+func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
 	if c.fd.isConnected {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		return 0, 0, ErrWriteToConnected
 	}
 	if addr == nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
-	}
-	var sa syscall.Sockaddr
-	sa, err = addr.sockaddr(c.fd.family)
-	if err != nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+		return 0, 0, errMissingAddress
 	}
-	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+		return 0, 0, err
 	}
-	return
-}
-
-// DialIP connects to the remote address raddr on the network protocol
-// netProto, which must be "ip", "ip4", or "ip6" followed by a colon
-// and a protocol number or name.
-func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
-	return dialIP(netProto, laddr, raddr, noDeadline)
+	return c.fd.writeMsg(b, oob, sa)
 }
 
-func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
-	net, proto, err := parseNetwork(netProto)
+func dialIP(ctx context.Context, netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
+	network, proto, err := parseNetwork(ctx, netProto)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+		return nil, err
 	}
-	switch net {
+	switch network {
 	case "ip", "ip4", "ip6":
 	default:
-		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(netProto)}
+		return nil, UnknownNetworkError(netProto)
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+		return nil, errMissingAddress
 	}
-	fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial", noCancel)
+	fd, err := internetSocket(ctx, network, laddr, raddr, syscall.SOCK_RAW, proto, "dial")
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+		return nil, err
 	}
 	return newIPConn(fd), nil
 }
 
-// ListenIP listens for incoming IP packets addressed to the local
-// address laddr.  The returned connection's ReadFrom and WriteTo
-// methods can be used to receive and send IP packets with per-packet
-// addressing.
-func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
-	net, proto, err := parseNetwork(netProto)
+func listenIP(ctx context.Context, netProto string, laddr *IPAddr) (*IPConn, error) {
+	network, proto, err := parseNetwork(ctx, netProto)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
+		return nil, err
 	}
-	switch net {
+	switch network {
 	case "ip", "ip4", "ip6":
 	default:
-		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(netProto)}
+		return nil, UnknownNetworkError(netProto)
 	}
-	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen", noCancel)
+	fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_RAW, proto, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
+		return nil, err
 	}
 	return newIPConn(fd), nil
 }
diff --git a/src/net/iprawsock_test.go b/src/net/iprawsock_test.go
new file mode 100644
index 0000000..29cd4b6
--- /dev/null
+++ b/src/net/iprawsock_test.go
@@ -0,0 +1,116 @@
+// 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 (
+	"reflect"
+	"testing"
+)
+
+// 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 {
+	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},
+
+	{"ip", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
+	{"ip6", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
+	{"ip6:ipv6-icmp", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
+	{"ip6:IPv6-ICMP", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
+
+	{"ip", "::1%en0", &IPAddr{IP: ParseIP("::1"), Zone: "en0"}, nil},
+	{"ip6", "::1%911", &IPAddr{IP: ParseIP("::1"), Zone: "911"}, nil},
+
+	{"", "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 TestResolveIPAddr(t *testing.T) {
+	if !testableNetwork("ip+nopriv") {
+		t.Skip("ip+nopriv test")
+	}
+
+	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.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 := ResolveIPAddr(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)
+		}
+	}
+}
+
+var ipConnLocalNameTests = []struct {
+	net   string
+	laddr *IPAddr
+}{
+	{"ip4:icmp", &IPAddr{IP: IPv4(127, 0, 0, 1)}},
+	{"ip4:icmp", &IPAddr{}},
+	{"ip4:icmp", nil},
+}
+
+func TestIPConnLocalName(t *testing.T) {
+	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.Fatal(err)
+		}
+		defer c.Close()
+		if la := c.LocalAddr(); la == nil {
+			t.Fatal("should not fail")
+		}
+	}
+}
+
+func TestIPConnRemoteName(t *testing.T) {
+	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.Fatal(err)
+	}
+	defer c.Close()
+	if !reflect.DeepEqual(raddr, c.RemoteAddr()) {
+		t.Fatalf("got %#v; want %#v", c.RemoteAddr(), raddr)
+	}
+}
diff --git a/src/net/ipsock.go b/src/net/ipsock.go
index 55f697f..24daf17 100644
--- a/src/net/ipsock.go
+++ b/src/net/ipsock.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,8 +7,7 @@
 package net
 
 import (
-	"errors"
-	"time"
+	"context"
 )
 
 var (
@@ -22,7 +21,7 @@ var (
 
 	// supportsIPv4map reports whether the platform supports
 	// mapping an IPv4 address inside an IPv6 address at transport
-	// layer protocols.  See RFC 4291, RFC 4038 and RFC 3493.
+	// layer protocols. See RFC 4291, RFC 4038 and RFC 3493.
 	supportsIPv4map bool
 )
 
@@ -73,8 +72,6 @@ func (addrs addrList) partition(strategy func(Addr) bool) (primaries, fallbacks
 	return
 }
 
-var errNoSuitableAddress = errors.New("no suitable address found")
-
 // 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.
@@ -106,73 +103,65 @@ func ipv6only(addr IPAddr) bool {
 
 // SplitHostPort splits a network address of the form "host:port",
 // "[host]:port" or "[ipv6-host%zone]:port" into host or
-// ipv6-host%zone and port.  A literal address or host name for IPv6
+// ipv6-host%zone and port. A literal address or host name for IPv6
 // must be enclosed in square brackets, as in "[::1]:80",
 // "[ipv6-host]:http" or "[ipv6-host%zone]:80".
 func SplitHostPort(hostport string) (host, port string, err error) {
+	const (
+		missingPort   = "missing port in address"
+		tooManyColons = "too many colons in address"
+	)
+	addrErr := func(addr, why string) (host, port string, err error) {
+		return "", "", &AddrError{Err: why, Addr: addr}
+	}
 	j, k := 0, 0
 
 	// The port starts after the last colon.
 	i := last(hostport, ':')
 	if i < 0 {
-		goto missingPort
+		return addrErr(hostport, missingPort)
 	}
 
 	if hostport[0] == '[' {
 		// Expect the first ']' just before the last ':'.
 		end := byteIndex(hostport, ']')
 		if end < 0 {
-			err = &AddrError{Err: "missing ']' in address", Addr: hostport}
-			return
+			return addrErr(hostport, "missing ']' in address")
 		}
 		switch end + 1 {
 		case len(hostport):
 			// There can't be a ':' behind the ']' now.
-			goto missingPort
+			return addrErr(hostport, missingPort)
 		case i:
 			// The expected result.
 		default:
 			// Either ']' isn't followed by a colon, or it is
 			// followed by a colon that is not the last one.
 			if hostport[end+1] == ':' {
-				goto tooManyColons
+				return addrErr(hostport, tooManyColons)
 			}
-			goto missingPort
+			return addrErr(hostport, missingPort)
 		}
 		host = hostport[1:end]
 		j, k = 1, end+1 // there can't be a '[' resp. ']' before these positions
 	} else {
 		host = hostport[:i]
 		if byteIndex(host, ':') >= 0 {
-			goto tooManyColons
+			return addrErr(hostport, tooManyColons)
 		}
 		if byteIndex(host, '%') >= 0 {
-			goto missingBrackets
+			return addrErr(hostport, "missing brackets in address")
 		}
 	}
 	if byteIndex(hostport[j:], '[') >= 0 {
-		err = &AddrError{Err: "unexpected '[' in address", Addr: hostport}
-		return
+		return addrErr(hostport, "unexpected '[' in address")
 	}
 	if byteIndex(hostport[k:], ']') >= 0 {
-		err = &AddrError{Err: "unexpected ']' in address", Addr: hostport}
-		return
+		return addrErr(hostport, "unexpected ']' in address")
 	}
 
 	port = hostport[i+1:]
-	return
-
-missingPort:
-	err = &AddrError{Err: "missing port in address", Addr: hostport}
-	return
-
-tooManyColons:
-	err = &AddrError{Err: "too many colons in address", Addr: hostport}
-	return
-
-missingBrackets:
-	err = &AddrError{Err: "missing brackets in address", Addr: hostport}
-	return
+	return host, port, nil
 }
 
 func splitHostZone(s string) (host, zone string) {
@@ -201,7 +190,7 @@ func JoinHostPort(host, port string) string {
 // 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) {
+func internetAddrList(ctx context.Context, net, addr string) (addrList, error) {
 	var (
 		err        error
 		host, port string
@@ -249,7 +238,7 @@ func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
 		return addrList{inetaddr(IPAddr{IP: ip, Zone: zone})}, nil
 	}
 	// Try as a DNS name.
-	ips, err := lookupIPDeadline(host, deadline)
+	ips, err := lookupIPContext(ctx, host)
 	if err != nil {
 		return nil, err
 	}
@@ -262,24 +251,3 @@ func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
 	}
 	return filterAddrList(filter, ips, inetaddr)
 }
-
-func zoneToString(zone int) string {
-	if zone == 0 {
-		return ""
-	}
-	if ifi, err := InterfaceByIndex(zone); err == nil {
-		return ifi.Name
-	}
-	return uitoa(uint(zone))
-}
-
-func zoneToInt(zone string) int {
-	if zone == "" {
-		return 0
-	}
-	if ifi, err := InterfaceByName(zone); err == nil {
-		return ifi.Index
-	}
-	n, _, _ := dtoi(zone, 0)
-	return n
-}
diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go
index 9da6ec3..2b84683 100644
--- a/src/net/ipsock_plan9.go
+++ b/src/net/ipsock_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,6 +7,7 @@
 package net
 
 import (
+	"context"
 	"os"
 	"syscall"
 )
@@ -39,8 +40,8 @@ func probeIPv4Stack() bool {
 	return probe(netdir+"/iproute", "4i")
 }
 
-// probeIPv6Stack returns two boolean values.  If the first boolean
-// value is true, kernel supports basic IPv6 functionality.  If the
+// probeIPv6Stack returns two boolean values. If the first boolean
+// value is true, kernel supports basic IPv6 functionality. If the
 // second boolean value is true, kernel supports IPv6 IPv4-mapping.
 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	// Plan 9 uses IPv6 natively, see ip(3).
@@ -99,7 +100,7 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) {
 	return addr, nil
 }
 
-func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
+func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest, proto, name string, err error) {
 	var (
 		ip   IP
 		port int
@@ -118,7 +119,7 @@ func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string,
 		return
 	}
 
-	clone, dest, err := queryCS1(proto, ip, port)
+	clone, dest, err := queryCS1(ctx, proto, ip, port)
 	if err != nil {
 		return
 	}
@@ -135,8 +136,8 @@ func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string,
 	return f, dest, proto, string(buf[:n]), nil
 }
 
-func netErr(e error) {
-	oe, ok := e.(*OpError)
+func fixErr(err error) {
+	oe, ok := err.(*OpError)
 	if !ok {
 		return
 	}
@@ -165,46 +166,71 @@ func netErr(e error) {
 	}
 }
 
-func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
-	defer func() { netErr(err) }()
-	f, dest, proto, name, err := startPlan9(net, raddr)
+func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
+	defer func() { fixErr(err) }()
+	type res struct {
+		fd  *netFD
+		err error
+	}
+	resc := make(chan res)
+	go func() {
+		testHookDialChannel()
+		fd, err := dialPlan9Blocking(ctx, net, laddr, raddr)
+		select {
+		case resc <- res{fd, err}:
+		case <-ctx.Done():
+			if fd != nil {
+				fd.Close()
+			}
+		}
+	}()
+	select {
+	case res := <-resc:
+		return res.fd, res.err
+	case <-ctx.Done():
+		return nil, mapErr(ctx.Err())
+	}
+}
+
+func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
+	f, dest, proto, name, err := startPlan9(ctx, net, raddr)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
+		return nil, err
 	}
 	_, err = f.WriteString("connect " + dest)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err}
+		return nil, err
 	}
 	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
+		return nil, err
 	}
 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		data.Close()
 		f.Close()
-		return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err}
+		return nil, err
 	}
 	return newFD(proto, name, f, data, laddr, raddr)
 }
 
-func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
-	defer func() { netErr(err) }()
-	f, dest, proto, name, err := startPlan9(net, laddr)
+func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
+	defer func() { fixErr(err) }()
+	f, dest, proto, name, err := startPlan9(ctx, net, laddr)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, err
 	}
 	_, err = f.WriteString("announce " + dest)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err}
+		return nil, err
 	}
 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, err
 	}
 	return newFD(proto, name, f, nil, laddr, nil)
 }
@@ -214,32 +240,32 @@ func (fd *netFD) netFD() (*netFD, error) {
 }
 
 func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
-	defer func() { netErr(err) }()
+	defer func() { fixErr(err) }()
 	if err := fd.readLock(); err != nil {
 		return nil, err
 	}
 	defer fd.readUnlock()
 	f, err := os.Open(fd.dir + "/listen")
 	if err != nil {
-		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
+		return nil, err
 	}
 	var buf [16]byte
 	n, err := f.Read(buf[:])
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
+		return nil, err
 	}
 	name := string(buf[:n])
 	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
+		return nil, err
 	}
 	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
 	if err != nil {
 		data.Close()
 		f.Close()
-		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
+		return nil, err
 	}
 	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 2bddd46..abe90ac 100644
--- a/src/net/ipsock_posix.go
+++ b/src/net/ipsock_posix.go
@@ -1,17 +1,15 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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
 
-// Internet protocol family sockets for POSIX
-
 package net
 
 import (
+	"context"
 	"runtime"
 	"syscall"
-	"time"
 )
 
 // BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the
@@ -35,15 +33,15 @@ func probeIPv4Stack() bool {
 // Should we try to use the IPv4 socket interface if we're
 // only dealing with IPv4 sockets?  As long as the host system
 // understands IPv6, it's okay to pass IPv4 addresses to the IPv6
-// interface.  That simplifies our code and is most general.
+// interface. That simplifies our code and is most general.
 // Unfortunately, we need to run on kernels built without IPv6
-// support too.  So probe the kernel to figure it out.
+// support too. So probe the kernel to figure it out.
 //
 // probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4-
 // mapping capability which is controlled by IPV6_V6ONLY socket
 // option and/or kernel state "net.inet6.ip6.v6only".
-// It returns two boolean values.  If the first boolean value is
-// true, kernel supports basic IPv6 functionality.  If the second
+// It returns two boolean values. If the first boolean value is
+// true, kernel supports basic IPv6 functionality. If the second
 // boolean value is true, kernel supports IPv6 IPv4-mapping.
 func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	var probes = []struct {
@@ -52,7 +50,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	}{
 		// IPv6 communication capability
 		{laddr: TCPAddr{IP: ParseIP("::1")}, value: 1},
-		// IPv6 IPv4-mapped address communication capability
+		// IPv4-mapped IPv6 address communication capability
 		{laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
 	}
 	var supps [2]bool
@@ -61,7 +59,7 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 		// 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
+		// stops pretending, but the transition period would
 		// cause unpredictable behavior and we need to avoid
 		// it.
 		//
@@ -93,8 +91,8 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 }
 
 // favoriteAddrFamily returns the appropriate address family to
-// the given net, laddr, raddr and mode.  At first it figures
-// address family out from the net.  If mode indicates "listen"
+// the given net, laddr, raddr and mode. At first it figures
+// address family out from the net. If mode indicates "listen"
 // and laddr is a wildcard, it assumes that the user wants to
 // make a passive connection with a wildcard address family, both
 // AF_INET and AF_INET6, and a wildcard address like following:
@@ -155,10 +153,9 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family
 }
 
 // Internet sockets (TCP, UDP, IP)
-
-func internetSocket(net string, laddr, raddr sockaddr, deadline time.Time, sotype, proto int, mode string, cancel <-chan struct{}) (fd *netFD, err error) {
+func internetSocket(ctx context.Context, net string, laddr, raddr sockaddr, sotype, proto int, mode string) (fd *netFD, err error) {
 	family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
-	return socket(net, family, sotype, proto, ipv6only, laddr, raddr, deadline, cancel)
+	return socket(ctx, net, family, sotype, proto, ipv6only, laddr, raddr)
 }
 
 func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) {
@@ -167,34 +164,35 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
 		if len(ip) == 0 {
 			ip = IPv4zero
 		}
-		if ip = ip.To4(); ip == nil {
+		ip4 := ip.To4()
+		if ip4 == nil {
 			return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
 		}
-		sa := new(syscall.SockaddrInet4)
-		for i := 0; i < IPv4len; i++ {
-			sa.Addr[i] = ip[i]
-		}
-		sa.Port = port
+		sa := &syscall.SockaddrInet4{Port: port}
+		copy(sa.Addr[:], ip4)
 		return sa, nil
 	case syscall.AF_INET6:
-		if len(ip) == 0 {
-			ip = IPv6zero
-		}
-		// IPv4 callers use 0.0.0.0 to mean "announce on any available address".
-		// In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
-		// which it refuses to do.  Rewrite to the IPv6 unspecified address.
-		if ip.Equal(IPv4zero) {
+		// In general, an IP wildcard address, which is either
+		// "0.0.0.0" or "::", means the entire IP addressing
+		// space. For some historical reason, it is used to
+		// specify "any available address" on some operations
+		// of IP node.
+		//
+		// When the IP node supports IPv4-mapped IPv6 address,
+		// we allow an listener to listen to the wildcard
+		// address of both IP addressing spaces by specifying
+		// IPv6 wildcard address.
+		if len(ip) == 0 || ip.Equal(IPv4zero) {
 			ip = IPv6zero
 		}
-		if ip = ip.To16(); ip == nil {
+		// We accept any IPv6 address including IPv4-mapped
+		// IPv6 address.
+		ip6 := ip.To16()
+		if ip6 == nil {
 			return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
 		}
-		sa := new(syscall.SockaddrInet6)
-		for i := 0; i < IPv6len; i++ {
-			sa.Addr[i] = ip[i]
-		}
-		sa.Port = port
-		sa.ZoneId = uint32(zoneToInt(zone))
+		sa := &syscall.SockaddrInet6{Port: port, ZoneId: uint32(zoneToInt(zone))}
+		copy(sa.Addr[:], ip6)
 		return sa, nil
 	}
 	return nil, &AddrError{Err: "invalid address family", Addr: ip.String()}
diff --git a/src/net/listen_test.go b/src/net/listen_test.go
index 51ffe67..6037f36 100644
--- a/src/net/listen_test.go
+++ b/src/net/listen_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,6 +8,7 @@ package net
 
 import (
 	"fmt"
+	"internal/testenv"
 	"os"
 	"runtime"
 	"syscall"
@@ -157,7 +158,7 @@ var dualStackTCPListenerTests = []struct {
 	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
+	// Test cases and expected results for the attempting 2nd listen on the same port
 	// 1st listen                2nd listen                 darwin  freebsd  linux  openbsd
 	// ------------------------------------------------------------------------------------
 	// "tcp"  ""                 "tcp"  ""                    -        -       -       -
@@ -216,9 +217,12 @@ var dualStackTCPListenerTests = []struct {
 // TestDualStackTCPListener tests both single and double listen
 // to a test listener with various address families, different
 // listening address and same port.
+//
+// On DragonFly BSD, we expect the kernel version of node under test
+// to be greater than or equal to 4.4.
 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
+	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	if !supportsIPv4 || !supportsIPv6 {
@@ -301,11 +305,14 @@ var dualStackUDPListenerTests = []struct {
 }
 
 // TestDualStackUDPListener tests both single and double listen
-// to a test listener with various address families, differnet
+// to a test listener with various address families, different
 // listening address and same port.
+//
+// On DragonFly BSD, we expect the kernel version of node under test
+// to be greater than or equal to 4.4.
 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
+	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	if !supportsIPv4 || !supportsIPv6 {
@@ -477,13 +484,12 @@ func checkDualStackAddrFamily(fd *netFD) error {
 }
 
 func TestWildWildcardListener(t *testing.T) {
+	testenv.MustHaveExternalNetwork(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 {
@@ -521,12 +527,17 @@ var ipv4MulticastListenerTests = []struct {
 // test listener with same address family, same group address and same
 // port.
 func TestIPv4MulticastListener(t *testing.T) {
+	testenv.MustHaveExternalNetwork(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")
 	}
+	if !supportsIPv4 {
+		t.Skip("IPv4 is not supported")
+	}
 
 	closer := func(cs []*UDPConn) {
 		for _, c := range cs {
@@ -542,7 +553,7 @@ func TestIPv4MulticastListener(t *testing.T) {
 		// routing stuff for finding out an appropriate
 		// nexthop containing both network and link layer
 		// adjacencies.
-		if ifi == nil && (testing.Short() || !*testExternal) {
+		if ifi == nil || !*testIPv4 {
 			continue
 		}
 		for _, tt := range ipv4MulticastListenerTests {
@@ -591,6 +602,8 @@ var ipv6MulticastListenerTests = []struct {
 // test listener with same address family, same group address and same
 // port.
 func TestIPv6MulticastListener(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -598,7 +611,7 @@ func TestIPv6MulticastListener(t *testing.T) {
 		t.Skipf("not supported on solaris, see issue 7399")
 	}
 	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
+		t.Skip("IPv6 is not supported")
 	}
 	if os.Getuid() != 0 {
 		t.Skip("must be root")
@@ -618,7 +631,7 @@ func TestIPv6MulticastListener(t *testing.T) {
 		// routing stuff for finding out an appropriate
 		// nexthop containing both network and link layer
 		// adjacencies.
-		if ifi == nil && (testing.Short() || !*testExternal || !*testIPv6) {
+		if ifi == nil && !*testIPv6 {
 			continue
 		}
 		for _, tt := range ipv6MulticastListenerTests {
diff --git a/src/net/lookup.go b/src/net/lookup.go
index 7aa111b..c169e9e 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -1,12 +1,13 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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 net
 
 import (
+	"context"
+	"internal/nettrace"
 	"internal/singleflight"
-	"time"
 )
 
 // protocols contains minimal mappings between internet protocol
@@ -33,7 +34,7 @@ func LookupHost(host string) (addrs []string, err error) {
 	if ip := ParseIP(host); ip != nil {
 		return []string{host}, nil
 	}
-	return lookupHost(host)
+	return lookupHost(context.Background(), host)
 }
 
 // LookupIP looks up host using the local resolver.
@@ -47,7 +48,7 @@ func LookupIP(host string) (ips []IP, err error) {
 	if ip := ParseIP(host); ip != nil {
 		return []IP{ip}, nil
 	}
-	addrs, err := lookupIPMerge(host)
+	addrs, err := lookupIPMerge(context.Background(), host)
 	if err != nil {
 		return
 	}
@@ -63,9 +64,9 @@ 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 []IPAddr, err error) {
+func lookupIPMerge(ctx context.Context, host string) (addrs []IPAddr, err error) {
 	addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
-		return testHookLookupIP(lookupIP, host)
+		return testHookLookupIP(ctx, lookupIP, host)
 	})
 	return lookupIPReturn(addrsi, err, shared)
 }
@@ -85,52 +86,65 @@ func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error
 	return addrs, nil
 }
 
-// lookupIPDeadline looks up a hostname with a deadline.
-func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err error) {
-	if deadline.IsZero() {
-		return lookupIPMerge(host)
+// ipAddrsEface returns an empty interface slice of addrs.
+func ipAddrsEface(addrs []IPAddr) []interface{} {
+	s := make([]interface{}, len(addrs))
+	for i, v := range addrs {
+		s[i] = v
 	}
+	return s
+}
 
-	// We could push the deadline down into the name resolution
-	// functions.  However, the most commonly used implementation
-	// calls getaddrinfo, which has no timeout.
-
-	timeout := deadline.Sub(time.Now())
-	if timeout <= 0 {
-		return nil, errTimeout
+// lookupIPContext looks up a hostname with a context.
+//
+// TODO(bradfitz): rename this function. All the other
+// build-tag-specific lookupIP funcs also take a context now, so this
+// name is no longer great. Maybe make this lookupIPMerge and ditch
+// the other one, making its callers call this instead with a
+// context.Background().
+func lookupIPContext(ctx context.Context, host string) (addrs []IPAddr, err error) {
+	trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
+	if trace != nil && trace.DNSStart != nil {
+		trace.DNSStart(host)
+	}
+	// The underlying resolver func is lookupIP by default but it
+	// can be overridden by tests. This is needed by net/http, so it
+	// uses a context key instead of unexported variables.
+	resolverFunc := lookupIP
+	if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil {
+		resolverFunc = alt
 	}
-	t := time.NewTimer(timeout)
-	defer t.Stop()
 
 	ch := lookupGroup.DoChan(host, func() (interface{}, error) {
-		return testHookLookupIP(lookupIP, host)
+		return testHookLookupIP(ctx, resolverFunc, host)
 	})
 
 	select {
-	case <-t.C:
-		// The DNS lookup timed out for some reason.  Force
+	case <-ctx.Done():
+		// The DNS lookup timed out for some reason. Force
 		// future requests to start the DNS lookup again
 		// rather than waiting for the current lookup to
-		// complete.  See issue 8602.
+		// complete. See issue 8602.
+		err := mapErr(ctx.Err())
 		lookupGroup.Forget(host)
-
-		return nil, errTimeout
-
+		if trace != nil && trace.DNSDone != nil {
+			trace.DNSDone(nil, false, err)
+		}
+		return nil, err
 	case r := <-ch:
+		if trace != nil && trace.DNSDone != nil {
+			addrs, _ := r.Val.([]IPAddr)
+			trace.DNSDone(ipAddrsEface(addrs), r.Shared, r.Err)
+		}
 		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 service == "" {
-		// Lock in the legacy behavior that an empty string
-		// means port 0. See Issue 13610.
-		return 0, nil
-	}
-	port, _, ok := dtoi(service, 0)
-	if !ok && port != big && port != -big {
-		port, err = lookupPort(network, service)
+	port, needsLookup := parsePort(service)
+	if needsLookup {
+		port, err = lookupPort(context.Background(), network, service)
 		if err != nil {
 			return 0, err
 		}
@@ -146,39 +160,39 @@ func LookupPort(network, service string) (port int, err error) {
 // LookupHost or LookupIP directly; both take care of resolving
 // the canonical name as part of the lookup.
 func LookupCNAME(name string) (cname string, err error) {
-	return lookupCNAME(name)
+	return lookupCNAME(context.Background(), name)
 }
 
 // LookupSRV tries to resolve an SRV query of the given service,
-// protocol, and domain name.  The proto is "tcp" or "udp".
+// protocol, and domain name. The proto is "tcp" or "udp".
 // The returned records are sorted by priority and randomized
 // by weight within a priority.
 //
 // LookupSRV constructs the DNS name to look up following RFC 2782.
-// That is, it looks up _service._proto.name.  To accommodate services
+// That is, it looks up _service._proto.name. To accommodate services
 // publishing SRV records under non-standard names, if both service
 // and proto are empty strings, LookupSRV looks up name directly.
 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
-	return lookupSRV(service, proto, name)
+	return lookupSRV(context.Background(), service, proto, name)
 }
 
 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
 func LookupMX(name string) (mxs []*MX, err error) {
-	return lookupMX(name)
+	return lookupMX(context.Background(), name)
 }
 
 // LookupNS returns the DNS NS records for the given domain name.
 func LookupNS(name string) (nss []*NS, err error) {
-	return lookupNS(name)
+	return lookupNS(context.Background(), name)
 }
 
 // LookupTXT returns the DNS TXT records for the given domain name.
 func LookupTXT(name string) (txts []string, err error) {
-	return lookupTXT(name)
+	return lookupTXT(context.Background(), name)
 }
 
 // LookupAddr performs a reverse lookup for the given address, returning a list
 // of names mapping to that address.
 func LookupAddr(addr string) (names []string, err error) {
-	return lookupAddr(addr)
+	return lookupAddr(context.Background(), addr)
 }
diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go
index a331628..3f7af2a 100644
--- a/src/net/lookup_plan9.go
+++ b/src/net/lookup_plan9.go
@@ -1,22 +1,24 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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 (
+	"context"
 	"errors"
+	"io"
 	"os"
 )
 
-func query(filename, query string, bufSize int) (res []string, err error) {
+func query(ctx context.Context, filename, query string, bufSize int) (res []string, err error) {
 	file, err := os.OpenFile(filename, os.O_RDWR, 0)
 	if err != nil {
 		return
 	}
 	defer file.Close()
 
-	_, err = file.Seek(0, 0)
+	_, err = file.Seek(0, io.SeekStart)
 	if err != nil {
 		return
 	}
@@ -24,7 +26,7 @@ func query(filename, query string, bufSize int) (res []string, err error) {
 	if err != nil {
 		return
 	}
-	_, err = file.Seek(0, 0)
+	_, err = file.Seek(0, io.SeekStart)
 	if err != nil {
 		return
 	}
@@ -39,7 +41,7 @@ func query(filename, query string, bufSize int) (res []string, err error) {
 	return
 }
 
-func queryCS(net, host, service string) (res []string, err error) {
+func queryCS(ctx context.Context, net, host, service string) (res []string, err error) {
 	switch net {
 	case "tcp4", "tcp6":
 		net = "tcp"
@@ -49,15 +51,15 @@ func queryCS(net, host, service string) (res []string, err error) {
 	if host == "" {
 		host = "*"
 	}
-	return query(netdir+"/cs", net+"!"+host+"!"+service, 128)
+	return query(ctx, netdir+"/cs", net+"!"+host+"!"+service, 128)
 }
 
-func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
+func queryCS1(ctx context.Context, net string, ip IP, port int) (clone, dest string, err error) {
 	ips := "*"
 	if len(ip) != 0 && !ip.IsUnspecified() {
 		ips = ip.String()
 	}
-	lines, err := queryCS(net, ips, itoa(port))
+	lines, err := queryCS(ctx, net, ips, itoa(port))
 	if err != nil {
 		return
 	}
@@ -69,8 +71,8 @@ func queryCS1(net string, ip IP, port int) (clone, dest string, err error) {
 	return
 }
 
-func queryDNS(addr string, typ string) (res []string, err error) {
-	return query(netdir+"/dns", addr+" "+typ, 1024)
+func queryDNS(ctx context.Context, addr string, typ string) (res []string, err error) {
+	return query(ctx, netdir+"/dns", addr+" "+typ, 1024)
 }
 
 // toLower returns a lower-case version of in. Restricting us to
@@ -96,8 +98,8 @@ func toLower(in string) string {
 
 // lookupProtocol looks up IP protocol name and returns
 // the corresponding protocol number.
-func lookupProtocol(name string) (proto int, err error) {
-	lines, err := query(netdir+"/cs", "!protocol="+toLower(name), 128)
+func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
+	lines, err := query(ctx, netdir+"/cs", "!protocol="+toLower(name), 128)
 	if err != nil {
 		return 0, err
 	}
@@ -115,10 +117,10 @@ func lookupProtocol(name string) (proto int, err error) {
 	return 0, UnknownNetworkError(name)
 }
 
-func lookupHost(host string) (addrs []string, err error) {
+func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
 	// Use netdir/cs instead of netdir/dns because cs knows about
 	// host names in local network (e.g. from /lib/ndb/local)
-	lines, err := queryCS("net", host, "1")
+	lines, err := queryCS(ctx, "net", host, "1")
 	if err != nil {
 		return
 	}
@@ -146,8 +148,8 @@ loop:
 	return
 }
 
-func lookupIP(host string) (addrs []IPAddr, err error) {
-	lits, err := LookupHost(host)
+func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+	lits, err := lookupHost(ctx, host)
 	if err != nil {
 		return
 	}
@@ -161,14 +163,14 @@ func lookupIP(host string) (addrs []IPAddr, err error) {
 	return
 }
 
-func lookupPort(network, service string) (port int, err error) {
+func lookupPort(ctx context.Context, network, service string) (port int, err error) {
 	switch network {
 	case "tcp4", "tcp6":
 		network = "tcp"
 	case "udp4", "udp6":
 		network = "udp"
 	}
-	lines, err := queryCS(network, "127.0.0.1", service)
+	lines, err := queryCS(ctx, network, "127.0.0.1", service)
 	if err != nil {
 		return
 	}
@@ -190,8 +192,8 @@ func lookupPort(network, service string) (port int, err error) {
 	return 0, unknownPortError
 }
 
-func lookupCNAME(name string) (cname string, err error) {
-	lines, err := queryDNS(name, "cname")
+func lookupCNAME(ctx context.Context, name string) (cname string, err error) {
+	lines, err := queryDNS(ctx, name, "cname")
 	if err != nil {
 		return
 	}
@@ -203,14 +205,14 @@ func lookupCNAME(name string) (cname string, err error) {
 	return "", errors.New("bad response from ndb/dns")
 }
 
-func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+func lookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
 	var target string
 	if service == "" && proto == "" {
 		target = name
 	} else {
 		target = "_" + service + "._" + proto + "." + name
 	}
-	lines, err := queryDNS(target, "srv")
+	lines, err := queryDNS(ctx, target, "srv")
 	if err != nil {
 		return
 	}
@@ -232,8 +234,8 @@ func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
 	return
 }
 
-func lookupMX(name string) (mx []*MX, err error) {
-	lines, err := queryDNS(name, "mx")
+func lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
+	lines, err := queryDNS(ctx, name, "mx")
 	if err != nil {
 		return
 	}
@@ -250,8 +252,8 @@ func lookupMX(name string) (mx []*MX, err error) {
 	return
 }
 
-func lookupNS(name string) (ns []*NS, err error) {
-	lines, err := queryDNS(name, "ns")
+func lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
+	lines, err := queryDNS(ctx, name, "ns")
 	if err != nil {
 		return
 	}
@@ -265,8 +267,8 @@ func lookupNS(name string) (ns []*NS, err error) {
 	return
 }
 
-func lookupTXT(name string) (txt []string, err error) {
-	lines, err := queryDNS(name, "txt")
+func lookupTXT(ctx context.Context, name string) (txt []string, err error) {
+	lines, err := queryDNS(ctx, name, "txt")
 	if err != nil {
 		return
 	}
@@ -278,12 +280,12 @@ func lookupTXT(name string) (txt []string, err error) {
 	return
 }
 
-func lookupAddr(addr string) (name []string, err error) {
+func lookupAddr(ctx context.Context, addr string) (name []string, err error) {
 	arpa, err := reverseaddr(addr)
 	if err != nil {
 		return
 	}
-	lines, err := queryDNS(arpa, "ptr")
+	lines, err := queryDNS(ctx, arpa, "ptr")
 	if err != nil {
 		return
 	}
diff --git a/src/net/lookup_stub.go b/src/net/lookup_stub.go
index 5636198..bd096b3 100644
--- a/src/net/lookup_stub.go
+++ b/src/net/lookup_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,44 +6,47 @@
 
 package net
 
-import "syscall"
+import (
+	"context"
+	"syscall"
+)
 
-func lookupProtocol(name string) (proto int, err error) {
+func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
 	return 0, syscall.ENOPROTOOPT
 }
 
-func lookupHost(host string) (addrs []string, err error) {
+func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
 	return nil, syscall.ENOPROTOOPT
 }
 
-func lookupIP(host string) (addrs []IPAddr, err error) {
+func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
 	return nil, syscall.ENOPROTOOPT
 }
 
-func lookupPort(network, service string) (port int, err error) {
+func lookupPort(ctx context.Context, network, service string) (port int, err error) {
 	return 0, syscall.ENOPROTOOPT
 }
 
-func lookupCNAME(name string) (cname string, err error) {
+func lookupCNAME(ctx context.Context, name string) (cname string, err error) {
 	return "", syscall.ENOPROTOOPT
 }
 
-func lookupSRV(service, proto, name string) (cname string, srvs []*SRV, err error) {
+func lookupSRV(ctx context.Context, service, proto, name string) (cname string, srvs []*SRV, err error) {
 	return "", nil, syscall.ENOPROTOOPT
 }
 
-func lookupMX(name string) (mxs []*MX, err error) {
+func lookupMX(ctx context.Context, name string) (mxs []*MX, err error) {
 	return nil, syscall.ENOPROTOOPT
 }
 
-func lookupNS(name string) (nss []*NS, err error) {
+func lookupNS(ctx context.Context, name string) (nss []*NS, err error) {
 	return nil, syscall.ENOPROTOOPT
 }
 
-func lookupTXT(name string) (txts []string, err error) {
+func lookupTXT(ctx context.Context, name string) (txts []string, err error) {
 	return nil, syscall.ENOPROTOOPT
 }
 
-func lookupAddr(addr string) (ptrs []string, err error) {
+func lookupAddr(ctx context.Context, addr string) (ptrs []string, err error) {
 	return nil, syscall.ENOPROTOOPT
 }
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 439496a..b3aeb85 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -6,6 +6,7 @@ package net
 
 import (
 	"bytes"
+	"context"
 	"fmt"
 	"internal/testenv"
 	"runtime"
@@ -14,7 +15,7 @@ import (
 	"time"
 )
 
-func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+func lookupLocalhost(ctx context.Context, fn func(context.Context, string) ([]IPAddr, error), host string) ([]IPAddr, error) {
 	switch host {
 	case "localhost":
 		return []IPAddr{
@@ -22,7 +23,7 @@ func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr,
 			{IP: IPv6loopback},
 		}, nil
 	default:
-		return fn(host)
+		return fn(ctx, host)
 	}
 }
 
@@ -58,9 +59,10 @@ var lookupGoogleSRVTests = []struct {
 }
 
 func TestLookupGoogleSRV(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" || !*testExternal {
-		t.Skip("avoid external network")
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
 	}
+
 	if !supportsIPv4 || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
@@ -68,6 +70,7 @@ func TestLookupGoogleSRV(t *testing.T) {
 	for _, tt := range lookupGoogleSRVTests {
 		cname, srvs, err := LookupSRV(tt.service, tt.proto, tt.name)
 		if err != nil {
+			testenv.SkipFlakyNet(t)
 			t.Fatal(err)
 		}
 		if len(srvs) == 0 {
@@ -92,9 +95,10 @@ var lookupGmailMXTests = []struct {
 }
 
 func TestLookupGmailMX(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" || !*testExternal {
-		t.Skip("avoid external network")
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
 	}
+
 	if !supportsIPv4 || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
@@ -123,9 +127,10 @@ var lookupGmailNSTests = []struct {
 }
 
 func TestLookupGmailNS(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" || !*testExternal {
-		t.Skip("avoid external network")
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
 	}
+
 	if !supportsIPv4 || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
@@ -133,6 +138,7 @@ func TestLookupGmailNS(t *testing.T) {
 	for _, tt := range lookupGmailNSTests {
 		nss, err := LookupNS(tt.name)
 		if err != nil {
+			testenv.SkipFlakyNet(t)
 			t.Fatal(err)
 		}
 		if len(nss) == 0 {
@@ -154,9 +160,10 @@ var lookupGmailTXTTests = []struct {
 }
 
 func TestLookupGmailTXT(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" || !*testExternal {
-		t.Skip("avoid external network")
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
 	}
+
 	if !supportsIPv4 || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
@@ -188,9 +195,10 @@ var lookupGooglePublicDNSAddrTests = []struct {
 }
 
 func TestLookupGooglePublicDNSAddr(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" || !*testExternal {
-		t.Skip("avoid external network")
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
 	}
+
 	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
@@ -243,9 +251,10 @@ var lookupIANACNAMETests = []struct {
 }
 
 func TestLookupIANACNAME(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" || !*testExternal {
-		t.Skip("avoid external network")
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
 	}
+
 	if !supportsIPv4 || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
@@ -269,9 +278,10 @@ var lookupGoogleHostTests = []struct {
 }
 
 func TestLookupGoogleHost(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" || !*testExternal {
-		t.Skip("avoid external network")
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
 	}
+
 	if !supportsIPv4 || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
@@ -300,9 +310,10 @@ var lookupGoogleIPTests = []struct {
 }
 
 func TestLookupGoogleIP(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" || !*testExternal {
-		t.Skip("avoid external network")
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
 	}
+
 	if !supportsIPv4 || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
@@ -360,22 +371,38 @@ func TestReverseAddress(t *testing.T) {
 	}
 }
 
-func TestLookupIPDeadline(t *testing.T) {
+func TestDNSFlood(t *testing.T) {
 	if !*testDNSFlood {
 		t.Skip("test disabled; use -dnsflood to enable")
 	}
 
-	const N = 5000
+	var N = 5000
+	if runtime.GOOS == "darwin" {
+		// On Darwin this test consumes kernel threads much
+		// than other platforms for some reason.
+		// When we monitor the number of allocated Ms by
+		// observing on runtime.newm calls, we can see that it
+		// easily reaches the per process ceiling
+		// kern.num_threads when CGO_ENABLED=1 and
+		// GODEBUG=netdns=go.
+		N = 500
+	}
+
 	const timeout = 3 * time.Second
+	ctxHalfTimeout, cancel := context.WithTimeout(context.Background(), timeout/2)
+	defer cancel()
+	ctxTimeout, cancel := context.WithTimeout(context.Background(), timeout)
+	defer cancel()
+
 	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))
+			_, err := lookupIPContext(ctxHalfTimeout, name)
 			c <- err
 		}()
 		go func() {
-			_, err := lookupIPDeadline(name, time.Now().Add(timeout))
+			_, err := lookupIPContext(ctxTimeout, name)
 			c <- err
 		}()
 	}
@@ -426,6 +453,10 @@ func TestLookupDotsWithLocalSource(t *testing.T) {
 		t.Skip("IPv4 is required")
 	}
 
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
+	}
+
 	for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} {
 		fixup := fn()
 		if fixup == nil {
@@ -463,9 +494,10 @@ func TestLookupDotsWithLocalSource(t *testing.T) {
 }
 
 func TestLookupDotsWithRemoteSource(t *testing.T) {
-	if testing.Short() && testenv.Builder() == "" || !*testExternal {
-		t.Skip("avoid external network")
+	if testenv.Builder() == "" {
+		testenv.MustHaveExternalNetwork(t)
 	}
+
 	if !supportsIPv4 || !*testIPv4 {
 		t.Skip("IPv4 is required")
 	}
@@ -483,6 +515,7 @@ func TestLookupDotsWithRemoteSource(t *testing.T) {
 func testDots(t *testing.T, mode string) {
 	names, err := LookupAddr("8.8.8.8") // Google dns server
 	if err != nil {
+		testenv.SkipFlakyNet(t)
 		t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
 	} else {
 		for _, name := range names {
@@ -494,12 +527,16 @@ func testDots(t *testing.T, mode string) {
 	}
 
 	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)
+	if err != nil {
+		testenv.SkipFlakyNet(t)
+		t.Errorf("LookupCNAME(www.mit.edu, mode=%v): %v", mode, err)
+	} else if !strings.HasSuffix(cname, ".") {
+		t.Errorf("LookupCNAME(www.mit.edu) = %v, want cname ending in . with trailing dot (mode=%v)", cname, mode)
 	}
 
 	mxs, err := LookupMX("google.com")
 	if err != nil {
+		testenv.SkipFlakyNet(t)
 		t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode)
 	} else {
 		for _, mx := range mxs {
@@ -512,6 +549,7 @@ func testDots(t *testing.T, mode string) {
 
 	nss, err := LookupNS("google.com")
 	if err != nil {
+		testenv.SkipFlakyNet(t)
 		t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode)
 	} else {
 		for _, ns := range nss {
@@ -524,6 +562,7 @@ func testDots(t *testing.T, mode string) {
 
 	cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com")
 	if err != nil {
+		testenv.SkipFlakyNet(t)
 		t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode)
 	} else {
 		if !strings.HasSuffix(cname, ".google.com.") {
@@ -574,61 +613,60 @@ func srvString(srvs []*SRV) string {
 	return buf.String()
 }
 
-var lookupPortTests = []struct {
-	network string
-	name    string
-	port    int
-	ok      bool
-}{
-	{"tcp", "0", 0, true},
-	{"tcp", "echo", 7, true},
-	{"tcp", "discard", 9, true},
-	{"tcp", "systat", 11, true},
-	{"tcp", "daytime", 13, true},
-	{"tcp", "chargen", 19, true},
-	{"tcp", "ftp-data", 20, true},
-	{"tcp", "ftp", 21, true},
-	{"tcp", "telnet", 23, true},
-	{"tcp", "smtp", 25, true},
-	{"tcp", "time", 37, true},
-	{"tcp", "domain", 53, true},
-	{"tcp", "finger", 79, true},
-	{"tcp", "42", 42, true},
-
-	{"udp", "0", 0, true},
-	{"udp", "echo", 7, true},
-	{"udp", "tftp", 69, true},
-	{"udp", "bootpc", 68, true},
-	{"udp", "bootps", 67, true},
-	{"udp", "domain", 53, true},
-	{"udp", "ntp", 123, true},
-	{"udp", "snmp", 161, true},
-	{"udp", "syslog", 514, true},
-	{"udp", "42", 42, true},
-
-	{"--badnet--", "zzz", 0, false},
-	{"tcp", "--badport--", 0, false},
-	{"tcp", "-1", 0, false},
-	{"tcp", "65536", 0, false},
-	{"udp", "-1", 0, false},
-	{"udp", "65536", 0, false},
-
-	// Issue 13610: LookupPort("tcp", "")
-	{"tcp", "", 0, true},
-	{"tcp6", "", 0, true},
-	{"tcp4", "", 0, true},
-	{"udp", "", 0, true},
-}
-
 func TestLookupPort(t *testing.T) {
+	// See http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
+	//
+	// Please be careful about adding new mappings for testings.
+	// There are platforms having incomplete mappings for
+	// restricted resource access and security reasons.
+	type test struct {
+		network string
+		name    string
+		port    int
+		ok      bool
+	}
+	var tests = []test{
+		{"tcp", "0", 0, true},
+		{"udp", "0", 0, true},
+		{"udp", "domain", 53, true},
+
+		{"--badnet--", "zzz", 0, false},
+		{"tcp", "--badport--", 0, false},
+		{"tcp", "-1", 0, false},
+		{"tcp", "65536", 0, false},
+		{"udp", "-1", 0, false},
+		{"udp", "65536", 0, false},
+		{"tcp", "123456789", 0, false},
+
+		// Issue 13610: LookupPort("tcp", "")
+		{"tcp", "", 0, true},
+		{"tcp4", "", 0, true},
+		{"tcp6", "", 0, true},
+		{"udp", "", 0, true},
+		{"udp4", "", 0, true},
+		{"udp6", "", 0, true},
+	}
+
 	switch runtime.GOOS {
 	case "nacl":
 		t.Skipf("not supported on %s", runtime.GOOS)
+	case "android":
+		if netGo {
+			t.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime.GOOS)
+		}
+	default:
+		tests = append(tests, test{"tcp", "http", 80, true})
 	}
 
-	for _, tt := range lookupPortTests {
-		if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
-			t.Errorf("LookupPort(%q, %q) = %d, %v; want %d", tt.network, tt.name, port, err, tt.port)
+	for _, tt := range tests {
+		port, err := LookupPort(tt.network, tt.name)
+		if port != tt.port || (err == nil) != tt.ok {
+			t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=%t", tt.network, tt.name, port, err, tt.port, !tt.ok)
+		}
+		if err != nil {
+			if perr := parseLookupPortError(err); perr != nil {
+				t.Error(perr)
+			}
 		}
 	}
 }
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index a64da8b..15397e8 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,7 +6,10 @@
 
 package net
 
-import "sync"
+import (
+	"context"
+	"sync"
+)
 
 var onceReadProtocols sync.Once
 
@@ -40,7 +43,7 @@ func readProtocols() {
 
 // lookupProtocol looks up IP protocol name in /etc/protocols and
 // returns correspondent protocol number.
-func lookupProtocol(name string) (int, error) {
+func lookupProtocol(_ context.Context, name string) (int, error) {
 	onceReadProtocols.Do(readProtocols)
 	proto, found := protocols[name]
 	if !found {
@@ -49,56 +52,61 @@ func lookupProtocol(name string) (int, error) {
 	return proto, nil
 }
 
-func lookupHost(host string) (addrs []string, err error) {
+func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
 	order := systemConf().hostLookupOrder(host)
 	if order == hostLookupCgo {
-		if addrs, err, ok := cgoLookupHost(host); ok {
+		if addrs, err, ok := cgoLookupHost(ctx, host); ok {
 			return addrs, err
 		}
 		// cgo not available (or netgo); fall back to Go's DNS resolver
 		order = hostLookupFilesDNS
 	}
-	return goLookupHostOrder(host, order)
+	return goLookupHostOrder(ctx, host, order)
 }
 
-func lookupIP(host string) (addrs []IPAddr, err error) {
+func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
 	order := systemConf().hostLookupOrder(host)
 	if order == hostLookupCgo {
-		if addrs, err, ok := cgoLookupIP(host); ok {
+		if addrs, err, ok := cgoLookupIP(ctx, host); ok {
 			return addrs, err
 		}
 		// cgo not available (or netgo); fall back to Go's DNS resolver
 		order = hostLookupFilesDNS
 	}
-	return goLookupIPOrder(host, order)
+	return goLookupIPOrder(ctx, host, order)
 }
 
-func lookupPort(network, service string) (int, error) {
+func lookupPort(ctx context.Context, network, service string) (int, error) {
+	// TODO: use the context if there ever becomes a need. Related
+	// is issue 15321. But port lookup generally just involves
+	// local files, and the os package has no context support. The
+	// files might be on a remote filesystem, though. This should
+	// probably race goroutines if ctx != context.Background().
 	if systemConf().canUseCgo() {
-		if port, err, ok := cgoLookupPort(network, service); ok {
+		if port, err, ok := cgoLookupPort(ctx, network, service); ok {
 			return port, err
 		}
 	}
 	return goLookupPort(network, service)
 }
 
-func lookupCNAME(name string) (string, error) {
+func lookupCNAME(ctx context.Context, name string) (string, error) {
 	if systemConf().canUseCgo() {
-		if cname, err, ok := cgoLookupCNAME(name); ok {
+		if cname, err, ok := cgoLookupCNAME(ctx, name); ok {
 			return cname, err
 		}
 	}
-	return goLookupCNAME(name)
+	return goLookupCNAME(ctx, name)
 }
 
-func lookupSRV(service, proto, name string) (string, []*SRV, error) {
+func lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
 	var target string
 	if service == "" && proto == "" {
 		target = name
 	} else {
 		target = "_" + service + "._" + proto + "." + name
 	}
-	cname, rrs, err := lookup(target, dnsTypeSRV)
+	cname, rrs, err := lookup(ctx, target, dnsTypeSRV)
 	if err != nil {
 		return "", nil, err
 	}
@@ -111,8 +119,8 @@ func lookupSRV(service, proto, name string) (string, []*SRV, error) {
 	return cname, srvs, nil
 }
 
-func lookupMX(name string) ([]*MX, error) {
-	_, rrs, err := lookup(name, dnsTypeMX)
+func lookupMX(ctx context.Context, name string) ([]*MX, error) {
+	_, rrs, err := lookup(ctx, name, dnsTypeMX)
 	if err != nil {
 		return nil, err
 	}
@@ -125,8 +133,8 @@ func lookupMX(name string) ([]*MX, error) {
 	return mxs, nil
 }
 
-func lookupNS(name string) ([]*NS, error) {
-	_, rrs, err := lookup(name, dnsTypeNS)
+func lookupNS(ctx context.Context, name string) ([]*NS, error) {
+	_, rrs, err := lookup(ctx, name, dnsTypeNS)
 	if err != nil {
 		return nil, err
 	}
@@ -137,8 +145,8 @@ func lookupNS(name string) ([]*NS, error) {
 	return nss, nil
 }
 
-func lookupTXT(name string) ([]string, error) {
-	_, rrs, err := lookup(name, dnsTypeTXT)
+func lookupTXT(ctx context.Context, name string) ([]string, error) {
+	_, rrs, err := lookup(ctx, name, dnsTypeTXT)
 	if err != nil {
 		return nil, err
 	}
@@ -149,11 +157,11 @@ func lookupTXT(name string) ([]string, error) {
 	return txts, nil
 }
 
-func lookupAddr(addr string) ([]string, error) {
+func lookupAddr(ctx context.Context, addr string) ([]string, error) {
 	if systemConf().canUseCgo() {
-		if ptrs, err, ok := cgoLookupPTR(addr); ok {
+		if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok {
 			return ptrs, err
 		}
 	}
-	return goLookupPTR(addr)
+	return goLookupPTR(ctx, addr)
 }
diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go
index 13edc26..5f65c2d 100644
--- a/src/net/lookup_windows.go
+++ b/src/net/lookup_windows.go
@@ -5,17 +5,13 @@
 package net
 
 import (
+	"context"
 	"os"
 	"runtime"
 	"syscall"
 	"unsafe"
 )
 
-var (
-	lookupPort = oldLookupPort
-	lookupIP   = oldLookupIP
-)
-
 func getprotobyname(name string) (proto int, err error) {
 	p, err := syscall.GetProtoByName(name)
 	if err != nil {
@@ -25,34 +21,41 @@ func getprotobyname(name string) (proto int, err error) {
 }
 
 // lookupProtocol looks up IP protocol name and returns correspondent protocol number.
-func lookupProtocol(name string) (int, error) {
+func lookupProtocol(ctx context.Context, 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 {
 		proto int
 		err   error
 	}
-	ch := make(chan result)
+	ch := make(chan result) // unbuffered
 	go func() {
 		acquireThread()
 		defer releaseThread()
 		runtime.LockOSThread()
 		defer runtime.UnlockOSThread()
 		proto, err := getprotobyname(name)
-		ch <- result{proto: proto, err: err}
+		select {
+		case ch <- result{proto: proto, err: err}:
+		case <-ctx.Done():
+		}
 	}()
-	r := <-ch
-	if r.err != nil {
-		if proto, ok := protocols[name]; ok {
-			return proto, nil
+	select {
+	case r := <-ch:
+		if r.err != nil {
+			if proto, ok := protocols[name]; ok {
+				return proto, nil
+			}
+			r.err = &DNSError{Err: r.err.Error(), Name: name}
 		}
-		r.err = &DNSError{Err: r.err.Error(), Name: name}
+		return r.proto, r.err
+	case <-ctx.Done():
+		return 0, mapErr(ctx.Err())
 	}
-	return r.proto, r.err
 }
 
-func lookupHost(name string) ([]string, error) {
-	ips, err := LookupIP(name)
+func lookupHost(ctx context.Context, name string) ([]string, error) {
+	ips, err := lookupIP(ctx, name)
 	if err != nil {
 		return nil, err
 	}
@@ -63,121 +66,67 @@ func lookupHost(name string) ([]string, error) {
 	return addrs, nil
 }
 
-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)
-	}
-	switch h.AddrType {
-	case syscall.AF_INET:
-		i := 0
-		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] = 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, syscall.EWINDOWS
-	}
-	return addrs, nil
-}
+func lookupIP(ctx context.Context, name string) ([]IPAddr, error) {
+	// TODO(bradfitz,brainman): use ctx?
 
-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 {
+	type ret struct {
 		addrs []IPAddr
 		err   error
 	}
-	ch := make(chan result)
+	ch := make(chan ret, 1)
 	go func() {
 		acquireThread()
 		defer releaseThread()
-		runtime.LockOSThread()
-		defer runtime.UnlockOSThread()
-		addrs, err := gethostbyname(name)
-		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) ([]IPAddr, error) {
-	acquireThread()
-	defer releaseThread()
-	hints := syscall.AddrinfoW{
-		Family:   syscall.AF_UNSPEC,
-		Socktype: syscall.SOCK_STREAM,
-		Protocol: syscall.IPPROTO_IP,
-	}
-	var result *syscall.AddrinfoW
-	e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
-	if e != nil {
-		return nil, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: name}
-	}
-	defer syscall.FreeAddrInfoW(result)
-	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, IPAddr{IP: IPv4(a[0], a[1], a[2], a[3])})
-		case syscall.AF_INET6:
-			a := (*syscall.RawSockaddrInet6)(addr).Addr
-			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, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name}
+		hints := syscall.AddrinfoW{
+			Family:   syscall.AF_UNSPEC,
+			Socktype: syscall.SOCK_STREAM,
+			Protocol: syscall.IPPROTO_IP,
 		}
-	}
-	return addrs, nil
-}
-
-func getservbyname(network, service string) (int, error) {
-	acquireThread()
-	defer releaseThread()
-	switch network {
-	case "tcp4", "tcp6":
-		network = "tcp"
-	case "udp4", "udp6":
-		network = "udp"
-	}
-	s, err := syscall.GetServByName(service, network)
-	if err != nil {
-		return 0, os.NewSyscallError("getservbyname", err)
-	}
-	return int(syscall.Ntohs(s.Port)), nil
-}
-
-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 {
-		port int
-		err  error
-	}
-	ch := make(chan result)
-	go func() {
-		acquireThread()
-		defer releaseThread()
-		runtime.LockOSThread()
-		defer runtime.UnlockOSThread()
-		port, err := getservbyname(network, service)
-		ch <- result{port: port, err: err}
+		var result *syscall.AddrinfoW
+		e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
+		if e != nil {
+			ch <- ret{err: &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: name}}
+		}
+		defer syscall.FreeAddrInfoW(result)
+		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, IPAddr{IP: IPv4(a[0], a[1], a[2], a[3])})
+			case syscall.AF_INET6:
+				a := (*syscall.RawSockaddrInet6)(addr).Addr
+				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:
+				ch <- ret{err: &DNSError{Err: syscall.EWINDOWS.Error(), Name: name}}
+			}
+		}
+		ch <- ret{addrs: addrs}
 	}()
-	r := <-ch
-	if r.err != nil {
-		r.err = &DNSError{Err: r.err.Error(), Name: network + "/" + service}
+	select {
+	case r := <-ch:
+		return r.addrs, r.err
+	case <-ctx.Done():
+		// TODO(bradfitz,brainman): cancel the ongoing
+		// GetAddrInfoW? It would require conditionally using
+		// GetAddrInfoEx with lpOverlapped, which requires
+		// Windows 8 or newer. I guess we'll need oldLookupIP,
+		// newLookupIP, and newerLookUP.
+		//
+		// For now we just let it finish and write to the
+		// buffered channel.
+		return nil, &DNSError{
+			Name:      name,
+			Err:       ctx.Err().Error(),
+			IsTimeout: ctx.Err() == context.DeadlineExceeded,
+		}
 	}
-	return r.port, r.err
 }
 
-func newLookupPort(network, service string) (int, error) {
+func lookupPort(ctx context.Context, network, service string) (int, error) {
+	// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
 	acquireThread()
 	defer releaseThread()
 	var stype int32
@@ -213,7 +162,8 @@ func newLookupPort(network, service string) (int, error) {
 	return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
 }
 
-func lookupCNAME(name string) (string, error) {
+func lookupCNAME(ctx context.Context, name string) (string, error) {
+	// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
@@ -233,7 +183,8 @@ func lookupCNAME(name string) (string, error) {
 	return absDomainName([]byte(cname)), nil
 }
 
-func lookupSRV(service, proto, name string) (string, []*SRV, error) {
+func lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
+	// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
 	acquireThread()
 	defer releaseThread()
 	var target string
@@ -258,7 +209,8 @@ func lookupSRV(service, proto, name string) (string, []*SRV, error) {
 	return absDomainName([]byte(target)), srvs, nil
 }
 
-func lookupMX(name string) ([]*MX, error) {
+func lookupMX(ctx context.Context, name string) ([]*MX, error) {
+	// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
@@ -277,7 +229,8 @@ func lookupMX(name string) ([]*MX, error) {
 	return mxs, nil
 }
 
-func lookupNS(name string) ([]*NS, error) {
+func lookupNS(ctx context.Context, name string) ([]*NS, error) {
+	// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
@@ -295,7 +248,8 @@ func lookupNS(name string) ([]*NS, error) {
 	return nss, nil
 }
 
-func lookupTXT(name string) ([]string, error) {
+func lookupTXT(ctx context.Context, name string) ([]string, error) {
+	// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
@@ -316,7 +270,8 @@ func lookupTXT(name string) ([]string, error) {
 	return txts, nil
 }
 
-func lookupAddr(addr string) ([]string, error) {
+func lookupAddr(ctx context.Context, addr string) ([]string, error) {
+	// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
 	acquireThread()
 	defer releaseThread()
 	arpa, err := reverseaddr(addr)
diff --git a/src/net/lookup_windows_test.go b/src/net/lookup_windows_test.go
index 7ff32b8..9af2c61 100644
--- a/src/net/lookup_windows_test.go
+++ b/src/net/lookup_windows_test.go
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"encoding/json"
 	"errors"
+	"internal/testenv"
 	"os/exec"
 	"reflect"
 	"regexp"
@@ -24,9 +25,7 @@ func toJson(v interface{}) string {
 }
 
 func TestLookupMX(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
 
 	for _, server := range nslookupTestServers {
 		mx, err := LookupMX(server)
@@ -51,9 +50,7 @@ func TestLookupMX(t *testing.T) {
 }
 
 func TestLookupCNAME(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
 
 	for _, server := range nslookupTestServers {
 		cname, err := LookupCNAME(server)
@@ -76,9 +73,7 @@ func TestLookupCNAME(t *testing.T) {
 }
 
 func TestLookupNS(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
 
 	for _, server := range nslookupTestServers {
 		ns, err := LookupNS(server)
@@ -104,9 +99,7 @@ func TestLookupNS(t *testing.T) {
 }
 
 func TestLookupTXT(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
+	testenv.MustHaveExternalNetwork(t)
 
 	for _, server := range nslookupTestServers {
 		txt, err := LookupTXT(server)
diff --git a/src/net/mac.go b/src/net/mac.go
index 93f0b09..f3b1694 100644
--- a/src/net/mac.go
+++ b/src/net/mac.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/mac_test.go b/src/net/mac_test.go
index 1ec6b28..2630d19 100644
--- a/src/net/mac_test.go
+++ b/src/net/mac_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/mail/message.go b/src/net/mail/message.go
index 923630c..0c00069 100644
--- a/src/net/mail/message.go
+++ b/src/net/mail/message.go
@@ -5,13 +5,15 @@
 /*
 Package mail implements parsing of mail messages.
 
-For the most part, this package follows the syntax as specified by RFC 5322.
+For the most part, this package follows the syntax as specified by RFC 5322 and
+extended by RFC 6532.
 Notable divergences:
 	* Obsolete address formats are not parsed, including addresses with
 	  embedded route information.
 	* Group addresses are not parsed.
 	* The full range of spacing (the CFWS syntax element) is not supported,
 	  such as breaking addresses across lines.
+	* No unicode normalization is performed.
 */
 package mail
 
@@ -26,6 +28,7 @@ import (
 	"net/textproto"
 	"strings"
 	"time"
+	"unicode/utf8"
 )
 
 var debug = debugT(false)
@@ -138,7 +141,7 @@ type Address struct {
 
 // Parses a single RFC 5322 address, e.g. "Barry Gibbs <bg at example.com>"
 func ParseAddress(address string) (*Address, error) {
-	return (&addrParser{s: address}).parseAddress()
+	return (&addrParser{s: address}).parseSingleAddress()
 }
 
 // ParseAddressList parses the given string as a list of addresses.
@@ -155,7 +158,7 @@ type AddressParser struct {
 // 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()
+	return (&addrParser{s: address, dec: p.WordDecoder}).parseSingleAddress()
 }
 
 // ParseList parses the given string as a list of comma-separated addresses
@@ -168,7 +171,6 @@ func (p *AddressParser) ParseList(list string) ([]*Address, error) {
 // If the address's name contains non-ASCII characters
 // the name will be rendered according to RFC 2047.
 func (a *Address) String() string {
-
 	// Format address local at domain
 	at := strings.LastIndex(a.Address, "@")
 	var local, domain string
@@ -181,15 +183,12 @@ func (a *Address) String() string {
 	}
 
 	// 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) {
+	for i, r := range local {
+		if isAtext(r, false) {
 			continue
 		}
-		if ch == '.' {
+		if r == '.' {
 			// 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.
@@ -213,25 +212,16 @@ func (a *Address) String() string {
 
 	// If every character is printable ASCII, quoting is simple.
 	allPrintable := true
-	for i := 0; i < len(a.Name); i++ {
+	for _, r := range a.Name {
 		// isWSP here should actually be isFWS,
 		// but we don't support folding yet.
-		if !isVchar(a.Name[i]) && !isWSP(a.Name[i]) {
+		if !isVchar(r) && !isWSP(r) || isMultibyte(r) {
 			allPrintable = false
 			break
 		}
 	}
 	if allPrintable {
-		b := bytes.NewBufferString(`"`)
-		for i := 0; i < len(a.Name); i++ {
-			if !isQtext(a.Name[i]) && !isWSP(a.Name[i]) {
-				b.WriteByte('\\')
-			}
-			b.WriteByte(a.Name[i])
-		}
-		b.WriteString(`" `)
-		b.WriteString(s)
-		return b.String()
+		return quoteString(a.Name) + " " + s
 	}
 
 	// Text in an encoded-word in a display-name must not contain certain
@@ -269,6 +259,18 @@ func (p *addrParser) parseAddressList() ([]*Address, error) {
 	return list, nil
 }
 
+func (p *addrParser) parseSingleAddress() (*Address, error) {
+	addr, err := p.parseAddress()
+	if err != nil {
+		return nil, err
+	}
+	p.skipSpace()
+	if !p.empty() {
+		return nil, fmt.Errorf("mail: expected single address, got %q", p.s)
+	}
+	return addr, nil
+}
+
 // 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.s)
@@ -416,29 +418,48 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
 func (p *addrParser) consumeQuotedString() (qs string, err error) {
 	// Assume first byte is '"'.
 	i := 1
-	qsb := make([]byte, 0, 10)
+	qsb := make([]rune, 0, 10)
+
+	escaped := false
+
 Loop:
 	for {
-		if i >= p.len() {
+		r, size := utf8.DecodeRuneInString(p.s[i:])
+
+		switch {
+		case size == 0:
 			return "", errors.New("mail: unclosed quoted-string")
-		}
-		switch c := p.s[i]; {
-		case c == '"':
-			break Loop
-		case c == '\\':
-			if i+1 == p.len() {
-				return "", errors.New("mail: unclosed quoted-string")
+
+		case size == 1 && r == utf8.RuneError:
+			return "", fmt.Errorf("mail: invalid utf-8 in quoted-string: %q", p.s)
+
+		case escaped:
+			//  quoted-pair = ("\" (VCHAR / WSP))
+
+			if !isVchar(r) && !isWSP(r) {
+				return "", fmt.Errorf("mail: bad character in quoted-string: %q", r)
 			}
-			qsb = append(qsb, p.s[i+1])
-			i += 2
-		case isQtext(c), c == ' ':
+
+			qsb = append(qsb, r)
+			escaped = false
+
+		case isQtext(r) || isWSP(r):
 			// qtext (printable US-ASCII excluding " and \), or
 			// FWS (almost; we're ignoring CRLF)
-			qsb = append(qsb, c)
-			i++
+			qsb = append(qsb, r)
+
+		case r == '"':
+			break Loop
+
+		case r == '\\':
+			escaped = true
+
 		default:
-			return "", fmt.Errorf("mail: bad character in quoted-string: %q", c)
+			return "", fmt.Errorf("mail: bad character in quoted-string: %q", r)
+
 		}
+
+		i += size
 	}
 	p.s = p.s[i+1:]
 	if len(qsb) == 0 {
@@ -447,26 +468,34 @@ Loop:
 	return string(qsb), nil
 }
 
-var errNonASCII = errors.New("mail: unencoded non-ASCII text in address")
-
 // consumeAtom parses an RFC 5322 atom at the start of p.
 // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
 // 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 c := p.peek(); !isAtext(c, false) {
-		if c > 127 {
-			return "", errNonASCII
+	i := 0
+
+Loop:
+	for {
+		r, size := utf8.DecodeRuneInString(p.s[i:])
+
+		switch {
+		case size == 1 && r == utf8.RuneError:
+			return "", fmt.Errorf("mail: invalid utf-8 in address: %q", p.s)
+
+		case size == 0 || !isAtext(r, dot):
+			break Loop
+
+		default:
+			i += size
+
 		}
-		return "", errors.New("mail: invalid string")
-	}
-	i := 1
-	for ; i < p.len() && isAtext(p.s[i], dot); i++ {
 	}
-	if i < p.len() && p.s[i] > 127 {
-		return "", errNonASCII
+
+	if i == 0 {
+		return "", errors.New("mail: invalid string")
 	}
-	atom, p.s = string(p.s[:i]), p.s[i:]
+	atom, p.s = p.s[:i], p.s[i:]
 	if !permissive {
 		if strings.HasPrefix(atom, ".") {
 			return "", errors.New("mail: leading dot in atom")
@@ -536,54 +565,58 @@ func (e charsetError) Error() string {
 	return fmt.Sprintf("charset not supported: %q", string(e))
 }
 
-var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
-	"abcdefghijklmnopqrstuvwxyz" +
-	"0123456789" +
-	"!#$%&'*+-/=?^_`{|}~")
-
-// isAtext reports whether c is an RFC 5322 atext character.
+// isAtext reports whether r is an RFC 5322 atext character.
 // If dot is true, period is included.
-func isAtext(c byte, dot bool) bool {
-	if dot && c == '.' {
-		return true
+func isAtext(r rune, dot bool) bool {
+	switch r {
+	case '.':
+		return dot
+
+	case '(', ')', '<', '>', '[', ']', ':', ';', '@', '\\', ',', '"': // RFC 5322 3.2.3. specials
+		return false
 	}
-	return bytes.IndexByte(atextChars, c) >= 0
+	return isVchar(r)
 }
 
-// isQtext reports whether c is an RFC 5322 qtext character.
-func isQtext(c byte) bool {
+// isQtext reports whether r is an RFC 5322 qtext character.
+func isQtext(r rune) bool {
 	// Printable US-ASCII, excluding backslash or quote.
-	if c == '\\' || c == '"' {
+	if r == '\\' || r == '"' {
 		return false
 	}
-	return '!' <= c && c <= '~'
+	return isVchar(r)
 }
 
-// quoteString renders a string as a RFC5322 quoted-string.
+// quoteString renders a string as an RFC 5322 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) {
+	for _, r := range s {
+		if isQtext(r) || isWSP(r) {
+			buf.WriteRune(r)
+		} else if isVchar(r) {
 			buf.WriteByte('\\')
-			buf.WriteByte(ch)
+			buf.WriteRune(r)
 		}
 	}
 	buf.WriteByte('"')
 	return buf.String()
 }
 
-// isVchar reports whether c is an RFC 5322 VCHAR character.
-func isVchar(c byte) bool {
+// isVchar reports whether r is an RFC 5322 VCHAR character.
+func isVchar(r rune) bool {
 	// Visible (printing) characters.
-	return '!' <= c && c <= '~'
+	return '!' <= r && r <= '~' || isMultibyte(r)
+}
+
+// isMultibyte reports whether r is a multi-byte UTF-8 character
+// as supported by RFC 6532
+func isMultibyte(r rune) bool {
+	return r >= utf8.RuneSelf
 }
 
-// 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'
+// isWSP reports whether r is a WSP (white space).
+// WSP is a space or horizontal tab (RFC 5234 Appendix B).
+func isWSP(r rune) bool {
+	return r == ' ' || r == '\t'
 }
diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go
index 4e718e2..bbbba6b 100644
--- a/src/net/mail/message_test.go
+++ b/src/net/mail/message_test.go
@@ -92,7 +92,7 @@ func TestDateParsing(t *testing.T) {
 			"Fri, 21 Nov 1997 09:55:06 -0600",
 			time.Date(1997, 11, 21, 9, 55, 6, 0, time.FixedZone("", -6*60*60)),
 		},
-		// RFC5322, Appendix A.6.2
+		// RFC 5322, Appendix A.6.2
 		// Obsolete date.
 		{
 			"21 Nov 97 09:55:06 GMT",
@@ -120,18 +120,24 @@ func TestDateParsing(t *testing.T) {
 }
 
 func TestAddressParsingError(t *testing.T) {
-	const txt = "=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown at gmail.com>"
-	_, err := ParseAddress(txt)
-	if err == nil || !strings.Contains(err.Error(), "charset not supported") {
-		t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*charset not supported.*"`, txt, err)
+	mustErrTestCases := [...]struct {
+		text        string
+		wantErrText string
+	}{
+		0: {"=?iso-8859-2?Q?Bogl=E1rka_Tak=E1cs?= <unknown at gmail.com>", "charset not supported"},
+		1: {"a at gmail.com b at gmail.com", "expected single address"},
+		2: {string([]byte{0xed, 0xa0, 0x80}) + " <micro at example.net>", "invalid utf-8 in address"},
+		3: {"\"" + string([]byte{0xed, 0xa0, 0x80}) + "\" <half-surrogate at example.com>", "invalid utf-8 in quoted-string"},
+		4: {"\"\\" + string([]byte{0x80}) + "\" <escaped-invalid-unicode at example.net>", "invalid utf-8 in quoted-string"},
+		5: {"\"\x00\" <null at example.net>", "bad character in quoted-string"},
+		6: {"\"\\\x00\" <escaped-null at example.net>", "bad character in quoted-string"},
 	}
-}
 
-func TestAddressParsingErrorUnquotedNonASCII(t *testing.T) {
-	const txt = "µ <micro at example.net>"
-	_, err := ParseAddress(txt)
-	if err == nil || !strings.Contains(err.Error(), "unencoded non-ASCII text in address") {
-		t.Errorf(`mail.ParseAddress(%q) err: %q, want ".*unencoded non-ASCII text in address.*"`, txt, err)
+	for i, tc := range mustErrTestCases {
+		_, err := ParseAddress(tc.text)
+		if err == nil || !strings.Contains(err.Error(), tc.wantErrText) {
+			t.Errorf(`mail.ParseAddress(%q) #%d want %q, got %v`, tc.text, i, tc.wantErrText, err)
+		}
 	}
 }
 
@@ -264,6 +270,46 @@ func TestAddressParsing(t *testing.T) {
 				},
 			},
 		},
+		// RFC 6532 3.2.3, qtext /= UTF8-non-ascii
+		{
+			`"Gø Pher" <gopher at example.com>`,
+			[]*Address{
+				{
+					Name:    `Gø Pher`,
+					Address: "gopher at example.com",
+				},
+			},
+		},
+		// RFC 6532 3.2, atext /= UTF8-non-ascii
+		{
+			`µ <micro at example.com>`,
+			[]*Address{
+				{
+					Name:    `µ`,
+					Address: "micro at example.com",
+				},
+			},
+		},
+		// RFC 6532 3.2.2, local address parts allow UTF-8
+		{
+			`Micro <µ@example.com>`,
+			[]*Address{
+				{
+					Name:    `Micro`,
+					Address: "µ@example.com",
+				},
+			},
+		},
+		// RFC 6532 3.2.4, domains parts allow UTF-8
+		{
+			`Micro <micro@µ.example.com>`,
+			[]*Address{
+				{
+					Name:    `Micro`,
+					Address: "micro@µ.example.com",
+				},
+			},
+		},
 	}
 	for _, test := range tests {
 		if len(test.exp) == 1 {
@@ -515,6 +561,11 @@ func TestAddressString(t *testing.T) {
 			&Address{Name: "world?=", Address: "hello at world.com"},
 			`"world?=" <hello at world.com>`,
 		},
+		{
+			// should q-encode even for invalid utf-8.
+			&Address{Name: string([]byte{0xed, 0xa0, 0x80}), Address: "invalid-utf8 at example.net"},
+			"=?utf-8?q?=ED=A0=80?= <invalid-utf8 at example.net>",
+		},
 	}
 	for _, test := range tests {
 		s := test.addr.String()
@@ -610,7 +661,6 @@ func TestAddressParsingAndFormatting(t *testing.T) {
 		`< @example.com>`,
 		`<""test""blah""@example.com>`,
 		`<""@0>`,
-		"<\"\t0\"@0>",
 	}
 
 	for _, test := range badTests {
diff --git a/src/net/main_conf_test.go b/src/net/main_conf_test.go
new file mode 100644
index 0000000..9875cea
--- /dev/null
+++ b/src/net/main_conf_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.
+
+// +build !nacl,!plan9,!windows
+
+package net
+
+// 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 a fixup function to restore the old settings.
+// (On non-Unix systems forceCgoDNS returns nil.)
+func forceCgoDNS() func() {
+	c := systemConf()
+	oldGo := c.netGo
+	oldCgo := c.netCgo
+	fixup := func() {
+		c.netGo = oldGo
+		c.netCgo = oldCgo
+	}
+	c.netGo = false
+	c.netCgo = true
+	return fixup
+}
diff --git a/src/net/main_noconf_test.go b/src/net/main_noconf_test.go
new file mode 100644
index 0000000..489477b
--- /dev/null
+++ b/src/net/main_noconf_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.
+
+// +build nacl plan9 windows
+
+package net
+
+import "runtime"
+
+// See main_conf_test.go for what these (don't) do.
+func forceGoDNS() func() {
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		return func() {}
+	default:
+		return nil
+	}
+}
+
+// See main_conf_test.go for what these (don't) do.
+func forceCgoDNS() func() { return nil }
diff --git a/src/net/main_plan9_test.go b/src/net/main_plan9_test.go
index 94501ca..2bc5be8 100644
--- a/src/net/main_plan9_test.go
+++ b/src/net/main_plan9_test.go
@@ -8,6 +8,7 @@ func installTestHooks() {}
 
 func uninstallTestHooks() {}
 
+// forceCloseSockets must be called only from TestMain.
 func forceCloseSockets() {}
 
 func enableSocketConnect() {}
diff --git a/src/net/main_test.go b/src/net/main_test.go
index f3f8b1a9..7573ded 100644
--- a/src/net/main_test.go
+++ b/src/net/main_test.go
@@ -26,8 +26,6 @@ var (
 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
diff --git a/src/net/main_unix_test.go b/src/net/main_unix_test.go
index bfb4cd0..0cc129f 100644
--- a/src/net/main_unix_test.go
+++ b/src/net/main_unix_test.go
@@ -45,6 +45,7 @@ func uninstallTestHooks() {
 	}
 }
 
+// forceCloseSockets must be called only from TestMain.
 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
index 2d82974..6ea318c 100644
--- a/src/net/main_windows_test.go
+++ b/src/net/main_windows_test.go
@@ -11,6 +11,7 @@ var (
 	origConnect     = connectFunc
 	origConnectEx   = connectExFunc
 	origListen      = listenFunc
+	origAccept      = acceptFunc
 )
 
 func installTestHooks() {
@@ -19,6 +20,7 @@ func installTestHooks() {
 	connectFunc = sw.Connect
 	connectExFunc = sw.ConnectEx
 	listenFunc = sw.Listen
+	acceptFunc = sw.AcceptEx
 }
 
 func uninstallTestHooks() {
@@ -27,8 +29,10 @@ func uninstallTestHooks() {
 	connectFunc = origConnect
 	connectExFunc = origConnectEx
 	listenFunc = origListen
+	acceptFunc = origAccept
 }
 
+// forceCloseSockets must be called only from TestMain.
 func forceCloseSockets() {
 	for s := range sw.Sockets() {
 		closeFunc(s)
diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go
index dd6f4df..766de6a 100644
--- a/src/net/mockserver_test.go
+++ b/src/net/mockserver_test.go
@@ -30,10 +30,20 @@ func testUnixAddr() string {
 
 func newLocalListener(network string) (Listener, error) {
 	switch network {
-	case "tcp", "tcp4", "tcp6":
+	case "tcp":
+		if supportsIPv4 {
+			if ln, err := Listen("tcp4", "127.0.0.1:0"); err == nil {
+				return ln, nil
+			}
+		}
+		if supportsIPv6 {
+			return Listen("tcp6", "[::1]:0")
+		}
+	case "tcp4":
 		if supportsIPv4 {
 			return Listen("tcp4", "127.0.0.1:0")
 		}
+	case "tcp6":
 		if supportsIPv6 {
 			return Listen("tcp6", "[::1]:0")
 		}
@@ -142,13 +152,6 @@ func (dss *dualStackServer) buildup(handler func(*dualStackServer, Listener)) er
 	return nil
 }
 
-func (dss *dualStackServer) putConn(c Conn) error {
-	dss.cmu.Lock()
-	dss.cs = append(dss.cs, c)
-	dss.cmu.Unlock()
-	return nil
-}
-
 func (dss *dualStackServer) teardownNetwork(network string) error {
 	dss.lnmu.Lock()
 	for i := range dss.lns {
@@ -181,28 +184,24 @@ func (dss *dualStackServer) teardown() error {
 	return nil
 }
 
-func newDualStackServer(lns []streamListener) (*dualStackServer, error) {
-	dss := &dualStackServer{lns: lns, port: "0"}
-	for i := range dss.lns {
-		ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port))
-		if err != nil {
-			for _, ln := range dss.lns[:i] {
-				ln.Listener.Close()
-			}
-			return nil, err
-		}
-		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 {
-				for _, ln := range dss.lns {
-					ln.Listener.Close()
-				}
-				return nil, err
-			}
-		}
+func newDualStackServer() (*dualStackServer, error) {
+	lns, err := newDualStackListener()
+	if err != nil {
+		return nil, err
+	}
+	_, port, err := SplitHostPort(lns[0].Addr().String())
+	if err != nil {
+		lns[0].Close()
+		lns[1].Close()
+		return nil, err
 	}
-	return dss, nil
+	return &dualStackServer{
+		lns: []streamListener{
+			{network: "tcp4", address: lns[0].Addr().String(), Listener: lns[0], done: make(chan bool)},
+			{network: "tcp6", address: lns[1].Addr().String(), Listener: lns[1], done: make(chan bool)},
+		},
+		port: port,
+	}, nil
 }
 
 func transponder(ln Listener, ch chan<- error) {
@@ -225,7 +224,7 @@ func transponder(ln Listener, ch chan<- error) {
 	defer c.Close()
 
 	network := ln.Addr().Network()
-	if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+	if c.LocalAddr().Network() != network || c.RemoteAddr().Network() != network {
 		ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
 		return
 	}
@@ -333,10 +332,18 @@ func timeoutTransmitter(c Conn, d, min, max time.Duration, ch chan<- error) {
 
 func newLocalPacketListener(network string) (PacketConn, error) {
 	switch network {
-	case "udp", "udp4", "udp6":
+	case "udp":
+		if supportsIPv4 {
+			return ListenPacket("udp4", "127.0.0.1:0")
+		}
+		if supportsIPv6 {
+			return ListenPacket("udp6", "[::1]:0")
+		}
+	case "udp4":
 		if supportsIPv4 {
 			return ListenPacket("udp4", "127.0.0.1:0")
 		}
+	case "udp6":
 		if supportsIPv6 {
 			return ListenPacket("udp6", "[::1]:0")
 		}
diff --git a/src/net/net.go b/src/net/net.go
index d9d23fa..d6812d1 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -14,7 +14,7 @@ the same interfaces and similar Dial and Listen functions.
 
 The Dial function connects to a server:
 
-	conn, err := net.Dial("tcp", "google.com:80")
+	conn, err := net.Dial("tcp", "golang.org:80")
 	if err != nil {
 		// handle error
 	}
@@ -79,6 +79,7 @@ On Windows, the resolver always uses C library functions, such as GetAddrInfo an
 package net
 
 import (
+	"context"
 	"errors"
 	"io"
 	"os"
@@ -297,7 +298,7 @@ func (c *conn) File() (f *os.File, err error) {
 // Multiple goroutines may invoke methods on a PacketConn simultaneously.
 type PacketConn interface {
 	// ReadFrom reads a packet from the connection,
-	// copying the payload into b.  It returns the number of
+	// copying the payload into b. It returns the number of
 	// bytes copied into b and the return address that
 	// was on the packet.
 	// ReadFrom can be made to time out and return
@@ -364,6 +365,9 @@ type Error interface {
 
 // Various errors contained in OpError.
 var (
+	// For connection setup operations.
+	errNoSuitableAddress = errors.New("no suitable address found")
+
 	// For connection setup and write operations.
 	errMissingAddress = errors.New("missing address")
 
@@ -374,6 +378,22 @@ var (
 	ErrWriteToConnected       = errors.New("use of WriteTo with pre-connected connection")
 )
 
+// mapErr maps from the context errors to the historical internal net
+// error values.
+//
+// TODO(bradfitz): get rid of this after adjusting tests and making
+// context.DeadlineExceeded implement net.Error?
+func mapErr(err error) error {
+	switch err {
+	case context.Canceled:
+		return errCanceled
+	case context.DeadlineExceeded:
+		return errTimeout
+	default:
+		return err
+	}
+}
+
 // OpError is the error type usually returned by functions in the net
 // package. It describes the operation, network type, and address of
 // an error.
diff --git a/src/net/net_test.go b/src/net/net_test.go
index cd62b43..b2f825d 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -6,6 +6,7 @@ package net
 
 import (
 	"io"
+	"net/internal/socktest"
 	"os"
 	"runtime"
 	"testing"
@@ -304,3 +305,112 @@ func TestListenCloseListen(t *testing.T) {
 	}
 	t.Fatalf("failed to listen/close/listen on same address after %d tries", maxTries)
 }
+
+// See golang.org/issue/6163, golang.org/issue/6987.
+func TestAcceptIgnoreAbortedConnRequest(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	}
+
+	syserr := make(chan error)
+	go func() {
+		defer close(syserr)
+		for _, err := range abortedConnRequestErrors {
+			syserr <- err
+		}
+	}()
+	sw.Set(socktest.FilterAccept, func(so *socktest.Status) (socktest.AfterFilter, error) {
+		if err, ok := <-syserr; ok {
+			return nil, err
+		}
+		return nil, nil
+	})
+	defer sw.Set(socktest.FilterAccept, nil)
+
+	operr := make(chan error, 1)
+	handler := func(ls *localServer, ln Listener) {
+		defer close(operr)
+		c, err := ln.Accept()
+		if err != nil {
+			if perr := parseAcceptError(err); perr != nil {
+				operr <- perr
+			}
+			operr <- err
+			return
+		}
+		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.Fatal(err)
+	}
+	c.Close()
+
+	for err := range operr {
+		t.Error(err)
+	}
+}
+
+func TestZeroByteRead(t *testing.T) {
+	for _, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
+		}
+
+		ln, err := newLocalListener(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		connc := make(chan Conn, 1)
+		go func() {
+			defer ln.Close()
+			c, err := ln.Accept()
+			if err != nil {
+				t.Error(err)
+			}
+			connc <- c // might be nil
+		}()
+		c, err := Dial(network, ln.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer c.Close()
+		sc := <-connc
+		if sc == nil {
+			continue
+		}
+		defer sc.Close()
+
+		if runtime.GOOS == "windows" {
+			// A zero byte read on Windows caused a wait for readability first.
+			// Rather than change that behavior, satisfy it in this test.
+			// See Issue 15735.
+			go io.WriteString(sc, "a")
+		}
+
+		n, err := c.Read(nil)
+		if n != 0 || err != nil {
+			t.Errorf("%s: zero byte client read = %v, %v; want 0, nil", network, n, err)
+		}
+
+		if runtime.GOOS == "windows" {
+			// Same as comment above.
+			go io.WriteString(c, "a")
+		}
+		n, err = sc.Read(nil)
+		if n != 0 || err != nil {
+			t.Errorf("%s: zero byte server read = %v, %v; want 0, nil", network, n, err)
+		}
+	}
+}
diff --git a/src/net/net_windows_test.go b/src/net/net_windows_test.go
index df39032..38edbc2 100644
--- a/src/net/net_windows_test.go
+++ b/src/net/net_windows_test.go
@@ -178,18 +178,6 @@ func isWindowsXP(t *testing.T) bool {
 	return major < 6
 }
 
-var (
-	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
-	procGetACP  = modkernel32.NewProc("GetACP")
-)
-
-func isEnglishOS(t *testing.T) bool {
-	const windows_1252 = 1252 // ANSI Latin 1; Western European (Windows)
-	r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0)
-	acp := uint32(r0)
-	return acp == windows_1252
-}
-
 func runCmd(args ...string) ([]byte, error) {
 	removeUTF8BOM := func(b []byte) []byte {
 		if len(b) >= 3 && b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF {
@@ -226,6 +214,14 @@ func runCmd(args ...string) ([]byte, error) {
 	return removeUTF8BOM(out), nil
 }
 
+func netshSpeaksEnglish(t *testing.T) bool {
+	out, err := runCmd("netsh", "help")
+	if err != nil {
+		t.Fatal(err)
+	}
+	return bytes.Contains(out, []byte("The following commands are available:"))
+}
+
 func netshInterfaceIPShowInterface(ipver string, ifaces map[string]bool) error {
 	out, err := runCmd("netsh", "interface", ipver, "show", "interface", "level=verbose")
 	if err != nil {
@@ -273,8 +269,8 @@ func TestInterfacesWithNetsh(t *testing.T) {
 	if isWindowsXP(t) {
 		t.Skip("Windows XP netsh command does not provide required functionality")
 	}
-	if !isEnglishOS(t) {
-		t.Skip("English version of OS required for this test")
+	if !netshSpeaksEnglish(t) {
+		t.Skip("English version of netsh required for this test")
 	}
 
 	toString := func(name string, isup bool) string {
@@ -315,7 +311,7 @@ func TestInterfacesWithNetsh(t *testing.T) {
 }
 
 func netshInterfaceIPv4ShowAddress(name string, netshOutput []byte) []string {
-	// adress information is listed like:
+	// Address information is listed like:
 	//
 	//Configuration for interface "Local Area Connection"
 	//    DHCP enabled:                         Yes
@@ -378,7 +374,7 @@ func netshInterfaceIPv4ShowAddress(name string, netshOutput []byte) []string {
 }
 
 func netshInterfaceIPv6ShowAddress(name string, netshOutput []byte) []string {
-	// adress information is listed like:
+	// Address information is listed like:
 	//
 	//Address ::1 Parameters
 	//---------------------------------------------------------
@@ -447,8 +443,8 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
 	if isWindowsXP(t) {
 		t.Skip("Windows XP netsh command does not provide required functionality")
 	}
-	if !isEnglishOS(t) {
-		t.Skip("English version of OS required for this test")
+	if !netshSpeaksEnglish(t) {
+		t.Skip("English version of netsh required for this test")
 	}
 
 	outIPV4, err := runCmd("netsh", "interface", "ipv4", "show", "address")
@@ -507,12 +503,20 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
 	}
 }
 
+func getmacSpeaksEnglish(t *testing.T) bool {
+	out, err := runCmd("getmac", "/?")
+	if err != nil {
+		t.Fatal(err)
+	}
+	return bytes.Contains(out, []byte("network adapters on a system"))
+}
+
 func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
 	if isWindowsXP(t) {
 		t.Skip("Windows XP does not have powershell command")
 	}
-	if !isEnglishOS(t) {
-		t.Skip("English version of OS required for this test")
+	if !getmacSpeaksEnglish(t) {
+		t.Skip("English version of getmac required for this test")
 	}
 
 	ift, err := Interfaces()
@@ -561,24 +565,24 @@ func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
 		if bytes.Contains(line, []byte("Connection Name:")) {
 			f := bytes.Split(line, []byte{':'})
 			if len(f) != 2 {
-				t.Fatal("unexpected \"Connection Name\" line: %q", line)
+				t.Fatalf("unexpected \"Connection Name\" line: %q", line)
 			}
 			name = string(bytes.TrimSpace(f[1]))
 			if name == "" {
-				t.Fatal("empty name on \"Connection Name\" line: %q", line)
+				t.Fatalf("empty name on \"Connection Name\" line: %q", line)
 			}
 		}
 		if bytes.Contains(line, []byte("Physical Address:")) {
 			if name == "" {
-				t.Fatal("no matching name found: %q", string(out))
+				t.Fatalf("no matching name found: %q", string(out))
 			}
 			f := bytes.Split(line, []byte{':'})
 			if len(f) != 2 {
-				t.Fatal("unexpected \"Physical Address\" line: %q", line)
+				t.Fatalf("unexpected \"Physical Address\" line: %q", line)
 			}
 			addr := string(bytes.ToLower(bytes.TrimSpace(f[1])))
 			if addr == "" {
-				t.Fatal("empty address on \"Physical Address\" line: %q", line)
+				t.Fatalf("empty address on \"Physical Address\" line: %q", line)
 			}
 			if addr == "disabled" || addr == "n/a" {
 				continue
diff --git a/src/net/netgo_unix_test.go b/src/net/netgo_unix_test.go
index 1d950d6..5f1eb19 100644
--- a/src/net/netgo_unix_test.go
+++ b/src/net/netgo_unix_test.go
@@ -7,18 +7,22 @@
 
 package net
 
-import "testing"
+import (
+	"context"
+	"testing"
+)
 
 func TestGoLookupIP(t *testing.T) {
 	host := "localhost"
-	_, err, ok := cgoLookupIP(host)
+	ctx := context.Background()
+	_, err, ok := cgoLookupIP(ctx, host)
 	if ok {
 		t.Errorf("cgoLookupIP must be a placeholder")
 	}
 	if err != nil {
 		t.Error(err)
 	}
-	if _, err := goLookupIP(host); err != nil {
+	if _, err := goLookupIP(ctx, host); err != nil {
 		t.Error(err)
 	}
 }
diff --git a/src/net/non_unix_test.go b/src/net/non_unix_test.go
deleted file mode 100644
index db3427e..0000000
--- a/src/net/non_unix_test.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2015 The Go 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
-
-import "runtime"
-
-// See unix_test.go for what these (don't) do.
-func forceGoDNS() func() {
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		return func() {}
-	default:
-		return nil
-	}
-}
-
-// See unix_test.go for what these (don't) do.
-func forceCgoDNS() func() { return nil }
diff --git a/src/net/packetconn_test.go b/src/net/packetconn_test.go
index 7f3ea8a..7d50489 100644
--- a/src/net/packetconn_test.go
+++ b/src/net/packetconn_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/net/parse.go b/src/net/parse.go
index eaaa1ed..ed82a77 100644
--- a/src/net/parse.go
+++ b/src/net/parse.go
@@ -105,14 +105,14 @@ func splitAtBytes(s string, t string) []string {
 	for i := 0; i < len(s); i++ {
 		if byteIndex(t, s[i]) >= 0 {
 			if last < i {
-				a[n] = string(s[last:i])
+				a[n] = s[last:i]
 				n++
 			}
 			last = i + 1
 		}
 	}
 	if last < len(s) {
-		a[n] = string(s[last:])
+		a[n] = s[last:]
 		n++
 	}
 	return a[0:n]
diff --git a/src/net/pipe.go b/src/net/pipe.go
index 5fc830b..37e552f 100644
--- a/src/net/pipe.go
+++ b/src/net/pipe.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/net/pipe_test.go b/src/net/pipe_test.go
index 60c3920..e3172d8 100644
--- a/src/net/pipe_test.go
+++ b/src/net/pipe_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
index 76c5313..2a14095 100644
--- a/src/net/platform_test.go
+++ b/src/net/platform_test.go
@@ -5,6 +5,7 @@
 package net
 
 import (
+	"internal/testenv"
 	"os"
 	"runtime"
 	"strings"
@@ -110,7 +111,7 @@ func testableListenArgs(network, address, client string) bool {
 	}
 
 	// Test wildcard IP addresses.
-	if wildcard && (testing.Short() || !*testExternal) {
+	if wildcard && !testenv.HasExternalNetwork() {
 		return false
 	}
 
diff --git a/src/net/port.go b/src/net/port.go
new file mode 100644
index 0000000..8e1321a
--- /dev/null
+++ b/src/net/port.go
@@ -0,0 +1,62 @@
+// Copyright 2016 The Go Authors. 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
+
+// parsePort parses service as a decimal interger and returns the
+// corresponding value as port. It is the caller's responsibility to
+// parse service as a non-decimal integer when needsLookup is true.
+//
+// Some system resolvers will return a valid port number when given a number
+// over 65536 (see https://github.com/golang/go/issues/11715). Alas, the parser
+// can't bail early on numbers > 65536. Therefore reasonably large/small
+// numbers are parsed in full and rejected if invalid.
+func parsePort(service string) (port int, needsLookup bool) {
+	if service == "" {
+		// Lock in the legacy behavior that an empty string
+		// means port 0. See golang.org/issue/13610.
+		return 0, false
+	}
+	const (
+		max    = uint32(1<<32 - 1)
+		cutoff = uint32(1 << 30)
+	)
+	neg := false
+	if service[0] == '+' {
+		service = service[1:]
+	} else if service[0] == '-' {
+		neg = true
+		service = service[1:]
+	}
+	var n uint32
+	for _, d := range service {
+		if '0' <= d && d <= '9' {
+			d -= '0'
+		} else {
+			return 0, true
+		}
+		if n >= cutoff {
+			n = max
+			break
+		}
+		n *= 10
+		nn := n + uint32(d)
+		if nn < n || nn > max {
+			n = max
+			break
+		}
+		n = nn
+	}
+	if !neg && n >= cutoff {
+		port = int(cutoff - 1)
+	} else if neg && n > cutoff {
+		port = int(cutoff)
+	} else {
+		port = int(n)
+	}
+	if neg {
+		port = -port
+	}
+	return port, false
+}
diff --git a/src/net/port_test.go b/src/net/port_test.go
new file mode 100644
index 0000000..e0bdb42
--- /dev/null
+++ b/src/net/port_test.go
@@ -0,0 +1,52 @@
+// Copyright 2016 The Go Authors. 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 "testing"
+
+var parsePortTests = []struct {
+	service     string
+	port        int
+	needsLookup bool
+}{
+	{"", 0, false},
+
+	// Decimal number literals
+	{"-1073741825", -1 << 30, false},
+	{"-1073741824", -1 << 30, false},
+	{"-1073741823", -(1<<30 - 1), false},
+	{"-123456789", -123456789, false},
+	{"-1", -1, false},
+	{"-0", 0, false},
+	{"0", 0, false},
+	{"+0", 0, false},
+	{"+1", 1, false},
+	{"65535", 65535, false},
+	{"65536", 65536, false},
+	{"123456789", 123456789, false},
+	{"1073741822", 1<<30 - 2, false},
+	{"1073741823", 1<<30 - 1, false},
+	{"1073741824", 1<<30 - 1, false},
+	{"1073741825", 1<<30 - 1, false},
+
+	// Others
+	{"abc", 0, true},
+	{"9pfs", 0, true},
+	{"123badport", 0, true},
+	{"bad123port", 0, true},
+	{"badport123", 0, true},
+	{"123456789badport", 0, true},
+	{"-2147483649badport", 0, true},
+	{"2147483649badport", 0, true},
+}
+
+func TestParsePort(t *testing.T) {
+	// The following test cases are cribbed from the strconv
+	for _, tt := range parsePortTests {
+		if port, needsLookup := parsePort(tt.service); port != tt.port || needsLookup != tt.needsLookup {
+			t.Errorf("parsePort(%q) = %d, %t; want %d, %t", tt.service, port, needsLookup, tt.port, tt.needsLookup)
+		}
+	}
+}
diff --git a/src/net/protoconn_test.go b/src/net/protoconn_test.go
index c6ef23b..23589d3 100644
--- a/src/net/protoconn_test.go
+++ b/src/net/protoconn_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/net/rpc/client.go b/src/net/rpc/client.go
index d0c4a69..862fb1a 100644
--- a/src/net/rpc/client.go
+++ b/src/net/rpc/client.go
@@ -55,7 +55,7 @@ type Client struct {
 // reading of RPC responses for the client side of an RPC session.
 // The client calls WriteRequest to write a request to the connection
 // and calls ReadResponseHeader and ReadResponseBody in pairs
-// to read responses.  The client calls Close when finished with the
+// to read responses. The client calls Close when finished with the
 // connection. ReadResponseBody may be called with a nil
 // argument to force the body of the response to be read and then
 // discarded.
@@ -173,7 +173,7 @@ func (call *Call) done() {
 	case call.Done <- call:
 		// ok
 	default:
-		// We don't want to block here.  It is the caller's responsibility to make
+		// We don't want to block here. It is the caller's responsibility to make
 		// sure the channel has enough buffer space. See comment in Go().
 		if debugLog {
 			log.Println("rpc: discarding Call reply due to insufficient Done chan capacity")
@@ -285,9 +285,9 @@ func (client *Client) Close() error {
 	return client.codec.Close()
 }
 
-// Go invokes the function asynchronously.  It returns the Call structure representing
-// the invocation.  The done channel will signal when the call is complete by returning
-// the same Call object.  If done is nil, Go will allocate a new channel.
+// Go invokes the function asynchronously. It returns the Call structure representing
+// the invocation. The done channel will signal when the call is complete by returning
+// the same Call object. If done is nil, Go will allocate a new channel.
 // If non-nil, done must be buffered or Go will deliberately crash.
 func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
 	call := new(Call)
@@ -299,7 +299,7 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface
 	} else {
 		// If caller passes done != nil, it must arrange that
 		// done has enough buffer for the number of simultaneous
-		// RPCs that will be using that channel.  If the channel
+		// RPCs that will be using that channel. If the channel
 		// is totally unbuffered, it's best not to run at all.
 		if cap(done) == 0 {
 			log.Panic("rpc: done channel is unbuffered")
diff --git a/src/net/rpc/jsonrpc/all_test.go b/src/net/rpc/jsonrpc/all_test.go
index a433a36..b811d3c 100644
--- a/src/net/rpc/jsonrpc/all_test.go
+++ b/src/net/rpc/jsonrpc/all_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/net/rpc/jsonrpc/client.go b/src/net/rpc/jsonrpc/client.go
index 2194f21..da1b816 100644
--- a/src/net/rpc/jsonrpc/client.go
+++ b/src/net/rpc/jsonrpc/client.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/net/rpc/jsonrpc/server.go b/src/net/rpc/jsonrpc/server.go
index e6d37cf..40e4e6f 100644
--- a/src/net/rpc/jsonrpc/server.go
+++ b/src/net/rpc/jsonrpc/server.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -110,7 +110,7 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
 	c.mutex.Unlock()
 
 	if b == nil {
-		// Invalid request so no id.  Use JSON null.
+		// Invalid request so no id. Use JSON null.
 		b = &null
 	}
 	resp := serverResponse{Id: b}
diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go
index c4d4479..cff3241 100644
--- a/src/net/rpc/server.go
+++ b/src/net/rpc/server.go
@@ -143,8 +143,8 @@ const (
 	DefaultDebugPath = "/debug/rpc"
 )
 
-// Precompute the reflect type for error.  Can't use error directly
-// because Typeof takes an empty interface value.  This is annoying.
+// Precompute the reflect type for error. Can't use error directly
+// because Typeof takes an empty interface value. This is annoying.
 var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
 
 type methodType struct {
@@ -162,7 +162,7 @@ type service struct {
 	method map[string]*methodType // registered methods
 }
 
-// Request is a header written before every RPC call.  It is used internally
+// Request is a header written before every RPC call. It is used internally
 // but documented here as an aid to debugging, such as when analyzing
 // network traffic.
 type Request struct {
@@ -171,7 +171,7 @@ type Request struct {
 	next          *Request // for free list in Server
 }
 
-// Response is a header written before every RPC return.  It is used internally
+// Response is a header written before every RPC return. It is used internally
 // but documented here as an aid to debugging, such as when analyzing
 // network traffic.
 type Response struct {
@@ -442,7 +442,7 @@ func (c *gobServerCodec) Close() error {
 // ServeConn blocks, serving the connection until the client hangs up.
 // The caller typically invokes ServeConn in a go statement.
 // ServeConn uses the gob wire format (see package gob) on the
-// connection.  To use an alternate codec, use ServeCodec.
+// connection. To use an alternate codec, use ServeCodec.
 func (server *Server) ServeConn(conn io.ReadWriteCloser) {
 	buf := bufio.NewWriter(conn)
 	srv := &gobServerCodec{
@@ -583,7 +583,7 @@ func (server *Server) readRequestHeader(codec ServerCodec) (service *service, mt
 		return
 	}
 
-	// We read the header successfully.  If we see an error now,
+	// We read the header successfully. If we see an error now,
 	// we can still recover and move on to the next request.
 	keepReading = true
 
@@ -638,7 +638,7 @@ func RegisterName(name string, rcvr interface{}) error {
 // RPC responses for the server side of an RPC session.
 // The server calls ReadRequestHeader and ReadRequestBody in pairs
 // to read requests from the connection, and it calls WriteResponse to
-// write a response back.  The server calls Close when finished with the
+// write a response back. The server calls Close when finished with the
 // connection. ReadRequestBody may be called with a nil
 // argument to force the body of the request to be read and discarded.
 type ServerCodec interface {
@@ -654,7 +654,7 @@ type ServerCodec interface {
 // ServeConn blocks, serving the connection until the client hangs up.
 // The caller typically invokes ServeConn in a go statement.
 // ServeConn uses the gob wire format (see package gob) on the
-// connection.  To use an alternate codec, use ServeCodec.
+// connection. To use an alternate codec, use ServeCodec.
 func ServeConn(conn io.ReadWriteCloser) {
 	DefaultServer.ServeConn(conn)
 }
diff --git a/src/net/rpc/server_test.go b/src/net/rpc/server_test.go
index 8871c88..d04271d 100644
--- a/src/net/rpc/server_test.go
+++ b/src/net/rpc/server_test.go
@@ -183,7 +183,7 @@ func testRPC(t *testing.T, addr string) {
 	err = client.Call("Arith.Unknown", args, reply)
 	if err == nil {
 		t.Error("expected error calling unknown service")
-	} else if strings.Index(err.Error(), "method") < 0 {
+	} else if !strings.Contains(err.Error(), "method") {
 		t.Error("expected error about method; got", err)
 	}
 
@@ -226,7 +226,7 @@ func testRPC(t *testing.T, addr string) {
 	err = client.Call("Arith.Add", reply, reply) // args, reply would be the correct thing to use
 	if err == nil {
 		t.Error("expected error calling Arith.Add with wrong arg type")
-	} else if strings.Index(err.Error(), "type") < 0 {
+	} else if !strings.Contains(err.Error(), "type") {
 		t.Error("expected error about type; got", err)
 	}
 
@@ -657,6 +657,9 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) {
 }
 
 func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
+	if b.N == 0 {
+		return
+	}
 	const MaxConcurrentCalls = 100
 	once.Do(startServer)
 	client, err := dial()
diff --git a/src/net/sendfile_dragonfly.go b/src/net/sendfile_dragonfly.go
index a9cf3fe..d4b825c 100644
--- a/src/net/sendfile_dragonfly.go
+++ b/src/net/sendfile_dragonfly.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -53,7 +53,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 	// 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)
+	pos, err := f.Seek(0, io.SeekCurrent)
 	if err != nil {
 		return 0, err, false
 	}
@@ -81,7 +81,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 			break
 		}
 		if err1 == syscall.EAGAIN {
-			if err1 = c.pd.WaitWrite(); err1 == nil {
+			if err1 = c.pd.waitWrite(); err1 == nil {
 				continue
 			}
 		}
diff --git a/src/net/sendfile_freebsd.go b/src/net/sendfile_freebsd.go
index d0bf603..18cbb27 100644
--- a/src/net/sendfile_freebsd.go
+++ b/src/net/sendfile_freebsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -53,7 +53,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 	// 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)
+	pos, err := f.Seek(0, io.SeekCurrent)
 	if err != nil {
 		return 0, err, false
 	}
@@ -81,7 +81,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 			break
 		}
 		if err1 == syscall.EAGAIN {
-			if err1 = c.pd.WaitWrite(); err1 == nil {
+			if err1 = c.pd.waitWrite(); err1 == nil {
 				continue
 			}
 		}
diff --git a/src/net/sendfile_linux.go b/src/net/sendfile_linux.go
index 5ca41c3..7e741f9 100644
--- a/src/net/sendfile_linux.go
+++ b/src/net/sendfile_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -57,7 +57,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 			break
 		}
 		if err1 == syscall.EAGAIN {
-			if err1 = c.pd.WaitWrite(); err1 == nil {
+			if err1 = c.pd.waitWrite(); err1 == nil {
 				continue
 			}
 		}
diff --git a/src/net/sendfile_solaris.go b/src/net/sendfile_solaris.go
index f683381..add70c3 100644
--- a/src/net/sendfile_solaris.go
+++ b/src/net/sendfile_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -26,8 +26,6 @@ const maxSendfileSize int = 4 << 20
 //
 // if handled == false, sendFile performed no work.
 func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
-	return // Solaris sendfile is disabled until Issue 13892 is understood and fixed
-
 	// 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
@@ -59,7 +57,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 	// 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)
+	pos, err := f.Seek(0, io.SeekCurrent)
 	if err != nil {
 		return 0, err, false
 	}
@@ -78,6 +76,13 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 		}
 		pos1 := pos
 		n, err1 := syscall.Sendfile(dst, src, &pos1, n)
+		if err1 == syscall.EAGAIN || err1 == syscall.EINTR {
+			// partial write may have occurred
+			if n = int(pos1 - pos); n == 0 {
+				// nothing more to write
+				err1 = nil
+			}
+		}
 		if n > 0 {
 			pos += int64(n)
 			written += int64(n)
@@ -87,7 +92,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 			break
 		}
 		if err1 == syscall.EAGAIN {
-			if err1 = c.pd.WaitWrite(); err1 == nil {
+			if err1 = c.pd.waitWrite(); err1 == nil {
 				continue
 			}
 		}
diff --git a/src/net/sendfile_stub.go b/src/net/sendfile_stub.go
index a0760b4..905f1d6 100644
--- a/src/net/sendfile_stub.go
+++ b/src/net/sendfile_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/sendfile_test.go b/src/net/sendfile_test.go
new file mode 100644
index 0000000..2255e7c
--- /dev/null
+++ b/src/net/sendfile_test.go
@@ -0,0 +1,90 @@
+// Copyright 2016 The Go Authors. 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 (
+	"crypto/sha256"
+	"encoding/hex"
+	"fmt"
+	"io"
+	"os"
+	"testing"
+)
+
+const (
+	twain       = "testdata/Mark.Twain-Tom.Sawyer.txt"
+	twainLen    = 387851
+	twainSHA256 = "461eb7cb2d57d293fc680c836464c9125e4382be3596f7d415093ae9db8fcb0e"
+)
+
+func TestSendfile(t *testing.T) {
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+
+	errc := make(chan error, 1)
+	go func(ln Listener) {
+		// Wait for a connection.
+		conn, err := ln.Accept()
+		if err != nil {
+			errc <- err
+			close(errc)
+			return
+		}
+
+		go func() {
+			defer close(errc)
+			defer conn.Close()
+
+			f, err := os.Open(twain)
+			if err != nil {
+				errc <- err
+				return
+			}
+			defer f.Close()
+
+			// Return file data using io.Copy, which should use
+			// sendFile if available.
+			sbytes, err := io.Copy(conn, f)
+			if err != nil {
+				errc <- err
+				return
+			}
+
+			if sbytes != twainLen {
+				errc <- fmt.Errorf("sent %d bytes; expected %d", sbytes, twainLen)
+				return
+			}
+		}()
+	}(ln)
+
+	// Connect to listener to retrieve file and verify digest matches
+	// expected.
+	c, err := Dial("tcp", ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	h := sha256.New()
+	rbytes, err := io.Copy(h, c)
+	if err != nil {
+		t.Error(err)
+	}
+
+	if rbytes != twainLen {
+		t.Errorf("received %d bytes; expected %d", rbytes, twainLen)
+	}
+
+	if res := hex.EncodeToString(h.Sum(nil)); res != twainSHA256 {
+		t.Error("retrieved data hash did not match")
+	}
+
+	for err := range errc {
+		t.Error(err)
+	}
+}
diff --git a/src/net/sendfile_windows.go b/src/net/sendfile_windows.go
index f3f3b54..bc0b7fb 100644
--- a/src/net/sendfile_windows.go
+++ b/src/net/sendfile_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -18,7 +18,7 @@ import (
 //
 // if handled == false, sendFile performed no work.
 //
-// Note that sendfile for windows does not suppport >2GB file.
+// Note that sendfile for windows does not support >2GB file.
 func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) {
 	var n int64 = 0 // by default, copy until EOF
 
diff --git a/src/net/smtp/smtp.go b/src/net/smtp/smtp.go
index 0988350..b4e4867 100644
--- a/src/net/smtp/smtp.go
+++ b/src/net/smtp/smtp.go
@@ -83,8 +83,8 @@ func (c *Client) hello() error {
 
 // Hello sends a HELO or EHLO to the server as the given host name.
 // Calling this method is only necessary if the client needs control
-// over the host name used.  The client will introduce itself as "localhost"
-// automatically otherwise.  If Hello is called, it must be called before
+// over the host name used. The client will introduce itself as "localhost"
+// automatically otherwise. If Hello is called, it must be called before
 // any of the other methods.
 func (c *Client) Hello(localName string) error {
 	if c.didHello {
@@ -265,7 +265,7 @@ func (d *dataCloser) Close() error {
 
 // Data issues a DATA command to the server and returns a writer that
 // 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
+// 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")
@@ -287,7 +287,7 @@ var testHookStartTLS func(*tls.Config) // nil, except for tests
 //
 // 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
+// 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.
diff --git a/src/net/sock_bsd.go b/src/net/sock_bsd.go
index 6c37109..4e0e9e0 100644
--- a/src/net/sock_bsd.go
+++ b/src/net/sock_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/sock_linux.go b/src/net/sock_linux.go
index cc5ce15..e2732c5 100644
--- a/src/net/sock_linux.go
+++ b/src/net/sock_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/sock_plan9.go b/src/net/sock_plan9.go
index 88d9ed1..9367ad8 100644
--- a/src/net/sock_plan9.go
+++ b/src/net/sock_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/net/sock_posix.go b/src/net/sock_posix.go
index 4676721..c3af27b 100644
--- a/src/net/sock_posix.go
+++ b/src/net/sock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,9 +7,9 @@
 package net
 
 import (
+	"context"
 	"os"
 	"syscall"
-	"time"
 )
 
 // A sockaddr represents a TCP, UDP, IP or Unix network endpoint
@@ -34,7 +34,7 @@ type sockaddr interface {
 
 // socket returns a network file descriptor that is ready for
 // asynchronous I/O using the network poller.
-func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr, deadline time.Time, cancel <-chan struct{}) (fd *netFD, err error) {
+func socket(ctx context.Context, net string, family, sotype, proto int, ipv6only bool, laddr, raddr sockaddr) (fd *netFD, err error) {
 	s, err := sysSocket(family, sotype, proto)
 	if err != nil {
 		return nil, err
@@ -86,7 +86,7 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s
 			return fd, nil
 		}
 	}
-	if err := fd.dial(laddr, raddr, deadline, cancel); err != nil {
+	if err := fd.dial(ctx, laddr, raddr); err != nil {
 		fd.Close()
 		return nil, err
 	}
@@ -117,7 +117,7 @@ func (fd *netFD) addrFunc() func(syscall.Sockaddr) Addr {
 	return func(syscall.Sockaddr) Addr { return nil }
 }
 
-func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, cancel <-chan struct{}) error {
+func (fd *netFD) dial(ctx context.Context, laddr, raddr sockaddr) error {
 	var err error
 	var lsa syscall.Sockaddr
 	if laddr != nil {
@@ -134,7 +134,7 @@ func (fd *netFD) dial(laddr, raddr sockaddr, deadline time.Time, cancel <-chan s
 		if rsa, err = raddr.sockaddr(fd.family); err != nil {
 			return err
 		}
-		if err := fd.connect(lsa, rsa, deadline, cancel); err != nil {
+		if err := fd.connect(ctx, lsa, rsa); err != nil {
 			return err
 		}
 		fd.isConnected = true
diff --git a/src/net/sock_stub.go b/src/net/sock_stub.go
index ed6b089..5ac1e86 100644
--- a/src/net/sock_stub.go
+++ b/src/net/sock_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/sock_windows.go b/src/net/sock_windows.go
index 888e70b..89a3ca4 100644
--- a/src/net/sock_windows.go
+++ b/src/net/sock_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/sockopt_bsd.go b/src/net/sockopt_bsd.go
index 1b4a586..567e4e1 100644
--- a/src/net/sockopt_bsd.go
+++ b/src/net/sockopt_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -27,7 +27,7 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
 	}
 	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
+		// is otherwise. Note that some operating systems
 		// never admit this option.
 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
 	}
diff --git a/src/net/sockopt_linux.go b/src/net/sockopt_linux.go
index 54c20b1..0f70b12 100644
--- a/src/net/sockopt_linux.go
+++ b/src/net/sockopt_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -12,7 +12,7 @@ import (
 func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
 	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
 		// Allow both IP versions even if the OS default
-		// is otherwise.  Note that some operating systems
+		// is otherwise. Note that some operating systems
 		// never admit this option.
 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
 	}
diff --git a/src/net/sockopt_plan9.go b/src/net/sockopt_plan9.go
index 8bc689b..02468cd 100644
--- a/src/net/sockopt_plan9.go
+++ b/src/net/sockopt_plan9.go
@@ -1,9 +1,11 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 net
 
+import "syscall"
+
 func setKeepAlive(fd *netFD, keepalive bool) error {
 	if keepalive {
 		_, e := fd.ctl.WriteAt([]byte("keepalive"), 0)
@@ -11,3 +13,7 @@ func setKeepAlive(fd *netFD, keepalive bool) error {
 	}
 	return nil
 }
+
+func setLinger(fd *netFD, sec int) error {
+	return syscall.EPLAN9
+}
diff --git a/src/net/sockopt_posix.go b/src/net/sockopt_posix.go
index 1654d1b..cd3d562 100644
--- a/src/net/sockopt_posix.go
+++ b/src/net/sockopt_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/sockopt_solaris.go b/src/net/sockopt_solaris.go
index 54c20b1..0f70b12 100644
--- a/src/net/sockopt_solaris.go
+++ b/src/net/sockopt_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -12,7 +12,7 @@ import (
 func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
 	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
 		// Allow both IP versions even if the OS default
-		// is otherwise.  Note that some operating systems
+		// is otherwise. Note that some operating systems
 		// never admit this option.
 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
 	}
diff --git a/src/net/sockopt_stub.go b/src/net/sockopt_stub.go
index de5ee0b..7e9e560 100644
--- a/src/net/sockopt_stub.go
+++ b/src/net/sockopt_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/sockopt_windows.go b/src/net/sockopt_windows.go
index cb64a40..8017426 100644
--- a/src/net/sockopt_windows.go
+++ b/src/net/sockopt_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -12,7 +12,7 @@ import (
 func setDefaultSockopts(s syscall.Handle, family, sotype int, ipv6only bool) error {
 	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
 		// Allow both IP versions even if the OS default
-		// is otherwise.  Note that some operating systems
+		// is otherwise. Note that some operating systems
 		// never admit this option.
 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
 	}
diff --git a/src/net/sockoptip_bsd.go b/src/net/sockoptip_bsd.go
index 2199e48..b15c639 100644
--- a/src/net/sockoptip_bsd.go
+++ b/src/net/sockoptip_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/sockoptip_linux.go b/src/net/sockoptip_linux.go
index a69b778..c1dcc91 100644
--- a/src/net/sockoptip_linux.go
+++ b/src/net/sockoptip_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/sockoptip_posix.go b/src/net/sockoptip_posix.go
index c2579be..d508860 100644
--- a/src/net/sockoptip_posix.go
+++ b/src/net/sockoptip_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/sockoptip_stub.go b/src/net/sockoptip_stub.go
index 32ec5dd..f698687 100644
--- a/src/net/sockoptip_stub.go
+++ b/src/net/sockoptip_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/sockoptip_windows.go b/src/net/sockoptip_windows.go
index 7b11f20..916debe 100644
--- a/src/net/sockoptip_windows.go
+++ b/src/net/sockoptip_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/net/tcp_test.go b/src/net/tcp_test.go
deleted file mode 100644
index 30c5762..0000000
--- a/src/net/tcp_test.go
+++ /dev/null
@@ -1,590 +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 net
-
-import (
-	"io"
-	"reflect"
-	"runtime"
-	"sync"
-	"testing"
-	"time"
-)
-
-func BenchmarkTCP4OneShot(b *testing.B) {
-	benchmarkTCP(b, false, false, "127.0.0.1:0")
-}
-
-func BenchmarkTCP4OneShotTimeout(b *testing.B) {
-	benchmarkTCP(b, false, true, "127.0.0.1:0")
-}
-
-func BenchmarkTCP4Persistent(b *testing.B) {
-	benchmarkTCP(b, true, false, "127.0.0.1:0")
-}
-
-func BenchmarkTCP4PersistentTimeout(b *testing.B) {
-	benchmarkTCP(b, true, true, "127.0.0.1:0")
-}
-
-func BenchmarkTCP6OneShot(b *testing.B) {
-	if !supportsIPv6 {
-		b.Skip("ipv6 is not supported")
-	}
-	benchmarkTCP(b, false, false, "[::1]:0")
-}
-
-func BenchmarkTCP6OneShotTimeout(b *testing.B) {
-	if !supportsIPv6 {
-		b.Skip("ipv6 is not supported")
-	}
-	benchmarkTCP(b, false, true, "[::1]:0")
-}
-
-func BenchmarkTCP6Persistent(b *testing.B) {
-	if !supportsIPv6 {
-		b.Skip("ipv6 is not supported")
-	}
-	benchmarkTCP(b, true, false, "[::1]:0")
-}
-
-func BenchmarkTCP6PersistentTimeout(b *testing.B) {
-	if !supportsIPv6 {
-		b.Skip("ipv6 is not supported")
-	}
-	benchmarkTCP(b, true, true, "[::1]:0")
-}
-
-func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
-	const msgLen = 512
-	conns := b.N
-	numConcurrent := runtime.GOMAXPROCS(-1) * 2
-	msgs := 1
-	if persistent {
-		conns = numConcurrent
-		msgs = b.N / conns
-		if msgs == 0 {
-			msgs = 1
-		}
-		if conns > b.N {
-			conns = b.N
-		}
-	}
-	sendMsg := func(c Conn, buf []byte) bool {
-		n, err := c.Write(buf)
-		if n != len(buf) || err != nil {
-			b.Log(err)
-			return false
-		}
-		return true
-	}
-	recvMsg := func(c Conn, buf []byte) bool {
-		for read := 0; read != len(buf); {
-			n, err := c.Read(buf)
-			read += n
-			if err != nil {
-				b.Log(err)
-				return false
-			}
-		}
-		return true
-	}
-	ln, err := Listen("tcp", laddr)
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer ln.Close()
-	serverSem := make(chan bool, numConcurrent)
-	// Acceptor.
-	go func() {
-		for {
-			c, err := ln.Accept()
-			if err != nil {
-				break
-			}
-			serverSem <- true
-			// Server connection.
-			go func(c Conn) {
-				defer func() {
-					c.Close()
-					<-serverSem
-				}()
-				if timeout {
-					c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
-				}
-				var buf [msgLen]byte
-				for m := 0; m < msgs; m++ {
-					if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
-						break
-					}
-				}
-			}(c)
-		}
-	}()
-	clientSem := make(chan bool, numConcurrent)
-	for i := 0; i < conns; i++ {
-		clientSem <- true
-		// Client connection.
-		go func() {
-			defer func() {
-				<-clientSem
-			}()
-			c, err := Dial("tcp", ln.Addr().String())
-			if err != nil {
-				b.Log(err)
-				return
-			}
-			defer c.Close()
-			if timeout {
-				c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
-			}
-			var buf [msgLen]byte
-			for m := 0; m < msgs; m++ {
-				if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
-					break
-				}
-			}
-		}()
-	}
-	for i := 0; i < numConcurrent; i++ {
-		clientSem <- true
-		serverSem <- true
-	}
-}
-
-func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) {
-	benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0")
-}
-
-func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
-	if !supportsIPv6 {
-		b.Skip("ipv6 is not supported")
-	}
-	benchmarkTCPConcurrentReadWrite(b, "[::1]:0")
-}
-
-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.
-	// 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([]Conn, P)
-	servers := make([]Conn, P)
-	ln, err := Listen("tcp", laddr)
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer ln.Close()
-	done := make(chan bool)
-	go func() {
-		for p := 0; p < P; p++ {
-			s, err := ln.Accept()
-			if err != nil {
-				b.Error(err)
-				return
-			}
-			servers[p] = s
-		}
-		done <- true
-	}()
-	for p := 0; p < P; p++ {
-		c, err := Dial("tcp", ln.Addr().String())
-		if err != nil {
-			b.Fatal(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 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
-				_, err := c.Write(buf[:])
-				if err != nil {
-					b.Error(err)
-					return
-				}
-			}
-		}(clients[p])
-
-		// Pipe between server reader and server writer.
-		pipe := make(chan byte, 128)
-
-		// Server reader.
-		go func(s Conn) {
-			defer wg.Done()
-			var buf [1]byte
-			for i := 0; i < N; i++ {
-				_, err := s.Read(buf[:])
-				if err != nil {
-					b.Error(err)
-					return
-				}
-				pipe <- buf[0]
-			}
-		}(servers[p])
-
-		// Server writer.
-		go func(s 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
-				_, err := s.Write(buf[:])
-				if err != nil {
-					b.Error(err)
-					return
-				}
-			}
-			s.Close()
-		}(servers[p])
-
-		// Client reader.
-		go func(c Conn) {
-			defer wg.Done()
-			var buf [1]byte
-			for i := 0; i < N; i++ {
-				_, err := c.Read(buf[:])
-				if err != nil {
-					b.Error(err)
-					return
-				}
-			}
-			c.Close()
-		}(clients[p])
-	}
-	wg.Wait()
-}
-
-type resolveTCPAddrTest struct {
-	network       string
-	litAddrOrName string
-	addr          *TCPAddr
-	err           error
-}
-
-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]: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},
-
-	{"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
-	{"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
-
-	{"tcp", ":12345", &TCPAddr{Port: 12345}, nil},
-
-	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
-}
-
-func TestResolveTCPAddr(t *testing.T) {
-	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.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 := 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)
-		}
-	}
-}
-
-var tcpListenerNameTests = []struct {
-	net   string
-	laddr *TCPAddr
-}{
-	{"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}},
-	{"tcp4", &TCPAddr{}},
-	{"tcp4", nil},
-}
-
-func TestTCPListenerName(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-
-	for _, tt := range tcpListenerNameTests {
-		ln, err := ListenTCP(tt.net, tt.laddr)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer ln.Close()
-		la := ln.Addr()
-		if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
-			t.Fatalf("got %v; expected a proper address with non-zero port number", la)
-		}
-	}
-}
-
-func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv6 {
-		t.Skip("IPv6 is not supported")
-	}
-
-	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.Log(err)
-			continue
-		}
-		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)
-		}
-
-		c, err := Dial(tt.network, ls.Listener.Addr().String())
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer c.Close()
-		if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
-			t.Fatalf("got %v; expected a proper address with zone identifier", la)
-		}
-		if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
-			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
-		}
-
-		if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
-			t.Fatal(err)
-		}
-		b := make([]byte, 32)
-		if _, err := c.Read(b); err != nil {
-			t.Fatal(err)
-		}
-
-		for err := range ch {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-func TestTCPConcurrentAccept(t *testing.T) {
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	const N = 10
-	var wg sync.WaitGroup
-	wg.Add(N)
-	for i := 0; i < N; i++ {
-		go func() {
-			for {
-				c, err := ln.Accept()
-				if err != nil {
-					break
-				}
-				c.Close()
-			}
-			wg.Done()
-		}()
-	}
-	attempts := 10 * N
-	fails := 0
-	d := &Dialer{Timeout: 200 * time.Millisecond}
-	for i := 0; i < attempts; i++ {
-		c, err := d.Dial("tcp", ln.Addr().String())
-		if err != nil {
-			fails++
-		} else {
-			c.Close()
-		}
-	}
-	ln.Close()
-	wg.Wait()
-	if fails > attempts/9 { // see issues 7400 and 7541
-		t.Fatalf("too many Dial failed: %v", fails)
-	}
-	if fails > 0 {
-		t.Logf("# of failed Dials: %v", fails)
-	}
-}
-
-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.Fatal(err)
-	}
-	defer ln.Close()
-	var server Conn
-	errc := make(chan error)
-	go func() {
-		var err error
-		server, err = ln.Accept()
-		errc <- err
-	}()
-	client, err := Dial("tcp", ln.Addr().String())
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer client.Close()
-	if err := <-errc; err != nil {
-		t.Fatal(err)
-	}
-	defer server.Close()
-	var buf [128]byte
-	allocs := testing.AllocsPerRun(1000, func() {
-		_, err := server.Write(buf[:])
-		if err != nil {
-			t.Fatal(err)
-		}
-		_, err = io.ReadFull(client, buf[:])
-		if err != nil {
-			t.Fatal(err)
-		}
-	})
-	if allocs > 0 {
-		t.Fatalf("got %v; want 0", allocs)
-	}
-}
-
-func TestTCPStress(t *testing.T) {
-	const conns = 2
-	const msgLen = 512
-	msgs := int(1e4)
-	if testing.Short() {
-		msgs = 1e2
-	}
-
-	sendMsg := func(c Conn, buf []byte) bool {
-		n, err := c.Write(buf)
-		if n != len(buf) || err != nil {
-			t.Log(err)
-			return false
-		}
-		return true
-	}
-	recvMsg := func(c Conn, buf []byte) bool {
-		for read := 0; read != len(buf); {
-			n, err := c.Read(buf)
-			read += n
-			if err != nil {
-				t.Log(err)
-				return false
-			}
-		}
-		return true
-	}
-
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	done := make(chan bool)
-	// Acceptor.
-	go func() {
-		defer func() {
-			done <- true
-		}()
-		for {
-			c, err := ln.Accept()
-			if err != nil {
-				break
-			}
-			// Server connection.
-			go func(c Conn) {
-				defer c.Close()
-				var buf [msgLen]byte
-				for m := 0; m < msgs; m++ {
-					if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
-						break
-					}
-				}
-			}(c)
-		}
-	}()
-	for i := 0; i < conns; i++ {
-		// Client connection.
-		go func() {
-			defer func() {
-				done <- true
-			}()
-			c, err := Dial("tcp", ln.Addr().String())
-			if err != nil {
-				t.Log(err)
-				return
-			}
-			defer c.Close()
-			var buf [msgLen]byte
-			for m := 0; m < msgs; m++ {
-				if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
-					break
-				}
-			}
-		}()
-	}
-	for i := 0; i < conns; i++ {
-		<-done
-	}
-	ln.Close()
-	<-done
-}
diff --git a/src/net/tcpsock.go b/src/net/tcpsock.go
index 8765aff..7cffcc5 100644
--- a/src/net/tcpsock.go
+++ b/src/net/tcpsock.go
@@ -1,9 +1,17 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 (
+	"context"
+	"io"
+	"os"
+	"syscall"
+	"time"
+)
+
 // TCPAddr represents the address of a TCP end point.
 type TCPAddr struct {
 	IP   IP
@@ -53,9 +61,234 @@ func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	addrs, err := internetAddrList(net, addr, noDeadline)
+	addrs, err := internetAddrList(context.Background(), net, addr)
 	if err != nil {
 		return nil, err
 	}
 	return addrs.first(isIPv4).(*TCPAddr), nil
 }
+
+// TCPConn is an implementation of the Conn interface for TCP network
+// connections.
+type TCPConn struct {
+	conn
+}
+
+// ReadFrom implements the io.ReaderFrom ReadFrom method.
+func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	n, err := c.readFrom(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.
+// Most callers should just use Close.
+func (c *TCPConn) CloseRead() error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	if err := c.fd.closeRead(); err != nil {
+		return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
+}
+
+// CloseWrite shuts down the writing side of the TCP connection.
+// Most callers should just use Close.
+func (c *TCPConn) CloseWrite() error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	if err := c.fd.closeWrite(); err != nil {
+		return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
+}
+
+// SetLinger sets the behavior of Close on a connection which still
+// has data waiting to be sent or to be acknowledged.
+//
+// If sec < 0 (the default), the operating system finishes sending the
+// data in the background.
+//
+// If sec == 0, the operating system discards any unsent or
+// unacknowledged data.
+//
+// If sec > 0, the data is sent in the background as with sec < 0. On
+// some operating systems after sec seconds have elapsed any remaining
+// unsent data may be discarded.
+func (c *TCPConn) SetLinger(sec int) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	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
+// keepalive messages on the connection.
+func (c *TCPConn) SetKeepAlive(keepalive bool) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	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.
+func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	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
+// packet transmission in hopes of sending fewer packets (Nagle's
+// 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 {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	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
+}
+
+func newTCPConn(fd *netFD) *TCPConn {
+	c := &TCPConn{conn{fd}}
+	setNoDelay(c.fd, true)
+	return c
+}
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is
+// used as the local address for the connection.
+func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+	switch net {
+	case "tcp", "tcp4", "tcp6":
+	default:
+		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, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+	}
+	c, err := dialTCP(context.Background(), net, laddr, raddr)
+	if err != nil {
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+	}
+	return c, nil
+}
+
+// TCPListener is a TCP network listener. Clients should typically
+// use variables of type Listener instead of assuming TCP.
+type TCPListener struct {
+	fd *netFD
+}
+
+// AcceptTCP accepts the next incoming call and returns the new
+// connection.
+func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
+	if !l.ok() {
+		return nil, syscall.EINVAL
+	}
+	c, err := l.accept()
+	if err != nil {
+		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return c, nil
+}
+
+// Accept implements the Accept method in the Listener interface; it
+// waits for the next call and returns a generic Conn.
+func (l *TCPListener) Accept() (Conn, error) {
+	if !l.ok() {
+		return nil, syscall.EINVAL
+	}
+	c, err := l.accept()
+	if err != nil {
+		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return c, nil
+}
+
+// Close stops listening on the TCP address.
+// Already Accepted connections are not closed.
+func (l *TCPListener) Close() error {
+	if !l.ok() {
+		return syscall.EINVAL
+	}
+	if err := l.close(); err != nil {
+		return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return nil
+}
+
+// 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.
+// A zero time value disables the deadline.
+func (l *TCPListener) SetDeadline(t time.Time) error {
+	if !l.ok() {
+		return syscall.EINVAL
+	}
+	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
+// mode. It is the caller's responsibility to close f when finished.
+// Closing l does not affect f, and closing f does not affect l.
+//
+// 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) {
+	if !l.ok() {
+		return nil, syscall.EINVAL
+	}
+	f, err = l.file()
+	if err != nil {
+		return nil, &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
+// port of 0, ListenTCP will choose an available port. The caller can
+// use the Addr method of TCPListener to retrieve the chosen address.
+func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
+	switch net {
+	case "tcp", "tcp4", "tcp6":
+	default:
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+	}
+	if laddr == nil {
+		laddr = &TCPAddr{}
+	}
+	ln, err := listenTCP(context.Background(), net, laddr)
+	if err != nil {
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+	}
+	return ln, nil
+}
diff --git a/src/net/tcpsock_plan9.go b/src/net/tcpsock_plan9.go
index afccbfe..d286060 100644
--- a/src/net/tcpsock_plan9.go
+++ b/src/net/tcpsock_plan9.go
@@ -1,230 +1,73 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 (
+	"context"
 	"io"
 	"os"
-	"syscall"
-	"time"
 )
 
-// TCPConn is an implementation of the Conn interface for TCP network
-// connections.
-type TCPConn struct {
-	conn
+func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
+	return genericReadFrom(c, r)
 }
 
-func newTCPConn(fd *netFD) *TCPConn {
-	return &TCPConn{conn{fd}}
-}
-
-// ReadFrom implements the io.ReaderFrom ReadFrom method.
-func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
-	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.
-// Most callers should just use Close.
-func (c *TCPConn) CloseRead() error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	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}
+func dialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+	if testHookDialTCP != nil {
+		return testHookDialTCP(ctx, net, laddr, raddr)
 	}
-	return err
-}
-
-// CloseWrite shuts down the writing side of the TCP connection.
-// Most callers should just use Close.
-func (c *TCPConn) CloseWrite() error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	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
-// has data waiting to be sent or to be acknowledged.
-//
-// If sec < 0 (the default), the operating system finishes sending the
-// data in the background.
-//
-// If sec == 0, the operating system discards any unsent or
-// unacknowledged data.
-//
-// If sec > 0, the data is sent in the background as with sec < 0. On
-// some operating systems after sec seconds have elapsed any remaining
-// unsent data may be discarded.
-func (c *TCPConn) SetLinger(sec int) error {
-	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
-// keepalive messages on the connection.
-func (c *TCPConn) SetKeepAlive(keepalive bool) error {
-	if !c.ok() {
-		return syscall.EPLAN9
-	}
-	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.
-func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
-	if !c.ok() {
-		return syscall.EPLAN9
-	}
-	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
-// packet transmission in hopes of sending fewer packets (Nagle's
-// 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 &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,
-// which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is
-// used as the local address for the connection.
-func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
-	return dialTCP(net, laddr, raddr, noDeadline, noCancel)
+	return doDialTCP(ctx, net, laddr, raddr)
 }
 
-func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
-	if !deadline.IsZero() {
-		panic("net.dialTCP: deadline not implemented on Plan 9")
-	}
-	// TODO(bradfitz,0intro): also use the cancel channel.
+func doDialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, UnknownNetworkError(net)
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+		return nil, errMissingAddress
 	}
-	fd, err := dialPlan9(net, laddr, raddr)
+	fd, err := dialPlan9(ctx, net, laddr, raddr)
 	if err != nil {
 		return nil, err
 	}
 	return newTCPConn(fd), nil
 }
 
-// TCPListener is a TCP network listener.  Clients should typically
-// use variables of type Listener instead of assuming TCP.
-type TCPListener struct {
-	fd *netFD
-}
+func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil && ln.fd.ctl != nil }
 
-// AcceptTCP accepts the next incoming call and returns the new
-// connection.
-func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
-	if l == nil || l.fd == nil || l.fd.ctl == nil {
-		return nil, syscall.EINVAL
-	}
-	fd, err := l.fd.acceptPlan9()
+func (ln *TCPListener) accept() (*TCPConn, error) {
+	fd, err := ln.fd.acceptPlan9()
 	if err != nil {
 		return nil, err
 	}
 	return newTCPConn(fd), nil
 }
 
-// Accept implements the Accept method in the Listener interface; it
-// waits for the next call and returns a generic Conn.
-func (l *TCPListener) Accept() (Conn, error) {
-	if l == nil || l.fd == nil || l.fd.ctl == nil {
-		return nil, syscall.EINVAL
+func (ln *TCPListener) close() error {
+	if _, err := ln.fd.ctl.WriteString("hangup"); err != nil {
+		ln.fd.ctl.Close()
+		return err
 	}
-	c, err := l.AcceptTCP()
-	if err != nil {
-		return nil, err
-	}
-	return c, nil
-}
-
-// Close stops listening on the TCP address.
-// Already Accepted connections are not closed.
-func (l *TCPListener) Close() error {
-	if l == nil || l.fd == nil || l.fd.ctl == nil {
-		return syscall.EINVAL
-	}
-	if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
-		l.fd.ctl.Close()
-		return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	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.
-// A zero time value disables the deadline.
-func (l *TCPListener) SetDeadline(t time.Time) error {
-	if l == nil || l.fd == nil || l.fd.ctl == nil {
-		return syscall.EINVAL
-	}
-	if err := l.fd.setDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+	if err := ln.fd.ctl.Close(); err != nil {
+		return err
 	}
 	return nil
 }
 
-// File returns a copy of the underlying os.File, set to blocking
-// mode.  It is the caller's responsibility to close f when finished.
-// Closing l does not affect f, and closing f does not affect l.
-//
-// 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) {
-	f, err = l.dup()
+func (ln *TCPListener) file() (*os.File, error) {
+	f, err := ln.dup()
 	if err != nil {
-		err = &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+		return nil, err
 	}
-	return
+	return f, nil
 }
 
-// ListenTCP announces on the TCP address laddr and returns a TCP
-// listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
-// port of 0, ListenTCP will choose an available port.  The caller can
-// use the Addr method of TCPListener to retrieve the chosen address.
-func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
-	}
-	if laddr == nil {
-		laddr = &TCPAddr{}
-	}
-	fd, err := listenPlan9(net, laddr)
+func listenTCP(ctx context.Context, network string, laddr *TCPAddr) (*TCPListener, error) {
+	fd, err := listenPlan9(ctx, network, laddr)
 	if err != nil {
 		return nil, err
 	}
diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go
index 0e12d54..c9a8b68 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,10 +7,10 @@
 package net
 
 import (
+	"context"
 	"io"
 	"os"
 	"syscall"
-	"time"
 )
 
 func sockaddrToTCP(sa syscall.Sockaddr) Addr {
@@ -40,151 +40,38 @@ func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	return ipToSockaddr(family, a.IP, a.Port, a.Zone)
 }
 
-// TCPConn is an implementation of the Conn interface for TCP network
-// connections.
-type TCPConn struct {
-	conn
-}
-
-func newTCPConn(fd *netFD) *TCPConn {
-	c := &TCPConn{conn{fd}}
-	setNoDelay(c.fd, true)
-	return c
-}
-
-// ReadFrom implements the io.ReaderFrom ReadFrom method.
-func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
+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
 	}
-	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.
-// Most callers should just use Close.
-func (c *TCPConn) CloseRead() error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	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.
-// Most callers should just use Close.
-func (c *TCPConn) CloseWrite() error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	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
+	return genericReadFrom(c, r)
 }
 
-// SetLinger sets the behavior of Close on a connection which still
-// has data waiting to be sent or to be acknowledged.
-//
-// If sec < 0 (the default), the operating system finishes sending the
-// data in the background.
-//
-// If sec == 0, the operating system discards any unsent or
-// unacknowledged data.
-//
-// If sec > 0, the data is sent in the background as with sec < 0. On
-// some operating systems after sec seconds have elapsed any remaining
-// unsent data may be discarded.
-func (c *TCPConn) SetLinger(sec int) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	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}
+func dialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+	if testHookDialTCP != nil {
+		return testHookDialTCP(ctx, net, laddr, raddr)
 	}
-	return nil
+	return doDialTCP(ctx, net, laddr, raddr)
 }
 
-// SetKeepAlive sets whether the operating system should send
-// keepalive messages on the connection.
-func (c *TCPConn) SetKeepAlive(keepalive bool) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	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.
-func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	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
-// packet transmission in hopes of sending fewer packets (Nagle's
-// 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 {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	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,
-// which must be "tcp", "tcp4", or "tcp6".  If laddr is not nil, it is
-// used as the local address for the connection.
-func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-	default:
-		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, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
-	}
-	return dialTCP(net, laddr, raddr, noDeadline, noCancel)
-}
-
-func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-chan struct{}) (*TCPConn, error) {
-	fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", cancel)
+func doDialTCP(ctx context.Context, net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
+	fd, err := internetSocket(ctx, net, laddr, raddr, syscall.SOCK_STREAM, 0, "dial")
 
 	// TCP has a rarely used mechanism called a 'simultaneous connection' in
 	// which Dial("tcp", addr1, addr2) run on the machine at addr1 can
 	// connect to a simultaneous Dial("tcp", addr2, addr1) run on the machine
-	// at addr2, without either machine executing Listen.  If laddr == nil,
+	// at addr2, without either machine executing Listen. If laddr == nil,
 	// it means we want the kernel to pick an appropriate originating local
-	// address.  Some Linux kernels cycle blindly through a fixed range of
-	// local ports, regardless of destination port.  If a kernel happens to
+	// address. Some Linux kernels cycle blindly through a fixed range of
+	// local ports, regardless of destination port. If a kernel happens to
 	// pick local port 50001 as the source for a Dial("tcp", "", "localhost:50001"),
 	// then the Dial will succeed, having simultaneously connected to itself.
 	// This can only happen when we are letting the kernel pick a port (laddr == nil)
 	// and when there is no listener for the destination address.
-	// It's hard to argue this is anything other than a kernel bug.  If we
+	// It's hard to argue this is anything other than a kernel bug. If we
 	// 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:
+	// close the fd and try again. If it happens twice more, we relent and
+	// use the result. See also:
 	//	https://golang.org/issue/2690
 	//	http://stackoverflow.com/questions/4949858/
 	//
@@ -198,11 +85,11 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time, cancel <-cha
 		if err == nil {
 			fd.Close()
 		}
-		fd, err = internetSocket(net, laddr, raddr, deadline, syscall.SOCK_STREAM, 0, "dial", cancel)
+		fd, err = internetSocket(ctx, net, laddr, raddr, syscall.SOCK_STREAM, 0, "dial")
 	}
 
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+		return nil, err
 	}
 	return newTCPConn(fd), nil
 }
@@ -239,96 +126,32 @@ func spuriousENOTAVAIL(err error) bool {
 	return err == syscall.EADDRNOTAVAIL
 }
 
-// TCPListener is a TCP network listener.  Clients should typically
-// use variables of type Listener instead of assuming TCP.
-type TCPListener struct {
-	fd *netFD
-}
-
-// AcceptTCP accepts the next incoming call and returns the new
-// connection.
-func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
-	if l == nil || l.fd == nil {
-		return nil, syscall.EINVAL
-	}
-	fd, err := l.fd.accept()
-	if err != nil {
-		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	return newTCPConn(fd), nil
-}
+func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil }
 
-// Accept implements the Accept method in the Listener interface; it
-// waits for the next call and returns a generic Conn.
-func (l *TCPListener) Accept() (Conn, error) {
-	c, err := l.AcceptTCP()
+func (ln *TCPListener) accept() (*TCPConn, error) {
+	fd, err := ln.fd.accept()
 	if err != nil {
 		return nil, err
 	}
-	return c, nil
-}
-
-// Close stops listening on the TCP address.
-// Already Accepted connections are not closed.
-func (l *TCPListener) Close() error {
-	if l == nil || l.fd == nil {
-		return syscall.EINVAL
-	}
-	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
+	return newTCPConn(fd), nil
 }
 
-// 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.
-// A zero time value disables the deadline.
-func (l *TCPListener) SetDeadline(t time.Time) error {
-	if l == nil || l.fd == nil {
-		return syscall.EINVAL
-	}
-	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
+func (ln *TCPListener) close() error {
+	return ln.fd.Close()
 }
 
-// File returns a copy of the underlying os.File, set to blocking
-// mode.  It is the caller's responsibility to close f when finished.
-// Closing l does not affect f, and closing f does not affect l.
-//
-// 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) {
-	f, err = l.fd.dup()
+func (ln *TCPListener) file() (*os.File, error) {
+	f, err := ln.fd.dup()
 	if err != nil {
-		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+		return nil, err
 	}
-	return
+	return f, nil
 }
 
-// ListenTCP announces on the TCP address laddr and returns a TCP
-// listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
-// port of 0, ListenTCP will choose an available port.  The caller can
-// use the Addr method of TCPListener to retrieve the chosen address.
-func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-	default:
-		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", noCancel)
+func listenTCP(ctx context.Context, network string, laddr *TCPAddr) (*TCPListener, error) {
+	fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_STREAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, err
 	}
 	return &TCPListener{fd}, nil
 }
diff --git a/src/net/tcpsock_test.go b/src/net/tcpsock_test.go
new file mode 100644
index 0000000..4af47fc
--- /dev/null
+++ b/src/net/tcpsock_test.go
@@ -0,0 +1,635 @@
+// 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 net
+
+import (
+	"internal/testenv"
+	"io"
+	"reflect"
+	"runtime"
+	"sync"
+	"testing"
+	"time"
+)
+
+func BenchmarkTCP4OneShot(b *testing.B) {
+	benchmarkTCP(b, false, false, "127.0.0.1:0")
+}
+
+func BenchmarkTCP4OneShotTimeout(b *testing.B) {
+	benchmarkTCP(b, false, true, "127.0.0.1:0")
+}
+
+func BenchmarkTCP4Persistent(b *testing.B) {
+	benchmarkTCP(b, true, false, "127.0.0.1:0")
+}
+
+func BenchmarkTCP4PersistentTimeout(b *testing.B) {
+	benchmarkTCP(b, true, true, "127.0.0.1:0")
+}
+
+func BenchmarkTCP6OneShot(b *testing.B) {
+	if !supportsIPv6 {
+		b.Skip("ipv6 is not supported")
+	}
+	benchmarkTCP(b, false, false, "[::1]:0")
+}
+
+func BenchmarkTCP6OneShotTimeout(b *testing.B) {
+	if !supportsIPv6 {
+		b.Skip("ipv6 is not supported")
+	}
+	benchmarkTCP(b, false, true, "[::1]:0")
+}
+
+func BenchmarkTCP6Persistent(b *testing.B) {
+	if !supportsIPv6 {
+		b.Skip("ipv6 is not supported")
+	}
+	benchmarkTCP(b, true, false, "[::1]:0")
+}
+
+func BenchmarkTCP6PersistentTimeout(b *testing.B) {
+	if !supportsIPv6 {
+		b.Skip("ipv6 is not supported")
+	}
+	benchmarkTCP(b, true, true, "[::1]:0")
+}
+
+func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
+	const msgLen = 512
+	conns := b.N
+	numConcurrent := runtime.GOMAXPROCS(-1) * 2
+	msgs := 1
+	if persistent {
+		conns = numConcurrent
+		msgs = b.N / conns
+		if msgs == 0 {
+			msgs = 1
+		}
+		if conns > b.N {
+			conns = b.N
+		}
+	}
+	sendMsg := func(c Conn, buf []byte) bool {
+		n, err := c.Write(buf)
+		if n != len(buf) || err != nil {
+			b.Log(err)
+			return false
+		}
+		return true
+	}
+	recvMsg := func(c Conn, buf []byte) bool {
+		for read := 0; read != len(buf); {
+			n, err := c.Read(buf)
+			read += n
+			if err != nil {
+				b.Log(err)
+				return false
+			}
+		}
+		return true
+	}
+	ln, err := Listen("tcp", laddr)
+	if err != nil {
+		b.Fatal(err)
+	}
+	defer ln.Close()
+	serverSem := make(chan bool, numConcurrent)
+	// Acceptor.
+	go func() {
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				break
+			}
+			serverSem <- true
+			// Server connection.
+			go func(c Conn) {
+				defer func() {
+					c.Close()
+					<-serverSem
+				}()
+				if timeout {
+					c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
+				}
+				var buf [msgLen]byte
+				for m := 0; m < msgs; m++ {
+					if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
+						break
+					}
+				}
+			}(c)
+		}
+	}()
+	clientSem := make(chan bool, numConcurrent)
+	for i := 0; i < conns; i++ {
+		clientSem <- true
+		// Client connection.
+		go func() {
+			defer func() {
+				<-clientSem
+			}()
+			c, err := Dial("tcp", ln.Addr().String())
+			if err != nil {
+				b.Log(err)
+				return
+			}
+			defer c.Close()
+			if timeout {
+				c.SetDeadline(time.Now().Add(time.Hour)) // Not intended to fire.
+			}
+			var buf [msgLen]byte
+			for m := 0; m < msgs; m++ {
+				if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
+					break
+				}
+			}
+		}()
+	}
+	for i := 0; i < numConcurrent; i++ {
+		clientSem <- true
+		serverSem <- true
+	}
+}
+
+func BenchmarkTCP4ConcurrentReadWrite(b *testing.B) {
+	benchmarkTCPConcurrentReadWrite(b, "127.0.0.1:0")
+}
+
+func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
+	if !supportsIPv6 {
+		b.Skip("ipv6 is not supported")
+	}
+	benchmarkTCPConcurrentReadWrite(b, "[::1]:0")
+}
+
+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.
+	// 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([]Conn, P)
+	servers := make([]Conn, P)
+	ln, err := Listen("tcp", laddr)
+	if err != nil {
+		b.Fatal(err)
+	}
+	defer ln.Close()
+	done := make(chan bool)
+	go func() {
+		for p := 0; p < P; p++ {
+			s, err := ln.Accept()
+			if err != nil {
+				b.Error(err)
+				return
+			}
+			servers[p] = s
+		}
+		done <- true
+	}()
+	for p := 0; p < P; p++ {
+		c, err := Dial("tcp", ln.Addr().String())
+		if err != nil {
+			b.Fatal(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 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
+				_, err := c.Write(buf[:])
+				if err != nil {
+					b.Error(err)
+					return
+				}
+			}
+		}(clients[p])
+
+		// Pipe between server reader and server writer.
+		pipe := make(chan byte, 128)
+
+		// Server reader.
+		go func(s Conn) {
+			defer wg.Done()
+			var buf [1]byte
+			for i := 0; i < N; i++ {
+				_, err := s.Read(buf[:])
+				if err != nil {
+					b.Error(err)
+					return
+				}
+				pipe <- buf[0]
+			}
+		}(servers[p])
+
+		// Server writer.
+		go func(s 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
+				_, err := s.Write(buf[:])
+				if err != nil {
+					b.Error(err)
+					return
+				}
+			}
+			s.Close()
+		}(servers[p])
+
+		// Client reader.
+		go func(c Conn) {
+			defer wg.Done()
+			var buf [1]byte
+			for i := 0; i < N; i++ {
+				_, err := c.Read(buf[:])
+				if err != nil {
+					b.Error(err)
+					return
+				}
+			}
+			c.Close()
+		}(clients[p])
+	}
+	wg.Wait()
+}
+
+type resolveTCPAddrTest struct {
+	network       string
+	litAddrOrName string
+	addr          *TCPAddr
+	err           error
+}
+
+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]: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},
+
+	{"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
+	{"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
+
+	{"tcp", ":12345", &TCPAddr{Port: 12345}, nil},
+
+	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
+}
+
+func TestResolveTCPAddr(t *testing.T) {
+	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.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 := 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)
+		}
+	}
+}
+
+var tcpListenerNameTests = []struct {
+	net   string
+	laddr *TCPAddr
+}{
+	{"tcp4", &TCPAddr{IP: IPv4(127, 0, 0, 1)}},
+	{"tcp4", &TCPAddr{}},
+	{"tcp4", nil},
+}
+
+func TestTCPListenerName(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	for _, tt := range tcpListenerNameTests {
+		ln, err := ListenTCP(tt.net, tt.laddr)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ln.Close()
+		la := ln.Addr()
+		if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
+			t.Fatalf("got %v; expected a proper address with non-zero port number", la)
+		}
+	}
+}
+
+func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	if !supportsIPv6 {
+		t.Skip("IPv6 is not supported")
+	}
+
+	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.Log(err)
+			continue
+		}
+		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)
+		}
+
+		c, err := Dial(tt.network, ls.Listener.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer c.Close()
+		if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
+			t.Fatalf("got %v; expected a proper address with zone identifier", la)
+		}
+		if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
+			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
+		}
+
+		if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
+			t.Fatal(err)
+		}
+		b := make([]byte, 32)
+		if _, err := c.Read(b); err != nil {
+			t.Fatal(err)
+		}
+
+		for err := range ch {
+			t.Errorf("#%d: %v", i, err)
+		}
+	}
+}
+
+func TestTCPConcurrentAccept(t *testing.T) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+	ln, err := Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatal(err)
+	}
+	const N = 10
+	var wg sync.WaitGroup
+	wg.Add(N)
+	for i := 0; i < N; i++ {
+		go func() {
+			for {
+				c, err := ln.Accept()
+				if err != nil {
+					break
+				}
+				c.Close()
+			}
+			wg.Done()
+		}()
+	}
+	attempts := 10 * N
+	fails := 0
+	d := &Dialer{Timeout: 200 * time.Millisecond}
+	for i := 0; i < attempts; i++ {
+		c, err := d.Dial("tcp", ln.Addr().String())
+		if err != nil {
+			fails++
+		} else {
+			c.Close()
+		}
+	}
+	ln.Close()
+	wg.Wait()
+	if fails > attempts/9 { // see issues 7400 and 7541
+		t.Fatalf("too many Dial failed: %v", fails)
+	}
+	if fails > 0 {
+		t.Logf("# of failed Dials: %v", fails)
+	}
+}
+
+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.Fatal(err)
+	}
+	defer ln.Close()
+	var server Conn
+	errc := make(chan error)
+	go func() {
+		var err error
+		server, err = ln.Accept()
+		errc <- err
+	}()
+	client, err := Dial("tcp", ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer client.Close()
+	if err := <-errc; err != nil {
+		t.Fatal(err)
+	}
+	defer server.Close()
+	var buf [128]byte
+	allocs := testing.AllocsPerRun(1000, func() {
+		_, err := server.Write(buf[:])
+		if err != nil {
+			t.Fatal(err)
+		}
+		_, err = io.ReadFull(client, buf[:])
+		if err != nil {
+			t.Fatal(err)
+		}
+	})
+	if allocs > 0 {
+		t.Fatalf("got %v; want 0", allocs)
+	}
+}
+
+func TestTCPStress(t *testing.T) {
+	const conns = 2
+	const msgLen = 512
+	msgs := int(1e4)
+	if testing.Short() {
+		msgs = 1e2
+	}
+
+	sendMsg := func(c Conn, buf []byte) bool {
+		n, err := c.Write(buf)
+		if n != len(buf) || err != nil {
+			t.Log(err)
+			return false
+		}
+		return true
+	}
+	recvMsg := func(c Conn, buf []byte) bool {
+		for read := 0; read != len(buf); {
+			n, err := c.Read(buf)
+			read += n
+			if err != nil {
+				t.Log(err)
+				return false
+			}
+		}
+		return true
+	}
+
+	ln, err := Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatal(err)
+	}
+	done := make(chan bool)
+	// Acceptor.
+	go func() {
+		defer func() {
+			done <- true
+		}()
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				break
+			}
+			// Server connection.
+			go func(c Conn) {
+				defer c.Close()
+				var buf [msgLen]byte
+				for m := 0; m < msgs; m++ {
+					if !recvMsg(c, buf[:]) || !sendMsg(c, buf[:]) {
+						break
+					}
+				}
+			}(c)
+		}
+	}()
+	for i := 0; i < conns; i++ {
+		// Client connection.
+		go func() {
+			defer func() {
+				done <- true
+			}()
+			c, err := Dial("tcp", ln.Addr().String())
+			if err != nil {
+				t.Log(err)
+				return
+			}
+			defer c.Close()
+			var buf [msgLen]byte
+			for m := 0; m < msgs; m++ {
+				if !sendMsg(c, buf[:]) || !recvMsg(c, buf[:]) {
+					break
+				}
+			}
+		}()
+	}
+	for i := 0; i < conns; i++ {
+		<-done
+	}
+	ln.Close()
+	<-done
+}
+
+func TestTCPSelfConnect(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		// TODO(brainman): do not know why it hangs.
+		t.Skip("known-broken test on windows")
+	}
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	var d Dialer
+	c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		ln.Close()
+		t.Fatal(err)
+	}
+	network := c.LocalAddr().Network()
+	laddr := *c.LocalAddr().(*TCPAddr)
+	c.Close()
+	ln.Close()
+
+	// Try to connect to that address repeatedly.
+	n := 100000
+	if testing.Short() {
+		n = 1000
+	}
+	switch runtime.GOOS {
+	case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
+		// Non-Linux systems take a long time to figure
+		// out that there is nothing listening on localhost.
+		n = 100
+	}
+	for i := 0; i < n; i++ {
+		d.Timeout = time.Millisecond
+		c, err := d.Dial(network, laddr.String())
+		if err == nil {
+			addr := c.LocalAddr().(*TCPAddr)
+			if addr.Port == laddr.Port || addr.IP.Equal(laddr.IP) {
+				t.Errorf("Dial %v should fail", addr)
+			} else {
+				t.Logf("Dial %v succeeded - possibly racing with other listener", addr)
+			}
+			c.Close()
+		}
+	}
+}
diff --git a/src/net/tcpsock_unix_test.go b/src/net/tcpsock_unix_test.go
new file mode 100644
index 0000000..c07f7d7
--- /dev/null
+++ b/src/net/tcpsock_unix_test.go
@@ -0,0 +1,79 @@
+// Copyright 2016 The Go 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
+
+package net
+
+import (
+	"runtime"
+	"sync"
+	"syscall"
+	"testing"
+	"time"
+)
+
+// See golang.org/issue/14548.
+func TestTCPSupriousConnSetupCompletion(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func(ln Listener) {
+		defer wg.Done()
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				return
+			}
+			wg.Add(1)
+			go func(c Conn) {
+				var b [1]byte
+				c.Read(b[:])
+				c.Close()
+				wg.Done()
+			}(c)
+		}
+	}(ln)
+
+	attempts := int(1e4) // larger is better
+	wg.Add(attempts)
+	throttle := make(chan struct{}, runtime.GOMAXPROCS(-1)*2)
+	for i := 0; i < attempts; i++ {
+		throttle <- struct{}{}
+		go func(i int) {
+			defer func() {
+				<-throttle
+				wg.Done()
+			}()
+			d := Dialer{Timeout: 50 * time.Millisecond}
+			c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Errorf("#%d: %v", i, err)
+				}
+				return
+			}
+			var b [1]byte
+			if _, err := c.Write(b[:]); err != nil {
+				if perr := parseWriteError(err); perr != nil {
+					t.Errorf("#%d: %v", i, err)
+				}
+				if samePlatformError(err, syscall.ENOTCONN) {
+					t.Errorf("#%d: %v", i, err)
+				}
+			}
+			c.Close()
+		}(i)
+	}
+
+	ln.Close()
+	wg.Wait()
+}
diff --git a/src/net/tcpsockopt_darwin.go b/src/net/tcpsockopt_darwin.go
index 1f16090..0d1310e 100644
--- a/src/net/tcpsockopt_darwin.go
+++ b/src/net/tcpsockopt_darwin.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/tcpsockopt_dragonfly.go b/src/net/tcpsockopt_dragonfly.go
index 0aa2132..7cc716b 100644
--- a/src/net/tcpsockopt_dragonfly.go
+++ b/src/net/tcpsockopt_dragonfly.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/tcpsockopt_openbsd.go b/src/net/tcpsockopt_openbsd.go
index 041e178..10e1bef 100644
--- a/src/net/tcpsockopt_openbsd.go
+++ b/src/net/tcpsockopt_openbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/tcpsockopt_plan9.go b/src/net/tcpsockopt_plan9.go
index 157282a..fb56871 100644
--- a/src/net/tcpsockopt_plan9.go
+++ b/src/net/tcpsockopt_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,9 +7,14 @@
 package net
 
 import (
+	"syscall"
 	"time"
 )
 
+func setNoDelay(fd *netFD, noDelay bool) error {
+	return syscall.EPLAN9
+}
+
 // Set keep alive period.
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
 	cmd := "keepalive " + itoa(int(d/time.Millisecond))
diff --git a/src/net/tcpsockopt_posix.go b/src/net/tcpsockopt_posix.go
index 0abf3f9..805b56b 100644
--- a/src/net/tcpsockopt_posix.go
+++ b/src/net/tcpsockopt_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/tcpsockopt_solaris.go b/src/net/tcpsockopt_solaris.go
index 31f5df0..76285e5 100644
--- a/src/net/tcpsockopt_solaris.go
+++ b/src/net/tcpsockopt_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/net/tcpsockopt_stub.go b/src/net/tcpsockopt_stub.go
index b413a76..19c83e6 100644
--- a/src/net/tcpsockopt_stub.go
+++ b/src/net/tcpsockopt_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/tcpsockopt_unix.go b/src/net/tcpsockopt_unix.go
index c8970d1..8d44fb2 100644
--- a/src/net/tcpsockopt_unix.go
+++ b/src/net/tcpsockopt_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/tcpsockopt_windows.go b/src/net/tcpsockopt_windows.go
index ae2d7c8..45a4dca 100644
--- a/src/net/tcpsockopt_windows.go
+++ b/src/net/tcpsockopt_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/net/testdata/Mark.Twain-Tom.Sawyer.txt b/src/net/testdata/Mark.Twain-Tom.Sawyer.txt
new file mode 100644
index 0000000..c9106fd
--- /dev/null
+++ b/src/net/testdata/Mark.Twain-Tom.Sawyer.txt
@@ -0,0 +1,8465 @@
+Produced by David Widger. The previous edition was updated by Jose
+Menendez.
+
+
+
+
+
+                   THE ADVENTURES OF TOM SAWYER
+                                BY
+                            MARK TWAIN
+                     (Samuel Langhorne Clemens)
+
+
+
+
+                           P R E F A C E
+
+MOST of the adventures recorded in this book really occurred; one or
+two were experiences of my own, the rest those of boys who were
+schoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but
+not from an individual--he is a combination of the characteristics of
+three boys whom I knew, and therefore belongs to the composite order of
+architecture.
+
+The odd superstitions touched upon were all prevalent among children
+and slaves in the West at the period of this story--that is to say,
+thirty or forty years ago.
+
+Although my book is intended mainly for the entertainment of boys and
+girls, I hope it will not be shunned by men and women on that account,
+for part of my plan has been to try to pleasantly remind adults of what
+they once were themselves, and of how they felt and thought and talked,
+and what queer enterprises they sometimes engaged in.
+
+                                                            THE AUTHOR.
+
+HARTFORD, 1876.
+
+
+
+                          T O M   S A W Y E R
+
+
+
+CHAPTER I
+
+"TOM!"
+
+No answer.
+
+"TOM!"
+
+No answer.
+
+"What's gone with that boy,  I wonder? You TOM!"
+
+No answer.
+
+The old lady pulled her spectacles down and looked over them about the
+room; then she put them up and looked out under them. She seldom or
+never looked THROUGH them for so small a thing as a boy; they were her
+state pair, the pride of her heart, and were built for "style," not
+service--she could have seen through a pair of stove-lids just as well.
+She looked perplexed for a moment, and then said, not fiercely, but
+still loud enough for the furniture to hear:
+
+"Well, I lay if I get hold of you I'll--"
+
+She did not finish, for by this time she was bending down and punching
+under the bed with the broom, and so she needed breath to punctuate the
+punches with. She resurrected nothing but the cat.
+
+"I never did see the beat of that boy!"
+
+She went to the open door and stood in it and looked out among the
+tomato vines and "jimpson" weeds that constituted the garden. No Tom.
+So she lifted up her voice at an angle calculated for distance and
+shouted:
+
+"Y-o-u-u TOM!"
+
+There was a slight noise behind her and she turned just in time to
+seize a small boy by the slack of his roundabout and arrest his flight.
+
+"There! I might 'a' thought of that closet. What you been doing in
+there?"
+
+"Nothing."
+
+"Nothing! Look at your hands. And look at your mouth. What IS that
+truck?"
+
+"I don't know, aunt."
+
+"Well, I know. It's jam--that's what it is. Forty times I've said if
+you didn't let that jam alone I'd skin you. Hand me that switch."
+
+The switch hovered in the air--the peril was desperate--
+
+"My! Look behind you, aunt!"
+
+The old lady whirled round, and snatched her skirts out of danger. The
+lad fled on the instant, scrambled up the high board-fence, and
+disappeared over it.
+
+His aunt Polly stood surprised a moment, and then broke into a gentle
+laugh.
+
+"Hang the boy, can't I never learn anything? Ain't he played me tricks
+enough like that for me to be looking out for him by this time? But old
+fools is the biggest fools there is. Can't learn an old dog new tricks,
+as the saying is. But my goodness, he never plays them alike, two days,
+and how is a body to know what's coming? He 'pears to know just how
+long he can torment me before I get my dander up, and he knows if he
+can make out to put me off for a minute or make me laugh, it's all down
+again and I can't hit him a lick. I ain't doing my duty by that boy,
+and that's the Lord's truth, goodness knows. Spare the rod and spile
+the child, as the Good Book says. I'm a laying up sin and suffering for
+us both, I know. He's full of the Old Scratch, but laws-a-me! he's my
+own dead sister's boy, poor thing, and I ain't got the heart to lash
+him, somehow. Every time I let him off, my conscience does hurt me so,
+and every time I hit him my old heart most breaks. Well-a-well, man
+that is born of woman is of few days and full of trouble, as the
+Scripture says, and I reckon it's so. He'll play hookey this evening, *
+and [* Southwestern for "afternoon"] I'll just be obleeged to make him
+work, to-morrow, to punish him. It's mighty hard to make him work
+Saturdays, when all the boys is having holiday, but he hates work more
+than he hates anything else, and I've GOT to do some of my duty by him,
+or I'll be the ruination of the child."
+
+Tom did play hookey, and he had a very good time. He got back home
+barely in season to help Jim, the small colored boy, saw next-day's
+wood and split the kindlings before supper--at least he was there in
+time to tell his adventures to Jim while Jim did three-fourths of the
+work. Tom's younger brother (or rather half-brother) Sid was already
+through with his part of the work (picking up chips), for he was a
+quiet boy, and had no adventurous, troublesome ways.
+
+While Tom was eating his supper, and stealing sugar as opportunity
+offered, Aunt Polly asked him questions that were full of guile, and
+very deep--for she wanted to trap him into damaging revealments. Like
+many other simple-hearted souls, it was her pet vanity to believe she
+was endowed with a talent for dark and mysterious diplomacy, and she
+loved to contemplate her most transparent devices as marvels of low
+cunning. Said she:
+
+"Tom, it was middling warm in school, warn't it?"
+
+"Yes'm."
+
+"Powerful warm, warn't it?"
+
+"Yes'm."
+
+"Didn't you want to go in a-swimming, Tom?"
+
+A bit of a scare shot through Tom--a touch of uncomfortable suspicion.
+He searched Aunt Polly's face, but it told him nothing. So he said:
+
+"No'm--well, not very much."
+
+The old lady reached out her hand and felt Tom's shirt, and said:
+
+"But you ain't too warm now, though." And it flattered her to reflect
+that she had discovered that the shirt was dry without anybody knowing
+that that was what she had in her mind. But in spite of her, Tom knew
+where the wind lay, now. So he forestalled what might be the next move:
+
+"Some of us pumped on our heads--mine's damp yet. See?"
+
+Aunt Polly was vexed to think she had overlooked that bit of
+circumstantial evidence, and missed a trick. Then she had a new
+inspiration:
+
+"Tom, you didn't have to undo your shirt collar where I sewed it, to
+pump on your head, did you? Unbutton your jacket!"
+
+The trouble vanished out of Tom's face. He opened his jacket. His
+shirt collar was securely sewed.
+
+"Bother! Well, go 'long with you. I'd made sure you'd played hookey
+and been a-swimming. But I forgive ye, Tom. I reckon you're a kind of a
+singed cat, as the saying is--better'n you look. THIS time."
+
+She was half sorry her sagacity had miscarried, and half glad that Tom
+had stumbled into obedient conduct for once.
+
+But Sidney said:
+
+"Well, now, if I didn't think you sewed his collar with white thread,
+but it's black."
+
+"Why, I did sew it with white! Tom!"
+
+But Tom did not wait for the rest. As he went out at the door he said:
+
+"Siddy, I'll lick you for that."
+
+In a safe place Tom examined two large needles which were thrust into
+the lapels of his jacket, and had thread bound about them--one needle
+carried white thread and the other black. He said:
+
+"She'd never noticed if it hadn't been for Sid. Confound it! sometimes
+she sews it with white, and sometimes she sews it with black. I wish to
+geeminy she'd stick to one or t'other--I can't keep the run of 'em. But
+I bet you I'll lam Sid for that. I'll learn him!"
+
+He was not the Model Boy of the village. He knew the model boy very
+well though--and loathed him.
+
+Within two minutes, or even less, he had forgotten all his troubles.
+Not because his troubles were one whit less heavy and bitter to him
+than a man's are to a man, but because a new and powerful interest bore
+them down and drove them out of his mind for the time--just as men's
+misfortunes are forgotten in the excitement of new enterprises. This
+new interest was a valued novelty in whistling, which he had just
+acquired from a negro, and he was suffering to practise it undisturbed.
+It consisted in a peculiar bird-like turn, a sort of liquid warble,
+produced by touching the tongue to the roof of the mouth at short
+intervals in the midst of the music--the reader probably remembers how
+to do it, if he has ever been a boy. Diligence and attention soon gave
+him the knack of it, and he strode down the street with his mouth full
+of harmony and his soul full of gratitude. He felt much as an
+astronomer feels who has discovered a new planet--no doubt, as far as
+strong, deep, unalloyed pleasure is concerned, the advantage was with
+the boy, not the astronomer.
+
+The summer evenings were long. It was not dark, yet. Presently Tom
+checked his whistle. A stranger was before him--a boy a shade larger
+than himself. A new-comer of any age or either sex was an impressive
+curiosity in the poor little shabby village of St. Petersburg. This boy
+was well dressed, too--well dressed on a week-day. This was simply
+astounding. His cap was a dainty thing, his close-buttoned blue cloth
+roundabout was new and natty, and so were his pantaloons. He had shoes
+on--and it was only Friday. He even wore a necktie, a bright bit of
+ribbon. He had a citified air about him that ate into Tom's vitals. The
+more Tom stared at the splendid marvel, the higher he turned up his
+nose at his finery and the shabbier and shabbier his own outfit seemed
+to him to grow. Neither boy spoke. If one moved, the other moved--but
+only sidewise, in a circle; they kept face to face and eye to eye all
+the time. Finally Tom said:
+
+"I can lick you!"
+
+"I'd like to see you try it."
+
+"Well, I can do it."
+
+"No you can't, either."
+
+"Yes I can."
+
+"No you can't."
+
+"I can."
+
+"You can't."
+
+"Can!"
+
+"Can't!"
+
+An uncomfortable pause. Then Tom said:
+
+"What's your name?"
+
+"'Tisn't any of your business, maybe."
+
+"Well I 'low I'll MAKE it my business."
+
+"Well why don't you?"
+
+"If you say much, I will."
+
+"Much--much--MUCH. There now."
+
+"Oh, you think you're mighty smart, DON'T you? I could lick you with
+one hand tied behind me, if I wanted to."
+
+"Well why don't you DO it? You SAY you can do it."
+
+"Well I WILL, if you fool with me."
+
+"Oh yes--I've seen whole families in the same fix."
+
+"Smarty! You think you're SOME, now, DON'T you? Oh, what a hat!"
+
+"You can lump that hat if you don't like it. I dare you to knock it
+off--and anybody that'll take a dare will suck eggs."
+
+"You're a liar!"
+
+"You're another."
+
+"You're a fighting liar and dasn't take it up."
+
+"Aw--take a walk!"
+
+"Say--if you give me much more of your sass I'll take and bounce a
+rock off'n your head."
+
+"Oh, of COURSE you will."
+
+"Well I WILL."
+
+"Well why don't you DO it then? What do you keep SAYING you will for?
+Why don't you DO it? It's because you're afraid."
+
+"I AIN'T afraid."
+
+"You are."
+
+"I ain't."
+
+"You are."
+
+Another pause, and more eying and sidling around each other. Presently
+they were shoulder to shoulder. Tom said:
+
+"Get away from here!"
+
+"Go away yourself!"
+
+"I won't."
+
+"I won't either."
+
+So they stood, each with a foot placed at an angle as a brace, and
+both shoving with might and main, and glowering at each other with
+hate. But neither could get an advantage. After struggling till both
+were hot and flushed, each relaxed his strain with watchful caution,
+and Tom said:
+
+"You're a coward and a pup. I'll tell my big brother on you, and he
+can thrash you with his little finger, and I'll make him do it, too."
+
+"What do I care for your big brother? I've got a brother that's bigger
+than he is--and what's more, he can throw him over that fence, too."
+[Both brothers were imaginary.]
+
+"That's a lie."
+
+"YOUR saying so don't make it so."
+
+Tom drew a line in the dust with his big toe, and said:
+
+"I dare you to step over that, and I'll lick you till you can't stand
+up. Anybody that'll take a dare will steal sheep."
+
+The new boy stepped over promptly, and said:
+
+"Now you said you'd do it, now let's see you do it."
+
+"Don't you crowd me now; you better look out."
+
+"Well, you SAID you'd do it--why don't you do it?"
+
+"By jingo! for two cents I WILL do it."
+
+The new boy took two broad coppers out of his pocket and held them out
+with derision. Tom struck them to the ground. In an instant both boys
+were rolling and tumbling in the dirt, gripped together like cats; and
+for the space of a minute they tugged and tore at each other's hair and
+clothes, punched and scratched each other's nose, and covered
+themselves with dust and glory. Presently the confusion took form, and
+through the fog of battle Tom appeared, seated astride the new boy, and
+pounding him with his fists. "Holler 'nuff!" said he.
+
+The boy only struggled to free himself. He was crying--mainly from rage.
+
+"Holler 'nuff!"--and the pounding went on.
+
+At last the stranger got out a smothered "'Nuff!" and Tom let him up
+and said:
+
+"Now that'll learn you. Better look out who you're fooling with next
+time."
+
+The new boy went off brushing the dust from his clothes, sobbing,
+snuffling, and occasionally looking back and shaking his head and
+threatening what he would do to Tom the "next time he caught him out."
+To which Tom responded with jeers, and started off in high feather, and
+as soon as his back was turned the new boy snatched up a stone, threw
+it and hit him between the shoulders and then turned tail and ran like
+an antelope. Tom chased the traitor home, and thus found out where he
+lived. He then held a position at the gate for some time, daring the
+enemy to come outside, but the enemy only made faces at him through the
+window and declined. At last the enemy's mother appeared, and called
+Tom a bad, vicious, vulgar child, and ordered him away. So he went
+away; but he said he "'lowed" to "lay" for that boy.
+
+He got home pretty late that night, and when he climbed cautiously in
+at the window, he uncovered an ambuscade, in the person of his aunt;
+and when she saw the state his clothes were in her resolution to turn
+his Saturday holiday into captivity at hard labor became adamantine in
+its firmness.
+
+
+
+CHAPTER II
+
+SATURDAY morning was come, and all the summer world was bright and
+fresh, and brimming with life. There was a song in every heart; and if
+the heart was young the music issued at the lips. There was cheer in
+every face and a spring in every step. The locust-trees were in bloom
+and the fragrance of the blossoms filled the air. Cardiff Hill, beyond
+the village and above it, was green with vegetation and it lay just far
+enough away to seem a Delectable Land, dreamy, reposeful, and inviting.
+
+Tom appeared on the sidewalk with a bucket of whitewash and a
+long-handled brush. He surveyed the fence, and all gladness left him and
+a deep melancholy settled down upon his spirit. Thirty yards of board
+fence nine feet high. Life to him seemed hollow, and existence but a
+burden. Sighing, he dipped his brush and passed it along the topmost
+plank; repeated the operation; did it again; compared the insignificant
+whitewashed streak with the far-reaching continent of unwhitewashed
+fence, and sat down on a tree-box discouraged. Jim came skipping out at
+the gate with a tin pail, and singing Buffalo Gals. Bringing water from
+the town pump had always been hateful work in Tom's eyes, before, but
+now it did not strike him so. He remembered that there was company at
+the pump. White, mulatto, and negro boys and girls were always there
+waiting their turns, resting, trading playthings, quarrelling,
+fighting, skylarking. And he remembered that although the pump was only
+a hundred and fifty yards off, Jim never got back with a bucket of
+water under an hour--and even then somebody generally had to go after
+him. Tom said:
+
+"Say, Jim, I'll fetch the water if you'll whitewash some."
+
+Jim shook his head and said:
+
+"Can't, Mars Tom. Ole missis, she tole me I got to go an' git dis
+water an' not stop foolin' roun' wid anybody. She say she spec' Mars
+Tom gwine to ax me to whitewash, an' so she tole me go 'long an' 'tend
+to my own business--she 'lowed SHE'D 'tend to de whitewashin'."
+
+"Oh, never you mind what she said, Jim. That's the way she always
+talks. Gimme the bucket--I won't be gone only a a minute. SHE won't
+ever know."
+
+"Oh, I dasn't, Mars Tom. Ole missis she'd take an' tar de head off'n
+me. 'Deed she would."
+
+"SHE! She never licks anybody--whacks 'em over the head with her
+thimble--and who cares for that, I'd like to know. She talks awful, but
+talk don't hurt--anyways it don't if she don't cry. Jim, I'll give you
+a marvel. I'll give you a white alley!"
+
+Jim began to waver.
+
+"White alley, Jim! And it's a bully taw."
+
+"My! Dat's a mighty gay marvel, I tell you! But Mars Tom I's powerful
+'fraid ole missis--"
+
+"And besides, if you will I'll show you my sore toe."
+
+Jim was only human--this attraction was too much for him. He put down
+his pail, took the white alley, and bent over the toe with absorbing
+interest while the bandage was being unwound. In another moment he was
+flying down the street with his pail and a tingling rear, Tom was
+whitewashing with vigor, and Aunt Polly was retiring from the field
+with a slipper in her hand and triumph in her eye.
+
+But Tom's energy did not last. He began to think of the fun he had
+planned for this day, and his sorrows multiplied. Soon the free boys
+would come tripping along on all sorts of delicious expeditions, and
+they would make a world of fun of him for having to work--the very
+thought of it burnt him like fire. He got out his worldly wealth and
+examined it--bits of toys, marbles, and trash; enough to buy an
+exchange of WORK, maybe, but not half enough to buy so much as half an
+hour of pure freedom. So he returned his straitened means to his
+pocket, and gave up the idea of trying to buy the boys. At this dark
+and hopeless moment an inspiration burst upon him! Nothing less than a
+great, magnificent inspiration.
+
+He took up his brush and went tranquilly to work. Ben Rogers hove in
+sight presently--the very boy, of all boys, whose ridicule he had been
+dreading. Ben's gait was the hop-skip-and-jump--proof enough that his
+heart was light and his anticipations high. He was eating an apple, and
+giving a long, melodious whoop, at intervals, followed by a deep-toned
+ding-dong-dong, ding-dong-dong, for he was personating a steamboat. As
+he drew near, he slackened speed, took the middle of the street, leaned
+far over to starboard and rounded to ponderously and with laborious
+pomp and circumstance--for he was personating the Big Missouri, and
+considered himself to be drawing nine feet of water. He was boat and
+captain and engine-bells combined, so he had to imagine himself
+standing on his own hurricane-deck giving the orders and executing them:
+
+"Stop her, sir! Ting-a-ling-ling!" The headway ran almost out, and he
+drew up slowly toward the sidewalk.
+
+"Ship up to back! Ting-a-ling-ling!" His arms straightened and
+stiffened down his sides.
+
+"Set her back on the stabboard! Ting-a-ling-ling! Chow! ch-chow-wow!
+Chow!" His right hand, meantime, describing stately circles--for it was
+representing a forty-foot wheel.
+
+"Let her go back on the labboard! Ting-a-lingling! Chow-ch-chow-chow!"
+The left hand began to describe circles.
+
+"Stop the stabboard! Ting-a-ling-ling! Stop the labboard! Come ahead
+on the stabboard! Stop her! Let your outside turn over slow!
+Ting-a-ling-ling! Chow-ow-ow! Get out that head-line! LIVELY now!
+Come--out with your spring-line--what're you about there! Take a turn
+round that stump with the bight of it! Stand by that stage, now--let her
+go! Done with the engines, sir! Ting-a-ling-ling! SH'T! S'H'T! SH'T!"
+(trying the gauge-cocks).
+
+Tom went on whitewashing--paid no attention to the steamboat. Ben
+stared a moment and then said: "Hi-YI! YOU'RE up a stump, ain't you!"
+
+No answer. Tom surveyed his last touch with the eye of an artist, then
+he gave his brush another gentle sweep and surveyed the result, as
+before. Ben ranged up alongside of him. Tom's mouth watered for the
+apple, but he stuck to his work. Ben said:
+
+"Hello, old chap, you got to work, hey?"
+
+Tom wheeled suddenly and said:
+
+"Why, it's you, Ben! I warn't noticing."
+
+"Say--I'm going in a-swimming, I am. Don't you wish you could? But of
+course you'd druther WORK--wouldn't you? Course you would!"
+
+Tom contemplated the boy a bit, and said:
+
+"What do you call work?"
+
+"Why, ain't THAT work?"
+
+Tom resumed his whitewashing, and answered carelessly:
+
+"Well, maybe it is, and maybe it ain't. All I know, is, it suits Tom
+Sawyer."
+
+"Oh come, now, you don't mean to let on that you LIKE it?"
+
+The brush continued to move.
+
+"Like it? Well, I don't see why I oughtn't to like it. Does a boy get
+a chance to whitewash a fence every day?"
+
+That put the thing in a new light. Ben stopped nibbling his apple. Tom
+swept his brush daintily back and forth--stepped back to note the
+effect--added a touch here and there--criticised the effect again--Ben
+watching every move and getting more and more interested, more and more
+absorbed. Presently he said:
+
+"Say, Tom, let ME whitewash a little."
+
+Tom considered, was about to consent; but he altered his mind:
+
+"No--no--I reckon it wouldn't hardly do, Ben. You see, Aunt Polly's
+awful particular about this fence--right here on the street, you know
+--but if it was the back fence I wouldn't mind and SHE wouldn't. Yes,
+she's awful particular about this fence; it's got to be done very
+careful; I reckon there ain't one boy in a thousand, maybe two
+thousand, that can do it the way it's got to be done."
+
+"No--is that so? Oh come, now--lemme just try. Only just a little--I'd
+let YOU, if you was me, Tom."
+
+"Ben, I'd like to, honest injun; but Aunt Polly--well, Jim wanted to
+do it, but she wouldn't let him; Sid wanted to do it, and she wouldn't
+let Sid. Now don't you see how I'm fixed? If you was to tackle this
+fence and anything was to happen to it--"
+
+"Oh, shucks, I'll be just as careful. Now lemme try. Say--I'll give
+you the core of my apple."
+
+"Well, here--No, Ben, now don't. I'm afeard--"
+
+"I'll give you ALL of it!"
+
+Tom gave up the brush with reluctance in his face, but alacrity in his
+heart. And while the late steamer Big Missouri worked and sweated in
+the sun, the retired artist sat on a barrel in the shade close by,
+dangled his legs, munched his apple, and planned the slaughter of more
+innocents. There was no lack of material; boys happened along every
+little while; they came to jeer, but remained to whitewash. By the time
+Ben was fagged out, Tom had traded the next chance to Billy Fisher for
+a kite, in good repair; and when he played out, Johnny Miller bought in
+for a dead rat and a string to swing it with--and so on, and so on,
+hour after hour. And when the middle of the afternoon came, from being
+a poor poverty-stricken boy in the morning, Tom was literally rolling
+in wealth. He had besides the things before mentioned, twelve marbles,
+part of a jews-harp, a piece of blue bottle-glass to look through, a
+spool cannon, a key that wouldn't unlock anything, a fragment of chalk,
+a glass stopper of a decanter, a tin soldier, a couple of tadpoles, six
+fire-crackers, a kitten with only one eye, a brass doorknob, a
+dog-collar--but no dog--the handle of a knife, four pieces of
+orange-peel, and a dilapidated old window sash.
+
+He had had a nice, good, idle time all the while--plenty of company
+--and the fence had three coats of whitewash on it! If he hadn't run out
+of whitewash he would have bankrupted every boy in the village.
+
+Tom said to himself that it was not such a hollow world, after all. He
+had discovered a great law of human action, without knowing it--namely,
+that in order to make a man or a boy covet a thing, it is only
+necessary to make the thing difficult to attain. If he had been a great
+and wise philosopher, like the writer of this book, he would now have
+comprehended that Work consists of whatever a body is OBLIGED to do,
+and that Play consists of whatever a body is not obliged to do. And
+this would help him to understand why constructing artificial flowers
+or performing on a tread-mill is work, while rolling ten-pins or
+climbing Mont Blanc is only amusement. There are wealthy gentlemen in
+England who drive four-horse passenger-coaches twenty or thirty miles
+on a daily line, in the summer, because the privilege costs them
+considerable money; but if they were offered wages for the service,
+that would turn it into work and then they would resign.
+
+The boy mused awhile over the substantial change which had taken place
+in his worldly circumstances, and then wended toward headquarters to
+report.
+
+
+
+CHAPTER III
+
+TOM presented himself before Aunt Polly, who was sitting by an open
+window in a pleasant rearward apartment, which was bedroom,
+breakfast-room, dining-room, and library, combined. The balmy summer
+air, the restful quiet, the odor of the flowers, and the drowsing murmur
+of the bees had had their effect, and she was nodding over her knitting
+--for she had no company but the cat, and it was asleep in her lap. Her
+spectacles were propped up on her gray head for safety. She had thought
+that of course Tom had deserted long ago, and she wondered at seeing him
+place himself in her power again in this intrepid way. He said: "Mayn't
+I go and play now, aunt?"
+
+"What, a'ready? How much have you done?"
+
+"It's all done, aunt."
+
+"Tom, don't lie to me--I can't bear it."
+
+"I ain't, aunt; it IS all done."
+
+Aunt Polly placed small trust in such evidence. She went out to see
+for herself; and she would have been content to find twenty per cent.
+of Tom's statement true. When she found the entire fence whitewashed,
+and not only whitewashed but elaborately coated and recoated, and even
+a streak added to the ground, her astonishment was almost unspeakable.
+She said:
+
+"Well, I never! There's no getting round it, you can work when you're
+a mind to, Tom." And then she diluted the compliment by adding, "But
+it's powerful seldom you're a mind to, I'm bound to say. Well, go 'long
+and play; but mind you get back some time in a week, or I'll tan you."
+
+She was so overcome by the splendor of his achievement that she took
+him into the closet and selected a choice apple and delivered it to
+him, along with an improving lecture upon the added value and flavor a
+treat took to itself when it came without sin through virtuous effort.
+And while she closed with a happy Scriptural flourish, he "hooked" a
+doughnut.
+
+Then he skipped out, and saw Sid just starting up the outside stairway
+that led to the back rooms on the second floor. Clods were handy and
+the air was full of them in a twinkling. They raged around Sid like a
+hail-storm; and before Aunt Polly could collect her surprised faculties
+and sally to the rescue, six or seven clods had taken personal effect,
+and Tom was over the fence and gone. There was a gate, but as a general
+thing he was too crowded for time to make use of it. His soul was at
+peace, now that he had settled with Sid for calling attention to his
+black thread and getting him into trouble.
+
+Tom skirted the block, and came round into a muddy alley that led by
+the back of his aunt's cow-stable. He presently got safely beyond the
+reach of capture and punishment, and hastened toward the public square
+of the village, where two "military" companies of boys had met for
+conflict, according to previous appointment. Tom was General of one of
+these armies, Joe Harper (a bosom friend) General of the other. These
+two great commanders did not condescend to fight in person--that being
+better suited to the still smaller fry--but sat together on an eminence
+and conducted the field operations by orders delivered through
+aides-de-camp. Tom's army won a great victory, after a long and
+hard-fought battle. Then the dead were counted, prisoners exchanged,
+the terms of the next disagreement agreed upon, and the day for the
+necessary battle appointed; after which the armies fell into line and
+marched away, and Tom turned homeward alone.
+
+As he was passing by the house where Jeff Thatcher lived, he saw a new
+girl in the garden--a lovely little blue-eyed creature with yellow hair
+plaited into two long-tails, white summer frock and embroidered
+pantalettes. The fresh-crowned hero fell without firing a shot. A
+certain Amy Lawrence vanished out of his heart and left not even a
+memory of herself behind. He had thought he loved her to distraction;
+he had regarded his passion as adoration; and behold it was only a poor
+little evanescent partiality. He had been months winning her; she had
+confessed hardly a week ago; he had been the happiest and the proudest
+boy in the world only seven short days, and here in one instant of time
+she had gone out of his heart like a casual stranger whose visit is
+done.
+
+He worshipped this new angel with furtive eye, till he saw that she
+had discovered him; then he pretended he did not know she was present,
+and began to "show off" in all sorts of absurd boyish ways, in order to
+win her admiration. He kept up this grotesque foolishness for some
+time; but by-and-by, while he was in the midst of some dangerous
+gymnastic performances, he glanced aside and saw that the little girl
+was wending her way toward the house. Tom came up to the fence and
+leaned on it, grieving, and hoping she would tarry yet awhile longer.
+She halted a moment on the steps and then moved toward the door. Tom
+heaved a great sigh as she put her foot on the threshold. But his face
+lit up, right away, for she tossed a pansy over the fence a moment
+before she disappeared.
+
+The boy ran around and stopped within a foot or two of the flower, and
+then shaded his eyes with his hand and began to look down street as if
+he had discovered something of interest going on in that direction.
+Presently he picked up a straw and began trying to balance it on his
+nose, with his head tilted far back; and as he moved from side to side,
+in his efforts, he edged nearer and nearer toward the pansy; finally
+his bare foot rested upon it, his pliant toes closed upon it, and he
+hopped away with the treasure and disappeared round the corner. But
+only for a minute--only while he could button the flower inside his
+jacket, next his heart--or next his stomach, possibly, for he was not
+much posted in anatomy, and not hypercritical, anyway.
+
+He returned, now, and hung about the fence till nightfall, "showing
+off," as before; but the girl never exhibited herself again, though Tom
+comforted himself a little with the hope that she had been near some
+window, meantime, and been aware of his attentions. Finally he strode
+home reluctantly, with his poor head full of visions.
+
+All through supper his spirits were so high that his aunt wondered
+"what had got into the child." He took a good scolding about clodding
+Sid, and did not seem to mind it in the least. He tried to steal sugar
+under his aunt's very nose, and got his knuckles rapped for it. He said:
+
+"Aunt, you don't whack Sid when he takes it."
+
+"Well, Sid don't torment a body the way you do. You'd be always into
+that sugar if I warn't watching you."
+
+Presently she stepped into the kitchen, and Sid, happy in his
+immunity, reached for the sugar-bowl--a sort of glorying over Tom which
+was wellnigh unbearable. But Sid's fingers slipped and the bowl dropped
+and broke. Tom was in ecstasies. In such ecstasies that he even
+controlled his tongue and was silent. He said to himself that he would
+not speak a word, even when his aunt came in, but would sit perfectly
+still till she asked who did the mischief; and then he would tell, and
+there would be nothing so good in the world as to see that pet model
+"catch it." He was so brimful of exultation that he could hardly hold
+himself when the old lady came back and stood above the wreck
+discharging lightnings of wrath from over her spectacles. He said to
+himself, "Now it's coming!" And the next instant he was sprawling on
+the floor! The potent palm was uplifted to strike again when Tom cried
+out:
+
+"Hold on, now, what 'er you belting ME for?--Sid broke it!"
+
+Aunt Polly paused, perplexed, and Tom looked for healing pity. But
+when she got her tongue again, she only said:
+
+"Umf! Well, you didn't get a lick amiss, I reckon. You been into some
+other audacious mischief when I wasn't around, like enough."
+
+Then her conscience reproached her, and she yearned to say something
+kind and loving; but she judged that this would be construed into a
+confession that she had been in the wrong, and discipline forbade that.
+So she kept silence, and went about her affairs with a troubled heart.
+Tom sulked in a corner and exalted his woes. He knew that in her heart
+his aunt was on her knees to him, and he was morosely gratified by the
+consciousness of it. He would hang out no signals, he would take notice
+of none. He knew that a yearning glance fell upon him, now and then,
+through a film of tears, but he refused recognition of it. He pictured
+himself lying sick unto death and his aunt bending over him beseeching
+one little forgiving word, but he would turn his face to the wall, and
+die with that word unsaid. Ah, how would she feel then? And he pictured
+himself brought home from the river, dead, with his curls all wet, and
+his sore heart at rest. How she would throw herself upon him, and how
+her tears would fall like rain, and her lips pray God to give her back
+her boy and she would never, never abuse him any more! But he would lie
+there cold and white and make no sign--a poor little sufferer, whose
+griefs were at an end. He so worked upon his feelings with the pathos
+of these dreams, that he had to keep swallowing, he was so like to
+choke; and his eyes swam in a blur of water, which overflowed when he
+winked, and ran down and trickled from the end of his nose. And such a
+luxury to him was this petting of his sorrows, that he could not bear
+to have any worldly cheeriness or any grating delight intrude upon it;
+it was too sacred for such contact; and so, presently, when his cousin
+Mary danced in, all alive with the joy of seeing home again after an
+age-long visit of one week to the country, he got up and moved in
+clouds and darkness out at one door as she brought song and sunshine in
+at the other.
+
+He wandered far from the accustomed haunts of boys, and sought
+desolate places that were in harmony with his spirit. A log raft in the
+river invited him, and he seated himself on its outer edge and
+contemplated the dreary vastness of the stream, wishing, the while,
+that he could only be drowned, all at once and unconsciously, without
+undergoing the uncomfortable routine devised by nature. Then he thought
+of his flower. He got it out, rumpled and wilted, and it mightily
+increased his dismal felicity. He wondered if she would pity him if she
+knew? Would she cry, and wish that she had a right to put her arms
+around his neck and comfort him? Or would she turn coldly away like all
+the hollow world? This picture brought such an agony of pleasurable
+suffering that he worked it over and over again in his mind and set it
+up in new and varied lights, till he wore it threadbare. At last he
+rose up sighing and departed in the darkness.
+
+About half-past nine or ten o'clock he came along the deserted street
+to where the Adored Unknown lived; he paused a moment; no sound fell
+upon his listening ear; a candle was casting a dull glow upon the
+curtain of a second-story window. Was the sacred presence there? He
+climbed the fence, threaded his stealthy way through the plants, till
+he stood under that window; he looked up at it long, and with emotion;
+then he laid him down on the ground under it, disposing himself upon
+his back, with his hands clasped upon his breast and holding his poor
+wilted flower. And thus he would die--out in the cold world, with no
+shelter over his homeless head, no friendly hand to wipe the
+death-damps from his brow, no loving face to bend pityingly over him
+when the great agony came. And thus SHE would see him when she looked
+out upon the glad morning, and oh! would she drop one little tear upon
+his poor, lifeless form, would she heave one little sigh to see a bright
+young life so rudely blighted, so untimely cut down?
+
+The window went up, a maid-servant's discordant voice profaned the
+holy calm, and a deluge of water drenched the prone martyr's remains!
+
+The strangling hero sprang up with a relieving snort. There was a whiz
+as of a missile in the air, mingled with the murmur of a curse, a sound
+as of shivering glass followed, and a small, vague form went over the
+fence and shot away in the gloom.
+
+Not long after, as Tom, all undressed for bed, was surveying his
+drenched garments by the light of a tallow dip, Sid woke up; but if he
+had any dim idea of making any "references to allusions," he thought
+better of it and held his peace, for there was danger in Tom's eye.
+
+Tom turned in without the added vexation of prayers, and Sid made
+mental note of the omission.
+
+
+
+CHAPTER IV
+
+THE sun rose upon a tranquil world, and beamed down upon the peaceful
+village like a benediction. Breakfast over, Aunt Polly had family
+worship: it began with a prayer built from the ground up of solid
+courses of Scriptural quotations, welded together with a thin mortar of
+originality; and from the summit of this she delivered a grim chapter
+of the Mosaic Law, as from Sinai.
+
+Then Tom girded up his loins, so to speak, and went to work to "get
+his verses." Sid had learned his lesson days before. Tom bent all his
+energies to the memorizing of five verses, and he chose part of the
+Sermon on the Mount, because he could find no verses that were shorter.
+At the end of half an hour Tom had a vague general idea of his lesson,
+but no more, for his mind was traversing the whole field of human
+thought, and his hands were busy with distracting recreations. Mary
+took his book to hear him recite, and he tried to find his way through
+the fog:
+
+"Blessed are the--a--a--"
+
+"Poor"--
+
+"Yes--poor; blessed are the poor--a--a--"
+
+"In spirit--"
+
+"In spirit; blessed are the poor in spirit, for they--they--"
+
+"THEIRS--"
+
+"For THEIRS. Blessed are the poor in spirit, for theirs is the kingdom
+of heaven. Blessed are they that mourn, for they--they--"
+
+"Sh--"
+
+"For they--a--"
+
+"S, H, A--"
+
+"For they S, H--Oh, I don't know what it is!"
+
+"SHALL!"
+
+"Oh, SHALL! for they shall--for they shall--a--a--shall mourn--a--a--
+blessed are they that shall--they that--a--they that shall mourn, for
+they shall--a--shall WHAT? Why don't you tell me, Mary?--what do you
+want to be so mean for?"
+
+"Oh, Tom, you poor thick-headed thing, I'm not teasing you. I wouldn't
+do that. You must go and learn it again. Don't you be discouraged, Tom,
+you'll manage it--and if you do, I'll give you something ever so nice.
+There, now, that's a good boy."
+
+"All right! What is it, Mary, tell me what it is."
+
+"Never you mind, Tom. You know if I say it's nice, it is nice."
+
+"You bet you that's so, Mary. All right, I'll tackle it again."
+
+And he did "tackle it again"--and under the double pressure of
+curiosity and prospective gain he did it with such spirit that he
+accomplished a shining success. Mary gave him a brand-new "Barlow"
+knife worth twelve and a half cents; and the convulsion of delight that
+swept his system shook him to his foundations. True, the knife would
+not cut anything, but it was a "sure-enough" Barlow, and there was
+inconceivable grandeur in that--though where the Western boys ever got
+the idea that such a weapon could possibly be counterfeited to its
+injury is an imposing mystery and will always remain so, perhaps. Tom
+contrived to scarify the cupboard with it, and was arranging to begin
+on the bureau, when he was called off to dress for Sunday-school.
+
+Mary gave him a tin basin of water and a piece of soap, and he went
+outside the door and set the basin on a little bench there; then he
+dipped the soap in the water and laid it down; turned up his sleeves;
+poured out the water on the ground, gently, and then entered the
+kitchen and began to wipe his face diligently on the towel behind the
+door. But Mary removed the towel and said:
+
+"Now ain't you ashamed, Tom. You mustn't be so bad. Water won't hurt
+you."
+
+Tom was a trifle disconcerted. The basin was refilled, and this time
+he stood over it a little while, gathering resolution; took in a big
+breath and began. When he entered the kitchen presently, with both eyes
+shut and groping for the towel with his hands, an honorable testimony
+of suds and water was dripping from his face. But when he emerged from
+the towel, he was not yet satisfactory, for the clean territory stopped
+short at his chin and his jaws, like a mask; below and beyond this line
+there was a dark expanse of unirrigated soil that spread downward in
+front and backward around his neck. Mary took him in hand, and when she
+was done with him he was a man and a brother, without distinction of
+color, and his saturated hair was neatly brushed, and its short curls
+wrought into a dainty and symmetrical general effect. [He privately
+smoothed out the curls, with labor and difficulty, and plastered his
+hair close down to his head; for he held curls to be effeminate, and
+his own filled his life with bitterness.] Then Mary got out a suit of
+his clothing that had been used only on Sundays during two years--they
+were simply called his "other clothes"--and so by that we know the
+size of his wardrobe. The girl "put him to rights" after he had dressed
+himself; she buttoned his neat roundabout up to his chin, turned his
+vast shirt collar down over his shoulders, brushed him off and crowned
+him with his speckled straw hat. He now looked exceedingly improved and
+uncomfortable. He was fully as uncomfortable as he looked; for there
+was a restraint about whole clothes and cleanliness that galled him. He
+hoped that Mary would forget his shoes, but the hope was blighted; she
+coated them thoroughly with tallow, as was the custom, and brought them
+out. He lost his temper and said he was always being made to do
+everything he didn't want to do. But Mary said, persuasively:
+
+"Please, Tom--that's a good boy."
+
+So he got into the shoes snarling. Mary was soon ready, and the three
+children set out for Sunday-school--a place that Tom hated with his
+whole heart; but Sid and Mary were fond of it.
+
+Sabbath-school hours were from nine to half-past ten; and then church
+service. Two of the children always remained for the sermon
+voluntarily, and the other always remained too--for stronger reasons.
+The church's high-backed, uncushioned pews would seat about three
+hundred persons; the edifice was but a small, plain affair, with a sort
+of pine board tree-box on top of it for a steeple. At the door Tom
+dropped back a step and accosted a Sunday-dressed comrade:
+
+"Say, Billy, got a yaller ticket?"
+
+"Yes."
+
+"What'll you take for her?"
+
+"What'll you give?"
+
+"Piece of lickrish and a fish-hook."
+
+"Less see 'em."
+
+Tom exhibited. They were satisfactory, and the property changed hands.
+Then Tom traded a couple of white alleys for three red tickets, and
+some small trifle or other for a couple of blue ones. He waylaid other
+boys as they came, and went on buying tickets of various colors ten or
+fifteen minutes longer. He entered the church, now, with a swarm of
+clean and noisy boys and girls, proceeded to his seat and started a
+quarrel with the first boy that came handy. The teacher, a grave,
+elderly man, interfered; then turned his back a moment and Tom pulled a
+boy's hair in the next bench, and was absorbed in his book when the boy
+turned around; stuck a pin in another boy, presently, in order to hear
+him say "Ouch!" and got a new reprimand from his teacher. Tom's whole
+class were of a pattern--restless, noisy, and troublesome. When they
+came to recite their lessons, not one of them knew his verses
+perfectly, but had to be prompted all along. However, they worried
+through, and each got his reward--in small blue tickets, each with a
+passage of Scripture on it; each blue ticket was pay for two verses of
+the recitation. Ten blue tickets equalled a red one, and could be
+exchanged for it; ten red tickets equalled a yellow one; for ten yellow
+tickets the superintendent gave a very plainly bound Bible (worth forty
+cents in those easy times) to the pupil. How many of my readers would
+have the industry and application to memorize two thousand verses, even
+for a Dore Bible? And yet Mary had acquired two Bibles in this way--it
+was the patient work of two years--and a boy of German parentage had
+won four or five. He once recited three thousand verses without
+stopping; but the strain upon his mental faculties was too great, and
+he was little better than an idiot from that day forth--a grievous
+misfortune for the school, for on great occasions, before company, the
+superintendent (as Tom expressed it) had always made this boy come out
+and "spread himself." Only the older pupils managed to keep their
+tickets and stick to their tedious work long enough to get a Bible, and
+so the delivery of one of these prizes was a rare and noteworthy
+circumstance; the successful pupil was so great and conspicuous for
+that day that on the spot every scholar's heart was fired with a fresh
+ambition that often lasted a couple of weeks. It is possible that Tom's
+mental stomach had never really hungered for one of those prizes, but
+unquestionably his entire being had for many a day longed for the glory
+and the eclat that came with it.
+
+In due course the superintendent stood up in front of the pulpit, with
+a closed hymn-book in his hand and his forefinger inserted between its
+leaves, and commanded attention. When a Sunday-school superintendent
+makes his customary little speech, a hymn-book in the hand is as
+necessary as is the inevitable sheet of music in the hand of a singer
+who stands forward on the platform and sings a solo at a concert
+--though why, is a mystery: for neither the hymn-book nor the sheet of
+music is ever referred to by the sufferer. This superintendent was a
+slim creature of thirty-five, with a sandy goatee and short sandy hair;
+he wore a stiff standing-collar whose upper edge almost reached his
+ears and whose sharp points curved forward abreast the corners of his
+mouth--a fence that compelled a straight lookout ahead, and a turning
+of the whole body when a side view was required; his chin was propped
+on a spreading cravat which was as broad and as long as a bank-note,
+and had fringed ends; his boot toes were turned sharply up, in the
+fashion of the day, like sleigh-runners--an effect patiently and
+laboriously produced by the young men by sitting with their toes
+pressed against a wall for hours together. Mr. Walters was very earnest
+of mien, and very sincere and honest at heart; and he held sacred
+things and places in such reverence, and so separated them from worldly
+matters, that unconsciously to himself his Sunday-school voice had
+acquired a peculiar intonation which was wholly absent on week-days. He
+began after this fashion:
+
+"Now, children, I want you all to sit up just as straight and pretty
+as you can and give me all your attention for a minute or two. There
+--that is it. That is the way good little boys and girls should do. I see
+one little girl who is looking out of the window--I am afraid she
+thinks I am out there somewhere--perhaps up in one of the trees making
+a speech to the little birds. [Applausive titter.] I want to tell you
+how good it makes me feel to see so many bright, clean little faces
+assembled in a place like this, learning to do right and be good." And
+so forth and so on. It is not necessary to set down the rest of the
+oration. It was of a pattern which does not vary, and so it is familiar
+to us all.
+
+The latter third of the speech was marred by the resumption of fights
+and other recreations among certain of the bad boys, and by fidgetings
+and whisperings that extended far and wide, washing even to the bases
+of isolated and incorruptible rocks like Sid and Mary. But now every
+sound ceased suddenly, with the subsidence of Mr. Walters' voice, and
+the conclusion of the speech was received with a burst of silent
+gratitude.
+
+A good part of the whispering had been occasioned by an event which
+was more or less rare--the entrance of visitors: lawyer Thatcher,
+accompanied by a very feeble and aged man; a fine, portly, middle-aged
+gentleman with iron-gray hair; and a dignified lady who was doubtless
+the latter's wife. The lady was leading a child. Tom had been restless
+and full of chafings and repinings; conscience-smitten, too--he could
+not meet Amy Lawrence's eye, he could not brook her loving gaze. But
+when he saw this small new-comer his soul was all ablaze with bliss in
+a moment. The next moment he was "showing off" with all his might
+--cuffing boys, pulling hair, making faces--in a word, using every art
+that seemed likely to fascinate a girl and win her applause. His
+exaltation had but one alloy--the memory of his humiliation in this
+angel's garden--and that record in sand was fast washing out, under
+the waves of happiness that were sweeping over it now.
+
+The visitors were given the highest seat of honor, and as soon as Mr.
+Walters' speech was finished, he introduced them to the school. The
+middle-aged man turned out to be a prodigious personage--no less a one
+than the county judge--altogether the most august creation these
+children had ever looked upon--and they wondered what kind of material
+he was made of--and they half wanted to hear him roar, and were half
+afraid he might, too. He was from Constantinople, twelve miles away--so
+he had travelled, and seen the world--these very eyes had looked upon
+the county court-house--which was said to have a tin roof. The awe
+which these reflections inspired was attested by the impressive silence
+and the ranks of staring eyes. This was the great Judge Thatcher,
+brother of their own lawyer. Jeff Thatcher immediately went forward, to
+be familiar with the great man and be envied by the school. It would
+have been music to his soul to hear the whisperings:
+
+"Look at him, Jim! He's a going up there. Say--look! he's a going to
+shake hands with him--he IS shaking hands with him! By jings, don't you
+wish you was Jeff?"
+
+Mr. Walters fell to "showing off," with all sorts of official
+bustlings and activities, giving orders, delivering judgments,
+discharging directions here, there, everywhere that he could find a
+target. The librarian "showed off"--running hither and thither with his
+arms full of books and making a deal of the splutter and fuss that
+insect authority delights in. The young lady teachers "showed off"
+--bending sweetly over pupils that were lately being boxed, lifting
+pretty warning fingers at bad little boys and patting good ones
+lovingly. The young gentlemen teachers "showed off" with small
+scoldings and other little displays of authority and fine attention to
+discipline--and most of the teachers, of both sexes, found business up
+at the library, by the pulpit; and it was business that frequently had
+to be done over again two or three times (with much seeming vexation).
+The little girls "showed off" in various ways, and the little boys
+"showed off" with such diligence that the air was thick with paper wads
+and the murmur of scufflings. And above it all the great man sat and
+beamed a majestic judicial smile upon all the house, and warmed himself
+in the sun of his own grandeur--for he was "showing off," too.
+
+There was only one thing wanting to make Mr. Walters' ecstasy
+complete, and that was a chance to deliver a Bible-prize and exhibit a
+prodigy. Several pupils had a few yellow tickets, but none had enough
+--he had been around among the star pupils inquiring. He would have given
+worlds, now, to have that German lad back again with a sound mind.
+
+And now at this moment, when hope was dead, Tom Sawyer came forward
+with nine yellow tickets, nine red tickets, and ten blue ones, and
+demanded a Bible. This was a thunderbolt out of a clear sky. Walters
+was not expecting an application from this source for the next ten
+years. But there was no getting around it--here were the certified
+checks, and they were good for their face. Tom was therefore elevated
+to a place with the Judge and the other elect, and the great news was
+announced from headquarters. It was the most stunning surprise of the
+decade, and so profound was the sensation that it lifted the new hero
+up to the judicial one's altitude, and the school had two marvels to
+gaze upon in place of one. The boys were all eaten up with envy--but
+those that suffered the bitterest pangs were those who perceived too
+late that they themselves had contributed to this hated splendor by
+trading tickets to Tom for the wealth he had amassed in selling
+whitewashing privileges. These despised themselves, as being the dupes
+of a wily fraud, a guileful snake in the grass.
+
+The prize was delivered to Tom with as much effusion as the
+superintendent could pump up under the circumstances; but it lacked
+somewhat of the true gush, for the poor fellow's instinct taught him
+that there was a mystery here that could not well bear the light,
+perhaps; it was simply preposterous that this boy had warehoused two
+thousand sheaves of Scriptural wisdom on his premises--a dozen would
+strain his capacity, without a doubt.
+
+Amy Lawrence was proud and glad, and she tried to make Tom see it in
+her face--but he wouldn't look. She wondered; then she was just a grain
+troubled; next a dim suspicion came and went--came again; she watched;
+a furtive glance told her worlds--and then her heart broke, and she was
+jealous, and angry, and the tears came and she hated everybody. Tom
+most of all (she thought).
+
+Tom was introduced to the Judge; but his tongue was tied, his breath
+would hardly come, his heart quaked--partly because of the awful
+greatness of the man, but mainly because he was her parent. He would
+have liked to fall down and worship him, if it were in the dark. The
+Judge put his hand on Tom's head and called him a fine little man, and
+asked him what his name was. The boy stammered, gasped, and got it out:
+
+"Tom."
+
+"Oh, no, not Tom--it is--"
+
+"Thomas."
+
+"Ah, that's it. I thought there was more to it, maybe. That's very
+well. But you've another one I daresay, and you'll tell it to me, won't
+you?"
+
+"Tell the gentleman your other name, Thomas," said Walters, "and say
+sir. You mustn't forget your manners."
+
+"Thomas Sawyer--sir."
+
+"That's it! That's a good boy. Fine boy. Fine, manly little fellow.
+Two thousand verses is a great many--very, very great many. And you
+never can be sorry for the trouble you took to learn them; for
+knowledge is worth more than anything there is in the world; it's what
+makes great men and good men; you'll be a great man and a good man
+yourself, some day, Thomas, and then you'll look back and say, It's all
+owing to the precious Sunday-school privileges of my boyhood--it's all
+owing to my dear teachers that taught me to learn--it's all owing to
+the good superintendent, who encouraged me, and watched over me, and
+gave me a beautiful Bible--a splendid elegant Bible--to keep and have
+it all for my own, always--it's all owing to right bringing up! That is
+what you will say, Thomas--and you wouldn't take any money for those
+two thousand verses--no indeed you wouldn't. And now you wouldn't mind
+telling me and this lady some of the things you've learned--no, I know
+you wouldn't--for we are proud of little boys that learn. Now, no
+doubt you know the names of all the twelve disciples. Won't you tell us
+the names of the first two that were appointed?"
+
+Tom was tugging at a button-hole and looking sheepish. He blushed,
+now, and his eyes fell. Mr. Walters' heart sank within him. He said to
+himself, it is not possible that the boy can answer the simplest
+question--why DID the Judge ask him? Yet he felt obliged to speak up
+and say:
+
+"Answer the gentleman, Thomas--don't be afraid."
+
+Tom still hung fire.
+
+"Now I know you'll tell me," said the lady. "The names of the first
+two disciples were--"
+
+"DAVID AND GOLIAH!"
+
+Let us draw the curtain of charity over the rest of the scene.
+
+
+
+CHAPTER V
+
+ABOUT half-past ten the cracked bell of the small church began to
+ring, and presently the people began to gather for the morning sermon.
+The Sunday-school children distributed themselves about the house and
+occupied pews with their parents, so as to be under supervision. Aunt
+Polly came, and Tom and Sid and Mary sat with her--Tom being placed
+next the aisle, in order that he might be as far away from the open
+window and the seductive outside summer scenes as possible. The crowd
+filed up the aisles: the aged and needy postmaster, who had seen better
+days; the mayor and his wife--for they had a mayor there, among other
+unnecessaries; the justice of the peace; the widow Douglass, fair,
+smart, and forty, a generous, good-hearted soul and well-to-do, her
+hill mansion the only palace in the town, and the most hospitable and
+much the most lavish in the matter of festivities that St. Petersburg
+could boast; the bent and venerable Major and Mrs. Ward; lawyer
+Riverson, the new notable from a distance; next the belle of the
+village, followed by a troop of lawn-clad and ribbon-decked young
+heart-breakers; then all the young clerks in town in a body--for they
+had stood in the vestibule sucking their cane-heads, a circling wall of
+oiled and simpering admirers, till the last girl had run their gantlet;
+and last of all came the Model Boy, Willie Mufferson, taking as heedful
+care of his mother as if she were cut glass. He always brought his
+mother to church, and was the pride of all the matrons. The boys all
+hated him, he was so good. And besides, he had been "thrown up to them"
+so much. His white handkerchief was hanging out of his pocket behind, as
+usual on Sundays--accidentally. Tom had no handkerchief, and he looked
+upon boys who had as snobs.
+
+The congregation being fully assembled, now, the bell rang once more,
+to warn laggards and stragglers, and then a solemn hush fell upon the
+church which was only broken by the tittering and whispering of the
+choir in the gallery. The choir always tittered and whispered all
+through service. There was once a church choir that was not ill-bred,
+but I have forgotten where it was, now. It was a great many years ago,
+and I can scarcely remember anything about it, but I think it was in
+some foreign country.
+
+The minister gave out the hymn, and read it through with a relish, in
+a peculiar style which was much admired in that part of the country.
+His voice began on a medium key and climbed steadily up till it reached
+a certain point, where it bore with strong emphasis upon the topmost
+word and then plunged down as if from a spring-board:
+
+  Shall I be car-ri-ed toe the skies, on flow'ry BEDS of ease,
+
+  Whilst others fight to win the prize, and sail thro' BLOODY seas?
+
+He was regarded as a wonderful reader. At church "sociables" he was
+always called upon to read poetry; and when he was through, the ladies
+would lift up their hands and let them fall helplessly in their laps,
+and "wall" their eyes, and shake their heads, as much as to say, "Words
+cannot express it; it is too beautiful, TOO beautiful for this mortal
+earth."
+
+After the hymn had been sung, the Rev. Mr. Sprague turned himself into
+a bulletin-board, and read off "notices" of meetings and societies and
+things till it seemed that the list would stretch out to the crack of
+doom--a queer custom which is still kept up in America, even in cities,
+away here in this age of abundant newspapers. Often, the less there is
+to justify a traditional custom, the harder it is to get rid of it.
+
+And now the minister prayed. A good, generous prayer it was, and went
+into details: it pleaded for the church, and the little children of the
+church; for the other churches of the village; for the village itself;
+for the county; for the State; for the State officers; for the United
+States; for the churches of the United States; for Congress; for the
+President; for the officers of the Government; for poor sailors, tossed
+by stormy seas; for the oppressed millions groaning under the heel of
+European monarchies and Oriental despotisms; for such as have the light
+and the good tidings, and yet have not eyes to see nor ears to hear
+withal; for the heathen in the far islands of the sea; and closed with
+a supplication that the words he was about to speak might find grace
+and favor, and be as seed sown in fertile ground, yielding in time a
+grateful harvest of good. Amen.
+
+There was a rustling of dresses, and the standing congregation sat
+down. The boy whose history this book relates did not enjoy the prayer,
+he only endured it--if he even did that much. He was restive all
+through it; he kept tally of the details of the prayer, unconsciously
+--for he was not listening, but he knew the ground of old, and the
+clergyman's regular route over it--and when a little trifle of new
+matter was interlarded, his ear detected it and his whole nature
+resented it; he considered additions unfair, and scoundrelly. In the
+midst of the prayer a fly had lit on the back of the pew in front of
+him and tortured his spirit by calmly rubbing its hands together,
+embracing its head with its arms, and polishing it so vigorously that
+it seemed to almost part company with the body, and the slender thread
+of a neck was exposed to view; scraping its wings with its hind legs
+and smoothing them to its body as if they had been coat-tails; going
+through its whole toilet as tranquilly as if it knew it was perfectly
+safe. As indeed it was; for as sorely as Tom's hands itched to grab for
+it they did not dare--he believed his soul would be instantly destroyed
+if he did such a thing while the prayer was going on. But with the
+closing sentence his hand began to curve and steal forward; and the
+instant the "Amen" was out the fly was a prisoner of war. His aunt
+detected the act and made him let it go.
+
+The minister gave out his text and droned along monotonously through
+an argument that was so prosy that many a head by and by began to nod
+--and yet it was an argument that dealt in limitless fire and brimstone
+and thinned the predestined elect down to a company so small as to be
+hardly worth the saving. Tom counted the pages of the sermon; after
+church he always knew how many pages there had been, but he seldom knew
+anything else about the discourse. However, this time he was really
+interested for a little while. The minister made a grand and moving
+picture of the assembling together of the world's hosts at the
+millennium when the lion and the lamb should lie down together and a
+little child should lead them. But the pathos, the lesson, the moral of
+the great spectacle were lost upon the boy; he only thought of the
+conspicuousness of the principal character before the on-looking
+nations; his face lit with the thought, and he said to himself that he
+wished he could be that child, if it was a tame lion.
+
+Now he lapsed into suffering again, as the dry argument was resumed.
+Presently he bethought him of a treasure he had and got it out. It was
+a large black beetle with formidable jaws--a "pinchbug," he called it.
+It was in a percussion-cap box. The first thing the beetle did was to
+take him by the finger. A natural fillip followed, the beetle went
+floundering into the aisle and lit on its back, and the hurt finger
+went into the boy's mouth. The beetle lay there working its helpless
+legs, unable to turn over. Tom eyed it, and longed for it; but it was
+safe out of his reach. Other people uninterested in the sermon found
+relief in the beetle, and they eyed it too. Presently a vagrant poodle
+dog came idling along, sad at heart, lazy with the summer softness and
+the quiet, weary of captivity, sighing for change. He spied the beetle;
+the drooping tail lifted and wagged. He surveyed the prize; walked
+around it; smelt at it from a safe distance; walked around it again;
+grew bolder, and took a closer smell; then lifted his lip and made a
+gingerly snatch at it, just missing it; made another, and another;
+began to enjoy the diversion; subsided to his stomach with the beetle
+between his paws, and continued his experiments; grew weary at last,
+and then indifferent and absent-minded. His head nodded, and little by
+little his chin descended and touched the enemy, who seized it. There
+was a sharp yelp, a flirt of the poodle's head, and the beetle fell a
+couple of yards away, and lit on its back once more. The neighboring
+spectators shook with a gentle inward joy, several faces went behind
+fans and handkerchiefs, and Tom was entirely happy. The dog looked
+foolish, and probably felt so; but there was resentment in his heart,
+too, and a craving for revenge. So he went to the beetle and began a
+wary attack on it again; jumping at it from every point of a circle,
+lighting with his fore-paws within an inch of the creature, making even
+closer snatches at it with his teeth, and jerking his head till his
+ears flapped again. But he grew tired once more, after a while; tried
+to amuse himself with a fly but found no relief; followed an ant
+around, with his nose close to the floor, and quickly wearied of that;
+yawned, sighed, forgot the beetle entirely, and sat down on it. Then
+there was a wild yelp of agony and the poodle went sailing up the
+aisle; the yelps continued, and so did the dog; he crossed the house in
+front of the altar; he flew down the other aisle; he crossed before the
+doors; he clamored up the home-stretch; his anguish grew with his
+progress, till presently he was but a woolly comet moving in its orbit
+with the gleam and the speed of light. At last the frantic sufferer
+sheered from its course, and sprang into its master's lap; he flung it
+out of the window, and the voice of distress quickly thinned away and
+died in the distance.
+
+By this time the whole church was red-faced and suffocating with
+suppressed laughter, and the sermon had come to a dead standstill. The
+discourse was resumed presently, but it went lame and halting, all
+possibility of impressiveness being at an end; for even the gravest
+sentiments were constantly being received with a smothered burst of
+unholy mirth, under cover of some remote pew-back, as if the poor
+parson had said a rarely facetious thing. It was a genuine relief to
+the whole congregation when the ordeal was over and the benediction
+pronounced.
+
+Tom Sawyer went home quite cheerful, thinking to himself that there
+was some satisfaction about divine service when there was a bit of
+variety in it. He had but one marring thought; he was willing that the
+dog should play with his pinchbug, but he did not think it was upright
+in him to carry it off.
+
+
+
+CHAPTER VI
+
+MONDAY morning found Tom Sawyer miserable. Monday morning always found
+him so--because it began another week's slow suffering in school. He
+generally began that day with wishing he had had no intervening
+holiday, it made the going into captivity and fetters again so much
+more odious.
+
+Tom lay thinking. Presently it occurred to him that he wished he was
+sick; then he could stay home from school. Here was a vague
+possibility. He canvassed his system. No ailment was found, and he
+investigated again. This time he thought he could detect colicky
+symptoms, and he began to encourage them with considerable hope. But
+they soon grew feeble, and presently died wholly away. He reflected
+further. Suddenly he discovered something. One of his upper front teeth
+was loose. This was lucky; he was about to begin to groan, as a
+"starter," as he called it, when it occurred to him that if he came
+into court with that argument, his aunt would pull it out, and that
+would hurt. So he thought he would hold the tooth in reserve for the
+present, and seek further. Nothing offered for some little time, and
+then he remembered hearing the doctor tell about a certain thing that
+laid up a patient for two or three weeks and threatened to make him
+lose a finger. So the boy eagerly drew his sore toe from under the
+sheet and held it up for inspection. But now he did not know the
+necessary symptoms. However, it seemed well worth while to chance it,
+so he fell to groaning with considerable spirit.
+
+But Sid slept on unconscious.
+
+Tom groaned louder, and fancied that he began to feel pain in the toe.
+
+No result from Sid.
+
+Tom was panting with his exertions by this time. He took a rest and
+then swelled himself up and fetched a succession of admirable groans.
+
+Sid snored on.
+
+Tom was aggravated. He said, "Sid, Sid!" and shook him. This course
+worked well, and Tom began to groan again. Sid yawned, stretched, then
+brought himself up on his elbow with a snort, and began to stare at
+Tom. Tom went on groaning. Sid said:
+
+"Tom! Say, Tom!" [No response.] "Here, Tom! TOM! What is the matter,
+Tom?" And he shook him and looked in his face anxiously.
+
+Tom moaned out:
+
+"Oh, don't, Sid. Don't joggle me."
+
+"Why, what's the matter, Tom? I must call auntie."
+
+"No--never mind. It'll be over by and by, maybe. Don't call anybody."
+
+"But I must! DON'T groan so, Tom, it's awful. How long you been this
+way?"
+
+"Hours. Ouch! Oh, don't stir so, Sid, you'll kill me."
+
+"Tom, why didn't you wake me sooner? Oh, Tom, DON'T! It makes my
+flesh crawl to hear you. Tom, what is the matter?"
+
+"I forgive you everything, Sid. [Groan.] Everything you've ever done
+to me. When I'm gone--"
+
+"Oh, Tom, you ain't dying, are you? Don't, Tom--oh, don't. Maybe--"
+
+"I forgive everybody, Sid. [Groan.] Tell 'em so, Sid. And Sid, you
+give my window-sash and my cat with one eye to that new girl that's
+come to town, and tell her--"
+
+But Sid had snatched his clothes and gone. Tom was suffering in
+reality, now, so handsomely was his imagination working, and so his
+groans had gathered quite a genuine tone.
+
+Sid flew down-stairs and said:
+
+"Oh, Aunt Polly, come! Tom's dying!"
+
+"Dying!"
+
+"Yes'm. Don't wait--come quick!"
+
+"Rubbage! I don't believe it!"
+
+But she fled up-stairs, nevertheless, with Sid and Mary at her heels.
+And her face grew white, too, and her lip trembled. When she reached
+the bedside she gasped out:
+
+"You, Tom! Tom, what's the matter with you?"
+
+"Oh, auntie, I'm--"
+
+"What's the matter with you--what is the matter with you, child?"
+
+"Oh, auntie, my sore toe's mortified!"
+
+The old lady sank down into a chair and laughed a little, then cried a
+little, then did both together. This restored her and she said:
+
+"Tom, what a turn you did give me. Now you shut up that nonsense and
+climb out of this."
+
+The groans ceased and the pain vanished from the toe. The boy felt a
+little foolish, and he said:
+
+"Aunt Polly, it SEEMED mortified, and it hurt so I never minded my
+tooth at all."
+
+"Your tooth, indeed! What's the matter with your tooth?"
+
+"One of them's loose, and it aches perfectly awful."
+
+"There, there, now, don't begin that groaning again. Open your mouth.
+Well--your tooth IS loose, but you're not going to die about that.
+Mary, get me a silk thread, and a chunk of fire out of the kitchen."
+
+Tom said:
+
+"Oh, please, auntie, don't pull it out. It don't hurt any more. I wish
+I may never stir if it does. Please don't, auntie. I don't want to stay
+home from school."
+
+"Oh, you don't, don't you? So all this row was because you thought
+you'd get to stay home from school and go a-fishing? Tom, Tom, I love
+you so, and you seem to try every way you can to break my old heart
+with your outrageousness." By this time the dental instruments were
+ready. The old lady made one end of the silk thread fast to Tom's tooth
+with a loop and tied the other to the bedpost. Then she seized the
+chunk of fire and suddenly thrust it almost into the boy's face. The
+tooth hung dangling by the bedpost, now.
+
+But all trials bring their compensations. As Tom wended to school
+after breakfast, he was the envy of every boy he met because the gap in
+his upper row of teeth enabled him to expectorate in a new and
+admirable way. He gathered quite a following of lads interested in the
+exhibition; and one that had cut his finger and had been a centre of
+fascination and homage up to this time, now found himself suddenly
+without an adherent, and shorn of his glory. His heart was heavy, and
+he said with a disdain which he did not feel that it wasn't anything to
+spit like Tom Sawyer; but another boy said, "Sour grapes!" and he
+wandered away a dismantled hero.
+
+Shortly Tom came upon the juvenile pariah of the village, Huckleberry
+Finn, son of the town drunkard. Huckleberry was cordially hated and
+dreaded by all the mothers of the town, because he was idle and lawless
+and vulgar and bad--and because all their children admired him so, and
+delighted in his forbidden society, and wished they dared to be like
+him. Tom was like the rest of the respectable boys, in that he envied
+Huckleberry his gaudy outcast condition, and was under strict orders
+not to play with him. So he played with him every time he got a chance.
+Huckleberry was always dressed in the cast-off clothes of full-grown
+men, and they were in perennial bloom and fluttering with rags. His hat
+was a vast ruin with a wide crescent lopped out of its brim; his coat,
+when he wore one, hung nearly to his heels and had the rearward buttons
+far down the back; but one suspender supported his trousers; the seat
+of the trousers bagged low and contained nothing, the fringed legs
+dragged in the dirt when not rolled up.
+
+Huckleberry came and went, at his own free will. He slept on doorsteps
+in fine weather and in empty hogsheads in wet; he did not have to go to
+school or to church, or call any being master or obey anybody; he could
+go fishing or swimming when and where he chose, and stay as long as it
+suited him; nobody forbade him to fight; he could sit up as late as he
+pleased; he was always the first boy that went barefoot in the spring
+and the last to resume leather in the fall; he never had to wash, nor
+put on clean clothes; he could swear wonderfully. In a word, everything
+that goes to make life precious that boy had. So thought every
+harassed, hampered, respectable boy in St. Petersburg.
+
+Tom hailed the romantic outcast:
+
+"Hello, Huckleberry!"
+
+"Hello yourself, and see how you like it."
+
+"What's that you got?"
+
+"Dead cat."
+
+"Lemme see him, Huck. My, he's pretty stiff. Where'd you get him?"
+
+"Bought him off'n a boy."
+
+"What did you give?"
+
+"I give a blue ticket and a bladder that I got at the slaughter-house."
+
+"Where'd you get the blue ticket?"
+
+"Bought it off'n Ben Rogers two weeks ago for a hoop-stick."
+
+"Say--what is dead cats good for, Huck?"
+
+"Good for? Cure warts with."
+
+"No! Is that so? I know something that's better."
+
+"I bet you don't. What is it?"
+
+"Why, spunk-water."
+
+"Spunk-water! I wouldn't give a dern for spunk-water."
+
+"You wouldn't, wouldn't you? D'you ever try it?"
+
+"No, I hain't. But Bob Tanner did."
+
+"Who told you so!"
+
+"Why, he told Jeff Thatcher, and Jeff told Johnny Baker, and Johnny
+told Jim Hollis, and Jim told Ben Rogers, and Ben told a nigger, and
+the nigger told me. There now!"
+
+"Well, what of it? They'll all lie. Leastways all but the nigger. I
+don't know HIM. But I never see a nigger that WOULDN'T lie. Shucks! Now
+you tell me how Bob Tanner done it, Huck."
+
+"Why, he took and dipped his hand in a rotten stump where the
+rain-water was."
+
+"In the daytime?"
+
+"Certainly."
+
+"With his face to the stump?"
+
+"Yes. Least I reckon so."
+
+"Did he say anything?"
+
+"I don't reckon he did. I don't know."
+
+"Aha! Talk about trying to cure warts with spunk-water such a blame
+fool way as that! Why, that ain't a-going to do any good. You got to go
+all by yourself, to the middle of the woods, where you know there's a
+spunk-water stump, and just as it's midnight you back up against the
+stump and jam your hand in and say:
+
+  'Barley-corn, barley-corn, injun-meal shorts,
+   Spunk-water, spunk-water, swaller these warts,'
+
+and then walk away quick, eleven steps, with your eyes shut, and then
+turn around three times and walk home without speaking to anybody.
+Because if you speak the charm's busted."
+
+"Well, that sounds like a good way; but that ain't the way Bob Tanner
+done."
+
+"No, sir, you can bet he didn't, becuz he's the wartiest boy in this
+town; and he wouldn't have a wart on him if he'd knowed how to work
+spunk-water. I've took off thousands of warts off of my hands that way,
+Huck. I play with frogs so much that I've always got considerable many
+warts. Sometimes I take 'em off with a bean."
+
+"Yes, bean's good. I've done that."
+
+"Have you? What's your way?"
+
+"You take and split the bean, and cut the wart so as to get some
+blood, and then you put the blood on one piece of the bean and take and
+dig a hole and bury it 'bout midnight at the crossroads in the dark of
+the moon, and then you burn up the rest of the bean. You see that piece
+that's got the blood on it will keep drawing and drawing, trying to
+fetch the other piece to it, and so that helps the blood to draw the
+wart, and pretty soon off she comes."
+
+"Yes, that's it, Huck--that's it; though when you're burying it if you
+say 'Down bean; off wart; come no more to bother me!' it's better.
+That's the way Joe Harper does, and he's been nearly to Coonville and
+most everywheres. But say--how do you cure 'em with dead cats?"
+
+"Why, you take your cat and go and get in the graveyard 'long about
+midnight when somebody that was wicked has been buried; and when it's
+midnight a devil will come, or maybe two or three, but you can't see
+'em, you can only hear something like the wind, or maybe hear 'em talk;
+and when they're taking that feller away, you heave your cat after 'em
+and say, 'Devil follow corpse, cat follow devil, warts follow cat, I'm
+done with ye!' That'll fetch ANY wart."
+
+"Sounds right. D'you ever try it, Huck?"
+
+"No, but old Mother Hopkins told me."
+
+"Well, I reckon it's so, then. Becuz they say she's a witch."
+
+"Say! Why, Tom, I KNOW she is. She witched pap. Pap says so his own
+self. He come along one day, and he see she was a-witching him, so he
+took up a rock, and if she hadn't dodged, he'd a got her. Well, that
+very night he rolled off'n a shed wher' he was a layin drunk, and broke
+his arm."
+
+"Why, that's awful. How did he know she was a-witching him?"
+
+"Lord, pap can tell, easy. Pap says when they keep looking at you
+right stiddy, they're a-witching you. Specially if they mumble. Becuz
+when they mumble they're saying the Lord's Prayer backards."
+
+"Say, Hucky, when you going to try the cat?"
+
+"To-night. I reckon they'll come after old Hoss Williams to-night."
+
+"But they buried him Saturday. Didn't they get him Saturday night?"
+
+"Why, how you talk! How could their charms work till midnight?--and
+THEN it's Sunday. Devils don't slosh around much of a Sunday, I don't
+reckon."
+
+"I never thought of that. That's so. Lemme go with you?"
+
+"Of course--if you ain't afeard."
+
+"Afeard! 'Tain't likely. Will you meow?"
+
+"Yes--and you meow back, if you get a chance. Last time, you kep' me
+a-meowing around till old Hays went to throwing rocks at me and says
+'Dern that cat!' and so I hove a brick through his window--but don't
+you tell."
+
+"I won't. I couldn't meow that night, becuz auntie was watching me,
+but I'll meow this time. Say--what's that?"
+
+"Nothing but a tick."
+
+"Where'd you get him?"
+
+"Out in the woods."
+
+"What'll you take for him?"
+
+"I don't know. I don't want to sell him."
+
+"All right. It's a mighty small tick, anyway."
+
+"Oh, anybody can run a tick down that don't belong to them. I'm
+satisfied with it. It's a good enough tick for me."
+
+"Sho, there's ticks a plenty. I could have a thousand of 'em if I
+wanted to."
+
+"Well, why don't you? Becuz you know mighty well you can't. This is a
+pretty early tick, I reckon. It's the first one I've seen this year."
+
+"Say, Huck--I'll give you my tooth for him."
+
+"Less see it."
+
+Tom got out a bit of paper and carefully unrolled it. Huckleberry
+viewed it wistfully. The temptation was very strong. At last he said:
+
+"Is it genuwyne?"
+
+Tom lifted his lip and showed the vacancy.
+
+"Well, all right," said Huckleberry, "it's a trade."
+
+Tom enclosed the tick in the percussion-cap box that had lately been
+the pinchbug's prison, and the boys separated, each feeling wealthier
+than before.
+
+When Tom reached the little isolated frame schoolhouse, he strode in
+briskly, with the manner of one who had come with all honest speed.
+He hung his hat on a peg and flung himself into his seat with
+business-like alacrity. The master, throned on high in his great
+splint-bottom arm-chair, was dozing, lulled by the drowsy hum of study.
+The interruption roused him.
+
+"Thomas Sawyer!"
+
+Tom knew that when his name was pronounced in full, it meant trouble.
+
+"Sir!"
+
+"Come up here. Now, sir, why are you late again, as usual?"
+
+Tom was about to take refuge in a lie, when he saw two long tails of
+yellow hair hanging down a back that he recognized by the electric
+sympathy of love; and by that form was THE ONLY VACANT PLACE on the
+girls' side of the schoolhouse. He instantly said:
+
+"I STOPPED TO TALK WITH HUCKLEBERRY FINN!"
+
+The master's pulse stood still, and he stared helplessly. The buzz of
+study ceased. The pupils wondered if this foolhardy boy had lost his
+mind. The master said:
+
+"You--you did what?"
+
+"Stopped to talk with Huckleberry Finn."
+
+There was no mistaking the words.
+
+"Thomas Sawyer, this is the most astounding confession I have ever
+listened to. No mere ferule will answer for this offence. Take off your
+jacket."
+
+The master's arm performed until it was tired and the stock of
+switches notably diminished. Then the order followed:
+
+"Now, sir, go and sit with the girls! And let this be a warning to you."
+
+The titter that rippled around the room appeared to abash the boy, but
+in reality that result was caused rather more by his worshipful awe of
+his unknown idol and the dread pleasure that lay in his high good
+fortune. He sat down upon the end of the pine bench and the girl
+hitched herself away from him with a toss of her head. Nudges and winks
+and whispers traversed the room, but Tom sat still, with his arms upon
+the long, low desk before him, and seemed to study his book.
+
+By and by attention ceased from him, and the accustomed school murmur
+rose upon the dull air once more. Presently the boy began to steal
+furtive glances at the girl. She observed it, "made a mouth" at him and
+gave him the back of her head for the space of a minute. When she
+cautiously faced around again, a peach lay before her. She thrust it
+away. Tom gently put it back. She thrust it away again, but with less
+animosity. Tom patiently returned it to its place. Then she let it
+remain. Tom scrawled on his slate, "Please take it--I got more." The
+girl glanced at the words, but made no sign. Now the boy began to draw
+something on the slate, hiding his work with his left hand. For a time
+the girl refused to notice; but her human curiosity presently began to
+manifest itself by hardly perceptible signs. The boy worked on,
+apparently unconscious. The girl made a sort of noncommittal attempt to
+see, but the boy did not betray that he was aware of it. At last she
+gave in and hesitatingly whispered:
+
+"Let me see it."
+
+Tom partly uncovered a dismal caricature of a house with two gable
+ends to it and a corkscrew of smoke issuing from the chimney. Then the
+girl's interest began to fasten itself upon the work and she forgot
+everything else. When it was finished, she gazed a moment, then
+whispered:
+
+"It's nice--make a man."
+
+The artist erected a man in the front yard, that resembled a derrick.
+He could have stepped over the house; but the girl was not
+hypercritical; she was satisfied with the monster, and whispered:
+
+"It's a beautiful man--now make me coming along."
+
+Tom drew an hour-glass with a full moon and straw limbs to it and
+armed the spreading fingers with a portentous fan. The girl said:
+
+"It's ever so nice--I wish I could draw."
+
+"It's easy," whispered Tom, "I'll learn you."
+
+"Oh, will you? When?"
+
+"At noon. Do you go home to dinner?"
+
+"I'll stay if you will."
+
+"Good--that's a whack. What's your name?"
+
+"Becky Thatcher. What's yours? Oh, I know. It's Thomas Sawyer."
+
+"That's the name they lick me by. I'm Tom when I'm good. You call me
+Tom, will you?"
+
+"Yes."
+
+Now Tom began to scrawl something on the slate, hiding the words from
+the girl. But she was not backward this time. She begged to see. Tom
+said:
+
+"Oh, it ain't anything."
+
+"Yes it is."
+
+"No it ain't. You don't want to see."
+
+"Yes I do, indeed I do. Please let me."
+
+"You'll tell."
+
+"No I won't--deed and deed and double deed won't."
+
+"You won't tell anybody at all? Ever, as long as you live?"
+
+"No, I won't ever tell ANYbody. Now let me."
+
+"Oh, YOU don't want to see!"
+
+"Now that you treat me so, I WILL see." And she put her small hand
+upon his and a little scuffle ensued, Tom pretending to resist in
+earnest but letting his hand slip by degrees till these words were
+revealed: "I LOVE YOU."
+
+"Oh, you bad thing!" And she hit his hand a smart rap, but reddened
+and looked pleased, nevertheless.
+
+Just at this juncture the boy felt a slow, fateful grip closing on his
+ear, and a steady lifting impulse. In that wise he was borne across the
+house and deposited in his own seat, under a peppering fire of giggles
+from the whole school. Then the master stood over him during a few
+awful moments, and finally moved away to his throne without saying a
+word. But although Tom's ear tingled, his heart was jubilant.
+
+As the school quieted down Tom made an honest effort to study, but the
+turmoil within him was too great. In turn he took his place in the
+reading class and made a botch of it; then in the geography class and
+turned lakes into mountains, mountains into rivers, and rivers into
+continents, till chaos was come again; then in the spelling class, and
+got "turned down," by a succession of mere baby words, till he brought
+up at the foot and yielded up the pewter medal which he had worn with
+ostentation for months.
+
+
+
+CHAPTER VII
+
+THE harder Tom tried to fasten his mind on his book, the more his
+ideas wandered. So at last, with a sigh and a yawn, he gave it up. It
+seemed to him that the noon recess would never come. The air was
+utterly dead. There was not a breath stirring. It was the sleepiest of
+sleepy days. The drowsing murmur of the five and twenty studying
+scholars soothed the soul like the spell that is in the murmur of bees.
+Away off in the flaming sunshine, Cardiff Hill lifted its soft green
+sides through a shimmering veil of heat, tinted with the purple of
+distance; a few birds floated on lazy wing high in the air; no other
+living thing was visible but some cows, and they were asleep. Tom's
+heart ached to be free, or else to have something of interest to do to
+pass the dreary time. His hand wandered into his pocket and his face
+lit up with a glow of gratitude that was prayer, though he did not know
+it. Then furtively the percussion-cap box came out. He released the
+tick and put him on the long flat desk. The creature probably glowed
+with a gratitude that amounted to prayer, too, at this moment, but it
+was premature: for when he started thankfully to travel off, Tom turned
+him aside with a pin and made him take a new direction.
+
+Tom's bosom friend sat next him, suffering just as Tom had been, and
+now he was deeply and gratefully interested in this entertainment in an
+instant. This bosom friend was Joe Harper. The two boys were sworn
+friends all the week, and embattled enemies on Saturdays. Joe took a
+pin out of his lapel and began to assist in exercising the prisoner.
+The sport grew in interest momently. Soon Tom said that they were
+interfering with each other, and neither getting the fullest benefit of
+the tick. So he put Joe's slate on the desk and drew a line down the
+middle of it from top to bottom.
+
+"Now," said he, "as long as he is on your side you can stir him up and
+I'll let him alone; but if you let him get away and get on my side,
+you're to leave him alone as long as I can keep him from crossing over."
+
+"All right, go ahead; start him up."
+
+The tick escaped from Tom, presently, and crossed the equator. Joe
+harassed him awhile, and then he got away and crossed back again. This
+change of base occurred often. While one boy was worrying the tick with
+absorbing interest, the other would look on with interest as strong,
+the two heads bowed together over the slate, and the two souls dead to
+all things else. At last luck seemed to settle and abide with Joe. The
+tick tried this, that, and the other course, and got as excited and as
+anxious as the boys themselves, but time and again just as he would
+have victory in his very grasp, so to speak, and Tom's fingers would be
+twitching to begin, Joe's pin would deftly head him off, and keep
+possession. At last Tom could stand it no longer. The temptation was
+too strong. So he reached out and lent a hand with his pin. Joe was
+angry in a moment. Said he:
+
+"Tom, you let him alone."
+
+"I only just want to stir him up a little, Joe."
+
+"No, sir, it ain't fair; you just let him alone."
+
+"Blame it, I ain't going to stir him much."
+
+"Let him alone, I tell you."
+
+"I won't!"
+
+"You shall--he's on my side of the line."
+
+"Look here, Joe Harper, whose is that tick?"
+
+"I don't care whose tick he is--he's on my side of the line, and you
+sha'n't touch him."
+
+"Well, I'll just bet I will, though. He's my tick and I'll do what I
+blame please with him, or die!"
+
+A tremendous whack came down on Tom's shoulders, and its duplicate on
+Joe's; and for the space of two minutes the dust continued to fly from
+the two jackets and the whole school to enjoy it. The boys had been too
+absorbed to notice the hush that had stolen upon the school awhile
+before when the master came tiptoeing down the room and stood over
+them. He had contemplated a good part of the performance before he
+contributed his bit of variety to it.
+
+When school broke up at noon, Tom flew to Becky Thatcher, and
+whispered in her ear:
+
+"Put on your bonnet and let on you're going home; and when you get to
+the corner, give the rest of 'em the slip, and turn down through the
+lane and come back. I'll go the other way and come it over 'em the same
+way."
+
+So the one went off with one group of scholars, and the other with
+another. In a little while the two met at the bottom of the lane, and
+when they reached the school they had it all to themselves. Then they
+sat together, with a slate before them, and Tom gave Becky the pencil
+and held her hand in his, guiding it, and so created another surprising
+house. When the interest in art began to wane, the two fell to talking.
+Tom was swimming in bliss. He said:
+
+"Do you love rats?"
+
+"No! I hate them!"
+
+"Well, I do, too--LIVE ones. But I mean dead ones, to swing round your
+head with a string."
+
+"No, I don't care for rats much, anyway. What I like is chewing-gum."
+
+"Oh, I should say so! I wish I had some now."
+
+"Do you? I've got some. I'll let you chew it awhile, but you must give
+it back to me."
+
+That was agreeable, so they chewed it turn about, and dangled their
+legs against the bench in excess of contentment.
+
+"Was you ever at a circus?" said Tom.
+
+"Yes, and my pa's going to take me again some time, if I'm good."
+
+"I been to the circus three or four times--lots of times. Church ain't
+shucks to a circus. There's things going on at a circus all the time.
+I'm going to be a clown in a circus when I grow up."
+
+"Oh, are you! That will be nice. They're so lovely, all spotted up."
+
+"Yes, that's so. And they get slathers of money--most a dollar a day,
+Ben Rogers says. Say, Becky, was you ever engaged?"
+
+"What's that?"
+
+"Why, engaged to be married."
+
+"No."
+
+"Would you like to?"
+
+"I reckon so. I don't know. What is it like?"
+
+"Like? Why it ain't like anything. You only just tell a boy you won't
+ever have anybody but him, ever ever ever, and then you kiss and that's
+all. Anybody can do it."
+
+"Kiss? What do you kiss for?"
+
+"Why, that, you know, is to--well, they always do that."
+
+"Everybody?"
+
+"Why, yes, everybody that's in love with each other. Do you remember
+what I wrote on the slate?"
+
+"Ye--yes."
+
+"What was it?"
+
+"I sha'n't tell you."
+
+"Shall I tell YOU?"
+
+"Ye--yes--but some other time."
+
+"No, now."
+
+"No, not now--to-morrow."
+
+"Oh, no, NOW. Please, Becky--I'll whisper it, I'll whisper it ever so
+easy."
+
+Becky hesitating, Tom took silence for consent, and passed his arm
+about her waist and whispered the tale ever so softly, with his mouth
+close to her ear. And then he added:
+
+"Now you whisper it to me--just the same."
+
+She resisted, for a while, and then said:
+
+"You turn your face away so you can't see, and then I will. But you
+mustn't ever tell anybody--WILL you, Tom? Now you won't, WILL you?"
+
+"No, indeed, indeed I won't. Now, Becky."
+
+He turned his face away. She bent timidly around till her breath
+stirred his curls and whispered, "I--love--you!"
+
+Then she sprang away and ran around and around the desks and benches,
+with Tom after her, and took refuge in a corner at last, with her
+little white apron to her face. Tom clasped her about her neck and
+pleaded:
+
+"Now, Becky, it's all done--all over but the kiss. Don't you be afraid
+of that--it ain't anything at all. Please, Becky." And he tugged at her
+apron and the hands.
+
+By and by she gave up, and let her hands drop; her face, all glowing
+with the struggle, came up and submitted. Tom kissed the red lips and
+said:
+
+"Now it's all done, Becky. And always after this, you know, you ain't
+ever to love anybody but me, and you ain't ever to marry anybody but
+me, ever never and forever. Will you?"
+
+"No, I'll never love anybody but you, Tom, and I'll never marry
+anybody but you--and you ain't to ever marry anybody but me, either."
+
+"Certainly. Of course. That's PART of it. And always coming to school
+or when we're going home, you're to walk with me, when there ain't
+anybody looking--and you choose me and I choose you at parties, because
+that's the way you do when you're engaged."
+
+"It's so nice. I never heard of it before."
+
+"Oh, it's ever so gay! Why, me and Amy Lawrence--"
+
+The big eyes told Tom his blunder and he stopped, confused.
+
+"Oh, Tom! Then I ain't the first you've ever been engaged to!"
+
+The child began to cry. Tom said:
+
+"Oh, don't cry, Becky, I don't care for her any more."
+
+"Yes, you do, Tom--you know you do."
+
+Tom tried to put his arm about her neck, but she pushed him away and
+turned her face to the wall, and went on crying. Tom tried again, with
+soothing words in his mouth, and was repulsed again. Then his pride was
+up, and he strode away and went outside. He stood about, restless and
+uneasy, for a while, glancing at the door, every now and then, hoping
+she would repent and come to find him. But she did not. Then he began
+to feel badly and fear that he was in the wrong. It was a hard struggle
+with him to make new advances, now, but he nerved himself to it and
+entered. She was still standing back there in the corner, sobbing, with
+her face to the wall. Tom's heart smote him. He went to her and stood a
+moment, not knowing exactly how to proceed. Then he said hesitatingly:
+
+"Becky, I--I don't care for anybody but you."
+
+No reply--but sobs.
+
+"Becky"--pleadingly. "Becky, won't you say something?"
+
+More sobs.
+
+Tom got out his chiefest jewel, a brass knob from the top of an
+andiron, and passed it around her so that she could see it, and said:
+
+"Please, Becky, won't you take it?"
+
+She struck it to the floor. Then Tom marched out of the house and over
+the hills and far away, to return to school no more that day. Presently
+Becky began to suspect. She ran to the door; he was not in sight; she
+flew around to the play-yard; he was not there. Then she called:
+
+"Tom! Come back, Tom!"
+
+She listened intently, but there was no answer. She had no companions
+but silence and loneliness. So she sat down to cry again and upbraid
+herself; and by this time the scholars began to gather again, and she
+had to hide her griefs and still her broken heart and take up the cross
+of a long, dreary, aching afternoon, with none among the strangers
+about her to exchange sorrows with.
+
+
+
+CHAPTER VIII
+
+TOM dodged hither and thither through lanes until he was well out of
+the track of returning scholars, and then fell into a moody jog. He
+crossed a small "branch" two or three times, because of a prevailing
+juvenile superstition that to cross water baffled pursuit. Half an hour
+later he was disappearing behind the Douglas mansion on the summit of
+Cardiff Hill, and the schoolhouse was hardly distinguishable away off
+in the valley behind him. He entered a dense wood, picked his pathless
+way to the centre of it, and sat down on a mossy spot under a spreading
+oak. There was not even a zephyr stirring; the dead noonday heat had
+even stilled the songs of the birds; nature lay in a trance that was
+broken by no sound but the occasional far-off hammering of a
+woodpecker, and this seemed to render the pervading silence and sense
+of loneliness the more profound. The boy's soul was steeped in
+melancholy; his feelings were in happy accord with his surroundings. He
+sat long with his elbows on his knees and his chin in his hands,
+meditating. It seemed to him that life was but a trouble, at best, and
+he more than half envied Jimmy Hodges, so lately released; it must be
+very peaceful, he thought, to lie and slumber and dream forever and
+ever, with the wind whispering through the trees and caressing the
+grass and the flowers over the grave, and nothing to bother and grieve
+about, ever any more. If he only had a clean Sunday-school record he
+could be willing to go, and be done with it all. Now as to this girl.
+What had he done? Nothing. He had meant the best in the world, and been
+treated like a dog--like a very dog. She would be sorry some day--maybe
+when it was too late. Ah, if he could only die TEMPORARILY!
+
+But the elastic heart of youth cannot be compressed into one
+constrained shape long at a time. Tom presently began to drift
+insensibly back into the concerns of this life again. What if he turned
+his back, now, and disappeared mysteriously? What if he went away--ever
+so far away, into unknown countries beyond the seas--and never came
+back any more! How would she feel then! The idea of being a clown
+recurred to him now, only to fill him with disgust. For frivolity and
+jokes and spotted tights were an offense, when they intruded themselves
+upon a spirit that was exalted into the vague august realm of the
+romantic. No, he would be a soldier, and return after long years, all
+war-worn and illustrious. No--better still, he would join the Indians,
+and hunt buffaloes and go on the warpath in the mountain ranges and the
+trackless great plains of the Far West, and away in the future come
+back a great chief, bristling with feathers, hideous with paint, and
+prance into Sunday-school, some drowsy summer morning, with a
+bloodcurdling war-whoop, and sear the eyeballs of all his companions
+with unappeasable envy. But no, there was something gaudier even than
+this. He would be a pirate! That was it! NOW his future lay plain
+before him, and glowing with unimaginable splendor. How his name would
+fill the world, and make people shudder! How gloriously he would go
+plowing the dancing seas, in his long, low, black-hulled racer, the
+Spirit of the Storm, with his grisly flag flying at the fore! And at
+the zenith of his fame, how he would suddenly appear at the old village
+and stalk into church, brown and weather-beaten, in his black velvet
+doublet and trunks, his great jack-boots, his crimson sash, his belt
+bristling with horse-pistols, his crime-rusted cutlass at his side, his
+slouch hat with waving plumes, his black flag unfurled, with the skull
+and crossbones on it, and hear with swelling ecstasy the whisperings,
+"It's Tom Sawyer the Pirate!--the Black Avenger of the Spanish Main!"
+
+Yes, it was settled; his career was determined. He would run away from
+home and enter upon it. He would start the very next morning. Therefore
+he must now begin to get ready. He would collect his resources
+together. He went to a rotten log near at hand and began to dig under
+one end of it with his Barlow knife. He soon struck wood that sounded
+hollow. He put his hand there and uttered this incantation impressively:
+
+"What hasn't come here, come! What's here, stay here!"
+
+Then he scraped away the dirt, and exposed a pine shingle. He took it
+up and disclosed a shapely little treasure-house whose bottom and sides
+were of shingles. In it lay a marble. Tom's astonishment was boundless!
+He scratched his head with a perplexed air, and said:
+
+"Well, that beats anything!"
+
+Then he tossed the marble away pettishly, and stood cogitating. The
+truth was, that a superstition of his had failed, here, which he and
+all his comrades had always looked upon as infallible. If you buried a
+marble with certain necessary incantations, and left it alone a
+fortnight, and then opened the place with the incantation he had just
+used, you would find that all the marbles you had ever lost had
+gathered themselves together there, meantime, no matter how widely they
+had been separated. But now, this thing had actually and unquestionably
+failed. Tom's whole structure of faith was shaken to its foundations.
+He had many a time heard of this thing succeeding but never of its
+failing before. It did not occur to him that he had tried it several
+times before, himself, but could never find the hiding-places
+afterward. He puzzled over the matter some time, and finally decided
+that some witch had interfered and broken the charm. He thought he
+would satisfy himself on that point; so he searched around till he
+found a small sandy spot with a little funnel-shaped depression in it.
+He laid himself down and put his mouth close to this depression and
+called--
+
+"Doodle-bug, doodle-bug, tell me what I want to know! Doodle-bug,
+doodle-bug, tell me what I want to know!"
+
+The sand began to work, and presently a small black bug appeared for a
+second and then darted under again in a fright.
+
+"He dasn't tell! So it WAS a witch that done it. I just knowed it."
+
+He well knew the futility of trying to contend against witches, so he
+gave up discouraged. But it occurred to him that he might as well have
+the marble he had just thrown away, and therefore he went and made a
+patient search for it. But he could not find it. Now he went back to
+his treasure-house and carefully placed himself just as he had been
+standing when he tossed the marble away; then he took another marble
+from his pocket and tossed it in the same way, saying:
+
+"Brother, go find your brother!"
+
+He watched where it stopped, and went there and looked. But it must
+have fallen short or gone too far; so he tried twice more. The last
+repetition was successful. The two marbles lay within a foot of each
+other.
+
+Just here the blast of a toy tin trumpet came faintly down the green
+aisles of the forest. Tom flung off his jacket and trousers, turned a
+suspender into a belt, raked away some brush behind the rotten log,
+disclosing a rude bow and arrow, a lath sword and a tin trumpet, and in
+a moment had seized these things and bounded away, barelegged, with
+fluttering shirt. He presently halted under a great elm, blew an
+answering blast, and then began to tiptoe and look warily out, this way
+and that. He said cautiously--to an imaginary company:
+
+"Hold, my merry men! Keep hid till I blow."
+
+Now appeared Joe Harper, as airily clad and elaborately armed as Tom.
+Tom called:
+
+"Hold! Who comes here into Sherwood Forest without my pass?"
+
+"Guy of Guisborne wants no man's pass. Who art thou that--that--"
+
+"Dares to hold such language," said Tom, prompting--for they talked
+"by the book," from memory.
+
+"Who art thou that dares to hold such language?"
+
+"I, indeed! I am Robin Hood, as thy caitiff carcase soon shall know."
+
+"Then art thou indeed that famous outlaw? Right gladly will I dispute
+with thee the passes of the merry wood. Have at thee!"
+
+They took their lath swords, dumped their other traps on the ground,
+struck a fencing attitude, foot to foot, and began a grave, careful
+combat, "two up and two down." Presently Tom said:
+
+"Now, if you've got the hang, go it lively!"
+
+So they "went it lively," panting and perspiring with the work. By and
+by Tom shouted:
+
+"Fall! fall! Why don't you fall?"
+
+"I sha'n't! Why don't you fall yourself? You're getting the worst of
+it."
+
+"Why, that ain't anything. I can't fall; that ain't the way it is in
+the book. The book says, 'Then with one back-handed stroke he slew poor
+Guy of Guisborne.' You're to turn around and let me hit you in the
+back."
+
+There was no getting around the authorities, so Joe turned, received
+the whack and fell.
+
+"Now," said Joe, getting up, "you got to let me kill YOU. That's fair."
+
+"Why, I can't do that, it ain't in the book."
+
+"Well, it's blamed mean--that's all."
+
+"Well, say, Joe, you can be Friar Tuck or Much the miller's son, and
+lam me with a quarter-staff; or I'll be the Sheriff of Nottingham and
+you be Robin Hood a little while and kill me."
+
+This was satisfactory, and so these adventures were carried out. Then
+Tom became Robin Hood again, and was allowed by the treacherous nun to
+bleed his strength away through his neglected wound. And at last Joe,
+representing a whole tribe of weeping outlaws, dragged him sadly forth,
+gave his bow into his feeble hands, and Tom said, "Where this arrow
+falls, there bury poor Robin Hood under the greenwood tree." Then he
+shot the arrow and fell back and would have died, but he lit on a
+nettle and sprang up too gaily for a corpse.
+
+The boys dressed themselves, hid their accoutrements, and went off
+grieving that there were no outlaws any more, and wondering what modern
+civilization could claim to have done to compensate for their loss.
+They said they would rather be outlaws a year in Sherwood Forest than
+President of the United States forever.
+
+
+
+CHAPTER IX
+
+AT half-past nine, that night, Tom and Sid were sent to bed, as usual.
+They said their prayers, and Sid was soon asleep. Tom lay awake and
+waited, in restless impatience. When it seemed to him that it must be
+nearly daylight, he heard the clock strike ten! This was despair. He
+would have tossed and fidgeted, as his nerves demanded, but he was
+afraid he might wake Sid. So he lay still, and stared up into the dark.
+Everything was dismally still. By and by, out of the stillness, little,
+scarcely perceptible noises began to emphasize themselves. The ticking
+of the clock began to bring itself into notice. Old beams began to
+crack mysteriously. The stairs creaked faintly. Evidently spirits were
+abroad. A measured, muffled snore issued from Aunt Polly's chamber. And
+now the tiresome chirping of a cricket that no human ingenuity could
+locate, began. Next the ghastly ticking of a deathwatch in the wall at
+the bed's head made Tom shudder--it meant that somebody's days were
+numbered. Then the howl of a far-off dog rose on the night air, and was
+answered by a fainter howl from a remoter distance. Tom was in an
+agony. At last he was satisfied that time had ceased and eternity
+begun; he began to doze, in spite of himself; the clock chimed eleven,
+but he did not hear it. And then there came, mingling with his
+half-formed dreams, a most melancholy caterwauling. The raising of a
+neighboring window disturbed him. A cry of "Scat! you devil!" and the
+crash of an empty bottle against the back of his aunt's woodshed
+brought him wide awake, and a single minute later he was dressed and
+out of the window and creeping along the roof of the "ell" on all
+fours. He "meow'd" with caution once or twice, as he went; then jumped
+to the roof of the woodshed and thence to the ground. Huckleberry Finn
+was there, with his dead cat. The boys moved off and disappeared in the
+gloom. At the end of half an hour they were wading through the tall
+grass of the graveyard.
+
+It was a graveyard of the old-fashioned Western kind. It was on a
+hill, about a mile and a half from the village. It had a crazy board
+fence around it, which leaned inward in places, and outward the rest of
+the time, but stood upright nowhere. Grass and weeds grew rank over the
+whole cemetery. All the old graves were sunken in, there was not a
+tombstone on the place; round-topped, worm-eaten boards staggered over
+the graves, leaning for support and finding none. "Sacred to the memory
+of" So-and-So had been painted on them once, but it could no longer
+have been read, on the most of them, now, even if there had been light.
+
+A faint wind moaned through the trees, and Tom feared it might be the
+spirits of the dead, complaining at being disturbed. The boys talked
+little, and only under their breath, for the time and the place and the
+pervading solemnity and silence oppressed their spirits. They found the
+sharp new heap they were seeking, and ensconced themselves within the
+protection of three great elms that grew in a bunch within a few feet
+of the grave.
+
+Then they waited in silence for what seemed a long time. The hooting
+of a distant owl was all the sound that troubled the dead stillness.
+Tom's reflections grew oppressive. He must force some talk. So he said
+in a whisper:
+
+"Hucky, do you believe the dead people like it for us to be here?"
+
+Huckleberry whispered:
+
+"I wisht I knowed. It's awful solemn like, AIN'T it?"
+
+"I bet it is."
+
+There was a considerable pause, while the boys canvassed this matter
+inwardly. Then Tom whispered:
+
+"Say, Hucky--do you reckon Hoss Williams hears us talking?"
+
+"O' course he does. Least his sperrit does."
+
+Tom, after a pause:
+
+"I wish I'd said Mister Williams. But I never meant any harm.
+Everybody calls him Hoss."
+
+"A body can't be too partic'lar how they talk 'bout these-yer dead
+people, Tom."
+
+This was a damper, and conversation died again.
+
+Presently Tom seized his comrade's arm and said:
+
+"Sh!"
+
+"What is it, Tom?" And the two clung together with beating hearts.
+
+"Sh! There 'tis again! Didn't you hear it?"
+
+"I--"
+
+"There! Now you hear it."
+
+"Lord, Tom, they're coming! They're coming, sure. What'll we do?"
+
+"I dono. Think they'll see us?"
+
+"Oh, Tom, they can see in the dark, same as cats. I wisht I hadn't
+come."
+
+"Oh, don't be afeard. I don't believe they'll bother us. We ain't
+doing any harm. If we keep perfectly still, maybe they won't notice us
+at all."
+
+"I'll try to, Tom, but, Lord, I'm all of a shiver."
+
+"Listen!"
+
+The boys bent their heads together and scarcely breathed. A muffled
+sound of voices floated up from the far end of the graveyard.
+
+"Look! See there!" whispered Tom. "What is it?"
+
+"It's devil-fire. Oh, Tom, this is awful."
+
+Some vague figures approached through the gloom, swinging an
+old-fashioned tin lantern that freckled the ground with innumerable
+little spangles of light. Presently Huckleberry whispered with a
+shudder:
+
+"It's the devils sure enough. Three of 'em! Lordy, Tom, we're goners!
+Can you pray?"
+
+"I'll try, but don't you be afeard. They ain't going to hurt us. 'Now
+I lay me down to sleep, I--'"
+
+"Sh!"
+
+"What is it, Huck?"
+
+"They're HUMANS! One of 'em is, anyway. One of 'em's old Muff Potter's
+voice."
+
+"No--'tain't so, is it?"
+
+"I bet I know it. Don't you stir nor budge. He ain't sharp enough to
+notice us. Drunk, the same as usual, likely--blamed old rip!"
+
+"All right, I'll keep still. Now they're stuck. Can't find it. Here
+they come again. Now they're hot. Cold again. Hot again. Red hot!
+They're p'inted right, this time. Say, Huck, I know another o' them
+voices; it's Injun Joe."
+
+"That's so--that murderin' half-breed! I'd druther they was devils a
+dern sight. What kin they be up to?"
+
+The whisper died wholly out, now, for the three men had reached the
+grave and stood within a few feet of the boys' hiding-place.
+
+"Here it is," said the third voice; and the owner of it held the
+lantern up and revealed the face of young Doctor Robinson.
+
+Potter and Injun Joe were carrying a handbarrow with a rope and a
+couple of shovels on it. They cast down their load and began to open
+the grave. The doctor put the lantern at the head of the grave and came
+and sat down with his back against one of the elm trees. He was so
+close the boys could have touched him.
+
+"Hurry, men!" he said, in a low voice; "the moon might come out at any
+moment."
+
+They growled a response and went on digging. For some time there was
+no noise but the grating sound of the spades discharging their freight
+of mould and gravel. It was very monotonous. Finally a spade struck
+upon the coffin with a dull woody accent, and within another minute or
+two the men had hoisted it out on the ground. They pried off the lid
+with their shovels, got out the body and dumped it rudely on the
+ground. The moon drifted from behind the clouds and exposed the pallid
+face. The barrow was got ready and the corpse placed on it, covered
+with a blanket, and bound to its place with the rope. Potter took out a
+large spring-knife and cut off the dangling end of the rope and then
+said:
+
+"Now the cussed thing's ready, Sawbones, and you'll just out with
+another five, or here she stays."
+
+"That's the talk!" said Injun Joe.
+
+"Look here, what does this mean?" said the doctor. "You required your
+pay in advance, and I've paid you."
+
+"Yes, and you done more than that," said Injun Joe, approaching the
+doctor, who was now standing. "Five years ago you drove me away from
+your father's kitchen one night, when I come to ask for something to
+eat, and you said I warn't there for any good; and when I swore I'd get
+even with you if it took a hundred years, your father had me jailed for
+a vagrant. Did you think I'd forget? The Injun blood ain't in me for
+nothing. And now I've GOT you, and you got to SETTLE, you know!"
+
+He was threatening the doctor, with his fist in his face, by this
+time. The doctor struck out suddenly and stretched the ruffian on the
+ground. Potter dropped his knife, and exclaimed:
+
+"Here, now, don't you hit my pard!" and the next moment he had
+grappled with the doctor and the two were struggling with might and
+main, trampling the grass and tearing the ground with their heels.
+Injun Joe sprang to his feet, his eyes flaming with passion, snatched
+up Potter's knife, and went creeping, catlike and stooping, round and
+round about the combatants, seeking an opportunity. All at once the
+doctor flung himself free, seized the heavy headboard of Williams'
+grave and felled Potter to the earth with it--and in the same instant
+the half-breed saw his chance and drove the knife to the hilt in the
+young man's breast. He reeled and fell partly upon Potter, flooding him
+with his blood, and in the same moment the clouds blotted out the
+dreadful spectacle and the two frightened boys went speeding away in
+the dark.
+
+Presently, when the moon emerged again, Injun Joe was standing over
+the two forms, contemplating them. The doctor murmured inarticulately,
+gave a long gasp or two and was still. The half-breed muttered:
+
+"THAT score is settled--damn you."
+
+Then he robbed the body. After which he put the fatal knife in
+Potter's open right hand, and sat down on the dismantled coffin. Three
+--four--five minutes passed, and then Potter began to stir and moan. His
+hand closed upon the knife; he raised it, glanced at it, and let it
+fall, with a shudder. Then he sat up, pushing the body from him, and
+gazed at it, and then around him, confusedly. His eyes met Joe's.
+
+"Lord, how is this, Joe?" he said.
+
+"It's a dirty business," said Joe, without moving.
+
+"What did you do it for?"
+
+"I! I never done it!"
+
+"Look here! That kind of talk won't wash."
+
+Potter trembled and grew white.
+
+"I thought I'd got sober. I'd no business to drink to-night. But it's
+in my head yet--worse'n when we started here. I'm all in a muddle;
+can't recollect anything of it, hardly. Tell me, Joe--HONEST, now, old
+feller--did I do it? Joe, I never meant to--'pon my soul and honor, I
+never meant to, Joe. Tell me how it was, Joe. Oh, it's awful--and him
+so young and promising."
+
+"Why, you two was scuffling, and he fetched you one with the headboard
+and you fell flat; and then up you come, all reeling and staggering
+like, and snatched the knife and jammed it into him, just as he fetched
+you another awful clip--and here you've laid, as dead as a wedge til
+now."
+
+"Oh, I didn't know what I was a-doing. I wish I may die this minute if
+I did. It was all on account of the whiskey and the excitement, I
+reckon. I never used a weepon in my life before, Joe. I've fought, but
+never with weepons. They'll all say that. Joe, don't tell! Say you
+won't tell, Joe--that's a good feller. I always liked you, Joe, and
+stood up for you, too. Don't you remember? You WON'T tell, WILL you,
+Joe?" And the poor creature dropped on his knees before the stolid
+murderer, and clasped his appealing hands.
+
+"No, you've always been fair and square with me, Muff Potter, and I
+won't go back on you. There, now, that's as fair as a man can say."
+
+"Oh, Joe, you're an angel. I'll bless you for this the longest day I
+live." And Potter began to cry.
+
+"Come, now, that's enough of that. This ain't any time for blubbering.
+You be off yonder way and I'll go this. Move, now, and don't leave any
+tracks behind you."
+
+Potter started on a trot that quickly increased to a run. The
+half-breed stood looking after him. He muttered:
+
+"If he's as much stunned with the lick and fuddled with the rum as he
+had the look of being, he won't think of the knife till he's gone so
+far he'll be afraid to come back after it to such a place by himself
+--chicken-heart!"
+
+Two or three minutes later the murdered man, the blanketed corpse, the
+lidless coffin, and the open grave were under no inspection but the
+moon's. The stillness was complete again, too.
+
+
+
+CHAPTER X
+
+THE two boys flew on and on, toward the village, speechless with
+horror. They glanced backward over their shoulders from time to time,
+apprehensively, as if they feared they might be followed. Every stump
+that started up in their path seemed a man and an enemy, and made them
+catch their breath; and as they sped by some outlying cottages that lay
+near the village, the barking of the aroused watch-dogs seemed to give
+wings to their feet.
+
+"If we can only get to the old tannery before we break down!"
+whispered Tom, in short catches between breaths. "I can't stand it much
+longer."
+
+Huckleberry's hard pantings were his only reply, and the boys fixed
+their eyes on the goal of their hopes and bent to their work to win it.
+They gained steadily on it, and at last, breast to breast, they burst
+through the open door and fell grateful and exhausted in the sheltering
+shadows beyond. By and by their pulses slowed down, and Tom whispered:
+
+"Huckleberry, what do you reckon'll come of this?"
+
+"If Doctor Robinson dies, I reckon hanging'll come of it."
+
+"Do you though?"
+
+"Why, I KNOW it, Tom."
+
+Tom thought a while, then he said:
+
+"Who'll tell? We?"
+
+"What are you talking about? S'pose something happened and Injun Joe
+DIDN'T hang? Why, he'd kill us some time or other, just as dead sure as
+we're a laying here."
+
+"That's just what I was thinking to myself, Huck."
+
+"If anybody tells, let Muff Potter do it, if he's fool enough. He's
+generally drunk enough."
+
+Tom said nothing--went on thinking. Presently he whispered:
+
+"Huck, Muff Potter don't know it. How can he tell?"
+
+"What's the reason he don't know it?"
+
+"Because he'd just got that whack when Injun Joe done it. D'you reckon
+he could see anything? D'you reckon he knowed anything?"
+
+"By hokey, that's so, Tom!"
+
+"And besides, look-a-here--maybe that whack done for HIM!"
+
+"No, 'taint likely, Tom. He had liquor in him; I could see that; and
+besides, he always has. Well, when pap's full, you might take and belt
+him over the head with a church and you couldn't phase him. He says so,
+his own self. So it's the same with Muff Potter, of course. But if a
+man was dead sober, I reckon maybe that whack might fetch him; I dono."
+
+After another reflective silence, Tom said:
+
+"Hucky, you sure you can keep mum?"
+
+"Tom, we GOT to keep mum. You know that. That Injun devil wouldn't
+make any more of drownding us than a couple of cats, if we was to
+squeak 'bout this and they didn't hang him. Now, look-a-here, Tom, less
+take and swear to one another--that's what we got to do--swear to keep
+mum."
+
+"I'm agreed. It's the best thing. Would you just hold hands and swear
+that we--"
+
+"Oh no, that wouldn't do for this. That's good enough for little
+rubbishy common things--specially with gals, cuz THEY go back on you
+anyway, and blab if they get in a huff--but there orter be writing
+'bout a big thing like this. And blood."
+
+Tom's whole being applauded this idea. It was deep, and dark, and
+awful; the hour, the circumstances, the surroundings, were in keeping
+with it. He picked up a clean pine shingle that lay in the moonlight,
+took a little fragment of "red keel" out of his pocket, got the moon on
+his work, and painfully scrawled these lines, emphasizing each slow
+down-stroke by clamping his tongue between his teeth, and letting up
+the pressure on the up-strokes. [See next page.]
+
+   "Huck Finn and
+    Tom Sawyer swears
+    they will keep mum
+    about This and They
+    wish They may Drop
+    down dead in Their
+    Tracks if They ever
+    Tell and Rot."
+
+Huckleberry was filled with admiration of Tom's facility in writing,
+and the sublimity of his language. He at once took a pin from his lapel
+and was going to prick his flesh, but Tom said:
+
+"Hold on! Don't do that. A pin's brass. It might have verdigrease on
+it."
+
+"What's verdigrease?"
+
+"It's p'ison. That's what it is. You just swaller some of it once
+--you'll see."
+
+So Tom unwound the thread from one of his needles, and each boy
+pricked the ball of his thumb and squeezed out a drop of blood. In
+time, after many squeezes, Tom managed to sign his initials, using the
+ball of his little finger for a pen. Then he showed Huckleberry how to
+make an H and an F, and the oath was complete. They buried the shingle
+close to the wall, with some dismal ceremonies and incantations, and
+the fetters that bound their tongues were considered to be locked and
+the key thrown away.
+
+A figure crept stealthily through a break in the other end of the
+ruined building, now, but they did not notice it.
+
+"Tom," whispered Huckleberry, "does this keep us from EVER telling
+--ALWAYS?"
+
+"Of course it does. It don't make any difference WHAT happens, we got
+to keep mum. We'd drop down dead--don't YOU know that?"
+
+"Yes, I reckon that's so."
+
+They continued to whisper for some little time. Presently a dog set up
+a long, lugubrious howl just outside--within ten feet of them. The boys
+clasped each other suddenly, in an agony of fright.
+
+"Which of us does he mean?" gasped Huckleberry.
+
+"I dono--peep through the crack. Quick!"
+
+"No, YOU, Tom!"
+
+"I can't--I can't DO it, Huck!"
+
+"Please, Tom. There 'tis again!"
+
+"Oh, lordy, I'm thankful!" whispered Tom. "I know his voice. It's Bull
+Harbison." *
+
+[* If Mr. Harbison owned a slave named Bull, Tom would have spoken of
+him as "Harbison's Bull," but a son or a dog of that name was "Bull
+Harbison."]
+
+"Oh, that's good--I tell you, Tom, I was most scared to death; I'd a
+bet anything it was a STRAY dog."
+
+The dog howled again. The boys' hearts sank once more.
+
+"Oh, my! that ain't no Bull Harbison!" whispered Huckleberry. "DO, Tom!"
+
+Tom, quaking with fear, yielded, and put his eye to the crack. His
+whisper was hardly audible when he said:
+
+"Oh, Huck, IT S A STRAY DOG!"
+
+"Quick, Tom, quick! Who does he mean?"
+
+"Huck, he must mean us both--we're right together."
+
+"Oh, Tom, I reckon we're goners. I reckon there ain't no mistake 'bout
+where I'LL go to. I been so wicked."
+
+"Dad fetch it! This comes of playing hookey and doing everything a
+feller's told NOT to do. I might a been good, like Sid, if I'd a tried
+--but no, I wouldn't, of course. But if ever I get off this time, I lay
+I'll just WALLER in Sunday-schools!" And Tom began to snuffle a little.
+
+"YOU bad!" and Huckleberry began to snuffle too. "Consound it, Tom
+Sawyer, you're just old pie, 'longside o' what I am. Oh, LORDY, lordy,
+lordy, I wisht I only had half your chance."
+
+Tom choked off and whispered:
+
+"Look, Hucky, look! He's got his BACK to us!"
+
+Hucky looked, with joy in his heart.
+
+"Well, he has, by jingoes! Did he before?"
+
+"Yes, he did. But I, like a fool, never thought. Oh, this is bully,
+you know. NOW who can he mean?"
+
+The howling stopped. Tom pricked up his ears.
+
+"Sh! What's that?" he whispered.
+
+"Sounds like--like hogs grunting. No--it's somebody snoring, Tom."
+
+"That IS it! Where 'bouts is it, Huck?"
+
+"I bleeve it's down at 'tother end. Sounds so, anyway. Pap used to
+sleep there, sometimes, 'long with the hogs, but laws bless you, he
+just lifts things when HE snores. Besides, I reckon he ain't ever
+coming back to this town any more."
+
+The spirit of adventure rose in the boys' souls once more.
+
+"Hucky, do you das't to go if I lead?"
+
+"I don't like to, much. Tom, s'pose it's Injun Joe!"
+
+Tom quailed. But presently the temptation rose up strong again and the
+boys agreed to try, with the understanding that they would take to
+their heels if the snoring stopped. So they went tiptoeing stealthily
+down, the one behind the other. When they had got to within five steps
+of the snorer, Tom stepped on a stick, and it broke with a sharp snap.
+The man moaned, writhed a little, and his face came into the moonlight.
+It was Muff Potter. The boys' hearts had stood still, and their hopes
+too, when the man moved, but their fears passed away now. They tiptoed
+out, through the broken weather-boarding, and stopped at a little
+distance to exchange a parting word. That long, lugubrious howl rose on
+the night air again! They turned and saw the strange dog standing
+within a few feet of where Potter was lying, and FACING Potter, with
+his nose pointing heavenward.
+
+"Oh, geeminy, it's HIM!" exclaimed both boys, in a breath.
+
+"Say, Tom--they say a stray dog come howling around Johnny Miller's
+house, 'bout midnight, as much as two weeks ago; and a whippoorwill
+come in and lit on the banisters and sung, the very same evening; and
+there ain't anybody dead there yet."
+
+"Well, I know that. And suppose there ain't. Didn't Gracie Miller fall
+in the kitchen fire and burn herself terrible the very next Saturday?"
+
+"Yes, but she ain't DEAD. And what's more, she's getting better, too."
+
+"All right, you wait and see. She's a goner, just as dead sure as Muff
+Potter's a goner. That's what the niggers say, and they know all about
+these kind of things, Huck."
+
+Then they separated, cogitating. When Tom crept in at his bedroom
+window the night was almost spent. He undressed with excessive caution,
+and fell asleep congratulating himself that nobody knew of his
+escapade. He was not aware that the gently-snoring Sid was awake, and
+had been so for an hour.
+
+When Tom awoke, Sid was dressed and gone. There was a late look in the
+light, a late sense in the atmosphere. He was startled. Why had he not
+been called--persecuted till he was up, as usual? The thought filled
+him with bodings. Within five minutes he was dressed and down-stairs,
+feeling sore and drowsy. The family were still at table, but they had
+finished breakfast. There was no voice of rebuke; but there were
+averted eyes; there was a silence and an air of solemnity that struck a
+chill to the culprit's heart. He sat down and tried to seem gay, but it
+was up-hill work; it roused no smile, no response, and he lapsed into
+silence and let his heart sink down to the depths.
+
+After breakfast his aunt took him aside, and Tom almost brightened in
+the hope that he was going to be flogged; but it was not so. His aunt
+wept over him and asked him how he could go and break her old heart so;
+and finally told him to go on, and ruin himself and bring her gray
+hairs with sorrow to the grave, for it was no use for her to try any
+more. This was worse than a thousand whippings, and Tom's heart was
+sorer now than his body. He cried, he pleaded for forgiveness, promised
+to reform over and over again, and then received his dismissal, feeling
+that he had won but an imperfect forgiveness and established but a
+feeble confidence.
+
+He left the presence too miserable to even feel revengeful toward Sid;
+and so the latter's prompt retreat through the back gate was
+unnecessary. He moped to school gloomy and sad, and took his flogging,
+along with Joe Harper, for playing hookey the day before, with the air
+of one whose heart was busy with heavier woes and wholly dead to
+trifles. Then he betook himself to his seat, rested his elbows on his
+desk and his jaws in his hands, and stared at the wall with the stony
+stare of suffering that has reached the limit and can no further go.
+His elbow was pressing against some hard substance. After a long time
+he slowly and sadly changed his position, and took up this object with
+a sigh. It was in a paper. He unrolled it. A long, lingering, colossal
+sigh followed, and his heart broke. It was his brass andiron knob!
+
+This final feather broke the camel's back.
+
+
+
+CHAPTER XI
+
+CLOSE upon the hour of noon the whole village was suddenly electrified
+with the ghastly news. No need of the as yet undreamed-of telegraph;
+the tale flew from man to man, from group to group, from house to
+house, with little less than telegraphic speed. Of course the
+schoolmaster gave holiday for that afternoon; the town would have
+thought strangely of him if he had not.
+
+A gory knife had been found close to the murdered man, and it had been
+recognized by somebody as belonging to Muff Potter--so the story ran.
+And it was said that a belated citizen had come upon Potter washing
+himself in the "branch" about one or two o'clock in the morning, and
+that Potter had at once sneaked off--suspicious circumstances,
+especially the washing which was not a habit with Potter. It was also
+said that the town had been ransacked for this "murderer" (the public
+are not slow in the matter of sifting evidence and arriving at a
+verdict), but that he could not be found. Horsemen had departed down
+all the roads in every direction, and the Sheriff "was confident" that
+he would be captured before night.
+
+All the town was drifting toward the graveyard. Tom's heartbreak
+vanished and he joined the procession, not because he would not a
+thousand times rather go anywhere else, but because an awful,
+unaccountable fascination drew him on. Arrived at the dreadful place,
+he wormed his small body through the crowd and saw the dismal
+spectacle. It seemed to him an age since he was there before. Somebody
+pinched his arm. He turned, and his eyes met Huckleberry's. Then both
+looked elsewhere at once, and wondered if anybody had noticed anything
+in their mutual glance. But everybody was talking, and intent upon the
+grisly spectacle before them.
+
+"Poor fellow!" "Poor young fellow!" "This ought to be a lesson to
+grave robbers!" "Muff Potter'll hang for this if they catch him!" This
+was the drift of remark; and the minister said, "It was a judgment; His
+hand is here."
+
+Now Tom shivered from head to heel; for his eye fell upon the stolid
+face of Injun Joe. At this moment the crowd began to sway and struggle,
+and voices shouted, "It's him! it's him! he's coming himself!"
+
+"Who? Who?" from twenty voices.
+
+"Muff Potter!"
+
+"Hallo, he's stopped!--Look out, he's turning! Don't let him get away!"
+
+People in the branches of the trees over Tom's head said he wasn't
+trying to get away--he only looked doubtful and perplexed.
+
+"Infernal impudence!" said a bystander; "wanted to come and take a
+quiet look at his work, I reckon--didn't expect any company."
+
+The crowd fell apart, now, and the Sheriff came through,
+ostentatiously leading Potter by the arm. The poor fellow's face was
+haggard, and his eyes showed the fear that was upon him. When he stood
+before the murdered man, he shook as with a palsy, and he put his face
+in his hands and burst into tears.
+
+"I didn't do it, friends," he sobbed; "'pon my word and honor I never
+done it."
+
+"Who's accused you?" shouted a voice.
+
+This shot seemed to carry home. Potter lifted his face and looked
+around him with a pathetic hopelessness in his eyes. He saw Injun Joe,
+and exclaimed:
+
+"Oh, Injun Joe, you promised me you'd never--"
+
+"Is that your knife?" and it was thrust before him by the Sheriff.
+
+Potter would have fallen if they had not caught him and eased him to
+the ground. Then he said:
+
+"Something told me 't if I didn't come back and get--" He shuddered;
+then waved his nerveless hand with a vanquished gesture and said, "Tell
+'em, Joe, tell 'em--it ain't any use any more."
+
+Then Huckleberry and Tom stood dumb and staring, and heard the
+stony-hearted liar reel off his serene statement, they expecting every
+moment that the clear sky would deliver God's lightnings upon his head,
+and wondering to see how long the stroke was delayed. And when he had
+finished and still stood alive and whole, their wavering impulse to
+break their oath and save the poor betrayed prisoner's life faded and
+vanished away, for plainly this miscreant had sold himself to Satan and
+it would be fatal to meddle with the property of such a power as that.
+
+"Why didn't you leave? What did you want to come here for?" somebody
+said.
+
+"I couldn't help it--I couldn't help it," Potter moaned. "I wanted to
+run away, but I couldn't seem to come anywhere but here." And he fell
+to sobbing again.
+
+Injun Joe repeated his statement, just as calmly, a few minutes
+afterward on the inquest, under oath; and the boys, seeing that the
+lightnings were still withheld, were confirmed in their belief that Joe
+had sold himself to the devil. He was now become, to them, the most
+balefully interesting object they had ever looked upon, and they could
+not take their fascinated eyes from his face.
+
+They inwardly resolved to watch him nights, when opportunity should
+offer, in the hope of getting a glimpse of his dread master.
+
+Injun Joe helped to raise the body of the murdered man and put it in a
+wagon for removal; and it was whispered through the shuddering crowd
+that the wound bled a little! The boys thought that this happy
+circumstance would turn suspicion in the right direction; but they were
+disappointed, for more than one villager remarked:
+
+"It was within three feet of Muff Potter when it done it."
+
+Tom's fearful secret and gnawing conscience disturbed his sleep for as
+much as a week after this; and at breakfast one morning Sid said:
+
+"Tom, you pitch around and talk in your sleep so much that you keep me
+awake half the time."
+
+Tom blanched and dropped his eyes.
+
+"It's a bad sign," said Aunt Polly, gravely. "What you got on your
+mind, Tom?"
+
+"Nothing. Nothing 't I know of." But the boy's hand shook so that he
+spilled his coffee.
+
+"And you do talk such stuff," Sid said. "Last night you said, 'It's
+blood, it's blood, that's what it is!' You said that over and over. And
+you said, 'Don't torment me so--I'll tell!' Tell WHAT? What is it
+you'll tell?"
+
+Everything was swimming before Tom. There is no telling what might
+have happened, now, but luckily the concern passed out of Aunt Polly's
+face and she came to Tom's relief without knowing it. She said:
+
+"Sho! It's that dreadful murder. I dream about it most every night
+myself. Sometimes I dream it's me that done it."
+
+Mary said she had been affected much the same way. Sid seemed
+satisfied. Tom got out of the presence as quick as he plausibly could,
+and after that he complained of toothache for a week, and tied up his
+jaws every night. He never knew that Sid lay nightly watching, and
+frequently slipped the bandage free and then leaned on his elbow
+listening a good while at a time, and afterward slipped the bandage
+back to its place again. Tom's distress of mind wore off gradually and
+the toothache grew irksome and was discarded. If Sid really managed to
+make anything out of Tom's disjointed mutterings, he kept it to himself.
+
+It seemed to Tom that his schoolmates never would get done holding
+inquests on dead cats, and thus keeping his trouble present to his
+mind. Sid noticed that Tom never was coroner at one of these inquiries,
+though it had been his habit to take the lead in all new enterprises;
+he noticed, too, that Tom never acted as a witness--and that was
+strange; and Sid did not overlook the fact that Tom even showed a
+marked aversion to these inquests, and always avoided them when he
+could. Sid marvelled, but said nothing. However, even inquests went out
+of vogue at last, and ceased to torture Tom's conscience.
+
+Every day or two, during this time of sorrow, Tom watched his
+opportunity and went to the little grated jail-window and smuggled such
+small comforts through to the "murderer" as he could get hold of. The
+jail was a trifling little brick den that stood in a marsh at the edge
+of the village, and no guards were afforded for it; indeed, it was
+seldom occupied. These offerings greatly helped to ease Tom's
+conscience.
+
+The villagers had a strong desire to tar-and-feather Injun Joe and
+ride him on a rail, for body-snatching, but so formidable was his
+character that nobody could be found who was willing to take the lead
+in the matter, so it was dropped. He had been careful to begin both of
+his inquest-statements with the fight, without confessing the
+grave-robbery that preceded it; therefore it was deemed wisest not
+to try the case in the courts at present.
+
+
+
+CHAPTER XII
+
+ONE of the reasons why Tom's mind had drifted away from its secret
+troubles was, that it had found a new and weighty matter to interest
+itself about. Becky Thatcher had stopped coming to school. Tom had
+struggled with his pride a few days, and tried to "whistle her down the
+wind," but failed. He began to find himself hanging around her father's
+house, nights, and feeling very miserable. She was ill. What if she
+should die! There was distraction in the thought. He no longer took an
+interest in war, nor even in piracy. The charm of life was gone; there
+was nothing but dreariness left. He put his hoop away, and his bat;
+there was no joy in them any more. His aunt was concerned. She began to
+try all manner of remedies on him. She was one of those people who are
+infatuated with patent medicines and all new-fangled methods of
+producing health or mending it. She was an inveterate experimenter in
+these things. When something fresh in this line came out she was in a
+fever, right away, to try it; not on herself, for she was never ailing,
+but on anybody else that came handy. She was a subscriber for all the
+"Health" periodicals and phrenological frauds; and the solemn ignorance
+they were inflated with was breath to her nostrils. All the "rot" they
+contained about ventilation, and how to go to bed, and how to get up,
+and what to eat, and what to drink, and how much exercise to take, and
+what frame of mind to keep one's self in, and what sort of clothing to
+wear, was all gospel to her, and she never observed that her
+health-journals of the current month customarily upset everything they
+had recommended the month before. She was as simple-hearted and honest
+as the day was long, and so she was an easy victim. She gathered
+together her quack periodicals and her quack medicines, and thus armed
+with death, went about on her pale horse, metaphorically speaking, with
+"hell following after." But she never suspected that she was not an
+angel of healing and the balm of Gilead in disguise, to the suffering
+neighbors.
+
+The water treatment was new, now, and Tom's low condition was a
+windfall to her. She had him out at daylight every morning, stood him
+up in the woodshed and drowned him with a deluge of cold water; then
+she scrubbed him down with a towel like a file, and so brought him to;
+then she rolled him up in a wet sheet and put him away under blankets
+till she sweated his soul clean and "the yellow stains of it came
+through his pores"--as Tom said.
+
+Yet notwithstanding all this, the boy grew more and more melancholy
+and pale and dejected. She added hot baths, sitz baths, shower baths,
+and plunges. The boy remained as dismal as a hearse. She began to
+assist the water with a slim oatmeal diet and blister-plasters. She
+calculated his capacity as she would a jug's, and filled him up every
+day with quack cure-alls.
+
+Tom had become indifferent to persecution by this time. This phase
+filled the old lady's heart with consternation. This indifference must
+be broken up at any cost. Now she heard of Pain-killer for the first
+time. She ordered a lot at once. She tasted it and was filled with
+gratitude. It was simply fire in a liquid form. She dropped the water
+treatment and everything else, and pinned her faith to Pain-killer. She
+gave Tom a teaspoonful and watched with the deepest anxiety for the
+result. Her troubles were instantly at rest, her soul at peace again;
+for the "indifference" was broken up. The boy could not have shown a
+wilder, heartier interest, if she had built a fire under him.
+
+Tom felt that it was time to wake up; this sort of life might be
+romantic enough, in his blighted condition, but it was getting to have
+too little sentiment and too much distracting variety about it. So he
+thought over various plans for relief, and finally hit pon that of
+professing to be fond of Pain-killer. He asked for it so often that he
+became a nuisance, and his aunt ended by telling him to help himself
+and quit bothering her. If it had been Sid, she would have had no
+misgivings to alloy her delight; but since it was Tom, she watched the
+bottle clandestinely. She found that the medicine did really diminish,
+but it did not occur to her that the boy was mending the health of a
+crack in the sitting-room floor with it.
+
+One day Tom was in the act of dosing the crack when his aunt's yellow
+cat came along, purring, eying the teaspoon avariciously, and begging
+for a taste. Tom said:
+
+"Don't ask for it unless you want it, Peter."
+
+But Peter signified that he did want it.
+
+"You better make sure."
+
+Peter was sure.
+
+"Now you've asked for it, and I'll give it to you, because there ain't
+anything mean about me; but if you find you don't like it, you mustn't
+blame anybody but your own self."
+
+Peter was agreeable. So Tom pried his mouth open and poured down the
+Pain-killer. Peter sprang a couple of yards in the air, and then
+delivered a war-whoop and set off round and round the room, banging
+against furniture, upsetting flower-pots, and making general havoc.
+Next he rose on his hind feet and pranced around, in a frenzy of
+enjoyment, with his head over his shoulder and his voice proclaiming
+his unappeasable happiness. Then he went tearing around the house again
+spreading chaos and destruction in his path. Aunt Polly entered in time
+to see him throw a few double summersets, deliver a final mighty
+hurrah, and sail through the open window, carrying the rest of the
+flower-pots with him. The old lady stood petrified with astonishment,
+peering over her glasses; Tom lay on the floor expiring with laughter.
+
+"Tom, what on earth ails that cat?"
+
+"I don't know, aunt," gasped the boy.
+
+"Why, I never see anything like it. What did make him act so?"
+
+"Deed I don't know, Aunt Polly; cats always act so when they're having
+a good time."
+
+"They do, do they?" There was something in the tone that made Tom
+apprehensive.
+
+"Yes'm. That is, I believe they do."
+
+"You DO?"
+
+"Yes'm."
+
+The old lady was bending down, Tom watching, with interest emphasized
+by anxiety. Too late he divined her "drift." The handle of the telltale
+teaspoon was visible under the bed-valance. Aunt Polly took it, held it
+up. Tom winced, and dropped his eyes. Aunt Polly raised him by the
+usual handle--his ear--and cracked his head soundly with her thimble.
+
+"Now, sir, what did you want to treat that poor dumb beast so, for?"
+
+"I done it out of pity for him--because he hadn't any aunt."
+
+"Hadn't any aunt!--you numskull. What has that got to do with it?"
+
+"Heaps. Because if he'd had one she'd a burnt him out herself! She'd a
+roasted his bowels out of him 'thout any more feeling than if he was a
+human!"
+
+Aunt Polly felt a sudden pang of remorse. This was putting the thing
+in a new light; what was cruelty to a cat MIGHT be cruelty to a boy,
+too. She began to soften; she felt sorry. Her eyes watered a little,
+and she put her hand on Tom's head and said gently:
+
+"I was meaning for the best, Tom. And, Tom, it DID do you good."
+
+Tom looked up in her face with just a perceptible twinkle peeping
+through his gravity.
+
+"I know you was meaning for the best, aunty, and so was I with Peter.
+It done HIM good, too. I never see him get around so since--"
+
+"Oh, go 'long with you, Tom, before you aggravate me again. And you
+try and see if you can't be a good boy, for once, and you needn't take
+any more medicine."
+
+Tom reached school ahead of time. It was noticed that this strange
+thing had been occurring every day latterly. And now, as usual of late,
+he hung about the gate of the schoolyard instead of playing with his
+comrades. He was sick, he said, and he looked it. He tried to seem to
+be looking everywhere but whither he really was looking--down the road.
+Presently Jeff Thatcher hove in sight, and Tom's face lighted; he gazed
+a moment, and then turned sorrowfully away. When Jeff arrived, Tom
+accosted him; and "led up" warily to opportunities for remark about
+Becky, but the giddy lad never could see the bait. Tom watched and
+watched, hoping whenever a frisking frock came in sight, and hating the
+owner of it as soon as he saw she was not the right one. At last frocks
+ceased to appear, and he dropped hopelessly into the dumps; he entered
+the empty schoolhouse and sat down to suffer. Then one more frock
+passed in at the gate, and Tom's heart gave a great bound. The next
+instant he was out, and "going on" like an Indian; yelling, laughing,
+chasing boys, jumping over the fence at risk of life and limb, throwing
+handsprings, standing on his head--doing all the heroic things he could
+conceive of, and keeping a furtive eye out, all the while, to see if
+Becky Thatcher was noticing. But she seemed to be unconscious of it
+all; she never looked. Could it be possible that she was not aware that
+he was there? He carried his exploits to her immediate vicinity; came
+war-whooping around, snatched a boy's cap, hurled it to the roof of the
+schoolhouse, broke through a group of boys, tumbling them in every
+direction, and fell sprawling, himself, under Becky's nose, almost
+upsetting her--and she turned, with her nose in the air, and he heard
+her say: "Mf! some people think they're mighty smart--always showing
+off!"
+
+Tom's cheeks burned. He gathered himself up and sneaked off, crushed
+and crestfallen.
+
+
+
+CHAPTER XIII
+
+TOM'S mind was made up now. He was gloomy and desperate. He was a
+forsaken, friendless boy, he said; nobody loved him; when they found
+out what they had driven him to, perhaps they would be sorry; he had
+tried to do right and get along, but they would not let him; since
+nothing would do them but to be rid of him, let it be so; and let them
+blame HIM for the consequences--why shouldn't they? What right had the
+friendless to complain? Yes, they had forced him to it at last: he
+would lead a life of crime. There was no choice.
+
+By this time he was far down Meadow Lane, and the bell for school to
+"take up" tinkled faintly upon his ear. He sobbed, now, to think he
+should never, never hear that old familiar sound any more--it was very
+hard, but it was forced on him; since he was driven out into the cold
+world, he must submit--but he forgave them. Then the sobs came thick
+and fast.
+
+Just at this point he met his soul's sworn comrade, Joe Harper
+--hard-eyed, and with evidently a great and dismal purpose in his heart.
+Plainly here were "two souls with but a single thought." Tom, wiping
+his eyes with his sleeve, began to blubber out something about a
+resolution to escape from hard usage and lack of sympathy at home by
+roaming abroad into the great world never to return; and ended by
+hoping that Joe would not forget him.
+
+But it transpired that this was a request which Joe had just been
+going to make of Tom, and had come to hunt him up for that purpose. His
+mother had whipped him for drinking some cream which he had never
+tasted and knew nothing about; it was plain that she was tired of him
+and wished him to go; if she felt that way, there was nothing for him
+to do but succumb; he hoped she would be happy, and never regret having
+driven her poor boy out into the unfeeling world to suffer and die.
+
+As the two boys walked sorrowing along, they made a new compact to
+stand by each other and be brothers and never separate till death
+relieved them of their troubles. Then they began to lay their plans.
+Joe was for being a hermit, and living on crusts in a remote cave, and
+dying, some time, of cold and want and grief; but after listening to
+Tom, he conceded that there were some conspicuous advantages about a
+life of crime, and so he consented to be a pirate.
+
+Three miles below St. Petersburg, at a point where the Mississippi
+River was a trifle over a mile wide, there was a long, narrow, wooded
+island, with a shallow bar at the head of it, and this offered well as
+a rendezvous. It was not inhabited; it lay far over toward the further
+shore, abreast a dense and almost wholly unpeopled forest. So Jackson's
+Island was chosen. Who were to be the subjects of their piracies was a
+matter that did not occur to them. Then they hunted up Huckleberry
+Finn, and he joined them promptly, for all careers were one to him; he
+was indifferent. They presently separated to meet at a lonely spot on
+the river-bank two miles above the village at the favorite hour--which
+was midnight. There was a small log raft there which they meant to
+capture. Each would bring hooks and lines, and such provision as he
+could steal in the most dark and mysterious way--as became outlaws. And
+before the afternoon was done, they had all managed to enjoy the sweet
+glory of spreading the fact that pretty soon the town would "hear
+something." All who got this vague hint were cautioned to "be mum and
+wait."
+
+About midnight Tom arrived with a boiled ham and a few trifles,
+and stopped in a dense undergrowth on a small bluff overlooking the
+meeting-place. It was starlight, and very still. The mighty river lay
+like an ocean at rest. Tom listened a moment, but no sound disturbed the
+quiet. Then he gave a low, distinct whistle. It was answered from under
+the bluff. Tom whistled twice more; these signals were answered in the
+same way. Then a guarded voice said:
+
+"Who goes there?"
+
+"Tom Sawyer, the Black Avenger of the Spanish Main. Name your names."
+
+"Huck Finn the Red-Handed, and Joe Harper the Terror of the Seas." Tom
+had furnished these titles, from his favorite literature.
+
+"'Tis well. Give the countersign."
+
+Two hoarse whispers delivered the same awful word simultaneously to
+the brooding night:
+
+"BLOOD!"
+
+Then Tom tumbled his ham over the bluff and let himself down after it,
+tearing both skin and clothes to some extent in the effort. There was
+an easy, comfortable path along the shore under the bluff, but it
+lacked the advantages of difficulty and danger so valued by a pirate.
+
+The Terror of the Seas had brought a side of bacon, and had about worn
+himself out with getting it there. Finn the Red-Handed had stolen a
+skillet and a quantity of half-cured leaf tobacco, and had also brought
+a few corn-cobs to make pipes with. But none of the pirates smoked or
+"chewed" but himself. The Black Avenger of the Spanish Main said it
+would never do to start without some fire. That was a wise thought;
+matches were hardly known there in that day. They saw a fire
+smouldering upon a great raft a hundred yards above, and they went
+stealthily thither and helped themselves to a chunk. They made an
+imposing adventure of it, saying, "Hist!" every now and then, and
+suddenly halting with finger on lip; moving with hands on imaginary
+dagger-hilts; and giving orders in dismal whispers that if "the foe"
+stirred, to "let him have it to the hilt," because "dead men tell no
+tales." They knew well enough that the raftsmen were all down at the
+village laying in stores or having a spree, but still that was no
+excuse for their conducting this thing in an unpiratical way.
+
+They shoved off, presently, Tom in command, Huck at the after oar and
+Joe at the forward. Tom stood amidships, gloomy-browed, and with folded
+arms, and gave his orders in a low, stern whisper:
+
+"Luff, and bring her to the wind!"
+
+"Aye-aye, sir!"
+
+"Steady, steady-y-y-y!"
+
+"Steady it is, sir!"
+
+"Let her go off a point!"
+
+"Point it is, sir!"
+
+As the boys steadily and monotonously drove the raft toward mid-stream
+it was no doubt understood that these orders were given only for
+"style," and were not intended to mean anything in particular.
+
+"What sail's she carrying?"
+
+"Courses, tops'ls, and flying-jib, sir."
+
+"Send the r'yals up! Lay out aloft, there, half a dozen of ye
+--foretopmaststuns'l! Lively, now!"
+
+"Aye-aye, sir!"
+
+"Shake out that maintogalans'l! Sheets and braces! NOW my hearties!"
+
+"Aye-aye, sir!"
+
+"Hellum-a-lee--hard a port! Stand by to meet her when she comes! Port,
+port! NOW, men! With a will! Stead-y-y-y!"
+
+"Steady it is, sir!"
+
+The raft drew beyond the middle of the river; the boys pointed her
+head right, and then lay on their oars. The river was not high, so
+there was not more than a two or three mile current. Hardly a word was
+said during the next three-quarters of an hour. Now the raft was
+passing before the distant town. Two or three glimmering lights showed
+where it lay, peacefully sleeping, beyond the vague vast sweep of
+star-gemmed water, unconscious of the tremendous event that was happening.
+The Black Avenger stood still with folded arms, "looking his last" upon
+the scene of his former joys and his later sufferings, and wishing
+"she" could see him now, abroad on the wild sea, facing peril and death
+with dauntless heart, going to his doom with a grim smile on his lips.
+It was but a small strain on his imagination to remove Jackson's Island
+beyond eyeshot of the village, and so he "looked his last" with a
+broken and satisfied heart. The other pirates were looking their last,
+too; and they all looked so long that they came near letting the
+current drift them out of the range of the island. But they discovered
+the danger in time, and made shift to avert it. About two o'clock in
+the morning the raft grounded on the bar two hundred yards above the
+head of the island, and they waded back and forth until they had landed
+their freight. Part of the little raft's belongings consisted of an old
+sail, and this they spread over a nook in the bushes for a tent to
+shelter their provisions; but they themselves would sleep in the open
+air in good weather, as became outlaws.
+
+They built a fire against the side of a great log twenty or thirty
+steps within the sombre depths of the forest, and then cooked some
+bacon in the frying-pan for supper, and used up half of the corn "pone"
+stock they had brought. It seemed glorious sport to be feasting in that
+wild, free way in the virgin forest of an unexplored and uninhabited
+island, far from the haunts of men, and they said they never would
+return to civilization. The climbing fire lit up their faces and threw
+its ruddy glare upon the pillared tree-trunks of their forest temple,
+and upon the varnished foliage and festooning vines.
+
+When the last crisp slice of bacon was gone, and the last allowance of
+corn pone devoured, the boys stretched themselves out on the grass,
+filled with contentment. They could have found a cooler place, but they
+would not deny themselves such a romantic feature as the roasting
+camp-fire.
+
+"AIN'T it gay?" said Joe.
+
+"It's NUTS!" said Tom. "What would the boys say if they could see us?"
+
+"Say? Well, they'd just die to be here--hey, Hucky!"
+
+"I reckon so," said Huckleberry; "anyways, I'm suited. I don't want
+nothing better'n this. I don't ever get enough to eat, gen'ally--and
+here they can't come and pick at a feller and bullyrag him so."
+
+"It's just the life for me," said Tom. "You don't have to get up,
+mornings, and you don't have to go to school, and wash, and all that
+blame foolishness. You see a pirate don't have to do ANYTHING, Joe,
+when he's ashore, but a hermit HE has to be praying considerable, and
+then he don't have any fun, anyway, all by himself that way."
+
+"Oh yes, that's so," said Joe, "but I hadn't thought much about it,
+you know. I'd a good deal rather be a pirate, now that I've tried it."
+
+"You see," said Tom, "people don't go much on hermits, nowadays, like
+they used to in old times, but a pirate's always respected. And a
+hermit's got to sleep on the hardest place he can find, and put
+sackcloth and ashes on his head, and stand out in the rain, and--"
+
+"What does he put sackcloth and ashes on his head for?" inquired Huck.
+
+"I dono. But they've GOT to do it. Hermits always do. You'd have to do
+that if you was a hermit."
+
+"Dern'd if I would," said Huck.
+
+"Well, what would you do?"
+
+"I dono. But I wouldn't do that."
+
+"Why, Huck, you'd HAVE to. How'd you get around it?"
+
+"Why, I just wouldn't stand it. I'd run away."
+
+"Run away! Well, you WOULD be a nice old slouch of a hermit. You'd be
+a disgrace."
+
+The Red-Handed made no response, being better employed. He had
+finished gouging out a cob, and now he fitted a weed stem to it, loaded
+it with tobacco, and was pressing a coal to the charge and blowing a
+cloud of fragrant smoke--he was in the full bloom of luxurious
+contentment. The other pirates envied him this majestic vice, and
+secretly resolved to acquire it shortly. Presently Huck said:
+
+"What does pirates have to do?"
+
+Tom said:
+
+"Oh, they have just a bully time--take ships and burn them, and get
+the money and bury it in awful places in their island where there's
+ghosts and things to watch it, and kill everybody in the ships--make
+'em walk a plank."
+
+"And they carry the women to the island," said Joe; "they don't kill
+the women."
+
+"No," assented Tom, "they don't kill the women--they're too noble. And
+the women's always beautiful, too.
+
+"And don't they wear the bulliest clothes! Oh no! All gold and silver
+and di'monds," said Joe, with enthusiasm.
+
+"Who?" said Huck.
+
+"Why, the pirates."
+
+Huck scanned his own clothing forlornly.
+
+"I reckon I ain't dressed fitten for a pirate," said he, with a
+regretful pathos in his voice; "but I ain't got none but these."
+
+But the other boys told him the fine clothes would come fast enough,
+after they should have begun their adventures. They made him understand
+that his poor rags would do to begin with, though it was customary for
+wealthy pirates to start with a proper wardrobe.
+
+Gradually their talk died out and drowsiness began to steal upon the
+eyelids of the little waifs. The pipe dropped from the fingers of the
+Red-Handed, and he slept the sleep of the conscience-free and the
+weary. The Terror of the Seas and the Black Avenger of the Spanish Main
+had more difficulty in getting to sleep. They said their prayers
+inwardly, and lying down, since there was nobody there with authority
+to make them kneel and recite aloud; in truth, they had a mind not to
+say them at all, but they were afraid to proceed to such lengths as
+that, lest they might call down a sudden and special thunderbolt from
+heaven. Then at once they reached and hovered upon the imminent verge
+of sleep--but an intruder came, now, that would not "down." It was
+conscience. They began to feel a vague fear that they had been doing
+wrong to run away; and next they thought of the stolen meat, and then
+the real torture came. They tried to argue it away by reminding
+conscience that they had purloined sweetmeats and apples scores of
+times; but conscience was not to be appeased by such thin
+plausibilities; it seemed to them, in the end, that there was no
+getting around the stubborn fact that taking sweetmeats was only
+"hooking," while taking bacon and hams and such valuables was plain
+simple stealing--and there was a command against that in the Bible. So
+they inwardly resolved that so long as they remained in the business,
+their piracies should not again be sullied with the crime of stealing.
+Then conscience granted a truce, and these curiously inconsistent
+pirates fell peacefully to sleep.
+
+
+
+CHAPTER XIV
+
+WHEN Tom awoke in the morning, he wondered where he was. He sat up and
+rubbed his eyes and looked around. Then he comprehended. It was the
+cool gray dawn, and there was a delicious sense of repose and peace in
+the deep pervading calm and silence of the woods. Not a leaf stirred;
+not a sound obtruded upon great Nature's meditation. Beaded dewdrops
+stood upon the leaves and grasses. A white layer of ashes covered the
+fire, and a thin blue breath of smoke rose straight into the air. Joe
+and Huck still slept.
+
+Now, far away in the woods a bird called; another answered; presently
+the hammering of a woodpecker was heard. Gradually the cool dim gray of
+the morning whitened, and as gradually sounds multiplied and life
+manifested itself. The marvel of Nature shaking off sleep and going to
+work unfolded itself to the musing boy. A little green worm came
+crawling over a dewy leaf, lifting two-thirds of his body into the air
+from time to time and "sniffing around," then proceeding again--for he
+was measuring, Tom said; and when the worm approached him, of its own
+accord, he sat as still as a stone, with his hopes rising and falling,
+by turns, as the creature still came toward him or seemed inclined to
+go elsewhere; and when at last it considered a painful moment with its
+curved body in the air and then came decisively down upon Tom's leg and
+began a journey over him, his whole heart was glad--for that meant that
+he was going to have a new suit of clothes--without the shadow of a
+doubt a gaudy piratical uniform. Now a procession of ants appeared,
+from nowhere in particular, and went about their labors; one struggled
+manfully by with a dead spider five times as big as itself in its arms,
+and lugged it straight up a tree-trunk. A brown spotted lady-bug
+climbed the dizzy height of a grass blade, and Tom bent down close to
+it and said, "Lady-bug, lady-bug, fly away home, your house is on fire,
+your children's alone," and she took wing and went off to see about it
+--which did not surprise the boy, for he knew of old that this insect was
+credulous about conflagrations, and he had practised upon its
+simplicity more than once. A tumblebug came next, heaving sturdily at
+its ball, and Tom touched the creature, to see it shut its legs against
+its body and pretend to be dead. The birds were fairly rioting by this
+time. A catbird, the Northern mocker, lit in a tree over Tom's head,
+and trilled out her imitations of her neighbors in a rapture of
+enjoyment; then a shrill jay swept down, a flash of blue flame, and
+stopped on a twig almost within the boy's reach, cocked his head to one
+side and eyed the strangers with a consuming curiosity; a gray squirrel
+and a big fellow of the "fox" kind came skurrying along, sitting up at
+intervals to inspect and chatter at the boys, for the wild things had
+probably never seen a human being before and scarcely knew whether to
+be afraid or not. All Nature was wide awake and stirring, now; long
+lances of sunlight pierced down through the dense foliage far and near,
+and a few butterflies came fluttering upon the scene.
+
+Tom stirred up the other pirates and they all clattered away with a
+shout, and in a minute or two were stripped and chasing after and
+tumbling over each other in the shallow limpid water of the white
+sandbar. They felt no longing for the little village sleeping in the
+distance beyond the majestic waste of water. A vagrant current or a
+slight rise in the river had carried off their raft, but this only
+gratified them, since its going was something like burning the bridge
+between them and civilization.
+
+They came back to camp wonderfully refreshed, glad-hearted, and
+ravenous; and they soon had the camp-fire blazing up again. Huck found
+a spring of clear cold water close by, and the boys made cups of broad
+oak or hickory leaves, and felt that water, sweetened with such a
+wildwood charm as that, would be a good enough substitute for coffee.
+While Joe was slicing bacon for breakfast, Tom and Huck asked him to
+hold on a minute; they stepped to a promising nook in the river-bank
+and threw in their lines; almost immediately they had reward. Joe had
+not had time to get impatient before they were back again with some
+handsome bass, a couple of sun-perch and a small catfish--provisions
+enough for quite a family. They fried the fish with the bacon, and were
+astonished; for no fish had ever seemed so delicious before. They did
+not know that the quicker a fresh-water fish is on the fire after he is
+caught the better he is; and they reflected little upon what a sauce
+open-air sleeping, open-air exercise, bathing, and a large ingredient
+of hunger make, too.
+
+They lay around in the shade, after breakfast, while Huck had a smoke,
+and then went off through the woods on an exploring expedition. They
+tramped gayly along, over decaying logs, through tangled underbrush,
+among solemn monarchs of the forest, hung from their crowns to the
+ground with a drooping regalia of grape-vines. Now and then they came
+upon snug nooks carpeted with grass and jeweled with flowers.
+
+They found plenty of things to be delighted with, but nothing to be
+astonished at. They discovered that the island was about three miles
+long and a quarter of a mile wide, and that the shore it lay closest to
+was only separated from it by a narrow channel hardly two hundred yards
+wide. They took a swim about every hour, so it was close upon the
+middle of the afternoon when they got back to camp. They were too
+hungry to stop to fish, but they fared sumptuously upon cold ham, and
+then threw themselves down in the shade to talk. But the talk soon
+began to drag, and then died. The stillness, the solemnity that brooded
+in the woods, and the sense of loneliness, began to tell upon the
+spirits of the boys. They fell to thinking. A sort of undefined longing
+crept upon them. This took dim shape, presently--it was budding
+homesickness. Even Finn the Red-Handed was dreaming of his doorsteps
+and empty hogsheads. But they were all ashamed of their weakness, and
+none was brave enough to speak his thought.
+
+For some time, now, the boys had been dully conscious of a peculiar
+sound in the distance, just as one sometimes is of the ticking of a
+clock which he takes no distinct note of. But now this mysterious sound
+became more pronounced, and forced a recognition. The boys started,
+glanced at each other, and then each assumed a listening attitude.
+There was a long silence, profound and unbroken; then a deep, sullen
+boom came floating down out of the distance.
+
+"What is it!" exclaimed Joe, under his breath.
+
+"I wonder," said Tom in a whisper.
+
+"'Tain't thunder," said Huckleberry, in an awed tone, "becuz thunder--"
+
+"Hark!" said Tom. "Listen--don't talk."
+
+They waited a time that seemed an age, and then the same muffled boom
+troubled the solemn hush.
+
+"Let's go and see."
+
+They sprang to their feet and hurried to the shore toward the town.
+They parted the bushes on the bank and peered out over the water. The
+little steam ferryboat was about a mile below the village, drifting
+with the current. Her broad deck seemed crowded with people. There were
+a great many skiffs rowing about or floating with the stream in the
+neighborhood of the ferryboat, but the boys could not determine what
+the men in them were doing. Presently a great jet of white smoke burst
+from the ferryboat's side, and as it expanded and rose in a lazy cloud,
+that same dull throb of sound was borne to the listeners again.
+
+"I know now!" exclaimed Tom; "somebody's drownded!"
+
+"That's it!" said Huck; "they done that last summer, when Bill Turner
+got drownded; they shoot a cannon over the water, and that makes him
+come up to the top. Yes, and they take loaves of bread and put
+quicksilver in 'em and set 'em afloat, and wherever there's anybody
+that's drownded, they'll float right there and stop."
+
+"Yes, I've heard about that," said Joe. "I wonder what makes the bread
+do that."
+
+"Oh, it ain't the bread, so much," said Tom; "I reckon it's mostly
+what they SAY over it before they start it out."
+
+"But they don't say anything over it," said Huck. "I've seen 'em and
+they don't."
+
+"Well, that's funny," said Tom. "But maybe they say it to themselves.
+Of COURSE they do. Anybody might know that."
+
+The other boys agreed that there was reason in what Tom said, because
+an ignorant lump of bread, uninstructed by an incantation, could not be
+expected to act very intelligently when set upon an errand of such
+gravity.
+
+"By jings, I wish I was over there, now," said Joe.
+
+"I do too" said Huck "I'd give heaps to know who it is."
+
+The boys still listened and watched. Presently a revealing thought
+flashed through Tom's mind, and he exclaimed:
+
+"Boys, I know who's drownded--it's us!"
+
+They felt like heroes in an instant. Here was a gorgeous triumph; they
+were missed; they were mourned; hearts were breaking on their account;
+tears were being shed; accusing memories of unkindness to these poor
+lost lads were rising up, and unavailing regrets and remorse were being
+indulged; and best of all, the departed were the talk of the whole
+town, and the envy of all the boys, as far as this dazzling notoriety
+was concerned. This was fine. It was worth while to be a pirate, after
+all.
+
+As twilight drew on, the ferryboat went back to her accustomed
+business and the skiffs disappeared. The pirates returned to camp. They
+were jubilant with vanity over their new grandeur and the illustrious
+trouble they were making. They caught fish, cooked supper and ate it,
+and then fell to guessing at what the village was thinking and saying
+about them; and the pictures they drew of the public distress on their
+account were gratifying to look upon--from their point of view. But
+when the shadows of night closed them in, they gradually ceased to
+talk, and sat gazing into the fire, with their minds evidently
+wandering elsewhere. The excitement was gone, now, and Tom and Joe
+could not keep back thoughts of certain persons at home who were not
+enjoying this fine frolic as much as they were. Misgivings came; they
+grew troubled and unhappy; a sigh or two escaped, unawares. By and by
+Joe timidly ventured upon a roundabout "feeler" as to how the others
+might look upon a return to civilization--not right now, but--
+
+Tom withered him with derision! Huck, being uncommitted as yet, joined
+in with Tom, and the waverer quickly "explained," and was glad to get
+out of the scrape with as little taint of chicken-hearted homesickness
+clinging to his garments as he could. Mutiny was effectually laid to
+rest for the moment.
+
+As the night deepened, Huck began to nod, and presently to snore. Joe
+followed next. Tom lay upon his elbow motionless, for some time,
+watching the two intently. At last he got up cautiously, on his knees,
+and went searching among the grass and the flickering reflections flung
+by the camp-fire. He picked up and inspected several large
+semi-cylinders of the thin white bark of a sycamore, and finally chose
+two which seemed to suit him. Then he knelt by the fire and painfully
+wrote something upon each of these with his "red keel"; one he rolled up
+and put in his jacket pocket, and the other he put in Joe's hat and
+removed it to a little distance from the owner. And he also put into the
+hat certain schoolboy treasures of almost inestimable value--among them
+a lump of chalk, an India-rubber ball, three fishhooks, and one of that
+kind of marbles known as a "sure 'nough crystal." Then he tiptoed his
+way cautiously among the trees till he felt that he was out of hearing,
+and straightway broke into a keen run in the direction of the sandbar.
+
+
+
+CHAPTER XV
+
+A FEW minutes later Tom was in the shoal water of the bar, wading
+toward the Illinois shore. Before the depth reached his middle he was
+half-way over; the current would permit no more wading, now, so he
+struck out confidently to swim the remaining hundred yards. He swam
+quartering upstream, but still was swept downward rather faster than he
+had expected. However, he reached the shore finally, and drifted along
+till he found a low place and drew himself out. He put his hand on his
+jacket pocket, found his piece of bark safe, and then struck through
+the woods, following the shore, with streaming garments. Shortly before
+ten o'clock he came out into an open place opposite the village, and
+saw the ferryboat lying in the shadow of the trees and the high bank.
+Everything was quiet under the blinking stars. He crept down the bank,
+watching with all his eyes, slipped into the water, swam three or four
+strokes and climbed into the skiff that did "yawl" duty at the boat's
+stern. He laid himself down under the thwarts and waited, panting.
+
+Presently the cracked bell tapped and a voice gave the order to "cast
+off." A minute or two later the skiff's head was standing high up,
+against the boat's swell, and the voyage was begun. Tom felt happy in
+his success, for he knew it was the boat's last trip for the night. At
+the end of a long twelve or fifteen minutes the wheels stopped, and Tom
+slipped overboard and swam ashore in the dusk, landing fifty yards
+downstream, out of danger of possible stragglers.
+
+He flew along unfrequented alleys, and shortly found himself at his
+aunt's back fence. He climbed over, approached the "ell," and looked in
+at the sitting-room window, for a light was burning there. There sat
+Aunt Polly, Sid, Mary, and Joe Harper's mother, grouped together,
+talking. They were by the bed, and the bed was between them and the
+door. Tom went to the door and began to softly lift the latch; then he
+pressed gently and the door yielded a crack; he continued pushing
+cautiously, and quaking every time it creaked, till he judged he might
+squeeze through on his knees; so he put his head through and began,
+warily.
+
+"What makes the candle blow so?" said Aunt Polly. Tom hurried up.
+"Why, that door's open, I believe. Why, of course it is. No end of
+strange things now. Go 'long and shut it, Sid."
+
+Tom disappeared under the bed just in time. He lay and "breathed"
+himself for a time, and then crept to where he could almost touch his
+aunt's foot.
+
+"But as I was saying," said Aunt Polly, "he warn't BAD, so to say
+--only mischEEvous. Only just giddy, and harum-scarum, you know. He
+warn't any more responsible than a colt. HE never meant any harm, and
+he was the best-hearted boy that ever was"--and she began to cry.
+
+"It was just so with my Joe--always full of his devilment, and up to
+every kind of mischief, but he was just as unselfish and kind as he
+could be--and laws bless me, to think I went and whipped him for taking
+that cream, never once recollecting that I throwed it out myself
+because it was sour, and I never to see him again in this world, never,
+never, never, poor abused boy!" And Mrs. Harper sobbed as if her heart
+would break.
+
+"I hope Tom's better off where he is," said Sid, "but if he'd been
+better in some ways--"
+
+"SID!" Tom felt the glare of the old lady's eye, though he could not
+see it. "Not a word against my Tom, now that he's gone! God'll take
+care of HIM--never you trouble YOURself, sir! Oh, Mrs. Harper, I don't
+know how to give him up! I don't know how to give him up! He was such a
+comfort to me, although he tormented my old heart out of me, 'most."
+
+"The Lord giveth and the Lord hath taken away--Blessed be the name of
+the Lord! But it's so hard--Oh, it's so hard! Only last Saturday my
+Joe busted a firecracker right under my nose and I knocked him
+sprawling. Little did I know then, how soon--Oh, if it was to do over
+again I'd hug him and bless him for it."
+
+"Yes, yes, yes, I know just how you feel, Mrs. Harper, I know just
+exactly how you feel. No longer ago than yesterday noon, my Tom took
+and filled the cat full of Pain-killer, and I did think the cretur
+would tear the house down. And God forgive me, I cracked Tom's head
+with my thimble, poor boy, poor dead boy. But he's out of all his
+troubles now. And the last words I ever heard him say was to reproach--"
+
+But this memory was too much for the old lady, and she broke entirely
+down. Tom was snuffling, now, himself--and more in pity of himself than
+anybody else. He could hear Mary crying, and putting in a kindly word
+for him from time to time. He began to have a nobler opinion of himself
+than ever before. Still, he was sufficiently touched by his aunt's
+grief to long to rush out from under the bed and overwhelm her with
+joy--and the theatrical gorgeousness of the thing appealed strongly to
+his nature, too, but he resisted and lay still.
+
+He went on listening, and gathered by odds and ends that it was
+conjectured at first that the boys had got drowned while taking a swim;
+then the small raft had been missed; next, certain boys said the
+missing lads had promised that the village should "hear something"
+soon; the wise-heads had "put this and that together" and decided that
+the lads had gone off on that raft and would turn up at the next town
+below, presently; but toward noon the raft had been found, lodged
+against the Missouri shore some five or six miles below the village
+--and then hope perished; they must be drowned, else hunger would have
+driven them home by nightfall if not sooner. It was believed that the
+search for the bodies had been a fruitless effort merely because the
+drowning must have occurred in mid-channel, since the boys, being good
+swimmers, would otherwise have escaped to shore. This was Wednesday
+night. If the bodies continued missing until Sunday, all hope would be
+given over, and the funerals would be preached on that morning. Tom
+shuddered.
+
+Mrs. Harper gave a sobbing good-night and turned to go. Then with a
+mutual impulse the two bereaved women flung themselves into each
+other's arms and had a good, consoling cry, and then parted. Aunt Polly
+was tender far beyond her wont, in her good-night to Sid and Mary. Sid
+snuffled a bit and Mary went off crying with all her heart.
+
+Aunt Polly knelt down and prayed for Tom so touchingly, so
+appealingly, and with such measureless love in her words and her old
+trembling voice, that he was weltering in tears again, long before she
+was through.
+
+He had to keep still long after she went to bed, for she kept making
+broken-hearted ejaculations from time to time, tossing unrestfully, and
+turning over. But at last she was still, only moaning a little in her
+sleep. Now the boy stole out, rose gradually by the bedside, shaded the
+candle-light with his hand, and stood regarding her. His heart was full
+of pity for her. He took out his sycamore scroll and placed it by the
+candle. But something occurred to him, and he lingered considering. His
+face lighted with a happy solution of his thought; he put the bark
+hastily in his pocket. Then he bent over and kissed the faded lips, and
+straightway made his stealthy exit, latching the door behind him.
+
+He threaded his way back to the ferry landing, found nobody at large
+there, and walked boldly on board the boat, for he knew she was
+tenantless except that there was a watchman, who always turned in and
+slept like a graven image. He untied the skiff at the stern, slipped
+into it, and was soon rowing cautiously upstream. When he had pulled a
+mile above the village, he started quartering across and bent himself
+stoutly to his work. He hit the landing on the other side neatly, for
+this was a familiar bit of work to him. He was moved to capture the
+skiff, arguing that it might be considered a ship and therefore
+legitimate prey for a pirate, but he knew a thorough search would be
+made for it and that might end in revelations. So he stepped ashore and
+entered the woods.
+
+He sat down and took a long rest, torturing himself meanwhile to keep
+awake, and then started warily down the home-stretch. The night was far
+spent. It was broad daylight before he found himself fairly abreast the
+island bar. He rested again until the sun was well up and gilding the
+great river with its splendor, and then he plunged into the stream. A
+little later he paused, dripping, upon the threshold of the camp, and
+heard Joe say:
+
+"No, Tom's true-blue, Huck, and he'll come back. He won't desert. He
+knows that would be a disgrace to a pirate, and Tom's too proud for
+that sort of thing. He's up to something or other. Now I wonder what?"
+
+"Well, the things is ours, anyway, ain't they?"
+
+"Pretty near, but not yet, Huck. The writing says they are if he ain't
+back here to breakfast."
+
+"Which he is!" exclaimed Tom, with fine dramatic effect, stepping
+grandly into camp.
+
+A sumptuous breakfast of bacon and fish was shortly provided, and as
+the boys set to work upon it, Tom recounted (and adorned) his
+adventures. They were a vain and boastful company of heroes when the
+tale was done. Then Tom hid himself away in a shady nook to sleep till
+noon, and the other pirates got ready to fish and explore.
+
+
+
+CHAPTER XVI
+
+AFTER dinner all the gang turned out to hunt for turtle eggs on the
+bar. They went about poking sticks into the sand, and when they found a
+soft place they went down on their knees and dug with their hands.
+Sometimes they would take fifty or sixty eggs out of one hole. They
+were perfectly round white things a trifle smaller than an English
+walnut. They had a famous fried-egg feast that night, and another on
+Friday morning.
+
+After breakfast they went whooping and prancing out on the bar, and
+chased each other round and round, shedding clothes as they went, until
+they were naked, and then continued the frolic far away up the shoal
+water of the bar, against the stiff current, which latter tripped their
+legs from under them from time to time and greatly increased the fun.
+And now and then they stooped in a group and splashed water in each
+other's faces with their palms, gradually approaching each other, with
+averted faces to avoid the strangling sprays, and finally gripping and
+struggling till the best man ducked his neighbor, and then they all
+went under in a tangle of white legs and arms and came up blowing,
+sputtering, laughing, and gasping for breath at one and the same time.
+
+When they were well exhausted, they would run out and sprawl on the
+dry, hot sand, and lie there and cover themselves up with it, and by
+and by break for the water again and go through the original
+performance once more. Finally it occurred to them that their naked
+skin represented flesh-colored "tights" very fairly; so they drew a
+ring in the sand and had a circus--with three clowns in it, for none
+would yield this proudest post to his neighbor.
+
+Next they got their marbles and played "knucks" and "ring-taw" and
+"keeps" till that amusement grew stale. Then Joe and Huck had another
+swim, but Tom would not venture, because he found that in kicking off
+his trousers he had kicked his string of rattlesnake rattles off his
+ankle, and he wondered how he had escaped cramp so long without the
+protection of this mysterious charm. He did not venture again until he
+had found it, and by that time the other boys were tired and ready to
+rest. They gradually wandered apart, dropped into the "dumps," and fell
+to gazing longingly across the wide river to where the village lay
+drowsing in the sun. Tom found himself writing "BECKY" in the sand with
+his big toe; he scratched it out, and was angry with himself for his
+weakness. But he wrote it again, nevertheless; he could not help it. He
+erased it once more and then took himself out of temptation by driving
+the other boys together and joining them.
+
+But Joe's spirits had gone down almost beyond resurrection. He was so
+homesick that he could hardly endure the misery of it. The tears lay
+very near the surface. Huck was melancholy, too. Tom was downhearted,
+but tried hard not to show it. He had a secret which he was not ready
+to tell, yet, but if this mutinous depression was not broken up soon,
+he would have to bring it out. He said, with a great show of
+cheerfulness:
+
+"I bet there's been pirates on this island before, boys. We'll explore
+it again. They've hid treasures here somewhere. How'd you feel to light
+on a rotten chest full of gold and silver--hey?"
+
+But it roused only faint enthusiasm, which faded out, with no reply.
+Tom tried one or two other seductions; but they failed, too. It was
+discouraging work. Joe sat poking up the sand with a stick and looking
+very gloomy. Finally he said:
+
+"Oh, boys, let's give it up. I want to go home. It's so lonesome."
+
+"Oh no, Joe, you'll feel better by and by," said Tom. "Just think of
+the fishing that's here."
+
+"I don't care for fishing. I want to go home."
+
+"But, Joe, there ain't such another swimming-place anywhere."
+
+"Swimming's no good. I don't seem to care for it, somehow, when there
+ain't anybody to say I sha'n't go in. I mean to go home."
+
+"Oh, shucks! Baby! You want to see your mother, I reckon."
+
+"Yes, I DO want to see my mother--and you would, too, if you had one.
+I ain't any more baby than you are." And Joe snuffled a little.
+
+"Well, we'll let the cry-baby go home to his mother, won't we, Huck?
+Poor thing--does it want to see its mother? And so it shall. You like
+it here, don't you, Huck? We'll stay, won't we?"
+
+Huck said, "Y-e-s"--without any heart in it.
+
+"I'll never speak to you again as long as I live," said Joe, rising.
+"There now!" And he moved moodily away and began to dress himself.
+
+"Who cares!" said Tom. "Nobody wants you to. Go 'long home and get
+laughed at. Oh, you're a nice pirate. Huck and me ain't cry-babies.
+We'll stay, won't we, Huck? Let him go if he wants to. I reckon we can
+get along without him, per'aps."
+
+But Tom was uneasy, nevertheless, and was alarmed to see Joe go
+sullenly on with his dressing. And then it was discomforting to see
+Huck eying Joe's preparations so wistfully, and keeping up such an
+ominous silence. Presently, without a parting word, Joe began to wade
+off toward the Illinois shore. Tom's heart began to sink. He glanced at
+Huck. Huck could not bear the look, and dropped his eyes. Then he said:
+
+"I want to go, too, Tom. It was getting so lonesome anyway, and now
+it'll be worse. Let's us go, too, Tom."
+
+"I won't! You can all go, if you want to. I mean to stay."
+
+"Tom, I better go."
+
+"Well, go 'long--who's hendering you."
+
+Huck began to pick up his scattered clothes. He said:
+
+"Tom, I wisht you'd come, too. Now you think it over. We'll wait for
+you when we get to shore."
+
+"Well, you'll wait a blame long time, that's all."
+
+Huck started sorrowfully away, and Tom stood looking after him, with a
+strong desire tugging at his heart to yield his pride and go along too.
+He hoped the boys would stop, but they still waded slowly on. It
+suddenly dawned on Tom that it was become very lonely and still. He
+made one final struggle with his pride, and then darted after his
+comrades, yelling:
+
+"Wait! Wait! I want to tell you something!"
+
+They presently stopped and turned around. When he got to where they
+were, he began unfolding his secret, and they listened moodily till at
+last they saw the "point" he was driving at, and then they set up a
+war-whoop of applause and said it was "splendid!" and said if he had
+told them at first, they wouldn't have started away. He made a plausible
+excuse; but his real reason had been the fear that not even the secret
+would keep them with him any very great length of time, and so he had
+meant to hold it in reserve as a last seduction.
+
+The lads came gayly back and went at their sports again with a will,
+chattering all the time about Tom's stupendous plan and admiring the
+genius of it. After a dainty egg and fish dinner, Tom said he wanted to
+learn to smoke, now. Joe caught at the idea and said he would like to
+try, too. So Huck made pipes and filled them. These novices had never
+smoked anything before but cigars made of grape-vine, and they "bit"
+the tongue, and were not considered manly anyway.
+
+Now they stretched themselves out on their elbows and began to puff,
+charily, and with slender confidence. The smoke had an unpleasant
+taste, and they gagged a little, but Tom said:
+
+"Why, it's just as easy! If I'd a knowed this was all, I'd a learnt
+long ago."
+
+"So would I," said Joe. "It's just nothing."
+
+"Why, many a time I've looked at people smoking, and thought well I
+wish I could do that; but I never thought I could," said Tom.
+
+"That's just the way with me, hain't it, Huck? You've heard me talk
+just that way--haven't you, Huck? I'll leave it to Huck if I haven't."
+
+"Yes--heaps of times," said Huck.
+
+"Well, I have too," said Tom; "oh, hundreds of times. Once down by the
+slaughter-house. Don't you remember, Huck? Bob Tanner was there, and
+Johnny Miller, and Jeff Thatcher, when I said it. Don't you remember,
+Huck, 'bout me saying that?"
+
+"Yes, that's so," said Huck. "That was the day after I lost a white
+alley. No, 'twas the day before."
+
+"There--I told you so," said Tom. "Huck recollects it."
+
+"I bleeve I could smoke this pipe all day," said Joe. "I don't feel
+sick."
+
+"Neither do I," said Tom. "I could smoke it all day. But I bet you
+Jeff Thatcher couldn't."
+
+"Jeff Thatcher! Why, he'd keel over just with two draws. Just let him
+try it once. HE'D see!"
+
+"I bet he would. And Johnny Miller--I wish could see Johnny Miller
+tackle it once."
+
+"Oh, don't I!" said Joe. "Why, I bet you Johnny Miller couldn't any
+more do this than nothing. Just one little snifter would fetch HIM."
+
+"'Deed it would, Joe. Say--I wish the boys could see us now."
+
+"So do I."
+
+"Say--boys, don't say anything about it, and some time when they're
+around, I'll come up to you and say, 'Joe, got a pipe? I want a smoke.'
+And you'll say, kind of careless like, as if it warn't anything, you'll
+say, 'Yes, I got my OLD pipe, and another one, but my tobacker ain't
+very good.' And I'll say, 'Oh, that's all right, if it's STRONG
+enough.' And then you'll out with the pipes, and we'll light up just as
+ca'm, and then just see 'em look!"
+
+"By jings, that'll be gay, Tom! I wish it was NOW!"
+
+"So do I! And when we tell 'em we learned when we was off pirating,
+won't they wish they'd been along?"
+
+"Oh, I reckon not! I'll just BET they will!"
+
+So the talk ran on. But presently it began to flag a trifle, and grow
+disjointed. The silences widened; the expectoration marvellously
+increased. Every pore inside the boys' cheeks became a spouting
+fountain; they could scarcely bail out the cellars under their tongues
+fast enough to prevent an inundation; little overflowings down their
+throats occurred in spite of all they could do, and sudden retchings
+followed every time. Both boys were looking very pale and miserable,
+now. Joe's pipe dropped from his nerveless fingers. Tom's followed.
+Both fountains were going furiously and both pumps bailing with might
+and main. Joe said feebly:
+
+"I've lost my knife. I reckon I better go and find it."
+
+Tom said, with quivering lips and halting utterance:
+
+"I'll help you. You go over that way and I'll hunt around by the
+spring. No, you needn't come, Huck--we can find it."
+
+So Huck sat down again, and waited an hour. Then he found it lonesome,
+and went to find his comrades. They were wide apart in the woods, both
+very pale, both fast asleep. But something informed him that if they
+had had any trouble they had got rid of it.
+
+They were not talkative at supper that night. They had a humble look,
+and when Huck prepared his pipe after the meal and was going to prepare
+theirs, they said no, they were not feeling very well--something they
+ate at dinner had disagreed with them.
+
+About midnight Joe awoke, and called the boys. There was a brooding
+oppressiveness in the air that seemed to bode something. The boys
+huddled themselves together and sought the friendly companionship of
+the fire, though the dull dead heat of the breathless atmosphere was
+stifling. They sat still, intent and waiting. The solemn hush
+continued. Beyond the light of the fire everything was swallowed up in
+the blackness of darkness. Presently there came a quivering glow that
+vaguely revealed the foliage for a moment and then vanished. By and by
+another came, a little stronger. Then another. Then a faint moan came
+sighing through the branches of the forest and the boys felt a fleeting
+breath upon their cheeks, and shuddered with the fancy that the Spirit
+of the Night had gone by. There was a pause. Now a weird flash turned
+night into day and showed every little grass-blade, separate and
+distinct, that grew about their feet. And it showed three white,
+startled faces, too. A deep peal of thunder went rolling and tumbling
+down the heavens and lost itself in sullen rumblings in the distance. A
+sweep of chilly air passed by, rustling all the leaves and snowing the
+flaky ashes broadcast about the fire. Another fierce glare lit up the
+forest and an instant crash followed that seemed to rend the tree-tops
+right over the boys' heads. They clung together in terror, in the thick
+gloom that followed. A few big rain-drops fell pattering upon the
+leaves.
+
+"Quick! boys, go for the tent!" exclaimed Tom.
+
+They sprang away, stumbling over roots and among vines in the dark, no
+two plunging in the same direction. A furious blast roared through the
+trees, making everything sing as it went. One blinding flash after
+another came, and peal on peal of deafening thunder. And now a
+drenching rain poured down and the rising hurricane drove it in sheets
+along the ground. The boys cried out to each other, but the roaring
+wind and the booming thunder-blasts drowned their voices utterly.
+However, one by one they straggled in at last and took shelter under
+the tent, cold, scared, and streaming with water; but to have company
+in misery seemed something to be grateful for. They could not talk, the
+old sail flapped so furiously, even if the other noises would have
+allowed them. The tempest rose higher and higher, and presently the
+sail tore loose from its fastenings and went winging away on the blast.
+The boys seized each others' hands and fled, with many tumblings and
+bruises, to the shelter of a great oak that stood upon the river-bank.
+Now the battle was at its highest. Under the ceaseless conflagration of
+lightning that flamed in the skies, everything below stood out in
+clean-cut and shadowless distinctness: the bending trees, the billowy
+river, white with foam, the driving spray of spume-flakes, the dim
+outlines of the high bluffs on the other side, glimpsed through the
+drifting cloud-rack and the slanting veil of rain. Every little while
+some giant tree yielded the fight and fell crashing through the younger
+growth; and the unflagging thunder-peals came now in ear-splitting
+explosive bursts, keen and sharp, and unspeakably appalling. The storm
+culminated in one matchless effort that seemed likely to tear the island
+to pieces, burn it up, drown it to the tree-tops, blow it away, and
+deafen every creature in it, all at one and the same moment. It was a
+wild night for homeless young heads to be out in.
+
+But at last the battle was done, and the forces retired with weaker
+and weaker threatenings and grumblings, and peace resumed her sway. The
+boys went back to camp, a good deal awed; but they found there was
+still something to be thankful for, because the great sycamore, the
+shelter of their beds, was a ruin, now, blasted by the lightnings, and
+they were not under it when the catastrophe happened.
+
+Everything in camp was drenched, the camp-fire as well; for they were
+but heedless lads, like their generation, and had made no provision
+against rain. Here was matter for dismay, for they were soaked through
+and chilled. They were eloquent in their distress; but they presently
+discovered that the fire had eaten so far up under the great log it had
+been built against (where it curved upward and separated itself from
+the ground), that a handbreadth or so of it had escaped wetting; so
+they patiently wrought until, with shreds and bark gathered from the
+under sides of sheltered logs, they coaxed the fire to burn again. Then
+they piled on great dead boughs till they had a roaring furnace, and
+were glad-hearted once more. They dried their boiled ham and had a
+feast, and after that they sat by the fire and expanded and glorified
+their midnight adventure until morning, for there was not a dry spot to
+sleep on, anywhere around.
+
+As the sun began to steal in upon the boys, drowsiness came over them,
+and they went out on the sandbar and lay down to sleep. They got
+scorched out by and by, and drearily set about getting breakfast. After
+the meal they felt rusty, and stiff-jointed, and a little homesick once
+more. Tom saw the signs, and fell to cheering up the pirates as well as
+he could. But they cared nothing for marbles, or circus, or swimming,
+or anything. He reminded them of the imposing secret, and raised a ray
+of cheer. While it lasted, he got them interested in a new device. This
+was to knock off being pirates, for a while, and be Indians for a
+change. They were attracted by this idea; so it was not long before
+they were stripped, and striped from head to heel with black mud, like
+so many zebras--all of them chiefs, of course--and then they went
+tearing through the woods to attack an English settlement.
+
+By and by they separated into three hostile tribes, and darted upon
+each other from ambush with dreadful war-whoops, and killed and scalped
+each other by thousands. It was a gory day. Consequently it was an
+extremely satisfactory one.
+
+They assembled in camp toward supper-time, hungry and happy; but now a
+difficulty arose--hostile Indians could not break the bread of
+hospitality together without first making peace, and this was a simple
+impossibility without smoking a pipe of peace. There was no other
+process that ever they had heard of. Two of the savages almost wished
+they had remained pirates. However, there was no other way; so with
+such show of cheerfulness as they could muster they called for the pipe
+and took their whiff as it passed, in due form.
+
+And behold, they were glad they had gone into savagery, for they had
+gained something; they found that they could now smoke a little without
+having to go and hunt for a lost knife; they did not get sick enough to
+be seriously uncomfortable. They were not likely to fool away this high
+promise for lack of effort. No, they practised cautiously, after
+supper, with right fair success, and so they spent a jubilant evening.
+They were prouder and happier in their new acquirement than they would
+have been in the scalping and skinning of the Six Nations. We will
+leave them to smoke and chatter and brag, since we have no further use
+for them at present.
+
+
+
+CHAPTER XVII
+
+BUT there was no hilarity in the little town that same tranquil
+Saturday afternoon. The Harpers, and Aunt Polly's family, were being
+put into mourning, with great grief and many tears. An unusual quiet
+possessed the village, although it was ordinarily quiet enough, in all
+conscience. The villagers conducted their concerns with an absent air,
+and talked little; but they sighed often. The Saturday holiday seemed a
+burden to the children. They had no heart in their sports, and
+gradually gave them up.
+
+In the afternoon Becky Thatcher found herself moping about the
+deserted schoolhouse yard, and feeling very melancholy. But she found
+nothing there to comfort her. She soliloquized:
+
+"Oh, if I only had a brass andiron-knob again! But I haven't got
+anything now to remember him by." And she choked back a little sob.
+
+Presently she stopped, and said to herself:
+
+"It was right here. Oh, if it was to do over again, I wouldn't say
+that--I wouldn't say it for the whole world. But he's gone now; I'll
+never, never, never see him any more."
+
+This thought broke her down, and she wandered away, with tears rolling
+down her cheeks. Then quite a group of boys and girls--playmates of
+Tom's and Joe's--came by, and stood looking over the paling fence and
+talking in reverent tones of how Tom did so-and-so the last time they
+saw him, and how Joe said this and that small trifle (pregnant with
+awful prophecy, as they could easily see now!)--and each speaker
+pointed out the exact spot where the lost lads stood at the time, and
+then added something like "and I was a-standing just so--just as I am
+now, and as if you was him--I was as close as that--and he smiled, just
+this way--and then something seemed to go all over me, like--awful, you
+know--and I never thought what it meant, of course, but I can see now!"
+
+Then there was a dispute about who saw the dead boys last in life, and
+many claimed that dismal distinction, and offered evidences, more or
+less tampered with by the witness; and when it was ultimately decided
+who DID see the departed last, and exchanged the last words with them,
+the lucky parties took upon themselves a sort of sacred importance, and
+were gaped at and envied by all the rest. One poor chap, who had no
+other grandeur to offer, said with tolerably manifest pride in the
+remembrance:
+
+"Well, Tom Sawyer he licked me once."
+
+But that bid for glory was a failure. Most of the boys could say that,
+and so that cheapened the distinction too much. The group loitered
+away, still recalling memories of the lost heroes, in awed voices.
+
+When the Sunday-school hour was finished, the next morning, the bell
+began to toll, instead of ringing in the usual way. It was a very still
+Sabbath, and the mournful sound seemed in keeping with the musing hush
+that lay upon nature. The villagers began to gather, loitering a moment
+in the vestibule to converse in whispers about the sad event. But there
+was no whispering in the house; only the funereal rustling of dresses
+as the women gathered to their seats disturbed the silence there. None
+could remember when the little church had been so full before. There
+was finally a waiting pause, an expectant dumbness, and then Aunt Polly
+entered, followed by Sid and Mary, and they by the Harper family, all
+in deep black, and the whole congregation, the old minister as well,
+rose reverently and stood until the mourners were seated in the front
+pew. There was another communing silence, broken at intervals by
+muffled sobs, and then the minister spread his hands abroad and prayed.
+A moving hymn was sung, and the text followed: "I am the Resurrection
+and the Life."
+
+As the service proceeded, the clergyman drew such pictures of the
+graces, the winning ways, and the rare promise of the lost lads that
+every soul there, thinking he recognized these pictures, felt a pang in
+remembering that he had persistently blinded himself to them always
+before, and had as persistently seen only faults and flaws in the poor
+boys. The minister related many a touching incident in the lives of the
+departed, too, which illustrated their sweet, generous natures, and the
+people could easily see, now, how noble and beautiful those episodes
+were, and remembered with grief that at the time they occurred they had
+seemed rank rascalities, well deserving of the cowhide. The
+congregation became more and more moved, as the pathetic tale went on,
+till at last the whole company broke down and joined the weeping
+mourners in a chorus of anguished sobs, the preacher himself giving way
+to his feelings, and crying in the pulpit.
+
+There was a rustle in the gallery, which nobody noticed; a moment
+later the church door creaked; the minister raised his streaming eyes
+above his handkerchief, and stood transfixed! First one and then
+another pair of eyes followed the minister's, and then almost with one
+impulse the congregation rose and stared while the three dead boys came
+marching up the aisle, Tom in the lead, Joe next, and Huck, a ruin of
+drooping rags, sneaking sheepishly in the rear! They had been hid in
+the unused gallery listening to their own funeral sermon!
+
+Aunt Polly, Mary, and the Harpers threw themselves upon their restored
+ones, smothered them with kisses and poured out thanksgivings, while
+poor Huck stood abashed and uncomfortable, not knowing exactly what to
+do or where to hide from so many unwelcoming eyes. He wavered, and
+started to slink away, but Tom seized him and said:
+
+"Aunt Polly, it ain't fair. Somebody's got to be glad to see Huck."
+
+"And so they shall. I'm glad to see him, poor motherless thing!" And
+the loving attentions Aunt Polly lavished upon him were the one thing
+capable of making him more uncomfortable than he was before.
+
+Suddenly the minister shouted at the top of his voice: "Praise God
+from whom all blessings flow--SING!--and put your hearts in it!"
+
+And they did. Old Hundred swelled up with a triumphant burst, and
+while it shook the rafters Tom Sawyer the Pirate looked around upon the
+envying juveniles about him and confessed in his heart that this was
+the proudest moment of his life.
+
+As the "sold" congregation trooped out they said they would almost be
+willing to be made ridiculous again to hear Old Hundred sung like that
+once more.
+
+Tom got more cuffs and kisses that day--according to Aunt Polly's
+varying moods--than he had earned before in a year; and he hardly knew
+which expressed the most gratefulness to God and affection for himself.
+
+
+
+CHAPTER XVIII
+
+THAT was Tom's great secret--the scheme to return home with his
+brother pirates and attend their own funerals. They had paddled over to
+the Missouri shore on a log, at dusk on Saturday, landing five or six
+miles below the village; they had slept in the woods at the edge of the
+town till nearly daylight, and had then crept through back lanes and
+alleys and finished their sleep in the gallery of the church among a
+chaos of invalided benches.
+
+At breakfast, Monday morning, Aunt Polly and Mary were very loving to
+Tom, and very attentive to his wants. There was an unusual amount of
+talk. In the course of it Aunt Polly said:
+
+"Well, I don't say it wasn't a fine joke, Tom, to keep everybody
+suffering 'most a week so you boys had a good time, but it is a pity
+you could be so hard-hearted as to let me suffer so. If you could come
+over on a log to go to your funeral, you could have come over and give
+me a hint some way that you warn't dead, but only run off."
+
+"Yes, you could have done that, Tom," said Mary; "and I believe you
+would if you had thought of it."
+
+"Would you, Tom?" said Aunt Polly, her face lighting wistfully. "Say,
+now, would you, if you'd thought of it?"
+
+"I--well, I don't know. 'Twould 'a' spoiled everything."
+
+"Tom, I hoped you loved me that much," said Aunt Polly, with a grieved
+tone that discomforted the boy. "It would have been something if you'd
+cared enough to THINK of it, even if you didn't DO it."
+
+"Now, auntie, that ain't any harm," pleaded Mary; "it's only Tom's
+giddy way--he is always in such a rush that he never thinks of
+anything."
+
+"More's the pity. Sid would have thought. And Sid would have come and
+DONE it, too. Tom, you'll look back, some day, when it's too late, and
+wish you'd cared a little more for me when it would have cost you so
+little."
+
+"Now, auntie, you know I do care for you," said Tom.
+
+"I'd know it better if you acted more like it."
+
+"I wish now I'd thought," said Tom, with a repentant tone; "but I
+dreamt about you, anyway. That's something, ain't it?"
+
+"It ain't much--a cat does that much--but it's better than nothing.
+What did you dream?"
+
+"Why, Wednesday night I dreamt that you was sitting over there by the
+bed, and Sid was sitting by the woodbox, and Mary next to him."
+
+"Well, so we did. So we always do. I'm glad your dreams could take
+even that much trouble about us."
+
+"And I dreamt that Joe Harper's mother was here."
+
+"Why, she was here! Did you dream any more?"
+
+"Oh, lots. But it's so dim, now."
+
+"Well, try to recollect--can't you?"
+
+"Somehow it seems to me that the wind--the wind blowed the--the--"
+
+"Try harder, Tom! The wind did blow something. Come!"
+
+Tom pressed his fingers on his forehead an anxious minute, and then
+said:
+
+"I've got it now! I've got it now! It blowed the candle!"
+
+"Mercy on us! Go on, Tom--go on!"
+
+"And it seems to me that you said, 'Why, I believe that that door--'"
+
+"Go ON, Tom!"
+
+"Just let me study a moment--just a moment. Oh, yes--you said you
+believed the door was open."
+
+"As I'm sitting here, I did! Didn't I, Mary! Go on!"
+
+"And then--and then--well I won't be certain, but it seems like as if
+you made Sid go and--and--"
+
+"Well? Well? What did I make him do, Tom? What did I make him do?"
+
+"You made him--you--Oh, you made him shut it."
+
+"Well, for the land's sake! I never heard the beat of that in all my
+days! Don't tell ME there ain't anything in dreams, any more. Sereny
+Harper shall know of this before I'm an hour older. I'd like to see her
+get around THIS with her rubbage 'bout superstition. Go on, Tom!"
+
+"Oh, it's all getting just as bright as day, now. Next you said I
+warn't BAD, only mischeevous and harum-scarum, and not any more
+responsible than--than--I think it was a colt, or something."
+
+"And so it was! Well, goodness gracious! Go on, Tom!"
+
+"And then you began to cry."
+
+"So I did. So I did. Not the first time, neither. And then--"
+
+"Then Mrs. Harper she began to cry, and said Joe was just the same,
+and she wished she hadn't whipped him for taking cream when she'd
+throwed it out her own self--"
+
+"Tom! The sperrit was upon you! You was a prophesying--that's what you
+was doing! Land alive, go on, Tom!"
+
+"Then Sid he said--he said--"
+
+"I don't think I said anything," said Sid.
+
+"Yes you did, Sid," said Mary.
+
+"Shut your heads and let Tom go on! What did he say, Tom?"
+
+"He said--I THINK he said he hoped I was better off where I was gone
+to, but if I'd been better sometimes--"
+
+"THERE, d'you hear that! It was his very words!"
+
+"And you shut him up sharp."
+
+"I lay I did! There must 'a' been an angel there. There WAS an angel
+there, somewheres!"
+
+"And Mrs. Harper told about Joe scaring her with a firecracker, and
+you told about Peter and the Painkiller--"
+
+"Just as true as I live!"
+
+"And then there was a whole lot of talk 'bout dragging the river for
+us, and 'bout having the funeral Sunday, and then you and old Miss
+Harper hugged and cried, and she went."
+
+"It happened just so! It happened just so, as sure as I'm a-sitting in
+these very tracks. Tom, you couldn't told it more like if you'd 'a'
+seen it! And then what? Go on, Tom!"
+
+"Then I thought you prayed for me--and I could see you and hear every
+word you said. And you went to bed, and I was so sorry that I took and
+wrote on a piece of sycamore bark, 'We ain't dead--we are only off
+being pirates,' and put it on the table by the candle; and then you
+looked so good, laying there asleep, that I thought I went and leaned
+over and kissed you on the lips."
+
+"Did you, Tom, DID you! I just forgive you everything for that!" And
+she seized the boy in a crushing embrace that made him feel like the
+guiltiest of villains.
+
+"It was very kind, even though it was only a--dream," Sid soliloquized
+just audibly.
+
+"Shut up, Sid! A body does just the same in a dream as he'd do if he
+was awake. Here's a big Milum apple I've been saving for you, Tom, if
+you was ever found again--now go 'long to school. I'm thankful to the
+good God and Father of us all I've got you back, that's long-suffering
+and merciful to them that believe on Him and keep His word, though
+goodness knows I'm unworthy of it, but if only the worthy ones got His
+blessings and had His hand to help them over the rough places, there's
+few enough would smile here or ever enter into His rest when the long
+night comes. Go 'long Sid, Mary, Tom--take yourselves off--you've
+hendered me long enough."
+
+The children left for school, and the old lady to call on Mrs. Harper
+and vanquish her realism with Tom's marvellous dream. Sid had better
+judgment than to utter the thought that was in his mind as he left the
+house. It was this: "Pretty thin--as long a dream as that, without any
+mistakes in it!"
+
+What a hero Tom was become, now! He did not go skipping and prancing,
+but moved with a dignified swagger as became a pirate who felt that the
+public eye was on him. And indeed it was; he tried not to seem to see
+the looks or hear the remarks as he passed along, but they were food
+and drink to him. Smaller boys than himself flocked at his heels, as
+proud to be seen with him, and tolerated by him, as if he had been the
+drummer at the head of a procession or the elephant leading a menagerie
+into town. Boys of his own size pretended not to know he had been away
+at all; but they were consuming with envy, nevertheless. They would
+have given anything to have that swarthy suntanned skin of his, and his
+glittering notoriety; and Tom would not have parted with either for a
+circus.
+
+At school the children made so much of him and of Joe, and delivered
+such eloquent admiration from their eyes, that the two heroes were not
+long in becoming insufferably "stuck-up." They began to tell their
+adventures to hungry listeners--but they only began; it was not a thing
+likely to have an end, with imaginations like theirs to furnish
+material. And finally, when they got out their pipes and went serenely
+puffing around, the very summit of glory was reached.
+
+Tom decided that he could be independent of Becky Thatcher now. Glory
+was sufficient. He would live for glory. Now that he was distinguished,
+maybe she would be wanting to "make up." Well, let her--she should see
+that he could be as indifferent as some other people. Presently she
+arrived. Tom pretended not to see her. He moved away and joined a group
+of boys and girls and began to talk. Soon he observed that she was
+tripping gayly back and forth with flushed face and dancing eyes,
+pretending to be busy chasing schoolmates, and screaming with laughter
+when she made a capture; but he noticed that she always made her
+captures in his vicinity, and that she seemed to cast a conscious eye
+in his direction at such times, too. It gratified all the vicious
+vanity that was in him; and so, instead of winning him, it only "set
+him up" the more and made him the more diligent to avoid betraying that
+he knew she was about. Presently she gave over skylarking, and moved
+irresolutely about, sighing once or twice and glancing furtively and
+wistfully toward Tom. Then she observed that now Tom was talking more
+particularly to Amy Lawrence than to any one else. She felt a sharp
+pang and grew disturbed and uneasy at once. She tried to go away, but
+her feet were treacherous, and carried her to the group instead. She
+said to a girl almost at Tom's elbow--with sham vivacity:
+
+"Why, Mary Austin! you bad girl, why didn't you come to Sunday-school?"
+
+"I did come--didn't you see me?"
+
+"Why, no! Did you? Where did you sit?"
+
+"I was in Miss Peters' class, where I always go. I saw YOU."
+
+"Did you? Why, it's funny I didn't see you. I wanted to tell you about
+the picnic."
+
+"Oh, that's jolly. Who's going to give it?"
+
+"My ma's going to let me have one."
+
+"Oh, goody; I hope she'll let ME come."
+
+"Well, she will. The picnic's for me. She'll let anybody come that I
+want, and I want you."
+
+"That's ever so nice. When is it going to be?"
+
+"By and by. Maybe about vacation."
+
+"Oh, won't it be fun! You going to have all the girls and boys?"
+
+"Yes, every one that's friends to me--or wants to be"; and she glanced
+ever so furtively at Tom, but he talked right along to Amy Lawrence
+about the terrible storm on the island, and how the lightning tore the
+great sycamore tree "all to flinders" while he was "standing within
+three feet of it."
+
+"Oh, may I come?" said Grace Miller.
+
+"Yes."
+
+"And me?" said Sally Rogers.
+
+"Yes."
+
+"And me, too?" said Susy Harper. "And Joe?"
+
+"Yes."
+
+And so on, with clapping of joyful hands till all the group had begged
+for invitations but Tom and Amy. Then Tom turned coolly away, still
+talking, and took Amy with him. Becky's lips trembled and the tears
+came to her eyes; she hid these signs with a forced gayety and went on
+chattering, but the life had gone out of the picnic, now, and out of
+everything else; she got away as soon as she could and hid herself and
+had what her sex call "a good cry." Then she sat moody, with wounded
+pride, till the bell rang. She roused up, now, with a vindictive cast
+in her eye, and gave her plaited tails a shake and said she knew what
+SHE'D do.
+
+At recess Tom continued his flirtation with Amy with jubilant
+self-satisfaction. And he kept drifting about to find Becky and lacerate
+her with the performance. At last he spied her, but there was a sudden
+falling of his mercury. She was sitting cosily on a little bench behind
+the schoolhouse looking at a picture-book with Alfred Temple--and so
+absorbed were they, and their heads so close together over the book,
+that they did not seem to be conscious of anything in the world besides.
+Jealousy ran red-hot through Tom's veins. He began to hate himself for
+throwing away the chance Becky had offered for a reconciliation. He
+called himself a fool, and all the hard names he could think of. He
+wanted to cry with vexation. Amy chatted happily along, as they walked,
+for her heart was singing, but Tom's tongue had lost its function. He
+did not hear what Amy was saying, and whenever she paused expectantly he
+could only stammer an awkward assent, which was as often misplaced as
+otherwise. He kept drifting to the rear of the schoolhouse, again and
+again, to sear his eyeballs with the hateful spectacle there. He could
+not help it. And it maddened him to see, as he thought he saw, that
+Becky Thatcher never once suspected that he was even in the land of the
+living. But she did see, nevertheless; and she knew she was winning her
+fight, too, and was glad to see him suffer as she had suffered.
+
+Amy's happy prattle became intolerable. Tom hinted at things he had to
+attend to; things that must be done; and time was fleeting. But in
+vain--the girl chirped on. Tom thought, "Oh, hang her, ain't I ever
+going to get rid of her?" At last he must be attending to those
+things--and she said artlessly that she would be "around" when school
+let out. And he hastened away, hating her for it.
+
+"Any other boy!" Tom thought, grating his teeth. "Any boy in the whole
+town but that Saint Louis smarty that thinks he dresses so fine and is
+aristocracy! Oh, all right, I licked you the first day you ever saw
+this town, mister, and I'll lick you again! You just wait till I catch
+you out! I'll just take and--"
+
+And he went through the motions of thrashing an imaginary boy
+--pummelling the air, and kicking and gouging. "Oh, you do, do you? You
+holler 'nough, do you? Now, then, let that learn you!" And so the
+imaginary flogging was finished to his satisfaction.
+
+Tom fled home at noon. His conscience could not endure any more of
+Amy's grateful happiness, and his jealousy could bear no more of the
+other distress. Becky resumed her picture inspections with Alfred, but
+as the minutes dragged along and no Tom came to suffer, her triumph
+began to cloud and she lost interest; gravity and absent-mindedness
+followed, and then melancholy; two or three times she pricked up her
+ear at a footstep, but it was a false hope; no Tom came. At last she
+grew entirely miserable and wished she hadn't carried it so far. When
+poor Alfred, seeing that he was losing her, he did not know how, kept
+exclaiming: "Oh, here's a jolly one! look at this!" she lost patience
+at last, and said, "Oh, don't bother me! I don't care for them!" and
+burst into tears, and got up and walked away.
+
+Alfred dropped alongside and was going to try to comfort her, but she
+said:
+
+"Go away and leave me alone, can't you! I hate you!"
+
+So the boy halted, wondering what he could have done--for she had said
+she would look at pictures all through the nooning--and she walked on,
+crying. Then Alfred went musing into the deserted schoolhouse. He was
+humiliated and angry. He easily guessed his way to the truth--the girl
+had simply made a convenience of him to vent her spite upon Tom Sawyer.
+He was far from hating Tom the less when this thought occurred to him.
+He wished there was some way to get that boy into trouble without much
+risk to himself. Tom's spelling-book fell under his eye. Here was his
+opportunity. He gratefully opened to the lesson for the afternoon and
+poured ink upon the page.
+
+Becky, glancing in at a window behind him at the moment, saw the act,
+and moved on, without discovering herself. She started homeward, now,
+intending to find Tom and tell him; Tom would be thankful and their
+troubles would be healed. Before she was half way home, however, she
+had changed her mind. The thought of Tom's treatment of her when she
+was talking about her picnic came scorching back and filled her with
+shame. She resolved to let him get whipped on the damaged
+spelling-book's account, and to hate him forever, into the bargain.
+
+
+
+CHAPTER XIX
+
+TOM arrived at home in a dreary mood, and the first thing his aunt
+said to him showed him that he had brought his sorrows to an
+unpromising market:
+
+"Tom, I've a notion to skin you alive!"
+
+"Auntie, what have I done?"
+
+"Well, you've done enough. Here I go over to Sereny Harper, like an
+old softy, expecting I'm going to make her believe all that rubbage
+about that dream, when lo and behold you she'd found out from Joe that
+you was over here and heard all the talk we had that night. Tom, I
+don't know what is to become of a boy that will act like that. It makes
+me feel so bad to think you could let me go to Sereny Harper and make
+such a fool of myself and never say a word."
+
+This was a new aspect of the thing. His smartness of the morning had
+seemed to Tom a good joke before, and very ingenious. It merely looked
+mean and shabby now. He hung his head and could not think of anything
+to say for a moment. Then he said:
+
+"Auntie, I wish I hadn't done it--but I didn't think."
+
+"Oh, child, you never think. You never think of anything but your own
+selfishness. You could think to come all the way over here from
+Jackson's Island in the night to laugh at our troubles, and you could
+think to fool me with a lie about a dream; but you couldn't ever think
+to pity us and save us from sorrow."
+
+"Auntie, I know now it was mean, but I didn't mean to be mean. I
+didn't, honest. And besides, I didn't come over here to laugh at you
+that night."
+
+"What did you come for, then?"
+
+"It was to tell you not to be uneasy about us, because we hadn't got
+drownded."
+
+"Tom, Tom, I would be the thankfullest soul in this world if I could
+believe you ever had as good a thought as that, but you know you never
+did--and I know it, Tom."
+
+"Indeed and 'deed I did, auntie--I wish I may never stir if I didn't."
+
+"Oh, Tom, don't lie--don't do it. It only makes things a hundred times
+worse."
+
+"It ain't a lie, auntie; it's the truth. I wanted to keep you from
+grieving--that was all that made me come."
+
+"I'd give the whole world to believe that--it would cover up a power
+of sins, Tom. I'd 'most be glad you'd run off and acted so bad. But it
+ain't reasonable; because, why didn't you tell me, child?"
+
+"Why, you see, when you got to talking about the funeral, I just got
+all full of the idea of our coming and hiding in the church, and I
+couldn't somehow bear to spoil it. So I just put the bark back in my
+pocket and kept mum."
+
+"What bark?"
+
+"The bark I had wrote on to tell you we'd gone pirating. I wish, now,
+you'd waked up when I kissed you--I do, honest."
+
+The hard lines in his aunt's face relaxed and a sudden tenderness
+dawned in her eyes.
+
+"DID you kiss me, Tom?"
+
+"Why, yes, I did."
+
+"Are you sure you did, Tom?"
+
+"Why, yes, I did, auntie--certain sure."
+
+"What did you kiss me for, Tom?"
+
+"Because I loved you so, and you laid there moaning and I was so sorry."
+
+The words sounded like truth. The old lady could not hide a tremor in
+her voice when she said:
+
+"Kiss me again, Tom!--and be off with you to school, now, and don't
+bother me any more."
+
+The moment he was gone, she ran to a closet and got out the ruin of a
+jacket which Tom had gone pirating in. Then she stopped, with it in her
+hand, and said to herself:
+
+"No, I don't dare. Poor boy, I reckon he's lied about it--but it's a
+blessed, blessed lie, there's such a comfort come from it. I hope the
+Lord--I KNOW the Lord will forgive him, because it was such
+goodheartedness in him to tell it. But I don't want to find out it's a
+lie. I won't look."
+
+She put the jacket away, and stood by musing a minute. Twice she put
+out her hand to take the garment again, and twice she refrained. Once
+more she ventured, and this time she fortified herself with the
+thought: "It's a good lie--it's a good lie--I won't let it grieve me."
+So she sought the jacket pocket. A moment later she was reading Tom's
+piece of bark through flowing tears and saying: "I could forgive the
+boy, now, if he'd committed a million sins!"
+
+
+
+CHAPTER XX
+
+THERE was something about Aunt Polly's manner, when she kissed Tom,
+that swept away his low spirits and made him lighthearted and happy
+again. He started to school and had the luck of coming upon Becky
+Thatcher at the head of Meadow Lane. His mood always determined his
+manner. Without a moment's hesitation he ran to her and said:
+
+"I acted mighty mean to-day, Becky, and I'm so sorry. I won't ever,
+ever do that way again, as long as ever I live--please make up, won't
+you?"
+
+The girl stopped and looked him scornfully in the face:
+
+"I'll thank you to keep yourself TO yourself, Mr. Thomas Sawyer. I'll
+never speak to you again."
+
+She tossed her head and passed on. Tom was so stunned that he had not
+even presence of mind enough to say "Who cares, Miss Smarty?" until the
+right time to say it had gone by. So he said nothing. But he was in a
+fine rage, nevertheless. He moped into the schoolyard wishing she were
+a boy, and imagining how he would trounce her if she were. He presently
+encountered her and delivered a stinging remark as he passed. She
+hurled one in return, and the angry breach was complete. It seemed to
+Becky, in her hot resentment, that she could hardly wait for school to
+"take in," she was so impatient to see Tom flogged for the injured
+spelling-book. If she had had any lingering notion of exposing Alfred
+Temple, Tom's offensive fling had driven it entirely away.
+
+Poor girl, she did not know how fast she was nearing trouble herself.
+The master, Mr. Dobbins, had reached middle age with an unsatisfied
+ambition. The darling of his desires was, to be a doctor, but poverty
+had decreed that he should be nothing higher than a village
+schoolmaster. Every day he took a mysterious book out of his desk and
+absorbed himself in it at times when no classes were reciting. He kept
+that book under lock and key. There was not an urchin in school but was
+perishing to have a glimpse of it, but the chance never came. Every boy
+and girl had a theory about the nature of that book; but no two
+theories were alike, and there was no way of getting at the facts in
+the case. Now, as Becky was passing by the desk, which stood near the
+door, she noticed that the key was in the lock! It was a precious
+moment. She glanced around; found herself alone, and the next instant
+she had the book in her hands. The title-page--Professor Somebody's
+ANATOMY--carried no information to her mind; so she began to turn the
+leaves. She came at once upon a handsomely engraved and colored
+frontispiece--a human figure, stark naked. At that moment a shadow fell
+on the page and Tom Sawyer stepped in at the door and caught a glimpse
+of the picture. Becky snatched at the book to close it, and had the
+hard luck to tear the pictured page half down the middle. She thrust
+the volume into the desk, turned the key, and burst out crying with
+shame and vexation.
+
+"Tom Sawyer, you are just as mean as you can be, to sneak up on a
+person and look at what they're looking at."
+
+"How could I know you was looking at anything?"
+
+"You ought to be ashamed of yourself, Tom Sawyer; you know you're
+going to tell on me, and oh, what shall I do, what shall I do! I'll be
+whipped, and I never was whipped in school."
+
+Then she stamped her little foot and said:
+
+"BE so mean if you want to! I know something that's going to happen.
+You just wait and you'll see! Hateful, hateful, hateful!"--and she
+flung out of the house with a new explosion of crying.
+
+Tom stood still, rather flustered by this onslaught. Presently he said
+to himself:
+
+"What a curious kind of a fool a girl is! Never been licked in school!
+Shucks! What's a licking! That's just like a girl--they're so
+thin-skinned and chicken-hearted. Well, of course I ain't going to tell
+old Dobbins on this little fool, because there's other ways of getting
+even on her, that ain't so mean; but what of it? Old Dobbins will ask
+who it was tore his book. Nobody'll answer. Then he'll do just the way
+he always does--ask first one and then t'other, and when he comes to the
+right girl he'll know it, without any telling. Girls' faces always tell
+on them. They ain't got any backbone. She'll get licked. Well, it's a
+kind of a tight place for Becky Thatcher, because there ain't any way
+out of it." Tom conned the thing a moment longer, and then added: "All
+right, though; she'd like to see me in just such a fix--let her sweat it
+out!"
+
+Tom joined the mob of skylarking scholars outside. In a few moments
+the master arrived and school "took in." Tom did not feel a strong
+interest in his studies. Every time he stole a glance at the girls'
+side of the room Becky's face troubled him. Considering all things, he
+did not want to pity her, and yet it was all he could do to help it. He
+could get up no exultation that was really worthy the name. Presently
+the spelling-book discovery was made, and Tom's mind was entirely full
+of his own matters for a while after that. Becky roused up from her
+lethargy of distress and showed good interest in the proceedings. She
+did not expect that Tom could get out of his trouble by denying that he
+spilt the ink on the book himself; and she was right. The denial only
+seemed to make the thing worse for Tom. Becky supposed she would be
+glad of that, and she tried to believe she was glad of it, but she
+found she was not certain. When the worst came to the worst, she had an
+impulse to get up and tell on Alfred Temple, but she made an effort and
+forced herself to keep still--because, said she to herself, "he'll tell
+about me tearing the picture sure. I wouldn't say a word, not to save
+his life!"
+
+Tom took his whipping and went back to his seat not at all
+broken-hearted, for he thought it was possible that he had unknowingly
+upset the ink on the spelling-book himself, in some skylarking bout--he
+had denied it for form's sake and because it was custom, and had stuck
+to the denial from principle.
+
+A whole hour drifted by, the master sat nodding in his throne, the air
+was drowsy with the hum of study. By and by, Mr. Dobbins straightened
+himself up, yawned, then unlocked his desk, and reached for his book,
+but seemed undecided whether to take it out or leave it. Most of the
+pupils glanced up languidly, but there were two among them that watched
+his movements with intent eyes. Mr. Dobbins fingered his book absently
+for a while, then took it out and settled himself in his chair to read!
+Tom shot a glance at Becky. He had seen a hunted and helpless rabbit
+look as she did, with a gun levelled at its head. Instantly he forgot
+his quarrel with her. Quick--something must be done! done in a flash,
+too! But the very imminence of the emergency paralyzed his invention.
+Good!--he had an inspiration! He would run and snatch the book, spring
+through the door and fly. But his resolution shook for one little
+instant, and the chance was lost--the master opened the volume. If Tom
+only had the wasted opportunity back again! Too late. There was no help
+for Becky now, he said. The next moment the master faced the school.
+Every eye sank under his gaze. There was that in it which smote even
+the innocent with fear. There was silence while one might count ten
+--the master was gathering his wrath. Then he spoke: "Who tore this book?"
+
+There was not a sound. One could have heard a pin drop. The stillness
+continued; the master searched face after face for signs of guilt.
+
+"Benjamin Rogers, did you tear this book?"
+
+A denial. Another pause.
+
+"Joseph Harper, did you?"
+
+Another denial. Tom's uneasiness grew more and more intense under the
+slow torture of these proceedings. The master scanned the ranks of
+boys--considered a while, then turned to the girls:
+
+"Amy Lawrence?"
+
+A shake of the head.
+
+"Gracie Miller?"
+
+The same sign.
+
+"Susan Harper, did you do this?"
+
+Another negative. The next girl was Becky Thatcher. Tom was trembling
+from head to foot with excitement and a sense of the hopelessness of
+the situation.
+
+"Rebecca Thatcher" [Tom glanced at her face--it was white with terror]
+--"did you tear--no, look me in the face" [her hands rose in appeal]
+--"did you tear this book?"
+
+A thought shot like lightning through Tom's brain. He sprang to his
+feet and shouted--"I done it!"
+
+The school stared in perplexity at this incredible folly. Tom stood a
+moment, to gather his dismembered faculties; and when he stepped
+forward to go to his punishment the surprise, the gratitude, the
+adoration that shone upon him out of poor Becky's eyes seemed pay
+enough for a hundred floggings. Inspired by the splendor of his own
+act, he took without an outcry the most merciless flaying that even Mr.
+Dobbins had ever administered; and also received with indifference the
+added cruelty of a command to remain two hours after school should be
+dismissed--for he knew who would wait for him outside till his
+captivity was done, and not count the tedious time as loss, either.
+
+Tom went to bed that night planning vengeance against Alfred Temple;
+for with shame and repentance Becky had told him all, not forgetting
+her own treachery; but even the longing for vengeance had to give way,
+soon, to pleasanter musings, and he fell asleep at last with Becky's
+latest words lingering dreamily in his ear--
+
+"Tom, how COULD you be so noble!"
+
+
+
+CHAPTER XXI
+
+VACATION was approaching. The schoolmaster, always severe, grew
+severer and more exacting than ever, for he wanted the school to make a
+good showing on "Examination" day. His rod and his ferule were seldom
+idle now--at least among the smaller pupils. Only the biggest boys, and
+young ladies of eighteen and twenty, escaped lashing. Mr. Dobbins'
+lashings were very vigorous ones, too; for although he carried, under
+his wig, a perfectly bald and shiny head, he had only reached middle
+age, and there was no sign of feebleness in his muscle. As the great
+day approached, all the tyranny that was in him came to the surface; he
+seemed to take a vindictive pleasure in punishing the least
+shortcomings. The consequence was, that the smaller boys spent their
+days in terror and suffering and their nights in plotting revenge. They
+threw away no opportunity to do the master a mischief. But he kept
+ahead all the time. The retribution that followed every vengeful
+success was so sweeping and majestic that the boys always retired from
+the field badly worsted. At last they conspired together and hit upon a
+plan that promised a dazzling victory. They swore in the sign-painter's
+boy, told him the scheme, and asked his help. He had his own reasons
+for being delighted, for the master boarded in his father's family and
+had given the boy ample cause to hate him. The master's wife would go
+on a visit to the country in a few days, and there would be nothing to
+interfere with the plan; the master always prepared himself for great
+occasions by getting pretty well fuddled, and the sign-painter's boy
+said that when the dominie had reached the proper condition on
+Examination Evening he would "manage the thing" while he napped in his
+chair; then he would have him awakened at the right time and hurried
+away to school.
+
+In the fulness of time the interesting occasion arrived. At eight in
+the evening the schoolhouse was brilliantly lighted, and adorned with
+wreaths and festoons of foliage and flowers. The master sat throned in
+his great chair upon a raised platform, with his blackboard behind him.
+He was looking tolerably mellow. Three rows of benches on each side and
+six rows in front of him were occupied by the dignitaries of the town
+and by the parents of the pupils. To his left, back of the rows of
+citizens, was a spacious temporary platform upon which were seated the
+scholars who were to take part in the exercises of the evening; rows of
+small boys, washed and dressed to an intolerable state of discomfort;
+rows of gawky big boys; snowbanks of girls and young ladies clad in
+lawn and muslin and conspicuously conscious of their bare arms, their
+grandmothers' ancient trinkets, their bits of pink and blue ribbon and
+the flowers in their hair. All the rest of the house was filled with
+non-participating scholars.
+
+The exercises began. A very little boy stood up and sheepishly
+recited, "You'd scarce expect one of my age to speak in public on the
+stage," etc.--accompanying himself with the painfully exact and
+spasmodic gestures which a machine might have used--supposing the
+machine to be a trifle out of order. But he got through safely, though
+cruelly scared, and got a fine round of applause when he made his
+manufactured bow and retired.
+
+A little shamefaced girl lisped, "Mary had a little lamb," etc.,
+performed a compassion-inspiring curtsy, got her meed of applause, and
+sat down flushed and happy.
+
+Tom Sawyer stepped forward with conceited confidence and soared into
+the unquenchable and indestructible "Give me liberty or give me death"
+speech, with fine fury and frantic gesticulation, and broke down in the
+middle of it. A ghastly stage-fright seized him, his legs quaked under
+him and he was like to choke. True, he had the manifest sympathy of the
+house but he had the house's silence, too, which was even worse than
+its sympathy. The master frowned, and this completed the disaster. Tom
+struggled awhile and then retired, utterly defeated. There was a weak
+attempt at applause, but it died early.
+
+"The Boy Stood on the Burning Deck" followed; also "The Assyrian Came
+Down," and other declamatory gems. Then there were reading exercises,
+and a spelling fight. The meagre Latin class recited with honor. The
+prime feature of the evening was in order, now--original "compositions"
+by the young ladies. Each in her turn stepped forward to the edge of
+the platform, cleared her throat, held up her manuscript (tied with
+dainty ribbon), and proceeded to read, with labored attention to
+"expression" and punctuation. The themes were the same that had been
+illuminated upon similar occasions by their mothers before them, their
+grandmothers, and doubtless all their ancestors in the female line
+clear back to the Crusades. "Friendship" was one; "Memories of Other
+Days"; "Religion in History"; "Dream Land"; "The Advantages of
+Culture"; "Forms of Political Government Compared and Contrasted";
+"Melancholy"; "Filial Love"; "Heart Longings," etc., etc.
+
+A prevalent feature in these compositions was a nursed and petted
+melancholy; another was a wasteful and opulent gush of "fine language";
+another was a tendency to lug in by the ears particularly prized words
+and phrases until they were worn entirely out; and a peculiarity that
+conspicuously marked and marred them was the inveterate and intolerable
+sermon that wagged its crippled tail at the end of each and every one
+of them. No matter what the subject might be, a brain-racking effort
+was made to squirm it into some aspect or other that the moral and
+religious mind could contemplate with edification. The glaring
+insincerity of these sermons was not sufficient to compass the
+banishment of the fashion from the schools, and it is not sufficient
+to-day; it never will be sufficient while the world stands, perhaps.
+There is no school in all our land where the young ladies do not feel
+obliged to close their compositions with a sermon; and you will find
+that the sermon of the most frivolous and the least religious girl in
+the school is always the longest and the most relentlessly pious. But
+enough of this. Homely truth is unpalatable.
+
+Let us return to the "Examination." The first composition that was
+read was one entitled "Is this, then, Life?" Perhaps the reader can
+endure an extract from it:
+
+  "In the common walks of life, with what delightful
+   emotions does the youthful mind look forward to some
+   anticipated scene of festivity! Imagination is busy
+   sketching rose-tinted pictures of joy. In fancy, the
+   voluptuous votary of fashion sees herself amid the
+   festive throng, 'the observed of all observers.' Her
+   graceful form, arrayed in snowy robes, is whirling
+   through the mazes of the joyous dance; her eye is
+   brightest, her step is lightest in the gay assembly.
+
+  "In such delicious fancies time quickly glides by,
+   and the welcome hour arrives for her entrance into
+   the Elysian world, of which she has had such bright
+   dreams. How fairy-like does everything appear to
+   her enchanted vision! Each new scene is more charming
+   than the last. But after a while she finds that
+   beneath this goodly exterior, all is vanity, the
+   flattery which once charmed her soul, now grates
+   harshly upon her ear; the ball-room has lost its
+   charms; and with wasted health and imbittered heart,
+   she turns away with the conviction that earthly
+   pleasures cannot satisfy the longings of the soul!"
+
+And so forth and so on. There was a buzz of gratification from time to
+time during the reading, accompanied by whispered ejaculations of "How
+sweet!" "How eloquent!" "So true!" etc., and after the thing had closed
+with a peculiarly afflicting sermon the applause was enthusiastic.
+
+Then arose a slim, melancholy girl, whose face had the "interesting"
+paleness that comes of pills and indigestion, and read a "poem." Two
+stanzas of it will do:
+
+   "A MISSOURI MAIDEN'S FAREWELL TO ALABAMA
+
+   "Alabama, good-bye! I love thee well!
+      But yet for a while do I leave thee now!
+    Sad, yes, sad thoughts of thee my heart doth swell,
+      And burning recollections throng my brow!
+    For I have wandered through thy flowery woods;
+      Have roamed and read near Tallapoosa's stream;
+    Have listened to Tallassee's warring floods,
+      And wooed on Coosa's side Aurora's beam.
+
+   "Yet shame I not to bear an o'er-full heart,
+      Nor blush to turn behind my tearful eyes;
+    'Tis from no stranger land I now must part,
+      'Tis to no strangers left I yield these sighs.
+    Welcome and home were mine within this State,
+      Whose vales I leave--whose spires fade fast from me
+    And cold must be mine eyes, and heart, and tete,
+      When, dear Alabama! they turn cold on thee!"
+
+There were very few there who knew what "tete" meant, but the poem was
+very satisfactory, nevertheless.
+
+Next appeared a dark-complexioned, black-eyed, black-haired young
+lady, who paused an impressive moment, assumed a tragic expression, and
+began to read in a measured, solemn tone:
+
+  "A VISION
+
+   "Dark and tempestuous was night. Around the
+   throne on high not a single star quivered; but
+   the deep intonations of the heavy thunder
+   constantly vibrated upon the ear; whilst the
+   terrific lightning revelled in angry mood
+   through the cloudy chambers of heaven, seeming
+   to scorn the power exerted over its terror by
+   the illustrious Franklin! Even the boisterous
+   winds unanimously came forth from their mystic
+   homes, and blustered about as if to enhance by
+   their aid the wildness of the scene.
+
+   "At such a time, so dark, so dreary, for human
+   sympathy my very spirit sighed; but instead thereof,
+
+   "'My dearest friend, my counsellor, my comforter
+   and guide--My joy in grief, my second bliss
+   in joy,' came to my side. She moved like one of
+   those bright beings pictured in the sunny walks
+   of fancy's Eden by the romantic and young, a
+   queen of beauty unadorned save by her own
+   transcendent loveliness. So soft was her step, it
+   failed to make even a sound, and but for the
+   magical thrill imparted by her genial touch, as
+   other unobtrusive beauties, she would have glided
+   away un-perceived--unsought. A strange sadness
+   rested upon her features, like icy tears upon
+   the robe of December, as she pointed to the
+   contending elements without, and bade me contemplate
+   the two beings presented."
+
+This nightmare occupied some ten pages of manuscript and wound up with
+a sermon so destructive of all hope to non-Presbyterians that it took
+the first prize. This composition was considered to be the very finest
+effort of the evening. The mayor of the village, in delivering the
+prize to the author of it, made a warm speech in which he said that it
+was by far the most "eloquent" thing he had ever listened to, and that
+Daniel Webster himself might well be proud of it.
+
+It may be remarked, in passing, that the number of compositions in
+which the word "beauteous" was over-fondled, and human experience
+referred to as "life's page," was up to the usual average.
+
+Now the master, mellow almost to the verge of geniality, put his chair
+aside, turned his back to the audience, and began to draw a map of
+America on the blackboard, to exercise the geography class upon. But he
+made a sad business of it with his unsteady hand, and a smothered
+titter rippled over the house. He knew what the matter was, and set
+himself to right it. He sponged out lines and remade them; but he only
+distorted them more than ever, and the tittering was more pronounced.
+He threw his entire attention upon his work, now, as if determined not
+to be put down by the mirth. He felt that all eyes were fastened upon
+him; he imagined he was succeeding, and yet the tittering continued; it
+even manifestly increased. And well it might. There was a garret above,
+pierced with a scuttle over his head; and down through this scuttle
+came a cat, suspended around the haunches by a string; she had a rag
+tied about her head and jaws to keep her from mewing; as she slowly
+descended she curved upward and clawed at the string, she swung
+downward and clawed at the intangible air. The tittering rose higher
+and higher--the cat was within six inches of the absorbed teacher's
+head--down, down, a little lower, and she grabbed his wig with her
+desperate claws, clung to it, and was snatched up into the garret in an
+instant with her trophy still in her possession! And how the light did
+blaze abroad from the master's bald pate--for the sign-painter's boy
+had GILDED it!
+
+That broke up the meeting. The boys were avenged. Vacation had come.
+
+   NOTE:--The pretended "compositions" quoted in
+   this chapter are taken without alteration from a
+   volume entitled "Prose and Poetry, by a Western
+   Lady"--but they are exactly and precisely after
+   the schoolgirl pattern, and hence are much
+   happier than any mere imitations could be.
+
+
+
+CHAPTER XXII
+
+TOM joined the new order of Cadets of Temperance, being attracted by
+the showy character of their "regalia." He promised to abstain from
+smoking, chewing, and profanity as long as he remained a member. Now he
+found out a new thing--namely, that to promise not to do a thing is the
+surest way in the world to make a body want to go and do that very
+thing. Tom soon found himself tormented with a desire to drink and
+swear; the desire grew to be so intense that nothing but the hope of a
+chance to display himself in his red sash kept him from withdrawing
+from the order. Fourth of July was coming; but he soon gave that up
+--gave it up before he had worn his shackles over forty-eight hours--and
+fixed his hopes upon old Judge Frazer, justice of the peace, who was
+apparently on his deathbed and would have a big public funeral, since
+he was so high an official. During three days Tom was deeply concerned
+about the Judge's condition and hungry for news of it. Sometimes his
+hopes ran high--so high that he would venture to get out his regalia
+and practise before the looking-glass. But the Judge had a most
+discouraging way of fluctuating. At last he was pronounced upon the
+mend--and then convalescent. Tom was disgusted; and felt a sense of
+injury, too. He handed in his resignation at once--and that night the
+Judge suffered a relapse and died. Tom resolved that he would never
+trust a man like that again.
+
+The funeral was a fine thing. The Cadets paraded in a style calculated
+to kill the late member with envy. Tom was a free boy again, however
+--there was something in that. He could drink and swear, now--but found
+to his surprise that he did not want to. The simple fact that he could,
+took the desire away, and the charm of it.
+
+Tom presently wondered to find that his coveted vacation was beginning
+to hang a little heavily on his hands.
+
+He attempted a diary--but nothing happened during three days, and so
+he abandoned it.
+
+The first of all the negro minstrel shows came to town, and made a
+sensation. Tom and Joe Harper got up a band of performers and were
+happy for two days.
+
+Even the Glorious Fourth was in some sense a failure, for it rained
+hard, there was no procession in consequence, and the greatest man in
+the world (as Tom supposed), Mr. Benton, an actual United States
+Senator, proved an overwhelming disappointment--for he was not
+twenty-five feet high, nor even anywhere in the neighborhood of it.
+
+A circus came. The boys played circus for three days afterward in
+tents made of rag carpeting--admission, three pins for boys, two for
+girls--and then circusing was abandoned.
+
+A phrenologist and a mesmerizer came--and went again and left the
+village duller and drearier than ever.
+
+There were some boys-and-girls' parties, but they were so few and so
+delightful that they only made the aching voids between ache the harder.
+
+Becky Thatcher was gone to her Constantinople home to stay with her
+parents during vacation--so there was no bright side to life anywhere.
+
+The dreadful secret of the murder was a chronic misery. It was a very
+cancer for permanency and pain.
+
+Then came the measles.
+
+During two long weeks Tom lay a prisoner, dead to the world and its
+happenings. He was very ill, he was interested in nothing. When he got
+upon his feet at last and moved feebly down-town, a melancholy change
+had come over everything and every creature. There had been a
+"revival," and everybody had "got religion," not only the adults, but
+even the boys and girls. Tom went about, hoping against hope for the
+sight of one blessed sinful face, but disappointment crossed him
+everywhere. He found Joe Harper studying a Testament, and turned sadly
+away from the depressing spectacle. He sought Ben Rogers, and found him
+visiting the poor with a basket of tracts. He hunted up Jim Hollis, who
+called his attention to the precious blessing of his late measles as a
+warning. Every boy he encountered added another ton to his depression;
+and when, in desperation, he flew for refuge at last to the bosom of
+Huckleberry Finn and was received with a Scriptural quotation, his
+heart broke and he crept home and to bed realizing that he alone of all
+the town was lost, forever and forever.
+
+And that night there came on a terrific storm, with driving rain,
+awful claps of thunder and blinding sheets of lightning. He covered his
+head with the bedclothes and waited in a horror of suspense for his
+doom; for he had not the shadow of a doubt that all this hubbub was
+about him. He believed he had taxed the forbearance of the powers above
+to the extremity of endurance and that this was the result. It might
+have seemed to him a waste of pomp and ammunition to kill a bug with a
+battery of artillery, but there seemed nothing incongruous about the
+getting up such an expensive thunderstorm as this to knock the turf
+from under an insect like himself.
+
+By and by the tempest spent itself and died without accomplishing its
+object. The boy's first impulse was to be grateful, and reform. His
+second was to wait--for there might not be any more storms.
+
+The next day the doctors were back; Tom had relapsed. The three weeks
+he spent on his back this time seemed an entire age. When he got abroad
+at last he was hardly grateful that he had been spared, remembering how
+lonely was his estate, how companionless and forlorn he was. He drifted
+listlessly down the street and found Jim Hollis acting as judge in a
+juvenile court that was trying a cat for murder, in the presence of her
+victim, a bird. He found Joe Harper and Huck Finn up an alley eating a
+stolen melon. Poor lads! they--like Tom--had suffered a relapse.
+
+
+
+CHAPTER XXIII
+
+AT last the sleepy atmosphere was stirred--and vigorously: the murder
+trial came on in the court. It became the absorbing topic of village
+talk immediately. Tom could not get away from it. Every reference to
+the murder sent a shudder to his heart, for his troubled conscience and
+fears almost persuaded him that these remarks were put forth in his
+hearing as "feelers"; he did not see how he could be suspected of
+knowing anything about the murder, but still he could not be
+comfortable in the midst of this gossip. It kept him in a cold shiver
+all the time. He took Huck to a lonely place to have a talk with him.
+It would be some relief to unseal his tongue for a little while; to
+divide his burden of distress with another sufferer. Moreover, he
+wanted to assure himself that Huck had remained discreet.
+
+"Huck, have you ever told anybody about--that?"
+
+"'Bout what?"
+
+"You know what."
+
+"Oh--'course I haven't."
+
+"Never a word?"
+
+"Never a solitary word, so help me. What makes you ask?"
+
+"Well, I was afeard."
+
+"Why, Tom Sawyer, we wouldn't be alive two days if that got found out.
+YOU know that."
+
+Tom felt more comfortable. After a pause:
+
+"Huck, they couldn't anybody get you to tell, could they?"
+
+"Get me to tell? Why, if I wanted that half-breed devil to drownd me
+they could get me to tell. They ain't no different way."
+
+"Well, that's all right, then. I reckon we're safe as long as we keep
+mum. But let's swear again, anyway. It's more surer."
+
+"I'm agreed."
+
+So they swore again with dread solemnities.
+
+"What is the talk around, Huck? I've heard a power of it."
+
+"Talk? Well, it's just Muff Potter, Muff Potter, Muff Potter all the
+time. It keeps me in a sweat, constant, so's I want to hide som'ers."
+
+"That's just the same way they go on round me. I reckon he's a goner.
+Don't you feel sorry for him, sometimes?"
+
+"Most always--most always. He ain't no account; but then he hain't
+ever done anything to hurt anybody. Just fishes a little, to get money
+to get drunk on--and loafs around considerable; but lord, we all do
+that--leastways most of us--preachers and such like. But he's kind of
+good--he give me half a fish, once, when there warn't enough for two;
+and lots of times he's kind of stood by me when I was out of luck."
+
+"Well, he's mended kites for me, Huck, and knitted hooks on to my
+line. I wish we could get him out of there."
+
+"My! we couldn't get him out, Tom. And besides, 'twouldn't do any
+good; they'd ketch him again."
+
+"Yes--so they would. But I hate to hear 'em abuse him so like the
+dickens when he never done--that."
+
+"I do too, Tom. Lord, I hear 'em say he's the bloodiest looking
+villain in this country, and they wonder he wasn't ever hung before."
+
+"Yes, they talk like that, all the time. I've heard 'em say that if he
+was to get free they'd lynch him."
+
+"And they'd do it, too."
+
+The boys had a long talk, but it brought them little comfort. As the
+twilight drew on, they found themselves hanging about the neighborhood
+of the little isolated jail, perhaps with an undefined hope that
+something would happen that might clear away their difficulties. But
+nothing happened; there seemed to be no angels or fairies interested in
+this luckless captive.
+
+The boys did as they had often done before--went to the cell grating
+and gave Potter some tobacco and matches. He was on the ground floor
+and there were no guards.
+
+His gratitude for their gifts had always smote their consciences
+before--it cut deeper than ever, this time. They felt cowardly and
+treacherous to the last degree when Potter said:
+
+"You've been mighty good to me, boys--better'n anybody else in this
+town. And I don't forget it, I don't. Often I says to myself, says I,
+'I used to mend all the boys' kites and things, and show 'em where the
+good fishin' places was, and befriend 'em what I could, and now they've
+all forgot old Muff when he's in trouble; but Tom don't, and Huck
+don't--THEY don't forget him, says I, 'and I don't forget them.' Well,
+boys, I done an awful thing--drunk and crazy at the time--that's the
+only way I account for it--and now I got to swing for it, and it's
+right. Right, and BEST, too, I reckon--hope so, anyway. Well, we won't
+talk about that. I don't want to make YOU feel bad; you've befriended
+me. But what I want to say, is, don't YOU ever get drunk--then you won't
+ever get here. Stand a litter furder west--so--that's it; it's a prime
+comfort to see faces that's friendly when a body's in such a muck of
+trouble, and there don't none come here but yourn. Good friendly
+faces--good friendly faces. Git up on one another's backs and let me
+touch 'em. That's it. Shake hands--yourn'll come through the bars, but
+mine's too big. Little hands, and weak--but they've helped Muff Potter
+a power, and they'd help him more if they could."
+
+Tom went home miserable, and his dreams that night were full of
+horrors. The next day and the day after, he hung about the court-room,
+drawn by an almost irresistible impulse to go in, but forcing himself
+to stay out. Huck was having the same experience. They studiously
+avoided each other. Each wandered away, from time to time, but the same
+dismal fascination always brought them back presently. Tom kept his
+ears open when idlers sauntered out of the court-room, but invariably
+heard distressing news--the toils were closing more and more
+relentlessly around poor Potter. At the end of the second day the
+village talk was to the effect that Injun Joe's evidence stood firm and
+unshaken, and that there was not the slightest question as to what the
+jury's verdict would be.
+
+Tom was out late, that night, and came to bed through the window. He
+was in a tremendous state of excitement. It was hours before he got to
+sleep. All the village flocked to the court-house the next morning, for
+this was to be the great day. Both sexes were about equally represented
+in the packed audience. After a long wait the jury filed in and took
+their places; shortly afterward, Potter, pale and haggard, timid and
+hopeless, was brought in, with chains upon him, and seated where all
+the curious eyes could stare at him; no less conspicuous was Injun Joe,
+stolid as ever. There was another pause, and then the judge arrived and
+the sheriff proclaimed the opening of the court. The usual whisperings
+among the lawyers and gathering together of papers followed. These
+details and accompanying delays worked up an atmosphere of preparation
+that was as impressive as it was fascinating.
+
+Now a witness was called who testified that he found Muff Potter
+washing in the brook, at an early hour of the morning that the murder
+was discovered, and that he immediately sneaked away. After some
+further questioning, counsel for the prosecution said:
+
+"Take the witness."
+
+The prisoner raised his eyes for a moment, but dropped them again when
+his own counsel said:
+
+"I have no questions to ask him."
+
+The next witness proved the finding of the knife near the corpse.
+Counsel for the prosecution said:
+
+"Take the witness."
+
+"I have no questions to ask him," Potter's lawyer replied.
+
+A third witness swore he had often seen the knife in Potter's
+possession.
+
+"Take the witness."
+
+Counsel for Potter declined to question him. The faces of the audience
+began to betray annoyance. Did this attorney mean to throw away his
+client's life without an effort?
+
+Several witnesses deposed concerning Potter's guilty behavior when
+brought to the scene of the murder. They were allowed to leave the
+stand without being cross-questioned.
+
+Every detail of the damaging circumstances that occurred in the
+graveyard upon that morning which all present remembered so well was
+brought out by credible witnesses, but none of them were cross-examined
+by Potter's lawyer. The perplexity and dissatisfaction of the house
+expressed itself in murmurs and provoked a reproof from the bench.
+Counsel for the prosecution now said:
+
+"By the oaths of citizens whose simple word is above suspicion, we
+have fastened this awful crime, beyond all possibility of question,
+upon the unhappy prisoner at the bar. We rest our case here."
+
+A groan escaped from poor Potter, and he put his face in his hands and
+rocked his body softly to and fro, while a painful silence reigned in
+the court-room. Many men were moved, and many women's compassion
+testified itself in tears. Counsel for the defence rose and said:
+
+"Your honor, in our remarks at the opening of this trial, we
+foreshadowed our purpose to prove that our client did this fearful deed
+while under the influence of a blind and irresponsible delirium
+produced by drink. We have changed our mind. We shall not offer that
+plea." [Then to the clerk:] "Call Thomas Sawyer!"
+
+A puzzled amazement awoke in every face in the house, not even
+excepting Potter's. Every eye fastened itself with wondering interest
+upon Tom as he rose and took his place upon the stand. The boy looked
+wild enough, for he was badly scared. The oath was administered.
+
+"Thomas Sawyer, where were you on the seventeenth of June, about the
+hour of midnight?"
+
+Tom glanced at Injun Joe's iron face and his tongue failed him. The
+audience listened breathless, but the words refused to come. After a
+few moments, however, the boy got a little of his strength back, and
+managed to put enough of it into his voice to make part of the house
+hear:
+
+"In the graveyard!"
+
+"A little bit louder, please. Don't be afraid. You were--"
+
+"In the graveyard."
+
+A contemptuous smile flitted across Injun Joe's face.
+
+"Were you anywhere near Horse Williams' grave?"
+
+"Yes, sir."
+
+"Speak up--just a trifle louder. How near were you?"
+
+"Near as I am to you."
+
+"Were you hidden, or not?"
+
+"I was hid."
+
+"Where?"
+
+"Behind the elms that's on the edge of the grave."
+
+Injun Joe gave a barely perceptible start.
+
+"Any one with you?"
+
+"Yes, sir. I went there with--"
+
+"Wait--wait a moment. Never mind mentioning your companion's name. We
+will produce him at the proper time. Did you carry anything there with
+you."
+
+Tom hesitated and looked confused.
+
+"Speak out, my boy--don't be diffident. The truth is always
+respectable. What did you take there?"
+
+"Only a--a--dead cat."
+
+There was a ripple of mirth, which the court checked.
+
+"We will produce the skeleton of that cat. Now, my boy, tell us
+everything that occurred--tell it in your own way--don't skip anything,
+and don't be afraid."
+
+Tom began--hesitatingly at first, but as he warmed to his subject his
+words flowed more and more easily; in a little while every sound ceased
+but his own voice; every eye fixed itself upon him; with parted lips
+and bated breath the audience hung upon his words, taking no note of
+time, rapt in the ghastly fascinations of the tale. The strain upon
+pent emotion reached its climax when the boy said:
+
+"--and as the doctor fetched the board around and Muff Potter fell,
+Injun Joe jumped with the knife and--"
+
+Crash! Quick as lightning the half-breed sprang for a window, tore his
+way through all opposers, and was gone!
+
+
+
+CHAPTER XXIV
+
+TOM was a glittering hero once more--the pet of the old, the envy of
+the young. His name even went into immortal print, for the village
+paper magnified him. There were some that believed he would be
+President, yet, if he escaped hanging.
+
+As usual, the fickle, unreasoning world took Muff Potter to its bosom
+and fondled him as lavishly as it had abused him before. But that sort
+of conduct is to the world's credit; therefore it is not well to find
+fault with it.
+
+Tom's days were days of splendor and exultation to him, but his nights
+were seasons of horror. Injun Joe infested all his dreams, and always
+with doom in his eye. Hardly any temptation could persuade the boy to
+stir abroad after nightfall. Poor Huck was in the same state of
+wretchedness and terror, for Tom had told the whole story to the lawyer
+the night before the great day of the trial, and Huck was sore afraid
+that his share in the business might leak out, yet, notwithstanding
+Injun Joe's flight had saved him the suffering of testifying in court.
+The poor fellow had got the attorney to promise secrecy, but what of
+that? Since Tom's harassed conscience had managed to drive him to the
+lawyer's house by night and wring a dread tale from lips that had been
+sealed with the dismalest and most formidable of oaths, Huck's
+confidence in the human race was well-nigh obliterated.
+
+Daily Muff Potter's gratitude made Tom glad he had spoken; but nightly
+he wished he had sealed up his tongue.
+
+Half the time Tom was afraid Injun Joe would never be captured; the
+other half he was afraid he would be. He felt sure he never could draw
+a safe breath again until that man was dead and he had seen the corpse.
+
+Rewards had been offered, the country had been scoured, but no Injun
+Joe was found. One of those omniscient and awe-inspiring marvels, a
+detective, came up from St. Louis, moused around, shook his head,
+looked wise, and made that sort of astounding success which members of
+that craft usually achieve. That is to say, he "found a clew." But you
+can't hang a "clew" for murder, and so after that detective had got
+through and gone home, Tom felt just as insecure as he was before.
+
+The slow days drifted on, and each left behind it a slightly lightened
+weight of apprehension.
+
+
+
+CHAPTER XXV
+
+THERE comes a time in every rightly-constructed boy's life when he has
+a raging desire to go somewhere and dig for hidden treasure. This
+desire suddenly came upon Tom one day. He sallied out to find Joe
+Harper, but failed of success. Next he sought Ben Rogers; he had gone
+fishing. Presently he stumbled upon Huck Finn the Red-Handed. Huck
+would answer. Tom took him to a private place and opened the matter to
+him confidentially. Huck was willing. Huck was always willing to take a
+hand in any enterprise that offered entertainment and required no
+capital, for he had a troublesome superabundance of that sort of time
+which is not money. "Where'll we dig?" said Huck.
+
+"Oh, most anywhere."
+
+"Why, is it hid all around?"
+
+"No, indeed it ain't. It's hid in mighty particular places, Huck
+--sometimes on islands, sometimes in rotten chests under the end of a
+limb of an old dead tree, just where the shadow falls at midnight; but
+mostly under the floor in ha'nted houses."
+
+"Who hides it?"
+
+"Why, robbers, of course--who'd you reckon? Sunday-school
+sup'rintendents?"
+
+"I don't know. If 'twas mine I wouldn't hide it; I'd spend it and have
+a good time."
+
+"So would I. But robbers don't do that way. They always hide it and
+leave it there."
+
+"Don't they come after it any more?"
+
+"No, they think they will, but they generally forget the marks, or
+else they die. Anyway, it lays there a long time and gets rusty; and by
+and by somebody finds an old yellow paper that tells how to find the
+marks--a paper that's got to be ciphered over about a week because it's
+mostly signs and hy'roglyphics."
+
+"Hyro--which?"
+
+"Hy'roglyphics--pictures and things, you know, that don't seem to mean
+anything."
+
+"Have you got one of them papers, Tom?"
+
+"No."
+
+"Well then, how you going to find the marks?"
+
+"I don't want any marks. They always bury it under a ha'nted house or
+on an island, or under a dead tree that's got one limb sticking out.
+Well, we've tried Jackson's Island a little, and we can try it again
+some time; and there's the old ha'nted house up the Still-House branch,
+and there's lots of dead-limb trees--dead loads of 'em."
+
+"Is it under all of them?"
+
+"How you talk! No!"
+
+"Then how you going to know which one to go for?"
+
+"Go for all of 'em!"
+
+"Why, Tom, it'll take all summer."
+
+"Well, what of that? Suppose you find a brass pot with a hundred
+dollars in it, all rusty and gray, or rotten chest full of di'monds.
+How's that?"
+
+Huck's eyes glowed.
+
+"That's bully. Plenty bully enough for me. Just you gimme the hundred
+dollars and I don't want no di'monds."
+
+"All right. But I bet you I ain't going to throw off on di'monds. Some
+of 'em's worth twenty dollars apiece--there ain't any, hardly, but's
+worth six bits or a dollar."
+
+"No! Is that so?"
+
+"Cert'nly--anybody'll tell you so. Hain't you ever seen one, Huck?"
+
+"Not as I remember."
+
+"Oh, kings have slathers of them."
+
+"Well, I don' know no kings, Tom."
+
+"I reckon you don't. But if you was to go to Europe you'd see a raft
+of 'em hopping around."
+
+"Do they hop?"
+
+"Hop?--your granny! No!"
+
+"Well, what did you say they did, for?"
+
+"Shucks, I only meant you'd SEE 'em--not hopping, of course--what do
+they want to hop for?--but I mean you'd just see 'em--scattered around,
+you know, in a kind of a general way. Like that old humpbacked Richard."
+
+"Richard? What's his other name?"
+
+"He didn't have any other name. Kings don't have any but a given name."
+
+"No?"
+
+"But they don't."
+
+"Well, if they like it, Tom, all right; but I don't want to be a king
+and have only just a given name, like a nigger. But say--where you
+going to dig first?"
+
+"Well, I don't know. S'pose we tackle that old dead-limb tree on the
+hill t'other side of Still-House branch?"
+
+"I'm agreed."
+
+So they got a crippled pick and a shovel, and set out on their
+three-mile tramp. They arrived hot and panting, and threw themselves
+down in the shade of a neighboring elm to rest and have a smoke.
+
+"I like this," said Tom.
+
+"So do I."
+
+"Say, Huck, if we find a treasure here, what you going to do with your
+share?"
+
+"Well, I'll have pie and a glass of soda every day, and I'll go to
+every circus that comes along. I bet I'll have a gay time."
+
+"Well, ain't you going to save any of it?"
+
+"Save it? What for?"
+
+"Why, so as to have something to live on, by and by."
+
+"Oh, that ain't any use. Pap would come back to thish-yer town some
+day and get his claws on it if I didn't hurry up, and I tell you he'd
+clean it out pretty quick. What you going to do with yourn, Tom?"
+
+"I'm going to buy a new drum, and a sure-'nough sword, and a red
+necktie and a bull pup, and get married."
+
+"Married!"
+
+"That's it."
+
+"Tom, you--why, you ain't in your right mind."
+
+"Wait--you'll see."
+
+"Well, that's the foolishest thing you could do. Look at pap and my
+mother. Fight! Why, they used to fight all the time. I remember, mighty
+well."
+
+"That ain't anything. The girl I'm going to marry won't fight."
+
+"Tom, I reckon they're all alike. They'll all comb a body. Now you
+better think 'bout this awhile. I tell you you better. What's the name
+of the gal?"
+
+"It ain't a gal at all--it's a girl."
+
+"It's all the same, I reckon; some says gal, some says girl--both's
+right, like enough. Anyway, what's her name, Tom?"
+
+"I'll tell you some time--not now."
+
+"All right--that'll do. Only if you get married I'll be more lonesomer
+than ever."
+
+"No you won't. You'll come and live with me. Now stir out of this and
+we'll go to digging."
+
+They worked and sweated for half an hour. No result. They toiled
+another half-hour. Still no result. Huck said:
+
+"Do they always bury it as deep as this?"
+
+"Sometimes--not always. Not generally. I reckon we haven't got the
+right place."
+
+So they chose a new spot and began again. The labor dragged a little,
+but still they made progress. They pegged away in silence for some
+time. Finally Huck leaned on his shovel, swabbed the beaded drops from
+his brow with his sleeve, and said:
+
+"Where you going to dig next, after we get this one?"
+
+"I reckon maybe we'll tackle the old tree that's over yonder on
+Cardiff Hill back of the widow's."
+
+"I reckon that'll be a good one. But won't the widow take it away from
+us, Tom? It's on her land."
+
+"SHE take it away! Maybe she'd like to try it once. Whoever finds one
+of these hid treasures, it belongs to him. It don't make any difference
+whose land it's on."
+
+That was satisfactory. The work went on. By and by Huck said:
+
+"Blame it, we must be in the wrong place again. What do you think?"
+
+"It is mighty curious, Huck. I don't understand it. Sometimes witches
+interfere. I reckon maybe that's what's the trouble now."
+
+"Shucks! Witches ain't got no power in the daytime."
+
+"Well, that's so. I didn't think of that. Oh, I know what the matter
+is! What a blamed lot of fools we are! You got to find out where the
+shadow of the limb falls at midnight, and that's where you dig!"
+
+"Then consound it, we've fooled away all this work for nothing. Now
+hang it all, we got to come back in the night. It's an awful long way.
+Can you get out?"
+
+"I bet I will. We've got to do it to-night, too, because if somebody
+sees these holes they'll know in a minute what's here and they'll go
+for it."
+
+"Well, I'll come around and maow to-night."
+
+"All right. Let's hide the tools in the bushes."
+
+The boys were there that night, about the appointed time. They sat in
+the shadow waiting. It was a lonely place, and an hour made solemn by
+old traditions. Spirits whispered in the rustling leaves, ghosts lurked
+in the murky nooks, the deep baying of a hound floated up out of the
+distance, an owl answered with his sepulchral note. The boys were
+subdued by these solemnities, and talked little. By and by they judged
+that twelve had come; they marked where the shadow fell, and began to
+dig. Their hopes commenced to rise. Their interest grew stronger, and
+their industry kept pace with it. The hole deepened and still deepened,
+but every time their hearts jumped to hear the pick strike upon
+something, they only suffered a new disappointment. It was only a stone
+or a chunk. At last Tom said:
+
+"It ain't any use, Huck, we're wrong again."
+
+"Well, but we CAN'T be wrong. We spotted the shadder to a dot."
+
+"I know it, but then there's another thing."
+
+"What's that?".
+
+"Why, we only guessed at the time. Like enough it was too late or too
+early."
+
+Huck dropped his shovel.
+
+"That's it," said he. "That's the very trouble. We got to give this
+one up. We can't ever tell the right time, and besides this kind of
+thing's too awful, here this time of night with witches and ghosts
+a-fluttering around so. I feel as if something's behind me all the time;
+and I'm afeard to turn around, becuz maybe there's others in front
+a-waiting for a chance. I been creeping all over, ever since I got here."
+
+"Well, I've been pretty much so, too, Huck. They most always put in a
+dead man when they bury a treasure under a tree, to look out for it."
+
+"Lordy!"
+
+"Yes, they do. I've always heard that."
+
+"Tom, I don't like to fool around much where there's dead people. A
+body's bound to get into trouble with 'em, sure."
+
+"I don't like to stir 'em up, either. S'pose this one here was to
+stick his skull out and say something!"
+
+"Don't Tom! It's awful."
+
+"Well, it just is. Huck, I don't feel comfortable a bit."
+
+"Say, Tom, let's give this place up, and try somewheres else."
+
+"All right, I reckon we better."
+
+"What'll it be?"
+
+Tom considered awhile; and then said:
+
+"The ha'nted house. That's it!"
+
+"Blame it, I don't like ha'nted houses, Tom. Why, they're a dern sight
+worse'n dead people. Dead people might talk, maybe, but they don't come
+sliding around in a shroud, when you ain't noticing, and peep over your
+shoulder all of a sudden and grit their teeth, the way a ghost does. I
+couldn't stand such a thing as that, Tom--nobody could."
+
+"Yes, but, Huck, ghosts don't travel around only at night. They won't
+hender us from digging there in the daytime."
+
+"Well, that's so. But you know mighty well people don't go about that
+ha'nted house in the day nor the night."
+
+"Well, that's mostly because they don't like to go where a man's been
+murdered, anyway--but nothing's ever been seen around that house except
+in the night--just some blue lights slipping by the windows--no regular
+ghosts."
+
+"Well, where you see one of them blue lights flickering around, Tom,
+you can bet there's a ghost mighty close behind it. It stands to
+reason. Becuz you know that they don't anybody but ghosts use 'em."
+
+"Yes, that's so. But anyway they don't come around in the daytime, so
+what's the use of our being afeard?"
+
+"Well, all right. We'll tackle the ha'nted house if you say so--but I
+reckon it's taking chances."
+
+They had started down the hill by this time. There in the middle of
+the moonlit valley below them stood the "ha'nted" house, utterly
+isolated, its fences gone long ago, rank weeds smothering the very
+doorsteps, the chimney crumbled to ruin, the window-sashes vacant, a
+corner of the roof caved in. The boys gazed awhile, half expecting to
+see a blue light flit past a window; then talking in a low tone, as
+befitted the time and the circumstances, they struck far off to the
+right, to give the haunted house a wide berth, and took their way
+homeward through the woods that adorned the rearward side of Cardiff
+Hill.
+
+
+
+CHAPTER XXVI
+
+ABOUT noon the next day the boys arrived at the dead tree; they had
+come for their tools. Tom was impatient to go to the haunted house;
+Huck was measurably so, also--but suddenly said:
+
+"Lookyhere, Tom, do you know what day it is?"
+
+Tom mentally ran over the days of the week, and then quickly lifted
+his eyes with a startled look in them--
+
+"My! I never once thought of it, Huck!"
+
+"Well, I didn't neither, but all at once it popped onto me that it was
+Friday."
+
+"Blame it, a body can't be too careful, Huck. We might 'a' got into an
+awful scrape, tackling such a thing on a Friday."
+
+"MIGHT! Better say we WOULD! There's some lucky days, maybe, but
+Friday ain't."
+
+"Any fool knows that. I don't reckon YOU was the first that found it
+out, Huck."
+
+"Well, I never said I was, did I? And Friday ain't all, neither. I had
+a rotten bad dream last night--dreampt about rats."
+
+"No! Sure sign of trouble. Did they fight?"
+
+"No."
+
+"Well, that's good, Huck. When they don't fight it's only a sign that
+there's trouble around, you know. All we got to do is to look mighty
+sharp and keep out of it. We'll drop this thing for to-day, and play.
+Do you know Robin Hood, Huck?"
+
+"No. Who's Robin Hood?"
+
+"Why, he was one of the greatest men that was ever in England--and the
+best. He was a robber."
+
+"Cracky, I wisht I was. Who did he rob?"
+
+"Only sheriffs and bishops and rich people and kings, and such like.
+But he never bothered the poor. He loved 'em. He always divided up with
+'em perfectly square."
+
+"Well, he must 'a' been a brick."
+
+"I bet you he was, Huck. Oh, he was the noblest man that ever was.
+They ain't any such men now, I can tell you. He could lick any man in
+England, with one hand tied behind him; and he could take his yew bow
+and plug a ten-cent piece every time, a mile and a half."
+
+"What's a YEW bow?"
+
+"I don't know. It's some kind of a bow, of course. And if he hit that
+dime only on the edge he would set down and cry--and curse. But we'll
+play Robin Hood--it's nobby fun. I'll learn you."
+
+"I'm agreed."
+
+So they played Robin Hood all the afternoon, now and then casting a
+yearning eye down upon the haunted house and passing a remark about the
+morrow's prospects and possibilities there. As the sun began to sink
+into the west they took their way homeward athwart the long shadows of
+the trees and soon were buried from sight in the forests of Cardiff
+Hill.
+
+On Saturday, shortly after noon, the boys were at the dead tree again.
+They had a smoke and a chat in the shade, and then dug a little in
+their last hole, not with great hope, but merely because Tom said there
+were so many cases where people had given up a treasure after getting
+down within six inches of it, and then somebody else had come along and
+turned it up with a single thrust of a shovel. The thing failed this
+time, however, so the boys shouldered their tools and went away feeling
+that they had not trifled with fortune, but had fulfilled all the
+requirements that belong to the business of treasure-hunting.
+
+When they reached the haunted house there was something so weird and
+grisly about the dead silence that reigned there under the baking sun,
+and something so depressing about the loneliness and desolation of the
+place, that they were afraid, for a moment, to venture in. Then they
+crept to the door and took a trembling peep. They saw a weed-grown,
+floorless room, unplastered, an ancient fireplace, vacant windows, a
+ruinous staircase; and here, there, and everywhere hung ragged and
+abandoned cobwebs. They presently entered, softly, with quickened
+pulses, talking in whispers, ears alert to catch the slightest sound,
+and muscles tense and ready for instant retreat.
+
+In a little while familiarity modified their fears and they gave the
+place a critical and interested examination, rather admiring their own
+boldness, and wondering at it, too. Next they wanted to look up-stairs.
+This was something like cutting off retreat, but they got to daring
+each other, and of course there could be but one result--they threw
+their tools into a corner and made the ascent. Up there were the same
+signs of decay. In one corner they found a closet that promised
+mystery, but the promise was a fraud--there was nothing in it. Their
+courage was up now and well in hand. They were about to go down and
+begin work when--
+
+"Sh!" said Tom.
+
+"What is it?" whispered Huck, blanching with fright.
+
+"Sh!... There!... Hear it?"
+
+"Yes!... Oh, my! Let's run!"
+
+"Keep still! Don't you budge! They're coming right toward the door."
+
+The boys stretched themselves upon the floor with their eyes to
+knot-holes in the planking, and lay waiting, in a misery of fear.
+
+"They've stopped.... No--coming.... Here they are. Don't whisper
+another word, Huck. My goodness, I wish I was out of this!"
+
+Two men entered. Each boy said to himself: "There's the old deaf and
+dumb Spaniard that's been about town once or twice lately--never saw
+t'other man before."
+
+"T'other" was a ragged, unkempt creature, with nothing very pleasant
+in his face. The Spaniard was wrapped in a serape; he had bushy white
+whiskers; long white hair flowed from under his sombrero, and he wore
+green goggles. When they came in, "t'other" was talking in a low voice;
+they sat down on the ground, facing the door, with their backs to the
+wall, and the speaker continued his remarks. His manner became less
+guarded and his words more distinct as he proceeded:
+
+"No," said he, "I've thought it all over, and I don't like it. It's
+dangerous."
+
+"Dangerous!" grunted the "deaf and dumb" Spaniard--to the vast
+surprise of the boys. "Milksop!"
+
+This voice made the boys gasp and quake. It was Injun Joe's! There was
+silence for some time. Then Joe said:
+
+"What's any more dangerous than that job up yonder--but nothing's come
+of it."
+
+"That's different. Away up the river so, and not another house about.
+'Twon't ever be known that we tried, anyway, long as we didn't succeed."
+
+"Well, what's more dangerous than coming here in the daytime!--anybody
+would suspicion us that saw us."
+
+"I know that. But there warn't any other place as handy after that
+fool of a job. I want to quit this shanty. I wanted to yesterday, only
+it warn't any use trying to stir out of here, with those infernal boys
+playing over there on the hill right in full view."
+
+"Those infernal boys" quaked again under the inspiration of this
+remark, and thought how lucky it was that they had remembered it was
+Friday and concluded to wait a day. They wished in their hearts they
+had waited a year.
+
+The two men got out some food and made a luncheon. After a long and
+thoughtful silence, Injun Joe said:
+
+"Look here, lad--you go back up the river where you belong. Wait there
+till you hear from me. I'll take the chances on dropping into this town
+just once more, for a look. We'll do that 'dangerous' job after I've
+spied around a little and think things look well for it. Then for
+Texas! We'll leg it together!"
+
+This was satisfactory. Both men presently fell to yawning, and Injun
+Joe said:
+
+"I'm dead for sleep! It's your turn to watch."
+
+He curled down in the weeds and soon began to snore. His comrade
+stirred him once or twice and he became quiet. Presently the watcher
+began to nod; his head drooped lower and lower, both men began to snore
+now.
+
+The boys drew a long, grateful breath. Tom whispered:
+
+"Now's our chance--come!"
+
+Huck said:
+
+"I can't--I'd die if they was to wake."
+
+Tom urged--Huck held back. At last Tom rose slowly and softly, and
+started alone. But the first step he made wrung such a hideous creak
+from the crazy floor that he sank down almost dead with fright. He
+never made a second attempt. The boys lay there counting the dragging
+moments till it seemed to them that time must be done and eternity
+growing gray; and then they were grateful to note that at last the sun
+was setting.
+
+Now one snore ceased. Injun Joe sat up, stared around--smiled grimly
+upon his comrade, whose head was drooping upon his knees--stirred him
+up with his foot and said:
+
+"Here! YOU'RE a watchman, ain't you! All right, though--nothing's
+happened."
+
+"My! have I been asleep?"
+
+"Oh, partly, partly. Nearly time for us to be moving, pard. What'll we
+do with what little swag we've got left?"
+
+"I don't know--leave it here as we've always done, I reckon. No use to
+take it away till we start south. Six hundred and fifty in silver's
+something to carry."
+
+"Well--all right--it won't matter to come here once more."
+
+"No--but I'd say come in the night as we used to do--it's better."
+
+"Yes: but look here; it may be a good while before I get the right
+chance at that job; accidents might happen; 'tain't in such a very good
+place; we'll just regularly bury it--and bury it deep."
+
+"Good idea," said the comrade, who walked across the room, knelt down,
+raised one of the rearward hearth-stones and took out a bag that
+jingled pleasantly. He subtracted from it twenty or thirty dollars for
+himself and as much for Injun Joe, and passed the bag to the latter,
+who was on his knees in the corner, now, digging with his bowie-knife.
+
+The boys forgot all their fears, all their miseries in an instant.
+With gloating eyes they watched every movement. Luck!--the splendor of
+it was beyond all imagination! Six hundred dollars was money enough to
+make half a dozen boys rich! Here was treasure-hunting under the
+happiest auspices--there would not be any bothersome uncertainty as to
+where to dig. They nudged each other every moment--eloquent nudges and
+easily understood, for they simply meant--"Oh, but ain't you glad NOW
+we're here!"
+
+Joe's knife struck upon something.
+
+"Hello!" said he.
+
+"What is it?" said his comrade.
+
+"Half-rotten plank--no, it's a box, I believe. Here--bear a hand and
+we'll see what it's here for. Never mind, I've broke a hole."
+
+He reached his hand in and drew it out--
+
+"Man, it's money!"
+
+The two men examined the handful of coins. They were gold. The boys
+above were as excited as themselves, and as delighted.
+
+Joe's comrade said:
+
+"We'll make quick work of this. There's an old rusty pick over amongst
+the weeds in the corner the other side of the fireplace--I saw it a
+minute ago."
+
+He ran and brought the boys' pick and shovel. Injun Joe took the pick,
+looked it over critically, shook his head, muttered something to
+himself, and then began to use it. The box was soon unearthed. It was
+not very large; it was iron bound and had been very strong before the
+slow years had injured it. The men contemplated the treasure awhile in
+blissful silence.
+
+"Pard, there's thousands of dollars here," said Injun Joe.
+
+"'Twas always said that Murrel's gang used to be around here one
+summer," the stranger observed.
+
+"I know it," said Injun Joe; "and this looks like it, I should say."
+
+"Now you won't need to do that job."
+
+The half-breed frowned. Said he:
+
+"You don't know me. Least you don't know all about that thing. 'Tain't
+robbery altogether--it's REVENGE!" and a wicked light flamed in his
+eyes. "I'll need your help in it. When it's finished--then Texas. Go
+home to your Nance and your kids, and stand by till you hear from me."
+
+"Well--if you say so; what'll we do with this--bury it again?"
+
+"Yes. [Ravishing delight overhead.] NO! by the great Sachem, no!
+[Profound distress overhead.] I'd nearly forgot. That pick had fresh
+earth on it! [The boys were sick with terror in a moment.] What
+business has a pick and a shovel here? What business with fresh earth
+on them? Who brought them here--and where are they gone? Have you heard
+anybody?--seen anybody? What! bury it again and leave them to come and
+see the ground disturbed? Not exactly--not exactly. We'll take it to my
+den."
+
+"Why, of course! Might have thought of that before. You mean Number
+One?"
+
+"No--Number Two--under the cross. The other place is bad--too common."
+
+"All right. It's nearly dark enough to start."
+
+Injun Joe got up and went about from window to window cautiously
+peeping out. Presently he said:
+
+"Who could have brought those tools here? Do you reckon they can be
+up-stairs?"
+
+The boys' breath forsook them. Injun Joe put his hand on his knife,
+halted a moment, undecided, and then turned toward the stairway. The
+boys thought of the closet, but their strength was gone. The steps came
+creaking up the stairs--the intolerable distress of the situation woke
+the stricken resolution of the lads--they were about to spring for the
+closet, when there was a crash of rotten timbers and Injun Joe landed
+on the ground amid the debris of the ruined stairway. He gathered
+himself up cursing, and his comrade said:
+
+"Now what's the use of all that? If it's anybody, and they're up
+there, let them STAY there--who cares? If they want to jump down, now,
+and get into trouble, who objects? It will be dark in fifteen minutes
+--and then let them follow us if they want to. I'm willing. In my
+opinion, whoever hove those things in here caught a sight of us and
+took us for ghosts or devils or something. I'll bet they're running
+yet."
+
+Joe grumbled awhile; then he agreed with his friend that what daylight
+was left ought to be economized in getting things ready for leaving.
+Shortly afterward they slipped out of the house in the deepening
+twilight, and moved toward the river with their precious box.
+
+Tom and Huck rose up, weak but vastly relieved, and stared after them
+through the chinks between the logs of the house. Follow? Not they.
+They were content to reach ground again without broken necks, and take
+the townward track over the hill. They did not talk much. They were too
+much absorbed in hating themselves--hating the ill luck that made them
+take the spade and the pick there. But for that, Injun Joe never would
+have suspected. He would have hidden the silver with the gold to wait
+there till his "revenge" was satisfied, and then he would have had the
+misfortune to find that money turn up missing. Bitter, bitter luck that
+the tools were ever brought there!
+
+They resolved to keep a lookout for that Spaniard when he should come
+to town spying out for chances to do his revengeful job, and follow him
+to "Number Two," wherever that might be. Then a ghastly thought
+occurred to Tom.
+
+"Revenge? What if he means US, Huck!"
+
+"Oh, don't!" said Huck, nearly fainting.
+
+They talked it all over, and as they entered town they agreed to
+believe that he might possibly mean somebody else--at least that he
+might at least mean nobody but Tom, since only Tom had testified.
+
+Very, very small comfort it was to Tom to be alone in danger! Company
+would be a palpable improvement, he thought.
+
+
+
+CHAPTER XXVII
+
+THE adventure of the day mightily tormented Tom's dreams that night.
+Four times he had his hands on that rich treasure and four times it
+wasted to nothingness in his fingers as sleep forsook him and
+wakefulness brought back the hard reality of his misfortune. As he lay
+in the early morning recalling the incidents of his great adventure, he
+noticed that they seemed curiously subdued and far away--somewhat as if
+they had happened in another world, or in a time long gone by. Then it
+occurred to him that the great adventure itself must be a dream! There
+was one very strong argument in favor of this idea--namely, that the
+quantity of coin he had seen was too vast to be real. He had never seen
+as much as fifty dollars in one mass before, and he was like all boys
+of his age and station in life, in that he imagined that all references
+to "hundreds" and "thousands" were mere fanciful forms of speech, and
+that no such sums really existed in the world. He never had supposed
+for a moment that so large a sum as a hundred dollars was to be found
+in actual money in any one's possession. If his notions of hidden
+treasure had been analyzed, they would have been found to consist of a
+handful of real dimes and a bushel of vague, splendid, ungraspable
+dollars.
+
+But the incidents of his adventure grew sensibly sharper and clearer
+under the attrition of thinking them over, and so he presently found
+himself leaning to the impression that the thing might not have been a
+dream, after all. This uncertainty must be swept away. He would snatch
+a hurried breakfast and go and find Huck. Huck was sitting on the
+gunwale of a flatboat, listlessly dangling his feet in the water and
+looking very melancholy. Tom concluded to let Huck lead up to the
+subject. If he did not do it, then the adventure would be proved to
+have been only a dream.
+
+"Hello, Huck!"
+
+"Hello, yourself."
+
+Silence, for a minute.
+
+"Tom, if we'd 'a' left the blame tools at the dead tree, we'd 'a' got
+the money. Oh, ain't it awful!"
+
+"'Tain't a dream, then, 'tain't a dream! Somehow I most wish it was.
+Dog'd if I don't, Huck."
+
+"What ain't a dream?"
+
+"Oh, that thing yesterday. I been half thinking it was."
+
+"Dream! If them stairs hadn't broke down you'd 'a' seen how much dream
+it was! I've had dreams enough all night--with that patch-eyed Spanish
+devil going for me all through 'em--rot him!"
+
+"No, not rot him. FIND him! Track the money!"
+
+"Tom, we'll never find him. A feller don't have only one chance for
+such a pile--and that one's lost. I'd feel mighty shaky if I was to see
+him, anyway."
+
+"Well, so'd I; but I'd like to see him, anyway--and track him out--to
+his Number Two."
+
+"Number Two--yes, that's it. I been thinking 'bout that. But I can't
+make nothing out of it. What do you reckon it is?"
+
+"I dono. It's too deep. Say, Huck--maybe it's the number of a house!"
+
+"Goody!... No, Tom, that ain't it. If it is, it ain't in this
+one-horse town. They ain't no numbers here."
+
+"Well, that's so. Lemme think a minute. Here--it's the number of a
+room--in a tavern, you know!"
+
+"Oh, that's the trick! They ain't only two taverns. We can find out
+quick."
+
+"You stay here, Huck, till I come."
+
+Tom was off at once. He did not care to have Huck's company in public
+places. He was gone half an hour. He found that in the best tavern, No.
+2 had long been occupied by a young lawyer, and was still so occupied.
+In the less ostentatious house, No. 2 was a mystery. The
+tavern-keeper's young son said it was kept locked all the time, and he
+never saw anybody go into it or come out of it except at night; he did
+not know any particular reason for this state of things; had had some
+little curiosity, but it was rather feeble; had made the most of the
+mystery by entertaining himself with the idea that that room was
+"ha'nted"; had noticed that there was a light in there the night before.
+
+"That's what I've found out, Huck. I reckon that's the very No. 2
+we're after."
+
+"I reckon it is, Tom. Now what you going to do?"
+
+"Lemme think."
+
+Tom thought a long time. Then he said:
+
+"I'll tell you. The back door of that No. 2 is the door that comes out
+into that little close alley between the tavern and the old rattle trap
+of a brick store. Now you get hold of all the door-keys you can find,
+and I'll nip all of auntie's, and the first dark night we'll go there
+and try 'em. And mind you, keep a lookout for Injun Joe, because he
+said he was going to drop into town and spy around once more for a
+chance to get his revenge. If you see him, you just follow him; and if
+he don't go to that No. 2, that ain't the place."
+
+"Lordy, I don't want to foller him by myself!"
+
+"Why, it'll be night, sure. He mightn't ever see you--and if he did,
+maybe he'd never think anything."
+
+"Well, if it's pretty dark I reckon I'll track him. I dono--I dono.
+I'll try."
+
+"You bet I'll follow him, if it's dark, Huck. Why, he might 'a' found
+out he couldn't get his revenge, and be going right after that money."
+
+"It's so, Tom, it's so. I'll foller him; I will, by jingoes!"
+
+"Now you're TALKING! Don't you ever weaken, Huck, and I won't."
+
+
+
+CHAPTER XXVIII
+
+THAT night Tom and Huck were ready for their adventure. They hung
+about the neighborhood of the tavern until after nine, one watching the
+alley at a distance and the other the tavern door. Nobody entered the
+alley or left it; nobody resembling the Spaniard entered or left the
+tavern door. The night promised to be a fair one; so Tom went home with
+the understanding that if a considerable degree of darkness came on,
+Huck was to come and "maow," whereupon he would slip out and try the
+keys. But the night remained clear, and Huck closed his watch and
+retired to bed in an empty sugar hogshead about twelve.
+
+Tuesday the boys had the same ill luck. Also Wednesday. But Thursday
+night promised better. Tom slipped out in good season with his aunt's
+old tin lantern, and a large towel to blindfold it with. He hid the
+lantern in Huck's sugar hogshead and the watch began. An hour before
+midnight the tavern closed up and its lights (the only ones
+thereabouts) were put out. No Spaniard had been seen. Nobody had
+entered or left the alley. Everything was auspicious. The blackness of
+darkness reigned, the perfect stillness was interrupted only by
+occasional mutterings of distant thunder.
+
+Tom got his lantern, lit it in the hogshead, wrapped it closely in the
+towel, and the two adventurers crept in the gloom toward the tavern.
+Huck stood sentry and Tom felt his way into the alley. Then there was a
+season of waiting anxiety that weighed upon Huck's spirits like a
+mountain. He began to wish he could see a flash from the lantern--it
+would frighten him, but it would at least tell him that Tom was alive
+yet. It seemed hours since Tom had disappeared. Surely he must have
+fainted; maybe he was dead; maybe his heart had burst under terror and
+excitement. In his uneasiness Huck found himself drawing closer and
+closer to the alley; fearing all sorts of dreadful things, and
+momentarily expecting some catastrophe to happen that would take away
+his breath. There was not much to take away, for he seemed only able to
+inhale it by thimblefuls, and his heart would soon wear itself out, the
+way it was beating. Suddenly there was a flash of light and Tom came
+tearing by him: "Run!" said he; "run, for your life!"
+
+He needn't have repeated it; once was enough; Huck was making thirty
+or forty miles an hour before the repetition was uttered. The boys
+never stopped till they reached the shed of a deserted slaughter-house
+at the lower end of the village. Just as they got within its shelter
+the storm burst and the rain poured down. As soon as Tom got his breath
+he said:
+
+"Huck, it was awful! I tried two of the keys, just as soft as I could;
+but they seemed to make such a power of racket that I couldn't hardly
+get my breath I was so scared. They wouldn't turn in the lock, either.
+Well, without noticing what I was doing, I took hold of the knob, and
+open comes the door! It warn't locked! I hopped in, and shook off the
+towel, and, GREAT CAESAR'S GHOST!"
+
+"What!--what'd you see, Tom?"
+
+"Huck, I most stepped onto Injun Joe's hand!"
+
+"No!"
+
+"Yes! He was lying there, sound asleep on the floor, with his old
+patch on his eye and his arms spread out."
+
+"Lordy, what did you do? Did he wake up?"
+
+"No, never budged. Drunk, I reckon. I just grabbed that towel and
+started!"
+
+"I'd never 'a' thought of the towel, I bet!"
+
+"Well, I would. My aunt would make me mighty sick if I lost it."
+
+"Say, Tom, did you see that box?"
+
+"Huck, I didn't wait to look around. I didn't see the box, I didn't
+see the cross. I didn't see anything but a bottle and a tin cup on the
+floor by Injun Joe; yes, I saw two barrels and lots more bottles in the
+room. Don't you see, now, what's the matter with that ha'nted room?"
+
+"How?"
+
+"Why, it's ha'nted with whiskey! Maybe ALL the Temperance Taverns have
+got a ha'nted room, hey, Huck?"
+
+"Well, I reckon maybe that's so. Who'd 'a' thought such a thing? But
+say, Tom, now's a mighty good time to get that box, if Injun Joe's
+drunk."
+
+"It is, that! You try it!"
+
+Huck shuddered.
+
+"Well, no--I reckon not."
+
+"And I reckon not, Huck. Only one bottle alongside of Injun Joe ain't
+enough. If there'd been three, he'd be drunk enough and I'd do it."
+
+There was a long pause for reflection, and then Tom said:
+
+"Lookyhere, Huck, less not try that thing any more till we know Injun
+Joe's not in there. It's too scary. Now, if we watch every night, we'll
+be dead sure to see him go out, some time or other, and then we'll
+snatch that box quicker'n lightning."
+
+"Well, I'm agreed. I'll watch the whole night long, and I'll do it
+every night, too, if you'll do the other part of the job."
+
+"All right, I will. All you got to do is to trot up Hooper Street a
+block and maow--and if I'm asleep, you throw some gravel at the window
+and that'll fetch me."
+
+"Agreed, and good as wheat!"
+
+"Now, Huck, the storm's over, and I'll go home. It'll begin to be
+daylight in a couple of hours. You go back and watch that long, will
+you?"
+
+"I said I would, Tom, and I will. I'll ha'nt that tavern every night
+for a year! I'll sleep all day and I'll stand watch all night."
+
+"That's all right. Now, where you going to sleep?"
+
+"In Ben Rogers' hayloft. He lets me, and so does his pap's nigger man,
+Uncle Jake. I tote water for Uncle Jake whenever he wants me to, and
+any time I ask him he gives me a little something to eat if he can
+spare it. That's a mighty good nigger, Tom. He likes me, becuz I don't
+ever act as if I was above him. Sometime I've set right down and eat
+WITH him. But you needn't tell that. A body's got to do things when
+he's awful hungry he wouldn't want to do as a steady thing."
+
+"Well, if I don't want you in the daytime, I'll let you sleep. I won't
+come bothering around. Any time you see something's up, in the night,
+just skip right around and maow."
+
+
+
+CHAPTER XXIX
+
+THE first thing Tom heard on Friday morning was a glad piece of news
+--Judge Thatcher's family had come back to town the night before. Both
+Injun Joe and the treasure sunk into secondary importance for a moment,
+and Becky took the chief place in the boy's interest. He saw her and
+they had an exhausting good time playing "hi-spy" and "gully-keeper"
+with a crowd of their school-mates. The day was completed and crowned
+in a peculiarly satisfactory way: Becky teased her mother to appoint
+the next day for the long-promised and long-delayed picnic, and she
+consented. The child's delight was boundless; and Tom's not more
+moderate. The invitations were sent out before sunset, and straightway
+the young folks of the village were thrown into a fever of preparation
+and pleasurable anticipation. Tom's excitement enabled him to keep
+awake until a pretty late hour, and he had good hopes of hearing Huck's
+"maow," and of having his treasure to astonish Becky and the picnickers
+with, next day; but he was disappointed. No signal came that night.
+
+Morning came, eventually, and by ten or eleven o'clock a giddy and
+rollicking company were gathered at Judge Thatcher's, and everything
+was ready for a start. It was not the custom for elderly people to mar
+the picnics with their presence. The children were considered safe
+enough under the wings of a few young ladies of eighteen and a few
+young gentlemen of twenty-three or thereabouts. The old steam ferryboat
+was chartered for the occasion; presently the gay throng filed up the
+main street laden with provision-baskets. Sid was sick and had to miss
+the fun; Mary remained at home to entertain him. The last thing Mrs.
+Thatcher said to Becky, was:
+
+"You'll not get back till late. Perhaps you'd better stay all night
+with some of the girls that live near the ferry-landing, child."
+
+"Then I'll stay with Susy Harper, mamma."
+
+"Very well. And mind and behave yourself and don't be any trouble."
+
+Presently, as they tripped along, Tom said to Becky:
+
+"Say--I'll tell you what we'll do. 'Stead of going to Joe Harper's
+we'll climb right up the hill and stop at the Widow Douglas'. She'll
+have ice-cream! She has it most every day--dead loads of it. And she'll
+be awful glad to have us."
+
+"Oh, that will be fun!"
+
+Then Becky reflected a moment and said:
+
+"But what will mamma say?"
+
+"How'll she ever know?"
+
+The girl turned the idea over in her mind, and said reluctantly:
+
+"I reckon it's wrong--but--"
+
+"But shucks! Your mother won't know, and so what's the harm? All she
+wants is that you'll be safe; and I bet you she'd 'a' said go there if
+she'd 'a' thought of it. I know she would!"
+
+The Widow Douglas' splendid hospitality was a tempting bait. It and
+Tom's persuasions presently carried the day. So it was decided to say
+nothing anybody about the night's programme. Presently it occurred to
+Tom that maybe Huck might come this very night and give the signal. The
+thought took a deal of the spirit out of his anticipations. Still he
+could not bear to give up the fun at Widow Douglas'. And why should he
+give it up, he reasoned--the signal did not come the night before, so
+why should it be any more likely to come to-night? The sure fun of the
+evening outweighed the uncertain treasure; and, boy-like, he determined
+to yield to the stronger inclination and not allow himself to think of
+the box of money another time that day.
+
+Three miles below town the ferryboat stopped at the mouth of a woody
+hollow and tied up. The crowd swarmed ashore and soon the forest
+distances and craggy heights echoed far and near with shoutings and
+laughter. All the different ways of getting hot and tired were gone
+through with, and by-and-by the rovers straggled back to camp fortified
+with responsible appetites, and then the destruction of the good things
+began. After the feast there was a refreshing season of rest and chat
+in the shade of spreading oaks. By-and-by somebody shouted:
+
+"Who's ready for the cave?"
+
+Everybody was. Bundles of candles were procured, and straightway there
+was a general scamper up the hill. The mouth of the cave was up the
+hillside--an opening shaped like a letter A. Its massive oaken door
+stood unbarred. Within was a small chamber, chilly as an ice-house, and
+walled by Nature with solid limestone that was dewy with a cold sweat.
+It was romantic and mysterious to stand here in the deep gloom and look
+out upon the green valley shining in the sun. But the impressiveness of
+the situation quickly wore off, and the romping began again. The moment
+a candle was lighted there was a general rush upon the owner of it; a
+struggle and a gallant defence followed, but the candle was soon
+knocked down or blown out, and then there was a glad clamor of laughter
+and a new chase. But all things have an end. By-and-by the procession
+went filing down the steep descent of the main avenue, the flickering
+rank of lights dimly revealing the lofty walls of rock almost to their
+point of junction sixty feet overhead. This main avenue was not more
+than eight or ten feet wide. Every few steps other lofty and still
+narrower crevices branched from it on either hand--for McDougal's cave
+was but a vast labyrinth of crooked aisles that ran into each other and
+out again and led nowhere. It was said that one might wander days and
+nights together through its intricate tangle of rifts and chasms, and
+never find the end of the cave; and that he might go down, and down,
+and still down, into the earth, and it was just the same--labyrinth
+under labyrinth, and no end to any of them. No man "knew" the cave.
+That was an impossible thing. Most of the young men knew a portion of
+it, and it was not customary to venture much beyond this known portion.
+Tom Sawyer knew as much of the cave as any one.
+
+The procession moved along the main avenue some three-quarters of a
+mile, and then groups and couples began to slip aside into branch
+avenues, fly along the dismal corridors, and take each other by
+surprise at points where the corridors joined again. Parties were able
+to elude each other for the space of half an hour without going beyond
+the "known" ground.
+
+By-and-by, one group after another came straggling back to the mouth
+of the cave, panting, hilarious, smeared from head to foot with tallow
+drippings, daubed with clay, and entirely delighted with the success of
+the day. Then they were astonished to find that they had been taking no
+note of time and that night was about at hand. The clanging bell had
+been calling for half an hour. However, this sort of close to the day's
+adventures was romantic and therefore satisfactory. When the ferryboat
+with her wild freight pushed into the stream, nobody cared sixpence for
+the wasted time but the captain of the craft.
+
+Huck was already upon his watch when the ferryboat's lights went
+glinting past the wharf. He heard no noise on board, for the young
+people were as subdued and still as people usually are who are nearly
+tired to death. He wondered what boat it was, and why she did not stop
+at the wharf--and then he dropped her out of his mind and put his
+attention upon his business. The night was growing cloudy and dark. Ten
+o'clock came, and the noise of vehicles ceased, scattered lights began
+to wink out, all straggling foot-passengers disappeared, the village
+betook itself to its slumbers and left the small watcher alone with the
+silence and the ghosts. Eleven o'clock came, and the tavern lights were
+put out; darkness everywhere, now. Huck waited what seemed a weary long
+time, but nothing happened. His faith was weakening. Was there any use?
+Was there really any use? Why not give it up and turn in?
+
+A noise fell upon his ear. He was all attention in an instant. The
+alley door closed softly. He sprang to the corner of the brick store.
+The next moment two men brushed by him, and one seemed to have
+something under his arm. It must be that box! So they were going to
+remove the treasure. Why call Tom now? It would be absurd--the men
+would get away with the box and never be found again. No, he would
+stick to their wake and follow them; he would trust to the darkness for
+security from discovery. So communing with himself, Huck stepped out
+and glided along behind the men, cat-like, with bare feet, allowing
+them to keep just far enough ahead not to be invisible.
+
+They moved up the river street three blocks, then turned to the left
+up a cross-street. They went straight ahead, then, until they came to
+the path that led up Cardiff Hill; this they took. They passed by the
+old Welshman's house, half-way up the hill, without hesitating, and
+still climbed upward. Good, thought Huck, they will bury it in the old
+quarry. But they never stopped at the quarry. They passed on, up the
+summit. They plunged into the narrow path between the tall sumach
+bushes, and were at once hidden in the gloom. Huck closed up and
+shortened his distance, now, for they would never be able to see him.
+He trotted along awhile; then slackened his pace, fearing he was
+gaining too fast; moved on a piece, then stopped altogether; listened;
+no sound; none, save that he seemed to hear the beating of his own
+heart. The hooting of an owl came over the hill--ominous sound! But no
+footsteps. Heavens, was everything lost! He was about to spring with
+winged feet, when a man cleared his throat not four feet from him!
+Huck's heart shot into his throat, but he swallowed it again; and then
+he stood there shaking as if a dozen agues had taken charge of him at
+once, and so weak that he thought he must surely fall to the ground. He
+knew where he was. He knew he was within five steps of the stile
+leading into Widow Douglas' grounds. Very well, he thought, let them
+bury it there; it won't be hard to find.
+
+Now there was a voice--a very low voice--Injun Joe's:
+
+"Damn her, maybe she's got company--there's lights, late as it is."
+
+"I can't see any."
+
+This was that stranger's voice--the stranger of the haunted house. A
+deadly chill went to Huck's heart--this, then, was the "revenge" job!
+His thought was, to fly. Then he remembered that the Widow Douglas had
+been kind to him more than once, and maybe these men were going to
+murder her. He wished he dared venture to warn her; but he knew he
+didn't dare--they might come and catch him. He thought all this and
+more in the moment that elapsed between the stranger's remark and Injun
+Joe's next--which was--
+
+"Because the bush is in your way. Now--this way--now you see, don't
+you?"
+
+"Yes. Well, there IS company there, I reckon. Better give it up."
+
+"Give it up, and I just leaving this country forever! Give it up and
+maybe never have another chance. I tell you again, as I've told you
+before, I don't care for her swag--you may have it. But her husband was
+rough on me--many times he was rough on me--and mainly he was the
+justice of the peace that jugged me for a vagrant. And that ain't all.
+It ain't a millionth part of it! He had me HORSEWHIPPED!--horsewhipped
+in front of the jail, like a nigger!--with all the town looking on!
+HORSEWHIPPED!--do you understand? He took advantage of me and died. But
+I'll take it out of HER."
+
+"Oh, don't kill her! Don't do that!"
+
+"Kill? Who said anything about killing? I would kill HIM if he was
+here; but not her. When you want to get revenge on a woman you don't
+kill her--bosh! you go for her looks. You slit her nostrils--you notch
+her ears like a sow!"
+
+"By God, that's--"
+
+"Keep your opinion to yourself! It will be safest for you. I'll tie
+her to the bed. If she bleeds to death, is that my fault? I'll not cry,
+if she does. My friend, you'll help me in this thing--for MY sake
+--that's why you're here--I mightn't be able alone. If you flinch, I'll
+kill you. Do you understand that? And if I have to kill you, I'll kill
+her--and then I reckon nobody'll ever know much about who done this
+business."
+
+"Well, if it's got to be done, let's get at it. The quicker the
+better--I'm all in a shiver."
+
+"Do it NOW? And company there? Look here--I'll get suspicious of you,
+first thing you know. No--we'll wait till the lights are out--there's
+no hurry."
+
+Huck felt that a silence was going to ensue--a thing still more awful
+than any amount of murderous talk; so he held his breath and stepped
+gingerly back; planted his foot carefully and firmly, after balancing,
+one-legged, in a precarious way and almost toppling over, first on one
+side and then on the other. He took another step back, with the same
+elaboration and the same risks; then another and another, and--a twig
+snapped under his foot! His breath stopped and he listened. There was
+no sound--the stillness was perfect. His gratitude was measureless. Now
+he turned in his tracks, between the walls of sumach bushes--turned
+himself as carefully as if he were a ship--and then stepped quickly but
+cautiously along. When he emerged at the quarry he felt secure, and so
+he picked up his nimble heels and flew. Down, down he sped, till he
+reached the Welshman's. He banged at the door, and presently the heads
+of the old man and his two stalwart sons were thrust from windows.
+
+"What's the row there? Who's banging? What do you want?"
+
+"Let me in--quick! I'll tell everything."
+
+"Why, who are you?"
+
+"Huckleberry Finn--quick, let me in!"
+
+"Huckleberry Finn, indeed! It ain't a name to open many doors, I
+judge! But let him in, lads, and let's see what's the trouble."
+
+"Please don't ever tell I told you," were Huck's first words when he
+got in. "Please don't--I'd be killed, sure--but the widow's been good
+friends to me sometimes, and I want to tell--I WILL tell if you'll
+promise you won't ever say it was me."
+
+"By George, he HAS got something to tell, or he wouldn't act so!"
+exclaimed the old man; "out with it and nobody here'll ever tell, lad."
+
+Three minutes later the old man and his sons, well armed, were up the
+hill, and just entering the sumach path on tiptoe, their weapons in
+their hands. Huck accompanied them no further. He hid behind a great
+bowlder and fell to listening. There was a lagging, anxious silence,
+and then all of a sudden there was an explosion of firearms and a cry.
+
+Huck waited for no particulars. He sprang away and sped down the hill
+as fast as his legs could carry him.
+
+
+
+CHAPTER XXX
+
+AS the earliest suspicion of dawn appeared on Sunday morning, Huck
+came groping up the hill and rapped gently at the old Welshman's door.
+The inmates were asleep, but it was a sleep that was set on a
+hair-trigger, on account of the exciting episode of the night. A call
+came from a window:
+
+"Who's there!"
+
+Huck's scared voice answered in a low tone:
+
+"Please let me in! It's only Huck Finn!"
+
+"It's a name that can open this door night or day, lad!--and welcome!"
+
+These were strange words to the vagabond boy's ears, and the
+pleasantest he had ever heard. He could not recollect that the closing
+word had ever been applied in his case before. The door was quickly
+unlocked, and he entered. Huck was given a seat and the old man and his
+brace of tall sons speedily dressed themselves.
+
+"Now, my boy, I hope you're good and hungry, because breakfast will be
+ready as soon as the sun's up, and we'll have a piping hot one, too
+--make yourself easy about that! I and the boys hoped you'd turn up and
+stop here last night."
+
+"I was awful scared," said Huck, "and I run. I took out when the
+pistols went off, and I didn't stop for three mile. I've come now becuz
+I wanted to know about it, you know; and I come before daylight becuz I
+didn't want to run across them devils, even if they was dead."
+
+"Well, poor chap, you do look as if you'd had a hard night of it--but
+there's a bed here for you when you've had your breakfast. No, they
+ain't dead, lad--we are sorry enough for that. You see we knew right
+where to put our hands on them, by your description; so we crept along
+on tiptoe till we got within fifteen feet of them--dark as a cellar
+that sumach path was--and just then I found I was going to sneeze. It
+was the meanest kind of luck! I tried to keep it back, but no use
+--'twas bound to come, and it did come! I was in the lead with my pistol
+raised, and when the sneeze started those scoundrels a-rustling to get
+out of the path, I sung out, 'Fire boys!' and blazed away at the place
+where the rustling was. So did the boys. But they were off in a jiffy,
+those villains, and we after them, down through the woods. I judge we
+never touched them. They fired a shot apiece as they started, but their
+bullets whizzed by and didn't do us any harm. As soon as we lost the
+sound of their feet we quit chasing, and went down and stirred up the
+constables. They got a posse together, and went off to guard the river
+bank, and as soon as it is light the sheriff and a gang are going to
+beat up the woods. My boys will be with them presently. I wish we had
+some sort of description of those rascals--'twould help a good deal.
+But you couldn't see what they were like, in the dark, lad, I suppose?"
+
+"Oh yes; I saw them down-town and follered them."
+
+"Splendid! Describe them--describe them, my boy!"
+
+"One's the old deaf and dumb Spaniard that's ben around here once or
+twice, and t'other's a mean-looking, ragged--"
+
+"That's enough, lad, we know the men! Happened on them in the woods
+back of the widow's one day, and they slunk away. Off with you, boys,
+and tell the sheriff--get your breakfast to-morrow morning!"
+
+The Welshman's sons departed at once. As they were leaving the room
+Huck sprang up and exclaimed:
+
+"Oh, please don't tell ANYbody it was me that blowed on them! Oh,
+please!"
+
+"All right if you say it, Huck, but you ought to have the credit of
+what you did."
+
+"Oh no, no! Please don't tell!"
+
+When the young men were gone, the old Welshman said:
+
+"They won't tell--and I won't. But why don't you want it known?"
+
+Huck would not explain, further than to say that he already knew too
+much about one of those men and would not have the man know that he
+knew anything against him for the whole world--he would be killed for
+knowing it, sure.
+
+The old man promised secrecy once more, and said:
+
+"How did you come to follow these fellows, lad? Were they looking
+suspicious?"
+
+Huck was silent while he framed a duly cautious reply. Then he said:
+
+"Well, you see, I'm a kind of a hard lot,--least everybody says so,
+and I don't see nothing agin it--and sometimes I can't sleep much, on
+account of thinking about it and sort of trying to strike out a new way
+of doing. That was the way of it last night. I couldn't sleep, and so I
+come along up-street 'bout midnight, a-turning it all over, and when I
+got to that old shackly brick store by the Temperance Tavern, I backed
+up agin the wall to have another think. Well, just then along comes
+these two chaps slipping along close by me, with something under their
+arm, and I reckoned they'd stole it. One was a-smoking, and t'other one
+wanted a light; so they stopped right before me and the cigars lit up
+their faces and I see that the big one was the deaf and dumb Spaniard,
+by his white whiskers and the patch on his eye, and t'other one was a
+rusty, ragged-looking devil."
+
+"Could you see the rags by the light of the cigars?"
+
+This staggered Huck for a moment. Then he said:
+
+"Well, I don't know--but somehow it seems as if I did."
+
+"Then they went on, and you--"
+
+"Follered 'em--yes. That was it. I wanted to see what was up--they
+sneaked along so. I dogged 'em to the widder's stile, and stood in the
+dark and heard the ragged one beg for the widder, and the Spaniard
+swear he'd spile her looks just as I told you and your two--"
+
+"What! The DEAF AND DUMB man said all that!"
+
+Huck had made another terrible mistake! He was trying his best to keep
+the old man from getting the faintest hint of who the Spaniard might
+be, and yet his tongue seemed determined to get him into trouble in
+spite of all he could do. He made several efforts to creep out of his
+scrape, but the old man's eye was upon him and he made blunder after
+blunder. Presently the Welshman said:
+
+"My boy, don't be afraid of me. I wouldn't hurt a hair of your head
+for all the world. No--I'd protect you--I'd protect you. This Spaniard
+is not deaf and dumb; you've let that slip without intending it; you
+can't cover that up now. You know something about that Spaniard that
+you want to keep dark. Now trust me--tell me what it is, and trust me
+--I won't betray you."
+
+Huck looked into the old man's honest eyes a moment, then bent over
+and whispered in his ear:
+
+"'Tain't a Spaniard--it's Injun Joe!"
+
+The Welshman almost jumped out of his chair. In a moment he said:
+
+"It's all plain enough, now. When you talked about notching ears and
+slitting noses I judged that that was your own embellishment, because
+white men don't take that sort of revenge. But an Injun! That's a
+different matter altogether."
+
+During breakfast the talk went on, and in the course of it the old man
+said that the last thing which he and his sons had done, before going
+to bed, was to get a lantern and examine the stile and its vicinity for
+marks of blood. They found none, but captured a bulky bundle of--
+
+"Of WHAT?"
+
+If the words had been lightning they could not have leaped with a more
+stunning suddenness from Huck's blanched lips. His eyes were staring
+wide, now, and his breath suspended--waiting for the answer. The
+Welshman started--stared in return--three seconds--five seconds--ten
+--then replied:
+
+"Of burglar's tools. Why, what's the MATTER with you?"
+
+Huck sank back, panting gently, but deeply, unutterably grateful. The
+Welshman eyed him gravely, curiously--and presently said:
+
+"Yes, burglar's tools. That appears to relieve you a good deal. But
+what did give you that turn? What were YOU expecting we'd found?"
+
+Huck was in a close place--the inquiring eye was upon him--he would
+have given anything for material for a plausible answer--nothing
+suggested itself--the inquiring eye was boring deeper and deeper--a
+senseless reply offered--there was no time to weigh it, so at a venture
+he uttered it--feebly:
+
+"Sunday-school books, maybe."
+
+Poor Huck was too distressed to smile, but the old man laughed loud
+and joyously, shook up the details of his anatomy from head to foot,
+and ended by saying that such a laugh was money in a-man's pocket,
+because it cut down the doctor's bill like everything. Then he added:
+
+"Poor old chap, you're white and jaded--you ain't well a bit--no
+wonder you're a little flighty and off your balance. But you'll come
+out of it. Rest and sleep will fetch you out all right, I hope."
+
+Huck was irritated to think he had been such a goose and betrayed such
+a suspicious excitement, for he had dropped the idea that the parcel
+brought from the tavern was the treasure, as soon as he had heard the
+talk at the widow's stile. He had only thought it was not the treasure,
+however--he had not known that it wasn't--and so the suggestion of a
+captured bundle was too much for his self-possession. But on the whole
+he felt glad the little episode had happened, for now he knew beyond
+all question that that bundle was not THE bundle, and so his mind was
+at rest and exceedingly comfortable. In fact, everything seemed to be
+drifting just in the right direction, now; the treasure must be still
+in No. 2, the men would be captured and jailed that day, and he and Tom
+could seize the gold that night without any trouble or any fear of
+interruption.
+
+Just as breakfast was completed there was a knock at the door. Huck
+jumped for a hiding-place, for he had no mind to be connected even
+remotely with the late event. The Welshman admitted several ladies and
+gentlemen, among them the Widow Douglas, and noticed that groups of
+citizens were climbing up the hill--to stare at the stile. So the news
+had spread. The Welshman had to tell the story of the night to the
+visitors. The widow's gratitude for her preservation was outspoken.
+
+"Don't say a word about it, madam. There's another that you're more
+beholden to than you are to me and my boys, maybe, but he don't allow
+me to tell his name. We wouldn't have been there but for him."
+
+Of course this excited a curiosity so vast that it almost belittled
+the main matter--but the Welshman allowed it to eat into the vitals of
+his visitors, and through them be transmitted to the whole town, for he
+refused to part with his secret. When all else had been learned, the
+widow said:
+
+"I went to sleep reading in bed and slept straight through all that
+noise. Why didn't you come and wake me?"
+
+"We judged it warn't worth while. Those fellows warn't likely to come
+again--they hadn't any tools left to work with, and what was the use of
+waking you up and scaring you to death? My three negro men stood guard
+at your house all the rest of the night. They've just come back."
+
+More visitors came, and the story had to be told and retold for a
+couple of hours more.
+
+There was no Sabbath-school during day-school vacation, but everybody
+was early at church. The stirring event was well canvassed. News came
+that not a sign of the two villains had been yet discovered. When the
+sermon was finished, Judge Thatcher's wife dropped alongside of Mrs.
+Harper as she moved down the aisle with the crowd and said:
+
+"Is my Becky going to sleep all day? I just expected she would be
+tired to death."
+
+"Your Becky?"
+
+"Yes," with a startled look--"didn't she stay with you last night?"
+
+"Why, no."
+
+Mrs. Thatcher turned pale, and sank into a pew, just as Aunt Polly,
+talking briskly with a friend, passed by. Aunt Polly said:
+
+"Good-morning, Mrs. Thatcher. Good-morning, Mrs. Harper. I've got a
+boy that's turned up missing. I reckon my Tom stayed at your house last
+night--one of you. And now he's afraid to come to church. I've got to
+settle with him."
+
+Mrs. Thatcher shook her head feebly and turned paler than ever.
+
+"He didn't stay with us," said Mrs. Harper, beginning to look uneasy.
+A marked anxiety came into Aunt Polly's face.
+
+"Joe Harper, have you seen my Tom this morning?"
+
+"No'm."
+
+"When did you see him last?"
+
+Joe tried to remember, but was not sure he could say. The people had
+stopped moving out of church. Whispers passed along, and a boding
+uneasiness took possession of every countenance. Children were
+anxiously questioned, and young teachers. They all said they had not
+noticed whether Tom and Becky were on board the ferryboat on the
+homeward trip; it was dark; no one thought of inquiring if any one was
+missing. One young man finally blurted out his fear that they were
+still in the cave! Mrs. Thatcher swooned away. Aunt Polly fell to
+crying and wringing her hands.
+
+The alarm swept from lip to lip, from group to group, from street to
+street, and within five minutes the bells were wildly clanging and the
+whole town was up! The Cardiff Hill episode sank into instant
+insignificance, the burglars were forgotten, horses were saddled,
+skiffs were manned, the ferryboat ordered out, and before the horror
+was half an hour old, two hundred men were pouring down highroad and
+river toward the cave.
+
+All the long afternoon the village seemed empty and dead. Many women
+visited Aunt Polly and Mrs. Thatcher and tried to comfort them. They
+cried with them, too, and that was still better than words. All the
+tedious night the town waited for news; but when the morning dawned at
+last, all the word that came was, "Send more candles--and send food."
+Mrs. Thatcher was almost crazed; and Aunt Polly, also. Judge Thatcher
+sent messages of hope and encouragement from the cave, but they
+conveyed no real cheer.
+
+The old Welshman came home toward daylight, spattered with
+candle-grease, smeared with clay, and almost worn out. He found Huck
+still in the bed that had been provided for him, and delirious with
+fever. The physicians were all at the cave, so the Widow Douglas came
+and took charge of the patient. She said she would do her best by him,
+because, whether he was good, bad, or indifferent, he was the Lord's,
+and nothing that was the Lord's was a thing to be neglected. The
+Welshman said Huck had good spots in him, and the widow said:
+
+"You can depend on it. That's the Lord's mark. He don't leave it off.
+He never does. Puts it somewhere on every creature that comes from his
+hands."
+
+Early in the forenoon parties of jaded men began to straggle into the
+village, but the strongest of the citizens continued searching. All the
+news that could be gained was that remotenesses of the cavern were
+being ransacked that had never been visited before; that every corner
+and crevice was going to be thoroughly searched; that wherever one
+wandered through the maze of passages, lights were to be seen flitting
+hither and thither in the distance, and shoutings and pistol-shots sent
+their hollow reverberations to the ear down the sombre aisles. In one
+place, far from the section usually traversed by tourists, the names
+"BECKY & TOM" had been found traced upon the rocky wall with
+candle-smoke, and near at hand a grease-soiled bit of ribbon. Mrs.
+Thatcher recognized the ribbon and cried over it. She said it was the
+last relic she should ever have of her child; and that no other memorial
+of her could ever be so precious, because this one parted latest from
+the living body before the awful death came. Some said that now and
+then, in the cave, a far-away speck of light would glimmer, and then a
+glorious shout would burst forth and a score of men go trooping down the
+echoing aisle--and then a sickening disappointment always followed; the
+children were not there; it was only a searcher's light.
+
+Three dreadful days and nights dragged their tedious hours along, and
+the village sank into a hopeless stupor. No one had heart for anything.
+The accidental discovery, just made, that the proprietor of the
+Temperance Tavern kept liquor on his premises, scarcely fluttered the
+public pulse, tremendous as the fact was. In a lucid interval, Huck
+feebly led up to the subject of taverns, and finally asked--dimly
+dreading the worst--if anything had been discovered at the Temperance
+Tavern since he had been ill.
+
+"Yes," said the widow.
+
+Huck started up in bed, wild-eyed:
+
+"What? What was it?"
+
+"Liquor!--and the place has been shut up. Lie down, child--what a turn
+you did give me!"
+
+"Only tell me just one thing--only just one--please! Was it Tom Sawyer
+that found it?"
+
+The widow burst into tears. "Hush, hush, child, hush! I've told you
+before, you must NOT talk. You are very, very sick!"
+
+Then nothing but liquor had been found; there would have been a great
+powwow if it had been the gold. So the treasure was gone forever--gone
+forever! But what could she be crying about? Curious that she should
+cry.
+
+These thoughts worked their dim way through Huck's mind, and under the
+weariness they gave him he fell asleep. The widow said to herself:
+
+"There--he's asleep, poor wreck. Tom Sawyer find it! Pity but somebody
+could find Tom Sawyer! Ah, there ain't many left, now, that's got hope
+enough, or strength enough, either, to go on searching."
+
+
+
+CHAPTER XXXI
+
+NOW to return to Tom and Becky's share in the picnic. They tripped
+along the murky aisles with the rest of the company, visiting the
+familiar wonders of the cave--wonders dubbed with rather
+over-descriptive names, such as "The Drawing-Room," "The Cathedral,"
+"Aladdin's Palace," and so on. Presently the hide-and-seek frolicking
+began, and Tom and Becky engaged in it with zeal until the exertion
+began to grow a trifle wearisome; then they wandered down a sinuous
+avenue holding their candles aloft and reading the tangled web-work of
+names, dates, post-office addresses, and mottoes with which the rocky
+walls had been frescoed (in candle-smoke). Still drifting along and
+talking, they scarcely noticed that they were now in a part of the cave
+whose walls were not frescoed. They smoked their own names under an
+overhanging shelf and moved on. Presently they came to a place where a
+little stream of water, trickling over a ledge and carrying a limestone
+sediment with it, had, in the slow-dragging ages, formed a laced and
+ruffled Niagara in gleaming and imperishable stone. Tom squeezed his
+small body behind it in order to illuminate it for Becky's
+gratification. He found that it curtained a sort of steep natural
+stairway which was enclosed between narrow walls, and at once the
+ambition to be a discoverer seized him. Becky responded to his call,
+and they made a smoke-mark for future guidance, and started upon their
+quest. They wound this way and that, far down into the secret depths of
+the cave, made another mark, and branched off in search of novelties to
+tell the upper world about. In one place they found a spacious cavern,
+from whose ceiling depended a multitude of shining stalactites of the
+length and circumference of a man's leg; they walked all about it,
+wondering and admiring, and presently left it by one of the numerous
+passages that opened into it. This shortly brought them to a bewitching
+spring, whose basin was incrusted with a frostwork of glittering
+crystals; it was in the midst of a cavern whose walls were supported by
+many fantastic pillars which had been formed by the joining of great
+stalactites and stalagmites together, the result of the ceaseless
+water-drip of centuries. Under the roof vast knots of bats had packed
+themselves together, thousands in a bunch; the lights disturbed the
+creatures and they came flocking down by hundreds, squeaking and
+darting furiously at the candles. Tom knew their ways and the danger of
+this sort of conduct. He seized Becky's hand and hurried her into the
+first corridor that offered; and none too soon, for a bat struck
+Becky's light out with its wing while she was passing out of the
+cavern. The bats chased the children a good distance; but the fugitives
+plunged into every new passage that offered, and at last got rid of the
+perilous things. Tom found a subterranean lake, shortly, which
+stretched its dim length away until its shape was lost in the shadows.
+He wanted to explore its borders, but concluded that it would be best
+to sit down and rest awhile, first. Now, for the first time, the deep
+stillness of the place laid a clammy hand upon the spirits of the
+children. Becky said:
+
+"Why, I didn't notice, but it seems ever so long since I heard any of
+the others."
+
+"Come to think, Becky, we are away down below them--and I don't know
+how far away north, or south, or east, or whichever it is. We couldn't
+hear them here."
+
+Becky grew apprehensive.
+
+"I wonder how long we've been down here, Tom? We better start back."
+
+"Yes, I reckon we better. P'raps we better."
+
+"Can you find the way, Tom? It's all a mixed-up crookedness to me."
+
+"I reckon I could find it--but then the bats. If they put our candles
+out it will be an awful fix. Let's try some other way, so as not to go
+through there."
+
+"Well. But I hope we won't get lost. It would be so awful!" and the
+girl shuddered at the thought of the dreadful possibilities.
+
+They started through a corridor, and traversed it in silence a long
+way, glancing at each new opening, to see if there was anything
+familiar about the look of it; but they were all strange. Every time
+Tom made an examination, Becky would watch his face for an encouraging
+sign, and he would say cheerily:
+
+"Oh, it's all right. This ain't the one, but we'll come to it right
+away!"
+
+But he felt less and less hopeful with each failure, and presently
+began to turn off into diverging avenues at sheer random, in desperate
+hope of finding the one that was wanted. He still said it was "all
+right," but there was such a leaden dread at his heart that the words
+had lost their ring and sounded just as if he had said, "All is lost!"
+Becky clung to his side in an anguish of fear, and tried hard to keep
+back the tears, but they would come. At last she said:
+
+"Oh, Tom, never mind the bats, let's go back that way! We seem to get
+worse and worse off all the time."
+
+"Listen!" said he.
+
+Profound silence; silence so deep that even their breathings were
+conspicuous in the hush. Tom shouted. The call went echoing down the
+empty aisles and died out in the distance in a faint sound that
+resembled a ripple of mocking laughter.
+
+"Oh, don't do it again, Tom, it is too horrid," said Becky.
+
+"It is horrid, but I better, Becky; they might hear us, you know," and
+he shouted again.
+
+The "might" was even a chillier horror than the ghostly laughter, it
+so confessed a perishing hope. The children stood still and listened;
+but there was no result. Tom turned upon the back track at once, and
+hurried his steps. It was but a little while before a certain
+indecision in his manner revealed another fearful fact to Becky--he
+could not find his way back!
+
+"Oh, Tom, you didn't make any marks!"
+
+"Becky, I was such a fool! Such a fool! I never thought we might want
+to come back! No--I can't find the way. It's all mixed up."
+
+"Tom, Tom, we're lost! we're lost! We never can get out of this awful
+place! Oh, why DID we ever leave the others!"
+
+She sank to the ground and burst into such a frenzy of crying that Tom
+was appalled with the idea that she might die, or lose her reason. He
+sat down by her and put his arms around her; she buried her face in his
+bosom, she clung to him, she poured out her terrors, her unavailing
+regrets, and the far echoes turned them all to jeering laughter. Tom
+begged her to pluck up hope again, and she said she could not. He fell
+to blaming and abusing himself for getting her into this miserable
+situation; this had a better effect. She said she would try to hope
+again, she would get up and follow wherever he might lead if only he
+would not talk like that any more. For he was no more to blame than
+she, she said.
+
+So they moved on again--aimlessly--simply at random--all they could do
+was to move, keep moving. For a little while, hope made a show of
+reviving--not with any reason to back it, but only because it is its
+nature to revive when the spring has not been taken out of it by age
+and familiarity with failure.
+
+By-and-by Tom took Becky's candle and blew it out. This economy meant
+so much! Words were not needed. Becky understood, and her hope died
+again. She knew that Tom had a whole candle and three or four pieces in
+his pockets--yet he must economize.
+
+By-and-by, fatigue began to assert its claims; the children tried to
+pay attention, for it was dreadful to think of sitting down when time
+was grown to be so precious, moving, in some direction, in any
+direction, was at least progress and might bear fruit; but to sit down
+was to invite death and shorten its pursuit.
+
+At last Becky's frail limbs refused to carry her farther. She sat
+down. Tom rested with her, and they talked of home, and the friends
+there, and the comfortable beds and, above all, the light! Becky cried,
+and Tom tried to think of some way of comforting her, but all his
+encouragements were grown threadbare with use, and sounded like
+sarcasms. Fatigue bore so heavily upon Becky that she drowsed off to
+sleep. Tom was grateful. He sat looking into her drawn face and saw it
+grow smooth and natural under the influence of pleasant dreams; and
+by-and-by a smile dawned and rested there. The peaceful face reflected
+somewhat of peace and healing into his own spirit, and his thoughts
+wandered away to bygone times and dreamy memories. While he was deep in
+his musings, Becky woke up with a breezy little laugh--but it was
+stricken dead upon her lips, and a groan followed it.
+
+"Oh, how COULD I sleep! I wish I never, never had waked! No! No, I
+don't, Tom! Don't look so! I won't say it again."
+
+"I'm glad you've slept, Becky; you'll feel rested, now, and we'll find
+the way out."
+
+"We can try, Tom; but I've seen such a beautiful country in my dream.
+I reckon we are going there."
+
+"Maybe not, maybe not. Cheer up, Becky, and let's go on trying."
+
+They rose up and wandered along, hand in hand and hopeless. They tried
+to estimate how long they had been in the cave, but all they knew was
+that it seemed days and weeks, and yet it was plain that this could not
+be, for their candles were not gone yet. A long time after this--they
+could not tell how long--Tom said they must go softly and listen for
+dripping water--they must find a spring. They found one presently, and
+Tom said it was time to rest again. Both were cruelly tired, yet Becky
+said she thought she could go a little farther. She was surprised to
+hear Tom dissent. She could not understand it. They sat down, and Tom
+fastened his candle to the wall in front of them with some clay.
+Thought was soon busy; nothing was said for some time. Then Becky broke
+the silence:
+
+"Tom, I am so hungry!"
+
+Tom took something out of his pocket.
+
+"Do you remember this?" said he.
+
+Becky almost smiled.
+
+"It's our wedding-cake, Tom."
+
+"Yes--I wish it was as big as a barrel, for it's all we've got."
+
+"I saved it from the picnic for us to dream on, Tom, the way grown-up
+people do with wedding-cake--but it'll be our--"
+
+She dropped the sentence where it was. Tom divided the cake and Becky
+ate with good appetite, while Tom nibbled at his moiety. There was
+abundance of cold water to finish the feast with. By-and-by Becky
+suggested that they move on again. Tom was silent a moment. Then he
+said:
+
+"Becky, can you bear it if I tell you something?"
+
+Becky's face paled, but she thought she could.
+
+"Well, then, Becky, we must stay here, where there's water to drink.
+That little piece is our last candle!"
+
+Becky gave loose to tears and wailings. Tom did what he could to
+comfort her, but with little effect. At length Becky said:
+
+"Tom!"
+
+"Well, Becky?"
+
+"They'll miss us and hunt for us!"
+
+"Yes, they will! Certainly they will!"
+
+"Maybe they're hunting for us now, Tom."
+
+"Why, I reckon maybe they are. I hope they are."
+
+"When would they miss us, Tom?"
+
+"When they get back to the boat, I reckon."
+
+"Tom, it might be dark then--would they notice we hadn't come?"
+
+"I don't know. But anyway, your mother would miss you as soon as they
+got home."
+
+A frightened look in Becky's face brought Tom to his senses and he saw
+that he had made a blunder. Becky was not to have gone home that night!
+The children became silent and thoughtful. In a moment a new burst of
+grief from Becky showed Tom that the thing in his mind had struck hers
+also--that the Sabbath morning might be half spent before Mrs. Thatcher
+discovered that Becky was not at Mrs. Harper's.
+
+The children fastened their eyes upon their bit of candle and watched
+it melt slowly and pitilessly away; saw the half inch of wick stand
+alone at last; saw the feeble flame rise and fall, climb the thin
+column of smoke, linger at its top a moment, and then--the horror of
+utter darkness reigned!
+
+How long afterward it was that Becky came to a slow consciousness that
+she was crying in Tom's arms, neither could tell. All that they knew
+was, that after what seemed a mighty stretch of time, both awoke out of
+a dead stupor of sleep and resumed their miseries once more. Tom said
+it might be Sunday, now--maybe Monday. He tried to get Becky to talk,
+but her sorrows were too oppressive, all her hopes were gone. Tom said
+that they must have been missed long ago, and no doubt the search was
+going on. He would shout and maybe some one would come. He tried it;
+but in the darkness the distant echoes sounded so hideously that he
+tried it no more.
+
+The hours wasted away, and hunger came to torment the captives again.
+A portion of Tom's half of the cake was left; they divided and ate it.
+But they seemed hungrier than before. The poor morsel of food only
+whetted desire.
+
+By-and-by Tom said:
+
+"SH! Did you hear that?"
+
+Both held their breath and listened. There was a sound like the
+faintest, far-off shout. Instantly Tom answered it, and leading Becky
+by the hand, started groping down the corridor in its direction.
+Presently he listened again; again the sound was heard, and apparently
+a little nearer.
+
+"It's them!" said Tom; "they're coming! Come along, Becky--we're all
+right now!"
+
+The joy of the prisoners was almost overwhelming. Their speed was
+slow, however, because pitfalls were somewhat common, and had to be
+guarded against. They shortly came to one and had to stop. It might be
+three feet deep, it might be a hundred--there was no passing it at any
+rate. Tom got down on his breast and reached as far down as he could.
+No bottom. They must stay there and wait until the searchers came. They
+listened; evidently the distant shoutings were growing more distant! a
+moment or two more and they had gone altogether. The heart-sinking
+misery of it! Tom whooped until he was hoarse, but it was of no use. He
+talked hopefully to Becky; but an age of anxious waiting passed and no
+sounds came again.
+
+The children groped their way back to the spring. The weary time
+dragged on; they slept again, and awoke famished and woe-stricken. Tom
+believed it must be Tuesday by this time.
+
+Now an idea struck him. There were some side passages near at hand. It
+would be better to explore some of these than bear the weight of the
+heavy time in idleness. He took a kite-line from his pocket, tied it to
+a projection, and he and Becky started, Tom in the lead, unwinding the
+line as he groped along. At the end of twenty steps the corridor ended
+in a "jumping-off place." Tom got down on his knees and felt below, and
+then as far around the corner as he could reach with his hands
+conveniently; he made an effort to stretch yet a little farther to the
+right, and at that moment, not twenty yards away, a human hand, holding
+a candle, appeared from behind a rock! Tom lifted up a glorious shout,
+and instantly that hand was followed by the body it belonged to--Injun
+Joe's! Tom was paralyzed; he could not move. He was vastly gratified
+the next moment, to see the "Spaniard" take to his heels and get
+himself out of sight. Tom wondered that Joe had not recognized his
+voice and come over and killed him for testifying in court. But the
+echoes must have disguised the voice. Without doubt, that was it, he
+reasoned. Tom's fright weakened every muscle in his body. He said to
+himself that if he had strength enough to get back to the spring he
+would stay there, and nothing should tempt him to run the risk of
+meeting Injun Joe again. He was careful to keep from Becky what it was
+he had seen. He told her he had only shouted "for luck."
+
+But hunger and wretchedness rise superior to fears in the long run.
+Another tedious wait at the spring and another long sleep brought
+changes. The children awoke tortured with a raging hunger. Tom believed
+that it must be Wednesday or Thursday or even Friday or Saturday, now,
+and that the search had been given over. He proposed to explore another
+passage. He felt willing to risk Injun Joe and all other terrors. But
+Becky was very weak. She had sunk into a dreary apathy and would not be
+roused. She said she would wait, now, where she was, and die--it would
+not be long. She told Tom to go with the kite-line and explore if he
+chose; but she implored him to come back every little while and speak
+to her; and she made him promise that when the awful time came, he
+would stay by her and hold her hand until all was over.
+
+Tom kissed her, with a choking sensation in his throat, and made a
+show of being confident of finding the searchers or an escape from the
+cave; then he took the kite-line in his hand and went groping down one
+of the passages on his hands and knees, distressed with hunger and sick
+with bodings of coming doom.
+
+
+
+CHAPTER XXXII
+
+TUESDAY afternoon came, and waned to the twilight. The village of St.
+Petersburg still mourned. The lost children had not been found. Public
+prayers had been offered up for them, and many and many a private
+prayer that had the petitioner's whole heart in it; but still no good
+news came from the cave. The majority of the searchers had given up the
+quest and gone back to their daily avocations, saying that it was plain
+the children could never be found. Mrs. Thatcher was very ill, and a
+great part of the time delirious. People said it was heartbreaking to
+hear her call her child, and raise her head and listen a whole minute
+at a time, then lay it wearily down again with a moan. Aunt Polly had
+drooped into a settled melancholy, and her gray hair had grown almost
+white. The village went to its rest on Tuesday night, sad and forlorn.
+
+Away in the middle of the night a wild peal burst from the village
+bells, and in a moment the streets were swarming with frantic half-clad
+people, who shouted, "Turn out! turn out! they're found! they're
+found!" Tin pans and horns were added to the din, the population massed
+itself and moved toward the river, met the children coming in an open
+carriage drawn by shouting citizens, thronged around it, joined its
+homeward march, and swept magnificently up the main street roaring
+huzzah after huzzah!
+
+The village was illuminated; nobody went to bed again; it was the
+greatest night the little town had ever seen. During the first half-hour
+a procession of villagers filed through Judge Thatcher's house, seized
+the saved ones and kissed them, squeezed Mrs. Thatcher's hand, tried to
+speak but couldn't--and drifted out raining tears all over the place.
+
+Aunt Polly's happiness was complete, and Mrs. Thatcher's nearly so. It
+would be complete, however, as soon as the messenger dispatched with
+the great news to the cave should get the word to her husband. Tom lay
+upon a sofa with an eager auditory about him and told the history of
+the wonderful adventure, putting in many striking additions to adorn it
+withal; and closed with a description of how he left Becky and went on
+an exploring expedition; how he followed two avenues as far as his
+kite-line would reach; how he followed a third to the fullest stretch of
+the kite-line, and was about to turn back when he glimpsed a far-off
+speck that looked like daylight; dropped the line and groped toward it,
+pushed his head and shoulders through a small hole, and saw the broad
+Mississippi rolling by! And if it had only happened to be night he would
+not have seen that speck of daylight and would not have explored that
+passage any more! He told how he went back for Becky and broke the good
+news and she told him not to fret her with such stuff, for she was
+tired, and knew she was going to die, and wanted to. He described how he
+labored with her and convinced her; and how she almost died for joy when
+she had groped to where she actually saw the blue speck of daylight; how
+he pushed his way out at the hole and then helped her out; how they sat
+there and cried for gladness; how some men came along in a skiff and Tom
+hailed them and told them their situation and their famished condition;
+how the men didn't believe the wild tale at first, "because," said they,
+"you are five miles down the river below the valley the cave is in"
+--then took them aboard, rowed to a house, gave them supper, made them
+rest till two or three hours after dark and then brought them home.
+
+Before day-dawn, Judge Thatcher and the handful of searchers with him
+were tracked out, in the cave, by the twine clews they had strung
+behind them, and informed of the great news.
+
+Three days and nights of toil and hunger in the cave were not to be
+shaken off at once, as Tom and Becky soon discovered. They were
+bedridden all of Wednesday and Thursday, and seemed to grow more and
+more tired and worn, all the time. Tom got about, a little, on
+Thursday, was down-town Friday, and nearly as whole as ever Saturday;
+but Becky did not leave her room until Sunday, and then she looked as
+if she had passed through a wasting illness.
+
+Tom learned of Huck's sickness and went to see him on Friday, but
+could not be admitted to the bedroom; neither could he on Saturday or
+Sunday. He was admitted daily after that, but was warned to keep still
+about his adventure and introduce no exciting topic. The Widow Douglas
+stayed by to see that he obeyed. At home Tom learned of the Cardiff
+Hill event; also that the "ragged man's" body had eventually been found
+in the river near the ferry-landing; he had been drowned while trying
+to escape, perhaps.
+
+About a fortnight after Tom's rescue from the cave, he started off to
+visit Huck, who had grown plenty strong enough, now, to hear exciting
+talk, and Tom had some that would interest him, he thought. Judge
+Thatcher's house was on Tom's way, and he stopped to see Becky. The
+Judge and some friends set Tom to talking, and some one asked him
+ironically if he wouldn't like to go to the cave again. Tom said he
+thought he wouldn't mind it. The Judge said:
+
+"Well, there are others just like you, Tom, I've not the least doubt.
+But we have taken care of that. Nobody will get lost in that cave any
+more."
+
+"Why?"
+
+"Because I had its big door sheathed with boiler iron two weeks ago,
+and triple-locked--and I've got the keys."
+
+Tom turned as white as a sheet.
+
+"What's the matter, boy! Here, run, somebody! Fetch a glass of water!"
+
+The water was brought and thrown into Tom's face.
+
+"Ah, now you're all right. What was the matter with you, Tom?"
+
+"Oh, Judge, Injun Joe's in the cave!"
+
+
+
+CHAPTER XXXIII
+
+WITHIN a few minutes the news had spread, and a dozen skiff-loads of
+men were on their way to McDougal's cave, and the ferryboat, well
+filled with passengers, soon followed. Tom Sawyer was in the skiff that
+bore Judge Thatcher.
+
+When the cave door was unlocked, a sorrowful sight presented itself in
+the dim twilight of the place. Injun Joe lay stretched upon the ground,
+dead, with his face close to the crack of the door, as if his longing
+eyes had been fixed, to the latest moment, upon the light and the cheer
+of the free world outside. Tom was touched, for he knew by his own
+experience how this wretch had suffered. His pity was moved, but
+nevertheless he felt an abounding sense of relief and security, now,
+which revealed to him in a degree which he had not fully appreciated
+before how vast a weight of dread had been lying upon him since the day
+he lifted his voice against this bloody-minded outcast.
+
+Injun Joe's bowie-knife lay close by, its blade broken in two. The
+great foundation-beam of the door had been chipped and hacked through,
+with tedious labor; useless labor, too, it was, for the native rock
+formed a sill outside it, and upon that stubborn material the knife had
+wrought no effect; the only damage done was to the knife itself. But if
+there had been no stony obstruction there the labor would have been
+useless still, for if the beam had been wholly cut away Injun Joe could
+not have squeezed his body under the door, and he knew it. So he had
+only hacked that place in order to be doing something--in order to pass
+the weary time--in order to employ his tortured faculties. Ordinarily
+one could find half a dozen bits of candle stuck around in the crevices
+of this vestibule, left there by tourists; but there were none now. The
+prisoner had searched them out and eaten them. He had also contrived to
+catch a few bats, and these, also, he had eaten, leaving only their
+claws. The poor unfortunate had starved to death. In one place, near at
+hand, a stalagmite had been slowly growing up from the ground for ages,
+builded by the water-drip from a stalactite overhead. The captive had
+broken off the stalagmite, and upon the stump had placed a stone,
+wherein he had scooped a shallow hollow to catch the precious drop
+that fell once in every three minutes with the dreary regularity of a
+clock-tick--a dessertspoonful once in four and twenty hours. That drop
+was falling when the Pyramids were new; when Troy fell; when the
+foundations of Rome were laid; when Christ was crucified; when the
+Conqueror created the British empire; when Columbus sailed; when the
+massacre at Lexington was "news." It is falling now; it will still be
+falling when all these things shall have sunk down the afternoon of
+history, and the twilight of tradition, and been swallowed up in the
+thick night of oblivion. Has everything a purpose and a mission? Did
+this drop fall patiently during five thousand years to be ready for
+this flitting human insect's need? and has it another important object
+to accomplish ten thousand years to come? No matter. It is many and
+many a year since the hapless half-breed scooped out the stone to catch
+the priceless drops, but to this day the tourist stares longest at that
+pathetic stone and that slow-dropping water when he comes to see the
+wonders of McDougal's cave. Injun Joe's cup stands first in the list of
+the cavern's marvels; even "Aladdin's Palace" cannot rival it.
+
+Injun Joe was buried near the mouth of the cave; and people flocked
+there in boats and wagons from the towns and from all the farms and
+hamlets for seven miles around; they brought their children, and all
+sorts of provisions, and confessed that they had had almost as
+satisfactory a time at the funeral as they could have had at the
+hanging.
+
+This funeral stopped the further growth of one thing--the petition to
+the governor for Injun Joe's pardon. The petition had been largely
+signed; many tearful and eloquent meetings had been held, and a
+committee of sappy women been appointed to go in deep mourning and wail
+around the governor, and implore him to be a merciful ass and trample
+his duty under foot. Injun Joe was believed to have killed five
+citizens of the village, but what of that? If he had been Satan himself
+there would have been plenty of weaklings ready to scribble their names
+to a pardon-petition, and drip a tear on it from their permanently
+impaired and leaky water-works.
+
+The morning after the funeral Tom took Huck to a private place to have
+an important talk. Huck had learned all about Tom's adventure from the
+Welshman and the Widow Douglas, by this time, but Tom said he reckoned
+there was one thing they had not told him; that thing was what he
+wanted to talk about now. Huck's face saddened. He said:
+
+"I know what it is. You got into No. 2 and never found anything but
+whiskey. Nobody told me it was you; but I just knowed it must 'a' ben
+you, soon as I heard 'bout that whiskey business; and I knowed you
+hadn't got the money becuz you'd 'a' got at me some way or other and
+told me even if you was mum to everybody else. Tom, something's always
+told me we'd never get holt of that swag."
+
+"Why, Huck, I never told on that tavern-keeper. YOU know his tavern
+was all right the Saturday I went to the picnic. Don't you remember you
+was to watch there that night?"
+
+"Oh yes! Why, it seems 'bout a year ago. It was that very night that I
+follered Injun Joe to the widder's."
+
+"YOU followed him?"
+
+"Yes--but you keep mum. I reckon Injun Joe's left friends behind him,
+and I don't want 'em souring on me and doing me mean tricks. If it
+hadn't ben for me he'd be down in Texas now, all right."
+
+Then Huck told his entire adventure in confidence to Tom, who had only
+heard of the Welshman's part of it before.
+
+"Well," said Huck, presently, coming back to the main question,
+"whoever nipped the whiskey in No. 2, nipped the money, too, I reckon
+--anyways it's a goner for us, Tom."
+
+"Huck, that money wasn't ever in No. 2!"
+
+"What!" Huck searched his comrade's face keenly. "Tom, have you got on
+the track of that money again?"
+
+"Huck, it's in the cave!"
+
+Huck's eyes blazed.
+
+"Say it again, Tom."
+
+"The money's in the cave!"
+
+"Tom--honest injun, now--is it fun, or earnest?"
+
+"Earnest, Huck--just as earnest as ever I was in my life. Will you go
+in there with me and help get it out?"
+
+"I bet I will! I will if it's where we can blaze our way to it and not
+get lost."
+
+"Huck, we can do that without the least little bit of trouble in the
+world."
+
+"Good as wheat! What makes you think the money's--"
+
+"Huck, you just wait till we get in there. If we don't find it I'll
+agree to give you my drum and every thing I've got in the world. I
+will, by jings."
+
+"All right--it's a whiz. When do you say?"
+
+"Right now, if you say it. Are you strong enough?"
+
+"Is it far in the cave? I ben on my pins a little, three or four days,
+now, but I can't walk more'n a mile, Tom--least I don't think I could."
+
+"It's about five mile into there the way anybody but me would go,
+Huck, but there's a mighty short cut that they don't anybody but me
+know about. Huck, I'll take you right to it in a skiff. I'll float the
+skiff down there, and I'll pull it back again all by myself. You
+needn't ever turn your hand over."
+
+"Less start right off, Tom."
+
+"All right. We want some bread and meat, and our pipes, and a little
+bag or two, and two or three kite-strings, and some of these
+new-fangled things they call lucifer matches. I tell you, many's
+the time I wished I had some when I was in there before."
+
+A trifle after noon the boys borrowed a small skiff from a citizen who
+was absent, and got under way at once. When they were several miles
+below "Cave Hollow," Tom said:
+
+"Now you see this bluff here looks all alike all the way down from the
+cave hollow--no houses, no wood-yards, bushes all alike. But do you see
+that white place up yonder where there's been a landslide? Well, that's
+one of my marks. We'll get ashore, now."
+
+They landed.
+
+"Now, Huck, where we're a-standing you could touch that hole I got out
+of with a fishing-pole. See if you can find it."
+
+Huck searched all the place about, and found nothing. Tom proudly
+marched into a thick clump of sumach bushes and said:
+
+"Here you are! Look at it, Huck; it's the snuggest hole in this
+country. You just keep mum about it. All along I've been wanting to be
+a robber, but I knew I'd got to have a thing like this, and where to
+run across it was the bother. We've got it now, and we'll keep it
+quiet, only we'll let Joe Harper and Ben Rogers in--because of course
+there's got to be a Gang, or else there wouldn't be any style about it.
+Tom Sawyer's Gang--it sounds splendid, don't it, Huck?"
+
+"Well, it just does, Tom. And who'll we rob?"
+
+"Oh, most anybody. Waylay people--that's mostly the way."
+
+"And kill them?"
+
+"No, not always. Hive them in the cave till they raise a ransom."
+
+"What's a ransom?"
+
+"Money. You make them raise all they can, off'n their friends; and
+after you've kept them a year, if it ain't raised then you kill them.
+That's the general way. Only you don't kill the women. You shut up the
+women, but you don't kill them. They're always beautiful and rich, and
+awfully scared. You take their watches and things, but you always take
+your hat off and talk polite. They ain't anybody as polite as robbers
+--you'll see that in any book. Well, the women get to loving you, and
+after they've been in the cave a week or two weeks they stop crying and
+after that you couldn't get them to leave. If you drove them out they'd
+turn right around and come back. It's so in all the books."
+
+"Why, it's real bully, Tom. I believe it's better'n to be a pirate."
+
+"Yes, it's better in some ways, because it's close to home and
+circuses and all that."
+
+By this time everything was ready and the boys entered the hole, Tom
+in the lead. They toiled their way to the farther end of the tunnel,
+then made their spliced kite-strings fast and moved on. A few steps
+brought them to the spring, and Tom felt a shudder quiver all through
+him. He showed Huck the fragment of candle-wick perched on a lump of
+clay against the wall, and described how he and Becky had watched the
+flame struggle and expire.
+
+The boys began to quiet down to whispers, now, for the stillness and
+gloom of the place oppressed their spirits. They went on, and presently
+entered and followed Tom's other corridor until they reached the
+"jumping-off place." The candles revealed the fact that it was not
+really a precipice, but only a steep clay hill twenty or thirty feet
+high. Tom whispered:
+
+"Now I'll show you something, Huck."
+
+He held his candle aloft and said:
+
+"Look as far around the corner as you can. Do you see that? There--on
+the big rock over yonder--done with candle-smoke."
+
+"Tom, it's a CROSS!"
+
+"NOW where's your Number Two? 'UNDER THE CROSS,' hey? Right yonder's
+where I saw Injun Joe poke up his candle, Huck!"
+
+Huck stared at the mystic sign awhile, and then said with a shaky voice:
+
+"Tom, less git out of here!"
+
+"What! and leave the treasure?"
+
+"Yes--leave it. Injun Joe's ghost is round about there, certain."
+
+"No it ain't, Huck, no it ain't. It would ha'nt the place where he
+died--away out at the mouth of the cave--five mile from here."
+
+"No, Tom, it wouldn't. It would hang round the money. I know the ways
+of ghosts, and so do you."
+
+Tom began to fear that Huck was right. Misgivings gathered in his
+mind. But presently an idea occurred to him--
+
+"Lookyhere, Huck, what fools we're making of ourselves! Injun Joe's
+ghost ain't a going to come around where there's a cross!"
+
+The point was well taken. It had its effect.
+
+"Tom, I didn't think of that. But that's so. It's luck for us, that
+cross is. I reckon we'll climb down there and have a hunt for that box."
+
+Tom went first, cutting rude steps in the clay hill as he descended.
+Huck followed. Four avenues opened out of the small cavern which the
+great rock stood in. The boys examined three of them with no result.
+They found a small recess in the one nearest the base of the rock, with
+a pallet of blankets spread down in it; also an old suspender, some
+bacon rind, and the well-gnawed bones of two or three fowls. But there
+was no money-box. The lads searched and researched this place, but in
+vain. Tom said:
+
+"He said UNDER the cross. Well, this comes nearest to being under the
+cross. It can't be under the rock itself, because that sets solid on
+the ground."
+
+They searched everywhere once more, and then sat down discouraged.
+Huck could suggest nothing. By-and-by Tom said:
+
+"Lookyhere, Huck, there's footprints and some candle-grease on the
+clay about one side of this rock, but not on the other sides. Now,
+what's that for? I bet you the money IS under the rock. I'm going to
+dig in the clay."
+
+"That ain't no bad notion, Tom!" said Huck with animation.
+
+Tom's "real Barlow" was out at once, and he had not dug four inches
+before he struck wood.
+
+"Hey, Huck!--you hear that?"
+
+Huck began to dig and scratch now. Some boards were soon uncovered and
+removed. They had concealed a natural chasm which led under the rock.
+Tom got into this and held his candle as far under the rock as he
+could, but said he could not see to the end of the rift. He proposed to
+explore. He stooped and passed under; the narrow way descended
+gradually. He followed its winding course, first to the right, then to
+the left, Huck at his heels. Tom turned a short curve, by-and-by, and
+exclaimed:
+
+"My goodness, Huck, lookyhere!"
+
+It was the treasure-box, sure enough, occupying a snug little cavern,
+along with an empty powder-keg, a couple of guns in leather cases, two
+or three pairs of old moccasins, a leather belt, and some other rubbish
+well soaked with the water-drip.
+
+"Got it at last!" said Huck, ploughing among the tarnished coins with
+his hand. "My, but we're rich, Tom!"
+
+"Huck, I always reckoned we'd get it. It's just too good to believe,
+but we HAVE got it, sure! Say--let's not fool around here. Let's snake
+it out. Lemme see if I can lift the box."
+
+It weighed about fifty pounds. Tom could lift it, after an awkward
+fashion, but could not carry it conveniently.
+
+"I thought so," he said; "THEY carried it like it was heavy, that day
+at the ha'nted house. I noticed that. I reckon I was right to think of
+fetching the little bags along."
+
+The money was soon in the bags and the boys took it up to the cross
+rock.
+
+"Now less fetch the guns and things," said Huck.
+
+"No, Huck--leave them there. They're just the tricks to have when we
+go to robbing. We'll keep them there all the time, and we'll hold our
+orgies there, too. It's an awful snug place for orgies."
+
+"What orgies?"
+
+"I dono. But robbers always have orgies, and of course we've got to
+have them, too. Come along, Huck, we've been in here a long time. It's
+getting late, I reckon. I'm hungry, too. We'll eat and smoke when we
+get to the skiff."
+
+They presently emerged into the clump of sumach bushes, looked warily
+out, found the coast clear, and were soon lunching and smoking in the
+skiff. As the sun dipped toward the horizon they pushed out and got
+under way. Tom skimmed up the shore through the long twilight, chatting
+cheerily with Huck, and landed shortly after dark.
+
+"Now, Huck," said Tom, "we'll hide the money in the loft of the
+widow's woodshed, and I'll come up in the morning and we'll count it
+and divide, and then we'll hunt up a place out in the woods for it
+where it will be safe. Just you lay quiet here and watch the stuff till
+I run and hook Benny Taylor's little wagon; I won't be gone a minute."
+
+He disappeared, and presently returned with the wagon, put the two
+small sacks into it, threw some old rags on top of them, and started
+off, dragging his cargo behind him. When the boys reached the
+Welshman's house, they stopped to rest. Just as they were about to move
+on, the Welshman stepped out and said:
+
+"Hallo, who's that?"
+
+"Huck and Tom Sawyer."
+
+"Good! Come along with me, boys, you are keeping everybody waiting.
+Here--hurry up, trot ahead--I'll haul the wagon for you. Why, it's not
+as light as it might be. Got bricks in it?--or old metal?"
+
+"Old metal," said Tom.
+
+"I judged so; the boys in this town will take more trouble and fool
+away more time hunting up six bits' worth of old iron to sell to the
+foundry than they would to make twice the money at regular work. But
+that's human nature--hurry along, hurry along!"
+
+The boys wanted to know what the hurry was about.
+
+"Never mind; you'll see, when we get to the Widow Douglas'."
+
+Huck said with some apprehension--for he was long used to being
+falsely accused:
+
+"Mr. Jones, we haven't been doing nothing."
+
+The Welshman laughed.
+
+"Well, I don't know, Huck, my boy. I don't know about that. Ain't you
+and the widow good friends?"
+
+"Yes. Well, she's ben good friends to me, anyway."
+
+"All right, then. What do you want to be afraid for?"
+
+This question was not entirely answered in Huck's slow mind before he
+found himself pushed, along with Tom, into Mrs. Douglas' drawing-room.
+Mr. Jones left the wagon near the door and followed.
+
+The place was grandly lighted, and everybody that was of any
+consequence in the village was there. The Thatchers were there, the
+Harpers, the Rogerses, Aunt Polly, Sid, Mary, the minister, the editor,
+and a great many more, and all dressed in their best. The widow
+received the boys as heartily as any one could well receive two such
+looking beings. They were covered with clay and candle-grease. Aunt
+Polly blushed crimson with humiliation, and frowned and shook her head
+at Tom. Nobody suffered half as much as the two boys did, however. Mr.
+Jones said:
+
+"Tom wasn't at home, yet, so I gave him up; but I stumbled on him and
+Huck right at my door, and so I just brought them along in a hurry."
+
+"And you did just right," said the widow. "Come with me, boys."
+
+She took them to a bedchamber and said:
+
+"Now wash and dress yourselves. Here are two new suits of clothes
+--shirts, socks, everything complete. They're Huck's--no, no thanks,
+Huck--Mr. Jones bought one and I the other. But they'll fit both of you.
+Get into them. We'll wait--come down when you are slicked up enough."
+
+Then she left.
+
+
+
+CHAPTER XXXIV
+
+HUCK said: "Tom, we can slope, if we can find a rope. The window ain't
+high from the ground."
+
+"Shucks! what do you want to slope for?"
+
+"Well, I ain't used to that kind of a crowd. I can't stand it. I ain't
+going down there, Tom."
+
+"Oh, bother! It ain't anything. I don't mind it a bit. I'll take care
+of you."
+
+Sid appeared.
+
+"Tom," said he, "auntie has been waiting for you all the afternoon.
+Mary got your Sunday clothes ready, and everybody's been fretting about
+you. Say--ain't this grease and clay, on your clothes?"
+
+"Now, Mr. Siddy, you jist 'tend to your own business. What's all this
+blow-out about, anyway?"
+
+"It's one of the widow's parties that she's always having. This time
+it's for the Welshman and his sons, on account of that scrape they
+helped her out of the other night. And say--I can tell you something,
+if you want to know."
+
+"Well, what?"
+
+"Why, old Mr. Jones is going to try to spring something on the people
+here to-night, but I overheard him tell auntie to-day about it, as a
+secret, but I reckon it's not much of a secret now. Everybody knows
+--the widow, too, for all she tries to let on she don't. Mr. Jones was
+bound Huck should be here--couldn't get along with his grand secret
+without Huck, you know!"
+
+"Secret about what, Sid?"
+
+"About Huck tracking the robbers to the widow's. I reckon Mr. Jones
+was going to make a grand time over his surprise, but I bet you it will
+drop pretty flat."
+
+Sid chuckled in a very contented and satisfied way.
+
+"Sid, was it you that told?"
+
+"Oh, never mind who it was. SOMEBODY told--that's enough."
+
+"Sid, there's only one person in this town mean enough to do that, and
+that's you. If you had been in Huck's place you'd 'a' sneaked down the
+hill and never told anybody on the robbers. You can't do any but mean
+things, and you can't bear to see anybody praised for doing good ones.
+There--no thanks, as the widow says"--and Tom cuffed Sid's ears and
+helped him to the door with several kicks. "Now go and tell auntie if
+you dare--and to-morrow you'll catch it!"
+
+Some minutes later the widow's guests were at the supper-table, and a
+dozen children were propped up at little side-tables in the same room,
+after the fashion of that country and that day. At the proper time Mr.
+Jones made his little speech, in which he thanked the widow for the
+honor she was doing himself and his sons, but said that there was
+another person whose modesty--
+
+And so forth and so on. He sprung his secret about Huck's share in the
+adventure in the finest dramatic manner he was master of, but the
+surprise it occasioned was largely counterfeit and not as clamorous and
+effusive as it might have been under happier circumstances. However,
+the widow made a pretty fair show of astonishment, and heaped so many
+compliments and so much gratitude upon Huck that he almost forgot the
+nearly intolerable discomfort of his new clothes in the entirely
+intolerable discomfort of being set up as a target for everybody's gaze
+and everybody's laudations.
+
+The widow said she meant to give Huck a home under her roof and have
+him educated; and that when she could spare the money she would start
+him in business in a modest way. Tom's chance was come. He said:
+
+"Huck don't need it. Huck's rich."
+
+Nothing but a heavy strain upon the good manners of the company kept
+back the due and proper complimentary laugh at this pleasant joke. But
+the silence was a little awkward. Tom broke it:
+
+"Huck's got money. Maybe you don't believe it, but he's got lots of
+it. Oh, you needn't smile--I reckon I can show you. You just wait a
+minute."
+
+Tom ran out of doors. The company looked at each other with a
+perplexed interest--and inquiringly at Huck, who was tongue-tied.
+
+"Sid, what ails Tom?" said Aunt Polly. "He--well, there ain't ever any
+making of that boy out. I never--"
+
+Tom entered, struggling with the weight of his sacks, and Aunt Polly
+did not finish her sentence. Tom poured the mass of yellow coin upon
+the table and said:
+
+"There--what did I tell you? Half of it's Huck's and half of it's mine!"
+
+The spectacle took the general breath away. All gazed, nobody spoke
+for a moment. Then there was a unanimous call for an explanation. Tom
+said he could furnish it, and he did. The tale was long, but brimful of
+interest. There was scarcely an interruption from any one to break the
+charm of its flow. When he had finished, Mr. Jones said:
+
+"I thought I had fixed up a little surprise for this occasion, but it
+don't amount to anything now. This one makes it sing mighty small, I'm
+willing to allow."
+
+The money was counted. The sum amounted to a little over twelve
+thousand dollars. It was more than any one present had ever seen at one
+time before, though several persons were there who were worth
+considerably more than that in property.
+
+
+
+CHAPTER XXXV
+
+THE reader may rest satisfied that Tom's and Huck's windfall made a
+mighty stir in the poor little village of St. Petersburg. So vast a
+sum, all in actual cash, seemed next to incredible. It was talked
+about, gloated over, glorified, until the reason of many of the
+citizens tottered under the strain of the unhealthy excitement. Every
+"haunted" house in St. Petersburg and the neighboring villages was
+dissected, plank by plank, and its foundations dug up and ransacked for
+hidden treasure--and not by boys, but men--pretty grave, unromantic
+men, too, some of them. Wherever Tom and Huck appeared they were
+courted, admired, stared at. The boys were not able to remember that
+their remarks had possessed weight before; but now their sayings were
+treasured and repeated; everything they did seemed somehow to be
+regarded as remarkable; they had evidently lost the power of doing and
+saying commonplace things; moreover, their past history was raked up
+and discovered to bear marks of conspicuous originality. The village
+paper published biographical sketches of the boys.
+
+The Widow Douglas put Huck's money out at six per cent., and Judge
+Thatcher did the same with Tom's at Aunt Polly's request. Each lad had
+an income, now, that was simply prodigious--a dollar for every week-day
+in the year and half of the Sundays. It was just what the minister got
+--no, it was what he was promised--he generally couldn't collect it. A
+dollar and a quarter a week would board, lodge, and school a boy in
+those old simple days--and clothe him and wash him, too, for that
+matter.
+
+Judge Thatcher had conceived a great opinion of Tom. He said that no
+commonplace boy would ever have got his daughter out of the cave. When
+Becky told her father, in strict confidence, how Tom had taken her
+whipping at school, the Judge was visibly moved; and when she pleaded
+grace for the mighty lie which Tom had told in order to shift that
+whipping from her shoulders to his own, the Judge said with a fine
+outburst that it was a noble, a generous, a magnanimous lie--a lie that
+was worthy to hold up its head and march down through history breast to
+breast with George Washington's lauded Truth about the hatchet! Becky
+thought her father had never looked so tall and so superb as when he
+walked the floor and stamped his foot and said that. She went straight
+off and told Tom about it.
+
+Judge Thatcher hoped to see Tom a great lawyer or a great soldier some
+day. He said he meant to look to it that Tom should be admitted to the
+National Military Academy and afterward trained in the best law school
+in the country, in order that he might be ready for either career or
+both.
+
+Huck Finn's wealth and the fact that he was now under the Widow
+Douglas' protection introduced him into society--no, dragged him into
+it, hurled him into it--and his sufferings were almost more than he
+could bear. The widow's servants kept him clean and neat, combed and
+brushed, and they bedded him nightly in unsympathetic sheets that had
+not one little spot or stain which he could press to his heart and know
+for a friend. He had to eat with a knife and fork; he had to use
+napkin, cup, and plate; he had to learn his book, he had to go to
+church; he had to talk so properly that speech was become insipid in
+his mouth; whithersoever he turned, the bars and shackles of
+civilization shut him in and bound him hand and foot.
+
+He bravely bore his miseries three weeks, and then one day turned up
+missing. For forty-eight hours the widow hunted for him everywhere in
+great distress. The public were profoundly concerned; they searched
+high and low, they dragged the river for his body. Early the third
+morning Tom Sawyer wisely went poking among some old empty hogsheads
+down behind the abandoned slaughter-house, and in one of them he found
+the refugee. Huck had slept there; he had just breakfasted upon some
+stolen odds and ends of food, and was lying off, now, in comfort, with
+his pipe. He was unkempt, uncombed, and clad in the same old ruin of
+rags that had made him picturesque in the days when he was free and
+happy. Tom routed him out, told him the trouble he had been causing,
+and urged him to go home. Huck's face lost its tranquil content, and
+took a melancholy cast. He said:
+
+"Don't talk about it, Tom. I've tried it, and it don't work; it don't
+work, Tom. It ain't for me; I ain't used to it. The widder's good to
+me, and friendly; but I can't stand them ways. She makes me get up just
+at the same time every morning; she makes me wash, they comb me all to
+thunder; she won't let me sleep in the woodshed; I got to wear them
+blamed clothes that just smothers me, Tom; they don't seem to any air
+git through 'em, somehow; and they're so rotten nice that I can't set
+down, nor lay down, nor roll around anywher's; I hain't slid on a
+cellar-door for--well, it 'pears to be years; I got to go to church and
+sweat and sweat--I hate them ornery sermons! I can't ketch a fly in
+there, I can't chaw. I got to wear shoes all Sunday. The widder eats by
+a bell; she goes to bed by a bell; she gits up by a bell--everything's
+so awful reg'lar a body can't stand it."
+
+"Well, everybody does that way, Huck."
+
+"Tom, it don't make no difference. I ain't everybody, and I can't
+STAND it. It's awful to be tied up so. And grub comes too easy--I don't
+take no interest in vittles, that way. I got to ask to go a-fishing; I
+got to ask to go in a-swimming--dern'd if I hain't got to ask to do
+everything. Well, I'd got to talk so nice it wasn't no comfort--I'd got
+to go up in the attic and rip out awhile, every day, to git a taste in
+my mouth, or I'd a died, Tom. The widder wouldn't let me smoke; she
+wouldn't let me yell, she wouldn't let me gape, nor stretch, nor
+scratch, before folks--" [Then with a spasm of special irritation and
+injury]--"And dad fetch it, she prayed all the time! I never see such a
+woman! I HAD to shove, Tom--I just had to. And besides, that school's
+going to open, and I'd a had to go to it--well, I wouldn't stand THAT,
+Tom. Looky here, Tom, being rich ain't what it's cracked up to be. It's
+just worry and worry, and sweat and sweat, and a-wishing you was dead
+all the time. Now these clothes suits me, and this bar'l suits me, and
+I ain't ever going to shake 'em any more. Tom, I wouldn't ever got into
+all this trouble if it hadn't 'a' ben for that money; now you just take
+my sheer of it along with your'n, and gimme a ten-center sometimes--not
+many times, becuz I don't give a dern for a thing 'thout it's tollable
+hard to git--and you go and beg off for me with the widder."
+
+"Oh, Huck, you know I can't do that. 'Tain't fair; and besides if
+you'll try this thing just a while longer you'll come to like it."
+
+"Like it! Yes--the way I'd like a hot stove if I was to set on it long
+enough. No, Tom, I won't be rich, and I won't live in them cussed
+smothery houses. I like the woods, and the river, and hogsheads, and
+I'll stick to 'em, too. Blame it all! just as we'd got guns, and a
+cave, and all just fixed to rob, here this dern foolishness has got to
+come up and spile it all!"
+
+Tom saw his opportunity--
+
+"Lookyhere, Huck, being rich ain't going to keep me back from turning
+robber."
+
+"No! Oh, good-licks; are you in real dead-wood earnest, Tom?"
+
+"Just as dead earnest as I'm sitting here. But Huck, we can't let you
+into the gang if you ain't respectable, you know."
+
+Huck's joy was quenched.
+
+"Can't let me in, Tom? Didn't you let me go for a pirate?"
+
+"Yes, but that's different. A robber is more high-toned than what a
+pirate is--as a general thing. In most countries they're awful high up
+in the nobility--dukes and such."
+
+"Now, Tom, hain't you always ben friendly to me? You wouldn't shet me
+out, would you, Tom? You wouldn't do that, now, WOULD you, Tom?"
+
+"Huck, I wouldn't want to, and I DON'T want to--but what would people
+say? Why, they'd say, 'Mph! Tom Sawyer's Gang! pretty low characters in
+it!' They'd mean you, Huck. You wouldn't like that, and I wouldn't."
+
+Huck was silent for some time, engaged in a mental struggle. Finally
+he said:
+
+"Well, I'll go back to the widder for a month and tackle it and see if
+I can come to stand it, if you'll let me b'long to the gang, Tom."
+
+"All right, Huck, it's a whiz! Come along, old chap, and I'll ask the
+widow to let up on you a little, Huck."
+
+"Will you, Tom--now will you? That's good. If she'll let up on some of
+the roughest things, I'll smoke private and cuss private, and crowd
+through or bust. When you going to start the gang and turn robbers?"
+
+"Oh, right off. We'll get the boys together and have the initiation
+to-night, maybe."
+
+"Have the which?"
+
+"Have the initiation."
+
+"What's that?"
+
+"It's to swear to stand by one another, and never tell the gang's
+secrets, even if you're chopped all to flinders, and kill anybody and
+all his family that hurts one of the gang."
+
+"That's gay--that's mighty gay, Tom, I tell you."
+
+"Well, I bet it is. And all that swearing's got to be done at
+midnight, in the lonesomest, awfulest place you can find--a ha'nted
+house is the best, but they're all ripped up now."
+
+"Well, midnight's good, anyway, Tom."
+
+"Yes, so it is. And you've got to swear on a coffin, and sign it with
+blood."
+
+"Now, that's something LIKE! Why, it's a million times bullier than
+pirating. I'll stick to the widder till I rot, Tom; and if I git to be
+a reg'lar ripper of a robber, and everybody talking 'bout it, I reckon
+she'll be proud she snaked me in out of the wet."
+
+
+
+CONCLUSION
+
+SO endeth this chronicle. It being strictly a history of a BOY, it
+must stop here; the story could not go much further without becoming
+the history of a MAN. When one writes a novel about grown people, he
+knows exactly where to stop--that is, with a marriage; but when he
+writes of juveniles, he must stop where he best can.
+
+Most of the characters that perform in this book still live, and are
+prosperous and happy. Some day it may seem worth while to take up the
+story of the younger ones again and see what sort of men and women they
+turned out to be; therefore it will be wisest not to reveal any of that
+part of their lives at present.
diff --git a/src/net/textproto/header.go b/src/net/textproto/header.go
index 7fb32f8..2e2752a 100644
--- a/src/net/textproto/header.go
+++ b/src/net/textproto/header.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -16,7 +16,7 @@ func (h MIMEHeader) Add(key, value string) {
 }
 
 // Set sets the header entries associated with key to
-// the single element value.  It replaces any existing
+// the single element value. It replaces any existing
 // values associated with key.
 func (h MIMEHeader) Set(key, value string) {
 	h[CanonicalMIMEHeaderKey(key)] = []string{value}
@@ -24,7 +24,7 @@ func (h MIMEHeader) Set(key, value string) {
 
 // Get gets the first value associated with the given key.
 // If there are no values associated with the key, Get returns "".
-// Get is a convenience method.  For more complex queries,
+// Get is a convenience method. For more complex queries,
 // access the map directly.
 func (h MIMEHeader) Get(key string) string {
 	if h == nil {
diff --git a/src/net/textproto/pipeline.go b/src/net/textproto/pipeline.go
index ca50edd..2e28321 100644
--- a/src/net/textproto/pipeline.go
+++ b/src/net/textproto/pipeline.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -66,8 +66,8 @@ func (p *Pipeline) EndResponse(id uint) {
 }
 
 // A sequencer schedules a sequence of numbered events that must
-// happen in order, one after the other.  The event numbering must start
-// at 0 and increment without skipping.  The event number wraps around
+// happen in order, one after the other. The event numbering must start
+// at 0 and increment without skipping. The event number wraps around
 // safely as long as there are not 2^32 simultaneous events pending.
 type sequencer struct {
 	mu   sync.Mutex
diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
index 91bbb57..e07d1d6 100644
--- a/src/net/textproto/reader.go
+++ b/src/net/textproto/reader.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -71,7 +71,7 @@ func (r *Reader) readLineSlice() ([]byte, error) {
 // ReadContinuedLine reads a possibly continued line from r,
 // eliding the final trailing ASCII white space.
 // Lines after the first are considered continuations if they
-// begin with a space or tab character.  In the returned data,
+// begin with a space or tab character. In the returned data,
 // continuation lines are separated from the previous line
 // only by a single space: the newline and leading white space
 // are removed.
@@ -204,7 +204,7 @@ func parseCodeLine(line string, expectCode int) (code int, continued bool, messa
 // ReadCodeLine reads a response code line of the form
 //	code message
 // where code is a three-digit status code and the message
-// extends to the rest of the line.  An example of such a line is:
+// extends to the rest of the line. An example of such a line is:
 //	220 plan9.bell-labs.com ESMTP
 //
 // If the prefix of the status does not match the digits in expectCode,
@@ -366,7 +366,7 @@ func (d *dotReader) Read(b []byte) (n int, err error) {
 				d.state = stateBeginLine
 				break
 			}
-			// Not part of \r\n.  Emit saved \r
+			// Not part of \r\n. Emit saved \r
 			br.UnreadByte()
 			c = '\r'
 			d.state = stateData
@@ -552,9 +552,9 @@ func (r *Reader) upcomingHeaderNewlines() (n int) {
 }
 
 // CanonicalMIMEHeaderKey returns the canonical format of the
-// MIME header key s.  The canonicalization converts the first
+// MIME header key s. The canonicalization converts the first
 // letter and any letter following a hyphen to upper case;
-// the rest are converted to lowercase.  For example, the
+// the rest are converted to lowercase. For example, the
 // canonical key for "accept-encoding" is "Accept-Encoding".
 // MIME header keys are assumed to be ASCII only.
 // If s contains a space or invalid header field bytes, it is
@@ -581,18 +581,14 @@ func CanonicalMIMEHeaderKey(s string) string {
 const toLower = 'a' - 'A'
 
 // validHeaderFieldByte reports whether b is a valid byte in a header
-// field key. This is actually stricter than RFC 7230, which says:
+// field name. RFC 7230 says:
+//   header-field   = field-name ":" OWS field-value OWS
+//   field-name     = token
 //   tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
 //           "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
 //   token = 1*tchar
-// TODO: revisit in Go 1.6+ and possibly expand this. But note that many
-// servers have historically dropped '_' to prevent ambiguities when mapping
-// to CGI environment variables.
 func validHeaderFieldByte(b byte) bool {
-	return ('A' <= b && b <= 'Z') ||
-		('a' <= b && b <= 'z') ||
-		('0' <= b && b <= '9') ||
-		b == '-'
+	return int(b) < len(isTokenTable) && isTokenTable[b]
 }
 
 // canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
@@ -682,3 +678,85 @@ func init() {
 		commonHeader[v] = v
 	}
 }
+
+// isTokenTable is a copy of net/http/lex.go's isTokenTable.
+// See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators
+var isTokenTable = [127]bool{
+	'!':  true,
+	'#':  true,
+	'$':  true,
+	'%':  true,
+	'&':  true,
+	'\'': true,
+	'*':  true,
+	'+':  true,
+	'-':  true,
+	'.':  true,
+	'0':  true,
+	'1':  true,
+	'2':  true,
+	'3':  true,
+	'4':  true,
+	'5':  true,
+	'6':  true,
+	'7':  true,
+	'8':  true,
+	'9':  true,
+	'A':  true,
+	'B':  true,
+	'C':  true,
+	'D':  true,
+	'E':  true,
+	'F':  true,
+	'G':  true,
+	'H':  true,
+	'I':  true,
+	'J':  true,
+	'K':  true,
+	'L':  true,
+	'M':  true,
+	'N':  true,
+	'O':  true,
+	'P':  true,
+	'Q':  true,
+	'R':  true,
+	'S':  true,
+	'T':  true,
+	'U':  true,
+	'W':  true,
+	'V':  true,
+	'X':  true,
+	'Y':  true,
+	'Z':  true,
+	'^':  true,
+	'_':  true,
+	'`':  true,
+	'a':  true,
+	'b':  true,
+	'c':  true,
+	'd':  true,
+	'e':  true,
+	'f':  true,
+	'g':  true,
+	'h':  true,
+	'i':  true,
+	'j':  true,
+	'k':  true,
+	'l':  true,
+	'm':  true,
+	'n':  true,
+	'o':  true,
+	'p':  true,
+	'q':  true,
+	'r':  true,
+	's':  true,
+	't':  true,
+	'u':  true,
+	'v':  true,
+	'w':  true,
+	'x':  true,
+	'y':  true,
+	'z':  true,
+	'|':  true,
+	'~':  true,
+}
diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go
index 9c71594..6cd98ed 100644
--- a/src/net/textproto/reader_test.go
+++ b/src/net/textproto/reader_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -25,6 +25,12 @@ var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{
 	{"user-agent", "User-Agent"},
 	{"USER-AGENT", "User-Agent"},
 
+	// Other valid tchar bytes in tokens:
+	{"foo-bar_baz", "Foo-Bar_baz"},
+	{"foo-bar$baz", "Foo-Bar$baz"},
+	{"foo-bar~baz", "Foo-Bar~baz"},
+	{"foo-bar*baz", "Foo-Bar*baz"},
+
 	// Non-ASCII or anything with spaces or non-token chars is unchanged:
 	{"üser-agenT", "üser-agenT"},
 	{"a B", "a B"},
diff --git a/src/net/textproto/textproto.go b/src/net/textproto/textproto.go
index 026eb02..8fd781e 100644
--- a/src/net/textproto/textproto.go
+++ b/src/net/textproto/textproto.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -87,7 +87,7 @@ func Dial(network, addr string) (*Conn, error) {
 }
 
 // Cmd is a convenience method that sends a command after
-// waiting its turn in the pipeline.  The command text is the
+// waiting its turn in the pipeline. The command text is the
 // result of formatting format with args and appending \r\n.
 // Cmd returns the id of the command, for use with StartResponse and EndResponse.
 //
diff --git a/src/net/textproto/writer.go b/src/net/textproto/writer.go
index 03e2fd6..1bc5974 100644
--- a/src/net/textproto/writer.go
+++ b/src/net/textproto/writer.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -36,7 +36,7 @@ func (w *Writer) PrintfLine(format string, args ...interface{}) error {
 // DotWriter returns a writer that can be used to write a dot-encoding to w.
 // It takes care of inserting leading dots when necessary,
 // translating line-ending \n into \r\n, and adding the final .\r\n line
-// when the DotWriter is closed.  The caller should close the
+// when the DotWriter is closed. The caller should close the
 // DotWriter before the next call to a method on w.
 //
 // See the documentation for Reader's DotReader method for details about dot-encoding.
diff --git a/src/net/textproto/writer_test.go b/src/net/textproto/writer_test.go
index e03ab5e..ac03669 100644
--- a/src/net/textproto/writer_test.go
+++ b/src/net/textproto/writer_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go
index 98e3164..ed26f2a 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -5,7 +5,9 @@
 package net
 
 import (
+	"context"
 	"fmt"
+	"internal/testenv"
 	"io"
 	"io/ioutil"
 	"net/internal/socktest"
@@ -26,6 +28,8 @@ var dialTimeoutTests = []struct {
 	{-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
+	{-1 << 63, 0, time.Second, 100 * time.Millisecond},
+	{0, -1 << 63, time.Second, 100 * time.Millisecond},
 
 	{50 * time.Millisecond, 0, 100 * time.Millisecond, time.Second},
 	{0, 50 * time.Millisecond, 100 * time.Millisecond, time.Second},
@@ -38,19 +42,6 @@ func TestDialTimeout(t *testing.T) {
 	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":
@@ -99,6 +90,56 @@ func TestDialTimeout(t *testing.T) {
 	}
 }
 
+var dialTimeoutMaxDurationTests = []struct {
+	timeout time.Duration
+	delta   time.Duration // for deadline
+}{
+	// Large timeouts that will overflow an int64 unix nanos.
+	{1<<63 - 1, 0},
+	{0, 1<<63 - 1},
+}
+
+func TestDialTimeoutMaxDuration(t *testing.T) {
+	if runtime.GOOS == "openbsd" {
+		testenv.SkipFlaky(t, 15157)
+	}
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+
+	for i, tt := range dialTimeoutMaxDurationTests {
+		ch := make(chan error)
+		max := time.NewTimer(250 * time.Millisecond)
+		defer max.Stop()
+		go func() {
+			d := Dialer{Timeout: tt.timeout}
+			if tt.delta != 0 {
+				d.Deadline = time.Now().Add(tt.delta)
+			}
+			c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
+			if err == nil {
+				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.Error(perr)
+			}
+			if err != nil {
+				t.Errorf("#%d: %v", i, err)
+			}
+		}
+	}
+}
+
 var acceptTimeoutTests = []struct {
 	timeout time.Duration
 	xerrs   [2]error // expected errors in transition
@@ -124,10 +165,13 @@ func TestAcceptTimeout(t *testing.T) {
 	}
 	defer ln.Close()
 
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
 	for i, tt := range acceptTimeoutTests {
 		if tt.timeout < 0 {
 			go func() {
-				c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+				var d Dialer
+				c, err := d.DialContext(ctx, ln.Addr().Network(), ln.Addr().String())
 				if err != nil {
 					t.Error(err)
 					return
@@ -261,8 +305,6 @@ var readTimeoutTests = []struct {
 }
 
 func TestReadTimeout(t *testing.T) {
-	t.Parallel()
-
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
diff --git a/src/net/udp_test.go b/src/net/udp_test.go
deleted file mode 100644
index b25f96a..0000000
--- a/src/net/udp_test.go
+++ /dev/null
@@ -1,364 +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 net
-
-import (
-	"reflect"
-	"runtime"
-	"testing"
-	"time"
-)
-
-type resolveUDPAddrTest struct {
-	network       string
-	litAddrOrName string
-	addr          *UDPAddr
-	err           error
-}
-
-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},
-
-	{"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},
-	{"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
-
-	{"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},
-
-	{"", "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
-
-	{"udp", ":12345", &UDPAddr{Port: 12345}, nil},
-
-	{"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("not supported on %s", runtime.GOOS)
-	}
-
-	c, err := ListenPacket("udp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
-
-	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.Fatal(err)
-	}
-	defer c.Close()
-
-	ra, err := ResolveUDPAddr("udp", raddr)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	b := []byte("CONNECTED-MODE SOCKET")
-	_, err = c.(*UDPConn).WriteToUDP(b, 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).WriteTo(b, 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.Write(b)
-	if err != nil {
-		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.Fatal(err)
-	}
-	defer c.Close()
-
-	ra, err := ResolveUDPAddr("udp", raddr)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	b := []byte("UNCONNECTED-MODE SOCKET")
-	_, err = c.(*UDPConn).WriteToUDP(b, ra)
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = c.WriteTo(b, ra)
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = c.(*UDPConn).Write(b)
-	if err == nil {
-		t.Fatal("should fail")
-	}
-	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
-	if err == nil {
-		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)
-		}
-	}
-}
-
-var udpConnLocalNameTests = []struct {
-	net   string
-	laddr *UDPAddr
-}{
-	{"udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)}},
-	{"udp4", &UDPAddr{}},
-	{"udp4", nil},
-}
-
-func TestUDPConnLocalName(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-
-	for _, tt := range udpConnLocalNameTests {
-		c, err := ListenUDP(tt.net, tt.laddr)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer c.Close()
-		la := c.LocalAddr()
-		if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
-			t.Fatalf("got %v; expected a proper address with non-zero port number", la)
-		}
-	}
-}
-
-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.Fatal(err)
-		}
-		defer c1.Close()
-
-		var la *UDPAddr
-		if laddr != "" {
-			var err error
-			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
-				t.Fatal(err)
-			}
-		}
-		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer c2.Close()
-
-		var connAddrs = [4]struct {
-			got Addr
-			ok  bool
-		}{
-			{c1.LocalAddr(), true},
-			{c1.(*UDPConn).RemoteAddr(), false},
-			{c2.LocalAddr(), true},
-			{c2.RemoteAddr(), true},
-		}
-		for _, ca := range connAddrs {
-			if a, ok := ca.got.(*UDPAddr); ok != ca.ok || ok && a.Port == 0 {
-				t.Fatalf("got %v; expected a proper address with non-zero port number", ca.got)
-			}
-		}
-	}
-}
-
-func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv6 {
-		t.Skip("IPv6 is not supported")
-	}
-
-	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.Log(err)
-			continue
-		}
-		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.network, ls.PacketConn.LocalAddr().String())
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer c2.Close()
-		if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
-			t.Fatalf("got %v; expected a proper address with zone identifier", la)
-		}
-		if ra, ok := c2.RemoteAddr().(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
-			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
-		}
-
-		if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
-			t.Fatal(err)
-		}
-		b := make([]byte, 32)
-		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 {
-			_, _, 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 9292133..980f67c 100644
--- a/src/net/udpsock.go
+++ b/src/net/udpsock.go
@@ -1,9 +1,14 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 (
+	"context"
+	"syscall"
+)
+
 // UDPAddr represents the address of a UDP end point.
 type UDPAddr struct {
 	IP   IP
@@ -53,9 +58,185 @@ func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	addrs, err := internetAddrList(net, addr, noDeadline)
+	addrs, err := internetAddrList(context.Background(), net, addr)
 	if err != nil {
 		return nil, err
 	}
 	return addrs.first(isIPv4).(*UDPAddr), nil
 }
+
+// UDPConn is the implementation of the Conn and PacketConn interfaces
+// for UDP network connections.
+type UDPConn struct {
+	conn
+}
+
+// ReadFromUDP reads a UDP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// 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) (int, *UDPAddr, error) {
+	if !c.ok() {
+		return 0, nil, syscall.EINVAL
+	}
+	n, addr, err := c.readFrom(b)
+	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.
+func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
+	if !c.ok() {
+		return 0, nil, syscall.EINVAL
+	}
+	n, addr, err := c.readFrom(b)
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	if addr == nil {
+		return n, nil, err
+	}
+	return n, addr, err
+}
+
+// ReadMsgUDP reads a packet from c, copying the payload into b and
+// the associated out-of-band data into oob. It returns the number
+// of 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 *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
+	if !c.ok() {
+		return 0, 0, 0, nil, syscall.EINVAL
+	}
+	n, oobn, flags, addr, err = c.readMsg(b, oob)
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return
+}
+
+// WriteToUDP writes a UDP packet to addr via c, copying the payload
+// from b.
+//
+// WriteToUDP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetDeadline and
+// SetWriteDeadline. On packet-oriented connections, write timeouts
+// are rare.
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	n, err := c.writeTo(b, addr)
+	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.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	a, ok := addr.(*UDPAddr)
+	if !ok {
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+	}
+	n, err := c.writeTo(b, a)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
+	}
+	return n, err
+}
+
+// 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
+	}
+	n, oobn, err = c.writeMsg(b, oob, addr)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	return
+}
+
+func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
+
+// DialUDP connects to the remote address raddr on the network net,
+// which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is
+// used as the local address for the connection.
+func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
+	switch net {
+	case "udp", "udp4", "udp6":
+	default:
+		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, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+	}
+	c, err := dialUDP(context.Background(), net, laddr, raddr)
+	if err != nil {
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+	}
+	return c, nil
+}
+
+// ListenUDP listens for incoming UDP packets addressed to the local
+// address laddr. Net must be "udp", "udp4", or "udp6".  If laddr has
+// a port of 0, ListenUDP will choose an available port.
+// The LocalAddr method of the returned UDPConn can be used to
+// discover the port. The returned connection's ReadFrom and WriteTo
+// methods can be used to receive and send UDP packets with per-packet
+// addressing.
+func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
+	switch net {
+	case "udp", "udp4", "udp6":
+	default:
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+	}
+	if laddr == nil {
+		laddr = &UDPAddr{}
+	}
+	c, err := listenUDP(context.Background(), net, laddr)
+	if err != nil {
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+	}
+	return c, nil
+}
+
+// ListenMulticastUDP listens for incoming multicast UDP packets
+// 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: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)}
+	}
+	if gaddr == nil || gaddr.IP == nil {
+		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
+	}
+	c, err := listenMulticastUDP(context.Background(), network, ifi, gaddr)
+	if err != nil {
+		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: err}
+	}
+	return c, nil
+}
diff --git a/src/net/udpsock_plan9.go b/src/net/udpsock_plan9.go
index 1ba57a2..666f206 100644
--- a/src/net/udpsock_plan9.go
+++ b/src/net/udpsock_plan9.go
@@ -1,42 +1,24 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 (
+	"context"
 	"errors"
 	"os"
 	"syscall"
-	"time"
 )
 
-// UDPConn is the implementation of the Conn and PacketConn interfaces
-// for UDP network connections.
-type UDPConn struct {
-	conn
-}
-
-func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
-
-// ReadFromUDP reads a UDP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// 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) {
-	if !c.ok() || c.fd.data == nil {
-		return 0, nil, syscall.EINVAL
-	}
+func (c *UDPConn) readFrom(b []byte) (n int, addr *UDPAddr, err error) {
 	buf := make([]byte, udpHeaderSize+len(b))
-	m, err := c.fd.data.Read(buf)
+	m, err := c.fd.Read(buf)
 	if err != nil {
-		return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+		return 0, nil, err
 	}
 	if m < udpHeaderSize {
-		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")}
+		return 0, nil, errors.New("short read reading UDP header")
 	}
 	buf = buf[:m]
 
@@ -45,36 +27,13 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
 	return n, &UDPAddr{IP: h.raddr, Port: int(h.rport)}, nil
 }
 
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
-	if !c.ok() {
-		return 0, nil, syscall.EINVAL
-	}
-	return c.ReadFromUDP(b)
+func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
+	return 0, 0, 0, nil, syscall.EPLAN9
 }
 
-// ReadMsgUDP reads a packet from c, copying the payload into b and
-// the associated out-of-band data into oob.  It returns the number
-// of 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 *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
-	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
-// from b.
-//
-// WriteToUDP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline.  On packet-oriented connections, write timeouts
-// are rare.
-func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
-	if !c.ok() || c.fd.data == nil {
-		return 0, syscall.EINVAL
-	}
+func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+		return 0, errMissingAddress
 	}
 	h := new(udpHeader)
 	h.raddr = addr.IP.To16()
@@ -86,53 +45,18 @@ 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)
-	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}
+	if _, err := c.fd.Write(buf); err != nil {
+		return 0, err
 	}
 	return len(b), nil
 }
 
-// WriteTo implements the PacketConn WriteTo method.
-func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	a, ok := addr.(*UDPAddr)
-	if !ok {
-		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
-	}
-	return c.WriteToUDP(b, a)
+func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
+	return 0, 0, syscall.EPLAN9
 }
 
-// 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, &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,
-// which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is
-// used as the local address for the connection.
-func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
-	return dialUDP(net, laddr, raddr, noDeadline)
-}
-
-func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
-	if !deadline.IsZero() {
-		panic("net.dialUDP: deadline not implemented on Plan 9")
-	}
-	switch net {
-	case "udp", "udp4", "udp6":
-	default:
-		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, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
-	}
-	fd, err := dialPlan9(net, laddr, raddr)
+func dialUDP(ctx context.Context, net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
+	fd, err := dialPlan9(ctx, net, laddr, raddr)
 	if err != nil {
 		return nil, err
 	}
@@ -167,49 +91,23 @@ func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
 	return h, b
 }
 
-// ListenUDP listens for incoming UDP packets addressed to the local
-// address laddr.  Net must be "udp", "udp4", or "udp6".  If laddr has
-// a port of 0, ListenUDP will choose an available port.
-// The LocalAddr method of the returned UDPConn can be used to
-// discover the port.  The returned connection's ReadFrom and WriteTo
-// methods can be used to receive and send UDP packets with per-packet
-// addressing.
-func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
-	switch net {
-	case "udp", "udp4", "udp6":
-	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
-	}
-	if laddr == nil {
-		laddr = &UDPAddr{}
-	}
-	l, err := listenPlan9(net, laddr)
+func listenUDP(ctx context.Context, network string, laddr *UDPAddr) (*UDPConn, error) {
+	l, err := listenPlan9(ctx, network, laddr)
 	if err != nil {
 		return nil, err
 	}
 	_, err = l.ctl.WriteString("headers")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, err
 	}
 	l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, err
 	}
 	fd, err := l.netFD()
 	return newUDPConn(fd), err
 }
 
-// ListenMulticastUDP listens for incoming multicast UDP packets
-// 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}
+func listenMulticastUDP(ctx context.Context, network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+	return nil, syscall.EPLAN9
 }
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index 932c6ce..4924801 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,8 +7,8 @@
 package net
 
 import (
+	"context"
 	"syscall"
-	"time"
 )
 
 func sockaddrToUDP(sa syscall.Sockaddr) Addr {
@@ -38,25 +38,7 @@ func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	return ipToSockaddr(family, a.IP, a.Port, a.Zone)
 }
 
-// UDPConn is the implementation of the Conn and PacketConn interfaces
-// for UDP network connections.
-type UDPConn struct {
-	conn
-}
-
-func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
-
-// ReadFromUDP reads a UDP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// 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) (int, *UDPAddr, error) {
-	if !c.ok() {
-		return 0, nil, syscall.EINVAL
-	}
+func (c *UDPConn) readFrom(b []byte) (int, *UDPAddr, error) {
 	var addr *UDPAddr
 	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
@@ -65,33 +47,10 @@ func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
 	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 n, addr, err
-}
-
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
-	if !c.ok() {
-		return 0, nil, syscall.EINVAL
-	}
-	n, addr, err := c.ReadFromUDP(b)
-	if addr == nil {
-		return n, nil, err
-	}
 	return n, addr, err
 }
 
-// ReadMsgUDP reads a packet from c, copying the payload into b and
-// the associated out-of-band data into oob.  It returns the number
-// of 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 *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
-	if !c.ok() {
-		return 0, 0, 0, nil, syscall.EINVAL
-	}
+func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
 	var sa syscall.Sockaddr
 	n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
 	switch sa := sa.(type) {
@@ -100,159 +59,68 @@ 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
 }
 
-// WriteToUDP writes a UDP packet to addr via c, copying the payload
-// from b.
-//
-// WriteToUDP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetDeadline and
-// SetWriteDeadline.  On packet-oriented connections, write timeouts
-// are rare.
-func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
+func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
 	if c.fd.isConnected {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		return 0, ErrWriteToConnected
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+		return 0, errMissingAddress
 	}
 	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		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 0, err
 	}
-	return n, err
+	return c.fd.writeTo(b, sa)
 }
 
-// WriteTo implements the PacketConn WriteTo method.
-func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	a, ok := addr.(*UDPAddr)
-	if !ok {
-		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 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
-	}
+func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
 	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}
+		return 0, 0, 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: errMissingAddress}
+		return 0, 0, errMissingAddress
 	}
-	var sa syscall.Sockaddr
-	sa, err = addr.sockaddr(c.fd.family)
-	if err != nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
-	}
-	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+		return 0, 0, err
 	}
-	return
-}
-
-// DialUDP connects to the remote address raddr on the network net,
-// which must be "udp", "udp4", or "udp6".  If laddr is not nil, it is
-// used as the local address for the connection.
-func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
-	switch net {
-	case "udp", "udp4", "udp6":
-	default:
-		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, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
-	}
-	return dialUDP(net, laddr, raddr, noDeadline)
+	return c.fd.writeMsg(b, oob, sa)
 }
 
-func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
-	fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial", noCancel)
+func dialUDP(ctx context.Context, net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
+	fd, err := internetSocket(ctx, net, laddr, raddr, syscall.SOCK_DGRAM, 0, "dial")
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+		return nil, err
 	}
 	return newUDPConn(fd), nil
 }
 
-// ListenUDP listens for incoming UDP packets addressed to the local
-// address laddr.  Net must be "udp", "udp4", or "udp6".  If laddr has
-// a port of 0, ListenUDP will choose an available port.
-// The LocalAddr method of the returned UDPConn can be used to
-// discover the port.  The returned connection's ReadFrom and WriteTo
-// methods can be used to receive and send UDP packets with per-packet
-// addressing.
-func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
-	switch net {
-	case "udp", "udp4", "udp6":
-	default:
-		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", noCancel)
+func listenUDP(ctx context.Context, network string, laddr *UDPAddr) (*UDPConn, error) {
+	fd, err := internetSocket(ctx, network, laddr, nil, syscall.SOCK_DGRAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, err
 	}
 	return newUDPConn(fd), nil
 }
 
-// ListenMulticastUDP listens for incoming multicast UDP packets
-// 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: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)}
-	}
-	if gaddr == nil || gaddr.IP == nil {
-		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
-	}
-	fd, err := internetSocket(network, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen", noCancel)
+func listenMulticastUDP(ctx context.Context, network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+	fd, err := internetSocket(ctx, network, gaddr, nil, syscall.SOCK_DGRAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: err}
+		return nil, 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: network, Source: c.fd.laddr, Addr: &IPAddr{IP: ip4}, Err: err}
+			return nil, err
 		}
 	} else {
 		if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
 			c.Close()
-			return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
+			return nil, err
 		}
 	}
 	return c, nil
diff --git a/src/net/udpsock_test.go b/src/net/udpsock_test.go
new file mode 100644
index 0000000..29d769c
--- /dev/null
+++ b/src/net/udpsock_test.go
@@ -0,0 +1,399 @@
+// 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 net
+
+import (
+	"internal/testenv"
+	"reflect"
+	"runtime"
+	"testing"
+	"time"
+)
+
+func BenchmarkUDP6LinkLocalUnicast(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
+	if !supportsIPv6 {
+		b.Skip("IPv6 is not supported")
+	}
+	ifi := loopbackInterface()
+	if ifi == nil {
+		b.Skip("loopback interface not found")
+	}
+	lla := ipv6LinkLocalUnicastAddr(ifi)
+	if lla == "" {
+		b.Skip("IPv6 link-local unicast address not found")
+	}
+
+	c1, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
+	if err != nil {
+		b.Fatal(err)
+	}
+	defer c1.Close()
+	c2, err := ListenPacket("udp6", JoinHostPort(lla+"%"+ifi.Name, "0"))
+	if err != nil {
+		b.Fatal(err)
+	}
+	defer c2.Close()
+
+	var buf [1]byte
+	for i := 0; i < b.N; i++ {
+		if _, err := c1.WriteTo(buf[:], c2.LocalAddr()); err != nil {
+			b.Fatal(err)
+		}
+		if _, _, err := c2.ReadFrom(buf[:]); err != nil {
+			b.Fatal(err)
+		}
+	}
+}
+
+type resolveUDPAddrTest struct {
+	network       string
+	litAddrOrName string
+	addr          *UDPAddr
+	err           error
+}
+
+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},
+
+	{"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},
+	{"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
+
+	{"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},
+
+	{"", "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
+
+	{"udp", ":12345", &UDPAddr{Port: 12345}, nil},
+
+	{"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("not supported on %s", runtime.GOOS)
+	}
+
+	c, err := ListenPacket("udp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	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.Fatal(err)
+	}
+	defer c.Close()
+
+	ra, err := ResolveUDPAddr("udp", raddr)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	b := []byte("CONNECTED-MODE SOCKET")
+	_, err = c.(*UDPConn).WriteToUDP(b, 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).WriteTo(b, 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.Write(b)
+	if err != nil {
+		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.Fatal(err)
+	}
+	defer c.Close()
+
+	ra, err := ResolveUDPAddr("udp", raddr)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	b := []byte("UNCONNECTED-MODE SOCKET")
+	_, err = c.(*UDPConn).WriteToUDP(b, ra)
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = c.WriteTo(b, ra)
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = c.(*UDPConn).Write(b)
+	if err == nil {
+		t.Fatal("should fail")
+	}
+	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
+	if err == nil {
+		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)
+		}
+	}
+}
+
+var udpConnLocalNameTests = []struct {
+	net   string
+	laddr *UDPAddr
+}{
+	{"udp4", &UDPAddr{IP: IPv4(127, 0, 0, 1)}},
+	{"udp4", &UDPAddr{}},
+	{"udp4", nil},
+}
+
+func TestUDPConnLocalName(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	for _, tt := range udpConnLocalNameTests {
+		c, err := ListenUDP(tt.net, tt.laddr)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer c.Close()
+		la := c.LocalAddr()
+		if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
+			t.Fatalf("got %v; expected a proper address with non-zero port number", la)
+		}
+	}
+}
+
+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.Fatal(err)
+		}
+		defer c1.Close()
+
+		var la *UDPAddr
+		if laddr != "" {
+			var err error
+			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
+				t.Fatal(err)
+			}
+		}
+		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer c2.Close()
+
+		var connAddrs = [4]struct {
+			got Addr
+			ok  bool
+		}{
+			{c1.LocalAddr(), true},
+			{c1.(*UDPConn).RemoteAddr(), false},
+			{c2.LocalAddr(), true},
+			{c2.RemoteAddr(), true},
+		}
+		for _, ca := range connAddrs {
+			if a, ok := ca.got.(*UDPAddr); ok != ca.ok || ok && a.Port == 0 {
+				t.Fatalf("got %v; expected a proper address with non-zero port number", ca.got)
+			}
+		}
+	}
+}
+
+func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	if !supportsIPv6 {
+		t.Skip("IPv6 is not supported")
+	}
+
+	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.Log(err)
+			continue
+		}
+		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.network, ls.PacketConn.LocalAddr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer c2.Close()
+		if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
+			t.Fatalf("got %v; expected a proper address with zone identifier", la)
+		}
+		if ra, ok := c2.RemoteAddr().(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
+			t.Fatalf("got %v; expected a proper address with zone identifier", ra)
+		}
+
+		if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
+			t.Fatal(err)
+		}
+		b := make([]byte, 32)
+		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 {
+			_, _, 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 returns WSAEMSGSIZ
+				t.Fatal(err)
+			}
+		}
+	}
+}
diff --git a/src/net/unix_test.go b/src/net/unix_test.go
deleted file mode 100644
index f0c5830..0000000
--- a/src/net/unix_test.go
+++ /dev/null
@@ -1,473 +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 !nacl,!plan9,!windows
-
-package net
-
-import (
-	"bytes"
-	"os"
-	"reflect"
-	"runtime"
-	"syscall"
-	"testing"
-	"time"
-)
-
-func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
-	if !testableNetwork("unixgram") {
-		t.Skip("unixgram test")
-	}
-
-	addr := testUnixAddr()
-	la, err := ResolveUnixAddr("unixgram", addr)
-	if err != nil {
-		t.Fatal(err)
-	}
-	c, err := ListenUnixgram("unixgram", la)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer func() {
-		c.Close()
-		os.Remove(addr)
-	}()
-
-	off := make(chan bool)
-	data := [5]byte{1, 2, 3, 4, 5}
-	go func() {
-		defer func() { off <- true }()
-		s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
-		if err != nil {
-			t.Error(err)
-			return
-		}
-		defer syscall.Close(s)
-		rsa := &syscall.SockaddrUnix{Name: addr}
-		if err := syscall.Sendto(s, data[:], 0, rsa); err != nil {
-			t.Error(err)
-			return
-		}
-	}()
-
-	<-off
-	b := make([]byte, 64)
-	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-	n, from, err := c.ReadFrom(b)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if from != nil {
-		t.Fatalf("unexpected peer address: %v", from)
-	}
-	if !bytes.Equal(b[:n], data[:]) {
-		t.Fatalf("got %v; want %v", b[:n], data[:])
-	}
-}
-
-func TestUnixgramZeroBytePayload(t *testing.T) {
-	if !testableNetwork("unixgram") {
-		t.Skip("unixgram test")
-	}
-
-	c1, err := newLocalPacketListener("unixgram")
-	if err != nil {
-		t.Fatal(err)
-	}
-	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()
-
-	for _, genericRead := range []bool{false, true} {
-		n, err := c2.Write(nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		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)
-			}
-		}
-	}
-}
-
-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.Fatal(err)
-	}
-	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("autobind is linux only")
-	}
-
-	laddr := &UnixAddr{Name: "", Net: "unixgram"}
-	c1, err := ListenUnixgram("unixgram", laddr)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c1.Close()
-
-	// retrieve the autobind address
-	autoAddr := c1.LocalAddr().(*UnixAddr)
-	if len(autoAddr.Name) <= 1 {
-		t.Fatalf("invalid autobind address: %v", autoAddr)
-	}
-	if autoAddr.Name[0] != '@' {
-		t.Fatalf("invalid autobind address: %v", autoAddr)
-	}
-
-	c2, err := DialUnix("unixgram", nil, autoAddr)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c2.Close()
-
-	if !reflect.DeepEqual(c1.LocalAddr(), c2.RemoteAddr()) {
-		t.Fatalf("expected autobind address %v, got %v", c1.LocalAddr(), c2.RemoteAddr())
-	}
-}
-
-func TestUnixAutobindClose(t *testing.T) {
-	if runtime.GOOS != "linux" {
-		t.Skip("autobind is linux only")
-	}
-
-	laddr := &UnixAddr{Name: "", Net: "unix"}
-	ln, err := ListenUnix("unix", laddr)
-	if err != nil {
-		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.Fatal(err)
-	}
-	c, err := ListenPacket("unixgram", addr)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.Remove(addr)
-	defer c.Close()
-
-	testUnixgramWriteConn(t, laddr)
-	testUnixgramWritePacketConn(t, laddr)
-}
-
-func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) {
-	c, err := Dial("unixgram", raddr.String())
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
-
-	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("should fail as ErrWriteToConnected: %v", err)
-	}
-	if _, err = c.(*UnixConn).WriteTo(b, raddr); err == nil {
-		t.Fatal("should fail")
-	} else if err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
-	}
-	if _, _, err = c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err == nil {
-		t.Fatal("should fail")
-	} else if err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
-	}
-	if _, err := c.Write(b); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) {
-	addr := testUnixAddr()
-	c, err := ListenPacket("unixgram", addr)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.Remove(addr)
-	defer c.Close()
-
-	b := []byte("UNCONNECTED-MODE SOCKET")
-	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err != nil {
-		t.Fatal(err)
-	}
-	if _, err := c.WriteTo(b, raddr); err != nil {
-		t.Fatal(err)
-	}
-	if _, _, err := c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err != nil {
-		t.Fatal(err)
-	}
-	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.Fatal(err)
-		}
-		ln, err := ListenUnix("unix", ta)
-		if err != nil {
-			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)
-		}
-
-		la, err := ResolveUnixAddr("unix", laddr)
-		if err != nil {
-			t.Fatal(err)
-		}
-		c, err := DialUnix("unix", la, ta)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer func() {
-			c.Close()
-			if la != nil {
-				defer os.Remove(laddr)
-			}
-		}()
-		if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil {
-			t.Fatal(err)
-		}
-
-		switch runtime.GOOS {
-		case "android", "linux":
-			if laddr == "" {
-				laddr = "@" // autobind feature
-			}
-		}
-		var connAddrs = [3]struct{ got, want Addr }{
-			{ln.Addr(), ta},
-			{c.LocalAddr(), &UnixAddr{Name: laddr, Net: "unix"}},
-			{c.RemoteAddr(), ta},
-		}
-		for _, ca := range connAddrs {
-			if !reflect.DeepEqual(ca.got, ca.want) {
-				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
-			}
-		}
-	}
-}
-
-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.Fatal(err)
-		}
-		c1, err := ListenUnixgram("unixgram", ta)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer func() {
-			c1.Close()
-			os.Remove(taddr)
-		}()
-
-		var la *UnixAddr
-		if laddr != "" {
-			if la, err = ResolveUnixAddr("unixgram", laddr); err != nil {
-				t.Fatal(err)
-			}
-		}
-		c2, err := DialUnix("unixgram", la, ta)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer func() {
-			c2.Close()
-			if la != nil {
-				defer os.Remove(laddr)
-			}
-		}()
-
-		switch runtime.GOOS {
-		case "android", "linux":
-			if laddr == "" {
-				laddr = "@" // autobind feature
-			}
-		}
-
-		var connAddrs = [4]struct{ got, want Addr }{
-			{c1.LocalAddr(), ta},
-			{c1.RemoteAddr(), nil},
-			{c2.LocalAddr(), &UnixAddr{Name: laddr, Net: "unixgram"}},
-			{c2.RemoteAddr(), ta},
-		}
-		for _, ca := range connAddrs {
-			if !reflect.DeepEqual(ca.got, ca.want) {
-				t.Fatalf("got %#v; want %#v", ca.got, ca.want)
-			}
-		}
-	}
-}
-
-func TestUnixUnlink(t *testing.T) {
-	if !testableNetwork("unix") {
-		t.Skip("unix test")
-	}
-	name := testUnixAddr()
-	l, err := Listen("unix", name)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if _, err := os.Stat(name); err != nil {
-		t.Fatalf("cannot stat unix socket after ListenUnix: %v", err)
-	}
-	f, _ := l.(*UnixListener).File()
-	l1, err := FileListener(f)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if _, err := os.Stat(name); err != nil {
-		t.Fatalf("cannot stat unix socket after FileListener: %v", err)
-	}
-	if err := l1.Close(); err != nil {
-		t.Fatalf("closing file listener: %v", err)
-	}
-	if _, err := os.Stat(name); err != nil {
-		t.Fatalf("cannot stat unix socket after closing FileListener: %v", err)
-	}
-	f.Close()
-	if _, err := os.Stat(name); err != nil {
-		t.Fatalf("cannot stat unix socket after closing FileListener and fd: %v", err)
-	}
-	l.Close()
-	if _, err := os.Stat(name); err == nil {
-		t.Fatal("closing unix listener did not remove unix socket")
-	}
-}
-
-// 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 a fixup function to restore the old settings.
-// (On non-Unix systems forceCgoDNS returns nil.)
-func forceCgoDNS() func() {
-	c := systemConf()
-	oldGo := c.netGo
-	oldCgo := c.netCgo
-	fixup := func() {
-		c.netGo = oldGo
-		c.netCgo = oldCgo
-	}
-	c.netGo = false
-	c.netCgo = true
-	return fixup
-}
diff --git a/src/net/unixsock.go b/src/net/unixsock.go
index eb91d0d..bacdaa4 100644
--- a/src/net/unixsock.go
+++ b/src/net/unixsock.go
@@ -1,9 +1,16 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 (
+	"context"
+	"os"
+	"syscall"
+	"time"
+)
+
 // UnixAddr represents the address of a Unix domain socket end point.
 type UnixAddr struct {
 	Name string
@@ -45,3 +52,268 @@ func ResolveUnixAddr(net, addr string) (*UnixAddr, error) {
 		return nil, UnknownNetworkError(net)
 	}
 }
+
+// UnixConn is an implementation of the Conn interface for connections
+// to Unix domain sockets.
+type UnixConn struct {
+	conn
+}
+
+// CloseRead shuts down the reading side of the Unix domain connection.
+// Most callers should just use Close.
+func (c *UnixConn) CloseRead() error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	if err := c.fd.closeRead(); err != nil {
+		return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
+}
+
+// CloseWrite shuts down the writing side of the Unix domain connection.
+// Most callers should just use Close.
+func (c *UnixConn) CloseWrite() error {
+	if !c.ok() {
+		return syscall.EINVAL
+	}
+	if err := c.fd.closeWrite(); err != nil {
+		return &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
+}
+
+// ReadFromUnix reads a packet from c, copying the payload into b. It
+// returns the number of bytes copied into b and the source address of
+// the packet.
+//
+// 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) (int, *UnixAddr, error) {
+	if !c.ok() {
+		return 0, nil, syscall.EINVAL
+	}
+	n, addr, err := c.readFrom(b)
+	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.
+func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
+	if !c.ok() {
+		return 0, nil, syscall.EINVAL
+	}
+	n, addr, err := c.readFrom(b)
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	if addr == nil {
+		return n, nil, err
+	}
+	return n, addr, err
+}
+
+// ReadMsgUnix reads a packet from c, copying the payload into b and
+// the associated out-of-band data into oob. It returns the number of
+// 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) {
+	if !c.ok() {
+		return 0, 0, 0, nil, syscall.EINVAL
+	}
+	n, oobn, flags, addr, err = c.readMsg(b, oob)
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return
+}
+
+// WriteToUnix writes a packet to addr via c, copying the payload from b.
+//
+// WriteToUnix can be made to time out and return an error with
+// 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) (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	n, err := c.writeTo(b, addr)
+	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.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
+	if !c.ok() {
+		return 0, syscall.EINVAL
+	}
+	a, ok := addr.(*UnixAddr)
+	if !ok {
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+	}
+	n, err := c.writeTo(b, a)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: a.opAddr(), Err: err}
+	}
+	return n, err
+}
+
+// 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) {
+	if !c.ok() {
+		return 0, 0, syscall.EINVAL
+	}
+	n, oobn, err = c.writeMsg(b, oob, addr)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	return
+}
+
+func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
+
+// DialUnix connects to the remote address raddr on the network net,
+// which must be "unix", "unixgram" or "unixpacket".  If laddr is not
+// nil, it is used as the local address for the connection.
+func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
+	switch net {
+	case "unix", "unixgram", "unixpacket":
+	default:
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+	}
+	c, err := dialUnix(context.Background(), net, laddr, raddr)
+	if err != nil {
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+	}
+	return c, nil
+}
+
+// UnixListener is a Unix domain socket listener. Clients should
+// typically use variables of type Listener instead of assuming Unix
+// domain sockets.
+type UnixListener struct {
+	fd     *netFD
+	path   string
+	unlink bool
+}
+
+func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil }
+
+// AcceptUnix accepts the next incoming call and returns the new
+// connection.
+func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
+	if !l.ok() {
+		return nil, syscall.EINVAL
+	}
+	c, err := l.accept()
+	if err != nil {
+		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return c, nil
+}
+
+// Accept implements the Accept method in the Listener interface.
+// Returned connections will be of type *UnixConn.
+func (l *UnixListener) Accept() (Conn, error) {
+	if !l.ok() {
+		return nil, syscall.EINVAL
+	}
+	c, err := l.accept()
+	if err != nil {
+		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return c, nil
+}
+
+// Close stops listening on the Unix address. Already accepted
+// connections are not closed.
+func (l *UnixListener) Close() error {
+	if !l.ok() {
+		return syscall.EINVAL
+	}
+	if err := l.close(); err != nil {
+		return &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return nil
+}
+
+// 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) error {
+	if !l.ok() {
+		return syscall.EINVAL
+	}
+	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
+// mode. It is the caller's responsibility to close f when finished.
+// Closing l does not affect f, and closing f does not affect l.
+//
+// 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) {
+	if !l.ok() {
+		return nil, syscall.EINVAL
+	}
+	f, err = l.file()
+	if err != nil {
+		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return
+}
+
+// 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) {
+	switch net {
+	case "unix", "unixpacket":
+	default:
+		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, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
+	}
+	ln, err := listenUnix(context.Background(), net, laddr)
+	if err != nil {
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+	}
+	return ln, nil
+}
+
+// ListenUnixgram listens for incoming Unix datagram packets addressed
+// to the local address laddr. The network net must be "unixgram".
+// 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) {
+	switch net {
+	case "unixgram":
+	default:
+		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, Source: nil, Addr: nil, Err: errMissingAddress}
+	}
+	c, err := listenUnixgram(context.Background(), net, laddr)
+	if err != nil {
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+	}
+	return c, nil
+}
diff --git a/src/net/unixsock_plan9.go b/src/net/unixsock_plan9.go
index 84b6b60..e70eb21 100644
--- a/src/net/unixsock_plan9.go
+++ b/src/net/unixsock_plan9.go
@@ -1,147 +1,51 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 (
+	"context"
 	"os"
 	"syscall"
-	"time"
 )
 
-// UnixConn is an implementation of the Conn interface for connections
-// to Unix domain sockets.
-type UnixConn struct {
-	conn
+func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
+	return 0, nil, syscall.EPLAN9
 }
 
-// ReadFromUnix reads a packet from c, copying the payload into b.  It
-// returns the number of bytes copied into b and the source address of
-// the packet.
-//
-// 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) (int, *UnixAddr, error) {
-	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
+	return 0, 0, 0, nil, syscall.EPLAN9
 }
 
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
-	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
+	return 0, syscall.EPLAN9
 }
 
-// ReadMsgUnix reads a packet from c, copying the payload into b and
-// the associated out-of-band data into oob.  It returns the number of
-// 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, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
+	return 0, 0, syscall.EPLAN9
 }
 
-// WriteToUnix writes a packet to addr via c, copying the payload from b.
-//
-// WriteToUnix can be made to time out and return an error with
-// 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) (int, error) {
-	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+func dialUnix(ctx context.Context, network string, laddr, raddr *UnixAddr) (*UnixConn, error) {
+	return nil, syscall.EPLAN9
 }
 
-// WriteTo implements the PacketConn WriteTo method.
-func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
-	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
+func (ln *UnixListener) accept() (*UnixConn, error) {
+	return nil, 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, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+func (ln *UnixListener) close() error {
+	return 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 &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func (ln *UnixListener) file() (*os.File, error) {
+	return nil, 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 &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+func listenUnix(ctx context.Context, network string, laddr *UnixAddr) (*UnixListener, error) {
+	return nil, syscall.EPLAN9
 }
 
-// DialUnix connects to the remote address raddr on the network net,
-// which must be "unix", "unixgram" or "unixpacket".  If laddr is not
-// nil, it is used as the local address for the connection.
-func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
-	return dialUnix(net, laddr, raddr, noDeadline)
-}
-
-func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
-	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 {
-	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, &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, &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, &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 &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 &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
-// mode.  It is the caller's responsibility to close f when finished.
-// Closing l does not affect f, and closing f does not affect l.
-//
-// 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() (*os.File, error) {
-	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
-// to the local address laddr.  The network net must be "unixgram".
-// 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, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
+func listenUnixgram(ctx context.Context, network string, laddr *UnixAddr) (*UnixConn, error) {
+	return nil, syscall.EPLAN9
 }
diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go
index fb2397e..5f0999c 100644
--- a/src/net/unixsock_posix.go
+++ b/src/net/unixsock_posix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,13 +7,13 @@
 package net
 
 import (
+	"context"
 	"errors"
 	"os"
 	"syscall"
-	"time"
 )
 
-func unixSocket(net string, laddr, raddr sockaddr, mode string, deadline time.Time) (*netFD, error) {
+func unixSocket(ctx context.Context, net string, laddr, raddr sockaddr, mode string) (*netFD, error) {
 	var sotype int
 	switch net {
 	case "unix":
@@ -42,7 +42,7 @@ func unixSocket(net string, laddr, raddr sockaddr, mode string, deadline time.Ti
 		return nil, errors.New("unknown mode: " + mode)
 	}
 
-	fd, err := socket(net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr, deadline, noCancel)
+	fd, err := socket(ctx, net, syscall.AF_UNIX, sotype, 0, false, laddr, raddr)
 	if err != nil {
 		return nil, err
 	}
@@ -94,25 +94,7 @@ func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	return &syscall.SockaddrUnix{Name: a.Name}, nil
 }
 
-// UnixConn is an implementation of the Conn interface for connections
-// to Unix domain sockets.
-type UnixConn struct {
-	conn
-}
-
-func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
-
-// ReadFromUnix reads a packet from c, copying the payload into b.  It
-// returns the number of bytes copied into b and the source address of
-// the packet.
-//
-// 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) (int, *UnixAddr, error) {
-	if !c.ok() {
-		return 0, nil, syscall.EINVAL
-	}
+func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
 	var addr *UnixAddr
 	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
@@ -121,211 +103,66 @@ func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
 			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 n, addr, err
-}
-
-// ReadFrom implements the PacketConn ReadFrom method.
-func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
-	if !c.ok() {
-		return 0, nil, syscall.EINVAL
-	}
-	n, addr, err := c.ReadFromUnix(b)
-	if addr == nil {
-		return n, nil, err
-	}
 	return n, addr, err
 }
 
-// ReadMsgUnix reads a packet from c, copying the payload into b and
-// the associated out-of-band data into oob.  It returns the number of
-// 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) {
-	if !c.ok() {
-		return 0, 0, 0, nil, syscall.EINVAL
-	}
-	n, oobn, flags, sa, err := c.fd.readMsg(b, oob)
+func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
+	var sa syscall.Sockaddr
+	n, oobn, flags, sa, err = c.fd.readMsg(b, oob)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrUnix:
 		if sa.Name != "" {
 			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
 }
 
-// WriteToUnix writes a packet to addr via c, copying the payload from b.
-//
-// WriteToUnix can be made to time out and return an error with
-// 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) (int, error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
+func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
 	if c.fd.isConnected {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		return 0, ErrWriteToConnected
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+		return 0, errMissingAddress
 	}
 	if addr.Net != sotypeToNet(c.fd.sotype) {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
+		return 0, syscall.EAFNOSUPPORT
 	}
 	sa := &syscall.SockaddrUnix{Name: addr.Name}
-	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.
-func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
-	if !c.ok() {
-		return 0, syscall.EINVAL
-	}
-	a, ok := addr.(*UnixAddr)
-	if !ok {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
-	}
-	return c.WriteToUnix(b, a)
+	return c.fd.writeTo(b, sa)
 }
 
-// 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) {
-	if !c.ok() {
-		return 0, 0, syscall.EINVAL
-	}
+func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
 	if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		return 0, 0, ErrWriteToConnected
 	}
 	var sa syscall.Sockaddr
 	if addr != nil {
 		if addr.Net != sotypeToNet(c.fd.sotype) {
-			return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
+			return 0, 0, syscall.EAFNOSUPPORT
 		}
 		sa = &syscall.SockaddrUnix{Name: addr.Name}
 	}
-	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.
-// Most callers should just use Close.
-func (c *UnixConn) CloseRead() error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	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
+	return c.fd.writeMsg(b, oob, sa)
 }
 
-// CloseWrite shuts down the writing side of the Unix domain connection.
-// Most callers should just use Close.
-func (c *UnixConn) CloseWrite() error {
-	if !c.ok() {
-		return syscall.EINVAL
-	}
-	err := c.fd.closeWrite()
+func dialUnix(ctx context.Context, net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
+	fd, err := unixSocket(ctx, net, laddr, raddr, "dial")
 	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,
-// which must be "unix", "unixgram" or "unixpacket".  If laddr is not
-// nil, it is used as the local address for the connection.
-func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
-	switch net {
-	case "unix", "unixgram", "unixpacket":
-	default:
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
-	}
-	return dialUnix(net, laddr, raddr, noDeadline)
-}
-
-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, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
-	}
-	return newUnixConn(fd), nil
-}
-
-// UnixListener is a Unix domain socket listener.  Clients should
-// typically use variables of type Listener instead of assuming Unix
-// domain sockets.
-type UnixListener struct {
-	fd     *netFD
-	path   string
-	unlink bool
-}
-
-// 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) {
-	switch net {
-	case "unix", "unixpacket":
-	default:
-		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, 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, Source: nil, Addr: laddr.opAddr(), Err: err}
-	}
-	return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
-}
-
-// AcceptUnix accepts the next incoming call and returns the new
-// connection.
-func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
-	if l == nil || l.fd == nil {
-		return nil, syscall.EINVAL
-	}
-	fd, err := l.fd.accept()
-	if err != nil {
-		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+		return nil, err
 	}
 	return newUnixConn(fd), nil
 }
 
-// Accept implements the Accept method in the Listener interface; it
-// waits for the next call and returns a generic Conn.
-func (l *UnixListener) Accept() (c Conn, err error) {
-	c1, err := l.AcceptUnix()
+func (ln *UnixListener) accept() (*UnixConn, error) {
+	fd, err := ln.fd.accept()
 	if err != nil {
 		return nil, err
 	}
-	return c1, nil
+	return newUnixConn(fd), nil
 }
 
-// Close stops listening on the Unix address.  Already accepted
-// connections are not closed.
-func (l *UnixListener) Close() error {
-	if l == nil || l.fd == nil {
-		return syscall.EINVAL
-	}
-
+func (ln *UnixListener) close() error {
 	// The operating system doesn't clean up
 	// the file that announcing created, so
 	// we have to clean it up ourselves.
@@ -334,66 +171,34 @@ func (l *UnixListener) Close() error {
 	// and replaced our socket name already--
 	// but this sequence (remove then close)
 	// is at least compatible with the auto-remove
-	// sequence in ListenUnix.  It's only non-Go
+	// sequence in ListenUnix. It's only non-Go
 	// programs that can mess us up.
-	if l.path[0] != '@' && l.unlink {
-		syscall.Unlink(l.path)
-	}
-	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}
+	if ln.path[0] != '@' && ln.unlink {
+		syscall.Unlink(ln.path)
 	}
-	return err
+	return ln.fd.Close()
 }
 
-// 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) error {
-	if l == nil || l.fd == nil {
-		return syscall.EINVAL
-	}
-	if err := l.fd.setDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+func (ln *UnixListener) file() (*os.File, error) {
+	f, err := ln.fd.dup()
+	if err != nil {
+		return nil, err
 	}
-	return nil
+	return f, nil
 }
 
-// File returns a copy of the underlying os.File, set to blocking
-// mode.  It is the caller's responsibility to close f when finished.
-// Closing l does not affect f, and closing f does not affect l.
-//
-// 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) {
-	f, err = l.fd.dup()
+func listenUnix(ctx context.Context, network string, laddr *UnixAddr) (*UnixListener, error) {
+	fd, err := unixSocket(ctx, network, laddr, nil, "listen")
 	if err != nil {
-		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+		return nil, err
 	}
-	return
+	return &UnixListener{fd: fd, path: fd.laddr.String(), unlink: true}, nil
 }
 
-// ListenUnixgram listens for incoming Unix datagram packets addressed
-// to the local address laddr.  The network net must be "unixgram".
-// 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) {
-	switch net {
-	case "unixgram":
-	default:
-		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, Source: nil, Addr: nil, Err: errMissingAddress}
-	}
-	fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
+func listenUnixgram(ctx context.Context, network string, laddr *UnixAddr) (*UnixConn, error) {
+	fd, err := unixSocket(ctx, network, laddr, nil, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+		return nil, err
 	}
 	return newUnixConn(fd), nil
 }
diff --git a/src/net/unixsock_test.go b/src/net/unixsock_test.go
new file mode 100644
index 0000000..f0f88ed
--- /dev/null
+++ b/src/net/unixsock_test.go
@@ -0,0 +1,446 @@
+// 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 !nacl,!plan9,!windows
+
+package net
+
+import (
+	"bytes"
+	"internal/testenv"
+	"os"
+	"reflect"
+	"runtime"
+	"syscall"
+	"testing"
+	"time"
+)
+
+func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
+	if runtime.GOOS == "openbsd" {
+		testenv.SkipFlaky(t, 15157)
+	}
+
+	addr := testUnixAddr()
+	la, err := ResolveUnixAddr("unixgram", addr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	c, err := ListenUnixgram("unixgram", la)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		c.Close()
+		os.Remove(addr)
+	}()
+
+	off := make(chan bool)
+	data := [5]byte{1, 2, 3, 4, 5}
+	go func() {
+		defer func() { off <- true }()
+		s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		defer syscall.Close(s)
+		rsa := &syscall.SockaddrUnix{Name: addr}
+		if err := syscall.Sendto(s, data[:], 0, rsa); err != nil {
+			t.Error(err)
+			return
+		}
+	}()
+
+	<-off
+	b := make([]byte, 64)
+	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+	n, from, err := c.ReadFrom(b)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if from != nil {
+		t.Fatalf("unexpected peer address: %v", from)
+	}
+	if !bytes.Equal(b[:n], data[:]) {
+		t.Fatalf("got %v; want %v", b[:n], data[:])
+	}
+}
+
+func TestUnixgramZeroBytePayload(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
+
+	c1, err := newLocalPacketListener("unixgram")
+	if err != nil {
+		t.Fatal(err)
+	}
+	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()
+
+	for _, genericRead := range []bool{false, true} {
+		n, err := c2.Write(nil)
+		if err != nil {
+			t.Fatal(err)
+		}
+		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)
+			}
+		}
+	}
+}
+
+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.Fatal(err)
+	}
+	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("autobind is linux only")
+	}
+
+	laddr := &UnixAddr{Name: "", Net: "unixgram"}
+	c1, err := ListenUnixgram("unixgram", laddr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c1.Close()
+
+	// retrieve the autobind address
+	autoAddr := c1.LocalAddr().(*UnixAddr)
+	if len(autoAddr.Name) <= 1 {
+		t.Fatalf("invalid autobind address: %v", autoAddr)
+	}
+	if autoAddr.Name[0] != '@' {
+		t.Fatalf("invalid autobind address: %v", autoAddr)
+	}
+
+	c2, err := DialUnix("unixgram", nil, autoAddr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c2.Close()
+
+	if !reflect.DeepEqual(c1.LocalAddr(), c2.RemoteAddr()) {
+		t.Fatalf("expected autobind address %v, got %v", c1.LocalAddr(), c2.RemoteAddr())
+	}
+}
+
+func TestUnixAutobindClose(t *testing.T) {
+	if runtime.GOOS != "linux" {
+		t.Skip("autobind is linux only")
+	}
+
+	laddr := &UnixAddr{Name: "", Net: "unix"}
+	ln, err := ListenUnix("unix", laddr)
+	if err != nil {
+		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.Fatal(err)
+	}
+	c, err := ListenPacket("unixgram", addr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(addr)
+	defer c.Close()
+
+	testUnixgramWriteConn(t, laddr)
+	testUnixgramWritePacketConn(t, laddr)
+}
+
+func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) {
+	c, err := Dial("unixgram", raddr.String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	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("should fail as ErrWriteToConnected: %v", err)
+	}
+	if _, err = c.(*UnixConn).WriteTo(b, raddr); err == nil {
+		t.Fatal("should fail")
+	} else if err.(*OpError).Err != ErrWriteToConnected {
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
+	}
+	if _, _, err = c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err == nil {
+		t.Fatal("should fail")
+	} else if err.(*OpError).Err != ErrWriteToConnected {
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
+	}
+	if _, err := c.Write(b); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) {
+	addr := testUnixAddr()
+	c, err := ListenPacket("unixgram", addr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(addr)
+	defer c.Close()
+
+	b := []byte("UNCONNECTED-MODE SOCKET")
+	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err != nil {
+		t.Fatal(err)
+	}
+	if _, err := c.WriteTo(b, raddr); err != nil {
+		t.Fatal(err)
+	}
+	if _, _, err := c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err != nil {
+		t.Fatal(err)
+	}
+	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.Fatal(err)
+		}
+		ln, err := ListenUnix("unix", ta)
+		if err != nil {
+			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)
+		}
+
+		la, err := ResolveUnixAddr("unix", laddr)
+		if err != nil {
+			t.Fatal(err)
+		}
+		c, err := DialUnix("unix", la, ta)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer func() {
+			c.Close()
+			if la != nil {
+				defer os.Remove(laddr)
+			}
+		}()
+		if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil {
+			t.Fatal(err)
+		}
+
+		switch runtime.GOOS {
+		case "android", "linux":
+			if laddr == "" {
+				laddr = "@" // autobind feature
+			}
+		}
+		var connAddrs = [3]struct{ got, want Addr }{
+			{ln.Addr(), ta},
+			{c.LocalAddr(), &UnixAddr{Name: laddr, Net: "unix"}},
+			{c.RemoteAddr(), ta},
+		}
+		for _, ca := range connAddrs {
+			if !reflect.DeepEqual(ca.got, ca.want) {
+				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
+			}
+		}
+	}
+}
+
+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.Fatal(err)
+		}
+		c1, err := ListenUnixgram("unixgram", ta)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer func() {
+			c1.Close()
+			os.Remove(taddr)
+		}()
+
+		var la *UnixAddr
+		if laddr != "" {
+			if la, err = ResolveUnixAddr("unixgram", laddr); err != nil {
+				t.Fatal(err)
+			}
+		}
+		c2, err := DialUnix("unixgram", la, ta)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer func() {
+			c2.Close()
+			if la != nil {
+				defer os.Remove(laddr)
+			}
+		}()
+
+		switch runtime.GOOS {
+		case "android", "linux":
+			if laddr == "" {
+				laddr = "@" // autobind feature
+			}
+		}
+
+		var connAddrs = [4]struct{ got, want Addr }{
+			{c1.LocalAddr(), ta},
+			{c1.RemoteAddr(), nil},
+			{c2.LocalAddr(), &UnixAddr{Name: laddr, Net: "unixgram"}},
+			{c2.RemoteAddr(), ta},
+		}
+		for _, ca := range connAddrs {
+			if !reflect.DeepEqual(ca.got, ca.want) {
+				t.Fatalf("got %#v; want %#v", ca.got, ca.want)
+			}
+		}
+	}
+}
+
+func TestUnixUnlink(t *testing.T) {
+	if !testableNetwork("unix") {
+		t.Skip("unix test")
+	}
+	name := testUnixAddr()
+	l, err := Listen("unix", name)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if _, err := os.Stat(name); err != nil {
+		t.Fatalf("cannot stat unix socket after ListenUnix: %v", err)
+	}
+	f, _ := l.(*UnixListener).File()
+	l1, err := FileListener(f)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if _, err := os.Stat(name); err != nil {
+		t.Fatalf("cannot stat unix socket after FileListener: %v", err)
+	}
+	if err := l1.Close(); err != nil {
+		t.Fatalf("closing file listener: %v", err)
+	}
+	if _, err := os.Stat(name); err != nil {
+		t.Fatalf("cannot stat unix socket after closing FileListener: %v", err)
+	}
+	f.Close()
+	if _, err := os.Stat(name); err != nil {
+		t.Fatalf("cannot stat unix socket after closing FileListener and fd: %v", err)
+	}
+	l.Close()
+	if _, err := os.Stat(name); err == nil {
+		t.Fatal("closing unix listener did not remove unix socket")
+	}
+}
diff --git a/src/net/url/url.go b/src/net/url/url.go
index 1a93e34..30e9277 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -3,9 +3,13 @@
 // license that can be found in the LICENSE file.
 
 // Package url parses URLs and implements query escaping.
-// See RFC 3986.
 package url
 
+// See RFC 3986. This package generally follows RFC 3986, except where
+// it deviates for compatibility reasons. When sending changes, first
+// search old issues for history on decisions. Unit tests should also
+// contain references to issue numbers with details.
+
 import (
 	"bytes"
 	"errors"
@@ -307,14 +311,15 @@ func escape(s string, mode encoding) string {
 // 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 '#'
+	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)
+	ForceQuery bool   // append a query ('?') even if RawQuery is empty
+	RawQuery   string // encoded query values, without '?'
+	Fragment   string // fragment for references, without '#'
 }
 
 // User returns a Userinfo containing the provided username
@@ -410,10 +415,11 @@ func split(s string, c string, cutc bool) (string, string) {
 
 // Parse parses rawurl into a URL structure.
 // The rawurl may be relative or absolute.
-func Parse(rawurl string) (url *URL, err error) {
+func Parse(rawurl string) (*URL, error) {
 	// Cut off #frag
 	u, frag := split(rawurl, "#", true)
-	if url, err = parse(u, false); err != nil {
+	url, err := parse(u, false)
+	if err != nil {
 		return nil, err
 	}
 	if frag == "" {
@@ -425,16 +431,16 @@ func Parse(rawurl string) (url *URL, err error) {
 	return url, nil
 }
 
-// ParseRequestURI parses rawurl into a URL structure.  It assumes that
+// ParseRequestURI parses rawurl into a URL structure. It assumes that
 // rawurl was received in an HTTP request, so the rawurl is interpreted
 // only as an absolute URI or an absolute path.
 // The string rawurl is assumed not to have a #fragment suffix.
 // (Web browsers strip #fragment before sending the URL to a web server.)
-func ParseRequestURI(rawurl string) (url *URL, err error) {
+func ParseRequestURI(rawurl string) (*URL, error) {
 	return parse(rawurl, true)
 }
 
-// parse parses a URL from a string in one of two contexts.  If
+// parse parses a URL from a string in one of two contexts. If
 // viaRequest is true, the URL is assumed to have arrived via an HTTP request,
 // in which case only absolute URLs or path-absolute relative URLs are allowed.
 // If viaRequest is false, all forms of relative URLs are allowed.
@@ -459,7 +465,12 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
 	}
 	url.Scheme = strings.ToLower(url.Scheme)
 
-	rest, url.RawQuery = split(rest, "?", true)
+	if strings.HasSuffix(rest, "?") && strings.Count(rest, "?") == 1 {
+		url.ForceQuery = true
+		rest = rest[:len(rest)-1]
+	} else {
+		rest, url.RawQuery = split(rest, "?", true)
+	}
 
 	if !strings.HasPrefix(rest, "/") {
 		if url.Scheme != "" {
@@ -511,7 +522,7 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
 		return nil, host, nil
 	}
 	userinfo := authority[:i]
-	if strings.Index(userinfo, ":") < 0 {
+	if !strings.Contains(userinfo, ":") {
 		if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
 			return nil, "", err
 		}
@@ -684,7 +695,7 @@ func (u *URL) String() string {
 		}
 		buf.WriteString(path)
 	}
-	if u.RawQuery != "" {
+	if u.ForceQuery || u.RawQuery != "" {
 		buf.WriteByte('?')
 		buf.WriteString(u.RawQuery)
 	}
@@ -709,8 +720,8 @@ func (v Values) Get(key string) string {
 	if v == nil {
 		return ""
 	}
-	vs, ok := v[key]
-	if !ok || len(vs) == 0 {
+	vs := v[key]
+	if len(vs) == 0 {
 		return ""
 	}
 	return vs[0]
@@ -738,10 +749,10 @@ func (v Values) Del(key string) {
 // ParseQuery always returns a non-nil map containing all the
 // valid query parameters found; err describes the first decoding error
 // encountered, if any.
-func ParseQuery(query string) (m Values, err error) {
-	m = make(Values)
-	err = parseQuery(m, query)
-	return
+func ParseQuery(query string) (Values, error) {
+	m := make(Values)
+	err := parseQuery(m, query)
+	return m, err
 }
 
 func parseQuery(m Values, query string) (err error) {
@@ -845,8 +856,8 @@ func (u *URL) IsAbs() bool {
 	return u.Scheme != ""
 }
 
-// Parse parses a URL in the context of the receiver.  The provided URL
-// may be relative or absolute.  Parse returns nil, err on parse
+// Parse parses a URL in the context of the receiver. The provided URL
+// may be relative or absolute. Parse returns nil, err on parse
 // failure, otherwise its return value is the same as ResolveReference.
 func (u *URL) Parse(ref string) (*URL, error) {
 	refurl, err := Parse(ref)
@@ -858,7 +869,7 @@ func (u *URL) Parse(ref string) (*URL, error) {
 
 // ResolveReference resolves a URI reference to an absolute URI from
 // an absolute base URI, per RFC 3986 Section 5.2.  The URI reference
-// may be relative or absolute.  ResolveReference always returns a new
+// may be relative or absolute. ResolveReference always returns a new
 // URL instance, even if the returned URL is identical to either the
 // base or reference. If ref is an absolute URL, then ResolveReference
 // ignores base and returns a copy of ref.
@@ -913,7 +924,7 @@ func (u *URL) RequestURI() string {
 			result = u.Scheme + ":" + result
 		}
 	}
-	if u.RawQuery != "" {
+	if u.ForceQuery || u.RawQuery != "" {
 		result += "?" + u.RawQuery
 	}
 	return result
diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go
index d3f8487..7560f22 100644
--- a/src/net/url/url_test.go
+++ b/src/net/url/url_test.go
@@ -72,6 +72,28 @@ var urltests = []URLTest{
 		},
 		"ftp://john%20doe@www.google.com/",
 	},
+	// empty query
+	{
+		"http://www.google.com/?",
+		&URL{
+			Scheme:     "http",
+			Host:       "www.google.com",
+			Path:       "/",
+			ForceQuery: true,
+		},
+		"",
+	},
+	// query ending in question mark (Issue 14573)
+	{
+		"http://www.google.com/?foo=bar?",
+		&URL{
+			Scheme:   "http",
+			Host:     "www.google.com",
+			Path:     "/",
+			RawQuery: "foo=bar?",
+		},
+		"",
+	},
 	// query
 	{
 		"http://www.google.com/?q=go+language",
@@ -553,8 +575,8 @@ func ufmt(u *URL) string {
 			pass = p
 		}
 	}
-	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)
+	return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawpath=%q, rawq=%q, frag=%q, forcequery=%v",
+		u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawPath, u.RawQuery, u.Fragment, u.ForceQuery)
 }
 
 func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) {
@@ -589,7 +611,7 @@ func BenchmarkString(b *testing.B) {
 			g = u.String()
 		}
 		b.StopTimer()
-		if w := tt.roundtrip; g != w {
+		if w := tt.roundtrip; b.N > 0 && g != w {
 			b.Errorf("Parse(%q).String() == %q, want %q", tt.in, g, w)
 		}
 	}
@@ -874,11 +896,13 @@ var resolveReferenceTests = []struct {
 	// Absolute URL references
 	{"http://foo.com?a=b", "https://bar.com/", "https://bar.com/"},
 	{"http://foo.com/", "https://bar.com/?a=b", "https://bar.com/?a=b"},
+	{"http://foo.com/", "https://bar.com/?", "https://bar.com/?"},
 	{"http://foo.com/bar", "mailto:foo at example.com", "mailto:foo at example.com"},
 
 	// Path-absolute references
 	{"http://foo.com/bar", "/baz", "http://foo.com/baz"},
 	{"http://foo.com/bar?a=b#f", "/baz", "http://foo.com/baz"},
+	{"http://foo.com/bar?a=b", "/baz?", "http://foo.com/baz?"},
 	{"http://foo.com/bar?a=b", "/baz?c=d", "http://foo.com/baz?c=d"},
 
 	// Scheme-relative
@@ -1217,6 +1241,15 @@ var requritests = []RequestURITest{
 		},
 		"//foo",
 	},
+	{
+		&URL{
+			Scheme:     "http",
+			Host:       "example.com",
+			Path:       "/foo",
+			ForceQuery: true,
+		},
+		"/foo?",
+	},
 }
 
 func TestRequestURI(t *testing.T) {
diff --git a/src/os/doc.go b/src/os/doc.go
index 869a28a..0313eac 100644
--- a/src/os/doc.go
+++ b/src/os/doc.go
@@ -77,14 +77,14 @@ func (p *ProcessState) Success() bool {
 }
 
 // Sys returns system-dependent exit information about
-// the process.  Convert it to the appropriate underlying
+// the process. Convert it to the appropriate underlying
 // type, such as syscall.WaitStatus on Unix, to access its contents.
 func (p *ProcessState) Sys() interface{} {
 	return p.sys()
 }
 
 // SysUsage returns system-dependent resource usage information about
-// the exited process.  Convert it to the appropriate underlying
+// the exited process. Convert it to the appropriate underlying
 // type, such as *syscall.Rusage on Unix, to access its contents.
 // (On Unix, *syscall.Rusage matches struct rusage as defined in the
 // getrusage(2) manual page.)
@@ -112,7 +112,7 @@ func Hostname() (name string, err error) {
 // nil error. If it encounters an error before the end of the
 // directory, Readdir returns the FileInfo read until that point
 // and a non-nil error.
-func (f *File) Readdir(n int) (fi []FileInfo, err error) {
+func (f *File) Readdir(n int) ([]FileInfo, error) {
 	if f == nil {
 		return nil, ErrInvalid
 	}
diff --git a/src/os/env.go b/src/os/env.go
index a4ede15..4a14714 100644
--- a/src/os/env.go
+++ b/src/os/env.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -27,7 +27,7 @@ func Expand(s string, mapping func(string) string) string {
 }
 
 // ExpandEnv replaces ${var} or $var in the string according to the values
-// of the current environment variables.  References to undefined
+// of the current environment variables. References to undefined
 // variables are replaced by the empty string.
 func ExpandEnv(s string) string {
 	return Expand(s, Getenv)
@@ -49,7 +49,7 @@ func isAlphaNum(c uint8) bool {
 }
 
 // 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 ${}
+// 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) {
 	switch {
diff --git a/src/os/error_test.go b/src/os/error_test.go
index 5477e7e..a47c173 100644
--- a/src/os/error_test.go
+++ b/src/os/error_test.go
@@ -80,11 +80,13 @@ func checkErrorPredicate(predName string, pred func(error) bool, err error) stri
 	return ""
 }
 
-var isExistTests = []struct {
+type isExistTest struct {
 	err   error
 	is    bool
 	isnot bool
-}{
+}
+
+var isExistTests = []isExistTest{
 	{&os.PathError{Err: os.ErrInvalid}, false, false},
 	{&os.PathError{Err: os.ErrPermission}, false, false},
 	{&os.PathError{Err: os.ErrExist}, true, false},
@@ -109,10 +111,12 @@ func TestIsExist(t *testing.T) {
 	}
 }
 
-var isPermissionTests = []struct {
+type isPermissionTest struct {
 	err  error
 	want bool
-}{
+}
+
+var isPermissionTests = []isPermissionTest{
 	{nil, false},
 	{&os.PathError{Err: os.ErrPermission}, true},
 	{&os.SyscallError{Err: os.ErrPermission}, true},
diff --git a/src/os/error_unix.go b/src/os/error_unix.go
index c600227..3c78eb4 100644
--- a/src/os/error_unix.go
+++ b/src/os/error_unix.go
@@ -19,7 +19,7 @@ func isExist(err error) bool {
 	case *SyscallError:
 		err = pe.Err
 	}
-	return err == syscall.EEXIST || err == ErrExist
+	return err == syscall.EEXIST || err == syscall.ENOTEMPTY || err == ErrExist
 }
 
 func isNotExist(err error) bool {
diff --git a/src/os/error_unix_test.go b/src/os/error_unix_test.go
new file mode 100644
index 0000000..76fe015
--- /dev/null
+++ b/src/os/error_unix_test.go
@@ -0,0 +1,39 @@
+// Copyright 2016 The Go 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 os_test
+
+import (
+	"os"
+	"syscall"
+)
+
+func init() {
+	isExistTests = append(isExistTests,
+		isExistTest{err: &os.PathError{Err: syscall.EEXIST}, is: true, isnot: false},
+		isExistTest{err: &os.PathError{Err: syscall.ENOTEMPTY}, is: true, isnot: false},
+
+		isExistTest{err: &os.LinkError{Err: syscall.EEXIST}, is: true, isnot: false},
+		isExistTest{err: &os.LinkError{Err: syscall.ENOTEMPTY}, is: true, isnot: false},
+
+		isExistTest{err: &os.SyscallError{Err: syscall.EEXIST}, is: true, isnot: false},
+		isExistTest{err: &os.SyscallError{Err: syscall.ENOTEMPTY}, is: true, isnot: false},
+	)
+	isPermissionTests = append(isPermissionTests,
+		isPermissionTest{err: &os.PathError{Err: syscall.EACCES}, want: true},
+		isPermissionTest{err: &os.PathError{Err: syscall.EPERM}, want: true},
+		isPermissionTest{err: &os.PathError{Err: syscall.EEXIST}, want: false},
+
+		isPermissionTest{err: &os.LinkError{Err: syscall.EACCES}, want: true},
+		isPermissionTest{err: &os.LinkError{Err: syscall.EPERM}, want: true},
+		isPermissionTest{err: &os.LinkError{Err: syscall.EEXIST}, want: false},
+
+		isPermissionTest{err: &os.SyscallError{Err: syscall.EACCES}, want: true},
+		isPermissionTest{err: &os.SyscallError{Err: syscall.EPERM}, want: true},
+		isPermissionTest{err: &os.SyscallError{Err: syscall.EEXIST}, want: false},
+	)
+
+}
diff --git a/src/os/error_windows_test.go b/src/os/error_windows_test.go
new file mode 100644
index 0000000..427dfdb
--- /dev/null
+++ b/src/os/error_windows_test.go
@@ -0,0 +1,35 @@
+// Copyright 2016 The Go 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 os_test
+
+import (
+	"os"
+	"syscall"
+)
+
+func init() {
+	const _ERROR_BAD_NETPATH = syscall.Errno(53)
+
+	isExistTests = append(isExistTests,
+		isExistTest{err: &os.PathError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true},
+		isExistTest{err: &os.LinkError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true},
+		isExistTest{err: &os.SyscallError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true},
+
+		isExistTest{err: &os.PathError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true},
+		isExistTest{err: &os.LinkError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true},
+		isExistTest{err: &os.SyscallError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true},
+
+		isExistTest{err: &os.PathError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true},
+		isExistTest{err: &os.LinkError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true},
+		isExistTest{err: &os.SyscallError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true},
+	)
+	isPermissionTests = append(isPermissionTests,
+		isPermissionTest{err: &os.PathError{Err: syscall.ERROR_ACCESS_DENIED}, want: true},
+		isPermissionTest{err: &os.LinkError{Err: syscall.ERROR_ACCESS_DENIED}, want: true},
+		isPermissionTest{err: &os.SyscallError{Err: syscall.ERROR_ACCESS_DENIED}, want: true},
+	)
+}
diff --git a/src/os/exec.go b/src/os/exec.go
index 15e95b9..bf32498 100644
--- a/src/os/exec.go
+++ b/src/os/exec.go
@@ -6,6 +6,7 @@ package os
 
 import (
 	"runtime"
+	"sync"
 	"sync/atomic"
 	"syscall"
 )
@@ -13,8 +14,9 @@ import (
 // Process stores the information about a process created by StartProcess.
 type Process struct {
 	Pid    int
-	handle uintptr // handle is accessed atomically on Windows
-	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
+	sigMu  sync.RWMutex // avoid race between wait and signal
 }
 
 func newProcess(pid int, handle uintptr) *Process {
@@ -41,10 +43,10 @@ type ProcAttr struct {
 	// new process in the form returned by Environ.
 	// If it is nil, the result of Environ will be used.
 	Env []string
-	// Files specifies the open files inherited by the new process.  The
+	// Files specifies the open files inherited by the new process. The
 	// first three entries correspond to standard input, standard output, and
-	// standard error.  An implementation may support additional entries,
-	// depending on the underlying operating system.  A nil entry corresponds
+	// standard error. An implementation may support additional entries,
+	// depending on the underlying operating system. A nil entry corresponds
 	// to that file being closed when the process starts.
 	Files []*File
 
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index 340ebd4..d2c1b17 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -13,6 +13,7 @@ package exec
 
 import (
 	"bytes"
+	"context"
 	"errors"
 	"io"
 	"os"
@@ -102,13 +103,15 @@ type Cmd struct {
 	// available after a call to Wait or Run.
 	ProcessState *os.ProcessState
 
-	lookPathErr     error // LookPath error, if any.
-	finished        bool  // when Wait was called
+	ctx             context.Context // nil means none
+	lookPathErr     error           // LookPath error, if any.
+	finished        bool            // when Wait was called
 	childFiles      []*os.File
 	closeAfterStart []io.Closer
 	closeAfterWait  []io.Closer
 	goroutine       []func() error
 	errch           chan error // one send per goroutine
+	waitDone        chan struct{}
 }
 
 // Command returns the Cmd struct to execute the named program with
@@ -138,6 +141,20 @@ func Command(name string, arg ...string) *Cmd {
 	return cmd
 }
 
+// CommandContext is like Command but includes a context.
+//
+// The provided context is used to kill the process (by calling
+// os.Process.Kill) if the context becomes done before the command
+// completes on its own.
+func CommandContext(ctx context.Context, name string, arg ...string) *Cmd {
+	if ctx == nil {
+		panic("nil Context")
+	}
+	cmd := Command(name, arg...)
+	cmd.ctx = ctx
+	return cmd
+}
+
 // interfaceEqual protects against panics from doing equality tests on
 // two interfaces with non-comparable underlying types.
 func interfaceEqual(a, b interface{}) bool {
@@ -310,6 +327,15 @@ func (c *Cmd) Start() error {
 	if c.Process != nil {
 		return errors.New("exec: already started")
 	}
+	if c.ctx != nil {
+		select {
+		case <-c.ctx.Done():
+			c.closeDescriptors(c.closeAfterStart)
+			c.closeDescriptors(c.closeAfterWait)
+			return c.ctx.Err()
+		default:
+		}
+	}
 
 	type F func(*Cmd) (*os.File, error)
 	for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
@@ -345,6 +371,17 @@ func (c *Cmd) Start() error {
 		}(fn)
 	}
 
+	if c.ctx != nil {
+		c.waitDone = make(chan struct{})
+		go func() {
+			select {
+			case <-c.ctx.Done():
+				c.Process.Kill()
+			case <-c.waitDone:
+			}
+		}()
+	}
+
 	return nil
 }
 
@@ -393,7 +430,11 @@ func (c *Cmd) Wait() error {
 		return errors.New("exec: Wait was already called")
 	}
 	c.finished = true
+
 	state, err := c.Process.Wait()
+	if c.waitDone != nil {
+		close(c.waitDone)
+	}
 	c.ProcessState = state
 
 	var copyError error
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index 52b4724..4cc9847 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -10,6 +10,7 @@ package exec_test
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"fmt"
 	"internal/testenv"
 	"io"
@@ -28,16 +29,24 @@ import (
 	"time"
 )
 
-func helperCommand(t *testing.T, s ...string) *exec.Cmd {
+func helperCommandContext(t *testing.T, ctx context.Context, s ...string) (cmd *exec.Cmd) {
 	testenv.MustHaveExec(t)
 
 	cs := []string{"-test.run=TestHelperProcess", "--"}
 	cs = append(cs, s...)
-	cmd := exec.Command(os.Args[0], cs...)
+	if ctx != nil {
+		cmd = exec.CommandContext(ctx, os.Args[0], cs...)
+	} else {
+		cmd = exec.Command(os.Args[0], cs...)
+	}
 	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
 	return cmd
 }
 
+func helperCommand(t *testing.T, s ...string) *exec.Cmd {
+	return helperCommandContext(t, nil, s...)
+}
+
 func TestEcho(t *testing.T) {
 	bs, err := helperCommand(t, "echo", "foo bar", "baz").Output()
 	if err != nil {
@@ -341,7 +350,7 @@ func TestExtraFilesFDShuffle(t *testing.T) {
 	//
 	// We want to test that FDs in the child do not get overwritten
 	// by one another as this shuffle occurs. The original implementation
-	// was buggy in that in some data dependent cases it would ovewrite
+	// was buggy in that in some data dependent cases it would overwrite
 	// stderr in the child with one of the ExtraFile members.
 	// Testing for this case is difficult because it relies on using
 	// the same FD values as that case. In particular, an FD of 3
@@ -479,7 +488,7 @@ func TestExtraFiles(t *testing.T) {
 	if err != nil {
 		t.Fatalf("Write: %v", err)
 	}
-	_, err = tf.Seek(0, os.SEEK_SET)
+	_, err = tf.Seek(0, io.SeekStart)
 	if err != nil {
 		t.Fatalf("Seek: %v", err)
 	}
@@ -659,10 +668,6 @@ func TestHelperProcess(*testing.T) {
 			// the cloned file descriptors that result from opening
 			// /dev/urandom.
 			// https://golang.org/issue/3955
-		case "plan9":
-			// TODO(0intro): Determine why Plan 9 is leaking
-			// file descriptors.
-			// 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,
@@ -697,7 +702,7 @@ func TestHelperProcess(*testing.T) {
 		}
 		// Referring to fd3 here ensures that it is not
 		// garbage collected, and therefore closed, while
-		// executing the wantfd loop above.  It doesn't matter
+		// executing the wantfd loop above. It doesn't matter
 		// what we do with fd3 as long as we refer to it;
 		// closing it is the easy choice.
 		fd3.Close()
@@ -835,3 +840,111 @@ func TestOutputStderrCapture(t *testing.T) {
 		t.Errorf("ExitError.Stderr = %q; want %q", got, want)
 	}
 }
+
+func TestContext(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	c := helperCommandContext(t, ctx, "pipetest")
+	stdin, err := c.StdinPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	stdout, err := c.StdoutPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := c.Start(); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := stdin.Write([]byte("O:hi\n")); err != nil {
+		t.Fatal(err)
+	}
+	buf := make([]byte, 5)
+	n, err := io.ReadFull(stdout, buf)
+	if n != len(buf) || err != nil || string(buf) != "O:hi\n" {
+		t.Fatalf("ReadFull = %d, %v, %q", n, err, buf[:n])
+	}
+	waitErr := make(chan error, 1)
+	go func() {
+		waitErr <- c.Wait()
+	}()
+	cancel()
+	select {
+	case err := <-waitErr:
+		if err == nil {
+			t.Fatal("expected Wait failure")
+		}
+	case <-time.After(3 * time.Second):
+		t.Fatal("timeout waiting for child process death")
+	}
+}
+
+func TestContextCancel(t *testing.T) {
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+	c := helperCommandContext(t, ctx, "cat")
+
+	r, w, err := os.Pipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	c.Stdin = r
+
+	stdout, err := c.StdoutPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	readDone := make(chan struct{})
+	go func() {
+		defer close(readDone)
+		var a [1024]byte
+		for {
+			n, err := stdout.Read(a[:])
+			if err != nil {
+				if err != io.EOF {
+					t.Errorf("unexpected read error: %v", err)
+				}
+				return
+			}
+			t.Logf("%s", a[:n])
+		}
+	}()
+
+	if err := c.Start(); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := r.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := io.WriteString(w, "echo"); err != nil {
+		t.Fatal(err)
+	}
+
+	cancel()
+
+	// Calling cancel should have killed the process, so writes
+	// should now fail.  Give the process a little while to die.
+	start := time.Now()
+	for {
+		if _, err := io.WriteString(w, "echo"); err != nil {
+			break
+		}
+		if time.Since(start) > time.Second {
+			t.Fatal("cancelling context did not stop program")
+		}
+		time.Sleep(time.Millisecond)
+	}
+
+	if err := w.Close(); err != nil {
+		t.Error("error closing write end of pipe: %v", err)
+	}
+	<-readDone
+
+	if err := c.Wait(); err == nil {
+		t.Error("program unexpectedly exited successfully")
+	} else {
+		t.Logf("exit status: %v", err)
+	}
+}
diff --git a/src/os/exec/lp_plan9.go b/src/os/exec/lp_plan9.go
index 5aa8a54..142f87e 100644
--- a/src/os/exec/lp_plan9.go
+++ b/src/os/exec/lp_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,6 +7,7 @@ package exec
 import (
 	"errors"
 	"os"
+	"path/filepath"
 	"strings"
 )
 
@@ -44,9 +45,10 @@ func LookPath(file string) (string, error) {
 	}
 
 	path := os.Getenv("path")
-	for _, dir := range strings.Split(path, "\000") {
-		if err := findExecutable(dir + "/" + file); err == nil {
-			return dir + "/" + file, nil
+	for _, dir := range filepath.SplitList(path) {
+		path := filepath.Join(dir, file)
+		if err := findExecutable(path); err == nil {
+			return path, nil
 		}
 	}
 	return "", &Error{file, ErrNotFound}
diff --git a/src/os/exec/lp_unix.go b/src/os/exec/lp_unix.go
index 3f895d5..7a30275 100644
--- a/src/os/exec/lp_unix.go
+++ b/src/os/exec/lp_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -9,6 +9,7 @@ package exec
 import (
 	"errors"
 	"os"
+	"path/filepath"
 	"strings"
 )
 
@@ -42,16 +43,13 @@ func LookPath(file string) (string, error) {
 		}
 		return "", &Error{file, err}
 	}
-	pathenv := os.Getenv("PATH")
-	if pathenv == "" {
-		return "", &Error{file, ErrNotFound}
-	}
-	for _, dir := range strings.Split(pathenv, ":") {
+	path := os.Getenv("PATH")
+	for _, dir := range filepath.SplitList(path) {
 		if dir == "" {
 			// Unix shell semantics: path element "" means "."
 			dir = "."
 		}
-		path := dir + "/" + file
+		path := filepath.Join(dir, file)
 		if err := findExecutable(path); err == nil {
 			return path, nil
 		}
diff --git a/src/os/exec/lp_unix_test.go b/src/os/exec/lp_unix_test.go
index 051db66..d467acf 100644
--- a/src/os/exec/lp_unix_test.go
+++ b/src/os/exec/lp_unix_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/os/exec/lp_windows.go b/src/os/exec/lp_windows.go
index c3efd67..793d4d9 100644
--- a/src/os/exec/lp_windows.go
+++ b/src/os/exec/lp_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,6 +7,7 @@ package exec
 import (
 	"errors"
 	"os"
+	"path/filepath"
 	"strings"
 )
 
@@ -46,7 +47,7 @@ func findExecutable(file string, exts []string) (string, error) {
 			return f, nil
 		}
 	}
-	return ``, os.ErrNotExist
+	return "", os.ErrNotExist
 }
 
 // LookPath searches for an executable binary named file
@@ -55,69 +56,38 @@ func findExecutable(file string, exts []string) (string, error) {
 // LookPath also uses PATHEXT environment variable to match
 // a suitable candidate.
 // The result may be an absolute path or a path relative to the current directory.
-func LookPath(file string) (f string, err error) {
+func LookPath(file string) (string, error) {
+	var exts []string
 	x := os.Getenv(`PATHEXT`)
-	if x == `` {
-		x = `.COM;.EXE;.BAT;.CMD`
-	}
-	exts := []string{}
-	for _, e := range strings.Split(strings.ToLower(x), `;`) {
-		if e == "" {
-			continue
-		}
-		if e[0] != '.' {
-			e = "." + e
-		}
-		exts = append(exts, e)
-	}
-	if strings.IndexAny(file, `:\/`) != -1 {
-		if f, err = findExecutable(file, exts); err == nil {
-			return
-		}
-		return ``, &Error{file, err}
-	}
-	if f, err = findExecutable(`.\`+file, exts); err == nil {
-		return
-	}
-	if pathenv := os.Getenv(`PATH`); pathenv != `` {
-		for _, dir := range splitList(pathenv) {
-			if f, err = findExecutable(dir+`\`+file, exts); err == nil {
-				return
+	if x != "" {
+		for _, e := range strings.Split(strings.ToLower(x), `;`) {
+			if e == "" {
+				continue
 			}
+			if e[0] != '.' {
+				e = "." + e
+			}
+			exts = append(exts, e)
 		}
+	} else {
+		exts = []string{".com", ".exe", ".bat", ".cmd"}
 	}
-	return ``, &Error{file, ErrNotFound}
-}
 
-func splitList(path string) []string {
-	// The same implementation is used in SplitList in path/filepath;
-	// consider changing path/filepath when changing this.
-
-	if path == "" {
-		return []string{}
-	}
-
-	// Split path, respecting but preserving quotes.
-	list := []string{}
-	start := 0
-	quo := false
-	for i := 0; i < len(path); i++ {
-		switch c := path[i]; {
-		case c == '"':
-			quo = !quo
-		case c == os.PathListSeparator && !quo:
-			list = append(list, path[start:i])
-			start = i + 1
+	if strings.ContainsAny(file, `:\/`) {
+		if f, err := findExecutable(file, exts); err == nil {
+			return f, nil
+		} else {
+			return "", &Error{file, err}
 		}
 	}
-	list = append(list, path[start:])
-
-	// Remove quotes.
-	for i, s := range list {
-		if strings.Contains(s, `"`) {
-			list[i] = strings.Replace(s, `"`, ``, -1)
+	if f, err := findExecutable(filepath.Join(".", file), exts); err == nil {
+		return f, nil
+	}
+	path := os.Getenv("path")
+	for _, dir := range filepath.SplitList(path) {
+		if f, err := findExecutable(filepath.Join(dir, file), exts); err == nil {
+			return f, nil
 		}
 	}
-
-	return list
+	return "", &Error{file, ErrNotFound}
 }
diff --git a/src/os/exec/lp_windows_test.go b/src/os/exec/lp_windows_test.go
index 8e1d423..96a22d8 100644
--- a/src/os/exec/lp_windows_test.go
+++ b/src/os/exec/lp_windows_test.go
@@ -107,7 +107,7 @@ func createEnv(dir, PATH, PATHEXT string) []string {
 	env := os.Environ()
 	env = updateEnv(env, "PATHEXT", PATHEXT)
 	// Add dir in front of every directory in the PATH.
-	dirs := splitList(PATH)
+	dirs := filepath.SplitList(PATH)
 	for i := range dirs {
 		dirs[i] = filepath.Join(dir, dirs[i])
 	}
@@ -117,7 +117,7 @@ func createEnv(dir, PATH, PATHEXT string) []string {
 }
 
 // createFiles copies srcPath file into multiply files.
-// It uses dir as preifx for all destination files.
+// It uses dir as prefix for all destination files.
 func createFiles(t *testing.T, dir string, files []string, srcPath string) {
 	for _, f := range files {
 		installProg(t, filepath.Join(dir, f), srcPath)
@@ -431,7 +431,7 @@ var commandTests = []commandTest{
 	},
 	{
 		// LookPath(`a.exe`) will find `.\a.exe`, but prefixing that with
-		// dir `p\a.exe` will refer to not existant file
+		// dir `p\a.exe` will refer to a non-existent file
 		files: []string{`a.exe`, `p\not_important_file`},
 		dir:   `p`,
 		arg0:  `a.exe`,
@@ -440,7 +440,7 @@ var commandTests = []commandTest{
 	},
 	{
 		// like above, but making test succeed by installing file
-		// in refered destination (so LookPath(`a.exe`) will still
+		// in referred destination (so LookPath(`a.exe`) will still
 		// find `.\a.exe`, but we successfully execute `p\a.exe`)
 		files: []string{`a.exe`, `p\a.exe`},
 		dir:   `p`,
diff --git a/src/os/exec_posix.go b/src/os/exec_posix.go
index 94dd04b..3cf38b6 100644
--- a/src/os/exec_posix.go
+++ b/src/os/exec_posix.go
@@ -21,7 +21,7 @@ var (
 func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
 	// If there is no SysProcAttr (ie. no Chroot or changed
 	// UID/GID), double-check existence of the directory we want
-	// to chdir into.  We can make the error clearer this way.
+	// to chdir into. We can make the error clearer this way.
 	if attr != nil && attr.Sys == nil && attr.Dir != "" {
 		if _, err := Stat(attr.Dir); err != nil {
 			pe := err.(*PathError)
diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go
index ed97f85..c4999db 100644
--- a/src/os/exec_unix.go
+++ b/src/os/exec_unix.go
@@ -17,6 +17,22 @@ func (p *Process) wait() (ps *ProcessState, err error) {
 	if p.Pid == -1 {
 		return nil, syscall.EINVAL
 	}
+
+	// If we can block until Wait4 will succeed immediately, do so.
+	ready, err := p.blockUntilWaitable()
+	if err != nil {
+		return nil, err
+	}
+	if ready {
+		// Mark the process done now, before the call to Wait4,
+		// so that Process.signal will not send a signal.
+		p.setDone()
+		// Acquire a write lock on sigMu to wait for any
+		// active call to the signal method to complete.
+		p.sigMu.Lock()
+		p.sigMu.Unlock()
+	}
+
 	var status syscall.WaitStatus
 	var rusage syscall.Rusage
 	pid1, e := syscall.Wait4(p.Pid, &status, 0, &rusage)
@@ -43,6 +59,8 @@ func (p *Process) signal(sig Signal) error {
 	if p.Pid == 0 {
 		return errors.New("os: process not initialized")
 	}
+	p.sigMu.RLock()
+	defer p.sigMu.RUnlock()
 	if p.done() {
 		return errFinished
 	}
diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go
index 3264271..72b5a93 100644
--- a/src/os/exec_windows.go
+++ b/src/os/exec_windows.go
@@ -104,7 +104,7 @@ func init() {
 	defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
 	Args = make([]string, argc)
 	for i, v := range (*argv)[:argc] {
-		Args[i] = string(syscall.UTF16ToString((*v)[:]))
+		Args[i] = syscall.UTF16ToString((*v)[:])
 	}
 }
 
diff --git a/src/os/export_test.go b/src/os/export_test.go
index 9fa7936..d735aee 100644
--- a/src/os/export_test.go
+++ b/src/os/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/os/file.go b/src/os/file.go
index 4f8e3f3..e546441 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -46,6 +46,10 @@ func (f *File) Name() string { return f.name }
 
 // Stdin, Stdout, and Stderr are open Files pointing to the standard input,
 // standard output, and standard error file descriptors.
+//
+// Note that the Go runtime writes to standard error for panics and crashes;
+// closing Stderr may cause those messages to go elsewhere, perhaps
+// to a file opened later.
 var (
 	Stdin  = NewFile(uintptr(syscall.Stdin), "/dev/stdin")
 	Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
@@ -66,6 +70,8 @@ const (
 )
 
 // Seek whence values.
+//
+// Deprecated: Use io.SeekStart, io.SeekCurrent, and io.SeekEnd.
 const (
 	SEEK_SET int = 0 // seek relative to the origin of the file
 	SEEK_CUR int = 1 // seek relative to the current offset
@@ -236,7 +242,7 @@ func (f *File) Chdir() error {
 	return nil
 }
 
-// Open opens the named file for reading.  If successful, methods on
+// Open opens the named file for reading. If successful, methods on
 // 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.
diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go
index c83fa02..9edb6bc 100644
--- a/src/os/file_plan9.go
+++ b/src/os/file_plan9.go
@@ -5,6 +5,7 @@
 package os
 
 import (
+	"io"
 	"runtime"
 	"syscall"
 	"time"
@@ -75,8 +76,8 @@ func syscallMode(i FileMode) (o uint32) {
 }
 
 // OpenFile is the generalized open call; most users will use Open
-// or Create instead.  It opens the named file with specified flag
-// (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
+// or Create instead. It opens the named file with specified flag
+// (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, error) {
@@ -123,7 +124,7 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) {
 	}
 
 	if append {
-		if _, e = syscall.Seek(fd, 0, SEEK_END); e != nil {
+		if _, e = syscall.Seek(fd, 0, io.SeekEnd); e != nil {
 			return nil, &PathError{"seek", name, e}
 		}
 	}
@@ -145,11 +146,9 @@ func (file *file) close() error {
 		return ErrInvalid
 	}
 	var err error
-	syscall.ForkLock.RLock()
 	if e := syscall.Close(file.fd); e != nil {
 		err = &PathError{"close", file.name, e}
 	}
-	syscall.ForkLock.RUnlock()
 	file.fd = -1 // so it can't be closed again
 
 	// no need for a finalizer anymore
@@ -419,12 +418,9 @@ func Chtimes(name string, atime time.Time, mtime time.Time) error {
 func Pipe() (r *File, w *File, err error) {
 	var p [2]int
 
-	syscall.ForkLock.RLock()
 	if e := syscall.Pipe(p[0:]); e != nil {
-		syscall.ForkLock.RUnlock()
 		return nil, nil, NewSyscallError("pipe", e)
 	}
-	syscall.ForkLock.RUnlock()
 
 	return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
 }
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index 05d94f6..9b64f21 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -79,8 +79,8 @@ func epipecheck(file *File, e error) {
 const DevNull = "/dev/null"
 
 // OpenFile is the generalized open call; most users will use Open
-// or Create instead.  It opens the named file with specified flag
-// (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
+// or Create instead. It opens the named file with specified flag
+// (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, error) {
@@ -115,7 +115,7 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) {
 	}
 
 	// There's a race here with fork/exec, which we are
-	// content to live with.  See ../syscall/exec_unix.go.
+	// content to live with. See ../syscall/exec_unix.go.
 	if !supportsCloseOnExec {
 		syscall.CloseOnExec(r)
 	}
@@ -176,7 +176,7 @@ func Stat(name string) (FileInfo, error) {
 
 // Lstat returns a FileInfo 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.
+// 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) (FileInfo, error) {
 	var fs fileStat
@@ -311,7 +311,7 @@ func Remove(name string) error {
 
 	// Both failed: figure out which error to return.
 	// OS X and Linux differ on whether unlink(dir)
-	// returns EISDIR, so can't use that.  However,
+	// returns EISDIR, so can't use that. However,
 	// both agree that rmdir(file) returns ENOTDIR,
 	// so we can use that to decide which error is real.
 	// Rmdir might also return ENOTDIR if given a bad
diff --git a/src/os/file_windows.go b/src/os/file_windows.go
index aa8c05c..f470fc4 100644
--- a/src/os/file_windows.go
+++ b/src/os/file_windows.go
@@ -136,8 +136,8 @@ func openDir(name string) (file *File, err error) {
 }
 
 // OpenFile is the generalized open call; most users will use Open
-// or Create instead.  It opens the named file with specified flag
-// (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
+// or Create instead. It opens the named file with specified flag
+// (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, error) {
@@ -181,9 +181,9 @@ func (file *file) close() error {
 	}
 	var e error
 	if file.isdir() {
-		e = syscall.FindClose(syscall.Handle(file.fd))
+		e = syscall.FindClose(file.fd)
 	} else {
-		e = syscall.CloseHandle(syscall.Handle(file.fd))
+		e = syscall.CloseHandle(file.fd)
 	}
 	var err error
 	if e != nil {
@@ -216,7 +216,7 @@ func (file *File) readdir(n int) (fi []FileInfo, err error) {
 	d := &file.dirinfo.data
 	for n != 0 && !file.dirinfo.isempty {
 		if file.dirinfo.needdata {
-			e := syscall.FindNextFile(syscall.Handle(file.fd), d)
+			e := syscall.FindNextFile(file.fd, d)
 			if e != nil {
 				if e == syscall.ERROR_NO_MORE_FILES {
 					break
@@ -230,7 +230,7 @@ func (file *File) readdir(n int) (fi []FileInfo, err error) {
 			}
 		}
 		file.dirinfo.needdata = true
-		name := string(syscall.UTF16ToString(d.FileName[0:]))
+		name := syscall.UTF16ToString(d.FileName[0:])
 		if name == "." || name == ".." { // Useless names
 			continue
 		}
@@ -288,7 +288,7 @@ func (f *File) readConsole(b []byte) (n int, err error) {
 			}
 			wchars := make([]uint16, nwc)
 			pwc := &wchars[0]
-			nwc, err = windows.MultiByteToWideChar(acp, 2, pmb, int32(nmb), pwc, int32(nwc))
+			nwc, err = windows.MultiByteToWideChar(acp, 2, pmb, int32(nmb), pwc, nwc)
 			if err != nil {
 				return 0, err
 			}
@@ -325,17 +325,17 @@ func (f *File) read(b []byte) (n int, err error) {
 func (f *File) pread(b []byte, off int64) (n int, err error) {
 	f.l.Lock()
 	defer f.l.Unlock()
-	curoffset, e := syscall.Seek(f.fd, 0, 1)
+	curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent)
 	if e != nil {
 		return 0, e
 	}
-	defer syscall.Seek(f.fd, curoffset, 0)
+	defer syscall.Seek(f.fd, curoffset, io.SeekStart)
 	o := syscall.Overlapped{
 		OffsetHigh: uint32(off >> 32),
 		Offset:     uint32(off),
 	}
 	var done uint32
-	e = syscall.ReadFile(syscall.Handle(f.fd), b, &done, &o)
+	e = syscall.ReadFile(f.fd, b, &done, &o)
 	if e != nil {
 		if e == syscall.ERROR_HANDLE_EOF {
 			// end of file
@@ -405,17 +405,17 @@ func (f *File) write(b []byte) (n int, err error) {
 func (f *File) pwrite(b []byte, off int64) (n int, err error) {
 	f.l.Lock()
 	defer f.l.Unlock()
-	curoffset, e := syscall.Seek(f.fd, 0, 1)
+	curoffset, e := syscall.Seek(f.fd, 0, io.SeekCurrent)
 	if e != nil {
 		return 0, e
 	}
-	defer syscall.Seek(f.fd, curoffset, 0)
+	defer syscall.Seek(f.fd, curoffset, io.SeekStart)
 	o := syscall.Overlapped{
 		OffsetHigh: uint32(off >> 32),
 		Offset:     uint32(off),
 	}
 	var done uint32
-	e = syscall.WriteFile(syscall.Handle(f.fd), b, &done, &o)
+	e = syscall.WriteFile(f.fd, b, &done, &o)
 	if e != nil {
 		return 0, e
 	}
@@ -474,6 +474,12 @@ func Remove(name string) error {
 		} else {
 			if a&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
 				e = e1
+			} else if a&syscall.FILE_ATTRIBUTE_READONLY != 0 {
+				if e1 = syscall.SetFileAttributes(p, a&^syscall.FILE_ATTRIBUTE_READONLY); e1 == nil {
+					if e = syscall.DeleteFile(p); e == nil {
+						return nil
+					}
+				}
 			}
 		}
 	}
diff --git a/src/os/getwd.go b/src/os/getwd.go
index d5da53b..4c3c0d9 100644
--- a/src/os/getwd.go
+++ b/src/os/getwd.go
@@ -20,7 +20,7 @@ var getwdCache struct {
 var useSyscallwd = func(error) bool { return true }
 
 // Getwd returns a rooted path name corresponding to the
-// current directory.  If the current directory can be
+// current directory. If the current directory can be
 // reached via multiple paths (due to symbolic links),
 // Getwd may return any one of them.
 func Getwd() (dir string, err error) {
@@ -74,7 +74,7 @@ func Getwd() (dir string, err error) {
 	}
 
 	// General algorithm: find name in parent
-	// and then find name of parent.  Each iteration
+	// and then find name of parent. Each iteration
 	// adds /name to the beginning of dir.
 	dir = ""
 	for parent := ".."; ; parent = "../" + parent {
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 945724b..baa2f07 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -47,10 +47,10 @@ var sysdir = func() *sysDir {
 	switch runtime.GOOS {
 	case "android":
 		return &sysDir{
-			"/system/framework",
+			"/system/lib",
 			[]string{
-				"ext.jar",
-				"framework.jar",
+				"libmedia.so",
+				"libpowermanager.so",
 			},
 		}
 	case "darwin":
@@ -538,7 +538,7 @@ func TestReaddirStatFailures(t *testing.T) {
 		return s
 	}
 
-	if got, want := names(mustReadDir("inital readdir")),
+	if got, want := names(mustReadDir("initial readdir")),
 		[]string{"good1", "good2", "x"}; !reflect.DeepEqual(got, want) {
 		t.Errorf("initial readdir got %q; want %q", got, want)
 	}
@@ -1182,14 +1182,14 @@ func TestSeek(t *testing.T) {
 		out    int64
 	}
 	var tests = []test{
-		{0, 1, int64(len(data))},
-		{0, 0, 0},
-		{5, 0, 5},
-		{0, 2, int64(len(data))},
-		{0, 0, 0},
-		{-1, 2, int64(len(data)) - 1},
-		{1 << 33, 0, 1 << 33},
-		{1 << 33, 2, 1<<33 + int64(len(data))},
+		{0, io.SeekCurrent, int64(len(data))},
+		{0, io.SeekStart, 0},
+		{5, io.SeekStart, 5},
+		{0, io.SeekEnd, int64(len(data))},
+		{0, io.SeekStart, 0},
+		{-1, io.SeekEnd, int64(len(data)) - 1},
+		{1 << 33, io.SeekStart, 1 << 33},
+		{1 << 33, io.SeekEnd, 1<<33 + int64(len(data))},
 	}
 	for i, tt := range tests {
 		off, err := f.Seek(tt.in, tt.whence)
@@ -1275,15 +1275,19 @@ func TestOpenNoName(t *testing.T) {
 	}
 }
 
-func run(t *testing.T, cmd []string) string {
+func runBinHostname(t *testing.T) string {
 	// Run /bin/hostname and collect output.
 	r, w, err := Pipe()
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer r.Close()
-	p, err := StartProcess("/bin/hostname", []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
+	const path = "/bin/hostname"
+	p, err := StartProcess(path, []string{"hostname"}, &ProcAttr{Files: []*File{nil, w, Stderr}})
 	if err != nil {
+		if _, err := Stat(path); IsNotExist(err) {
+			t.Skipf("skipping test; test requires %s but it does not exist", path)
+		}
 		t.Fatal(err)
 	}
 	w.Close()
@@ -1303,7 +1307,7 @@ func run(t *testing.T, cmd []string) string {
 		output = output[0 : n-1]
 	}
 	if output == "" {
-		t.Fatalf("%v produced no output", cmd)
+		t.Fatalf("/bin/hostname produced no output")
 	}
 
 	return output
@@ -1345,7 +1349,7 @@ func TestHostname(t *testing.T) {
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
-	want := run(t, []string{"/bin/hostname"})
+	want := runBinHostname(t)
 	if hostname != want {
 		i := strings.Index(hostname, ".")
 		if i < 0 || hostname[0:i] != want {
@@ -1372,6 +1376,38 @@ func TestReadAt(t *testing.T) {
 	}
 }
 
+// Verify that ReadAt doesn't affect seek offset.
+// In the Plan 9 kernel, there used to be a bug in the implementation of
+// the pread syscall, where the channel offset was erroneously updated after
+// calling pread on a file.
+func TestReadAtOffset(t *testing.T) {
+	f := newFile("TestReadAtOffset", t)
+	defer Remove(f.Name())
+	defer f.Close()
+
+	const data = "hello, world\n"
+	io.WriteString(f, data)
+
+	f.Seek(0, 0)
+	b := make([]byte, 5)
+
+	n, err := f.ReadAt(b, 7)
+	if err != nil || n != len(b) {
+		t.Fatalf("ReadAt 7: %d, %v", n, err)
+	}
+	if string(b) != "world" {
+		t.Fatalf("ReadAt 7: have %q want %q", string(b), "world")
+	}
+
+	n, err = f.Read(b)
+	if err != nil || n != len(b) {
+		t.Fatalf("Read: %d, %v", n, err)
+	}
+	if string(b) != "hello" {
+		t.Fatalf("Read: have %q want %q", string(b), "hello")
+	}
+}
+
 func TestWriteAt(t *testing.T) {
 	f := newFile("TestWriteAt", t)
 	defer Remove(f.Name())
@@ -1579,6 +1615,42 @@ func TestStatDirModeExec(t *testing.T) {
 	}
 }
 
+func TestStatStdin(t *testing.T) {
+	switch runtime.GOOS {
+	case "android", "plan9":
+		t.Skipf("%s doesn't have /bin/sh", runtime.GOOS)
+	}
+
+	testenv.MustHaveExec(t)
+
+	if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
+		st, err := Stdin.Stat()
+		if err != nil {
+			t.Fatalf("Stat failed: %v", err)
+		}
+		fmt.Println(st.Mode() & ModeNamedPipe)
+		Exit(0)
+	}
+
+	var cmd *osexec.Cmd
+	if runtime.GOOS == "windows" {
+		cmd = osexec.Command("cmd", "/c", "echo output | "+Args[0]+" -test.run=TestStatStdin")
+	} else {
+		cmd = osexec.Command("/bin/sh", "-c", "echo output | "+Args[0]+" -test.run=TestStatStdin")
+	}
+	cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
+
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
+	}
+
+	// result will be like "prw-rw-rw"
+	if len(output) < 1 || output[0] != 'p' {
+		t.Fatalf("Child process reports stdin is not pipe '%v'", string(output))
+	}
+}
+
 func TestReadAtEOF(t *testing.T) {
 	f := newFile("TestReadAtEOF", t)
 	defer Remove(f.Name())
@@ -1686,7 +1758,7 @@ var nilFileMethodTests = []struct {
 	{"ReadAt", func(f *File) error { _, err := f.ReadAt(make([]byte, 0), 0); return err }},
 	{"Readdir", func(f *File) error { _, err := f.Readdir(1); return err }},
 	{"Readdirnames", func(f *File) error { _, err := f.Readdirnames(1); return err }},
-	{"Seek", func(f *File) error { _, err := f.Seek(0, 0); return err }},
+	{"Seek", func(f *File) error { _, err := f.Seek(0, io.SeekStart); return err }},
 	{"Stat", func(f *File) error { _, err := f.Stat(); return err }},
 	{"Sync", func(f *File) error { return f.Sync() }},
 	{"Truncate", func(f *File) error { return f.Truncate(0) }},
diff --git a/src/os/os_unix_test.go b/src/os/os_unix_test.go
index d02e07b..5c10154 100644
--- a/src/os/os_unix_test.go
+++ b/src/os/os_unix_test.go
@@ -39,7 +39,7 @@ func TestChown(t *testing.T) {
 	}
 	// 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
+	// on the file. On NFS, the Getgroups groups are
 	// basically useless.
 	f := newFile("TestChown", t)
 	defer Remove(f.Name())
@@ -50,7 +50,7 @@ func TestChown(t *testing.T) {
 	}
 
 	// Can't change uid unless root, but can try
-	// changing the group id.  First try our current group.
+	// changing the group id. First try our current group.
 	gid := Getgid()
 	t.Log("gid:", gid)
 	if err = Chown(f.Name(), -1, gid); err != nil {
@@ -86,7 +86,7 @@ func TestFileChown(t *testing.T) {
 	}
 	// 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
+	// on the file. On NFS, the Getgroups groups are
 	// basically useless.
 	f := newFile("TestFileChown", t)
 	defer Remove(f.Name())
@@ -97,7 +97,7 @@ func TestFileChown(t *testing.T) {
 	}
 
 	// Can't change uid unless root, but can try
-	// changing the group id.  First try our current group.
+	// changing the group id. First try our current group.
 	gid := Getgid()
 	t.Log("gid:", gid)
 	if err = f.Chown(-1, gid); err != nil {
@@ -133,7 +133,7 @@ func TestLchown(t *testing.T) {
 	}
 	// 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
+	// on the file. On NFS, the Getgroups groups are
 	// basically useless.
 	f := newFile("TestLchown", t)
 	defer Remove(f.Name())
@@ -145,12 +145,15 @@ func TestLchown(t *testing.T) {
 
 	linkname := f.Name() + "2"
 	if err := Symlink(f.Name(), linkname); err != nil {
+		if runtime.GOOS == "android" && IsPermission(err) {
+			t.Skip("skipping test on Android; permission error creating symlink")
+		}
 		t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err)
 	}
 	defer Remove(linkname)
 
 	// Can't change uid unless root, but can try
-	// changing the group id.  First try our current group.
+	// changing the group id. First try our current group.
 	gid := Getgid()
 	t.Log("gid:", gid)
 	if err = Lchown(linkname, -1, gid); err != nil {
diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go
index 5c073da..05d7a8f 100644
--- a/src/os/os_windows_test.go
+++ b/src/os/os_windows_test.go
@@ -177,7 +177,7 @@ func TestStatDir(t *testing.T) {
 	}
 
 	if !os.SameFile(fi, fi2) {
-		t.Fatal("race condition occured")
+		t.Fatal("race condition occurred")
 	}
 }
 
@@ -223,3 +223,25 @@ func TestOpenVolumeName(t *testing.T) {
 		t.Fatalf("unexpected file list %q, want %q", have, want)
 	}
 }
+
+func TestDeleteReadOnly(t *testing.T) {
+	tmpdir, err := ioutil.TempDir("", "TestDeleteReadOnly")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+	p := filepath.Join(tmpdir, "a")
+	// This sets FILE_ATTRIBUTE_READONLY.
+	f, err := os.OpenFile(p, os.O_CREATE, 0400)
+	if err != nil {
+		t.Fatal(err)
+	}
+	f.Close()
+
+	if err = os.Chmod(p, 0400); err != nil {
+		t.Fatal(err)
+	}
+	if err = os.Remove(p); err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/src/os/path.go b/src/os/path.go
index 84a3be3..146d7b6 100644
--- a/src/os/path.go
+++ b/src/os/path.go
@@ -61,7 +61,7 @@ func MkdirAll(path string, perm FileMode) error {
 
 // RemoveAll removes path and any children it contains.
 // It removes everything it can but returns the first error
-// it encounters.  If the path does not exist, RemoveAll
+// it encounters. If the path does not exist, RemoveAll
 // returns nil (no error).
 func RemoveAll(path string) error {
 	// Simple case: if Remove works, we're done.
diff --git a/src/os/path_test.go b/src/os/path_test.go
index b453131..51dc25b 100644
--- a/src/os/path_test.go
+++ b/src/os/path_test.go
@@ -147,7 +147,7 @@ func TestRemoveAll(t *testing.T) {
 		// No error checking here: either RemoveAll
 		// will or won't be able to remove dpath;
 		// either way we want to see if it removes fpath
-		// and path/zzz.  Reasons why RemoveAll might
+		// and path/zzz. Reasons why RemoveAll might
 		// succeed in removing dpath as well include:
 		//	* running as root
 		//	* running on a file system without permissions (FAT)
diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go
index 82b792e..74cce80 100644
--- a/src/os/pipe_test.go
+++ b/src/os/pipe_test.go
@@ -88,7 +88,7 @@ func TestStdPipe(t *testing.T) {
 	}
 }
 
-// This is a helper for TestStdPipe.  It's not a test in itself.
+// This is a helper for TestStdPipe. It's not a test in itself.
 func TestStdPipeHelper(t *testing.T) {
 	if os.Getenv("GO_TEST_STD_PIPE_HELPER_SIGNAL") != "" {
 		signal.Notify(make(chan os.Signal, 1), syscall.SIGPIPE)
diff --git a/src/os/signal/doc.go b/src/os/signal/doc.go
index 80e66cf..73b01a2 100644
--- a/src/os/signal/doc.go
+++ b/src/os/signal/doc.go
@@ -11,7 +11,7 @@ package on Windows and Plan 9, see below.
 Types of signals
 
 The signals SIGKILL and SIGSTOP may not be caught by a program, and
-therefore can not be affected by this package.
+therefore cannot be affected by this package.
 
 Synchronous signals are signals triggered by errors in program
 execution: SIGBUS, SIGFPE, and SIGSEGV. These are only considered
@@ -205,8 +205,8 @@ before raising the signal.
 Windows
 
 On Windows a ^C (Control-C) or ^BREAK (Control-Break) normally cause
-the program to exit. If Notify is called for os.SIGINT, ^C or ^BREAK
-will cause os.SIGINT to be sent on the channel, and the program will
+the program to exit. If Notify is called for os.Interrupt, ^C or ^BREAK
+will cause os.Interrupt to be sent on the channel, and the program will
 not exit. If Reset is called, or Stop is called on all channels passed
 to Notify, then the default behavior will be restored.
 
diff --git a/src/os/signal/sig.s b/src/os/signal/sig.s
index 2e94c91..12833a8 100644
--- a/src/os/signal/sig.s
+++ b/src/os/signal/sig.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/os/signal/signal.go b/src/os/signal/signal.go
index 2e6f186..c1376da 100644
--- a/src/os/signal/signal.go
+++ b/src/os/signal/signal.go
@@ -79,7 +79,7 @@ func Ignore(sig ...os.Signal) {
 //
 // Package signal will not block sending to c: the caller must ensure
 // that c has sufficient buffer space to keep up with the expected
-// signal rate.  For a channel used for notification of just one signal value,
+// signal rate. For a channel used for notification of just one signal value,
 // a buffer of size 1 is sufficient.
 //
 // It is allowed to call Notify multiple times with the same channel:
diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go
index 56d786e..406102c 100644
--- a/src/os/signal/signal_test.go
+++ b/src/os/signal/signal_test.go
@@ -139,6 +139,19 @@ func testCancel(t *testing.T, ignore bool) {
 		Reset(syscall.SIGWINCH, syscall.SIGHUP)
 	}
 
+	// At this point we do not expect any further signals on c1.
+	// However, it is just barely possible that the initial SIGWINCH
+	// at the start of this function was delivered after we called
+	// Notify on c1. In that case the waitSig for SIGWINCH may have
+	// picked up that initial SIGWINCH, and the second SIGWINCH may
+	// then have been delivered on the channel. This sequence of events
+	// may have caused issue 15661.
+	// So, read any possible signal from the channel now.
+	select {
+	case <-c1:
+	default:
+	}
+
 	// Send this process a SIGWINCH. It should be ignored.
 	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
 
diff --git a/src/os/stat_darwin.go b/src/os/stat_darwin.go
index 9dc7a99..74214ce 100644
--- a/src/os/stat_darwin.go
+++ b/src/os/stat_darwin.go
@@ -11,7 +11,7 @@ import (
 
 func fillFileStatFromSys(fs *fileStat, name string) {
 	fs.name = basename(name)
-	fs.size = int64(fs.sys.Size)
+	fs.size = fs.sys.Size
 	fs.modTime = timespecToTime(fs.sys.Mtimespec)
 	fs.mode = FileMode(fs.sys.Mode & 0777)
 	switch fs.sys.Mode & syscall.S_IFMT {
diff --git a/src/os/stat_dragonfly.go b/src/os/stat_dragonfly.go
index 69e6323..217bc67 100644
--- a/src/os/stat_dragonfly.go
+++ b/src/os/stat_dragonfly.go
@@ -11,7 +11,7 @@ import (
 
 func fillFileStatFromSys(fs *fileStat, name string) {
 	fs.name = basename(name)
-	fs.size = int64(fs.sys.Size)
+	fs.size = fs.sys.Size
 	fs.modTime = timespecToTime(fs.sys.Mtim)
 	fs.mode = FileMode(fs.sys.Mode & 0777)
 	switch fs.sys.Mode & syscall.S_IFMT {
@@ -42,7 +42,7 @@ func fillFileStatFromSys(fs *fileStat, name string) {
 }
 
 func timespecToTime(ts syscall.Timespec) time.Time {
-	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+	return time.Unix(ts.Sec, ts.Nsec)
 }
 
 // For testing.
diff --git a/src/os/stat_freebsd.go b/src/os/stat_freebsd.go
index e9d38aa..bab4ffa 100644
--- a/src/os/stat_freebsd.go
+++ b/src/os/stat_freebsd.go
@@ -11,7 +11,7 @@ import (
 
 func fillFileStatFromSys(fs *fileStat, name string) {
 	fs.name = basename(name)
-	fs.size = int64(fs.sys.Size)
+	fs.size = fs.sys.Size
 	fs.modTime = timespecToTime(fs.sys.Mtimespec)
 	fs.mode = FileMode(fs.sys.Mode & 0777)
 	switch fs.sys.Mode & syscall.S_IFMT {
diff --git a/src/os/stat_linux.go b/src/os/stat_linux.go
index 69e6323..d36afa9 100644
--- a/src/os/stat_linux.go
+++ b/src/os/stat_linux.go
@@ -11,7 +11,7 @@ import (
 
 func fillFileStatFromSys(fs *fileStat, name string) {
 	fs.name = basename(name)
-	fs.size = int64(fs.sys.Size)
+	fs.size = fs.sys.Size
 	fs.modTime = timespecToTime(fs.sys.Mtim)
 	fs.mode = FileMode(fs.sys.Mode & 0777)
 	switch fs.sys.Mode & syscall.S_IFMT {
diff --git a/src/os/stat_nacl.go b/src/os/stat_nacl.go
index d3bed14..0c53f2f 100644
--- a/src/os/stat_nacl.go
+++ b/src/os/stat_nacl.go
@@ -11,7 +11,7 @@ import (
 
 func fillFileStatFromSys(fs *fileStat, name string) {
 	fs.name = basename(name)
-	fs.size = int64(fs.sys.Size)
+	fs.size = fs.sys.Size
 	fs.modTime = timespecToTime(fs.sys.Mtime, fs.sys.MtimeNsec)
 	fs.mode = FileMode(fs.sys.Mode & 0777)
 	switch fs.sys.Mode & syscall.S_IFMT {
diff --git a/src/os/stat_netbsd.go b/src/os/stat_netbsd.go
index e9d38aa..11ebcac 100644
--- a/src/os/stat_netbsd.go
+++ b/src/os/stat_netbsd.go
@@ -11,7 +11,7 @@ import (
 
 func fillFileStatFromSys(fs *fileStat, name string) {
 	fs.name = basename(name)
-	fs.size = int64(fs.sys.Size)
+	fs.size = fs.sys.Size
 	fs.modTime = timespecToTime(fs.sys.Mtimespec)
 	fs.mode = FileMode(fs.sys.Mode & 0777)
 	switch fs.sys.Mode & syscall.S_IFMT {
@@ -42,7 +42,7 @@ func fillFileStatFromSys(fs *fileStat, name string) {
 }
 
 func timespecToTime(ts syscall.Timespec) time.Time {
-	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+	return time.Unix(ts.Sec, int64(ts.Nsec))
 }
 
 // For testing.
diff --git a/src/os/stat_openbsd.go b/src/os/stat_openbsd.go
index 69e6323..9df2d7f 100644
--- a/src/os/stat_openbsd.go
+++ b/src/os/stat_openbsd.go
@@ -11,7 +11,7 @@ import (
 
 func fillFileStatFromSys(fs *fileStat, name string) {
 	fs.name = basename(name)
-	fs.size = int64(fs.sys.Size)
+	fs.size = fs.sys.Size
 	fs.modTime = timespecToTime(fs.sys.Mtim)
 	fs.mode = FileMode(fs.sys.Mode & 0777)
 	switch fs.sys.Mode & syscall.S_IFMT {
@@ -42,7 +42,7 @@ func fillFileStatFromSys(fs *fileStat, name string) {
 }
 
 func timespecToTime(ts syscall.Timespec) time.Time {
-	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+	return time.Unix(ts.Sec, int64(ts.Nsec))
 }
 
 // For testing.
diff --git a/src/os/stat_plan9.go b/src/os/stat_plan9.go
index fa4bd83..96f056c 100644
--- a/src/os/stat_plan9.go
+++ b/src/os/stat_plan9.go
@@ -20,7 +20,7 @@ func sameFile(fs1, fs2 *fileStat) bool {
 func fileInfoFromStat(d *syscall.Dir) FileInfo {
 	fs := &fileStat{
 		name:    d.Name,
-		size:    int64(d.Length),
+		size:    d.Length,
 		modTime: time.Unix(int64(d.Mtime), 0),
 		sys:     d,
 	}
@@ -100,7 +100,7 @@ func Stat(name string) (FileInfo, error) {
 
 // Lstat returns a FileInfo 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.
+// 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) (FileInfo, error) {
 	return Stat(name)
diff --git a/src/os/stat_solaris.go b/src/os/stat_solaris.go
index 69e6323..217bc67 100644
--- a/src/os/stat_solaris.go
+++ b/src/os/stat_solaris.go
@@ -11,7 +11,7 @@ import (
 
 func fillFileStatFromSys(fs *fileStat, name string) {
 	fs.name = basename(name)
-	fs.size = int64(fs.sys.Size)
+	fs.size = fs.sys.Size
 	fs.modTime = timespecToTime(fs.sys.Mtim)
 	fs.mode = FileMode(fs.sys.Mode & 0777)
 	switch fs.sys.Mode & syscall.S_IFMT {
@@ -42,7 +42,7 @@ func fillFileStatFromSys(fs *fileStat, name string) {
 }
 
 func timespecToTime(ts syscall.Timespec) time.Time {
-	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+	return time.Unix(ts.Sec, ts.Nsec)
 }
 
 // For testing.
diff --git a/src/os/stat_windows.go b/src/os/stat_windows.go
index 0b6c22c..e55eeb0 100644
--- a/src/os/stat_windows.go
+++ b/src/os/stat_windows.go
@@ -25,10 +25,19 @@ func (file *File) Stat() (FileInfo, error) {
 	if file.name == DevNull {
 		return &devNullStat, nil
 	}
+
+	ft, err := syscall.GetFileType(file.fd)
+	if err != nil {
+		return nil, &PathError{"GetFileType", file.name, err}
+	}
+	if ft == syscall.FILE_TYPE_PIPE {
+		return &fileStat{name: basename(file.name), pipe: true}, nil
+	}
+
 	var d syscall.ByHandleFileInformation
-	e := syscall.GetFileInformationByHandle(syscall.Handle(file.fd), &d)
-	if e != nil {
-		return nil, &PathError{"GetFileInformationByHandle", file.name, e}
+	err = syscall.GetFileInformationByHandle(file.fd, &d)
+	if err != nil {
+		return nil, &PathError{"GetFileInformationByHandle", file.name, err}
 	}
 	return &fileStat{
 		name: basename(file.name),
@@ -43,6 +52,7 @@ func (file *File) Stat() (FileInfo, error) {
 		vol:   d.VolumeSerialNumber,
 		idxhi: d.FileIndexHigh,
 		idxlo: d.FileIndexLow,
+		pipe:  false,
 	}, nil
 }
 
@@ -68,7 +78,7 @@ func Stat(name string) (FileInfo, error) {
 
 // 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.
+// 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) (FileInfo, error) {
 	if len(name) == 0 {
diff --git a/src/os/str.go b/src/os/str.go
index d3e03e9..cba9fa3 100644
--- a/src/os/str.go
+++ b/src/os/str.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.
 
-// Simple converions to avoid depending on strconv.
+// Simple conversions to avoid depending on strconv.
 
 package os
 
diff --git a/src/os/sys_windows.go b/src/os/sys_windows.go
index 9490ea6..f6da88c 100644
--- a/src/os/sys_windows.go
+++ b/src/os/sys_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/os/types.go b/src/os/types.go
index 9d6f8e1..12b593f 100644
--- a/src/os/types.go
+++ b/src/os/types.go
@@ -25,7 +25,7 @@ type FileInfo interface {
 // A FileMode represents a file's mode and permission bits.
 // The bits have the same definition on all systems, so that
 // information about files can be moved from one system
-// to another portably.  Not all bits apply to all systems.
+// to another portably. Not all bits apply to all systems.
 // The only required bit is ModeDir for directories.
 type FileMode uint32
 
diff --git a/src/os/types_windows.go b/src/os/types_windows.go
index 7b2e546..ad4e863 100644
--- a/src/os/types_windows.go
+++ b/src/os/types_windows.go
@@ -14,6 +14,7 @@ import (
 type fileStat struct {
 	name string
 	sys  syscall.Win32FileAttributeData
+	pipe bool
 
 	// used to implement SameFile
 	sync.Mutex
@@ -42,6 +43,9 @@ func (fs *fileStat) Mode() (m FileMode) {
 	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
 		m |= ModeSymlink
 	}
+	if fs.pipe {
+		m |= ModeNamedPipe
+	}
 	return m
 }
 
@@ -69,7 +73,7 @@ func (fs *fileStat) loadFileId() error {
 	}
 	defer syscall.CloseHandle(h)
 	var i syscall.ByHandleFileInformation
-	err = syscall.GetFileInformationByHandle(syscall.Handle(h), &i)
+	err = syscall.GetFileInformationByHandle(h, &i)
 	if err != nil {
 		return err
 	}
diff --git a/src/os/user/getgrouplist_darwin.go b/src/os/user/getgrouplist_darwin.go
new file mode 100644
index 0000000..54a2da3
--- /dev/null
+++ b/src/os/user/getgrouplist_darwin.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package user
+
+/*
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+static int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
+	int* buf = malloc(*ngroups * sizeof(int));
+	int rv = getgrouplist(user, (int) group, buf, ngroups);
+	int i;
+	if (rv == 0) {
+		for (i = 0; i < *ngroups; i++) {
+			groups[i] = (gid_t) buf[i];
+		}
+	}
+	free(buf);
+	return rv;
+}
+*/
+import "C"
+
+func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int {
+	return C.mygetgrouplist(name, userGID, gids, n)
+}
diff --git a/src/os/user/getgrouplist_unix.go b/src/os/user/getgrouplist_unix.go
new file mode 100644
index 0000000..14da7c0
--- /dev/null
+++ b/src/os/user/getgrouplist_unix.go
@@ -0,0 +1,22 @@
+// Copyright 2016 The Go 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 !android,linux netbsd openbsd
+
+package user
+
+/*
+#include <unistd.h>
+#include <sys/types.h>
+#include <grp.h>
+
+static int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
+	return getgrouplist(user, group, groups, ngroups);
+}
+*/
+import "C"
+
+func getGroupList(name *C.char, userGID C.gid_t, gids *C.gid_t, n *C.int) C.int {
+	return C.mygetgrouplist(name, userGID, gids, n)
+}
diff --git a/src/os/user/listgroups_solaris.go b/src/os/user/listgroups_solaris.go
new file mode 100644
index 0000000..28a8a78
--- /dev/null
+++ b/src/os/user/listgroups_solaris.go
@@ -0,0 +1,17 @@
+// Copyright 2016 The Go 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
+
+// Even though this file requires no C, it is used to provide a
+// listGroup stub because all the other Solaris calls work.  Otherwise,
+// this stub will conflict with the lookup_stubs.go fallback.
+
+package user
+
+import "fmt"
+
+func listGroups(u *User) ([]string, error) {
+	return nil, fmt.Errorf("user: list groups for %s: not supported on Solaris", u.Username)
+}
diff --git a/src/os/user/listgroups_unix.go b/src/os/user/listgroups_unix.go
new file mode 100644
index 0000000..db952c6
--- /dev/null
+++ b/src/os/user/listgroups_unix.go
@@ -0,0 +1,52 @@
+// Copyright 2016 The Go 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 darwin freebsd !android,linux netbsd openbsd
+
+package user
+
+import (
+	"fmt"
+	"strconv"
+	"unsafe"
+)
+
+/*
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+*/
+import "C"
+
+func listGroups(u *User) ([]string, error) {
+	ug, err := strconv.Atoi(u.Gid)
+	if err != nil {
+		return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)
+	}
+	userGID := C.gid_t(ug)
+	nameC := C.CString(u.Username)
+	defer C.free(unsafe.Pointer(nameC))
+
+	n := C.int(256)
+	gidsC := make([]C.gid_t, n)
+	rv := getGroupList(nameC, userGID, &gidsC[0], &n)
+	if rv == -1 {
+		// More than initial buffer, but now n contains the correct size.
+		const maxGroups = 2048
+		if n > maxGroups {
+			return nil, fmt.Errorf("user: list groups for %s: member of more than %d groups", u.Username, maxGroups)
+		}
+		gidsC = make([]C.gid_t, n)
+		rv := getGroupList(nameC, userGID, &gidsC[0], &n)
+		if rv == -1 {
+			return nil, fmt.Errorf("user: list groups for %s failed (changed groups?)", u.Username)
+		}
+	}
+	gidsC = gidsC[:n]
+	gids := make([]string, 0, n)
+	for _, g := range gidsC[:n] {
+		gids = append(gids, strconv.Itoa(int(g)))
+	}
+	return gids, nil
+}
diff --git a/src/os/user/lookup.go b/src/os/user/lookup.go
index 09f00c7..3b4421b 100644
--- a/src/os/user/lookup.go
+++ b/src/os/user/lookup.go
@@ -12,11 +12,28 @@ func Current() (*User, error) {
 // Lookup looks up a user by username. If the user cannot be found, the
 // returned error is of type UnknownUserError.
 func Lookup(username string) (*User, error) {
-	return lookup(username)
+	return lookupUser(username)
 }
 
 // LookupId looks up a user by userid. If the user cannot be found, the
 // returned error is of type UnknownUserIdError.
 func LookupId(uid string) (*User, error) {
-	return lookupId(uid)
+	return lookupUserId(uid)
+}
+
+// LookupGroup looks up a group by name. If the group cannot be found, the
+// returned error is of type UnknownGroupError.
+func LookupGroup(name string) (*Group, error) {
+	return lookupGroup(name)
+}
+
+// LookupGroupId looks up a group by groupid. If the group cannot be found, the
+// returned error is of type UnknownGroupIdError.
+func LookupGroupId(gid string) (*Group, error) {
+	return lookupGroupId(gid)
+}
+
+// GroupIds returns the list of group IDs that the user is a member of.
+func (u *User) GroupIds() ([]string, error) {
+	return listGroups(u)
 }
diff --git a/src/os/user/lookup_android.go b/src/os/user/lookup_android.go
new file mode 100644
index 0000000..b1be3dc
--- /dev/null
+++ b/src/os/user/lookup_android.go
@@ -0,0 +1,38 @@
+// Copyright 2016 The Go 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 user
+
+import "errors"
+
+func init() {
+	userImplemented = false
+	groupImplemented = false
+}
+
+func current() (*User, error) {
+	return nil, errors.New("user: Current not implemented on android")
+}
+
+func lookupUser(string) (*User, error) {
+	return nil, errors.New("user: Lookup not implemented on android")
+}
+
+func lookupUserId(string) (*User, error) {
+	return nil, errors.New("user: LookupId not implemented on android")
+}
+
+func lookupGroup(string) (*Group, error) {
+	return nil, errors.New("user: LookupGroup not implemented on android")
+}
+
+func lookupGroupId(string) (*Group, error) {
+	return nil, errors.New("user: LookupGroupId not implemented on android")
+}
+
+func listGroups(*User) ([]string, error) {
+	return nil, errors.New("user: GroupIds not implemented on android")
+}
diff --git a/src/os/user/lookup_plan9.go b/src/os/user/lookup_plan9.go
index f7ef348..ea3ce0b 100644
--- a/src/os/user/lookup_plan9.go
+++ b/src/os/user/lookup_plan9.go
@@ -18,6 +18,10 @@ const (
 	userFile = "/dev/user"
 )
 
+func init() {
+	groupImplemented = false
+}
+
 func current() (*User, error) {
 	ubytes, err := ioutil.ReadFile(userFile)
 	if err != nil {
@@ -37,10 +41,22 @@ func current() (*User, error) {
 	return u, nil
 }
 
-func lookup(username string) (*User, error) {
+func lookupUser(username string) (*User, error) {
+	return nil, syscall.EPLAN9
+}
+
+func lookupUserId(uid string) (*User, error) {
+	return nil, syscall.EPLAN9
+}
+
+func lookupGroup(groupname string) (*Group, error) {
+	return nil, syscall.EPLAN9
+}
+
+func lookupGroupId(string) (*Group, error) {
 	return nil, syscall.EPLAN9
 }
 
-func lookupId(uid string) (*User, error) {
+func listGroups(*User) ([]string, error) {
 	return nil, syscall.EPLAN9
 }
diff --git a/src/os/user/lookup_stubs.go b/src/os/user/lookup_stubs.go
index 4fb0e3c..ebf24f7 100644
--- a/src/os/user/lookup_stubs.go
+++ b/src/os/user/lookup_stubs.go
@@ -2,27 +2,83 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !cgo,!windows,!plan9 android
+// +build !cgo,!windows,!plan9,!android
 
 package user
 
 import (
+	"errors"
 	"fmt"
+	"os"
 	"runtime"
+	"strconv"
 )
 
 func init() {
-	implemented = false
+	userImplemented = false
+	groupImplemented = false
 }
 
 func current() (*User, error) {
-	return nil, fmt.Errorf("user: Current not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+	u := &User{
+		Uid:      currentUID(),
+		Gid:      currentGID(),
+		Username: os.Getenv("USER"),
+		Name:     "", // ignored
+		HomeDir:  os.Getenv("HOME"),
+	}
+	if runtime.GOOS == "nacl" {
+		if u.Uid == "" {
+			u.Uid = "1"
+		}
+		if u.Username == "" {
+			u.Username = "nacl"
+		}
+		if u.HomeDir == "" {
+			u.HomeDir = "/home/nacl"
+		}
+	}
+	// cgo isn't available, but if we found the minimum information
+	// without it, use it:
+	if u.Uid != "" && u.Username != "" && u.HomeDir != "" {
+		return u, nil
+	}
+	return u, fmt.Errorf("user: Current not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
 }
 
-func lookup(username string) (*User, error) {
-	return nil, fmt.Errorf("user: Lookup not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+func lookupUser(username string) (*User, error) {
+	return nil, errors.New("user: Lookup requires cgo")
 }
 
-func lookupId(uid string) (*User, error) {
-	return nil, fmt.Errorf("user: LookupId not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+func lookupUserId(uid string) (*User, error) {
+	return nil, errors.New("user: LookupId requires cgo")
+}
+
+func lookupGroup(groupname string) (*Group, error) {
+	return nil, errors.New("user: LookupGroup requires cgo")
+}
+
+func lookupGroupId(string) (*Group, error) {
+	return nil, errors.New("user: LookupGroupId requires cgo")
+}
+
+func listGroups(*User) ([]string, error) {
+	return nil, errors.New("user: GroupIds requires cgo")
+}
+
+func currentUID() string {
+	if id := os.Getuid(); id >= 0 {
+		return strconv.Itoa(id)
+	}
+	// Note: Windows returns -1, but this file isn't used on
+	// Windows anyway, so this empty return path shouldn't be
+	// used.
+	return ""
+}
+
+func currentGID() string {
+	if id := os.Getgid(); id >= 0 {
+		return strconv.Itoa(id)
+	}
+	return ""
 }
diff --git a/src/os/user/lookup_unix.go b/src/os/user/lookup_unix.go
index e8a1eb1..58ecf32 100644
--- a/src/os/user/lookup_unix.go
+++ b/src/os/user/lookup_unix.go
@@ -20,6 +20,7 @@ import (
 #include <unistd.h>
 #include <sys/types.h>
 #include <pwd.h>
+#include <grp.h>
 #include <stdlib.h>
 
 static int mygetpwuid_r(int uid, struct passwd *pwd,
@@ -31,76 +32,87 @@ 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);
 }
+
+static int mygetgrgid_r(int gid, struct group *grp,
+	char *buf, size_t buflen, struct group **result) {
+ return getgrgid_r(gid, grp, buf, buflen, result);
+}
+
+static int mygetgrnam_r(const char *name, struct group *grp,
+	char *buf, size_t buflen, struct group **result) {
+ return getgrnam_r(name, grp, buf, buflen, result);
+}
 */
 import "C"
 
 func current() (*User, error) {
-	return lookupUnix(syscall.Getuid(), "", false)
+	return lookupUnixUid(syscall.Getuid())
 }
 
-func lookup(username string) (*User, error) {
-	return lookupUnix(-1, username, true)
+func lookupUser(username string) (*User, error) {
+	var pwd C.struct_passwd
+	var result *C.struct_passwd
+	nameC := C.CString(username)
+	defer C.free(unsafe.Pointer(nameC))
+
+	buf := alloc(userBuffer)
+	defer buf.free()
+
+	err := retryWithBuffer(buf, func() syscall.Errno {
+		// 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.
+		return syscall.Errno(C.mygetpwnam_r(nameC,
+			&pwd,
+			(*C.char)(buf.ptr),
+			C.size_t(buf.size),
+			&result))
+	})
+	if err != nil {
+		return nil, fmt.Errorf("user: lookup username %s: %v", username, err)
+	}
+	if result == nil {
+		return nil, UnknownUserError(username)
+	}
+	return buildUser(&pwd), err
 }
 
-func lookupId(uid string) (*User, error) {
+func lookupUserId(uid string) (*User, error) {
 	i, e := strconv.Atoi(uid)
 	if e != nil {
 		return nil, e
 	}
-	return lookupUnix(i, "", false)
+	return lookupUnixUid(i)
 }
 
-func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
+func lookupUnixUid(uid int) (*User, error) {
 	var pwd C.struct_passwd
 	var result *C.struct_passwd
 
-	bufSize := C.sysconf(C._SC_GETPW_R_SIZE_MAX)
-	if bufSize == -1 {
-		// DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX.
-		// Additionally, not all Linux systems have it, either. For
-		// example, the musl libc returns -1.
-		bufSize = 1024
-	}
-	if bufSize <= 0 || bufSize > 1<<20 {
-		return nil, fmt.Errorf("user: unreasonable _SC_GETPW_R_SIZE_MAX of %d", bufSize)
-	}
-	buf := C.malloc(C.size_t(bufSize))
-	defer C.free(buf)
-	var rv C.int
-	if lookupByName {
-		nameC := C.CString(username)
-		defer C.free(unsafe.Pointer(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),
-			&result)
-		if rv != 0 {
-			return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.Errno(rv))
-		}
-		if result == nil {
-			return nil, UnknownUserError(username)
-		}
-	} else {
+	buf := alloc(userBuffer)
+	defer buf.free()
+
+	err := retryWithBuffer(buf, func() syscall.Errno {
 		// mygetpwuid_r is a wrapper around getpwuid_r to
 		// to avoid using uid_t because C.uid_t(uid) for
 		// unknown reasons doesn't work on linux.
-		rv = C.mygetpwuid_r(C.int(uid),
+		return syscall.Errno(C.mygetpwuid_r(C.int(uid),
 			&pwd,
-			(*C.char)(buf),
-			C.size_t(bufSize),
-			&result)
-		if rv != 0 {
-			return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.Errno(rv))
-		}
-		if result == nil {
-			return nil, UnknownUserIdError(uid)
-		}
+			(*C.char)(buf.ptr),
+			C.size_t(buf.size),
+			&result))
+	})
+	if err != nil {
+		return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err)
 	}
+	if result == nil {
+		return nil, UnknownUserIdError(uid)
+	}
+	return buildUser(&pwd), nil
+}
+
+func buildUser(pwd *C.struct_passwd) *User {
 	u := &User{
 		Uid:      strconv.Itoa(int(pwd.pw_uid)),
 		Gid:      strconv.Itoa(int(pwd.pw_gid)),
@@ -108,12 +120,152 @@ func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
 		Name:     C.GoString(pwd.pw_gecos),
 		HomeDir:  C.GoString(pwd.pw_dir),
 	}
-	// The pw_gecos field isn't quite standardized.  Some docs
+	// The pw_gecos field isn't quite standardized. Some docs
 	// say: "It is expected to be a comma separated list of
 	// personal data where the first item is the full name of the
 	// user."
 	if i := strings.Index(u.Name, ","); i >= 0 {
 		u.Name = u.Name[:i]
 	}
-	return u, nil
+	return u
+}
+
+func currentGroup() (*Group, error) {
+	return lookupUnixGid(syscall.Getgid())
+}
+
+func lookupGroup(groupname string) (*Group, error) {
+	var grp C.struct_group
+	var result *C.struct_group
+
+	buf := alloc(groupBuffer)
+	defer buf.free()
+	cname := C.CString(groupname)
+	defer C.free(unsafe.Pointer(cname))
+
+	err := retryWithBuffer(buf, func() syscall.Errno {
+		return syscall.Errno(C.mygetgrnam_r(cname,
+			&grp,
+			(*C.char)(buf.ptr),
+			C.size_t(buf.size),
+			&result))
+	})
+	if err != nil {
+		return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err)
+	}
+	if result == nil {
+		return nil, UnknownGroupError(groupname)
+	}
+	return buildGroup(&grp), nil
+}
+
+func lookupGroupId(gid string) (*Group, error) {
+	i, e := strconv.Atoi(gid)
+	if e != nil {
+		return nil, e
+	}
+	return lookupUnixGid(i)
+}
+
+func lookupUnixGid(gid int) (*Group, error) {
+	var grp C.struct_group
+	var result *C.struct_group
+
+	buf := alloc(groupBuffer)
+	defer buf.free()
+
+	err := retryWithBuffer(buf, func() syscall.Errno {
+		// mygetgrgid_r is a wrapper around getgrgid_r to
+		// to avoid using gid_t because C.gid_t(gid) for
+		// unknown reasons doesn't work on linux.
+		return syscall.Errno(C.mygetgrgid_r(C.int(gid),
+			&grp,
+			(*C.char)(buf.ptr),
+			C.size_t(buf.size),
+			&result))
+	})
+	if err != nil {
+		return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err)
+	}
+	if result == nil {
+		return nil, UnknownGroupIdError(strconv.Itoa(gid))
+	}
+	return buildGroup(&grp), nil
+}
+
+func buildGroup(grp *C.struct_group) *Group {
+	g := &Group{
+		Gid:  strconv.Itoa(int(grp.gr_gid)),
+		Name: C.GoString(grp.gr_name),
+	}
+	return g
+}
+
+type bufferKind C.int
+
+const (
+	userBuffer  = bufferKind(C._SC_GETPW_R_SIZE_MAX)
+	groupBuffer = bufferKind(C._SC_GETGR_R_SIZE_MAX)
+)
+
+func (k bufferKind) initialSize() C.size_t {
+	sz := C.sysconf(C.int(k))
+	if sz == -1 {
+		// DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX.
+		// Additionally, not all Linux systems have it, either. For
+		// example, the musl libc returns -1.
+		return 1024
+	}
+	if !isSizeReasonable(int64(sz)) {
+		// Truncate.  If this truly isn't enough, retryWithBuffer will error on the first run.
+		return maxBufferSize
+	}
+	return C.size_t(sz)
+}
+
+type memBuffer struct {
+	ptr  unsafe.Pointer
+	size C.size_t
+}
+
+func alloc(kind bufferKind) *memBuffer {
+	sz := kind.initialSize()
+	return &memBuffer{
+		ptr:  C.malloc(sz),
+		size: sz,
+	}
+}
+
+func (mb *memBuffer) resize(newSize C.size_t) {
+	mb.ptr = C.realloc(mb.ptr, newSize)
+	mb.size = newSize
+}
+
+func (mb *memBuffer) free() {
+	C.free(mb.ptr)
+}
+
+// retryWithBuffer repeatedly calls f(), increasing the size of the
+// buffer each time, until f succeeds, fails with a non-ERANGE error,
+// or the buffer exceeds a reasonable limit.
+func retryWithBuffer(buf *memBuffer, f func() syscall.Errno) error {
+	for {
+		errno := f()
+		if errno == 0 {
+			return nil
+		} else if errno != syscall.ERANGE {
+			return errno
+		}
+		newSize := buf.size * 2
+		if !isSizeReasonable(int64(newSize)) {
+			return fmt.Errorf("internal buffer exceeds %d bytes", maxBufferSize)
+		}
+		buf.resize(newSize)
+	}
+}
+
+const maxBufferSize = 1 << 20
+
+func isSizeReasonable(sz int64) bool {
+	return sz > 0 && sz <= maxBufferSize
 }
diff --git a/src/os/user/lookup_windows.go b/src/os/user/lookup_windows.go
index 99c325f..4e36a5c 100644
--- a/src/os/user/lookup_windows.go
+++ b/src/os/user/lookup_windows.go
@@ -5,11 +5,16 @@
 package user
 
 import (
+	"errors"
 	"fmt"
 	"syscall"
 	"unsafe"
 )
 
+func init() {
+	groupImplemented = false
+}
+
 func isDomainJoined() (bool, error) {
 	var domain *uint16
 	var status uint32
@@ -61,7 +66,7 @@ func lookupFullName(domain, username, domainAndUser string) (string, error) {
 	if err == nil {
 		return name, nil
 	}
-	// domain worked neigher as a domain nor as a server
+	// domain worked neither as a domain nor as a server
 	// could be domain server unavailable
 	// pretend username is fullname
 	return username, nil
@@ -129,7 +134,7 @@ func newUserFromSid(usid *syscall.SID) (*User, error) {
 	return newUser(usid, gid, dir)
 }
 
-func lookup(username string) (*User, error) {
+func lookupUser(username string) (*User, error) {
 	sid, _, t, e := syscall.LookupSID("", username)
 	if e != nil {
 		return nil, e
@@ -140,10 +145,22 @@ func lookup(username string) (*User, error) {
 	return newUserFromSid(sid)
 }
 
-func lookupId(uid string) (*User, error) {
+func lookupUserId(uid string) (*User, error) {
 	sid, e := syscall.StringToSid(uid)
 	if e != nil {
 		return nil, e
 	}
 	return newUserFromSid(sid)
 }
+
+func lookupGroup(groupname string) (*Group, error) {
+	return nil, errors.New("user: LookupGroup not implemented on windows")
+}
+
+func lookupGroupId(string) (*Group, error) {
+	return nil, errors.New("user: LookupGroupId not implemented on windows")
+}
+
+func listGroups(*User) ([]string, error) {
+	return nil, errors.New("user: GroupIds not implemented on windows")
+}
diff --git a/src/os/user/user.go b/src/os/user/user.go
index e8680fe..7b44397 100644
--- a/src/os/user/user.go
+++ b/src/os/user/user.go
@@ -9,23 +9,35 @@ import (
 	"strconv"
 )
 
-var implemented = true // set to false by lookup_stubs.go's init
+var (
+	userImplemented  = true // set to false by lookup_stubs.go's init
+	groupImplemented = true // set to false by lookup_stubs.go's init
+)
 
 // User represents a user account.
 //
-// On posix systems Uid and Gid contain a decimal number
+// On POSIX systems Uid and Gid contain a decimal number
 // representing uid and gid. On windows Uid and Gid
 // contain security identifier (SID) in a string format.
 // On Plan 9, Uid, Gid, Username, and Name will be the
 // contents of /dev/user.
 type User struct {
-	Uid      string // user id
-	Gid      string // primary group id
+	Uid      string // user ID
+	Gid      string // primary group ID
 	Username string
 	Name     string
 	HomeDir  string
 }
 
+// Group represents a grouping of users.
+//
+// On POSIX systems Gid contains a decimal number
+// representing the group ID.
+type Group struct {
+	Gid  string // group ID
+	Name string // group name
+}
+
 // UnknownUserIdError is returned by LookupId when
 // a user cannot be found.
 type UnknownUserIdError int
@@ -41,3 +53,19 @@ type UnknownUserError string
 func (e UnknownUserError) Error() string {
 	return "user: unknown user " + string(e)
 }
+
+// UnknownGroupIdError is returned by LookupGroupId when
+// a group cannot be found.
+type UnknownGroupIdError string
+
+func (e UnknownGroupIdError) Error() string {
+	return "group: unknown groupid " + string(e)
+}
+
+// UnknownGroupError is returned by LookupGroup when
+// a group cannot be found.
+type UnknownGroupError string
+
+func (e UnknownGroupError) Error() string {
+	return "group: unknown group " + string(e)
+}
diff --git a/src/os/user/user_test.go b/src/os/user/user_test.go
index 9d9420e..9d8d94d 100644
--- a/src/os/user/user_test.go
+++ b/src/os/user/user_test.go
@@ -9,18 +9,19 @@ import (
 	"testing"
 )
 
-func check(t *testing.T) {
-	if !implemented {
+func checkUser(t *testing.T) {
+	if !userImplemented {
 		t.Skip("user: not implemented; skipping tests")
 	}
 }
 
 func TestCurrent(t *testing.T) {
-	check(t)
-
+	if runtime.GOOS == "android" {
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
 	u, err := Current()
 	if err != nil {
-		t.Fatalf("Current: %v", err)
+		t.Fatalf("Current: %v (got %#v)", err, u)
 	}
 	if u.HomeDir == "" {
 		t.Errorf("didn't get a HomeDir")
@@ -53,7 +54,7 @@ func compare(t *testing.T, want, got *User) {
 }
 
 func TestLookup(t *testing.T) {
-	check(t)
+	checkUser(t)
 
 	if runtime.GOOS == "plan9" {
 		t.Skipf("Lookup not implemented on %q", runtime.GOOS)
@@ -71,7 +72,7 @@ func TestLookup(t *testing.T) {
 }
 
 func TestLookupId(t *testing.T) {
-	check(t)
+	checkUser(t)
 
 	if runtime.GOOS == "plan9" {
 		t.Skipf("LookupId not implemented on %q", runtime.GOOS)
@@ -87,3 +88,64 @@ func TestLookupId(t *testing.T) {
 	}
 	compare(t, want, got)
 }
+
+func checkGroup(t *testing.T) {
+	if !groupImplemented {
+		t.Skip("user: group not implemented; skipping test")
+	}
+}
+
+func TestLookupGroup(t *testing.T) {
+	checkGroup(t)
+	user, err := Current()
+	if err != nil {
+		t.Fatalf("Current(): %v", err)
+	}
+
+	g1, err := LookupGroupId(user.Gid)
+	if err != nil {
+		// NOTE(rsc): Maybe the group isn't defined. That's fine.
+		// On my OS X laptop, rsc logs in with group 5000 even
+		// though there's no name for group 5000. Such is Unix.
+		t.Logf("LookupGroupId(%q): %v", user.Gid, err)
+		return
+	}
+	if g1.Gid != user.Gid {
+		t.Errorf("LookupGroupId(%q).Gid = %s; want %s", user.Gid, g1.Gid, user.Gid)
+	}
+
+	g2, err := LookupGroup(g1.Name)
+	if err != nil {
+		t.Fatalf("LookupGroup(%q): %v", g1.Name, err)
+	}
+	if g1.Gid != g2.Gid || g1.Name != g2.Name {
+		t.Errorf("LookupGroup(%q) = %+v; want %+v", g1.Name, g2, g1)
+	}
+}
+
+func TestGroupIds(t *testing.T) {
+	checkGroup(t)
+	if runtime.GOOS == "solaris" {
+		t.Skip("skipping GroupIds, see golang.org/issue/14709")
+	}
+	user, err := Current()
+	if err != nil {
+		t.Fatalf("Current(): %v", err)
+	}
+	gids, err := user.GroupIds()
+	if err != nil {
+		t.Fatalf("%+v.GroupIds(): %v", user, err)
+	}
+	if !containsID(gids, user.Gid) {
+		t.Errorf("%+v.GroupIds() = %v; does not contain user GID %s", user, gids, user.Gid)
+	}
+}
+
+func containsID(ids []string, id string) bool {
+	for _, x := range ids {
+		if x == id {
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/os/wait_unimp.go b/src/os/wait_unimp.go
new file mode 100644
index 0000000..7059e59
--- /dev/null
+++ b/src/os/wait_unimp.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Go 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 nacl netbsd openbsd solaris
+
+package os
+
+// blockUntilWaitable attempts to block until a call to p.Wait will
+// succeed immediately, and returns whether it has done so.
+// It does not actually call p.Wait.
+// This version is used on systems that do not implement waitid,
+// or where we have not implemented it yet.
+func (p *Process) blockUntilWaitable() (bool, error) {
+	return false, nil
+}
diff --git a/src/os/wait_wait6.go b/src/os/wait_wait6.go
new file mode 100644
index 0000000..7f4780a
--- /dev/null
+++ b/src/os/wait_wait6.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go 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 os
+
+import (
+	"runtime"
+	"syscall"
+)
+
+const _P_PID = 0
+
+// blockUntilWaitable attempts to block until a call to p.Wait will
+// succeed immediately, and returns whether it has done so.
+// It does not actually call p.Wait.
+func (p *Process) blockUntilWaitable() (bool, error) {
+	var errno syscall.Errno
+	// The arguments on 32-bit FreeBSD look like the following:
+	// - freebsd32_wait6_args{ idtype, id1, id2, status, options, wrusage, info } or
+	// - freebsd32_wait6_args{ idtype, pad, id1, id2, status, options, wrusage, info } when PAD64_REQUIRED=1 on ARM, MIPS or PowerPC
+	if runtime.GOARCH == "386" {
+		_, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0, 0)
+	} else if runtime.GOARCH == "arm" {
+		_, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, 0, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0)
+	} else {
+		_, _, errno = syscall.Syscall6(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+	}
+	if errno != 0 {
+		// The wait6 system call is supported only on FreeBSD
+		// 9.3 and above, so it may return an ENOSYS error.
+		if errno == syscall.ENOSYS {
+			return false, nil
+		}
+		return false, NewSyscallError("wait6", errno)
+	}
+	return true, nil
+}
diff --git a/src/os/wait_waitid.go b/src/os/wait_waitid.go
new file mode 100644
index 0000000..5dbd7f9
--- /dev/null
+++ b/src/os/wait_waitid.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go 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 linux
+
+package os
+
+import (
+	"runtime"
+	"syscall"
+	"unsafe"
+)
+
+const _P_PID = 1
+
+// blockUntilWaitable attempts to block until a call to p.Wait will
+// succeed immediately, and returns whether it has done so.
+// It does not actually call p.Wait.
+func (p *Process) blockUntilWaitable() (bool, error) {
+	// The waitid system call expects a pointer to a siginfo_t,
+	// which is 128 bytes on all GNU/Linux systems.
+	// On Darwin, it requires greater than or equal to 64 bytes
+	// for darwin/{386,arm} and 104 bytes for darwin/amd64.
+	// We don't care about the values it returns.
+	var siginfo [128]byte
+	psig := &siginfo[0]
+	_, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+	runtime.KeepAlive(psig)
+	if e != 0 {
+		return false, NewSyscallError("waitid", e)
+	}
+	return true, nil
+}
diff --git a/src/path/example_test.go b/src/path/example_test.go
index fa8c28d..e8d684f 100644
--- a/src/path/example_test.go
+++ b/src/path/example_test.go
@@ -54,7 +54,14 @@ func ExampleIsAbs() {
 
 func ExampleJoin() {
 	fmt.Println(path.Join("a", "b", "c"))
-	// Output: a/b/c
+	fmt.Println(path.Join("a", "b/c"))
+	fmt.Println(path.Join("a/b", "c"))
+	fmt.Println(path.Join("a/b", "/c"))
+	// Output:
+	// a/b/c
+	// a/b/c
+	// a/b/c
+	// a/b/c
 }
 
 func ExampleSplit() {
diff --git a/src/path/filepath/example_unix_test.go b/src/path/filepath/example_unix_test.go
index 893be1b..cd8233c 100644
--- a/src/path/filepath/example_unix_test.go
+++ b/src/path/filepath/example_unix_test.go
@@ -65,3 +65,17 @@ func ExampleSplit() {
 	// 	dir: "/usr/local//"
 	// 	file: "go"
 }
+
+func ExampleJoin() {
+	fmt.Println("On Unix:")
+	fmt.Println(filepath.Join("a", "b", "c"))
+	fmt.Println(filepath.Join("a", "b/c"))
+	fmt.Println(filepath.Join("a/b", "c"))
+	fmt.Println(filepath.Join("a/b", "/c"))
+	// Output:
+	// On Unix:
+	// a/b/c
+	// a/b/c
+	// a/b/c
+	// a/b/c
+}
diff --git a/src/path/filepath/export_windows_test.go b/src/path/filepath/export_windows_test.go
new file mode 100644
index 0000000..8ca007f
--- /dev/null
+++ b/src/path/filepath/export_windows_test.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package filepath
+
+var ToNorm = toNorm
diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go
index 89f16de..9fa68f5 100644
--- a/src/path/filepath/match.go
+++ b/src/path/filepath/match.go
@@ -49,7 +49,7 @@ Pattern:
 		star, chunk, pattern = scanChunk(pattern)
 		if star && chunk == "" {
 			// Trailing * matches rest of string unless it has a /.
-			return strings.Index(name, string(Separator)) < 0, nil
+			return !strings.Contains(name, string(Separator)), nil
 		}
 		// Look for match at current position.
 		t, ok, err := matchChunk(chunk, name)
@@ -240,19 +240,21 @@ func Glob(pattern string) (matches []string, err error) {
 	}
 
 	dir, file := Split(pattern)
-	switch dir {
-	case "":
-		dir = "."
-	case string(Separator):
-		// nothing
-	default:
-		dir = dir[0 : len(dir)-1] // chop off trailing separator
+	if runtime.GOOS == "windows" {
+		dir = cleanGlobPathWindows(dir)
+	} else {
+		dir = cleanGlobPath(dir)
 	}
 
 	if !hasMeta(dir) {
 		return glob(dir, file, nil)
 	}
 
+	// Prevent infinite recursion. See issue 15879.
+	if dir == pattern {
+		return nil, ErrBadPattern
+	}
+
 	var m []string
 	m, err = Glob(dir)
 	if err != nil {
@@ -267,6 +269,35 @@ func Glob(pattern string) (matches []string, err error) {
 	return
 }
 
+// cleanGlobPath prepares path for glob matching.
+func cleanGlobPath(path string) string {
+	switch path {
+	case "":
+		return "."
+	case string(Separator):
+		// do nothing to the path
+		return path
+	default:
+		return path[0 : len(path)-1] // chop off trailing separator
+	}
+}
+
+// cleanGlobPathWindows is windows version of cleanGlobPath.
+func cleanGlobPathWindows(path string) string {
+	vollen := volumeNameLen(path)
+	switch {
+	case path == "":
+		return "."
+	case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/
+		// do nothing to the path
+		return path
+	case vollen == len(path) && len(path) == 2: // C:
+		return path + "." // convert C: into C:.
+	default:
+		return path[0 : len(path)-1] // chop off trailing separator
+	}
+}
+
 // glob searches for files matching pattern in the directory dir
 // and appends them to matches. If the directory cannot be
 // opened, it returns the existing matches. New matches are
@@ -305,5 +336,5 @@ func glob(dir, pattern string, matches []string) (m []string, e error) {
 // recognized by Match.
 func hasMeta(path string) bool {
 	// TODO(niemeyer): Should other magic characters be added here?
-	return strings.IndexAny(path, "*?[") >= 0
+	return strings.ContainsAny(path, "*?[")
 }
diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go
index 0edbfc7..6b068c7 100644
--- a/src/path/filepath/match_test.go
+++ b/src/path/filepath/match_test.go
@@ -5,10 +5,12 @@
 package filepath_test
 
 import (
+	"fmt"
 	"io/ioutil"
 	"os"
 	. "path/filepath"
 	"runtime"
+	"sort"
 	"strings"
 	"testing"
 )
@@ -88,7 +90,7 @@ func TestMatch(t *testing.T) {
 		pattern := tt.pattern
 		s := tt.s
 		if runtime.GOOS == "windows" {
-			if strings.Index(pattern, "\\") >= 0 {
+			if strings.Contains(pattern, "\\") {
 				// no escape allowed on windows.
 				continue
 			}
@@ -157,6 +159,12 @@ func TestGlobError(t *testing.T) {
 	}
 }
 
+func TestGlobUNC(t *testing.T) {
+	// Just make sure this runs without crashing for now.
+	// See issue 15879.
+	Glob(`\\?\C:\*`)
+}
+
 var globSymlinkTests = []struct {
 	path, dest string
 	brokenLink bool
@@ -209,3 +217,164 @@ func TestGlobSymlink(t *testing.T) {
 		}
 	}
 }
+
+type globTest struct {
+	pattern string
+	matches []string
+}
+
+func (test *globTest) buildWant(root string) []string {
+	want := make([]string, 0)
+	for _, m := range test.matches {
+		want = append(want, root+FromSlash(m))
+	}
+	sort.Strings(want)
+	return want
+}
+
+func (test *globTest) globAbs(root, rootPattern string) error {
+	p := FromSlash(rootPattern + `\` + test.pattern)
+	have, err := Glob(p)
+	if err != nil {
+		return err
+	}
+	sort.Strings(have)
+	want := test.buildWant(root + `\`)
+	if strings.Join(want, "_") == strings.Join(have, "_") {
+		return nil
+	}
+	return fmt.Errorf("Glob(%q) returns %q, but %q expected", p, have, want)
+}
+
+func (test *globTest) globRel(root string) error {
+	p := root + FromSlash(test.pattern)
+	have, err := Glob(p)
+	if err != nil {
+		return err
+	}
+	sort.Strings(have)
+	want := test.buildWant(root)
+	if strings.Join(want, "_") == strings.Join(have, "_") {
+		return nil
+	}
+	// try also matching version without root prefix
+	wantWithNoRoot := test.buildWant("")
+	if strings.Join(wantWithNoRoot, "_") == strings.Join(have, "_") {
+		return nil
+	}
+	return fmt.Errorf("Glob(%q) returns %q, but %q expected", p, have, want)
+}
+
+func TestWindowsGlob(t *testing.T) {
+	if runtime.GOOS != "windows" {
+		t.Skipf("skipping windows specific test")
+	}
+
+	tmpDir, err := ioutil.TempDir("", "TestWindowsGlob")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpDir)
+
+	// /tmp may itself be a symlink
+	tmpDir, err = EvalSymlinks(tmpDir)
+	if err != nil {
+		t.Fatal("eval symlink for tmp dir:", err)
+	}
+
+	if len(tmpDir) < 3 {
+		t.Fatalf("tmpDir path %q is too short", tmpDir)
+	}
+	if tmpDir[1] != ':' {
+		t.Fatalf("tmpDir path %q must have drive letter in it", tmpDir)
+	}
+
+	dirs := []string{
+		"a",
+		"b",
+		"dir/d/bin",
+	}
+	files := []string{
+		"dir/d/bin/git.exe",
+	}
+	for _, dir := range dirs {
+		err := os.MkdirAll(Join(tmpDir, dir), 0777)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+	for _, file := range files {
+		err := ioutil.WriteFile(Join(tmpDir, file), nil, 0666)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	tests := []globTest{
+		{"a", []string{"a"}},
+		{"b", []string{"b"}},
+		{"c", []string{}},
+		{"*", []string{"a", "b", "dir"}},
+		{"d*", []string{"dir"}},
+		{"*i*", []string{"dir"}},
+		{"*r", []string{"dir"}},
+		{"?ir", []string{"dir"}},
+		{"?r", []string{}},
+		{"d*/*/bin/git.exe", []string{"dir/d/bin/git.exe"}},
+	}
+
+	// test absolute paths
+	for _, test := range tests {
+		var p string
+		err = test.globAbs(tmpDir, tmpDir)
+		if err != nil {
+			t.Error(err)
+		}
+		// test C:\*Documents and Settings\...
+		p = tmpDir
+		p = strings.Replace(p, `:\`, `:\*`, 1)
+		err = test.globAbs(tmpDir, p)
+		if err != nil {
+			t.Error(err)
+		}
+		// test C:\Documents and Settings*\...
+		p = tmpDir
+		p = strings.Replace(p, `:\`, `:`, 1)
+		p = strings.Replace(p, `\`, `*\`, 1)
+		p = strings.Replace(p, `:`, `:\`, 1)
+		err = test.globAbs(tmpDir, p)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	// test relative paths
+	wd, err := os.Getwd()
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = os.Chdir(tmpDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		err := os.Chdir(wd)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}()
+	for _, test := range tests {
+		err := test.globRel("")
+		if err != nil {
+			t.Error(err)
+		}
+		err = test.globRel(`.\`)
+		if err != nil {
+			t.Error(err)
+		}
+		err = test.globRel(tmpDir[:2]) // C:
+		if err != nil {
+			t.Error(err)
+		}
+	}
+}
diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go
index dd6f3e7..0dc559c 100644
--- a/src/path/filepath/path.go
+++ b/src/path/filepath/path.go
@@ -4,9 +4,6 @@
 
 // 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 (
@@ -61,7 +58,7 @@ const (
 )
 
 // Clean returns the shortest path name equivalent to path
-// by purely lexical processing.  It applies the following rules
+// by purely lexical processing. It applies the following rules
 // iteratively until no further processing can be done:
 //
 //	1. Replace multiple Separator elements with a single one.
@@ -75,12 +72,14 @@ const (
 // The returned path ends in a slash only if it represents a root directory,
 // such as "/" on Unix or `C:\` on Windows.
 //
+// Finally, any occurrences of slash are replaced by Separator.
+//
 // If the result of this process is an empty string, Clean
 // returns the string ".".
 //
 // See also Rob Pike, ``Lexical File Names in Plan 9 or
 // Getting Dot-Dot Right,''
-// http://plan9.bell-labs.com/sys/doc/lexnames.html
+// https://9p.io/sys/doc/lexnames.html
 func Clean(path string) string {
 	originalPath := path
 	volLen := volumeNameLen(path)
@@ -198,7 +197,7 @@ 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
+// a Separator if necessary. Join calls Clean on the result; 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.
@@ -223,14 +222,16 @@ func Ext(path string) string {
 // links.
 // If path is relative the result will be relative to the current directory,
 // unless one of the components is an absolute symbolic link.
+// EvalSymlinks calls Clean on the result.
 func EvalSymlinks(path string) (string, error) {
 	return evalSymlinks(path)
 }
 
 // Abs returns an absolute representation of path.
 // If the path is not absolute it will be joined with the current
-// working directory to turn it into an absolute path.  The absolute
+// working directory to turn it into an absolute path. The absolute
 // path name for a given file is not guaranteed to be unique.
+// Abs calls Clean on the result.
 func Abs(path string) (string, error) {
 	return abs(path)
 }
@@ -253,6 +254,7 @@ func unixAbs(path string) (string, error) {
 // even if basepath and targpath share no elements.
 // An error is returned if targpath can't be made relative to basepath or if
 // knowing the current working directory would be necessary to compute it.
+// Rel calls Clean on the result.
 func Rel(basepath, targpath string) (string, error) {
 	baseVol := VolumeName(basepath)
 	targVol := VolumeName(targpath)
@@ -442,7 +444,7 @@ func Base(path string) string {
 }
 
 // Dir returns all but the last element of path, typically the path's directory.
-// After dropping the final element, the path is Cleaned and trailing
+// After dropping the final element, Dir calls Clean on the path and trailing
 // slashes are removed.
 // If the path is empty, Dir returns ".".
 // If the path consists entirely of separators, Dir returns a single separator.
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index baeee97..1a4a9d2 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -449,7 +449,7 @@ func TestWalk(t *testing.T) {
 	checkMarks(t, true)
 	errors = errors[0:0]
 
-	// Test permission errors.  Only possible if we're not root
+	// Test permission errors. Only possible if we're not root
 	// and only on some file systems (AFS, FAT).  To avoid errors during
 	// all.bash on those file systems, skip during go test -short.
 	if os.Getuid() > 0 && !testing.Short() {
@@ -1015,7 +1015,7 @@ func TestAbs(t *testing.T) {
 		vol := filepath.VolumeName(root)
 		var extra []string
 		for _, path := range absTests {
-			if strings.Index(path, "$") != -1 {
+			if strings.Contains(path, "$") {
 				continue
 			}
 			path = vol + path
diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go
index ef6e7ca..41c57df 100644
--- a/src/path/filepath/path_windows.go
+++ b/src/path/filepath/path_windows.go
@@ -121,7 +121,7 @@ func join(elem []string) string {
 // joinNonEmpty is like join, but it assumes that the first element is non-empty.
 func joinNonEmpty(elem []string) string {
 	if len(elem[0]) == 2 && elem[0][1] == ':' {
-		// First element is drive leter without terminating slash.
+		// First element is drive letter without terminating slash.
 		// Keep path relative to current directory on that drive.
 		return Clean(elem[0] + strings.Join(elem[1:], string(Separator)))
 	}
diff --git a/src/path/filepath/path_windows_test.go b/src/path/filepath/path_windows_test.go
index 255c894..b47cdfd 100644
--- a/src/path/filepath/path_windows_test.go
+++ b/src/path/filepath/path_windows_test.go
@@ -5,6 +5,8 @@
 package filepath_test
 
 import (
+	"flag"
+	"fmt"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -174,3 +176,162 @@ func TestEvalSymlinksCanonicalNames(t *testing.T) {
 		}
 	}
 }
+
+// checkVolume8dot3Setting runs "fsutil 8dot3name query c:" command
+// (where c: is vol parameter) to discover "8dot3 name creation state".
+// The state is combination of 2 flags. The global flag controls if it
+// is per volume or global setting:
+//   0 - Enable 8dot3 name creation on all volumes on the system
+//   1 - Disable 8dot3 name creation on all volumes on the system
+//   2 - Set 8dot3 name creation on a per volume basis
+//   3 - Disable 8dot3 name creation on all volumes except the system volume
+// If global flag is set to 2, then per-volume flag needs to be examined:
+//   0 - Enable 8dot3 name creation on this volume
+//   1 - Disable 8dot3 name creation on this volume
+// checkVolume8dot3Setting verifies that "8dot3 name creation" flags
+// are set to 2 and 0, if enabled parameter is true, or 2 and 1, if enabled
+// is false. Otherwise checkVolume8dot3Setting returns error.
+func checkVolume8dot3Setting(vol string, enabled bool) error {
+	// It appears, on some systems "fsutil 8dot3name query ..." command always
+	// exits with error. Ignore exit code, and look at fsutil output instead.
+	out, _ := exec.Command("fsutil", "8dot3name", "query", vol).CombinedOutput()
+	// Check that system has "Volume level setting" set.
+	expected := "The registry state of NtfsDisable8dot3NameCreation is 2, the default (Volume level setting)"
+	if !strings.Contains(string(out), expected) {
+		// Windows 10 version of fsutil has different output message.
+		expectedWindow10 := "The registry state is: 2 (Per volume setting - the default)"
+		if !strings.Contains(string(out), expectedWindow10) {
+			return fmt.Errorf("fsutil output should contain %q, but is %q", expected, string(out))
+		}
+	}
+	// Now check the volume setting.
+	expected = "Based on the above two settings, 8dot3 name creation is %s on %s"
+	if enabled {
+		expected = fmt.Sprintf(expected, "enabled", vol)
+	} else {
+		expected = fmt.Sprintf(expected, "disabled", vol)
+	}
+	if !strings.Contains(string(out), expected) {
+		return fmt.Errorf("unexpected fsutil output: %q", string(out))
+	}
+	return nil
+}
+
+func setVolume8dot3Setting(vol string, enabled bool) error {
+	cmd := []string{"fsutil", "8dot3name", "set", vol}
+	if enabled {
+		cmd = append(cmd, "0")
+	} else {
+		cmd = append(cmd, "1")
+	}
+	// It appears, on some systems "fsutil 8dot3name set ..." command always
+	// exits with error. Ignore exit code, and look at fsutil output instead.
+	out, _ := exec.Command(cmd[0], cmd[1:]...).CombinedOutput()
+	if string(out) != "\r\nSuccessfully set 8dot3name behavior.\r\n" {
+		// Windows 10 version of fsutil has different output message.
+		expectedWindow10 := "Successfully %s 8dot3name generation on %s\r\n"
+		if enabled {
+			expectedWindow10 = fmt.Sprintf(expectedWindow10, "enabled", vol)
+		} else {
+			expectedWindow10 = fmt.Sprintf(expectedWindow10, "disabled", vol)
+		}
+		if string(out) != expectedWindow10 {
+			return fmt.Errorf("%v command failed: %q", cmd, string(out))
+		}
+	}
+	return nil
+}
+
+var runFSModifyTests = flag.Bool("run_fs_modify_tests", false, "run tests which modify filesystem parameters")
+
+// This test assumes registry state of NtfsDisable8dot3NameCreation is 2,
+// the default (Volume level setting).
+func TestEvalSymlinksCanonicalNamesWith8dot3Disabled(t *testing.T) {
+	if !*runFSModifyTests {
+		t.Skip("skipping test that modifies file system setting; enable with -run_fs_modify_tests")
+	}
+	tempVol := filepath.VolumeName(os.TempDir())
+	if len(tempVol) != 2 {
+		t.Fatalf("unexpected temp volume name %q", tempVol)
+	}
+
+	err := checkVolume8dot3Setting(tempVol, true)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = setVolume8dot3Setting(tempVol, false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		err := setVolume8dot3Setting(tempVol, true)
+		if err != nil {
+			t.Fatal(err)
+		}
+		err = checkVolume8dot3Setting(tempVol, true)
+		if err != nil {
+			t.Fatal(err)
+		}
+	}()
+	err = checkVolume8dot3Setting(tempVol, false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	TestEvalSymlinksCanonicalNames(t)
+}
+
+func TestToNorm(t *testing.T) {
+	stubBase := func(path string) (string, error) {
+		vol := filepath.VolumeName(path)
+		path = path[len(vol):]
+
+		if strings.Contains(path, "/") {
+			return "", fmt.Errorf("invalid path is given to base: %s", vol+path)
+		}
+
+		if path == "" || path == "." || path == `\` {
+			return "", fmt.Errorf("invalid path is given to base: %s", vol+path)
+		}
+
+		i := strings.LastIndexByte(path, filepath.Separator)
+		if i == len(path)-1 { // trailing '\' is invalid
+			return "", fmt.Errorf("invalid path is given to base: %s", vol+path)
+		}
+		if i == -1 {
+			return strings.ToUpper(path), nil
+		}
+
+		return strings.ToUpper(path[i+1:]), nil
+	}
+
+	// On this test, toNorm should be same as string.ToUpper(filepath.Clean(path)) except empty string.
+	tests := []struct {
+		arg  string
+		want string
+	}{
+		{"", ""},
+		{".", "."},
+		{"./foo/bar", `FOO\BAR`},
+		{"/", `\`},
+		{"/foo/bar", `\FOO\BAR`},
+		{"/foo/bar/baz/qux", `\FOO\BAR\BAZ\QUX`},
+		{"foo/bar", `FOO\BAR`},
+		{"C:/foo/bar", `C:\FOO\BAR`},
+		{"C:foo/bar", `C:FOO\BAR`},
+		{"c:/foo/bar", `C:\FOO\BAR`},
+		{"C:/foo/bar", `C:\FOO\BAR`},
+		{"C:/foo/bar/", `C:\FOO\BAR`},
+		{`C:\foo\bar`, `C:\FOO\BAR`},
+		{`C:\foo/bar\`, `C:\FOO\BAR`},
+		{"C:/ふー/バー", `C:\ふー\バー`},
+	}
+
+	for _, test := range tests {
+		got, err := filepath.ToNorm(test.arg, stubBase)
+		if err != nil {
+			t.Errorf("unexpected toNorm error, arg: %s, err: %v\n", test.arg, err)
+		} else if got != test.want {
+			t.Errorf("toNorm error, arg: %s, want: %s, got: %s\n", test.arg, test.want, got)
+		}
+	}
+}
diff --git a/src/path/filepath/symlink.go b/src/path/filepath/symlink.go
index bc287c5..f627a94 100644
--- a/src/path/filepath/symlink.go
+++ b/src/path/filepath/symlink.go
@@ -100,7 +100,7 @@ func walkSymlinks(path string) (string, error) {
 			return "", err
 		}
 		if runtime.GOOS == "windows" {
-			// walkLinks(".", ...) always retuns "." on unix.
+			// walkLinks(".", ...) always returns "." on unix.
 			// But on windows it returns symlink target, if current
 			// directory is a symlink. Stop the walk, if symlink
 			// target is not absolute path, and return "."
diff --git a/src/path/filepath/symlink_windows.go b/src/path/filepath/symlink_windows.go
index eb48367..2433528 100644
--- a/src/path/filepath/symlink_windows.go
+++ b/src/path/filepath/symlink_windows.go
@@ -5,45 +5,82 @@
 package filepath
 
 import (
+	"strings"
 	"syscall"
 )
 
-func toShort(path string) (string, error) {
-	p, err := syscall.UTF16FromString(path)
+// normVolumeName is like VolumeName, but makes drive letter upper case.
+// result of EvalSymlinks must be unique, so we have
+// EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
+func normVolumeName(path string) string {
+	volume := VolumeName(path)
+
+	if len(volume) > 2 { // isUNC
+		return volume
+	}
+
+	return strings.ToUpper(volume)
+}
+
+// normBase retruns the last element of path.
+func normBase(path string) (string, error) {
+	p, err := syscall.UTF16PtrFromString(path)
 	if err != nil {
 		return "", err
 	}
-	b := p // GetShortPathName says we can reuse buffer
-	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)
-	}
-}
 
-func toLong(path string) (string, error) {
-	p, err := syscall.UTF16FromString(path)
+	var data syscall.Win32finddata
+
+	h, err := syscall.FindFirstFile(p, &data)
 	if err != nil {
 		return "", err
 	}
-	b := p // GetLongPathName says we can reuse buffer
-	n := uint32(len(b))
+	syscall.FindClose(h)
+
+	return syscall.UTF16ToString(data.FileName[:]), nil
+}
+
+func toNorm(path string, base func(string) (string, error)) (string, error) {
+	if path == "" {
+		return path, nil
+	}
+
+	path = Clean(path)
+
+	volume := normVolumeName(path)
+	path = path[len(volume):]
+
+	// skip special cases
+	if path == "." || path == `\` {
+		return volume + path, nil
+	}
+
+	var normPath string
+
 	for {
-		n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
+		name, err := base(volume + path)
 		if err != nil {
 			return "", err
 		}
-		if n <= uint32(len(b)) {
-			return syscall.UTF16ToString(b[:n]), nil
+
+		normPath = name + `\` + normPath
+
+		i := strings.LastIndexByte(path, Separator)
+		if i == -1 {
+			break
+		}
+		if i == 0 { // `\Go` or `C:\Go`
+			normPath = `\` + normPath
+
+			break
 		}
-		b = make([]uint16, n)
+
+		path = path[:i]
 	}
+
+	normPath = normPath[:len(normPath)-1] // remove trailing '\'
+
+	return volume + normPath, nil
 }
 
 func evalSymlinks(path string) (string, error) {
@@ -51,20 +88,5 @@ func evalSymlinks(path string) (string, error) {
 	if err != nil {
 		return "", err
 	}
-	p, err := toShort(path)
-	if err != nil {
-		return "", err
-	}
-	p, err = toLong(p)
-	if err != nil {
-		return "", err
-	}
-	// syscall.GetLongPathName does not change the case of the drive letter,
-	// but the result of EvalSymlinks must be unique, so we have
-	// EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
-	// Make drive letter upper case.
-	if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' {
-		p = string(p[0]+'A'-'a') + p[1:]
-	}
-	return Clean(p), nil
+	return toNorm(path, normBase)
 }
diff --git a/src/path/match.go b/src/path/match.go
index 75dd3b3..8d9aa51 100644
--- a/src/path/match.go
+++ b/src/path/match.go
@@ -43,7 +43,7 @@ Pattern:
 		star, chunk, pattern = scanChunk(pattern)
 		if star && chunk == "" {
 			// Trailing * matches rest of string unless it has a /.
-			return strings.Index(name, "/") < 0, nil
+			return !strings.Contains(name, "/"), nil
 		}
 		// Look for match at current position.
 		t, ok, err := matchChunk(chunk, name)
diff --git a/src/path/path.go b/src/path/path.go
index 01071a9..c1d4d8a 100644
--- a/src/path/path.go
+++ b/src/path/path.go
@@ -48,7 +48,7 @@ func (b *lazybuf) string() string {
 }
 
 // Clean returns the shortest path name equivalent to path
-// by purely lexical processing.  It applies the following rules
+// by purely lexical processing. It applies the following rules
 // iteratively until no further processing can be done:
 //
 //	1. Replace multiple slashes with a single slash.
@@ -65,7 +65,7 @@ func (b *lazybuf) string() string {
 //
 // See also Rob Pike, ``Lexical File Names in Plan 9 or
 // Getting Dot-Dot Right,''
-// http://plan9.bell-labs.com/sys/doc/lexnames.html
+// https://9p.io/sys/doc/lexnames.html
 func Clean(path string) string {
 	if path == "" {
 		return "."
diff --git a/src/path/path_test.go b/src/path/path_test.go
index 13b5852..85b2450 100644
--- a/src/path/path_test.go
+++ b/src/path/path_test.go
@@ -135,15 +135,9 @@ var jointests = []JoinTest{
 	{[]string{"", ""}, ""},
 }
 
-// join takes a []string and passes it to Join.
-func join(elem []string, args ...string) string {
-	args = elem
-	return Join(args...)
-}
-
 func TestJoin(t *testing.T) {
 	for _, test := range jointests {
-		if p := join(test.elem); p != test.path {
+		if p := Join(test.elem...); p != test.path {
 			t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
 		}
 	}
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index c80df34..adde582 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -21,6 +21,8 @@ import (
 	"sync"
 	"testing"
 	"time"
+	"unicode"
+	"unicode/utf8"
 	"unsafe"
 )
 
@@ -44,16 +46,12 @@ type pair struct {
 	s string
 }
 
-func isDigit(c uint8) bool { return '0' <= c && c <= '9' }
-
 func assert(t *testing.T, s, want string) {
 	if s != want {
 		t.Errorf("have %#q want %#q", s, want)
 	}
 }
 
-func typestring(i interface{}) string { return TypeOf(i).String() }
-
 var typeTests = []pair{
 	{struct{ x int }{}, "int"},
 	{struct{ x int8 }{}, "int8"},
@@ -1478,6 +1476,12 @@ func TestFunc(t *testing.T) {
 	if i != 10 || j != 20 || k != 30 || l != (two{40, 50}) || m != 60 || n != 70 || o != 80 {
 		t.Errorf("Call returned %d, %d, %d, %v, %d, %g, %d; want 10, 20, 30, [40, 50], 60, 70, 80", i, j, k, l, m, n, o)
 	}
+
+	for i, v := range ret {
+		if v.CanAddr() {
+			t.Errorf("result %d is addressable", i)
+		}
+	}
 }
 
 type emptyStruct struct{}
@@ -1885,32 +1889,6 @@ type Tbigp [2]uintptr
 
 func (p *Tbigp) M(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) }
 
-// Again, with an unexported method.
-
-type tsmallv byte
-
-func (v tsmallv) m(x int, b byte) (byte, int) { return b, x + int(v) }
-
-type tsmallp byte
-
-func (p *tsmallp) m(x int, b byte) (byte, int) { return b, x + int(*p) }
-
-type twordv uintptr
-
-func (v twordv) m(x int, b byte) (byte, int) { return b, x + int(v) }
-
-type twordp uintptr
-
-func (p *twordp) m(x int, b byte) (byte, int) { return b, x + int(*p) }
-
-type tbigv [2]uintptr
-
-func (v tbigv) m(x int, b byte) (byte, int) { return b, x + int(v[0]) + int(v[1]) }
-
-type tbigp [2]uintptr
-
-func (p *tbigp) m(x int, b byte) (byte, int) { return b, x + int(p[0]) + int(p[1]) }
-
 type tinter interface {
 	m(int, byte) (byte, int)
 }
@@ -1954,7 +1932,6 @@ func TestMethod5(t *testing.T) {
 	}
 
 	var TinterType = TypeOf(new(Tinter)).Elem()
-	var tinterType = TypeOf(new(tinter)).Elem()
 
 	CheckI := func(name string, i interface{}, inc int) {
 		v := ValueOf(i)
@@ -1996,39 +1973,6 @@ func TestMethod5(t *testing.T) {
 	CheckI("t1", t1, 40)
 	CheckI("&t1", &t1, 40)
 
-	methodShouldPanic := func(name string, i interface{}) {
-		v := ValueOf(i)
-		m := v.Method(0)
-		shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) })
-		shouldPanic(func() { m.Interface() })
-
-		v = v.Convert(tinterType)
-		m = v.Method(0)
-		shouldPanic(func() { m.Call([]Value{ValueOf(1000), ValueOf(byte(99))}) })
-		shouldPanic(func() { m.Interface() })
-	}
-
-	_sv := tsmallv(1)
-	methodShouldPanic("_sv", _sv)
-	methodShouldPanic("&_sv", &_sv)
-
-	_sp := tsmallp(2)
-	methodShouldPanic("&_sp", &_sp)
-
-	_wv := twordv(3)
-	methodShouldPanic("_wv", _wv)
-	methodShouldPanic("&_wv", &_wv)
-
-	_wp := twordp(4)
-	methodShouldPanic("&_wp", &_wp)
-
-	_bv := tbigv([2]uintptr{5, 6})
-	methodShouldPanic("_bv", _bv)
-	methodShouldPanic("&_bv", &_bv)
-
-	_bp := tbigp([2]uintptr{7, 8})
-	methodShouldPanic("&_bp", &_bp)
-
 	var tnil Tinter
 	vnil := ValueOf(&tnil).Elem()
 	shouldPanic(func() { vnil.Method(0) })
@@ -2325,6 +2269,33 @@ func TestImportPath(t *testing.T) {
 	}
 }
 
+func TestFieldPkgPath(t *testing.T) {
+	typ := TypeOf(struct {
+		Exported   string
+		unexported string
+		OtherPkgFields
+	}{})
+	for _, test := range []struct {
+		index     []int
+		pkgPath   string
+		anonymous bool
+	}{
+		{[]int{0}, "", false},             // Exported
+		{[]int{1}, "reflect_test", false}, // unexported
+		{[]int{2}, "", true},              // OtherPkgFields
+		{[]int{2, 0}, "", false},          // OtherExported
+		{[]int{2, 1}, "reflect", false},   // otherUnexported
+	} {
+		f := typ.FieldByIndex(test.index)
+		if got, want := f.PkgPath, test.pkgPath; got != want {
+			t.Errorf("Field(%d).PkgPath = %q, want %q", test.index, got, want)
+		}
+		if got, want := f.Anonymous, test.anonymous; got != want {
+			t.Errorf("Field(%d).Anonymous = %v, want %v", test.index, got, want)
+		}
+	}
+}
+
 func TestVariadicType(t *testing.T) {
 	// Test example from Type documentation.
 	var f func(x int, y ...float64)
@@ -2357,13 +2328,13 @@ type outer struct {
 	inner
 }
 
-func (*inner) m() {}
-func (*outer) m() {}
+func (*inner) M() {}
+func (*outer) M() {}
 
 func TestNestedMethods(t *testing.T) {
 	typ := TypeOf((*outer)(nil))
-	if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).m).Pointer() {
-		t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
+	if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != ValueOf((*outer).M).Pointer() {
+		t.Errorf("Wrong method table for outer: (M=%p)", (*outer).M)
 		for i := 0; i < typ.NumMethod(); i++ {
 			m := typ.Method(i)
 			t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
@@ -2371,6 +2342,25 @@ func TestNestedMethods(t *testing.T) {
 	}
 }
 
+type unexp struct{}
+
+func (*unexp) f() (int32, int8) { return 7, 7 }
+func (*unexp) g() (int64, int8) { return 8, 8 }
+
+type unexpI interface {
+	f() (int32, int8)
+}
+
+var unexpi unexpI = new(unexp)
+
+func TestUnexportedMethods(t *testing.T) {
+	typ := TypeOf(unexpi)
+
+	if got := typ.NumMethod(); got != 0 {
+		t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
+	}
+}
+
 type InnerInt struct {
 	X int
 }
@@ -2410,6 +2400,17 @@ func TestEmbeddedMethods(t *testing.T) {
 	}
 }
 
+type FuncDDD func(...interface{}) error
+
+func (f FuncDDD) M() {}
+
+func TestNumMethodOnDDD(t *testing.T) {
+	rv := ValueOf((FuncDDD)(nil))
+	if n := rv.NumMethod(); n != 1 {
+		t.Fatalf("NumMethod()=%d, want 1", n)
+	}
+}
+
 func TestPtrTo(t *testing.T) {
 	var i int
 
@@ -2848,12 +2849,11 @@ func TestUnexported(t *testing.T) {
 	isValid(v.Elem().Field(1))
 	isValid(v.Elem().FieldByName("x"))
 	isValid(v.Elem().FieldByName("y"))
-	isValid(v.Type().Method(0).Func)
 	shouldPanic(func() { v.Elem().Field(0).Interface() })
 	shouldPanic(func() { v.Elem().Field(1).Interface() })
 	shouldPanic(func() { v.Elem().FieldByName("x").Interface() })
 	shouldPanic(func() { v.Elem().FieldByName("y").Interface() })
-	shouldPanic(func() { v.Type().Method(0).Func.Interface() })
+	shouldPanic(func() { v.Type().Method(0) })
 }
 
 func TestSetPanic(t *testing.T) {
@@ -3832,6 +3832,9 @@ func TestSliceOf(t *testing.T) {
 	// check construction and use of type not in binary
 	type T int
 	st := SliceOf(TypeOf(T(1)))
+	if got, want := st.String(), "[]reflect_test.T"; got != want {
+		t.Errorf("SliceOf(T(1)).String()=%q, want %q", got, want)
+	}
 	v := MakeSlice(st, 10, 10)
 	runtime.GC()
 	for i := 0; i < v.Len(); i++ {
@@ -3896,6 +3899,583 @@ func TestSliceOfGC(t *testing.T) {
 	}
 }
 
+func TestStructOf(t *testing.T) {
+	// check construction and use of type not in binary
+	fields := []StructField{
+		StructField{
+			Name: "S",
+			Tag:  "s",
+			Type: TypeOf(""),
+		},
+		StructField{
+			Name: "X",
+			Tag:  "x",
+			Type: TypeOf(byte(0)),
+		},
+		StructField{
+			Name: "Y",
+			Type: TypeOf(uint64(0)),
+		},
+		StructField{
+			Name: "Z",
+			Type: TypeOf([3]uint16{}),
+		},
+	}
+
+	st := StructOf(fields)
+	v := New(st).Elem()
+	runtime.GC()
+	v.FieldByName("X").Set(ValueOf(byte(2)))
+	v.FieldByIndex([]int{1}).Set(ValueOf(byte(1)))
+	runtime.GC()
+
+	s := fmt.Sprint(v.Interface())
+	want := `{ 1 0 [0 0 0]}`
+	if s != want {
+		t.Errorf("constructed struct = %s, want %s", s, want)
+	}
+	const stStr = `struct { S string "s"; X uint8 "x"; Y uint64; Z [3]uint16 }`
+	if got, want := st.String(), stStr; got != want {
+		t.Errorf("StructOf(fields).String()=%q, want %q", got, want)
+	}
+
+	// check the size, alignment and field offsets
+	stt := TypeOf(struct {
+		String string
+		X      byte
+		Y      uint64
+		Z      [3]uint16
+	}{})
+	if st.Size() != stt.Size() {
+		t.Errorf("constructed struct size = %v, want %v", st.Size(), stt.Size())
+	}
+	if st.Align() != stt.Align() {
+		t.Errorf("constructed struct align = %v, want %v", st.Align(), stt.Align())
+	}
+	if st.FieldAlign() != stt.FieldAlign() {
+		t.Errorf("constructed struct field align = %v, want %v", st.FieldAlign(), stt.FieldAlign())
+	}
+	for i := 0; i < st.NumField(); i++ {
+		o1 := st.Field(i).Offset
+		o2 := stt.Field(i).Offset
+		if o1 != o2 {
+			t.Errorf("constructed struct field %v offset = %v, want %v", i, o1, o2)
+		}
+	}
+
+	// check duplicate names
+	shouldPanic(func() {
+		StructOf([]StructField{
+			StructField{Name: "string", Type: TypeOf("")},
+			StructField{Name: "string", Type: TypeOf("")},
+		})
+	})
+	shouldPanic(func() {
+		StructOf([]StructField{
+			StructField{Type: TypeOf("")},
+			StructField{Name: "string", Type: TypeOf("")},
+		})
+	})
+	shouldPanic(func() {
+		StructOf([]StructField{
+			StructField{Type: TypeOf("")},
+			StructField{Type: TypeOf("")},
+		})
+	})
+	// check that type already in binary is found
+	checkSameType(t, Zero(StructOf(fields[2:3])).Interface(), struct{ Y uint64 }{})
+}
+
+func TestStructOfExportRules(t *testing.T) {
+	type S1 struct{}
+	type s2 struct{}
+	type ΦType struct{}
+	type φType struct{}
+
+	testPanic := func(i int, mustPanic bool, f func()) {
+		defer func() {
+			err := recover()
+			if err == nil && mustPanic {
+				t.Errorf("test-%d did not panic", i)
+			}
+			if err != nil && !mustPanic {
+				t.Errorf("test-%d panicked: %v\n", i, err)
+			}
+		}()
+		f()
+	}
+
+	for i, test := range []struct {
+		field     StructField
+		mustPanic bool
+		exported  bool
+	}{
+		{
+			field:     StructField{Name: "", Type: TypeOf(S1{})},
+			mustPanic: false,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "", Type: TypeOf((*S1)(nil))},
+			mustPanic: false,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "", Type: TypeOf(s2{})},
+			mustPanic: false,
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "", Type: TypeOf((*s2)(nil))},
+			mustPanic: false,
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+			mustPanic: true,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+			mustPanic: true,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+			mustPanic: true,
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+			mustPanic: true,
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "S", Type: TypeOf(S1{})},
+			mustPanic: false,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "S", Type: TypeOf((*S1)(nil))},
+			mustPanic: false,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "S", Type: TypeOf(s2{})},
+			mustPanic: false,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "S", Type: TypeOf((*s2)(nil))},
+			mustPanic: false,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "s", Type: TypeOf(S1{})},
+			mustPanic: true,
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "s", Type: TypeOf((*S1)(nil))},
+			mustPanic: true,
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "s", Type: TypeOf(s2{})},
+			mustPanic: true,
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "s", Type: TypeOf((*s2)(nil))},
+			mustPanic: true,
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "s", Type: TypeOf(S1{}), PkgPath: "other/pkg"},
+			mustPanic: true, // TODO(sbinet): creating a name with a package path
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "s", Type: TypeOf((*S1)(nil)), PkgPath: "other/pkg"},
+			mustPanic: true, // TODO(sbinet): creating a name with a package path
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "s", Type: TypeOf(s2{}), PkgPath: "other/pkg"},
+			mustPanic: true, // TODO(sbinet): creating a name with a package path
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "s", Type: TypeOf((*s2)(nil)), PkgPath: "other/pkg"},
+			mustPanic: true, // TODO(sbinet): creating a name with a package path
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "", Type: TypeOf(ΦType{})},
+			mustPanic: false,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "", Type: TypeOf(φType{})},
+			mustPanic: false,
+			exported:  false,
+		},
+		{
+			field:     StructField{Name: "Φ", Type: TypeOf(0)},
+			mustPanic: false,
+			exported:  true,
+		},
+		{
+			field:     StructField{Name: "φ", Type: TypeOf(0)},
+			mustPanic: false,
+			exported:  false,
+		},
+	} {
+		testPanic(i, test.mustPanic, func() {
+			typ := StructOf([]StructField{test.field})
+			if typ == nil {
+				t.Errorf("test-%d: error creating struct type", i)
+				return
+			}
+			field := typ.Field(0)
+			n := field.Name
+			if n == "" {
+				n = field.Type.Name()
+			}
+			exported := isExported(n)
+			if exported != test.exported {
+				t.Errorf("test-%d: got exported=%v want exported=%v", i, exported, test.exported)
+			}
+		})
+	}
+}
+
+// isExported reports whether name is an exported Go symbol
+// (that is, whether it begins with an upper-case letter).
+//
+func isExported(name string) bool {
+	ch, _ := utf8.DecodeRuneInString(name)
+	return unicode.IsUpper(ch)
+}
+
+func TestStructOfGC(t *testing.T) {
+	type T *uintptr
+	tt := TypeOf(T(nil))
+	fields := []StructField{
+		{Name: "X", Type: tt},
+		{Name: "Y", Type: tt},
+	}
+	st := StructOf(fields)
+
+	const n = 10000
+	var x []interface{}
+	for i := 0; i < n; i++ {
+		v := New(st).Elem()
+		for j := 0; j < v.NumField(); j++ {
+			p := new(uintptr)
+			*p = uintptr(i*n + j)
+			v.Field(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.NumField(); j++ {
+			k := v.Field(j).Elem().Interface()
+			if k != uintptr(i*n+j) {
+				t.Errorf("lost x[%d].%c = %d, want %d", i, "XY"[j], k, i*n+j)
+			}
+		}
+	}
+}
+
+func TestStructOfAlg(t *testing.T) {
+	st := StructOf([]StructField{{Name: "X", Tag: "x", Type: TypeOf(int(0))}})
+	v1 := New(st).Elem()
+	v2 := New(st).Elem()
+	if !DeepEqual(v1.Interface(), v1.Interface()) {
+		t.Errorf("constructed struct %v not equal to itself", v1.Interface())
+	}
+	v1.FieldByName("X").Set(ValueOf(int(1)))
+	if i1, i2 := v1.Interface(), v2.Interface(); DeepEqual(i1, i2) {
+		t.Errorf("constructed structs %v and %v should not be equal", i1, i2)
+	}
+
+	st = StructOf([]StructField{{Name: "X", Tag: "x", Type: TypeOf([]int(nil))}})
+	v1 = New(st).Elem()
+	shouldPanic(func() { _ = v1.Interface() == v1.Interface() })
+}
+
+func TestStructOfGenericAlg(t *testing.T) {
+	st1 := StructOf([]StructField{
+		{Name: "X", Tag: "x", Type: TypeOf(int64(0))},
+		{Name: "Y", Type: TypeOf(string(""))},
+	})
+	st := StructOf([]StructField{
+		{Name: "S0", Type: st1},
+		{Name: "S1", Type: st1},
+	})
+
+	for _, table := range []struct {
+		rt  Type
+		idx []int
+	}{
+		{
+			rt:  st,
+			idx: []int{0, 1},
+		},
+		{
+			rt:  st1,
+			idx: []int{1},
+		},
+		{
+			rt: StructOf(
+				[]StructField{
+					{Name: "XX", Type: TypeOf([0]int{})},
+					{Name: "YY", Type: TypeOf("")},
+				},
+			),
+			idx: []int{1},
+		},
+		{
+			rt: StructOf(
+				[]StructField{
+					{Name: "XX", Type: TypeOf([0]int{})},
+					{Name: "YY", Type: TypeOf("")},
+					{Name: "ZZ", Type: TypeOf([2]int{})},
+				},
+			),
+			idx: []int{1},
+		},
+		{
+			rt: StructOf(
+				[]StructField{
+					{Name: "XX", Type: TypeOf([1]int{})},
+					{Name: "YY", Type: TypeOf("")},
+				},
+			),
+			idx: []int{1},
+		},
+		{
+			rt: StructOf(
+				[]StructField{
+					{Name: "XX", Type: TypeOf([1]int{})},
+					{Name: "YY", Type: TypeOf("")},
+					{Name: "ZZ", Type: TypeOf([1]int{})},
+				},
+			),
+			idx: []int{1},
+		},
+		{
+			rt: StructOf(
+				[]StructField{
+					{Name: "XX", Type: TypeOf([2]int{})},
+					{Name: "YY", Type: TypeOf("")},
+					{Name: "ZZ", Type: TypeOf([2]int{})},
+				},
+			),
+			idx: []int{1},
+		},
+		{
+			rt: StructOf(
+				[]StructField{
+					{Name: "XX", Type: TypeOf(int64(0))},
+					{Name: "YY", Type: TypeOf(byte(0))},
+					{Name: "ZZ", Type: TypeOf("")},
+				},
+			),
+			idx: []int{2},
+		},
+		{
+			rt: StructOf(
+				[]StructField{
+					{Name: "XX", Type: TypeOf(int64(0))},
+					{Name: "YY", Type: TypeOf(int64(0))},
+					{Name: "ZZ", Type: TypeOf("")},
+					{Name: "AA", Type: TypeOf([1]int64{})},
+				},
+			),
+			idx: []int{2},
+		},
+	} {
+		v1 := New(table.rt).Elem()
+		v2 := New(table.rt).Elem()
+
+		if !DeepEqual(v1.Interface(), v1.Interface()) {
+			t.Errorf("constructed struct %v not equal to itself", v1.Interface())
+		}
+
+		v1.FieldByIndex(table.idx).Set(ValueOf("abc"))
+		v2.FieldByIndex(table.idx).Set(ValueOf("def"))
+		if i1, i2 := v1.Interface(), v2.Interface(); DeepEqual(i1, i2) {
+			t.Errorf("constructed structs %v and %v should not be equal", i1, i2)
+		}
+
+		abc := "abc"
+		v1.FieldByIndex(table.idx).Set(ValueOf(abc))
+		val := "+" + abc + "-"
+		v2.FieldByIndex(table.idx).Set(ValueOf(val[1:4]))
+		if i1, i2 := v1.Interface(), v2.Interface(); !DeepEqual(i1, i2) {
+			t.Errorf("constructed structs %v and %v should be equal", i1, i2)
+		}
+
+		// Test hash
+		m := MakeMap(MapOf(table.rt, TypeOf(int(0))))
+		m.SetMapIndex(v1, ValueOf(1))
+		if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() {
+			t.Errorf("constructed structs %#v and %#v have different hashes", i1, i2)
+		}
+
+		v2.FieldByIndex(table.idx).Set(ValueOf("abc"))
+		if i1, i2 := v1.Interface(), v2.Interface(); !DeepEqual(i1, i2) {
+			t.Errorf("constructed structs %v and %v should be equal", i1, i2)
+		}
+
+		if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() {
+			t.Errorf("constructed structs %v and %v have different hashes", i1, i2)
+		}
+	}
+}
+
+func TestStructOfDirectIface(t *testing.T) {
+	{
+		type T struct{ X [1]*byte }
+		i1 := Zero(TypeOf(T{})).Interface()
+		v1 := ValueOf(&i1).Elem()
+		p1 := v1.InterfaceData()[1]
+
+		i2 := Zero(StructOf([]StructField{
+			{
+				Name: "X",
+				Type: ArrayOf(1, TypeOf((*int8)(nil))),
+			},
+		})).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 struct{ X [0]*byte }
+		i1 := Zero(TypeOf(T{})).Interface()
+		v1 := ValueOf(&i1).Elem()
+		p1 := v1.InterfaceData()[1]
+
+		i2 := Zero(StructOf([]StructField{
+			{
+				Name: "X",
+				Type: ArrayOf(0, TypeOf((*int8)(nil))),
+			},
+		})).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)
+		}
+	}
+}
+
+type StructI int
+
+func (i StructI) Get() int { return int(i) }
+
+type StructIPtr int
+
+func (i *StructIPtr) Get() int { return int(*i) }
+
+func TestStructOfWithInterface(t *testing.T) {
+	const want = 42
+	type Iface interface {
+		Get() int
+	}
+	for i, table := range []struct {
+		typ  Type
+		val  Value
+		impl bool
+	}{
+		{
+			typ:  TypeOf(StructI(want)),
+			val:  ValueOf(StructI(want)),
+			impl: true,
+		},
+		{
+			typ: PtrTo(TypeOf(StructI(want))),
+			val: ValueOf(func() interface{} {
+				v := StructI(want)
+				return &v
+			}()),
+			impl: true,
+		},
+		{
+			typ: PtrTo(TypeOf(StructIPtr(want))),
+			val: ValueOf(func() interface{} {
+				v := StructIPtr(want)
+				return &v
+			}()),
+			impl: true,
+		},
+		{
+			typ:  TypeOf(StructIPtr(want)),
+			val:  ValueOf(StructIPtr(want)),
+			impl: false,
+		},
+		// {
+		//	typ:  TypeOf((*Iface)(nil)).Elem(), // FIXME(sbinet): fix method.ifn/tfn
+		//	val:  ValueOf(StructI(want)),
+		//	impl: true,
+		// },
+	} {
+		rt := StructOf(
+			[]StructField{
+				{
+					Name:    "",
+					PkgPath: "",
+					Type:    table.typ,
+				},
+			},
+		)
+		rv := New(rt).Elem()
+		rv.Field(0).Set(table.val)
+
+		if _, ok := rv.Interface().(Iface); ok != table.impl {
+			if table.impl {
+				t.Errorf("test-%d: type=%v fails to implement Iface.\n", i, table.typ)
+			} else {
+				t.Errorf("test-%d: type=%v should NOT implement Iface\n", i, table.typ)
+			}
+			continue
+		}
+
+		if !table.impl {
+			continue
+		}
+
+		v := rv.Interface().(Iface).Get()
+		if v != want {
+			t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, v, want)
+		}
+
+		fct := rv.MethodByName("Get")
+		out := fct.Call(nil)
+		if !DeepEqual(out[0].Interface(), want) {
+			t.Errorf("test-%d: x.Get()=%v. want=%v\n", i, out[0].Interface(), want)
+		}
+	}
+}
+
 func TestChanOf(t *testing.T) {
 	// check construction and use of type not in binary
 	type T string
@@ -4102,7 +4682,7 @@ func TestFuncOf(t *testing.T) {
 		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("")))
+			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")
 		}
@@ -4114,7 +4694,7 @@ func TestFuncOf(t *testing.T) {
 	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)))
+		t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type(), TypeOf(V(0)))
 	}
 	f := outs[0].Float()
 	if f != 3.14 {
@@ -4465,7 +5045,7 @@ func TestFieldByIndexNil(t *testing.T) {
 // off the stack into the frame will store an *Inner there, and then if a garbage collection
 // happens to scan that argument frame before it is discarded, it will scan the *Inner
 // memory as if it were an *Outer. If the two have different memory layouts, the
-// collection will intepret the memory incorrectly.
+// collection will interpret the memory incorrectly.
 //
 // One such possible incorrect interpretation is to treat two arbitrary memory words
 // (Inner.P1 and Inner.P2 below) as an interface (Outer.R below). Because interpreting
@@ -4541,7 +5121,7 @@ func useStack(n int) {
 
 type Impl struct{}
 
-func (Impl) f() {}
+func (Impl) F() {}
 
 func TestValueString(t *testing.T) {
 	rv := ValueOf(Impl{})
@@ -4575,6 +5155,41 @@ func TestLargeGCProg(t *testing.T) {
 	fv.Call([]Value{ValueOf([256]*byte{})})
 }
 
+func fieldIndexRecover(t Type, i int) (recovered interface{}) {
+	defer func() {
+		recovered = recover()
+	}()
+
+	t.Field(i)
+	return
+}
+
+// Issue 15046.
+func TestTypeFieldOutOfRangePanic(t *testing.T) {
+	typ := TypeOf(struct{ X int }{10})
+	testIndices := [...]struct {
+		i         int
+		mustPanic bool
+	}{
+		0: {-2, true},
+		1: {0, false},
+		2: {1, true},
+		3: {1 << 10, true},
+	}
+	for i, tt := range testIndices {
+		recoveredErr := fieldIndexRecover(typ, tt.i)
+		if tt.mustPanic {
+			if recoveredErr == nil {
+				t.Errorf("#%d: fieldIndex %d expected to panic", i, tt.i)
+			}
+		} else {
+			if recoveredErr != nil {
+				t.Errorf("#%d: got err=%v, expected no panic", i, recoveredErr)
+			}
+		}
+	}
+}
+
 // Issue 9179.
 func TestCallGC(t *testing.T) {
 	f := func(a, b, c, d, e string) {
@@ -4702,7 +5317,7 @@ func init() {
 			2 * PtrSize,
 			[]byte{1},
 			[]byte{1},
-			// Note: this one is tricky, as the receiver is not a pointer.  But we
+			// 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.
 		})
@@ -4753,6 +5368,9 @@ func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) {
 	for len(bits) > 2 && bits[len(bits)-1] == 0 {
 		bits = bits[:len(bits)-1]
 	}
+	if len(bits) == 2 && bits[0] == 0 && bits[1] == 0 {
+		bits = bits[:0]
+	}
 	if !bytes.Equal(heapBits, bits) {
 		t.Errorf("heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", typ, cap, heapBits, bits)
 	}
@@ -5004,6 +5622,129 @@ func TestChanAlloc(t *testing.T) {
 		t.Errorf("allocs per chan send/recv: want 1 got %f", allocs)
 	}
 	// Note: there is one allocation in reflect.recv which seems to be
-	// a limitation of escape analysis.  If that is ever fixed the
+	// a limitation of escape analysis. If that is ever fixed the
 	// allocs < 0.5 condition will trigger and this test should be fixed.
 }
+
+type TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678 int
+
+type nameTest struct {
+	v    interface{}
+	want string
+}
+
+var nameTests = []nameTest{
+	{(*int32)(nil), "int32"},
+	{(*D1)(nil), "D1"},
+	{(*[]D1)(nil), ""},
+	{(*chan D1)(nil), ""},
+	{(*func() D1)(nil), ""},
+	{(*<-chan D1)(nil), ""},
+	{(*chan<- D1)(nil), ""},
+	{(*interface{})(nil), ""},
+	{(*interface {
+		F()
+	})(nil), ""},
+	{(*TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678)(nil), "TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_0123 [...]
+}
+
+func TestNames(t *testing.T) {
+	for _, test := range nameTests {
+		typ := TypeOf(test.v).Elem()
+		if got := typ.Name(); got != test.want {
+			t.Errorf("%v Name()=%q, want %q", typ, got, test.want)
+		}
+	}
+}
+
+func TestExported(t *testing.T) {
+	type ΦExported struct{}
+	type φUnexported struct{}
+	type BigP *big
+	type P int
+	type p *P
+	type P2 p
+	type p3 p
+
+	type exportTest struct {
+		v    interface{}
+		want bool
+	}
+	exportTests := []exportTest{
+		{D1{}, true},
+		{(*D1)(nil), true},
+		{big{}, false},
+		{(*big)(nil), false},
+		{(BigP)(nil), true},
+		{(*BigP)(nil), true},
+		{ΦExported{}, true},
+		{φUnexported{}, false},
+		{P(0), true},
+		{(p)(nil), false},
+		{(P2)(nil), true},
+		{(p3)(nil), false},
+	}
+
+	for i, test := range exportTests {
+		typ := TypeOf(test.v)
+		if got := IsExported(typ); got != test.want {
+			t.Errorf("%d: %s exported=%v, want %v", i, typ.Name(), got, test.want)
+		}
+	}
+}
+
+type embed struct {
+	EmbedWithUnexpMeth
+}
+
+func TestNameBytesAreAligned(t *testing.T) {
+	typ := TypeOf(embed{})
+	b := FirstMethodNameBytes(typ)
+	v := uintptr(unsafe.Pointer(b))
+	if v%unsafe.Alignof((*byte)(nil)) != 0 {
+		t.Errorf("reflect.name.bytes pointer is not aligned: %x", v)
+	}
+}
+
+func TestTypeStrings(t *testing.T) {
+	type stringTest struct {
+		typ  Type
+		want string
+	}
+	stringTests := []stringTest{
+		{TypeOf(func(int) {}), "func(int)"},
+		{FuncOf([]Type{TypeOf(int(0))}, nil, false), "func(int)"},
+		{TypeOf(XM{}), "reflect_test.XM"},
+		{TypeOf(new(XM)), "*reflect_test.XM"},
+		{TypeOf(new(XM).String), "func() string"},
+		{TypeOf(new(XM)).Method(0).Type, "func(*reflect_test.XM) string"},
+	}
+
+	for i, test := range stringTests {
+		if got, want := test.typ.String(), test.want; got != want {
+			t.Errorf("type %d String()=%q, want %q", i, got, want)
+		}
+	}
+}
+
+func TestOffsetLock(t *testing.T) {
+	var wg sync.WaitGroup
+	for i := 0; i < 4; i++ {
+		i := i
+		wg.Add(1)
+		go func() {
+			for j := 0; j < 50; j++ {
+				ResolveReflectName(fmt.Sprintf("OffsetLockName:%d:%d", i, j))
+			}
+			wg.Done()
+		}()
+	}
+	wg.Wait()
+}
+
+func BenchmarkNew(b *testing.B) {
+	v := TypeOf(XM{})
+	for i := 0; i < b.N; i++ {
+		New(v)
+	}
+}
diff --git a/src/reflect/asm_386.s b/src/reflect/asm_386.s
index 0ffccf7..d827360 100644
--- a/src/reflect/asm_386.s
+++ b/src/reflect/asm_386.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/reflect/asm_amd64.s b/src/reflect/asm_amd64.s
index 5a6c27a..1272c48 100644
--- a/src/reflect/asm_amd64.s
+++ b/src/reflect/asm_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/reflect/asm_amd64p32.s b/src/reflect/asm_amd64p32.s
index 0ffccf7..d827360 100644
--- a/src/reflect/asm_amd64p32.s
+++ b/src/reflect/asm_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/reflect/asm_arm.s b/src/reflect/asm_arm.s
index 5a14c6f..b721ed2 100644
--- a/src/reflect/asm_arm.s
+++ b/src/reflect/asm_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/reflect/asm_arm64.s b/src/reflect/asm_arm64.s
index bdd3843..d156370 100644
--- a/src/reflect/asm_arm64.s
+++ b/src/reflect/asm_arm64.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/reflect/asm_mips64x.s b/src/reflect/asm_mips64x.s
index 159d3d5..98afb52 100644
--- a/src/reflect/asm_mips64x.s
+++ b/src/reflect/asm_mips64x.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/reflect/asm_ppc64x.s b/src/reflect/asm_ppc64x.s
index 0fa570c..42f5774 100644
--- a/src/reflect/asm_ppc64x.s
+++ b/src/reflect/asm_ppc64x.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/reflect/asm_s390x.s b/src/reflect/asm_s390x.s
new file mode 100644
index 0000000..e6b86cf
--- /dev/null
+++ b/src/reflect/asm_s390x.s
@@ -0,0 +1,30 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "funcdata.h"
+
+// makeFuncStub is the code half of the function returned by MakeFunc.
+// See the comment on the declaration of makeFuncStub in makefunc.go
+// for more details.
+// No arg size here, runtime pulls arg map out of the func value.
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
+	NO_LOCAL_POINTERS
+	MOVD	R12, 8(R15)
+	MOVD	$argframe+0(FP), R3
+	MOVD	R3, 16(R15)
+	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	R12, 8(R15)
+	MOVD	$argframe+0(FP), R3
+	MOVD	R3, 16(R15)
+	BL	·callMethod(SB)
+	RET
diff --git a/src/reflect/deepequal.go b/src/reflect/deepequal.go
index 3743e80..9770358 100644
--- a/src/reflect/deepequal.go
+++ b/src/reflect/deepequal.go
@@ -9,7 +9,7 @@ package reflect
 import "unsafe"
 
 // During deepValueEqual, must keep track of checks that are
-// in progress.  The comparison algorithm assumes that all
+// in progress. The comparison algorithm assumes that all
 // checks in progress are true when it reencounters them.
 // Visited comparisons are stored in a map indexed by visit.
 type visit struct {
diff --git a/src/reflect/example_test.go b/src/reflect/example_test.go
index 8ebf976..9e2b9b3 100644
--- a/src/reflect/example_test.go
+++ b/src/reflect/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -67,6 +67,34 @@ func ExampleStructTag() {
 	// blue gopher
 }
 
+func ExampleStructTag_Lookup() {
+	type S struct {
+		F0 string `alias:"field_0"`
+		F1 string `alias:""`
+		F2 string
+	}
+
+	s := S{}
+	st := reflect.TypeOf(s)
+	for i := 0; i < st.NumField(); i++ {
+		field := st.Field(i)
+		if alias, ok := field.Tag.Lookup("alias"); ok {
+			if alias == "" {
+				fmt.Println("(blank)")
+			} else {
+				fmt.Println(alias)
+			}
+		} else {
+			fmt.Println("(not specified)")
+		}
+	}
+
+	// Output:
+	// field_0
+	// (blank)
+	// (not specified)
+}
+
 func ExampleTypeOf() {
 	// As interface types are only used for static typing, a
 	// common idiom to find the reflection Type for an interface
diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go
index 26a648e..2cc1530 100644
--- a/src/reflect/export_test.go
+++ b/src/reflect/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -46,9 +46,12 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr,
 
 func TypeLinks() []string {
 	var r []string
-	for _, m := range typelinks() {
-		for _, t := range m {
-			r = append(r, *t.string)
+	sections, offset := typelinks()
+	for i, offs := range offset {
+		rodata := sections[i]
+		for _, off := range offs {
+			typ := (*rtype)(resolveTypeOff(unsafe.Pointer(rodata), off))
+			r = append(r, typ.String())
 		}
 	}
 	return r
@@ -70,3 +73,43 @@ func CachedBucketOf(m Type) Type {
 	tt := (*mapType)(unsafe.Pointer(t))
 	return tt.bucket
 }
+
+type EmbedWithUnexpMeth struct{}
+
+func (EmbedWithUnexpMeth) f() {}
+
+type pinUnexpMeth interface {
+	f()
+}
+
+var pinUnexpMethI = pinUnexpMeth(EmbedWithUnexpMeth{})
+
+func FirstMethodNameBytes(t Type) *byte {
+	_ = pinUnexpMethI
+
+	ut := t.uncommon()
+	if ut == nil {
+		panic("type has no methods")
+	}
+	m := ut.methods()[0]
+	mname := t.(*rtype).nameOff(m.name)
+	if *mname.data(0)&(1<<2) == 0 {
+		panic("method name does not have pkgPath *string")
+	}
+	return mname.bytes
+}
+
+type OtherPkgFields struct {
+	OtherExported   int
+	otherUnexported int
+}
+
+func IsExported(t Type) bool {
+	typ := t.(*rtype)
+	n := typ.nameOff(typ.str)
+	return n.isExported()
+}
+
+func ResolveReflectName(s string) {
+	resolveReflectName(newName(s, "", "", false))
+}
diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go
index 032057d..ad2ebd0 100644
--- a/src/reflect/makefunc.go
+++ b/src/reflect/makefunc.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/reflect/set_test.go b/src/reflect/set_test.go
index 85dc55e..bc35c78 100644
--- a/src/reflect/set_test.go
+++ b/src/reflect/set_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -194,11 +194,13 @@ var assignableTests = []struct {
 	{new(*int), new(IntPtr), true},
 	{new(IntPtr), new(*int), true},
 	{new(IntPtr), new(IntPtr1), false},
+	{new(Ch), new(<-chan interface{}), true},
 	// test runs implementsTests too
 }
 
 type IntPtr *int
 type IntPtr1 *int
+type Ch <-chan interface{}
 
 func TestAssignableTo(t *testing.T) {
 	for _, tt := range append(assignableTests, implementsTests...) {
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 003c610..bedfba4 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Package reflect implements run-time reflection, allowing a program to
-// manipulate objects with arbitrary types.  The typical use is to take a value
+// manipulate objects with arbitrary types. The typical use is to take a value
 // with static type interface{} and extract its dynamic type information by
 // calling TypeOf, which returns a Type.
 //
@@ -24,10 +24,10 @@ import (
 
 // Type is the representation of a Go type.
 //
-// Not all methods apply to all kinds of types.  Restrictions,
+// Not all methods apply to all kinds of types. Restrictions,
 // if any, are noted in the documentation for each method.
 // Use the Kind method to find out the kind of type before
-// calling kind-specific methods.  Calling a method
+// calling kind-specific methods. Calling a method
 // inappropriate to the kind of type causes a run-time panic.
 type Type interface {
 	// Methods applicable to all types.
@@ -80,7 +80,7 @@ type Type interface {
 	// String returns a string representation of the type.
 	// The string representation may use shortened package names
 	// (e.g., base64 instead of "encoding/base64") and is not
-	// guaranteed to be unique among types.  To test for equality,
+	// guaranteed to be unique among types. To test for equality,
 	// compare the Types directly.
 	String() string
 
@@ -121,7 +121,7 @@ type Type interface {
 	ChanDir() ChanDir
 
 	// IsVariadic reports whether a function type's final input parameter
-	// is a "..." parameter.  If so, t.In(t.NumIn() - 1) returns the parameter's
+	// is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
 	// implicit actual type []T.
 	//
 	// For concreteness, if t represents func(x int, y ... float64), then
@@ -144,7 +144,7 @@ type Type interface {
 	Field(i int) StructField
 
 	// FieldByIndex returns the nested field corresponding
-	// to the index sequence.  It is equivalent to calling Field
+	// to the index sequence. It is equivalent to calling Field
 	// successively for each index i.
 	// It panics if the type's Kind is not Struct.
 	FieldByIndex(index []int) StructField
@@ -240,23 +240,55 @@ const (
 	UnsafePointer
 )
 
+// tflag is used by an rtype to signal what extra type information is
+// available in the memory directly following the rtype value.
+//
+// tflag values must be kept in sync with copies in:
+//	cmd/compile/internal/gc/reflect.go
+//	cmd/link/internal/ld/decodesym.go
+//	runtime/type.go
+type tflag uint8
+
+const (
+	// tflagUncommon means that there is a pointer, *uncommonType,
+	// just beyond the outer type structure.
+	//
+	// For example, if t.Kind() == Struct and t.tflag&tflagUncommon != 0,
+	// then t has uncommonType data and it can be accessed as:
+	//
+	//	type tUncommon struct {
+	//		structType
+	//		u uncommonType
+	//	}
+	//	u := &(*tUncommon)(unsafe.Pointer(t)).u
+	tflagUncommon tflag = 1 << 0
+
+	// tflagExtraStar means the name in the str field has an
+	// extraneous '*' prefix. This is because for most types T in
+	// a program, the type *T also exists and reusing the str data
+	// saves binary size.
+	tflagExtraStar tflag = 1 << 1
+
+	// tflagNamed means the type has a name.
+	tflagNamed tflag = 1 << 2
+)
+
 // rtype is the common implementation of most values.
 // It is embedded in other, public struct types, but always
 // with a unique tag like `reflect:"array"` or `reflect:"ptr"`
 // so that code cannot convert from, say, *arrayType to *ptrType.
 type rtype struct {
-	size          uintptr
-	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
+	size       uintptr
+	ptrdata    uintptr
+	hash       uint32   // hash of type; avoids computation in hash tables
+	tflag      tflag    // extra type information flags
+	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
+	str        nameOff  // string form
+	ptrToThis  typeOff  // type for pointer to this type, may be zero
 }
 
 // a copy of runtime.typeAlg
@@ -271,12 +303,10 @@ type typeAlg struct {
 
 // Method on non-interface type
 type method struct {
-	name    *string        // name of method
-	pkgPath *string        // nil for exported Names; otherwise import path
-	mtyp    *rtype         // method type (without receiver)
-	typ     *rtype         // .(*FuncType) underneath (with receiver)
-	ifn     unsafe.Pointer // fn used in interface call (one-word receiver)
-	tfn     unsafe.Pointer // fn used for normal method call
+	name nameOff // name of method
+	mtyp typeOff // method type (without receiver)
+	ifn  textOff // fn used in interface call (one-word receiver)
+	tfn  textOff // fn used for normal method call
 }
 
 // uncommonType is present only for types with names or methods
@@ -284,9 +314,11 @@ type method struct {
 // Using a pointer to this struct reduces the overall size required
 // to describe an unnamed type with no methods.
 type uncommonType struct {
-	name    *string  // name of type
-	pkgPath *string  // import path; nil for built-in types like int, string
-	methods []method // methods associated with type
+	pkgPath nameOff // import path; empty for built-in types like int, string
+	mcount  uint16  // number of methods
+	_       uint16  // unused
+	moff    uint32  // offset from this uncommontype to [mcount]method
+	_       uint32  // unused
 }
 
 // ChanDir represents a channel type's direction.
@@ -314,23 +346,32 @@ type chanType struct {
 }
 
 // funcType represents a function type.
+//
+// A *rtype for each in and out parameter is stored in an array that
+// directly follows the funcType (and possibly its uncommonType). So
+// a function type with one method, one input, and one output is:
+//
+//	struct {
+//		funcType
+//		uncommonType
+//		[2]*rtype    // [0] is in, [1] is out
+//	}
 type funcType struct {
-	rtype     `reflect:"func"`
-	dotdotdot bool     // last input parameter is ...
-	in        []*rtype // input parameter types
-	out       []*rtype // output parameter types
+	rtype    `reflect:"func"`
+	inCount  uint16
+	outCount uint16 // top bit is set if last input parameter is ...
 }
 
 // imethod represents a method on an interface type
 type imethod struct {
-	name    *string // name of method
-	pkgPath *string // nil for exported Names; otherwise import path
-	typ     *rtype  // .(*FuncType) underneath
+	name nameOff // name of method
+	typ  typeOff // .(*FuncType) underneath
 }
 
 // interfaceType represents an interface type.
 type interfaceType struct {
 	rtype   `reflect:"interface"`
+	pkgPath name      // import path
 	methods []imethod // sorted by hash
 }
 
@@ -364,17 +405,146 @@ type sliceType struct {
 
 // Struct field
 type structField struct {
-	name    *string // nil for embedded fields
-	pkgPath *string // nil for exported Names; otherwise import path
-	typ     *rtype  // type of field
-	tag     *string // nil if no tag
-	offset  uintptr // byte offset of field within struct
+	name   name    // name is empty for embedded fields
+	typ    *rtype  // type of field
+	offset uintptr // byte offset of field within struct
 }
 
 // structType represents a struct type.
 type structType struct {
-	rtype  `reflect:"struct"`
-	fields []structField // sorted by offset
+	rtype   `reflect:"struct"`
+	pkgPath name
+	fields  []structField // sorted by offset
+}
+
+// name is an encoded type name with optional extra data.
+//
+// The first byte is a bit field containing:
+//
+//	1<<0 the name is exported
+//	1<<1 tag data follows the name
+//	1<<2 pkgPath nameOff follows the name and tag
+//
+// The next two bytes are the data length:
+//
+//	 l := uint16(data[1])<<8 | uint16(data[2])
+//
+// Bytes [3:3+l] are the string data.
+//
+// If tag data follows then bytes 3+l and 3+l+1 are the tag length,
+// with the data following.
+//
+// If the import path follows, then 4 bytes at the end of
+// the data form a nameOff. The import path is only set for concrete
+// methods that are defined in a different package than their type.
+//
+// If a name starts with "*", then the exported bit represents
+// whether the pointed to type is exported.
+type name struct {
+	bytes *byte
+}
+
+func (n name) data(off int) *byte {
+	return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off)))
+}
+
+func (n name) isExported() bool {
+	return (*n.bytes)&(1<<0) != 0
+}
+
+func (n name) nameLen() int {
+	return int(uint16(*n.data(1))<<8 | uint16(*n.data(2)))
+}
+
+func (n name) tagLen() int {
+	if *n.data(0)&(1<<1) == 0 {
+		return 0
+	}
+	off := 3 + n.nameLen()
+	return int(uint16(*n.data(off))<<8 | uint16(*n.data(off + 1)))
+}
+
+func (n name) name() (s string) {
+	if n.bytes == nil {
+		return
+	}
+	b := (*[4]byte)(unsafe.Pointer(n.bytes))
+
+	hdr := (*stringHeader)(unsafe.Pointer(&s))
+	hdr.Data = unsafe.Pointer(&b[3])
+	hdr.Len = int(b[1])<<8 | int(b[2])
+	return s
+}
+
+func (n name) tag() (s string) {
+	tl := n.tagLen()
+	if tl == 0 {
+		return ""
+	}
+	nl := n.nameLen()
+	hdr := (*stringHeader)(unsafe.Pointer(&s))
+	hdr.Data = unsafe.Pointer(n.data(3 + nl + 2))
+	hdr.Len = tl
+	return s
+}
+
+func (n name) pkgPath() string {
+	if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
+		return ""
+	}
+	off := 3 + n.nameLen()
+	if tl := n.tagLen(); tl > 0 {
+		off += 2 + tl
+	}
+	var nameOff int32
+	copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
+	pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n.bytes), nameOff))}
+	return pkgPathName.name()
+}
+
+// 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)
+}
+
+func newName(n, tag, pkgPath string, exported bool) name {
+	if len(n) > 1<<16-1 {
+		panic("reflect.nameFrom: name too long: " + n)
+	}
+	if len(tag) > 1<<16-1 {
+		panic("reflect.nameFrom: tag too long: " + tag)
+	}
+
+	var bits byte
+	l := 1 + 2 + len(n)
+	if exported {
+		bits |= 1 << 0
+	}
+	if len(tag) > 0 {
+		l += 2 + len(tag)
+		bits |= 1 << 1
+	}
+	if pkgPath != "" {
+		bits |= 1 << 2
+	}
+
+	b := make([]byte, l)
+	b[0] = bits
+	b[1] = uint8(len(n) >> 8)
+	b[2] = uint8(len(n))
+	copy(b[3:], n)
+	if len(tag) > 0 {
+		tb := b[3+len(n):]
+		tb[0] = uint8(len(tag) >> 8)
+		tb[1] = uint8(len(tag))
+		copy(tb[2:], tag)
+	}
+
+	if pkgPath != "" {
+		panic("reflect: creating a name with a package path is not supported")
+	}
+
+	return name{bytes: &b[0]}
 }
 
 /*
@@ -386,7 +556,7 @@ type structType struct {
 type Method struct {
 	// Name is the method name.
 	// PkgPath is the package path that qualifies a lower case (unexported)
-	// method name.  It is empty for upper case (exported) method names.
+	// 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 https://golang.org/ref/spec#Uniqueness_of_identifiers
@@ -442,25 +612,130 @@ var kindNames = []string{
 	UnsafePointer: "unsafe.Pointer",
 }
 
-func (t *uncommonType) uncommon() *uncommonType {
-	return t
+func (t *uncommonType) methods() []method {
+	return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff)))[:t.mcount:t.mcount]
 }
 
-func (t *uncommonType) PkgPath() string {
-	if t == nil || t.pkgPath == nil {
-		return ""
-	}
-	return *t.pkgPath
+// resolveNameOff resolves a name offset from a base pointer.
+// The (*rtype).nameOff method is a convenience wrapper for this function.
+// Implemented in the runtime package.
+func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer
+
+// resolveTypeOff resolves an *rtype offset from a base type.
+// The (*rtype).typeOff method is a convenience wrapper for this function.
+// Implemented in the runtime package.
+func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
+
+// resolveTextOff resolves an function pointer offset from a base type.
+// The (*rtype).textOff method is a convenience wrapper for this function.
+// Implemented in the runtime package.
+func resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
+
+// addReflectOff adds a pointer to the reflection lookup map in the runtime.
+// It returns a new ID that can be used as a typeOff or textOff, and will
+// be resolved correctly. Implemented in the runtime package.
+func addReflectOff(ptr unsafe.Pointer) int32
+
+// resolveReflectType adds a name to the reflection lookup map in the runtime.
+// It returns a new nameOff that can be used to refer to the pointer.
+func resolveReflectName(n name) nameOff {
+	return nameOff(addReflectOff(unsafe.Pointer(n.bytes)))
 }
 
-func (t *uncommonType) Name() string {
-	if t == nil || t.name == nil {
-		return ""
+// resolveReflectType adds a *rtype to the reflection lookup map in the runtime.
+// It returns a new typeOff that can be used to refer to the pointer.
+func resolveReflectType(t *rtype) typeOff {
+	return typeOff(addReflectOff(unsafe.Pointer(t)))
+}
+
+// resolveReflectText adds a function pointer to the reflection lookup map in
+// the runtime. It returns a new textOff that can be used to refer to the
+// pointer.
+func resolveReflectText(ptr unsafe.Pointer) textOff {
+	return textOff(addReflectOff(ptr))
+}
+
+type nameOff int32 // offset to a name
+type typeOff int32 // offset to an *rtype
+type textOff int32 // offset from top of text section
+
+func (t *rtype) nameOff(off nameOff) name {
+	return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))}
+}
+
+func (t *rtype) typeOff(off typeOff) *rtype {
+	return (*rtype)(resolveTypeOff(unsafe.Pointer(t), int32(off)))
+}
+
+func (t *rtype) textOff(off textOff) unsafe.Pointer {
+	return resolveTextOff(unsafe.Pointer(t), int32(off))
+}
+
+func (t *rtype) uncommon() *uncommonType {
+	if t.tflag&tflagUncommon == 0 {
+		return nil
+	}
+	switch t.Kind() {
+	case Struct:
+		return &(*structTypeUncommon)(unsafe.Pointer(t)).u
+	case Ptr:
+		type u struct {
+			ptrType
+			u uncommonType
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case Func:
+		type u struct {
+			funcType
+			u uncommonType
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case Slice:
+		type u struct {
+			sliceType
+			u uncommonType
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case Array:
+		type u struct {
+			arrayType
+			u uncommonType
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case Chan:
+		type u struct {
+			chanType
+			u uncommonType
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case Map:
+		type u struct {
+			mapType
+			u uncommonType
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case Interface:
+		type u struct {
+			interfaceType
+			u uncommonType
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	default:
+		type u struct {
+			rtype
+			u uncommonType
+		}
+		return &(*u)(unsafe.Pointer(t)).u
 	}
-	return *t.name
 }
 
-func (t *rtype) String() string { return *t.string }
+func (t *rtype) String() string {
+	s := t.nameOff(t.str).name()
+	if t.tflag&tflagExtraStar != 0 {
+		return s[1:]
+	}
+	return s
+}
 
 func (t *rtype) Size() uintptr { return t.size }
 
@@ -485,57 +760,65 @@ func (t *rtype) pointers() bool { return t.kind&kindNoPointers == 0 }
 
 func (t *rtype) common() *rtype { return t }
 
-func (t *uncommonType) Method(i int) (m Method) {
-	if t == nil || i < 0 || i >= len(t.methods) {
-		panic("reflect: Method index out of range")
-	}
-	p := &t.methods[i]
-	if p.name != nil {
-		m.Name = *p.name
-	}
-	fl := flag(Func)
-	if p.pkgPath != nil {
-		m.PkgPath = *p.pkgPath
-		fl |= flagStickyRO
-	}
-	mt := p.typ
-	m.Type = mt
-	fn := unsafe.Pointer(&p.tfn)
-	m.Func = Value{mt, fn, fl}
-	m.Index = i
-	return
+var methodCache struct {
+	sync.RWMutex
+	m map[*rtype][]method
 }
 
-func (t *uncommonType) NumMethod() int {
-	if t == nil {
-		return 0
+func (t *rtype) exportedMethods() []method {
+	methodCache.RLock()
+	methods, found := methodCache.m[t]
+	methodCache.RUnlock()
+
+	if found {
+		return methods
 	}
-	return len(t.methods)
-}
 
-func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
-	if t == nil {
-		return
+	ut := t.uncommon()
+	if ut == nil {
+		return nil
 	}
-	var p *method
-	for i := range t.methods {
-		p = &t.methods[i]
-		if p.name != nil && *p.name == name {
-			return t.Method(i), true
+	allm := ut.methods()
+	allExported := true
+	for _, m := range allm {
+		name := t.nameOff(m.name)
+		if !name.isExported() {
+			allExported = false
+			break
 		}
 	}
-	return
+	if allExported {
+		methods = allm
+	} else {
+		methods = make([]method, 0, len(allm))
+		for _, m := range allm {
+			name := t.nameOff(m.name)
+			if name.isExported() {
+				methods = append(methods, m)
+			}
+		}
+		methods = methods[:len(methods):len(methods)]
+	}
+
+	methodCache.Lock()
+	if methodCache.m == nil {
+		methodCache.m = make(map[*rtype][]method)
+	}
+	methodCache.m[t] = methods
+	methodCache.Unlock()
+
+	return methods
 }
 
-// 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 {
 	if t.Kind() == Interface {
 		tt := (*interfaceType)(unsafe.Pointer(t))
 		return tt.NumMethod()
 	}
-	return t.uncommonType.NumMethod()
+	if t.tflag&tflagUncommon == 0 {
+		return 0 // avoid methodCache lock in zero case
+	}
+	return len(t.exportedMethods())
 }
 
 func (t *rtype) Method(i int) (m Method) {
@@ -543,7 +826,33 @@ func (t *rtype) Method(i int) (m Method) {
 		tt := (*interfaceType)(unsafe.Pointer(t))
 		return tt.Method(i)
 	}
-	return t.uncommonType.Method(i)
+	methods := t.exportedMethods()
+	if i < 0 || i >= len(methods) {
+		panic("reflect: Method index out of range")
+	}
+	p := methods[i]
+	pname := t.nameOff(p.name)
+	m.Name = pname.name()
+	fl := flag(Func)
+	mtyp := t.typeOff(p.mtyp)
+	ft := (*funcType)(unsafe.Pointer(mtyp))
+	in := make([]Type, 0, 1+len(ft.in()))
+	in = append(in, t)
+	for _, arg := range ft.in() {
+		in = append(in, arg)
+	}
+	out := make([]Type, 0, len(ft.out()))
+	for _, ret := range ft.out() {
+		out = append(out, ret)
+	}
+	mt := FuncOf(in, out, ft.IsVariadic())
+	m.Type = mt
+	tfn := t.textOff(p.tfn)
+	fn := unsafe.Pointer(&tfn)
+	m.Func = Value{mt.(*rtype), fn, fl}
+
+	m.Index = i
+	return m
 }
 
 func (t *rtype) MethodByName(name string) (m Method, ok bool) {
@@ -551,15 +860,46 @@ func (t *rtype) MethodByName(name string) (m Method, ok bool) {
 		tt := (*interfaceType)(unsafe.Pointer(t))
 		return tt.MethodByName(name)
 	}
-	return t.uncommonType.MethodByName(name)
+	ut := t.uncommon()
+	if ut == nil {
+		return Method{}, false
+	}
+	utmethods := ut.methods()
+	for i := 0; i < int(ut.mcount); i++ {
+		p := utmethods[i]
+		pname := t.nameOff(p.name)
+		if pname.isExported() && pname.name() == name {
+			return t.Method(i), true
+		}
+	}
+	return Method{}, false
 }
 
 func (t *rtype) PkgPath() string {
-	return t.uncommonType.PkgPath()
+	ut := t.uncommon()
+	if ut == nil {
+		return ""
+	}
+	return t.nameOff(ut.pkgPath).name()
+}
+
+func hasPrefix(s, prefix string) bool {
+	return len(s) >= len(prefix) && s[:len(prefix)] == prefix
 }
 
 func (t *rtype) Name() string {
-	return t.uncommonType.Name()
+	if t.tflag&tflagNamed == 0 {
+		return ""
+	}
+	s := t.String()
+	i := len(s) - 1
+	for i >= 0 {
+		if s[i] == '.' {
+			break
+		}
+		i--
+	}
+	return s[i+1:]
 }
 
 func (t *rtype) ChanDir() ChanDir {
@@ -575,7 +915,7 @@ func (t *rtype) IsVariadic() bool {
 		panic("reflect: IsVariadic of non-func type")
 	}
 	tt := (*funcType)(unsafe.Pointer(t))
-	return tt.dotdotdot
+	return tt.outCount&(1<<15) != 0
 }
 
 func (t *rtype) Elem() Type {
@@ -636,7 +976,7 @@ func (t *rtype) In(i int) Type {
 		panic("reflect: In of non-func type")
 	}
 	tt := (*funcType)(unsafe.Pointer(t))
-	return toType(tt.in[i])
+	return toType(tt.in()[i])
 }
 
 func (t *rtype) Key() Type {
@@ -668,7 +1008,7 @@ func (t *rtype) NumIn() int {
 		panic("reflect: NumIn of non-func type")
 	}
 	tt := (*funcType)(unsafe.Pointer(t))
-	return len(tt.in)
+	return int(tt.inCount)
 }
 
 func (t *rtype) NumOut() int {
@@ -676,7 +1016,7 @@ func (t *rtype) NumOut() int {
 		panic("reflect: NumOut of non-func type")
 	}
 	tt := (*funcType)(unsafe.Pointer(t))
-	return len(tt.out)
+	return len(tt.out())
 }
 
 func (t *rtype) Out(i int) Type {
@@ -684,7 +1024,28 @@ func (t *rtype) Out(i int) Type {
 		panic("reflect: Out of non-func type")
 	}
 	tt := (*funcType)(unsafe.Pointer(t))
-	return toType(tt.out[i])
+	return toType(tt.out()[i])
+}
+
+func (t *funcType) in() []*rtype {
+	uadd := unsafe.Sizeof(*t)
+	if t.tflag&tflagUncommon != 0 {
+		uadd += unsafe.Sizeof(uncommonType{})
+	}
+	return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd))[:t.inCount]
+}
+
+func (t *funcType) out() []*rtype {
+	uadd := unsafe.Sizeof(*t)
+	if t.tflag&tflagUncommon != 0 {
+		uadd += unsafe.Sizeof(uncommonType{})
+	}
+	outCount := t.outCount & (1<<15 - 1)
+	return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount]
+}
+
+func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
+	return unsafe.Pointer(uintptr(p) + x)
 }
 
 func (d ChanDir) String() string {
@@ -705,11 +1066,15 @@ func (t *interfaceType) Method(i int) (m Method) {
 		return
 	}
 	p := &t.methods[i]
-	m.Name = *p.name
-	if p.pkgPath != nil {
-		m.PkgPath = *p.pkgPath
+	pname := t.nameOff(p.name)
+	m.Name = pname.name()
+	if !pname.isExported() {
+		m.PkgPath = pname.pkgPath()
+		if m.PkgPath == "" {
+			m.PkgPath = t.pkgPath.name()
+		}
 	}
-	m.Type = toType(p.typ)
+	m.Type = toType(t.typeOff(p.typ))
 	m.Index = i
 	return
 }
@@ -725,7 +1090,7 @@ func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
 	var p *imethod
 	for i := range t.methods {
 		p = &t.methods[i]
-		if *p.name == name {
+		if t.nameOff(p.name).name() == name {
 			return t.Method(i), true
 		}
 	}
@@ -737,7 +1102,7 @@ type StructField struct {
 	// Name is the field name.
 	Name string
 	// PkgPath is the package path that qualifies a lower case (unexported)
-	// field name.  It is empty for upper case (exported) field names.
+	// field name. It is empty for upper case (exported) field names.
 	// See https://golang.org/ref/spec#Uniqueness_of_identifiers
 	PkgPath string
 
@@ -761,8 +1126,20 @@ type StructTag string
 // Get returns the value associated with key in the tag string.
 // If there is no such key in the tag, Get returns the empty string.
 // If the tag does not have the conventional format, the value
-// returned by Get is unspecified.
+// returned by Get is unspecified. To determine whether a tag is
+// explicitly set to the empty string, use Lookup.
 func (tag StructTag) Get(key string) string {
+	v, _ := tag.Lookup(key)
+	return v
+}
+
+// Lookup returns the value associated with key in the tag string.
+// If the key is present in the tag the value (which may be empty)
+// is returned. Otherwise the returned value will be the empty string.
+// The ok return value reports whether the value was explicitly set in
+// the tag string. If the tag does not have the conventional format,
+// the value returned by Lookup is unspecified.
+func (tag StructTag) Lookup(key string) (value string, ok bool) {
 	// When modifying this code, also update the validateStructTag code
 	// in golang.org/x/tools/cmd/vet/structtag.go.
 
@@ -810,21 +1187,21 @@ func (tag StructTag) Get(key string) string {
 			if err != nil {
 				break
 			}
-			return value
+			return value, true
 		}
 	}
-	return ""
+	return "", false
 }
 
 // Field returns the i'th struct field.
 func (t *structType) Field(i int) (f StructField) {
 	if i < 0 || i >= len(t.fields) {
-		return
+		panic("reflect: Field index out of bounds")
 	}
 	p := &t.fields[i]
 	f.Type = toType(p.typ)
-	if p.name != nil {
-		f.Name = *p.name
+	if name := p.name.name(); name != "" {
+		f.Name = name
 	} else {
 		t := f.Type
 		if t.Kind() == Ptr {
@@ -833,21 +1210,22 @@ func (t *structType) Field(i int) (f StructField) {
 		f.Name = t.Name()
 		f.Anonymous = true
 	}
-	if p.pkgPath != nil {
-		f.PkgPath = *p.pkgPath
+	if !p.name.isExported() {
+		// Fields never have an import path in their name.
+		f.PkgPath = t.pkgPath.name()
 	}
-	if p.tag != nil {
-		f.Tag = StructTag(*p.tag)
+	if tag := p.name.tag(); tag != "" {
+		f.Tag = StructTag(tag)
 	}
 	f.Offset = p.offset
 
 	// NOTE(rsc): This is the only allocation in the interface
-	// presented by a reflect.Type.  It would be nice to avoid,
+	// presented by a reflect.Type. It would be nice to avoid,
 	// at least in the common cases, but we need to make sure
 	// that misbehaving clients of reflect cannot affect other
-	// uses of reflect.  One possibility is CL 5371098, but we
+	// uses of reflect. One possibility is CL 5371098, but we
 	// postponed that ugliness until there is a demonstrated
-	// need for the performance.  This is issue 2320.
+	// need for the performance. This is issue 2320.
 	f.Index = []int{i}
 	return
 }
@@ -929,8 +1307,8 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel
 				// Find name and type for field f.
 				var fname string
 				var ntyp *rtype
-				if f.name != nil {
-					fname = *f.name
+				if name := f.name.name(); name != "" {
+					fname = name
 				} else {
 					// Anonymous field of type T or *T.
 					// Name taken from type.
@@ -995,11 +1373,12 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
 	if name != "" {
 		for i := range t.fields {
 			tf := &t.fields[i]
-			if tf.name == nil {
+			tfname := tf.name.name()
+			if tfname == "" {
 				hasAnon = true
 				continue
 			}
-			if *tf.name == name {
+			if tfname == name {
 				return t.Field(i), true
 			}
 		}
@@ -1030,15 +1409,11 @@ func PtrTo(t Type) Type {
 }
 
 func (t *rtype) ptrTo() *rtype {
-	if p := t.ptrToThis; p != nil {
-		return p
+	if t.ptrToThis != 0 {
+		return t.typeOff(t.ptrToThis)
 	}
 
-	// Otherwise, synthesize one.
-	// This only happens for pointers with no methods.
-	// We keep the mapping in a map on the side, because
-	// this operation is rare and a separate map lets us keep
-	// the type structures in read-only memory.
+	// Check the cache.
 	ptrMap.RLock()
 	if m := ptrMap.m; m != nil {
 		if p := m[t]; p != nil {
@@ -1047,6 +1422,7 @@ func (t *rtype) ptrTo() *rtype {
 		}
 	}
 	ptrMap.RUnlock()
+
 	ptrMap.Lock()
 	if ptrMap.m == nil {
 		ptrMap.m = make(map[*rtype]*ptrType)
@@ -1059,7 +1435,7 @@ func (t *rtype) ptrTo() *rtype {
 	}
 
 	// Look in known types.
-	s := "*" + *t.string
+	s := "*" + t.String()
 	for _, tt := range typesByString(s) {
 		p = (*ptrType)(unsafe.Pointer(tt))
 		if p.elem == t {
@@ -1076,7 +1452,7 @@ func (t *rtype) ptrTo() *rtype {
 	prototype := *(**ptrType)(unsafe.Pointer(&iptr))
 	*p = *prototype
 
-	p.string = &s
+	p.str = resolveReflectName(newName(s, "", "", false))
 
 	// For the type structures linked into the binary, the
 	// compiler provides a good hash of the string.
@@ -1085,8 +1461,6 @@ func (t *rtype) ptrTo() *rtype {
 	// old hash and the new "*".
 	p.hash = fnv1(t.hash, '*')
 
-	p.uncommonType = nil
-	p.ptrToThis = nil
 	p.elem = t
 
 	ptrMap.m[t] = p
@@ -1160,7 +1534,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.typ == tm.typ {
+			if V.nameOff(vm.name).name() == t.nameOff(tm.name).name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
 				if i++; i >= len(t.methods) {
 					return true
 				}
@@ -1174,10 +1548,11 @@ func implements(T, V *rtype) bool {
 		return false
 	}
 	i := 0
-	for j := 0; j < len(v.methods); j++ {
+	vmethods := v.methods()
+	for j := 0; j < int(v.mcount); j++ {
 		tm := &t.methods[i]
-		vm := &v.methods[j]
-		if *vm.name == *tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
+		vm := vmethods[j]
+		if V.nameOff(vm.name).name() == t.nameOff(tm.name).name() && V.typeOff(vm.mtyp) == t.typeOff(tm.typ) {
 			if i++; i >= len(t.methods) {
 				return true
 			}
@@ -1242,16 +1617,16 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
 	case Func:
 		t := (*funcType)(unsafe.Pointer(T))
 		v := (*funcType)(unsafe.Pointer(V))
-		if t.dotdotdot != v.dotdotdot || len(t.in) != len(v.in) || len(t.out) != len(v.out) {
+		if t.outCount != v.outCount || t.inCount != v.inCount {
 			return false
 		}
-		for i, typ := range t.in {
-			if typ != v.in[i] {
+		for i := 0; i < t.NumIn(); i++ {
+			if t.In(i) != v.In(i) {
 				return false
 			}
 		}
-		for i, typ := range t.out {
-			if typ != v.out[i] {
+		for i := 0; i < t.NumOut(); i++ {
+			if t.Out(i) != v.Out(i) {
 				return false
 			}
 		}
@@ -1282,16 +1657,13 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
 		for i := range t.fields {
 			tf := &t.fields[i]
 			vf := &v.fields[i]
-			if tf.name != vf.name && (tf.name == nil || vf.name == nil || *tf.name != *vf.name) {
-				return false
-			}
-			if tf.pkgPath != vf.pkgPath && (tf.pkgPath == nil || vf.pkgPath == nil || *tf.pkgPath != *vf.pkgPath) {
+			if tf.name.name() != vf.name.name() {
 				return false
 			}
 			if tf.typ != vf.typ {
 				return false
 			}
-			if tf.tag != vf.tag && (tf.tag == nil || vf.tag == nil || *tf.tag != *vf.tag) {
+			if tf.name.tag() != vf.name.tag() {
 				return false
 			}
 			if tf.offset != vf.offset {
@@ -1305,30 +1677,48 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
 }
 
 // typelinks is implemented in package runtime.
-// It returns a slice of all the 'typelink' information in the binary,
-// which is to say a slice of known types, sorted by string.
+// It returns a slice of the sections in each module,
+// and a slice of *rtype offsets in each module.
+//
+// The types in each module are sorted by string. That is, the first
+// two linked types of the first module are:
+//
+//	d0 := sections[0]
+//	t1 := (*rtype)(add(d0, offset[0][0]))
+//	t2 := (*rtype)(add(d0, offset[0][1]))
+//
+// and
+//
+//	t1.String() < t2.String()
+//
 // Note that strings are not unique identifiers for types:
 // 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
+// pointers, channels, maps, slices, and arrays.
+func typelinks() (sections []unsafe.Pointer, offset [][]int32)
+
+func rtypeOff(section unsafe.Pointer, off int32) *rtype {
+	return (*rtype)(add(section, uintptr(off)))
+}
 
 // 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 {
-	typs := typelinks()
+	sections, offset := typelinks()
 	var ret []*rtype
 
-	for _, typ := range typs {
+	for offsI, offs := range offset {
+		section := sections[offsI]
+
 		// 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)
+		// This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s).
+		i, j := 0, len(offs)
 		for i < j {
 			h := i + (j-i)/2 // avoid overflow when computing h
 			// i ≤ h < j
-			if !(*typ[h].string >= s) {
+			if !(rtypeOff(section, offs[h]).String() >= s) {
 				i = h + 1 // preserves f(i-1) == false
 			} else {
 				j = h // preserves f(j) == true
@@ -1339,23 +1729,18 @@ func typesByString(s string) []*rtype {
 		// 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]...)
+		for j := i; j < len(offs); j++ {
+			typ := rtypeOff(section, offs[j])
+			if typ.String() != s {
+				break
 			}
+			ret = append(ret, typ)
 		}
 	}
 	return ret
 }
 
-// The lookupCache caches ChanOf, MapOf, and SliceOf lookups.
+// The lookupCache caches ArrayOf, ChanOf, MapOf and SliceOf lookups.
 var lookupCache struct {
 	sync.RWMutex
 	m map[cacheKey]*rtype
@@ -1442,11 +1827,11 @@ func ChanOf(dir ChanDir, t Type) Type {
 		lookupCache.Unlock()
 		panic("reflect.ChanOf: invalid dir")
 	case SendDir:
-		s = "chan<- " + *typ.string
+		s = "chan<- " + typ.String()
 	case RecvDir:
-		s = "<-chan " + *typ.string
+		s = "<-chan " + typ.String()
 	case BothDir:
-		s = "chan " + *typ.string
+		s = "chan " + typ.String()
 	}
 	for _, tt := range typesByString(s) {
 		ch := (*chanType)(unsafe.Pointer(tt))
@@ -1461,11 +1846,9 @@ func ChanOf(dir ChanDir, t Type) Type {
 	ch := new(chanType)
 	*ch = *prototype
 	ch.dir = uintptr(dir)
-	ch.string = &s
+	ch.str = resolveReflectName(newName(s, "", "", false))
 	ch.hash = fnv1(typ.hash, 'c', byte(dir))
 	ch.elem = typ
-	ch.uncommonType = nil
-	ch.ptrToThis = nil
 
 	return cachePut(ckey, &ch.rtype)
 }
@@ -1493,7 +1876,7 @@ func MapOf(key, elem Type) Type {
 	}
 
 	// Look in known types.
-	s := "map[" + *ktyp.string + "]" + *etyp.string
+	s := "map[" + ktyp.String() + "]" + etyp.String()
 	for _, tt := range typesByString(s) {
 		mt := (*mapType)(unsafe.Pointer(tt))
 		if mt.key == ktyp && mt.elem == etyp {
@@ -1505,7 +1888,7 @@ func MapOf(key, elem Type) Type {
 	var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
 	mt := new(mapType)
 	*mt = **(**mapType)(unsafe.Pointer(&imap))
-	mt.string = &s
+	mt.str = resolveReflectName(newName(s, "", "", false))
 	mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
 	mt.key = ktyp
 	mt.elem = etyp
@@ -1527,12 +1910,36 @@ func MapOf(key, elem Type) Type {
 	mt.bucketsize = uint16(mt.bucket.size)
 	mt.reflexivekey = isReflexive(ktyp)
 	mt.needkeyupdate = needKeyUpdate(ktyp)
-	mt.uncommonType = nil
-	mt.ptrToThis = nil
+	mt.ptrToThis = 0
 
 	return cachePut(ckey, &mt.rtype)
 }
 
+type funcTypeFixed4 struct {
+	funcType
+	args [4]*rtype
+}
+type funcTypeFixed8 struct {
+	funcType
+	args [8]*rtype
+}
+type funcTypeFixed16 struct {
+	funcType
+	args [16]*rtype
+}
+type funcTypeFixed32 struct {
+	funcType
+	args [32]*rtype
+}
+type funcTypeFixed64 struct {
+	funcType
+	args [64]*rtype
+}
+type funcTypeFixed128 struct {
+	funcType
+	args [128]*rtype
+}
+
 // 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.
@@ -1548,15 +1955,45 @@ func FuncOf(in, out []Type, variadic bool) Type {
 	// Make a func type.
 	var ifunc interface{} = (func())(nil)
 	prototype := *(**funcType)(unsafe.Pointer(&ifunc))
-	ft := new(funcType)
+	n := len(in) + len(out)
+
+	var ft *funcType
+	var args []*rtype
+	switch {
+	case n <= 4:
+		fixed := new(funcTypeFixed4)
+		args = fixed.args[:0:len(fixed.args)]
+		ft = &fixed.funcType
+	case n <= 8:
+		fixed := new(funcTypeFixed8)
+		args = fixed.args[:0:len(fixed.args)]
+		ft = &fixed.funcType
+	case n <= 16:
+		fixed := new(funcTypeFixed16)
+		args = fixed.args[:0:len(fixed.args)]
+		ft = &fixed.funcType
+	case n <= 32:
+		fixed := new(funcTypeFixed32)
+		args = fixed.args[:0:len(fixed.args)]
+		ft = &fixed.funcType
+	case n <= 64:
+		fixed := new(funcTypeFixed64)
+		args = fixed.args[:0:len(fixed.args)]
+		ft = &fixed.funcType
+	case n <= 128:
+		fixed := new(funcTypeFixed128)
+		args = fixed.args[:0:len(fixed.args)]
+		ft = &fixed.funcType
+	default:
+		panic("reflect.FuncOf: too many arguments")
+	}
 	*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)
+		args = append(args, t)
 		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
 	}
 	if variadic {
@@ -1565,13 +2002,19 @@ func FuncOf(in, out []Type, variadic bool) Type {
 	hash = fnv1(hash, '.')
 	for _, out := range out {
 		t := out.(*rtype)
-		fout = append(fout, t)
+		args = append(args, t)
 		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
 	}
+	if len(args) > 50 {
+		panic("reflect.FuncOf does not support more than 50 arguments")
+	}
+	ft.tflag = 0
 	ft.hash = hash
-	ft.in = fin
-	ft.out = fout
-	ft.dotdotdot = variadic
+	ft.inCount = uint16(len(in))
+	ft.outCount = uint16(len(out))
+	if variadic {
+		ft.outCount |= 1 << 15
+	}
 
 	// Look in cache.
 	funcLookupCache.RLock()
@@ -1605,9 +2048,8 @@ func FuncOf(in, out []Type, variadic bool) Type {
 	}
 
 	// Populate the remaining fields of ft and store in cache.
-	ft.string = &str
-	ft.uncommonType = nil
-	ft.ptrToThis = nil
+	ft.str = resolveReflectName(newName(str, "", "", false))
+	ft.ptrToThis = 0
 	funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
 
 	return &ft.rtype
@@ -1617,30 +2059,31 @@ func FuncOf(in, out []Type, variadic bool) Type {
 func funcStr(ft *funcType) string {
 	repr := make([]byte, 0, 64)
 	repr = append(repr, "func("...)
-	for i, t := range ft.in {
+	for i, t := range ft.in() {
 		if i > 0 {
 			repr = append(repr, ", "...)
 		}
-		if ft.dotdotdot && i == len(ft.in)-1 {
+		if ft.IsVariadic() && i == int(ft.inCount)-1 {
 			repr = append(repr, "..."...)
-			repr = append(repr, *(*sliceType)(unsafe.Pointer(t)).elem.string...)
+			repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.String()...)
 		} else {
-			repr = append(repr, *t.string...)
+			repr = append(repr, t.String()...)
 		}
 	}
 	repr = append(repr, ')')
-	if l := len(ft.out); l == 1 {
+	out := ft.out()
+	if len(out) == 1 {
 		repr = append(repr, ' ')
-	} else if l > 1 {
+	} else if len(out) > 1 {
 		repr = append(repr, " ("...)
 	}
-	for i, t := range ft.out {
+	for i, t := range out {
 		if i > 0 {
 			repr = append(repr, ", "...)
 		}
-		repr = append(repr, *t.string...)
+		repr = append(repr, t.String()...)
 	}
-	if len(ft.out) > 1 {
+	if len(out) > 1 {
 		repr = append(repr, ')')
 	}
 	return string(repr)
@@ -1700,7 +2143,7 @@ func needKeyUpdate(t *rtype) bool {
 
 // 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
+// Currently, that's just size and the GC program. We also fill in string
 // for possible debugging use.
 const (
 	bucketSize uintptr = 8
@@ -1803,8 +2246,8 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
 	b.ptrdata = ptrdata
 	b.kind = kind
 	b.gcdata = gcdata
-	s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
-	b.string = &s
+	s := "bucket(" + ktyp.String() + "," + etyp.String() + ")"
+	b.str = resolveReflectName(newName(s, "", "", false))
 	return b
 }
 
@@ -1820,7 +2263,7 @@ func SliceOf(t Type) Type {
 	}
 
 	// Look in known types.
-	s := "[]" + *typ.string
+	s := "[]" + typ.String()
 	for _, tt := range typesByString(s) {
 		slice := (*sliceType)(unsafe.Pointer(tt))
 		if slice.elem == typ {
@@ -1833,15 +2276,516 @@ func SliceOf(t Type) Type {
 	prototype := *(**sliceType)(unsafe.Pointer(&islice))
 	slice := new(sliceType)
 	*slice = *prototype
-	slice.string = &s
+	slice.tflag = 0
+	slice.str = resolveReflectName(newName(s, "", "", false))
 	slice.hash = fnv1(typ.hash, '[')
 	slice.elem = typ
-	slice.uncommonType = nil
-	slice.ptrToThis = nil
+	slice.ptrToThis = 0
 
 	return cachePut(ckey, &slice.rtype)
 }
 
+// The structLookupCache caches StructOf lookups.
+// StructOf does not share the common lookupCache since we need to pin
+// the memory associated with *structTypeFixedN.
+var structLookupCache struct {
+	sync.RWMutex
+	m map[uint32][]interface {
+		common() *rtype
+	} // keyed by hash calculated in StructOf
+}
+
+type structTypeUncommon struct {
+	structType
+	u uncommonType
+}
+
+// A *rtype representing a struct is followed directly in memory by an
+// array of method objects representing the methods attached to the
+// struct. To get the same layout for a run time generated type, we
+// need an array directly following the uncommonType memory. The types
+// structTypeFixed4, ...structTypeFixedN are used to do this.
+//
+// A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN.
+
+// TODO(crawshaw): as these structTypeFixedN and funcTypeFixedN structs
+// have no methods, they could be defined at runtime using the StructOf
+// function.
+
+type structTypeFixed4 struct {
+	structType
+	u uncommonType
+	m [4]method
+}
+
+type structTypeFixed8 struct {
+	structType
+	u uncommonType
+	m [8]method
+}
+
+type structTypeFixed16 struct {
+	structType
+	u uncommonType
+	m [16]method
+}
+
+type structTypeFixed32 struct {
+	structType
+	u uncommonType
+	m [32]method
+}
+
+// StructOf returns the struct type containing fields.
+// The Offset and Index fields are ignored and computed as they would be
+// by the compiler.
+//
+// StructOf currently does not generate wrapper methods for embedded fields.
+// This limitation may be lifted in a future version.
+func StructOf(fields []StructField) Type {
+	var (
+		hash       = fnv1(0, []byte("struct {")...)
+		size       uintptr
+		typalign   uint8
+		comparable = true
+		hashable   = true
+		methods    []method
+
+		fs   = make([]structField, len(fields))
+		repr = make([]byte, 0, 64)
+		fset = map[string]struct{}{} // fields' names
+
+		hasPtr    = false // records whether at least one struct-field is a pointer
+		hasGCProg = false // records whether a struct-field type has a GCProg
+	)
+
+	repr = append(repr, "struct {"...)
+	for i, field := range fields {
+		if field.Type == nil {
+			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
+		}
+		f := runtimeStructField(field)
+		ft := f.typ
+		if ft.kind&kindGCProg != 0 {
+			hasGCProg = true
+		}
+		if ft.pointers() {
+			hasPtr = true
+		}
+
+		name := ""
+		// Update string and hash
+		if f.name.nameLen() > 0 {
+			hash = fnv1(hash, []byte(f.name.name())...)
+			repr = append(repr, (" " + f.name.name())...)
+			name = f.name.name()
+		} else {
+			// Embedded field
+			if f.typ.Kind() == Ptr {
+				// Embedded ** and *interface{} are illegal
+				elem := ft.Elem()
+				if k := elem.Kind(); k == Ptr || k == Interface {
+					panic("reflect.StructOf: illegal anonymous field type " + ft.String())
+				}
+				name = elem.String()
+			} else {
+				name = ft.String()
+			}
+			// TODO(sbinet) check for syntactically impossible type names?
+
+			switch f.typ.Kind() {
+			case Interface:
+				ift := (*interfaceType)(unsafe.Pointer(ft))
+				for im, m := range ift.methods {
+					if ift.nameOff(m.name).pkgPath() != "" {
+						// TODO(sbinet)
+						panic("reflect: embedded interface with unexported method(s) not implemented")
+					}
+
+					var (
+						mtyp    = ift.typeOff(m.typ)
+						ifield  = i
+						imethod = im
+						ifn     Value
+						tfn     Value
+					)
+
+					if ft.kind&kindDirectIface != 0 {
+						tfn = MakeFunc(mtyp, func(in []Value) []Value {
+							var args []Value
+							var recv = in[0]
+							if len(in) > 1 {
+								args = in[1:]
+							}
+							return recv.Field(ifield).Method(imethod).Call(args)
+						})
+						ifn = MakeFunc(mtyp, func(in []Value) []Value {
+							var args []Value
+							var recv = in[0]
+							if len(in) > 1 {
+								args = in[1:]
+							}
+							return recv.Field(ifield).Method(imethod).Call(args)
+						})
+					} else {
+						tfn = MakeFunc(mtyp, func(in []Value) []Value {
+							var args []Value
+							var recv = in[0]
+							if len(in) > 1 {
+								args = in[1:]
+							}
+							return recv.Field(ifield).Method(imethod).Call(args)
+						})
+						ifn = MakeFunc(mtyp, func(in []Value) []Value {
+							var args []Value
+							var recv = Indirect(in[0])
+							if len(in) > 1 {
+								args = in[1:]
+							}
+							return recv.Field(ifield).Method(imethod).Call(args)
+						})
+					}
+
+					methods = append(methods, method{
+						name: resolveReflectName(ift.nameOff(m.name)),
+						mtyp: resolveReflectType(mtyp),
+						ifn:  resolveReflectText(unsafe.Pointer(&ifn)),
+						tfn:  resolveReflectText(unsafe.Pointer(&tfn)),
+					})
+				}
+			case Ptr:
+				ptr := (*ptrType)(unsafe.Pointer(ft))
+				if unt := ptr.uncommon(); unt != nil {
+					for _, m := range unt.methods() {
+						mname := ptr.nameOff(m.name)
+						if mname.pkgPath() != "" {
+							// TODO(sbinet)
+							panic("reflect: embedded interface with unexported method(s) not implemented")
+						}
+						methods = append(methods, method{
+							name: resolveReflectName(mname),
+							mtyp: resolveReflectType(ptr.typeOff(m.mtyp)),
+							ifn:  resolveReflectText(ptr.textOff(m.ifn)),
+							tfn:  resolveReflectText(ptr.textOff(m.tfn)),
+						})
+					}
+				}
+				if unt := ptr.elem.uncommon(); unt != nil {
+					for _, m := range unt.methods() {
+						mname := ptr.nameOff(m.name)
+						if mname.pkgPath() != "" {
+							// TODO(sbinet)
+							panic("reflect: embedded interface with unexported method(s) not implemented")
+						}
+						methods = append(methods, method{
+							name: resolveReflectName(mname),
+							mtyp: resolveReflectType(ptr.elem.typeOff(m.mtyp)),
+							ifn:  resolveReflectText(ptr.elem.textOff(m.ifn)),
+							tfn:  resolveReflectText(ptr.elem.textOff(m.tfn)),
+						})
+					}
+				}
+			default:
+				if unt := ft.uncommon(); unt != nil {
+					for _, m := range unt.methods() {
+						mname := ft.nameOff(m.name)
+						if mname.pkgPath() != "" {
+							// TODO(sbinet)
+							panic("reflect: embedded interface with unexported method(s) not implemented")
+						}
+						methods = append(methods, method{
+							name: resolveReflectName(mname),
+							mtyp: resolveReflectType(ft.typeOff(m.mtyp)),
+							ifn:  resolveReflectText(ft.textOff(m.ifn)),
+							tfn:  resolveReflectText(ft.textOff(m.tfn)),
+						})
+
+					}
+				}
+			}
+		}
+		if _, dup := fset[name]; dup {
+			panic("reflect.StructOf: duplicate field " + name)
+		}
+		fset[name] = struct{}{}
+
+		hash = fnv1(hash, byte(ft.hash>>24), byte(ft.hash>>16), byte(ft.hash>>8), byte(ft.hash))
+
+		repr = append(repr, (" " + ft.String())...)
+		if f.name.tagLen() > 0 {
+			hash = fnv1(hash, []byte(f.name.tag())...)
+			repr = append(repr, (" " + strconv.Quote(f.name.tag()))...)
+		}
+		if i < len(fields)-1 {
+			repr = append(repr, ';')
+		}
+
+		comparable = comparable && (ft.alg.equal != nil)
+		hashable = hashable && (ft.alg.hash != nil)
+
+		f.offset = align(size, uintptr(ft.align))
+		if ft.align > typalign {
+			typalign = ft.align
+		}
+		size = f.offset + ft.size
+
+		fs[i] = f
+	}
+
+	var typ *structType
+	var ut *uncommonType
+	var typPin interface {
+		common() *rtype
+	} // structTypeFixedN
+
+	switch {
+	case len(methods) == 0:
+		t := new(structTypeUncommon)
+		typ = &t.structType
+		ut = &t.u
+		typPin = t
+	case len(methods) <= 4:
+		t := new(structTypeFixed4)
+		typ = &t.structType
+		ut = &t.u
+		copy(t.m[:], methods)
+		typPin = t
+	case len(methods) <= 8:
+		t := new(structTypeFixed8)
+		typ = &t.structType
+		ut = &t.u
+		copy(t.m[:], methods)
+		typPin = t
+	case len(methods) <= 16:
+		t := new(structTypeFixed16)
+		typ = &t.structType
+		ut = &t.u
+		copy(t.m[:], methods)
+		typPin = t
+	case len(methods) <= 32:
+		t := new(structTypeFixed32)
+		typ = &t.structType
+		ut = &t.u
+		copy(t.m[:], methods)
+		typPin = t
+	default:
+		panic("reflect.StructOf: too many methods")
+	}
+	ut.mcount = uint16(len(methods))
+	ut.moff = uint32(unsafe.Sizeof(uncommonType{}))
+
+	if len(fs) > 0 {
+		repr = append(repr, ' ')
+	}
+	repr = append(repr, '}')
+	hash = fnv1(hash, '}')
+	str := string(repr)
+
+	// Round the size up to be a multiple of the alignment.
+	size = align(size, uintptr(typalign))
+
+	// Make the struct type.
+	var istruct interface{} = struct{}{}
+	prototype := *(**structType)(unsafe.Pointer(&istruct))
+	*typ = *prototype
+	typ.fields = fs
+
+	// Look in cache
+	structLookupCache.RLock()
+	for _, st := range structLookupCache.m[hash] {
+		t := st.common()
+		if haveIdenticalUnderlyingType(&typ.rtype, t) {
+			structLookupCache.RUnlock()
+			return t
+		}
+	}
+	structLookupCache.RUnlock()
+
+	// not in cache, lock and retry
+	structLookupCache.Lock()
+	defer structLookupCache.Unlock()
+	if structLookupCache.m == nil {
+		structLookupCache.m = make(map[uint32][]interface {
+			common() *rtype
+		})
+	}
+	for _, st := range structLookupCache.m[hash] {
+		t := st.common()
+		if haveIdenticalUnderlyingType(&typ.rtype, t) {
+			return t
+		}
+	}
+
+	// Look in known types.
+	for _, t := range typesByString(str) {
+		if haveIdenticalUnderlyingType(&typ.rtype, t) {
+			// even if 't' wasn't a structType with methods, we should be ok
+			// as the 'u uncommonType' field won't be accessed except when
+			// tflag&tflagUncommon is set.
+			structLookupCache.m[hash] = append(structLookupCache.m[hash], t)
+			return t
+		}
+	}
+
+	typ.str = resolveReflectName(newName(str, "", "", false))
+	typ.tflag = 0
+	typ.hash = hash
+	typ.size = size
+	typ.align = typalign
+	typ.fieldAlign = typalign
+	if len(methods) > 0 {
+		typ.tflag |= tflagUncommon
+	}
+	if !hasPtr {
+		typ.kind |= kindNoPointers
+	} else {
+		typ.kind &^= kindNoPointers
+	}
+
+	if hasGCProg {
+		lastPtrField := 0
+		for i, ft := range fs {
+			if ft.typ.pointers() {
+				lastPtrField = i
+			}
+		}
+		prog := []byte{0, 0, 0, 0} // will be length of prog
+		for i, ft := range fs {
+			if i > lastPtrField {
+				// gcprog should not include anything for any field after
+				// the last field that contains pointer data
+				break
+			}
+			// FIXME(sbinet) handle padding, fields smaller than a word
+			elemGC := (*[1 << 30]byte)(unsafe.Pointer(ft.typ.gcdata))[:]
+			elemPtrs := ft.typ.ptrdata / ptrSize
+			switch {
+			case ft.typ.kind&kindGCProg == 0 && ft.typ.ptrdata != 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]...)
+			case ft.typ.kind&kindGCProg != 0:
+				// 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 := ft.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)
+				}
+			}
+		}
+		*(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
+		typ.kind |= kindGCProg
+		typ.gcdata = &prog[0]
+	} else {
+		typ.kind &^= kindGCProg
+		bv := new(bitVector)
+		addTypeBits(bv, 0, typ.common())
+		if len(bv.data) > 0 {
+			typ.gcdata = &bv.data[0]
+		}
+	}
+	typ.ptrdata = typeptrdata(typ.common())
+	typ.alg = new(typeAlg)
+	if hashable {
+		typ.alg.hash = func(p unsafe.Pointer, seed uintptr) uintptr {
+			o := seed
+			for _, ft := range typ.fields {
+				pi := unsafe.Pointer(uintptr(p) + ft.offset)
+				o = ft.typ.alg.hash(pi, o)
+			}
+			return o
+		}
+	}
+
+	if comparable {
+		typ.alg.equal = func(p, q unsafe.Pointer) bool {
+			for _, ft := range typ.fields {
+				pi := unsafe.Pointer(uintptr(p) + ft.offset)
+				qi := unsafe.Pointer(uintptr(q) + ft.offset)
+				if !ft.typ.alg.equal(pi, qi) {
+					return false
+				}
+			}
+			return true
+		}
+	}
+
+	switch {
+	case len(fs) == 1 && !ifaceIndir(fs[0].typ):
+		// structs of 1 direct iface type can be direct
+		typ.kind |= kindDirectIface
+	default:
+		typ.kind &^= kindDirectIface
+	}
+
+	structLookupCache.m[hash] = append(structLookupCache.m[hash], typPin)
+	return &typ.rtype
+}
+
+func runtimeStructField(field StructField) structField {
+	exported := field.PkgPath == ""
+	if field.Name == "" {
+		t := field.Type.(*rtype)
+		if t.Kind() == Ptr {
+			t = t.Elem().(*rtype)
+		}
+		exported = t.nameOff(t.str).isExported()
+	} else if exported {
+		b0 := field.Name[0]
+		if ('a' <= b0 && b0 <= 'z') || b0 == '_' {
+			panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but has no PkgPath")
+		}
+	}
+
+	_ = resolveReflectType(field.Type.common())
+	return structField{
+		name:   newName(field.Name, string(field.Tag), field.PkgPath, exported),
+		typ:    field.Type.common(),
+		offset: 0,
+	}
+}
+
+// typeptrdata returns the length in bytes of the prefix of t
+// containing pointer data. Anything after this offset is scalar data.
+// keep in sync with ../cmd/compile/internal/gc/reflect.go
+func typeptrdata(t *rtype) uintptr {
+	if !t.pointers() {
+		return 0
+	}
+	switch t.Kind() {
+	case Struct:
+		st := (*structType)(unsafe.Pointer(t))
+		// find the last field that has pointers.
+		field := 0
+		for i := range st.fields {
+			ft := st.fields[i].typ
+			if ft.pointers() {
+				field = i
+			}
+		}
+		f := st.fields[field]
+		return f.offset + f.typ.ptrdata
+
+	default:
+		panic("reflect.typeptrdata: unexpected type, " + t.String())
+	}
+}
+
 // See cmd/compile/internal/gc/reflect.go for derivation of constant.
 const maxPtrmaskBytes = 2048
 
@@ -1864,7 +2808,7 @@ func ArrayOf(count int, elem Type) Type {
 	}
 
 	// Look in known types.
-	s := "[" + strconv.Itoa(count) + "]" + *typ.string
+	s := "[" + strconv.Itoa(count) + "]" + typ.String()
 	for _, tt := range typesByString(s) {
 		array := (*arrayType)(unsafe.Pointer(tt))
 		if array.elem == typ {
@@ -1877,13 +2821,14 @@ func ArrayOf(count int, elem Type) Type {
 	prototype := *(**arrayType)(unsafe.Pointer(&iarray))
 	array := new(arrayType)
 	*array = *prototype
-	array.string = &s
+	array.str = resolveReflectName(newName(s, "", "", false))
 	array.hash = fnv1(typ.hash, '[')
 	for n := uint32(count); n > 0; n >>= 8 {
 		array.hash = fnv1(array.hash, byte(n))
 	}
 	array.hash = fnv1(array.hash, ']')
 	array.elem = typ
+	array.ptrToThis = 0
 	max := ^uintptr(0) / typ.size
 	if uintptr(count) > max {
 		panic("reflect.ArrayOf: array size would exceed virtual address space")
@@ -1894,8 +2839,6 @@ func ArrayOf(count int, elem Type) Type {
 	}
 	array.align = typ.align
 	array.fieldAlign = typ.fieldAlign
-	array.uncommonType = nil
-	array.ptrToThis = nil
 	array.len = uintptr(count)
 	array.slice = slice.(*rtype)
 
@@ -2061,7 +3004,7 @@ var layoutCache struct {
 // function arguments and return values for the function type t.
 // If rcvr != nil, rcvr specifies the type of the receiver.
 // 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
+// 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, stk *bitVector, framePool *sync.Pool) {
 	if t.Kind() != Func {
@@ -2097,7 +3040,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 		}
 		offset += ptrSize
 	}
-	for _, arg := range tt.in {
+	for _, arg := range tt.in() {
 		offset += -offset & uintptr(arg.align-1)
 		addTypeBits(ptrmap, offset, arg)
 		offset += arg.size
@@ -2109,7 +3052,7 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 	}
 	offset += -offset & (ptrSize - 1)
 	retOffset = offset
-	for _, res := range tt.out {
+	for _, res := range tt.out() {
 		offset += -offset & uintptr(res.align-1)
 		addTypeBits(ptrmap, offset, res)
 		offset += res.size
@@ -2133,11 +3076,11 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 
 	var s string
 	if rcvr != nil {
-		s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
+		s = "methodargs(" + rcvr.String() + ")(" + t.String() + ")"
 	} else {
-		s = "funcargs(" + *t.string + ")"
+		s = "funcargs(" + t.String() + ")"
 	}
-	x.string = &s
+	x.str = resolveReflectName(newName(s, "", "", false))
 
 	// cache result for future callers
 	if layoutCache.m == nil {
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 182c45a..e6b846e 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -11,14 +11,13 @@ import (
 )
 
 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.
 //
-// Not all methods apply to all kinds of values.  Restrictions,
+// Not all methods apply to all kinds of values. Restrictions,
 // if any, are noted in the documentation for each method.
 // Use the Kind method to find out the kind of value before
-// calling kind-specific methods.  Calling a method
+// calling kind-specific methods. Calling a method
 // inappropriate to the kind of type causes a run time panic.
 //
 // The zero Value represents no value.
@@ -57,7 +56,7 @@ type Value struct {
 	flag
 
 	// A method value represents a curried method invocation
-	// like r.Read for some receiver r.  The typ+val+flag bits describe
+	// like r.Read for some receiver r. The typ+val+flag bits describe
 	// the receiver r, but the flag's Kind bits say Func (methods are
 	// functions), and the top bits of the flag give the method number
 	// in r's type's method table.
@@ -115,14 +114,14 @@ func packEface(v Value) interface{} {
 		}
 		e.word = ptr
 	case v.flag&flagIndir != 0:
-		// Value is indirect, but interface is direct.  We need
+		// Value is indirect, but interface is direct. We need
 		// to load the data at v.ptr into the interface data word.
 		e.word = *(*unsafe.Pointer)(v.ptr)
 	default:
 		// Value is direct, and so is the interface.
 		e.word = v.ptr
 	}
-	// Now, fill in the type portion.  We're very careful here not
+	// Now, fill in the type portion. We're very careful here not
 	// to have any operation between the e.word and e.typ assignments
 	// that would let the garbage collector observe the partially-built
 	// interface value.
@@ -146,7 +145,7 @@ func unpackEface(i interface{}) Value {
 }
 
 // A ValueError occurs when a Value method is invoked on
-// a Value that does not support it.  Such cases are documented
+// a Value that does not support it. Such cases are documented
 // in the description of each method.
 type ValueError struct {
 	Method string
@@ -272,7 +271,7 @@ func (v Value) runes() []rune {
 }
 
 // CanAddr reports whether the value's address can be obtained with Addr.
-// Such values are called addressable.  A value is addressable if it is
+// 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.
 // If CanAddr returns false, calling Addr will panic.
@@ -483,9 +482,8 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 	// Copy argument frame into Values.
 	ptr := frame
 	off := uintptr(0)
-	in := make([]Value, 0, len(ftyp.in))
-	for _, arg := range ftyp.in {
-		typ := arg
+	in := make([]Value, 0, int(ftyp.inCount))
+	for _, typ := range ftyp.in() {
 		off += -off & uintptr(typ.align-1)
 		addr := unsafe.Pointer(uintptr(ptr) + off)
 		v := Value{typ, nil, flag(typ.Kind())}
@@ -506,18 +504,18 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 
 	// Call underlying function.
 	out := f(in)
-	if len(out) != len(ftyp.out) {
+	numOut := ftyp.NumOut()
+	if len(out) != numOut {
 		panic("reflect: wrong return count from function created by MakeFunc")
 	}
 
 	// Copy results back into argument frame.
-	if len(ftyp.out) > 0 {
+	if numOut > 0 {
 		off += -off & (ptrSize - 1)
 		if runtime.GOARCH == "amd64p32" {
 			off = align(off, 8)
 		}
-		for i, arg := range ftyp.out {
-			typ := arg
+		for i, typ := range ftyp.out() {
 			v := out[i]
 			if v.typ != typ {
 				panic("reflect: function created by MakeFunc using " + funcName(f) +
@@ -555,7 +553,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
 			panic("reflect: internal error: invalid method index")
 		}
 		m := &tt.methods[i]
-		if m.pkgPath != nil {
+		if !tt.nameOff(m.name).isExported() {
 			panic("reflect: " + op + " of unexported method")
 		}
 		iface := (*nonEmptyInterface)(v.ptr)
@@ -564,24 +562,25 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn
 		}
 		rcvrtype = iface.itab.typ
 		fn = unsafe.Pointer(&iface.itab.fun[i])
-		t = m.typ
+		t = tt.typeOff(m.typ)
 	} else {
 		rcvrtype = v.typ
 		ut := v.typ.uncommon()
-		if ut == nil || uint(i) >= uint(len(ut.methods)) {
+		if ut == nil || uint(i) >= uint(ut.mcount) {
 			panic("reflect: internal error: invalid method index")
 		}
-		m := &ut.methods[i]
-		if m.pkgPath != nil {
+		m := ut.methods()[i]
+		if !v.typ.nameOff(m.name).isExported() {
 			panic("reflect: " + op + " of unexported method")
 		}
-		fn = unsafe.Pointer(&m.ifn)
-		t = m.mtyp
+		ifn := v.typ.textOff(m.ifn)
+		fn = unsafe.Pointer(&ifn)
+		t = v.typ.typeOff(m.mtyp)
 	}
 	return
 }
 
-// v is a method receiver.  Store at p the word which is used to
+// v is a method receiver. Store at p the word which is used to
 // encode that receiver at the start of the argument list.
 // Reflect uses the "interface" calling convention for
 // methods, which always uses one word to record the receiver.
@@ -667,7 +666,7 @@ func (v Value) Cap() int {
 	case Array:
 		return v.typ.Len()
 	case Chan:
-		return int(chancap(v.pointer()))
+		return chancap(v.pointer())
 	case Slice:
 		// Slice is always bigger than a word; assume flagIndir.
 		return (*sliceHeader)(v.ptr).Cap
@@ -751,8 +750,8 @@ func (v Value) Field(i int) Value {
 	// Inherit permission bits from v, but clear flagEmbedRO.
 	fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
 	// Using an unexported field forces flagRO.
-	if field.pkgPath != nil {
-		if field.name == nil {
+	if !field.name.isExported() {
+		if field.name.name() == "" {
 			fl |= flagEmbedRO
 		} else {
 			fl |= flagStickyRO
@@ -886,7 +885,7 @@ func (v Value) Int() int64 {
 	case Int32:
 		return int64(*(*int32)(p))
 	case Int64:
-		return int64(*(*int64)(p))
+		return *(*int64)(p)
 	}
 	panic(&ValueError{"reflect.Value.Int", v.kind()})
 }
@@ -1025,9 +1024,9 @@ func (v Value) MapIndex(key Value) Value {
 
 	// Do not require key to be exported, so that DeepEqual
 	// and other programs can use all the keys returned by
-	// MapKeys as arguments to MapIndex.  If either the map
+	// MapKeys as arguments to MapIndex. If either the map
 	// or the key is unexported, though, the result will be
-	// considered unexported.  This is consistent with the
+	// considered unexported. This is consistent with the
 	// behavior for structs, which allow read but not write
 	// of unexported fields.
 	key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
@@ -1079,7 +1078,7 @@ func (v Value) MapKeys() []Value {
 		key := mapiterkey(it)
 		if key == nil {
 			// Someone deleted an entry from the map since we
-			// called maplen above.  It's a data race, but nothing
+			// called maplen above. It's a data race, but nothing
 			// we can do about it.
 			break
 		}
@@ -1226,7 +1225,7 @@ func (v Value) OverflowUint(x uint64) bool {
 // result is zero if and only if v is a nil func Value.
 //
 // If v's Kind is Slice, the returned pointer is to the first
-// element of the slice.  If the slice is nil the returned value
+// element of the slice. If the slice is nil the returned value
 // is 0.  If the slice is empty but non-nil the return value is non-zero.
 func (v Value) Pointer() uintptr {
 	// TODO: deprecate
@@ -1437,7 +1436,7 @@ func (v Value) SetCap(n int) {
 	v.mustBeAssignable()
 	v.mustBe(Slice)
 	s := (*sliceHeader)(v.ptr)
-	if n < int(s.Len) || n > int(s.Cap) {
+	if n < s.Len || n > s.Cap {
 		panic("reflect: slice capacity out of range in SetCap")
 	}
 	s.Cap = n
@@ -1539,7 +1538,7 @@ func (v Value) Slice(i, j int) Value {
 	case Slice:
 		typ = (*sliceType)(unsafe.Pointer(v.typ))
 		s := (*sliceHeader)(v.ptr)
-		base = unsafe.Pointer(s.Data)
+		base = s.Data
 		cap = s.Cap
 
 	case String:
@@ -1685,15 +1684,15 @@ func (v Value) Type() Type {
 			panic("reflect: internal error: invalid method index")
 		}
 		m := &tt.methods[i]
-		return m.typ
+		return v.typ.typeOff(m.typ)
 	}
 	// Method on concrete type.
 	ut := v.typ.uncommon()
-	if ut == nil || uint(i) >= uint(len(ut.methods)) {
+	if ut == nil || uint(i) >= uint(ut.mcount) {
 		panic("reflect: internal error: invalid method index")
 	}
-	m := &ut.methods[i]
-	return m.mtyp
+	m := ut.methods()[i]
+	return v.typ.typeOff(m.mtyp)
 }
 
 // Uint returns v's underlying value, as a uint64.
@@ -1711,7 +1710,7 @@ func (v Value) Uint() uint64 {
 	case Uint32:
 		return uint64(*(*uint32)(p))
 	case Uint64:
-		return uint64(*(*uint64)(p))
+		return *(*uint64)(p)
 	case Uintptr:
 		return uint64(*(*uintptr)(p))
 	}
@@ -1877,13 +1876,13 @@ func Copy(dst, src Value) int {
 // A runtimeSelect is a single case passed to rselect.
 // This must match ../runtime/select.go:/runtimeSelect
 type runtimeSelect struct {
-	dir uintptr        // 0, SendDir, or RecvDir
+	dir SelectDir      // SelectSend, SelectRecv or SelectDefault
 	typ *rtype         // channel type
 	ch  unsafe.Pointer // channel
 	val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir)
 }
 
-// rselect runs a select.  It returns the index of the chosen case.
+// rselect runs a select. It returns the index of the chosen case.
 // If the case was a receive, val is filled in with the received value.
 // The conventional OK bool indicates whether the receive corresponds
 // to a sent value.
@@ -1940,7 +1939,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
 	haveDefault := false
 	for i, c := range cases {
 		rc := &runcases[i]
-		rc.dir = uintptr(c.Dir)
+		rc.dir = c.Dir
 		switch c.Dir {
 		default:
 			panic("reflect.Select: invalid Dir")
@@ -2003,7 +2002,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
 	}
 
 	chosen, recvOK = rselect(runcases)
-	if runcases[chosen].dir == uintptr(SelectRecv) {
+	if runcases[chosen].dir == SelectRecv {
 		tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
 		t := tt.elem
 		p := runcases[chosen].val
@@ -2080,14 +2079,14 @@ func Indirect(v Value) Value {
 }
 
 // ValueOf returns a new Value initialized to the concrete value
-// stored in the interface i.  ValueOf(nil) returns the zero Value.
+// stored in the interface i. ValueOf(nil) returns the zero Value.
 func ValueOf(i interface{}) Value {
 	if i == nil {
 		return Value{}
 	}
 
 	// TODO: Maybe allow contents of a Value to live on the stack.
-	// For now we make the contents always escape to the heap.  It
+	// For now we make the contents always escape to the heap. It
 	// makes life easier in a few places (see chanrecv/mapassign
 	// comment below).
 	escapes(i)
@@ -2113,7 +2112,7 @@ func Zero(typ Type) Value {
 }
 
 // New returns a Value representing a pointer to a new zero value
-// for the specified type.  That is, the returned Value's Type is PtrTo(typ).
+// for the specified type. That is, the returned Value's Type is PtrTo(typ).
 func New(typ Type) Value {
 	if typ == nil {
 		panic("reflect: New(nil)")
@@ -2268,13 +2267,13 @@ func makeInt(f flag, bits uint64, t Type) Value {
 	ptr := unsafe_New(typ)
 	switch typ.size {
 	case 1:
-		*(*uint8)(unsafe.Pointer(ptr)) = uint8(bits)
+		*(*uint8)(ptr) = uint8(bits)
 	case 2:
-		*(*uint16)(unsafe.Pointer(ptr)) = uint16(bits)
+		*(*uint16)(ptr) = uint16(bits)
 	case 4:
-		*(*uint32)(unsafe.Pointer(ptr)) = uint32(bits)
+		*(*uint32)(ptr) = uint32(bits)
 	case 8:
-		*(*uint64)(unsafe.Pointer(ptr)) = bits
+		*(*uint64)(ptr) = bits
 	}
 	return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
 }
@@ -2286,9 +2285,9 @@ func makeFloat(f flag, v float64, t Type) Value {
 	ptr := unsafe_New(typ)
 	switch typ.size {
 	case 4:
-		*(*float32)(unsafe.Pointer(ptr)) = float32(v)
+		*(*float32)(ptr) = float32(v)
 	case 8:
-		*(*float64)(unsafe.Pointer(ptr)) = v
+		*(*float64)(ptr) = v
 	}
 	return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
 }
@@ -2300,9 +2299,9 @@ func makeComplex(f flag, v complex128, t Type) Value {
 	ptr := unsafe_New(typ)
 	switch typ.size {
 	case 8:
-		*(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
+		*(*complex64)(ptr) = complex64(v)
 	case 16:
-		*(*complex128)(unsafe.Pointer(ptr)) = v
+		*(*complex128)(ptr) = v
 	}
 	return Value{typ, ptr, f | flagIndir | flag(typ.Kind())}
 }
@@ -2446,7 +2445,7 @@ func chanclose(ch unsafe.Pointer)
 func chanlen(ch unsafe.Pointer) int
 
 // Note: some of the noescape annotations below are technically a lie,
-// but safe in the context of this package.  Functions like chansend
+// but safe in the context of this package. Functions like chansend
 // and mapassign don't escape the referent, but may escape anything
 // the referent points to (they do shallow copies of the referent).
 // It is safe in this package because the referent may only point
diff --git a/src/regexp/backtrack.go b/src/regexp/backtrack.go
index fd95604..29f624b 100644
--- a/src/regexp/backtrack.go
+++ b/src/regexp/backtrack.go
@@ -36,7 +36,6 @@ type bitState struct {
 
 	end     int
 	cap     []int
-	input   input
 	jobs    []job
 	visited []uint32
 }
@@ -146,7 +145,7 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
 		// 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
+		// and jumps to CheckAndLoop. We have to
 		// do the ShouldVisit check that Push
 		// would have, but we avoid the stack
 		// manipulation.
@@ -254,7 +253,6 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
 
 			}
 			panic("bad arg in InstCapture")
-			continue
 
 		case syntax.InstEmptyWidth:
 			if syntax.EmptyOp(inst.Arg)&^i.context(pos) != 0 {
@@ -299,7 +297,6 @@ func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
 			// Otherwise, continue on in hope of a longer match.
 			continue
 		}
-		panic("unreachable")
 	}
 
 	return m.matched
diff --git a/src/regexp/exec.go b/src/regexp/exec.go
index 5182720..4fd61b5 100644
--- a/src/regexp/exec.go
+++ b/src/regexp/exec.go
@@ -19,7 +19,7 @@ type queue struct {
 // A entry is an entry on a queue.
 // It holds both the instruction pc and the actual thread.
 // Some queue entries are just place holders so that the machine
-// knows it has considered that pc.  Such entries have t == nil.
+// knows it has considered that pc. Such entries have t == nil.
 type entry struct {
 	pc uint32
 	t  *thread
@@ -107,14 +107,6 @@ func (m *machine) alloc(i *syntax.Inst) *thread {
 	return t
 }
 
-// free returns t to the free pool.
-func (m *machine) free(t *thread) {
-	m.inputBytes.str = nil
-	m.inputString.str = ""
-	m.inputReader.r = nil
-	m.pool = append(m.pool, t)
-}
-
 // match runs the machine over the input starting at pos.
 // It reports whether a match was found.
 // If so, m.matchcap holds the submatch information.
@@ -192,7 +184,6 @@ func (m *machine) match(i input, pos int) bool {
 func (m *machine) clear(q *queue) {
 	for _, d := range q.dense {
 		if d.t != nil {
-			// m.free(d.t)
 			m.pool = append(m.pool, d.t)
 		}
 	}
@@ -213,7 +204,6 @@ func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond sy
 			continue
 		}
 		if longest && m.matched && len(t.cap) > 0 && m.matchcap[0] < t.cap[0] {
-			// m.free(t)
 			m.pool = append(m.pool, t)
 			continue
 		}
@@ -232,7 +222,6 @@ func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond sy
 				// First-match mode: cut off all lower-priority threads.
 				for _, d := range runq.dense[j+1:] {
 					if d.t != nil {
-						// m.free(d.t)
 						m.pool = append(m.pool, d.t)
 					}
 				}
@@ -253,7 +242,6 @@ func (m *machine) step(runq, nextq *queue, pos, nextPos int, c rune, nextCond sy
 			t = m.add(nextq, i.Out, nextPos, t.cap, nextCond, t)
 		}
 		if t != nil {
-			// m.free(t)
 			m.pool = append(m.pool, t)
 		}
 	}
diff --git a/src/regexp/exec_test.go b/src/regexp/exec_test.go
index 4872cb3..69f187e 100644
--- a/src/regexp/exec_test.go
+++ b/src/regexp/exec_test.go
@@ -22,7 +22,7 @@ import (
 // considered during RE2's exhaustive tests, which run all possible
 // regexps over a given set of atoms and operators, up to a given
 // complexity, over all possible strings over a given alphabet,
-// up to a given size.  Rather than try to link with RE2, we read a
+// 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-exhaustive.txt, is generated by running 'make log'
 // in the open source RE2 distribution https://github.com/google/re2/.
@@ -41,21 +41,21 @@ import (
 //	-;0-3 0-1 1-2 2-3
 //
 // The stanza begins by defining a set of strings, quoted
-// using Go double-quote syntax, one per line.  Then the
+// using Go double-quote syntax, one per line. Then the
 // regexps section gives a sequence of regexps to run on
-// the strings.  In the block that follows a regexp, each line
+// the strings. In the block that follows a regexp, each line
 // gives the semicolon-separated match results of running
 // the regexp on the corresponding string.
 // Each match result is either a single -, meaning no match, or a
 // space-separated sequence of pairs giving the match and
-// submatch indices.  An unmatched subexpression formats
+// submatch indices. An unmatched subexpression formats
 // its pair as a single - (not illustrated above).  For now
 // each regexp run produces two match results, one for a
 // ``full match'' that restricts the regexp to matching the entire
 // string or nothing, and one for a ``partial match'' that gives
 // the leftmost first match found in the string.
 //
-// Lines beginning with # are comments.  Lines beginning with
+// Lines beginning with # are comments. Lines beginning with
 // a capital letter are test names printed during RE2's test suite
 // and are echoed into t but otherwise ignored.
 //
@@ -155,9 +155,9 @@ func testRE2(t *testing.T, file string) {
 			if !isSingleBytes(text) && strings.Contains(re.String(), `\B`) {
 				// RE2's \B considers every byte position,
 				// so it sees 'not word boundary' in the
-				// middle of UTF-8 sequences.  This package
+				// middle of UTF-8 sequences. This package
 				// only considers the positions between runes,
-				// so it disagrees.  Skip those cases.
+				// so it disagrees. Skip those cases.
 				continue
 			}
 			res := strings.Split(line, ";")
@@ -409,7 +409,7 @@ Reading:
 		//     h	REG_MULTIREF		multiple digit backref
 		//     i	REG_ICASE		ignore case
 		//     j	REG_SPAN		. matches \n
-		//     k	REG_ESCAPE		\ to ecape [...] delimiter
+		//     k	REG_ESCAPE		\ to escape [...] delimiter
 		//     l	REG_LEFT		implicit ^...
 		//     m	REG_MINIMAL		minimal match
 		//     n	REG_NEWLINE		explicit \n match
@@ -658,47 +658,42 @@ func makeText(n int) []byte {
 	return text
 }
 
-func benchmark(b *testing.B, re string, n int) {
-	r := MustCompile(re)
-	t := makeText(n)
-	b.ResetTimer()
-	b.SetBytes(int64(n))
-	for i := 0; i < b.N; i++ {
-		if r.Match(t) {
-			b.Fatal("match!")
+func BenchmarkMatch(b *testing.B) {
+	for _, data := range benchData {
+		r := MustCompile(data.re)
+		for _, size := range benchSizes {
+			t := makeText(size.n)
+			b.Run(data.name+"/"+size.name, func(b *testing.B) {
+				b.SetBytes(int64(size.n))
+				for i := 0; i < b.N; i++ {
+					if r.Match(t) {
+						b.Fatal("match!")
+					}
+				}
+			})
 		}
 	}
 }
 
-const (
-	easy0  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
-	easy1  = "A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$"
-	medium = "[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
-	hard   = "[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
-	parens = "([ -~])*(A)(B)(C)(D)(E)(F)(G)(H)(I)(J)(K)(L)(M)" +
-		"(N)(O)(P)(Q)(R)(S)(T)(U)(V)(W)(X)(Y)(Z)$"
-)
+var benchData = []struct{ name, re string }{
+	{"Easy0", "ABCDEFGHIJKLMNOPQRSTUVWXYZ$"},
+	{"Easy0i", "(?i)ABCDEFGHIJklmnopqrstuvwxyz$"},
+	{"Easy1", "A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$"},
+	{"Medium", "[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$"},
+	{"Hard", "[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$"},
+	{"Hard1", "ABCD|CDEF|EFGH|GHIJ|IJKL|KLMN|MNOP|OPQR|QRST|STUV|UVWX|WXYZ"},
+}
 
-func BenchmarkMatchEasy0_32(b *testing.B)   { benchmark(b, easy0, 32<<0) }
-func BenchmarkMatchEasy0_1K(b *testing.B)   { benchmark(b, easy0, 1<<10) }
-func BenchmarkMatchEasy0_32K(b *testing.B)  { benchmark(b, easy0, 32<<10) }
-func BenchmarkMatchEasy0_1M(b *testing.B)   { benchmark(b, easy0, 1<<20) }
-func BenchmarkMatchEasy0_32M(b *testing.B)  { benchmark(b, easy0, 32<<20) }
-func BenchmarkMatchEasy1_32(b *testing.B)   { benchmark(b, easy1, 32<<0) }
-func BenchmarkMatchEasy1_1K(b *testing.B)   { benchmark(b, easy1, 1<<10) }
-func BenchmarkMatchEasy1_32K(b *testing.B)  { benchmark(b, easy1, 32<<10) }
-func BenchmarkMatchEasy1_1M(b *testing.B)   { benchmark(b, easy1, 1<<20) }
-func BenchmarkMatchEasy1_32M(b *testing.B)  { benchmark(b, easy1, 32<<20) }
-func BenchmarkMatchMedium_32(b *testing.B)  { benchmark(b, medium, 32<<0) }
-func BenchmarkMatchMedium_1K(b *testing.B)  { benchmark(b, medium, 1<<10) }
-func BenchmarkMatchMedium_32K(b *testing.B) { benchmark(b, medium, 32<<10) }
-func BenchmarkMatchMedium_1M(b *testing.B)  { benchmark(b, medium, 1<<20) }
-func BenchmarkMatchMedium_32M(b *testing.B) { benchmark(b, medium, 32<<20) }
-func BenchmarkMatchHard_32(b *testing.B)    { benchmark(b, hard, 32<<0) }
-func BenchmarkMatchHard_1K(b *testing.B)    { benchmark(b, hard, 1<<10) }
-func BenchmarkMatchHard_32K(b *testing.B)   { benchmark(b, hard, 32<<10) }
-func BenchmarkMatchHard_1M(b *testing.B)    { benchmark(b, hard, 1<<20) }
-func BenchmarkMatchHard_32M(b *testing.B)   { benchmark(b, hard, 32<<20) }
+var benchSizes = []struct {
+	name string
+	n    int
+}{
+	{"32", 32},
+	{"1K", 1 << 10},
+	{"32K", 32 << 10},
+	{"1M", 1 << 20},
+	{"32M", 32 << 20},
+}
 
 func TestLongest(t *testing.T) {
 	re, err := Compile(`a(|b)`)
diff --git a/src/regexp/onepass.go b/src/regexp/onepass.go
index 2ce3902..4991954 100644
--- a/src/regexp/onepass.go
+++ b/src/regexp/onepass.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -33,7 +33,7 @@ type onePassInst struct {
 }
 
 // OnePassPrefix returns a literal string that all matches for the
-// regexp must start with.  Complete is true if the prefix
+// regexp must start with. Complete is true if the prefix
 // is the entire match. Pc is the index of the last rune instruction
 // in the string. The OnePassPrefix skips over the mandatory
 // EmptyBeginText
@@ -450,7 +450,7 @@ func makeOnePass(p *onePassProg) *onePassProg {
 	for !instQueue.empty() {
 		visitQueue.clear()
 		pc := instQueue.next()
-		if !check(uint32(pc), m) {
+		if !check(pc, m) {
 			p = notOnePass
 			break
 		}
diff --git a/src/regexp/onepass_test.go b/src/regexp/onepass_test.go
index 8202ebe..f4e336c 100644
--- a/src/regexp/onepass_test.go
+++ b/src/regexp/onepass_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -133,8 +133,6 @@ func TestMergeRuneSet(t *testing.T) {
 	}
 }
 
-const noStr = `!`
-
 var onePass = &onePassProg{}
 
 var onePassTests = []struct {
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index d7d0edb..fe3db9f 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -22,14 +22,14 @@
 // All characters are UTF-8-encoded code points.
 //
 // There are 16 methods of Regexp that match a regular expression and identify
-// the matched text.  Their names are matched by this regular expression:
+// the matched text. Their names are matched by this regular expression:
 //
 //	Find(All)?(String)?(Submatch)?(Index)?
 //
 // If 'All' is present, the routine matches successive non-overlapping
-// matches of the entire expression.  Empty matches abutting a preceding
-// match are ignored.  The return value is a slice containing the successive
-// return values of the corresponding non-'All' routine.  These routines take
+// matches of the entire expression. Empty matches abutting a preceding
+// match are ignored. The return value is a slice containing the successive
+// return values of the corresponding non-'All' routine. These routines take
 // an extra integer argument, n; if n >= 0, the function returns at most n
 // matches/submatches.
 //
@@ -45,9 +45,9 @@
 //
 // If 'Index' is present, matches and submatches are identified by byte index
 // pairs within the input string: result[2*n:2*n+1] identifies the indexes of
-// the nth submatch.  The pair for n==0 identifies the match of the entire
-// expression.  If 'Index' is not present, the match is identified by the
-// text of the match/submatch.  If an index is negative, it means that
+// the nth submatch. The pair for n==0 identifies the match of the entire
+// expression. If 'Index' is not present, the match is identified by the
+// text of the match/submatch. If an index is negative, it means that
 // subexpression did not match any string in the input.
 //
 // There is also a subset of the methods that can be applied to text read
@@ -55,7 +55,7 @@
 //
 //	MatchReader, FindReaderIndex, FindReaderSubmatchIndex
 //
-// This set may grow.  Note that regular expression matches may need to
+// This set may grow. Note that regular expression matches may need to
 // examine text beyond the text returned by a match, so the methods that
 // match text from a RuneReader may read arbitrarily far into the input
 // before returning.
@@ -75,12 +75,18 @@ import (
 	"unicode/utf8"
 )
 
-var debug = false
-
 // Regexp is the representation of a compiled regular expression.
 // A Regexp is safe for concurrent use by multiple goroutines.
 type Regexp struct {
 	// read-only after Compile
+	regexpRO
+
+	// cache of machines for running regexp
+	mu      sync.Mutex
+	machine []*machine
+}
+
+type regexpRO struct {
 	expr           string         // as passed to Compile
 	prog           *syntax.Prog   // compiled program
 	onepass        *onePassProg   // onepass program or nil
@@ -93,10 +99,6 @@ type Regexp struct {
 	numSubexp      int
 	subexpNames    []string
 	longest        bool
-
-	// cache of machines for running regexp
-	mu      sync.Mutex
-	machine []*machine
 }
 
 // String returns the source text used to compile the regular expression.
@@ -109,10 +111,11 @@ func (re *Regexp) String() string {
 // When using a Regexp in multiple goroutines, giving each goroutine
 // its own copy helps to avoid lock contention.
 func (re *Regexp) Copy() *Regexp {
-	r := *re
-	r.mu = sync.Mutex{}
-	r.machine = nil
-	return &r
+	// It is not safe to copy Regexp by value
+	// since it contains a sync.Mutex.
+	return &Regexp{
+		regexpRO: re.regexpRO,
+	}
 }
 
 // Compile parses a regular expression and returns, if successful,
@@ -174,13 +177,15 @@ func compile(expr string, mode syntax.Flags, longest bool) (*Regexp, error) {
 		return nil, err
 	}
 	regexp := &Regexp{
-		expr:        expr,
-		prog:        prog,
-		onepass:     compileOnePass(prog),
-		numSubexp:   maxCap,
-		subexpNames: capNames,
-		cond:        prog.StartCond(),
-		longest:     longest,
+		regexpRO: regexpRO{
+			expr:        expr,
+			prog:        prog,
+			onepass:     compileOnePass(prog),
+			numSubexp:   maxCap,
+			subexpNames: capNames,
+			cond:        prog.StartCond(),
+			longest:     longest,
+		},
 	}
 	if regexp.onepass == notOnePass {
 		regexp.prefix, regexp.prefixComplete = prog.Prefix()
@@ -258,10 +263,10 @@ func (re *Regexp) NumSubexp() int {
 }
 
 // SubexpNames returns the names of the parenthesized subexpressions
-// in this Regexp.  The name for the first sub-expression is names[1],
+// in this Regexp. The name for the first sub-expression is names[1],
 // so that if m is a match slice, the name for m[i] is SubexpNames()[i].
 // Since the Regexp as a whole cannot be named, names[0] is always
-// the empty string.  The slice should not be modified.
+// the empty string. The slice should not be modified.
 func (re *Regexp) SubexpNames() []string {
 	return re.subexpNames
 }
@@ -394,7 +399,7 @@ func (i *inputReader) context(pos int) syntax.EmptyOp {
 }
 
 // LiteralPrefix returns a literal string that must begin any match
-// of the regular expression re.  It returns the boolean true if the
+// of the regular expression re. It returns the boolean true if the
 // literal string comprises the entire regular expression.
 func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
 	return re.prefix, re.prefixComplete
@@ -417,7 +422,7 @@ func (re *Regexp) Match(b []byte) bool {
 }
 
 // MatchReader checks whether a textual regular expression matches the text
-// read by the RuneReader.  More complicated queries need to use Compile and
+// read by the RuneReader. More complicated queries need to use Compile and
 // the full Regexp interface.
 func MatchReader(pattern string, r io.RuneReader) (matched bool, err error) {
 	re, err := Compile(pattern)
@@ -428,7 +433,7 @@ func MatchReader(pattern string, r io.RuneReader) (matched bool, err error) {
 }
 
 // MatchString checks whether a textual regular expression
-// matches a string.  More complicated queries need
+// matches a string. More complicated queries need
 // to use Compile and the full Regexp interface.
 func MatchString(pattern string, s string) (matched bool, err error) {
 	re, err := Compile(pattern)
@@ -439,7 +444,7 @@ func MatchString(pattern string, s string) (matched bool, err error) {
 }
 
 // Match checks whether a textual regular expression
-// matches a byte slice.  More complicated queries need
+// matches a byte slice. More complicated queries need
 // to use Compile and the full Regexp interface.
 func Match(pattern string, b []byte) (matched bool, err error) {
 	re, err := Compile(pattern)
@@ -450,11 +455,11 @@ func Match(pattern string, b []byte) (matched bool, err error) {
 }
 
 // ReplaceAllString returns a copy of src, replacing matches of the Regexp
-// with the replacement string repl.  Inside repl, $ signs are interpreted as
+// with the replacement string repl. Inside repl, $ signs are interpreted as
 // in Expand, so for instance $1 represents the text of the first submatch.
 func (re *Regexp) ReplaceAllString(src, repl string) string {
 	n := 2
-	if strings.Index(repl, "$") >= 0 {
+	if strings.Contains(repl, "$") {
 		n = 2 * (re.numSubexp + 1)
 	}
 	b := re.replaceAll(nil, src, n, func(dst []byte, match []int) []byte {
@@ -464,7 +469,7 @@ func (re *Regexp) ReplaceAllString(src, repl string) string {
 }
 
 // ReplaceAllLiteralString returns a copy of src, replacing matches of the Regexp
-// with the replacement string repl.  The replacement repl is substituted directly,
+// with the replacement string repl. The replacement repl is substituted directly,
 // without using Expand.
 func (re *Regexp) ReplaceAllLiteralString(src, repl string) string {
 	return string(re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte {
@@ -474,7 +479,7 @@ func (re *Regexp) ReplaceAllLiteralString(src, repl string) string {
 
 // ReplaceAllStringFunc returns a copy of src in which all matches of the
 // Regexp have been replaced by the return value of function repl applied
-// to the matched substring.  The replacement returned by repl is substituted
+// to the matched substring. The replacement returned by repl is substituted
 // directly, without using Expand.
 func (re *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
 	b := re.replaceAll(nil, src, 2, func(dst []byte, match []int) []byte {
@@ -530,7 +535,7 @@ func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst
 			searchPos += width
 		} else if searchPos+1 > a[1] {
 			// This clause is only needed at the end of the input
-			// string.  In that case, DecodeRuneInString returns width=0.
+			// string. In that case, DecodeRuneInString returns width=0.
 			searchPos++
 		} else {
 			searchPos = a[1]
@@ -548,7 +553,7 @@ func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst
 }
 
 // ReplaceAll returns a copy of src, replacing matches of the Regexp
-// with the replacement text repl.  Inside repl, $ signs are interpreted as
+// with the replacement text repl. Inside repl, $ signs are interpreted as
 // in Expand, so for instance $1 represents the text of the first submatch.
 func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
 	n := 2
@@ -566,7 +571,7 @@ func (re *Regexp) ReplaceAll(src, repl []byte) []byte {
 }
 
 // ReplaceAllLiteral returns a copy of src, replacing matches of the Regexp
-// with the replacement bytes repl.  The replacement repl is substituted directly,
+// with the replacement bytes repl. The replacement repl is substituted directly,
 // without using Expand.
 func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte {
 	return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte {
@@ -576,7 +581,7 @@ func (re *Regexp) ReplaceAllLiteral(src, repl []byte) []byte {
 
 // ReplaceAllFunc returns a copy of src in which all matches of the
 // Regexp have been replaced by the return value of function repl applied
-// to the matched byte slice.  The replacement returned by repl is substituted
+// to the matched byte slice. The replacement returned by repl is substituted
 // directly, without using Expand.
 func (re *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
 	return re.replaceAll(src, "", 2, func(dst []byte, match []int) []byte {
@@ -592,7 +597,7 @@ func special(b byte) bool {
 
 // QuoteMeta returns a string that quotes all regular expression metacharacters
 // inside the argument text; the returned string is a regular expression matching
-// the literal text.  For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
+// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
 func QuoteMeta(s string) string {
 	b := make([]byte, 2*len(s))
 
@@ -684,7 +689,7 @@ func (re *Regexp) Find(b []byte) []byte {
 }
 
 // FindIndex returns a two-element slice of integers defining the location of
-// the leftmost match in b of the regular expression.  The match itself is at
+// the leftmost match in b of the regular expression. The match itself is at
 // b[loc[0]:loc[1]].
 // A return value of nil indicates no match.
 func (re *Regexp) FindIndex(b []byte) (loc []int) {
@@ -696,9 +701,9 @@ func (re *Regexp) FindIndex(b []byte) (loc []int) {
 }
 
 // FindString returns a string holding the text of the leftmost match in s of the regular
-// expression.  If there is no match, the return value is an empty string,
+// expression. If there is no match, the return value is an empty string,
 // but it will also be empty if the regular expression successfully matches
-// an empty string.  Use FindStringIndex or FindStringSubmatch if it is
+// an empty string. Use FindStringIndex or FindStringSubmatch if it is
 // necessary to distinguish these cases.
 func (re *Regexp) FindString(s string) string {
 	a := re.doExecute(nil, nil, s, 0, 2)
@@ -709,7 +714,7 @@ func (re *Regexp) FindString(s string) string {
 }
 
 // FindStringIndex returns a two-element slice of integers defining the
-// location of the leftmost match in s of the regular expression.  The match
+// location of the leftmost match in s of the regular expression. The match
 // itself is at s[loc[0]:loc[1]].
 // A return value of nil indicates no match.
 func (re *Regexp) FindStringIndex(s string) (loc []int) {
@@ -722,7 +727,7 @@ func (re *Regexp) FindStringIndex(s string) (loc []int) {
 
 // FindReaderIndex returns a two-element slice of integers defining the
 // location of the leftmost match of the regular expression in text read from
-// the RuneReader.  The match text was found in the input stream at
+// the RuneReader. The match text was found in the input stream at
 // byte offset loc[0] through loc[1]-1.
 // A return value of nil indicates no match.
 func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int) {
@@ -754,14 +759,14 @@ func (re *Regexp) FindSubmatch(b []byte) [][]byte {
 
 // Expand appends template to dst and returns the result; during the
 // append, Expand replaces variables in the template with corresponding
-// matches drawn from src.  The match slice should have been returned by
+// matches drawn from src. The match slice should have been returned by
 // FindSubmatchIndex.
 //
 // In the template, a variable is denoted by a substring of the form
 // $name or ${name}, where name is a non-empty sequence of letters,
-// digits, and underscores.  A purely numeric name like $1 refers to
+// digits, and underscores. A purely numeric name like $1 refers to
 // the submatch with the corresponding index; other names refer to
-// capturing parentheses named with the (?P<name>...) syntax.  A
+// capturing parentheses named with the (?P<name>...) syntax. A
 // reference to an out of range or unmatched index or a name that is not
 // present in the regular expression is replaced with an empty slice.
 //
@@ -920,7 +925,7 @@ func (re *Regexp) FindStringSubmatchIndex(s string) []int {
 // FindReaderSubmatchIndex returns a slice holding the index pairs
 // identifying the leftmost match of the regular expression of text read by
 // the RuneReader, and the matches, if any, of its subexpressions, as defined
-// by the 'Submatch' and 'Index' descriptions in the package comment.  A
+// by the 'Submatch' and 'Index' descriptions in the package comment. A
 // return value of nil indicates no match.
 func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int {
 	return re.pad(re.doExecute(r, nil, "", 0, re.prog.NumCap))
diff --git a/src/regexp/syntax/compile.go b/src/regexp/syntax/compile.go
index 95f6f15..83e53ba 100644
--- a/src/regexp/syntax/compile.go
+++ b/src/regexp/syntax/compile.go
@@ -8,11 +8,11 @@ import "unicode"
 
 // A patchList is a list of instruction pointers that need to be filled in (patched).
 // Because the pointers haven't been filled in yet, we can reuse their storage
-// to hold the list.  It's kind of sleazy, but works well in practice.
+// to hold the list. It's kind of sleazy, but works well in practice.
 // See http://swtch.com/~rsc/regexp/regexp1.html for inspiration.
 //
 // These aren't really pointers: they're integers, so we can reinterpret them
-// this way without using package unsafe.  A value l denotes
+// this way without using package unsafe. A value l denotes
 // p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1).
 // l == 0 denotes the empty list, okay because we start every program
 // with a fail instruction, so we'll never want to point at its output link.
diff --git a/src/regexp/syntax/doc.go b/src/regexp/syntax/doc.go
index e5e71f1..efc0b43 100644
--- a/src/regexp/syntax/doc.go
+++ b/src/regexp/syntax/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -66,7 +66,7 @@ Grouping:
 
 Empty strings:
   ^              at beginning of text or line (flag m=true)
-  $              at end of text (like \z not \Z) or line (flag m=true)
+  $              at end of text (like \z not Perl's \Z) or line (flag m=true)
   \A             at beginning of text
   \b             at ASCII word boundary (\w on one side and \W, \A, or \z on the other)
   \B             not at ASCII word boundary
diff --git a/src/regexp/syntax/make_perl_groups.pl b/src/regexp/syntax/make_perl_groups.pl
index 90040fc..dc6d232 100755
--- a/src/regexp/syntax/make_perl_groups.pl
+++ b/src/regexp/syntax/make_perl_groups.pl
@@ -1,5 +1,5 @@
 #!/usr/bin/perl
-# Copyright 2008 The Go Authors.  All rights reserved.
+# Copyright 2008 The Go 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/regexp/syntax/parse.go b/src/regexp/syntax/parse.go
index f38bbf6..7b8be55 100644
--- a/src/regexp/syntax/parse.go
+++ b/src/regexp/syntax/parse.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -141,9 +141,9 @@ func (p *parser) push(re *Regexp) *Regexp {
 }
 
 // maybeConcat implements incremental concatenation
-// of literal runes into string nodes.  The parser calls this
+// of literal runes into string nodes. The parser calls this
 // before each push, so only the top fragment of the stack
-// might need processing.  Since this is called before a push,
+// might need processing. Since this is called before a push,
 // the topmost literal is no longer subject to operators like *
 // (Otherwise ab* would turn into (ab)*.)
 // If r >= 0 and there's a node left over, maybeConcat uses it
@@ -600,7 +600,7 @@ func (p *parser) leadingString(re *Regexp) ([]rune, Flags) {
 }
 
 // removeLeadingString removes the first n leading runes
-// from the beginning of re.  It returns the replacement for re.
+// from the beginning of re. It returns the replacement for re.
 func (p *parser) removeLeadingString(re *Regexp, n int) *Regexp {
 	if re.Op == OpConcat && len(re.Sub) > 0 {
 		// Removing a leading string in a concatenation
@@ -957,11 +957,11 @@ func (p *parser) parsePerlFlags(s string) (rest string, err error) {
 	// Perl 5.10 gave in and implemented the Python version too,
 	// but they claim that the last two are the preferred forms.
 	// PCRE and languages based on it (specifically, PHP and Ruby)
-	// support all three as well.  EcmaScript 4 uses only the Python form.
+	// support all three as well. EcmaScript 4 uses only the Python form.
 	//
 	// In both the open source world (via Code Search) and the
 	// Google source tree, (?P<expr>name) is the dominant form,
-	// so that's the one we implement.  One is enough.
+	// so that's the one we implement. One is enough.
 	if len(t) > 4 && t[2] == 'P' && t[3] == '<' {
 		// Pull out name.
 		end := strings.IndexRune(t, '>')
@@ -989,7 +989,7 @@ func (p *parser) parsePerlFlags(s string) (rest string, err error) {
 		return t[end+1:], nil
 	}
 
-	// Non-capturing group.  Might also twiddle Perl flags.
+	// Non-capturing group. Might also twiddle Perl flags.
 	var c rune
 	t = t[2:] // skip (?
 	flags := p.flags
@@ -1257,7 +1257,7 @@ Switch:
 		if c < utf8.RuneSelf && !isalnum(c) {
 			// Escaped non-word characters are always themselves.
 			// PCRE is not quite so rigorous: it accepts things like
-			// \q, but we don't.  We once rejected \_, but too many
+			// \q, but we don't. We once rejected \_, but too many
 			// programs and people insist on using it, so allow \_.
 			return c, t, nil
 		}
@@ -1292,7 +1292,7 @@ Switch:
 		if c == '{' {
 			// Any number of digits in braces.
 			// Perl accepts any text at all; it ignores all text
-			// after the first non-hex digit.  We require only hex digits,
+			// after the first non-hex digit. We require only hex digits,
 			// and at least one.
 			nhex := 0
 			r = 0
@@ -1333,10 +1333,10 @@ Switch:
 		}
 		return x*16 + y, t, nil
 
-	// C escapes.  There is no case 'b', to avoid misparsing
+	// C escapes. There is no case 'b', to avoid misparsing
 	// the Perl word-boundary \b as the C backspace \b
-	// when in POSIX mode.  In Perl, /\b/ means word-boundary
-	// but /[\b]/ means backspace.  We don't support that.
+	// when in POSIX mode. In Perl, /\b/ means word-boundary
+	// but /[\b]/ means backspace. We don't support that.
 	// If you want a backspace, embed a literal backspace
 	// character or use \x08.
 	case 'a':
@@ -1377,7 +1377,7 @@ type charGroup struct {
 }
 
 // parsePerlClassEscape parses a leading Perl character class escape like \d
-// from the beginning of s.  If one is present, it appends the characters to r
+// from the beginning of s. If one is present, it appends the characters to r
 // and returns the new slice r and the remainder of the string.
 func (p *parser) parsePerlClassEscape(s string, r []rune) (out []rune, rest string) {
 	if p.flags&PerlX == 0 || len(s) < 2 || s[0] != '\\' {
@@ -1391,7 +1391,7 @@ func (p *parser) parsePerlClassEscape(s string, r []rune) (out []rune, rest stri
 }
 
 // parseNamedClass parses a leading POSIX named character class like [:alnum:]
-// from the beginning of s.  If one is present, it appends the characters to r
+// from the beginning of s. If one is present, it appends the characters to r
 // and returns the new slice r and the remainder of the string.
 func (p *parser) parseNamedClass(s string, r []rune) (out []rune, rest string, err error) {
 	if len(s) < 2 || s[0] != '[' || s[1] != ':' {
@@ -1454,7 +1454,7 @@ func unicodeTable(name string) (*unicode.RangeTable, *unicode.RangeTable) {
 }
 
 // parseUnicodeClass parses a leading Unicode character class like \p{Han}
-// from the beginning of s.  If one is present, it appends the characters to r
+// from the beginning of s. If one is present, it appends the characters to r
 // and returns the new slice r and the remainder of the string.
 func (p *parser) parseUnicodeClass(s string, r []rune) (out []rune, rest string, err error) {
 	if p.flags&UnicodeGroups == 0 || len(s) < 2 || s[0] != '\\' || s[1] != 'p' && s[1] != 'P' {
@@ -1692,7 +1692,7 @@ const (
 	// minimum and maximum runes involved in folding.
 	// checked during test.
 	minFold = 0x0041
-	maxFold = 0x118df
+	maxFold = 0x1e943
 )
 
 // appendFoldedRange returns the result of appending the range lo-hi
@@ -1718,7 +1718,7 @@ func appendFoldedRange(r []rune, lo, hi rune) []rune {
 		hi = maxFold
 	}
 
-	// Brute force.  Depend on appendRange to coalesce ranges on the fly.
+	// Brute force. Depend on appendRange to coalesce ranges on the fly.
 	for c := lo; c <= hi; c++ {
 		r = appendRange(r, c, c)
 		f := unicode.SimpleFold(c)
diff --git a/src/regexp/syntax/parse_test.go b/src/regexp/syntax/parse_test.go
index 5ca54bb..dd6529f 100644
--- a/src/regexp/syntax/parse_test.go
+++ b/src/regexp/syntax/parse_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/regexp/syntax/prog.go b/src/regexp/syntax/prog.go
index ae6db31..c32ae8d 100644
--- a/src/regexp/syntax/prog.go
+++ b/src/regexp/syntax/prog.go
@@ -144,7 +144,7 @@ func (i *Inst) op() InstOp {
 }
 
 // Prefix returns a literal string that all matches for the
-// regexp must start with.  Complete is true if the prefix
+// regexp must start with. Complete is true if the prefix
 // is the entire match.
 func (p *Prog) Prefix() (prefix string, complete bool) {
 	i, _ := p.skipNop(uint32(p.Start))
@@ -164,7 +164,7 @@ func (p *Prog) Prefix() (prefix string, complete bool) {
 }
 
 // StartCond returns the leading empty-width conditions that must
-// be true in any match.  It returns ^EmptyOp(0) if no matches are possible.
+// be true in any match. It returns ^EmptyOp(0) if no matches are possible.
 func (p *Prog) StartCond() EmptyOp {
 	var flag EmptyOp
 	pc := uint32(p.Start)
diff --git a/src/regexp/syntax/regexp.go b/src/regexp/syntax/regexp.go
index 75822cf..0fe9269 100644
--- a/src/regexp/syntax/regexp.go
+++ b/src/regexp/syntax/regexp.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -139,7 +139,7 @@ func writeRegexp(b *bytes.Buffer, re *Regexp) {
 		if len(re.Rune) == 0 {
 			b.WriteString(`^\x00-\x{10FFFF}`)
 		} else if re.Rune[0] == 0 && re.Rune[len(re.Rune)-1] == unicode.MaxRune {
-			// Contains 0 and MaxRune.  Probably a negated class.
+			// Contains 0 and MaxRune. Probably a negated class.
 			// Print the gaps.
 			b.WriteRune('^')
 			for i := 1; i < len(re.Rune)-1; i += 2 {
@@ -252,7 +252,7 @@ const meta = `\.+*?()|[]{}^$`
 
 func escape(b *bytes.Buffer, r rune, force bool) {
 	if unicode.IsPrint(r) {
-		if strings.IndexRune(meta, r) >= 0 || force {
+		if strings.ContainsRune(meta, r) || force {
 			b.WriteRune('\\')
 		}
 		b.WriteRune(r)
diff --git a/src/regexp/syntax/simplify.go b/src/regexp/syntax/simplify.go
index 7239041..e439325 100644
--- a/src/regexp/syntax/simplify.go
+++ b/src/regexp/syntax/simplify.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,7 +8,7 @@ package syntax
 // and with various other simplifications, such as rewriting /(?:a+)+/ to /a+/.
 // The resulting regexp will execute correctly but its string representation
 // will not produce the same parse tree, because capturing parentheses
-// may have been duplicated or removed.  For example, the simplified form
+// may have been duplicated or removed. For example, the simplified form
 // for /(x){1,2}/ is /(x)(x)?/ but both parentheses capture as $1.
 // The returned regexp may share structure with or be the original.
 func (re *Regexp) Simplify() *Regexp {
@@ -117,13 +117,13 @@ func (re *Regexp) Simplify() *Regexp {
 }
 
 // simplify1 implements Simplify for the unary OpStar,
-// OpPlus, and OpQuest operators.  It returns the simple regexp
+// OpPlus, and OpQuest operators. It returns the simple regexp
 // equivalent to
 //
 //	Regexp{Op: op, Flags: flags, Sub: {sub}}
 //
 // under the assumption that sub is already simple, and
-// without first allocating that structure.  If the regexp
+// without first allocating that structure. If the regexp
 // to be returned turns out to be equivalent to re, simplify1
 // returns re instead.
 //
diff --git a/src/regexp/syntax/simplify_test.go b/src/regexp/syntax/simplify_test.go
index 5d0f1de..9877db3 100644
--- a/src/regexp/syntax/simplify_test.go
+++ b/src/regexp/syntax/simplify_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -59,7 +59,7 @@ var simplifyTests = []struct {
 	{`a{0,1}`, `a?`},
 	// The next three are illegible because Simplify inserts (?:)
 	// parens instead of () parens to avoid creating extra
-	// captured subexpressions.  The comments show a version with fewer parens.
+	// captured subexpressions. The comments show a version with fewer parens.
 	{`(a){0,2}`, `(?:(a)(a)?)?`},                       //       (aa?)?
 	{`(a){0,4}`, `(?:(a)(?:(a)(?:(a)(a)?)?)?)?`},       //   (a(a(aa?)?)?)?
 	{`(a){2,6}`, `(a)(a)(?:(a)(?:(a)(?:(a)(a)?)?)?)?`}, // aa(a(a(aa?)?)?)?
@@ -117,7 +117,7 @@ var simplifyTests = []struct {
 	// Empty string as a regular expression.
 	// The empty string must be preserved inside parens in order
 	// to make submatches work right, so these tests are less
-	// interesting than they might otherwise be.  String inserts
+	// interesting than they might otherwise be. String inserts
 	// explicit (?:) in place of non-parenthesized empty strings,
 	// to make them easier to spot for other parsers.
 	{`(a|b|)`, `([a-b]|(?:))`},
diff --git a/src/run.bash b/src/run.bash
index 3acf46a..293b775 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -11,6 +11,7 @@ export GOROOT   # the api test requires GOROOT to be set.
 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
+unset GOBIN     # Issue 14340
 
 export GOHOSTOS
 export CC
diff --git a/src/run.bat b/src/run.bat
index 01a66bc..6e42922 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -15,6 +15,8 @@ set GOBUILDFAIL=0
 :: we disallow local import for non-local packages, if %GOROOT% happens
 :: to be under %GOPATH%, then some tests below will fail
 set GOPATH=
+:: Issue 14340: ignore GOBIN during all.bat.
+set GOBIN=
 
 rem TODO avoid rebuild if possible
 
diff --git a/src/run.rc b/src/run.rc
index d314808..88d7791 100755
--- a/src/run.rc
+++ b/src/run.rc
@@ -9,5 +9,6 @@ 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
+GOBIN = () # Issue 14340
 
 exec go tool dist test -rebuild $*
diff --git a/src/runtime/alg.go b/src/runtime/alg.go
index 9ea0eb0..6694349 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -16,24 +16,16 @@ const (
 
 // type algorithms - known to compiler
 const (
-	alg_MEM = iota
+	alg_NOEQ = iota
 	alg_MEM0
 	alg_MEM8
 	alg_MEM16
 	alg_MEM32
 	alg_MEM64
 	alg_MEM128
-	alg_NOEQ
-	alg_NOEQ0
-	alg_NOEQ8
-	alg_NOEQ16
-	alg_NOEQ32
-	alg_NOEQ64
-	alg_NOEQ128
 	alg_STRING
 	alg_INTER
 	alg_NILINTER
-	alg_SLICE
 	alg_FLOAT32
 	alg_FLOAT64
 	alg_CPLX64
@@ -72,29 +64,21 @@ func memhash128(p unsafe.Pointer, h uintptr) uintptr {
 }
 
 // memhash_varlen is defined in assembly because it needs access
-// to the closure.  It appears here to provide an argument
+// 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:      {nil, nil}, // not used
+	alg_NOEQ:     {nil, nil},
 	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},
-	alg_NOEQ16:   {nil, nil},
-	alg_NOEQ32:   {nil, nil},
-	alg_NOEQ64:   {nil, nil},
-	alg_NOEQ128:  {nil, nil},
 	alg_STRING:   {strhash, strequal},
 	alg_INTER:    {interhash, interequal},
 	alg_NILINTER: {nilinterhash, nilinterequal},
-	alg_SLICE:    {nil, nil},
 	alg_FLOAT32:  {f32hash, f32equal},
 	alg_FLOAT64:  {f64hash, f64equal},
 	alg_CPLX64:   {c64hash, c64equal},
@@ -162,7 +146,7 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr {
 	t := tab._type
 	fn := t.alg.hash
 	if fn == nil {
-		panic(errorString("hash of unhashable type " + *t._string))
+		panic(errorString("hash of unhashable type " + t.string()))
 	}
 	if isDirectIface(t) {
 		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
@@ -179,7 +163,7 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
 	}
 	fn := t.alg.hash
 	if fn == nil {
-		panic(errorString("hash of unhashable type " + *t._string))
+		panic(errorString("hash of unhashable type " + t.string()))
 	}
 	if isDirectIface(t) {
 		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
@@ -188,13 +172,6 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
 	}
 }
 
-func memequal(p, q unsafe.Pointer, size uintptr) bool {
-	if p == q {
-		return true
-	}
-	return memeq(p, q, size)
-}
-
 func memequal0(p, q unsafe.Pointer) bool {
 	return true
 }
@@ -244,7 +221,7 @@ func efaceeq(x, y eface) bool {
 	}
 	eq := t.alg.equal
 	if eq == nil {
-		panic(errorString("comparing uncomparable type " + *t._string))
+		panic(errorString("comparing uncomparable type " + t.string()))
 	}
 	if isDirectIface(t) {
 		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
@@ -262,7 +239,7 @@ func ifaceeq(x, y iface) bool {
 	t := xtab._type
 	eq := t.alg.equal
 	if eq == nil {
-		panic(errorString("comparing uncomparable type " + *t._string))
+		panic(errorString("comparing uncomparable type " + t.string()))
 	}
 	if isDirectIface(t) {
 		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
diff --git a/src/runtime/append_test.go b/src/runtime/append_test.go
index a67dc9b..6b8968e 100644
--- a/src/runtime/append_test.go
+++ b/src/runtime/append_test.go
@@ -3,10 +3,59 @@
 // license that can be found in the LICENSE file.
 package runtime_test
 
-import "testing"
+import (
+	"fmt"
+	"testing"
+)
 
 const N = 20
 
+func BenchmarkMakeSlice(b *testing.B) {
+	var x []byte
+	for i := 0; i < b.N; i++ {
+		x = make([]byte, 32)
+		_ = x
+	}
+}
+
+func BenchmarkGrowSliceBytes(b *testing.B) {
+	b.StopTimer()
+	var x = make([]byte, 9)
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		_ = append([]byte(nil), x...)
+	}
+}
+
+func BenchmarkGrowSliceInts(b *testing.B) {
+	b.StopTimer()
+	var x = make([]int, 9)
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		_ = append([]int(nil), x...)
+	}
+}
+
+func BenchmarkGrowSlicePtr(b *testing.B) {
+	b.StopTimer()
+	var x = make([]*byte, 9)
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		_ = append([]*byte(nil), x...)
+	}
+}
+
+type struct24 struct{ a, b, c int64 }
+
+func BenchmarkGrowSliceStruct24Bytes(b *testing.B) {
+	b.StopTimer()
+	var x = make([]struct24, 9)
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		_ = append([]struct24(nil), x...)
+	}
+}
+
 func BenchmarkAppend(b *testing.B) {
 	b.StopTimer()
 	x := make([]int, 0, N)
@@ -38,75 +87,37 @@ func BenchmarkAppendGrowString(b *testing.B) {
 	}
 }
 
-func benchmarkAppendBytes(b *testing.B, length int) {
-	b.StopTimer()
-	x := make([]byte, 0, N)
-	y := make([]byte, length)
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		x = x[0:0]
-		x = append(x, y...)
+func BenchmarkAppendSlice(b *testing.B) {
+	for _, length := range []int{1, 4, 7, 8, 15, 16, 32} {
+		b.Run(fmt.Sprint(length, "Bytes"), func(b *testing.B) {
+			x := make([]byte, 0, N)
+			y := make([]byte, length)
+			for i := 0; i < b.N; i++ {
+				x = x[0:0]
+				x = append(x, y...)
+			}
+		})
 	}
 }
 
-func BenchmarkAppend1Byte(b *testing.B) {
-	benchmarkAppendBytes(b, 1)
-}
-
-func BenchmarkAppend4Bytes(b *testing.B) {
-	benchmarkAppendBytes(b, 4)
-}
-
-func BenchmarkAppend7Bytes(b *testing.B) {
-	benchmarkAppendBytes(b, 7)
-}
-
-func BenchmarkAppend8Bytes(b *testing.B) {
-	benchmarkAppendBytes(b, 8)
-}
-
-func BenchmarkAppend15Bytes(b *testing.B) {
-	benchmarkAppendBytes(b, 15)
-}
-
-func BenchmarkAppend16Bytes(b *testing.B) {
-	benchmarkAppendBytes(b, 16)
-}
-
-func BenchmarkAppend32Bytes(b *testing.B) {
-	benchmarkAppendBytes(b, 32)
-}
-
-func benchmarkAppendStr(b *testing.B, str string) {
-	b.StopTimer()
-	x := make([]byte, 0, N)
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		x = x[0:0]
-		x = append(x, str...)
+func BenchmarkAppendStr(b *testing.B) {
+	for _, str := range []string{
+		"1",
+		"1234",
+		"12345678",
+		"1234567890123456",
+		"12345678901234567890123456789012",
+	} {
+		b.Run(fmt.Sprint(len(str), "Bytes"), func(b *testing.B) {
+			x := make([]byte, 0, N)
+			for i := 0; i < b.N; i++ {
+				x = x[0:0]
+				x = append(x, str...)
+			}
+		})
 	}
 }
 
-func BenchmarkAppendStr1Byte(b *testing.B) {
-	benchmarkAppendStr(b, "1")
-}
-
-func BenchmarkAppendStr4Bytes(b *testing.B) {
-	benchmarkAppendStr(b, "1234")
-}
-
-func BenchmarkAppendStr8Bytes(b *testing.B) {
-	benchmarkAppendStr(b, "12345678")
-}
-
-func BenchmarkAppendStr16Bytes(b *testing.B) {
-	benchmarkAppendStr(b, "1234567890123456")
-}
-
-func BenchmarkAppendStr32Bytes(b *testing.B) {
-	benchmarkAppendStr(b, "12345678901234567890123456789012")
-}
-
 func BenchmarkAppendSpecialCase(b *testing.B) {
 	b.StopTimer()
 	x := make([]int, 0, N)
@@ -149,42 +160,153 @@ func TestAppendOverlap(t *testing.T) {
 	}
 }
 
-func benchmarkCopySlice(b *testing.B, l int) {
-	s := make([]byte, l)
-	buf := make([]byte, 4096)
-	var n int
-	for i := 0; i < b.N; i++ {
-		n = copy(buf, s)
+func BenchmarkCopy(b *testing.B) {
+	for _, l := range []int{1, 2, 4, 8, 12, 16, 32, 128, 1024} {
+		buf := make([]byte, 4096)
+		b.Run(fmt.Sprint(l, "Byte"), func(b *testing.B) {
+			s := make([]byte, l)
+			var n int
+			for i := 0; i < b.N; i++ {
+				n = copy(buf, s)
+			}
+			b.SetBytes(int64(n))
+		})
+		b.Run(fmt.Sprint(l, "String"), func(b *testing.B) {
+			s := string(make([]byte, l))
+			var n int
+			for i := 0; i < b.N; i++ {
+				n = copy(buf, s)
+			}
+			b.SetBytes(int64(n))
+		})
 	}
-	b.SetBytes(int64(n))
 }
 
-func benchmarkCopyStr(b *testing.B, l int) {
-	s := string(make([]byte, l))
-	buf := make([]byte, 4096)
-	var n int
-	for i := 0; i < b.N; i++ {
-		n = copy(buf, s)
-	}
-	b.SetBytes(int64(n))
-}
-
-func BenchmarkCopy1Byte(b *testing.B)    { benchmarkCopySlice(b, 1) }
-func BenchmarkCopy2Byte(b *testing.B)    { benchmarkCopySlice(b, 2) }
-func BenchmarkCopy4Byte(b *testing.B)    { benchmarkCopySlice(b, 4) }
-func BenchmarkCopy8Byte(b *testing.B)    { benchmarkCopySlice(b, 8) }
-func BenchmarkCopy12Byte(b *testing.B)   { benchmarkCopySlice(b, 12) }
-func BenchmarkCopy16Byte(b *testing.B)   { benchmarkCopySlice(b, 16) }
-func BenchmarkCopy32Byte(b *testing.B)   { benchmarkCopySlice(b, 32) }
-func BenchmarkCopy128Byte(b *testing.B)  { benchmarkCopySlice(b, 128) }
-func BenchmarkCopy1024Byte(b *testing.B) { benchmarkCopySlice(b, 1024) }
-
-func BenchmarkCopy1String(b *testing.B)    { benchmarkCopyStr(b, 1) }
-func BenchmarkCopy2String(b *testing.B)    { benchmarkCopyStr(b, 2) }
-func BenchmarkCopy4String(b *testing.B)    { benchmarkCopyStr(b, 4) }
-func BenchmarkCopy8String(b *testing.B)    { benchmarkCopyStr(b, 8) }
-func BenchmarkCopy12String(b *testing.B)   { benchmarkCopyStr(b, 12) }
-func BenchmarkCopy16String(b *testing.B)   { benchmarkCopyStr(b, 16) }
-func BenchmarkCopy32String(b *testing.B)   { benchmarkCopyStr(b, 32) }
-func BenchmarkCopy128String(b *testing.B)  { benchmarkCopyStr(b, 128) }
-func BenchmarkCopy1024String(b *testing.B) { benchmarkCopyStr(b, 1024) }
+var (
+	sByte []byte
+	s1Ptr []uintptr
+	s2Ptr [][2]uintptr
+	s3Ptr [][3]uintptr
+	s4Ptr [][4]uintptr
+)
+
+// BenchmarkAppendInPlace tests the performance of append
+// when the result is being written back to the same slice.
+// In order for the in-place optimization to occur,
+// the slice must be referred to by address;
+// using a global is an easy way to trigger that.
+// We test the "grow" and "no grow" paths separately,
+// but not the "normal" (occasionally grow) path,
+// because it is a blend of the other two.
+// We use small numbers and small sizes in an attempt
+// to avoid benchmarking memory allocation and copying.
+// We use scalars instead of pointers in an attempt
+// to avoid benchmarking the write barriers.
+// We benchmark four common sizes (byte, pointer, string/interface, slice),
+// and one larger size.
+func BenchmarkAppendInPlace(b *testing.B) {
+	b.Run("NoGrow", func(b *testing.B) {
+		const C = 128
+
+		b.Run("Byte", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				sByte = make([]byte, C)
+				for j := 0; j < C; j++ {
+					sByte = append(sByte, 0x77)
+				}
+			}
+		})
+
+		b.Run("1Ptr", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				s1Ptr = make([]uintptr, C)
+				for j := 0; j < C; j++ {
+					s1Ptr = append(s1Ptr, 0x77)
+				}
+			}
+		})
+
+		b.Run("2Ptr", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				s2Ptr = make([][2]uintptr, C)
+				for j := 0; j < C; j++ {
+					s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88})
+				}
+			}
+		})
+
+		b.Run("3Ptr", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				s3Ptr = make([][3]uintptr, C)
+				for j := 0; j < C; j++ {
+					s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99})
+				}
+			}
+		})
+
+		b.Run("4Ptr", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				s4Ptr = make([][4]uintptr, C)
+				for j := 0; j < C; j++ {
+					s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA})
+				}
+			}
+		})
+
+	})
+
+	b.Run("Grow", func(b *testing.B) {
+		const C = 5
+
+		b.Run("Byte", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				sByte = make([]byte, 0)
+				for j := 0; j < C; j++ {
+					sByte = append(sByte, 0x77)
+					sByte = sByte[:cap(sByte)]
+				}
+			}
+		})
+
+		b.Run("1Ptr", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				s1Ptr = make([]uintptr, 0)
+				for j := 0; j < C; j++ {
+					s1Ptr = append(s1Ptr, 0x77)
+					s1Ptr = s1Ptr[:cap(s1Ptr)]
+				}
+			}
+		})
+
+		b.Run("2Ptr", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				s2Ptr = make([][2]uintptr, 0)
+				for j := 0; j < C; j++ {
+					s2Ptr = append(s2Ptr, [2]uintptr{0x77, 0x88})
+					s2Ptr = s2Ptr[:cap(s2Ptr)]
+				}
+			}
+		})
+
+		b.Run("3Ptr", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				s3Ptr = make([][3]uintptr, 0)
+				for j := 0; j < C; j++ {
+					s3Ptr = append(s3Ptr, [3]uintptr{0x77, 0x88, 0x99})
+					s3Ptr = s3Ptr[:cap(s3Ptr)]
+				}
+			}
+		})
+
+		b.Run("4Ptr", func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				s4Ptr = make([][4]uintptr, 0)
+				for j := 0; j < C; j++ {
+					s4Ptr = append(s4Ptr, [4]uintptr{0x77, 0x88, 0x99, 0xAA})
+					s4Ptr = s4Ptr[:cap(s4Ptr)]
+				}
+			}
+		})
+
+	})
+}
diff --git a/src/runtime/asm.s b/src/runtime/asm.s
index f1c812b..646dc2f 100644
--- a/src/runtime/asm.s
+++ b/src/runtime/asm.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/asm_386.s b/src/runtime/asm_386.s
index 4181859..ea11b2b 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -54,6 +54,7 @@ bad_proc: // show that the program requires MMX.
 has_cpuid:
 	MOVL	$0, AX
 	CPUID
+	MOVL	AX, SI
 	CMPL	AX, $0
 	JE	nocpuinfo
 
@@ -69,6 +70,7 @@ has_cpuid:
 	MOVB	$1, runtime·lfenceBeforeRdtsc(SB)
 notintel:
 
+	// Load EAX=1 cpuid flags
 	MOVL	$1, AX
 	CPUID
 	MOVL	CX, AX // Move to global variable clobbers CX when generating PIC
@@ -79,6 +81,14 @@ notintel:
 	TESTL	$(1<<23), DX	// MMX
 	JZ 	bad_proc
 
+	// Load EAX=7/ECX=0 cpuid flags
+	CMPL	SI, $7
+	JLT	nocpuinfo
+	MOVL	$7, AX
+	MOVL	$0, CX
+	CPUID
+	MOVL	BX, runtime·cpuid_ebx7(SB)
+
 nocpuinfo:	
 
 	// if there is an _cgo_init, call it to let it
@@ -164,7 +174,7 @@ DATA	bad_proc_msg<>+0x00(SB)/8, $"This pro"
 DATA	bad_proc_msg<>+0x08(SB)/8, $"gram can"
 DATA	bad_proc_msg<>+0x10(SB)/8, $" only be"
 DATA	bad_proc_msg<>+0x18(SB)/8, $" run on "
-DATA	bad_proc_msg<>+0x20(SB)/8, $"processe"
+DATA	bad_proc_msg<>+0x20(SB)/8, $"processo"
 DATA	bad_proc_msg<>+0x28(SB)/8, $"rs with "
 DATA	bad_proc_msg<>+0x30(SB)/8, $"MMX supp"
 DATA	bad_proc_msg<>+0x38(SB)/4, $"ort."
@@ -226,7 +236,7 @@ TEXT runtime·gogo(SB), NOSPLIT, $0-4
 
 // func mcall(fn func(*g))
 // Switch to m->g0's stack, call fn(g).
-// Fn must never return.  It should gogo(&g->sched)
+// Fn must never return. It should gogo(&g->sched)
 // to keep running g.
 TEXT runtime·mcall(SB), NOSPLIT, $0-4
 	MOVL	fn+0(FP), DI
@@ -259,7 +269,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4
 	RET
 
 // systemstack_switch is a dummy routine that systemstack leaves at the bottom
-// of the G stack.  We need to distinguish the routine that
+// 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()).
@@ -291,7 +301,7 @@ TEXT runtime·systemstack(SB), NOSPLIT, $0-4
 	CALL	AX
 
 switch:
-	// save our state in g->sched.  Pretend to
+	// save our state in g->sched. Pretend to
 	// 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)
@@ -529,13 +539,20 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
-// 2. sub 5 bytes from the callers return
+// 2. sub 5 bytes (the length of CALL & a 32 bit displacement) from the callers
+//    return (when building for shared libraries, subtract 16 bytes -- 5 bytes
+//    for CALL & displacement to call __x86.get_pc_thunk.cx, 6 bytes for the
+//    LEAL to load the offset into BX, and finally 5 for the call & displacement)
 // 3. jmp to the argument
 TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8
 	MOVL	fv+0(FP), DX	// fn
 	MOVL	argp+4(FP), BX	// caller sp
 	LEAL	-4(BX), SP	// caller sp after CALL
+#ifdef GOBUILDMODE_shared
+	SUBL	$16, (SP)	// return to CALL again
+#else
 	SUBL	$5, (SP)	// return to CALL again
+#endif
 	MOVL	0(DX), BX
 	JMP	BX	// but first run the deferred function
 
@@ -602,23 +619,25 @@ noswitch:
 	MOVL	AX, ret+8(FP)
 	RET
 
-// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
 // Turn the fn into a Go func (by taking its address) and call
 // cgocallback_gofunc.
-TEXT runtime·cgocallback(SB),NOSPLIT,$12-12
+TEXT runtime·cgocallback(SB),NOSPLIT,$16-16
 	LEAL	fn+0(FP), AX
 	MOVL	AX, 0(SP)
 	MOVL	frame+4(FP), AX
 	MOVL	AX, 4(SP)
 	MOVL	framesize+8(FP), AX
 	MOVL	AX, 8(SP)
+	MOVL	ctxt+12(FP), AX
+	MOVL	AX, 12(SP)
 	MOVL	$runtime·cgocallback_gofunc(SB), AX
 	CALL	AX
 	RET
 
-// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
 // See cgocall.go for more details.
-TEXT ·cgocallback_gofunc(SB),NOSPLIT,$12-12
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$12-16
 	NO_LOCAL_POINTERS
 
 	// If g is nil, Go did not create the current thread.
@@ -686,17 +705,19 @@ havem:
 	// so that the traceback will seamlessly trace back into
 	// the earlier calls.
 	//
-	// In the new goroutine, 0(SP) holds the saved oldm (DX) register.
-	// 4(SP) and 8(SP) are unused.
+	// In the new goroutine, 4(SP) holds the saved oldm (DX) register.
+	// 8(SP) is unused.
 	MOVL	m_curg(BP), SI
 	MOVL	SI, g(CX)
 	MOVL	(g_sched+gobuf_sp)(SI), DI // prepare stack as DI
 	MOVL	(g_sched+gobuf_pc)(SI), BP
 	MOVL	BP, -4(DI)
+	MOVL	ctxt+12(FP), CX
 	LEAL	-(4+12)(DI), SP
-	MOVL	DX, 0(SP)
+	MOVL	DX, 4(SP)
+	MOVL	CX, 0(SP)
 	CALL	runtime·cgocallbackg(SB)
-	MOVL	0(SP), DX
+	MOVL	4(SP), DX
 
 	// Restore g->sched (== m->curg->sched) from saved values.
 	get_tls(CX)
@@ -900,7 +921,7 @@ final1:
 	RET
 
 endofpage:
-	// address ends in 1111xxxx.  Might be up against
+	// address ends in 1111xxxx. Might be up against
 	// a page boundary, so load ending at last byte.
 	// Then shift bytes down using pshufb.
 	MOVOU	-32(AX)(BX*1), X1
@@ -1145,7 +1166,7 @@ DATA masks<>+0xfc(SB)/4, $0x00ffffff
 
 GLOBL masks<>(SB),RODATA,$256
 
-// these are arguments to pshufb.  They move data down from
+// these are arguments to pshufb. They move data down from
 // the high bytes of the register to the low bytes of the register.
 // index is how many bytes to move.
 DATA shifts<>+0x00(SB)/4, $0x00000000
@@ -1239,12 +1260,18 @@ TEXT ·checkASM(SB),NOSPLIT,$0-1
 	SETEQ	ret+0(FP)
 	RET
 
-TEXT runtime·memeq(SB),NOSPLIT,$0-13
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$0-13
 	MOVL	a+0(FP), SI
 	MOVL	b+4(FP), DI
+	CMPL	SI, DI
+	JEQ	eq
 	MOVL	size+8(FP), BX
 	LEAL	ret+12(FP), AX
 	JMP	runtime·memeqbody(SB)
+eq:
+	MOVB    $1, ret+12(FP)
+	RET
 
 // memequal_varlen(a, b unsafe.Pointer) bool
 TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
@@ -1364,7 +1391,7 @@ small:
 	MOVL	(SI), SI
 	JMP	si_finish
 si_high:
-	// address ends in 111111xx.  Load up to bytes we want, move to correct position.
+	// address ends in 111111xx. Load up to bytes we want, move to correct position.
 	MOVL	-4(SI)(BX*1), SI
 	SHRL	CX, SI
 si_finish:
@@ -1600,7 +1627,7 @@ TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
 TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
 	RET
 
-// Add a module's moduledata to the linked list of moduledata objects.  This
+// Add a module's moduledata to the linked list of moduledata objects. This
 // is called from .init_array by a function generated in the linker and so
 // follows the platform ABI wrt register preservation -- it only touches AX,
 // CX (implicitly) and DX, but it does not follow the ABI wrt arguments:
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 5094812..6103d54 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -28,6 +28,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
 	// find out information about the processor we're on
 	MOVQ	$0, AX
 	CPUID
+	MOVQ	AX, SI
 	CMPQ	AX, $0
 	JE	nocpuinfo
 
@@ -42,15 +43,25 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
 	JNE	notintel
 	MOVB	$1, runtime·lfenceBeforeRdtsc(SB)
 notintel:
-	// Do nothing.
 
+	// Load EAX=1 cpuid flags
 	MOVQ	$1, AX
 	CPUID
 	MOVL	CX, runtime·cpuid_ecx(SB)
 	MOVL	DX, runtime·cpuid_edx(SB)
+
+	// Load EAX=7/ECX=0 cpuid flags
+	CMPQ	SI, $7
+	JLT	no7
+	MOVL	$7, AX
+	MOVL	$0, CX
+	CPUID
+	MOVL	BX, runtime·cpuid_ebx7(SB)
+no7:
 	// Detect AVX and AVX2 as per 14.7.1  Detection of AVX2 chapter of [1]
 	// [1] 64-ia-32-architectures-software-developer-manual-325462.pdf
 	// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf
+	MOVL	runtime·cpuid_ecx(SB), CX
 	ANDL    $0x18000000, CX // check for OSXSAVE and AVX bits
 	CMPL    CX, $0x18000000
 	JNE     noavx
@@ -61,12 +72,8 @@ notintel:
 	CMPL    AX, $6 // Check for OS support of YMM registers
 	JNE     noavx
 	MOVB    $1, runtime·support_avx(SB)
-	MOVL    $7, AX
-	MOVL    $0, CX
-	CPUID
-	ANDL    $0x20, BX // check for AVX2 bit
-	CMPL    BX, $0x20
-	JNE     noavx2
+	TESTL   $(1<<5), runtime·cpuid_ebx7(SB) // check for AVX2 bit
+	JEQ     noavx2
 	MOVB    $1, runtime·support_avx2(SB)
 	JMP     nocpuinfo
 noavx:
@@ -203,7 +210,7 @@ TEXT runtime·gogo(SB), NOSPLIT, $0-8
 
 // func mcall(fn func(*g))
 // Switch to m->g0's stack, call fn(g).
-// Fn must never return.  It should gogo(&g->sched)
+// Fn must never return. It should gogo(&g->sched)
 // to keep running g.
 TEXT runtime·mcall(SB), NOSPLIT, $0-8
 	MOVQ	fn+0(FP), DI
@@ -237,7 +244,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8
 	RET
 
 // systemstack_switch is a dummy routine that systemstack leaves at the bottom
-// of the G stack.  We need to distinguish the routine that
+// 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()).
@@ -268,7 +275,7 @@ TEXT runtime·systemstack(SB), NOSPLIT, $0-8
 	CALL	AX
 
 switch:
-	// save our state in g->sched.  Pretend to
+	// save our state in g->sched. Pretend to
 	// be systemstack_switch if the G stack is scanned.
 	MOVQ	$runtime·systemstack_switch(SB), SI
 	MOVQ	SI, (g_sched+gobuf_pc)(AX)
@@ -519,6 +526,7 @@ TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16
 	MOVQ	fv+0(FP), DX	// fn
 	MOVQ	argp+8(FP), BX	// caller sp
 	LEAQ	-8(BX), SP	// caller sp after CALL
+	MOVQ	-8(SP), BP	// restore BP as if deferreturn returned (harmless if framepointers not in use)
 	SUBQ	$5, (SP)	// return to CALL again
 	MOVQ	0(DX), BX
 	JMP	BX	// but first run the deferred function
@@ -615,23 +623,25 @@ nosave:
 	MOVL	AX, ret+16(FP)
 	RET
 
-// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
 // Turn the fn into a Go func (by taking its address) and call
 // cgocallback_gofunc.
-TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
+TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
 	LEAQ	fn+0(FP), AX
 	MOVQ	AX, 0(SP)
 	MOVQ	frame+8(FP), AX
 	MOVQ	AX, 8(SP)
 	MOVQ	framesize+16(FP), AX
 	MOVQ	AX, 16(SP)
+	MOVQ	ctxt+24(FP), AX
+	MOVQ	AX, 24(SP)
 	MOVQ	$runtime·cgocallback_gofunc(SB), AX
 	CALL	AX
 	RET
 
-// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
 // See cgocall.go for more details.
-TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-24
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-32
 	NO_LOCAL_POINTERS
 
 	// If g is nil, Go did not create the current thread.
@@ -699,7 +709,7 @@ havem:
 	// so that the traceback will seamlessly trace back into
 	// the earlier calls.
 	//
-	// In the new goroutine, 0(SP) holds the saved R8.
+	// In the new goroutine, 8(SP) holds the saved R8.
 	MOVQ	m_curg(BX), SI
 	MOVQ	SI, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(SI), DI  // prepare stack as DI
@@ -707,16 +717,18 @@ havem:
 	MOVQ	BX, -8(DI)
 	// Compute the size of the frame, including return PC and, if
 	// GOEXPERIMENT=framepointer, the saved based pointer
+	MOVQ	ctxt+24(FP), BX
 	LEAQ	fv+0(FP), AX
 	SUBQ	SP, AX
 	SUBQ	AX, DI
 	MOVQ	DI, SP
 
-	MOVQ	R8, 0(SP)
+	MOVQ	R8, 8(SP)
+	MOVQ	BX, 0(SP)
 	CALL	runtime·cgocallbackg(SB)
-	MOVQ	0(SP), R8
+	MOVQ	8(SP), R8
 
-	// Compute the size of the frame again.  FP and SP have
+	// 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
@@ -902,14 +914,15 @@ aes0to15:
 	MOVQ	$masks<>(SB), AX
 	PAND	(AX)(CX*8), X1
 final1:
-	AESENC	X0, X1	// scramble input, xor in seed
-	AESENC	X1, X1  // scramble combo 2 times
+	PXOR	X0, X1	// xor data with seed
+	AESENC	X1, X1	// scramble combo 3 times
+	AESENC	X1, X1
 	AESENC	X1, X1
 	MOVQ	X1, (DX)
 	RET
 
 endofpage:
-	// address ends in 1111xxxx.  Might be up against
+	// address ends in 1111xxxx. Might be up against
 	// a page boundary, so load ending at last byte.
 	// Then shift bytes down using pshufb.
 	MOVOU	-32(AX)(CX*1), X1
@@ -937,9 +950,13 @@ aes17to32:
 	MOVOU	(AX), X2
 	MOVOU	-16(AX)(CX*1), X3
 
+	// xor with seed
+	PXOR	X0, X2
+	PXOR	X1, X3
+
 	// scramble 3 times
-	AESENC	X0, X2
-	AESENC	X1, X3
+	AESENC	X2, X2
+	AESENC	X3, X3
 	AESENC	X2, X2
 	AESENC	X3, X3
 	AESENC	X2, X2
@@ -965,11 +982,16 @@ aes33to64:
 	MOVOU	16(AX), X5
 	MOVOU	-32(AX)(CX*1), X6
 	MOVOU	-16(AX)(CX*1), X7
+
+	PXOR	X0, X4
+	PXOR	X1, X5
+	PXOR	X2, X6
+	PXOR	X3, X7
 	
-	AESENC	X0, X4
-	AESENC	X1, X5
-	AESENC	X2, X6
-	AESENC	X3, X7
+	AESENC	X4, X4
+	AESENC	X5, X5
+	AESENC	X6, X6
+	AESENC	X7, X7
 	
 	AESENC	X4, X4
 	AESENC	X5, X5
@@ -1020,17 +1042,17 @@ aes65to128:
 	MOVOU	-32(AX)(CX*1), X14
 	MOVOU	-16(AX)(CX*1), X15
 
-	// scramble data, xor in seed
-	AESENC	X0, X8
-	AESENC	X1, X9
-	AESENC	X2, X10
-	AESENC	X3, X11
-	AESENC	X4, X12
-	AESENC	X5, X13
-	AESENC	X6, X14
-	AESENC	X7, X15
+	// xor with seed
+	PXOR	X0, X8
+	PXOR	X1, X9
+	PXOR	X2, X10
+	PXOR	X3, X11
+	PXOR	X4, X12
+	PXOR	X5, X13
+	PXOR	X6, X14
+	PXOR	X7, X15
 
-	// scramble twice
+	// scramble 3 times
 	AESENC	X8, X8
 	AESENC	X9, X9
 	AESENC	X10, X10
@@ -1039,7 +1061,16 @@ aes65to128:
 	AESENC	X13, X13
 	AESENC	X14, X14
 	AESENC	X15, X15
-	
+
+	AESENC	X8, X8
+	AESENC	X9, X9
+	AESENC	X10, X10
+	AESENC	X11, X11
+	AESENC	X12, X12
+	AESENC	X13, X13
+	AESENC	X14, X14
+	AESENC	X15, X15
+
 	AESENC	X8, X8
 	AESENC	X9, X9
 	AESENC	X10, X10
@@ -1093,21 +1124,31 @@ aes129plus:
 	MOVOU	-32(AX)(CX*1), X14
 	MOVOU	-16(AX)(CX*1), X15
 
-	// scramble input once, xor in seed
-	AESENC	X0, X8
-	AESENC	X1, X9
-	AESENC	X2, X10
-	AESENC	X3, X11
-	AESENC	X4, X12
-	AESENC	X5, X13
-	AESENC	X6, X14
-	AESENC	X7, X15
+	// xor in seed
+	PXOR	X0, X8
+	PXOR	X1, X9
+	PXOR	X2, X10
+	PXOR	X3, X11
+	PXOR	X4, X12
+	PXOR	X5, X13
+	PXOR	X6, X14
+	PXOR	X7, X15
 	
 	// compute number of remaining 128-byte blocks
 	DECQ	CX
 	SHRQ	$7, CX
 	
 aesloop:
+	// scramble state
+	AESENC	X8, X8
+	AESENC	X9, X9
+	AESENC	X10, X10
+	AESENC	X11, X11
+	AESENC	X12, X12
+	AESENC	X13, X13
+	AESENC	X14, X14
+	AESENC	X15, X15
+
 	// scramble state, xor in a block
 	MOVOU	(AX), X0
 	MOVOU	16(AX), X1
@@ -1126,7 +1167,11 @@ aesloop:
 	AESENC	X6, X14
 	AESENC	X7, X15
 
-	// scramble state
+	ADDQ	$128, AX
+	DECQ	CX
+	JNE	aesloop
+
+	// 3 more scrambles to finish
 	AESENC	X8, X8
 	AESENC	X9, X9
 	AESENC	X10, X10
@@ -1135,12 +1180,6 @@ aesloop:
 	AESENC	X13, X13
 	AESENC	X14, X14
 	AESENC	X15, X15
-
-	ADDQ	$128, AX
-	DECQ	CX
-	JNE	aesloop
-
-	// 2 more scrambles to finish
 	AESENC	X8, X8
 	AESENC	X9, X9
 	AESENC	X10, X10
@@ -1232,7 +1271,7 @@ TEXT ·checkASM(SB),NOSPLIT,$0-1
 	SETEQ	ret+0(FP)
 	RET
 
-// these are arguments to pshufb.  They move data down from
+// these are arguments to pshufb. They move data down from
 // the high bytes of the register to the low bytes of the register.
 // index is how many bytes to move.
 DATA shifts<>+0x00(SB)/8, $0x0000000000000000
@@ -1269,12 +1308,18 @@ DATA shifts<>+0xf0(SB)/8, $0x0807060504030201
 DATA shifts<>+0xf8(SB)/8, $0xff0f0e0d0c0b0a09
 GLOBL shifts<>(SB),RODATA,$256
 
-TEXT runtime·memeq(SB),NOSPLIT,$0-25
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$0-25
 	MOVQ	a+0(FP), SI
 	MOVQ	b+8(FP), DI
+	CMPQ	SI, DI
+	JEQ	eq
 	MOVQ	size+16(FP), BX
 	LEAQ	ret+24(FP), AX
 	JMP	runtime·memeqbody(SB)
+eq:
+	MOVB	$1, ret+24(FP)
+	RET
 
 // memequal_varlen(a, b unsafe.Pointer) bool
 TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17
@@ -1406,7 +1451,7 @@ small:
 	MOVQ	(SI), SI
 	JMP	si_finish
 si_high:
-	// address ends in 11111xxx.  Load up to bytes we want, move to correct position.
+	// address ends in 11111xxx. Load up to bytes we want, move to correct position.
 	MOVQ	-8(SI)(BX*1), SI
 	SHRQ	CX, SI
 si_finish:
@@ -1653,122 +1698,126 @@ big_loop_avx2_exit:
 // TODO: Also use this in bytes.Index
 TEXT strings·indexShortStr(SB),NOSPLIT,$0-40
 	MOVQ s+0(FP), DI
-	MOVQ s_len+8(FP), CX
-	MOVQ c+16(FP), AX
-	MOVQ c_len+24(FP), BX
-	CMPQ BX, CX
+	// We want len in DX and AX, because PCMPESTRI implicitly consumes them
+	MOVQ s_len+8(FP), DX
+	MOVQ c+16(FP), BP
+	MOVQ c_len+24(FP), AX
+	CMPQ AX, DX
 	JA fail
-	CMPQ BX, $2
+	CMPQ DX, $16
+	JAE sse42
+no_sse42:
+	CMPQ AX, $2
 	JA   _3_or_more
-	MOVW (AX), AX
-	LEAQ -1(DI)(CX*1), CX
+	MOVW (BP), BP
+	LEAQ -1(DI)(DX*1), DX
 loop2:
 	MOVW (DI), SI
-	CMPW SI,AX
+	CMPW SI,BP
 	JZ success
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop2
 	JMP fail
 _3_or_more:
-	CMPQ BX, $3
+	CMPQ AX, $3
 	JA   _4_or_more
-	MOVW 1(AX), DX
-	MOVW (AX), AX
-	LEAQ -2(DI)(CX*1), CX
+	MOVW 1(BP), BX
+	MOVW (BP), BP
+	LEAQ -2(DI)(DX*1), DX
 loop3:
 	MOVW (DI), SI
-	CMPW SI,AX
+	CMPW SI,BP
 	JZ   partial_success3
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop3
 	JMP fail
 partial_success3:
 	MOVW 1(DI), SI
-	CMPW SI,DX
+	CMPW SI,BX
 	JZ success
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop3
 	JMP fail
 _4_or_more:
-	CMPQ BX, $4
+	CMPQ AX, $4
 	JA   _5_or_more
-	MOVL (AX), AX
-	LEAQ -3(DI)(CX*1), CX
+	MOVL (BP), BP
+	LEAQ -3(DI)(DX*1), DX
 loop4:
 	MOVL (DI), SI
-	CMPL SI,AX
+	CMPL SI,BP
 	JZ   success
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop4
 	JMP fail
 _5_or_more:
-	CMPQ BX, $7
+	CMPQ AX, $7
 	JA   _8_or_more
-	LEAQ 1(DI)(CX*1), CX
-	SUBQ BX, CX
-	MOVL -4(AX)(BX*1), DX
-	MOVL (AX), AX
+	LEAQ 1(DI)(DX*1), DX
+	SUBQ AX, DX
+	MOVL -4(BP)(AX*1), BX
+	MOVL (BP), BP
 loop5to7:
 	MOVL (DI), SI
-	CMPL SI,AX
+	CMPL SI,BP
 	JZ   partial_success5to7
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop5to7
 	JMP fail
 partial_success5to7:
-	MOVL -4(BX)(DI*1), SI
-	CMPL SI,DX
+	MOVL -4(AX)(DI*1), SI
+	CMPL SI,BX
 	JZ success
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop5to7
 	JMP fail
 _8_or_more:
-	CMPQ BX, $8
+	CMPQ AX, $8
 	JA   _9_or_more
-	MOVQ (AX), AX
-	LEAQ -7(DI)(CX*1), CX
+	MOVQ (BP), BP
+	LEAQ -7(DI)(DX*1), DX
 loop8:
 	MOVQ (DI), SI
-	CMPQ SI,AX
+	CMPQ SI,BP
 	JZ   success
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop8
 	JMP fail
 _9_or_more:
-	CMPQ BX, $16
+	CMPQ AX, $16
 	JA   _16_or_more
-	LEAQ 1(DI)(CX*1), CX
-	SUBQ BX, CX
-	MOVQ -8(AX)(BX*1), DX
-	MOVQ (AX), AX
+	LEAQ 1(DI)(DX*1), DX
+	SUBQ AX, DX
+	MOVQ -8(BP)(AX*1), BX
+	MOVQ (BP), BP
 loop9to15:
 	MOVQ (DI), SI
-	CMPQ SI,AX
+	CMPQ SI,BP
 	JZ   partial_success9to15
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop9to15
 	JMP fail
 partial_success9to15:
-	MOVQ -8(BX)(DI*1), SI
-	CMPQ SI,DX
+	MOVQ -8(AX)(DI*1), SI
+	CMPQ SI,BX
 	JZ success
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop9to15
 	JMP fail
 _16_or_more:
-	CMPQ BX, $16
+	CMPQ AX, $16
 	JA   _17_to_31
-	MOVOU (AX), X1
-	LEAQ -15(DI)(CX*1), CX
+	MOVOU (BP), X1
+	LEAQ -15(DI)(DX*1), DX
 loop16:
 	MOVOU (DI), X2
 	PCMPEQB X1, X2
@@ -1776,14 +1825,14 @@ loop16:
 	CMPQ  SI, $0xffff
 	JE   success
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop16
 	JMP fail
 _17_to_31:
-	LEAQ 1(DI)(CX*1), CX
-	SUBQ BX, CX
-	MOVOU -16(AX)(BX*1), X0
-	MOVOU (AX), X1
+	LEAQ 1(DI)(DX*1), DX
+	SUBQ AX, DX
+	MOVOU -16(BP)(AX*1), X0
+	MOVOU (BP), X1
 loop17to31:
 	MOVOU (DI), X2
 	PCMPEQB X1,X2
@@ -1791,21 +1840,58 @@ loop17to31:
 	CMPQ  SI, $0xffff
 	JE   partial_success17to31
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop17to31
 	JMP fail
 partial_success17to31:
-	MOVOU -16(BX)(DI*1), X3
+	MOVOU -16(AX)(DI*1), X3
 	PCMPEQB X0, X3
 	PMOVMSKB X3, SI
 	CMPQ  SI, $0xffff
 	JE success
 	ADDQ $1,DI
-	CMPQ DI,CX
+	CMPQ DI,DX
 	JB loop17to31
 fail:
 	MOVQ $-1, ret+32(FP)
 	RET
+sse42:
+	MOVL runtime·cpuid_ecx(SB), CX
+	ANDL $0x100000, CX
+	JZ no_sse42
+	CMPQ AX, $12
+	// PCMPESTRI is slower than normal compare,
+	// so using it makes sense only if we advance 4+ bytes per compare
+	// This value was determined experimentally and is the ~same
+	// on Nehalem (first with SSE42) and Haswell.
+	JAE _9_or_more
+	LEAQ 16(BP), SI
+	TESTW $0xff0, SI
+	JEQ no_sse42
+	MOVOU (BP), X1
+	LEAQ -15(DI)(DX*1), SI
+	MOVQ $16, R9
+	SUBQ AX, R9 // We advance by 16-len(sep) each iteration, so precalculate it into R9
+loop_sse42:
+	// 0x0c means: unsigned byte compare (bits 0,1 are 00)
+	// for equality (bits 2,3 are 11)
+	// result is not masked or inverted (bits 4,5 are 00)
+	// and corresponds to first matching byte (bit 6 is 0)
+	PCMPESTRI $0x0c, (DI), X1
+	// CX == 16 means no match,
+	// CX > R9 means partial match at the end of the string,
+	// otherwise sep is at offset CX from X1 start
+	CMPQ CX, R9
+	JBE sse42_success
+	ADDQ R9, DI
+	CMPQ DI, SI
+	JB loop_sse42
+	PCMPESTRI $0x0c, -1(SI), X1
+	CMPQ CX, R9
+	JA fail
+	LEAQ -1(SI), DI
+sse42_success:
+	ADDQ CX, DI
 success:
 	SUBQ s+0(FP), DI
 	MOVQ DI, ret+32(FP)
@@ -1832,80 +1918,98 @@ TEXT strings·IndexByte(SB),NOSPLIT,$0-32
 //   AL: byte sought
 //   R8: address to put result
 TEXT runtime·indexbytebody(SB),NOSPLIT,$0
-	MOVQ SI, DI
-
-	CMPQ BX, $16
-	JLT small
-
-	CMPQ BX, $32
-	JA avx2
-no_avx2:
-	// round up to first 16-byte boundary
-	TESTQ $15, SI
-	JZ aligned
-	MOVQ SI, CX
-	ANDQ $~15, CX
-	ADDQ $16, CX
-
-	// search the beginning
-	SUBQ SI, CX
-	REPN; SCASB
-	JZ success
-
-// DI is 16-byte aligned; get ready to search using SSE instructions
-aligned:
-	// round down to last 16-byte boundary
-	MOVQ BX, R11
-	ADDQ SI, R11
-	ANDQ $~15, R11
-
-	// shuffle X0 around so that each byte contains c
+	// Shuffle X0 around so that each byte contains
+	// the character we're looking for.
 	MOVD AX, X0
 	PUNPCKLBW X0, X0
 	PUNPCKLBW X0, X0
 	PSHUFL $0, X0, X0
-	JMP condition
+	
+	CMPQ BX, $16
+	JLT small
+
+	MOVQ SI, DI
 
+	CMPQ BX, $32
+	JA avx2
 sse:
-	// move the next 16-byte chunk of the buffer into X1
-	MOVO (DI), X1
-	// compare bytes in X0 to X1
-	PCMPEQB X0, X1
-	// take the top bit of each byte in X1 and put the result in DX
+	LEAQ	-16(SI)(BX*1), AX	// AX = address of last 16 bytes
+	JMP	sseloopentry
+	
+sseloop:
+	// Move the next 16-byte chunk of the data into X1.
+	MOVOU	(DI), X1
+	// Compare bytes in X0 to X1.
+	PCMPEQB	X0, X1
+	// Take the top bit of each byte in X1 and put the result in DX.
 	PMOVMSKB X1, DX
-	TESTL DX, DX
-	JNZ ssesuccess
-	ADDQ $16, DI
+	// Find first set bit, if any.
+	BSFL	DX, DX
+	JNZ	ssesuccess
+	// Advance to next block.
+	ADDQ	$16, DI
+sseloopentry:
+	CMPQ	DI, AX
+	JB	sseloop
 
-condition:
-	CMPQ DI, R11
-	JLT sse
-
-	// search the end
-	MOVQ SI, CX
-	ADDQ BX, CX
-	SUBQ R11, CX
-	// if CX == 0, the zero flag will be set and we'll end up
-	// returning a false success
-	JZ failure
-	REPN; SCASB
-	JZ success
+	// Search the last 16-byte chunk. This chunk may overlap with the
+	// chunks we've already searched, but that's ok.
+	MOVQ	AX, DI
+	MOVOU	(AX), X1
+	PCMPEQB	X0, X1
+	PMOVMSKB X1, DX
+	BSFL	DX, DX
+	JNZ	ssesuccess
 
 failure:
 	MOVQ $-1, (R8)
 	RET
 
+// We've found a chunk containing the byte.
+// The chunk was loaded from DI.
+// The index of the matching byte in the chunk is DX.
+// The start of the data is SI.
+ssesuccess:
+	SUBQ SI, DI	// Compute offset of chunk within data.
+	ADDQ DX, DI	// Add offset of byte within chunk.
+	MOVQ DI, (R8)
+	RET
+
 // handle for lengths < 16
 small:
-	MOVQ BX, CX
-	REPN; SCASB
-	JZ success
-	MOVQ $-1, (R8)
+	TESTQ	BX, BX
+	JEQ	failure
+
+	// Check if we'll load across a page boundary.
+	LEAQ	16(SI), AX
+	TESTW	$0xff0, AX
+	JEQ	endofpage
+
+	MOVOU	(SI), X1 // Load data
+	PCMPEQB	X0, X1	// Compare target byte with each byte in data.
+	PMOVMSKB X1, DX	// Move result bits to integer register.
+	BSFL	DX, DX	// Find first set bit.
+	JZ	failure	// No set bit, failure.
+	CMPL	DX, BX
+	JAE	failure	// Match is past end of data.
+	MOVQ	DX, (R8)
+	RET
+
+endofpage:
+	MOVOU	-16(SI)(BX*1), X1	// Load data into the high end of X1.
+	PCMPEQB	X0, X1	// Compare target byte with each byte in data.
+	PMOVMSKB X1, DX	// Move result bits to integer register.
+	MOVL	BX, CX
+	SHLL	CX, DX
+	SHRL	$16, DX	// Shift desired bits down to bottom of register.
+	BSFL	DX, DX	// Find first set bit.
+	JZ	failure	// No set bit, failure.
+	MOVQ	DX, (R8)
 	RET
 
 avx2:
 	CMPB   runtime·support_avx2(SB), $1
-	JNE no_avx2
+	JNE sse
 	MOVD AX, X0
 	LEAQ -32(SI)(BX*1), R11
 	VPBROADCASTB  X0, Y1
@@ -1935,22 +2039,6 @@ avx2success:
 	VZEROUPPER
 	RET
 
-// we've found the chunk containing the byte
-// now just figure out which specific byte it is
-ssesuccess:
-	// get the index of the least significant set bit
-	BSFW DX, DX
-	SUBQ SI, DI
-	ADDQ DI, DX
-	MOVQ DX, (R8)
-	RET
-
-success:
-	SUBQ SI, DI
-	SUBL $1, DI
-	MOVQ DI, (R8)
-	RET
-
 TEXT bytes·Equal(SB),NOSPLIT,$0-49
 	MOVQ	a_len+8(FP), BX
 	MOVQ	b_len+32(FP), CX
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index ecbc597..452ce04 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -133,7 +133,7 @@ TEXT runtime·gogo(SB), NOSPLIT, $0-4
 
 // func mcall(fn func(*g))
 // Switch to m->g0's stack, call fn(g).
-// Fn must never return.  It should gogo(&g->sched)
+// Fn must never return. It should gogo(&g->sched)
 // to keep running g.
 TEXT runtime·mcall(SB), NOSPLIT, $0-4
 	MOVL	fn+0(FP), DI
@@ -166,7 +166,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4
 	RET
 
 // systemstack_switch is a dummy routine that systemstack leaves at the bottom
-// of the G stack.  We need to distinguish the routine that
+// 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()).
@@ -198,7 +198,7 @@ TEXT runtime·systemstack(SB), NOSPLIT, $0-4
 	CALL	AX
 
 switch:
-	// save our state in g->sched.  Pretend to
+	// save our state in g->sched. Pretend to
 	// be systemstack_switch if the G stack is scanned.
 	MOVL	$runtime·systemstack_switch(SB), SI
 	MOVL	SI, (g_sched+gobuf_pc)(AX)
@@ -491,7 +491,7 @@ TEXT runtime·memclr(SB),NOSPLIT,$0-8
 	REP
 	STOSB
 	// Note: we zero only 4 bytes at a time so that the tail is at most
-	// 3 bytes.  That guarantees that we aren't zeroing pointers with STOSB.
+	// 3 bytes. That guarantees that we aren't zeroing pointers with STOSB.
 	// See issue 13160.
 	RET
 
@@ -573,13 +573,19 @@ TEXT runtime·aeshash64(SB),NOSPLIT,$0-20
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·memeq(SB),NOSPLIT,$0-17
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$0-13
 	MOVL	a+0(FP), SI
 	MOVL	b+4(FP), DI
+	CMPL	SI, DI
+	JEQ	eq
 	MOVL	size+8(FP), BX
 	CALL	runtime·memeqbody(SB)
 	MOVB	AX, ret+16(FP)
 	RET
+eq:
+	MOVB    $1, ret+16(FP)
+	RET
 
 // memequal_varlen(a, b unsafe.Pointer) bool
 TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
@@ -686,7 +692,7 @@ small:
 	MOVQ	(SI), SI
 	JMP	si_finish
 si_high:
-	// address ends in 11111xxx.  Load up to bytes we want, move to correct position.
+	// address ends in 11111xxx. Load up to bytes we want, move to correct position.
 	MOVQ	BX, DX
 	ADDQ	SI, DX
 	MOVQ	-8(DX), SI
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 07894a3..f02297e 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -153,7 +153,7 @@ TEXT runtime·gogo(SB),NOSPLIT,$-4-4
 
 // func mcall(fn func(*g))
 // Switch to m->g0's stack, call fn(g).
-// Fn must never return.  It should gogo(&g->sched)
+// Fn must never return. It should gogo(&g->sched)
 // to keep running g.
 TEXT runtime·mcall(SB),NOSPLIT,$-4-4
 	// Save caller state in g->sched.
@@ -185,7 +185,7 @@ TEXT runtime·mcall(SB),NOSPLIT,$-4-4
 	RET
 
 // systemstack_switch is a dummy routine that systemstack leaves at the bottom
-// of the G stack.  We need to distinguish the routine that
+// 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()).
@@ -217,7 +217,7 @@ TEXT runtime·systemstack(SB),NOSPLIT,$0-4
 	BL	(R0)
 
 switch:
-	// save our state in g->sched.  Pretend to
+	// save our state in g->sched. Pretend to
 	// be systemstack_switch if the G stack is scanned.
 	MOVW	$runtime·systemstack_switch(SB), R3
 #ifdef GOOS_nacl
@@ -530,23 +530,25 @@ g0:
 	MOVW	R0, ret+8(FP)
 	RET
 
-// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
 // Turn the fn into a Go func (by taking its address) and call
 // cgocallback_gofunc.
-TEXT runtime·cgocallback(SB),NOSPLIT,$12-12
+TEXT runtime·cgocallback(SB),NOSPLIT,$16-16
 	MOVW	$fn+0(FP), R0
 	MOVW	R0, 4(R13)
 	MOVW	frame+4(FP), R0
 	MOVW	R0, 8(R13)
 	MOVW	framesize+8(FP), R0
 	MOVW	R0, 12(R13)
+	MOVW	ctxt+12(FP), R0
+	MOVW	R0, 16(R13)
 	MOVW	$runtime·cgocallback_gofunc(SB), R0
 	BL	(R0)
 	RET
 
-// cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize)
+// cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
 // See cgocall.go for more details.
-TEXT	·cgocallback_gofunc(SB),NOSPLIT,$8-12
+TEXT	·cgocallback_gofunc(SB),NOSPLIT,$8-16
 	NO_LOCAL_POINTERS
 	
 	// Load m and g from thread-local storage.
@@ -611,12 +613,15 @@ havem:
 	// so that the traceback will seamlessly trace back into
 	// the earlier calls.
 	//
-	// In the new goroutine, -8(SP) and -4(SP) are unused.
+	// In the new goroutine, -4(SP) is unused (where SP refers to
+	// m->curg's SP while we're setting it up, before we've adjusted it).
 	MOVW	m_curg(R8), R0
 	BL	setg<>(SB)
 	MOVW	(g_sched+gobuf_sp)(g), R4 // prepare stack as R4
 	MOVW	(g_sched+gobuf_pc)(g), R5
 	MOVW	R5, -12(R4)
+	MOVW	ctxt+12(FP), R0
+	MOVW	R0, -8(R4)
 	MOVW	$-12(R4), R13
 	BL	runtime·cgocallbackg(SB)
 
@@ -706,7 +711,7 @@ TEXT runtime·abort(SB),NOSPLIT,$-4-0
 // 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
+// To implement publicationBarrier in sys_$GOOS_arm.s using the native
 // instructions, use:
 //
 //	TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
@@ -750,13 +755,16 @@ TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
 	MOVW	R0, ret+8(FP)
 	RET
 
-TEXT runtime·memeq(SB),NOSPLIT,$-4-13
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$-4-13
 	MOVW	a+0(FP), R1
 	MOVW	b+4(FP), R2
 	MOVW	size+8(FP), R3
 	ADD	R1, R3, R6
 	MOVW	$1, R0
 	MOVB	R0, ret+12(FP)
+	CMP	R1, R2
+	RET.EQ
 loop:
 	CMP	R1, R6
 	RET.EQ
@@ -779,7 +787,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$16-9
 	MOVW	R0, 4(R13)
 	MOVW	R1, 8(R13)
 	MOVW	R2, 12(R13)
-	BL	runtime·memeq(SB)
+	BL	runtime·memequal(SB)
 	MOVB	16(R13), R0
 	MOVB	R0, ret+8(FP)
 	RET
@@ -866,7 +874,7 @@ loop:
 	MOVB	R8, v+16(FP)
 	RET
 
-// TODO: share code with memeq?
+// TODO: share code with memequal?
 TEXT bytes·Equal(SB),NOSPLIT,$0-25
 	MOVW	a_len+4(FP), R1
 	MOVW	b_len+16(FP), R3
@@ -970,7 +978,7 @@ yieldloop:
 // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
 // Must obey the gcc calling convention.
 TEXT _cgo_topofstack(SB),NOSPLIT,$8
-	// R11 and g register are clobbered by load_g.  They are
+	// R11 and g register are clobbered by load_g. They are
 	// callee-save in the gcc calling convention, so save them here.
 	MOVW	R11, saveR11-4(SP)
 	MOVW	g, saveG-8(SP)
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
index ab5d5b5..7ebd7ba 100644
--- a/src/runtime/asm_arm64.s
+++ b/src/runtime/asm_arm64.s
@@ -149,7 +149,7 @@ TEXT runtime·gogo(SB), NOSPLIT, $-8-8
 
 // void mcall(fn func(*g))
 // Switch to m->g0's stack, call fn(g).
-// Fn must never return.  It should gogo(&g->sched)
+// 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
@@ -178,7 +178,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $-8-8
 	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
+// 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()).
@@ -211,7 +211,7 @@ TEXT runtime·systemstack(SB), NOSPLIT, $0-8
 	BL	(R3)
 
 switch:
-	// save our state in g->sched.  Pretend to
+	// 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
@@ -542,7 +542,7 @@ g0:
 	BL	(R1)
 	MOVD	R0, R9
 
-	// Restore g, stack pointer.  R0 is errno, so don't touch it
+	// 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
@@ -554,23 +554,25 @@ g0:
 	MOVW	R0, ret+16(FP)
 	RET
 
-// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
 // Turn the fn into a Go func (by taking its address) and call
 // cgocallback_gofunc.
-TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
+TEXT runtime·cgocallback(SB),NOSPLIT,$40-32
 	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	ctxt+24(FP), R0
+	MOVD	R0, 32(RSP)
 	MOVD	$runtime·cgocallback_gofunc(SB), R0
 	BL	(R0)
 	RET
 
-// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
 // See cgocall.go for more details.
-TEXT ·cgocallback_gofunc(SB),NOSPLIT,$24-24
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$24-32
 	NO_LOCAL_POINTERS
 
 	// Load g from thread-local storage.
@@ -640,13 +642,16 @@ havem:
 	// so that the traceback will seamlessly trace back into
 	// the earlier calls.
 	//
-	// In the new goroutine, -16(SP) and -8(SP) are unused.
+	// In the new goroutine, -8(SP) is unused (where SP refers to
+	// m->curg's SP while we're setting it up, before we've adjusted it).
 	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	R5, -(24+8)(R4)
+	MOVD	ctxt+24(FP), R0
+	MOVD	R0, -(16+8)(R4)
+	MOVD	$-(24+8)(R4), R0 // maintain 16-byte SP alignment
 	MOVD	R0, RSP
 	BL	runtime·cgocallbackg(SB)
 
@@ -765,13 +770,16 @@ TEXT runtime·memhash_varlen(SB),NOSPLIT,$40-24
 	MOVD	R3, ret+16(FP)
 	RET
 
-TEXT runtime·memeq(SB),NOSPLIT,$-8-25
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(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)
+	CMP	R1, R2
+	BEQ	done
 loop:
 	CMP	R1, R6
 	BEQ	done
@@ -794,7 +802,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
 	MOVD	R3, 8(RSP)
 	MOVD	R4, 16(RSP)
 	MOVD	R5, 24(RSP)
-	BL	runtime·memeq(SB)
+	BL	runtime·memequal(SB)
 	MOVBU	32(RSP), R3
 	MOVB	R3, ret+16(FP)
 	RET
@@ -929,7 +937,7 @@ notfound:
 	MOVD	R0, ret+24(FP)
 	RET
 
-// TODO: share code with memeq?
+// TODO: share code with memequal?
 TEXT bytes·Equal(SB),NOSPLIT,$0-49
 	MOVD	a_len+8(FP), R1
 	MOVD	b_len+32(FP), R3
diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s
index 08482fe..7dd35aa 100644
--- a/src/runtime/asm_mips64x.s
+++ b/src/runtime/asm_mips64x.s
@@ -12,26 +12,34 @@
 #define	REGCTXT	R22
 
 TEXT runtime·rt0_go(SB),NOSPLIT,$0
-	// R29 = stack; R1 = argc; R2 = argv
+	// R29 = stack; R4 = argc; R5 = argv
 
 	// initialize essential registers
 	JAL	runtime·reginit(SB)
 
 	ADDV	$-24, R29
-	MOVW	R1, 8(R29) // argc
-	MOVV	R2, 16(R29) // argv
+	MOVW	R4, 8(R29) // argc
+	MOVV	R5, 16(R29) // argv
 
 	// create istack out of the given (operating system) stack.
 	// _cgo_init may update stackguard.
 	MOVV	$runtime·g0(SB), g
-	MOVV	$(-64*1024), R28
-	ADDV	R28, R29, R1
+	MOVV	$(-64*1024), R23
+	ADDV	R23, R29, R1
 	MOVV	R1, g_stackguard0(g)
 	MOVV	R1, g_stackguard1(g)
 	MOVV	R1, (g_stack+stack_lo)(g)
 	MOVV	R29, (g_stack+stack_hi)(g)
 
-	// no cgo yet
+	// if there is a _cgo_init, call it using the gcc ABI.
+	MOVV	_cgo_init(SB), R25
+	BEQ	R25, nocgo
+
+	MOVV	R0, R7	// arg 3: not used
+	MOVV	R0, R6	// arg 2: not used
+	MOVV	$setg_gcc<>(SB), R5	// arg 1: setg
+	MOVV	g, R4	// arg 0: G
+	JAL	(R25)
 
 nocgo:
 	// update stackguard after _cgo_init
@@ -81,7 +89,7 @@ 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
+	// crosscall1 needs to reginit, but can't
 	// get at the 'runtime.reginit' symbol.
 	JMP	runtime·reginit(SB)
 
@@ -130,7 +138,7 @@ TEXT runtime·gogo(SB), NOSPLIT, $-8-8
 
 // void mcall(fn func(*g))
 // Switch to m->g0's stack, call fn(g).
-// Fn must never return.  It should gogo(&g->sched)
+// 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
@@ -156,7 +164,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $-8-8
 	JMP	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
+// 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()).
@@ -186,7 +194,7 @@ TEXT runtime·systemstack(SB), NOSPLIT, $0-8
 	JAL	(R4)
 
 switch:
-	// save our state in g->sched.  Pretend to
+	// save our state in g->sched. Pretend to
 	// be systemstack_switch if the G stack is scanned.
 	MOVV	$runtime·systemstack_switch(SB), R4
 	ADDV	$8, R4	// get past prologue
@@ -299,9 +307,9 @@ TEXT runtime·stackBarrier(SB),NOSPLIT,$0
 // Caution: ugly multiline assembly macros in your future!
 
 #define DISPATCH(NAME,MAXSIZE)		\
-	MOVV	$MAXSIZE, R28;		\
-	SGTU	R1, R28, R28;		\
-	BNE	R28, 3(PC);			\
+	MOVV	$MAXSIZE, R23;		\
+	SGTU	R1, R23, R23;		\
+	BNE	R23, 3(PC);			\
 	MOVV	$NAME(SB), R4;	\
 	JMP	(R4)
 // Note: can't just "BR NAME(SB)" - bad inlining results.
@@ -453,26 +461,64 @@ TEXT gosave<>(SB),NOSPLIT,$-8
 // aligned appropriately for the gcc ABI.
 // See cgocall.go for more details.
 TEXT ·asmcgocall(SB),NOSPLIT,$0-20
-	UNDEF	// no cgo yet
+	MOVV	fn+0(FP), R25
+	MOVV	arg+8(FP), R4
+
+	MOVV	R29, R3	// save original stack pointer
+	MOVV	g, R2
+
+	// 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.
+	MOVV	g_m(g), R5
+	MOVV	m_g0(R5), R6
+	BEQ	R6, g, g0
+
+	JAL	gosave<>(SB)
+	MOVV	R6, g
+	JAL	runtime·save_g(SB)
+	MOVV	(g_sched+gobuf_sp)(g), R29
+
+	// Now on a scheduling stack (a pthread-created stack).
+g0:
+	// Save room for two of our pointers.
+	ADDV	$-16, R29
+	MOVV	R2, 0(R29)	// save old g on stack
+	MOVV	(g_stack+stack_hi)(R2), R2
+	SUBVU	R3, R2
+	MOVV	R2, 8(R29)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
+	JAL	(R25)
+
+	// Restore g, stack pointer. R2 is return value.
+	MOVV	0(R29), g
+	JAL	runtime·save_g(SB)
+	MOVV	(g_stack+stack_hi)(g), R5
+	MOVV	8(R29), R6
+	SUBVU	R6, R5
+	MOVV	R5, R29
+
+	MOVW	R2, ret+16(FP)
 	RET
 
-// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
 // Turn the fn into a Go func (by taking its address) and call
 // cgocallback_gofunc.
-TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
+TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
 	MOVV	$fn+0(FP), R1
 	MOVV	R1, 8(R29)
 	MOVV	frame+8(FP), R1
 	MOVV	R1, 16(R29)
 	MOVV	framesize+16(FP), R1
 	MOVV	R1, 24(R29)
+	MOVV	ctxt+24(FP), R1
+	MOVV	R1, 32(R29)
 	MOVV	$runtime·cgocallback_gofunc(SB), R1
 	JAL	(R1)
 	RET
 
-// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
 // See cgocall.go for more details.
-TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-24
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-32
 	NO_LOCAL_POINTERS
 
 	// Load m and g from thread-local storage.
@@ -508,8 +554,8 @@ needm:
 	// 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.
-	MOVV	g_m(g), R1
-	MOVV	m_g0(R1), R1
+	MOVV	g_m(g), R3
+	MOVV	m_g0(R3), R1
 	MOVV	R29, (g_sched+gobuf_sp)(R1)
 
 havem:
@@ -537,18 +583,21 @@ havem:
 	// so that the traceback will seamlessly trace back into
 	// the earlier calls.
 	//
-	// In the new goroutine, -16(SP) and -8(SP) are unused.
+	// In the new goroutine, -8(SP) is unused (where SP refers to
+	// m->curg's SP while we're setting it up, before we've adjusted it).
 	MOVV	m_curg(R3), g
 	JAL	runtime·save_g(SB)
 	MOVV	(g_sched+gobuf_sp)(g), R2 // prepare stack as R2
-	MOVV	(g_sched+gobuf_pc)(g), R3
-	MOVV	R3, -24(R2)
+	MOVV	(g_sched+gobuf_pc)(g), R4
+	MOVV	R4, -24(R2)
+	MOVV    ctxt+24(FP), R1
+	MOVV    R1, -16(R2)
 	MOVV	$-24(R2), R29
 	JAL	runtime·cgocallbackg(SB)
 
 	// Restore g->sched (== m->curg->sched) from saved values.
-	MOVV	0(R29), R3
-	MOVV	R3, (g_sched+gobuf_pc)(g)
+	MOVV	0(R29), R4
+	MOVV	R4, (g_sched+gobuf_pc)(g)
 	MOVV	$24(R29), R2
 	MOVV	R2, (g_sched+gobuf_sp)(g)
 
@@ -580,10 +629,10 @@ TEXT runtime·setg(SB), NOSPLIT, $0-8
 	JAL	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
-	UNDEF	// no cgo yet
+// void setg_gcc(G*); set g called from gcc with g in R1
+TEXT setg_gcc<>(SB),NOSPLIT,$0-0
+	MOVV	R1, g
+	JAL	runtime·save_g(SB)
 	RET
 
 TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
@@ -647,9 +696,11 @@ TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0
 TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0
 	MOVW	(R0), R1
 
-TEXT runtime·memeq(SB),NOSPLIT,$-8-25
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$-8-25
 	MOVV	a+0(FP), R1
 	MOVV	b+8(FP), R2
+	BEQ	R1, R2, eq
 	MOVV	size+16(FP), R3
 	ADDV	R1, R3, R4
 loop:
@@ -666,6 +717,10 @@ test:
 
 	MOVB	R0, ret+24(FP)
 	RET
+eq:
+	MOVV	$1, R1
+	MOVB	R1, ret+24(FP)
+	RET
 
 // memequal_varlen(a, b unsafe.Pointer) bool
 TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
@@ -676,7 +731,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
 	MOVV	R1, 8(R29)
 	MOVV	R2, 16(R29)
 	MOVV	R3, 24(R29)
-	JAL	runtime·memeq(SB)
+	JAL	runtime·memequal(SB)
 	MOVBU	32(R29), R1
 	MOVB	R1, ret+16(FP)
 	RET
@@ -710,7 +765,7 @@ loop:
 	MOVB	R0, ret+32(FP)
 	RET
 
-// TODO: share code with memeq?
+// TODO: share code with memequal?
 TEXT bytes·Equal(SB),NOSPLIT,$0-49
 	MOVV	a_len+8(FP), R3
 	MOVV	b_len+32(FP), R4
@@ -799,8 +854,19 @@ TEXT runtime·return0(SB), NOSPLIT, $0
 
 // Called from cgo wrappers, this function returns g->m->curg.stack.hi.
 // Must obey the gcc calling convention.
-TEXT _cgo_topofstack(SB),NOSPLIT,$-8
-	UNDEF	// no cgo yet
+TEXT _cgo_topofstack(SB),NOSPLIT,$16
+	// g (R30) and REGTMP (R23)  might be clobbered by load_g. They
+	// are callee-save in the gcc calling convention, so save them.
+	MOVV	R23, savedR23-16(SP)
+	MOVV	g, savedG-8(SP)
+
+	JAL	runtime·load_g(SB)
+	MOVV	g_m(g), R1
+	MOVV	m_curg(R1), R1
+	MOVV	(g_stack+stack_hi)(R1), R2 // return value in R2
+
+	MOVV	savedG-8(SP), g
+	MOVV	savedR23-16(SP), R23
 	RET
 
 // The top-most function running on a goroutine
diff --git a/src/runtime/asm_ppc64x.h b/src/runtime/asm_ppc64x.h
index a413df6..5e55055 100644
--- a/src/runtime/asm_ppc64x.h
+++ b/src/runtime/asm_ppc64x.h
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -14,7 +14,7 @@
 // +---------------------+ <- R1
 //
 // So a function that sets up a stack frame at all uses as least FIXED_FRAME
-// bytes of stack.  This mostly affects assembly that calls other functions
+// bytes of stack. This mostly affects assembly that calls other functions
 // with arguments (the arguments should be stored at FIXED_FRAME+0(R1),
 // FIXED_FRAME+8(R1) etc) and some other low-level places.
 //
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index 50c4f26..32c63c2 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -155,7 +155,7 @@ TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8
 
 // void mcall(fn func(*g))
 // Switch to m->g0's stack, call fn(g).
-// Fn must never return.  It should gogo(&g->sched)
+// Fn must never return. It should gogo(&g->sched)
 // to keep running g.
 TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8
 	// Save caller state in g->sched
@@ -187,7 +187,7 @@ TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8
 	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
+// 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()).
@@ -226,7 +226,7 @@ TEXT runtime·systemstack(SB), NOSPLIT, $0-8
 	BL	(CTR)
 
 switch:
-	// save our state in g->sched.  Pretend to
+	// save our state in g->sched. Pretend to
 	// be systemstack_switch if the G stack is scanned.
 	MOVD	$runtime·systemstack_switch(SB), R6
 	ADD     $16, R6 // get past prologue (including r2-setting instructions when they're there)
@@ -569,24 +569,26 @@ g0:
 	MOVW	R3, ret+16(FP)
 	RET
 
-// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
 // Turn the fn into a Go func (by taking its address) and call
 // cgocallback_gofunc.
-TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
+TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
 	MOVD	$fn+0(FP), R3
 	MOVD	R3, FIXED_FRAME+0(R1)
 	MOVD	frame+8(FP), R3
 	MOVD	R3, FIXED_FRAME+8(R1)
 	MOVD	framesize+16(FP), R3
 	MOVD	R3, FIXED_FRAME+16(R1)
+	MOVD	ctxt+24(FP), R3
+	MOVD	R3, FIXED_FRAME+24(R1)
 	MOVD	$runtime·cgocallback_gofunc(SB), R12
 	MOVD	R12, CTR
 	BL	(CTR)
 	RET
 
-// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
 // See cgocall.go for more details.
-TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-24
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-32
 	NO_LOCAL_POINTERS
 
 	// Load m and g from thread-local storage.
@@ -654,12 +656,15 @@ havem:
 	// so that the traceback will seamlessly trace back into
 	// the earlier calls.
 	//
-	// In the new goroutine, -16(SP) and -8(SP) are unused.
+	// In the new goroutine, -8(SP) is unused (where SP refers to
+	// m->curg's SP while we're setting it up, before we've adjusted it).
 	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, -(FIXED_FRAME+16)(R4)
+	MOVD	ctxt+24(FP), R3
+	MOVD	R3, -16(R4)
 	MOVD	$-(FIXED_FRAME+16)(R4), R1
 	BL	runtime·cgocallbackg(SB)
 
@@ -795,26 +800,13 @@ TEXT runtime·aeshash64(SB),NOSPLIT|NOFRAME,$0-0
 TEXT runtime·aeshashstr(SB),NOSPLIT|NOFRAME,$0-0
 	MOVW	(R0), R1
 
-TEXT runtime·memeq(SB),NOSPLIT|NOFRAME,$0-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
+TEXT runtime·memequal(SB),NOSPLIT,$0-25
+	MOVD    a+0(FP), R3
+	MOVD    b+8(FP), R4
+	MOVD    size+16(FP), R5
 
-	MOVB	R0, ret+24(FP)
+	BL	runtime·memeqbody(SB)
+	MOVB    R9, ret+24(FP)
 	RET
 
 // memequal_varlen(a, b unsafe.Pointer) bool
@@ -824,75 +816,129 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
 	CMP	R3, R4
 	BEQ	eq
 	MOVD	8(R11), R5    // compiler stores size at offset 8 in the closure
-	MOVD	R3, FIXED_FRAME+0(R1)
-	MOVD	R4, FIXED_FRAME+8(R1)
-	MOVD	R5, FIXED_FRAME+16(R1)
-	BL	runtime·memeq(SB)
-	MOVBZ	FIXED_FRAME+24(R1), R3
-	MOVB	R3, ret+16(FP)
+	BL	runtime·memeqbody(SB)
+	MOVB	R9, ret+16(FP)
 	RET
 eq:
 	MOVD	$1, R3
 	MOVB	R3, ret+16(FP)
 	RET
 
+// Do an efficieint memequal for ppc64
+// for reuse where possible.
+// R3 = s1
+// R4 = s2
+// R5 = len
+// R9 = return value
+// R6, R7 clobbered
+TEXT runtime·memeqbody(SB),NOSPLIT|NOFRAME,$0-0
+	MOVD    R5,CTR
+	CMP     R5,$8		// only optimize >=8
+	BLT     simplecheck
+	DCBT	(R3)		// cache hint
+	DCBT	(R4)
+	CMP	R5,$32		// optimize >= 32
+	MOVD	R5,R6		// needed if setup8a branch
+	BLT	setup8a		// 8 byte moves only
+setup32a:                       // 8 byte aligned, >= 32 bytes
+	SRADCC  $5,R5,R6        // number of 32 byte chunks to compare
+	MOVD	R6,CTR
+loop32a:
+	MOVD    0(R3),R6        // doublewords to compare
+	MOVD    0(R4),R7
+	MOVD	8(R3),R8	//
+	MOVD	8(R4),R9
+	CMP     R6,R7           // bytes batch?
+	BNE     noteq
+	MOVD	16(R3),R6
+	MOVD	16(R4),R7
+	CMP     R8,R9		// bytes match?
+	MOVD	24(R3),R8
+	MOVD	24(R4),R9
+	BNE     noteq
+	CMP     R6,R7           // bytes match?
+	BNE	noteq
+	ADD     $32,R3		// bump up to next 32
+	ADD     $32,R4
+	CMP     R8,R9           // bytes match?
+	BC      8,2,loop32a	// br ctr and cr
+	BNE	noteq
+	ANDCC	$24,R5,R6       // Any 8 byte chunks?
+	BEQ	leftover	// and result is 0
+setup8a:
+	SRADCC  $3,R6,R6        // get the 8 byte count
+	BEQ	leftover	// shifted value is 0
+	MOVD    R6,CTR
+loop8:
+	MOVD    0(R3),R6        // doublewords to compare
+	ADD	$8,R3
+	MOVD    0(R4),R7
+	ADD     $8,R4
+	CMP     R6,R7           // match?
+	BC	8,2,loop8	// bt ctr <> 0 && cr
+	BNE     noteq
+leftover:
+	ANDCC   $7,R5,R6        // check for leftover bytes
+	BEQ     equal
+	MOVD    R6,CTR
+	BR	simple
+simplecheck:
+	CMP	R5,$0
+	BEQ	equal
+simple:
+	MOVBZ   0(R3), R6
+	ADD	$1,R3
+	MOVBZ   0(R4), R7
+	ADD     $1,R4
+	CMP     R6, R7
+	BNE     noteq
+	BC      8,2,simple
+	BNE	noteq
+	BR	equal
+noteq:
+	MOVD    $0, R9
+	RET
+equal:
+	MOVD    $1, R9
+	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)
+	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)
+	MOVD    s1len+8(FP), R5
+	BL      runtime·memeqbody(SB)
+	MOVB    R9, 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
+	MOVD	a_len+8(FP), R4
+	MOVD	b_len+32(FP), R5
+	CMP	R5, R4		// unequal lengths are not equal
 	BNE	noteq
+	MOVD	a+0(FP), R3
+	MOVD	b+24(FP), R4
+	BL	runtime·memeqbody(SB)
 
-	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
+	MOVBZ	R9,ret+48(FP)
+	RET
 
 noteq:
-	MOVBZ	R0, ret+48(FP)
+	MOVBZ	$0,ret+48(FP)
 	RET
 
 equal:
-	MOVD	$1, R3
-	MOVBZ	R3, ret+48(FP)
+	MOVD	$1,R3
+	MOVBZ	R3,ret+48(FP)
 	RET
 
 TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s
new file mode 100644
index 0000000..896ccde
--- /dev/null
+++ b/src/runtime/asm_s390x.s
@@ -0,0 +1,1135 @@
+// Copyright 2016 The Go 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"
+
+// Indicate the status of vector facility
+// -1: 	init value
+// 0:	vector not installed
+// 1:	vector installed and enabled
+// 2:	vector installed but not enabled
+
+DATA runtime·vectorfacility+0x00(SB)/4, $-1
+GLOBL runtime·vectorfacility(SB), NOPTR, $4
+
+TEXT runtime·checkvectorfacility(SB),NOSPLIT,$32-0
+	MOVD    $2, R0
+	MOVD	R1, tmp-32(SP)
+	MOVD    $x-24(SP), R1
+//      STFLE   0(R1)
+	WORD    $0xB2B01000
+	MOVBZ   z-8(SP), R1
+	AND     $0x40, R1
+	BNE     vectorinstalled
+	MOVB    $0, runtime·vectorfacility(SB) //Vector not installed
+	MOVD	tmp-32(SP), R1
+	MOVD    $0, R0
+	RET
+vectorinstalled:
+	// check if the vector instruction has been enabled
+	VLEIB   $0, $0xF, V16
+	VLGVB   $0, V16, R0
+	CMPBEQ  R0, $0xF, vectorenabled
+	MOVB    $2, runtime·vectorfacility(SB) //Vector installed but not enabled
+	MOVD    tmp-32(SP), R1
+	MOVD    $0, R0
+	RET
+vectorenabled:
+	MOVB    $1, runtime·vectorfacility(SB) //Vector installed and enabled
+	MOVD    tmp-32(SP), R1
+	MOVD    $0, R0
+	RET
+
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
+	// R2 = argc; R3 = argv; R11 = temp; R13 = g; R15 = stack pointer
+	// C TLS base pointer in AR0:AR1
+
+	// initialize essential registers
+	XOR	R0, R0
+
+	SUB	$24, R15
+	MOVW	R2, 8(R15) // argc
+	MOVD	R3, 16(R15) // argv
+
+	// create istack out of the given (operating system) stack.
+	// _cgo_init may update stackguard.
+	MOVD	$runtime·g0(SB), g
+	MOVD	R15, R11
+	SUB	$(64*1024), R11
+	MOVD	R11, g_stackguard0(g)
+	MOVD	R11, g_stackguard1(g)
+	MOVD	R11, (g_stack+stack_lo)(g)
+	MOVD	R15, (g_stack+stack_hi)(g)
+
+	// if there is a _cgo_init, call it using the gcc ABI.
+	MOVD	_cgo_init(SB), R11
+	CMPBEQ	R11, $0, nocgo
+	MOVW	AR0, R4			// (AR0 << 32 | AR1) is the TLS base pointer; MOVD is translated to EAR
+	SLD	$32, R4, R4
+	MOVW	AR1, R4			// arg 2: TLS base pointer
+	MOVD	$setg_gcc<>(SB), R3 	// arg 1: setg
+	MOVD	g, R2			// arg 0: G
+	// C functions expect 160 bytes of space on caller stack frame
+	// and an 8-byte aligned stack pointer
+	MOVD	R15, R9			// save current stack (R9 is preserved in the Linux ABI)
+	SUB	$160, R15		// reserve 160 bytes
+	MOVD    $~7, R6
+	AND 	R6, R15			// 8-byte align
+	BL	R11			// this call clobbers volatile registers according to Linux ABI (R0-R5, R14)
+	MOVD	R9, R15			// restore stack
+	XOR	R0, R0			// zero R0
+
+nocgo:
+	// update stackguard after _cgo_init
+	MOVD	(g_stack+stack_lo)(g), R2
+	ADD	$const__StackGuard, R2
+	MOVD	R2, g_stackguard0(g)
+	MOVD	R2, g_stackguard1(g)
+
+	// set the per-goroutine and per-mach "registers"
+	MOVD	$runtime·m0(SB), R2
+
+	// save m->g0 = g0
+	MOVD	g, m_g0(R2)
+	// save m0 to g0->m
+	MOVD	R2, g_m(g)
+
+	BL	runtime·check(SB)
+
+	// argc/argv are already prepared on stack
+	BL	runtime·args(SB)
+	BL	runtime·osinit(SB)
+	BL	runtime·schedinit(SB)
+
+	// create a new goroutine to start program
+	MOVD	$runtime·mainPC(SB), R2		// entry
+	SUB     $24, R15
+	MOVD 	R2, 16(R15)
+	MOVD 	R0, 8(R15)
+	MOVD 	R0, 0(R15)
+	BL	runtime·newproc(SB)
+	ADD	$24, R15
+
+	// 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|NOFRAME,$0-0
+	MOVD	R0, 2(R0)
+	RET
+
+TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0
+	RET
+
+/*
+ *  go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+TEXT runtime·gosave(SB), NOSPLIT, $-8-8
+	MOVD	buf+0(FP), R3
+	MOVD	R15, gobuf_sp(R3)
+	MOVD	LR, gobuf_pc(R3)
+	MOVD	g, gobuf_g(R3)
+	MOVD	$0, gobuf_lr(R3)
+	MOVD	$0, gobuf_ret(R3)
+	MOVD	$0, 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), R15
+	MOVD	gobuf_lr(R5), LR
+	MOVD	gobuf_ret(R5), R3
+	MOVD	gobuf_ctxt(R5), R12
+	MOVD	$0, gobuf_sp(R5)
+	MOVD	$0, gobuf_ret(R5)
+	MOVD	$0, gobuf_lr(R5)
+	MOVD	$0, gobuf_ctxt(R5)
+	CMP	R0, R0 // set condition codes for == test, needed by stack split
+	MOVD	gobuf_pc(R5), R6
+	BR	(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	R15, (g_sched+gobuf_sp)(g)
+	MOVD	LR, (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), R12			// context
+	MOVD	0(R12), R4			// code pointer
+	MOVD	(g_sched+gobuf_sp)(g), R15	// sp = m->g0->sched.sp
+	SUB	$16, R15
+	MOVD	R3, 8(R15)
+	MOVD	$0, 0(R15)
+	BL	(R4)
+	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, R12		// context
+	MOVD	g_m(g), R4	// R4 = m
+
+	MOVD	m_gsignal(R4), R5	// R5 = gsignal
+	CMPBEQ	g, R5, noswitch
+
+	MOVD	m_g0(R4), R5	// R5 = g0
+	CMPBEQ	g, R5, noswitch
+
+	MOVD	m_curg(R4), R6
+	CMPBEQ	g, R6, 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	$16, R6	// get past prologue
+	MOVD	R6, (g_sched+gobuf_pc)(g)
+	MOVD	R15, (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, R15
+
+	// call target function
+	MOVD	0(R12), 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), R15
+	MOVD	$0, (g_sched+gobuf_sp)(g)
+	RET
+
+noswitch:
+	// already on m stack, just call directly
+	MOVD	0(R12), R3	// code pointer
+	BL	(R3)
+	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|NOFRAME,$0-0
+	// Cannot grow scheduler stack (m->g0).
+	MOVD	g_m(g), R7
+	MOVD	m_g0(R7), R8
+	CMPBNE	g, R8, 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	R12, (g_sched+gobuf_ctxt)(g)
+	MOVD	R15, (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	R15, (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), R15
+	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|NOFRAME,$0-0
+	MOVD	$0, R12
+	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.
+	BR	(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, R4;		\
+	CMP	R3, R4;		\
+	BGT	3(PC);			\
+	MOVD	$NAME(SB), R5;	\
+	BR	(R5)
+// 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), R5
+	BR	(R5)
+
+#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	R15, R5;				\
+	ADD	$(8-1), R5;			\
+	SUB	$1, R3;				\
+	ADD	R5, R4;				\
+	CMP	R5, R4;				\
+	BEQ	6(PC);				\
+	ADD	$1, R3;				\
+	ADD	$1, R5;				\
+	MOVBZ	0(R3), R6;			\
+	MOVBZ	R6, 0(R5);			\
+	BR	-6(PC);				\
+	/* call function */			\
+	MOVD	f+8(FP), R12;			\
+	MOVD	(R12), R8;			\
+	PCDATA  $PCDATA_StackMapIndex, $0;	\
+	BL	(R8);				\
+	/* copy return values back */		\
+	MOVD	arg+16(FP), R3;			\
+	MOVWZ	n+24(FP), R4;			\
+	MOVWZ	retoffset+28(FP), R6;		\
+	MOVD	R15, 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;				\
+	ADD	$1, R5;				\
+	ADD	$1, R3;				\
+	MOVBZ	0(R5), R6;			\
+	MOVBZ	R6, 0(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(R15);			\
+	MOVD	R3, 16(R15);			\
+	MOVD	R4, 24(R15);			\
+	MOVD	R6, 32(R15);			\
+	BL	runtime·callwritebarrier(SB);	\
+	RET
+
+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)
+
+TEXT runtime·procyield(SB),NOSPLIT,$0-0
+	RET
+
+// void jmpdefer(fv, sp);
+// called from deferreturn.
+// 1. grab stored LR for caller
+// 2. sub 6 bytes to get back to BL deferreturn (size of BRASL instruction)
+// 3. BR to fn
+TEXT runtime·jmpdefer(SB),NOSPLIT|NOFRAME,$0-16
+	MOVD	0(R15), R1
+	SUB	$6, R1, LR
+
+	MOVD	fv+0(FP), R12
+	MOVD	argp+8(FP), R15
+	SUB	$8, R15
+	MOVD	0(R12), R3
+	BR	(R3)
+
+// Save state of caller into g->sched. Smashes R31.
+TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
+	MOVD	LR, (g_sched+gobuf_pc)(g)
+	MOVD	R15, (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
+	// R2 = argc; R3 = argv; R11 = temp; R13 = g; R15 = stack pointer
+	// C TLS base pointer in AR0:AR1
+	MOVD	fn+0(FP), R3
+	MOVD	arg+8(FP), R4
+
+	MOVD	R15, 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
+	CMPBEQ	R6, g, g0
+	BL	gosave<>(SB)
+	MOVD	R6, g
+	BL	runtime·save_g(SB)
+	MOVD	(g_sched+gobuf_sp)(g), R15
+
+	// Now on a scheduling stack (a pthread-created stack).
+g0:
+	// Save room for two of our pointers, plus 160 bytes of callee
+	// save area that lives on the caller stack.
+	SUB	$176, R15
+	MOVD	$~7, R6
+	AND	R6, R15                 // 8-byte alignment for gcc ABI
+	MOVD	R5, 168(R15)             // save old g on stack
+	MOVD	(g_stack+stack_hi)(R5), R5
+	SUB	R2, R5
+	MOVD	R5, 160(R15)             // save depth in old g stack (can't just save SP, as stack might be copied during a callback)
+	MOVD	R0, 0(R15)              // clear back chain pointer (TODO can we give it real back trace information?)
+	MOVD	R4, R2                  // arg in R2
+	BL	R3                      // can clobber: R0-R5, R14, F0-F3, F5, F7-F15
+
+	XOR	R0, R0                  // set R0 back to 0.
+	// Restore g, stack pointer.
+	MOVD	168(R15), g
+	BL	runtime·save_g(SB)
+	MOVD	(g_stack+stack_hi)(g), R5
+	MOVD	160(R15), R6
+	SUB	R6, R5
+	MOVD	R5, R15
+
+	MOVW	R2, ret+16(FP)
+	RET
+
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
+// Turn the fn into a Go func (by taking its address) and call
+// cgocallback_gofunc.
+TEXT runtime·cgocallback(SB),NOSPLIT,$32-32
+	MOVD	$fn+0(FP), R3
+	MOVD	R3, 8(R15)
+	MOVD	frame+8(FP), R3
+	MOVD	R3, 16(R15)
+	MOVD	framesize+16(FP), R3
+	MOVD	R3, 24(R15)
+	MOVD	ctxt+24(FP), R3
+	MOVD	R3, 32(R15)
+	MOVD	$runtime·cgocallback_gofunc(SB), R3
+	BL	(R3)
+	RET
+
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize, uintptr ctxt)
+// See cgocall.go for more details.
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-32
+	NO_LOCAL_POINTERS
+
+	// Load m and g from thread-local storage.
+	MOVB	runtime·iscgo(SB), R3
+	CMPBEQ	R3, $0, 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.
+	CMPBEQ	g, $0, needm
+
+	MOVD	g_m(g), R8
+	MOVD	R8, savedm-8(SP)
+	BR	havem
+
+needm:
+	MOVD	g, savedm-8(SP) // g is zero, so is m.
+	MOVD	$runtime·needm(SB), R3
+	BL	(R3)
+
+	// Set m->sched.sp = SP, so that if a panic happens
+	// during the function we are about to execute, it will
+	// have a valid SP to run on the g0 stack.
+	// The next few lines (after the havem label)
+	// will save this SP onto the stack and then write
+	// the same SP back to m->sched.sp. That seems redundant,
+	// but if an unrecovered panic happens, unwindm will
+	// restore the g->sched.sp from the stack location
+	// and then systemstack will try to use it. If we don't set it here,
+	// that restored SP will be uninitialized (typically 0) and
+	// will not be usable.
+	MOVD	g_m(g), R8
+	MOVD	m_g0(R8), R3
+	MOVD	R15, (g_sched+gobuf_sp)(R3)
+
+havem:
+	// 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	R15, (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, -8(SP) is unused (where SP refers to
+	// m->curg's SP while we're setting it up, before we've adjusted it).
+	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	ctxt+24(FP), R5
+	MOVD	R5, -16(R4)
+	MOVD	$-24(R4), R15
+	BL	runtime·cgocallbackg(SB)
+
+	// Restore g->sched (== m->curg->sched) from saved values.
+	MOVD	0(R15), R5
+	MOVD	R5, (g_sched+gobuf_pc)(g)
+	MOVD	$24(R15), 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), R15
+	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
+	CMPBNE	R6, $0, droppedm
+	MOVD	$runtime·dropm(SB), R3
+	BL	(R3)
+droppedm:
+
+	// Done!
+	RET
+
+// void setg(G*); set g. for use by needm.
+TEXT runtime·setg(SB), NOSPLIT, $0-8
+	MOVD	gg+0(FP), g
+	// This only happens if iscgo, so jump straight to save_g
+	BL	runtime·save_g(SB)
+	RET
+
+// void setg_gcc(G*); set g in C TLS.
+// Must obey the gcc calling convention.
+TEXT setg_gcc<>(SB),NOSPLIT|NOFRAME,$0-0
+	// The standard prologue clobbers LR (R14), which is callee-save in
+	// the C ABI, so we have to use NOFRAME and save LR ourselves.
+	MOVD	LR, R1
+	// Also save g, R10, and R11 since they're callee-save in C ABI
+	MOVD	R10, R3
+	MOVD	g, R4
+	MOVD	R11, R5
+
+	MOVD	R2, g
+	BL	runtime·save_g(SB)
+
+	MOVD	R5, R11
+	MOVD	R4, g
+	MOVD	R3, R10
+	MOVD	R1, LR
+	RET
+
+TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
+	MOVD	16(R15), R3		// LR saved by caller
+	MOVD	runtime·stackBarrierPC(SB), R4
+	CMPBNE	R3, R4, nobar
+	// Get original return PC.
+	BL	runtime·nextBarrierPC(SB)
+	MOVD	8(R15), R3
+nobar:
+	MOVD	R3, ret+8(FP)
+	RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
+	MOVD	pc+8(FP), R3
+	MOVD	16(R15), R4
+	MOVD	runtime·stackBarrierPC(SB), R5
+	CMPBEQ	R4, R5, setbar
+	MOVD	R3, 16(R15)		// set LR in caller
+	RET
+setbar:
+	// Set the stack barrier return PC.
+	MOVD	R3, 8(R15)
+	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|NOFRAME,$0-0
+	MOVW	(R0), R0
+	UNDEF
+
+// int64 runtime·cputicks(void)
+TEXT runtime·cputicks(SB),NOSPLIT,$0-8
+	// The TOD clock on s390 counts from the year 1900 in ~250ps intervals.
+	// This means that since about 1972 the msb has been set, making the
+	// result of a call to STORE CLOCK (stck) a negative number.
+	// We clear the msb to make it positive.
+	STCK	ret+0(FP)      // serialises before and after call
+	MOVD	ret+0(FP), R3  // R3 will wrap to 0 in the year 2043
+	SLD	$1, R3
+	SRD	$1, 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(R12), R5
+	MOVD	R3, 8(R15)
+	MOVD	R4, 16(R15)
+	MOVD	R5, 24(R15)
+	BL	runtime·memhash(SB)
+	MOVD	32(R15), R3
+	MOVD	R3, ret+16(FP)
+	RET
+
+// AES hashing not implemented for s390x
+TEXT runtime·aeshash(SB),NOSPLIT|NOFRAME,$0-0
+	MOVW	(R0), R15
+TEXT runtime·aeshash32(SB),NOSPLIT|NOFRAME,$0-0
+	MOVW	(R0), R15
+TEXT runtime·aeshash64(SB),NOSPLIT|NOFRAME,$0-0
+	MOVW	(R0), R15
+TEXT runtime·aeshashstr(SB),NOSPLIT|NOFRAME,$0-0
+	MOVW	(R0), R15
+
+// memequal(p, q unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25
+	MOVD	p+0(FP), R3
+	MOVD	q+8(FP), R5
+	MOVD	size+16(FP), R6
+	LA	ret+24(FP), R7
+	BR	runtime·memeqbody(SB)
+
+// memequal_varlen(a, b unsafe.Pointer) bool
+TEXT runtime·memequal_varlen(SB),NOSPLIT|NOFRAME,$0-17
+	MOVD	a+0(FP), R3
+	MOVD	b+8(FP), R5
+	MOVD	8(R12), R6    // compiler stores size at offset 8 in the closure
+	LA	ret+16(FP), R7
+	BR	runtime·memeqbody(SB)
+
+// 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|NOFRAME,$0-33
+	MOVD	s1str+0(FP), R3
+	MOVD	s1len+8(FP), R6
+	MOVD	s2str+16(FP), R5
+	LA	ret+32(FP), R7
+	BR	runtime·memeqbody(SB)
+
+TEXT bytes·Equal(SB),NOSPLIT|NOFRAME,$0-49
+	MOVD	a_len+8(FP), R2
+	MOVD	b_len+32(FP), R6
+	MOVD	a+0(FP), R3
+	MOVD	b+24(FP), R5
+	LA	ret+48(FP), R7
+	CMPBNE	R2, R6, notequal
+	BR	runtime·memeqbody(SB)
+notequal:
+	MOVB	$0, ret+48(FP)
+	RET
+
+// input:
+//   R3 = a
+//   R5 = b
+//   R6 = len
+//   R7 = address of output byte (stores 0 or 1 here)
+//   a and b have the same length
+TEXT runtime·memeqbody(SB),NOSPLIT|NOFRAME,$0-0
+	CMPBEQ	R3, R5, equal
+loop:
+	CMPBEQ	R6, $0, equal
+	CMPBLT	R6, $32, tiny
+	CMP	R6, $256
+	BLT	tail
+	CLC	$256, 0(R3), 0(R5)
+	BNE	notequal
+	SUB	$256, R6
+	LA	256(R3), R3
+	LA	256(R5), R5
+	BR	loop
+tail:
+	SUB	$1, R6, R8
+	EXRL	$runtime·memeqbodyclc(SB), R8
+	BEQ	equal
+notequal:
+	MOVB	$0, 0(R7)
+	RET
+equal:
+	MOVB	$1, 0(R7)
+	RET
+tiny:
+	MOVD	$0, R2
+	CMPBLT	R6, $16, lt16
+	MOVD	0(R3), R8
+	MOVD	0(R5), R9
+	CMPBNE	R8, R9, notequal
+	MOVD	8(R3), R8
+	MOVD	8(R5), R9
+	CMPBNE	R8, R9, notequal
+	LA	16(R2), R2
+	SUB	$16, R6
+lt16:
+	CMPBLT	R6, $8, lt8
+	MOVD	0(R3)(R2*1), R8
+	MOVD	0(R5)(R2*1), R9
+	CMPBNE	R8, R9, notequal
+	LA	8(R2), R2
+	SUB	$8, R6
+lt8:
+	CMPBLT	R6, $4, lt4
+	MOVWZ	0(R3)(R2*1), R8
+	MOVWZ	0(R5)(R2*1), R9
+	CMPBNE	R8, R9, notequal
+	LA	4(R2), R2
+	SUB	$4, R6
+lt4:
+#define CHECK(n) \
+	CMPBEQ	R6, $n, equal \
+	MOVB	n(R3)(R2*1), R8 \
+	MOVB	n(R5)(R2*1), R9 \
+	CMPBNE	R8, R9, notequal
+	CHECK(0)
+	CHECK(1)
+	CHECK(2)
+	CHECK(3)
+	BR	equal
+
+TEXT runtime·memeqbodyclc(SB),NOSPLIT|NOFRAME,$0-0
+	CLC	$1, 0(R3), 0(R5)
+	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 bytes·IndexByte(SB),NOSPLIT,$0-40
+	MOVD	s+0(FP), R3     // s => R3
+	MOVD	s_len+8(FP), R4 // s_len => R4
+	MOVBZ	c+24(FP), R5    // c => R5
+	MOVD	$ret+32(FP), R2 // &ret => R9
+	BR	runtime·indexbytebody(SB)
+
+TEXT strings·IndexByte(SB),NOSPLIT,$0-32
+	MOVD	s+0(FP), R3     // s => R3
+	MOVD	s_len+8(FP), R4 // s_len => R4
+	MOVBZ	c+16(FP), R5    // c => R5
+	MOVD	$ret+24(FP), R2 // &ret => R9
+	BR	runtime·indexbytebody(SB)
+
+// input:
+// R3: s
+// R4: s_len
+// R5: c -- byte sought
+// R2: &ret -- address to put index into
+TEXT runtime·indexbytebody(SB),NOSPLIT,$0
+	CMPBEQ	R4, $0, notfound
+	MOVD	R3, R6          // store base for later
+	ADD	R3, R4, R8      // the address after the end of the string
+	//if the length is small, use loop; otherwise, use vector or srst search
+	CMPBGE	R4, $16, large
+
+residual:
+	CMPBEQ	R3, R8, notfound
+	MOVBZ	0(R3), R7
+	LA	1(R3), R3
+	CMPBNE	R7, R5, residual
+
+found:
+	SUB	R6, R3
+	SUB	$1, R3
+	MOVD	R3, 0(R2)
+	RET
+
+notfound:
+	MOVD	$-1, 0(R2)
+	RET
+
+large:
+	MOVB	runtime·vectorfacility(SB), R1
+	CMPBEQ	R1, $-1, checkvector	// vectorfacility = -1, vector not checked yet
+vectorchecked:
+	CMPBEQ	R1, $1, vectorimpl      // vectorfacility = 1, vector supported
+
+srstimpl:                       // vectorfacility != 1, not support or enable vector
+	MOVBZ	R5, R0          // c needs to be in R0, leave until last minute as currently R0 is expected to be 0
+srstloop:
+	WORD	$0xB25E0083     // srst %r8, %r3 (search the range [R3, R8))
+	BVS	srstloop        // interrupted - continue
+	BGT	notfoundr0
+foundr0:
+	XOR	R0, R0          // reset R0
+	SUB	R6, R8          // remove base
+	MOVD	R8, 0(R2)
+	RET
+notfoundr0:
+	XOR	R0, R0          // reset R0
+	MOVD	$-1, 0(R2)
+	RET
+
+vectorimpl:
+	//if the address is not 16byte aligned, use loop for the header
+	AND	$15, R3, R8
+	CMPBGT	R8, $0, notaligned
+
+aligned:
+	ADD	R6, R4, R8
+	AND	$-16, R8, R7
+	// replicate c across V17
+	VLVGB	$0, R5, V19
+	VREPB	$0, V19, V17
+
+vectorloop:
+	CMPBGE	R3, R7, residual
+	VL	0(R3), V16    // load string to be searched into V16
+	ADD	$16, R3
+	VFEEBS	V16, V17, V18 // search V17 in V16 and set conditional code accordingly
+	BVS	vectorloop
+
+	// when vector search found c in the string
+	VLGVB	$7, V18, R7   // load 7th element of V18 containing index into R7
+	SUB	$16, R3
+	SUB	R6, R3
+	ADD	R3, R7
+	MOVD	R7, 0(R2)
+	RET
+
+notaligned:
+	AND	$-16, R3, R8
+	ADD     $16, R8
+notalignedloop:
+	CMPBEQ	R3, R8, aligned
+	MOVBZ	0(R3), R7
+	LA	1(R3), R3
+	CMPBNE	R7, R5, notalignedloop
+	BR	found
+
+checkvector:
+	CALL	runtime·checkvectorfacility(SB)
+	MOVB    runtime·vectorfacility(SB), R1
+	BR	vectorchecked
+
+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|NOFRAME,$0
+	// g (R13), R10, R11 and LR (R14) are callee-save in the C ABI, so save them
+	MOVD	g, R1
+	MOVD	R10, R3
+	MOVD	LR, R4
+	MOVD	R11, R5
+
+	BL	runtime·load_g(SB)	// clobbers g (R13), R10, R11
+	MOVD	g_m(g), R2
+	MOVD	m_curg(R2), R2
+	MOVD	(g_stack+stack_hi)(R2), R2
+
+	MOVD	R1, g
+	MOVD	R3, R10
+	MOVD	R4, LR
+	MOVD	R5, R11
+	RET
+
+// The top-most function running on a goroutine
+// returns to goexit+PCQuantum.
+TEXT runtime·goexit(SB),NOSPLIT|NOFRAME,$0-0
+	BYTE $0x07; BYTE $0x00; // 2-byte nop
+	BL	runtime·goexit1(SB)	// does not return
+	// traceback from goexit1 must hit code range of goexit
+	BYTE $0x07; BYTE $0x00; // 2-byte 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
+
+TEXT runtime·sigreturn(SB),NOSPLIT,$0-8
+	RET
+
+TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
+	SYNC
+	RET
+
+TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40
+	MOVD	s1_base+0(FP), R3
+	MOVD	s1_len+8(FP), R4
+	MOVD	s2_base+16(FP), R5
+	MOVD	s2_len+24(FP), R6
+	LA	ret+32(FP), R7
+	BR	runtime·cmpbody(SB)
+
+TEXT bytes·Compare(SB),NOSPLIT|NOFRAME,$0-56
+	MOVD	s1+0(FP), R3
+	MOVD	s1+8(FP), R4
+	MOVD	s2+24(FP), R5
+	MOVD	s2+32(FP), R6
+	LA	res+48(FP), R7
+	BR	runtime·cmpbody(SB)
+
+// input:
+//   R3 = a
+//   R4 = alen
+//   R5 = b
+//   R6 = blen
+//   R7 = address of output word (stores -1/0/1 here)
+TEXT runtime·cmpbody(SB),NOSPLIT|NOFRAME,$0-0
+	CMPBEQ	R3, R5, cmplengths
+	MOVD	R4, R8
+	CMPBLE	R4, R6, amin
+	MOVD	R6, R8
+amin:
+	CMPBEQ	R8, $0, cmplengths
+	CMP	R8, $256
+	BLE	tail
+loop:
+	CLC	$256, 0(R3), 0(R5)
+	BGT	gt
+	BLT	lt
+	SUB	$256, R8
+	CMP	R8, $256
+	BGT	loop
+tail:
+	SUB	$1, R8
+	EXRL	$runtime·cmpbodyclc(SB), R8
+	BGT	gt
+	BLT	lt
+cmplengths:
+	CMP	R4, R6
+	BEQ	eq
+	BLT	lt
+gt:
+	MOVD	$1, 0(R7)
+	RET
+lt:
+	MOVD	$-1, 0(R7)
+	RET
+eq:
+	MOVD	$0, 0(R7)
+	RET
+
+TEXT runtime·cmpbodyclc(SB),NOSPLIT|NOFRAME,$0-0
+	CLC	$1, 0(R3), 0(R5)
+	RET
+
+// This is called from .init_array and follows the platform, not Go, ABI.
+// We are overly conservative. We could only save the registers we use.
+// However, since this function is only called once per loaded module
+// performance is unimportant.
+TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0
+	// Save R6-R15, F0, F2, F4 and F6 in the
+	// register save area of the calling function
+	STMG	R6, R15, 48(R15)
+	FMOVD	F0, 128(R15)
+	FMOVD	F2, 136(R15)
+	FMOVD	F4, 144(R15)
+	FMOVD	F6, 152(R15)
+
+	// append the argument (passed in R2, as per the ELF ABI) to the
+	// moduledata linked list.
+	MOVD	runtime·lastmoduledatap(SB), R1
+	MOVD	R2, moduledata_next(R1)
+	MOVD	R2, runtime·lastmoduledatap(SB)
+
+	// Restore R6-R15, F0, F2, F4 and F6
+	LMG	48(R15), R6, R15
+	FMOVD	F0, 128(R15)
+	FMOVD	F2, 136(R15)
+	FMOVD	F4, 144(R15)
+	FMOVD	F6, 152(R15)
+	RET
+
+TEXT ·checkASM(SB),NOSPLIT,$0-1
+	MOVB	$1, ret+0(FP)
+	RET
diff --git a/src/runtime/atomic_pointer.go b/src/runtime/atomic_pointer.go
index bd21b49..4fe3340 100644
--- a/src/runtime/atomic_pointer.go
+++ b/src/runtime/atomic_pointer.go
@@ -15,13 +15,12 @@ import (
 // escape analysis decisions about the pointer value being stored.
 // Instead, these are wrappers around the actual atomics (casp1 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.
 
+// atomicstorep performs *ptr = new atomically and invokes a write barrier.
+//
 //go:nosplit
 func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
-	atomic.Storep1(noescape(ptr), new)
+	atomic.StorepNoWB(noescape(ptr), new)
 	writebarrierptr_nostore((*uintptr)(ptr), uintptr(new))
 }
 
@@ -45,7 +44,6 @@ func sync_atomic_StoreUintptr(ptr *uintptr, new uintptr)
 //go:nosplit
 func sync_atomic_StorePointer(ptr *unsafe.Pointer, new unsafe.Pointer) {
 	sync_atomic_StoreUintptr((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
-	atomic.Storep1(noescape(unsafe.Pointer(ptr)), new)
 	writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
 }
 
@@ -54,9 +52,9 @@ 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))
+func sync_atomic_SwapPointer(ptr *unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
+	old := unsafe.Pointer(sync_atomic_SwapUintptr((*uintptr)(noescape(unsafe.Pointer(ptr))), uintptr(new)))
+	writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
 	return old
 }
 
diff --git a/src/runtime/atomic_ppc64x.s b/src/runtime/atomic_ppc64x.s
index 7cdb746..57f672f 100644
--- a/src/runtime/atomic_ppc64x.s
+++ b/src/runtime/atomic_ppc64x.s
@@ -10,5 +10,5 @@ TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-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
+	LWSYNC
 	RET
diff --git a/src/runtime/callers_test.go b/src/runtime/callers_test.go
new file mode 100644
index 0000000..ad83f99
--- /dev/null
+++ b/src/runtime/callers_test.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. 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"
+	"strings"
+	"testing"
+)
+
+func f1(pan bool) []uintptr {
+	return f2(pan) // line 14
+}
+
+func f2(pan bool) []uintptr {
+	return f3(pan) // line 18
+}
+
+func f3(pan bool) []uintptr {
+	if pan {
+		panic("f3") // line 23
+	}
+	ret := make([]uintptr, 20)
+	return ret[:runtime.Callers(0, ret)] // line 26
+}
+
+func testCallers(t *testing.T, pcs []uintptr, pan bool) {
+	m := make(map[string]int, len(pcs))
+	frames := runtime.CallersFrames(pcs)
+	for {
+		frame, more := frames.Next()
+		if frame.Function != "" {
+			m[frame.Function] = frame.Line
+		}
+		if !more {
+			break
+		}
+	}
+
+	var seen []string
+	for k := range m {
+		seen = append(seen, k)
+	}
+	t.Logf("functions seen: %s", strings.Join(seen, " "))
+
+	var f3Line int
+	if pan {
+		f3Line = 23
+	} else {
+		f3Line = 26
+	}
+	want := []struct {
+		name string
+		line int
+	}{
+		{"f1", 14},
+		{"f2", 18},
+		{"f3", f3Line},
+	}
+	for _, w := range want {
+		if got := m["runtime_test."+w.name]; got != w.line {
+			t.Errorf("%s is line %d, want %d", w.name, got, w.line)
+		}
+	}
+}
+
+func TestCallers(t *testing.T) {
+	testCallers(t, f1(false), false)
+}
+
+func TestCallersPanic(t *testing.T) {
+	defer func() {
+		if r := recover(); r == nil {
+			t.Fatal("did not panic")
+		}
+		pcs := make([]uintptr, 20)
+		pcs = pcs[:runtime.Callers(0, pcs)]
+		testCallers(t, pcs, true)
+	}()
+	f1(true)
+}
diff --git a/src/runtime/cgo.go b/src/runtime/cgo.go
index 169a31d..9cf7b58 100644
--- a/src/runtime/cgo.go
+++ b/src/runtime/cgo.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -11,19 +11,19 @@ import "unsafe"
 // 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
+//go:linkname _cgo_callers _cgo_callers
+//go:linkname _cgo_set_context_function _cgo_set_context_function
 
 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
+	_cgo_callers                  unsafe.Pointer
+	_cgo_set_context_function     unsafe.Pointer
 )
 
 // iscgo is set to true by the runtime/cgo package
diff --git a/src/runtime/cgo/asm_386.s b/src/runtime/cgo/asm_386.s
index a895083..dc8897d 100644
--- a/src/runtime/cgo/asm_386.s
+++ b/src/runtime/cgo/asm_386.s
@@ -1,13 +1,12 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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"
 
-/*
- * void crosscall2(void (*fn)(void*, int32), void*, int32)
- * Save registers and call fn with two arguments.
- */
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls fn with three arguments.
 TEXT crosscall2(SB),NOSPLIT,$0
 	PUSHL	BP
 	MOVL	SP, BP
@@ -15,14 +14,16 @@ TEXT crosscall2(SB),NOSPLIT,$0
 	PUSHL	SI
 	PUSHL	DI
 	
-	SUBL	$8, SP
+	SUBL	$12, SP
+	MOVL	20(BP), AX
+	MOVL	AX, 8(SP)
 	MOVL	16(BP), AX
 	MOVL	AX, 4(SP)
 	MOVL	12(BP), AX
 	MOVL	AX, 0(SP)
 	MOVL	8(BP), AX
 	CALL	AX
-	ADDL	$8, SP
+	ADDL	$12, SP
 	
 	POPL	DI
 	POPL	SI
diff --git a/src/runtime/cgo/asm_amd64.s b/src/runtime/cgo/asm_amd64.s
index 6095bd1..541bd9e 100644
--- a/src/runtime/cgo/asm_amd64.s
+++ b/src/runtime/cgo/asm_amd64.s
@@ -1,47 +1,76 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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"
 
-/*
- * void crosscall2(void (*fn)(void*, int32), void*, int32)
- * Save registers and call fn with two arguments.
- */
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls fn with three arguments.
 TEXT crosscall2(SB),NOSPLIT,$0
+#ifndef GOOS_windows
 	SUBQ	$0x58, SP	/* keeps stack pointer 32-byte aligned */
-	MOVQ	BX, 0x10(SP)
-	MOVQ	BP, 0x18(SP)
-	MOVQ	R12, 0x20(SP)
-	MOVQ	R13, 0x28(SP)
-	MOVQ	R14, 0x30(SP)
-	MOVQ	R15, 0x38(SP)
+#else
+	SUBQ	$0x118, SP	/* also need to save xmm6 - xmm15 */
+#endif
+	MOVQ	BX, 0x18(SP)
+	MOVQ	BP, 0x20(SP)
+	MOVQ	R12, 0x28(SP)
+	MOVQ	R13, 0x30(SP)
+	MOVQ	R14, 0x38(SP)
+	MOVQ	R15, 0x40(SP)
 
 #ifdef GOOS_windows
-	// Win64 save RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15
-	MOVQ	DI, 0x40(SP)
-	MOVQ	SI, 0x48(SP)
+	// Win64 save RBX, RBP, RDI, RSI, RSP, R12, R13, R14, R15 and XMM6 -- XMM15.
+	MOVQ	DI, 0x48(SP)
+	MOVQ	SI, 0x50(SP)
+	MOVUPS	X6, 0x60(SP)
+	MOVUPS	X7, 0x70(SP)
+	MOVUPS	X8, 0x80(SP)
+	MOVUPS	X9, 0x90(SP)
+	MOVUPS	X10, 0xa0(SP)
+	MOVUPS	X11, 0xb0(SP)
+	MOVUPS	X12, 0xc0(SP)
+	MOVUPS	X13, 0xd0(SP)
+	MOVUPS	X14, 0xe0(SP)
+	MOVUPS	X15, 0xf0(SP)
 
-	MOVQ	DX, 0(SP)	/* arg */
-	MOVQ	R8, 8(SP)	/* argsize (includes padding) */
+	MOVQ	DX, 0x0(SP)	/* arg */
+	MOVQ	R8, 0x8(SP)	/* argsize (includes padding) */
+	MOVQ	R9, 0x10(SP)	/* ctxt */
 	
 	CALL	CX	/* fn */
 	
-	MOVQ	0x40(SP), DI
-	MOVQ	0x48(SP), SI
+	MOVQ	0x48(SP), DI
+	MOVQ	0x50(SP), SI
+	MOVUPS	0x60(SP), X6
+	MOVUPS	0x70(SP), X7
+	MOVUPS	0x80(SP), X8
+	MOVUPS	0x90(SP), X9
+	MOVUPS	0xa0(SP), X10
+	MOVUPS	0xb0(SP), X11
+	MOVUPS	0xc0(SP), X12
+	MOVUPS	0xd0(SP), X13
+	MOVUPS	0xe0(SP), X14
+	MOVUPS	0xf0(SP), X15
 #else
-	MOVQ	SI, 0(SP)	/* arg */
-	MOVQ	DX, 8(SP)	/* argsize (includes padding) */
+	MOVQ	SI, 0x0(SP)	/* arg */
+	MOVQ	DX, 0x8(SP)	/* argsize (includes padding) */
+	MOVQ	CX, 0x10(SP)	/* ctxt */
 
 	CALL	DI	/* fn */
 #endif
 
-	MOVQ	0x10(SP), BX
-	MOVQ	0x18(SP), BP
-	MOVQ	0x20(SP), R12
-	MOVQ	0x28(SP), R13
-	MOVQ	0x30(SP), R14
-	MOVQ	0x38(SP), R15
+	MOVQ	0x18(SP), BX
+	MOVQ	0x20(SP), BP
+	MOVQ	0x28(SP), R12
+	MOVQ	0x30(SP), R13
+	MOVQ	0x38(SP), R14
+	MOVQ	0x40(SP), R15
 	
+#ifndef GOOS_windows
 	ADDQ	$0x58, SP
+#else
+	ADDQ	$0x118, SP
+#endif
 	RET
diff --git a/src/runtime/cgo/asm_arm.s b/src/runtime/cgo/asm_arm.s
index 9aeaf9a..0f35422 100644
--- a/src/runtime/cgo/asm_arm.s
+++ b/src/runtime/cgo/asm_arm.s
@@ -1,24 +1,55 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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"
 
-/*
- * void crosscall2(void (*fn)(void*, int32), void*, int32)
- * Save registers and call fn with two arguments.
- */
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls fn with three arguments.
 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).
+	 *  push 3 args for fn (R1, R2, R3).
 	 * 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)
+	SUB	$(8*9), R13 // Reserve space for the floating point registers.
+	MOVM.WP	[R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R14], (R13)
+
+	// Skip floating point registers on GOARM < 6.
+	MOVB    runtime·goarm(SB), R11
+	CMP $6, R11
+	BLT skipfpsave
+	MOVD	F8, (14*4+8*1)(R13)
+	MOVD	F9, (14*4+8*2)(R13)
+	MOVD	F10, (14*4+8*3)(R13)
+	MOVD	F11, (14*4+8*4)(R13)
+	MOVD	F12, (14*4+8*5)(R13)
+	MOVD	F13, (14*4+8*6)(R13)
+	MOVD	F14, (14*4+8*7)(R13)
+	MOVD	F15, (14*4+8*8)(R13)
+
+skipfpsave:
 	BL	runtime·load_g(SB)
 	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]
+
+	MOVB    runtime·goarm(SB), R11
+	CMP $6, R11
+	BLT skipfprest
+	MOVD	(14*4+8*1)(R13), F8
+	MOVD	(14*4+8*2)(R13), F9
+	MOVD	(14*4+8*3)(R13), F10
+	MOVD	(14*4+8*4)(R13), F11
+	MOVD	(14*4+8*5)(R13), F12
+	MOVD	(14*4+8*6)(R13), F13
+	MOVD	(14*4+8*7)(R13), F14
+	MOVD	(14*4+8*8)(R13), F15
+
+skipfprest:
+	MOVM.IAW	(R13), [R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, g, R11, R12, R14]
+	ADD	$(8*9), R13
+	MOVW	R14, R15
diff --git a/src/runtime/cgo/asm_arm64.s b/src/runtime/cgo/asm_arm64.s
index c6f98fa..e55a70f 100644
--- a/src/runtime/cgo/asm_arm64.s
+++ b/src/runtime/cgo/asm_arm64.s
@@ -1,36 +1,44 @@
-// Copyright 2015 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.
 
 #include "textflag.h"
 
-/*
- * void crosscall2(void (*fn)(void*, int32), void*, int32)
- * Save registers and call fn with two arguments.
- */
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls fn with three 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).
+	 *  push 3 args for fn (R1, R2, R3).
 	 * 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
+	SUB	$(8*24), 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	R3, (8*3)(RSP)
+	MOVD	R19, (8*4)(RSP)
+	MOVD	R20, (8*5)(RSP)
+	MOVD	R21, (8*6)(RSP)
+	MOVD	R22, (8*7)(RSP)
+	MOVD	R23, (8*8)(RSP)
+	MOVD	R24, (8*9)(RSP)
+	MOVD	R25, (8*10)(RSP)
+	MOVD	R26, (8*11)(RSP)
+	MOVD	R27, (8*12)(RSP)
+	MOVD	g, (8*13)(RSP)
+	MOVD	R29, (8*14)(RSP)
+	MOVD	R30, (8*15)(RSP)
+	FMOVD	F8, (8*16)(RSP)
+	FMOVD	F9, (8*17)(RSP)
+	FMOVD	F10, (8*18)(RSP)
+	FMOVD	F11, (8*19)(RSP)
+	FMOVD	F12, (8*20)(RSP)
+	FMOVD	F13, (8*21)(RSP)
+	FMOVD	F14, (8*22)(RSP)
+	FMOVD	F15, (8*23)(RSP)
 
 	MOVD	R0, R19
 
@@ -41,17 +49,26 @@ TEXT crosscall2(SB),NOSPLIT,$-8
 
 	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
+	MOVD	(8*3)(RSP), R3
+	MOVD	(8*4)(RSP), R19
+	MOVD	(8*5)(RSP), R20
+	MOVD	(8*6)(RSP), R21
+	MOVD	(8*7)(RSP), R22
+	MOVD	(8*8)(RSP), R23
+	MOVD	(8*9)(RSP), R24
+	MOVD	(8*10)(RSP), R25
+	MOVD	(8*11)(RSP), R26
+	MOVD	(8*12)(RSP), R27
+	MOVD	(8*13)(RSP), g
+	MOVD	(8*14)(RSP), R29
+	MOVD	(8*15)(RSP), R30
+	FMOVD	(8*16)(RSP), F8
+	FMOVD	(8*17)(RSP), F9
+	FMOVD	(8*18)(RSP), F10
+	FMOVD	(8*19)(RSP), F11
+	FMOVD	(8*20)(RSP), F12
+	FMOVD	(8*21)(RSP), F13
+	FMOVD	(8*22)(RSP), F14
+	FMOVD	(8*23)(RSP), F15
+	ADD	$(8*24), RSP
 	RET
diff --git a/src/runtime/cgo/asm_mips64x.s b/src/runtime/cgo/asm_mips64x.s
new file mode 100644
index 0000000..19e9014
--- /dev/null
+++ b/src/runtime/cgo/asm_mips64x.s
@@ -0,0 +1,76 @@
+// Copyright 2016 The Go 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 mips64 mips64le
+
+#include "textflag.h"
+
+/*
+ * void crosscall2(void (*fn)(void*, int32, uintptr), void*, int32, uintptr)
+ * 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 3 args for fn (R5, R6, R7).
+	 * Also note that at procedure entry in gc world, 8(R29) will be the
+	 *  first arg.
+	 */
+	ADDV	$(-8*23), R29
+	MOVV	R5, (8*1)(R29)
+	MOVV	R6, (8*2)(R29)
+	MOVV	R7, (8*3)(R29)
+	MOVV	R16, (8*4)(R29)
+	MOVV	R17, (8*5)(R29)
+	MOVV	R18, (8*6)(R29)
+	MOVV	R19, (8*7)(R29)
+	MOVV	R20, (8*8)(R29)
+	MOVV	R21, (8*9)(R29)
+	MOVV	R22, (8*10)(R29)
+	MOVV	R23, (8*11)(R29)
+	MOVV	RSB, (8*12)(R29)
+	MOVV	g, (8*13)(R29)
+	MOVV	R31, (8*14)(R29)
+	MOVD	F24, (8*15)(R29)
+	MOVD	F25, (8*16)(R29)
+	MOVD	F26, (8*17)(R29)
+	MOVD	F27, (8*18)(R29)
+	MOVD	F28, (8*19)(R29)
+	MOVD	F29, (8*20)(R29)
+	MOVD	F30, (8*21)(R29)
+	MOVD	F31, (8*22)(R29)
+
+	// Initialize Go ABI environment
+	// prepare SB register = PC & 0xffffffff00000000
+	BGEZAL	R0, 1(PC)
+	SRLV	$32, R31, RSB
+	SLLV	$32, RSB
+	JAL	runtime·reginit(SB)
+	JAL	runtime·load_g(SB)
+	JAL	(R4)
+
+	MOVV	(8*1)(R29), R5
+	MOVV	(8*2)(R29), R6
+	MOVV	(8*3)(R29), R7
+	MOVV	(8*4)(R29), R16
+	MOVV	(8*5)(R29), R17
+	MOVV	(8*6)(R29), R18
+	MOVV	(8*7)(R29), R19
+	MOVV	(8*8)(R29), R20
+	MOVV	(8*9)(R29), R21
+	MOVV	(8*10)(R29), R22
+	MOVV	(8*11)(R29), R23
+	MOVV	(8*12)(R29), RSB
+	MOVV	(8*13)(R29), g
+	MOVV	(8*14)(R29), R31
+	MOVD	(8*15)(R29), F24
+	MOVD	(8*16)(R29), F25
+	MOVD	(8*17)(R29), F26
+	MOVD	(8*18)(R29), F27
+	MOVD	(8*19)(R29), F28
+	MOVD	(8*20)(R29), F29
+	MOVD	(8*21)(R29), F30
+	MOVD	(8*22)(R29), F31
+	ADDV	$(8*23), R29
+	RET
diff --git a/src/runtime/cgo/asm_nacl_amd64p32.s b/src/runtime/cgo/asm_nacl_amd64p32.s
index eb92014..82aaecd 100644
--- a/src/runtime/cgo/asm_nacl_amd64p32.s
+++ b/src/runtime/cgo/asm_nacl_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/cgo/asm_ppc64x.s b/src/runtime/cgo/asm_ppc64x.s
index 5cdbe06..dded1be 100644
--- a/src/runtime/cgo/asm_ppc64x.s
+++ b/src/runtime/cgo/asm_ppc64x.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,11 +7,9 @@
 #include "textflag.h"
 #include "asm_ppc64x.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.
- */
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls fn with three arguments.
 TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
 	// TODO(austin): ABI v1 (fn is probably a function descriptor)
 
@@ -22,7 +20,7 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
 
 	BL	saveregs2<>(SB)
 
-	MOVDU	R1, (-288-2*8-FIXED_FRAME)(R1)
+	MOVDU	R1, (-288-3*8-FIXED_FRAME)(R1)
 
 	// Initialize Go ABI environment
 	BL	runtime·reginit(SB)
@@ -32,9 +30,10 @@ TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
 	MOVD	R3, CTR
 	MOVD	R4, FIXED_FRAME+0(R1)
 	MOVD	R5, FIXED_FRAME+8(R1)
+	MOVD	R6, FIXED_FRAME+16(R1)
 	BL	(CTR)
 
-	ADD	$(288+2*8+FIXED_FRAME), R1
+	ADD	$(288+3*8+FIXED_FRAME), R1
 
 	BL	restoreregs2<>(SB)
 
diff --git a/src/runtime/cgo/asm_s390x.s b/src/runtime/cgo/asm_s390x.s
new file mode 100644
index 0000000..ae688b6
--- /dev/null
+++ b/src/runtime/cgo/asm_s390x.s
@@ -0,0 +1,43 @@
+// Copyright 2016 The Go 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"
+
+// Called by C code generated by cmd/cgo.
+// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
+// Saves C callee-saved registers and calls fn with three arguments.
+TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
+	// Start with standard C stack frame layout and linkage
+
+	// Save R6-R15, F0, F2, F4 and F6 in the
+	// register save area of the calling function
+	STMG	R6, R15, 48(R15)
+	FMOVD	F0, 128(R15)
+	FMOVD	F2, 136(R15)
+	FMOVD	F4, 144(R15)
+	FMOVD	F6, 152(R15)
+
+	// Initialize Go ABI environment
+	XOR	R0, R0
+	BL	runtime·load_g(SB)
+
+	// Allocate 32 bytes on the stack
+	SUB	$32, R15
+
+	MOVD	R3, 8(R15)  // arg1
+	MOVW	R4, 16(R15) // arg2
+	MOVD	R5, 24(R15) // arg3
+	BL	(R2)        // fn(arg1, arg2, arg3)
+
+	ADD	$32, R15
+
+	// Restore R6-R15, F0, F2, F4 and F6
+	LMG	48(R15), R6, R15
+	FMOVD	F0, 128(R15)
+	FMOVD	F2, 136(R15)
+	FMOVD	F4, 144(R15)
+	FMOVD	F6, 152(R15)
+
+	RET
+
diff --git a/src/runtime/cgo/callbacks.go b/src/runtime/cgo/callbacks.go
index 08f230d..9bde5a9 100644
--- a/src/runtime/cgo/callbacks.go
+++ b/src/runtime/cgo/callbacks.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -11,7 +11,7 @@ import "unsafe"
 
 // cgocallback is defined in runtime
 //go:linkname _runtime_cgocallback runtime.cgocallback
-func _runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
+func _runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
 
 // The declaration of crosscall2 is:
 //   void crosscall2(void (*fn)(void *, int), void *, int);
@@ -19,10 +19,14 @@ func _runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
 // We need to export the symbol crosscall2 in order to support
 // callbacks from shared libraries. This applies regardless of
 // linking mode.
+//
+// Compatibility note: crosscall2 actually takes four arguments, but
+// it works to call it with three arguments when calling _cgo_panic.
+// That is supported for backward compatibility.
 //go:cgo_export_static crosscall2
 //go:cgo_export_dynamic crosscall2
 
-// Panic.  The argument is converted into a Go string.
+// Panic. The argument is converted into a Go string.
 
 // Call like this in code compiled with gcc:
 //   struct { const char *p; } a;
@@ -39,7 +43,7 @@ var _runtime_cgo_panic_internal byte
 //go:nosplit
 //go:norace
 func _cgo_panic(a unsafe.Pointer, n int32) {
-	_runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_panic_internal), a, uintptr(n))
+	_runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_panic_internal), a, uintptr(n), 0)
 }
 
 //go:cgo_import_static x_cgo_init
@@ -48,18 +52,6 @@ func _cgo_panic(a unsafe.Pointer, n int32) {
 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
@@ -69,7 +61,7 @@ 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
+// 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
@@ -78,11 +70,11 @@ var _cgo_thread_start = &x_cgo_thread_start
 var x_cgo_sys_thread_create byte
 var _cgo_sys_thread_create = &x_cgo_sys_thread_create
 
-// Notifies that the runtime has been intialized.
+// Notifies that the runtime has been initialized.
 //
 // 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
+// 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.
 
@@ -92,5 +84,13 @@ var _cgo_sys_thread_create = &x_cgo_sys_thread_create
 var x_cgo_notify_runtime_init_done byte
 var _cgo_notify_runtime_init_done = &x_cgo_notify_runtime_init_done
 
+// Sets the traceback context function. See runtime.SetCgoTraceback.
+
+//go:cgo_import_static x_cgo_set_context_function
+//go:linkname x_cgo_set_context_function x_cgo_set_context_function
+//go:linkname _cgo_set_context_function _cgo_set_context_function
+var x_cgo_set_context_function byte
+var _cgo_set_context_function = &x_cgo_set_context_function
+
 //go:cgo_export_static _cgo_topofstack
 //go:cgo_export_dynamic _cgo_topofstack
diff --git a/src/runtime/cgo/callbacks_traceback.go b/src/runtime/cgo/callbacks_traceback.go
new file mode 100644
index 0000000..f754846
--- /dev/null
+++ b/src/runtime/cgo/callbacks_traceback.go
@@ -0,0 +1,17 @@
+// Copyright 2016 The Go 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 cgo
+
+import _ "unsafe" // for go:linkname
+
+// Calls the traceback function passed to SetCgoTraceback.
+
+//go:cgo_import_static x_cgo_callers
+//go:linkname x_cgo_callers x_cgo_callers
+//go:linkname _cgo_callers _cgo_callers
+var x_cgo_callers byte
+var _cgo_callers = &x_cgo_callers
diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go
index 8f3e66f..ce0e6a3 100644
--- a/src/runtime/cgo/cgo.go
+++ b/src/runtime/cgo/cgo.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/cgo/dragonfly.go b/src/runtime/cgo/dragonfly.go
index 69d52b5..d6d6918 100644
--- a/src/runtime/cgo/dragonfly.go
+++ b/src/runtime/cgo/dragonfly.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/cgo/freebsd.go b/src/runtime/cgo/freebsd.go
index 99cf3fb..5c9ddbd 100644
--- a/src/runtime/cgo/freebsd.go
+++ b/src/runtime/cgo/freebsd.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/cgo/gcc_386.S b/src/runtime/cgo/gcc_386.S
index ff11ce1..ff55b2c 100644
--- a/src/runtime/cgo/gcc_386.S
+++ b/src/runtime/cgo/gcc_386.S
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/runtime/cgo/gcc_amd64.S b/src/runtime/cgo/gcc_amd64.S
index 32d0200..17d9d47 100644
--- a/src/runtime/cgo/gcc_amd64.S
+++ b/src/runtime/cgo/gcc_amd64.S
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/runtime/cgo/gcc_android.c b/src/runtime/cgo/gcc_android.c
index a3bc6c4..b756ede 100644
--- a/src/runtime/cgo/gcc_android.c
+++ b/src/runtime/cgo/gcc_android.c
@@ -1,9 +1,7 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <stdarg.h>
 #include <android/log.h>
 #include "libcgo.h"
diff --git a/src/runtime/cgo/gcc_android_386.c b/src/runtime/cgo/gcc_android_386.c
index db1d48a..23a15f1 100644
--- a/src/runtime/cgo/gcc_android_386.c
+++ b/src/runtime/cgo/gcc_android_386.c
@@ -1,9 +1,7 @@
-// Copyright 2015 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.
 
-// +build cgo
-
 #include <string.h> /* for strerror */
 #include <pthread.h>
 #include <signal.h>
diff --git a/src/runtime/cgo/gcc_android_amd64.c b/src/runtime/cgo/gcc_android_amd64.c
index 17d88ce..e006c49 100644
--- a/src/runtime/cgo/gcc_android_amd64.c
+++ b/src/runtime/cgo/gcc_android_amd64.c
@@ -1,9 +1,7 @@
-// Copyright 2015 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.
 
-// +build cgo
-
 #include <string.h> /* for strerror */
 #include <pthread.h>
 #include <signal.h>
diff --git a/src/runtime/cgo/gcc_android_arm.c b/src/runtime/cgo/gcc_android_arm.c
index 67cb5a8..c7b13f9 100644
--- a/src/runtime/cgo/gcc_android_arm.c
+++ b/src/runtime/cgo/gcc_android_arm.c
@@ -1,9 +1,7 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <pthread.h>
 #include <signal.h>
 #include <stdio.h>
diff --git a/src/runtime/cgo/gcc_android_arm64.c b/src/runtime/cgo/gcc_android_arm64.c
index acf3735..f8ad684 100644
--- a/src/runtime/cgo/gcc_android_arm64.c
+++ b/src/runtime/cgo/gcc_android_arm64.c
@@ -1,9 +1,7 @@
-// Copyright 2015 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.
 
-// +build cgo
-
 #include <pthread.h>
 #include <signal.h>
 #include <stdio.h>
diff --git a/src/runtime/cgo/gcc_arm.S b/src/runtime/cgo/gcc_arm.S
index d225298..fe1c48b 100644
--- a/src/runtime/cgo/gcc_arm.S
+++ b/src/runtime/cgo/gcc_arm.S
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/runtime/cgo/gcc_arm64.S b/src/runtime/cgo/gcc_arm64.S
index d9da272..59dce08 100644
--- a/src/runtime/cgo/gcc_arm64.S
+++ b/src/runtime/cgo/gcc_arm64.S
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/cgo/gcc_context.c b/src/runtime/cgo/gcc_context.c
new file mode 100644
index 0000000..1e6cf7e
--- /dev/null
+++ b/src/runtime/cgo/gcc_context.c
@@ -0,0 +1,21 @@
+// Copyright 2016 The Go 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 dragonfly freebsd linux netbsd openbsd solaris windows
+
+#include "libcgo.h"
+
+// Releases the cgo traceback context.
+void _cgo_release_context(uintptr_t ctxt) {
+	void (*pfn)(struct context_arg*);
+
+	pfn = _cgo_get_context_function();
+	if (ctxt != 0 && pfn != nil) {
+		struct context_arg arg;
+
+		arg.Context = ctxt;
+		(*pfn)(&arg);
+	}
+}
diff --git a/src/runtime/cgo/gcc_darwin_386.c b/src/runtime/cgo/gcc_darwin_386.c
index a94e5ee..effbcdf 100644
--- a/src/runtime/cgo/gcc_darwin_386.c
+++ b/src/runtime/cgo/gcc_darwin_386.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <string.h> /* for strerror */
 #include <pthread.h>
 #include <signal.h>
diff --git a/src/runtime/cgo/gcc_darwin_amd64.c b/src/runtime/cgo/gcc_darwin_amd64.c
index b70c833..15396b0 100644
--- a/src/runtime/cgo/gcc_darwin_amd64.c
+++ b/src/runtime/cgo/gcc_darwin_amd64.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <string.h> /* for strerror */
 #include <pthread.h>
 #include <signal.h>
diff --git a/src/runtime/cgo/gcc_darwin_arm.c b/src/runtime/cgo/gcc_darwin_arm.c
index c0ce449..dbf88c3 100644
--- a/src/runtime/cgo/gcc_darwin_arm.c
+++ b/src/runtime/cgo/gcc_darwin_arm.c
@@ -1,9 +1,7 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <limits.h>
 #include <pthread.h>
 #include <signal.h>
diff --git a/src/runtime/cgo/gcc_darwin_arm64.c b/src/runtime/cgo/gcc_darwin_arm64.c
index 1ba00b0..a9eb4f2 100644
--- a/src/runtime/cgo/gcc_darwin_arm64.c
+++ b/src/runtime/cgo/gcc_darwin_arm64.c
@@ -1,9 +1,7 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <limits.h>
 #include <pthread.h>
 #include <signal.h>
diff --git a/src/runtime/cgo/gcc_dragonfly_amd64.c b/src/runtime/cgo/gcc_dragonfly_amd64.c
index 9d02add..b534dcc 100644
--- a/src/runtime/cgo/gcc_dragonfly_amd64.c
+++ b/src/runtime/cgo/gcc_dragonfly_amd64.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <sys/types.h>
 #include <sys/signalvar.h>
 #include <pthread.h>
@@ -69,11 +67,11 @@ threadentry(void *v)
 	setg_gcc((void*)ts.g);
 
 	// On DragonFly, a new thread inherits the signal stack of the
-	// creating thread.  That confuses minit, so we remove that
-	// signal stack here before calling the regular mstart.  It's
+	// creating thread. That confuses minit, so we remove that
+	// signal stack here before calling the regular mstart. It's
 	// a bit baroque to remove a signal stack here only to add one
 	// in minit, but it's a simple change that keeps DragonFly
-	// working like other OS's.  At this point all signals are
+	// working like other OS's. At this point all signals are
 	// blocked, so there is no race.
 	memset(&ss, 0, sizeof ss);
 	ss.ss_flags = SS_DISABLE;
diff --git a/src/runtime/cgo/gcc_fatalf.c b/src/runtime/cgo/gcc_fatalf.c
index c931b79..5ac419b 100644
--- a/src/runtime/cgo/gcc_fatalf.c
+++ b/src/runtime/cgo/gcc_fatalf.c
@@ -1,9 +1,7 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 cgo
-
 // +build !android,linux
 
 #include <stdarg.h>
diff --git a/src/runtime/cgo/gcc_freebsd_386.c b/src/runtime/cgo/gcc_freebsd_386.c
index 2afdf20..d288666 100644
--- a/src/runtime/cgo/gcc_freebsd_386.c
+++ b/src/runtime/cgo/gcc_freebsd_386.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <sys/types.h>
 #include <sys/signalvar.h>
 #include <pthread.h>
diff --git a/src/runtime/cgo/gcc_freebsd_amd64.c b/src/runtime/cgo/gcc_freebsd_amd64.c
index bf71d4c..e532ad6 100644
--- a/src/runtime/cgo/gcc_freebsd_amd64.c
+++ b/src/runtime/cgo/gcc_freebsd_amd64.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <sys/types.h>
 #include <sys/signalvar.h>
 #include <pthread.h>
diff --git a/src/runtime/cgo/gcc_freebsd_arm.c b/src/runtime/cgo/gcc_freebsd_arm.c
index 60bca55..c4e7574 100644
--- a/src/runtime/cgo/gcc_freebsd_arm.c
+++ b/src/runtime/cgo/gcc_freebsd_arm.c
@@ -1,9 +1,7 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <sys/types.h>
 #include <machine/sysarch.h>
 #include <sys/signalvar.h>
@@ -53,7 +51,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
 	// 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.
+	// out of pthread_attr_getstacksize. C'est la Linux.
 	memset(&attr, 0, sizeof attr);
 	pthread_attr_init(&attr);
 	size = 0;
diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c
index 5b9558a..0bdf40a 100644
--- a/src/runtime/cgo/gcc_libinit.c
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -1,20 +1,23 @@
-// Copyright 2015 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.
 
 // +build cgo
 // +build darwin dragonfly freebsd linux netbsd solaris
-// +build !ppc64,!ppc64le
 
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h> // strerror
+#include "libcgo.h"
 
 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;
 
+// The context function, used when tracing back C calls into Go.
+static void (*cgo_context_function)(struct context_arg*);
+
 void
 x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
 	pthread_t p;
@@ -25,13 +28,35 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
 	}
 }
 
-void
+uintptr_t
 _cgo_wait_runtime_init_done() {
+	void (*pfn)(struct context_arg*);
+
 	pthread_mutex_lock(&runtime_init_mu);
 	while (runtime_init_done == 0) {
 		pthread_cond_wait(&runtime_init_cond, &runtime_init_mu);
 	}
+
+	// TODO(iant): For the case of a new C thread calling into Go, such
+	// as when using -buildmode=c-archive, we know that Go runtime
+	// initialization is complete but we do not know that all Go init
+	// functions have been run. We should not fetch cgo_context_function
+	// until they have been, because that is where a call to
+	// SetCgoTraceback is likely to occur. We are going to wait for Go
+	// initialization to be complete anyhow, later, by waiting for
+	// main_init_done to be closed in cgocallbackg1. We should wait here
+	// instead. See also issue #15943.
+	pfn = cgo_context_function;
+
 	pthread_mutex_unlock(&runtime_init_mu);
+	if (pfn != nil) {
+		struct context_arg arg;
+
+		arg.Context = 0;
+		(*pfn)(&arg);
+		return arg.Context;
+	}
+	return 0;
 }
 
 void
@@ -41,3 +66,21 @@ x_cgo_notify_runtime_init_done(void* dummy) {
 	pthread_cond_broadcast(&runtime_init_cond);
 	pthread_mutex_unlock(&runtime_init_mu);
 }
+
+// Sets the context function to call to record the traceback context
+// when calling a Go function from C code. Called from runtime.SetCgoTraceback.
+void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
+	pthread_mutex_lock(&runtime_init_mu);
+	cgo_context_function = context;
+	pthread_mutex_unlock(&runtime_init_mu);
+}
+
+// Gets the context function.
+void (*(_cgo_get_context_function(void)))(struct context_arg*) {
+	void (*ret)(struct context_arg*);
+
+	pthread_mutex_lock(&runtime_init_mu);
+	ret = cgo_context_function;
+	pthread_mutex_unlock(&runtime_init_mu);
+	return ret;
+}
diff --git a/src/runtime/cgo/gcc_libinit_linux_ppc64x.c b/src/runtime/cgo/gcc_libinit_linux_ppc64x.c
deleted file mode 100644
index 18ccf93..0000000
--- a/src/runtime/cgo/gcc_libinit_linux_ppc64x.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2015 The Go 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
-
-// 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
index 13904ee..626bf8a 100644
--- a/src/runtime/cgo/gcc_libinit_openbsd.c
+++ b/src/runtime/cgo/gcc_libinit_openbsd.c
@@ -1,11 +1,13 @@
-// Copyright 2015 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.
 
-// +build cgo
-
 #include <stdio.h>
 #include <stdlib.h>
+#include "libcgo.h"
+
+// The context function, used when tracing back C calls into Go.
+static void (*cgo_context_function)(struct context_arg*);
 
 void
 x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
@@ -13,12 +15,36 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
 	abort();
 }
 
-void
+uintptr_t
 _cgo_wait_runtime_init_done() {
+	void (*pfn)(struct context_arg*);
+
 	// TODO(spetrovic): implement this method.
+
+	pfn = _cgo_get_context_function();
+	if (pfn != nil) {
+		struct context_arg arg;
+
+		arg.Context = 0;
+		(*pfn)(&arg);
+		return arg.Context;
+	}
+	return 0;
 }
 
 void
 x_cgo_notify_runtime_init_done(void* dummy) {
 	// TODO(spetrovic): implement this method.
-}
\ No newline at end of file
+}
+
+// Sets the context function to call to record the traceback context
+// when calling a Go function from C code. Called from runtime.SetCgoTraceback.
+void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
+	// TODO(iant): Needs synchronization.
+	cgo_context_function = context;
+}
+
+// Gets the context function.
+void (*(_cgo_get_context_function(void)))(struct context_arg*) {
+	return cgo_context_function;
+}
diff --git a/src/runtime/cgo/gcc_libinit_windows.c b/src/runtime/cgo/gcc_libinit_windows.c
index 13904ee..0824e20 100644
--- a/src/runtime/cgo/gcc_libinit_windows.c
+++ b/src/runtime/cgo/gcc_libinit_windows.c
@@ -1,24 +1,123 @@
-// Copyright 2015 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.
 
 // +build cgo
+#define WIN64_LEAN_AND_MEAN
+#include <windows.h>
+#include <process.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "libcgo.h"
+
+static volatile long runtime_init_once_gate = 0;
+static volatile long runtime_init_once_done = 0;
+
+static CRITICAL_SECTION runtime_init_cs;
+
+static HANDLE runtime_init_wait;
+static int runtime_init_done;
+
+// Pre-initialize the runtime synchronization objects
+void
+_cgo_preinit_init() {
+	 runtime_init_wait = CreateEvent(NULL, TRUE, FALSE, NULL);
+	 if (runtime_init_wait == NULL) {
+		fprintf(stderr, "runtime: failed to create runtime initialization wait event.\n");
+		abort();
+	 }
+
+	 InitializeCriticalSection(&runtime_init_cs);
+}
+
+// Make sure that the preinit sequence has run.
 void
-x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
-	fprintf(stderr, "x_cgo_sys_thread_create not implemented");
-	abort();
+_cgo_maybe_run_preinit() {
+	 if (!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
+			if (InterlockedIncrement(&runtime_init_once_gate) == 1) {
+				 _cgo_preinit_init();
+				 InterlockedIncrement(&runtime_init_once_done);
+			} else {
+				 // Decrement to avoid overflow.
+				 InterlockedDecrement(&runtime_init_once_gate);
+				 while(!InterlockedExchangeAdd(&runtime_init_once_done, 0)) {
+						Sleep(0);
+				 }
+			}
+	 }
 }
 
 void
+x_cgo_sys_thread_create(void (*func)(void*), void* arg) {
+	uintptr_t thandle;
+
+	thandle = _beginthread(func, 0, arg);
+	if(thandle == -1) {
+		fprintf(stderr, "runtime: failed to create new OS thread (%d)\n", errno);
+		abort();
+	}
+}
+
+int
+_cgo_is_runtime_initialized() {
+	 EnterCriticalSection(&runtime_init_cs);
+	 int status = runtime_init_done;
+	 LeaveCriticalSection(&runtime_init_cs);
+	 return status;
+}
+
+uintptr_t
 _cgo_wait_runtime_init_done() {
-	// TODO(spetrovic): implement this method.
+	void (*pfn)(struct context_arg*);
+
+	 _cgo_maybe_run_preinit();
+	while (!_cgo_is_runtime_initialized()) {
+			WaitForSingleObject(runtime_init_wait, INFINITE);
+	}
+	pfn = _cgo_get_context_function();
+	if (pfn != nil) {
+		struct context_arg arg;
+
+		arg.Context = 0;
+		(*pfn)(&arg);
+		return arg.Context;
+	}
+	return 0;
 }
 
 void
 x_cgo_notify_runtime_init_done(void* dummy) {
-	// TODO(spetrovic): implement this method.
-}
\ No newline at end of file
+	 _cgo_maybe_run_preinit();
+
+	 EnterCriticalSection(&runtime_init_cs);
+	runtime_init_done = 1;
+	 LeaveCriticalSection(&runtime_init_cs);
+
+	 if (!SetEvent(runtime_init_wait)) {
+		fprintf(stderr, "runtime: failed to signal runtime initialization complete.\n");
+		abort();
+	}
+}
+
+// The context function, used when tracing back C calls into Go.
+static void (*cgo_context_function)(struct context_arg*);
+
+// Sets the context function to call to record the traceback context
+// when calling a Go function from C code. Called from runtime.SetCgoTraceback.
+void x_cgo_set_context_function(void (*context)(struct context_arg*)) {
+	EnterCriticalSection(&runtime_init_cs);
+	cgo_context_function = context;
+	LeaveCriticalSection(&runtime_init_cs);
+}
+
+// Gets the context function.
+void (*(_cgo_get_context_function(void)))(struct context_arg*) {
+	void (*ret)(struct context_arg*);
+
+	EnterCriticalSection(&runtime_init_cs);
+	ret = cgo_context_function;
+	LeaveCriticalSection(&runtime_init_cs);
+	return ret;
+}
diff --git a/src/runtime/cgo/gcc_linux_386.c b/src/runtime/cgo/gcc_linux_386.c
index 2457eb3..30fe92b 100644
--- a/src/runtime/cgo/gcc_linux_386.c
+++ b/src/runtime/cgo/gcc_linux_386.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <pthread.h>
 #include <string.h>
 #include <signal.h>
@@ -48,7 +46,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
 	// 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.
+	// out of pthread_attr_getstacksize. C'est la Linux.
 	memset(&attr, 0, sizeof attr);
 	pthread_attr_init(&attr);
 	size = 0;
diff --git a/src/runtime/cgo/gcc_linux_amd64.c b/src/runtime/cgo/gcc_linux_amd64.c
index 5113a76..0c34c66 100644
--- a/src/runtime/cgo/gcc_linux_amd64.c
+++ b/src/runtime/cgo/gcc_linux_amd64.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <pthread.h>
 #include <errno.h>
 #include <string.h> // strerror
@@ -91,7 +89,9 @@ threadentry(void *v)
 	ThreadStart ts;
 
 	ts = *(ThreadStart*)v;
+	_cgo_tsan_acquire();
 	free(v);
+	_cgo_tsan_release();
 
 	/*
 	 * Set specific keys.
diff --git a/src/runtime/cgo/gcc_linux_arm.c b/src/runtime/cgo/gcc_linux_arm.c
index ce940fe..945c3f1 100644
--- a/src/runtime/cgo/gcc_linux_arm.c
+++ b/src/runtime/cgo/gcc_linux_arm.c
@@ -1,9 +1,7 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <pthread.h>
 #include <string.h>
 #include <signal.h>
@@ -28,7 +26,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
 	// 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.
+	// out of pthread_attr_getstacksize. C'est la Linux.
 	memset(&attr, 0, sizeof attr);
 	pthread_attr_init(&attr);
 	size = 0;
diff --git a/src/runtime/cgo/gcc_linux_arm64.c b/src/runtime/cgo/gcc_linux_arm64.c
index babbd50..ca9ba0b 100644
--- a/src/runtime/cgo/gcc_linux_arm64.c
+++ b/src/runtime/cgo/gcc_linux_arm64.c
@@ -1,9 +1,7 @@
-// Copyright 2015 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.
 
-// +build cgo
-
 #include <pthread.h>
 #include <string.h>
 #include <signal.h>
@@ -28,7 +26,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
 	// 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.
+	// out of pthread_attr_getstacksize. C'est la Linux.
 	memset(&attr, 0, sizeof attr);
 	pthread_attr_init(&attr);
 	size = 0;
diff --git a/src/runtime/cgo/gcc_linux_mips64x.c b/src/runtime/cgo/gcc_linux_mips64x.c
new file mode 100644
index 0000000..5bf5197
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux_mips64x.c
@@ -0,0 +1,77 @@
+// Copyright 2016 The Go 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 linux
+// +build mips64 mips64le
+
+#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
index 1264ab5..fb19805 100644
--- a/src/runtime/cgo/gcc_linux_ppc64x.c
+++ b/src/runtime/cgo/gcc_linux_ppc64x.c
@@ -1,9 +1,7 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 cgo
-
 // +build ppc64 ppc64le
 
 #include <pthread.h>
diff --git a/src/runtime/cgo/gcc_linux_s390x.c b/src/runtime/cgo/gcc_linux_s390x.c
new file mode 100644
index 0000000..81e3b33
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux_s390x.c
@@ -0,0 +1,68 @@
+// Copyright 2016 The Go 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);
+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_s390x(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_s390x(ts.fn, (void*)ts.g);
+	return nil;
+}
diff --git a/src/runtime/cgo/gcc_mips64x.S b/src/runtime/cgo/gcc_mips64x.S
new file mode 100644
index 0000000..adeb7ae
--- /dev/null
+++ b/src/runtime/cgo/gcc_mips64x.S
@@ -0,0 +1,79 @@
+// Copyright 2016 The Go 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 mips64 mips64le
+
+/*
+ * 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 MIPS N64 ABI, where $16-$23, $28, $30, and $f24-$f31
+ * are callee-save, so they must be saved explicitly, along with $31 (LR).
+ */
+.globl crosscall1
+.set noat
+crosscall1:
+	daddiu	$29, $29, -160
+	sd	$31, 0($29)
+	sd	$16, 8($29)
+	sd	$17, 16($29)
+	sd	$18, 24($29)
+	sd	$19, 32($29)
+	sd	$20, 40($29)
+	sd	$21, 48($29)
+	sd	$22, 56($29)
+	sd	$23, 64($29)
+	sd	$28, 72($29)
+	sd	$30, 80($29)
+	sdc1	$f24, 88($29)
+	sdc1	$f25, 96($29)
+	sdc1	$f26, 104($29)
+	sdc1	$f27, 112($29)
+	sdc1	$f28, 120($29)
+	sdc1	$f29, 128($29)
+	sdc1	$f30, 136($29)
+	sdc1	$f31, 144($29)
+
+	dla	$23,_cgo_reginit
+
+	// prepare SB register = pc & 0xffffffff00000000
+	bal	1f
+1:
+	dsrl	$28, $31, 32
+	dsll	$28, $28, 32
+
+	move	$20, $4 // save R4
+	jalr	$23	// call _cgo_reginit, set up Go ABI constant registers
+	move	$1, $6
+	jalr	$5	// call setg_gcc (clobbers R4)
+	jalr	$20	// call fn
+
+	ld	$16, 8($29)
+	ld	$17, 16($29)
+	ld	$18, 24($29)
+	ld	$19, 32($29)
+	ld	$20, 40($29)
+	ld	$21, 48($29)
+	ld	$22, 56($29)
+	ld	$23, 64($29)
+	ld	$28, 72($29)
+	ld	$30, 80($29)
+	ldc1	$f24, 88($29)
+	ldc1	$f25, 96($29)
+	ldc1	$f26, 104($29)
+	ldc1	$f27, 112($29)
+	ldc1	$f28, 120($29)
+	ldc1	$f29, 128($29)
+	ldc1	$f30, 136($29)
+	ldc1	$f31, 144($29)
+	ld	$31, 0($29)
+
+	daddiu	$29, $29, 160
+	jr	$31
+
+.set at
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_mmap.c b/src/runtime/cgo/gcc_mmap.c
index f2bcc98..088bcb2 100644
--- a/src/runtime/cgo/gcc_mmap.c
+++ b/src/runtime/cgo/gcc_mmap.c
@@ -1,20 +1,22 @@
-// Copyright 2015 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.
 
-// +build cgo
-
 // +build linux,amd64
 
 #include <errno.h>
 #include <stdint.h>
 #include <sys/mman.h>
 
+#include "libcgo.h"
+
 void *
 x_cgo_mmap(void *addr, uintptr_t length, int32_t prot, int32_t flags, int32_t fd, uint32_t offset) {
 	void *p;
 
+	_cgo_tsan_acquire();
 	p = mmap(addr, length, prot, flags, fd, offset);
+	_cgo_tsan_release();
 	if (p == MAP_FAILED) {
 		/* This is what the Go code expects on failure.  */
 		p = (void *) (uintptr_t) errno;
diff --git a/src/runtime/cgo/gcc_netbsd_386.c b/src/runtime/cgo/gcc_netbsd_386.c
index 4355bd0..99558ea 100644
--- a/src/runtime/cgo/gcc_netbsd_386.c
+++ b/src/runtime/cgo/gcc_netbsd_386.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <sys/types.h>
 #include <pthread.h>
 #include <signal.h>
@@ -68,11 +66,11 @@ threadentry(void *v)
 	setg_gcc((void*)ts.g);
 
 	// On NetBSD, a new thread inherits the signal stack of the
-	// creating thread.  That confuses minit, so we remove that
-	// signal stack here before calling the regular mstart.  It's
+	// creating thread. That confuses minit, so we remove that
+	// signal stack here before calling the regular mstart. It's
 	// a bit baroque to remove a signal stack here only to add one
 	// in minit, but it's a simple change that keeps NetBSD
-	// working like other OS's.  At this point all signals are
+	// working like other OS's. At this point all signals are
 	// blocked, so there is no race.
 	memset(&ss, 0, sizeof ss);
 	ss.ss_flags = SS_DISABLE;
diff --git a/src/runtime/cgo/gcc_netbsd_amd64.c b/src/runtime/cgo/gcc_netbsd_amd64.c
index 00e0667..f5c8b1e 100644
--- a/src/runtime/cgo/gcc_netbsd_amd64.c
+++ b/src/runtime/cgo/gcc_netbsd_amd64.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <sys/types.h>
 #include <pthread.h>
 #include <signal.h>
@@ -69,11 +67,11 @@ threadentry(void *v)
 	setg_gcc((void*)ts.g);
 
 	// On NetBSD, a new thread inherits the signal stack of the
-	// creating thread.  That confuses minit, so we remove that
-	// signal stack here before calling the regular mstart.  It's
+	// creating thread. That confuses minit, so we remove that
+	// signal stack here before calling the regular mstart. It's
 	// a bit baroque to remove a signal stack here only to add one
 	// in minit, but it's a simple change that keeps NetBSD
-	// working like other OS's.  At this point all signals are
+	// working like other OS's. At this point all signals are
 	// blocked, so there is no race.
 	memset(&ss, 0, sizeof ss);
 	ss.ss_flags = SS_DISABLE;
diff --git a/src/runtime/cgo/gcc_netbsd_arm.c b/src/runtime/cgo/gcc_netbsd_arm.c
index 32bc85b..97ce908 100644
--- a/src/runtime/cgo/gcc_netbsd_arm.c
+++ b/src/runtime/cgo/gcc_netbsd_arm.c
@@ -1,9 +1,7 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <sys/types.h>
 #include <pthread.h>
 #include <signal.h>
@@ -65,11 +63,11 @@ threadentry(void *v)
 	free(v);
 
 	// On NetBSD, a new thread inherits the signal stack of the
-	// creating thread.  That confuses minit, so we remove that
-	// signal stack here before calling the regular mstart.  It's
+	// creating thread. That confuses minit, so we remove that
+	// signal stack here before calling the regular mstart. It's
 	// a bit baroque to remove a signal stack here only to add one
 	// in minit, but it's a simple change that keeps NetBSD
-	// working like other OS's.  At this point all signals are
+	// working like other OS's. At this point all signals are
 	// blocked, so there is no race.
 	memset(&ss, 0, sizeof ss);
 	ss.ss_flags = SS_DISABLE;
diff --git a/src/runtime/cgo/gcc_openbsd_386.c b/src/runtime/cgo/gcc_openbsd_386.c
index 5f6d4cb..1bc61ff 100644
--- a/src/runtime/cgo/gcc_openbsd_386.c
+++ b/src/runtime/cgo/gcc_openbsd_386.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <sys/types.h>
 #include <dlfcn.h>
 #include <errno.h>
@@ -15,9 +13,15 @@
 static void* threadentry(void*);
 static void (*setg_gcc)(void*);
 
-// TCB_SIZE is sizeof(struct thread_control_block),
-// as defined in /usr/src/lib/librthread/tcb.h
+// TCB_SIZE is sizeof(struct thread_control_block), as defined in
+// /usr/src/lib/librthread/tcb.h on OpenBSD 5.9 and earlier.
 #define TCB_SIZE (4 * sizeof(void *))
+
+// TIB_SIZE is sizeof(struct tib), as defined in
+// /usr/include/tib.h on OpenBSD 6.0 and later.
+#define TIB_SIZE (4 * sizeof(void *) + 6 * sizeof(int))
+
+// TLS_SIZE is the size of TLS needed for Go.
 #define TLS_SIZE (2 * sizeof(void *))
 
 void *__get_tcb(void);
@@ -31,25 +35,38 @@ struct thread_args {
 	void *arg;
 };
 
+static int has_tib = 0;
+
 static void
 tcb_fixup(int mainthread)
 {
-	void *newtcb, *oldtcb;
+	void *tls, *newtcb, *oldtcb;
+	size_t tls_size, tcb_size;
+
+	// TODO(jsing): Remove once OpenBSD 6.1 is released and OpenBSD 5.9 is
+	// no longer supported.
 
 	// The OpenBSD ld.so(1) does not currently support PT_TLS. As a result,
 	// we need to allocate our own TLS space while preserving the existing
-	// TCB that has been setup via librthread.
+	// TCB or TIB that has been setup via librthread.
 
-	newtcb = malloc(TCB_SIZE + TLS_SIZE);
-	if(newtcb == NULL)
+	tcb_size = has_tib ? TIB_SIZE : TCB_SIZE;
+	tls_size = TLS_SIZE + tcb_size;
+	tls = malloc(tls_size);
+	if(tls == NULL)
 		abort();
 
 	// The signal trampoline expects the TLS slots to be zeroed.
-	bzero(newtcb, TLS_SIZE);
+	bzero(tls, TLS_SIZE);
 
 	oldtcb = __get_tcb();
-	bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
-	__set_tcb(newtcb + TLS_SIZE);
+	newtcb = tls + TLS_SIZE;
+	bcopy(oldtcb, newtcb, tcb_size);
+	if(has_tib) {
+		 // Fix up self pointer.
+		*(uintptr_t *)(newtcb) = (uintptr_t)newtcb;
+	}
+	__set_tcb(newtcb);
 
 	// NOTE(jsing, minux): we can't free oldtcb without causing double-free
 	// problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
@@ -81,6 +98,10 @@ static void init_pthread_wrapper(void) {
 		fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror());
 		abort();
 	}
+	// _rthread_init is hidden in OpenBSD librthread that has TIB.
+	if(dlsym(handle, "_rthread_init") == NULL) {
+		has_tib = 1;
+	}
 	dlclose(handle);
 }
 
@@ -146,6 +167,7 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
 	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 = sys_pthread_create(&p, &attr, threadentry, ts);
diff --git a/src/runtime/cgo/gcc_openbsd_amd64.c b/src/runtime/cgo/gcc_openbsd_amd64.c
index 4226567..4d4d143 100644
--- a/src/runtime/cgo/gcc_openbsd_amd64.c
+++ b/src/runtime/cgo/gcc_openbsd_amd64.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include <sys/types.h>
 #include <dlfcn.h>
 #include <errno.h>
@@ -15,9 +13,15 @@
 static void* threadentry(void*);
 static void (*setg_gcc)(void*);
 
-// TCB_SIZE is sizeof(struct thread_control_block),
-// as defined in /usr/src/lib/librthread/tcb.h
+// TCB_SIZE is sizeof(struct thread_control_block), as defined in
+// /usr/src/lib/librthread/tcb.h on OpenBSD 5.9 and earlier.
 #define TCB_SIZE (4 * sizeof(void *))
+
+// TIB_SIZE is sizeof(struct tib), as defined in
+// /usr/include/tib.h on OpenBSD 6.0 and later.
+#define TIB_SIZE (4 * sizeof(void *) + 6 * sizeof(int))
+
+// TLS_SIZE is the size of TLS needed for Go.
 #define TLS_SIZE (2 * sizeof(void *))
 
 void *__get_tcb(void);
@@ -31,25 +35,38 @@ struct thread_args {
 	void *arg;
 };
 
+static int has_tib = 0;
+
 static void
 tcb_fixup(int mainthread)
 {
-	void *newtcb, *oldtcb;
+	void *tls, *newtcb, *oldtcb;
+	size_t tls_size, tcb_size;
+
+	// TODO(jsing): Remove once OpenBSD 6.1 is released and OpenBSD 5.9 is
+	// no longer supported.
 
 	// The OpenBSD ld.so(1) does not currently support PT_TLS. As a result,
 	// we need to allocate our own TLS space while preserving the existing
-	// TCB that has been setup via librthread.
+	// TCB or TIB that has been setup via librthread.
 
-	newtcb = malloc(TCB_SIZE + TLS_SIZE);
-	if(newtcb == NULL)
+	tcb_size = has_tib ? TIB_SIZE : TCB_SIZE;
+	tls_size = TLS_SIZE + tcb_size;
+	tls = malloc(tls_size);
+	if(tls == NULL)
 		abort();
 
 	// The signal trampoline expects the TLS slots to be zeroed.
-	bzero(newtcb, TLS_SIZE);
+	bzero(tls, TLS_SIZE);
 
 	oldtcb = __get_tcb();
-	bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
-	__set_tcb(newtcb + TLS_SIZE);
+	newtcb = tls + TLS_SIZE;
+	bcopy(oldtcb, newtcb, tcb_size);
+	if(has_tib) {
+		 // Fix up self pointer.
+		*(uintptr_t *)(newtcb) = (uintptr_t)newtcb;
+	}
+	__set_tcb(newtcb);
 
 	// NOTE(jsing, minux): we can't free oldtcb without causing double-free
 	// problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
@@ -81,6 +98,10 @@ static void init_pthread_wrapper(void) {
 		fprintf(stderr, "runtime/cgo: dlsym failed to find pthread_create: %s\n", dlerror());
 		abort();
 	}
+	// _rthread_init is hidden in OpenBSD librthread that has TIB.
+	if(dlsym(handle, "_rthread_init") == NULL) {
+		has_tib = 1;
+	}
 	dlclose(handle);
 }
 
diff --git a/src/runtime/cgo/gcc_ppc64x.S b/src/runtime/cgo/gcc_ppc64x.S
index a817b3a..5f37a8b 100644
--- a/src/runtime/cgo/gcc_ppc64x.S
+++ b/src/runtime/cgo/gcc_ppc64x.S
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/cgo/gcc_s390x.S b/src/runtime/cgo/gcc_s390x.S
new file mode 100644
index 0000000..022f82d
--- /dev/null
+++ b/src/runtime/cgo/gcc_s390x.S
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ * void crosscall_s390x(void (*fn)(void), void *g)
+ *
+ * Calling into the go tool chain, where all registers are caller save.
+ * Called from standard s390x C ABI, where r6-r13, r15, and f0, f2, f4 and f6 are
+ * callee-save, so they must be saved explicitly.
+ */
+.globl crosscall_s390x
+crosscall_s390x:
+	/*
+	 * save r6-r15, f0, f2, f4 and f6 in the
+	 * register save area of the calling function
+	 */
+	stmg	%r6, %r15, 48(%r15)
+	stdy	%f0, 128(%r15)
+	stdy	%f2, 136(%r15)
+	stdy	%f4, 144(%r15)
+	stdy	%f6, 152(%r15)
+
+	/* set r0 to 0 */
+	xgr	%r0, %r0
+
+	/* restore g pointer */
+	lgr	%r13, %r3
+
+	/* grow stack 8 bytes and call fn */
+	agfi    %r15, -8
+	basr    %r14, %r2
+	agfi	%r15, 8
+
+	/* restore registers */
+	lmg	%r6, %r15, 48(%r15)
+	ldy	%f0, 128(%r15)
+	ldy	%f2, 136(%r15)
+	ldy	%f4, 144(%r15)
+	ldy	%f6, 152(%r15)
+
+	br      %r14 /* restored by lmg */
+
+#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 c976ac3..8708d40 100644
--- a/src/runtime/cgo/gcc_setenv.c
+++ b/src/runtime/cgo/gcc_setenv.c
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cgo/gcc_signal_darwin_armx.c b/src/runtime/cgo/gcc_signal_darwin_armx.c
index 295c562..02c54d8 100644
--- a/src/runtime/cgo/gcc_signal_darwin_armx.c
+++ b/src/runtime/cgo/gcc_signal_darwin_armx.c
@@ -1,9 +1,7 @@
-// Copyright 2015 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.
 
-// +build cgo
-
 // Emulation of the Unix signal SIGSEGV.
 //
 // On iOS, Go tests and apps under development are run by lldb.
@@ -184,6 +182,7 @@ darwin_arm_init_mach_exception_handler()
 	int ret;
 	pthread_t thr = NULL;
 	pthread_attr_t attr;
+	sigset_t ign, oset;
 
 	ret = mach_port_allocate(
 		mach_task_self(),
@@ -194,11 +193,18 @@ darwin_arm_init_mach_exception_handler()
 		abort();
 	}
 
+	// Block all signals to the exception handler thread
+	sigfillset(&ign);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
 	// 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);
+
+	pthread_sigmask(SIG_SETMASK, &oset, nil);
+
 	if (ret) {
 		fprintf(stderr, "runtime/cgo: pthread_create failed: %d\n", ret);
 		abort();
diff --git a/src/runtime/cgo/gcc_signal_darwin_lldb.c b/src/runtime/cgo/gcc_signal_darwin_lldb.c
index edb55f3..12cc388 100644
--- a/src/runtime/cgo/gcc_signal_darwin_lldb.c
+++ b/src/runtime/cgo/gcc_signal_darwin_lldb.c
@@ -1,9 +1,7 @@
-// Copyright 2015 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.
 
-// +build cgo
-
 // +build !lldb
 // +build darwin
 // +build arm arm64
diff --git a/src/runtime/cgo/gcc_solaris_amd64.c b/src/runtime/cgo/gcc_solaris_amd64.c
index 5a01e08..98a1a8b 100644
--- a/src/runtime/cgo/gcc_solaris_amd64.c
+++ b/src/runtime/cgo/gcc_solaris_amd64.c
@@ -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 cgo
-
 #include <pthread.h>
 #include <string.h>
 #include <signal.h>
diff --git a/src/runtime/cgo/gcc_traceback.c b/src/runtime/cgo/gcc_traceback.c
new file mode 100644
index 0000000..667ea4c
--- /dev/null
+++ b/src/runtime/cgo/gcc_traceback.c
@@ -0,0 +1,31 @@
+// Copyright 2016 The Go 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 linux
+
+#include <stdint.h>
+
+struct cgoTracebackArg {
+	uintptr_t  Context;
+	uintptr_t  SigContext;
+	uintptr_t* Buf;
+	uintptr_t  Max;
+};
+
+// Call the user's traceback function and then call sigtramp.
+// The runtime signal handler will jump to this code.
+// We do it this way so that the user's traceback function will be called
+// by a C function with proper unwind info.
+void
+x_cgo_callers(uintptr_t sig, void *info, void *context, void (*cgoTraceback)(struct cgoTracebackArg*), uintptr_t* cgoCallers, void (*sigtramp)(uintptr_t, void*, void*)) {
+	struct cgoTracebackArg arg;
+
+	arg.Context = 0;
+	arg.SigContext = (uintptr_t)(context);
+	arg.Buf = cgoCallers;
+	arg.Max = 32; // must match len(runtime.cgoCallers)
+	(*cgoTraceback)(&arg);
+	sigtramp(sig, info, context);
+}
diff --git a/src/runtime/cgo/gcc_util.c b/src/runtime/cgo/gcc_util.c
index d5efec3..99af021 100644
--- a/src/runtime/cgo/gcc_util.c
+++ b/src/runtime/cgo/gcc_util.c
@@ -1,36 +1,9 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #include "libcgo.h"
 
-/* Stub for calling malloc from Go */
-void
-x_cgo_malloc(void *p)
-{
-	struct a {
-		long long n;
-		void *ret;
-	} *a = p;
-
-	a->ret = malloc(a->n);
-	if(a->ret == NULL && a->n == 0)
-		a->ret = malloc(1);
-}
-
-/* Stub for calling free from Go */
-void
-x_cgo_free(void *p)
-{
-	struct a {
-		void *arg;
-	} *a = p;
-
-	free(a->arg);
-}
-
 /* Stub for creating a new thread */
 void
 x_cgo_thread_start(ThreadStart *arg)
@@ -38,7 +11,9 @@ x_cgo_thread_start(ThreadStart *arg)
 	ThreadStart *ts;
 
 	/* Make our own copy that can persist after we return. */
+	_cgo_tsan_acquire();
 	ts = malloc(sizeof *ts);
+	_cgo_tsan_release();
 	if(ts == nil) {
 		fprintf(stderr, "runtime/cgo: out of memory in thread_start\n");
 		abort();
diff --git a/src/runtime/cgo/gcc_windows_386.c b/src/runtime/cgo/gcc_windows_386.c
index e02991a..fa0c69b 100644
--- a/src/runtime/cgo/gcc_windows_386.c
+++ b/src/runtime/cgo/gcc_windows_386.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <process.h>
diff --git a/src/runtime/cgo/gcc_windows_amd64.c b/src/runtime/cgo/gcc_windows_amd64.c
index 1b3e8e3..a3c3896 100644
--- a/src/runtime/cgo/gcc_windows_amd64.c
+++ b/src/runtime/cgo/gcc_windows_amd64.c
@@ -1,9 +1,7 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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 cgo
-
 #define WIN64_LEAN_AND_MEAN
 #include <windows.h>
 #include <process.h>
diff --git a/src/runtime/cgo/iscgo.go b/src/runtime/cgo/iscgo.go
index 54f0a13..e12d0f4 100644
--- a/src/runtime/cgo/iscgo.go
+++ b/src/runtime/cgo/iscgo.go
@@ -1,12 +1,12 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
+// 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
+// correctly, and sometimes they break. This variable is a
 // backup: it depends only on old C style static linking rules.
 
 package cgo
diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h
index bda2499..01f9e72 100644
--- a/src/runtime/cgo/libcgo.h
+++ b/src/runtime/cgo/libcgo.h
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -57,8 +57,10 @@ void _cgo_sys_thread_start(ThreadStart *ts);
 
 /*
  * Waits for the Go runtime to be initialized (OS dependent).
+ * If runtime.SetCgoTraceback is used to set a context function,
+ * calls the context function and returns the context value.
  */
-void _cgo_wait_runtime_init_done();
+uintptr_t _cgo_wait_runtime_init_done();
 
 /*
  * Call fn in the 6c world.
@@ -84,3 +86,50 @@ 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);
+
+/*
+ * The cgo context function. See runtime.SetCgoTraceback.
+ */
+struct context_arg {
+	uintptr_t Context;
+};
+extern void (*(_cgo_get_context_function(void)))(struct context_arg*);
+
+/*
+ * TSAN support.  This is only useful when building with
+ *   CGO_CFLAGS="-fsanitize=thread" CGO_LDFLAGS="-fsanitize=thread" go install
+ */
+#undef CGO_TSAN
+#if defined(__has_feature)
+# if __has_feature(thread_sanitizer)
+#  define CGO_TSAN
+# endif
+#elif defined(__SANITIZE_THREAD__)
+# define CGO_TSAN
+#endif
+
+#ifdef CGO_TSAN
+
+// These must match the definitions in yesTsanProlog in cmd/cgo/out.go.
+
+long long _cgo_sync __attribute__ ((common));
+
+extern void __tsan_acquire(void*);
+extern void __tsan_release(void*);
+
+__attribute__ ((unused))
+static void _cgo_tsan_acquire() {
+	__tsan_acquire(&_cgo_sync);
+}
+
+__attribute__ ((unused))
+static void _cgo_tsan_release() {
+	__tsan_release(&_cgo_sync);
+}
+
+#else // !defined(CGO_TSAN)
+
+#define _cgo_tsan_acquire()
+#define _cgo_tsan_release()
+
+#endif // !defined(CGO_TSAN)
diff --git a/src/runtime/cgo/mmap.go b/src/runtime/cgo/mmap.go
index d514c38..ff98359 100644
--- a/src/runtime/cgo/mmap.go
+++ b/src/runtime/cgo/mmap.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -10,8 +10,8 @@ package cgo
 import _ "unsafe"
 
 // When using cgo, call the C library for mmap, so that we call into
-// any sanitizer interceptors.  This supports using the memory
-// sanitizer with Go programs.  The memory sanitizer only applies to
+// any sanitizer interceptors. This supports using the memory
+// sanitizer with Go programs. The memory sanitizer only applies to
 // C/C++ code; this permits that code to see the Go code as normal
 // program addresses that have been initialized.
 
diff --git a/src/runtime/cgo/netbsd.go b/src/runtime/cgo/netbsd.go
index ac6b18a..2cecd0c 100644
--- a/src/runtime/cgo/netbsd.go
+++ b/src/runtime/cgo/netbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/cgo/openbsd.go b/src/runtime/cgo/openbsd.go
index 61af3a8..5c70dbd 100644
--- a/src/runtime/cgo/openbsd.go
+++ b/src/runtime/cgo/openbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/cgo/setenv.go b/src/runtime/cgo/setenv.go
index 20d5703..fab4339 100644
--- a/src/runtime/cgo/setenv.go
+++ b/src/runtime/cgo/setenv.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cgo/signal_darwin_armx.go b/src/runtime/cgo/signal_darwin_armx.go
index 9c1ba5d..9f6741e 100644
--- a/src/runtime/cgo/signal_darwin_armx.go
+++ b/src/runtime/cgo/signal_darwin_armx.go
@@ -13,10 +13,14 @@ import "unsafe"
 //go:linkname x_cgo_panicmem x_cgo_panicmem
 var x_cgo_panicmem uintptr
 
+// use a pointer to avoid relocation of external symbol in __TEXT
+// make linker happy
+var _cgo_panicmem = &x_cgo_panicmem
+
 // 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)
+	*_cgo_panicmem = funcPC(panicmem)
 }
 
 func funcPC(f interface{}) uintptr {
diff --git a/src/runtime/cgo_mips64x.go b/src/runtime/cgo_mips64x.go
new file mode 100644
index 0000000..f718e92
--- /dev/null
+++ b/src/runtime/cgo_mips64x.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go 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 mips64 mips64le
+
+package runtime
+
+// crosscall1 calls into the runtime to set up the registers the
+// Go runtime expects and so the symbol it calls needs to be exported
+// for external linking to work.
+//go:cgo_export_static _cgo_reginit
diff --git a/src/runtime/cgo_mmap.go b/src/runtime/cgo_mmap.go
index c0396bd..a23cc79 100644
--- a/src/runtime/cgo_mmap.go
+++ b/src/runtime/cgo_mmap.go
@@ -1,8 +1,8 @@
-// Copyright 2015 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.
 
-// Support for memory sanitizer.  See runtime/cgo/mmap.go.
+// Support for memory sanitizer. See runtime/cgo/mmap.go.
 
 // +build linux,amd64
 
@@ -32,10 +32,10 @@ func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uns
 	return sysMmap(addr, n, prot, flags, fd, off)
 }
 
-// sysMmap calls the mmap system call.  It is implemented in assembly.
+// sysMmap calls the mmap system call. It is implemented in assembly.
 func sysMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
 
 // cgoMmap calls the mmap function in the runtime/cgo package on the
 // callCgoMmap calls the mmap function in the runtime/cgo package
-// using the GCC calling convention.  It is implemented in assembly.
+// using the GCC calling convention. It is implemented in assembly.
 func callCgoMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uintptr
diff --git a/src/runtime/cgo_ppc64x.go b/src/runtime/cgo_ppc64x.go
index 6a1b3bb..fb2da32 100644
--- a/src/runtime/cgo_ppc64x.go
+++ b/src/runtime/cgo_ppc64x.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index fef8add..0f8386b 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -28,7 +28,7 @@
 // and then unlocks g from m.
 //
 // The above description skipped over the possibility of the gcc-compiled
-// function f calling back into Go.  If that happens, we continue down
+// function f calling back into Go. If that happens, we continue down
 // the rabbit hole during the execution of f.
 //
 // To make it possible for gcc-compiled C code to call a Go function p.GoF,
@@ -38,9 +38,9 @@
 // GoF calls crosscall2(_cgoexp_GoF, frame, framesize).  Crosscall2
 // (in cgo/gcc_$GOARCH.S, a gcc-compiled assembly file) is a two-argument
 // adapter from the gcc function call ABI to the 6c function call ABI.
-// It is called from gcc to call 6c functions.  In this case it calls
+// It is called from gcc to call 6c functions. In this case it calls
 // _cgoexp_GoF(frame, framesize), still running on m->g0's stack
-// and outside the $GOMAXPROCS limit.  Thus, this code cannot yet
+// and outside the $GOMAXPROCS limit. Thus, this code cannot yet
 // call arbitrary Go code directly and must be careful not to allocate
 // memory or use up m->g0's stack.
 //
@@ -84,6 +84,10 @@ import (
 	"unsafe"
 )
 
+// Addresses collected in a cgo backtrace when crashing.
+// Length must match arg.Max in x_cgo_callers in runtime/cgo/gcc_traceback.c.
+type cgoCallers [32]uintptr
+
 // Call from Go to C.
 //go:nosplit
 func cgocall(fn, arg unsafe.Pointer) int32 {
@@ -109,6 +113,9 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
 	mp.ncgo++
 	defer endcgo(mp)
 
+	// Reset traceback.
+	mp.cgoCallers[0] = 0
+
 	/*
 	 * Announce we are entering a system call
 	 * so that the scheduler knows to create another
@@ -138,28 +145,9 @@ func endcgo(mp *m) {
 	unlockOSThread() // invalidates mp
 }
 
-// Helper functions for cgo code.
-
-func cmalloc(n uintptr) unsafe.Pointer {
-	var args struct {
-		n   uint64
-		ret unsafe.Pointer
-	}
-	args.n = uint64(n)
-	cgocall(_cgo_malloc, unsafe.Pointer(&args))
-	if args.ret == nil {
-		throw("C malloc failed")
-	}
-	return args.ret
-}
-
-func cfree(p unsafe.Pointer) {
-	cgocall(_cgo_free, p)
-}
-
 // Call from C back to Go.
 //go:nosplit
-func cgocallbackg() {
+func cgocallbackg(ctxt uintptr) {
 	gp := getg()
 	if gp != gp.m.curg {
 		println("runtime: bad g in cgocallback")
@@ -177,20 +165,43 @@ func cgocallbackg() {
 	savedsp := unsafe.Pointer(gp.syscallsp)
 	savedpc := gp.syscallpc
 	exitsyscall(0) // coming out of cgo call
-	cgocallbackg1()
+
+	cgocallbackg1(ctxt)
+
 	// going back to cgo call
 	reentersyscall(savedpc, uintptr(savedsp))
 
 	gp.m.syscall = syscall
 }
 
-func cgocallbackg1() {
+func cgocallbackg1(ctxt uintptr) {
 	gp := getg()
 	if gp.m.needextram {
 		gp.m.needextram = false
 		systemstack(newextram)
 	}
 
+	if ctxt != 0 {
+		s := append(gp.cgoCtxt, ctxt)
+
+		// Now we need to set gp.cgoCtxt = s, but we could get
+		// a SIGPROF signal while manipulating the slice, and
+		// the SIGPROF handler could pick up gp.cgoCtxt while
+		// tracing up the stack.  We need to ensure that the
+		// handler always sees a valid slice, so set the
+		// values in an order such that it always does.
+		p := (*slice)(unsafe.Pointer(&gp.cgoCtxt))
+		atomicstorep(unsafe.Pointer(&p.array), unsafe.Pointer(&s[0]))
+		p.cap = cap(s)
+		p.len = len(s)
+
+		defer func(gp *g) {
+			// Decrease the length of the slice by one, safely.
+			p := (*slice)(unsafe.Pointer(&gp.cgoCtxt))
+			p.len--
+		}(gp)
+	}
+
 	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,
@@ -229,18 +240,18 @@ func cgocallbackg1() {
 		// SP and the stack frame and between the stack frame and the arguments.
 		cb = (*args)(unsafe.Pointer(sp + 5*sys.PtrSize))
 	case "amd64":
-		// On amd64, stack frame is one word, plus caller PC.
+		// On amd64, stack frame is two words, plus caller PC.
 		if framepointer_enabled {
 			// In this case, there's also saved BP.
-			cb = (*args)(unsafe.Pointer(sp + 3*sys.PtrSize))
+			cb = (*args)(unsafe.Pointer(sp + 4*sys.PtrSize))
 			break
 		}
-		cb = (*args)(unsafe.Pointer(sp + 2*sys.PtrSize))
+		cb = (*args)(unsafe.Pointer(sp + 3*sys.PtrSize))
 	case "386":
 		// On 386, stack frame is three words, plus caller PC.
 		cb = (*args)(unsafe.Pointer(sp + 4*sys.PtrSize))
-	case "ppc64", "ppc64le":
-		// On ppc64, the callback arguments are in the arguments area of
+	case "ppc64", "ppc64le", "s390x":
+		// On ppc64 and s390x, the callback arguments are in the arguments area of
 		// cgocallback's stack frame. The stack looks like this:
 		// +--------------------+------------------------------+
 		// |                    | ...                          |
@@ -256,6 +267,10 @@ func cgocallbackg1() {
 		// |                    | fixed frame area             |
 		// +--------------------+------------------------------+ <- sp
 		cb = (*args)(unsafe.Pointer(sp + 2*sys.MinFrameSize + 2*sys.PtrSize))
+	case "mips64", "mips64le":
+		// On mips64x, 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*sys.PtrSize))
 	}
 
 	// Invoke callback.
@@ -264,7 +279,7 @@ func cgocallbackg1() {
 	// 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)
+	reflectcall(nil, unsafe.Pointer(cb.fn), cb.arg, uint32(cb.argsize), 0)
 
 	if raceenabled {
 		racereleasemerge(unsafe.Pointer(&racecgosync))
@@ -293,7 +308,7 @@ func unwindm(restore *bool) {
 	switch GOARCH {
 	default:
 		throw("unwindm not implemented")
-	case "386", "amd64", "arm", "ppc64", "ppc64le":
+	case "386", "amd64", "arm", "ppc64", "ppc64le", "mips64", "mips64le", "s390x":
 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + sys.MinFrameSize))
 	case "arm64":
 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 16))
@@ -317,8 +332,8 @@ var racecgosync uint64 // represents possible synchronization in C code
 
 // We want to detect all cases where a program that does not use
 // unsafe makes a cgo call passing a Go pointer to memory that
-// contains a Go pointer.  Here a Go pointer is defined as a pointer
-// to memory allocated by the Go runtime.  Programs that use unsafe
+// contains a Go pointer. Here a Go pointer is defined as a pointer
+// to memory allocated by the Go runtime. Programs that use unsafe
 // can evade this restriction easily, so we don't try to catch them.
 // The cgo program will rewrite all possibly bad pointer arguments to
 // call cgoCheckPointer, where we can catch cases of a Go pointer
@@ -326,25 +341,25 @@ var racecgosync uint64 // represents possible synchronization in C code
 
 // Complicating matters, taking the address of a slice or array
 // element permits the C program to access all elements of the slice
-// or array.  In that case we will see a pointer to a single element,
+// or array. In that case we will see a pointer to a single element,
 // but we need to check the entire data structure.
 
 // The cgoCheckPointer call takes additional arguments indicating that
-// it was called on an address expression.  An additional argument of
-// true means that it only needs to check a single element.  An
+// it was called on an address expression. An additional argument of
+// true means that it only needs to check a single element. An
 // additional argument of a slice or array means that it needs to
-// check the entire slice/array, but nothing else.  Otherwise, the
+// check the entire slice/array, but nothing else. Otherwise, the
 // pointer could be anything, and we check the entire heap object,
 // which is conservative but safe.
 
 // When and if we implement a moving garbage collector,
 // cgoCheckPointer will pin the pointer for the duration of the cgo
 // call.  (This is necessary but not sufficient; the cgo program will
-// also have to change to pin Go pointers that can not point to Go
+// also have to change to pin Go pointers that cannot point to Go
 // pointers.)
 
 // cgoCheckPointer checks if the argument contains a Go pointer that
-// points to a Go pointer, and panics if it does.  It returns the pointer.
+// points to a Go pointer, and panics if it does. It returns the pointer.
 func cgoCheckPointer(ptr interface{}, args ...interface{}) interface{} {
 	if debug.cgocheck == 0 {
 		return ptr
@@ -395,9 +410,9 @@ func cgoCheckPointer(ptr interface{}, args ...interface{}) interface{} {
 const cgoCheckPointerFail = "cgo argument has Go pointer to Go pointer"
 const cgoResultFail = "cgo result has Go pointer"
 
-// cgoCheckArg is the real work of cgoCheckPointer.  The argument p
+// cgoCheckArg is the real work of cgoCheckPointer. The argument p
 // is either a pointer to the value (of type t), or the value itself,
-// depending on indir.  The top parameter is whether we are at the top
+// depending on indir. The top parameter is whether we are at the top
 // level, where Go pointers are allowed.
 func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
 	if t.kind&kindNoPointers != 0 {
@@ -423,7 +438,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
 		}
 	case kindChan, kindMap:
 		// These types contain internal pointers that will
-		// always be allocated in the Go heap.  It's never OK
+		// always be allocated in the Go heap. It's never OK
 		// to pass them to C.
 		panic(errorString(msg))
 	case kindFunc:
@@ -440,7 +455,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
 			return
 		}
 		// A type known at compile time is OK since it's
-		// constant.  A type not known at compile time will be
+		// constant. A type not known at compile time will be
 		// in the heap and will not be OK.
 		if inheap(uintptr(unsafe.Pointer(it))) {
 			panic(errorString(msg))
@@ -507,8 +522,8 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) {
 }
 
 // cgoCheckUnknownPointer is called for an arbitrary pointer into Go
-// memory.  It checks whether that Go memory contains any other
-// pointer into Go memory.  If it does, we panic.
+// memory. It checks whether that Go memory contains any other
+// pointer into Go memory. If it does, we panic.
 // The return values are unused but useful to see in panic tracebacks.
 func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) {
 	if cgoInRange(p, mheap_.arena_start, mheap_.arena_used) {
@@ -522,19 +537,18 @@ func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) {
 			return
 		}
 
-		b, hbits, span := heapBitsForObject(uintptr(p), 0, 0)
+		b, hbits, span, _ := heapBitsForObject(uintptr(p), 0, 0)
 		base = b
 		if base == 0 {
 			return
 		}
 		n := span.elemsize
 		for i = uintptr(0); i < n; i += sys.PtrSize {
-			bits := hbits.bits()
-			if i >= 2*sys.PtrSize && bits&bitMarked == 0 {
+			if i != 1*sys.PtrSize && !hbits.morePointers() {
 				// No more possible pointers.
 				break
 			}
-			if bits&bitPointer != 0 {
+			if hbits.isPointer() {
 				if cgoIsGoPointer(*(*unsafe.Pointer)(unsafe.Pointer(base + i))) {
 					panic(errorString(msg))
 				}
@@ -559,7 +573,7 @@ func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) {
 }
 
 // cgoIsGoPointer returns whether the pointer is a Go pointer--a
-// pointer to Go memory.  We only care about Go memory that might
+// pointer to Go memory. We only care about Go memory that might
 // contain pointers.
 //go:nosplit
 //go:nowritebarrierrec
@@ -568,7 +582,7 @@ func cgoIsGoPointer(p unsafe.Pointer) bool {
 		return false
 	}
 
-	if cgoInRange(p, mheap_.arena_start, mheap_.arena_used) {
+	if inHeapOrStack(uintptr(p)) {
 		return true
 	}
 
@@ -589,7 +603,7 @@ func cgoInRange(p unsafe.Pointer, start, end uintptr) bool {
 }
 
 // cgoCheckResult is called to check the result parameter of an
-// exported Go function.  It panics if the result is or contains a Go
+// exported Go function. It panics if the result is or contains a Go
 // pointer.
 func cgoCheckResult(val interface{}) {
 	if debug.cgocheck == 0 {
diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go
index f93acab..59953f1 100644
--- a/src/runtime/cgocallback.go
+++ b/src/runtime/cgocallback.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/cgocheck.go b/src/runtime/cgocheck.go
index aebce15..2d06414 100644
--- a/src/runtime/cgocheck.go
+++ b/src/runtime/cgocheck.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -89,17 +89,25 @@ func cgoCheckSliceCopy(typ *_type, dst, src slice, n int) {
 }
 
 // cgoCheckTypedBlock checks the block of memory at src, for up to size bytes,
-// and throws if it finds a Go pointer.  The type of the memory is typ,
+// and throws if it finds a Go pointer. The type of the memory is typ,
 // and src is off bytes into that type.
 //go:nosplit
 //go:nowritebarrier
 func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
+	// Anything past typ.ptrdata is not a pointer.
+	if typ.ptrdata <= off {
+		return
+	}
+	if ptrdataSize := typ.ptrdata - off; size > ptrdataSize {
+		size = ptrdataSize
+	}
+
 	if typ.kind&kindGCProg == 0 {
 		cgoCheckBits(src, typ.gcdata, off, size)
 		return
 	}
 
-	// The type has a GC program.  Try to find GC bits somewhere else.
+	// The type has a GC program. Try to find GC bits somewhere else.
 	for datap := &firstmoduledata; datap != nil; datap = datap.next {
 		if cgoInRange(src, datap.data, datap.edata) {
 			doff := uintptr(src) - datap.data
@@ -148,8 +156,8 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
 }
 
 // cgoCheckBits checks the block of memory at src, for up to size
-// bytes, and throws if it finds a Go pointer.  The gcbits mark each
-// pointer value.  The src pointer is off bytes into the gcbits.
+// bytes, and throws if it finds a Go pointer. The gcbits mark each
+// pointer value. The src pointer is off bytes into the gcbits.
 //go:nosplit
 //go:nowritebarrier
 func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) {
@@ -184,15 +192,24 @@ func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) {
 
 // cgoCheckUsingType is like cgoCheckTypedBlock, but is a last ditch
 // fall back to look for pointers in src using the type information.
-// We only this when looking at a value on the stack when the type
+// We only use this when looking at a value on the stack when the type
 // uses a GC program, because otherwise it's more efficient to use the
-// GC bits.  This is called on the system stack.
+// GC bits. This is called on the system stack.
 //go:nowritebarrier
 //go:systemstack
 func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) {
 	if typ.kind&kindNoPointers != 0 {
 		return
 	}
+
+	// Anything past typ.ptrdata is not a pointer.
+	if typ.ptrdata <= off {
+		return
+	}
+	if ptrdataSize := typ.ptrdata - off; size > ptrdataSize {
+		size = ptrdataSize
+	}
+
 	if typ.kind&kindGCProg == 0 {
 		cgoCheckBits(src, typ.gcdata, off, size)
 		return
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 5be18be..712ad8c 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -33,7 +33,14 @@ type hchan struct {
 	recvx    uint   // receive index
 	recvq    waitq  // list of recv waiters
 	sendq    waitq  // list of send waiters
-	lock     mutex
+
+	// lock protects all fields in hchan, as well as several
+	// fields in sudogs blocked on this channel.
+	//
+	// Do not change another G's status while holding this lock
+	// (in particular, do not ready a G), as this can deadlock
+	// with stack shrinking.
+	lock mutex
 }
 
 type waitq struct {
@@ -56,8 +63,8 @@ func makechan(t *chantype, size int64) *hchan {
 	if hchanSize%maxAlign != 0 || elem.align > maxAlign {
 		throw("makechan: bad alignment")
 	}
-	if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/uintptr(elem.size)) {
-		panic("makechan: size out of range")
+	if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/elem.size) {
+		panic(plainError("makechan: size out of range"))
 	}
 
 	var c *hchan
@@ -67,7 +74,7 @@ func makechan(t *chantype, size int64) *hchan {
 		// buf points into the same allocation, elemtype is persistent.
 		// SudoG's are referenced from their owning thread so they can't be collected.
 		// TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
-		c = (*hchan)(mallocgc(hchanSize+uintptr(size)*uintptr(elem.size), nil, flagNoScan))
+		c = (*hchan)(mallocgc(hchanSize+uintptr(size)*elem.size, nil, true))
 		if size > 0 && elem.size != 0 {
 			c.buf = add(unsafe.Pointer(c), hchanSize)
 		} else {
@@ -77,7 +84,7 @@ func makechan(t *chantype, size int64) *hchan {
 		}
 	} else {
 		c = new(hchan)
-		c.buf = newarray(elem, uintptr(size))
+		c.buf = newarray(elem, int(size))
 	}
 	c.elemsize = uint16(elem.size)
 	c.elemtype = elem
@@ -164,7 +171,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 
 	if c.closed != 0 {
 		unlock(&c.lock)
-		panic("send on closed channel")
+		panic(plainError("send on closed channel"))
 	}
 
 	if sg := c.recvq.dequeue(); sg != nil {
@@ -175,7 +182,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 	}
 
 	if c.qcount < c.dataqsiz {
-		// Space is available in the channel buffer.  Enqueue the element to send.
+		// Space is available in the channel buffer. Enqueue the element to send.
 		qp := chanbuf(c, c.sendx)
 		if raceenabled {
 			raceacquire(qp)
@@ -196,17 +203,20 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		return false
 	}
 
-	// Block on the channel.  Some receiver will complete our operation for us.
+	// Block on the channel. Some receiver will complete our operation for us.
 	gp := getg()
 	mysg := acquireSudog()
 	mysg.releasetime = 0
 	if t0 != 0 {
 		mysg.releasetime = -1
 	}
+	// No stack splits between assigning elem and enqueuing mysg
+	// on gp.waiting where copystack can find it.
 	mysg.elem = ep
 	mysg.waitlink = nil
 	mysg.g = gp
 	mysg.selectdone = nil
+	mysg.c = c
 	gp.waiting = mysg
 	gp.param = nil
 	c.sendq.enqueue(mysg)
@@ -221,12 +231,13 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		if c.closed == 0 {
 			throw("chansend: spurious wakeup")
 		}
-		panic("send on closed channel")
+		panic(plainError("send on closed channel"))
 	}
 	gp.param = nil
 	if mysg.releasetime > 0 {
-		blockevent(int64(mysg.releasetime)-t0, 2)
+		blockevent(mysg.releasetime-t0, 2)
 	}
+	mysg.c = nil
 	releaseSudog(mysg)
 	return true
 }
@@ -243,7 +254,7 @@ func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
 			racesync(c, sg)
 		} else {
 			// Pretend we go through the buffer, even though
-			// we copy directly.  Note that we need to increment
+			// we copy directly. Note that we need to increment
 			// the head/tail locations only when raceenabled.
 			qp := chanbuf(c, c.recvx)
 			raceacquire(qp)
@@ -257,12 +268,12 @@ func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
 			c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz
 		}
 	}
-	unlockf()
 	if sg.elem != nil {
 		sendDirect(c.elemtype, sg, ep)
 		sg.elem = nil
 	}
 	gp := sg.g
+	unlockf()
 	gp.param = unsafe.Pointer(sg)
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
@@ -291,13 +302,13 @@ func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) {
 
 func closechan(c *hchan) {
 	if c == nil {
-		panic("close of nil channel")
+		panic(plainError("close of nil channel"))
 	}
 
 	lock(&c.lock)
 	if c.closed != 0 {
 		unlock(&c.lock)
-		panic("close of closed channel")
+		panic(plainError("close of closed channel"))
 	}
 
 	if raceenabled {
@@ -308,6 +319,8 @@ func closechan(c *hchan) {
 
 	c.closed = 1
 
+	var glist *g
+
 	// release all readers
 	for {
 		sg := c.recvq.dequeue()
@@ -326,7 +339,8 @@ func closechan(c *hchan) {
 		if raceenabled {
 			raceacquireg(gp, unsafe.Pointer(c))
 		}
-		goready(gp, 3)
+		gp.schedlink.set(glist)
+		glist = gp
 	}
 
 	// release all writers (they will panic)
@@ -344,9 +358,18 @@ func closechan(c *hchan) {
 		if raceenabled {
 			raceacquireg(gp, unsafe.Pointer(c))
 		}
-		goready(gp, 3)
+		gp.schedlink.set(glist)
+		glist = gp
 	}
 	unlock(&c.lock)
+
+	// Ready all Gs now that we've dropped the channel lock.
+	for glist != nil {
+		gp := glist
+		glist = glist.schedlink.ptr()
+		gp.schedlink = 0
+		goready(gp, 3)
+	}
 }
 
 // entry points for <- c from compiled code
@@ -420,8 +443,8 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 	}
 
 	if sg := c.sendq.dequeue(); sg != nil {
-		// Found a waiting sender.  If buffer is size 0, receive value
-		// directly from sender.  Otherwise, recieve from head of queue
+		// Found a waiting sender. If buffer is size 0, receive value
+		// directly from sender. Otherwise, receive from head of queue
 		// and add sender's value to the tail of the queue (both map to
 		// the same buffer slot because the queue is full).
 		recv(c, sg, ep, func() { unlock(&c.lock) })
@@ -460,11 +483,14 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 	if t0 != 0 {
 		mysg.releasetime = -1
 	}
+	// No stack splits between assigning elem and enqueuing mysg
+	// on gp.waiting where copystack can find it.
 	mysg.elem = ep
 	mysg.waitlink = nil
 	gp.waiting = mysg
 	mysg.g = gp
 	mysg.selectdone = nil
+	mysg.c = c
 	gp.param = nil
 	c.recvq.enqueue(mysg)
 	goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
@@ -479,6 +505,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 	}
 	closed := gp.param == nil
 	gp.param = nil
+	mysg.c = nil
 	releaseSudog(mysg)
 	return true, !closed
 }
@@ -501,7 +528,6 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
 		if raceenabled {
 			racesync(c, sg)
 		}
-		unlockf()
 		if ep != nil {
 			// copy data from sender
 			// ep points to our own stack or heap, so nothing
@@ -509,9 +535,9 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
 			typedmemmove(c.elemtype, ep, sg.elem)
 		}
 	} else {
-		// Queue is full.  Take the item at the
-		// head of the queue.  Make the sender enqueue
-		// its item at the tail of the queue.  Since the
+		// Queue is full. Take the item at the
+		// head of the queue. Make the sender enqueue
+		// its item at the tail of the queue. Since the
 		// queue is full, those are both the same slot.
 		qp := chanbuf(c, c.recvx)
 		if raceenabled {
@@ -531,10 +557,10 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
 			c.recvx = 0
 		}
 		c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz
-		unlockf()
 	}
 	sg.elem = nil
 	gp := sg.g
+	unlockf()
 	gp.param = unsafe.Pointer(sg)
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
diff --git a/src/runtime/chan_test.go b/src/runtime/chan_test.go
index 497e87f..8e8c47b 100644
--- a/src/runtime/chan_test.go
+++ b/src/runtime/chan_test.go
@@ -573,7 +573,7 @@ func TestSelectDuplicateChannel(t *testing.T) {
 		}
 		e <- 9
 	}()
-	time.Sleep(time.Millisecond) // make sure goroutine A gets qeueued first on c
+	time.Sleep(time.Millisecond) // make sure goroutine A gets queued first on c
 
 	// goroutine B
 	go func() {
@@ -586,6 +586,84 @@ func TestSelectDuplicateChannel(t *testing.T) {
 	c <- 8 // wake up B.  This operation used to fail because c.recvq was corrupted (it tries to wake up an already running G instead of B)
 }
 
+var selectSink interface{}
+
+func TestSelectStackAdjust(t *testing.T) {
+	// Test that channel receive slots that contain local stack
+	// pointers are adjusted correctly by stack shrinking.
+	c := make(chan *int)
+	d := make(chan *int)
+	ready1 := make(chan bool)
+	ready2 := make(chan bool)
+
+	f := func(ready chan bool, dup bool) {
+		// Temporarily grow the stack to 10K.
+		stackGrowthRecursive((10 << 10) / (128 * 8))
+
+		// We're ready to trigger GC and stack shrink.
+		ready <- true
+
+		val := 42
+		var cx *int
+		cx = &val
+
+		var c2 chan *int
+		var d2 chan *int
+		if dup {
+			c2 = c
+			d2 = d
+		}
+
+		// Receive from d. cx won't be affected.
+		select {
+		case cx = <-c:
+		case <-c2:
+		case <-d:
+		case <-d2:
+		}
+
+		// Check that pointer in cx was adjusted correctly.
+		if cx != &val {
+			t.Error("cx no longer points to val")
+		} else if val != 42 {
+			t.Error("val changed")
+		} else {
+			*cx = 43
+			if val != 43 {
+				t.Error("changing *cx failed to change val")
+			}
+		}
+		ready <- true
+	}
+
+	go f(ready1, false)
+	go f(ready2, true)
+
+	// Let the goroutines get into the select.
+	<-ready1
+	<-ready2
+	time.Sleep(10 * time.Millisecond)
+
+	// Force concurrent GC a few times.
+	var before, after runtime.MemStats
+	runtime.ReadMemStats(&before)
+	for i := 0; i < 100; i++ {
+		selectSink = new([1 << 20]byte)
+		runtime.ReadMemStats(&after)
+		if after.NumGC-before.NumGC >= 2 {
+			goto done
+		}
+	}
+	t.Fatal("failed to trigger concurrent GC")
+done:
+	selectSink = nil
+
+	// Wake selects.
+	close(d)
+	<-ready1
+	<-ready2
+}
+
 func BenchmarkChanNonblocking(b *testing.B) {
 	myc := make(chan int)
 	b.RunParallel(func(pb *testing.PB) {
@@ -716,7 +794,7 @@ func BenchmarkChanContended(b *testing.B) {
 	})
 }
 
-func BenchmarkChanSync(b *testing.B) {
+func benchmarkChanSync(b *testing.B, work int) {
 	const CallsPerSched = 1000
 	procs := 2
 	N := int32(b.N / CallsPerSched / procs * procs)
@@ -732,10 +810,14 @@ func BenchmarkChanSync(b *testing.B) {
 				for g := 0; g < CallsPerSched; g++ {
 					if i%2 == 0 {
 						<-myc
+						localWork(work)
 						myc <- 0
+						localWork(work)
 					} else {
 						myc <- 0
+						localWork(work)
 						<-myc
+						localWork(work)
 					}
 				}
 			}
@@ -747,6 +829,14 @@ func BenchmarkChanSync(b *testing.B) {
 	}
 }
 
+func BenchmarkChanSync(b *testing.B) {
+	benchmarkChanSync(b, 0)
+}
+
+func BenchmarkChanSyncWork(b *testing.B) {
+	benchmarkChanSync(b, 1000)
+}
+
 func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) {
 	const CallsPerSched = 1000
 	procs := runtime.GOMAXPROCS(-1)
@@ -920,3 +1010,18 @@ func BenchmarkChanPopular(b *testing.B) {
 	}
 	wg.Wait()
 }
+
+var (
+	alwaysFalse = false
+	workSink    = 0
+)
+
+func localWork(w int) {
+	foo := 0
+	for i := 0; i < w; i++ {
+		foo /= (foo + 1)
+	}
+	if alwaysFalse {
+		workSink += foo
+	}
+}
diff --git a/src/runtime/chanbarrier_test.go b/src/runtime/chanbarrier_test.go
index 770b850..b6029fb 100644
--- a/src/runtime/chanbarrier_test.go
+++ b/src/runtime/chanbarrier_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/compiler.go b/src/runtime/compiler.go
index 5f1e8d8..1ebc62d 100644
--- a/src/runtime/compiler.go
+++ b/src/runtime/compiler.go
@@ -1,11 +1,11 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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
 
 // Compiler is the name of the compiler toolchain that built the
-// running binary.  Known toolchains are:
+// running binary. Known toolchains are:
 //
 //	gc      Also known as cmd/compile.
 //	gccgo   The gccgo front end, part of the GCC compiler suite.
diff --git a/src/runtime/cpuprof.go b/src/runtime/cpuprof.go
index 87d5f99..5308200 100644
--- a/src/runtime/cpuprof.go
+++ b/src/runtime/cpuprof.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -12,30 +12,30 @@
 // writes to an operating system file.
 //
 // The signal handler for the profiling clock tick adds a new stack trace
-// to a hash table tracking counts for recent traces.  Most clock ticks
-// hit in the cache.  In the event of a cache miss, an entry must be
+// to a hash table tracking counts for recent traces. Most clock ticks
+// hit in the cache. In the event of a cache miss, an entry must be
 // evicted from the hash table, copied to a log that will eventually be
-// written as profile data.  The google-perftools code flushed the
-// log itself during the signal handler.  This code cannot do that, because
+// written as profile data. The google-perftools code flushed the
+// log itself during the signal handler. This code cannot do that, because
 // the io.Writer might block or need system calls or locks that are not
-// safe to use from within the signal handler.  Instead, we split the log
+// safe to use from within the signal handler. Instead, we split the log
 // into two halves and let the signal handler fill one half while a goroutine
-// is writing out the other half.  When the signal handler fills its half, it
-// offers to swap with the goroutine.  If the writer is not done with its half,
+// is writing out the other half. When the signal handler fills its half, it
+// offers to swap with the goroutine. If the writer is not done with its half,
 // we lose the stack trace for this clock tick (and record that loss).
 // The goroutine interacts with the signal handler by calling getprofile() to
 // get the next log piece to write, implicitly handing back the last log
 // piece it obtained.
 //
 // 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 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)
-// 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
+// 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
-// back to zero.  Setting the high bit in handoff means that the profiling is over,
+// back to zero. Setting the high bit in handoff means that the profiling is over,
 // and the goroutine is now in charge of flushing the data left in the hash table
 // to the log and returning that data.
 //
@@ -44,7 +44,7 @@
 // then the signal handler owns it and can change it to non-zero.
 // If handoff != 0 then the goroutine owns it and can change it to zero.
 // If that were the end of the story then we would not need to manipulate
-// handoff using atomic operations.  The operations are needed, however,
+// handoff using atomic operations. The operations are needed, however,
 // in order to let the log closer set the high bit to indicate "EOF" safely
 // in the situation when normally the goroutine "owns" handoff.
 
@@ -149,7 +149,7 @@ func SetCPUProfileRate(hz int) {
 
 		cpuprof.on = true
 		// pprof binary header format.
-		// http://code.google.com/p/google-perftools/source/browse/trunk/src/profiledata.cc#117
+		// https://github.com/gperftools/gperftools/blob/master/src/profiledata.cc#L119
 		p := &cpuprof.log[0]
 		p[0] = 0                 // count for header
 		p[1] = 3                 // depth for header
@@ -192,8 +192,21 @@ func SetCPUProfileRate(hz int) {
 // 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.
+// of stack. It is allowed to call evict.
+//go:nowritebarrierrec
 func (p *cpuProfile) add(pc []uintptr) {
+	p.addWithFlushlog(pc, p.flushlog)
+}
+
+// addWithFlushlog implements add and addNonGo.
+// 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 may be called by a signal handler with no g or m.
+// It is allowed to call evict, passing the flushlog parameter.
+//go:nosplit
+//go:nowritebarrierrec
+func (p *cpuProfile) addWithFlushlog(pc []uintptr, flushlog func() bool) {
 	if len(pc) > maxCPUProfStack {
 		pc = pc[:maxCPUProfStack]
 	}
@@ -231,8 +244,8 @@ Assoc:
 		}
 	}
 	if e.count > 0 {
-		if !p.evict(e) {
-			// Could not evict entry.  Record lost stack.
+		if !p.evict(e, flushlog) {
+			// Could not evict entry. Record lost stack.
 			p.lost++
 			return
 		}
@@ -248,15 +261,17 @@ Assoc:
 // evict copies the given entry's data into the log, so that
 // the entry can be reused.  evict is called from add, which
 // is called from the profiling signal handler, so it must not
-// allocate memory or block.  It is safe to call flushlog.
-// evict returns true if the entry was copied to the log,
-// false if there was no room available.
-func (p *cpuProfile) evict(e *cpuprofEntry) bool {
+// allocate memory or block, and it may be called with no g or m.
+// It is safe to call flushlog. evict returns true if the entry was
+// copied to the log, false if there was no room available.
+//go:nosplit
+//go:nowritebarrierrec
+func (p *cpuProfile) evict(e *cpuprofEntry, flushlog func() bool) bool {
 	d := e.depth
 	nslot := d + 2
 	log := &p.log[p.toggle]
 	if p.nlog+nslot > len(log) {
-		if !p.flushlog() {
+		if !flushlog() {
 			return false
 		}
 		log = &p.log[p.toggle]
@@ -276,8 +291,9 @@ func (p *cpuProfile) evict(e *cpuprofEntry) bool {
 
 // flushlog tries to flush the current log and switch to the other one.
 // flushlog is called from evict, called from add, called from the signal handler,
-// so it cannot allocate memory or block.  It can try to swap logs with
+// so it cannot allocate memory or block. It can try to swap logs with
 // the writing goroutine, as explained in the comment at the top of this file.
+//go:nowritebarrierrec
 func (p *cpuProfile) flushlog() bool {
 	if !atomic.Cas(&p.handoff, 0, uint32(p.nlog)) {
 		return false
@@ -299,8 +315,18 @@ func (p *cpuProfile) flushlog() bool {
 	return true
 }
 
+// addNonGo is like add, but runs on a non-Go thread.
+// It can't do anything that might need a g or an m.
+// With this entry point, we don't try to flush the log when evicting an
+// old entry. Instead, we just drop the stack trace if we're out of space.
+//go:nosplit
+//go:nowritebarrierrec
+func (p *cpuProfile) addNonGo(pc []uintptr) {
+	p.addWithFlushlog(pc, func() bool { return false })
+}
+
 // getprofile blocks until the next block of profiling data is available
-// and returns it as a []byte.  It is called from the writing goroutine.
+// and returns it as a []byte. It is called from the writing goroutine.
 func (p *cpuProfile) getprofile() []byte {
 	if p == nil {
 		return nil
@@ -358,7 +384,7 @@ func (p *cpuProfile) getprofile() []byte {
 	}
 
 	// In flush mode.
-	// Add is no longer being called.  We own the log.
+	// Add is no longer being called. We own the log.
 	// Also, p.handoff is non-zero, so flushlog will return false.
 	// Evict the hash table into the log and return it.
 Flush:
@@ -366,8 +392,8 @@ Flush:
 		b := &p.hash[i]
 		for j := range b.entry {
 			e := &b.entry[j]
-			if e.count > 0 && !p.evict(e) {
-				// Filled the log.  Stop the loop and return what we've got.
+			if e.count > 0 && !p.evict(e, p.flushlog) {
+				// Filled the log. Stop the loop and return what we've got.
 				break Flush
 			}
 		}
@@ -390,7 +416,7 @@ Flush:
 		return uintptrBytes(eod[:])
 	}
 
-	// Finally done.  Clean up and return nil.
+	// Finally done. Clean up and return nil.
 	p.flushing = false
 	if !atomic.Cas(&p.handoff, p.handoff, 0) {
 		print("runtime: profile flush racing with something\n")
@@ -410,7 +436,7 @@ func uintptrBytes(p []uintptr) (ret []byte) {
 }
 
 // CPUProfile returns the next chunk of binary CPU profiling stack trace data,
-// blocking until data is available.  If profiling is turned off and all the profile
+// blocking until data is available. If profiling is turned off and all the profile
 // data accumulated while it was on has been returned, CPUProfile returns nil.
 // The caller must save the returned data before calling CPUProfile again.
 //
diff --git a/src/runtime/cputicks.go b/src/runtime/cputicks.go
index f5a60e6..9162746 100644
--- a/src/runtime/cputicks.go
+++ b/src/runtime/cputicks.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -10,5 +10,5 @@
 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.
+// 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 1802e49..2504bd0 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -7,8 +7,10 @@
 package runtime_test
 
 import (
+	"bytes"
 	"fmt"
 	"internal/testenv"
+	"os"
 	"os/exec"
 	"runtime"
 	"strings"
@@ -49,6 +51,8 @@ func TestCgoCallbackGC(t *testing.T) {
 			t.Skip("see golang.org/issue/11990")
 		case runtime.GOOS == "linux" && runtime.GOARCH == "arm":
 			t.Skip("too slow for arm builders")
+		case runtime.GOOS == "linux" && (runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le"):
+			t.Skip("too slow for mips64x builders")
 		}
 	}
 	got := runTestProg(t, "testprogcgo", "CgoCallbackGC")
@@ -193,6 +197,15 @@ func TestCgoCheckBytes(t *testing.T) {
 	t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20)
 }
 
+func TestCgoPanicDeadlock(t *testing.T) {
+	// test issue 14432
+	got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock")
+	want := "panic: cgo error\n\n"
+	if !strings.HasPrefix(got, want) {
+		t.Fatalf("output does not start with %q:\n%s", want, got)
+	}
+}
+
 func TestCgoCCodeSIGPROF(t *testing.T) {
 	got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF")
 	want := "OK\n"
@@ -200,3 +213,78 @@ func TestCgoCCodeSIGPROF(t *testing.T) {
 		t.Errorf("expected %q got %v", want, got)
 	}
 }
+
+func TestCgoCrashTraceback(t *testing.T) {
+	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+	}
+	got := runTestProg(t, "testprogcgo", "CrashTraceback")
+	for i := 1; i <= 3; i++ {
+		if !strings.Contains(got, fmt.Sprintf("cgo symbolizer:%d", i)) {
+			t.Errorf("missing cgo symbolizer:%d", i)
+		}
+	}
+}
+
+func TestCgoTracebackContext(t *testing.T) {
+	got := runTestProg(t, "testprogcgo", "TracebackContext")
+	want := "OK\n"
+	if got != want {
+		t.Errorf("expected %q got %v", want, got)
+	}
+}
+
+func testCgoPprof(t *testing.T, buildArg, runArg string) {
+	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+	}
+	testenv.MustHaveGoRun(t)
+
+	exe, err := buildTestProg(t, "testprogcgo", buildArg)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	got, err := testEnv(exec.Command(exe, runArg)).CombinedOutput()
+	if err != nil {
+		t.Fatal(err)
+	}
+	fn := strings.TrimSpace(string(got))
+	defer os.Remove(fn)
+
+	cmd := testEnv(exec.Command("go", "tool", "pprof", "-top", "-nodecount=1", exe, fn))
+
+	found := false
+	for i, e := range cmd.Env {
+		if strings.HasPrefix(e, "PPROF_TMPDIR=") {
+			cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
+			found = true
+			break
+		}
+	}
+	if !found {
+		cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
+	}
+
+	top, err := cmd.CombinedOutput()
+	t.Logf("%s", top)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !bytes.Contains(top, []byte("cpuHog")) {
+		t.Error("missing cpuHog in pprof output")
+	}
+}
+
+func TestCgoPprof(t *testing.T) {
+	testCgoPprof(t, "", "CgoPprof")
+}
+
+func TestCgoPprofPIE(t *testing.T) {
+	testCgoPprof(t, "-ldflags=-extldflags=-pie", "CgoPprof")
+}
+
+func TestCgoPprofThread(t *testing.T) {
+	testCgoPprof(t, "", "CgoPprofThread")
+}
diff --git a/src/runtime/crash_nonunix_test.go b/src/runtime/crash_nonunix_test.go
new file mode 100644
index 0000000..2ce995c
--- /dev/null
+++ b/src/runtime/crash_nonunix_test.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go 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 nacl
+
+package runtime_test
+
+import "os"
+
+// sigquit is the signal to send to kill a hanging testdata program.
+// On Unix we send SIGQUIT, but on non-Unix we only have os.Kill.
+var sigquit = os.Kill
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index 5f0e77b..a2f7ff7 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -5,6 +5,7 @@
 package runtime_test
 
 import (
+	"bytes"
 	"fmt"
 	"internal/testenv"
 	"io/ioutil"
@@ -13,9 +14,11 @@ import (
 	"path/filepath"
 	"regexp"
 	"runtime"
+	"strconv"
 	"strings"
 	"sync"
 	"testing"
+	"time"
 )
 
 var toRemove []string
@@ -65,11 +68,48 @@ func runTestProg(t *testing.T, binary, name string) string {
 	if err != nil {
 		t.Fatal(err)
 	}
-	got, _ := testEnv(exec.Command(exe, name)).CombinedOutput()
-	return string(got)
+
+	cmd := testEnv(exec.Command(exe, name))
+	var b bytes.Buffer
+	cmd.Stdout = &b
+	cmd.Stderr = &b
+	if err := cmd.Start(); err != nil {
+		t.Fatalf("starting %s %s: %v", binary, name, err)
+	}
+
+	// If the process doesn't complete within 1 minute,
+	// assume it is hanging and kill it to get a stack trace.
+	p := cmd.Process
+	done := make(chan bool)
+	go func() {
+		scale := 1
+		// This GOARCH/GOOS test is copied from cmd/dist/test.go.
+		// TODO(iant): Have cmd/dist update the environment variable.
+		if runtime.GOARCH == "arm" || runtime.GOOS == "windows" {
+			scale = 2
+		}
+		if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
+			if sc, err := strconv.Atoi(s); err == nil {
+				scale = sc
+			}
+		}
+
+		select {
+		case <-done:
+		case <-time.After(time.Duration(scale) * time.Minute):
+			p.Signal(sigquit)
+		}
+	}()
+
+	if err := cmd.Wait(); err != nil {
+		t.Logf("%s %s exit status: %v", binary, name, err)
+	}
+	close(done)
+
+	return b.String()
 }
 
-func buildTestProg(t *testing.T, binary string) (string, error) {
+func buildTestProg(t *testing.T, binary string, flags ...string) (string, error) {
 	checkStaleRuntime(t)
 
 	testprog.Lock()
@@ -86,23 +126,27 @@ func buildTestProg(t *testing.T, binary string) (string, error) {
 	if testprog.target == nil {
 		testprog.target = make(map[string]buildexe)
 	}
-	target, ok := testprog.target[binary]
+	name := binary
+	if len(flags) > 0 {
+		name += "_" + strings.Join(flags, "_")
+	}
+	target, ok := testprog.target[name]
 	if ok {
 		return target.exe, target.err
 	}
 
-	exe := filepath.Join(testprog.dir, binary+".exe")
-	cmd := exec.Command("go", "build", "-o", exe)
+	exe := filepath.Join(testprog.dir, name+".exe")
+	cmd := exec.Command("go", append([]string{"build", "-o", exe}, flags...)...)
 	cmd.Dir = "testdata/" + binary
 	out, err := testEnv(cmd).CombinedOutput()
 	if err != nil {
 		exe = ""
-		target.err = fmt.Errorf("building %s: %v\n%s", binary, err, out)
-		testprog.target[binary] = target
+		target.err = fmt.Errorf("building %s %v: %v\n%s", binary, flags, err, out)
+		testprog.target[name] = target
 		return "", target.err
 	}
 	target.exe = exe
-	testprog.target[binary] = target
+	testprog.target[name] = target
 	return exe, nil
 }
 
@@ -273,6 +317,52 @@ func TestGoexitInPanic(t *testing.T) {
 	}
 }
 
+// Issue 14965: Runtime panics should be of type runtime.Error
+func TestRuntimePanicWithRuntimeError(t *testing.T) {
+	testCases := [...]func(){
+		0: func() {
+			var m map[uint64]bool
+			m[1234] = true
+		},
+		1: func() {
+			ch := make(chan struct{})
+			close(ch)
+			close(ch)
+		},
+		2: func() {
+			var ch = make(chan struct{})
+			close(ch)
+			ch <- struct{}{}
+		},
+		3: func() {
+			var s = make([]int, 2)
+			_ = s[2]
+		},
+		4: func() {
+			n := -1
+			_ = make(chan bool, n)
+		},
+		5: func() {
+			close((chan bool)(nil))
+		},
+	}
+
+	for i, fn := range testCases {
+		got := panicValue(fn)
+		if _, ok := got.(runtime.Error); !ok {
+			t.Errorf("test #%d: recovered value %v(type %T) does not implement runtime.Error", i, got, got)
+		}
+	}
+}
+
+func panicValue(fn func()) (recovered interface{}) {
+	defer func() {
+		recovered = recover()
+	}()
+	fn()
+	return
+}
+
 func TestPanicAfterGoexit(t *testing.T) {
 	// an uncaught panic should still work after goexit
 	output := runTestProg(t, "testprog", "PanicAfterGoexit")
@@ -294,9 +384,9 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
 	// 1. defer a function that recovers
 	// 2. defer a function that panics
 	// 3. call goexit
-	// Goexit should run the #2 defer.  Its panic
+	// Goexit should run the #2 defer. Its panic
 	// should be caught by the #1 defer, and execution
-	// should resume in the caller.  Like the Goexit
+	// should resume in the caller. Like the Goexit
 	// never happened!
 	defer func() {
 		r := recover()
@@ -336,3 +426,59 @@ func TestPanicTraceback(t *testing.T) {
 		output = output[idx[1]:]
 	}
 }
+
+func testPanicDeadlock(t *testing.T, name string, want string) {
+	// test issue 14432
+	output := runTestProg(t, "testprog", name)
+	if !strings.HasPrefix(output, want) {
+		t.Fatalf("output does not start with %q:\n%s", want, output)
+	}
+}
+
+func TestPanicDeadlockGosched(t *testing.T) {
+	testPanicDeadlock(t, "GoschedInPanic", "panic: errorThatGosched\n\n")
+}
+
+func TestPanicDeadlockSyscall(t *testing.T) {
+	testPanicDeadlock(t, "SyscallInPanic", "1\n2\npanic: 3\n\n")
+}
+
+func TestMemPprof(t *testing.T) {
+	testenv.MustHaveGoRun(t)
+
+	exe, err := buildTestProg(t, "testprog")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	got, err := testEnv(exec.Command(exe, "MemProf")).CombinedOutput()
+	if err != nil {
+		t.Fatal(err)
+	}
+	fn := strings.TrimSpace(string(got))
+	defer os.Remove(fn)
+
+	cmd := testEnv(exec.Command("go", "tool", "pprof", "-alloc_space", "-top", exe, fn))
+
+	found := false
+	for i, e := range cmd.Env {
+		if strings.HasPrefix(e, "PPROF_TMPDIR=") {
+			cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
+			found = true
+			break
+		}
+	}
+	if !found {
+		cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
+	}
+
+	top, err := cmd.CombinedOutput()
+	t.Logf("%s", top)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if !bytes.Contains(top, []byte("MemProf")) {
+		t.Error("missing MemProf in pprof output")
+	}
+}
diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go
index 771b303..6e4d04b 100644
--- a/src/runtime/crash_unix_test.go
+++ b/src/runtime/crash_unix_test.go
@@ -19,6 +19,10 @@ import (
 	"testing"
 )
 
+// sigquit is the signal to send to kill a hanging testdata program.
+// Send SIGQUIT to get a stack trace.
+var sigquit = syscall.SIGQUIT
+
 func TestCrashDumpsAllThreads(t *testing.T) {
 	switch runtime.GOOS {
 	case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
@@ -149,10 +153,6 @@ func loop(i int, c chan bool) {
 
 func TestSignalExitStatus(t *testing.T) {
 	testenv.MustHaveGoBuild(t)
-	switch runtime.GOOS {
-	case "netbsd", "solaris":
-		t.Skipf("skipping on %s; see https://golang.org/issue/14063", runtime.GOOS)
-	}
 	exe, err := buildTestProg(t, "testprog")
 	if err != nil {
 		t.Fatal(err)
diff --git a/src/runtime/debug.go b/src/runtime/debug.go
index 0f59365..0e798fc 100644
--- a/src/runtime/debug.go
+++ b/src/runtime/debug.go
@@ -10,7 +10,7 @@ import (
 )
 
 // GOMAXPROCS sets the maximum number of CPUs that can be executing
-// simultaneously and returns the previous setting.  If n < 1, it does not
+// simultaneously and returns the previous setting. If n < 1, it does not
 // change the current setting.
 // The number of logical CPUs on the local machine can be queried with NumCPU.
 // This call will go away when the scheduler improves.
diff --git a/src/runtime/debug/debug.s b/src/runtime/debug/debug.s
index a7292c4..6aae33a 100644
--- a/src/runtime/debug/debug.s
+++ b/src/runtime/debug/debug.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/debug/garbage.go b/src/runtime/debug/garbage.go
index 8d6d278..8144497 100644
--- a/src/runtime/debug/garbage.go
+++ b/src/runtime/debug/garbage.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -155,7 +155,13 @@ 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 https://golang.org/s/go13heapdump.
+//
+// WriteHeapDump suspends the execution of all goroutines until the heap
+// dump is completely written.  Thus, the file descriptor must not be
+// connected to a pipe or socket whose other end is in the same Go
+// process; instead, use a temporary file or network socket.
+//
+// The heap dump format is defined at https://golang.org/s/go15heapdump.
 func WriteHeapDump(fd uintptr)
 
 // SetTraceback sets the amount of detail printed by the runtime in
diff --git a/src/runtime/debug/garbage_test.go b/src/runtime/debug/garbage_test.go
index d834da8..6ec94aa 100644
--- a/src/runtime/debug/garbage_test.go
+++ b/src/runtime/debug/garbage_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/debug/heapdump_test.go b/src/runtime/debug/heapdump_test.go
index 5761c01..7d5b950 100644
--- a/src/runtime/debug/heapdump_test.go
+++ b/src/runtime/debug/heapdump_test.go
@@ -38,7 +38,7 @@ type Obj struct {
 }
 
 func objfin(x *Obj) {
-	println("finalized", x)
+	//println("finalized", x)
 }
 
 func TestWriteHeapDumpFinalizers(t *testing.T) {
diff --git a/src/runtime/debug/stack_test.go b/src/runtime/debug/stack_test.go
index f544372..9376e82 100644
--- a/src/runtime/debug/stack_test.go
+++ b/src/runtime/debug/stack_test.go
@@ -59,7 +59,7 @@ func TestStack(t *testing.T) {
 }
 
 func check(t *testing.T, line, has string) {
-	if strings.Index(line, has) < 0 {
+	if !strings.Contains(line, has) {
 		t.Errorf("expected %q in %q", has, line)
 	}
 }
diff --git a/src/runtime/debug/stubs.go b/src/runtime/debug/stubs.go
index 6c87ffd..2cba136 100644
--- a/src/runtime/debug/stubs.go
+++ b/src/runtime/debug/stubs.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/defs2_linux.go b/src/runtime/defs2_linux.go
index 980df9e..9dea6a1 100644
--- a/src/runtime/defs2_linux.go
+++ b/src/runtime/defs2_linux.go
@@ -32,7 +32,7 @@ package runtime
 #include <linux/eventpoll.h>
 
 // This is the sigaction structure from the Linux 2.1.68 kernel which
-//   is used with the rt_sigaction system call.  For 386 this is not
+//   is used with the rt_sigaction system call. For 386 this is not
 //   defined in any public header file.
 
 struct kernel_sigaction {
diff --git a/src/runtime/defs_linux_s390x.go b/src/runtime/defs_linux_s390x.go
new file mode 100644
index 0000000..5f55d5a
--- /dev/null
+++ b/src/runtime/defs_linux_s390x.go
@@ -0,0 +1,167 @@
+// Copyright 2016 The Go Authors. 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 (
+	_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
+)
+
+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
+}
+
+const (
+	_O_RDONLY    = 0x0
+	_O_CLOEXEC   = 0x80000
+	_SA_RESTORER = 0
+)
+
+type sigaltstackt struct {
+	ss_sp    *byte
+	ss_flags int32
+	ss_size  uintptr
+}
+
+type sigcontext struct {
+	psw_mask uint64
+	psw_addr uint64
+	gregs    [16]uint64
+	aregs    [16]uint32
+	fpc      uint32
+	fpregs   [16]uint64
+}
+
+type ucontext struct {
+	uc_flags    uint64
+	uc_link     *ucontext
+	uc_stack    sigaltstackt
+	uc_mcontext sigcontext
+	uc_sigmask  uint64
+}
diff --git a/src/runtime/defs_plan9_386.go b/src/runtime/defs_plan9_386.go
index 3574cb6..54ace48 100644
--- a/src/runtime/defs_plan9_386.go
+++ b/src/runtime/defs_plan9_386.go
@@ -30,9 +30,13 @@ type sigctxt struct {
 
 func (c *sigctxt) pc() uintptr { return uintptr(c.u.pc) }
 func (c *sigctxt) sp() uintptr { return uintptr(c.u.sp) }
+func (c *sigctxt) lr() uintptr { return uintptr(0) }
 
 func (c *sigctxt) setpc(x uintptr) { c.u.pc = uint32(x) }
 func (c *sigctxt) setsp(x uintptr) { c.u.sp = uint32(x) }
+func (c *sigctxt) setlr(x uintptr) {}
+
+func (c *sigctxt) savelr(x uintptr) {}
 
 func dumpregs(u *ureg) {
 	print("ax    ", hex(u.ax), "\n")
@@ -49,3 +53,5 @@ func dumpregs(u *ureg) {
 	print("fs    ", hex(u.fs), "\n")
 	print("gs    ", hex(u.gs), "\n")
 }
+
+func sigpanictramp() {}
diff --git a/src/runtime/defs_plan9_amd64.go b/src/runtime/defs_plan9_amd64.go
index 54b4d39..1633ec1 100644
--- a/src/runtime/defs_plan9_amd64.go
+++ b/src/runtime/defs_plan9_amd64.go
@@ -39,9 +39,13 @@ type sigctxt struct {
 
 func (c *sigctxt) pc() uintptr { return uintptr(c.u.ip) }
 func (c *sigctxt) sp() uintptr { return uintptr(c.u.sp) }
+func (c *sigctxt) lr() uintptr { return uintptr(0) }
 
 func (c *sigctxt) setpc(x uintptr) { c.u.ip = uint64(x) }
 func (c *sigctxt) setsp(x uintptr) { c.u.sp = uint64(x) }
+func (c *sigctxt) setlr(x uintptr) {}
+
+func (c *sigctxt) savelr(x uintptr) {}
 
 func dumpregs(u *ureg) {
 	print("ax    ", hex(u.ax), "\n")
@@ -66,3 +70,5 @@ func dumpregs(u *ureg) {
 	print("fs    ", hex(u.fs), "\n")
 	print("gs    ", hex(u.gs), "\n")
 }
+
+func sigpanictramp() {}
diff --git a/src/runtime/defs_plan9_arm.go b/src/runtime/defs_plan9_arm.go
new file mode 100644
index 0000000..9c700ae
--- /dev/null
+++ b/src/runtime/defs_plan9_arm.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.
+
+package runtime
+
+const _PAGESIZE = 0x1000
+
+type ureg struct {
+	r0   uint32 /* general registers */
+	r1   uint32 /* ... */
+	r2   uint32 /* ... */
+	r3   uint32 /* ... */
+	r4   uint32 /* ... */
+	r5   uint32 /* ... */
+	r6   uint32 /* ... */
+	r7   uint32 /* ... */
+	r8   uint32 /* ... */
+	r9   uint32 /* ... */
+	r10  uint32 /* ... */
+	r11  uint32 /* ... */
+	r12  uint32 /* ... */
+	sp   uint32
+	link uint32 /* ... */
+	trap uint32 /* trap type */
+	psr  uint32
+	pc   uint32 /* interrupted addr */
+}
+
+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) lr() uintptr { return uintptr(c.u.link) }
+
+func (c *sigctxt) setpc(x uintptr)  { c.u.pc = uint32(x) }
+func (c *sigctxt) setsp(x uintptr)  { c.u.sp = uint32(x) }
+func (c *sigctxt) setlr(x uintptr)  { c.u.link = uint32(x) }
+func (c *sigctxt) savelr(x uintptr) { c.u.r0 = uint32(x) }
+
+func dumpregs(u *ureg) {
+	print("r0    ", hex(u.r0), "\n")
+	print("r1    ", hex(u.r1), "\n")
+	print("r2    ", hex(u.r2), "\n")
+	print("r3    ", hex(u.r3), "\n")
+	print("r4    ", hex(u.r4), "\n")
+	print("r5    ", hex(u.r5), "\n")
+	print("r6    ", hex(u.r6), "\n")
+	print("r7    ", hex(u.r7), "\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("sp    ", hex(u.sp), "\n")
+	print("link  ", hex(u.link), "\n")
+	print("pc    ", hex(u.pc), "\n")
+	print("psr   ", hex(u.psr), "\n")
+}
+
+func sigpanictramp()
diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go
index 2daba0c..c95b5db 100644
--- a/src/runtime/env_plan9.go
+++ b/src/runtime/env_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/runtime/env_posix.go b/src/runtime/env_posix.go
index c3b06f7..da34425 100644
--- a/src/runtime/env_posix.go
+++ b/src/runtime/env_posix.go
@@ -32,7 +32,7 @@ func syscall_setenv_c(k string, v string) {
 		return
 	}
 	arg := [2]unsafe.Pointer{cstring(k), cstring(v)}
-	asmcgocall(unsafe.Pointer(_cgo_setenv), unsafe.Pointer(&arg))
+	asmcgocall(_cgo_setenv, unsafe.Pointer(&arg))
 }
 
 // Update the C environment if cgo is loaded.
@@ -43,7 +43,7 @@ func syscall_unsetenv_c(k string) {
 		return
 	}
 	arg := [1]unsafe.Pointer{cstring(k)}
-	asmcgocall(unsafe.Pointer(_cgo_unsetenv), unsafe.Pointer(&arg))
+	asmcgocall(_cgo_unsetenv, unsafe.Pointer(&arg))
 }
 
 func cstring(s string) unsafe.Pointer {
diff --git a/src/runtime/error.go b/src/runtime/error.go
index de07bcb..0238c5e 100644
--- a/src/runtime/error.go
+++ b/src/runtime/error.go
@@ -50,13 +50,24 @@ func (e errorString) Error() string {
 	return "runtime error: " + string(e)
 }
 
+// plainError represents a runtime error described a string without
+// the prefix "runtime error: " after invoking errorString.Error().
+// See Issue #14965.
+type plainError string
+
+func (e plainError) RuntimeError() {}
+
+func (e plainError) Error() string {
+	return string(e)
+}
+
 type stringer interface {
 	String() string
 }
 
 func typestring(x interface{}) string {
 	e := efaceOf(&x)
-	return *e._type._string
+	return e._type.string()
 }
 
 // For calling from C.
@@ -82,5 +93,5 @@ func printany(i interface{}) {
 
 // called from generated code
 func panicwrap(pkg, typ, meth string) {
-	panic("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer")
+	panic(plainError("value method " + pkg + "." + typ + "." + meth + " called using nil *" + typ + " pointer"))
 }
diff --git a/src/runtime/export_arm_test.go b/src/runtime/export_arm_test.go
index 446d264..b8a89fc 100644
--- a/src/runtime/export_arm_test.go
+++ b/src/runtime/export_arm_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/export_futex_test.go b/src/runtime/export_futex_test.go
index 96281f6..5e27236 100644
--- a/src/runtime/export_futex_test.go
+++ b/src/runtime/export_futex_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/export_linux_test.go b/src/runtime/export_linux_test.go
index 61d6ae4..ef0c111 100644
--- a/src/runtime/export_linux_test.go
+++ b/src/runtime/export_linux_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/export_mmap_test.go b/src/runtime/export_mmap_test.go
index 11ea076..bc8191e 100644
--- a/src/runtime/export_mmap_test.go
+++ b/src/runtime/export_mmap_test.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/export_test.go b/src/runtime/export_test.go
index 4380908..199a049 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -45,42 +45,6 @@ func LFStackPop(head *uint64) *LFNode {
 	return (*LFNode)(unsafe.Pointer(lfstackpop(head)))
 }
 
-type ParFor struct {
-	body   func(*ParFor, uint32)
-	done   uint32
-	Nthr   uint32
-	thrseq uint32
-	Cnt    uint32
-	wait   bool
-}
-
-func NewParFor(nthrmax uint32) *ParFor {
-	var desc *ParFor
-	systemstack(func() {
-		desc = (*ParFor)(unsafe.Pointer(parforalloc(nthrmax)))
-	})
-	return desc
-}
-
-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) {
-	systemstack(func() {
-		parfordo((*parfor)(unsafe.Pointer(desc)))
-	})
-}
-
-func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
-	desc1 := (*parfor)(unsafe.Pointer(desc))
-	pos := desc1.thr[tid].pos
-	return uint32(pos), uint32(pos >> 32)
-}
-
 func GCMask(x interface{}) (ret []byte) {
 	systemstack(func() {
 		ret = getgcmask(x)
@@ -89,10 +53,100 @@ func GCMask(x interface{}) (ret []byte) {
 }
 
 func RunSchedLocalQueueTest() {
-	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 RunSchedLocalQueueStealTest() {
-	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 RunSchedLocalQueueEmptyTest(iters int) {
+	// Test that runq is not spuriously reported as empty.
+	// Runq emptiness affects scheduling decisions and spurious emptiness
+	// can lead to underutilization (both runnable Gs and idle Ps coexist
+	// for arbitrary long time).
+	done := make(chan bool, 1)
+	p := new(p)
+	gs := make([]g, 2)
+	ready := new(uint32)
+	for i := 0; i < iters; i++ {
+		*ready = 0
+		next0 := (i & 1) == 0
+		next1 := (i & 2) == 0
+		runqput(p, &gs[0], next0)
+		go func() {
+			for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
+			}
+			if runqempty(p) {
+				println("next:", next0, next1)
+				throw("queue is empty")
+			}
+			done <- true
+		}()
+		for atomic.Xadd(ready, 1); atomic.Load(ready) != 2; {
+		}
+		runqput(p, &gs[1], next1)
+		runqget(p)
+		<-done
+		runqget(p)
+	}
 }
 
 var StringHash = stringHash
@@ -172,6 +226,9 @@ func SetTracebackEnv(level string) {
 	traceback_env = traceback_cache
 }
 
+var ReadUnaligned32 = readUnaligned32
+var ReadUnaligned64 = readUnaligned64
+
 func CountPagesInUse() (pagesInUse, counted uintptr) {
 	stopTheWorld("CountPagesInUse")
 
diff --git a/src/runtime/export_windows_test.go b/src/runtime/export_windows_test.go
index 7b269ec..536b398 100644
--- a/src/runtime/export_windows_test.go
+++ b/src/runtime/export_windows_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,7 +8,11 @@ package runtime
 
 import "unsafe"
 
-var TestingWER = &testingWER
+var (
+	TestingWER              = &testingWER
+	OsYield                 = osyield
+	TimeBeginPeriodRetValue = &timeBeginPeriodRetValue
+)
 
 func NumberOfProcessors() int32 {
 	var info systeminfo
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 2c98482..441dcd9 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -82,6 +82,21 @@ It is a comma-separated list of name=val pairs setting these named variables:
 	If the line ends with "(forced)", this GC was forced by a
 	runtime.GC() call and all phases are STW.
 
+	Setting gctrace to any value > 0 also causes the garbage collector
+	to emit a summary when memory is released back to the system.
+	This process of returning memory to the system is called scavenging.
+	The format of this summary is subject to change.
+	Currently it is:
+		scvg#: # MB released  printed only if non-zero
+		scvg#: inuse: # idle: # sys: # released: # consumed: # (MB)
+	where the fields are as follows:
+		scvg#        the scavenge cycle number, incremented at each scavenge
+		inuse: #     MB used or partially used spans
+		idle: #      MB spans pending scavenging
+		sys: #       MB mapped from the system
+		released: #  MB released to the system
+		consumed: #  MB allocated from the system
+
 	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.
@@ -147,11 +162,11 @@ package runtime
 import "runtime/internal/sys"
 
 // Caller reports file and line number information about function invocations on
-// the calling goroutine's stack.  The argument skip is the number of stack frames
+// the calling goroutine's stack. The argument skip is the number of stack frames
 // to ascend, with 0 identifying the caller of Caller.  (For historical reasons the
 // meaning of skip differs between Caller and Callers.) The return values report the
 // program counter, file name, and line number within the file of the corresponding
-// call.  The boolean ok is false if it was not possible to recover the information.
+// call. The boolean ok is false if it was not possible to recover the information.
 func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
 	// Ask for two PCs: the one we were asked for
 	// and what it called, so that we can see if it
@@ -184,22 +199,19 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
 }
 
 // Callers fills the slice pc with the return program counters of function invocations
-// on the calling goroutine's stack.  The argument skip is the number of stack frames
+// on the calling goroutine's stack. The argument skip is the number of stack frames
 // to skip before recording in pc, with 0 identifying the frame for Callers itself and
 // 1 identifying the caller of Callers.
 // It returns the number of entries written to pc.
 //
 // Note that since each slice entry pc[i] is a return program counter,
 // looking up the file and line for pc[i] (for example, using (*Func).FileLine)
-// will return the file and line number of the instruction immediately
+// will normally return the file and line number of the instruction immediately
 // following the call.
-// To look up the file and line number of the call itself, use pc[i]-1.
-// As an exception to this rule, if pc[i-1] corresponds to the function
-// runtime.sigpanic, then pc[i] is the program counter of a faulting
-// instruction and should be used without any subtraction.
+// To easily look up file/line information for the call sequence, use Frames.
 func Callers(skip int, pc []uintptr) int {
 	// runtime.callers uses pc.array==nil as a signal
-	// to print a stack trace.  Pick off 0-length pc here
+	// to print a stack trace. Pick off 0-length pc here
 	// so that we don't let a nil pc slice get to it.
 	if len(pc) == 0 {
 		return 0
@@ -227,8 +239,8 @@ func Version() string {
 
 // GOOS is the running program's operating system target:
 // one of darwin, freebsd, linux, and so on.
-const GOOS string = sys.TheGoos
+const GOOS string = sys.GOOS
 
 // GOARCH is the running program's architecture target:
-// 386, amd64, or arm.
-const GOARCH string = sys.TheGoarch
+// 386, amd64, arm, or s390x.
+const GOARCH string = sys.GOARCH
diff --git a/src/runtime/fastlog2_test.go b/src/runtime/fastlog2_test.go
index 14f6c90..ae0f40b 100644
--- a/src/runtime/fastlog2_test.go
+++ b/src/runtime/fastlog2_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/funcdata.h b/src/runtime/funcdata.h
index 375a881..82992e2 100644
--- a/src/runtime/funcdata.h
+++ b/src/runtime/funcdata.h
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -36,7 +36,7 @@
 // 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.
-#define GO_RESULTS_INITIALIZED	FUNCDATA PCDATA $PCDATA_StackMapIndex, 1
+#define GO_RESULTS_INITIALIZED	PCDATA $PCDATA_StackMapIndex, $1
 
 // NO_LOCAL_POINTERS indicates that the assembly function stores
 // no pointers to heap objects in its local stack variables.
diff --git a/src/runtime/futex_test.go b/src/runtime/futex_test.go
index 8504396..0738f8f 100644
--- a/src/runtime/futex_test.go
+++ b/src/runtime/futex_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go
index edb6361..011f005 100644
--- a/src/runtime/gcinfo_test.go
+++ b/src/runtime/gcinfo_test.go
@@ -59,14 +59,14 @@ func TestGCInfo(t *testing.T) {
 
 func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
 	mask := runtime.GCMask(p)
-	if bytes.Compare(mask, mask0) != 0 {
+	if !bytes.Equal(mask, mask0) {
 		t.Errorf("bad GC program for %v:\nwant %+v\ngot  %+v", name, mask0, mask)
 		return
 	}
 }
 
 func padDead(mask []byte) []byte {
-	// Because the dead bit isn't encoded until the third word,
+	// Because the dead bit isn't encoded in the second 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
@@ -81,6 +81,9 @@ func trimDead(mask []byte) []byte {
 	for len(mask) > 2 && mask[len(mask)-1] == typeScalar {
 		mask = mask[:len(mask)-1]
 	}
+	if len(mask) == 2 && mask[0] == typeScalar && mask[1] == typeScalar {
+		mask = mask[:0]
+	}
 	return mask
 }
 
@@ -144,7 +147,7 @@ func infoBigStruct() []byte {
 			typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
 			typePointer, typeScalar, // i string
 		}
-	case "arm64", "amd64", "mips64", "mips64le", "ppc64", "ppc64le":
+	case "arm64", "amd64", "mips64", "mips64le", "ppc64", "ppc64le", "s390x":
 		return []byte{
 			typePointer,                        // q *int
 			typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
diff --git a/src/runtime/go_tls.h b/src/runtime/go_tls.h
index 6a707cf..61f7dbe 100644
--- a/src/runtime/go_tls.h
+++ b/src/runtime/go_tls.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/hash64.go b/src/runtime/hash64.go
index fb3dba4..d61f114 100644
--- a/src/runtime/hash64.go
+++ b/src/runtime/hash64.go
@@ -6,7 +6,7 @@
 //   xxhash: https://code.google.com/p/xxhash/
 // cityhash: https://code.google.com/p/cityhash/
 
-// +build amd64 amd64p32 arm64 mips64 mips64le ppc64 ppc64le
+// +build amd64 amd64p32 arm64 mips64 mips64le ppc64 ppc64le s390x
 
 package runtime
 
diff --git a/src/runtime/hash_test.go b/src/runtime/hash_test.go
index 1651485..3108b3b 100644
--- a/src/runtime/hash_test.go
+++ b/src/runtime/hash_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -11,13 +11,14 @@ import (
 	. "runtime"
 	"strings"
 	"testing"
+	"unsafe"
 )
 
 // Smhasher is a torture test for hash functions.
 // https://code.google.com/p/smhasher/
 // This code is a port of some of the Smhasher tests to Go.
 //
-// The current AES hash function passes Smhasher.  Our fallback
+// The current AES hash function passes Smhasher. Our fallback
 // hash functions don't, so we only enable the difficult tests when
 // we know the AES implementation is available.
 
@@ -349,7 +350,7 @@ func (k *EfaceKey) random(r *rand.Rand) {
 	k.i = uint64(r.Int63())
 }
 func (k *EfaceKey) bits() int {
-	// use 64 bits.  This tests inlined interfaces
+	// use 64 bits. This tests inlined interfaces
 	// on 64-bit targets and indirect interfaces on
 	// 32-bit targets.
 	return 64
@@ -381,7 +382,7 @@ func (k *IfaceKey) random(r *rand.Rand) {
 	k.i = fInter(r.Int63())
 }
 func (k *IfaceKey) bits() int {
-	// use 64 bits.  This tests inlined interfaces
+	// use 64 bits. This tests inlined interfaces
 	// on 64-bit targets and indirect interfaces on
 	// 32-bit targets.
 	return 64
@@ -443,7 +444,7 @@ func avalancheTest1(t *testing.T, k Key) {
 
 	// Each entry in the grid should be about REP/2.
 	// More precisely, we did N = k.bits() * hashSize experiments where
-	// each is the sum of REP coin flips.  We want to find bounds on the
+	// each is the sum of REP coin flips. We want to find bounds on the
 	// sum of coin flips such that a truly random experiment would have
 	// all sums inside those bounds with 99% probability.
 	N := n * hashSize
@@ -563,19 +564,19 @@ func BenchmarkHash1024(b *testing.B)  { benchmarkHash(b, 1024) }
 func BenchmarkHash65536(b *testing.B) { benchmarkHash(b, 65536) }
 
 func TestArrayHash(t *testing.T) {
-	// Make sure that "" in arrays hash correctly.  The hash
+	// Make sure that "" in arrays hash correctly. The hash
 	// should at least scramble the input seed so that, e.g.,
 	// {"","foo"} and {"foo",""} have different hashes.
 
 	// If the hash is bad, then all (8 choose 4) = 70 keys
 	// have the same hash. If so, we allocate 70/8 = 8
-	// overflow buckets.  If the hash is good we don't
+	// overflow buckets. If the hash is good we don't
 	// normally allocate any overflow buckets, and the
 	// probability of even one or two overflows goes down rapidly.
-	// (There is always 1 allocation of the bucket array.  The map
+	// (There is always 1 allocation of the bucket array. The map
 	// header is allocated on the stack.)
 	f := func() {
-		// Make the key type at most 128 bytes.  Otherwise,
+		// Make the key type at most 128 bytes. Otherwise,
 		// we get an allocation per key.
 		type key [8]string
 		m := make(map[key]bool, 70)
@@ -658,3 +659,45 @@ func TestStructHash(t *testing.T) {
 		t.Errorf("too many allocs %f - hash not balanced", n)
 	}
 }
+
+var sink uint64
+
+func BenchmarkAlignedLoad(b *testing.B) {
+	var buf [16]byte
+	p := unsafe.Pointer(&buf[0])
+	var s uint64
+	for i := 0; i < b.N; i++ {
+		s += ReadUnaligned64(p)
+	}
+	sink = s
+}
+
+func BenchmarkUnalignedLoad(b *testing.B) {
+	var buf [16]byte
+	p := unsafe.Pointer(&buf[1])
+	var s uint64
+	for i := 0; i < b.N; i++ {
+		s += ReadUnaligned64(p)
+	}
+	sink = s
+}
+
+func TestCollisions(t *testing.T) {
+	for i := 0; i < 16; i++ {
+		for j := 0; j < 16; j++ {
+			if j == i {
+				continue
+			}
+			var a [16]byte
+			m := make(map[uint16]struct{}, 1<<16)
+			for n := 0; n < 1<<16; n++ {
+				a[i] = byte(n)
+				a[j] = byte(n >> 8)
+				m[uint16(BytesHash(a[:], 0))] = struct{}{}
+			}
+			if len(m) <= 1<<15 {
+				t.Errorf("too many collisions i=%d j=%d outputs=%d out of 65536\n", i, j, len(m))
+			}
+		}
+	}
+}
diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go
index 892a79a..509cab2 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -6,10 +6,10 @@ package runtime
 
 // This file contains the implementation of Go's map type.
 //
-// A map is just a hash table.  The data is arranged
-// into an array of buckets.  Each bucket contains up to
-// 8 key/value pairs.  The low-order bits of the hash are
-// used to select a bucket.  Each bucket contains a few
+// A map is just a hash table. The data is arranged
+// into an array of buckets. Each bucket contains up to
+// 8 key/value pairs. The low-order bits of the hash are
+// used to select a bucket. Each bucket contains a few
 // high-order bits of each hash to distinguish the entries
 // within a single bucket.
 //
@@ -17,7 +17,7 @@ package runtime
 // extra buckets.
 //
 // When the hashtable grows, we allocate a new array
-// of buckets twice as big.  Buckets are incrementally
+// of buckets twice as big. Buckets are incrementally
 // copied from the old bucket array to the new bucket array.
 //
 // Map iterators walk through the array of buckets and
@@ -31,7 +31,7 @@ package runtime
 // to the new table.
 
 // Picking loadFactor: too large and we have lots of overflow
-// buckets, too small and we waste a lot of space.  I wrote
+// buckets, too small and we waste a lot of space. I wrote
 // a simple program to check some stats for different loads:
 // (64-bit, 8 byte keys and values)
 //  loadFactor    %overflow  bytes/entry     hitprobe    missprobe
@@ -51,7 +51,7 @@ package runtime
 // missprobe   = # of entries to check when looking up an absent key
 //
 // Keep in mind this data is for maximally loaded tables, i.e. just
-// before the table grows.  Typical tables will be somewhat less loaded.
+// before the table grows. Typical tables will be somewhat less loaded.
 
 import (
 	"runtime/internal/atomic"
@@ -75,14 +75,14 @@ const (
 	maxValueSize = 128
 
 	// data offset should be the size of the bmap struct, but needs to be
-	// aligned correctly.  For amd64p32 this means 64-bit alignment
+	// aligned correctly. For amd64p32 this means 64-bit alignment
 	// even though pointers are 32 bit.
 	dataOffset = unsafe.Offsetof(struct {
 		b bmap
 		v int64
 	}{}.v)
 
-	// Possible tophash values.  We reserve a few possibilities for special marks.
+	// Possible tophash values. We reserve a few possibilities for special marks.
 	// Each bucket (including its overflow buckets, if any) will have either all or none of its
 	// entries in the evacuated* states (except during the evacuate() method, which only happens
 	// during map writes and thus no one else can observe the map during that time).
@@ -104,7 +104,7 @@ const (
 // A header for a Go map.
 type hmap struct {
 	// 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!
+	// ../reflect/type.go. Don't change this structure without also changing that code!
 	count int // # live cells == size of map.  Must be first (used by len() builtin)
 	flags uint8
 	B     uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
@@ -188,13 +188,13 @@ func (h *hmap) createOverflow() {
 // 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) {
+	if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != t.hmap.size {
 		println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size)
 		throw("bad hmap size")
 	}
 
 	if hint < 0 || int64(int32(hint)) != hint {
-		panic("makemap: size out of range")
+		panic(plainError("makemap: size out of range"))
 		// TODO: make hint an int, then none of this nonsense
 	}
 
@@ -212,7 +212,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 		throw("value size wrong")
 	}
 
-	// invariants we depend on.  We should probably check these at compile time
+	// 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 {
 		throw("key align too big")
@@ -220,10 +220,10 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 	if t.elem.align > bucketCnt {
 		throw("value align too big")
 	}
-	if uintptr(t.key.size)%uintptr(t.key.align) != 0 {
+	if t.key.size%uintptr(t.key.align) != 0 {
 		throw("key size not a multiple of key align")
 	}
-	if uintptr(t.elem.size)%uintptr(t.elem.align) != 0 {
+	if t.elem.size%uintptr(t.elem.align) != 0 {
 		throw("value size not a multiple of value align")
 	}
 	if bucketCnt < 8 {
@@ -236,9 +236,6 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 		throw("need padding in bucket (value)")
 	}
 
-	// make sure zeroptr is large enough
-	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++ {
@@ -249,7 +246,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 	// If hint is large zeroing this memory could take a while.
 	buckets := bucket
 	if B != 0 {
-		buckets = newarray(t.bucket, uintptr(1)<<B)
+		buckets = newarray(t.bucket, 1<<B)
 	}
 
 	// initialize Hmap
@@ -283,7 +280,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 		msanread(key, t.key.size)
 	}
 	if h == nil || h.count == 0 {
-		return atomic.Loadp(unsafe.Pointer(&zeroptr))
+		return unsafe.Pointer(&zeroVal[0])
 	}
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map read and map write")
@@ -321,7 +318,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 		}
 		b = b.overflow(t)
 		if b == nil {
-			return atomic.Loadp(unsafe.Pointer(&zeroptr))
+			return unsafe.Pointer(&zeroVal[0])
 		}
 	}
 }
@@ -337,7 +334,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
 		msanread(key, t.key.size)
 	}
 	if h == nil || h.count == 0 {
-		return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+		return unsafe.Pointer(&zeroVal[0]), false
 	}
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map read and map write")
@@ -375,12 +372,12 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
 		}
 		b = b.overflow(t)
 		if b == nil {
-			return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+			return unsafe.Pointer(&zeroVal[0]), false
 		}
 	}
 }
 
-// returns both key and value.  Used by map iterator
+// returns both key and value. Used by map iterator
 func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe.Pointer) {
 	if h == nil || h.count == 0 {
 		return nil, nil
@@ -426,9 +423,25 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
 	}
 }
 
+func mapaccess1_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) unsafe.Pointer {
+	v := mapaccess1(t, h, key)
+	if v == unsafe.Pointer(&zeroVal[0]) {
+		return zero
+	}
+	return v
+}
+
+func mapaccess2_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) (unsafe.Pointer, bool) {
+	v := mapaccess1(t, h, key)
+	if v == unsafe.Pointer(&zeroVal[0]) {
+		return zero, false
+	}
+	return v, true
+}
+
 func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
 	if h == nil {
-		panic("assignment to entry in nil map")
+		panic(plainError("assignment to entry in nil map"))
 	}
 	if raceenabled {
 		callerpc := getcallerpc(unsafe.Pointer(&t))
@@ -485,7 +498,7 @@ again:
 			if !alg.equal(key, k2) {
 				continue
 			}
-			// already have a mapping for key.  Update it.
+			// already have a mapping for key. Update it.
 			if t.needkeyupdate {
 				typedmemmove(t.key, k2, key)
 			}
@@ -504,7 +517,7 @@ again:
 		b = ovf
 	}
 
-	// did not find mapping for key.  Allocate new cell & add entry.
+	// did not find mapping for key. Allocate new cell & add entry.
 	if float32(h.count) >= loadFactor*float32((uintptr(1)<<h.B)) && h.count >= bucketCnt {
 		hashGrow(t, h)
 		goto again // Growing the table invalidates everything, so try again
@@ -718,9 +731,9 @@ next:
 		if b.tophash[offi] != empty && b.tophash[offi] != evacuatedEmpty {
 			if checkBucket != noCheck {
 				// Special case: iterator was started during a grow and the
-				// grow is not done yet.  We're working on a bucket whose
-				// oldbucket has not been evacuated yet.  Or at least, it wasn't
-				// evacuated when we started the bucket.  So we're iterating
+				// grow is not done yet. We're working on a bucket whose
+				// oldbucket has not been evacuated yet. Or at least, it wasn't
+				// evacuated when we started the bucket. So we're iterating
 				// through the oldbucket, skipping any keys that will go
 				// to the other new bucket (each oldbucket expands to two
 				// buckets during a grow).
@@ -738,7 +751,7 @@ next:
 				} else {
 					// Hash isn't repeatable if k != k (NaNs).  We need a
 					// repeatable and randomish choice of which direction
-					// to send NaNs during evacuation.  We'll use the low
+					// to send NaNs during evacuation. We'll use the low
 					// bit of tophash to decide which way NaNs go.
 					// NOTE: this case is why we need two evacuate tophash
 					// values, evacuatedX and evacuatedY, that differ in
@@ -779,7 +792,7 @@ next:
 					it.value = rv
 				} else {
 					// if key!=key then the entry can't be deleted or
-					// updated, so we can just return it.  That's lucky for
+					// updated, so we can just return it. That's lucky for
 					// us because when key!=key we can't look it up
 					// successfully in the current table.
 					it.key = k2
@@ -790,7 +803,9 @@ next:
 				}
 			}
 			it.bucket = bucket
-			it.bptr = b
+			if it.bptr != b { // avoid unnecessary write barrier; see issue 14921
+				it.bptr = b
+			}
 			it.i = i + 1
 			it.checkBucket = checkBucket
 			return
@@ -806,7 +821,7 @@ func hashGrow(t *maptype, h *hmap) {
 		throw("evacuation not done in time")
 	}
 	oldbuckets := h.buckets
-	newbuckets := newarray(t.bucket, uintptr(1)<<(h.B+1))
+	newbuckets := newarray(t.bucket, 1<<(h.B+1))
 	flags := h.flags &^ (iterator | oldIterator)
 	if h.flags&iterator != 0 {
 		flags |= oldIterator
@@ -882,12 +897,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 				if h.flags&iterator != 0 {
 					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
+						// will be) entirely different from the old hash. Moreover,
+						// it isn't reproducible. Reproducibility is required in the
 						// presence of iterators, as our evacuation decision must
 						// match whatever decision the iterator made.
 						// Fortunately, we have the freedom to send these keys either
-						// way.  Also, tophash is meaningless for these kinds of keys.
+						// way. Also, tophash is meaningless for these kinds of keys.
 						// We let the low bit of tophash drive the evacuation decision.
 						// We recompute a new random tophash for the next level so
 						// these keys will get evenly distributed across all buckets
@@ -965,7 +980,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 	if oldbucket == h.nevacuate {
 		h.nevacuate = oldbucket + 1
 		if oldbucket+1 == newbit { // newbit == # of oldbuckets
-			// Growing is all done.  Free old main bucket array.
+			// 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,
@@ -981,7 +996,7 @@ func ismapkey(t *_type) bool {
 	return t.alg.hash != nil
 }
 
-// Reflect stubs.  Called from ../reflect/asm_*.s
+// Reflect stubs. Called from ../reflect/asm_*.s
 
 //go:linkname reflect_makemap reflect.makemap
 func reflect_makemap(t *maptype) *hmap {
@@ -1042,39 +1057,5 @@ func reflect_ismapkey(t *_type) bool {
 	return ismapkey(t)
 }
 
-var zerolock mutex
-
-const initialZeroSize = 1024
-
-var zeroinitial [initialZeroSize]byte
-
-// All accesses to zeroptr and zerosize must be atomic so that they
-// can be accessed without locks in the common case.
-var zeroptr unsafe.Pointer = unsafe.Pointer(&zeroinitial)
-var zerosize uintptr = initialZeroSize
-
-// mapzero ensures that zeroptr points to a buffer large enough to
-// serve as the zero value for t.
-func mapzero(t *_type) {
-	// Is the type small enough for existing buffer?
-	cursize := uintptr(atomic.Loadp(unsafe.Pointer(&zerosize)))
-	if t.size <= cursize {
-		return
-	}
-
-	// Allocate a new buffer.
-	lock(&zerolock)
-	cursize = uintptr(atomic.Loadp(unsafe.Pointer(&zerosize)))
-	if cursize < t.size {
-		for cursize < t.size {
-			cursize *= 2
-			if cursize == 0 {
-				// need >2GB zero on 32-bit machine
-				throw("map element too large")
-			}
-		}
-		atomic.Storep1(unsafe.Pointer(&zeroptr), persistentalloc(cursize, 64, &memstats.other_sys))
-		atomic.Storep1(unsafe.Pointer(&zerosize), unsafe.Pointer(zerosize))
-	}
-	unlock(&zerolock)
-}
+const maxZero = 1024 // must match value in ../cmd/compile/internal/gc/walk.go
+var zeroVal [maxZero]byte
diff --git a/src/runtime/hashmap_fast.go b/src/runtime/hashmap_fast.go
index 519dc77..8f9bb5a 100644
--- a/src/runtime/hashmap_fast.go
+++ b/src/runtime/hashmap_fast.go
@@ -5,7 +5,6 @@
 package runtime
 
 import (
-	"runtime/internal/atomic"
 	"runtime/internal/sys"
 	"unsafe"
 )
@@ -16,14 +15,14 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
 		racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast32))
 	}
 	if h == nil || h.count == 0 {
-		return atomic.Loadp(unsafe.Pointer(&zeroptr))
+		return unsafe.Pointer(&zeroVal[0])
 	}
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map read and map write")
 	}
 	var b *bmap
 	if h.B == 0 {
-		// One-bucket table.  No need to hash.
+		// One-bucket table. No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
 		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
@@ -50,7 +49,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
 		}
 		b = b.overflow(t)
 		if b == nil {
-			return atomic.Loadp(unsafe.Pointer(&zeroptr))
+			return unsafe.Pointer(&zeroVal[0])
 		}
 	}
 }
@@ -61,14 +60,14 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
 		racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast32))
 	}
 	if h == nil || h.count == 0 {
-		return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+		return unsafe.Pointer(&zeroVal[0]), false
 	}
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map read and map write")
 	}
 	var b *bmap
 	if h.B == 0 {
-		// One-bucket table.  No need to hash.
+		// One-bucket table. No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
 		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
@@ -95,7 +94,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
 		}
 		b = b.overflow(t)
 		if b == nil {
-			return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+			return unsafe.Pointer(&zeroVal[0]), false
 		}
 	}
 }
@@ -106,14 +105,14 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
 		racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast64))
 	}
 	if h == nil || h.count == 0 {
-		return atomic.Loadp(unsafe.Pointer(&zeroptr))
+		return unsafe.Pointer(&zeroVal[0])
 	}
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map read and map write")
 	}
 	var b *bmap
 	if h.B == 0 {
-		// One-bucket table.  No need to hash.
+		// One-bucket table. No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
 		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
@@ -140,7 +139,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
 		}
 		b = b.overflow(t)
 		if b == nil {
-			return atomic.Loadp(unsafe.Pointer(&zeroptr))
+			return unsafe.Pointer(&zeroVal[0])
 		}
 	}
 }
@@ -151,14 +150,14 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
 		racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast64))
 	}
 	if h == nil || h.count == 0 {
-		return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+		return unsafe.Pointer(&zeroVal[0]), false
 	}
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map read and map write")
 	}
 	var b *bmap
 	if h.B == 0 {
-		// One-bucket table.  No need to hash.
+		// One-bucket table. No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
 		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
@@ -185,7 +184,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
 		}
 		b = b.overflow(t)
 		if b == nil {
-			return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+			return unsafe.Pointer(&zeroVal[0]), false
 		}
 	}
 }
@@ -196,7 +195,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
 		racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_faststr))
 	}
 	if h == nil || h.count == 0 {
-		return atomic.Loadp(unsafe.Pointer(&zeroptr))
+		return unsafe.Pointer(&zeroVal[0])
 	}
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map read and map write")
@@ -216,11 +215,11 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
 				if k.len != key.len {
 					continue
 				}
-				if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) {
+				if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
 					return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
 				}
 			}
-			return atomic.Loadp(unsafe.Pointer(&zeroptr))
+			return unsafe.Pointer(&zeroVal[0])
 		}
 		// long key, try not to do more comparisons than necessary
 		keymaybe := uintptr(bucketCnt)
@@ -247,18 +246,18 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
 				continue
 			}
 			if keymaybe != bucketCnt {
-				// Two keys are potential matches.  Use hash to distinguish them.
+				// Two keys are potential matches. Use hash to distinguish them.
 				goto dohash
 			}
 			keymaybe = i
 		}
 		if keymaybe != bucketCnt {
 			k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize))
-			if memeq(k.str, key.str, uintptr(key.len)) {
+			if memequal(k.str, key.str, uintptr(key.len)) {
 				return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize))
 			}
 		}
-		return atomic.Loadp(unsafe.Pointer(&zeroptr))
+		return unsafe.Pointer(&zeroVal[0])
 	}
 dohash:
 	hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
@@ -284,13 +283,13 @@ dohash:
 			if k.len != key.len {
 				continue
 			}
-			if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) {
+			if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
 				return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
 			}
 		}
 		b = b.overflow(t)
 		if b == nil {
-			return atomic.Loadp(unsafe.Pointer(&zeroptr))
+			return unsafe.Pointer(&zeroVal[0])
 		}
 	}
 }
@@ -301,7 +300,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
 		racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_faststr))
 	}
 	if h == nil || h.count == 0 {
-		return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+		return unsafe.Pointer(&zeroVal[0]), false
 	}
 	if h.flags&hashWriting != 0 {
 		throw("concurrent map read and map write")
@@ -321,11 +320,11 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
 				if k.len != key.len {
 					continue
 				}
-				if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) {
+				if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
 					return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
 				}
 			}
-			return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+			return unsafe.Pointer(&zeroVal[0]), false
 		}
 		// long key, try not to do more comparisons than necessary
 		keymaybe := uintptr(bucketCnt)
@@ -350,18 +349,18 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
 				continue
 			}
 			if keymaybe != bucketCnt {
-				// Two keys are potential matches.  Use hash to distinguish them.
+				// Two keys are potential matches. Use hash to distinguish them.
 				goto dohash
 			}
 			keymaybe = i
 		}
 		if keymaybe != bucketCnt {
 			k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*sys.PtrSize))
-			if memeq(k.str, key.str, uintptr(key.len)) {
+			if memequal(k.str, key.str, uintptr(key.len)) {
 				return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+keymaybe*uintptr(t.valuesize)), true
 			}
 		}
-		return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+		return unsafe.Pointer(&zeroVal[0]), false
 	}
 dohash:
 	hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
@@ -387,13 +386,13 @@ dohash:
 			if k.len != key.len {
 				continue
 			}
-			if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) {
+			if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) {
 				return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize)), true
 			}
 		}
 		b = b.overflow(t)
 		if b == nil {
-			return atomic.Loadp(unsafe.Pointer(&zeroptr)), false
+			return unsafe.Pointer(&zeroVal[0]), false
 		}
 	}
 }
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
index 4d1da1c..c317b5f 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -2,12 +2,12 @@
 // 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
+// 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.
+// https://golang.org/s/go15heapdump.
 
 package runtime
 
@@ -97,7 +97,7 @@ func flush() {
 // 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.
+// serializing a type more than once. That's ok.
 const (
 	typeCacheBuckets = 256
 	typeCacheAssoc   = 4
@@ -172,7 +172,7 @@ func dumptype(t *_type) {
 		}
 	}
 
-	// Might not have been dumped yet.  Dump it and
+	// 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]
@@ -183,11 +183,13 @@ func dumptype(t *_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)
+	if x := t.uncommon(); x == nil || t.nameOff(x.pkgpath).name() == "" {
+		dumpstr(t.string())
 	} else {
-		pkgpath := stringStructOf(t.x.pkgpath)
-		name := stringStructOf(t.x.name)
+		pkgpathstr := t.nameOff(x.pkgpath).name()
+		pkgpath := stringStructOf(&pkgpathstr)
+		namestr := t.name()
+		name := stringStructOf(&namestr)
 		dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
 		dwrite(pkgpath.str, uintptr(pkgpath.len))
 		dwritebyte('.')
@@ -233,7 +235,7 @@ type childInfo struct {
 // 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++ {
+	for i := uintptr(0); i < bv.n; i++ {
 		if bv.bytedata[i/8]>>(i%8)&1 == 1 {
 			dumpint(fieldKindPtr)
 			dumpint(uint64(offset + i*sys.PtrSize))
@@ -253,7 +255,7 @@ func dumpframe(s *stkframe, arg unsafe.Pointer) bool {
 	pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, pc, nil)
 	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
+		// stackmap for this function. It is likely that we are looking
 		// at the function prologue, assume so and hope for the best.
 		pcdata = 0
 	}
@@ -445,7 +447,7 @@ func dumproots() {
 					continue
 				}
 				spf := (*specialfinalizer)(unsafe.Pointer(sp))
-				p := unsafe.Pointer((uintptr(s.start) << _PageShift) + uintptr(spf.special.offset))
+				p := unsafe.Pointer(s.base() + uintptr(spf.special.offset))
 				dumpfinalizer(p, spf.fn, spf.fint, spf.ot)
 			}
 		}
@@ -465,15 +467,19 @@ func dumpobjs() {
 		if s.state != _MSpanInUse {
 			continue
 		}
-		p := uintptr(s.start << _PageShift)
+		p := s.base()
 		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 freeIndex := s.freeindex; freeIndex < s.nelems; freeIndex++ {
+			if s.isFree(freeIndex) {
+				freemark[freeIndex] = true
+			}
 		}
+
 		for j := uintptr(0); j < n; j, p = j+1, p+size {
 			if freemark[j] {
 				freemark[j] = false
@@ -495,35 +501,17 @@ func dumpparams() {
 	dumpint(sys.PtrSize)
 	dumpint(uint64(mheap_.arena_start))
 	dumpint(uint64(mheap_.arena_used))
-	dumpint(sys.TheChar)
+	dumpstr(sys.GOARCH)
 	dumpstr(sys.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))))
-	}
+	dumptype(t)
+	dumpint(tagItab)
+	dumpint(uint64(uintptr(unsafe.Pointer(tab))))
+	dumpint(uint64(uintptr(unsafe.Pointer(t))))
 }
 
 func dumpitabs() {
@@ -631,7 +619,7 @@ func dumpmemprof() {
 				continue
 			}
 			spp := (*specialprofile)(unsafe.Pointer(sp))
-			p := uintptr(s.start<<_PageShift) + uintptr(spp.special.offset)
+			p := s.base() + uintptr(spp.special.offset)
 			dumpint(tagAllocSample)
 			dumpint(uint64(p))
 			dumpint(uint64(uintptr(unsafe.Pointer(spp.b))))
@@ -639,7 +627,7 @@ func dumpmemprof() {
 	}
 }
 
-var dumphdr = []byte("go1.6 heap dump\n")
+var dumphdr = []byte("go1.7 heap dump\n")
 
 func mdump() {
 	// make sure we're done sweeping
@@ -696,8 +684,8 @@ func dumpfields(bv bitvector) {
 }
 
 // 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.
+// 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
@@ -726,7 +714,7 @@ func makeheapobjbv(p uintptr, size uintptr) bitvector {
 	i := uintptr(0)
 	hbits := heapBitsForAddr(p)
 	for ; i < nptr; i++ {
-		if i >= 2 && !hbits.isMarked() {
+		if i != 1 && !hbits.morePointers() {
 			break // end of object
 		}
 		if hbits.isPointer() {
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 71dc865..1690147 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -19,25 +19,29 @@ var (
 	hash      [hashSize]*itab
 )
 
+func itabhash(inter *interfacetype, typ *_type) uint32 {
+	// compiler has provided some good hash codes for us.
+	h := inter.typ.hash
+	h += 17 * typ.hash
+	// TODO(rsc): h += 23 * x.mhash ?
+	return h % hashSize
+}
+
 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 	if len(inter.mhdr) == 0 {
 		throw("internal error - misuse of itab")
 	}
 
 	// easy case
-	x := typ.x
-	if x == nil {
+	if typ.tflag&tflagUncommon == 0 {
 		if canfail {
 			return nil
 		}
-		panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *inter.mhdr[0].name})
+		name := inter.typ.nameOff(inter.mhdr[0].name)
+		panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), name.name()})
 	}
 
-	// compiler has provided some good hash codes for us.
-	h := inter.typ.hash
-	h += 17 * typ.hash
-	// TODO(rsc): h += 23 * x.mhash ?
-	h %= hashSize
+	h := itabhash(inter, typ)
 
 	// look twice - once without lock, once with.
 	// common case will be no lock contention.
@@ -50,17 +54,16 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 		for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
 			if m.inter == inter && m._type == typ {
 				if m.bad != 0 {
-					m = nil
 					if !canfail {
 						// this can only happen if the conversion
 						// was already done once using the , ok form
 						// and we have a cached negative result.
 						// the cached result doesn't record which
-						// interface function was missing, so jump
-						// down to the interface check, which will
-						// do more work but give a better error.
-						goto search
+						// interface function was missing, so try
+						// adding the itab again, which will throw an error.
+						additab(m, locked != 0, false)
 					}
+					m = nil
 				}
 				if locked != 0 {
 					unlock(&ifaceLock)
@@ -73,56 +76,80 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 	m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys))
 	m.inter = inter
 	m._type = typ
+	additab(m, true, canfail)
+	unlock(&ifaceLock)
+	if m.bad != 0 {
+		return nil
+	}
+	return m
+}
+
+func additab(m *itab, locked, canfail bool) {
+	inter := m.inter
+	typ := m._type
+	x := typ.uncommon()
 
-search:
 	// both inter and typ have method sorted by name,
 	// and interface names are unique,
 	// so can iterate over both in lock step;
 	// the loop is O(ni+nt) not O(ni*nt).
 	ni := len(inter.mhdr)
-	nt := len(x.mhdr)
+	nt := int(x.mcount)
+	xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt]
 	j := 0
 	for k := 0; k < ni; k++ {
 		i := &inter.mhdr[k]
-		iname := i.name
-		ipkgpath := i.pkgpath
-		itype := i._type
+		itype := inter.typ.typeOff(i.ityp)
+		name := inter.typ.nameOff(i.name)
+		iname := name.name()
+		ipkg := name.pkgPath()
+		if ipkg == "" {
+			ipkg = inter.pkgpath.name()
+		}
 		for ; j < nt; j++ {
-			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.fun[0]), uintptr(k)*sys.PtrSize)) = t.ifn
+			t := &xmhdr[j]
+			tname := typ.nameOff(t.name)
+			if typ.typeOff(t.mtyp) == itype && tname.name() == iname {
+				pkgPath := tname.pkgPath()
+				if pkgPath == "" {
+					pkgPath = typ.nameOff(x.pkgpath).name()
+				}
+				if tname.isExported() || pkgPath == ipkg {
+					if m != nil {
+						ifn := typ.textOff(t.ifn)
+						*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn
+					}
+					goto nextimethod
 				}
-				goto nextimethod
 			}
 		}
 		// didn't find method
 		if !canfail {
-			if locked != 0 {
+			if locked {
 				unlock(&ifaceLock)
 			}
-			panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *iname})
+			panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname})
 		}
 		m.bad = 1
 		break
 	nextimethod:
 	}
-	if locked == 0 {
+	if !locked {
 		throw("invalid itab locking")
 	}
+	h := itabhash(inter, typ)
 	m.link = hash[h]
 	atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
-	unlock(&ifaceLock)
-	if m.bad != 0 {
-		return nil
-	}
-	return m
 }
 
-func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
-	tab := getitab(inter, t, false)
-	atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
-	return tab
+func itabsinit() {
+	lock(&ifaceLock)
+	for m := &firstmoduledata; m != nil; m = m.next {
+		for _, i := range m.itablinks {
+			additab(i, true, false)
+		}
+	}
+	unlock(&ifaceLock)
 }
 
 func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
@@ -133,62 +160,54 @@ func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
 		msanread(elem, t.size)
 	}
 	if isDirectIface(t) {
-		e._type = t
-		typedmemmove(t, unsafe.Pointer(&e.data), elem)
-	} else {
-		if x == nil {
-			x = newobject(t)
-		}
+		throw("direct convT2E")
+	}
+	if x == nil {
+		x = newobject(t)
 		// TODO: We allocate a zeroed object only to overwrite it with
-		// actual data.  Figure out how to avoid zeroing.  Also below in convT2I.
-		typedmemmove(t, x, elem)
-		e._type = t
-		e.data = x
+		// actual data. Figure out how to avoid zeroing. Also below in convT2I.
 	}
+	typedmemmove(t, x, elem)
+	e._type = t
+	e.data = x
 	return
 }
 
-func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
+func convT2I(tab *itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
+	t := tab._type
 	if raceenabled {
-		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2I))
+		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I))
 	}
 	if msanenabled {
 		msanread(elem, t.size)
 	}
-	tab := (*itab)(atomic.Loadp(unsafe.Pointer(cache)))
-	if tab == nil {
-		tab = getitab(inter, t, false)
-		atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
-	}
 	if isDirectIface(t) {
-		i.tab = tab
-		typedmemmove(t, unsafe.Pointer(&i.data), elem)
-	} else {
-		if x == nil {
-			x = newobject(t)
-		}
-		typedmemmove(t, x, elem)
-		i.tab = tab
-		i.data = x
+		throw("direct convT2I")
 	}
+	if x == nil {
+		x = newobject(t)
+	}
+	typedmemmove(t, x, elem)
+	i.tab = tab
+	i.data = x
 	return
 }
 
 func panicdottype(have, want, iface *_type) {
 	haveString := ""
 	if have != nil {
-		haveString = *have._string
+		haveString = have.string()
 	}
-	panic(&TypeAssertionError{*iface._string, haveString, *want._string, ""})
+	panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""})
 }
 
 func assertI2T(t *_type, i iface, r unsafe.Pointer) {
 	tab := i.tab
 	if tab == nil {
-		panic(&TypeAssertionError{"", "", *t._string, ""})
+		panic(&TypeAssertionError{"", "", t.string(), ""})
 	}
 	if tab._type != t {
-		panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
+		panic(&TypeAssertionError{tab.inter.typ.string(), tab._type.string(), t.string(), ""})
 	}
 	if r != nil {
 		if isDirectIface(t) {
@@ -203,7 +222,7 @@ func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool {
 	tab := i.tab
 	if tab == nil || tab._type != t {
 		if r != nil {
-			memclr(r, uintptr(t.size))
+			memclr(r, t.size)
 		}
 		return false
 	}
@@ -219,10 +238,10 @@ func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool {
 
 func assertE2T(t *_type, e eface, r unsafe.Pointer) {
 	if e._type == nil {
-		panic(&TypeAssertionError{"", "", *t._string, ""})
+		panic(&TypeAssertionError{"", "", t.string(), ""})
 	}
 	if e._type != t {
-		panic(&TypeAssertionError{"", *e._type._string, *t._string, ""})
+		panic(&TypeAssertionError{"", e._type.string(), t.string(), ""})
 	}
 	if r != nil {
 		if isDirectIface(t) {
@@ -241,7 +260,7 @@ func assertE2T2(t *_type, e eface, r unsafe.Pointer) bool {
 		GC()
 	}
 	if e._type != t {
-		memclr(r, uintptr(t.size))
+		memclr(r, t.size)
 		return false
 	}
 	if isDirectIface(t) {
@@ -266,7 +285,7 @@ func assertI2E(inter *interfacetype, i iface, r *eface) {
 	tab := i.tab
 	if tab == nil {
 		// explicit conversions require non-nil interface value.
-		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
+		panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
 	}
 	r._type = tab._type
 	r.data = i.data
@@ -303,7 +322,7 @@ func assertI2I(inter *interfacetype, i iface, r *iface) {
 	tab := i.tab
 	if tab == nil {
 		// explicit conversions require non-nil interface value.
-		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
+		panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
 	}
 	if tab.inter == inter {
 		r.tab = tab
@@ -342,7 +361,7 @@ func assertE2I(inter *interfacetype, e eface, r *iface) {
 	t := e._type
 	if t == nil {
 		// explicit conversions require non-nil interface value.
-		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
+		panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
 	}
 	r.tab = getitab(inter, t, false)
 	r.data = e.data
@@ -383,7 +402,7 @@ func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
 func assertE2E(inter *interfacetype, e eface, r *eface) {
 	if e._type == nil {
 		// explicit conversions require non-nil interface value.
-		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
+		panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
 	}
 	*r = e
 }
@@ -398,22 +417,6 @@ func assertE2E2(inter *interfacetype, e eface, r *eface) bool {
 	return true
 }
 
-func ifacethash(i iface) uint32 {
-	tab := i.tab
-	if tab == nil {
-		return 0
-	}
-	return tab._type.hash
-}
-
-func efacethash(e eface) uint32 {
-	t := e._type
-	if t == nil {
-		return 0
-	}
-	return t.hash
-}
-
 func iterate_itabs(fn func(*itab)) {
 	for _, h := range &hash {
 		for ; h != nil; h = h.link {
diff --git a/src/runtime/internal/atomic/asm.s b/src/runtime/internal/atomic/asm.s
index b5d0211..8488585 100644
--- a/src/runtime/internal/atomic/asm.s
+++ b/src/runtime/internal/atomic/asm.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/internal/atomic/asm_386.s b/src/runtime/internal/atomic/asm_386.s
index ce84fd8..ebecd0b 100644
--- a/src/runtime/internal/atomic/asm_386.s
+++ b/src/runtime/internal/atomic/asm_386.s
@@ -102,7 +102,7 @@ TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-12
 	JMP	runtime∕internal∕atomic·Xchg(SB)
 
 
-TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-8
+TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-8
 	MOVL	ptr+0(FP), BX
 	MOVL	val+4(FP), AX
 	XCHGL	AX, 0(BX)
diff --git a/src/runtime/internal/atomic/asm_amd64.s b/src/runtime/internal/atomic/asm_amd64.s
index 7463fec..94d4ac2 100644
--- a/src/runtime/internal/atomic/asm_amd64.s
+++ b/src/runtime/internal/atomic/asm_amd64.s
@@ -115,7 +115,7 @@ TEXT runtime∕internal∕atomic·Xchg64(SB), NOSPLIT, $0-24
 TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-24
 	JMP	runtime∕internal∕atomic·Xchg64(SB)
 
-TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-16
+TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-16
 	MOVQ	ptr+0(FP), BX
 	MOVQ	val+8(FP), AX
 	XCHGQ	AX, 0(BX)
diff --git a/src/runtime/internal/atomic/asm_amd64p32.s b/src/runtime/internal/atomic/asm_amd64p32.s
index f1e2c3a..74c79d0 100644
--- a/src/runtime/internal/atomic/asm_amd64p32.s
+++ b/src/runtime/internal/atomic/asm_amd64p32.s
@@ -115,7 +115,7 @@ TEXT runtime∕internal∕atomic·Xchg64(SB), NOSPLIT, $0-24
 TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-12
 	JMP	runtime∕internal∕atomic·Xchg(SB)
 
-TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-8
+TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-8
 	MOVL	ptr+0(FP), BX
 	MOVL	val+4(FP), AX
 	XCHGL	AX, 0(BX)
diff --git a/src/runtime/internal/atomic/asm_mips64x.s b/src/runtime/internal/atomic/asm_mips64x.s
index 4cab434..80b178d 100644
--- a/src/runtime/internal/atomic/asm_mips64x.s
+++ b/src/runtime/internal/atomic/asm_mips64x.s
@@ -83,7 +83,7 @@ TEXT ·Xadduintptr(SB), NOSPLIT, $0-24
 TEXT ·Loadint64(SB), NOSPLIT, $0-16
 	JMP	·Load64(SB)
 
-TEXT ·Xaddint64(SB), NOSPLIT, $0-16
+TEXT ·Xaddint64(SB), NOSPLIT, $0-24
 	JMP	·Xadd64(SB)
 
 // bool casp(void **val, void *old, void *new)
@@ -155,7 +155,7 @@ TEXT ·Xchg64(SB), NOSPLIT, $0-24
 TEXT ·Xchguintptr(SB), NOSPLIT, $0-24
 	JMP	·Xchg64(SB)
 
-TEXT ·Storep1(SB), NOSPLIT, $0-16
+TEXT ·StorepNoWB(SB), NOSPLIT, $0-16
 	JMP	·Store64(SB)
 
 TEXT ·Store(SB), NOSPLIT, $0-12
@@ -189,7 +189,7 @@ TEXT ·Or8(SB), NOSPLIT, $0-9
 	// R4 = ((ptr & 3) * 8)
 	AND	$3, R1, R4
 	SLLV	$3, R4
-	// Shift val for aligned ptr.  R2 = val << R4
+	// Shift val for aligned ptr. R2 = val << R4
 	SLLV	R4, R2
 
 	SYNC
@@ -215,7 +215,7 @@ TEXT ·And8(SB), NOSPLIT, $0-9
 	// R4 = ((ptr & 3) * 8)
 	AND	$3, R1, R4
 	SLLV	$3, R4
-	// Shift val for aligned ptr.  R2 = val << R4 | ^(0xFF << R4)
+	// Shift val for aligned ptr. R2 = val << R4 | ^(0xFF << R4)
 	MOVV	$0xFF, R5
 	SLLV	R4, R2
 	SLLV	R4, R5
diff --git a/src/runtime/internal/atomic/asm_ppc64x.s b/src/runtime/internal/atomic/asm_ppc64x.s
index 87f7f5d..de4f895 100644
--- a/src/runtime/internal/atomic/asm_ppc64x.s
+++ b/src/runtime/internal/atomic/asm_ppc64x.s
@@ -17,21 +17,20 @@ TEXT runtime∕internal∕atomic·Cas(SB), NOSPLIT, $0-17
 	MOVD	ptr+0(FP), R3
 	MOVWZ	old+8(FP), R4
 	MOVWZ	new+12(FP), R5
-cas_again:
 	SYNC
+cas_again:
 	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)
+	MOVB	R0, ret+16(FP)
+	RET
 
 // bool	runtime∕internal∕atomic·Cas64(uint64 *ptr, uint64 old, uint64 new)
 // Atomically:
@@ -45,21 +44,20 @@ TEXT runtime∕internal∕atomic·Cas64(SB), NOSPLIT, $0-25
 	MOVD	ptr+0(FP), R3
 	MOVD	old+8(FP), R4
 	MOVD	new+16(FP), R5
-cas64_again:
 	SYNC
+cas64_again:
 	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)
+	MOVB	R0, ret+24(FP)
+	RET
 
 TEXT runtime∕internal∕atomic·Casuintptr(SB), NOSPLIT, $0-25
 	BR	runtime∕internal∕atomic·Cas64(SB)
@@ -103,8 +101,7 @@ TEXT runtime∕internal∕atomic·Xadd(SB), NOSPLIT, $0-20
 	LWAR	(R4), R3
 	ADD	R5, R3
 	STWCCC	R3, (R4)
-	BNE	-4(PC)
-	SYNC
+	BNE	-3(PC)
 	ISYNC
 	MOVW	R3, ret+16(FP)
 	RET
@@ -116,8 +113,7 @@ TEXT runtime∕internal∕atomic·Xadd64(SB), NOSPLIT, $0-24
 	LDAR	(R4), R3
 	ADD	R5, R3
 	STDCCC	R3, (R4)
-	BNE	-4(PC)
-	SYNC
+	BNE	-3(PC)
 	ISYNC
 	MOVD	R3, ret+16(FP)
 	RET
@@ -128,8 +124,7 @@ TEXT runtime∕internal∕atomic·Xchg(SB), NOSPLIT, $0-20
 	SYNC
 	LWAR	(R4), R3
 	STWCCC	R5, (R4)
-	BNE	-3(PC)
-	SYNC
+	BNE	-2(PC)
 	ISYNC
 	MOVW	R3, ret+16(FP)
 	RET
@@ -140,8 +135,7 @@ TEXT runtime∕internal∕atomic·Xchg64(SB), NOSPLIT, $0-24
 	SYNC
 	LDAR	(R4), R3
 	STDCCC	R5, (R4)
-	BNE	-3(PC)
-	SYNC
+	BNE	-2(PC)
 	ISYNC
 	MOVD	R3, ret+16(FP)
 	RET
@@ -150,7 +144,7 @@ TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-24
 	BR	runtime∕internal∕atomic·Xchg64(SB)
 
 
-TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-16
+TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-16
 	BR	runtime∕internal∕atomic·Store64(SB)
 
 TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12
@@ -167,59 +161,71 @@ TEXT runtime∕internal∕atomic·Store64(SB), NOSPLIT, $0-16
 	MOVD	R4, 0(R3)
 	RET
 
-// void	runtime∕internal∕atomic·Or8(byte volatile*, byte);
+// void runtime∕internal∕atomic·Or8(byte volatile*, byte);
 TEXT runtime∕internal∕atomic·Or8(SB), NOSPLIT, $0-9
 	MOVD	ptr+0(FP), R3
 	MOVBZ	val+8(FP), R4
+#ifdef  GOARCH_ppc64
 	// 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
+	SYNC
 
 again:
-	SYNC
 	LWAR	(R5), R6
 	OR	R4, R6
 	STWCCC	R6, (R5)
 	BNE	again
+#else
 	SYNC
+again:
+	LBAR	(R3), R6
+	OR	R4, R6
+	STBCCC	R6, (R3)
+	BNE	again
+#endif
 	ISYNC
 	RET
 
-// void	runtime∕internal∕atomic·And8(byte volatile*, byte);
+// void runtime∕internal∕atomic·And8(byte volatile*, byte);
 TEXT runtime∕internal∕atomic·And8(SB), NOSPLIT, $0-9
 	MOVD	ptr+0(FP), R3
 	MOVBZ	val+8(FP), R4
+#ifdef  GOARCH_ppc64
 	// 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
+	XOR	$-1, R7
 	OR	R7, R4
-again:
 	SYNC
+again:
 	LWAR	(R5), R6
 	AND	R4, R6
 	STWCCC	R6, (R5)
 	BNE	again
+#else
 	SYNC
+again:
+	LBAR	(R3),R6
+	AND	R4,R6
+	STBCCC	R6,(R3)
+	BNE	again
+#endif
 	ISYNC
 	RET
diff --git a/src/runtime/internal/atomic/asm_s390x.s b/src/runtime/internal/atomic/asm_s390x.s
new file mode 100644
index 0000000..c84718c
--- /dev/null
+++ b/src/runtime/internal/atomic/asm_s390x.s
@@ -0,0 +1,174 @@
+// Copyright 2016 The Go 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 Cas(ptr *uint32, old, new uint32) bool
+// Atomically:
+//	if *ptr == old {
+//		*val = new
+//		return 1
+//	} else {
+//		return 0
+//	}
+TEXT ·Cas(SB), NOSPLIT, $0-17
+	MOVD	ptr+0(FP), R3
+	MOVWZ	old+8(FP), R4
+	MOVWZ	new+12(FP), R5
+	CS	R4, R5, 0(R3)    //  if (R4 == 0(R3)) then 0(R3)= R5
+	BNE	cas_fail
+	MOVB	$1, ret+16(FP)
+	RET
+cas_fail:
+	MOVB	$0, ret+16(FP)
+	RET
+
+// func Cas64(ptr *uint64, old, new uint64) bool
+// Atomically:
+//	if *ptr == old {
+//		*ptr = new
+//		return 1
+//	} else {
+//		return 0
+//	}
+TEXT ·Cas64(SB), NOSPLIT, $0-25
+	MOVD	ptr+0(FP), R3
+	MOVD	old+8(FP), R4
+	MOVD	new+16(FP), R5
+	CSG	R4, R5, 0(R3)    //  if (R4 == 0(R3)) then 0(R3)= R5
+	BNE	cas64_fail
+	MOVB	$1, ret+24(FP)
+	RET
+cas64_fail:
+	MOVB	$0, ret+24(FP)
+	RET
+
+// func Casuintptr(ptr *uintptr, old, new uintptr) bool
+TEXT ·Casuintptr(SB), NOSPLIT, $0-25
+	BR	·Cas64(SB)
+
+// func Loaduintptr(ptr *uintptr) uintptr
+TEXT ·Loaduintptr(SB), NOSPLIT, $0-16
+	BR	·Load64(SB)
+
+// func Loaduint(ptr *uint) uint
+TEXT ·Loaduint(SB), NOSPLIT, $0-16
+	BR	·Load64(SB)
+
+// func Storeuintptr(ptr *uintptr, new uintptr)
+TEXT ·Storeuintptr(SB), NOSPLIT, $0-16
+	BR	·Store64(SB)
+
+// func Loadint64(ptr *int64) int64
+TEXT ·Loadint64(SB), NOSPLIT, $0-16
+	BR	·Load64(SB)
+
+// func Xadduintptr(ptr *uintptr, delta uintptr) uintptr
+TEXT ·Xadduintptr(SB), NOSPLIT, $0-24
+	BR	·Xadd64(SB)
+
+// func Xaddint64(ptr *int64, delta int64) int64
+TEXT ·Xaddint64(SB), NOSPLIT, $0-16
+	BR	·Xadd64(SB)
+
+// func Casp1(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
+// Atomically:
+//	if *ptr == old {
+//		*ptr = new
+//		return 1
+//	} else {
+//		return 0
+//	}
+TEXT ·Casp1(SB), NOSPLIT, $0-25
+	BR ·Cas64(SB)
+
+// func Xadd(ptr *uint32, delta int32) uint32
+// Atomically:
+//	*ptr += delta
+//	return *ptr
+TEXT ·Xadd(SB), NOSPLIT, $0-20
+	MOVD	ptr+0(FP), R4
+	MOVW	delta+8(FP), R5
+	MOVW	(R4), R3
+repeat:
+	ADD	R5, R3, R6
+	CS	R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4)
+	BNE	repeat
+	MOVW	R6, ret+16(FP)
+	RET
+
+// func Xadd64(ptr *uint64, delta int64) uint64
+TEXT ·Xadd64(SB), NOSPLIT, $0-24
+	MOVD	ptr+0(FP), R4
+	MOVD	delta+8(FP), R5
+	MOVD	(R4), R3
+repeat:
+	ADD	R5, R3, R6
+	CSG	R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4)
+	BNE	repeat
+	MOVD	R6, ret+16(FP)
+	RET
+
+// func Xchg(ptr *uint32, new uint32) uint32
+TEXT ·Xchg(SB), NOSPLIT, $0-20
+	MOVD	ptr+0(FP), R4
+	MOVW	new+8(FP), R3
+	MOVW	(R4), R6
+repeat:
+	CS	R6, R3, (R4) // if R6==(R4) then (R4)=R3 else R6=(R4)
+	BNE	repeat
+	MOVW	R6, ret+16(FP)
+	RET
+
+// func Xchg64(ptr *uint64, new uint64) uint64
+TEXT ·Xchg64(SB), NOSPLIT, $0-24
+	MOVD	ptr+0(FP), R4
+	MOVD	new+8(FP), R3
+	MOVD	(R4), R6
+repeat:
+	CSG	R6, R3, (R4) // if R6==(R4) then (R4)=R3 else R6=(R4)
+	BNE	repeat
+	MOVD	R6, ret+16(FP)
+	RET
+
+// func Xchguintptr(ptr *uintptr, new uintptr) uintptr
+TEXT ·Xchguintptr(SB), NOSPLIT, $0-24
+	BR	·Xchg64(SB)
+
+// func Or8(addr *uint8, v uint8)
+TEXT ·Or8(SB), NOSPLIT, $0-9
+	MOVD    ptr+0(FP), R3
+	MOVBZ   val+8(FP), R4
+	// Calculate shift.
+	AND	$3, R3, R5
+	XOR	$3, R5 // big endian - flip direction
+	SLD	$3, R5 // MUL $8, R5
+	SLD	R5, R4
+	// Align ptr down to 4 bytes so we can use 32-bit load/store.
+	AND	$-4, R3
+	MOVWZ	0(R3), R6
+again:
+	OR	R4, R6, R7
+	CS	R6, R7, 0(R3) // if R6==(R3) then (R3)=R7 else R6=(R3)
+	BNE	again
+	RET
+
+// func And8(addr *uint8, v uint8)
+TEXT ·And8(SB), NOSPLIT, $0-9
+	MOVD    ptr+0(FP), R3
+	MOVBZ   val+8(FP), R4
+	// Calculate shift.
+	AND	$3, R3, R5
+	XOR	$3, R5 // big endian - flip direction
+	SLD	$3, R5 // MUL $8, R5
+	OR	$-256, R4 // create 0xffffffffffffffxx
+	RLLG	R5, R4
+	// Align ptr down to 4 bytes so we can use 32-bit load/store.
+	AND	$-4, R3
+	MOVWZ	0(R3), R6
+again:
+	AND	R4, R6, R7
+	CS	R6, R7, 0(R3) // if R6==(R3) then (R3)=R7 else R6=(R3)
+	BNE	again
+	RET
diff --git a/src/runtime/internal/atomic/atomic_386.go b/src/runtime/internal/atomic/atomic_386.go
index f4c50b0..23a8479 100644
--- a/src/runtime/internal/atomic/atomic_386.go
+++ b/src/runtime/internal/atomic/atomic_386.go
@@ -73,4 +73,4 @@ func Store(ptr *uint32, val uint32)
 func Store64(ptr *uint64, val uint64)
 
 // NO go:noescape annotation; see atomic_pointer.go.
-func Storep1(ptr unsafe.Pointer, val unsafe.Pointer)
+func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/internal/atomic/atomic_amd64x.go b/src/runtime/internal/atomic/atomic_amd64x.go
index bd40fb3..54851d3 100644
--- a/src/runtime/internal/atomic/atomic_amd64x.go
+++ b/src/runtime/internal/atomic/atomic_amd64x.go
@@ -61,5 +61,8 @@ func Store(ptr *uint32, val uint32)
 //go:noescape
 func Store64(ptr *uint64, val uint64)
 
+// StorepNoWB performs *ptr = val atomically and without a write
+// barrier.
+//
 // NO go:noescape annotation; see atomic_pointer.go.
-func Storep1(ptr unsafe.Pointer, val unsafe.Pointer)
+func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/internal/atomic/atomic_arm.go b/src/runtime/internal/atomic/atomic_arm.go
index c361aef..244237d 100644
--- a/src/runtime/internal/atomic/atomic_arm.go
+++ b/src/runtime/internal/atomic/atomic_arm.go
@@ -85,7 +85,7 @@ func Loadp(addr unsafe.Pointer) unsafe.Pointer {
 }
 
 //go:nosplit
-func Storep1(addr unsafe.Pointer, v unsafe.Pointer) {
+func StorepNoWB(addr unsafe.Pointer, v unsafe.Pointer) {
 	for {
 		old := *(*unsafe.Pointer)(addr)
 		if Casp1((*unsafe.Pointer)(addr), old, v) {
diff --git a/src/runtime/internal/atomic/atomic_arm64.go b/src/runtime/internal/atomic/atomic_arm64.go
index 6b32346..dc82c33 100644
--- a/src/runtime/internal/atomic/atomic_arm64.go
+++ b/src/runtime/internal/atomic/atomic_arm64.go
@@ -77,4 +77,4 @@ func Store(ptr *uint32, val uint32)
 func Store64(ptr *uint64, val uint64)
 
 // NO go:noescape annotation; see atomic_pointer.go.
-func Storep1(ptr unsafe.Pointer, val unsafe.Pointer)
+func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/internal/atomic/atomic_arm64.s b/src/runtime/internal/atomic/atomic_arm64.s
index 7b1b0ef..eb32f37 100644
--- a/src/runtime/internal/atomic/atomic_arm64.s
+++ b/src/runtime/internal/atomic/atomic_arm64.s
@@ -25,7 +25,7 @@ TEXT ·Loadp(SB),NOSPLIT,$-8-16
 	MOVD	R0, ret+8(FP)
 	RET
 
-TEXT runtime∕internal∕atomic·Storep1(SB), NOSPLIT, $0-16
+TEXT runtime∕internal∕atomic·StorepNoWB(SB), NOSPLIT, $0-16
 	B	runtime∕internal∕atomic·Store64(SB)
 
 TEXT runtime∕internal∕atomic·Store(SB), NOSPLIT, $0-12
diff --git a/src/runtime/internal/atomic/atomic_mips64x.go b/src/runtime/internal/atomic/atomic_mips64x.go
index 8094db5..d06ea48 100644
--- a/src/runtime/internal/atomic/atomic_mips64x.go
+++ b/src/runtime/internal/atomic/atomic_mips64x.go
@@ -53,4 +53,4 @@ func Store(ptr *uint32, val uint32)
 func Store64(ptr *uint64, val uint64)
 
 // NO go:noescape annotation; see atomic_pointer.go.
-func Storep1(ptr unsafe.Pointer, val unsafe.Pointer)
+func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/internal/atomic/atomic_mips64x.s b/src/runtime/internal/atomic/atomic_mips64x.s
index ae8500e..71d3f7f 100644
--- a/src/runtime/internal/atomic/atomic_mips64x.s
+++ b/src/runtime/internal/atomic/atomic_mips64x.s
@@ -8,27 +8,27 @@
 
 #define SYNC	WORD $0xf
 
-// uint32 runtime∕internal∕atomic·Load(uint32 volatile* addr)
+// uint32 runtime∕internal∕atomic·Load(uint32 volatile* ptr)
 TEXT ·Load(SB),NOSPLIT,$-8-12
-	MOVV	addr+0(FP), R1
+	MOVV	ptr+0(FP), R1
 	SYNC
 	MOVWU	0(R1), R1
 	SYNC
 	MOVW	R1, ret+8(FP)
 	RET
 
-// uint64 runtime∕internal∕atomic·Load64(uint64 volatile* addr)
+// uint64 runtime∕internal∕atomic·Load64(uint64 volatile* ptr)
 TEXT ·Load64(SB),NOSPLIT,$-8-16
-	MOVV	addr+0(FP), R1
+	MOVV	ptr+0(FP), R1
 	SYNC
 	MOVV	0(R1), R1
 	SYNC
 	MOVV	R1, ret+8(FP)
 	RET
 
-// void *runtime∕internal∕atomic·Loadp(void *volatile *addr)
+// void *runtime∕internal∕atomic·Loadp(void *volatile *ptr)
 TEXT ·Loadp(SB),NOSPLIT,$-8-16
-	MOVV	addr+0(FP), R1
+	MOVV	ptr+0(FP), R1
 	SYNC
 	MOVV	0(R1), R1
 	SYNC
diff --git a/src/runtime/internal/atomic/atomic_ppc64x.go b/src/runtime/internal/atomic/atomic_ppc64x.go
index bf82b82..72c98eb 100644
--- a/src/runtime/internal/atomic/atomic_ppc64x.go
+++ b/src/runtime/internal/atomic/atomic_ppc64x.go
@@ -53,4 +53,4 @@ func Store(ptr *uint32, val uint32)
 func Store64(ptr *uint64, val uint64)
 
 // NO go:noescape annotation; see atomic_pointer.go.
-func Storep1(ptr unsafe.Pointer, val unsafe.Pointer)
+func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/internal/atomic/atomic_s390x.go b/src/runtime/internal/atomic/atomic_s390x.go
new file mode 100644
index 0000000..9343853
--- /dev/null
+++ b/src/runtime/internal/atomic/atomic_s390x.go
@@ -0,0 +1,73 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic
+
+import "unsafe"
+
+//go:nosplit
+//go:noinline
+func Load(ptr *uint32) uint32 {
+	return *ptr
+}
+
+//go:nosplit
+//go:noinline
+func Loadp(ptr unsafe.Pointer) unsafe.Pointer {
+	return *(*unsafe.Pointer)(ptr)
+}
+
+//go:nosplit
+//go:noinline
+func Load64(ptr *uint64) uint64 {
+	return *ptr
+}
+
+//go:noinline
+//go:nosplit
+func Store(ptr *uint32, val uint32) {
+	*ptr = val
+}
+
+//go:noinline
+//go:nosplit
+func Store64(ptr *uint64, val uint64) {
+	*ptr = val
+}
+
+// NO go:noescape annotation; see atomic_pointer.go.
+//go:noinline
+//go:nosplit
+func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer) {
+	*(*uintptr)(ptr) = uintptr(val)
+}
+
+//go:noescape
+func And8(ptr *uint8, val uint8)
+
+//go:noescape
+func Or8(ptr *uint8, val uint8)
+
+// NOTE: Do not add atomicxor8 (XOR is not idempotent).
+
+//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
+
+//go:noescape
+func Xchguintptr(ptr *uintptr, new uintptr) uintptr
+
+//go:noescape
+func Cas64(ptr *uint64, old, new uint64) bool
diff --git a/src/runtime/internal/atomic/atomic_test.go b/src/runtime/internal/atomic/atomic_test.go
index e8ec788..d5dc552 100644
--- a/src/runtime/internal/atomic/atomic_test.go
+++ b/src/runtime/internal/atomic/atomic_test.go
@@ -48,7 +48,7 @@ func TestXadduintptr(t *testing.T) {
 	}
 }
 
-// Tests that xadduintptr correctly updates 64-bit values.  The place where
+// 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 {
diff --git a/src/runtime/internal/atomic/sys_plan9_arm.s b/src/runtime/internal/atomic/sys_plan9_arm.s
new file mode 100644
index 0000000..01b7aef
--- /dev/null
+++ b/src/runtime/internal/atomic/sys_plan9_arm.s
@@ -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.
+
+#include "textflag.h"
+
+TEXT runtime∕internal∕atomic·Cas(SB),NOSPLIT,$0
+	B	runtime∕internal∕atomic·armcas(SB)
+
+TEXT runtime∕internal∕atomic·Casp1(SB),NOSPLIT,$0
+	B	runtime∕internal∕atomic·Cas(SB)
diff --git a/src/runtime/internal/sys/arch.go b/src/runtime/internal/sys/arch.go
new file mode 100644
index 0000000..c175704
--- /dev/null
+++ b/src/runtime/internal/sys/arch.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.
+
+package sys
+
+type ArchFamilyType int
+
+const (
+	AMD64 ArchFamilyType = iota
+	ARM
+	ARM64
+	I386
+	MIPS64
+	PPC64
+	S390X
+)
diff --git a/src/runtime/internal/sys/arch_386.go b/src/runtime/internal/sys/arch_386.go
index 1f1c704..48c42f7 100644
--- a/src/runtime/internal/sys/arch_386.go
+++ b/src/runtime/internal/sys/arch_386.go
@@ -5,7 +5,7 @@
 package sys
 
 const (
-	TheChar       = '8'
+	ArchFamily    = I386
 	BigEndian     = 0
 	CacheLineSize = 64
 	PhysPageSize  = GoosNacl*65536 + (1-GoosNacl)*4096 // 4k normally; 64k on NaCl
diff --git a/src/runtime/internal/sys/arch_amd64.go b/src/runtime/internal/sys/arch_amd64.go
index 80fff55..1bbdb99 100644
--- a/src/runtime/internal/sys/arch_amd64.go
+++ b/src/runtime/internal/sys/arch_amd64.go
@@ -5,7 +5,7 @@
 package sys
 
 const (
-	TheChar       = '6'
+	ArchFamily    = AMD64
 	BigEndian     = 0
 	CacheLineSize = 64
 	PhysPageSize  = 4096
diff --git a/src/runtime/internal/sys/arch_amd64p32.go b/src/runtime/internal/sys/arch_amd64p32.go
index ca29f69..b7011a4 100644
--- a/src/runtime/internal/sys/arch_amd64p32.go
+++ b/src/runtime/internal/sys/arch_amd64p32.go
@@ -5,7 +5,7 @@
 package sys
 
 const (
-	TheChar       = '6'
+	ArchFamily    = AMD64
 	BigEndian     = 0
 	CacheLineSize = 64
 	PhysPageSize  = 65536*GoosNacl + 4096*(1-GoosNacl)
diff --git a/src/runtime/internal/sys/arch_arm.go b/src/runtime/internal/sys/arch_arm.go
index b185e8f..f90f52d 100644
--- a/src/runtime/internal/sys/arch_arm.go
+++ b/src/runtime/internal/sys/arch_arm.go
@@ -5,7 +5,7 @@
 package sys
 
 const (
-	TheChar       = '5'
+	ArchFamily    = ARM
 	BigEndian     = 0
 	CacheLineSize = 32
 	PhysPageSize  = 65536*GoosNacl + 4096*(1-GoosNacl)
diff --git a/src/runtime/internal/sys/arch_arm64.go b/src/runtime/internal/sys/arch_arm64.go
index b63a7a6..aaaa4b0 100644
--- a/src/runtime/internal/sys/arch_arm64.go
+++ b/src/runtime/internal/sys/arch_arm64.go
@@ -5,7 +5,7 @@
 package sys
 
 const (
-	TheChar       = '7'
+	ArchFamily    = ARM64
 	BigEndian     = 0
 	CacheLineSize = 32
 	PhysPageSize  = 65536
diff --git a/src/runtime/internal/sys/arch_mips64.go b/src/runtime/internal/sys/arch_mips64.go
index 5b933d4..d567259 100644
--- a/src/runtime/internal/sys/arch_mips64.go
+++ b/src/runtime/internal/sys/arch_mips64.go
@@ -5,7 +5,7 @@
 package sys
 
 const (
-	TheChar       = '0'
+	ArchFamily    = MIPS64
 	BigEndian     = 1
 	CacheLineSize = 32
 	PhysPageSize  = 16384
diff --git a/src/runtime/internal/sys/arch_mips64le.go b/src/runtime/internal/sys/arch_mips64le.go
index ce2e98b..f8cdf2b 100644
--- a/src/runtime/internal/sys/arch_mips64le.go
+++ b/src/runtime/internal/sys/arch_mips64le.go
@@ -5,7 +5,7 @@
 package sys
 
 const (
-	TheChar       = '0'
+	ArchFamily    = MIPS64
 	BigEndian     = 0
 	CacheLineSize = 32
 	PhysPageSize  = 16384
diff --git a/src/runtime/internal/sys/arch_ppc64.go b/src/runtime/internal/sys/arch_ppc64.go
index 3aa07e1..cdec63f 100644
--- a/src/runtime/internal/sys/arch_ppc64.go
+++ b/src/runtime/internal/sys/arch_ppc64.go
@@ -5,7 +5,7 @@
 package sys
 
 const (
-	TheChar       = '9'
+	ArchFamily    = PPC64
 	BigEndian     = 1
 	CacheLineSize = 64
 	PhysPageSize  = 65536
diff --git a/src/runtime/internal/sys/arch_ppc64le.go b/src/runtime/internal/sys/arch_ppc64le.go
index 0f02f0b..4fd68f9 100644
--- a/src/runtime/internal/sys/arch_ppc64le.go
+++ b/src/runtime/internal/sys/arch_ppc64le.go
@@ -5,7 +5,7 @@
 package sys
 
 const (
-	TheChar       = '9'
+	ArchFamily    = PPC64
 	BigEndian     = 0
 	CacheLineSize = 64
 	PhysPageSize  = 65536
diff --git a/src/runtime/internal/sys/arch_s390x.go b/src/runtime/internal/sys/arch_s390x.go
new file mode 100644
index 0000000..ca1cb86
--- /dev/null
+++ b/src/runtime/internal/sys/arch_s390x.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+const (
+	ArchFamily    = S390X
+	BigEndian     = 1
+	CacheLineSize = 256
+	PhysPageSize  = 4096
+	PCQuantum     = 2
+	Int64Align    = 8
+	HugePageSize  = 0
+	MinFrameSize  = 8
+)
+
+type Uintreg uint64
diff --git a/src/runtime/internal/sys/gengoos.go b/src/runtime/internal/sys/gengoos.go
index 55d991c..4c45c0a 100644
--- a/src/runtime/internal/sys/gengoos.go
+++ b/src/runtime/internal/sys/gengoos.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -50,7 +50,7 @@ func main() {
 			fmt.Fprintf(&buf, "// +build !android\n\n") // must explicitly exclude android for linux
 		}
 		fmt.Fprintf(&buf, "package sys\n\n")
-		fmt.Fprintf(&buf, "const TheGoos = `%s`\n\n", target)
+		fmt.Fprintf(&buf, "const GOOS = `%s`\n\n", target)
 		for _, goos := range gooses {
 			value := 0
 			if goos == target {
@@ -68,7 +68,7 @@ func main() {
 		var buf bytes.Buffer
 		fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n")
 		fmt.Fprintf(&buf, "package sys\n\n")
-		fmt.Fprintf(&buf, "const TheGoarch = `%s`\n\n", target)
+		fmt.Fprintf(&buf, "const GOARCH = `%s`\n\n", target)
 		for _, goarch := range goarches {
 			value := 0
 			if goarch == target {
diff --git a/src/runtime/internal/sys/intrinsics.go b/src/runtime/internal/sys/intrinsics.go
new file mode 100644
index 0000000..08a062f
--- /dev/null
+++ b/src/runtime/internal/sys/intrinsics.go
@@ -0,0 +1,116 @@
+// Copyright 2016 The Go 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
+
+package sys
+
+// Using techniques from http://supertech.csail.mit.edu/papers/debruijn.pdf
+
+const deBruijn64 = 0x0218a392cd3d5dbf
+
+var deBruijnIdx64 = [64]byte{
+	0, 1, 2, 7, 3, 13, 8, 19,
+	4, 25, 14, 28, 9, 34, 20, 40,
+	5, 17, 26, 38, 15, 46, 29, 48,
+	10, 31, 35, 54, 21, 50, 41, 57,
+	63, 6, 12, 18, 24, 27, 33, 39,
+	16, 37, 45, 47, 30, 53, 49, 56,
+	62, 11, 23, 32, 36, 44, 52, 55,
+	61, 22, 43, 51, 60, 42, 59, 58,
+}
+
+const deBruijn32 = 0x04653adf
+
+var deBruijnIdx32 = [32]byte{
+	0, 1, 2, 6, 3, 11, 7, 16,
+	4, 14, 12, 21, 8, 23, 17, 26,
+	31, 5, 10, 15, 13, 20, 22, 25,
+	30, 9, 19, 24, 29, 18, 28, 27,
+}
+
+const deBruijn16 = 0x09af
+
+var deBruijnIdx16 = [16]byte{
+	0, 1, 2, 5, 3, 9, 6, 11,
+	15, 4, 8, 10, 14, 7, 13, 12,
+}
+
+const deBruijn8 = 0x17
+
+var deBruijnIdx8 = [8]byte{
+	0, 1, 2, 4, 7, 3, 6, 5,
+}
+
+// Ctz64 counts trailing (low-order) zeroes,
+// and if all are zero, then 64.
+func Ctz64(x uint64) uint64 {
+	x &= -x                      // isolate low-order bit
+	y := x * deBruijn64 >> 58    // extract part of deBruijn sequence
+	y = uint64(deBruijnIdx64[y]) // convert to bit index
+	z := (x - 1) >> 57 & 64      // adjustment if zero
+	return y + z
+}
+
+// Ctz32 counts trailing (low-order) zeroes,
+// and if all are zero, then 32.
+func Ctz32(x uint32) uint32 {
+	x &= -x                      // isolate low-order bit
+	y := x * deBruijn32 >> 27    // extract part of deBruijn sequence
+	y = uint32(deBruijnIdx32[y]) // convert to bit index
+	z := (x - 1) >> 26 & 32      // adjustment if zero
+	return y + z
+}
+
+// Ctz16 counts trailing (low-order) zeroes,
+// and if all are zero, then 16.
+func Ctz16(x uint16) uint16 {
+	x &= -x                      // isolate low-order bit
+	y := x * deBruijn16 >> 12    // extract part of deBruijn sequence
+	y = uint16(deBruijnIdx16[y]) // convert to bit index
+	z := (x - 1) >> 11 & 16      // adjustment if zero
+	return y + z
+}
+
+// Ctz8 counts trailing (low-order) zeroes,
+// and if all are zero, then 8.
+func Ctz8(x uint8) uint8 {
+	x &= -x                    // isolate low-order bit
+	y := x * deBruijn8 >> 5    // extract part of deBruijn sequence
+	y = uint8(deBruijnIdx8[y]) // convert to bit index
+	z := (x - 1) >> 4 & 8      // adjustment if zero
+	return y + z
+}
+
+// Bswap64 returns its input with byte order reversed
+// 0x0102030405060708 -> 0x0807060504030201
+func Bswap64(x uint64) uint64 {
+	c8 := uint64(0x00ff00ff00ff00ff)
+	a := x >> 8 & c8
+	b := (x & c8) << 8
+	x = a | b
+	c16 := uint64(0x0000ffff0000ffff)
+	a = x >> 16 & c16
+	b = (x & c16) << 16
+	x = a | b
+	c32 := uint64(0x00000000ffffffff)
+	a = x >> 32 & c32
+	b = (x & c32) << 32
+	x = a | b
+	return x
+}
+
+// Bswap32 returns its input with byte order reversed
+// 0x01020304 -> 0x04030201
+func Bswap32(x uint32) uint32 {
+	c8 := uint32(0x00ff00ff)
+	a := x >> 8 & c8
+	b := (x & c8) << 8
+	x = a | b
+	c16 := uint32(0x0000ffff)
+	a = x >> 16 & c16
+	b = (x & c16) << 16
+	x = a | b
+	return x
+}
diff --git a/src/runtime/internal/sys/intrinsics_386.s b/src/runtime/internal/sys/intrinsics_386.s
new file mode 100644
index 0000000..1f48e26
--- /dev/null
+++ b/src/runtime/internal/sys/intrinsics_386.s
@@ -0,0 +1,68 @@
+// Copyright 2016 The Go 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 runtime∕internal∕sys·Ctz64(SB), NOSPLIT, $0-16
+	MOVL	$0, ret_hi+12(FP)
+
+	// Try low 32 bits.
+	MOVL	x_lo+0(FP), AX
+	BSFL	AX, AX
+	JZ	tryhigh
+	MOVL	AX, ret_lo+8(FP)
+	RET
+
+tryhigh:
+	// Try high 32 bits.
+	MOVL	x_hi+4(FP), AX
+	BSFL	AX, AX
+	JZ	none
+	ADDL	$32, AX
+	MOVL	AX, ret_lo+8(FP)
+	RET
+
+none:
+	// No bits are set.
+	MOVL	$64, ret_lo+8(FP)
+	RET
+
+TEXT runtime∕internal∕sys·Ctz32(SB), NOSPLIT, $0-8
+	MOVL	x+0(FP), AX
+	BSFL	AX, AX
+	JNZ	2(PC)
+	MOVL	$32, AX
+	MOVL	AX, ret+4(FP)
+	RET
+
+TEXT runtime∕internal∕sys·Ctz16(SB), NOSPLIT, $0-6
+	MOVW	x+0(FP), AX
+	BSFW	AX, AX
+	JNZ	2(PC)
+	MOVW	$16, AX
+	MOVW	AX, ret+4(FP)
+	RET
+
+TEXT runtime∕internal∕sys·Ctz8(SB), NOSPLIT, $0-5
+	MOVBLZX	x+0(FP), AX
+	BSFL	AX, AX
+	JNZ	2(PC)
+	MOVB	$8, AX
+	MOVB	AX, ret+4(FP)
+	RET
+
+TEXT runtime∕internal∕sys·Bswap64(SB), NOSPLIT, $0-16
+	MOVL	x_lo+0(FP), AX
+	MOVL	x_hi+4(FP), BX
+	BSWAPL	AX
+	BSWAPL	BX
+	MOVL	BX, ret_lo+8(FP)
+	MOVL	AX, ret_hi+12(FP)
+	RET
+
+TEXT runtime∕internal∕sys·Bswap32(SB), NOSPLIT, $0-8
+	MOVL	x+0(FP), AX
+	BSWAPL	AX
+	MOVL	AX, ret+4(FP)
+	RET
diff --git a/src/runtime/internal/sys/intrinsics_stubs.go b/src/runtime/internal/sys/intrinsics_stubs.go
new file mode 100644
index 0000000..079844f
--- /dev/null
+++ b/src/runtime/internal/sys/intrinsics_stubs.go
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go 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
+
+package sys
+
+func Ctz64(x uint64) uint64
+func Ctz32(x uint32) uint32
+func Ctz16(x uint16) uint16
+func Ctz8(x uint8) uint8
+func Bswap64(x uint64) uint64
+func Bswap32(x uint32) uint32
diff --git a/src/runtime/internal/sys/intrinsics_test.go b/src/runtime/internal/sys/intrinsics_test.go
new file mode 100644
index 0000000..097631b
--- /dev/null
+++ b/src/runtime/internal/sys/intrinsics_test.go
@@ -0,0 +1,54 @@
+package sys_test
+
+import (
+	"runtime/internal/sys"
+	"testing"
+)
+
+func TestCtz64(t *testing.T) {
+	for i := uint(0); i <= 64; i++ {
+		x := uint64(5) << i
+		if got := sys.Ctz64(x); got != uint64(i) {
+			t.Errorf("Ctz64(%d)=%d, want %d", x, got, i)
+		}
+	}
+}
+func TestCtz32(t *testing.T) {
+	for i := uint(0); i <= 32; i++ {
+		x := uint32(5) << i
+		if got := sys.Ctz32(x); got != uint32(i) {
+			t.Errorf("Ctz32(%d)=%d, want %d", x, got, i)
+		}
+	}
+}
+func TestCtz16(t *testing.T) {
+	for i := uint(0); i <= 16; i++ {
+		x := uint16(5) << i
+		if got := sys.Ctz16(x); got != uint16(i) {
+			t.Errorf("Ctz16(%d)=%d, want %d", x, got, i)
+		}
+	}
+}
+func TestCtz8(t *testing.T) {
+	for i := uint(0); i <= 8; i++ {
+		x := uint8(5) << i
+		if got := sys.Ctz8(x); got != uint8(i) {
+			t.Errorf("Ctz8(%d)=%d, want %d", x, got, i)
+		}
+	}
+}
+
+func TestBswap64(t *testing.T) {
+	x := uint64(0x1122334455667788)
+	y := sys.Bswap64(x)
+	if y != 0x8877665544332211 {
+		t.Errorf("Bswap(%x)=%x, want 0x8877665544332211", x, y)
+	}
+}
+func TestBswap32(t *testing.T) {
+	x := uint32(0x11223344)
+	y := sys.Bswap32(x)
+	if y != 0x44332211 {
+		t.Errorf("Bswap(%x)=%x, want 0x44332211", x, y)
+	}
+}
diff --git a/src/runtime/internal/sys/sys.go b/src/runtime/internal/sys/sys.go
index 15ad7f5..586a763 100644
--- a/src/runtime/internal/sys/sys.go
+++ b/src/runtime/internal/sys/sys.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/internal/sys/zgoarch_386.go b/src/runtime/internal/sys/zgoarch_386.go
index 3ad2445..3bcf83b 100644
--- a/src/runtime/internal/sys/zgoarch_386.go
+++ b/src/runtime/internal/sys/zgoarch_386.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoarch = `386`
+const GOARCH = `386`
 
 const Goarch386 = 1
 const GoarchAmd64 = 0
diff --git a/src/runtime/internal/sys/zgoarch_amd64.go b/src/runtime/internal/sys/zgoarch_amd64.go
index 7c858e3..699f191 100644
--- a/src/runtime/internal/sys/zgoarch_amd64.go
+++ b/src/runtime/internal/sys/zgoarch_amd64.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoarch = `amd64`
+const GOARCH = `amd64`
 
 const Goarch386 = 0
 const GoarchAmd64 = 1
diff --git a/src/runtime/internal/sys/zgoarch_amd64p32.go b/src/runtime/internal/sys/zgoarch_amd64p32.go
index 772031c..cc2d658 100644
--- a/src/runtime/internal/sys/zgoarch_amd64p32.go
+++ b/src/runtime/internal/sys/zgoarch_amd64p32.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoarch = `amd64p32`
+const GOARCH = `amd64p32`
 
 const Goarch386 = 0
 const GoarchAmd64 = 0
diff --git a/src/runtime/internal/sys/zgoarch_arm.go b/src/runtime/internal/sys/zgoarch_arm.go
index 276e8a8..a5fd789 100644
--- a/src/runtime/internal/sys/zgoarch_arm.go
+++ b/src/runtime/internal/sys/zgoarch_arm.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoarch = `arm`
+const GOARCH = `arm`
 
 const Goarch386 = 0
 const GoarchAmd64 = 0
diff --git a/src/runtime/internal/sys/zgoarch_arm64.go b/src/runtime/internal/sys/zgoarch_arm64.go
index d124ec0..084d2c7 100644
--- a/src/runtime/internal/sys/zgoarch_arm64.go
+++ b/src/runtime/internal/sys/zgoarch_arm64.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoarch = `arm64`
+const GOARCH = `arm64`
 
 const Goarch386 = 0
 const GoarchAmd64 = 0
diff --git a/src/runtime/internal/sys/zgoarch_mips64.go b/src/runtime/internal/sys/zgoarch_mips64.go
index b4a97d6..2ad62bd 100644
--- a/src/runtime/internal/sys/zgoarch_mips64.go
+++ b/src/runtime/internal/sys/zgoarch_mips64.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoarch = `mips64`
+const GOARCH = `mips64`
 
 const Goarch386 = 0
 const GoarchAmd64 = 0
diff --git a/src/runtime/internal/sys/zgoarch_mips64le.go b/src/runtime/internal/sys/zgoarch_mips64le.go
index 3328a35..047c8b4 100644
--- a/src/runtime/internal/sys/zgoarch_mips64le.go
+++ b/src/runtime/internal/sys/zgoarch_mips64le.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoarch = `mips64le`
+const GOARCH = `mips64le`
 
 const Goarch386 = 0
 const GoarchAmd64 = 0
diff --git a/src/runtime/internal/sys/zgoarch_ppc64.go b/src/runtime/internal/sys/zgoarch_ppc64.go
index 06f78b2..748b5b5 100644
--- a/src/runtime/internal/sys/zgoarch_ppc64.go
+++ b/src/runtime/internal/sys/zgoarch_ppc64.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoarch = `ppc64`
+const GOARCH = `ppc64`
 
 const Goarch386 = 0
 const GoarchAmd64 = 0
diff --git a/src/runtime/internal/sys/zgoarch_ppc64le.go b/src/runtime/internal/sys/zgoarch_ppc64le.go
index 50b56db..d3dcba4 100644
--- a/src/runtime/internal/sys/zgoarch_ppc64le.go
+++ b/src/runtime/internal/sys/zgoarch_ppc64le.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoarch = `ppc64le`
+const GOARCH = `ppc64le`
 
 const Goarch386 = 0
 const GoarchAmd64 = 0
diff --git a/src/runtime/internal/sys/zgoarch_s390x.go b/src/runtime/internal/sys/zgoarch_s390x.go
new file mode 100644
index 0000000..1ead5d5
--- /dev/null
+++ b/src/runtime/internal/sys/zgoarch_s390x.go
@@ -0,0 +1,26 @@
+// generated by gengoos.go using 'go generate'
+
+package sys
+
+const GOARCH = `s390x`
+
+const Goarch386 = 0
+const GoarchAmd64 = 0
+const GoarchAmd64p32 = 0
+const GoarchArm = 0
+const GoarchArmbe = 0
+const GoarchArm64 = 0
+const GoarchArm64be = 0
+const GoarchPpc64 = 0
+const GoarchPpc64le = 0
+const GoarchMips = 0
+const GoarchMipsle = 0
+const GoarchMips64 = 0
+const GoarchMips64le = 0
+const GoarchMips64p32 = 0
+const GoarchMips64p32le = 0
+const GoarchPpc = 0
+const GoarchS390 = 0
+const GoarchS390x = 1
+const GoarchSparc = 0
+const GoarchSparc64 = 0
diff --git a/src/runtime/internal/sys/zgoos_android.go b/src/runtime/internal/sys/zgoos_android.go
index 03d9176..6503b15 100644
--- a/src/runtime/internal/sys/zgoos_android.go
+++ b/src/runtime/internal/sys/zgoos_android.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `android`
+const GOOS = `android`
 
 const GoosAndroid = 1
 const GoosDarwin = 0
diff --git a/src/runtime/internal/sys/zgoos_darwin.go b/src/runtime/internal/sys/zgoos_darwin.go
index eb2efeb..6a28598 100644
--- a/src/runtime/internal/sys/zgoos_darwin.go
+++ b/src/runtime/internal/sys/zgoos_darwin.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `darwin`
+const GOOS = `darwin`
 
 const GoosAndroid = 0
 const GoosDarwin = 1
diff --git a/src/runtime/internal/sys/zgoos_dragonfly.go b/src/runtime/internal/sys/zgoos_dragonfly.go
index 403cf65..886ac26 100644
--- a/src/runtime/internal/sys/zgoos_dragonfly.go
+++ b/src/runtime/internal/sys/zgoos_dragonfly.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `dragonfly`
+const GOOS = `dragonfly`
 
 const GoosAndroid = 0
 const GoosDarwin = 0
diff --git a/src/runtime/internal/sys/zgoos_freebsd.go b/src/runtime/internal/sys/zgoos_freebsd.go
index 632d5db..0bf2403 100644
--- a/src/runtime/internal/sys/zgoos_freebsd.go
+++ b/src/runtime/internal/sys/zgoos_freebsd.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `freebsd`
+const GOOS = `freebsd`
 
 const GoosAndroid = 0
 const GoosDarwin = 0
diff --git a/src/runtime/internal/sys/zgoos_linux.go b/src/runtime/internal/sys/zgoos_linux.go
index 2d43869..c8664db 100644
--- a/src/runtime/internal/sys/zgoos_linux.go
+++ b/src/runtime/internal/sys/zgoos_linux.go
@@ -4,7 +4,7 @@
 
 package sys
 
-const TheGoos = `linux`
+const GOOS = `linux`
 
 const GoosAndroid = 0
 const GoosDarwin = 0
diff --git a/src/runtime/internal/sys/zgoos_nacl.go b/src/runtime/internal/sys/zgoos_nacl.go
index a56b6ef..0541226 100644
--- a/src/runtime/internal/sys/zgoos_nacl.go
+++ b/src/runtime/internal/sys/zgoos_nacl.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `nacl`
+const GOOS = `nacl`
 
 const GoosAndroid = 0
 const GoosDarwin = 0
diff --git a/src/runtime/internal/sys/zgoos_netbsd.go b/src/runtime/internal/sys/zgoos_netbsd.go
index 46fd0a7..5c509a1 100644
--- a/src/runtime/internal/sys/zgoos_netbsd.go
+++ b/src/runtime/internal/sys/zgoos_netbsd.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `netbsd`
+const GOOS = `netbsd`
 
 const GoosAndroid = 0
 const GoosDarwin = 0
diff --git a/src/runtime/internal/sys/zgoos_openbsd.go b/src/runtime/internal/sys/zgoos_openbsd.go
index 7ee650a..dc43157 100644
--- a/src/runtime/internal/sys/zgoos_openbsd.go
+++ b/src/runtime/internal/sys/zgoos_openbsd.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `openbsd`
+const GOOS = `openbsd`
 
 const GoosAndroid = 0
 const GoosDarwin = 0
diff --git a/src/runtime/internal/sys/zgoos_plan9.go b/src/runtime/internal/sys/zgoos_plan9.go
index 162e7f6..4b0934f 100644
--- a/src/runtime/internal/sys/zgoos_plan9.go
+++ b/src/runtime/internal/sys/zgoos_plan9.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `plan9`
+const GOOS = `plan9`
 
 const GoosAndroid = 0
 const GoosDarwin = 0
diff --git a/src/runtime/internal/sys/zgoos_solaris.go b/src/runtime/internal/sys/zgoos_solaris.go
index b2a8f98..42511a3 100644
--- a/src/runtime/internal/sys/zgoos_solaris.go
+++ b/src/runtime/internal/sys/zgoos_solaris.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `solaris`
+const GOOS = `solaris`
 
 const GoosAndroid = 0
 const GoosDarwin = 0
diff --git a/src/runtime/internal/sys/zgoos_windows.go b/src/runtime/internal/sys/zgoos_windows.go
index 817ec79..d77f62c 100644
--- a/src/runtime/internal/sys/zgoos_windows.go
+++ b/src/runtime/internal/sys/zgoos_windows.go
@@ -2,7 +2,7 @@
 
 package sys
 
-const TheGoos = `windows`
+const GOOS = `windows`
 
 const GoosAndroid = 0
 const GoosDarwin = 0
diff --git a/src/runtime/lfstack.go b/src/runtime/lfstack.go
index ea640eb..8e33ce1 100644
--- a/src/runtime/lfstack.go
+++ b/src/runtime/lfstack.go
@@ -3,7 +3,10 @@
 // license that can be found in the LICENSE file.
 
 // Lock-free stack.
-// The following code runs only on g0 stack.
+// Initialize 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.
+// The following code runs only in non-preemptible contexts.
 
 package runtime
 
@@ -15,7 +18,7 @@ import (
 func lfstackpush(head *uint64, node *lfnode) {
 	node.pushcnt++
 	new := lfstackPack(node, node.pushcnt)
-	if node1, _ := lfstackUnpack(new); node1 != node {
+	if node1 := lfstackUnpack(new); node1 != node {
 		print("runtime: lfstackpush invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n")
 		throw("lfstackpush")
 	}
@@ -34,7 +37,7 @@ func lfstackpop(head *uint64) unsafe.Pointer {
 		if old == 0 {
 			return nil
 		}
-		node, _ := lfstackUnpack(old)
+		node := lfstackUnpack(old)
 		next := atomic.Load64(&node.next)
 		if atomic.Cas64(head, old, next) {
 			return unsafe.Pointer(node)
diff --git a/src/runtime/lfstack_32bit.go b/src/runtime/lfstack_32bit.go
index 4b8bcba..2f59e02 100644
--- a/src/runtime/lfstack_32bit.go
+++ b/src/runtime/lfstack_32bit.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -14,8 +14,6 @@ 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
+func lfstackUnpack(val uint64) *lfnode {
+	return (*lfnode)(unsafe.Pointer(uintptr(val >> 32)))
 }
diff --git a/src/runtime/lfstack_64bit.go b/src/runtime/lfstack_64bit.go
new file mode 100644
index 0000000..5367f08
--- /dev/null
+++ b/src/runtime/lfstack_64bit.go
@@ -0,0 +1,48 @@
+// 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 arm64 mips64 mips64le ppc64 ppc64le s390x
+
+package runtime
+
+import "unsafe"
+
+const (
+	// addrBits is the number of bits needed to represent a virtual address.
+	//
+	// In Linux the user address space for each architecture is limited as
+	// follows (taken from the processor.h file for the architecture):
+	//
+	// Architecture  Name              Maximum Value (exclusive)
+	// ---------------------------------------------------------------------
+	// arm64         TASK_SIZE_64      Depends on configuration.
+	// ppc64{,le}    TASK_SIZE_USER64  0x400000000000UL (46 bit addresses)
+	// mips64{,le}   TASK_SIZE64       0x010000000000UL (40 bit addresses)
+	// s390x         TASK_SIZE         0x020000000000UL (41 bit addresses)
+	//
+	// These values may increase over time.
+	//
+	// 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.
+	addrBits = 48
+
+	// 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.
+	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) *lfnode {
+	if GOARCH == "amd64" {
+		// amd64 systems can place the stack above the VA hole, so we need to sign extend
+		// val before unpacking.
+		return (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> cntBits << 3)))
+	}
+	return (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
+}
diff --git a/src/runtime/lfstack_amd64.go b/src/runtime/lfstack_amd64.go
deleted file mode 100644
index 84e2851..0000000
--- a/src/runtime/lfstack_amd64.go
+++ /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.
-
-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
deleted file mode 100644
index 54cae39..0000000
--- a/src/runtime/lfstack_darwin_arm64.go
+++ /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.
-
-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
deleted file mode 100644
index 54cae39..0000000
--- a/src/runtime/lfstack_linux_arm64.go
+++ /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.
-
-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_mips64x.go b/src/runtime/lfstack_linux_mips64x.go
deleted file mode 100644
index 49b6558..0000000
--- a/src/runtime/lfstack_linux_mips64x.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2015 The Go 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 mips64 mips64le
-// +build linux
-
-package runtime
-
-import "unsafe"
-
-// On mips64, Linux limits the user address space to 40 bits (see
-// TASK_SIZE64 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_linux_ppc64x.go b/src/runtime/lfstack_linux_ppc64x.go
deleted file mode 100644
index 7ed5025..0000000
--- a/src/runtime/lfstack_linux_ppc64x.go
+++ /dev/null
@@ -1,32 +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 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/lock_futex.go b/src/runtime/lock_futex.go
index fc48029..073136a 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.go
@@ -13,13 +13,13 @@ import (
 
 // This implementation depends on OS-specific implementations of
 //
-//	runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
+//	futexsleep(addr *uint32, val uint32, ns int64)
 //		Atomically,
-//			if(*addr == val) sleep
+//			if *addr == val { sleep }
 //		Might be woken up spuriously; that's allowed.
 //		Don't sleep longer than ns; ns < 0 means forever.
 //
-//	runtime·futexwakeup(uint32 *addr, uint32 cnt)
+//	futexwakeup(addr *uint32, cnt uint32)
 //		If any procs are sleeping on addr, wake up at most cnt.
 
 const (
@@ -58,7 +58,7 @@ func lock(l *mutex) {
 
 	// wait is either MUTEX_LOCKED or MUTEX_SLEEPING
 	// depending on whether there is a thread sleeping
-	// on this mutex.  If we ever change l->key from
+	// on this mutex. If we ever change l->key from
 	// MUTEX_SLEEPING to some other value, we must be
 	// careful to change it back to MUTEX_SLEEPING before
 	// returning, to ensure that the sleeping thread gets
diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go
index d39b010..0fa0481 100644
--- a/src/runtime/lock_sema.go
+++ b/src/runtime/lock_sema.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -81,7 +81,7 @@ Loop:
 				}
 			}
 			if v&locked != 0 {
-				// Queued.  Wait.
+				// Queued. Wait.
 				semasleep(-1)
 				i = 0
 			}
@@ -143,7 +143,7 @@ func notewakeup(n *note) {
 		// Two notewakeups!  Not allowed.
 		throw("notewakeup - double wakeup")
 	default:
-		// Must be the waiting m.  Wake it up.
+		// Must be the waiting m. Wake it up.
 		semawakeup((*m)(unsafe.Pointer(v)))
 	}
 }
@@ -161,7 +161,7 @@ func notesleep(n *note) {
 		}
 		return
 	}
-	// Queued.  Sleep.
+	// Queued. Sleep.
 	gp.m.blocked = true
 	semasleep(-1)
 	gp.m.blocked = false
@@ -184,7 +184,7 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 		return true
 	}
 	if ns < 0 {
-		// Queued.  Sleep.
+		// Queued. Sleep.
 		gp.m.blocked = true
 		semasleep(-1)
 		gp.m.blocked = false
@@ -193,7 +193,7 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 
 	deadline = nanotime() + ns
 	for {
-		// Registered.  Sleep.
+		// Registered. Sleep.
 		gp.m.blocked = true
 		if semasleep(ns) >= 0 {
 			gp.m.blocked = false
@@ -202,15 +202,15 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 			return true
 		}
 		gp.m.blocked = false
-		// Interrupted or timed out.  Still registered.  Semaphore not acquired.
+		// Interrupted or timed out. Still registered. Semaphore not acquired.
 		ns = deadline - nanotime()
 		if ns <= 0 {
 			break
 		}
-		// Deadline hasn't arrived.  Keep sleeping.
+		// Deadline hasn't arrived. Keep sleeping.
 	}
 
-	// Deadline arrived.  Still registered.  Semaphore not acquired.
+	// Deadline arrived. Still registered. Semaphore not acquired.
 	// Want to give up and return, but have to unregister first,
 	// so that any notewakeup racing with the return does not
 	// try to grant us the semaphore when we don't expect it.
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index b520c68..b079a07 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -65,8 +65,8 @@
 // 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
+// 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
@@ -87,9 +87,6 @@ import (
 const (
 	debugMalloc = false
 
-	flagNoScan = _FlagNoScan
-	flagNoZero = _FlagNoZero
-
 	maxTinySize   = _TinySize
 	tinySizeClass = _TinySizeClass
 	maxSmallSize  = _MaxSmallSize
@@ -97,6 +94,9 @@ const (
 	pageShift = _PageShift
 	pageSize  = _PageSize
 	pageMask  = _PageMask
+	// By construction, single page spans of the smallest object class
+	// have the most objects per span.
+	maxObjsPerSpan = pageSize / 8
 
 	mSpanInUse = _MSpanInUse
 
@@ -113,9 +113,9 @@ 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
+	// 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
+	// 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
@@ -134,9 +134,9 @@ const (
 	// Per-P, per order stack segment cache size.
 	_StackCacheSize = 32 * 1024
 
-	// Number of orders that get caching.  Order 0 is FixedStack
+	// 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
+	// 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.
@@ -165,15 +165,12 @@ const (
 
 	// 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
+	// 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
+const _MaxArena32 = 1<<32 - 1
 
 // OS-defined helpers:
 //
@@ -192,14 +189,14 @@ const _MaxArena32 = 2 << 30
 //
 // 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.
+// 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
+// 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
+// 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
@@ -211,7 +208,7 @@ const _MaxArena32 = 2 << 30
 // reserved, not merely checked.
 //
 // SysFault marks a (already sysAlloc'd) region to fault
-// if accessed.  Used only for debugging the runtime.
+// if accessed. Used only for debugging the runtime.
 
 func mallocinit() {
 	initSizes()
@@ -229,8 +226,8 @@ func mallocinit() {
 	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.
+	// allocated data will be found. The arena begins with a bitmap large
+	// enough to hold 2 bits per allocated word.
 	if sys.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.
@@ -239,12 +236,12 @@ func mallocinit() {
 		// 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
+		// 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
+		// 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
@@ -262,7 +259,7 @@ func mallocinit() {
 		// 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 / (sys.PtrSize * 8 / 4)
+		bitmapSize = arenaSize / (sys.PtrSize * 8 / 2)
 		spansSize = arenaSize / _PageSize * sys.PtrSize
 		spansSize = round(spansSize, _PageSize)
 		for i := 0; i <= 0x7f; i++ {
@@ -287,32 +284,26 @@ func mallocinit() {
 		// 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),
+		// to handle the entire 4GB address space (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.
+		// for any memory anywhere.
 
 		// 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.
+		// In the worst case, fall back to a 0-sized initial arena,
+		// in the hope that subsequent reservations will succeed.
 		arenaSizes := []uintptr{
 			512 << 20,
 			256 << 20,
 			128 << 20,
+			0,
 		}
 
 		for _, arenaSize := range arenaSizes {
-			bitmapSize = _MaxArena32 / (sys.PtrSize * 8 / 4)
-			spansSize = _MaxArena32 / _PageSize * sys.PtrSize
+			bitmapSize = (_MaxArena32 + 1) / (sys.PtrSize * 8 / 2)
+			spansSize = (_MaxArena32 + 1) / _PageSize * sys.PtrSize
 			if limit > 0 && arenaSize+bitmapSize+spansSize > limit {
 				bitmapSize = (limit / 9) &^ ((1 << _PageShift) - 1)
 				arenaSize = bitmapSize * 8
@@ -321,10 +312,10 @@ func mallocinit() {
 			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
+			// 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
+			// 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
@@ -347,10 +338,16 @@ func mallocinit() {
 	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_.bitmap = p1 + spansSize + bitmapSize
+	if sys.PtrSize == 4 {
+		// Set arena_start such that we can accept memory
+		// reservations located anywhere in the 4GB virtual space.
+		mheap_.arena_start = 0
+	} else {
+		mheap_.arena_start = p1 + (spansSize + bitmapSize)
+	}
 	mheap_.arena_end = p + pSize
+	mheap_.arena_used = p1 + (spansSize + bitmapSize)
 	mheap_.arena_reserved = reserved
 
 	if mheap_.arena_start&(_PageSize-1) != 0 {
@@ -364,36 +361,17 @@ func mallocinit() {
 	_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 sys.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)
-}
-
+// sysAlloc allocates the next n bytes from the heap arena. The
+// returned pointer is always _PageSize aligned and between
+// h.arena_start and h.arena_end. sysAlloc returns nil on failure.
+// There is no corresponding free function.
 func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
 	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.
 		p_size := round(n+_PageSize, 256<<20)
 		new_end := h.arena_end + p_size // Careful: can overflow
-		if h.arena_end <= new_end && new_end <= h.arena_start+_MaxArena32 {
+		if h.arena_end <= new_end && new_end-h.arena_start-1 <= _MaxArena32 {
 			// TODO: It would be bad if part of the arena
 			// is reserved and part is not.
 			var reserved bool
@@ -404,11 +382,11 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
 			if p == h.arena_end {
 				h.arena_end = new_end
 				h.arena_reserved = reserved
-			} else if h.arena_start <= p && p+p_size <= h.arena_start+_MaxArena32 {
+			} else if h.arena_start <= p && p+p_size-h.arena_start-1 <= _MaxArena32 {
 				// Keep everything page-aligned.
 				// Our pages are bigger than hardware pages.
 				h.arena_end = p + p_size
-				used := p + (-uintptr(p) & (_PageSize - 1))
+				used := p + (-p & (_PageSize - 1))
 				h.mapBits(used)
 				h.mapSpans(used)
 				h.arena_used = used
@@ -434,30 +412,29 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
 			racemapshadow(unsafe.Pointer(p), n)
 		}
 
-		if uintptr(p)&(_PageSize-1) != 0 {
+		if 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 h.arena_end-h.arena_start >= _MaxArena32 {
+	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.
+	// try to get memory at a location chosen by the OS.
 	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-h.arena_start >= _MaxArena32 {
+	if p < h.arena_start || p+p_size-h.arena_start > _MaxArena32 {
 		top := ^uintptr(0)
-		if top-h.arena_start > _MaxArena32 {
-			top = h.arena_start + _MaxArena32
+		if top-h.arena_start-1 > _MaxArena32 {
+			top = h.arena_start + _MaxArena32 + 1
 		}
 		print("runtime: memory allocated by OS (", hex(p), ") not in usable range [", hex(h.arena_start), ",", hex(top), ")\n")
 		sysFree(unsafe.Pointer(p), p_size, &memstats.heap_sys)
@@ -466,7 +443,7 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
 
 	p_end := p + p_size
 	p += -p & (_PageSize - 1)
-	if uintptr(p)+n > h.arena_used {
+	if p+n > h.arena_used {
 		h.mapBits(p + n)
 		h.mapSpans(p + n)
 		h.arena_used = p + n
@@ -478,7 +455,7 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
 		}
 	}
 
-	if uintptr(p)&(_PageSize-1) != 0 {
+	if p&(_PageSize-1) != 0 {
 		throw("misrounded allocation in MHeap_SysAlloc")
 	}
 	return unsafe.Pointer(p)
@@ -487,16 +464,69 @@ func (h *mheap) sysAlloc(n uintptr) unsafe.Pointer {
 // 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
-)
+// nextFreeFast returns the next free object if one is quickly available.
+// Otherwise it returns 0.
+func nextFreeFast(s *mspan) gclinkptr {
+	theBit := sys.Ctz64(s.allocCache) // Is there a free object in the allocCache?
+	if theBit < 64 {
+		result := s.freeindex + uintptr(theBit)
+		if result < s.nelems {
+			freeidx := result + 1
+			if freeidx%64 == 0 && freeidx != s.nelems {
+				return 0
+			}
+			s.allocCache >>= (theBit + 1)
+			s.freeindex = freeidx
+			v := gclinkptr(result*s.elemsize + s.base())
+			s.allocCount++
+			return v
+		}
+	}
+	return 0
+}
+
+// nextFree returns the next free object from the cached span if one is available.
+// Otherwise it refills the cache with a span with an available object and
+// returns that object along with a flag indicating that this was a heavy
+// weight allocation. If it is a heavy weight allocation the caller must
+// determine whether a new GC cycle needs to be started or if the GC is active
+// whether this goroutine needs to assist the GC.
+func (c *mcache) nextFree(sizeclass int8) (v gclinkptr, s *mspan, shouldhelpgc bool) {
+	s = c.alloc[sizeclass]
+	shouldhelpgc = false
+	freeIndex := s.nextFreeIndex()
+	if freeIndex == s.nelems {
+		// The span is full.
+		if uintptr(s.allocCount) != s.nelems {
+			println("runtime: s.allocCount=", s.allocCount, "s.nelems=", s.nelems)
+			throw("s.allocCount != s.nelems && freeIndex == s.nelems")
+		}
+		systemstack(func() {
+			c.refill(int32(sizeclass))
+		})
+		shouldhelpgc = true
+		s = c.alloc[sizeclass]
+
+		freeIndex = s.nextFreeIndex()
+	}
+
+	if freeIndex >= s.nelems {
+		throw("freeIndex is not valid")
+	}
+
+	v = gclinkptr(freeIndex*s.elemsize + s.base())
+	s.allocCount++
+	if uintptr(s.allocCount) > s.nelems {
+		println("s.allocCount=", s.allocCount, "s.nelems=", s.nelems)
+		throw("s.allocCount > s.nelems")
+	}
+	return
+}
 
 // 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 {
+func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
 	if gcphase == _GCmarktermination {
 		throw("mallocgc called with gcphase == _GCmarktermination")
 	}
@@ -505,10 +535,6 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 		return unsafe.Pointer(&zerobase)
 	}
 
-	if flags&flagNoScan == 0 && typ == nil {
-		throw("malloc missing type")
-	}
-
 	if debug.sbrk != 0 {
 		align := uintptr(16)
 		if typ != nil {
@@ -551,16 +577,16 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 	shouldhelpgc := false
 	dataSize := size
 	c := gomcache()
-	var s *mspan
 	var x unsafe.Pointer
+	noscan := typ == nil || typ.kind&kindNoPointers != 0
 	if size <= maxSmallSize {
-		if flags&flagNoScan != 0 && size < maxTinySize {
+		if noscan && size < maxTinySize {
 			// Tiny allocator.
 			//
 			// Tiny allocator combines several tiny allocation requests
 			// into a single memory block. The resulting memory block
 			// is freed when all subobjects are unreachable. The subobjects
-			// must be FlagNoScan (don't have pointers), this ensures that
+			// must be noscan (don't have pointers), this ensures that
 			// the amount of potentially wasted memory is bounded.
 			//
 			// Size of the memory block used for combining (maxTinySize) is tunable.
@@ -603,20 +629,11 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 				return x
 			}
 			// Allocate a new maxTinySize block.
-			s = c.alloc[tinySizeClass]
-			v := s.freelist
-			if v.ptr() == nil {
-				systemstack(func() {
-					c.refill(tinySizeClass)
-				})
-				shouldhelpgc = true
-				s = c.alloc[tinySizeClass]
-				v = s.freelist
+			span := c.alloc[tinySizeClass]
+			v := nextFreeFast(span)
+			if v == 0 {
+				v, _, shouldhelpgc = c.nextFree(tinySizeClass)
 			}
-			s.freelist = v.ptr().next
-			s.ref++
-			// 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
@@ -635,40 +652,31 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 				sizeclass = size_to_class128[(size-1024+127)>>7]
 			}
 			size = uintptr(class_to_size[sizeclass])
-			s = c.alloc[sizeclass]
-			v := s.freelist
-			if v.ptr() == nil {
-				systemstack(func() {
-					c.refill(int32(sizeclass))
-				})
-				shouldhelpgc = true
-				s = c.alloc[sizeclass]
-				v = s.freelist
+			span := c.alloc[sizeclass]
+			v := nextFreeFast(span)
+			if v == 0 {
+				v, span, shouldhelpgc = c.nextFree(sizeclass)
 			}
-			s.freelist = v.ptr().next
-			s.ref++
-			// prefetchnta offers best performance, see change list message.
-			prefetchnta(uintptr(v.ptr().next))
 			x = unsafe.Pointer(v)
-			if flags&flagNoZero == 0 {
-				v.ptr().next = 0
-				if size > 2*sys.PtrSize && ((*[2]uintptr)(x))[1] != 0 {
-					memclr(unsafe.Pointer(v), size)
-				}
+			if needzero && span.needzero != 0 {
+				memclr(unsafe.Pointer(v), size)
 			}
 		}
 	} else {
 		var s *mspan
 		shouldhelpgc = true
 		systemstack(func() {
-			s = largeAlloc(size, uint32(flags))
+			s = largeAlloc(size, needzero)
 		})
-		x = unsafe.Pointer(uintptr(s.start << pageShift))
-		size = uintptr(s.elemsize)
+		s.freeindex = 1
+		s.allocCount = 1
+		x = unsafe.Pointer(s.base())
+		size = s.elemsize
 	}
 
-	if flags&flagNoScan != 0 {
-		// All objects are pre-marked as noscan. Nothing to do.
+	var scanSize uintptr
+	if noscan {
+		heapBitsSetTypeNoScan(uintptr(x))
 	} 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
@@ -685,34 +693,34 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 			// pointers, GC has to scan to the last
 			// element.
 			if typ.ptrdata != 0 {
-				c.local_scan += dataSize - typ.size + typ.ptrdata
+				scanSize = dataSize - typ.size + typ.ptrdata
 			}
 		} else {
-			c.local_scan += typ.ptrdata
+			scanSize = typ.ptrdata
 		}
-
-		// 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()
+		c.local_scan += scanSize
 	}
 
-	// GCmarkterminate allocates black
+	// 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()
+
+	// Allocate black during GC.
 	// 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 gcphase != _GCoff {
+		gcmarknewobject(uintptr(x), size, scanSize)
 	}
 
 	if raceenabled {
 		racemalloc(x, size)
 	}
+
 	if msanenabled {
 		msanmalloc(x, size)
 	}
@@ -747,7 +755,7 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 	return x
 }
 
-func largeAlloc(size uintptr, flag uint32) *mspan {
+func largeAlloc(size uintptr, needzero bool) *mspan {
 	// print("largeAlloc size=", size, "\n")
 
 	if size+_PageSize < size {
@@ -763,22 +771,18 @@ func largeAlloc(size uintptr, flag uint32) *mspan {
 	// pays the debt down to npage pages.
 	deductSweepCredit(npages*_PageSize, npages)
 
-	s := mheap_.alloc(npages, 0, true, flag&_FlagNoZero == 0)
+	s := mheap_.alloc(npages, 0, true, needzero)
 	if s == nil {
 		throw("out of memory")
 	}
-	s.limit = uintptr(s.start)<<_PageShift + size
-	heapBitsForSpan(s.base()).initSpan(s.layout())
+	s.limit = s.base() + size
+	heapBitsForSpan(s.base()).initSpan(s)
 	return s
 }
 
 // implementation of new builtin
 func newobject(typ *_type) unsafe.Pointer {
-	flags := uint32(0)
-	if typ.kind&kindNoPointers != 0 {
-		flags |= flagNoScan
-	}
-	return mallocgc(uintptr(typ.size), typ, flags)
+	return mallocgc(typ.size, typ, true)
 }
 
 //go:linkname reflect_unsafe_New reflect.unsafe_New
@@ -786,29 +790,19 @@ 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)) {
-		panic("runtime: allocation size out of range")
+// newarray allocates an array of n elements of type typ.
+func newarray(typ *_type, n int) unsafe.Pointer {
+	if n < 0 || uintptr(n) > maxSliceCap(typ.size) {
+		panic(plainError("runtime: allocation size out of range"))
 	}
-	return mallocgc(uintptr(typ.size)*n, typ, flags)
+	return mallocgc(typ.size*uintptr(n), typ, true)
 }
 
 //go:linkname reflect_unsafe_NewArray reflect.unsafe_NewArray
-func reflect_unsafe_NewArray(typ *_type, n uintptr) unsafe.Pointer {
+func reflect_unsafe_NewArray(typ *_type, n int) 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)
-}
-
 func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
 	mp.mcache.next_sample = nextSample()
 	mProf_Malloc(x, size)
@@ -847,7 +841,7 @@ func nextSample() int32 {
 	// x = -log_e(q) * period
 	// x = log_2(q) * (-log_e(2)) * period    ; Using log_2 for efficiency
 	const randomBitCount = 26
-	q := uint32(fastrand1())%(1<<randomBitCount) + 1
+	q := fastrand1()%(1<<randomBitCount) + 1
 	qlog := fastlog2(float64(q)) - randomBitCount
 	if qlog > 0 {
 		qlog = 0
diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go
index 9d2894c..496f8e8 100644
--- a/src/runtime/map_test.go
+++ b/src/runtime/map_test.go
@@ -317,6 +317,22 @@ func TestBigItems(t *testing.T) {
 	}
 }
 
+func TestMapHugeZero(t *testing.T) {
+	type T [4000]byte
+	m := map[int]T{}
+	x := m[0]
+	if x != (T{}) {
+		t.Errorf("map value not zero")
+	}
+	y, ok := m[0]
+	if ok {
+		t.Errorf("map value should be missing")
+	}
+	if y != (T{}) {
+		t.Errorf("map value not zero")
+	}
+}
+
 type empty struct {
 }
 
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
index 45086c4..bf75934 100644
--- a/src/runtime/mbarrier.go
+++ b/src/runtime/mbarrier.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -87,6 +87,17 @@ import (
 // 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.
+//
+//
+// Global writes:
+//
+// The Go garbage collector requires write barriers when heap pointers
+// are stored in globals. Many garbage collectors ignore writes to
+// globals and instead pick up global -> heap pointers during
+// termination. This increases pause time, so we instead rely on write
+// barriers for writes to globals so that we don't have to rescan
+// global during mark termination.
+//
 //go:nowritebarrierrec
 func gcmarkwb_m(slot *uintptr, ptr uintptr) {
 	if writeBarrier.needed {
@@ -100,7 +111,7 @@ func gcmarkwb_m(slot *uintptr, ptr uintptr) {
 // 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
+// queues and so forth. This code cannot 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
@@ -134,7 +145,7 @@ func writebarrierptr(dst *uintptr, src uintptr) {
 	if !writeBarrier.needed {
 		return
 	}
-	if src != 0 && (src < sys.PhysPageSize || src == poisonStack) {
+	if src != 0 && src < sys.PhysPageSize {
 		systemstack(func() {
 			print("runtime: writebarrierptr *", dst, " = ", hex(src), "\n")
 			throw("bad pointer in write barrier")
@@ -153,37 +164,12 @@ func writebarrierptr_nostore(dst *uintptr, src uintptr) {
 	if !writeBarrier.needed {
 		return
 	}
-	if src != 0 && (src < sys.PhysPageSize || src == poisonStack) {
+	if src != 0 && src < sys.PhysPageSize {
 		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) {
@@ -210,7 +196,7 @@ func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size
 	if writeBarrier.cgo {
 		cgoCheckMemmove(typ, dst, src, off, size)
 	}
-	if !writeBarrier.needed || typ.kind&kindNoPointers != 0 || size < sys.PtrSize || !inheap(uintptr(dst)) {
+	if !writeBarrier.needed || typ.kind&kindNoPointers != 0 || size < sys.PtrSize {
 		return
 	}
 
@@ -226,11 +212,11 @@ func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size
 // 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.
+// happened, we call writebarrierptr_nostore, and this is nosplit so
+// the copy and write barrier appear atomic to GC.
 //go:nosplit
 func callwritebarrier(typ *_type, frame unsafe.Pointer, framesize, retoffset uintptr) {
-	if !writeBarrier.needed || typ == nil || typ.kind&kindNoPointers != 0 || framesize-retoffset < sys.PtrSize || !inheap(uintptr(frame)) {
+	if !writeBarrier.needed || typ == nil || typ.kind&kindNoPointers != 0 || framesize-retoffset < sys.PtrSize {
 		return
 	}
 	heapBitsBulkBarrier(uintptr(add(frame, retoffset)), framesize-retoffset)
@@ -247,8 +233,8 @@ func typedslicecopy(typ *_type, dst, src slice) int {
 	if n == 0 {
 		return 0
 	}
-	dstp := unsafe.Pointer(dst.array)
-	srcp := unsafe.Pointer(src.array)
+	dstp := dst.array
+	srcp := src.array
 
 	if raceenabled {
 		callerpc := getcallerpc(unsafe.Pointer(&typ))
@@ -304,7 +290,7 @@ func typedslicecopy(typ *_type, dst, src slice) int {
 			}
 		}
 	})
-	return int(n)
+	return n
 }
 
 //go:linkname reflect_typedslicecopy reflect.typedslicecopy
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index 336d4d8..ccefbcd 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -24,21 +24,24 @@
 // 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 its allocated object. In all words *except* the second word, 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.
+//
 // 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.
+// of the byte contains 4 high bits and the bottom half contains 4 low (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,
+// has no live pointer bit set and is (depending on position), not used,
 // not checkmarked, and is the dead encoding.
 // These properties must be preserved when modifying the encoding.
 //
@@ -63,6 +66,7 @@
 // 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
 
@@ -74,7 +78,7 @@ import (
 
 const (
 	bitPointer = 1 << 0
-	bitMarked  = 1 << 4
+	bitMarked  = 1 << 4 // TODO: Rename bitScan.
 
 	heapBitsShift   = 1                     // shift offset between successive bitPointer or bitMarked entries
 	heapBitmapScale = sys.PtrSize * (8 / 2) // number of data bytes described by one heap bitmap byte
@@ -86,6 +90,7 @@ const (
 
 // addb returns the byte pointer p+n.
 //go:nowritebarrier
+//go:nosplit
 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
@@ -94,7 +99,10 @@ func addb(p *byte, n uintptr) *byte {
 }
 
 // subtractb returns the byte pointer p-n.
+// subtractb is typically used when traversing the pointer tables referred to by hbits
+// which are arranged in reverse order.
 //go:nowritebarrier
+//go:nosplit
 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
@@ -104,6 +112,7 @@ func subtractb(p *byte, n uintptr) *byte {
 
 // add1 returns the byte pointer p+1.
 //go:nowritebarrier
+//go:nosplit
 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
@@ -112,6 +121,8 @@ func add1(p *byte) *byte {
 }
 
 // subtract1 returns the byte pointer p-1.
+// subtract1 is typically used when traversing the pointer tables referred to by hbits
+// which are arranged in reverse order.
 //go:nowritebarrier
 //
 // nosplit because it is used during write barriers and must not be preempted.
@@ -145,7 +156,7 @@ func (h *mheap) mapBits(arena_used uintptr) {
 		return
 	}
 
-	sysMap(unsafe.Pointer(h.arena_start-n), n-h.bitmap_mapped, h.arena_reserved, &memstats.gc_sys)
+	sysMap(unsafe.Pointer(h.bitmap-n), n-h.bitmap_mapped, h.arena_reserved, &memstats.gc_sys)
 	h.bitmap_mapped = n
 }
 
@@ -158,6 +169,193 @@ type heapBits struct {
 	shift uint32
 }
 
+// markBits provides access to the mark bit for an object in the heap.
+// bytep points to the byte holding the mark bit.
+// mask is a byte with a single bit set that can be &ed with *bytep
+// to see if the bit has been set.
+// *m.byte&m.mask != 0 indicates the mark bit is set.
+// index can be used along with span information to generate
+// the address of the object in the heap.
+// We maintain one set of mark bits for allocation and one for
+// marking purposes.
+type markBits struct {
+	bytep *uint8
+	mask  uint8
+	index uintptr
+}
+
+//go:nosplit
+func (s *mspan) allocBitsForIndex(allocBitIndex uintptr) markBits {
+	whichByte := allocBitIndex / 8
+	whichBit := allocBitIndex % 8
+	bytePtr := addb(s.allocBits, whichByte)
+	return markBits{bytePtr, uint8(1 << whichBit), allocBitIndex}
+}
+
+// refillaCache takes 8 bytes s.allocBits starting at whichByte
+// and negates them so that ctz (count trailing zeros) instructions
+// can be used. It then places these 8 bytes into the cached 64 bit
+// s.allocCache.
+func (s *mspan) refillAllocCache(whichByte uintptr) {
+	bytes := (*[8]uint8)(unsafe.Pointer(addb(s.allocBits, whichByte)))
+	aCache := uint64(0)
+	aCache |= uint64(bytes[0])
+	aCache |= uint64(bytes[1]) << (1 * 8)
+	aCache |= uint64(bytes[2]) << (2 * 8)
+	aCache |= uint64(bytes[3]) << (3 * 8)
+	aCache |= uint64(bytes[4]) << (4 * 8)
+	aCache |= uint64(bytes[5]) << (5 * 8)
+	aCache |= uint64(bytes[6]) << (6 * 8)
+	aCache |= uint64(bytes[7]) << (7 * 8)
+	s.allocCache = ^aCache
+}
+
+// nextFreeIndex returns the index of the next free object in s at
+// or after s.freeindex.
+// There are hardware instructions that can be used to make this
+// faster if profiling warrants it.
+func (s *mspan) nextFreeIndex() uintptr {
+	sfreeindex := s.freeindex
+	snelems := s.nelems
+	if sfreeindex == snelems {
+		return sfreeindex
+	}
+	if sfreeindex > snelems {
+		throw("s.freeindex > s.nelems")
+	}
+
+	aCache := s.allocCache
+
+	bitIndex := sys.Ctz64(aCache)
+	for bitIndex == 64 {
+		// Move index to start of next cached bits.
+		sfreeindex = (sfreeindex + 64) &^ (64 - 1)
+		if sfreeindex >= snelems {
+			s.freeindex = snelems
+			return snelems
+		}
+		whichByte := sfreeindex / 8
+		// Refill s.allocCache with the next 64 alloc bits.
+		s.refillAllocCache(whichByte)
+		aCache = s.allocCache
+		bitIndex = sys.Ctz64(aCache)
+		// nothing available in cached bits
+		// grab the next 8 bytes and try again.
+	}
+	result := sfreeindex + uintptr(bitIndex)
+	if result >= snelems {
+		s.freeindex = snelems
+		return snelems
+	}
+
+	s.allocCache >>= (bitIndex + 1)
+	sfreeindex = result + 1
+
+	if sfreeindex%64 == 0 && sfreeindex != snelems {
+		// We just incremented s.freeindex so it isn't 0.
+		// As each 1 in s.allocCache was encountered and used for allocation
+		// it was shifted away. At this point s.allocCache contains all 0s.
+		// Refill s.allocCache so that it corresponds
+		// to the bits at s.allocBits starting at s.freeindex.
+		whichByte := sfreeindex / 8
+		s.refillAllocCache(whichByte)
+	}
+	s.freeindex = sfreeindex
+	return result
+}
+
+func (s *mspan) isFree(index uintptr) bool {
+	whichByte := index / 8
+	whichBit := index % 8
+	byteVal := *addb(s.allocBits, whichByte)
+	return byteVal&uint8(1<<whichBit) == 0
+}
+
+func (s *mspan) objIndex(p uintptr) uintptr {
+	byteOffset := p - s.base()
+	if byteOffset == 0 {
+		return 0
+	}
+	if s.baseMask != 0 {
+		// s.baseMask is 0, elemsize is a power of two, so shift by s.divShift
+		return byteOffset >> s.divShift
+	}
+	return uintptr(((uint64(byteOffset) >> s.divShift) * uint64(s.divMul)) >> s.divShift2)
+}
+
+func markBitsForAddr(p uintptr) markBits {
+	s := spanOf(p)
+	objIndex := s.objIndex(p)
+	return s.markBitsForIndex(objIndex)
+}
+
+func (s *mspan) markBitsForIndex(objIndex uintptr) markBits {
+	whichByte := objIndex / 8
+	bitMask := uint8(1 << (objIndex % 8)) // low 3 bits hold the bit index
+	bytePtr := addb(s.gcmarkBits, whichByte)
+	return markBits{bytePtr, bitMask, objIndex}
+}
+
+func (s *mspan) markBitsForBase() markBits {
+	return markBits{s.gcmarkBits, uint8(1), 0}
+}
+
+// isMarked reports whether mark bit m is set.
+func (m markBits) isMarked() bool {
+	return *m.bytep&m.mask != 0
+}
+
+// setMarked sets the marked bit in the markbits, atomically. Some compilers
+// are not able to inline atomic.Or8 function so if it appears as a hot spot consider
+// inlining it manually.
+func (m markBits) setMarked() {
+	// 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.
+	atomic.Or8(m.bytep, m.mask)
+}
+
+// setMarkedNonAtomic sets the marked bit in the markbits, non-atomically.
+func (m markBits) setMarkedNonAtomic() {
+	*m.bytep |= m.mask
+}
+
+// clearMarked clears the marked bit in the markbits, atomically.
+func (m markBits) clearMarked() {
+	// 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.
+	atomic.And8(m.bytep, ^m.mask)
+}
+
+// clearMarkedNonAtomic clears the marked bit non-atomically.
+func (m markBits) clearMarkedNonAtomic() {
+	*m.bytep ^= m.mask
+}
+
+// markBitsForSpan returns the markBits for the span base address base.
+func markBitsForSpan(base uintptr) (mbits markBits) {
+	if base < mheap_.arena_start || base >= mheap_.arena_used {
+		throw("heapBitsForSpan: base out of range")
+	}
+	mbits = markBitsForAddr(base)
+	if mbits.mask != 1 {
+		throw("markBitsForSpan: unaligned start")
+	}
+	return mbits
+}
+
+// advance advances the markBits to the next object in the span.
+func (m *markBits) advance() {
+	if m.mask == 1<<7 {
+		m.bytep = (*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(m.bytep)) + 1))
+		m.mask = 1
+	} else {
+		m.mask = m.mask << 1
+	}
+	m.index++
+}
+
 // 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).
 //
@@ -166,7 +364,7 @@ type heapBits struct {
 func heapBitsForAddr(addr uintptr) heapBits {
 	// 2 bits per work, 4 pairs per byte, and a mask is hard coded.
 	off := (addr - mheap_.arena_start) / sys.PtrSize
-	return heapBits{(*uint8)(unsafe.Pointer(mheap_.arena_start - off/4 - 1)), uint32(off & 3)}
+	return heapBits{(*uint8)(unsafe.Pointer(mheap_.bitmap - off/4 - 1)), uint32(off & 3)}
 }
 
 // heapBitsForSpan returns the heapBits for the span base address base.
@@ -174,15 +372,12 @@ 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
+	return heapBitsForAddr(base)
 }
 
 // heapBitsForObject returns the base address for the heap object
-// containing the address p, along with the heapBits for base.
+// containing the address p, the heapBits for base,
+// the object's span, and of the index of the object in s.
 // If p does not point into a heap object,
 // return base == 0
 // otherwise return the base of the object.
@@ -190,7 +385,7 @@ func heapBitsForSpan(base uintptr) (hbits heapBits) {
 // refBase and refOff optionally give the base address of the object
 // in which the pointer p was found and the byte offset at which it
 // was found. These are used for error reporting.
-func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits, s *mspan) {
+func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits, s *mspan, objIndex uintptr) {
 	arenaStart := mheap_.arena_start
 	if p < arenaStart || p >= mheap_.arena_used {
 		return
@@ -199,9 +394,8 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
 	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 || p < s.base() || 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.
@@ -227,7 +421,7 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
 			} else {
 				print(" to unused region of span")
 			}
-			print("idx=", hex(idx), " span.start=", hex(s.start<<_PageShift), " span.limit=", hex(s.limit), " span.state=", s.state, "\n")
+			print("idx=", hex(idx), " span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", s.state, "\n")
 			if refBase != 0 {
 				print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n")
 				gcDumpObject("object", refBase, refOff)
@@ -242,6 +436,7 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
 		// optimize for power of 2 sized objects.
 		base = s.base()
 		base = base + (p-base)&s.baseMask
+		objIndex = (base - s.base()) >> s.divShift
 		// 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.
@@ -249,8 +444,8 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
 		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
+			objIndex = uintptr(uint64(p-base) >> s.divShift * uint64(s.divMul) >> s.divShift2)
+			base += objIndex * s.elemsize
 		}
 	}
 	// Now that we know the actual base, compute heapBits to return to caller.
@@ -290,64 +485,34 @@ func (h heapBits) forward(n uintptr) heapBits {
 // 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.
-	atomic.Or8(h.bitp, bitMarked<<h.shift)
+	// The (shift & 31) eliminates a test and conditional branch
+	// from the generated code.
+	return uint32(*h.bitp) >> (h.shift & 31)
 }
 
-// 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
+// morePointers returns true if this word and all remaining words in this object
+// are scalars.
+// h must not describe the second word of the object.
+func (h heapBits) morePointers() bool {
+	return h.bits()&bitMarked != 0
 }
 
 // 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
+	return h.bits()&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.
+// It must be told how large the object at h is for efficiency.
 // h must describe the initial word of the object.
 func (h heapBits) hasPointers(size uintptr) bool {
 	if size == sys.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 2, 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*sys.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
+	return (*h.bitp>>h.shift)&bitMarked != 0
 }
 
 // isCheckmarked reports whether the heap bits have the checkmarked bit set.
@@ -379,10 +544,10 @@ func (h heapBits) setCheckmarked(size uintptr) {
 
 // heapBitsBulkBarrier executes writebarrierptr_nostore
 // for every pointer slot in the memory range [p, p+size),
-// using the heap bitmap to locate those pointer slots.
+// using the heap, data, or BSS 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.
+// The range [p, p+size) must lie within a single object.
 //
 // Callers should call heapBitsBulkBarrier immediately after
 // calling memmove(p, src, size). This function is marked nosplit
@@ -426,6 +591,22 @@ func heapBitsBulkBarrier(p, size uintptr) {
 			systemstack(func() {
 				gcUnwindBarriers(gp, p)
 			})
+			return
+		}
+
+		// If p is a global, use the data or BSS bitmaps to
+		// execute write barriers.
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			if datap.data <= p && p < datap.edata {
+				bulkBarrierBitmap(p, size, p-datap.data, datap.gcdatamask.bytedata)
+				return
+			}
+		}
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			if datap.bss <= p && p < datap.ebss {
+				bulkBarrierBitmap(p, size, p-datap.bss, datap.gcbssmask.bytedata)
+				return
+			}
 		}
 		return
 	}
@@ -440,6 +621,36 @@ func heapBitsBulkBarrier(p, size uintptr) {
 	}
 }
 
+// bulkBarrierBitmap executes write barriers for [p, p+size) using a
+// 1-bit pointer bitmap. p is assumed to start maskOffset bytes into
+// the data covered by the bitmap in bits.
+//
+// This is used by heapBitsBulkBarrier for writes to data and BSS.
+//
+//go:nosplit
+func bulkBarrierBitmap(p, size, maskOffset uintptr, bits *uint8) {
+	word := maskOffset / sys.PtrSize
+	bits = addb(bits, word/8)
+	mask := uint8(1) << (word % 8)
+
+	for i := uintptr(0); i < size; i += sys.PtrSize {
+		if mask == 0 {
+			bits = addb(bits, 1)
+			if *bits == 0 {
+				// Skip 8 words.
+				i += 7 * sys.PtrSize
+				continue
+			}
+			mask = 1
+		}
+		if *bits&mask != 0 {
+			x := (*uintptr)(unsafe.Pointer(p + i))
+			writebarrierptr_nostore(x, *x)
+		}
+		mask <<= 1
+	}
+}
+
 // typeBitsBulkBarrier executes writebarrierptr_nostore
 // for every pointer slot in the memory range [p, p+size),
 // using the type bitmap to locate those pointer slots.
@@ -459,11 +670,11 @@ func typeBitsBulkBarrier(typ *_type, p, size uintptr) {
 		throw("runtime: typeBitsBulkBarrier without type")
 	}
 	if typ.size != size {
-		println("runtime: typeBitsBulkBarrier with type ", *typ._string, " of size ", typ.size, " but memory 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")
+		println("runtime: typeBitsBulkBarrier with type ", typ.string(), " with GC prog")
 		throw("runtime: invalid typeBitsBulkBarrier")
 	}
 	if !writeBarrier.needed {
@@ -494,7 +705,23 @@ func typeBitsBulkBarrier(typ *_type, p, size uintptr) {
 // TODO(rsc): Perhaps introduce a different heapBitsSpan type.
 
 // initSpan initializes the heap bitmap for a span.
-func (h heapBits) initSpan(size, n, total uintptr) {
+// It clears all checkmark bits.
+// If this is a span of pointer-sized objects, it initializes all
+// words to pointer/scan.
+// Otherwise, it initializes all words to scalar/dead.
+func (h heapBits) initSpan(s *mspan) {
+	size, n, total := s.layout()
+
+	// Init the markbit structures
+	s.freeindex = 0
+	s.allocCache = ^uint64(0) // all 1s indicating all free.
+	s.nelems = n
+	s.allocBits = nil
+	s.gcmarkBits = nil
+	s.gcmarkBits = newMarkBits(s.nelems)
+	s.allocBits = newAllocBits(s.nelems)
+
+	// Clear bits corresponding to objects.
 	if total%heapBitmapScale != 0 {
 		throw("initSpan: unaligned length")
 	}
@@ -503,7 +730,7 @@ func (h heapBits) initSpan(size, n, total uintptr) {
 		end := h.bitp
 		bitp := subtractb(end, nbyte-1)
 		for {
-			*bitp = bitPointerAll
+			*bitp = bitPointerAll | bitMarkedAll
 			if bitp == end {
 				break
 			}
@@ -555,106 +782,60 @@ func (h heapBits) clearCheckmarkSpan(size, n, total uintptr) {
 	}
 }
 
-// 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 sys.PtrSize == 8 && size == sys.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*sys.PtrSize)
-			}
-			if x&(bitMarked<<heapBitsShift) != 0 {
-				x &^= bitMarked << heapBitsShift
-			} else {
-				f(base + (i+1)*sys.PtrSize)
-			}
-			if x&(bitMarked<<(2*heapBitsShift)) != 0 {
-				x &^= bitMarked << (2 * heapBitsShift)
-			} else {
-				f(base + (i+2)*sys.PtrSize)
-			}
-			if x&(bitMarked<<(3*heapBitsShift)) != 0 {
-				x &^= bitMarked << (3 * heapBitsShift)
-			} else {
-				f(base + (i+3)*sys.PtrSize)
-			}
-			*bitp = uint8(x)
-			bitp = subtract1(bitp)
-		}
-
-	case size%(4*sys.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*sys.PtrSize) == 2*sys.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*sys.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*sys.PtrSize {
-					*subtract1(bitp) = 0
-				}
-			}
-			*bitp = uint8(x)
-			bitp = subtractb(bitp, step+1)
-		}
+// oneBitCount is indexed by byte and produces the
+// number of 1 bits in that byte. For example 128 has 1 bit set
+// and oneBitCount[128] will holds 1.
+var oneBitCount = [256]uint8{
+	0, 1, 1, 2, 1, 2, 2, 3,
+	1, 2, 2, 3, 2, 3, 3, 4,
+	1, 2, 2, 3, 2, 3, 3, 4,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	1, 2, 2, 3, 2, 3, 3, 4,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	1, 2, 2, 3, 2, 3, 3, 4,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	4, 5, 5, 6, 5, 6, 6, 7,
+	1, 2, 2, 3, 2, 3, 3, 4,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	4, 5, 5, 6, 5, 6, 6, 7,
+	2, 3, 3, 4, 3, 4, 4, 5,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	4, 5, 5, 6, 5, 6, 6, 7,
+	3, 4, 4, 5, 4, 5, 5, 6,
+	4, 5, 5, 6, 5, 6, 6, 7,
+	4, 5, 5, 6, 5, 6, 6, 7,
+	5, 6, 6, 7, 6, 7, 7, 8}
+
+// countFree runs through the mark bits in a span and counts the number of free objects
+// in the span.
+// TODO:(rlh) Use popcount intrinsic.
+func (s *mspan) countFree() int {
+	count := 0
+	maxIndex := s.nelems / 8
+	for i := uintptr(0); i < maxIndex; i++ {
+		mrkBits := *addb(s.gcmarkBits, i)
+		count += int(oneBitCount[mrkBits])
 	}
+	if bitsInLastByte := s.nelems % 8; bitsInLastByte != 0 {
+		mrkBits := *addb(s.gcmarkBits, maxIndex)
+		mask := uint8((1 << bitsInLastByte) - 1)
+		bits := mrkBits & mask
+		count += int(oneBitCount[bits])
+	}
+	return int(s.nelems) - count
 }
 
 // heapBitsSetType records that the new allocation [x, x+size)
@@ -666,16 +847,23 @@ func heapBitsSweepSpan(base, size, n uintptr, f func(uintptr)) {
 // 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.
+// and the bitmap for a span always falls on byte boundaries,
+// so there are no write-write races for access to the heap bitmap.
+// Hence, heapBitsSetType can access the bitmap without atomics.
+//
+// There can be read-write races between heapBitsSetType and things
+// that read the heap bitmap like scanobject. However, since
+// heapBitsSetType is only used for objects that have not yet been
+// made reachable, readers will ignore bits being modified by this
+// function. This does mean this function cannot transiently modify
+// bits that belong to neighboring objects. Also, on weakly-ordered
+// machines, callers must execute a store/store (publication) barrier
+// between calling this function and making the object reachable.
+//
+// TODO: This still has atomic accesses left over from when it could
+// race with GC accessing mark bits in the bitmap. Remove these.
 func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 	const doubleCheck = false // slow but helpful; enable to test modifications to this code
 
@@ -684,7 +872,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 	// 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
+	// The checks for size == sys.PtrSize and size == 2*sys.PtrSize can therefore
 	// assume that dataSize == size without checking it explicitly.
 
 	if sys.PtrSize == 8 && size == sys.PtrSize {
@@ -701,6 +889,9 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 			if !h.isPointer() {
 				throw("heapBitsSetType: pointer bit missing")
 			}
+			if !h.morePointers() {
+				throw("heapBitsSetType: scan bit missing")
+			}
 		}
 		return
 	}
@@ -724,23 +915,27 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 			// (In general the number of instances of typ being allocated is
 			// dataSize/typ.size.)
 			if sys.PtrSize == 4 && dataSize == sys.PtrSize {
-				// 1 pointer.
+				// 1 pointer object. On 32-bit machines clear the bit for the
+				// unused second word.
 				if gcphase == _GCoff {
-					*h.bitp |= bitPointer << h.shift
+					*h.bitp &^= (bitPointer | bitMarked | ((bitPointer | bitMarked) << heapBitsShift)) << h.shift
+					*h.bitp |= (bitPointer | bitMarked) << h.shift
 				} else {
-					atomic.Or8(h.bitp, bitPointer<<h.shift)
+					atomic.And8(h.bitp, ^uint8((bitPointer|bitMarked|((bitPointer|bitMarked)<<heapBitsShift))<<h.shift))
+					atomic.Or8(h.bitp, (bitPointer|bitMarked)<<h.shift)
 				}
 			} else {
 				// 2-element slice of pointer.
 				if gcphase == _GCoff {
-					*h.bitp |= (bitPointer | bitPointer<<heapBitsShift) << h.shift
+					*h.bitp |= (bitPointer | bitMarked | bitPointer<<heapBitsShift) << h.shift
 				} else {
-					atomic.Or8(h.bitp, (bitPointer|bitPointer<<heapBitsShift)<<h.shift)
+					atomic.Or8(h.bitp, (bitPointer|bitMarked|bitPointer<<heapBitsShift)<<h.shift)
 				}
 			}
 			return
 		}
-		// Otherwise typ.size must be 2*ptrSize, and typ.kind&kindGCProg == 0.
+		// Otherwise typ.size must be 2*sys.PtrSize,
+		// and typ.kind&kindGCProg == 0.
 		if doubleCheck {
 			if typ.size != 2*sys.PtrSize || typ.kind&kindGCProg != 0 {
 				print("runtime: heapBitsSetType size=", size, " but typ.size=", typ.size, " gcprog=", typ.kind&kindGCProg != 0, "\n")
@@ -748,10 +943,21 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 			}
 		}
 		b := uint32(*ptrmask)
-		hb := b & 3
+		hb := (b & 3) | bitMarked
 		if gcphase == _GCoff {
+			// bitPointer == 1, bitMarked is 1 << 4, heapBitsShift is 1.
+			// 110011 is shifted h.shift and complemented.
+			// This clears out the bits that are about to be
+			// ored into *h.hbitp in the next instructions.
+			*h.bitp &^= (bitPointer | bitMarked | ((bitPointer | bitMarked) << heapBitsShift)) << h.shift
 			*h.bitp |= uint8(hb << h.shift)
 		} else {
+			// TODO:(rlh) since the GC is not concurrently setting the
+			// mark bits in the heap map anymore and malloc
+			// owns the span we are allocating in why does this have
+			// to be atomic?
+
+			atomic.And8(h.bitp, ^uint8((bitPointer|bitMarked|((bitPointer|bitMarked)<<heapBitsShift))<<h.shift))
 			atomic.Or8(h.bitp, uint8(hb<<h.shift))
 		}
 		return
@@ -865,8 +1071,8 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 			// 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,
+			// Since we loaded typ.ptrdata/sys.PtrSize bits
+			// but are pretending to have typ.size/sys.PtrSize,
 			// there might be no replication necessary/possible.
 			pbits = b
 			endnb = nb
@@ -910,7 +1116,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 	}
 	if nw == 0 {
 		// No pointers! Caller was supposed to check.
-		println("runtime: invalid type ", *typ._string)
+		println("runtime: invalid type ", typ.string())
 		throw("heapBitsSetType: called with non-pointer type")
 		return
 	}
@@ -921,8 +1127,8 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 	}
 
 	// 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 byte is special because it contains the bits for word 1,
+	// which does 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 {
@@ -932,12 +1138,20 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 	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.
+		//
+		// The first byte we write out covers the first four
+		// words of the object. The scan/dead bit on the first
+		// word must be set to scan since there are pointers
+		// somewhere in the object. The scan/dead bit on the
+		// second word is the checkmark, so we don't set it.
+		// In all following words, we set the scan/dead
+		// appropriately to indicate that the object contains
+		// to the next 2-bit entry in the bitmap.
+		//
+		// TODO: It doesn't matter if we set the checkmark, so
+		// maybe this case isn't needed any more.
 		hb = b & bitPointerAll
-		hb |= bitMarked<<(2*heapBitsShift) | bitMarked<<(3*heapBitsShift)
+		hb |= bitMarked | bitMarked<<(2*heapBitsShift) | bitMarked<<(3*heapBitsShift)
 		if w += 4; w >= nw {
 			goto Phase3
 		}
@@ -957,13 +1171,19 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
 		// 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)
+		hb = (b & (bitPointer | bitPointer<<heapBitsShift)) << (2 * heapBitsShift)
+		// This is not noscan, so set the scan bit in the
+		// first word.
+		hb |= bitMarked << (2 * heapBitsShift)
 		b >>= 2
 		nb -= 2
-		// Note: no bitMarker in hb because the first two words don't get markers from us.
+		// Note: no bitMarker for second word because that's
+		// the checkmark.
 		if gcphase == _GCoff {
+			*hbitp &^= uint8((bitPointer | bitMarked | (bitPointer << heapBitsShift)) << (2 * heapBitsShift))
 			*hbitp |= uint8(hb)
 		} else {
+			atomic.And8(hbitp, ^(uint8(bitPointer|bitMarked|bitPointer<<heapBitsShift) << (2 * heapBitsShift)))
 			atomic.Or8(hbitp, uint8(hb))
 		}
 		hbitp = subtract1(hbitp)
@@ -1094,7 +1314,7 @@ Phase4:
 	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)
+			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)
@@ -1123,14 +1343,14 @@ Phase4:
 				if j < nptr && (*addb(ptrmask, j/8)>>(j%8))&1 != 0 {
 					want |= bitPointer
 				}
-				if i >= 2 {
+				if i != 1 {
 					want |= bitMarked
 				} else {
 					have &^= bitMarked
 				}
 			}
 			if have != want {
-				println("mismatch writing bits for", *typ._string, "x", dataSize/typ.size)
+				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")
@@ -1153,6 +1373,13 @@ Phase4:
 	}
 }
 
+// heapBitsSetTypeNoScan marks x as noscan by setting the first word
+// of x in the heap bitmap to scalar/dead.
+func heapBitsSetTypeNoScan(x uintptr) {
+	h := heapBitsForAddr(uintptr(x))
+	*h.bitp &^= (bitPointer | bitMarked) << h.shift
+}
+
 var debugPtrmask struct {
 	lock mutex
 	data *byte
@@ -1246,7 +1473,7 @@ func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize u
 
 // 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.
+// The resulting bitvector will have no more than size/sys.PtrSize bits.
 func progToPointerMask(prog *byte, size uintptr) bitvector {
 	n := (size/sys.PtrSize + 7) / 8
 	x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1]
@@ -1382,7 +1609,7 @@ Run:
 		// 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 cutoff is sys.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
@@ -1556,12 +1783,6 @@ Run:
 			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
 }
@@ -1677,7 +1898,7 @@ func getgcmask(ep interface{}) (mask []byte) {
 			if hbits.isPointer() {
 				mask[i/sys.PtrSize] = 1
 			}
-			if i >= 2*sys.PtrSize && !hbits.isMarked() {
+			if i != 1*sys.PtrSize && !hbits.morePointers() {
 				mask = mask[:i/sys.PtrSize]
 				break
 			}
diff --git a/src/runtime/mcache.go b/src/runtime/mcache.go
index b06d354..5938e53 100644
--- a/src/runtime/mcache.go
+++ b/src/runtime/mcache.go
@@ -101,16 +101,18 @@ func freemcache(c *mcache) {
 }
 
 // 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.
+// to be the cached span for the given sizeclass. Returns this span.
 func (c *mcache) refill(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 uintptr(s.allocCount) != s.nelems {
+		throw("refill of span with free space remaining")
 	}
+
 	if s != &emptymspan {
 		s.incache = false
 	}
@@ -120,10 +122,11 @@ func (c *mcache) refill(sizeclass int32) *mspan {
 	if s == nil {
 		throw("out of memory")
 	}
-	if s.freelist.ptr() == nil {
-		println(s.ref, (s.npages<<_PageShift)/s.elemsize)
-		throw("empty span")
+
+	if uintptr(s.allocCount) == s.nelems {
+		throw("span has no free space")
 	}
+
 	c.alloc[sizeclass] = s
 	_g_.m.locks--
 	return s
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
index 29a7b77..7b63110 100644
--- a/src/runtime/mcentral.go
+++ b/src/runtime/mcentral.go
@@ -18,7 +18,7 @@ import "runtime/internal/atomic"
 type mcentral struct {
 	lock      mutex
 	sizeclass int32
-	nonempty  mSpanList // list of spans with a free object
+	nonempty  mSpanList // list of spans with a free object, ie a nonempty free list
 	empty     mSpanList // list of spans with no free objects (or cached in an mcache)
 }
 
@@ -67,7 +67,9 @@ retry:
 			c.empty.insertBack(s)
 			unlock(&c.lock)
 			s.sweep(true)
-			if s.freelist.ptr() != nil {
+			freeIndex := s.nextFreeIndex()
+			if freeIndex != s.nelems {
+				s.freeindex = freeIndex
 				goto havespan
 			}
 			lock(&c.lock)
@@ -98,11 +100,11 @@ retry:
 	// c is unlocked.
 havespan:
 	cap := int32((s.npages << _PageShift) / s.elemsize)
-	n := cap - int32(s.ref)
-	if n == 0 {
-		throw("empty span")
+	n := cap - int32(s.allocCount)
+	if n == 0 || s.freeindex == s.nelems || uintptr(s.allocCount) == s.nelems {
+		throw("span has no free objects")
 	}
-	usedBytes := uintptr(s.ref) * s.elemsize
+	usedBytes := uintptr(s.allocCount) * s.elemsize
 	if usedBytes > 0 {
 		reimburseSweepCredit(usedBytes)
 	}
@@ -115,10 +117,16 @@ havespan:
 		// heap_live changed.
 		gcController.revise()
 	}
-	if s.freelist.ptr() == nil {
-		throw("freelist empty")
-	}
 	s.incache = true
+	freeByteBase := s.freeindex &^ (64 - 1)
+	whichByte := freeByteBase / 8
+	// Init alloc bits cache.
+	s.refillAllocCache(whichByte)
+
+	// Adjust the allocCache so that s.freeindex corresponds to the low bit in
+	// s.allocCache.
+	s.allocCache >>= s.freeindex % 64
+
 	return s
 }
 
@@ -128,12 +136,12 @@ func (c *mcentral) uncacheSpan(s *mspan) {
 
 	s.incache = false
 
-	if s.ref == 0 {
-		throw("uncaching full span")
+	if s.allocCount == 0 {
+		throw("uncaching span but s.allocCount == 0")
 	}
 
 	cap := int32((s.npages << _PageShift) / s.elemsize)
-	n := cap - int32(s.ref)
+	n := cap - int32(s.allocCount)
 	if n > 0 {
 		c.empty.remove(s)
 		c.nonempty.insert(s)
@@ -144,22 +152,19 @@ func (c *mcentral) uncacheSpan(s *mspan) {
 	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 (c *mcentral) freeSpan(s *mspan, n int32, start gclinkptr, end gclinkptr, preserve bool) bool {
+// freeSpan updates c and s after sweeping s.
+// It sets s's sweepgen to the latest generation,
+// and, based on the number of free objects in s,
+// moves s to the appropriate list of c or returns it
+// to the heap.
+// freeSpan returns true if s was returned to the heap.
+// If preserve=true, it does not move s (the caller
+// must take care of it).
+func (c *mcentral) freeSpan(s *mspan, preserve bool, wasempty bool) bool {
 	if s.incache {
-		throw("freespan into cached span")
+		throw("freeSpan given 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)
+	s.needzero = 1
 
 	if preserve {
 		// preserve is set only when called from MCentral_CacheSpan above,
@@ -179,28 +184,24 @@ func (c *mcentral) freeSpan(s *mspan, n int32, start gclinkptr, end gclinkptr, p
 		c.nonempty.insert(s)
 	}
 
-	// delay updating sweepgen until here.  This is the signal that
+	// 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.)
 	atomic.Store(&s.sweepgen, mheap_.sweepgen)
 
-	if s.ref != 0 {
+	if s.allocCount != 0 {
 		unlock(&c.lock)
 		return false
 	}
 
-	// s is completely freed, return it to the heap.
 	c.nonempty.remove(s)
-	s.needzero = 1
-	s.freelist = 0
 	unlock(&c.lock)
-	heapBitsForSpan(s.base()).initSpan(s.layout())
 	mheap_.freeSpan(s, 0)
 	return true
 }
 
-// Fetch a new span from the heap and carve into objects for the free list.
+// grow allocates a new empty span from the heap and initializes it for c's size class.
 func (c *mcentral) grow() *mspan {
 	npages := uintptr(class_to_allocnpages[c.sizeclass])
 	size := uintptr(class_to_size[c.sizeclass])
@@ -211,21 +212,9 @@ func (c *mcentral) grow() *mspan {
 		return nil
 	}
 
-	p := uintptr(s.start << _PageShift)
+	p := s.base()
 	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())
+
+	heapBitsForSpan(s.base()).initSpan(s)
 	return s
 }
diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go
index c3fe610..a65933f 100644
--- a/src/runtime/mem_bsd.go
+++ b/src/runtime/mem_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -15,7 +15,7 @@ import (
 // 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))
+	v := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
 	if uintptr(v) < 4096 {
 		return nil
 	}
@@ -44,14 +44,14 @@ func sysFault(v unsafe.Pointer, n uintptr) {
 
 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
+	// much address space. Instead, assume that the reservation is okay
 	// and check the assumption in SysMap.
 	if sys.PtrSize == 8 && uint64(n) > 1<<32 || sys.GoosNacl != 0 {
 		*reserved = false
 		return v
 	}
 
-	p := unsafe.Pointer(mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
+	p := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
 	if uintptr(p) < 4096 {
 		return nil
 	}
diff --git a/src/runtime/mem_darwin.go b/src/runtime/mem_darwin.go
index 65b1b48..3f1c4d7 100644
--- a/src/runtime/mem_darwin.go
+++ b/src/runtime/mem_darwin.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -10,7 +10,7 @@ import "unsafe"
 // 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))
+	v := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
 	if uintptr(v) < 4096 {
 		return nil
 	}
@@ -40,7 +40,7 @@ func sysFault(v unsafe.Pointer, n uintptr) {
 
 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))
+	p := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
 	if uintptr(p) < 4096 {
 		return nil
 	}
@@ -53,7 +53,7 @@ const (
 
 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))
+	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")
 	}
diff --git a/src/runtime/mem_linux.go b/src/runtime/mem_linux.go
index 330504b..61fdcee 100644
--- a/src/runtime/mem_linux.go
+++ b/src/runtime/mem_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -132,6 +132,13 @@ func sysUnused(v unsafe.Pointer, n uintptr) {
 		}
 	}
 
+	if uintptr(v)&(sys.PhysPageSize-1) != 0 || n&(sys.PhysPageSize-1) != 0 {
+		// madvise will round this to any physical page
+		// *covered* by this range, so an unaligned madvise
+		// will release more memory than intended.
+		throw("unaligned sysUnused")
+	}
+
 	madvise(v, n, _MADV_DONTNEED)
 }
 
@@ -172,7 +179,7 @@ func sysFault(v unsafe.Pointer, n uintptr) {
 
 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
+	// 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 sys.PtrSize == 8 && uint64(n) > 1<<32 {
diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go
index cf9e99c..3d82a98 100644
--- a/src/runtime/mem_plan9.go
+++ b/src/runtime/mem_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/mem_windows.go b/src/runtime/mem_windows.go
index 71be0e6..2c338c8 100644
--- a/src/runtime/mem_windows.go
+++ b/src/runtime/mem_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s
index c257d59..6f30eca 100644
--- a/src/runtime/memclr_amd64.s
+++ b/src/runtime/memclr_amd64.s
@@ -103,7 +103,7 @@ loop_avx2_huge:
 	ADDQ	$128, DI
 	CMPQ	BX, $128
 	JAE	loop_avx2_huge
-	// In the desciption of MOVNTDQ in [1]
+	// In the description of MOVNTDQ in [1]
 	// "... fencing operation implemented with the SFENCE or MFENCE instruction
 	// should be used in conjunction with MOVNTDQ instructions..."
 	// [1] 64-ia-32-architectures-software-developer-manual-325462.pdf
diff --git a/src/runtime/memclr_arm.s b/src/runtime/memclr_arm.s
index 8b5fe31..c9b8586 100644
--- a/src/runtime/memclr_arm.s
+++ b/src/runtime/memclr_arm.s
@@ -1,7 +1,7 @@
 // Inferno's libkern/memset-arm.s
 // http://code.google.com/p/inferno-os/source/browse/libkern/memset-arm.s
 //
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         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.
 //
diff --git a/src/runtime/memclr_s390x.s b/src/runtime/memclr_s390x.s
new file mode 100644
index 0000000..86eafec
--- /dev/null
+++ b/src/runtime/memclr_s390x.s
@@ -0,0 +1,122 @@
+// Copyright 2016 The Go 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|NOFRAME,$0-16
+	MOVD	ptr+0(FP), R4
+	MOVD	n+8(FP), R5
+
+start:
+	CMPBLE	R5, $3, clear0to3
+	CMPBLE	R5, $7, clear4to7
+	CMPBLE	R5, $11, clear8to11
+	CMPBLE	R5, $15, clear12to15
+	CMP	R5, $32
+	BGE	clearmt32
+	MOVD	R0, 0(R4)
+	MOVD	R0, 8(R4)
+	ADD	$16, R4
+	SUB	$16, R5
+	BR	start
+
+clear0to3:
+	CMPBEQ	R5, $0, done
+	CMPBNE	R5, $1, clear2
+	MOVB	R0, 0(R4)
+	RET
+clear2:
+	CMPBNE	R5, $2, clear3
+	MOVH	R0, 0(R4)
+	RET
+clear3:
+	MOVH	R0, 0(R4)
+	MOVB	R0, 2(R4)
+	RET
+
+clear4to7:
+	CMPBNE	R5, $4, clear5
+	MOVW	R0, 0(R4)
+	RET
+clear5:
+	CMPBNE	R5, $5, clear6
+	MOVW	R0, 0(R4)
+	MOVB	R0, 4(R4)
+	RET
+clear6:
+	CMPBNE	R5, $6, clear7
+	MOVW	R0, 0(R4)
+	MOVH	R0, 4(R4)
+	RET
+clear7:
+	MOVW	R0, 0(R4)
+	MOVH	R0, 4(R4)
+	MOVB	R0, 6(R4)
+	RET
+
+clear8to11:
+	CMPBNE	R5, $8, clear9
+	MOVD	R0, 0(R4)
+	RET
+clear9:
+	CMPBNE	R5, $9, clear10
+	MOVD	R0, 0(R4)
+	MOVB	R0, 8(R4)
+	RET
+clear10:
+	CMPBNE	R5, $10, clear11
+	MOVD	R0, 0(R4)
+	MOVH	R0, 8(R4)
+	RET
+clear11:
+	MOVD	R0, 0(R4)
+	MOVH	R0, 8(R4)
+	MOVB	R0, 10(R4)
+	RET
+
+clear12to15:
+	CMPBNE	R5, $12, clear13
+	MOVD	R0, 0(R4)
+	MOVW	R0, 8(R4)
+	RET
+clear13:
+	CMPBNE	R5, $13, clear14
+	MOVD	R0, 0(R4)
+	MOVW	R0, 8(R4)
+	MOVB	R0, 12(R4)
+	RET
+clear14:
+	CMPBNE	R5, $14, clear15
+	MOVD	R0, 0(R4)
+	MOVW	R0, 8(R4)
+	MOVH	R0, 12(R4)
+	RET
+clear15:
+	MOVD	R0, 0(R4)
+	MOVW	R0, 8(R4)
+	MOVH	R0, 12(R4)
+	MOVB	R0, 14(R4)
+	RET
+
+clearmt32:
+	CMP	R5, $256
+	BLT	clearlt256
+	XC	$256, 0(R4), 0(R4)
+	ADD	$256, R4
+	ADD	$-256, R5
+	BR	clearmt32
+clearlt256:
+	CMPBEQ	R5, $0, done
+	ADD	$-1, R5
+	EXRL	$runtime·memclr_s390x_exrl_xc(SB), R5
+done:
+	RET
+
+// DO NOT CALL - target for exrl (execute relative long) instruction.
+TEXT runtime·memclr_s390x_exrl_xc(SB),NOSPLIT|NOFRAME,$0-0
+	XC	$1, 0(R4), 0(R4)
+	MOVD	R0, 0(R0)
+	RET
+
diff --git a/src/runtime/memmove_386.s b/src/runtime/memmove_386.s
index f72a73a..52b35a6 100644
--- a/src/runtime/memmove_386.s
+++ b/src/runtime/memmove_386.s
@@ -1,7 +1,7 @@
 // Inferno's libkern/memmove-386.s
 // http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
 //
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         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.
 //
@@ -33,8 +33,8 @@ TEXT runtime·memmove(SB), NOSPLIT, $0-12
 	MOVL	n+8(FP), BX
 
 	// REP instructions have a high startup cost, so we handle small sizes
-	// with some straightline code.  The REP MOVSL instruction is really fast
-	// for large sizes.  The cutover is approximately 1K.  We implement up to
+	// with some straightline code. The REP MOVSL instruction is really fast
+	// for large sizes. The cutover is approximately 1K.  We implement up to
 	// 128 because that is the maximum SSE register load (loading all data
 	// into registers lets us ignore copy direction).
 tail:
@@ -69,13 +69,30 @@ nosse2:
 /*
  * forward copy loop
  */
-forward:	
+forward:
+	// If REP MOVSB isn't fast, don't use it
+	TESTL	$(1<<9), runtime·cpuid_ebx7(SB) // erms, aka enhanced REP MOVSB/STOSB
+	JEQ	fwdBy4
+
+	// Check alignment
+	MOVL	SI, AX
+	ORL	DI, AX
+	TESTL	$3, AX
+	JEQ	fwdBy4
+
+	// Do 1 byte at a time
+	MOVL	BX, CX
+	REP;	MOVSB
+	RET
+
+fwdBy4:
+	// Do 4 bytes at a time
 	MOVL	BX, CX
 	SHRL	$2, CX
 	ANDL	$3, BX
-
 	REP;	MOVSL
 	JMP	tail
+
 /*
  * check overlap
  */
diff --git a/src/runtime/memmove_amd64.s b/src/runtime/memmove_amd64.s
index e14614d..39b4c3a 100644
--- a/src/runtime/memmove_amd64.s
+++ b/src/runtime/memmove_amd64.s
@@ -1,7 +1,7 @@
 // Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
 // http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
 //
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         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.
 //
@@ -35,8 +35,8 @@ TEXT runtime·memmove(SB), NOSPLIT, $0-24
 	MOVQ	n+16(FP), BX
 
 	// REP instructions have a high startup cost, so we handle small sizes
-	// with some straightline code.  The REP MOVSQ instruction is really fast
-	// for large sizes.  The cutover is approximately 2K.
+	// with some straightline code. The REP MOVSQ instruction is really fast
+	// for large sizes. The cutover is approximately 2K.
 tail:
 	// move_129through256 or smaller work whether or not the source and the
 	// destination memory regions overlap because they load all data into
@@ -77,6 +77,23 @@ forward:
 	CMPQ	BX, $2048
 	JLS	move_256through2048
 
+	// If REP MOVSB isn't fast, don't use it
+	TESTL	$(1<<9), runtime·cpuid_ebx7(SB) // erms, aka enhanced REP MOVSB/STOSB
+	JEQ	fwdBy8
+
+	// Check alignment
+	MOVL	SI, AX
+	ORL	DI, AX
+	TESTL	$7, AX
+	JEQ	fwdBy8
+
+	// Do 1 byte at a time
+	MOVQ	BX, CX
+	REP;	MOVSB
+	RET
+
+fwdBy8:
+	// Do 8 bytes at a time
 	MOVQ	BX, CX
 	SHRQ	$3, CX
 	ANDQ	$7, BX
diff --git a/src/runtime/memmove_arm.s b/src/runtime/memmove_arm.s
index 35f04a8..6b880d5 100644
--- a/src/runtime/memmove_arm.s
+++ b/src/runtime/memmove_arm.s
@@ -1,7 +1,7 @@
 // Inferno's libkern/memmove-arm.s
 // http://code.google.com/p/inferno-os/source/browse/libkern/memmove-arm.s
 //
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         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.
 //
diff --git a/src/runtime/memmove_linux_amd64_test.go b/src/runtime/memmove_linux_amd64_test.go
index f7221f4..1dd5d49 100644
--- a/src/runtime/memmove_linux_amd64_test.go
+++ b/src/runtime/memmove_linux_amd64_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/memmove_nacl_amd64p32.s b/src/runtime/memmove_nacl_amd64p32.s
index dd7ac76..13907a9 100644
--- a/src/runtime/memmove_nacl_amd64p32.s
+++ b/src/runtime/memmove_nacl_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -47,6 +47,6 @@ back:
 	CLD
 
 	// Note: we copy only 4 bytes at a time so that the tail is at most
-	// 3 bytes.  That guarantees that we aren't copying pointers with MOVSB.
+	// 3 bytes. That guarantees that we aren't copying pointers with MOVSB.
 	// See issue 13160.
 	RET
diff --git a/src/runtime/memmove_plan9_386.s b/src/runtime/memmove_plan9_386.s
index 3b492eb..c4d62ec 100644
--- a/src/runtime/memmove_plan9_386.s
+++ b/src/runtime/memmove_plan9_386.s
@@ -1,7 +1,7 @@
 // Inferno's libkern/memmove-386.s
 // http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
 //
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         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.
 //
@@ -31,8 +31,8 @@ TEXT runtime·memmove(SB), NOSPLIT, $0-12
 	MOVL	n+8(FP), BX
 
 	// REP instructions have a high startup cost, so we handle small sizes
-	// with some straightline code.  The REP MOVSL instruction is really fast
-	// for large sizes.  The cutover is approximately 1K.
+	// with some straightline code. The REP MOVSL instruction is really fast
+	// for large sizes. The cutover is approximately 1K.
 tail:
 	TESTL	BX, BX
 	JEQ	move_0
diff --git a/src/runtime/memmove_plan9_amd64.s b/src/runtime/memmove_plan9_amd64.s
index a1cc255..9bef31d 100644
--- a/src/runtime/memmove_plan9_amd64.s
+++ b/src/runtime/memmove_plan9_amd64.s
@@ -1,7 +1,7 @@
 // Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
 // http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
 //
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         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.
 //
@@ -33,8 +33,8 @@ TEXT runtime·memmove(SB), NOSPLIT, $0-24
 	MOVQ	n+16(FP), BX
 
 	// REP instructions have a high startup cost, so we handle small sizes
-	// with some straightline code.  The REP MOVSQ instruction is really fast
-	// for large sizes.  The cutover is approximately 1K.
+	// with some straightline code. The REP MOVSQ instruction is really fast
+	// for large sizes. The cutover is approximately 1K.
 tail:
 	TESTQ	BX, BX
 	JEQ	move_0
diff --git a/src/runtime/memmove_ppc64x.s b/src/runtime/memmove_ppc64x.s
index b6d0b85..26dabd9 100644
--- a/src/runtime/memmove_ppc64x.s
+++ b/src/runtime/memmove_ppc64x.s
@@ -11,78 +11,109 @@ TEXT runtime·memmove(SB), NOSPLIT|NOFRAME, $0-24
 	MOVD	to+0(FP), R3
 	MOVD	from+8(FP), R4
 	MOVD	n+16(FP), R5
-	CMP	R5, $0
-	BNE	check
-	RET
 
+	// Determine if there are doublewords to
+	// copy so a more efficient move can be done
 check:
-	ANDCC	$7, R5, R7	// R7 is the number of bytes to copy and CR0[EQ] is set if there are none.
-	SRAD	$3, R5, R6	// R6 is the number of words to copy
-	CMP	R6, $0, CR1	// CR1[EQ] is set if there are no words to copy.
-
-	CMP	R3, R4, CR2
-	BC	12, 9, backward	// I think you should be able to write this as "BGT CR2, backward"
+	ANDCC	$7, R5, R7	// R7: bytes to copy
+	SRAD	$3, R5, R6	// R6: double words to copy
+	CMP	R6, $0, CR1	// CR1[EQ] set if no double words to copy
 
-	// Copying forward proceeds by copying R6 words then copying R7 bytes.
-	// R3 and R4 are advanced as we copy. Becuase PPC64 lacks post-increment
-	// load/store, R3 and R4 point before the bytes that are to be copied.
+	// Determine overlap by subtracting dest - src and comparing against the
+	// length.  The catches the cases where src and dest are in different types
+	// of storage such as stack and static to avoid doing backward move when not
+	// necessary.
 
-	BC	12, 6, noforwardlarge	// "BEQ CR1, noforwardlarge"
-
-	MOVD	R6, CTR
+	SUB	R4, R3, R8	// dest - src
+	CMPU	R8, R5, CR2	// < len?
+	BC	12, 8, backward // BLT CR2 backward
 
-	SUB	$8, R3
-	SUB	$8, R4
+	// Copying forward if no overlap.
 
-forwardlargeloop:
-	MOVDU	8(R4), R8
-	MOVDU	R8, 8(R3)
-	BC	16, 0, forwardlargeloop // "BDNZ"
-
-	ADD	$8, R3
-	ADD	$8, R4
+	BC	12, 6, noforwardlarge	// "BEQ CR1, noforwardlarge"
+	MOVD	R6,CTR			// R6 = number of double words
+	SRADCC	$2,R6,R8		// 32 byte chunks?
+	BNE	forward32setup		//
+
+	// Move double words
+
+forward8:
+	MOVD    0(R4), R8		// double word
+	ADD     $8,R4
+	MOVD    R8, 0(R3)		//
+	ADD     $8,R3
+	BC      16, 0, forward8
+	BR	noforwardlarge		// handle remainder
+
+	// Prepare for moves of 32 bytes at a time.
+
+forward32setup:
+	DCBTST	(R3)			// prepare data cache
+	DCBT	(R4)
+	MOVD	R8, CTR			// double work count
+
+forward32:
+	MOVD	0(R4), R8		// load 4 double words
+	MOVD	8(R4), R9
+	MOVD	16(R4), R14
+	MOVD	24(R4), R15
+	ADD	$32,R4
+	MOVD	R8, 0(R3)		// store those 4
+	MOVD	R9, 8(R3)
+	MOVD	R14,16(R3)
+	MOVD	R15,24(R3)
+	ADD	$32,R3			// bump up for next set
+	BC	16, 0, forward32	// continue
+	RLDCLCC	$61,R5,$3,R6		// remaining doublewords
+	BEQ	noforwardlarge
+	MOVD	R6,CTR			// set up the CTR
+	BR	forward8
 
 noforwardlarge:
-	BNE	forwardtail	// Tests the bit set by ANDCC above
-	RET
+	CMP	R7,$0			// any remaining bytes
+	BC	4, 1, LR
 
 forwardtail:
-	SUB	$1, R3
-	SUB	$1, R4
-	MOVD	R7, CTR
+	MOVD	R7, CTR			// move tail bytes
 
 forwardtailloop:
-	MOVBZU	1(R4), R8
-	MOVBZU	R8, 1(R3)
+	MOVBZ	0(R4), R8		// move single bytes
+	ADD	$1,R4
+	MOVBZ	R8, 0(R3)
+	ADD	$1,R3
 	BC	16, 0, forwardtailloop
 	RET
 
 backward:
-	// Copying backwards proceeds by copying R7 bytes then copying R6 words.
+	// Copying backwards proceeds by copying R7 bytes then copying R6 double words.
 	// R3 and R4 are advanced to the end of the destination/source buffers
 	// respectively and moved back as we copy.
 
-	ADD	R5, R4, R4
-	ADD	R3, R5, R3
+	ADD	R5, R4, R4		// end of source
+	ADD	R3, R5, R3		// end of dest
 
-	BEQ	nobackwardtail
+	BEQ	nobackwardtail		// earlier condition
 
-	MOVD	R7, CTR
+	MOVD	R7, CTR			// bytes to move
 
 backwardtailloop:
-	MOVBZU	-1(R4), R8
-	MOVBZU	R8, -1(R3)
+	MOVBZ 	-1(R4), R8		// point to last byte
+	SUB	$1,R4
+	MOVBZ 	R8, -1(R3)
+	SUB	$1,R3
 	BC	16, 0, backwardtailloop
 
 nobackwardtail:
-	BC	4, 6, backwardlarge		// "BNE CR1"
-	RET
+	CMP	R6,$0
+	BC	4, 5, LR
 
 backwardlarge:
 	MOVD	R6, CTR
 
 backwardlargeloop:
-	MOVDU	-8(R4), R8
-	MOVDU	R8, -8(R3)
-	BC	16, 0, backwardlargeloop	// "BDNZ"
+	MOVD 	-8(R4), R8
+	SUB	$8,R4
+	MOVD 	R8, -8(R3)
+	SUB	$8,R3
+	BC	16, 0, backwardlargeloop	//
 	RET
diff --git a/src/runtime/memmove_s390x.s b/src/runtime/memmove_s390x.s
new file mode 100644
index 0000000..238f308
--- /dev/null
+++ b/src/runtime/memmove_s390x.s
@@ -0,0 +1,189 @@
+// Copyright 2016 The Go 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|NOFRAME,$0-24
+	MOVD	to+0(FP), R6
+	MOVD	from+8(FP), R4
+	MOVD	n+16(FP), R5
+
+	CMPBEQ	R6, R4, done
+
+start:
+	CMPBLE	R5, $3, move0to3
+	CMPBLE	R5, $7, move4to7
+	CMPBLE	R5, $11, move8to11
+	CMPBLE	R5, $15, move12to15
+	CMPBNE	R5, $16, movemt16
+	MOVD	0(R4), R7
+	MOVD	8(R4), R8
+	MOVD	R7, 0(R6)
+	MOVD	R8, 8(R6)
+	RET
+
+movemt16:
+	CMPBGT	R4, R6, forwards
+	ADD	R5, R4, R7
+	CMPBLE	R7, R6, forwards
+	ADD	R5, R6, R8
+backwards:
+	MOVD	-8(R7), R3
+	MOVD	R3, -8(R8)
+	MOVD	-16(R7), R3
+	MOVD	R3, -16(R8)
+	ADD	$-16, R5
+	ADD	$-16, R7
+	ADD	$-16, R8
+	CMP	R5, $16
+	BGE	backwards
+	BR	start
+
+forwards:
+	CMPBGT	R5, $64, forwards_fast
+	MOVD	0(R4), R3
+	MOVD	R3, 0(R6)
+	MOVD	8(R4), R3
+	MOVD	R3, 8(R6)
+	ADD	$16, R4
+	ADD	$16, R6
+	ADD	$-16, R5
+	CMP	R5, $16
+	BGE	forwards
+	BR	start
+
+forwards_fast:
+	CMP	R5, $256
+	BLE	forwards_small
+	MVC	$256, 0(R4), 0(R6)
+	ADD	$256, R4
+	ADD	$256, R6
+	ADD	$-256, R5
+	BR	forwards_fast
+
+forwards_small:
+	CMPBEQ	R5, $0, done
+	ADD	$-1, R5
+	EXRL	$runtime·memmove_s390x_exrl_mvc(SB), R5
+	RET
+
+move0to3:
+	CMPBEQ	R5, $0, done
+move1:
+	CMPBNE	R5, $1, move2
+	MOVB	0(R4), R3
+	MOVB	R3, 0(R6)
+	RET
+move2:
+	CMPBNE	R5, $2, move3
+	MOVH	0(R4), R3
+	MOVH	R3, 0(R6)
+	RET
+move3:
+	MOVH	0(R4), R3
+	MOVB	2(R4), R7
+	MOVH	R3, 0(R6)
+	MOVB	R7, 2(R6)
+	RET
+
+move4to7:
+	CMPBNE	R5, $4, move5
+	MOVW	0(R4), R3
+	MOVW	R3, 0(R6)
+	RET
+move5:
+	CMPBNE	R5, $5, move6
+	MOVW	0(R4), R3
+	MOVB	4(R4), R7
+	MOVW	R3, 0(R6)
+	MOVB	R7, 4(R6)
+	RET
+move6:
+	CMPBNE	R5, $6, move7
+	MOVW	0(R4), R3
+	MOVH	4(R4), R7
+	MOVW	R3, 0(R6)
+	MOVH	R7, 4(R6)
+	RET
+move7:
+	MOVW	0(R4), R3
+	MOVH	4(R4), R7
+	MOVB	6(R4), R8
+	MOVW	R3, 0(R6)
+	MOVH	R7, 4(R6)
+	MOVB	R8, 6(R6)
+	RET
+
+move8to11:
+	CMPBNE	R5, $8, move9
+	MOVD	0(R4), R3
+	MOVD	R3, 0(R6)
+	RET
+move9:
+	CMPBNE	R5, $9, move10
+	MOVD	0(R4), R3
+	MOVB	8(R4), R7
+	MOVD	R3, 0(R6)
+	MOVB	R7, 8(R6)
+	RET
+move10:
+	CMPBNE	R5, $10, move11
+	MOVD	0(R4), R3
+	MOVH	8(R4), R7
+	MOVD	R3, 0(R6)
+	MOVH	R7, 8(R6)
+	RET
+move11:
+	MOVD	0(R4), R3
+	MOVH	8(R4), R7
+	MOVB	10(R4), R8
+	MOVD	R3, 0(R6)
+	MOVH	R7, 8(R6)
+	MOVB	R8, 10(R6)
+	RET
+
+move12to15:
+	CMPBNE	R5, $12, move13
+	MOVD	0(R4), R3
+	MOVW	8(R4), R7
+	MOVD	R3, 0(R6)
+	MOVW	R7, 8(R6)
+	RET
+move13:
+	CMPBNE	R5, $13, move14
+	MOVD	0(R4), R3
+	MOVW	8(R4), R7
+	MOVB	12(R4), R8
+	MOVD	R3, 0(R6)
+	MOVW	R7, 8(R6)
+	MOVB	R8, 12(R6)
+	RET
+move14:
+	CMPBNE	R5, $14, move15
+	MOVD	0(R4), R3
+	MOVW	8(R4), R7
+	MOVH	12(R4), R8
+	MOVD	R3, 0(R6)
+	MOVW	R7, 8(R6)
+	MOVH	R8, 12(R6)
+	RET
+move15:
+	MOVD	0(R4), R3
+	MOVW	8(R4), R7
+	MOVH	12(R4), R8
+	MOVB	14(R4), R10
+	MOVD	R3, 0(R6)
+	MOVW	R7, 8(R6)
+	MOVH	R8, 12(R6)
+	MOVB	R10, 14(R6)
+done:
+	RET
+
+// DO NOT CALL - target for exrl (execute relative long) instruction.
+TEXT runtime·memmove_s390x_exrl_mvc(SB),NOSPLIT|NOFRAME,$0-0
+	MVC	$1, 0(R4), 0(R6)
+	MOVD	R0, 0(R0)
+	RET
+
diff --git a/src/runtime/memmove_test.go b/src/runtime/memmove_test.go
index 7f9d3f1..2124cb9 100644
--- a/src/runtime/memmove_test.go
+++ b/src/runtime/memmove_test.go
@@ -1,10 +1,11 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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_test
 
 import (
+	"fmt"
 	. "runtime"
 	"testing"
 )
@@ -81,75 +82,49 @@ func TestMemmoveAlias(t *testing.T) {
 	}
 }
 
-func bmMemmove(b *testing.B, n int) {
-	x := make([]byte, n)
-	y := make([]byte, n)
-	b.SetBytes(int64(n))
-	for i := 0; i < b.N; i++ {
-		copy(x, y)
+func benchmarkSizes(b *testing.B, sizes []int, fn func(b *testing.B, n int)) {
+	for _, n := range sizes {
+		b.Run(fmt.Sprint(n), func(b *testing.B) {
+			b.SetBytes(int64(n))
+			fn(b, n)
+		})
 	}
 }
 
-func BenchmarkMemmove0(b *testing.B)    { bmMemmove(b, 0) }
-func BenchmarkMemmove1(b *testing.B)    { bmMemmove(b, 1) }
-func BenchmarkMemmove2(b *testing.B)    { bmMemmove(b, 2) }
-func BenchmarkMemmove3(b *testing.B)    { bmMemmove(b, 3) }
-func BenchmarkMemmove4(b *testing.B)    { bmMemmove(b, 4) }
-func BenchmarkMemmove5(b *testing.B)    { bmMemmove(b, 5) }
-func BenchmarkMemmove6(b *testing.B)    { bmMemmove(b, 6) }
-func BenchmarkMemmove7(b *testing.B)    { bmMemmove(b, 7) }
-func BenchmarkMemmove8(b *testing.B)    { bmMemmove(b, 8) }
-func BenchmarkMemmove9(b *testing.B)    { bmMemmove(b, 9) }
-func BenchmarkMemmove10(b *testing.B)   { bmMemmove(b, 10) }
-func BenchmarkMemmove11(b *testing.B)   { bmMemmove(b, 11) }
-func BenchmarkMemmove12(b *testing.B)   { bmMemmove(b, 12) }
-func BenchmarkMemmove13(b *testing.B)   { bmMemmove(b, 13) }
-func BenchmarkMemmove14(b *testing.B)   { bmMemmove(b, 14) }
-func BenchmarkMemmove15(b *testing.B)   { bmMemmove(b, 15) }
-func BenchmarkMemmove16(b *testing.B)   { bmMemmove(b, 16) }
-func BenchmarkMemmove32(b *testing.B)   { bmMemmove(b, 32) }
-func BenchmarkMemmove64(b *testing.B)   { bmMemmove(b, 64) }
-func BenchmarkMemmove128(b *testing.B)  { bmMemmove(b, 128) }
-func BenchmarkMemmove256(b *testing.B)  { bmMemmove(b, 256) }
-func BenchmarkMemmove512(b *testing.B)  { bmMemmove(b, 512) }
-func BenchmarkMemmove1024(b *testing.B) { bmMemmove(b, 1024) }
-func BenchmarkMemmove2048(b *testing.B) { bmMemmove(b, 2048) }
-func BenchmarkMemmove4096(b *testing.B) { bmMemmove(b, 4096) }
+var bufSizes = []int{
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+	32, 64, 128, 256, 512, 1024, 2048, 4096,
+}
 
-func bmMemmoveUnaligned(b *testing.B, n int) {
-	x := make([]byte, n+1)
-	y := make([]byte, n)
-	b.SetBytes(int64(n))
-	for i := 0; i < b.N; i++ {
-		copy(x[1:], y)
-	}
+func BenchmarkMemmove(b *testing.B) {
+	benchmarkSizes(b, bufSizes, func(b *testing.B, n int) {
+		x := make([]byte, n)
+		y := make([]byte, n)
+		for i := 0; i < b.N; i++ {
+			copy(x, y)
+		}
+	})
 }
 
-func BenchmarkMemmoveUnaligned0(b *testing.B)    { bmMemmoveUnaligned(b, 0) }
-func BenchmarkMemmoveUnaligned1(b *testing.B)    { bmMemmoveUnaligned(b, 1) }
-func BenchmarkMemmoveUnaligned2(b *testing.B)    { bmMemmoveUnaligned(b, 2) }
-func BenchmarkMemmoveUnaligned3(b *testing.B)    { bmMemmoveUnaligned(b, 3) }
-func BenchmarkMemmoveUnaligned4(b *testing.B)    { bmMemmoveUnaligned(b, 4) }
-func BenchmarkMemmoveUnaligned5(b *testing.B)    { bmMemmoveUnaligned(b, 5) }
-func BenchmarkMemmoveUnaligned6(b *testing.B)    { bmMemmoveUnaligned(b, 6) }
-func BenchmarkMemmoveUnaligned7(b *testing.B)    { bmMemmoveUnaligned(b, 7) }
-func BenchmarkMemmoveUnaligned8(b *testing.B)    { bmMemmoveUnaligned(b, 8) }
-func BenchmarkMemmoveUnaligned9(b *testing.B)    { bmMemmoveUnaligned(b, 9) }
-func BenchmarkMemmoveUnaligned10(b *testing.B)   { bmMemmoveUnaligned(b, 10) }
-func BenchmarkMemmoveUnaligned11(b *testing.B)   { bmMemmoveUnaligned(b, 11) }
-func BenchmarkMemmoveUnaligned12(b *testing.B)   { bmMemmoveUnaligned(b, 12) }
-func BenchmarkMemmoveUnaligned13(b *testing.B)   { bmMemmoveUnaligned(b, 13) }
-func BenchmarkMemmoveUnaligned14(b *testing.B)   { bmMemmoveUnaligned(b, 14) }
-func BenchmarkMemmoveUnaligned15(b *testing.B)   { bmMemmoveUnaligned(b, 15) }
-func BenchmarkMemmoveUnaligned16(b *testing.B)   { bmMemmoveUnaligned(b, 16) }
-func BenchmarkMemmoveUnaligned32(b *testing.B)   { bmMemmoveUnaligned(b, 32) }
-func BenchmarkMemmoveUnaligned64(b *testing.B)   { bmMemmoveUnaligned(b, 64) }
-func BenchmarkMemmoveUnaligned128(b *testing.B)  { bmMemmoveUnaligned(b, 128) }
-func BenchmarkMemmoveUnaligned256(b *testing.B)  { bmMemmoveUnaligned(b, 256) }
-func BenchmarkMemmoveUnaligned512(b *testing.B)  { bmMemmoveUnaligned(b, 512) }
-func BenchmarkMemmoveUnaligned1024(b *testing.B) { bmMemmoveUnaligned(b, 1024) }
-func BenchmarkMemmoveUnaligned2048(b *testing.B) { bmMemmoveUnaligned(b, 2048) }
-func BenchmarkMemmoveUnaligned4096(b *testing.B) { bmMemmoveUnaligned(b, 4096) }
+func BenchmarkMemmoveUnalignedDst(b *testing.B) {
+	benchmarkSizes(b, bufSizes, func(b *testing.B, n int) {
+		x := make([]byte, n+1)
+		y := make([]byte, n)
+		for i := 0; i < b.N; i++ {
+			copy(x[1:], y)
+		}
+	})
+}
+
+func BenchmarkMemmoveUnalignedSrc(b *testing.B) {
+	benchmarkSizes(b, bufSizes, func(b *testing.B, n int) {
+		x := make([]byte, n)
+		y := make([]byte, n+1)
+		for i := 0; i < b.N; i++ {
+			copy(x, y[1:])
+		}
+	})
+}
 
 func TestMemclr(t *testing.T) {
 	size := 512
@@ -183,38 +158,37 @@ func TestMemclr(t *testing.T) {
 	}
 }
 
-func bmMemclr(b *testing.B, n int) {
-	x := make([]byte, n)
-	b.SetBytes(int64(n))
-	for i := 0; i < b.N; i++ {
-		MemclrBytes(x)
-	}
-}
-func BenchmarkMemclr5(b *testing.B)     { bmMemclr(b, 5) }
-func BenchmarkMemclr16(b *testing.B)    { bmMemclr(b, 16) }
-func BenchmarkMemclr64(b *testing.B)    { bmMemclr(b, 64) }
-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 BenchmarkMemclr1M(b *testing.B)    { bmMemclr(b, 1<<20) }
-func BenchmarkMemclr4M(b *testing.B)    { bmMemclr(b, 4<<20) }
-func BenchmarkMemclr8M(b *testing.B)    { bmMemclr(b, 8<<20) }
-func BenchmarkMemclr16M(b *testing.B)   { bmMemclr(b, 16<<20) }
-func BenchmarkMemclr64M(b *testing.B)   { bmMemclr(b, 64<<20) }
+func BenchmarkMemclr(b *testing.B) {
+	for _, n := range []int{5, 16, 64, 256, 4096, 65536} {
+		x := make([]byte, n)
+		b.Run(fmt.Sprint(n), func(b *testing.B) {
+			b.SetBytes(int64(n))
+			for i := 0; i < b.N; i++ {
+				MemclrBytes(x)
+			}
+		})
+	}
+	for _, m := range []int{1, 4, 8, 16, 64} {
+		x := make([]byte, m<<20)
+		b.Run(fmt.Sprint(m, "M"), func(b *testing.B) {
+			b.SetBytes(int64(m << 20))
+			for i := 0; i < b.N; i++ {
+				MemclrBytes(x)
+			}
+		})
+	}
+}
 
-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 BenchmarkGoMemclr(b *testing.B) {
+	benchmarkSizes(b, []int{5, 16, 64, 256}, func(b *testing.B, n int) {
+		x := make([]byte, 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++ {
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index 512edef..1a744e4 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -166,13 +166,13 @@ func runfinq() {
 			for i := fb.cnt; i > 0; i-- {
 				f := &fb.fin[i-1]
 
-				framesz := unsafe.Sizeof((interface{})(nil)) + uintptr(f.nret)
+				framesz := unsafe.Sizeof((interface{})(nil)) + 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)
+					frame = mallocgc(framesz, nil, true)
 					framecap = framesz
 				}
 
@@ -216,20 +216,20 @@ func runfinq() {
 	}
 }
 
-// SetFinalizer sets the finalizer associated with x to f.
-// When the garbage collector finds an unreachable block
+// SetFinalizer sets the finalizer associated with obj to the provided
+// finalizer function. 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
+// finalizer(obj) in a separate goroutine. This makes obj 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.
+// that obj is unreachable, it will free obj.
 //
-// SetFinalizer(x, nil) clears any finalizer associated with x.
+// SetFinalizer(obj, nil) clears any finalizer associated with obj.
 //
-// The argument x must be a pointer to an object allocated by
+// The argument obj 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
+// The argument finalizer must be a function that takes a single argument
+// to which obj's type can be assigned, and can have arbitrary ignored return
 // values. If either of these is not true, SetFinalizer aborts the
 // program.
 //
@@ -241,8 +241,8 @@ func runfinq() {
 // 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.
+// The finalizer for obj is scheduled to run at some arbitrary time after
+// obj 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.
@@ -252,13 +252,31 @@ func runfinq() {
 // 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
+// It is not guaranteed that a finalizer will run if the size of *obj 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 finalizer may run as soon as an object becomes unreachable.
+// In order to use finalizers correctly, the program must ensure that
+// the object is reachable until it is no longer required.
+// Objects stored in global variables, or that can be found by tracing
+// pointers from a global variable, are reachable. For other objects,
+// pass the object to a call of the KeepAlive function to mark the
+// last point in the function where the object must be reachable.
+//
+// For example, if p points to a struct that contains a file descriptor d,
+// and p has a finalizer that closes that file descriptor, and if the last
+// use of p in a function is a call to syscall.Write(p.d, buf, size), then
+// p may be unreachable as soon as the program enters syscall.Write. The
+// finalizer may run at that moment, closing p.d, causing syscall.Write
+// to fail because it is writing to a closed file descriptor (or, worse,
+// to an entirely different file descriptor opened by a different goroutine).
+// To avoid this problem, call runtime.KeepAlive(p) after the call to
+// syscall.Write.
+//
 // 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.
@@ -274,7 +292,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
 		throw("runtime.SetFinalizer: first argument is nil")
 	}
 	if etyp.kind&kindMask != kindPtr {
-		throw("runtime.SetFinalizer: first argument is " + *etyp._string + ", not pointer")
+		throw("runtime.SetFinalizer: first argument is " + etyp.string() + ", not pointer")
 	}
 	ot := (*ptrtype)(unsafe.Pointer(etyp))
 	if ot.elem == nil {
@@ -328,19 +346,22 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
 	}
 
 	if ftyp.kind&kindMask != kindFunc {
-		throw("runtime.SetFinalizer: second argument is " + *ftyp._string + ", not a function")
+		throw("runtime.SetFinalizer: second argument is " + ftyp.string() + ", not a function")
 	}
 	ft := (*functype)(unsafe.Pointer(ftyp))
-	if ft.dotdotdot || len(ft.in) != 1 {
-		throw("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
+	if ft.dotdotdot() {
+		throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string() + " because dotdotdot")
 	}
-	fint := ft.in[0]
+	if ft.dotdotdot() || ft.inCount != 1 {
+		throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
+	}
+	fint := ft.in()[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 {
+		if (fint.uncommon() == nil || etyp.uncommon() == 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
@@ -355,11 +376,11 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
 			goto okarg
 		}
 	}
-	throw("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
+	throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
 okarg:
 	// compute size needed for return parameters
 	nret := uintptr(0)
-	for _, t := range ft.out {
+	for _, t := range ft.out() {
 		nret = round(nret, uintptr(t.align)) + uintptr(t.size)
 	}
 	nret = round(nret, sys.PtrSize)
@@ -374,8 +395,8 @@ okarg:
 	})
 }
 
-// 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
+// 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()
@@ -399,7 +420,7 @@ func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
 	if s == nil {
 		return
 	}
-	x = unsafe.Pointer(uintptr(s.start) << pageShift)
+	x = unsafe.Pointer(s.base())
 
 	if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse {
 		s = nil
@@ -407,9 +428,37 @@ func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
 		return
 	}
 
-	n = uintptr(s.elemsize)
+	n = s.elemsize
 	if s.sizeclass != 0 {
 		x = add(x, (uintptr(v)-uintptr(x))/n*n)
 	}
 	return
 }
+
+// Mark KeepAlive as noinline so that the current compiler will ensure
+// that the argument is alive at the point of the function call.
+// If it were inlined, it would disappear, and there would be nothing
+// keeping the argument alive. Perhaps a future compiler will recognize
+// runtime.KeepAlive specially and do something more efficient.
+//go:noinline
+
+// KeepAlive marks its argument as currently reachable.
+// This ensures that the object is not freed, and its finalizer is not run,
+// before the point in the program where KeepAlive is called.
+//
+// A very simplified example showing where KeepAlive is required:
+// 	type File struct { d int }
+// 	d, err := syscall.Open("/file/path", syscall.O_RDONLY, 0)
+// 	// ... do something if err != nil ...
+// 	p := &FILE{d}
+// 	runtime.SetFinalizer(p, func(p *File) { syscall.Close(p.d) })
+// 	var buf [10]byte
+// 	n, err := syscall.Read(p.d, buf[:])
+// 	// Ensure p is not finalized until Read returns.
+// 	runtime.KeepAlive(p)
+// 	// No more uses of p after this point.
+//
+// Without the KeepAlive call, the finalizer could run at the start of
+// syscall.Read, closing the file descriptor before syscall.Read makes
+// the actual system call.
+func KeepAlive(interface{}) {}
diff --git a/src/runtime/mfixalloc.go b/src/runtime/mfixalloc.go
index 8653a6a..c4ab648 100644
--- a/src/runtime/mfixalloc.go
+++ b/src/runtime/mfixalloc.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.
 
-// Fixed-size object allocator.  Returned memory is not zeroed.
+// Fixed-size object allocator. Returned memory is not zeroed.
 //
 // See malloc.go for overview.
 
@@ -30,8 +30,8 @@ type fixalloc struct {
 }
 
 // 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
+// Since assignments to mlink.next will result in a write barrier being performed
+// this cannot 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 {
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index ab099d8..1eabf43 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -24,6 +24,10 @@
 // Hudson, R., and Moss, J.E.B. Copying Garbage Collection without stopping the world.
 // Concurrency and Computation: Practice and Experience 15(3-5), 2003.
 //
+// TODO(austin): The rest of this comment is woefully out of date and
+// needs to be rewritten. There is no distinct scan phase any more and
+// we allocate black during GC.
+//
 //  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
@@ -216,9 +220,10 @@ var gcphase uint32
 // The compiler knows about this variable.
 // If you change it, you must change the compiler too.
 var writeBarrier struct {
-	enabled bool // compiler emits a check of this before calling write barrier
-	needed  bool // whether we need a write barrier for current GC phase
-	cgo     bool // whether we need a write barrier for a cgo check
+	enabled bool   // compiler emits a check of this before calling write barrier
+	needed  bool   // whether we need a write barrier for current GC phase
+	cgo     bool   // whether we need a write barrier for a cgo check
+	alignme uint64 // guarantee alignment so that compiler can use a 32 or 64-bit load
 }
 
 // gcBlackenEnabled is 1 if mutator assists and background mark
@@ -243,7 +248,7 @@ var gcBlackenPromptly bool
 
 const (
 	_GCoff             = iota // GC not running; sweeping in background, write barrier disabled
-	_GCmark                   // GC marking roots and workbufs, write barrier ENABLED
+	_GCmark                   // GC marking roots and workbufs: allocate black, write barrier ENABLED
 	_GCmarktermination        // GC mark termination: allocate black, P's help GC, write barrier ENABLED
 )
 
@@ -303,7 +308,8 @@ type gcControllerState struct {
 	// scanWork is the total scan work performed this cycle. This
 	// is updated atomically during the cycle. Updates occur in
 	// bounded batches, since it is both written and read
-	// throughout the cycle.
+	// throughout the cycle. At the end of the cycle, this is how
+	// much of the retained heap is scannable.
 	//
 	// Currently this is the bytes of heap scanned. For most uses,
 	// this is an opaque unit of work, but for estimation the
@@ -339,13 +345,9 @@ type gcControllerState struct {
 	// 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
+	// markStartTime is the absolute start time in nanoseconds
+	// that assists and background mark workers started.
+	markStartTime int64
 
 	// heapGoal is the goal memstats.heap_live for when this cycle
 	// ends. This is computed at the beginning of each cycle.
@@ -469,14 +471,18 @@ func (c *gcControllerState) startCycle() {
 // It should only be called when gcBlackenEnabled != 0 (because this
 // is when assists are enabled and the necessary statistics are
 // available).
+//
+// TODO: Consider removing the periodic controller update altogether.
+// Since we switched to allocating black, in theory we shouldn't have
+// to change the assist ratio. However, this is still a useful hook
+// that we've found many uses for when experimenting.
 func (c *gcControllerState) revise() {
 	// Compute the expected scan work remaining.
 	//
-	// Note that the scannable heap size is likely to increase
-	// during the GC cycle. This is why it's important to revise
-	// the assist ratio throughout the cycle: if the scannable
-	// heap size increases, the assist ratio based on the initial
-	// scannable heap size may target too little scan work.
+	// Note that we currently count allocations during GC as both
+	// scannable heap (heap_scan) and scan work completed
+	// (scanWork), so this difference won't be changed by
+	// allocations during GC.
 	//
 	// This particular estimate is a strict upper bound on the
 	// possible remaining scan work for the current heap.
@@ -541,7 +547,7 @@ func (c *gcControllerState) endCycle() {
 	// 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
+	assistDuration := nanotime() - c.markStartTime
 
 	// Assume background mark hit its utilization goal.
 	utilization := gcGoalUtilization
@@ -699,7 +705,7 @@ func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g {
 		// TODO(austin): Shorter preemption interval for mark
 		// worker to improve fairness and give this
 		// finer-grained control over schedule?
-		now := nanotime() - gcController.bgMarkStartTime
+		now := nanotime() - gcController.markStartTime
 		then := now + gcForcePreemptNS
 		timeUsed := c.fractionalMarkTime + gcForcePreemptNS
 		if then > 0 && float64(timeUsed)/float64(then) > c.fractionalUtilizationGoal {
@@ -756,13 +762,15 @@ var work struct {
 	alldone note
 
 	// Number of roots of various root types. Set by gcMarkRootPrepare.
-	nDataRoots, nBSSRoots, nSpanRoots, nStackRoots int
+	nDataRoots, nBSSRoots, nSpanRoots, nStackRoots, nRescanRoots int
 
-	// finalizersDone indicates that finalizers and objects with
-	// finalizers have been scanned by markroot. During concurrent
-	// GC, this happens during the concurrent scan phase. During
-	// STW GC, this happens during mark termination.
-	finalizersDone bool
+	// markrootDone indicates that roots have been marked at least
+	// once during the current GC cycle. This is checked by root
+	// marking operations that have to happen only during the
+	// first root marking pass, whether that's during the
+	// concurrent mark phase in current GC or mark termination in
+	// STW GC.
+	markrootDone bool
 
 	// Each type of GC state transition is protected by a lock.
 	// Since multiple threads can simultaneously detect the state
@@ -822,6 +830,14 @@ var work struct {
 		head, tail guintptr
 	}
 
+	// rescan is a list of G's that need to be rescanned during
+	// mark termination. A G adds itself to this list when it
+	// first invalidates its stack scan.
+	rescan struct {
+		lock mutex
+		list []guintptr
+	}
+
 	// Timing/utilization stats for this cycle.
 	stwprocs, maxprocs                 int32
 	tSweepTerm, tMark, tMarkTerm, tEnd int64 // nanotime() of phase start
@@ -952,8 +968,6 @@ func gcStart(mode gcMode, forceTrigger bool) {
 	// reclaimed until the next GC cycle.
 	clearpools()
 
-	work.finalizersDone = false
-
 	if mode == gcBackgroundMode { // Do as much work concurrently as possible
 		gcController.startCycle()
 		work.heapGoal = gcController.heapGoal
@@ -1001,8 +1015,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
 
 		// Assists and workers can start the moment we start
 		// the world.
-		gcController.assistStartTime = now
-		gcController.bgMarkStartTime = now
+		gcController.markStartTime = now
 
 		// Concurrent mark.
 		systemstack(startTheWorldWithSema)
@@ -1073,13 +1086,6 @@ top:
 		// cached workbufs.
 		atomic.Xadd(&work.nwait, -1)
 
-		// Rescan global data and BSS. There may still work
-		// workers running at this point, so bump "jobs" down
-		// before "next" so they won't try running root jobs
-		// until we set next.
-		atomic.Store(&work.markrootJobs, uint32(fixedRootCount+work.nDataRoots+work.nBSSRoots))
-		atomic.Store(&work.markrootNext, fixedRootCount)
-
 		// GC is set up for mark 2. Let Gs blocked on the
 		// transition lock go while we flush caches.
 		semrelease(&work.markDoneSema)
@@ -1118,9 +1124,8 @@ top:
 		// below. The important thing is that the wb remains active until
 		// all marking is complete. This includes writes made by the GC.
 
-		// markroot is done now, so record that objects with
-		// finalizers have been scanned.
-		work.finalizersDone = true
+		// Record that one root marking pass has completed.
+		work.markrootDone = true
 
 		// Disable assists and background workers. We must do
 		// this before waking blocked assists.
@@ -1165,8 +1170,8 @@ func gcMarkTermination() {
 	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
+	// 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.
@@ -1262,6 +1267,13 @@ func gcMarkTermination() {
 	// Free stack spans. This must be done between GC cycles.
 	systemstack(freeStackSpans)
 
+	// Best-effort remove stack barriers so they don't get in the
+	// way of things like GDB and perf.
+	lock(&allglock)
+	myallgs := allgs
+	unlock(&allglock)
+	gcTryRemoveAllStackBarriers(myallgs)
+
 	// Print gctrace before dropping worldsema. As soon as we drop
 	// worldsema another cycle could start and smash the stats
 	// we're trying to print.
@@ -1351,15 +1363,21 @@ func gcBgMarkPrepare() {
 }
 
 func gcBgMarkWorker(_p_ *p) {
-	type parkInfo struct {
-		m      *m // Release this m on park.
-		attach *p // If non-nil, attach to this p on park.
-	}
-	var park parkInfo
-
 	gp := getg()
-	park.m = acquirem()
-	park.attach = _p_
+
+	type parkInfo struct {
+		m      muintptr // Release this m on park.
+		attach puintptr // If non-nil, attach to this p on park.
+	}
+	// We pass park to a gopark unlock function, so it can't be on
+	// the stack (see gopark). Prevent deadlock from recursively
+	// starting GC by disabling preemption.
+	gp.m.preemptoff = "GC worker init"
+	park := new(parkInfo)
+	gp.m.preemptoff = ""
+
+	park.m.set(acquirem())
+	park.attach.set(_p_)
 	// Inform gcBgMarkStartWorkers that this worker is ready.
 	// After this point, the background mark worker is scheduled
 	// cooperatively by gcController.findRunnable. Hence, it must
@@ -1370,7 +1388,7 @@ func gcBgMarkWorker(_p_ *p) {
 	notewakeup(&work.bgMarkReady)
 
 	for {
-		// Go to sleep until woken by gcContoller.findRunnable.
+		// Go to sleep until woken by gcController.findRunnable.
 		// We can't releasem yet since even the call to gopark
 		// may be preempted.
 		gopark(func(g *g, parkp unsafe.Pointer) bool {
@@ -1378,7 +1396,7 @@ func gcBgMarkWorker(_p_ *p) {
 
 			// The worker G is no longer running, so it's
 			// now safe to allow preemption.
-			releasem(park.m)
+			releasem(park.m.ptr())
 
 			// If the worker isn't attached to its P,
 			// attach now. During initialization and after
@@ -1387,9 +1405,9 @@ func gcBgMarkWorker(_p_ *p) {
 			// attach, the owner P may schedule the
 			// worker, so this must be done after the G is
 			// stopped.
-			if park.attach != nil {
-				p := park.attach
-				park.attach = nil
+			if park.attach != 0 {
+				p := park.attach.ptr()
+				park.attach.set(nil)
 				// cas the worker because we may be
 				// racing with a new worker starting
 				// on this P.
@@ -1400,7 +1418,7 @@ func gcBgMarkWorker(_p_ *p) {
 				}
 			}
 			return true
-		}, noescape(unsafe.Pointer(&park)), "GC worker (idle)", traceEvGoBlock, 0)
+		}, unsafe.Pointer(park), "GC worker (idle)", traceEvGoBlock, 0)
 
 		// Loop until the P dies and disassociates this
 		// worker (the P may later be reused, in which case
@@ -1412,7 +1430,7 @@ func gcBgMarkWorker(_p_ *p) {
 		// 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.
-		park.m = acquirem()
+		park.m.set(acquirem())
 
 		if gcBlackenEnabled == 0 {
 			throw("gcBgMarkWorker: blackening not enabled")
@@ -1475,7 +1493,7 @@ func gcBgMarkWorker(_p_ *p) {
 			// findRunnableGCWorker doesn't try to
 			// schedule it.
 			_p_.gcBgMarkWorker.set(nil)
-			releasem(park.m)
+			releasem(park.m.ptr())
 
 			gcMarkDone()
 
@@ -1485,8 +1503,8 @@ func gcBgMarkWorker(_p_ *p) {
 			// We may be running on a different P at this
 			// point, so we can't reattach until this G is
 			// parked.
-			park.m = acquirem()
-			park.attach = _p_
+			park.m.set(acquirem())
+			park.attach.set(_p_)
 		}
 	}
 }
@@ -1556,12 +1574,15 @@ func gcMark(start_time int64) {
 
 	gchelperstart()
 
-	var gcw gcWork
-	gcDrain(&gcw, gcDrainBlock)
+	gcw := &getg().m.p.ptr().gcw
+	gcDrain(gcw, gcDrainBlock)
 	gcw.dispose()
 
-	// TODO: Re-enable once this is cheap.
-	//gcMarkRootCheck()
+	if debug.gccheckmark > 0 {
+		// This is expensive when there's a large number of
+		// Gs, so only do it if checkmark is also enabled.
+		gcMarkRootCheck()
+	}
 	if work.full != 0 {
 		throw("work.full != 0")
 	}
@@ -1570,14 +1591,17 @@ func gcMark(start_time int64) {
 		notesleep(&work.alldone)
 	}
 
-	// markroot is done now, so record that objects with
-	// finalizers have been scanned.
-	work.finalizersDone = true
+	// Record that at least one root marking pass has completed.
+	work.markrootDone = true
 
 	for i := 0; i < int(gomaxprocs); i++ {
-		if !allp[i].gcw.empty() {
+		gcw := &allp[i].gcw
+		if !gcw.empty() {
 			throw("P has cached GC work at end of mark termination")
 		}
+		if gcw.scanWork != 0 || gcw.bytesMarked != 0 {
+			throw("P has unflushed stats at end of mark termination")
+		}
 	}
 
 	if trace.enabled {
@@ -1586,27 +1610,8 @@ func gcMark(start_time int64) {
 
 	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 memstats.heap_live < work.initialHeapLive {
-		// This can happen if mCentral_UncacheSpan tightens
-		// the heap_live approximation.
-		allocatedDuringCycle = 0
-	}
-	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
-	}
+	// Update the reachable heap stat.
+	memstats.heap_reachable = work.bytesMarked
 
 	// Trigger the next GC cycle when the allocated heap has grown
 	// by triggerRatio over the reachable heap size. Assume that
@@ -1699,7 +1704,7 @@ func gcSweep(mode gcMode) {
 	lock(&sweep.lock)
 	if sweep.parked {
 		sweep.parked = false
-		ready(sweep.g, 0)
+		ready(sweep.g, 0, true)
 	}
 	unlock(&sweep.lock)
 	mProf_GC()
@@ -1732,16 +1737,25 @@ func gcCopySpans() {
 func gcResetMarkState() {
 	// This may be called during a concurrent phase, so make sure
 	// allgs doesn't change.
+	if !(gcphase == _GCoff || gcphase == _GCmarktermination) {
+		// Accessing gcRescan is unsafe.
+		throw("bad GC phase")
+	}
 	lock(&allglock)
 	for _, gp := range allgs {
 		gp.gcscandone = false  // set to true in gcphasework
 		gp.gcscanvalid = false // stack has not been scanned
+		gp.gcRescan = -1
 		gp.gcAssistBytes = 0
 	}
 	unlock(&allglock)
 
+	// Clear rescan list.
+	work.rescan.list = work.rescan.list[:0]
+
 	work.bytesMarked = 0
 	work.initialHeapLive = memstats.heap_live
+	work.markrootDone = false
 }
 
 // Hooks for other packages
@@ -1802,8 +1816,8 @@ func gchelper() {
 
 	// Parallel mark over GC roots and heap
 	if gcphase == _GCmarktermination {
-		var gcw gcWork
-		gcDrain(&gcw, gcDrainBlock) // blocks in getfull
+		gcw := &_g_.m.p.ptr().gcw
+		gcDrain(gcw, gcDrainBlock) // blocks in getfull
 		gcw.dispose()
 	}
 
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index eac45ec..00b96fd 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -15,6 +15,7 @@ import (
 const (
 	fixedRootFinalizers = iota
 	fixedRootFlushCaches
+	fixedRootFreeGStacks
 	fixedRootCount
 
 	// rootBlockBytes is the number of bytes to scan per data or
@@ -31,6 +32,8 @@ const (
 //
 // The caller must have call gcCopySpans().
 //
+// The world must be stopped.
+//
 //go:nowritebarrier
 func gcMarkRootPrepare() {
 	// Compute how many data and BSS root blocks there are.
@@ -39,36 +42,58 @@ func gcMarkRootPrepare() {
 	}
 
 	work.nDataRoots = 0
-	for datap := &firstmoduledata; datap != nil; datap = datap.next {
-		nDataRoots := nBlocks(datap.edata - datap.data)
-		if nDataRoots > work.nDataRoots {
-			work.nDataRoots = nDataRoots
+	work.nBSSRoots = 0
+
+	// Only scan globals once per cycle; preferably concurrently.
+	if !work.markrootDone {
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			nDataRoots := nBlocks(datap.edata - datap.data)
+			if nDataRoots > work.nDataRoots {
+				work.nDataRoots = nDataRoots
+			}
 		}
-	}
 
-	work.nBSSRoots = 0
-	for datap := &firstmoduledata; datap != nil; datap = datap.next {
-		nBSSRoots := nBlocks(datap.ebss - datap.bss)
-		if nBSSRoots > work.nBSSRoots {
-			work.nBSSRoots = nBSSRoots
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			nBSSRoots := nBlocks(datap.ebss - datap.bss)
+			if nBSSRoots > work.nBSSRoots {
+				work.nBSSRoots = nBSSRoots
+			}
 		}
 	}
 
-	// Compute number of span roots.
-	work.nSpanRoots = (len(work.spans) + rootBlockSpans - 1) / rootBlockSpans
-
-	// Snapshot of allglen. During concurrent scan, we just need
-	// to be consistent about how many markroot jobs we create and
-	// how many Gs we check. Gs may be created after this point,
-	// but it's okay that we ignore them because they begin life
-	// without any roots, so there's nothing to scan, and any
-	// roots they create during the concurrent phase will be
-	// scanned during mark termination. During mark termination,
-	// allglen isn't changing, so we'll scan all Gs.
-	work.nStackRoots = int(atomic.Loaduintptr(&allglen))
+	if !work.markrootDone {
+		// On the first markroot, we need to scan span roots.
+		// In concurrent GC, this happens during concurrent
+		// mark and we depend on addfinalizer to ensure the
+		// above invariants for objects that get finalizers
+		// after concurrent mark. In STW GC, this will happen
+		// during mark termination.
+		work.nSpanRoots = (len(work.spans) + rootBlockSpans - 1) / rootBlockSpans
+
+		// On the first markroot, we need to scan all Gs. Gs
+		// may be created after this point, but it's okay that
+		// we ignore them because they begin life without any
+		// roots, so there's nothing to scan, and any roots
+		// they create during the concurrent phase will be
+		// scanned during mark termination. During mark
+		// termination, allglen isn't changing, so we'll scan
+		// all Gs.
+		work.nStackRoots = int(atomic.Loaduintptr(&allglen))
+		work.nRescanRoots = 0
+	} else {
+		// We've already scanned span roots and kept the scan
+		// up-to-date during concurrent mark.
+		work.nSpanRoots = 0
+
+		// On the second pass of markroot, we're just scanning
+		// dirty stacks. It's safe to access rescan since the
+		// world is stopped.
+		work.nStackRoots = 0
+		work.nRescanRoots = len(work.rescan.list)
+	}
 
 	work.markrootNext = 0
-	work.markrootJobs = uint32(fixedRootCount + work.nDataRoots + work.nBSSRoots + work.nSpanRoots + work.nStackRoots)
+	work.markrootJobs = uint32(fixedRootCount + work.nDataRoots + work.nBSSRoots + work.nSpanRoots + work.nStackRoots + work.nRescanRoots)
 }
 
 // gcMarkRootCheck checks that all roots have been scanned. It is
@@ -80,11 +105,24 @@ func gcMarkRootCheck() {
 	}
 
 	lock(&allglock)
-	// Check that gc work is done.
-	for i := 0; i < work.nStackRoots; i++ {
-		gp := allgs[i]
-		if !gp.gcscandone {
-			throw("scan missed a g")
+	// Check that stacks have been scanned.
+	if gcphase == _GCmarktermination {
+		for i := 0; i < len(allgs); i++ {
+			gp := allgs[i]
+			if !(gp.gcscandone && gp.gcscanvalid) && readgstatus(gp) != _Gdead {
+				println("gp", gp, "goid", gp.goid,
+					"status", readgstatus(gp),
+					"gcscandone", gp.gcscandone,
+					"gcscanvalid", gp.gcscanvalid)
+				throw("scan missed a g")
+			}
+		}
+	} else {
+		for i := 0; i < work.nStackRoots; i++ {
+			gp := allgs[i]
+			if !gp.gcscandone {
+				throw("scan missed a g")
+			}
 		}
 	}
 	unlock(&allglock)
@@ -97,31 +135,34 @@ var oneptrmask = [...]uint8{1}
 //
 // Preemption must be disabled (because this uses a gcWork).
 //
+// nowritebarrier is only advisory here.
+//
 //go:nowritebarrier
-func markroot(i uint32) {
-	// TODO: Consider using getg().m.p.ptr().gcw.
-	var gcw gcWork
-
+func markroot(gcw *gcWork, i uint32) {
+	// TODO(austin): This is a bit ridiculous. Compute and store
+	// the bases in gcMarkRootPrepare instead of the counts.
 	baseData := uint32(fixedRootCount)
 	baseBSS := baseData + uint32(work.nDataRoots)
 	baseSpans := baseBSS + uint32(work.nBSSRoots)
 	baseStacks := baseSpans + uint32(work.nSpanRoots)
+	baseRescan := baseStacks + uint32(work.nStackRoots)
+	end := baseRescan + uint32(work.nRescanRoots)
 
 	// Note: if you add a case here, please also update heapdump.go:dumproots.
 	switch {
 	case baseData <= i && i < baseBSS:
 		for datap := &firstmoduledata; datap != nil; datap = datap.next {
-			markrootBlock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, &gcw, int(i-baseData))
+			markrootBlock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, gcw, int(i-baseData))
 		}
 
 	case baseBSS <= i && i < baseSpans:
 		for datap := &firstmoduledata; datap != nil; datap = datap.next {
-			markrootBlock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, &gcw, int(i-baseBSS))
+			markrootBlock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, gcw, int(i-baseBSS))
 		}
 
 	case i == fixedRootFinalizers:
 		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)
+			scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], gcw)
 		}
 
 	case i == fixedRootFlushCaches:
@@ -129,16 +170,29 @@ func markroot(i uint32) {
 			flushallmcaches()
 		}
 
+	case i == fixedRootFreeGStacks:
+		// Only do this once per GC cycle; preferably
+		// concurrently.
+		if !work.markrootDone {
+			// Switch to the system stack so we can call
+			// stackfree.
+			systemstack(markrootFreeGStacks)
+		}
+
 	case baseSpans <= i && i < baseStacks:
 		// mark MSpan.specials
-		markrootSpans(&gcw, int(i-baseSpans))
+		markrootSpans(gcw, int(i-baseSpans))
 
 	default:
 		// the rest is scanning goroutine stacks
-		if uintptr(i-baseStacks) >= allglen {
+		var gp *g
+		if baseStacks <= i && i < baseRescan {
+			gp = allgs[i-baseStacks]
+		} else if baseRescan <= i && i < end {
+			gp = work.rescan.list[i-baseRescan].ptr()
+		} else {
 			throw("markroot: bad index")
 		}
-		gp := allgs[i-baseStacks]
 
 		// remember when we've first observed the G blocked
 		// needed only to output in traceback
@@ -147,21 +201,14 @@ func markroot(i uint32) {
 			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)
-		}
-
-		if gcphase != _GCmarktermination && gp.startpc == gcBgMarkWorkerPC {
+		if gcphase != _GCmarktermination && gp.startpc == gcBgMarkWorkerPC && readgstatus(gp) != _Gdead {
 			// GC background workers may be
 			// non-preemptible, so we may deadlock if we
 			// try to scan them during a concurrent phase.
 			// They also have tiny stacks, so just ignore
 			// them until mark termination.
 			gp.gcscandone = true
+			queueRescan(gp)
 			break
 		}
 
@@ -186,15 +233,13 @@ func markroot(i uint32) {
 			// we scan the stacks we can and ask running
 			// goroutines to scan themselves; and the
 			// second blocks.
-			scang(gp)
+			scang(gp, gcw)
 
 			if selfScan {
 				casgstatus(userG, _Gwaiting, _Grunning)
 			}
 		})
 	}
-
-	gcw.dispose()
 }
 
 // markrootBlock scans the shard'th shard of the block of memory [b0,
@@ -221,6 +266,36 @@ func markrootBlock(b0, n0 uintptr, ptrmask0 *uint8, gcw *gcWork, shard int) {
 	scanblock(b, n, ptrmask, gcw)
 }
 
+// markrootFreeGStacks frees stacks of dead Gs.
+//
+// This does not free stacks of dead Gs cached on Ps, but having a few
+// cached stacks around isn't a problem.
+//
+//TODO go:nowritebarrier
+func markrootFreeGStacks() {
+	// Take list of dead Gs with stacks.
+	lock(&sched.gflock)
+	list := sched.gfreeStack
+	sched.gfreeStack = nil
+	unlock(&sched.gflock)
+	if list == nil {
+		return
+	}
+
+	// Free stacks.
+	tail := list
+	for gp := list; gp != nil; gp = gp.schedlink.ptr() {
+		shrinkstack(gp)
+		tail = gp
+	}
+
+	// Put Gs back on the free list.
+	lock(&sched.gflock)
+	tail.schedlink.set(sched.gfreeNoStack)
+	sched.gfreeNoStack = list
+	unlock(&sched.gflock)
+}
+
 // markrootSpans marks roots for one shard of work.spans.
 //
 //go:nowritebarrier
@@ -238,14 +313,8 @@ func markrootSpans(gcw *gcWork, shard int) {
 	// TODO(austin): There are several ideas for making this more
 	// efficient in issue #11485.
 
-	// We process objects with finalizers only during the first
-	// markroot pass. In concurrent GC, this happens during
-	// concurrent scan and we depend on addfinalizer to ensure the
-	// above invariants for objects that get finalizers after
-	// concurrent scan. In STW GC, this will happen during mark
-	// termination.
-	if work.finalizersDone {
-		return
+	if work.markrootDone {
+		throw("markrootSpans during second markroot")
 	}
 
 	sg := mheap_.sweepgen
@@ -293,7 +362,7 @@ func markrootSpans(gcw *gcWork, shard int) {
 			// 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
+			p := s.base() + uintptr(spf.special.offset)/s.elemsize*s.elemsize
 
 			// Mark everything that can be reached from
 			// the object (but *not* the object itself or
@@ -534,7 +603,13 @@ func gcFlushBgCredit(scanWork int64) {
 			gp.gcAssistBytes = 0
 			xgp := gp
 			gp = gp.schedlink.ptr()
-			ready(xgp, 0)
+			// It's important that we *not* put xgp in
+			// runnext. Otherwise, it's possible for user
+			// code to exploit the GC worker's high
+			// scheduler priority to get itself always run
+			// before other goroutines and always in the
+			// fresh quantum started by GC.
+			ready(xgp, 0, false)
 		} else {
 			// Partially satisfy this assist.
 			gp.gcAssistBytes += scanBytes
@@ -569,12 +644,19 @@ func gcFlushBgCredit(scanWork int64) {
 	unlock(&work.assistQueue.lock)
 }
 
+// scanstack scans gp's stack, greying all pointers found on the stack.
+//
+// During mark phase, it also installs stack barriers while traversing
+// gp's stack. During mark termination, it stops scanning when it
+// reaches an unhit stack barrier.
+//
+// scanstack is marked go:systemstack because it must not be preempted
+// while using a workbuf.
+//
 //go:nowritebarrier
-func scanstack(gp *g) {
+//go:systemstack
+func scanstack(gp *g, gcw *gcWork) {
 	if gp.gcscanvalid {
-		if gcphase == _GCmarktermination {
-			gcRemoveStackBarriers(gp)
-		}
 		return
 	}
 
@@ -604,12 +686,20 @@ func scanstack(gp *g) {
 		throw("can't scan gchelper stack")
 	}
 
+	// Shrink the stack if not much of it is being used. During
+	// concurrent GC, we can do this during concurrent mark.
+	if !work.markrootDone {
+		shrinkstack(gp)
+	}
+
+	// Prepare for stack barrier insertion/removal.
 	var sp, barrierOffset, nextBarrier uintptr
 	if gp.syscallsp != 0 {
 		sp = gp.syscallsp
 	} else {
 		sp = gp.sched.sp
 	}
+	gcLockStackBarriers(gp) // Not necessary during mark term, but harmless.
 	switch gcphase {
 	case _GCmark:
 		// Install stack barriers during stack scan.
@@ -620,16 +710,18 @@ func scanstack(gp *g) {
 			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")
-		}
-
-		gcLockStackBarriers(gp)
+		// Remove any existing stack barriers before we
+		// install new ones.
+		gcRemoveStackBarriers(gp)
 
 	case _GCmarktermination:
+		if !work.markrootDone {
+			// This is a STW GC. There may be stale stack
+			// barriers from an earlier cycle since we
+			// never passed through mark phase.
+			gcRemoveStackBarriers(gp)
+		}
+
 		if int(gp.stkbarPos) == len(gp.stkbar) {
 			// gp hit all of the stack barriers (or there
 			// were none). Re-scan the whole stack.
@@ -646,14 +738,12 @@ func scanstack(gp *g) {
 			}
 		}
 
-		gcRemoveStackBarriers(gp)
-
 	default:
 		throw("scanstack in wrong phase")
 	}
 
+	// Scan the stack.
 	var cache pcvalueCache
-	gcw := &getg().m.p.ptr().gcw
 	n := 0
 	scanframe := func(frame *stkframe, unused unsafe.Pointer) bool {
 		scanframeworker(frame, &cache, gcw)
@@ -681,11 +771,14 @@ func scanstack(gp *g) {
 	}
 	gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
 	tracebackdefers(gp, scanframe, nil)
-	if gcphase == _GCmarktermination {
-		gcw.dispose()
-	}
+	gcUnlockStackBarriers(gp)
 	if gcphase == _GCmark {
-		gcUnlockStackBarriers(gp)
+		// gp may have added itself to the rescan list between
+		// when GC started and now. It's clean now, so remove
+		// it. This isn't safe during mark termination because
+		// mark termination is consuming this list, but it's
+		// also not necessary.
+		dequeueRescan(gp)
 	}
 	gp.gcscanvalid = true
 }
@@ -709,7 +802,7 @@ func scanframeworker(frame *stkframe, cache *pcvalueCache, gcw *gcWork) {
 	pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc, cache)
 	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
+		// stackmap for this function. It is likely that we are looking
 		// at the function prologue, assume so and hope for the best.
 		pcdata = 0
 	}
@@ -717,8 +810,8 @@ func scanframeworker(frame *stkframe, cache *pcvalueCache, gcw *gcWork) {
 	// Scan local variables if stack frame has been allocated.
 	size := frame.varp - frame.sp
 	var minsize uintptr
-	switch sys.TheChar {
-	case '7':
+	switch sys.ArchFamily {
+	case sys.ARM64:
 		minsize = sys.SpAlign
 	default:
 		minsize = sys.MinFrameSize
@@ -763,6 +856,60 @@ func scanframeworker(frame *stkframe, cache *pcvalueCache, gcw *gcWork) {
 	}
 }
 
+// queueRescan adds gp to the stack rescan list and clears
+// gp.gcscanvalid. The caller must own gp and ensure that gp isn't
+// already on the rescan list.
+func queueRescan(gp *g) {
+	if gcphase == _GCoff {
+		gp.gcscanvalid = false
+		return
+	}
+	if gp.gcRescan != -1 {
+		throw("g already on rescan list")
+	}
+
+	lock(&work.rescan.lock)
+	gp.gcscanvalid = false
+
+	// Recheck gcphase under the lock in case there was a phase change.
+	if gcphase == _GCoff {
+		unlock(&work.rescan.lock)
+		return
+	}
+	if len(work.rescan.list) == cap(work.rescan.list) {
+		throw("rescan list overflow")
+	}
+	n := len(work.rescan.list)
+	gp.gcRescan = int32(n)
+	work.rescan.list = work.rescan.list[:n+1]
+	work.rescan.list[n].set(gp)
+	unlock(&work.rescan.lock)
+}
+
+// dequeueRescan removes gp from the stack rescan list, if gp is on
+// the rescan list. The caller must own gp.
+func dequeueRescan(gp *g) {
+	if gp.gcRescan == -1 {
+		return
+	}
+	if gcphase == _GCoff {
+		gp.gcRescan = -1
+		return
+	}
+
+	lock(&work.rescan.lock)
+	if work.rescan.list[gp.gcRescan].ptr() != gp {
+		throw("bad dequeueRescan")
+	}
+	// Careful: gp may itself be the last G on the list.
+	last := work.rescan.list[len(work.rescan.list)-1]
+	work.rescan.list[gp.gcRescan] = last
+	last.ptr().gcRescan = gp.gcRescan
+	gp.gcRescan = -1
+	work.rescan.list = work.rescan.list[:len(work.rescan.list)-1]
+	unlock(&work.rescan.lock)
+}
+
 type gcDrainFlags int
 
 const (
@@ -808,8 +955,7 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
 			if job >= work.markrootJobs {
 				break
 			}
-			// TODO: Pass in gcw.
-			markroot(job)
+			markroot(gcw, job)
 		}
 	}
 
@@ -830,7 +976,10 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
 		if blocking {
 			b = gcw.get()
 		} else {
-			b = gcw.tryGet()
+			b = gcw.tryGetFast()
+			if b == 0 {
+				b = gcw.tryGet()
+			}
 		}
 		if b == 0 {
 			// work barrier reached or tryGet failed.
@@ -893,7 +1042,11 @@ func gcDrainN(gcw *gcWork, scanWork int64) int64 {
 		//         PREFETCH(wbuf->obj[wbuf.nobj - 3];
 		//  }
 		//
-		b := gcw.tryGet()
+		b := gcw.tryGetFast()
+		if b == 0 {
+			b = gcw.tryGet()
+		}
+
 		if b == 0 {
 			break
 		}
@@ -943,8 +1096,8 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
 				// 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, b, i); obj != 0 {
-						greyobject(obj, b, i, hbits, span, gcw)
+					if obj, hbits, span, objIndex := heapBitsForObject(obj, b, i); obj != 0 {
+						greyobject(obj, b, i, hbits, span, gcw, objIndex)
 					}
 				}
 			}
@@ -957,7 +1110,7 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
 // 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).
+// object.
 //go:nowritebarrier
 func scanobject(b uintptr, gcw *gcWork) {
 	// Note that arena_used may change concurrently during
@@ -993,11 +1146,10 @@ func scanobject(b uintptr, gcw *gcWork) {
 		// 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*sys.PtrSize && bits&bitMarked == 0 {
+		if i != 1*sys.PtrSize && !hbits.morePointers() {
 			break // no more pointers in this object
 		}
-		if bits&bitPointer == 0 {
+		if !hbits.isPointer() {
 			continue // not a pointer
 		}
 
@@ -1009,8 +1161,8 @@ func scanobject(b uintptr, gcw *gcWork) {
 		// 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, b, i); obj != 0 {
-				greyobject(obj, b, i, hbits, span, gcw)
+			if obj, hbits, span, objIndex := heapBitsForObject(obj, b, i); obj != 0 {
+				greyobject(obj, b, i, hbits, span, gcw, objIndex)
 			}
 		}
 	}
@@ -1023,9 +1175,9 @@ func scanobject(b uintptr, gcw *gcWork) {
 // Preemption must be disabled.
 //go:nowritebarrier
 func shade(b uintptr) {
-	if obj, hbits, span := heapBitsForObject(b, 0, 0); obj != 0 {
+	if obj, hbits, span, objIndex := heapBitsForObject(b, 0, 0); obj != 0 {
 		gcw := &getg().m.p.ptr().gcw
-		greyobject(obj, 0, 0, hbits, span, gcw)
+		greyobject(obj, 0, 0, hbits, span, gcw, objIndex)
 		if gcphase == _GCmarktermination || gcBlackenPromptly {
 			// Ps aren't allowed to cache work during mark
 			// termination.
@@ -1038,14 +1190,15 @@ func shade(b uintptr) {
 // If it isn't already marked, mark it and enqueue into gcw.
 // base and off are for debugging only and could be removed.
 //go:nowritebarrierrec
-func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork) {
+func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork, objIndex uintptr) {
 	// obj should be start of allocation, and so must be at least pointer-aligned.
 	if obj&(sys.PtrSize-1) != 0 {
 		throw("greyobject: obj not pointer-aligned")
 	}
+	mbits := span.markBitsForIndex(objIndex)
 
 	if useCheckmark {
-		if !hbits.isMarked() {
+		if !mbits.isMarked() {
 			printlock()
 			print("runtime:greyobject: checkmarks finds unexpected unmarked object obj=", hex(obj), "\n")
 			print("runtime: found obj at *(", hex(base), "+", hex(off), ")\n")
@@ -1067,11 +1220,11 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
 		}
 	} else {
 		// If marked we have nothing to do.
-		if hbits.isMarked() {
+		if mbits.isMarked() {
 			return
 		}
-		hbits.setMarked()
-
+		// mbits.setMarked() // Avoid extra call overhead with manual inlining.
+		atomic.Or8(mbits.bytep, mbits.mask)
 		// If this is a noscan object, fast-track it to black
 		// instead of greying it.
 		if !hbits.hasPointers(span.elemsize) {
@@ -1086,8 +1239,9 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
 	// 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)
+	if !gcw.putFast(obj) {
+		gcw.put(obj)
+	}
 }
 
 // gcDumpObject dumps the contents of obj for debugging and marks the
@@ -1106,7 +1260,7 @@ func gcDumpObject(label string, obj, off uintptr) {
 		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")
+	print(" s.base()=", hex(s.base()), " s.limit=", hex(s.limit), " s.sizeclass=", s.sizeclass, " s.elemsize=", s.elemsize, "\n")
 	skipped := false
 	for i := uintptr(0); i < s.elemsize; i += sys.PtrSize {
 		// For big objects, just print the beginning (because
@@ -1120,7 +1274,7 @@ func gcDumpObject(label string, obj, off uintptr) {
 			print(" ...\n")
 			skipped = false
 		}
-		print(" *(", label, "+", i, ") = ", hex(*(*uintptr)(unsafe.Pointer(obj + uintptr(i)))))
+		print(" *(", label, "+", i, ") = ", hex(*(*uintptr)(unsafe.Pointer(obj + i))))
 		if i == off {
 			print(" <==")
 		}
@@ -1131,14 +1285,21 @@ func gcDumpObject(label string, obj, off uintptr) {
 	}
 }
 
-// If gcBlackenPromptly is true we are in the second mark phase phase so we allocate black.
+// gcmarknewobject marks a newly allocated object black. obj must
+// not contain any non-nil pointers.
+//
+// This is nosplit so it can manipulate a gcWork without preemption.
+//
 //go:nowritebarrier
-func gcmarknewobject_m(obj, size uintptr) {
+//go:nosplit
+func gcmarknewobject(obj, size, scanSize uintptr) {
 	if useCheckmark && !gcBlackenPromptly { // The world should be stopped so this should not happen.
 		throw("gcmarknewobject called while doing checkmark")
 	}
-	heapBitsForAddr(obj).setMarked()
-	atomic.Xadd64(&work.bytesMarked, int64(size))
+	markBitsForAddr(obj).setMarked()
+	gcw := &getg().m.p.ptr().gcw
+	gcw.bytesMarked += uint64(size)
+	gcw.scanWork += int64(scanSize)
 }
 
 // Checkmarking
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index b00ceb0..947c38e 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -8,7 +8,6 @@ package runtime
 
 import (
 	"runtime/internal/atomic"
-	"runtime/internal/sys"
 	"unsafe"
 )
 
@@ -52,6 +51,7 @@ func finishsweep_m(stw bool) {
 			}
 		}
 	}
+	nextMarkBitArenaEpoch()
 }
 
 func bgsweep(c chan int) {
@@ -96,7 +96,7 @@ func sweepone() uintptr {
 			mheap_.sweepdone = 1
 			_g_.m.locks--
 			if debug.gcpacertrace > 0 && idx == uint32(len(work.spans)) {
-				print("pacer: sweep done at heap size ", memstats.heap_live>>20, "MB; allocated ", mheap_.spanBytesAlloc>>20, "MB of spans; swept ", mheap_.pagesSwept, " pages\n")
+				print("pacer: sweep done at heap size ", memstats.heap_live>>20, "MB; allocated ", mheap_.spanBytesAlloc>>20, "MB of spans; swept ", mheap_.pagesSwept, " pages at ", mheap_.sweepPagesPerByte, " pages/byte\n")
 			}
 			return ^uintptr(0)
 		}
@@ -187,21 +187,16 @@ func (s *mspan) sweep(preserve bool) bool {
 	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()
-	}
+	// The allocBits indicate which unmarked objects don't need to be
+	// processed since they were free at the end of the last GC cycle
+	// and were not allocated since then.
+	// If the allocBits index is >= s.freeindex and the bit
+	// is not marked then the object remains unallocated
+	// since the last GC.
+	// This situation is analogous to being on a freelist.
 
 	// Unlink & free special records for any objects we're about to free.
 	// Two complications here:
@@ -215,17 +210,18 @@ func (s *mspan) sweep(preserve bool) bool {
 	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() {
+		objIndex := uintptr(special.offset) / size
+		p := s.base() + objIndex*size
+		mbits := s.markBitsForIndex(objIndex)
+		if !mbits.isMarked() {
 			// This object is not marked and has at least one special record.
 			// Pass 1: see if it has at least one finalizer.
 			hasFin := false
-			endOffset := p - uintptr(s.start<<_PageShift) + size
+			endOffset := p - s.base() + size
 			for tmp := special; tmp != nil && uintptr(tmp.offset) < endOffset; tmp = tmp.next {
 				if tmp.kind == _KindSpecialFinalizer {
 					// Stop freeing of object if it has a finalizer.
-					hbits.setMarkedNonAtomic()
+					mbits.setMarkedNonAtomic()
 					hasFin = true
 					break
 				}
@@ -234,7 +230,7 @@ func (s *mspan) sweep(preserve bool) bool {
 			for special != nil && uintptr(special.offset) < endOffset {
 				// Find the exact byte for which the special was setup
 				// (as opposed to object beginning).
-				p := uintptr(s.start<<_PageShift) + uintptr(special.offset)
+				p := s.base() + uintptr(special.offset)
 				if special.kind == _KindSpecialFinalizer || !hasFin {
 					// Splice out special record.
 					y := special
@@ -255,68 +251,75 @@ func (s *mspan) sweep(preserve bool) bool {
 		}
 	}
 
-	// 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)
-		}
-		if msanenabled {
-			msanfree(unsafe.Pointer(p), size)
+	if debug.allocfreetrace != 0 || raceenabled || msanenabled {
+		// Find all newly freed objects. This doesn't have to
+		// efficient; allocfreetrace has massive overhead.
+		mbits := s.markBitsForBase()
+		abits := s.allocBitsForIndex(0)
+		for i := uintptr(0); i < s.nelems; i++ {
+			if !mbits.isMarked() && (abits.index < s.freeindex || abits.isMarked()) {
+				x := s.base() + i*s.elemsize
+				if debug.allocfreetrace != 0 {
+					tracefree(unsafe.Pointer(x), size)
+				}
+				if raceenabled {
+					racefree(unsafe.Pointer(x), size)
+				}
+				if msanenabled {
+					msanfree(unsafe.Pointer(x), size)
+				}
+			}
+			mbits.advance()
+			abits.advance()
 		}
+	}
 
-		// 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
+	// Count the number of free objects in this span.
+	nfree = s.countFree()
+	if cl == 0 && nfree != 0 {
+		s.needzero = 1
+		freeToHeap = true
+	}
+	nalloc := uint16(s.nelems) - uint16(nfree)
+	nfreed := s.allocCount - nalloc
+	if nalloc > s.allocCount {
+		print("runtime: nelems=", s.nelems, " nfree=", nfree, " nalloc=", nalloc, " previous allocCount=", s.allocCount, " nfreed=", nfreed, "\n")
+		throw("sweep increased allocation count")
+	}
 
-			// Free the span after heapBitsSweepSpan
-			// returns, since it's not done with the span.
-			freeToHeap = true
-		} else {
-			// Free small object.
-			if size > 2*sys.PtrSize {
-				*(*uintptr)(unsafe.Pointer(p + sys.PtrSize)) = uintptrMask & 0xdeaddeaddeaddead // mark as "needs to be zeroed"
-			} else if size > sys.PtrSize {
-				*(*uintptr)(unsafe.Pointer(p + sys.PtrSize)) = 0
-			}
-			if head.ptr() == nil {
-				head = gclinkptr(p)
-			} else {
-				end.ptr().next = gclinkptr(p)
-			}
-			end = gclinkptr(p)
-			end.ptr().next = gclinkptr(0x0bade5)
-			nfree++
-		}
-	})
+	s.allocCount = nalloc
+	wasempty := s.nextFreeIndex() == s.nelems
+	s.freeindex = 0 // reset allocation index to start of span.
+
+	// gcmarkBits becomes the allocBits.
+	// get a fresh cleared gcmarkBits in preparation for next GC
+	s.allocBits = s.gcmarkBits
+	s.gcmarkBits = newMarkBits(s.nelems)
+
+	// Initialize alloc bits cache.
+	s.refillAllocCache(0)
 
 	// 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 freeToHeap || nfree == 0 {
+	if freeToHeap || nfreed == 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")
 		}
+		// Serialization point.
+		// At this point the mark bits are cleared and allocation ready
+		// to go so release the span.
 		atomic.Store(&s.sweepgen, sweepgen)
 	}
-	if nfree > 0 {
-		c.local_nsmallfree[cl] += uintptr(nfree)
-		res = mheap_.central[cl].mcentral.freeSpan(s, int32(nfree), head, end, preserve)
+
+	if nfreed > 0 && cl != 0 {
+		c.local_nsmallfree[cl] += uintptr(nfreed)
+		res = mheap_.central[cl].mcentral.freeSpan(s, preserve, wasempty)
 		// MCentral_FreeSpan updates sweepgen
 	} else if freeToHeap {
 		// Free large span to heap
@@ -337,7 +340,7 @@ func (s *mspan) sweep(preserve bool) bool {
 		// 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)
+			sysFault(unsafe.Pointer(s.base()), size)
 		} else {
 			mheap_.freeSpan(s, 1)
 		}
@@ -400,27 +403,3 @@ func reimburseSweepCredit(unusableBytes uintptr) {
 		throw("spanBytesAlloc underflow")
 	}
 }
-
-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
index 0a0285d..d04840b 100644
--- a/src/runtime/mgcwork.go
+++ b/src/runtime/mgcwork.go
@@ -11,18 +11,17 @@ import (
 )
 
 const (
-	_Debugwbufs  = false // if true check wbufs consistency
-	_WorkbufSize = 2048  // in bytes; larger values result in less contention
+	_WorkbufSize = 2048 // in bytes; larger values result in less contention
 )
 
 // 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.
+// 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
+// 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.
 
@@ -44,14 +43,6 @@ func (wp wbufptr) ptr() *workbuf {
 //
 // 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 ..
@@ -94,10 +85,10 @@ type gcWork struct {
 }
 
 func (w *gcWork) init() {
-	w.wbuf1 = wbufptrOf(getempty(101))
-	wbuf2 := trygetfull(102)
+	w.wbuf1 = wbufptrOf(getempty())
+	wbuf2 := trygetfull()
 	if wbuf2 == nil {
-		wbuf2 = getempty(103)
+		wbuf2 = getempty()
 	}
 	w.wbuf2 = wbufptrOf(wbuf2)
 }
@@ -105,9 +96,7 @@ func (w *gcWork) init() {
 // 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
-
+func (w *gcWork) put(obj uintptr) {
 	wbuf := w.wbuf1.ptr()
 	if wbuf == nil {
 		w.init()
@@ -117,8 +106,8 @@ func (ww *gcWork) put(obj uintptr) {
 		w.wbuf1, w.wbuf2 = w.wbuf2, w.wbuf1
 		wbuf = w.wbuf1.ptr()
 		if wbuf.nobj == len(wbuf.obj) {
-			putfull(wbuf, 132)
-			wbuf = getempty(133)
+			putfull(wbuf)
+			wbuf = getempty()
 			w.wbuf1 = wbufptrOf(wbuf)
 		}
 	}
@@ -127,15 +116,29 @@ func (ww *gcWork) put(obj uintptr) {
 	wbuf.nobj++
 }
 
+// putFast does a put and returns true if it can be done quickly
+// otherwise it returns false and the caller needs to call put.
+//go:nowritebarrier
+func (w *gcWork) putFast(obj uintptr) bool {
+	wbuf := w.wbuf1.ptr()
+	if wbuf == nil {
+		return false
+	} else if wbuf.nobj == len(wbuf.obj) {
+		return false
+	}
+
+	wbuf.obj[wbuf.nobj] = obj
+	wbuf.nobj++
+	return true
+}
+
 // 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
-
+func (w *gcWork) tryGet() uintptr {
 	wbuf := w.wbuf1.ptr()
 	if wbuf == nil {
 		w.init()
@@ -147,11 +150,11 @@ func (ww *gcWork) tryGet() uintptr {
 		wbuf = w.wbuf1.ptr()
 		if wbuf.nobj == 0 {
 			owbuf := wbuf
-			wbuf = trygetfull(167)
+			wbuf = trygetfull()
 			if wbuf == nil {
 				return 0
 			}
-			putempty(owbuf, 166)
+			putempty(owbuf)
 			w.wbuf1 = wbufptrOf(wbuf)
 		}
 	}
@@ -160,13 +163,28 @@ func (ww *gcWork) tryGet() uintptr {
 	return wbuf.obj[wbuf.nobj]
 }
 
+// tryGetFast dequeues a pointer for the garbage collector to trace
+// if one is readily available. Otherwise it returns 0 and
+// the caller is expected to call tryGet().
+//go:nowritebarrier
+func (w *gcWork) tryGetFast() uintptr {
+	wbuf := w.wbuf1.ptr()
+	if wbuf == nil {
+		return 0
+	}
+	if wbuf.nobj == 0 {
+		return 0
+	}
+
+	wbuf.nobj--
+	return wbuf.obj[wbuf.nobj]
+}
+
 // 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
-
+func (w *gcWork) get() uintptr {
 	wbuf := w.wbuf1.ptr()
 	if wbuf == nil {
 		w.init()
@@ -178,11 +196,11 @@ func (ww *gcWork) get() uintptr {
 		wbuf = w.wbuf1.ptr()
 		if wbuf.nobj == 0 {
 			owbuf := wbuf
-			wbuf = getfull(185)
+			wbuf = getfull()
 			if wbuf == nil {
 				return 0
 			}
-			putempty(owbuf, 184)
+			putempty(owbuf)
 			w.wbuf1 = wbufptrOf(wbuf)
 		}
 	}
@@ -203,17 +221,17 @@ func (ww *gcWork) get() uintptr {
 func (w *gcWork) dispose() {
 	if wbuf := w.wbuf1.ptr(); wbuf != nil {
 		if wbuf.nobj == 0 {
-			putempty(wbuf, 212)
+			putempty(wbuf)
 		} else {
-			putfull(wbuf, 214)
+			putfull(wbuf)
 		}
 		w.wbuf1 = 0
 
 		wbuf = w.wbuf2.ptr()
 		if wbuf.nobj == 0 {
-			putempty(wbuf, 218)
+			putempty(wbuf)
 		} else {
-			putfull(wbuf, 220)
+			putfull(wbuf)
 		}
 		w.wbuf2 = 0
 	}
@@ -239,8 +257,8 @@ func (w *gcWork) balance() {
 		return
 	}
 	if wbuf := w.wbuf2.ptr(); wbuf.nobj != 0 {
-		putfull(wbuf, 246)
-		w.wbuf2 = wbufptrOf(getempty(247))
+		putfull(wbuf)
+		w.wbuf2 = wbufptrOf(getempty())
 	} else if wbuf := w.wbuf1.ptr(); wbuf.nobj > 4 {
 		w.wbuf1 = wbufptrOf(handoff(wbuf))
 	}
@@ -257,10 +275,8 @@ func (w *gcWork) empty() bool {
 // 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/full queues.
-	log   [4]int // line numbers forming a history of ownership changes to workbuf
+	node lfnode // must be first
+	nobj int
 }
 
 type workbuf struct {
@@ -273,69 +289,23 @@ type workbuf struct {
 // workbufs.
 // If the GC asks for some work these are the only routines that
 // make 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 {
+func getempty() *workbuf {
 	var b *workbuf
 	if work.empty != 0 {
 		b = (*workbuf)(lfstackpop(&work.empty))
@@ -346,16 +316,14 @@ func getempty(entry int) *workbuf {
 	if b == nil {
 		b = (*workbuf)(persistentalloc(unsafe.Sizeof(*b), sys.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) {
+func putempty(b *workbuf) {
 	b.checkempty()
-	b.logput(entry)
 	lfstackpush(&work.empty, &b.node)
 }
 
@@ -363,9 +331,8 @@ func putempty(b *workbuf, entry int) {
 // 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) {
+func putfull(b *workbuf) {
 	b.checknonempty()
-	b.logput(entry)
 	lfstackpush(&work.full, &b.node)
 
 	// We just made more work available. Let the GC controller
@@ -378,10 +345,9 @@ func putfull(b *workbuf, entry int) {
 // 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 {
+func trygetfull() *workbuf {
 	b := (*workbuf)(lfstackpop(&work.full))
 	if b != nil {
-		b.logget(entry)
 		b.checknonempty()
 		return b
 	}
@@ -400,10 +366,9 @@ func trygetfull(entry int) *workbuf {
 // This is in fact the termination condition for the STW mark
 // phase.
 //go:nowritebarrier
-func getfull(entry int) *workbuf {
+func getfull() *workbuf {
 	b := (*workbuf)(lfstackpop(&work.full))
 	if b != nil {
-		b.logget(entry)
 		b.checknonempty()
 		return b
 	}
@@ -422,7 +387,6 @@ func getfull(entry int) *workbuf {
 			}
 			b = (*workbuf)(lfstackpop(&work.full))
 			if b != nil {
-				b.logget(entry)
 				b.checknonempty()
 				return b
 			}
@@ -452,7 +416,7 @@ func getfull(entry int) *workbuf {
 //go:nowritebarrier
 func handoff(b *workbuf) *workbuf {
 	// Make new buffer with half of b's pointers.
-	b1 := getempty(915)
+	b1 := getempty()
 	n := b.nobj / 2
 	b.nobj -= n
 	b1.nobj = n
@@ -462,6 +426,6 @@ func handoff(b *workbuf) *workbuf {
 	_g_.m.gcstats.nhandoffcnt += uint64(n)
 
 	// Put b on full list - let first half of b get stolen.
-	putfull(b, 942)
+	putfull(b)
 	return b1
 }
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index a153df0..4093288 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -46,7 +46,7 @@ type mheap struct {
 	nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)
 
 	// range of addresses we might see in the heap
-	bitmap         uintptr
+	bitmap         uintptr // Points to one byte past the end of the bitmap
 	bitmap_mapped  uintptr
 	arena_start    uintptr
 	arena_used     uintptr // always mHeap_Map{Bits,Spans} before updating
@@ -117,9 +117,63 @@ type mspan struct {
 	prev **mspan    // previous span's next field, or list head's first field if none
 	list *mSpanList // For debugging. TODO: Remove.
 
-	start    pageID    // starting page number
-	npages   uintptr   // number of pages in span
-	freelist gclinkptr // list of free objects
+	startAddr     uintptr   // address of first byte of span aka s.base()
+	npages        uintptr   // number of pages in span
+	stackfreelist gclinkptr // list of free stacks, avoids overloading freelist
+
+	// freeindex is the slot index between 0 and nelems at which to begin scanning
+	// for the next free object in this span.
+	// Each allocation scans allocBits starting at freeindex until it encounters a 0
+	// indicating a free object. freeindex is then adjusted so that subsequent scans begin
+	// just past the the newly discovered free object.
+	//
+	// If freeindex == nelem, this span has no free objects.
+	//
+	// allocBits is a bitmap of objects in this span.
+	// If n >= freeindex and allocBits[n/8] & (1<<(n%8)) is 0
+	// then object n is free;
+	// otherwise, object n is allocated. Bits starting at nelem are
+	// undefined and should never be referenced.
+	//
+	// Object n starts at address n*elemsize + (start << pageShift).
+	freeindex uintptr
+	// TODO: Look up nelems from sizeclass and remove this field if it
+	// helps performance.
+	nelems uintptr // number of object in the span.
+
+	// Cache of the allocBits at freeindex. allocCache is shifted
+	// such that the lowest bit corresponds to the bit freeindex.
+	// allocCache holds the complement of allocBits, thus allowing
+	// ctz (count trailing zero) to use it directly.
+	// allocCache may contain bits beyond s.nelems; the caller must ignore
+	// these.
+	allocCache uint64
+
+	// allocBits and gcmarkBits hold pointers to a span's mark and
+	// allocation bits. The pointers are 8 byte aligned.
+	// There are three arenas where this data is held.
+	// free: Dirty arenas that are no longer accessed
+	//       and can be reused.
+	// next: Holds information to be used in the next GC cycle.
+	// current: Information being used during this GC cycle.
+	// previous: Information being used during the last GC cycle.
+	// A new GC cycle starts with the call to finishsweep_m.
+	// finishsweep_m moves the previous arena to the free arena,
+	// the current arena to the previous arena, and
+	// the next arena to the current arena.
+	// The next arena is populated as the spans request
+	// memory to hold gcmarkBits for the next GC cycle as well
+	// as allocBits for newly allocated spans.
+	//
+	// The pointer arithmetic is done "by hand" instead of using
+	// arrays to avoid bounds checks along critical performance
+	// paths.
+	// The sweep will free the old allocBits and set allocBits to the
+	// gcmarkBits. The gcmarkBits are replaced with a fresh zeroed
+	// out memory.
+	allocBits  *uint8
+	gcmarkBits *uint8
+
 	// sweep generation:
 	// if sweepgen == h->sweepgen - 2, the span needs sweeping
 	// if sweepgen == h->sweepgen - 1, the span is currently being swept
@@ -128,7 +182,7 @@ type mspan struct {
 
 	sweepgen    uint32
 	divMul      uint32   // for divide by elemsize - divMagic.mul
-	ref         uint16   // capacity - number of objects in freelist
+	allocCount  uint16   // capacity - number of objects in freelist
 	sizeclass   uint8    // size class
 	incache     bool     // being used by an mcache
 	state       uint8    // mspaninuse etc
@@ -145,7 +199,7 @@ type mspan struct {
 }
 
 func (s *mspan) base() uintptr {
-	return uintptr(s.start << _PageShift)
+	return s.startAddr
 }
 
 func (s *mspan) layout() (size, n, total uintptr) {
@@ -161,7 +215,7 @@ var h_allspans []*mspan // TODO: make this h.allspans once mheap can be defined
 
 // 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
+// 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
@@ -191,7 +245,7 @@ func recordspan(vh unsafe.Pointer, p unsafe.Pointer) {
 			}
 		}
 		h_allspans = new
-		h.allspans = (**mspan)(unsafe.Pointer(sp.array))
+		h.allspans = (**mspan)(sp.array)
 	}
 	h_allspans = append(h_allspans, s)
 	h.nspan = uint32(len(h_allspans))
@@ -207,16 +261,35 @@ func inheap(b uintptr) bool {
 		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 {
+	s := h_spans[(b-mheap_.arena_start)>>_PageShift]
+	if s == nil || b < s.base() || b >= s.limit || s.state != mSpanInUse {
 		return false
 	}
 	return true
 }
 
+// inHeapOrStack is a variant of inheap that returns true for pointers into stack spans.
+//go:nowritebarrier
+//go:nosplit
+func inHeapOrStack(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.
+	s := h_spans[(b-mheap_.arena_start)>>_PageShift]
+	if s == nil || b < s.base() {
+		return false
+	}
+	switch s.state {
+	case mSpanInUse:
+		return b < s.limit
+	case _MSpanStack:
+		return b < s.base()+s.npages<<_PageShift
+	default:
+		return false
+	}
+}
+
 // TODO: spanOf and spanOfUnchecked are open-coded in a lot of places.
 // Use the functions instead.
 
@@ -261,7 +334,7 @@ func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
 		return 0
 	}
 
-	p := uintptr(s.start) << _PageShift
+	p := s.base()
 	if s.sizeclass == 0 {
 		// Large object.
 		if base != nil {
@@ -275,7 +348,7 @@ func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
 
 	n := s.elemsize
 	if base != nil {
-		i := (uintptr(v) - uintptr(p)) / n
+		i := (v - p) / n
 		*base = p + i*n
 	}
 	if size != nil {
@@ -440,8 +513,7 @@ func (h *mheap) alloc_m(npage uintptr, sizeclass int32, large bool) *mspan {
 		// able to map interior pointer to containing span.
 		atomic.Store(&s.sweepgen, h.sweepgen)
 		s.state = _MSpanInUse
-		s.freelist = 0
-		s.ref = 0
+		s.allocCount = 0
 		s.sizeclass = uint8(sizeclass)
 		if sizeclass == 0 {
 			s.elemsize = s.npages << _PageShift
@@ -504,7 +576,7 @@ func (h *mheap) alloc(npage uintptr, sizeclass int32, large bool, needzero bool)
 
 	if s != nil {
 		if needzero && s.needzero != 0 {
-			memclr(unsafe.Pointer(s.start<<_PageShift), s.npages<<_PageShift)
+			memclr(unsafe.Pointer(s.base()), s.npages<<_PageShift)
 		}
 		s.needzero = 0
 	}
@@ -520,8 +592,8 @@ func (h *mheap) allocStack(npage uintptr) *mspan {
 	s := h.allocSpanLocked(npage)
 	if s != nil {
 		s.state = _MSpanStack
-		s.freelist = 0
-		s.ref = 0
+		s.stackfreelist = 0
+		s.allocCount = 0
 		memstats.stacks_inuse += uint64(s.npages << _PageShift)
 	}
 
@@ -572,7 +644,7 @@ HaveSpan:
 		throw("still in list")
 	}
 	if s.npreleased > 0 {
-		sysUsed(unsafe.Pointer(s.start<<_PageShift), s.npages<<_PageShift)
+		sysUsed(unsafe.Pointer(s.base()), s.npages<<_PageShift)
 		memstats.heap_released -= uint64(s.npreleased << _PageShift)
 		s.npreleased = 0
 	}
@@ -580,10 +652,9 @@ HaveSpan:
 	if s.npages > npage {
 		// Trim extra and put it back in the heap.
 		t := (*mspan)(h.spanalloc.alloc())
-		t.init(s.start+pageID(npage), s.npages-npage)
+		t.init(s.base()+npage<<_PageShift, s.npages-npage)
 		s.npages = npage
-		p := uintptr(t.start)
-		p -= (h.arena_start >> _PageShift)
+		p := (t.base() - h.arena_start) >> _PageShift
 		if p > 0 {
 			h_spans[p-1] = s
 		}
@@ -597,8 +668,7 @@ HaveSpan:
 	}
 	s.unusedsince = 0
 
-	p := uintptr(s.start)
-	p -= (h.arena_start >> _PageShift)
+	p := (s.base() - h.arena_start) >> _PageShift
 	for n := uintptr(0); n < npage; n++ {
 		h_spans[p+n] = s
 	}
@@ -626,7 +696,7 @@ func bestFit(list *mSpanList, npage uintptr, best *mspan) *mspan {
 		if s.npages < npage {
 			continue
 		}
-		if best == nil || s.npages < best.npages || (s.npages == best.npages && s.start < best.start) {
+		if best == nil || s.npages < best.npages || (s.npages == best.npages && s.base() < best.base()) {
 			best = s
 		}
 	}
@@ -663,9 +733,8 @@ func (h *mheap) grow(npage uintptr) bool {
 	// Create a fake "in use" span and free it, so that the
 	// right coalescing happens.
 	s := (*mspan)(h.spanalloc.alloc())
-	s.init(pageID(uintptr(v)>>_PageShift), ask>>_PageShift)
-	p := uintptr(s.start)
-	p -= (h.arena_start >> _PageShift)
+	s.init(uintptr(v), ask>>_PageShift)
+	p := (s.base() - h.arena_start) >> _PageShift
 	for i := p; i < p+s.npages; i++ {
 		h_spans[i] = s
 	}
@@ -689,18 +758,15 @@ func (h *mheap) lookup(v unsafe.Pointer) *mspan {
 // 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
+// valid for allocated spans. Free spans may have
 // other garbage in their middles, so we have to
 // check for that.
 func (h *mheap) lookupMaybe(v unsafe.Pointer) *mspan {
 	if uintptr(v) < h.arena_start || uintptr(v) >= h.arena_used {
 		return nil
 	}
-	p := uintptr(v) >> _PageShift
-	q := p
-	q -= 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 {
+	s := h_spans[(uintptr(v)-h.arena_start)>>_PageShift]
+	if s == nil || uintptr(v) < s.base() || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != _MSpanInUse {
 		return nil
 	}
 	return s
@@ -715,6 +781,12 @@ func (h *mheap) freeSpan(s *mspan, acct int32) {
 		mp.mcache.local_scan = 0
 		memstats.tinyallocs += uint64(mp.mcache.local_tinyallocs)
 		mp.mcache.local_tinyallocs = 0
+		if msanenabled {
+			// Tell msan that this entire span is no longer in use.
+			base := unsafe.Pointer(s.base())
+			bytes := s.npages << _PageShift
+			msanfree(base, bytes)
+		}
 		if acct != 0 {
 			memstats.heap_objects--
 		}
@@ -743,12 +815,12 @@ func (h *mheap) freeStack(s *mspan) {
 func (h *mheap) freeSpanLocked(s *mspan, acctinuse, acctidle bool, unusedsince int64) {
 	switch s.state {
 	case _MSpanStack:
-		if s.ref != 0 {
+		if s.allocCount != 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")
+		if s.allocCount != 0 || s.sweepgen != h.sweepgen {
+			print("MHeap_FreeSpanLocked - span ", s, " ptr ", hex(s.base()), " allocCount ", s.allocCount, " sweepgen ", s.sweepgen, "/", h.sweepgen, "\n")
 			throw("MHeap_FreeSpanLocked - invalid free")
 		}
 		h.pagesInUse -= uint64(s.npages)
@@ -776,12 +848,11 @@ func (h *mheap) freeSpanLocked(s *mspan, acctinuse, acctidle bool, unusedsince i
 	s.npreleased = 0
 
 	// Coalesce with earlier, later spans.
-	p := uintptr(s.start)
-	p -= h.arena_start >> _PageShift
+	p := (s.base() - h.arena_start) >> _PageShift
 	if p > 0 {
 		t := h_spans[p-1]
 		if t != nil && t.state == _MSpanFree {
-			s.start = t.start
+			s.startAddr = t.startAddr
 			s.npages += t.npages
 			s.npreleased = t.npreleased // absorb released pages
 			s.needzero |= t.needzero
@@ -824,15 +895,6 @@ func (h *mheap) busyList(npages uintptr) *mSpanList {
 }
 
 func scavengelist(list *mSpanList, now, limit uint64) uintptr {
-	if sys.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 list.isEmpty() {
 		return 0
 	}
@@ -840,11 +902,30 @@ func scavengelist(list *mSpanList, now, limit uint64) uintptr {
 	var sumreleased uintptr
 	for s := list.first; s != nil; s = s.next {
 		if (now-uint64(s.unusedsince)) > limit && s.npreleased != s.npages {
-			released := (s.npages - s.npreleased) << _PageShift
+			start := s.base()
+			end := start + s.npages<<_PageShift
+			if sys.PhysPageSize > _PageSize {
+				// We can only release pages in
+				// PhysPageSize blocks, so round start
+				// and end in. (Otherwise, madvise
+				// will round them *out* and release
+				// more memory than we want.)
+				start = (start + sys.PhysPageSize - 1) &^ (sys.PhysPageSize - 1)
+				end &^= sys.PhysPageSize - 1
+				if start == end {
+					continue
+				}
+			}
+			len := end - start
+
+			released := len - (s.npreleased << _PageShift)
+			if sys.PhysPageSize > _PageSize && released == 0 {
+				continue
+			}
 			memstats.heap_released += uint64(released)
 			sumreleased += released
-			s.npreleased = s.npages
-			sysUnused(unsafe.Pointer(s.start<<_PageShift), s.npages<<_PageShift)
+			s.npreleased = len >> _PageShift
+			sysUnused(unsafe.Pointer(start), len)
 		}
 	}
 	return sumreleased
@@ -876,14 +957,13 @@ func runtime_debug_freeOSMemory() {
 }
 
 // Initialize a new span with the given start and npages.
-func (span *mspan) init(start pageID, npages uintptr) {
+func (span *mspan) init(base uintptr, npages uintptr) {
 	span.next = nil
 	span.prev = nil
 	span.list = nil
-	span.start = start
+	span.startAddr = base
 	span.npages = npages
-	span.freelist = 0
-	span.ref = 0
+	span.allocCount = 0
 	span.sizeclass = 0
 	span.incache = false
 	span.elemsize = 0
@@ -893,6 +973,9 @@ func (span *mspan) init(start pageID, npages uintptr) {
 	span.speciallock.key = 0
 	span.specials = nil
 	span.needzero = 0
+	span.freeindex = 0
+	span.allocBits = nil
+	span.gcmarkBits = nil
 }
 
 func (span *mspan) inList() bool {
@@ -907,7 +990,7 @@ func (list *mSpanList) init() {
 
 func (list *mSpanList) remove(span *mspan) {
 	if span.prev == nil || span.list != list {
-		println("failed MSpanList_Remove", span, span.prev, span.list, list)
+		println("runtime: failed MSpanList_Remove", span, span.prev, span.list, list)
 		throw("MSpanList_Remove")
 	}
 	if span.next != nil {
@@ -929,7 +1012,7 @@ func (list *mSpanList) isEmpty() bool {
 
 func (list *mSpanList) insert(span *mspan) {
 	if span.next != nil || span.prev != nil || span.list != nil {
-		println("failed MSpanList_Insert", span, span.next, span.prev, span.list)
+		println("runtime: failed MSpanList_Insert", span, span.next, span.prev, span.list)
 		throw("MSpanList_Insert")
 	}
 	span.next = list.first
@@ -971,7 +1054,7 @@ type special struct {
 }
 
 // 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
+// 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
@@ -988,7 +1071,7 @@ func addspecial(p unsafe.Pointer, s *special) bool {
 	mp := acquirem()
 	span.ensureSwept()
 
-	offset := uintptr(p) - uintptr(span.start<<_PageShift)
+	offset := uintptr(p) - span.base()
 	kind := s.kind
 
 	lock(&span.speciallock)
@@ -1036,7 +1119,7 @@ func removespecial(p unsafe.Pointer, kind uint8) *special {
 	mp := acquirem()
 	span.ensureSwept()
 
-	offset := uintptr(p) - uintptr(span.start<<_PageShift)
+	offset := uintptr(p) - span.base()
 
 	lock(&span.speciallock)
 	t := &span.specials
@@ -1069,7 +1152,7 @@ type specialfinalizer struct {
 	ot      *ptrtype
 }
 
-// Adds a finalizer to the object p.  Returns true if it succeeded.
+// 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)(mheap_.specialfinalizeralloc.alloc())
@@ -1138,7 +1221,7 @@ func setprofilebucket(p unsafe.Pointer, b *bucket) {
 	}
 }
 
-// Do whatever cleanup needs to be done to deallocate s.  It has
+// Do whatever cleanup needs to be done to deallocate s. It has
 // already been unlinked from the MSpan specials list.
 func freespecial(s *special, p unsafe.Pointer, size uintptr) {
 	switch s.kind {
@@ -1159,3 +1242,117 @@ func freespecial(s *special, p unsafe.Pointer, size uintptr) {
 		panic("not reached")
 	}
 }
+
+const gcBitsChunkBytes = uintptr(64 << 10)
+const gcBitsHeaderBytes = unsafe.Sizeof(gcBitsHeader{})
+
+type gcBitsHeader struct {
+	free uintptr // free is the index into bits of the next free byte.
+	next uintptr // *gcBits triggers recursive type bug. (issue 14620)
+}
+
+type gcBits struct {
+	// gcBitsHeader // side step recursive type bug (issue 14620) by including fields by hand.
+	free uintptr // free is the index into bits of the next free byte.
+	next *gcBits
+	bits [gcBitsChunkBytes - gcBitsHeaderBytes]uint8
+}
+
+var gcBitsArenas struct {
+	lock     mutex
+	free     *gcBits
+	next     *gcBits
+	current  *gcBits
+	previous *gcBits
+}
+
+// newMarkBits returns a pointer to 8 byte aligned bytes
+// to be used for a span's mark bits.
+func newMarkBits(nelems uintptr) *uint8 {
+	lock(&gcBitsArenas.lock)
+	blocksNeeded := uintptr((nelems + 63) / 64)
+	bytesNeeded := blocksNeeded * 8
+	if gcBitsArenas.next == nil ||
+		gcBitsArenas.next.free+bytesNeeded > uintptr(len(gcBits{}.bits)) {
+		// Allocate a new arena.
+		fresh := newArena()
+		fresh.next = gcBitsArenas.next
+		gcBitsArenas.next = fresh
+	}
+	if gcBitsArenas.next.free >= gcBitsChunkBytes {
+		println("runtime: gcBitsArenas.next.free=", gcBitsArenas.next.free, gcBitsChunkBytes)
+		throw("markBits overflow")
+	}
+	result := &gcBitsArenas.next.bits[gcBitsArenas.next.free]
+	gcBitsArenas.next.free += bytesNeeded
+	unlock(&gcBitsArenas.lock)
+	return result
+}
+
+// newAllocBits returns a pointer to 8 byte aligned bytes
+// to be used for this span's alloc bits.
+// newAllocBits is used to provide newly initialized spans
+// allocation bits. For spans not being initialized the
+// the mark bits are repurposed as allocation bits when
+// the span is swept.
+func newAllocBits(nelems uintptr) *uint8 {
+	return newMarkBits(nelems)
+}
+
+// nextMarkBitArenaEpoch establishes a new epoch for the arenas
+// holding the mark bits. The arenas are named relative to the
+// current GC cycle which is demarcated by the call to finishweep_m.
+//
+// All current spans have been swept.
+// During that sweep each span allocated room for its gcmarkBits in
+// gcBitsArenas.next block. gcBitsArenas.next becomes the gcBitsArenas.current
+// where the GC will mark objects and after each span is swept these bits
+// will be used to allocate objects.
+// gcBitsArenas.current becomes gcBitsArenas.previous where the span's
+// gcAllocBits live until all the spans have been swept during this GC cycle.
+// The span's sweep extinguishes all the references to gcBitsArenas.previous
+// by pointing gcAllocBits into the gcBitsArenas.current.
+// The gcBitsArenas.previous is released to the gcBitsArenas.free list.
+func nextMarkBitArenaEpoch() {
+	lock(&gcBitsArenas.lock)
+	if gcBitsArenas.previous != nil {
+		if gcBitsArenas.free == nil {
+			gcBitsArenas.free = gcBitsArenas.previous
+		} else {
+			// Find end of previous arenas.
+			last := gcBitsArenas.previous
+			for last = gcBitsArenas.previous; last.next != nil; last = last.next {
+			}
+			last.next = gcBitsArenas.free
+			gcBitsArenas.free = gcBitsArenas.previous
+		}
+	}
+	gcBitsArenas.previous = gcBitsArenas.current
+	gcBitsArenas.current = gcBitsArenas.next
+	gcBitsArenas.next = nil // newMarkBits calls newArena when needed
+	unlock(&gcBitsArenas.lock)
+}
+
+// newArena allocates and zeroes a gcBits arena.
+func newArena() *gcBits {
+	var result *gcBits
+	if gcBitsArenas.free == nil {
+		result = (*gcBits)(sysAlloc(gcBitsChunkBytes, &memstats.gc_sys))
+		if result == nil {
+			throw("runtime: cannot allocate memory")
+		}
+	} else {
+		result = gcBitsArenas.free
+		gcBitsArenas.free = gcBitsArenas.free.next
+		memclr(unsafe.Pointer(result), gcBitsChunkBytes)
+	}
+	result.next = nil
+	// If result.bits is not 8 byte aligned adjust index so
+	// that &result.bits[result.free] is 8 byte aligned.
+	if uintptr(unsafe.Offsetof(gcBits{}.bits))&7 == 0 {
+		result.free = 0
+	} else {
+		result.free = 8 - (uintptr(unsafe.Pointer(&result.bits[0])) & 7)
+	}
+	return result
+}
diff --git a/src/runtime/mknacl.sh b/src/runtime/mknacl.sh
index 47fb7bd..0a74db1 100644
--- a/src/runtime/mknacl.sh
+++ b/src/runtime/mknacl.sh
@@ -1,5 +1,5 @@
 #!/bin/bash
-# Copyright 2013 The Go Authors.  All rights reserved.
+# 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/src/runtime/mmap.go b/src/runtime/mmap.go
index a076842..53617e4 100644
--- a/src/runtime/mmap.go
+++ b/src/runtime/mmap.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -12,5 +12,8 @@ package runtime
 
 import "unsafe"
 
-// mmap calls the mmap system call.  It is implemented in assembly.
+// mmap calls the mmap system call. It is implemented in assembly.
+// 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.
 func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index fc73bbf..c3e4e2c 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -262,7 +262,7 @@ func mProf_Free(b *bucket, size uintptr) {
 var blockprofilerate uint64 // in CPU ticks
 
 // SetBlockProfileRate controls the fraction of goroutine blocking events
-// that are reported in the blocking profile.  The profiler aims to sample
+// that are reported in the blocking profile. The profiler aims to sample
 // an average of one blocking event per rate nanoseconds spent blocked.
 //
 // To include every blocking event in the profile, pass rate = 1.
@@ -335,7 +335,7 @@ func (r *StackRecord) Stack() []uintptr {
 //
 // The tools that process the memory profiles assume that the
 // profile rate is constant across the lifetime of the program
-// and equal to the current value.  Programs that change the
+// and equal to the current value. Programs that change the
 // memory profiling rate should do so just once, as early as
 // possible in the execution of the program (for example,
 // at the beginning of main).
@@ -448,7 +448,7 @@ func iterate_memprof(fn func(*bucket, uintptr, *uintptr, uintptr, uintptr, uintp
 	lock(&proflock)
 	for b := mbuckets; b != nil; b = b.allnext {
 		mp := b.mp()
-		fn(b, uintptr(b.nstk), &b.stk()[0], b.size, mp.allocs, mp.frees)
+		fn(b, b.nstk, &b.stk()[0], b.size, mp.allocs, mp.frees)
 	}
 	unlock(&proflock)
 }
@@ -478,8 +478,8 @@ func BlockProfile(p []BlockProfileRecord) (n int, ok bool) {
 		for b := bbuckets; b != nil; b = b.allnext {
 			bp := b.bp()
 			r := &p[0]
-			r.Count = int64(bp.count)
-			r.Cycles = int64(bp.cycles)
+			r.Count = bp.count
+			r.Cycles = bp.cycles
 			i := copy(r.Stack0[:], b.stk())
 			for ; i < len(r.Stack0); i++ {
 				r.Stack0[i] = 0
@@ -506,9 +506,7 @@ func ThreadCreateProfile(p []StackRecord) (n int, ok bool) {
 		ok = true
 		i := 0
 		for mp := first; mp != nil; mp = mp.alllink {
-			for s := range mp.createstack {
-				p[i].Stack0[s] = uintptr(mp.createstack[s])
-			}
+			p[i].Stack0 = mp.createstack
 			i++
 		}
 	}
@@ -626,7 +624,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
 	if typ == nil {
 		print("tracealloc(", p, ", ", hex(size), ")\n")
 	} else {
-		print("tracealloc(", p, ", ", hex(size), ", ", *typ._string, ")\n")
+		print("tracealloc(", p, ", ", hex(size), ", ", typ.string(), ")\n")
 	}
 	if gp.m.curg == nil || gp == gp.m.curg {
 		goroutineheader(gp)
diff --git a/src/runtime/msan.go b/src/runtime/msan.go
index 4dbdf05..7177c8e 100644
--- a/src/runtime/msan.go
+++ b/src/runtime/msan.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -24,10 +24,10 @@ func MSanWrite(addr unsafe.Pointer, len int) {
 const msanenabled = true
 
 // If we are running on the system stack, the C program may have
-// marked part of that stack as uninitialized.  We don't instrument
+// marked part of that stack as uninitialized. We don't instrument
 // the runtime, but operations like a slice copy can call msanread
-// anyhow for values on the stack.  Just ignore msanread when running
-// on the system stack.  The other msan functions are fine.
+// anyhow for values on the stack. Just ignore msanread when running
+// on the system stack. The other msan functions are fine.
 func msanread(addr unsafe.Pointer, sz uintptr) {
 	g := getg()
 	if g == g.m.g0 || g == g.m.gsignal {
diff --git a/src/runtime/msan0.go b/src/runtime/msan0.go
index e206720..117c5e5 100644
--- a/src/runtime/msan0.go
+++ b/src/runtime/msan0.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/msan_amd64.s b/src/runtime/msan_amd64.s
index 6131495..9c59eec 100644
--- a/src/runtime/msan_amd64.s
+++ b/src/runtime/msan_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/msize.go b/src/runtime/msize.go
index bc735be..18577b3 100644
--- a/src/runtime/msize.go
+++ b/src/runtime/msize.go
@@ -13,7 +13,7 @@
 // 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
+// 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
@@ -27,7 +27,7 @@
 
 package runtime
 
-// Size classes.  Computed and initialized by InitSizes.
+// Size classes. Computed and initialized by InitSizes.
 //
 // SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
 //	1 <= sizeclass < NumSizeClasses, for n.
@@ -55,7 +55,7 @@ var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8
 
 func sizeToClass(size int32) int32 {
 	if size > _MaxSmallSize {
-		throw("SizeToClass - invalid size")
+		throw("invalid size")
 	}
 	if size > 1024-8 {
 		return int32(size_to_class128[(size-1024+127)>>7])
@@ -79,7 +79,7 @@ func initSizes() {
 			}
 		}
 		if align&(align-1) != 0 {
-			throw("InitSizes - bug")
+			throw("incorrect alignment")
 		}
 
 		// Make the allocnpages big enough that
@@ -106,10 +106,18 @@ func initSizes() {
 		sizeclass++
 	}
 	if sizeclass != _NumSizeClasses {
-		print("sizeclass=", sizeclass, " NumSizeClasses=", _NumSizeClasses, "\n")
-		throw("InitSizes - bad NumSizeClasses")
+		print("runtime: sizeclass=", sizeclass, " NumSizeClasses=", _NumSizeClasses, "\n")
+		throw("bad NumSizeClasses")
+	}
+	// Check maxObjsPerSpan => number of objects invariant.
+	for i, size := range class_to_size {
+		if size != 0 && class_to_allocnpages[i]*pageSize/size > maxObjsPerSpan {
+			throw("span contains too many objects")
+		}
+		if size == 0 && i != 0 {
+			throw("size is 0 but class is not 0")
+		}
 	}
-
 	// Initialize the size_to_class tables.
 	nextsize := 0
 	for sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++ {
@@ -128,12 +136,12 @@ func initSizes() {
 		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("runtime: 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("runtime: size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
 				print("SizeToClass too big\n")
 				goto dump
 			}
@@ -155,18 +163,18 @@ func initSizes() {
 
 dump:
 	if true {
-		print("NumSizeClasses=", _NumSizeClasses, "\n")
+		print("runtime: 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:")
+		print("runtime: 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:")
+		print("runtime: 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")
 		}
diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go
index 368687d..2d75d2f 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -165,7 +165,7 @@ type MemStats struct {
 
 // 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.
+// NumSizeClasses was changed, but we cannot 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])
 
@@ -192,7 +192,7 @@ 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.
+	// NumSizeClasses was changed, but we cannot 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
@@ -295,9 +295,9 @@ func updatememstats(stats *gcstats) {
 			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)
+			memstats.nmalloc += uint64(s.allocCount)
+			memstats.by_size[s.sizeclass].nmalloc += uint64(s.allocCount)
+			memstats.alloc += uint64(s.allocCount) * uint64(s.elemsize)
 		}
 	}
 	unlock(&mheap_.lock)
@@ -309,13 +309,13 @@ func updatememstats(stats *gcstats) {
 		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])
+		smallfree += 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.total_alloc = memstats.alloc + mheap_.largefree + smallfree
 	memstats.heap_alloc = memstats.alloc
 	memstats.heap_objects = memstats.nmalloc - memstats.nfree
 }
@@ -371,7 +371,7 @@ func purgecachedstats(c *mcache) {
 	}
 }
 
-// Atomically increases a given *system* memory stat.  We are counting on this
+// 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.
 //
@@ -395,7 +395,7 @@ func mSysStatInc(sysStat *uint64, n uintptr) {
 	}
 }
 
-// Atomically decreases a given *system* memory stat.  Same comments as
+// Atomically decreases a given *system* memory stat. Same comments as
 // mSysStatInc apply.
 //go:nosplit
 func mSysStatDec(sysStat *uint64, n uintptr) {
diff --git a/src/runtime/mstkbar.go b/src/runtime/mstkbar.go
index 016625a..1bf9d57 100644
--- a/src/runtime/mstkbar.go
+++ b/src/runtime/mstkbar.go
@@ -214,14 +214,15 @@ func gcInstallStackBarrier(gp *g, frame *stkframe) bool {
 }
 
 // gcRemoveStackBarriers removes all stack barriers installed in gp's stack.
+//
+// gp's stack barriers must be locked.
+//
 //go:nowritebarrier
 func gcRemoveStackBarriers(gp *g) {
 	if debugStackBarrier && gp.stkbarPos != 0 {
 		print("hit ", gp.stkbarPos, " stack barriers, goid=", gp.goid, "\n")
 	}
 
-	gcLockStackBarriers(gp)
-
 	// Remove stack barriers that we didn't hit.
 	for _, stkbar := range gp.stkbar[gp.stkbarPos:] {
 		gcRemoveStackBarrier(gp, stkbar)
@@ -231,8 +232,6 @@ func gcRemoveStackBarriers(gp *g) {
 	// adjust them.
 	gp.stkbarPos = 0
 	gp.stkbar = gp.stkbar[:0]
-
-	gcUnlockStackBarriers(gp)
 }
 
 // gcRemoveStackBarrier removes a single stack barrier. It is the
@@ -258,6 +257,31 @@ func gcRemoveStackBarrier(gp *g, stkbar stkbar) {
 	*lrPtr = sys.Uintreg(stkbar.savedLRVal)
 }
 
+// gcTryRemoveAllStackBarriers tries to remove stack barriers from all
+// Gs in gps. It is best-effort and efficient. If it can't remove
+// barriers from a G immediately, it will simply skip it.
+func gcTryRemoveAllStackBarriers(gps []*g) {
+	for _, gp := range gps {
+	retry:
+		for {
+			switch s := readgstatus(gp); s {
+			default:
+				break retry
+
+			case _Grunnable, _Gsyscall, _Gwaiting:
+				if !castogscanstatus(gp, s, s|_Gscan) {
+					continue
+				}
+				gcLockStackBarriers(gp)
+				gcRemoveStackBarriers(gp)
+				gcUnlockStackBarriers(gp)
+				restartg(gp)
+				break retry
+			}
+		}
+	}
+}
+
 // gcPrintStkbars prints the stack barriers of gp for debugging. It
 // places a "@@@" marker at gp.stkbarPos. If marker >= 0, it will also
 // place a "==>" marker before the marker'th entry.
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 19adeff..2ef248d 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -122,7 +122,7 @@ func net_runtime_pollClose(pd *pollDesc) {
 	if pd.rg != 0 && pd.rg != pdReady {
 		throw("netpollClose: blocked read on closing descriptor")
 	}
-	netpollclose(uintptr(pd.fd))
+	netpollclose(pd.fd)
 	pollcache.free(pd)
 }
 
diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go
index 36956ba..337377a 100644
--- a/src/runtime/netpoll_kqueue.go
+++ b/src/runtime/netpoll_kqueue.go
@@ -31,7 +31,7 @@ func netpollinit() {
 
 func netpollopen(fd uintptr, pd *pollDesc) int32 {
 	// Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR)
-	// for the whole fd lifetime.  The notifications are automatically unregistered
+	// for the whole fd lifetime. The notifications are automatically unregistered
 	// when fd is closed.
 	var ev [2]keventt
 	*(*uintptr)(unsafe.Pointer(&ev[0].ident)) = fd
diff --git a/src/runtime/netpoll_solaris.go b/src/runtime/netpoll_solaris.go
index 86e9b99..53b2aac 100644
--- a/src/runtime/netpoll_solaris.go
+++ b/src/runtime/netpoll_solaris.go
@@ -58,7 +58,7 @@ import "unsafe"
 //
 // 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
+// asynchronously 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
@@ -125,7 +125,7 @@ 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
+	// asynchronous 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.
diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go
index 7e15cd2..7ad1158 100644
--- a/src/runtime/netpoll_windows.go
+++ b/src/runtime/netpoll_windows.go
@@ -33,7 +33,7 @@ type overlappedEntry struct {
 var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle
 
 func netpollinit() {
-	iocphandle = uintptr(stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX))
+	iocphandle = 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")
diff --git a/src/runtime/noasm.go b/src/runtime/noasm.go
index 351e325..0a8f9e6 100644
--- a/src/runtime/noasm.go
+++ b/src/runtime/noasm.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.
 
-// Routines that are implemented in assembly in asm_{amd64,386,arm,arm64,ppc64x}.s
+// Routines that are implemented in assembly in asm_{amd64,386,arm,arm64,ppc64x,s390x}.s
 
 // +build mips64 mips64le
 
diff --git a/src/runtime/norace_linux_test.go b/src/runtime/norace_linux_test.go
index bbf9d0b..3517a5d 100644
--- a/src/runtime/norace_linux_test.go
+++ b/src/runtime/norace_linux_test.go
@@ -1,8 +1,8 @@
-// Copyright 2015 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.
 
-// The file contains tests that can not run under race detector for some reason.
+// The file contains tests that cannot run under race detector for some reason.
 // +build !race
 
 package runtime_test
diff --git a/src/runtime/norace_test.go b/src/runtime/norace_test.go
index 3681bf1..e9b39b2 100644
--- a/src/runtime/norace_test.go
+++ b/src/runtime/norace_test.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.
 
-// The file contains tests that can not run under race detector for some reason.
+// The file contains tests that cannot run under race detector for some reason.
 // +build !race
 
 package runtime_test
diff --git a/src/runtime/os1_darwin.go b/src/runtime/os1_darwin.go
deleted file mode 100644
index 5c00407..0000000
--- a/src/runtime/os1_darwin.go
+++ /dev/null
@@ -1,538 +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"
-
-//extern SigTabTT runtime·sigtab[];
-
-type sigset uint32
-
-var sigset_all = ^sigset(0)
-
-func unimplemented(name string) {
-	println(name, "not implemented")
-	*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
-}
-
-//go:nosplit
-func semawakeup(mp *m) {
-	mach_semrelease(mp.waitsema)
-}
-
-//go:nosplit
-func semacreate(mp *m) {
-	if mp.waitsema != 0 {
-		return
-	}
-	systemstack(func() {
-		mp.waitsema = mach_semcreate()
-	})
-}
-
-// 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) {
-	if false {
-		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
-	}
-
-	var oset sigset
-	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 sigset
-	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 do synchronous initialization of Go code built with
-// -buildmode=c-archive or -buildmode=c-shared.
-// None of the Go runtime is initialized.
-//go:nosplit
-//go:nowritebarrierrec
-func libpreinit() {
-	initsig(true)
-}
-
-// 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
-}
-
-//go:nosplit
-func msigsave(mp *m) {
-	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-	sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
-	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
-// 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()
-
-	// The alternate signal stack is buggy on arm and arm64.
-	// The signal handler handles it directly.
-	// The sigaltstack assembly function does nothing.
-	if GOARCH != "arm" && GOARCH != "arm64" {
-		var st stackt
-		sigaltstack(nil, &st)
-		if st.ss_flags&_SS_DISABLE != 0 {
-			signalstack(&_g_.m.gsignal.stack)
-			_g_.m.newSigstack = true
-		} else {
-			// Use existing signal stack.
-			stsp := uintptr(unsafe.Pointer(st.ss_sp))
-			_g_.m.gsignal.stack.lo = stsp
-			_g_.m.gsignal.stack.hi = stsp + st.ss_size
-			_g_.m.gsignal.stackguard0 = stsp + _StackGuard
-			_g_.m.gsignal.stackguard1 = stsp + _StackGuard
-			_g_.m.gsignal.stackAlloc = st.ss_size
-			_g_.m.newSigstack = false
-		}
-	}
-
-	// restore signal mask from m.sigmask and unblock essential signals
-	nmask := _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.
-//go:nosplit
-func unminit() {
-	if getg().m.newSigstack {
-		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(_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(_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
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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 = ^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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i int32) {
-	var osa usigactiont
-	sigaction(uint32(i), nil, &osa)
-	handler := *(*uintptr)(unsafe.Pointer(&osa.__sigaction_u))
-	if handler == 0 || handler == _SIG_DFL || handler == _SIG_IGN || osa.sa_flags&_SA_ONSTACK != 0 {
-		return
-	}
-	var sa sigactiont
-	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
-	sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp))
-	sa.sa_mask = osa.sa_mask
-	sa.sa_flags = osa.sa_flags | _SA_ONSTACK
-	sigaction(uint32(i), &sa, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func getsig(i int32) uintptr {
-	var sa usigactiont
-	sigaction(uint32(i), nil, &sa)
-	return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
-}
-
-//go:nosplit
-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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
-	s := sigset(m[0])
-	sigprocmask(_SIG_SETMASK, &s, nil)
-}
-
-func unblocksig(sig int32) {
-	mask := sigset(1) << (uint32(sig) - 1)
-	sigprocmask(_SIG_UNBLOCK, &mask, nil)
-}
diff --git a/src/runtime/os1_dragonfly.go b/src/runtime/os1_dragonfly.go
deleted file mode 100644
index bf3e1cc..0000000
--- a/src/runtime/os1_dragonfly.go
+++ /dev/null
@@ -1,270 +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
-
-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, " 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,
-	}
-
-	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
-}
-
-//go:nosplit
-func msigsave(mp *m) {
-	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-	sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
-	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
-// 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.
-
-	// On DragonFly a thread created by pthread_create inherits
-	// the signal stack of the creating thread.  We always create
-	// a new signal stack here, to avoid having two Go threads
-	// using the same signal stack.  This breaks the case of a
-	// thread created in C that calls sigaltstack and then calls a
-	// Go function, because we will lose track of the C code's
-	// sigaltstack, but it's the best we can do.
-	signalstack(&_g_.m.gsignal.stack)
-	_g_.m.newSigstack = true
-
-	// restore signal mask from m.sigmask and unblock essential signals
-	nmask := _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.
-//go:nosplit
-func unminit() {
-	if getg().m.newSigstack {
-		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
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i int32) {
-	throw("setsigstack")
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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
-}
-
-//go:nosplit
-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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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
deleted file mode 100644
index 79d9954..0000000
--- a/src/runtime/os1_freebsd.go
+++ /dev/null
@@ -1,281 +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
-
-import (
-	"runtime/internal/sys"
-	"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, " 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),
-	}
-
-	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
-}
-
-//go:nosplit
-func msigsave(mp *m) {
-	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-	sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
-	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
-// 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 sys.PtrSize == 4 {
-		_g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
-	}
-
-	// Initialize signal handling.
-	var st stackt
-	sigaltstack(nil, &st)
-	if st.ss_flags&_SS_DISABLE != 0 {
-		signalstack(&_g_.m.gsignal.stack)
-		_g_.m.newSigstack = true
-	} else {
-		// Use existing signal stack.
-		stsp := uintptr(unsafe.Pointer(st.ss_sp))
-		_g_.m.gsignal.stack.lo = stsp
-		_g_.m.gsignal.stack.hi = stsp + st.ss_size
-		_g_.m.gsignal.stackguard0 = stsp + _StackGuard
-		_g_.m.gsignal.stackguard1 = stsp + _StackGuard
-		_g_.m.gsignal.stackAlloc = st.ss_size
-		_g_.m.newSigstack = false
-	}
-
-	// restore signal mask from m.sigmask and unblock essential signals
-	nmask := _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.
-//go:nosplit
-func unminit() {
-	if getg().m.newSigstack {
-		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
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i int32) {
-	throw("setsigstack")
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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
-}
-
-//go:nosplit
-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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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
deleted file mode 100644
index b38cfc1..0000000
--- a/src/runtime/os1_linux.go
+++ /dev/null
@@ -1,388 +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 (
-	"runtime/internal/sys"
-	"unsafe"
-)
-
-// 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 sys.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).
-	// 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
-	var buf [maxCPUs / (sys.PtrSize * 8)]uintptr
-	r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
-	n := int32(0)
-	for _, v := range buf[:r/sys.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.
-	 */
-	if false {
-		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, " 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 do synchronous initialization of Go code built with
-// -buildmode=c-archive or -buildmode=c-shared.
-// None of the Go runtime is initialized.
-//go:nosplit
-//go:nowritebarrierrec
-func libpreinit() {
-	initsig(true)
-}
-
-// 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
-}
-
-//go:nosplit
-func msigsave(mp *m) {
-	smask := &mp.sigmask
-	rtsigprocmask(_SIG_SETMASK, nil, smask, int32(unsafe.Sizeof(*smask)))
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-	rtsigprocmask(_SIG_SETMASK, &sigmask, nil, int32(unsafe.Sizeof(sigmask)))
-}
-
-//go:nosplit
-func sigblock() {
-	rtsigprocmask(_SIG_SETMASK, &sigset_all, nil, int32(unsafe.Sizeof(sigset_all)))
-}
-
-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()
-
-	var st sigaltstackt
-	sigaltstack(nil, &st)
-	if st.ss_flags&_SS_DISABLE != 0 {
-		signalstack(&_g_.m.gsignal.stack)
-		_g_.m.newSigstack = true
-	} else {
-		// Use existing signal stack.
-		stsp := uintptr(unsafe.Pointer(st.ss_sp))
-		_g_.m.gsignal.stack.lo = stsp
-		_g_.m.gsignal.stack.hi = stsp + st.ss_size
-		_g_.m.gsignal.stackguard0 = stsp + _StackGuard
-		_g_.m.gsignal.stackguard1 = stsp + _StackGuard
-		_g_.m.gsignal.stackAlloc = st.ss_size
-		_g_.m.newSigstack = false
-	}
-
-	// for debuggers, in case cgo created the thread
-	_g_.m.procid = uint64(gettid())
-
-	// restore signal mask from m.sigmask and unblock essential signals
-	nmask := _g_.m.sigmask
-	for i := range sigtable {
-		if sigtable[i].flags&_SigUnblock != 0 {
-			sigdelset(&nmask, i)
-		}
-	}
-	rtsigprocmask(_SIG_SETMASK, &nmask, nil, int32(unsafe.Sizeof(nmask)))
-}
-
-// Called from dropm to undo the effect of an minit.
-//go:nosplit
-func unminit() {
-	if getg().m.newSigstack {
-		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()
-
-//go:nosplit
-//go:nowritebarrierrec
-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
-	}
-	sigfillset(&sa.sa_mask)
-	// 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
-	rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask))
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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")
-	}
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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
-}
-
-//go:nosplit
-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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
-	var mask sigset
-	sigcopyset(&mask, m)
-	rtsigprocmask(_SIG_SETMASK, &mask, nil, int32(unsafe.Sizeof(mask)))
-}
-
-func unblocksig(sig int32) {
-	var mask sigset
-	sigaddset(&mask, int(sig))
-	rtsigprocmask(_SIG_UNBLOCK, &mask, nil, int32(unsafe.Sizeof(mask)))
-}
diff --git a/src/runtime/os1_linux_generic.go b/src/runtime/os1_linux_generic.go
deleted file mode 100644
index 2c8b743..0000000
--- a/src/runtime/os1_linux_generic.go
+++ /dev/null
@@ -1,27 +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 !mips64
-// +build !mips64le
-// +build linux
-
-package runtime
-
-var sigset_all = sigset{^uint32(0), ^uint32(0)}
-
-func sigaddset(mask *sigset, i int) {
-	(*mask)[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
-}
-
-func sigdelset(mask *sigset, i int) {
-	(*mask)[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
-}
-
-func sigfillset(mask *uint64) {
-	*mask = ^uint64(0)
-}
-
-func sigcopyset(mask *sigset, m sigmask) {
-	copy((*mask)[:], m[:])
-}
diff --git a/src/runtime/os1_linux_mips64x.go b/src/runtime/os1_linux_mips64x.go
deleted file mode 100644
index 701e979..0000000
--- a/src/runtime/os1_linux_mips64x.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2015 The Go 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 mips64 mips64le
-// +build linux
-
-package runtime
-
-var sigset_all = sigset{^uint64(0), ^uint64(0)}
-
-func sigaddset(mask *sigset, i int) {
-	(*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63)
-}
-
-func sigdelset(mask *sigset, i int) {
-	(*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63)
-}
-
-func sigfillset(mask *[2]uint64) {
-	(*mask)[0], (*mask)[1] = ^uint64(0), ^uint64(0)
-}
-
-func sigcopyset(mask *sigset, m sigmask) {
-	(*mask)[0] = uint64(m[0]) | uint64(m[1])<<32
-}
diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go
deleted file mode 100644
index dab205d..0000000
--- a/src/runtime/os1_nacl.go
+++ /dev/null
@@ -1,214 +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.
-
-package runtime
-
-import "unsafe"
-
-type sigset struct{}
-
-// 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()
-
-//go:nosplit
-func msigsave(mp *m) {
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-}
-
-//go:nosplit
-func sigblock() {
-}
-
-// 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(preinit bool) {
-}
-
-//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(mp *m) {
-	if mp.waitsema != 0 {
-		return
-	}
-	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 ", -c, "\n")
-			throw("semacreate")
-		}
-		mp.waitsema = c
-		mp.waitsemalock = mu
-	})
-}
-
-//go:nosplit
-func semasleep(ns int64) int32 {
-	var ret int32
-
-	systemstack(func() {
-		_g_ := getg()
-		if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
-			throw("semasleep")
-		}
-
-		for _g_.m.waitsemacount == 0 {
-			if ns < 0 {
-				if nacl_cond_wait(_g_.m.waitsema, _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(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
-				if r == -_ETIMEDOUT {
-					nacl_mutex_unlock(_g_.m.waitsemalock)
-					ret = -1
-					return
-				}
-				if r < 0 {
-					throw("semasleep")
-				}
-			}
-		}
-
-		_g_.m.waitsemacount = 0
-		nacl_mutex_unlock(_g_.m.waitsemalock)
-		ret = 0
-	})
-	return ret
-}
-
-//go:nosplit
-func semawakeup(mp *m) {
-	systemstack(func() {
-		if nacl_mutex_lock(mp.waitsemalock) < 0 {
-			throw("semawakeup")
-		}
-		if mp.waitsemacount != 0 {
-			throw("semawakeup")
-		}
-		mp.waitsemacount = 1
-		nacl_cond_signal(mp.waitsema)
-		nacl_mutex_unlock(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
deleted file mode 100644
index eab8eb8..0000000
--- a/src/runtime/os1_netbsd.go
+++ /dev/null
@@ -1,275 +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
-
-import (
-	"runtime/internal/atomic"
-	"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(mp *m) {
-}
-
-//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 := atomic.Load(&_g_.m.waitsemacount)
-		if v > 0 {
-			if atomic.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) {
-	atomic.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, " ostk=", &mp, "\n")
-	}
-
-	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(netbsdMstart))
-
-	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")
-	}
-}
-
-// netbsdMStart is the function call that starts executing a newly
-// created thread.  On NetBSD, a new thread inherits the signal stack
-// of the creating thread.  That confuses minit, so we remove that
-// signal stack here before calling the regular mstart.  It's a bit
-// baroque to remove a signal stack here only to add one in minit, but
-// it's a simple change that keeps NetBSD working like other OS's.
-// At this point all signals are blocked, so there is no race.
-//go:nosplit
-func netbsdMstart() {
-	signalstack(nil)
-	mstart()
-}
-
-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
-}
-
-//go:nosplit
-func msigsave(mp *m) {
-	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-	sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
-	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
-// 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.
-
-	// On NetBSD a thread created by pthread_create inherits the
-	// signal stack of the creating thread.  We always create a
-	// new signal stack here, to avoid having two Go threads using
-	// the same signal stack.  This breaks the case of a thread
-	// created in C that calls sigaltstack and then calls a Go
-	// function, because we will lose track of the C code's
-	// sigaltstack, but it's the best we can do.
-	signalstack(&_g_.m.gsignal.stack)
-	_g_.m.newSigstack = true
-
-	// restore signal mask from m.sigmask and unblock essential signals
-	nmask := _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.
-//go:nosplit
-func unminit() {
-	if getg().m.newSigstack {
-		signalstack(nil)
-	}
-}
-
-func memlimit() uintptr {
-	return 0
-}
-
-func sigtramp()
-
-type sigactiont struct {
-	sa_sigaction uintptr
-	sa_mask      sigset
-	sa_flags     int32
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i int32) {
-	throw("setsigstack")
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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
-}
-
-//go:nosplit
-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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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_openbsd.go b/src/runtime/os1_openbsd.go
deleted file mode 100644
index a6cefa2..0000000
--- a/src/runtime/os1_openbsd.go
+++ /dev/null
@@ -1,278 +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
-
-import (
-	"runtime/internal/atomic"
-	"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
-)
-
-type sigset uint32
-
-const (
-	sigset_none = sigset(0)
-	sigset_all  = ^sigset(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(mp *m) {
-}
-
-//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 := atomic.Load(&_g_.m.waitsemacount)
-		if v > 0 {
-			if atomic.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) {
-	atomic.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, " ostk=", &mp, "\n")
-	}
-
-	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
-}
-
-//go:nosplit
-func msigsave(mp *m) {
-	mp.sigmask = sigprocmask(_SIG_BLOCK, 0)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-	sigprocmask(_SIG_SETMASK, sigmask)
-}
-
-//go:nosplit
-func sigblock() {
-	sigprocmask(_SIG_SETMASK, sigset_all)
-}
-
-// 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
-	var st stackt
-	sigaltstack(nil, &st)
-	if st.ss_flags&_SS_DISABLE != 0 {
-		signalstack(&_g_.m.gsignal.stack)
-		_g_.m.newSigstack = true
-	} else {
-		// Use existing signal stack.
-		stsp := uintptr(unsafe.Pointer(st.ss_sp))
-		_g_.m.gsignal.stack.lo = stsp
-		_g_.m.gsignal.stack.hi = stsp + st.ss_size
-		_g_.m.gsignal.stackguard0 = stsp + _StackGuard
-		_g_.m.gsignal.stackguard1 = stsp + _StackGuard
-		_g_.m.gsignal.stackAlloc = st.ss_size
-		_g_.m.newSigstack = false
-	}
-
-	// restore signal mask from m.sigmask and unblock essential signals
-	nmask := _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.
-//go:nosplit
-func unminit() {
-	if getg().m.newSigstack {
-		signalstack(nil)
-	}
-}
-
-func memlimit() uintptr {
-	return 0
-}
-
-func sigtramp()
-
-type sigactiont struct {
-	sa_sigaction uintptr
-	sa_mask      uint32
-	sa_flags     int32
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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 = uint32(sigset_all)
-	if fn == funcPC(sighandler) {
-		fn = funcPC(sigtramp)
-	}
-	sa.sa_sigaction = fn
-	sigaction(i, &sa, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i int32) {
-	throw("setsigstack")
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-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
-}
-
-//go:nosplit
-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)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
-	sigprocmask(_SIG_SETMASK, sigset(m[0]))
-}
-
-func unblocksig(sig int32) {
-	mask := sigset(1) << (uint32(sig) - 1)
-	sigprocmask(_SIG_UNBLOCK, mask)
-}
diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go
deleted file mode 100644
index 7506d59..0000000
--- a/src/runtime/os1_plan9.go
+++ /dev/null
@@ -1,278 +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.
-
-package runtime
-
-import (
-	"runtime/internal/atomic"
-	"unsafe"
-)
-
-type sigset struct{}
-
-// 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) {
-}
-
-func msigrestore(sigmask sigset) {
-}
-
-func sigblock() {
-}
-
-// 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(preinit bool) {
-}
-
-//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)(atomic.Loadp(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(mp *m) {
-}
-
-//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
deleted file mode 100644
index 8e41ac3..0000000
--- a/src/runtime/os1_windows.go
+++ /dev/null
@@ -1,682 +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 (
-	"runtime/internal/atomic"
-	"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._GetConsoleMode GetConsoleMode%2 "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._GetProcessAffinityMask GetProcessAffinityMask%3 "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._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
-//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.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,
-	_GetConsoleMode,
-	_GetEnvironmentStringsW,
-	_GetProcAddress,
-	_GetProcessAffinityMask,
-	_GetQueuedCompletionStatus,
-	_GetStdHandle,
-	_GetSystemInfo,
-	_GetThreadContext,
-	_LoadLibraryW,
-	_LoadLibraryA,
-	_NtWaitForSingleObject,
-	_ResumeThread,
-	_SetConsoleCtrlHandler,
-	_SetErrorMode,
-	_SetEvent,
-	_SetProcessPriorityBoost,
-	_SetThreadPriority,
-	_SetUnhandledExceptionFilter,
-	_SetWaitableTimer,
-	_SuspendThread,
-	_VirtualAlloc,
-	_VirtualFree,
-	_WSAGetOverlappedResult,
-	_WaitForSingleObject,
-	_WriteConsoleW,
-	_WriteFile stdFunction
-
-	// Following syscalls are only available on some Windows PCs.
-	// We will load syscalls, if available, before using them.
-	_AddDllDirectory,
-	_AddVectoredContinueHandler,
-	_GetQueuedCompletionStatusEx,
-	_LoadLibraryExW,
-	_ stdFunction
-)
-
-type sigset struct{}
-
-// 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 windowsFindfunc(name []byte, lib uintptr) stdFunction {
-	f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0])))
-	return stdFunction(unsafe.Pointer(f))
-}
-
-func loadOptionalSyscalls() {
-	var (
-		kernel32dll                 = []byte("kernel32.dll\000")
-		addVectoredContinueHandler  = []byte("AddVectoredContinueHandler\000")
-		getQueuedCompletionStatusEx = []byte("GetQueuedCompletionStatusEx\000")
-		addDllDirectory             = []byte("AddDllDirectory\000")
-		loadLibraryExW              = []byte("LoadLibraryExW\000")
-	)
-
-	k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
-	if k32 == 0 {
-		throw("kernel32.dll not found")
-	}
-	_AddDllDirectory = windowsFindfunc(addDllDirectory, k32)
-	_AddVectoredContinueHandler = windowsFindfunc(addVectoredContinueHandler, k32)
-	_GetQueuedCompletionStatusEx = windowsFindfunc(getQueuedCompletionStatusEx, k32)
-	_LoadLibraryExW = windowsFindfunc(loadLibraryExW, k32)
-}
-
-//go:nosplit
-func getLoadLibrary() uintptr {
-	return uintptr(unsafe.Pointer(_LoadLibraryW))
-}
-
-//go:nosplit
-func getLoadLibraryEx() uintptr {
-	return uintptr(unsafe.Pointer(_LoadLibraryExW))
-}
-
-//go:nosplit
-func getGetProcAddress() uintptr {
-	return uintptr(unsafe.Pointer(_GetProcAddress))
-}
-
-func getproccount() int32 {
-	var mask, sysmask uintptr
-	ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
-	if ret != 0 {
-		n := 0
-		maskbits := int(unsafe.Sizeof(mask) * 8)
-		for i := 0; i < maskbits; i++ {
-			if mask&(1<<uint(i)) != 0 {
-				n++
-			}
-		}
-		if n != 0 {
-			return int32(n)
-		}
-	}
-	// use GetSystemInfo if GetProcessAffinityMask fails
-	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()
-
-// When loading DLLs, we prefer to use LoadLibraryEx with
-// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not
-// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_*
-// flags are not available on some versions of Windows without a
-// security patch.
-//
-// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
-// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
-// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
-// systems that have KB2533623 installed. To determine whether the
-// flags are available, use GetProcAddress to get the address of the
-// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
-// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
-// flags can be used with LoadLibraryEx."
-var useLoadLibraryEx bool
-
-func osinit() {
-	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
-
-	setBadSignalMsg()
-
-	loadOptionalSyscalls()
-
-	useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
-
-	disableWER()
-
-	externalthreadhandlerp = funcPC(externalthreadhandler)
-
-	initExceptionHandler()
-
-	stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 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
-	}
-	isASCII := true
-	b := (*[1 << 30]byte)(buf)[:n]
-	for _, x := range b {
-		if x >= 0x80 {
-			isASCII = false
-			break
-		}
-	}
-
-	if !isASCII {
-		var m uint32
-		isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
-		// If this is a console output, various non-unicode code pages can be in use.
-		// Use the dedicated WriteConsole call to ensure unicode is printed correctly.
-		if isConsole {
-			return int32(writeConsole(handle, buf, n))
-		}
-	}
-	var written uint32
-	stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
-	return int32(written)
-}
-
-var (
-	utf16ConsoleBack     [1000]uint16
-	utf16ConsoleBackLock mutex
-)
-
-// writeConsole writes bufLen bytes from buf to the console File.
-// It returns the number of bytes written.
-func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
-	const surr2 = (surrogateMin + surrogateMax + 1) / 2
-
-	// Do not use defer for unlock. May cause issues when printing a panic.
-	lock(&utf16ConsoleBackLock)
-
-	b := (*[1 << 30]byte)(buf)[:bufLen]
-	s := *(*string)(unsafe.Pointer(&b))
-
-	utf16tmp := utf16ConsoleBack[:]
-
-	total := len(s)
-	w := 0
-	for len(s) > 0 {
-		if w >= len(utf16tmp)-2 {
-			writeConsoleUTF16(handle, utf16tmp[:w])
-			w = 0
-		}
-		r, n := charntorune(s)
-		s = s[n:]
-		if r < 0x10000 {
-			utf16tmp[w] = uint16(r)
-			w++
-		} else {
-			r -= 0x10000
-			utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff
-			utf16tmp[w+1] = surr2 + uint16(r)&0x3ff
-			w += 2
-		}
-	}
-	writeConsoleUTF16(handle, utf16tmp[:w])
-	unlock(&utf16ConsoleBackLock)
-	return total
-}
-
-// writeConsoleUTF16 is the dedicated windows calls that correctly prints
-// to the console regardless of the current code page. Input is utf-16 code points.
-// The handle must be a console handle.
-func writeConsoleUTF16(handle uintptr, b []uint16) {
-	l := uint32(len(b))
-	if l == 0 {
-		return
-	}
-	var written uint32
-	stdcall5(_WriteConsoleW,
-		handle,
-		uintptr(unsafe.Pointer(&b[0])),
-		uintptr(l),
-		uintptr(unsafe.Pointer(&written)),
-		0,
-	)
-	return
-}
-
-//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(mp *m) {
-	if mp.waitsema != 0 {
-		return
-	}
-	mp.waitsema = 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) {
-}
-
-//go:nosplit
-func msigsave(mp *m) {
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
-}
-
-//go:nosplit
-func sigblock() {
-}
-
-// 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)
-	atomic.Storeuintptr(&getg().m.thread, thandle)
-}
-
-// Called from dropm to undo the effect of an minit.
-//go:nosplit
-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]
-	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)(atomic.Loadp(unsafe.Pointer(&allm)))
-		for mp := first; mp != nil; mp = mp.alllink {
-			thread := atomic.Loaduintptr(&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)
-		atomic.Storeuintptr(&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)
-	atomic.Store((*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
deleted file mode 100644
index 542bd74..0000000
--- a/src/runtime/os2_darwin.go
+++ /dev/null
@@ -1,14 +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
-
-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
deleted file mode 100644
index 6ea2da0..0000000
--- a/src/runtime/os2_dragonfly.go
+++ /dev/null
@@ -1,15 +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 (
-	_NSIG        = 33
-	_SI_USER     = 0
-	_SS_DISABLE  = 4
-	_RLIMIT_AS   = 10
-	_SIG_BLOCK   = 1
-	_SIG_UNBLOCK = 2
-	_SIG_SETMASK = 3
-)
diff --git a/src/runtime/os2_linux_generic.go b/src/runtime/os2_linux_generic.go
deleted file mode 100644
index 01e6c8a..0000000
--- a/src/runtime/os2_linux_generic.go
+++ /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 !mips64
-// +build !mips64le
-// +build linux
-
-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_linux_mips64x.go b/src/runtime/os2_linux_mips64x.go
deleted file mode 100644
index 9a6a92a..0000000
--- a/src/runtime/os2_linux_mips64x.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2015 The Go 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 mips64 mips64le
-
-package runtime
-
-const (
-	_SS_DISABLE  = 2
-	_NSIG        = 65
-	_SI_USER     = 0
-	_SIG_BLOCK   = 1
-	_SIG_UNBLOCK = 2
-	_SIG_SETMASK = 3
-	_RLIMIT_AS   = 6
-)
-
-type sigset [2]uint64
-
-type rlimit struct {
-	rlim_cur uintptr
-	rlim_max uintptr
-}
diff --git a/src/runtime/os2_nacl.go b/src/runtime/os2_nacl.go
index d8c88db..b84cb18 100644
--- a/src/runtime/os2_nacl.go
+++ b/src/runtime/os2_nacl.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/os2_netbsd.go b/src/runtime/os2_netbsd.go
deleted file mode 100644
index 46576b9..0000000
--- a/src/runtime/os2_netbsd.go
+++ /dev/null
@@ -1,18 +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.
-
-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
index 1e785ad..8656a91 100644
--- a/src/runtime/os2_openbsd.go
+++ b/src/runtime/os2_openbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/os2_windows.go b/src/runtime/os2_windows.go
deleted file mode 100644
index a867dfe..0000000
--- a/src/runtime/os2_windows.go
+++ /dev/null
@@ -1,19 +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
-
-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
index edd66c5..aff1d05 100644
--- a/src/runtime/os3_plan9.go
+++ b/src/runtime/os3_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -55,8 +55,8 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int {
 		gp.sig = uint32(sig)
 		gp.sigpc = c.pc()
 
-		pc := uintptr(c.pc())
-		sp := uintptr(c.sp())
+		pc := c.pc()
+		sp := c.sp()
 
 		// If we don't recognize the PC as code
 		// but we do recognize the top pointer on the stack as code,
@@ -66,22 +66,37 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int {
 			pc = 0
 		}
 
-		// Only push sigpanic if PC != 0.
-		//
+		// IF LR exists, sigpanictramp must save it to the stack
+		// before entry to sigpanic so that panics in leaf
+		// functions are correctly handled. This will smash
+		// the stack frame but we're not going back there
+		// anyway.
+		if usesLR {
+			c.savelr(c.lr())
+		}
+
 		// 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
+		// Not faking that as the return address 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 sys.RegSize > sys.PtrSize {
+			if usesLR {
+				c.setlr(pc)
+			} else {
+				if sys.RegSize > sys.PtrSize {
+					sp -= sys.PtrSize
+					*(*uintptr)(unsafe.Pointer(sp)) = 0
+				}
 				sp -= sys.PtrSize
-				*(*uintptr)(unsafe.Pointer(sp)) = 0
+				*(*uintptr)(unsafe.Pointer(sp)) = pc
+				c.setsp(sp)
 			}
-			sp -= sys.PtrSize
-			*(*uintptr)(unsafe.Pointer(sp)) = pc
-			c.setsp(sp)
 		}
-		c.setpc(funcPC(sigpanic))
+		if usesLR {
+			c.setpc(funcPC(sigpanictramp))
+		} else {
+			c.setpc(funcPC(sigpanic))
+		}
 		return _NCONT
 	}
 	if flags&_SigNotify != 0 {
@@ -105,7 +120,7 @@ Throw:
 	level, _, docrash = gotraceback()
 	if level > 0 {
 		goroutineheader(gp)
-		tracebacktrap(c.pc(), c.sp(), 0, gp)
+		tracebacktrap(c.pc(), c.sp(), c.lr(), gp)
 		tracebackothers(gp)
 		print("\n")
 		dumpregs(_ureg)
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index 7ebb35c..9368e0d 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -159,12 +159,15 @@ func newosproc(mp *m, _ unsafe.Pointer) {
 	}
 
 	// Disable signals during create, so that the new thread starts
-	// with signals disabled.  It will enable them in minit.
+	// 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")
+		if ret == -_EAGAIN {
+			println("runtime: may need to increase max user processes (ulimit -u)")
+		}
 		throw("newosproc")
 	}
 }
@@ -208,7 +211,7 @@ func sigblock() {
 }
 
 // Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
+// Called on the new thread, cannot allocate memory.
 func minit() {
 	_g_ := getg()
 	asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno))
@@ -266,7 +269,7 @@ func memlimit() uintptr {
 			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.
+		// not going to be able to do much. Treat as no limit.
 		rl.rlim_cur -= used;
 		if(rl.rlim_cur < (16<<20))
 			return 0;
@@ -357,8 +360,8 @@ func semacreate(mp *m) {
 	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
+	// 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
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index b825776..a0e3d8e 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -7,6 +7,7 @@ package runtime
 import "unsafe"
 
 type mOS struct {
+	machport uint32 // return address for mach ipc
 	waitsema uint32 // semaphore for parking on locks
 }
 
@@ -23,6 +24,476 @@ func mach_thread_self() uint32
 //go:noescape
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
 
+func unimplemented(name string) {
+	println(name, "not implemented")
+	*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	mach_semrelease(mp.waitsema)
+}
+
+//go:nosplit
+func semacreate(mp *m) {
+	if mp.waitsema != 0 {
+		return
+	}
+	systemstack(func() {
+		mp.waitsema = mach_semcreate()
+	})
+}
+
+// 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) {
+	if false {
+		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, " ostk=", &mp, "\n")
+	}
+
+	var oset sigset
+	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 sigset
+	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 do synchronous initialization of Go code built with
+// -buildmode=c-archive or -buildmode=c-shared.
+// None of the Go runtime is initialized.
+//go:nosplit
+//go:nowritebarrierrec
+func libpreinit() {
+	initsig(true)
+}
+
+// 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
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+	sigprocmask(_SIG_SETMASK, &sigmask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+	// Initialize signal handling.
+	_g_ := getg()
+
+	// The alternate signal stack is buggy on arm and arm64.
+	// The signal handler handles it directly.
+	// The sigaltstack assembly function does nothing.
+	if GOARCH != "arm" && GOARCH != "arm64" {
+		var st stackt
+		sigaltstack(nil, &st)
+		if st.ss_flags&_SS_DISABLE != 0 {
+			signalstack(&_g_.m.gsignal.stack)
+			_g_.m.newSigstack = true
+		} else {
+			// Use existing signal stack.
+			stsp := uintptr(unsafe.Pointer(st.ss_sp))
+			_g_.m.gsignal.stack.lo = stsp
+			_g_.m.gsignal.stack.hi = stsp + st.ss_size
+			_g_.m.gsignal.stackguard0 = stsp + _StackGuard
+			_g_.m.gsignal.stackguard1 = stsp + _StackGuard
+			_g_.m.gsignal.stackAlloc = st.ss_size
+			_g_.m.newSigstack = false
+		}
+	}
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := _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.
+//go:nosplit
+func unminit() {
+	if getg().m.newSigstack {
+		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(_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(_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
+}
+
+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
+)
+
 //go:noescape
 func sigprocmask(how uint32, new, old *sigset)
 
@@ -39,3 +510,73 @@ func setitimer(mode int32, new, old *itimerval)
 
 func raise(sig int32)
 func raiseproc(int32)
+
+//extern SigTabTT runtime·sigtab[];
+
+type sigset uint32
+
+var sigset_all = ^sigset(0)
+
+//go:nosplit
+//go:nowritebarrierrec
+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 = ^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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+	var osa usigactiont
+	sigaction(uint32(i), nil, &osa)
+	handler := *(*uintptr)(unsafe.Pointer(&osa.__sigaction_u))
+	if handler == 0 || handler == _SIG_DFL || handler == _SIG_IGN || osa.sa_flags&_SA_ONSTACK != 0 {
+		return
+	}
+	var sa sigactiont
+	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
+	sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp))
+	sa.sa_mask = osa.sa_mask
+	sa.sa_flags = osa.sa_flags | _SA_ONSTACK
+	sigaction(uint32(i), &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func getsig(i int32) uintptr {
+	var sa usigactiont
+	sigaction(uint32(i), nil, &sa)
+	return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
+}
+
+//go:nosplit
+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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func updatesigmask(m sigmask) {
+	s := sigset(m[0])
+	sigprocmask(_SIG_SETMASK, &s, nil)
+}
+
+func unblocksig(sig int32) {
+	mask := sigset(1) << (uint32(sig) - 1)
+	sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go
index d6856f1..85d4aad 100644
--- a/src/runtime/os_dragonfly.go
+++ b/src/runtime/os_dragonfly.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,6 +6,16 @@ package runtime
 
 import "unsafe"
 
+const (
+	_NSIG        = 33
+	_SI_USER     = 0
+	_SS_DISABLE  = 4
+	_RLIMIT_AS   = 10
+	_SIG_BLOCK   = 1
+	_SIG_UNBLOCK = 2
+	_SIG_SETMASK = 3
+)
+
 type mOS struct{}
 
 //go:noescape
@@ -41,3 +51,267 @@ func sys_umtx_wakeup(addr *uint32, val int32) int32
 func osyield()
 
 const stackSystem = 0
+
+// 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, " 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,
+	}
+
+	// TODO: Check for error.
+	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
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+	sigprocmask(_SIG_SETMASK, &sigmask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot 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.
+
+	// On DragonFly a thread created by pthread_create inherits
+	// the signal stack of the creating thread. We always create
+	// a new signal stack here, to avoid having two Go threads
+	// using the same signal stack. This breaks the case of a
+	// thread created in C that calls sigaltstack and then calls a
+	// Go function, because we will lose track of the C code's
+	// sigaltstack, but it's the best we can do.
+	signalstack(&_g_.m.gsignal.stack)
+	_g_.m.newSigstack = true
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := _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.
+//go:nosplit
+func unminit() {
+	if getg().m.newSigstack {
+		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
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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
+}
+
+//go:nosplit
+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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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/os_freebsd.go b/src/runtime/os_freebsd.go
index 61f8fae..c187ee8 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -1,10 +1,13 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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"
+import (
+	"runtime/internal/sys"
+	"unsafe"
+)
 
 type mOS struct{}
 
@@ -35,3 +38,275 @@ func raiseproc(sig int32)
 func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32
 
 func osyield()
+
+// 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, " 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),
+	}
+
+	var oset sigset
+	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+	// TODO: Check for error.
+	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
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+	sigprocmask(_SIG_SETMASK, &sigmask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot 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 sys.PtrSize == 4 {
+		_g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
+	}
+
+	// Initialize signal handling.
+	var st stackt
+	sigaltstack(nil, &st)
+	if st.ss_flags&_SS_DISABLE != 0 {
+		signalstack(&_g_.m.gsignal.stack)
+		_g_.m.newSigstack = true
+	} else {
+		// Use existing signal stack.
+		stsp := uintptr(unsafe.Pointer(st.ss_sp))
+		_g_.m.gsignal.stack.lo = stsp
+		_g_.m.gsignal.stack.hi = stsp + st.ss_size
+		_g_.m.gsignal.stackguard0 = stsp + _StackGuard
+		_g_.m.gsignal.stackguard1 = stsp + _StackGuard
+		_g_.m.gsignal.stackAlloc = st.ss_size
+		_g_.m.newSigstack = false
+	}
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := _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.
+//go:nosplit
+func unminit() {
+	if getg().m.newSigstack {
+		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
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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
+}
+
+//go:nosplit
+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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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/os_linux.go b/src/runtime/os_linux.go
index 51a7fa0..542f214 100644
--- a/src/runtime/os_linux.go
+++ b/src/runtime/os_linux.go
@@ -1,19 +1,368 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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"
+import (
+	"runtime/internal/sys"
+	"unsafe"
+)
 
 type mOS struct{}
 
 //go:noescape
 func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32
 
+// 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 sys.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).
+	// 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
+	var buf [maxCPUs / (sys.PtrSize * 8)]uintptr
+	r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
+	n := int32(0)
+	for _, v := range buf[:r/sys.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 */
+)
+
 //go:noescape
 func clone(flags int32, stk, mm, gg, fn unsafe.Pointer) int32
 
+// 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.
+	 */
+	if false {
+		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, " 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")
+		if ret == -_EAGAIN {
+			println("runtime: may need to increase max user processes (ulimit -u)")
+		}
+		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")
+
+const (
+	_AT_NULL   = 0  // End of vector
+	_AT_PAGESZ = 6  // System physical page size
+	_AT_RANDOM = 25 // introduced in 2.6.29
+)
+
+func sysargs(argc int32, argv **byte) {
+	n := argc + 1
+
+	// skip over argv, envp to get to auxv
+	for argv_index(argv, n) != nil {
+		n++
+	}
+
+	// skip NULL separator
+	n++
+
+	// now argv+n is auxv
+	auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize))
+	for i := 0; auxv[i] != _AT_NULL; i += 2 {
+		tag, val := auxv[i], auxv[i+1]
+		switch tag {
+		case _AT_RANDOM:
+			// The kernel provides a pointer to 16-bytes
+			// worth of random data.
+			startupRandomData = (*[16]byte)(unsafe.Pointer(val))[:]
+
+		case _AT_PAGESZ:
+			// Check that the true physical page size is
+			// compatible with the runtime's assumed
+			// physical page size.
+			if sys.PhysPageSize < val {
+				print("runtime: kernel page size (", val, ") is larger than runtime page size (", sys.PhysPageSize, ")\n")
+				exit(1)
+			}
+			if sys.PhysPageSize%val != 0 {
+				print("runtime: runtime page size (", sys.PhysPageSize, ") is not a multiple of kernel page size (", val, ")\n")
+				exit(1)
+			}
+		}
+
+		archauxv(tag, val)
+	}
+}
+
+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 do synchronous initialization of Go code built with
+// -buildmode=c-archive or -buildmode=c-shared.
+// None of the Go runtime is initialized.
+//go:nosplit
+//go:nowritebarrierrec
+func libpreinit() {
+	initsig(true)
+}
+
+// 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
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+	smask := &mp.sigmask
+	rtsigprocmask(_SIG_SETMASK, nil, smask, int32(unsafe.Sizeof(*smask)))
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+	rtsigprocmask(_SIG_SETMASK, &sigmask, nil, int32(unsafe.Sizeof(sigmask)))
+}
+
+//go:nosplit
+func sigblock() {
+	rtsigprocmask(_SIG_SETMASK, &sigset_all, nil, int32(unsafe.Sizeof(sigset_all)))
+}
+
+func gettid() uint32
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+	// Initialize signal handling.
+	_g_ := getg()
+
+	var st sigaltstackt
+	sigaltstack(nil, &st)
+	if st.ss_flags&_SS_DISABLE != 0 {
+		signalstack(&_g_.m.gsignal.stack)
+		_g_.m.newSigstack = true
+	} else {
+		// Use existing signal stack.
+		stsp := uintptr(unsafe.Pointer(st.ss_sp))
+		_g_.m.gsignal.stack.lo = stsp
+		_g_.m.gsignal.stack.hi = stsp + st.ss_size
+		_g_.m.gsignal.stackguard0 = stsp + _StackGuard
+		_g_.m.gsignal.stackguard1 = stsp + _StackGuard
+		_g_.m.gsignal.stackAlloc = st.ss_size
+		_g_.m.newSigstack = false
+	}
+
+	// for debuggers, in case cgo created the thread
+	_g_.m.procid = uint64(gettid())
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := _g_.m.sigmask
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			sigdelset(&nmask, i)
+		}
+	}
+	rtsigprocmask(_SIG_SETMASK, &nmask, nil, int32(unsafe.Sizeof(nmask)))
+}
+
+// Called from dropm to undo the effect of an minit.
+//go:nosplit
+func unminit() {
+	if getg().m.newSigstack {
+		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 cgoSigtramp()
+
 //go:noescape
 func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
 
@@ -34,3 +383,88 @@ func raiseproc(sig int32)
 //go:noescape
 func sched_getaffinity(pid, len uintptr, buf *uintptr) int32
 func osyield()
+
+//go:nosplit
+//go:nowritebarrierrec
+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
+	}
+	sigfillset(&sa.sa_mask)
+	// 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) {
+		if iscgo {
+			fn = funcPC(cgoSigtramp)
+		} else {
+			fn = funcPC(sigtramp)
+		}
+	}
+	sa.sa_handler = fn
+	rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask))
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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")
+	}
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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) || sa.sa_handler == funcPC(cgoSigtramp) {
+		return funcPC(sighandler)
+	}
+	return sa.sa_handler
+}
+
+//go:nosplit
+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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func updatesigmask(m sigmask) {
+	var mask sigset
+	sigcopyset(&mask, m)
+	rtsigprocmask(_SIG_SETMASK, &mask, nil, int32(unsafe.Sizeof(mask)))
+}
+
+func unblocksig(sig int32) {
+	var mask sigset
+	sigaddset(&mask, int(sig))
+	rtsigprocmask(_SIG_UNBLOCK, &mask, nil, int32(unsafe.Sizeof(mask)))
+}
diff --git a/src/runtime/os_linux_386.go b/src/runtime/os_linux_386.go
deleted file mode 100644
index 0f39cad..0000000
--- a/src/runtime/os_linux_386.go
+++ /dev/null
@@ -1,33 +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 (
-	"runtime/internal/sys"
-	"unsafe"
-)
-
-const (
-	_AT_NULL    = 0
-	_AT_RANDOM  = 25
-	_AT_SYSINFO = 32
-)
-
-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)*sys.PtrSize))
-
-	for i := 0; auxv[i] != _AT_NULL; i += 2 {
-		switch auxv[i] {
-		case _AT_RANDOM:
-			startupRandomData = (*[16]byte)(unsafe.Pointer(uintptr(auxv[i+1])))[:]
-		}
-	}
-}
diff --git a/src/runtime/os_linux_arm.go b/src/runtime/os_linux_arm.go
index 8fdfb58..8e2765a 100644
--- a/src/runtime/os_linux_arm.go
+++ b/src/runtime/os_linux_arm.go
@@ -4,16 +4,11 @@
 
 package runtime
 
-import (
-	"runtime/internal/sys"
-	"unsafe"
-)
+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
@@ -36,33 +31,23 @@ func checkgoarm() {
 	}
 }
 
-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)*sys.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]
+func archauxv(tag, val uintptr) {
+	switch tag {
+	case _AT_RANDOM:
+		// sysargs filled in startupRandomData, but that
+		// pointer 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(val + 1))
+		if '5' <= t && t <= '7' {
+			armArch = t - '0'
 		}
+
+	case _AT_HWCAP: // CPU capability bit flags
+		hwcap = uint32(val)
 	}
 }
 
diff --git a/src/runtime/os_linux_arm64.go b/src/runtime/os_linux_arm64.go
index 3f994f1..43262ae 100644
--- a/src/runtime/os_linux_arm64.go
+++ b/src/runtime/os_linux_arm64.go
@@ -4,13 +4,19 @@
 
 package runtime
 
-const (
-	_AT_NULL   = 0
-	_AT_RANDOM = 25 // introduced in 2.6.29
-)
-
 var randomNumber uint32
 
+func archauxv(tag, val uintptr) {
+	switch tag {
+	case _AT_RANDOM:
+		// sysargs filled in startupRandomData, but that
+		// pointer 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
+	}
+}
+
 //go:nosplit
 func cputicks() int64 {
 	// Currently cputicks() is used in blocking profiler and to seed fastrand1().
diff --git a/src/runtime/os_linux_generic.go b/src/runtime/os_linux_generic.go
new file mode 100644
index 0000000..a16d140
--- /dev/null
+++ b/src/runtime/os_linux_generic.go
@@ -0,0 +1,48 @@
+// 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 !mips64
+// +build !mips64le
+// +build !s390x
+// +build linux
+
+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
+}
+
+var sigset_all = sigset{^uint32(0), ^uint32(0)}
+
+func sigaddset(mask *sigset, i int) {
+	(*mask)[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigdelset(mask *sigset, i int) {
+	(*mask)[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigfillset(mask *uint64) {
+	*mask = ^uint64(0)
+}
+
+func sigcopyset(mask *sigset, m sigmask) {
+	copy((*mask)[:], m[:])
+}
diff --git a/src/runtime/os_linux_mips64x.go b/src/runtime/os_linux_mips64x.go
index 4d2e9e8..8039b2f 100644
--- a/src/runtime/os_linux_mips64x.go
+++ b/src/runtime/os_linux_mips64x.go
@@ -2,13 +2,24 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build mips64 mips64le
 // +build linux
+// +build mips64 mips64le
 
 package runtime
 
 var randomNumber uint32
 
+func archauxv(tag, val uintptr) {
+	switch tag {
+	case _AT_RANDOM:
+		// sysargs filled in startupRandomData, but that
+		// pointer 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
+	}
+}
+
 //go:nosplit
 func cputicks() int64 {
 	// Currently cputicks() is used in blocking profiler and to seed fastrand1().
@@ -16,3 +27,38 @@ func cputicks() int64 {
 	// randomNumber provides better seeding of fastrand1.
 	return nanotime() + int64(randomNumber)
 }
+
+const (
+	_SS_DISABLE  = 2
+	_NSIG        = 65
+	_SI_USER     = 0
+	_SIG_BLOCK   = 1
+	_SIG_UNBLOCK = 2
+	_SIG_SETMASK = 3
+	_RLIMIT_AS   = 6
+)
+
+type sigset [2]uint64
+
+type rlimit struct {
+	rlim_cur uintptr
+	rlim_max uintptr
+}
+
+var sigset_all = sigset{^uint64(0), ^uint64(0)}
+
+func sigaddset(mask *sigset, i int) {
+	(*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63)
+}
+
+func sigdelset(mask *sigset, i int) {
+	(*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63)
+}
+
+func sigfillset(mask *[2]uint64) {
+	(*mask)[0], (*mask)[1] = ^uint64(0), ^uint64(0)
+}
+
+func sigcopyset(mask *sigset, m sigmask) {
+	(*mask)[0] = uint64(m[0]) | uint64(m[1])<<32
+}
diff --git a/src/runtime/os_linux_noauxv.go b/src/runtime/os_linux_noauxv.go
new file mode 100644
index 0000000..22522dd
--- /dev/null
+++ b/src/runtime/os_linux_noauxv.go
@@ -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 !amd64,!arm,!arm64,!mips64,!mips64le
+
+package runtime
+
+func archauxv(tag, val uintptr) {
+}
diff --git a/src/runtime/os_linux_s390x.go b/src/runtime/os_linux_s390x.go
new file mode 100644
index 0000000..e659dff
--- /dev/null
+++ b/src/runtime/os_linux_s390x.go
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors. 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
+)
+
+type sigset uint64
+
+type rlimit struct {
+	rlim_cur uintptr
+	rlim_max uintptr
+}
+
+var sigset_all = sigset(^uint64(0))
+
+func sigaddset(mask *sigset, i int) {
+	if i > 64 {
+		throw("unexpected signal greater than 64")
+	}
+	*mask |= 1 << (uint(i) - 1)
+}
+
+func sigdelset(mask *sigset, i int) {
+	if i > 64 {
+		throw("unexpected signal greater than 64")
+	}
+	*mask &^= 1 << (uint(i) - 1)
+}
+
+func sigfillset(mask *uint64) {
+	*mask = ^uint64(0)
+}
+
+func sigcopyset(mask *sigset, m sigmask) {
+	*mask = sigset(uint64(m[0]) | uint64(m[1])<<32)
+}
diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go
index c7cc0a9..6cbd16d 100644
--- a/src/runtime/os_nacl.go
+++ b/src/runtime/os_nacl.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -63,7 +63,237 @@ func sigpanic() {
 func raiseproc(sig int32) {
 }
 
-// Stubs so tests can link correctly.  These should never be called.
+// 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
+
+type sigset struct{}
+
+// 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()
+
+//go:nosplit
+func msigsave(mp *m) {
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+}
+
+//go:nosplit
+func sigblock() {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot 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 signame(sig uint32) string {
+	if sig >= uint32(len(sigtable)) {
+		return ""
+	}
+	return sigtable[sig].name
+}
+
+func crash() {
+	*(*int32)(nil) = 0
+}
+
+//go:noescape
+func getRandomData([]byte)
+
+func goenvs() {
+	goenvs_unix()
+}
+
+func initsig(preinit bool) {
+}
+
+//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(mp *m) {
+	if mp.waitsema != 0 {
+		return
+	}
+	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 ", -c, "\n")
+			throw("semacreate")
+		}
+		mp.waitsema = c
+		mp.waitsemalock = mu
+	})
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	var ret int32
+
+	systemstack(func() {
+		_g_ := getg()
+		if nacl_mutex_lock(_g_.m.waitsemalock) < 0 {
+			throw("semasleep")
+		}
+
+		for _g_.m.waitsemacount == 0 {
+			if ns < 0 {
+				if nacl_cond_wait(_g_.m.waitsema, _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(_g_.m.waitsema, _g_.m.waitsemalock, &ts)
+				if r == -_ETIMEDOUT {
+					nacl_mutex_unlock(_g_.m.waitsemalock)
+					ret = -1
+					return
+				}
+				if r < 0 {
+					throw("semasleep")
+				}
+			}
+		}
+
+		_g_.m.waitsemacount = 0
+		nacl_mutex_unlock(_g_.m.waitsemalock)
+		ret = 0
+	})
+	return ret
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	systemstack(func() {
+		if nacl_mutex_lock(mp.waitsemalock) < 0 {
+			throw("semawakeup")
+		}
+		if mp.waitsemacount != 0 {
+			throw("semawakeup")
+		}
+		mp.waitsemacount = 1
+		nacl_cond_signal(mp.waitsema)
+		nacl_mutex_unlock(mp.waitsemalock)
+	})
+}
+
+func memlimit() uintptr {
+	return 0
+}
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+//go:norace
+//go:nowritebarrierrec
+func badsignal(sig uintptr) {
+	cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+}
+
+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))
+	}
+}
+
+// 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/os_netbsd.go b/src/runtime/os_netbsd.go
index 9883741..4c44b2b 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -1,10 +1,28 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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"
+import (
+	"runtime/internal/atomic"
+	"unsafe"
+)
+
+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
+
+	_EAGAIN = 35
+)
 
 type mOS struct {
 	waitsemacount uint32
@@ -45,3 +63,271 @@ func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
 func lwp_self() int32
 
 func osyield()
+
+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(mp *m) {
+}
+
+//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 := atomic.Load(&_g_.m.waitsemacount)
+		if v > 0 {
+			if atomic.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) {
+	atomic.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, " ostk=", &mp, "\n")
+	}
+
+	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(netbsdMstart))
+
+	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")
+		if ret == -_EAGAIN {
+			println("runtime: may need to increase max user processes (ulimit -p)")
+		}
+		throw("runtime.newosproc")
+	}
+}
+
+// netbsdMStart is the function call that starts executing a newly
+// created thread. On NetBSD, a new thread inherits the signal stack
+// of the creating thread. That confuses minit, so we remove that
+// signal stack here before calling the regular mstart. It's a bit
+// baroque to remove a signal stack here only to add one in minit, but
+// it's a simple change that keeps NetBSD working like other OS's.
+// At this point all signals are blocked, so there is no race.
+//go:nosplit
+func netbsdMstart() {
+	signalstack(nil)
+	mstart()
+}
+
+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
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+	sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+	sigprocmask(_SIG_SETMASK, &sigmask, nil)
+}
+
+//go:nosplit
+func sigblock() {
+	sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+	_g_ := getg()
+	_g_.m.procid = uint64(lwp_self())
+
+	// Initialize signal handling.
+
+	// On NetBSD a thread created by pthread_create inherits the
+	// signal stack of the creating thread. We always create a
+	// new signal stack here, to avoid having two Go threads using
+	// the same signal stack. This breaks the case of a thread
+	// created in C that calls sigaltstack and then calls a Go
+	// function, because we will lose track of the C code's
+	// sigaltstack, but it's the best we can do.
+	signalstack(&_g_.m.gsignal.stack)
+	_g_.m.newSigstack = true
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := _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.
+//go:nosplit
+func unminit() {
+	if getg().m.newSigstack {
+		signalstack(nil)
+	}
+}
+
+func memlimit() uintptr {
+	return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+	sa_sigaction uintptr
+	sa_mask      sigset
+	sa_flags     int32
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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
+}
+
+//go:nosplit
+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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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/os_netbsd_386.go
similarity index 100%
rename from src/runtime/os1_netbsd_386.go
rename to src/runtime/os_netbsd_386.go
diff --git a/src/runtime/os1_netbsd_amd64.go b/src/runtime/os_netbsd_amd64.go
similarity index 100%
rename from src/runtime/os1_netbsd_amd64.go
rename to src/runtime/os_netbsd_amd64.go
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index b6285e4..9a5c53e 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -1,9 +1,14 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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 (
+	"runtime/internal/atomic"
+	"unsafe"
+)
+
 type mOS struct {
 	waitsemacount uint32
 }
@@ -36,3 +41,274 @@ func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort
 func thrwakeup(ident uintptr, n int32) int32
 
 func osyield()
+
+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
+)
+
+type sigset uint32
+
+const (
+	sigset_none = sigset(0)
+	sigset_all  = ^sigset(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(mp *m) {
+}
+
+//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 := atomic.Load(&_g_.m.waitsemacount)
+		if v > 0 {
+			if atomic.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) {
+	atomic.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, " ostk=", &mp, "\n")
+	}
+
+	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")
+		if ret == -_EAGAIN {
+			println("runtime: may need to increase max user processes (ulimit -p)")
+		}
+		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
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+	mp.sigmask = sigprocmask(_SIG_BLOCK, 0)
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+	sigprocmask(_SIG_SETMASK, sigmask)
+}
+
+//go:nosplit
+func sigblock() {
+	sigprocmask(_SIG_SETMASK, sigset_all)
+}
+
+// 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
+	var st stackt
+	sigaltstack(nil, &st)
+	if st.ss_flags&_SS_DISABLE != 0 {
+		signalstack(&_g_.m.gsignal.stack)
+		_g_.m.newSigstack = true
+	} else {
+		// Use existing signal stack.
+		stsp := uintptr(unsafe.Pointer(st.ss_sp))
+		_g_.m.gsignal.stack.lo = stsp
+		_g_.m.gsignal.stack.hi = stsp + st.ss_size
+		_g_.m.gsignal.stackguard0 = stsp + _StackGuard
+		_g_.m.gsignal.stackguard1 = stsp + _StackGuard
+		_g_.m.gsignal.stackAlloc = st.ss_size
+		_g_.m.newSigstack = false
+	}
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := _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.
+//go:nosplit
+func unminit() {
+	if getg().m.newSigstack {
+		signalstack(nil)
+	}
+}
+
+func memlimit() uintptr {
+	return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+	sa_sigaction uintptr
+	sa_mask      uint32
+	sa_flags     int32
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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 = uint32(sigset_all)
+	if fn == funcPC(sighandler) {
+		fn = funcPC(sigtramp)
+	}
+	sa.sa_sigaction = fn
+	sigaction(i, &sa, nil)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+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
+}
+
+//go:nosplit
+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)
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func updatesigmask(m sigmask) {
+	sigprocmask(_SIG_SETMASK, sigset(m[0]))
+}
+
+func unblocksig(sig int32) {
+	mask := sigset(1) << (uint32(sig) - 1)
+	sigprocmask(_SIG_UNBLOCK, mask)
+}
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index 6e6a55e..2f3a0d1 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -1,10 +1,13 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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"
+import (
+	"runtime/internal/atomic"
+	"unsafe"
+)
 
 type mOS struct {
 	waitsemacount uint32
@@ -78,7 +81,15 @@ func sigpanic() {
 	note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig)))
 	switch g.sig {
 	case _SIGRFAULT, _SIGWFAULT:
-		addr := note[index(note, "addr=")+5:]
+		i := index(note, "addr=")
+		if i >= 0 {
+			i += 5
+		} else if i = index(note, "va="); i >= 0 {
+			i += 3
+		} else {
+			panicmem()
+		}
+		addr := note[i:]
 		g.sigcode1 = uintptr(atolwhex(addr))
 		if g.sigcode1 < 0x1000 || g.paniconfault {
 			panicmem()
@@ -140,3 +151,288 @@ func atolwhex(p string) int64 {
 	}
 	return n
 }
+
+type sigset struct{}
+
+// 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, true))
+	// Initialize stack for handling strings from the
+	// errstr system call, as used in package syscall.
+	mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true))
+}
+
+func msigsave(mp *m) {
+}
+
+func msigrestore(sigmask sigset) {
+}
+
+func sigblock() {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+	if atomic.Load(&exiting) != 0 {
+		exits(&emptystatus[0])
+	}
+	// 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(preinit bool) {
+}
+
+//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 ")
+var emptystatus = []byte("\x00")
+var exiting uint32
+
+func goexitsall(status *byte) {
+	var buf [_ERRMAX]byte
+	if !atomic.Cas(&exiting, 0, 1) {
+		return
+	}
+	getg().m.locks++
+	n := copy(buf[:], goexits)
+	n = copy(buf[n:], gostringnocopy(status))
+	pid := getpid()
+	for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
+		if mp.procid != 0 && mp.procid != pid {
+			postnote(mp.procid, buf[:])
+		}
+	}
+	getg().m.locks--
+}
+
+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 = emptystatus
+	} 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(mp *m) {
+}
+
+//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
+}
+
+func signame(sig uint32) string {
+	if sig >= uint32(len(sigtable)) {
+		return ""
+	}
+	return sigtable[sig].name
+}
diff --git a/src/runtime/os_plan9_arm.go b/src/runtime/os_plan9_arm.go
new file mode 100644
index 0000000..30cde8f
--- /dev/null
+++ b/src/runtime/os_plan9_arm.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 runtime
+
+func checkgoarm() {
+	return // TODO(minux)
+}
+
+//go:nosplit
+func cputicks() int64 {
+	// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+	// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+	// TODO: need more entropy to better seed fastrand1.
+	return nanotime()
+}
diff --git a/src/runtime/os_solaris.go b/src/runtime/os_solaris.go
index fbf2886..0c39715 100644
--- a/src/runtime/os_solaris.go
+++ b/src/runtime/os_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 5dab1de..9147091 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -1,23 +1,133 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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"
+import (
+	"runtime/internal/atomic"
+	"unsafe"
+)
+
+// TODO(brainman): should not need those
+const (
+	_NSIG = 65
+)
+
+//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._GetConsoleMode GetConsoleMode%2 "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._GetProcessAffinityMask GetProcessAffinityMask%3 "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._SwitchToThread SwitchToThread%0 "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._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
+//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
+//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll"
+
+type stdFunction unsafe.Pointer
+
+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,
+	_GetConsoleMode,
+	_GetEnvironmentStringsW,
+	_GetProcAddress,
+	_GetProcessAffinityMask,
+	_GetQueuedCompletionStatus,
+	_GetStdHandle,
+	_GetSystemInfo,
+	_GetThreadContext,
+	_LoadLibraryW,
+	_LoadLibraryA,
+	_NtWaitForSingleObject,
+	_ResumeThread,
+	_SetConsoleCtrlHandler,
+	_SetErrorMode,
+	_SetEvent,
+	_SetProcessPriorityBoost,
+	_SetThreadPriority,
+	_SetUnhandledExceptionFilter,
+	_SetWaitableTimer,
+	_SuspendThread,
+	_SwitchToThread,
+	_VirtualAlloc,
+	_VirtualFree,
+	_WSAGetOverlappedResult,
+	_WaitForSingleObject,
+	_WriteConsoleW,
+	_WriteFile,
+	_timeBeginPeriod,
+	_ stdFunction
+
+	// Following syscalls are only available on some Windows PCs.
+	// We will load syscalls, if available, before using them.
+	_AddDllDirectory,
+	_AddVectoredContinueHandler,
+	_GetQueuedCompletionStatusEx,
+	_LoadLibraryExW,
+	_ stdFunction
+)
+
+// Function to be called by windows CreateThread
+// to start new os thread.
+func tstart_stdcall(newm *m) uint32
+
+func ctrlhandler(_type uint32) uint32
 
 type mOS struct {
 	waitsema uintptr // semaphore for parking on locks
 }
 
-type stdFunction *byte
-
 //go:linkname os_sigpipe os.sigpipe
 func os_sigpipe() {
 	throw("too many writes on closed pipe")
 }
 
-// Stubs so tests can link correctly.  These should never be called.
+// Stubs so tests can link correctly. These should never be called.
 func open(name *byte, mode, perm int32) int32 {
 	throw("unimplemented")
 	return -1
@@ -30,3 +140,605 @@ func read(fd int32, p unsafe.Pointer, n int32) int32 {
 	throw("unimplemented")
 	return -1
 }
+
+type sigset struct{}
+
+// 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 windowsFindfunc(lib uintptr, name []byte) stdFunction {
+	if name[len(name)-1] != 0 {
+		throw("usage")
+	}
+	f := stdcall2(_GetProcAddress, lib, uintptr(unsafe.Pointer(&name[0])))
+	return stdFunction(unsafe.Pointer(f))
+}
+
+func loadOptionalSyscalls() {
+	var kernel32dll = []byte("kernel32.dll\000")
+	k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0])))
+	if k32 == 0 {
+		throw("kernel32.dll not found")
+	}
+	_AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
+	_AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
+	_GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000"))
+	_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
+}
+
+//go:nosplit
+func getLoadLibrary() uintptr {
+	return uintptr(unsafe.Pointer(_LoadLibraryW))
+}
+
+//go:nosplit
+func getLoadLibraryEx() uintptr {
+	return uintptr(unsafe.Pointer(_LoadLibraryExW))
+}
+
+//go:nosplit
+func getGetProcAddress() uintptr {
+	return uintptr(unsafe.Pointer(_GetProcAddress))
+}
+
+func getproccount() int32 {
+	var mask, sysmask uintptr
+	ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask)))
+	if ret != 0 {
+		n := 0
+		maskbits := int(unsafe.Sizeof(mask) * 8)
+		for i := 0; i < maskbits; i++ {
+			if mask&(1<<uint(i)) != 0 {
+				n++
+			}
+		}
+		if n != 0 {
+			return int32(n)
+		}
+	}
+	// use GetSystemInfo if GetProcessAffinityMask fails
+	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 getlasterror() uint32
+func setlasterror(err uint32)
+
+// When loading DLLs, we prefer to use LoadLibraryEx with
+// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not
+// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_*
+// flags are not available on some versions of Windows without a
+// security patch.
+//
+// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
+// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
+// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
+// systems that have KB2533623 installed. To determine whether the
+// flags are available, use GetProcAddress to get the address of the
+// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
+// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
+// flags can be used with LoadLibraryEx."
+var useLoadLibraryEx bool
+
+var timeBeginPeriodRetValue uint32
+
+func osinit() {
+	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
+	usleep2Addr = unsafe.Pointer(funcPC(usleep2))
+	switchtothreadAddr = unsafe.Pointer(funcPC(switchtothread))
+
+	setBadSignalMsg()
+
+	loadOptionalSyscalls()
+
+	useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil)
+
+	disableWER()
+
+	externalthreadhandlerp = funcPC(externalthreadhandler)
+
+	initExceptionHandler()
+
+	stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
+
+	timeBeginPeriodRetValue = uint32(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
+	}
+	isASCII := true
+	b := (*[1 << 30]byte)(buf)[:n]
+	for _, x := range b {
+		if x >= 0x80 {
+			isASCII = false
+			break
+		}
+	}
+
+	if !isASCII {
+		var m uint32
+		isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
+		// If this is a console output, various non-unicode code pages can be in use.
+		// Use the dedicated WriteConsole call to ensure unicode is printed correctly.
+		if isConsole {
+			return int32(writeConsole(handle, buf, n))
+		}
+	}
+	var written uint32
+	stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
+	return int32(written)
+}
+
+var (
+	utf16ConsoleBack     [1000]uint16
+	utf16ConsoleBackLock mutex
+)
+
+// writeConsole writes bufLen bytes from buf to the console File.
+// It returns the number of bytes written.
+func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
+	const surr2 = (surrogateMin + surrogateMax + 1) / 2
+
+	// Do not use defer for unlock. May cause issues when printing a panic.
+	lock(&utf16ConsoleBackLock)
+
+	b := (*[1 << 30]byte)(buf)[:bufLen]
+	s := *(*string)(unsafe.Pointer(&b))
+
+	utf16tmp := utf16ConsoleBack[:]
+
+	total := len(s)
+	w := 0
+	for len(s) > 0 {
+		if w >= len(utf16tmp)-2 {
+			writeConsoleUTF16(handle, utf16tmp[:w])
+			w = 0
+		}
+		r, n := charntorune(s)
+		s = s[n:]
+		if r < 0x10000 {
+			utf16tmp[w] = uint16(r)
+			w++
+		} else {
+			r -= 0x10000
+			utf16tmp[w] = surrogateMin + uint16(r>>10)&0x3ff
+			utf16tmp[w+1] = surr2 + uint16(r)&0x3ff
+			w += 2
+		}
+	}
+	writeConsoleUTF16(handle, utf16tmp[:w])
+	unlock(&utf16ConsoleBackLock)
+	return total
+}
+
+// writeConsoleUTF16 is the dedicated windows calls that correctly prints
+// to the console regardless of the current code page. Input is utf-16 code points.
+// The handle must be a console handle.
+func writeConsoleUTF16(handle uintptr, b []uint16) {
+	l := uint32(len(b))
+	if l == 0 {
+		return
+	}
+	var written uint32
+	stdcall5(_WriteConsoleW,
+		handle,
+		uintptr(unsafe.Pointer(&b[0])),
+		uintptr(l),
+		uintptr(unsafe.Pointer(&written)),
+		0,
+	)
+	return
+}
+
+//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(mp *m) {
+	if mp.waitsema != 0 {
+		return
+	}
+	mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0)
+}
+
+// May run with m.p==nil, so write barriers are not allowed. This
+// function is called by newosproc0, so it is also required to
+// operate without stack guards.
+//go:nowritebarrierc
+//go:nosplit
+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")
+	}
+}
+
+// Used by the C library build mode. On Linux this function would allocate a
+// stack, but that's not necessary for Windows. No stack guards are present
+// and the GC has not been initialized, so write barriers will fail.
+//go:nowritebarrierc
+//go:nosplit
+func newosproc0(mp *m, stk unsafe.Pointer) {
+	newosproc(mp, stk)
+}
+
+// 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) {
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+}
+
+//go:nosplit
+func sigblock() {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, cannot allocate memory.
+func minit() {
+	var thandle uintptr
+	stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
+	atomic.Storeuintptr(&getg().m.thread, thandle)
+}
+
+// Called from dropm to undo the effect of an minit.
+//go:nosplit
+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 onosstack(fn unsafe.Pointer, arg uint32)
+func usleep2(usec uint32)
+func switchtothread()
+
+var usleep2Addr unsafe.Pointer
+var switchtothreadAddr unsafe.Pointer
+
+//go:nosplit
+func osyield() {
+	onosstack(switchtothreadAddr, 0)
+}
+
+//go:nosplit
+func usleep(us uint32) {
+	// Have 1us units; want 100ns units.
+	onosstack(usleep2Addr, 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]
+	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)(atomic.Loadp(unsafe.Pointer(&allm)))
+		for mp := first; mp != nil; mp = mp.alllink {
+			thread := atomic.Loaduintptr(&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)
+		atomic.Storeuintptr(&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)
+	atomic.Store((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
+}
+
+func memlimit() uintptr {
+	return 0
+}
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 3d9d035..60b277d 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -79,10 +79,10 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
 		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
+	// 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.  The memmove below does that.
+	// 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)
@@ -205,7 +205,7 @@ func newdefer(siz int32) *_defer {
 	if d == nil {
 		// Allocate new defer+args.
 		total := roundupsize(totaldefersize(uintptr(siz)))
-		d = (*_defer)(mallocgc(total, deferType, 0))
+		d = (*_defer)(mallocgc(total, deferType, true))
 	}
 	d.siz = siz
 	gp := mp.curg
@@ -272,7 +272,7 @@ func freedeferfn() {
 // If there is a deferred function, this will call runtime·jmpdefer,
 // which will jump to the deferred function such that it appears
 // to have been called by the caller of deferreturn at the point
-// just before deferreturn was called.  The effect is that deferreturn
+// just before deferreturn was called. The effect is that deferreturn
 // is called again and again until there are no more deferred functions.
 // Cannot split the stack because we reuse the caller's frame to
 // call the deferred function.
@@ -308,8 +308,8 @@ func deferreturn(arg0 uintptr) {
 	jmpdefer(fn, uintptr(unsafe.Pointer(&arg0)))
 }
 
-// Goexit terminates the goroutine that calls it.  No other goroutine is affected.
-// Goexit runs all deferred calls before terminating the goroutine.  Because Goexit
+// Goexit terminates the goroutine that calls it. No other goroutine is affected.
+// Goexit runs all deferred calls before terminating the goroutine. Because Goexit
 // is not panic, however, any recover calls in those deferred functions will return nil.
 //
 // Calling Goexit from the main goroutine terminates that goroutine
@@ -350,7 +350,22 @@ func Goexit() {
 	goexit1()
 }
 
-// Print all currently active panics.  Used when crashing.
+// Call all Error and String methods before freezing the world.
+// Used when crashing with panicking.
+// This must match types handled by printany.
+func preprintpanics(p *_panic) {
+	for p != nil {
+		switch v := p.arg.(type) {
+		case error:
+			p.arg = v.Error()
+		case stringer:
+			p.arg = v.String()
+		}
+		p = p.link
+	}
+}
+
+// Print all currently active panics. Used when crashing.
 func printpanics(p *_panic) {
 	if p.link != nil {
 		printpanics(p.link)
@@ -451,7 +466,7 @@ func gopanic(e interface{}) {
 		d.fn = nil
 		gp._defer = d.link
 
-		// trigger shrinkage to test stack copy.  See stack_test.go:TestStackPanic
+		// trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic
 		//GC()
 
 		pc := d.pc
@@ -476,6 +491,10 @@ func gopanic(e interface{}) {
 	}
 
 	// ran out of deferred calls - old-school panic now
+	// Because it is unsafe to call arbitrary user code after freezing
+	// the world, we call preprintpanics to invoke all necessary Error
+	// and String methods to prepare the panic strings before startpanic.
+	preprintpanics(gp._panic)
 	startpanic()
 	printpanics(gp._panic)
 	dopanic(0)       // should not return
@@ -552,7 +571,7 @@ func throw(s string) {
 var paniclk mutex
 
 // Unwind the stack after a deferred function calls recover
-// after a panic.  Then arrange to continue running as though
+// 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.
@@ -622,7 +641,13 @@ 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")
+		signame := signame(gp.sig)
+		if signame != "" {
+			print("[signal ", signame)
+		} else {
+			print("[signal ", hex(gp.sig))
+		}
+		print(" code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n")
 	}
 
 	level, all, docrash := gotraceback()
diff --git a/src/runtime/parfor.go b/src/runtime/parfor.go
deleted file mode 100644
index 9e11cb3..0000000
--- a/src/runtime/parfor.go
+++ /dev/null
@@ -1,217 +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.
-
-package runtime
-
-import (
-	"runtime/internal/atomic"
-	"runtime/internal/sys"
-)
-
-// 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        [sys.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 := atomic.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 := atomic.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
-				atomic.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 {
-					atomic.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 := atomic.Load64(victimpos)
-				begin = uint32(pos)
-				end = uint32(pos >> 32)
-				if begin+1 >= end {
-					end = 0
-					begin = end
-					break
-				}
-				if idle {
-					atomic.Xadd(&desc.done, -1)
-					idle = false
-				}
-				begin2 := begin + (end-begin)/2
-				newpos := uint64(begin) | uint64(begin2)<<32
-				if atomic.Cas64(victimpos, pos, newpos) {
-					begin = begin2
-					break
-				}
-			}
-			if begin < end {
-				// Has successfully stolen some work.
-				if idle {
-					throw("parfor: should not be idle")
-				}
-				atomic.Store64(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 {
-					atomic.Xadd(&desc.done, 1)
-				}
-				goto exit
-			} else if try < 6*desc.nthr {
-				me.nosyield++
-				osyield()
-			} else {
-				me.nsleep++
-				usleep(1)
-			}
-		}
-	}
-
-exit:
-	atomic.Xadd64(&desc.nsteal, int64(me.nsteal))
-	atomic.Xadd64(&desc.nstealcnt, int64(me.nstealcnt))
-	atomic.Xadd64(&desc.nprocyield, int64(me.nprocyield))
-	atomic.Xadd64(&desc.nosyield, int64(me.nosyield))
-	atomic.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
deleted file mode 100644
index 5d22aec..0000000
--- a/src/runtime/parfor_test.go
+++ /dev/null
@@ -1,128 +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 race detector does not understand ParFor synchronization.
-// +build !race
-
-package runtime_test
-
-import (
-	. "runtime"
-	"testing"
-)
-
-// Simple serial sanity test for parallelfor.
-func TestParFor(t *testing.T) {
-	const P = 1
-	const N = 20
-	data := make([]uint64, N)
-	for i := uint64(0); i < N; i++ {
-		data[i] = i
-	}
-	desc := NewParFor(P)
-	ParForSetup(desc, P, N, true, func(desc *ParFor, i uint32) {
-		data[i] = data[i]*data[i] + 1
-	})
-	ParForDo(desc)
-	for i := uint64(0); i < N; i++ {
-		if data[i] != i*i+1 {
-			t.Fatalf("Wrong element %d: %d", i, data[i])
-		}
-	}
-}
-
-// Test that nonblocking parallelfor does not block.
-func TestParFor2(t *testing.T) {
-	const P = 7
-	const N = 1003
-	data := make([]uint64, N)
-	for i := uint64(0); i < N; i++ {
-		data[i] = i
-	}
-	desc := NewParFor(P)
-	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)
-	}
-	for i := uint64(0); i < N; i++ {
-		if data[i] != i*i+1 {
-			t.Fatalf("Wrong element %d: %d", i, data[i])
-		}
-	}
-}
-
-// Test that iterations are properly distributed.
-func TestParForSetup(t *testing.T) {
-	const P = 11
-	const N = 101
-	desc := NewParFor(P)
-	for n := uint32(0); n < N; n++ {
-		for p := uint32(1); p <= P; p++ {
-			ParForSetup(desc, p, n, true, func(desc *ParFor, i uint32) {})
-			sum := uint32(0)
-			size0 := uint32(0)
-			end0 := uint32(0)
-			for i := uint32(0); i < p; i++ {
-				begin, end := ParForIters(desc, i)
-				size := end - begin
-				sum += size
-				if i == 0 {
-					size0 = size
-					if begin != 0 {
-						t.Fatalf("incorrect begin: %d (n=%d, p=%d)", begin, n, p)
-					}
-				} else {
-					if size != size0 && size != size0+1 {
-						t.Fatalf("incorrect size: %d/%d (n=%d, p=%d)", size, size0, n, p)
-					}
-					if begin != end0 {
-						t.Fatalf("incorrect begin/end: %d/%d (n=%d, p=%d)", begin, end0, n, p)
-					}
-				}
-				end0 = end
-			}
-			if sum != n {
-				t.Fatalf("incorrect sum: %d/%d (p=%d)", sum, n, p)
-			}
-		}
-	}
-}
-
-// Test parallel parallelfor.
-func TestParForParallel(t *testing.T) {
-	N := uint64(1e7)
-	if testing.Short() {
-		N /= 10
-	}
-	data := make([]uint64, N)
-	for i := uint64(0); i < N; i++ {
-		data[i] = i
-	}
-	P := GOMAXPROCS(-1)
-	c := make(chan bool, P)
-	desc := NewParFor(uint32(P))
-	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++ {
-		go func() {
-			ParForDo(desc)
-			c <- true
-		}()
-	}
-	ParForDo(desc)
-	for p := 1; p < P; p++ {
-		<-c
-	}
-	for i := uint64(0); i < N; i++ {
-		if data[i] != i*i+1 {
-			t.Fatalf("Wrong element %d: %d", i, data[i])
-		}
-	}
-
-	data, desc = nil, nil
-	GC()
-}
diff --git a/src/runtime/pprof/mprof_test.go b/src/runtime/pprof/mprof_test.go
index d14fb58..0fff9d4 100644
--- a/src/runtime/pprof/mprof_test.go
+++ b/src/runtime/pprof/mprof_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -82,7 +82,7 @@ func TestMemoryProfiler(t *testing.T) {
 #	0x[0-9,a-f]+	runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:61
 `, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun),
 
-		fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
+		fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+ 0x[0-9,a-f]+
 #	0x[0-9,a-f]+	runtime/pprof_test\.allocateTransient2M\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:27
 #	0x[0-9,a-f]+	runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+	.*/runtime/pprof/mprof_test.go:62
 `, memoryProfilerRun, (2<<20)*memoryProfilerRun),
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index e09a33d..f2cd81a 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -1,11 +1,11 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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 pprof writes runtime profiling data in the format expected
 // by the pprof visualization tool.
 // For more information about pprof, see
-// http://code.google.com/p/google-perftools/.
+// http://github.com/google/pprof/.
 package pprof
 
 import (
@@ -13,6 +13,7 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"os"
 	"runtime"
 	"sort"
 	"strings"
@@ -31,7 +32,7 @@ import (
 //
 // A Profile's methods can be called from multiple goroutines simultaneously.
 //
-// Each Profile has a unique name.  A few profiles are predefined:
+// Each Profile has a unique name. A few profiles are predefined:
 //
 //	goroutine    - stack traces of all current goroutines
 //	heap         - a sampling of all heap allocations
@@ -48,7 +49,7 @@ import (
 // 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 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.
 //
@@ -173,11 +174,11 @@ func (p *Profile) Count() int {
 // Add adds the current execution stack to the profile, associated with value.
 // Add stores value in an internal map, so value must be suitable for use as
 // a map key and will not be garbage collected until the corresponding
-// call to Remove.  Add panics if the profile already contains a stack for value.
+// call to Remove. Add panics if the profile already contains a stack for value.
 //
 // The skip parameter has the same meaning as runtime.Caller's skip
-// and controls where the stack trace begins.  Passing skip=0 begins the
-// trace in the function calling Add.  For example, given this
+// and controls where the stack trace begins. Passing skip=0 begins the
+// trace in the function calling Add. For example, given this
 // execution stack:
 //
 //	Add
@@ -266,7 +267,7 @@ func (x stackProfile) Less(i, j int) bool {
 }
 
 // A countProfile is a set of stack traces to be printed as counts
-// grouped by stack trace.  There are multiple implementations:
+// grouped by stack trace. There are multiple implementations:
 // all that matters is that we can find out how many traces there are
 // and obtain each trace in turn.
 type countProfile interface {
@@ -296,22 +297,25 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro
 		}
 		return buf.String()
 	}
-	m := map[string]int{}
+	count := map[string]int{}
+	index := map[string]int{}
+	var keys []string
 	n := p.Len()
 	for i := 0; i < n; i++ {
-		m[key(p.Stack(i))]++
+		k := key(p.Stack(i))
+		if count[k] == 0 {
+			index[k] = i
+			keys = append(keys, k)
+		}
+		count[k]++
 	}
 
-	// Print stacks, listing count on first occurrence of a unique stack.
-	for i := 0; i < n; i++ {
-		stk := p.Stack(i)
-		s := key(stk)
-		if count := m[s]; count != 0 {
-			fmt.Fprintf(w, "%d %s\n", count, s)
-			if debug > 0 {
-				printStackRecord(w, stk, false)
-			}
-			delete(m, s)
+	sort.Sort(&keysByCount{keys, count})
+
+	for _, k := range keys {
+		fmt.Fprintf(w, "%d %s\n", count[k], k)
+		if debug > 0 {
+			printStackRecord(w, p.Stack(index[k]), false)
 		}
 	}
 
@@ -321,37 +325,45 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro
 	return b.Flush()
 }
 
+// keysByCount sorts keys with higher counts first, breaking ties by key string order.
+type keysByCount struct {
+	keys  []string
+	count map[string]int
+}
+
+func (x *keysByCount) Len() int      { return len(x.keys) }
+func (x *keysByCount) Swap(i, j int) { x.keys[i], x.keys[j] = x.keys[j], x.keys[i] }
+func (x *keysByCount) Less(i, j int) bool {
+	ki, kj := x.keys[i], x.keys[j]
+	ci, cj := x.count[ki], x.count[kj]
+	if ci != cj {
+		return ci > cj
+	}
+	return ki < kj
+}
+
 // printStackRecord prints the function + source line information
 // for a single stack trace.
 func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
 	show := allFrames
-	wasPanic := false
-	for i, pc := range stk {
-		f := runtime.FuncForPC(pc)
-		if f == nil {
+	frames := runtime.CallersFrames(stk)
+	for {
+		frame, more := frames.Next()
+		name := frame.Function
+		if name == "" {
 			show = true
-			fmt.Fprintf(w, "#\t%#x\n", pc)
-			wasPanic = false
+			fmt.Fprintf(w, "#\t%#x\n", frame.PC)
 		} else {
-			tracepc := pc
-			// Back up to call instruction.
-			if i > 0 && pc > f.Entry() && !wasPanic {
-				if runtime.GOARCH == "386" || runtime.GOARCH == "amd64" {
-					tracepc--
-				} else {
-					tracepc -= 4 // arm, etc
-				}
-			}
-			file, line := f.FileLine(tracepc)
-			name := f.Name()
 			// Hide runtime.goexit and any runtime functions at the beginning.
 			// This is useful mainly for allocation traces.
-			wasPanic = name == "runtime.gopanic"
 			if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") {
 				continue
 			}
 			show = true
-			fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", pc, name, pc-f.Entry(), file, line)
+			fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", frame.PC, name, frame.PC-frame.Entry, frame.File, frame.Line)
+		}
+		if !more {
+			break
 		}
 	}
 	if !show {
@@ -474,7 +486,6 @@ func writeHeap(w io.Writer, debug int) error {
 	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 {
@@ -509,7 +520,7 @@ func writeGoroutine(w io.Writer, debug int) error {
 
 func writeGoroutineStacks(w io.Writer) error {
 	// We don't know how big the buffer needs to be to collect
-	// all the goroutines.  Start with 1 MB and try a few times, doubling each time.
+	// all the goroutines. Start with 1 MB and try a few times, doubling each time.
 	// Give up and use a truncated trace if 64 MB is not enough.
 	buf := make([]byte, 1<<20)
 	for i := 0; ; i++ {
@@ -572,7 +583,7 @@ var cpu struct {
 // Go code built with -buildmode=c-archive or -buildmode=c-shared.
 // StartCPUProfile relies on the SIGPROF signal, but that signal will
 // be delivered to the main program's SIGPROF signal handler (if any)
-// not to the one used by Go.  To make it work, call os/signal.Notify
+// not to the one used by Go. To make it work, call os/signal.Notify
 // for syscall.SIGPROF, but note that doing so may break any profiling
 // being done by the main program.
 func StartCPUProfile(w io.Writer) error {
@@ -583,7 +594,7 @@ func StartCPUProfile(w io.Writer) error {
 	// 100 Hz is a reasonable choice: it is frequent enough to
 	// produce useful data, rare enough not to bog down the
 	// system, and a nice round number to make it easy to
-	// convert sample counts to seconds.  Instead of requiring
+	// convert sample counts to seconds. Instead of requiring
 	// each client to specify the frequency, we hard code it.
 	const hz = 100
 
@@ -610,6 +621,42 @@ func profileWriter(w io.Writer) {
 		}
 		w.Write(data)
 	}
+
+	// We are emitting the legacy profiling format, which permits
+	// a memory map following the CPU samples. The memory map is
+	// simply a copy of the GNU/Linux /proc/self/maps file. The
+	// profiler uses the memory map to map PC values in shared
+	// libraries to a shared library in the filesystem, in order
+	// to report the correct function and, if the shared library
+	// has debug info, file/line. This is particularly useful for
+	// PIE (position independent executables) as on ELF systems a
+	// PIE is simply an executable shared library.
+	//
+	// Because the profiling format expects the memory map in
+	// GNU/Linux format, we only do this on GNU/Linux for now. To
+	// add support for profiling PIE on other ELF-based systems,
+	// it may be necessary to map the system-specific mapping
+	// information to the GNU/Linux format. For a reasonably
+	// portable C++ version, see the FillProcSelfMaps function in
+	// https://github.com/gperftools/gperftools/blob/master/src/base/sysinfo.cc
+	//
+	// The code that parses this mapping for the pprof tool is
+	// ParseMemoryMap in cmd/internal/pprof/legacy_profile.go, but
+	// don't change that code, as similar code exists in other
+	// (non-Go) pprof readers. Change this code so that that code works.
+	//
+	// We ignore errors reading or copying the memory map; the
+	// profile is likely usable without it, and we have no good way
+	// to report errors.
+	if runtime.GOOS == "linux" {
+		f, err := os.Open("/proc/self/maps")
+		if err == nil {
+			io.WriteString(w, "\nMAPPED_LIBRARIES:\n")
+			io.Copy(w, f)
+			f.Close()
+		}
+	}
+
 	cpu.done <- true
 }
 
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index ab6b183..a6f5eda 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -86,10 +86,14 @@ func TestCPUProfileMultithreaded(t *testing.T) {
 	})
 }
 
-func parseProfile(t *testing.T, bytes []byte, f func(uintptr, []uintptr)) {
+func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []uintptr)) {
 	// Convert []byte to []uintptr.
-	l := len(bytes) / int(unsafe.Sizeof(uintptr(0)))
-	val := *(*[]uintptr)(unsafe.Pointer(&bytes))
+	l := len(valBytes)
+	if i := bytes.Index(valBytes, []byte("\nMAPPED_LIBRARIES:\n")); i >= 0 {
+		l = i
+	}
+	l /= int(unsafe.Sizeof(uintptr(0)))
+	val := *(*[]uintptr)(unsafe.Pointer(&valBytes))
 	val = val[:l]
 
 	// 5 for the header, 3 for the trailer.
@@ -388,7 +392,7 @@ func TestStackBarrierProfiling(t *testing.T) {
 			args = append(args, "-test.short")
 		}
 		cmd := exec.Command(os.Args[0], args...)
-		cmd.Env = append([]string{"GODEBUG=gcstackbarrierall=1", "GOGC=1"}, os.Environ()...)
+		cmd.Env = append([]string{"GODEBUG=gcstackbarrierall=1", "GOGC=1", "GOTRACEBACK=system"}, os.Environ()...)
 		if out, err := cmd.CombinedOutput(); err != nil {
 			t.Fatalf("subprocess failed with %v:\n%s", err, out)
 		}
@@ -530,15 +534,20 @@ func blockChanClose() {
 }
 
 func blockSelectRecvAsync() {
+	const numTries = 3
 	c := make(chan bool, 1)
 	c2 := make(chan bool, 1)
 	go func() {
-		time.Sleep(blockDelay)
-		c <- true
+		for i := 0; i < numTries; i++ {
+			time.Sleep(blockDelay)
+			c <- true
+		}
 	}()
-	select {
-	case <-c:
-	case <-c2:
+	for i := 0; i < numTries; i++ {
+		select {
+		case <-c:
+		case <-c2:
+		}
 	}
 }
 
@@ -578,3 +587,50 @@ func blockCond() {
 	c.Wait()
 	mu.Unlock()
 }
+
+func func1(c chan int) { <-c }
+func func2(c chan int) { <-c }
+func func3(c chan int) { <-c }
+func func4(c chan int) { <-c }
+
+func TestGoroutineCounts(t *testing.T) {
+	if runtime.GOOS == "openbsd" {
+		testenv.SkipFlaky(t, 15156)
+	}
+	c := make(chan int)
+	for i := 0; i < 100; i++ {
+		if i%10 == 0 {
+			go func1(c)
+			continue
+		}
+		if i%2 == 0 {
+			go func2(c)
+			continue
+		}
+		go func3(c)
+	}
+	time.Sleep(10 * time.Millisecond) // let goroutines block on channel
+
+	var w bytes.Buffer
+	Lookup("goroutine").WriteTo(&w, 1)
+	prof := w.String()
+
+	if !containsInOrder(prof, "\n50 @ ", "\n40 @", "\n10 @", "\n1 @") {
+		t.Errorf("expected sorted goroutine counts:\n%s", prof)
+	}
+
+	close(c)
+
+	time.Sleep(10 * time.Millisecond) // let goroutines exit
+}
+
+func containsInOrder(s string, all ...string) bool {
+	for _, t := range all {
+		i := strings.Index(s, t)
+		if i < 0 {
+			return false
+		}
+		s = s[i+len(t):]
+	}
+	return true
+}
diff --git a/src/runtime/print.go b/src/runtime/print.go
index f789f89..32626c1 100644
--- a/src/runtime/print.go
+++ b/src/runtime/print.go
@@ -209,7 +209,7 @@ func printstring(s string) {
 func printslice(s []byte) {
 	sp := (*slice)(unsafe.Pointer(&s))
 	print("[", len(s), "/", cap(s), "]")
-	printpointer(unsafe.Pointer(sp.array))
+	printpointer(sp.array)
 }
 
 func printeface(e eface) {
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 47ccb37..2c0b3df 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -76,8 +76,9 @@ var buildVersion = sys.TheVersion
 // for nmspinning manipulation.
 
 var (
-	m0 m
-	g0 g
+	m0           m
+	g0           g
+	raceprocctx0 uintptr
 )
 
 //go:linkname runtime_init runtime.init
@@ -126,7 +127,7 @@ func main() {
 	})
 
 	// Lock the main goroutine onto this, the main OS thread,
-	// during initialization.  Most programs won't care, but a few
+	// during initialization. Most programs won't care, but a few
 	// do require certain calls to be made by the main thread.
 	// Those can arrange for main.main to run in the main thread
 	// by calling runtime.LockOSThread during initialization
@@ -154,12 +155,6 @@ func main() {
 		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")
@@ -237,7 +232,7 @@ func forcegchelper() {
 
 //go:nosplit
 
-// Gosched yields the processor, allowing other goroutines to run.  It does not
+// Gosched yields the processor, allowing other goroutines to run. It does not
 // suspend the current goroutine, so execution resumes automatically.
 func Gosched() {
 	mcall(gosched_m)
@@ -245,6 +240,8 @@ func Gosched() {
 
 // Puts the current goroutine into a waiting state and calls unlockf.
 // If unlockf returns false, the goroutine is resumed.
+// unlockf must not access this G's stack, as it may be moved between
+// the call to gopark and the call to unlockf.
 func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string, traceEv byte, traceskip int) {
 	mp := acquirem()
 	gp := mp.curg
@@ -270,7 +267,7 @@ func goparkunlock(lock *mutex, reason string, traceEv byte, traceskip int) {
 
 func goready(gp *g, traceskip int) {
 	systemstack(func() {
-		ready(gp, traceskip)
+		ready(gp, traceskip, true)
 	})
 }
 
@@ -329,6 +326,9 @@ func releaseSudog(s *sudog) {
 	if s.waitlink != nil {
 		throw("runtime: sudog with non-nil waitlink")
 	}
+	if s.c != nil {
+		throw("runtime: sudog with non-nil c")
+	}
 	gp := getg()
 	if gp.param != nil {
 		throw("runtime: releaseSudog with non-nil gp.param")
@@ -376,7 +376,7 @@ func badmcall2(fn func(*g)) {
 }
 
 func badreflectcall() {
-	panic("runtime: arg size to reflect.call more than 1GB")
+	panic(plainError("arg size to reflect.call more than 1GB"))
 }
 
 func lockedOSThread() bool {
@@ -397,6 +397,16 @@ func allgadd(gp *g) {
 	lock(&allglock)
 	allgs = append(allgs, gp)
 	allglen = uintptr(len(allgs))
+
+	// Grow GC rescan list if necessary.
+	if len(allgs) > cap(work.rescan.list) {
+		lock(&work.rescan.lock)
+		l := work.rescan.list
+		// Let append do the heavy lifting, but keep the
+		// length the same.
+		work.rescan.list = append(l[:cap(l)], 0)[:len(l)]
+		unlock(&work.rescan.lock)
+	}
 	unlock(&allglock)
 }
 
@@ -419,19 +429,18 @@ func schedinit() {
 	// In particular, it must be done before mallocinit below calls racemapshadow.
 	_g_ := getg()
 	if raceenabled {
-		_g_.racectx = raceinit()
+		_g_.racectx, raceprocctx0 = raceinit()
 	}
 
 	sched.maxmcount = 10000
 
-	// Cache the framepointer experiment.  This affects stack unwinding.
-	framepointer_enabled = haveexperiment("framepointer")
-
 	tracebackinit()
 	moduledataverify()
 	stackinit()
 	mallocinit()
 	mcommoninit(_g_.m)
+	typelinksinit()
+	itabsinit()
 
 	msigsave(_g_.m)
 	initSigmask = _g_.m.sigmask
@@ -457,7 +466,7 @@ func schedinit() {
 	}
 
 	if buildVersion == "" {
-		// Condition should never trigger.  This code just serves
+		// Condition should never trigger. This code just serves
 		// to ensure runtime·buildVersion is kept in the resulting binary.
 		buildVersion = "unknown"
 	}
@@ -507,10 +516,15 @@ func mcommoninit(mp *m) {
 	// so we need to publish it safely.
 	atomicstorep(unsafe.Pointer(&allm), unsafe.Pointer(mp))
 	unlock(&sched.lock)
+
+	// Allocate memory to hold a cgo traceback if the cgo call crashes.
+	if iscgo || GOOS == "solaris" || GOOS == "windows" {
+		mp.cgoCallers = new(cgoCallers)
+	}
 }
 
 // Mark gp ready to run.
-func ready(gp *g, traceskip int) {
+func ready(gp *g, traceskip int, next bool) {
 	if trace.enabled {
 		traceGoUnpark(gp, traceskip)
 	}
@@ -527,7 +541,7 @@ func ready(gp *g, traceskip int) {
 
 	// status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
 	casgstatus(gp, _Gwaiting, _Grunnable)
-	runqput(_g_.m.p.ptr(), gp, true)
+	runqput(_g_.m.p.ptr(), gp, next)
 	if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 { // TODO: fast atomic
 		wakep()
 	}
@@ -631,17 +645,17 @@ func readgstatus(gp *g) uint32 {
 	return atomic.Load(&gp.atomicstatus)
 }
 
-// Ownership of gscanvalid:
+// Ownership of gcscanvalid:
 //
 // If gp is running (meaning status == _Grunning or _Grunning|_Gscan),
-// then gp owns gp.gscanvalid, and other goroutines must not modify it.
+// then gp owns gp.gcscanvalid, 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.
+// in the status bit and then modify gcscanvalid, 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.
+// that second goroutine still does not have the right to modify gcscanvalid.
 
 // 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
@@ -663,19 +677,12 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
 		if newval == oldval&^_Gscan {
 			success = atomic.Cas(&gp.atomicstatus, oldval, newval)
 		}
-	case _Gscanenqueue:
-		if newval == _Gwaiting {
-			success = atomic.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.
@@ -683,15 +690,12 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
 func castogscanstatus(gp *g, oldval, newval uint32) bool {
 	switch oldval {
 	case _Grunnable,
+		_Grunning,
 		_Gwaiting,
 		_Gsyscall:
 		if newval == oldval|_Gscan {
 			return atomic.Cas(&gp.atomicstatus, oldval, newval)
 		}
-	case _Grunning:
-		if newval == _Gscanrunning || newval == _Gscanenqueue {
-			return atomic.Cas(&gp.atomicstatus, oldval, newval)
-		}
 	}
 	print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n")
 	throw("castogscanstatus")
@@ -720,9 +724,13 @@ func casgstatus(gp *g, oldval, newval uint32) {
 		throw("casgstatus")
 	}
 
+	// See http://golang.org/cl/21503 for justification of the yield delay.
+	const yieldDelay = 5 * 1000
+	var nextYield int64
+
 	// loop if gp->atomicstatus is in a scan state giving
 	// GC time to finish and change the state to oldval.
-	for !atomic.Cas(&gp.atomicstatus, oldval, newval) {
+	for i := 0; !atomic.Cas(&gp.atomicstatus, oldval, newval); i++ {
 		if oldval == _Gwaiting && gp.atomicstatus == _Grunnable {
 			systemstack(func() {
 				throw("casgstatus: waiting for Gwaiting but is Grunnable")
@@ -735,9 +743,22 @@ func casgstatus(gp *g, oldval, newval uint32) {
 		// 		gcphasework(gp)
 		// 	})
 		// }
+		// But meanwhile just yield.
+		if i == 0 {
+			nextYield = nanotime() + yieldDelay
+		}
+		if nanotime() < nextYield {
+			for x := 0; x < 10 && gp.atomicstatus != oldval; x++ {
+				procyield(1)
+			}
+		} else {
+			osyield()
+			nextYield = nanotime() + yieldDelay/2
+		}
 	}
-	if newval == _Grunning {
-		gp.gcscanvalid = false
+	if newval == _Grunning && gp.gcscanvalid {
+		// Run queueRescan on the system stack so it has more space.
+		systemstack(func() { queueRescan(gp) })
 	}
 }
 
@@ -762,7 +783,7 @@ func casgcopystack(gp *g) uint32 {
 // 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) {
+func scang(gp *g, gcw *gcWork) {
 	// 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).
@@ -772,12 +793,17 @@ func scang(gp *g) {
 
 	gp.gcscandone = false
 
+	// See http://golang.org/cl/21503 for justification of the yield delay.
+	const yieldDelay = 10 * 1000
+	var nextYield int64
+
 	// 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 {
+loop:
+	for i := 0; !gp.gcscandone; i++ {
 		switch s := readgstatus(gp); s {
 		default:
 			dumpgstatus(gp)
@@ -786,6 +812,7 @@ func scang(gp *g) {
 		case _Gdead:
 			// No stack.
 			gp.gcscandone = true
+			break loop
 
 		case _Gcopystack:
 		// Stack being switched. Go around again.
@@ -797,10 +824,11 @@ func scang(gp *g) {
 			// the goroutine until we're done.
 			if castogscanstatus(gp, s, s|_Gscan) {
 				if !gp.gcscandone {
-					scanstack(gp)
+					scanstack(gp, gcw)
 					gp.gcscandone = true
 				}
 				restartg(gp)
+				break loop
 			}
 
 		case _Gscanwaiting:
@@ -826,6 +854,16 @@ func scang(gp *g) {
 				casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
 			}
 		}
+
+		if i == 0 {
+			nextYield = nanotime() + yieldDelay
+		}
+		if nanotime() < nextYield {
+			procyield(10)
+		} else {
+			osyield()
+			nextYield = nanotime() + yieldDelay/2
+		}
 	}
 
 	gp.preemptscan = false // cancel scan request if no longer needed
@@ -846,17 +884,6 @@ func restartg(gp *g) {
 		_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)
 	}
 }
 
@@ -1035,7 +1062,7 @@ func startTheWorldWithSema() {
 		// 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:
+		// 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)
@@ -1381,6 +1408,8 @@ func newextram() {
 	gp.syscallpc = gp.sched.pc
 	gp.syscallsp = gp.sched.sp
 	gp.stktopsp = gp.sched.sp
+	gp.gcscanvalid = true // fresh G, so no dequeueRescan necessary
+	gp.gcRescan = -1
 	// malg returns status as Gidle, change to Gsyscall before adding to allg
 	// where GC will see it.
 	casgstatus(gp, _Gidle, _Gsyscall)
@@ -1491,7 +1520,7 @@ func unlockextra(mp *m) {
 	atomic.Storeuintptr(&extram, uintptr(unsafe.Pointer(mp)))
 }
 
-// Create a new m.  It will start off with a call to fn, or else the scheduler.
+// 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
@@ -1769,23 +1798,7 @@ func execute(gp *g, inheritTime bool) {
 		// 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)
+			traceGoSysExit(gp.sysexitticks)
 		}
 		traceGoStart()
 	}
@@ -1803,28 +1816,29 @@ func findrunnable() (gp *g, inheritTime bool) {
 	// an M.
 
 top:
+	_p_ := _g_.m.p.ptr()
 	if sched.gcwaiting != 0 {
 		gcstopm()
 		goto top
 	}
-	if _g_.m.p.ptr().runSafePointFn != 0 {
+	if _p_.runSafePointFn != 0 {
 		runSafePointFn()
 	}
 	if fingwait && fingwake {
 		if gp := wakefing(); gp != nil {
-			ready(gp, 0)
+			ready(gp, 0, true)
 		}
 	}
 
 	// local runq
-	if gp, inheritTime := runqget(_g_.m.p.ptr()); gp != nil {
+	if gp, inheritTime := runqget(_p_); gp != nil {
 		return gp, inheritTime
 	}
 
 	// global runq
 	if sched.runqsize != 0 {
 		lock(&sched.lock)
-		gp := globrunqget(_g_.m.p.ptr(), 0)
+		gp := globrunqget(_p_, 0)
 		unlock(&sched.lock)
 		if gp != nil {
 			return gp, false
@@ -1849,31 +1863,33 @@ top:
 		}
 	}
 
+	// Steal work from other P's.
+	procs := uint32(gomaxprocs)
+	if atomic.Load(&sched.npidle) == procs-1 {
+		// Either GOMAXPROCS=1 or everybody, except for us, is idle already.
+		// New work can appear from returning syscall/cgocall, network or timers.
+		// Neither of that submits to local run queues, so no point in stealing.
+		goto stop
+	}
 	// 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*atomic.Load(&sched.nmspinning) >= uint32(gomaxprocs)-atomic.Load(&sched.npidle) { // TODO: fast atomic
+	if !_g_.m.spinning && 2*atomic.Load(&sched.nmspinning) >= procs-atomic.Load(&sched.npidle) { // TODO: fast atomic
 		goto stop
 	}
 	if !_g_.m.spinning {
 		_g_.m.spinning = true
 		atomic.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
+	for i := 0; i < 4; i++ {
+		for enum := stealOrder.start(fastrand1()); !enum.done(); enum.next() {
+			if sched.gcwaiting != 0 {
+				goto top
+			}
+			stealRunNextG := i > 2 // first look for ready queues with more than 1 g
+			if gp := runqsteal(_p_, allp[enum.position()], stealRunNextG); gp != nil {
+				return gp, false
+			}
 		}
 	}
 
@@ -1882,7 +1898,7 @@ stop:
 	// We have nothing to do. If we're in the GC mark phase, can
 	// safely scan and blacken objects, and have work to do, run
 	// idle-time marking rather than give up the P.
-	if _p_ := _g_.m.p.ptr(); gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != 0 && gcMarkWorkAvailable(_p_) {
+	if gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != 0 && gcMarkWorkAvailable(_p_) {
 		_p_.gcMarkWorkerMode = gcMarkWorkerIdleMode
 		gp := _p_.gcBgMarkWorker.ptr()
 		casgstatus(gp, _Gwaiting, _Grunnable)
@@ -1894,16 +1910,18 @@ stop:
 
 	// return P and block
 	lock(&sched.lock)
-	if sched.gcwaiting != 0 || _g_.m.p.ptr().runSafePointFn != 0 {
+	if sched.gcwaiting != 0 || _p_.runSafePointFn != 0 {
 		unlock(&sched.lock)
 		goto top
 	}
 	if sched.runqsize != 0 {
-		gp := globrunqget(_g_.m.p.ptr(), 0)
+		gp := globrunqget(_p_, 0)
 		unlock(&sched.lock)
 		return gp, false
 	}
-	_p_ := releasep()
+	if releasep() != _p_ {
+		throw("findrunnable: wrong p")
+	}
 	pidleput(_p_)
 	unlock(&sched.lock)
 
@@ -2102,10 +2120,8 @@ top:
 func dropg() {
 	_g_ := getg()
 
-	if _g_.m.lockedg == nil {
-		_g_.m.curg.m = nil
-		_g_.m.curg = nil
-	}
+	_g_.m.curg.m = nil
+	_g_.m.curg = nil
 }
 
 func parkunlock_c(gp *g, lock unsafe.Pointer) bool {
@@ -2199,6 +2215,10 @@ func goexit0(gp *g) {
 	gp.waitreason = ""
 	gp.param = nil
 
+	// Note that gp's stack scan is now "valid" because it has no
+	// stack. We could dequeueRescan, but that takes a lock and
+	// isn't really necessary.
+	gp.gcscanvalid = true
 	dropg()
 
 	if _g_.m.locked&^_LockExternal != 0 {
@@ -2409,14 +2429,19 @@ func entersyscallblock_handoff() {
 // 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
+// from the low-level system calls used by the runtime.
 //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")
+		// throw calls print which may try to grow the stack,
+		// but throwsplit == true so the stack can not be grown;
+		// use systemstack to avoid that possible problem.
+		systemstack(func() {
+			throw("exitsyscall: syscall frame is no longer valid")
+		})
 	}
 
 	_g_.waitsince = 0
@@ -2451,7 +2476,6 @@ func exitsyscall(dummy int32) {
 	}
 
 	_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).
@@ -2462,7 +2486,7 @@ func exitsyscall(dummy int32) {
 		// 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_.sysexitticks = cputicks()
 	}
 
 	_g_.m.locks--
@@ -2510,7 +2534,7 @@ func exitsyscallfast() bool {
 					// Denote blocking of the new syscall.
 					traceGoSysBlock(_g_.m.p.ptr())
 					// Denote completion of the current syscall.
-					traceGoSysExit(tracestamp())
+					traceGoSysExit(0)
 				})
 			}
 			_g_.m.p.ptr().syscalltick++
@@ -2534,7 +2558,7 @@ func exitsyscallfast() bool {
 						osyield()
 					}
 				}
-				traceGoSysExit(tracestamp())
+				traceGoSysExit(0)
 			}
 		})
 		if ok {
@@ -2664,7 +2688,7 @@ func newproc(siz int32, fn *funcval) {
 
 // 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
+// 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()
@@ -2690,6 +2714,7 @@ func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr
 	if newg == nil {
 		newg = malg(_StackMin)
 		casgstatus(newg, _Gidle, _Gdead)
+		newg.gcRescan = -1
 		allgadd(newg) // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack.
 	}
 	if newg.stack.hi == 0 {
@@ -2723,6 +2748,17 @@ func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr
 	if isSystemGoroutine(newg) {
 		atomic.Xadd(&sched.ngsys, +1)
 	}
+	// The stack is dirty from the argument frame, so queue it for
+	// scanning. Do this before setting it to runnable so we still
+	// own the G. If we're recycling a G, it may already be on the
+	// rescan list.
+	if newg.gcRescan == -1 {
+		queueRescan(newg)
+	} else {
+		// The recycled G is already on the rescan list. Just
+		// mark the stack dirty.
+		newg.gcscanvalid = false
+	}
 	casgstatus(newg, _Gdead, _Grunnable)
 
 	if _p_.goidcache == _p_.goidcacheend {
@@ -2785,8 +2821,13 @@ func gfput(_p_ *p, gp *g) {
 			_p_.gfreecnt--
 			gp = _p_.gfree
 			_p_.gfree = gp.schedlink.ptr()
-			gp.schedlink.set(sched.gfree)
-			sched.gfree = gp
+			if gp.stack.lo == 0 {
+				gp.schedlink.set(sched.gfreeNoStack)
+				sched.gfreeNoStack = gp
+			} else {
+				gp.schedlink.set(sched.gfreeStack)
+				sched.gfreeStack = gp
+			}
 			sched.ngfree++
 		}
 		unlock(&sched.gflock)
@@ -2798,12 +2839,20 @@ func gfput(_p_ *p, gp *g) {
 func gfget(_p_ *p) *g {
 retry:
 	gp := _p_.gfree
-	if gp == nil && sched.gfree != nil {
+	if gp == nil && (sched.gfreeStack != nil || sched.gfreeNoStack != nil) {
 		lock(&sched.gflock)
-		for _p_.gfreecnt < 32 && sched.gfree != nil {
+		for _p_.gfreecnt < 32 {
+			if sched.gfreeStack != nil {
+				// Prefer Gs with stacks.
+				gp = sched.gfreeStack
+				sched.gfreeStack = gp.schedlink.ptr()
+			} else if sched.gfreeNoStack != nil {
+				gp = sched.gfreeNoStack
+				sched.gfreeNoStack = gp.schedlink.ptr()
+			} else {
+				break
+			}
 			_p_.gfreecnt++
-			gp = sched.gfree
-			sched.gfree = gp.schedlink.ptr()
 			sched.ngfree--
 			gp.schedlink.set(_p_.gfree)
 			_p_.gfree = gp
@@ -2815,7 +2864,7 @@ retry:
 		_p_.gfree = gp.schedlink.ptr()
 		_p_.gfreecnt--
 		if gp.stack.lo == 0 {
-			// Stack was deallocated in gfput.  Allocate a new one.
+			// Stack was deallocated in gfput. Allocate a new one.
 			systemstack(func() {
 				gp.stack, gp.stkbar = stackalloc(_FixedStack)
 			})
@@ -2840,8 +2889,13 @@ func gfpurge(_p_ *p) {
 		_p_.gfreecnt--
 		gp := _p_.gfree
 		_p_.gfree = gp.schedlink.ptr()
-		gp.schedlink.set(sched.gfree)
-		sched.gfree = gp
+		if gp.stack.lo == 0 {
+			gp.schedlink.set(sched.gfreeNoStack)
+			sched.gfreeNoStack = gp
+		} else {
+			gp.schedlink.set(sched.gfreeStack)
+			sched.gfreeStack = gp
+		}
 		sched.ngfree++
 	}
 	unlock(&sched.gflock)
@@ -2946,6 +3000,8 @@ func _ExternalCode() { _ExternalCode() }
 func _GC()           { _GC() }
 
 // Called if we receive a SIGPROF signal.
+// Called by the signal handler, may run during STW.
+//go:nowritebarrierrec
 func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	if prof.hz == 0 {
 		return
@@ -3027,12 +3083,24 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	var haveStackLock *g
 	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.
+		cgoOff := 0
+		// Check cgoCallersUse to make sure that we are not
+		// interrupting other code that is fiddling with
+		// cgoCallers.  We are running in a signal handler
+		// with all signals blocked, so we don't have to worry
+		// about any other code interrupting us.
+		if atomic.Load(&mp.cgoCallersUse) == 0 && mp.cgoCallers != nil && mp.cgoCallers[0] != 0 {
+			for cgoOff < len(mp.cgoCallers) && mp.cgoCallers[cgoOff] != 0 {
+				cgoOff++
+			}
+			copy(stk[:], mp.cgoCallers[:cgoOff])
+			mp.cgoCallers[0] = 0
+		}
+
+		// Collect Go stack that leads to the cgo call.
 		if gcTryLockStackBarriers(mp.curg) {
 			haveStackLock = mp.curg
-			n = gentraceback(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, 0, &stk[0], len(stk), nil, nil, 0)
+			n = gentraceback(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, 0, &stk[cgoOff], len(stk)-cgoOff, nil, nil, 0)
 		}
 	} else if traceback {
 		var flags uint = _TraceTrap
@@ -3093,6 +3161,36 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	mp.mallocing--
 }
 
+// If the signal handler receives a SIGPROF signal on a non-Go thread,
+// it tries to collect a traceback into sigprofCallers.
+// sigprofCallersUse is set to non-zero while sigprofCallers holds a traceback.
+var sigprofCallers cgoCallers
+var sigprofCallersUse uint32
+
+// Called if we receive a SIGPROF signal on a non-Go thread.
+// When this is called, sigprofCallersUse will be non-zero.
+// g is nil, and what we can do is very limited.
+//go:nosplit
+//go:nowritebarrierrec
+func sigprofNonGo() {
+	if prof.hz != 0 {
+		n := 0
+		for n < len(sigprofCallers) && sigprofCallers[n] != 0 {
+			n++
+		}
+
+		// Simple cas-lock to coordinate with setcpuprofilerate.
+		if atomic.Cas(&prof.lock, 0, 1) {
+			if prof.hz != 0 {
+				cpuprof.addNonGo(sigprofCallers[:n])
+			}
+			atomic.Store(&prof.lock, 0)
+		}
+	}
+
+	atomic.Store(&sigprofCallersUse, 0)
+}
+
 // Reports whether a function will set the SP
 // to an absolute value. Important that
 // we don't traceback when these are at the bottom
@@ -3151,7 +3249,7 @@ func setcpuprofilerate_m(hz int32) {
 	_g_.m.locks--
 }
 
-// Change number of processors.  The world is stopped, sched is locked.
+// 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.
@@ -3194,6 +3292,14 @@ func procresize(nprocs int32) *p {
 				pp.mcache = allocmcache()
 			}
 		}
+		if raceenabled && pp.racectx == 0 {
+			if old == 0 && i == 0 {
+				pp.racectx = raceprocctx0
+				raceprocctx0 = 0 // bootstrap
+			} else {
+				pp.racectx = raceproccreate()
+			}
+		}
 	}
 
 	// free unused P's
@@ -3245,6 +3351,10 @@ func procresize(nprocs int32) *p {
 		p.mcache = nil
 		gfpurge(p)
 		traceProcFree(p)
+		if raceenabled {
+			raceprocdestroy(p.racectx)
+			p.racectx = 0
+		}
 		p.status = _Pdead
 		// can't free P itself because it can be referenced by an M in syscall
 	}
@@ -3283,6 +3393,7 @@ func procresize(nprocs int32) *p {
 			runnablePs = p
 		}
 	}
+	stealOrder.reset(uint32(nprocs))
 	var int32p *int32 = &gomaxprocs // make compiler check that gomaxprocs is an int32
 	atomic.Store((*uint32)(unsafe.Pointer(int32p)), uint32(nprocs))
 	return runnablePs
@@ -3357,7 +3468,7 @@ func incidlelocked(v int32) {
 // 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
+	// there are no running goroutines. The calling program is
 	// assumed to be running.
 	if islibrary || isarchive {
 		return
@@ -3602,7 +3713,7 @@ func retake(now int64) uint32 {
 }
 
 // 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
+// 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.
@@ -3621,8 +3732,8 @@ func preemptall() bool {
 }
 
 // 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
+// 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.
@@ -3715,7 +3826,7 @@ func schedtrace(detailed bool) {
 		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")
+		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=", mp.blocked, " lockedg=", id3, "\n")
 	}
 
 	lock(&allglock)
@@ -3863,9 +3974,20 @@ func pidleget() *p {
 }
 
 // runqempty returns true if _p_ has no Gs on its local run queue.
-// Note that this test is generally racy.
+// It never returns true spuriously.
 func runqempty(_p_ *p) bool {
-	return _p_.runqhead == _p_.runqtail && _p_.runnext == 0
+	// Defend against a race where 1) _p_ has G1 in runqnext but runqhead == runqtail,
+	// 2) runqput on _p_ kicks G1 to the runq, 3) runqget on _p_ empties runqnext.
+	// Simply observing that runqhead == runqtail and then observing that runqnext == nil
+	// does not mean the queue is empty.
+	for {
+		head := atomic.Load(&_p_.runqhead)
+		tail := atomic.Load(&_p_.runqtail)
+		runnext := atomic.Loaduintptr((*uintptr)(unsafe.Pointer(&_p_.runnext)))
+		if tail == atomic.Load(&_p_.runqtail) {
+			return head == tail && runnext == 0
+		}
+	}
 }
 
 // To shake out latent assumptions about scheduling order,
@@ -3913,7 +4035,7 @@ retry:
 	if runqputslow(_p_, gp, h, t) {
 		return
 	}
-	// the queue is not full, now the put above must suceed
+	// the queue is not full, now the put above must succeed
 	goto retry
 }
 
@@ -4005,7 +4127,16 @@ func runqgrab(_p_ *p, batch *[256]guintptr, batchHead uint32, stealRunNextG bool
 					// 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)
+					// A sync chan send/recv takes ~50ns as of time of writing,
+					// so 3us gives ~50x overshoot.
+					if GOOS != "windows" {
+						usleep(3)
+					} else {
+						// On windows system timer granularity is 1-15ms,
+						// which is way too much for this optimization.
+						// So just yield.
+						osyield()
+					}
 					if !_p_.runnext.cas(next, 0) {
 						continue
 					}
@@ -4050,71 +4181,6 @@ func runqsteal(_p_, p2 *p, stealRunNextG bool) *g {
 	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")
-		}
-	}
-}
-
 //go:linkname setMaxThreads runtime/debug.setMaxThreads
 func setMaxThreads(in int) (out int) {
 	lock(&sched.lock)
@@ -4126,6 +4192,9 @@ func setMaxThreads(in int) (out int) {
 }
 
 func haveexperiment(name string) bool {
+	if name == "framepointer" {
+		return framepointer_enabled // set by linker
+	}
 	x := sys.Goexperiment
 	for x != "" {
 		xname := ""
@@ -4138,6 +4207,9 @@ func haveexperiment(name string) bool {
 		if xname == name {
 			return true
 		}
+		if len(xname) > 2 && xname[:2] == "no" && xname[2:] == name {
+			return false
+		}
 	}
 	return false
 }
@@ -4204,3 +4276,59 @@ func sync_runtime_canSpin(i int) bool {
 func sync_runtime_doSpin() {
 	procyield(active_spin_cnt)
 }
+
+var stealOrder randomOrder
+
+// randomOrder/randomEnum are helper types for randomized work stealing.
+// They allow to enumerate all Ps in different pseudo-random orders without repetitions.
+// The algorithm is based on the fact that if we have X such that X and GOMAXPROCS
+// are coprime, then a sequences of (i + X) % GOMAXPROCS gives the required enumeration.
+type randomOrder struct {
+	count    uint32
+	coprimes []uint32
+}
+
+type randomEnum struct {
+	i     uint32
+	count uint32
+	pos   uint32
+	inc   uint32
+}
+
+func (ord *randomOrder) reset(count uint32) {
+	ord.count = count
+	ord.coprimes = ord.coprimes[:0]
+	for i := uint32(1); i <= count; i++ {
+		if gcd(i, count) == 1 {
+			ord.coprimes = append(ord.coprimes, i)
+		}
+	}
+}
+
+func (ord *randomOrder) start(i uint32) randomEnum {
+	return randomEnum{
+		count: ord.count,
+		pos:   i % ord.count,
+		inc:   ord.coprimes[i%uint32(len(ord.coprimes))],
+	}
+}
+
+func (enum *randomEnum) done() bool {
+	return enum.i == enum.count
+}
+
+func (enum *randomEnum) next() {
+	enum.i++
+	enum.pos = (enum.pos + enum.inc) % enum.count
+}
+
+func (enum *randomEnum) position() uint32 {
+	return enum.pos
+}
+
+func gcd(a, b uint32) uint32 {
+	for b != 0 {
+		a, b = b, a%b
+	}
+	return a
+}
diff --git a/src/runtime/proc_runtime_test.go b/src/runtime/proc_runtime_test.go
new file mode 100644
index 0000000..a7bde2c
--- /dev/null
+++ b/src/runtime/proc_runtime_test.go
@@ -0,0 +1,33 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Proc unit tests. In runtime package so can use runtime guts.
+
+package runtime
+
+func RunStealOrderTest() {
+	var ord randomOrder
+	for procs := 1; procs <= 64; procs++ {
+		ord.reset(uint32(procs))
+		if procs >= 3 && len(ord.coprimes) < 2 {
+			panic("too few coprimes")
+		}
+		for co := 0; co < len(ord.coprimes); co++ {
+			enum := ord.start(uint32(co))
+			checked := make([]bool, procs)
+			for p := 0; p < procs; p++ {
+				x := enum.position()
+				if checked[x] {
+					println("procs:", procs, "inc:", enum.inc)
+					panic("duplicate during enumeration")
+				}
+				checked[x] = true
+				enum.next()
+			}
+			if !enum.done() {
+				panic("not done")
+			}
+		}
+	}
+}
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index 9e5960b..22e4dca 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -178,7 +178,14 @@ func testGoroutineParallelism2(t *testing.T, load, netpoll bool) {
 		}
 		if netpoll {
 			// Enable netpoller, affects schedler behavior.
-			ln, err := net.Listen("tcp", "localhost:0")
+			laddr := "localhost:0"
+			if runtime.GOOS == "android" {
+				// On some Android devices, there are no records for localhost,
+				// see https://golang.org/issues/14486.
+				// Don't use 127.0.0.1 for every case, it won't work on IPv6-only systems.
+				laddr = "127.0.0.1:0"
+			}
+			ln, err := net.Listen("tcp", laddr)
 			if err != nil {
 				defer ln.Close() // yup, defer in a loop
 			}
@@ -337,6 +344,14 @@ func TestGCFairness(t *testing.T) {
 	}
 }
 
+func TestGCFairness2(t *testing.T) {
+	output := runTestProg(t, "testprog", "GCFairness2")
+	want := "OK\n"
+	if output != want {
+		t.Fatalf("want %s, got %s\n", want, output)
+	}
+}
+
 func TestNumGoroutine(t *testing.T) {
 	output := runTestProg(t, "testprog", "NumGoroutine")
 	want := "1\n"
@@ -421,6 +436,9 @@ func TestPingPongHog(t *testing.T) {
 }
 
 func BenchmarkPingPongHog(b *testing.B) {
+	if b.N == 0 {
+		return
+	}
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
 
 	// Create a CPU hog
@@ -543,6 +561,24 @@ func TestSchedLocalQueueSteal(t *testing.T) {
 	runtime.RunSchedLocalQueueStealTest()
 }
 
+func TestSchedLocalQueueEmpty(t *testing.T) {
+	if runtime.NumCPU() == 1 {
+		// Takes too long and does not trigger the race.
+		t.Skip("skipping on uniprocessor")
+	}
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+
+	// If runtime triggers a forced GC during this test then it will deadlock,
+	// since the goroutines can't be stopped/preempted during spin wait.
+	defer debug.SetGCPercent(debug.SetGCPercent(-1))
+
+	iters := int(1e5)
+	if testing.Short() {
+		iters = 1e2
+	}
+	runtime.RunSchedLocalQueueEmptyTest(iters)
+}
+
 func benchmarkStackGrowth(b *testing.B, rec int) {
 	b.RunParallel(func(pb *testing.PB) {
 		for pb.Next() {
@@ -679,3 +715,7 @@ func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, thres
 		done <- struct{}{}
 	}
 }
+
+func TestStealOrder(t *testing.T) {
+	runtime.RunStealOrderTest()
+}
diff --git a/src/runtime/race.go b/src/runtime/race.go
index 6ee1475..42da936 100644
--- a/src/runtime/race.go
+++ b/src/runtime/race.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -58,7 +58,7 @@ func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)
 //go:noescape
 func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)
 
-type symbolizeContext struct {
+type symbolizeCodeContext struct {
 	pc   uintptr
 	fn   *byte
 	file *byte
@@ -70,8 +70,27 @@ type symbolizeContext struct {
 var qq = [...]byte{'?', '?', 0}
 var dash = [...]byte{'-', 0}
 
+const (
+	raceGetProcCmd = iota
+	raceSymbolizeCodeCmd
+	raceSymbolizeDataCmd
+)
+
 // Callback from C into Go, runs on g0.
-func racesymbolize(ctx *symbolizeContext) {
+func racecallback(cmd uintptr, ctx unsafe.Pointer) {
+	switch cmd {
+	case raceGetProcCmd:
+		throw("should have been handled by racecallbackthunk")
+	case raceSymbolizeCodeCmd:
+		raceSymbolizeCode((*symbolizeCodeContext)(ctx))
+	case raceSymbolizeDataCmd:
+		raceSymbolizeData((*symbolizeDataContext)(ctx))
+	default:
+		throw("unknown command")
+	}
+}
+
+func raceSymbolizeCode(ctx *symbolizeCodeContext) {
 	f := findfunc(ctx.pc)
 	if f == nil {
 		ctx.fn = &qq[0]
@@ -91,6 +110,26 @@ func racesymbolize(ctx *symbolizeContext) {
 	return
 }
 
+type symbolizeDataContext struct {
+	addr  uintptr
+	heap  uintptr
+	start uintptr
+	size  uintptr
+	name  *byte
+	file  *byte
+	line  uintptr
+	res   uintptr
+}
+
+func raceSymbolizeData(ctx *symbolizeDataContext) {
+	if _, x, n := findObject(unsafe.Pointer(ctx.addr)); x != nil {
+		ctx.heap = 1
+		ctx.start = uintptr(x)
+		ctx.size = n
+		ctx.res = 1
+	}
+}
+
 // Race runtime functions called via runtime·racecall.
 //go:linkname __tsan_init __tsan_init
 var __tsan_init byte
@@ -98,6 +137,12 @@ var __tsan_init byte
 //go:linkname __tsan_fini __tsan_fini
 var __tsan_fini byte
 
+//go:linkname __tsan_proc_create __tsan_proc_create
+var __tsan_proc_create byte
+
+//go:linkname __tsan_proc_destroy __tsan_proc_destroy
+var __tsan_proc_destroy byte
+
 //go:linkname __tsan_map_shadow __tsan_map_shadow
 var __tsan_map_shadow byte
 
@@ -113,6 +158,9 @@ var __tsan_go_end byte
 //go:linkname __tsan_malloc __tsan_malloc
 var __tsan_malloc byte
 
+//go:linkname __tsan_free __tsan_free
+var __tsan_free byte
+
 //go:linkname __tsan_acquire __tsan_acquire
 var __tsan_acquire byte
 
@@ -131,11 +179,14 @@ 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_proc_create
+//go:cgo_import_static __tsan_proc_destroy
 //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_free
 //go:cgo_import_static __tsan_acquire
 //go:cgo_import_static __tsan_release
 //go:cgo_import_static __tsan_release_merge
@@ -175,7 +226,7 @@ func racefuncenter(uintptr)
 func racefuncexit()
 func racereadrangepc1(uintptr, uintptr, uintptr)
 func racewriterangepc1(uintptr, uintptr, uintptr)
-func racesymbolizethunk(uintptr)
+func racecallbackthunk(uintptr)
 
 // racecall allows calling an arbitrary function f from C race runtime
 // with up to 4 uintptr arguments.
@@ -189,14 +240,13 @@ func isvalidaddr(addr unsafe.Pointer) bool {
 }
 
 //go:nosplit
-func raceinit() uintptr {
+func raceinit() (gctx, pctx 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)
+	racecall(&__tsan_init, uintptr(unsafe.Pointer(&gctx)), uintptr(unsafe.Pointer(&pctx)), funcPC(racecallbackthunk), 0)
 
 	// Round data segment to page boundaries, because it's used in mmap().
 	start := ^uintptr(0)
@@ -230,15 +280,35 @@ func raceinit() uintptr {
 	racedatastart = start
 	racedataend = start + size
 
-	return racectx
+	return
 }
 
+var raceFiniLock mutex
+
 //go:nosplit
 func racefini() {
+	// racefini() can only be called once to avoid races.
+	// This eventually (via __tsan_fini) calls C.exit which has
+	// undefined behavior if called more than once. If the lock is
+	// already held it's assumed that the first caller exits the program
+	// so other calls can hang forever without an issue.
+	lock(&raceFiniLock)
 	racecall(&__tsan_fini, 0, 0, 0, 0)
 }
 
 //go:nosplit
+func raceproccreate() uintptr {
+	var ctx uintptr
+	racecall(&__tsan_proc_create, uintptr(unsafe.Pointer(&ctx)), 0, 0, 0)
+	return ctx
+}
+
+//go:nosplit
+func raceprocdestroy(ctx uintptr) {
+	racecall(&__tsan_proc_destroy, ctx, 0, 0, 0)
+}
+
+//go:nosplit
 func racemapshadow(addr unsafe.Pointer, size uintptr) {
 	if racearenastart == 0 {
 		racearenastart = uintptr(addr)
@@ -251,7 +321,12 @@ func racemapshadow(addr unsafe.Pointer, size uintptr) {
 
 //go:nosplit
 func racemalloc(p unsafe.Pointer, sz uintptr) {
-	racecall(&__tsan_malloc, uintptr(p), sz, 0, 0)
+	racecall(&__tsan_malloc, 0, 0, uintptr(p), sz)
+}
+
+//go:nosplit
+func racefree(p unsafe.Pointer, sz uintptr) {
+	racecall(&__tsan_free, uintptr(p), sz, 0, 0)
 }
 
 //go:nosplit
@@ -323,11 +398,7 @@ func raceacquireg(gp *g, addr unsafe.Pointer) {
 
 //go:nosplit
 func racerelease(addr unsafe.Pointer) {
-	_g_ := getg()
-	if _g_.raceignore != 0 || !isvalidaddr(addr) {
-		return
-	}
-	racereleaseg(_g_, addr)
+	racereleaseg(getg(), addr)
 }
 
 //go:nosplit
diff --git a/src/runtime/race/README b/src/runtime/race/README
index 1831699..3a506b0 100644
--- a/src/runtime/race/README
+++ b/src/runtime/race/README
@@ -4,4 +4,4 @@ the LLVM project (http://llvm.org/git/compiler-rt.git).
 
 To update the .syso files use golang.org/x/build/cmd/racebuild.
 
-Current runtime is built on rev 389d49d4943780efbfcd2a434f4462b6d0f23c44.
+Current runtime is built on rev 9d79ea3416bfbe3acac50e47802ee9621bf53254.
diff --git a/src/runtime/race/output_test.go b/src/runtime/race/output_test.go
index 0c71a01..5157f7e 100644
--- a/src/runtime/race/output_test.go
+++ b/src/runtime/race/output_test.go
@@ -93,13 +93,13 @@ func racer(x *int, done chan bool) {
 }
 `, `==================
 WARNING: DATA RACE
-Write by goroutine [0-9]:
+Write at 0x[0-9,a-f]+ by goroutine [0-9]:
   main\.store\(\)
       .+/main\.go:12 \+0x[0-9,a-f]+
   main\.racer\(\)
       .+/main\.go:19 \+0x[0-9,a-f]+
 
-Previous write by main goroutine:
+Previous write at 0x[0-9,a-f]+ by main goroutine:
   main\.store\(\)
       .+/main\.go:12 \+0x[0-9,a-f]+
   main\.main\(\)
@@ -180,4 +180,21 @@ func TestFail(t *testing.T) {
 PASS
 Found 1 data race\(s\)
 FAIL`},
+
+	{"slicebytetostring_pc", "run", "atexit_sleep_ms=0", `
+package main
+func main() {
+	done := make(chan string)
+	data := make([]byte, 10)
+	go func() {
+		done <- string(data)
+	}()
+	data[0] = 1
+	<-done
+}
+`, `
+  runtime\.slicebytetostring\(\)
+      .*/runtime/string\.go:.*
+  main\.main\.func1\(\)
+      .*/main.go:7`},
 }
diff --git a/src/runtime/race/race_darwin_amd64.syso b/src/runtime/race/race_darwin_amd64.syso
index 745d970..1822486 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 074b676..75d9495 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 042ca59..8f571af 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_linux_test.go b/src/runtime/race/race_linux_test.go
new file mode 100644
index 0000000..c00ce4d
--- /dev/null
+++ b/src/runtime/race/race_linux_test.go
@@ -0,0 +1,37 @@
+// Copyright 2016 The Go 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,race
+
+package race_test
+
+import (
+	"sync/atomic"
+	"syscall"
+	"testing"
+	"unsafe"
+)
+
+func TestAtomicMmap(t *testing.T) {
+	// Test that atomic operations work on "external" memory. Previously they crashed (#16206).
+	// Also do a sanity correctness check: under race detector atomic operations
+	// are implemented inside of race runtime.
+	mem, err := syscall.Mmap(-1, 0, 1<<20, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+	if err != nil {
+		t.Fatalf("mmap failed: %v", err)
+	}
+	defer syscall.Munmap(mem)
+	a := (*uint64)(unsafe.Pointer(&mem[0]))
+	if *a != 0 {
+		t.Fatalf("bad atomic value: %v, want 0", *a)
+	}
+	atomic.AddUint64(a, 1)
+	if *a != 1 {
+		t.Fatalf("bad atomic value: %v, want 1", *a)
+	}
+	atomic.AddUint64(a, 1)
+	if *a != 2 {
+		t.Fatalf("bad atomic value: %v, want 2", *a)
+	}
+}
diff --git a/src/runtime/race/race_test.go b/src/runtime/race/race_test.go
index 748f338..81e51cc 100644
--- a/src/runtime/race/race_test.go
+++ b/src/runtime/race/race_test.go
@@ -17,10 +17,13 @@ import (
 	"fmt"
 	"io"
 	"log"
+	"math/rand"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"strings"
+	"sync"
+	"sync/atomic"
 	"testing"
 )
 
@@ -195,3 +198,26 @@ func TestIssue9137(t *testing.T) {
 		t.Errorf("mangled a: %q %q", a, a[:1])
 	}
 }
+
+func BenchmarkSyncLeak(b *testing.B) {
+	const (
+		G = 1000
+		S = 1000
+		H = 10
+	)
+	var wg sync.WaitGroup
+	wg.Add(G)
+	for g := 0; g < G; g++ {
+		go func() {
+			defer wg.Done()
+			hold := make([][]uint32, H)
+			for i := 0; i < b.N; i++ {
+				a := make([]uint32, S)
+				atomic.AddUint32(&a[rand.Intn(len(a))], 1)
+				hold[rand.Intn(len(hold))] = a
+			}
+			_ = hold
+		}()
+	}
+	wg.Wait()
+}
diff --git a/src/runtime/race/race_windows_amd64.syso b/src/runtime/race/race_windows_amd64.syso
index cb4446b..64c54b6 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/race_windows_test.go b/src/runtime/race/race_windows_test.go
new file mode 100644
index 0000000..307a1ea
--- /dev/null
+++ b/src/runtime/race/race_windows_test.go
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go 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,race
+
+package race_test
+
+import (
+	"sync/atomic"
+	"syscall"
+	"testing"
+	"unsafe"
+)
+
+func TestAtomicMmap(t *testing.T) {
+	// Test that atomic operations work on "external" memory. Previously they crashed (#16206).
+	// Also do a sanity correctness check: under race detector atomic operations
+	// are implemented inside of race runtime.
+	kernel32 := syscall.NewLazyDLL("kernel32.dll")
+	VirtualAlloc := kernel32.NewProc("VirtualAlloc")
+	VirtualFree := kernel32.NewProc("VirtualFree")
+	const (
+		MEM_COMMIT     = 0x00001000
+		MEM_RESERVE    = 0x00002000
+		MEM_RELEASE    = 0x8000
+		PAGE_READWRITE = 0x04
+	)
+	mem, _, err := syscall.Syscall6(VirtualAlloc.Addr(), 4, 0, 1<<20, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE, 0, 0)
+	if err != 0 {
+		t.Fatalf("VirtualAlloc failed: %v", err)
+	}
+	defer syscall.Syscall(VirtualFree.Addr(), 3, mem, 1<<20, MEM_RELEASE)
+	a := (*uint64)(unsafe.Pointer(mem))
+	if *a != 0 {
+		t.Fatalf("bad atomic value: %v, want 0", *a)
+	}
+	atomic.AddUint64(a, 1)
+	if *a != 1 {
+		t.Fatalf("bad atomic value: %v, want 1", *a)
+	}
+	atomic.AddUint64(a, 1)
+	if *a != 2 {
+		t.Fatalf("bad atomic value: %v, want 2", *a)
+	}
+}
diff --git a/src/runtime/race/sched_test.go b/src/runtime/race/sched_test.go
index aac8fed..d6bb323 100644
--- a/src/runtime/race/sched_test.go
+++ b/src/runtime/race/sched_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/race/testdata/chan_test.go b/src/runtime/race/testdata/chan_test.go
index cddd9a6..4491916 100644
--- a/src/runtime/race/testdata/chan_test.go
+++ b/src/runtime/race/testdata/chan_test.go
@@ -285,17 +285,20 @@ func TestRaceChanWrongClose(t *testing.T) {
 	v1 := 0
 	v2 := 0
 	c := make(chan int, 1)
+	done := make(chan bool)
 	go func() {
 		defer func() {
 			recover()
 		}()
 		v1 = 1
 		c <- 1
+		done <- true
 	}()
 	go func() {
 		time.Sleep(1e7)
 		v2 = 2
 		close(c)
+		done <- true
 	}()
 	time.Sleep(2e7)
 	if _, who := <-c; who {
@@ -303,6 +306,8 @@ func TestRaceChanWrongClose(t *testing.T) {
 	} else {
 		v1 = 2
 	}
+	<-done
+	<-done
 }
 
 func TestRaceChanSendClose(t *testing.T) {
diff --git a/src/runtime/race/testdata/io_test.go b/src/runtime/race/testdata/io_test.go
index 1b3ee38..30a121b 100644
--- a/src/runtime/race/testdata/io_test.go
+++ b/src/runtime/race/testdata/io_test.go
@@ -7,9 +7,11 @@ package race_test
 import (
 	"fmt"
 	"io/ioutil"
+	"net"
 	"net/http"
 	"os"
 	"path/filepath"
+	"sync"
 	"testing"
 	"time"
 )
@@ -41,29 +43,34 @@ func TestNoRaceIOFile(t *testing.T) {
 	_ = x
 }
 
+var (
+	regHandler  sync.Once
+	handlerData int
+)
+
 func TestNoRaceIOHttp(t *testing.T) {
-	x := 0
-	go func() {
+	regHandler.Do(func() {
 		http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
-			x = 41
+			handlerData++
 			fmt.Fprintf(w, "test")
-			x = 42
+			handlerData++
 		})
-		err := http.ListenAndServe("127.0.0.1:23651", nil)
-		if err != nil {
-			t.Fatalf("http.ListenAndServe: %v", err)
-		}
-	}()
-	time.Sleep(1e7)
-	x = 1
-	_, err := http.Get("http://127.0.0.1:23651")
+	})
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("net.Listen: %v", err)
+	}
+	defer ln.Close()
+	go http.Serve(ln, nil)
+	handlerData++
+	_, err = http.Get("http://" + ln.Addr().String())
 	if err != nil {
 		t.Fatalf("http.Get: %v", err)
 	}
-	x = 2
-	_, err = http.Get("http://127.0.0.1:23651")
+	handlerData++
+	_, err = http.Get("http://" + ln.Addr().String())
 	if err != nil {
 		t.Fatalf("http.Get: %v", err)
 	}
-	x = 3
+	handlerData++
 }
diff --git a/src/runtime/race0.go b/src/runtime/race0.go
index 591d5d9..f1d3706 100644
--- a/src/runtime/race0.go
+++ b/src/runtime/race0.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -18,8 +18,10 @@ const raceenabled = false
 
 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 raceinit() (uintptr, uintptr)                                          { throw("race"); return 0, 0 }
 func racefini()                                                             { throw("race") }
+func raceproccreate() uintptr                                               { throw("race"); return 0 }
+func raceprocdestroy(ctx uintptr)                                           { 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") }
@@ -33,5 +35,6 @@ func racereleasemerge(addr unsafe.Pointer)                                  { th
 func racereleasemergeg(gp *g, addr unsafe.Pointer)                          { throw("race") }
 func racefingo()                                                            { throw("race") }
 func racemalloc(p unsafe.Pointer, sz uintptr)                               { throw("race") }
+func racefree(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/race_amd64.s b/src/runtime/race_amd64.s
index d9e674b..cc1d92f 100644
--- a/src/runtime/race_amd64.s
+++ b/src/runtime/race_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -159,14 +159,28 @@ call:
 ret:
 	RET
 
+// func runtime·racefuncenterfp(fp uintptr)
+// Called from instrumented code.
+// Like racefuncenter but passes FP, not PC
+TEXT	runtime·racefuncenterfp(SB), NOSPLIT, $0-8
+	MOVQ	fp+0(FP), R11
+	MOVQ	-8(R11), R11
+	JMP	racefuncenter<>(SB)
+
 // func runtime·racefuncenter(pc uintptr)
 // Called from instrumented code.
 TEXT	runtime·racefuncenter(SB), NOSPLIT, $0-8
+	MOVQ	callpc+0(FP), R11
+	JMP	racefuncenter<>(SB)
+
+// Common code for racefuncenter/racefuncenterfp
+// R11 = caller's return address
+TEXT	racefuncenter<>(SB), NOSPLIT, $0-0
 	MOVQ	DX, R15		// save function entry context (for closures)
 	get_tls(R12)
 	MOVQ	g(R12), R14
 	MOVQ	g_racectx(R14), RARG0	// goroutine context
-	MOVQ	callpc+0(FP), RARG1
+	MOVQ	R11, RARG1
 	// void __tsan_func_enter(ThreadState *thr, void *pc);
 	MOVQ	$__tsan_func_enter(SB), AX
 	// racecall<> preserves R15
@@ -324,6 +338,7 @@ racecallatomic_ignore:
 	// An attempt to synchronize on the address would cause crash.
 	MOVQ	AX, R15	// remember the original function
 	MOVQ	$__tsan_go_ignore_sync_begin(SB), AX
+	get_tls(R12)
 	MOVQ	g(R12), R14
 	MOVQ	g_racectx(R14), RARG0	// goroutine context
 	CALL	racecall<>(SB)
@@ -370,7 +385,24 @@ call:
 // C->Go callback thunk that allows to call runtime·racesymbolize from C code.
 // Direct Go->C race call has only switched SP, finish g->g0 switch by setting correct g.
 // The overall effect of Go->C->Go call chain is similar to that of mcall.
-TEXT	runtime·racesymbolizethunk(SB), NOSPLIT, $56-8
+// RARG0 contains command code. RARG1 contains command-specific context.
+// See racecallback for command codes.
+TEXT	runtime·racecallbackthunk(SB), NOSPLIT, $56-8
+	// Handle command raceGetProcCmd (0) here.
+	// First, code below assumes that we are on curg, while raceGetProcCmd
+	// can be executed on g0. Second, it is called frequently, so will
+	// benefit from this fast path.
+	CMPQ	RARG0, $0
+	JNE	rest
+	get_tls(RARG0)
+	MOVQ	g(RARG0), RARG0
+	MOVQ	g_m(RARG0), RARG0
+	MOVQ	m_p(RARG0), RARG0
+	MOVQ	p_racectx(RARG0), RARG0
+	MOVQ	RARG0, (RARG1)
+	RET
+
+rest:
 	// Save callee-saved registers (Go code won't respect that).
 	// This is superset of darwin/linux/windows registers.
 	PUSHQ	BX
@@ -387,8 +419,10 @@ TEXT	runtime·racesymbolizethunk(SB), NOSPLIT, $56-8
 	MOVQ	g_m(R13), R13
 	MOVQ	m_g0(R13), R14
 	MOVQ	R14, g(R12)	// g = m->g0
+	PUSHQ	RARG1	// func arg
 	PUSHQ	RARG0	// func arg
-	CALL	runtime·racesymbolize(SB)
+	CALL	runtime·racecallback(SB)
+	POPQ	R12
 	POPQ	R12
 	// All registers are smashed after Go code, reload.
 	get_tls(R12)
diff --git a/src/runtime/rdebug.go b/src/runtime/rdebug.go
index ad7b976..1b213f1 100644
--- a/src/runtime/rdebug.go
+++ b/src/runtime/rdebug.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -15,9 +15,8 @@ func setMaxStack(in int) (out int) {
 
 //go:linkname setPanicOnFault runtime/debug.setPanicOnFault
 func setPanicOnFault(new bool) (old bool) {
-	mp := acquirem()
-	old = mp.curg.paniconfault
-	mp.curg.paniconfault = new
-	releasem(mp)
+	_g_ := getg()
+	old = _g_.paniconfault
+	_g_.paniconfault = new
 	return old
 }
diff --git a/src/runtime/rt0_darwin_amd64.s b/src/runtime/rt0_darwin_amd64.s
index ad46fd4..655e77a 100644
--- a/src/runtime/rt0_darwin_amd64.s
+++ b/src/runtime/rt0_darwin_amd64.s
@@ -12,7 +12,14 @@ TEXT _rt0_amd64_darwin(SB),NOSPLIT,$-8
 
 // When linking with -shared, this symbol is called when the shared library
 // is loaded.
-TEXT _rt0_amd64_darwin_lib(SB),NOSPLIT,$0x48
+TEXT _rt0_amd64_darwin_lib(SB),NOSPLIT,$0x58
+	// Align stack. We don't know whether Go is adding a frame pointer here or not.
+	MOVQ	SP, R8
+	SUBQ	$16, R8
+	ANDQ	$~15, R8
+	XCHGQ	SP, R8
+
+	MOVQ	R8, 0x48(SP)
 	MOVQ	BX, 0x18(SP)
 	MOVQ	BP, 0x20(SP)
 	MOVQ	R12, 0x28(SP)
@@ -51,6 +58,9 @@ restore:
 	MOVQ	0x30(SP), R13
 	MOVQ	0x38(SP), R14
 	MOVQ	0x40(SP), R15
+	
+	MOVQ	0x48(SP), R8
+	MOVQ	R8, SP
 	RET
 
 TEXT _rt0_amd64_darwin_lib_go(SB),NOSPLIT,$0
diff --git a/src/runtime/rt0_darwin_arm.s b/src/runtime/rt0_darwin_arm.s
index 59733d3..526d88f 100644
--- a/src/runtime/rt0_darwin_arm.s
+++ b/src/runtime/rt0_darwin_arm.s
@@ -16,7 +16,7 @@ TEXT _rt0_arm_darwin(SB),7,$-4
 //
 // Note that all currently shipping darwin/arm platforms require
 // cgo and do not support c-shared.
-TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$32
+TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$104
 	// Preserve callee-save registers.
 	MOVW    R4, 12(R13)
 	MOVW    R5, 16(R13)
@@ -25,6 +25,15 @@ TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$32
 	MOVW    R8, 28(R13)
 	MOVW    R11, 32(R13)
 
+	MOVD	F8, (32+8*1)(R13)
+	MOVD	F9, (32+8*2)(R13)
+	MOVD	F10, (32+8*3)(R13)
+	MOVD	F11, (32+8*4)(R13)
+	MOVD	F12, (32+8*5)(R13)
+	MOVD	F13, (32+8*6)(R13)
+	MOVD	F14, (32+8*7)(R13)
+	MOVD	F15, (32+8*8)(R13)
+
 	MOVW  R0, _rt0_arm_darwin_lib_argc<>(SB)
 	MOVW  R1, _rt0_arm_darwin_lib_argv<>(SB)
 
@@ -57,6 +66,14 @@ rr:
 	MOVW    24(R13), R7
 	MOVW    28(R13), R8
 	MOVW    32(R13), R11
+	MOVD	(32+8*1)(R13), F8
+	MOVD	(32+8*2)(R13), F9
+	MOVD	(32+8*3)(R13), F10
+	MOVD	(32+8*4)(R13), F11
+	MOVD	(32+8*5)(R13), F12
+	MOVD	(32+8*6)(R13), F13
+	MOVD	(32+8*7)(R13), F14
+	MOVD	(32+8*8)(R13), F15
 	RET
 
 
diff --git a/src/runtime/rt0_darwin_arm64.s b/src/runtime/rt0_darwin_arm64.s
index 0a1feb1..f607683 100644
--- a/src/runtime/rt0_darwin_arm64.s
+++ b/src/runtime/rt0_darwin_arm64.s
@@ -16,7 +16,7 @@ TEXT _rt0_arm64_darwin(SB),NOSPLIT,$-8
 //
 // Note that all currently shipping darwin/arm64 platforms require
 // cgo and do not support c-shared.
-TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$88
+TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$168
 	// Preserve callee-save registers.
 	MOVD R19, 24(RSP)
 	MOVD R20, 32(RSP)
@@ -27,6 +27,14 @@ TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$88
 	MOVD R25, 72(RSP)
 	MOVD R26, 80(RSP)
 	MOVD R27, 88(RSP)
+	FMOVD F8, 96(RSP)
+	FMOVD F9, 104(RSP)
+	FMOVD F10, 112(RSP)
+	FMOVD F11, 120(RSP)
+	FMOVD F12, 128(RSP)
+	FMOVD F13, 136(RSP)
+	FMOVD F14, 144(RSP)
+	FMOVD F15, 152(RSP)
 
 	MOVD  R0, _rt0_arm64_darwin_lib_argc<>(SB)
 	MOVD  R1, _rt0_arm64_darwin_lib_argv<>(SB)
@@ -51,6 +59,14 @@ TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$88
 	MOVD 72(RSP), R25
 	MOVD 80(RSP), R26
 	MOVD 88(RSP), R27
+	FMOVD 96(RSP), F8
+	FMOVD 104(RSP), F9
+	FMOVD 112(RSP), F10
+	FMOVD 120(RSP), F11
+	FMOVD 128(RSP), F12
+	FMOVD 136(RSP), F13
+	FMOVD 144(RSP), F14
+	FMOVD 152(RSP), F15
 	RET
 
 TEXT _rt0_arm64_darwin_lib_go(SB),NOSPLIT,$0
diff --git a/src/runtime/rt0_linux_arm.s b/src/runtime/rt0_linux_arm.s
index d28c15a..597e642 100644
--- a/src/runtime/rt0_linux_arm.s
+++ b/src/runtime/rt0_linux_arm.s
@@ -12,8 +12,8 @@ TEXT _rt0_arm_linux(SB),NOSPLIT,$-4
 
 // 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,
+TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$104
+	// Preserve callee-save registers. Raspberry Pi's dlopen(), for example,
 	// actually cares that R11 is preserved.
 	MOVW	R4, 12(R13)
 	MOVW	R5, 16(R13)
@@ -22,6 +22,19 @@ TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$32
 	MOVW	R8, 28(R13)
 	MOVW	R11, 32(R13)
 
+	// Skip floating point registers on GOARM < 6.
+	MOVB    runtime·goarm(SB), R11
+	CMP $6, R11
+	BLT skipfpsave
+	MOVD	F8, (32+8*1)(R13)
+	MOVD	F9, (32+8*2)(R13)
+	MOVD	F10, (32+8*3)(R13)
+	MOVD	F11, (32+8*4)(R13)
+	MOVD	F12, (32+8*5)(R13)
+	MOVD	F13, (32+8*6)(R13)
+	MOVD	F14, (32+8*7)(R13)
+	MOVD	F15, (32+8*8)(R13)
+skipfpsave:
 	// Save argc/argv.
 	MOVW	R0, _rt0_arm_linux_lib_argc<>(SB)
 	MOVW	R1, _rt0_arm_linux_lib_argv<>(SB)
@@ -46,6 +59,18 @@ nocgo:
 	BL	runtime·newosproc0(SB)
 rr:
 	// Restore callee-save registers and return.
+	MOVB    runtime·goarm(SB), R11
+	CMP $6, R11
+	BLT skipfprest
+	MOVD	(32+8*1)(R13), F8
+	MOVD	(32+8*2)(R13), F9
+	MOVD	(32+8*3)(R13), F10
+	MOVD	(32+8*4)(R13), F11
+	MOVD	(32+8*5)(R13), F12
+	MOVD	(32+8*6)(R13), F13
+	MOVD	(32+8*7)(R13), F14
+	MOVD	(32+8*8)(R13), F15
+skipfprest:
 	MOVW	12(R13), R4
 	MOVW	16(R13), R5
 	MOVW	20(R13), R6
diff --git a/src/runtime/rt0_linux_arm64.s b/src/runtime/rt0_linux_arm64.s
index 31c2367..d01d415 100644
--- a/src/runtime/rt0_linux_arm64.s
+++ b/src/runtime/rt0_linux_arm64.s
@@ -11,7 +11,7 @@ TEXT _rt0_arm64_linux(SB),NOSPLIT,$-8
 
 // When building with -buildmode=c-shared, this symbol is called when the shared
 // library is loaded.
-TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$88
+TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$168
 	// Preserve callee-save registers.
 	MOVD R19, 24(RSP)
 	MOVD R20, 32(RSP)
@@ -22,6 +22,14 @@ TEXT _rt0_arm64_linux_lib(SB),NOSPLIT,$88
 	MOVD R25, 72(RSP)
 	MOVD R26, 80(RSP)
 	MOVD R27, 88(RSP)
+	FMOVD F8, 96(RSP)
+	FMOVD F9, 104(RSP)
+	FMOVD F10, 112(RSP)
+	FMOVD F11, 120(RSP)
+	FMOVD F12, 128(RSP)
+	FMOVD F13, 136(RSP)
+	FMOVD F14, 144(RSP)
+	FMOVD F15, 152(RSP)
 
 	MOVD	R0, _rt0_arm64_linux_lib_argc<>(SB)
 	MOVD	R1, _rt0_arm64_linux_lib_argv<>(SB)
@@ -58,6 +66,14 @@ restore:
 	MOVD 72(RSP), R25
 	MOVD 80(RSP), R26
 	MOVD 88(RSP), R27
+	FMOVD 96(RSP), F8
+	FMOVD 104(RSP), F9
+	FMOVD 112(RSP), F10
+	FMOVD 120(RSP), F11
+	FMOVD 128(RSP), F12
+	FMOVD 136(RSP), F13
+	FMOVD 144(RSP), F14
+	FMOVD 152(RSP), F15
 	RET
 
 TEXT _rt0_arm64_linux_lib_go(SB),NOSPLIT,$0
diff --git a/src/runtime/rt0_linux_mips64x.s b/src/runtime/rt0_linux_mips64x.s
index c7e35f5..beb4ef2 100644
--- a/src/runtime/rt0_linux_mips64x.s
+++ b/src/runtime/rt0_linux_mips64x.s
@@ -19,13 +19,21 @@ TEXT _main<>(SB),NOSPLIT,$-8
 	// sequence of string pointers followed by a NULL, and auxv.
 	// There is no TLS base pointer.
 #ifdef GOARCH_mips64
-	MOVW 4(R29), R1 // argc, big-endian ABI places int32 at offset 4
+	MOVW	4(R29), R4 // argc, big-endian ABI places int32 at offset 4
 #else
-	MOVW 0(R29), R1 // argc
+	MOVW	0(R29), R4 // argc
 #endif
-	ADDV $8, R29, R2 // argv
-	JMP main(SB)
+	ADDV	$8, R29, R5 // argv
+	JMP	main(SB)
 
 TEXT main(SB),NOSPLIT,$-8
-	MOVV	$runtime·rt0_go(SB), R4
-	JMP	(R4)
+	// in external linking, glibc jumps to main with argc in R4
+	// and argv in R5
+
+	// initalize REGSB = PC&0xffffffff00000000
+	BGEZAL	R0, 1(PC)
+	SRLV	$32, R31, RSB
+	SLLV	$32, RSB
+
+	MOVV	$runtime·rt0_go(SB), R1
+	JMP	(R1)
diff --git a/src/runtime/rt0_linux_ppc64le.s b/src/runtime/rt0_linux_ppc64le.s
index ac7b922..2c55413 100644
--- a/src/runtime/rt0_linux_ppc64le.s
+++ b/src/runtime/rt0_linux_ppc64le.s
@@ -4,6 +4,135 @@
 TEXT _rt0_ppc64le_linux(SB),NOSPLIT,$0
 	BR _main<>(SB)
 
+TEXT _rt0_ppc64le_linux_lib(SB),NOSPLIT,$-8
+	// 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.
+	MOVDU	R1, -320(R1) // Allocate frame.
+	
+	// Preserve callee-save registers.
+	MOVD	R14, 24(R1)
+	MOVD	R15, 32(R1)
+	MOVD	R16, 40(R1)
+	MOVD	R17, 48(R1)
+	MOVD	R18, 56(R1)
+	MOVD	R19, 64(R1)
+	MOVD	R20, 72(R1)
+	MOVD	R21, 80(R1)
+	MOVD	R22, 88(R1)
+	MOVD	R23, 96(R1)
+	MOVD	R24, 104(R1)
+	MOVD	R25, 112(R1)
+	MOVD	R26, 120(R1)
+	MOVD	R27, 128(R1)
+	MOVD	R28, 136(R1)
+	MOVD	R29, 144(R1)
+	MOVD	g, 152(R1) // R30
+	MOVD	R31, 160(R1)
+	FMOVD	F14, 168(R1)
+	FMOVD	F15, 176(R1)
+	FMOVD	F16, 184(R1)
+	FMOVD	F17, 192(R1)
+	FMOVD	F18, 200(R1)
+	FMOVD	F19, 208(R1)
+	FMOVD	F20, 216(R1)
+	FMOVD	F21, 224(R1)
+	FMOVD	F22, 232(R1)
+	FMOVD	F23, 240(R1)
+	FMOVD	F24, 248(R1)
+	FMOVD	F25, 256(R1)
+	FMOVD	F26, 264(R1)
+	FMOVD	F27, 272(R1)
+	FMOVD	F28, 280(R1)
+	FMOVD	F29, 288(R1)
+	FMOVD	F30, 296(R1)
+	FMOVD	F31, 304(R1)
+
+	MOVD	R3, _rt0_ppc64le_linux_lib_argc<>(SB)
+	MOVD	R4, _rt0_ppc64le_linux_lib_argv<>(SB)
+
+	// Synchronous initialization.
+	MOVD	$runtime·libpreinit(SB), R12
+	MOVD	R12, CTR
+	BL	(CTR)
+
+	// Create a new thread to do the runtime initialization and return.
+	MOVD	_cgo_sys_thread_create(SB), R12
+	CMP	$0, R12
+	BEQ	nocgo
+	MOVD	$_rt0_ppc64le_linux_lib_go(SB), R3
+	MOVD	$0, R4
+	MOVD	R12, CTR
+	BL	(CTR)
+	BR	done
+
+nocgo:
+	MOVD	$0x800000, R12                     // stacksize = 8192KB
+	MOVD	R12, 8(R1)
+	MOVD	$_rt0_ppc64le_linux_lib_go(SB), R12
+	MOVD	R12, 16(R1)
+	MOVD	$runtime·newosproc0(SB),R12
+	MOVD	R12, CTR
+	BL	(CTR)
+
+done:
+	// Restore saved registers.
+	MOVD	24(R1), R14
+	MOVD	32(R1), R15
+	MOVD	40(R1), R16
+	MOVD	48(R1), R17
+	MOVD	56(R1), R18
+	MOVD	64(R1), R19
+	MOVD	72(R1), R20
+	MOVD	80(R1), R21
+	MOVD	88(R1), R22
+	MOVD	96(R1), R23
+	MOVD	104(R1), R24
+	MOVD	112(R1), R25
+	MOVD	120(R1), R26
+	MOVD	128(R1), R27
+	MOVD	136(R1), R28
+	MOVD	144(R1), R29
+	MOVD	152(R1), g // R30
+	MOVD	160(R1), R31
+	FMOVD	168(R1), F14
+	FMOVD	176(R1), F15
+	FMOVD	184(R1), F16
+	FMOVD	192(R1), F17
+	FMOVD	200(R1), F18
+	FMOVD	208(R1), F19
+	FMOVD	216(R1), F20
+	FMOVD	224(R1), F21
+	FMOVD	232(R1), F22
+	FMOVD	240(R1), F23
+	FMOVD	248(R1), F24
+	FMOVD	256(R1), F25
+	FMOVD	264(R1), F26
+	FMOVD	272(R1), F27
+	FMOVD	280(R1), F28
+	FMOVD	288(R1), F29
+	FMOVD	296(R1), F30
+	FMOVD	304(R1), F31
+
+	ADD	$320, R1
+	MOVD	24(R1), R2
+	MOVD	16(R1), R0
+	MOVD	R0, LR
+	RET
+
+TEXT _rt0_ppc64le_linux_lib_go(SB),NOSPLIT,$0
+	MOVD	_rt0_ppc64le_linux_lib_argc<>(SB), R3
+	MOVD	_rt0_ppc64le_linux_lib_argv<>(SB), R4
+	MOVD	$runtime·rt0_go(SB), R12
+	MOVD	R12, CTR
+	BR	(CTR)
+
+DATA _rt0_ppc64le_linux_lib_argc<>(SB)/8, $0
+GLOBL _rt0_ppc64le_linux_lib_argc<>(SB),NOPTR, $8
+DATA _rt0_ppc64le_linux_lib_argv<>(SB)/8, $0
+GLOBL _rt0_ppc64le_linux_lib_argv<>(SB),NOPTR, $8
+
 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
diff --git a/src/runtime/rt0_linux_s390x.s b/src/runtime/rt0_linux_s390x.s
new file mode 100644
index 0000000..aedd6c7
--- /dev/null
+++ b/src/runtime/rt0_linux_s390x.s
@@ -0,0 +1,20 @@
+// Copyright 2016 The Go 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_s390x_linux(SB),NOSPLIT|NOFRAME,$0
+	// 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: Support dynamic linking entry point
+	MOVD 0(R15), R2 // argc
+	ADD $8, R15, R3 // argv
+	BR main(SB)
+
+TEXT main(SB),NOSPLIT|NOFRAME,$0
+	MOVD	$runtime·rt0_go(SB), R11
+	BR	R11
diff --git a/src/runtime/rt0_plan9_arm.s b/src/runtime/rt0_plan9_arm.s
new file mode 100644
index 0000000..2a35e4e
--- /dev/null
+++ b/src/runtime/rt0_plan9_arm.s
@@ -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.
+
+#include "textflag.h"
+
+//in plan 9 argc is at top of stack followed by ptrs to arguments
+
+TEXT _rt0_arm_plan9(SB),NOSPLIT,$-4
+	MOVW	R0, _tos(SB)
+	MOVW	0(R13), R0
+	MOVW	$4(R13), R1
+	MOVW.W	R1, -4(R13)
+	MOVW.W	R0, -4(R13)
+	B	runtime·rt0_go(SB)
+
+GLOBL _tos(SB), NOPTR, $4
diff --git a/src/runtime/rt0_windows_386.s b/src/runtime/rt0_windows_386.s
index 0150cc2..b9407a9 100644
--- a/src/runtime/rt0_windows_386.s
+++ b/src/runtime/rt0_windows_386.s
@@ -12,5 +12,39 @@ TEXT _rt0_386_windows(SB),NOSPLIT,$12
 	MOVL	$-1, 0(SP) // return PC for main
 	JMP	_main(SB)
 
+// When building with -buildmode=(c-shared or c-archive), this
+// symbol is called. For dynamic libraries it is called when the
+// library is loaded. For static libraries it is called when the
+// final executable starts, during the C runtime initialization
+// phase.
+TEXT _rt0_386_windows_lib(SB),NOSPLIT,$0x1C
+	MOVL	BP, 0x08(SP)
+	MOVL	BX, 0x0C(SP)
+	MOVL	AX, 0x10(SP)
+	MOVL  CX, 0x14(SP)
+	MOVL  DX, 0x18(SP)
+
+	// Create a new thread to do the runtime initialization and return.
+	MOVL	_cgo_sys_thread_create(SB), AX
+	MOVL	$_rt0_386_windows_lib_go(SB), 0x00(SP)
+	MOVL	$0, 0x04(SP)
+
+	 // Top two items on the stack are passed to _cgo_sys_thread_create
+	 // as parameters. This is the calling convention on 32-bit Windows.
+	CALL	AX
+
+	MOVL	0x08(SP), BP
+	MOVL	0x0C(SP), BX
+	MOVL	0x10(SP), AX
+	MOVL	0x14(SP), CX
+	MOVL	0x18(SP), DX
+	RET
+
+TEXT _rt0_386_windows_lib_go(SB),NOSPLIT,$0
+	MOVL  $0, DI
+	MOVL	$0, SI
+	MOVL	$runtime·rt0_go(SB), AX
+	JMP	AX
+
 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 95dce06..2f73b37 100644
--- a/src/runtime/rt0_windows_amd64.s
+++ b/src/runtime/rt0_windows_amd64.s
@@ -12,6 +12,37 @@ TEXT _rt0_amd64_windows(SB),NOSPLIT,$-8
 	MOVQ	$main(SB), AX
 	JMP	AX
 
+// When building with -buildmode=(c-shared or c-archive), this
+// symbol is called. For dynamic libraries it is called when the
+// library is loaded. For static libraries it is called when the
+// final executable starts, during the C runtime initialization
+// phase.
+TEXT _rt0_amd64_windows_lib(SB),NOSPLIT,$0x28
+	MOVQ	BP, 0x00(SP)
+	MOVQ	BX, 0x08(SP)
+	MOVQ	AX, 0x10(SP)
+	MOVQ  CX, 0x18(SP)
+	MOVQ  DX, 0x20(SP)
+
+	// Create a new thread to do the runtime initialization and return.
+	MOVQ	_cgo_sys_thread_create(SB), AX
+	MOVQ	$_rt0_amd64_windows_lib_go(SB), CX
+	MOVQ	$0, DX
+	CALL	AX
+
+	MOVQ	0x00(SP), BP
+	MOVQ	0x08(SP), BX
+	MOVQ	0x10(SP), AX
+	MOVQ	0x18(SP), CX
+	MOVQ	0x20(SP), DX
+	RET
+
+TEXT _rt0_amd64_windows_lib_go(SB),NOSPLIT,$0
+	MOVQ  $0, DI
+	MOVQ	$0, SI
+	MOVQ	$runtime·rt0_go(SB), AX
+	JMP	AX
+
 TEXT main(SB),NOSPLIT,$-8
 	MOVQ	$runtime·rt0_go(SB), AX
 	JMP	AX
diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py
index e57fa00..5c9b2a0 100644
--- a/src/runtime/runtime-gdb.py
+++ b/src/runtime/runtime-gdb.py
@@ -448,15 +448,15 @@ class GoroutineCmd(gdb.Command):
 		except gdb.error:
 			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')
-		gdb.parse_and_eval('$pc = {0}'.format(str(pc)))
+		gdb.parse_and_eval('$save_pc = $pc')
 		gdb.parse_and_eval('$sp = {0}'.format(str(sp)))
+		gdb.parse_and_eval('$pc = {0}'.format(str(pc)))
 		try:
 			gdb.execute(cmd)
 		finally:
-			gdb.parse_and_eval('$pc = $save_pc')
 			gdb.parse_and_eval('$sp = $save_sp')
+			gdb.parse_and_eval('$pc = $save_pc')
 			save_frame.select()
 
 
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index 6ebc69a..aabe52d 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -1,8 +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 runtime_test
 
 import (
 	"bytes"
 	"fmt"
+	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -13,19 +18,22 @@ import (
 	"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)
+func checkGdbEnvironment(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+	if runtime.GOOS == "darwin" {
+		t.Skip("gdb does not work on darwin")
 	}
-	if string(out) != "go gdb python support\n" {
-		t.Skipf("skipping due to lack of python gdb support: %s", out)
+	if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
+		t.Skip("gdb test can fail with GOROOT_FINAL pending")
 	}
+}
 
+func checkGdbVersion(t *testing.T) {
 	// Issue 11214 reports various failures with older versions of gdb.
-	out, err = exec.Command("gdb", "--version").CombinedOutput()
+	out, err := exec.Command("gdb", "--version").CombinedOutput()
+	if err != nil {
+		t.Skipf("skipping: error executing gdb: %v", err)
+	}
 	re := regexp.MustCompile(`([0-9]+)\.([0-9]+)`)
 	matches := re.FindSubmatch(out)
 	if len(matches) < 3 {
@@ -42,6 +50,18 @@ func checkGdbPython(t *testing.T) {
 	t.Logf("gdb version %d.%d", major, minor)
 }
 
+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)
+	}
+}
+
 const helloSource = `
 package main
 import "fmt"
@@ -57,13 +77,8 @@ func main() {
 `
 
 func TestGdbPython(t *testing.T) {
-	if runtime.GOOS == "darwin" {
-		t.Skip("gdb does not work on darwin")
-	}
-	if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
-		t.Skip("gdb test can fail with GOROOT_FINAL pending")
-	}
-
+	checkGdbEnvironment(t)
+	checkGdbVersion(t)
 	checkGdbPython(t)
 
 	dir, err := ioutil.TempDir("", "go-build")
@@ -87,7 +102,9 @@ func TestGdbPython(t *testing.T) {
 
 	args := []string{"-nx", "-q", "--batch", "-iex",
 		fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
+		"-ex", "set startup-with-shell off",
 		"-ex", "info auto-load python-scripts",
+		"-ex", "set python print-stack full",
 		"-ex", "br main.go:10",
 		"-ex", "run",
 		"-ex", "echo BEGIN info goroutines\n",
@@ -98,16 +115,13 @@ func TestGdbPython(t *testing.T) {
 		"-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", "mips64", "mips64le":
+	case "amd64", "386", "ppc64", "ppc64le", "arm", "arm64", "mips64", "mips64le", "s390x":
 		canBackTrace = true
 		args = append(args,
 			"-ex", "echo BEGIN goroutine 2 bt\n",
@@ -158,10 +172,6 @@ func TestGdbPython(t *testing.T) {
 		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)
@@ -169,3 +179,87 @@ func TestGdbPython(t *testing.T) {
 		t.Logf("gdb cannot backtrace for GOARCH=%s, skipped goroutine backtrace test", runtime.GOARCH)
 	}
 }
+
+const backtraceSource = `
+package main
+
+//go:noinline
+func aaa() bool { return bbb() }
+
+//go:noinline
+func bbb() bool { return ccc() }
+
+//go:noinline
+func ccc() bool { return ddd() }
+
+//go:noinline
+func ddd() bool { return f() }
+
+//go:noinline
+func eee() bool { return true }
+
+var f = eee
+
+func main() {
+	_ = aaa()
+}
+`
+
+// TestGdbBacktrace tests that gdb can unwind the stack correctly
+// using only the DWARF debug info.
+func TestGdbBacktrace(t *testing.T) {
+	checkGdbEnvironment(t)
+	checkGdbVersion(t)
+
+	if runtime.GOOS == "netbsd" {
+		testenv.SkipFlaky(t, 15603)
+	}
+
+	dir, err := ioutil.TempDir("", "go-build")
+	if err != nil {
+		t.Fatalf("failed to create temp directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	// Build the source code.
+	src := filepath.Join(dir, "main.go")
+	err = ioutil.WriteFile(src, []byte(backtraceSource), 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)
+	}
+
+	// Execute gdb commands.
+	args := []string{"-nx", "-batch",
+		"-ex", "set startup-with-shell off",
+		"-ex", "break main.eee",
+		"-ex", "run",
+		"-ex", "backtrace",
+		"-ex", "continue",
+		filepath.Join(dir, "a.exe"),
+	}
+	got, _ := exec.Command("gdb", args...).CombinedOutput()
+
+	// Check that the backtrace matches the source code.
+	bt := []string{
+		"eee",
+		"ddd",
+		"ccc",
+		"bbb",
+		"aaa",
+		"main",
+	}
+	for i, name := range bt {
+		s := fmt.Sprintf("#%v.*main\\.%v", i, name)
+		re := regexp.MustCompile(s)
+		if found := re.Find(got) != nil; !found {
+			t.Errorf("could not find '%v' in backtrace", s)
+			t.Fatalf("gdb output:\n%v", string(got))
+		}
+	}
+}
diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go
index 2bd91c1..4c379b9 100644
--- a/src/runtime/runtime-lldb_test.go
+++ b/src/runtime/runtime-lldb_test.go
@@ -232,7 +232,7 @@ func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker)
 		SegmentSize uint8
 	}
 	for {
-		offset, err := data.Seek(0, 1)
+		offset, err := data.Seek(0, io.SeekCurrent)
 		if err != nil {
 			t.Fatalf("Seek error: %v", err)
 		}
@@ -246,7 +246,7 @@ func verifyAranges(t *testing.T, byteorder binary.ByteOrder, data io.ReadSeeker)
 		if lastTupleOffset%tupleSize != 0 {
 			t.Fatalf("Invalid arange length %d, (addr %d, seg %d)", header.UnitLength, header.AddressSize, header.SegmentSize)
 		}
-		if _, err = data.Seek(lastTupleOffset, 0); err != nil {
+		if _, err = data.Seek(lastTupleOffset, io.SeekStart); err != nil {
 			t.Fatalf("Seek error: %v", err)
 		}
 		buf := make([]byte, tupleSize)
diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go
index 265edf2..d9c26cc 100644
--- a/src/runtime/runtime.go
+++ b/src/runtime/runtime.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/runtime/runtime1.go b/src/runtime/runtime1.go
index 400ea29..302f58d 100644
--- a/src/runtime/runtime1.go
+++ b/src/runtime/runtime1.go
@@ -77,7 +77,7 @@ func goargs() {
 
 func goenvs_unix() {
 	// TODO(austin): ppc64 in dynamic linking mode doesn't
-	// guarantee env[] will immediately follow argv.  Might cause
+	// guarantee env[] will immediately follow argv. Might cause
 	// problems.
 	n := int32(0)
 	for argv_index(argv, argc+1+n) != nil {
@@ -242,7 +242,7 @@ func check() {
 
 	k = unsafe.Pointer(uintptr(0xfedcb123))
 	if sys.PtrSize == 8 {
-		k = unsafe.Pointer(uintptr(unsafe.Pointer(k)) << 10)
+		k = unsafe.Pointer(uintptr(k) << 10)
 	}
 	if casp(&k, nil, nil) {
 		throw("casp1")
@@ -477,10 +477,51 @@ func gomcache() *mcache {
 }
 
 //go:linkname reflect_typelinks reflect.typelinks
-func reflect_typelinks() [][]*_type {
-	ret := [][]*_type{firstmoduledata.typelinks}
+func reflect_typelinks() ([]unsafe.Pointer, [][]int32) {
+	sections := []unsafe.Pointer{unsafe.Pointer(firstmoduledata.types)}
+	ret := [][]int32{firstmoduledata.typelinks}
 	for datap := firstmoduledata.next; datap != nil; datap = datap.next {
+		sections = append(sections, unsafe.Pointer(datap.types))
 		ret = append(ret, datap.typelinks)
 	}
-	return ret
+	return sections, ret
+}
+
+// reflect_resolveNameOff resolves a name offset from a base pointer.
+//go:linkname reflect_resolveNameOff reflect.resolveNameOff
+func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer {
+	return unsafe.Pointer(resolveNameOff(ptrInModule, nameOff(off)).bytes)
+}
+
+// reflect_resolveTypeOff resolves an *rtype offset from a base type.
+//go:linkname reflect_resolveTypeOff reflect.resolveTypeOff
+func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
+	return unsafe.Pointer((*_type)(rtype).typeOff(typeOff(off)))
+}
+
+// reflect_resolveTextOff resolves an function pointer offset from a base type.
+//go:linkname reflect_resolveTextOff reflect.resolveTextOff
+func reflect_resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer {
+	return (*_type)(rtype).textOff(textOff(off))
+
+}
+
+// reflect_addReflectOff adds a pointer to the reflection offset lookup map.
+//go:linkname reflect_addReflectOff reflect.addReflectOff
+func reflect_addReflectOff(ptr unsafe.Pointer) int32 {
+	reflectOffsLock()
+	if reflectOffs.m == nil {
+		reflectOffs.m = make(map[int32]unsafe.Pointer)
+		reflectOffs.minv = make(map[unsafe.Pointer]int32)
+		reflectOffs.next = -1
+	}
+	id, found := reflectOffs.minv[ptr]
+	if !found {
+		id = reflectOffs.next
+		reflectOffs.next-- // use negative offsets as IDs to aid debugging
+		reflectOffs.m[id] = ptr
+		reflectOffs.minv[ptr] = id
+	}
+	reflectOffsUnlock()
+	return id
 }
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 917fe89..6119e75 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -10,34 +10,82 @@ import (
 	"unsafe"
 )
 
-/*
- * defined constants
- */
+// defined constants
 const (
 	// G status
 	//
+	// Beyond indicating the general state of a G, the G status
+	// acts like a lock on the goroutine's stack (and hence its
+	// ability to execute user code).
+	//
 	// 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
+
+	// _Gidle means this goroutine was just allocated and has not
+	// yet been initialized.
+	_Gidle = iota // 0
+
+	// _Grunnable means this goroutine is on a run queue. It is
+	// not currently executing user code. The stack is not owned.
+	_Grunnable // 1
+
+	// _Grunning means this goroutine may execute user code. The
+	// stack is owned by this goroutine. It is not on a run queue.
+	// It is assigned an M and a P.
+	_Grunning // 2
+
+	// _Gsyscall means this goroutine is executing a system call.
+	// It is not executing user code. The stack is owned by this
+	// goroutine. It is not on a run queue. It is assigned an M.
+	_Gsyscall // 3
+
+	// _Gwaiting means this goroutine is blocked in the runtime.
+	// It is not executing user code. It is not on a run queue,
+	// but should be recorded somewhere (e.g., a channel wait
+	// queue) so it can be ready()d when necessary. The stack is
+	// not owned *except* that a channel operation may read or
+	// write parts of the stack under the appropriate channel
+	// lock. Otherwise, it is not safe to access the stack after a
+	// goroutine enters _Gwaiting (e.g., it may get moved).
+	_Gwaiting // 4
+
+	// _Gmoribund_unused is currently unused, but hardcoded in gdb
+	// scripts.
+	_Gmoribund_unused // 5
+
+	// _Gdead means this goroutine is currently unused. It may be
+	// just exited, on a free list, or just being initialized. It
+	// is not executing user code. It may or may not have a stack
+	// allocated. The G and its stack (if any) are owned by the M
+	// that is exiting the G or that obtained the G from the free
+	// list.
+	_Gdead // 6
+
+	// _Genqueue_unused is currently unused.
+	_Genqueue_unused // 7
+
+	// _Gcopystack means this goroutine's stack is being moved. It
+	// is not executing user code and is not on a run queue. The
+	// stack is owned by the goroutine that put it in _Gcopystack.
+	_Gcopystack // 8
+
+	// _Gscan combined with one of the above states other than
+	// _Grunning indicates that GC is scanning the stack. The
+	// goroutine is not executing user code and the stack is owned
+	// by the goroutine that set the _Gscan bit.
+	//
+	// _Gscanrunning is different: it is used to briefly block
+	// state transitions while GC signals the G to scan its own
+	// stack. This is otherwise like _Grunning.
+	//
+	// atomicstatus&~Gscan gives the state the goroutine will
+	// return to when the scan completes.
+	_Gscan         = 0x1000
+	_Gscanrunnable = _Gscan + _Grunnable // 0x1001
+	_Gscanrunning  = _Gscan + _Grunning  // 0x1002
+	_Gscansyscall  = _Gscan + _Gsyscall  // 0x1003
+	_Gscanwaiting  = _Gscan + _Gwaiting  // 0x1004
 )
 
 const (
@@ -49,6 +97,10 @@ const (
 	_Pdead
 )
 
+// 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).
 type mutex struct {
 	// Futex-based impl treats it as uint32 key,
 	// while sema-based impl as M* waitm.
@@ -56,6 +108,26 @@ type mutex struct {
 	key uintptr
 }
 
+// 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.
 type note struct {
 	// Futex-based impl treats it as uint32 key,
 	// while sema-based impl as M* waitm.
@@ -160,17 +232,34 @@ type gobuf struct {
 	bp   uintptr // for GOEXPERIMENT=framepointer
 }
 
-// Known to compiler.
-// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
+// sudog represents a g in a wait list, such as for sending/receiving
+// on a channel.
+//
+// sudog is necessary because the g ↔ synchronization object relation
+// is many-to-many. A g can be on many wait lists, so there may be
+// many sudogs for one g; and many gs may be waiting on the same
+// synchronization object, so there may be many sudogs for one object.
+//
+// sudogs are allocated from a special pool. Use acquireSudog and
+// releaseSudog to allocate and free them.
 type sudog struct {
-	g           *g
-	selectdone  *uint32
-	next        *sudog
-	prev        *sudog
-	elem        unsafe.Pointer // data element
+	// The following fields are protected by the hchan.lock of the
+	// channel this sudog is blocking on. shrinkstack depends on
+	// this.
+
+	g          *g
+	selectdone *uint32 // CAS to 1 to win select race (may point to stack)
+	next       *sudog
+	prev       *sudog
+	elem       unsafe.Pointer // data element (may point to stack)
+
+	// The following fields are never accessed concurrently.
+	// waitlink is only accessed by g.
+
 	releasetime int64
-	nrelease    int32  // -1 for acquire
+	ticket      uint32
 	waitlink    *sudog // g.waiting list
+	c           *hchan // channel
 }
 
 type gcstats struct {
@@ -243,16 +332,17 @@ type g struct {
 	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)
+	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; transition from true to false by calling queueRescan and false to true by calling dequeueRescan
+	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)
+	traceseq       uint64   // trace event sequencer
+	tracelastp     puintptr // last P emitted an event for this goroutine
 	lockedm        *m
 	sig            uint32
 	writebuf       []byte
@@ -262,9 +352,17 @@ type g struct {
 	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)
+	waiting        *sudog    // sudog structures this g is waiting on (that have a valid elem ptr); in lock order
+	cgoCtxt        []uintptr // cgo traceback context
 
-	// Per-G gcController state
+	// Per-G GC state
+
+	// gcRescan is this G's index in work.rescan.list. If this is
+	// -1, this G is not on the rescan list.
+	//
+	// If gcphase != _GCoff and this G is visible to the garbage
+	// collector, writes to this are protected by work.rescan.lock.
+	gcRescan int32
 
 	// gcAssistBytes is this G's GC assist credit in terms of
 	// bytes allocated. If this is positive, then the G has credit
@@ -306,12 +404,13 @@ type m struct {
 	newSigstack   bool // minit on C thread called sigaltstack
 	printlock     int8
 	fastrand      uint32
-	ncgocall      uint64 // number of cgo calls in total
-	ncgo          int32  // number of cgo calls currently in progress
+	ncgocall      uint64      // number of cgo calls in total
+	ncgo          int32       // number of cgo calls currently in progress
+	cgoCallersUse uint32      // if non-zero, cgoCallers in use temporarily
+	cgoCallers    *cgoCallers // cgo traceback if crashing in cgo call
 	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.
@@ -329,8 +428,8 @@ type m struct {
 	waittraceskip int
 	startingtrace bool
 	syscalltick   uint32
-	//#ifdef GOOS_windows
-	thread uintptr // thread handle
+	thread        uintptr // thread handle
+
 	// these are here because they are too large to be on the stack
 	// of low-level NOSPLIT functions.
 	libcall   libcall
@@ -338,7 +437,7 @@ type m struct {
 	libcallsp uintptr
 	libcallg  guintptr
 	syscall   libcall // stores syscall parameters on windows
-	//#endif
+
 	mOS
 }
 
@@ -352,6 +451,7 @@ type p struct {
 	syscalltick uint32   // incremented on every system call
 	m           muintptr // back-link to associated m (nil if idle)
 	mcache      *mcache
+	racectx     uintptr
 
 	deferpool    [5][]*_defer // pool of available defer structs of different sizes (see panic.go)
 	deferpoolbuf [5][32]*_defer
@@ -432,9 +532,10 @@ type schedt struct {
 	runqsize int32
 
 	// Global cache of dead G's.
-	gflock mutex
-	gfree  *g
-	ngfree int32
+	gflock       mutex
+	gfreeStack   *g
+	gfreeNoStack *g
+	ngfree       int32
 
 	// Central cache of sudog structs.
 	sudoglock  mutex
@@ -462,10 +563,10 @@ type schedt struct {
 	totaltime      int64 // ∫gomaxprocs dt up to procresizetime
 }
 
-// The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread.
+// 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
+// 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.
@@ -511,6 +612,8 @@ type _func struct {
 
 // layout of Itab known to compilers
 // allocated in non-garbage-collected memory
+// Needs to be in sync with
+// ../cmd/compile/internal/gc/reflect.go:/^func.dumptypestructs.
 type itab struct {
 	inter  *interfacetype
 	_type  *_type
@@ -533,14 +636,7 @@ type forcegcstate struct {
 	idle uint32
 }
 
-/*
- * known to compiler
- */
-const (
-	_Structrnd = sys.RegSize
-)
-
-// startup_random_data holds random bytes initialized at startup.  These come from
+// 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
 
@@ -565,9 +661,7 @@ func extendRandom(r []byte, n int) {
 	}
 }
 
-/*
- * deferred subroutine calls
- */
+// deferred subroutine calls
 type _defer struct {
 	siz     int32
 	started bool
@@ -578,9 +672,7 @@ type _defer struct {
 	link    *_defer
 }
 
-/*
- * panics
- */
+// 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
@@ -589,10 +681,7 @@ type _panic struct {
 	aborted   bool           // the panic was aborted
 }
 
-/*
- * stack traces
- */
-
+// stack traces
 type stkframe struct {
 	fn       *_func     // function being run
 	pc       uintptr    // program counter within fn
@@ -612,10 +701,8 @@ const (
 	_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
-)
+// The maximum number of frames we print for a traceback
+const _TracebackMaxFrames = 100
 
 var (
 	emptystring string
@@ -633,11 +720,13 @@ var (
 	// Set on startup in asm_{x86,amd64}.s.
 	cpuid_ecx         uint32
 	cpuid_edx         uint32
+	cpuid_ebx7        uint32
 	lfenceBeforeRdtsc bool
 	support_avx       bool
 	support_avx2      bool
 
-	goarm uint8 // set by cmd/link on arm systems
+	goarm                uint8 // set by cmd/link on arm systems
+	framepointer_enabled bool  // set by cmd/link
 )
 
 // Set by the linker so the runtime can determine the buildmode.
@@ -645,46 +734,3 @@ 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_linux_test.go b/src/runtime/runtime_linux_test.go
index 58c797f..2b6daec 100644
--- a/src/runtime/runtime_linux_test.go
+++ b/src/runtime/runtime_linux_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/runtime/runtime_mmap_test.go b/src/runtime/runtime_mmap_test.go
index ff5e733..cf240c1 100644
--- a/src/runtime/runtime_mmap_test.go
+++ b/src/runtime/runtime_mmap_test.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/runtime_test.go b/src/runtime/runtime_test.go
index a6150a7..cd078c7 100644
--- a/src/runtime/runtime_test.go
+++ b/src/runtime/runtime_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -104,7 +104,7 @@ func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
 // of the larger addresses must themselves be invalid addresses.
 // We might get unlucky and the OS might have mapped one of these
 // addresses, but probably not: they're all in the first page, very high
-// adderesses that normally an OS would reserve for itself, or malformed
+// addresses that normally an OS would reserve for itself, or malformed
 // addresses. Even so, we might have to remove one or two on different
 // systems. We will see.
 
@@ -247,8 +247,8 @@ 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.
+	// 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 {
diff --git a/src/runtime/runtime_unix_test.go b/src/runtime/runtime_unix_test.go
index cfec332..e912163 100644
--- a/src/runtime/runtime_unix_test.go
+++ b/src/runtime/runtime_unix_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/select.go b/src/runtime/select.go
index b6c3fea..433048f 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -27,7 +27,7 @@ type hselect struct {
 	tcase     uint16   // total count of scase[]
 	ncase     uint16   // currently filled scase[]
 	pollorder *uint16  // case poll order
-	lockorder **hchan  // channel lock order
+	lockorder *uint16  // channel lock order
 	scase     [1]scase // one per case (in order of appearance)
 }
 
@@ -64,7 +64,7 @@ func newselect(sel *hselect, selsize int64, size int32) {
 	}
 	sel.tcase = uint16(size)
 	sel.ncase = 0
-	sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(hselect{}.scase[0])))
+	sel.lockorder = (*uint16)(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 {
@@ -161,11 +161,10 @@ func selectdefaultImpl(sel *hselect, callerpc uintptr, so uintptr) {
 	}
 }
 
-func sellock(sel *hselect) {
-	lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
-	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
+func sellock(scases []scase, lockorder []uint16) {
 	var c *hchan
-	for _, c0 := range lockorder {
+	for _, o := range lockorder {
+		c0 := scases[o].c
 		if c0 != nil && c0 != c {
 			c = c0
 			lock(&c.lock)
@@ -173,7 +172,7 @@ func sellock(sel *hselect) {
 	}
 }
 
-func selunlock(sel *hselect) {
+func selunlock(scases []scase, lockorder []uint16) {
 	// 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.
@@ -182,25 +181,42 @@ func selunlock(sel *hselect) {
 	// the G that calls select runnable again and schedules it for execution.
 	// When the G runs on another M, it locks all the locks and frees sel.
 	// Now if the first M touches sel, it will access freed memory.
-	n := int(sel.ncase)
+	n := len(scases)
 	r := 0
-	lockslice := slice{unsafe.Pointer(sel.lockorder), n, n}
-	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	// skip the default case
-	if n > 0 && lockorder[0] == nil {
+	if n > 0 && scases[lockorder[0]].c == nil {
 		r = 1
 	}
 	for i := n - 1; i >= r; i-- {
-		c := lockorder[i]
-		if i > 0 && c == lockorder[i-1] {
+		c := scases[lockorder[i]].c
+		if i > 0 && c == scases[lockorder[i-1]].c {
 			continue // will unlock it on the next iteration
 		}
 		unlock(&c.lock)
 	}
 }
 
-func selparkcommit(gp *g, sel unsafe.Pointer) bool {
-	selunlock((*hselect)(sel))
+func selparkcommit(gp *g, _ unsafe.Pointer) bool {
+	// This must not access gp's stack (see gopark). In
+	// particular, it must not access the *hselect. That's okay,
+	// because by the time this is called, gp.waiting has all
+	// channels in lock order.
+	var lastc *hchan
+	for sg := gp.waiting; sg != nil; sg = sg.waitlink {
+		if sg.c != lastc && lastc != nil {
+			// As soon as we unlock the channel, fields in
+			// any sudog with that channel may change,
+			// including c and waitlink. Since multiple
+			// sudogs may have the same channel, we unlock
+			// only after we've passed the last instance
+			// of a channel.
+			unlock(&lastc.lock)
+		}
+		lastc = sg.c
+	}
+	if lastc != nil {
+		unlock(&lastc.lock)
+	}
 	return true
 }
 
@@ -208,8 +224,15 @@ func block() {
 	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.
+// selectgo implements the select statement.
+//
+// *sel is on the current goroutine's stack (regardless of any
+// escaping in selectgo).
+//
+// selectgo does not return. Instead, it overwrites its return PC and
+// returns directly to the triggered select case. Because of this, it
+// cannot appear at the top of a split stack.
+//
 //go:nosplit
 func selectgo(sel *hselect) {
 	pc, offset := selectgoImpl(sel)
@@ -239,7 +262,7 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 	// only 0 or 1 cases plus default into simpler constructs.
 	// The only way we can end up with such small sel.ncase
 	// values here is for a larger select in which most channels
-	// have been nilled out.  The general code handles those
+	// have been nilled out. The general code handles those
 	// cases correctly, and they are rare enough not to bother
 	// optimizing (and needing to test).
 
@@ -255,19 +278,21 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 	// 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 := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
-	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
+	lockorder := *(*[]uint16)(unsafe.Pointer(&lockslice))
 	for i := 0; i < int(sel.ncase); i++ {
 		j := i
-		c := scases[j].c
-		for j > 0 && lockorder[(j-1)/2].sortkey() < c.sortkey() {
+		// Start with the pollorder to permute cases on the same channel.
+		c := scases[pollorder[i]].c
+		for j > 0 && scases[lockorder[(j-1)/2]].c.sortkey() < c.sortkey() {
 			k := (j - 1) / 2
 			lockorder[j] = lockorder[k]
 			j = k
 		}
-		lockorder[j] = c
+		lockorder[j] = pollorder[i]
 	}
 	for i := int(sel.ncase) - 1; i >= 0; i-- {
-		c := lockorder[i]
+		o := lockorder[i]
+		c := scases[o].c
 		lockorder[i] = lockorder[0]
 		j := 0
 		for {
@@ -275,21 +300,21 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 			if k >= i {
 				break
 			}
-			if k+1 < i && lockorder[k].sortkey() < lockorder[k+1].sortkey() {
+			if k+1 < i && scases[lockorder[k]].c.sortkey() < scases[lockorder[k+1]].c.sortkey() {
 				k++
 			}
-			if c.sortkey() < lockorder[k].sortkey() {
+			if c.sortkey() < scases[lockorder[k]].c.sortkey() {
 				lockorder[j] = lockorder[k]
 				j = k
 				continue
 			}
 			break
 		}
-		lockorder[j] = c
+		lockorder[j] = o
 	}
 	/*
 		for i := 0; i+1 < int(sel.ncase); i++ {
-			if lockorder[i].sortkey() > lockorder[i+1].sortkey() {
+			if scases[lockorder[i]].c.sortkey() > scases[lockorder[i+1]].c.sortkey() {
 				print("i=", i, " x=", lockorder[i], " y=", lockorder[i+1], "\n")
 				throw("select: broken sort")
 			}
@@ -297,7 +322,7 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 	*/
 
 	// lock all the channels involved in the select
-	sellock(sel)
+	sellock(scases, lockorder)
 
 	var (
 		gp     *g
@@ -308,6 +333,7 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 		sglist *sudog
 		sgnext *sudog
 		qp     unsafe.Pointer
+		nextp  **sudog
 	)
 
 loop:
@@ -352,7 +378,7 @@ loop:
 	}
 
 	if dfl != nil {
-		selunlock(sel)
+		selunlock(scases, lockorder)
 		cas = dfl
 		goto retc
 	}
@@ -363,20 +389,25 @@ loop:
 	if gp.waiting != nil {
 		throw("gp.waiting != nil")
 	}
-	for i := 0; i < int(sel.ncase); i++ {
-		cas = &scases[pollorder[i]]
+	nextp = &gp.waiting
+	for _, casei := range lockorder {
+		cas = &scases[casei]
 		c = cas.c
 		sg := acquireSudog()
 		sg.g = gp
 		// Note: selectdone is adjusted for stack copies in stack1.go:adjustsudogs
 		sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done)))
+		// No stack splits between assigning elem and enqueuing
+		// sg on gp.waiting where copystack can find it.
 		sg.elem = cas.elem
 		sg.releasetime = 0
 		if t0 != 0 {
 			sg.releasetime = -1
 		}
-		sg.waitlink = gp.waiting
-		gp.waiting = sg
+		sg.c = c
+		// Construct waiting list in lock order.
+		*nextp = sg
+		nextp = &sg.waitlink
 
 		switch cas.kind {
 		case caseRecv:
@@ -389,28 +420,29 @@ loop:
 
 	// wait for someone to wake us up
 	gp.param = nil
-	gopark(selparkcommit, unsafe.Pointer(sel), "select", traceEvGoBlockSelect, 2)
+	gopark(selparkcommit, nil, "select", traceEvGoBlockSelect, 2)
 
 	// someone woke us up
-	sellock(sel)
+	sellock(scases, lockorder)
 	sg = (*sudog)(gp.param)
 	gp.param = nil
 
 	// pass 3 - dequeue from unsuccessful chans
 	// otherwise they stack up on quiet channels
 	// record the successful case, if any.
-	// We singly-linked up the SudoGs in case order, so when
-	// iterating through the linked list they are in reverse order.
+	// We singly-linked up the SudoGs in lock order.
 	cas = nil
 	sglist = gp.waiting
 	// Clear all elem before unlinking from gp.waiting.
 	for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
 		sg1.selectdone = nil
 		sg1.elem = nil
+		sg1.c = nil
 	}
 	gp.waiting = nil
-	for i := int(sel.ncase) - 1; i >= 0; i-- {
-		k = &scases[pollorder[i]]
+
+	for _, casei := range lockorder {
+		k = &scases[casei]
 		if sglist.releasetime > 0 {
 			k.releasetime = sglist.releasetime
 		}
@@ -464,7 +496,7 @@ loop:
 		}
 	}
 
-	selunlock(sel)
+	selunlock(scases, lockorder)
 	goto retc
 
 bufrecv:
@@ -492,7 +524,7 @@ bufrecv:
 		c.recvx = 0
 	}
 	c.qcount--
-	selunlock(sel)
+	selunlock(scases, lockorder)
 	goto retc
 
 bufsend:
@@ -511,12 +543,12 @@ bufsend:
 		c.sendx = 0
 	}
 	c.qcount++
-	selunlock(sel)
+	selunlock(scases, lockorder)
 	goto retc
 
 recv:
 	// can receive from sleeping sender (sg)
-	recv(c, sg, cas.elem, func() { selunlock(sel) })
+	recv(c, sg, cas.elem, func() { selunlock(scases, lockorder) })
 	if debugSelect {
 		print("syncrecv: sel=", sel, " c=", c, "\n")
 	}
@@ -527,7 +559,7 @@ recv:
 
 rclose:
 	// read at end of closed channel
-	selunlock(sel)
+	selunlock(scases, lockorder)
 	if cas.receivedp != nil {
 		*cas.receivedp = false
 	}
@@ -547,7 +579,7 @@ send:
 	if msanenabled {
 		msanread(cas.elem, c.elemtype.size)
 	}
-	send(c, sg, cas.elem, func() { selunlock(sel) })
+	send(c, sg, cas.elem, func() { selunlock(scases, lockorder) })
 	if debugSelect {
 		print("syncsend: sel=", sel, " c=", c, "\n")
 	}
@@ -561,8 +593,8 @@ retc:
 
 sclose:
 	// send on closed channel
-	selunlock(sel)
-	panic("send on closed channel")
+	selunlock(scases, lockorder)
+	panic(plainError("send on closed channel"))
 }
 
 func (c *hchan) sortkey() uintptr {
@@ -594,7 +626,7 @@ const (
 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 := (*hselect)(mallocgc(size, nil, flagNoScan))
+	sel := (*hselect)(mallocgc(size, nil, true))
 	newselect(sel, int64(size), int32(len(cases)))
 	r := new(bool)
 	for i := range cases {
@@ -647,8 +679,8 @@ func (q *waitq) dequeueSudoG(sgp *sudog) {
 		return
 	}
 
-	// x==y==nil.  Either sgp is the only element in the queue,
-	// or it has already been removed.  Use q.first to disambiguate.
+	// 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 b54621b..45fbbca 100644
--- a/src/runtime/sema.go
+++ b/src/runtime/sema.go
@@ -62,6 +62,13 @@ func net_runtime_Semrelease(addr *uint32) {
 	semrelease(addr)
 }
 
+func readyWithTime(s *sudog, traceskip int) {
+	if s.releasetime != 0 {
+		s.releasetime = cputicks()
+	}
+	goready(s.g, traceskip)
+}
+
 // Called from runtime.
 func semacquire(addr *uint32, profile bool) {
 	gp := getg()
@@ -107,7 +114,7 @@ func semacquire(addr *uint32, profile bool) {
 		}
 	}
 	if s.releasetime > 0 {
-		blockevent(int64(s.releasetime)-t0, 3)
+		blockevent(s.releasetime-t0, 3)
 	}
 	releaseSudog(s)
 }
@@ -141,10 +148,7 @@ func semrelease(addr *uint32) {
 	}
 	unlock(&root.lock)
 	if s != nil {
-		if s.releasetime != 0 {
-			s.releasetime = cputicks()
-		}
-		goready(s.g, 4)
+		readyWithTime(s, 5)
 	}
 }
 
@@ -193,101 +197,158 @@ func (root *semaRoot) dequeue(s *sudog) {
 	s.prev = nil
 }
 
-// Synchronous semaphore for sync.Cond.
-type syncSema struct {
+// notifyList is a ticket-based notification list used to implement sync.Cond.
+//
+// It must be kept in sync with the sync package.
+type notifyList struct {
+	// wait is the ticket number of the next waiter. It is atomically
+	// incremented outside the lock.
+	wait uint32
+
+	// notify is the ticket number of the next waiter to be notified. It can
+	// be read outside the lock, but is only written to with lock held.
+	//
+	// Both wait & notify can wrap around, and such cases will be correctly
+	// handled as long as their "unwrapped" difference is bounded by 2^31.
+	// For this not to be the case, we'd need to have 2^31+ goroutines
+	// blocked on the same condvar, which is currently not possible.
+	notify uint32
+
+	// List of parked waiters.
 	lock mutex
 	head *sudog
 	tail *sudog
 }
 
-// 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 {
-		// Have pending release, consume it.
-		var wake *sudog
-		s.head.nrelease--
-		if s.head.nrelease == 0 {
-			wake = s.head
-			s.head = wake.next
-			if s.head == nil {
-				s.tail = nil
-			}
-		}
-		unlock(&s.lock)
-		if wake != nil {
-			wake.next = nil
-			goready(wake.g, 4)
-		}
+// less checks if a < b, considering a & b running counts that may overflow the
+// 32-bit range, and that their "unwrapped" difference is always less than 2^31.
+func less(a, b uint32) bool {
+	return int32(a-b) < 0
+}
+
+// notifyListAdd adds the caller to a notify list such that it can receive
+// notifications. The caller must eventually call notifyListWait to wait for
+// such a notification, passing the returned ticket number.
+//go:linkname notifyListAdd sync.runtime_notifyListAdd
+func notifyListAdd(l *notifyList) uint32 {
+	// This may be called concurrently, for example, when called from
+	// sync.Cond.Wait while holding a RWMutex in read mode.
+	return atomic.Xadd(&l.wait, 1) - 1
+}
+
+// notifyListWait waits for a notification. If one has been sent since
+// notifyListAdd was called, it returns immediately. Otherwise, it blocks.
+//go:linkname notifyListWait sync.runtime_notifyListWait
+func notifyListWait(l *notifyList, t uint32) {
+	lock(&l.lock)
+
+	// Return right away if this ticket has already been notified.
+	if less(t, l.notify) {
+		unlock(&l.lock)
+		return
+	}
+
+	// Enqueue itself.
+	s := acquireSudog()
+	s.g = getg()
+	s.ticket = t
+	s.releasetime = 0
+	t0 := int64(0)
+	if blockprofilerate > 0 {
+		t0 = cputicks()
+		s.releasetime = -1
+	}
+	if l.tail == nil {
+		l.head = s
 	} else {
-		// Enqueue itself.
-		w := acquireSudog()
-		w.g = getg()
-		w.nrelease = -1
-		w.next = nil
-		w.releasetime = 0
-		t0 := int64(0)
-		if blockprofilerate > 0 {
-			t0 = cputicks()
-			w.releasetime = -1
-		}
-		if s.tail == nil {
-			s.head = w
-		} else {
-			s.tail.next = w
-		}
-		s.tail = w
-		goparkunlock(&s.lock, "semacquire", traceEvGoBlockCond, 3)
-		if t0 != 0 {
-			blockevent(int64(w.releasetime)-t0, 2)
-		}
-		releaseSudog(w)
+		l.tail.next = s
 	}
+	l.tail = s
+	goparkunlock(&l.lock, "semacquire", traceEvGoBlockCond, 3)
+	if t0 != 0 {
+		blockevent(s.releasetime-t0, 2)
+	}
+	releaseSudog(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 {
-		// Have pending acquire, satisfy it.
-		wake := s.head
-		s.head = wake.next
-		if s.head == nil {
-			s.tail = nil
-		}
-		if wake.releasetime != 0 {
-			wake.releasetime = cputicks()
-		}
-		wake.next = nil
-		goready(wake.g, 4)
-		n--
+// notifyListNotifyAll notifies all entries in the list.
+//go:linkname notifyListNotifyAll sync.runtime_notifyListNotifyAll
+func notifyListNotifyAll(l *notifyList) {
+	// Fast-path: if there are no new waiters since the last notification
+	// we don't need to acquire the lock.
+	if atomic.Load(&l.wait) == atomic.Load(&l.notify) {
+		return
+	}
+
+	// Pull the list out into a local variable, waiters will be readied
+	// outside the lock.
+	lock(&l.lock)
+	s := l.head
+	l.head = nil
+	l.tail = nil
+
+	// Update the next ticket to be notified. We can set it to the current
+	// value of wait because any previous waiters are already in the list
+	// or will notice that they have already been notified when trying to
+	// add themselves to the list.
+	atomic.Store(&l.notify, atomic.Load(&l.wait))
+	unlock(&l.lock)
+
+	// Go through the local list and ready all waiters.
+	for s != nil {
+		next := s.next
+		s.next = nil
+		readyWithTime(s, 4)
+		s = next
 	}
-	if n > 0 {
-		// enqueue itself
-		w := acquireSudog()
-		w.g = getg()
-		w.nrelease = int32(n)
-		w.next = nil
-		w.releasetime = 0
-		if s.tail == nil {
-			s.head = w
-		} else {
-			s.tail.next = w
+}
+
+// notifyListNotifyOne notifies one entry in the list.
+//go:linkname notifyListNotifyOne sync.runtime_notifyListNotifyOne
+func notifyListNotifyOne(l *notifyList) {
+	// Fast-path: if there are no new waiters since the last notification
+	// we don't need to acquire the lock at all.
+	if atomic.Load(&l.wait) == atomic.Load(&l.notify) {
+		return
+	}
+
+	lock(&l.lock)
+
+	// Re-check under the lock if we need to do anything.
+	t := l.notify
+	if t == atomic.Load(&l.wait) {
+		unlock(&l.lock)
+		return
+	}
+
+	// Update the next notify ticket number, and try to find the G that
+	// needs to be notified. If it hasn't made it to the list yet we won't
+	// find it, but it won't park itself once it sees the new notify number.
+	atomic.Store(&l.notify, t+1)
+	for p, s := (*sudog)(nil), l.head; s != nil; p, s = s, s.next {
+		if s.ticket == t {
+			n := s.next
+			if p != nil {
+				p.next = n
+			} else {
+				l.head = n
+			}
+			if n == nil {
+				l.tail = p
+			}
+			unlock(&l.lock)
+			s.next = nil
+			readyWithTime(s, 4)
+			return
 		}
-		s.tail = w
-		goparkunlock(&s.lock, "semarelease", traceEvGoBlockCond, 3)
-		releaseSudog(w)
-	} else {
-		unlock(&s.lock)
 	}
+	unlock(&l.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")
-		throw("bad syncSema size")
+//go:linkname notifyListCheck sync.runtime_notifyListCheck
+func notifyListCheck(sz uintptr) {
+	if sz != unsafe.Sizeof(notifyList{}) {
+		print("runtime: bad notifyList size - sync=", sz, " runtime=", unsafe.Sizeof(notifyList{}), "\n")
+		throw("bad notifyList size")
 	}
 }
diff --git a/src/runtime/signal1_unix.go b/src/runtime/signal1_unix.go
index abb9639..5080202 100644
--- a/src/runtime/signal1_unix.go
+++ b/src/runtime/signal1_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -6,7 +6,10 @@
 
 package runtime
 
-import "runtime/internal/sys"
+import (
+	"runtime/internal/sys"
+	"unsafe"
+)
 
 const (
 	_SIG_DFL uintptr = 0
@@ -190,14 +193,24 @@ func dieFromSignal(sig int32) {
 	setsig(sig, _SIG_DFL, false)
 	updatesigmask(sigmask{})
 	raise(sig)
-	// That should have killed us; call exit just in case.
+
+	// That should have killed us. On some systems, though, raise
+	// sends the signal to the whole process rather than to just
+	// the current thread, which means that the signal may not yet
+	// have been delivered. Give other threads a chance to run and
+	// pick up the signal.
+	osyield()
+	osyield()
+	osyield()
+
+	// If we are still somehow running, just exit with the wrong status.
 	exit(2)
 }
 
 // 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) {
+func raisebadsignal(sig int32, c *sigctxt) {
 	if sig == _SIGPROF {
 		// Ignore profiling signals that arrive on non-Go threads.
 		return
@@ -212,14 +225,26 @@ func raisebadsignal(sig int32) {
 
 	// 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 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
+	// 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
+	// it. That means that we don't have to worry about blocking it
 	// again.
 	unblocksig(sig)
 	setsig(sig, handler, false)
+
+	// If we're linked into a non-Go program we want to try to
+	// avoid modifying the original context in which the signal
+	// was raised. If the handler is the default, we know it
+	// is non-recoverable, so we don't have to worry about
+	// re-installing sighandler. At this point we can just
+	// return and the signal will be re-raised and caught by
+	// the default handler with the correct context.
+	if (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
+		return
+	}
+
 	raise(sig)
 
 	// If the signal didn't cause the program to exit, restore the
@@ -294,16 +319,32 @@ func ensureSigM() {
 
 // This is called when we receive a signal when there is no signal stack.
 // This can only happen if non-Go code calls sigaltstack to disable the
-// signal stack.  This is called via cgocallback to establish a stack.
+// signal stack. This is called via cgocallback to establish a stack.
 func noSignalStack(sig uint32) {
 	println("signal", sig, "received on thread with no signal stack")
 	throw("non-Go code disabled sigaltstack")
 }
 
 // This is called if we receive a signal when there is a signal stack
-// but we are not on it.  This can only happen if non-Go code called
+// but we are not on it. This can only happen if non-Go code called
 // sigaction without setting the SS_ONSTACK flag.
 func sigNotOnStack(sig uint32) {
 	println("signal", sig, "received but handler not on signal stack")
 	throw("non-Go code set up signal handler without SA_ONSTACK flag")
 }
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+//go:norace
+//go:nowritebarrierrec
+func badsignal(sig uintptr, c *sigctxt) {
+	cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)+unsafe.Sizeof(c))
+}
+
+func badsignalgo(sig uintptr, c *sigctxt) {
+	if !sigsend(uint32(sig)) {
+		// A foreign thread received the signal sig, and the
+		// Go code does not want to handle it.
+		raisebadsignal(int32(sig), c)
+	}
+}
diff --git a/src/runtime/signal2_unix.go b/src/runtime/signal2_unix.go
index 3fe625f..b137169 100644
--- a/src/runtime/signal2_unix.go
+++ b/src/runtime/signal2_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -12,7 +12,7 @@ import "unsafe"
 func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
 
 // 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 to the handler that was installed before Go's. Returns whether the
 // signal was forwarded.
 // This is called by the signal handler, and the world may be stopped.
 //go:nosplit
@@ -54,7 +54,7 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
 	if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
 		return false
 	}
-	// Determine if the signal occurred inside Go code.  We test that:
+	// 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).
 	g := getg()
diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go
index 25187da..f27cf9d 100644
--- a/src/runtime/signal_386.go
+++ b/src/runtime/signal_386.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -84,7 +84,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 
 		// 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
+		// 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.)
diff --git a/src/runtime/signal_amd64x.go b/src/runtime/signal_amd64x.go
index 0f6700d..7b51fcc 100644
--- a/src/runtime/signal_amd64x.go
+++ b/src/runtime/signal_amd64x.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -116,7 +116,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 
 		// 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
+		// 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.)
diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go
index 3ea3938..3b8eaf6 100644
--- a/src/runtime/signal_arm.go
+++ b/src/runtime/signal_arm.go
@@ -70,7 +70,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 		c.set_sp(sp)
 		*(*uint32)(unsafe.Pointer(uintptr(sp))) = c.lr()
 
-		pc := uintptr(gp.sigpc)
+		pc := gp.sigpc
 
 		// If we don't recognize the PC as code
 		// but we do recognize the link register as code,
diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go
index e647c76..0e08623 100644
--- a/src/runtime/signal_arm64.go
+++ b/src/runtime/signal_arm64.go
@@ -86,7 +86,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 		c.set_sp(sp)
 		*(*uint64)(unsafe.Pointer(uintptr(sp))) = c.lr()
 
-		pc := uintptr(gp.sigpc)
+		pc := gp.sigpc
 
 		// If we don't recognize the PC as code
 		// but we do recognize the link register as code,
diff --git a/src/runtime/signal_darwin.go b/src/runtime/signal_darwin.go
index 8d43724..c8534ff 100644
--- a/src/runtime/signal_darwin.go
+++ b/src/runtime/signal_darwin.go
@@ -58,7 +58,7 @@ func sigtrampgo(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Poi
 	}
 	g := getg()
 	if g == nil {
-		badsignal(uintptr(sig))
+		badsignal(uintptr(sig), &sigctxt{info, ctx})
 		sigreturn(ctx, infostyle)
 		return
 	}
diff --git a/src/runtime/signal_darwin_386.go b/src/runtime/signal_darwin_386.go
index 7f7c22a..056f09a 100644
--- a/src/runtime/signal_darwin_386.go
+++ b/src/runtime/signal_darwin_386.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_darwin_amd64.go b/src/runtime/signal_darwin_amd64.go
index c9ac293..d219fa4 100644
--- a/src/runtime/signal_darwin_amd64.go
+++ b/src/runtime/signal_darwin_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_darwin_arm.go b/src/runtime/signal_darwin_arm.go
index 24c5f5a..82c7c93 100644
--- a/src/runtime/signal_darwin_arm.go
+++ b/src/runtime/signal_darwin_arm.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_darwin_arm64.go b/src/runtime/signal_darwin_arm64.go
index 82f4a82..12fa520 100644
--- a/src/runtime/signal_darwin_arm64.go
+++ b/src/runtime/signal_darwin_arm64.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/signal_dragonfly.go b/src/runtime/signal_dragonfly.go
index f507a07..8e9ce17 100644
--- a/src/runtime/signal_dragonfly.go
+++ b/src/runtime/signal_dragonfly.go
@@ -14,14 +14,14 @@ var sigtable = [...]sigTabT{
 	/* 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"},
+	/* 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, "SIGFPE: floating-point exception"},
+	/* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
 	/* 9 */ {0, "SIGKILL: kill"},
-	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
-	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 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"},
@@ -30,14 +30,14 @@ var sigtable = [...]sigTabT{
 	/* 17 */ {0, "SIGSTOP: stop"},
 	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
 	/* 19 */ {_SigNotify + _SigDefault, "SIGCONT: continue after stop"},
-	/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 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, "SIGPROF: profiling 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"},
diff --git a/src/runtime/signal_dragonfly_amd64.go b/src/runtime/signal_dragonfly_amd64.go
index 740959c..b32df29 100644
--- a/src/runtime/signal_dragonfly_amd64.go
+++ b/src/runtime/signal_dragonfly_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -32,11 +32,11 @@ 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) cs() uint64      { return c.regs().mc_cs }
+func (c *sigctxt) fs() uint64      { return c.regs().mc_ss }
+func (c *sigctxt) gs() uint64      { return 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) sigaddr() uint64 { return 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 }
diff --git a/src/runtime/signal_freebsd.go b/src/runtime/signal_freebsd.go
index f3411aa..c4cb687 100644
--- a/src/runtime/signal_freebsd.go
+++ b/src/runtime/signal_freebsd.go
@@ -16,15 +16,15 @@ var sigtable = [...]sigTabT{
 	/* 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"},
+	/* 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, "SIGFPE: floating-point exception"},
+	/* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
 	/* 9 */ {0, "SIGKILL: kill"},
-	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
-	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
-	/* 12 */ {_SigNotify, "SIGSYS: bad system call"},
+	/* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
+	/* 12 */ {_SigNotify, "SIGSYS: bad system call"}, // see golang.org/issues/15204
 	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
 	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
 	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
@@ -32,14 +32,14 @@ var sigtable = [...]sigTabT{
 	/* 17 */ {0, "SIGSTOP: stop"},
 	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
 	/* 19 */ {_SigNotify + _SigDefault, "SIGCONT: continue after stop"},
-	/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 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, "SIGPROF: profiling 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"},
@@ -55,7 +55,7 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
 	}
 	g := getg()
 	if g == nil {
-		badsignal(uintptr(sig))
+		badsignal(uintptr(sig), &sigctxt{info, ctx})
 		return
 	}
 
diff --git a/src/runtime/signal_freebsd_386.go b/src/runtime/signal_freebsd_386.go
index a0fec13..092e6df 100644
--- a/src/runtime/signal_freebsd_386.go
+++ b/src/runtime/signal_freebsd_386.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -22,9 +22,9 @@ 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) cs() uint32      { return c.regs().mc_cs }
+func (c *sigctxt) fs() uint32      { return c.regs().mc_fs }
+func (c *sigctxt) gs() uint32      { return 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) }
 
diff --git a/src/runtime/signal_freebsd_amd64.go b/src/runtime/signal_freebsd_amd64.go
index d10c883..a0b4a72 100644
--- a/src/runtime/signal_freebsd_amd64.go
+++ b/src/runtime/signal_freebsd_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -32,11 +32,11 @@ 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) cs() uint64      { return 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) sigaddr() uint64 { return 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 }
diff --git a/src/runtime/signal_freebsd_arm.go b/src/runtime/signal_freebsd_arm.go
index 12de23d..0357304 100644
--- a/src/runtime/signal_freebsd_arm.go
+++ b/src/runtime/signal_freebsd_arm.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_linux_386.go b/src/runtime/signal_linux_386.go
index 45074f9..415f361 100644
--- a/src/runtime/signal_linux_386.go
+++ b/src/runtime/signal_linux_386.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_linux_amd64.go b/src/runtime/signal_linux_amd64.go
index b8b38cc..433747f 100644
--- a/src/runtime/signal_linux_amd64.go
+++ b/src/runtime/signal_linux_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_linux_arm.go b/src/runtime/signal_linux_arm.go
index 469f47c..cd6a0d7 100644
--- a/src/runtime/signal_linux_arm.go
+++ b/src/runtime/signal_linux_arm.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_linux_arm64.go b/src/runtime/signal_linux_arm64.go
index 465fc4f..4964e7b 100644
--- a/src/runtime/signal_linux_arm64.go
+++ b/src/runtime/signal_linux_arm64.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/signal_linux_mips64x.go b/src/runtime/signal_linux_mips64x.go
index 671b916..0f590e4 100644
--- a/src/runtime/signal_linux_mips64x.go
+++ b/src/runtime/signal_linux_mips64x.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/signal_linux_ppc64x.go b/src/runtime/signal_linux_ppc64x.go
index 49e97a4..95835ca 100644
--- a/src/runtime/signal_linux_ppc64x.go
+++ b/src/runtime/signal_linux_ppc64x.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_linux_s390x.go b/src/runtime/signal_linux_s390x.go
new file mode 100644
index 0000000..155d3a3
--- /dev/null
+++ b/src/runtime/signal_linux_s390x.go
@@ -0,0 +1,208 @@
+// Copyright 2016 The Go Authors. 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 (
+	"runtime/internal/sys"
+	"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) r0() uint64      { return c.regs().gregs[0] }
+func (c *sigctxt) r1() uint64      { return c.regs().gregs[1] }
+func (c *sigctxt) r2() uint64      { return c.regs().gregs[2] }
+func (c *sigctxt) r3() uint64      { return c.regs().gregs[3] }
+func (c *sigctxt) r4() uint64      { return c.regs().gregs[4] }
+func (c *sigctxt) r5() uint64      { return c.regs().gregs[5] }
+func (c *sigctxt) r6() uint64      { return c.regs().gregs[6] }
+func (c *sigctxt) r7() uint64      { return c.regs().gregs[7] }
+func (c *sigctxt) r8() uint64      { return c.regs().gregs[8] }
+func (c *sigctxt) r9() uint64      { return c.regs().gregs[9] }
+func (c *sigctxt) r10() uint64     { return c.regs().gregs[10] }
+func (c *sigctxt) r11() uint64     { return c.regs().gregs[11] }
+func (c *sigctxt) r12() uint64     { return c.regs().gregs[12] }
+func (c *sigctxt) r13() uint64     { return c.regs().gregs[13] }
+func (c *sigctxt) r14() uint64     { return c.regs().gregs[14] }
+func (c *sigctxt) r15() uint64     { return c.regs().gregs[15] }
+func (c *sigctxt) link() uint64    { return c.regs().gregs[14] }
+func (c *sigctxt) sp() uint64      { return c.regs().gregs[15] }
+func (c *sigctxt) pc() uint64      { return c.regs().psw_addr }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
+
+func (c *sigctxt) set_r0(x uint64)      { c.regs().gregs[0] = x }
+func (c *sigctxt) set_r13(x uint64)     { c.regs().gregs[13] = x }
+func (c *sigctxt) set_link(x uint64)    { c.regs().gregs[14] = x }
+func (c *sigctxt) set_sp(x uint64)      { c.regs().gregs[15] = x }
+func (c *sigctxt) set_pc(x uint64)      { c.regs().psw_addr = 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*sys.PtrSize)) = uintptr(x)
+}
+
+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("pc   ", hex(c.pc()), "\t")
+	print("link ", hex(c.link()), "\n")
+}
+
+var crashing int32
+
+// May run during STW, so write barriers are not allowed.
+//
+//go:nowritebarrierrec
+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.sigaddr())
+		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() - sys.MinFrameSize
+		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_r13(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 c.sigcode() == _SI_USER && signal_ignored(sig) {
+		return
+	}
+
+	if flags&_SigKill != 0 {
+		dieFromSignal(int32(sig))
+	}
+
+	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")
+
+	level, _, docrash := gotraceback()
+	if level > 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_mips64x.go b/src/runtime/signal_mips64x.go
index 77c2714..4dbeb42 100644
--- a/src/runtime/signal_mips64x.go
+++ b/src/runtime/signal_mips64x.go
@@ -88,7 +88,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 		c.set_sp(sp)
 		*(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
 
-		pc := uintptr(gp.sigpc)
+		pc := gp.sigpc
 
 		// If we don't recognize the PC as code
 		// but we do recognize the link register as code,
diff --git a/src/runtime/signal_nacl_386.go b/src/runtime/signal_nacl_386.go
index 0a1e7c6..1f48590 100644
--- a/src/runtime/signal_nacl_386.go
+++ b/src/runtime/signal_nacl_386.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_nacl_amd64p32.go b/src/runtime/signal_nacl_amd64p32.go
index 024ceba..cb72dd0 100644
--- a/src/runtime/signal_nacl_amd64p32.go
+++ b/src/runtime/signal_nacl_amd64p32.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_nacl_arm.go b/src/runtime/signal_nacl_arm.go
index 1aeaa4e..b99827c 100644
--- a/src/runtime/signal_nacl_arm.go
+++ b/src/runtime/signal_nacl_arm.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_netbsd_386.go b/src/runtime/signal_netbsd_386.go
index 6702336..af49d5d 100644
--- a/src/runtime/signal_netbsd_386.go
+++ b/src/runtime/signal_netbsd_386.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -22,12 +22,12 @@ 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) cs() uint32       { return c.regs().__gregs[_REG_CS] }
+func (c *sigctxt) fs() uint32       { return c.regs().__gregs[_REG_FS] }
+func (c *sigctxt) gs() uint32       { return 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])))
+	return *(*uint32)(unsafe.Pointer(&c.info._reason[0]))
 }
 
 func (c *sigctxt) set_eip(x uint32)     { c.regs().__gregs[_REG_EIP] = x }
diff --git a/src/runtime/signal_netbsd_amd64.go b/src/runtime/signal_netbsd_amd64.go
index e22f4a7..db230f8 100644
--- a/src/runtime/signal_netbsd_amd64.go
+++ b/src/runtime/signal_netbsd_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -37,7 +37,7 @@ 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])))
+	return *(*uint64)(unsafe.Pointer(&c.info._reason[0]))
 }
 
 func (c *sigctxt) set_rip(x uint64)     { c.regs().__gregs[_REG_RIP] = x }
diff --git a/src/runtime/signal_netbsd_arm.go b/src/runtime/signal_netbsd_arm.go
index 9b114c8..4e58d3b 100644
--- a/src/runtime/signal_netbsd_arm.go
+++ b/src/runtime/signal_netbsd_arm.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_openbsd.go b/src/runtime/signal_openbsd.go
index d0239b1..9275279 100644
--- a/src/runtime/signal_openbsd.go
+++ b/src/runtime/signal_openbsd.go
@@ -16,14 +16,14 @@ var sigtable = [...]sigTabT{
 	/*  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"},
+	/*  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, "SIGFPE: floating-point exception"},
+	/*  8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
 	/*  9 */ {0, "SIGKILL: kill"},
-	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
-	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 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"},
@@ -32,14 +32,14 @@ var sigtable = [...]sigTabT{
 	/* 17 */ {0, "SIGSTOP: stop"},
 	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
 	/* 19 */ {_SigNotify + _SigDefault, "SIGCONT: continue after stop"},
-	/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 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, "SIGPROF: profiling 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"},
@@ -55,7 +55,7 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
 	}
 	g := getg()
 	if g == nil {
-		badsignal(uintptr(sig))
+		badsignal(uintptr(sig), &sigctxt{info, ctx})
 		return
 	}
 
diff --git a/src/runtime/signal_openbsd_386.go b/src/runtime/signal_openbsd_386.go
index c582a449..dbbb2c8 100644
--- a/src/runtime/signal_openbsd_386.go
+++ b/src/runtime/signal_openbsd_386.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_openbsd_amd64.go b/src/runtime/signal_openbsd_amd64.go
index 4f0d19d..5631ab4 100644
--- a/src/runtime/signal_openbsd_amd64.go
+++ b/src/runtime/signal_openbsd_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_openbsd_arm.go b/src/runtime/signal_openbsd_arm.go
index 8ee255c..3158a4e 100644
--- a/src/runtime/signal_openbsd_arm.go
+++ b/src/runtime/signal_openbsd_arm.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/runtime/signal_plan9.go b/src/runtime/signal_plan9.go
index 19247f2..d3894c8 100644
--- a/src/runtime/signal_plan9.go
+++ b/src/runtime/signal_plan9.go
@@ -22,8 +22,8 @@ var sigtable = [...]sigTabT{
 	{_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
+	{_SigPanic, "sys: trap: fault read"},  // SIGRFAULT
+	{_SigPanic, "sys: trap: fault write"}, // SIGWFAULT
 
 	// We can also recover from math errors.
 	{_SigPanic, "sys: trap: divide error"}, // SIGINTDIV
diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go
index 1c868b8..01a4af7 100644
--- a/src/runtime/signal_ppc64x.go
+++ b/src/runtime/signal_ppc64x.go
@@ -90,7 +90,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 		c.set_sp(sp)
 		*(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
 
-		pc := uintptr(gp.sigpc)
+		pc := gp.sigpc
 
 		// If we don't recognize the PC as code
 		// but we do recognize the link register as code,
diff --git a/src/runtime/signal_sigtramp.go b/src/runtime/signal_sigtramp.go
index 00ab038..3e0b104 100644
--- a/src/runtime/signal_sigtramp.go
+++ b/src/runtime/signal_sigtramp.go
@@ -18,7 +18,15 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
 	}
 	g := getg()
 	if g == nil {
-		badsignal(uintptr(sig))
+		if sig == _SIGPROF {
+			// Ignore profiling signals that arrive on
+			// non-Go threads. On some systems they will
+			// be handled directly by the signal handler,
+			// by calling sigprofNonGo, in which case we won't
+			// get here anyhow.
+			return
+		}
+		badsignal(uintptr(sig), &sigctxt{info, ctx})
 		return
 	}
 
diff --git a/src/runtime/signal_solaris.go b/src/runtime/signal_solaris.go
index 2cab5b8..a86f7bf 100644
--- a/src/runtime/signal_solaris.go
+++ b/src/runtime/signal_solaris.go
@@ -32,7 +32,7 @@ var sigtable = [...]sigTabT{
 	/* 19 */ {_SigNotify, "SIGPWR: power-fail restart"},
 	/* 20 */ {_SigNotify, "SIGWINCH: window size change"},
 	/* 21 */ {_SigNotify, "SIGURG: urgent socket condition"},
-	/* 22 */ {_SigNotify, "SIGPOLL: pollable event occured"},
+	/* 22 */ {_SigNotify, "SIGPOLL: pollable event occurred"},
 	/* 23 */ {_SigNotify + _SigDefault, "SIGSTOP: stop (cannot be caught or ignored)"},
 	/* 24 */ {_SigNotify + _SigDefault, "SIGTSTP: user stop requested from tty"},
 	/* 25 */ {_SigNotify + _SigDefault, "SIGCONT: stopped process has been continued"},
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index 8834e51..f59c9b9 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -12,3 +12,10 @@ import _ "unsafe" // for go:linkname
 func os_sigpipe() {
 	systemstack(sigpipe)
 }
+
+func signame(sig uint32) string {
+	if sig >= uint32(len(sigtable)) {
+		return ""
+	}
+	return sigtable[sig].name
+}
diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go
index ab7183f..298dcc9 100644
--- a/src/runtime/signal_windows.go
+++ b/src/runtime/signal_windows.go
@@ -82,13 +82,13 @@ func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
 
 	// 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
+	// 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--
+		sp = add(sp, ^(unsafe.Sizeof(uintptr(0)) - 1)) // sp--
 		*((*uintptr)(sp)) = r.ip()
 		r.setsp(uintptr(sp))
 	}
@@ -155,7 +155,7 @@ func sigpanic() {
 		throw("unexpected signal during runtime execution")
 	}
 
-	switch uint32(g.sig) {
+	switch g.sig {
 	case _EXCEPTION_ACCESS_VIOLATION:
 		if g.sigcode1 < 0x1000 || g.paniconfault {
 			panicmem()
@@ -209,6 +209,10 @@ func raisebadsignal(sig int32) {
 	badsignal2()
 }
 
+func signame(sig uint32) string {
+	return ""
+}
+
 func crash() {
 	// TODO: This routine should do whatever is needed
 	// to make the Windows program abort/crash as it
diff --git a/src/runtime/sigpanic_unix.go b/src/runtime/sigpanic_unix.go
index 1ce6223..4cd8615 100644
--- a/src/runtime/sigpanic_unix.go
+++ b/src/runtime/sigpanic_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/sigqueue.go b/src/runtime/sigqueue.go
index 546d3ab..0162ffa 100644
--- a/src/runtime/sigqueue.go
+++ b/src/runtime/sigqueue.go
@@ -12,7 +12,7 @@
 // sigsend is called by the signal handler to queue a new signal.
 // signal_recv is called by the Go program to receive a newly queued signal.
 // Synchronization between sigsend and signal_recv is based on the sig.state
-// variable.  It can be in 3 states: sigIdle, sigReceiving and sigSending.
+// variable. It can be in 3 states: sigIdle, sigReceiving and sigSending.
 // sigReceiving means that signal_recv is blocked on sig.Note and there are no
 // new pending signals.
 // sigSending means that sig.mask *may* contain new pending signals,
@@ -30,7 +30,7 @@ package runtime
 
 import (
 	"runtime/internal/atomic"
-	"unsafe"
+	_ "unsafe" // for go:linkname
 )
 
 var sig struct {
@@ -136,7 +136,7 @@ func signal_recv() uint32 {
 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
+		// to use for initialization. It does not pass
 		// signal information in m.
 		sig.inuse = true // enable reception of signals; cannot disable
 		noteclear(&sig.note)
@@ -176,19 +176,3 @@ func signal_ignore(s uint32) {
 func signal_ignored(s uint32) bool {
 	return sig.ignored[s/32]&(1<<(s&31)) != 0
 }
-
-// This runs on a foreign stack, without an m or a g.  No stack split.
-//go:nosplit
-//go:norace
-//go:nowritebarrierrec
-func badsignal(sig uintptr) {
-	cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
-}
-
-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
index 89f96be..575d26a 100644
--- a/src/runtime/sigqueue_plan9.go
+++ b/src/runtime/sigqueue_plan9.go
@@ -115,7 +115,7 @@ func signal_recv() string {
 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
+		// to use for initialization. It does not pass
 		// signal information in m.
 		sig.inuse = true // enable reception of signals; cannot disable
 		noteclear(&sig.note)
diff --git a/src/runtime/sigtab_linux_generic.go b/src/runtime/sigtab_linux_generic.go
index 32c40c4..ea36bf3 100644
--- a/src/runtime/sigtab_linux_generic.go
+++ b/src/runtime/sigtab_linux_generic.go
@@ -45,7 +45,7 @@ var sigtable = [...]sigTabT{
 	/* 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"},
+	/* 31 */ {_SigThrow, "SIGSYS: bad system call"},
 	/* 32 */ {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */
 	/* 33 */ {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */
 	/* 34 */ {_SigNotify, "signal 34"},
diff --git a/src/runtime/sigtab_linux_mips64x.go b/src/runtime/sigtab_linux_mips64x.go
index dbd50f7..201fe3d 100644
--- a/src/runtime/sigtab_linux_mips64x.go
+++ b/src/runtime/sigtab_linux_mips64x.go
@@ -25,7 +25,7 @@ var sigtable = [...]sigTabT{
 	/* 9 */ {0, "SIGKILL: kill"},
 	/* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
 	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
-	/* 12 */ {_SigNotify, "SIGSYS: bad system call"},
+	/* 12 */ {_SigThrow, "SIGSYS: bad system call"},
 	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
 	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
 	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index 943ecdc..e15e6c4 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -14,90 +14,121 @@ type slice struct {
 	cap   int
 }
 
+// maxElems is a lookup table containing the maximum capacity for a slice.
+// The index is the size of the slice element.
+var maxElems = [...]uintptr{
+	^uintptr(0),
+	_MaxMem / 1, _MaxMem / 2, _MaxMem / 3, _MaxMem / 4,
+	_MaxMem / 5, _MaxMem / 6, _MaxMem / 7, _MaxMem / 8,
+	_MaxMem / 9, _MaxMem / 10, _MaxMem / 11, _MaxMem / 12,
+	_MaxMem / 13, _MaxMem / 14, _MaxMem / 15, _MaxMem / 16,
+	_MaxMem / 17, _MaxMem / 18, _MaxMem / 19, _MaxMem / 20,
+	_MaxMem / 21, _MaxMem / 22, _MaxMem / 23, _MaxMem / 24,
+	_MaxMem / 25, _MaxMem / 26, _MaxMem / 27, _MaxMem / 28,
+	_MaxMem / 29, _MaxMem / 30, _MaxMem / 31, _MaxMem / 32,
+}
+
+// maxSliceCap returns the maximum capacity for a slice.
+func maxSliceCap(elemsize uintptr) uintptr {
+	if elemsize < uintptr(len(maxElems)) {
+		return maxElems[elemsize]
+	}
+	return _MaxMem / elemsize
+}
+
 // TODO: take uintptrs instead of int64s?
-func makeslice(t *slicetype, len64, cap64 int64) slice {
-	// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
+func makeslice(et *_type, len64, cap64 int64) slice {
+	// NOTE: The len > maxElements 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.
+	maxElements := maxSliceCap(et.size)
 	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 || uintptr(len) > maxElements {
 		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 || uintptr(cap) > maxElements {
 		panic(errorString("makeslice: cap out of range"))
 	}
-	p := newarray(t.elem, uintptr(cap))
-	return slice{p, len, cap}
-}
 
-// 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)
+	p := mallocgc(et.size*uintptr(cap), et, true)
+	return slice{p, len, cap}
 }
 
 // growslice handles slice growth during append.
-// It is passed the slice type, the old slice, and the desired new minimum capacity,
+// It is passed the slice element 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"))
-	}
-
+// The new slice's length is set to the old slice's length,
+// NOT to the new requested capacity.
+// This is for codegen convenience. The old slice's length is used immediately
+// to calculate where to write new values during an append.
+// TODO: When the old backend is gone, reconsider this decision.
+// The SSA backend might prefer the new length or to return only ptr/cap and save stack space.
+func growslice(et *_type, old slice, cap int) slice {
 	if raceenabled {
-		callerpc := getcallerpc(unsafe.Pointer(&t))
-		racereadrangepc(old.array, uintptr(old.len*int(t.elem.size)), callerpc, funcPC(growslice))
+		callerpc := getcallerpc(unsafe.Pointer(&et))
+		racereadrangepc(old.array, uintptr(old.len*int(et.size)), callerpc, funcPC(growslice))
 	}
 	if msanenabled {
-		msanread(old.array, uintptr(old.len*int(t.elem.size)))
+		msanread(old.array, uintptr(old.len*int(et.size)))
 	}
 
-	et := t.elem
 	if et.size == 0 {
+		if cap < old.cap {
+			panic(errorString("growslice: cap out of range"))
+		}
 		// 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 slice{unsafe.Pointer(&zerobase), old.len, cap}
 	}
 
 	newcap := old.cap
-	if newcap+newcap < cap {
+	doublecap := newcap + newcap
+	if cap > doublecap {
 		newcap = cap
 	} else {
-		for {
-			if old.len < 1024 {
-				newcap += newcap
-			} else {
+		if old.len < 1024 {
+			newcap = doublecap
+		} else {
+			for newcap < cap {
 				newcap += newcap / 4
 			}
-			if newcap >= cap {
-				break
-			}
 		}
 	}
 
-	if uintptr(newcap) >= _MaxMem/uintptr(et.size) {
+	var lenmem, capmem uintptr
+	const ptrSize = unsafe.Sizeof((*byte)(nil))
+	switch et.size {
+	case 1:
+		lenmem = uintptr(old.len)
+		capmem = roundupsize(uintptr(newcap))
+		newcap = int(capmem)
+	case ptrSize:
+		lenmem = uintptr(old.len) * ptrSize
+		capmem = roundupsize(uintptr(newcap) * ptrSize)
+		newcap = int(capmem / ptrSize)
+	default:
+		lenmem = uintptr(old.len) * et.size
+		capmem = roundupsize(uintptr(newcap) * et.size)
+		newcap = int(capmem / et.size)
+	}
+
+	if cap < old.cap || uintptr(newcap) > maxSliceCap(et.size) {
 		panic(errorString("growslice: cap out of range"))
 	}
-	lenmem := uintptr(old.len) * 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)
+		p = mallocgc(capmem, nil, false)
 		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 uninitialized memory.
-		p = newarray(et, uintptr(newcap))
+		p = mallocgc(capmem, et, true)
 		if !writeBarrier.enabled {
 			memmove(p, old.array, lenmem)
 		} else {
@@ -142,7 +173,7 @@ func slicecopy(to, fm slice, width uintptr) int {
 	} else {
 		memmove(to.array, fm.array, size)
 	}
-	return int(n)
+	return n
 }
 
 func slicestringcopy(to []byte, fm string) int {
@@ -164,6 +195,6 @@ func slicestringcopy(to []byte, fm string) int {
 		msanwrite(unsafe.Pointer(&to[0]), uintptr(n))
 	}
 
-	memmove(unsafe.Pointer(&to[0]), unsafe.Pointer(stringStructOf(&fm).str), uintptr(n))
+	memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n))
 	return n
 }
diff --git a/src/runtime/softfloat64.go b/src/runtime/softfloat64.go
index 790dbda..1678e8f 100644
--- a/src/runtime/softfloat64.go
+++ b/src/runtime/softfloat64.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/softfloat64_test.go b/src/runtime/softfloat64_test.go
index e108872..7347aff 100644
--- a/src/runtime/softfloat64_test.go
+++ b/src/runtime/softfloat64_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/runtime/softfloat_arm.go b/src/runtime/softfloat_arm.go
index 202e7bb..5f609c8 100644
--- a/src/runtime/softfloat_arm.go
+++ b/src/runtime/softfloat_arm.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.
 
-// Software floating point interpretaton of ARM 7500 FP instructions.
+// Software floating point interpretation 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.
 
@@ -168,14 +168,15 @@ execute:
 		}
 		return 1
 	}
-	if i == 0xe08bb00d {
-		// add sp to r11.
-		// might be part of a large stack offset address
+	if i&0xfffffff0 == 0xe08bb000 {
+		r := i & 0xf
+		// add r to r11.
+		// might be part of a large offset address calculation
 		// (or might not, but again no harm done).
-		regs[11] += regs[13]
+		regs[11] += regs[r]
 
 		if fptrace > 0 {
-			print("*** cpu R[11] += R[13] ", hex(regs[11]), "\n")
+			print("*** cpu R[11] += R[", r, "] ", hex(regs[11]), "\n")
 		}
 		return 1
 	}
@@ -529,7 +530,7 @@ execute:
 	case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF)
 		cmp := int32(m.freglo[regm])
 		if cmp < 0 {
-			fputf(regd, f64to32(fintto64(int64(-cmp))))
+			fputf(regd, f64to32(fintto64(-int64(cmp))))
 			m.freglo[regd] ^= 0x80000000
 		} else {
 			fputf(regd, f64to32(fintto64(int64(cmp))))
@@ -551,7 +552,7 @@ execute:
 	case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD)
 		cmp := int32(m.freglo[regm])
 		if cmp < 0 {
-			fputd(regd, fintto64(int64(-cmp)))
+			fputd(regd, fintto64(-int64(cmp)))
 			m.freghi[regd] ^= 0x80000000
 		} else {
 			fputd(regd, fintto64(int64(cmp)))
@@ -609,7 +610,7 @@ func sfloat2(pc uint32, regs *[15]uint32) uint32 {
 			pc = uint32(funcPC(_sfloatpanic))
 			break
 		}
-		pc += 4 * uint32(skip)
+		pc += 4 * skip
 	}
 	if first {
 		print("sfloat2 ", pc, " ", hex(*(*uint32)(unsafe.Pointer(uintptr(pc)))), "\n")
diff --git a/src/runtime/sqrt.go b/src/runtime/sqrt.go
index 1b130e3..d71a498 100644
--- a/src/runtime/sqrt.go
+++ b/src/runtime/sqrt.go
@@ -11,7 +11,7 @@ package runtime
 
 // 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
+// came with this notice. The go code is a simplified
 // version of the original C.
 //
 // ====================================================
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 8105996..8398a10 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -93,7 +93,7 @@ const (
 	_StackGuard = 720*sys.StackGuardMultiplier + _StackSystem
 
 	// After a stack split check the SP is allowed to be this
-	// many bytes below the stack guard.  This saves an instruction
+	// many bytes below the stack guard. This saves an instruction
 	// in the checking sequence for tiny frames.
 	_StackSmall = 128
 
@@ -127,7 +127,6 @@ const (
 
 const (
 	uintptrMask = 1<<(8*sys.PtrSize) - 1
-	poisonStack = uintptrMask & 0x6868686868686868
 
 	// Goroutine preemption request.
 	// Stored into g->stackguard0 to cause split stack check failure.
@@ -155,9 +154,6 @@ var stackLarge struct {
 	free [_MHeapMap_Bits]mSpanList // free lists by log_2(s.npages)
 }
 
-// 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")
@@ -180,57 +176,57 @@ func stacklog2(n uintptr) int {
 	return log2
 }
 
-// Allocates a stack from the free pool.  Must be called with
+// Allocates a stack from the free pool. Must be called with
 // stackpoolmu held.
 func stackpoolalloc(order uint8) gclinkptr {
 	list := &stackpool[order]
 	s := list.first
 	if s == nil {
-		// no free stacks.  Allocate another span worth.
+		// no free stacks. Allocate another span worth.
 		s = mheap_.allocStack(_StackCacheSize >> _PageShift)
 		if s == nil {
 			throw("out of memory")
 		}
-		if s.ref != 0 {
-			throw("bad ref")
+		if s.allocCount != 0 {
+			throw("bad allocCount")
 		}
-		if s.freelist.ptr() != nil {
-			throw("bad freelist")
+		if s.stackfreelist.ptr() != nil {
+			throw("bad stackfreelist")
 		}
 		for i := uintptr(0); i < _StackCacheSize; i += _FixedStack << order {
-			x := gclinkptr(uintptr(s.start)<<_PageShift + i)
-			x.ptr().next = s.freelist
-			s.freelist = x
+			x := gclinkptr(s.base() + i)
+			x.ptr().next = s.stackfreelist
+			s.stackfreelist = x
 		}
 		list.insert(s)
 	}
-	x := s.freelist
+	x := s.stackfreelist
 	if x.ptr() == nil {
 		throw("span has no free stacks")
 	}
-	s.freelist = x.ptr().next
-	s.ref++
-	if s.freelist.ptr() == nil {
+	s.stackfreelist = x.ptr().next
+	s.allocCount++
+	if s.stackfreelist.ptr() == nil {
 		// all stacks in s are allocated.
 		list.remove(s)
 	}
 	return x
 }
 
-// Adds stack x to the free pool.  Must be called with stackpoolmu held.
+// Adds stack x to the free pool. Must be called with stackpoolmu held.
 func stackpoolfree(x gclinkptr, order uint8) {
 	s := mheap_.lookup(unsafe.Pointer(x))
 	if s.state != _MSpanStack {
 		throw("freeing stack not in a stack span")
 	}
-	if s.freelist.ptr() == nil {
+	if s.stackfreelist.ptr() == nil {
 		// s will now have a free stack
 		stackpool[order].insert(s)
 	}
-	x.ptr().next = s.freelist
-	s.freelist = x
-	s.ref--
-	if gcphase == _GCoff && s.ref == 0 {
+	x.ptr().next = s.stackfreelist
+	s.stackfreelist = x
+	s.allocCount--
+	if gcphase == _GCoff && s.allocCount == 0 {
 		// Span is completely free. Return it to the heap
 		// immediately if we're sweeping.
 		//
@@ -247,13 +243,15 @@ func stackpoolfree(x gclinkptr, order uint8) {
 		//
 		// By not freeing, we prevent step #4 until GC is done.
 		stackpool[order].remove(s)
-		s.freelist = 0
+		s.stackfreelist = 0
 		mheap_.freeStack(s)
 	}
 }
 
 // stackcacherefill/stackcacherelease implement a global pool of stack segments.
 // The pool is required to prevent unlimited growth of per-thread caches.
+//
+//go:systemstack
 func stackcacherefill(c *mcache, order uint8) {
 	if stackDebug >= 1 {
 		print("stackcacherefill order=", order, "\n")
@@ -275,6 +273,7 @@ func stackcacherefill(c *mcache, order uint8) {
 	c.stackcache[order].size = size
 }
 
+//go:systemstack
 func stackcacherelease(c *mcache, order uint8) {
 	if stackDebug >= 1 {
 		print("stackcacherelease order=", order, "\n")
@@ -293,6 +292,7 @@ func stackcacherelease(c *mcache, order uint8) {
 	c.stackcache[order].size = size
 }
 
+//go:systemstack
 func stackcache_clear(c *mcache) {
 	if stackDebug >= 1 {
 		print("stackcache clear\n")
@@ -311,6 +311,12 @@ func stackcache_clear(c *mcache) {
 	unlock(&stackpoolmu)
 }
 
+// stackalloc allocates an n byte stack.
+//
+// stackalloc must run on the system stack because it uses per-P
+// resources and must not split the stack.
+//
+//go:systemstack
 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.
@@ -391,7 +397,7 @@ func stackalloc(n uint32) (stack, []stkbar) {
 				throw("out of memory")
 			}
 		}
-		v = unsafe.Pointer(s.start << _PageShift)
+		v = unsafe.Pointer(s.base())
 	}
 
 	if raceenabled {
@@ -408,6 +414,12 @@ func stackalloc(n uint32) (stack, []stkbar) {
 	return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
 }
 
+// stackfree frees an n byte stack allocation at stk.
+//
+// stackfree must run on the system stack because it uses per-P
+// resources and must not split the stack.
+//
+//go:systemstack
 func stackfree(stk stack, n uintptr) {
 	gp := getg()
 	v := unsafe.Pointer(stk.lo)
@@ -456,7 +468,7 @@ func stackfree(stk stack, n uintptr) {
 	} else {
 		s := mheap_.lookup(v)
 		if s.state != _MSpanStack {
-			println(hex(s.start<<_PageShift), v)
+			println(hex(s.base()), v)
 			throw("bad span state")
 		}
 		if gcphase == _GCoff {
@@ -516,20 +528,23 @@ type adjustinfo struct {
 	old   stack
 	delta uintptr // ptr distance from old to new stack (newbase - oldbase)
 	cache pcvalueCache
+
+	// sghi is the highest sudog.elem on the stack.
+	sghi uintptr
 }
 
 // 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)
+	pp := (*uintptr)(vpp)
 	p := *pp
 	if stackDebug >= 4 {
-		print("        ", pp, ":", p, "\n")
+		print("        ", pp, ":", hex(p), "\n")
 	}
-	if adjinfo.old.lo <= uintptr(p) && uintptr(p) < adjinfo.old.hi {
-		*pp = add(p, adjinfo.delta)
+	if adjinfo.old.lo <= p && p < adjinfo.old.hi {
+		*pp = p + adjinfo.delta
 		if stackDebug >= 3 {
-			print("        adjust ptr ", pp, ":", p, " -> ", *pp, "\n")
+			print("        adjust ptr ", pp, ":", hex(p), " -> ", hex(*pp), "\n")
 		}
 	}
 }
@@ -563,15 +578,22 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
 	minp := adjinfo.old.lo
 	maxp := adjinfo.old.hi
 	delta := adjinfo.delta
-	num := uintptr(bv.n)
+	num := bv.n
+	// If this frame might contain channel receive slots, use CAS
+	// to adjust pointers. If the slot hasn't been received into
+	// yet, it may contain stack pointers and a concurrent send
+	// could race with adjusting those pointers. (The sent value
+	// itself can never contain stack pointers.)
+	useCAS := uintptr(scanp) < adjinfo.sghi
 	for i := uintptr(0); i < num; i++ {
 		if stackDebug >= 4 {
 			print("        ", add(scanp, i*sys.PtrSize), ":", ptrnames[ptrbit(&bv, i)], ":", hex(*(*uintptr)(add(scanp, i*sys.PtrSize))), " # ", i, " ", bv.bytedata[i/8], "\n")
 		}
 		if ptrbit(&bv, i) == 1 {
 			pp := (*uintptr)(add(scanp, i*sys.PtrSize))
+		retry:
 			p := *pp
-			if f != nil && 0 < p && p < _PageSize && debug.invalidptr != 0 || p == poisonStack {
+			if f != nil && 0 < p && p < _PageSize && debug.invalidptr != 0 {
 				// Looks like a junk value in a pointer slot.
 				// Live analysis wrong?
 				getg().m.traceback = 2
@@ -582,7 +604,14 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
 				if stackDebug >= 3 {
 					print("adjust ptr ", p, " ", funcname(f), "\n")
 				}
-				*pp = p + delta
+				if useCAS {
+					ppu := (*unsafe.Pointer)(unsafe.Pointer(pp))
+					if !atomic.Casp1(ppu, unsafe.Pointer(p), unsafe.Pointer(p+delta)) {
+						goto retry
+					}
+				} else {
+					*pp = p + delta
+				}
 			}
 		}
 	}
@@ -617,8 +646,8 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
 	// Adjust local variables if stack frame has been allocated.
 	size := frame.varp - frame.sp
 	var minsize uintptr
-	switch sys.TheChar {
-	case '7':
+	switch sys.ArchFamily {
+	case sys.ARM64:
 		minsize = sys.SpAlign
 	default:
 		minsize = sys.MinFrameSize
@@ -645,7 +674,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
 	}
 
 	// Adjust saved base pointer if there is one.
-	if sys.TheChar == '6' && frame.argp-frame.varp == 2*sys.RegSize {
+	if sys.ArchFamily == sys.AMD64 && frame.argp-frame.varp == 2*sys.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")
@@ -665,7 +694,7 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
 		} 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")
+				print("runtime: frame ", funcname(f), " untyped args ", frame.argp, "+", frame.arglen, "\n")
 				throw("missing stackmap")
 			}
 			if pcdata < 0 || pcdata >= stackmap.n {
@@ -727,9 +756,76 @@ func fillstack(stk stack, b byte) {
 	}
 }
 
+func findsghi(gp *g, stk stack) uintptr {
+	var sghi uintptr
+	for sg := gp.waiting; sg != nil; sg = sg.waitlink {
+		p := uintptr(sg.elem) + uintptr(sg.c.elemsize)
+		if stk.lo <= p && p < stk.hi && p > sghi {
+			sghi = p
+		}
+		p = uintptr(unsafe.Pointer(sg.selectdone)) + unsafe.Sizeof(sg.selectdone)
+		if stk.lo <= p && p < stk.hi && p > sghi {
+			sghi = p
+		}
+	}
+	return sghi
+}
+
+// syncadjustsudogs adjusts gp's sudogs and copies the part of gp's
+// stack they refer to while synchronizing with concurrent channel
+// operations. It returns the number of bytes of stack copied.
+func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr {
+	if gp.waiting == nil {
+		return 0
+	}
+
+	// Lock channels to prevent concurrent send/receive.
+	// It's important that we *only* do this for async
+	// copystack; otherwise, gp may be in the middle of
+	// putting itself on wait queues and this would
+	// self-deadlock.
+	var lastc *hchan
+	for sg := gp.waiting; sg != nil; sg = sg.waitlink {
+		if sg.c != lastc {
+			lock(&sg.c.lock)
+		}
+		lastc = sg.c
+	}
+
+	// Adjust sudogs.
+	adjustsudogs(gp, adjinfo)
+
+	// Copy the part of the stack the sudogs point in to
+	// while holding the lock to prevent races on
+	// send/receive slots.
+	var sgsize uintptr
+	if adjinfo.sghi != 0 {
+		oldBot := adjinfo.old.hi - used
+		newBot := oldBot + adjinfo.delta
+		sgsize = adjinfo.sghi - oldBot
+		memmove(unsafe.Pointer(newBot), unsafe.Pointer(oldBot), sgsize)
+	}
+
+	// Unlock channels.
+	lastc = nil
+	for sg := gp.waiting; sg != nil; sg = sg.waitlink {
+		if sg.c != lastc {
+			unlock(&sg.c.lock)
+		}
+		lastc = sg.c
+	}
+
+	return sgsize
+}
+
 // 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 sync is true, this is a self-triggered stack growth and, in
+// particular, no other G may be writing to gp's stack (e.g., via a
+// channel operation). If sync is false, copystack protects against
+// concurrent channel operations.
+func copystack(gp *g, newsize uintptr, sync bool) {
 	if gp.syscallsp != 0 {
 		throw("stack growth not allowed in system call")
 	}
@@ -748,28 +844,46 @@ func copystack(gp *g, newsize uintptr) {
 		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")
 	}
 
-	// Disallow sigprof scans of this stack and block if there's
-	// one in progress.
-	gcLockStackBarriers(gp)
-
-	// adjust pointers in the to-be-copied frames
+	// Compute adjustment.
 	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.
+	// Adjust sudogs, synchronizing with channel ops if necessary.
+	ncopy := used
+	if sync {
+		adjustsudogs(gp, &adjinfo)
+	} else {
+		// sudogs can point in to the stack. During concurrent
+		// shrinking, these areas may be written to. Find the
+		// highest such pointer so we can handle everything
+		// there and below carefully. (This shouldn't be far
+		// from the bottom of the stack, so there's little
+		// cost in handling everything below it carefully.)
+		adjinfo.sghi = findsghi(gp, old)
+
+		// Synchronize with channel ops and copy the part of
+		// the stack they may interact with.
+		ncopy -= syncadjustsudogs(gp, used, &adjinfo)
+	}
+
+	// Copy the stack (or the rest of it) to the new location
+	memmove(unsafe.Pointer(new.hi-ncopy), unsafe.Pointer(old.hi-ncopy), ncopy)
+
+	// Disallow sigprof scans of this stack and block if there's
+	// one in progress.
+	gcLockStackBarriers(gp)
+
+	// Adjust remaining structures that have pointers into stacks.
+	// We have to do most of these before we traceback the new
+	// stack because gentraceback uses them.
 	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)
+	if adjinfo.sghi != 0 {
+		adjinfo.sghi += adjinfo.delta
 	}
-	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)]
@@ -784,6 +898,9 @@ func copystack(gp *g, newsize uintptr) {
 	gp.stkbar = newstkbar
 	gp.stktopsp += adjinfo.delta
 
+	// Adjust pointers in the new stack.
+	gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, adjustframe, noescape(unsafe.Pointer(&adjinfo)), 0)
+
 	gcUnlockStackBarriers(gp)
 
 	// free old stack
@@ -868,16 +985,11 @@ func newstack() {
 		}
 	}
 
-	// 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 sys.TheChar == '6' || sys.TheChar == '8' {
+	if sys.ArchFamily == sys.AMD64 || sys.ArchFamily == sys.I386 {
 		// The call to morestack cost a word.
 		sp -= sys.PtrSize
 	}
@@ -907,6 +1019,8 @@ func newstack() {
 		if thisg.m.p == 0 && thisg.m.locks == 0 {
 			throw("runtime: g is running but p is not")
 		}
+		// Synchronize with scang.
+		casgstatus(gp, _Grunning, _Gwaiting)
 		if gp.preemptscan {
 			for !castogscanstatus(gp, _Gwaiting, _Gscanwaiting) {
 				// Likely to be racing with the GC as
@@ -916,12 +1030,19 @@ func newstack() {
 				// return.
 			}
 			if !gp.gcscandone {
-				scanstack(gp)
+				// gcw is safe because we're on the
+				// system stack.
+				gcw := &gp.m.p.ptr().gcw
+				scanstack(gp, gcw)
+				if gcBlackenPromptly {
+					gcw.dispose()
+				}
 				gp.gcscandone = true
 			}
 			gp.preemptscan = false
 			gp.preempt = false
 			casfrom_Gscanstatus(gp, _Gscanwaiting, _Gwaiting)
+			// This clears gcscanvalid.
 			casgstatus(gp, _Gwaiting, _Grunning)
 			gp.stackguard0 = gp.stack.lo + _StackGuard
 			gogo(&gp.sched) // never return
@@ -940,11 +1061,13 @@ func newstack() {
 		throw("stack overflow")
 	}
 
-	casgstatus(gp, _Gwaiting, _Gcopystack)
+	// The goroutine must be executing in order to call newstack,
+	// so it must be Grunning (or Gscanrunning).
+	casgstatus(gp, _Grunning, _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))
+	copystack(gp, uintptr(newsize), true)
 	if stackDebug >= 1 {
 		print("stack grow done\n")
 	}
@@ -971,8 +1094,10 @@ func gostartcallfn(gobuf *gobuf, fv *funcval) {
 
 // Maybe shrink the stack being used by gp.
 // Called at garbage collection time.
+// gp must be stopped, but the world need not be.
 func shrinkstack(gp *g) {
-	if readgstatus(gp) == _Gdead {
+	gstatus := readgstatus(gp)
+	if gstatus&^_Gscan == _Gdead {
 		if gp.stack.lo != 0 {
 			// Free whole stack - it will get reallocated
 			// if G is used again.
@@ -987,6 +1112,9 @@ func shrinkstack(gp *g) {
 	if gp.stack.lo == 0 {
 		throw("missing stack in shrinkstack")
 	}
+	if gstatus&_Gscan == 0 {
+		throw("bad status in shrinkstack")
+	}
 
 	if debug.gcshrinkstackoff > 0 {
 		return
@@ -1022,9 +1150,7 @@ func shrinkstack(gp *g) {
 		print("shrinking stack ", oldsize, "->", newsize, "\n")
 	}
 
-	oldstatus := casgcopystack(gp)
-	copystack(gp, newsize)
-	casgstatus(gp, _Gcopystack, oldstatus)
+	copystack(gp, newsize, false)
 }
 
 // freeStackSpans frees unused stack spans at the end of GC.
@@ -1036,9 +1162,9 @@ func freeStackSpans() {
 		list := &stackpool[order]
 		for s := list.first; s != nil; {
 			next := s.next
-			if s.ref == 0 {
+			if s.allocCount == 0 {
 				list.remove(s)
-				s.freelist = 0
+				s.stackfreelist = 0
 				mheap_.freeStack(s)
 			}
 			s = next
diff --git a/src/runtime/stack_test.go b/src/runtime/stack_test.go
index 928d1ec..a32b68b 100644
--- a/src/runtime/stack_test.go
+++ b/src/runtime/stack_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -416,9 +416,9 @@ func TestStackAllOutput(t *testing.T) {
 }
 
 func TestStackPanic(t *testing.T) {
-	// Test that stack copying copies panics correctly.  This is difficult
+	// Test that stack copying copies panics correctly. This is difficult
 	// to test because it is very unlikely that the stack will be copied
-	// in the middle of gopanic.  But it can happen.
+	// in the middle of gopanic. But it can happen.
 	// To make this test effective, edit panic.go:gopanic and uncomment
 	// the GC() call just before freedefer(d).
 	defer func() {
diff --git a/src/runtime/string.go b/src/runtime/string.go
index dd04bda..ef28ba9 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -84,7 +84,7 @@ func slicebytetostring(buf *tmpBuf, b []byte) string {
 	if raceenabled && l > 0 {
 		racereadrangepc(unsafe.Pointer(&b[0]),
 			uintptr(l),
-			getcallerpc(unsafe.Pointer(&b)),
+			getcallerpc(unsafe.Pointer(&buf)),
 			funcPC(slicebytetostring))
 	}
 	if msanenabled && l > 0 {
@@ -139,7 +139,8 @@ func slicebytetostringtmp(b []byte) string {
 func stringtoslicebyte(buf *tmpBuf, s string) []byte {
 	var b []byte
 	if buf != nil && len(s) <= len(buf) {
-		b = buf[:len(s):len(s)]
+		*buf = tmpBuf{}
+		b = buf[:len(s)]
 	} else {
 		b = rawbyteslice(len(s))
 	}
@@ -155,7 +156,7 @@ func stringtoslicebytetmp(s string) []byte {
 	// for i, c := range []byte(str)
 
 	str := stringStructOf(&s)
-	ret := slice{array: unsafe.Pointer(str.str), len: str.len, cap: str.len}
+	ret := slice{array: str.str, len: str.len, cap: str.len}
 	return *(*[]byte)(unsafe.Pointer(&ret))
 }
 
@@ -171,7 +172,8 @@ func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
 	}
 	var a []rune
 	if buf != nil && n <= len(buf) {
-		a = buf[:n:n]
+		*buf = [tmpStringBufSize]rune{}
+		a = buf[:n]
 	} else {
 		a = rawruneslice(n)
 	}
@@ -189,7 +191,7 @@ func slicerunetostring(buf *tmpBuf, a []rune) string {
 	if raceenabled && len(a) > 0 {
 		racereadrangepc(unsafe.Pointer(&a[0]),
 			uintptr(len(a))*unsafe.Sizeof(a[0]),
-			getcallerpc(unsafe.Pointer(&a)),
+			getcallerpc(unsafe.Pointer(&buf)),
 			funcPC(slicerunetostring))
 	}
 	if msanenabled && len(a) > 0 {
@@ -236,6 +238,9 @@ func intstring(buf *[4]byte, v int64) string {
 	} else {
 		s, b = rawstring(4)
 	}
+	if int64(rune(v)) != v {
+		v = runeerror
+	}
 	n := runetochar(b, rune(v))
 	return s[:n]
 }
@@ -281,7 +286,7 @@ func stringiter2(s string, k int) (int, rune) {
 // The storage is not zeroed. Callers should use
 // b to set the string contents and then drop b.
 func rawstring(size int) (s string, b []byte) {
-	p := mallocgc(uintptr(size), nil, flagNoScan|flagNoZero)
+	p := mallocgc(uintptr(size), nil, false)
 
 	stringStructOf(&s).str = p
 	stringStructOf(&s).len = size
@@ -290,7 +295,7 @@ func rawstring(size int) (s string, b []byte) {
 
 	for {
 		ms := maxstring
-		if uintptr(size) <= uintptr(ms) || atomic.Casuintptr((*uintptr)(unsafe.Pointer(&maxstring)), uintptr(ms), uintptr(size)) {
+		if uintptr(size) <= ms || atomic.Casuintptr((*uintptr)(unsafe.Pointer(&maxstring)), ms, uintptr(size)) {
 			return
 		}
 	}
@@ -299,7 +304,7 @@ 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 := roundupsize(uintptr(size))
-	p := mallocgc(cap, nil, flagNoScan|flagNoZero)
+	p := mallocgc(cap, nil, false)
 	if cap != uintptr(size) {
 		memclr(add(p, uintptr(size)), cap-uintptr(size))
 	}
@@ -314,7 +319,7 @@ func rawruneslice(size int) (b []rune) {
 		throw("out of memory")
 	}
 	mem := roundupsize(uintptr(size) * 4)
-	p := mallocgc(mem, nil, flagNoScan|flagNoZero)
+	p := mallocgc(mem, nil, false)
 	if mem != uintptr(size)*4 {
 		memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4)
 	}
diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go
index 150a255..0f1d82a 100644
--- a/src/runtime/string_test.go
+++ b/src/runtime/string_test.go
@@ -10,6 +10,10 @@ import (
 	"testing"
 )
 
+// Strings and slices that don't escape and fit into tmpBuf are stack allocated,
+// which defeats using AllocsPerRun to test other optimizations.
+const sizeNoStack = 100
+
 func BenchmarkCompareStringEqual(b *testing.B) {
 	bytes := []byte("Hello Gophers!")
 	s1, s2 := string(bytes), string(bytes)
@@ -102,6 +106,17 @@ func BenchmarkRuneIterate2(b *testing.B) {
 	}
 }
 
+func BenchmarkArrayEqual(b *testing.B) {
+	a1 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+	a2 := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		if a1 != a2 {
+			b.Fatal("not equal")
+		}
+	}
+}
+
 func TestStringW(t *testing.T) {
 	strings := []string{
 		"hello",
@@ -147,7 +162,7 @@ func TestGostringnocopy(t *testing.T) {
 }
 
 func TestCompareTempString(t *testing.T) {
-	s := "foo"
+	s := strings.Repeat("x", sizeNoStack)
 	b := []byte(s)
 	n := testing.AllocsPerRun(1000, func() {
 		if string(b) != s {
@@ -210,7 +225,7 @@ func TestIntStringAllocs(t *testing.T) {
 }
 
 func TestRangeStringCast(t *testing.T) {
-	s := "abc"
+	s := strings.Repeat("x", sizeNoStack)
 	n := testing.AllocsPerRun(1000, func() {
 		for i, c := range []byte(s) {
 			if c != s[i] {
@@ -223,17 +238,35 @@ func TestRangeStringCast(t *testing.T) {
 	}
 }
 
+func isZeroed(b []byte) bool {
+	for _, x := range b {
+		if x != 0 {
+			return false
+		}
+	}
+	return true
+}
+
+func isZeroedR(r []rune) bool {
+	for _, x := range r {
+		if x != 0 {
+			return false
+		}
+	}
+	return true
+}
+
 func TestString2Slice(t *testing.T) {
 	// Make sure we don't return slices that expose
 	// an unzeroed section of stack-allocated temp buf
-	// between len and cap.  See issue 14232.
+	// between len and cap. See issue 14232.
 	s := "foož"
 	b := ([]byte)(s)
-	if cap(b) != 5 {
-		t.Errorf("want cap of 5, got %d", cap(b))
+	if !isZeroed(b[len(b):cap(b)]) {
+		t.Errorf("extra bytes not zeroed")
 	}
 	r := ([]rune)(s)
-	if cap(r) != 4 {
-		t.Errorf("want cap of 4, got %d", cap(r))
+	if !isZeroedR(r[len(r):cap(r)]) {
+		t.Errorf("extra runes not zeroed")
 	}
 }
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index f060182..6c28fd2 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -85,7 +85,7 @@ func fastrand1() uint32
 
 // in asm_*.s
 //go:noescape
-func memeq(a, b unsafe.Pointer, size uintptr) bool
+func memequal(a, b unsafe.Pointer, size uintptr) bool
 
 // noescape hides a pointer from escape analysis.  noescape is
 // the identity function but escape analysis doesn't think the
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 6e02f1e..4f6fae2 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -9,6 +9,150 @@ import (
 	"unsafe"
 )
 
+// Frames may be used to get function/file/line information for a
+// slice of PC values returned by Callers.
+type Frames struct {
+	callers []uintptr
+
+	// If previous caller in iteration was a panic, then
+	// ci.callers[0] is the address of the faulting instruction
+	// instead of the return address of the call.
+	wasPanic bool
+
+	// Frames to return for subsequent calls to the Next method.
+	// Used for non-Go frames.
+	frames *[]Frame
+}
+
+// Frame is the information returned by Frames for each call frame.
+type Frame struct {
+	// Program counter for this frame; multiple frames may have
+	// the same PC value.
+	PC uintptr
+
+	// Func for this frame; may be nil for non-Go code or fully
+	// inlined functions.
+	Func *Func
+
+	// Function name, file name, and line number for this call frame.
+	// May be the empty string or zero if not known.
+	// If Func is not nil then Function == Func.Name().
+	Function string
+	File     string
+	Line     int
+
+	// Entry point for the function; may be zero if not known.
+	// If Func is not nil then Entry == Func.Entry().
+	Entry uintptr
+}
+
+// CallersFrames takes a slice of PC values returned by Callers and
+// prepares to return function/file/line information.
+// Do not change the slice until you are done with the Frames.
+func CallersFrames(callers []uintptr) *Frames {
+	return &Frames{callers: callers}
+}
+
+// Next returns frame information for the next caller.
+// If more is false, there are no more callers (the Frame value is valid).
+func (ci *Frames) Next() (frame Frame, more bool) {
+	if ci.frames != nil {
+		// We have saved up frames to return.
+		f := (*ci.frames)[0]
+		if len(*ci.frames) == 1 {
+			ci.frames = nil
+		} else {
+			*ci.frames = (*ci.frames)[1:]
+		}
+		return f, ci.frames != nil || len(ci.callers) > 0
+	}
+
+	if len(ci.callers) == 0 {
+		ci.wasPanic = false
+		return Frame{}, false
+	}
+	pc := ci.callers[0]
+	ci.callers = ci.callers[1:]
+	more = len(ci.callers) > 0
+	f := FuncForPC(pc)
+	if f == nil {
+		ci.wasPanic = false
+		if cgoSymbolizer != nil {
+			return ci.cgoNext(pc, more)
+		}
+		return Frame{}, more
+	}
+
+	entry := f.Entry()
+	xpc := pc
+	if xpc > entry && !ci.wasPanic {
+		xpc--
+	}
+	file, line := f.FileLine(xpc)
+
+	function := f.Name()
+	ci.wasPanic = entry == sigpanicPC
+
+	frame = Frame{
+		PC:       xpc,
+		Func:     f,
+		Function: function,
+		File:     file,
+		Line:     line,
+		Entry:    entry,
+	}
+
+	return frame, more
+}
+
+// cgoNext returns frame information for pc, known to be a non-Go function,
+// using the cgoSymbolizer hook.
+func (ci *Frames) cgoNext(pc uintptr, more bool) (Frame, bool) {
+	arg := cgoSymbolizerArg{pc: pc}
+	callCgoSymbolizer(&arg)
+
+	if arg.file == nil && arg.funcName == nil {
+		// No useful information from symbolizer.
+		return Frame{}, more
+	}
+
+	var frames []Frame
+	for {
+		frames = append(frames, Frame{
+			PC:       pc,
+			Func:     nil,
+			Function: gostring(arg.funcName),
+			File:     gostring(arg.file),
+			Line:     int(arg.lineno),
+			Entry:    arg.entry,
+		})
+		if arg.more == 0 {
+			break
+		}
+		callCgoSymbolizer(&arg)
+	}
+
+	// No more frames for this PC. Tell the symbolizer we are done.
+	// We don't try to maintain a single cgoSymbolizerArg for the
+	// whole use of Frames, because there would be no good way to tell
+	// the symbolizer when we are done.
+	arg.pc = 0
+	callCgoSymbolizer(&arg)
+
+	if len(frames) == 1 {
+		// Return a single frame.
+		return frames[0], more
+	}
+
+	// Return the first frame we saw and store the rest to be
+	// returned by later calls to Next.
+	rf := frames[0]
+	frames = frames[1:]
+	ci.frames = new([]Frame)
+	*ci.frames = frames
+	return rf, true
+}
+
 // NOTE: Func does not expose the actual unexported fields, because we return *Func
 // values to users, and we want to keep them from being able to overwrite the data
 // with (say) *f = Func{}.
@@ -49,14 +193,18 @@ type moduledata struct {
 	bss, ebss             uintptr
 	noptrbss, enoptrbss   uintptr
 	end, gcdata, gcbss    uintptr
+	types, etypes         uintptr
 
-	typelinks []*_type
+	typelinks []int32 // offsets from types
+	itablinks []*itab
 
 	modulename   string
 	modulehashes []modulehash
 
 	gcdatamask, gcbssmask bitvector
 
+	typemap map[typeOff]*_type // offset to *_rtype in previous module
+
 	next *moduledata
 }
 
@@ -85,8 +233,8 @@ const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup tabl
 // 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
+// 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 {
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index ad3dca4..83f4709 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -201,6 +201,11 @@ systime:
 	MOVL	$0, 8(SP)	// time zone pointer
 	MOVL	$116, AX
 	INT	$0x80
+	CMPL	AX, $0
+	JNE	inreg
+	MOVL	12(SP), AX
+	MOVL	16(SP), DX
+inreg:
 	// sec is in AX, usec in DX
 	// convert to DX:AX nsec
 	MOVL	DX, BX
@@ -377,7 +382,7 @@ TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
 	POPL	AX
 	POPAL
 
-	// Now segment is established.  Initialize m, g.
+	// Now segment is established. Initialize m, g.
 	get_tls(BP)
 	MOVL    m_g0(DX), AX
 	MOVL	AX, g(BP)
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index 7b9cf6a..e09b906 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -155,10 +155,15 @@ timeloop:
 
 systime:
 	// Fall back to system call (usually first call in this thread).
-	MOVQ	SP, DI	// must be non-nil, unused
+	MOVQ	SP, DI
 	MOVQ	$0, SI
 	MOVL	$(0x2000000+116), AX
 	SYSCALL
+	CMPQ	AX, $0
+	JNE	inreg
+	MOVQ	0(SP), AX
+	MOVL	8(SP), DX
+inreg:
 	// sec is in AX, usec in DX
 	// return nsec in AX
 	IMULQ	$1000000000, AX
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 82a8db9..6b6437d 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -261,7 +261,7 @@ cont:
 	MOVW    R1, 24(R6)
 
 	// switch stack and g
-	MOVW	R6, R13 // sigtramp can not re-entrant, so no need to back up R13.
+	MOVW	R6, R13 // sigtramp is not re-entrant, so no need to back up R13.
 	MOVW	R5, g
 
 	BL	(R0)
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index d0034d5..a3b851d 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -245,7 +245,7 @@ cont:
 	MOVD	R1, 48(R6)
 
 	// switch stack and g
-	MOVD	R6, RSP	// sigtramp can not re-entrant, so no need to back up RSP.
+	MOVD	R6, RSP	// sigtramp is not re-entrant, so no need to back up RSP.
 	MOVD	R5, g
 
 	BL	(R0)
diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s
index 4e4d793..be964cb 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -52,11 +52,11 @@ TEXT runtime·lwp_start(SB),NOSPLIT,$0
 	MOVQ	DI, g(CX)
 
 	// On DragonFly, a new thread inherits the signal stack of the
-	// creating thread.  That confuses minit, so we remove that
-	// signal stack here before calling the regular mstart.  It's
+	// creating thread. That confuses minit, so we remove that
+	// signal stack here before calling the regular mstart. It's
 	// a bit baroque to remove a signal stack here only to add one
 	// in minit, but it's a simple change that keeps DragonFly
-	// working like other OS's.  At this point all signals are
+	// working like other OS's. At this point all signals are
 	// blocked, so there is no race.
 	SUBQ	$8, SP
 	MOVQ	$0, 0(SP)
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 4a74196..4fe07e0 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -232,6 +232,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
 	CALL	runtime·sigtrampgo(SB)
 	RET
 
+TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
+	JMP	runtime·sigtramp(SB)
+
 TEXT runtime·sigreturn(SB),NOSPLIT,$0
 	MOVL	$173, AX	// rt_sigreturn
 	// Sigreturn expects same SP as signal handler,
@@ -355,7 +358,7 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	POPL	AX
 	POPAL
 
-	// Now segment is established.  Initialize m, g.
+	// Now segment is established. Initialize m, g.
 	get_tls(AX)
 	MOVL	DX, g(AX)
 	MOVL	BX, g_m(DX)
@@ -406,9 +409,18 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
 #define SEG_NOT_PRESENT 0x20
 #define USEABLE 0x40
 
+// `-1` means the kernel will pick a TLS entry on the first setldt call,
+// which happens during runtime init, and that we'll store back the saved
+// entry and reuse that on subsequent calls when creating new threads.
+DATA  runtime·tls_entry_number+0(SB)/4, $-1
+GLOBL runtime·tls_entry_number(SB), NOPTR, $4
+
 // setldt(int entry, int address, int limit)
+// We use set_thread_area, which mucks with the GDT, instead of modify_ldt,
+// which would modify the LDT, but is disabled on some kernels.
+// The name, setldt, is a misnomer, although we leave this name as it is for
+// the compatibility with other platforms.
 TEXT runtime·setldt(SB),NOSPLIT,$32
-	MOVL	entry+0(FP), BX	// entry
 	MOVL	address+4(FP), DX	// base address
 
 #ifdef GOOS_android
@@ -437,18 +449,19 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
 	MOVL	DX, 0(DX)
 #endif
 
+	// get entry number
+	MOVL	runtime·tls_entry_number(SB), CX
+
 	// set up user_desc
 	LEAL	16(SP), AX	// struct user_desc
-	MOVL	BX, 0(AX)
-	MOVL	DX, 4(AX)
-	MOVL	$0xfffff, 8(AX)
+	MOVL	CX, 0(AX)	// unsigned int entry_number
+	MOVL	DX, 4(AX)	// unsigned long base_addr
+	MOVL	$0xfffff, 8(AX)	// unsigned int limit
 	MOVL	$(SEG_32BIT|LIMIT_IN_PAGES|USEABLE|CONTENTS_DATA), 12(AX)	// flag bits
 
-	// call modify_ldt
-	MOVL	$1, BX	// func = 1 (write)
-	MOVL	AX, CX	// user_desc
-	MOVL	$16, DX	// sizeof(user_desc)
-	MOVL	$123, AX	// syscall - modify_ldt
+	// call set_thread_area
+	MOVL	AX, BX	// user_desc
+	MOVL	$243, AX	// syscall - set_thread_area
 	// We can't call this via 0x10(GS) because this is called from setldt0 to set that up.
 	INT     $0x80
 
@@ -457,10 +470,18 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
 	JLS 2(PC)
 	INT $3
 
-	// compute segment selector - (entry*8+7)
-	MOVL	entry+0(FP), AX
+	// read allocated entry number back out of user_desc
+	LEAL	16(SP), AX	// get our user_desc back
+	MOVL	0(AX), AX
+
+	// store entry number if the kernel allocated it
+	CMPL	CX, $-1
+	JNE	2(PC)
+	MOVL	AX, runtime·tls_entry_number(SB)
+
+	// compute segment selector - (entry*8+3)
 	SHLL	$3, AX
-	ADDL	$7, AX
+	ADDL	$3, AX
 	MOVW	AX, GS
 
 	RET
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index f407078..8a8f3cc 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -234,8 +234,89 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$24
 	CALL AX
 	RET
 
+// Used instead of sigtramp in programs that use cgo.
+// Arguments from kernel are in DI, SI, DX.
+TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
+	// If no traceback function, do usual sigtramp.
+	MOVQ	runtime·cgoTraceback(SB), AX
+	TESTQ	AX, AX
+	JZ	sigtramp
+
+	// If no traceback support function, which means that
+	// runtime/cgo was not linked in, do usual sigtramp.
+	MOVQ	_cgo_callers(SB), AX
+	TESTQ	AX, AX
+	JZ	sigtramp
+
+	// Figure out if we are currently in a cgo call.
+	// If not, just do usual sigtramp.
+	get_tls(CX)
+	MOVQ	g(CX),AX
+	TESTQ	AX, AX
+	JZ	sigtrampnog     // g == nil
+	MOVQ	g_m(AX), AX
+	TESTQ	AX, AX
+	JZ	sigtramp        // g.m == nil
+	MOVL	m_ncgo(AX), CX
+	TESTL	CX, CX
+	JZ	sigtramp        // g.m.ncgo == 0
+	MOVQ	m_curg(AX), CX
+	TESTQ	CX, CX
+	JZ	sigtramp        // g.m.curg == nil
+	MOVQ	g_syscallsp(CX), CX
+	TESTQ	CX, CX
+	JZ	sigtramp        // g.m.curg.syscallsp == 0
+	MOVQ	m_cgoCallers(AX), R8
+	TESTQ	R8, R8
+	JZ	sigtramp        // g.m.cgoCallers == nil
+	MOVL	m_cgoCallersUse(AX), CX
+	TESTL	CX, CX
+	JNZ	sigtramp	// g.m.cgoCallersUse != 0
+
+	// Jump to a function in runtime/cgo.
+	// That function, written in C, will call the user's traceback
+	// function with proper unwind info, and will then call back here.
+	// The first three arguments, and the fifth, are already in registers.
+	// Set the two remaining arguments now.
+	MOVQ	runtime·cgoTraceback(SB), CX
+	MOVQ	$runtime·sigtramp(SB), R9
+	MOVQ	_cgo_callers(SB), AX
+	JMP	AX
+
+sigtramp:
+	JMP	runtime·sigtramp(SB)
+
+sigtrampnog:
+	// Signal arrived on a non-Go thread. If this is SIGPROF, get a
+	// stack trace.
+	CMPL	DI, $27 // 27 == SIGPROF
+	JNZ	sigtramp
+
+	// Lock sigprofCallersUse.
+	MOVL	$0, AX
+	MOVL	$1, CX
+	MOVQ	$runtime·sigprofCallersUse(SB), BX
+	LOCK
+	CMPXCHGL	CX, 0(BX)
+	JNZ	sigtramp  // Skip stack trace if already locked.
+
+	// Jump to the traceback function in runtime/cgo.
+	// It will call back to sigprofNonGo, which will ignore the
+	// arguments passed in registers.
+	// First three arguments to traceback function are in registers already.
+	MOVQ	runtime·cgoTraceback(SB), CX
+	MOVQ	$runtime·sigprofCallers(SB), R8
+	MOVQ	$runtime·sigprofNonGo(SB), R9
+	MOVQ	_cgo_callers(SB), AX
+	JMP	AX
+
+// For cgo unwinding to work, this function must look precisely like
+// the one in glibc.  The glibc source code is:
+// https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/x86_64/sigaction.c
+// The code that cares about the precise instructions used is:
+// https://gcc.gnu.org/viewcvs/gcc/trunk/libgcc/config/i386/linux-unwind.h?revision=219188&view=markup
 TEXT runtime·sigreturn(SB),NOSPLIT,$0
-	MOVL	$15, AX	// rt_sigreturn
+	MOVQ	$15, AX	// rt_sigreturn
 	SYSCALL
 	INT $3	// not reached
 
@@ -357,7 +438,7 @@ nog:
 	// Call fn
 	CALL	R12
 
-	// It shouldn't return.  If it does, exit that thread.
+	// It shouldn't return. If it does, exit that thread.
 	MOVL	$111, DI
 	MOVL	$60, AX
 	SYSCALL
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 6a3b924..5e5fcf0 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -313,7 +313,7 @@ nog:
 	MOVW	$16(R13), R13
 	BL	(R0)
 
-	// It shouldn't return.  If it does, exit that thread.
+	// 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)
@@ -361,6 +361,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
 	BL	(R11)
 	RET
 
+TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
+	MOVW  	$runtime·sigtramp(SB), R11
+	B	(R11)
+
 TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0
 	MOVW	sig+0(FP), R0
 	MOVW	new+4(FP), R1
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 94c101a..1bee847 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -259,6 +259,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$24
 	BL	(R0)
 	RET
 
+TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
+	MOVD	$runtime·sigtramp(SB), R3
+	B	(R3)
+
 TEXT runtime·mmap(SB),NOSPLIT,$-8
 	MOVD	addr+0(FP), R0
 	MOVD	n+8(FP), R1
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index 26437dd..d4a81ca 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -228,11 +228,16 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
 	MOVW	sig+8(FP), R4
 	MOVV	info+16(FP), R5
 	MOVV	ctx+24(FP), R6
-	MOVV	fn+0(FP), R1
-	JAL	(R1)
+	MOVV	fn+0(FP), R25
+	JAL	(R25)
 	RET
 
 TEXT runtime·sigtramp(SB),NOSPLIT,$64
+	// initialize REGSB = PC&0xffffffff00000000
+	BGEZAL	R0, 1(PC)
+	SRLV	$32, R31, RSB
+	SLLV	$32, RSB
+
 	// initialize essential registers (just in case)
 	JAL	runtime·reginit(SB)
 
@@ -249,6 +254,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
 	JAL	(R1)
 	RET
 
+TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
+	JMP	runtime·sigtramp(SB)
+
 TEXT runtime·mmap(SB),NOSPLIT,$-8
 	MOVV	addr+0(FP), R4
 	MOVV	n+8(FP), R5
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index d063e02..56b842a 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -243,6 +243,21 @@ TEXT runtime·_sigtramp(SB),NOSPLIT,$64
 	MOVD	24(R1), R2
 	RET
 
+#ifdef GOARCH_ppc64le
+// ppc64le doesn't need function descriptors
+TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
+#else
+// function descriptor for the real sigtramp
+TEXT runtime·cgoSigtramp(SB),NOSPLIT|NOFRAME,$0
+	DWORD	$runtime·_cgoSigtramp(SB)
+	DWORD	$0
+	DWORD	$0
+TEXT runtime·_cgoSigtramp(SB),NOSPLIT,$0
+#endif
+	MOVD	$runtime·sigtramp(SB), R12
+	MOVD	R12, CTR
+	JMP	(CTR)
+
 TEXT runtime·mmap(SB),NOSPLIT|NOFRAME,$0
 	MOVD	addr+0(FP), R3
 	MOVD	n+8(FP), R4
diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s
new file mode 100644
index 0000000..f43792b
--- /dev/null
+++ b/src/runtime/sys_linux_s390x.s
@@ -0,0 +1,440 @@
+// Copyright 2016 The Go 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 system stuff for Linux s390x; see
+// /usr/include/asm/unistd.h for the syscall number definitions.
+
+#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_mmap                 90
+#define SYS_munmap               91
+#define SYS_setitimer           104
+#define SYS_clone               120
+#define SYS_select              142
+#define SYS_sched_yield         158
+#define SYS_rt_sigreturn        173
+#define SYS_rt_sigaction        174
+#define SYS_rt_sigprocmask      175
+#define SYS_sigaltstack         186
+#define SYS_ugetrlimit          191
+#define SYS_madvise             219
+#define SYS_mincore             218
+#define SYS_gettid              236
+#define SYS_tkill               237
+#define SYS_futex               238
+#define SYS_sched_getaffinity   240
+#define SYS_exit_group          248
+#define SYS_epoll_create        249
+#define SYS_epoll_ctl           250
+#define SYS_epoll_wait          251
+#define SYS_clock_gettime       260
+#define SYS_epoll_create1       327
+
+TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0-4
+	MOVW	code+0(FP), R2
+	MOVW	$SYS_exit_group, R1
+	SYSCALL
+	RET
+
+TEXT runtime·exit1(SB),NOSPLIT|NOFRAME,$0-4
+	MOVW	code+0(FP), R2
+	MOVW	$SYS_exit, R1
+	SYSCALL
+	RET
+
+TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0-20
+	MOVD	name+0(FP), R2
+	MOVW	mode+8(FP), R3
+	MOVW	perm+12(FP), R4
+	MOVW	$SYS_open, R1
+	SYSCALL
+	MOVD	$-4095, R3
+	CMPUBLT	R2, R3, 2(PC)
+	MOVW	$-1, R2
+	MOVW	R2, ret+16(FP)
+	RET
+
+TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0-12
+	MOVW	fd+0(FP), R2
+	MOVW	$SYS_close, R1
+	SYSCALL
+	MOVD	$-4095, R3
+	CMPUBLT	R2, R3, 2(PC)
+	MOVW	$-1, R2
+	MOVW	R2, ret+8(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT|NOFRAME,$0-28
+	MOVD	fd+0(FP), R2
+	MOVD	p+8(FP), R3
+	MOVW	n+16(FP), R4
+	MOVW	$SYS_write, R1
+	SYSCALL
+	MOVD	$-4095, R3
+	CMPUBLT	R2, R3, 2(PC)
+	MOVW	$-1, R2
+	MOVW	R2, ret+24(FP)
+	RET
+
+TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0-28
+	MOVW	fd+0(FP), R2
+	MOVD	p+8(FP), R3
+	MOVW	n+16(FP), R4
+	MOVW	$SYS_read, R1
+	SYSCALL
+	MOVD	$-4095, R3
+	CMPUBLT	R2, R3, 2(PC)
+	MOVW	$-1, R2
+	MOVW	R2, ret+24(FP)
+	RET
+
+TEXT runtime·getrlimit(SB),NOSPLIT|NOFRAME,$0-20
+	MOVW	kind+0(FP), R2
+	MOVD	limit+8(FP), R3
+	MOVW	$SYS_ugetrlimit, R1
+	SYSCALL
+	MOVW	R2, ret+16(FP)
+	RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$16-4
+	MOVW	usec+0(FP), R2
+	MOVD	R2, R4
+	MOVW	$1000000, R3
+	DIVD	R3, R2
+	MOVD	R2, 8(R15)
+	MULLD	R2, R3
+	SUB	R3, R4
+	MOVD	R4, 16(R15)
+
+	// select(0, 0, 0, 0, &tv)
+	MOVW	$0, R2
+	MOVW	$0, R3
+	MOVW	$0, R4
+	MOVW	$0, R5
+	ADD	$8, R15, R6
+	MOVW	$SYS_select, R1
+	SYSCALL
+	RET
+
+TEXT runtime·gettid(SB),NOSPLIT,$0-4
+	MOVW	$SYS_gettid, R1
+	SYSCALL
+	MOVW	R2, ret+0(FP)
+	RET
+
+TEXT runtime·raise(SB),NOSPLIT|NOFRAME,$0
+	MOVW	$SYS_gettid, R1
+	SYSCALL
+	MOVW	R2, R2	// arg 1 tid
+	MOVW	sig+0(FP), R3	// arg 2
+	MOVW	$SYS_tkill, R1
+	SYSCALL
+	RET
+
+TEXT runtime·raiseproc(SB),NOSPLIT|NOFRAME,$0
+	MOVW	$SYS_getpid, R1
+	SYSCALL
+	MOVW	R2, R2	// arg 1 pid
+	MOVW	sig+0(FP), R3	// arg 2
+	MOVW	$SYS_kill, R1
+	SYSCALL
+	RET
+
+TEXT runtime·setitimer(SB),NOSPLIT|NOFRAME,$0-24
+	MOVW	mode+0(FP), R2
+	MOVD	new+8(FP), R3
+	MOVD	old+16(FP), R4
+	MOVW	$SYS_setitimer, R1
+	SYSCALL
+	RET
+
+TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
+	MOVD	addr+0(FP), R2
+	MOVD	n+8(FP), R3
+	MOVD	dst+16(FP), R4
+	MOVW	$SYS_mincore, R1
+	SYSCALL
+	MOVW	R2, ret+24(FP)
+	RET
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB),NOSPLIT,$16
+	MOVD	$0(R15), R2
+	MOVD	$0, R3
+	MOVW	$SYS_gettimeofday, R1
+	SYSCALL
+	MOVD	0(R15), R2	// sec
+	MOVD	8(R15), R4	// usec
+	MOVD	$1000, R3
+	MULLD	R3, R4
+	MOVD	R2, sec+0(FP)
+	MOVW	R4, nsec+8(FP)
+	RET
+
+TEXT runtime·nanotime(SB),NOSPLIT,$16
+	MOVW	$1, R2 // CLOCK_MONOTONIC
+	MOVD	$0(R15), R3
+	MOVW	$SYS_clock_gettime, R1
+	SYSCALL
+	MOVD	0(R15), R2	// sec
+	MOVD	8(R15), R4	// nsec
+	// sec is in R2, nsec in R4
+	// return nsec in R2
+	MOVD	$1000000000, R3
+	MULLD	R3, R2
+	ADD	R4, R2
+	MOVD	R2, ret+0(FP)
+	RET
+
+TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
+	MOVW	sig+0(FP), R2
+	MOVD	new+8(FP), R3
+	MOVD	old+16(FP), R4
+	MOVW	size+24(FP), R5
+	MOVW	$SYS_rt_sigprocmask, R1
+	SYSCALL
+	MOVD	$-4095, R3
+	CMPUBLT	R2, R3, 2(PC)
+	MOVD	R0, 0(R0) // crash
+	RET
+
+TEXT runtime·rt_sigaction(SB),NOSPLIT|NOFRAME,$0-36
+	MOVD	sig+0(FP), R2
+	MOVD	new+8(FP), R3
+	MOVD	old+16(FP), R4
+	MOVD	size+24(FP), R5
+	MOVW	$SYS_rt_sigaction, R1
+	SYSCALL
+	MOVW	R2, ret+32(FP)
+	RET
+
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+	MOVW	sig+8(FP), R2
+	MOVD	info+16(FP), R3
+	MOVD	ctx+24(FP), R4
+	MOVD	fn+0(FP), R5
+	BL	R5
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$64
+	// initialize essential registers (just in case)
+	XOR	R0, R0
+
+	// this might be called in external code context,
+	// where g is not set.
+	MOVB	runtime·iscgo(SB), R6
+	CMPBEQ	R6, $0, 2(PC)
+	BL	runtime·load_g(SB)
+
+	MOVW	R2, 8(R15)
+	MOVD	R3, 16(R15)
+	MOVD	R4, 24(R15)
+	MOVD	$runtime·sigtrampgo(SB), R5
+	BL	R5
+	RET
+
+TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
+	BR	runtime·sigtramp(SB)
+
+// func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
+TEXT runtime·mmap(SB),NOSPLIT,$48-40
+	MOVD	addr+0(FP), R2
+	MOVD	n+8(FP), R3
+	MOVW	prot+16(FP), R4
+	MOVW	flags+20(FP), R5
+	MOVW	fd+24(FP), R6
+	MOVWZ	off+28(FP), R7
+
+	// s390x uses old_mmap, so the arguments need to be placed into
+	// a struct and a pointer to the struct passed to mmap.
+	MOVD	R2, addr-48(SP)
+	MOVD	R3, n-40(SP)
+	MOVD	R4, prot-32(SP)
+	MOVD	R5, flags-24(SP)
+	MOVD	R6, fd-16(SP)
+	MOVD	R7, off-8(SP)
+
+	MOVD	$addr-48(SP), R2
+	MOVW	$SYS_mmap, R1
+	SYSCALL
+	MOVD	$-4095, R3
+	CMPUBLT	R2, R3, 2(PC)
+	NEG	R2
+	MOVD	R2, ret+32(FP)
+	RET
+
+TEXT runtime·munmap(SB),NOSPLIT|NOFRAME,$0
+	MOVD	addr+0(FP), R2
+	MOVD	n+8(FP), R3
+	MOVW	$SYS_munmap, R1
+	SYSCALL
+	MOVD	$-4095, R3
+	CMPUBLT	R2, R3, 2(PC)
+	MOVD	R0, 0(R0) // crash
+	RET
+
+TEXT runtime·madvise(SB),NOSPLIT|NOFRAME,$0
+	MOVD	addr+0(FP), R2
+	MOVD	n+8(FP), R3
+	MOVW	flags+16(FP), R4
+	MOVW	$SYS_madvise, R1
+	SYSCALL
+	// 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|NOFRAME,$0
+	MOVD	addr+0(FP), R2
+	MOVW	op+8(FP), R3
+	MOVW	val+12(FP), R4
+	MOVD	ts+16(FP), R5
+	MOVD	addr2+24(FP), R6
+	MOVW	val3+32(FP),  R7
+	MOVW	$SYS_futex, R1
+	SYSCALL
+	MOVW	R2, ret+40(FP)
+	RET
+
+// int32 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
+TEXT runtime·clone(SB),NOSPLIT|NOFRAME,$0
+	MOVW	flags+0(FP), R3
+	MOVD	stk+8(FP), R2
+
+	// 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), R9
+
+	MOVD	R7, -8(R2)
+	MOVD	R8, -16(R2)
+	MOVD	R9, -24(R2)
+	MOVD	$1234, R7
+	MOVD	R7, -32(R2)
+
+	SYSCALL $SYS_clone
+
+	// In parent, return.
+	CMPBEQ	R2, $0, 3(PC)
+	MOVW	R2, ret+40(FP)
+	RET
+
+	// In child, on new stack.
+	// initialize essential registers
+	XOR	R0, R0
+	MOVD	-32(R15), R7
+	CMP	R7, $1234
+	BEQ	2(PC)
+	MOVD	R0, 0(R0)
+
+	// Initialize m->procid to Linux tid
+	SYSCALL $SYS_gettid
+
+	MOVD	-24(R15), R9        // fn
+	MOVD	-16(R15), R8        // g
+	MOVD	-8(R15), R7         // m
+
+	CMPBEQ	R7, $0, nog
+	CMP	R8, $0
+	BEQ	nog
+
+	MOVD	R2, m_procid(R7)
+
+	// In child, set up new stack
+	MOVD	R7, g_m(R8)
+	MOVD	R8, g
+	//CALL	runtime·stackcheck(SB)
+
+nog:
+	// Call fn
+	BL	R9
+
+	// It shouldn't return.	 If it does, exit that thread.
+	MOVW	$111, R2
+	MOVW	$SYS_exit, R1
+	SYSCALL
+	BR	-2(PC)	// keep exiting
+
+TEXT runtime·sigaltstack(SB),NOSPLIT|NOFRAME,$0
+	MOVD	new+0(FP), R2
+	MOVD	old+8(FP), R3
+	MOVW	$SYS_sigaltstack, R1
+	SYSCALL
+	MOVD	$-4095, R3
+	CMPUBLT	R2, R3, 2(PC)
+	MOVD	R0, 0(R0) // crash
+	RET
+
+TEXT runtime·osyield(SB),NOSPLIT|NOFRAME,$0
+	MOVW	$SYS_sched_yield, R1
+	SYSCALL
+	RET
+
+TEXT runtime·sched_getaffinity(SB),NOSPLIT|NOFRAME,$0
+	MOVD	pid+0(FP), R2
+	MOVD	len+8(FP), R3
+	MOVD	buf+16(FP), R4
+	MOVW	$SYS_sched_getaffinity, R1
+	SYSCALL
+	MOVW	R2, ret+24(FP)
+	RET
+
+// int32 runtime·epollcreate(int32 size);
+TEXT runtime·epollcreate(SB),NOSPLIT|NOFRAME,$0
+	MOVW    size+0(FP), R2
+	MOVW	$SYS_epoll_create, R1
+	SYSCALL
+	MOVW	R2, ret+8(FP)
+	RET
+
+// int32 runtime·epollcreate1(int32 flags);
+TEXT runtime·epollcreate1(SB),NOSPLIT|NOFRAME,$0
+	MOVW	flags+0(FP), R2
+	MOVW	$SYS_epoll_create1, R1
+	SYSCALL
+	MOVW	R2, ret+8(FP)
+	RET
+
+// func epollctl(epfd, op, fd int32, ev *epollEvent) int
+TEXT runtime·epollctl(SB),NOSPLIT|NOFRAME,$0
+	MOVW	epfd+0(FP), R2
+	MOVW	op+4(FP), R3
+	MOVW	fd+8(FP), R4
+	MOVD	ev+16(FP), R5
+	MOVW	$SYS_epoll_ctl, R1
+	SYSCALL
+	MOVW	R2, ret+24(FP)
+	RET
+
+// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
+TEXT runtime·epollwait(SB),NOSPLIT|NOFRAME,$0
+	MOVW	epfd+0(FP), R2
+	MOVD	ev+8(FP), R3
+	MOVW	nev+16(FP), R4
+	MOVW	timeout+20(FP), R5
+	MOVW	$SYS_epoll_wait, R1
+	SYSCALL
+	MOVW	R2, ret+24(FP)
+	RET
+
+// void runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),NOSPLIT|NOFRAME,$0
+	MOVW    fd+0(FP), R2  // fd
+	MOVD    $2, R3  // F_SETFD
+	MOVD    $1, R4  // FD_CLOEXEC
+	MOVW	$SYS_fcntl, R1
+	SYSCALL
+	RET
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index 3b3c109..0322c36 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -262,7 +262,7 @@ TEXT runtime·lwp_tramp(SB),NOSPLIT,$0
 	POPL	AX
 	POPAL
 
-	// Now segment is established.  Initialize m, g.
+	// Now segment is established. Initialize m, g.
 	get_tls(AX)
 	MOVL	DX, g(AX)
 	MOVL	BX, g_m(DX)
diff --git a/src/runtime/sys_netbsd_amd64.s b/src/runtime/sys_netbsd_amd64.s
index fb21f11..d6b5d35 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -37,7 +37,7 @@ TEXT runtime·lwp_tramp(SB),NOSPLIT,$0
 	// Call fn
 	CALL	R12
 
-	// It shouldn't return.  If it does, exit.
+	// It shouldn't return. If it does, exit.
 	MOVL	$310, AX		// sys__lwp_exit
 	SYSCALL
 	JMP	-3(PC)			// keep exiting
diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s
index 769b2f9..2bb818f 100644
--- a/src/runtime/sys_openbsd_386.s
+++ b/src/runtime/sys_openbsd_386.s
@@ -214,14 +214,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
 	MOVL	context+8(FP), BX
 	MOVL	BX, 8(SP)
 	CALL	runtime·sigtrampgo(SB)
-
-	// call sigreturn
-	MOVL	context+8(FP), AX
-	MOVL	$0, 0(SP)		// syscall gap
-	MOVL	AX, 4(SP)		// arg 1 - sigcontext
-	MOVL	$103, AX		// sys_sigreturn
-	INT	$0x80
-	MOVL	$0xf1, 0xf1		// crash
 	RET
 
 // int32 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
@@ -279,7 +271,7 @@ TEXT runtime·tfork(SB),NOSPLIT,$12
 	POPL	AX
 	POPAL
 	
-	// Now segment is established.  Initialize m, g.
+	// Now segment is established. Initialize m, g.
 	get_tls(AX)
 	MOVL	DX, g(AX)
 	MOVL	BX, g_m(DX)
diff --git a/src/runtime/sys_openbsd_amd64.s b/src/runtime/sys_openbsd_amd64.s
index ed368ba..c9fb832 100644
--- a/src/runtime/sys_openbsd_amd64.s
+++ b/src/runtime/sys_openbsd_amd64.s
@@ -50,7 +50,7 @@ TEXT runtime·tfork(SB),NOSPLIT,$32
 	// Call fn
 	CALL	R12
 
-	// It shouldn't return.  If it does, exit
+	// It shouldn't return. If it does, exit
 	MOVQ	$0, DI			// arg 1 - notdead
 	MOVL	$302, AX		// sys___threxit
 	SYSCALL
diff --git a/src/runtime/sys_plan9_arm.s b/src/runtime/sys_plan9_arm.s
new file mode 100644
index 0000000..6dee611
--- /dev/null
+++ b/src/runtime/sys_plan9_arm.s
@@ -0,0 +1,318 @@
+// Copyright 2015 The Go 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 "textflag.h"
+
+// from ../syscall/zsysnum_plan9.go
+
+#define SYS_SYSR1       0
+#define SYS_BIND        2
+#define SYS_CHDIR       3
+#define SYS_CLOSE       4
+#define SYS_DUP         5
+#define SYS_ALARM       6
+#define SYS_EXEC        7
+#define SYS_EXITS       8
+#define SYS_FAUTH       10
+#define SYS_SEGBRK      12
+#define SYS_OPEN        14
+#define SYS_OSEEK       16
+#define SYS_SLEEP       17
+#define SYS_RFORK       19
+#define SYS_PIPE        21
+#define SYS_CREATE      22
+#define SYS_FD2PATH     23
+#define SYS_BRK_        24
+#define SYS_REMOVE      25
+#define SYS_NOTIFY      28
+#define SYS_NOTED       29
+#define SYS_SEGATTACH   30
+#define SYS_SEGDETACH   31
+#define SYS_SEGFREE     32
+#define SYS_SEGFLUSH    33
+#define SYS_RENDEZVOUS  34
+#define SYS_UNMOUNT     35
+#define SYS_SEMACQUIRE  37
+#define SYS_SEMRELEASE  38
+#define SYS_SEEK        39
+#define SYS_FVERSION    40
+#define SYS_ERRSTR      41
+#define SYS_STAT        42
+#define SYS_FSTAT       43
+#define SYS_WSTAT       44
+#define SYS_FWSTAT      45
+#define SYS_MOUNT       46
+#define SYS_AWAIT       47
+#define SYS_PREAD       50
+#define SYS_PWRITE      51
+#define SYS_TSEMACQUIRE 52
+#define SYS_NSEC        53
+
+//func open(name *byte, mode, perm int32) int32
+TEXT runtime·open(SB),NOSPLIT,$0-16
+	MOVW    $SYS_OPEN, R0
+	SWI	0
+	MOVW	R0, ret+12(FP)
+	RET
+
+//func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
+TEXT runtime·pread(SB),NOSPLIT,$0-24
+	MOVW    $SYS_PREAD, R0
+	SWI	0
+	MOVW	R0, ret+20(FP)
+	RET
+
+//func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
+TEXT runtime·pwrite(SB),NOSPLIT,$0-24
+	MOVW    $SYS_PWRITE, R0
+	SWI	0
+	MOVW	R0, ret+20(FP)
+	RET
+
+//func seek(fd int32, offset int64, whence int32) int64
+TEXT runtime·seek(SB),NOSPLIT,$0-24
+	MOVW	$ret_lo+16(FP), R0
+	MOVW	0(R13), R1
+	MOVW	R0, 0(R13)
+	MOVW.W	R1, -4(R13)
+	MOVW	$SYS_SEEK, R0
+	SWI	0
+	MOVW.W	R1, 4(R13)
+	CMP	$-1, R0
+	MOVW.EQ	R0, ret_lo+16(FP)
+	MOVW.EQ	R0, ret_hi+20(FP)
+	RET
+
+//func closefd(fd int32) int32
+TEXT runtime·closefd(SB),NOSPLIT,$0-8
+	MOVW	$SYS_CLOSE, R0
+	SWI	0
+	MOVW	R0, ret+4(FP)
+	RET
+
+//func exits(msg *byte)
+TEXT runtime·exits(SB),NOSPLIT,$0-4
+	MOVW    $SYS_EXITS, R0
+	SWI	0
+	RET
+
+//func brk_(addr unsafe.Pointer) int32
+TEXT runtime·brk_(SB),NOSPLIT,$0-8
+	MOVW    $SYS_BRK_, R0
+	SWI	0
+	MOVW	R0, ret+4(FP)
+	RET
+
+//func sleep(ms int32) int32
+TEXT runtime·sleep(SB),NOSPLIT,$0-8
+	MOVW    $SYS_SLEEP, R0
+	SWI	0
+	MOVW	R0, ret+4(FP)
+	RET
+
+//func plan9_semacquire(addr *uint32, block int32) int32
+TEXT runtime·plan9_semacquire(SB),NOSPLIT,$0-12
+	MOVW	$SYS_SEMACQUIRE, R0
+	SWI	0
+	MOVW	R0, ret+8(FP)
+	RET
+
+//func plan9_tsemacquire(addr *uint32, ms int32) int32
+TEXT runtime·plan9_tsemacquire(SB),NOSPLIT,$0-12
+	MOVW	$SYS_TSEMACQUIRE, R0
+	SWI	0
+	MOVW	R0, ret+8(FP)
+	RET
+
+//func nsec(*int64) int64
+TEXT runtime·nsec(SB),NOSPLIT,$-4-12
+	MOVW	$SYS_NSEC, R0
+	SWI	0
+	MOVW	unnamed+0(FP), R1
+	MOVW	0(R1), R0
+	MOVW	R0, ret_lo+4(FP)
+	MOVW	4(R1), R0
+	MOVW	R0, ret_hi+8(FP)
+	RET
+
+// time.now() (sec int64, nsec int32)
+TEXT time·now(SB),NOSPLIT,$12-12
+	// use nsec system call to get current time in nanoseconds
+	MOVW	$sysnsec_lo-8(SP), R0	// destination addr
+	MOVW	R0,res-12(SP)
+	MOVW	$SYS_NSEC, R0
+	SWI	0
+	MOVW	sysnsec_lo-8(SP), R1	// R1:R2 = nsec
+	MOVW	sysnsec_hi-4(SP), R2
+
+	// multiply nanoseconds by reciprocal of 10**9 (scaled by 2**61)
+	// to get seconds (96 bit scaled result)
+	MOVW	$0x89705f41, R3		// 2**61 * 10**-9
+	MULLU	R1,R3,(R6,R5)		// R5:R6:R7 = R1:R2 * R3
+	MOVW	$0,R7
+	MULALU	R2,R3,(R7,R6)
+
+	// unscale by discarding low 32 bits, shifting the rest by 29
+	MOVW	R6>>29,R6		// R6:R7 = (R5:R6:R7 >> 61)
+	ORR	R7<<3,R6
+	MOVW	R7>>29,R7
+
+	// subtract (10**9 * sec) from nsec to get nanosecond remainder
+	MOVW	$1000000000, R5		// 10**9
+	MULLU	R6,R5,(R9,R8)		// R8:R9 = R6:R7 * R5
+	MULA	R7,R5,R9,R9
+	SUB.S	R8,R1			// R1:R2 -= R8:R9
+	SBC	R9,R2
+
+	// because reciprocal was a truncated repeating fraction, quotient
+	// may be slightly too small -- adjust to make remainder < 10**9
+	CMP	R5,R1			// if remainder > 10**9
+	SUB.HS	R5,R1			//    remainder -= 10**9
+	ADD.HS	$1,R6			//    sec += 1
+
+	MOVW	R6,sec_lo+0(FP)
+	MOVW	R7,sec_hi+4(FP)
+	MOVW	R1,nsec+8(FP)
+	RET
+
+//func notify(fn unsafe.Pointer) int32
+TEXT runtime·notify(SB),NOSPLIT,$0-8
+	MOVW	$SYS_NOTIFY, R0
+	SWI	0
+	MOVW	R0, ret+4(FP)
+	RET
+
+//func noted(mode int32) int32
+TEXT runtime·noted(SB),NOSPLIT,$0-8
+	MOVW	$SYS_NOTED, R0
+	SWI	0
+	MOVW	R0, ret+4(FP)
+	RET
+
+//func plan9_semrelease(addr *uint32, count int32) int32
+TEXT runtime·plan9_semrelease(SB),NOSPLIT,$0-12
+	MOVW	$SYS_SEMRELEASE, R0
+	SWI	0
+	MOVW	R0, ret+8(FP)
+	RET
+
+//func rfork(flags int32) int32
+TEXT runtime·rfork(SB),NOSPLIT,$0-8
+	MOVW	$SYS_RFORK, R0
+	SWI	0
+	MOVW	R0, ret+4(FP)
+	RET
+
+//func tstart_plan9(newm *m)
+TEXT runtime·tstart_plan9(SB),NOSPLIT,$0-4
+	MOVW	newm+0(FP), R1
+	MOVW	m_g0(R1), g
+
+	// Layout new m scheduler stack on os stack.
+	MOVW	R13, R0
+	MOVW	R0, g_stack+stack_hi(g)
+	SUB	$(64*1024), R0
+	MOVW	R0, (g_stack+stack_lo)(g)
+	MOVW	R0, g_stackguard0(g)
+	MOVW	R0, g_stackguard1(g)
+
+	// Initialize procid from TOS struct.
+	MOVW	_tos(SB), R0
+	MOVW	48(R0), R0
+	MOVW	R0, m_procid(R1)	// save pid as m->procid
+
+	BL	runtime·mstart(SB)
+
+	MOVW	$0x1234, R0
+	MOVW	R0, 0(R0)		// not reached
+	RET
+
+//func sigtramp(ureg, msg unsafe.Pointer)
+TEXT runtime·sigtramp(SB),NOSPLIT,$0-8
+	// check that g and m exist
+	CMP	$0, g
+	BEQ	4(PC)
+	MOVW	g_m(g), R0
+	CMP 	$0, R0
+	BNE	2(PC)
+	BL	runtime·badsignal2(SB)	// will exit
+
+	// save args
+	MOVW	ureg+0(FP), R1
+	MOVW	msg+4(FP), R2
+
+	// change stack
+	MOVW	m_gsignal(R0), R3
+	MOVW	(g_stack+stack_hi)(R3), R13
+
+	// make room for args, retval and g
+	SUB	$24, R13
+
+	// save g
+	MOVW	g, R3
+	MOVW	R3, 20(R13)
+
+	// g = m->gsignal
+	MOVW	m_gsignal(R0), g
+
+	// load args and call sighandler
+	ADD	$4,R13,R5
+	MOVM.IA	[R1-R3], (R5)
+	BL	runtime·sighandler(SB)
+	MOVW	16(R13), R0			// retval
+
+	// restore g
+	MOVW	20(R13), g
+
+	// call noted(R0)
+	MOVW	R0, 4(R13)
+	BL	runtime·noted(SB)
+	RET
+
+//func sigpanictramp()
+TEXT  runtime·sigpanictramp(SB),NOSPLIT,$0-0
+	MOVW.W	R0, -4(R13)
+	B	runtime·sigpanic(SB)
+
+//func setfpmasks()
+// Only used by the 64-bit runtime.
+TEXT runtime·setfpmasks(SB),NOSPLIT,$0
+	RET
+
+#define ERRMAX 128	/* from os_plan9.h */
+
+// func errstr() string
+// Only used by package syscall.
+// Grab error string due to a syscall made
+// in entersyscall mode, without going
+// through the allocator (issue 4994).
+// See ../syscall/asm_plan9_arm.s:/·Syscall/
+TEXT runtime·errstr(SB),NOSPLIT,$0-8
+	MOVW	g_m(g), R0
+	MOVW	(m_mOS+mOS_errstr)(R0), R1
+	MOVW	R1, ret_base+0(FP)
+	MOVW	$ERRMAX, R2
+	MOVW	R2, ret_len+4(FP)
+	MOVW    $SYS_ERRSTR, R0
+	SWI	0
+	MOVW	R1, R2
+	MOVBU	0(R2), R0
+	CMP	$0, R0
+	BEQ	3(PC)
+	ADD	$1, R2
+	B	-4(PC)
+	SUB	R1, R2
+	MOVW	R2, ret_len+4(FP)
+	RET
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
+	B	runtime·armPublicationBarrier(SB)
+
+// never called (cgo not supported)
+TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
+	MOVW	$0, R0
+	MOVW	R0, (R0)
+	RET
diff --git a/src/runtime/sys_s390x.go b/src/runtime/sys_s390x.go
new file mode 100644
index 0000000..2aa81e7
--- /dev/null
+++ b/src/runtime/sys_s390x.go
@@ -0,0 +1,45 @@
+// Copyright 2016 The Go Authors. 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 uint64
+	if buf.pc&1 == 0 && buf.pc != 0 {
+		inst = *(*uint64)(unsafe.Pointer(buf.pc))
+		switch inst >> 48 {
+		case 0xa7f4: // BRC (branch relative on condition) instruction.
+			inst >>= 32
+			inst &= 0xFFFF
+			offset := int64(int16(inst))
+			offset <<= 1
+			buf.pc += uintptr(offset)
+			return
+		case 0xc0f4: // BRCL (branch relative on condition long) instruction.
+			inst >>= 16
+			inst = inst & 0xFFFFFFFF
+			inst = (inst << 1) & 0xFFFFFFFF
+			buf.pc += uintptr(int32(inst))
+			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 3a82674..07a7ace 100644
--- a/src/runtime/sys_solaris_amd64.s
+++ b/src/runtime/sys_solaris_amd64.s
@@ -52,7 +52,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0
 // pipe(3c) wrapper that returns fds in AX, DX.
 // NOT USING GO CALLING CONVENTION.
 TEXT runtime·pipe1(SB),NOSPLIT,$0
-	SUBQ	$16, SP // 8 bytes will do, but stack has to be 16-byte alligned
+	SUBQ	$16, SP // 8 bytes will do, but stack has to be 16-byte aligned
 	MOVQ	SP, DI
 	LEAQ	libc_pipe(SB), AX
 	CALL	AX
@@ -173,7 +173,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
 	MOVQ	g(BX), R10
 	CMPQ	R10, $0
 	JNE	allgood
+	MOVQ	SI, 80(SP)
+	MOVQ	DX, 88(SP)
+	LEAQ	80(SP), AX
 	MOVQ	DI, 0(SP)
+	MOVQ	AX, 8(SP)
 	MOVQ	$runtime·badsignal(SB), AX
 	CALL	AX
 	JMP	exit
diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
index 55cdcf4..95130b7 100644
--- a/src/runtime/sys_windows_386.s
+++ b/src/runtime/sys_windows_386.s
@@ -358,10 +358,11 @@ TEXT runtime·setldt(SB),NOSPLIT,$0
 	MOVL	CX, 0x14(FS)
 	RET
 
-// Sleep duration is in 100ns units.
-TEXT runtime·usleep1(SB),NOSPLIT,$0
-	MOVL	usec+0(FP), BX
-	MOVL	$runtime·usleep2(SB), AX // to hide from 8l
+// onosstack calls fn on OS stack.
+// func onosstack(fn unsafe.Pointer, arg uint32)
+TEXT runtime·onosstack(SB),NOSPLIT,$0
+	MOVL	fn+0(FP), AX		// to hide from 8l
+	MOVL	arg+4(FP), BX
 
 	// Execute call on m->g0 stack, in case we are not actually
 	// calling a system call wrapper, like when running under WINE.
@@ -423,6 +424,14 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20
 	MOVL	BP, SP
 	RET
 
+// Runs on OS stack.
+TEXT runtime·switchtothread(SB),NOSPLIT,$0
+	MOVL	SP, BP
+	MOVL	runtime·_SwitchToThread(SB), AX
+	CALL	AX
+	MOVL	BP, SP
+	RET
+
 // func now() (sec int64, nsec int32)
 TEXT time·now(SB),NOSPLIT,$8-12
 	CALL	runtime·unixnano(SB)
diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
index caa18e6..9c19737 100644
--- a/src/runtime/sys_windows_amd64.s
+++ b/src/runtime/sys_windows_amd64.s
@@ -11,7 +11,7 @@
 #define maxargs 16
 
 // void runtime·asmstdcall(void *c);
-TEXT runtime·asmstdcall(SB),NOSPLIT,$0
+TEXT runtime·asmstdcall(SB),NOSPLIT|NOFRAME,$0
 	// asmcgocall will put first argument into CX.
 	PUSHQ	CX			// save for later
 	MOVQ	libcall_fn(CX), AX
@@ -62,7 +62,7 @@ loadregs:
 
 	RET
 
-TEXT runtime·badsignal2(SB),NOSPLIT,$48
+TEXT runtime·badsignal2(SB),NOSPLIT|NOFRAME,$48
 	// stderr
 	MOVQ	$-12, CX // stderr
 	MOVQ	CX, 0(SP)
@@ -102,7 +102,7 @@ TEXT runtime·setlasterror(SB),NOSPLIT,$0
 // exception record and context pointers.
 // Handler function is stored in AX.
 // Return 0 for 'not handled', -1 for handled.
-TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
+TEXT runtime·sigtramp(SB),NOSPLIT|NOFRAME,$0-0
 	// CX: PEXCEPTION_POINTERS ExceptionInfo
 
 	// DI SI BP BX R12 R13 R14 R15 registers and DF flag are preserved
@@ -190,32 +190,32 @@ done:
 
 	RET
 
-TEXT runtime·exceptiontramp(SB),NOSPLIT,$0
+TEXT runtime·exceptiontramp(SB),NOSPLIT|NOFRAME,$0
 	MOVQ	$runtime·exceptionhandler(SB), AX
 	JMP	runtime·sigtramp(SB)
 
-TEXT runtime·firstcontinuetramp(SB),NOSPLIT,$0-0
+TEXT runtime·firstcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
 	MOVQ	$runtime·firstcontinuehandler(SB), AX
 	JMP	runtime·sigtramp(SB)
 
-TEXT runtime·lastcontinuetramp(SB),NOSPLIT,$0-0
+TEXT runtime·lastcontinuetramp(SB),NOSPLIT|NOFRAME,$0-0
 	MOVQ	$runtime·lastcontinuehandler(SB), AX
 	JMP	runtime·sigtramp(SB)
 
-TEXT runtime·ctrlhandler(SB),NOSPLIT,$8
+TEXT runtime·ctrlhandler(SB),NOSPLIT|NOFRAME,$8
 	MOVQ	CX, 16(SP)		// spill
 	MOVQ	$runtime·ctrlhandler1(SB), CX
 	MOVQ	CX, 0(SP)
 	CALL	runtime·externalthreadhandler(SB)
 	RET
 
-TEXT runtime·profileloop(SB),NOSPLIT,$8
+TEXT runtime·profileloop(SB),NOSPLIT|NOFRAME,$8
 	MOVQ	$runtime·profileloop1(SB), CX
 	MOVQ	CX, 0(SP)
 	CALL	runtime·externalthreadhandler(SB)
 	RET
 
-TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
+TEXT runtime·externalthreadhandler(SB),NOSPLIT|NOFRAME,$0
 	PUSHQ	BP
 	MOVQ	SP, BP
 	PUSHQ	BX
@@ -228,7 +228,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
 	SUBQ	$m__size, SP		// space for M
 	MOVQ	SP, 0(SP)
 	MOVQ	$m__size, 8(SP)
-	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
+	CALL	runtime·memclr(SB)	// smashes AX,BX,CX, maybe BP
 
 	LEAQ	m_tls(SP), CX
 	MOVQ	CX, 0x28(GS)
@@ -239,7 +239,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
 
 	MOVQ	SP, 0(SP)
 	MOVQ	$g__size, 8(SP)
-	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
+	CALL	runtime·memclr(SB)	// smashes AX,BX,CX, maybe BP
 	LEAQ	g__size(SP), BX
 	MOVQ	BX, g_m(SP)
 
@@ -381,10 +381,10 @@ TEXT runtime·settls(SB),NOSPLIT,$0
 	MOVQ	DI, 0x28(GS)
 	RET
 
-// Sleep duration is in 100ns units.
-TEXT runtime·usleep1(SB),NOSPLIT,$0
-	MOVL	usec+0(FP), BX
-	MOVQ	$runtime·usleep2(SB), AX // to hide from 6l
+// func onosstack(fn unsafe.Pointer, arg uint32)
+TEXT runtime·onosstack(SB),NOSPLIT,$0
+	MOVQ	fn+0(FP), AX		// to hide from 6l
+	MOVL	arg+8(FP), BX
 
 	// Execute call on m->g0 stack, in case we are not actually
 	// calling a system call wrapper, like when running under WINE.
@@ -430,7 +430,7 @@ ret:
 // Runs on OS stack. duration (in 100ns units) is in BX.
 // The function leaves room for 4 syscall parameters
 // (as per windows amd64 calling convention).
-TEXT runtime·usleep2(SB),NOSPLIT,$48
+TEXT runtime·usleep2(SB),NOSPLIT|NOFRAME,$48
 	MOVQ	SP, AX
 	ANDQ	$~15, SP	// alignment as per Windows requirement
 	MOVQ	AX, 40(SP)
@@ -445,6 +445,18 @@ TEXT runtime·usleep2(SB),NOSPLIT,$48
 	MOVQ	40(SP), SP
 	RET
 
+// Runs on OS stack.
+TEXT runtime·switchtothread(SB),NOSPLIT|NOFRAME,$0
+	MOVQ	SP, AX
+	ANDQ	$~15, SP	// alignment as per Windows requirement
+	SUBQ	$(48), SP	// room for SP and 4 args as per Windows requirement
+				// plus one extra word to keep stack 16 bytes aligned
+	MOVQ	AX, 32(SP)
+	MOVQ	runtime·_SwitchToThread(SB), AX
+	CALL	AX
+	MOVQ	32(SP), SP
+	RET
+
 // func now() (sec int64, nsec int32)
 TEXT time·now(SB),NOSPLIT,$8-12
 	CALL	runtime·unixnano(SB)
diff --git a/src/runtime/sys_x86.go b/src/runtime/sys_x86.go
index 137e706..f6e45cc 100644
--- a/src/runtime/sys_x86.go
+++ b/src/runtime/sys_x86.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -40,13 +40,13 @@ func rewindmorestack(buf *gobuf) {
 		return
 	}
 	if pc[0] == 0xcc {
-		// This is a breakpoint inserted by gdb.  We could use
-		// runtime·findfunc to find the function.  But if we
+		// 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
+		// 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
+		// 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.
diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go
index ae1f334..6c9dbe2 100644
--- a/src/runtime/syscall_solaris.go
+++ b/src/runtime/syscall_solaris.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index 0d52544..cd23b8d 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -45,15 +45,15 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
 		panic("compileCallback: not a function")
 	}
 	ft := (*functype)(unsafe.Pointer(fn._type))
-	if len(ft.out) != 1 {
+	if len(ft.out()) != 1 {
 		panic("compileCallback: function must have one output parameter")
 	}
 	uintptrSize := unsafe.Sizeof(uintptr(0))
-	if ft.out[0].size != uintptrSize {
+	if ft.out()[0].size != uintptrSize {
 		panic("compileCallback: output parameter size is wrong")
 	}
 	argsize := uintptr(0)
-	for _, t := range ft.in {
+	for _, t := range ft.in() {
 		if t.size > uintptrSize {
 			panic("compileCallback: input parameter size is wrong")
 		}
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
index 7c82caa..4a10749 100644
--- a/src/runtime/syscall_windows_test.go
+++ b/src/runtime/syscall_windows_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -622,6 +622,13 @@ uintptr_t cfunc(callback f, uintptr_t n) {
 	}
 }
 
+func TestTimeBeginPeriod(t *testing.T) {
+	const TIMERR_NOERROR = 0
+	if *runtime.TimeBeginPeriodRetValue != TIMERR_NOERROR {
+		t.Fatalf("timeBeginPeriod failed: it returned %d", *runtime.TimeBeginPeriodRetValue)
+	}
+}
+
 // removeOneCPU removes one (any) cpu from affinity mask.
 // It returns new affinity mask.
 func removeOneCPU(mask uintptr) (uintptr, error) {
@@ -869,3 +876,99 @@ func TestLoadLibraryEx(t *testing.T) {
 	t.Skipf("LoadLibraryEx not usable, but not expected. (LoadLibraryEx=%v; flags=%v)",
 		have, flags)
 }
+
+var (
+	modwinmm    = syscall.NewLazyDLL("winmm.dll")
+	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+	procCreateEvent = modkernel32.NewProc("CreateEventW")
+	procSetEvent    = modkernel32.NewProc("SetEvent")
+)
+
+func createEvent() (syscall.Handle, error) {
+	r0, _, e0 := syscall.Syscall6(procCreateEvent.Addr(), 4, 0, 0, 0, 0, 0, 0)
+	if r0 == 0 {
+		return 0, syscall.Errno(e0)
+	}
+	return syscall.Handle(r0), nil
+}
+
+func setEvent(h syscall.Handle) error {
+	r0, _, e0 := syscall.Syscall(procSetEvent.Addr(), 1, uintptr(h), 0, 0)
+	if r0 == 0 {
+		return syscall.Errno(e0)
+	}
+	return nil
+}
+
+func BenchmarkChanToSyscallPing(b *testing.B) {
+	n := b.N
+	ch := make(chan int)
+	event, err := createEvent()
+	if err != nil {
+		b.Fatal(err)
+	}
+	go func() {
+		for i := 0; i < n; i++ {
+			syscall.WaitForSingleObject(event, syscall.INFINITE)
+			ch <- 1
+		}
+	}()
+	for i := 0; i < n; i++ {
+		err := setEvent(event)
+		if err != nil {
+			b.Fatal(err)
+		}
+		<-ch
+	}
+}
+
+func BenchmarkSyscallToSyscallPing(b *testing.B) {
+	n := b.N
+	event1, err := createEvent()
+	if err != nil {
+		b.Fatal(err)
+	}
+	event2, err := createEvent()
+	if err != nil {
+		b.Fatal(err)
+	}
+	go func() {
+		for i := 0; i < n; i++ {
+			syscall.WaitForSingleObject(event1, syscall.INFINITE)
+			err := setEvent(event2)
+			if err != nil {
+				b.Fatal(err)
+			}
+		}
+	}()
+	for i := 0; i < n; i++ {
+		err := setEvent(event1)
+		if err != nil {
+			b.Fatal(err)
+		}
+		syscall.WaitForSingleObject(event2, syscall.INFINITE)
+	}
+}
+
+func BenchmarkChanToChanPing(b *testing.B) {
+	n := b.N
+	ch1 := make(chan int)
+	ch2 := make(chan int)
+	go func() {
+		for i := 0; i < n; i++ {
+			<-ch1
+			ch2 <- 1
+		}
+	}()
+	for i := 0; i < n; i++ {
+		ch1 <- 1
+		<-ch2
+	}
+}
+
+func BenchmarkOsYield(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		runtime.OsYield()
+	}
+}
diff --git a/src/runtime/testdata/testprog/crash.go b/src/runtime/testdata/testprog/crash.go
index 3d7c7c6..4d83132 100644
--- a/src/runtime/testdata/testprog/crash.go
+++ b/src/runtime/testdata/testprog/crash.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprog/deadlock.go b/src/runtime/testdata/testprog/deadlock.go
index 73fbf62..c938fcf 100644
--- a/src/runtime/testdata/testprog/deadlock.go
+++ b/src/runtime/testdata/testprog/deadlock.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -30,6 +30,8 @@ func init() {
 	register("PanicAfterGoexit", PanicAfterGoexit)
 	register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit)
 	register("PanicTraceback", PanicTraceback)
+	register("GoschedInPanic", GoschedInPanic)
+	register("SyscallInPanic", SyscallInPanic)
 }
 
 func SimpleDeadlock() {
@@ -152,6 +154,29 @@ func GoexitInPanic() {
 	runtime.Goexit()
 }
 
+type errorThatGosched struct{}
+
+func (errorThatGosched) Error() string {
+	runtime.Gosched()
+	return "errorThatGosched"
+}
+
+func GoschedInPanic() {
+	panic(errorThatGosched{})
+}
+
+type errorThatPrint struct{}
+
+func (errorThatPrint) Error() string {
+	fmt.Println("1")
+	fmt.Println("2")
+	return "3"
+}
+
+func SyscallInPanic() {
+	panic(errorThatPrint{})
+}
+
 func PanicAfterGoexit() {
 	defer func() {
 		panic("hello")
diff --git a/src/runtime/testdata/testprog/gc.go b/src/runtime/testdata/testprog/gc.go
index 9bb367c..a0c1f82 100644
--- a/src/runtime/testdata/testprog/gc.go
+++ b/src/runtime/testdata/testprog/gc.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -8,11 +8,14 @@ import (
 	"fmt"
 	"os"
 	"runtime"
+	"runtime/debug"
+	"sync/atomic"
 	"time"
 )
 
 func init() {
 	register("GCFairness", GCFairness)
+	register("GCFairness2", GCFairness2)
 	register("GCSys", GCSys)
 }
 
@@ -72,3 +75,35 @@ func GCFairness() {
 	time.Sleep(10 * time.Millisecond)
 	fmt.Println("OK")
 }
+
+func GCFairness2() {
+	// Make sure user code can't exploit the GC's high priority
+	// scheduling to make scheduling of user code unfair. See
+	// issue #15706.
+	runtime.GOMAXPROCS(1)
+	debug.SetGCPercent(1)
+	var count [3]int64
+	var sink [3]interface{}
+	for i := range count {
+		go func(i int) {
+			for {
+				sink[i] = make([]byte, 1024)
+				atomic.AddInt64(&count[i], 1)
+			}
+		}(i)
+	}
+	// Note: If the unfairness is really bad, it may not even get
+	// past the sleep.
+	//
+	// If the scheduling rules change, this may not be enough time
+	// to let all goroutines run, but for now we cycle through
+	// them rapidly.
+	time.Sleep(30 * time.Millisecond)
+	for i := range count {
+		if atomic.LoadInt64(&count[i]) == 0 {
+			fmt.Printf("goroutine %d did not run\n", i)
+			return
+		}
+	}
+	fmt.Println("OK")
+}
diff --git a/src/runtime/testdata/testprog/main.go b/src/runtime/testdata/testprog/main.go
index 9c227bb..ae491a2 100644
--- a/src/runtime/testdata/testprog/main.go
+++ b/src/runtime/testdata/testprog/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprog/memprof.go b/src/runtime/testdata/testprog/memprof.go
new file mode 100644
index 0000000..a22fee6
--- /dev/null
+++ b/src/runtime/testdata/testprog/memprof.go
@@ -0,0 +1,49 @@
+// Copyright 2016 The Go Authors. 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"
+	"runtime"
+	"runtime/pprof"
+)
+
+func init() {
+	register("MemProf", MemProf)
+}
+
+var memProfBuf bytes.Buffer
+var memProfStr string
+
+func MemProf() {
+	for i := 0; i < 1000; i++ {
+		fmt.Fprintf(&memProfBuf, "%*d\n", i, i)
+	}
+	memProfStr = memProfBuf.String()
+
+	runtime.GC()
+
+	f, err := ioutil.TempFile("", "memprof")
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+
+	if err := pprof.WriteHeapProfile(f); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+
+	name := f.Name()
+	if err := f.Close(); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+
+	fmt.Println(name)
+}
diff --git a/src/runtime/testdata/testprog/misc.go b/src/runtime/testdata/testprog/misc.go
index 237680f..7ccd389 100644
--- a/src/runtime/testdata/testprog/misc.go
+++ b/src/runtime/testdata/testprog/misc.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/testdata/testprog/signal.go b/src/runtime/testdata/testprog/signal.go
index ac2d3e8..2ccbada 100644
--- a/src/runtime/testdata/testprog/signal.go
+++ b/src/runtime/testdata/testprog/signal.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -6,7 +6,10 @@
 
 package main
 
-import "syscall"
+import (
+	"syscall"
+	"time"
+)
 
 func init() {
 	register("SignalExitStatus", SignalExitStatus)
@@ -14,4 +17,13 @@ func init() {
 
 func SignalExitStatus() {
 	syscall.Kill(syscall.Getpid(), syscall.SIGTERM)
+
+	// Should die immediately, but we've seen flakiness on various
+	// systems (see issue 14063). It's possible that the signal is
+	// being delivered to a different thread and we are returning
+	// and exiting before that thread runs again. Give the program
+	// a little while to die to make sure we pick up the signal
+	// before we return and exit the program. The time here
+	// shouldn't matter--we'll never really sleep this long.
+	time.Sleep(time.Second)
 }
diff --git a/src/runtime/testdata/testprog/stringconcat.go b/src/runtime/testdata/testprog/stringconcat.go
index 9dddf19..f233e66 100644
--- a/src/runtime/testdata/testprog/stringconcat.go
+++ b/src/runtime/testdata/testprog/stringconcat.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprog/syscall_windows.go b/src/runtime/testdata/testprog/syscall_windows.go
index 73165be..6e6782e 100644
--- a/src/runtime/testdata/testprog/syscall_windows.go
+++ b/src/runtime/testdata/testprog/syscall_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/aprof.go b/src/runtime/testdata/testprogcgo/aprof.go
index cf52107..aabca9e 100644
--- a/src/runtime/testdata/testprogcgo/aprof.go
+++ b/src/runtime/testdata/testprogcgo/aprof.go
@@ -17,6 +17,7 @@ import (
 	"bytes"
 	"fmt"
 	"runtime/pprof"
+	"time"
 )
 
 func init() {
@@ -29,13 +30,17 @@ func GoNop() {}
 func CgoCCodeSIGPROF() {
 	c := make(chan bool)
 	go func() {
-		for {
-			<-c
-			for i := 0; i < 1e7; i++ {
-				C.GoNop()
+		<-c
+		start := time.Now()
+		for i := 0; i < 1e7; i++ {
+			if i%1000 == 0 {
+				if time.Since(start) > time.Second {
+					break
+				}
 			}
-			c <- true
+			C.GoNop()
 		}
+		c <- true
 	}()
 
 	var buf bytes.Buffer
diff --git a/src/runtime/testdata/testprogcgo/callback.go b/src/runtime/testdata/testprogcgo/callback.go
index 10e248a..7d9d68d 100644
--- a/src/runtime/testdata/testprogcgo/callback.go
+++ b/src/runtime/testdata/testprogcgo/callback.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/cgo.go b/src/runtime/testdata/testprogcgo/cgo.go
index 7a2e013..870d4ef 100644
--- a/src/runtime/testdata/testprogcgo/cgo.go
+++ b/src/runtime/testdata/testprogcgo/cgo.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/crash.go b/src/runtime/testdata/testprogcgo/crash.go
index 3d7c7c6..4d83132 100644
--- a/src/runtime/testdata/testprogcgo/crash.go
+++ b/src/runtime/testdata/testprogcgo/crash.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/deadlock.go b/src/runtime/testdata/testprogcgo/deadlock.go
new file mode 100644
index 0000000..2cc68a8
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/deadlock.go
@@ -0,0 +1,30 @@
+// Copyright 2016 The Go Authors. 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
+
+/*
+char *geterror() {
+	return "cgo error";
+}
+*/
+import "C"
+import (
+	"fmt"
+)
+
+func init() {
+	register("CgoPanicDeadlock", CgoPanicDeadlock)
+}
+
+type cgoError struct{}
+
+func (cgoError) Error() string {
+	fmt.Print("") // necessary to trigger the deadlock
+	return C.GoString(C.geterror())
+}
+
+func CgoPanicDeadlock() {
+	panic(cgoError{})
+}
diff --git a/src/runtime/testdata/testprogcgo/dll_windows.go b/src/runtime/testdata/testprogcgo/dll_windows.go
index a0647ef..aed2410 100644
--- a/src/runtime/testdata/testprogcgo/dll_windows.go
+++ b/src/runtime/testdata/testprogcgo/dll_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/dropm.go b/src/runtime/testdata/testprogcgo/dropm.go
index 75984ea..9e782f5 100644
--- a/src/runtime/testdata/testprogcgo/dropm.go
+++ b/src/runtime/testdata/testprogcgo/dropm.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/testdata/testprogcgo/dropm_stub.go b/src/runtime/testdata/testprogcgo/dropm_stub.go
index 4c3f46a..f7f142c 100644
--- a/src/runtime/testdata/testprogcgo/dropm_stub.go
+++ b/src/runtime/testdata/testprogcgo/dropm_stub.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/testdata/testprogcgo/exec.go b/src/runtime/testdata/testprogcgo/exec.go
index 8dc1d51..2e94840 100644
--- a/src/runtime/testdata/testprogcgo/exec.go
+++ b/src/runtime/testdata/testprogcgo/exec.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/main.go b/src/runtime/testdata/testprogcgo/main.go
index 9c227bb..ae491a2 100644
--- a/src/runtime/testdata/testprogcgo/main.go
+++ b/src/runtime/testdata/testprogcgo/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/pprof.go b/src/runtime/testdata/testprogcgo/pprof.go
new file mode 100644
index 0000000..cb30ec5
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/pprof.go
@@ -0,0 +1,97 @@
+// Copyright 2016 The Go Authors.  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
+
+// Run a slow C function saving a CPU profile.
+
+/*
+#include <stdint.h>
+
+int salt1;
+int salt2;
+
+void cpuHog() {
+	int foo = salt1;
+	int i;
+
+	for (i = 0; i < 100000; i++) {
+		if (foo > 0) {
+			foo *= foo;
+		} else {
+			foo *= foo + 1;
+		}
+	}
+	salt2 = foo;
+}
+
+static int cpuHogCount;
+
+struct cgoTracebackArg {
+	uintptr_t  context;
+	uintptr_t  sigContext;
+	uintptr_t* buf;
+	uintptr_t  max;
+};
+
+// pprofCgoTraceback is passed to runtime.SetCgoTraceback.
+// For testing purposes it pretends that all CPU hits in C code are in cpuHog.
+void pprofCgoTraceback(void* parg) {
+	struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+	arg->buf[0] = (uintptr_t)(cpuHog) + 0x10;
+	arg->buf[1] = 0;
+	++cpuHogCount;
+}
+
+// getCpuHogCount fetches the number of times we've seen cpuHog in the
+// traceback.
+int getCpuHogCount() {
+	return cpuHogCount;
+}
+*/
+import "C"
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"runtime"
+	"runtime/pprof"
+	"time"
+	"unsafe"
+)
+
+func init() {
+	register("CgoPprof", CgoPprof)
+}
+
+func CgoPprof() {
+	runtime.SetCgoTraceback(0, unsafe.Pointer(C.pprofCgoTraceback), nil, nil)
+
+	f, err := ioutil.TempFile("", "prof")
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+
+	if err := pprof.StartCPUProfile(f); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+
+	t0 := time.Now()
+	for C.getCpuHogCount() < 2 && time.Since(t0) < time.Second {
+		C.cpuHog()
+	}
+
+	pprof.StopCPUProfile()
+
+	name := f.Name()
+	if err := f.Close(); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+
+	fmt.Println(name)
+}
diff --git a/src/runtime/testdata/testprogcgo/threadpanic.go b/src/runtime/testdata/testprogcgo/threadpanic.go
index 3c9baba..f9b48a9 100644
--- a/src/runtime/testdata/testprogcgo/threadpanic.go
+++ b/src/runtime/testdata/testprogcgo/threadpanic.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/threadpanic_unix.c b/src/runtime/testdata/testprogcgo/threadpanic_unix.c
index dea8160..c426452 100644
--- a/src/runtime/testdata/testprogcgo/threadpanic_unix.c
+++ b/src/runtime/testdata/testprogcgo/threadpanic_unix.c
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/threadpanic_windows.c b/src/runtime/testdata/testprogcgo/threadpanic_windows.c
index 0a19ffa..ba66d0f 100644
--- a/src/runtime/testdata/testprogcgo/threadpanic_windows.c
+++ b/src/runtime/testdata/testprogcgo/threadpanic_windows.c
@@ -1,13 +1,14 @@
-// Copyright 2015 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.
 
+#include <process.h>
 #include <stdlib.h>
 #include <stdio.h>
 
 void gopanic(void);
 
-static void*
+static unsigned int __attribute__((__stdcall__))
 die(void* x)
 {
 	gopanic();
diff --git a/src/runtime/testdata/testprogcgo/threadpprof.go b/src/runtime/testdata/testprogcgo/threadpprof.go
new file mode 100644
index 0000000..fdeee69
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/threadpprof.go
@@ -0,0 +1,112 @@
+// Copyright 2016 The Go 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 main
+
+// Run a slow C function saving a CPU profile.
+
+/*
+#include <stdint.h>
+#include <time.h>
+#include <pthread.h>
+
+int threadSalt1;
+int threadSalt2;
+
+void cpuHogThread() {
+	int foo = threadSalt1;
+	int i;
+
+	for (i = 0; i < 100000; i++) {
+		if (foo > 0) {
+			foo *= foo;
+		} else {
+			foo *= foo + 1;
+		}
+	}
+	threadSalt2 = foo;
+}
+
+static int cpuHogThreadCount;
+
+struct cgoTracebackArg {
+	uintptr_t  context;
+	uintptr_t  sigContext;
+	uintptr_t* buf;
+	uintptr_t  max;
+};
+
+static void *pprofThread(void* p) {
+	time_t start;
+
+	(void)p;
+	start = time(NULL);
+	while (__sync_add_and_fetch(&cpuHogThreadCount, 0) < 2 && time(NULL) - start < 2) {
+		cpuHogThread();
+	}
+}
+
+
+// pprofCgoThreadTraceback is passed to runtime.SetCgoTraceback.
+// For testing purposes it pretends that all CPU hits in C code are in cpuHog.
+void pprofCgoThreadTraceback(void* parg) {
+	struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+	arg->buf[0] = (uintptr_t)(cpuHogThread) + 0x10;
+	arg->buf[1] = 0;
+	__sync_add_and_fetch(&cpuHogThreadCount, 1);
+}
+
+// getCPUHogThreadCount fetches the number of times we've seen cpuHogThread
+// in the traceback.
+int getCPUHogThreadCount() {
+	return __sync_add_and_fetch(&cpuHogThreadCount, 0);
+}
+*/
+import "C"
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"runtime"
+	"runtime/pprof"
+	"time"
+	"unsafe"
+)
+
+func init() {
+	register("CgoPprofThread", CgoPprofThread)
+}
+
+func CgoPprofThread() {
+	runtime.SetCgoTraceback(0, unsafe.Pointer(C.pprofCgoThreadTraceback), nil, nil)
+
+	f, err := ioutil.TempFile("", "prof")
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+
+	if err := pprof.StartCPUProfile(f); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+
+	t0 := time.Now()
+	for C.getCPUHogThreadCount() < 2 && time.Since(t0) < time.Second {
+		time.Sleep(100 * time.Millisecond)
+	}
+
+	pprof.StopCPUProfile()
+
+	name := f.Name()
+	if err := f.Close(); err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(2)
+	}
+
+	fmt.Println(name)
+}
diff --git a/src/runtime/testdata/testprogcgo/threadprof.go b/src/runtime/testdata/testprogcgo/threadprof.go
index 03e35d2..a77479d 100644
--- a/src/runtime/testdata/testprogcgo/threadprof.go
+++ b/src/runtime/testdata/testprogcgo/threadprof.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprogcgo/traceback.go b/src/runtime/testdata/testprogcgo/traceback.go
new file mode 100644
index 0000000..e8b0a04
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/traceback.go
@@ -0,0 +1,81 @@
+// Copyright 2016 The Go Authors. 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
+
+// This program will crash.
+// We want the stack trace to include the C functions.
+// We use a fake traceback, and a symbolizer that dumps a string we recognize.
+
+/*
+#cgo CFLAGS: -g -O0
+
+#include <stdint.h>
+
+char *p;
+
+static int f3() {
+	*p = 0;
+	return 0;
+}
+
+static int f2() {
+	return f3();
+}
+
+static int f1() {
+	return f2();
+}
+
+struct cgoTracebackArg {
+	uintptr_t  context;
+	uintptr_t  sigContext;
+	uintptr_t* buf;
+	uintptr_t  max;
+};
+
+struct cgoSymbolizerArg {
+	uintptr_t   pc;
+	const char* file;
+	uintptr_t   lineno;
+	const char* func;
+	uintptr_t   entry;
+	uintptr_t   more;
+	uintptr_t   data;
+};
+
+void cgoTraceback(void* parg) {
+	struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+	arg->buf[0] = 1;
+	arg->buf[1] = 2;
+	arg->buf[2] = 3;
+	arg->buf[3] = 0;
+}
+
+void cgoSymbolizer(void* parg) {
+	struct cgoSymbolizerArg* arg = (struct cgoSymbolizerArg*)(parg);
+	if (arg->pc != arg->data + 1) {
+		arg->file = "unexpected data";
+	} else {
+		arg->file = "cgo symbolizer";
+	}
+	arg->lineno = arg->data + 1;
+	arg->data++;
+}
+*/
+import "C"
+
+import (
+	"runtime"
+	"unsafe"
+)
+
+func init() {
+	register("CrashTraceback", CrashTraceback)
+}
+
+func CrashTraceback() {
+	runtime.SetCgoTraceback(0, unsafe.Pointer(C.cgoTraceback), nil, unsafe.Pointer(C.cgoSymbolizer))
+	C.f1()
+}
diff --git a/src/runtime/testdata/testprogcgo/tracebackctxt.go b/src/runtime/testdata/testprogcgo/tracebackctxt.go
new file mode 100644
index 0000000..51fa4ad
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/tracebackctxt.go
@@ -0,0 +1,107 @@
+// Copyright 2016 The Go 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 __attribute__((weak)) used below doesn't seem to work on Windows.
+
+package main
+
+// Test the context argument to SetCgoTraceback.
+// Use fake context, traceback, and symbolizer functions.
+
+/*
+// Defined in tracebackctxt_c.c.
+extern void C1(void);
+extern void C2(void);
+extern void tcContext(void*);
+extern void tcTraceback(void*);
+extern void tcSymbolizer(void*);
+extern int getContextCount(void);
+*/
+import "C"
+
+import (
+	"fmt"
+	"runtime"
+	"unsafe"
+)
+
+func init() {
+	register("TracebackContext", TracebackContext)
+}
+
+var tracebackOK bool
+
+func TracebackContext() {
+	runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContext), unsafe.Pointer(C.tcSymbolizer))
+	C.C1()
+	if got := C.getContextCount(); got != 0 {
+		fmt.Printf("at end contextCount == %d, expected 0\n", got)
+		tracebackOK = false
+	}
+	if tracebackOK {
+		fmt.Println("OK")
+	}
+}
+
+//export G1
+func G1() {
+	C.C2()
+}
+
+//export G2
+func G2() {
+	pc := make([]uintptr, 32)
+	n := runtime.Callers(0, pc)
+	cf := runtime.CallersFrames(pc[:n])
+	var frames []runtime.Frame
+	for {
+		frame, more := cf.Next()
+		frames = append(frames, frame)
+		if !more {
+			break
+		}
+	}
+
+	want := []struct {
+		function string
+		line     int
+	}{
+		{"main.G2", 0},
+		{"cFunction", 0x10200},
+		{"cFunction", 0x200},
+		{"cFunction", 0x10201},
+		{"cFunction", 0x201},
+		{"main.G1", 0},
+		{"cFunction", 0x10100},
+		{"cFunction", 0x100},
+		{"main.TracebackContext", 0},
+	}
+
+	ok := true
+	i := 0
+wantLoop:
+	for _, w := range want {
+		for ; i < len(frames); i++ {
+			if w.function == frames[i].Function {
+				if w.line != 0 && w.line != frames[i].Line {
+					fmt.Printf("found function %s at wrong line %#x (expected %#x)\n", w.function, frames[i].Line, w.line)
+					ok = false
+				}
+				i++
+				continue wantLoop
+			}
+		}
+		fmt.Printf("did not find function %s in\n", w.function)
+		for _, f := range frames {
+			fmt.Println(f)
+		}
+		ok = false
+		break
+	}
+	tracebackOK = ok
+	if got := C.getContextCount(); got != 2 {
+		fmt.Printf("at bottom contextCount == %d, expected 2\n", got)
+		tracebackOK = false
+	}
+}
diff --git a/src/runtime/testdata/testprogcgo/tracebackctxt_c.c b/src/runtime/testdata/testprogcgo/tracebackctxt_c.c
new file mode 100644
index 0000000..900cada
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/tracebackctxt_c.c
@@ -0,0 +1,91 @@
+// Copyright 2016 The Go 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 C definitions for tracebackctxt.go. That file uses //export so
+// it can't put function definitions in the "C" import comment.
+
+#include <stdlib.h>
+#include <stdint.h>
+
+// Functions exported from Go.
+extern void G1(void);
+extern void G2(void);
+
+void C1() {
+	G1();
+}
+
+void C2() {
+	G2();
+}
+
+struct cgoContextArg {
+	uintptr_t context;
+};
+
+struct cgoTracebackArg {
+	uintptr_t  context;
+	uintptr_t  sigContext;
+	uintptr_t* buf;
+	uintptr_t  max;
+};
+
+struct cgoSymbolizerArg {
+	uintptr_t   pc;
+	const char* file;
+	uintptr_t   lineno;
+	const char* func;
+	uintptr_t   entry;
+	uintptr_t   more;
+	uintptr_t   data;
+};
+
+// Uses atomic adds and subtracts to catch the possibility of
+// erroneous calls from multiple threads; that should be impossible in
+// this test case, but we check just in case.
+static int contextCount;
+
+int getContextCount() {
+	return __sync_add_and_fetch(&contextCount, 0);
+}
+
+void tcContext(void* parg) {
+	struct cgoContextArg* arg = (struct cgoContextArg*)(parg);
+	if (arg->context == 0) {
+		arg->context = __sync_add_and_fetch(&contextCount, 1);
+	} else {
+		if (arg->context != __sync_add_and_fetch(&contextCount, 0)) {
+			abort();
+		}
+		__sync_sub_and_fetch(&contextCount, 1);
+	}
+}
+
+void tcTraceback(void* parg) {
+	int base, i;
+	struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+	if (arg->context == 0) {
+		// This shouldn't happen in this program.
+		abort();
+	}
+	// Return a variable number of PC values.
+	base = arg->context << 8;
+	for (i = 0; i < arg->context; i++) {
+		if (i < arg->max) {
+			arg->buf[i] = base + i;
+		}
+	}
+}
+
+void tcSymbolizer(void *parg) {
+	struct cgoSymbolizerArg* arg = (struct cgoSymbolizerArg*)(parg);
+	if (arg->pc == 0) {
+		return;
+	}
+	// Report two lines per PC returned by traceback, to test more handling.
+	arg->more = arg->file == NULL;
+	arg->file = "tracebackctxt.go";
+	arg->func = "cFunction";
+	arg->lineno = arg->pc + (arg->more << 16);
+}
diff --git a/src/runtime/testdata/testprognet/main.go b/src/runtime/testdata/testprognet/main.go
index 9c227bb..ae491a2 100644
--- a/src/runtime/testdata/testprognet/main.go
+++ b/src/runtime/testdata/testprognet/main.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprognet/net.go b/src/runtime/testdata/testprognet/net.go
index c1a7f3f..714b101 100644
--- a/src/runtime/testdata/testprognet/net.go
+++ b/src/runtime/testdata/testprognet/net.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/runtime/testdata/testprognet/signal.go b/src/runtime/testdata/testprognet/signal.go
index 24d1424..a1559fe 100644
--- a/src/runtime/testdata/testprognet/signal.go
+++ b/src/runtime/testdata/testprognet/signal.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/textflag.h b/src/runtime/textflag.h
index dbf3d99..929e9b3 100644
--- a/src/runtime/textflag.h
+++ b/src/runtime/textflag.h
@@ -1,14 +1,16 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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
+// and data objects. The compilers, assemblers, and linker must
 // all agree on these values.
+//
+// Keep in sync with src/cmd/internal/obj/textflag.go.
 
-// Don't profile the marked routine.  This flag is deprecated.
+// 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
+// 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.
@@ -28,3 +30,5 @@
 // Only valid on functions that declare a frame size of 0.
 // TODO(mwhudson): only implemented for ppc64x at present.
 #define NOFRAME 512
+// Function can call reflect.Type.Method or reflect.Type.MethodByName.
+#define REFLECTMETHOD = 1024
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 3f8f696..8df185d 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -202,7 +202,7 @@ func timerproc() {
 			goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
 			continue
 		}
-		// At least one timer pending.  Sleep until then.
+		// At least one timer pending. Sleep until then.
 		timers.sleeping = true
 		noteclear(&timers.waitnote)
 		unlock(&timers.lock)
diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s
index 00ca469..32bfcf8 100644
--- a/src/runtime/tls_arm.s
+++ b/src/runtime/tls_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/tls_mips64x.s b/src/runtime/tls_mips64x.s
index c6f5bfa..53bd6f2 100644
--- a/src/runtime/tls_mips64x.s
+++ b/src/runtime/tls_mips64x.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
@@ -11,13 +11,20 @@
 
 // If !iscgo, this is a no-op.
 //
-// NOTE: mcall() assumes this clobbers only R28 (REGTMP).
+// NOTE: mcall() assumes this clobbers only R23 (REGTMP).
 TEXT runtime·save_g(SB),NOSPLIT,$-8-0
-	MOVB	runtime·iscgo(SB), R28
-	BEQ	R28, nocgo
+	MOVB	runtime·iscgo(SB), R23
+	BEQ	R23, nocgo
+
+	MOVV	R3, R23	// save R3
+	MOVV	g, runtime·tls_g(SB) // TLS relocation clobbers R3
+	MOVV	R23, R3	// restore R3
 
 nocgo:
 	RET
 
 TEXT runtime·load_g(SB),NOSPLIT,$-8-0
+	MOVV	runtime·tls_g(SB), g // TLS relocation clobbers R3
 	RET
+
+GLOBL runtime·tls_g(SB), TLSBSS, $8
diff --git a/src/runtime/tls_ppc64x.s b/src/runtime/tls_ppc64x.s
index c79c97d..69c0d9e 100644
--- a/src/runtime/tls_ppc64x.s
+++ b/src/runtime/tls_ppc64x.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/tls_s390x.s b/src/runtime/tls_s390x.s
new file mode 100644
index 0000000..cb6a21c
--- /dev/null
+++ b/src/runtime/tls_s390x.s
@@ -0,0 +1,51 @@
+// Copyright 2016 The Go 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"
+
+// We have to resort to TLS variable to save g (R13).
+// 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 R13,
+// 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
+// s390x code that will overwrite this register.
+//
+// If !iscgo, this is a no-op.
+//
+// NOTE: setg_gcc<> assume this clobbers only R10 and R11.
+TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0-0
+	MOVB	runtime·iscgo(SB),  R10
+	CMPBEQ	R10, $0, nocgo
+	MOVW	AR0, R11
+	SLD	$32, R11
+	MOVW	AR1, R11
+	MOVD	runtime·tls_g(SB), R10
+	MOVD	g, 0(R10)(R11*1)
+nocgo:
+	RET
+
+// load_g loads the g register from pthread-provided
+// thread-local memory, for use after calling externally compiled
+// s390x 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 (R13), R10 and R11.
+TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0-0
+	MOVW	AR0, R11
+	SLD	$32, R11
+	MOVW	AR1, R11
+	MOVD	runtime·tls_g(SB), R10
+	MOVD	0(R10)(R11*1), g
+	RET
+
+GLOBL runtime·tls_g+0(SB),TLSBSS,$8
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index 805c34f..092f941 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -13,7 +13,6 @@
 package runtime
 
 import (
-	"runtime/internal/atomic"
 	"runtime/internal/sys"
 	"unsafe"
 )
@@ -23,25 +22,25 @@ 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]
+	traceEvStack          = 3  // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}]
 	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]
+	traceEvGCStart        = 7  // GC start [timestamp, seq, 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]
+	traceEvGoCreate       = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id]
+	traceEvGoStart        = 14 // goroutine starts running [timestamp, goroutine id, seq]
 	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]
+	traceEvGoUnblock      = 21 // goroutine is unblocked [timestamp, goroutine id, seq, 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]
@@ -49,15 +48,19 @@ const (
 	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]
+	traceEvGoSysExit      = 29 // syscall exit [timestamp, goroutine id, seq, 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]
+	traceEvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id]
+	traceEvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, 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
+	traceEvString         = 37 // string dictionary entry [ID, length, string]
+	traceEvGoStartLocal   = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id]
+	traceEvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack]
+	traceEvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp]
+	traceEvCount          = 41
 )
 
 const (
@@ -104,6 +107,7 @@ var trace struct {
 	ticksEnd      int64       // cputicks when tracing was stopped
 	timeStart     int64       // nanotime when tracing was started
 	timeEnd       int64       // nanotime when tracing was stopped
+	seqGC         uint64      // GC start/done sequencer
 	reading       traceBufPtr // buffer currently handed off to user
 	empty         traceBufPtr // stack of empty buffers
 	fullHead      traceBufPtr // queue of full buffers
@@ -111,35 +115,19 @@ var trace struct {
 	reader        *g              // goroutine that called ReadTrace, or nil
 	stackTab      traceStackTable // maps stack traces to unique ids
 
+	// Dictionary for traceEvString.
+	// Currently this is used only for func/file:line info after tracing session,
+	// so we assume single-threaded access.
+	strings   map[string]uint64
+	stringSeq uint64
+
 	bufLock mutex       // protects buf
 	buf     traceBufPtr // 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 = atomic.Load64(&traceseq)
-	for seq&1 != 0 || !atomic.Cas64(&traceseq, seq, seq+1) {
-		seq = atomic.Load64(&traceseq)
-	}
-	ts = cputicks()
-	atomic.Store64(&traceseq, seq+2)
-	return seq >> 1, ts
-}
-
 // traceBufHeader is per-P tracing buffer.
 type traceBufHeader struct {
 	link      traceBufPtr             // in trace.empty/full
-	lastSeq   uint64                  // sequence number of last event
 	lastTicks uint64                  // when we wrote the last event
 	pos       int                     // next write offset in arr
 	stk       [traceStackSize]uintptr // scratch buffer for traceback
@@ -187,11 +175,6 @@ func StartTrace() error {
 		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:
@@ -204,12 +187,15 @@ func StartTrace() error {
 	for _, gp := range allgs {
 		status := readgstatus(gp)
 		if status != _Gdead {
-			traceGoCreate(gp, gp.startpc)
+			traceGoCreate(gp, gp.startpc) // also resets gp.traceseq/tracelastp
 		}
 		if status == _Gwaiting {
+			// traceEvGoWaiting is implied to have seq=1.
+			gp.traceseq++
 			traceEvent(traceEvGoWaiting, -1, uint64(gp.goid))
 		}
 		if status == _Gsyscall {
+			gp.traceseq++
 			traceEvent(traceEvGoInSyscall, -1, uint64(gp.goid))
 		} else {
 			gp.sysblocktraced = false
@@ -217,6 +203,17 @@ func StartTrace() error {
 	}
 	traceProcStart()
 	traceGoStart()
+	// Note: ticksStart needs to be set after we emit traceEvGoInSyscall events.
+	// If we do it the other way around, it is possible that exitsyscall will
+	// query sysexitticks after ticksStart but before traceEvGoInSyscall timestamp.
+	// It will lead to a false conclusion that cputicks is broken.
+	trace.ticksStart = cputicks()
+	trace.timeStart = nanotime()
+	trace.headerWritten = false
+	trace.footerWritten = false
+	trace.strings = make(map[string]uint64)
+	trace.stringSeq = 0
+	trace.seqGC = 0
 	_g_.m.startingtrace = false
 	trace.enabled = true
 
@@ -272,8 +269,6 @@ func StopTrace() {
 
 	trace.enabled = false
 	trace.shutdown = true
-	trace.stackTab.dump()
-
 	unlock(&trace.bufLock)
 
 	startTheWorld()
@@ -309,6 +304,7 @@ func StopTrace() {
 		trace.empty = buf.ptr().link
 		sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf.ptr()), &memstats.other_sys)
 	}
+	trace.strings = nil
 	trace.shutdown = false
 	unlock(&trace.lock)
 }
@@ -348,7 +344,7 @@ func ReadTrace() []byte {
 		trace.headerWritten = true
 		trace.lockOwner = nil
 		unlock(&trace.lock)
-		return []byte("go 1.5 trace\x00\x00\x00\x00")
+		return []byte("go 1.7 trace\x00\x00\x00\x00")
 	}
 	// Wait for new data.
 	if trace.fullHead == 0 && !trace.shutdown {
@@ -374,12 +370,13 @@ func ReadTrace() []byte {
 		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)
 		}
+		// This will emit a bunch of full buffers, we will pick them up
+		// on the next iteration.
+		trace.stackTab.dump()
 		return data
 	}
 	// Done.
@@ -483,19 +480,14 @@ func traceEvent(ev byte, skip int, args ...uint64) {
 		(*bufp).set(buf)
 	}
 
-	seq, ticksraw := tracestamp()
-	seqDiff := seq - buf.lastSeq
-	ticks := uint64(ticksraw) / traceTickDiv
+	ticks := uint64(cputicks()) / traceTickDiv
 	tickDiff := ticks - buf.lastTicks
 	if buf.pos == 0 {
 		buf.byte(traceEvBatch | 1<<traceArgCountShift)
 		buf.varint(uint64(pid))
-		buf.varint(seq)
 		buf.varint(ticks)
-		seqDiff = 0
 		tickDiff = 0
 	}
-	buf.lastSeq = seq
 	buf.lastTicks = ticks
 	narg := byte(len(args))
 	if skip >= 0 {
@@ -514,7 +506,6 @@ func traceEvent(ev byte, skip int, args ...uint64) {
 		buf.varint(0)
 		lenp = &buf.arr[buf.pos-1]
 	}
-	buf.varint(seqDiff)
 	buf.varint(tickDiff)
 	for _, a := range args {
 		buf.varint(a)
@@ -603,6 +594,29 @@ func traceFlush(buf traceBufPtr) traceBufPtr {
 	return buf
 }
 
+func traceString(buf *traceBuf, s string) (uint64, *traceBuf) {
+	if s == "" {
+		return 0, buf
+	}
+	if id, ok := trace.strings[s]; ok {
+		return id, buf
+	}
+
+	trace.stringSeq++
+	id := trace.stringSeq
+	trace.strings[s] = id
+
+	size := 1 + 2*traceBytesPerNumber + len(s)
+	if len(buf.arr)-buf.pos < size {
+		buf = traceFlush(traceBufPtrOf(buf)).ptr()
+	}
+	buf.byte(traceEvString)
+	buf.varint(id)
+	buf.varint(uint64(len(s)))
+	buf.pos += copy(buf.arr[buf.pos:], s)
+	return id, buf
+}
+
 // traceAppend appends v to buf in little-endian-base-128 encoding.
 func traceAppend(buf []byte, v uint64) []byte {
 	for ; v >= 0x80; v >>= 7 {
@@ -716,23 +730,28 @@ func (tab *traceStackTable) newStack(n int) *traceStack {
 // 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
+	frames := make(map[uintptr]traceFrame)
+	var tmp [(2 + 4*traceStackSize) * traceBytesPerNumber]byte
 	buf := traceFlush(0).ptr()
 	for _, stk := range tab.tab {
 		stk := stk.ptr()
 		for ; stk != nil; stk = stk.link.ptr() {
-			maxSize := 1 + (3+stk.n)*traceBytesPerNumber
-			if len(buf.arr)-buf.pos < maxSize {
-				buf = traceFlush(traceBufPtrOf(buf)).ptr()
-			}
-			// 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() {
+				var frame traceFrame
+				frame, buf = traceFrameForPC(buf, frames, pc)
 				tmpbuf = traceAppend(tmpbuf, uint64(pc))
+				tmpbuf = traceAppend(tmpbuf, uint64(frame.funcID))
+				tmpbuf = traceAppend(tmpbuf, uint64(frame.fileID))
+				tmpbuf = traceAppend(tmpbuf, uint64(frame.line))
 			}
 			// Now copy to the buffer.
+			size := 1 + traceBytesPerNumber + len(tmpbuf)
+			if len(buf.arr)-buf.pos < size {
+				buf = traceFlush(traceBufPtrOf(buf)).ptr()
+			}
 			buf.byte(traceEvStack | 3<<traceArgCountShift)
 			buf.varint(uint64(len(tmpbuf)))
 			buf.pos += copy(buf.arr[buf.pos:], tmpbuf)
@@ -747,6 +766,39 @@ func (tab *traceStackTable) dump() {
 	*tab = traceStackTable{}
 }
 
+type traceFrame struct {
+	funcID uint64
+	fileID uint64
+	line   uint64
+}
+
+func traceFrameForPC(buf *traceBuf, frames map[uintptr]traceFrame, pc uintptr) (traceFrame, *traceBuf) {
+	if frame, ok := frames[pc]; ok {
+		return frame, buf
+	}
+
+	var frame traceFrame
+	f := findfunc(pc)
+	if f == nil {
+		frames[pc] = frame
+		return frame, buf
+	}
+
+	fn := funcname(f)
+	const maxLen = 1 << 10
+	if len(fn) > maxLen {
+		fn = fn[len(fn)-maxLen:]
+	}
+	frame.funcID, buf = traceString(buf, fn)
+	file, line := funcline(f, pc-sys.PCQuantum)
+	frame.line = uint64(line)
+	if len(file) > maxLen {
+		file = file[len(file)-maxLen:]
+	}
+	frame.fileID, buf = traceString(buf, file)
+	return frame, buf
+}
+
 // traceAlloc is a non-thread-safe region allocator.
 // It holds a linked list of traceAllocBlock.
 type traceAlloc struct {
@@ -820,7 +872,8 @@ func traceProcStop(pp *p) {
 }
 
 func traceGCStart() {
-	traceEvent(traceEvGCStart, 3)
+	traceEvent(traceEvGCStart, 3, trace.seqGC)
+	trace.seqGC++
 }
 
 func traceGCDone() {
@@ -844,11 +897,23 @@ func traceGCSweepDone() {
 }
 
 func traceGoCreate(newg *g, pc uintptr) {
-	traceEvent(traceEvGoCreate, 2, uint64(newg.goid), uint64(pc))
+	newg.traceseq = 0
+	newg.tracelastp = getg().m.p
+	// +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum.
+	id := trace.stackTab.put([]uintptr{pc + sys.PCQuantum})
+	traceEvent(traceEvGoCreate, 2, uint64(newg.goid), uint64(id))
 }
 
 func traceGoStart() {
-	traceEvent(traceEvGoStart, -1, uint64(getg().m.curg.goid))
+	_g_ := getg().m.curg
+	_p_ := _g_.m.p
+	_g_.traceseq++
+	if _g_.tracelastp == _p_ {
+		traceEvent(traceEvGoStartLocal, -1, uint64(_g_.goid))
+	} else {
+		_g_.tracelastp = _p_
+		traceEvent(traceEvGoStart, -1, uint64(_g_.goid), _g_.traceseq)
+	}
 }
 
 func traceGoEnd() {
@@ -856,10 +921,14 @@ func traceGoEnd() {
 }
 
 func traceGoSched() {
+	_g_ := getg()
+	_g_.tracelastp = _g_.m.p
 	traceEvent(traceEvGoSched, 1)
 }
 
 func traceGoPreempt() {
+	_g_ := getg()
+	_g_.tracelastp = _g_.m.p
 	traceEvent(traceEvGoPreempt, 1)
 }
 
@@ -871,19 +940,37 @@ func traceGoPark(traceEv byte, skip int, gp *g) {
 }
 
 func traceGoUnpark(gp *g, skip int) {
-	traceEvent(traceEvGoUnblock, skip, uint64(gp.goid))
+	_p_ := getg().m.p
+	gp.traceseq++
+	if gp.tracelastp == _p_ {
+		traceEvent(traceEvGoUnblockLocal, skip, uint64(gp.goid))
+	} else {
+		gp.tracelastp = _p_
+		traceEvent(traceEvGoUnblock, skip, uint64(gp.goid), gp.traceseq)
+	}
 }
 
 func traceGoSysCall() {
 	traceEvent(traceEvGoSysCall, 1)
 }
 
-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 traceGoSysExit(ts int64) {
+	if ts != 0 && ts < trace.ticksStart {
+		// There is a race between the code that initializes 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 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.
+		ts = 0
+	}
+	_g_ := getg().m.curg
+	_g_.traceseq++
+	_g_.tracelastp = _g_.m.p
+	traceEvent(traceEvGoSysExit, -1, uint64(_g_.goid), _g_.traceseq, uint64(ts)/traceTickDiv)
 }
 
 func traceGoSysBlock(pp *p) {
diff --git a/src/runtime/trace/trace_stack_test.go b/src/runtime/trace/trace_stack_test.go
index b5fe7c3..52a71bf 100644
--- a/src/runtime/trace/trace_stack_test.go
+++ b/src/runtime/trace/trace_stack_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -125,14 +125,7 @@ func TestTraceSymbolize(t *testing.T) {
 	<-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)
-	}
+	events, _ := parseTrace(t, buf)
 
 	// Now check that the stacks are correct.
 	type frame struct {
@@ -149,6 +142,9 @@ func TestTraceSymbolize(t *testing.T) {
 			{"runtime/trace_test.TestTraceSymbolize", 106},
 			{"testing.tRunner", 0},
 		}},
+		{trace.EvGoStart, []frame{
+			{"runtime/trace_test.TestTraceSymbolize.func1", 37},
+		}},
 		{trace.EvGoSched, []frame{
 			{"runtime/trace_test.TestTraceSymbolize", 107},
 			{"testing.tRunner", 0},
@@ -235,7 +231,7 @@ func TestTraceSymbolize(t *testing.T) {
 		want = append(want, []eventDesc{
 			{trace.EvGoBlockNet, []frame{
 				{"net.(*netFD).accept", 0},
-				{"net.(*TCPListener).AcceptTCP", 0},
+				{"net.(*TCPListener).accept", 0},
 				{"net.(*TCPListener).Accept", 0},
 				{"runtime/trace_test.TestTraceSymbolize.func10", 86},
 			}},
diff --git a/src/runtime/trace/trace_test.go b/src/runtime/trace/trace_test.go
index f4791c2..5fad3fb 100644
--- a/src/runtime/trace/trace_test.go
+++ b/src/runtime/trace/trace_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -52,7 +52,7 @@ func TestTrace(t *testing.T) {
 		t.Fatalf("failed to start tracing: %v", err)
 	}
 	Stop()
-	_, err := trace.Parse(buf)
+	_, err := trace.Parse(buf, "")
 	if err == trace.ErrTimeOrder {
 		t.Skipf("skipping trace: %v", err)
 	}
@@ -61,13 +61,13 @@ func TestTrace(t *testing.T) {
 	}
 }
 
-func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GDesc, error) {
-	events, err := trace.Parse(r)
+func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GDesc) {
+	events, err := trace.Parse(r, "")
 	if err == trace.ErrTimeOrder {
 		t.Skipf("skipping trace: %v", err)
 	}
 	if err != nil {
-		return nil, nil, err
+		t.Fatalf("failed to parse trace: %v", err)
 	}
 	gs := trace.GoroutineStats(events)
 	for goid := range gs {
@@ -75,7 +75,31 @@ func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GD
 		// But still check that RelatedGoroutines does not crash, hang, etc.
 		_ = trace.RelatedGoroutines(events, goid)
 	}
-	return events, gs, nil
+	return events, gs
+}
+
+func testBrokenTimestamps(t *testing.T, data []byte) {
+	// On some processors cputicks (used to generate trace timestamps)
+	// produce non-monotonic timestamps. It is important that the parser
+	// distinguishes logically inconsistent traces (e.g. missing, excessive
+	// or misordered events) from broken timestamps. The former is a bug
+	// in tracer, the latter is a machine issue.
+	// So now that we have a consistent trace, test that (1) parser does
+	// not return a logical error in case of broken timestamps
+	// and (2) broken timestamps are eventually detected and reported.
+	trace.BreakTimestampsForTesting = true
+	defer func() {
+		trace.BreakTimestampsForTesting = false
+	}()
+	for i := 0; i < 1e4; i++ {
+		_, err := trace.Parse(bytes.NewReader(data), "")
+		if err == trace.ErrTimeOrder {
+			return
+		}
+		if err != nil {
+			t.Fatalf("failed to parse trace: %v", err)
+		}
+	}
 }
 
 func TestTraceStress(t *testing.T) {
@@ -209,10 +233,9 @@ func TestTraceStress(t *testing.T) {
 	runtime.GOMAXPROCS(procs)
 
 	Stop()
-	_, _, err = parseTrace(t, buf)
-	if err != nil {
-		t.Fatalf("failed to parse trace: %v", err)
-	}
+	trace := buf.Bytes()
+	parseTrace(t, buf)
+	testBrokenTimestamps(t, trace)
 }
 
 // Do a bunch of various stuff (timers, GC, network, etc) in a separate goroutine.
@@ -353,9 +376,9 @@ func TestTraceStressStartStop(t *testing.T) {
 		}
 		time.Sleep(time.Millisecond)
 		Stop()
-		if _, _, err := parseTrace(t, buf); err != nil {
-			t.Fatalf("failed to parse trace: %v", err)
-		}
+		trace := buf.Bytes()
+		parseTrace(t, buf)
+		testBrokenTimestamps(t, trace)
 	}
 	<-outerDone
 }
@@ -413,10 +436,7 @@ func TestTraceFutileWakeup(t *testing.T) {
 	done.Wait()
 
 	Stop()
-	events, _, err := parseTrace(t, buf)
-	if err != nil {
-		t.Fatalf("failed to parse trace: %v", err)
-	}
+	events, _ := parseTrace(t, buf)
 	// 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).
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index b4bfe71..80a5440 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -5,6 +5,7 @@
 package runtime
 
 import (
+	"runtime/internal/atomic"
 	"runtime/internal/sys"
 	"unsafe"
 )
@@ -98,7 +99,7 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 			frame.arglen = 0
 			frame.argmap = nil
 		} else {
-			frame.pc = uintptr(fn.fn)
+			frame.pc = fn.fn
 			f := findfunc(frame.pc)
 			if f == nil {
 				print("runtime: unknown pc in defer ", hex(frame.pc), "\n")
@@ -115,7 +116,7 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 	}
 }
 
-// Generic traceback.  Handles runtime stack prints (pcbuf == nil),
+// Generic traceback. Handles runtime stack prints (pcbuf == nil),
 // 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.
@@ -171,10 +172,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		frame.lr = lr0
 	}
 	waspanic := false
+	cgoCtxt := gp.cgoCtxt
 	printing := pcbuf == nil && callback == nil
 	_defer := gp._defer
 
-	for _defer != nil && uintptr(_defer.sp) == _NoArgs {
+	for _defer != nil && _defer.sp == _NoArgs {
 		_defer = _defer.link
 	}
 
@@ -239,6 +241,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		//	stk is the stack containing sp.
 		//	The caller's program counter is lr, unless lr is zero, in which case it is *(uintptr*)sp.
 		f = frame.fn
+		if f.pcsp == 0 {
+			// No frame information, must be external function, like race support.
+			// See golang.org/issue/13568.
+			break
+		}
 
 		// Found an actual function.
 		// Derive frame pointer and link register.
@@ -249,8 +256,10 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 			sp := frame.sp
 			if flags&_TraceJumpStack != 0 && f.entry == systemstackPC && gp == g.m.g0 && gp.m.curg != nil {
 				sp = gp.m.curg.sched.sp
+				frame.sp = sp
 				stkbarG = gp.m.curg
 				stkbar = stkbarG.stkbar[stkbarG.stkbarPos:]
+				cgoCtxt = gp.m.curg.cgoCtxt
 			}
 			frame.fp = sp + uintptr(funcspdelta(f, frame.pc, &cache))
 			if !usesLR {
@@ -412,6 +421,18 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		n++
 
 	skipped:
+		if f.entry == cgocallback_gofuncPC && len(cgoCtxt) > 0 {
+			ctxt := cgoCtxt[len(cgoCtxt)-1]
+			cgoCtxt = cgoCtxt[:len(cgoCtxt)-1]
+
+			// skip only applies to Go frames.
+			// callback != nil only used when we only care
+			// about Go frames.
+			if skip == 0 && callback == nil {
+				n = tracebackCgoContext(pcbuf, printing, ctxt, n, max)
+			}
+		}
+
 		waspanic = f.entry == sigpanicPC
 
 		// Do not unwind past the bottom of the stack.
@@ -545,6 +566,39 @@ func getArgInfo(frame *stkframe, f *_func, needArgMap bool) (arglen uintptr, arg
 	return
 }
 
+// tracebackCgoContext handles tracing back a cgo context value, from
+// the context argument to setCgoTraceback, for the gentraceback
+// function. It returns the new value of n.
+func tracebackCgoContext(pcbuf *uintptr, printing bool, ctxt uintptr, n, max int) int {
+	var cgoPCs [32]uintptr
+	cgoContextPCs(ctxt, cgoPCs[:])
+	var arg cgoSymbolizerArg
+	anySymbolized := false
+	for _, pc := range cgoPCs {
+		if pc == 0 || n >= max {
+			break
+		}
+		if pcbuf != nil {
+			(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = pc
+		}
+		if printing {
+			if cgoSymbolizer == nil {
+				print("non-Go function at pc=", hex(pc), "\n")
+			} else {
+				c := printOneCgoTraceback(pc, max-n, &arg)
+				n += c - 1 // +1 a few lines down
+				anySymbolized = true
+			}
+		}
+		n++
+	}
+	if anySymbolized {
+		arg.pc = 0
+		callCgoSymbolizer(&arg)
+	}
+	return n
+}
+
 func printcreatedby(gp *g) {
 	// Show what created goroutine, except main goroutine (goid 1).
 	pc := gp.gopc
@@ -579,6 +633,22 @@ func tracebacktrap(pc, sp, lr uintptr, gp *g) {
 }
 
 func traceback1(pc, sp, lr uintptr, gp *g, flags uint) {
+	// If the goroutine is in cgo, and we have a cgo traceback, print that.
+	if iscgo && gp.m != nil && gp.m.ncgo > 0 && gp.syscallsp != 0 && gp.m.cgoCallers != nil && gp.m.cgoCallers[0] != 0 {
+		// Lock cgoCallers so that a signal handler won't
+		// change it, copy the array, reset it, unlock it.
+		// We are locked to the thread and are not running
+		// concurrently with a signal handler.
+		// We just have to stop a signal handler from interrupting
+		// in the middle of our copy.
+		atomic.Store(&gp.m.cgoCallersUse, 1)
+		cgoCallers := *gp.m.cgoCallers
+		gp.m.cgoCallers[0] = 0
+		atomic.Store(&gp.m.cgoCallersUse, 0)
+
+		printCgoTraceback(&cgoCallers)
+	}
+
 	var n int
 	if readgstatus(gp)&^_Gscan == _Gsyscall {
 		// Override registers if blocked in system call.
@@ -600,7 +670,7 @@ func traceback1(pc, sp, lr uintptr, gp *g, flags uint) {
 
 func callers(skip int, pcbuf []uintptr) int {
 	sp := getcallersp(unsafe.Pointer(&skip))
-	pc := uintptr(getcallerpc(unsafe.Pointer(&skip)))
+	pc := getcallerpc(unsafe.Pointer(&skip))
 	gp := getg()
 	var n int
 	systemstack(func() {
@@ -645,7 +715,6 @@ var gStatusStrings = [...]string{
 	_Gsyscall:   "syscall",
 	_Gwaiting:   "waiting",
 	_Gdead:      "dead",
-	_Genqueue:   "enqueue",
 	_Gcopystack: "copystack",
 }
 
@@ -707,7 +776,7 @@ func tracebackothers(me *g) {
 		goroutineheader(gp)
 		// 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
+		// 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")
@@ -740,3 +809,292 @@ func isSystemGoroutine(gp *g) bool {
 		pc == timerprocPC ||
 		pc == gcBgMarkWorkerPC
 }
+
+// SetCgoTraceback records three C functions to use to gather
+// traceback information from C code and to convert that traceback
+// information into symbolic information. These are used when printing
+// stack traces for a program that uses cgo.
+//
+// The traceback and context functions may be called from a signal
+// handler, and must therefore use only async-signal safe functions.
+// The symbolizer function may be called while the program is
+// crashing, and so must be cautious about using memory.  None of the
+// functions may call back into Go.
+//
+// The context function will be called with a single argument, a
+// pointer to a struct:
+//
+//	struct {
+//		Context uintptr
+//	}
+//
+// In C syntax, this struct will be
+//
+//	struct {
+//		uintptr_t Context;
+//	};
+//
+// If the Context field is 0, the context function is being called to
+// record the current traceback context. It should record in the
+// Context field whatever information is needed about the current
+// point of execution to later produce a stack trace, probably the
+// stack pointer and PC. In this case the context function will be
+// called from C code.
+//
+// If the Context field is not 0, then it is a value returned by a
+// previous call to the context function. This case is called when the
+// context is no longer needed; that is, when the Go code is returning
+// to its C code caller. This permits the context function to release
+// any associated resources.
+//
+// While it would be correct for the context function to record a
+// complete a stack trace whenever it is called, and simply copy that
+// out in the traceback function, in a typical program the context
+// function will be called many times without ever recording a
+// traceback for that context. Recording a complete stack trace in a
+// call to the context function is likely to be inefficient.
+//
+// The traceback function will be called with a single argument, a
+// pointer to a struct:
+//
+//	struct {
+//		Context    uintptr
+//		SigContext uintptr
+//		Buf        *uintptr
+//		Max        uintptr
+//	}
+//
+// In C syntax, this struct will be
+//
+//	struct {
+//		uintptr_t  Context;
+//		uintptr_t  SigContext;
+//		uintptr_t* Buf;
+//		uintptr_t  Max;
+//	};
+//
+// The Context field will be zero to gather a traceback from the
+// current program execution point. In this case, the traceback
+// function will be called from C code.
+//
+// Otherwise Context will be a value previously returned by a call to
+// the context function. The traceback function should gather a stack
+// trace from that saved point in the program execution. The traceback
+// function may be called from an execution thread other than the one
+// that recorded the context, but only when the context is known to be
+// valid and unchanging. The traceback function may also be called
+// deeper in the call stack on the same thread that recorded the
+// context. The traceback function may be called multiple times with
+// the same Context value; it will usually be appropriate to cache the
+// result, if possible, the first time this is called for a specific
+// context value.
+//
+// If the traceback function is called from a signal handler on a Unix
+// system, SigContext will be the signal context argument passed to
+// the signal handler (a C ucontext_t* cast to uintptr_t). This may be
+// used to start tracing at the point where the signal occurred. If
+// the traceback function is not called from a signal handler,
+// SigContext will be zero.
+//
+// Buf is where the traceback information should be stored. It should
+// be PC values, such that Buf[0] is the PC of the caller, Buf[1] is
+// the PC of that function's caller, and so on.  Max is the maximum
+// number of entries to store.  The function should store a zero to
+// indicate the top of the stack, or that the caller is on a different
+// stack, presumably a Go stack.
+//
+// Unlike runtime.Callers, the PC values returned should, when passed
+// to the symbolizer function, return the file/line of the call
+// instruction.  No additional subtraction is required or appropriate.
+//
+// The symbolizer function will be called with a single argument, a
+// pointer to a struct:
+//
+//	struct {
+//		PC      uintptr // program counter to fetch information for
+//		File    *byte   // file name (NUL terminated)
+//		Lineno  uintptr // line number
+//		Func    *byte   // function name (NUL terminated)
+//		Entry   uintptr // function entry point
+//		More    uintptr // set non-zero if more info for this PC
+//		Data    uintptr // unused by runtime, available for function
+//	}
+//
+// In C syntax, this struct will be
+//
+//	struct {
+//		uintptr_t PC;
+//		char*     File;
+//		uintptr_t Lineno;
+//		char*     Func;
+//		uintptr_t Entry;
+//		uintptr_t More;
+//		uintptr_t Data;
+//	};
+//
+// The PC field will be a value returned by a call to the traceback
+// function.
+//
+// The first time the function is called for a particular traceback,
+// all the fields except PC will be 0. The function should fill in the
+// other fields if possible, setting them to 0/nil if the information
+// is not available. The Data field may be used to store any useful
+// information across calls. The More field should be set to non-zero
+// if there is more information for this PC, zero otherwise. If More
+// is set non-zero, the function will be called again with the same
+// PC, and may return different information (this is intended for use
+// with inlined functions). If More is zero, the function will be
+// called with the next PC value in the traceback. When the traceback
+// is complete, the function will be called once more with PC set to
+// zero; this may be used to free any information. Each call will
+// leave the fields of the struct set to the same values they had upon
+// return, except for the PC field when the More field is zero. The
+// function must not keep a copy of the struct pointer between calls.
+//
+// When calling SetCgoTraceback, the version argument is the version
+// number of the structs that the functions expect to receive.
+// Currently this must be zero.
+//
+// The symbolizer function may be nil, in which case the results of
+// the traceback function will be displayed as numbers. If the
+// traceback function is nil, the symbolizer function will never be
+// called. The context function may be nil, in which case the
+// traceback function will only be called with the context field set
+// to zero.  If the context function is nil, then calls from Go to C
+// to Go will not show a traceback for the C portion of the call stack.
+//
+// SetCgoTraceback should be called only once, ideally from an init function.
+func SetCgoTraceback(version int, traceback, context, symbolizer unsafe.Pointer) {
+	if version != 0 {
+		panic("unsupported version")
+	}
+
+	if cgoTraceback != nil && cgoTraceback != traceback ||
+		cgoContext != nil && cgoContext != context ||
+		cgoSymbolizer != nil && cgoSymbolizer != symbolizer {
+		panic("call SetCgoTraceback only once")
+	}
+
+	cgoTraceback = traceback
+	cgoContext = context
+	cgoSymbolizer = symbolizer
+
+	// The context function is called when a C function calls a Go
+	// function. As such it is only called by C code in runtime/cgo.
+	if _cgo_set_context_function != nil {
+		cgocall(_cgo_set_context_function, context)
+	}
+}
+
+var cgoTraceback unsafe.Pointer
+var cgoContext unsafe.Pointer
+var cgoSymbolizer unsafe.Pointer
+
+// cgoTracebackArg is the type passed to cgoTraceback.
+type cgoTracebackArg struct {
+	context    uintptr
+	sigContext uintptr
+	buf        *uintptr
+	max        uintptr
+}
+
+// cgoContextArg is the type passed to the context function.
+type cgoContextArg struct {
+	context uintptr
+}
+
+// cgoSymbolizerArg is the type passed to cgoSymbolizer.
+type cgoSymbolizerArg struct {
+	pc       uintptr
+	file     *byte
+	lineno   uintptr
+	funcName *byte
+	entry    uintptr
+	more     uintptr
+	data     uintptr
+}
+
+// cgoTraceback prints a traceback of callers.
+func printCgoTraceback(callers *cgoCallers) {
+	if cgoSymbolizer == nil {
+		for _, c := range callers {
+			if c == 0 {
+				break
+			}
+			print("non-Go function at pc=", hex(c), "\n")
+		}
+		return
+	}
+
+	var arg cgoSymbolizerArg
+	for _, c := range callers {
+		if c == 0 {
+			break
+		}
+		printOneCgoTraceback(c, 0x7fffffff, &arg)
+	}
+	arg.pc = 0
+	callCgoSymbolizer(&arg)
+}
+
+// printOneCgoTraceback prints the traceback of a single cgo caller.
+// This can print more than one line because of inlining.
+// Returns the number of frames printed.
+func printOneCgoTraceback(pc uintptr, max int, arg *cgoSymbolizerArg) int {
+	c := 0
+	arg.pc = pc
+	for {
+		if c > max {
+			break
+		}
+		callCgoSymbolizer(arg)
+		if arg.funcName != nil {
+			// Note that we don't print any argument
+			// information here, not even parentheses.
+			// The symbolizer must add that if appropriate.
+			println(gostringnocopy(arg.funcName))
+		} else {
+			println("non-Go function")
+		}
+		print("\t")
+		if arg.file != nil {
+			print(gostringnocopy(arg.file), ":", arg.lineno, " ")
+		}
+		print("pc=", hex(pc), "\n")
+		c++
+		if arg.more == 0 {
+			break
+		}
+	}
+	return c
+}
+
+// callCgoSymbolizer calls the cgoSymbolizer function.
+func callCgoSymbolizer(arg *cgoSymbolizerArg) {
+	call := cgocall
+	if panicking > 0 || getg().m.curg != getg() {
+		// We do not want to call into the scheduler when panicking
+		// or when on the system stack.
+		call = asmcgocall
+	}
+	call(cgoSymbolizer, noescape(unsafe.Pointer(arg)))
+}
+
+// cgoContextPCs gets the PC values from a cgo traceback.
+func cgoContextPCs(ctxt uintptr, buf []uintptr) {
+	if cgoTraceback == nil {
+		return
+	}
+	call := cgocall
+	if panicking > 0 || getg().m.curg != getg() {
+		// We do not want to call into the scheduler when panicking
+		// or when on the system stack.
+		call = asmcgocall
+	}
+	arg := cgoTracebackArg{
+		context: ctxt,
+		buf:     (*uintptr)(noescape(unsafe.Pointer(&buf[0]))),
+		max:     uintptr(len(buf)),
+	}
+	call(cgoTraceback, noescape(unsafe.Pointer(&arg)))
+}
diff --git a/src/runtime/type.go b/src/runtime/type.go
index d5f3bb1..5ef11a4 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -8,6 +8,20 @@ package runtime
 
 import "unsafe"
 
+// tflag is documented in reflect/type.go.
+//
+// tflag values must be kept in sync with copies in:
+//	cmd/compile/internal/gc/reflect.go
+//	cmd/link/internal/ld/decodesym.go
+//	reflect/type.go
+type tflag uint8
+
+const (
+	tflagUncommon  tflag = 1 << 0
+	tflagExtraStar tflag = 1 << 1
+	tflagNamed     tflag = 1 << 2
+)
+
 // Needs to be in sync with ../cmd/compile/internal/ld/decodesym.go:/^func.commonsize,
 // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and
 // ../reflect/type.go:/^type.rtype.
@@ -15,7 +29,7 @@ type _type struct {
 	size       uintptr
 	ptrdata    uintptr // size of memory prefix holding all pointers
 	hash       uint32
-	_unused    uint8
+	tflag      tflag
 	align      uint8
 	fieldalign uint8
 	kind       uint8
@@ -23,36 +37,285 @@ type _type struct {
 	// 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
+	gcdata    *byte
+	str       nameOff
+	ptrToThis typeOff
+}
+
+func (t *_type) string() string {
+	s := t.nameOff(t.str).name()
+	if t.tflag&tflagExtraStar != 0 {
+		return s[1:]
+	}
+	return s
+}
+
+func (t *_type) uncommon() *uncommontype {
+	if t.tflag&tflagUncommon == 0 {
+		return nil
+	}
+	switch t.kind & kindMask {
+	case kindStruct:
+		type u struct {
+			structtype
+			u uncommontype
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case kindPtr:
+		type u struct {
+			ptrtype
+			u uncommontype
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case kindFunc:
+		type u struct {
+			functype
+			u uncommontype
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case kindSlice:
+		type u struct {
+			slicetype
+			u uncommontype
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case kindArray:
+		type u struct {
+			arraytype
+			u uncommontype
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case kindChan:
+		type u struct {
+			chantype
+			u uncommontype
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case kindMap:
+		type u struct {
+			maptype
+			u uncommontype
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	case kindInterface:
+		type u struct {
+			interfacetype
+			u uncommontype
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	default:
+		type u struct {
+			_type
+			u uncommontype
+		}
+		return &(*u)(unsafe.Pointer(t)).u
+	}
+}
+
+func hasPrefix(s, prefix string) bool {
+	return len(s) >= len(prefix) && s[:len(prefix)] == prefix
+}
+
+func (t *_type) name() string {
+	if t.tflag&tflagNamed == 0 {
+		return ""
+	}
+	s := t.string()
+	i := len(s) - 1
+	for i >= 0 {
+		if s[i] == '.' {
+			break
+		}
+		i--
+	}
+	return s[i+1:]
+}
+
+// reflectOffs holds type offsets defined at run time by the reflect package.
+//
+// When a type is defined at run time, its *rtype data lives on the heap.
+// There are a wide range of possible addresses the heap may use, that
+// may not be representable as a 32-bit offset. Moreover the GC may
+// one day start moving heap memory, in which case there is no stable
+// offset that can be defined.
+//
+// To provide stable offsets, we add pin *rtype objects in a global map
+// and treat the offset as an identifier. We use negative offsets that
+// do not overlap with any compile-time module offsets.
+//
+// Entries are created by reflect.addReflectOff.
+var reflectOffs struct {
+	lock mutex
+	next int32
+	m    map[int32]unsafe.Pointer
+	minv map[unsafe.Pointer]int32
+}
+
+func reflectOffsLock() {
+	lock(&reflectOffs.lock)
+	if raceenabled {
+		raceacquire(unsafe.Pointer(&reflectOffs.lock))
+	}
+}
+
+func reflectOffsUnlock() {
+	if raceenabled {
+		racerelease(unsafe.Pointer(&reflectOffs.lock))
+	}
+	unlock(&reflectOffs.lock)
+}
+
+func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
+	if off == 0 {
+		return name{}
+	}
+	base := uintptr(ptrInModule)
+	for md := &firstmoduledata; md != nil; md = md.next {
+		if base >= md.types && base < md.etypes {
+			res := md.types + uintptr(off)
+			if res > md.etypes {
+				println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
+				throw("runtime: name offset out of range")
+			}
+			return name{(*byte)(unsafe.Pointer(res))}
+		}
+	}
+
+	// No module found. see if it is a run time name.
+	reflectOffsLock()
+	res, found := reflectOffs.m[int32(off)]
+	reflectOffsUnlock()
+	if !found {
+		println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
+		for next := &firstmoduledata; next != nil; next = next.next {
+			println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
+		}
+		throw("runtime: name offset base pointer out of range")
+	}
+	return name{(*byte)(res)}
+}
+
+func (t *_type) nameOff(off nameOff) name {
+	return resolveNameOff(unsafe.Pointer(t), off)
+}
+
+func (t *_type) typeOff(off typeOff) *_type {
+	if off == 0 {
+		return nil
+	}
+	base := uintptr(unsafe.Pointer(t))
+	var md *moduledata
+	for next := &firstmoduledata; next != nil; next = next.next {
+		if base >= next.types && base < next.etypes {
+			md = next
+			break
+		}
+	}
+	if md == nil {
+		reflectOffsLock()
+		res := reflectOffs.m[int32(off)]
+		reflectOffsUnlock()
+		if res == nil {
+			println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:")
+			for next := &firstmoduledata; next != nil; next = next.next {
+				println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
+			}
+			throw("runtime: type offset base pointer out of range")
+		}
+		return (*_type)(res)
+	}
+	if t := md.typemap[off]; t != nil {
+		return t
+	}
+	res := md.types + uintptr(off)
+	if res > md.etypes {
+		println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
+		throw("runtime: type offset out of range")
+	}
+	return (*_type)(unsafe.Pointer(res))
+}
+
+func (t *_type) textOff(off textOff) unsafe.Pointer {
+	base := uintptr(unsafe.Pointer(t))
+	var md *moduledata
+	for next := &firstmoduledata; next != nil; next = next.next {
+		if base >= next.types && base < next.etypes {
+			md = next
+			break
+		}
+	}
+	if md == nil {
+		reflectOffsLock()
+		res := reflectOffs.m[int32(off)]
+		reflectOffsUnlock()
+		if res == nil {
+			println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:")
+			for next := &firstmoduledata; next != nil; next = next.next {
+				println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
+			}
+			throw("runtime: text offset base pointer out of range")
+		}
+		return res
+	}
+	res := md.text + uintptr(off)
+	if res > md.etext {
+		println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext))
+		throw("runtime: text offset out of range")
+	}
+	return unsafe.Pointer(res)
+}
+
+func (t *functype) in() []*_type {
+	// See funcType in reflect/type.go for details on data layout.
+	uadd := uintptr(unsafe.Sizeof(functype{}))
+	if t.typ.tflag&tflagUncommon != 0 {
+		uadd += unsafe.Sizeof(uncommontype{})
+	}
+	return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount]
+}
+
+func (t *functype) out() []*_type {
+	// See funcType in reflect/type.go for details on data layout.
+	uadd := uintptr(unsafe.Sizeof(functype{}))
+	if t.typ.tflag&tflagUncommon != 0 {
+		uadd += unsafe.Sizeof(uncommontype{})
+	}
+	outCount := t.outCount & (1<<15 - 1)
+	return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount]
+}
+
+func (t *functype) dotdotdot() bool {
+	return t.outCount&(1<<15) != 0
 }
 
+type nameOff int32
+type typeOff int32
+type textOff int32
+
 type method struct {
-	name    *string
-	pkgpath *string
-	mtyp    *_type
-	typ     *_type
-	ifn     unsafe.Pointer
-	tfn     unsafe.Pointer
+	name nameOff
+	mtyp typeOff
+	ifn  textOff
+	tfn  textOff
 }
 
 type uncommontype struct {
-	name    *string
-	pkgpath *string
-	mhdr    []method
+	pkgpath nameOff
+	mcount  uint16 // number of methods
+	_       uint16 // unused
+	moff    uint32 // offset from this uncommontype to [mcount]method
+	_       uint32 // unused
 }
 
 type imethod struct {
-	name    *string
-	pkgpath *string
-	_type   *_type
+	name nameOff
+	ityp typeOff
 }
 
 type interfacetype struct {
-	typ  _type
-	mhdr []imethod
+	typ     _type
+	pkgpath name
+	mhdr    []imethod
 }
 
 type maptype struct {
@@ -89,10 +352,9 @@ type slicetype struct {
 }
 
 type functype struct {
-	typ       _type
-	dotdotdot bool
-	in        []*_type
-	out       []*_type
+	typ      _type
+	inCount  uint16
+	outCount uint16
 }
 
 type ptrtype struct {
@@ -101,14 +363,270 @@ type ptrtype struct {
 }
 
 type structfield struct {
-	name    *string
-	pkgpath *string
-	typ     *_type
-	tag     *string
-	offset  uintptr
+	name   name
+	typ    *_type
+	offset uintptr
 }
 
 type structtype struct {
-	typ    _type
-	fields []structfield
+	typ     _type
+	pkgPath name
+	fields  []structfield
+}
+
+// name is an encoded type name with optional extra data.
+// See reflect/type.go for details.
+type name struct {
+	bytes *byte
+}
+
+func (n name) data(off int) *byte {
+	return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off)))
+}
+
+func (n name) isExported() bool {
+	return (*n.bytes)&(1<<0) != 0
+}
+
+func (n name) nameLen() int {
+	return int(uint16(*n.data(1))<<8 | uint16(*n.data(2)))
+}
+
+func (n name) tagLen() int {
+	if *n.data(0)&(1<<1) == 0 {
+		return 0
+	}
+	off := 3 + n.nameLen()
+	return int(uint16(*n.data(off))<<8 | uint16(*n.data(off + 1)))
+}
+
+func (n name) name() (s string) {
+	if n.bytes == nil {
+		return ""
+	}
+	nl := n.nameLen()
+	if nl == 0 {
+		return ""
+	}
+	hdr := (*stringStruct)(unsafe.Pointer(&s))
+	hdr.str = unsafe.Pointer(n.data(3))
+	hdr.len = nl
+	return s
+}
+
+func (n name) tag() (s string) {
+	tl := n.tagLen()
+	if tl == 0 {
+		return ""
+	}
+	nl := n.nameLen()
+	hdr := (*stringStruct)(unsafe.Pointer(&s))
+	hdr.str = unsafe.Pointer(n.data(3 + nl + 2))
+	hdr.len = tl
+	return s
+}
+
+func (n name) pkgPath() string {
+	if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
+		return ""
+	}
+	off := 3 + n.nameLen()
+	if tl := n.tagLen(); tl > 0 {
+		off += 2 + tl
+	}
+	var nameOff nameOff
+	copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
+	pkgPathName := resolveNameOff(unsafe.Pointer(n.bytes), nameOff)
+	return pkgPathName.name()
+}
+
+// typelinksinit scans the types from extra modules and builds the
+// moduledata typemap used to de-duplicate type pointers.
+func typelinksinit() {
+	if firstmoduledata.next == nil {
+		return
+	}
+	typehash := make(map[uint32][]*_type)
+
+	modules := []*moduledata{}
+	for md := &firstmoduledata; md != nil; md = md.next {
+		modules = append(modules, md)
+	}
+	prev, modules := modules[len(modules)-1], modules[:len(modules)-1]
+	for len(modules) > 0 {
+		// Collect types from the previous module into typehash.
+	collect:
+		for _, tl := range prev.typelinks {
+			var t *_type
+			if prev.typemap == nil {
+				t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl)))
+			} else {
+				t = prev.typemap[typeOff(tl)]
+			}
+			// Add to typehash if not seen before.
+			tlist := typehash[t.hash]
+			for _, tcur := range tlist {
+				if tcur == t {
+					continue collect
+				}
+			}
+			typehash[t.hash] = append(tlist, t)
+		}
+
+		// If any of this module's typelinks match a type from a
+		// prior module, prefer that prior type by adding the offset
+		// to this module's typemap.
+		md := modules[len(modules)-1]
+		md.typemap = make(map[typeOff]*_type, len(md.typelinks))
+		for _, tl := range md.typelinks {
+			t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
+			for _, candidate := range typehash[t.hash] {
+				if typesEqual(t, candidate) {
+					t = candidate
+					break
+				}
+			}
+			md.typemap[typeOff(tl)] = t
+		}
+
+		prev, modules = md, modules[:len(modules)-1]
+	}
+}
+
+// typesEqual reports whether two types are equal.
+//
+// Everywhere in the runtime and reflect packages, it is assumed that
+// there is exactly one *_type per Go type, so that pointer equality
+// can be used to test if types are equal. There is one place that
+// breaks this assumption: buildmode=shared. In this case a type can
+// appear as two different pieces of memory. This is hidden from the
+// runtime and reflect package by the per-module typemap built in
+// typelinksinit. It uses typesEqual to map types from later modules
+// back into earlier ones.
+//
+// Only typelinksinit needs this function.
+func typesEqual(t, v *_type) bool {
+	if t == v {
+		return true
+	}
+	kind := t.kind & kindMask
+	if kind != v.kind&kindMask {
+		return false
+	}
+	if t.string() != v.string() {
+		return false
+	}
+	ut := t.uncommon()
+	uv := v.uncommon()
+	if ut != nil || uv != nil {
+		if ut == nil || uv == nil {
+			return false
+		}
+		pkgpatht := t.nameOff(ut.pkgpath).name()
+		pkgpathv := v.nameOff(uv.pkgpath).name()
+		if pkgpatht != pkgpathv {
+			return false
+		}
+	}
+	if kindBool <= kind && kind <= kindComplex128 {
+		return true
+	}
+	switch kind {
+	case kindString, kindUnsafePointer:
+		return true
+	case kindArray:
+		at := (*arraytype)(unsafe.Pointer(t))
+		av := (*arraytype)(unsafe.Pointer(v))
+		return typesEqual(at.elem, av.elem) && at.len == av.len
+	case kindChan:
+		ct := (*chantype)(unsafe.Pointer(t))
+		cv := (*chantype)(unsafe.Pointer(v))
+		return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem)
+	case kindFunc:
+		ft := (*functype)(unsafe.Pointer(t))
+		fv := (*functype)(unsafe.Pointer(v))
+		if ft.outCount != fv.outCount || ft.inCount != fv.inCount {
+			return false
+		}
+		tin, vin := ft.in(), fv.in()
+		for i := 0; i < len(tin); i++ {
+			if !typesEqual(tin[i], vin[i]) {
+				return false
+			}
+		}
+		tout, vout := ft.out(), fv.out()
+		for i := 0; i < len(tout); i++ {
+			if !typesEqual(tout[i], vout[i]) {
+				return false
+			}
+		}
+		return true
+	case kindInterface:
+		it := (*interfacetype)(unsafe.Pointer(t))
+		iv := (*interfacetype)(unsafe.Pointer(v))
+		if it.pkgpath.name() != iv.pkgpath.name() {
+			return false
+		}
+		if len(it.mhdr) != len(iv.mhdr) {
+			return false
+		}
+		for i := range it.mhdr {
+			tm := &it.mhdr[i]
+			vm := &iv.mhdr[i]
+			tname := it.typ.nameOff(tm.name)
+			vname := iv.typ.nameOff(vm.name)
+			if tname.name() != vname.name() {
+				return false
+			}
+			if tname.pkgPath() != vname.pkgPath() {
+				return false
+			}
+			if !typesEqual(it.typ.typeOff(tm.ityp), iv.typ.typeOff(vm.ityp)) {
+				return false
+			}
+		}
+		return true
+	case kindMap:
+		mt := (*maptype)(unsafe.Pointer(t))
+		mv := (*maptype)(unsafe.Pointer(v))
+		return typesEqual(mt.key, mv.key) && typesEqual(mt.elem, mv.elem)
+	case kindPtr:
+		pt := (*ptrtype)(unsafe.Pointer(t))
+		pv := (*ptrtype)(unsafe.Pointer(v))
+		return typesEqual(pt.elem, pv.elem)
+	case kindSlice:
+		st := (*slicetype)(unsafe.Pointer(t))
+		sv := (*slicetype)(unsafe.Pointer(v))
+		return typesEqual(st.elem, sv.elem)
+	case kindStruct:
+		st := (*structtype)(unsafe.Pointer(t))
+		sv := (*structtype)(unsafe.Pointer(v))
+		if len(st.fields) != len(sv.fields) {
+			return false
+		}
+		for i := range st.fields {
+			tf := &st.fields[i]
+			vf := &sv.fields[i]
+			if tf.name.name() != vf.name.name() {
+				return false
+			}
+			if tf.name.pkgPath() != vf.name.pkgPath() {
+				return false
+			}
+			if !typesEqual(tf.typ, vf.typ) {
+				return false
+			}
+			if tf.name.tag() != vf.name.tag() {
+				return false
+			}
+			if tf.offset != vf.offset {
+				return false
+			}
+		}
+		return true
+	default:
+		println("runtime: impossible type kind", kind)
+		throw("runtime: impossible type kind")
+		return false
+	}
 }
diff --git a/src/runtime/typekind.go b/src/runtime/typekind.go
index d146dca..abb2777 100644
--- a/src/runtime/typekind.go
+++ b/src/runtime/typekind.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/runtime/unaligned1.go b/src/runtime/unaligned1.go
index d3d6c70..754d63b 100644
--- a/src/runtime/unaligned1.go
+++ b/src/runtime/unaligned1.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build 386 amd64 amd64p32 arm64
+// +build 386 amd64 amd64p32 arm64 ppc64 ppc64le s390x
 
 package runtime
 
diff --git a/src/runtime/unaligned2.go b/src/runtime/unaligned2.go
index 1ec1d16..fed3cca 100644
--- a/src/runtime/unaligned2.go
+++ b/src/runtime/unaligned2.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 arm ppc64 ppc64le mips64 mips64le
+// +build arm mips64 mips64le
 
 package runtime
 
diff --git a/src/runtime/vdso_linux_amd64.go b/src/runtime/vdso_linux_amd64.go
index 38914bb..8a970df 100644
--- a/src/runtime/vdso_linux_amd64.go
+++ b/src/runtime/vdso_linux_amd64.go
@@ -4,10 +4,7 @@
 
 package runtime
 
-import (
-	"runtime/internal/sys"
-	"unsafe"
-)
+import "unsafe"
 
 // Look up symbols in the Linux vDSO.
 
@@ -21,9 +18,7 @@ import (
 // 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 */
@@ -263,7 +258,7 @@ func vdso_find_version(info *vdso_info, ver *version_key) int32 {
 		def = (*elf64Verdef)(add(unsafe.Pointer(def), uintptr(def.vd_next)))
 	}
 
-	return -1 // can not match any version
+	return -1 // cannot match any version
 }
 
 func vdso_parse_symbols(info *vdso_info, version int32) {
@@ -294,37 +289,18 @@ func vdso_parse_symbols(info *vdso_info, version int32) {
 	}
 }
 
-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)*sys.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)))[:]
+func archauxv(tag, val uintptr) {
+	switch tag {
+	case _AT_SYSINFO_EHDR:
+		if val == 0 {
+			// Something went wrong
+			return
 		}
+		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(val)))
+		vdso_parse_symbols(info1, vdso_find_version(info1, &linux26))
 	}
 }
diff --git a/src/runtime/vdso_none.go b/src/runtime/vdso_none.go
index 93bd91c..efae23f 100644
--- a/src/runtime/vdso_none.go
+++ b/src/runtime/vdso_none.go
@@ -1,10 +1,8 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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
+// +build !linux
 
 package runtime
 
diff --git a/src/runtime/vlop_386.s b/src/runtime/vlop_386.s
index ce8e7d0..92232d5 100644
--- a/src/runtime/vlop_386.s
+++ b/src/runtime/vlop_386.s
@@ -1,7 +1,7 @@
 // Inferno's libkern/vlop-386.s
 // http://code.google.com/p/inferno-os/source/browse/libkern/vlop-386.s
 //
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         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.
 //
diff --git a/src/runtime/vlop_arm.s b/src/runtime/vlop_arm.s
index ae1f582..338d9d5 100644
--- a/src/runtime/vlop_arm.s
+++ b/src/runtime/vlop_arm.s
@@ -1,7 +1,7 @@
 // Inferno's libkern/vlop-arm.s
 // http://code.google.com/p/inferno-os/source/browse/libkern/vlop-arm.s
 //
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         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.
 //
diff --git a/src/runtime/vlop_arm_test.go b/src/runtime/vlop_arm_test.go
index 1a21119..85cea92 100644
--- a/src/runtime/vlop_arm_test.go
+++ b/src/runtime/vlop_arm_test.go
@@ -82,3 +82,47 @@ func TestUsplit(t *testing.T) {
 		}
 	}
 }
+
+//go:noinline
+func armFloatWrite(a *[129]float64) {
+	// This used to miscompile on arm5.
+	// The offset is too big to fit in a load.
+	// So the code does:
+	//   ldr     r0, [sp, #8]
+	//   bl      6f690 <_sfloat>
+	//   ldr     fp, [pc, #32]   ; (address of 128.0)
+	//   vldr    d0, [fp]
+	//   ldr     fp, [pc, #28]   ; (1024)
+	//   add     fp, fp, r0
+	//   vstr    d0, [fp]
+	// The software floating-point emulator gives up on the add.
+	// This causes the store to not work.
+	// See issue 15440.
+	a[128] = 128.0
+}
+func TestArmFloatBigOffsetWrite(t *testing.T) {
+	var a [129]float64
+	for i := 0; i < 128; i++ {
+		a[i] = float64(i)
+	}
+	armFloatWrite(&a)
+	for i, x := range a {
+		if x != float64(i) {
+			t.Errorf("bad entry %d:%f\n", i, x)
+		}
+	}
+}
+
+//go:noinline
+func armFloatRead(a *[129]float64) float64 {
+	return a[128]
+}
+func TestArmFloatBigOffsetRead(t *testing.T) {
+	var a [129]float64
+	for i := 0; i < 129; i++ {
+		a[i] = float64(i)
+	}
+	if x := armFloatRead(&a); x != 128.0 {
+		t.Errorf("bad value %f\n", x)
+	}
+}
diff --git a/src/runtime/vlrt.go b/src/runtime/vlrt.go
index 6370732..cd37828 100644
--- a/src/runtime/vlrt.go
+++ b/src/runtime/vlrt.go
@@ -1,7 +1,7 @@
 // Inferno's libkern/vlrt-arm.c
 // http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-arm.c
 //
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//         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.
 //
@@ -195,7 +195,6 @@ func dodiv(n, d uint64) (q, r uint64) {
 	if GOARCH == "arm" {
 		// arm doesn't have a division instruction, so
 		// slowdodiv is the best that we can do.
-		// TODO: revisit for arm64.
 		return slowdodiv(n, d)
 	}
 
diff --git a/src/runtime/wbfat.go b/src/runtime/wbfat.go
deleted file mode 100644
index 8fe2cef..0000000
--- a/src/runtime/wbfat.go
+++ /dev/null
@@ -1,190 +0,0 @@
-// 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
deleted file mode 100644
index 9482cfe..0000000
--- a/src/runtime/wbfat_gen.go
+++ /dev/null
@@ -1,41 +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 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
index a16ad21..9f003ae 100644
--- a/src/runtime/wincallback.go
+++ b/src/runtime/wincallback.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/sort/search.go b/src/sort/search.go
index de8178f..b9640a4 100644
--- a/src/sort/search.go
+++ b/src/sort/search.go
@@ -8,10 +8,10 @@ package sort
 
 // Search uses binary search to find and return the smallest index i
 // in [0, n) at which f(i) is true, assuming that on the range [0, n),
-// f(i) == true implies f(i+1) == true.  That is, Search requires that
+// f(i) == true implies f(i+1) == true. That is, Search requires that
 // f is false for some (possibly empty) prefix of the input range [0, n)
 // and then true for the (possibly empty) remainder; Search returns
-// the first true index.  If there is no such index, Search returns n.
+// the first true index. If there is no such index, Search returns n.
 // (Note that the "not found" return value is not -1 as in, for instance,
 // strings.Index.)
 // Search calls f(i) only for i in the range [0, n).
@@ -85,7 +85,7 @@ func SearchInts(a []int, x int) int {
 }
 
 // SearchFloat64s searches for x in a sorted slice of float64s and returns the index
-// as specified by Search.  The return value is the index to insert x if x is not
+// as specified by Search. The return value is the index to insert x if x is not
 // present (it could be len(a)).
 // The slice must be sorted in ascending order.
 //
@@ -94,7 +94,7 @@ func SearchFloat64s(a []float64, x float64) int {
 }
 
 // SearchStrings searches for x in a sorted slice of strings and returns the index
-// as specified by Search.  The return value is the index to insert x if x is not
+// as specified by Search. The return value is the index to insert x if x is not
 // present (it could be len(a)).
 // The slice must be sorted in ascending order.
 //
diff --git a/src/sort/search_test.go b/src/sort/search_test.go
index 29b8d62..ded68eb 100644
--- a/src/sort/search_test.go
+++ b/src/sort/search_test.go
@@ -147,7 +147,7 @@ func BenchmarkSearchWrappers(b *testing.B) {
 }
 
 // Abstract exhaustive test: all sizes up to 100,
-// all possible return values.  If there are any small
+// all possible return values. If there are any small
 // corner cases, this test exercises them.
 func TestSearchExhaustive(t *testing.T) {
 	for size := 0; size <= 100; size++ {
diff --git a/src/sort/sort.go b/src/sort/sort.go
index ee437d3..d07a0c2 100644
--- a/src/sort/sort.go
+++ b/src/sort/sort.go
@@ -7,7 +7,7 @@
 package sort
 
 // A type, typically a collection, that satisfies sort.Interface can be
-// sorted by the routines in this package.  The methods require that the
+// sorted by the routines in this package. The methods require that the
 // elements of the collection be enumerated by an integer index.
 type Interface interface {
 	// Len is the number of elements in the collection.
@@ -19,13 +19,6 @@ type Interface interface {
 	Swap(i, j int)
 }
 
-func min(a, b int) int {
-	if a < b {
-		return a
-	}
-	return b
-}
-
 // Insertion sort
 func insertionSort(data Interface, a, b int) {
 	for i := a + 1; i < b; i++ {
@@ -315,7 +308,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
 
 // Notes on stable sorting:
 // The used algorithms are simple and provable correct on all input and use
-// only logarithmic additional stack space.  They perform well if compared
+// only logarithmic additional stack space. They perform well if compared
 // experimentally to other stable in-place sorting algorithms.
 //
 // Remarks on other algorithms evaluated:
@@ -335,7 +328,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
 //    unstable or rely on enough different elements in each step to encode the
 //    performed block rearrangements. See also "In-Place Merging Algorithms",
 //    Denham Coates-Evely, Department of Computer Science, Kings College,
-//    January 2004 and the reverences in there.
+//    January 2004 and the references in there.
 //  - Often "optimal" algorithms are optimal in the number of assignments
 //    but Interface has only Swap as operation.
 
diff --git a/src/sort/sort_test.go b/src/sort/sort_test.go
index a5da6b2..60fac2d 100644
--- a/src/sort/sort_test.go
+++ b/src/sort/sort_test.go
@@ -506,10 +506,10 @@ func TestStability(t *testing.T) {
 	data.initB()
 	Stable(data)
 	if !IsSorted(data) {
-		t.Errorf("Stable shuffeled sorted %d ints (order)", n)
+		t.Errorf("Stable shuffled sorted %d ints (order)", n)
 	}
 	if !data.inOrder() {
-		t.Errorf("Stable shuffeled sorted %d ints (stability)", n)
+		t.Errorf("Stable shuffled sorted %d ints (stability)", n)
 	}
 
 	// sorted reversed
diff --git a/src/strconv/atob.go b/src/strconv/atob.go
index d0cb097..879ceb3 100644
--- a/src/strconv/atob.go
+++ b/src/strconv/atob.go
@@ -7,7 +7,7 @@ package strconv
 // ParseBool returns the boolean value represented by the string.
 // It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False.
 // Any other value returns an error.
-func ParseBool(str string) (value bool, err error) {
+func ParseBool(str string) (bool, error) {
 	switch str {
 	case "1", "t", "T", "true", "TRUE", "True":
 		return true, nil
diff --git a/src/strconv/atof.go b/src/strconv/atof.go
index 85b959f..ada85e9 100644
--- a/src/strconv/atof.go
+++ b/src/strconv/atof.go
@@ -244,7 +244,9 @@ func readFloat(s string) (mantissa uint64, exp int, neg, trunc, ok bool) {
 		return
 	}
 
-	exp = dp - ndMant
+	if mantissa != 0 {
+		exp = dp - ndMant
+	}
 	ok = true
 	return
 
@@ -528,11 +530,10 @@ func atof64(s string) (f float64, err error) {
 // If s is syntactically well-formed but is more than 1/2 ULP
 // away from the largest floating point number of the given size,
 // ParseFloat returns f = ±Inf, err.Err = ErrRange.
-func ParseFloat(s string, bitSize int) (f float64, err error) {
+func ParseFloat(s string, bitSize int) (float64, error) {
 	if bitSize == 32 {
-		f1, err1 := atof32(s)
-		return float64(f1), err1
+		f, err := atof32(s)
+		return float64(f), err
 	}
-	f1, err1 := atof64(s)
-	return f1, err1
+	return atof64(s)
 }
diff --git a/src/strconv/atof_test.go b/src/strconv/atof_test.go
index ba49332..0a89c3e 100644
--- a/src/strconv/atof_test.go
+++ b/src/strconv/atof_test.go
@@ -42,6 +42,30 @@ var atoftests = []atofTest{
 	{"1e-20", "1e-20", nil},
 	{"625e-3", "0.625", nil},
 
+	// zeros
+	{"0", "0", nil},
+	{"0e0", "0", nil},
+	{"-0e0", "-0", nil},
+	{"+0e0", "0", nil},
+	{"0e-0", "0", nil},
+	{"-0e-0", "-0", nil},
+	{"+0e-0", "0", nil},
+	{"0e+0", "0", nil},
+	{"-0e+0", "-0", nil},
+	{"+0e+0", "0", nil},
+	{"0e+01234567890123456789", "0", nil},
+	{"0.00e-01234567890123456789", "0", nil},
+	{"-0e+01234567890123456789", "-0", nil},
+	{"-0.00e-01234567890123456789", "-0", nil},
+	{"0e291", "0", nil}, // issue 15364
+	{"0e292", "0", nil}, // issue 15364
+	{"0e347", "0", nil}, // issue 15364
+	{"0e348", "0", nil}, // issue 15364
+	{"-0e291", "-0", nil},
+	{"-0e292", "-0", nil},
+	{"-0e347", "-0", nil},
+	{"-0e348", "-0", nil},
+
 	// NaNs
 	{"nan", "NaN", nil},
 	{"NaN", "NaN", nil},
@@ -196,7 +220,7 @@ var (
 
 func init() {
 	// The atof routines return NumErrors wrapping
-	// the error and the string.  Convert the table above.
+	// the error and the string. Convert the table above.
 	for i := range atoftests {
 		test := &atoftests[i]
 		if test.err != nil {
diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go
index 965e3a2..a236de4 100644
--- a/src/strconv/atoi.go
+++ b/src/strconv/atoi.go
@@ -39,7 +39,9 @@ const IntSize = intSize
 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) {
+func ParseUint(s string, base int, bitSize int) (uint64, error) {
+	var n uint64
+	var err error
 	var cutoff, maxVal uint64
 
 	if bitSize == 0 {
@@ -136,16 +138,16 @@ Error:
 }
 
 // ParseInt interprets a string s in the given base (2 to 36) and
-// returns the corresponding value i.  If base == 0, the base is
+// returns the corresponding value i. If base == 0, the base is
 // implied by the string's prefix: base 16 for "0x", base 8 for
 // "0", and base 10 otherwise.
 //
 // The bitSize argument specifies the integer type
-// that the result must fit into.  Bit sizes 0, 8, 16, 32, and 64
+// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
 // correspond to int, int8, int16, int32, and int64.
 //
 // The errors that ParseInt returns have concrete type *NumError
-// and include err.Num = s.  If s is empty or contains invalid
+// and include err.Num = s. If s is empty or contains invalid
 // digits, err.Err = ErrSyntax and the returned value is 0;
 // if the value corresponding to s cannot be represented by a
 // signed integer of the given size, err.Err = ErrRange and the
@@ -195,8 +197,8 @@ func ParseInt(s string, base int, bitSize int) (i int64, err error) {
 	return n, nil
 }
 
-// Atoi is shorthand for ParseInt(s, 10, 0).
-func Atoi(s string) (i int, err error) {
+// Atoi returns the result of ParseInt(s, 10, 0) converted to type int.
+func Atoi(s string) (int, error) {
 	i64, err := ParseInt(s, 10, 0)
 	return int(i64), err
 }
diff --git a/src/strconv/atoi_test.go b/src/strconv/atoi_test.go
index bd6a6a0..d608505 100644
--- a/src/strconv/atoi_test.go
+++ b/src/strconv/atoi_test.go
@@ -196,7 +196,7 @@ var numErrorTests = []numErrorTest{
 
 func init() {
 	// The atoi routines return NumErrors wrapping
-	// the error and the string.  Convert the tables above.
+	// the error and the string. Convert the tables above.
 	for i := range atoui64tests {
 		test := &atoui64tests[i]
 		if test.err != nil {
diff --git a/src/strconv/extfloat.go b/src/strconv/extfloat.go
index 019b4ee..7033e96 100644
--- a/src/strconv/extfloat.go
+++ b/src/strconv/extfloat.go
@@ -311,9 +311,9 @@ func (f *extFloat) AssignDecimal(mantissa uint64, exp10 int, neg bool, trunc boo
 	var extrabits uint
 	if f.exp <= denormalExp {
 		// f.mant * 2^f.exp is smaller than 2^(flt.bias+1).
-		extrabits = uint(63 - flt.mantbits + 1 + uint(denormalExp-f.exp))
+		extrabits = 63 - flt.mantbits + 1 + uint(denormalExp-f.exp)
 	} else {
-		extrabits = uint(63 - flt.mantbits)
+		extrabits = 63 - flt.mantbits
 	}
 
 	halfway := uint64(1) << (extrabits - 1)
diff --git a/src/strconv/fp_test.go b/src/strconv/fp_test.go
index 6de2f8b..39dd9c4 100644
--- a/src/strconv/fp_test.go
+++ b/src/strconv/fp_test.go
@@ -41,7 +41,7 @@ func myatof64(s string) (f float64, ok bool) {
 		}
 		v := float64(n)
 		// We expect that v*pow2(e) fits in a float64,
-		// but pow2(e) by itself may not.  Be careful.
+		// but pow2(e) by itself may not. Be careful.
 		if e <= -1000 {
 			v *= pow2(-1000)
 			e += 1000
diff --git a/src/strconv/ftoa.go b/src/strconv/ftoa.go
index 9ff5d10..8b3d33e 100644
--- a/src/strconv/ftoa.go
+++ b/src/strconv/ftoa.go
@@ -23,7 +23,7 @@ var float32info = floatInfo{23, 8, -127}
 var float64info = floatInfo{52, 11, -1023}
 
 // FormatFloat converts the floating-point number f to a string,
-// according to the format fmt and precision prec.  It rounds the
+// according to the format fmt and precision prec. It rounds the
 // result assuming that the original was obtained from a floating-point
 // value of bitSize bits (32 for float32, 64 for float64).
 //
diff --git a/src/strconv/ftoa_test.go b/src/strconv/ftoa_test.go
index 0b9f0fe..1d25242 100644
--- a/src/strconv/ftoa_test.go
+++ b/src/strconv/ftoa_test.go
@@ -183,59 +183,50 @@ func TestFtoaRandom(t *testing.T) {
 	}
 }
 
-func BenchmarkFormatFloatDecimal(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		FormatFloat(33909, 'g', -1, 64)
-	}
+var ftoaBenches = []struct {
+	name    string
+	float   float64
+	fmt     byte
+	prec    int
+	bitSize int
+}{
+	{"Decimal", 33909, 'g', -1, 64},
+	{"Float", 339.7784, 'g', -1, 64},
+	{"Exp", -5.09e75, 'g', -1, 64},
+	{"NegExp", -5.11e-95, 'g', -1, 64},
+
+	{"Big", 123456789123456789123456789, 'g', -1, 64},
+	{"BinaryExp", -1, 'b', -1, 64},
+
+	{"32Integer", 33909, 'g', -1, 32},
+	{"32ExactFraction", 3.375, 'g', -1, 32},
+	{"32Point", 339.7784, 'g', -1, 32},
+	{"32Exp", -5.09e25, 'g', -1, 32},
+	{"32NegExp", -5.11e-25, 'g', -1, 32},
+
+	{"64Fixed1", 123456, 'e', 3, 64},
+	{"64Fixed2", 123.456, 'e', 3, 64},
+	{"64Fixed3", 1.23456e+78, 'e', 3, 64},
+	{"64Fixed4", 1.23456e-78, 'e', 3, 64},
 }
 
 func BenchmarkFormatFloat(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		FormatFloat(339.7784, 'g', -1, 64)
-	}
-}
-
-func BenchmarkFormatFloatExp(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		FormatFloat(-5.09e75, 'g', -1, 64)
-	}
-}
-
-func BenchmarkFormatFloatNegExp(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		FormatFloat(-5.11e-95, 'g', -1, 64)
-	}
-}
-
-func BenchmarkFormatFloatBig(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		FormatFloat(123456789123456789123456789, 'g', -1, 64)
+	for _, c := range ftoaBenches {
+		b.Run(c.name, func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				FormatFloat(c.float, c.fmt, c.prec, c.bitSize)
+			}
+		})
 	}
 }
 
-func benchmarkAppendFloat(b *testing.B, f float64, fmt byte, prec, bitSize int) {
+func BenchmarkAppendFloat(b *testing.B) {
 	dst := make([]byte, 30)
-	for i := 0; i < b.N; i++ {
-		AppendFloat(dst[:0], f, fmt, prec, bitSize)
+	for _, c := range ftoaBenches {
+		b.Run(c.name, func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				AppendFloat(dst[:0], c.float, c.fmt, c.prec, c.bitSize)
+			}
+		})
 	}
 }
-
-func BenchmarkAppendFloatDecimal(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 64) }
-func BenchmarkAppendFloat(b *testing.B)        { benchmarkAppendFloat(b, 339.7784, 'g', -1, 64) }
-func BenchmarkAppendFloatExp(b *testing.B)     { benchmarkAppendFloat(b, -5.09e75, 'g', -1, 64) }
-func BenchmarkAppendFloatNegExp(b *testing.B)  { benchmarkAppendFloat(b, -5.11e-95, 'g', -1, 64) }
-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) }
-func BenchmarkAppendFloat32Point(b *testing.B)         { benchmarkAppendFloat(b, 339.7784, 'g', -1, 32) }
-func BenchmarkAppendFloat32Exp(b *testing.B)           { benchmarkAppendFloat(b, -5.09e25, 'g', -1, 32) }
-func BenchmarkAppendFloat32NegExp(b *testing.B)        { benchmarkAppendFloat(b, -5.11e-25, 'g', -1, 32) }
-
-func BenchmarkAppendFloat64Fixed1(b *testing.B) { benchmarkAppendFloat(b, 123456, 'e', 3, 64) }
-func BenchmarkAppendFloat64Fixed2(b *testing.B) { benchmarkAppendFloat(b, 123.456, 'e', 3, 64) }
-func BenchmarkAppendFloat64Fixed3(b *testing.B) { benchmarkAppendFloat(b, 1.23456e+78, 'e', 3, 64) }
-func BenchmarkAppendFloat64Fixed4(b *testing.B) { benchmarkAppendFloat(b, 1.23456e-78, 'e', 3, 64) }
diff --git a/src/strconv/isprint.go b/src/strconv/isprint.go
index 20a02de..a30d8d8 100644
--- a/src/strconv/isprint.go
+++ b/src/strconv/isprint.go
@@ -7,7 +7,7 @@
 
 package strconv
 
-// (470+136+73)*2 + (342)*4 = 2726 bytes
+// (462+139+82)*2 + (378)*4 = 2878 bytes
 
 var isPrint16 = []uint16{
 	0x0020, 0x007e,
@@ -26,8 +26,8 @@ var isPrint16 = []uint16{
 	0x0800, 0x082d,
 	0x0830, 0x085b,
 	0x085e, 0x085e,
-	0x08a0, 0x08b4,
-	0x08e3, 0x098c,
+	0x08a0, 0x08bd,
+	0x08d4, 0x098c,
 	0x098f, 0x0990,
 	0x0993, 0x09b2,
 	0x09b6, 0x09b9,
@@ -83,11 +83,9 @@ var isPrint16 = []uint16{
 	0x0cde, 0x0ce3,
 	0x0ce6, 0x0cf2,
 	0x0d01, 0x0d3a,
-	0x0d3d, 0x0d4e,
-	0x0d57, 0x0d57,
-	0x0d5f, 0x0d63,
-	0x0d66, 0x0d75,
-	0x0d79, 0x0d7f,
+	0x0d3d, 0x0d4f,
+	0x0d54, 0x0d63,
+	0x0d66, 0x0d7f,
 	0x0d82, 0x0d96,
 	0x0d9a, 0x0dbd,
 	0x0dc0, 0x0dc6,
@@ -153,11 +151,11 @@ var isPrint16 = []uint16{
 	0x1b80, 0x1bf3,
 	0x1bfc, 0x1c37,
 	0x1c3b, 0x1c49,
-	0x1c4d, 0x1c7f,
+	0x1c4d, 0x1c88,
 	0x1cc0, 0x1cc7,
 	0x1cd0, 0x1cf9,
 	0x1d00, 0x1df5,
-	0x1dfc, 0x1f15,
+	0x1dfb, 0x1f15,
 	0x1f18, 0x1f1d,
 	0x1f20, 0x1f45,
 	0x1f48, 0x1f4d,
@@ -172,8 +170,7 @@ var isPrint16 = []uint16{
 	0x20a0, 0x20be,
 	0x20d0, 0x20f0,
 	0x2100, 0x218b,
-	0x2190, 0x23fa,
-	0x2400, 0x2426,
+	0x2190, 0x2426,
 	0x2440, 0x244a,
 	0x2460, 0x2b73,
 	0x2b76, 0x2b95,
@@ -186,7 +183,7 @@ var isPrint16 = []uint16{
 	0x2d30, 0x2d67,
 	0x2d6f, 0x2d70,
 	0x2d7f, 0x2d96,
-	0x2da0, 0x2e42,
+	0x2da0, 0x2e44,
 	0x2e80, 0x2ef3,
 	0x2f00, 0x2fd5,
 	0x2ff0, 0x2ffb,
@@ -201,12 +198,11 @@ var isPrint16 = []uint16{
 	0xa490, 0xa4c6,
 	0xa4d0, 0xa62b,
 	0xa640, 0xa6f7,
-	0xa700, 0xa7ad,
-	0xa7b0, 0xa7b7,
+	0xa700, 0xa7b7,
 	0xa7f7, 0xa82b,
 	0xa830, 0xa839,
 	0xa840, 0xa877,
-	0xa880, 0xa8c4,
+	0xa880, 0xa8c5,
 	0xa8ce, 0xa8d9,
 	0xa8e0, 0xa8fd,
 	0xa900, 0xa953,
@@ -258,6 +254,8 @@ var isNotPrint16 = []uint16{
 	0x0590,
 	0x06dd,
 	0x083f,
+	0x08b5,
+	0x08e2,
 	0x0984,
 	0x09a9,
 	0x09b1,
@@ -294,7 +292,6 @@ var isNotPrint16 = []uint16{
 	0x0c45,
 	0x0c49,
 	0x0c57,
-	0x0c80,
 	0x0c84,
 	0x0c8d,
 	0x0c91,
@@ -354,6 +351,7 @@ var isNotPrint16 = []uint16{
 	0x1fdc,
 	0x1ff5,
 	0x208f,
+	0x23ff,
 	0x2bc9,
 	0x2c2f,
 	0x2c5f,
@@ -371,6 +369,7 @@ var isNotPrint16 = []uint16{
 	0x318f,
 	0x321f,
 	0x32ff,
+	0xa7af,
 	0xa9ce,
 	0xa9ff,
 	0xab27,
@@ -392,8 +391,7 @@ var isPrint32 = []uint32{
 	0x010080, 0x0100fa,
 	0x010100, 0x010102,
 	0x010107, 0x010133,
-	0x010137, 0x01018c,
-	0x010190, 0x01019b,
+	0x010137, 0x01019b,
 	0x0101a0, 0x0101a0,
 	0x0101d0, 0x0101fd,
 	0x010280, 0x01029c,
@@ -406,6 +404,8 @@ var isPrint32 = []uint32{
 	0x0103c8, 0x0103d5,
 	0x010400, 0x01049d,
 	0x0104a0, 0x0104a9,
+	0x0104b0, 0x0104d3,
+	0x0104d8, 0x0104fb,
 	0x010500, 0x010527,
 	0x010530, 0x010563,
 	0x01056f, 0x01056f,
@@ -451,7 +451,7 @@ var isPrint32 = []uint32{
 	0x011150, 0x011176,
 	0x011180, 0x0111cd,
 	0x0111d0, 0x0111f4,
-	0x011200, 0x01123d,
+	0x011200, 0x01123e,
 	0x011280, 0x0112a9,
 	0x0112b0, 0x0112ea,
 	0x0112f0, 0x0112f9,
@@ -466,12 +466,14 @@ var isPrint32 = []uint32{
 	0x01135d, 0x011363,
 	0x011366, 0x01136c,
 	0x011370, 0x011374,
+	0x011400, 0x01145d,
 	0x011480, 0x0114c7,
 	0x0114d0, 0x0114d9,
 	0x011580, 0x0115b5,
 	0x0115b8, 0x0115dd,
 	0x011600, 0x011644,
 	0x011650, 0x011659,
+	0x011660, 0x01166c,
 	0x011680, 0x0116b7,
 	0x0116c0, 0x0116c9,
 	0x011700, 0x011719,
@@ -480,6 +482,10 @@ var isPrint32 = []uint32{
 	0x0118a0, 0x0118f2,
 	0x0118ff, 0x0118ff,
 	0x011ac0, 0x011af8,
+	0x011c00, 0x011c45,
+	0x011c50, 0x011c6c,
+	0x011c70, 0x011c8f,
+	0x011c92, 0x011cb6,
 	0x012000, 0x012399,
 	0x012400, 0x012474,
 	0x012480, 0x012543,
@@ -496,6 +502,9 @@ var isPrint32 = []uint32{
 	0x016f00, 0x016f44,
 	0x016f50, 0x016f7e,
 	0x016f8f, 0x016f9f,
+	0x016fe0, 0x016fe0,
+	0x017000, 0x0187ec,
+	0x018800, 0x018af2,
 	0x01b000, 0x01b001,
 	0x01bc00, 0x01bc6a,
 	0x01bc70, 0x01bc7c,
@@ -518,8 +527,13 @@ var isPrint32 = []uint32{
 	0x01d6a8, 0x01d7cb,
 	0x01d7ce, 0x01da8b,
 	0x01da9b, 0x01daaf,
+	0x01e000, 0x01e018,
+	0x01e01b, 0x01e02a,
 	0x01e800, 0x01e8c4,
 	0x01e8c7, 0x01e8d6,
+	0x01e900, 0x01e94a,
+	0x01e950, 0x01e959,
+	0x01e95e, 0x01e95f,
 	0x01ee00, 0x01ee24,
 	0x01ee27, 0x01ee3b,
 	0x01ee42, 0x01ee42,
@@ -534,14 +548,14 @@ var isPrint32 = []uint32{
 	0x01f0b1, 0x01f0f5,
 	0x01f100, 0x01f10c,
 	0x01f110, 0x01f16b,
-	0x01f170, 0x01f19a,
+	0x01f170, 0x01f1ac,
 	0x01f1e6, 0x01f202,
-	0x01f210, 0x01f23a,
+	0x01f210, 0x01f23b,
 	0x01f240, 0x01f248,
 	0x01f250, 0x01f251,
-	0x01f300, 0x01f6d0,
+	0x01f300, 0x01f6d2,
 	0x01f6e0, 0x01f6ec,
-	0x01f6f0, 0x01f6f3,
+	0x01f6f0, 0x01f6f6,
 	0x01f700, 0x01f773,
 	0x01f780, 0x01f7d4,
 	0x01f800, 0x01f80b,
@@ -549,8 +563,11 @@ var isPrint32 = []uint32{
 	0x01f850, 0x01f859,
 	0x01f860, 0x01f887,
 	0x01f890, 0x01f8ad,
-	0x01f910, 0x01f918,
-	0x01f980, 0x01f984,
+	0x01f910, 0x01f927,
+	0x01f930, 0x01f930,
+	0x01f933, 0x01f94b,
+	0x01f950, 0x01f95e,
+	0x01f980, 0x01f991,
 	0x01f9c0, 0x01f9c0,
 	0x020000, 0x02a6d6,
 	0x02a700, 0x02b734,
@@ -565,6 +582,7 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0x0027,
 	0x003b,
 	0x003e,
+	0x018f,
 	0x039e,
 	0x0809,
 	0x0836,
@@ -585,6 +603,11 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0x1329,
 	0x1331,
 	0x1334,
+	0x145a,
+	0x145c,
+	0x1c09,
+	0x1c37,
+	0x1ca8,
 	0x246f,
 	0x6a5f,
 	0x6b5a,
@@ -603,6 +626,9 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0xd545,
 	0xd551,
 	0xdaa0,
+	0xe007,
+	0xe022,
+	0xe025,
 	0xee04,
 	0xee20,
 	0xee23,
@@ -632,8 +658,8 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0xf0c0,
 	0xf0d0,
 	0xf12f,
-	0xf57a,
-	0xf5a4,
+	0xf91f,
+	0xf93f,
 }
 
 // isGraphic lists the graphic runes not matched by IsPrint.
diff --git a/src/strconv/makeisprint.go b/src/strconv/makeisprint.go
index 5142580..0a3e5b2 100644
--- a/src/strconv/makeisprint.go
+++ b/src/strconv/makeisprint.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/strconv/quote.go b/src/strconv/quote.go
index 40d0667..becfe1d 100644
--- a/src/strconv/quote.go
+++ b/src/strconv/quote.go
@@ -6,15 +6,19 @@
 
 package strconv
 
-import (
-	"unicode/utf8"
-)
+import "unicode/utf8"
 
 const lowerhex = "0123456789abcdef"
 
 func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
-	var runeTmp [utf8.UTFMax]byte
-	buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
+	return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly))
+}
+
+func quoteRuneWith(r rune, quote byte, ASCIIonly, graphicOnly bool) string {
+	return string(appendQuotedRuneWith(nil, r, quote, ASCIIonly, graphicOnly))
+}
+
+func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly bool) []byte {
 	buf = append(buf, quote)
 	for width := 0; len(s) > 0; s = s[width:] {
 		r := rune(s[0])
@@ -28,64 +32,79 @@ func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
 			buf = append(buf, lowerhex[s[0]&0xF])
 			continue
 		}
-		if r == rune(quote) || r == '\\' { // always backslashed
-			buf = append(buf, '\\')
+		buf = appendEscapedRune(buf, r, width, quote, ASCIIonly, graphicOnly)
+	}
+	buf = append(buf, quote)
+	return buf
+}
+
+func appendQuotedRuneWith(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte {
+	buf = append(buf, quote)
+	if !utf8.ValidRune(r) {
+		r = utf8.RuneError
+	}
+	buf = appendEscapedRune(buf, r, utf8.RuneLen(r), quote, ASCIIonly, graphicOnly)
+	buf = append(buf, quote)
+	return buf
+}
+
+func appendEscapedRune(buf []byte, r rune, width int, quote byte, ASCIIonly, graphicOnly bool) []byte {
+	var runeTmp [utf8.UTFMax]byte
+	if r == rune(quote) || r == '\\' { // always backslashed
+		buf = append(buf, '\\')
+		buf = append(buf, byte(r))
+		return buf
+	}
+	if ASCIIonly {
+		if r < utf8.RuneSelf && IsPrint(r) {
 			buf = append(buf, byte(r))
-			continue
+			return buf
 		}
-		if ASCIIonly {
-			if r < utf8.RuneSelf && IsPrint(r) {
-				buf = append(buf, byte(r))
-				continue
+	} else if IsPrint(r) || graphicOnly && isInGraphicList(r) {
+		n := utf8.EncodeRune(runeTmp[:], r)
+		buf = append(buf, runeTmp[:n]...)
+		return buf
+	}
+	switch r {
+	case '\a':
+		buf = append(buf, `\a`...)
+	case '\b':
+		buf = append(buf, `\b`...)
+	case '\f':
+		buf = append(buf, `\f`...)
+	case '\n':
+		buf = append(buf, `\n`...)
+	case '\r':
+		buf = append(buf, `\r`...)
+	case '\t':
+		buf = append(buf, `\t`...)
+	case '\v':
+		buf = append(buf, `\v`...)
+	default:
+		switch {
+		case r < ' ':
+			buf = append(buf, `\x`...)
+			buf = append(buf, lowerhex[byte(r)>>4])
+			buf = append(buf, lowerhex[byte(r)&0xF])
+		case r > utf8.MaxRune:
+			r = 0xFFFD
+			fallthrough
+		case r < 0x10000:
+			buf = append(buf, `\u`...)
+			for s := 12; s >= 0; s -= 4 {
+				buf = append(buf, lowerhex[r>>uint(s)&0xF])
 			}
-		} else if IsPrint(r) || graphicOnly && isInGraphicList(r) {
-			n := utf8.EncodeRune(runeTmp[:], r)
-			buf = append(buf, runeTmp[:n]...)
-			continue
-		}
-		switch r {
-		case '\a':
-			buf = append(buf, `\a`...)
-		case '\b':
-			buf = append(buf, `\b`...)
-		case '\f':
-			buf = append(buf, `\f`...)
-		case '\n':
-			buf = append(buf, `\n`...)
-		case '\r':
-			buf = append(buf, `\r`...)
-		case '\t':
-			buf = append(buf, `\t`...)
-		case '\v':
-			buf = append(buf, `\v`...)
 		default:
-			switch {
-			case r < ' ':
-				buf = append(buf, `\x`...)
-				buf = append(buf, lowerhex[s[0]>>4])
-				buf = append(buf, lowerhex[s[0]&0xF])
-			case r > utf8.MaxRune:
-				r = 0xFFFD
-				fallthrough
-			case r < 0x10000:
-				buf = append(buf, `\u`...)
-				for s := 12; s >= 0; s -= 4 {
-					buf = append(buf, lowerhex[r>>uint(s)&0xF])
-				}
-			default:
-				buf = append(buf, `\U`...)
-				for s := 28; s >= 0; s -= 4 {
-					buf = append(buf, lowerhex[r>>uint(s)&0xF])
-				}
+			buf = append(buf, `\U`...)
+			for s := 28; s >= 0; s -= 4 {
+				buf = append(buf, lowerhex[r>>uint(s)&0xF])
 			}
 		}
 	}
-	buf = append(buf, quote)
-	return string(buf)
-
+	return buf
 }
 
-// Quote returns a double-quoted Go string literal representing s.  The
+// Quote returns a double-quoted Go string literal representing s. The
 // returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for
 // control characters and non-printable characters as defined by
 // IsPrint.
@@ -96,7 +115,7 @@ func Quote(s string) string {
 // AppendQuote appends a double-quoted Go string literal representing s,
 // as generated by Quote, to dst and returns the extended buffer.
 func AppendQuote(dst []byte, s string) []byte {
-	return append(dst, Quote(s)...)
+	return appendQuotedWith(dst, s, '"', false, false)
 }
 
 // QuoteToASCII returns a double-quoted Go string literal representing s.
@@ -109,7 +128,7 @@ func QuoteToASCII(s string) string {
 // AppendQuoteToASCII appends a double-quoted Go string literal representing s,
 // as generated by QuoteToASCII, to dst and returns the extended buffer.
 func AppendQuoteToASCII(dst []byte, s string) []byte {
-	return append(dst, QuoteToASCII(s)...)
+	return appendQuotedWith(dst, s, '"', true, false)
 }
 
 // QuoteToGraphic returns a double-quoted Go string literal representing s.
@@ -122,21 +141,20 @@ func QuoteToGraphic(s string) string {
 // AppendQuoteToGraphic appends a double-quoted Go string literal representing s,
 // as generated by QuoteToGraphic, to dst and returns the extended buffer.
 func AppendQuoteToGraphic(dst []byte, s string) []byte {
-	return append(dst, QuoteToGraphic(s)...)
+	return appendQuotedWith(dst, s, '"', false, true)
 }
 
 // QuoteRune returns a single-quoted Go character literal representing the
 // rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100)
 // for control characters and non-printable characters as defined by IsPrint.
 func QuoteRune(r rune) string {
-	// TODO: avoid the allocation here.
-	return quoteWith(string(r), '\'', false, false)
+	return quoteRuneWith(r, '\'', false, false)
 }
 
 // AppendQuoteRune appends a single-quoted Go character literal representing the rune,
 // as generated by QuoteRune, to dst and returns the extended buffer.
 func AppendQuoteRune(dst []byte, r rune) []byte {
-	return append(dst, QuoteRune(r)...)
+	return appendQuotedRuneWith(dst, r, '\'', false, false)
 }
 
 // QuoteRuneToASCII returns a single-quoted Go character literal representing
@@ -144,14 +162,13 @@ func AppendQuoteRune(dst []byte, r rune) []byte {
 // \u0100) for non-ASCII characters and non-printable characters as defined
 // by IsPrint.
 func QuoteRuneToASCII(r rune) string {
-	// TODO: avoid the allocation here.
-	return quoteWith(string(r), '\'', true, false)
+	return quoteRuneWith(r, '\'', true, false)
 }
 
 // AppendQuoteRuneToASCII appends a single-quoted Go character literal representing the rune,
 // as generated by QuoteRuneToASCII, to dst and returns the extended buffer.
 func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
-	return append(dst, QuoteRuneToASCII(r)...)
+	return appendQuotedRuneWith(dst, r, '\'', true, false)
 }
 
 // QuoteRuneToGraphic returns a single-quoted Go character literal representing
@@ -159,14 +176,13 @@ func AppendQuoteRuneToASCII(dst []byte, r rune) []byte {
 // \u0100) for non-ASCII characters and non-printable characters as defined
 // by IsGraphic.
 func QuoteRuneToGraphic(r rune) string {
-	// TODO: avoid the allocation here.
-	return quoteWith(string(r), '\'', false, true)
+	return quoteRuneWith(r, '\'', false, true)
 }
 
 // AppendQuoteRuneToGraphic appends a single-quoted Go character literal representing the rune,
 // as generated by QuoteRuneToGraphic, to dst and returns the extended buffer.
 func AppendQuoteRuneToGraphic(dst []byte, r rune) []byte {
-	return append(dst, QuoteRuneToGraphic(r)...)
+	return appendQuotedRuneWith(dst, r, '\'', false, true)
 }
 
 // CanBackquote reports whether the string s can be represented
@@ -331,7 +347,7 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string,
 // that s quotes.  (If s is single-quoted, it would be a Go
 // character literal; Unquote returns the corresponding
 // one-character string.)
-func Unquote(s string) (t string, err error) {
+func Unquote(s string) (string, error) {
 	n := len(s)
 	if n < 2 {
 		return "", ErrSyntax
diff --git a/src/strconv/quote_test.go b/src/strconv/quote_test.go
index 3e8ec2c..10735e3 100644
--- a/src/strconv/quote_test.go
+++ b/src/strconv/quote_test.go
@@ -89,6 +89,34 @@ func TestQuoteToGraphic(t *testing.T) {
 	}
 }
 
+func BenchmarkQuote(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		Quote("\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
+	}
+}
+
+func BenchmarkQuoteRune(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		QuoteRune('\a')
+	}
+}
+
+var benchQuoteBuf []byte
+
+func BenchmarkAppendQuote(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		benchQuoteBuf = AppendQuote(benchQuoteBuf[:0], "\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
+	}
+}
+
+var benchQuoteRuneBuf []byte
+
+func BenchmarkAppendQuoteRune(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		benchQuoteRuneBuf = AppendQuoteRune(benchQuoteRuneBuf[:0], '\a')
+	}
+}
+
 type quoteRuneTest struct {
 	in      rune
 	out     string
diff --git a/src/strings/compare.go b/src/strings/compare.go
index b84ddde..1fe6b8d 100644
--- a/src/strings/compare.go
+++ b/src/strings/compare.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/strings/compare_test.go b/src/strings/compare_test.go
index 68fc88e..bc12e42 100644
--- a/src/strings/compare_test.go
+++ b/src/strings/compare_test.go
@@ -56,7 +56,7 @@ func TestCompareStrings(t *testing.T) {
 	a := make([]byte, n+1)
 	b := make([]byte, n+1)
 	for len := 0; len < 128; len++ {
-		// randomish but deterministic data.  No 0 or 255.
+		// 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)
diff --git a/src/strings/reader.go b/src/strings/reader.go
index 7a872fb..6c1a506 100644
--- a/src/strings/reader.go
+++ b/src/strings/reader.go
@@ -35,9 +35,6 @@ func (r *Reader) Len() int {
 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
-	}
 	if r.i >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
@@ -62,14 +59,14 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
 	return
 }
 
-func (r *Reader) ReadByte() (b byte, err error) {
+func (r *Reader) ReadByte() (byte, error) {
 	r.prevRune = -1
 	if r.i >= int64(len(r.s)) {
 		return 0, io.EOF
 	}
-	b = r.s[r.i]
+	b := r.s[r.i]
 	r.i++
-	return
+	return b, nil
 }
 
 func (r *Reader) UnreadByte() error {
@@ -110,11 +107,11 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
 	r.prevRune = -1
 	var abs int64
 	switch whence {
-	case 0:
+	case io.SeekStart:
 		abs = offset
-	case 1:
-		abs = int64(r.i) + offset
-	case 2:
+	case io.SeekCurrent:
+		abs = r.i + offset
+	case io.SeekEnd:
 		abs = int64(len(r.s)) + offset
 	default:
 		return 0, errors.New("strings.Reader.Seek: invalid whence")
@@ -145,6 +142,9 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
 	return
 }
 
+// Reset resets the Reader to be reading from s.
+func (r *Reader) Reset(s string) { *r = Reader{s, 0, -1} }
+
 // NewReader returns a new Reader reading from s.
 // It is similar to bytes.NewBufferString but more efficient and read-only.
 func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
diff --git a/src/strings/reader_test.go b/src/strings/reader_test.go
index 5003a37..bf40eb1 100644
--- a/src/strings/reader_test.go
+++ b/src/strings/reader_test.go
@@ -9,7 +9,6 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
-	"os"
 	"strings"
 	"sync"
 	"testing"
@@ -23,17 +22,18 @@ func TestReader(t *testing.T) {
 		n       int
 		want    string
 		wantpos int64
+		readerr error
 		seekerr string
 	}{
-		{seek: os.SEEK_SET, off: 0, n: 20, want: "0123456789"},
-		{seek: os.SEEK_SET, off: 1, n: 1, want: "1"},
-		{seek: os.SEEK_CUR, off: 1, wantpos: 3, n: 2, want: "34"},
-		{seek: os.SEEK_SET, off: -1, seekerr: "strings.Reader.Seek: negative position"},
-		{seek: os.SEEK_SET, off: 1 << 33, wantpos: 1 << 33},
-		{seek: os.SEEK_CUR, off: 1, wantpos: 1<<33 + 1},
-		{seek: os.SEEK_SET, n: 5, want: "01234"},
-		{seek: os.SEEK_CUR, n: 5, want: "56789"},
-		{seek: os.SEEK_END, off: -1, n: 1, wantpos: 9, want: "9"},
+		{seek: io.SeekStart, off: 0, n: 20, want: "0123456789"},
+		{seek: io.SeekStart, off: 1, n: 1, want: "1"},
+		{seek: io.SeekCurrent, off: 1, wantpos: 3, n: 2, want: "34"},
+		{seek: io.SeekStart, off: -1, seekerr: "strings.Reader.Seek: negative position"},
+		{seek: io.SeekStart, off: 1 << 33, wantpos: 1 << 33, readerr: io.EOF},
+		{seek: io.SeekCurrent, off: 1, wantpos: 1<<33 + 1, readerr: io.EOF},
+		{seek: io.SeekStart, n: 5, want: "01234"},
+		{seek: io.SeekCurrent, n: 5, want: "56789"},
+		{seek: io.SeekEnd, off: -1, n: 1, wantpos: 9, want: "9"},
 	}
 
 	for i, tt := range tests {
@@ -51,8 +51,8 @@ func TestReader(t *testing.T) {
 		}
 		buf := make([]byte, tt.n)
 		n, err := r.Read(buf)
-		if err != nil {
-			t.Errorf("%d. read = %v", i, err)
+		if err != tt.readerr {
+			t.Errorf("%d. read = %v; want %v", i, err, tt.readerr)
 			continue
 		}
 		got := string(buf[:n])
@@ -64,7 +64,7 @@ func TestReader(t *testing.T) {
 
 func TestReadAfterBigSeek(t *testing.T) {
 	r := strings.NewReader("0123456789")
-	if _, err := r.Seek(1<<31+5, os.SEEK_SET); err != nil {
+	if _, err := r.Seek(1<<31+5, io.SeekStart); err != nil {
 		t.Fatal(err)
 	}
 	if n, err := r.Read(make([]byte, 10)); n != 0 || err != io.EOF {
@@ -170,3 +170,23 @@ func TestReaderLenSize(t *testing.T) {
 		t.Errorf("Size = %d; want 3", r.Size())
 	}
 }
+
+func TestReaderReset(t *testing.T) {
+	r := strings.NewReader("世界")
+	if _, _, err := r.ReadRune(); err != nil {
+		t.Errorf("ReadRune: unexpected error: %v", err)
+	}
+
+	const want = "abcdef"
+	r.Reset(want)
+	if err := r.UnreadRune(); err == nil {
+		t.Errorf("UnreadRune: expected error, got nil")
+	}
+	buf, err := ioutil.ReadAll(r)
+	if err != nil {
+		t.Errorf("ReadAll: unexpected error: %v", err)
+	}
+	if got := string(buf); got != want {
+		t.Errorf("ReadAll: got %q, want %q", got, want)
+	}
+}
diff --git a/src/strings/strings.go b/src/strings/strings.go
index 37d5647..919e8c8 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -12,32 +12,25 @@ import (
 	"unicode/utf8"
 )
 
-// explode splits s into an array of UTF-8 sequences, one per Unicode character (still strings) up to a maximum of n (n < 0 means no limit).
-// Invalid UTF-8 sequences become correct encodings of U+FFF8.
+// explode splits s into a slice of UTF-8 strings,
+// one string per Unicode character up to a maximum of n (n < 0 means no limit).
+// Invalid UTF-8 sequences become correct encodings of U+FFFD.
 func explode(s string, n int) []string {
-	if n == 0 {
-		return nil
-	}
 	l := utf8.RuneCountInString(s)
-	if n <= 0 || n > l {
+	if n < 0 || n > l {
 		n = l
 	}
 	a := make([]string, n)
-	var size int
-	var ch rune
-	i, cur := 0, 0
-	for ; i+1 < n; i++ {
-		ch, size = utf8.DecodeRuneInString(s[cur:])
+	for i := 0; i < n-1; i++ {
+		ch, size := utf8.DecodeRuneInString(s)
+		a[i] = s[:size]
+		s = s[size:]
 		if ch == utf8.RuneError {
 			a[i] = string(utf8.RuneError)
-		} else {
-			a[i] = s[cur : cur+size]
 		}
-		cur += size
 	}
-	// add the rest, if there is any
-	if cur < len(s) {
-		a[i] = s[cur:]
+	if n > 0 {
+		a[n-1] = s
 	}
 	return a
 }
@@ -346,7 +339,7 @@ func FieldsFunc(s string, f func(rune) bool) []string {
 	return a
 }
 
-// Join concatenates the elements of a to create a single string.   The separator string
+// Join concatenates the elements of a to create a single string. The separator string
 // sep is placed between elements in the resulting string.
 func Join(a []string, sep string) string {
 	if len(a) == 0 {
@@ -384,8 +377,8 @@ func HasSuffix(s, suffix string) bool {
 // dropped from the string with no replacement.
 func Map(mapping func(rune) rune, s string) string {
 	// In the worst case, the string can grow when mapped, making
-	// things unpleasant.  But it's so rare we barge in assuming it's
-	// fine.  It could also shrink but that falls out naturally.
+	// things unpleasant. But it's so rare we barge in assuming it's
+	// fine. It could also shrink but that falls out naturally.
 	maxbytes := len(s) // length of b
 	nbytes := 0        // number of bytes encoded in b
 	// The output buffer b is initialized on demand, the first
@@ -714,7 +707,7 @@ func EqualFold(s, t string) bool {
 			return false
 		}
 
-		// General case.  SimpleFold(x) returns the next equivalent rune > x
+		// General case. SimpleFold(x) returns the next equivalent rune > x
 		// or wraps around to smaller values.
 		r := unicode.SimpleFold(sr)
 		for r != sr && r < tr {
@@ -726,6 +719,6 @@ func EqualFold(s, t string) bool {
 		return false
 	}
 
-	// One string is empty.  Are both?
+	// One string is empty. Are both?
 	return s == t
 }
diff --git a/src/strings/strings_amd64.go b/src/strings/strings_amd64.go
index 376113f..55bf2d2 100644
--- a/src/strings/strings_amd64.go
+++ b/src/strings/strings_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/strings/strings_decl.go b/src/strings/strings_decl.go
index 810a696..3bae844 100644
--- a/src/strings/strings_decl.go
+++ b/src/strings/strings_decl.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/strings/strings_generic.go b/src/strings/strings_generic.go
index 811cb80..d356f50 100644
--- a/src/strings/strings_generic.go
+++ b/src/strings/strings_generic.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go
index 49f55fe..fcef761 100644
--- a/src/strings/strings_test.go
+++ b/src/strings/strings_test.go
@@ -190,6 +190,43 @@ func TestLastIndexByte(t *testing.T) {
 	}
 }
 
+func simpleIndex(s, sep string) int {
+	n := len(sep)
+	for i := n; i <= len(s); i++ {
+		if s[i-n:i] == sep {
+			return i - n
+		}
+	}
+	return -1
+}
+
+func TestIndexRandom(t *testing.T) {
+	const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
+	for times := 0; times < 10; times++ {
+		for strLen := 5 + rand.Intn(5); strLen < 140; strLen += 10 { // Arbitrary
+			s1 := make([]byte, strLen)
+			for i := range s1 {
+				s1[i] = chars[rand.Intn(len(chars))]
+			}
+			s := string(s1)
+			for i := 0; i < 50; i++ {
+				begin := rand.Intn(len(s) + 1)
+				end := begin + rand.Intn(len(s)+1-begin)
+				sep := s[begin:end]
+				if i%4 == 0 {
+					pos := rand.Intn(len(sep) + 1)
+					sep = sep[:pos] + "A" + sep[pos:]
+				}
+				want := simpleIndex(s, sep)
+				res := Index(s, sep)
+				if res != want {
+					t.Errorf("Index(%s,%s) = %d; want %d", s, sep, res, want)
+				}
+			}
+		}
+	}
+}
+
 var indexRuneTests = []struct {
 	s    string
 	rune rune
@@ -256,31 +293,6 @@ func BenchmarkIndexByte(b *testing.B) {
 	}
 }
 
-var explodetests = []struct {
-	s string
-	n int
-	a []string
-}{
-	{"", -1, []string{}},
-	{abcd, 4, []string{"a", "b", "c", "d"}},
-	{faces, 3, []string{"☺", "☻", "☹"}},
-	{abcd, 2, []string{"a", "bcd"}},
-}
-
-func TestExplode(t *testing.T) {
-	for _, tt := range explodetests {
-		a := SplitN(tt.s, "", tt.n)
-		if !eq(a, tt.a) {
-			t.Errorf("explode(%q, %d) = %v; want %v", tt.s, tt.n, a, tt.a)
-			continue
-		}
-		s := Join(a, "")
-		if s != tt.s {
-			t.Errorf(`Join(explode(%q, %d), "") = %q`, tt.s, tt.n, s)
-		}
-	}
-}
-
 type SplitTest struct {
 	s   string
 	sep string
@@ -289,19 +301,23 @@ type SplitTest struct {
 }
 
 var splittests = []SplitTest{
+	{"", "", -1, []string{}},
+	{abcd, "", 2, []string{"a", "bcd"}},
+	{abcd, "", 4, []string{"a", "b", "c", "d"}},
+	{abcd, "", -1, []string{"a", "b", "c", "d"}},
+	{faces, "", -1, []string{"☺", "☻", "☹"}},
+	{faces, "", 3, []string{"☺", "☻", "☹"}},
+	{faces, "", 17, []string{"☺", "☻", "☹"}},
+	{"☺�☹", "", -1, []string{"☺", "�", "☹"}},
 	{abcd, "a", 0, nil},
 	{abcd, "a", -1, []string{"", "bcd"}},
 	{abcd, "z", -1, []string{"abcd"}},
-	{abcd, "", -1, []string{"a", "b", "c", "d"}},
 	{commas, ",", -1, []string{"1", "2", "3", "4"}},
 	{dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
 	{faces, "☹", -1, []string{"☺☻", ""}},
 	{faces, "~", -1, []string{faces}},
-	{faces, "", -1, []string{"☺", "☻", "☹"}},
 	{"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
 	{"1 2", " ", 3, []string{"1", "2"}},
-	{"123", "", 2, []string{"1", "23"}},
-	{"123", "", 17, []string{"1", "2", "3"}},
 }
 
 func TestSplit(t *testing.T) {
@@ -492,7 +508,7 @@ func rot13(r rune) rune {
 func TestMap(t *testing.T) {
 	// Run a couple of awful growth/shrinkage tests
 	a := tenRunes('a')
-	// 1.  Grow.  This triggers two reallocations in Map.
+	// 1.  Grow. This triggers two reallocations in Map.
 	maxRune := func(rune) rune { return unicode.MaxRune }
 	m := Map(maxRune, a)
 	expect := tenRunes(unicode.MaxRune)
@@ -973,7 +989,7 @@ var UnreadRuneErrorTests = []struct {
 	{"Read", func(r *Reader) { r.Read([]byte{0}) }},
 	{"ReadByte", func(r *Reader) { r.ReadByte() }},
 	{"UnreadRune", func(r *Reader) { r.UnreadRune() }},
-	{"Seek", func(r *Reader) { r.Seek(0, 1) }},
+	{"Seek", func(r *Reader) { r.Seek(0, io.SeekCurrent) }},
 	{"WriteTo", func(r *Reader) { r.WriteTo(&bytes.Buffer{}) }},
 }
 
@@ -1057,6 +1073,70 @@ var ContainsTests = []struct {
 	{"abc", "bcd", false},
 	{"abc", "", true},
 	{"", "a", false},
+
+	// cases to cover code in runtime/asm_amd64.s:indexShortStr
+	// 2-byte needle
+	{"xxxxxx", "01", false},
+	{"01xxxx", "01", true},
+	{"xx01xx", "01", true},
+	{"xxxx01", "01", true},
+	{"01xxxxx"[1:], "01", false},
+	{"xxxxx01"[:6], "01", false},
+	// 3-byte needle
+	{"xxxxxxx", "012", false},
+	{"012xxxx", "012", true},
+	{"xx012xx", "012", true},
+	{"xxxx012", "012", true},
+	{"012xxxxx"[1:], "012", false},
+	{"xxxxx012"[:7], "012", false},
+	// 4-byte needle
+	{"xxxxxxxx", "0123", false},
+	{"0123xxxx", "0123", true},
+	{"xx0123xx", "0123", true},
+	{"xxxx0123", "0123", true},
+	{"0123xxxxx"[1:], "0123", false},
+	{"xxxxx0123"[:8], "0123", false},
+	// 5-7-byte needle
+	{"xxxxxxxxx", "01234", false},
+	{"01234xxxx", "01234", true},
+	{"xx01234xx", "01234", true},
+	{"xxxx01234", "01234", true},
+	{"01234xxxxx"[1:], "01234", false},
+	{"xxxxx01234"[:9], "01234", false},
+	// 8-byte needle
+	{"xxxxxxxxxxxx", "01234567", false},
+	{"01234567xxxx", "01234567", true},
+	{"xx01234567xx", "01234567", true},
+	{"xxxx01234567", "01234567", true},
+	{"01234567xxxxx"[1:], "01234567", false},
+	{"xxxxx01234567"[:12], "01234567", false},
+	// 9-15-byte needle
+	{"xxxxxxxxxxxxx", "012345678", false},
+	{"012345678xxxx", "012345678", true},
+	{"xx012345678xx", "012345678", true},
+	{"xxxx012345678", "012345678", true},
+	{"012345678xxxxx"[1:], "012345678", false},
+	{"xxxxx012345678"[:13], "012345678", false},
+	// 16-byte needle
+	{"xxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEF", false},
+	{"0123456789ABCDEFxxxx", "0123456789ABCDEF", true},
+	{"xx0123456789ABCDEFxx", "0123456789ABCDEF", true},
+	{"xxxx0123456789ABCDEF", "0123456789ABCDEF", true},
+	{"0123456789ABCDEFxxxxx"[1:], "0123456789ABCDEF", false},
+	{"xxxxx0123456789ABCDEF"[:20], "0123456789ABCDEF", false},
+	// 17-31-byte needle
+	{"xxxxxxxxxxxxxxxxxxxxx", "0123456789ABCDEFG", false},
+	{"0123456789ABCDEFGxxxx", "0123456789ABCDEFG", true},
+	{"xx0123456789ABCDEFGxx", "0123456789ABCDEFG", true},
+	{"xxxx0123456789ABCDEFG", "0123456789ABCDEFG", true},
+	{"0123456789ABCDEFGxxxxx"[1:], "0123456789ABCDEFG", false},
+	{"xxxxx0123456789ABCDEFG"[:21], "0123456789ABCDEFG", false},
+
+	// partial match cases
+	{"xx01x", "012", false},                             // 3
+	{"xx0123x", "01234", false},                         // 5-7
+	{"xx01234567x", "012345678", false},                 // 9-15
+	{"xx0123456789ABCDEFx", "0123456789ABCDEFG", false}, // 17-31, issue 15679
 }
 
 func TestContains(t *testing.T) {
diff --git a/src/sync/atomic/64bit_arm.go b/src/sync/atomic/64bit_arm.go
index b98e608..4ef1174 100644
--- a/src/sync/atomic/64bit_arm.go
+++ b/src/sync/atomic/64bit_arm.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/asm_386.s b/src/sync/atomic/asm_386.s
index 383d759..f2a13da 100644
--- a/src/sync/atomic/asm_386.s
+++ b/src/sync/atomic/asm_386.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/sync/atomic/asm_amd64.s b/src/sync/atomic/asm_amd64.s
index 551c002..690907c 100644
--- a/src/sync/atomic/asm_amd64.s
+++ b/src/sync/atomic/asm_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/sync/atomic/asm_amd64p32.s b/src/sync/atomic/asm_amd64p32.s
index b4e19ee..8164b3e 100644
--- a/src/sync/atomic/asm_amd64p32.s
+++ b/src/sync/atomic/asm_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/sync/atomic/asm_arm.s b/src/sync/atomic/asm_arm.s
index 3b50657..d35ea2a 100644
--- a/src/sync/atomic/asm_arm.s
+++ b/src/sync/atomic/asm_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -208,7 +208,7 @@ loop:
 ok:
 	RET
 
-// Fast, cached version of check.  No frame, just MOVW CMP RET after first time.
+// Fast, cached version of check. No frame, just MOVW CMP RET after first time.
 TEXT	fastCheck64<>(SB),NOSPLIT,$-4
 	MOVW	ok64<>(SB), R0
 	CMP	$0, R0	// have we been here before?
diff --git a/src/sync/atomic/asm_arm64.s b/src/sync/atomic/asm_arm64.s
index 32e9625..b351603 100644
--- a/src/sync/atomic/asm_arm64.s
+++ b/src/sync/atomic/asm_arm64.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/asm_darwin_arm.s b/src/sync/atomic/asm_darwin_arm.s
index 36dd483..c643360 100644
--- a/src/sync/atomic/asm_darwin_arm.s
+++ b/src/sync/atomic/asm_darwin_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/asm_freebsd_arm.s b/src/sync/atomic/asm_freebsd_arm.s
index 46710ea..cb8c783 100644
--- a/src/sync/atomic/asm_freebsd_arm.s
+++ b/src/sync/atomic/asm_freebsd_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/asm_linux_arm.s b/src/sync/atomic/asm_linux_arm.s
index 97b7b57..fc41968 100644
--- a/src/sync/atomic/asm_linux_arm.s
+++ b/src/sync/atomic/asm_linux_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/sync/atomic/asm_mips64x.s b/src/sync/atomic/asm_mips64x.s
index 608ff21..b3c4627 100644
--- a/src/sync/atomic/asm_mips64x.s
+++ b/src/sync/atomic/asm_mips64x.s
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/sync/atomic/asm_nacl_arm.s b/src/sync/atomic/asm_nacl_arm.s
index 8b4b687..f85544c 100644
--- a/src/sync/atomic/asm_nacl_arm.s
+++ b/src/sync/atomic/asm_nacl_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/asm_netbsd_arm.s b/src/sync/atomic/asm_netbsd_arm.s
index 5c98de3..9a2ab1d 100644
--- a/src/sync/atomic/asm_netbsd_arm.s
+++ b/src/sync/atomic/asm_netbsd_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/asm_openbsd_arm.s b/src/sync/atomic/asm_openbsd_arm.s
index 8c48a0a..a1a062a 100644
--- a/src/sync/atomic/asm_openbsd_arm.s
+++ b/src/sync/atomic/asm_openbsd_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/asm_plan9_arm.s b/src/sync/atomic/asm_plan9_arm.s
new file mode 100644
index 0000000..d74ff4a
--- /dev/null
+++ b/src/sync/atomic/asm_plan9_arm.s
@@ -0,0 +1,108 @@
+// 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"
+
+#define DMB_ISH_7 \
+	MOVB	runtime·goarm(SB), R11; \
+	CMP	$7, R11; \
+	BLT	2(PC); \
+	WORD	$0xf57ff05b	// dmb ish
+
+// Plan9/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)
+	DMB_ISH_7
+	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
+	DMB_ISH_7
+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
index d3e49ae..2474e96 100644
--- a/src/sync/atomic/asm_ppc64x.s
+++ b/src/sync/atomic/asm_ppc64x.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -15,8 +15,7 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0-20
 	SYNC
 	LWAR	(R3), R5
 	STWCCC	R4, (R3)
-	BNE	-3(PC)
-	SYNC
+	BNE	-2(PC)
 	ISYNC
 	MOVW	R5, old+16(FP)
 	RET
@@ -30,8 +29,7 @@ TEXT ·SwapUint64(SB),NOSPLIT,$0-24
 	SYNC
 	LDAR	(R3), R5
 	STDCCC	R4, (R3)
-	BNE	-3(PC)
-	SYNC
+	BNE	-2(PC)
 	ISYNC
 	MOVD	R5, old+16(FP)
 	RET
@@ -49,10 +47,9 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
 	SYNC
 	LWAR	(R3), R6
 	CMPW	R6, R4
-	BNE	8(PC)
+	BNE	7(PC)
 	STWCCC	R5, (R3)
-	BNE	-5(PC)
-	SYNC
+	BNE	-4(PC)
 	ISYNC
 	MOVD	$1, R3
 	MOVB	R3, swapped+16(FP)
@@ -73,10 +70,9 @@ TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
 	SYNC
 	LDAR	(R3), R6
 	CMP	R6, R4
-	BNE	8(PC)
+	BNE	7(PC)
 	STDCCC	R5, (R3)
-	BNE	-5(PC)
-	SYNC
+	BNE	-4(PC)
 	ISYNC
 	MOVD	$1, R3
 	MOVB	R3, swapped+24(FP)
@@ -94,8 +90,7 @@ TEXT ·AddUint32(SB),NOSPLIT,$0-20
 	LWAR	(R3), R5
 	ADD	R4, R5
 	STWCCC	R5, (R3)
-	BNE	-4(PC)
-	SYNC
+	BNE	-3(PC)
 	ISYNC
 	MOVW	R5, ret+16(FP)
 	RET
@@ -113,8 +108,7 @@ TEXT ·AddUint64(SB),NOSPLIT,$0-24
 	LDAR	(R3), R5
 	ADD	R4, R5
 	STDCCC	R5, (R3)
-	BNE	-4(PC)
-	SYNC
+	BNE	-3(PC)
 	ISYNC
 	MOVD	R5, ret+16(FP)
 	RET
diff --git a/src/sync/atomic/asm_s390x.s b/src/sync/atomic/asm_s390x.s
new file mode 100644
index 0000000..b5389be
--- /dev/null
+++ b/src/sync/atomic/asm_s390x.s
@@ -0,0 +1,143 @@
+// Copyright 2016 The Go 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
+	BR	·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0-20
+	MOVD	addr+0(FP), R3
+	MOVWZ	new+8(FP), R4
+	MOVWZ	(R3), R5
+repeat:
+	CS	R5, R4, (R3) // if (R3)==R5 then (R3)=R4 else R5=(R3)
+	BNE	repeat
+	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
+	MOVD	(R3), R5
+repeat:
+	CSG	R5, R4, (R3) // if (R3)==R5 then (R3)=R4 else R5=(R3)
+	BNE	repeat
+	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	ptr+0(FP), R3
+	MOVWZ	old+8(FP), R4
+	MOVWZ	new+12(FP), R5
+	CS	R4, R5, 0(R3) // if R4==(R3) then (R3)=R5 else R4=(R3)
+	BNE	cas_fail
+	MOVB	$1, ret+16(FP)
+	RET
+cas_fail:
+	MOVB	$0, ret+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	ptr+0(FP), R3
+	MOVD	old+8(FP), R4
+	MOVD	new+16(FP), R5
+	CSG	R4, R5, 0(R3) // if R4==(R3) then (R3)=R5 else R4=(R3)
+	BNE	cas64_fail
+	MOVB	$1, ret+24(FP)
+	RET
+cas64_fail:
+	MOVB	$0, ret+24(FP)
+	RET
+
+TEXT ·AddInt32(SB),NOSPLIT,$0-20
+	BR	·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0-20
+	MOVD	ptr+0(FP), R4
+	MOVWZ	delta+8(FP), R5
+	MOVWZ	(R4), R3
+repeat:
+	ADD	R3, R5, R6
+	CS	R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4)
+	BNE	repeat
+	MOVW	R6, 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	ptr+0(FP), R4
+	MOVD	delta+8(FP), R5
+	MOVD	(R4), R3
+repeat:
+	ADD	R3, R5, R6
+	CSG	R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4)
+	BNE	repeat
+	MOVD	R6, ret+16(FP)
+	RET
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0-12
+	BR	·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-12
+	MOVD	addr+0(FP), R3
+	MOVW	0(R3), R4
+	MOVW	R4, val+8(FP)
+	RET
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+	BR	·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+	MOVD	addr+0(FP), R3
+	MOVD	0(R3), R4
+	MOVD	R4, 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	ptr+0(FP), R3
+	MOVW	val+8(FP), R4
+	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
+	MOVD	R4, 0(R3)
+	RET
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0-16
+	BR	·StoreUint64(SB)
diff --git a/src/sync/atomic/atomic_linux_arm_test.go b/src/sync/atomic/atomic_linux_arm_test.go
index b6965b9..922eb17 100644
--- a/src/sync/atomic/atomic_linux_arm_test.go
+++ b/src/sync/atomic/atomic_linux_arm_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/atomic_test.go b/src/sync/atomic/atomic_test.go
index e2c63b9..deb3ccb 100644
--- a/src/sync/atomic/atomic_test.go
+++ b/src/sync/atomic/atomic_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -747,7 +747,7 @@ func TestStorePointer(t *testing.T) {
 // (Is the function atomic?)
 //
 // For each function, we write a "hammer" function that repeatedly
-// uses the atomic operation to add 1 to a value.  After running
+// uses the atomic operation to add 1 to a value. After running
 // multiple hammers in parallel, check that we end with the correct
 // total.
 // Swap can't add 1, so it uses a different scheme.
diff --git a/src/sync/atomic/doc.go b/src/sync/atomic/doc.go
index 10fb8c9..302ff43 100644
--- a/src/sync/atomic/doc.go
+++ b/src/sync/atomic/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/sync/atomic/export_linux_arm_test.go b/src/sync/atomic/export_linux_arm_test.go
index 9f0c856..51f1577 100644
--- a/src/sync/atomic/export_linux_arm_test.go
+++ b/src/sync/atomic/export_linux_arm_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/race.s b/src/sync/atomic/race.s
index bdce766..fd6ca22 100644
--- a/src/sync/atomic/race.s
+++ b/src/sync/atomic/race.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/sync/atomic/value.go b/src/sync/atomic/value.go
index ab3aa11..30abf72 100644
--- a/src/sync/atomic/value.go
+++ b/src/sync/atomic/value.go
@@ -12,7 +12,11 @@ import (
 // Values can be created as part of other data structures.
 // The zero value for a Value returns nil from Load.
 // Once Store has been called, a Value must not be copied.
+//
+// A Value must not be copied after first use.
 type Value struct {
+	noCopy noCopy
+
 	v interface{}
 }
 
@@ -83,3 +87,13 @@ func (v *Value) Store(x interface{}) {
 // Disable/enable preemption, implemented in runtime.
 func runtime_procPin()
 func runtime_procUnpin()
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
diff --git a/src/sync/atomic/value_test.go b/src/sync/atomic/value_test.go
index 382dc68..fd90451 100644
--- a/src/sync/atomic/value_test.go
+++ b/src/sync/atomic/value_test.go
@@ -86,6 +86,11 @@ func TestValueConcurrent(t *testing.T) {
 		{complex(0, 0), complex(1, 2), complex(3, 4), complex(5, 6)},
 	}
 	p := 4 * runtime.GOMAXPROCS(0)
+	N := int(1e5)
+	if testing.Short() {
+		p /= 2
+		N = 1e3
+	}
 	for _, test := range tests {
 		var v Value
 		done := make(chan bool)
@@ -93,7 +98,7 @@ func TestValueConcurrent(t *testing.T) {
 			go func() {
 				r := rand.New(rand.NewSource(rand.Int63()))
 			loop:
-				for j := 0; j < 1e5; j++ {
+				for j := 0; j < N; j++ {
 					x := test[r.Intn(len(test))]
 					v.Store(x)
 					x = v.Load()
diff --git a/src/sync/cond.go b/src/sync/cond.go
index 0aefcda..c070d9d 100644
--- a/src/sync/cond.go
+++ b/src/sync/cond.go
@@ -5,7 +5,6 @@
 package sync
 
 import (
-	"internal/race"
 	"sync/atomic"
 	"unsafe"
 )
@@ -21,11 +20,12 @@ import (
 // A Cond can be created as part of other structures.
 // A Cond must not be copied after first use.
 type Cond struct {
+	noCopy noCopy
+
 	// L is held while observing or changing the condition
 	L Locker
 
-	sema    syncSema
-	waiters uint32 // number of waiters
+	notify  notifyList
 	checker copyChecker
 }
 
@@ -35,13 +35,13 @@ func NewCond(l Locker) *Cond {
 }
 
 // Wait atomically unlocks c.L and suspends execution
-// of the calling goroutine.  After later resuming execution,
-// Wait locks c.L before returning.  Unlike in other systems,
+// of the calling goroutine. After later resuming execution,
+// Wait locks c.L before returning. Unlike in other systems,
 // Wait cannot return unless awoken by Broadcast or Signal.
 //
 // Because c.L is not locked when Wait first resumes, the caller
 // typically cannot assume that the condition is true when
-// Wait returns.  Instead, the caller should Wait in a loop:
+// Wait returns. Instead, the caller should Wait in a loop:
 //
 //    c.L.Lock()
 //    for !condition() {
@@ -52,15 +52,9 @@ func NewCond(l Locker) *Cond {
 //
 func (c *Cond) Wait() {
 	c.checker.check()
-	if race.Enabled {
-		race.Disable()
-	}
-	atomic.AddUint32(&c.waiters, 1)
-	if race.Enabled {
-		race.Enable()
-	}
+	t := runtime_notifyListAdd(&c.notify)
 	c.L.Unlock()
-	runtime_Syncsemacquire(&c.sema)
+	runtime_notifyListWait(&c.notify, t)
 	c.L.Lock()
 }
 
@@ -69,7 +63,8 @@ func (c *Cond) Wait() {
 // It is allowed but not required for the caller to hold c.L
 // during the call.
 func (c *Cond) Signal() {
-	c.signalImpl(false)
+	c.checker.check()
+	runtime_notifyListNotifyOne(&c.notify)
 }
 
 // Broadcast wakes all goroutines waiting on c.
@@ -77,34 +72,8 @@ func (c *Cond) Signal() {
 // It is allowed but not required for the caller to hold c.L
 // during the call.
 func (c *Cond) Broadcast() {
-	c.signalImpl(true)
-}
-
-func (c *Cond) signalImpl(all bool) {
 	c.checker.check()
-	if race.Enabled {
-		race.Disable()
-	}
-	for {
-		old := atomic.LoadUint32(&c.waiters)
-		if old == 0 {
-			if race.Enabled {
-				race.Enable()
-			}
-			return
-		}
-		new := old - 1
-		if all {
-			new = 0
-		}
-		if atomic.CompareAndSwapUint32(&c.waiters, old, new) {
-			if race.Enabled {
-				race.Enable()
-			}
-			runtime_Syncsemrelease(&c.sema, old-new)
-			return
-		}
-	}
+	runtime_notifyListNotifyAll(&c.notify)
 }
 
 // copyChecker holds back pointer to itself to detect object copying.
@@ -117,3 +86,13 @@ func (c *copyChecker) check() {
 		panic("sync.Cond is copied")
 	}
 }
+
+// noCopy may be embedded into structs which must not be copied
+// after the first use.
+//
+// See https://github.com/golang/go/issues/8005#issuecomment-190753527
+// for details.
+type noCopy struct{}
+
+// Lock is a no-op used by -copylocks checker from `go vet`.
+func (*noCopy) Lock() {}
diff --git a/src/sync/cond_test.go b/src/sync/cond_test.go
index 467c806..7b07295 100644
--- a/src/sync/cond_test.go
+++ b/src/sync/cond_test.go
@@ -8,6 +8,7 @@ import (
 
 	"runtime"
 	"testing"
+	"time"
 )
 
 func TestCondSignal(t *testing.T) {
@@ -183,6 +184,64 @@ func TestRace(t *testing.T) {
 	<-done
 }
 
+func TestCondSignalStealing(t *testing.T) {
+	for iters := 0; iters < 1000; iters++ {
+		var m Mutex
+		cond := NewCond(&m)
+
+		// Start a waiter.
+		ch := make(chan struct{})
+		go func() {
+			m.Lock()
+			ch <- struct{}{}
+			cond.Wait()
+			m.Unlock()
+
+			ch <- struct{}{}
+		}()
+
+		<-ch
+		m.Lock()
+		m.Unlock()
+
+		// We know that the waiter is in the cond.Wait() call because we
+		// synchronized with it, then acquired/released the mutex it was
+		// holding when we synchronized.
+		//
+		// Start two goroutines that will race: one will broadcast on
+		// the cond var, the other will wait on it.
+		//
+		// The new waiter may or may not get notified, but the first one
+		// has to be notified.
+		done := false
+		go func() {
+			cond.Broadcast()
+		}()
+
+		go func() {
+			m.Lock()
+			for !done {
+				cond.Wait()
+			}
+			m.Unlock()
+		}()
+
+		// Check that the first waiter does get signaled.
+		select {
+		case <-ch:
+		case <-time.After(2 * time.Second):
+			t.Fatalf("First waiter didn't get broadcast.")
+		}
+
+		// Release the second waiter in case it didn't get the
+		// broadcast.
+		m.Lock()
+		done = true
+		m.Unlock()
+		cond.Broadcast()
+	}
+}
+
 func TestCondCopy(t *testing.T) {
 	defer func() {
 		err := recover()
diff --git a/src/sync/export_test.go b/src/sync/export_test.go
index fa5983a..6ed38da 100644
--- a/src/sync/export_test.go
+++ b/src/sync/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/sync/mutex.go b/src/sync/mutex.go
index eb52614..9089279 100644
--- a/src/sync/mutex.go
+++ b/src/sync/mutex.go
@@ -3,8 +3,8 @@
 // license that can be found in the LICENSE file.
 
 // Package sync provides basic synchronization primitives such as mutual
-// exclusion locks.  Other than the Once and WaitGroup types, most are intended
-// for use by low-level library routines.  Higher-level synchronization is
+// exclusion locks. Other than the Once and WaitGroup types, most are intended
+// for use by low-level library routines. Higher-level synchronization is
 // better done via channels and communication.
 //
 // Values containing the types defined in this package should not be copied.
@@ -19,6 +19,8 @@ import (
 // A Mutex is a mutual exclusion lock.
 // Mutexes can be created as part of other structures;
 // the zero value for a Mutex is an unlocked mutex.
+//
+// A Mutex must not be copied after first use.
 type Mutex struct {
 	state int32
 	sema  uint32
diff --git a/src/sync/once.go b/src/sync/once.go
index 10b42fd..d8ef952 100644
--- a/src/sync/once.go
+++ b/src/sync/once.go
@@ -18,10 +18,10 @@ type Once struct {
 // first time for this instance of Once. In other words, given
 // 	var once Once
 // if once.Do(f) is called multiple times, only the first call will invoke f,
-// even if f has a different value in each invocation.  A new instance of
+// even if f has a different value in each invocation. A new instance of
 // Once is required for each function to execute.
 //
-// Do is intended for initialization that must be run exactly once.  Since f
+// Do is intended for initialization that must be run exactly once. Since f
 // is niladic, it may be necessary to use a function literal to capture the
 // arguments to a function to be invoked by Do:
 // 	config.once.Do(func() { config.init(filename) })
diff --git a/src/sync/pool.go b/src/sync/pool.go
index 381af0b..bf29d88 100644
--- a/src/sync/pool.go
+++ b/src/sync/pool.go
@@ -40,7 +40,10 @@ import (
 // that scenario. It is more efficient to have such objects implement their own
 // free list.
 //
+// A Pool must not be copied after first use.
 type Pool struct {
+	noCopy noCopy
+
 	local     unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal
 	localSize uintptr        // size of the local array
 
@@ -149,7 +152,7 @@ func (p *Pool) getSlow() (x interface{}) {
 func (p *Pool) pin() *poolLocal {
 	pid := runtime_procPin()
 	// In pinSlow we store to localSize and then to local, here we load in opposite order.
-	// Since we've disabled preemption, GC can not happen in between.
+	// Since we've disabled preemption, GC cannot happen in between.
 	// Thus here we must observe local at least as large localSize.
 	// We can observe a newer/larger local, it is fine (we must observe its zero-initialized-ness).
 	s := atomic.LoadUintptr(&p.localSize) // load-acquire
@@ -179,8 +182,8 @@ func (p *Pool) pinSlow() *poolLocal {
 	// If GOMAXPROCS changes between GCs, we re-allocate the array and lose the old one.
 	size := runtime.GOMAXPROCS(0)
 	local := make([]poolLocal, size)
-	atomic.StorePointer((*unsafe.Pointer)(&p.local), unsafe.Pointer(&local[0])) // store-release
-	atomic.StoreUintptr(&p.localSize, uintptr(size))                            // store-release
+	atomic.StorePointer(&p.local, unsafe.Pointer(&local[0])) // store-release
+	atomic.StoreUintptr(&p.localSize, uintptr(size))         // store-release
 	return &local[pid]
 }
 
diff --git a/src/sync/runtime.go b/src/sync/runtime.go
index c66d2de..96c56c8 100644
--- a/src/sync/runtime.go
+++ b/src/sync/runtime.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -19,24 +19,33 @@ func runtime_Semacquire(s *uint32)
 // library and should not be used directly.
 func runtime_Semrelease(s *uint32)
 
-// Approximation of syncSema in runtime/sema.go.
-type syncSema struct {
-	lock uintptr
-	head unsafe.Pointer
-	tail unsafe.Pointer
+// Approximation of notifyList in runtime/sema.go. Size and alignment must
+// agree.
+type notifyList struct {
+	wait   uint32
+	notify uint32
+	lock   uintptr
+	head   unsafe.Pointer
+	tail   unsafe.Pointer
 }
 
-// Syncsemacquire waits for a pairing Syncsemrelease on the same semaphore s.
-func runtime_Syncsemacquire(s *syncSema)
+// See runtime/sema.go for documentation.
+func runtime_notifyListAdd(l *notifyList) uint32
 
-// Syncsemrelease waits for n pairing Syncsemacquire on the same semaphore s.
-func runtime_Syncsemrelease(s *syncSema, n uint32)
+// See runtime/sema.go for documentation.
+func runtime_notifyListWait(l *notifyList, t uint32)
 
-// Ensure that sync and runtime agree on size of syncSema.
-func runtime_Syncsemcheck(size uintptr)
+// See runtime/sema.go for documentation.
+func runtime_notifyListNotifyAll(l *notifyList)
+
+// See runtime/sema.go for documentation.
+func runtime_notifyListNotifyOne(l *notifyList)
+
+// Ensure that sync and runtime agree on size of notifyList.
+func runtime_notifyListCheck(size uintptr)
 func init() {
-	var s syncSema
-	runtime_Syncsemcheck(unsafe.Sizeof(s))
+	var n notifyList
+	runtime_notifyListCheck(unsafe.Sizeof(n))
 }
 
 // Active spinning runtime support.
diff --git a/src/sync/runtime_sema_test.go b/src/sync/runtime_sema_test.go
index 5b7dd3d..a2382f4 100644
--- a/src/sync/runtime_sema_test.go
+++ b/src/sync/runtime_sema_test.go
@@ -25,6 +25,9 @@ func BenchmarkSemaUncontended(b *testing.B) {
 }
 
 func benchmarkSema(b *testing.B, block, work bool) {
+	if b.N == 0 {
+		return
+	}
 	sem := uint32(0)
 	if block {
 		done := make(chan bool)
diff --git a/src/sync/rwmutex.go b/src/sync/rwmutex.go
index d438c93..6734360 100644
--- a/src/sync/rwmutex.go
+++ b/src/sync/rwmutex.go
@@ -11,11 +11,17 @@ import (
 )
 
 // An RWMutex is a reader/writer mutual exclusion lock.
-// The lock can be held by an arbitrary number of readers
-// or a single writer.
-// RWMutexes can be created as part of other
-// structures; the zero value for a RWMutex is
-// an unlocked mutex.
+// The lock can be held by an arbitrary number of readers or a single writer.
+// RWMutexes can be created as part of other structures;
+// the zero value for a RWMutex is an unlocked mutex.
+//
+// An RWMutex must not be copied after first use.
+//
+// If a goroutine holds a RWMutex for reading, it must not expect this or any
+// other goroutine to be able to also take the read lock until the first read
+// lock is released. In particular, this prohibits recursive read locking.
+// This is to ensure that the lock eventually becomes available;
+// a blocked Lock call excludes new readers from acquiring the lock.
 type RWMutex struct {
 	w           Mutex  // held if there are pending writers
 	writerSem   uint32 // semaphore for writers to wait for completing readers
@@ -71,9 +77,6 @@ func (rw *RWMutex) RUnlock() {
 // Lock locks rw for writing.
 // If the lock is already locked for reading or writing,
 // Lock blocks until the lock is available.
-// To ensure that the lock eventually becomes available,
-// a blocked Lock call excludes new readers from acquiring
-// the lock.
 func (rw *RWMutex) Lock() {
 	if race.Enabled {
 		_ = rw.w.state
@@ -94,11 +97,11 @@ func (rw *RWMutex) Lock() {
 	}
 }
 
-// Unlock unlocks rw for writing.  It is a run-time error if rw is
+// Unlock unlocks rw for writing. It is a run-time error if rw is
 // not locked for writing on entry to Unlock.
 //
 // As with Mutexes, a locked RWMutex is not associated with a particular
-// goroutine.  One goroutine may RLock (Lock) an RWMutex and then
+// goroutine. One goroutine may RLock (Lock) an RWMutex and then
 // arrange for another goroutine to RUnlock (Unlock) it.
 func (rw *RWMutex) Unlock() {
 	if race.Enabled {
diff --git a/src/sync/waitgroup.go b/src/sync/waitgroup.go
index c77fec3..b386e1f 100644
--- a/src/sync/waitgroup.go
+++ b/src/sync/waitgroup.go
@@ -12,10 +12,14 @@ import (
 
 // A WaitGroup waits for a collection of goroutines to finish.
 // The main goroutine calls Add to set the number of
-// goroutines to wait for.  Then each of the goroutines
-// runs and calls Done when finished.  At the same time,
+// goroutines to wait for. Then each of the goroutines
+// runs and calls Done when finished. At the same time,
 // Wait can be used to block until all goroutines have finished.
+//
+// A WaitGroup must not be copied after first use.
 type WaitGroup struct {
+	noCopy noCopy
+
 	// 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
diff --git a/src/syscall/asm.s b/src/syscall/asm.s
index d4ca868..06449eb 100644
--- a/src/syscall/asm.s
+++ b/src/syscall/asm.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/syscall/asm_linux_s390x.s b/src/syscall/asm_linux_s390x.s
new file mode 100644
index 0000000..e22a92b
--- /dev/null
+++ b/src/syscall/asm_linux_s390x.s
@@ -0,0 +1,156 @@
+// Copyright 2016 The Go 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 calls for s390x, 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), R2
+	MOVD	a2+16(FP), R3
+	MOVD	a3+24(FP), R4
+	MOVD	$0, R5
+	MOVD	$0, R6
+	MOVD	$0, R7
+	MOVD	trap+0(FP), R1	// syscall entry
+	SYSCALL
+	MOVD	$0xfffffffffffff001, R8
+	CMPUBLT	R2, R8, ok
+	MOVD	$-1, r1+32(FP)
+	MOVD	$0, r2+40(FP)
+	NEG	R2, R2
+	MOVD	R2, err+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R2, r1+32(FP)
+	MOVD	R3, r2+40(FP)
+	MOVD	$0, err+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+	BL	runtime·entersyscall(SB)
+	MOVD	a1+8(FP), R2
+	MOVD	a2+16(FP), R3
+	MOVD	a3+24(FP), R4
+	MOVD	a4+32(FP), R5
+	MOVD	a5+40(FP), R6
+	MOVD	a6+48(FP), R7
+	MOVD	trap+0(FP), R1	// syscall entry
+	SYSCALL
+	MOVD	$0xfffffffffffff001, R8
+	CMPUBLT	R2, R8, ok6
+	MOVD	$-1, r1+56(FP)
+	MOVD	$0, r2+64(FP)
+	NEG	R2, R2
+	MOVD	R2, err+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok6:
+	MOVD	R2, r1+56(FP)
+	MOVD	R3, r2+64(FP)
+	MOVD	$0, err+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+	MOVD	a1+8(FP), R2
+	MOVD	a2+16(FP), R3
+	MOVD	a3+24(FP), R4
+	MOVD	$0, R5
+	MOVD	$0, R6
+	MOVD	$0, R7
+	MOVD	trap+0(FP), R1	// syscall entry
+	SYSCALL
+	MOVD	$0xfffffffffffff001, R8
+	CMPUBLT	R2, R8, ok1
+	MOVD	$-1, r1+32(FP)
+	MOVD	$0, r2+40(FP)
+	NEG	R2, R2
+	MOVD	R2, err+48(FP)	// errno
+	RET
+ok1:
+	MOVD	R2, r1+32(FP)
+	MOVD	R3, r2+40(FP)
+	MOVD	$0, err+48(FP)	// errno
+	RET
+
+// func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+	MOVD	a1+8(FP), R2
+	MOVD	a2+16(FP), R3
+	MOVD	a3+24(FP), R4
+	MOVD	a4+32(FP), R5
+	MOVD	a5+40(FP), R6
+	MOVD	a6+48(FP), R7
+	MOVD	trap+0(FP), R1	// syscall entry
+	SYSCALL
+	MOVD	$0xfffffffffffff001, R8
+	CMPUBLT	R2, R8, ok2
+	MOVD	$-1, r1+56(FP)
+	MOVD	$0, r2+64(FP)
+	NEG	R2, R2
+	MOVD	R2, err+72(FP)	// errno
+	RET
+ok2:
+	MOVD	R2, r1+56(FP)
+	MOVD	R3, r2+64(FP)
+	MOVD	$0, err+72(FP)	// errno
+	RET
+
+#define SYS_SOCKETCALL 102	/* from zsysnum_linux_s390x.go */
+
+// 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-72
+	BL	runtime·entersyscall(SB)
+	MOVD	$SYS_SOCKETCALL, R1	// syscall entry
+	MOVD	call+0(FP), R2		// socket call number
+	MOVD	$a0+8(FP), R3		// pointer to call arguments
+	MOVD	$0, R4
+	MOVD	$0, R5
+	MOVD	$0, R6
+	MOVD	$0, R7
+	SYSCALL
+	MOVD	$0xfffffffffffff001, R8
+	CMPUBLT	R2, R8, oksock
+	MOVD	$-1, n+56(FP)
+	NEG	R2, R2
+	MOVD	R2, err+64(FP)
+	BL	runtime·exitsyscall(SB)
+	RET
+oksock:
+	MOVD	R2, n+56(FP)
+	MOVD	$0, err+64(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET
+
+// 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-72
+	MOVD	$SYS_SOCKETCALL, R1	// syscall entry
+	MOVD	call+0(FP), R2		// socket call number
+	MOVD	$a0+8(FP), R3		// pointer to call arguments
+	MOVD	$0, R4
+	MOVD	$0, R5
+	MOVD	$0, R6
+	MOVD	$0, R7
+	SYSCALL
+	MOVD	$0xfffffffffffff001, R8
+	CMPUBLT	R2, R8, oksock1
+	MOVD	$-1, n+56(FP)
+	NEG	R2, R2
+	MOVD	R2, err+64(FP)
+	RET
+oksock1:
+	MOVD	R2, n+56(FP)
+	MOVD	$0, err+64(FP)
+	RET
diff --git a/src/syscall/asm_plan9_arm.s b/src/syscall/asm_plan9_arm.s
new file mode 100644
index 0000000..aad515f
--- /dev/null
+++ b/src/syscall/asm_plan9_arm.s
@@ -0,0 +1,99 @@
+// 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"
+
+#define SYS_SEEK 39	/* from zsysnum_plan9.go */
+
+// System call support for plan9 on arm
+
+TEXT	sysresult<>(SB),NOSPLIT,$12
+	MOVW	$runtime·emptystring+0(SB), R2
+	CMP		$-1, R0
+	B.NE	ok
+	MOVW	R1, save-4(SP)
+	BL		runtime·errstr(SB)
+	MOVW	save-4(SP), R1
+	MOVW	$err-12(SP), R2
+ok:
+	MOVM.IA	(R2), [R3-R4]
+	MOVM.IA	[R3-R4], (R1)
+	RET
+	
+//func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err ErrorString)
+TEXT	·Syscall(SB),NOSPLIT,$0-32
+	BL		runtime·entersyscall(SB)
+	MOVW	trap+0(FP), R0	// syscall num
+	MOVM.IA.W	(R13),[R1-R2]	// pop LR and caller's LR
+	SWI		0
+	MOVM.DB.W	[R1-R2],(R13)	// push LR and caller's LR
+	MOVW	$0, R2
+	MOVW	$r1+16(FP), R1
+	MOVM.IA.W	[R0,R2], (R1)
+	BL		sysresult<>(SB)
+	BL		runtime·exitsyscall(SB)
+	RET
+
+//func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err ErrorString)
+// Actually Syscall5 but the rest of the code expects it to be named Syscall6.
+TEXT	·Syscall6(SB),NOSPLIT,$0-44
+	BL		runtime·entersyscall(SB)
+	MOVW	trap+0(FP), R0	// syscall num
+	MOVM.IA.W	(R13),[R1-R2]	// pop LR and caller's LR
+	SWI		0
+	MOVM.DB.W	[R1-R2],(R13)	// push LR and caller's LR
+	MOVW	$0, R1
+	MOVW	$r1+28(FP), R1
+	MOVM.IA.W	[R0,R2], (R1)
+	BL		sysresult<>(SB)
+	BL		runtime·exitsyscall(SB)
+	RET
+
+//func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+	MOVW	trap+0(FP), R0	// syscall num
+	MOVM.IA.W	(R13),[R1]		// pop caller's LR
+	SWI		0
+	MOVM.DB.W	[R1],(R13)		// push caller's LR
+	MOVW	R0, r1+16(FP)
+	MOVW	R0, r2+20(FP)
+	MOVW	R0, err+24(FP)
+	RET
+
+//func RawSyscall6(trap, 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	trap+0(FP), R0	// syscall num
+	MOVM.IA.W	(R13),[R1]		// pop caller's LR
+	SWI		0
+	MOVM.DB.W	[R1],(R13)		// push caller's LR
+	MOVW	R0, r1+28(FP)
+	MOVW	R0, r2+32(FP)
+	MOVW	R0, err+36(FP)
+	RET
+
+//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
+TEXT ·seek(SB),NOSPLIT,$0-36
+	MOVW	$newoffset_lo+20(FP), R5
+	MOVW	R5, placeholder+0(FP)	//placeholder = dest for return value
+	MOVW	$SYS_SEEK, R0		// syscall num
+	MOVM.IA.W	(R13),[R1]		// pop LR
+	SWI		0
+	MOVM.DB.W	[R1],(R13)		// push LR
+	CMP		$-1, R0
+	MOVW.EQ	R0, 0(R5)
+	MOVW.EQ	R0, 4(R5)
+	MOVW	$err+28(FP), R1
+	BL		sysresult<>(SB)
+	RET
+
+//func exit(code int)
+// Import runtime·exit for cleanly exiting.
+TEXT ·exit(SB),NOSPLIT,$4-4
+	NO_LOCAL_POINTERS
+	MOVW	code+0(FP), R0
+	MOVW	R0, e-4(SP)
+	BL		runtime·exit(SB)
+	RET
diff --git a/src/syscall/bpf_bsd.go b/src/syscall/bpf_bsd.go
index cc6c1e7..8b58755 100644
--- a/src/syscall/bpf_bsd.go
+++ b/src/syscall/bpf_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -12,14 +12,17 @@ import (
 	"unsafe"
 )
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func BpfStmt(code, k int) *BpfInsn {
 	return &BpfInsn{Code: uint16(code), K: uint32(k)}
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func BpfJump(code, k, jt, jf int) *BpfInsn {
 	return &BpfInsn{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func BpfBuflen(fd int) (int, error) {
 	var l int
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGBLEN, uintptr(unsafe.Pointer(&l)))
@@ -29,6 +32,7 @@ func BpfBuflen(fd int) (int, error) {
 	return l, nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func SetBpfBuflen(fd, l int) (int, error) {
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSBLEN, uintptr(unsafe.Pointer(&l)))
 	if err != 0 {
@@ -37,6 +41,7 @@ func SetBpfBuflen(fd, l int) (int, error) {
 	return l, nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func BpfDatalink(fd int) (int, error) {
 	var t int
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGDLT, uintptr(unsafe.Pointer(&t)))
@@ -46,6 +51,7 @@ func BpfDatalink(fd int) (int, error) {
 	return t, nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func SetBpfDatalink(fd, t int) (int, error) {
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSDLT, uintptr(unsafe.Pointer(&t)))
 	if err != 0 {
@@ -54,6 +60,7 @@ func SetBpfDatalink(fd, t int) (int, error) {
 	return t, nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func SetBpfPromisc(fd, m int) error {
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCPROMISC, uintptr(unsafe.Pointer(&m)))
 	if err != 0 {
@@ -62,6 +69,7 @@ func SetBpfPromisc(fd, m int) error {
 	return nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func FlushBpf(fd int) error {
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCFLUSH, 0)
 	if err != 0 {
@@ -75,6 +83,7 @@ type ivalue struct {
 	value int16
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func BpfInterface(fd int, name string) (string, error) {
 	var iv ivalue
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGETIF, uintptr(unsafe.Pointer(&iv)))
@@ -84,6 +93,7 @@ func BpfInterface(fd int, name string) (string, error) {
 	return name, nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func SetBpfInterface(fd int, name string) error {
 	var iv ivalue
 	copy(iv.name[:], []byte(name))
@@ -94,6 +104,7 @@ func SetBpfInterface(fd int, name string) error {
 	return nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func BpfTimeout(fd int) (*Timeval, error) {
 	var tv Timeval
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGRTIMEOUT, uintptr(unsafe.Pointer(&tv)))
@@ -103,6 +114,7 @@ func BpfTimeout(fd int) (*Timeval, error) {
 	return &tv, nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func SetBpfTimeout(fd int, tv *Timeval) error {
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSRTIMEOUT, uintptr(unsafe.Pointer(tv)))
 	if err != 0 {
@@ -111,6 +123,7 @@ func SetBpfTimeout(fd int, tv *Timeval) error {
 	return nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func BpfStats(fd int) (*BpfStat, error) {
 	var s BpfStat
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGSTATS, uintptr(unsafe.Pointer(&s)))
@@ -120,6 +133,7 @@ func BpfStats(fd int) (*BpfStat, error) {
 	return &s, nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func SetBpfImmediate(fd, m int) error {
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCIMMEDIATE, uintptr(unsafe.Pointer(&m)))
 	if err != 0 {
@@ -128,6 +142,7 @@ func SetBpfImmediate(fd, m int) error {
 	return nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func SetBpf(fd int, i []BpfInsn) error {
 	var p BpfProgram
 	p.Len = uint32(len(i))
@@ -139,6 +154,7 @@ func SetBpf(fd int, i []BpfInsn) error {
 	return nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func CheckBpfVersion(fd int) error {
 	var v BpfVersion
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCVERSION, uintptr(unsafe.Pointer(&v)))
@@ -151,6 +167,7 @@ func CheckBpfVersion(fd int) error {
 	return nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func BpfHeadercmpl(fd int) (int, error) {
 	var f int
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCGHDRCMPLT, uintptr(unsafe.Pointer(&f)))
@@ -160,6 +177,7 @@ func BpfHeadercmpl(fd int) (int, error) {
 	return f, nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func SetBpfHeadercmpl(fd, f int) error {
 	_, _, err := Syscall(SYS_IOCTL, uintptr(fd), BIOCSHDRCMPLT, uintptr(unsafe.Pointer(&f)))
 	if err != 0 {
diff --git a/src/syscall/creds_test.go b/src/syscall/creds_test.go
index b4a14ff..7c6ab1d 100644
--- a/src/syscall/creds_test.go
+++ b/src/syscall/creds_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/syscall/dir_plan9.go b/src/syscall/dir_plan9.go
index 697bf54..15b2674 100644
--- a/src/syscall/dir_plan9.go
+++ b/src/syscall/dir_plan9.go
@@ -184,6 +184,7 @@ func gbit8(b []byte) (uint8, []byte) {
 }
 
 // gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
+//go:nosplit
 func gbit16(b []byte) (uint16, []byte) {
 	return uint16(b[0]) | uint16(b[1])<<8, b[2:]
 }
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
index 9c5c226..e563848 100644
--- a/src/syscall/dll_windows.go
+++ b/src/syscall/dll_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -130,6 +130,8 @@ func (p *Proc) Addr() uintptr {
 	return p.addr
 }
 
+//go:uintptrescapes
+
 // Call executes procedure p with arguments a. It will panic, if more than 15 arguments
 // are supplied.
 //
@@ -288,6 +290,8 @@ func (p *LazyProc) Addr() uintptr {
 	return p.proc.Addr()
 }
 
+//go:uintptrescapes
+
 // Call executes procedure p with arguments a. It will panic, if more than 15 arguments
 // are supplied.
 //
diff --git a/src/syscall/env_plan9.go b/src/syscall/env_plan9.go
index cbf7f41..9a8a837 100644
--- a/src/syscall/env_plan9.go
+++ b/src/syscall/env_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/syscall/env_unix.go b/src/syscall/env_unix.go
index b5ded9c..5bf3336 100644
--- a/src/syscall/env_unix.go
+++ b/src/syscall/env_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go
index 1cb4754..3f75167 100644
--- a/src/syscall/env_windows.go
+++ b/src/syscall/env_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/src/syscall/errors_plan9.go b/src/syscall/errors_plan9.go
index d7634c9..6952562 100644
--- a/src/syscall/errors_plan9.go
+++ b/src/syscall/errors_plan9.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/syscall/exec_bsd.go b/src/syscall/exec_bsd.go
index d182896..317645f 100644
--- a/src/syscall/exec_bsd.go
+++ b/src/syscall/exec_bsd.go
@@ -32,7 +32,7 @@ func runtime_AfterFork()
 // If a dup or exec fails, write the errno error to pipe.
 // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
 // In the child, this function must not acquire any locks, because
-// they might have been locked at the time of the fork.  This means
+// they might have been locked at the time of the fork. This means
 // no rescheduling, no malloc calls, and no new stack segments.
 // For the same reason compiler does not race instrument it.
 // The calls to RawSyscall are okay because they are assembly
@@ -181,6 +181,9 @@ 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) {
+			if nextfd == pipe { // don't stomp on pipe
+				nextfd++
+			}
 			_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
 			if err1 != 0 {
 				goto childerror
@@ -188,9 +191,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 			RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
 			fd[i] = nextfd
 			nextfd++
-			if nextfd == pipe { // don't stomp on pipe
-				nextfd++
-			}
 		}
 	}
 
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 3e08d43..39764f7 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -7,6 +7,7 @@
 package syscall
 
 import (
+	"runtime"
 	"unsafe"
 )
 
@@ -19,20 +20,21 @@ type SysProcIDMap struct {
 }
 
 type SysProcAttr struct {
-	Chroot      string         // Chroot.
-	Credential  *Credential    // Credential.
-	Ptrace      bool           // Enable tracing.
-	Setsid      bool           // Create session.
-	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
-	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.
+	Chroot       string         // Chroot.
+	Credential   *Credential    // Credential.
+	Ptrace       bool           // Enable tracing.
+	Setsid       bool           // Create session.
+	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
+	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)
+	Unshareflags uintptr        // Flags for unshare 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
@@ -48,7 +50,7 @@ func runtime_AfterFork()
 // If a dup or exec fails, write the errno error to pipe.
 // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
 // In the child, this function must not acquire any locks, because
-// they might have been locked at the time of the fork.  This means
+// they might have been locked at the time of the fork. This means
 // no rescheduling, no malloc calls, and no new stack segments.
 // For the same reason compiler does not race instrument it.
 // The calls to RawSyscall are okay because they are assembly
@@ -93,7 +95,11 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	// About to call fork.
 	// No more allocation or calls of non-assembly functions.
 	runtime_BeforeFork()
-	r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
+	if runtime.GOARCH == "s390x" {
+		r1, _, err1 = RawSyscall6(SYS_CLONE, 0, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0)
+	} else {
+		r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
+	}
 	if err1 != 0 {
 		runtime_AfterFork()
 		return 0, err1
@@ -189,12 +195,26 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
+	// Unshare
+	if sys.Unshareflags != 0 {
+		_, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshareflags, 0, 0)
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
 	// User and groups
 	if cred := sys.Credential; cred != nil {
 		ngroups := uintptr(len(cred.Groups))
+		groups := uintptr(0)
 		if ngroups > 0 {
-			groups := unsafe.Pointer(&cred.Groups[0])
-			_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, uintptr(groups), 0)
+			groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
+		}
+		// Don't call setgroups in case of user namespace, gid mappings
+		// and disabled setgroups, because otherwise unprivileged user namespace
+		// will fail with any non-empty SysProcAttr.Credential.
+		if !(sys.GidMappings != nil && !sys.GidMappingsEnableSetgroups && ngroups == 0) {
+			_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
 			if err1 != 0 {
 				goto childerror
 			}
@@ -250,6 +270,9 @@ 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) {
+			if nextfd == pipe { // don't stomp on pipe
+				nextfd++
+			}
 			_, _, err1 = RawSyscall(_SYS_dup, uintptr(fd[i]), uintptr(nextfd), 0)
 			if err1 != 0 {
 				goto childerror
@@ -257,9 +280,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 			RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
 			fd[i] = nextfd
 			nextfd++
-			if nextfd == pipe { // don't stomp on pipe
-				nextfd++
-			}
 		}
 	}
 
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index 6d31941..cb24c59 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -26,11 +26,14 @@ func isChrooted(t *testing.T) bool {
 	return root.Sys().(*syscall.Stat_t).Ino != 2
 }
 
-func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
+func checkUserNS(t *testing.T) {
 	if _, err := os.Stat("/proc/self/ns/user"); err != nil {
 		if os.IsNotExist(err) {
 			t.Skip("kernel doesn't support user namespaces")
 		}
+		if os.IsPermission(err) {
+			t.Skip("unable to test user namespaces due to permissions")
+		}
 		t.Fatalf("Failed to stat /proc/self/ns/user: %v", err)
 	}
 	if isChrooted(t) {
@@ -53,6 +56,10 @@ func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
 	if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
 		t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
 	}
+}
+
+func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
+	checkUserNS(t)
 	cmd := exec.Command("whoami")
 	cmd.SysProcAttr = &syscall.SysProcAttr{
 		Cloneflags: syscall.CLONE_NEWUSER,
@@ -122,3 +129,120 @@ func TestEmptyCredGroupsDisableSetgroups(t *testing.T) {
 		t.Fatal(err)
 	}
 }
+
+func TestUnshare(t *testing.T) {
+	// Make sure we are running as root so we have permissions to use unshare
+	// and create a network namespace.
+	if os.Getuid() != 0 {
+		t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
+	}
+
+	// When running under the Go continuous build, skip tests for
+	// now when under Kubernetes. (where things are root but not quite)
+	// Both of these are our own environment variables.
+	// See Issue 12815.
+	if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+		t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+	}
+
+	path := "/proc/net/dev"
+	if _, err := os.Stat(path); err != nil {
+		if os.IsNotExist(err) {
+			t.Skip("kernel doesn't support proc filesystem")
+		}
+		if os.IsPermission(err) {
+			t.Skip("unable to test proc filesystem due to permissions")
+		}
+		t.Fatal(err)
+	}
+	if _, err := os.Stat("/proc/self/ns/net"); err != nil {
+		if os.IsNotExist(err) {
+			t.Skip("kernel doesn't support net namespace")
+		}
+		t.Fatal(err)
+	}
+
+	cmd := exec.Command("cat", path)
+	cmd.SysProcAttr = &syscall.SysProcAttr{
+		Unshareflags: syscall.CLONE_NEWNET,
+	}
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+	}
+
+	// Check there is only the local network interface
+	sout := strings.TrimSpace(string(out))
+	if !strings.Contains(sout, "lo:") {
+		t.Fatalf("Expected lo network interface to exist, got %s", sout)
+	}
+
+	lines := strings.Split(sout, "\n")
+	if len(lines) != 3 {
+		t.Fatalf("Expected 3 lines of output, got %d", len(lines))
+	}
+}
+
+func TestGroupCleanup(t *testing.T) {
+	if os.Getuid() != 0 {
+		t.Skip("we need root for credential")
+	}
+	cmd := exec.Command("id")
+	cmd.SysProcAttr = &syscall.SysProcAttr{
+		Credential: &syscall.Credential{
+			Uid: 0,
+			Gid: 0,
+		},
+	}
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+	}
+	strOut := strings.TrimSpace(string(out))
+	expected := "uid=0(root) gid=0(root) groups=0(root)"
+	// Just check prefix because some distros reportedly output a
+	// context parameter; see https://golang.org/issue/16224.
+	if !strings.HasPrefix(strOut, expected) {
+		t.Errorf("id command output: %q, expected prefix: %q", strOut, expected)
+	}
+}
+
+func TestGroupCleanupUserNamespace(t *testing.T) {
+	if os.Getuid() != 0 {
+		t.Skip("we need root for credential")
+	}
+	checkUserNS(t)
+	cmd := exec.Command("id")
+	uid, gid := os.Getuid(), os.Getgid()
+	cmd.SysProcAttr = &syscall.SysProcAttr{
+		Cloneflags: syscall.CLONE_NEWUSER,
+		Credential: &syscall.Credential{
+			Uid: uint32(uid),
+			Gid: uint32(gid),
+		},
+		UidMappings: []syscall.SysProcIDMap{
+			{ContainerID: 0, HostID: uid, Size: 1},
+		},
+		GidMappings: []syscall.SysProcIDMap{
+			{ContainerID: 0, HostID: gid, Size: 1},
+		},
+	}
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+	}
+	strOut := strings.TrimSpace(string(out))
+
+	// Strings we've seen in the wild.
+	expected := []string{
+		"uid=0(root) gid=0(root) groups=0(root)",
+		"uid=0(root) gid=0(root) groups=0(root),65534(nobody)",
+		"uid=0(root) gid=0(root) groups=0(root),65534(nogroup)",
+	}
+	for _, e := range expected {
+		if strOut == e {
+			return
+		}
+	}
+	t.Errorf("id command output: %q, expected one of %q", strOut, expected)
+}
diff --git a/src/syscall/exec_plan9.go b/src/syscall/exec_plan9.go
index d342cb0..6551bcb 100644
--- a/src/syscall/exec_plan9.go
+++ b/src/syscall/exec_plan9.go
@@ -12,55 +12,44 @@ import (
 	"unsafe"
 )
 
-// Lock synchronizing creation of new file descriptors with fork.
-//
-// We want the child in a fork/exec sequence to inherit only the
-// file descriptors we intend.  To do that, we mark all file
-// descriptors close-on-exec and then, in the child, explicitly
-// unmark the ones we want the exec'ed program to keep.
-// Unix doesn't make this easy: there is, in general, no way to
-// allocate a new file descriptor close-on-exec.  Instead you
-// have to allocate the descriptor and then mark it close-on-exec.
-// If a fork happens between those two events, the child's exec
-// will inherit an unwanted file descriptor.
-//
-// This lock solves that race: the create new fd/mark close-on-exec
-// operation is done holding ForkLock for reading, and the fork itself
-// is done holding ForkLock for writing.  At least, that's the idea.
-// There are some complications.
-//
-// Some system calls that create new file descriptors can block
-// for arbitrarily long times: open on a hung NFS server or named
-// pipe, accept on a socket, and so on.  We can't reasonably grab
-// the lock across those operations.
-//
-// It is worse to inherit some file descriptors than others.
-// If a non-malicious child accidentally inherits an open ordinary file,
-// that's not a big deal.  On the other hand, if a long-lived child
-// accidentally inherits the write end of a pipe, then the reader
-// of that pipe will not see EOF until that child exits, potentially
-// causing the parent program to hang.  This is a common problem
-// in threaded C programs that use popen.
-//
-// Luckily, the file descriptors that are most important not to
-// inherit are not the ones that can take an arbitrarily long time
-// to create: pipe returns instantly, and the net package uses
-// non-blocking I/O to accept on a listening socket.
-// The rules for which file descriptor-creating operations use the
-// ForkLock are as follows:
-//
-// 1) Pipe.    Does not block.  Use the ForkLock.
-// 2) Socket.  Does not block.  Use the ForkLock.
-// 3) Accept.  If using non-blocking mode, use the ForkLock.
-//             Otherwise, live with the race.
-// 4) Open.    Can block.  Use O_CLOEXEC if available (Linux).
-//             Otherwise, live with the race.
-// 5) Dup.     Does not block.  Use the ForkLock.
-//             On Linux, could use fcntl F_DUPFD_CLOEXEC
-//             instead of the ForkLock, but only for dup(fd, -1).
-
+// ForkLock is not used on plan9.
 var ForkLock sync.RWMutex
 
+// gstringb reads a non-empty string from b, prefixed with a 16-bit length in little-endian order.
+// It returns the string as a byte slice, or nil if b is too short to contain the length or
+// the full string.
+//go:nosplit
+func gstringb(b []byte) []byte {
+	if len(b) < 2 {
+		return nil
+	}
+	n, b := gbit16(b)
+	if int(n) > len(b) {
+		return nil
+	}
+	return b[:n]
+}
+
+// Offset of the name field in a 9P directory entry - see UnmarshalDir() in dir_plan9.go
+const nameOffset = 39
+
+// gdirname returns the first filename from a buffer of directory entries,
+// and a slice containing the remaining directory entries.
+// If the buffer doesn't start with a valid directory entry, the returned name is nil.
+//go:nosplit
+func gdirname(buf []byte) (name []byte, rest []byte) {
+	if len(buf) < 2 {
+		return
+	}
+	size, buf := gbit16(buf)
+	if size < STATFIXLEN || int(size) > len(buf) {
+		return
+	}
+	name = gstringb(buf[nameOffset:size])
+	rest = buf[size:]
+	return
+}
+
 // 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.
@@ -104,64 +93,20 @@ func readdirnames(dirfd int) (names []string, err error) {
 		if n == 0 {
 			break
 		}
-		for i := 0; i < n; {
-			m, _ := gbit16(buf[i:])
-			m += 2
-
-			if m < STATFIXLEN {
+		for b := buf[:n]; len(b) > 0; {
+			var s []byte
+			s, b = gdirname(b)
+			if s == nil {
 				return nil, ErrBadStat
 			}
-
-			s, _, ok := gstring(buf[i+41:])
-			if !ok {
-				return nil, ErrBadStat
-			}
-			names = append(names, s)
-			i += int(m)
-		}
-	}
-	return
-}
-
-// readdupdevice returns a list of currently opened fds (excluding stdin, stdout, stderr) from the dup device #d.
-// ForkLock should be write locked before calling, so that no new fds would be created while the fd list is being read.
-func readdupdevice() (fds []int, err error) {
-	dupdevfd, err := Open("#d", O_RDONLY)
-	if err != nil {
-		return
-	}
-	defer Close(dupdevfd)
-
-	names, err := readdirnames(dupdevfd)
-	if err != nil {
-		return
-	}
-
-	fds = make([]int, 0, len(names)/2)
-	for _, name := range names {
-		if n := len(name); n > 3 && name[n-3:n] == "ctl" {
-			continue
-		}
-		fd := int(atoi([]byte(name)))
-		switch fd {
-		case 0, 1, 2, dupdevfd:
-			continue
+			names = append(names, string(s))
 		}
-		fds = append(fds, fd)
 	}
 	return
 }
 
-var startupFds []int
-
-// Plan 9 does not allow clearing the OCEXEC flag
-// from the underlying channel backing an open file descriptor,
-// therefore we store a list of already opened file descriptors
-// inside startupFds and skip them when manually closing descriptors
-// not meant to be passed to a child exec.
-func init() {
-	startupFds, _ = readdupdevice()
-}
+// name of the directory containing names and control files for all open file descriptors
+var dupdev, _ = BytePtrFromString("#d")
 
 // forkAndExecInChild forks the process, calling dup onto 0..len(fd)
 // and finally invoking exec(argv0, argvv, envv) in the child.
@@ -169,12 +114,12 @@ func init() {
 // (The pipe write end is close-on-exec so if exec succeeds, it will be closed.)
 //
 // In the child, this function must not acquire any locks, because
-// they might have been locked at the time of the fork.  This means
+// they might have been locked at the time of the fork. This means
 // no rescheduling, no malloc calls, and no new stack segments.
 // The calls to RawSyscall are okay because they are assembly
 // functions that do not grow the stack.
 //go:norace
-func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, pipe int, rflag int) (pid int, err error) {
+func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, pipe int, rflag int) (pid int, err error) {
 	// Declare all variables at top in case any
 	// declarations require heap allocation (e.g., errbuf).
 	var (
@@ -184,6 +129,8 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at
 		clearenv int
 		envfd    int
 		errbuf   [ERRMAX]byte
+		statbuf  [STATMAX]byte
+		dupdevfd int
 	)
 
 	// Guard against side effects of shuffling fds below.
@@ -218,12 +165,39 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at
 	// Fork succeeded, now in child.
 
 	// Close fds we don't need.
-	for i = 0; i < len(fdsToClose); i++ {
-		RawSyscall(SYS_CLOSE, uintptr(fdsToClose[i]), 0, 0)
+	r1, _, _ = RawSyscall(SYS_OPEN, uintptr(unsafe.Pointer(dupdev)), uintptr(O_RDONLY), 0)
+	dupdevfd = int(r1)
+	if dupdevfd == -1 {
+		goto childerror
+	}
+dirloop:
+	for {
+		r1, _, _ = RawSyscall6(SYS_PREAD, uintptr(dupdevfd), uintptr(unsafe.Pointer(&statbuf[0])), uintptr(len(statbuf)), ^uintptr(0), ^uintptr(0), 0)
+		n := int(r1)
+		switch n {
+		case -1:
+			goto childerror
+		case 0:
+			break dirloop
+		}
+		for b := statbuf[:n]; len(b) > 0; {
+			var s []byte
+			s, b = gdirname(b)
+			if s == nil {
+				copy(errbuf[:], ErrBadStat.Error())
+				goto childerror1
+			}
+			if s[len(s)-1] == 'l' {
+				// control file for descriptor <N> is named <N>ctl
+				continue
+			}
+			closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd)
+		}
 	}
+	RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0)
 
+	// Write new environment variables.
 	if envv != nil {
-		// Write new environment variables.
 		for i = 0; i < len(envv); i++ {
 			r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666))
 
@@ -268,6 +242,9 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at
 	}
 	for i = 0; i < len(fd); i++ {
 		if fd[i] >= 0 && fd[i] < int(i) {
+			if nextfd == pipe { // don't stomp on pipe
+				nextfd++
+			}
 			r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(nextfd), 0)
 			if int32(r1) == -1 {
 				goto childerror
@@ -275,9 +252,6 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at
 
 			fd[i] = nextfd
 			nextfd++
-			if nextfd == pipe { // don't stomp on pipe
-				nextfd++
-			}
 		}
 	}
 
@@ -311,6 +285,7 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at
 childerror:
 	// send error string on pipe
 	RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0)
+childerror1:
 	errbuf[len(errbuf)-1] = 0
 	i = 0
 	for i < len(errbuf) && errbuf[i] != 0 {
@@ -330,6 +305,20 @@ childerror:
 	panic("unreached")
 }
 
+// close the numbered file descriptor, unless it is fd1, fd2, or a member of fds.
+//go:nosplit
+func closeFdExcept(n int, fd1 int, fd2 int, fds []int) {
+	if n == fd1 || n == fd2 {
+		return
+	}
+	for _, fd := range fds {
+		if n == fd {
+			return
+		}
+	}
+	RawSyscall(SYS_CLOSE, uintptr(n), 0, 0)
+}
+
 func cexecPipe(p []int) error {
 	e := Pipe(p)
 	if e != nil {
@@ -428,62 +417,23 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
 		}
 	}
 
-	// Acquire the fork lock to prevent other threads from creating new fds before we fork.
-	ForkLock.Lock()
-
-	// get a list of open fds, excluding stdin,stdout and stderr that need to be closed in the child.
-	// no new fds can be created while we hold the ForkLock for writing.
-	openFds, e := readdupdevice()
-	if e != nil {
-		ForkLock.Unlock()
-		return 0, e
-	}
-
-	fdsToClose := make([]int, 0, len(openFds))
-	for _, fd := range openFds {
-		doClose := true
-
-		// exclude files opened at startup.
-		for _, sfd := range startupFds {
-			if fd == sfd {
-				doClose = false
-				break
-			}
-		}
-
-		// exclude files explicitly requested by the caller.
-		for _, rfd := range attr.Files {
-			if fd == int(rfd) {
-				doClose = false
-				break
-			}
-		}
-
-		if doClose {
-			fdsToClose = append(fdsToClose, fd)
-		}
-	}
-
 	// Allocate child status pipe close on exec.
-	e = cexecPipe(p[:])
+	e := cexecPipe(p[:])
 
 	if e != nil {
 		return 0, e
 	}
-	fdsToClose = append(fdsToClose, p[0])
 
 	// Kick off child.
-	pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, fdsToClose, p[1], sys.Rfork)
+	pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, p[1], sys.Rfork)
 
 	if err != nil {
 		if p[0] >= 0 {
 			Close(p[0])
 			Close(p[1])
 		}
-		ForkLock.Unlock()
 		return 0, err
 	}
-	ForkLock.Unlock()
 
 	// Read child error status from pipe.
 	Close(p[1])
@@ -491,8 +441,10 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
 	Close(p[0])
 
 	if err != nil || n != 0 {
-		if n != 0 {
+		if n > 0 {
 			err = NewError(string(errbuf[:n]))
+		} else if err == nil {
+			err = NewError("failed to read exec status")
 		}
 
 		// Child failed; wait for it to exit, to make sure
diff --git a/src/syscall/exec_solaris.go b/src/syscall/exec_solaris.go
index 63fa848..fcb481c 100644
--- a/src/syscall/exec_solaris.go
+++ b/src/syscall/exec_solaris.go
@@ -44,7 +44,7 @@ func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno)
 // If a dup or exec fails, write the errno error to pipe.
 // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
 // In the child, this function must not acquire any locks, because
-// they might have been locked at the time of the fork.  This means
+// they might have been locked at the time of the fork. This means
 // no rescheduling, no malloc calls, and no new stack segments.
 //
 // We call hand-crafted syscalls, implemented in
@@ -178,6 +178,9 @@ 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) {
+			if nextfd == pipe { // don't stomp on pipe
+				nextfd++
+			}
 			_, err1 = fcntl1(uintptr(fd[i]), F_DUP2FD, uintptr(nextfd))
 			if err1 != 0 {
 				goto childerror
@@ -185,9 +188,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 			fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC)
 			fd[i] = nextfd
 			nextfd++
-			if nextfd == pipe { // don't stomp on pipe
-				nextfd++
-			}
 		}
 	}
 
diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go
index 565252c..9fd8cf4 100644
--- a/src/syscall/exec_unix.go
+++ b/src/syscall/exec_unix.go
@@ -17,31 +17,31 @@ import (
 // Lock synchronizing creation of new file descriptors with fork.
 //
 // We want the child in a fork/exec sequence to inherit only the
-// file descriptors we intend.  To do that, we mark all file
+// file descriptors we intend. To do that, we mark all file
 // descriptors close-on-exec and then, in the child, explicitly
 // unmark the ones we want the exec'ed program to keep.
 // Unix doesn't make this easy: there is, in general, no way to
-// allocate a new file descriptor close-on-exec.  Instead you
+// allocate a new file descriptor close-on-exec. Instead you
 // have to allocate the descriptor and then mark it close-on-exec.
 // If a fork happens between those two events, the child's exec
 // will inherit an unwanted file descriptor.
 //
 // This lock solves that race: the create new fd/mark close-on-exec
 // operation is done holding ForkLock for reading, and the fork itself
-// is done holding ForkLock for writing.  At least, that's the idea.
+// is done holding ForkLock for writing. At least, that's the idea.
 // There are some complications.
 //
 // Some system calls that create new file descriptors can block
 // for arbitrarily long times: open on a hung NFS server or named
-// pipe, accept on a socket, and so on.  We can't reasonably grab
+// pipe, accept on a socket, and so on. We can't reasonably grab
 // the lock across those operations.
 //
 // It is worse to inherit some file descriptors than others.
 // If a non-malicious child accidentally inherits an open ordinary file,
-// that's not a big deal.  On the other hand, if a long-lived child
+// that's not a big deal. On the other hand, if a long-lived child
 // accidentally inherits the write end of a pipe, then the reader
 // of that pipe will not see EOF until that child exits, potentially
-// causing the parent program to hang.  This is a common problem
+// causing the parent program to hang. This is a common problem
 // in threaded C programs that use popen.
 //
 // Luckily, the file descriptors that are most important not to
@@ -51,13 +51,13 @@ import (
 // The rules for which file descriptor-creating operations use the
 // ForkLock are as follows:
 //
-// 1) Pipe.    Does not block.  Use the ForkLock.
-// 2) Socket.  Does not block.  Use the ForkLock.
-// 3) Accept.  If using non-blocking mode, use the ForkLock.
+// 1) Pipe. Does not block. Use the ForkLock.
+// 2) Socket. Does not block. Use the ForkLock.
+// 3) Accept. If using non-blocking mode, use the ForkLock.
 //             Otherwise, live with the race.
-// 4) Open.    Can block.  Use O_CLOEXEC if available (Linux).
+// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
 //             Otherwise, live with the race.
-// 5) Dup.     Does not block.  Use the ForkLock.
+// 5) Dup. Does not block. Use the ForkLock.
 //             On Linux, could use fcntl F_DUPFD_CLOEXEC
 //             instead of the ForkLock, but only for dup(fd, -1).
 
@@ -103,7 +103,7 @@ func SetNonblock(fd int, nonblocking bool) (err error) {
 	if nonblocking {
 		flag |= O_NONBLOCK
 	} else {
-		flag &= ^O_NONBLOCK
+		flag &^= O_NONBLOCK
 	}
 	_, err = fcntl(fd, F_SETFL, flag)
 	return err
diff --git a/src/syscall/export_test.go b/src/syscall/export_test.go
index c977462..55c09e6 100644
--- a/src/syscall/export_test.go
+++ b/src/syscall/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/syscall/fd_nacl.go b/src/syscall/fd_nacl.go
index 7432414..e559793 100644
--- a/src/syscall/fd_nacl.go
+++ b/src/syscall/fd_nacl.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -10,6 +10,7 @@
 package syscall
 
 import (
+	"io"
 	"sync"
 )
 
@@ -252,15 +253,15 @@ func (f *naclFile) seek(off int64, whence int) (int64, error) {
 
 func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) {
 	// NaCl has no pread; simulate with seek and hope for no races.
-	old, err := f.seek(0, 1)
+	old, err := f.seek(0, io.SeekCurrent)
 	if err != nil {
 		return 0, err
 	}
-	if _, err := f.seek(offset, 0); err != nil {
+	if _, err := f.seek(offset, io.SeekStart); err != nil {
 		return 0, err
 	}
 	n, err := rw(b)
-	f.seek(old, 0)
+	f.seek(old, io.SeekStart)
 	return n, err
 }
 
diff --git a/src/syscall/fs_nacl.go b/src/syscall/fs_nacl.go
index 711809f..cbd9539 100644
--- a/src/syscall/fs_nacl.go
+++ b/src/syscall/fs_nacl.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -15,6 +15,7 @@
 package syscall
 
 import (
+	"io"
 	"sync"
 	"unsafe"
 )
@@ -367,9 +368,9 @@ func (f *fsysFile) seek(offset int64, whence int) (int64, error) {
 	f.fsys.mu.Lock()
 	defer f.fsys.mu.Unlock()
 	switch whence {
-	case 1:
+	case io.SeekCurrent:
 		offset += f.offset
-	case 2:
+	case io.SeekEnd:
 		offset += f.inode.Size
 	}
 	if offset < 0 {
diff --git a/src/syscall/lsf_linux.go b/src/syscall/lsf_linux.go
index ee07fea..b89239e 100644
--- a/src/syscall/lsf_linux.go
+++ b/src/syscall/lsf_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -10,14 +10,17 @@ import (
 	"unsafe"
 )
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func LsfStmt(code, k int) *SockFilter {
 	return &SockFilter{Code: uint16(code), K: uint32(k)}
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func LsfJump(code, k, jt, jf int) *SockFilter {
 	return &SockFilter{Code: uint16(code), Jt: uint8(jt), Jf: uint8(jf), K: uint32(k)}
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func LsfSocket(ifindex, proto int) (int, error) {
 	var lsall SockaddrLinklayer
 	s, e := Socket(AF_PACKET, SOCK_RAW, proto)
@@ -41,6 +44,7 @@ type iflags struct {
 	flags uint16
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func SetLsfPromisc(name string, m bool) error {
 	s, e := Socket(AF_INET, SOCK_DGRAM, 0)
 	if e != nil {
@@ -56,7 +60,7 @@ func SetLsfPromisc(name string, m bool) error {
 	if m {
 		ifl.flags |= uint16(IFF_PROMISC)
 	} else {
-		ifl.flags &= ^uint16(IFF_PROMISC)
+		ifl.flags &^= uint16(IFF_PROMISC)
 	}
 	_, _, ep = Syscall(SYS_IOCTL, uintptr(s), SIOCSIFFLAGS, uintptr(unsafe.Pointer(&ifl)))
 	if ep != 0 {
@@ -65,6 +69,7 @@ func SetLsfPromisc(name string, m bool) error {
 	return nil
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func AttachLsf(fd int, i []SockFilter) error {
 	var p SockFprog
 	p.Len = uint16(len(i))
@@ -72,6 +77,7 @@ func AttachLsf(fd int, i []SockFilter) error {
 	return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, unsafe.Pointer(&p), unsafe.Sizeof(p))
 }
 
+// Deprecated: Use golang.org/x/net/bpf instead.
 func DetachLsf(fd int) error {
 	var dummy int
 	return setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, unsafe.Pointer(&dummy), unsafe.Sizeof(dummy))
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index 85fab4f..6a9aacb 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -156,8 +156,8 @@ freebsd_arm)
 	mkerrors="$mkerrors"
 	mksyscall="./mksyscall.pl -l32 -arm"
 	mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
-	# Let the type of C char be singed for making the bare syscall
-	# API consistent across over platforms.
+	# Let the type of C char be signed to make the bare syscall
+	# API consistent between platforms.
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
 	;;
 linux_386)
@@ -189,8 +189,8 @@ linux_arm64)
 		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.
+	# Let the type of C char be signed to make the bare syscall
+	# API consistent between platforms.
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
 	;;
 linux_ppc64)
@@ -207,6 +207,13 @@ linux_ppc64le)
 	mksysnum="./mksysnum_linux.pl $unistd_h"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
+linux_s390x)
+	GOOSARCH_in=syscall_linux_s390x.go
+	unistd_h=/usr/include/asm/unistd.h
+	mkerrors="$mkerrors -m64"
+	mksysnum="./mksysnum_linux.pl $unistd_h"
+	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+	;;
 nacl_386)
 	mkerrors=""
 	mksyscall="./mksyscall.pl -l32 -nacl"
@@ -288,5 +295,5 @@ 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
+	if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |go run mkpost.go >ztypes_$GOOSARCH.go"; fi
 ) | $run
diff --git a/src/syscall/mkpost.go b/src/syscall/mkpost.go
new file mode 100644
index 0000000..26aeec8
--- /dev/null
+++ b/src/syscall/mkpost.go
@@ -0,0 +1,63 @@
+// Copyright 2016 The Go 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
+
+// mkpost processes the output of cgo -godefs to
+// modify the generated types. It is used to clean up
+// the syscall API in an architecture specific manner.
+//
+// mkpost is run after cgo -godefs by mkall.sh.
+package main
+
+import (
+	"fmt"
+	"go/format"
+	"io/ioutil"
+	"log"
+	"os"
+	"regexp"
+)
+
+func main() {
+	b, err := ioutil.ReadAll(os.Stdin)
+	if err != nil {
+		log.Fatal(err)
+	}
+	s := string(b)
+
+	goarch := os.Getenv("GOARCH")
+	goos := os.Getenv("GOOS")
+	if goarch == "s390x" && goos == "linux" {
+		// Export the types of PtraceRegs fields.
+		re := regexp.MustCompile("ptrace(Psw|Fpregs|Per)")
+		s = re.ReplaceAllString(s, "Ptrace$1")
+
+		// Replace padding fields inserted by cgo with blank identifiers.
+		re = regexp.MustCompile("Pad_cgo[A-Za-z0-9_]*")
+		s = re.ReplaceAllString(s, "_")
+
+		// Replace other unwanted fields with blank identifiers.
+		re = regexp.MustCompile("X_[A-Za-z0-9_]*")
+		s = re.ReplaceAllString(s, "_")
+
+		// Force the type of RawSockaddr.Data to [14]int8 to match
+		// the existing gccgo API.
+		re = regexp.MustCompile("(Data\\s+\\[14\\])uint8")
+		s = re.ReplaceAllString(s, "${1}int8")
+	}
+
+	// gofmt
+	b, err = format.Source([]byte(s))
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Append this command to the header to show where the new file
+	// came from.
+	re := regexp.MustCompile("(cgo -godefs [a-zA-Z0-9_]+\\.go.*)")
+	s = re.ReplaceAllString(string(b), "$1 | go run mkpost.go")
+
+	fmt.Print(s)
+}
diff --git a/src/syscall/mksyscall.pl b/src/syscall/mksyscall.pl
index 96437fe..6ee7c3c 100755
--- a/src/syscall/mksyscall.pl
+++ b/src/syscall/mksyscall.pl
@@ -100,7 +100,7 @@ while(<>) {
 	# Line must be of the form
 	#	func Open(path string, mode int, perm int) (fd int, errno error)
 	# Split into name, in params, out params.
-	if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
+	if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)_?SYS_[A-Z0-9_]+))?$/) {
 		print STDERR "$ARGV:$.: malformed //sys declaration\n";
 		$errors = 1;
 		next;
diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go
index 7786d13..1e0d940 100644
--- a/src/syscall/mksyscall_windows.go
+++ b/src/syscall/mksyscall_windows.go
@@ -57,6 +57,8 @@ import (
 	"io/ioutil"
 	"log"
 	"os"
+	"path/filepath"
+	"runtime"
 	"sort"
 	"strconv"
 	"strings"
@@ -66,8 +68,7 @@ import (
 var (
 	filename       = flag.String("output", "", "output file name (standard output if omitted)")
 	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
-	systemDLL      = flag.Bool("systemdll", false, "whether all DLLs should be loaded from the Windows system directory")
-	sysRepo        = flag.Bool("xsys", false, "whether this code is for the x/sys subrepo")
+	systemDLL      = flag.Bool("systemdll", true, "whether all DLLs should be loaded from the Windows system directory")
 )
 
 func trim(s string) string {
@@ -596,14 +597,20 @@ func (f *Fn) HelperName() string {
 
 // Source files and functions.
 type Source struct {
-	Funcs   []*Fn
-	Files   []string
-	Imports []string
+	Funcs           []*Fn
+	Files           []string
+	StdLibImports   []string
+	ExternalImports []string
 }
 
 func (src *Source) Import(pkg string) {
-	src.Imports = append(src.Imports, pkg)
-	sort.Strings(src.Imports)
+	src.StdLibImports = append(src.StdLibImports, pkg)
+	sort.Strings(src.StdLibImports)
+}
+
+func (src *Source) ExternalImport(pkg string) {
+	src.ExternalImports = append(src.ExternalImports, pkg)
+	sort.Strings(src.ExternalImports)
 }
 
 // ParseFiles parses files listed in fs and extracts all syscall
@@ -613,12 +620,10 @@ func ParseFiles(fs []string) (*Source, error) {
 	src := &Source{
 		Funcs: make([]*Fn, 0),
 		Files: make([]string, 0),
-		Imports: []string{
+		StdLibImports: []string{
 			"unsafe",
 		},
-	}
-	if *systemDLL {
-		src.Import("internal/syscall/windows/sysdll")
+		ExternalImports: make([]string, 0),
 	}
 	for _, file := range fs {
 		if err := src.ParseFile(file); err != nil {
@@ -689,10 +694,52 @@ func (src *Source) ParseFile(path string) error {
 	return nil
 }
 
+// IsStdRepo returns true if src is part of standard library.
+func (src *Source) IsStdRepo() (bool, error) {
+	if len(src.Files) == 0 {
+		return false, errors.New("no input files provided")
+	}
+	abspath, err := filepath.Abs(src.Files[0])
+	if err != nil {
+		return false, err
+	}
+	goroot := runtime.GOROOT()
+	if runtime.GOOS == "windows" {
+		abspath = strings.ToLower(abspath)
+		goroot = strings.ToLower(goroot)
+	}
+	return strings.HasPrefix(abspath, goroot), nil
+}
+
 // Generate output source file from a source set src.
 func (src *Source) Generate(w io.Writer) error {
-	if *sysRepo && packageName != "windows" {
-		src.Import("golang.org/x/sys/windows")
+	const (
+		pkgStd         = iota // any package in std library
+		pkgXSysWindows        // x/sys/windows package
+		pkgOther
+	)
+	isStdRepo, err := src.IsStdRepo()
+	if err != nil {
+		return err
+	}
+	var pkgtype int
+	switch {
+	case isStdRepo:
+		pkgtype = pkgStd
+	case packageName == "windows":
+		// TODO: this needs better logic than just using package name
+		pkgtype = pkgXSysWindows
+	default:
+		pkgtype = pkgOther
+	}
+	if *systemDLL {
+		switch pkgtype {
+		case pkgStd:
+			src.Import("internal/syscall/windows/sysdll")
+		case pkgXSysWindows:
+		default:
+			src.ExternalImport("golang.org/x/sys/windows")
+		}
 	}
 	if packageName != "syscall" {
 		src.Import("syscall")
@@ -702,22 +749,21 @@ func (src *Source) Generate(w io.Writer) error {
 		"syscalldot":  syscalldot,
 		"newlazydll": func(dll string) string {
 			arg := "\"" + dll + ".dll\""
-			if *systemDLL {
-				arg = "sysdll.Add(" + arg + ")"
-			}
-			if *sysRepo {
-				if packageName == "windows" {
-					return "&LazyDLL{Name: " + arg + ", System: true}"
-				} else {
-					return "&windows.LazyDLL{Name: " + arg + ", System: true}"
-				}
-			} else {
+			if !*systemDLL {
 				return syscalldot() + "NewLazyDLL(" + arg + ")"
 			}
+			switch pkgtype {
+			case pkgStd:
+				return syscalldot() + "NewLazyDLL(sysdll.Add(" + arg + "))"
+			case pkgXSysWindows:
+				return "NewLazySystemDLL(" + arg + ")"
+			default:
+				return "windows.NewLazySystemDLL(" + arg + ")"
+			}
 		},
 	}
 	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
-	err := t.Execute(w, src)
+	err = t.Execute(w, src)
 	if err != nil {
 		return errors.New("Failed to execute template: " + err.Error())
 	}
@@ -770,7 +816,10 @@ const srcTemplate = `
 package {{packagename}}
 
 import (
-{{range .Imports}}"{{.}}"
+{{range .StdLibImports}}"{{.}}"
+{{end}}
+
+{{range .ExternalImports}}"{{.}}"
 {{end}}
 )
 
diff --git a/src/syscall/msan.go b/src/syscall/msan.go
index edd8d1e..baaad6d 100644
--- a/src/syscall/msan.go
+++ b/src/syscall/msan.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/syscall/msan0.go b/src/syscall/msan0.go
index 7617494..ff10be9 100644
--- a/src/syscall/msan0.go
+++ b/src/syscall/msan0.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/src/syscall/net_nacl.go b/src/syscall/net_nacl.go
index d3378f9..1a0122c 100644
--- a/src/syscall/net_nacl.go
+++ b/src/syscall/net_nacl.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/syscall/netlink_linux.go b/src/syscall/netlink_linux.go
index 1b73dce..26b3040 100644
--- a/src/syscall/netlink_linux.go
+++ b/src/syscall/netlink_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/syscall/route_bsd.go b/src/syscall/route_bsd.go
index c635a13..b364eea 100644
--- a/src/syscall/route_bsd.go
+++ b/src/syscall/route_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -138,7 +138,7 @@ func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) {
 	//
 	// - The kernel form appends leading bytes to the prefix field
 	//   to make the <length, prefix> tuple to be conformed with
-	//   the routing messeage boundary
+	//   the routing message boundary
 	l := int(rsaAlignOf(int(b[0])))
 	if len(b) < l {
 		return nil, EINVAL
@@ -176,6 +176,8 @@ func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) {
 // RouteRIB returns routing information base, as known as RIB,
 // which consists of network facility information, states and
 // parameters.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 func RouteRIB(facility, param int) ([]byte, error) {
 	mib := []_C_int{CTL_NET, AF_ROUTE, 0, 0, _C_int(facility), _C_int(param)}
 	// Find size.
@@ -194,6 +196,8 @@ func RouteRIB(facility, param int) ([]byte, error) {
 }
 
 // RoutingMessage represents a routing message.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type RoutingMessage interface {
 	sockaddr() ([]Sockaddr, error)
 }
@@ -208,6 +212,8 @@ type anyMessage struct {
 
 // RouteMessage represents a routing message containing routing
 // entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type RouteMessage struct {
 	Header RtMsghdr
 	Data   []byte
@@ -252,6 +258,8 @@ func (m *RouteMessage) sockaddr() ([]Sockaddr, error) {
 
 // InterfaceMessage represents a routing message containing
 // network interface entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type InterfaceMessage struct {
 	Header IfMsghdr
 	Data   []byte
@@ -272,6 +280,8 @@ func (m *InterfaceMessage) sockaddr() ([]Sockaddr, error) {
 
 // InterfaceAddrMessage represents a routing message containing
 // network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type InterfaceAddrMessage struct {
 	Header IfaMsghdr
 	Data   []byte
@@ -316,6 +326,8 @@ func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) {
 
 // ParseRoutingMessage parses b as routing messages and returns the
 // slice containing the RoutingMessage interfaces.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
 	nmsgs, nskips := 0, 0
 	for len(b) >= anyMessageLen {
@@ -341,6 +353,8 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
 
 // ParseRoutingSockaddr parses msg's payload as raw sockaddrs and
 // returns the slice containing the Sockaddr interfaces.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) {
 	sas, err := msg.sockaddr()
 	if err != nil {
diff --git a/src/syscall/route_bsd_test.go b/src/syscall/route_bsd_test.go
deleted file mode 100644
index 74d11f9..0000000
--- a/src/syscall/route_bsd_test.go
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2015 The Go 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
-}
-
-var parseInterfaceMessageTests = []*syscall.InterfaceMessage{
-	// with link-layer address
-	{
-		Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
-		Data: []uint8{
-			0x11, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0,
-			0x77, 0x6d, 0x31, 0x01, 0x23, 0x45, 0xab, 0xcd,
-			0xef, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
-		},
-	},
-	// without link-layer address
-	{
-		Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
-		Data: []uint8{
-			0xe, 0x12, 0x4, 0x0, 0xf5, 0x6, 0x0, 0x0,
-			0x70, 0x66, 0x6c, 0x6f, 0x67, 0x30, 0x0, 0x0,
-		},
-	},
-	// no data
-	{
-		Header: syscall.IfMsghdr{Version: syscall.RTM_VERSION, Addrs: syscall.RTA_IFP},
-		Data: []uint8{
-			0x8, 0xa, 0xb, 0xc, 0xd, 0x0, 0x0, 0x0,
-		},
-	},
-}
-
-func TestParseInterfaceMessage(t *testing.T) {
-	for i, tt := range parseInterfaceMessageTests {
-		if _, err := syscall.ParseRoutingSockaddr(tt); err != nil {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-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 89bca12..b0636ed 100644
--- a/src/syscall/route_darwin.go
+++ b/src/syscall/route_darwin.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -26,6 +26,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 
 // InterfaceMulticastAddrMessage represents a routing message
 // containing network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type InterfaceMulticastAddrMessage struct {
 	Header IfmaMsghdr2
 	Data   []byte
diff --git a/src/syscall/route_dragonfly.go b/src/syscall/route_dragonfly.go
index 5226f7f..b562400 100644
--- a/src/syscall/route_dragonfly.go
+++ b/src/syscall/route_dragonfly.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -31,6 +31,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 
 // InterfaceAnnounceMessage represents a routing message containing
 // network interface arrival and departure information.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
@@ -39,6 +41,8 @@ func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil,
 
 // InterfaceMulticastAddrMessage represents a routing message
 // containing network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type InterfaceMulticastAddrMessage struct {
 	Header IfmaMsghdr
 	Data   []byte
diff --git a/src/syscall/route_freebsd.go b/src/syscall/route_freebsd.go
index 0e18103..2c2de74 100644
--- a/src/syscall/route_freebsd.go
+++ b/src/syscall/route_freebsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -53,6 +53,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 
 // InterfaceAnnounceMessage represents a routing message containing
 // network interface arrival and departure information.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
@@ -61,6 +63,8 @@ func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil,
 
 // InterfaceMulticastAddrMessage represents a routing message
 // containing network interface address entries.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type InterfaceMulticastAddrMessage struct {
 	Header IfmaMsghdr
 	Data   []byte
diff --git a/src/syscall/route_ifma_test.go b/src/syscall/route_ifma_test.go
deleted file mode 100644
index af2b67d..0000000
--- a/src/syscall/route_ifma_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2015 The Go 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 d605ffa..a10c8b6 100644
--- a/src/syscall/route_netbsd.go
+++ b/src/syscall/route_netbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -28,6 +28,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 
 // InterfaceAnnounceMessage represents a routing message containing
 // network interface arrival and departure information.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
diff --git a/src/syscall/route_noifma_test.go b/src/syscall/route_noifma_test.go
deleted file mode 100644
index 19d5d8e..0000000
--- a/src/syscall/route_noifma_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2015 The Go 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 7804a08..fe173ad 100644
--- a/src/syscall/route_openbsd.go
+++ b/src/syscall/route_openbsd.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -28,6 +28,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 
 // InterfaceAnnounceMessage represents a routing message containing
 // network interface arrival and departure information.
+//
+// Deprecated: Use golang.org/x/net/route instead.
 type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go
index 1625b07..e2a9dc5 100644
--- a/src/syscall/security_windows.go
+++ b/src/syscall/security_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/syscall/sockcmsg_linux.go b/src/syscall/sockcmsg_linux.go
index a2e26a1..5a56b25 100644
--- a/src/syscall/sockcmsg_linux.go
+++ b/src/syscall/sockcmsg_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/syscall/sockcmsg_unix.go b/src/syscall/sockcmsg_unix.go
index 4724275..bc4caf5 100644
--- a/src/syscall/sockcmsg_unix.go
+++ b/src/syscall/sockcmsg_unix.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -62,7 +62,7 @@ func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
 
 func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
 	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
-	if h.Len < SizeofCmsghdr || int(h.Len) > len(b) {
+	if h.Len < SizeofCmsghdr || uint64(h.Len) > uint64(len(b)) {
 		return nil, nil, EINVAL
 	}
 	return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil
diff --git a/src/syscall/syscall.go b/src/syscall/syscall.go
index 769e6b9..bb102c6 100644
--- a/src/syscall/syscall.go
+++ b/src/syscall/syscall.go
@@ -3,10 +3,10 @@
 // license that can be found in the LICENSE file.
 
 // Package syscall contains an interface to the low-level operating system
-// primitives.  The details vary depending on the underlying system, and
+// primitives. The details vary depending on the underlying system, and
 // by default, godoc will display the syscall documentation for the current
-// system.  If you want godoc to display syscall documentation for another
-// system, set $GOOS and $GOARCH to the desired system.  For example, if
+// system. If you want godoc to display syscall documentation for another
+// system, set $GOOS and $GOARCH to the desired system. For example, if
 // you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
 // to freebsd and $GOARCH to arm.
 // The primary use of syscall is inside other packages that provide a more
diff --git a/src/syscall/syscall_bsd.go b/src/syscall/syscall_bsd.go
index af56391..9370dd4 100644
--- a/src/syscall/syscall_bsd.go
+++ b/src/syscall/syscall_bsd.go
@@ -33,7 +33,7 @@ func Getgroups() (gids []int, err error) {
 		return nil, nil
 	}
 
-	// Sanity check group count.  Max is 16 on BSD.
+	// Sanity check group count. Max is 16 on BSD.
 	if n < 0 || n > 1000 {
 		return nil, EINVAL
 	}
diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go
index 52fd4e7..380be70 100644
--- a/src/syscall/syscall_darwin.go
+++ b/src/syscall/syscall_darwin.go
@@ -53,7 +53,7 @@ func nametomib(name string) (mib []_C_int, err error) {
 
 	// NOTE(rsc): It seems strange to set the buffer to have
 	// size CTL_MAXNAME+2 but use only CTL_MAXNAME
-	// as the size.  I don't know why the +2 is here, but the
+	// as the size. I don't know why the +2 is here, but the
 	// kernel uses +2 for its own implementation of this function.
 	// I am scared that if we don't include the +2 here, the kernel
 	// will silently write 2 words farther than we specify
@@ -76,7 +76,7 @@ func nametomib(name string) (mib []_C_int, err error) {
 }
 
 // ParseDirent parses up to max directory entries in buf,
-// appending the names to names.  It returns the number
+// appending the names to names. It returns the number
 // bytes consumed from buf, the number of entries added
 // to names, and the new names slice.
 func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
@@ -196,6 +196,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 		bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
 	}
 	r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags))
+	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
diff --git a/src/syscall/syscall_darwin_386.go b/src/syscall/syscall_darwin_386.go
index 2074e7a..7dbb1c3 100644
--- a/src/syscall/syscall_darwin_386.go
+++ b/src/syscall/syscall_darwin_386.go
@@ -28,7 +28,7 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 //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
+	// but is otherwise unused. The answers come back
 	// in the two registers.
 	sec, usec, err := gettimeofday(tv)
 	tv.Sec = int32(sec)
diff --git a/src/syscall/syscall_darwin_amd64.go b/src/syscall/syscall_darwin_amd64.go
index 70b53b8..80e6024 100644
--- a/src/syscall/syscall_darwin_amd64.go
+++ b/src/syscall/syscall_darwin_amd64.go
@@ -28,7 +28,7 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 //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
+	// but is otherwise unused. The answers come back
 	// in the two registers.
 	sec, usec, err := gettimeofday(tv)
 	tv.Sec = sec
diff --git a/src/syscall/syscall_darwin_arm.go b/src/syscall/syscall_darwin_arm.go
index 2a7d4f2..c302d83 100644
--- a/src/syscall/syscall_darwin_arm.go
+++ b/src/syscall/syscall_darwin_arm.go
@@ -28,7 +28,7 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 //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
+	// but is otherwise unused. The answers come back
 	// in the two registers.
 	sec, usec, err := gettimeofday(tv)
 	tv.Sec = int32(sec)
diff --git a/src/syscall/syscall_darwin_arm64.go b/src/syscall/syscall_darwin_arm64.go
index de7a08b..29f40d4 100644
--- a/src/syscall/syscall_darwin_arm64.go
+++ b/src/syscall/syscall_darwin_arm64.go
@@ -28,7 +28,7 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 //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
+	// but is otherwise unused. The answers come back
 	// in the two registers.
 	sec, usec, err := gettimeofday(tv)
 	tv.Sec = sec
diff --git a/src/syscall/syscall_dragonfly.go b/src/syscall/syscall_dragonfly.go
index c25963c..4080b6b 100644
--- a/src/syscall/syscall_dragonfly.go
+++ b/src/syscall/syscall_dragonfly.go
@@ -34,7 +34,7 @@ func nametomib(name string) (mib []_C_int, err error) {
 
 	// NOTE(rsc): It seems strange to set the buffer to have
 	// size CTL_MAXNAME+2 but use only CTL_MAXNAME
-	// as the size.  I don't know why the +2 is here, but the
+	// as the size. I don't know why the +2 is here, but the
 	// kernel uses +2 for its own implementation of this function.
 	// I am scared that if we don't include the +2 here, the kernel
 	// will silently write 2 words farther than we specify
@@ -57,7 +57,7 @@ func nametomib(name string) (mib []_C_int, err error) {
 }
 
 // ParseDirent parses up to max directory entries in buf,
-// appending the names to names.  It returns the number
+// appending the names to names. It returns the number
 // bytes consumed from buf, the number of entries added
 // to names, and the new names slice.
 func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
@@ -109,6 +109,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 		bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
 	}
 	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go
index 257d419..950dc64 100644
--- a/src/syscall/syscall_freebsd.go
+++ b/src/syscall/syscall_freebsd.go
@@ -32,7 +32,7 @@ func nametomib(name string) (mib []_C_int, err error) {
 
 	// NOTE(rsc): It seems strange to set the buffer to have
 	// size CTL_MAXNAME+2 but use only CTL_MAXNAME
-	// as the size.  I don't know why the +2 is here, but the
+	// as the size. I don't know why the +2 is here, but the
 	// kernel uses +2 for its own implementation of this function.
 	// I am scared that if we don't include the +2 here, the kernel
 	// will silently write 2 words farther than we specify
@@ -55,7 +55,7 @@ func nametomib(name string) (mib []_C_int, err error) {
 }
 
 // ParseDirent parses up to max directory entries in buf,
-// appending the names to names.  It returns the number
+// appending the names to names. It returns the number
 // bytes consumed from buf, the number of entries added
 // to names, and the new names slice.
 func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
@@ -129,6 +129,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 		bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
 	}
 	r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go
index 2875067..73a16f8 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -163,7 +163,7 @@ func Getgroups() (gids []int, err error) {
 		return nil, nil
 	}
 
-	// Sanity check group count.  Max is 1<<16 on Linux.
+	// Sanity check group count. Max is 1<<16 on Linux.
 	if n < 0 || n > 1<<20 {
 		return nil, EINVAL
 	}
@@ -198,8 +198,8 @@ type WaitStatus uint32
 // 0x7F (stopped), or a signal number that caused an exit.
 // The 0x80 bit is whether there was a core dump.
 // An extra number (exit code, signal causing a stop)
-// is in the high bits.  At least that's the idea.
-// There are various irregularities.  For example, the
+// is in the high bits. At least that's the idea.
+// There are various irregularities. For example, the
 // "continued" status is 0xFFFF, distinguishing itself
 // from stopped via the core dump bit.
 
@@ -620,7 +620,7 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err erro
 
 	var buf [sizeofPtr]byte
 
-	// Leading edge.  PEEKTEXT/PEEKDATA don't require aligned
+	// Leading edge. PEEKTEXT/PEEKDATA don't require aligned
 	// access (PEEKUSER warns that it might), but if we don't
 	// align our reads, we might straddle an unmapped page
 	// boundary and not get the bytes leading up to the page
diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go
index 0e637b4..d9e0ed5 100644
--- a/src/syscall/syscall_linux_386.go
+++ b/src/syscall/syscall_linux_386.go
@@ -182,9 +182,9 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 
 // On x86 Linux, all the socket calls go through an extra indirection,
 // I think because the 5-register system call interface can't handle
-// the 6-argument calls like sendto and recvfrom.  Instead the
+// the 6-argument calls like sendto and recvfrom. Instead the
 // arguments to the underlying system call are the number below
-// and a pointer to an array of uintptr.  We hide the pointer in the
+// and a pointer to an array of uintptr. We hide the pointer in the
 // socketcall assembly to avoid allocation on every system call.
 
 const (
diff --git a/src/syscall/syscall_linux_s390x.go b/src/syscall/syscall_linux_s390x.go
new file mode 100644
index 0000000..d74277a
--- /dev/null
+++ b/src/syscall/syscall_linux_s390x.go
@@ -0,0 +1,299 @@
+// Copyright 2016 The Go Authors. 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"
+
+const (
+	_SYS_dup      = SYS_DUP2
+	_SYS_getdents = SYS_GETDENTS64
+)
+
+//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_GETRLIMIT
+//sysnb	Getuid() (uid int)
+//sysnb	InotifyInit() (fd int, err error)
+//sys	Lchown(path string, uid int, gid 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	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_RANGE
+//sys	Truncate(path string, length int64) (err error)
+//sysnb	getgroups(n int, list *_Gid_t) (nn int, err error)
+//sysnb	setgroups(n int, list *_Gid_t) (err error)
+
+func Getpagesize() int { return 4096 }
+
+//sysnb	Gettimeofday(tv *Timeval) (err error)
+
+func Time(t *Time_t) (tt Time_t, err error) {
+	var tv Timeval
+	err = Gettimeofday(&tv)
+	if err != nil {
+		return 0, err
+	}
+	if t != nil {
+		*t = Time_t(tv.Sec)
+	}
+	return Time_t(tv.Sec), nil
+}
+
+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
+}
+
+// Linux on s390x uses the old mmap interface, which requires arguments to be passed in a struct.
+// mmap2 also requires arguments to be passed in a struct; it is currently not exposed in <asm/unistd.h>.
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
+	mmap_args := [6]uintptr{addr, length, uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset)}
+	r0, _, e1 := Syscall(SYS_MMAP, uintptr(unsafe.Pointer(&mmap_args[0])), 0, 0)
+	use(unsafe.Pointer(&mmap_args[0]))
+	xaddr = uintptr(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// On s390x Linux, all the socket calls go through an extra indirection.
+// The arguments to the underlying system call are the number below
+// and a pointer to an array of uintptr.  We hide the pointer in the
+// socketcall assembly to avoid allocation on every system call.
+
+const (
+	// see linux/net.h
+	_SOCKET      = 1
+	_BIND        = 2
+	_CONNECT     = 3
+	_LISTEN      = 4
+	_ACCEPT      = 5
+	_GETSOCKNAME = 6
+	_GETPEERNAME = 7
+	_SOCKETPAIR  = 8
+	_SEND        = 9
+	_RECV        = 10
+	_SENDTO      = 11
+	_RECVFROM    = 12
+	_SHUTDOWN    = 13
+	_SETSOCKOPT  = 14
+	_GETSOCKOPT  = 15
+	_SENDMSG     = 16
+	_RECVMSG     = 17
+	_ACCEPT4     = 18
+	_RECVMMSG    = 19
+	_SENDMMSG    = 20
+)
+
+func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err Errno)
+func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err Errno)
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+	fd, e := socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
+	fd, e := socketcall(_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func getsockname(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, e := rawsocketcall(_GETSOCKNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, e := rawsocketcall(_GETPEERNAME, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func socketpair(domain int, typ int, flags int, fd *[2]int32) (err error) {
+	_, e := rawsocketcall(_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+	_, e := socketcall(_BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+	_, e := socketcall(_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+	fd, e := rawsocketcall(_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+	_, e := socketcall(_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+	_, e := socketcall(_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), vallen, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func recvfrom(s int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+	var base uintptr
+	if len(p) > 0 {
+		base = uintptr(unsafe.Pointer(&p[0]))
+	}
+	n, e := socketcall(_RECVFROM, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func sendto(s int, p []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+	var base uintptr
+	if len(p) > 0 {
+		base = uintptr(unsafe.Pointer(&p[0]))
+	}
+	_, e := socketcall(_SENDTO, uintptr(s), base, uintptr(len(p)), uintptr(flags), uintptr(to), uintptr(addrlen))
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	n, e := socketcall(_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	n, e := socketcall(_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func Listen(s int, n int) (err error) {
+	_, e := socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func Shutdown(s, how int) (err error) {
+	_, e := socketcall(_SHUTDOWN, uintptr(s), uintptr(how), 0, 0, 0, 0)
+	if e != 0 {
+		err = e
+	}
+	return
+}
+
+func (r *PtraceRegs) PC() uint64 { return r.Psw.Addr }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Psw.Addr = 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_nacl.go b/src/syscall/syscall_nacl.go
index f8f63ef..ba6eafe 100644
--- a/src/syscall/syscall_nacl.go
+++ b/src/syscall/syscall_nacl.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -59,7 +59,7 @@ func clen(n []byte) int {
 const PathMax = 256
 
 // An Errno is an unsigned number describing an error condition.
-// It implements the error interface.  The zero Errno is by convention
+// It implements the error interface. The zero Errno is by convention
 // a non-error, so code to convert from Errno to error should use:
 //	err = nil
 //	if errno != 0 {
diff --git a/src/syscall/syscall_nacl_386.go b/src/syscall/syscall_nacl_386.go
index d12f8e2..0d685a6 100644
--- a/src/syscall/syscall_nacl_386.go
+++ b/src/syscall/syscall_nacl_386.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/syscall/syscall_nacl_amd64p32.go b/src/syscall/syscall_nacl_amd64p32.go
index d12f8e2..0d685a6 100644
--- a/src/syscall/syscall_nacl_amd64p32.go
+++ b/src/syscall/syscall_nacl_amd64p32.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/syscall/syscall_nacl_arm.go b/src/syscall/syscall_nacl_arm.go
index fc0cdda..5d72503 100644
--- a/src/syscall/syscall_nacl_arm.go
+++ b/src/syscall/syscall_nacl_arm.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go
index 7968708..b511867 100644
--- a/src/syscall/syscall_plan9.go
+++ b/src/syscall/syscall_plan9.go
@@ -56,6 +56,7 @@ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err ErrorSt
 func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
 func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 
+//go:nosplit
 func atoi(b []byte) (n uint) {
 	n = 0
 	for i := 0; i < len(b); i++ {
diff --git a/src/syscall/syscall_solaris.go b/src/syscall/syscall_solaris.go
index 2f68760..b307a80 100644
--- a/src/syscall/syscall_solaris.go
+++ b/src/syscall/syscall_solaris.go
@@ -39,7 +39,7 @@ func clen(n []byte) int {
 }
 
 // ParseDirent parses up to max directory entries in buf,
-// appending the names to names.  It returns the number
+// appending the names to names. It returns the number
 // bytes consumed from buf, the number of entries added
 // to names, and the new names slice.
 func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
@@ -176,7 +176,7 @@ func Getgroups() (gids []int, err error) {
 		return nil, nil
 	}
 
-	// Sanity check group count.  Max is 16 on BSD.
+	// Sanity check group count. Max is 16 on BSD.
 	if n < 0 || n > 1000 {
 		return nil, EINVAL
 	}
diff --git a/src/syscall/syscall_test.go b/src/syscall/syscall_test.go
index 846c487..0a0b8b7 100644
--- a/src/syscall/syscall_test.go
+++ b/src/syscall/syscall_test.go
@@ -6,6 +6,8 @@ package syscall_test
 
 import (
 	"fmt"
+	"internal/testenv"
+	"os"
 	"syscall"
 	"testing"
 )
@@ -45,3 +47,15 @@ func TestItoa(t *testing.T) {
 		t.Fatalf("itoa(%d) = %s, want %s", i, s, f)
 	}
 }
+
+// Check that permuting child process fds doesn't interfere with
+// reporting of fork/exec status. See Issue 14979.
+func TestExecErrPermutedFds(t *testing.T) {
+	testenv.MustHaveExec(t)
+
+	attr := &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stderr, os.Stdout}}
+	_, err := os.StartProcess("/", []string{"/"}, attr)
+	if err == nil {
+		t.Fatalf("StartProcess of invalid program returned err = nil")
+	}
+}
diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go
index 5703133..4dae9d9 100644
--- a/src/syscall/syscall_unix.go
+++ b/src/syscall/syscall_unix.go
@@ -91,7 +91,7 @@ func (m *mmapper) Munmap(data []byte) (err error) {
 }
 
 // An Errno is an unsigned number describing an error condition.
-// It implements the error interface.  The zero Errno is by convention
+// It implements the error interface. The zero Errno is by convention
 // a non-error, so code to convert from Errno to error should use:
 //	err = nil
 //	if errno != 0 {
diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go
index c7b4560..80544f3 100644
--- a/src/syscall/syscall_unix_test.go
+++ b/src/syscall/syscall_unix_test.go
@@ -10,6 +10,7 @@ import (
 	"flag"
 	"fmt"
 	"internal/testenv"
+	"io"
 	"io/ioutil"
 	"net"
 	"os"
@@ -244,7 +245,7 @@ func passFDChild() {
 	}
 
 	f.Write([]byte("Hello from child process!\n"))
-	f.Seek(0, 0)
+	f.Seek(0, io.SeekStart)
 
 	rights := syscall.UnixRights(int(f.Fd()))
 	dummyByte := []byte("x")
@@ -344,7 +345,7 @@ func TestRlimit(t *testing.T) {
 }
 
 func TestSeekFailure(t *testing.T) {
-	_, err := syscall.Seek(-1, 0, 0)
+	_, err := syscall.Seek(-1, 0, io.SeekStart)
 	if err == nil {
 		t.Fatalf("Seek(-1, 0, 0) did not fail")
 	}
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index 1d02ee0..703bb53 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/syscall/syscall_windows_386.go b/src/syscall/syscall_windows_386.go
index 61d2d8c..e82b540 100644
--- a/src/syscall/syscall_windows_386.go
+++ b/src/syscall/syscall_windows_386.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/syscall/syscall_windows_amd64.go b/src/syscall/syscall_windows_amd64.go
index 61d2d8c..e82b540 100644
--- a/src/syscall/syscall_windows_amd64.go
+++ b/src/syscall/syscall_windows_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/src/syscall/tables_nacl.go b/src/syscall/tables_nacl.go
index adc6be2..d97e2b4 100644
--- a/src/syscall/tables_nacl.go
+++ b/src/syscall/tables_nacl.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/syscall/time_nacl_386.s b/src/syscall/time_nacl_386.s
index c0c89dc..90cf366 100644
--- a/src/syscall/time_nacl_386.s
+++ b/src/syscall/time_nacl_386.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/syscall/time_nacl_amd64p32.s b/src/syscall/time_nacl_amd64p32.s
index c0c89dc..90cf366 100644
--- a/src/syscall/time_nacl_amd64p32.s
+++ b/src/syscall/time_nacl_amd64p32.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/src/syscall/time_nacl_arm.s b/src/syscall/time_nacl_arm.s
index 4f4b4d8..7864ec9 100644
--- a/src/syscall/time_nacl_arm.s
+++ b/src/syscall/time_nacl_arm.s
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/syscall/types_linux.go b/src/syscall/types_linux.go
index cb6836b..2a16650 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;
-#if defined(__ARM_EABI__) || defined(__powerpc64__)
-	// on ARM and PPC char is by default unsigned
+#if defined(__ARM_EABI__) || defined(__powerpc64__) || defined(__s390x__)
+	// on ARM, PPC and s390x char is by default unsigned
 	signed char sun_path[108];
 #else
 	char sun_path[108];
@@ -93,10 +93,22 @@ typedef struct user_pt_regs PtraceRegs;
 typedef struct pt_regs PtraceRegs;
 #elif defined(__mips__)
 typedef struct user PtraceRegs;
+#elif defined(__s390x__)
+typedef struct _user_regs_struct PtraceRegs;
 #else
 typedef struct user_regs_struct PtraceRegs;
 #endif
 
+#if defined(__s390x__)
+typedef struct _user_psw_struct ptracePsw;
+typedef struct _user_fpregs_struct ptraceFpregs;
+typedef struct _user_per_struct ptracePer;
+#else
+typedef struct {} ptracePsw;
+typedef struct {} ptraceFpregs;
+typedef struct {} ptracePer;
+#endif
+
 // The real epoll_event is a union, and godefs doesn't handle it well.
 struct my_epoll_event {
 	uint32_t events;
@@ -105,7 +117,7 @@ struct my_epoll_event {
 	// alignment requirements of EABI
 	int32_t padFd;
 #endif
-#ifdef  __powerpc64__
+#if defined(__powerpc64__) || defined(__s390x__)
 	int32_t _padFd;
 #endif
 	int32_t fd;
@@ -370,6 +382,13 @@ const SizeofInotifyEvent = C.sizeof_struct_inotify_event
 // Register structures
 type PtraceRegs C.PtraceRegs
 
+// Structures contained in PtraceRegs on s390x (exported by post.go)
+type ptracePsw C.ptracePsw
+
+type ptraceFpregs C.ptraceFpregs
+
+type ptracePer C.ptracePer
+
 // Misc
 
 type FdSet C.fd_set
diff --git a/src/syscall/unzip_nacl.go b/src/syscall/unzip_nacl.go
index 5845e44..14b5bd1 100644
--- a/src/syscall/unzip_nacl.go
+++ b/src/syscall/unzip_nacl.go
@@ -162,7 +162,7 @@ func (f *decompressor) readHuffman() {
 
 // Decode a single Huffman block from f.
 // hl and hd are the Huffman states for the lit/length values
-// and the distance values, respectively.  If hd == nil, using the
+// and the distance values, respectively. If hd == nil, using the
 // fixed distance encoding associated with fixed Huffman blocks.
 func (f *decompressor) huffmanBlock(hl, hd *huffmanDecoder) {
 	for {
diff --git a/src/syscall/zerrors_linux_s390x.go b/src/syscall/zerrors_linux_s390x.go
new file mode 100644
index 0000000..4c3dbe9
--- /dev/null
+++ b/src/syscall/zerrors_linux_s390x.go
@@ -0,0 +1,1940 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+package syscall
+
+const (
+	AF_ALG                           = 0x26
+	AF_APPLETALK                     = 0x5
+	AF_ASH                           = 0x12
+	AF_ATMPVC                        = 0x8
+	AF_ATMSVC                        = 0x14
+	AF_AX25                          = 0x3
+	AF_BLUETOOTH                     = 0x1f
+	AF_BRIDGE                        = 0x7
+	AF_CAIF                          = 0x25
+	AF_CAN                           = 0x1d
+	AF_DECnet                        = 0xc
+	AF_ECONET                        = 0x13
+	AF_FILE                          = 0x1
+	AF_IEEE802154                    = 0x24
+	AF_INET                          = 0x2
+	AF_INET6                         = 0xa
+	AF_IPX                           = 0x4
+	AF_IRDA                          = 0x17
+	AF_ISDN                          = 0x22
+	AF_IUCV                          = 0x20
+	AF_KEY                           = 0xf
+	AF_LLC                           = 0x1a
+	AF_LOCAL                         = 0x1
+	AF_MAX                           = 0x29
+	AF_NETBEUI                       = 0xd
+	AF_NETLINK                       = 0x10
+	AF_NETROM                        = 0x6
+	AF_NFC                           = 0x27
+	AF_PACKET                        = 0x11
+	AF_PHONET                        = 0x23
+	AF_PPPOX                         = 0x18
+	AF_RDS                           = 0x15
+	AF_ROSE                          = 0xb
+	AF_ROUTE                         = 0x10
+	AF_RXRPC                         = 0x21
+	AF_SECURITY                      = 0xe
+	AF_SNA                           = 0x16
+	AF_TIPC                          = 0x1e
+	AF_UNIX                          = 0x1
+	AF_UNSPEC                        = 0x0
+	AF_VSOCK                         = 0x28
+	AF_WANPIPE                       = 0x19
+	AF_X25                           = 0x9
+	ARPHRD_6LOWPAN                   = 0x339
+	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_LL_OFF                       = -0x200000
+	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_NET_OFF                      = -0x100000
+	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_NEWCGROUP                  = 0x2000000
+	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_80221                      = 0x8917
+	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_LOOPBACK                   = 0x9000
+	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_TSN                        = 0x22f0
+	ETH_P_WAN_PPP                    = 0x7
+	ETH_P_WCCP                       = 0x883e
+	ETH_P_X25                        = 0x805
+	ETH_P_XDSA                       = 0xf8
+	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_OFD_GETLK                      = 0x24
+	F_OFD_SETLK                      = 0x25
+	F_OFD_SETLKW                     = 0x26
+	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_MANAGETEMPADDR             = 0x100
+	IFA_F_MCAUTOJOIN                 = 0x400
+	IFA_F_NODAD                      = 0x2
+	IFA_F_NOPREFIXROUTE              = 0x200
+	IFA_F_OPTIMISTIC                 = 0x4
+	IFA_F_PERMANENT                  = 0x80
+	IFA_F_SECONDARY                  = 0x1
+	IFA_F_STABLE_PRIVACY             = 0x800
+	IFA_F_TEMPORARY                  = 0x1
+	IFA_F_TENTATIVE                  = 0x40
+	IFA_MAX                          = 0x8
+	IFF_ALLMULTI                     = 0x200
+	IFF_ATTACH_QUEUE                 = 0x200
+	IFF_AUTOMEDIA                    = 0x4000
+	IFF_BROADCAST                    = 0x2
+	IFF_DEBUG                        = 0x4
+	IFF_DETACH_QUEUE                 = 0x400
+	IFF_DORMANT                      = 0x20000
+	IFF_DYNAMIC                      = 0x8000
+	IFF_ECHO                         = 0x40000
+	IFF_LOOPBACK                     = 0x8
+	IFF_LOWER_UP                     = 0x10000
+	IFF_MASTER                       = 0x400
+	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_PERSIST                      = 0x800
+	IFF_POINTOPOINT                  = 0x10
+	IFF_PORTSEL                      = 0x2000
+	IFF_PROMISC                      = 0x100
+	IFF_RUNNING                      = 0x40
+	IFF_SLAVE                        = 0x800
+	IFF_TAP                          = 0x2
+	IFF_TUN                          = 0x1
+	IFF_TUN_EXCL                     = 0x8000
+	IFF_UP                           = 0x1
+	IFF_VNET_HDR                     = 0x4000
+	IFF_VOLATILE                     = 0x70c5a
+	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_INTERFACE          = 0x4
+	IPV6_PMTUDISC_OMIT               = 0x5
+	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_NODEFRAG                      = 0x16
+	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_INTERFACE            = 0x4
+	IP_PMTUDISC_OMIT                 = 0x5
+	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_CAP_ACK                  = 0xa
+	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_LISTEN_ALL_NSID          = 0x8
+	NETLINK_LIST_MEMBERSHIPS         = 0x9
+	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_FILTERED              = 0x20
+	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                         = 0x4000
+	O_DIRECTORY                      = 0x10000
+	O_DSYNC                          = 0x1000
+	O_EXCL                           = 0x80
+	O_FSYNC                          = 0x101000
+	O_LARGEFILE                      = 0x0
+	O_NDELAY                         = 0x800
+	O_NOATIME                        = 0x40000
+	O_NOCTTY                         = 0x100
+	O_NOFOLLOW                       = 0x20000
+	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_CBPF               = 0x6
+	PACKET_FANOUT_CPU                = 0x2
+	PACKET_FANOUT_DATA               = 0x16
+	PACKET_FANOUT_EBPF               = 0x7
+	PACKET_FANOUT_FLAG_DEFRAG        = 0x8000
+	PACKET_FANOUT_FLAG_ROLLOVER      = 0x1000
+	PACKET_FANOUT_HASH               = 0x0
+	PACKET_FANOUT_LB                 = 0x1
+	PACKET_FANOUT_QM                 = 0x5
+	PACKET_FANOUT_RND                = 0x4
+	PACKET_FANOUT_ROLLOVER           = 0x3
+	PACKET_FASTROUTE                 = 0x6
+	PACKET_HDRLEN                    = 0xb
+	PACKET_HOST                      = 0x0
+	PACKET_KERNEL                    = 0x7
+	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_QDISC_BYPASS              = 0x14
+	PACKET_RECV_OUTPUT               = 0x3
+	PACKET_RESERVE                   = 0xc
+	PACKET_ROLLOVER_STATS            = 0x15
+	PACKET_RX_RING                   = 0x5
+	PACKET_STATISTICS                = 0x6
+	PACKET_TIMESTAMP                 = 0x11
+	PACKET_TX_HAS_OFF                = 0x13
+	PACKET_TX_RING                   = 0xd
+	PACKET_TX_TIMESTAMP              = 0x10
+	PACKET_USER                      = 0x6
+	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_CAP_AMBIENT                   = 0x2f
+	PR_CAP_AMBIENT_CLEAR_ALL         = 0x4
+	PR_CAP_AMBIENT_IS_SET            = 0x1
+	PR_CAP_AMBIENT_LOWER             = 0x3
+	PR_CAP_AMBIENT_RAISE             = 0x2
+	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_FP_MODE_FR                    = 0x1
+	PR_FP_MODE_FRE                   = 0x2
+	PR_GET_CHILD_SUBREAPER           = 0x25
+	PR_GET_DUMPABLE                  = 0x3
+	PR_GET_ENDIAN                    = 0x13
+	PR_GET_FPEMU                     = 0x9
+	PR_GET_FPEXC                     = 0xb
+	PR_GET_FP_MODE                   = 0x2e
+	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_THP_DISABLE               = 0x2a
+	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_MPX_DISABLE_MANAGEMENT        = 0x2c
+	PR_MPX_ENABLE_MANAGEMENT         = 0x2b
+	PR_SET_CHILD_SUBREAPER           = 0x24
+	PR_SET_DUMPABLE                  = 0x4
+	PR_SET_ENDIAN                    = 0x14
+	PR_SET_FPEMU                     = 0xa
+	PR_SET_FPEXC                     = 0xc
+	PR_SET_FP_MODE                   = 0x2d
+	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_MAP                    = 0xe
+	PR_SET_MM_MAP_SIZE               = 0xf
+	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_THP_DISABLE               = 0x29
+	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_DISABLE_TE                = 0x5010
+	PTRACE_ENABLE_TE                 = 0x5009
+	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_GET_LAST_BREAK            = 0x5006
+	PTRACE_INTERRUPT                 = 0x4207
+	PTRACE_KILL                      = 0x8
+	PTRACE_LISTEN                    = 0x4208
+	PTRACE_OLDSETOPTIONS             = 0x15
+	PTRACE_O_EXITKILL                = 0x100000
+	PTRACE_O_MASK                    = 0x3000ff
+	PTRACE_O_SUSPEND_SECCOMP         = 0x200000
+	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_PEEKDATA_AREA             = 0x5003
+	PTRACE_PEEKSIGINFO               = 0x4209
+	PTRACE_PEEKSIGINFO_SHARED        = 0x1
+	PTRACE_PEEKTEXT                  = 0x1
+	PTRACE_PEEKTEXT_AREA             = 0x5002
+	PTRACE_PEEKUSR                   = 0x3
+	PTRACE_PEEKUSR_AREA              = 0x5000
+	PTRACE_PEEK_SYSTEM_CALL          = 0x5007
+	PTRACE_POKEDATA                  = 0x5
+	PTRACE_POKEDATA_AREA             = 0x5005
+	PTRACE_POKETEXT                  = 0x4
+	PTRACE_POKETEXT_AREA             = 0x5004
+	PTRACE_POKEUSR                   = 0x6
+	PTRACE_POKEUSR_AREA              = 0x5001
+	PTRACE_POKE_SYSTEM_CALL          = 0x5008
+	PTRACE_PROT                      = 0x15
+	PTRACE_SECCOMP_GET_FILTER        = 0x420c
+	PTRACE_SEIZE                     = 0x4206
+	PTRACE_SETOPTIONS                = 0x4200
+	PTRACE_SETREGS                   = 0xd
+	PTRACE_SETREGSET                 = 0x4205
+	PTRACE_SETSIGINFO                = 0x4203
+	PTRACE_SETSIGMASK                = 0x420b
+	PTRACE_SINGLEBLOCK               = 0xc
+	PTRACE_SINGLESTEP                = 0x9
+	PTRACE_SYSCALL                   = 0x18
+	PTRACE_TE_ABORT_RAND             = 0x5011
+	PTRACE_TRACEME                   = 0x0
+	PT_ACR0                          = 0x90
+	PT_ACR1                          = 0x94
+	PT_ACR10                         = 0xb8
+	PT_ACR11                         = 0xbc
+	PT_ACR12                         = 0xc0
+	PT_ACR13                         = 0xc4
+	PT_ACR14                         = 0xc8
+	PT_ACR15                         = 0xcc
+	PT_ACR2                          = 0x98
+	PT_ACR3                          = 0x9c
+	PT_ACR4                          = 0xa0
+	PT_ACR5                          = 0xa4
+	PT_ACR6                          = 0xa8
+	PT_ACR7                          = 0xac
+	PT_ACR8                          = 0xb0
+	PT_ACR9                          = 0xb4
+	PT_CR_10                         = 0x168
+	PT_CR_11                         = 0x170
+	PT_CR_9                          = 0x160
+	PT_ENDREGS                       = 0x1af
+	PT_FPC                           = 0xd8
+	PT_FPR0                          = 0xe0
+	PT_FPR1                          = 0xe8
+	PT_FPR10                         = 0x130
+	PT_FPR11                         = 0x138
+	PT_FPR12                         = 0x140
+	PT_FPR13                         = 0x148
+	PT_FPR14                         = 0x150
+	PT_FPR15                         = 0x158
+	PT_FPR2                          = 0xf0
+	PT_FPR3                          = 0xf8
+	PT_FPR4                          = 0x100
+	PT_FPR5                          = 0x108
+	PT_FPR6                          = 0x110
+	PT_FPR7                          = 0x118
+	PT_FPR8                          = 0x120
+	PT_FPR9                          = 0x128
+	PT_GPR0                          = 0x10
+	PT_GPR1                          = 0x18
+	PT_GPR10                         = 0x60
+	PT_GPR11                         = 0x68
+	PT_GPR12                         = 0x70
+	PT_GPR13                         = 0x78
+	PT_GPR14                         = 0x80
+	PT_GPR15                         = 0x88
+	PT_GPR2                          = 0x20
+	PT_GPR3                          = 0x28
+	PT_GPR4                          = 0x30
+	PT_GPR5                          = 0x38
+	PT_GPR6                          = 0x40
+	PT_GPR7                          = 0x48
+	PT_GPR8                          = 0x50
+	PT_GPR9                          = 0x58
+	PT_IEEE_IP                       = 0x1a8
+	PT_LASTOFF                       = 0x1a8
+	PT_ORIGGPR2                      = 0xd0
+	PT_PSWADDR                       = 0x8
+	PT_PSWMASK                       = 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_CC_ALGO                     = 0x10
+	RTAX_CWND                        = 0x7
+	RTAX_FEATURES                    = 0xc
+	RTAX_FEATURE_ALLFRAG             = 0x8
+	RTAX_FEATURE_ECN                 = 0x1
+	RTAX_FEATURE_MASK                = 0xf
+	RTAX_FEATURE_SACK                = 0x2
+	RTAX_FEATURE_TIMESTAMP           = 0x4
+	RTAX_HOPLIMIT                    = 0xa
+	RTAX_INITCWND                    = 0xb
+	RTAX_INITRWND                    = 0xe
+	RTAX_LOCK                        = 0x1
+	RTAX_MAX                         = 0x10
+	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                          = 0x16
+	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_DELNSID                      = 0x59
+	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_LOOKUP_TABLE               = 0x1000
+	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_GETNSID                      = 0x5a
+	RTM_GETQDISC                     = 0x26
+	RTM_GETROUTE                     = 0x1a
+	RTM_GETRULE                      = 0x22
+	RTM_GETTCLASS                    = 0x2a
+	RTM_GETTFILTER                   = 0x2e
+	RTM_MAX                          = 0x5b
+	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_NEWNSID                      = 0x58
+	RTM_NEWPREFIX                    = 0x34
+	RTM_NEWQDISC                     = 0x24
+	RTM_NEWROUTE                     = 0x18
+	RTM_NEWRULE                      = 0x20
+	RTM_NEWTCLASS                    = 0x28
+	RTM_NEWTFILTER                   = 0x2c
+	RTM_NR_FAMILIES                  = 0x13
+	RTM_NR_MSGTYPES                  = 0x4c
+	RTM_SETDCB                       = 0x4f
+	RTM_SETLINK                      = 0x13
+	RTM_SETNEIGHTBL                  = 0x43
+	RTNH_ALIGNTO                     = 0x4
+	RTNH_COMPARE_MASK                = 0x11
+	RTNH_F_DEAD                      = 0x1
+	RTNH_F_LINKDOWN                  = 0x10
+	RTNH_F_OFFLOAD                   = 0x8
+	RTNH_F_ONLINK                    = 0x4
+	RTNH_F_PERVASIVE                 = 0x2
+	RTN_MAX                          = 0xb
+	RTPROT_BABEL                     = 0x2a
+	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_BPF                    = 0x32
+	SO_ATTACH_FILTER                 = 0x1a
+	SO_BINDTODEVICE                  = 0x19
+	SO_BPF_EXTENSIONS                = 0x30
+	SO_BROADCAST                     = 0x6
+	SO_BSDCOMPAT                     = 0xe
+	SO_BUSY_POLL                     = 0x2e
+	SO_DEBUG                         = 0x1
+	SO_DETACH_BPF                    = 0x1b
+	SO_DETACH_FILTER                 = 0x1b
+	SO_DOMAIN                        = 0x27
+	SO_DONTROUTE                     = 0x5
+	SO_ERROR                         = 0x4
+	SO_GET_FILTER                    = 0x1a
+	SO_INCOMING_CPU                  = 0x31
+	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
+	TUNGETVNETBE                     = 0x800454df
+	TUNGETVNETHDRSZ                  = 0x800454d7
+	TUNGETVNETLE                     = 0x800454dd
+	TUNSETDEBUG                      = 0x400454c9
+	TUNSETGROUP                      = 0x400454ce
+	TUNSETIFF                        = 0x400454ca
+	TUNSETIFINDEX                    = 0x400454da
+	TUNSETLINK                       = 0x400454cd
+	TUNSETNOCSUM                     = 0x400454c8
+	TUNSETOFFLOAD                    = 0x400454d0
+	TUNSETOWNER                      = 0x400454cc
+	TUNSETPERSIST                    = 0x400454cb
+	TUNSETQUEUE                      = 0x400454d9
+	TUNSETSNDBUF                     = 0x400454d4
+	TUNSETTXFILTER                   = 0x400454d1
+	TUNSETVNETBE                     = 0x400454de
+	TUNSETVNETHDRSZ                  = 0x400454d8
+	TUNSETVNETLE                     = 0x400454dc
+	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_windows_386.go b/src/syscall/zerrors_windows_386.go
index d1008bd..8bc5b6b 100644
--- a/src/syscall/zerrors_windows_386.go
+++ b/src/syscall/zerrors_windows_386.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/syscall/zerrors_windows_amd64.go b/src/syscall/zerrors_windows_amd64.go
index d1008bd..8bc5b6b 100644
--- a/src/syscall/zerrors_windows_amd64.go
+++ b/src/syscall/zerrors_windows_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go
index 23e7b5e..9c3ba5a 100644
--- a/src/syscall/zsyscall_darwin_386.go
+++ b/src/syscall/zsyscall_darwin_386.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go
index 6e63d9a..12f4782 100644
--- a/src/syscall/zsyscall_darwin_amd64.go
+++ b/src/syscall/zsyscall_darwin_amd64.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_darwin_arm.go b/src/syscall/zsyscall_darwin_arm.go
index f996a50..ab5b4a9 100644
--- a/src/syscall/zsyscall_darwin_arm.go
+++ b/src/syscall/zsyscall_darwin_arm.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go
index 88e09d3..85d2777 100644
--- a/src/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/syscall/zsyscall_dragonfly_amd64.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go
index 30f29e5..b9ed271 100644
--- a/src/syscall/zsyscall_freebsd_386.go
+++ b/src/syscall/zsyscall_freebsd_386.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go
index 93059d1..12d1db0 100644
--- a/src/syscall/zsyscall_freebsd_amd64.go
+++ b/src/syscall/zsyscall_freebsd_amd64.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go
index 84096b0..78b7c07 100644
--- a/src/syscall/zsyscall_freebsd_arm.go
+++ b/src/syscall/zsyscall_freebsd_arm.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_linux_s390x.go b/src/syscall/zsyscall_linux_s390x.go
new file mode 100644
index 0000000..fd15366
--- /dev/null
+++ b/src/syscall/zsyscall_linux_s390x.go
@@ -0,0 +1,1576 @@
+// mksyscall.pl syscall_linux.go syscall_linux_s390x.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0)
+	use(unsafe.Pointer(_p0))
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(buf) > 0 {
+		_p1 = unsafe.Pointer(&buf[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)))
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func unlinkat(dirfd int, path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, times *[2]Timeval) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+	wpid = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(arg)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(source)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(target)
+	if err != nil {
+		return
+	}
+	var _p2 *byte
+	_p2, err = BytePtrFromString(fstype)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	use(unsafe.Pointer(_p2))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Acct(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtimex(buf *Timex) (state int, err error) {
+	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
+	state = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int) (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup3(oldfd int, newfd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate(size int) (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate1(flag int) (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
+	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(events) > 0 {
+		_p0 = unsafe.Pointer(&events[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+	Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+	val = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fdatasync(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdents(fd int, buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(_SYS_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 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_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 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)
+	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 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 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_RANGE, 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 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 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 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_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go
index e24c3b7..61b52cd 100644
--- a/src/syscall/zsyscall_netbsd_386.go
+++ b/src/syscall/zsyscall_netbsd_386.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go
index 7aa75ab..52987ba 100644
--- a/src/syscall/zsyscall_netbsd_amd64.go
+++ b/src/syscall/zsyscall_netbsd_amd64.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go
index 21f482b..5c59a0d 100644
--- a/src/syscall/zsyscall_netbsd_arm.go
+++ b/src/syscall/zsyscall_netbsd_arm.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go
index df7df1e..37bbd85 100644
--- a/src/syscall/zsyscall_openbsd_386.go
+++ b/src/syscall/zsyscall_openbsd_386.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go
index 1d64070..0d831df 100644
--- a/src/syscall/zsyscall_openbsd_amd64.go
+++ b/src/syscall/zsyscall_openbsd_amd64.go
@@ -217,6 +217,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 		_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))
+	use(_p0)
 	if e1 != 0 {
 		err = errnoErr(e1)
 	}
diff --git a/src/syscall/zsyscall_plan9_arm.go b/src/syscall/zsyscall_plan9_arm.go
new file mode 100644
index 0000000..d54aeff
--- /dev/null
+++ b/src/syscall/zsyscall_plan9_arm.go
@@ -0,0 +1,294 @@
+// mksyscall.pl -l32 -plan9 syscall_plan9.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// +build arm,plan9
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fd2path(fd int, buf []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]int32) (err error) {
+	r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func await(s []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(s) > 0 {
+		_p0 = unsafe.Pointer(&s[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 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 open(path string, mode int) (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), 0)
+	use(unsafe.Pointer(_p0))
+	fd = int(r0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// 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) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+	use(unsafe.Pointer(_p0))
+	fd = int(r0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func remove(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_REMOVE, 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 stat(path string, edir []byte) (n int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(name string, old string, flag int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(name)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(old)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// 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) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(old)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(aname)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// 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
+	}
+	var _p1 unsafe.Pointer
+	if len(edir) > 0 {
+		_p1 = unsafe.Pointer(&edir[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	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
+	}
+	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 Fstat(fd int, edir []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(edir) > 0 {
+		_p0 = unsafe.Pointer(&edir[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+	n = int(r0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fwstat(fd int, edir []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(edir) > 0 {
+		_p0 = unsafe.Pointer(&edir[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
diff --git a/src/syscall/zsysnum_linux_s390x.go b/src/syscall/zsysnum_linux_s390x.go
new file mode 100644
index 0000000..2cb7dbb
--- /dev/null
+++ b/src/syscall/zsysnum_linux_s390x.go
@@ -0,0 +1,326 @@
+// mksysnum_linux.pl /usr/include/asm/unistd.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+	SYS_EXIT                   = 1
+	SYS_FORK                   = 2
+	SYS_READ                   = 3
+	SYS_WRITE                  = 4
+	SYS_OPEN                   = 5
+	SYS_CLOSE                  = 6
+	SYS_RESTART_SYSCALL        = 7
+	SYS_CREAT                  = 8
+	SYS_LINK                   = 9
+	SYS_UNLINK                 = 10
+	SYS_EXECVE                 = 11
+	SYS_CHDIR                  = 12
+	SYS_MKNOD                  = 14
+	SYS_CHMOD                  = 15
+	SYS_LSEEK                  = 19
+	SYS_GETPID                 = 20
+	SYS_MOUNT                  = 21
+	SYS_UMOUNT                 = 22
+	SYS_PTRACE                 = 26
+	SYS_ALARM                  = 27
+	SYS_PAUSE                  = 29
+	SYS_UTIME                  = 30
+	SYS_ACCESS                 = 33
+	SYS_NICE                   = 34
+	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_BRK                    = 45
+	SYS_SIGNAL                 = 48
+	SYS_ACCT                   = 51
+	SYS_UMOUNT2                = 52
+	SYS_IOCTL                  = 54
+	SYS_FCNTL                  = 55
+	SYS_SETPGID                = 57
+	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_SIGSUSPEND             = 72
+	SYS_SIGPENDING             = 73
+	SYS_SETHOSTNAME            = 74
+	SYS_SETRLIMIT              = 75
+	SYS_GETRUSAGE              = 77
+	SYS_GETTIMEOFDAY           = 78
+	SYS_SETTIMEOFDAY           = 79
+	SYS_SYMLINK                = 83
+	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_GETPRIORITY            = 96
+	SYS_SETPRIORITY            = 97
+	SYS_STATFS                 = 99
+	SYS_FSTATFS                = 100
+	SYS_SOCKETCALL             = 102
+	SYS_SYSLOG                 = 103
+	SYS_SETITIMER              = 104
+	SYS_GETITIMER              = 105
+	SYS_STAT                   = 106
+	SYS_LSTAT                  = 107
+	SYS_FSTAT                  = 108
+	SYS_LOOKUP_DCOOKIE         = 110
+	SYS_VHANGUP                = 111
+	SYS_IDLE                   = 112
+	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_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_GETDENTS               = 141
+	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_QUERY_MODULE           = 167
+	SYS_POLL                   = 168
+	SYS_NFSSERVCTL             = 169
+	SYS_PRCTL                  = 172
+	SYS_RT_SIGRETURN           = 173
+	SYS_RT_SIGACTION           = 174
+	SYS_RT_SIGPROCMASK         = 175
+	SYS_RT_SIGPENDING          = 176
+	SYS_RT_SIGTIMEDWAIT        = 177
+	SYS_RT_SIGQUEUEINFO        = 178
+	SYS_RT_SIGSUSPEND          = 179
+	SYS_PREAD64                = 180
+	SYS_PWRITE64               = 181
+	SYS_GETCWD                 = 183
+	SYS_CAPGET                 = 184
+	SYS_CAPSET                 = 185
+	SYS_SIGALTSTACK            = 186
+	SYS_SENDFILE               = 187
+	SYS_GETPMSG                = 188
+	SYS_PUTPMSG                = 189
+	SYS_VFORK                  = 190
+	SYS_PIVOT_ROOT             = 217
+	SYS_MINCORE                = 218
+	SYS_MADVISE                = 219
+	SYS_GETDENTS64             = 220
+	SYS_READAHEAD              = 222
+	SYS_SETXATTR               = 224
+	SYS_LSETXATTR              = 225
+	SYS_FSETXATTR              = 226
+	SYS_GETXATTR               = 227
+	SYS_LGETXATTR              = 228
+	SYS_FGETXATTR              = 229
+	SYS_LISTXATTR              = 230
+	SYS_LLISTXATTR             = 231
+	SYS_FLISTXATTR             = 232
+	SYS_REMOVEXATTR            = 233
+	SYS_LREMOVEXATTR           = 234
+	SYS_FREMOVEXATTR           = 235
+	SYS_GETTID                 = 236
+	SYS_TKILL                  = 237
+	SYS_FUTEX                  = 238
+	SYS_SCHED_SETAFFINITY      = 239
+	SYS_SCHED_GETAFFINITY      = 240
+	SYS_TGKILL                 = 241
+	SYS_IO_SETUP               = 243
+	SYS_IO_DESTROY             = 244
+	SYS_IO_GETEVENTS           = 245
+	SYS_IO_SUBMIT              = 246
+	SYS_IO_CANCEL              = 247
+	SYS_EXIT_GROUP             = 248
+	SYS_EPOLL_CREATE           = 249
+	SYS_EPOLL_CTL              = 250
+	SYS_EPOLL_WAIT             = 251
+	SYS_SET_TID_ADDRESS        = 252
+	SYS_FADVISE64              = 253
+	SYS_TIMER_CREATE           = 254
+	SYS_TIMER_SETTIME          = 255
+	SYS_TIMER_GETTIME          = 256
+	SYS_TIMER_GETOVERRUN       = 257
+	SYS_TIMER_DELETE           = 258
+	SYS_CLOCK_SETTIME          = 259
+	SYS_CLOCK_GETTIME          = 260
+	SYS_CLOCK_GETRES           = 261
+	SYS_CLOCK_NANOSLEEP        = 262
+	SYS_STATFS64               = 265
+	SYS_FSTATFS64              = 266
+	SYS_REMAP_FILE_PAGES       = 267
+	SYS_MBIND                  = 268
+	SYS_GET_MEMPOLICY          = 269
+	SYS_SET_MEMPOLICY          = 270
+	SYS_MQ_OPEN                = 271
+	SYS_MQ_UNLINK              = 272
+	SYS_MQ_TIMEDSEND           = 273
+	SYS_MQ_TIMEDRECEIVE        = 274
+	SYS_MQ_NOTIFY              = 275
+	SYS_MQ_GETSETATTR          = 276
+	SYS_KEXEC_LOAD             = 277
+	SYS_ADD_KEY                = 278
+	SYS_REQUEST_KEY            = 279
+	SYS_KEYCTL                 = 280
+	SYS_WAITID                 = 281
+	SYS_IOPRIO_SET             = 282
+	SYS_IOPRIO_GET             = 283
+	SYS_INOTIFY_INIT           = 284
+	SYS_INOTIFY_ADD_WATCH      = 285
+	SYS_INOTIFY_RM_WATCH       = 286
+	SYS_MIGRATE_PAGES          = 287
+	SYS_OPENAT                 = 288
+	SYS_MKDIRAT                = 289
+	SYS_MKNODAT                = 290
+	SYS_FCHOWNAT               = 291
+	SYS_FUTIMESAT              = 292
+	SYS_UNLINKAT               = 294
+	SYS_RENAMEAT               = 295
+	SYS_LINKAT                 = 296
+	SYS_SYMLINKAT              = 297
+	SYS_READLINKAT             = 298
+	SYS_FCHMODAT               = 299
+	SYS_FACCESSAT              = 300
+	SYS_PSELECT6               = 301
+	SYS_PPOLL                  = 302
+	SYS_UNSHARE                = 303
+	SYS_SET_ROBUST_LIST        = 304
+	SYS_GET_ROBUST_LIST        = 305
+	SYS_SPLICE                 = 306
+	SYS_SYNC_FILE_RANGE        = 307
+	SYS_TEE                    = 308
+	SYS_VMSPLICE               = 309
+	SYS_MOVE_PAGES             = 310
+	SYS_GETCPU                 = 311
+	SYS_EPOLL_PWAIT            = 312
+	SYS_UTIMES                 = 313
+	SYS_FALLOCATE              = 314
+	SYS_UTIMENSAT              = 315
+	SYS_SIGNALFD               = 316
+	SYS_TIMERFD                = 317
+	SYS_EVENTFD                = 318
+	SYS_TIMERFD_CREATE         = 319
+	SYS_TIMERFD_SETTIME        = 320
+	SYS_TIMERFD_GETTIME        = 321
+	SYS_SIGNALFD4              = 322
+	SYS_EVENTFD2               = 323
+	SYS_INOTIFY_INIT1          = 324
+	SYS_PIPE2                  = 325
+	SYS_DUP3                   = 326
+	SYS_EPOLL_CREATE1          = 327
+	SYS_PREADV                 = 328
+	SYS_PWRITEV                = 329
+	SYS_RT_TGSIGQUEUEINFO      = 330
+	SYS_PERF_EVENT_OPEN        = 331
+	SYS_FANOTIFY_INIT          = 332
+	SYS_FANOTIFY_MARK          = 333
+	SYS_PRLIMIT64              = 334
+	SYS_NAME_TO_HANDLE_AT      = 335
+	SYS_OPEN_BY_HANDLE_AT      = 336
+	SYS_CLOCK_ADJTIME          = 337
+	SYS_SYNCFS                 = 338
+	SYS_SETNS                  = 339
+	SYS_PROCESS_VM_READV       = 340
+	SYS_PROCESS_VM_WRITEV      = 341
+	SYS_S390_RUNTIME_INSTR     = 342
+	SYS_KCMP                   = 343
+	SYS_FINIT_MODULE           = 344
+	SYS_SCHED_SETATTR          = 345
+	SYS_SCHED_GETATTR          = 346
+	SYS_RENAMEAT2              = 347
+	SYS_SECCOMP                = 348
+	SYS_GETRANDOM              = 349
+	SYS_MEMFD_CREATE           = 350
+	SYS_BPF                    = 351
+	SYS_S390_PCI_MMIO_WRITE    = 352
+	SYS_S390_PCI_MMIO_READ     = 353
+	SYS_EXECVEAT               = 354
+	SYS_USERFAULTFD            = 355
+	SYS_MEMBARRIER             = 356
+	SYS_RECVMMSG               = 357
+	SYS_SENDMMSG               = 358
+	SYS_SOCKET                 = 359
+	SYS_SOCKETPAIR             = 360
+	SYS_BIND                   = 361
+	SYS_CONNECT                = 362
+	SYS_LISTEN                 = 363
+	SYS_ACCEPT4                = 364
+	SYS_GETSOCKOPT             = 365
+	SYS_SETSOCKOPT             = 366
+	SYS_GETSOCKNAME            = 367
+	SYS_GETPEERNAME            = 368
+	SYS_SENDTO                 = 369
+	SYS_SENDMSG                = 370
+	SYS_RECVFROM               = 371
+	SYS_RECVMSG                = 372
+	SYS_SHUTDOWN               = 373
+	SYS_MLOCK2                 = 374
+	SYS_SELECT                 = 142
+	SYS_GETRLIMIT              = 191
+	SYS_LCHOWN                 = 198
+	SYS_GETUID                 = 199
+	SYS_GETGID                 = 200
+	SYS_GETEUID                = 201
+	SYS_GETEGID                = 202
+	SYS_SETREUID               = 203
+	SYS_SETREGID               = 204
+	SYS_GETGROUPS              = 205
+	SYS_SETGROUPS              = 206
+	SYS_FCHOWN                 = 207
+	SYS_SETRESUID              = 208
+	SYS_GETRESUID              = 209
+	SYS_SETRESGID              = 210
+	SYS_GETRESGID              = 211
+	SYS_CHOWN                  = 212
+	SYS_SETUID                 = 213
+	SYS_SETGID                 = 214
+	SYS_SETFSUID               = 215
+	SYS_SETFSGID               = 216
+	SYS_NEWFSTATAT             = 293
+)
diff --git a/src/syscall/ztypes_linux_s390x.go b/src/syscall/ztypes_linux_s390x.go
new file mode 100644
index 0000000..cdde478
--- /dev/null
+++ b/src/syscall/ztypes_linux_s390x.go
@@ -0,0 +1,620 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go | go run mkpost.go
+
+package syscall
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+	PathMax        = 0x1000
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+type Timex struct {
+	Modes     uint32
+	_         [4]byte
+	Offset    int64
+	Freq      int64
+	Maxerror  int64
+	Esterror  int64
+	Status    int32
+	_         [4]byte
+	Constant  int64
+	Precision int64
+	Tolerance int64
+	Time      Timeval
+	Tick      int64
+	Ppsfreq   int64
+	Jitter    int64
+	Shift     int32
+	_         [4]byte
+	Stabil    int64
+	Jitcnt    int64
+	Calcnt    int64
+	Errcnt    int64
+	Stbcnt    int64
+	Tai       int32
+	_         [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
+	_       int32
+	Rdev    uint64
+	Size    int64
+	Atim    Timespec
+	Mtim    Timespec
+	Ctim    Timespec
+	Blksize int64
+	Blocks  int64
+	_       [3]int64
+}
+
+type Statfs_t struct {
+	Type    uint32
+	Bsize   uint32
+	Blocks  uint64
+	Bfree   uint64
+	Bavail  uint64
+	Files   uint64
+	Ffree   uint64
+	Fsid    Fsid
+	Namelen uint32
+	Frsize  uint32
+	Flags   uint32
+	Spare   [4]uint32
+	_       [4]byte
+}
+
+type Dirent struct {
+	Ino    uint64
+	Off    int64
+	Reclen uint16
+	Type   uint8
+	Name   [256]uint8
+	_      [5]byte
+}
+
+type Fsid struct {
+	_ [2]int32
+}
+
+type Flock_t struct {
+	Type   int16
+	Whence int16
+	_      [4]byte
+	Start  int64
+	Len    int64
+	Pid    int32
+	_      [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]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
+	_          [4]byte
+	Iov        *Iovec
+	Iovlen     uint64
+	Control    *byte
+	Controllen uint64
+	Flags      int32
+	_          [4]byte
+}
+
+type Cmsghdr struct {
+	Len   uint64
+	Level int32
+	Type  int32
+}
+
+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
+	_              [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            = 0x27
+	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
+	_      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
+	_      [6]byte
+	Filter *SockFilter
+}
+
+type InotifyEvent struct {
+	Wd     int32
+	Mask   uint32
+	Cookie uint32
+	Len    uint32
+}
+
+const SizeofInotifyEvent = 0x10
+
+type PtraceRegs struct {
+	Psw                      PtracePsw
+	Gprs                     [16]uint64
+	Acrs                     [16]uint32
+	Orig_gpr2                uint64
+	Fp_regs                  PtraceFpregs
+	Per_info                 PtracePer
+	Ieee_instruction_pointer uint64
+}
+
+type PtracePsw struct {
+	Mask uint64
+	Addr uint64
+}
+
+type PtraceFpregs struct {
+	Fpc  uint32
+	_    [4]byte
+	Fprs [16]float64
+}
+
+type PtracePer struct {
+	Control_regs  [0]uint64
+	_             [24]byte
+	_             [8]byte
+	Starting_addr uint64
+	Ending_addr   uint64
+	Perc_atmid    uint16
+	_             [6]byte
+	Address       uint64
+	Access_id     uint8
+	_             [7]byte
+}
+
+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
+	_         [4]byte
+	Totalhigh uint64
+	Freehigh  uint64
+	Unit      uint32
+	_         [0]uint8
+	_         [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
+	_      [4]byte
+	Tinode uint64
+	Fname  [6]uint8
+	Fpack  [6]uint8
+	_      [4]byte
+}
+
+type EpollEvent struct {
+	Events uint32
+	_      int32
+	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
+	_      [3]byte
+	Ispeed uint32
+	Ospeed uint32
+}
+
+const (
+	IUCLC  = 0x200
+	OLCUC  = 0x2
+	TCGETS = 0x5401
+	TCSETS = 0x5402
+	XCASE  = 0x4
+)
diff --git a/src/syscall/ztypes_windows.go b/src/syscall/ztypes_windows.go
index e5c7325..191c6e6 100644
--- a/src/syscall/ztypes_windows.go
+++ b/src/syscall/ztypes_windows.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/syscall/ztypes_windows_386.go b/src/syscall/ztypes_windows_386.go
index 734ee6e..4f40a09 100644
--- a/src/syscall/ztypes_windows_386.go
+++ b/src/syscall/ztypes_windows_386.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/syscall/ztypes_windows_amd64.go b/src/syscall/ztypes_windows_amd64.go
index 78aa55b..7d45ddb 100644
--- a/src/syscall/ztypes_windows_amd64.go
+++ b/src/syscall/ztypes_windows_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/testing/allocs.go b/src/testing/allocs.go
index 9ec47bd..1eeb2d4 100644
--- a/src/testing/allocs.go
+++ b/src/testing/allocs.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -12,7 +12,7 @@ import (
 // Although the return value has type float64, it will always be an integral value.
 //
 // To compute the number of allocations, the function will first be run once as
-// a warm-up.  The average number of allocations over the specified number of
+// a warm-up. The average number of allocations over the specified number of
 // runs will then be measured and returned.
 //
 // AllocsPerRun sets GOMAXPROCS to 1 during its measurement and will restore
diff --git a/src/testing/allocs_test.go b/src/testing/allocs_test.go
index ec17daa..5b346aa 100644
--- a/src/testing/allocs_test.go
+++ b/src/testing/allocs_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/testing/benchmark.go b/src/testing/benchmark.go
index 85178c2..5d58b85 100644
--- a/src/testing/benchmark.go
+++ b/src/testing/benchmark.go
@@ -14,7 +14,7 @@ import (
 	"time"
 )
 
-var matchBenchmarks = flag.String("test.bench", "", "regular expression to select benchmarks to run")
+var matchBenchmarks = flag.String("test.bench", "", "regular expression per path component to select benchmarks to run")
 var benchTime = flag.Duration("test.benchtime", 1*time.Second, "approximate run time for each benchmark")
 var benchmarkMemory = flag.Bool("test.benchmem", false, "print memory allocations for benchmarks")
 
@@ -46,13 +46,17 @@ type InternalBenchmark struct {
 // affecting benchmark results.
 type B struct {
 	common
+	context          *benchContext
 	N                int
 	previousN        int           // number of iterations in the previous run
 	previousDuration time.Duration // total duration of the previous run
-	benchmark        InternalBenchmark
+	benchFunc        func(b *B)
+	benchTime        time.Duration
 	bytes            int64
+	missingBytes     bool // one of the subbenchmarks does not have bytes set.
 	timerOn          bool
 	showAllocResult  bool
+	hasSub           bool
 	result           BenchmarkResult
 	parallelism      int // RunParallel creates parallelism*GOMAXPROCS goroutines
 	// The initial states of memStats.Mallocs and memStats.TotalAlloc.
@@ -63,7 +67,7 @@ type B struct {
 	netBytes  uint64
 }
 
-// StartTimer starts timing a test.  This function is called automatically
+// StartTimer starts timing a test. This function is called automatically
 // before a benchmark starts, but it can also used to resume timing after
 // a call to StopTimer.
 func (b *B) StartTimer() {
@@ -76,7 +80,7 @@ func (b *B) StartTimer() {
 	}
 }
 
-// StopTimer stops timing a test.  This can be used to pause the timer
+// StopTimer stops timing a test. This can be used to pause the timer
 // while performing complex initialization that you don't
 // want to measure.
 func (b *B) StopTimer() {
@@ -132,7 +136,7 @@ func (b *B) runN(n int) {
 	b.parallelism = 1
 	b.ResetTimer()
 	b.StartTimer()
-	b.benchmark.F(b)
+	b.benchFunc(b)
 	b.StopTimer()
 	b.previousN = n
 	b.previousDuration = b.duration
@@ -185,32 +189,78 @@ func roundUp(n int) int {
 	}
 }
 
-// run times the benchmark function in a separate goroutine.
+// run1 runs the first iteration of benchFunc. It returns whether more
+// iterations of this benchmarks should be run.
+func (b *B) run1() bool {
+	if ctx := b.context; ctx != nil {
+		// Extend maxLen, if needed.
+		if n := len(b.name) + ctx.extLen + 1; n > ctx.maxLen {
+			ctx.maxLen = n + 8 // Add additional slack to avoid too many jumps in size.
+		}
+	}
+	go func() {
+		// Signal that we're done whether we return normally
+		// or by FailNow's runtime.Goexit.
+		defer func() {
+			b.signal <- true
+		}()
+
+		b.runN(1)
+	}()
+	<-b.signal
+	if b.failed {
+		fmt.Fprintf(b.w, "--- FAIL: %s\n%s", b.name, b.output)
+		return false
+	}
+	// Only print the output if we know we are not going to proceed.
+	// Otherwise it is printed in processBench.
+	if b.hasSub || b.finished {
+		tag := "BENCH"
+		if b.skipped {
+			tag = "SKIP"
+		}
+		if b.chatty && (len(b.output) > 0 || b.finished) {
+			b.trimOutput()
+			fmt.Fprintf(b.w, "--- %s: %s\n%s", tag, b.name, b.output)
+		}
+		return false
+	}
+	return true
+}
+
+// run executes the benchmark in a separate goroutine, including all of its
+// subbenchmarks. b must not have subbenchmarks.
 func (b *B) run() BenchmarkResult {
+	if b.context != nil {
+		// Running go test --test.bench
+		b.context.processBench(b) // Must call doBench.
+	} else {
+		// Running func Benchmark.
+		b.doBench()
+	}
+	return b.result
+}
+
+func (b *B) doBench() BenchmarkResult {
 	go b.launch()
 	<-b.signal
 	return b.result
 }
 
-// launch launches the benchmark function.  It gradually increases the number
+// launch launches the benchmark function. It gradually increases the number
 // of benchmark iterations until the benchmark runs for the requested benchtime.
-// It prints timing information in this form
-//		testing.BenchmarkHello	100000		19 ns/op
-// launch is run by the run function as a separate goroutine.
+// launch is run by the doBench function as a separate goroutine.
+// run1 must have been called on b.
 func (b *B) launch() {
-	// Run the benchmark for a single iteration in case it's expensive.
-	n := 1
-
 	// Signal that we're done whether we return normally
 	// or by FailNow's runtime.Goexit.
 	defer func() {
-		b.signal <- b
+		b.signal <- true
 	}()
 
-	b.runN(n)
 	// Run the benchmark for at least the specified amount of time.
-	d := *benchTime
-	for !b.failed && b.duration < d && n < 1e9 {
+	d := b.benchTime
+	for n := 1; !b.failed && b.duration < d && n < 1e9; {
 		last := n
 		// Predict required iterations.
 		if b.nsPerOp() == 0 {
@@ -299,12 +349,23 @@ func benchmarkName(name string, n int) string {
 	return name
 }
 
+type benchContext struct {
+	match *matcher
+
+	maxLen int // The largest recorded benchmark name.
+	extLen int // Maximum extension length.
+}
+
 // 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) {
+	runBenchmarksInternal(matchString, benchmarks)
+}
+
+func runBenchmarksInternal(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool {
 	// If no flag was specified, don't run benchmarks.
 	if len(*matchBenchmarks) == 0 {
-		return
+		return true
 	}
 	// Collect matching benchmarks and determine longest name.
 	maxprocs := 1
@@ -313,59 +374,144 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
 			maxprocs = procs
 		}
 	}
-	maxlen := 0
+	ctx := &benchContext{
+		match:  newMatcher(matchString, *matchBenchmarks, "-test.bench"),
+		extLen: len(benchmarkName("", maxprocs)),
+	}
 	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 {
+		if _, matched := ctx.match.fullName(nil, Benchmark.Name); matched {
 			bs = append(bs, Benchmark)
 			benchName := benchmarkName(Benchmark.Name, maxprocs)
-			if l := len(benchName); l > maxlen {
-				maxlen = l
+			if l := len(benchName) + ctx.extLen + 1; l > ctx.maxLen {
+				ctx.maxLen = l
 			}
 		}
 	}
-	for _, Benchmark := range bs {
-		for _, procs := range cpuList {
-			runtime.GOMAXPROCS(procs)
-			b := &B{
+	main := &B{
+		common: common{
+			name:   "Main",
+			w:      os.Stdout,
+			chatty: *chatty,
+		},
+		benchFunc: func(b *B) {
+			for _, Benchmark := range bs {
+				b.Run(Benchmark.Name, Benchmark.F)
+			}
+		},
+		benchTime: *benchTime,
+		context:   ctx,
+	}
+	main.runN(1)
+	return !main.failed
+}
+
+// processBench runs bench b for the configured CPU counts and prints the results.
+func (ctx *benchContext) processBench(b *B) {
+	for i, procs := range cpuList {
+		runtime.GOMAXPROCS(procs)
+		benchName := benchmarkName(b.name, procs)
+		fmt.Fprintf(b.w, "%-*s\t", ctx.maxLen, benchName)
+		// Recompute the running time for all but the first iteration.
+		if i > 0 {
+			b = &B{
 				common: common{
-					signal: make(chan interface{}),
+					signal: make(chan bool),
+					name:   b.name,
+					w:      b.w,
+					chatty: b.chatty,
 				},
-				benchmark: Benchmark,
-			}
-			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.
-				// We print it all, regardless, because we don't want to trim the reason
-				// the benchmark failed.
-				fmt.Printf("--- FAIL: %s\n%s", benchName, b.output)
-				continue
-			}
-			results := r.String()
-			if *benchmarkMemory || b.showAllocResult {
-				results += "\t" + r.MemString()
-			}
-			fmt.Println(results)
-			// Unlike with tests, we ignore the -chatty flag and always print output for
-			// benchmarks since the output generation time will skew the results.
-			if len(b.output) > 0 {
-				b.trimOutput()
-				fmt.Printf("--- BENCH: %s\n%s", benchName, b.output)
-			}
-			if p := runtime.GOMAXPROCS(-1); p != procs {
-				fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p)
+				benchFunc: b.benchFunc,
+				benchTime: b.benchTime,
 			}
+			b.run1()
+		}
+		r := b.doBench()
+		if b.failed {
+			// The output could be very long here, but probably isn't.
+			// We print it all, regardless, because we don't want to trim the reason
+			// the benchmark failed.
+			fmt.Fprintf(b.w, "--- FAIL: %s\n%s", benchName, b.output)
+			continue
+		}
+		results := r.String()
+		if *benchmarkMemory || b.showAllocResult {
+			results += "\t" + r.MemString()
+		}
+		fmt.Fprintln(b.w, results)
+		// Unlike with tests, we ignore the -chatty flag and always print output for
+		// benchmarks since the output generation time will skew the results.
+		if len(b.output) > 0 {
+			b.trimOutput()
+			fmt.Fprintf(b.w, "--- BENCH: %s\n%s", benchName, b.output)
+		}
+		if p := runtime.GOMAXPROCS(-1); p != procs {
+			fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p)
 		}
 	}
 }
 
+// Run benchmarks f as a subbenchmark with the given name. It reports
+// whether there were any failures.
+//
+// A subbenchmark is like any other benchmark. A benchmark that calls Run at
+// least once will not be measured itself and will be called once with N=1.
+func (b *B) Run(name string, f func(b *B)) bool {
+	// Since b has subbenchmarks, we will no longer run it as a benchmark itself.
+	// Release the lock and acquire it on exit to ensure locks stay paired.
+	b.hasSub = true
+	benchmarkLock.Unlock()
+	defer benchmarkLock.Lock()
+
+	benchName, ok := b.name, true
+	if b.context != nil {
+		benchName, ok = b.context.match.fullName(&b.common, name)
+	}
+	if !ok {
+		return true
+	}
+	sub := &B{
+		common: common{
+			signal: make(chan bool),
+			name:   benchName,
+			parent: &b.common,
+			level:  b.level + 1,
+			w:      b.w,
+			chatty: b.chatty,
+		},
+		benchFunc: f,
+		benchTime: b.benchTime,
+		context:   b.context,
+	}
+	if sub.run1() {
+		sub.run()
+	}
+	b.add(sub.result)
+	return !sub.failed
+}
+
+// add simulates running benchmarks in sequence in a single iteration. It is
+// used to give some meaningful results in case func Benchmark is used in
+// combination with Run.
+func (b *B) add(other BenchmarkResult) {
+	r := &b.result
+	// The aggregated BenchmarkResults resemble running all subbenchmarks as
+	// in sequence in a single benchmark.
+	r.N = 1
+	r.T += time.Duration(other.NsPerOp())
+	if other.Bytes == 0 {
+		// Summing Bytes is meaningless in aggregate if not all subbenchmarks
+		// set it.
+		b.missingBytes = true
+		r.Bytes = 0
+	}
+	if !b.missingBytes {
+		r.Bytes += other.Bytes
+	}
+	r.MemAllocs += uint64(other.AllocsPerOp())
+	r.MemBytes += uint64(other.AllocedBytesPerOp())
+}
+
 // trimOutput shortens the output from a benchmark, which can be very long.
 func (b *B) trimOutput() {
 	// The output is likely to appear multiple times because the benchmark
@@ -416,8 +562,11 @@ func (pb *PB) Next() bool {
 // The body function will be run in each goroutine. It should set up any
 // goroutine-local state and then iterate until pb.Next returns false.
 // It should not use the StartTimer, StopTimer, or ResetTimer functions,
-// because they have global effect.
+// because they have global effect. It should also not call Run.
 func (b *B) RunParallel(body func(*PB)) {
+	if b.N == 0 {
+		return // Nothing to do when probing.
+	}
 	// Calculate grain size as number of iterations that take ~100µs.
 	// 100µs is enough to amortize the overhead and provide sufficient
 	// dynamic load balancing.
@@ -466,12 +615,24 @@ func (b *B) SetParallelism(p int) {
 
 // Benchmark benchmarks a single function. Useful for creating
 // custom benchmarks that do not use the "go test" command.
+//
+// If f calls Run, the result will be an estimate of running all its
+// subbenchmarks that don't call Run in sequence in a single benchmark.
 func Benchmark(f func(b *B)) BenchmarkResult {
 	b := &B{
 		common: common{
-			signal: make(chan interface{}),
+			signal: make(chan bool),
+			w:      discard{},
 		},
-		benchmark: InternalBenchmark{"", f},
+		benchFunc: f,
+		benchTime: *benchTime,
+	}
+	if !b.run1() {
+		return BenchmarkResult{}
 	}
 	return b.run()
 }
+
+type discard struct{}
+
+func (discard) Write(b []byte) (n int, err error) { return len(b), nil }
diff --git a/src/testing/example.go b/src/testing/example.go
index 30baf27..fd8343f 100644
--- a/src/testing/example.go
+++ b/src/testing/example.go
@@ -9,14 +9,16 @@ import (
 	"fmt"
 	"io"
 	"os"
+	"sort"
 	"strings"
 	"time"
 )
 
 type InternalExample struct {
-	Name   string
-	F      func()
-	Output string
+	Name      string
+	F         func()
+	Output    string
+	Unordered bool
 }
 
 func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
@@ -41,6 +43,12 @@ func RunExamples(matchString func(pat, str string) (bool, error), examples []Int
 	return
 }
 
+func sortLines(output string) string {
+	lines := strings.Split(output, "\n")
+	sort.Strings(lines)
+	return strings.Join(lines, "\n")
+}
+
 func runExample(eg InternalExample) (ok bool) {
 	if *chatty {
 		fmt.Printf("=== RUN   %s\n", eg.Name)
@@ -80,8 +88,16 @@ func runExample(eg InternalExample) (ok bool) {
 
 		var fail string
 		err := recover()
-		if g, e := strings.TrimSpace(out), strings.TrimSpace(eg.Output); g != e && err == nil {
-			fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", g, e)
+		got := strings.TrimSpace(out)
+		want := strings.TrimSpace(eg.Output)
+		if eg.Unordered {
+			if sortLines(got) != sortLines(want) && err == nil {
+				fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", out, eg.Output)
+			}
+		} else {
+			if got != want && err == nil {
+				fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want)
+			}
 		}
 		if fail != "" || err != nil {
 			fmt.Printf("--- FAIL: %s (%s)\n%s", eg.Name, dstr, fail)
diff --git a/src/testing/iotest/reader.go b/src/testing/iotest/reader.go
index a5bccca..8d82018 100644
--- a/src/testing/iotest/reader.go
+++ b/src/testing/iotest/reader.go
@@ -71,7 +71,7 @@ func (r *dataErrReader) Read(p []byte) (n int, err error) {
 var ErrTimeout = errors.New("timeout")
 
 // TimeoutReader returns ErrTimeout on the second read
-// with no data.  Subsequent calls to read succeed.
+// with no data. Subsequent calls to read succeed.
 func TimeoutReader(r io.Reader) io.Reader { return &timeoutReader{r, 0} }
 
 type timeoutReader struct {
diff --git a/src/testing/match.go b/src/testing/match.go
new file mode 100644
index 0000000..7751035
--- /dev/null
+++ b/src/testing/match.go
@@ -0,0 +1,167 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing
+
+import (
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+	"sync"
+)
+
+// matcher sanitizes, uniques, and filters names of subtests and subbenchmarks.
+type matcher struct {
+	filter    []string
+	matchFunc func(pat, str string) (bool, error)
+
+	mu       sync.Mutex
+	subNames map[string]int64
+}
+
+// TODO: fix test_main to avoid race and improve caching, also allowing to
+// eliminate this Mutex.
+var matchMutex sync.Mutex
+
+func newMatcher(matchString func(pat, str string) (bool, error), patterns, name string) *matcher {
+	var filter []string
+	if patterns != "" {
+		filter = splitRegexp(patterns)
+		for i, s := range filter {
+			filter[i] = rewrite(s)
+		}
+		// Verify filters before doing any processing.
+		for i, s := range filter {
+			if _, err := matchString(s, "non-empty"); err != nil {
+				fmt.Fprintf(os.Stderr, "testing: invalid regexp for element %d of %s (%q): %s\n", i, name, s, err)
+				os.Exit(1)
+			}
+		}
+	}
+	return &matcher{
+		filter:    filter,
+		matchFunc: matchString,
+		subNames:  map[string]int64{},
+	}
+}
+
+func (m *matcher) fullName(c *common, subname string) (name string, ok bool) {
+	name = subname
+
+	m.mu.Lock()
+	defer m.mu.Unlock()
+
+	if c != nil && c.level > 0 {
+		name = m.unique(c.name, rewrite(subname))
+	}
+
+	matchMutex.Lock()
+	defer matchMutex.Unlock()
+
+	// We check the full array of paths each time to allow for the case that
+	// a pattern contains a '/'.
+	for i, s := range strings.Split(name, "/") {
+		if i >= len(m.filter) {
+			break
+		}
+		if ok, _ := m.matchFunc(m.filter[i], s); !ok {
+			return name, false
+		}
+	}
+	return name, true
+}
+
+func splitRegexp(s string) []string {
+	a := make([]string, 0, strings.Count(s, "/"))
+	cs := 0
+	cp := 0
+	for i := 0; i < len(s); {
+		switch s[i] {
+		case '[':
+			cs++
+		case ']':
+			if cs--; cs < 0 { // An unmatched ']' is legal.
+				cs = 0
+			}
+		case '(':
+			if cs == 0 {
+				cp++
+			}
+		case ')':
+			if cs == 0 {
+				cp--
+			}
+		case '\\':
+			i++
+		case '/':
+			if cs == 0 && cp == 0 {
+				a = append(a, s[:i])
+				s = s[i+1:]
+				i = 0
+				continue
+			}
+		}
+		i++
+	}
+	return append(a, s)
+}
+
+// unique creates a unique name for the given parent and subname by affixing it
+// with one ore more counts, if necessary.
+func (m *matcher) unique(parent, subname string) string {
+	name := fmt.Sprintf("%s/%s", parent, subname)
+	empty := subname == ""
+	for {
+		next, exists := m.subNames[name]
+		if !empty && !exists {
+			m.subNames[name] = 1 // next count is 1
+			return name
+		}
+		// Name was already used. We increment with the count and append a
+		// string with the count.
+		m.subNames[name] = next + 1
+
+		// Add a count to guarantee uniqueness.
+		name = fmt.Sprintf("%s#%02d", name, next)
+		empty = false
+	}
+}
+
+// rewrite rewrites a subname to having only printable characters and no white
+// space.
+func rewrite(s string) string {
+	b := []byte{}
+	for _, r := range s {
+		switch {
+		case isSpace(r):
+			b = append(b, '_')
+		case !strconv.IsPrint(r):
+			s := strconv.QuoteRune(r)
+			b = append(b, s[1:len(s)-1]...)
+		default:
+			b = append(b, string(r)...)
+		}
+	}
+	return string(b)
+}
+
+func isSpace(r rune) bool {
+	if r < 0x2000 {
+		switch r {
+		// Note: not the same as Unicode Z class.
+		case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0, 0x1680:
+			return true
+		}
+	} else {
+		if r <= 0x200a {
+			return true
+		}
+		switch r {
+		case 0x2028, 0x2029, 0x202f, 0x205f, 0x3000:
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/testing/match_test.go b/src/testing/match_test.go
new file mode 100644
index 0000000..8c1c5f4
--- /dev/null
+++ b/src/testing/match_test.go
@@ -0,0 +1,185 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing
+
+import (
+	"reflect"
+	"regexp"
+	"unicode"
+)
+
+// Verify that our IsSpace agrees with unicode.IsSpace.
+func TestIsSpace(t *T) {
+	n := 0
+	for r := rune(0); r <= unicode.MaxRune; r++ {
+		if isSpace(r) != unicode.IsSpace(r) {
+			t.Errorf("IsSpace(%U)=%t incorrect", r, isSpace(r))
+			n++
+			if n > 10 {
+				return
+			}
+		}
+	}
+}
+
+func TestSplitRegexp(t *T) {
+	res := func(s ...string) []string { return s }
+	testCases := []struct {
+		pattern string
+		result  []string
+	}{
+		// Correct patterns
+		// If a regexp pattern is correct, all split regexps need to be correct
+		// as well.
+		{"", res("")},
+		{"/", res("", "")},
+		{"//", res("", "", "")},
+		{"A", res("A")},
+		{"A/B", res("A", "B")},
+		{"A/B/", res("A", "B", "")},
+		{"/A/B/", res("", "A", "B", "")},
+		{"[A]/(B)", res("[A]", "(B)")},
+		{"[/]/[/]", res("[/]", "[/]")},
+		{"[/]/[:/]", res("[/]", "[:/]")},
+		{"/]", res("", "]")},
+		{"]/", res("]", "")},
+		{"]/[/]", res("]", "[/]")},
+		{`([)/][(])`, res(`([)/][(])`)},
+		{"[(]/[)]", res("[(]", "[)]")},
+
+		// Faulty patterns
+		// Errors in original should produce at least one faulty regexp in results.
+		{")/", res(")/")},
+		{")/(/)", res(")/(", ")")},
+		{"a[/)b", res("a[/)b")},
+		{"(/]", res("(/]")},
+		{"(/", res("(/")},
+		{"[/]/[/", res("[/]", "[/")},
+		{`\p{/}`, res(`\p{`, "}")},
+		{`\p/`, res(`\p`, "")},
+		{`[[:/:]]`, res(`[[:/:]]`)},
+	}
+	for _, tc := range testCases {
+		a := splitRegexp(tc.pattern)
+		if !reflect.DeepEqual(a, tc.result) {
+			t.Errorf("splitRegexp(%q) = %#v; want %#v", tc.pattern, a, tc.result)
+		}
+
+		// If there is any error in the pattern, one of the returned subpatterns
+		// needs to have an error as well.
+		if _, err := regexp.Compile(tc.pattern); err != nil {
+			ok := true
+			for _, re := range a {
+				if _, err := regexp.Compile(re); err != nil {
+					ok = false
+				}
+			}
+			if ok {
+				t.Errorf("%s: expected error in any of %q", tc.pattern, a)
+			}
+		}
+	}
+}
+
+func TestMatcher(t *T) {
+	testCases := []struct {
+		pattern     string
+		parent, sub string
+		ok          bool
+	}{
+		// Behavior without subtests.
+		{"", "", "TestFoo", true},
+		{"TestFoo", "", "TestFoo", true},
+		{"TestFoo/", "", "TestFoo", true},
+		{"TestFoo/bar/baz", "", "TestFoo", true},
+		{"TestFoo", "", "TestBar", false},
+		{"TestFoo/", "", "TestBar", false},
+		{"TestFoo/bar/baz", "", "TestBar/bar/baz", false},
+
+		// with subtests
+		{"", "TestFoo", "x", true},
+		{"TestFoo", "TestFoo", "x", true},
+		{"TestFoo/", "TestFoo", "x", true},
+		{"TestFoo/bar/baz", "TestFoo", "bar", true},
+		// Subtest with a '/' in its name still allows for copy and pasted names
+		// to match.
+		{"TestFoo/bar/baz", "TestFoo", "bar/baz", true},
+		{"TestFoo/bar/baz", "TestFoo/bar", "baz", true},
+		{"TestFoo/bar/baz", "TestFoo", "x", false},
+		{"TestFoo", "TestBar", "x", false},
+		{"TestFoo/", "TestBar", "x", false},
+		{"TestFoo/bar/baz", "TestBar", "x/bar/baz", false},
+
+		// subtests only
+		{"", "TestFoo", "x", true},
+		{"/", "TestFoo", "x", true},
+		{"./", "TestFoo", "x", true},
+		{"./.", "TestFoo", "x", true},
+		{"/bar/baz", "TestFoo", "bar", true},
+		{"/bar/baz", "TestFoo", "bar/baz", true},
+		{"//baz", "TestFoo", "bar/baz", true},
+		{"//", "TestFoo", "bar/baz", true},
+		{"/bar/baz", "TestFoo/bar", "baz", true},
+		{"//foo", "TestFoo", "bar/baz", false},
+		{"/bar/baz", "TestFoo", "x", false},
+		{"/bar/baz", "TestBar", "x/bar/baz", false},
+	}
+
+	for _, tc := range testCases {
+		m := newMatcher(regexp.MatchString, tc.pattern, "-test.run")
+
+		parent := &common{name: tc.parent}
+		if tc.parent != "" {
+			parent.level = 1
+		}
+		if n, ok := m.fullName(parent, tc.sub); ok != tc.ok {
+			t.Errorf("for pattern %q, fullName(parent=%q, sub=%q) = %q, ok %v; want ok %v",
+				tc.pattern, tc.parent, tc.sub, n, ok, tc.ok)
+		}
+	}
+}
+
+func TestNaming(t *T) {
+	m := newMatcher(regexp.MatchString, "", "")
+
+	parent := &common{name: "x", level: 1} // top-level test.
+
+	// Rig the matcher with some preloaded values.
+	m.subNames["x/b"] = 1000
+
+	testCases := []struct {
+		name, want string
+	}{
+		// Uniqueness
+		{"", "x/#00"},
+		{"", "x/#01"},
+
+		{"t", "x/t"},
+		{"t", "x/t#01"},
+		{"t", "x/t#02"},
+
+		{"a#01", "x/a#01"}, // user has subtest with this name.
+		{"a", "x/a"},       // doesn't conflict with this name.
+		{"a", "x/a#01#01"}, // conflict, add disambiguating string.
+		{"a", "x/a#02"},    // This string is claimed now, so resume
+		{"a", "x/a#03"},    // with counting.
+		{"a#02", "x/a#02#01"},
+
+		{"b", "x/b#1000"}, // rigged, see above
+		{"b", "x/b#1001"},
+
+		// // Sanitizing
+		{"A:1 B:2", "x/A:1_B:2"},
+		{"s\t\r\u00a0", "x/s___"},
+		{"\x01", `x/\x01`},
+		{"\U0010ffff", `x/\U0010ffff`},
+	}
+
+	for i, tc := range testCases {
+		if got, _ := m.fullName(parent, tc.name); got != tc.want {
+			t.Errorf("%d:%s: got %q; want %q", i, tc.name, got, tc.want)
+		}
+	}
+}
diff --git a/src/testing/quick/quick.go b/src/testing/quick/quick.go
index 187195c..798d41a 100644
--- a/src/testing/quick/quick.go
+++ b/src/testing/quick/quick.go
@@ -239,8 +239,8 @@ func (s *CheckEqualError) Error() string {
 }
 
 // Check looks for an input to f, any function that returns bool,
-// such that f returns false.  It calls f repeatedly, with arbitrary
-// values for each argument.  If f returns false on a given input,
+// such that f returns false. It calls f repeatedly, with arbitrary
+// values for each argument. If f returns false on a given input,
 // Check returns that input as a *CheckError.
 // For example:
 //
@@ -253,24 +253,21 @@ func (s *CheckEqualError) Error() string {
 // 			t.Error(err)
 // 		}
 // 	}
-func Check(f interface{}, config *Config) (err error) {
+func Check(f interface{}, config *Config) error {
 	if config == nil {
 		config = &defaultConfig
 	}
 
 	fVal, fType, ok := functionAndType(f)
 	if !ok {
-		err = SetupError("argument is not a function")
-		return
+		return SetupError("argument is not a function")
 	}
 
 	if fType.NumOut() != 1 {
-		err = SetupError("function does not return one value")
-		return
+		return SetupError("function does not return one value")
 	}
 	if fType.Out(0).Kind() != reflect.Bool {
-		err = SetupError("function does not return a bool")
-		return
+		return SetupError("function does not return a bool")
 	}
 
 	arguments := make([]reflect.Value, fType.NumIn())
@@ -278,43 +275,39 @@ func Check(f interface{}, config *Config) (err error) {
 	maxCount := config.getMaxCount()
 
 	for i := 0; i < maxCount; i++ {
-		err = arbitraryValues(arguments, fType, config, rand)
+		err := arbitraryValues(arguments, fType, config, rand)
 		if err != nil {
-			return
+			return err
 		}
 
 		if !fVal.Call(arguments)[0].Bool() {
-			err = &CheckError{i + 1, toInterfaces(arguments)}
-			return
+			return &CheckError{i + 1, toInterfaces(arguments)}
 		}
 	}
 
-	return
+	return nil
 }
 
 // CheckEqual looks for an input on which f and g return different results.
 // It calls f and g repeatedly with arbitrary values for each argument.
 // If f and g return different answers, CheckEqual returns a *CheckEqualError
 // describing the input and the outputs.
-func CheckEqual(f, g interface{}, config *Config) (err error) {
+func CheckEqual(f, g interface{}, config *Config) error {
 	if config == nil {
 		config = &defaultConfig
 	}
 
 	x, xType, ok := functionAndType(f)
 	if !ok {
-		err = SetupError("f is not a function")
-		return
+		return SetupError("f is not a function")
 	}
 	y, yType, ok := functionAndType(g)
 	if !ok {
-		err = SetupError("g is not a function")
-		return
+		return SetupError("g is not a function")
 	}
 
 	if xType != yType {
-		err = SetupError("functions have different types")
-		return
+		return SetupError("functions have different types")
 	}
 
 	arguments := make([]reflect.Value, xType.NumIn())
@@ -322,21 +315,20 @@ func CheckEqual(f, g interface{}, config *Config) (err error) {
 	maxCount := config.getMaxCount()
 
 	for i := 0; i < maxCount; i++ {
-		err = arbitraryValues(arguments, xType, config, rand)
+		err := arbitraryValues(arguments, xType, config, rand)
 		if err != nil {
-			return
+			return err
 		}
 
 		xOut := toInterfaces(x.Call(arguments))
 		yOut := toInterfaces(y.Call(arguments))
 
 		if !reflect.DeepEqual(xOut, yOut) {
-			err = &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
-			return
+			return &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut}
 		}
 	}
 
-	return
+	return nil
 }
 
 // arbitraryValues writes Values to args such that args contains Values
diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go
new file mode 100644
index 0000000..2a24aaa
--- /dev/null
+++ b/src/testing/sub_test.go
@@ -0,0 +1,517 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testing
+
+import (
+	"bytes"
+	"regexp"
+	"strings"
+	"sync/atomic"
+	"time"
+)
+
+func TestTestContext(t *T) {
+	const (
+		add1 = 0
+		done = 1
+	)
+	// After each of the calls are applied to the context, the
+	type call struct {
+		typ int // run or done
+		// result from applying the call
+		running int
+		waiting int
+		started bool
+	}
+	testCases := []struct {
+		max int
+		run []call
+	}{{
+		max: 1,
+		run: []call{
+			{typ: add1, running: 1, waiting: 0, started: true},
+			{typ: done, running: 0, waiting: 0, started: false},
+		},
+	}, {
+		max: 1,
+		run: []call{
+			{typ: add1, running: 1, waiting: 0, started: true},
+			{typ: add1, running: 1, waiting: 1, started: false},
+			{typ: done, running: 1, waiting: 0, started: true},
+			{typ: done, running: 0, waiting: 0, started: false},
+			{typ: add1, running: 1, waiting: 0, started: true},
+		},
+	}, {
+		max: 3,
+		run: []call{
+			{typ: add1, running: 1, waiting: 0, started: true},
+			{typ: add1, running: 2, waiting: 0, started: true},
+			{typ: add1, running: 3, waiting: 0, started: true},
+			{typ: add1, running: 3, waiting: 1, started: false},
+			{typ: add1, running: 3, waiting: 2, started: false},
+			{typ: add1, running: 3, waiting: 3, started: false},
+			{typ: done, running: 3, waiting: 2, started: true},
+			{typ: add1, running: 3, waiting: 3, started: false},
+			{typ: done, running: 3, waiting: 2, started: true},
+			{typ: done, running: 3, waiting: 1, started: true},
+			{typ: done, running: 3, waiting: 0, started: true},
+			{typ: done, running: 2, waiting: 0, started: false},
+			{typ: done, running: 1, waiting: 0, started: false},
+			{typ: done, running: 0, waiting: 0, started: false},
+		},
+	}}
+	for i, tc := range testCases {
+		ctx := &testContext{
+			startParallel: make(chan bool),
+			maxParallel:   tc.max,
+		}
+		for j, call := range tc.run {
+			doCall := func(f func()) chan bool {
+				done := make(chan bool)
+				go func() {
+					f()
+					done <- true
+				}()
+				return done
+			}
+			started := false
+			switch call.typ {
+			case add1:
+				signal := doCall(ctx.waitParallel)
+				select {
+				case <-signal:
+					started = true
+				case ctx.startParallel <- true:
+					<-signal
+				}
+			case done:
+				signal := doCall(ctx.release)
+				select {
+				case <-signal:
+				case <-ctx.startParallel:
+					started = true
+					<-signal
+				}
+			}
+			if started != call.started {
+				t.Errorf("%d:%d:started: got %v; want %v", i, j, started, call.started)
+			}
+			if ctx.running != call.running {
+				t.Errorf("%d:%d:running: got %v; want %v", i, j, ctx.running, call.running)
+			}
+			if ctx.numWaiting != call.waiting {
+				t.Errorf("%d:%d:waiting: got %v; want %v", i, j, ctx.numWaiting, call.waiting)
+			}
+		}
+	}
+}
+
+func TestTRun(t *T) {
+	realTest := t
+	testCases := []struct {
+		desc   string
+		ok     bool
+		maxPar int
+		chatty bool
+		output string
+		f      func(*T)
+	}{{
+		desc:   "failnow skips future sequential and parallel tests at same level",
+		ok:     false,
+		maxPar: 1,
+		output: `
+--- FAIL: failnow skips future sequential and parallel tests at same level (N.NNs)
+    --- FAIL: failnow skips future sequential and parallel tests at same level/#00 (N.NNs)
+    `,
+		f: func(t *T) {
+			ranSeq := false
+			ranPar := false
+			t.Run("", func(t *T) {
+				t.Run("par", func(t *T) {
+					t.Parallel()
+					ranPar = true
+				})
+				t.Run("seq", func(t *T) {
+					ranSeq = true
+				})
+				t.FailNow()
+				t.Run("seq", func(t *T) {
+					realTest.Error("test must be skipped")
+				})
+				t.Run("par", func(t *T) {
+					t.Parallel()
+					realTest.Error("test must be skipped.")
+				})
+			})
+			if !ranPar {
+				realTest.Error("parallel test was not run")
+			}
+			if !ranSeq {
+				realTest.Error("sequential test was not run")
+			}
+		},
+	}, {
+		desc:   "failure in parallel test propagates upwards",
+		ok:     false,
+		maxPar: 1,
+		output: `
+--- FAIL: failure in parallel test propagates upwards (N.NNs)
+    --- FAIL: failure in parallel test propagates upwards/#00 (N.NNs)
+        --- FAIL: failure in parallel test propagates upwards/#00/par (N.NNs)
+		`,
+		f: func(t *T) {
+			t.Run("", func(t *T) {
+				t.Parallel()
+				t.Run("par", func(t *T) {
+					t.Parallel()
+					t.Fail()
+				})
+			})
+		},
+	}, {
+		desc:   "skipping without message, chatty",
+		ok:     true,
+		chatty: true,
+		output: `
+=== RUN   skipping without message, chatty
+--- SKIP: skipping without message, chatty (N.NNs)`,
+		f: func(t *T) { t.SkipNow() },
+	}, {
+		desc:   "chatty with recursion",
+		ok:     true,
+		chatty: true,
+		output: `
+=== RUN   chatty with recursion
+=== RUN   chatty with recursion/#00
+=== RUN   chatty with recursion/#00/#00
+--- PASS: chatty with recursion (N.NNs)
+    --- PASS: chatty with recursion/#00 (N.NNs)
+        --- PASS: chatty with recursion/#00/#00 (N.NNs)`,
+		f: func(t *T) {
+			t.Run("", func(t *T) {
+				t.Run("", func(t *T) {})
+			})
+		},
+	}, {
+		desc: "skipping without message, not chatty",
+		ok:   true,
+		f:    func(t *T) { t.SkipNow() },
+	}, {
+		desc: "skipping after error",
+		output: `
+--- FAIL: skipping after error (N.NNs)
+	sub_test.go:NNN: an error
+	sub_test.go:NNN: skipped`,
+		f: func(t *T) {
+			t.Error("an error")
+			t.Skip("skipped")
+		},
+	}, {
+		desc:   "use Run to locally synchronize parallelism",
+		ok:     true,
+		maxPar: 1,
+		f: func(t *T) {
+			var count uint32
+			t.Run("waitGroup", func(t *T) {
+				for i := 0; i < 4; i++ {
+					t.Run("par", func(t *T) {
+						t.Parallel()
+						atomic.AddUint32(&count, 1)
+					})
+				}
+			})
+			if count != 4 {
+				t.Errorf("count was %d; want 4", count)
+			}
+		},
+	}, {
+		desc: "alternate sequential and parallel",
+		// Sequential tests should partake in the counting of running threads.
+		// Otherwise, if one runs parallel subtests in sequential tests that are
+		// itself subtests of parallel tests, the counts can get askew.
+		ok:     true,
+		maxPar: 1,
+		f: func(t *T) {
+			t.Run("a", func(t *T) {
+				t.Parallel()
+				t.Run("b", func(t *T) {
+					// Sequential: ensure running count is decremented.
+					t.Run("c", func(t *T) {
+						t.Parallel()
+					})
+
+				})
+			})
+		},
+	}, {
+		desc: "alternate sequential and parallel 2",
+		// Sequential tests should partake in the counting of running threads.
+		// Otherwise, if one runs parallel subtests in sequential tests that are
+		// itself subtests of parallel tests, the counts can get askew.
+		ok:     true,
+		maxPar: 2,
+		f: func(t *T) {
+			for i := 0; i < 2; i++ {
+				t.Run("a", func(t *T) {
+					t.Parallel()
+					time.Sleep(time.Nanosecond)
+					for i := 0; i < 2; i++ {
+						t.Run("b", func(t *T) {
+							time.Sleep(time.Nanosecond)
+							for i := 0; i < 2; i++ {
+								t.Run("c", func(t *T) {
+									t.Parallel()
+									time.Sleep(time.Nanosecond)
+								})
+							}
+
+						})
+					}
+				})
+			}
+		},
+	}, {
+		desc:   "stress test",
+		ok:     true,
+		maxPar: 4,
+		f: func(t *T) {
+			t.Parallel()
+			for i := 0; i < 12; i++ {
+				t.Run("a", func(t *T) {
+					t.Parallel()
+					time.Sleep(time.Nanosecond)
+					for i := 0; i < 12; i++ {
+						t.Run("b", func(t *T) {
+							time.Sleep(time.Nanosecond)
+							for i := 0; i < 12; i++ {
+								t.Run("c", func(t *T) {
+									t.Parallel()
+									time.Sleep(time.Nanosecond)
+									t.Run("d1", func(t *T) {})
+									t.Run("d2", func(t *T) {})
+									t.Run("d3", func(t *T) {})
+									t.Run("d4", func(t *T) {})
+								})
+							}
+						})
+					}
+				})
+			}
+		},
+	}, {
+		desc:   "skip output",
+		ok:     true,
+		maxPar: 4,
+		f: func(t *T) {
+			t.Skip()
+		},
+	}, {
+		desc:   "panic on goroutine fail after test exit",
+		ok:     false,
+		maxPar: 4,
+		f: func(t *T) {
+			ch := make(chan bool)
+			t.Run("", func(t *T) {
+				go func() {
+					<-ch
+					defer func() {
+						if r := recover(); r == nil {
+							realTest.Errorf("expected panic")
+						}
+						ch <- true
+					}()
+					t.Errorf("failed after success")
+				}()
+			})
+			ch <- true
+			<-ch
+		},
+	}}
+	for _, tc := range testCases {
+		ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", ""))
+		buf := &bytes.Buffer{}
+		root := &T{
+			common: common{
+				signal: make(chan bool),
+				name:   "Test",
+				w:      buf,
+				chatty: tc.chatty,
+			},
+			context: ctx,
+		}
+		ok := root.Run(tc.desc, tc.f)
+		ctx.release()
+
+		if ok != tc.ok {
+			t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok)
+		}
+		if ok != !root.Failed() {
+			t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
+		}
+		if ctx.running != 0 || ctx.numWaiting != 0 {
+			t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, ctx.running, ctx.numWaiting)
+		}
+		got := strings.TrimSpace(buf.String())
+		want := strings.TrimSpace(tc.output)
+		re := makeRegexp(want)
+		if ok, err := regexp.MatchString(re, got); !ok || err != nil {
+			t.Errorf("%s:ouput:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
+		}
+	}
+}
+
+func TestBRun(t *T) {
+	work := func(b *B) {
+		for i := 0; i < b.N; i++ {
+			time.Sleep(time.Nanosecond)
+		}
+	}
+	testCases := []struct {
+		desc   string
+		failed bool
+		chatty bool
+		output string
+		f      func(*B)
+	}{{
+		desc: "simulate sequential run of subbenchmarks.",
+		f: func(b *B) {
+			b.Run("", func(b *B) { work(b) })
+			time1 := b.result.NsPerOp()
+			b.Run("", func(b *B) { work(b) })
+			time2 := b.result.NsPerOp()
+			if time1 >= time2 {
+				t.Errorf("no time spent in benchmark t1 >= t2 (%d >= %d)", time1, time2)
+			}
+		},
+	}, {
+		desc: "bytes set by all benchmarks",
+		f: func(b *B) {
+			b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+			b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+			if b.result.Bytes != 20 {
+				t.Errorf("bytes: got: %d; want 20", b.result.Bytes)
+			}
+		},
+	}, {
+		desc: "bytes set by some benchmarks",
+		// In this case the bytes result is meaningless, so it must be 0.
+		f: func(b *B) {
+			b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+			b.Run("", func(b *B) { work(b) })
+			b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+			if b.result.Bytes != 0 {
+				t.Errorf("bytes: got: %d; want 0", b.result.Bytes)
+			}
+		},
+	}, {
+		desc:   "failure carried over to root",
+		failed: true,
+		output: "--- FAIL: root",
+		f:      func(b *B) { b.Fail() },
+	}, {
+		desc:   "skipping without message, chatty",
+		chatty: true,
+		output: "--- SKIP: root",
+		f:      func(b *B) { b.SkipNow() },
+	}, {
+		desc:   "skipping with message, chatty",
+		chatty: true,
+		output: `
+--- SKIP: root
+	sub_test.go:NNN: skipping`,
+		f: func(b *B) { b.Skip("skipping") },
+	}, {
+		desc:   "chatty with recursion",
+		chatty: true,
+		f: func(b *B) {
+			b.Run("", func(b *B) {
+				b.Run("", func(b *B) {})
+			})
+		},
+	}, {
+		desc: "skipping without message, not chatty",
+		f:    func(b *B) { b.SkipNow() },
+	}, {
+		desc:   "skipping after error",
+		failed: true,
+		output: `
+--- FAIL: root
+	sub_test.go:NNN: an error
+	sub_test.go:NNN: skipped`,
+		f: func(b *B) {
+			b.Error("an error")
+			b.Skip("skipped")
+		},
+	}, {
+		desc: "memory allocation",
+		f: func(b *B) {
+			const bufSize = 256
+			alloc := func(b *B) {
+				var buf [bufSize]byte
+				for i := 0; i < b.N; i++ {
+					_ = append([]byte(nil), buf[:]...)
+				}
+			}
+			b.Run("", func(b *B) { alloc(b) })
+			b.Run("", func(b *B) { alloc(b) })
+			// runtime.MemStats sometimes reports more allocations than the
+			// benchmark is responsible for. Luckily the point of this test is
+			// to ensure that the results are not underreported, so we can
+			// simply verify the lower bound.
+			if got := b.result.MemAllocs; got < 2 {
+				t.Errorf("MemAllocs was %v; want 2", got)
+			}
+			if got := b.result.MemBytes; got < 2*bufSize {
+				t.Errorf("MemBytes was %v; want %v", got, 2*bufSize)
+			}
+		},
+	}}
+	for _, tc := range testCases {
+		var ok bool
+		buf := &bytes.Buffer{}
+		// This is almost like the Benchmark function, except that we override
+		// the benchtime and catch the failure result of the subbenchmark.
+		root := &B{
+			common: common{
+				signal: make(chan bool),
+				name:   "root",
+				w:      buf,
+				chatty: tc.chatty,
+			},
+			benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
+			benchTime: time.Microsecond,
+		}
+		root.runN(1)
+		if ok != !tc.failed {
+			t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed)
+		}
+		if !ok != root.Failed() {
+			t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
+		}
+		// All tests are run as subtests
+		if root.result.N != 1 {
+			t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N)
+		}
+		got := strings.TrimSpace(buf.String())
+		want := strings.TrimSpace(tc.output)
+		re := makeRegexp(want)
+		if ok, err := regexp.MatchString(re, got); !ok || err != nil {
+			t.Errorf("%s:ouput:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
+		}
+	}
+}
+
+func makeRegexp(s string) string {
+	s = strings.Replace(s, ":NNN:", `:\d\d\d:`, -1)
+	s = strings.Replace(s, "(N.NNs)", `\(\d*\.\d*s\)`, -1)
+	return s
+}
+
+func TestBenchmarkOutput(t *T) {
+	// Ensure Benchmark initialized common.w by invoking it with an error and
+	// normal case.
+	Benchmark(func(b *B) { b.Error("do not print this output") })
+	Benchmark(func(b *B) {})
+}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index e4c4772..e1dbe00 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -45,7 +45,7 @@
 //
 // The benchmark function must run the target code b.N times.
 // During benchmark execution, b.N is adjusted until the benchmark function lasts
-// long enough to be timed reliably.  The output
+// 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.
 //
@@ -118,6 +118,61 @@
 // example function, at least one other function, type, variable, or constant
 // declaration, and no test or benchmark functions.
 //
+// Subtests and Sub-benchmarks
+//
+// The Run methods of T and B allow defining subtests and sub-benchmarks,
+// without having to define separate functions for each. This enables uses
+// like table-driven benchmarks and creating hierarchical tests.
+// It also provides a way to share common setup and tear-down code:
+//
+//     func TestFoo(t *testing.T) {
+//         // <setup code>
+//         t.Run("A=1", func(t *testing.T) { ... })
+//         t.Run("A=2", func(t *testing.T) { ... })
+//         t.Run("B=1", func(t *testing.T) { ... })
+//         // <tear-down code>
+//     }
+//
+// Each subtest and sub-benchmark has a unique name: the combination of the name
+// of the top-level test and the sequence of names passed to Run, separated by
+// slashes, with an optional trailing sequence number for disambiguation.
+//
+// The argument to the -run and -bench command-line flags is a slash-separated
+// list of regular expressions that match each name element in turn.
+// For example:
+//
+//     go test -run Foo     # Run top-level tests matching "Foo".
+//     go test -run Foo/A=  # Run subtests of Foo matching "A=".
+//     go test -run /A=1    # Run all subtests of a top-level test matching "A=1".
+//
+// Subtests can also be used to control parallelism. A parent test will only
+// complete once all of its subtests complete. In this example, all tests are
+// run in parallel with each other, and only with each other, regardless of
+// other top-level tests that may be defined:
+//
+//     func TestGroupedParallel(t *testing.T) {
+//         for _, tc := range tests {
+//             tc := tc // capture range variable
+//             t.Run(tc.Name, func(t *testing.T) {
+//                 t.Parallel()
+//                 ...
+//             })
+//         }
+//     }
+//
+// Run does not return until parallel subtests have completed, providing a way
+// to clean up after a group of parallel tests:
+//
+//     func TestTeardownParallel(t *testing.T) {
+//         // This Run will not return until the parallel tests finish.
+//         t.Run("group", func(t *testing.T) {
+//             t.Run("Test1", parallelTest1)
+//             t.Run("Test2", parallelTest2)
+//             t.Run("Test3", parallelTest3)
+//         })
+//         // <tear-down code>
+//     }
+//
 // Main
 //
 // It is sometimes necessary for a test program to do extra setup or teardown
@@ -147,6 +202,7 @@ import (
 	"bytes"
 	"flag"
 	"fmt"
+	"io"
 	"os"
 	"runtime"
 	"runtime/debug"
@@ -160,8 +216,8 @@ import (
 
 var (
 	// The short flag requests that tests run more quickly, but its functionality
-	// is provided by test writers themselves.  The testing package is just its
-	// home.  The all.bash installation script sets it to make installation more
+	// is provided by test writers themselves. The testing package is just its
+	// home. The all.bash installation script sets it to make installation more
 	// efficient, but by default the flag is off so a plain "go test" will do a
 	// full test of the package.
 	short = flag.Bool("test.short", false, "run smaller test suite to save time")
@@ -195,16 +251,23 @@ var (
 // common holds the elements common between T and B and
 // captures common methods such as Errorf.
 type common struct {
-	mu       sync.RWMutex // guards output and failed
+	mu       sync.RWMutex // guards output, failed, and done.
 	output   []byte       // Output generated by test or benchmark.
+	w        io.Writer    // For flushToParent.
+	chatty   bool         // A copy of the chatty flag.
 	failed   bool         // Test or benchmark has failed.
 	skipped  bool         // Test of benchmark has been skipped.
-	finished bool
+	finished bool         // Test function has completed.
+	done     bool         // Test is finished and all subtests have completed.
 
+	parent   *common
+	level    int       // Nesting depth of test or benchmark.
+	name     string    // Name of test or benchmark.
 	start    time.Time // Time test or benchmark started
 	duration time.Duration
-	self     interface{}      // To be sent on signal channel when done.
-	signal   chan interface{} // Output for serial tests.
+	barrier  chan bool // To signal parallel subtests they may start.
+	signal   chan bool // To signal a test is done.
+	sub      []*T      // Queue of subtests to be run in parallel.
 }
 
 // Short reports whether the -test.short flag is set.
@@ -251,6 +314,44 @@ func decorate(s string) string {
 	return buf.String()
 }
 
+// flushToParent writes c.output to the parent after first writing the header
+// with the given format and arguments.
+func (c *common) flushToParent(format string, args ...interface{}) {
+	p := c.parent
+	p.mu.Lock()
+	defer p.mu.Unlock()
+
+	fmt.Fprintf(p.w, format, args...)
+
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	io.Copy(p.w, bytes.NewReader(c.output))
+	c.output = c.output[:0]
+}
+
+type indenter struct {
+	c *common
+}
+
+func (w indenter) Write(b []byte) (n int, err error) {
+	n = len(b)
+	for len(b) > 0 {
+		end := bytes.IndexByte(b, '\n')
+		if end == -1 {
+			end = len(b)
+		} else {
+			end++
+		}
+		// An indent of 4 spaces will neatly align the dashes with the status
+		// indicator of the parent.
+		const indent = "    "
+		w.c.output = append(w.c.output, indent...)
+		w.c.output = append(w.c.output, b[:end]...)
+		b = b[end:]
+	}
+	return
+}
+
 // fmtDuration returns a string representing d in the form "87.00s".
 func fmtDuration(d time.Duration) string {
 	return fmt.Sprintf("%.2fs", d.Seconds())
@@ -282,7 +383,7 @@ var _ TB = (*T)(nil)
 var _ TB = (*B)(nil)
 
 // T is a type passed to Test functions to manage test state and support formatted test logs.
-// Logs are accumulated during execution and dumped to standard error when done.
+// Logs are accumulated during execution and dumped to standard output when done.
 //
 // A test ends when its Test function returns or calls any of the methods
 // FailNow, Fatal, Fatalf, SkipNow, Skip, or Skipf. Those methods, as well as
@@ -293,17 +394,23 @@ var _ TB = (*B)(nil)
 // may be called simultaneously from multiple goroutines.
 type T struct {
 	common
-	name          string // Name of test.
-	isParallel    bool
-	startParallel chan bool // Parallel tests will wait on this.
+	isParallel bool
+	context    *testContext // For running tests and subtests.
 }
 
 func (c *common) private() {}
 
 // Fail marks the function as having failed but continues execution.
 func (c *common) Fail() {
+	if c.parent != nil {
+		c.parent.Fail()
+	}
 	c.mu.Lock()
 	defer c.mu.Unlock()
+	// c.done needs to be locked to synchronize checks to c.done in parent tests.
+	if c.done {
+		panic("Fail in goroutine after " + c.name + " has completed")
+	}
 	c.failed = true
 }
 
@@ -337,9 +444,9 @@ func (c *common) FailNow() {
 	// This previous version duplicated code (those lines are in
 	// tRunner no matter what), but worse the goroutine teardown
 	// implicit in runtime.Goexit was not guaranteed to complete
-	// before the test exited.  If a test deferred an important cleanup
+	// before the test exited. If a test deferred an important cleanup
 	// function (like removing temporary files), there was no guarantee
-	// it would run on a test failure.  Because we send on c.signal during
+	// it would run on a test failure. Because we send on c.signal during
 	// a top-of-stack deferred function now, we know that the send
 	// only happens after any other stacked defers have completed.
 	c.finished = true
@@ -437,8 +544,13 @@ func (t *T) Parallel() {
 	// in the test duration. Record the elapsed time thus far and reset the
 	// timer afterwards.
 	t.duration += time.Since(t.start)
-	t.signal <- (*T)(nil) // Release main testing loop
-	<-t.startParallel     // Wait for serial tests to finish
+
+	// Add to the list of tests to be released by the parent.
+	t.parent.sub = append(t.parent.sub, t)
+
+	t.signal <- true   // Release calling test.
+	<-t.parent.barrier // Wait for the parent test to complete.
+	t.context.waitParallel()
 	t.start = time.Now()
 }
 
@@ -449,8 +561,8 @@ type InternalTest struct {
 	F    func(*T)
 }
 
-func tRunner(t *T, test *InternalTest) {
-	// When this goroutine is done, either because test.F(t)
+func tRunner(t *T, fn func(t *T)) {
+	// When this goroutine is done, either because fn(t)
 	// returned normally or because a test failure triggered
 	// a call to runtime.Goexit, record the duration and send
 	// a signal saying that the test is done.
@@ -466,14 +578,130 @@ func tRunner(t *T, test *InternalTest) {
 			t.report()
 			panic(err)
 		}
-		t.signal <- t
+
+		if len(t.sub) > 0 {
+			// Run parallel subtests.
+			// Decrease the running count for this test.
+			t.context.release()
+			// Release the parallel subtests.
+			close(t.barrier)
+			// Wait for subtests to complete.
+			for _, sub := range t.sub {
+				<-sub.signal
+			}
+			if !t.isParallel {
+				// Reacquire the count for sequential tests. See comment in Run.
+				t.context.waitParallel()
+			}
+		} else if t.isParallel {
+			// Only release the count for this test if it was run as a parallel
+			// test. See comment in Run method.
+			t.context.release()
+		}
+		t.report() // Report after all subtests have finished.
+
+		// Do not lock t.done to allow race detector to detect race in case
+		// the user does not appropriately synchronizes a goroutine.
+		t.done = true
+		t.signal <- true
 	}()
 
 	t.start = time.Now()
-	test.F(t)
+	fn(t)
 	t.finished = true
 }
 
+// Run runs f as a subtest of t called name. It reports whether f succeeded.
+// Run will block until all its parallel subtests have completed.
+func (t *T) Run(name string, f func(t *T)) bool {
+	testName, ok := t.context.match.fullName(&t.common, name)
+	if !ok {
+		return true
+	}
+	t = &T{
+		common: common{
+			barrier: make(chan bool),
+			signal:  make(chan bool),
+			name:    testName,
+			parent:  &t.common,
+			level:   t.level + 1,
+			chatty:  t.chatty,
+		},
+		context: t.context,
+	}
+	t.w = indenter{&t.common}
+
+	if t.chatty {
+		// Print directly to root's io.Writer so there is no delay.
+		root := t.parent
+		for ; root.parent != nil; root = root.parent {
+		}
+		fmt.Fprintf(root.w, "=== RUN   %s\n", t.name)
+	}
+	// Instead of reducing the running count of this test before calling the
+	// tRunner and increasing it afterwards, we rely on tRunner keeping the
+	// count correct. This ensures that a sequence of sequential tests runs
+	// without being preempted, even when their parent is a parallel test. This
+	// may especially reduce surprises if *parallel == 1.
+	go tRunner(t, f)
+	<-t.signal
+	return !t.failed
+}
+
+// testContext holds all fields that are common to all tests. This includes
+// synchronization primitives to run at most *parallel tests.
+type testContext struct {
+	match *matcher
+
+	mu sync.Mutex
+
+	// Channel used to signal tests that are ready to be run in parallel.
+	startParallel chan bool
+
+	// running is the number of tests currently running in parallel.
+	// This does not include tests that are waiting for subtests to complete.
+	running int
+
+	// numWaiting is the number tests waiting to be run in parallel.
+	numWaiting int
+
+	// maxParallel is a copy of the parallel flag.
+	maxParallel int
+}
+
+func newTestContext(maxParallel int, m *matcher) *testContext {
+	return &testContext{
+		match:         m,
+		startParallel: make(chan bool),
+		maxParallel:   maxParallel,
+		running:       1, // Set the count to 1 for the main (sequential) test.
+	}
+}
+
+func (c *testContext) waitParallel() {
+	c.mu.Lock()
+	if c.running < c.maxParallel {
+		c.running++
+		c.mu.Unlock()
+		return
+	}
+	c.numWaiting++
+	c.mu.Unlock()
+	<-c.startParallel
+}
+
+func (c *testContext) release() {
+	c.mu.Lock()
+	if c.numWaiting == 0 {
+		c.running--
+		c.mu.Unlock()
+		return
+	}
+	c.numWaiting--
+	c.mu.Unlock()
+	c.startParallel <- true // Pick a waiting test to be run.
+}
+
 // An internal function but exported because it is cross-package; part of the implementation
 // of the "go test" command.
 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
@@ -515,27 +743,29 @@ func (m *M) Run() int {
 	testOk := RunTests(m.matchString, m.tests)
 	exampleOk := RunExamples(m.matchString, m.examples)
 	stopAlarm()
-	if !testOk || !exampleOk {
+	if !testOk || !exampleOk || !runBenchmarksInternal(m.matchString, m.benchmarks) {
 		fmt.Println("FAIL")
 		after()
 		return 1
 	}
 	fmt.Println("PASS")
-	RunBenchmarks(m.matchString, m.benchmarks)
 	after()
 	return 0
 }
 
 func (t *T) report() {
+	if t.parent == nil {
+		return
+	}
 	dstr := fmtDuration(t.duration)
-	format := "--- %s: %s (%s)\n%s"
+	format := "--- %s: %s (%s)\n"
 	if t.Failed() {
-		fmt.Printf(format, "FAIL", t.name, dstr, t.output)
-	} else if *chatty {
+		t.flushToParent(format, "FAIL", t.name, dstr)
+	} else if t.chatty {
 		if t.Skipped() {
-			fmt.Printf(format, "SKIP", t.name, dstr, t.output)
+			t.flushToParent(format, "SKIP", t.name, dstr)
 		} else {
-			fmt.Printf(format, "PASS", t.name, dstr, t.output)
+			t.flushToParent(format, "PASS", t.name, dstr)
 		}
 	}
 }
@@ -548,63 +778,26 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
 	}
 	for _, procs := range cpuList {
 		runtime.GOMAXPROCS(procs)
-		// We build a new channel tree for each run of the loop.
-		// collector merges in one channel all the upstream signals from parallel tests.
-		// If all tests pump to the same channel, a bug can occur where a test
-		// kicks off a goroutine that Fails, yet the test still delivers a completion signal,
-		// which skews the counting.
-		var collector = make(chan interface{})
-
-		numParallel := 0
-		startParallel := make(chan bool)
-
-		for i := 0; i < len(tests); i++ {
-			matched, err := matchString(*match, tests[i].Name)
-			if err != nil {
-				fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.run: %s\n", err)
-				os.Exit(1)
-			}
-			if !matched {
-				continue
-			}
-			testName := tests[i].Name
-			t := &T{
-				common: common{
-					signal: make(chan interface{}),
-				},
-				name:          testName,
-				startParallel: startParallel,
-			}
-			t.self = t
-			if *chatty {
-				fmt.Printf("=== RUN   %s\n", t.name)
-			}
-			go tRunner(t, &tests[i])
-			out := (<-t.signal).(*T)
-			if out == nil { // Parallel run.
-				go func() {
-					collector <- <-t.signal
-				}()
-				numParallel++
-				continue
-			}
-			t.report()
-			ok = ok && !out.Failed()
+		ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run"))
+		t := &T{
+			common: common{
+				signal:  make(chan bool),
+				barrier: make(chan bool),
+				w:       os.Stdout,
+				chatty:  *chatty,
+			},
+			context: ctx,
 		}
-
-		running := 0
-		for numParallel+running > 0 {
-			if running < *parallel && numParallel > 0 {
-				startParallel <- true
-				running++
-				numParallel--
-				continue
+		tRunner(t, func(t *T) {
+			for _, test := range tests {
+				t.Run(test.Name, test.F)
 			}
-			t := (<-collector).(*T)
-			t.report()
-			ok = ok && !t.Failed()
-			running--
-		}
+			// Run catching the signal rather than the tRunner as a separate
+			// goroutine to avoid adding a goroutine during the sequential
+			// phase as this pollutes the stacktrace output when aborting.
+			go func() { <-t.signal }()
+		})
+		ok = ok && !t.Failed()
 	}
 	return
 }
diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go
index 87a5c16..45e4468 100644
--- a/src/testing/testing_test.go
+++ b/src/testing/testing_test.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/src/text/scanner/example_test.go b/src/text/scanner/example_test.go
index 1011459..1d5d34a 100644
--- a/src/text/scanner/example_test.go
+++ b/src/text/scanner/example_test.go
@@ -17,6 +17,7 @@ func Example() {
 		someParsable = text
 	}`
 	var s scanner.Scanner
+	s.Filename = "example"
 	s.Init(strings.NewReader(src))
 	var tok rune
 	for tok != scanner.EOF {
@@ -25,14 +26,14 @@ func Example() {
 	}
 
 	// 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 :
+	// At position example:3:4 : if
+	// At position example:3:6 : a
+	// At position example:3:8 : >
+	// At position example:3:11 : 10
+	// At position example:3:13 : {
+	// At position example:4:15 : someParsable
+	// At position example:4:17 : =
+	// At position example:4:22 : text
+	// At position example:5:3 : }
+	// At position example:5:3 :
 }
diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go
index 0155800..e085f8a 100644
--- a/src/text/scanner/scanner.go
+++ b/src/text/scanner/scanner.go
@@ -4,12 +4,12 @@
 
 // Package scanner provides a scanner and tokenizer for UTF-8-encoded text.
 // It takes an io.Reader providing the source, which then can be tokenized
-// through repeated calls to the Scan function.  For compatibility with
+// through repeated calls to the Scan function. For compatibility with
 // existing tools, the NUL character is not allowed. If the first character
 // in the source is a UTF-8 encoded byte order mark (BOM), it is discarded.
 //
 // By default, a Scanner skips white space and Go comments and recognizes all
-// literals as defined by the Go language specification.  It may be
+// 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.
 package scanner
@@ -37,14 +37,11 @@ func (pos *Position) IsValid() bool { return pos.Line > 0 }
 
 func (pos Position) String() string {
 	s := pos.Filename
-	if pos.IsValid() {
-		if s != "" {
-			s += ":"
-		}
-		s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
-	}
 	if s == "" {
-		s = "???"
+		s = "<input>"
+	}
+	if pos.IsValid() {
+		s += fmt.Sprintf(":%d:%d", pos.Line, pos.Column)
 	}
 	return s
 }
diff --git a/src/text/scanner/scanner_test.go b/src/text/scanner/scanner_test.go
index 798bed7..3e92d65 100644
--- a/src/text/scanner/scanner_test.go
+++ b/src/text/scanner/scanner_test.go
@@ -451,37 +451,37 @@ func testError(t *testing.T, src, pos, msg string, tok rune) {
 }
 
 func TestError(t *testing.T) {
-	testError(t, "\x00", "1:1", "illegal character NUL", 0)
-	testError(t, "\x80", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
-	testError(t, "\xff", "1:1", "illegal UTF-8 encoding", utf8.RuneError)
-
-	testError(t, "a\x00", "1:2", "illegal character NUL", Ident)
-	testError(t, "ab\x80", "1:3", "illegal UTF-8 encoding", Ident)
-	testError(t, "abc\xff", "1:4", "illegal UTF-8 encoding", Ident)
-
-	testError(t, `"a`+"\x00", "1:3", "illegal character NUL", String)
-	testError(t, `"ab`+"\x80", "1:4", "illegal UTF-8 encoding", String)
-	testError(t, `"abc`+"\xff", "1:5", "illegal UTF-8 encoding", String)
-
-	testError(t, "`a"+"\x00", "1:3", "illegal character NUL", String)
-	testError(t, "`ab"+"\x80", "1:4", "illegal UTF-8 encoding", String)
-	testError(t, "`abc"+"\xff", "1:5", "illegal UTF-8 encoding", String)
-
-	testError(t, `'\"'`, "1:3", "illegal char escape", Char)
-	testError(t, `"\'"`, "1:3", "illegal char escape", String)
-
-	testError(t, `01238`, "1:6", "illegal octal number", Int)
-	testError(t, `01238123`, "1:9", "illegal octal number", Int)
-	testError(t, `0x`, "1:3", "illegal hexadecimal number", Int)
-	testError(t, `0xg`, "1:3", "illegal hexadecimal number", Int)
-	testError(t, `'aa'`, "1:4", "illegal char literal", Char)
-
-	testError(t, `'`, "1:2", "literal not terminated", Char)
-	testError(t, `'`+"\n", "1:2", "literal not terminated", Char)
-	testError(t, `"abc`, "1:5", "literal not terminated", String)
-	testError(t, `"abc`+"\n", "1:5", "literal not terminated", String)
-	testError(t, "`abc\n", "2:1", "literal not terminated", String)
-	testError(t, `/*/`, "1:4", "comment not terminated", EOF)
+	testError(t, "\x00", "<input>:1:1", "illegal character NUL", 0)
+	testError(t, "\x80", "<input>:1:1", "illegal UTF-8 encoding", utf8.RuneError)
+	testError(t, "\xff", "<input>:1:1", "illegal UTF-8 encoding", utf8.RuneError)
+
+	testError(t, "a\x00", "<input>:1:2", "illegal character NUL", Ident)
+	testError(t, "ab\x80", "<input>:1:3", "illegal UTF-8 encoding", Ident)
+	testError(t, "abc\xff", "<input>:1:4", "illegal UTF-8 encoding", Ident)
+
+	testError(t, `"a`+"\x00", "<input>:1:3", "illegal character NUL", String)
+	testError(t, `"ab`+"\x80", "<input>:1:4", "illegal UTF-8 encoding", String)
+	testError(t, `"abc`+"\xff", "<input>:1:5", "illegal UTF-8 encoding", String)
+
+	testError(t, "`a"+"\x00", "<input>:1:3", "illegal character NUL", String)
+	testError(t, "`ab"+"\x80", "<input>:1:4", "illegal UTF-8 encoding", String)
+	testError(t, "`abc"+"\xff", "<input>:1:5", "illegal UTF-8 encoding", String)
+
+	testError(t, `'\"'`, "<input>:1:3", "illegal char escape", Char)
+	testError(t, `"\'"`, "<input>:1:3", "illegal char escape", String)
+
+	testError(t, `01238`, "<input>:1:6", "illegal octal number", Int)
+	testError(t, `01238123`, "<input>:1:9", "illegal octal number", Int)
+	testError(t, `0x`, "<input>:1:3", "illegal hexadecimal number", Int)
+	testError(t, `0xg`, "<input>:1:3", "illegal hexadecimal number", Int)
+	testError(t, `'aa'`, "<input>:1:4", "illegal char literal", Char)
+
+	testError(t, `'`, "<input>:1:2", "literal not terminated", Char)
+	testError(t, `'`+"\n", "<input>:1:2", "literal not terminated", Char)
+	testError(t, `"abc`, "<input>:1:5", "literal not terminated", String)
+	testError(t, `"abc`+"\n", "<input>:1:5", "literal not terminated", String)
+	testError(t, "`abc\n", "<input>:2:1", "literal not terminated", String)
+	testError(t, `/*/`, "<input>:1:4", "comment not terminated", EOF)
 }
 
 // An errReader returns (0, err) where err is not io.EOF.
diff --git a/src/text/tabwriter/example_test.go b/src/text/tabwriter/example_test.go
index 20443cb..422ec11 100644
--- a/src/text/tabwriter/example_test.go
+++ b/src/text/tabwriter/example_test.go
@@ -36,3 +36,38 @@ func ExampleWriter_Init() {
 	//     a     b       c         d.
 	//   123 12345 1234567 123456789.
 }
+
+func Example_elastic() {
+	// Observe how the b's and the d's, despite appearing in the
+	// second cell of each line, belong to different columns.
+	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, '.', tabwriter.AlignRight|tabwriter.Debug)
+	fmt.Fprintln(w, "a\tb\tc")
+	fmt.Fprintln(w, "aa\tbb\tcc")
+	fmt.Fprintln(w, "aaa\t") // trailing tab
+	fmt.Fprintln(w, "aaaa\tdddd\teeee")
+	w.Flush()
+
+	// output:
+	// ....a|..b|c
+	// ...aa|.bb|cc
+	// ..aaa|
+	// .aaaa|.dddd|eeee
+}
+
+func Example_trailingTab() {
+	// Observe that the third line has no trailing tab,
+	// so its final cell is not part of an aligned column.
+	const padding = 3
+	w := tabwriter.NewWriter(os.Stdout, 0, 0, padding, '-', tabwriter.AlignRight|tabwriter.Debug)
+	fmt.Fprintln(w, "a\tb\taligned\t")
+	fmt.Fprintln(w, "aa\tbb\taligned\t")
+	fmt.Fprintln(w, "aaa\tbbb\tunaligned") // no trailing tab
+	fmt.Fprintln(w, "aaaa\tbbbb\taligned\t")
+	w.Flush()
+
+	// output:
+	// ------a|------b|---aligned|
+	// -----aa|-----bb|---aligned|
+	// ----aaa|----bbb|unaligned
+	// ---aaaa|---bbbb|---aligned|
+}
diff --git a/src/text/tabwriter/tabwriter.go b/src/text/tabwriter/tabwriter.go
index c0c32d5..796e1e8 100644
--- a/src/text/tabwriter/tabwriter.go
+++ b/src/text/tabwriter/tabwriter.go
@@ -33,18 +33,32 @@ type cell struct {
 // A Writer is a filter that inserts padding around tab-delimited
 // columns in its input to align them in the output.
 //
-// The Writer treats incoming bytes as UTF-8 encoded text consisting
-// of cells terminated by (horizontal or vertical) tabs or line
-// breaks (newline or formfeed characters). Cells in adjacent lines
-// constitute a column. The Writer inserts padding as needed to
-// make all cells in a column have the same width, effectively
-// aligning the columns. It assumes that all characters have the
-// same width except for tabs for which a tabwidth must be specified.
-// Note that cells are tab-terminated, not tab-separated: trailing
-// non-tab text at the end of a line does not form a column cell.
+// The Writer treats incoming bytes as UTF-8-encoded text consisting
+// of cells terminated by horizontal ('\t') or vertical ('\v') tabs,
+// and newline ('\n') or formfeed ('\f') characters; both newline and
+// formfeed act as line breaks.
+//
+// Tab-terminated cells in contiguous lines constitute a column. The
+// Writer inserts padding as needed to make all cells in a column have
+// the same width, effectively aligning the columns. It assumes that
+// all characters have the same width, except for tabs for which a
+// tabwidth must be specified. Column cells must be tab-terminated, not
+// tab-separated: non-tab terminated trailing text at the end of a line
+// forms a cell but that cell is not part of an aligned column.
+// For instance, in this example (where | stands for a horizontal tab):
+//
+//	aaaa|bbb|d
+//	aa  |b  |dd
+//	a   |
+//	aa  |cccc|eee
+//
+// the b and c are in distinct columns (the b column is not contiguous
+// all the way). The d and e are not in a column at all (there's no
+// terminating tab, nor would the column be contiguous).
 //
 // The Writer assumes that all Unicode code points have the same width;
-// this may not be true in some fonts.
+// this may not be true in some fonts or if the string contains combining
+// characters.
 //
 // If DiscardEmptyColumns is set, empty columns that are terminated
 // entirely by vertical (or "soft") tabs are discarded. Columns
@@ -64,9 +78,9 @@ type cell struct {
 // width of the escaped text is always computed excluding the Escape
 // characters.
 //
-// The formfeed character ('\f') acts like a newline but it also
-// terminates all columns in the current line (effectively calling
-// Flush). Cells in the next line start new columns. Unless found
+// The formfeed character acts like a newline but it also terminates
+// all columns in the current line (effectively calling Flush). Tab-
+// terminated cells in the next line start new columns. Unless found
 // inside an HTML tag or inside an escaped text segment, formfeed
 // characters appear as newlines in the output.
 //
@@ -448,8 +462,11 @@ func handlePanic(err *error, op string) {
 // that any data buffered in the Writer is written to output. Any
 // incomplete escape sequence at the end is considered
 // complete for formatting purposes.
-//
-func (b *Writer) Flush() (err error) {
+func (b *Writer) Flush() error {
+	return b.flush()
+}
+
+func (b *Writer) flush() (err error) {
 	defer b.reset() // even in the presence of errors
 	defer handlePanic(&err, "Flush")
 
@@ -464,8 +481,7 @@ func (b *Writer) Flush() (err error) {
 
 	// format contents of buffer
 	b.format(0, 0, len(b.lines))
-
-	return
+	return nil
 }
 
 var hbar = []byte("---\n")
diff --git a/src/text/template/doc.go b/src/text/template/doc.go
index df8c95f..fe59e3f 100644
--- a/src/text/template/doc.go
+++ b/src/text/template/doc.go
@@ -74,8 +74,9 @@ data, defined in detail in the corresponding sections that follow.
 /*
 
 	{{pipeline}}
-		The default textual representation of the value of the pipeline
-		is copied to the output.
+		The default textual representation (the same as would be
+		printed by fmt.Print) of the value of the pipeline is copied
+		to the output.
 
 	{{if pipeline}} T1 {{end}}
 		If the value of the pipeline is empty, no output is generated;
@@ -220,7 +221,7 @@ value (argument) or a function or method call, possibly with multiple arguments:
 		Functions and function names are described below.
 
 A pipeline may be "chained" by separating a sequence of commands with pipeline
-characters '|'. In a chained pipeline, the result of the each command is
+characters '|'. In a chained pipeline, the result of each command is
 passed as the last argument of the following command. The output of the final
 command in the pipeline is the value of the pipeline.
 
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index efe1817..8e5ad93 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -15,14 +15,21 @@ import (
 	"text/template/parse"
 )
 
+// maxExecDepth specifies the maximum stack depth of templates within
+// templates. This limit is only practically reached by accidentally
+// recursive template invocations. This limit allows us to return
+// an error instead of triggering a stack overflow.
+const maxExecDepth = 100000
+
 // state represents the state of an execution. It's not part of the
 // template so that multiple executions of the same template
 // can execute in parallel.
 type state struct {
-	tmpl *Template
-	wr   io.Writer
-	node parse.Node // current node, for errors
-	vars []variable // push-down stack of variable values.
+	tmpl  *Template
+	wr    io.Writer
+	node  parse.Node // current node, for errors
+	vars  []variable // push-down stack of variable values.
+	depth int        // the height of the stack of executing templates.
 }
 
 // variable holds the dynamic value of a variable such as $, $x etc.
@@ -164,7 +171,11 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
 // execution stops, but partial results may already have been written to
 // the output writer.
 // A template may be executed safely in parallel.
-func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
+func (t *Template) Execute(wr io.Writer, data interface{}) error {
+	return t.execute(wr, data)
+}
+
+func (t *Template) execute(wr io.Writer, data interface{}) (err error) {
 	defer errRecover(&err)
 	value := reflect.ValueOf(data)
 	state := &state{
@@ -359,9 +370,13 @@ func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {
 	if tmpl == nil {
 		s.errorf("template %q not defined", t.Name)
 	}
+	if s.depth == maxExecDepth {
+		s.errorf("exceeded maximum template depth (%v)", maxExecDepth)
+	}
 	// Variables declared by the pipeline persist.
 	dot = s.evalPipeline(dot, t.Pipe)
 	newState := *s
+	newState.depth++
 	newState.tmpl = tmpl
 	// No dynamic scoping: template invocations inherit no variables.
 	newState.vars = []variable{{"$", dot}}
@@ -436,7 +451,7 @@ func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final ref
 
 // idealConstant is called to return the value of a number in a context where
 // we don't know the type. In that case, the syntax of the number tells us
-// its type, and we use Go rules to resolve.  Note there is no such thing as
+// its type, and we use Go rules to resolve. Note there is no such thing as
 // a uint ideal constant in this situation - the value must be of int type.
 func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
 	// These are ideal constants but we don't know the type
@@ -446,7 +461,7 @@ func (s *state) idealConstant(constant *parse.NumberNode) reflect.Value {
 	switch {
 	case constant.IsComplex:
 		return reflect.ValueOf(constant.Complex128) // incontrovertible.
-	case constant.IsFloat && !isHexConstant(constant.Text) && strings.IndexAny(constant.Text, ".eE") >= 0:
+	case constant.IsFloat && !isHexConstant(constant.Text) && strings.ContainsAny(constant.Text, ".eE"):
 		return reflect.ValueOf(constant.Float64)
 	case constant.IsInt:
 		n := int(constant.Int64)
@@ -534,14 +549,14 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
 		return s.evalCall(dot, method, node, fieldName, args, final)
 	}
 	hasArgs := len(args) > 1 || final.IsValid()
-	// It's not a method; must be a field of a struct or an element of a map. The receiver must not be nil.
-	if isNil {
-		s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
-	}
+	// It's not a method; must be a field of a struct or an element of a map.
 	switch receiver.Kind() {
 	case reflect.Struct:
 		tField, ok := receiver.Type().FieldByName(fieldName)
 		if ok {
+			if isNil {
+				s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
+			}
 			field := receiver.FieldByIndex(tField.Index)
 			if tField.PkgPath != "" { // field is unexported
 				s.errorf("%s is an unexported field of struct type %s", fieldName, typ)
@@ -552,8 +567,10 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
 			}
 			return field
 		}
-		s.errorf("%s is not a field of struct type %s", fieldName, typ)
 	case reflect.Map:
+		if isNil {
+			s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
+		}
 		// If it's a map, attempt to use the field name as a key.
 		nameVal := reflect.ValueOf(fieldName)
 		if nameVal.Type().AssignableTo(receiver.Type().Key()) {
@@ -584,7 +601,7 @@ var (
 )
 
 // evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
-// it looks just like a function call.  The arg list, if non-nil, includes (in the manner of the shell), arg[0]
+// it looks just like a function call. The arg list, if non-nil, includes (in the manner of the shell), arg[0]
 // as the function itself.
 func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, args []parse.Node, final reflect.Value) reflect.Value {
 	if args != nil {
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index e507e91..3ef065e 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -1280,3 +1280,33 @@ func TestBlock(t *testing.T) {
 		t.Errorf("got %q, want %q", got, want2)
 	}
 }
+
+// Check that calling an invalid field on nil pointer prints
+// a field error instead of a distracting nil pointer error.
+// https://golang.org/issue/15125
+func TestMissingFieldOnNil(t *testing.T) {
+	tmpl := Must(New("tmpl").Parse("{{.MissingField}}"))
+	var d *T
+	err := tmpl.Execute(ioutil.Discard, d)
+	got := "<nil>"
+	if err != nil {
+		got = err.Error()
+	}
+	want := "can't evaluate field MissingField in type *template.T"
+	if !strings.HasSuffix(got, want) {
+		t.Errorf("got error %q, want %q", got, want)
+	}
+}
+
+func TestMaxExecDepth(t *testing.T) {
+	tmpl := Must(New("tmpl").Parse(`{{template "tmpl" .}}`))
+	err := tmpl.Execute(ioutil.Discard, nil)
+	got := "<nil>"
+	if err != nil {
+		got = err.Error()
+	}
+	const want = "exceeded maximum template depth"
+	if !strings.Contains(got, want) {
+		t.Errorf("got error %q; want %q", got, want)
+	}
+}
diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
index 49e9e74..cd0b82b 100644
--- a/src/text/template/funcs.go
+++ b/src/text/template/funcs.go
@@ -142,7 +142,7 @@ func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error
 // Indexing.
 
 // index returns the result of indexing its first argument by the following
-// arguments.  Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
+// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
 // indexed item must be a map, slice, or array.
 func index(item interface{}, indices ...interface{}) (interface{}, error) {
 	v := reflect.ValueOf(item)
@@ -322,7 +322,6 @@ const (
 	complexKind
 	intKind
 	floatKind
-	integerKind
 	stringKind
 	uintKind
 )
@@ -515,7 +514,7 @@ func HTMLEscape(w io.Writer, b []byte) {
 // HTMLEscapeString returns the escaped HTML equivalent of the plain text data s.
 func HTMLEscapeString(s string) string {
 	// Avoid allocation if we can.
-	if strings.IndexAny(s, `'"&<>`) < 0 {
+	if !strings.ContainsAny(s, `'"&<>`) {
 		return s
 	}
 	var b bytes.Buffer
diff --git a/src/text/template/helper.go b/src/text/template/helper.go
index 787ca62..9e0200c 100644
--- a/src/text/template/helper.go
+++ b/src/text/template/helper.go
@@ -29,6 +29,11 @@ func Must(t *Template, err error) *Template {
 // 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.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
+// For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
+// named "foo", while "a/foo" is unavailable.
 func ParseFiles(filenames ...string) (*Template, error) {
 	return parseFiles(nil, filenames...)
 }
@@ -41,6 +46,9 @@ func ParseFiles(filenames ...string) (*Template, error) {
 // 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.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
 func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
 	t.init()
 	return parseFiles(t, filenames...)
@@ -88,6 +96,9 @@ func parseFiles(t *Template, filenames ...string) (*Template, error) {
 // returned template will have the (base) name and (parsed) contents of the
 // first file matched by the pattern. ParseGlob is equivalent to calling
 // ParseFiles with the list of files matched by the pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
 func ParseGlob(pattern string) (*Template, error) {
 	return parseGlob(nil, pattern)
 }
@@ -97,6 +108,9 @@ func ParseGlob(pattern string) (*Template, error) {
 // processed by filepath.Glob and must match at least one file. ParseGlob is
 // equivalent to calling t.ParseFiles with the list of files matched by the
 // pattern.
+//
+// When parsing multiple files with the same name in different directories,
+// the last one mentioned will be the one that results.
 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 a8342f5..c8723cb 100644
--- a/src/text/template/multi_test.go
+++ b/src/text/template/multi_test.go
@@ -4,7 +4,7 @@
 
 package template
 
-// Tests for mulitple-template parsing and execution.
+// Tests for multiple-template parsing and execution.
 
 import (
 	"bytes"
diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go
index ea93e05..079c0ea 100644
--- a/src/text/template/parse/lex.go
+++ b/src/text/template/parse/lex.go
@@ -155,7 +155,7 @@ func (l *lexer) ignore() {
 
 // accept consumes the next rune if it's from the valid set.
 func (l *lexer) accept(valid string) bool {
-	if strings.IndexRune(valid, l.next()) >= 0 {
+	if strings.ContainsRune(valid, l.next()) {
 		return true
 	}
 	l.backup()
@@ -164,7 +164,7 @@ func (l *lexer) accept(valid string) bool {
 
 // acceptRun consumes a run of runes from the valid set.
 func (l *lexer) acceptRun(valid string) {
-	for strings.IndexRune(valid, l.next()) >= 0 {
+	for strings.ContainsRune(valid, l.next()) {
 	}
 	l.backup()
 }
diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go
index dc56cf7..86705e5 100644
--- a/src/text/template/parse/parse.go
+++ b/src/text/template/parse/parse.go
@@ -48,12 +48,12 @@ func (t *Tree) Copy() *Tree {
 // templates described in the argument string. The top-level template will be
 // given the specified name. If an error is encountered, parsing stops and an
 // empty map is returned with the error.
-func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (treeSet map[string]*Tree, err error) {
-	treeSet = make(map[string]*Tree)
+func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (map[string]*Tree, error) {
+	treeSet := make(map[string]*Tree)
 	t := New(name)
 	t.text = text
-	_, err = t.Parse(text, leftDelim, rightDelim, treeSet, funcs...)
-	return
+	_, err := t.Parse(text, leftDelim, rightDelim, treeSet, funcs...)
+	return treeSet, err
 }
 
 // next returns the next token.
@@ -556,7 +556,7 @@ func (t *Tree) blockControl() Node {
 
 // Template:
 //	{{template stringValue pipeline}}
-// Template keyword is past.  The name must be something that can evaluate
+// Template keyword is past. The name must be something that can evaluate
 // to a string.
 func (t *Tree) templateControl() Node {
 	const context = "template clause"
diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go
index b4512d3..9d856bc 100644
--- a/src/text/template/parse/parse_test.go
+++ b/src/text/template/parse/parse_test.go
@@ -76,7 +76,7 @@ var numberTests = []numberTest{
 
 func TestNumberParse(t *testing.T) {
 	for _, test := range numberTests {
-		// If fmt.Sscan thinks it's complex, it's complex.  We can't trust the output
+		// If fmt.Sscan thinks it's complex, it's complex. We can't trust the output
 		// because imaginary comes out as a number.
 		var c complex128
 		typ := itemNumber
diff --git a/src/time/example_test.go b/src/time/example_test.go
index f76fdcd..4170d51 100644
--- a/src/time/example_test.go
+++ b/src/time/example_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/time/format.go b/src/time/format.go
index e616feb..c2ae793 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -23,7 +23,7 @@ import "errors"
 // compatibility with fixed-width Unix time formats.
 //
 // A decimal point followed by one or more zeros represents a fractional
-// second, printed to the given number of decimal places.  A decimal point
+// second, printed to the given number of decimal places. A decimal point
 // followed by one or more nines represents a fractional second, printed to
 // the given number of decimal places, with trailing zeros removed.
 // When parsing (only), the input may contain a fractional second
@@ -37,7 +37,7 @@ import "errors"
 //	-07    ±hh
 // Replacing the sign in the format with a Z triggers
 // the ISO 8601 behavior of printing Z instead of an
-// offset for the UTC zone.  Thus:
+// offset for the UTC zone. Thus:
 //	Z0700  Z or ±hhmm
 //	Z07:00 Z or ±hh:mm
 //	Z07    Z or ±hh
@@ -51,6 +51,9 @@ import "errors"
 // use of "GMT" in that case.
 // In general RFC1123Z should be used instead of RFC1123 for servers
 // that insist on that format, and RFC3339 should be preferred for new protocols.
+// RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting;
+// when used with time.Parse they do not accept all the time formats
+// permitted by the RFCs.
 const (
 	ANSIC       = "Mon Jan _2 15:04:05 2006"
 	UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
@@ -551,7 +554,7 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
 				b = append(b, "am"...)
 			}
 		case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumColonTZ, stdNumSecondsTz, stdNumShortTZ, stdNumColonSecondsTZ:
-			// Ugly special case.  We cheat and take the "Z" variants
+			// Ugly special case. We cheat and take the "Z" variants
 			// to mean "the time zone as formatted for ISO 8601".
 			if offset == 0 && (std == stdISO8601TZ || std == stdISO8601ColonTZ || std == stdISO8601SecondsTZ || std == stdISO8601ShortTZ || std == stdISO8601ColonSecondsTZ) {
 				b = append(b, 'Z')
diff --git a/src/time/format_test.go b/src/time/format_test.go
index af950a7..8c47dbc 100644
--- a/src/time/format_test.go
+++ b/src/time/format_test.go
@@ -447,7 +447,7 @@ func TestParseErrors(t *testing.T) {
 		_, err := Parse(test.format, test.value)
 		if err == nil {
 			t.Errorf("expected error for %q %q", test.format, test.value)
-		} else if strings.Index(err.Error(), test.expect) < 0 {
+		} else if !strings.Contains(err.Error(), test.expect) {
 			t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
 		}
 	}
diff --git a/src/time/genzabbrs.go b/src/time/genzabbrs.go
index 9eb0728..6281f73 100644
--- a/src/time/genzabbrs.go
+++ b/src/time/genzabbrs.go
@@ -30,7 +30,7 @@ var filename = flag.String("output", "zoneinfo_abbrs_windows.go", "output file n
 // getAbbrs finds timezone abbreviations (standard and daylight saving time)
 // for location l.
 func getAbbrs(l *time.Location) (st, dt string) {
-	t := time.Date(time.Now().Year(), 0, 0, 0, 0, 0, 0, l)
+	t := time.Date(time.Now().Year(), 0, 1, 0, 0, 0, 0, l)
 	abbr1, off1 := t.Zone()
 	for i := 0; i < 12; i++ {
 		t = t.AddDate(0, 1, 0)
diff --git a/src/time/sleep.go b/src/time/sleep.go
index e7a2ee2..73114f5 100644
--- a/src/time/sleep.go
+++ b/src/time/sleep.go
@@ -24,7 +24,7 @@ type runtimeTimer struct {
 
 // when is a helper function for setting the 'when' field of a runtimeTimer.
 // It returns what the time will be, in nanoseconds, Duration d in the future.
-// If d is negative, it is ignored.  If the returned value would be less than
+// If d is negative, it is ignored. If the returned value would be less than
 // zero because of an overflow, MaxInt64 is returned.
 func when(d Duration) int64 {
 	if d <= 0 {
@@ -54,6 +54,14 @@ type Timer struct {
 // expired or been stopped.
 // Stop does not close the channel, to prevent a read from the channel succeeding
 // incorrectly.
+//
+// To prevent the timer firing after a call to Stop,
+// check the return value and drain the channel. For example:
+// 	if !t.Stop() {
+// 		<-t.C
+// 	}
+// This cannot be done concurrent to other receives from the Timer's
+// channel.
 func (t *Timer) Stop() bool {
 	if t.r.f == nil {
 		panic("time: Stop called on uninitialized Timer")
@@ -80,6 +88,20 @@ func NewTimer(d Duration) *Timer {
 // Reset changes the timer to expire after duration d.
 // It returns true if the timer had been active, false if the timer had
 // expired or been stopped.
+//
+// To reuse an active timer, always call its Stop method first and—if it had
+// expired—drain the value from its channel. For example:
+// 	if !t.Stop() {
+// 		<-t.C
+// 	}
+// 	t.Reset(d)
+// This should not be done concurrent to other receives from the Timer's
+// channel.
+//
+// Note that it is not possible to use Reset's return value correctly, as there
+// is a race condition between draining the channel and the new timer expiring.
+// Reset should always be used in concert with Stop, as described above.
+// The return value exists to preserve compatibility with existing programs.
 func (t *Timer) Reset(d Duration) bool {
 	if t.r.f == nil {
 		panic("time: Reset called on uninitialized Timer")
@@ -106,6 +128,9 @@ func sendTime(c interface{}, seq uintptr) {
 // After waits for the duration to elapse and then sends the current time
 // on the returned channel.
 // It is equivalent to NewTimer(d).C.
+// The underlying Timer is not recovered by the garbage collector
+// until the timer fires. If efficiency is a concern, use NewTimer
+// instead and call Timer.Stop if the timer is no longer needed.
 func After(d Duration) <-chan Time {
 	return NewTimer(d).C
 }
diff --git a/src/time/sys_plan9.go b/src/time/sys_plan9.go
index 8484729..11365a7 100644
--- a/src/time/sys_plan9.go
+++ b/src/time/sys_plan9.go
@@ -55,9 +55,9 @@ func closefd(fd uintptr) {
 }
 
 func preadn(fd uintptr, buf []byte, off int) error {
-	whence := 0
+	whence := seekStart
 	if off < 0 {
-		whence = 2
+		whence = seekEnd
 	}
 	if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
 		return err
diff --git a/src/time/sys_unix.go b/src/time/sys_unix.go
index e592415..91d54c9 100644
--- a/src/time/sys_unix.go
+++ b/src/time/sys_unix.go
@@ -55,9 +55,9 @@ func closefd(fd uintptr) {
 }
 
 func preadn(fd uintptr, buf []byte, off int) error {
-	whence := 0
+	whence := seekStart
 	if off < 0 {
-		whence = 2
+		whence = seekEnd
 	}
 	if _, err := syscall.Seek(int(fd), int64(off), whence); err != nil {
 		return err
diff --git a/src/time/sys_windows.go b/src/time/sys_windows.go
index de63b4b..a4a068f 100644
--- a/src/time/sys_windows.go
+++ b/src/time/sys_windows.go
@@ -52,9 +52,9 @@ func closefd(fd uintptr) {
 }
 
 func preadn(fd uintptr, buf []byte, off int) error {
-	whence := 0
+	whence := seekStart
 	if off < 0 {
-		whence = 2
+		whence = seekEnd
 	}
 	if _, err := syscall.Seek(syscall.Handle(fd), int64(off), whence); err != nil {
 		return err
diff --git a/src/time/tick.go b/src/time/tick.go
index 196e8ac..3d69320 100644
--- a/src/time/tick.go
+++ b/src/time/tick.go
@@ -39,7 +39,7 @@ func NewTicker(d Duration) *Ticker {
 	return t
 }
 
-// Stop turns off a ticker.  After Stop, no more ticks will be sent.
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
 // Stop does not close the channel, to prevent a read from the channel succeeding
 // incorrectly.
 func (t *Ticker) Stop() {
@@ -50,6 +50,7 @@ func (t *Ticker) Stop() {
 // 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".
+// Unlike NewTicker, Tick will return nil if d <= 0.
 func Tick(d Duration) <-chan Time {
 	if d <= 0 {
 		return nil
diff --git a/src/time/tick_test.go b/src/time/tick_test.go
index 32f4740..2ab77f6 100644
--- a/src/time/tick_test.go
+++ b/src/time/tick_test.go
@@ -35,7 +35,7 @@ func TestTicker(t *testing.T) {
 	}
 }
 
-// Test that a bug tearing down a ticker has been fixed.  This routine should not deadlock.
+// Test that a bug tearing down a ticker has been fixed. This routine should not deadlock.
 func TestTeardown(t *testing.T) {
 	Delta := 100 * Millisecond
 	if testing.Short() {
diff --git a/src/time/time.go b/src/time/time.go
index ef4ba58..c31de35 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -12,8 +12,8 @@ import "errors"
 // A Time represents an instant in time with nanosecond precision.
 //
 // Programs using times should typically store and pass them as values,
-// not pointers.  That is, time variables and struct fields should be of
-// type time.Time, not *time.Time.  A Time value can be used by
+// not pointers. That is, time variables and struct fields should be of
+// type time.Time, not *time.Time. A Time value can be used by
 // multiple goroutines simultaneously.
 //
 // Time instants can be compared using the Before, After, and Equal methods.
@@ -146,7 +146,7 @@ func (d Weekday) String() string { return days[d] }
 // 00:00:00 UTC, which would be 12-31-(-1) 19:00:00 in New York.
 //
 // The zero Time value does not force a specific epoch for the time
-// representation.  For example, to use the Unix epoch internally, we
+// representation. For example, to use the Unix epoch internally, we
 // could define that to distinguish a zero value from Jan 1 1970, that
 // time would be represented by sec=-1, nsec=1e9.  However, it does
 // suggest a representation, namely using 1-1-1 00:00:00 UTC as the
@@ -155,17 +155,17 @@ func (d Weekday) String() string { return days[d] }
 // The Add and Sub computations are oblivious to the choice of epoch.
 //
 // The presentation computations - year, month, minute, and so on - all
-// rely heavily on division and modulus by positive constants.  For
+// rely heavily on division and modulus by positive constants. For
 // calendrical calculations we want these divisions to round down, even
 // for negative values, so that the remainder is always positive, but
 // Go's division (like most hardware division instructions) rounds to
-// zero.  We can still do those computations and then adjust the result
+// zero. We can still do those computations and then adjust the result
 // for a negative numerator, but it's annoying to write the adjustment
-// over and over.  Instead, we can change to a different epoch so long
+// over and over. Instead, we can change to a different epoch so long
 // ago that all the times we care about will be positive, and then round
-// to zero and round down coincide.  These presentation routines already
+// to zero and round down coincide. These presentation routines already
 // have to add the zone offset, so adding the translation to the
-// alternate epoch is cheap.  For example, having a non-negative time t
+// alternate epoch is cheap. For example, having a non-negative time t
 // means that we can write
 //
 //	sec = t % 60
@@ -181,9 +181,9 @@ func (d Weekday) String() string { return days[d] }
 //
 // The calendar runs on an exact 400 year cycle: a 400-year calendar
 // printed for 1970-2469 will apply as well to 2370-2769.  Even the days
-// of the week match up.  It simplifies the computations to choose the
+// of the week match up. It simplifies the computations to choose the
 // cycle boundaries so that the exceptional years are always delayed as
-// long as possible.  That means choosing a year equal to 1 mod 400, so
+// long as possible. That means choosing a year equal to 1 mod 400, so
 // that the first leap year is the 4th year, the first missed leap year
 // is the 100th year, and the missed missed leap year is the 400th year.
 // So we'd prefer instead to print a calendar for 2001-2400 and reuse it
@@ -209,7 +209,7 @@ func (d Weekday) String() string { return days[d] }
 // routines would then be invalid when displaying the epoch in time zones
 // west of UTC, since it is year 0.  It doesn't seem tenable to say that
 // printing the zero time correctly isn't supported in half the time
-// zones.  By comparison, it's reasonable to mishandle some times in
+// zones. By comparison, it's reasonable to mishandle some times in
 // the year -292277022399.
 //
 // All this is opaque to clients of the API and can be changed if a
@@ -225,9 +225,6 @@ const (
 	// Assumed by the unixToInternal computation below.
 	internalYear = 1
 
-	// The year of the zero Unix time.
-	unixYear = 1970
-
 	// Offsets to convert between internal and absolute or Unix times.
 	absoluteToInternal int64 = (absoluteZeroYear - internalYear) * 365.2425 * secondsPerDay
 	internalToAbsolute       = -absoluteToInternal
@@ -425,7 +422,7 @@ func (t Time) YearDay() int {
 }
 
 // A Duration represents the elapsed time between two instants
-// as an int64 nanosecond count.  The representation limits the
+// as an int64 nanosecond count. The representation limits the
 // largest representable duration to approximately 290 years.
 type Duration int64
 
@@ -434,7 +431,7 @@ const (
 	maxDuration Duration = 1<<63 - 1
 )
 
-// Common durations.  There is no definition for units of Day or larger
+// Common durations. There is no definition for units of Day or larger
 // to avoid confusion across daylight savings time zone transitions.
 //
 // To count the number of units in a Duration, divide:
@@ -455,10 +452,9 @@ const (
 )
 
 // String returns a string representing the duration in the form "72h3m0.5s".
-// Leading zero units are omitted.  As a special case, durations less than one
+// Leading zero units are omitted. As a special case, durations less than one
 // second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure
-// that the leading digit is non-zero.  The zero duration formats as 0,
-// with no unit.
+// that the leading digit is non-zero. The zero duration formats as 0s.
 func (d Duration) String() string {
 	// Largest time is 2540400h10m10.000000000s
 	var buf [32]byte
@@ -479,7 +475,7 @@ func (d Duration) String() string {
 		w--
 		switch {
 		case u == 0:
-			return "0"
+			return "0s"
 		case u < uint64(Microsecond):
 			// print nanoseconds
 			prec = 0
@@ -609,7 +605,7 @@ func (d Duration) Hours() float64 {
 // Add returns the time t+d.
 func (t Time) Add(d Duration) Time {
 	t.sec += int64(d / 1e9)
-	nsec := int32(t.nsec) + int32(d%1e9)
+	nsec := t.nsec + int32(d%1e9)
 	if nsec >= 1e9 {
 		t.sec++
 		nsec -= 1e9
@@ -626,7 +622,7 @@ func (t Time) Add(d Duration) Time {
 // will be returned.
 // To compute t-d for a duration d, use t.Add(-d).
 func (t Time) Sub(u Time) Duration {
-	d := Duration(t.sec-u.sec)*Second + Duration(int32(t.nsec)-int32(u.nsec))
+	d := Duration(t.sec-u.sec)*Second + Duration(t.nsec-u.nsec)
 	// Check for overflow or underflow.
 	switch {
 	case u.Add(d).Equal(t):
@@ -749,7 +745,7 @@ func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) {
 }
 
 // daysBefore[m] counts the number of days in a non-leap year
-// before month m begins.  There is an entry for m=12, counting
+// before month m begins. There is an entry for m=12, counting
 // the number of days before January of next year (365).
 var daysBefore = [...]int32{
 	0,
@@ -945,10 +941,11 @@ func (t Time) MarshalJSON() ([]byte, error) {
 
 // UnmarshalJSON implements the json.Unmarshaler interface.
 // The time is expected to be a quoted string in RFC 3339 format.
-func (t *Time) UnmarshalJSON(data []byte) (err error) {
+func (t *Time) UnmarshalJSON(data []byte) error {
 	// Fractional seconds are handled implicitly by Parse.
+	var err error
 	*t, err = Parse(`"`+RFC3339+`"`, string(data))
-	return
+	return err
 }
 
 // MarshalText implements the encoding.TextMarshaler interface.
@@ -964,10 +961,11 @@ func (t Time) MarshalText() ([]byte, error) {
 
 // UnmarshalText implements the encoding.TextUnmarshaler interface.
 // The time is expected to be in RFC 3339 format.
-func (t *Time) UnmarshalText(data []byte) (err error) {
+func (t *Time) UnmarshalText(data []byte) error {
 	// Fractional seconds are handled implicitly by Parse.
+	var err error
 	*t, err = Parse(RFC3339, string(data))
-	return
+	return err
 }
 
 // Unix returns the local Time corresponding to the given Unix time,
@@ -1019,7 +1017,7 @@ func norm(hi, lo, base int) (nhi, nlo int) {
 //
 // A daylight savings time transition skips or repeats times.
 // For example, in the United States, March 13, 2011 2:15am never occurred,
-// while November 6, 2011 1:15am occurred twice.  In such cases, the
+// while November 6, 2011 1:15am occurred twice. In such cases, the
 // choice of time zone, and therefore the time, is not well-defined.
 // Date returns a time that is correct in one of the two zones involved
 // in the transition, but it does not guarantee which.
@@ -1126,7 +1124,7 @@ func (t Time) Round(d Duration) Time {
 // but it's still here in case we change our minds.
 func div(t Time, d Duration) (qmod2 int, r Duration) {
 	neg := false
-	nsec := int32(t.nsec)
+	nsec := t.nsec
 	if t.sec < 0 {
 		// Operate on absolute value.
 		neg = true
@@ -1160,7 +1158,7 @@ func div(t Time, d Duration) (qmod2 int, r Duration) {
 		tmp := (sec >> 32) * 1e9
 		u1 := tmp >> 32
 		u0 := tmp << 32
-		tmp = uint64(sec&0xFFFFFFFF) * 1e9
+		tmp = (sec & 0xFFFFFFFF) * 1e9
 		u0x, u0 := u0, u0+tmp
 		if u0 < u0x {
 			u1++
diff --git a/src/time/time_test.go b/src/time/time_test.go
index a925e98..b7ebb37 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -22,7 +22,7 @@ import (
 // the subsequent tests fail.
 func TestZoneData(t *testing.T) {
 	lt := Now()
-	// PST is 8 hours west, PDT is 7 hours west.  We could use the name but it's not unique.
+	// PST is 8 hours west, PDT is 7 hours west. We could use the name but it's not unique.
 	if name, off := lt.Zone(); off != -8*60*60 && off != -7*60*60 {
 		t.Errorf("Unable to find US Pacific time zone data for testing; time zone is %q offset %d", name, off)
 		t.Error("Likely problem: the time zone files have not been installed.")
@@ -533,7 +533,7 @@ var durationTests = []struct {
 	str string
 	d   Duration
 }{
-	{"0", 0},
+	{"0s", 0},
 	{"1ns", 1 * Nanosecond},
 	{"1.1µs", 1100 * Nanosecond},
 	{"2.2ms", 2200 * Microsecond},
diff --git a/src/time/zoneinfo_abbrs_windows.go b/src/time/zoneinfo_abbrs_windows.go
index 51a1a2f..344a891 100644
--- a/src/time/zoneinfo_abbrs_windows.go
+++ b/src/time/zoneinfo_abbrs_windows.go
@@ -22,9 +22,10 @@ var abbrs = map[string]abbr{
 	"Namibia Standard Time":           {"WAT", "WAST"},   // Africa/Windhoek
 	"Alaskan Standard Time":           {"AKST", "AKDT"},  // America/Anchorage
 	"Paraguay Standard Time":          {"PYT", "PYST"},   // America/Asuncion
-	"Bahia Standard Time":             {"BRT", "BRST"},   // America/Bahia
+	"Bahia Standard Time":             {"BRT", "BRT"},    // America/Bahia
 	"SA Pacific Standard Time":        {"COT", "COT"},    // America/Bogota
 	"Argentina Standard Time":         {"ART", "ART"},    // America/Buenos_Aires
+	"Eastern Standard Time (Mexico)":  {"EST", "EST"},    // America/Cancun
 	"Venezuela Standard Time":         {"VET", "VET"},    // America/Caracas
 	"SA Eastern Standard Time":        {"GFT", "GFT"},    // America/Cayenne
 	"Central Standard Time":           {"CST", "CDT"},    // America/Chicago
@@ -38,21 +39,22 @@ var abbrs = map[string]abbr{
 	"SA Western Standard Time":        {"BOT", "BOT"},    // America/La_Paz
 	"Pacific Standard Time":           {"PST", "PDT"},    // America/Los_Angeles
 	"Central Standard Time (Mexico)":  {"CST", "CDT"},    // America/Mexico_City
-	"Montevideo Standard Time":        {"UYT", "UYST"},   // America/Montevideo
+	"Montevideo Standard Time":        {"UYT", "UYT"},    // America/Montevideo
 	"Eastern Standard Time":           {"EST", "EDT"},    // America/New_York
 	"US Mountain Standard Time":       {"MST", "MST"},    // America/Phoenix
 	"Canada Central Standard Time":    {"CST", "CST"},    // America/Regina
-	"Pacific Standard Time (Mexico)":  {"PST", "PDT"},    // America/Santa_Isabel
 	"Pacific SA Standard Time":        {"CLT", "CLST"},   // America/Santiago
 	"E. South America Standard Time":  {"BRT", "BRST"},   // America/Sao_Paulo
 	"Newfoundland Standard Time":      {"NST", "NDT"},    // America/St_Johns
-	"Central Asia Standard Time":      {"ALMT", "ALMT"},  // Asia/Almaty
+	"Central Asia Standard Time":      {"+06", "+06"},    // Asia/Almaty
 	"Jordan Standard Time":            {"EET", "EEST"},   // Asia/Amman
 	"Arabic Standard Time":            {"AST", "AST"},    // Asia/Baghdad
-	"Azerbaijan Standard Time":        {"AZT", "AZST"},   // Asia/Baku
+	"Azerbaijan Standard Time":        {"AZT", "AZT"},    // Asia/Baku
 	"SE Asia Standard Time":           {"ICT", "ICT"},    // Asia/Bangkok
+	"Altai Standard Time":             {"+06", "+07"},    // Asia/Barnaul
 	"Middle East Standard Time":       {"EET", "EEST"},   // Asia/Beirut
 	"India Standard Time":             {"IST", "IST"},    // Asia/Calcutta
+	"Transbaikal Standard Time":       {"IRKT", "YAKT"},  // Asia/Chita
 	"Sri Lanka Standard Time":         {"IST", "IST"},    // Asia/Colombo
 	"Syria Standard Time":             {"EET", "EEST"},   // Asia/Damascus
 	"Bangladesh Standard Time":        {"BDT", "BDT"},    // Asia/Dhaka
@@ -60,22 +62,26 @@ var abbrs = map[string]abbr{
 	"North Asia East Standard Time":   {"IRKT", "IRKT"},  // Asia/Irkutsk
 	"Israel Standard Time":            {"IST", "IDT"},    // Asia/Jerusalem
 	"Afghanistan Standard Time":       {"AFT", "AFT"},    // Asia/Kabul
+	"Russia Time Zone 11":             {"PETT", "PETT"},  // Asia/Kamchatka
 	"Pakistan Standard Time":          {"PKT", "PKT"},    // Asia/Karachi
 	"Nepal Standard Time":             {"NPT", "NPT"},    // Asia/Katmandu
 	"North Asia Standard Time":        {"KRAT", "KRAT"},  // Asia/Krasnoyarsk
 	"Magadan Standard Time":           {"MAGT", "MAGT"},  // Asia/Magadan
 	"N. Central Asia Standard Time":   {"NOVT", "NOVT"},  // Asia/Novosibirsk
+	"North Korea Standard Time":       {"KST", "KST"},    // Asia/Pyongyang
 	"Myanmar Standard Time":           {"MMT", "MMT"},    // Asia/Rangoon
 	"Arab Standard Time":              {"AST", "AST"},    // Asia/Riyadh
+	"Sakhalin Standard Time":          {"SAKT", "SAKT"},  // Asia/Sakhalin
 	"Korea Standard Time":             {"KST", "KST"},    // Asia/Seoul
 	"China Standard Time":             {"CST", "CST"},    // Asia/Shanghai
 	"Singapore Standard Time":         {"SGT", "SGT"},    // Asia/Singapore
+	"Russia Time Zone 10":             {"SRET", "SRET"},  // Asia/Srednekolymsk
 	"Taipei Standard Time":            {"CST", "CST"},    // Asia/Taipei
 	"West Asia Standard Time":         {"UZT", "UZT"},    // Asia/Tashkent
 	"Georgian Standard Time":          {"GET", "GET"},    // Asia/Tbilisi
 	"Iran Standard Time":              {"IRST", "IRDT"},  // Asia/Tehran
 	"Tokyo Standard Time":             {"JST", "JST"},    // Asia/Tokyo
-	"Ulaanbaatar Standard Time":       {"ULAT", "ULAT"},  // Asia/Ulaanbaatar
+	"Ulaanbaatar Standard Time":       {"ULAT", "ULAST"}, // Asia/Ulaanbaatar
 	"Vladivostok Standard Time":       {"VLAT", "VLAT"},  // Asia/Vladivostok
 	"Yakutsk Standard Time":           {"YAKT", "YAKT"},  // Asia/Yakutsk
 	"Ekaterinburg Standard Time":      {"YEKT", "YEKT"},  // Asia/Yekaterinburg
@@ -83,31 +89,35 @@ var abbrs = map[string]abbr{
 	"Azores Standard Time":            {"AZOT", "AZOST"}, // Atlantic/Azores
 	"Cape Verde Standard Time":        {"CVT", "CVT"},    // Atlantic/Cape_Verde
 	"Greenwich Standard Time":         {"GMT", "GMT"},    // Atlantic/Reykjavik
-	"Cen. Australia Standard Time":    {"CST", "CST"},    // Australia/Adelaide
-	"E. Australia Standard Time":      {"EST", "EST"},    // Australia/Brisbane
-	"AUS Central Standard Time":       {"CST", "CST"},    // Australia/Darwin
-	"Tasmania Standard Time":          {"EST", "EST"},    // Australia/Hobart
-	"W. Australia Standard Time":      {"WST", "WST"},    // Australia/Perth
-	"AUS Eastern Standard Time":       {"EST", "EST"},    // Australia/Sydney
+	"Cen. Australia Standard Time":    {"ACST", "ACDT"},  // Australia/Adelaide
+	"E. Australia Standard Time":      {"AEST", "AEST"},  // Australia/Brisbane
+	"AUS Central Standard Time":       {"ACST", "ACST"},  // Australia/Darwin
+	"Tasmania Standard Time":          {"AEST", "AEDT"},  // Australia/Hobart
+	"W. Australia Standard Time":      {"AWST", "AWST"},  // Australia/Perth
+	"AUS Eastern Standard Time":       {"AEST", "AEDT"},  // Australia/Sydney
 	"UTC":                            {"GMT", "GMT"},       // Etc/GMT
 	"UTC-11":                         {"GMT+11", "GMT+11"}, // Etc/GMT+11
 	"Dateline Standard Time":         {"GMT+12", "GMT+12"}, // Etc/GMT+12
 	"UTC-02":                         {"GMT+2", "GMT+2"},   // Etc/GMT+2
 	"UTC+12":                         {"GMT-12", "GMT-12"}, // Etc/GMT-12
+	"Astrakhan Standard Time":        {"+03", "+04"},       // Europe/Astrakhan
 	"W. Europe Standard Time":        {"CET", "CEST"},      // Europe/Berlin
 	"GTB Standard Time":              {"EET", "EEST"},      // Europe/Bucharest
 	"Central Europe Standard Time":   {"CET", "CEST"},      // Europe/Budapest
+	"E. Europe Standard Time":        {"EET", "EEST"},      // Europe/Chisinau
 	"Turkey Standard Time":           {"EET", "EEST"},      // Europe/Istanbul
-	"Kaliningrad Standard Time":      {"FET", "FET"},       // Europe/Kaliningrad
+	"Kaliningrad Standard Time":      {"EET", "EET"},       // Europe/Kaliningrad
 	"FLE Standard Time":              {"EET", "EEST"},      // Europe/Kiev
 	"GMT Standard Time":              {"GMT", "BST"},       // Europe/London
+	"Belarus Standard Time":          {"MSK", "MSK"},       // Europe/Minsk
 	"Russian Standard Time":          {"MSK", "MSK"},       // Europe/Moscow
 	"Romance Standard Time":          {"CET", "CEST"},      // Europe/Paris
+	"Russia Time Zone 3":             {"SAMT", "SAMT"},     // Europe/Samara
 	"Central European Standard Time": {"CET", "CEST"},      // Europe/Warsaw
 	"Mauritius Standard Time":        {"MUT", "MUT"},       // Indian/Mauritius
-	"Samoa Standard Time":            {"WST", "WST"},       // Pacific/Apia
+	"Samoa Standard Time":            {"WSST", "WSDT"},     // Pacific/Apia
 	"New Zealand Standard Time":      {"NZST", "NZDT"},     // Pacific/Auckland
-	"Fiji Standard Time":             {"FJT", "FJT"},       // Pacific/Fiji
+	"Fiji Standard Time":             {"FJT", "FJST"},      // Pacific/Fiji
 	"Central Pacific Standard Time":  {"SBT", "SBT"},       // Pacific/Guadalcanal
 	"Hawaiian Standard Time":         {"HST", "HST"},       // Pacific/Honolulu
 	"Line Islands Standard Time":     {"LINT", "LINT"},     // Pacific/Kiritimati
diff --git a/src/time/zoneinfo_read.go b/src/time/zoneinfo_read.go
index de9ebb4..19cd40d 100644
--- a/src/time/zoneinfo_read.go
+++ b/src/time/zoneinfo_read.go
@@ -11,6 +11,13 @@ package time
 
 import "errors"
 
+// Copies of io.Seek* constants to avoid importing "io":
+const (
+	seekStart   = 0
+	seekCurrent = 1
+	seekEnd     = 2
+)
+
 // Simple I/O interface to binary blob of data.
 type data struct {
 	p     []byte
@@ -210,10 +217,10 @@ func loadZoneFile(dir, name string) (l *Location, err error) {
 	return loadZoneData(buf)
 }
 
-// There are 500+ zoneinfo files.  Rather than distribute them all
+// There are 500+ zoneinfo files. Rather than distribute them all
 // individually, we ship them in an uncompressed zip file.
 // Used this way, the zip file format serves as a commonly readable
-// container for the individual small files.  We choose zip over tar
+// container for the individual small files. We choose zip over tar
 // because zip files have a contiguous table of contents, making
 // individual file lookups faster, and because the per-file overhead
 // in a zip file is considerably less than tar's 512 bytes.
diff --git a/src/time/zoneinfo_test.go b/src/time/zoneinfo_test.go
index 4ca7fad..4b50dc5 100644
--- a/src/time/zoneinfo_test.go
+++ b/src/time/zoneinfo_test.go
@@ -19,7 +19,7 @@ func TestVersion3(t *testing.T) {
 }
 
 // Test that we get the correct results for times before the first
-// transition time.  To do this we explicitly check early dates in a
+// transition time. To do this we explicitly check early dates in a
 // couple of specific timezones.
 func TestFirstZone(t *testing.T) {
 	time.ForceZipFileForTesting(true)
@@ -61,3 +61,12 @@ func TestFirstZone(t *testing.T) {
 		}
 	}
 }
+
+func TestLocationNames(t *testing.T) {
+	if time.Local.String() != "Local" {
+		t.Errorf(`invalid Local location name: got %q want "Local"`, time.Local)
+	}
+	if time.UTC.String() != "UTC" {
+		t.Errorf(`invalid UTC location name: got %q want "UTC"`, time.UTC)
+	}
+}
diff --git a/src/time/zoneinfo_windows.go b/src/time/zoneinfo_windows.go
index bcb8ccd..a6546f5 100644
--- a/src/time/zoneinfo_windows.go
+++ b/src/time/zoneinfo_windows.go
@@ -83,7 +83,7 @@ func extractCAPS(desc string) string {
 	var short []rune
 	for _, c := range desc {
 		if 'A' <= c && c <= 'Z' {
-			short = append(short, rune(c))
+			short = append(short, c)
 		}
 	}
 	return string(short)
@@ -140,6 +140,8 @@ func pseudoUnix(year int, d *syscall.Systemtime) int64 {
 func initLocalFromTZI(i *syscall.Timezoneinformation) {
 	l := &localLoc
 
+	l.name = "Local"
+
 	nzone := 1
 	if i.StandardDate.Month > 0 {
 		nzone++
diff --git a/src/unicode/graphic.go b/src/unicode/graphic.go
index 81eae3e..ca62419 100644
--- a/src/unicode/graphic.go
+++ b/src/unicode/graphic.go
@@ -45,7 +45,7 @@ func IsGraphic(r rune) bool {
 // IsPrint reports whether the rune is defined as printable by Go. Such
 // characters include letters, marks, numbers, punctuation, symbols, and the
 // ASCII space character, from categories L, M, N, P, S and the ASCII space
-// character.  This categorization is the same as IsGraphic except that the
+// character. This categorization is the same as IsGraphic except that the
 // only spacing character is ASCII space, U+0020.
 func IsPrint(r rune) bool {
 	if uint32(r) <= MaxLatin1 {
diff --git a/src/unicode/letter.go b/src/unicode/letter.go
index 7fe4241..8aec920 100644
--- a/src/unicode/letter.go
+++ b/src/unicode/letter.go
@@ -27,7 +27,7 @@ type RangeTable struct {
 	LatinOffset int // number of entries in R16 with Hi <= MaxLatin1
 }
 
-// Range16 represents of a range of 16-bit Unicode code points.  The range runs from Lo to Hi
+// Range16 represents of a range of 16-bit Unicode code points. The range runs from Lo to Hi
 // inclusive and has the specified stride.
 type Range16 struct {
 	Lo     uint16
@@ -36,7 +36,7 @@ type Range16 struct {
 }
 
 // Range32 represents of a range of Unicode code points and is used when one or
-// more of the values will not fit in 16 bits.  The range runs from Lo to Hi
+// more of the values will not fit in 16 bits. The range runs from Lo to Hi
 // inclusive and has the specified stride. Lo and Hi must always be >= 1<<16.
 type Range32 struct {
 	Lo     uint32
@@ -48,10 +48,10 @@ type Range32 struct {
 // code point to one code point) case conversion.
 // The range runs from Lo to Hi inclusive, with a fixed stride of 1.  Deltas
 // are the number to add to the code point to reach the code point for a
-// different case for that character.  They may be negative.  If zero, it
+// different case for that character. They may be negative. If zero, it
 // means the character is in the corresponding case. There is a special
 // case representing sequences of alternating corresponding Upper and Lower
-// pairs.  It appears with a fixed Delta of
+// pairs. It appears with a fixed Delta of
 //	{UpperLower, UpperLower, UpperLower}
 // The constant UpperLower has an otherwise impossible delta value.
 type CaseRange struct {
@@ -217,7 +217,7 @@ func to(_case int, r rune, caseRange []CaseRange) rune {
 		m := lo + (hi-lo)/2
 		cr := caseRange[m]
 		if rune(cr.Lo) <= r && r <= rune(cr.Hi) {
-			delta := rune(cr.Delta[_case])
+			delta := cr.Delta[_case]
 			if delta > MaxRune {
 				// In an Upper-Lower sequence, which always starts with
 				// an UpperCase letter, the real deltas always look like:
@@ -307,7 +307,7 @@ func (special SpecialCase) ToLower(r rune) rune {
 	return r1
 }
 
-// caseOrbit is defined in tables.go as []foldPair.  Right now all the
+// caseOrbit is defined in tables.go as []foldPair. Right now all the
 // entries fit in uint16, so use uint16.  If that changes, compilation
 // will fail (the constants in the composite literal will not fit in uint16)
 // and the types here can change to uint32.
@@ -317,7 +317,7 @@ type foldPair struct {
 }
 
 // SimpleFold iterates over Unicode code points equivalent under
-// the Unicode-defined simple case folding.  Among the code points
+// the Unicode-defined simple case folding. Among the code points
 // equivalent to rune (including rune itself), SimpleFold returns the
 // smallest rune > r if one exists, or else the smallest rune >= 0.
 //
@@ -332,6 +332,10 @@ type foldPair struct {
 //	SimpleFold('1') = '1'
 //
 func SimpleFold(r rune) rune {
+	if int(r) < len(asciiFold) {
+		return rune(asciiFold[r])
+	}
+
 	// Consult caseOrbit table for special cases.
 	lo := 0
 	hi := len(caseOrbit)
@@ -347,7 +351,7 @@ func SimpleFold(r rune) rune {
 		return rune(caseOrbit[lo].To)
 	}
 
-	// No folding specified.  This is a one- or two-element
+	// No folding specified. This is a one- or two-element
 	// equivalence class containing rune and ToLower(rune)
 	// and ToUpper(rune) if they are different from rune.
 	if l := ToLower(r); l != r {
diff --git a/src/unicode/letter_test.go b/src/unicode/letter_test.go
index a40b412..0eb9ee9 100644
--- a/src/unicode/letter_test.go
+++ b/src/unicode/letter_test.go
@@ -73,7 +73,6 @@ var letterTest = []rune{
 	0x1200,
 	0x1312,
 	0x1401,
-	0x1885,
 	0x2c00,
 	0xa800,
 	0xf900,
@@ -94,6 +93,7 @@ var notletterTest = []rune{
 	0x375,
 	0x619,
 	0x700,
+	0x1885,
 	0xfffe,
 	0x1ffff,
 	0x10ffff,
diff --git a/src/unicode/maketables.go b/src/unicode/maketables.go
index e0110c9..fdfcde4 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/8.0.0/ucd/",
+	"http://www.unicode.org/Public/9.0.0/ucd/",
 	"URL of Unicode database directory")
 var tablelist = flag.String("tables",
 	"all",
@@ -485,7 +485,7 @@ func printCategories() {
 			logger.Fatal("unknown category", name)
 		}
 		// We generate an UpperCase name to serve as concise documentation and an _UnderScored
-		// name to store the data.  This stops godoc dumping all the tables but keeps them
+		// name to store the data. This stops godoc dumping all the tables but keeps them
 		// available to clients.
 		// Cases deserving special comments
 		varDecl := ""
@@ -743,6 +743,10 @@ func fullScriptTest(list []string, installed map[string]*unicode.RangeTable, scr
 	}
 }
 
+var deprecatedAliases = map[string]string{
+	"Sentence_Terminal": "STerm",
+}
+
 // PropList.txt has the same format as Scripts.txt so we can share its parser.
 func printScriptOrProperty(doProps bool) {
 	flag := "scripts"
@@ -797,11 +801,14 @@ func printScriptOrProperty(doProps bool) {
 		}
 		for _, k := range all(table) {
 			printf("\t%q: %s,\n", k, k)
+			if alias, ok := deprecatedAliases[k]; ok {
+				printf("\t%q: %s,\n", alias, k)
+			}
 		}
 		print("}\n\n")
 	}
 
-	decl := make(sort.StringSlice, len(list))
+	decl := make(sort.StringSlice, len(list)+len(deprecatedAliases))
 	ndecl := 0
 	for _, name := range list {
 		if doProps {
@@ -814,6 +821,12 @@ func printScriptOrProperty(doProps bool) {
 				name, name, name, name)
 		}
 		ndecl++
+		if alias, ok := deprecatedAliases[name]; ok {
+			decl[ndecl] = fmt.Sprintf(
+				"\t%[1]s = _%[2]s;\t// %[1]s is an alias for %[2]s.\n",
+				alias, name)
+			ndecl++
+		}
 		printf("var _%s = &RangeTable {\n", name)
 		ranges := foldAdjacent(table[name])
 		print("\tR16: []Range16{\n")
@@ -964,7 +977,7 @@ func getCaseState(i rune) (c *caseState) {
 		c._case = CaseTitle
 	}
 	// Some things such as roman numeral U+2161 don't describe themselves
-	// as upper case, but have a lower case.  Second-guess them.
+	// as upper case, but have a lower case. Second-guess them.
 	if c._case == CaseNone && ch.lowerCase != 0 {
 		c._case = CaseUpper
 	}
@@ -1172,6 +1185,7 @@ func printCasefold() {
 		}
 	}
 
+	printAsciiFold()
 	printCaseOrbit()
 
 	// Tables of category and script folding exceptions: code points
@@ -1269,6 +1283,25 @@ var comment = map[string]string{
 		"// If there is no entry for a script name, there are no such points.\n",
 }
 
+func printAsciiFold() {
+	printf("var asciiFold = [MaxASCII + 1]uint16{\n")
+	for i := rune(0); i <= unicode.MaxASCII; i++ {
+		c := chars[i]
+		f := c.caseOrbit
+		if f == 0 {
+			if c.lowerCase != i && c.lowerCase != 0 {
+				f = c.lowerCase
+			} else if c.upperCase != i && c.upperCase != 0 {
+				f = c.upperCase
+			} else {
+				f = i
+			}
+		}
+		printf("\t0x%04X,\n", f)
+	}
+	printf("}\n\n")
+}
+
 func printCaseOrbit() {
 	if *test {
 		for j := range chars {
diff --git a/src/unicode/script_test.go b/src/unicode/script_test.go
index 935c225..1fe4581 100644
--- a/src/unicode/script_test.go
+++ b/src/unicode/script_test.go
@@ -18,10 +18,12 @@ type T struct {
 // mostly to discover when new scripts and categories arise.
 var inTest = []T{
 	{0x11711, "Ahom"},
+	{0x1e900, "Adlam"},
 	{0x14646, "Anatolian_Hieroglyphs"},
 	{0x06e2, "Arabic"},
 	{0x0567, "Armenian"},
 	{0x10b20, "Avestan"},
+	{0x11c00, "Bhaiksuki"},
 	{0x1b37, "Balinese"},
 	{0xa6af, "Bamum"},
 	{0x16ada, "Bassa_Vah"},
@@ -89,6 +91,7 @@ var inTest = []T{
 	{0x0d42, "Malayalam"},
 	{0x0843, "Mandaic"},
 	{0x10ac8, "Manichaean"},
+	{0x11cB6, "Marchen"},
 	{0xabd0, "Meetei_Mayek"},
 	{0x1e800, "Mende_Kikakui"},
 	{0x1099f, "Meroitic_Hieroglyphs"},
@@ -100,6 +103,7 @@ var inTest = []T{
 	{0x11293, "Multani"},
 	{0x104c, "Myanmar"},
 	{0x10880, "Nabataean"},
+	{0x11400, "Newa"},
 	{0x19c3, "New_Tai_Lue"},
 	{0x07f8, "Nko"},
 	{0x169b, "Ogham"},
@@ -112,6 +116,7 @@ var inTest = []T{
 	{0x10a6f, "Old_South_Arabian"},
 	{0x10c20, "Old_Turkic"},
 	{0x0b3e, "Oriya"},
+	{0x104d9, "Osage"},
 	{0x10491, "Osmanya"},
 	{0x16b2b, "Pahawh_Hmong"},
 	{0x10876, "Palmyrene"},
@@ -139,6 +144,7 @@ var inTest = []T{
 	{0xaadc, "Tai_Viet"},
 	{0x116c9, "Takri"},
 	{0x0bbf, "Tamil"},
+	{0x17000, "Tangut"},
 	{0x0c55, "Telugu"},
 	{0x07a7, "Thaana"},
 	{0x0e46, "Thai"},
@@ -220,9 +226,11 @@ var inPropTest = []T{
 	{0x216F, "Other_Uppercase"},
 	{0x0027, "Pattern_Syntax"},
 	{0x0020, "Pattern_White_Space"},
+	{0x06DD, "Prepended_Concatenation_Mark"},
 	{0x300D, "Quotation_Mark"},
 	{0x2EF3, "Radical"},
-	{0x061F, "STerm"},
+	{0x061F, "STerm"}, // Deprecated alias of Sentence_Terminal
+	{0x061F, "Sentence_Terminal"},
 	{0x2071, "Soft_Dotted"},
 	{0x003A, "Terminal_Punctuation"},
 	{0x9FC3, "Unified_Ideograph"},
diff --git a/src/unicode/tables.go b/src/unicode/tables.go
index 8bb4206..15fecd9 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/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt
+//	maketables --tables=all --data=http://www.unicode.org/Public/9.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt
 // DO NOT EDIT
 
 package unicode
 
 // Version is the Unicode edition from which the tables are derived.
-const Version = "8.0.0"
+const Version = "9.0.0"
 
 // Categories is the set of Unicode category tables.
 var Categories = map[string]*RangeTable{
@@ -58,8 +58,9 @@ var _C = &RangeTable{
 		{0x00ad, 0x0600, 1363},
 		{0x0601, 0x0605, 1},
 		{0x061c, 0x06dd, 193},
-		{0x070f, 0x180e, 4351},
-		{0x200b, 0x200f, 1},
+		{0x070f, 0x08e2, 467},
+		{0x180e, 0x200b, 2045},
+		{0x200c, 0x200f, 1},
 		{0x202a, 0x202e, 1},
 		{0x2060, 0x2064, 1},
 		{0x2066, 0x206f, 1},
@@ -92,8 +93,9 @@ var _Cf = &RangeTable{
 		{0x00ad, 0x0600, 1363},
 		{0x0601, 0x0605, 1},
 		{0x061c, 0x06dd, 193},
-		{0x070f, 0x180e, 4351},
-		{0x200b, 0x200f, 1},
+		{0x070f, 0x08e2, 467},
+		{0x180e, 0x200b, 2045},
+		{0x200c, 0x200f, 1},
 		{0x202a, 0x202e, 1},
 		{0x2060, 0x2064, 1},
 		{0x2066, 0x206f, 1},
@@ -171,6 +173,7 @@ var _L = &RangeTable{
 		{0x0828, 0x0840, 24},
 		{0x0841, 0x0858, 1},
 		{0x08a0, 0x08b4, 1},
+		{0x08b6, 0x08bd, 1},
 		{0x0904, 0x0939, 1},
 		{0x093d, 0x0950, 19},
 		{0x0958, 0x0961, 1},
@@ -231,7 +234,8 @@ var _L = &RangeTable{
 		{0x0c3d, 0x0c58, 27},
 		{0x0c59, 0x0c5a, 1},
 		{0x0c60, 0x0c61, 1},
-		{0x0c85, 0x0c8c, 1},
+		{0x0c80, 0x0c85, 5},
+		{0x0c86, 0x0c8c, 1},
 		{0x0c8e, 0x0c90, 1},
 		{0x0c92, 0x0ca8, 1},
 		{0x0caa, 0x0cb3, 1},
@@ -242,8 +246,9 @@ var _L = &RangeTable{
 		{0x0d05, 0x0d0c, 1},
 		{0x0d0e, 0x0d10, 1},
 		{0x0d12, 0x0d3a, 1},
-		{0x0d3d, 0x0d5f, 17},
-		{0x0d60, 0x0d61, 1},
+		{0x0d3d, 0x0d4e, 17},
+		{0x0d54, 0x0d56, 1},
+		{0x0d5f, 0x0d61, 1},
 		{0x0d7a, 0x0d7f, 1},
 		{0x0d85, 0x0d96, 1},
 		{0x0d9a, 0x0db1, 1},
@@ -317,7 +322,8 @@ var _L = &RangeTable{
 		{0x1780, 0x17b3, 1},
 		{0x17d7, 0x17dc, 5},
 		{0x1820, 0x1877, 1},
-		{0x1880, 0x18a8, 1},
+		{0x1880, 0x1884, 1},
+		{0x1887, 0x18a8, 1},
 		{0x18aa, 0x18b0, 6},
 		{0x18b1, 0x18f5, 1},
 		{0x1900, 0x191e, 1},
@@ -336,6 +342,7 @@ var _L = &RangeTable{
 		{0x1c00, 0x1c23, 1},
 		{0x1c4d, 0x1c4f, 1},
 		{0x1c5a, 0x1c7d, 1},
+		{0x1c80, 0x1c88, 1},
 		{0x1ce9, 0x1cec, 1},
 		{0x1cee, 0x1cf1, 1},
 		{0x1cf5, 0x1cf6, 1},
@@ -412,7 +419,7 @@ var _L = &RangeTable{
 		{0xa6a0, 0xa6e5, 1},
 		{0xa717, 0xa71f, 1},
 		{0xa722, 0xa788, 1},
-		{0xa78b, 0xa7ad, 1},
+		{0xa78b, 0xa7ae, 1},
 		{0xa7b0, 0xa7b7, 1},
 		{0xa7f7, 0xa801, 1},
 		{0xa803, 0xa805, 1},
@@ -498,6 +505,8 @@ var _L = &RangeTable{
 		{0x103a0, 0x103c3, 1},
 		{0x103c8, 0x103cf, 1},
 		{0x10400, 0x1049d, 1},
+		{0x104b0, 0x104d3, 1},
+		{0x104d8, 0x104fb, 1},
 		{0x10500, 0x10527, 1},
 		{0x10530, 0x10563, 1},
 		{0x10600, 0x10736, 1},
@@ -557,6 +566,8 @@ var _L = &RangeTable{
 		{0x11335, 0x11339, 1},
 		{0x1133d, 0x11350, 19},
 		{0x1135d, 0x11361, 1},
+		{0x11400, 0x11434, 1},
+		{0x11447, 0x1144a, 1},
 		{0x11480, 0x114af, 1},
 		{0x114c4, 0x114c5, 1},
 		{0x114c7, 0x11580, 185},
@@ -569,6 +580,10 @@ var _L = &RangeTable{
 		{0x118a0, 0x118df, 1},
 		{0x118ff, 0x11ac0, 449},
 		{0x11ac1, 0x11af8, 1},
+		{0x11c00, 0x11c08, 1},
+		{0x11c0a, 0x11c2e, 1},
+		{0x11c40, 0x11c72, 50},
+		{0x11c73, 0x11c8f, 1},
 		{0x12000, 0x12399, 1},
 		{0x12480, 0x12543, 1},
 		{0x13000, 0x1342e, 1},
@@ -583,6 +598,9 @@ var _L = &RangeTable{
 		{0x16f00, 0x16f44, 1},
 		{0x16f50, 0x16f93, 67},
 		{0x16f94, 0x16f9f, 1},
+		{0x16fe0, 0x17000, 32},
+		{0x17001, 0x187ec, 1},
+		{0x18800, 0x18af2, 1},
 		{0x1b000, 0x1b001, 1},
 		{0x1bc00, 0x1bc6a, 1},
 		{0x1bc70, 0x1bc7c, 1},
@@ -619,6 +637,7 @@ var _L = &RangeTable{
 		{0x1d7aa, 0x1d7c2, 1},
 		{0x1d7c4, 0x1d7cb, 1},
 		{0x1e800, 0x1e8c4, 1},
+		{0x1e900, 0x1e943, 1},
 		{0x1ee00, 0x1ee03, 1},
 		{0x1ee05, 0x1ee1f, 1},
 		{0x1ee21, 0x1ee22, 1},
@@ -706,6 +725,7 @@ var _Ll = &RangeTable{
 		{0x04cf, 0x052f, 2},
 		{0x0561, 0x0587, 1},
 		{0x13f8, 0x13fd, 1},
+		{0x1c80, 0x1c88, 1},
 		{0x1d00, 0x1d2b, 1},
 		{0x1d6b, 0x1d77, 1},
 		{0x1d79, 0x1d9a, 1},
@@ -773,6 +793,7 @@ var _Ll = &RangeTable{
 	},
 	R32: []Range32{
 		{0x10428, 0x1044f, 1},
+		{0x104d8, 0x104fb, 1},
 		{0x10cc0, 0x10cf2, 1},
 		{0x118c0, 0x118df, 1},
 		{0x1d41a, 0x1d433, 1},
@@ -802,7 +823,8 @@ var _Ll = &RangeTable{
 		{0x1d78a, 0x1d78f, 1},
 		{0x1d7aa, 0x1d7c2, 1},
 		{0x1d7c4, 0x1d7c9, 1},
-		{0x1d7cb, 0x1d7cb, 1},
+		{0x1d7cb, 0x1e922, 4439},
+		{0x1e923, 0x1e943, 1},
 	},
 	LatinOffset: 4,
 }
@@ -854,6 +876,7 @@ var _Lm = &RangeTable{
 		{0x16b40, 0x16b40, 1},
 		{0x16b41, 0x16b43, 1},
 		{0x16f93, 0x16f9f, 1},
+		{0x16fe0, 0x16fe0, 1},
 	},
 }
 
@@ -880,6 +903,7 @@ var _Lo = &RangeTable{
 		{0x0800, 0x0815, 1},
 		{0x0840, 0x0858, 1},
 		{0x08a0, 0x08b4, 1},
+		{0x08b6, 0x08bd, 1},
 		{0x0904, 0x0939, 1},
 		{0x093d, 0x0950, 19},
 		{0x0958, 0x0961, 1},
@@ -940,7 +964,8 @@ var _Lo = &RangeTable{
 		{0x0c3d, 0x0c58, 27},
 		{0x0c59, 0x0c5a, 1},
 		{0x0c60, 0x0c61, 1},
-		{0x0c85, 0x0c8c, 1},
+		{0x0c80, 0x0c85, 5},
+		{0x0c86, 0x0c8c, 1},
 		{0x0c8e, 0x0c90, 1},
 		{0x0c92, 0x0ca8, 1},
 		{0x0caa, 0x0cb3, 1},
@@ -951,8 +976,9 @@ var _Lo = &RangeTable{
 		{0x0d05, 0x0d0c, 1},
 		{0x0d0e, 0x0d10, 1},
 		{0x0d12, 0x0d3a, 1},
-		{0x0d3d, 0x0d5f, 17},
-		{0x0d60, 0x0d61, 1},
+		{0x0d3d, 0x0d4e, 17},
+		{0x0d54, 0x0d56, 1},
+		{0x0d5f, 0x0d61, 1},
 		{0x0d7a, 0x0d7f, 1},
 		{0x0d85, 0x0d96, 1},
 		{0x0d9a, 0x0db1, 1},
@@ -1022,7 +1048,8 @@ var _Lo = &RangeTable{
 		{0x17dc, 0x1820, 68},
 		{0x1821, 0x1842, 1},
 		{0x1844, 0x1877, 1},
-		{0x1880, 0x18a8, 1},
+		{0x1880, 0x1884, 1},
+		{0x1887, 0x18a8, 1},
 		{0x18aa, 0x18b0, 6},
 		{0x18b1, 0x18f5, 1},
 		{0x1900, 0x191e, 1},
@@ -1211,6 +1238,8 @@ var _Lo = &RangeTable{
 		{0x11335, 0x11339, 1},
 		{0x1133d, 0x11350, 19},
 		{0x1135d, 0x11361, 1},
+		{0x11400, 0x11434, 1},
+		{0x11447, 0x1144a, 1},
 		{0x11480, 0x114af, 1},
 		{0x114c4, 0x114c5, 1},
 		{0x114c7, 0x11580, 185},
@@ -1222,6 +1251,10 @@ var _Lo = &RangeTable{
 		{0x11700, 0x11719, 1},
 		{0x118ff, 0x11ac0, 449},
 		{0x11ac1, 0x11af8, 1},
+		{0x11c00, 0x11c08, 1},
+		{0x11c0a, 0x11c2e, 1},
+		{0x11c40, 0x11c72, 50},
+		{0x11c73, 0x11c8f, 1},
 		{0x12000, 0x12399, 1},
 		{0x12480, 0x12543, 1},
 		{0x13000, 0x1342e, 1},
@@ -1233,9 +1266,11 @@ var _Lo = &RangeTable{
 		{0x16b63, 0x16b77, 1},
 		{0x16b7d, 0x16b8f, 1},
 		{0x16f00, 0x16f44, 1},
-		{0x16f50, 0x1b000, 16560},
-		{0x1b001, 0x1bc00, 3071},
-		{0x1bc01, 0x1bc6a, 1},
+		{0x16f50, 0x17000, 176},
+		{0x17001, 0x187ec, 1},
+		{0x18800, 0x18af2, 1},
+		{0x1b000, 0x1b001, 1},
+		{0x1bc00, 0x1bc6a, 1},
 		{0x1bc70, 0x1bc7c, 1},
 		{0x1bc80, 0x1bc88, 1},
 		{0x1bc90, 0x1bc99, 1},
@@ -1386,13 +1421,14 @@ var _Lu = &RangeTable{
 		{0xa78b, 0xa78d, 2},
 		{0xa790, 0xa792, 2},
 		{0xa796, 0xa7aa, 2},
-		{0xa7ab, 0xa7ad, 1},
+		{0xa7ab, 0xa7ae, 1},
 		{0xa7b0, 0xa7b4, 1},
 		{0xa7b6, 0xff21, 22379},
 		{0xff22, 0xff3a, 1},
 	},
 	R32: []Range32{
 		{0x10400, 0x10427, 1},
+		{0x104b0, 0x104d3, 1},
 		{0x10c80, 0x10cb2, 1},
 		{0x118a0, 0x118bf, 1},
 		{0x1d400, 0x1d419, 1},
@@ -1424,7 +1460,8 @@ var _Lu = &RangeTable{
 		{0x1d71c, 0x1d734, 1},
 		{0x1d756, 0x1d76e, 1},
 		{0x1d790, 0x1d7a8, 1},
-		{0x1d7ca, 0x1d7ca, 1},
+		{0x1d7ca, 0x1e900, 4406},
+		{0x1e901, 0x1e921, 1},
 	},
 	LatinOffset: 3,
 }
@@ -1453,6 +1490,7 @@ var _M = &RangeTable{
 		{0x0825, 0x0827, 1},
 		{0x0829, 0x082d, 1},
 		{0x0859, 0x085b, 1},
+		{0x08d4, 0x08e1, 1},
 		{0x08e3, 0x0903, 1},
 		{0x093a, 0x093c, 1},
 		{0x093e, 0x094f, 1},
@@ -1546,6 +1584,7 @@ var _M = &RangeTable{
 		{0x17b4, 0x17d3, 1},
 		{0x17dd, 0x180b, 46},
 		{0x180c, 0x180d, 1},
+		{0x1885, 0x1886, 1},
 		{0x18a9, 0x1920, 119},
 		{0x1921, 0x192b, 1},
 		{0x1930, 0x193b, 1},
@@ -1567,7 +1606,7 @@ var _M = &RangeTable{
 		{0x1cf3, 0x1cf4, 1},
 		{0x1cf8, 0x1cf9, 1},
 		{0x1dc0, 0x1df5, 1},
-		{0x1dfc, 0x1dff, 1},
+		{0x1dfb, 0x1dff, 1},
 		{0x20d0, 0x20f0, 1},
 		{0x2cef, 0x2cf1, 1},
 		{0x2d7f, 0x2de0, 97},
@@ -1582,7 +1621,7 @@ var _M = &RangeTable{
 		{0xa80b, 0xa823, 24},
 		{0xa824, 0xa827, 1},
 		{0xa880, 0xa881, 1},
-		{0xa8b4, 0xa8c4, 1},
+		{0xa8b4, 0xa8c5, 1},
 		{0xa8e0, 0xa8f1, 1},
 		{0xa926, 0xa92d, 1},
 		{0xa947, 0xa953, 1},
@@ -1626,7 +1665,8 @@ var _M = &RangeTable{
 		{0x111b3, 0x111c0, 1},
 		{0x111ca, 0x111cc, 1},
 		{0x1122c, 0x11237, 1},
-		{0x112df, 0x112ea, 1},
+		{0x1123e, 0x112df, 161},
+		{0x112e0, 0x112ea, 1},
 		{0x11300, 0x11303, 1},
 		{0x1133c, 0x1133e, 2},
 		{0x1133f, 0x11344, 1},
@@ -1636,6 +1676,7 @@ var _M = &RangeTable{
 		{0x11363, 0x11366, 3},
 		{0x11367, 0x1136c, 1},
 		{0x11370, 0x11374, 1},
+		{0x11435, 0x11446, 1},
 		{0x114b0, 0x114c3, 1},
 		{0x115af, 0x115b5, 1},
 		{0x115b8, 0x115c0, 1},
@@ -1643,6 +1684,10 @@ var _M = &RangeTable{
 		{0x11630, 0x11640, 1},
 		{0x116ab, 0x116b7, 1},
 		{0x1171d, 0x1172b, 1},
+		{0x11c2f, 0x11c36, 1},
+		{0x11c38, 0x11c3f, 1},
+		{0x11c92, 0x11ca7, 1},
+		{0x11ca9, 0x11cb6, 1},
 		{0x16af0, 0x16af4, 1},
 		{0x16b30, 0x16b36, 1},
 		{0x16f51, 0x16f7e, 1},
@@ -1659,7 +1704,13 @@ var _M = &RangeTable{
 		{0x1da75, 0x1da84, 15},
 		{0x1da9b, 0x1da9f, 1},
 		{0x1daa1, 0x1daaf, 1},
+		{0x1e000, 0x1e006, 1},
+		{0x1e008, 0x1e018, 1},
+		{0x1e01b, 0x1e021, 1},
+		{0x1e023, 0x1e024, 1},
+		{0x1e026, 0x1e02a, 1},
 		{0x1e8d0, 0x1e8d6, 1},
+		{0x1e944, 0x1e94a, 1},
 		{0xe0100, 0xe01ef, 1},
 	},
 }
@@ -1781,7 +1832,10 @@ var _Mc = &RangeTable{
 		{0x11347, 0x11348, 1},
 		{0x1134b, 0x1134d, 1},
 		{0x11357, 0x11362, 11},
-		{0x11363, 0x114b0, 333},
+		{0x11363, 0x11435, 210},
+		{0x11436, 0x11437, 1},
+		{0x11440, 0x11441, 1},
+		{0x11445, 0x114b0, 107},
 		{0x114b1, 0x114b2, 1},
 		{0x114b9, 0x114bb, 2},
 		{0x114bc, 0x114be, 1},
@@ -1795,7 +1849,10 @@ var _Mc = &RangeTable{
 		{0x116ae, 0x116af, 1},
 		{0x116b6, 0x11720, 106},
 		{0x11721, 0x11726, 5},
-		{0x16f51, 0x16f7e, 1},
+		{0x11c2f, 0x11c3e, 15},
+		{0x11ca9, 0x11cb1, 8},
+		{0x11cb4, 0x16f51, 21149},
+		{0x16f52, 0x16f7e, 1},
 		{0x1d165, 0x1d166, 1},
 		{0x1d16d, 0x1d172, 1},
 	},
@@ -1835,6 +1892,7 @@ var _Mn = &RangeTable{
 		{0x0825, 0x0827, 1},
 		{0x0829, 0x082d, 1},
 		{0x0859, 0x085b, 1},
+		{0x08d4, 0x08e1, 1},
 		{0x08e3, 0x0902, 1},
 		{0x093a, 0x093c, 2},
 		{0x0941, 0x0948, 1},
@@ -1913,6 +1971,7 @@ var _Mn = &RangeTable{
 		{0x17ca, 0x17d3, 1},
 		{0x17dd, 0x180b, 46},
 		{0x180c, 0x180d, 1},
+		{0x1885, 0x1886, 1},
 		{0x18a9, 0x1920, 119},
 		{0x1921, 0x1922, 1},
 		{0x1927, 0x1928, 1},
@@ -1946,7 +2005,7 @@ var _Mn = &RangeTable{
 		{0x1ced, 0x1cf4, 7},
 		{0x1cf8, 0x1cf9, 1},
 		{0x1dc0, 0x1df5, 1},
-		{0x1dfc, 0x1dff, 1},
+		{0x1dfb, 0x1dff, 1},
 		{0x20d0, 0x20dc, 1},
 		{0x20e1, 0x20e5, 4},
 		{0x20e6, 0x20f0, 1},
@@ -1962,7 +2021,8 @@ var _Mn = &RangeTable{
 		{0xa802, 0xa806, 4},
 		{0xa80b, 0xa825, 26},
 		{0xa826, 0xa8c4, 158},
-		{0xa8e0, 0xa8f1, 1},
+		{0xa8c5, 0xa8e0, 27},
+		{0xa8e1, 0xa8f1, 1},
 		{0xa926, 0xa92d, 1},
 		{0xa947, 0xa951, 1},
 		{0xa980, 0xa982, 1},
@@ -2006,13 +2066,17 @@ var _Mn = &RangeTable{
 		{0x111ca, 0x111cc, 1},
 		{0x1122f, 0x11231, 1},
 		{0x11234, 0x11236, 2},
-		{0x11237, 0x112df, 168},
-		{0x112e3, 0x112ea, 1},
+		{0x11237, 0x1123e, 7},
+		{0x112df, 0x112e3, 4},
+		{0x112e4, 0x112ea, 1},
 		{0x11300, 0x11301, 1},
 		{0x1133c, 0x11340, 4},
 		{0x11366, 0x1136c, 1},
 		{0x11370, 0x11374, 1},
-		{0x114b3, 0x114b8, 1},
+		{0x11438, 0x1143f, 1},
+		{0x11442, 0x11444, 1},
+		{0x11446, 0x114b3, 109},
+		{0x114b4, 0x114b8, 1},
 		{0x114ba, 0x114bf, 5},
 		{0x114c0, 0x114c2, 2},
 		{0x114c3, 0x115b2, 239},
@@ -2029,6 +2093,13 @@ var _Mn = &RangeTable{
 		{0x1171e, 0x1171f, 1},
 		{0x11722, 0x11725, 1},
 		{0x11727, 0x1172b, 1},
+		{0x11c30, 0x11c36, 1},
+		{0x11c38, 0x11c3d, 1},
+		{0x11c3f, 0x11c92, 83},
+		{0x11c93, 0x11ca7, 1},
+		{0x11caa, 0x11cb0, 1},
+		{0x11cb2, 0x11cb3, 1},
+		{0x11cb5, 0x11cb6, 1},
 		{0x16af0, 0x16af4, 1},
 		{0x16b30, 0x16b36, 1},
 		{0x16f8f, 0x16f92, 1},
@@ -2043,7 +2114,13 @@ var _Mn = &RangeTable{
 		{0x1da75, 0x1da84, 15},
 		{0x1da9b, 0x1da9f, 1},
 		{0x1daa1, 0x1daaf, 1},
+		{0x1e000, 0x1e006, 1},
+		{0x1e008, 0x1e018, 1},
+		{0x1e01b, 0x1e021, 1},
+		{0x1e023, 0x1e024, 1},
+		{0x1e026, 0x1e02a, 1},
 		{0x1e8d0, 0x1e8d6, 1},
+		{0x1e944, 0x1e94a, 1},
 		{0xe0100, 0xe01ef, 1},
 	},
 }
@@ -2068,7 +2145,8 @@ var _N = &RangeTable{
 		{0x0c66, 0x0c6f, 1},
 		{0x0c78, 0x0c7e, 1},
 		{0x0ce6, 0x0cef, 1},
-		{0x0d66, 0x0d75, 1},
+		{0x0d58, 0x0d5e, 1},
+		{0x0d66, 0x0d78, 1},
 		{0x0de6, 0x0def, 1},
 		{0x0e50, 0x0e59, 1},
 		{0x0ed0, 0x0ed9, 1},
@@ -2148,11 +2226,13 @@ var _N = &RangeTable{
 		{0x111d0, 0x111d9, 1},
 		{0x111e1, 0x111f4, 1},
 		{0x112f0, 0x112f9, 1},
+		{0x11450, 0x11459, 1},
 		{0x114d0, 0x114d9, 1},
 		{0x11650, 0x11659, 1},
 		{0x116c0, 0x116c9, 1},
 		{0x11730, 0x1173b, 1},
 		{0x118e0, 0x118f2, 1},
+		{0x11c50, 0x11c6c, 1},
 		{0x12400, 0x1246e, 1},
 		{0x16a60, 0x16a69, 1},
 		{0x16b50, 0x16b59, 1},
@@ -2160,6 +2240,7 @@ var _N = &RangeTable{
 		{0x1d360, 0x1d371, 1},
 		{0x1d7ce, 0x1d7ff, 1},
 		{0x1e8c7, 0x1e8cf, 1},
+		{0x1e950, 0x1e959, 1},
 		{0x1f100, 0x1f10c, 1},
 	},
 	LatinOffset: 4,
@@ -2212,14 +2293,17 @@ var _Nd = &RangeTable{
 		{0x11136, 0x1113f, 1},
 		{0x111d0, 0x111d9, 1},
 		{0x112f0, 0x112f9, 1},
+		{0x11450, 0x11459, 1},
 		{0x114d0, 0x114d9, 1},
 		{0x11650, 0x11659, 1},
 		{0x116c0, 0x116c9, 1},
 		{0x11730, 0x11739, 1},
 		{0x118e0, 0x118e9, 1},
+		{0x11c50, 0x11c59, 1},
 		{0x16a60, 0x16a69, 1},
 		{0x16b50, 0x16b59, 1},
 		{0x1d7ce, 0x1d7ff, 1},
+		{0x1e950, 0x1e959, 1},
 	},
 	LatinOffset: 1,
 }
@@ -2251,7 +2335,8 @@ var _No = &RangeTable{
 		{0x0b72, 0x0b77, 1},
 		{0x0bf0, 0x0bf2, 1},
 		{0x0c78, 0x0c7e, 1},
-		{0x0d70, 0x0d75, 1},
+		{0x0d58, 0x0d5e, 1},
+		{0x0d70, 0x0d78, 1},
 		{0x0f2a, 0x0f33, 1},
 		{0x1369, 0x137c, 1},
 		{0x17f0, 0x17f9, 1},
@@ -2299,6 +2384,7 @@ var _No = &RangeTable{
 		{0x111e1, 0x111f4, 1},
 		{0x1173a, 0x1173b, 1},
 		{0x118ea, 0x118f2, 1},
+		{0x11c5a, 0x11c6c, 1},
 		{0x16b5b, 0x16b61, 1},
 		{0x1d360, 0x1d371, 1},
 		{0x1e8c7, 0x1e8cf, 1},
@@ -2385,7 +2471,7 @@ var _P = &RangeTable{
 		{0x2cfe, 0x2cff, 1},
 		{0x2d70, 0x2e00, 144},
 		{0x2e01, 0x2e2e, 1},
-		{0x2e30, 0x2e42, 1},
+		{0x2e30, 0x2e44, 1},
 		{0x3001, 0x3003, 1},
 		{0x3008, 0x3011, 1},
 		{0x3014, 0x301f, 1},
@@ -2441,16 +2527,23 @@ var _P = &RangeTable{
 		{0x111cd, 0x111db, 14},
 		{0x111dd, 0x111df, 1},
 		{0x11238, 0x1123d, 1},
-		{0x112a9, 0x114c6, 541},
-		{0x115c1, 0x115d7, 1},
+		{0x112a9, 0x1144b, 418},
+		{0x1144c, 0x1144f, 1},
+		{0x1145b, 0x1145d, 2},
+		{0x114c6, 0x115c1, 251},
+		{0x115c2, 0x115d7, 1},
 		{0x11641, 0x11643, 1},
+		{0x11660, 0x1166c, 1},
 		{0x1173c, 0x1173e, 1},
+		{0x11c41, 0x11c45, 1},
+		{0x11c70, 0x11c71, 1},
 		{0x12470, 0x12474, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16b37, 66},
 		{0x16b38, 0x16b3b, 1},
 		{0x16b44, 0x1bc9f, 20827},
 		{0x1da87, 0x1da8b, 1},
+		{0x1e95e, 0x1e95f, 1},
 	},
 	LatinOffset: 11,
 }
@@ -2605,7 +2698,8 @@ var _Po = &RangeTable{
 		{0x2e2b, 0x2e2e, 1},
 		{0x2e30, 0x2e39, 1},
 		{0x2e3c, 0x2e3f, 1},
-		{0x2e41, 0x3001, 448},
+		{0x2e41, 0x2e43, 2},
+		{0x2e44, 0x3001, 445},
 		{0x3002, 0x3003, 1},
 		{0x303d, 0x30fb, 190},
 		{0xa4fe, 0xa4ff, 1},
@@ -2661,16 +2755,23 @@ var _Po = &RangeTable{
 		{0x111cd, 0x111db, 14},
 		{0x111dd, 0x111df, 1},
 		{0x11238, 0x1123d, 1},
-		{0x112a9, 0x114c6, 541},
-		{0x115c1, 0x115d7, 1},
+		{0x112a9, 0x1144b, 418},
+		{0x1144c, 0x1144f, 1},
+		{0x1145b, 0x1145d, 2},
+		{0x114c6, 0x115c1, 251},
+		{0x115c2, 0x115d7, 1},
 		{0x11641, 0x11643, 1},
+		{0x11660, 0x1166c, 1},
 		{0x1173c, 0x1173e, 1},
+		{0x11c41, 0x11c45, 1},
+		{0x11c70, 0x11c71, 1},
 		{0x12470, 0x12474, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16b37, 66},
 		{0x16b38, 0x16b3b, 1},
 		{0x16b44, 0x1bc9f, 20827},
 		{0x1da87, 0x1da8b, 1},
+		{0x1e95e, 0x1e95f, 1},
 	},
 	LatinOffset: 8,
 }
@@ -2736,9 +2837,9 @@ var _S = &RangeTable{
 		{0x09fa, 0x09fb, 1},
 		{0x0af1, 0x0b70, 127},
 		{0x0bf3, 0x0bfa, 1},
-		{0x0c7f, 0x0d79, 250},
-		{0x0e3f, 0x0f01, 194},
-		{0x0f02, 0x0f03, 1},
+		{0x0c7f, 0x0d4f, 208},
+		{0x0d79, 0x0e3f, 198},
+		{0x0f01, 0x0f03, 1},
 		{0x0f13, 0x0f15, 2},
 		{0x0f16, 0x0f17, 1},
 		{0x0f1a, 0x0f1f, 1},
@@ -2778,7 +2879,7 @@ var _S = &RangeTable{
 		{0x218b, 0x2190, 5},
 		{0x2191, 0x2307, 1},
 		{0x230c, 0x2328, 1},
-		{0x232b, 0x23fa, 1},
+		{0x232b, 0x23fe, 1},
 		{0x2400, 0x2426, 1},
 		{0x2440, 0x244a, 1},
 		{0x249c, 0x24e9, 1},
@@ -2839,8 +2940,8 @@ var _S = &RangeTable{
 	R32: []Range32{
 		{0x10137, 0x1013f, 1},
 		{0x10179, 0x10189, 1},
-		{0x1018c, 0x10190, 4},
-		{0x10191, 0x1019b, 1},
+		{0x1018c, 0x1018e, 1},
+		{0x10190, 0x1019b, 1},
 		{0x101a0, 0x101d0, 48},
 		{0x101d1, 0x101fc, 1},
 		{0x10877, 0x10878, 1},
@@ -2876,16 +2977,14 @@ var _S = &RangeTable{
 		{0x1f0d1, 0x1f0f5, 1},
 		{0x1f110, 0x1f12e, 1},
 		{0x1f130, 0x1f16b, 1},
-		{0x1f170, 0x1f19a, 1},
+		{0x1f170, 0x1f1ac, 1},
 		{0x1f1e6, 0x1f202, 1},
-		{0x1f210, 0x1f23a, 1},
+		{0x1f210, 0x1f23b, 1},
 		{0x1f240, 0x1f248, 1},
 		{0x1f250, 0x1f251, 1},
-		{0x1f300, 0x1f579, 1},
-		{0x1f57b, 0x1f5a3, 1},
-		{0x1f5a5, 0x1f6d0, 1},
+		{0x1f300, 0x1f6d2, 1},
 		{0x1f6e0, 0x1f6ec, 1},
-		{0x1f6f0, 0x1f6f3, 1},
+		{0x1f6f0, 0x1f6f6, 1},
 		{0x1f700, 0x1f773, 1},
 		{0x1f780, 0x1f7d4, 1},
 		{0x1f800, 0x1f80b, 1},
@@ -2893,8 +2992,13 @@ var _S = &RangeTable{
 		{0x1f850, 0x1f859, 1},
 		{0x1f860, 0x1f887, 1},
 		{0x1f890, 0x1f8ad, 1},
-		{0x1f910, 0x1f918, 1},
-		{0x1f980, 0x1f984, 1},
+		{0x1f910, 0x1f91e, 1},
+		{0x1f920, 0x1f927, 1},
+		{0x1f930, 0x1f933, 3},
+		{0x1f934, 0x1f93e, 1},
+		{0x1f940, 0x1f94b, 1},
+		{0x1f950, 0x1f95e, 1},
+		{0x1f980, 0x1f991, 1},
 		{0x1f9c0, 0x1f9c0, 1},
 	},
 	LatinOffset: 10,
@@ -3020,8 +3124,8 @@ var _So = &RangeTable{
 		{0x09fa, 0x0b70, 374},
 		{0x0bf3, 0x0bf8, 1},
 		{0x0bfa, 0x0c7f, 133},
-		{0x0d79, 0x0f01, 392},
-		{0x0f02, 0x0f03, 1},
+		{0x0d4f, 0x0d79, 42},
+		{0x0f01, 0x0f03, 1},
 		{0x0f13, 0x0f15, 2},
 		{0x0f16, 0x0f17, 1},
 		{0x0f1a, 0x0f1f, 1},
@@ -3063,7 +3167,7 @@ var _So = &RangeTable{
 		{0x232b, 0x237b, 1},
 		{0x237d, 0x239a, 1},
 		{0x23b4, 0x23db, 1},
-		{0x23e2, 0x23fa, 1},
+		{0x23e2, 0x23fe, 1},
 		{0x2400, 0x2426, 1},
 		{0x2440, 0x244a, 1},
 		{0x249c, 0x24e9, 1},
@@ -3116,8 +3220,8 @@ var _So = &RangeTable{
 		{0x10137, 0x10137, 1},
 		{0x10138, 0x1013f, 1},
 		{0x10179, 0x10189, 1},
-		{0x1018c, 0x10190, 4},
-		{0x10191, 0x1019b, 1},
+		{0x1018c, 0x1018e, 1},
+		{0x10190, 0x1019b, 1},
 		{0x101a0, 0x101d0, 48},
 		{0x101d1, 0x101fc, 1},
 		{0x10877, 0x10878, 1},
@@ -3147,17 +3251,15 @@ var _So = &RangeTable{
 		{0x1f0d1, 0x1f0f5, 1},
 		{0x1f110, 0x1f12e, 1},
 		{0x1f130, 0x1f16b, 1},
-		{0x1f170, 0x1f19a, 1},
+		{0x1f170, 0x1f1ac, 1},
 		{0x1f1e6, 0x1f202, 1},
-		{0x1f210, 0x1f23a, 1},
+		{0x1f210, 0x1f23b, 1},
 		{0x1f240, 0x1f248, 1},
 		{0x1f250, 0x1f251, 1},
 		{0x1f300, 0x1f3fa, 1},
-		{0x1f400, 0x1f579, 1},
-		{0x1f57b, 0x1f5a3, 1},
-		{0x1f5a5, 0x1f6d0, 1},
+		{0x1f400, 0x1f6d2, 1},
 		{0x1f6e0, 0x1f6ec, 1},
-		{0x1f6f0, 0x1f6f3, 1},
+		{0x1f6f0, 0x1f6f6, 1},
 		{0x1f700, 0x1f773, 1},
 		{0x1f780, 0x1f7d4, 1},
 		{0x1f800, 0x1f80b, 1},
@@ -3165,8 +3267,13 @@ var _So = &RangeTable{
 		{0x1f850, 0x1f859, 1},
 		{0x1f860, 0x1f887, 1},
 		{0x1f890, 0x1f8ad, 1},
-		{0x1f910, 0x1f918, 1},
-		{0x1f980, 0x1f984, 1},
+		{0x1f910, 0x1f91e, 1},
+		{0x1f920, 0x1f927, 1},
+		{0x1f930, 0x1f933, 3},
+		{0x1f934, 0x1f93e, 1},
+		{0x1f940, 0x1f94b, 1},
+		{0x1f950, 0x1f95e, 1},
+		{0x1f980, 0x1f991, 1},
 		{0x1f9c0, 0x1f9c0, 1},
 	},
 	LatinOffset: 2,
@@ -3259,11 +3366,12 @@ var (
 )
 
 // Generated by running
-//	maketables --scripts=all --url=http://www.unicode.org/Public/8.0.0/ucd/
+//	maketables --scripts=all --url=http://www.unicode.org/Public/9.0.0/ucd/
 // DO NOT EDIT
 
 // Scripts is the set of Unicode script tables.
 var Scripts = map[string]*RangeTable{
+	"Adlam":                  Adlam,
 	"Ahom":                   Ahom,
 	"Anatolian_Hieroglyphs":  Anatolian_Hieroglyphs,
 	"Arabic":                 Arabic,
@@ -3274,6 +3382,7 @@ var Scripts = map[string]*RangeTable{
 	"Bassa_Vah":              Bassa_Vah,
 	"Batak":                  Batak,
 	"Bengali":                Bengali,
+	"Bhaiksuki":              Bhaiksuki,
 	"Bopomofo":               Bopomofo,
 	"Brahmi":                 Brahmi,
 	"Braille":                Braille,
@@ -3335,6 +3444,7 @@ var Scripts = map[string]*RangeTable{
 	"Malayalam":              Malayalam,
 	"Mandaic":                Mandaic,
 	"Manichaean":             Manichaean,
+	"Marchen":                Marchen,
 	"Meetei_Mayek":           Meetei_Mayek,
 	"Mende_Kikakui":          Mende_Kikakui,
 	"Meroitic_Cursive":       Meroitic_Cursive,
@@ -3347,6 +3457,7 @@ var Scripts = map[string]*RangeTable{
 	"Myanmar":                Myanmar,
 	"Nabataean":              Nabataean,
 	"New_Tai_Lue":            New_Tai_Lue,
+	"Newa":                   Newa,
 	"Nko":                    Nko,
 	"Ogham":                  Ogham,
 	"Ol_Chiki":               Ol_Chiki,
@@ -3358,6 +3469,7 @@ var Scripts = map[string]*RangeTable{
 	"Old_South_Arabian":      Old_South_Arabian,
 	"Old_Turkic":             Old_Turkic,
 	"Oriya":                  Oriya,
+	"Osage":                  Osage,
 	"Osmanya":                Osmanya,
 	"Pahawh_Hmong":           Pahawh_Hmong,
 	"Palmyrene":              Palmyrene,
@@ -3385,6 +3497,7 @@ var Scripts = map[string]*RangeTable{
 	"Tai_Viet":               Tai_Viet,
 	"Takri":                  Takri,
 	"Tamil":                  Tamil,
+	"Tangut":                 Tangut,
 	"Telugu":                 Telugu,
 	"Thaana":                 Thaana,
 	"Thai":                   Thai,
@@ -3397,6 +3510,15 @@ var Scripts = map[string]*RangeTable{
 	"Yi":                     Yi,
 }
 
+var _Adlam = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x1e900, 0x1e94a, 1},
+		{0x1e950, 0x1e959, 1},
+		{0x1e95e, 0x1e95f, 1},
+	},
+}
+
 var _Ahom = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
@@ -3426,6 +3548,8 @@ var _Arabic = &RangeTable{
 		{0x06de, 0x06ff, 1},
 		{0x0750, 0x077f, 1},
 		{0x08a0, 0x08b4, 1},
+		{0x08b6, 0x08bd, 1},
+		{0x08d4, 0x08e1, 1},
 		{0x08e3, 0x08ff, 1},
 		{0xfb50, 0xfbc1, 1},
 		{0xfbd3, 0xfd3d, 1},
@@ -3543,6 +3667,16 @@ var _Bengali = &RangeTable{
 	},
 }
 
+var _Bhaiksuki = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x11c00, 0x11c08, 1},
+		{0x11c0a, 0x11c36, 1},
+		{0x11c38, 0x11c45, 1},
+		{0x11c50, 0x11c6c, 1},
+	},
+}
+
 var _Bopomofo = &RangeTable{
 	R16: []Range16{
 		{0x02ea, 0x02eb, 1},
@@ -3649,6 +3783,7 @@ var _Common = &RangeTable{
 		{0x061f, 0x061f, 1},
 		{0x0640, 0x0640, 1},
 		{0x06dd, 0x06dd, 1},
+		{0x08e2, 0x08e2, 1},
 		{0x0964, 0x0965, 1},
 		{0x0e3f, 0x0e3f, 1},
 		{0x0fd5, 0x0fd8, 1},
@@ -3674,7 +3809,7 @@ var _Common = &RangeTable{
 		{0x2133, 0x214d, 1},
 		{0x214f, 0x215f, 1},
 		{0x2189, 0x218b, 1},
-		{0x2190, 0x23fa, 1},
+		{0x2190, 0x23fe, 1},
 		{0x2400, 0x2426, 1},
 		{0x2440, 0x244a, 1},
 		{0x2460, 0x27ff, 1},
@@ -3684,7 +3819,7 @@ var _Common = &RangeTable{
 		{0x2bbd, 0x2bc8, 1},
 		{0x2bca, 0x2bd1, 1},
 		{0x2bec, 0x2bef, 1},
-		{0x2e00, 0x2e42, 1},
+		{0x2e00, 0x2e44, 1},
 		{0x2ff0, 0x2ffb, 1},
 		{0x3000, 0x3004, 1},
 		{0x3006, 0x3006, 1},
@@ -3768,17 +3903,15 @@ var _Common = &RangeTable{
 		{0x1f100, 0x1f10c, 1},
 		{0x1f110, 0x1f12e, 1},
 		{0x1f130, 0x1f16b, 1},
-		{0x1f170, 0x1f19a, 1},
+		{0x1f170, 0x1f1ac, 1},
 		{0x1f1e6, 0x1f1ff, 1},
 		{0x1f201, 0x1f202, 1},
-		{0x1f210, 0x1f23a, 1},
+		{0x1f210, 0x1f23b, 1},
 		{0x1f240, 0x1f248, 1},
 		{0x1f250, 0x1f251, 1},
-		{0x1f300, 0x1f579, 1},
-		{0x1f57b, 0x1f5a3, 1},
-		{0x1f5a5, 0x1f6d0, 1},
+		{0x1f300, 0x1f6d2, 1},
 		{0x1f6e0, 0x1f6ec, 1},
-		{0x1f6f0, 0x1f6f3, 1},
+		{0x1f6f0, 0x1f6f6, 1},
 		{0x1f700, 0x1f773, 1},
 		{0x1f780, 0x1f7d4, 1},
 		{0x1f800, 0x1f80b, 1},
@@ -3786,8 +3919,13 @@ var _Common = &RangeTable{
 		{0x1f850, 0x1f859, 1},
 		{0x1f860, 0x1f887, 1},
 		{0x1f890, 0x1f8ad, 1},
-		{0x1f910, 0x1f918, 1},
-		{0x1f980, 0x1f984, 1},
+		{0x1f910, 0x1f91e, 1},
+		{0x1f920, 0x1f927, 1},
+		{0x1f930, 0x1f930, 1},
+		{0x1f933, 0x1f93e, 1},
+		{0x1f940, 0x1f94b, 1},
+		{0x1f950, 0x1f95e, 1},
+		{0x1f980, 0x1f991, 1},
 		{0x1f9c0, 0x1f9c0, 1},
 		{0xe0001, 0xe0001, 1},
 		{0xe0020, 0xe007f, 1},
@@ -3829,6 +3967,7 @@ var _Cyrillic = &RangeTable{
 	R16: []Range16{
 		{0x0400, 0x0484, 1},
 		{0x0487, 0x052f, 1},
+		{0x1c80, 0x1c88, 1},
 		{0x1d2b, 0x1d2b, 1},
 		{0x1d78, 0x1d78, 1},
 		{0x2de0, 0x2dff, 1},
@@ -3933,6 +4072,13 @@ var _Glagolitic = &RangeTable{
 		{0x2c00, 0x2c2e, 1},
 		{0x2c30, 0x2c5e, 1},
 	},
+	R32: []Range32{
+		{0x1e000, 0x1e006, 1},
+		{0x1e008, 0x1e018, 1},
+		{0x1e01b, 0x1e021, 1},
+		{0x1e023, 0x1e024, 1},
+		{0x1e026, 0x1e02a, 1},
+	},
 }
 
 var _Gothic = &RangeTable{
@@ -4000,7 +4146,7 @@ var _Greek = &RangeTable{
 		{0xab65, 0xab65, 1},
 	},
 	R32: []Range32{
-		{0x10140, 0x1018c, 1},
+		{0x10140, 0x1018e, 1},
 		{0x101a0, 0x101a0, 1},
 		{0x1d200, 0x1d245, 1},
 	},
@@ -4151,7 +4297,7 @@ var _Inherited = &RangeTable{
 		{0x1cf4, 0x1cf4, 1},
 		{0x1cf8, 0x1cf9, 1},
 		{0x1dc0, 0x1df5, 1},
-		{0x1dfc, 0x1dff, 1},
+		{0x1dfb, 0x1dff, 1},
 		{0x200c, 0x200d, 1},
 		{0x20d0, 0x20f0, 1},
 		{0x302a, 0x302d, 1},
@@ -4203,7 +4349,7 @@ var _Kaithi = &RangeTable{
 
 var _Kannada = &RangeTable{
 	R16: []Range16{
-		{0x0c81, 0x0c83, 1},
+		{0x0c80, 0x0c83, 1},
 		{0x0c85, 0x0c8c, 1},
 		{0x0c8e, 0x0c90, 1},
 		{0x0c92, 0x0ca8, 1},
@@ -4269,7 +4415,7 @@ var _Khojki = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
 		{0x11200, 0x11211, 1},
-		{0x11213, 0x1123d, 1},
+		{0x11213, 0x1123e, 1},
 	},
 }
 
@@ -4329,7 +4475,7 @@ var _Latin = &RangeTable{
 		{0x2160, 0x2188, 1},
 		{0x2c60, 0x2c7f, 1},
 		{0xa722, 0xa787, 1},
-		{0xa78b, 0xa7ad, 1},
+		{0xa78b, 0xa7ae, 1},
 		{0xa7b0, 0xa7b7, 1},
 		{0xa7f7, 0xa7ff, 1},
 		{0xab30, 0xab5a, 1},
@@ -4417,11 +4563,9 @@ var _Malayalam = &RangeTable{
 		{0x0d12, 0x0d3a, 1},
 		{0x0d3d, 0x0d44, 1},
 		{0x0d46, 0x0d48, 1},
-		{0x0d4a, 0x0d4e, 1},
-		{0x0d57, 0x0d57, 1},
-		{0x0d5f, 0x0d63, 1},
-		{0x0d66, 0x0d75, 1},
-		{0x0d79, 0x0d7f, 1},
+		{0x0d4a, 0x0d4f, 1},
+		{0x0d54, 0x0d63, 1},
+		{0x0d66, 0x0d7f, 1},
 	},
 }
 
@@ -4440,6 +4584,15 @@ var _Manichaean = &RangeTable{
 	},
 }
 
+var _Marchen = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x11c70, 0x11c8f, 1},
+		{0x11c92, 0x11ca7, 1},
+		{0x11ca9, 0x11cb6, 1},
+	},
+}
+
 var _Meetei_Mayek = &RangeTable{
 	R16: []Range16{
 		{0xaae0, 0xaaf6, 1},
@@ -4498,6 +4651,9 @@ var _Mongolian = &RangeTable{
 		{0x1820, 0x1877, 1},
 		{0x1880, 0x18aa, 1},
 	},
+	R32: []Range32{
+		{0x11660, 0x1166c, 1},
+	},
 }
 
 var _Mro = &RangeTable{
@@ -4545,6 +4701,15 @@ var _New_Tai_Lue = &RangeTable{
 	},
 }
 
+var _Newa = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x11400, 0x11459, 1},
+		{0x1145b, 0x1145b, 1},
+		{0x1145d, 0x1145d, 1},
+	},
+}
+
 var _Nko = &RangeTable{
 	R16: []Range16{
 		{0x07c0, 0x07fa, 1},
@@ -4634,6 +4799,14 @@ var _Oriya = &RangeTable{
 	},
 }
 
+var _Osage = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x104b0, 0x104d3, 1},
+		{0x104d8, 0x104fb, 1},
+	},
+}
+
 var _Osmanya = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
@@ -4713,7 +4886,7 @@ var _Samaritan = &RangeTable{
 
 var _Saurashtra = &RangeTable{
 	R16: []Range16{
-		{0xa880, 0xa8c4, 1},
+		{0xa880, 0xa8c5, 1},
 		{0xa8ce, 0xa8d9, 1},
 	},
 }
@@ -4867,6 +5040,15 @@ var _Tamil = &RangeTable{
 	},
 }
 
+var _Tangut = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x16fe0, 0x16fe0, 1},
+		{0x17000, 0x187ec, 1},
+		{0x18800, 0x18af2, 1},
+	},
+}
+
 var _Telugu = &RangeTable{
 	R16: []Range16{
 		{0x0c00, 0x0c03, 1},
@@ -4957,6 +5139,7 @@ var _Yi = &RangeTable{
 
 // These variables have type *RangeTable.
 var (
+	Adlam                  = _Adlam                  // Adlam is the set of Unicode characters in script Adlam.
 	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.
@@ -4967,6 +5150,7 @@ var (
 	Bassa_Vah              = _Bassa_Vah              // Bassa_Vah is the set of Unicode characters in script Bassa_Vah.
 	Batak                  = _Batak                  // Batak is the set of Unicode characters in script Batak.
 	Bengali                = _Bengali                // Bengali is the set of Unicode characters in script Bengali.
+	Bhaiksuki              = _Bhaiksuki              // Bhaiksuki is the set of Unicode characters in script Bhaiksuki.
 	Bopomofo               = _Bopomofo               // Bopomofo is the set of Unicode characters in script Bopomofo.
 	Brahmi                 = _Brahmi                 // Brahmi is the set of Unicode characters in script Brahmi.
 	Braille                = _Braille                // Braille is the set of Unicode characters in script Braille.
@@ -5028,6 +5212,7 @@ var (
 	Malayalam              = _Malayalam              // Malayalam is the set of Unicode characters in script Malayalam.
 	Mandaic                = _Mandaic                // Mandaic is the set of Unicode characters in script Mandaic.
 	Manichaean             = _Manichaean             // Manichaean is the set of Unicode characters in script Manichaean.
+	Marchen                = _Marchen                // Marchen is the set of Unicode characters in script Marchen.
 	Meetei_Mayek           = _Meetei_Mayek           // Meetei_Mayek is the set of Unicode characters in script Meetei_Mayek.
 	Mende_Kikakui          = _Mende_Kikakui          // Mende_Kikakui is the set of Unicode characters in script Mende_Kikakui.
 	Meroitic_Cursive       = _Meroitic_Cursive       // Meroitic_Cursive is the set of Unicode characters in script Meroitic_Cursive.
@@ -5040,6 +5225,7 @@ var (
 	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.
+	Newa                   = _Newa                   // Newa is the set of Unicode characters in script Newa.
 	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.
@@ -5051,6 +5237,7 @@ var (
 	Old_South_Arabian      = _Old_South_Arabian      // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian.
 	Old_Turkic             = _Old_Turkic             // Old_Turkic is the set of Unicode characters in script Old_Turkic.
 	Oriya                  = _Oriya                  // Oriya is the set of Unicode characters in script Oriya.
+	Osage                  = _Osage                  // Osage is the set of Unicode characters in script Osage.
 	Osmanya                = _Osmanya                // Osmanya is the set of Unicode characters in script Osmanya.
 	Pahawh_Hmong           = _Pahawh_Hmong           // Pahawh_Hmong is the set of Unicode characters in script Pahawh_Hmong.
 	Palmyrene              = _Palmyrene              // Palmyrene is the set of Unicode characters in script Palmyrene.
@@ -5078,6 +5265,7 @@ var (
 	Tai_Viet               = _Tai_Viet               // Tai_Viet is the set of Unicode characters in script Tai_Viet.
 	Takri                  = _Takri                  // Takri is the set of Unicode characters in script Takri.
 	Tamil                  = _Tamil                  // Tamil is the set of Unicode characters in script Tamil.
+	Tangut                 = _Tangut                 // Tangut is the set of Unicode characters in script Tangut.
 	Telugu                 = _Telugu                 // Telugu is the set of Unicode characters in script Telugu.
 	Thaana                 = _Thaana                 // Thaana is the set of Unicode characters in script Thaana.
 	Thai                   = _Thai                   // Thai is the set of Unicode characters in script Thai.
@@ -5091,7 +5279,7 @@ var (
 )
 
 // Generated by running
-//	maketables --props=all --url=http://www.unicode.org/Public/8.0.0/ucd/
+//	maketables --props=all --url=http://www.unicode.org/Public/9.0.0/ucd/
 // DO NOT EDIT
 
 // Properties is the set of Unicode property tables.
@@ -5120,9 +5308,11 @@ var Properties = map[string]*RangeTable{
 	"Other_Uppercase":                    Other_Uppercase,
 	"Pattern_Syntax":                     Pattern_Syntax,
 	"Pattern_White_Space":                Pattern_White_Space,
+	"Prepended_Concatenation_Mark":       Prepended_Concatenation_Mark,
 	"Quotation_Mark":                     Quotation_Mark,
 	"Radical":                            Radical,
-	"STerm":                              STerm,
+	"Sentence_Terminal":                  Sentence_Terminal,
+	"STerm":                              Sentence_Terminal,
 	"Soft_Dotted":                        Soft_Dotted,
 	"Terminal_Punctuation":               Terminal_Punctuation,
 	"Unified_Ideograph":                  Unified_Ideograph,
@@ -5187,7 +5377,6 @@ var _Deprecated = &RangeTable{
 	},
 	R32: []Range32{
 		{0xe0001, 0xe0001, 1},
-		{0xe007f, 0xe007f, 1},
 	},
 }
 
@@ -5329,11 +5518,14 @@ var _Diacritic = &RangeTable{
 		{0x1134d, 0x1134d, 1},
 		{0x11366, 0x1136c, 1},
 		{0x11370, 0x11374, 1},
+		{0x11442, 0x11442, 1},
+		{0x11446, 0x11446, 1},
 		{0x114c2, 0x114c3, 1},
 		{0x115bf, 0x115c0, 1},
 		{0x1163f, 0x1163f, 1},
 		{0x116b6, 0x116b7, 1},
 		{0x1172b, 0x1172b, 1},
+		{0x11c3f, 0x11c3f, 1},
 		{0x16af0, 0x16af4, 1},
 		{0x16f8f, 0x16f9f, 1},
 		{0x1d167, 0x1d169, 1},
@@ -5342,6 +5534,8 @@ var _Diacritic = &RangeTable{
 		{0x1d185, 0x1d18b, 1},
 		{0x1d1aa, 0x1d1ad, 1},
 		{0x1e8d0, 0x1e8d6, 1},
+		{0x1e944, 0x1e946, 1},
+		{0x1e948, 0x1e94a, 1},
 	},
 	LatinOffset: 6,
 }
@@ -5376,6 +5570,8 @@ var _Extender = &RangeTable{
 		{0x1135d, 0x1135d, 1},
 		{0x115c6, 0x115c8, 1},
 		{0x16b42, 0x16b43, 1},
+		{0x16fe0, 0x16fe0, 1},
+		{0x1e944, 0x1e946, 1},
 	},
 	LatinOffset: 1,
 }
@@ -5432,6 +5628,8 @@ var _Ideographic = &RangeTable{
 		{0xfa70, 0xfad9, 1},
 	},
 	R32: []Range32{
+		{0x17000, 0x187ec, 1},
+		{0x18800, 0x18af2, 1},
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
@@ -5506,6 +5704,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0x081b, 0x0823, 1},
 		{0x0825, 0x0827, 1},
 		{0x0829, 0x082c, 1},
+		{0x08d4, 0x08df, 1},
 		{0x08e3, 0x08e9, 1},
 		{0x08f0, 0x0903, 1},
 		{0x093a, 0x093b, 1},
@@ -5591,6 +5790,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0x1752, 0x1753, 1},
 		{0x1772, 0x1773, 1},
 		{0x17b6, 0x17c8, 1},
+		{0x1885, 0x1886, 1},
 		{0x18a9, 0x18a9, 1},
 		{0x1920, 0x192b, 1},
 		{0x1930, 0x1938, 1},
@@ -5613,6 +5813,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0xa823, 0xa827, 1},
 		{0xa880, 0xa881, 1},
 		{0xa8b4, 0xa8c3, 1},
+		{0xa8c5, 0xa8c5, 1},
 		{0xa926, 0xa92a, 1},
 		{0xa947, 0xa952, 1},
 		{0xa980, 0xa983, 1},
@@ -5644,6 +5845,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0x111b3, 0x111bf, 1},
 		{0x1122c, 0x11234, 1},
 		{0x11237, 0x11237, 1},
+		{0x1123e, 0x1123e, 1},
 		{0x112df, 0x112e8, 1},
 		{0x11300, 0x11303, 1},
 		{0x1133e, 0x11344, 1},
@@ -5651,6 +5853,8 @@ var _Other_Alphabetic = &RangeTable{
 		{0x1134b, 0x1134c, 1},
 		{0x11357, 0x11357, 1},
 		{0x11362, 0x11363, 1},
+		{0x11435, 0x11441, 1},
+		{0x11443, 0x11445, 1},
 		{0x114b0, 0x114c1, 1},
 		{0x115af, 0x115b5, 1},
 		{0x115b8, 0x115be, 1},
@@ -5659,9 +5863,19 @@ var _Other_Alphabetic = &RangeTable{
 		{0x11640, 0x11640, 1},
 		{0x116ab, 0x116b5, 1},
 		{0x1171d, 0x1172a, 1},
+		{0x11c2f, 0x11c36, 1},
+		{0x11c38, 0x11c3e, 1},
+		{0x11c92, 0x11ca7, 1},
+		{0x11ca9, 0x11cb6, 1},
 		{0x16b30, 0x16b36, 1},
 		{0x16f51, 0x16f7e, 1},
 		{0x1bc9e, 0x1bc9e, 1},
+		{0x1e000, 0x1e006, 1},
+		{0x1e008, 0x1e018, 1},
+		{0x1e01b, 0x1e021, 1},
+		{0x1e023, 0x1e024, 1},
+		{0x1e026, 0x1e02a, 1},
+		{0x1e947, 0x1e947, 1},
 		{0x1f130, 0x1f149, 1},
 		{0x1f150, 0x1f169, 1},
 		{0x1f170, 0x1f189, 1},
@@ -5700,7 +5914,7 @@ var _Other_Grapheme_Extend = &RangeTable{
 		{0x0d57, 0x0d57, 1},
 		{0x0dcf, 0x0dcf, 1},
 		{0x0ddf, 0x0ddf, 1},
-		{0x200c, 0x200d, 1},
+		{0x200c, 0x200c, 1},
 		{0x302e, 0x302f, 1},
 		{0xff9e, 0xff9f, 1},
 	},
@@ -5712,6 +5926,7 @@ var _Other_Grapheme_Extend = &RangeTable{
 		{0x115af, 0x115af, 1},
 		{0x1d165, 0x1d165, 1},
 		{0x1d16e, 0x1d172, 1},
+		{0xe0020, 0xe007f, 1},
 	},
 }
 
@@ -5727,6 +5942,7 @@ var _Other_ID_Continue = &RangeTable{
 
 var _Other_ID_Start = &RangeTable{
 	R16: []Range16{
+		{0x1885, 0x1886, 1},
 		{0x2118, 0x2118, 1},
 		{0x212e, 0x212e, 1},
 		{0x309b, 0x309c, 1},
@@ -5958,6 +6174,18 @@ var _Pattern_White_Space = &RangeTable{
 	LatinOffset: 3,
 }
 
+var _Prepended_Concatenation_Mark = &RangeTable{
+	R16: []Range16{
+		{0x0600, 0x0605, 1},
+		{0x06dd, 0x06dd, 1},
+		{0x070f, 0x070f, 1},
+		{0x08e2, 0x08e2, 1},
+	},
+	R32: []Range32{
+		{0x110bd, 0x110bd, 1},
+	},
+}
+
 var _Quotation_Mark = &RangeTable{
 	R16: []Range16{
 		{0x0022, 0x0022, 1},
@@ -5985,7 +6213,7 @@ var _Radical = &RangeTable{
 	},
 }
 
-var _STerm = &RangeTable{
+var _Sentence_Terminal = &RangeTable{
 	R16: []Range16{
 		{0x0021, 0x0021, 1},
 		{0x002e, 0x002e, 1},
@@ -6043,10 +6271,12 @@ var _STerm = &RangeTable{
 		{0x11238, 0x11239, 1},
 		{0x1123b, 0x1123c, 1},
 		{0x112a9, 0x112a9, 1},
+		{0x1144b, 0x1144c, 1},
 		{0x115c2, 0x115c3, 1},
 		{0x115c9, 0x115d7, 1},
 		{0x11641, 0x11642, 1},
 		{0x1173c, 0x1173e, 1},
+		{0x11c41, 0x11c42, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16af5, 1},
 		{0x16b37, 0x16b38, 1},
@@ -6179,10 +6409,14 @@ var _Terminal_Punctuation = &RangeTable{
 		{0x111de, 0x111df, 1},
 		{0x11238, 0x1123c, 1},
 		{0x112a9, 0x112a9, 1},
+		{0x1144b, 0x1144d, 1},
+		{0x1145b, 0x1145b, 1},
 		{0x115c2, 0x115c5, 1},
 		{0x115c9, 0x115d7, 1},
 		{0x11641, 0x11642, 1},
 		{0x1173c, 0x1173e, 1},
+		{0x11c41, 0x11c43, 1},
+		{0x11c71, 0x11c71, 1},
 		{0x12470, 0x12474, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16af5, 1},
@@ -6266,9 +6500,11 @@ var (
 	Other_Uppercase                    = _Other_Uppercase                    // Other_Uppercase is the set of Unicode characters with property Other_Uppercase.
 	Pattern_Syntax                     = _Pattern_Syntax                     // Pattern_Syntax is the set of Unicode characters with property Pattern_Syntax.
 	Pattern_White_Space                = _Pattern_White_Space                // Pattern_White_Space is the set of Unicode characters with property Pattern_White_Space.
+	Prepended_Concatenation_Mark       = _Prepended_Concatenation_Mark       // Prepended_Concatenation_Mark is the set of Unicode characters with property Prepended_Concatenation_Mark.
 	Quotation_Mark                     = _Quotation_Mark                     // Quotation_Mark is the set of Unicode characters with property Quotation_Mark.
 	Radical                            = _Radical                            // Radical is the set of Unicode characters with property Radical.
-	STerm                              = _STerm                              // STerm is the set of Unicode characters with property STerm.
+	STerm                              = _Sentence_Terminal                  // STerm is an alias for Sentence_Terminal.
+	Sentence_Terminal                  = _Sentence_Terminal                  // Sentence_Terminal is the set of Unicode characters with property Sentence_Terminal.
 	Soft_Dotted                        = _Soft_Dotted                        // Soft_Dotted is the set of Unicode characters with property Soft_Dotted.
 	Terminal_Punctuation               = _Terminal_Punctuation               // Terminal_Punctuation is the set of Unicode characters with property Terminal_Punctuation.
 	Unified_Ideograph                  = _Unified_Ideograph                  // Unified_Ideograph is the set of Unicode characters with property Unified_Ideograph.
@@ -6277,7 +6513,7 @@ var (
 )
 
 // Generated by running
-//	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
+//	maketables --data=http://www.unicode.org/Public/9.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/9.0.0/ucd/CaseFolding.txt
 // DO NOT EDIT
 
 // CaseRanges is the table describing case mappings for all letters with
@@ -6383,6 +6619,7 @@ var _CaseRanges = []CaseRange{
 	{0x0266, 0x0266, d{42308, 0, 42308}},
 	{0x0268, 0x0268, d{-209, 0, -209}},
 	{0x0269, 0x0269, d{-211, 0, -211}},
+	{0x026A, 0x026A, d{42308, 0, 42308}},
 	{0x026B, 0x026B, d{10743, 0, 10743}},
 	{0x026C, 0x026C, d{42305, 0, 42305}},
 	{0x026F, 0x026F, d{-211, 0, -211}},
@@ -6453,6 +6690,14 @@ var _CaseRanges = []CaseRange{
 	{0x13A0, 0x13EF, d{0, 38864, 0}},
 	{0x13F0, 0x13F5, d{0, 8, 0}},
 	{0x13F8, 0x13FD, d{-8, 0, -8}},
+	{0x1C80, 0x1C80, d{-6254, 0, -6254}},
+	{0x1C81, 0x1C81, d{-6253, 0, -6253}},
+	{0x1C82, 0x1C82, d{-6244, 0, -6244}},
+	{0x1C83, 0x1C84, d{-6242, 0, -6242}},
+	{0x1C85, 0x1C85, d{-6243, 0, -6243}},
+	{0x1C86, 0x1C86, d{-6236, 0, -6236}},
+	{0x1C87, 0x1C87, d{-6181, 0, -6181}},
+	{0x1C88, 0x1C88, d{35266, 0, 35266}},
 	{0x1D79, 0x1D79, d{35332, 0, 35332}},
 	{0x1D7D, 0x1D7D, d{3814, 0, 3814}},
 	{0x1E00, 0x1E95, d{UpperLower, UpperLower, UpperLower}},
@@ -6559,6 +6804,7 @@ var _CaseRanges = []CaseRange{
 	{0xA7AB, 0xA7AB, d{0, -42319, 0}},
 	{0xA7AC, 0xA7AC, d{0, -42315, 0}},
 	{0xA7AD, 0xA7AD, d{0, -42305, 0}},
+	{0xA7AE, 0xA7AE, d{0, -42308, 0}},
 	{0xA7B0, 0xA7B0, d{0, -42258, 0}},
 	{0xA7B1, 0xA7B1, d{0, -42282, 0}},
 	{0xA7B2, 0xA7B2, d{0, -42261, 0}},
@@ -6570,10 +6816,14 @@ var _CaseRanges = []CaseRange{
 	{0xFF41, 0xFF5A, d{-32, 0, -32}},
 	{0x10400, 0x10427, d{0, 40, 0}},
 	{0x10428, 0x1044F, d{-40, 0, -40}},
+	{0x104B0, 0x104D3, d{0, 40, 0}},
+	{0x104D8, 0x104FB, 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}},
+	{0x1E900, 0x1E921, d{0, 34, 0}},
+	{0x1E922, 0x1E943, d{-34, 0, -34}},
 }
 var properties = [MaxLatin1 + 1]uint8{
 	0x00: pC,       // '\x00'
@@ -6834,6 +7084,137 @@ var properties = [MaxLatin1 + 1]uint8{
 	0xFF: pLl | pp, // 'ÿ'
 }
 
+var asciiFold = [MaxASCII + 1]uint16{
+	0x0000,
+	0x0001,
+	0x0002,
+	0x0003,
+	0x0004,
+	0x0005,
+	0x0006,
+	0x0007,
+	0x0008,
+	0x0009,
+	0x000A,
+	0x000B,
+	0x000C,
+	0x000D,
+	0x000E,
+	0x000F,
+	0x0010,
+	0x0011,
+	0x0012,
+	0x0013,
+	0x0014,
+	0x0015,
+	0x0016,
+	0x0017,
+	0x0018,
+	0x0019,
+	0x001A,
+	0x001B,
+	0x001C,
+	0x001D,
+	0x001E,
+	0x001F,
+	0x0020,
+	0x0021,
+	0x0022,
+	0x0023,
+	0x0024,
+	0x0025,
+	0x0026,
+	0x0027,
+	0x0028,
+	0x0029,
+	0x002A,
+	0x002B,
+	0x002C,
+	0x002D,
+	0x002E,
+	0x002F,
+	0x0030,
+	0x0031,
+	0x0032,
+	0x0033,
+	0x0034,
+	0x0035,
+	0x0036,
+	0x0037,
+	0x0038,
+	0x0039,
+	0x003A,
+	0x003B,
+	0x003C,
+	0x003D,
+	0x003E,
+	0x003F,
+	0x0040,
+	0x0061,
+	0x0062,
+	0x0063,
+	0x0064,
+	0x0065,
+	0x0066,
+	0x0067,
+	0x0068,
+	0x0069,
+	0x006A,
+	0x006B,
+	0x006C,
+	0x006D,
+	0x006E,
+	0x006F,
+	0x0070,
+	0x0071,
+	0x0072,
+	0x0073,
+	0x0074,
+	0x0075,
+	0x0076,
+	0x0077,
+	0x0078,
+	0x0079,
+	0x007A,
+	0x005B,
+	0x005C,
+	0x005D,
+	0x005E,
+	0x005F,
+	0x0060,
+	0x0041,
+	0x0042,
+	0x0043,
+	0x0044,
+	0x0045,
+	0x0046,
+	0x0047,
+	0x0048,
+	0x0049,
+	0x004A,
+	0x212A,
+	0x004C,
+	0x004D,
+	0x004E,
+	0x004F,
+	0x0050,
+	0x0051,
+	0x0052,
+	0x017F,
+	0x0054,
+	0x0055,
+	0x0056,
+	0x0057,
+	0x0058,
+	0x0059,
+	0x005A,
+	0x007B,
+	0x007C,
+	0x007D,
+	0x007E,
+	0x007F,
+}
+
 var caseOrbit = []foldPair{
 	{0x004B, 0x006B},
 	{0x0053, 0x0073},
@@ -6890,6 +7271,29 @@ var caseOrbit = []foldPair{
 	{0x03F1, 0x03A1},
 	{0x03F4, 0x0398},
 	{0x03F5, 0x0395},
+	{0x0412, 0x0432},
+	{0x0414, 0x0434},
+	{0x041E, 0x043E},
+	{0x0421, 0x0441},
+	{0x0422, 0x0442},
+	{0x042A, 0x044A},
+	{0x0432, 0x1C80},
+	{0x0434, 0x1C81},
+	{0x043E, 0x1C82},
+	{0x0441, 0x1C83},
+	{0x0442, 0x1C84},
+	{0x044A, 0x1C86},
+	{0x0462, 0x0463},
+	{0x0463, 0x1C87},
+	{0x1C80, 0x0412},
+	{0x1C81, 0x0414},
+	{0x1C82, 0x041E},
+	{0x1C83, 0x0421},
+	{0x1C84, 0x1C85},
+	{0x1C85, 0x0422},
+	{0x1C86, 0x042A},
+	{0x1C87, 0x0462},
+	{0x1C88, 0xA64A},
 	{0x1E60, 0x1E61},
 	{0x1E61, 0x1E9B},
 	{0x1E9B, 0x1E60},
@@ -6898,6 +7302,8 @@ var caseOrbit = []foldPair{
 	{0x2126, 0x03A9},
 	{0x212A, 0x004B},
 	{0x212B, 0x00C5},
+	{0xA64A, 0xA64B},
+	{0xA64B, 0x1C88},
 }
 
 // FoldCategory maps a category name to a table of
@@ -7041,15 +7447,17 @@ var foldLl = &RangeTable{
 		{0xa78b, 0xa78d, 2},
 		{0xa790, 0xa792, 2},
 		{0xa796, 0xa7aa, 2},
-		{0xa7ab, 0xa7ad, 1},
+		{0xa7ab, 0xa7ae, 1},
 		{0xa7b0, 0xa7b4, 1},
 		{0xa7b6, 0xff21, 22379},
 		{0xff22, 0xff3a, 1},
 	},
 	R32: []Range32{
 		{0x10400, 0x10427, 1},
+		{0x104b0, 0x104d3, 1},
 		{0x10c80, 0x10cb2, 1},
 		{0x118a0, 0x118bf, 1},
+		{0x1e900, 0x1e921, 1},
 	},
 	LatinOffset: 3,
 }
@@ -7108,11 +7516,10 @@ var foldLu = &RangeTable{
 		{0x025c, 0x0260, 4},
 		{0x0261, 0x0265, 2},
 		{0x0266, 0x0268, 2},
-		{0x0269, 0x026b, 2},
-		{0x026c, 0x026f, 3},
-		{0x0271, 0x0272, 1},
-		{0x0275, 0x027d, 8},
-		{0x0280, 0x0283, 3},
+		{0x0269, 0x026c, 1},
+		{0x026f, 0x0271, 2},
+		{0x0272, 0x0275, 3},
+		{0x027d, 0x0283, 3},
 		{0x0287, 0x028c, 1},
 		{0x0292, 0x029d, 11},
 		{0x029e, 0x0345, 167},
@@ -7133,6 +7540,7 @@ var foldLu = &RangeTable{
 		{0x04cf, 0x052f, 2},
 		{0x0561, 0x0586, 1},
 		{0x13f8, 0x13fd, 1},
+		{0x1c80, 0x1c88, 1},
 		{0x1d79, 0x1d7d, 4},
 		{0x1e01, 0x1e95, 2},
 		{0x1e9b, 0x1ea1, 6},
@@ -7175,8 +7583,10 @@ var foldLu = &RangeTable{
 	},
 	R32: []Range32{
 		{0x10428, 0x1044f, 1},
+		{0x104d8, 0x104fb, 1},
 		{0x10cc0, 0x10cf2, 1},
 		{0x118c0, 0x118df, 1},
+		{0x1e922, 0x1e943, 1},
 	},
 	LatinOffset: 4,
 }
@@ -7201,7 +7611,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: 3546 16-bit, 1306 32-bit, 4852 total.
-// Range bytes: 21276 16-bit, 15672 32-bit, 36948 total.
+// Range entries: 3576 16-bit, 1454 32-bit, 5030 total.
+// Range bytes: 21456 16-bit, 17448 32-bit, 38904 total.
 
-// Fold orbit bytes: 63 pairs, 252 bytes
+// Fold orbit bytes: 88 pairs, 352 bytes
diff --git a/src/unicode/utf16/export_test.go b/src/unicode/utf16/export_test.go
index 306247e..e0c57f5 100644
--- a/src/unicode/utf16/export_test.go
+++ b/src/unicode/utf16/export_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/src/unicode/utf16/utf16.go b/src/unicode/utf16/utf16.go
index b497500..1a881aa 100644
--- a/src/unicode/utf16/utf16.go
+++ b/src/unicode/utf16/utf16.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -36,7 +36,7 @@ func IsSurrogate(r rune) bool {
 // the Unicode replacement code point U+FFFD.
 func DecodeRune(r1, r2 rune) rune {
 	if surr1 <= r1 && r1 < surr2 && surr2 <= r2 && r2 < surr3 {
-		return (r1-surr1)<<10 | (r2 - surr2) + 0x10000
+		return (r1-surr1)<<10 | (r2 - surr2) + surrSelf
 	}
 	return replacementChar
 }
@@ -45,7 +45,7 @@ func DecodeRune(r1, r2 rune) rune {
 // If the rune is not a valid Unicode code point or does not need encoding,
 // EncodeRune returns U+FFFD, U+FFFD.
 func EncodeRune(r rune) (r1, r2 rune) {
-	if r < surrSelf || r > maxRune || IsSurrogate(r) {
+	if r < surrSelf || r > maxRune {
 		return replacementChar, replacementChar
 	}
 	r -= surrSelf
@@ -65,20 +65,22 @@ func Encode(s []rune) []uint16 {
 	n = 0
 	for _, v := range s {
 		switch {
-		case v < 0, surr1 <= v && v < surr3, v > maxRune:
-			v = replacementChar
-			fallthrough
-		case v < surrSelf:
+		case 0 <= v && v < surr1, surr3 <= v && v < surrSelf:
+			// normal rune
 			a[n] = uint16(v)
 			n++
-		default:
+		case surrSelf <= v && v <= maxRune:
+			// needs surrogate sequence
 			r1, r2 := EncodeRune(v)
 			a[n] = uint16(r1)
 			a[n+1] = uint16(r2)
 			n += 2
+		default:
+			a[n] = uint16(replacementChar)
+			n++
 		}
 	}
-	return a[0:n]
+	return a[:n]
 }
 
 // Decode returns the Unicode code point sequence represented
@@ -88,21 +90,19 @@ func Decode(s []uint16) []rune {
 	n := 0
 	for i := 0; i < len(s); i++ {
 		switch r := s[i]; {
+		case r < surr1, surr3 <= r:
+			// normal rune
+			a[n] = rune(r)
 		case surr1 <= r && r < surr2 && i+1 < len(s) &&
 			surr2 <= s[i+1] && s[i+1] < surr3:
 			// valid surrogate sequence
 			a[n] = DecodeRune(rune(r), rune(s[i+1]))
 			i++
-			n++
-		case surr1 <= r && r < surr3:
+		default:
 			// invalid surrogate sequence
 			a[n] = replacementChar
-			n++
-		default:
-			// normal rune
-			a[n] = rune(r)
-			n++
 		}
+		n++
 	}
-	return a[0:n]
+	return a[:n]
 }
diff --git a/src/unicode/utf16/utf16_test.go b/src/unicode/utf16/utf16_test.go
index 3dca472..d258f0b 100644
--- a/src/unicode/utf16/utf16_test.go
+++ b/src/unicode/utf16/utf16_test.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
@@ -147,3 +147,56 @@ func TestIsSurrogate(t *testing.T) {
 		}
 	}
 }
+
+func BenchmarkDecodeValidASCII(b *testing.B) {
+	// "hello world"
+	data := []uint16{104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100}
+	for i := 0; i < b.N; i++ {
+		Decode(data)
+	}
+}
+
+func BenchmarkDecodeValidJapaneseChars(b *testing.B) {
+	// "日本語日本語日本語"
+	data := []uint16{26085, 26412, 35486, 26085, 26412, 35486, 26085, 26412, 35486}
+	for i := 0; i < b.N; i++ {
+		Decode(data)
+	}
+}
+
+func BenchmarkDecodeRune(b *testing.B) {
+	rs := make([]rune, 10)
+	// U+1D4D0 to U+1D4D4: MATHEMATICAL BOLD SCRIPT CAPITAL LETTERS
+	for i, u := range []rune{'𝓐', '𝓑', '𝓒', '𝓓', '𝓔'} {
+		rs[2*i], rs[2*i+1] = EncodeRune(u)
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		for j := 0; j < 5; j++ {
+			DecodeRune(rs[2*j], rs[2*j+1])
+		}
+	}
+}
+
+func BenchmarkEncodeValidASCII(b *testing.B) {
+	data := []rune{'h', 'e', 'l', 'l', 'o'}
+	for i := 0; i < b.N; i++ {
+		Encode(data)
+	}
+}
+
+func BenchmarkEncodeValidJapaneseChars(b *testing.B) {
+	data := []rune{'日', '本', '語'}
+	for i := 0; i < b.N; i++ {
+		Encode(data)
+	}
+}
+
+func BenchmarkEncodeRune(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		for _, u := range []rune{'𝓐', '𝓑', '𝓒', '𝓓', '𝓔'} {
+			EncodeRune(u)
+		}
+	}
+}
diff --git a/src/unicode/utf8/utf8.go b/src/unicode/utf8/utf8.go
index bbaf14a..9d35be6 100644
--- a/src/unicode/utf8/utf8.go
+++ b/src/unicode/utf8/utf8.go
@@ -341,7 +341,7 @@ func RuneLen(r rune) int {
 // EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune.
 // It returns the number of bytes written.
 func EncodeRune(p []byte, r rune) int {
-	// Negative values are erroneous.  Making it unsigned addresses the problem.
+	// Negative values are erroneous. Making it unsigned addresses the problem.
 	switch i := uint32(r); {
 	case i <= rune1Max:
 		p[0] = byte(r)
@@ -367,7 +367,7 @@ func EncodeRune(p []byte, r rune) int {
 	}
 }
 
-// RuneCount returns the number of runes in p.  Erroneous and short
+// RuneCount returns the number of runes in p. Erroneous and short
 // encodings are treated as single runes of width 1 byte.
 func RuneCount(p []byte) int {
 	np := len(p)
@@ -441,7 +441,7 @@ func RuneCountInString(s string) (n int) {
 }
 
 // RuneStart reports whether the byte could be the first byte of an encoded,
-// possibly invalid rune.  Second and subsequent bytes always have the top two
+// possibly invalid rune. Second and subsequent bytes always have the top two
 // bits set to 10.
 func RuneStart(b byte) bool { return b&0xC0 != 0x80 }
 
diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go
index 532fa4a..8f43e72 100644
--- a/src/unsafe/unsafe.go
+++ b/src/unsafe/unsafe.go
@@ -11,10 +11,10 @@
 package unsafe
 
 // ArbitraryType is here for the purposes of documentation only and is not actually
-// part of the unsafe package.  It represents the type of an arbitrary Go expression.
+// part of the unsafe package. It represents the type of an arbitrary Go expression.
 type ArbitraryType int
 
-// Pointer represents a pointer to an arbitrary type.  There are four special operations
+// Pointer represents a pointer to an arbitrary type. There are four special operations
 // available for type Pointer that are not available for other types:
 //	- A pointer value of any type can be converted to a Pointer.
 //	- A Pointer can be converted to a pointer value of any type.
@@ -179,7 +179,7 @@ type Pointer *ArbitraryType
 func Sizeof(x ArbitraryType) uintptr
 
 // 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
+// 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(x ArbitraryType) uintptr
 
@@ -189,6 +189,6 @@ func Offsetof(x ArbitraryType) uintptr
 // It is the same as the value returned by reflect.TypeOf(x).Align().
 // As a special case, if a variable s is of struct type and f is a field
 // within that struct, then Alignof(s.f) will return the required alignment
-// of a field of that type within a struct.  This case is the same as the
+// of a field of that type within a struct. This case is the same as the
 // value returned by reflect.TypeOf(s.f).FieldAlign().
 func Alignof(x ArbitraryType) uintptr
diff --git a/src/vendor/README b/src/vendor/README
deleted file mode 100644
index e540318..0000000
--- a/src/vendor/README
+++ /dev/null
@@ -1,8 +0,0 @@
-This file needs to exist because the vendor directory needs
-to exist for some go/build tests to pass, and git can't track
-empty directories.
-
-In Go 1.7 we'll use this directory again. (In Go 1.6 we tried but
-reverted).
-
-See http://golang.org/issue/14047 for details.
diff --git a/src/vendor/golang.org/x/net/http2/hpack/encode.go b/src/vendor/golang.org/x/net/http2/hpack/encode.go
new file mode 100644
index 0000000..f9bb033
--- /dev/null
+++ b/src/vendor/golang.org/x/net/http2/hpack/encode.go
@@ -0,0 +1,251 @@
+// 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 hpack
+
+import (
+	"io"
+)
+
+const (
+	uint32Max              = ^uint32(0)
+	initialHeaderTableSize = 4096
+)
+
+type Encoder struct {
+	dynTab dynamicTable
+	// minSize is the minimum table size set by
+	// SetMaxDynamicTableSize after the previous Header Table Size
+	// Update.
+	minSize uint32
+	// maxSizeLimit is the maximum table size this encoder
+	// supports. This will protect the encoder from too large
+	// size.
+	maxSizeLimit uint32
+	// tableSizeUpdate indicates whether "Header Table Size
+	// Update" is required.
+	tableSizeUpdate bool
+	w               io.Writer
+	buf             []byte
+}
+
+// NewEncoder returns a new Encoder which performs HPACK encoding. An
+// encoded data is written to w.
+func NewEncoder(w io.Writer) *Encoder {
+	e := &Encoder{
+		minSize:         uint32Max,
+		maxSizeLimit:    initialHeaderTableSize,
+		tableSizeUpdate: false,
+		w:               w,
+	}
+	e.dynTab.setMaxSize(initialHeaderTableSize)
+	return e
+}
+
+// WriteField encodes f into a single Write to e's underlying Writer.
+// This function may also produce bytes for "Header Table Size Update"
+// if necessary.  If produced, it is done before encoding f.
+func (e *Encoder) WriteField(f HeaderField) error {
+	e.buf = e.buf[:0]
+
+	if e.tableSizeUpdate {
+		e.tableSizeUpdate = false
+		if e.minSize < e.dynTab.maxSize {
+			e.buf = appendTableSize(e.buf, e.minSize)
+		}
+		e.minSize = uint32Max
+		e.buf = appendTableSize(e.buf, e.dynTab.maxSize)
+	}
+
+	idx, nameValueMatch := e.searchTable(f)
+	if nameValueMatch {
+		e.buf = appendIndexed(e.buf, idx)
+	} else {
+		indexing := e.shouldIndex(f)
+		if indexing {
+			e.dynTab.add(f)
+		}
+
+		if idx == 0 {
+			e.buf = appendNewName(e.buf, f, indexing)
+		} else {
+			e.buf = appendIndexedName(e.buf, f, idx, indexing)
+		}
+	}
+	n, err := e.w.Write(e.buf)
+	if err == nil && n != len(e.buf) {
+		err = io.ErrShortWrite
+	}
+	return err
+}
+
+// searchTable searches f in both stable and dynamic header tables.
+// The static header table is searched first. Only when there is no
+// exact match for both name and value, the dynamic header table is
+// then searched. If there is no match, i is 0. If both name and value
+// match, i is the matched index and nameValueMatch becomes true. If
+// only name matches, i points to that index and nameValueMatch
+// becomes false.
+func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) {
+	for idx, hf := range staticTable {
+		if !constantTimeStringCompare(hf.Name, f.Name) {
+			continue
+		}
+		if i == 0 {
+			i = uint64(idx + 1)
+		}
+		if f.Sensitive {
+			continue
+		}
+		if !constantTimeStringCompare(hf.Value, f.Value) {
+			continue
+		}
+		i = uint64(idx + 1)
+		nameValueMatch = true
+		return
+	}
+
+	j, nameValueMatch := e.dynTab.search(f)
+	if nameValueMatch || (i == 0 && j != 0) {
+		i = j + uint64(len(staticTable))
+	}
+	return
+}
+
+// SetMaxDynamicTableSize changes the dynamic header table size to v.
+// The actual size is bounded by the value passed to
+// SetMaxDynamicTableSizeLimit.
+func (e *Encoder) SetMaxDynamicTableSize(v uint32) {
+	if v > e.maxSizeLimit {
+		v = e.maxSizeLimit
+	}
+	if v < e.minSize {
+		e.minSize = v
+	}
+	e.tableSizeUpdate = true
+	e.dynTab.setMaxSize(v)
+}
+
+// SetMaxDynamicTableSizeLimit changes the maximum value that can be
+// specified in SetMaxDynamicTableSize to v. By default, it is set to
+// 4096, which is the same size of the default dynamic header table
+// size described in HPACK specification. If the current maximum
+// dynamic header table size is strictly greater than v, "Header Table
+// Size Update" will be done in the next WriteField call and the
+// maximum dynamic header table size is truncated to v.
+func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
+	e.maxSizeLimit = v
+	if e.dynTab.maxSize > v {
+		e.tableSizeUpdate = true
+		e.dynTab.setMaxSize(v)
+	}
+}
+
+// shouldIndex reports whether f should be indexed.
+func (e *Encoder) shouldIndex(f HeaderField) bool {
+	return !f.Sensitive && f.Size() <= e.dynTab.maxSize
+}
+
+// appendIndexed appends index i, as encoded in "Indexed Header Field"
+// representation, to dst and returns the extended buffer.
+func appendIndexed(dst []byte, i uint64) []byte {
+	first := len(dst)
+	dst = appendVarInt(dst, 7, i)
+	dst[first] |= 0x80
+	return dst
+}
+
+// appendNewName appends f, as encoded in one of "Literal Header field
+// - New Name" representation variants, to dst and returns the
+// extended buffer.
+//
+// If f.Sensitive is true, "Never Indexed" representation is used. If
+// f.Sensitive is false and indexing is true, "Inremental Indexing"
+// representation is used.
+func appendNewName(dst []byte, f HeaderField, indexing bool) []byte {
+	dst = append(dst, encodeTypeByte(indexing, f.Sensitive))
+	dst = appendHpackString(dst, f.Name)
+	return appendHpackString(dst, f.Value)
+}
+
+// appendIndexedName appends f and index i referring indexed name
+// entry, as encoded in one of "Literal Header field - Indexed Name"
+// representation variants, to dst and returns the extended buffer.
+//
+// If f.Sensitive is true, "Never Indexed" representation is used. If
+// f.Sensitive is false and indexing is true, "Incremental Indexing"
+// representation is used.
+func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byte {
+	first := len(dst)
+	var n byte
+	if indexing {
+		n = 6
+	} else {
+		n = 4
+	}
+	dst = appendVarInt(dst, n, i)
+	dst[first] |= encodeTypeByte(indexing, f.Sensitive)
+	return appendHpackString(dst, f.Value)
+}
+
+// appendTableSize appends v, as encoded in "Header Table Size Update"
+// representation, to dst and returns the extended buffer.
+func appendTableSize(dst []byte, v uint32) []byte {
+	first := len(dst)
+	dst = appendVarInt(dst, 5, uint64(v))
+	dst[first] |= 0x20
+	return dst
+}
+
+// appendVarInt appends i, as encoded in variable integer form using n
+// bit prefix, to dst and returns the extended buffer.
+//
+// See
+// http://http2.github.io/http2-spec/compression.html#integer.representation
+func appendVarInt(dst []byte, n byte, i uint64) []byte {
+	k := uint64((1 << n) - 1)
+	if i < k {
+		return append(dst, byte(i))
+	}
+	dst = append(dst, byte(k))
+	i -= k
+	for ; i >= 128; i >>= 7 {
+		dst = append(dst, byte(0x80|(i&0x7f)))
+	}
+	return append(dst, byte(i))
+}
+
+// appendHpackString appends s, as encoded in "String Literal"
+// representation, to dst and returns the the extended buffer.
+//
+// s will be encoded in Huffman codes only when it produces strictly
+// shorter byte string.
+func appendHpackString(dst []byte, s string) []byte {
+	huffmanLength := HuffmanEncodeLength(s)
+	if huffmanLength < uint64(len(s)) {
+		first := len(dst)
+		dst = appendVarInt(dst, 7, huffmanLength)
+		dst = AppendHuffmanString(dst, s)
+		dst[first] |= 0x80
+	} else {
+		dst = appendVarInt(dst, 7, uint64(len(s)))
+		dst = append(dst, s...)
+	}
+	return dst
+}
+
+// encodeTypeByte returns type byte. If sensitive is true, type byte
+// for "Never Indexed" representation is returned. If sensitive is
+// false and indexing is true, type byte for "Incremental Indexing"
+// representation is returned. Otherwise, type byte for "Without
+// Indexing" is returned.
+func encodeTypeByte(indexing, sensitive bool) byte {
+	if sensitive {
+		return 0x10
+	}
+	if indexing {
+		return 0x40
+	}
+	return 0
+}
diff --git a/src/internal/golang.org/x/net/http2/hpack/encode_test.go b/src/vendor/golang.org/x/net/http2/hpack/encode_test.go
similarity index 100%
rename from src/internal/golang.org/x/net/http2/hpack/encode_test.go
rename to src/vendor/golang.org/x/net/http2/hpack/encode_test.go
diff --git a/src/vendor/golang.org/x/net/http2/hpack/hpack.go b/src/vendor/golang.org/x/net/http2/hpack/hpack.go
new file mode 100644
index 0000000..8aa197a
--- /dev/null
+++ b/src/vendor/golang.org/x/net/http2/hpack/hpack.go
@@ -0,0 +1,542 @@
+// 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 hpack implements HPACK, a compression format for
+// efficiently representing HTTP header fields in the context of HTTP/2.
+//
+// See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09
+package hpack
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+)
+
+// A DecodingError is something the spec defines as a decoding error.
+type DecodingError struct {
+	Err error
+}
+
+func (de DecodingError) Error() string {
+	return fmt.Sprintf("decoding error: %v", de.Err)
+}
+
+// An InvalidIndexError is returned when an encoder references a table
+// entry before the static table or after the end of the dynamic table.
+type InvalidIndexError int
+
+func (e InvalidIndexError) Error() string {
+	return fmt.Sprintf("invalid indexed representation index %d", int(e))
+}
+
+// A HeaderField is a name-value pair. Both the name and value are
+// treated as opaque sequences of octets.
+type HeaderField struct {
+	Name, Value string
+
+	// Sensitive means that this header field should never be
+	// indexed.
+	Sensitive bool
+}
+
+// IsPseudo reports whether the header field is an http2 pseudo header.
+// That is, it reports whether it starts with a colon.
+// It is not otherwise guaranteed to be a valid pseudo header field,
+// though.
+func (hf HeaderField) IsPseudo() bool {
+	return len(hf.Name) != 0 && hf.Name[0] == ':'
+}
+
+func (hf HeaderField) String() string {
+	var suffix string
+	if hf.Sensitive {
+		suffix = " (sensitive)"
+	}
+	return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
+}
+
+// Size returns the size of an entry per RFC 7540 section 5.2.
+func (hf HeaderField) Size() uint32 {
+	// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
+	// "The size of the dynamic table is the sum of the size of
+	// its entries.  The size of an entry is the sum of its name's
+	// length in octets (as defined in Section 5.2), its value's
+	// length in octets (see Section 5.2), plus 32.  The size of
+	// an entry is calculated using the length of the name and
+	// value without any Huffman encoding applied."
+
+	// This can overflow if somebody makes a large HeaderField
+	// Name and/or Value by hand, but we don't care, because that
+	// won't happen on the wire because the encoding doesn't allow
+	// it.
+	return uint32(len(hf.Name) + len(hf.Value) + 32)
+}
+
+// A Decoder is the decoding context for incremental processing of
+// header blocks.
+type Decoder struct {
+	dynTab dynamicTable
+	emit   func(f HeaderField)
+
+	emitEnabled bool // whether calls to emit are enabled
+	maxStrLen   int  // 0 means unlimited
+
+	// buf is the unparsed buffer. It's only written to
+	// saveBuf if it was truncated in the middle of a header
+	// block. Because it's usually not owned, we can only
+	// process it under Write.
+	buf []byte // not owned; only valid during Write
+
+	// saveBuf is previous data passed to Write which we weren't able
+	// to fully parse before. Unlike buf, we own this data.
+	saveBuf bytes.Buffer
+}
+
+// NewDecoder returns a new decoder with the provided maximum dynamic
+// table size. The emitFunc will be called for each valid field
+// parsed, in the same goroutine as calls to Write, before Write returns.
+func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder {
+	d := &Decoder{
+		emit:        emitFunc,
+		emitEnabled: true,
+	}
+	d.dynTab.allowedMaxSize = maxDynamicTableSize
+	d.dynTab.setMaxSize(maxDynamicTableSize)
+	return d
+}
+
+// ErrStringLength is returned by Decoder.Write when the max string length
+// (as configured by Decoder.SetMaxStringLength) would be violated.
+var ErrStringLength = errors.New("hpack: string too long")
+
+// SetMaxStringLength sets the maximum size of a HeaderField name or
+// value string. If a string exceeds this length (even after any
+// decompression), Write will return ErrStringLength.
+// A value of 0 means unlimited and is the default from NewDecoder.
+func (d *Decoder) SetMaxStringLength(n int) {
+	d.maxStrLen = n
+}
+
+// SetEmitFunc changes the callback used when new header fields
+// are decoded.
+// It must be non-nil. It does not affect EmitEnabled.
+func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField)) {
+	d.emit = emitFunc
+}
+
+// SetEmitEnabled controls whether the emitFunc provided to NewDecoder
+// should be called. The default is true.
+//
+// This facility exists to let servers enforce MAX_HEADER_LIST_SIZE
+// while still decoding and keeping in-sync with decoder state, but
+// without doing unnecessary decompression or generating unnecessary
+// garbage for header fields past the limit.
+func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v }
+
+// EmitEnabled reports whether calls to the emitFunc provided to NewDecoder
+// are currently enabled. The default is true.
+func (d *Decoder) EmitEnabled() bool { return d.emitEnabled }
+
+// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their
+// underlying buffers for garbage reasons.
+
+func (d *Decoder) SetMaxDynamicTableSize(v uint32) {
+	d.dynTab.setMaxSize(v)
+}
+
+// SetAllowedMaxDynamicTableSize sets the upper bound that the encoded
+// stream (via dynamic table size updates) may set the maximum size
+// to.
+func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
+	d.dynTab.allowedMaxSize = v
+}
+
+type dynamicTable struct {
+	// ents is the FIFO described at
+	// http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2
+	// The newest (low index) is append at the end, and items are
+	// evicted from the front.
+	ents           []HeaderField
+	size           uint32
+	maxSize        uint32 // current maxSize
+	allowedMaxSize uint32 // maxSize may go up to this, inclusive
+}
+
+func (dt *dynamicTable) setMaxSize(v uint32) {
+	dt.maxSize = v
+	dt.evict()
+}
+
+// TODO: change dynamicTable to be a struct with a slice and a size int field,
+// per http://http2.github.io/http2-spec/compression.html#rfc.section.4.1:
+//
+//
+// Then make add increment the size. maybe the max size should move from Decoder to
+// dynamicTable and add should return an ok bool if there was enough space.
+//
+// Later we'll need a remove operation on dynamicTable.
+
+func (dt *dynamicTable) add(f HeaderField) {
+	dt.ents = append(dt.ents, f)
+	dt.size += f.Size()
+	dt.evict()
+}
+
+// If we're too big, evict old stuff (front of the slice)
+func (dt *dynamicTable) evict() {
+	base := dt.ents // keep base pointer of slice
+	for dt.size > dt.maxSize {
+		dt.size -= dt.ents[0].Size()
+		dt.ents = dt.ents[1:]
+	}
+
+	// Shift slice contents down if we evicted things.
+	if len(dt.ents) != len(base) {
+		copy(base, dt.ents)
+		dt.ents = base[:len(dt.ents)]
+	}
+}
+
+// constantTimeStringCompare compares string a and b in a constant
+// time manner.
+func constantTimeStringCompare(a, b string) bool {
+	if len(a) != len(b) {
+		return false
+	}
+
+	c := byte(0)
+
+	for i := 0; i < len(a); i++ {
+		c |= a[i] ^ b[i]
+	}
+
+	return c == 0
+}
+
+// Search searches f in the table. The return value i is 0 if there is
+// no name match. If there is name match or name/value match, i is the
+// index of that entry (1-based). If both name and value match,
+// nameValueMatch becomes true.
+func (dt *dynamicTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
+	l := len(dt.ents)
+	for j := l - 1; j >= 0; j-- {
+		ent := dt.ents[j]
+		if !constantTimeStringCompare(ent.Name, f.Name) {
+			continue
+		}
+		if i == 0 {
+			i = uint64(l - j)
+		}
+		if f.Sensitive {
+			continue
+		}
+		if !constantTimeStringCompare(ent.Value, f.Value) {
+			continue
+		}
+		i = uint64(l - j)
+		nameValueMatch = true
+		return
+	}
+	return
+}
+
+func (d *Decoder) maxTableIndex() int {
+	return len(d.dynTab.ents) + len(staticTable)
+}
+
+func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
+	if i < 1 {
+		return
+	}
+	if i > uint64(d.maxTableIndex()) {
+		return
+	}
+	if i <= uint64(len(staticTable)) {
+		return staticTable[i-1], true
+	}
+	dents := d.dynTab.ents
+	return dents[len(dents)-(int(i)-len(staticTable))], true
+}
+
+// Decode decodes an entire block.
+//
+// TODO: remove this method and make it incremental later? This is
+// easier for debugging now.
+func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
+	var hf []HeaderField
+	saveFunc := d.emit
+	defer func() { d.emit = saveFunc }()
+	d.emit = func(f HeaderField) { hf = append(hf, f) }
+	if _, err := d.Write(p); err != nil {
+		return nil, err
+	}
+	if err := d.Close(); err != nil {
+		return nil, err
+	}
+	return hf, nil
+}
+
+func (d *Decoder) Close() error {
+	if d.saveBuf.Len() > 0 {
+		d.saveBuf.Reset()
+		return DecodingError{errors.New("truncated headers")}
+	}
+	return nil
+}
+
+func (d *Decoder) Write(p []byte) (n int, err error) {
+	if len(p) == 0 {
+		// Prevent state machine CPU attacks (making us redo
+		// work up to the point of finding out we don't have
+		// enough data)
+		return
+	}
+	// Only copy the data if we have to. Optimistically assume
+	// that p will contain a complete header block.
+	if d.saveBuf.Len() == 0 {
+		d.buf = p
+	} else {
+		d.saveBuf.Write(p)
+		d.buf = d.saveBuf.Bytes()
+		d.saveBuf.Reset()
+	}
+
+	for len(d.buf) > 0 {
+		err = d.parseHeaderFieldRepr()
+		if err == errNeedMore {
+			// Extra paranoia, making sure saveBuf won't
+			// get too large.  All the varint and string
+			// reading code earlier should already catch
+			// overlong things and return ErrStringLength,
+			// but keep this as a last resort.
+			const varIntOverhead = 8 // conservative
+			if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
+				return 0, ErrStringLength
+			}
+			d.saveBuf.Write(d.buf)
+			return len(p), nil
+		}
+		if err != nil {
+			break
+		}
+	}
+	return len(p), err
+}
+
+// errNeedMore is an internal sentinel error value that means the
+// buffer is truncated and we need to read more data before we can
+// continue parsing.
+var errNeedMore = errors.New("need more data")
+
+type indexType int
+
+const (
+	indexedTrue indexType = iota
+	indexedFalse
+	indexedNever
+)
+
+func (v indexType) indexed() bool   { return v == indexedTrue }
+func (v indexType) sensitive() bool { return v == indexedNever }
+
+// returns errNeedMore if there isn't enough data available.
+// any other error is fatal.
+// consumes d.buf iff it returns nil.
+// precondition: must be called with len(d.buf) > 0
+func (d *Decoder) parseHeaderFieldRepr() error {
+	b := d.buf[0]
+	switch {
+	case b&128 != 0:
+		// Indexed representation.
+		// High bit set?
+		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.1
+		return d.parseFieldIndexed()
+	case b&192 == 64:
+		// 6.2.1 Literal Header Field with Incremental Indexing
+		// 0b10xxxxxx: top two bits are 10
+		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.1
+		return d.parseFieldLiteral(6, indexedTrue)
+	case b&240 == 0:
+		// 6.2.2 Literal Header Field without Indexing
+		// 0b0000xxxx: top four bits are 0000
+		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.2
+		return d.parseFieldLiteral(4, indexedFalse)
+	case b&240 == 16:
+		// 6.2.3 Literal Header Field never Indexed
+		// 0b0001xxxx: top four bits are 0001
+		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.2.3
+		return d.parseFieldLiteral(4, indexedNever)
+	case b&224 == 32:
+		// 6.3 Dynamic Table Size Update
+		// Top three bits are '001'.
+		// http://http2.github.io/http2-spec/compression.html#rfc.section.6.3
+		return d.parseDynamicTableSizeUpdate()
+	}
+
+	return DecodingError{errors.New("invalid encoding")}
+}
+
+// (same invariants and behavior as parseHeaderFieldRepr)
+func (d *Decoder) parseFieldIndexed() error {
+	buf := d.buf
+	idx, buf, err := readVarInt(7, buf)
+	if err != nil {
+		return err
+	}
+	hf, ok := d.at(idx)
+	if !ok {
+		return DecodingError{InvalidIndexError(idx)}
+	}
+	d.buf = buf
+	return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value})
+}
+
+// (same invariants and behavior as parseHeaderFieldRepr)
+func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
+	buf := d.buf
+	nameIdx, buf, err := readVarInt(n, buf)
+	if err != nil {
+		return err
+	}
+
+	var hf HeaderField
+	wantStr := d.emitEnabled || it.indexed()
+	if nameIdx > 0 {
+		ihf, ok := d.at(nameIdx)
+		if !ok {
+			return DecodingError{InvalidIndexError(nameIdx)}
+		}
+		hf.Name = ihf.Name
+	} else {
+		hf.Name, buf, err = d.readString(buf, wantStr)
+		if err != nil {
+			return err
+		}
+	}
+	hf.Value, buf, err = d.readString(buf, wantStr)
+	if err != nil {
+		return err
+	}
+	d.buf = buf
+	if it.indexed() {
+		d.dynTab.add(hf)
+	}
+	hf.Sensitive = it.sensitive()
+	return d.callEmit(hf)
+}
+
+func (d *Decoder) callEmit(hf HeaderField) error {
+	if d.maxStrLen != 0 {
+		if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen {
+			return ErrStringLength
+		}
+	}
+	if d.emitEnabled {
+		d.emit(hf)
+	}
+	return nil
+}
+
+// (same invariants and behavior as parseHeaderFieldRepr)
+func (d *Decoder) parseDynamicTableSizeUpdate() error {
+	buf := d.buf
+	size, buf, err := readVarInt(5, buf)
+	if err != nil {
+		return err
+	}
+	if size > uint64(d.dynTab.allowedMaxSize) {
+		return DecodingError{errors.New("dynamic table size update too large")}
+	}
+	d.dynTab.setMaxSize(uint32(size))
+	d.buf = buf
+	return nil
+}
+
+var errVarintOverflow = DecodingError{errors.New("varint integer overflow")}
+
+// readVarInt reads an unsigned variable length integer off the
+// beginning of p. n is the parameter as described in
+// http://http2.github.io/http2-spec/compression.html#rfc.section.5.1.
+//
+// n must always be between 1 and 8.
+//
+// The returned remain buffer is either a smaller suffix of p, or err != nil.
+// The error is errNeedMore if p doesn't contain a complete integer.
+func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
+	if n < 1 || n > 8 {
+		panic("bad n")
+	}
+	if len(p) == 0 {
+		return 0, p, errNeedMore
+	}
+	i = uint64(p[0])
+	if n < 8 {
+		i &= (1 << uint64(n)) - 1
+	}
+	if i < (1<<uint64(n))-1 {
+		return i, p[1:], nil
+	}
+
+	origP := p
+	p = p[1:]
+	var m uint64
+	for len(p) > 0 {
+		b := p[0]
+		p = p[1:]
+		i += uint64(b&127) << m
+		if b&128 == 0 {
+			return i, p, nil
+		}
+		m += 7
+		if m >= 63 { // TODO: proper overflow check. making this up.
+			return 0, origP, errVarintOverflow
+		}
+	}
+	return 0, origP, errNeedMore
+}
+
+// readString decodes an hpack string from p.
+//
+// wantStr is whether s will be used. If false, decompression and
+// []byte->string garbage are skipped if s will be ignored
+// anyway. This does mean that huffman decoding errors for non-indexed
+// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
+// is returning an error anyway, and because they're not indexed, the error
+// won't affect the decoding state.
+func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
+	if len(p) == 0 {
+		return "", p, errNeedMore
+	}
+	isHuff := p[0]&128 != 0
+	strLen, p, err := readVarInt(7, p)
+	if err != nil {
+		return "", p, err
+	}
+	if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
+		return "", nil, ErrStringLength
+	}
+	if uint64(len(p)) < strLen {
+		return "", p, errNeedMore
+	}
+	if !isHuff {
+		if wantStr {
+			s = string(p[:strLen])
+		}
+		return s, p[strLen:], nil
+	}
+
+	if wantStr {
+		buf := bufPool.Get().(*bytes.Buffer)
+		buf.Reset() // don't trust others
+		defer bufPool.Put(buf)
+		if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
+			buf.Reset()
+			return "", nil, err
+		}
+		s = buf.String()
+		buf.Reset() // be nice to GC
+	}
+	return s, p[strLen:], nil
+}
diff --git a/src/vendor/golang.org/x/net/http2/hpack/hpack_test.go b/src/vendor/golang.org/x/net/http2/hpack/hpack_test.go
new file mode 100644
index 0000000..4c7b17b
--- /dev/null
+++ b/src/vendor/golang.org/x/net/http2/hpack/hpack_test.go
@@ -0,0 +1,854 @@
+// 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 hpack
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/hex"
+	"fmt"
+	"math/rand"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+)
+
+func TestStaticTable(t *testing.T) {
+	fromSpec := `
+          +-------+-----------------------------+---------------+
+          | 1     | :authority                  |               |
+          | 2     | :method                     | GET           |
+          | 3     | :method                     | POST          |
+          | 4     | :path                       | /             |
+          | 5     | :path                       | /index.html   |
+          | 6     | :scheme                     | http          |
+          | 7     | :scheme                     | https         |
+          | 8     | :status                     | 200           |
+          | 9     | :status                     | 204           |
+          | 10    | :status                     | 206           |
+          | 11    | :status                     | 304           |
+          | 12    | :status                     | 400           |
+          | 13    | :status                     | 404           |
+          | 14    | :status                     | 500           |
+          | 15    | accept-charset              |               |
+          | 16    | accept-encoding             | gzip, deflate |
+          | 17    | accept-language             |               |
+          | 18    | accept-ranges               |               |
+          | 19    | accept                      |               |
+          | 20    | access-control-allow-origin |               |
+          | 21    | age                         |               |
+          | 22    | allow                       |               |
+          | 23    | authorization               |               |
+          | 24    | cache-control               |               |
+          | 25    | content-disposition         |               |
+          | 26    | content-encoding            |               |
+          | 27    | content-language            |               |
+          | 28    | content-length              |               |
+          | 29    | content-location            |               |
+          | 30    | content-range               |               |
+          | 31    | content-type                |               |
+          | 32    | cookie                      |               |
+          | 33    | date                        |               |
+          | 34    | etag                        |               |
+          | 35    | expect                      |               |
+          | 36    | expires                     |               |
+          | 37    | from                        |               |
+          | 38    | host                        |               |
+          | 39    | if-match                    |               |
+          | 40    | if-modified-since           |               |
+          | 41    | if-none-match               |               |
+          | 42    | if-range                    |               |
+          | 43    | if-unmodified-since         |               |
+          | 44    | last-modified               |               |
+          | 45    | link                        |               |
+          | 46    | location                    |               |
+          | 47    | max-forwards                |               |
+          | 48    | proxy-authenticate          |               |
+          | 49    | proxy-authorization         |               |
+          | 50    | range                       |               |
+          | 51    | referer                     |               |
+          | 52    | refresh                     |               |
+          | 53    | retry-after                 |               |
+          | 54    | server                      |               |
+          | 55    | set-cookie                  |               |
+          | 56    | strict-transport-security   |               |
+          | 57    | transfer-encoding           |               |
+          | 58    | user-agent                  |               |
+          | 59    | vary                        |               |
+          | 60    | via                         |               |
+          | 61    | www-authenticate            |               |
+          +-------+-----------------------------+---------------+
+`
+	bs := bufio.NewScanner(strings.NewReader(fromSpec))
+	re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
+	for bs.Scan() {
+		l := bs.Text()
+		if !strings.Contains(l, "|") {
+			continue
+		}
+		m := re.FindStringSubmatch(l)
+		if m == nil {
+			continue
+		}
+		i, err := strconv.Atoi(m[1])
+		if err != nil {
+			t.Errorf("Bogus integer on line %q", l)
+			continue
+		}
+		if i < 1 || i > len(staticTable) {
+			t.Errorf("Bogus index %d on line %q", i, l)
+			continue
+		}
+		if got, want := staticTable[i-1].Name, m[2]; got != want {
+			t.Errorf("header index %d name = %q; want %q", i, got, want)
+		}
+		if got, want := staticTable[i-1].Value, m[3]; got != want {
+			t.Errorf("header index %d value = %q; want %q", i, got, want)
+		}
+	}
+	if err := bs.Err(); err != nil {
+		t.Error(err)
+	}
+}
+
+func (d *Decoder) mustAt(idx int) HeaderField {
+	if hf, ok := d.at(uint64(idx)); !ok {
+		panic(fmt.Sprintf("bogus index %d", idx))
+	} else {
+		return hf
+	}
+}
+
+func TestDynamicTableAt(t *testing.T) {
+	d := NewDecoder(4096, nil)
+	at := d.mustAt
+	if got, want := at(2), (pair(":method", "GET")); got != want {
+		t.Errorf("at(2) = %v; want %v", got, want)
+	}
+	d.dynTab.add(pair("foo", "bar"))
+	d.dynTab.add(pair("blake", "miz"))
+	if got, want := at(len(staticTable)+1), (pair("blake", "miz")); got != want {
+		t.Errorf("at(dyn 1) = %v; want %v", got, want)
+	}
+	if got, want := at(len(staticTable)+2), (pair("foo", "bar")); got != want {
+		t.Errorf("at(dyn 2) = %v; want %v", got, want)
+	}
+	if got, want := at(3), (pair(":method", "POST")); got != want {
+		t.Errorf("at(3) = %v; want %v", got, want)
+	}
+}
+
+func TestDynamicTableSearch(t *testing.T) {
+	dt := dynamicTable{}
+	dt.setMaxSize(4096)
+
+	dt.add(pair("foo", "bar"))
+	dt.add(pair("blake", "miz"))
+	dt.add(pair(":method", "GET"))
+
+	tests := []struct {
+		hf        HeaderField
+		wantI     uint64
+		wantMatch bool
+	}{
+		// Name and Value match
+		{pair("foo", "bar"), 3, true},
+		{pair(":method", "GET"), 1, true},
+
+		// Only name match because of Sensitive == true
+		{HeaderField{"blake", "miz", true}, 2, false},
+
+		// Only Name matches
+		{pair("foo", "..."), 3, false},
+		{pair("blake", "..."), 2, false},
+		{pair(":method", "..."), 1, false},
+
+		// None match
+		{pair("foo-", "bar"), 0, false},
+	}
+	for _, tt := range tests {
+		if gotI, gotMatch := dt.search(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
+			t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
+		}
+	}
+}
+
+func TestDynamicTableSizeEvict(t *testing.T) {
+	d := NewDecoder(4096, nil)
+	if want := uint32(0); d.dynTab.size != want {
+		t.Fatalf("size = %d; want %d", d.dynTab.size, want)
+	}
+	add := d.dynTab.add
+	add(pair("blake", "eats pizza"))
+	if want := uint32(15 + 32); d.dynTab.size != want {
+		t.Fatalf("after pizza, size = %d; want %d", d.dynTab.size, want)
+	}
+	add(pair("foo", "bar"))
+	if want := uint32(15 + 32 + 6 + 32); d.dynTab.size != want {
+		t.Fatalf("after foo bar, size = %d; want %d", d.dynTab.size, want)
+	}
+	d.dynTab.setMaxSize(15 + 32 + 1 /* slop */)
+	if want := uint32(6 + 32); d.dynTab.size != want {
+		t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want)
+	}
+	if got, want := d.mustAt(len(staticTable)+1), (pair("foo", "bar")); got != want {
+		t.Errorf("at(dyn 1) = %v; want %v", got, want)
+	}
+	add(pair("long", strings.Repeat("x", 500)))
+	if want := uint32(0); d.dynTab.size != want {
+		t.Fatalf("after big one, size = %d; want %d", d.dynTab.size, want)
+	}
+}
+
+func TestDecoderDecode(t *testing.T) {
+	tests := []struct {
+		name       string
+		in         []byte
+		want       []HeaderField
+		wantDynTab []HeaderField // newest entry first
+	}{
+		// C.2.1 Literal Header Field with Indexing
+		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.1
+		{"C.2.1", dehex("400a 6375 7374 6f6d 2d6b 6579 0d63 7573 746f 6d2d 6865 6164 6572"),
+			[]HeaderField{pair("custom-key", "custom-header")},
+			[]HeaderField{pair("custom-key", "custom-header")},
+		},
+
+		// C.2.2 Literal Header Field without Indexing
+		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.2
+		{"C.2.2", dehex("040c 2f73 616d 706c 652f 7061 7468"),
+			[]HeaderField{pair(":path", "/sample/path")},
+			[]HeaderField{}},
+
+		// C.2.3 Literal Header Field never Indexed
+		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.3
+		{"C.2.3", dehex("1008 7061 7373 776f 7264 0673 6563 7265 74"),
+			[]HeaderField{{"password", "secret", true}},
+			[]HeaderField{}},
+
+		// C.2.4 Indexed Header Field
+		// http://http2.github.io/http2-spec/compression.html#rfc.section.C.2.4
+		{"C.2.4", []byte("\x82"),
+			[]HeaderField{pair(":method", "GET")},
+			[]HeaderField{}},
+	}
+	for _, tt := range tests {
+		d := NewDecoder(4096, nil)
+		hf, err := d.DecodeFull(tt.in)
+		if err != nil {
+			t.Errorf("%s: %v", tt.name, err)
+			continue
+		}
+		if !reflect.DeepEqual(hf, tt.want) {
+			t.Errorf("%s: Got %v; want %v", tt.name, hf, tt.want)
+		}
+		gotDynTab := d.dynTab.reverseCopy()
+		if !reflect.DeepEqual(gotDynTab, tt.wantDynTab) {
+			t.Errorf("%s: dynamic table after = %v; want %v", tt.name, gotDynTab, tt.wantDynTab)
+		}
+	}
+}
+
+func (dt *dynamicTable) reverseCopy() (hf []HeaderField) {
+	hf = make([]HeaderField, len(dt.ents))
+	for i := range hf {
+		hf[i] = dt.ents[len(dt.ents)-1-i]
+	}
+	return
+}
+
+type encAndWant struct {
+	enc         []byte
+	want        []HeaderField
+	wantDynTab  []HeaderField
+	wantDynSize uint32
+}
+
+// C.3 Request Examples without Huffman Coding
+// http://http2.github.io/http2-spec/compression.html#rfc.section.C.3
+func TestDecodeC3_NoHuffman(t *testing.T) {
+	testDecodeSeries(t, 4096, []encAndWant{
+		{dehex("8286 8441 0f77 7777 2e65 7861 6d70 6c65 2e63 6f6d"),
+			[]HeaderField{
+				pair(":method", "GET"),
+				pair(":scheme", "http"),
+				pair(":path", "/"),
+				pair(":authority", "www.example.com"),
+			},
+			[]HeaderField{
+				pair(":authority", "www.example.com"),
+			},
+			57,
+		},
+		{dehex("8286 84be 5808 6e6f 2d63 6163 6865"),
+			[]HeaderField{
+				pair(":method", "GET"),
+				pair(":scheme", "http"),
+				pair(":path", "/"),
+				pair(":authority", "www.example.com"),
+				pair("cache-control", "no-cache"),
+			},
+			[]HeaderField{
+				pair("cache-control", "no-cache"),
+				pair(":authority", "www.example.com"),
+			},
+			110,
+		},
+		{dehex("8287 85bf 400a 6375 7374 6f6d 2d6b 6579 0c63 7573 746f 6d2d 7661 6c75 65"),
+			[]HeaderField{
+				pair(":method", "GET"),
+				pair(":scheme", "https"),
+				pair(":path", "/index.html"),
+				pair(":authority", "www.example.com"),
+				pair("custom-key", "custom-value"),
+			},
+			[]HeaderField{
+				pair("custom-key", "custom-value"),
+				pair("cache-control", "no-cache"),
+				pair(":authority", "www.example.com"),
+			},
+			164,
+		},
+	})
+}
+
+// C.4 Request Examples with Huffman Coding
+// http://http2.github.io/http2-spec/compression.html#rfc.section.C.4
+func TestDecodeC4_Huffman(t *testing.T) {
+	testDecodeSeries(t, 4096, []encAndWant{
+		{dehex("8286 8441 8cf1 e3c2 e5f2 3a6b a0ab 90f4 ff"),
+			[]HeaderField{
+				pair(":method", "GET"),
+				pair(":scheme", "http"),
+				pair(":path", "/"),
+				pair(":authority", "www.example.com"),
+			},
+			[]HeaderField{
+				pair(":authority", "www.example.com"),
+			},
+			57,
+		},
+		{dehex("8286 84be 5886 a8eb 1064 9cbf"),
+			[]HeaderField{
+				pair(":method", "GET"),
+				pair(":scheme", "http"),
+				pair(":path", "/"),
+				pair(":authority", "www.example.com"),
+				pair("cache-control", "no-cache"),
+			},
+			[]HeaderField{
+				pair("cache-control", "no-cache"),
+				pair(":authority", "www.example.com"),
+			},
+			110,
+		},
+		{dehex("8287 85bf 4088 25a8 49e9 5ba9 7d7f 8925 a849 e95b b8e8 b4bf"),
+			[]HeaderField{
+				pair(":method", "GET"),
+				pair(":scheme", "https"),
+				pair(":path", "/index.html"),
+				pair(":authority", "www.example.com"),
+				pair("custom-key", "custom-value"),
+			},
+			[]HeaderField{
+				pair("custom-key", "custom-value"),
+				pair("cache-control", "no-cache"),
+				pair(":authority", "www.example.com"),
+			},
+			164,
+		},
+	})
+}
+
+// http://http2.github.io/http2-spec/compression.html#rfc.section.C.5
+// "This section shows several consecutive header lists, corresponding
+// to HTTP responses, on the same connection. The HTTP/2 setting
+// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
+// octets, causing some evictions to occur."
+func TestDecodeC5_ResponsesNoHuff(t *testing.T) {
+	testDecodeSeries(t, 256, []encAndWant{
+		{dehex(`
+4803 3330 3258 0770 7269 7661 7465 611d
+4d6f 6e2c 2032 3120 4f63 7420 3230 3133
+2032 303a 3133 3a32 3120 474d 546e 1768
+7474 7073 3a2f 2f77 7777 2e65 7861 6d70
+6c65 2e63 6f6d
+`),
+			[]HeaderField{
+				pair(":status", "302"),
+				pair("cache-control", "private"),
+				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+				pair("location", "https://www.example.com"),
+			},
+			[]HeaderField{
+				pair("location", "https://www.example.com"),
+				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+				pair("cache-control", "private"),
+				pair(":status", "302"),
+			},
+			222,
+		},
+		{dehex("4803 3330 37c1 c0bf"),
+			[]HeaderField{
+				pair(":status", "307"),
+				pair("cache-control", "private"),
+				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+				pair("location", "https://www.example.com"),
+			},
+			[]HeaderField{
+				pair(":status", "307"),
+				pair("location", "https://www.example.com"),
+				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+				pair("cache-control", "private"),
+			},
+			222,
+		},
+		{dehex(`
+88c1 611d 4d6f 6e2c 2032 3120 4f63 7420
+3230 3133 2032 303a 3133 3a32 3220 474d
+54c0 5a04 677a 6970 7738 666f 6f3d 4153
+444a 4b48 514b 425a 584f 5157 454f 5049
+5541 5851 5745 4f49 553b 206d 6178 2d61
+6765 3d33 3630 303b 2076 6572 7369 6f6e
+3d31
+`),
+			[]HeaderField{
+				pair(":status", "200"),
+				pair("cache-control", "private"),
+				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
+				pair("location", "https://www.example.com"),
+				pair("content-encoding", "gzip"),
+				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
+			},
+			[]HeaderField{
+				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
+				pair("content-encoding", "gzip"),
+				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
+			},
+			215,
+		},
+	})
+}
+
+// http://http2.github.io/http2-spec/compression.html#rfc.section.C.6
+// "This section shows the same examples as the previous section, but
+// using Huffman encoding for the literal values. The HTTP/2 setting
+// parameter SETTINGS_HEADER_TABLE_SIZE is set to the value of 256
+// octets, causing some evictions to occur. The eviction mechanism
+// uses the length of the decoded literal values, so the same
+// evictions occurs as in the previous section."
+func TestDecodeC6_ResponsesHuffman(t *testing.T) {
+	testDecodeSeries(t, 256, []encAndWant{
+		{dehex(`
+4882 6402 5885 aec3 771a 4b61 96d0 7abe
+9410 54d4 44a8 2005 9504 0b81 66e0 82a6
+2d1b ff6e 919d 29ad 1718 63c7 8f0b 97c8
+e9ae 82ae 43d3
+`),
+			[]HeaderField{
+				pair(":status", "302"),
+				pair("cache-control", "private"),
+				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+				pair("location", "https://www.example.com"),
+			},
+			[]HeaderField{
+				pair("location", "https://www.example.com"),
+				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+				pair("cache-control", "private"),
+				pair(":status", "302"),
+			},
+			222,
+		},
+		{dehex("4883 640e ffc1 c0bf"),
+			[]HeaderField{
+				pair(":status", "307"),
+				pair("cache-control", "private"),
+				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+				pair("location", "https://www.example.com"),
+			},
+			[]HeaderField{
+				pair(":status", "307"),
+				pair("location", "https://www.example.com"),
+				pair("date", "Mon, 21 Oct 2013 20:13:21 GMT"),
+				pair("cache-control", "private"),
+			},
+			222,
+		},
+		{dehex(`
+88c1 6196 d07a be94 1054 d444 a820 0595
+040b 8166 e084 a62d 1bff c05a 839b d9ab
+77ad 94e7 821d d7f2 e6c7 b335 dfdf cd5b
+3960 d5af 2708 7f36 72c1 ab27 0fb5 291f
+9587 3160 65c0 03ed 4ee5 b106 3d50 07
+`),
+			[]HeaderField{
+				pair(":status", "200"),
+				pair("cache-control", "private"),
+				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
+				pair("location", "https://www.example.com"),
+				pair("content-encoding", "gzip"),
+				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
+			},
+			[]HeaderField{
+				pair("set-cookie", "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"),
+				pair("content-encoding", "gzip"),
+				pair("date", "Mon, 21 Oct 2013 20:13:22 GMT"),
+			},
+			215,
+		},
+	})
+}
+
+func testDecodeSeries(t *testing.T, size uint32, steps []encAndWant) {
+	d := NewDecoder(size, nil)
+	for i, step := range steps {
+		hf, err := d.DecodeFull(step.enc)
+		if err != nil {
+			t.Fatalf("Error at step index %d: %v", i, err)
+		}
+		if !reflect.DeepEqual(hf, step.want) {
+			t.Fatalf("At step index %d: Got headers %v; want %v", i, hf, step.want)
+		}
+		gotDynTab := d.dynTab.reverseCopy()
+		if !reflect.DeepEqual(gotDynTab, step.wantDynTab) {
+			t.Errorf("After step index %d, dynamic table = %v; want %v", i, gotDynTab, step.wantDynTab)
+		}
+		if d.dynTab.size != step.wantDynSize {
+			t.Errorf("After step index %d, dynamic table size = %v; want %v", i, d.dynTab.size, step.wantDynSize)
+		}
+	}
+}
+
+func TestHuffmanDecodeExcessPadding(t *testing.T) {
+	tests := [][]byte{
+		{0xff},                                   // Padding Exceeds 7 bits
+		{0x1f, 0xff},                             // {"a", 1 byte excess padding}
+		{0x1f, 0xff, 0xff},                       // {"a", 2 byte excess padding}
+		{0x1f, 0xff, 0xff, 0xff},                 // {"a", 3 byte excess padding}
+		{0xff, 0x9f, 0xff, 0xff, 0xff},           // {"a", 29 bit excess padding}
+		{'R', 0xbc, '0', 0xff, 0xff, 0xff, 0xff}, // Padding ends on partial symbol.
+	}
+	for i, in := range tests {
+		var buf bytes.Buffer
+		if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
+			t.Errorf("test-%d: decode(%q) = %v; want ErrInvalidHuffman", i, in, err)
+		}
+	}
+}
+
+func TestHuffmanDecodeEOS(t *testing.T) {
+	in := []byte{0xff, 0xff, 0xff, 0xff, 0xfc} // {EOS, "?"}
+	var buf bytes.Buffer
+	if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
+		t.Errorf("error = %v; want ErrInvalidHuffman", err)
+	}
+}
+
+func TestHuffmanDecodeMaxLengthOnTrailingByte(t *testing.T) {
+	in := []byte{0x00, 0x01} // {"0", "0", "0"}
+	var buf bytes.Buffer
+	if err := huffmanDecode(&buf, 2, in); err != ErrStringLength {
+		t.Errorf("error = %v; want ErrStringLength", err)
+	}
+}
+
+func TestHuffmanDecodeCorruptPadding(t *testing.T) {
+	in := []byte{0x00}
+	var buf bytes.Buffer
+	if _, err := HuffmanDecode(&buf, in); err != ErrInvalidHuffman {
+		t.Errorf("error = %v; want ErrInvalidHuffman", err)
+	}
+}
+
+func TestHuffmanDecode(t *testing.T) {
+	tests := []struct {
+		inHex, want string
+	}{
+		{"f1e3 c2e5 f23a 6ba0 ab90 f4ff", "www.example.com"},
+		{"a8eb 1064 9cbf", "no-cache"},
+		{"25a8 49e9 5ba9 7d7f", "custom-key"},
+		{"25a8 49e9 5bb8 e8b4 bf", "custom-value"},
+		{"6402", "302"},
+		{"aec3 771a 4b", "private"},
+		{"d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff", "Mon, 21 Oct 2013 20:13:21 GMT"},
+		{"9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3", "https://www.example.com"},
+		{"9bd9 ab", "gzip"},
+		{"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
+			"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
+	}
+	for i, tt := range tests {
+		var buf bytes.Buffer
+		in, err := hex.DecodeString(strings.Replace(tt.inHex, " ", "", -1))
+		if err != nil {
+			t.Errorf("%d. hex input error: %v", i, err)
+			continue
+		}
+		if _, err := HuffmanDecode(&buf, in); err != nil {
+			t.Errorf("%d. decode error: %v", i, err)
+			continue
+		}
+		if got := buf.String(); tt.want != got {
+			t.Errorf("%d. decode = %q; want %q", i, got, tt.want)
+		}
+	}
+}
+
+func TestAppendHuffmanString(t *testing.T) {
+	tests := []struct {
+		in, want string
+	}{
+		{"www.example.com", "f1e3 c2e5 f23a 6ba0 ab90 f4ff"},
+		{"no-cache", "a8eb 1064 9cbf"},
+		{"custom-key", "25a8 49e9 5ba9 7d7f"},
+		{"custom-value", "25a8 49e9 5bb8 e8b4 bf"},
+		{"302", "6402"},
+		{"private", "aec3 771a 4b"},
+		{"Mon, 21 Oct 2013 20:13:21 GMT", "d07a be94 1054 d444 a820 0595 040b 8166 e082 a62d 1bff"},
+		{"https://www.example.com", "9d29 ad17 1863 c78f 0b97 c8e9 ae82 ae43 d3"},
+		{"gzip", "9bd9 ab"},
+		{"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1",
+			"94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07"},
+	}
+	for i, tt := range tests {
+		buf := []byte{}
+		want := strings.Replace(tt.want, " ", "", -1)
+		buf = AppendHuffmanString(buf, tt.in)
+		if got := hex.EncodeToString(buf); want != got {
+			t.Errorf("%d. encode = %q; want %q", i, got, want)
+		}
+	}
+}
+
+func TestHuffmanMaxStrLen(t *testing.T) {
+	const msg = "Some string"
+	huff := AppendHuffmanString(nil, msg)
+
+	testGood := func(max int) {
+		var out bytes.Buffer
+		if err := huffmanDecode(&out, max, huff); err != nil {
+			t.Errorf("For maxLen=%d, unexpected error: %v", max, err)
+		}
+		if out.String() != msg {
+			t.Errorf("For maxLen=%d, out = %q; want %q", max, out.String(), msg)
+		}
+	}
+	testGood(0)
+	testGood(len(msg))
+	testGood(len(msg) + 1)
+
+	var out bytes.Buffer
+	if err := huffmanDecode(&out, len(msg)-1, huff); err != ErrStringLength {
+		t.Errorf("err = %v; want ErrStringLength", err)
+	}
+}
+
+func TestHuffmanRoundtripStress(t *testing.T) {
+	const Len = 50 // of uncompressed string
+	input := make([]byte, Len)
+	var output bytes.Buffer
+	var huff []byte
+
+	n := 5000
+	if testing.Short() {
+		n = 100
+	}
+	seed := time.Now().UnixNano()
+	t.Logf("Seed = %v", seed)
+	src := rand.New(rand.NewSource(seed))
+	var encSize int64
+	for i := 0; i < n; i++ {
+		for l := range input {
+			input[l] = byte(src.Intn(256))
+		}
+		huff = AppendHuffmanString(huff[:0], string(input))
+		encSize += int64(len(huff))
+		output.Reset()
+		if err := huffmanDecode(&output, 0, huff); err != nil {
+			t.Errorf("Failed to decode %q -> %q -> error %v", input, huff, err)
+			continue
+		}
+		if !bytes.Equal(output.Bytes(), input) {
+			t.Errorf("Roundtrip failure on %q -> %q -> %q", input, huff, output.Bytes())
+		}
+	}
+	t.Logf("Compressed size of original: %0.02f%% (%v -> %v)", 100*(float64(encSize)/(Len*float64(n))), Len*n, encSize)
+}
+
+func TestHuffmanDecodeFuzz(t *testing.T) {
+	const Len = 50 // of compressed
+	var buf, zbuf bytes.Buffer
+
+	n := 5000
+	if testing.Short() {
+		n = 100
+	}
+	seed := time.Now().UnixNano()
+	t.Logf("Seed = %v", seed)
+	src := rand.New(rand.NewSource(seed))
+	numFail := 0
+	for i := 0; i < n; i++ {
+		zbuf.Reset()
+		if i == 0 {
+			// Start with at least one invalid one.
+			zbuf.WriteString("00\x91\xff\xff\xff\xff\xc8")
+		} else {
+			for l := 0; l < Len; l++ {
+				zbuf.WriteByte(byte(src.Intn(256)))
+			}
+		}
+
+		buf.Reset()
+		if err := huffmanDecode(&buf, 0, zbuf.Bytes()); err != nil {
+			if err == ErrInvalidHuffman {
+				numFail++
+				continue
+			}
+			t.Errorf("Failed to decode %q: %v", zbuf.Bytes(), err)
+			continue
+		}
+	}
+	t.Logf("%0.02f%% are invalid (%d / %d)", 100*float64(numFail)/float64(n), numFail, n)
+	if numFail < 1 {
+		t.Error("expected at least one invalid huffman encoding (test starts with one)")
+	}
+}
+
+func TestReadVarInt(t *testing.T) {
+	type res struct {
+		i        uint64
+		consumed int
+		err      error
+	}
+	tests := []struct {
+		n    byte
+		p    []byte
+		want res
+	}{
+		// Fits in a byte:
+		{1, []byte{0}, res{0, 1, nil}},
+		{2, []byte{2}, res{2, 1, nil}},
+		{3, []byte{6}, res{6, 1, nil}},
+		{4, []byte{14}, res{14, 1, nil}},
+		{5, []byte{30}, res{30, 1, nil}},
+		{6, []byte{62}, res{62, 1, nil}},
+		{7, []byte{126}, res{126, 1, nil}},
+		{8, []byte{254}, res{254, 1, nil}},
+
+		// Doesn't fit in a byte:
+		{1, []byte{1}, res{0, 0, errNeedMore}},
+		{2, []byte{3}, res{0, 0, errNeedMore}},
+		{3, []byte{7}, res{0, 0, errNeedMore}},
+		{4, []byte{15}, res{0, 0, errNeedMore}},
+		{5, []byte{31}, res{0, 0, errNeedMore}},
+		{6, []byte{63}, res{0, 0, errNeedMore}},
+		{7, []byte{127}, res{0, 0, errNeedMore}},
+		{8, []byte{255}, res{0, 0, errNeedMore}},
+
+		// Ignoring top bits:
+		{5, []byte{255, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 111
+		{5, []byte{159, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 100
+		{5, []byte{191, 154, 10}, res{1337, 3, nil}}, // high dummy three bits: 101
+
+		// Extra byte:
+		{5, []byte{191, 154, 10, 2}, res{1337, 3, nil}}, // extra byte
+
+		// Short a byte:
+		{5, []byte{191, 154}, res{0, 0, errNeedMore}},
+
+		// integer overflow:
+		{1, []byte{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}, res{0, 0, errVarintOverflow}},
+	}
+	for _, tt := range tests {
+		i, remain, err := readVarInt(tt.n, tt.p)
+		consumed := len(tt.p) - len(remain)
+		got := res{i, consumed, err}
+		if got != tt.want {
+			t.Errorf("readVarInt(%d, %v ~ %x) = %+v; want %+v", tt.n, tt.p, tt.p, got, tt.want)
+		}
+	}
+}
+
+// Fuzz crash, originally reported at https://github.com/bradfitz/http2/issues/56
+func TestHuffmanFuzzCrash(t *testing.T) {
+	got, err := HuffmanDecodeToString([]byte("00\x91\xff\xff\xff\xff\xc8"))
+	if got != "" {
+		t.Errorf("Got %q; want empty string", got)
+	}
+	if err != ErrInvalidHuffman {
+		t.Errorf("Err = %v; want ErrInvalidHuffman", err)
+	}
+}
+
+func dehex(s string) []byte {
+	s = strings.Replace(s, " ", "", -1)
+	s = strings.Replace(s, "\n", "", -1)
+	b, err := hex.DecodeString(s)
+	if err != nil {
+		panic(err)
+	}
+	return b
+}
+
+func TestEmitEnabled(t *testing.T) {
+	var buf bytes.Buffer
+	enc := NewEncoder(&buf)
+	enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
+	enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
+
+	numCallback := 0
+	var dec *Decoder
+	dec = NewDecoder(8<<20, func(HeaderField) {
+		numCallback++
+		dec.SetEmitEnabled(false)
+	})
+	if !dec.EmitEnabled() {
+		t.Errorf("initial emit enabled = false; want true")
+	}
+	if _, err := dec.Write(buf.Bytes()); err != nil {
+		t.Error(err)
+	}
+	if numCallback != 1 {
+		t.Errorf("num callbacks = %d; want 1", numCallback)
+	}
+	if dec.EmitEnabled() {
+		t.Errorf("emit enabled = true; want false")
+	}
+}
+
+func TestSaveBufLimit(t *testing.T) {
+	const maxStr = 1 << 10
+	var got []HeaderField
+	dec := NewDecoder(initialHeaderTableSize, func(hf HeaderField) {
+		got = append(got, hf)
+	})
+	dec.SetMaxStringLength(maxStr)
+	var frag []byte
+	frag = append(frag[:0], encodeTypeByte(false, false))
+	frag = appendVarInt(frag, 7, 3)
+	frag = append(frag, "foo"...)
+	frag = appendVarInt(frag, 7, 3)
+	frag = append(frag, "bar"...)
+
+	if _, err := dec.Write(frag); err != nil {
+		t.Fatal(err)
+	}
+
+	want := []HeaderField{{Name: "foo", Value: "bar"}}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("After small writes, got %v; want %v", got, want)
+	}
+
+	frag = append(frag[:0], encodeTypeByte(false, false))
+	frag = appendVarInt(frag, 7, maxStr*3)
+	frag = append(frag, make([]byte, maxStr*3)...)
+
+	_, err := dec.Write(frag)
+	if err != ErrStringLength {
+		t.Fatalf("Write error = %v; want ErrStringLength", err)
+	}
+}
diff --git a/src/vendor/golang.org/x/net/http2/hpack/huffman.go b/src/vendor/golang.org/x/net/http2/hpack/huffman.go
new file mode 100644
index 0000000..8850e39
--- /dev/null
+++ b/src/vendor/golang.org/x/net/http2/hpack/huffman.go
@@ -0,0 +1,212 @@
+// 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 hpack
+
+import (
+	"bytes"
+	"errors"
+	"io"
+	"sync"
+)
+
+var bufPool = sync.Pool{
+	New: func() interface{} { return new(bytes.Buffer) },
+}
+
+// HuffmanDecode decodes the string in v and writes the expanded
+// result to w, returning the number of bytes written to w and the
+// Write call's return value. At most one Write call is made.
+func HuffmanDecode(w io.Writer, v []byte) (int, error) {
+	buf := bufPool.Get().(*bytes.Buffer)
+	buf.Reset()
+	defer bufPool.Put(buf)
+	if err := huffmanDecode(buf, 0, v); err != nil {
+		return 0, err
+	}
+	return w.Write(buf.Bytes())
+}
+
+// HuffmanDecodeToString decodes the string in v.
+func HuffmanDecodeToString(v []byte) (string, error) {
+	buf := bufPool.Get().(*bytes.Buffer)
+	buf.Reset()
+	defer bufPool.Put(buf)
+	if err := huffmanDecode(buf, 0, v); err != nil {
+		return "", err
+	}
+	return buf.String(), nil
+}
+
+// ErrInvalidHuffman is returned for errors found decoding
+// Huffman-encoded strings.
+var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
+
+// huffmanDecode decodes v to buf.
+// If maxLen is greater than 0, attempts to write more to buf than
+// maxLen bytes will return ErrStringLength.
+func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
+	n := rootHuffmanNode
+	// cur is the bit buffer that has not been fed into n.
+	// cbits is the number of low order bits in cur that are valid.
+	// sbits is the number of bits of the symbol prefix being decoded.
+	cur, cbits, sbits := uint(0), uint8(0), uint8(0)
+	for _, b := range v {
+		cur = cur<<8 | uint(b)
+		cbits += 8
+		sbits += 8
+		for cbits >= 8 {
+			idx := byte(cur >> (cbits - 8))
+			n = n.children[idx]
+			if n == nil {
+				return ErrInvalidHuffman
+			}
+			if n.children == nil {
+				if maxLen != 0 && buf.Len() == maxLen {
+					return ErrStringLength
+				}
+				buf.WriteByte(n.sym)
+				cbits -= n.codeLen
+				n = rootHuffmanNode
+				sbits = cbits
+			} else {
+				cbits -= 8
+			}
+		}
+	}
+	for cbits > 0 {
+		n = n.children[byte(cur<<(8-cbits))]
+		if n == nil {
+			return ErrInvalidHuffman
+		}
+		if n.children != nil || n.codeLen > cbits {
+			break
+		}
+		if maxLen != 0 && buf.Len() == maxLen {
+			return ErrStringLength
+		}
+		buf.WriteByte(n.sym)
+		cbits -= n.codeLen
+		n = rootHuffmanNode
+		sbits = cbits
+	}
+	if sbits > 7 {
+		// Either there was an incomplete symbol, or overlong padding.
+		// Both are decoding errors per RFC 7541 section 5.2.
+		return ErrInvalidHuffman
+	}
+	if mask := uint(1<<cbits - 1); cur&mask != mask {
+		// Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.
+		return ErrInvalidHuffman
+	}
+
+	return nil
+}
+
+type node struct {
+	// children is non-nil for internal nodes
+	children []*node
+
+	// The following are only valid if children is nil:
+	codeLen uint8 // number of bits that led to the output of sym
+	sym     byte  // output symbol
+}
+
+func newInternalNode() *node {
+	return &node{children: make([]*node, 256)}
+}
+
+var rootHuffmanNode = newInternalNode()
+
+func init() {
+	if len(huffmanCodes) != 256 {
+		panic("unexpected size")
+	}
+	for i, code := range huffmanCodes {
+		addDecoderNode(byte(i), code, huffmanCodeLen[i])
+	}
+}
+
+func addDecoderNode(sym byte, code uint32, codeLen uint8) {
+	cur := rootHuffmanNode
+	for codeLen > 8 {
+		codeLen -= 8
+		i := uint8(code >> codeLen)
+		if cur.children[i] == nil {
+			cur.children[i] = newInternalNode()
+		}
+		cur = cur.children[i]
+	}
+	shift := 8 - codeLen
+	start, end := int(uint8(code<<shift)), int(1<<shift)
+	for i := start; i < start+end; i++ {
+		cur.children[i] = &node{sym: sym, codeLen: codeLen}
+	}
+}
+
+// AppendHuffmanString appends s, as encoded in Huffman codes, to dst
+// and returns the extended buffer.
+func AppendHuffmanString(dst []byte, s string) []byte {
+	rembits := uint8(8)
+
+	for i := 0; i < len(s); i++ {
+		if rembits == 8 {
+			dst = append(dst, 0)
+		}
+		dst, rembits = appendByteToHuffmanCode(dst, rembits, s[i])
+	}
+
+	if rembits < 8 {
+		// special EOS symbol
+		code := uint32(0x3fffffff)
+		nbits := uint8(30)
+
+		t := uint8(code >> (nbits - rembits))
+		dst[len(dst)-1] |= t
+	}
+
+	return dst
+}
+
+// HuffmanEncodeLength returns the number of bytes required to encode
+// s in Huffman codes. The result is round up to byte boundary.
+func HuffmanEncodeLength(s string) uint64 {
+	n := uint64(0)
+	for i := 0; i < len(s); i++ {
+		n += uint64(huffmanCodeLen[s[i]])
+	}
+	return (n + 7) / 8
+}
+
+// appendByteToHuffmanCode appends Huffman code for c to dst and
+// returns the extended buffer and the remaining bits in the last
+// element. The appending is not byte aligned and the remaining bits
+// in the last element of dst is given in rembits.
+func appendByteToHuffmanCode(dst []byte, rembits uint8, c byte) ([]byte, uint8) {
+	code := huffmanCodes[c]
+	nbits := huffmanCodeLen[c]
+
+	for {
+		if rembits > nbits {
+			t := uint8(code << (rembits - nbits))
+			dst[len(dst)-1] |= t
+			rembits -= nbits
+			break
+		}
+
+		t := uint8(code >> (nbits - rembits))
+		dst[len(dst)-1] |= t
+
+		nbits -= rembits
+		rembits = 8
+
+		if nbits == 0 {
+			break
+		}
+
+		dst = append(dst, 0)
+	}
+
+	return dst, rembits
+}
diff --git a/src/internal/golang.org/x/net/http2/hpack/tables.go b/src/vendor/golang.org/x/net/http2/hpack/tables.go
similarity index 100%
rename from src/internal/golang.org/x/net/http2/hpack/tables.go
rename to src/vendor/golang.org/x/net/http2/hpack/tables.go
diff --git a/src/vendor/golang.org/x/net/lex/httplex/httplex.go b/src/vendor/golang.org/x/net/lex/httplex/httplex.go
new file mode 100644
index 0000000..bd0ec24
--- /dev/null
+++ b/src/vendor/golang.org/x/net/lex/httplex/httplex.go
@@ -0,0 +1,312 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package httplex contains rules around lexical matters of various
+// HTTP-related specifications.
+//
+// This package is shared by the standard library (which vendors it)
+// and x/net/http2. It comes with no API stability promise.
+package httplex
+
+import (
+	"strings"
+	"unicode/utf8"
+)
+
+var isTokenTable = [127]bool{
+	'!':  true,
+	'#':  true,
+	'$':  true,
+	'%':  true,
+	'&':  true,
+	'\'': true,
+	'*':  true,
+	'+':  true,
+	'-':  true,
+	'.':  true,
+	'0':  true,
+	'1':  true,
+	'2':  true,
+	'3':  true,
+	'4':  true,
+	'5':  true,
+	'6':  true,
+	'7':  true,
+	'8':  true,
+	'9':  true,
+	'A':  true,
+	'B':  true,
+	'C':  true,
+	'D':  true,
+	'E':  true,
+	'F':  true,
+	'G':  true,
+	'H':  true,
+	'I':  true,
+	'J':  true,
+	'K':  true,
+	'L':  true,
+	'M':  true,
+	'N':  true,
+	'O':  true,
+	'P':  true,
+	'Q':  true,
+	'R':  true,
+	'S':  true,
+	'T':  true,
+	'U':  true,
+	'W':  true,
+	'V':  true,
+	'X':  true,
+	'Y':  true,
+	'Z':  true,
+	'^':  true,
+	'_':  true,
+	'`':  true,
+	'a':  true,
+	'b':  true,
+	'c':  true,
+	'd':  true,
+	'e':  true,
+	'f':  true,
+	'g':  true,
+	'h':  true,
+	'i':  true,
+	'j':  true,
+	'k':  true,
+	'l':  true,
+	'm':  true,
+	'n':  true,
+	'o':  true,
+	'p':  true,
+	'q':  true,
+	'r':  true,
+	's':  true,
+	't':  true,
+	'u':  true,
+	'v':  true,
+	'w':  true,
+	'x':  true,
+	'y':  true,
+	'z':  true,
+	'|':  true,
+	'~':  true,
+}
+
+func IsTokenRune(r rune) bool {
+	i := int(r)
+	return i < len(isTokenTable) && isTokenTable[i]
+}
+
+func isNotToken(r rune) bool {
+	return !IsTokenRune(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
+}
+
+// isLWS reports whether b is linear white space, according
+// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
+//      LWS            = [CRLF] 1*( SP | HT )
+func isLWS(b byte) bool { return b == ' ' || b == '\t' }
+
+// isCTL reports whether b is a control byte, according
+// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
+//      CTL            = <any US-ASCII control character
+//                       (octets 0 - 31) and DEL (127)>
+func isCTL(b byte) bool {
+	const del = 0x7f // a CTL
+	return b < ' ' || b == del
+}
+
+// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name.
+// HTTP/2 imposes the additional restriction that uppercase ASCII
+// letters are not allowed.
+//
+//  RFC 7230 says:
+//   header-field   = field-name ":" OWS field-value OWS
+//   field-name     = token
+//   token          = 1*tchar
+//   tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
+//           "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
+func ValidHeaderFieldName(v string) bool {
+	if len(v) == 0 {
+		return false
+	}
+	for _, r := range v {
+		if !IsTokenRune(r) {
+			return false
+		}
+	}
+	return true
+}
+
+// ValidHostHeader reports whether h is a valid host header.
+func ValidHostHeader(h string) bool {
+	// The latest spec is actually this:
+	//
+	// http://tools.ietf.org/html/rfc7230#section-5.4
+	//     Host = uri-host [ ":" port ]
+	//
+	// Where uri-host is:
+	//     http://tools.ietf.org/html/rfc3986#section-3.2.2
+	//
+	// But we're going to be much more lenient for now and just
+	// search for any byte that's not a valid byte in any of those
+	// expressions.
+	for i := 0; i < len(h); i++ {
+		if !validHostByte[h[i]] {
+			return false
+		}
+	}
+	return true
+}
+
+// See the validHostHeader comment.
+var validHostByte = [256]bool{
+	'0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
+	'8': true, '9': true,
+
+	'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
+	'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
+	'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
+	'y': true, 'z': true,
+
+	'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
+	'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
+	'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
+	'Y': true, 'Z': true,
+
+	'!':  true, // sub-delims
+	'$':  true, // sub-delims
+	'%':  true, // pct-encoded (and used in IPv6 zones)
+	'&':  true, // sub-delims
+	'(':  true, // sub-delims
+	')':  true, // sub-delims
+	'*':  true, // sub-delims
+	'+':  true, // sub-delims
+	',':  true, // sub-delims
+	'-':  true, // unreserved
+	'.':  true, // unreserved
+	':':  true, // IPv6address + Host expression's optional port
+	';':  true, // sub-delims
+	'=':  true, // sub-delims
+	'[':  true,
+	'\'': true, // sub-delims
+	']':  true,
+	'_':  true, // unreserved
+	'~':  true, // unreserved
+}
+
+// ValidHeaderFieldValue reports whether v is a valid "field-value" according to
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
+//
+//        message-header = field-name ":" [ field-value ]
+//        field-value    = *( field-content | LWS )
+//        field-content  = <the OCTETs making up the field-value
+//                         and consisting of either *TEXT or combinations
+//                         of token, separators, and quoted-string>
+//
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
+//
+//        TEXT           = <any OCTET except CTLs,
+//                          but including LWS>
+//        LWS            = [CRLF] 1*( SP | HT )
+//        CTL            = <any US-ASCII control character
+//                         (octets 0 - 31) and DEL (127)>
+//
+// RFC 7230 says:
+//  field-value    = *( field-content / obs-fold )
+//  obj-fold       =  N/A to http2, and deprecated
+//  field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+//  field-vchar    = VCHAR / obs-text
+//  obs-text       = %x80-FF
+//  VCHAR          = "any visible [USASCII] character"
+//
+// http2 further says: "Similarly, HTTP/2 allows header field values
+// that are not valid. While most of the values that can be encoded
+// will not alter header field parsing, carriage return (CR, ASCII
+// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
+// 0x0) might be exploited by an attacker if they are translated
+// verbatim. Any request or response that contains a character not
+// permitted in a header field value MUST be treated as malformed
+// (Section 8.1.2.6). Valid characters are defined by the
+// field-content ABNF rule in Section 3.2 of [RFC7230]."
+//
+// This function does not (yet?) properly handle the rejection of
+// strings that begin or end with SP or HTAB.
+func ValidHeaderFieldValue(v string) bool {
+	for i := 0; i < len(v); i++ {
+		b := v[i]
+		if isCTL(b) && !isLWS(b) {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/vendor/golang.org/x/net/lex/httplex/httplex_test.go b/src/vendor/golang.org/x/net/lex/httplex/httplex_test.go
new file mode 100644
index 0000000..c4ace19
--- /dev/null
+++ b/src/vendor/golang.org/x/net/lex/httplex/httplex_test.go
@@ -0,0 +1,101 @@
+// 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 httplex
+
+import (
+	"testing"
+)
+
+func isChar(c rune) bool { return c <= 127 }
+
+func isCtl(c rune) bool { return c <= 31 || c == 127 }
+
+func isSeparator(c rune) bool {
+	switch c {
+	case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t':
+		return true
+	}
+	return false
+}
+
+func TestIsToken(t *testing.T) {
+	for i := 0; i <= 130; i++ {
+		r := rune(i)
+		expected := isChar(r) && !isCtl(r) && !isSeparator(r)
+		if IsTokenRune(r) != expected {
+			t.Errorf("isToken(0x%x) = %v", r, !expected)
+		}
+	}
+}
+
+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/vendor/golang.org/x/net/route/address.go b/src/vendor/golang.org/x/net/route/address.go
new file mode 100644
index 0000000..206a837
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/address.go
@@ -0,0 +1,269 @@
+// Copyright 2016 The Go 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 route
+
+import "runtime"
+
+// An Addr represents an address associated with packet routing.
+type Addr interface {
+	// Family returns an address family.
+	Family() int
+}
+
+// A LinkAddr represents a link-layer address.
+type LinkAddr struct {
+	Index int    // interface index when attached
+	Name  string // interface name when attached
+	Addr  []byte // link-layer address when attached
+}
+
+// Family implements the Family method of Addr interface.
+func (a *LinkAddr) Family() int { return sysAF_LINK }
+
+func parseLinkAddr(b []byte) (Addr, error) {
+	if len(b) < 8 {
+		return nil, errInvalidAddr
+	}
+	_, a, err := parseKernelLinkAddr(sysAF_LINK, b[4:])
+	if err != nil {
+		return nil, err
+	}
+	a.(*LinkAddr).Index = int(nativeEndian.Uint16(b[2:4]))
+	return a, nil
+}
+
+// parseKernelLinkAddr parses b as a link-layer address in
+// conventional BSD kernel form.
+func parseKernelLinkAddr(_ int, b []byte) (int, Addr, error) {
+	// The encoding looks like the following:
+	// +----------------------------+
+	// | Type             (1 octet) |
+	// +----------------------------+
+	// | Name length      (1 octet) |
+	// +----------------------------+
+	// | Address length   (1 octet) |
+	// +----------------------------+
+	// | Selector length  (1 octet) |
+	// +----------------------------+
+	// | Data            (variable) |
+	// +----------------------------+
+	//
+	// On some platforms, all-bit-one of length field means "don't
+	// care".
+	nlen, alen, slen := int(b[1]), int(b[2]), int(b[3])
+	if nlen == 0xff {
+		nlen = 0
+	}
+	if alen == 0xff {
+		alen = 0
+	}
+	if slen == 0xff {
+		slen = 0
+	}
+	l := 4 + nlen + alen + slen
+	if len(b) < l {
+		return 0, nil, errInvalidAddr
+	}
+	data := b[4:]
+	var name string
+	var addr []byte
+	if nlen > 0 {
+		name = string(data[:nlen])
+		data = data[nlen:]
+	}
+	if alen > 0 {
+		addr = data[:alen]
+		data = data[alen:]
+	}
+	return l, &LinkAddr{Name: name, Addr: addr}, nil
+}
+
+// An Inet4Addr represents an internet address for IPv4.
+type Inet4Addr struct {
+	IP [4]byte // IP address
+}
+
+// Family implements the Family method of Addr interface.
+func (a *Inet4Addr) Family() int { return sysAF_INET }
+
+// An Inet6Addr represents an internet address for IPv6.
+type Inet6Addr struct {
+	IP     [16]byte // IP address
+	ZoneID int      // zone identifier
+}
+
+// Family implements the Family method of Addr interface.
+func (a *Inet6Addr) Family() int { return sysAF_INET6 }
+
+// parseInetAddr parses b as an internet address for IPv4 or IPv6.
+func parseInetAddr(af int, b []byte) (Addr, error) {
+	switch af {
+	case sysAF_INET:
+		if len(b) < 16 {
+			return nil, errInvalidAddr
+		}
+		a := &Inet4Addr{}
+		copy(a.IP[:], b[4:8])
+		return a, nil
+	case sysAF_INET6:
+		if len(b) < 28 {
+			return nil, errInvalidAddr
+		}
+		a := &Inet6Addr{ZoneID: int(nativeEndian.Uint32(b[24:28]))}
+		copy(a.IP[:], b[8:24])
+		if a.IP[0] == 0xfe && a.IP[1]&0xc0 == 0x80 || a.IP[0] == 0xff && (a.IP[1]&0x0f == 0x01 || a.IP[1]&0x0f == 0x02) {
+			// KAME based IPv6 protocol stack usually
+			// embeds the interface index in the
+			// interface-local or link-local address as
+			// the kernel-internal form.
+			id := int(bigEndian.Uint16(a.IP[2:4]))
+			if id != 0 {
+				a.ZoneID = id
+				a.IP[2], a.IP[3] = 0, 0
+			}
+		}
+		return a, nil
+	default:
+		return nil, errInvalidAddr
+	}
+}
+
+// parseKernelInetAddr parses b as an internet address in conventional
+// BSD kernel form.
+func parseKernelInetAddr(af int, b []byte) (int, Addr, 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 message boundary
+	l := int(b[0])
+	if runtime.GOOS == "darwin" {
+		// On Darwn, an address in the kernel form is also
+		// used as a message filler.
+		if l == 0 || len(b) > roundup(l) {
+			l = roundup(l)
+		}
+	} else {
+		l = roundup(l)
+	}
+	if len(b) < l {
+		return 0, nil, errInvalidAddr
+	}
+	// Don't reorder case expressions.
+	// The case expressions for IPv6 must come first.
+	const (
+		off4 = 4 // offset of in_addr
+		off6 = 8 // offset of in6_addr
+	)
+	switch {
+	case b[0] == 28: // size of sockaddr_in6
+		a := &Inet6Addr{}
+		copy(a.IP[:], b[off6:off6+16])
+		return int(b[0]), a, nil
+	case af == sysAF_INET6:
+		a := &Inet6Addr{}
+		if l-1 < off6 {
+			copy(a.IP[:], b[1:l])
+		} else {
+			copy(a.IP[:], b[l-off6:l])
+		}
+		return int(b[0]), a, nil
+	case b[0] == 16: // size of sockaddr_in
+		a := &Inet4Addr{}
+		copy(a.IP[:], b[off4:off4+4])
+		return int(b[0]), a, nil
+	default: // an old fashion, AF_UNSPEC or unknown means AF_INET
+		a := &Inet4Addr{}
+		if l-1 < off4 {
+			copy(a.IP[:], b[1:l])
+		} else {
+			copy(a.IP[:], b[l-off4:l])
+		}
+		return int(b[0]), a, nil
+	}
+}
+
+// A DefaultAddr represents an address of various operating
+// system-specific features.
+type DefaultAddr struct {
+	af  int
+	Raw []byte // raw format of address
+}
+
+// Family implements the Family method of Addr interface.
+func (a *DefaultAddr) Family() int { return a.af }
+
+func parseDefaultAddr(b []byte) (Addr, error) {
+	if len(b) < 2 || len(b) < int(b[0]) {
+		return nil, errInvalidAddr
+	}
+	a := &DefaultAddr{af: int(b[1]), Raw: b[:b[0]]}
+	return a, nil
+}
+
+func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) ([]Addr, error) {
+	var as [sysRTAX_MAX]Addr
+	af := int(sysAF_UNSPEC)
+	for i := uint(0); i < sysRTAX_MAX && len(b) >= roundup(0); i++ {
+		if attrs&(1<<i) == 0 {
+			continue
+		}
+		if i <= sysRTAX_BRD {
+			switch b[1] {
+			case sysAF_LINK:
+				a, err := parseLinkAddr(b)
+				if err != nil {
+					return nil, err
+				}
+				as[i] = a
+				b = b[roundup(int(b[0])):]
+			case sysAF_INET, sysAF_INET6:
+				af = int(b[1])
+				a, err := parseInetAddr(af, b)
+				if err != nil {
+					return nil, err
+				}
+				as[i] = a
+				b = b[roundup(int(b[0])):]
+			default:
+				l, a, err := fn(af, b)
+				if err != nil {
+					return nil, err
+				}
+				as[i] = a
+				ll := roundup(l)
+				if len(b) < ll {
+					b = b[l:]
+				} else {
+					b = b[ll:]
+				}
+			}
+		} else {
+			a, err := parseDefaultAddr(b)
+			if err != nil {
+				return nil, err
+			}
+			as[i] = a
+			b = b[roundup(int(b[0])):]
+		}
+	}
+	return as[:], nil
+}
diff --git a/src/vendor/golang.org/x/net/route/address_darwin_test.go b/src/vendor/golang.org/x/net/route/address_darwin_test.go
new file mode 100644
index 0000000..b86bd3d
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/address_darwin_test.go
@@ -0,0 +1,63 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import (
+	"reflect"
+	"testing"
+)
+
+type parseAddrsOnDarwinTest struct {
+	attrs uint
+	fn    func(int, []byte) (int, Addr, error)
+	b     []byte
+	as    []Addr
+}
+
+var parseAddrsOnDarwinLittleEndianTests = []parseAddrsOnDarwinTest{
+	{
+		sysRTA_DST | sysRTA_GATEWAY | sysRTA_NETMASK,
+		parseKernelInetAddr,
+		[]byte{
+			0x10, 0x2, 0x0, 0x0, 0xc0, 0xa8, 0x56, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+			0x14, 0x12, 0x4, 0x0, 0x6, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0,
+
+			0x7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+		},
+		[]Addr{
+			&Inet4Addr{IP: [4]byte{192, 168, 86, 0}},
+			&LinkAddr{Index: 4},
+			&Inet4Addr{IP: [4]byte{255, 255, 255, 255}},
+			nil,
+			nil,
+			nil,
+			nil,
+			nil,
+		},
+	},
+}
+
+func TestParseAddrsOnDarwin(t *testing.T) {
+	tests := parseAddrsOnDarwinLittleEndianTests
+	if nativeEndian != littleEndian {
+		t.Skip("no test for non-little endian machine yet")
+	}
+
+	for i, tt := range tests {
+		as, err := parseAddrs(tt.attrs, tt.fn, tt.b)
+		if err != nil {
+			t.Error(i, err)
+			continue
+		}
+		if !reflect.DeepEqual(as, tt.as) {
+			t.Errorf("#%d: got %+v; want %+v", i, as, tt.as)
+			continue
+		}
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/address_test.go b/src/vendor/golang.org/x/net/route/address_test.go
new file mode 100644
index 0000000..2005ef7
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/address_test.go
@@ -0,0 +1,103 @@
+// Copyright 2016 The Go 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 route
+
+import (
+	"reflect"
+	"testing"
+)
+
+type parseAddrsTest struct {
+	attrs uint
+	fn    func(int, []byte) (int, Addr, error)
+	b     []byte
+	as    []Addr
+}
+
+var parseAddrsLittleEndianTests = []parseAddrsTest{
+	{
+		sysRTA_DST | sysRTA_GATEWAY | sysRTA_NETMASK | sysRTA_BRD,
+		parseKernelInetAddr,
+		[]byte{
+			0x38, 0x12, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+			0x38, 0x12, 0x2, 0x0, 0x6, 0x3, 0x6, 0x0,
+			0x65, 0x6d, 0x31, 0x0, 0xc, 0x29, 0x66, 0x2c,
+			0xdc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+			0x10, 0x2, 0x0, 0x0, 0xac, 0x10, 0xdc, 0xb4,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+			0x10, 0x2, 0x0, 0x0, 0xac, 0x10, 0xdc, 0xff,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+		},
+		[]Addr{
+			&LinkAddr{Index: 0},
+			&LinkAddr{Index: 2, Name: "em1", Addr: []byte{0x00, 0x0c, 0x29, 0x66, 0x2c, 0xdc}},
+			&Inet4Addr{IP: [4]byte{172, 16, 220, 180}},
+			nil,
+			nil,
+			nil,
+			nil,
+			&Inet4Addr{IP: [4]byte{172, 16, 220, 255}},
+		},
+	},
+	{
+		sysRTA_NETMASK | sysRTA_IFP | sysRTA_IFA,
+		parseKernelInetAddr,
+		[]byte{
+			0x7, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0x0,
+
+			0x18, 0x12, 0xa, 0x0, 0x87, 0x8, 0x0, 0x0,
+			0x76, 0x6c, 0x61, 0x6e, 0x35, 0x36, 0x38, 0x32,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+			0x10, 0x2, 0x0, 0x0, 0xa9, 0xfe, 0x0, 0x1,
+			0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+		},
+		[]Addr{
+			nil,
+			nil,
+			&Inet4Addr{IP: [4]byte{255, 255, 255, 0}},
+			nil,
+			&LinkAddr{Index: 10, Name: "vlan5682"},
+			&Inet4Addr{IP: [4]byte{169, 254, 0, 1}},
+			nil,
+			nil,
+		},
+	},
+}
+
+func TestParseAddrs(t *testing.T) {
+	tests := parseAddrsLittleEndianTests
+	if nativeEndian != littleEndian {
+		t.Skip("no test for non-little endian machine yet")
+	}
+
+	for i, tt := range tests {
+		as, err := parseAddrs(tt.attrs, tt.fn, tt.b)
+		if err != nil {
+			t.Error(i, err)
+			continue
+		}
+		as = as[:8] // the list varies between operating systems
+		if !reflect.DeepEqual(as, tt.as) {
+			t.Errorf("#%d: got %+v; want %+v", i, as, tt.as)
+			continue
+		}
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/binary.go b/src/vendor/golang.org/x/net/route/binary.go
new file mode 100644
index 0000000..4c56163
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/binary.go
@@ -0,0 +1,90 @@
+// Copyright 2016 The Go 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 route
+
+// This file contains duplicates of encoding/binary package.
+//
+// This package is supposed to be used by the net package of standard
+// library. Therefore a package set used in the package must be the
+// same as net package.
+
+var (
+	littleEndian binaryLittleEndian
+	bigEndian    binaryBigEndian
+)
+
+type binaryByteOrder interface {
+	Uint16([]byte) uint16
+	Uint32([]byte) uint32
+	PutUint16([]byte, uint16)
+	PutUint32([]byte, uint32)
+	Uint64([]byte) uint64
+}
+
+type binaryLittleEndian struct{}
+
+func (binaryLittleEndian) Uint16(b []byte) uint16 {
+	_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+	return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func (binaryLittleEndian) PutUint16(b []byte, v uint16) {
+	_ = b[1] // early bounds check to guarantee safety of writes below
+	b[0] = byte(v)
+	b[1] = byte(v >> 8)
+}
+
+func (binaryLittleEndian) Uint32(b []byte) uint32 {
+	_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func (binaryLittleEndian) PutUint32(b []byte, v uint32) {
+	_ = b[3] // early bounds check to guarantee safety of writes below
+	b[0] = byte(v)
+	b[1] = byte(v >> 8)
+	b[2] = byte(v >> 16)
+	b[3] = byte(v >> 24)
+}
+
+func (binaryLittleEndian) Uint64(b []byte) uint64 {
+	_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+	return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+		uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+type binaryBigEndian struct{}
+
+func (binaryBigEndian) Uint16(b []byte) uint16 {
+	_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+	return uint16(b[1]) | uint16(b[0])<<8
+}
+
+func (binaryBigEndian) PutUint16(b []byte, v uint16) {
+	_ = b[1] // early bounds check to guarantee safety of writes below
+	b[0] = byte(v >> 8)
+	b[1] = byte(v)
+}
+
+func (binaryBigEndian) Uint32(b []byte) uint32 {
+	_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+	return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+}
+
+func (binaryBigEndian) PutUint32(b []byte, v uint32) {
+	_ = b[3] // early bounds check to guarantee safety of writes below
+	b[0] = byte(v >> 24)
+	b[1] = byte(v >> 16)
+	b[2] = byte(v >> 8)
+	b[3] = byte(v)
+}
+
+func (binaryBigEndian) Uint64(b []byte) uint64 {
+	_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+	return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+		uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+}
diff --git a/src/vendor/golang.org/x/net/route/defs_darwin.go b/src/vendor/golang.org/x/net/route/defs_darwin.go
new file mode 100644
index 0000000..f452ad1
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/defs_darwin.go
@@ -0,0 +1,106 @@
+// Copyright 2016 The Go 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 route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+import "C"
+
+const (
+	sysAF_UNSPEC = C.AF_UNSPEC
+	sysAF_INET   = C.AF_INET
+	sysAF_ROUTE  = C.AF_ROUTE
+	sysAF_LINK   = C.AF_LINK
+	sysAF_INET6  = C.AF_INET6
+
+	sysNET_RT_DUMP    = C.NET_RT_DUMP
+	sysNET_RT_FLAGS   = C.NET_RT_FLAGS
+	sysNET_RT_IFLIST  = C.NET_RT_IFLIST
+	sysNET_RT_STAT    = C.NET_RT_STAT
+	sysNET_RT_TRASH   = C.NET_RT_TRASH
+	sysNET_RT_IFLIST2 = C.NET_RT_IFLIST2
+	sysNET_RT_DUMP2   = C.NET_RT_DUMP2
+	sysNET_RT_MAXID   = C.NET_RT_MAXID
+)
+
+const (
+	sysCTL_MAXNAME = C.CTL_MAXNAME
+
+	sysCTL_UNSPEC  = C.CTL_UNSPEC
+	sysCTL_KERN    = C.CTL_KERN
+	sysCTL_VM      = C.CTL_VM
+	sysCTL_VFS     = C.CTL_VFS
+	sysCTL_NET     = C.CTL_NET
+	sysCTL_DEBUG   = C.CTL_DEBUG
+	sysCTL_HW      = C.CTL_HW
+	sysCTL_MACHDEP = C.CTL_MACHDEP
+	sysCTL_USER    = C.CTL_USER
+	sysCTL_MAXID   = C.CTL_MAXID
+)
+
+const (
+	sysRTM_VERSION = C.RTM_VERSION
+
+	sysRTM_ADD       = C.RTM_ADD
+	sysRTM_DELETE    = C.RTM_DELETE
+	sysRTM_CHANGE    = C.RTM_CHANGE
+	sysRTM_GET       = C.RTM_GET
+	sysRTM_LOSING    = C.RTM_LOSING
+	sysRTM_REDIRECT  = C.RTM_REDIRECT
+	sysRTM_MISS      = C.RTM_MISS
+	sysRTM_LOCK      = C.RTM_LOCK
+	sysRTM_OLDADD    = C.RTM_OLDADD
+	sysRTM_OLDDEL    = C.RTM_OLDDEL
+	sysRTM_RESOLVE   = C.RTM_RESOLVE
+	sysRTM_NEWADDR   = C.RTM_NEWADDR
+	sysRTM_DELADDR   = C.RTM_DELADDR
+	sysRTM_IFINFO    = C.RTM_IFINFO
+	sysRTM_NEWMADDR  = C.RTM_NEWMADDR
+	sysRTM_DELMADDR  = C.RTM_DELMADDR
+	sysRTM_IFINFO2   = C.RTM_IFINFO2
+	sysRTM_NEWMADDR2 = C.RTM_NEWMADDR2
+	sysRTM_GET2      = C.RTM_GET2
+
+	sysRTA_DST     = C.RTA_DST
+	sysRTA_GATEWAY = C.RTA_GATEWAY
+	sysRTA_NETMASK = C.RTA_NETMASK
+	sysRTA_GENMASK = C.RTA_GENMASK
+	sysRTA_IFP     = C.RTA_IFP
+	sysRTA_IFA     = C.RTA_IFA
+	sysRTA_AUTHOR  = C.RTA_AUTHOR
+	sysRTA_BRD     = C.RTA_BRD
+
+	sysRTAX_DST     = C.RTAX_DST
+	sysRTAX_GATEWAY = C.RTAX_GATEWAY
+	sysRTAX_NETMASK = C.RTAX_NETMASK
+	sysRTAX_GENMASK = C.RTAX_GENMASK
+	sysRTAX_IFP     = C.RTAX_IFP
+	sysRTAX_IFA     = C.RTAX_IFA
+	sysRTAX_AUTHOR  = C.RTAX_AUTHOR
+	sysRTAX_BRD     = C.RTAX_BRD
+	sysRTAX_MAX     = C.RTAX_MAX
+)
+
+const (
+	sizeofIfMsghdrDarwin15    = C.sizeof_struct_if_msghdr
+	sizeofIfaMsghdrDarwin15   = C.sizeof_struct_ifa_msghdr
+	sizeofIfmaMsghdrDarwin15  = C.sizeof_struct_ifma_msghdr
+	sizeofIfMsghdr2Darwin15   = C.sizeof_struct_if_msghdr2
+	sizeofIfmaMsghdr2Darwin15 = C.sizeof_struct_ifma_msghdr2
+	sizeofIfDataDarwin15      = C.sizeof_struct_if_data
+	sizeofIfData64Darwin15    = C.sizeof_struct_if_data64
+
+	sizeofRtMsghdrDarwin15  = C.sizeof_struct_rt_msghdr
+	sizeofRtMsghdr2Darwin15 = C.sizeof_struct_rt_msghdr2
+	sizeofRtMetricsDarwin15 = C.sizeof_struct_rt_metrics
+)
diff --git a/src/vendor/golang.org/x/net/route/defs_dragonfly.go b/src/vendor/golang.org/x/net/route/defs_dragonfly.go
new file mode 100644
index 0000000..c737751
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/defs_dragonfly.go
@@ -0,0 +1,105 @@
+// Copyright 2016 The Go 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 route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+import "C"
+
+const (
+	sysAF_UNSPEC = C.AF_UNSPEC
+	sysAF_INET   = C.AF_INET
+	sysAF_ROUTE  = C.AF_ROUTE
+	sysAF_LINK   = C.AF_LINK
+	sysAF_INET6  = C.AF_INET6
+
+	sysNET_RT_DUMP   = C.NET_RT_DUMP
+	sysNET_RT_FLAGS  = C.NET_RT_FLAGS
+	sysNET_RT_IFLIST = C.NET_RT_IFLIST
+	sysNET_RT_MAXID  = C.NET_RT_MAXID
+)
+
+const (
+	sysCTL_MAXNAME = C.CTL_MAXNAME
+
+	sysCTL_UNSPEC   = C.CTL_UNSPEC
+	sysCTL_KERN     = C.CTL_KERN
+	sysCTL_VM       = C.CTL_VM
+	sysCTL_VFS      = C.CTL_VFS
+	sysCTL_NET      = C.CTL_NET
+	sysCTL_DEBUG    = C.CTL_DEBUG
+	sysCTL_HW       = C.CTL_HW
+	sysCTL_MACHDEP  = C.CTL_MACHDEP
+	sysCTL_USER     = C.CTL_USER
+	sysCTL_P1003_1B = C.CTL_P1003_1B
+	sysCTL_LWKT     = C.CTL_LWKT
+	sysCTL_MAXID    = C.CTL_MAXID
+)
+
+const (
+	sysRTM_VERSION = C.RTM_VERSION
+
+	sysRTM_ADD        = C.RTM_ADD
+	sysRTM_DELETE     = C.RTM_DELETE
+	sysRTM_CHANGE     = C.RTM_CHANGE
+	sysRTM_GET        = C.RTM_GET
+	sysRTM_LOSING     = C.RTM_LOSING
+	sysRTM_REDIRECT   = C.RTM_REDIRECT
+	sysRTM_MISS       = C.RTM_MISS
+	sysRTM_LOCK       = C.RTM_LOCK
+	sysRTM_OLDADD     = C.RTM_OLDADD
+	sysRTM_OLDDEL     = C.RTM_OLDDEL
+	sysRTM_RESOLVE    = C.RTM_RESOLVE
+	sysRTM_NEWADDR    = C.RTM_NEWADDR
+	sysRTM_DELADDR    = C.RTM_DELADDR
+	sysRTM_IFINFO     = C.RTM_IFINFO
+	sysRTM_NEWMADDR   = C.RTM_NEWMADDR
+	sysRTM_DELMADDR   = C.RTM_DELMADDR
+	sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE
+	sysRTM_IEEE80211  = C.RTM_IEEE80211
+
+	sysRTA_DST     = C.RTA_DST
+	sysRTA_GATEWAY = C.RTA_GATEWAY
+	sysRTA_NETMASK = C.RTA_NETMASK
+	sysRTA_GENMASK = C.RTA_GENMASK
+	sysRTA_IFP     = C.RTA_IFP
+	sysRTA_IFA     = C.RTA_IFA
+	sysRTA_AUTHOR  = C.RTA_AUTHOR
+	sysRTA_BRD     = C.RTA_BRD
+	sysRTA_MPLS1   = C.RTA_MPLS1
+	sysRTA_MPLS2   = C.RTA_MPLS2
+	sysRTA_MPLS3   = C.RTA_MPLS3
+
+	sysRTAX_DST     = C.RTAX_DST
+	sysRTAX_GATEWAY = C.RTAX_GATEWAY
+	sysRTAX_NETMASK = C.RTAX_NETMASK
+	sysRTAX_GENMASK = C.RTAX_GENMASK
+	sysRTAX_IFP     = C.RTAX_IFP
+	sysRTAX_IFA     = C.RTAX_IFA
+	sysRTAX_AUTHOR  = C.RTAX_AUTHOR
+	sysRTAX_BRD     = C.RTAX_BRD
+	sysRTAX_MPLS1   = C.RTAX_MPLS1
+	sysRTAX_MPLS2   = C.RTAX_MPLS2
+	sysRTAX_MPLS3   = C.RTAX_MPLS3
+	sysRTAX_MAX     = C.RTAX_MAX
+)
+
+const (
+	sizeofIfMsghdrDragonFlyBSD4         = C.sizeof_struct_if_msghdr
+	sizeofIfaMsghdrDragonFlyBSD4        = C.sizeof_struct_ifa_msghdr
+	sizeofIfmaMsghdrDragonFlyBSD4       = C.sizeof_struct_ifma_msghdr
+	sizeofIfAnnouncemsghdrDragonFlyBSD4 = C.sizeof_struct_if_announcemsghdr
+
+	sizeofRtMsghdrDragonFlyBSD4  = C.sizeof_struct_rt_msghdr
+	sizeofRtMetricsDragonFlyBSD4 = C.sizeof_struct_rt_metrics
+)
diff --git a/src/vendor/golang.org/x/net/route/defs_freebsd.go b/src/vendor/golang.org/x/net/route/defs_freebsd.go
new file mode 100644
index 0000000..8f834e8
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/defs_freebsd.go
@@ -0,0 +1,329 @@
+// Copyright 2016 The Go 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 route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+struct if_data_freebsd7 {
+	u_char ifi_type;
+	u_char ifi_physical;
+	u_char ifi_addrlen;
+	u_char ifi_hdrlen;
+	u_char ifi_link_state;
+	u_char ifi_spare_char1;
+	u_char ifi_spare_char2;
+	u_char ifi_datalen;
+	u_long ifi_mtu;
+	u_long ifi_metric;
+	u_long ifi_baudrate;
+	u_long ifi_ipackets;
+	u_long ifi_ierrors;
+	u_long ifi_opackets;
+	u_long ifi_oerrors;
+	u_long ifi_collisions;
+	u_long ifi_ibytes;
+	u_long ifi_obytes;
+	u_long ifi_imcasts;
+	u_long ifi_omcasts;
+	u_long ifi_iqdrops;
+	u_long ifi_noproto;
+	u_long ifi_hwassist;
+	time_t __ifi_epoch;
+	struct timeval __ifi_lastchange;
+};
+
+struct if_data_freebsd8 {
+	u_char ifi_type;
+	u_char ifi_physical;
+	u_char ifi_addrlen;
+	u_char ifi_hdrlen;
+	u_char ifi_link_state;
+	u_char ifi_spare_char1;
+	u_char ifi_spare_char2;
+	u_char ifi_datalen;
+	u_long ifi_mtu;
+	u_long ifi_metric;
+	u_long ifi_baudrate;
+	u_long ifi_ipackets;
+	u_long ifi_ierrors;
+	u_long ifi_opackets;
+	u_long ifi_oerrors;
+	u_long ifi_collisions;
+	u_long ifi_ibytes;
+	u_long ifi_obytes;
+	u_long ifi_imcasts;
+	u_long ifi_omcasts;
+	u_long ifi_iqdrops;
+	u_long ifi_noproto;
+	u_long ifi_hwassist;
+	time_t __ifi_epoch;
+	struct timeval __ifi_lastchange;
+};
+
+struct if_data_freebsd9 {
+	u_char ifi_type;
+	u_char ifi_physical;
+	u_char ifi_addrlen;
+	u_char ifi_hdrlen;
+	u_char ifi_link_state;
+	u_char ifi_spare_char1;
+	u_char ifi_spare_char2;
+	u_char ifi_datalen;
+	u_long ifi_mtu;
+	u_long ifi_metric;
+	u_long ifi_baudrate;
+	u_long ifi_ipackets;
+	u_long ifi_ierrors;
+	u_long ifi_opackets;
+	u_long ifi_oerrors;
+	u_long ifi_collisions;
+	u_long ifi_ibytes;
+	u_long ifi_obytes;
+	u_long ifi_imcasts;
+	u_long ifi_omcasts;
+	u_long ifi_iqdrops;
+	u_long ifi_noproto;
+	u_long ifi_hwassist;
+	time_t __ifi_epoch;
+	struct timeval __ifi_lastchange;
+};
+
+struct if_data_freebsd10 {
+	u_char ifi_type;
+	u_char ifi_physical;
+	u_char ifi_addrlen;
+	u_char ifi_hdrlen;
+	u_char ifi_link_state;
+	u_char ifi_vhid;
+	u_char ifi_baudrate_pf;
+	u_char ifi_datalen;
+	u_long ifi_mtu;
+	u_long ifi_metric;
+	u_long ifi_baudrate;
+	u_long ifi_ipackets;
+	u_long ifi_ierrors;
+	u_long ifi_opackets;
+	u_long ifi_oerrors;
+	u_long ifi_collisions;
+	u_long ifi_ibytes;
+	u_long ifi_obytes;
+	u_long ifi_imcasts;
+	u_long ifi_omcasts;
+	u_long ifi_iqdrops;
+	u_long ifi_noproto;
+	uint64_t ifi_hwassist;
+	time_t __ifi_epoch;
+	struct timeval __ifi_lastchange;
+};
+
+struct if_data_freebsd11 {
+	uint8_t ifi_type;
+	uint8_t ifi_physical;
+	uint8_t ifi_addrlen;
+	uint8_t ifi_hdrlen;
+	uint8_t ifi_link_state;
+	uint8_t ifi_vhid;
+	uint16_t ifi_datalen;
+	uint32_t ifi_mtu;
+	uint32_t ifi_metric;
+	uint64_t ifi_baudrate;
+	uint64_t ifi_ipackets;
+	uint64_t ifi_ierrors;
+	uint64_t ifi_opackets;
+	uint64_t ifi_oerrors;
+	uint64_t ifi_collisions;
+	uint64_t ifi_ibytes;
+	uint64_t ifi_obytes;
+	uint64_t ifi_imcasts;
+	uint64_t ifi_omcasts;
+	uint64_t ifi_iqdrops;
+	uint64_t ifi_oqdrops;
+	uint64_t ifi_noproto;
+	uint64_t ifi_hwassist;
+	union {
+		time_t tt;
+		uint64_t ph;
+	} __ifi_epoch;
+	union {
+		struct timeval tv;
+		struct {
+			uint64_t ph1;
+			uint64_t ph2;
+		} ph;
+	} __ifi_lastchange;
+};
+
+struct if_msghdr_freebsd7 {
+	u_short ifm_msglen;
+	u_char ifm_version;
+	u_char ifm_type;
+	int ifm_addrs;
+	int ifm_flags;
+	u_short ifm_index;
+	struct if_data_freebsd7 ifm_data;
+};
+
+struct if_msghdr_freebsd8 {
+	u_short ifm_msglen;
+	u_char ifm_version;
+	u_char ifm_type;
+	int ifm_addrs;
+	int ifm_flags;
+	u_short ifm_index;
+	struct if_data_freebsd8 ifm_data;
+};
+
+struct if_msghdr_freebsd9 {
+	u_short ifm_msglen;
+	u_char ifm_version;
+	u_char ifm_type;
+	int ifm_addrs;
+	int ifm_flags;
+	u_short ifm_index;
+	struct if_data_freebsd9 ifm_data;
+};
+
+struct if_msghdr_freebsd10 {
+	u_short ifm_msglen;
+	u_char ifm_version;
+	u_char ifm_type;
+	int ifm_addrs;
+	int ifm_flags;
+	u_short ifm_index;
+	struct if_data_freebsd10 ifm_data;
+};
+
+struct if_msghdr_freebsd11 {
+	u_short ifm_msglen;
+	u_char ifm_version;
+	u_char ifm_type;
+	int ifm_addrs;
+	int ifm_flags;
+	u_short ifm_index;
+	struct if_data_freebsd11 ifm_data;
+};
+*/
+import "C"
+
+const (
+	sysAF_UNSPEC = C.AF_UNSPEC
+	sysAF_INET   = C.AF_INET
+	sysAF_ROUTE  = C.AF_ROUTE
+	sysAF_LINK   = C.AF_LINK
+	sysAF_INET6  = C.AF_INET6
+
+	sysNET_RT_DUMP     = C.NET_RT_DUMP
+	sysNET_RT_FLAGS    = C.NET_RT_FLAGS
+	sysNET_RT_IFLIST   = C.NET_RT_IFLIST
+	sysNET_RT_IFMALIST = C.NET_RT_IFMALIST
+	sysNET_RT_IFLISTL  = C.NET_RT_IFLISTL
+)
+
+const (
+	sysCTL_MAXNAME = C.CTL_MAXNAME
+
+	sysCTL_UNSPEC   = C.CTL_UNSPEC
+	sysCTL_KERN     = C.CTL_KERN
+	sysCTL_VM       = C.CTL_VM
+	sysCTL_VFS      = C.CTL_VFS
+	sysCTL_NET      = C.CTL_NET
+	sysCTL_DEBUG    = C.CTL_DEBUG
+	sysCTL_HW       = C.CTL_HW
+	sysCTL_MACHDEP  = C.CTL_MACHDEP
+	sysCTL_USER     = C.CTL_USER
+	sysCTL_P1003_1B = C.CTL_P1003_1B
+)
+
+const (
+	sysRTM_VERSION = C.RTM_VERSION
+
+	sysRTM_ADD        = C.RTM_ADD
+	sysRTM_DELETE     = C.RTM_DELETE
+	sysRTM_CHANGE     = C.RTM_CHANGE
+	sysRTM_GET        = C.RTM_GET
+	sysRTM_LOSING     = C.RTM_LOSING
+	sysRTM_REDIRECT   = C.RTM_REDIRECT
+	sysRTM_MISS       = C.RTM_MISS
+	sysRTM_LOCK       = C.RTM_LOCK
+	sysRTM_RESOLVE    = C.RTM_RESOLVE
+	sysRTM_NEWADDR    = C.RTM_NEWADDR
+	sysRTM_DELADDR    = C.RTM_DELADDR
+	sysRTM_IFINFO     = C.RTM_IFINFO
+	sysRTM_NEWMADDR   = C.RTM_NEWMADDR
+	sysRTM_DELMADDR   = C.RTM_DELMADDR
+	sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE
+	sysRTM_IEEE80211  = C.RTM_IEEE80211
+
+	sysRTA_DST     = C.RTA_DST
+	sysRTA_GATEWAY = C.RTA_GATEWAY
+	sysRTA_NETMASK = C.RTA_NETMASK
+	sysRTA_GENMASK = C.RTA_GENMASK
+	sysRTA_IFP     = C.RTA_IFP
+	sysRTA_IFA     = C.RTA_IFA
+	sysRTA_AUTHOR  = C.RTA_AUTHOR
+	sysRTA_BRD     = C.RTA_BRD
+
+	sysRTAX_DST     = C.RTAX_DST
+	sysRTAX_GATEWAY = C.RTAX_GATEWAY
+	sysRTAX_NETMASK = C.RTAX_NETMASK
+	sysRTAX_GENMASK = C.RTAX_GENMASK
+	sysRTAX_IFP     = C.RTAX_IFP
+	sysRTAX_IFA     = C.RTAX_IFA
+	sysRTAX_AUTHOR  = C.RTAX_AUTHOR
+	sysRTAX_BRD     = C.RTAX_BRD
+	sysRTAX_MAX     = C.RTAX_MAX
+)
+
+const (
+	sizeofIfMsghdrlFreeBSD10        = C.sizeof_struct_if_msghdrl
+	sizeofIfaMsghdrFreeBSD10        = C.sizeof_struct_ifa_msghdr
+	sizeofIfaMsghdrlFreeBSD10       = C.sizeof_struct_ifa_msghdrl
+	sizeofIfmaMsghdrFreeBSD10       = C.sizeof_struct_ifma_msghdr
+	sizeofIfAnnouncemsghdrFreeBSD10 = C.sizeof_struct_if_announcemsghdr
+
+	sizeofRtMsghdrFreeBSD10  = C.sizeof_struct_rt_msghdr
+	sizeofRtMetricsFreeBSD10 = C.sizeof_struct_rt_metrics
+
+	sizeofIfMsghdrFreeBSD7  = C.sizeof_struct_if_msghdr_freebsd7
+	sizeofIfMsghdrFreeBSD8  = C.sizeof_struct_if_msghdr_freebsd8
+	sizeofIfMsghdrFreeBSD9  = C.sizeof_struct_if_msghdr_freebsd9
+	sizeofIfMsghdrFreeBSD10 = C.sizeof_struct_if_msghdr_freebsd10
+	sizeofIfMsghdrFreeBSD11 = C.sizeof_struct_if_msghdr_freebsd11
+
+	sizeofIfDataFreeBSD7  = C.sizeof_struct_if_data_freebsd7
+	sizeofIfDataFreeBSD8  = C.sizeof_struct_if_data_freebsd8
+	sizeofIfDataFreeBSD9  = C.sizeof_struct_if_data_freebsd9
+	sizeofIfDataFreeBSD10 = C.sizeof_struct_if_data_freebsd10
+	sizeofIfDataFreeBSD11 = C.sizeof_struct_if_data_freebsd11
+
+	sizeofIfMsghdrlFreeBSD10Emu        = C.sizeof_struct_if_msghdrl
+	sizeofIfaMsghdrFreeBSD10Emu        = C.sizeof_struct_ifa_msghdr
+	sizeofIfaMsghdrlFreeBSD10Emu       = C.sizeof_struct_ifa_msghdrl
+	sizeofIfmaMsghdrFreeBSD10Emu       = C.sizeof_struct_ifma_msghdr
+	sizeofIfAnnouncemsghdrFreeBSD10Emu = C.sizeof_struct_if_announcemsghdr
+
+	sizeofRtMsghdrFreeBSD10Emu  = C.sizeof_struct_rt_msghdr
+	sizeofRtMetricsFreeBSD10Emu = C.sizeof_struct_rt_metrics
+
+	sizeofIfMsghdrFreeBSD7Emu  = C.sizeof_struct_if_msghdr_freebsd7
+	sizeofIfMsghdrFreeBSD8Emu  = C.sizeof_struct_if_msghdr_freebsd8
+	sizeofIfMsghdrFreeBSD9Emu  = C.sizeof_struct_if_msghdr_freebsd9
+	sizeofIfMsghdrFreeBSD10Emu = C.sizeof_struct_if_msghdr_freebsd10
+	sizeofIfMsghdrFreeBSD11Emu = C.sizeof_struct_if_msghdr_freebsd11
+
+	sizeofIfDataFreeBSD7Emu  = C.sizeof_struct_if_data_freebsd7
+	sizeofIfDataFreeBSD8Emu  = C.sizeof_struct_if_data_freebsd8
+	sizeofIfDataFreeBSD9Emu  = C.sizeof_struct_if_data_freebsd9
+	sizeofIfDataFreeBSD10Emu = C.sizeof_struct_if_data_freebsd10
+	sizeofIfDataFreeBSD11Emu = C.sizeof_struct_if_data_freebsd11
+)
diff --git a/src/vendor/golang.org/x/net/route/defs_netbsd.go b/src/vendor/golang.org/x/net/route/defs_netbsd.go
new file mode 100644
index 0000000..b18d85e
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/defs_netbsd.go
@@ -0,0 +1,104 @@
+// Copyright 2016 The Go 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 route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+import "C"
+
+const (
+	sysAF_UNSPEC = C.AF_UNSPEC
+	sysAF_INET   = C.AF_INET
+	sysAF_ROUTE  = C.AF_ROUTE
+	sysAF_LINK   = C.AF_LINK
+	sysAF_INET6  = C.AF_INET6
+
+	sysNET_RT_DUMP   = C.NET_RT_DUMP
+	sysNET_RT_FLAGS  = C.NET_RT_FLAGS
+	sysNET_RT_IFLIST = C.NET_RT_IFLIST
+	sysNET_RT_MAXID  = C.NET_RT_MAXID
+)
+
+const (
+	sysCTL_MAXNAME = C.CTL_MAXNAME
+
+	sysCTL_UNSPEC   = C.CTL_UNSPEC
+	sysCTL_KERN     = C.CTL_KERN
+	sysCTL_VM       = C.CTL_VM
+	sysCTL_VFS      = C.CTL_VFS
+	sysCTL_NET      = C.CTL_NET
+	sysCTL_DEBUG    = C.CTL_DEBUG
+	sysCTL_HW       = C.CTL_HW
+	sysCTL_MACHDEP  = C.CTL_MACHDEP
+	sysCTL_USER     = C.CTL_USER
+	sysCTL_DDB      = C.CTL_DDB
+	sysCTL_PROC     = C.CTL_PROC
+	sysCTL_VENDOR   = C.CTL_VENDOR
+	sysCTL_EMUL     = C.CTL_EMUL
+	sysCTL_SECURITY = C.CTL_SECURITY
+	sysCTL_MAXID    = C.CTL_MAXID
+)
+
+const (
+	sysRTM_VERSION = C.RTM_VERSION
+
+	sysRTM_ADD        = C.RTM_ADD
+	sysRTM_DELETE     = C.RTM_DELETE
+	sysRTM_CHANGE     = C.RTM_CHANGE
+	sysRTM_GET        = C.RTM_GET
+	sysRTM_LOSING     = C.RTM_LOSING
+	sysRTM_REDIRECT   = C.RTM_REDIRECT
+	sysRTM_MISS       = C.RTM_MISS
+	sysRTM_LOCK       = C.RTM_LOCK
+	sysRTM_OLDADD     = C.RTM_OLDADD
+	sysRTM_OLDDEL     = C.RTM_OLDDEL
+	sysRTM_RESOLVE    = C.RTM_RESOLVE
+	sysRTM_NEWADDR    = C.RTM_NEWADDR
+	sysRTM_DELADDR    = C.RTM_DELADDR
+	sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE
+	sysRTM_IEEE80211  = C.RTM_IEEE80211
+	sysRTM_SETGATE    = C.RTM_SETGATE
+	sysRTM_LLINFO_UPD = C.RTM_LLINFO_UPD
+	sysRTM_IFINFO     = C.RTM_IFINFO
+	sysRTM_CHGADDR    = C.RTM_CHGADDR
+
+	sysRTA_DST     = C.RTA_DST
+	sysRTA_GATEWAY = C.RTA_GATEWAY
+	sysRTA_NETMASK = C.RTA_NETMASK
+	sysRTA_GENMASK = C.RTA_GENMASK
+	sysRTA_IFP     = C.RTA_IFP
+	sysRTA_IFA     = C.RTA_IFA
+	sysRTA_AUTHOR  = C.RTA_AUTHOR
+	sysRTA_BRD     = C.RTA_BRD
+	sysRTA_TAG     = C.RTA_TAG
+
+	sysRTAX_DST     = C.RTAX_DST
+	sysRTAX_GATEWAY = C.RTAX_GATEWAY
+	sysRTAX_NETMASK = C.RTAX_NETMASK
+	sysRTAX_GENMASK = C.RTAX_GENMASK
+	sysRTAX_IFP     = C.RTAX_IFP
+	sysRTAX_IFA     = C.RTAX_IFA
+	sysRTAX_AUTHOR  = C.RTAX_AUTHOR
+	sysRTAX_BRD     = C.RTAX_BRD
+	sysRTAX_TAG     = C.RTAX_TAG
+	sysRTAX_MAX     = C.RTAX_MAX
+)
+
+const (
+	sizeofIfMsghdrNetBSD7         = C.sizeof_struct_if_msghdr
+	sizeofIfaMsghdrNetBSD7        = C.sizeof_struct_ifa_msghdr
+	sizeofIfAnnouncemsghdrNetBSD7 = C.sizeof_struct_if_announcemsghdr
+
+	sizeofRtMsghdrNetBSD7  = C.sizeof_struct_rt_msghdr
+	sizeofRtMetricsNetBSD7 = C.sizeof_struct_rt_metrics
+)
diff --git a/src/vendor/golang.org/x/net/route/defs_openbsd.go b/src/vendor/golang.org/x/net/route/defs_openbsd.go
new file mode 100644
index 0000000..5df7a43
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/defs_openbsd.go
@@ -0,0 +1,93 @@
+// Copyright 2016 The Go 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 route
+
+/*
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+*/
+import "C"
+
+const (
+	sysAF_UNSPEC = C.AF_UNSPEC
+	sysAF_INET   = C.AF_INET
+	sysAF_ROUTE  = C.AF_ROUTE
+	sysAF_LINK   = C.AF_LINK
+	sysAF_INET6  = C.AF_INET6
+
+	sysNET_RT_DUMP    = C.NET_RT_DUMP
+	sysNET_RT_FLAGS   = C.NET_RT_FLAGS
+	sysNET_RT_IFLIST  = C.NET_RT_IFLIST
+	sysNET_RT_STATS   = C.NET_RT_STATS
+	sysNET_RT_TABLE   = C.NET_RT_TABLE
+	sysNET_RT_IFNAMES = C.NET_RT_IFNAMES
+	sysNET_RT_MAXID   = C.NET_RT_MAXID
+)
+
+const (
+	sysCTL_MAXNAME = C.CTL_MAXNAME
+
+	sysCTL_UNSPEC  = C.CTL_UNSPEC
+	sysCTL_KERN    = C.CTL_KERN
+	sysCTL_VM      = C.CTL_VM
+	sysCTL_FS      = C.CTL_FS
+	sysCTL_NET     = C.CTL_NET
+	sysCTL_DEBUG   = C.CTL_DEBUG
+	sysCTL_HW      = C.CTL_HW
+	sysCTL_MACHDEP = C.CTL_MACHDEP
+	sysCTL_DDB     = C.CTL_DDB
+	sysCTL_VFS     = C.CTL_VFS
+	sysCTL_MAXID   = C.CTL_MAXID
+)
+
+const (
+	sysRTM_VERSION = C.RTM_VERSION
+
+	sysRTM_ADD        = C.RTM_ADD
+	sysRTM_DELETE     = C.RTM_DELETE
+	sysRTM_CHANGE     = C.RTM_CHANGE
+	sysRTM_GET        = C.RTM_GET
+	sysRTM_LOSING     = C.RTM_LOSING
+	sysRTM_REDIRECT   = C.RTM_REDIRECT
+	sysRTM_MISS       = C.RTM_MISS
+	sysRTM_LOCK       = C.RTM_LOCK
+	sysRTM_RESOLVE    = C.RTM_RESOLVE
+	sysRTM_NEWADDR    = C.RTM_NEWADDR
+	sysRTM_DELADDR    = C.RTM_DELADDR
+	sysRTM_IFINFO     = C.RTM_IFINFO
+	sysRTM_IFANNOUNCE = C.RTM_IFANNOUNCE
+	sysRTM_DESYNC     = C.RTM_DESYNC
+
+	sysRTA_DST     = C.RTA_DST
+	sysRTA_GATEWAY = C.RTA_GATEWAY
+	sysRTA_NETMASK = C.RTA_NETMASK
+	sysRTA_GENMASK = C.RTA_GENMASK
+	sysRTA_IFP     = C.RTA_IFP
+	sysRTA_IFA     = C.RTA_IFA
+	sysRTA_AUTHOR  = C.RTA_AUTHOR
+	sysRTA_BRD     = C.RTA_BRD
+	sysRTA_SRC     = C.RTA_SRC
+	sysRTA_SRCMASK = C.RTA_SRCMASK
+	sysRTA_LABEL   = C.RTA_LABEL
+
+	sysRTAX_DST     = C.RTAX_DST
+	sysRTAX_GATEWAY = C.RTAX_GATEWAY
+	sysRTAX_NETMASK = C.RTAX_NETMASK
+	sysRTAX_GENMASK = C.RTAX_GENMASK
+	sysRTAX_IFP     = C.RTAX_IFP
+	sysRTAX_IFA     = C.RTAX_IFA
+	sysRTAX_AUTHOR  = C.RTAX_AUTHOR
+	sysRTAX_BRD     = C.RTAX_BRD
+	sysRTAX_SRC     = C.RTAX_SRC
+	sysRTAX_SRCMASK = C.RTAX_SRCMASK
+	sysRTAX_LABEL   = C.RTAX_LABEL
+	sysRTAX_MAX     = C.RTAX_MAX
+)
diff --git a/src/vendor/golang.org/x/net/route/interface.go b/src/vendor/golang.org/x/net/route/interface.go
new file mode 100644
index 0000000..854906d
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/interface.go
@@ -0,0 +1,64 @@
+// Copyright 2016 The Go 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 route
+
+// An InterfaceMessage represents an interface message.
+type InterfaceMessage struct {
+	Version int    // message version
+	Type    int    // message type
+	Flags   int    // interface flags
+	Index   int    // interface index
+	Name    string // interface name
+	Addrs   []Addr // addresses
+
+	extOff int    // offset of header extension
+	raw    []byte // raw message
+}
+
+// An InterfaceAddrMessage represents an interface address message.
+type InterfaceAddrMessage struct {
+	Version int    // message version
+	Type    int    // message type
+	Flags   int    // interface flags
+	Index   int    // interface index
+	Addrs   []Addr // addresses
+
+	raw []byte // raw message
+}
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceAddrMessage) Sys() []Sys { return nil }
+
+// An InterfaceMulticastAddrMessage represents an interface multicast
+// address message.
+type InterfaceMulticastAddrMessage struct {
+	Version int    // message version
+	Type    int    // messsage type
+	Flags   int    // interface flags
+	Index   int    // interface index
+	Addrs   []Addr // addresses
+
+	raw []byte // raw message
+}
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMulticastAddrMessage) Sys() []Sys { return nil }
+
+// An InterfaceAnnounceMessage represents an interface announcement
+// message.
+type InterfaceAnnounceMessage struct {
+	Version int    // message version
+	Type    int    // message type
+	Index   int    // interface index
+	Name    string // interface name
+	What    int    // what type of announcement
+
+	raw []byte // raw message
+}
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceAnnounceMessage) Sys() []Sys { return nil }
diff --git a/src/vendor/golang.org/x/net/route/interface_announce.go b/src/vendor/golang.org/x/net/route/interface_announce.go
new file mode 100644
index 0000000..520d657
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/interface_announce.go
@@ -0,0 +1,32 @@
+// Copyright 2016 The Go 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
+
+package route
+
+func (w *wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) {
+	if len(b) < w.bodyOff {
+		return nil, errMessageTooShort
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	m := &InterfaceAnnounceMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Index:   int(nativeEndian.Uint16(b[4:6])),
+		What:    int(nativeEndian.Uint16(b[22:24])),
+		raw:     b[:l],
+	}
+	for i := 0; i < 16; i++ {
+		if b[6+i] != 0 {
+			continue
+		}
+		m.Name = string(b[6 : 6+i])
+		break
+	}
+	return m, nil
+}
diff --git a/src/vendor/golang.org/x/net/route/interface_classic.go b/src/vendor/golang.org/x/net/route/interface_classic.go
new file mode 100644
index 0000000..ac4e7a6
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/interface_classic.go
@@ -0,0 +1,66 @@
+// Copyright 2016 The Go 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 netbsd
+
+package route
+
+import "runtime"
+
+func (w *wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) {
+	if len(b) < w.bodyOff {
+		return nil, errMessageTooShort
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	attrs := uint(nativeEndian.Uint32(b[4:8]))
+	if attrs&sysRTA_IFP == 0 {
+		return nil, nil
+	}
+	m := &InterfaceMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Addrs:   make([]Addr, sysRTAX_MAX),
+		Flags:   int(nativeEndian.Uint32(b[8:12])),
+		Index:   int(nativeEndian.Uint16(b[12:14])),
+		extOff:  w.extOff,
+		raw:     b[:l],
+	}
+	a, err := parseLinkAddr(b[w.bodyOff:])
+	if err != nil {
+		return nil, err
+	}
+	m.Addrs[sysRTAX_IFP] = a
+	m.Name = a.(*LinkAddr).Name
+	return m, nil
+}
+
+func (w *wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, error) {
+	if len(b) < w.bodyOff {
+		return nil, errMessageTooShort
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	m := &InterfaceAddrMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Flags:   int(nativeEndian.Uint32(b[8:12])),
+		raw:     b[:l],
+	}
+	if runtime.GOOS == "netbsd" {
+		m.Index = int(nativeEndian.Uint16(b[16:18]))
+	} else {
+		m.Index = int(nativeEndian.Uint16(b[12:14]))
+	}
+	var err error
+	m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:])
+	if err != nil {
+		return nil, err
+	}
+	return m, nil
+}
diff --git a/src/vendor/golang.org/x/net/route/interface_freebsd.go b/src/vendor/golang.org/x/net/route/interface_freebsd.go
new file mode 100644
index 0000000..c830539
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/interface_freebsd.go
@@ -0,0 +1,78 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+func (w *wireFormat) parseInterfaceMessage(typ RIBType, b []byte) (Message, error) {
+	var extOff, bodyOff int
+	if typ == sysNET_RT_IFLISTL {
+		if len(b) < 20 {
+			return nil, errMessageTooShort
+		}
+		extOff = int(nativeEndian.Uint16(b[18:20]))
+		bodyOff = int(nativeEndian.Uint16(b[16:18]))
+	} else {
+		if len(b) < w.bodyOff {
+			return nil, errMessageTooShort
+		}
+		extOff = w.extOff
+		bodyOff = w.bodyOff
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	attrs := uint(nativeEndian.Uint32(b[4:8]))
+	if attrs&sysRTA_IFP == 0 {
+		return nil, nil
+	}
+	m := &InterfaceMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Flags:   int(nativeEndian.Uint32(b[8:12])),
+		Index:   int(nativeEndian.Uint16(b[12:14])),
+		Addrs:   make([]Addr, sysRTAX_MAX),
+		extOff:  extOff,
+		raw:     b[:l],
+	}
+	a, err := parseLinkAddr(b[bodyOff:])
+	if err != nil {
+		return nil, err
+	}
+	m.Addrs[sysRTAX_IFP] = a
+	m.Name = a.(*LinkAddr).Name
+	return m, nil
+}
+
+func (w *wireFormat) parseInterfaceAddrMessage(typ RIBType, b []byte) (Message, error) {
+	var bodyOff int
+	if typ == sysNET_RT_IFLISTL {
+		if len(b) < 24 {
+			return nil, errMessageTooShort
+		}
+		bodyOff = int(nativeEndian.Uint16(b[16:18]))
+	} else {
+		if len(b) < w.bodyOff {
+			return nil, errMessageTooShort
+		}
+		bodyOff = w.bodyOff
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	m := &InterfaceAddrMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Flags:   int(nativeEndian.Uint32(b[8:12])),
+		Index:   int(nativeEndian.Uint16(b[12:14])),
+		raw:     b[:l],
+	}
+	var err error
+	m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[bodyOff:])
+	if err != nil {
+		return nil, err
+	}
+	return m, nil
+}
diff --git a/src/vendor/golang.org/x/net/route/interface_multicast.go b/src/vendor/golang.org/x/net/route/interface_multicast.go
new file mode 100644
index 0000000..1e99a9c
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/interface_multicast.go
@@ -0,0 +1,30 @@
+// Copyright 2016 The Go 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 route
+
+func (w *wireFormat) parseInterfaceMulticastAddrMessage(_ RIBType, b []byte) (Message, error) {
+	if len(b) < w.bodyOff {
+		return nil, errMessageTooShort
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	m := &InterfaceMulticastAddrMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Flags:   int(nativeEndian.Uint32(b[8:12])),
+		Index:   int(nativeEndian.Uint16(b[12:14])),
+		raw:     b[:l],
+	}
+	var err error
+	m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[4:8])), parseKernelInetAddr, b[w.bodyOff:])
+	if err != nil {
+		return nil, err
+	}
+	return m, nil
+}
diff --git a/src/vendor/golang.org/x/net/route/interface_openbsd.go b/src/vendor/golang.org/x/net/route/interface_openbsd.go
new file mode 100644
index 0000000..24451d8
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/interface_openbsd.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+func (*wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) {
+	if len(b) < 32 {
+		return nil, errMessageTooShort
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	attrs := uint(nativeEndian.Uint32(b[12:16]))
+	if attrs&sysRTA_IFP == 0 {
+		return nil, nil
+	}
+	m := &InterfaceMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Flags:   int(nativeEndian.Uint32(b[16:20])),
+		Index:   int(nativeEndian.Uint16(b[6:8])),
+		Addrs:   make([]Addr, sysRTAX_MAX),
+		raw:     b[:l],
+	}
+	a, err := parseLinkAddr(b[int(nativeEndian.Uint16(b[4:6])):])
+	if err != nil {
+		return nil, err
+	}
+	m.Addrs[sysRTAX_IFP] = a
+	m.Name = a.(*LinkAddr).Name
+	return m, nil
+}
+
+func (*wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, error) {
+	if len(b) < 24 {
+		return nil, errMessageTooShort
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	bodyOff := int(nativeEndian.Uint16(b[4:6]))
+	m := &InterfaceAddrMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Flags:   int(nativeEndian.Uint32(b[12:16])),
+		Index:   int(nativeEndian.Uint16(b[6:8])),
+		raw:     b[:l],
+	}
+	var err error
+	m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[bodyOff:])
+	if err != nil {
+		return nil, err
+	}
+	return m, nil
+}
+
+func (*wireFormat) parseInterfaceAnnounceMessage(_ RIBType, b []byte) (Message, error) {
+	if len(b) < 26 {
+		return nil, errMessageTooShort
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	m := &InterfaceAnnounceMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Index:   int(nativeEndian.Uint16(b[6:8])),
+		What:    int(nativeEndian.Uint16(b[8:10])),
+		raw:     b[:l],
+	}
+	for i := 0; i < 16; i++ {
+		if b[10+i] != 0 {
+			continue
+		}
+		m.Name = string(b[10 : 10+i])
+		break
+	}
+	return m, nil
+}
diff --git a/src/vendor/golang.org/x/net/route/message.go b/src/vendor/golang.org/x/net/route/message.go
new file mode 100644
index 0000000..27cbf6b
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/message.go
@@ -0,0 +1,70 @@
+// Copyright 2016 The Go 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 route
+
+// A Message represents a routing message.
+//
+// Note: This interface will be changed to support Marshal method in
+// future version.
+type Message interface {
+	// Sys returns operating system-specific information.
+	Sys() []Sys
+}
+
+// A Sys reprensents operating system-specific information.
+type Sys interface {
+	// SysType returns a type of operating system-specific
+	// information.
+	SysType() SysType
+}
+
+// A SysType represents a type of operating system-specific
+// information.
+type SysType int
+
+const (
+	SysMetrics SysType = iota
+	SysStats
+)
+
+// ParseRIB parses b as a routing information base and returns a list
+// of routing messages.
+func ParseRIB(typ RIBType, b []byte) ([]Message, error) {
+	if !typ.parseable() {
+		return nil, errUnsupportedMessage
+	}
+	var msgs []Message
+	nmsgs, nskips := 0, 0
+	for len(b) > 4 {
+		nmsgs++
+		l := int(nativeEndian.Uint16(b[:2]))
+		if b[2] != sysRTM_VERSION {
+			b = b[l:]
+			continue
+		}
+		mtyp := int(b[3])
+		if fn, ok := parseFns[mtyp]; !ok {
+			nskips++
+		} else {
+			m, err := fn(typ, b)
+			if err != nil {
+				return nil, err
+			}
+			if m == nil {
+				nskips++
+			} else {
+				msgs = append(msgs, m)
+			}
+		}
+		b = b[l:]
+	}
+	// We failed to parse any of the messages - version mismatch?
+	if nmsgs != len(msgs)+nskips {
+		return nil, errMessageMismatch
+	}
+	return msgs, nil
+}
diff --git a/src/vendor/golang.org/x/net/route/message_darwin_test.go b/src/vendor/golang.org/x/net/route/message_darwin_test.go
new file mode 100644
index 0000000..3fdd12d
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/message_darwin_test.go
@@ -0,0 +1,27 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import "testing"
+
+func TestFetchAndParseRIBOnDarwin(t *testing.T) {
+	for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+		for _, typ := range []RIBType{sysNET_RT_FLAGS, sysNET_RT_DUMP2, sysNET_RT_IFLIST2} {
+			ms, err := fetchAndParseRIB(af, typ)
+			if err != nil {
+				t.Error(err)
+				continue
+			}
+			ss, err := msgs(ms).validate()
+			if err != nil {
+				t.Errorf("%v %d %v", addrFamily(af), typ, err)
+				continue
+			}
+			for _, s := range ss {
+				t.Log(s)
+			}
+		}
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/message_freebsd_test.go b/src/vendor/golang.org/x/net/route/message_freebsd_test.go
new file mode 100644
index 0000000..785c273
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/message_freebsd_test.go
@@ -0,0 +1,106 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import (
+	"testing"
+	"time"
+	"unsafe"
+)
+
+func TestFetchAndParseRIBOnFreeBSD(t *testing.T) {
+	for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+		for _, typ := range []RIBType{sysNET_RT_IFMALIST} {
+			ms, err := fetchAndParseRIB(af, typ)
+			if err != nil {
+				t.Error(err)
+				continue
+			}
+			ss, err := msgs(ms).validate()
+			if err != nil {
+				t.Errorf("%v %d %v", addrFamily(af), typ, err)
+				continue
+			}
+			for _, s := range ss {
+				t.Log(s)
+			}
+		}
+	}
+}
+
+func TestFetchAndParseRIBOnFreeBSD10AndAbove(t *testing.T) {
+	if _, err := FetchRIB(sysAF_UNSPEC, sysNET_RT_IFLISTL, 0); err != nil {
+		t.Skip("NET_RT_IFLISTL not supported")
+	}
+	var p uintptr
+	if kernelAlign != int(unsafe.Sizeof(p)) {
+		t.Skip("NET_RT_IFLIST vs. NET_RT_IFLISTL doesn't work for 386 emulation on amd64")
+	}
+
+	var tests = [2]struct {
+		typ  RIBType
+		b    []byte
+		msgs []Message
+		ss   []string
+	}{
+		{typ: sysNET_RT_IFLIST},
+		{typ: sysNET_RT_IFLISTL},
+	}
+	for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+		var lastErr error
+		for i := 0; i < 3; i++ {
+			for j := range tests {
+				var err error
+				if tests[j].b, err = FetchRIB(af, tests[j].typ, 0); err != nil {
+					lastErr = err
+					time.Sleep(10 * time.Millisecond)
+				}
+			}
+			if lastErr == nil {
+				break
+			}
+		}
+		if lastErr != nil {
+			t.Error(af, lastErr)
+			continue
+		}
+		for i := range tests {
+			var err error
+			if tests[i].msgs, err = ParseRIB(tests[i].typ, tests[i].b); err != nil {
+				lastErr = err
+				t.Error(af, err)
+			}
+		}
+		if lastErr != nil {
+			continue
+		}
+		for i := range tests {
+			var err error
+			tests[i].ss, err = msgs(tests[i].msgs).validate()
+			if err != nil {
+				lastErr = err
+				t.Error(af, err)
+			}
+			for _, s := range tests[i].ss {
+				t.Log(s)
+			}
+		}
+		if lastErr != nil {
+			continue
+		}
+		for i := len(tests) - 1; i > 0; i-- {
+			if len(tests[i].ss) != len(tests[i-1].ss) {
+				t.Errorf("got %v; want %v", tests[i].ss, tests[i-1].ss)
+				continue
+			}
+			for j, s1 := range tests[i].ss {
+				s0 := tests[i-1].ss[j]
+				if s1 != s0 {
+					t.Errorf("got %s; want %s", s1, s0)
+				}
+			}
+		}
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/message_test.go b/src/vendor/golang.org/x/net/route/message_test.go
new file mode 100644
index 0000000..a1263d8
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/message_test.go
@@ -0,0 +1,95 @@
+// Copyright 2016 The Go 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 route
+
+import (
+	"os"
+	"syscall"
+	"testing"
+	"time"
+)
+
+func TestFetchAndParseRIB(t *testing.T) {
+	for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+		for _, typ := range []RIBType{sysNET_RT_DUMP, sysNET_RT_IFLIST} {
+			ms, err := fetchAndParseRIB(af, typ)
+			if err != nil {
+				t.Error(err)
+				continue
+			}
+			ss, err := msgs(ms).validate()
+			if err != nil {
+				t.Errorf("%v %d %v", addrFamily(af), typ, err)
+				continue
+			}
+			for _, s := range ss {
+				t.Log(s)
+			}
+		}
+	}
+}
+
+func TestMonitorAndParseRIB(t *testing.T) {
+	if testing.Short() || os.Getuid() != 0 {
+		t.Skip("must be root")
+	}
+
+	// We suppose that using an IPv4 link-local address and the
+	// dot1Q ID for Token Ring and FDDI doesn't harm anyone.
+	pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"}
+	if err := pv.configure(1002); err != nil {
+		t.Skip(err)
+	}
+	if err := pv.setup(); err != nil {
+		t.Skip(err)
+	}
+	pv.teardown()
+
+	s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer syscall.Close(s)
+
+	go func() {
+		b := make([]byte, os.Getpagesize())
+		for {
+			n, err := syscall.Read(s, b)
+			if err != nil {
+				return
+			}
+			ms, err := ParseRIB(0, b[:n])
+			if err != nil {
+				t.Error(err)
+				return
+			}
+			ss, err := msgs(ms).validate()
+			if err != nil {
+				t.Error(err)
+				return
+			}
+			for _, s := range ss {
+				t.Log(s)
+			}
+		}
+	}()
+
+	for _, vid := range []int{1002, 1003, 1004, 1005} {
+		pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"}
+		if err := pv.configure(vid); err != nil {
+			t.Fatal(err)
+		}
+		if err := pv.setup(); err != nil {
+			t.Fatal(err)
+		}
+		time.Sleep(200 * time.Millisecond)
+		if err := pv.teardown(); err != nil {
+			t.Fatal(err)
+		}
+		time.Sleep(200 * time.Millisecond)
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/route.go b/src/vendor/golang.org/x/net/route/route.go
new file mode 100644
index 0000000..c986e29
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/route.go
@@ -0,0 +1,74 @@
+// Copyright 2016 The Go 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 route provides basic functions for the manipulation of
+// packet routing facilities on BSD variants.
+//
+// The package supports any version of Darwin, any version of
+// DragonFly BSD, FreeBSD 7 through 11, NetBSD 6 and above, and
+// OpenBSD 5.6 and above.
+package route
+
+import (
+	"errors"
+	"os"
+	"syscall"
+)
+
+var (
+	errUnsupportedMessage = errors.New("unsupported message")
+	errMessageMismatch    = errors.New("message mismatch")
+	errMessageTooShort    = errors.New("message too short")
+	errInvalidMessage     = errors.New("invalid message")
+	errInvalidAddr        = errors.New("invalid address")
+)
+
+// A RouteMessage represents a message conveying an address prefix, a
+// nexthop address and an output interface.
+type RouteMessage struct {
+	Version int    // message version
+	Type    int    // message type
+	Flags   int    // route flags
+	Index   int    // interface index when atatched
+	Addrs   []Addr // addresses
+
+	extOff int    // offset of header extension
+	raw    []byte // raw message
+}
+
+// A RIBType reprensents a type of routing information base.
+type RIBType int
+
+const (
+	RIBTypeRoute     RIBType = syscall.NET_RT_DUMP
+	RIBTypeInterface RIBType = syscall.NET_RT_IFLIST
+)
+
+// FetchRIB fetches a routing information base from the operating
+// system.
+//
+// The provided af must be an address family.
+//
+// The provided arg must be a RIBType-specific argument.
+// When RIBType is related to routes, arg might be a set of route
+// flags. When RIBType is related to network interfaces, arg might be
+// an interface index or a set of interface flags. In most cases, zero
+// means a wildcard.
+func FetchRIB(af int, typ RIBType, arg int) ([]byte, error) {
+	mib := [6]int32{sysCTL_NET, sysAF_ROUTE, 0, int32(af), int32(typ), int32(arg)}
+	n := uintptr(0)
+	if err := sysctl(mib[:], nil, &n, nil, 0); err != nil {
+		return nil, os.NewSyscallError("sysctl", err)
+	}
+	if n == 0 {
+		return nil, nil
+	}
+	b := make([]byte, n)
+	if err := sysctl(mib[:], &b[0], &n, nil, 0); err != nil {
+		return nil, os.NewSyscallError("sysctl", err)
+	}
+	return b[:n], nil
+}
diff --git a/src/vendor/golang.org/x/net/route/route_classic.go b/src/vendor/golang.org/x/net/route/route_classic.go
new file mode 100644
index 0000000..d333c6a
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/route_classic.go
@@ -0,0 +1,31 @@
+// Copyright 2016 The Go 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
+
+package route
+
+func (w *wireFormat) parseRouteMessage(typ RIBType, b []byte) (Message, error) {
+	if len(b) < w.bodyOff {
+		return nil, errMessageTooShort
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	m := &RouteMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Flags:   int(nativeEndian.Uint32(b[8:12])),
+		Index:   int(nativeEndian.Uint16(b[4:6])),
+		extOff:  w.extOff,
+		raw:     b[:l],
+	}
+	var err error
+	m.Addrs, err = parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[w.bodyOff:])
+	if err != nil {
+		return nil, err
+	}
+	return m, nil
+}
diff --git a/src/vendor/golang.org/x/net/route/route_openbsd.go b/src/vendor/golang.org/x/net/route/route_openbsd.go
new file mode 100644
index 0000000..b07862f
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/route_openbsd.go
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+func (*wireFormat) parseRouteMessage(_ RIBType, b []byte) (Message, error) {
+	if len(b) < 40 {
+		return nil, errMessageTooShort
+	}
+	l := int(nativeEndian.Uint16(b[:2]))
+	if len(b) < l {
+		return nil, errInvalidMessage
+	}
+	m := &RouteMessage{
+		Version: int(b[2]),
+		Type:    int(b[3]),
+		Flags:   int(nativeEndian.Uint32(b[16:20])),
+		Index:   int(nativeEndian.Uint16(b[6:8])),
+		raw:     b[:l],
+	}
+	as, err := parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[int(nativeEndian.Uint16(b[4:6])):])
+	if err != nil {
+		return nil, err
+	}
+	m.Addrs = as
+	return m, nil
+}
diff --git a/src/vendor/golang.org/x/net/route/route_test.go b/src/vendor/golang.org/x/net/route/route_test.go
new file mode 100644
index 0000000..99f57b7
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/route_test.go
@@ -0,0 +1,385 @@
+// Copyright 2016 The Go 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 route
+
+import (
+	"fmt"
+	"os/exec"
+	"runtime"
+	"time"
+)
+
+func (m *RouteMessage) String() string {
+	return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[12:16])))
+}
+
+func (m *InterfaceMessage) String() string {
+	var attrs addrAttrs
+	if runtime.GOOS == "openbsd" {
+		attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
+	} else {
+		attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
+	}
+	return fmt.Sprintf("%s", attrs)
+}
+
+func (m *InterfaceAddrMessage) String() string {
+	var attrs addrAttrs
+	if runtime.GOOS == "openbsd" {
+		attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
+	} else {
+		attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
+	}
+	return fmt.Sprintf("%s", attrs)
+}
+
+func (m *InterfaceMulticastAddrMessage) String() string {
+	return fmt.Sprintf("%s", addrAttrs(nativeEndian.Uint32(m.raw[4:8])))
+}
+
+func (m *InterfaceAnnounceMessage) String() string {
+	what := "<nil>"
+	switch m.What {
+	case 0:
+		what = "arrival"
+	case 1:
+		what = "departure"
+	}
+	return fmt.Sprintf("(%d %s %s)", m.Index, m.Name, what)
+}
+
+func (m *InterfaceMetrics) String() string {
+	return fmt.Sprintf("(type=%d mtu=%d)", m.Type, m.MTU)
+}
+
+func (m *RouteMetrics) String() string {
+	return fmt.Sprintf("(pmtu=%d)", m.PathMTU)
+}
+
+type addrAttrs uint
+
+var addrAttrNames = [...]string{
+	"dst",
+	"gateway",
+	"netmask",
+	"genmask",
+	"ifp",
+	"ifa",
+	"author",
+	"brd",
+	"df:mpls1-n:tag-o:src", // mpls1 for dragonfly, tag for netbsd, src for openbsd
+	"df:mpls2-o:srcmask",   // mpls2 for dragonfly, srcmask for openbsd
+	"df:mpls3-o:label",     // mpls3 for dragonfly, label for openbsd
+}
+
+func (attrs addrAttrs) String() string {
+	var s string
+	for i, name := range addrAttrNames {
+		if attrs&(1<<uint(i)) != 0 {
+			if s != "" {
+				s += "|"
+			}
+			s += name
+		}
+	}
+	if s == "" {
+		return "<nil>"
+	}
+	return s
+}
+
+type msgs []Message
+
+func (ms msgs) validate() ([]string, error) {
+	var ss []string
+	for _, m := range ms {
+		switch m := m.(type) {
+		case *RouteMessage:
+			if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[12:16]))); err != nil {
+				return nil, err
+			}
+			sys := m.Sys()
+			if sys == nil {
+				return nil, fmt.Errorf("no sys for %s", m.String())
+			}
+			ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String())
+		case *InterfaceMessage:
+			var attrs addrAttrs
+			if runtime.GOOS == "openbsd" {
+				attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
+			} else {
+				attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
+			}
+			if err := addrs(m.Addrs).match(attrs); err != nil {
+				return nil, err
+			}
+			sys := m.Sys()
+			if sys == nil {
+				return nil, fmt.Errorf("no sys for %s", m.String())
+			}
+			ss = append(ss, m.String()+" "+syss(sys).String()+" "+addrs(m.Addrs).String())
+		case *InterfaceAddrMessage:
+			var attrs addrAttrs
+			if runtime.GOOS == "openbsd" {
+				attrs = addrAttrs(nativeEndian.Uint32(m.raw[12:16]))
+			} else {
+				attrs = addrAttrs(nativeEndian.Uint32(m.raw[4:8]))
+			}
+			if err := addrs(m.Addrs).match(attrs); err != nil {
+				return nil, err
+			}
+			ss = append(ss, m.String()+" "+addrs(m.Addrs).String())
+		case *InterfaceMulticastAddrMessage:
+			if err := addrs(m.Addrs).match(addrAttrs(nativeEndian.Uint32(m.raw[4:8]))); err != nil {
+				return nil, err
+			}
+			ss = append(ss, m.String()+" "+addrs(m.Addrs).String())
+		case *InterfaceAnnounceMessage:
+			ss = append(ss, m.String())
+		default:
+			ss = append(ss, fmt.Sprintf("%+v", m))
+		}
+	}
+	return ss, nil
+}
+
+type syss []Sys
+
+func (sys syss) String() string {
+	var s string
+	for _, sy := range sys {
+		switch sy := sy.(type) {
+		case *InterfaceMetrics:
+			if len(s) > 0 {
+				s += " "
+			}
+			s += sy.String()
+		case *RouteMetrics:
+			if len(s) > 0 {
+				s += " "
+			}
+			s += sy.String()
+		}
+	}
+	return s
+}
+
+type addrFamily int
+
+func (af addrFamily) String() string {
+	switch af {
+	case sysAF_UNSPEC:
+		return "unspec"
+	case sysAF_LINK:
+		return "link"
+	case sysAF_INET:
+		return "inet4"
+	case sysAF_INET6:
+		return "inet6"
+	default:
+		return fmt.Sprintf("%d", af)
+	}
+}
+
+const hexDigit = "0123456789abcdef"
+
+type llAddr []byte
+
+func (a llAddr) String() string {
+	if len(a) == 0 {
+		return ""
+	}
+	buf := make([]byte, 0, len(a)*3-1)
+	for i, b := range a {
+		if i > 0 {
+			buf = append(buf, ':')
+		}
+		buf = append(buf, hexDigit[b>>4])
+		buf = append(buf, hexDigit[b&0xF])
+	}
+	return string(buf)
+}
+
+type ipAddr []byte
+
+func (a ipAddr) String() string {
+	if len(a) == 0 {
+		return "<nil>"
+	}
+	if len(a) == 4 {
+		return fmt.Sprintf("%d.%d.%d.%d", a[0], a[1], a[2], a[3])
+	}
+	if len(a) == 16 {
+		return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", 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])
+	}
+	s := make([]byte, len(a)*2)
+	for i, tn := range a {
+		s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf]
+	}
+	return string(s)
+}
+
+func (a *LinkAddr) String() string {
+	name := a.Name
+	if name == "" {
+		name = "<nil>"
+	}
+	lla := llAddr(a.Addr).String()
+	if lla == "" {
+		lla = "<nil>"
+	}
+	return fmt.Sprintf("(%v %d %s %s)", addrFamily(a.Family()), a.Index, name, lla)
+}
+
+func (a Inet4Addr) String() string {
+	return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), ipAddr(a.IP[:]))
+}
+
+func (a *Inet6Addr) String() string {
+	return fmt.Sprintf("(%v %v %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.ZoneID)
+}
+
+func (a *DefaultAddr) String() string {
+	return fmt.Sprintf("(%v %s)", addrFamily(a.Family()), ipAddr(a.Raw[2:]).String())
+}
+
+type addrs []Addr
+
+func (as addrs) String() string {
+	var s string
+	for _, a := range as {
+		if a == nil {
+			continue
+		}
+		if len(s) > 0 {
+			s += " "
+		}
+		switch a := a.(type) {
+		case *LinkAddr:
+			s += a.String()
+		case *Inet4Addr:
+			s += a.String()
+		case *Inet6Addr:
+			s += a.String()
+		case *DefaultAddr:
+			s += a.String()
+		}
+	}
+	if s == "" {
+		return "<nil>"
+	}
+	return s
+}
+
+func (as addrs) match(attrs addrAttrs) error {
+	var ts addrAttrs
+	af := sysAF_UNSPEC
+	for i := range as {
+		if as[i] != nil {
+			ts |= 1 << uint(i)
+		}
+		switch as[i].(type) {
+		case *Inet4Addr:
+			if af == sysAF_UNSPEC {
+				af = sysAF_INET
+			}
+			if af != sysAF_INET {
+				return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af))
+			}
+		case *Inet6Addr:
+			if af == sysAF_UNSPEC {
+				af = sysAF_INET6
+			}
+			if af != sysAF_INET6 {
+				return fmt.Errorf("got %v; want %v", addrs(as), addrFamily(af))
+			}
+		}
+	}
+	if ts != attrs && ts > attrs {
+		return fmt.Errorf("%v not included in %v", ts, attrs)
+	}
+	return nil
+}
+
+func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) {
+	var err error
+	var b []byte
+	for i := 0; i < 3; i++ {
+		if b, err = FetchRIB(af, typ, 0); err != nil {
+			time.Sleep(10 * time.Millisecond)
+			continue
+		}
+		break
+	}
+	if err != nil {
+		return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err)
+	}
+	ms, err := ParseRIB(typ, b)
+	if err != nil {
+		return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err)
+	}
+	return ms, nil
+}
+
+type propVirtual struct {
+	name         string
+	addr, mask   string
+	setupCmds    []*exec.Cmd
+	teardownCmds []*exec.Cmd
+}
+
+func (ti *propVirtual) setup() error {
+	for _, cmd := range ti.setupCmds {
+		if err := cmd.Run(); err != nil {
+			ti.teardown()
+			return err
+		}
+	}
+	return nil
+}
+
+func (ti *propVirtual) teardown() error {
+	for _, cmd := range ti.teardownCmds {
+		if err := cmd.Run(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (ti *propVirtual) configure(suffix int) error {
+	if runtime.GOOS == "openbsd" {
+		ti.name = fmt.Sprintf("vether%d", suffix)
+	} else {
+		ti.name = fmt.Sprintf("vlan%d", suffix)
+	}
+	xname, err := exec.LookPath("ifconfig")
+	if err != nil {
+		return err
+	}
+	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+		Path: xname,
+		Args: []string{"ifconfig", ti.name, "create"},
+	})
+	if runtime.GOOS == "netbsd" {
+		// NetBSD requires an underlying dot1Q-capable network
+		// interface.
+		ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+			Path: xname,
+			Args: []string{"ifconfig", ti.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"},
+		})
+	}
+	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+		Path: xname,
+		Args: []string{"ifconfig", ti.name, "inet", ti.addr, "netmask", ti.mask},
+	})
+	ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
+		Path: xname,
+		Args: []string{"ifconfig", ti.name, "destroy"},
+	})
+	return nil
+}
diff --git a/src/vendor/golang.org/x/net/route/sys.go b/src/vendor/golang.org/x/net/route/sys.go
new file mode 100644
index 0000000..80ca83a
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/sys.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go 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 route
+
+import "unsafe"
+
+var (
+	nativeEndian binaryByteOrder
+	kernelAlign  int
+	parseFns     map[int]parseFn
+)
+
+func init() {
+	i := uint32(1)
+	b := (*[4]byte)(unsafe.Pointer(&i))
+	if b[0] == 1 {
+		nativeEndian = littleEndian
+	} else {
+		nativeEndian = bigEndian
+	}
+	kernelAlign, parseFns = probeRoutingStack()
+}
+
+func roundup(l int) int {
+	if l == 0 {
+		return kernelAlign
+	}
+	return (l + kernelAlign - 1) & ^(kernelAlign - 1)
+}
+
+type parseFn func(RIBType, []byte) (Message, error)
+
+type wireFormat struct {
+	extOff  int // offset of header extension
+	bodyOff int // offset of message body
+}
diff --git a/src/vendor/golang.org/x/net/route/sys_darwin.go b/src/vendor/golang.org/x/net/route/sys_darwin.go
new file mode 100644
index 0000000..fff3a0f
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/sys_darwin.go
@@ -0,0 +1,80 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+func (typ RIBType) parseable() bool {
+	switch typ {
+	case sysNET_RT_STAT, sysNET_RT_TRASH:
+		return false
+	default:
+		return true
+	}
+}
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+	PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+	return []Sys{
+		&RouteMetrics{
+			PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])),
+		},
+	}
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+	Type int // interface type
+	MTU  int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+	return []Sys{
+		&InterfaceMetrics{
+			Type: int(m.raw[m.extOff]),
+			MTU:  int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+		},
+	}
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+	rtm := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdrDarwin15}
+	rtm2 := &wireFormat{extOff: 36, bodyOff: sizeofRtMsghdr2Darwin15}
+	ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDarwin15}
+	ifm2 := &wireFormat{extOff: 32, bodyOff: sizeofIfMsghdr2Darwin15}
+	ifam := &wireFormat{extOff: sizeofIfaMsghdrDarwin15, bodyOff: sizeofIfaMsghdrDarwin15}
+	ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDarwin15, bodyOff: sizeofIfmaMsghdrDarwin15}
+	ifmam2 := &wireFormat{extOff: sizeofIfmaMsghdr2Darwin15, bodyOff: sizeofIfmaMsghdr2Darwin15}
+	// Darwin kernels require 32-bit aligned access to routing facilities.
+	return 4, map[int]parseFn{
+		sysRTM_ADD:       rtm.parseRouteMessage,
+		sysRTM_DELETE:    rtm.parseRouteMessage,
+		sysRTM_CHANGE:    rtm.parseRouteMessage,
+		sysRTM_GET:       rtm.parseRouteMessage,
+		sysRTM_LOSING:    rtm.parseRouteMessage,
+		sysRTM_REDIRECT:  rtm.parseRouteMessage,
+		sysRTM_MISS:      rtm.parseRouteMessage,
+		sysRTM_LOCK:      rtm.parseRouteMessage,
+		sysRTM_RESOLVE:   rtm.parseRouteMessage,
+		sysRTM_NEWADDR:   ifam.parseInterfaceAddrMessage,
+		sysRTM_DELADDR:   ifam.parseInterfaceAddrMessage,
+		sysRTM_IFINFO:    ifm.parseInterfaceMessage,
+		sysRTM_NEWMADDR:  ifmam.parseInterfaceMulticastAddrMessage,
+		sysRTM_DELMADDR:  ifmam.parseInterfaceMulticastAddrMessage,
+		sysRTM_IFINFO2:   ifm2.parseInterfaceMessage,
+		sysRTM_NEWMADDR2: ifmam2.parseInterfaceMulticastAddrMessage,
+		sysRTM_GET2:      rtm2.parseRouteMessage,
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/sys_dragonfly.go b/src/vendor/golang.org/x/net/route/sys_dragonfly.go
new file mode 100644
index 0000000..da848b3
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/sys_dragonfly.go
@@ -0,0 +1,71 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import "unsafe"
+
+func (typ RIBType) parseable() bool { return true }
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+	PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+	return []Sys{
+		&RouteMetrics{
+			PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
+		},
+	}
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+	Type int // interface type
+	MTU  int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+	return []Sys{
+		&InterfaceMetrics{
+			Type: int(m.raw[m.extOff]),
+			MTU:  int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+		},
+	}
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+	var p uintptr
+	rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrDragonFlyBSD4}
+	ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrDragonFlyBSD4}
+	ifam := &wireFormat{extOff: sizeofIfaMsghdrDragonFlyBSD4, bodyOff: sizeofIfaMsghdrDragonFlyBSD4}
+	ifmam := &wireFormat{extOff: sizeofIfmaMsghdrDragonFlyBSD4, bodyOff: sizeofIfmaMsghdrDragonFlyBSD4}
+	ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrDragonFlyBSD4, bodyOff: sizeofIfAnnouncemsghdrDragonFlyBSD4}
+	return int(unsafe.Sizeof(p)), map[int]parseFn{
+		sysRTM_ADD:        rtm.parseRouteMessage,
+		sysRTM_DELETE:     rtm.parseRouteMessage,
+		sysRTM_CHANGE:     rtm.parseRouteMessage,
+		sysRTM_GET:        rtm.parseRouteMessage,
+		sysRTM_LOSING:     rtm.parseRouteMessage,
+		sysRTM_REDIRECT:   rtm.parseRouteMessage,
+		sysRTM_MISS:       rtm.parseRouteMessage,
+		sysRTM_LOCK:       rtm.parseRouteMessage,
+		sysRTM_RESOLVE:    rtm.parseRouteMessage,
+		sysRTM_NEWADDR:    ifam.parseInterfaceAddrMessage,
+		sysRTM_DELADDR:    ifam.parseInterfaceAddrMessage,
+		sysRTM_IFINFO:     ifm.parseInterfaceMessage,
+		sysRTM_NEWMADDR:   ifmam.parseInterfaceMulticastAddrMessage,
+		sysRTM_DELMADDR:   ifmam.parseInterfaceMulticastAddrMessage,
+		sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage,
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/sys_freebsd.go b/src/vendor/golang.org/x/net/route/sys_freebsd.go
new file mode 100644
index 0000000..7b05c1a
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/sys_freebsd.go
@@ -0,0 +1,150 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+func (typ RIBType) parseable() bool { return true }
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+	PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+	if kernelAlign == 8 {
+		return []Sys{
+			&RouteMetrics{
+				PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
+			},
+		}
+	}
+	return []Sys{
+		&RouteMetrics{
+			PathMTU: int(nativeEndian.Uint32(m.raw[m.extOff+4 : m.extOff+8])),
+		},
+	}
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+	Type int // interface type
+	MTU  int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+	return []Sys{
+		&InterfaceMetrics{
+			Type: int(m.raw[m.extOff]),
+			MTU:  int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+		},
+	}
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+	var p uintptr
+	wordSize := int(unsafe.Sizeof(p))
+	align := int(unsafe.Sizeof(p))
+	// 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.
+	conf, _ := syscall.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
+			}
+			if s == "amd64" {
+				align = 8
+			}
+			break
+		}
+	}
+	var rtm, ifm, ifam, ifmam, ifanm *wireFormat
+	if align != wordSize { // 386 emulation on amd64
+		rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10Emu - sizeofRtMetricsFreeBSD10Emu, bodyOff: sizeofRtMsghdrFreeBSD10Emu}
+		ifm = &wireFormat{extOff: 16}
+		ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10Emu, bodyOff: sizeofIfaMsghdrFreeBSD10Emu}
+		ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10Emu, bodyOff: sizeofIfmaMsghdrFreeBSD10Emu}
+		ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10Emu, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10Emu}
+	} else {
+		rtm = &wireFormat{extOff: sizeofRtMsghdrFreeBSD10 - sizeofRtMetricsFreeBSD10, bodyOff: sizeofRtMsghdrFreeBSD10}
+		ifm = &wireFormat{extOff: 16}
+		ifam = &wireFormat{extOff: sizeofIfaMsghdrFreeBSD10, bodyOff: sizeofIfaMsghdrFreeBSD10}
+		ifmam = &wireFormat{extOff: sizeofIfmaMsghdrFreeBSD10, bodyOff: sizeofIfmaMsghdrFreeBSD10}
+		ifanm = &wireFormat{extOff: sizeofIfAnnouncemsghdrFreeBSD10, bodyOff: sizeofIfAnnouncemsghdrFreeBSD10}
+	}
+	rel, _ := syscall.SysctlUint32("kern.osreldate")
+	switch {
+	case rel < 800000:
+		if align != wordSize { // 386 emulation on amd64
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD7Emu
+		} else {
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD7
+		}
+	case 800000 <= rel && rel < 900000:
+		if align != wordSize { // 386 emulation on amd64
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD8Emu
+		} else {
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD8
+		}
+	case 900000 <= rel && rel < 1000000:
+		if align != wordSize { // 386 emulation on amd64
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD9Emu
+		} else {
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD9
+		}
+	case 1000000 <= rel && rel < 1100000:
+		if align != wordSize { // 386 emulation on amd64
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD10Emu
+		} else {
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD10
+		}
+	default:
+		if align != wordSize { // 386 emulation on amd64
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD11Emu
+		} else {
+			ifm.bodyOff = sizeofIfMsghdrFreeBSD11
+		}
+	}
+	return align, map[int]parseFn{
+		sysRTM_ADD:        rtm.parseRouteMessage,
+		sysRTM_DELETE:     rtm.parseRouteMessage,
+		sysRTM_CHANGE:     rtm.parseRouteMessage,
+		sysRTM_GET:        rtm.parseRouteMessage,
+		sysRTM_LOSING:     rtm.parseRouteMessage,
+		sysRTM_REDIRECT:   rtm.parseRouteMessage,
+		sysRTM_MISS:       rtm.parseRouteMessage,
+		sysRTM_LOCK:       rtm.parseRouteMessage,
+		sysRTM_RESOLVE:    rtm.parseRouteMessage,
+		sysRTM_NEWADDR:    ifam.parseInterfaceAddrMessage,
+		sysRTM_DELADDR:    ifam.parseInterfaceAddrMessage,
+		sysRTM_IFINFO:     ifm.parseInterfaceMessage,
+		sysRTM_NEWMADDR:   ifmam.parseInterfaceMulticastAddrMessage,
+		sysRTM_DELMADDR:   ifmam.parseInterfaceMulticastAddrMessage,
+		sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage,
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/sys_netbsd.go b/src/vendor/golang.org/x/net/route/sys_netbsd.go
new file mode 100644
index 0000000..4d8076b
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/sys_netbsd.go
@@ -0,0 +1,67 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+func (typ RIBType) parseable() bool { return true }
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+	PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+	return []Sys{
+		&RouteMetrics{
+			PathMTU: int(nativeEndian.Uint64(m.raw[m.extOff+8 : m.extOff+16])),
+		},
+	}
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+	Type int // interface type
+	MTU  int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+	return []Sys{
+		&InterfaceMetrics{
+			Type: int(m.raw[m.extOff]),
+			MTU:  int(nativeEndian.Uint32(m.raw[m.extOff+8 : m.extOff+12])),
+		},
+	}
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+	rtm := &wireFormat{extOff: 40, bodyOff: sizeofRtMsghdrNetBSD7}
+	ifm := &wireFormat{extOff: 16, bodyOff: sizeofIfMsghdrNetBSD7}
+	ifam := &wireFormat{extOff: sizeofIfaMsghdrNetBSD7, bodyOff: sizeofIfaMsghdrNetBSD7}
+	ifanm := &wireFormat{extOff: sizeofIfAnnouncemsghdrNetBSD7, bodyOff: sizeofIfAnnouncemsghdrNetBSD7}
+	// NetBSD 6 and above kernels require 64-bit aligned access to
+	// routing facilities.
+	return 8, map[int]parseFn{
+		sysRTM_ADD:        rtm.parseRouteMessage,
+		sysRTM_DELETE:     rtm.parseRouteMessage,
+		sysRTM_CHANGE:     rtm.parseRouteMessage,
+		sysRTM_GET:        rtm.parseRouteMessage,
+		sysRTM_LOSING:     rtm.parseRouteMessage,
+		sysRTM_REDIRECT:   rtm.parseRouteMessage,
+		sysRTM_MISS:       rtm.parseRouteMessage,
+		sysRTM_LOCK:       rtm.parseRouteMessage,
+		sysRTM_RESOLVE:    rtm.parseRouteMessage,
+		sysRTM_NEWADDR:    ifam.parseInterfaceAddrMessage,
+		sysRTM_DELADDR:    ifam.parseInterfaceAddrMessage,
+		sysRTM_IFANNOUNCE: ifanm.parseInterfaceAnnounceMessage,
+		sysRTM_IFINFO:     ifm.parseInterfaceMessage,
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/sys_openbsd.go b/src/vendor/golang.org/x/net/route/sys_openbsd.go
new file mode 100644
index 0000000..26d0438
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/sys_openbsd.go
@@ -0,0 +1,72 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package route
+
+import "unsafe"
+
+func (typ RIBType) parseable() bool {
+	switch typ {
+	case sysNET_RT_STATS, sysNET_RT_TABLE:
+		return false
+	default:
+		return true
+	}
+}
+
+// A RouteMetrics represents route metrics.
+type RouteMetrics struct {
+	PathMTU int // path maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (rmx *RouteMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *RouteMessage) Sys() []Sys {
+	return []Sys{
+		&RouteMetrics{
+			PathMTU: int(nativeEndian.Uint32(m.raw[60:64])),
+		},
+	}
+}
+
+// A InterfaceMetrics represents interface metrics.
+type InterfaceMetrics struct {
+	Type int // interface type
+	MTU  int // maximum transmission unit
+}
+
+// SysType implements the SysType method of Sys interface.
+func (imx *InterfaceMetrics) SysType() SysType { return SysMetrics }
+
+// Sys implements the Sys method of Message interface.
+func (m *InterfaceMessage) Sys() []Sys {
+	return []Sys{
+		&InterfaceMetrics{
+			Type: int(m.raw[24]),
+			MTU:  int(nativeEndian.Uint32(m.raw[28:32])),
+		},
+	}
+}
+
+func probeRoutingStack() (int, map[int]parseFn) {
+	var p uintptr
+	nooff := &wireFormat{extOff: -1, bodyOff: -1}
+	return int(unsafe.Sizeof(p)), map[int]parseFn{
+		sysRTM_ADD:        nooff.parseRouteMessage,
+		sysRTM_DELETE:     nooff.parseRouteMessage,
+		sysRTM_CHANGE:     nooff.parseRouteMessage,
+		sysRTM_GET:        nooff.parseRouteMessage,
+		sysRTM_LOSING:     nooff.parseRouteMessage,
+		sysRTM_REDIRECT:   nooff.parseRouteMessage,
+		sysRTM_MISS:       nooff.parseRouteMessage,
+		sysRTM_LOCK:       nooff.parseRouteMessage,
+		sysRTM_RESOLVE:    nooff.parseRouteMessage,
+		sysRTM_NEWADDR:    nooff.parseInterfaceAddrMessage,
+		sysRTM_DELADDR:    nooff.parseInterfaceAddrMessage,
+		sysRTM_IFINFO:     nooff.parseInterfaceMessage,
+		sysRTM_IFANNOUNCE: nooff.parseInterfaceAnnounceMessage,
+	}
+}
diff --git a/src/vendor/golang.org/x/net/route/syscall.go b/src/vendor/golang.org/x/net/route/syscall.go
new file mode 100644
index 0000000..d136325
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/syscall.go
@@ -0,0 +1,33 @@
+// Copyright 2016 The Go 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 route
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+// TODO: replace with runtime.KeepAlive when available
+//go:noescape
+func keepAlive(p unsafe.Pointer)
+
+var zero uintptr
+
+func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
+	var p unsafe.Pointer
+	if len(mib) > 0 {
+		p = unsafe.Pointer(&mib[0])
+	} else {
+		p = unsafe.Pointer(&zero)
+	}
+	_, _, errno := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(p), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+	keepAlive(p)
+	if errno != 0 {
+		return error(errno)
+	}
+	return nil
+}
diff --git a/src/vendor/golang.org/x/net/route/syscall.s b/src/vendor/golang.org/x/net/route/syscall.s
new file mode 100644
index 0000000..fa6297f
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/syscall.s
@@ -0,0 +1,8 @@
+// Copyright 2016 The Go 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 ·keepAlive(SB),NOSPLIT,$0
+	RET
diff --git a/src/vendor/golang.org/x/net/route/zsys_darwin.go b/src/vendor/golang.org/x/net/route/zsys_darwin.go
new file mode 100644
index 0000000..265b81c
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/zsys_darwin.go
@@ -0,0 +1,93 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_darwin.go
+
+package route
+
+const (
+	sysAF_UNSPEC = 0x0
+	sysAF_INET   = 0x2
+	sysAF_ROUTE  = 0x11
+	sysAF_LINK   = 0x12
+	sysAF_INET6  = 0x1e
+
+	sysNET_RT_DUMP    = 0x1
+	sysNET_RT_FLAGS   = 0x2
+	sysNET_RT_IFLIST  = 0x3
+	sysNET_RT_STAT    = 0x4
+	sysNET_RT_TRASH   = 0x5
+	sysNET_RT_IFLIST2 = 0x6
+	sysNET_RT_DUMP2   = 0x7
+	sysNET_RT_MAXID   = 0xa
+)
+
+const (
+	sysCTL_MAXNAME = 0xc
+
+	sysCTL_UNSPEC  = 0x0
+	sysCTL_KERN    = 0x1
+	sysCTL_VM      = 0x2
+	sysCTL_VFS     = 0x3
+	sysCTL_NET     = 0x4
+	sysCTL_DEBUG   = 0x5
+	sysCTL_HW      = 0x6
+	sysCTL_MACHDEP = 0x7
+	sysCTL_USER    = 0x8
+	sysCTL_MAXID   = 0x9
+)
+
+const (
+	sysRTM_VERSION = 0x5
+
+	sysRTM_ADD       = 0x1
+	sysRTM_DELETE    = 0x2
+	sysRTM_CHANGE    = 0x3
+	sysRTM_GET       = 0x4
+	sysRTM_LOSING    = 0x5
+	sysRTM_REDIRECT  = 0x6
+	sysRTM_MISS      = 0x7
+	sysRTM_LOCK      = 0x8
+	sysRTM_OLDADD    = 0x9
+	sysRTM_OLDDEL    = 0xa
+	sysRTM_RESOLVE   = 0xb
+	sysRTM_NEWADDR   = 0xc
+	sysRTM_DELADDR   = 0xd
+	sysRTM_IFINFO    = 0xe
+	sysRTM_NEWMADDR  = 0xf
+	sysRTM_DELMADDR  = 0x10
+	sysRTM_IFINFO2   = 0x12
+	sysRTM_NEWMADDR2 = 0x13
+	sysRTM_GET2      = 0x14
+
+	sysRTA_DST     = 0x1
+	sysRTA_GATEWAY = 0x2
+	sysRTA_NETMASK = 0x4
+	sysRTA_GENMASK = 0x8
+	sysRTA_IFP     = 0x10
+	sysRTA_IFA     = 0x20
+	sysRTA_AUTHOR  = 0x40
+	sysRTA_BRD     = 0x80
+
+	sysRTAX_DST     = 0x0
+	sysRTAX_GATEWAY = 0x1
+	sysRTAX_NETMASK = 0x2
+	sysRTAX_GENMASK = 0x3
+	sysRTAX_IFP     = 0x4
+	sysRTAX_IFA     = 0x5
+	sysRTAX_AUTHOR  = 0x6
+	sysRTAX_BRD     = 0x7
+	sysRTAX_MAX     = 0x8
+)
+
+const (
+	sizeofIfMsghdrDarwin15    = 0x70
+	sizeofIfaMsghdrDarwin15   = 0x14
+	sizeofIfmaMsghdrDarwin15  = 0x10
+	sizeofIfMsghdr2Darwin15   = 0xa0
+	sizeofIfmaMsghdr2Darwin15 = 0x14
+	sizeofIfDataDarwin15      = 0x60
+	sizeofIfData64Darwin15    = 0x80
+
+	sizeofRtMsghdrDarwin15  = 0x5c
+	sizeofRtMsghdr2Darwin15 = 0x5c
+	sizeofRtMetricsDarwin15 = 0x38
+)
diff --git a/src/vendor/golang.org/x/net/route/zsys_dragonfly.go b/src/vendor/golang.org/x/net/route/zsys_dragonfly.go
new file mode 100644
index 0000000..dd36dec
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/zsys_dragonfly.go
@@ -0,0 +1,92 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_dragonfly.go
+
+package route
+
+const (
+	sysAF_UNSPEC = 0x0
+	sysAF_INET   = 0x2
+	sysAF_ROUTE  = 0x11
+	sysAF_LINK   = 0x12
+	sysAF_INET6  = 0x1c
+
+	sysNET_RT_DUMP   = 0x1
+	sysNET_RT_FLAGS  = 0x2
+	sysNET_RT_IFLIST = 0x3
+	sysNET_RT_MAXID  = 0x4
+)
+
+const (
+	sysCTL_MAXNAME = 0xc
+
+	sysCTL_UNSPEC   = 0x0
+	sysCTL_KERN     = 0x1
+	sysCTL_VM       = 0x2
+	sysCTL_VFS      = 0x3
+	sysCTL_NET      = 0x4
+	sysCTL_DEBUG    = 0x5
+	sysCTL_HW       = 0x6
+	sysCTL_MACHDEP  = 0x7
+	sysCTL_USER     = 0x8
+	sysCTL_P1003_1B = 0x9
+	sysCTL_LWKT     = 0xa
+	sysCTL_MAXID    = 0xb
+)
+
+const (
+	sysRTM_VERSION = 0x6
+
+	sysRTM_ADD        = 0x1
+	sysRTM_DELETE     = 0x2
+	sysRTM_CHANGE     = 0x3
+	sysRTM_GET        = 0x4
+	sysRTM_LOSING     = 0x5
+	sysRTM_REDIRECT   = 0x6
+	sysRTM_MISS       = 0x7
+	sysRTM_LOCK       = 0x8
+	sysRTM_OLDADD     = 0x9
+	sysRTM_OLDDEL     = 0xa
+	sysRTM_RESOLVE    = 0xb
+	sysRTM_NEWADDR    = 0xc
+	sysRTM_DELADDR    = 0xd
+	sysRTM_IFINFO     = 0xe
+	sysRTM_NEWMADDR   = 0xf
+	sysRTM_DELMADDR   = 0x10
+	sysRTM_IFANNOUNCE = 0x11
+	sysRTM_IEEE80211  = 0x12
+
+	sysRTA_DST     = 0x1
+	sysRTA_GATEWAY = 0x2
+	sysRTA_NETMASK = 0x4
+	sysRTA_GENMASK = 0x8
+	sysRTA_IFP     = 0x10
+	sysRTA_IFA     = 0x20
+	sysRTA_AUTHOR  = 0x40
+	sysRTA_BRD     = 0x80
+	sysRTA_MPLS1   = 0x100
+	sysRTA_MPLS2   = 0x200
+	sysRTA_MPLS3   = 0x400
+
+	sysRTAX_DST     = 0x0
+	sysRTAX_GATEWAY = 0x1
+	sysRTAX_NETMASK = 0x2
+	sysRTAX_GENMASK = 0x3
+	sysRTAX_IFP     = 0x4
+	sysRTAX_IFA     = 0x5
+	sysRTAX_AUTHOR  = 0x6
+	sysRTAX_BRD     = 0x7
+	sysRTAX_MPLS1   = 0x8
+	sysRTAX_MPLS2   = 0x9
+	sysRTAX_MPLS3   = 0xa
+	sysRTAX_MAX     = 0xb
+)
+
+const (
+	sizeofIfMsghdrDragonFlyBSD4         = 0xb0
+	sizeofIfaMsghdrDragonFlyBSD4        = 0x14
+	sizeofIfmaMsghdrDragonFlyBSD4       = 0x10
+	sizeofIfAnnouncemsghdrDragonFlyBSD4 = 0x18
+
+	sizeofRtMsghdrDragonFlyBSD4  = 0x98
+	sizeofRtMetricsDragonFlyBSD4 = 0x70
+)
diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go b/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go
new file mode 100644
index 0000000..9bac2e3
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go
@@ -0,0 +1,120 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_freebsd.go
+
+package route
+
+const (
+	sysAF_UNSPEC = 0x0
+	sysAF_INET   = 0x2
+	sysAF_ROUTE  = 0x11
+	sysAF_LINK   = 0x12
+	sysAF_INET6  = 0x1c
+
+	sysNET_RT_DUMP     = 0x1
+	sysNET_RT_FLAGS    = 0x2
+	sysNET_RT_IFLIST   = 0x3
+	sysNET_RT_IFMALIST = 0x4
+	sysNET_RT_IFLISTL  = 0x5
+)
+
+const (
+	sysCTL_MAXNAME = 0x18
+
+	sysCTL_UNSPEC   = 0x0
+	sysCTL_KERN     = 0x1
+	sysCTL_VM       = 0x2
+	sysCTL_VFS      = 0x3
+	sysCTL_NET      = 0x4
+	sysCTL_DEBUG    = 0x5
+	sysCTL_HW       = 0x6
+	sysCTL_MACHDEP  = 0x7
+	sysCTL_USER     = 0x8
+	sysCTL_P1003_1B = 0x9
+)
+
+const (
+	sysRTM_VERSION = 0x5
+
+	sysRTM_ADD        = 0x1
+	sysRTM_DELETE     = 0x2
+	sysRTM_CHANGE     = 0x3
+	sysRTM_GET        = 0x4
+	sysRTM_LOSING     = 0x5
+	sysRTM_REDIRECT   = 0x6
+	sysRTM_MISS       = 0x7
+	sysRTM_LOCK       = 0x8
+	sysRTM_RESOLVE    = 0xb
+	sysRTM_NEWADDR    = 0xc
+	sysRTM_DELADDR    = 0xd
+	sysRTM_IFINFO     = 0xe
+	sysRTM_NEWMADDR   = 0xf
+	sysRTM_DELMADDR   = 0x10
+	sysRTM_IFANNOUNCE = 0x11
+	sysRTM_IEEE80211  = 0x12
+
+	sysRTA_DST     = 0x1
+	sysRTA_GATEWAY = 0x2
+	sysRTA_NETMASK = 0x4
+	sysRTA_GENMASK = 0x8
+	sysRTA_IFP     = 0x10
+	sysRTA_IFA     = 0x20
+	sysRTA_AUTHOR  = 0x40
+	sysRTA_BRD     = 0x80
+
+	sysRTAX_DST     = 0x0
+	sysRTAX_GATEWAY = 0x1
+	sysRTAX_NETMASK = 0x2
+	sysRTAX_GENMASK = 0x3
+	sysRTAX_IFP     = 0x4
+	sysRTAX_IFA     = 0x5
+	sysRTAX_AUTHOR  = 0x6
+	sysRTAX_BRD     = 0x7
+	sysRTAX_MAX     = 0x8
+)
+
+const (
+	sizeofIfMsghdrlFreeBSD10        = 0x68
+	sizeofIfaMsghdrFreeBSD10        = 0x14
+	sizeofIfaMsghdrlFreeBSD10       = 0x6c
+	sizeofIfmaMsghdrFreeBSD10       = 0x10
+	sizeofIfAnnouncemsghdrFreeBSD10 = 0x18
+
+	sizeofRtMsghdrFreeBSD10  = 0x5c
+	sizeofRtMetricsFreeBSD10 = 0x38
+
+	sizeofIfMsghdrFreeBSD7  = 0x60
+	sizeofIfMsghdrFreeBSD8  = 0x60
+	sizeofIfMsghdrFreeBSD9  = 0x60
+	sizeofIfMsghdrFreeBSD10 = 0x64
+	sizeofIfMsghdrFreeBSD11 = 0xa8
+
+	sizeofIfDataFreeBSD7  = 0x50
+	sizeofIfDataFreeBSD8  = 0x50
+	sizeofIfDataFreeBSD9  = 0x50
+	sizeofIfDataFreeBSD10 = 0x54
+	sizeofIfDataFreeBSD11 = 0x98
+
+	// MODIFIED BY HAND FOR 386 EMULATION ON AMD64
+	// 386 EMULATION USES THE UNDERLYING RAW DATA LAYOUT
+
+	sizeofIfMsghdrlFreeBSD10Emu        = 0xb0
+	sizeofIfaMsghdrFreeBSD10Emu        = 0x14
+	sizeofIfaMsghdrlFreeBSD10Emu       = 0xb0
+	sizeofIfmaMsghdrFreeBSD10Emu       = 0x10
+	sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18
+
+	sizeofRtMsghdrFreeBSD10Emu  = 0x98
+	sizeofRtMetricsFreeBSD10Emu = 0x70
+
+	sizeofIfMsghdrFreeBSD7Emu  = 0xa8
+	sizeofIfMsghdrFreeBSD8Emu  = 0xa8
+	sizeofIfMsghdrFreeBSD9Emu  = 0xa8
+	sizeofIfMsghdrFreeBSD10Emu = 0xa8
+	sizeofIfMsghdrFreeBSD11Emu = 0xa8
+
+	sizeofIfDataFreeBSD7Emu  = 0x98
+	sizeofIfDataFreeBSD8Emu  = 0x98
+	sizeofIfDataFreeBSD9Emu  = 0x98
+	sizeofIfDataFreeBSD10Emu = 0x98
+	sizeofIfDataFreeBSD11Emu = 0x98
+)
diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go b/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go
new file mode 100644
index 0000000..b1920d7
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go
@@ -0,0 +1,117 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_freebsd.go
+
+package route
+
+const (
+	sysAF_UNSPEC = 0x0
+	sysAF_INET   = 0x2
+	sysAF_ROUTE  = 0x11
+	sysAF_LINK   = 0x12
+	sysAF_INET6  = 0x1c
+
+	sysNET_RT_DUMP     = 0x1
+	sysNET_RT_FLAGS    = 0x2
+	sysNET_RT_IFLIST   = 0x3
+	sysNET_RT_IFMALIST = 0x4
+	sysNET_RT_IFLISTL  = 0x5
+)
+
+const (
+	sysCTL_MAXNAME = 0x18
+
+	sysCTL_UNSPEC   = 0x0
+	sysCTL_KERN     = 0x1
+	sysCTL_VM       = 0x2
+	sysCTL_VFS      = 0x3
+	sysCTL_NET      = 0x4
+	sysCTL_DEBUG    = 0x5
+	sysCTL_HW       = 0x6
+	sysCTL_MACHDEP  = 0x7
+	sysCTL_USER     = 0x8
+	sysCTL_P1003_1B = 0x9
+)
+
+const (
+	sysRTM_VERSION = 0x5
+
+	sysRTM_ADD        = 0x1
+	sysRTM_DELETE     = 0x2
+	sysRTM_CHANGE     = 0x3
+	sysRTM_GET        = 0x4
+	sysRTM_LOSING     = 0x5
+	sysRTM_REDIRECT   = 0x6
+	sysRTM_MISS       = 0x7
+	sysRTM_LOCK       = 0x8
+	sysRTM_RESOLVE    = 0xb
+	sysRTM_NEWADDR    = 0xc
+	sysRTM_DELADDR    = 0xd
+	sysRTM_IFINFO     = 0xe
+	sysRTM_NEWMADDR   = 0xf
+	sysRTM_DELMADDR   = 0x10
+	sysRTM_IFANNOUNCE = 0x11
+	sysRTM_IEEE80211  = 0x12
+
+	sysRTA_DST     = 0x1
+	sysRTA_GATEWAY = 0x2
+	sysRTA_NETMASK = 0x4
+	sysRTA_GENMASK = 0x8
+	sysRTA_IFP     = 0x10
+	sysRTA_IFA     = 0x20
+	sysRTA_AUTHOR  = 0x40
+	sysRTA_BRD     = 0x80
+
+	sysRTAX_DST     = 0x0
+	sysRTAX_GATEWAY = 0x1
+	sysRTAX_NETMASK = 0x2
+	sysRTAX_GENMASK = 0x3
+	sysRTAX_IFP     = 0x4
+	sysRTAX_IFA     = 0x5
+	sysRTAX_AUTHOR  = 0x6
+	sysRTAX_BRD     = 0x7
+	sysRTAX_MAX     = 0x8
+)
+
+const (
+	sizeofIfMsghdrlFreeBSD10        = 0xb0
+	sizeofIfaMsghdrFreeBSD10        = 0x14
+	sizeofIfaMsghdrlFreeBSD10       = 0xb0
+	sizeofIfmaMsghdrFreeBSD10       = 0x10
+	sizeofIfAnnouncemsghdrFreeBSD10 = 0x18
+
+	sizeofRtMsghdrFreeBSD10  = 0x98
+	sizeofRtMetricsFreeBSD10 = 0x70
+
+	sizeofIfMsghdrFreeBSD7  = 0xa8
+	sizeofIfMsghdrFreeBSD8  = 0xa8
+	sizeofIfMsghdrFreeBSD9  = 0xa8
+	sizeofIfMsghdrFreeBSD10 = 0xa8
+	sizeofIfMsghdrFreeBSD11 = 0xa8
+
+	sizeofIfDataFreeBSD7  = 0x98
+	sizeofIfDataFreeBSD8  = 0x98
+	sizeofIfDataFreeBSD9  = 0x98
+	sizeofIfDataFreeBSD10 = 0x98
+	sizeofIfDataFreeBSD11 = 0x98
+
+	sizeofIfMsghdrlFreeBSD10Emu        = 0xb0
+	sizeofIfaMsghdrFreeBSD10Emu        = 0x14
+	sizeofIfaMsghdrlFreeBSD10Emu       = 0xb0
+	sizeofIfmaMsghdrFreeBSD10Emu       = 0x10
+	sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18
+
+	sizeofRtMsghdrFreeBSD10Emu  = 0x98
+	sizeofRtMetricsFreeBSD10Emu = 0x70
+
+	sizeofIfMsghdrFreeBSD7Emu  = 0xa8
+	sizeofIfMsghdrFreeBSD8Emu  = 0xa8
+	sizeofIfMsghdrFreeBSD9Emu  = 0xa8
+	sizeofIfMsghdrFreeBSD10Emu = 0xa8
+	sizeofIfMsghdrFreeBSD11Emu = 0xa8
+
+	sizeofIfDataFreeBSD7Emu  = 0x98
+	sizeofIfDataFreeBSD8Emu  = 0x98
+	sizeofIfDataFreeBSD9Emu  = 0x98
+	sizeofIfDataFreeBSD10Emu = 0x98
+	sizeofIfDataFreeBSD11Emu = 0x98
+)
diff --git a/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go b/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go
new file mode 100644
index 0000000..a034d6f
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go
@@ -0,0 +1,117 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_freebsd.go
+
+package route
+
+const (
+	sysAF_UNSPEC = 0x0
+	sysAF_INET   = 0x2
+	sysAF_ROUTE  = 0x11
+	sysAF_LINK   = 0x12
+	sysAF_INET6  = 0x1c
+
+	sysNET_RT_DUMP     = 0x1
+	sysNET_RT_FLAGS    = 0x2
+	sysNET_RT_IFLIST   = 0x3
+	sysNET_RT_IFMALIST = 0x4
+	sysNET_RT_IFLISTL  = 0x5
+)
+
+const (
+	sysCTL_MAXNAME = 0x18
+
+	sysCTL_UNSPEC   = 0x0
+	sysCTL_KERN     = 0x1
+	sysCTL_VM       = 0x2
+	sysCTL_VFS      = 0x3
+	sysCTL_NET      = 0x4
+	sysCTL_DEBUG    = 0x5
+	sysCTL_HW       = 0x6
+	sysCTL_MACHDEP  = 0x7
+	sysCTL_USER     = 0x8
+	sysCTL_P1003_1B = 0x9
+)
+
+const (
+	sysRTM_VERSION = 0x5
+
+	sysRTM_ADD        = 0x1
+	sysRTM_DELETE     = 0x2
+	sysRTM_CHANGE     = 0x3
+	sysRTM_GET        = 0x4
+	sysRTM_LOSING     = 0x5
+	sysRTM_REDIRECT   = 0x6
+	sysRTM_MISS       = 0x7
+	sysRTM_LOCK       = 0x8
+	sysRTM_RESOLVE    = 0xb
+	sysRTM_NEWADDR    = 0xc
+	sysRTM_DELADDR    = 0xd
+	sysRTM_IFINFO     = 0xe
+	sysRTM_NEWMADDR   = 0xf
+	sysRTM_DELMADDR   = 0x10
+	sysRTM_IFANNOUNCE = 0x11
+	sysRTM_IEEE80211  = 0x12
+
+	sysRTA_DST     = 0x1
+	sysRTA_GATEWAY = 0x2
+	sysRTA_NETMASK = 0x4
+	sysRTA_GENMASK = 0x8
+	sysRTA_IFP     = 0x10
+	sysRTA_IFA     = 0x20
+	sysRTA_AUTHOR  = 0x40
+	sysRTA_BRD     = 0x80
+
+	sysRTAX_DST     = 0x0
+	sysRTAX_GATEWAY = 0x1
+	sysRTAX_NETMASK = 0x2
+	sysRTAX_GENMASK = 0x3
+	sysRTAX_IFP     = 0x4
+	sysRTAX_IFA     = 0x5
+	sysRTAX_AUTHOR  = 0x6
+	sysRTAX_BRD     = 0x7
+	sysRTAX_MAX     = 0x8
+)
+
+const (
+	sizeofIfMsghdrlFreeBSD10        = 0x68
+	sizeofIfaMsghdrFreeBSD10        = 0x14
+	sizeofIfaMsghdrlFreeBSD10       = 0x6c
+	sizeofIfmaMsghdrFreeBSD10       = 0x10
+	sizeofIfAnnouncemsghdrFreeBSD10 = 0x18
+
+	sizeofRtMsghdrFreeBSD10  = 0x5c
+	sizeofRtMetricsFreeBSD10 = 0x38
+
+	sizeofIfMsghdrFreeBSD7  = 0x70
+	sizeofIfMsghdrFreeBSD8  = 0x70
+	sizeofIfMsghdrFreeBSD9  = 0x70
+	sizeofIfMsghdrFreeBSD10 = 0x70
+	sizeofIfMsghdrFreeBSD11 = 0xa8
+
+	sizeofIfDataFreeBSD7  = 0x60
+	sizeofIfDataFreeBSD8  = 0x60
+	sizeofIfDataFreeBSD9  = 0x60
+	sizeofIfDataFreeBSD10 = 0x60
+	sizeofIfDataFreeBSD11 = 0x98
+
+	sizeofIfMsghdrlFreeBSD10Emu        = 0x68
+	sizeofIfaMsghdrFreeBSD10Emu        = 0x14
+	sizeofIfaMsghdrlFreeBSD10Emu       = 0x6c
+	sizeofIfmaMsghdrFreeBSD10Emu       = 0x10
+	sizeofIfAnnouncemsghdrFreeBSD10Emu = 0x18
+
+	sizeofRtMsghdrFreeBSD10Emu  = 0x5c
+	sizeofRtMetricsFreeBSD10Emu = 0x38
+
+	sizeofIfMsghdrFreeBSD7Emu  = 0x70
+	sizeofIfMsghdrFreeBSD8Emu  = 0x70
+	sizeofIfMsghdrFreeBSD9Emu  = 0x70
+	sizeofIfMsghdrFreeBSD10Emu = 0x70
+	sizeofIfMsghdrFreeBSD11Emu = 0xa8
+
+	sizeofIfDataFreeBSD7Emu  = 0x60
+	sizeofIfDataFreeBSD8Emu  = 0x60
+	sizeofIfDataFreeBSD9Emu  = 0x60
+	sizeofIfDataFreeBSD10Emu = 0x60
+	sizeofIfDataFreeBSD11Emu = 0x98
+)
diff --git a/src/vendor/golang.org/x/net/route/zsys_netbsd.go b/src/vendor/golang.org/x/net/route/zsys_netbsd.go
new file mode 100644
index 0000000..aa4aad1
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/zsys_netbsd.go
@@ -0,0 +1,91 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_netbsd.go
+
+package route
+
+const (
+	sysAF_UNSPEC = 0x0
+	sysAF_INET   = 0x2
+	sysAF_ROUTE  = 0x22
+	sysAF_LINK   = 0x12
+	sysAF_INET6  = 0x18
+
+	sysNET_RT_DUMP   = 0x1
+	sysNET_RT_FLAGS  = 0x2
+	sysNET_RT_IFLIST = 0x5
+	sysNET_RT_MAXID  = 0x6
+)
+
+const (
+	sysCTL_MAXNAME = 0xc
+
+	sysCTL_UNSPEC   = 0x0
+	sysCTL_KERN     = 0x1
+	sysCTL_VM       = 0x2
+	sysCTL_VFS      = 0x3
+	sysCTL_NET      = 0x4
+	sysCTL_DEBUG    = 0x5
+	sysCTL_HW       = 0x6
+	sysCTL_MACHDEP  = 0x7
+	sysCTL_USER     = 0x8
+	sysCTL_DDB      = 0x9
+	sysCTL_PROC     = 0xa
+	sysCTL_VENDOR   = 0xb
+	sysCTL_EMUL     = 0xc
+	sysCTL_SECURITY = 0xd
+	sysCTL_MAXID    = 0xe
+)
+
+const (
+	sysRTM_VERSION = 0x4
+
+	sysRTM_ADD        = 0x1
+	sysRTM_DELETE     = 0x2
+	sysRTM_CHANGE     = 0x3
+	sysRTM_GET        = 0x4
+	sysRTM_LOSING     = 0x5
+	sysRTM_REDIRECT   = 0x6
+	sysRTM_MISS       = 0x7
+	sysRTM_LOCK       = 0x8
+	sysRTM_OLDADD     = 0x9
+	sysRTM_OLDDEL     = 0xa
+	sysRTM_RESOLVE    = 0xb
+	sysRTM_NEWADDR    = 0xc
+	sysRTM_DELADDR    = 0xd
+	sysRTM_IFANNOUNCE = 0x10
+	sysRTM_IEEE80211  = 0x11
+	sysRTM_SETGATE    = 0x12
+	sysRTM_LLINFO_UPD = 0x13
+	sysRTM_IFINFO     = 0x14
+	sysRTM_CHGADDR    = 0x15
+
+	sysRTA_DST     = 0x1
+	sysRTA_GATEWAY = 0x2
+	sysRTA_NETMASK = 0x4
+	sysRTA_GENMASK = 0x8
+	sysRTA_IFP     = 0x10
+	sysRTA_IFA     = 0x20
+	sysRTA_AUTHOR  = 0x40
+	sysRTA_BRD     = 0x80
+	sysRTA_TAG     = 0x100
+
+	sysRTAX_DST     = 0x0
+	sysRTAX_GATEWAY = 0x1
+	sysRTAX_NETMASK = 0x2
+	sysRTAX_GENMASK = 0x3
+	sysRTAX_IFP     = 0x4
+	sysRTAX_IFA     = 0x5
+	sysRTAX_AUTHOR  = 0x6
+	sysRTAX_BRD     = 0x7
+	sysRTAX_TAG     = 0x8
+	sysRTAX_MAX     = 0x9
+)
+
+const (
+	sizeofIfMsghdrNetBSD7         = 0x98
+	sizeofIfaMsghdrNetBSD7        = 0x18
+	sizeofIfAnnouncemsghdrNetBSD7 = 0x18
+
+	sizeofRtMsghdrNetBSD7  = 0x78
+	sizeofRtMetricsNetBSD7 = 0x50
+)
diff --git a/src/vendor/golang.org/x/net/route/zsys_openbsd.go b/src/vendor/golang.org/x/net/route/zsys_openbsd.go
new file mode 100644
index 0000000..4fadc4e
--- /dev/null
+++ b/src/vendor/golang.org/x/net/route/zsys_openbsd.go
@@ -0,0 +1,80 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_openbsd.go
+
+package route
+
+const (
+	sysAF_UNSPEC = 0x0
+	sysAF_INET   = 0x2
+	sysAF_ROUTE  = 0x11
+	sysAF_LINK   = 0x12
+	sysAF_INET6  = 0x18
+
+	sysNET_RT_DUMP    = 0x1
+	sysNET_RT_FLAGS   = 0x2
+	sysNET_RT_IFLIST  = 0x3
+	sysNET_RT_STATS   = 0x4
+	sysNET_RT_TABLE   = 0x5
+	sysNET_RT_IFNAMES = 0x6
+	sysNET_RT_MAXID   = 0x7
+)
+
+const (
+	sysCTL_MAXNAME = 0xc
+
+	sysCTL_UNSPEC  = 0x0
+	sysCTL_KERN    = 0x1
+	sysCTL_VM      = 0x2
+	sysCTL_FS      = 0x3
+	sysCTL_NET     = 0x4
+	sysCTL_DEBUG   = 0x5
+	sysCTL_HW      = 0x6
+	sysCTL_MACHDEP = 0x7
+	sysCTL_DDB     = 0x9
+	sysCTL_VFS     = 0xa
+	sysCTL_MAXID   = 0xb
+)
+
+const (
+	sysRTM_VERSION = 0x5
+
+	sysRTM_ADD        = 0x1
+	sysRTM_DELETE     = 0x2
+	sysRTM_CHANGE     = 0x3
+	sysRTM_GET        = 0x4
+	sysRTM_LOSING     = 0x5
+	sysRTM_REDIRECT   = 0x6
+	sysRTM_MISS       = 0x7
+	sysRTM_LOCK       = 0x8
+	sysRTM_RESOLVE    = 0xb
+	sysRTM_NEWADDR    = 0xc
+	sysRTM_DELADDR    = 0xd
+	sysRTM_IFINFO     = 0xe
+	sysRTM_IFANNOUNCE = 0xf
+	sysRTM_DESYNC     = 0x10
+
+	sysRTA_DST     = 0x1
+	sysRTA_GATEWAY = 0x2
+	sysRTA_NETMASK = 0x4
+	sysRTA_GENMASK = 0x8
+	sysRTA_IFP     = 0x10
+	sysRTA_IFA     = 0x20
+	sysRTA_AUTHOR  = 0x40
+	sysRTA_BRD     = 0x80
+	sysRTA_SRC     = 0x100
+	sysRTA_SRCMASK = 0x200
+	sysRTA_LABEL   = 0x400
+
+	sysRTAX_DST     = 0x0
+	sysRTAX_GATEWAY = 0x1
+	sysRTAX_NETMASK = 0x2
+	sysRTAX_GENMASK = 0x3
+	sysRTAX_IFP     = 0x4
+	sysRTAX_IFA     = 0x5
+	sysRTAX_AUTHOR  = 0x6
+	sysRTAX_BRD     = 0x7
+	sysRTAX_SRC     = 0x8
+	sysRTAX_SRCMASK = 0x9
+	sysRTAX_LABEL   = 0xa
+	sysRTAX_MAX     = 0xb
+)
diff --git a/test/alg.go b/test/alg.go
new file mode 100644
index 0000000..7bb1b6b
--- /dev/null
+++ b/test/alg.go
@@ -0,0 +1,46 @@
+// build
+
+// Copyright 2016 The Go 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 that required algs are generated,
+// even when similar types have been marked elsewhere
+// as not needing algs. See CLs 19769 and 19770.
+
+package main
+
+import "fmt"
+
+//go:noinline
+func f(m map[[8]string]int) int {
+	var k [8]string
+	return m[k]
+}
+
+//go:noinline
+func g(m map[[8]interface{}]int) int {
+	var k [8]interface{}
+	return m[k]
+}
+
+//go:noinline
+func h(m map[[2]string]int) int {
+	var k [2]string
+	return m[k]
+}
+
+type T map[string]interface{}
+
+func v(x ...string) string {
+	return x[0] + x[1]
+}
+
+func main() {
+	fmt.Println(
+		f(map[[8]string]int{}),
+		g(map[[8]interface{}]int{}),
+		h(map[[2]string]int{}),
+		v("a", "b"),
+	)
+}
diff --git a/test/alias.go b/test/alias.go
index ec93a2d..aabaef8 100644
--- a/test/alias.go
+++ b/test/alias.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/alias1.go b/test/alias1.go
index 42cf693..5707917 100644
--- a/test/alias1.go
+++ b/test/alias1.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/atomicload.go b/test/atomicload.go
new file mode 100644
index 0000000..76f1ad4
--- /dev/null
+++ b/test/atomicload.go
@@ -0,0 +1,45 @@
+// run
+
+// Copyright 2016 The Go 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 we do loads exactly once. The SSA backend
+// once tried to do the load in f twice, once sign extended
+// and once zero extended.  This can cause problems in
+// racy code, particularly sync/mutex.
+
+package main
+
+func f(p *byte) bool {
+	x := *p
+	a := int64(int8(x))
+	b := int64(uint8(x))
+	return a == b
+}
+
+func main() {
+	var x byte
+	const N = 1000000
+	c := make(chan struct{})
+	go func() {
+		for i := 0; i < N; i++ {
+			x = 1
+		}
+		c <- struct{}{}
+	}()
+	go func() {
+		for i := 0; i < N; i++ {
+			x = 2
+		}
+		c <- struct{}{}
+	}()
+
+	for i := 0; i < N; i++ {
+		if !f(&x) {
+			panic("non-atomic load!")
+		}
+	}
+	<-c
+	<-c
+}
diff --git a/test/bench/garbage/Makefile b/test/bench/garbage/Makefile
index 9883845..c10ef0a 100644
--- a/test/bench/garbage/Makefile
+++ b/test/bench/garbage/Makefile
@@ -1,4 +1,4 @@
-# Copyright 2010 The Go Authors.  All rights reserved.
+# 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.
 
diff --git a/test/bench/garbage/parser.go b/test/bench/garbage/parser.go
index a685507..817afa9 100644
--- a/test/bench/garbage/parser.go
+++ b/test/bench/garbage/parser.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/bench/garbage/stats.go b/test/bench/garbage/stats.go
index 6dc0aeb..937e00f 100644
--- a/test/bench/garbage/stats.go
+++ b/test/bench/garbage/stats.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/bench/garbage/tree2.go b/test/bench/garbage/tree2.go
index a171c69..a70a106 100644
--- a/test/bench/garbage/tree2.go
+++ b/test/bench/garbage/tree2.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/binarytree_test.go b/test/bench/go1/binarytree_test.go
index c64c4b8..e5e49d5 100644
--- a/test/bench/go1/binarytree_test.go
+++ b/test/bench/go1/binarytree_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/fannkuch_test.go b/test/bench/go1/fannkuch_test.go
index ae45bfd..0cf6115 100644
--- a/test/bench/go1/fannkuch_test.go
+++ b/test/bench/go1/fannkuch_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/fasta_test.go b/test/bench/go1/fasta_test.go
index bff056f..99d8c97 100644
--- a/test/bench/go1/fasta_test.go
+++ b/test/bench/go1/fasta_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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,9 +14,9 @@ func makefasta() []byte {
 	var n int = 25e6
 	if runtime.GOARCH == "arm" {
 		// TODO(dfc) remove this limitation after precise gc.
-		// A value of 25e6 consumes 465mb of heap on 32bit 
-		// platforms, which is too much for most ARM systems. 
-		// A value of 25e5 produces a memory layout that 
+		// A value of 25e6 consumes 465mb of heap on 32bit
+		// platforms, which is too much for most ARM systems.
+		// A value of 25e5 produces a memory layout that
 		// confuses the gc on 32bit platforms. So 25e4 it is.
 		n = 25e4
 	}
diff --git a/test/bench/go1/gob_test.go b/test/bench/go1/gob_test.go
index b172b80..224beff 100644
--- a/test/bench/go1/gob_test.go
+++ b/test/bench/go1/gob_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/gzip_test.go b/test/bench/go1/gzip_test.go
index fe4c480..648eec5 100644
--- a/test/bench/go1/gzip_test.go
+++ b/test/bench/go1/gzip_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/http_test.go b/test/bench/go1/http_test.go
index 34e789f..7ece9b2 100644
--- a/test/bench/go1/http_test.go
+++ b/test/bench/go1/http_test.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/json_test.go b/test/bench/go1/json_test.go
index 1d42619..5ff1f8b 100644
--- a/test/bench/go1/json_test.go
+++ b/test/bench/go1/json_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/jsondata_test.go b/test/bench/go1/jsondata_test.go
index 59afe13..281b6ca 100644
--- a/test/bench/go1/jsondata_test.go
+++ b/test/bench/go1/jsondata_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/mandel_test.go b/test/bench/go1/mandel_test.go
index 888c5e4..dd543b2 100644
--- a/test/bench/go1/mandel_test.go
+++ b/test/bench/go1/mandel_test.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/parserdata_test.go b/test/bench/go1/parserdata_test.go
index 113e5e3..001c5d8 100644
--- a/test/bench/go1/parserdata_test.go
+++ b/test/bench/go1/parserdata_test.go
@@ -1,10 +1,10 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
 // Input for parser benchmark.
 // This was generated by starting with a the contents of
-// src/pkg/go/parser/parser.go at rev 9b455eb64690, then 
+// src/pkg/go/parser/parser.go at rev 9b455eb64690, then
 // compressing with bzip2 -9, then encoding to base64.
 // We compile the data into the binary so that the benchmark is
 // a stand-alone binary that can be copied easily from machine to
diff --git a/test/bench/go1/revcomp_test.go b/test/bench/go1/revcomp_test.go
index 6b6c1e5..7d57bd6 100644
--- a/test/bench/go1/revcomp_test.go
+++ b/test/bench/go1/revcomp_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/bench/go1/template_test.go b/test/bench/go1/template_test.go
index db4839a..10dacaa 100644
--- a/test/bench/go1/template_test.go
+++ b/test/bench/go1/template_test.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/bombad.go b/test/bombad.go
index b894d9b..6b79a98 100644
--- a/test/bombad.go
+++ b/test/bombad.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/bounds.go b/test/bounds.go
index 50f7ad7..a0febb5 100644
--- a/test/bounds.go
+++ b/test/bounds.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/bugs/bug395.go b/test/bugs/bug395.go
index 5490a3d..4fe81e0 100644
--- a/test/bugs/bug395.go
+++ b/test/bugs/bug395.go
@@ -2,7 +2,7 @@
 
 // When issue 1909 is fixed, change from skip to compile.
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/chan/select2.go b/test/chan/select2.go
index ccf9dab..31e27d7 100644
--- a/test/chan/select2.go
+++ b/test/chan/select2.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/chan/select5.go b/test/chan/select5.go
index cfdc085..8b98c3a 100644
--- a/test/chan/select5.go
+++ b/test/chan/select5.go
@@ -1,6 +1,6 @@
 // runoutput
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/chan/select6.go b/test/chan/select6.go
index af470a0..6e8129f 100644
--- a/test/chan/select6.go
+++ b/test/chan/select6.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/chan/select7.go b/test/chan/select7.go
index 20456a9..f7222ca 100644
--- a/test/chan/select7.go
+++ b/test/chan/select7.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/chan/sendstmt.go b/test/chan/sendstmt.go
index a92c4f6..278fa1b 100644
--- a/test/chan/sendstmt.go
+++ b/test/chan/sendstmt.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/checkbce.go b/test/checkbce.go
new file mode 100644
index 0000000..fa0ea12
--- /dev/null
+++ b/test/checkbce.go
@@ -0,0 +1,114 @@
+// +build amd64
+// errorcheck -0 -d=ssa/check_bce/debug=3
+
+package main
+
+func f0(a []int) {
+	a[0] = 1 // ERROR "Found IsInBounds$"
+	a[0] = 1
+	a[6] = 1 // ERROR "Found IsInBounds$"
+	a[6] = 1
+	a[5] = 1
+	a[5] = 1
+}
+
+func f1(a [256]int, i int) {
+	useInt(a[i])     // ERROR "Found IsInBounds$"
+	useInt(a[i%256]) // ERROR "Found IsInBounds$"
+	useInt(a[i&255])
+	useInt(a[i&17])
+
+	if 4 <= i && i < len(a) {
+		useInt(a[i])
+		useInt(a[i-1]) // ERROR "Found IsInBounds$"
+		useInt(a[i-4]) // ERROR "Found IsInBounds$"
+	}
+}
+
+func f2(a [256]int, i uint) {
+	useInt(a[i]) // ERROR "Found IsInBounds$"
+	useInt(a[i%256])
+	useInt(a[i&255])
+	useInt(a[i&17])
+}
+
+func f3(a [256]int, i uint8) {
+	useInt(a[i])
+	useInt(a[i+10])
+	useInt(a[i+14])
+}
+
+func f4(a [27]int, i uint8) {
+	useInt(a[i%15])
+	useInt(a[i%19])
+	useInt(a[i%27])
+}
+
+func f5(a []int) {
+	if len(a) > 5 {
+		useInt(a[5])
+		useSlice(a[6:])
+		useSlice(a[:6]) // ERROR "Found IsSliceInBounds$"
+	}
+}
+
+func f6(a [32]int, b [64]int, i int) {
+	useInt(a[uint32(i*0x07C4ACDD)>>27])
+	useInt(b[uint64(i*0x07C4ACDD)>>58])
+	useInt(a[uint(i*0x07C4ACDD)>>59])
+
+	// The following bounds should not be removed because they can overflow.
+	useInt(a[uint32(i*0x106297f105d0cc86)>>26]) // ERROR "Found IsInBounds$"
+	useInt(b[uint64(i*0x106297f105d0cc86)>>57]) // ERROR "Found IsInBounds$"
+	useInt(a[int32(i*0x106297f105d0cc86)>>26])  // ERROR "Found IsInBounds$"
+	useInt(b[int64(i*0x106297f105d0cc86)>>57])  // ERROR "Found IsInBounds$"
+}
+
+func g1(a []int) {
+	for i := range a {
+		a[i] = i
+		useSlice(a[:i+1])
+		useSlice(a[:i])
+	}
+}
+
+func g2(a []int) {
+	useInt(a[3]) // ERROR "Found IsInBounds$"
+	useInt(a[2])
+	useInt(a[1])
+	useInt(a[0])
+}
+
+func g3(a []int) {
+	for i := range a[:256] { // ERROR "Found IsSliceInBounds$"
+		useInt(a[i]) // ERROR "Found IsInBounds$"
+	}
+	b := a[:256]
+	for i := range b {
+		useInt(b[i])
+	}
+}
+
+func g4(a [100]int) {
+	for i := 10; i < 50; i++ {
+		useInt(a[i-10])
+		useInt(a[i])
+		useInt(a[i+25])
+		useInt(a[i+50])
+
+		// The following are out of bounds.
+		useInt(a[i-11]) // ERROR "Found IsInBounds$"
+		useInt(a[i+51]) // ERROR "Found IsInBounds$"
+	}
+}
+
+//go:noinline
+func useInt(a int) {
+}
+
+//go:noinline
+func useSlice(a []int) {
+}
+
+func main() {
+}
diff --git a/test/cmplxdivide.c b/test/cmplxdivide.c
index d654362..a475cc2 100644
--- a/test/cmplxdivide.c
+++ b/test/cmplxdivide.c
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/cmplxdivide.go b/test/cmplxdivide.go
index 8e29672..a8ae515 100644
--- a/test/cmplxdivide.go
+++ b/test/cmplxdivide.go
@@ -1,6 +1,6 @@
 // run cmplxdivide1.go
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/complit1.go b/test/complit1.go
index c7a2ac9..9dde994 100644
--- a/test/complit1.go
+++ b/test/complit1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/compos.go b/test/compos.go
index de688b3..e6375f2 100644
--- a/test/compos.go
+++ b/test/compos.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/const6.go b/test/const6.go
index c005ac3..b340e58 100644
--- a/test/const6.go
+++ b/test/const6.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/convert1.go b/test/convert1.go
index 0f417a3..afb63cd 100644
--- a/test/convert1.go
+++ b/test/convert1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/ddd.go b/test/ddd.go
index 01768b8..84503f7 100644
--- a/test/ddd.go
+++ b/test/ddd.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/ddd1.go b/test/ddd1.go
index 07981af..7ea04f3 100644
--- a/test/ddd1.go
+++ b/test/ddd1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/ddd2.dir/ddd2.go b/test/ddd2.dir/ddd2.go
index c9a2675..f3f863c 100644
--- a/test/ddd2.dir/ddd2.go
+++ b/test/ddd2.dir/ddd2.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/ddd2.dir/ddd3.go b/test/ddd2.dir/ddd3.go
index 5486fe8..608091d 100644
--- a/test/ddd2.dir/ddd3.go
+++ b/test/ddd2.dir/ddd3.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/ddd2.go b/test/ddd2.go
index 0d9f634..612ba29 100644
--- a/test/ddd2.go
+++ b/test/ddd2.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/deferprint.go b/test/deferprint.go
index 72c98b1..3dc0854 100644
--- a/test/deferprint.go
+++ b/test/deferprint.go
@@ -1,6 +1,6 @@
 // cmpout
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/divide.go b/test/divide.go
index b20f106..b557041 100644
--- a/test/divide.go
+++ b/test/divide.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/divmod.go b/test/divmod.go
index ad632bc..ab85b7f 100644
--- a/test/divmod.go
+++ b/test/divmod.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/eof.go b/test/eof.go
index 06c7790..d051f33 100644
--- a/test/eof.go
+++ b/test/eof.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/eof1.go b/test/eof1.go
index 2105b89..90792ca 100644
--- a/test/eof1.go
+++ b/test/eof1.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/errchk b/test/errchk
index b07bbc7..bc8ef19 100755
--- a/test/errchk
+++ b/test/errchk
@@ -37,6 +37,17 @@ foreach(reverse 0 .. @ARGV-1) {
 	}
 }
 
+# If no files have been specified try to grab SOURCEFILES from the last
+# argument that is an existing directory if any
+unless(@file) {
+    foreach(reverse 0 .. @ARGV-1) {
+        if(-d $ARGV[$_]) {
+            @file = glob($ARGV[$_] . "/*.go");
+            last;
+        }
+    }
+}
+
 foreach $file (@file) {
 	open(SRC, $file) || die "BUG: errchk: open $file: $!";
 	$src{$file} = [<SRC>];
diff --git a/test/escape2.go b/test/escape2.go
index 6940a09..3490c29 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/escape2n.go b/test/escape2n.go
index 25b5a9b..74f6f8d 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -N -m -l
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/escape3.go b/test/escape3.go
index 4c19891..f1131a2 100644
--- a/test/escape3.go
+++ b/test/escape3.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/escape4.go b/test/escape4.go
index 248f8a9..69a54ac 100644
--- a/test/escape4.go
+++ b/test/escape4.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/escape5.go b/test/escape5.go
index 6a138ea..c4bf17b 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/escape_array.go b/test/escape_array.go
index 5da7771..0204c69 100644
--- a/test/escape_array.go
+++ b/test/escape_array.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_because.go b/test/escape_because.go
new file mode 100644
index 0000000..f0bbd0b
--- /dev/null
+++ b/test/escape_because.go
@@ -0,0 +1,177 @@
+// errorcheck -0 -m -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.
+
+// Note the doubled -m; this tests the "because" explanations for escapes,
+// and is likely to be annoyingly fragile under compiler change.
+// As long as the explanations look reasonably sane, meaning eyeball verify output of
+//    go build -gcflags '-l -m -m' escape_because.go
+// and investigate changes, feel free to update with
+//    go run run.go -update_errors -- escape_because.go
+
+package main
+
+func main() {
+}
+
+var sink interface{}
+
+type pair struct {
+	x, y *int
+}
+
+type Pairy interface {
+	EqualParts() bool
+}
+
+func (p *pair) EqualParts() bool { // ERROR "\(\*pair\).EqualParts p does not escape$"
+	return p != nil && (p.x == p.y || *p.x == *p.y)
+}
+
+func f1(p *int) { // ERROR "from \[3\]\*int literal \(array literal element\) at escape_because.go:34$" "from a \(assigned\) at escape_because.go:34$" "from a \(interface-converted\) at escape_because.go:35$" "from sink \(assigned to top level variable\) at escape_because.go:19$" "leaking param: p$"
+	a := [3]*int{p, nil, nil}
+	sink = a // ERROR "a escapes to heap$" "from sink \(assigned to top level variable\) at escape_because.go:19$"
+
+}
+
+func f2(q *int) { // ERROR "from &u \(address-of\) at escape_because.go:43$" "from &u \(interface-converted\) at escape_because.go:43$" "from pair literal \(struct literal element\) at escape_because.go:41$" "from s \(assigned\) at escape_because.go:40$" "from sink \(assigned to top level variable\) at escape_because.go:19$" "from t \(assigned\) at escape_because.go:41$" "from u \(assigned\) at escape_because.go:42$" "leaking param: q$"
+	s := q
+	t := pair{s, nil}
+	u := t    // ERROR "moved to heap: u$"
+	sink = &u // ERROR "&u escapes to heap$" "from &u \(interface-converted\) at escape_because.go:43$" "from sink \(assigned to top level variable\) at escape_because.go:19$"
+}
+
+func f3(r *int) interface{} { // ERROR "from \[\]\*int literal \(slice-literal-element\) at escape_because.go:47$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:46$" "leaking param: r to result ~r1 level=-1$"
+	c := []*int{r} // ERROR "\[\]\*int literal escapes to heap$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:46$"
+	return c       // "return" // ERROR "c escapes to heap$" "from ~r1 \(return\) at escape_because.go:46$"
+}
+
+func f4(a *int, s []*int) int { // ERROR "from \*s \(indirection\) at escape_because.go:51$" "from append\(s, a\) \(appended to slice\) at escape_because.go:52$" "from append\(s, a\) \(appendee slice\) at escape_because.go:52$" "leaking param content: s$" "leaking param: a$"
+	s = append(s, a)
+	return *(s[0])
+}
+
+func f5(s1, s2 []*int) int { // ERROR "from \*s1 \(indirection\) at escape_because.go:56$" "from \*s2 \(indirection\) at escape_because.go:56$" "from append\(s1, s2...\) \(appended slice...\) at escape_because.go:57$" "from append\(s1, s2...\) \(appendee slice\) at escape_because.go:57$" "leaking param content: s1$" "leaking param content: s2$"
+	s1 = append(s1, s2...)
+	return *(s1[0])
+}
+
+func f6(x, y *int) bool { // ERROR "f6 x does not escape$" "f6 y does not escape$"
+	p := pair{x, y}
+	var P Pairy = &p // ERROR "f6 &p does not escape$"
+	pp := P.(*pair)
+	return pp.EqualParts()
+}
+
+func f7(x map[int]*int, y int) *int { // ERROR "f7 x does not escape$"
+	z, ok := x[y]
+	if !ok {
+		return nil
+	}
+	return z
+}
+
+func f8(x int, y *int) *int { // ERROR "from ~r2 \(return\) at escape_because.go:76$" "from ~r2 \(returned from recursive function\) at escape_because.go:76$" "leaking param: y$" "moved to heap: x$"
+	if x <= 0 {
+		return y
+	}
+	x--
+	return f8(*y, &x) // ERROR "&x escapes to heap$" "from y \(arg to recursive call\) at escape_because.go:76$" "from ~r2 \(return\) at escape_because.go:76$" "from ~r2 \(returned from recursive function\) at escape_because.go:76$"
+}
+
+func f9(x int, y ...*int) *int { // ERROR "from y\[0\] \(dot of pointer\) at escape_because.go:86$" "from ~r2 \(return\) at escape_because.go:84$" "from ~r2 \(returned from recursive function\) at escape_because.go:84$" "leaking param content: y$" "leaking param: y to result ~r2 level=1$" "moved to heap: x$"
+	if x <= 0 {
+		return y[0]
+	}
+	x--
+	return f9(*y[0], &x) // ERROR "&x escapes to heap$" "f9 ... argument does not escape$" "from ... argument \(... arg to recursive call\) at escape_because.go:89$"
+}
+
+func f10(x map[*int]*int, y, z *int) *int { // ERROR "f10 x does not escape$" "from x\[y\] \(key of map put\) at escape_because.go:93$" "from x\[y\] \(value of map put\) at escape_because.go:93$" "leaking param: y$" "leaking param: z$"
+	x[y] = z
+	return z
+}
+
+func f11(x map[*int]*int, y, z *int) map[*int]*int { // ERROR "f11 x does not escape$" "from map\[\*int\]\*int literal \(map literal key\) at escape_because.go:98$" "from map\[\*int\]\*int literal \(map literal value\) at escape_because.go:98$" "leaking param: y$" "leaking param: z$"
+	return map[*int]*int{y: z} // ERROR "from ~r3 \(return\) at escape_because.go:97$" "map\[\*int\]\*int literal escapes to heap$"
+}
+
+// The list below is all of the why-escapes messages seen building the escape analysis tests.
+/*
+   for i in escape*go ; do echo compile $i; go build -gcflags '-l -m -m' $i >& `basename $i .go`.log ; done
+   grep 'from .* at ' escape*.log | sed -e 's/^.*(\([^()]*\))[^()]*$/\1/' | sort -u
+*/
+// sed RE above assumes that (reason) is the last parenthesized phrase in the line,
+// and that none of the reasons contains any parentheses
+
+/*
+... arg to recursive call
+address-of
+appended slice...
+appended to slice
+appendee slice
+arg to ...
+arg to recursive call
+array literal element
+array-element-equals
+assign-pair
+assign-pair-dot-type
+assign-pair-func-call
+assigned
+assigned to top level variable
+call part
+captured by a closure
+closure-var
+converted
+copied slice
+defer func
+defer func ...
+defer func arg
+dot
+dot of pointer
+dot-equals
+fixed-array-index-of
+go func
+go func ...
+go func arg
+indirection
+interface-converted
+key of map put
+map literal key
+map literal value
+parameter to indirect call
+passed to function[content escapes]
+passed to function[unknown]
+passed-to-and-returned-from-function
+pointer literal
+range
+range-deref
+receiver in indirect call
+return
+returned from recursive function
+send
+slice
+slice-element-equals
+slice-literal-element
+star-dot-equals
+star-equals
+struct literal element
+switch case
+too large for stack
+value of map put
+*/
+
+// Expected, but not yet seen (they may be unreachable):
+
+/*
+append-first-arg
+assign-pair-mapr
+assign-pair-receive
+call receiver
+map index
+panic
+pointer literal [assign]
+slice literal element
+*/
diff --git a/test/escape_calls.go b/test/escape_calls.go
index 8c9a6da..20cb643 100644
--- a/test/escape_calls.go
+++ b/test/escape_calls.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_closure.go b/test/escape_closure.go
index f36073e..e9cf776 100644
--- a/test/escape_closure.go
+++ b/test/escape_closure.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_field.go b/test/escape_field.go
index 16d1e74..e8835ae 100644
--- a/test/escape_field.go
+++ b/test/escape_field.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_iface.go b/test/escape_iface.go
index 2b1144a..50a5132 100644
--- a/test/escape_iface.go
+++ b/test/escape_iface.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
@@ -225,3 +225,23 @@ func dotTypeEscape() *T2 { // #11931
 		T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap"
 	}
 }
+
+func dotTypeEscape2() { // #13805
+	{
+		i := 0
+		var v int
+		var x interface{} = i // ERROR "i does not escape"
+		*(&v) = x.(int) // ERROR "&v does not escape"
+	}
+	{
+		i := 0
+		var x interface{} = i // ERROR "i does not escape"
+		sink = x.(int)        // ERROR "x.\(int\) escapes to heap"
+
+	}
+	{
+		i := 0 // ERROR "moved to heap: i"
+		var x interface{} = &i // ERROR "&i escapes to heap"
+		sink = x.(*int)        // ERROR "x.\(\*int\) escapes to heap"
+	}
+}
diff --git a/test/escape_indir.go b/test/escape_indir.go
index fe03c3f..aac4e67 100644
--- a/test/escape_indir.go
+++ b/test/escape_indir.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_level.go b/test/escape_level.go
index 867c81a..490f615 100644
--- a/test/escape_level.go
+++ b/test/escape_level.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_map.go b/test/escape_map.go
index 868c456..99cbd48 100644
--- a/test/escape_map.go
+++ b/test/escape_map.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_param.go b/test/escape_param.go
index cfbcd51..2c43b96 100644
--- a/test/escape_param.go
+++ b/test/escape_param.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_slice.go b/test/escape_slice.go
index 0b65997..ffd7cdb 100644
--- a/test/escape_slice.go
+++ b/test/escape_slice.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_struct_param1.go b/test/escape_struct_param1.go
index e30e327..076fbc8 100644
--- a/test/escape_struct_param1.go
+++ b/test/escape_struct_param1.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_struct_param2.go b/test/escape_struct_param2.go
index c10c336..d5305d4 100644
--- a/test/escape_struct_param2.go
+++ b/test/escape_struct_param2.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/escape_struct_return.go b/test/escape_struct_return.go
index b423ebd..565f08e 100644
--- a/test/escape_struct_return.go
+++ b/test/escape_struct_return.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/bug083.dir/bug0.go b/test/fixedbugs/bug083.dir/bug0.go
index e312256..2f59d81 100644
--- a/test/fixedbugs/bug083.dir/bug0.go
+++ b/test/fixedbugs/bug083.dir/bug0.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug083.dir/bug1.go b/test/fixedbugs/bug083.dir/bug1.go
index 486fe76..ea5bcfe 100644
--- a/test/fixedbugs/bug083.dir/bug1.go
+++ b/test/fixedbugs/bug083.dir/bug1.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug088.dir/bug0.go b/test/fixedbugs/bug088.dir/bug0.go
index af9d991..7a6e347 100644
--- a/test/fixedbugs/bug088.dir/bug0.go
+++ b/test/fixedbugs/bug088.dir/bug0.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug088.dir/bug1.go b/test/fixedbugs/bug088.dir/bug1.go
index cadf0e6..2568e37 100644
--- a/test/fixedbugs/bug088.dir/bug1.go
+++ b/test/fixedbugs/bug088.dir/bug1.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug106.dir/bug0.go b/test/fixedbugs/bug106.dir/bug0.go
index d9c26a0..7494c58 100644
--- a/test/fixedbugs/bug106.dir/bug0.go
+++ b/test/fixedbugs/bug106.dir/bug0.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug106.dir/bug1.go b/test/fixedbugs/bug106.dir/bug1.go
index 0f1d20e..eff0d36 100644
--- a/test/fixedbugs/bug106.dir/bug1.go
+++ b/test/fixedbugs/bug106.dir/bug1.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug108.go b/test/fixedbugs/bug108.go
index 9f2a27e..cfec4c9 100644
--- a/test/fixedbugs/bug108.go
+++ b/test/fixedbugs/bug108.go
@@ -6,6 +6,6 @@
 
 package main
 func f() {
-	v := 1 << 1025;		// ERROR "overflow|stupid shift"
+	v := 1 << 1025;		// ERROR "overflow|shift count too large"
 	_ = v
 }
diff --git a/test/fixedbugs/bug133.dir/bug0.go b/test/fixedbugs/bug133.dir/bug0.go
index 48cd104..19a2bfb 100644
--- a/test/fixedbugs/bug133.dir/bug0.go
+++ b/test/fixedbugs/bug133.dir/bug0.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug133.dir/bug1.go b/test/fixedbugs/bug133.dir/bug1.go
index 7562147..dd59b2f 100644
--- a/test/fixedbugs/bug133.dir/bug1.go
+++ b/test/fixedbugs/bug133.dir/bug1.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug133.dir/bug2.go b/test/fixedbugs/bug133.dir/bug2.go
index e531001..b6184c2 100644
--- a/test/fixedbugs/bug133.dir/bug2.go
+++ b/test/fixedbugs/bug133.dir/bug2.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug13343.go b/test/fixedbugs/bug13343.go
index 4c30dac..5dc736d 100644
--- a/test/fixedbugs/bug13343.go
+++ b/test/fixedbugs/bug13343.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/bug1515.go b/test/fixedbugs/bug1515.go
index a4baccd..5fef5ad 100644
--- a/test/fixedbugs/bug1515.go
+++ b/test/fixedbugs/bug1515.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug160.dir/x.go b/test/fixedbugs/bug160.dir/x.go
index bd52c6c..2673552 100644
--- a/test/fixedbugs/bug160.dir/x.go
+++ b/test/fixedbugs/bug160.dir/x.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug160.dir/y.go b/test/fixedbugs/bug160.dir/y.go
index 27e2f35..428808d 100644
--- a/test/fixedbugs/bug160.dir/y.go
+++ b/test/fixedbugs/bug160.dir/y.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug203.go b/test/fixedbugs/bug203.go
index 2fb084b..68647ec 100644
--- a/test/fixedbugs/bug203.go
+++ b/test/fixedbugs/bug203.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug227.go b/test/fixedbugs/bug227.go
index ea8d02d..afbdd97 100644
--- a/test/fixedbugs/bug227.go
+++ b/test/fixedbugs/bug227.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug228.go b/test/fixedbugs/bug228.go
index 3fccd17..f7ac670 100644
--- a/test/fixedbugs/bug228.go
+++ b/test/fixedbugs/bug228.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug229.go b/test/fixedbugs/bug229.go
index 1977688..4baf65e 100644
--- a/test/fixedbugs/bug229.go
+++ b/test/fixedbugs/bug229.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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.
 
@@ -14,7 +14,7 @@ func main() {
 	// make sure error mentions that
 	// name is unexported, not just "name not found".
 
-	t.name = nil	// ERROR "unexported"
+	t.common.name = nil	// ERROR "unexported"
 	
 	println(testing.anyLowercaseName("asdf"))	// ERROR "unexported" "undefined: testing.anyLowercaseName"
 }
diff --git a/test/fixedbugs/bug230.go b/test/fixedbugs/bug230.go
index 210acc4..e5eead5 100644
--- a/test/fixedbugs/bug230.go
+++ b/test/fixedbugs/bug230.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug231.go b/test/fixedbugs/bug231.go
index a9d409b..f64ddc3 100644
--- a/test/fixedbugs/bug231.go
+++ b/test/fixedbugs/bug231.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug232.go b/test/fixedbugs/bug232.go
index d18727e..10b0c52 100644
--- a/test/fixedbugs/bug232.go
+++ b/test/fixedbugs/bug232.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug233.go b/test/fixedbugs/bug233.go
index 63f8ee2..d4e1e07 100644
--- a/test/fixedbugs/bug233.go
+++ b/test/fixedbugs/bug233.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug234.go b/test/fixedbugs/bug234.go
index 9f503f0..0d37ce2 100644
--- a/test/fixedbugs/bug234.go
+++ b/test/fixedbugs/bug234.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug235.go b/test/fixedbugs/bug235.go
index d12d9e7..a33092b 100644
--- a/test/fixedbugs/bug235.go
+++ b/test/fixedbugs/bug235.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug236.go b/test/fixedbugs/bug236.go
index 6c24556..de7e8e3 100644
--- a/test/fixedbugs/bug236.go
+++ b/test/fixedbugs/bug236.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug237.go b/test/fixedbugs/bug237.go
index 58996ca..75d6132 100644
--- a/test/fixedbugs/bug237.go
+++ b/test/fixedbugs/bug237.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug243.go b/test/fixedbugs/bug243.go
index 4870c36..5b6bb75 100644
--- a/test/fixedbugs/bug243.go
+++ b/test/fixedbugs/bug243.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug245.go b/test/fixedbugs/bug245.go
index c607a6d..adf62f9 100644
--- a/test/fixedbugs/bug245.go
+++ b/test/fixedbugs/bug245.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug247.go b/test/fixedbugs/bug247.go
index b6851e1..6550bd8 100644
--- a/test/fixedbugs/bug247.go
+++ b/test/fixedbugs/bug247.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug249.go b/test/fixedbugs/bug249.go
index dc92245..ec9699a 100644
--- a/test/fixedbugs/bug249.go
+++ b/test/fixedbugs/bug249.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug250.go b/test/fixedbugs/bug250.go
index 5140f3e..9fb34c3 100644
--- a/test/fixedbugs/bug250.go
+++ b/test/fixedbugs/bug250.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug251.go b/test/fixedbugs/bug251.go
index 43d9d52..f061723 100644
--- a/test/fixedbugs/bug251.go
+++ b/test/fixedbugs/bug251.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug252.go b/test/fixedbugs/bug252.go
index 6f007fb..f678925 100644
--- a/test/fixedbugs/bug252.go
+++ b/test/fixedbugs/bug252.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug253.go b/test/fixedbugs/bug253.go
index f6ab712..933f3f1 100644
--- a/test/fixedbugs/bug253.go
+++ b/test/fixedbugs/bug253.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug254.go b/test/fixedbugs/bug254.go
index 9b1c819..3902cd5 100644
--- a/test/fixedbugs/bug254.go
+++ b/test/fixedbugs/bug254.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug255.go b/test/fixedbugs/bug255.go
index 65ed1b8..cc7d92f 100644
--- a/test/fixedbugs/bug255.go
+++ b/test/fixedbugs/bug255.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug256.go b/test/fixedbugs/bug256.go
index 0498a40..705a032 100644
--- a/test/fixedbugs/bug256.go
+++ b/test/fixedbugs/bug256.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug257.go b/test/fixedbugs/bug257.go
index 003f3ff..b05c37a 100644
--- a/test/fixedbugs/bug257.go
+++ b/test/fixedbugs/bug257.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug258.go b/test/fixedbugs/bug258.go
index d362e5a..075da87 100644
--- a/test/fixedbugs/bug258.go
+++ b/test/fixedbugs/bug258.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug259.go b/test/fixedbugs/bug259.go
index e4dcaeb..857b442 100644
--- a/test/fixedbugs/bug259.go
+++ b/test/fixedbugs/bug259.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug261.go b/test/fixedbugs/bug261.go
index f7879b0..abe6431 100644
--- a/test/fixedbugs/bug261.go
+++ b/test/fixedbugs/bug261.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug266.go b/test/fixedbugs/bug266.go
index d4da891..5d2334c 100644
--- a/test/fixedbugs/bug266.go
+++ b/test/fixedbugs/bug266.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug269.go b/test/fixedbugs/bug269.go
index 60ee7ee..ec0dbc6 100644
--- a/test/fixedbugs/bug269.go
+++ b/test/fixedbugs/bug269.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug271.go b/test/fixedbugs/bug271.go
index 30d9bb1..a6abbfe 100644
--- a/test/fixedbugs/bug271.go
+++ b/test/fixedbugs/bug271.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug272.go b/test/fixedbugs/bug272.go
index f943d68..6b8862f 100644
--- a/test/fixedbugs/bug272.go
+++ b/test/fixedbugs/bug272.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug273.go b/test/fixedbugs/bug273.go
index b4e3f65..b6258d5 100644
--- a/test/fixedbugs/bug273.go
+++ b/test/fixedbugs/bug273.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug274.go b/test/fixedbugs/bug274.go
index e57d147..e93f30e 100644
--- a/test/fixedbugs/bug274.go
+++ b/test/fixedbugs/bug274.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug275.go b/test/fixedbugs/bug275.go
index f5f6b14..d3be754 100644
--- a/test/fixedbugs/bug275.go
+++ b/test/fixedbugs/bug275.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug278.go b/test/fixedbugs/bug278.go
index 68a3d81..4817ebf 100644
--- a/test/fixedbugs/bug278.go
+++ b/test/fixedbugs/bug278.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug279.go b/test/fixedbugs/bug279.go
index 726ba60..3b1df3b 100644
--- a/test/fixedbugs/bug279.go
+++ b/test/fixedbugs/bug279.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug280.go b/test/fixedbugs/bug280.go
index 3925b9a..afec57f 100644
--- a/test/fixedbugs/bug280.go
+++ b/test/fixedbugs/bug280.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug281.go b/test/fixedbugs/bug281.go
index 92c8d86..c65530f 100644
--- a/test/fixedbugs/bug281.go
+++ b/test/fixedbugs/bug281.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug282.dir/p1.go b/test/fixedbugs/bug282.dir/p1.go
index b562755..0f7422c 100644
--- a/test/fixedbugs/bug282.dir/p1.go
+++ b/test/fixedbugs/bug282.dir/p1.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug282.dir/p2.go b/test/fixedbugs/bug282.dir/p2.go
index 3f8bd9d..f614507 100644
--- a/test/fixedbugs/bug282.dir/p2.go
+++ b/test/fixedbugs/bug282.dir/p2.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug283.go b/test/fixedbugs/bug283.go
index 1f7f6e0..ef1953b 100644
--- a/test/fixedbugs/bug283.go
+++ b/test/fixedbugs/bug283.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug285.go b/test/fixedbugs/bug285.go
index e0b3766..0632ab4 100644
--- a/test/fixedbugs/bug285.go
+++ b/test/fixedbugs/bug285.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug286.go b/test/fixedbugs/bug286.go
index 44f0515..b1271f4 100644
--- a/test/fixedbugs/bug286.go
+++ b/test/fixedbugs/bug286.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug287.go b/test/fixedbugs/bug287.go
index 2ed81c5..94582a8 100644
--- a/test/fixedbugs/bug287.go
+++ b/test/fixedbugs/bug287.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug288.go b/test/fixedbugs/bug288.go
index d2461e6..0a53d32 100644
--- a/test/fixedbugs/bug288.go
+++ b/test/fixedbugs/bug288.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug289.go b/test/fixedbugs/bug289.go
index 3c6b687..5a30979 100644
--- a/test/fixedbugs/bug289.go
+++ b/test/fixedbugs/bug289.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug290.go b/test/fixedbugs/bug290.go
index 46ebc1f..4eee285 100644
--- a/test/fixedbugs/bug290.go
+++ b/test/fixedbugs/bug290.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug291.go b/test/fixedbugs/bug291.go
index d627a9d..ac84a7e 100644
--- a/test/fixedbugs/bug291.go
+++ b/test/fixedbugs/bug291.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug292.go b/test/fixedbugs/bug292.go
index 0c24912..1130a28 100644
--- a/test/fixedbugs/bug292.go
+++ b/test/fixedbugs/bug292.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug293.go b/test/fixedbugs/bug293.go
index c985305..ae7cc1f 100644
--- a/test/fixedbugs/bug293.go
+++ b/test/fixedbugs/bug293.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug294.go b/test/fixedbugs/bug294.go
index ec41fe8..b35b771 100644
--- a/test/fixedbugs/bug294.go
+++ b/test/fixedbugs/bug294.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug295.go b/test/fixedbugs/bug295.go
index 63a12a3..d1c961c 100644
--- a/test/fixedbugs/bug295.go
+++ b/test/fixedbugs/bug295.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug296.go b/test/fixedbugs/bug296.go
index a7c4e0c..2ef4e66 100644
--- a/test/fixedbugs/bug296.go
+++ b/test/fixedbugs/bug296.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug297.go b/test/fixedbugs/bug297.go
index ee2ff92..852d208 100644
--- a/test/fixedbugs/bug297.go
+++ b/test/fixedbugs/bug297.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug298.go b/test/fixedbugs/bug298.go
index bd362ac..0aed032 100644
--- a/test/fixedbugs/bug298.go
+++ b/test/fixedbugs/bug298.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug299.go b/test/fixedbugs/bug299.go
index 1067fd1..cf11bcc 100644
--- a/test/fixedbugs/bug299.go
+++ b/test/fixedbugs/bug299.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug300.go b/test/fixedbugs/bug300.go
index 1ef43a0..1695a96 100644
--- a/test/fixedbugs/bug300.go
+++ b/test/fixedbugs/bug300.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug301.go b/test/fixedbugs/bug301.go
index fc52503..2be62b8 100644
--- a/test/fixedbugs/bug301.go
+++ b/test/fixedbugs/bug301.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug302.dir/main.go b/test/fixedbugs/bug302.dir/main.go
index 281f908..52c054f 100644
--- a/test/fixedbugs/bug302.dir/main.go
+++ b/test/fixedbugs/bug302.dir/main.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug302.dir/p.go b/test/fixedbugs/bug302.dir/p.go
index 7c54b90..0be521b 100644
--- a/test/fixedbugs/bug302.dir/p.go
+++ b/test/fixedbugs/bug302.dir/p.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug302.go b/test/fixedbugs/bug302.go
index 42345a9..e4de25d 100644
--- a/test/fixedbugs/bug302.go
+++ b/test/fixedbugs/bug302.go
@@ -1,7 +1,7 @@
 // +build !nacl
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug303.go b/test/fixedbugs/bug303.go
index 94ca07e..aef8b22 100644
--- a/test/fixedbugs/bug303.go
+++ b/test/fixedbugs/bug303.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug304.go b/test/fixedbugs/bug304.go
index ad71b20..4073073 100644
--- a/test/fixedbugs/bug304.go
+++ b/test/fixedbugs/bug304.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug305.go b/test/fixedbugs/bug305.go
index d0a4b24..0c34b1a 100644
--- a/test/fixedbugs/bug305.go
+++ b/test/fixedbugs/bug305.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug306.dir/p1.go b/test/fixedbugs/bug306.dir/p1.go
index bf87ea1..b285518 100644
--- a/test/fixedbugs/bug306.dir/p1.go
+++ b/test/fixedbugs/bug306.dir/p1.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug306.dir/p2.go b/test/fixedbugs/bug306.dir/p2.go
index 3f8bd9d..f614507 100644
--- a/test/fixedbugs/bug306.dir/p2.go
+++ b/test/fixedbugs/bug306.dir/p2.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug308.go b/test/fixedbugs/bug308.go
index 5bea517..a23903c 100644
--- a/test/fixedbugs/bug308.go
+++ b/test/fixedbugs/bug308.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug309.go b/test/fixedbugs/bug309.go
index 948ca5c..d707aa3 100644
--- a/test/fixedbugs/bug309.go
+++ b/test/fixedbugs/bug309.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug311.go b/test/fixedbugs/bug311.go
index edcd975..f5cab44 100644
--- a/test/fixedbugs/bug311.go
+++ b/test/fixedbugs/bug311.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug312.go b/test/fixedbugs/bug312.go
index c7c17e1..af423e5 100644
--- a/test/fixedbugs/bug312.go
+++ b/test/fixedbugs/bug312.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug313.dir/a.go b/test/fixedbugs/bug313.dir/a.go
index cb4ca72..335f84d 100644
--- a/test/fixedbugs/bug313.dir/a.go
+++ b/test/fixedbugs/bug313.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug313.dir/b.go b/test/fixedbugs/bug313.dir/b.go
index 7eda72b..26e6413 100644
--- a/test/fixedbugs/bug313.dir/b.go
+++ b/test/fixedbugs/bug313.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug313.go b/test/fixedbugs/bug313.go
index a7c1d36..f7e0238 100644
--- a/test/fixedbugs/bug313.go
+++ b/test/fixedbugs/bug313.go
@@ -1,6 +1,6 @@
 // errorcheckdir
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/fixedbugs/bug317.go b/test/fixedbugs/bug317.go
index 3ff4dc4..4cd9ec2 100644
--- a/test/fixedbugs/bug317.go
+++ b/test/fixedbugs/bug317.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug319.go b/test/fixedbugs/bug319.go
index f8e959a..b93106d 100644
--- a/test/fixedbugs/bug319.go
+++ b/test/fixedbugs/bug319.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug320.go b/test/fixedbugs/bug320.go
index c2dd31b..0406b96 100644
--- a/test/fixedbugs/bug320.go
+++ b/test/fixedbugs/bug320.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug321.go b/test/fixedbugs/bug321.go
index 7d01827..19970af 100644
--- a/test/fixedbugs/bug321.go
+++ b/test/fixedbugs/bug321.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug323.go b/test/fixedbugs/bug323.go
index 9730ae5..3cb8eaa 100644
--- a/test/fixedbugs/bug323.go
+++ b/test/fixedbugs/bug323.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug325.go b/test/fixedbugs/bug325.go
index 6ccd0e3..e6528ae 100644
--- a/test/fixedbugs/bug325.go
+++ b/test/fixedbugs/bug325.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug326.go b/test/fixedbugs/bug326.go
index 57f6471..75d620c 100644
--- a/test/fixedbugs/bug326.go
+++ b/test/fixedbugs/bug326.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug327.go b/test/fixedbugs/bug327.go
index 0598d95..ecb5d22 100644
--- a/test/fixedbugs/bug327.go
+++ b/test/fixedbugs/bug327.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug328.go b/test/fixedbugs/bug328.go
index 73ab46d..180af05 100644
--- a/test/fixedbugs/bug328.go
+++ b/test/fixedbugs/bug328.go
@@ -1,6 +1,6 @@
 // cmpout
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug329.go b/test/fixedbugs/bug329.go
index 74fc781..37c93d0 100644
--- a/test/fixedbugs/bug329.go
+++ b/test/fixedbugs/bug329.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug330.go b/test/fixedbugs/bug330.go
index ef6a077..2f33feb 100644
--- a/test/fixedbugs/bug330.go
+++ b/test/fixedbugs/bug330.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug331.go b/test/fixedbugs/bug331.go
index fac0e36..9eb57cd 100644
--- a/test/fixedbugs/bug331.go
+++ b/test/fixedbugs/bug331.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug332.go b/test/fixedbugs/bug332.go
index 702779b..91ae0b2 100644
--- a/test/fixedbugs/bug332.go
+++ b/test/fixedbugs/bug332.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug333.go b/test/fixedbugs/bug333.go
index bb690f0..149843a 100644
--- a/test/fixedbugs/bug333.go
+++ b/test/fixedbugs/bug333.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug334.go b/test/fixedbugs/bug334.go
index bd67169..9558c06 100644
--- a/test/fixedbugs/bug334.go
+++ b/test/fixedbugs/bug334.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug335.dir/a.go b/test/fixedbugs/bug335.dir/a.go
index 256c110..6ecc5c4 100644
--- a/test/fixedbugs/bug335.dir/a.go
+++ b/test/fixedbugs/bug335.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug335.dir/b.go b/test/fixedbugs/bug335.dir/b.go
index 1474470..a7735a8 100644
--- a/test/fixedbugs/bug335.dir/b.go
+++ b/test/fixedbugs/bug335.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug335.go b/test/fixedbugs/bug335.go
index 37c97d7..fda9eb8 100644
--- a/test/fixedbugs/bug335.go
+++ b/test/fixedbugs/bug335.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug336.go b/test/fixedbugs/bug336.go
index fbf2320..fbcd3a5 100644
--- a/test/fixedbugs/bug336.go
+++ b/test/fixedbugs/bug336.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug337.go b/test/fixedbugs/bug337.go
index 38dc665..1a0616f 100644
--- a/test/fixedbugs/bug337.go
+++ b/test/fixedbugs/bug337.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug338.go b/test/fixedbugs/bug338.go
index c2193fc..a4537a4 100644
--- a/test/fixedbugs/bug338.go
+++ b/test/fixedbugs/bug338.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug339.go b/test/fixedbugs/bug339.go
index 59921d4..36be761 100644
--- a/test/fixedbugs/bug339.go
+++ b/test/fixedbugs/bug339.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug340.go b/test/fixedbugs/bug340.go
index d996ab6..118bbac 100644
--- a/test/fixedbugs/bug340.go
+++ b/test/fixedbugs/bug340.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug341.go b/test/fixedbugs/bug341.go
index db1af3e..baab282 100644
--- a/test/fixedbugs/bug341.go
+++ b/test/fixedbugs/bug341.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug342.go b/test/fixedbugs/bug342.go
index ffcb668..f90f6f3 100644
--- a/test/fixedbugs/bug342.go
+++ b/test/fixedbugs/bug342.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug343.go b/test/fixedbugs/bug343.go
index 8220108..fd8bd76 100644
--- a/test/fixedbugs/bug343.go
+++ b/test/fixedbugs/bug343.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug344.go b/test/fixedbugs/bug344.go
index 4a92624..b53abd2 100644
--- a/test/fixedbugs/bug344.go
+++ b/test/fixedbugs/bug344.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug345.dir/io.go b/test/fixedbugs/bug345.dir/io.go
index 1d695c3..ca7a509 100644
--- a/test/fixedbugs/bug345.dir/io.go
+++ b/test/fixedbugs/bug345.dir/io.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug345.dir/main.go b/test/fixedbugs/bug345.dir/main.go
index ddba8da..6e4fdf4 100644
--- a/test/fixedbugs/bug345.dir/main.go
+++ b/test/fixedbugs/bug345.dir/main.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug345.go b/test/fixedbugs/bug345.go
index e291a55..dcf62f0 100644
--- a/test/fixedbugs/bug345.go
+++ b/test/fixedbugs/bug345.go
@@ -1,7 +1,7 @@
 // +build !nacl,!plan9,!windows
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug347.go b/test/fixedbugs/bug347.go
index 08edf0f..92afb2e 100644
--- a/test/fixedbugs/bug347.go
+++ b/test/fixedbugs/bug347.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug348.go b/test/fixedbugs/bug348.go
index 54a289a..c7f1346 100644
--- a/test/fixedbugs/bug348.go
+++ b/test/fixedbugs/bug348.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug349.go b/test/fixedbugs/bug349.go
index a3e6bd1..a6e8386 100644
--- a/test/fixedbugs/bug349.go
+++ b/test/fixedbugs/bug349.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug350.go b/test/fixedbugs/bug350.go
index 5ce8996..cdce1cf 100644
--- a/test/fixedbugs/bug350.go
+++ b/test/fixedbugs/bug350.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug351.go b/test/fixedbugs/bug351.go
index 4c5c7c3..8fd63e3 100644
--- a/test/fixedbugs/bug351.go
+++ b/test/fixedbugs/bug351.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug352.go b/test/fixedbugs/bug352.go
index 1ae2d61..464ad7b 100644
--- a/test/fixedbugs/bug352.go
+++ b/test/fixedbugs/bug352.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug353.go b/test/fixedbugs/bug353.go
index 2a532c4..4a65f77 100644
--- a/test/fixedbugs/bug353.go
+++ b/test/fixedbugs/bug353.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug354.go b/test/fixedbugs/bug354.go
index 1245d91..293180f 100644
--- a/test/fixedbugs/bug354.go
+++ b/test/fixedbugs/bug354.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug355.go b/test/fixedbugs/bug355.go
index fcf859b..880353a 100644
--- a/test/fixedbugs/bug355.go
+++ b/test/fixedbugs/bug355.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug356.go b/test/fixedbugs/bug356.go
index 273c5b8..6d93860 100644
--- a/test/fixedbugs/bug356.go
+++ b/test/fixedbugs/bug356.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug357.go b/test/fixedbugs/bug357.go
index ceb2009..e9db50e 100644
--- a/test/fixedbugs/bug357.go
+++ b/test/fixedbugs/bug357.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug358.go b/test/fixedbugs/bug358.go
index 6f9d73c..5ca0be1 100644
--- a/test/fixedbugs/bug358.go
+++ b/test/fixedbugs/bug358.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug361.go b/test/fixedbugs/bug361.go
index 3e3b7c1..8e28243 100644
--- a/test/fixedbugs/bug361.go
+++ b/test/fixedbugs/bug361.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug362.go b/test/fixedbugs/bug362.go
index b888ccb..771d13d 100644
--- a/test/fixedbugs/bug362.go
+++ b/test/fixedbugs/bug362.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug363.go b/test/fixedbugs/bug363.go
index 615c668..1bd1400 100644
--- a/test/fixedbugs/bug363.go
+++ b/test/fixedbugs/bug363.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug365.go b/test/fixedbugs/bug365.go
index 795323b..985b6de 100644
--- a/test/fixedbugs/bug365.go
+++ b/test/fixedbugs/bug365.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug366.go b/test/fixedbugs/bug366.go
index 33a1a5a..3af5bea 100644
--- a/test/fixedbugs/bug366.go
+++ b/test/fixedbugs/bug366.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug368.go b/test/fixedbugs/bug368.go
index c38cc7f..353ea5a 100644
--- a/test/fixedbugs/bug368.go
+++ b/test/fixedbugs/bug368.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug369.dir/main.go b/test/fixedbugs/bug369.dir/main.go
index 1c9e36b..4812602 100644
--- a/test/fixedbugs/bug369.dir/main.go
+++ b/test/fixedbugs/bug369.dir/main.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug369.dir/pkg.go b/test/fixedbugs/bug369.dir/pkg.go
index cf57041..9964347 100644
--- a/test/fixedbugs/bug369.dir/pkg.go
+++ b/test/fixedbugs/bug369.dir/pkg.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug369.go b/test/fixedbugs/bug369.go
index dd48da8..60162ab 100644
--- a/test/fixedbugs/bug369.go
+++ b/test/fixedbugs/bug369.go
@@ -1,7 +1,7 @@
 // +build !nacl,!windows
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug370.go b/test/fixedbugs/bug370.go
index 246bc7c..c5165c5 100644
--- a/test/fixedbugs/bug370.go
+++ b/test/fixedbugs/bug370.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug371.go b/test/fixedbugs/bug371.go
index 86c73bf..3a626e5 100644
--- a/test/fixedbugs/bug371.go
+++ b/test/fixedbugs/bug371.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug372.go b/test/fixedbugs/bug372.go
index 3457856..5fba131 100644
--- a/test/fixedbugs/bug372.go
+++ b/test/fixedbugs/bug372.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug373.go b/test/fixedbugs/bug373.go
index e91f26d..aa0f5d1 100644
--- a/test/fixedbugs/bug373.go
+++ b/test/fixedbugs/bug373.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug374.go b/test/fixedbugs/bug374.go
index 4f0b721..2d604cb 100644
--- a/test/fixedbugs/bug374.go
+++ b/test/fixedbugs/bug374.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug375.go b/test/fixedbugs/bug375.go
index cb159b0..08d5afc 100644
--- a/test/fixedbugs/bug375.go
+++ b/test/fixedbugs/bug375.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug376.go b/test/fixedbugs/bug376.go
index 5fbbc9c..7bef58b 100644
--- a/test/fixedbugs/bug376.go
+++ b/test/fixedbugs/bug376.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug378.go b/test/fixedbugs/bug378.go
index f3346c6..c7b0dac 100644
--- a/test/fixedbugs/bug378.go
+++ b/test/fixedbugs/bug378.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug379.go b/test/fixedbugs/bug379.go
index 14abe46..5638123 100644
--- a/test/fixedbugs/bug379.go
+++ b/test/fixedbugs/bug379.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug380.go b/test/fixedbugs/bug380.go
index 96e1ede..0cb3487 100644
--- a/test/fixedbugs/bug380.go
+++ b/test/fixedbugs/bug380.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug381.go b/test/fixedbugs/bug381.go
index 0253e14..a0a1c8a 100644
--- a/test/fixedbugs/bug381.go
+++ b/test/fixedbugs/bug381.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug382.dir/pkg.go b/test/fixedbugs/bug382.dir/pkg.go
index f8d75d4..92fe4e3 100644
--- a/test/fixedbugs/bug382.dir/pkg.go
+++ b/test/fixedbugs/bug382.dir/pkg.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug383.go b/test/fixedbugs/bug383.go
index 503779c..dc2ecd6 100644
--- a/test/fixedbugs/bug383.go
+++ b/test/fixedbugs/bug383.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug384.go b/test/fixedbugs/bug384.go
index 0233c19..d02352b 100644
--- a/test/fixedbugs/bug384.go
+++ b/test/fixedbugs/bug384.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug385_32.go b/test/fixedbugs/bug385_32.go
index daf2a08..73a1311 100644
--- a/test/fixedbugs/bug385_32.go
+++ b/test/fixedbugs/bug385_32.go
@@ -1,7 +1,7 @@
 // +build 386 amd64p32 arm
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug385_64.go b/test/fixedbugs/bug385_64.go
index 6789c0a..0f941ca 100644
--- a/test/fixedbugs/bug385_64.go
+++ b/test/fixedbugs/bug385_64.go
@@ -1,7 +1,7 @@
 // +build amd64
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug386.go b/test/fixedbugs/bug386.go
index ec358bd..889c8b0 100644
--- a/test/fixedbugs/bug386.go
+++ b/test/fixedbugs/bug386.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug387.go b/test/fixedbugs/bug387.go
index 59d5ef9..d885445 100644
--- a/test/fixedbugs/bug387.go
+++ b/test/fixedbugs/bug387.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug388.go b/test/fixedbugs/bug388.go
index d41f9ea..af0c9d9 100644
--- a/test/fixedbugs/bug388.go
+++ b/test/fixedbugs/bug388.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -9,7 +9,7 @@
 package main
 import "runtime"
 
-func foo(runtime.UintType, i int) {  // ERROR "cannot declare name runtime.UintType|named/anonymous mix|undefined identifier"
+func foo(runtime.UintType, i int) {  // ERROR "cannot declare name runtime.UintType|mixed named and unnamed|undefined identifier"
 	println(i, runtime.UintType) // GCCGO_ERROR "undefined identifier"
 }
 
diff --git a/test/fixedbugs/bug389.go b/test/fixedbugs/bug389.go
index 55a02e0..14804c8 100644
--- a/test/fixedbugs/bug389.go
+++ b/test/fixedbugs/bug389.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug391.go b/test/fixedbugs/bug391.go
index 07d129d..9211b1c 100644
--- a/test/fixedbugs/bug391.go
+++ b/test/fixedbugs/bug391.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug392.dir/one.go b/test/fixedbugs/bug392.dir/one.go
index 8242f28..aba8649 100644
--- a/test/fixedbugs/bug392.dir/one.go
+++ b/test/fixedbugs/bug392.dir/one.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug392.dir/pkg2.go b/test/fixedbugs/bug392.dir/pkg2.go
index 8320b2f..2ee41f0 100644
--- a/test/fixedbugs/bug392.dir/pkg2.go
+++ b/test/fixedbugs/bug392.dir/pkg2.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug392.dir/pkg3.go b/test/fixedbugs/bug392.dir/pkg3.go
index 402c3b0..1403798 100644
--- a/test/fixedbugs/bug392.dir/pkg3.go
+++ b/test/fixedbugs/bug392.dir/pkg3.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug393.go b/test/fixedbugs/bug393.go
index f8a9c65..61af578 100644
--- a/test/fixedbugs/bug393.go
+++ b/test/fixedbugs/bug393.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug394.go b/test/fixedbugs/bug394.go
index 2d77156..08bac18 100644
--- a/test/fixedbugs/bug394.go
+++ b/test/fixedbugs/bug394.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug396.dir/one.go b/test/fixedbugs/bug396.dir/one.go
index 96a1dd7..66eba63 100644
--- a/test/fixedbugs/bug396.dir/one.go
+++ b/test/fixedbugs/bug396.dir/one.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug396.dir/two.go b/test/fixedbugs/bug396.dir/two.go
index 9b32508..9152bec 100644
--- a/test/fixedbugs/bug396.dir/two.go
+++ b/test/fixedbugs/bug396.dir/two.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug397.go b/test/fixedbugs/bug397.go
index 56cc7cd..6188e3e 100644
--- a/test/fixedbugs/bug397.go
+++ b/test/fixedbugs/bug397.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug398.go b/test/fixedbugs/bug398.go
index 1dd3fa4..81bf33c 100644
--- a/test/fixedbugs/bug398.go
+++ b/test/fixedbugs/bug398.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,17 +8,20 @@
 
 package p
 
-type I1 interface {
-      F() interface{I1}
+type i1 interface {
+      F() interface{i1}
 }
 
-type I2 interface {
-      F() interface{I2}
+type i2 interface {
+      F() interface{i2}
 }       
 
-var v1 I1
-var v2 I2
+var v1 i1
+var v2 i2
 
 func f() bool {
        return v1 == v2
 }
+
+// TODO(gri) Change test to use exported interfaces.
+// See issue #15596 for details.
\ No newline at end of file
diff --git a/test/fixedbugs/bug399.go b/test/fixedbugs/bug399.go
index 94852c9..e460d81 100644
--- a/test/fixedbugs/bug399.go
+++ b/test/fixedbugs/bug399.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug401.go b/test/fixedbugs/bug401.go
index c58e1ca..215498e 100644
--- a/test/fixedbugs/bug401.go
+++ b/test/fixedbugs/bug401.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug402.go b/test/fixedbugs/bug402.go
index db3f3da..f9f554d 100644
--- a/test/fixedbugs/bug402.go
+++ b/test/fixedbugs/bug402.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug403.go b/test/fixedbugs/bug403.go
index ed7b49a..aa3c1ea 100644
--- a/test/fixedbugs/bug403.go
+++ b/test/fixedbugs/bug403.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug404.dir/one.go b/test/fixedbugs/bug404.dir/one.go
index 2024eb0..9fc4770 100644
--- a/test/fixedbugs/bug404.dir/one.go
+++ b/test/fixedbugs/bug404.dir/one.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug404.dir/two.go b/test/fixedbugs/bug404.dir/two.go
index 162eae7..0c70a23 100644
--- a/test/fixedbugs/bug404.dir/two.go
+++ b/test/fixedbugs/bug404.dir/two.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug406.go b/test/fixedbugs/bug406.go
index 6df3c5c..32cf3e3 100644
--- a/test/fixedbugs/bug406.go
+++ b/test/fixedbugs/bug406.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug407.dir/one.go b/test/fixedbugs/bug407.dir/one.go
index a91d904..c85b077 100644
--- a/test/fixedbugs/bug407.dir/one.go
+++ b/test/fixedbugs/bug407.dir/one.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug407.dir/two.go b/test/fixedbugs/bug407.dir/two.go
index 67e1852..640305c 100644
--- a/test/fixedbugs/bug407.dir/two.go
+++ b/test/fixedbugs/bug407.dir/two.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug409.go b/test/fixedbugs/bug409.go
index 1dca43b..9e08a8e 100644
--- a/test/fixedbugs/bug409.go
+++ b/test/fixedbugs/bug409.go
@@ -1,6 +1,6 @@
 // cmpout
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug410.go b/test/fixedbugs/bug410.go
index 430ddcb..a4eef64 100644
--- a/test/fixedbugs/bug410.go
+++ b/test/fixedbugs/bug410.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug411.go b/test/fixedbugs/bug411.go
index 3b90db8..a1c36f6 100644
--- a/test/fixedbugs/bug411.go
+++ b/test/fixedbugs/bug411.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug412.go b/test/fixedbugs/bug412.go
index c7ddc0c..183fb7e 100644
--- a/test/fixedbugs/bug412.go
+++ b/test/fixedbugs/bug412.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug413.go b/test/fixedbugs/bug413.go
index ba80464..819bd1a 100644
--- a/test/fixedbugs/bug413.go
+++ b/test/fixedbugs/bug413.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug414.dir/p1.go b/test/fixedbugs/bug414.dir/p1.go
index 2463834..143e600 100644
--- a/test/fixedbugs/bug414.dir/p1.go
+++ b/test/fixedbugs/bug414.dir/p1.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug414.dir/prog.go b/test/fixedbugs/bug414.dir/prog.go
index f55d946..8945d65 100644
--- a/test/fixedbugs/bug414.dir/prog.go
+++ b/test/fixedbugs/bug414.dir/prog.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug414.go b/test/fixedbugs/bug414.go
index 35e19be..5b435b4 100644
--- a/test/fixedbugs/bug414.go
+++ b/test/fixedbugs/bug414.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug415.dir/p.go b/test/fixedbugs/bug415.dir/p.go
index b4152d6..e86a697 100644
--- a/test/fixedbugs/bug415.dir/p.go
+++ b/test/fixedbugs/bug415.dir/p.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug415.dir/prog.go b/test/fixedbugs/bug415.dir/prog.go
index b894453..1ffde18 100644
--- a/test/fixedbugs/bug415.dir/prog.go
+++ b/test/fixedbugs/bug415.dir/prog.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug415.go b/test/fixedbugs/bug415.go
index 8cd4c49..daf4f0c 100644
--- a/test/fixedbugs/bug415.go
+++ b/test/fixedbugs/bug415.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug416.go b/test/fixedbugs/bug416.go
index 1d24fa9..9fc3532 100644
--- a/test/fixedbugs/bug416.go
+++ b/test/fixedbugs/bug416.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug424.dir/lib.go b/test/fixedbugs/bug424.dir/lib.go
index 97054da..31df8c6 100644
--- a/test/fixedbugs/bug424.dir/lib.go
+++ b/test/fixedbugs/bug424.dir/lib.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug424.dir/main.go b/test/fixedbugs/bug424.dir/main.go
index c2fe146..28b41e6 100644
--- a/test/fixedbugs/bug424.dir/main.go
+++ b/test/fixedbugs/bug424.dir/main.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug424.go b/test/fixedbugs/bug424.go
index 59c2cd3..9c59abe 100644
--- a/test/fixedbugs/bug424.go
+++ b/test/fixedbugs/bug424.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug428.go b/test/fixedbugs/bug428.go
index 298c455..d9ad276 100644
--- a/test/fixedbugs/bug428.go
+++ b/test/fixedbugs/bug428.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug429.go b/test/fixedbugs/bug429.go
index 31d5a3a..2c31f32 100644
--- a/test/fixedbugs/bug429.go
+++ b/test/fixedbugs/bug429.go
@@ -1,6 +1,6 @@
 // skip
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug435.go b/test/fixedbugs/bug435.go
index 0c2ac7b..692a492 100644
--- a/test/fixedbugs/bug435.go
+++ b/test/fixedbugs/bug435.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug437.dir/one.go b/test/fixedbugs/bug437.dir/one.go
index 8d3caad..633573e 100644
--- a/test/fixedbugs/bug437.dir/one.go
+++ b/test/fixedbugs/bug437.dir/one.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug437.dir/two.go b/test/fixedbugs/bug437.dir/two.go
index 406dd59..61da121 100644
--- a/test/fixedbugs/bug437.dir/two.go
+++ b/test/fixedbugs/bug437.dir/two.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug437.dir/x.go b/test/fixedbugs/bug437.dir/x.go
index 364d017..585b480 100644
--- a/test/fixedbugs/bug437.dir/x.go
+++ b/test/fixedbugs/bug437.dir/x.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug437.go b/test/fixedbugs/bug437.go
index 5c4a2ad..98adce7 100644
--- a/test/fixedbugs/bug437.go
+++ b/test/fixedbugs/bug437.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug441.go b/test/fixedbugs/bug441.go
index 8562bfe..b67125b 100644
--- a/test/fixedbugs/bug441.go
+++ b/test/fixedbugs/bug441.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug442.go b/test/fixedbugs/bug442.go
index 1d1a948..684d54f 100644
--- a/test/fixedbugs/bug442.go
+++ b/test/fixedbugs/bug442.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug443.go b/test/fixedbugs/bug443.go
index b67bd8c..9abd254 100644
--- a/test/fixedbugs/bug443.go
+++ b/test/fixedbugs/bug443.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug444.go b/test/fixedbugs/bug444.go
index b54fb4f..29a60f5 100644
--- a/test/fixedbugs/bug444.go
+++ b/test/fixedbugs/bug444.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug445.go b/test/fixedbugs/bug445.go
index 497ecd3..45c3290 100644
--- a/test/fixedbugs/bug445.go
+++ b/test/fixedbugs/bug445.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug447.go b/test/fixedbugs/bug447.go
index a4c871b..8358f00 100644
--- a/test/fixedbugs/bug447.go
+++ b/test/fixedbugs/bug447.go
@@ -1,6 +1,6 @@
 // runoutput
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug448.dir/pkg1.go b/test/fixedbugs/bug448.dir/pkg1.go
index 032e5d9..291903c 100644
--- a/test/fixedbugs/bug448.dir/pkg1.go
+++ b/test/fixedbugs/bug448.dir/pkg1.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug448.dir/pkg2.go b/test/fixedbugs/bug448.dir/pkg2.go
index 5c78c7d..20d8509 100644
--- a/test/fixedbugs/bug448.dir/pkg2.go
+++ b/test/fixedbugs/bug448.dir/pkg2.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug448.go b/test/fixedbugs/bug448.go
index 242f599..481acda 100644
--- a/test/fixedbugs/bug448.go
+++ b/test/fixedbugs/bug448.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug450.go b/test/fixedbugs/bug450.go
index 3f13de1..af27b72 100644
--- a/test/fixedbugs/bug450.go
+++ b/test/fixedbugs/bug450.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug452.go b/test/fixedbugs/bug452.go
index d2e4a0b..f1f8b08 100644
--- a/test/fixedbugs/bug452.go
+++ b/test/fixedbugs/bug452.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug453.go b/test/fixedbugs/bug453.go
index 136abef..1f4f3ea 100644
--- a/test/fixedbugs/bug453.go
+++ b/test/fixedbugs/bug453.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug454.go b/test/fixedbugs/bug454.go
index a10abba..9e3344d 100644
--- a/test/fixedbugs/bug454.go
+++ b/test/fixedbugs/bug454.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug455.go b/test/fixedbugs/bug455.go
index 8e3c770..9f6974d 100644
--- a/test/fixedbugs/bug455.go
+++ b/test/fixedbugs/bug455.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug456.go b/test/fixedbugs/bug456.go
index 064e1aa..c77a76d 100644
--- a/test/fixedbugs/bug456.go
+++ b/test/fixedbugs/bug456.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug457.go b/test/fixedbugs/bug457.go
index ee70489..84f8db4 100644
--- a/test/fixedbugs/bug457.go
+++ b/test/fixedbugs/bug457.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug458.go b/test/fixedbugs/bug458.go
index ddc97bd..6332697 100644
--- a/test/fixedbugs/bug458.go
+++ b/test/fixedbugs/bug458.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug459.go b/test/fixedbugs/bug459.go
index 014f2ef..c71cb1b 100644
--- a/test/fixedbugs/bug459.go
+++ b/test/fixedbugs/bug459.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug460.dir/a.go b/test/fixedbugs/bug460.dir/a.go
index 29049d9..51c6836 100644
--- a/test/fixedbugs/bug460.dir/a.go
+++ b/test/fixedbugs/bug460.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug460.dir/b.go b/test/fixedbugs/bug460.dir/b.go
index 5c0a0c4..ef64694 100644
--- a/test/fixedbugs/bug460.dir/b.go
+++ b/test/fixedbugs/bug460.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug460.go b/test/fixedbugs/bug460.go
index 79234a3..a1b6f47 100644
--- a/test/fixedbugs/bug460.go
+++ b/test/fixedbugs/bug460.go
@@ -1,6 +1,6 @@
 // errorcheckdir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug461.go b/test/fixedbugs/bug461.go
index f0f7b0e..d7fe802 100644
--- a/test/fixedbugs/bug461.go
+++ b/test/fixedbugs/bug461.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug462.go b/test/fixedbugs/bug462.go
index 1a23ad0..3df63b0 100644
--- a/test/fixedbugs/bug462.go
+++ b/test/fixedbugs/bug462.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug463.go b/test/fixedbugs/bug463.go
index 3e7a184..c7f9237 100644
--- a/test/fixedbugs/bug463.go
+++ b/test/fixedbugs/bug463.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug464.go b/test/fixedbugs/bug464.go
index 5821939..3e2c18a 100644
--- a/test/fixedbugs/bug464.go
+++ b/test/fixedbugs/bug464.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug465.dir/a.go b/test/fixedbugs/bug465.dir/a.go
index a9a8614..3e5d012 100644
--- a/test/fixedbugs/bug465.dir/a.go
+++ b/test/fixedbugs/bug465.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug465.dir/b.go b/test/fixedbugs/bug465.dir/b.go
index c84c683..db7f731 100644
--- a/test/fixedbugs/bug465.dir/b.go
+++ b/test/fixedbugs/bug465.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug465.go b/test/fixedbugs/bug465.go
index a6ef587..84ff07b 100644
--- a/test/fixedbugs/bug465.go
+++ b/test/fixedbugs/bug465.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug466.dir/a.go b/test/fixedbugs/bug466.dir/a.go
index b9de63e..e27699c 100644
--- a/test/fixedbugs/bug466.dir/a.go
+++ b/test/fixedbugs/bug466.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug466.dir/b.go b/test/fixedbugs/bug466.dir/b.go
index 82d66ea..04e3626 100644
--- a/test/fixedbugs/bug466.dir/b.go
+++ b/test/fixedbugs/bug466.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug466.go b/test/fixedbugs/bug466.go
index 6b65b33..dc909d4 100644
--- a/test/fixedbugs/bug466.go
+++ b/test/fixedbugs/bug466.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug467.go b/test/fixedbugs/bug467.go
index d73adba..4126f92 100644
--- a/test/fixedbugs/bug467.go
+++ b/test/fixedbugs/bug467.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug468.dir/p1.go b/test/fixedbugs/bug468.dir/p1.go
index ca17577..cdda735 100644
--- a/test/fixedbugs/bug468.dir/p1.go
+++ b/test/fixedbugs/bug468.dir/p1.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug468.dir/p2.go b/test/fixedbugs/bug468.dir/p2.go
index 1793c0e..dbb4693 100644
--- a/test/fixedbugs/bug468.dir/p2.go
+++ b/test/fixedbugs/bug468.dir/p2.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug468.go b/test/fixedbugs/bug468.go
index 12e4997..77941ce 100644
--- a/test/fixedbugs/bug468.go
+++ b/test/fixedbugs/bug468.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug470.go b/test/fixedbugs/bug470.go
index 0a35918..c21663f 100644
--- a/test/fixedbugs/bug470.go
+++ b/test/fixedbugs/bug470.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug471.go b/test/fixedbugs/bug471.go
index e454259..343661f 100644
--- a/test/fixedbugs/bug471.go
+++ b/test/fixedbugs/bug471.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug472.dir/p1.go b/test/fixedbugs/bug472.dir/p1.go
index 9d47fd8..cda1aa7 100644
--- a/test/fixedbugs/bug472.dir/p1.go
+++ b/test/fixedbugs/bug472.dir/p1.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug472.dir/p2.go b/test/fixedbugs/bug472.dir/p2.go
index 34a3f04..581ec40 100644
--- a/test/fixedbugs/bug472.dir/p2.go
+++ b/test/fixedbugs/bug472.dir/p2.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug472.dir/z.go b/test/fixedbugs/bug472.dir/z.go
index 6c29dd0..eb791bf 100644
--- a/test/fixedbugs/bug472.dir/z.go
+++ b/test/fixedbugs/bug472.dir/z.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug472.go b/test/fixedbugs/bug472.go
index c79c64c..6939e64 100644
--- a/test/fixedbugs/bug472.go
+++ b/test/fixedbugs/bug472.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug473.go b/test/fixedbugs/bug473.go
index 49ce7d7..7649b6b 100644
--- a/test/fixedbugs/bug473.go
+++ b/test/fixedbugs/bug473.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug474.go b/test/fixedbugs/bug474.go
index b826487..1efabe4 100644
--- a/test/fixedbugs/bug474.go
+++ b/test/fixedbugs/bug474.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug475.go b/test/fixedbugs/bug475.go
index 1bd6fa3..0145aab 100644
--- a/test/fixedbugs/bug475.go
+++ b/test/fixedbugs/bug475.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug476.go b/test/fixedbugs/bug476.go
index 563fd91..8695f95 100644
--- a/test/fixedbugs/bug476.go
+++ b/test/fixedbugs/bug476.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug477.go b/test/fixedbugs/bug477.go
index 86289af..f1fbffa 100644
--- a/test/fixedbugs/bug477.go
+++ b/test/fixedbugs/bug477.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug478.dir/a.go b/test/fixedbugs/bug478.dir/a.go
index a40e454..b5a2dbc 100644
--- a/test/fixedbugs/bug478.dir/a.go
+++ b/test/fixedbugs/bug478.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug478.dir/b.go b/test/fixedbugs/bug478.dir/b.go
index c0fdf11..cfd1d27 100644
--- a/test/fixedbugs/bug478.dir/b.go
+++ b/test/fixedbugs/bug478.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug478.go b/test/fixedbugs/bug478.go
index 5e339e8..8757f46 100644
--- a/test/fixedbugs/bug478.go
+++ b/test/fixedbugs/bug478.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug479.dir/a.go b/test/fixedbugs/bug479.dir/a.go
index 5ff3bef..eddb4cf 100644
--- a/test/fixedbugs/bug479.dir/a.go
+++ b/test/fixedbugs/bug479.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug479.dir/b.go b/test/fixedbugs/bug479.dir/b.go
index a1b27b3..9f3f5e8 100644
--- a/test/fixedbugs/bug479.dir/b.go
+++ b/test/fixedbugs/bug479.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug479.go b/test/fixedbugs/bug479.go
index f8a0f93..80012ba 100644
--- a/test/fixedbugs/bug479.go
+++ b/test/fixedbugs/bug479.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug480.dir/a.go b/test/fixedbugs/bug480.dir/a.go
index 6dff515..26a8d11 100644
--- a/test/fixedbugs/bug480.dir/a.go
+++ b/test/fixedbugs/bug480.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug480.dir/b.go b/test/fixedbugs/bug480.dir/b.go
index 6207365..5bd40f6 100644
--- a/test/fixedbugs/bug480.dir/b.go
+++ b/test/fixedbugs/bug480.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug480.go b/test/fixedbugs/bug480.go
index 5b44af4..ad2f73c 100644
--- a/test/fixedbugs/bug480.go
+++ b/test/fixedbugs/bug480.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug481.go b/test/fixedbugs/bug481.go
index d0922a5..13a5339 100644
--- a/test/fixedbugs/bug481.go
+++ b/test/fixedbugs/bug481.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug482.go b/test/fixedbugs/bug482.go
index 10c4828..0e5417d 100644
--- a/test/fixedbugs/bug482.go
+++ b/test/fixedbugs/bug482.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug483.go b/test/fixedbugs/bug483.go
index 2372e89..8db6425 100644
--- a/test/fixedbugs/bug483.go
+++ b/test/fixedbugs/bug483.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug484.go b/test/fixedbugs/bug484.go
index 7025aff..bd4fa51 100644
--- a/test/fixedbugs/bug484.go
+++ b/test/fixedbugs/bug484.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug485.go b/test/fixedbugs/bug485.go
index 1544753..c99faed 100644
--- a/test/fixedbugs/bug485.go
+++ b/test/fixedbugs/bug485.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug486.go b/test/fixedbugs/bug486.go
index c1a4723..9ad23b3 100644
--- a/test/fixedbugs/bug486.go
+++ b/test/fixedbugs/bug486.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug487.go b/test/fixedbugs/bug487.go
index eb1ad5e..e60af6c 100644
--- a/test/fixedbugs/bug487.go
+++ b/test/fixedbugs/bug487.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug488.dir/a.go b/test/fixedbugs/bug488.dir/a.go
index 94eaf7f..fc49420 100644
--- a/test/fixedbugs/bug488.dir/a.go
+++ b/test/fixedbugs/bug488.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug488.dir/b.go b/test/fixedbugs/bug488.dir/b.go
index 21b4c5b..f93328c 100644
--- a/test/fixedbugs/bug488.dir/b.go
+++ b/test/fixedbugs/bug488.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug488.go b/test/fixedbugs/bug488.go
index 63a601e..3912deb 100644
--- a/test/fixedbugs/bug488.go
+++ b/test/fixedbugs/bug488.go
@@ -1,6 +1,6 @@
 // errorcheckdir
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug489.go b/test/fixedbugs/bug489.go
index 4cf19e0..34250cd 100644
--- a/test/fixedbugs/bug489.go
+++ b/test/fixedbugs/bug489.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug490.go b/test/fixedbugs/bug490.go
index 7d05f39..387a680 100644
--- a/test/fixedbugs/bug490.go
+++ b/test/fixedbugs/bug490.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/bug491.go b/test/fixedbugs/bug491.go
index f4b58af..39a3509 100644
--- a/test/fixedbugs/bug491.go
+++ b/test/fixedbugs/bug491.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61204.go b/test/fixedbugs/gcc61204.go
index 5a5bb16..e175f83 100644
--- a/test/fixedbugs/gcc61204.go
+++ b/test/fixedbugs/gcc61204.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61244.go b/test/fixedbugs/gcc61244.go
index 7fbc872..642bc61 100644
--- a/test/fixedbugs/gcc61244.go
+++ b/test/fixedbugs/gcc61244.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61246.go b/test/fixedbugs/gcc61246.go
index 4866570..797d6c7 100644
--- a/test/fixedbugs/gcc61246.go
+++ b/test/fixedbugs/gcc61246.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61248.go b/test/fixedbugs/gcc61248.go
index 593c634..cb59c9f 100644
--- a/test/fixedbugs/gcc61248.go
+++ b/test/fixedbugs/gcc61248.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61253.go b/test/fixedbugs/gcc61253.go
index dc125ac..696b26e 100644
--- a/test/fixedbugs/gcc61253.go
+++ b/test/fixedbugs/gcc61253.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61254.go b/test/fixedbugs/gcc61254.go
index 36ac7d4..82e666e 100644
--- a/test/fixedbugs/gcc61254.go
+++ b/test/fixedbugs/gcc61254.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61255.go b/test/fixedbugs/gcc61255.go
index a0e6d18..288fb54 100644
--- a/test/fixedbugs/gcc61255.go
+++ b/test/fixedbugs/gcc61255.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61258.go b/test/fixedbugs/gcc61258.go
index 8474665..e4dcb33 100644
--- a/test/fixedbugs/gcc61258.go
+++ b/test/fixedbugs/gcc61258.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61264.go b/test/fixedbugs/gcc61264.go
index d4e05f4..a4092f5 100644
--- a/test/fixedbugs/gcc61264.go
+++ b/test/fixedbugs/gcc61264.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61265.go b/test/fixedbugs/gcc61265.go
index 42fae36..be79233 100644
--- a/test/fixedbugs/gcc61265.go
+++ b/test/fixedbugs/gcc61265.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc61273.go b/test/fixedbugs/gcc61273.go
index 2983222..ed78b1e 100644
--- a/test/fixedbugs/gcc61273.go
+++ b/test/fixedbugs/gcc61273.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/gcc65755.go b/test/fixedbugs/gcc65755.go
index e76f4d1..1e5d116 100644
--- a/test/fixedbugs/gcc65755.go
+++ b/test/fixedbugs/gcc65755.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue10047.go b/test/fixedbugs/issue10047.go
index 1cb9c24..dcbde48 100644
--- a/test/fixedbugs/issue10047.go
+++ b/test/fixedbugs/issue10047.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue10284.go b/test/fixedbugs/issue10284.go
index e89d6f4..39028e7 100644
--- a/test/fixedbugs/issue10284.go
+++ b/test/fixedbugs/issue10284.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue10320.go b/test/fixedbugs/issue10320.go
index 697aad1..c7e2bab 100644
--- a/test/fixedbugs/issue10320.go
+++ b/test/fixedbugs/issue10320.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue10332.go b/test/fixedbugs/issue10332.go
index e00a8b4..096b7a5 100644
--- a/test/fixedbugs/issue10332.go
+++ b/test/fixedbugs/issue10332.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue10407.go b/test/fixedbugs/issue10407.go
index fe033ef..c6461a3 100644
--- a/test/fixedbugs/issue10407.go
+++ b/test/fixedbugs/issue10407.go
@@ -1,6 +1,6 @@
 // runoutput
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue10486.go b/test/fixedbugs/issue10486.go
index f346828..3b62cb9 100644
--- a/test/fixedbugs/issue10486.go
+++ b/test/fixedbugs/issue10486.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue10607.go b/test/fixedbugs/issue10607.go
index a1a65a7..bf527d0 100644
--- a/test/fixedbugs/issue10607.go
+++ b/test/fixedbugs/issue10607.go
@@ -1,4 +1,4 @@
-// +build linux,!ppc64,!ppc64le,!mips64,!mips64le
+// +build linux,!ppc64,!ppc64le
 // run
 
 // Copyright 2015 The Go Authors. All rights reserved.
diff --git a/test/fixedbugs/issue10975.go b/test/fixedbugs/issue10975.go
index 1aa7d89..b5f043f 100644
--- a/test/fixedbugs/issue10975.go
+++ b/test/fixedbugs/issue10975.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11053.dir/p.go b/test/fixedbugs/issue11053.dir/p.go
index e431cb4..81b412a 100644
--- a/test/fixedbugs/issue11053.dir/p.go
+++ b/test/fixedbugs/issue11053.dir/p.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11053.dir/p_test.go b/test/fixedbugs/issue11053.dir/p_test.go
index e0a9555..542c2a3 100644
--- a/test/fixedbugs/issue11053.dir/p_test.go
+++ b/test/fixedbugs/issue11053.dir/p_test.go
@@ -1,4 +1,4 @@
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11326.go b/test/fixedbugs/issue11326.go
index 3a4fbff..82754c7 100644
--- a/test/fixedbugs/issue11326.go
+++ b/test/fixedbugs/issue11326.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11326b.go b/test/fixedbugs/issue11326b.go
index 6a6ae2f..8aba4d9 100644
--- a/test/fixedbugs/issue11326b.go
+++ b/test/fixedbugs/issue11326b.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11361.go b/test/fixedbugs/issue11361.go
new file mode 100644
index 0000000..d01776b
--- /dev/null
+++ b/test/fixedbugs/issue11361.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors.  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
+
+import "fmt"  // ERROR "imported and not used"
+
+const n = fmt // ERROR "fmt without selector" "fmt is not a constant"
diff --git a/test/fixedbugs/issue11362.go b/test/fixedbugs/issue11362.go
index 680b0e5..9e9e599 100644
--- a/test/fixedbugs/issue11362.go
+++ b/test/fixedbugs/issue11362.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11590.go b/test/fixedbugs/issue11590.go
index f3032fc..0934547 100644
--- a/test/fixedbugs/issue11590.go
+++ b/test/fixedbugs/issue11590.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11610.go b/test/fixedbugs/issue11610.go
index a326249..f32d480 100644
--- a/test/fixedbugs/issue11610.go
+++ b/test/fixedbugs/issue11610.go
@@ -9,9 +9,9 @@
 
 package a
 import""  // ERROR "import path is empty"
-var?      // ERROR "invalid declaration"
+var?      // ERROR "illegal character U\+003F '\?'"
 
-var x int // ERROR "unexpected var"
+var x int // ERROR "unexpected var" "cannot declare name"
 
 func main() {
 }
diff --git a/test/fixedbugs/issue11656.go b/test/fixedbugs/issue11656.go
index 565e796..e0ef097 100644
--- a/test/fixedbugs/issue11656.go
+++ b/test/fixedbugs/issue11656.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
@@ -65,6 +65,8 @@ func f(n int) {
 		binary.BigEndian.PutUint32(ill, 0x00000034) // trap
 	case "mips64le":
 		binary.LittleEndian.PutUint32(ill, 0x00000034) // trap
+	case "s390x":
+		binary.BigEndian.PutUint32(ill, 0) // undefined instruction
 	default:
 		// Just leave it as 0 and hope for the best.
 	}
diff --git a/test/fixedbugs/issue11699.go b/test/fixedbugs/issue11699.go
index 965c87f..755e9a1 100644
--- a/test/fixedbugs/issue11699.go
+++ b/test/fixedbugs/issue11699.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11737.go b/test/fixedbugs/issue11737.go
index 01ef096..86ecf9a 100644
--- a/test/fixedbugs/issue11737.go
+++ b/test/fixedbugs/issue11737.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11750.go b/test/fixedbugs/issue11750.go
index 5e6fe60..d5a2b22 100644
--- a/test/fixedbugs/issue11750.go
+++ b/test/fixedbugs/issue11750.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11771.go b/test/fixedbugs/issue11771.go
index 7691ca6..d91fc5d 100644
--- a/test/fixedbugs/issue11771.go
+++ b/test/fixedbugs/issue11771.go
@@ -1,7 +1,7 @@
 // +build !nacl
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11790.go b/test/fixedbugs/issue11790.go
index d7669f8..096b297 100644
--- a/test/fixedbugs/issue11790.go
+++ b/test/fixedbugs/issue11790.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue11987.go b/test/fixedbugs/issue11987.go
index 78fc28b..9b665dc 100644
--- a/test/fixedbugs/issue11987.go
+++ b/test/fixedbugs/issue11987.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue12006.go b/test/fixedbugs/issue12006.go
index 01dced3..9d81a04 100644
--- a/test/fixedbugs/issue12006.go
+++ b/test/fixedbugs/issue12006.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue12133.go b/test/fixedbugs/issue12133.go
index 7b02a47..bbf9fb0 100644
--- a/test/fixedbugs/issue12133.go
+++ b/test/fixedbugs/issue12133.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue12347.go b/test/fixedbugs/issue12347.go
new file mode 100644
index 0000000..fc5678e
--- /dev/null
+++ b/test/fixedbugs/issue12347.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.
+
+package p
+
+func f_ssa(x int, p *int) {
+	if false {
+		y := x + 5
+		for {
+			*p = y
+		}
+	}
+}
diff --git a/test/fixedbugs/issue12411.go b/test/fixedbugs/issue12411.go
index 0a8b7c3..ff49314 100644
--- a/test/fixedbugs/issue12411.go
+++ b/test/fixedbugs/issue12411.go
@@ -1,7 +1,7 @@
 // +build !386
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue12525.go b/test/fixedbugs/issue12525.go
new file mode 100644
index 0000000..4a54eab
--- /dev/null
+++ b/test/fixedbugs/issue12525.go
@@ -0,0 +1,26 @@
+// errorcheck
+
+// Copyright 2016 The Go 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 12525: confusing error trying to increment boolean value
+
+package main
+
+func main() {
+	var i int
+	i++
+
+	var f float64
+	f++
+
+	var c complex128
+	c++
+
+	var b bool
+	b++ // ERROR "invalid operation: b\+\+ \(non-numeric type bool\)"
+
+	var s string
+	s-- // ERROR "invalid operation: s-- \(non-numeric type string\)"
+}
diff --git a/test/fixedbugs/issue12588.go b/test/fixedbugs/issue12588.go
index 3022f48..87f1d47 100644
--- a/test/fixedbugs/issue12588.go
+++ b/test/fixedbugs/issue12588.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue12686.go b/test/fixedbugs/issue12686.go
index 5783c99..bde4255 100644
--- a/test/fixedbugs/issue12686.go
+++ b/test/fixedbugs/issue12686.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue1304.go b/test/fixedbugs/issue1304.go
index 1206e18..9e0ca5a 100644
--- a/test/fixedbugs/issue1304.go
+++ b/test/fixedbugs/issue1304.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue13160.go b/test/fixedbugs/issue13160.go
index 7eb4811..c21ecf6 100644
--- a/test/fixedbugs/issue13160.go
+++ b/test/fixedbugs/issue13160.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13169.go b/test/fixedbugs/issue13169.go
index 77767cd..03c52e2 100644
--- a/test/fixedbugs/issue13169.go
+++ b/test/fixedbugs/issue13169.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13248.go b/test/fixedbugs/issue13248.go
index d01b823..5246281 100644
--- a/test/fixedbugs/issue13248.go
+++ b/test/fixedbugs/issue13248.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13261.go b/test/fixedbugs/issue13261.go
index c73062c..a944f3a 100644
--- a/test/fixedbugs/issue13261.go
+++ b/test/fixedbugs/issue13261.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13266.go b/test/fixedbugs/issue13266.go
index 3c4f74b..37c5594 100644
--- a/test/fixedbugs/issue13266.go
+++ b/test/fixedbugs/issue13266.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13273.go b/test/fixedbugs/issue13273.go
index fa3815f..f8f679d 100644
--- a/test/fixedbugs/issue13273.go
+++ b/test/fixedbugs/issue13273.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13274.go b/test/fixedbugs/issue13274.go
index a93c63f..480f5bc 100644
--- a/test/fixedbugs/issue13274.go
+++ b/test/fixedbugs/issue13274.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13319.go b/test/fixedbugs/issue13319.go
index fc35870..c9b4896 100644
--- a/test/fixedbugs/issue13319.go
+++ b/test/fixedbugs/issue13319.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13337.go b/test/fixedbugs/issue13337.go
new file mode 100644
index 0000000..81f984b
--- /dev/null
+++ b/test/fixedbugs/issue13337.go
@@ -0,0 +1,30 @@
+// compile
+
+// Copyright 2016 The Go 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 13337: The Go compiler limited how deeply embedded types
+// were searched for promoted fields and methods.
+
+package s
+
+type S0 struct{ f int }
+func (S0) m() {}
+
+type S1 struct{ S0 }
+type S2 struct{ S1 }
+type S3 struct{ S2 }
+type S4 struct{ S3 }
+type S5 struct{ S4 }
+type S6 struct{ S5 }
+type S7 struct{ S6 }
+type S8 struct{ S7 }
+type S9 struct{ S8 }
+type S10 struct{ S9 }
+type S11 struct{ S10 }
+type S12 struct{ S11 }
+type S13 struct{ S12 }
+
+var _ = S13{}.f
+var _ = S13.m
diff --git a/test/fixedbugs/issue13471.go b/test/fixedbugs/issue13471.go
index eee4081..81f034b 100644
--- a/test/fixedbugs/issue13471.go
+++ b/test/fixedbugs/issue13471.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13587.go b/test/fixedbugs/issue13587.go
index eea5502..b71bf9d 100644
--- a/test/fixedbugs/issue13587.go
+++ b/test/fixedbugs/issue13587.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -l -d=wb
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13684.go b/test/fixedbugs/issue13684.go
index eda92a3..a1d8856 100644
--- a/test/fixedbugs/issue13684.go
+++ b/test/fixedbugs/issue13684.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13779.go b/test/fixedbugs/issue13779.go
new file mode 100644
index 0000000..b18577c
--- /dev/null
+++ b/test/fixedbugs/issue13779.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2016 The Go 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 13779: provide better error message when directly assigning to struct field in map
+
+package main
+
+func main() {
+	type person struct{ age, weight, height int }
+	students := map[string]person{"sally": person{12, 50, 32}}
+	students["sally"].age = 3 // ERROR "cannot assign to struct field .* in map"
+}
diff --git a/test/fixedbugs/issue13799.go b/test/fixedbugs/issue13799.go
index e1b96f7..4819b5a 100644
--- a/test/fixedbugs/issue13799.go
+++ b/test/fixedbugs/issue13799.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m -l
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13821.go b/test/fixedbugs/issue13821.go
index 7d50248..187e4b4 100644
--- a/test/fixedbugs/issue13821.go
+++ b/test/fixedbugs/issue13821.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue13821b.go b/test/fixedbugs/issue13821b.go
index 0950fde..be67cea 100644
--- a/test/fixedbugs/issue13821b.go
+++ b/test/fixedbugs/issue13821b.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue14006.go b/test/fixedbugs/issue14006.go
index b56ed73..c3c56b1 100644
--- a/test/fixedbugs/issue14006.go
+++ b/test/fixedbugs/issue14006.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/test/fixedbugs/issue14010.go b/test/fixedbugs/issue14010.go
index 4fdbf76..f5cab41 100644
--- a/test/fixedbugs/issue14010.go
+++ b/test/fixedbugs/issue14010.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/test/fixedbugs/issue14136.go b/test/fixedbugs/issue14136.go
new file mode 100644
index 0000000..928a60b
--- /dev/null
+++ b/test/fixedbugs/issue14136.go
@@ -0,0 +1,19 @@
+// errorcheck
+
+// Copyright 2016 The Go 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 > 10 non-syntax errors on the same line
+// don't lead to early exit. Specifically, here test
+// that we see the initialization error for variable
+// s.
+
+package main
+
+type T struct{}
+
+func main() {
+	t := T{X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1} // ERROR "unknown T field"
+	var s string = 1 // ERROR "cannot use 1"
+}
diff --git a/test/fixedbugs/issue14331.dir/a.go b/test/fixedbugs/issue14331.dir/a.go
index 1b7f853..f1e57ef 100644
--- a/test/fixedbugs/issue14331.dir/a.go
+++ b/test/fixedbugs/issue14331.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/test/fixedbugs/issue14331.dir/b.go b/test/fixedbugs/issue14331.dir/b.go
index 7a0abb2..a2280a3 100644
--- a/test/fixedbugs/issue14331.dir/b.go
+++ b/test/fixedbugs/issue14331.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/test/fixedbugs/issue14331.go b/test/fixedbugs/issue14331.go
index 32f3e51..b8ee2fb 100644
--- a/test/fixedbugs/issue14331.go
+++ b/test/fixedbugs/issue14331.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2016 The Go Authors.  All rights reserved.
+// Copyright 2016 The Go 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/test/fixedbugs/issue14405.go b/test/fixedbugs/issue14405.go
new file mode 100644
index 0000000..94592fd
--- /dev/null
+++ b/test/fixedbugs/issue14405.go
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Mention of field with large offset in struct literal causes crash
+package p
+
+type T struct {
+	Slice [1 << 20][]int
+	Ptr   *int
+}
+
+func New(p *int) *T {
+	return &T{Ptr: p}
+}
diff --git a/test/fixedbugs/issue14520.go b/test/fixedbugs/issue14520.go
new file mode 100644
index 0000000..1b1f4de
--- /dev/null
+++ b/test/fixedbugs/issue14520.go
@@ -0,0 +1,14 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package f
+
+import /* // ERROR "import path" */ `
+bogus`
+
+func f(x int /* // ERROR "unexpected semicolon"
+
+*/)
diff --git a/test/fixedbugs/issue14553.go b/test/fixedbugs/issue14553.go
new file mode 100644
index 0000000..d7ebb12
--- /dev/null
+++ b/test/fixedbugs/issue14553.go
@@ -0,0 +1,45 @@
+// run
+
+// Copyright 2016 The Go 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 checks if the compiler's internal constant
+// arithmetic correctly rounds denormal float32 values.
+
+package main
+
+import (
+	"fmt"
+	"math"
+)
+
+func main() {
+	for _, t := range []struct {
+		value float32
+		bits  uint32
+	}{
+		{0e+00, 0x00000000},
+		{1e-46, 0x00000000},
+		{0.5e-45, 0x00000000},
+		{0.8e-45, 0x00000001},
+		{1e-45, 0x00000001},
+		{2e-45, 0x00000001},
+		{3e-45, 0x00000002},
+		{4e-45, 0x00000003},
+		{5e-45, 0x00000004},
+		{6e-45, 0x00000004},
+		{7e-45, 0x00000005},
+		{8e-45, 0x00000006},
+		{9e-45, 0x00000006},
+		{1.0e-44, 0x00000007},
+		{1.1e-44, 0x00000008},
+		{1.2e-44, 0x00000009},
+	} {
+		got := math.Float32bits(t.value)
+		want := t.bits
+		if got != want {
+			panic(fmt.Sprintf("bits(%g) = 0x%08x; want 0x%08x", t.value, got, want))
+		}
+	}
+}
diff --git a/test/fixedbugs/issue14591.go b/test/fixedbugs/issue14591.go
new file mode 100644
index 0000000..626fbbc
--- /dev/null
+++ b/test/fixedbugs/issue14591.go
@@ -0,0 +1,38 @@
+// run
+
+// Copyright 2016 The Go 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 to make sure we don't think values are dead
+// when they are assigned to a PPARAMOUT slot before
+// the last GC safepoint.
+
+package main
+
+import (
+	"fmt"
+	"runtime"
+)
+
+// When a T is deallocated, T[1] is certain to
+// get clobbered (the runtime writes 0xdeaddeaddeaddead there).
+type T [4]int
+
+func f() (r, s *T) {
+	r = &T{0x30, 0x31, 0x32, 0x33}
+	runtime.GC()
+	s = &T{0x40, 0x41, 0x42, 0x43}
+	runtime.GC()
+	return
+}
+
+func main() {
+	r, s := f()
+	if r[1] != 0x31 {
+		fmt.Printf("bad r[1], want 0x31 got %x\n", r[1])
+	}
+	if s[1] != 0x41 {
+		fmt.Printf("bad s[1], want 0x41 got %x\n", s[1])
+	}
+}
diff --git a/test/fixedbugs/issue14636.go b/test/fixedbugs/issue14636.go
new file mode 100644
index 0000000..7d1b606
--- /dev/null
+++ b/test/fixedbugs/issue14636.go
@@ -0,0 +1,43 @@
+// +build !nacl,!android,!darwin darwin,!arm
+// run
+
+// Copyright 2016 The Go Authors. 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"
+	"log"
+	"os/exec"
+	"strings"
+)
+
+func main() {
+	checkLinkOutput("", "-B argument must start with 0x")
+	checkLinkOutput("0", "-B argument must start with 0x")
+	checkLinkOutput("0x", "usage")
+	checkLinkOutput("0x0", "-B argument must have even number of digits")
+	checkLinkOutput("0x00", "usage")
+	checkLinkOutput("0xYZ", "-B argument contains invalid hex digit")
+	checkLinkOutput("0x"+strings.Repeat("00", 32), "usage")
+	checkLinkOutput("0x"+strings.Repeat("00", 33), "-B option too long (max 32 digits)")
+}
+
+func checkLinkOutput(buildid string, message string) {
+	cmd := exec.Command("go", "tool", "link", "-B", buildid)
+	out, err := cmd.CombinedOutput()
+	if err == nil {
+		log.Fatalf("expected cmd/link to fail")
+	}
+
+	firstLine := string(bytes.SplitN(out, []byte("\n"), 2)[0])
+	if strings.HasPrefix(firstLine, "panic") {
+		log.Fatalf("cmd/link panicked:\n%s", out)
+	}
+
+	if !strings.Contains(firstLine, message) {
+		log.Fatalf("cmd/link output did not include expected message %q: %s", message, firstLine)
+	}
+}
diff --git a/test/fixedbugs/issue14646.go b/test/fixedbugs/issue14646.go
new file mode 100644
index 0000000..96a6854
--- /dev/null
+++ b/test/fixedbugs/issue14646.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2016 The Go Authors. 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 "runtime"
+
+func main() {
+	var file string
+	var line int
+	func() {
+		defer func() {
+			_, file, line, _ = runtime.Caller(1)
+		}()
+	}() // this is the expected line
+	const EXPECTED = 18
+	if line != EXPECTED {
+		println("Expected line =", EXPECTED, "but got line =", line, "and file =", file)
+	}
+}
diff --git a/test/fixedbugs/issue14651.go b/test/fixedbugs/issue14651.go
new file mode 100644
index 0000000..4c756e5
--- /dev/null
+++ b/test/fixedbugs/issue14651.go
@@ -0,0 +1,71 @@
+// run
+
+// Copyright 2016 The Go 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 checks if the compiler's internal constant
+// arithmetic correctly rounds up floating-point values
+// that become the smallest denormal value.
+//
+// See also related issue 14553 and test issue14553.go.
+
+package main
+
+import (
+	"fmt"
+	"math"
+)
+
+const (
+	p149 = 1.0 / (1 << 149) // 1p-149
+	p500 = 1.0 / (1 << 500) // 1p-500
+	p1074 = p500 * p500 / (1<<74) // 1p-1074
+)
+
+const (
+	m0000p149 = 0x0 / 16.0 * p149 // = 0.0000p-149
+	m1000p149 = 0x8 / 16.0 * p149 // = 0.1000p-149
+	m1001p149 = 0x9 / 16.0 * p149 // = 0.1001p-149
+	m1011p149 = 0xb / 16.0 * p149 // = 0.1011p-149
+	m1100p149 = 0xc / 16.0 * p149 // = 0.1100p-149
+
+	m0000p1074 = 0x0 / 16.0 * p1074 // = 0.0000p-1074
+	m1000p1074 = 0x8 / 16.0 * p1074 // = 0.1000p-1074
+	m1001p1074 = 0x9 / 16.0 * p1074 // = 0.1001p-1074
+	m1011p1074 = 0xb / 16.0 * p1074 // = 0.1011p-1074
+	m1100p1074 = 0xc / 16.0 * p1074 // = 0.1100p-1074
+)
+
+func main() {
+	test32(float32(m0000p149), f32(m0000p149))
+	test32(float32(m1000p149), f32(m1000p149))
+	test32(float32(m1001p149), f32(m1001p149))
+	test32(float32(m1011p149), f32(m1011p149))
+	test32(float32(m1100p149), f32(m1100p149))
+
+	test64(float64(m0000p1074), f64(m0000p1074))
+	test64(float64(m1000p1074), f64(m1000p1074))
+	test64(float64(m1001p1074), f64(m1001p1074))
+	test64(float64(m1011p1074), f64(m1011p1074))
+	test64(float64(m1100p1074), f64(m1100p1074))
+}
+
+func f32(x float64) float32 { return float32(x) }
+func f64(x float64) float64 { return float64(x) }
+
+func test32(a, b float32) {
+	abits := math.Float32bits(a)
+	bbits := math.Float32bits(b)
+	if abits != bbits {
+		panic(fmt.Sprintf("%08x != %08x\n", abits, bbits))
+	}
+}
+
+func test64(a, b float64) {
+	abits := math.Float64bits(a)
+	bbits := math.Float64bits(b)
+	if abits != bbits {
+		panic(fmt.Sprintf("%016x != %016x\n", abits, bbits))
+	}
+}
diff --git a/test/fixedbugs/issue14652.go b/test/fixedbugs/issue14652.go
new file mode 100644
index 0000000..b030aee
--- /dev/null
+++ b/test/fixedbugs/issue14652.go
@@ -0,0 +1,9 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. 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
+
+var x any // ERROR "undefined: any"
diff --git a/test/fixedbugs/issue14725.go b/test/fixedbugs/issue14725.go
new file mode 100644
index 0000000..49f3fbc
--- /dev/null
+++ b/test/fixedbugs/issue14725.go
@@ -0,0 +1,57 @@
+// run
+
+// Copyright 2016 The Go Authors. 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 f1() (x int) {
+	for {
+		defer func() {
+			recover()
+			x = 1
+		}()
+		panic(nil)
+	}
+}
+
+var sink *int
+
+func f2() (x int) {
+	sink = &x
+	defer func() {
+		recover()
+		x = 1
+	}()
+	panic(nil)
+}
+
+func f3(b bool) (x int) {
+	sink = &x
+	defer func() {
+		recover()
+		x = 1
+	}()
+	if b {
+		panic(nil)
+	}
+	return
+}
+
+func main() {
+	if x := f1(); x != 1 {
+		panic(fmt.Sprintf("f1 returned %d, wanted 1", x))
+	}
+	if x := f2(); x != 1 {
+		panic(fmt.Sprintf("f2 returned %d, wanted 1", x))
+	}
+	if x := f3(true); x != 1 {
+		panic(fmt.Sprintf("f3(true) returned %d, wanted 1", x))
+	}
+	if x := f3(false); x != 1 {
+		panic(fmt.Sprintf("f3(false) returned %d, wanted 1", x))
+	}
+}
diff --git a/test/fixedbugs/issue14729.go b/test/fixedbugs/issue14729.go
new file mode 100644
index 0000000..88e01f9
--- /dev/null
+++ b/test/fixedbugs/issue14729.go
@@ -0,0 +1,14 @@
+// errorcheck
+
+// Copyright 2016 The Go 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 14729: structs cannot embed unsafe.Pointer per the spec.
+
+package main
+
+import "unsafe"
+
+type s struct { unsafe.Pointer } // ERROR "embedded type cannot be a pointer"
+type s1 struct { p unsafe.Pointer }
diff --git a/test/fixedbugs/issue14988.go b/test/fixedbugs/issue14988.go
new file mode 100644
index 0000000..4ddc7e7
--- /dev/null
+++ b/test/fixedbugs/issue14988.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2016 The Go 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 14988: defining a map with an invalid forward declaration array
+//              key doesn't cause a fatal.
+
+package main
+
+type m map[k]int // ERROR "invalid map key type"
+type k [1]m
diff --git a/test/fixedbugs/issue14999.go b/test/fixedbugs/issue14999.go
new file mode 100644
index 0000000..6ce768e
--- /dev/null
+++ b/test/fixedbugs/issue14999.go
@@ -0,0 +1,18 @@
+// errorcheck -+
+
+// Copyright 2016 The Go Authors. 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 int) func(int) int {
+	return func(y int) int { return x + y } // ERROR "heap-allocated closure, not allowed in runtime."
+}
+
+func g(x int) func(int) int { // ERROR "x escapes to heap, not allowed in runtime."
+	return func(y int) int { // ERROR "heap-allocated closure, not allowed in runtime."
+		x += y
+		return x + y
+	}
+}
diff --git a/test/fixedbugs/issue15002.go b/test/fixedbugs/issue15002.go
new file mode 100644
index 0000000..a27fd92
--- /dev/null
+++ b/test/fixedbugs/issue15002.go
@@ -0,0 +1,132 @@
+// run
+// +build amd64
+// +build linux darwin
+
+// Copyright 2016 The Go Authors. 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"
+	"syscall"
+)
+
+// Use global variables so the compiler
+// doesn't know that they are constants.
+var p = syscall.Getpagesize()
+var zero = 0
+var one = 1
+
+func main() {
+	// Allocate 2 pages of memory.
+	b, err := syscall.Mmap(-1, 0, 2*p, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+	if err != nil {
+		panic(err)
+	}
+	// Mark the second page as faulting.
+	err = syscall.Mprotect(b[p:], syscall.PROT_NONE)
+	if err != nil {
+		panic(err)
+	}
+	// Get a slice pointing to the last byte of the good page.
+	x := b[p-one : p]
+
+	test16(x)
+	test16i(x, 0)
+	test32(x)
+	test32i(x, 0)
+	test64(x)
+	test64i(x, 0)
+}
+
+func test16(x []byte) uint16 {
+	defer func() {
+		r := recover()
+		if r == nil {
+			panic("no fault or bounds check failure happened")
+		}
+		s := fmt.Sprintf("%s", r)
+		if s != "runtime error: index out of range" {
+			panic("bad panic: " + s)
+		}
+	}()
+	// Try to read 2 bytes from x.
+	return uint16(x[0]) | uint16(x[1])<<8
+
+	// We expect to get an "index out of range" error from x[1].
+	// If we promote the first load to a 2-byte load, it will segfault, which we don't want.
+}
+
+func test16i(x []byte, i int) uint16 {
+	defer func() {
+		r := recover()
+		if r == nil {
+			panic("no fault or bounds check failure happened")
+		}
+		s := fmt.Sprintf("%s", r)
+		if s != "runtime error: index out of range" {
+			panic("bad panic: " + s)
+		}
+	}()
+	return uint16(x[i]) | uint16(x[i+1])<<8
+}
+
+func test32(x []byte) uint32 {
+	defer func() {
+		r := recover()
+		if r == nil {
+			panic("no fault or bounds check failure happened")
+		}
+		s := fmt.Sprintf("%s", r)
+		if s != "runtime error: index out of range" {
+			panic("bad panic: " + s)
+		}
+	}()
+	return uint32(x[0]) | uint32(x[1])<<8 | uint32(x[2])<<16 | uint32(x[3])<<24
+}
+
+func test32i(x []byte, i int) uint32 {
+	defer func() {
+		r := recover()
+		if r == nil {
+			panic("no fault or bounds check failure happened")
+		}
+		s := fmt.Sprintf("%s", r)
+		if s != "runtime error: index out of range" {
+			panic("bad panic: " + s)
+		}
+	}()
+	return uint32(x[i]) | uint32(x[i+1])<<8 | uint32(x[i+2])<<16 | uint32(x[i+3])<<24
+}
+
+func test64(x []byte) uint64 {
+	defer func() {
+		r := recover()
+		if r == nil {
+			panic("no fault or bounds check failure happened")
+		}
+		s := fmt.Sprintf("%s", r)
+		if s != "runtime error: index out of range" {
+			panic("bad panic: " + s)
+		}
+	}()
+	return uint64(x[0]) | uint64(x[1])<<8 | uint64(x[2])<<16 | uint64(x[3])<<24 |
+		uint64(x[4])<<32 | uint64(x[5])<<40 | uint64(x[6])<<48 | uint64(x[7])<<56
+}
+
+func test64i(x []byte, i int) uint64 {
+	defer func() {
+		r := recover()
+		if r == nil {
+			panic("no fault or bounds check failure happened")
+		}
+		s := fmt.Sprintf("%s", r)
+		if s != "runtime error: index out of range" {
+			panic("bad panic: " + s)
+		}
+	}()
+	return uint64(x[i+0]) | uint64(x[i+1])<<8 | uint64(x[i+2])<<16 | uint64(x[i+3])<<24 |
+		uint64(x[i+4])<<32 | uint64(x[i+5])<<40 | uint64(x[i+6])<<48 | uint64(x[i+7])<<56
+}
diff --git a/test/fixedbugs/issue15013.go b/test/fixedbugs/issue15013.go
new file mode 100644
index 0000000..9e218e6
--- /dev/null
+++ b/test/fixedbugs/issue15013.go
@@ -0,0 +1,24 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CL 21202 introduced a compiler crash in the handling of a varargs
+// function in the same recursive group as a function that calls it.
+// Nothing in the standard library caught the problem, so adding a test.
+
+package p
+
+func F1(p *int, a ...*int) (int, *int) {
+	if p == nil {
+		return F2(), a[0]
+	}
+	return 0, a[0]
+}
+
+func F2() int {
+	var i0, i1 int
+	a, _ := F1(&i0, &i1)
+	return a
+}
diff --git a/test/fixedbugs/issue15039.go b/test/fixedbugs/issue15039.go
new file mode 100644
index 0000000..85d9e83
--- /dev/null
+++ b/test/fixedbugs/issue15039.go
@@ -0,0 +1,25 @@
+// run
+
+// Copyright 2016 The Go Authors. 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() {
+	const fffd = "\uFFFD"
+
+	// runtime.intstring used to convert int64 to rune without checking
+	// for truncation.
+	u := uint64(0x10001f4a9)
+	big := string(u)
+	if big != fffd {
+		panic("big != bad")
+	}
+
+	// cmd/compile used to require integer constants to fit into an "int".
+	const huge = string(1<<100)
+	if huge != fffd {
+		panic("huge != bad")
+	}
+}
diff --git a/test/fixedbugs/issue15042.go b/test/fixedbugs/issue15042.go
new file mode 100644
index 0000000..85d5d6c
--- /dev/null
+++ b/test/fixedbugs/issue15042.go
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Exchanging two struct fields was compiled incorrectly.
+
+package main
+
+type S struct {
+	i int
+}
+
+func F(c bool, s1, s2 S) (int, int) {
+	if c {
+		s1.i, s2.i = s2.i, s1.i
+	}
+	return s1.i, s2.i
+}
+
+func main() {
+	i, j := F(true, S{1}, S{20})
+	if i != 20 || j != 1 {
+		panic(i+j)
+	}
+}
diff --git a/test/fixedbugs/issue15071.dir/exp/exp.go b/test/fixedbugs/issue15071.dir/exp/exp.go
new file mode 100644
index 0000000..e6041e6
--- /dev/null
+++ b/test/fixedbugs/issue15071.dir/exp/exp.go
@@ -0,0 +1,24 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exp
+
+func Exported(x int) int {
+	return inlined(x)
+}
+
+func inlined(x int) int {
+	y := 0
+	switch {
+	case x > 0:
+		y += 5
+		return 0 + y
+	case x < 1:
+		y += 6
+		fallthrough
+	default:
+		y += 7
+		return 2 + y
+	}
+}
diff --git a/test/fixedbugs/issue15071.dir/main.go b/test/fixedbugs/issue15071.dir/main.go
new file mode 100644
index 0000000..96790da
--- /dev/null
+++ b/test/fixedbugs/issue15071.dir/main.go
@@ -0,0 +1,14 @@
+// run
+
+// Copyright 2016 The Go Authors. 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"
+import "./exp"
+
+func main() {
+	_ = exp.Exported(len(os.Args))
+}
diff --git a/test/fixedbugs/issue15084.go b/test/fixedbugs/issue15084.go
new file mode 100644
index 0000000..7eb294e
--- /dev/null
+++ b/test/fixedbugs/issue15084.go
@@ -0,0 +1,30 @@
+// compile
+
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x
+
+type T struct {
+	i int
+	e interface{}
+}
+
+func (t *T) F() bool {
+	if t.i != 0 {
+		return false
+	}
+	_, ok := t.e.(string)
+	return ok
+}
+
+var x int
+
+func g(t *T) {
+	if t.F() || true {
+		if t.F() {
+			x = 0
+		}
+	}
+}
diff --git a/test/fixedbugs/issue15091.go b/test/fixedbugs/issue15091.go
new file mode 100644
index 0000000..00fb473
--- /dev/null
+++ b/test/fixedbugs/issue15091.go
@@ -0,0 +1,25 @@
+// errorcheck -0 -race
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sample
+
+type Html struct {
+	headerIDs map[string]int
+}
+
+// We don't want to see:
+//    internal error: (*Html).xyzzy autotmp_3 (type *int) recorded as live on entry, p.Pc=0
+// or (now, with the error caught earlier)
+//    Treating auto as if it were arg, func (*Html).xyzzy, node ...
+// caused by racewalker inserting instrumentation before an OAS where the Ninit
+// of the OAS defines part of its right-hand-side. (I.e., the race instrumentation
+// references a variable before it is defined.)
+func (options *Html) xyzzy(id string) string {
+	for count, found := options.headerIDs[id]; found; count, found = options.headerIDs[id] {
+		_ = count
+	}
+	return ""
+}
diff --git a/test/fixedbugs/issue15175.go b/test/fixedbugs/issue15175.go
new file mode 100644
index 0000000..55a8f7d
--- /dev/null
+++ b/test/fixedbugs/issue15175.go
@@ -0,0 +1,66 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Make sure unsigned shift results get sign-extended correctly.
+package main
+
+import "fmt"
+
+func main() {
+	failed := false
+	a6 := uint8(253)
+	if got := a6 >> 0; got != 253 {
+		fmt.Printf("uint8(253)>>0 = %v, wanted 253\n", got)
+		failed = true
+	}
+	if got := f1(0, 2, 1, 0, 0, 1, true); got != 255 {
+		fmt.Printf("f1(...) = %v, wanted 255\n", got)
+		failed = true
+	}
+	if got := f2(1); got != 242 {
+		fmt.Printf("f2(...) = %v, wanted 242\n", got)
+		failed = true
+	}
+	if got := f3(false, 0, 0); got != 254 {
+		fmt.Printf("f3(...) = %v, wanted 254\n", got)
+		failed = true
+	}
+	if failed {
+		panic("bad")
+	}
+}
+
+func f1(a1 uint, a2 int8, a3 int8, a4 int8, a5 uint8, a6 int, a7 bool) uint8 {
+	a5--
+	a4 += (a2 << a1 << 2) | (a4 ^ a4<<(a1&a1)) - a3                              // int8
+	a6 -= a6 >> (2 + uint32(a2)>>3)                                              // int
+	a1 += a1                                                                     // uint
+	a3 *= a4 << (a1 | a1) << (uint16(3) >> 2 & (1 - 0) & (uint16(1) << a5 << 3)) // int8
+	a7 = a7 || ((a2 == a4) || (a7 && a7) || ((a5 == a5) || (a7 || a7)))          // bool
+	return a5 >> a1
+}
+
+func f2(a1 uint8) uint8 {
+	a1--
+	a1--
+	a1 -= a1 + (a1 << 1) - (a1*a1*a1)<<(2-0+(3|3)-1)                // uint8
+	v1 := 0 * ((2 * 1) ^ 1) & ((uint(0) >> a1) + (2+0)*(uint(2)+0)) // uint
+	_ = v1
+	return a1 >> (((2 ^ 2) >> (v1 | 2)) + 0)
+}
+
+func f3(a1 bool, a2 uint, a3 int64) uint8 {
+	a3--
+	v1 := 1 & (2 & 1 * (1 ^ 2) & (uint8(3*1) >> 0)) // uint8
+	_ = v1
+	v1 += v1 - (v1 >> a2) + (v1 << (a2 ^ a2) & v1) // uint8
+	v1 *= v1                                       // uint8
+	a3--
+	v1 += v1 & v1 // uint8
+	v1--
+	v1 = ((v1 << 0) | v1>>0) + v1 // uint8
+	return v1 >> 0
+}
diff --git a/test/fixedbugs/issue15252.go b/test/fixedbugs/issue15252.go
new file mode 100644
index 0000000..370a885
--- /dev/null
+++ b/test/fixedbugs/issue15252.go
@@ -0,0 +1,32 @@
+// run
+
+// Copyright 2016 The Go 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 makes sure that we use all 64 bits of an
+// index, even on 32 bit machines.  It also tests that nacl
+// can compile 64 bit indexes loaded from ODOTPTR properly.
+
+package main
+
+type T struct {
+	i int64
+}
+
+func f(t *T) byte {
+	b := [2]byte{3, 4}
+	return b[t.i]
+}
+
+func main() {
+	t := &T{0x100000001}
+	defer func() {
+		r := recover()
+		if r == nil {
+			panic("panic wasn't recoverable")
+		}
+	}()
+	f(t)
+	panic("index didn't panic")
+}
diff --git a/test/fixedbugs/issue15277.go b/test/fixedbugs/issue15277.go
new file mode 100644
index 0000000..719c9a4
--- /dev/null
+++ b/test/fixedbugs/issue15277.go
@@ -0,0 +1,38 @@
+// run
+
+// Copyright 2016 The Go 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
+
+package main
+
+import "runtime"
+
+type big [10 << 20]byte
+
+func f(x *big, start int64) {
+	if delta := inuse() - start; delta < 9<<20 {
+		println("after alloc: expected delta at least 9MB, got: ", delta)
+	}
+	x = nil
+	if delta := inuse() - start; delta > 1<<20 {
+		println("after drop: expected delta below 1MB, got: ", delta)
+	}
+	x = new(big)
+	if delta := inuse() - start; delta < 9<<20 {
+		println("second alloc: expected delta at least 9MB, got: ", delta)
+	}
+}
+
+func main() {
+	x := inuse()
+	f(new(big), x)
+}
+
+func inuse() int64 {
+	runtime.GC()
+	var st runtime.MemStats
+	runtime.ReadMemStats(&st)
+	return int64(st.Alloc)
+}
diff --git a/test/fixedbugs/issue15281.go b/test/fixedbugs/issue15281.go
new file mode 100644
index 0000000..187c96f
--- /dev/null
+++ b/test/fixedbugs/issue15281.go
@@ -0,0 +1,64 @@
+// run
+
+// Copyright 2016 The Go Authors.  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 "runtime"
+
+func main() {
+	{
+		x := inuse()
+		c := make(chan []byte, 10)
+		c <- make([]byte, 10<<20)
+		close(c)
+		f1(c, x)
+	}
+	{
+		x := inuse()
+		c := make(chan []byte, 10)
+		c <- make([]byte, 10<<20)
+		close(c)
+		f2(c, x)
+	}
+}
+
+func f1(c chan []byte, start int64) {
+	for x := range c {
+		if delta := inuse() - start; delta < 9<<20 {
+			println("BUG: f1: after alloc: expected delta at least 9MB, got: ", delta)
+			println(x)
+		}
+		x = nil
+		if delta := inuse() - start; delta > 1<<20 {
+			println("BUG: f1: after alloc: expected delta below 1MB, got: ", delta)
+			println(x)
+		}
+	}
+}
+
+func f2(c chan []byte, start int64) {
+	for {
+		x, ok := <-c
+		if !ok {
+			break
+		}
+		if delta := inuse() - start; delta < 9<<20 {
+			println("BUG: f2: after alloc: expected delta at least 9MB, got: ", delta)
+			println(x)
+		}
+		x = nil
+		if delta := inuse() - start; delta > 1<<20 {
+			println("BUG: f2: after alloc: expected delta below 1MB, got: ", delta)
+			println(x)
+		}
+	}
+}
+
+func inuse() int64 {
+	runtime.GC()
+	var st runtime.MemStats
+	runtime.ReadMemStats(&st)
+	return int64(st.Alloc)
+}
diff --git a/test/fixedbugs/issue15311.go b/test/fixedbugs/issue15311.go
new file mode 100644
index 0000000..81fa541
--- /dev/null
+++ b/test/fixedbugs/issue15311.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2016 The Go 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 compiler was failing to correctly report an error when a dot
+// expression was used a struct literal key.
+
+package p
+
+type T struct {
+        toInt    map[string]int
+        toString map[int]string
+}
+
+var t = T{
+        foo.toInt:    make(map[string]int), // ERROR "field name"
+        bar.toString: make(map[int]string), // ERROR "field name"
+}
diff --git a/test/fixedbugs/issue15329.go b/test/fixedbugs/issue15329.go
new file mode 100644
index 0000000..30fbf13
--- /dev/null
+++ b/test/fixedbugs/issue15329.go
@@ -0,0 +1,79 @@
+// run
+
+// Copyright 2016 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Previously, cmd/compile would rewrite
+//
+//     check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer()))
+//
+// to
+//
+//     var autotmp_1 uintptr = testMeth(1).Pointer()
+//     var autotmp_2 uintptr = testMeth(2).Pointer()
+//     check(unsafe.Pointer(autotmp_1), unsafe.Pointer(autotmp_2))
+//
+// However, that means autotmp_1 is the only reference to the int
+// variable containing the value "1", but it's not a pointer type,
+// so it was at risk of being garbage collected by the evaluation of
+// testMeth(2).Pointer(), even though package unsafe's documentation
+// says the original code was allowed.
+//
+// Now cmd/compile rewrites it to
+//
+//     var autotmp_1 unsafe.Pointer = unsafe.Pointer(testMeth(1).Pointer())
+//     var autotmp_2 unsafe.Pointer = unsafe.Pointer(testMeth(2).Pointer())
+//     check(autotmp_1, autotmp_2)
+//
+// to ensure the pointed-to variables are visible to the GC.
+
+package main
+
+import (
+	"fmt"
+	"reflect"
+	"runtime"
+	"unsafe"
+)
+
+func main() {
+	// Test all the different ways we can invoke reflect.Value.Pointer.
+
+	// Direct method invocation.
+	check(unsafe.Pointer(testMeth(1).Pointer()), unsafe.Pointer(testMeth(2).Pointer()))
+
+	// Invocation via method expression.
+	check(unsafe.Pointer(reflect.Value.Pointer(testMeth(1))), unsafe.Pointer(reflect.Value.Pointer(testMeth(2))))
+
+	// Invocation via interface.
+	check(unsafe.Pointer(testInter(1).Pointer()), unsafe.Pointer(testInter(2).Pointer()))
+
+	// Invocation via method value.
+	check(unsafe.Pointer(testFunc(1)()), unsafe.Pointer(testFunc(2)()))
+}
+
+func check(p, q unsafe.Pointer) {
+	a, b := *(*int)(p), *(*int)(q)
+	if a != 1 || b != 2 {
+		fmt.Printf("got %v, %v; expected 1, 2\n", a, b)
+	}
+}
+
+func testMeth(x int) reflect.Value {
+	// Force GC to run.
+	runtime.GC()
+	return reflect.ValueOf(&x)
+}
+
+type Pointerer interface {
+	Pointer() uintptr
+}
+
+func testInter(x int) Pointerer {
+	return testMeth(x)
+}
+
+func testFunc(x int) func() uintptr {
+	return testMeth(x).Pointer
+}
diff --git a/test/fixedbugs/issue15439.go b/test/fixedbugs/issue15439.go
new file mode 100644
index 0000000..840a3c0
--- /dev/null
+++ b/test/fixedbugs/issue15439.go
@@ -0,0 +1,25 @@
+// run
+
+// Copyright 2016 The Go Authors.  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 "reflect"
+
+func main() {
+	a := &struct{ x int }{}
+	b := &struct{ x int "" }{}
+
+	ta := reflect.TypeOf(a)
+	tb := reflect.TypeOf(b)
+
+	// Ensure cmd/compile treats absent and empty tags as equivalent.
+	a = b
+
+	// Ensure package reflect treats absent and empty tags as equivalent.
+	if !tb.AssignableTo(ta) {
+		panic("fail")
+	}
+}
diff --git a/test/fixedbugs/issue15470.dir/a.go b/test/fixedbugs/issue15470.dir/a.go
new file mode 100644
index 0000000..1fcf3ea
--- /dev/null
+++ b/test/fixedbugs/issue15470.dir/a.go
@@ -0,0 +1,24 @@
+package a
+
+import "io"
+
+type T interface {
+	M0(_ int)
+	M1(x, _ int) // _ (blank) caused crash
+	M2() (x, _ int)
+}
+
+type S struct{}
+
+func (S) M0(_ int) {}
+func (S) M1(x, _ int) {}
+func (S) M2() (x, _ int) { return }
+func (_ S) M3() {}
+
+// Snippet from x/tools/godoc/analysis/analysis.go.
+// Offending code from #5470.
+type Link interface {
+	Start() int
+	End() int
+	Write(w io.Writer, _ int, start bool) // _ (blank) caused crash
+}
diff --git a/test/fixedbugs/issue15470.dir/b.go b/test/fixedbugs/issue15470.dir/b.go
new file mode 100644
index 0000000..863ee9f
--- /dev/null
+++ b/test/fixedbugs/issue15470.dir/b.go
@@ -0,0 +1,3 @@
+package b
+
+import _ "./a" // must not fail
diff --git a/test/fixedbugs/issue15470.go b/test/fixedbugs/issue15470.go
new file mode 100644
index 0000000..22b48fe
--- /dev/null
+++ b/test/fixedbugs/issue15470.go
@@ -0,0 +1,10 @@
+// compiledir
+
+// Copyright 2016 The Go 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 15470: Make sure special-case signatures can
+// be exported and imported w/o problems.
+
+package ignored
diff --git a/test/fixedbugs/issue15548.dir/a.go b/test/fixedbugs/issue15548.dir/a.go
new file mode 100644
index 0000000..3c593fc
--- /dev/null
+++ b/test/fixedbugs/issue15548.dir/a.go
@@ -0,0 +1,17 @@
+// Copyright 2016 The Go Authors. 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 I0 interface {
+	I1
+}
+
+type T struct {
+	I1
+}
+
+type I1 interface {
+	M(*T) // removing * makes crash go away
+}
diff --git a/test/fixedbugs/issue15548.dir/b.go b/test/fixedbugs/issue15548.dir/b.go
new file mode 100644
index 0000000..b46f5ad
--- /dev/null
+++ b/test/fixedbugs/issue15548.dir/b.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. 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"
+
+var X a.T
diff --git a/test/fixedbugs/issue15548.dir/c.go b/test/fixedbugs/issue15548.dir/c.go
new file mode 100644
index 0000000..6d3f3be
--- /dev/null
+++ b/test/fixedbugs/issue15548.dir/c.go
@@ -0,0 +1,10 @@
+// Copyright 2016 The Go Authors. 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"
+	_ "./a"
+)
diff --git a/test/fixedbugs/issue15548.go b/test/fixedbugs/issue15548.go
new file mode 100644
index 0000000..4d2844d
--- /dev/null
+++ b/test/fixedbugs/issue15548.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2016 The Go Authors. 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/issue15572.dir/a.go b/test/fixedbugs/issue15572.dir/a.go
new file mode 100644
index 0000000..1356601
--- /dev/null
+++ b/test/fixedbugs/issue15572.dir/a.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go Authors. 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 T struct {
+}
+
+func F() []T {
+	return []T{T{}}
+}
+
+func Fi() []T {
+	return []T{{}} // element with implicit composite literal type
+}
+
+func Fp() []*T {
+	return []*T{&T{}}
+}
+
+func Fip() []*T {
+	return []*T{{}} // element with implicit composite literal type
+}
+
+func Gp() map[int]*T {
+	return map[int]*T{0: &T{}}
+}
+
+func Gip() map[int]*T {
+	return map[int]*T{0: {}} // element with implicit composite literal type
+}
+
+func Hp() map[*T]int {
+	return map[*T]int{&T{}: 0}
+}
+
+func Hip() map[*T]int {
+	return map[*T]int{{}: 0} // key with implicit composite literal type
+}
diff --git a/test/fixedbugs/issue15572.dir/b.go b/test/fixedbugs/issue15572.dir/b.go
new file mode 100644
index 0000000..355accc
--- /dev/null
+++ b/test/fixedbugs/issue15572.dir/b.go
@@ -0,0 +1,27 @@
+// Copyright 2016 The Go Authors. 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.F()
+	a.Fi()
+}
+
+func Fp() {
+	a.Fp()
+	a.Fip()
+}
+
+func Gp() {
+	a.Gp()
+	a.Gip()
+}
+
+func Hp() {
+	a.Hp()
+	a.Hip()
+}
diff --git a/test/fixedbugs/issue15572.go b/test/fixedbugs/issue15572.go
new file mode 100644
index 0000000..cf77778
--- /dev/null
+++ b/test/fixedbugs/issue15572.go
@@ -0,0 +1,11 @@
+// compiledir
+
+// Copyright 2016 The Go 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 exporting composite literals with implicit
+// types doesn't crash the typechecker when running over
+// inlined function bodies containing such literals.
+
+package ignored
diff --git a/test/fixedbugs/issue15585.go b/test/fixedbugs/issue15585.go
new file mode 100644
index 0000000..79eb13f
--- /dev/null
+++ b/test/fixedbugs/issue15585.go
@@ -0,0 +1,45 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug
+
+func example(n int) (rc int) {
+	var cc, ll, pp, rr [27]int
+	for q0 := 0; q0 < n-2; q0++ {
+		for q1 := q0 + 2; q1 < n; q1++ {
+			var c, d, l, p, r int
+			b0 := 1 << uint(q0)
+			b1 := 1 << uint(q1)
+			l = ((b0 << 1) | b1) << 1
+			c = b0 | b1 | (-1 << uint(n))
+			r = ((b0 >> 1) | b1) >> 1
+		E:
+			if c != -1 {
+				p = ^(l | c | r)
+			} else {
+				rc++
+				goto R
+			}
+		L:
+			if p != 0 {
+				lsb := p & -p
+				p &^= lsb
+				ll[d], cc[d], rr[d], pp[d] = l, c, r, p
+				l, c, r = (l|lsb)<<1, c|lsb, (r|lsb)>>1
+				d++
+				goto E
+			}
+		R:
+			d--
+			if d >= 0 {
+				l, c, r, p = ll[d], cc[d], rr[d], pp[d]
+				goto L
+			}
+		}
+	}
+	rc <<= 1
+	return
+}
diff --git a/test/fixedbugs/issue15602.go b/test/fixedbugs/issue15602.go
new file mode 100644
index 0000000..badf813
--- /dev/null
+++ b/test/fixedbugs/issue15602.go
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2016 The Go Authors. 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(i interface{}) {
+	i, _ = i.(error)
+}
diff --git a/test/fixedbugs/issue15604.go b/test/fixedbugs/issue15604.go
new file mode 100644
index 0000000..4dc0b0b
--- /dev/null
+++ b/test/fixedbugs/issue15604.go
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug
+
+import "os"
+
+func f(err error) {
+	var ok bool
+	if err, ok = err.(*os.PathError); ok {
+		if err == os.ErrNotExist {
+		}
+	}
+}
diff --git a/test/fixedbugs/issue15646.dir/a.go b/test/fixedbugs/issue15646.dir/a.go
new file mode 100644
index 0000000..842f196
--- /dev/null
+++ b/test/fixedbugs/issue15646.dir/a.go
@@ -0,0 +1,23 @@
+// Copyright 2016 The Go Authors. 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 T struct{}
+
+func (T) m() string {
+	return "m"
+}
+
+func (*T) mp() string {
+	return "mp"
+}
+
+func F() func(T) string {
+	return T.m // method expression
+}
+
+func Fp() func(*T) string {
+	return (*T).mp // method expression
+}
diff --git a/test/fixedbugs/issue15646.dir/b.go b/test/fixedbugs/issue15646.dir/b.go
new file mode 100644
index 0000000..3d011ba
--- /dev/null
+++ b/test/fixedbugs/issue15646.dir/b.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Go Authors. 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" // import must succeed
+
+func main() {
+	if a.F()(a.T{}) != "m" {
+		panic(0)
+	}
+	if a.Fp()(nil) != "mp" {
+		panic(1)
+	}
+}
diff --git a/test/fixedbugs/issue15646.go b/test/fixedbugs/issue15646.go
new file mode 100644
index 0000000..cd4ba9d
--- /dev/null
+++ b/test/fixedbugs/issue15646.go
@@ -0,0 +1,9 @@
+// rundir
+
+// Copyright 2016 The Go 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 method expressions are correctly encoded
+// in binary export data and can be imported again.
+package ignore
\ No newline at end of file
diff --git a/test/fixedbugs/issue15733.go b/test/fixedbugs/issue15733.go
new file mode 100644
index 0000000..8f609e6
--- /dev/null
+++ b/test/fixedbugs/issue15733.go
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2016 The Go Authors. 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
+
+type S struct {
+	a [1 << 16]byte
+}
+
+func f1() {
+	p := &S{}
+	_ = p
+}
+
+type T [1 << 16]byte
+
+func f2() {
+	p := &T{}
+	_ = p
+}
diff --git a/test/fixedbugs/issue15747.go b/test/fixedbugs/issue15747.go
new file mode 100644
index 0000000..34ec719
--- /dev/null
+++ b/test/fixedbugs/issue15747.go
@@ -0,0 +1,41 @@
+// errorcheck -0 -live
+
+// Copyright 2016 The Go 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 15747: liveness analysis was marking heap-escaped params live too much,
+// and worse was using the wrong bitmap bits to do so.
+
+package p
+
+var global *[]byte
+
+type Q struct{}
+
+type T struct{ M string }
+
+var b bool
+
+func f1(q *Q, xx []byte) interface{} { // ERROR "live at entry to f1: q xx" "live at call to newobject: q xx" "live at call to writebarrierptr: q &xx"
+	// xx was copied from the stack to the heap on the previous line:
+	// xx was live for the first two prints but then it switched to &xx
+	// being live. We should not see plain xx again.
+	if b {
+		global = &xx // ERROR "live at call to writebarrierptr: q &xx$"
+	}
+	xx, _, err := f2(xx, 5) // ERROR "live at call to newobject: q( d)? &xx( odata.ptr)?" "live at call to writebarrierptr: q (e|err.data err.type)$"
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func f2(d []byte, n int) (odata, res []byte, e interface{}) { // ERROR "live at entry to f2: d"
+	if n > len(d) {
+		return d, nil, &T{M: "hello"} // ERROR "live at call to newobject: d"
+	}
+	res = d[:n]
+	odata = d[n:]
+	return
+}
diff --git a/test/fixedbugs/issue15747b.go b/test/fixedbugs/issue15747b.go
new file mode 100644
index 0000000..9620d3d
--- /dev/null
+++ b/test/fixedbugs/issue15747b.go
@@ -0,0 +1,19 @@
+// compile
+
+// Copyright 2016 The Go 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 15747: If a ODCL is dropped, for example when inlining,
+// then it's easy to end up not initializing the '&x' pseudo-variable
+// to point to an actual allocation. The liveness analysis will detect
+// this and abort the computation, so this test just checks that the
+// compilation succeeds.
+
+package p
+
+type R [100]byte
+
+func (x R) New() *R {
+	return &x
+}
diff --git a/test/fixedbugs/issue15838.dir/a.go b/test/fixedbugs/issue15838.dir/a.go
new file mode 100644
index 0000000..15b7f1d
--- /dev/null
+++ b/test/fixedbugs/issue15838.dir/a.go
@@ -0,0 +1,61 @@
+// Copyright 2016 The Go Authors. 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
+
+func F1() {
+L:
+	goto L
+}
+
+func F2() {
+L:
+	for {
+		break L
+	}
+}
+
+func F3() {
+L:
+	for {
+		continue L
+	}
+}
+
+func F4() {
+	switch {
+	case true:
+		fallthrough
+	default:
+	}
+}
+
+type T struct{}
+
+func (T) M1() {
+L:
+	goto L
+}
+
+func (T) M2() {
+L:
+	for {
+		break L
+	}
+}
+
+func (T) M3() {
+L:
+	for {
+		continue L
+	}
+}
+
+func (T) M4() {
+	switch {
+	case true:
+		fallthrough
+	default:
+	}
+}
diff --git a/test/fixedbugs/issue15838.dir/b.go b/test/fixedbugs/issue15838.dir/b.go
new file mode 100644
index 0000000..9fd6efc
--- /dev/null
+++ b/test/fixedbugs/issue15838.dir/b.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. 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"
+
+type T struct{ a.T }
diff --git a/test/fixedbugs/issue15838.go b/test/fixedbugs/issue15838.go
new file mode 100644
index 0000000..fb1c64d
--- /dev/null
+++ b/test/fixedbugs/issue15838.go
@@ -0,0 +1,12 @@
+// compiledir
+
+// Copyright 2016 The Go 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 cases for issue #15838, and related failures.
+// Make sure the importer correctly sets up nodes for
+// label decls, goto, continue, break, and fallthrough
+// statements.
+
+package ignored
diff --git a/test/fixedbugs/issue15898.go b/test/fixedbugs/issue15898.go
new file mode 100644
index 0000000..7b66ea2
--- /dev/null
+++ b/test/fixedbugs/issue15898.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. 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(e interface{}) {
+	switch e.(type) {
+	case nil, nil: // ERROR "multiple nil cases in type switch"
+	}
+
+	switch e.(type) {
+	case nil:
+	case nil: // ERROR "multiple nil cases in type switch"
+	}
+}
diff --git a/test/fixedbugs/issue15902.go b/test/fixedbugs/issue15902.go
new file mode 100644
index 0000000..9511a22
--- /dev/null
+++ b/test/fixedbugs/issue15902.go
@@ -0,0 +1,27 @@
+// run
+
+// Copyright 2016 The Go 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 makes sure we don't use 4-byte unaligned writes
+// to zero memory on architectures that don't support them.
+
+package main
+
+type T struct {
+	a byte
+	b [10]byte
+}
+
+//go:noinline
+func f(t *T) {
+	// t will be aligned, so &t.b won't be.
+	t.b = [10]byte{}
+}
+
+var t T
+
+func main() {
+	f(&t)
+}
diff --git a/test/fixedbugs/issue15920.dir/a.go b/test/fixedbugs/issue15920.dir/a.go
new file mode 100644
index 0000000..15f9235
--- /dev/null
+++ b/test/fixedbugs/issue15920.dir/a.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. 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 Error error
+
+func F() Error { return nil }
diff --git a/test/fixedbugs/issue15920.dir/b.go b/test/fixedbugs/issue15920.dir/b.go
new file mode 100644
index 0000000..0a36c5c
--- /dev/null
+++ b/test/fixedbugs/issue15920.dir/b.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. 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"
diff --git a/test/fixedbugs/issue15920.go b/test/fixedbugs/issue15920.go
new file mode 100644
index 0000000..4d2844d
--- /dev/null
+++ b/test/fixedbugs/issue15920.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2016 The Go Authors. 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/issue15926.go b/test/fixedbugs/issue15926.go
new file mode 100644
index 0000000..76e25eb
--- /dev/null
+++ b/test/fixedbugs/issue15926.go
@@ -0,0 +1,20 @@
+// build
+
+// Copyright 2016 The Go 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 15926: linker was adding .def to the end of symbols, causing
+// a name collision with a method actually named def.
+
+package main
+
+type S struct{}
+
+func (s S) def() {}
+
+var I = S.def
+
+func main() {
+    I(S{})
+}
diff --git a/test/fixedbugs/issue15961.go b/test/fixedbugs/issue15961.go
new file mode 100644
index 0000000..db3d662
--- /dev/null
+++ b/test/fixedbugs/issue15961.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package y
+
+type symSet []int
+
+//go:noinline
+func (s symSet) len() (r int) {
+	return 0
+}
+
+func f(m map[int]symSet) {
+	var symSet []int
+	for _, x := range symSet {
+		m[x] = nil
+	}
+}
diff --git a/test/fixedbugs/issue15975.go b/test/fixedbugs/issue15975.go
new file mode 100644
index 0000000..56a50e1
--- /dev/null
+++ b/test/fixedbugs/issue15975.go
@@ -0,0 +1,36 @@
+// run
+
+// Copyright 2016 The Go Authors. 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 fail bool
+
+type Closer interface {
+	Close()
+}
+
+func nilInterfaceDeferCall() {
+	var x Closer
+	defer x.Close()
+	// if it panics when evaluating x.Close, it should not reach here
+	fail = true
+}
+
+func shouldPanic(f func()) {
+	defer func() {
+		if recover() == nil {
+			panic("did not panic")
+		}
+	}()
+	f()
+}
+
+func main() {
+	shouldPanic(nilInterfaceDeferCall)
+	if fail {
+		panic("fail")
+	}
+}
diff --git a/test/fixedbugs/issue15988.go b/test/fixedbugs/issue15988.go
new file mode 100644
index 0000000..2bed2a9
--- /dev/null
+++ b/test/fixedbugs/issue15988.go
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2016 The Go Authors. 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(p, q []int) {
+	p = append(q, 5)
+	sink = &p
+}
+
+var sink *[]int
diff --git a/test/fixedbugs/issue16008.go b/test/fixedbugs/issue16008.go
new file mode 100644
index 0000000..0e369ef
--- /dev/null
+++ b/test/fixedbugs/issue16008.go
@@ -0,0 +1,56 @@
+// errorcheck -0 -race
+
+// Copyright 2016 The Go Authors. 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
+
+const benchmarkNumNodes = 10000
+
+func BenchmarkUpdateNodeTransaction(b B) {
+	s, nodeIDs := setupNodes(benchmarkNumNodes)
+	b.ResetTimer()
+	for i := 0; i < b.N(); i++ {
+		_ = s.Update(func(tx1 Tx) error {
+			_ = UpdateNode(tx1, &Node{
+				ID: nodeIDs[i%benchmarkNumNodes],
+			})
+			return nil
+		})
+	}
+}
+
+type B interface {
+	ResetTimer()
+	N() int
+}
+
+type Tx interface {
+}
+
+type Node struct {
+	ID string
+}
+
+type MemoryStore struct {
+}
+
+// go:noinline
+func setupNodes(n int) (s *MemoryStore, nodeIDs []string) {
+	return
+}
+
+//go:noinline
+func (s *MemoryStore) Update(cb func(Tx) error) error {
+	return nil
+}
+
+var sink interface{}
+
+//go:noinline
+func UpdateNode(tx Tx, n *Node) error {
+	sink = tx
+	sink = n
+	return nil
+}
diff --git a/test/fixedbugs/issue16016.go b/test/fixedbugs/issue16016.go
new file mode 100644
index 0000000..e738e1d
--- /dev/null
+++ b/test/fixedbugs/issue16016.go
@@ -0,0 +1,35 @@
+// run
+
+// Copyright 2016 The Go Authors. 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 "time"
+
+type T struct{}
+
+func (*T) Foo(vals []interface{}) {
+	switch v := vals[0].(type) {
+	case string:
+		_ = v
+	}
+}
+
+type R struct{ *T }
+
+type Q interface {
+	Foo([]interface{})
+}
+
+func main() {
+	var q Q = &R{&T{}}
+	for i := 0; i < 10000; i++ {
+		go func() {
+			defer q.Foo([]interface{}{"meow"})
+			time.Sleep(100 * time.Millisecond)
+		}()
+	}
+	time.Sleep(1 * time.Second)
+}
diff --git a/test/fixedbugs/issue16037_run.go b/test/fixedbugs/issue16037_run.go
new file mode 100644
index 0000000..23fff59
--- /dev/null
+++ b/test/fixedbugs/issue16037_run.go
@@ -0,0 +1,70 @@
+// +build !nacl,!android
+// run
+
+// Copyright 2016 The Go Authors. 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"
+	"html/template"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+)
+
+var tmpl = template.Must(template.New("main").Parse(`
+package main
+
+type T struct {
+    {{range .Names}}
+	{{.Name}} *string
+	{{end}}
+}
+
+{{range .Names}}
+func (t *T) Get{{.Name}}() string {
+	if t.{{.Name}} == nil {
+		return ""
+	}
+	return *t.{{.Name}}
+}
+{{end}}
+
+func main() {}
+`))
+
+func main() {
+	const n = 5000
+
+	type Name struct{ Name string }
+	var t struct{ Names []Name }
+	for i := 0; i < n; i++ {
+		t.Names = append(t.Names, Name{Name: fmt.Sprintf("H%06X", i)})
+	}
+
+	buf := new(bytes.Buffer)
+	if err := tmpl.Execute(buf, t); err != nil {
+		log.Fatal(err)
+	}
+
+	dir, err := ioutil.TempDir("", "issue16037-")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer os.RemoveAll(dir)
+	path := filepath.Join(dir, "ridiculous_number_of_fields.go")
+	if err := ioutil.WriteFile(path, buf.Bytes(), 0664); err != nil {
+		log.Fatal(err)
+	}
+
+	out, err := exec.Command("go", "build", "-o="+filepath.Join(dir, "out"), path).CombinedOutput()
+	if err != nil {
+		log.Fatalf("build failed: %v\n%s", err, out)
+	}
+}
diff --git a/test/fixedbugs/issue16095.go b/test/fixedbugs/issue16095.go
new file mode 100644
index 0000000..864b4b7
--- /dev/null
+++ b/test/fixedbugs/issue16095.go
@@ -0,0 +1,104 @@
+// run
+
+// Copyright 2016 The Go Authors. 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"
+	"runtime"
+)
+
+var sink *[20]byte
+
+func f() (x [20]byte) {
+	// Initialize x.
+	for i := range x {
+		x[i] = byte(i)
+	}
+
+	// Force x to be allocated on the heap.
+	sink = &x
+	sink = nil
+
+	// Go to deferreturn after the panic below.
+	defer func() {
+		recover()
+	}()
+
+	// This call collects the heap-allocated version of x (oops!)
+	runtime.GC()
+
+	// Allocate that same object again and clobber it.
+	y := new([20]byte)
+	for i := 0; i < 20; i++ {
+		y[i] = 99
+	}
+	// Make sure y is heap allocated.
+	sink = y
+
+	panic(nil)
+
+	// After the recover we reach the deferreturn, which
+	// copies the heap version of x back to the stack.
+	// It gets the pointer to x from a stack slot that was
+	// not marked as live during the call to runtime.GC().
+}
+
+var sinkint int
+
+func g(p *int) (x [20]byte) {
+	// Initialize x.
+	for i := range x {
+		x[i] = byte(i)
+	}
+
+	// Force x to be allocated on the heap.
+	sink = &x
+	sink = nil
+
+	// Go to deferreturn after the panic below.
+	defer func() {
+		recover()
+	}()
+
+	// This call collects the heap-allocated version of x (oops!)
+	runtime.GC()
+
+	// Allocate that same object again and clobber it.
+	y := new([20]byte)
+	for i := 0; i < 20; i++ {
+		y[i] = 99
+	}
+	// Make sure y is heap allocated.
+	sink = y
+
+	// panic with a non-call (with no fallthrough)
+	for {
+		sinkint = *p
+	}
+
+	// After the recover we reach the deferreturn, which
+	// copies the heap version of x back to the stack.
+	// It gets the pointer to x from a stack slot that was
+	// not marked as live during the call to runtime.GC().
+}
+
+func main() {
+	x := f()
+	for i, v := range x {
+		if v != byte(i) {
+			fmt.Printf("%v\n", x)
+			panic("bad f")
+		}
+	}
+	x = g(nil)
+	for i, v := range x {
+		if v != byte(i) {
+			fmt.Printf("%v\n", x)
+			panic("bad g")
+		}
+	}
+}
diff --git a/test/fixedbugs/issue16130.go b/test/fixedbugs/issue16130.go
new file mode 100644
index 0000000..19c8264
--- /dev/null
+++ b/test/fixedbugs/issue16130.go
@@ -0,0 +1,43 @@
+// run
+
+// Copyright 2016 The Go 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 interface conversion error panics with an "interface
+// conversion" run-time error. It was (incorrectly) panicing with a
+// "nil pointer dereference."
+
+package main
+
+import (
+	"fmt"
+	"runtime"
+	"strings"
+)
+
+type I interface {
+	Get() int
+}
+
+func main() {
+	defer func() {
+		r := recover()
+		if r == nil {
+			panic("expected panic")
+		}
+		re, ok := r.(runtime.Error)
+		if !ok {
+			panic(fmt.Sprintf("got %T, expected runtime.Error", r))
+		}
+		if !strings.Contains(re.Error(), "interface conversion") {
+			panic(fmt.Sprintf("got %q, expected interface conversion error", re.Error()))
+		}
+	}()
+	e := (interface{})(0)
+	if _, ok := e.(I); ok {
+		panic("unexpected interface conversion success")
+	}
+	fmt.Println(e.(I))
+	panic("unexpected interface conversion success")
+}
diff --git a/test/fixedbugs/issue16133.dir/a1.go b/test/fixedbugs/issue16133.dir/a1.go
new file mode 100644
index 0000000..497cccf
--- /dev/null
+++ b/test/fixedbugs/issue16133.dir/a1.go
@@ -0,0 +1,7 @@
+package a
+
+type X string
+
+func NewX() X {
+	return ""
+}
diff --git a/test/fixedbugs/issue16133.dir/a2.go b/test/fixedbugs/issue16133.dir/a2.go
new file mode 100644
index 0000000..497cccf
--- /dev/null
+++ b/test/fixedbugs/issue16133.dir/a2.go
@@ -0,0 +1,7 @@
+package a
+
+type X string
+
+func NewX() X {
+	return ""
+}
diff --git a/test/fixedbugs/issue16133.dir/b.go b/test/fixedbugs/issue16133.dir/b.go
new file mode 100644
index 0000000..be1bebf
--- /dev/null
+++ b/test/fixedbugs/issue16133.dir/b.go
@@ -0,0 +1,7 @@
+package b
+
+import "./a2"
+
+type T struct {
+	X a.X
+}
diff --git a/test/fixedbugs/issue16133.dir/c.go b/test/fixedbugs/issue16133.dir/c.go
new file mode 100644
index 0000000..b25fe5a
--- /dev/null
+++ b/test/fixedbugs/issue16133.dir/c.go
@@ -0,0 +1,10 @@
+package p
+
+import (
+	"./a1"
+	"./b"
+)
+
+var _ = b.T{
+	X: a.NewX(), // ERROR `cannot use "a1"\.NewX\(\)`
+}
diff --git a/test/fixedbugs/issue16133.go b/test/fixedbugs/issue16133.go
new file mode 100644
index 0000000..4afffc5
--- /dev/null
+++ b/test/fixedbugs/issue16133.go
@@ -0,0 +1,10 @@
+// errorcheckdir -s
+
+// Copyright 2016 The Go 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 error messages referring to multiple different
+// packages with the same package name.
+
+package ignored
diff --git a/test/fixedbugs/issue16193.go b/test/fixedbugs/issue16193.go
new file mode 100644
index 0000000..eada62d
--- /dev/null
+++ b/test/fixedbugs/issue16193.go
@@ -0,0 +1,27 @@
+// compile
+
+// Copyright 2016 The Go 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 compiler used the name "glob" as the function holding a global
+// function literal, colliding with an actual function named "glob".
+
+package main
+
+func glob() {
+	func() {
+	}()
+}
+
+var c1 = func() {
+}
+
+var c2 = func() {
+}
+
+func main() {
+	glob()
+	c1()
+	c2()
+}
diff --git a/test/fixedbugs/issue16249.go b/test/fixedbugs/issue16249.go
new file mode 100644
index 0000000..723d5d9
--- /dev/null
+++ b/test/fixedbugs/issue16249.go
@@ -0,0 +1,58 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Liveness calculations were wrong for a result parameter pushed onto
+// the heap in a function that used defer.  Program would crash with
+//     runtime: bad pointer in frame main.A at 0xc4201e6838: 0x1
+
+package main
+
+import "errors"
+
+var sink interface{}
+
+//go:noinline
+func f(err *error) {
+	if err != nil {
+		sink = err
+	}
+}
+
+//go:noinline
+func A(n, m int64) (res int64, err error) {
+	defer f(&err) // output parameter's address escapes to a defer.
+	if n < 0 {
+		err = errors.New("No negative")
+		return
+	}
+	if n <= 1 {
+		res = n
+		return
+	}
+	res = B(m) // This call to B drizzles a little junk on the stack.
+	res, err = A(n-1, m)
+	res++
+	return
+}
+
+// B does a little bit of recursion dribbling not-zero onto the stack.
+//go:noinline
+func B(n int64) (res int64) {
+	if n <= 1 { // Prefer to leave a 1 on the stack.
+		return n
+	}
+	return 1 + B(n-1)
+}
+
+func main() {
+	x, e := A(0, 0)
+	for j := 0; j < 4; j++ { // j controls amount of B's stack dribble
+		for i := 0; i < 1000; i++ { // try more and more recursion until stack growth occurs in newobject in prologue
+			x, e = A(int64(i), int64(j))
+		}
+	}
+	_, _ = x, e
+}
diff --git a/test/fixedbugs/issue2615.go b/test/fixedbugs/issue2615.go
index 686e1e1..831110e 100644
--- a/test/fixedbugs/issue2615.go
+++ b/test/fixedbugs/issue2615.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue3552.dir/one.go b/test/fixedbugs/issue3552.dir/one.go
index 491ada1..e594db7 100644
--- a/test/fixedbugs/issue3552.dir/one.go
+++ b/test/fixedbugs/issue3552.dir/one.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue3552.dir/two.go b/test/fixedbugs/issue3552.dir/two.go
index 1366d24..2f330bf 100644
--- a/test/fixedbugs/issue3552.dir/two.go
+++ b/test/fixedbugs/issue3552.dir/two.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue3705.go b/test/fixedbugs/issue3705.go
index 64ef38b..ed0a193 100644
--- a/test/fixedbugs/issue3705.go
+++ b/test/fixedbugs/issue3705.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue3783.go b/test/fixedbugs/issue3783.go
index d7a4a2e..7db06d1 100644
--- a/test/fixedbugs/issue3783.go
+++ b/test/fixedbugs/issue3783.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue3925.go b/test/fixedbugs/issue3925.go
index a62d439..628c222 100644
--- a/test/fixedbugs/issue3925.go
+++ b/test/fixedbugs/issue3925.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4085a.go b/test/fixedbugs/issue4085a.go
index 089637d..200290a 100644
--- a/test/fixedbugs/issue4085a.go
+++ b/test/fixedbugs/issue4085a.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4085b.go b/test/fixedbugs/issue4085b.go
index 63aca23..583c417 100644
--- a/test/fixedbugs/issue4085b.go
+++ b/test/fixedbugs/issue4085b.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4097.go b/test/fixedbugs/issue4097.go
index c2b7d9b..30b65bc 100644
--- a/test/fixedbugs/issue4097.go
+++ b/test/fixedbugs/issue4097.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4099.go b/test/fixedbugs/issue4099.go
index 89392bf..8ea809c 100644
--- a/test/fixedbugs/issue4099.go
+++ b/test/fixedbugs/issue4099.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4162.go b/test/fixedbugs/issue4162.go
index c2a8338..f236bd0 100644
--- a/test/fixedbugs/issue4162.go
+++ b/test/fixedbugs/issue4162.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4167.go b/test/fixedbugs/issue4167.go
index 4e35331..86a636f 100644
--- a/test/fixedbugs/issue4167.go
+++ b/test/fixedbugs/issue4167.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4232.go b/test/fixedbugs/issue4232.go
index 755b1b1..935f382 100644
--- a/test/fixedbugs/issue4232.go
+++ b/test/fixedbugs/issue4232.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4251.go b/test/fixedbugs/issue4251.go
index 3668d4c..d11ce51 100644
--- a/test/fixedbugs/issue4251.go
+++ b/test/fixedbugs/issue4251.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4252.dir/a.go b/test/fixedbugs/issue4252.dir/a.go
index 089b6f2..a587e28 100644
--- a/test/fixedbugs/issue4252.dir/a.go
+++ b/test/fixedbugs/issue4252.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4252.dir/main.go b/test/fixedbugs/issue4252.dir/main.go
index 28e4342..02d9836 100644
--- a/test/fixedbugs/issue4252.dir/main.go
+++ b/test/fixedbugs/issue4252.dir/main.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4252.go b/test/fixedbugs/issue4252.go
index 1b0e5b2..01bcbc4 100644
--- a/test/fixedbugs/issue4252.go
+++ b/test/fixedbugs/issue4252.go
@@ -1,6 +1,6 @@
 // rundir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4283.go b/test/fixedbugs/issue4283.go
index 128c872..fa5629b 100644
--- a/test/fixedbugs/issue4283.go
+++ b/test/fixedbugs/issue4283.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4313.go b/test/fixedbugs/issue4313.go
index b2f69db..2494b83 100644
--- a/test/fixedbugs/issue4313.go
+++ b/test/fixedbugs/issue4313.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4316.go b/test/fixedbugs/issue4316.go
index bb18a08..de9a61b 100644
--- a/test/fixedbugs/issue4316.go
+++ b/test/fixedbugs/issue4316.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4323.go b/test/fixedbugs/issue4323.go
index 6bb78f4..f082a1f 100644
--- a/test/fixedbugs/issue4323.go
+++ b/test/fixedbugs/issue4323.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4326.go b/test/fixedbugs/issue4326.go
index 5ce2eea..6a510f9 100644
--- a/test/fixedbugs/issue4326.go
+++ b/test/fixedbugs/issue4326.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4348.go b/test/fixedbugs/issue4348.go
index 3dac8f7..c59b6b8 100644
--- a/test/fixedbugs/issue4348.go
+++ b/test/fixedbugs/issue4348.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4353.go b/test/fixedbugs/issue4353.go
index defe7c3..6a17c46 100644
--- a/test/fixedbugs/issue4353.go
+++ b/test/fixedbugs/issue4353.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4359.go b/test/fixedbugs/issue4359.go
index b5adb40..c79e9e2 100644
--- a/test/fixedbugs/issue4359.go
+++ b/test/fixedbugs/issue4359.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4365.go b/test/fixedbugs/issue4365.go
index 04d31f7..09ff1bf 100644
--- a/test/fixedbugs/issue4365.go
+++ b/test/fixedbugs/issue4365.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue4370.dir/p1.go b/test/fixedbugs/issue4370.dir/p1.go
index d732c8b..d010e93 100644
--- a/test/fixedbugs/issue4370.dir/p1.go
+++ b/test/fixedbugs/issue4370.dir/p1.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4370.dir/p2.go b/test/fixedbugs/issue4370.dir/p2.go
index 33370d0..0d3e236 100644
--- a/test/fixedbugs/issue4370.dir/p2.go
+++ b/test/fixedbugs/issue4370.dir/p2.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4370.dir/p3.go b/test/fixedbugs/issue4370.dir/p3.go
index 13c996b..c275c6e 100644
--- a/test/fixedbugs/issue4370.dir/p3.go
+++ b/test/fixedbugs/issue4370.dir/p3.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4370.go b/test/fixedbugs/issue4370.go
index 76b47e1..b1d0364 100644
--- a/test/fixedbugs/issue4370.go
+++ b/test/fixedbugs/issue4370.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4388.go b/test/fixedbugs/issue4388.go
index b18c98b..5bb05eb 100644
--- a/test/fixedbugs/issue4388.go
+++ b/test/fixedbugs/issue4388.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4396a.go b/test/fixedbugs/issue4396a.go
index 11ae1f7..38dd4b8 100644
--- a/test/fixedbugs/issue4396a.go
+++ b/test/fixedbugs/issue4396a.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4396b.go b/test/fixedbugs/issue4396b.go
index d0bf28f..1284870 100644
--- a/test/fixedbugs/issue4396b.go
+++ b/test/fixedbugs/issue4396b.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4399.go b/test/fixedbugs/issue4399.go
index 6674db9..3dc2126 100644
--- a/test/fixedbugs/issue4399.go
+++ b/test/fixedbugs/issue4399.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4405.go b/test/fixedbugs/issue4405.go
index b8458d7..5ba3e10 100644
--- a/test/fixedbugs/issue4405.go
+++ b/test/fixedbugs/issue4405.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4429.go b/test/fixedbugs/issue4429.go
index 6822760..9eb2e0f 100644
--- a/test/fixedbugs/issue4429.go
+++ b/test/fixedbugs/issue4429.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4448.go b/test/fixedbugs/issue4448.go
index fa1d9fe..f5e4715 100644
--- a/test/fixedbugs/issue4448.go
+++ b/test/fixedbugs/issue4448.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4452.go b/test/fixedbugs/issue4452.go
index 54dd214..f91bd2c 100644
--- a/test/fixedbugs/issue4452.go
+++ b/test/fixedbugs/issue4452.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4458.go b/test/fixedbugs/issue4458.go
index 820f18c..98ffea7 100644
--- a/test/fixedbugs/issue4458.go
+++ b/test/fixedbugs/issue4458.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4463.go b/test/fixedbugs/issue4463.go
index 70977ce..6ad1952 100644
--- a/test/fixedbugs/issue4463.go
+++ b/test/fixedbugs/issue4463.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4468.go b/test/fixedbugs/issue4468.go
index f882105..d26725e 100644
--- a/test/fixedbugs/issue4468.go
+++ b/test/fixedbugs/issue4468.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4470.go b/test/fixedbugs/issue4470.go
index 5ed09ca..d922478 100644
--- a/test/fixedbugs/issue4470.go
+++ b/test/fixedbugs/issue4470.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4495.go b/test/fixedbugs/issue4495.go
index 7ec1134..308acc2 100644
--- a/test/fixedbugs/issue4495.go
+++ b/test/fixedbugs/issue4495.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4517a.go b/test/fixedbugs/issue4517a.go
index a1b6b57..83d42e7 100644
--- a/test/fixedbugs/issue4517a.go
+++ b/test/fixedbugs/issue4517a.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4517b.go b/test/fixedbugs/issue4517b.go
index f04103f..34fa98f 100644
--- a/test/fixedbugs/issue4517b.go
+++ b/test/fixedbugs/issue4517b.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4517c.go b/test/fixedbugs/issue4517c.go
index 47b21cf..9023e0a 100644
--- a/test/fixedbugs/issue4517c.go
+++ b/test/fixedbugs/issue4517c.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4517d.go b/test/fixedbugs/issue4517d.go
index 3d727d4..197c225 100644
--- a/test/fixedbugs/issue4517d.go
+++ b/test/fixedbugs/issue4517d.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4518.go b/test/fixedbugs/issue4518.go
index 5c3a178..c482b0f 100644
--- a/test/fixedbugs/issue4518.go
+++ b/test/fixedbugs/issue4518.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4529.go b/test/fixedbugs/issue4529.go
index 4f37e7c..66b96c7 100644
--- a/test/fixedbugs/issue4529.go
+++ b/test/fixedbugs/issue4529.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4545.go b/test/fixedbugs/issue4545.go
index c37ccef..534ba71 100644
--- a/test/fixedbugs/issue4545.go
+++ b/test/fixedbugs/issue4545.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4562.go b/test/fixedbugs/issue4562.go
index 29d98b0..8c958f5 100644
--- a/test/fixedbugs/issue4562.go
+++ b/test/fixedbugs/issue4562.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4585.go b/test/fixedbugs/issue4585.go
index ad1242d..9191ec5 100644
--- a/test/fixedbugs/issue4585.go
+++ b/test/fixedbugs/issue4585.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4590.dir/pkg1.go b/test/fixedbugs/issue4590.dir/pkg1.go
index c447371..96cac0a 100644
--- a/test/fixedbugs/issue4590.dir/pkg1.go
+++ b/test/fixedbugs/issue4590.dir/pkg1.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4590.dir/pkg2.go b/test/fixedbugs/issue4590.dir/pkg2.go
index 61c01d7..98bc2a5 100644
--- a/test/fixedbugs/issue4590.dir/pkg2.go
+++ b/test/fixedbugs/issue4590.dir/pkg2.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4590.dir/prog.go b/test/fixedbugs/issue4590.dir/prog.go
index 3220e85..32055b2 100644
--- a/test/fixedbugs/issue4590.dir/prog.go
+++ b/test/fixedbugs/issue4590.dir/prog.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4614.go b/test/fixedbugs/issue4614.go
index 1aa318c..ad378d8 100644
--- a/test/fixedbugs/issue4614.go
+++ b/test/fixedbugs/issue4614.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4618.go b/test/fixedbugs/issue4618.go
index fe875b3..0ba9523 100644
--- a/test/fixedbugs/issue4618.go
+++ b/test/fixedbugs/issue4618.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4620.go b/test/fixedbugs/issue4620.go
index 7b4ebf9..5aa2908 100644
--- a/test/fixedbugs/issue4620.go
+++ b/test/fixedbugs/issue4620.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4654.go b/test/fixedbugs/issue4654.go
index d3f582b..76aff76 100644
--- a/test/fixedbugs/issue4654.go
+++ b/test/fixedbugs/issue4654.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4663.go b/test/fixedbugs/issue4663.go
index edaee93..971290d 100644
--- a/test/fixedbugs/issue4663.go
+++ b/test/fixedbugs/issue4663.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4667.go b/test/fixedbugs/issue4667.go
index 18d773c..31b3284 100644
--- a/test/fixedbugs/issue4667.go
+++ b/test/fixedbugs/issue4667.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4734.go b/test/fixedbugs/issue4734.go
index 69f66f2..45e609d 100644
--- a/test/fixedbugs/issue4734.go
+++ b/test/fixedbugs/issue4734.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4748.go b/test/fixedbugs/issue4748.go
index 73c7539..f7c77cf 100644
--- a/test/fixedbugs/issue4748.go
+++ b/test/fixedbugs/issue4748.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4752.go b/test/fixedbugs/issue4752.go
index d6781e3..af7bb92 100644
--- a/test/fixedbugs/issue4752.go
+++ b/test/fixedbugs/issue4752.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4776.go b/test/fixedbugs/issue4776.go
index 13781af..a1009ad 100644
--- a/test/fixedbugs/issue4776.go
+++ b/test/fixedbugs/issue4776.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4785.go b/test/fixedbugs/issue4785.go
index c3dd629..d0bcd56 100644
--- a/test/fixedbugs/issue4785.go
+++ b/test/fixedbugs/issue4785.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue4909a.go b/test/fixedbugs/issue4909a.go
index aefe2d6..09e1b85 100644
--- a/test/fixedbugs/issue4909a.go
+++ b/test/fixedbugs/issue4909a.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5002.go b/test/fixedbugs/issue5002.go
index 1e74fa1..5ac119a 100644
--- a/test/fixedbugs/issue5002.go
+++ b/test/fixedbugs/issue5002.go
@@ -1,6 +1,6 @@
 // build
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5056.go b/test/fixedbugs/issue5056.go
index a2cde2a..6fb444a 100644
--- a/test/fixedbugs/issue5056.go
+++ b/test/fixedbugs/issue5056.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5089.go b/test/fixedbugs/issue5089.go
index 81b9f05..9f7fa5a 100644
--- a/test/fixedbugs/issue5089.go
+++ b/test/fixedbugs/issue5089.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5231.go b/test/fixedbugs/issue5231.go
index 4039913..6bc8826 100644
--- a/test/fixedbugs/issue5231.go
+++ b/test/fixedbugs/issue5231.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5358.go b/test/fixedbugs/issue5358.go
index c2b1da9..25f1e52 100644
--- a/test/fixedbugs/issue5358.go
+++ b/test/fixedbugs/issue5358.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5373.go b/test/fixedbugs/issue5373.go
index 17ce189..8aee9a2 100644
--- a/test/fixedbugs/issue5373.go
+++ b/test/fixedbugs/issue5373.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue5581.go b/test/fixedbugs/issue5581.go
index 36a4ad6..8834b44 100644
--- a/test/fixedbugs/issue5581.go
+++ b/test/fixedbugs/issue5581.go
@@ -3,7 +3,7 @@
 // Used to emit a spurious "invalid recursive type" error.
 // See golang.org/issue/5581.
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5698.go b/test/fixedbugs/issue5698.go
index 035bbd3..081541c 100644
--- a/test/fixedbugs/issue5698.go
+++ b/test/fixedbugs/issue5698.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5704.go b/test/fixedbugs/issue5704.go
index 1dfa072..11b9a93 100644
--- a/test/fixedbugs/issue5704.go
+++ b/test/fixedbugs/issue5704.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5793.go b/test/fixedbugs/issue5793.go
index f5a9965..8104155 100644
--- a/test/fixedbugs/issue5793.go
+++ b/test/fixedbugs/issue5793.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5809.go b/test/fixedbugs/issue5809.go
index ca060b5..fc8eeef 100644
--- a/test/fixedbugs/issue5809.go
+++ b/test/fixedbugs/issue5809.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5820.go b/test/fixedbugs/issue5820.go
index 94de06d..1046d66 100644
--- a/test/fixedbugs/issue5820.go
+++ b/test/fixedbugs/issue5820.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5841.go b/test/fixedbugs/issue5841.go
index cfc4a50..2be1aee 100644
--- a/test/fixedbugs/issue5841.go
+++ b/test/fixedbugs/issue5841.go
@@ -1,6 +1,6 @@
 // build
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5856.go b/test/fixedbugs/issue5856.go
index 78ca3b9..5e16c78 100644
--- a/test/fixedbugs/issue5856.go
+++ b/test/fixedbugs/issue5856.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue5963.go b/test/fixedbugs/issue5963.go
index 190e8f4..f828303 100644
--- a/test/fixedbugs/issue5963.go
+++ b/test/fixedbugs/issue5963.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6004.go b/test/fixedbugs/issue6004.go
index 45aaffd..2b3dcd9 100644
--- a/test/fixedbugs/issue6004.go
+++ b/test/fixedbugs/issue6004.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6036.go b/test/fixedbugs/issue6036.go
index 5f787c5..795b223 100644
--- a/test/fixedbugs/issue6036.go
+++ b/test/fixedbugs/issue6036.go
@@ -1,7 +1,7 @@
 // +build amd64
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6055.go b/test/fixedbugs/issue6055.go
index 698f62a..4594348 100644
--- a/test/fixedbugs/issue6055.go
+++ b/test/fixedbugs/issue6055.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6131.go b/test/fixedbugs/issue6131.go
index 817e4a8..61548a2 100644
--- a/test/fixedbugs/issue6131.go
+++ b/test/fixedbugs/issue6131.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6140.go b/test/fixedbugs/issue6140.go
index d494933..dde7921 100644
--- a/test/fixedbugs/issue6140.go
+++ b/test/fixedbugs/issue6140.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6247.go b/test/fixedbugs/issue6247.go
index eea8f9c..2786786 100644
--- a/test/fixedbugs/issue6247.go
+++ b/test/fixedbugs/issue6247.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6269.go b/test/fixedbugs/issue6269.go
index af5feb7..2930f52 100644
--- a/test/fixedbugs/issue6269.go
+++ b/test/fixedbugs/issue6269.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6295.dir/p0.go b/test/fixedbugs/issue6295.dir/p0.go
index cf86fbc..d4d4da7 100644
--- a/test/fixedbugs/issue6295.dir/p0.go
+++ b/test/fixedbugs/issue6295.dir/p0.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6295.dir/p1.go b/test/fixedbugs/issue6295.dir/p1.go
index 974d02f..26efae7 100644
--- a/test/fixedbugs/issue6295.dir/p1.go
+++ b/test/fixedbugs/issue6295.dir/p1.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6295.dir/p2.go b/test/fixedbugs/issue6295.dir/p2.go
index 4703ec0..f5b6ffd 100644
--- a/test/fixedbugs/issue6295.dir/p2.go
+++ b/test/fixedbugs/issue6295.dir/p2.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6298.go b/test/fixedbugs/issue6298.go
index 6303dbe..ab3bfcd 100644
--- a/test/fixedbugs/issue6298.go
+++ b/test/fixedbugs/issue6298.go
@@ -3,7 +3,7 @@
 // golang.org/issue/6298.
 // Used to cause "internal error: typename ideal bool"
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6513.dir/a.go b/test/fixedbugs/issue6513.dir/a.go
index da90ca3..e5536fe 100644
--- a/test/fixedbugs/issue6513.dir/a.go
+++ b/test/fixedbugs/issue6513.dir/a.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6513.dir/b.go b/test/fixedbugs/issue6513.dir/b.go
index 3b35b2d..ce3d52e 100644
--- a/test/fixedbugs/issue6513.dir/b.go
+++ b/test/fixedbugs/issue6513.dir/b.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6513.dir/main.go b/test/fixedbugs/issue6513.dir/main.go
index f09b727..8d8c02b 100644
--- a/test/fixedbugs/issue6513.dir/main.go
+++ b/test/fixedbugs/issue6513.dir/main.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6572.go b/test/fixedbugs/issue6572.go
index e75da54..e4465e9 100644
--- a/test/fixedbugs/issue6572.go
+++ b/test/fixedbugs/issue6572.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6671.go b/test/fixedbugs/issue6671.go
index b88faa4..ce43f31 100644
--- a/test/fixedbugs/issue6671.go
+++ b/test/fixedbugs/issue6671.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703a.go b/test/fixedbugs/issue6703a.go
index d4c008f..38c5956 100644
--- a/test/fixedbugs/issue6703a.go
+++ b/test/fixedbugs/issue6703a.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703b.go b/test/fixedbugs/issue6703b.go
index 326b583..35438c3 100644
--- a/test/fixedbugs/issue6703b.go
+++ b/test/fixedbugs/issue6703b.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703c.go b/test/fixedbugs/issue6703c.go
index 4735764..ade40e3 100644
--- a/test/fixedbugs/issue6703c.go
+++ b/test/fixedbugs/issue6703c.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703d.go b/test/fixedbugs/issue6703d.go
index 0a1952f..dd48163 100644
--- a/test/fixedbugs/issue6703d.go
+++ b/test/fixedbugs/issue6703d.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703e.go b/test/fixedbugs/issue6703e.go
index 416066e..d362d6e 100644
--- a/test/fixedbugs/issue6703e.go
+++ b/test/fixedbugs/issue6703e.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703f.go b/test/fixedbugs/issue6703f.go
index 3023829..0b49026 100644
--- a/test/fixedbugs/issue6703f.go
+++ b/test/fixedbugs/issue6703f.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703g.go b/test/fixedbugs/issue6703g.go
index 002b5a6..05ec740 100644
--- a/test/fixedbugs/issue6703g.go
+++ b/test/fixedbugs/issue6703g.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703h.go b/test/fixedbugs/issue6703h.go
index 234ccb3..f6b69e1 100644
--- a/test/fixedbugs/issue6703h.go
+++ b/test/fixedbugs/issue6703h.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703i.go b/test/fixedbugs/issue6703i.go
index 78b4d49..fb580a2 100644
--- a/test/fixedbugs/issue6703i.go
+++ b/test/fixedbugs/issue6703i.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703j.go b/test/fixedbugs/issue6703j.go
index a7f63f7..b4c079f 100644
--- a/test/fixedbugs/issue6703j.go
+++ b/test/fixedbugs/issue6703j.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703k.go b/test/fixedbugs/issue6703k.go
index 19c6107..6f606e2 100644
--- a/test/fixedbugs/issue6703k.go
+++ b/test/fixedbugs/issue6703k.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703l.go b/test/fixedbugs/issue6703l.go
index 3f4ca31..684c225 100644
--- a/test/fixedbugs/issue6703l.go
+++ b/test/fixedbugs/issue6703l.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703m.go b/test/fixedbugs/issue6703m.go
index d80959c..7d1b604 100644
--- a/test/fixedbugs/issue6703m.go
+++ b/test/fixedbugs/issue6703m.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703n.go b/test/fixedbugs/issue6703n.go
index 2c623f2..22646af 100644
--- a/test/fixedbugs/issue6703n.go
+++ b/test/fixedbugs/issue6703n.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703o.go b/test/fixedbugs/issue6703o.go
index efc8947..a11fdfd 100644
--- a/test/fixedbugs/issue6703o.go
+++ b/test/fixedbugs/issue6703o.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703p.go b/test/fixedbugs/issue6703p.go
index dad88f6..3ac7a63 100644
--- a/test/fixedbugs/issue6703p.go
+++ b/test/fixedbugs/issue6703p.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703q.go b/test/fixedbugs/issue6703q.go
index 7bd748a..b087c15 100644
--- a/test/fixedbugs/issue6703q.go
+++ b/test/fixedbugs/issue6703q.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703r.go b/test/fixedbugs/issue6703r.go
index 6698462..de514f1 100644
--- a/test/fixedbugs/issue6703r.go
+++ b/test/fixedbugs/issue6703r.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703s.go b/test/fixedbugs/issue6703s.go
index 6aa2848..cd3c5b3 100644
--- a/test/fixedbugs/issue6703s.go
+++ b/test/fixedbugs/issue6703s.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703t.go b/test/fixedbugs/issue6703t.go
index bad65ad..62de37c 100644
--- a/test/fixedbugs/issue6703t.go
+++ b/test/fixedbugs/issue6703t.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703u.go b/test/fixedbugs/issue6703u.go
index b6813b7..961a000 100644
--- a/test/fixedbugs/issue6703u.go
+++ b/test/fixedbugs/issue6703u.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703v.go b/test/fixedbugs/issue6703v.go
index a1b3711..2409911 100644
--- a/test/fixedbugs/issue6703v.go
+++ b/test/fixedbugs/issue6703v.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703w.go b/test/fixedbugs/issue6703w.go
index d4733de..b7b3d91 100644
--- a/test/fixedbugs/issue6703w.go
+++ b/test/fixedbugs/issue6703w.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703x.go b/test/fixedbugs/issue6703x.go
index 8008b8c..48daf03 100644
--- a/test/fixedbugs/issue6703x.go
+++ b/test/fixedbugs/issue6703x.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703y.go b/test/fixedbugs/issue6703y.go
index ac4526d..278dfcd 100644
--- a/test/fixedbugs/issue6703y.go
+++ b/test/fixedbugs/issue6703y.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6703z.go b/test/fixedbugs/issue6703z.go
index d4c17e1..f81a3a8 100644
--- a/test/fixedbugs/issue6703z.go
+++ b/test/fixedbugs/issue6703z.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6847.go b/test/fixedbugs/issue6847.go
index e6427e1..da300bc 100644
--- a/test/fixedbugs/issue6847.go
+++ b/test/fixedbugs/issue6847.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6899.go b/test/fixedbugs/issue6899.go
index a693bf2..f98f551 100644
--- a/test/fixedbugs/issue6899.go
+++ b/test/fixedbugs/issue6899.go
@@ -1,6 +1,6 @@
 // cmpout
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue6964.go b/test/fixedbugs/issue6964.go
index 8f4b60d..7ad8336 100644
--- a/test/fixedbugs/issue6964.go
+++ b/test/fixedbugs/issue6964.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7044.go b/test/fixedbugs/issue7044.go
index cac6a76..00c78c8 100644
--- a/test/fixedbugs/issue7044.go
+++ b/test/fixedbugs/issue7044.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7050.go b/test/fixedbugs/issue7050.go
index e58b684..be7a118 100644
--- a/test/fixedbugs/issue7050.go
+++ b/test/fixedbugs/issue7050.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7150.go b/test/fixedbugs/issue7150.go
index 05e8d75..8a8a7d0 100644
--- a/test/fixedbugs/issue7150.go
+++ b/test/fixedbugs/issue7150.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7223.go b/test/fixedbugs/issue7223.go
index c5955d5..0ec3476 100644
--- a/test/fixedbugs/issue7223.go
+++ b/test/fixedbugs/issue7223.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7272.go b/test/fixedbugs/issue7272.go
index 97a08da..b10a8bf 100644
--- a/test/fixedbugs/issue7272.go
+++ b/test/fixedbugs/issue7272.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7310.go b/test/fixedbugs/issue7310.go
index 4a535a1..1169fcf 100644
--- a/test/fixedbugs/issue7310.go
+++ b/test/fixedbugs/issue7310.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7316.go b/test/fixedbugs/issue7316.go
index 4b32261..0734641 100644
--- a/test/fixedbugs/issue7316.go
+++ b/test/fixedbugs/issue7316.go
@@ -1,6 +1,6 @@
 // runoutput
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7346.go b/test/fixedbugs/issue7346.go
index dd5ea22..21fab2d 100644
--- a/test/fixedbugs/issue7346.go
+++ b/test/fixedbugs/issue7346.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7366.go b/test/fixedbugs/issue7366.go
index 754da6f..a6b786f 100644
--- a/test/fixedbugs/issue7366.go
+++ b/test/fixedbugs/issue7366.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7590.go b/test/fixedbugs/issue7590.go
index e283832..607a3ae 100644
--- a/test/fixedbugs/issue7590.go
+++ b/test/fixedbugs/issue7590.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7690.go b/test/fixedbugs/issue7690.go
index 4ad9e86..fea2aa1 100644
--- a/test/fixedbugs/issue7690.go
+++ b/test/fixedbugs/issue7690.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7794.go b/test/fixedbugs/issue7794.go
index 1e303bd..f31de94 100644
--- a/test/fixedbugs/issue7794.go
+++ b/test/fixedbugs/issue7794.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7863.go b/test/fixedbugs/issue7863.go
index 97f2255..da2ed05 100644
--- a/test/fixedbugs/issue7863.go
+++ b/test/fixedbugs/issue7863.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7867.go b/test/fixedbugs/issue7867.go
index 9f28a71..166506e 100644
--- a/test/fixedbugs/issue7867.go
+++ b/test/fixedbugs/issue7867.go
@@ -1,6 +1,6 @@
 // runoutput
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7884.go b/test/fixedbugs/issue7884.go
index 497e261..ab7a858 100644
--- a/test/fixedbugs/issue7884.go
+++ b/test/fixedbugs/issue7884.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7944.go b/test/fixedbugs/issue7944.go
index 9e5bed1..960065b 100644
--- a/test/fixedbugs/issue7944.go
+++ b/test/fixedbugs/issue7944.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7995.go b/test/fixedbugs/issue7995.go
index 05f1168..af77a6d 100644
--- a/test/fixedbugs/issue7995.go
+++ b/test/fixedbugs/issue7995.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7996.go b/test/fixedbugs/issue7996.go
index 98289eb..1ee6fc7 100644
--- a/test/fixedbugs/issue7996.go
+++ b/test/fixedbugs/issue7996.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7997.go b/test/fixedbugs/issue7997.go
index 10c5262..a342189 100644
--- a/test/fixedbugs/issue7997.go
+++ b/test/fixedbugs/issue7997.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue7998.go b/test/fixedbugs/issue7998.go
index 245035e..8da39e8 100644
--- a/test/fixedbugs/issue7998.go
+++ b/test/fixedbugs/issue7998.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8004.go b/test/fixedbugs/issue8004.go
index 37e2fe0..548ee1c 100644
--- a/test/fixedbugs/issue8004.go
+++ b/test/fixedbugs/issue8004.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8011.go b/test/fixedbugs/issue8011.go
index b966174..57af2a9 100644
--- a/test/fixedbugs/issue8011.go
+++ b/test/fixedbugs/issue8011.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8017.go b/test/fixedbugs/issue8017.go
index 22056e0..9afcdf0 100644
--- a/test/fixedbugs/issue8017.go
+++ b/test/fixedbugs/issue8017.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8028.go b/test/fixedbugs/issue8028.go
index 7ceb902..9f2649a 100644
--- a/test/fixedbugs/issue8028.go
+++ b/test/fixedbugs/issue8028.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8036.go b/test/fixedbugs/issue8036.go
index f052cf9..82ba7f7 100644
--- a/test/fixedbugs/issue8036.go
+++ b/test/fixedbugs/issue8036.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8039.go b/test/fixedbugs/issue8039.go
index b13e474..ee00c60 100644
--- a/test/fixedbugs/issue8039.go
+++ b/test/fixedbugs/issue8039.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8047.go b/test/fixedbugs/issue8047.go
index fe7ada5..5ac4a0e 100644
--- a/test/fixedbugs/issue8047.go
+++ b/test/fixedbugs/issue8047.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8047b.go b/test/fixedbugs/issue8047b.go
index de6acaa..df902a5 100644
--- a/test/fixedbugs/issue8047b.go
+++ b/test/fixedbugs/issue8047b.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8048.go b/test/fixedbugs/issue8048.go
index a7984c4..577f606 100644
--- a/test/fixedbugs/issue8048.go
+++ b/test/fixedbugs/issue8048.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8073.go b/test/fixedbugs/issue8073.go
index 6601221..d47481c 100644
--- a/test/fixedbugs/issue8073.go
+++ b/test/fixedbugs/issue8073.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8074.go b/test/fixedbugs/issue8074.go
index aedab24..604a4f9 100644
--- a/test/fixedbugs/issue8074.go
+++ b/test/fixedbugs/issue8074.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8076.go b/test/fixedbugs/issue8076.go
index ad89067..543ccc1 100644
--- a/test/fixedbugs/issue8076.go
+++ b/test/fixedbugs/issue8076.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8132.go b/test/fixedbugs/issue8132.go
index 52f5d39..b28a84c 100644
--- a/test/fixedbugs/issue8132.go
+++ b/test/fixedbugs/issue8132.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8139.go b/test/fixedbugs/issue8139.go
index 821c9ff..6e5607d 100644
--- a/test/fixedbugs/issue8139.go
+++ b/test/fixedbugs/issue8139.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8154.go b/test/fixedbugs/issue8154.go
index 92c3cac..3ffad34 100644
--- a/test/fixedbugs/issue8154.go
+++ b/test/fixedbugs/issue8154.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue8155.go b/test/fixedbugs/issue8155.go
index c611f6c..56a6738 100644
--- a/test/fixedbugs/issue8155.go
+++ b/test/fixedbugs/issue8155.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8158.go b/test/fixedbugs/issue8158.go
index b110de1..150b338 100644
--- a/test/fixedbugs/issue8158.go
+++ b/test/fixedbugs/issue8158.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8183.go b/test/fixedbugs/issue8183.go
index 7104f1e..f23e660 100644
--- a/test/fixedbugs/issue8183.go
+++ b/test/fixedbugs/issue8183.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue8311.go b/test/fixedbugs/issue8311.go
index dd92856..375b480 100644
--- a/test/fixedbugs/issue8311.go
+++ b/test/fixedbugs/issue8311.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8325.go b/test/fixedbugs/issue8325.go
index e22fd31..6b0fc25 100644
--- a/test/fixedbugs/issue8325.go
+++ b/test/fixedbugs/issue8325.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8336.go b/test/fixedbugs/issue8336.go
index 26bdeab..419fdf1 100644
--- a/test/fixedbugs/issue8336.go
+++ b/test/fixedbugs/issue8336.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8347.go b/test/fixedbugs/issue8347.go
index 0828ccf..6394a95 100644
--- a/test/fixedbugs/issue8347.go
+++ b/test/fixedbugs/issue8347.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8475.go b/test/fixedbugs/issue8475.go
index e697945..5b22067 100644
--- a/test/fixedbugs/issue8475.go
+++ b/test/fixedbugs/issue8475.go
@@ -1,6 +1,6 @@
 // build
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8507.go b/test/fixedbugs/issue8507.go
index 00a14aa..ad6ba8a 100644
--- a/test/fixedbugs/issue8507.go
+++ b/test/fixedbugs/issue8507.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8612.go b/test/fixedbugs/issue8612.go
index 93370cf..2a622f4 100644
--- a/test/fixedbugs/issue8612.go
+++ b/test/fixedbugs/issue8612.go
@@ -1,6 +1,6 @@
 //compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8613.go b/test/fixedbugs/issue8613.go
new file mode 100644
index 0000000..c0ad131
--- /dev/null
+++ b/test/fixedbugs/issue8613.go
@@ -0,0 +1,39 @@
+// +build amd64
+// run
+
+// Copyright 2016 The Go Authors. 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 out int
+var zero int
+
+func main() {
+	wantPanic("test1", func() {
+		out = 1 / zero
+	})
+	wantPanic("test2", func() {
+		_ = 1 / zero
+	})
+	wantPanic("test3", func() {
+		v := 0
+		_ = 1 / v
+	})
+	wantPanic("test4", func() { divby(0) })
+}
+
+func wantPanic(test string, fn func()) {
+	defer func() {
+		if e := recover(); e == nil {
+			panic(test + ": expected panic")
+		}
+	}()
+	fn()
+}
+
+//go:noinline
+func divby(v int) {
+	_ = 1 / v
+}
diff --git a/test/fixedbugs/issue8620.go b/test/fixedbugs/issue8620.go
index 30d7a82..4754604 100644
--- a/test/fixedbugs/issue8620.go
+++ b/test/fixedbugs/issue8620.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8745.go b/test/fixedbugs/issue8745.go
index f3a70af..fee2ca7 100644
--- a/test/fixedbugs/issue8745.go
+++ b/test/fixedbugs/issue8745.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue8761.go b/test/fixedbugs/issue8761.go
index badf639..7f458f7 100644
--- a/test/fixedbugs/issue8761.go
+++ b/test/fixedbugs/issue8761.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8836.go b/test/fixedbugs/issue8836.go
index 92c18f6..039b9c7 100644
--- a/test/fixedbugs/issue8836.go
+++ b/test/fixedbugs/issue8836.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2015 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.
 
diff --git a/test/fixedbugs/issue887.go b/test/fixedbugs/issue887.go
index 5bc193b..b68ba69 100644
--- a/test/fixedbugs/issue887.go
+++ b/test/fixedbugs/issue887.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8947.go b/test/fixedbugs/issue8947.go
index f40c02e..703207d 100644
--- a/test/fixedbugs/issue8947.go
+++ b/test/fixedbugs/issue8947.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue8961.go b/test/fixedbugs/issue8961.go
index fbfb7e6..22b0f04 100644
--- a/test/fixedbugs/issue8961.go
+++ b/test/fixedbugs/issue8961.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9006.go b/test/fixedbugs/issue9006.go
index c559f58..a61574b 100644
--- a/test/fixedbugs/issue9006.go
+++ b/test/fixedbugs/issue9006.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9017.go b/test/fixedbugs/issue9017.go
index e19bac2..5659785 100644
--- a/test/fixedbugs/issue9017.go
+++ b/test/fixedbugs/issue9017.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9036.go b/test/fixedbugs/issue9036.go
index 283159e..75ffb2d 100644
--- a/test/fixedbugs/issue9036.go
+++ b/test/fixedbugs/issue9036.go
@@ -1,10 +1,10 @@
 // errorcheck
 
-// Copyright 2015 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.
 
-// Expects to see error messages on "p" exponents.
+// Expects to see error messages on 'p' exponents.
 
 package main
 
@@ -14,11 +14,19 @@ 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"
 )
 
+// 'p' exponents are invalid - the 'p' is not considered
+// part of a floating-point number, but introduces a new
+// (unexpected) name.
+//
+// Error recovery is not ideal and we use a new declaration
+// each time for the parser to recover.
+
+const x4 = 0x1p10 // ERROR "unexpected p10"
+const x5 = 1p10   // ERROR "unexpected p10"
+const x6 = 0p0    // ERROR "unexpected p0"
+
 func main() {
 	fmt.Printf("%g %T\n", x1, x1)
 	fmt.Printf("%g %T\n", x2, x2)
diff --git a/test/fixedbugs/issue9076.go b/test/fixedbugs/issue9076.go
index ad1cd5d..8daf12f 100644
--- a/test/fixedbugs/issue9076.go
+++ b/test/fixedbugs/issue9076.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9083.go b/test/fixedbugs/issue9083.go
index c92c0a6..8fbd78b 100644
--- a/test/fixedbugs/issue9083.go
+++ b/test/fixedbugs/issue9083.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9110.go b/test/fixedbugs/issue9110.go
index b9e861f..086be77 100644
--- a/test/fixedbugs/issue9110.go
+++ b/test/fixedbugs/issue9110.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9321.go b/test/fixedbugs/issue9321.go
index e850d8f..2b2807a 100644
--- a/test/fixedbugs/issue9321.go
+++ b/test/fixedbugs/issue9321.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9355.go b/test/fixedbugs/issue9355.go
index 40c9ba9..10f8c73 100644
--- a/test/fixedbugs/issue9355.go
+++ b/test/fixedbugs/issue9355.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9432.go b/test/fixedbugs/issue9432.go
index 0d0bc96..2049460 100644
--- a/test/fixedbugs/issue9432.go
+++ b/test/fixedbugs/issue9432.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9731.go b/test/fixedbugs/issue9731.go
index 286cebd..9237d65 100644
--- a/test/fixedbugs/issue9731.go
+++ b/test/fixedbugs/issue9731.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/fixedbugs/issue9862.go b/test/fixedbugs/issue9862.go
index 692a60d..3572512 100644
--- a/test/fixedbugs/issue9862.go
+++ b/test/fixedbugs/issue9862.go
@@ -1,6 +1,6 @@
 // skip
 
-// Copyright 2015 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.
 
diff --git a/test/float_lit2.go b/test/float_lit2.go
index 96d23f3..bb86559 100644
--- a/test/float_lit2.go
+++ b/test/float_lit2.go
@@ -2,7 +2,7 @@
 
 // Check conversion of constant to float32/float64 near min/max boundaries.
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/float_lit3.go b/test/float_lit3.go
index 43dca9c..c4d1aa5 100644
--- a/test/float_lit3.go
+++ b/test/float_lit3.go
@@ -2,7 +2,7 @@
 
 // Check flagging of invalid conversion of constant to float32/float64 near min/max boundaries.
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/func6.go b/test/func6.go
index d1b7f46..5b2f9f2 100644
--- a/test/func6.go
+++ b/test/func6.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/func7.go b/test/func7.go
index feb7c20..3b22199 100644
--- a/test/func7.go
+++ b/test/func7.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/func8.go b/test/func8.go
index 09ca020..9de01d4 100644
--- a/test/func8.go
+++ b/test/func8.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/funcdup.go b/test/funcdup.go
index d15d685..7b05d12 100644
--- a/test/funcdup.go
+++ b/test/funcdup.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/funcdup2.go b/test/funcdup2.go
index 1db1a39..9513ef4 100644
--- a/test/funcdup2.go
+++ b/test/funcdup2.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/gc2.go b/test/gc2.go
index b33a027..31b36d8 100644
--- a/test/gc2.go
+++ b/test/gc2.go
@@ -1,7 +1,7 @@
 // +build !nacl
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/gcstring.go b/test/gcstring.go
index 627a426..7633d5d 100644
--- a/test/gcstring.go
+++ b/test/gcstring.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/goprint.go b/test/goprint.go
index cdaccf4..0648c77 100644
--- a/test/goprint.go
+++ b/test/goprint.go
@@ -1,6 +1,6 @@
 // cmpout
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -8,9 +8,14 @@
 
 package main
 
-import "time"
+import (
+	"runtime"
+	"time"
+)
 
 func main() {
 	go println(42, true, false, true, 1.5, "world", (chan int)(nil), []int(nil), (map[string]int)(nil), (func())(nil), byte(255))
-	time.Sleep(100*time.Millisecond)
+	for runtime.NumGoroutine() > 1 {
+		time.Sleep(10*time.Millisecond)
+	}
 }
diff --git a/test/goto.go b/test/goto.go
index ca477b3..f456901 100644
--- a/test/goto.go
+++ b/test/goto.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -40,7 +40,7 @@ L:
 // goto across declaration not okay
 func _() {
 	goto L // ERROR "goto L jumps over declaration of x at LINE+1|goto jumps over declaration"
-	x := 1	// GCCGO_ERROR "defined here"
+	x := 1 // GCCGO_ERROR "defined here"
 	_ = x
 L:
 }
@@ -62,7 +62,7 @@ func _() {
 		x := 1
 		_ = x
 	}
-	x := 1	// GCCGO_ERROR "defined here"
+	x := 1 // GCCGO_ERROR "defined here"
 	_ = x
 L:
 }
@@ -78,7 +78,7 @@ L:
 // error shows first offending variable
 func _() {
 	goto L // ERROR "goto L jumps over declaration of x at LINE+1|goto jumps over declaration"
-	x := 1	// GCCGO_ERROR "defined here"
+	x := 1 // GCCGO_ERROR "defined here"
 	_ = x
 	y := 1
 	_ = y
@@ -88,7 +88,7 @@ L:
 // goto not okay even if code path is dead
 func _() {
 	goto L // ERROR "goto L jumps over declaration of x at LINE+1|goto jumps over declaration"
-	x := 1	// GCCGO_ERROR "defined here"
+	x := 1 // GCCGO_ERROR "defined here"
 	_ = x
 	y := 1
 	_ = y
@@ -115,14 +115,14 @@ L:
 // goto into inner block not okay
 func _() {
 	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
-	{	// GCCGO_ERROR "block starts here"
+	{      // GCCGO_ERROR "block starts here"
 	L:
 	}
 }
 
 // goto backward into inner block still not okay
 func _() {
-	{	// GCCGO_ERROR "block starts here"
+	{ // GCCGO_ERROR "block starts here"
 	L:
 	}
 	goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
@@ -133,7 +133,7 @@ func _() {
 	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
 	{
 		{
-			{	// GCCGO_ERROR "block starts here"
+			{ // GCCGO_ERROR "block starts here"
 			L:
 			}
 		}
@@ -145,7 +145,7 @@ func _() {
 	goto L // ERROR "goto L jumps into block starting at LINE+3|goto jumps into block"
 	x := 1
 	_ = x
-	{	// GCCGO_ERROR "block starts here"
+	{ // GCCGO_ERROR "block starts here"
 	L:
 	}
 }
@@ -179,15 +179,15 @@ L:
 }
 
 func _() {
-	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
-	if true {	// GCCGO_ERROR "block starts here"
+	goto L    // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
+	if true { // GCCGO_ERROR "block starts here"
 	L:
 	}
 }
 
 func _() {
-	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
-	if true {	// GCCGO_ERROR "block starts here"
+	goto L    // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
+	if true { // GCCGO_ERROR "block starts here"
 	L:
 	} else {
 	}
@@ -196,13 +196,13 @@ func _() {
 func _() {
 	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
 	if true {
-	} else {	// GCCGO_ERROR "block starts here"
+	} else { // GCCGO_ERROR "block starts here"
 	L:
 	}
 }
 
 func _() {
-	if false {	// GCCGO_ERROR "block starts here"
+	if false { // GCCGO_ERROR "block starts here"
 	L:
 	} else {
 		goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
@@ -212,7 +212,7 @@ func _() {
 func _() {
 	if true {
 		goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
-	} else {	// GCCGO_ERROR "block starts here"
+	} else { // GCCGO_ERROR "block starts here"
 	L:
 	}
 }
@@ -220,7 +220,7 @@ func _() {
 func _() {
 	if true {
 		goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
-	} else if false {	// GCCGO_ERROR "block starts here"
+	} else if false { // GCCGO_ERROR "block starts here"
 	L:
 	}
 }
@@ -228,7 +228,7 @@ func _() {
 func _() {
 	if true {
 		goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
-	} else if false {	// GCCGO_ERROR "block starts here"
+	} else if false { // GCCGO_ERROR "block starts here"
 	L:
 	} else {
 	}
@@ -243,7 +243,7 @@ func _() {
 	if true {
 		goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
 	} else if false {
-	} else {	// GCCGO_ERROR "block starts here"
+	} else { // GCCGO_ERROR "block starts here"
 	L:
 	}
 }
@@ -287,14 +287,14 @@ func _() {
 }
 
 func _() {
-	for {	// GCCGO_ERROR "block starts here"
+	for { // GCCGO_ERROR "block starts here"
 	L:
 	}
 	goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
 }
 
 func _() {
-	for {	// GCCGO_ERROR "block starts here"
+	for { // GCCGO_ERROR "block starts here"
 		goto L
 	L1:
 	}
@@ -303,42 +303,42 @@ L:
 }
 
 func _() {
-	for i < n {	// GCCGO_ERROR "block starts here"
+	for i < n { // GCCGO_ERROR "block starts here"
 	L:
 	}
 	goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
 }
 
 func _() {
-	for i = 0; i < n; i++ {	// GCCGO_ERROR "block starts here"
+	for i = 0; i < n; i++ { // GCCGO_ERROR "block starts here"
 	L:
 	}
 	goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
 }
 
 func _() {
-	for i = range x {	// GCCGO_ERROR "block starts here"
+	for i = range x { // GCCGO_ERROR "block starts here"
 	L:
 	}
 	goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
 }
 
 func _() {
-	for i = range c {	// GCCGO_ERROR "block starts here"
+	for i = range c { // GCCGO_ERROR "block starts here"
 	L:
 	}
 	goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
 }
 
 func _() {
-	for i = range m {	// GCCGO_ERROR "block starts here"
+	for i = range m { // GCCGO_ERROR "block starts here"
 	L:
 	}
 	goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
 }
 
 func _() {
-	for i = range s {	// GCCGO_ERROR "block starts here"
+	for i = range s { // GCCGO_ERROR "block starts here"
 	L:
 	}
 	goto L // ERROR "goto L jumps into block starting at LINE-3|goto jumps into block"
@@ -398,7 +398,7 @@ func _() {
 	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
 	switch i {
 	case 0:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 	}
 }
 
@@ -406,7 +406,7 @@ func _() {
 	goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
 	switch i {
 	case 0:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 		;
 	default:
 	}
@@ -417,7 +417,7 @@ func _() {
 	switch i {
 	case 0:
 	default:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 	}
 }
 
@@ -426,14 +426,14 @@ func _() {
 	default:
 		goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
 	case 0:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 	}
 }
 
 func _() {
 	switch i {
 	case 0:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 		;
 	default:
 		goto L // ERROR "goto L jumps into block starting at LINE-4|goto jumps into block"
@@ -495,7 +495,7 @@ func _() {
 	goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
 	select {
 	case c <- 1:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 	}
 }
 
@@ -503,7 +503,7 @@ func _() {
 	goto L // ERROR "goto L jumps into block starting at LINE+2|goto jumps into block"
 	select {
 	case c <- 1:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 		;
 	default:
 	}
@@ -514,7 +514,7 @@ func _() {
 	select {
 	case <-c:
 	default:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 	}
 }
 
@@ -523,14 +523,14 @@ func _() {
 	default:
 		goto L // ERROR "goto L jumps into block starting at LINE+1|goto jumps into block"
 	case <-c:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 	}
 }
 
 func _() {
 	select {
 	case <-c:
-	L:	// GCCGO_ERROR "block starts here"
+	L: // GCCGO_ERROR "block starts here"
 		;
 	default:
 		goto L // ERROR "goto L jumps into block starting at LINE-4|goto jumps into block"
diff --git a/test/import2.dir/import2.go b/test/import2.dir/import2.go
index 8bb1eb9..9c54a1b 100644
--- a/test/import2.dir/import2.go
+++ b/test/import2.dir/import2.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/import2.dir/import3.go b/test/import2.dir/import3.go
index d7fe37b..3bf9cb0 100644
--- a/test/import2.dir/import3.go
+++ b/test/import2.dir/import3.go
@@ -1,4 +1,4 @@
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/import2.go b/test/import2.go
index f8d0b0a..1ef1dd4 100644
--- a/test/import2.go
+++ b/test/import2.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/index.go b/test/index.go
index 9ff9e9f..d73d137 100644
--- a/test/index.go
+++ b/test/index.go
@@ -1,6 +1,6 @@
 // skip
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/index0.go b/test/index0.go
index 04a1619..62f3392 100644
--- a/test/index0.go
+++ b/test/index0.go
@@ -1,6 +1,6 @@
 // runoutput ./index.go
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/index1.go b/test/index1.go
index e28efa3..40efc54 100644
--- a/test/index1.go
+++ b/test/index1.go
@@ -1,6 +1,6 @@
 // errorcheckoutput ./index.go
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/index2.go b/test/index2.go
index a7107cc..2a210cc 100644
--- a/test/index2.go
+++ b/test/index2.go
@@ -1,6 +1,6 @@
 // errorcheckoutput ./index.go
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/init1.go b/test/init1.go
index 62dfb72..0803dce 100644
--- a/test/init1.go
+++ b/test/init1.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -40,7 +40,7 @@ func init() {
 	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)
+		println("numGC went", numGC, "to", numGC1)
 		panic("init1")
 	}
 }
diff --git a/test/inline.go b/test/inline.go
index fb20fab..773b047 100644
--- a/test/inline.go
+++ b/test/inline.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -m
 
-// Copyright 2015 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.
 
@@ -31,3 +31,44 @@ func g(x int) int {
 func h(x int) int { // ERROR "can inline h"
 	return x + 2
 }
+
+func i(x int) int { // ERROR "can inline i"
+	const y = 2
+	return x + y
+}
+
+func j(x int) int { // ERROR "can inline j"
+	switch {
+	case x > 0:
+		return x + 2
+	default:
+		return x + 1
+	}
+}
+
+// can't currently inline functions with a break statement
+func switchBreak(x, y int) int {
+	var n int
+	switch x {
+	case 0:
+		n = 1
+	Done:
+		switch y {
+		case 0:
+			n += 10
+			break Done
+		}
+		n = 2
+	}
+	return n
+}
+
+// can't currently inline functions with a type switch
+func switchType(x interface{}) int { // ERROR "switchType x does not escape"
+	switch x.(type) {
+	case int:
+		return x.(int)
+	default:
+		return 0
+	}
+}
diff --git a/test/interface/assertinline.go b/test/interface/assertinline.go
index faa848a..227fe70 100644
--- a/test/interface/assertinline.go
+++ b/test/interface/assertinline.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -d=typeassert
 
-// Copyright 2015 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.
 
diff --git a/test/interface/noeq.go b/test/interface/noeq.go
index 1c5166e..bb36893 100644
--- a/test/interface/noeq.go
+++ b/test/interface/noeq.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/interface/recursive1.dir/recursive1.go b/test/interface/recursive1.dir/recursive1.go
index 441f0ec..8498cb5 100644
--- a/test/interface/recursive1.dir/recursive1.go
+++ b/test/interface/recursive1.dir/recursive1.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/interface/recursive1.dir/recursive2.go b/test/interface/recursive1.dir/recursive2.go
index e8048c6..29385df 100644
--- a/test/interface/recursive1.dir/recursive2.go
+++ b/test/interface/recursive1.dir/recursive2.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/interface/recursive1.go b/test/interface/recursive1.go
index 62f6108..ea2f4eb 100644
--- a/test/interface/recursive1.go
+++ b/test/interface/recursive1.go
@@ -1,6 +1,6 @@
 // compiledir
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/intrinsic.dir/main.go b/test/intrinsic.dir/main.go
new file mode 100644
index 0000000..46e6cb3
--- /dev/null
+++ b/test/intrinsic.dir/main.go
@@ -0,0 +1,109 @@
+// Copyright 2016 The Go Authors. 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"
+	T "runtime/internal/sys"
+)
+
+var A = []uint64{0x0102030405060708, 0x1122334455667788}
+var B = []uint64{0x0807060504030201, 0x8877665544332211}
+
+var errors int
+
+func logf(f string, args ...interface{}) {
+	errors++
+	fmt.Printf(f, args...)
+	if errors > 100 { // 100 is enough spewage
+		panic("100 errors is plenty is enough")
+	}
+}
+
+func test(i, x uint64) {
+	t := T.Ctz64(x) // ERROR "intrinsic substitution for Ctz64"
+	if i != t {
+		logf("Ctz64(0x%x) expected %d but got %d\n", x, i, t)
+	}
+	x = -x
+	t = T.Ctz64(x) // ERROR "intrinsic substitution for Ctz64"
+	if i != t {
+		logf("Ctz64(0x%x) expected %d but got %d\n", x, i, t)
+	}
+
+	if i <= 32 {
+		x32 := uint32(x)
+		t32 := T.Ctz32(x32) // ERROR "intrinsic substitution for Ctz32"
+		if uint32(i) != t32 {
+			logf("Ctz32(0x%x) expected %d but got %d\n", x32, i, t32)
+		}
+		x32 = -x32
+		t32 = T.Ctz32(x32) // ERROR "intrinsic substitution for Ctz32"
+		if uint32(i) != t32 {
+			logf("Ctz32(0x%x) expected %d but got %d\n", x32, i, t32)
+		}
+	}
+	if i <= 16 {
+		x16 := uint16(x)
+		t16 := T.Ctz16(x16) // ERROR "intrinsic substitution for Ctz16"
+		if uint16(i) != t16 {
+			logf("Ctz16(0x%x) expected %d but got %d\n", x16, i, t16)
+		}
+		x16 = -x16
+		t16 = T.Ctz16(x16) // ERROR "intrinsic substitution for Ctz16"
+		if uint16(i) != t16 {
+			logf("Ctz16(0x%x) expected %d but got %d\n", x16, i, t16)
+		}
+	}
+}
+
+func main() {
+	// Test Bswap first because the other test relies on it
+	// working correctly (to implement bit reversal).
+	for i := range A {
+		x := A[i]
+		y := B[i]
+		X := T.Bswap64(x) // ERROR "intrinsic substitution for Bswap64"
+		Y := T.Bswap64(y) // ERROR "intrinsic substitution for Bswap64"
+		if y != X {
+			logf("Bswap64(0x%08x) expected 0x%08x but got 0x%08x\n", x, y, X)
+		}
+		if x != Y {
+			logf("Bswap64(0x%08x) expected 0x%08x but got 0x%08x\n", y, x, Y)
+		}
+
+		x32 := uint32(X)
+		y32 := uint32(Y >> 32)
+
+		X32 := T.Bswap32(x32) // ERROR "intrinsic substitution for Bswap32"
+		Y32 := T.Bswap32(y32) // ERROR "intrinsic substitution for Bswap32"
+		if y32 != X32 {
+			logf("Bswap32(0x%08x) expected 0x%08x but got 0x%08x\n", x32, y32, X32)
+		}
+		if x32 != Y32 {
+			logf("Bswap32(0x%08x) expected 0x%08x but got 0x%08x\n", y32, x32, Y32)
+		}
+	}
+
+	// Zero is a special case, be sure it is done right.
+	if T.Ctz16(0) != 16 { // ERROR "intrinsic substitution for Ctz16"
+		logf("ctz16(0) != 16")
+	}
+	if T.Ctz32(0) != 32 { // ERROR "intrinsic substitution for Ctz32"
+		logf("ctz32(0) != 32")
+	}
+	if T.Ctz64(0) != 64 { // ERROR "intrinsic substitution for Ctz64"
+		logf("ctz64(0) != 64")
+	}
+
+	for i := uint64(0); i <= 64; i++ {
+		for j := uint64(1); j <= 255; j += 2 {
+			for k := uint64(1); k <= 65537; k += 128 {
+				x := (j * k) << i
+				test(i, x)
+			}
+		}
+	}
+}
diff --git a/test/intrinsic.go b/test/intrinsic.go
new file mode 100644
index 0000000..f774128
--- /dev/null
+++ b/test/intrinsic.go
@@ -0,0 +1,8 @@
+// errorcheckandrundir -0 -d=ssa/intrinsics/debug
+// +build !ppc64,!ppc64le,amd64
+
+// Copyright 2016 The Go Authors. 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/ken/embed.go b/test/ken/embed.go
index 9b35c56..f7ca066 100644
--- a/test/ken/embed.go
+++ b/test/ken/embed.go
@@ -253,7 +253,7 @@ func main() {
 		panic("fail")
 	}
 
-	// run it thru an interface
+	// run it through an interface
 	i = s
 	s = i.(*S)
 
diff --git a/test/label.go b/test/label.go
index b30c27e..11716cc 100644
--- a/test/label.go
+++ b/test/label.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
@@ -17,8 +17,7 @@ L1: // ERROR "label .*L1.* defined and not used"
 	for {
 	}
 L2: // ERROR "label .*L2.* defined and not used"
-	select {
-	}
+	select {}
 L3: // ERROR "label .*L3.* defined and not used"
 	switch {
 	}
@@ -59,4 +58,8 @@ L10:
 	default:
 		break L10
 	}
+
+	goto L10
+
+	goto go2 // ERROR "label go2 not defined"
 }
diff --git a/test/label1.go b/test/label1.go
index f923a18..bdd489f 100644
--- a/test/label1.go
+++ b/test/label1.go
@@ -1,10 +1,9 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
-
 // Verify that erroneous labels are caught by the compiler.
 // This set is caught by pass 2. That's why this file is label1.go.
 // Does not compile.
@@ -32,11 +31,17 @@ L2:
 			break L2
 		}
 		if x == 1 {
-			continue L2 // ERROR "invalid continue label .*L2"
+			continue L2 // ERROR "invalid continue label .*L2|continue is not in a loop"
 		}
 		goto L2
 	}
 
+	for {
+		if x == 1 {
+			continue L2 // ERROR "invalid continue label .*L2"
+		}
+	}
+
 L3:
 	switch {
 	case x > 10:
@@ -44,7 +49,7 @@ L3:
 			break L3
 		}
 		if x == 12 {
-			continue L3 // ERROR "invalid continue label .*L3"
+			continue L3 // ERROR "invalid continue label .*L3|continue is not in a loop"
 		}
 		goto L3
 	}
@@ -55,7 +60,7 @@ L4:
 			break L4 // ERROR "invalid break label .*L4"
 		}
 		if x == 14 {
-			continue L4 // ERROR "invalid continue label .*L4"
+			continue L4 // ERROR "invalid continue label .*L4|continue is not in a loop"
 		}
 		if x == 15 {
 			goto L4
@@ -68,7 +73,7 @@ L5:
 		break L5 // ERROR "invalid break label .*L5"
 	}
 	if x == 17 {
-		continue L5 // ERROR "invalid continue label .*L5"
+		continue L5 // ERROR "invalid continue label .*L5|continue is not in a loop"
 	}
 	if x == 18 {
 		goto L5
@@ -85,4 +90,21 @@ L5:
 			goto L1
 		}
 	}
+
+	continue // ERROR "continue is not in a loop"
+	for {
+		continue on // ERROR "continue label not defined: on"
+	}
+
+	break // ERROR "break is not in a loop"
+	for {
+		break dance // ERROR "break label not defined: dance"
+	}
+
+	for {
+		switch x {
+		case 1:
+			continue
+		}
+	}
 }
diff --git a/test/linkmain.go b/test/linkmain.go
index dcfbf50..af20ca5 100644
--- a/test/linkmain.go
+++ b/test/linkmain.go
@@ -1,6 +1,6 @@
 // +build ignore
 
-// Copyright 2015 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.
 
diff --git a/test/linkobj.go b/test/linkobj.go
new file mode 100644
index 0000000..8a86aa8
--- /dev/null
+++ b/test/linkobj.go
@@ -0,0 +1,155 @@
+// +build !nacl
+// run
+
+// Copyright 2016 The Go 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 compiler -linkobj flag.
+
+package main
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"strings"
+)
+
+var pwd, tmpdir string
+
+func main() {
+	dir, err := ioutil.TempDir("", "go-test-linkobj-")
+	if err != nil {
+		log.Fatal(err)
+	}
+	pwd, err = os.Getwd()
+	if err != nil {
+		log.Fatal(err)
+	}
+	if err := os.Chdir(dir); err != nil {
+		os.RemoveAll(dir)
+		log.Fatal(err)
+	}
+	tmpdir = dir
+
+	writeFile("p1.go", `
+		package p1
+		
+		func F() {
+			println("hello from p1")
+		}
+	`)
+	writeFile("p2.go", `
+		package p2
+		
+		import "./p1"
+
+		func F() {
+			p1.F()
+			println("hello from p2")
+		}
+		
+		func main() {}
+	`)
+	writeFile("p3.go", `
+		package main
+
+		import "./p2"
+		
+		func main() {
+			p2.F()
+			println("hello from main")
+		}
+	`)
+
+	// two rounds: once using normal objects, again using .a files (compile -pack).
+	for round := 0; round < 2; round++ {
+		pkg := "-pack=" + fmt.Sprint(round)
+
+		// The compiler expects the files being read to have the right suffix.
+		o := "o"
+		if round == 1 {
+			o = "a"
+		}
+
+		// inlining is disabled to make sure that the link objects contain needed code.
+		run("go", "tool", "compile", pkg, "-D", ".", "-I", ".", "-l", "-o", "p1."+o, "-linkobj", "p1.lo", "p1.go")
+		run("go", "tool", "compile", pkg, "-D", ".", "-I", ".", "-l", "-o", "p2."+o, "-linkobj", "p2.lo", "p2.go")
+		run("go", "tool", "compile", pkg, "-D", ".", "-I", ".", "-l", "-o", "p3."+o, "-linkobj", "p3.lo", "p3.go")
+
+		cp("p1."+o, "p1.oo")
+		cp("p2."+o, "p2.oo")
+		cp("p3."+o, "p3.oo")
+		cp("p1.lo", "p1."+o)
+		cp("p2.lo", "p2."+o)
+		cp("p3.lo", "p3."+o)
+		out := runFail("go", "tool", "link", "p2."+o)
+		if !strings.Contains(out, "not package main") {
+			fatalf("link p2.o failed but not for package main:\n%s", out)
+		}
+
+		run("go", "tool", "link", "-L", ".", "-o", "a.out.exe", "p3."+o)
+		out = run("./a.out.exe")
+		if !strings.Contains(out, "hello from p1\nhello from p2\nhello from main\n") {
+			fatalf("running main, incorrect output:\n%s", out)
+		}
+
+		// ensure that mistaken future round can't use these
+		os.Remove("p1.o")
+		os.Remove("a.out.exe")
+	}
+
+	cleanup()
+}
+
+func run(args ...string) string {
+	out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
+	if err != nil {
+		fatalf("run %v: %s\n%s", args, err, out)
+	}
+	return string(out)
+}
+
+func runFail(args ...string) string {
+	out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
+	if err == nil {
+		fatalf("runFail %v: unexpected success!\n%s", args, err, out)
+	}
+	return string(out)
+}
+
+func cp(src, dst string) {
+	data, err := ioutil.ReadFile(src)
+	if err != nil {
+		fatalf("%v", err)
+	}
+	err = ioutil.WriteFile(dst, data, 0666)
+	if err != nil {
+		fatalf("%v", err)
+	}
+}
+
+func writeFile(name, data string) {
+	err := ioutil.WriteFile(name, []byte(data), 0666)
+	if err != nil {
+		fatalf("%v", err)
+	}
+}
+
+func cleanup() {
+	const debug = false
+	if debug {
+		println("TMPDIR:", tmpdir)
+		return
+	}
+	os.Chdir(pwd) // get out of tmpdir before removing it
+	os.RemoveAll(tmpdir)
+}
+
+func fatalf(format string, args ...interface{}) {
+	cleanup()
+	log.Fatalf(format, args...)
+}
diff --git a/test/linkx.go b/test/linkx.go
index ac20334..20b8c77 100644
--- a/test/linkx.go
+++ b/test/linkx.go
@@ -1,6 +1,6 @@
 // skip
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/linkx_run.go b/test/linkx_run.go
index a6c7c67..cc249c9 100644
--- a/test/linkx_run.go
+++ b/test/linkx_run.go
@@ -18,7 +18,7 @@ import (
 )
 
 func main() {
-	test(" ") // old deprecated syntax
+	// test(" ") // old deprecated & removed syntax
 	test("=") // new syntax
 }
 
@@ -60,11 +60,11 @@ func test(sep string) {
 	}
 	outstr := string(outx)
 	if !strings.Contains(outstr, "main.b") {
-		fmt.Printf("-X linker flag did not diagnose overwrite of main.b\n")
+		fmt.Printf("-X linker flag did not diagnose overwrite of main.b:\n%s\n", outstr)
 		os.Exit(1)
 	}
 	if !strings.Contains(outstr, "main.x") {
-		fmt.Printf("-X linker flag did not diagnose overwrite of main.x\n")
+		fmt.Printf("-X linker flag did not diagnose overwrite of main.x:\n%s\n", outstr)
 		os.Exit(1)
 	}
 }
diff --git a/test/live.go b/test/live.go
index ae982f4..da0606d 100644
--- a/test/live.go
+++ b/test/live.go
@@ -1,6 +1,7 @@
+// +build !amd64
 // errorcheck -0 -l -live -wb=0
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/live1.go b/test/live1.go
index b05ec1f..87c8c97 100644
--- a/test/live1.go
+++ b/test/live1.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/live2.go b/test/live2.go
index 7474756..a5bbfa5 100644
--- a/test/live2.go
+++ b/test/live2.go
@@ -1,6 +1,7 @@
+// +build !amd64
 // errorcheck -0 -live -wb=0
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/live_ssa.go b/test/live_ssa.go
new file mode 100644
index 0000000..bd70924
--- /dev/null
+++ b/test/live_ssa.go
@@ -0,0 +1,648 @@
+// +build amd64
+// errorcheck -0 -l -live -wb=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.
+
+// liveness tests with inlining disabled.
+// see also live2.go.
+
+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
+	printpointer(&x) // ERROR "live at call to printpointer: x$"
+	printpointer(&x) // ERROR "live at call to printpointer: x$"
+}
+
+func f2(b bool) {
+	if b {
+		printint(0) // nothing live here
+		return
+	}
+	var x *int
+	printpointer(&x) // ERROR "live at call to printpointer: x$"
+	printpointer(&x) // ERROR "live at call to printpointer: x$"
+}
+
+func f3(b1, b2 bool) {
+	// Because x and y are ambiguously live, they appear
+	// live throughout the function, to avoid being poisoned
+	// in GODEBUG=gcdead=1 mode.
+
+	printint(0) // ERROR "live at call to printint: x y$"
+	if b1 == false {
+		printint(0) // ERROR "live at call to printint: x y$"
+		return
+	}
+
+	if b2 {
+		var x *int
+		printpointer(&x) // ERROR "live at call to printpointer: x y$"
+		printpointer(&x) // ERROR "live at call to printpointer: x y$"
+	} else {
+		var y *int
+		printpointer(&y) // ERROR "live at call to printpointer: x y$"
+		printpointer(&y) // ERROR "live at call to printpointer: x y$"
+	}
+	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
+// could flow to a return statement, so it included the
+// function entry and code above the declaration of x
+// but would not include an indirect use of x in an infinite loop.
+// Check that these cases are handled correctly.
+
+func f4(b1, b2 bool) { // x not live here
+	if b2 {
+		printint(0) // x not live here
+		return
+	}
+	var z **int
+	x := new(int)
+	*x = 42
+	z = &x
+	printint(**z) // ERROR "live at call to printint: x$"
+	if b2 {
+		printint(1) // x not live here
+		return
+	}
+	for {
+		printint(**z) // ERROR "live at call to printint: x$"
+	}
+}
+
+func f5(b1 bool) {
+	var z **int
+	if b1 {
+		x := new(int)
+		*x = 42
+		z = &x
+	} else {
+		y := new(int)
+		*y = 54
+		z = &y
+	}
+	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: _".
+
+func f6() (_, y string) {
+	y = "hello"
+	return
+}
+
+// confusion about addressed results used to cause "live at entry to f7: x".
+
+func f7() (x string) {
+	_ = &x
+	x = "hello"
+	return
+}
+
+// ignoring block returns used to cause "live at entry to f8: x, y".
+
+func f8() (x, y string) {
+	return g8()
+}
+
+func g8() (string, string)
+
+// ignoring block assignments used to cause "live at entry to f9: x"
+// issue 7205
+
+var i9 interface{}
+
+func f9() bool {
+	g8()
+	x := i9
+	return x != interface{}(99.0i) // ERROR "live at call to convT2E: x.data x.type$"
+}
+
+// liveness formerly confused by UNDEF followed by RET,
+// leading to "live at entry to f10: ~r1" (unnamed result).
+
+func f10() string {
+	panic(1)
+}
+
+// liveness formerly confused by select, thinking runtime.selectgo
+// can return to next instruction; it always jumps elsewhere.
+// note that you have to use at least two cases in the select
+// to get a true select; smaller selects compile to optimized helper functions.
+
+var c chan *int
+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_[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_[0-9]+$"
+		return nil
+	}
+}
+
+func f11b() *int {
+	p := new(int)
+	if b {
+		// 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".
+		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_[0-9]+$"
+			return nil
+		}
+	}
+	println(*p)
+	return nil
+}
+
+var sink *int
+
+func f11c() *int {
+	p := new(int)
+	sink = p // prevent stack allocation, otherwise p is rematerializeable
+	if b {
+		// Unlike previous, the cases in this select fall through,
+		// so we can get to the println, so p is not dead.
+		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)
+	return nil
+}
+
+// similarly, select{} does not fall through.
+// this used to have a spurious "live at entry to f12: ~r0".
+
+func f12() *int {
+	if b {
+		select {}
+	} else {
+		return nil
+	}
+}
+
+// incorrectly placed VARDEF annotations can cause missing liveness annotations.
+// this used to be missing the fact that s is live during the call to g13 (because it is
+// needed for the call to h13).
+
+func f13() {
+	s := g14()
+	s = h13(s, g13(s)) // ERROR "live at call to g13: s.ptr$"
+}
+
+func g13(string) string
+func h13(string, string) string
+
+// more incorrectly placed VARDEF.
+
+func f14() {
+	x := g14()
+	printstringpointer(&x) // ERROR "live at call to printstringpointer: x$"
+}
+
+func g14() string
+
+func f15() {
+	var x string
+	_ = &x
+	x = g15()      // ERROR "live at call to g15: x$"
+	printstring(x) // ERROR "live at call to printstring: x$"
+}
+
+func g15() string
+
+// Checking that various temporaries do not persist or cause
+// ambiguously live values that must be zeroed.
+// The exact temporary names are inconsequential but we are
+// trying to check that there is only one at any given site,
+// and also that none show up in "ambiguously live" messages.
+
+var m map[string]int
+
+func f16() {
+	if b {
+		delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+	}
+	delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+	delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+}
+
+var m2s map[string]*byte
+var m2 map[[2]string]*byte
+var x2 [2]string
+var bp *byte
+
+func f17a() {
+	// value temporary only
+	if b {
+		m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+	}
+	m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+	m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+}
+
+func f17b() {
+	// key temporary only
+	if b {
+		m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+	}
+	m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+	m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+}
+
+func f17c() {
+	// key and value temporaries
+	if b {
+		m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+	}
+	m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+	m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+}
+
+func g18() [2]string
+
+func f18() {
+	// key temporary for mapaccess.
+	// temporary introduced by orderexpr.
+	var z *byte
+	if b {
+		z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	}
+	z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	printbytepointer(z)
+}
+
+var ch chan *byte
+
+func f19() {
+	// dest temporary for channel receive.
+	var z *byte
+
+	if b {
+		z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+	}
+	z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+	z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+	printbytepointer(z)
+}
+
+func f20() {
+	// src temporary for channel send
+	if b {
+		ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+	}
+	ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+	ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+}
+
+func f21() {
+	// key temporary for mapaccess using array literal key.
+	var z *byte
+	if b {
+		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]+$"
+	z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+	printbytepointer(z)
+}
+
+func f23() {
+	// key temporary for two-result map access using array literal key.
+	var z *byte
+	var ok bool
+	if b {
+		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]+$"
+	z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
+	printbytepointer(z)
+	print(ok)
+}
+
+func f24() {
+	// key temporary for map access using array literal key.
+	// value temporary too.
+	if b {
+		m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+	}
+	m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+	m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+}
+
+// defer should not cause spurious ambiguously live variables
+
+func f25(b bool) {
+	defer g25()
+	if b {
+		return
+	}
+	var x string
+	_ = &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()
+
+// non-escaping ... slices passed to function call should die on return,
+// so that the temporaries do not stack and do not cause ambiguously
+// live variables.
+
+func f26(b bool) {
+	if b {
+		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]+$"
+	print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
+	printnl()
+}
+
+//go:noescape
+func print26(...interface{})
+
+// non-escaping closures passed to function call should die on return
+
+func f27(b bool) {
+	x := 0
+	if b {
+		call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
+	}
+	call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
+	call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
+	printnl()
+}
+
+// but defer does escape to later execution in the function
+
+func f27defer(b bool) {
+	x := 0
+	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 "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
+
+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$"
+	printnl()
+}
+
+//go:noescape
+func call27(func())
+
+// concatstring slice should die on return
+
+var s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 string
+
+func f28(b bool) {
+	if b {
+		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]+$"
+	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
+
+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]+$"
+			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]+$"
+		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]+$"
+		printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+	}
+}
+
+// copy of array of pointers should die at end of range loop
+
+var ptrarr [10]*int
+
+func f30(b bool) {
+	// two live temps during print(p):
+	// the copy of ptrarr and the internal iterator pointer.
+	if b {
+		for _, p := range ptrarr {
+			printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+		}
+	}
+	for _, p := range ptrarr {
+		printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+	}
+	for _, p := range ptrarr {
+		printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+	}
+}
+
+// conversion to interface should not leave temporary behind
+
+func f31(b1, b2, b3 bool) {
+	if b1 {
+		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 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]+$"
+	}
+	print(b3)
+}
+
+func g31(interface{})
+func h31(...interface{})
+
+// non-escaping partial functions passed to function call should die on return
+
+type T32 int
+
+func (t *T32) Inc() { // ERROR "live at entry to \(\*T32\).Inc: t$"
+	*t++
+}
+
+var t32 T32
+
+func f32(b bool) {
+	if b {
+		call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+	}
+	call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+	call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+}
+
+//go:noescape
+func call32(func())
+
+// temporaries introduced during if conditions and && || expressions
+// should die once the condition has been acted upon.
+
+var m33 map[interface{}]int
+
+func f33() {
+	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		printnl()
+		return
+	} else {
+		printnl()
+	}
+	printnl()
+}
+
+func f34() {
+	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		printnl()
+		return
+	}
+	printnl()
+}
+
+func f35() {
+	if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		printnl()
+		return
+	}
+	printnl()
+}
+
+func f36() {
+	if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		printnl()
+		return
+	}
+	printnl()
+}
+
+func f37() {
+	if (m33[nil] == 0 || m33[nil] == 0) && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+		printnl()
+		return
+	}
+	printnl()
+}
+
+// select temps should disappear in the case bodies
+
+var c38 chan string
+
+func fc38() chan string
+func fi38(int) *string
+func fb38() *bool
+
+func f38(b bool) {
+	// we don't care what temps are printed on the lines with output.
+	// we care that the println lines have no live variables
+	// and therefore no output.
+	if b {
+		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()
+		}
+		printnl()
+	}
+	printnl()
+}
+
+// issue 8097: mishandling of x = x during return.
+
+func f39() (x []int) {
+	x = []int{1}
+	printnl() // ERROR "live at call to printnl: autotmp_[0-9]+$"
+	return x
+}
+
+func f39a() (x []int) {
+	x = []int{1}
+	printnl() // ERROR "live at call to printnl: autotmp_[0-9]+$"
+	return
+}
+
+func f39b() (x [10]*int) {
+	x = [10]*int{}
+	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$"
+	printnl()       // ERROR "live at call to printnl: x$"
+	return
+}
+
+// issue 8142: lost 'addrtaken' bit on inlined variables.
+// no inlining in this test, so just checking that non-inlined works.
+
+type T40 struct {
+	m map[int]int
+}
+
+func newT40() *T40 {
+	ret := T40{}
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret$"
+	return &ret
+}
+
+func bad40() {
+	t := newT40()
+	_ = t
+	printnl()
+}
+
+func good40() {
+	ret := T40{}
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_[0-9]+ ret$"
+	t := &ret
+	printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ ret$"
+	_ = t
+}
diff --git a/test/live_syscall.go b/test/live_syscall.go
index c9bf0f2..8aaa691 100644
--- a/test/live_syscall.go
+++ b/test/live_syscall.go
@@ -2,7 +2,7 @@
 
 // +build !windows
 
-// Copyright 2015 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.
 
diff --git a/test/loopbce.go b/test/loopbce.go
new file mode 100644
index 0000000..ea19521
--- /dev/null
+++ b/test/loopbce.go
@@ -0,0 +1,253 @@
+// +build amd64
+// errorcheck -0 -d=ssa/loopbce/debug=3
+
+package main
+
+func f0a(a []int) int {
+	x := 0
+	for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
+		x += a[i] // ERROR "Found redundant IsInBounds$"
+	}
+	return x
+}
+
+func f0b(a []int) int {
+	x := 0
+	for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
+		b := a[i:] // ERROR "Found redundant IsSliceInBounds$"
+		x += b[0]
+	}
+	return x
+}
+
+func f0c(a []int) int {
+	x := 0
+	for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
+		b := a[:i+1] // ERROR "Found redundant IsSliceInBounds \(len promoted to cap\)$"
+		x += b[0]
+	}
+	return x
+}
+
+func f1(a []int) int {
+	x := 0
+	for _, i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
+		x += i
+	}
+	return x
+}
+
+func f2(a []int) int {
+	x := 0
+	for i := 1; i < len(a); i++ { // ERROR "Induction variable with minimum 1 and increment 1$"
+		x += a[i] // ERROR "Found redundant IsInBounds$"
+	}
+	return x
+}
+
+func f4(a [10]int) int {
+	x := 0
+	for i := 0; i < len(a); i += 2 { // ERROR "Induction variable with minimum 0 and increment 2$"
+		x += a[i] // ERROR "Found redundant IsInBounds$"
+	}
+	return x
+}
+
+func f5(a [10]int) int {
+	x := 0
+	for i := -10; i < len(a); i += 2 { // ERROR "Induction variable with minimum -10 and increment 2$"
+		x += a[i]
+	}
+	return x
+}
+
+func f6(a []int) {
+	for i := range a { // ERROR "Induction variable with minimum 0 and increment 1$"
+		b := a[0:i] // ERROR "Found redundant IsSliceInBounds \(len promoted to cap\)$"
+		f6(b)
+	}
+}
+
+func g0a(a string) int {
+	x := 0
+	for i := 0; i < len(a); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
+		x += int(a[i]) // ERROR "Found redundant IsInBounds$"
+	}
+	return x
+}
+
+func g0b(a string) int {
+	x := 0
+	for i := 0; len(a) > i; i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
+		x += int(a[i]) // ERROR "Found redundant IsInBounds$"
+	}
+	return x
+}
+
+func g1() int {
+	a := "evenlength"
+	x := 0
+	for i := 0; i < len(a); i += 2 { // ERROR "Induction variable with minimum 0 and increment 2$"
+		x += int(a[i]) // ERROR "Found redundant IsInBounds$"
+	}
+	return x
+}
+
+func g2() int {
+	a := "evenlength"
+	x := 0
+	for i := 0; i < len(a); i += 2 { // ERROR "Induction variable with minimum 0 and increment 2$"
+		j := i
+		if a[i] == 'e' { // ERROR "Found redundant IsInBounds$"
+			j = j + 1
+		}
+		x += int(a[j])
+	}
+	return x
+}
+
+func g3a() {
+	a := "this string has length 25"
+	for i := 0; i < len(a); i += 5 { // ERROR "Induction variable with minimum 0 and increment 5$"
+		useString(a[i:]) // ERROR "Found redundant IsSliceInBounds$"
+		useString(a[:i+3])
+	}
+}
+
+func g3b(a string) {
+	for i := 0; i < len(a); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
+		useString(a[i+1:]) // ERROR "Found redundant IsSliceInBounds$"
+	}
+}
+
+func g3c(a string) {
+	for i := 0; i < len(a); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
+		useString(a[:i+1]) // ERROR "Found redundant IsSliceInBounds$"
+	}
+}
+
+func h1(a []byte) {
+	c := a[:128]
+	for i := range c { // ERROR "Induction variable with minimum 0 and increment 1$"
+		c[i] = byte(i) // ERROR "Found redundant IsInBounds$"
+	}
+}
+
+func h2(a []byte) {
+	for i := range a[:128] { // ERROR "Induction variable with minimum 0 and increment 1$"
+		a[i] = byte(i)
+	}
+}
+
+func k0(a [100]int) [100]int {
+	for i := 10; i < 90; i++ { // ERROR "Induction variable with minimum 10 and increment 1$"
+		a[i-11] = i
+		a[i-10] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 80$"
+		a[i-5] = i  // ERROR "Found redundant \(IsInBounds ind 100\), ind < 85$"
+		a[i] = i    // ERROR "Found redundant \(IsInBounds ind 100\), ind < 90$"
+		a[i+5] = i  // ERROR "Found redundant \(IsInBounds ind 100\), ind < 95$"
+		a[i+10] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 100$"
+		a[i+11] = i
+	}
+	return a
+}
+
+func k1(a [100]int) [100]int {
+	for i := 10; i < 90; i++ { // ERROR "Induction variable with minimum 10 and increment 1$"
+		useSlice(a[:i-11])
+		useSlice(a[:i-10]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 80$"
+		useSlice(a[:i-5])  // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 85$"
+		useSlice(a[:i])    // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 90$"
+		useSlice(a[:i+5])  // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 95$"
+		useSlice(a[:i+10]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 100$"
+		useSlice(a[:i+11]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 101$"
+
+	}
+	return a
+}
+
+func k2(a [100]int) [100]int {
+	for i := 10; i < 90; i++ { // ERROR "Induction variable with minimum 10 and increment 1$"
+		useSlice(a[i-11:])
+		useSlice(a[i-10:]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 80$"
+		useSlice(a[i-5:])  // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 85$"
+		useSlice(a[i:])    // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 90$"
+		useSlice(a[i+5:])  // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 95$"
+		useSlice(a[i+10:]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 100$"
+		useSlice(a[i+11:]) // ERROR "Found redundant \(IsSliceInBounds ind 100\), ind < 101$"
+	}
+	return a
+}
+
+func k3(a [100]int) [100]int {
+	for i := -10; i < 90; i++ { // ERROR "Induction variable with minimum -10 and increment 1$"
+		a[i+10] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 100$"
+	}
+	return a
+}
+
+func k4(a [100]int) [100]int {
+	min := (-1) << 63
+	for i := min; i < min+50; i++ { // ERROR "Induction variable with minimum -9223372036854775808 and increment 1$"
+		a[i-min] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 50$"
+	}
+	return a
+}
+
+func k5(a [100]int) [100]int {
+	max := (1 << 63) - 1
+	for i := max - 50; i < max; i++ { // ERROR "Induction variable with minimum 9223372036854775757 and increment 1$"
+		a[i-max+50] = i
+		a[i-(max-70)] = i // ERROR "Found redundant \(IsInBounds ind 100\), ind < 70$"
+	}
+	return a
+}
+
+func nobce1() {
+	// tests overflow of max-min
+	a := int64(9223372036854774057)
+	b := int64(-1547)
+	z := int64(1337)
+
+	if a%z == b%z {
+		panic("invalid test: modulos should differ")
+	}
+
+	for i := b; i < a; i += z {
+		// No induction variable is possible because i will overflow a first iteration.
+		useString("foobar")
+	}
+}
+
+func nobce2(a string) {
+	for i := int64(0); i < int64(len(a)); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
+		useString(a[i:]) // ERROR "Found redundant IsSliceInBounds$"
+	}
+	for i := int64(0); i < int64(len(a))-31337; i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
+		useString(a[i:]) // ERROR "Found redundant IsSliceInBounds$"
+	}
+	for i := int64(0); i < int64(len(a))+int64(-1<<63); i++ { // ERROR "Induction variable with minimum 0 and increment 1$"
+		// tests an overflow of StringLen-MinInt64
+		useString(a[i:])
+	}
+}
+
+func nobce3(a [100]int64) [100]int64 {
+	min := int64((-1) << 63)
+	max := int64((1 << 63) - 1)
+	for i := min; i < max; i++ { // ERROR "Induction variable with minimum -9223372036854775808 and increment 1$"
+		a[i] = i
+	}
+	return a
+}
+
+//go:noinline
+func useString(a string) {
+}
+
+//go:noinline
+func useSlice(a []int) {
+}
+
+func main() {
+}
diff --git a/test/map1.go b/test/map1.go
index 6f1a1c8..d3c0a90 100644
--- a/test/map1.go
+++ b/test/map1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/method1.go b/test/method1.go
index 365b8ca..bb8c81d 100644
--- a/test/method1.go
+++ b/test/method1.go
@@ -9,12 +9,16 @@
 
 package main
 
-type T struct { }
-func (t *T) M(int, string)	// GCCGO_ERROR "previous"
-func (t *T) M(int, float64) { }   // ERROR "redeclared|redefinition"
+type T struct{}
 
-func f(int, string)	// GCCGO_ERROR "previous"
-func f(int, float64) { }  // ERROR "redeclared|redefinition"
+func (t *T) M(int, string)  // GCCGO_ERROR "previous"
+func (t *T) M(int, float64) {} // ERROR "redeclared|redefinition"
 
-func g(a int, b string)  // GCCGO_ERROR "previous"
-func g(a int, c string)  // ERROR "redeclared|redefinition"
+func (t T) H()  // GCCGO_ERROR "previous"
+func (t *T) H() {} // ERROR "redeclared|redefinition"
+
+func f(int, string)  // GCCGO_ERROR "previous"
+func f(int, float64) {} // ERROR "redeclared|redefinition"
+
+func g(a int, b string) // GCCGO_ERROR "previous"
+func g(a int, c string) // ERROR "redeclared|redefinition"
diff --git a/test/method5.go b/test/method5.go
index 36508f2..d87bb6f 100644
--- a/test/method5.go
+++ b/test/method5.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/named.go b/test/named.go
index d0330ab..9763c76 100644
--- a/test/named.go
+++ b/test/named.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/named1.go b/test/named1.go
index febad64..7feae13 100644
--- a/test/named1.go
+++ b/test/named1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/nilcheck.go b/test/nilcheck.go
index 99c3c5f..6879438 100644
--- a/test/nilcheck.go
+++ b/test/nilcheck.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -N -d=nil
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -17,7 +17,7 @@ type Struct struct {
 type BigStruct struct {
 	X int
 	Y float64
-	A [1<<20]int
+	A [1 << 20]int
 	Z string
 }
 
@@ -29,86 +29,86 @@ type Empty1 struct {
 }
 
 var (
-	intp *int
-	arrayp *[10]int
-	array0p *[0]int
-	bigarrayp *[1<<26]int
-	structp *Struct
+	intp       *int
+	arrayp     *[10]int
+	array0p    *[0]int
+	bigarrayp  *[1 << 26]int
+	structp    *Struct
 	bigstructp *BigStruct
-	emptyp *Empty
-	empty1p *Empty1
+	emptyp     *Empty
+	empty1p    *Empty1
 )
 
 func f1() {
-	_ = *intp // ERROR "nil check"
-	_ = *arrayp // ERROR "nil check"
+	_ = *intp    // ERROR "nil check"
+	_ = *arrayp  // ERROR "nil check"
 	_ = *array0p // ERROR "nil check"
 	_ = *array0p // ERROR "nil check"
-	_ = *intp // ERROR "nil check"
-	_ = *arrayp // ERROR "nil check"
+	_ = *intp    // ERROR "nil check"
+	_ = *arrayp  // ERROR "nil check"
 	_ = *structp // ERROR "nil check"
-	_ = *emptyp // ERROR "nil check"
-	_ = *arrayp // ERROR "nil check"
+	_ = *emptyp  // ERROR "nil check"
+	_ = *arrayp  // ERROR "nil check"
 }
 
 func f2() {
 	var (
-		intp *int
-		arrayp *[10]int
-		array0p *[0]int
-		bigarrayp *[1<<20]int
-		structp *Struct
+		intp       *int
+		arrayp     *[10]int
+		array0p    *[0]int
+		bigarrayp  *[1 << 20]int
+		structp    *Struct
 		bigstructp *BigStruct
-		emptyp *Empty
-		empty1p *Empty1
+		emptyp     *Empty
+		empty1p    *Empty1
 	)
 
-	_ = *intp // ERROR "nil check"
-	_ = *arrayp // ERROR "nil check"
-	_ = *array0p // ERROR "nil check"
-	_ = *array0p // ERROR "nil check"
-	_ = *intp // ERROR "nil check"
-	_ = *arrayp // ERROR "nil check"
-	_ = *structp // ERROR "nil check"
-	_ = *emptyp // ERROR "nil check"
-	_ = *arrayp // ERROR "nil check"
-	_ = *bigarrayp // ERROR "nil check"
+	_ = *intp       // ERROR "nil check"
+	_ = *arrayp     // ERROR "nil check"
+	_ = *array0p    // ERROR "nil check"
+	_ = *array0p    // ERROR "nil check"
+	_ = *intp       // ERROR "nil check"
+	_ = *arrayp     // ERROR "nil check"
+	_ = *structp    // ERROR "nil check"
+	_ = *emptyp     // ERROR "nil check"
+	_ = *arrayp     // ERROR "nil check"
+	_ = *bigarrayp  // ERROR "nil check"
 	_ = *bigstructp // ERROR "nil check"
-	_ = *empty1p // ERROR "nil check"
+	_ = *empty1p    // ERROR "nil check"
 }
 
 func fx10k() *[10000]int
-var b bool
 
+var b bool
 
 func f3(x *[10000]int) {
 	// Using a huge type and huge offsets so the compiler
 	// does not expect the memory hardware to fault.
 	_ = x[9999] // ERROR "nil check"
-	
+
 	for {
 		if x[9999] != 0 { // ERROR "nil check"
 			break
 		}
 	}
-	
-	x = fx10k() 
+
+	x = fx10k()
 	_ = x[9999] // ERROR "nil check"
 	if b {
 		_ = x[9999] // ERROR "nil check"
 	} else {
 		_ = x[9999] // ERROR "nil check"
-	}	
+	}
 	_ = x[9999] // ERROR "nil check"
 
-	x = fx10k() 
+	x = fx10k()
 	if b {
 		_ = x[9999] // ERROR "nil check"
 	} else {
 		_ = x[9999] // ERROR "nil check"
-	}	
+	}
 	_ = x[9999] // ERROR "nil check"
-	
+
 	fx10k()
 	// This one is a bit redundant, if we figured out that
 	// x wasn't going to change across the function call.
@@ -138,7 +138,7 @@ func f3b() {
 	_ = &x[9] // ERROR "nil check"
 }
 
-func fx10() *[10]int 
+func fx10() *[10]int
 
 func f4(x *[10]int) {
 	// Most of these have no checks because a real memory reference follows,
@@ -146,33 +146,33 @@ func f4(x *[10]int) {
 	// in the first unmapped page of memory.
 
 	_ = x[9] // ERROR "nil check"
-	
+
 	for {
 		if x[9] != 0 { // ERROR "nil check"
 			break
 		}
 	}
-	
-	x = fx10() 
+
+	x = fx10()
 	_ = x[9] // ERROR "nil check"
 	if b {
 		_ = x[9] // ERROR "nil check"
 	} else {
 		_ = x[9] // ERROR "nil check"
-	}	
+	}
 	_ = x[9] // ERROR "nil check"
 
-	x = fx10() 
+	x = fx10()
 	if b {
 		_ = x[9] // ERROR "nil check"
 	} else {
 		_ = &x[9] // ERROR "nil check"
-	}	
+	}
 	_ = x[9] // ERROR "nil check"
-	
+
 	fx10()
 	_ = x[9] // ERROR "nil check"
-	
+
 	x = fx10()
 	y := fx10()
 	_ = &x[9] // ERROR "nil check"
diff --git a/test/nilptr.go b/test/nilptr.go
index 9631d16..8d674a7 100644
--- a/test/nilptr.go
+++ b/test/nilptr.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/nilptr2.go b/test/nilptr2.go
index 57a5f80..a5c0369 100644
--- a/test/nilptr2.go
+++ b/test/nilptr2.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/nilptr3.go b/test/nilptr3.go
index 6c8aab3..8922729 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -1,10 +1,10 @@
 // errorcheck -0 -d=nil
 // Fails on ppc64x because of incomplete optimization.
 // See issues 9058.
-// Same reason for mips64x.
-// +build !ppc64,!ppc64le,!mips64,!mips64le
+// Same reason for mips64x and s390x.
+// +build !ppc64,!ppc64le,!mips64,!mips64le,!amd64,!s390x
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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.
 
@@ -193,3 +193,24 @@ func f4(x *[10]int) {
 	x = y
 	_ = &x[9] // ERROR "removed repeated nil check"
 }
+
+func m1(m map[int][80]byte) byte {
+	v := m[3] // ERROR "removed nil check"
+	return v[5]
+}
+func m2(m map[int][800]byte) byte {
+	v := m[3] // ERROR "removed nil check"
+	return v[5]
+}
+func m3(m map[int][80]byte) (byte, bool) {
+	v, ok := m[3] // ERROR "removed nil check"
+	return v[5], ok
+}
+func m4(m map[int][800]byte) (byte, bool) {
+	v, ok := m[3] // ERROR "removed nil check"
+	return v[5], ok
+}
+func p1() byte {
+	p := new([100]byte)
+	return p[5] // ERROR "removed nil check"
+}
diff --git a/test/nilptr3_ssa.go b/test/nilptr3_ssa.go
new file mode 100644
index 0000000..0d690eb
--- /dev/null
+++ b/test/nilptr3_ssa.go
@@ -0,0 +1,230 @@
+// errorcheck -0 -d=nil
+// Fails on ppc64x because of incomplete optimization.
+// See issues 9058.
+// +build !ppc64,!ppc64le,amd64
+
+// 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 that nil checks are removed.
+// Optimization is enabled.
+
+package p
+
+type Struct struct {
+	X int
+	Y float64
+}
+
+type BigStruct struct {
+	X int
+	Y float64
+	A [1 << 20]int
+	Z string
+}
+
+type Empty struct {
+}
+
+type Empty1 struct {
+	Empty
+}
+
+var (
+	intp       *int
+	arrayp     *[10]int
+	array0p    *[0]int
+	bigarrayp  *[1 << 26]int
+	structp    *Struct
+	bigstructp *BigStruct
+	emptyp     *Empty
+	empty1p    *Empty1
+)
+
+func f1() {
+	_ = *intp // ERROR "generated nil check"
+
+	// This one should be removed but the block copy needs
+	// to be turned into its own pseudo-op in order to see
+	// the indirect.
+	_ = *arrayp // ERROR "generated nil check"
+
+	// 0-byte indirect doesn't suffice.
+	// we don't registerize globals, so there are no removed.* nil checks.
+	_ = *array0p // ERROR "generated nil check"
+	_ = *array0p // ERROR "removed nil check"
+
+	_ = *intp    // ERROR "removed nil check"
+	_ = *arrayp  // ERROR "removed nil check"
+	_ = *structp // ERROR "generated nil check"
+	_ = *emptyp  // ERROR "generated nil check"
+	_ = *arrayp  // ERROR "removed nil check"
+}
+
+func f2() {
+	var (
+		intp       *int
+		arrayp     *[10]int
+		array0p    *[0]int
+		bigarrayp  *[1 << 20]int
+		structp    *Struct
+		bigstructp *BigStruct
+		emptyp     *Empty
+		empty1p    *Empty1
+	)
+
+	_ = *intp       // ERROR "generated nil check"
+	_ = *arrayp     // ERROR "generated nil check"
+	_ = *array0p    // ERROR "generated nil check"
+	_ = *array0p    // ERROR "removed.* nil check"
+	_ = *intp       // ERROR "removed.* nil check"
+	_ = *arrayp     // ERROR "removed.* nil check"
+	_ = *structp    // ERROR "generated nil check"
+	_ = *emptyp     // ERROR "generated nil check"
+	_ = *arrayp     // ERROR "removed.* nil check"
+	_ = *bigarrayp  // ERROR "generated nil check" ARM removed nil check before indirect!!
+	_ = *bigstructp // ERROR "generated nil check"
+	_ = *empty1p    // ERROR "generated nil check"
+}
+
+func fx10k() *[10000]int
+
+var b bool
+
+func f3(x *[10000]int) {
+	// Using a huge type and huge offsets so the compiler
+	// does not expect the memory hardware to fault.
+	_ = x[9999] // ERROR "generated nil check"
+
+	for {
+		if x[9999] != 0 { // ERROR "removed nil check"
+			break
+		}
+	}
+
+	x = fx10k()
+	_ = x[9999] // ERROR "generated nil check"
+	if b {
+		_ = x[9999] // ERROR "removed.* nil check"
+	} else {
+		_ = x[9999] // ERROR "removed.* nil check"
+	}
+	_ = x[9999] // ERROR "removed nil check"
+
+	x = fx10k()
+	if b {
+		_ = x[9999] // ERROR "generated nil check"
+	} else {
+		_ = x[9999] // ERROR "generated nil check"
+	}
+	_ = x[9999] // ERROR "generated nil check"
+
+	fx10k()
+	// This one is a bit redundant, if we figured out that
+	// x wasn't going to change across the function call.
+	// But it's a little complex to do and in practice doesn't
+	// matter enough.
+	_ = x[9999] // ERROR "removed nil check"
+}
+
+func f3a() {
+	x := fx10k()
+	y := fx10k()
+	z := fx10k()
+	_ = &x[9] // ERROR "generated nil check"
+	y = z
+	_ = &x[9] // ERROR "removed.* nil check"
+	x = y
+	_ = &x[9] // ERROR "generated nil check"
+}
+
+func f3b() {
+	x := fx10k()
+	y := fx10k()
+	_ = &x[9] // ERROR "generated nil check"
+	y = x
+	_ = &x[9] // ERROR "removed.* nil check"
+	x = y
+	_ = &x[9] // ERROR "removed.* nil check"
+}
+
+func fx10() *[10]int
+
+func f4(x *[10]int) {
+	// Most of these have no checks because a real memory reference follows,
+	// and the offset is small enough that if x is nil, the address will still be
+	// in the first unmapped page of memory.
+
+	_ = x[9] // ERROR "removed nil check"
+
+	for {
+		if x[9] != 0 { // ERROR "removed nil check"
+			break
+		}
+	}
+
+	x = fx10()
+	_ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
+	if b {
+		_ = x[9] // ERROR "removed nil check"
+	} else {
+		_ = x[9] // ERROR "removed nil check"
+	}
+	_ = x[9] // ERROR "removed nil check"
+
+	x = fx10()
+	if b {
+		_ = x[9] // ERROR "generated nil check"  // bug would like to remove before indirect
+	} else {
+		_ = &x[9] // ERROR "generated nil check"
+	}
+	_ = x[9] // ERROR "generated nil check"  // bug would like to remove before indirect
+
+	fx10()
+	_ = x[9] // ERROR "removed nil check"
+
+	x = fx10()
+	y := fx10()
+	_ = &x[9] // ERROR "generated nil check"
+	y = x
+	_ = &x[9] // ERROR "removed[a-z ]* nil check"
+	x = y
+	_ = &x[9] // ERROR "removed[a-z ]* nil check"
+}
+
+func f5(p *float32, q *float64, r *float32, s *float64) float64 {
+	x := float64(*p) // ERROR "removed nil check"
+	y := *q          // ERROR "removed nil check"
+	*r = 7           // ERROR "removed nil check"
+	*s = 9           // ERROR "removed nil check"
+	return x + y
+}
+
+type T [29]byte
+
+func f6(p, q *T) {
+	x := *p // ERROR "removed nil check"
+	*q = x  // ERROR "removed nil check"
+}
+
+func m1(m map[int][80]byte) byte {
+	v := m[3] // ERROR "removed nil check"
+	return v[5]
+}
+func m2(m map[int][800]byte) byte {
+	v := m[3] // ERROR "removed nil check"
+	return v[5]
+}
+func m3(m map[int][80]byte) (byte, bool) {
+	v, ok := m[3] // ERROR "removed nil check"
+	return v[5], ok
+}
+func m4(m map[int][800]byte) (byte, bool) {
+	v, ok := m[3] // ERROR "removed nil check"
+	return v[5], ok
+}
+func p1() byte {
+	p := new([100]byte)
+	return p[5] // ERROR "removed nil check"
+}
diff --git a/test/nilptr4.go b/test/nilptr4.go
index 3dd7d4e..c75ce10 100644
--- a/test/nilptr4.go
+++ b/test/nilptr4.go
@@ -1,6 +1,6 @@
 // build
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/nosplit.go b/test/nosplit.go
index 3c4ae10..a58a645 100644
--- a/test/nosplit.go
+++ b/test/nosplit.go
@@ -1,7 +1,7 @@
 // +build !nacl
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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.
 
@@ -275,6 +275,9 @@ TestCases:
 		case "amd64":
 			ptrSize = 8
 			fmt.Fprintf(&buf, "#define REGISTER AX\n")
+		case "s390x":
+			ptrSize = 8
+			fmt.Fprintf(&buf, "#define REGISTER R10\n")
 		default:
 			fmt.Fprintf(&buf, "#define REGISTER AX\n")
 		}
@@ -302,9 +305,10 @@ TestCases:
 				// Instead of rewriting the test cases above, adjust
 				// the first stack frame to use up the extra bytes.
 				if i == 0 {
-					size += 592 - 128
+					size += (720 - 128) - 128
 					// Noopt builds have a larger stackguard.
-					// See ../cmd/dist/buildruntime.go:stackGuardMultiplier
+					// See ../src/cmd/dist/buildruntime.go:stackGuardMultiplier
+					// This increase is included in obj.StackGuard
 					for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
 						if s == "-N" {
 							size += 720
diff --git a/test/opt_branchlikely.go b/test/opt_branchlikely.go
new file mode 100644
index 0000000..5781253
--- /dev/null
+++ b/test/opt_branchlikely.go
@@ -0,0 +1,85 @@
+// +build amd64
+// errorcheck -0 -d=ssa/likelyadjust/debug=1
+
+// Copyright 2016 The Go 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 branches have some prediction properties.
+package foo
+
+func f(x, y, z int) int {
+	a := 0
+	for i := 0; i < x; i++ { // ERROR "Branch prediction rule stay in loop"
+		for j := 0; j < y; j++ { // ERROR "Branch prediction rule stay in loop"
+			a += j
+		}
+		for k := 0; k < z; k++ { // ERROR "Branch prediction rule stay in loop"
+			a -= x + y + z
+		}
+	}
+	return a
+}
+
+func g(x, y, z int) int {
+	a := 0
+	if y == 0 { // ERROR "Branch prediction rule default < call"
+		y = g(y, z, x)
+	} else {
+		y++
+	}
+	if y == x { // ERROR "Branch prediction rule default < call"
+		y = g(y, z, x)
+	} else {
+	}
+	if y == 2 { // ERROR "Branch prediction rule default < call"
+		z++
+	} else {
+		y = g(z, x, y)
+	}
+	if y+z == 3 { // ERROR "Branch prediction rule call < exit"
+		println("ha ha")
+	} else {
+		panic("help help help")
+	}
+	if x != 0 { // ERROR "Branch prediction rule default < ret"
+		for i := 0; i < x; i++ { // ERROR "Branch prediction rule stay in loop"
+			if x == 4 { // ERROR "Branch prediction rule stay in loop"
+				return a
+			}
+			for j := 0; j < y; j++ { // ERROR "Branch prediction rule stay in loop"
+				for k := 0; k < z; k++ { // ERROR "Branch prediction rule stay in loop"
+					a -= j * i
+				}
+				a += j
+			}
+		}
+	}
+	return a
+}
+
+func h(x, y, z int) int {
+	a := 0
+	for i := 0; i < x; i++ { // ERROR "Branch prediction rule stay in loop"
+		for j := 0; j < y; j++ { // ERROR "Branch prediction rule stay in loop"
+			a += j
+			if i == j { // ERROR "Branch prediction rule stay in loop"
+				break
+			}
+			a *= j
+		}
+		for k := 0; k < z; k++ { // ERROR "Branch prediction rule stay in loop"
+			a -= k
+			if i == k {
+				continue
+			}
+			a *= k
+		}
+	}
+	if a > 0 { // ERROR "Branch prediction rule default < call"
+		a = g(x, y, z)
+	} else {
+		a = -a
+	}
+	return a
+}
diff --git a/test/phiopt.go b/test/phiopt.go
new file mode 100644
index 0000000..21dd131
--- /dev/null
+++ b/test/phiopt.go
@@ -0,0 +1,108 @@
+// +build amd64
+// errorcheck -0 -d=ssa/phiopt/debug=3
+
+// Copyright 2016 The Go Authors. 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
+
+//go:noinline
+func f0(a bool) bool {
+	x := false
+	if a {
+		x = true
+	} else {
+		x = false
+	}
+	return x // ERROR "converted OpPhi to Copy$"
+}
+
+//go:noinline
+func f1(a bool) bool {
+	x := false
+	if a {
+		x = false
+	} else {
+		x = true
+	}
+	return x // ERROR "converted OpPhi to Not$"
+}
+
+//go:noinline
+func f2(a, b int) bool {
+	x := true
+	if a == b {
+		x = false
+	}
+	return x // ERROR "converted OpPhi to Not$"
+}
+
+//go:noinline
+func f3(a, b int) bool {
+	x := false
+	if a == b {
+		x = true
+	}
+	return x // ERROR "converted OpPhi to Copy$"
+}
+
+//go:noinline
+func f4(a, b bool) bool {
+	return a || b // ERROR "converted OpPhi to OrB$"
+}
+
+//go:noinline
+func f5or(a int, b bool) bool {
+	var x bool
+	if a == 0 {
+		x = true
+	} else {
+		x = b
+	}
+	return x // ERROR "converted OpPhi to OrB$"
+}
+
+//go:noinline
+func f5and(a int, b bool) bool {
+	var x bool
+	if a == 0 {
+		x = b
+	} else {
+		x = false
+	}
+	return x // ERROR "converted OpPhi to AndB$"
+}
+
+//go:noinline
+func f6or(a int, b bool) bool {
+	x := b
+	if a == 0 {
+		// f6or has side effects so the OpPhi should not be converted.
+		x = f6or(a, b)
+	}
+	return x
+}
+
+//go:noinline
+func f6and(a int, b bool) bool {
+	x := b
+	if a == 0 {
+		// f6and has side effects so the OpPhi should not be converted.
+		x = f6and(a, b)
+	}
+	return x
+}
+
+//go:noinline
+func f7or(a bool, b bool) bool {
+	return a || b // ERROR "converted OpPhi to OrB$"
+}
+
+//go:noinline
+func f7and(a bool, b bool) bool {
+	return a && b // ERROR "converted OpPhi to AndB$"
+}
+
+func main() {
+}
diff --git a/test/prove.go b/test/prove.go
new file mode 100644
index 0000000..8bcc9ae
--- /dev/null
+++ b/test/prove.go
@@ -0,0 +1,450 @@
+// +build amd64
+// errorcheck -0 -d=ssa/prove/debug=3
+
+// Copyright 2016 The Go Authors. 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 "math"
+
+func f0(a []int) int {
+	a[0] = 1
+	a[0] = 1 // ERROR "Proved boolean IsInBounds$"
+	a[6] = 1
+	a[6] = 1 // ERROR "Proved boolean IsInBounds$"
+	a[5] = 1 // ERROR "Proved IsInBounds$"
+	a[5] = 1 // ERROR "Proved boolean IsInBounds$"
+	return 13
+}
+
+func f1(a []int) int {
+	if len(a) <= 5 {
+		return 18
+	}
+	a[0] = 1 // ERROR "Proved non-negative bounds IsInBounds$"
+	a[0] = 1 // ERROR "Proved boolean IsInBounds$"
+	a[6] = 1
+	a[6] = 1 // ERROR "Proved boolean IsInBounds$"
+	a[5] = 1 // ERROR "Proved IsInBounds$"
+	a[5] = 1 // ERROR "Proved boolean IsInBounds$"
+	return 26
+}
+
+func f1b(a []int, i int, j uint) int {
+	if i >= 0 && i < len(a) {
+		return a[i] // ERROR "Proved non-negative bounds IsInBounds$"
+	}
+	if i >= 10 && i < len(a) {
+		return a[i] // ERROR "Proved non-negative bounds IsInBounds$"
+	}
+	if i >= 10 && i < len(a) {
+		return a[i] // ERROR "Proved non-negative bounds IsInBounds$"
+	}
+	if i >= 10 && i < len(a) { // todo: handle this case
+		return a[i-10]
+	}
+	if j < uint(len(a)) {
+		return a[j] // ERROR "Proved IsInBounds$"
+	}
+	return 0
+}
+
+func f1c(a []int, i int64) int {
+	c := uint64(math.MaxInt64 + 10) // overflows int
+	d := int64(c)
+	if i >= d && i < int64(len(a)) {
+		// d overflows, should not be handled.
+		return a[i]
+	}
+	return 0
+}
+
+func f2(a []int) int {
+	for i := range a {
+		a[i+1] = i
+		a[i+1] = i // ERROR "Proved boolean IsInBounds$"
+	}
+	return 34
+}
+
+func f3(a []uint) int {
+	for i := uint(0); i < uint(len(a)); i++ {
+		a[i] = i // ERROR "Proved IsInBounds$"
+	}
+	return 41
+}
+
+func f4a(a, b, c int) int {
+	if a < b {
+		if a == b { // ERROR "Disproved Eq64$"
+			return 47
+		}
+		if a > b { // ERROR "Disproved Greater64$"
+			return 50
+		}
+		if a < b { // ERROR "Proved boolean Less64$"
+			return 53
+		}
+		if a == b { // ERROR "Disproved boolean Eq64$"
+			return 56
+		}
+		if a > b { // ERROR "Disproved boolean Greater64$"
+			return 59
+		}
+		return 61
+	}
+	return 63
+}
+
+func f4b(a, b, c int) int {
+	if a <= b {
+		if a >= b {
+			if a == b { // ERROR "Proved Eq64$"
+				return 70
+			}
+			return 75
+		}
+		return 77
+	}
+	return 79
+}
+
+func f4c(a, b, c int) int {
+	if a <= b {
+		if a >= b {
+			if a != b { // ERROR "Disproved Neq64$"
+				return 73
+			}
+			return 75
+		}
+		return 77
+	}
+	return 79
+}
+
+func f4d(a, b, c int) int {
+	if a < b {
+		if a < c {
+			if a < b { // ERROR "Proved boolean Less64$"
+				if a < c { // ERROR "Proved boolean Less64$"
+					return 87
+				}
+				return 89
+			}
+			return 91
+		}
+		return 93
+	}
+	return 95
+}
+
+func f4e(a, b, c int) int {
+	if a < b {
+		if b > a { // ERROR "Proved Greater64$"
+			return 101
+		}
+		return 103
+	}
+	return 105
+}
+
+func f4f(a, b, c int) int {
+	if a <= b {
+		if b > a {
+			if b == a { // ERROR "Disproved Eq64$"
+				return 112
+			}
+			return 114
+		}
+		if b >= a { // ERROR "Proved Geq64$"
+			if b == a { // ERROR "Proved Eq64$"
+				return 118
+			}
+			return 120
+		}
+		return 122
+	}
+	return 124
+}
+
+func f5(a, b uint) int {
+	if a == b {
+		if a <= b { // ERROR "Proved Leq64U$"
+			return 130
+		}
+		return 132
+	}
+	return 134
+}
+
+// These comparisons are compile time constants.
+func f6a(a uint8) int {
+	if a < a { // ERROR "Disproved Less8U$"
+		return 140
+	}
+	return 151
+}
+
+func f6b(a uint8) int {
+	if a < a { // ERROR "Disproved Less8U$"
+		return 140
+	}
+	return 151
+}
+
+func f6x(a uint8) int {
+	if a > a { // ERROR "Disproved Greater8U$"
+		return 143
+	}
+	return 151
+}
+
+func f6d(a uint8) int {
+	if a <= a { // ERROR "Proved Leq8U$"
+		return 146
+	}
+	return 151
+}
+
+func f6e(a uint8) int {
+	if a >= a { // ERROR "Proved Geq8U$"
+		return 149
+	}
+	return 151
+}
+
+func f7(a []int, b int) int {
+	if b < len(a) {
+		a[b] = 3
+		if b < len(a) { // ERROR "Proved boolean Less64$"
+			a[b] = 5 // ERROR "Proved boolean IsInBounds$"
+		}
+	}
+	return 161
+}
+
+func f8(a, b uint) int {
+	if a == b {
+		return 166
+	}
+	if a > b {
+		return 169
+	}
+	if a < b { // ERROR "Proved Less64U$"
+		return 172
+	}
+	return 174
+}
+
+func f9(a, b bool) int {
+	if a {
+		return 1
+	}
+	if a || b { // ERROR "Disproved boolean Arg$"
+		return 2
+	}
+	return 3
+}
+
+func f10(a string) int {
+	n := len(a)
+	if a[:n>>1] == "aaa" {
+		return 0
+	}
+	return 1
+}
+
+func f11a(a []int, i int) {
+	useInt(a[i])
+	useInt(a[i]) // ERROR "Proved boolean IsInBounds$"
+}
+
+func f11b(a []int, i int) {
+	useSlice(a[i:])
+	useSlice(a[i:]) // ERROR "Proved boolean IsSliceInBounds$"
+}
+
+func f11c(a []int, i int) {
+	useSlice(a[:i])
+	useSlice(a[:i]) // ERROR "Proved boolean IsSliceInBounds$"
+}
+
+func f11d(a []int, i int) {
+	useInt(a[2*i+7])
+	useInt(a[2*i+7])
+}
+
+func f12(a []int, b int) {
+	useSlice(a[:b])
+}
+
+func f13a(a, b, c int, x bool) int {
+	if a > 12 {
+		if x {
+			if a < 12 { // ERROR "Disproved Less64$"
+				return 1
+			}
+		}
+		if x {
+			if a <= 12 { // ERROR "Disproved Leq64$"
+				return 2
+			}
+		}
+		if x {
+			if a == 12 { // ERROR "Disproved Eq64$"
+				return 3
+			}
+		}
+		if x {
+			if a >= 12 { // ERROR "Proved Geq64$"
+				return 4
+			}
+		}
+		if x {
+			if a > 12 { // ERROR "Proved boolean Greater64$"
+				return 5
+			}
+		}
+		return 6
+	}
+	return 0
+}
+
+func f13b(a int, x bool) int {
+	if a == -9 {
+		if x {
+			if a < -9 { // ERROR "Disproved Less64$"
+				return 7
+			}
+		}
+		if x {
+			if a <= -9 { // ERROR "Proved Leq64$"
+				return 8
+			}
+		}
+		if x {
+			if a == -9 { // ERROR "Proved boolean Eq64$"
+				return 9
+			}
+		}
+		if x {
+			if a >= -9 { // ERROR "Proved Geq64$"
+				return 10
+			}
+		}
+		if x {
+			if a > -9 { // ERROR "Disproved Greater64$"
+				return 11
+			}
+		}
+		return 12
+	}
+	return 0
+}
+
+func f13c(a int, x bool) int {
+	if a < 90 {
+		if x {
+			if a < 90 { // ERROR "Proved boolean Less64$"
+				return 13
+			}
+		}
+		if x {
+			if a <= 90 { // ERROR "Proved Leq64$"
+				return 14
+			}
+		}
+		if x {
+			if a == 90 { // ERROR "Disproved Eq64$"
+				return 15
+			}
+		}
+		if x {
+			if a >= 90 { // ERROR "Disproved Geq64$"
+				return 16
+			}
+		}
+		if x {
+			if a > 90 { // ERROR "Disproved Greater64$"
+				return 17
+			}
+		}
+		return 18
+	}
+	return 0
+}
+
+func f13d(a int) int {
+	if a < 5 {
+		if a < 9 { // ERROR "Proved Less64$"
+			return 1
+		}
+	}
+	return 0
+}
+
+func f13e(a int) int {
+	if a > 9 {
+		if a > 5 { // ERROR "Proved Greater64$"
+			return 1
+		}
+	}
+	return 0
+}
+
+func f13f(a int64) int64 {
+	if a > math.MaxInt64 {
+		// Unreachable, but prove doesn't know that.
+		if a == 0 {
+			return 1
+		}
+	}
+	return 0
+}
+
+func f13g(a int) int {
+	if a < 3 {
+		return 5
+	}
+	if a > 3 {
+		return 6
+	}
+	if a == 3 { // ERROR "Proved Eq64$"
+		return 7
+	}
+	return 8
+}
+
+func f13h(a int) int {
+	if a < 3 {
+		if a > 1 {
+			if a == 2 { // ERROR "Proved Eq64$"
+				return 5
+			}
+		}
+	}
+	return 0
+}
+
+func f13i(a uint) int {
+	if a == 0 {
+		return 1
+	}
+	if a > 0 { // ERROR "Proved Greater64U$"
+		return 2
+	}
+	return 3
+}
+
+//go:noinline
+func useInt(a int) {
+}
+
+//go:noinline
+func useSlice(a []int) {
+}
+
+func main() {
+}
diff --git a/test/recover.go b/test/recover.go
index f92c15c..e4187c0 100644
--- a/test/recover.go
+++ b/test/recover.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/recover1.go b/test/recover1.go
index b763a10..c14a607 100644
--- a/test/recover1.go
+++ b/test/recover1.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/recover2.go b/test/recover2.go
index 946d05a..cf4657a 100644
--- a/test/recover2.go
+++ b/test/recover2.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/recover3.go b/test/recover3.go
index e17bfb3..1b26cb3 100644
--- a/test/recover3.go
+++ b/test/recover3.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/recover4.go b/test/recover4.go
index 4c50260..da5117c 100644
--- a/test/recover4.go
+++ b/test/recover4.go
@@ -1,7 +1,7 @@
 // +build linux darwin
 // run
 
-// Copyright 2015 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.
 
diff --git a/test/reflectmethod1.go b/test/reflectmethod1.go
new file mode 100644
index 0000000..973bf15
--- /dev/null
+++ b/test/reflectmethod1.go
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2016 The Go 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 linker can prune methods that are not directly called or
+// assigned to interfaces, but only if reflect.Type.Method is
+// never used. Test it here.
+
+package main
+
+import "reflect"
+
+var called = false
+
+type M int
+
+func (m M) UniqueMethodName() {
+	called = true
+}
+
+var v M
+
+func main() {
+	reflect.TypeOf(v).Method(0).Func.Interface().(func(M))(v)
+	if !called {
+		panic("UniqueMethodName not called")
+	}
+}
diff --git a/test/reflectmethod2.go b/test/reflectmethod2.go
new file mode 100644
index 0000000..9ee1c24
--- /dev/null
+++ b/test/reflectmethod2.go
@@ -0,0 +1,36 @@
+// run
+
+// Copyright 2016 The Go 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 linker can prune methods that are not directly called or
+// assigned to interfaces, but only if reflect.Type.MethodByName is
+// never used. Test it here.
+
+package main
+
+import reflect1 "reflect"
+
+var called = false
+
+type M int
+
+func (m M) UniqueMethodName() {
+	called = true
+}
+
+var v M
+
+type MyType interface {
+	MethodByName(string) (reflect1.Method, bool)
+}
+
+func main() {
+	var t MyType = reflect1.TypeOf(v)
+	m, _ := t.MethodByName("UniqueMethodName")
+	m.Func.Interface().(func(M))(v)
+	if !called {
+		panic("UniqueMethodName not called")
+	}
+}
diff --git a/test/reflectmethod3.go b/test/reflectmethod3.go
new file mode 100644
index 0000000..b423a59
--- /dev/null
+++ b/test/reflectmethod3.go
@@ -0,0 +1,35 @@
+// run
+
+// Copyright 2016 The Go 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 linker can prune methods that are not directly called or
+// assigned to interfaces, but only if reflect.Type.Method is
+// never used. Test it here.
+
+package main
+
+import "reflect"
+
+var called = false
+
+type M int
+
+func (m M) UniqueMethodName() {
+	called = true
+}
+
+var v M
+
+type MyType interface {
+	Method(int) reflect.Method
+}
+
+func main() {
+	var t MyType = reflect.TypeOf(v)
+	t.Method(0).Func.Interface().(func(M))(v)
+	if !called {
+		panic("UniqueMethodName not called")
+	}
+}
diff --git a/test/reflectmethod4.go b/test/reflectmethod4.go
new file mode 100644
index 0000000..037b3da
--- /dev/null
+++ b/test/reflectmethod4.go
@@ -0,0 +1,30 @@
+// run
+
+// Copyright 2016 The Go 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 linker can prune methods that are not directly called or
+// assigned to interfaces, but only if reflect.Value.Method is
+// never used. Test it here.
+
+package main
+
+import "reflect"
+
+var called = false
+
+type M int
+
+func (m M) UniqueMethodName() {
+	called = true
+}
+
+var v M
+
+func main() {
+	reflect.ValueOf(v).Method(0).Interface().(func())()
+	if !called {
+		panic("UniqueMethodName not called")
+	}
+}
diff --git a/test/rename.go b/test/rename.go
index dc43417..83f184b 100644
--- a/test/rename.go
+++ b/test/rename.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/rename1.go b/test/rename1.go
index 53db68d..a71e5b2 100644
--- a/test/rename1.go
+++ b/test/rename1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/reorder.go b/test/reorder.go
index 8fd623c..fc44be9 100644
--- a/test/reorder.go
+++ b/test/reorder.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/reorder2.go b/test/reorder2.go
index 3e87998..07f1b15 100644
--- a/test/reorder2.go
+++ b/test/reorder2.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/return.go b/test/return.go
index 482f22b..95f94b9 100644
--- a/test/return.go
+++ b/test/return.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/rotate.go b/test/rotate.go
index 1d71497..9dc4b1e 100644
--- a/test/rotate.go
+++ b/test/rotate.go
@@ -2,7 +2,7 @@
 
 // NOTE: the actual tests to run are rotate[0123].go
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/rotate0.go b/test/rotate0.go
index 400b225..09dd900 100644
--- a/test/rotate0.go
+++ b/test/rotate0.go
@@ -1,6 +1,6 @@
 // runoutput ./rotate.go
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/rotate1.go b/test/rotate1.go
index 98b0b1c..19757ec 100644
--- a/test/rotate1.go
+++ b/test/rotate1.go
@@ -1,6 +1,6 @@
 // runoutput ./rotate.go
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/rotate2.go b/test/rotate2.go
index c50f8ce..a55305a 100644
--- a/test/rotate2.go
+++ b/test/rotate2.go
@@ -1,6 +1,6 @@
 // runoutput ./rotate.go
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/rotate3.go b/test/rotate3.go
index 73d47d8..edd5d3a 100644
--- a/test/rotate3.go
+++ b/test/rotate3.go
@@ -1,6 +1,6 @@
 // runoutput ./rotate.go
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/run.go b/test/run.go
index 52230ef..a1ab9d5 100644
--- a/test/run.go
+++ b/test/run.go
@@ -1,6 +1,6 @@
 // skip
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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.
 
@@ -34,9 +34,11 @@ import (
 
 var (
 	verbose        = flag.Bool("v", false, "verbose. if set, parallelism is set to 1.")
+	keep           = flag.Bool("k", false, "keep. keep temporary directory.")
 	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")
+	runSkips       = flag.Bool("run_skips", false, "run skipped tests (ignore skip and build tags)")
 	linkshared     = flag.Bool("linkshared", false, "")
 	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")
@@ -120,9 +122,9 @@ func main() {
 		<-test.donec
 		status := "ok  "
 		errStr := ""
-		if _, isSkip := test.err.(skipError); isSkip {
+		if e, isSkip := test.err.(skipError); isSkip {
 			test.err = nil
-			errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr
+			errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + string(e)
 			status = "FAIL"
 		}
 		if test.err != nil {
@@ -200,8 +202,9 @@ func compileFile(runcmd runCmd, longname string) (out []byte, err error) {
 	return runcmd(cmd...)
 }
 
-func compileInDir(runcmd runCmd, dir string, names ...string) (out []byte, err error) {
+func compileInDir(runcmd runCmd, dir string, flags []string, names ...string) (out []byte, err error) {
 	cmd := []string{"go", "tool", "compile", "-e", "-D", ".", "-I", "."}
+	cmd = append(cmd, flags...)
 	if *linkshared {
 		cmd = append(cmd, "-dynlink", "-installsuffix=dynlink")
 	}
@@ -303,7 +306,9 @@ func goDirFiles(longdir string) (filter []os.FileInfo, err error) {
 
 var packageRE = regexp.MustCompile(`(?m)^package (\w+)`)
 
-func goDirPackages(longdir string) ([][]string, error) {
+// If singlefilepkgs is set, each file is considered a separate package
+// even if the package names are the same.
+func goDirPackages(longdir string, singlefilepkgs bool) ([][]string, error) {
 	files, err := goDirFiles(longdir)
 	if err != nil {
 		return nil, err
@@ -321,7 +326,7 @@ func goDirPackages(longdir string) ([][]string, error) {
 			return nil, fmt.Errorf("cannot find package name in %s", name)
 		}
 		i, ok := m[pkgname[1]]
-		if !ok {
+		if singlefilepkgs || !ok {
 			i = len(pkgs)
 			pkgs = append(pkgs, nil)
 			m[pkgname[1]] = i
@@ -339,6 +344,9 @@ 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 *runSkips {
+		return true, ""
+	}
 	for _, line := range strings.Split(src, "\n") {
 		line = strings.TrimSpace(line)
 		if strings.HasPrefix(line, "//") {
@@ -458,12 +466,14 @@ func (t *test) run() {
 
 	var args, flags []string
 	wantError := false
+	singlefilepkgs := false
 	f := strings.Fields(action)
 	if len(f) > 0 {
 		action = f[0]
 		args = f[1:]
 	}
 
+	// TODO: Clean up/simplify this switch statement.
 	switch action {
 	case "rundircmpout":
 		action = "rundir"
@@ -473,18 +483,16 @@ func (t *test) run() {
 		fallthrough
 	case "compile", "compiledir", "build", "run", "runoutput", "rundir":
 		t.action = action
+	case "errorcheckandrundir":
+		wantError = false // should be no error if also will run
+		fallthrough
 	case "errorcheck", "errorcheckdir", "errorcheckoutput":
 		t.action = action
 		wantError = true
-		for len(args) > 0 && strings.HasPrefix(args[0], "-") {
-			if args[0] == "-0" {
-				wantError = false
-			} else {
-				flags = append(flags, args[0])
-			}
-			args = args[1:]
-		}
 	case "skip":
+		if *runSkips {
+			break
+		}
 		t.action = "skip"
 		return
 	default:
@@ -493,8 +501,23 @@ func (t *test) run() {
 		return
 	}
 
+	// collect flags
+	for len(args) > 0 && strings.HasPrefix(args[0], "-") {
+		switch args[0] {
+		case "-0":
+			wantError = false
+		case "-s":
+			singlefilepkgs = true
+		default:
+			flags = append(flags, args[0])
+		}
+		args = args[1:]
+	}
+
 	t.makeTempDir()
-	defer os.RemoveAll(t.tempDir)
+	if !*keep {
+		defer os.RemoveAll(t.tempDir)
+	}
 
 	err = ioutil.WriteFile(filepath.Join(t.tempDir, t.gofile), srcBytes, 0644)
 	check(err)
@@ -508,6 +531,7 @@ func (t *test) run() {
 	}
 
 	useTmp := true
+	ssaMain := false
 	runcmd := func(args ...string) ([]byte, error) {
 		cmd := exec.Command(args[0], args[1:]...)
 		var buf bytes.Buffer
@@ -516,6 +540,11 @@ func (t *test) run() {
 		if useTmp {
 			cmd.Dir = t.tempDir
 			cmd.Env = envForDir(cmd.Dir)
+		} else {
+			cmd.Env = os.Environ()
+		}
+		if ssaMain && os.Getenv("GOARCH") == "amd64" {
+			cmd.Env = append(cmd.Env, "GOSSAPKG=main")
 		}
 		err := cmd.Run()
 		if err != nil {
@@ -558,29 +587,29 @@ func (t *test) run() {
 	case "compiledir":
 		// Compile all files in the directory in lexicographic order.
 		longdir := filepath.Join(cwd, t.goDirName())
-		pkgs, err := goDirPackages(longdir)
+		pkgs, err := goDirPackages(longdir, singlefilepkgs)
 		if err != nil {
 			t.err = err
 			return
 		}
 		for _, gofiles := range pkgs {
-			_, t.err = compileInDir(runcmd, longdir, gofiles...)
+			_, t.err = compileInDir(runcmd, longdir, flags, gofiles...)
 			if t.err != nil {
 				return
 			}
 		}
 
-	case "errorcheckdir":
+	case "errorcheckdir", "errorcheckandrundir":
 		// errorcheck all files in lexicographic order
 		// useful for finding importing errors
 		longdir := filepath.Join(cwd, t.goDirName())
-		pkgs, err := goDirPackages(longdir)
+		pkgs, err := goDirPackages(longdir, singlefilepkgs)
 		if err != nil {
 			t.err = err
 			return
 		}
 		for i, gofiles := range pkgs {
-			out, err := compileInDir(runcmd, longdir, gofiles...)
+			out, err := compileInDir(runcmd, longdir, flags, gofiles...)
 			if i == len(pkgs)-1 {
 				if wantError && err == nil {
 					t.err = fmt.Errorf("compilation succeeded unexpectedly\n%s", out)
@@ -602,18 +631,22 @@ func (t *test) run() {
 				break
 			}
 		}
+		if action == "errorcheckdir" {
+			return
+		}
+		fallthrough
 
 	case "rundir":
 		// Compile all files in the directory in lexicographic order.
 		// then link as if the last file is the main package and run it
 		longdir := filepath.Join(cwd, t.goDirName())
-		pkgs, err := goDirPackages(longdir)
+		pkgs, err := goDirPackages(longdir, singlefilepkgs)
 		if err != nil {
 			t.err = err
 			return
 		}
 		for i, gofiles := range pkgs {
-			_, err := compileInDir(runcmd, longdir, gofiles...)
+			_, err := compileInDir(runcmd, longdir, flags, gofiles...)
 			if err != nil {
 				t.err = err
 				return
@@ -647,6 +680,7 @@ func (t *test) run() {
 
 	case "run":
 		useTmp = false
+		ssaMain = true
 		cmd := []string{"go", "run"}
 		if *linkshared {
 			cmd = append(cmd, "-linkshared")
@@ -682,6 +716,7 @@ func (t *test) run() {
 			t.err = fmt.Errorf("write tempfile:%s", err)
 			return
 		}
+		ssaMain = true
 		cmd = []string{"go", "run"}
 		if *linkshared {
 			cmd = append(cmd, "-linkshared")
@@ -759,6 +794,9 @@ func (t *test) makeTempDir() {
 	var err error
 	t.tempDir, err = ioutil.TempDir("", "")
 	check(err)
+	if *keep {
+		log.Printf("Temporary directory is %s", t.tempDir)
+	}
 }
 
 func (t *test) expectedOutput() string {
@@ -780,7 +818,7 @@ func splitOutput(out string) []string {
 		}
 		if strings.HasPrefix(line, "\t") {
 			res[len(res)-1] += "\n" + line
-		} else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "<autogenerated>") {
+		} else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "<autogenerated>") || strings.HasPrefix(line, "#") {
 			continue
 		} else if strings.TrimSpace(line) != "" {
 			res = append(res, line)
@@ -855,7 +893,8 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
 	return errors.New(buf.String())
 }
 
-func (t *test) updateErrors(out string, file string) {
+func (t *test) updateErrors(out, file string) {
+	base := path.Base(file)
 	// Read in source file.
 	src, err := ioutil.ReadFile(file)
 	if err != nil {
@@ -889,6 +928,8 @@ func (t *test) updateErrors(out string, file string) {
 			continue
 		}
 		msg := errStr[colon2+2:]
+		msg = strings.Replace(msg, file, base, -1) // normalize file mentions in error itself
+		msg = strings.TrimLeft(msg, " \t")
 		for _, r := range []string{`\`, `*`, `+`, `[`, `]`, `(`, `)`} {
 			msg = strings.Replace(msg, r, `\`+r, -1)
 		}
diff --git a/test/rune.go b/test/rune.go
index c013c47..73a5aa2 100644
--- a/test/rune.go
+++ b/test/rune.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/runtime.go b/test/runtime.go
index 89f59e3..bccc9b5 100644
--- a/test/runtime.go
+++ b/test/runtime.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2009 The Go Authors.  All rights reserved.
+// 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/test/shift1.go b/test/shift1.go
index 04f5321..aeefbc4 100644
--- a/test/shift1.go
+++ b/test/shift1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/shift2.go b/test/shift2.go
index 80e6bbc..adbfb77 100644
--- a/test/shift2.go
+++ b/test/shift2.go
@@ -1,6 +1,6 @@
 // compile
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/sinit.go b/test/sinit.go
index 188a530..c4d0edf 100644
--- a/test/sinit.go
+++ b/test/sinit.go
@@ -1,6 +1,6 @@
 // skip
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/sizeof.go b/test/sizeof.go
index c3db1e5..3e2689f 100644
--- a/test/sizeof.go
+++ b/test/sizeof.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/slice3.go b/test/slice3.go
index 857eaf3..8a184d1 100644
--- a/test/slice3.go
+++ b/test/slice3.go
@@ -1,6 +1,6 @@
 // runoutput
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/slice3err.go b/test/slice3err.go
index 83fb39b..1309fdd 100644
--- a/test/slice3err.go
+++ b/test/slice3err.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/slicecap.go b/test/slicecap.go
index dceb7e2..f71a3b0 100644
--- a/test/slicecap.go
+++ b/test/slicecap.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2014 The Go Authors.  All rights reserved.
+// 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/test/sliceopt.go b/test/sliceopt.go
index c9d089f..a830ab7 100644
--- a/test/sliceopt.go
+++ b/test/sliceopt.go
@@ -1,6 +1,7 @@
+// +build !amd64
 // errorcheck -0 -d=append,slice
 
-// Copyright 2015 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.
 
diff --git a/test/strength.go b/test/strength.go
new file mode 100644
index 0000000..94d589c
--- /dev/null
+++ b/test/strength.go
@@ -0,0 +1,45 @@
+// runoutput
+
+// Copyright 2016 The Go 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 test of strength reduction for multiplications
+// with contstants. Especially useful for amd64/386.
+
+package main
+
+import "fmt"
+
+func testMul(fact, bits int) string {
+	n := fmt.Sprintf("testMul_%d_%d", fact, bits)
+	fmt.Printf("func %s(s int%d) {\n", n, bits)
+
+	want := 0
+	for i := 0; i < 200; i++ {
+		fmt.Printf(`	if want, got := int%d(%d), s*%d; want != got {
+		failed = true
+		fmt.Printf("got %d * %%d == %%d, wanted %d\n",  s, got)
+	}
+`, bits, want, i, i, want)
+		want += fact
+	}
+
+	fmt.Printf("}\n")
+	return fmt.Sprintf("%s(%d)", n, fact)
+}
+
+func main() {
+	fmt.Printf("package main\n")
+	fmt.Printf("import \"fmt\"\n")
+	fmt.Printf("var failed = false\n")
+
+	f1 := testMul(17, 32)
+	f2 := testMul(131, 64)
+
+	fmt.Printf("func main() {\n")
+	fmt.Println(f1)
+	fmt.Println(f2)
+	fmt.Printf("if failed {\n	panic(\"multiplication failed\")\n}\n")
+	fmt.Printf("}\n")
+}
diff --git a/test/stress/maps.go b/test/stress/maps.go
index fc5ab05..8ada23a 100644
--- a/test/stress/maps.go
+++ b/test/stress/maps.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/stress/parsego.go b/test/stress/parsego.go
index a5856dd..98c4d9a 100644
--- a/test/stress/parsego.go
+++ b/test/stress/parsego.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/stress/runstress.go b/test/stress/runstress.go
index 76ab2a8..3f16fc9 100644
--- a/test/stress/runstress.go
+++ b/test/stress/runstress.go
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors.  All rights reserved.
+// 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/test/struct0.go b/test/struct0.go
index e29eb30..403e977 100644
--- a/test/struct0.go
+++ b/test/struct0.go
@@ -1,6 +1,6 @@
 // run
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/switch5.go b/test/switch5.go
new file mode 100644
index 0000000..7da2c66
--- /dev/null
+++ b/test/switch5.go
@@ -0,0 +1,81 @@
+// errorcheck
+
+// Copyright 2016 The Go 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 switch statements with duplicate cases are detected by the compiler.
+// Does not compile.
+
+package main
+
+import "fmt"
+
+func f0(x int) {
+	switch x {
+	case 0:
+	case 0: // ERROR "duplicate case 0 in switch"
+	}
+
+	switch x {
+	case 0:
+	case int(0): // ERROR "duplicate case 0 in switch"
+	}
+}
+
+func f1(x float32) {
+	switch x {
+	case 5:
+	case 5: // ERROR "duplicate case 5 in switch"
+	case 5.0: // ERROR "duplicate case 5 in switch"
+	}
+}
+
+func f2(s string) {
+	switch s {
+	case "":
+	case "": // ERROR "duplicate case .. in switch"
+	case "abc":
+	case "abc": // ERROR "duplicate case .abc. in switch"
+	}
+}
+
+func f3(e interface{}) {
+	switch e {
+	case 0:
+	case 0: // ERROR "duplicate case 0 in switch"
+	case int64(0):
+	case float32(10):
+	case float32(10): // ERROR "duplicate case float32\(10\) in switch"
+	case float64(10):
+	case float64(10): // ERROR "duplicate case float64\(10\) in switch"
+	}
+}
+
+func f4(e interface{}) {
+	switch e.(type) {
+	case int:
+	case int: // ERROR "duplicate case int in type switch"
+	case int64:
+	case error: // ERROR "duplicate case error in type switch"
+	case error:
+	case fmt.Stringer:
+	case fmt.Stringer: // ERROR "duplicate case fmt.Stringer in type switch"
+	case struct {
+		i int "tag1"
+	}:
+	case struct {
+		i int "tag2"
+	}:
+	case struct {
+		i int "tag1"
+	}: // ERROR "duplicate case struct { i int .tag1. } in type switch"
+	}
+}
+
+func f5(a [1]int) {
+	switch a {
+	case [1]int{0}:
+	case [1]int{0}: // OK -- see issue 15896
+	}
+}
diff --git a/test/switch6.go b/test/switch6.go
new file mode 100644
index 0000000..bd62c62
--- /dev/null
+++ b/test/switch6.go
@@ -0,0 +1,32 @@
+// errorcheck
+
+// Copyright 2016 The Go 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 the compiler's switch handling that happens
+// at typechecking time.
+// This must be separate from other checks,
+// because errors during typechecking
+// prevent other errors from being discovered.
+
+package main
+
+// Verify that type switch statements with impossible cases are detected by the compiler.
+func f0(e error) {
+	switch e.(type) {
+	case int: // ERROR "impossible type switch case: e \(type error\) cannot have dynamic type int \(missing Error method\)"
+	}
+}
+
+// Verify that the compiler rejects multiple default cases.
+func f1(e interface{}) {
+	switch e { // ERROR "multiple defaults in switch"
+	default:
+	default:
+	}
+	switch e.(type) { // ERROR "multiple defaults in switch"
+	default:
+	default:
+	}
+}
diff --git a/test/syntax/chan.go b/test/syntax/chan.go
index b016790..6f9d77d 100644
--- a/test/syntax/chan.go
+++ b/test/syntax/chan.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/chan1.go b/test/syntax/chan1.go
index 4860422..2e9929b 100644
--- a/test/syntax/chan1.go
+++ b/test/syntax/chan1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/composite.go b/test/syntax/composite.go
index 722805a..f891931 100644
--- a/test/syntax/composite.go
+++ b/test/syntax/composite.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2012 The Go Authors.  All rights reserved.
+// 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/test/syntax/ddd.go b/test/syntax/ddd.go
new file mode 100644
index 0000000..476ae22
--- /dev/null
+++ b/test/syntax/ddd.go
@@ -0,0 +1,11 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. 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() {
+	g(f..3) // ERROR "unexpected literal \.3, expecting name or \("
+}
diff --git a/test/syntax/else.go b/test/syntax/else.go
index e985a9c..9537329 100644
--- a/test/syntax/else.go
+++ b/test/syntax/else.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/syntax/forvar.go b/test/syntax/forvar.go
index 043c299..3a70d9c 100644
--- a/test/syntax/forvar.go
+++ b/test/syntax/forvar.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/if.go b/test/syntax/if.go
index b2a65f9..c208a9f 100644
--- a/test/syntax/if.go
+++ b/test/syntax/if.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/syntax/import.go b/test/syntax/import.go
index f0a7921..8010bed 100644
--- a/test/syntax/import.go
+++ b/test/syntax/import.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/interface.go b/test/syntax/interface.go
index 0b76b54..010d3ce 100644
--- a/test/syntax/interface.go
+++ b/test/syntax/interface.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/semi1.go b/test/syntax/semi1.go
index 6e04281..c755445 100644
--- a/test/syntax/semi1.go
+++ b/test/syntax/semi1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/semi2.go b/test/syntax/semi2.go
index 23d7bd0..9216789 100644
--- a/test/syntax/semi2.go
+++ b/test/syntax/semi2.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/semi3.go b/test/syntax/semi3.go
index ca070d8..d625d08 100644
--- a/test/syntax/semi3.go
+++ b/test/syntax/semi3.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/semi4.go b/test/syntax/semi4.go
index 1f4e679..6315f34 100644
--- a/test/syntax/semi4.go
+++ b/test/syntax/semi4.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/semi5.go b/test/syntax/semi5.go
index cf690f0..c54a994 100644
--- a/test/syntax/semi5.go
+++ b/test/syntax/semi5.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/semi6.go b/test/syntax/semi6.go
index 1b51d8b..325cc27 100644
--- a/test/syntax/semi6.go
+++ b/test/syntax/semi6.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/semi7.go b/test/syntax/semi7.go
index 357352d..a1948b0 100644
--- a/test/syntax/semi7.go
+++ b/test/syntax/semi7.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/topexpr.go b/test/syntax/topexpr.go
index c5958f5..be080d2 100644
--- a/test/syntax/topexpr.go
+++ b/test/syntax/topexpr.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/typesw.go b/test/syntax/typesw.go
index cd8cf35..8d89860 100644
--- a/test/syntax/typesw.go
+++ b/test/syntax/typesw.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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/test/syntax/vareq.go b/test/syntax/vareq.go
index f08955e..0d4bb78 100644
--- a/test/syntax/vareq.go
+++ b/test/syntax/vareq.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/syntax/vareq1.go b/test/syntax/vareq1.go
index d4952fe..a2f9f34 100644
--- a/test/syntax/vareq1.go
+++ b/test/syntax/vareq1.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/uintptrescapes.dir/a.go b/test/uintptrescapes.dir/a.go
new file mode 100644
index 0000000..29c8340
--- /dev/null
+++ b/test/uintptrescapes.dir/a.go
@@ -0,0 +1,54 @@
+// Copyright 2016 The Go Authors. 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
+
+import (
+	"unsafe"
+)
+
+func recurse(i int, s []byte) byte {
+	s[0] = byte(i)
+	if i == 0 {
+		return s[i]
+	} else {
+		var a [1024]byte
+		r := recurse(i-1, a[:])
+		return r + a[0]
+	}
+}
+
+//go:uintptrescapes
+func F1(a uintptr) {
+	var s [16]byte
+	recurse(4096, s[:])
+	*(*int)(unsafe.Pointer(a)) = 42
+}
+
+//go:uintptrescapes
+func F2(a ...uintptr) {
+	var s [16]byte
+	recurse(4096, s[:])
+	*(*int)(unsafe.Pointer(a[0])) = 42
+}
+
+type t struct{}
+
+func GetT() *t {
+	return &t{}
+}
+
+//go:uintptrescapes
+func (*t) M1(a uintptr) {
+	var s [16]byte
+	recurse(4096, s[:])
+	*(*int)(unsafe.Pointer(a)) = 42
+}
+
+//go:uintptrescapes
+func (*t) M2(a ...uintptr) {
+	var s [16]byte
+	recurse(4096, s[:])
+	*(*int)(unsafe.Pointer(a[0])) = 42
+}
diff --git a/test/uintptrescapes.dir/main.go b/test/uintptrescapes.dir/main.go
new file mode 100644
index 0000000..afda621
--- /dev/null
+++ b/test/uintptrescapes.dir/main.go
@@ -0,0 +1,91 @@
+// Copyright 2016 The Go Authors. 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"
+	"sync"
+	"unsafe"
+
+	"./a"
+)
+
+func F1() int {
+	var buf [1024]int
+	a.F1(uintptr(unsafe.Pointer(&buf[0])))
+	return buf[0]
+}
+
+func F2() int {
+	var buf [1024]int
+	a.F2(uintptr(unsafe.Pointer(&buf[0])))
+	return buf[0]
+}
+
+var t = a.GetT()
+
+func M1() int {
+	var buf [1024]int
+	t.M1(uintptr(unsafe.Pointer(&buf[0])))
+	return buf[0]
+}
+
+func M2() int {
+	var buf [1024]int
+	t.M2(uintptr(unsafe.Pointer(&buf[0])))
+	return buf[0]
+}
+
+func main() {
+	// Use different goroutines to force stack growth.
+	var wg sync.WaitGroup
+	wg.Add(4)
+	c := make(chan bool, 4)
+
+	go func() {
+		defer wg.Done()
+		b := F1()
+		if b != 42 {
+			fmt.Printf("F1: got %d, expected 42\n", b)
+			c <- false
+		}
+	}()
+
+	go func() {
+		defer wg.Done()
+		b := F2()
+		if b != 42 {
+			fmt.Printf("F2: got %d, expected 42\n", b)
+			c <- false
+		}
+	}()
+
+	go func() {
+		defer wg.Done()
+		b := M1()
+		if b != 42 {
+			fmt.Printf("M1: got %d, expected 42\n", b)
+			c <- false
+		}
+	}()
+
+	go func() {
+		defer wg.Done()
+		b := M2()
+		if b != 42 {
+			fmt.Printf("M2: got %d, expected 42\n", b)
+			c <- false
+		}
+	}()
+
+	wg.Wait()
+
+	select {
+	case <-c:
+		os.Exit(1)
+	default:
+	}
+}
diff --git a/test/uintptrescapes.go b/test/uintptrescapes.go
new file mode 100644
index 0000000..554bb76
--- /dev/null
+++ b/test/uintptrescapes.go
@@ -0,0 +1,9 @@
+// rundir
+
+// Copyright 2016 The Go 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 go:uintptrescapes comment works as expected.
+
+package ignored
diff --git a/test/uintptrescapes2.go b/test/uintptrescapes2.go
new file mode 100644
index 0000000..7ff676d
--- /dev/null
+++ b/test/uintptrescapes2.go
@@ -0,0 +1,31 @@
+// errorcheck -0 -m -live
+
+// Copyright 2016 The Go 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 and liveness inferred for uintptrescapes functions.
+
+package p
+
+import (
+	"unsafe"
+)
+
+//go:uintptrescapes
+//go:noinline
+func F1(a uintptr) {} // ERROR "escaping uintptr"
+
+//go:uintptrescapes
+//go:noinline
+func F2(a ...uintptr) {} // ERROR "escaping ...uintptr" "live at entry" "a does not escape"
+
+func G() {
+	var t int // ERROR "moved to heap"
+	F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: autotmp" "&t escapes to heap"
+}
+
+func H() {
+	var v int // ERROR "moved to heap"
+	F2(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to newobject: autotmp" "live at call to F2: autotmp" "escapes to heap"
+}
diff --git a/test/undef.go b/test/undef.go
index 0a77e59..61524f3 100644
--- a/test/undef.go
+++ b/test/undef.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/varerr.go b/test/varerr.go
index 22aa932..82ab814 100644
--- a/test/varerr.go
+++ b/test/varerr.go
@@ -1,6 +1,6 @@
 // errorcheck
 
-// Copyright 2010 The Go Authors.  All rights reserved.
+// 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.
 
diff --git a/test/writebarrier.go b/test/writebarrier.go
index dcd20a0..88b4b29 100644
--- a/test/writebarrier.go
+++ b/test/writebarrier.go
@@ -1,6 +1,6 @@
 // errorcheck -0 -l -d=wb
 
-// Copyright 2015 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.
 
@@ -158,3 +158,56 @@ func t1(i interface{}) **int {
 	}
 	return nil
 }
+
+type T17 struct {
+	f func(*T17)
+}
+
+func f17(x *T17) {
+	// See golang.org/issue/13901
+	x.f = f17                      // no barrier
+	x.f = func(y *T17) { *y = *x } // ERROR "write barrier"
+}
+
+type T18 struct {
+	a []int
+	s string
+}
+
+func f18(p *T18, x *[]int) {
+	p.a = p.a[:5]    // no barrier
+	*x = (*x)[0:5]   // no barrier
+	p.a = p.a[3:5]   // ERROR "write barrier"
+	p.a = p.a[1:2:3] // ERROR "write barrier"
+	p.s = p.s[8:9]   // ERROR "write barrier"
+	*x = (*x)[3:5]   // ERROR "write barrier"
+}
+
+func f19(x, y *int, i int) int {
+	// Constructing a temporary slice on the stack should not
+	// require any write barriers. See issue 14263.
+	a := []*int{x, y} // no barrier
+	return *a[i]
+}
+
+func f20(x, y *int, i int) []*int {
+	// ... but if that temporary slice escapes, then the
+	// write barriers are necessary.
+	a := []*int{x, y} // ERROR "write barrier"
+	return a
+}
+
+var x21 *int
+var y21 struct {
+	x *int
+}
+var z21 int
+
+func f21(x *int) {
+	// Global -> heap pointer updates must have write barriers.
+	x21 = x                   // ERROR "write barrier"
+	y21.x = x                 // ERROR "write barrier"
+	x21 = &z21                // no barrier
+	y21.x = &z21              // no barrier
+	y21 = struct{ x *int }{x} // 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